layerscape: add patches-5.4
authorYangbo Lu <yangbo.lu@nxp.com>
Fri, 10 Apr 2020 02:47:05 +0000 (10:47 +0800)
committerPetr Štetiar <ynezz@true.cz>
Thu, 7 May 2020 10:53:06 +0000 (12:53 +0200)
Add patches for linux-5.4. The patches are from NXP LSDK-20.04 release
which was tagged LSDK-20.04-V5.4.
https://source.codeaurora.org/external/qoriq/qoriq-components/linux/

For boards LS1021A-IOT, and Traverse-LS1043 which are not involved in
LSDK, port the dts patches from 4.14.

The patches are sorted into the following categories:
  301-arch-xxxx
  302-dts-xxxx
  303-core-xxxx
  701-net-xxxx
  801-audio-xxxx
  802-can-xxxx
  803-clock-xxxx
  804-crypto-xxxx
  805-display-xxxx
  806-dma-xxxx
  807-gpio-xxxx
  808-i2c-xxxx
  809-jailhouse-xxxx
  810-keys-xxxx
  811-kvm-xxxx
  812-pcie-xxxx
  813-pm-xxxx
  814-qe-xxxx
  815-sata-xxxx
  816-sdhc-xxxx
  817-spi-xxxx
  818-thermal-xxxx
  819-uart-xxxx
  820-usb-xxxx
  821-vfio-xxxx

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
916 files changed:
target/linux/layerscape/patches-5.4/301-arch-0001-arm-kernel-utilize-hrtimer-based-broadcast.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/301-arch-0002-arm64-add-support-to-remap-kernel-cacheable-memory-t.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/301-arch-0003-arm64-pgtable-add-support-to-map-cacheable-and-non-s.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/301-arch-0004-arm64-add-ioremap-for-normal-cacheable-non-shareable.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/301-arch-0005-arch-arm-add-ARM-specific-fucntions-required-for-ehc.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/301-arch-0006-export-arch_setup_dma_ops.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/301-arch-0007-arm-dma-mapping-export-arch_setup_dma_ops.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/301-arch-0008-arm-add-new-non-shareable-ioremap.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/301-arch-0009-arm-add-pgprot_cached-and-pgprot_cached_ns-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/301-arch-0010-arm64-add-stage-2-cache-able-non-shareable-page-type.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/301-arch-0011-drivers-soc-fsl-add-qixis-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/301-arch-0012-soc-fsl-select-MFD_CORE-for-qixis-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0001-sdk-arm64-dts-add-update-DPAA1-include-files-for-SDK.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0002-sdk-arm64-dts-add-DPAA1-SDK-flavor-dts-files.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0003-arm64-dts-ls1012a-Add-LS1012A-2G5RDB-board-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0004-arm64-dts-ls1012a-Add-more-nodes-to-LS1012A-FRWY-boa.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0005-arm64-dts-ls2081ardb-Add-DTS-support-for-NXP-LS2081A.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0006-arm64-dts-ls1012a-accumulated-change-for-ls1012a-boa.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0007-arm64-dts-ls1043a-accumulated-change-for-ls1043a-boa.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0008-arm64-dts-ls1046a-accumulated-change-to-ls1046a-boar.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0009-arm64-dts-ls1088a-accumulated-change-to-ls1088a-boar.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0010-arm64-dts-ls208xa-accumulated-change-to-ls208xa-boar.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0011-ARM-dts-accumulated-change.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0012-arm64-dts-ls1046a-add-smmu-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0013-arm64-dts-ls1043a-add-smmu-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0014-arm64-dts-ls104xa-set-mask-to-drop-TBU-ID-from-Strea.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0015-arm64-dts-ls104x-add-missing-dma-ranges-property.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0016-arm64-dts-ls104x-add-iommu-map-to-pci-controllers.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0017-arm64-dts-ls104x-make-dma-coherent-global-to-the-SoC.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0018-arm64-dts-ls104x-use-a-pseudo-bus-to-constrain-usb-d.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0019-sdk-dts-ls104x-drop-smmu-from-the-sdk-device-trees.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0020-arm64-dts-lx2160a-add-MDIO-device-tree-nodes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0021-arm64-dts-lx2160a-rdb-Add-RGMII-PHY-nodes-for-dpmac-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0022-arm64-dts-lx2160a-correct-scl-gpios-property.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0023-arm64-dts-lx2160a-add-dspi-controller-DT-nodes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0024-arm64-dts-lx2160a-add-DT-node-for-all-DSPI-controlle.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0025-arm64-dts-nxp-ls208xa-add-more-thermal-zone-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0026-arm64-dts-nxp-add-more-thermal-zone-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0027-arm64-dts-lx2160a-rdb-Add-Inphi-PHY-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0028-arm64-dts-lx2160a-rdb-Add-Aquantia-PHY-nodes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0029-arm64-dts-lx2160-Add-all-pcs-mdio-definitions-accord.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0030-arm64-dts-lx2160-PCS-PHY-definitions-for-10GBase-KR-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0031-arm64-dts-lx2160-DPMAC-connections-to-backplane-PHYs.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0032-arm64-dts-Added-endianness-information-to-dts-serdes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0033-arm64-dts-freescale-lx2160a-add-pcie-DT-nodes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0034-arm64-dts-freescale-lx2160a-Inphi-in112525_s03-mdio-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0035-arm64-dts-lx2160a-add-optee-tz-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0036-arm64-dts-ls104x-constrain-sata-dma-address-size.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0037-arm64-dts-lx2160a-qds-add-sata-node-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0038-arm64-dts-ls1012a-use-phy-handle-to-handle-phy-param.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0039-arm64-dts-ls1012a-remove-unused-gemac-bus-id.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0040-arm64-dts-ls1012a-reorganize-pfe_mac-nodes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0041-sdk-dts-ls104x-drop-smmu-from-the-qds-and-usdpaa-sdk.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0042-arm64-dts-fix-the-LS104x-QDS-mdio-mux-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0043-arm64-dts-lx2160aqds-Add-mdio-mux-nodes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0044-sdk-arm64-dts-reduce-usdpaa-memory-to-4K-for-LS1046-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0045-arm64-dts-Fix-DWC3-IP-VBUS-glitch-issue-on-Layerscap.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0046-ARM-dts-Fix-DWC3-IP-VBUS-glitch-issue-on-LS1021A.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0047-ARM-dts-ls1021aqds-enable-esdhc-controller.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0048-arm64-dts-freescale-lx2160a-add-pcie-EP-mode-DT-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0049-sdk-dts-ls104x-move-dma-coherent-from-soc-to-its-chi.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0050-arm64-dts-lx2160a-add-interrupt-property-for-aquanti.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0051-arm64-dts-fsl-layerscape-fix-warnings-when-compiling.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0052-arm64-dts-fsl-layerscape-fix-warnings-when-compiling.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0053-sdk-arm64-dts-nxp-add-DPAA1-SDK-flavor-dts-files.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0054-arm64-dts-nxp-frwy-ls1046a-add-support-for-micron-no.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0055-arm64-dts-ls1028a-Add-PCIe-controller-DT-nodes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0056-arm64-dts-lx2160a-Enable-usb3-lpm-capable-for-usb3-n.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0057-arm64-dts-fsl-lx2160a-add-flexcan-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0058-arm64-dts-fsl-ls1028a-add-flexcan-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0059-arm64-dts-fsl-ls1046-Modify-the-qspi-flash-frequency.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0060-arm64-dts-ls1028a-add-flexspi-nodes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0061-sdk-dts-ls1046-drop-smmu-from-the-frwy-sdk-dtses.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0062-sdk-dts-ls1046frwy-move-dma-coherent-from-soc-to-its.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0063-arm64-dts-fsl-remove-backplane-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0064-arm64-dts-lx2160a-update-interrupt-property-for-Aqua.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0065-arm64-dts-ls1028a-Update-fspi-reg-properties.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0066-arm64-dts-ls1028a-add-gpu-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0067-arm64-dts-fsl-add-optee-node-for-ls1028.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0068-arm64-dts-lx2160a-Update-phy-mode-for-Aquantia-PHYs.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0069-arm64-dts-ls1028a-Add-ftm_alarm0-DT-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0070-arm64-dts-ls1012a-ls1043a-ls1046a-ls1088a-ls208xa-re.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0071-arm-dts-ls1021a-replace-ftm0-with-ftm_alarm0-DT-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0072-arm64-ls1028ardb-Add-support-DP-nodes-for-LS1028ARDB.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0073-arm64-ls1028aqds-Add-support-DP-nodes-for-LS1028AQDS.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0074-arm64-dts-fsl-ls1028a-Add-Felix-switch-port-DT-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0075-arm64-dts-fsl-ls1028a-Enable-switch-PHYs-on-RDB.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0076-arm64-dts-ls1028a-support-Felix-PF5-INTB-interrupt.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0077-arm64-dts-ls1028a-Add-ethernet-property-for-l2switch.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0078-arm64-dts-fix-endianness-of-rcpm.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0079-arm64-dts-ls1028a-Fix-interrupt-map-property-of-PCIe.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0080-arm64-dts-ls1028a-rdb-enable-emmc-hs400-mode.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0081-arm64-dts-lx2160a-add-ftm_alarm0-DT-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0082-arm64-dts-lx2160a-add-tmu-device-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0083-arm64-ls1028a-qds-correct-bus-of-rtc.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0084-arm64-dts-ls1028a-define-networking-options-for-QDS.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0085-arm64-dts-LS1028a-rdb-use-Ethernet-PHY-interrupt.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0086-usb-dwc3-enable-otg-mode-for-dwc3-usb-ip-on-layersca.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0087-arm-dts-ls1021a-fix-that-FlexTimer-cannot-wakeup-sys.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0088-arm64-dts-ls1028a-fix-dwc-pci-over-smmu.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0089-arm64-dts-ls1028a-Update-the-clock-providers-for-the.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0090-arm64-dts-ls1028a-Update-clock-cells-of-dpclk-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0091-arm64-dts-ls1028a-Add-properties-for-HD-Display-cont.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0092-arm64-dts-ls1028a-Add-DP-DT-nodes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0093-arm64-dts-fsl-Specify-phy-mode-for-CPU-ports.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0094-arm64-dts-fsl-Drop-compatible-string-from-Felix-swit.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0095-arm64-dts-fsl-ls1028a-Specify-that-the-Felix-port-4-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0096-arm64-dts-fsl-ls1028a-Disable-eno3-and-make-swp5-the.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0097-LF-387-5-arm64-dts-layerscape-add-chip-specific-comp.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0098-LF-403-ARM64-dts-fsl-Add-clock-names-mclk0-for-SAI-n.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0099-arm64-dts-layerscape-apply-dma-coherent-for-dwc3-nod.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0100-arm64-dts-ls208xa-Update-qspi-node-properties-for-LS.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0101-arm64-dts-ls208xa-Remove-dma-coherent-from-dwc3-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0102-LF-20-1-arm64-dts-ls1012ardb-Update-qspi-node-dts-pr.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0103-arm64-dts-ls1028a-Update-edma-compatible-to-fit-eDMA.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0104-arm64-dts-lx2160a-add-iommu-map-property-to-pci-node.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0105-LF-18-1-arm64-dts-ls1088ardb-Update-qspi-dts-node-pr.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0106-LF-18-2-arm64-dts-ls1046ardb-Update-qspi-node-dts-pr.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0107-arm64-dts-ls1012ardb-Update-qspi-node-property.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0108-Revert-arm64-dts-LS1028a-rdb-use-Ethernet-PHY-interr.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0109-arm64-dts-ls1028a-rdb-Enable-SGMII-AN-for-the-QSGMII.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0110-arm64-dts-ls1028a-Disable-swp5-by-default.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0111-arm64-dts-fsl-ls1028a-rdb-fix-QSGMII-PHY-node-names.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0112-arm64-dts-fsl-ls1028a-prepare-dts-for-overlay.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0113-arm64-dts-fsl-ls1028a-qds-Add-overlays-for-various-s.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0114-arm64-dts-fsl-ls1028a-add-labels-to-Ethernet-switch-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0115-LF-789-2-arm64-dts-add-overlay-support-for-ls1028a-q.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0116-LF-881-arm64-dts-add-a-dts-file-for-dpdk.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0117-arm-dts-ls1021a-Add-LS1021A-IOT-board-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/302-dts-0118-add-DTS-for-Traverse-LS1043-Boards.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/303-core-0001-net-readd-skb_recycle.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/303-core-0002-drivers-base-add-sysfs-entries-for-suppliers-and-con.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/303-core-0003-cgroup-let-a-symlink-too-be-created-with-a-cftype-fi.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/303-core-0004-cgroup-bfq-revert-bfq.weight-symlink-change.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/303-core-0005-nand-raw-workaround-for-EDO-high-speed-mode.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/303-core-0006-mm-Re-export-ioremap_page_range.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/303-core-0007-of-of_reserved_mem-Ensure-cma-reserved-region-not-cr.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/303-core-0008-ENGR00279980-ubi-attach-do-not-return-EINVAL-if-the-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/303-core-0009-arm64-move-elfcorehdr-reservation-early-for-crash-du.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/303-core-0010-scripts-Makefile-Enable-creation-of-_symbols_-DT-nod.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/303-core-0011-LF-419-arm64-crash_core-Export-TCR_EL1.T1SZ-in-vmcor.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/303-core-0012-LF-789-1-Revert-scripts-Makefile-Enable-creation-of-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0001-soc-fsl-qman-fixup-liodns-only-on-ppc-targets.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0002-soc-fsl-bman-map-FBPR-area-in-the-iommu.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0003-soc-fsl-qman-map-FQD-and-PFDR-areas-in-the-iommu.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0004-soc-fsl-qman-portal-map-CENA-area-in-the-iommu.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0005-soc-fsl-qbman_portals-add-APIs-to-retrieve-the-probi.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0006-soc-fsl-bqman-page-align-iommu-mapping-sizes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0007-fsl_qbman-SDK-DPAA-1.x-QBMan-drivers.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0008-fmd-SDK-DPAA-1.x-FMan-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0009-dpa-SDK-DPAA-1.x-Ethernet-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0010-dpaa_eth-ls1043a-errata-check-if-the-skb-is-linear-a.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0011-dpaa_eth-ceetm-adapt-to-net-sched-API-changes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0012-dpaa_eth-ceetm-adapt-to-the-new-gnet-stats-API.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0013-dpaa_eth-ceetm-update-include-paths-for-tc-filters.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0014-dpa_eth-remove-unused-code.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0015-fmd-use-ptp-timer-for-Fman-RTC-node-name.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0016-dpaa_eth-use-ptp-timer-phandle-instead-of-ptimer-han.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0017-dpaa_eth-move-global-variable-clock-into-ptp_priv_s-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0018-sdk_dpaa-use-new-api-ethtool_ksettings_-get-set.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0019-sdk_dpaa-fix-dpa_set_ksettings.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0020-dpaa_eth-memac-set-adjust_link-callback-for-fixed-li.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0021-sdk_dpaa-ls1043a-errata-resplit-the-skb-after-copy.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0022-sdk_dpaa-ls1043a-errata-realign-and-linearize-egress.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0023-sdk_dpaa-ls1043a-errata-realign-skb-in-place-if-need.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0024-sdk_dpaa-ls1043a-errata-verify-and-resize-headroom-a.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0025-sdk_dpaa-ls1043a-errata-do-not-recycle-the-realigned.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0026-sdk_dpaa-ls1043a-errata-fix-arm32-build.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0027-drivers-staging-fsl_qbman-Fix-SWP-Mask-in-Error-Hand.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0028-sdk_dpaa-avoid-crashing-on-OOM.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0029-sdk_dpaa-update-the-xmit-timestamp-to-avoid-watchdog.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0030-sdk_fman-resolve-arm32-compilation-issues-for-linux-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0031-sdk_dpaa-ls1043a-errata-maintain-timestamp-info.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0032-sdk_dpaa-ls1043a-errata-restrict-the-max-mtu.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0033-sdk_dpaa-adapt-to-the-new-API-for-MTU-changes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0034-Extend-FM-MAC-Statistics-with-frame-size-counters-re.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0035-sdk_dpaa-accept-frames-on-RX-even-if-larger-than-MTU.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0036-sdk-dpa-use-netdev-dev-for-DMA-mapping.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0037-Added-MII-IOCTL-support-for-SIOCGMIIREG.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0038-sdk_dpaa-ls1043a-errata-stop-advertising-S-G-and-GSO.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0039-staging-fsl_qbman-Calculate-valid-bit-from-MC-RR.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0040-fsl_qbman-usdpaa-Invalidate-software-portals-before-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0041-net-ethernet-Rename-PHY_INTERFACE_MODE_SGMII_2500.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0042-sdk_dpaa-ceetm-add-independent-CEETM-congestion-thre.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0043-sdk_dpaa-ceetm-stop-transmitting-frames-when-the-CQ-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0044-sdk_dpaa-ceetm-coding-style-fixes-and-added-comments.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0045-sdk_dpaa-ceetm-increment-the-interface-s-ern-counter.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0046-sdk_dpaa-update-buffer-recycling-conditions.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0047-sdk_dpaa-update-comments-about-recycling-and-back-po.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0048-sdk_dpaa-ceetm-pass-extended-ACK-struct-to-parsing-f.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0049-sdk_dpaa-ceetm-adapt-to-new-tcf-classify-API.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0050-sdk_dpaa-ceetm-introduce-a-TRAP-control-action.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0051-sdk_dpaa-ceetm-use-the-tcf-block-infrastructure.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0052-sdk_dpaa-ceetm-remove-tc-class-reference-counting.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0053-sdk_dpaa-ceetm-store-Qdisc-pointer-in-struct-block.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0054-dpaa_eth-workaround-for-ERR010022.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0055-sdk_fman-DPAA-dTSEC-ports-fail-to-work-when-link-cha.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0056-sdk-dpa-adapt-compatibles-to-upstream-binding-docume.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0057-sdk_fman-fix-probing-of-10G-ports-on-T102x.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0058-sdk_fman-probe-OH-ports-on-PPC.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0059-sdk_fman-on-P-series-platforms-the-OH-ports-start-at.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0060-sdk_fman-disable-timer-code.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0061-sdk_fman-disable-timer-code-in-arm-code.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0062-sdk_dpa-adapt-ceetm-code-to-new-kernel-API.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0063-sdk_dpaa-propagate-the-skb-ownership-information.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0064-memac_init_phy-RGMII-fixed-link-pass-adjust_link-cal.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0065-sdk_dpaa-ceetm-avoid-use-after-free-scenarios.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0066-sdk_dpaa-ceetm-stop-the-netdev-queues-when-switching.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0067-fsl_qbman-ceetm-export-the-qman_ceetm_query_cq-call.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0068-sdk_dpaa-ceetm-propagate-the-ceetm-channel-through-t.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0069-sdk_dpaa-ceetm-reset-the-wbfs-groups-and-priorities-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0070-sdk_dpaa-ceetm-WQ-CEETM-mode-switchover-cleanup.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0071-sdk_dpaa-ceetm-drain-the-ceetm-CQs-on-destroy.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0072-sdk_dpaa-ls1043a-errata-adapt-to-new-skb-copy-API.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0073-dpaa_eth-ERR010022-adapt-to-new-skb-copy-API.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0074-sdk_dpaa-enable-Jumbo-frame-support-on-LS1043A.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0075-sdk_dpaa-reserve-256-bytes-for-the-SGT-on-TX.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0076-fsl_qbman-usdpaa-change-to-debug-print-in-interrupt-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0077-staging-fsl_qbman-Consume-all-frames-in-DQRR-during-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0078-staging-fsl_qbman-Recalcuate-cursor-after-consuming-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0079-fmd-use-fsl-fman-ptp-timer-compatible-for-ptp-probe.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0080-sdk_dpaa-store-the-skb-backpointer-in-the-skb-headro.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0081-sdk_dpaa-ls1043a-errata-align-skb_shinfo.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0082-sdk_dpaa-ls1043a-errata-move-comment.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0083-sdk_dpaa-ceetm-lower-the-default-congestion-threshol.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0084-staging-fsl_qbman-remove-bootmem-header.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0085-staging-fsl_qbman-stop-using-current_kernel_time.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0086-sdk_dpaa-ceetm-avoid-double-frees-on-error-paths.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0087-sdk_dpaa-ceetm-rename-qdisc_destroy-to-qdisc_put.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0088-sdk_dpaa-remove-FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0089-fsl-fman-backup-and-restore-ICID-registers.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0090-fsl-fman-add-API-to-get-the-device-behind-a-fman-por.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0091-dpaa_eth-defer-probing-after-qbman.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0092-dpaa_eth-base-dma-mappings-on-the-fman-rx-port.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0093-dpaa_eth-fix-iova-handling-for-contiguous-frames.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0094-dpaa_eth-fix-iova-handling-for-sg-frames.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0095-sdk_dpaa-ceetm-guard-against-an-out-of-bounds-queue-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0096-sdk_dpaa-guard-against-an-out-of-bounds-queue-index.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0097-sdk_dpaa-set-the-skb-queue-mapping-when-looping.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0098-sdk_dpaa-remove-ptp-clock-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0099-sdk_fman-suspend-the-FMan-to-Deep-Sleep-on-PPC-only.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0100-sdk_fman-disable-ptp-timer-probe.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0101-sdk_dpaa-add-the-get_ts_info-interface-for-ethtool.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0102-sdk_fman-share-the-event-interrupt.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0103-sdk_dpaa-fix-hardware-timestamp-value.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0104-sdk_dpaa-remove-useless-1588-timer-enablement.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0105-sdk-qbman-fix-issue-in-qman_delete_cgr_safe.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0106-sdk_fman-avoid-array-overflow-error-in-fman-port-ini.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0107-fsl_qbman-Adjust-platform-device-creation-for-QMan-p.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0108-sdk_dpaa-ls1043a-errata-impose-S-G-frame-realignment.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0109-sdk_dpaa-remove-the-QM_FQCTRL_PREFERINCACHE-flag.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0110-sdk_dpaa-adapt-to-kernel-5.1.0-rc1.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0111-sdk_qbman-Avoid-variable-length-array-in-USDPAA.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0112-sdk_dpaa-Rework-QBMan-portal-mappings.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0113-sdk_qbman-Fix-error-in-IP-revision-comparison.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0114-sdk_dpaa-SGMII-2500-needs-AN-disabled.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0115-sdk_qbman-Update-cpus_allowed-to-cpus_mask-to-cope-w.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0116-sdk_dpaa-ceetm-align-to-upstream-API-changes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0117-dpaa_eth-ERR010022-align-skb_shinfo.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0118-dpaa_eth-ERR010022-preserve-timestamping.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0119-sdk_dpaa-ceetm-update-Makefile-to-use-absolute-inclu.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0120-sdk_dpaa-net-Rename-skb_frag_t-size-to-bv_len.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0121-dpaa_eth-Rename-skb_frag_t-size-to-bv_len.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0122-config-enable-SDK-FMan-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0123-config-enable-SDK-DPAA-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0124-config-enable-SDK-QBMan.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0125-config-add-SDK-QBMan-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0126-net-Makefile-re-add-DPAA-SDK-drivers.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0127-ptp-support-ptp_qoriq-for-sdk-dpaa.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0128-net-dpaa-fix-build-failure-due-to-skb_frag_t-struct-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0129-sdk_dpa-align-to-upstream-PHY_INTERFACE_MODE.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0130-bus-fsl-mc-move-fsl_mc_command-struct-in-a-uapi-head.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0131-bus-fsl-mc-add-fsl-mc-userspace-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0132-bus-fsl-mc-add-root-dprc-rescan-attribute.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0133-bus-fsl-mc-add-bus-rescan-attribute.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0134-bus-fsl-mc-Add-dprc-reset-container-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0135-bus-fsl-mc-Propagate-driver_override-for-a-child-DPR.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0136-bus-fsl-mc-add-device-binding-path-driver_override.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0137-bus-fsl-mc-move-fsl_mc_device_remove-to-common-heade.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0138-bus-fsl-mc-increase-MC_CMD_COMPLETION_TIMEOUT_MS-val.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0139-bus-fsl-mc-added-missing-fields-to-dprc_rsp_get_obj_.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0140-bus-fsl-mc-define-macros-for-iommu-enablement-for-fs.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0141-bus-fsl-mc-Extend-ICID-size-from-16bit-to-32bit.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0142-bus-fsl-mc-Some-apis-are-made-public-for-vfio.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0143-bus-fsl-mc-add-support-for-dpdmux-device-type.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0144-bus-fsl-mc-add-support-for-dpdcei-device-type.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0145-bus-fsl-mc-add-support-for-dpaiop-dpci-and-dpdmai-de.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0146-bus-fsl-mc-DMA-configure-to-have-force-dma-as-defaul.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0147-bus-fsl-mc-Allocate-mc-portal-from-root-dprc-contain.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0148-bus-fsl-mc-use-raw-spin-lock-to-serialize-mc-cmds.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0149-soc-fsl-dpio-change-CENA-regs-to-be-cacheable.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0150-soc-fsl-dpio-enable-qbman-CENA-portal-memory-access.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0151-soc-fsl-dpio-Prefer-the-CPU-affine-DPIO.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0152-soc-fsl-dpio-Add-Support-for-Order-Restoration.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0153-soc-fsl-dpio-Fix-order-restoration-API-for-QBMan-5.0.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0154-soc-fsl-dpio-add-support-for-opr.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0155-soc-fsl-dpio-aligned-access-of-qbman-cacheable-regio.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0156-staging-fsl-dpaa2-mac-Add-APIs-for-DPMAC-objects.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0157-staging-fsl-dpaa2-mac-Add-Freescale-DPAA2-mac-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0158-staging-fsl-dpaa2-mac-Remove-link-type-from-phy-sel-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0159-staging-fsl-dpaa2-mac-Update-ethtool-ops.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0160-staging-fsl-dpaa2-mac-Comply-with-mc-bus-header-upda.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0161-staging-fsl-dpaa2-mac-Request-atomic-context-MC-port.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0162-staging-fsl-dpaa2-mac-Remove-redundant-free.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0163-staging-fsl-dpaa2-mac-Cleanup-code.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0164-staging-fsl-dpaa2-mac-Free-phydev-on-unbind.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0165-staging-fsl-dpaa2-mac-defer-probe-if-no-mc-portal-is.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0166-staging-fsl-dpaa2-mac-make-compatible-with-upstream-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0167-staging-fsl-dpaa2-mac-probe-phy-as-fixed-link-based-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0168-staging-fsl-dpaa2-mac-Fix-uninitialized-variable.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0169-staging-fsl-dpaa2-mac-read-phy-mode-from-device-tree.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0170-staging-fsl-dpaa2-mac-Add-more-PHY-modes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0171-staging-fsl-dpaa2-mac-Check-DPMAC-version.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0172-staging-fsl-dpaa2-mac-Fix-dpmac_set_link_state-comma.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0173-staging-fsl-dpaa2-mac-Add-support-for-new-link-state.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0174-staging-fsl-dpaa2-mac-Add-autoneg-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0175-staging-fsl-dpaa2-mac-connect-to-the-fixed-phy.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0176-staging-fsl-dpaa2-mac-add-pause-frames-support-for-m.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0177-staging-dpaa2-mac-Update-interface-mode-array.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0178-staging-dpaa2-mac-add-link-up-down-events-for-dpmac.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0179-staging-dpaa2-evb-Add-Edge-Virtual-Bridge-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0180-staging-dpaa2-evb-Fix-W-1-warnings.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0181-staging-dpaa2-evb-Improve-ethtool-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0182-staging-dpaa2-evb-Update-MTU-update-procedure.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0183-staging-dpaa2-evb-Update-netlink-parsing-parameters.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0184-staging-dpaa2-evb-Update-netdev_master_upper_dev_lin.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0185-staging-dpaa2-evb-Use-MC-portal-in-atomic-context.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0186-staging-dpaa2-evb-change-mc_command-in-fsl_mc_comman.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0187-staging-dpaa2-evb-Fix-MC-bus-include.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0188-staging-dpaa2-evb-Defer-probe-if-no-mc-portal-is-fou.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0189-staging-dpaa2-evb-Update-netlink-attributes-API.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0190-dpaa2-eth-Cleanup-dead-code.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0191-dpaa2-eth-Avoid-unbounded-while-loops.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0192-dpaa2-eth-Add-support-for-Rx-traffic-classes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0193-dpaa2-eth-Trim-debugfs-FQ-stats.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0194-dpaa2-eth-Distribute-ingress-frames-based-on-VLAN-pr.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0195-dpaa2-eth-Add-helper-functions.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0196-dpaa2-eth-Minor-cleanup-in-dpaa2_eth_set_rx_taildrop.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0197-dpaa2-eth-Add-congestion-group-taildrop.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0198-dpaa2-eth-Update-FQ-taildrop-threshold-and-buffer-po.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0199-dpaa2-eth-Add-DCB-ops.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0200-dpaa2-eth-Enable-Rx-PFC.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0201-dpaa2-eth-Enable-Tx-PFC.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0202-dpaa2-eth-Keep-congestion-group-taildrop-enabled-whe.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0203-dpaa2-eth-Add-Tx-shaping-API.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0204-dpaa2-eth-Add-Tx-shaping-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0205-dpaa2-eth-Add-Rx-error-queue.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0206-dpaa2-eth-Add-API-for-counters-reset.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0207-dpaa2-eth-Add-reset-controls-for-debugfs-stats.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0208-dpaa2-eth-Add-channel-stat.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0209-dpaa2-eth-Update-dpni_set_tx_shaping-cmd-to-v2.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0210-dpaa2-eth-Add-dpni_set_tx_priorities-API.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0211-dpaa2-eth-Update-dpni_get_statistics.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0212-dpaa2-eth-Add-API-for-ceetm_id-tc-in-set-congestion.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0213-dpaa2-eth-Add-CEETM-qdisc-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0214-dpaa2-eth-Re-add-get_link_ksettings-ethtool-op.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0215-dpaa2-eth-Add-support-for-new-link-state-APIs.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0216-dpaa2-eth-Add-autoneg-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0217-dpaa2-eth-Don-t-use-netif_receive_skb_list-for-TCP-f.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0218-bus-fsl-mc-Add-a-new-parameter-to-dprc_scan_objects-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0219-bus-fsl-mc-Extend-functions-from-the-bus-driver-to-b.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0220-bus-fsl-mc-Set-the-QMAN-BMAN-region-flags.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0221-soc-fsl-dpio-Adding-QMAN-multiple-enqueue-interface.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0222-soc-fsl-dpio-QMAN-performance-improvement.-Function-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0223-soc-fsl-dpio-Replace-QMAN-array-mode-by-ring-mode-en.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0224-bus-fsl-mc-add-autorescan-sysfs.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0225-enetc-Configure-the-Time-Aware-Scheduler-via-tc-tapr.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0226-enetc-update-TSN-Qbv-PSPEED-set-according-to-adjust-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0227-enetc-Fix-if_mode-extraction.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0228-enetc-Make-mdio-accessors-more-generic.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0229-enetc-Initialize-SerDes-for-SGMII-and-SXGMII-protoco.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0230-enetc-Drop-redundant-device-node-check.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0231-enetc-Use-DT-protocol-information-to-set-up-the-port.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0232-enetc-Handle-USXGMII-protocol.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0233-enetc-Enable-live-mac-addr-change-for-PF.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0234-enetc-WA-for-MDIO-register-access-issue.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0235-enetc-Clean-up-of-ehtool-stats-len.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0236-enetc-Replace-enetc_gregs-with-a-readers-writer-lock.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0237-enetc-Remove-mdio-bus-on-PF-probe-error-path.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0238-net-mscc-ocelot-break-apart-ocelot_vlan_port_apply.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0239-net-mscc-ocelot-break-apart-vlan-operations-into-oce.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0240-net-mscc-ocelot-break-out-fdb-operations-into-abstra.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0241-net-mscc-ocelot-change-prototypes-of-hwtstamping-ioc.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0242-net-mscc-ocelot-change-prototypes-of-switchdev-port-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0243-net-mscc-ocelot-refactor-struct-ocelot_port-out-of-f.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0244-net-mscc-ocelot-separate-net_device-related-items-ou.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0245-net-mscc-ocelot-refactor-ethtool-callbacks.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0246-net-mscc-ocelot-limit-vlan-ingress-filtering-to-actu.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0247-net-mscc-ocelot-move-port-initialization-into-separa.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0248-net-mscc-ocelot-separate-the-common-implementation-o.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0249-net-mscc-ocelot-initialize-list-of-multicast-address.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0250-net-mscc-ocelot-refactor-adjust_link-into-a-netdev-i.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0251-net-mscc-ocelot-split-assignment-of-the-cpu-port-int.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0252-net-mscc-ocelot-don-t-hardcode-the-number-of-the-CPU.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0253-net-mscc-ocelot-move-resource-ioremap-and-regmap-ini.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0254-net-mscc-ocelot-filter-out-ocelot-SoC-specific-PCS-c.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0255-net-mscc-ocelot-move-invariant-configs-out-of-adjust.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0256-net-mscc-ocelot-create-a-helper-for-changing-the-por.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0257-net-mscc-ocelot-export-a-constant-for-the-tag-length.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0258-net-mscc-ocelot-adjust-MTU-on-the-CPU-port-in-NPI-mo.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0259-net-mscc-ocelot-separate-the-implementation-of-switc.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0260-net-mscc-ocelot-publish-structure-definitions-to-inc.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0261-net-mscc-ocelot-publish-ocelot_sys.h-to-include-soc-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0262-net-dsa-ocelot-add-tagger-for-Ocelot-Felix-switches.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0263-net-dsa-ocelot-add-driver-for-Felix-switch-family.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0264-net-dsa-felix-Fix-CPU-port-assignment-when-not-last-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0265-net-mscc-ocelot-export-ocelot_hwstamp_get-set-functi.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0266-net-mscc-ocelot-convert-to-use-ocelot_get_txtstamp.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0267-net-mscc-ocelot-convert-to-use-ocelot_port_add_txtst.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0268-net-dsa-ocelot-define-PTP-registers-for-felix_vsc995.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0269-net-dsa-ocelot-add-hardware-timestamping-support-for.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0270-net-mscc-ocelot-avoid-incorrect-consuming-in-skbs-li.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0271-net-mscc-ocelot-use-skb-queue-instead-of-skbs-list.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0272-net-mscc-ocelot-tsn-configuration-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0273-net-dsa-ocelot-add-tsn-support-for-felix-switch.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0274-net-dsa-ocelot-alloc-memory-for-dsa-switch-instance.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0275-mii-Add-helpers-for-parsing-SGMII-auto-negotiation.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0276-net-phylink-make-QSGMII-a-valid-PHY-mode-for-in-band.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0277-net-phylink-call-mac_an_restart-for-SGMII-QSGMII-inb.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0278-enetc-export-enetc_mdio-definitionns-to-include-linu.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0279-enetc-Set-MDIO_CFG_HOLD-to-the-recommended-value-of-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0280-net-mscc-ocelot-do-not-force-Felix-MACs-at-lower-spe.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0281-net-mscc-ocelot-convert-to-PHYLINK.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0282-net-mscc-ocelot-introduce-more-focused-PCS-ops-for-P.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0283-net-dsa-felix-Add-PCS-operations-for-PHYLINK.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0284-net-fsl_ppfe-dts-binding-for-ppfe.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0285-staging-fsl_ppfe-eth-header-files-for-pfe-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0286-staging-fsl_ppfe-eth-introduce-pfe-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0287-staging-fsl_ppfe-eth-fix-RGMII-tx-delay-issue.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0288-staging-fsl_ppfe-eth-remove-unused-functions.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0289-staging-fsl_ppfe-eth-fix-read-write-ack-idx-issue.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0290-staging-fsl_ppfe-eth-Make-phy_ethtool_ksettings_get-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0291-staging-fsl_ppfe-eth-add-function-to-update-tmu-cred.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0292-staging-fsl_ppfe-eth-Avoid-packet-drop-at-TMU-queues.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0293-staging-fsl_ppfe-eth-Enable-PFE-in-clause-45-mode.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0294-staging-fsl_ppfe-eth-Disable-autonegotiation-for-2.5.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0295-staging-fsl_ppfe-eth-calculate-PFE_PKT_SIZE-with-SKB.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0296-staging-fsl_ppfe-eth-support-for-userspace-networkin.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0297-staging-fsl_ppfe-eth-unregister-netdev-after-pfe_phy.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0298-staging-fsl_ppfe-eth-HW-parse-results-for-DPDK.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0299-staging-fsl_ppfe-eth-reorganize-pfe_netdev_ops.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0300-staging-fsl_ppfe-eth-use-mask-for-rx-max-frame-len.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0301-staging-fsl_ppfe-eth-define-pfe-ndo_change_mtu-funct.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0302-staging-fsl_ppfe-eth-remove-jumbo-frame-enable-from-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0303-staging-fsl_ppfe-eth-disable-CRC-removal.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0304-staging-fsl_ppfe-eth-handle-ls1012a-errata_a010897.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0305-staging-fsl_ppfe-eth-replace-magic-numbers.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0306-staging-fsl_ppfe-eth-resolve-indentation-warning.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0307-staging-fsl_ppfe-eth-add-fixed-link-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0308-staging-fsl_ppfe-add-support-for-a-char-dev-for-link.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0309-staging-fsl_ppfe-enable-hif-event-from-userspace.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0310-staging-fsl_ppfe-performance-tuning-for-user-space.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0311-staging-fsl_ppfe-eth-Update-to-use-SPDX-identifiers.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0312-staging-fsl_ppfe-eth-misc-clean-up.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0313-staging-fsl_ppfe-eth-reorganize-platform-phy-paramet.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0314-staging-fsl_ppfe-eth-support-single-interface-initia.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0315-net-fsl_ppfe-update-dts-properties-for-phy.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0316-staging-fsl_ppfe-eth-remove-unused-code.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0317-staging-fsl_ppfe-eth-separate-mdio-init-from-mac-ini.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0318-staging-fsl_ppfe-eth-adapt-to-link-mode-based-phydev.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0319-staging-fsl_ppfe-eth-use-generic-soc_device-infra-in.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0320-staging-fsl_ppfe-eth-use-memremap-to-map-RAM-area-us.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0321-staging-fsl_ppfe-eth-remove-fallback-argument-from-d.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0322-staging-fsl_ppfe-eth-prefix-header-search-paths-with.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0323-staging-fsl_ppfe-eth-add-pfe-support-to-Kconfig-and-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0324-staging-fsl_ppfe-eth-Disable-termination-of-CRC-fwd.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0325-net-phy-add-10G-fixed-link-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0326-phy-Add-2.5G-SGMII-interface-mode.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0327-at803x-Address-packet-drops-at-low-traffic-rate-due-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0328-net-phy-Inphi-IN112525_s03-retimer-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0329-net-phy-Inphi-IN112525_s03-retimer-updates.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0330-net-phy-at803x-add-vddio-1v8-and-eee-disable-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0331-drivers-net-phy-aquantia-enable-AQR112-and-AQR412.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0332-drivers-net-phy-aquantia-fix-system-side-protocol-mi.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0333-drivers-net-phy-aquantia-enable-USX-AN-for-USXGMII-p.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0334-net-tsn-netlink-interface-for-APP-layer-to-config-TS.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0335-net-tsn-fix-headfile-voliates-the-new-rule.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0336-enetc-add-support-Credit-Based-Shaper-CBS-for-hardwa.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0337-enetc-add-support-tsn-capabilities-qbv-qci-qbu-cbs.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0338-net-dsa-felix-Fix-probing-allocation-and-cleanup-pat.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0339-LF-368-net-mscc-ocelot-hard-code-VCAP_PORT_CNT-for-F.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0340-LF-368-net-mscc-ocelot-make-ocelot_ace_rule-support-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0341-LF-368-net-mscc-ocelot-add-VCAP-IS2-rule-to-trap-PTP.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0342-LF-376-enetc-disable-EEE-autoneg-by-default.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0343-staging-dpaa2-ethsw-move-port-notifier-per-ethsw.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0344-staging-dpaa2-ethsw-move-port-switchdev-notifier-per.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0345-staging-dpaa2-ethsw-move-port-switchdev-blocking-not.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0346-staging-dpaa2-ethsw-ordered-workqueue-should-be-per-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0347-staging-fsl-dpaa2-mac-do-not-call-dpmac_set_link_sta.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0348-staging-fsl-dpaa2-mac-reverse-order-of-handling-stop.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0349-fsl_qbman-add-dummy-functions-for-probe-deferal-APIs.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0350-sdk_fman-fix-identation-causing-compilation-warnings.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0351-sdk_fman-address-compilation-warning.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0352-soc-fsl-dpio-Enable-ACP-port-in-Linux-QMAN-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0353-staging-fsl-dpaa2-mac-do-not-stop-MAC-when-the-net_d.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0354-bus-fsl-mc-add-the-dpdbg-device-type.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0355-sdk_fman-decrease-log-severity-levels.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0356-sdk_dpaa-ethtool-drop-unused-variable.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0357-sdk_dpaa-ls1043a-errata-memory-related-fixes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0358-sdk_dpaa-ls1043a-errata-update-and-optimize-the-rest.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0359-sdk_dpaa-ls1043a-errata-re-enable-SG-support-and-rec.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0360-sdk_dpaa-sdk_fman-ls1043a-errata-detect-based-on-DTB.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0361-sdk_dpaa-sdk_fman-ls1034a-errata-update-number-to-A0.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0362-sdk_dpaa-ceetm-remove-references-to-qdisc_lookup.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0363-sdk_dpaa-ceetm-export-the-ceetm_tx-symbol.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0364-sdk_dpaa-ceetm-enable-building-as-a-module.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0365-sdk_dpaa-ceetm-coding-style-cleanup.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0366-LF-697-net-ethernet-freescale-sdk_fman-fix-the-build.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0367-net-mscc-ocelot-Workaround-to-allow-traffic-to-CPU-i.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0368-Revert-net-dsa-felix-Add-PCS-operations-for-PHYLINK.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0369-Revert-net-mscc-ocelot-introduce-more-focused-PCS-op.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0370-Revert-net-mscc-ocelot-convert-to-PHYLINK.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0371-Revert-net-mscc-ocelot-do-not-force-Felix-MACs-at-lo.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0372-Revert-enetc-Set-MDIO_CFG_HOLD-to-the-recommended-va.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0373-Revert-enetc-export-enetc_mdio-definitionns-to-inclu.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0374-Revert-net-phylink-call-mac_an_restart-for-SGMII-QSG.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0375-Revert-net-phylink-make-QSGMII-a-valid-PHY-mode-for-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0376-Revert-mii-Add-helpers-for-parsing-SGMII-auto-negoti.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0377-net-dsa-ocelot-add-NET_VENDOR_MICROSEMI-dependency.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0378-mii-Add-helpers-for-parsing-SGMII-auto-negotiation.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0379-net-phylink-make-QSGMII-a-valid-PHY-mode-for-in-band.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0380-net-phylink-add-support-for-polling-MAC-PCS.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0381-net-dsa-Pass-pcs_poll-flag-from-driver-to-PHYLINK.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0382-enetc-Make-MDIO-accessors-more-generic-and-export-to.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0383-enetc-Set-MDIO_CFG_HOLD-to-the-recommended-value-of-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0384-net-mscc-ocelot-make-phy_mode-a-member-of-the-common.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0385-net-mscc-ocelot-export-ANA-DEV-and-QSYS-registers-to.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0386-net-dsa-felix-Add-PCS-operations-for-PHYLINK.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0387-net-phy-vsc8514-enable-in-band-SGMII-auto-negotiatio.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0388-drivers-net-phy-aquantia-Add-XFI-counters.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0389-drivers-net-felix-set-link-based-on-BMSR-not-LPA.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0390-drivers-net-phylink-in-band-AN-for-USXGMII.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0391-drivers-net-phy-don-t-crash-in-phy_read-_write_mmd-w.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0392-drivers-net-dsa-felix-Allow-PHY-to-AN-10-100-1000-wi.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0393-drivers-net-dsa-felix-Handle-PAUSE-Rx-regardless-of-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0394-drivers-net-mscc_ocelot-don-t-flood-unicast-traffic-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0395-LF-183-sdk_fman-add-an-option-for-RTC-1588-timer-ini.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0396-LF-183-ptp-depend-on-FSL_SDK_FMAN_RTC_API-for-ptp_qo.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0397-sdk_dpaa-ceetm-fix-recursive-dependencies.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0398-enetc-add-ioctl-support-for-PHY-related-ops.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0399-staging-fsl_ppfe-eth-Enhance-error-checking-in-platf.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0400-drivers-staging-fsl_qbman-Disable-Portal-Channel-IRQ.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0401-fsl_qbman-Framework-for-enabling-Link-status-notific.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0402-drivers-net-dsa-felix-don-t-restart-PCS-SGMII-AN-if-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0403-net-dsa-felix-Don-t-error-out-on-disabled-ports-with.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0404-LF-457-ocelot-tsn-clean-preempt-interrupt-status.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0406-sdk_qbman-Only-create-debugfs-entries-when-QBMan-is-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/701-net-0407-LF-924-net-enetc-Set-MAC-Rx-FIFO-to-recommended-valu.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0001-Revert-ASoC-fsl_sai-Fix-noise-when-using-EDMA.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0002-Revert-ASoC-fsl_sai-Implement-set_bclk_ratio.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0003-Revert-ASoC-fsl_sai-Add-support-for-imx8qm.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0004-Revert-ASoC-fsl_sai-Add-support-for-imx7ulp-imx8mq.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0005-Revert-ASoC-fsl_sai-Add-support-for-SAI-new-version.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0006-Revert-ASoC-fsl_sai-Update-Tx-Rx-channel-enable-mask.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0007-Revert-ASoC-fsl_sai-Add-registers-definition-for-mul.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0008-Revert-ASoC-Remove-dev_err-usage-after-platform_get_.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0009-Revert-ASoC-fsl_sai-mark-regmap-as-fast_io.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0010-Revert-ASoC-fsl_sai-derive-TX-FIFO-watermark-from-FI.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0011-Revert-ASoC-fsl_sai-add-of_match-data.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0012-MLK-9974-ASoC-fsl_sai-There-is-underrun-detected-in-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0013-MLK-10611-1-ASoC-fsl-sai-Just-one-device-can-playbac.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0014-MLK-11628-ASoC-fsl_sai-add-initial-value-for-is_slav.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0015-ASoC-fsl-sai-set-xCR4-xCR5-xMR-for-SAI-master-mode.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0016-MLK-12374-ASoC-fsl_sai-Change-the-dev_warn-to-dev_db.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0017-MLK-12786-2-ASoC-fsl_sai-correct-the-clock-source-fo.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0018-MLK-13574-2-ASoC-fsl_sai-refine-driver-for-ip-upgrad.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0019-MLK-13609-ASoC-fsl_sai-fix-for-synchronize-mode.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0020-ASoC-fsl_-e-sai-introduce-shared-interrupt-DT-flag-p.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0021-ASoC-fsl_sai-handle-slave-mode-per-TX-RX-direction.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0022-ASoC-fsl_sai-set-specific-fmt-for-I2S-XTOR.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0023-ASoC-fsl-add-imx-pcm-dma-v2-platform-driver-part-2.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0024-MLK-14847-Revert-ASoC-fsl-sai-set-xCR4-xCR5-xMR-for-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0025-MLK-14870-ASoC-fsl_sai-Remove-support-for-S20_3LE.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0026-MLK-14935-ASoC-fsl_sai-Fix-mixing-initialization-dat.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0027-MLK-15140-1-ASoC-fsl_sai-support-latest-sai-module.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0028-MLK-15927-1-ASoC-fsl_sai-Fix-noise-when-using-EDMA.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0029-MLK-15960-1-ASoC-fsl_sai-update-fifo_depth-for-diffe.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0030-MLK-15960-2-ASoC-fsl_sai-refine-the-pm-runtime-funct.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0031-MLK-13975-ASoC-fsl_sai-Refine-master-flag-handling.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0032-MLK-16130-1-ASoC-fsl_sai-enable-TCE-RCE-according-to.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0033-MLK-13946-3-ASoC-fsl_sai-fix-the-xMR-setting.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0034-MLK-13946-8-ASoC-fsl_sai-use-min-channels-slots-for-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0035-MLK-16929-1-ASoC-fsl_sai-add-bitclk_freq.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0036-MLK-17442-ASoC-fsl-fix-wrong-usage-of-filter_data-pa.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0037-MLK-16224-4-ASoC-fsl_sai-support-multi-fifo-and-DSD.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0038-MLK-17467-ASoC-fsl_sai-fix-typo-for-fsl_sai.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0039-MLK-16224-6-ASoC-fsl_sai-fix-DSD-suspend-resume.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0040-MLK-17428-8-ASoC-fsl_sai-support-768KHz-sample-rate.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0041-MLK-17485-ASoC-fsl_sai-Specify-supported-rate_min-an.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0042-MLK-17566-ASoC-fsl_sai-fix-register-definition.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0043-MLK-17528-1-ASoC-fsl_sai-Introduce-FSL_SAI_CLK_BIT-c.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0044-MLK-17528-3-ASoC-fsl_sai-Set-clock-rate-in-set_syscl.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0045-MLK-17156-1-ASoC-fsl_sai-update-register-offset-for-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0046-Sound-Soc-fsl-Set-SAI-Channel-Mode-to-Output-Mode.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0047-MLK-17580-ASoC-fsl-dsd-Add-DSD-utilities-helper.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0048-MLK-17580-ASoC-fsl-sai-Use-DSD-helper.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0049-MLK-17580-ASoC-fsl-sai-check-for-pinctrl-status.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0050-MLK-17531-1-ASoC-fsl-sai-add-support-for-SAI-v3.01.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0051-MLK-18534-1-ASoC-fsl-sai-introduce-1-1-bclk-mclk-rat.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0052-MLK-18682-1-ASoC-fsl-sai-use-set_bclk_ratio-to-calcu.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0053-MLK-18682-2-ASoC-fsl-sai-allow-dynamic-pll-switching.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0054-MLK-18947-ASoC-fsl_sai-fix-volatile-function.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0055-MLK-18898-1-ASoC-fsl_sai-select-pinctrl-state-as-fun.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0056-MLK-19573-1-ASoC-fsl-dsd-make-fsl_get_pins_state-inl.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0057-MLK-15975-3-ASoC-fsl_sai-The-offset-of-fifo_off-is-c.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0058-MLK-20189-8-ASoC-fsl_sai-use-signed-offset-variable.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0059-MLK-20328-1-ASoC-fsl_sai-map-number-of-pins-to-datal.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0060-ASoC-fsl_sai-Support-EPROBE_DEFER.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0061-ASoC-fsl_sai-support-multi-power-domain.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0062-ASoC-fsl-sai-fix-build-failture-due-to-5.1-RC7-upgra.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0063-MLK-21876-4-ASoC-fsl-sai-fix-build-for-next-20190524.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0064-ASoC-fsl_sai-Mark-cache-dirty-at-resume.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0065-LF-106-ASoC-fsl_sai-request-BUS_FREQ_AUDIO.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0066-MLK-16224-2-ASoC-dmaengine_pcm-add-fifo_num-to-snd_d.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0067-Revert-MLK-17442-ASoC-fsl-fix-wrong-usage-of-filter_.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0068-Revert-ASoC-fsl-add-imx-pcm-dma-v2-platform-driver-p.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0069-MLK-21484-4-ASoC-fsl_sai-ensure-clk-not-in-use-prior.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0070-MLK-21957-1-ASoC-fsl_sai-remove-reset-code-from-dai_.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0071-MLK-21957-2-ASoC-fsl_sai-read-SAI-version-and-params.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0072-MLK-22522-ASoC-fsl_sai-fix-stack-out-of-bounds-KASAN.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0073-MLK-21957-3-ASoC-fsl_sai-add-bitcount-and-timestamp-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/801-audio-0074-ASoC-fsl_sai-fix-build-issue-of-incomplete-parenthes.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0001-imx-busfreq-Add-API-header-file.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0002-can-rx-offload-fix-long-lines.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0003-can-rx-offload-can_rx_offload_compare-fix-typo.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0004-can-rx-offload-can_rx_offload_irq_offload_timestamp-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0005-can-rx-offload-can_rx_offload_reset-remove-no-op-fun.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0006-can-rx-offload-Prepare-for-CAN-FD-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0007-can-flexcan-use-devm_platform_ioremap_resource-to-si.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0008-can-flexcan-flexcan_irq_state-only-read-timestamp-if.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0009-can-flexcan-rename-macro-FLEXCAN_IFLAG_MB-FLEXCAN_IF.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0010-can-flexcan-flexcan_irq-rename-variable-reg_iflag-re.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0011-can-flexcan-rename-struct-flexcan_priv-reg_imask-1-2.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0012-can-flexcan-remove-TX-mailbox-bit-from-struct-flexca.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0013-can-flexcan-convert-struct-flexcan_priv-rx_mask-1-2-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0014-can-flexcan-introduce-struct-flexcan_priv-tx_mask-an.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0015-can-flexcan-flexcan_read_reg_iflag_rx-optimize-readi.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0016-can-flexcan-flexcan_irq-add-support-for-TX-mailbox-i.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0017-can-flexcan-flexcan_mailbox_read-make-use-of-flexcan.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0018-can-flexcan-use-struct-canfd_frame-for-CAN-classic-f.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0019-can-flexcan-add-CAN-FD-mode-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0020-can-flexcan-add-CAN-FD-BRS-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0021-can-flexcan-add-ISO-CAN-FD-feature-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0022-can-flexcan-add-Transceiver-Delay-Compensation-suopp.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0023-can-flexcan-add-imx8qm-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0024-can-flexcan-add-lx2160ar1-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0025-can-flexcan-add-LPSR-mode-support-for-i.MX7D.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0026-can-flexcan-fix-deadlock-when-using-self-wakeup.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0027-can-flexcan-add-CAN-wakeup-function-for-i.MX8.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/802-can-0028-can-flexcan-Add-S32V234-support-to-FlexCAN-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/803-clock-0001-clk-ls1028a-Add-clock-driver-for-Display-output-inte.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0001-crypto-add-support-for-TLS-1.0-record-encryption.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0002-crypto-tcrypt-include-rsa-test.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0003-crypto-caam-use-mapped_-src-dst-_nents-for-descripto.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0004-crypto-caam-use-devres-to-unmap-memory.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0005-crypto-caam-use-devres-to-remove-debugfs.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0006-crypto-caam-use-devres-to-de-initialize-the-RNG.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0007-crypto-caam-use-devres-to-de-initialize-QI.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0008-crypto-caam-use-devres-to-populate-platform-devices.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0009-crypto-caam-populate-platform-devices-last.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0010-MLK-9769-1-crypto-caam-jr-remove-incorrect-comment-f.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0011-MLK-20204-crypto-caam-remove-deadcode-on-32-bit-plat.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0012-MLK-19053-crypto-caam-RNG4-TRNG-errata.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0013-MLK-9769-9-crypto-caam-adjust-RNG-timing-to-support-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0014-MLK-9769-8-crypto-caam-add-a-test-for-the-RNG.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0015-MLKU-123-1-crypto-caam-add-support-for-i.mx8mm-mn.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0016-MLKU-114-1-crypto-caam-reduce-page-0-regs-access-to-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0017-MLKU-114-2-crypto-caam-SCU-firmware-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0018-MLKU-114-3-crypto-caam-OP-TEE-firmware-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0019-MLKU-38-3-crypto-caam-add-SNVS-SECVIO-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0020-MLKU-25-3-crypto-caam-add-Secure-Memory-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0021-MLK-19801-1-crypto-caam-add-tag-functionality.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0022-MLK-19801-2-crypto-caam-add-support-of-tagged-keys-i.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0023-MLK-10036-crypto-caam-add-support-for-DSM-with-Mega-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0024-MLK-19449-crypto-caam-Change-structure-type-represen.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0025-crypto-caam-qi2-add-unused-dpseci-API.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0026-crypto-caam-qi2-add-OPR-Order-Preservation-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0027-crypto-caam-add-support-for-MOVEB-command.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0028-crypto-caam-qi-add-support-for-TLS-1.0-record.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0029-crypto-caam-qi2-add-support-for-TLS-1.0-record.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0030-crypto-caam-add-functionality-used-by-the-caam_dma-d.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0031-crypto-caam-add-caam_dma-device-on-caam_probe.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0032-crypto-caam-add-CAAM-job-ring-UIO-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0033-LFV-26-crypto-caam-fix-Secure-Memory-driver-init.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0034-LF-63-1-crypto-caam-fix-SM-test-init.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0035-crypto-caam-qi-use-QBMan-NXP-SDK-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0036-LF-933-crypto-caam-fix-iosource-busy-issue.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0038-LF-838-crypto-caam-increase-the-domain-of-write-memo.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0040-LF-292-1-crypto-caam-refactor-RNG-initialization.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/804-crypto-0041-LF-292-2-crypto-caam-add-power-management.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0001-drm-arm-mali-dp-Add-display-QoS-interface-configurat.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0002-drm-rockchip-prepare-common-code-for-cdns-and-rk-dpi.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0003-drm-bridge-add-Cadence-MHDP-HDMI-DP-API.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0004-drm-bridge-Add-Cadence-DP-HDMI-core-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0005-gpu-drm-Add-imx8qm-mq-DP-HDMI-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0006-drm-bridge-cadence-Add-new-api-functions.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0007-drm-bridge-cadence-Add-mhdp-audio-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0008-drm-bridge-cadence-Add-CEC-driver-for-cdns-mhdp-hdmi.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0009-drm-rockchip-Fix-build-failed-issue.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0010-drm-bridge-cadence-move-struct-imx_mhdp_device-to-dr.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0011-drm-imx-add-imx8mq-hdmi-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0012-drm-rockchip-change-base-address-name-from-regs-to-r.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0013-drm-bridge-cadence-Add-power_on-to-__cdns_dp_probe.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0014-drm-ls1028a-Add-DP-driver-support-for-LS1028A.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0015-drm-bridge-cadence-Add-support-for-periodically-poll.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0016-drm-imx-hdmi-support-arc-function.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0017-drm-bridge-cadence-Fix-return-value-for-set-log-addr.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0018-drm-bridge-cdns-dp-Remove-link-rate-lanes-set-by-dev.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0019-drm-imx-mhdp-add-dual-mode-support-for-imx8qm.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0020-drm-bridge-cdns-cec-fix-LA-failed-set-issue.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0021-DRM-mhdp-HDMI-skip-scdc-write-return-check.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0022-drm-mhdp-add-mutex-lock-to-mhdp-register-access-func.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0023-drm-mhdp-reset-video-mode-after-hdmi-dp-cable-plugin.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0024-drm-bridge-cadence-hdmi-remove-video-mode-limition.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0025-drm-imx-hdp-add-hdr10-metadata-property.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0026-drm-imx-hdp-add-colorspace-property.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0027-drm-imx-hdp-force-a-mode-set-when-colorspace-is-chan.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0028-drm-imx-hdp-handle-the-various-deep-color-settings.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0029-drm-imx-mhdp-Adjustment-core-rate-of-DP-TX-CTRL-for-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0030-drm-imx-hdp-fix-issue-with-non-SCDC-HDMI-sinks.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0031-Revert-drm-imx-hdp-fix-issue-with-non-SCDC-HDMI-sink.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0032-drm-hdmi-imx8-fix-wrong-hdmi-type-with-non-SCDC-HDMI.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0033-LF-94-drm-hdmi-imx-Add-hdmi-phy-video-mode-valid-fun.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0034-media-bus-format-Add-RGB888_1X30_PADLO-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0035-media-bus-format-Add-RGB666_1X30_PADLO-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0036-media-bus-format-Add-RGB101010_1X7X5_SPWG-JEIDA-supp.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0037-MLK-15110-1-drm-fourcc-Add-Amphion-tiled-layout-form.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0038-MLK-16290-drm-Add-drm_of_component_probe_with_match-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0039-MLK-17368-1-drm-add-fourcc-codes-for-Verisilicon-til.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0040-drm-fourcc-add-modifier-for-vivante-compressed-tiled.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0041-drm-fourcc-add-a-10bits-fully-packed-variant-of-NV12.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0042-drm-imx-Revert-a-patch-which-merges-imx-drm-core-and.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0043-gpu-Move-ipu-v3-to-imx-folder.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0044-drm-imx-Extract-IPUv3-specific-KMS-functions-to-ipuv.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0045-drm-imx-Add-DPU-KMS-support-part-2.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0046-MLK-22171-drm-imx-Avoid-leaking-dangling-pointer-dev.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0047-MLK-18535-6-drm-imx-core-add-LCDIF-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0048-Revert-drm-imx-Extract-IPUv3-specific-KMS-functions-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0049-Revert-gpu-Move-ipu-v3-to-imx-folder.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0050-Revert-drm-imx-Revert-a-patch-which-merges-imx-drm-c.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0051-LF-296-drm-mhdp-build-mhdp-sub-modules-into-one-driv.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0052-LF-323-1-drm-bridge-cdns-move-link-training-to-bridg.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0053-LF-323-2-drm-bridge-cdns-enhance-link-training-stabi.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0054-LF-568-1-drm-bridge-cdns-dp-change-bridge_enable-dis.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0055-LF-568-2-drm-gpu-bridge-cdns-Add-force-mode-set-flag.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0056-LF-794-3-gpu-cdn-imx8qm-Add-firmware-loading-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/805-display-0057-LF-794-4-gpu-cdn-mhdp-common-Increase-the-check-aliv.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0001-dmaengine-fsl-dpaa2-qdma-Add-the-DPDMAI-Data-Path-DM.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0002-dmaengine-fsl-dpaa2-qdma-Add-NXP-dpaa2-qDMA-controll.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0003-MLK-14610-DMA-fsl-edma-v3-add-fsl-edma-v3-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0004-MLK-15003-1-DMA-fsl-edma-v3-add-one-more-parameter-f.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0005-MLK-15003-2-Document-fsl_edma_v3-update-document.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0006-MLK-15014-dma-fsl-edma-v3-clear-DONE-before-E_SG-ena.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0007-MLK-15330-1-dma-fsl-edma-v3-combine-two-cells-into-o.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0008-MLK-15330-3-dma-fsl-edma-v3-add-dual-fifo-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0009-MLK-16327-1-dma-fsl-edma-v3-make-exclusive-channel-n.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0010-MLK-16437-dma-fsl-edma-v3-fix-kernel-crash-while-edm.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0011-MLK-16482-dma-fsl-edma-v3-Fix-RCU-issue-while-playin.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0012-MLK-17094-dma-fsl-edma-v3-add-suspend-resume-to-rest.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0013-MLK-17782-dma-fsl-edma-v3-fix-issue-reported-by-Cove.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0014-MLK-18248-dma-fsl-edma-v3-avoid-touch-unused-edma-ch.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0015-MLK-19022-2-dmaengine-fsl-edma-v3-add-device_synchro.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0016-MLK-19931-1-dmaengine-fsl-edma-v3-fix-potential-kern.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0017-MLK-20205-1-dmaengine-fsl-edma-v3-fix-NULL-pointer-d.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0018-dma-imx-add-the-32bit-dma-limitation.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0019-dmaengine-fsl-edma-calculate-the-real-count-for-slav.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0020-MLK-22798-1-dmaengine-fsl-edma-v3-do-not-enable-inte.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0021-MLK-21443-dmaengine-fsl-edma-v3-clear-pending-irq-be.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0022-MLK-22284-1-dmaengine-fsl-edma-v3-add-power-domains-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0023-MLK-22284-2-dmaengine-fsl-edma-v3-check-dma-descript.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0024-MLK-22302-2-dmaengine-fsl-edma-v3-fix-build-warning-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0025-MLK-22909-dmaengine-fsl-edma-v3-clear-interrupt-comi.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0026-dma-caam-add-dma-memcpy-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0027-dma-caam-fix-compilation-error.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/806-dma-0028-dmaengine-fsl-edma-Add-eDMA-support-for-QorIQ-LS1028.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/807-gpio-0001-gpio-mpc8xxx-change-irq-handler-from-chained-to-norm.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/807-gpio-0002-gpio-mpc8xxx-ls1088a-ls1028a-edge-detection-mode-bug.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0001-MLK-16095-01-i2c-mux-pca954x-add-i2c-bus-switch-PCA9.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0002-MLK-10893-i2c-imx-add-irqf_no_suspend.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0003-MLK-11403-I2C-imx-restore-pin-setting-for-i2c.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0004-MLK-16203-enable-runtime-pm-of-i2c-temporary-when-do.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0005-MLK-20773-i2c-imx-add-a-limit-of-maximum-transfer-sp.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0006-MLK-20368-i2c-imx-Coverity-fix-divide-by-zero-warnin.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0007-i2c-imx-add-workaround-for-erratum-ERR010027.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0008-i2c-imx-implement-bus-recovery-with-gpio-for-Layersc.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0009-i2c-imx-get-rid-of-CONFIG_ARCH_LAYERSCAPE.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0010-i2c-imx-fix-system-hang-due-to-access-i2c-registers-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0011-i2c-imx-support-slave-mode-for-imx-I2C-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0012-i2c-imx-correct-code-of-errata-A-010650-for-layersca.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0013-LF-98-i2c-imx-fix-the-judgement-of-slave-mode-in-isr.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0014-i2c-mux-pca954x-support-property-idle-state.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0015-LF-263-2-i2c-imx-increase-PM-timeout-to-avoid-operat.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/808-i2c-0016-LF-162-i2c-imx-Defer-probing-if-EDMA-not-available.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0001-ivshmem-net-virtual-network-device-for-Jailhouse.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0002-ivshmem-net-Map-shmem-region-as-RAM.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0003-ivshmem-net-fix-race-in-state-machine.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0004-ivshmem-net-Remove-unused-variable.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0005-ivshmem-net-Enable-INTx.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0006-ivshmem-net-Improve-identification-of-resources.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0007-ivshmem-net-Switch-to-reset-state-on-each-net-stop-a.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0008-ivshmem-net-Add-ethtool-register-dump.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0009-ivshmem-net-Fix-stuck-state-machine-during-setup.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0010-ivshmem-net-Switch-to-relative-descriptor-addresses.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0011-ivshmem-net-Switch-to-pci_alloc_irq_vectors.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0012-ivshmem-net-fill-in-and-check-used-descriptor-chain-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0013-ivshmem-net-slightly-improve-debug-output.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0014-ivshmem-net-set-and-check-descriptor-flags.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0015-ivshmem-net-add-MAC-changing-interface.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0016-ivshmem-net-Silence-compiler-warning.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0017-ivshmem-net-Fix-bogus-transition-to-RESET-state.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0018-ivshmem-net-Refactor-and-comment-ivshm_net_state_cha.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0019-ivshmem-net-Switch-to-netdev_xmit_more-helper.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0020-jailhouse-Add-simple-debug-console-via-the-hyperviso.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/809-jailhouse-0021-arm64-export-__hyp_stub_vectors.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/810-keys-0001-security-keys-secure_key-Adds-the-secure-key-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/810-keys-0002-encrypted_keys-Adds-support-for-secure-key-type-as-m.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/810-keys-0003-security-keys-secure_key-Fix-the-path-of-included-he.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/811-kvm-0001-arm64-KVM-support-flushing-device-memory.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/811-kvm-0002-arm-arm64-KVM-allow-specifying-s2-prot-bits-when-map.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/811-kvm-0003-arm-arm64-KVM-drop-qman-mmio-cacheable-mapping-hack.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/811-kvm-0004-virt-vgic-Increase-number-of-DeviceIDs-to-17.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0001-PCI-layerscape-Add-LS1028a-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0002-PCI-dwc-Use-interrupt-disabling-instead-of-masking.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0003-PCI-dwc-fix-the-msi-failure-after-pm-operations.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0004-pci-add-support-aer-pme-interrupts-with-none-MSI-MSI.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0005-MLK-20684-PCI-Disable-MSI-on-CYW4356-and-CYW4359-chi.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0006-MLK-20716-PCI-add-quirk-for-cyw4356-to-disable-D3-mo.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0007-PCI-Disable-MSI-on-marvel-88w9098-and-88w8997-chips.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0008-Revert-PCI-mobiveil-Fix-csr_read-write-build-issue.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0009-PCI-mobiveil-Refactor-Mobiveil-PCIe-Host-Bridge-IP-d.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0010-PCI-mobiveil-Make-mobiveil_host_init-can-be-used-to-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0011-PCI-mobiveil-Add-8-bit-and-16-bit-CSR-register-acces.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0012-PCI-mobiveil-Add-PCIe-Gen4-RC-driver-for-NXP-Layersc.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0013-PCI-mobiveil-ls_pcie_g4-add-Workaround-for-A-011577.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0014-PCI-mobiveil-ls_pcie_g4-add-Workaround-for-A-011451.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0015-PCI-ls_gen4-WA-for-SERROR.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0016-PCI-mobiveil-Add-the-EP-driver-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0017-PCI-mobiveil-Add-PCIe-Gen4-EP-driver-for-NXP-Layersc.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0018-PCI-mobiveil-Add-workaround-for-unsupported-request-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/812-pcie-0019-misc-pci_endpoint_test-Add-the-layerscape-PCIe-GEN4-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/813-pm-0001-soc-fsl-add-RCPM-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/813-pm-0002-fsl_pmc-update-device-bindings.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/813-pm-0003-drivers-soc-fsl-add-EPU-FSM-configuration-for-deep-s.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/813-pm-0004-PM-wakeup-Add-routine-to-help-fetch-wakeup-source-ob.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/813-pm-0005-soc-fsl-handle-RCPM-errata-A-008646-on-SoC-LS1021A.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/813-pm-0006-soc-fsl-rcpm-remove-build-warning.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/814-qe-0001-irqchip-qeic-move-qeic-driver-from-drivers-soc-fsl-q.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/814-qe-0002-irqchip-qeic-merge-qeic-init-code-from-platforms-to-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/814-qe-0003-irqchip-qeic-merge-qeic_of_init-into-qe_ic_init.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/814-qe-0004-irqchip-qeic-remove-PPCisms-for-QEIC.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/814-qe-0005-QE-remove-PPCisms-for-QE.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/814-qe-0006-config-qe-add-irq-qeic-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/815-sata-0001-ahci-qoriq-enable-acpi-support-in-qoriq-ahci-driver.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/815-sata-0002-ahci-qoriq-workaround-for-errata-A-379364-on-lx2160a.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/815-sata-0003-ahci_qoriq-bug-fix-for-ecc_addr.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/816-sdhc-0001-mmc-sdhci-of-esdhc-poll-ESDHC_FLUSH_ASYNC_FIFO-bit-u.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/816-sdhc-0002-LF-605-mmc-sdhci-of-esdhc-convert-to-use-esdhc_tunin.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/816-sdhc-0003-LF-605-mmc-sdhci-of-esdhc-update-tuning-erratum-A-00.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/817-spi-0001-spi-spi-fsl-qspi-dynamically-alloc-AHB-memory-for-QS.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/817-spi-0002-spi-spi-fsl-qspi-Introduce-variable-to-fix-different.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/817-spi-0003-MLK-21960-1-spi-fspi-enable-fspi-on-imx8qxp-and-imx8.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/817-spi-0004-MLK-21960-2-spi-fspi-dynamically-alloc-AHB-memory.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/817-spi-0005-spi-spi-nxp-fspi-Enable-the-Octal-Mode-in-MCR0.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/817-spi-0006-LF-20-2-mtd-spi-nor-Use-1-bit-mode-of-spansion-s25fs.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/817-spi-0007-LF-18-3-spi-fsl-qspi-Allocate-AHB-memory-dynamically.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/818-thermal-0001-thermal-Add-generic-device-cooling-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/818-thermal-0002-thermal-qoriq-Add-device-cooling-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/818-thermal-0003-thermal-qoriq-add-thermal-monitor-unit-version-2-sup.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/819-uart-0001-tty-serial-lpuart-add-power-domain-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/819-uart-0002-tty-serial-fsl_lpuart-add-modem-device-reset.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/819-uart-0003-tty-serial-fsl_lpuart-add-magic-SysRq-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/819-uart-0004-MLK-18137-fsl_lpuart-Fix-loopback-mode.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/819-uart-0005-tty-serial-fsl_lpuart-enable-dma-mode-for-imx8qxp.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/819-uart-0006-tty-serial-fsl_lpuart-enable-loopback-mode.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/819-uart-0007-MLK-15094-tty-serial-fsl_lpuart-check-dma_tx_in_prog.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/819-uart-0008-MLK-21445-serial-fsl_lpuart-do-HW-reset-for-communic.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/819-uart-0009-MLK-17133-02-tty-serial-lpuart-add-runtime-pm-suppor.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/819-uart-0010-tty-serial-lpuart-enable-wakeup-source-for-lpuart.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/819-uart-0011-serial-fsl_lpuart-enable-two-stop-bits.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/819-uart-0012-tty-serial-lpuart-add-LS1028A-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/819-uart-0013-LF-484-tty-serial-lpuart-support-UPIO_MEM32-for-lpua.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0001-MLK-11340-26-usb-phy-add-notify-suspend-and-resume-c.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0002-MLK-14285-1-usb-phy-add-usb-mode-for-usb_phy.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0003-usb-phy-show-USB-charger-type-for-user.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0004-usb-dwc3-use-suspend-clock-from-dt-to-set-power-down.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0005-usb-dwc3-add-otg-properties-update.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0006-usb-dwc3-drd-add-usb-role-switch-class-support-for-d.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0007-usb-dwc3-gadget-increase-timeout-value-for-send-ep-c.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0008-usb-dwc3-set-fwnode-for-role-switch.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0009-usb-dwc3-Add-workaround-for-host-mode-VBUS-glitch-wh.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0010-MLK-22675-usb-dwc3-host-disable-park-mode.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0011-usb-dwc3-Add-cache-type-configuration-support.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0012-MLK-11340-40-usb-whitelist-update-otg-eh-s-TPL-for-f.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0013-MLK-9785-1-usb-host-ehci-hcd-enable-park-mode.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0014-MLK-17380-3-usb-move-EH-SINGLE_STEP_SET_FEATURE-impl.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0015-MLK-17380-4-usb-host-xhci-add-EH-SINGLE_STEP_SET_FEA.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0016-MLK-16735-usb-host-add-XHCI_CDNS_HOST-flag.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0017-MLK-19153-2-usb-host-xhci-do-not-return-error-status.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0018-MLK-18794-1-usb-host-xhci-add-.bus_suspend-override.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0019-MLK-9829-usb-core-print-suggested-message-if-failed-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0020-MLK-16604-1-usb-host-xhci-plat-add-XHCI_MISSING_CAS-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0021-MLK-22099-usb-host-xhci-do-warm-reset-for-link-state.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0022-usb-fsl-Remove-unused-variable.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0023-usb-gadget-Correct-NULL-pointer-checking-in-fsl-gadg.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0024-LF-387-1-Revert-usb-dwc3-Add-cache-type-configuratio.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/820-usb-0025-LF-387-4-usb-dwc3-Add-cache-type-configuration-suppo.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/821-vfio-0001-vfio-fsl-mc-Add-VFIO-framework-skeleton-for-fsl-mc-d.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/821-vfio-0002-vfio-fsl-mc-Scan-DPRC-objects-on-vfio-fsl-mc-driver-.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/821-vfio-0003-vfio-fsl-mc-Implement-VFIO_DEVICE_GET_INFO-ioctl.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/821-vfio-0004-vfio-fsl-mc-Implement-VFIO_DEVICE_GET_REGION_INFO-io.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/821-vfio-0005-vfio-fsl-mc-Allow-userspace-to-MMAP-fsl-mc-device-MM.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/821-vfio-0006-vfio-fsl-mc-Added-lock-support-in-preparation-for-in.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/821-vfio-0007-vfio-fsl-mc-Add-irq-infrastructure-for-fsl-mc-device.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/821-vfio-0008-vfio-fsl-mc-trigger-an-interrupt-via-eventfd.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/821-vfio-0009-vfio-fsl-mc-Add-read-write-support-for-fsl-mc-device.patch [new file with mode: 0644]
target/linux/layerscape/patches-5.4/821-vfio-0010-vfio-fsl-mc-Map-the-VFIO-region-according-to-the-fla.patch [new file with mode: 0644]

diff --git a/target/linux/layerscape/patches-5.4/301-arch-0001-arm-kernel-utilize-hrtimer-based-broadcast.patch b/target/linux/layerscape/patches-5.4/301-arch-0001-arm-kernel-utilize-hrtimer-based-broadcast.patch
new file mode 100644 (file)
index 0000000..8b9c25d
--- /dev/null
@@ -0,0 +1,33 @@
+From 0f87c1dd8f10958121e10219c89e8d710babd1ce Mon Sep 17 00:00:00 2001
+From: Alison Wang <b18965@freescale.com>
+Date: Fri, 17 Jul 2015 17:11:52 +0800
+Subject: [PATCH] arm: kernel: utilize hrtimer based broadcast
+
+Hrtimer based broadcast is used on ARM platform. It can be
+registered as the tick broadcast device in the absence of
+a real external clock device.
+
+Signed-off-by: Alison Wang <alison.wang@freescale.com>
+Acked-by: Mark Rutland <mark.rutland@arm.com>
+---
+ arch/arm/kernel/time.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/arch/arm/kernel/time.c
++++ b/arch/arm/kernel/time.c
+@@ -9,6 +9,7 @@
+  *  reading the RTC at bootup, etc...
+  */
+ #include <linux/clk-provider.h>
++#include <linux/clockchips.h>
+ #include <linux/clocksource.h>
+ #include <linux/errno.h>
+ #include <linux/export.h>
+@@ -107,5 +108,7 @@ void __init time_init(void)
+               of_clk_init(NULL);
+ #endif
+               timer_probe();
++
++              tick_setup_hrtimer_broadcast();
+       }
+ }
diff --git a/target/linux/layerscape/patches-5.4/301-arch-0002-arm64-add-support-to-remap-kernel-cacheable-memory-t.patch b/target/linux/layerscape/patches-5.4/301-arch-0002-arm64-add-support-to-remap-kernel-cacheable-memory-t.patch
new file mode 100644 (file)
index 0000000..282f8e9
--- /dev/null
@@ -0,0 +1,25 @@
+From 0f90f5d6b3097fd6e7dea3389dc3d8f8894b345c Mon Sep 17 00:00:00 2001
+From: Haiying Wang <Haiying.Wang@freescale.com>
+Date: Wed, 22 Apr 2015 13:09:47 -0400
+Subject: [PATCH] arm64: add support to remap kernel cacheable memory to
+ userspace
+
+Signed-off-by: Haiying Wang <Haiying.Wang@freescale.com>
+Reviewed-by: Roy Pledge <roy.pledge@freescale.com>
+Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com>
+---
+ arch/arm64/include/asm/pgtable.h | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/arch/arm64/include/asm/pgtable.h
++++ b/arch/arm64/include/asm/pgtable.h
+@@ -414,6 +414,9 @@ static inline pmd_t pmd_mkdevmap(pmd_t p
+       __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE) | PTE_PXN | PTE_UXN)
+ #define pgprot_writecombine(prot) \
+       __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
++#define pgprot_cached(prot) \
++      __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL) | \
++                      PTE_PXN | PTE_UXN)
+ #define pgprot_device(prot) \
+       __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN)
+ /*
diff --git a/target/linux/layerscape/patches-5.4/301-arch-0003-arm64-pgtable-add-support-to-map-cacheable-and-non-s.patch b/target/linux/layerscape/patches-5.4/301-arch-0003-arm64-pgtable-add-support-to-map-cacheable-and-non-s.patch
new file mode 100644 (file)
index 0000000..084f13a
--- /dev/null
@@ -0,0 +1,22 @@
+From d59be41c014e2e17ea0aaa37d42f36548ad063b5 Mon Sep 17 00:00:00 2001
+From: Haiying Wang <Haiying.wang@freescale.com>
+Date: Sat, 8 Aug 2015 07:25:02 -0400
+Subject: [PATCH] arm64/pgtable: add support to map cacheable and non shareable
+ memory
+
+Signed-off-by: Haiying Wang <Haiying.wang@freescale.com>
+---
+ arch/arm64/include/asm/pgtable.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/arm64/include/asm/pgtable.h
++++ b/arch/arm64/include/asm/pgtable.h
+@@ -417,6 +417,8 @@ static inline pmd_t pmd_mkdevmap(pmd_t p
+ #define pgprot_cached(prot) \
+       __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL) | \
+                       PTE_PXN | PTE_UXN)
++#define pgprot_cached_ns(prot) \
++      __pgprot(pgprot_val(pgprot_cached(prot)) ^ PTE_SHARED)
+ #define pgprot_device(prot) \
+       __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN)
+ /*
diff --git a/target/linux/layerscape/patches-5.4/301-arch-0004-arm64-add-ioremap-for-normal-cacheable-non-shareable.patch b/target/linux/layerscape/patches-5.4/301-arch-0004-arm64-add-ioremap-for-normal-cacheable-non-shareable.patch
new file mode 100644 (file)
index 0000000..ca55e53
--- /dev/null
@@ -0,0 +1,33 @@
+From 120c8f221cb18f6630d5cb954484bac88288cced Mon Sep 17 00:00:00 2001
+From: Haiying Wang <Haiying.Wang@freescale.com>
+Date: Wed, 22 Apr 2015 13:07:25 -0400
+Subject: [PATCH] arm64: add ioremap for normal cacheable non-shareable memory
+
+Signed-off-by: Haiying Wang <Haiying.Wang@freescale.com>
+Reviewed-by: Roy Pledge <roy.pledge@freescale.com>
+Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com>
+---
+ arch/arm64/include/asm/io.h           | 1 +
+ arch/arm64/include/asm/pgtable-prot.h | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/arch/arm64/include/asm/io.h
++++ b/arch/arm64/include/asm/io.h
+@@ -170,6 +170,7 @@ extern void __iomem *ioremap_cache(phys_
+ #define ioremap_nocache(addr, size)   __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
+ #define ioremap_wc(addr, size)                __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))
+ #define ioremap_wt(addr, size)                __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
++#define ioremap_cache_ns(addr, size)  __ioremap((addr), (size), __pgprot(PROT_NORMAL_NS))
+ /*
+  * PCI configuration space mapping function.
+--- a/arch/arm64/include/asm/pgtable-prot.h
++++ b/arch/arm64/include/asm/pgtable-prot.h
+@@ -37,6 +37,7 @@
+ #define PROT_NORMAL_NC                (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_NC))
+ #define PROT_NORMAL_WT                (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_WT))
+ #define PROT_NORMAL           (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL))
++#define PROT_NORMAL_NS                (PTE_TYPE_PAGE | PTE_AF | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL))
+ #define PROT_SECT_DEVICE_nGnRE        (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE))
+ #define PROT_SECT_NORMAL      (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
diff --git a/target/linux/layerscape/patches-5.4/301-arch-0005-arch-arm-add-ARM-specific-fucntions-required-for-ehc.patch b/target/linux/layerscape/patches-5.4/301-arch-0005-arch-arm-add-ARM-specific-fucntions-required-for-ehc.patch
new file mode 100644 (file)
index 0000000..ddb77d4
--- /dev/null
@@ -0,0 +1,79 @@
+From 3bc37b0ee99b9d66ac47aea02784242cb3224366 Mon Sep 17 00:00:00 2001
+From: Zhao Qiang <B45475@freescale.com>
+Date: Fri, 10 Oct 2014 10:38:48 +0800
+Subject: [PATCH] arch: arm: add ARM specific fucntions required for ehci fsl
+ driver
+
+Add below functions for ARM platform which are used by ehci fsl driver:
+1. spin_event_timeout function
+2. set/clear bits functions
+
+Signed-off-by: Zhao Qiang <B45475@freescale.com>
+Signed-off-by: Rajesh Bhagat <rajesh.bhagat@nxp.com>
+---
+ arch/arm/include/asm/delay.h | 16 ++++++++++++++++
+ arch/arm/include/asm/io.h    | 28 ++++++++++++++++++++++++++++
+ 2 files changed, 44 insertions(+)
+
+--- a/arch/arm/include/asm/delay.h
++++ b/arch/arm/include/asm/delay.h
+@@ -85,6 +85,22 @@ extern void __bad_udelay(void);
+                       __const_udelay((n) * UDELAY_MULT)) :            \
+         __udelay(n))
++#define spin_event_timeout(condition, timeout, delay)                          \
++({                                                                             \
++      typeof(condition) __ret;                                               \
++      int i = 0;                                                             \
++      while (!(__ret = (condition)) && (i++ < timeout)) {                    \
++              if (delay)                                                     \
++                      udelay(delay);                                         \
++              else                                                           \
++                      cpu_relax();                                           \
++              udelay(1);                                                     \
++      }                                                                      \
++      if (!__ret)                                                            \
++              __ret = (condition);                                           \
++      __ret;                                                                 \
++})
++
+ /* Loop-based definitions for assembly code. */
+ extern void __loop_delay(unsigned long loops);
+ extern void __loop_udelay(unsigned long usecs);
+--- a/arch/arm/include/asm/io.h
++++ b/arch/arm/include/asm/io.h
+@@ -224,6 +224,34 @@ void __iomem *pci_remap_cfgspace(resourc
+ #endif
+ #endif
++/* access ports */
++#define setbits32(_addr, _v) iowrite32be(ioread32be(_addr) |  (_v), (_addr))
++#define clrbits32(_addr, _v) iowrite32be(ioread32be(_addr) & ~(_v), (_addr))
++
++#define setbits16(_addr, _v) iowrite16be(ioread16be(_addr) |  (_v), (_addr))
++#define clrbits16(_addr, _v) iowrite16be(ioread16be(_addr) & ~(_v), (_addr))
++
++#define setbits8(_addr, _v) iowrite8(ioread8(_addr) |  (_v), (_addr))
++#define clrbits8(_addr, _v) iowrite8(ioread8(_addr) & ~(_v), (_addr))
++
++/* Clear and set bits in one shot.  These macros can be used to clear and
++ * set multiple bits in a register using a single read-modify-write.  These
++ * macros can also be used to set a multiple-bit bit pattern using a mask,
++ * by specifying the mask in the 'clear' parameter and the new bit pattern
++ * in the 'set' parameter.
++ */
++
++#define clrsetbits_be32(addr, clear, set) \
++      iowrite32be((ioread32be(addr) & ~(clear)) | (set), (addr))
++#define clrsetbits_le32(addr, clear, set) \
++      iowrite32le((ioread32le(addr) & ~(clear)) | (set), (addr))
++#define clrsetbits_be16(addr, clear, set) \
++      iowrite16be((ioread16be(addr) & ~(clear)) | (set), (addr))
++#define clrsetbits_le16(addr, clear, set) \
++      iowrite16le((ioread16le(addr) & ~(clear)) | (set), (addr))
++#define clrsetbits_8(addr, clear, set) \
++      iowrite8((ioread8(addr) & ~(clear)) | (set), (addr))
++
+ /*
+  *  IO port access primitives
+  *  -------------------------
diff --git a/target/linux/layerscape/patches-5.4/301-arch-0006-export-arch_setup_dma_ops.patch b/target/linux/layerscape/patches-5.4/301-arch-0006-export-arch_setup_dma_ops.patch
new file mode 100644 (file)
index 0000000..92b7480
--- /dev/null
@@ -0,0 +1,17 @@
+From 1c86c2f332b3aafb119c4d1ef981cd2a44286a81 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Wed, 7 Jun 2017 17:54:10 +0300
+Subject: [PATCH] export arch_setup_dma_ops()
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ arch/arm64/mm/dma-mapping.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm64/mm/dma-mapping.c
++++ b/arch/arm64/mm/dma-mapping.c
+@@ -57,3 +57,4 @@ void arch_setup_dma_ops(struct device *d
+               dev->dma_ops = &xen_swiotlb_dma_ops;
+ #endif
+ }
++EXPORT_SYMBOL(arch_setup_dma_ops);
diff --git a/target/linux/layerscape/patches-5.4/301-arch-0007-arm-dma-mapping-export-arch_setup_dma_ops.patch b/target/linux/layerscape/patches-5.4/301-arch-0007-arm-dma-mapping-export-arch_setup_dma_ops.patch
new file mode 100644 (file)
index 0000000..c05b99b
--- /dev/null
@@ -0,0 +1,23 @@
+From 5f1b16ecaac2e891c43a9bbce0f5ee1c18e5aba7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Horia=20Geant=C4=83?= <horia.geanta@nxp.com>
+Date: Mon, 19 Jun 2017 16:38:59 +0300
+Subject: [PATCH] arm: dma-mapping: export arch_setup_dma_ops()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ arch/arm/mm/dma-mapping.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/mm/dma-mapping.c
++++ b/arch/arm/mm/dma-mapping.c
+@@ -2320,6 +2320,7 @@ void arch_setup_dma_ops(struct device *d
+ #endif
+       dev->archdata.dma_ops_setup = true;
+ }
++EXPORT_SYMBOL(arch_setup_dma_ops);
+ void arch_teardown_dma_ops(struct device *dev)
+ {
diff --git a/target/linux/layerscape/patches-5.4/301-arch-0008-arm-add-new-non-shareable-ioremap.patch b/target/linux/layerscape/patches-5.4/301-arch-0008-arm-add-new-non-shareable-ioremap.patch
new file mode 100644 (file)
index 0000000..a20909f
--- /dev/null
@@ -0,0 +1,95 @@
+From e5bf75ca33946d81c82014168042a64db7c81551 Mon Sep 17 00:00:00 2001
+From: Pan Jiafei <Jiafei.Pan@nxp.com>
+Date: Thu, 17 Mar 2016 02:01:03 +0000
+Subject: [PATCH] arm: add new non-shareable ioremap
+
+Signed-off-by: Pan Jiafei <Jiafei.Pan@nxp.com>
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+---
+ arch/arm/include/asm/io.h       | 3 +++
+ arch/arm/include/asm/mach/map.h | 4 ++--
+ arch/arm/mm/ioremap.c           | 7 +++++++
+ arch/arm/mm/mmu.c               | 9 +++++++++
+ 4 files changed, 21 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/include/asm/io.h
++++ b/arch/arm/include/asm/io.h
+@@ -123,6 +123,7 @@ static inline u32 __raw_readl(const vola
+ #define MT_DEVICE_NONSHARED   1
+ #define MT_DEVICE_CACHED      2
+ #define MT_DEVICE_WC          3
++#define MT_MEMORY_RW_NS               4
+ /*
+  * types 4 onwards can be found in asm/mach/map.h and are undefined
+  * for ioremap
+@@ -438,6 +439,8 @@ void __iomem *ioremap_wc(resource_size_t
+ #define ioremap_wc ioremap_wc
+ #define ioremap_wt ioremap_wc
++void __iomem *ioremap_cache_ns(resource_size_t res_cookie, size_t size);
++
+ void iounmap(volatile void __iomem *iomem_cookie);
+ #define iounmap iounmap
+--- a/arch/arm/include/asm/mach/map.h
++++ b/arch/arm/include/asm/mach/map.h
+@@ -18,9 +18,9 @@ struct map_desc {
+       unsigned int type;
+ };
+-/* types 0-3 are defined in asm/io.h */
++/* types 0-4 are defined in asm/io.h */
+ enum {
+-      MT_UNCACHED = 4,
++      MT_UNCACHED = 5,
+       MT_CACHECLEAN,
+       MT_MINICLEAN,
+       MT_LOW_VECTORS,
+--- a/arch/arm/mm/ioremap.c
++++ b/arch/arm/mm/ioremap.c
+@@ -399,6 +399,13 @@ void __iomem *ioremap_wc(resource_size_t
+ }
+ EXPORT_SYMBOL(ioremap_wc);
++void __iomem *ioremap_cache_ns(resource_size_t res_cookie, size_t size)
++{
++      return arch_ioremap_caller(res_cookie, size, MT_MEMORY_RW_NS,
++                                 __builtin_return_address(0));
++}
++EXPORT_SYMBOL(ioremap_cache_ns);
++
+ /*
+  * Remap an arbitrary physical address space into the kernel virtual
+  * address space as memory. Needed when the kernel wants to execute
+--- a/arch/arm/mm/mmu.c
++++ b/arch/arm/mm/mmu.c
+@@ -312,6 +312,13 @@ static struct mem_type mem_types[] __ro_
+               .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
+               .domain    = DOMAIN_KERNEL,
+       },
++      [MT_MEMORY_RW_NS] = {
++              .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
++                           L_PTE_XN,
++              .prot_l1   = PMD_TYPE_TABLE,
++              .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_XN,
++              .domain    = DOMAIN_KERNEL,
++      },
+       [MT_ROM] = {
+               .prot_sect = PMD_TYPE_SECT,
+               .domain    = DOMAIN_KERNEL,
+@@ -648,6 +655,7 @@ static void __init build_mem_type_table(
+       }
+       kern_pgprot |= PTE_EXT_AF;
+       vecs_pgprot |= PTE_EXT_AF;
++      mem_types[MT_MEMORY_RW_NS].prot_pte |= PTE_EXT_AF | cp->pte;
+       /*
+        * Set PXN for user mappings
+@@ -676,6 +684,7 @@ static void __init build_mem_type_table(
+       mem_types[MT_MEMORY_RWX].prot_pte |= kern_pgprot;
+       mem_types[MT_MEMORY_RW].prot_sect |= ecc_mask | cp->pmd;
+       mem_types[MT_MEMORY_RW].prot_pte |= kern_pgprot;
++      mem_types[MT_MEMORY_RW_NS].prot_sect |= ecc_mask | cp->pmd;
+       mem_types[MT_MEMORY_DMA_READY].prot_pte |= kern_pgprot;
+       mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= ecc_mask;
+       mem_types[MT_ROM].prot_sect |= cp->pmd;
diff --git a/target/linux/layerscape/patches-5.4/301-arch-0009-arm-add-pgprot_cached-and-pgprot_cached_ns-support.patch b/target/linux/layerscape/patches-5.4/301-arch-0009-arm-add-pgprot_cached-and-pgprot_cached_ns-support.patch
new file mode 100644 (file)
index 0000000..1f99073
--- /dev/null
@@ -0,0 +1,26 @@
+From 395718e9f6445369089dba16fa50182c5e0528f5 Mon Sep 17 00:00:00 2001
+From: Jianhua Xie <jianhua.xie@nxp.com>
+Date: Fri, 29 Jan 2016 16:40:46 +0800
+Subject: [PATCH] arm: add pgprot_cached and pgprot_cached_ns support
+
+Signed-off-by: Jianhua Xie <jianhua.xie@nxp.com>
+---
+ arch/arm/include/asm/pgtable.h | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/arch/arm/include/asm/pgtable.h
++++ b/arch/arm/include/asm/pgtable.h
+@@ -116,6 +116,13 @@ extern pgprot_t           pgprot_s2_device;
+ #define pgprot_noncached(prot) \
+       __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
++#define pgprot_cached(prot) \
++      __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_DEV_CACHED)
++
++#define pgprot_cached_ns(prot) \
++      __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_DEV_CACHED | \
++                      L_PTE_MT_DEV_NONSHARED)
++
+ #define pgprot_writecombine(prot) \
+       __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE)
diff --git a/target/linux/layerscape/patches-5.4/301-arch-0010-arm64-add-stage-2-cache-able-non-shareable-page-type.patch b/target/linux/layerscape/patches-5.4/301-arch-0010-arm64-add-stage-2-cache-able-non-shareable-page-type.patch
new file mode 100644 (file)
index 0000000..66fd760
--- /dev/null
@@ -0,0 +1,20 @@
+From 73b06aca47caafdce7bff2c7b27a070d5a8d8172 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 5 Dec 2017 15:24:05 +0200
+Subject: [PATCH] arm64: add stage-2 cache-able non-shareable page type
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ arch/arm64/include/asm/pgtable-prot.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm64/include/asm/pgtable-prot.h
++++ b/arch/arm64/include/asm/pgtable-prot.h
+@@ -78,6 +78,7 @@
+       })
+ #define PAGE_S2                       __pgprot(_PROT_DEFAULT | PAGE_S2_MEMATTR(NORMAL) | PTE_S2_RDONLY | PAGE_S2_XN)
++#define PAGE_S2_NS            __pgprot(PAGE_S2_MEMATTR(NORMAL) | PTE_S2_RDWR | PTE_TYPE_PAGE | PTE_AF)
+ #define PAGE_S2_DEVICE                __pgprot(_PROT_DEFAULT | PAGE_S2_MEMATTR(DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_S2_XN)
+ #define PAGE_NONE             __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)
diff --git a/target/linux/layerscape/patches-5.4/301-arch-0011-drivers-soc-fsl-add-qixis-driver.patch b/target/linux/layerscape/patches-5.4/301-arch-0011-drivers-soc-fsl-add-qixis-driver.patch
new file mode 100644 (file)
index 0000000..bd82274
--- /dev/null
@@ -0,0 +1,152 @@
+From 68e332146b6f0a1d2a4514810986a7cf3c3117e3 Mon Sep 17 00:00:00 2001
+From: Pankaj Bansal <pankaj.bansal@nxp.com>
+Date: Thu, 28 Feb 2019 17:22:28 +0530
+Subject: [PATCH] drivers: soc: fsl: add qixis driver
+
+FPGA on LX2160AQDS/LX2160ARDB connected on I2C bus, so add qixis driver
+which is basically an i2c client driver to control FPGA.
+
+Signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com>
+---
+ drivers/soc/fsl/Kconfig      |  11 +++++
+ drivers/soc/fsl/Makefile     |   1 +
+ drivers/soc/fsl/qixis_ctrl.c | 105 +++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 117 insertions(+)
+ create mode 100644 drivers/soc/fsl/qixis_ctrl.c
+
+--- a/drivers/soc/fsl/Kconfig
++++ b/drivers/soc/fsl/Kconfig
+@@ -40,4 +40,15 @@ config DPAA2_CONSOLE
+         /dev/dpaa2_mc_console and /dev/dpaa2_aiop_console,
+         which can be used to dump the Management Complex and AIOP
+         firmware logs.
++
++config FSL_QIXIS
++      tristate "QIXIS system controller driver"
++      depends on OF
++      select REGMAP_I2C
++      select REGMAP_MMIO
++      default n
++      help
++        Say y here to enable QIXIS system controller api. The qixis driver
++        provides FPGA functions to control system.
++
+ endmenu
+--- a/drivers/soc/fsl/Makefile
++++ b/drivers/soc/fsl/Makefile
+@@ -6,6 +6,7 @@
+ obj-$(CONFIG_FSL_DPAA)                 += qbman/
+ obj-$(CONFIG_QUICC_ENGINE)            += qe/
+ obj-$(CONFIG_CPM)                     += qe/
++obj-$(CONFIG_FSL_QIXIS)               += qixis_ctrl.o
+ obj-$(CONFIG_FSL_GUTS)                        += guts.o
+ obj-$(CONFIG_FSL_MC_DPIO)             += dpio/
+ obj-$(CONFIG_DPAA2_CONSOLE)           += dpaa2-console.o
+--- /dev/null
++++ b/drivers/soc/fsl/qixis_ctrl.c
+@@ -0,0 +1,105 @@
++// SPDX-License-Identifier: GPL-2.0+
++
++/* Freescale QIXIS system controller driver.
++ *
++ * Copyright 2015 Freescale Semiconductor, Inc.
++ * Copyright 2018-2019 NXP
++ */
++
++#include <linux/err.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/mfd/core.h>
++#include <linux/of.h>
++#include <linux/regmap.h>
++
++/* QIXIS MAP */
++struct fsl_qixis_regs {
++      u8              id;             /* Identification Registers */
++      u8              version;        /* Version Register */
++      u8              qixis_ver;      /* QIXIS Version Register */
++      u8              reserved1[0x1f];
++};
++
++struct qixis_priv {
++      struct regmap           *regmap;
++};
++
++static struct regmap_config qixis_regmap_config = {
++      .reg_bits = 8,
++      .val_bits = 8,
++};
++
++static const struct mfd_cell fsl_qixis_devs[] = {
++      {
++              .name = "reg-mux",
++              .of_compatible = "reg-mux",
++      },
++};
++
++static int fsl_qixis_i2c_probe(struct i2c_client *client)
++{
++      struct qixis_priv *priv;
++      int ret = 0;
++      u32 qver;
++
++      if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
++              return -EOPNOTSUPP;
++
++      priv = devm_kzalloc(&client->dev, sizeof(struct qixis_priv),
++                          GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++
++      priv->regmap = regmap_init_i2c(client, &qixis_regmap_config);
++      regmap_read(priv->regmap, offsetof(struct fsl_qixis_regs, qixis_ver),
++                  &qver);
++      pr_info("Freescale QIXIS Version: 0x%08x\n", qver);
++
++      i2c_set_clientdata(client, priv);
++
++      if (of_device_is_compatible(client->dev.of_node, "simple-mfd"))
++              ret = devm_mfd_add_devices(&client->dev, -1, fsl_qixis_devs,
++                                         ARRAY_SIZE(fsl_qixis_devs), NULL, 0,
++                                         NULL);
++      if (ret)
++              goto error;
++
++      return ret;
++error:
++      regmap_exit(priv->regmap);
++
++      return ret;
++}
++
++static int fsl_qixis_i2c_remove(struct i2c_client *client)
++{
++      struct qixis_priv *priv;
++
++      priv = i2c_get_clientdata(client);
++      regmap_exit(priv->regmap);
++
++      return 0;
++}
++
++static const struct of_device_id fsl_qixis_i2c_of_match[] = {
++      { .compatible = "fsl,fpga-qixis-i2c" },
++      {}
++};
++MODULE_DEVICE_TABLE(of, fsl_qixis_i2c_of_match);
++
++static struct i2c_driver fsl_qixis_i2c_driver = {
++      .driver = {
++              .name   = "qixis_ctrl_i2c",
++              .owner  = THIS_MODULE,
++              .of_match_table = of_match_ptr(fsl_qixis_i2c_of_match),
++      },
++      .probe_new      = fsl_qixis_i2c_probe,
++      .remove         = fsl_qixis_i2c_remove,
++};
++module_i2c_driver(fsl_qixis_i2c_driver);
++
++MODULE_AUTHOR("Wang Dongsheng <dongsheng.wang@freescale.com>");
++MODULE_DESCRIPTION("Freescale QIXIS system controller driver");
++MODULE_LICENSE("GPL");
++
diff --git a/target/linux/layerscape/patches-5.4/301-arch-0012-soc-fsl-select-MFD_CORE-for-qixis-driver.patch b/target/linux/layerscape/patches-5.4/301-arch-0012-soc-fsl-select-MFD_CORE-for-qixis-driver.patch
new file mode 100644 (file)
index 0000000..aefae7c
--- /dev/null
@@ -0,0 +1,22 @@
+From 5451ebbfc7e8ba51bceb12ee5409364000e6475b Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Thu, 9 Apr 2020 18:24:07 +0800
+Subject: [PATCH] soc: fsl: select MFD_CORE for qixis driver
+
+The QIXIS driver should select MFD_CORE option.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/soc/fsl/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/soc/fsl/Kconfig
++++ b/drivers/soc/fsl/Kconfig
+@@ -46,6 +46,7 @@ config FSL_QIXIS
+       depends on OF
+       select REGMAP_I2C
+       select REGMAP_MMIO
++      select MFD_CORE
+       default n
+       help
+         Say y here to enable QIXIS system controller api. The qixis driver
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0001-sdk-arm64-dts-add-update-DPAA1-include-files-for-SDK.patch b/target/linux/layerscape/patches-5.4/302-dts-0001-sdk-arm64-dts-add-update-DPAA1-include-files-for-SDK.patch
new file mode 100644 (file)
index 0000000..cdded8a
--- /dev/null
@@ -0,0 +1,550 @@
+From fd5901a48f68c74f074ea5c490377b7c9f3899f5 Mon Sep 17 00:00:00 2001
+From: Li Yang <leoyang.li@nxp.com>
+Date: Fri, 5 Oct 2018 17:52:23 -0500
+Subject: [PATCH] sdk: arm64: dts: add/update DPAA1 include files for SDK
+ flavor
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+Signed-off-by: Li Yang <leoyang.li@nxp.com>
+---
+ .../boot/dts/freescale/qoriq-bman-portals-sdk.dtsi | 55 +++++++++++++++++
+ arch/arm64/boot/dts/freescale/qoriq-dpaa-eth.dtsi  | 72 ++++++++++++++++++++++
+ .../boot/dts/freescale/qoriq-fman3-0-10g-0.dtsi    |  9 +--
+ .../boot/dts/freescale/qoriq-fman3-0-10g-1.dtsi    |  9 +--
+ .../boot/dts/freescale/qoriq-fman3-0-1g-0.dtsi     |  5 +-
+ .../boot/dts/freescale/qoriq-fman3-0-1g-1.dtsi     |  5 +-
+ .../boot/dts/freescale/qoriq-fman3-0-1g-2.dtsi     |  5 +-
+ .../boot/dts/freescale/qoriq-fman3-0-1g-3.dtsi     |  5 +-
+ .../boot/dts/freescale/qoriq-fman3-0-1g-4.dtsi     |  5 +-
+ .../boot/dts/freescale/qoriq-fman3-0-1g-5.dtsi     |  5 +-
+ .../boot/dts/freescale/qoriq-fman3-0-6oh.dtsi      | 47 ++++++++++++++
+ arch/arm64/boot/dts/freescale/qoriq-fman3-0.dtsi   | 52 +++++++++++++++-
+ .../boot/dts/freescale/qoriq-qman-portals-sdk.dtsi | 38 ++++++++++++
+ 13 files changed, 291 insertions(+), 21 deletions(-)
+ create mode 100644 arch/arm64/boot/dts/freescale/qoriq-bman-portals-sdk.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/qoriq-dpaa-eth.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/qoriq-fman3-0-6oh.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/qoriq-qman-portals-sdk.dtsi
+
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/qoriq-bman-portals-sdk.dtsi
+@@ -0,0 +1,55 @@
++/*
++ * QorIQ BMan SDK Portals device tree nodes
++ *
++ * Copyright 2011-2016 Freescale Semiconductor Inc.
++ * Copyright 2017 NXP
++ *
++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
++ */
++
++&bportals {
++      bman-portal@0 {
++              cell-index = <0>;
++      };
++
++      bman-portal@10000 {
++              cell-index = <1>;
++      };
++
++      bman-portal@20000 {
++              cell-index = <2>;
++      };
++
++      bman-portal@30000 {
++              cell-index = <3>;
++      };
++
++      bman-portal@40000 {
++              cell-index = <4>;
++      };
++
++      bman-portal@50000 {
++              cell-index = <5>;
++      };
++
++      bman-portal@60000 {
++              cell-index = <6>;
++      };
++
++      bman-portal@70000 {
++              cell-index = <7>;
++      };
++
++      bman-portal@80000 {
++              cell-index = <8>;
++      };
++
++      bman-portal@90000 {
++              cell-index = <9>;
++      };
++
++       bman-bpids@0 {
++              compatible = "fsl,bpid-range";
++              fsl,bpid-range = <32 32>;
++      };
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/qoriq-dpaa-eth.dtsi
+@@ -0,0 +1,72 @@
++/*
++ * QorIQ FMan v3 10g port #1 device tree stub [ controller @ offset 0x400000 ]
++ *
++ * Copyright 2012 - 2015 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++fsldpaa: fsl,dpaa {
++      compatible = "fsl,ls1043a-dpaa", "simple-bus", "fsl,dpaa";
++      ethernet@0 {
++              compatible = "fsl,dpa-ethernet";
++              fsl,fman-mac = <&enet0>;
++              dma-coherent;
++      };
++      ethernet@1 {
++              compatible = "fsl,dpa-ethernet";
++              fsl,fman-mac = <&enet1>;
++              dma-coherent;
++      };
++      ethernet@2 {
++              compatible = "fsl,dpa-ethernet";
++              fsl,fman-mac = <&enet2>;
++              dma-coherent;
++      };
++      ethernet@3 {
++              compatible = "fsl,dpa-ethernet";
++              fsl,fman-mac = <&enet3>;
++              dma-coherent;
++      };
++      ethernet@4 {
++              compatible = "fsl,dpa-ethernet";
++              fsl,fman-mac = <&enet4>;
++              dma-coherent;
++      };
++      ethernet@5 {
++              compatible = "fsl,dpa-ethernet";
++              fsl,fman-mac = <&enet5>;
++              dma-coherent;
++      };
++      ethernet@8 {
++              compatible = "fsl,dpa-ethernet";
++              fsl,fman-mac = <&enet6>;
++              dma-coherent;
++      };
++};
+--- a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-0.dtsi
++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-0.dtsi
+@@ -9,19 +9,20 @@
+ fman@1a00000 {
+       fman0_rx_0x10: port@90000 {
+               cell-index = <0x10>;
+-              compatible = "fsl,fman-v3-port-rx";
++              compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-10g-rx";
+               reg = <0x90000 0x1000>;
+               fsl,fman-10g-port;
+       };
+       fman0_tx_0x30: port@b0000 {
+               cell-index = <0x30>;
+-              compatible = "fsl,fman-v3-port-tx";
++              compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-10g-tx";
+               reg = <0xb0000 0x1000>;
+               fsl,fman-10g-port;
++              fsl,qman-channel-id = <0x800>;
+       };
+-      ethernet@f0000 {
++      mac9: ethernet@f0000 {
+               cell-index = <0x8>;
+               compatible = "fsl,fman-memac";
+               reg = <0xf0000 0x1000>;
+@@ -29,7 +30,7 @@ fman@1a00000 {
+               pcsphy-handle = <&pcsphy6>;
+       };
+-      mdio@f1000 {
++      mdio9: mdio@f1000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
+--- a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-1.dtsi
++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-1.dtsi
+@@ -9,19 +9,20 @@
+ fman@1a00000 {
+       fman0_rx_0x11: port@91000 {
+               cell-index = <0x11>;
+-              compatible = "fsl,fman-v3-port-rx";
++              compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-10g-rx";
+               reg = <0x91000 0x1000>;
+               fsl,fman-10g-port;
+       };
+       fman0_tx_0x31: port@b1000 {
+               cell-index = <0x31>;
+-              compatible = "fsl,fman-v3-port-tx";
++              compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-10g-tx";
+               reg = <0xb1000 0x1000>;
+               fsl,fman-10g-port;
++              fsl,qman-channel-id = <0x801>;
+       };
+-      ethernet@f2000 {
++      mac10: ethernet@f2000 {
+               cell-index = <0x9>;
+               compatible = "fsl,fman-memac";
+               reg = <0xf2000 0x1000>;
+@@ -29,7 +30,7 @@ fman@1a00000 {
+               pcsphy-handle = <&pcsphy7>;
+       };
+-      mdio@f3000 {
++      mdio10: mdio@f3000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
+--- a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-0.dtsi
++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-0.dtsi
+@@ -9,14 +9,15 @@
+ fman@1a00000 {
+       fman0_rx_0x08: port@88000 {
+               cell-index = <0x8>;
+-              compatible = "fsl,fman-v3-port-rx";
++              compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx";
+               reg = <0x88000 0x1000>;
+       };
+       fman0_tx_0x28: port@a8000 {
+               cell-index = <0x28>;
+-              compatible = "fsl,fman-v3-port-tx";
++              compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx";
+               reg = <0xa8000 0x1000>;
++              fsl,qman-channel-id = <0x802>;
+       };
+       ethernet@e0000 {
+--- a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-1.dtsi
++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-1.dtsi
+@@ -9,14 +9,15 @@
+ fman@1a00000 {
+       fman0_rx_0x09: port@89000 {
+               cell-index = <0x9>;
+-              compatible = "fsl,fman-v3-port-rx";
++              compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx";
+               reg = <0x89000 0x1000>;
+       };
+       fman0_tx_0x29: port@a9000 {
+               cell-index = <0x29>;
+-              compatible = "fsl,fman-v3-port-tx";
++              compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx";
+               reg = <0xa9000 0x1000>;
++              fsl,qman-channel-id = <0x803>;
+       };
+       ethernet@e2000 {
+--- a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-2.dtsi
++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-2.dtsi
+@@ -9,14 +9,15 @@
+ fman@1a00000 {
+       fman0_rx_0x0a: port@8a000 {
+               cell-index = <0xa>;
+-              compatible = "fsl,fman-v3-port-rx";
++              compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx";
+               reg = <0x8a000 0x1000>;
+       };
+       fman0_tx_0x2a: port@aa000 {
+               cell-index = <0x2a>;
+-              compatible = "fsl,fman-v3-port-tx";
++              compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx";
+               reg = <0xaa000 0x1000>;
++              fsl,qman-channel-id = <0x804>;
+       };
+       ethernet@e4000 {
+--- a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-3.dtsi
++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-3.dtsi
+@@ -9,14 +9,15 @@
+ fman@1a00000 {
+       fman0_rx_0x0b: port@8b000 {
+               cell-index = <0xb>;
+-              compatible = "fsl,fman-v3-port-rx";
++              compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx";
+               reg = <0x8b000 0x1000>;
+       };
+       fman0_tx_0x2b: port@ab000 {
+               cell-index = <0x2b>;
+-              compatible = "fsl,fman-v3-port-tx";
++              compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx";
+               reg = <0xab000 0x1000>;
++              fsl,qman-channel-id = <0x805>;
+       };
+       ethernet@e6000 {
+--- a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-4.dtsi
++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-4.dtsi
+@@ -9,14 +9,15 @@
+ fman@1a00000 {
+       fman0_rx_0x0c: port@8c000 {
+               cell-index = <0xc>;
+-              compatible = "fsl,fman-v3-port-rx";
++              compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx";
+               reg = <0x8c000 0x1000>;
+       };
+       fman0_tx_0x2c: port@ac000 {
+               cell-index = <0x2c>;
+-              compatible = "fsl,fman-v3-port-tx";
++              compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx";
+               reg = <0xac000 0x1000>;
++              fsl,qman-channel-id = <0x806>;
+       };
+       ethernet@e8000 {
+--- a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-5.dtsi
++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-5.dtsi
+@@ -9,14 +9,15 @@
+ fman@1a00000 {
+       fman0_rx_0x0d: port@8d000 {
+               cell-index = <0xd>;
+-              compatible = "fsl,fman-v3-port-rx";
++              compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx";
+               reg = <0x8d000 0x1000>;
+       };
+       fman0_tx_0x2d: port@ad000 {
+               cell-index = <0x2d>;
+-              compatible = "fsl,fman-v3-port-tx";
++              compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx";
+               reg = <0xad000 0x1000>;
++              fsl,qman-channel-id = <0x807>;
+       };
+       ethernet@ea000 {
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-6oh.dtsi
+@@ -0,0 +1,47 @@
++/*
++ * QorIQ FMan v3 OH ports device tree
++ *
++ * Copyright 2012-2015 Freescale Semiconductor Inc.
++ *
++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
++ */
++
++fman@1a00000 {
++
++      fman0_oh1: port@82000 {
++              cell-index = <0>;
++              compatible = "fsl,fman-port-oh";
++              reg = <0x82000 0x1000>;
++      };
++
++      fman0_oh2: port@83000 {
++              cell-index = <1>;
++              compatible = "fsl,fman-port-oh";
++              reg = <0x83000 0x1000>;
++      };
++
++      fman0_oh3: port@84000 {
++              cell-index = <2>;
++              compatible = "fsl,fman-port-oh";
++              reg = <0x84000 0x1000>;
++      };
++
++      fman0_oh4: port@85000 {
++              cell-index = <3>;
++              compatible = "fsl,fman-port-oh";
++              reg = <0x85000 0x1000>;
++      };
++
++      fman0_oh5: port@86000 {
++              cell-index = <4>;
++              compatible = "fsl,fman-port-oh";
++              reg = <0x86000 0x1000>;
++      };
++
++      fman0_oh6: port@87000 {
++              cell-index = <5>;
++              compatible = "fsl,fman-port-oh";
++              reg = <0x87000 0x1000>;
++      };
++
++};
+--- a/arch/arm64/boot/dts/freescale/qoriq-fman3-0.dtsi
++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0.dtsi
+@@ -20,45 +20,95 @@ fman0: fman@1a00000 {
+       fsl,qman-channel-range = <0x800 0x10>;
+       ptimer-handle = <&ptp_timer0>;
++      cc {
++              compatible = "fsl,fman-cc";
++      };
++
+       muram@0 {
+               compatible = "fsl,fman-muram";
+               reg = <0x0 0x60000>;
+       };
++      bmi@80000 {
++              compatible = "fsl,fman-bmi";
++              reg = <0x80000 0x400>;
++      };
++
++      qmi@80400 {
++              compatible = "fsl,fman-qmi";
++              reg = <0x80400 0x400>;
++      };
++
+       fman0_oh_0x2: port@82000 {
+               cell-index = <0x2>;
+               compatible = "fsl,fman-v3-port-oh";
+               reg = <0x82000 0x1000>;
++              fsl,qman-channel-id = <0x809>;
+       };
+       fman0_oh_0x3: port@83000 {
+               cell-index = <0x3>;
+               compatible = "fsl,fman-v3-port-oh";
+               reg = <0x83000 0x1000>;
++              fsl,qman-channel-id = <0x80a>;
+       };
+       fman0_oh_0x4: port@84000 {
+               cell-index = <0x4>;
+               compatible = "fsl,fman-v3-port-oh";
+               reg = <0x84000 0x1000>;
++              fsl,qman-channel-id = <0x80b>;
+       };
+       fman0_oh_0x5: port@85000 {
+               cell-index = <0x5>;
+               compatible = "fsl,fman-v3-port-oh";
+               reg = <0x85000 0x1000>;
++              fsl,qman-channel-id = <0x80c>;
+       };
+       fman0_oh_0x6: port@86000 {
+               cell-index = <0x6>;
+               compatible = "fsl,fman-v3-port-oh";
+               reg = <0x86000 0x1000>;
++              fsl,qman-channel-id = <0x80d>;
+       };
+       fman0_oh_0x7: port@87000 {
+               cell-index = <0x7>;
+               compatible = "fsl,fman-v3-port-oh";
+               reg = <0x87000 0x1000>;
++              fsl,qman-channel-id = <0x80e>;
++      };
++
++      policer@c0000 {
++              compatible = "fsl,fman-policer";
++              reg = <0xc0000 0x1000>;
++      };
++
++      keygen@c1000 {
++              compatible = "fsl,fman-keygen";
++              reg = <0xc1000 0x1000>;
++      };
++
++      dma@c2000 {
++              compatible = "fsl,fman-dma";
++              reg = <0xc2000 0x1000>;
++      };
++
++      fpm@c3000 {
++              compatible = "fsl,fman-fpm";
++              reg = <0xc3000 0x1000>;
++      };
++
++      parser@c7000 {
++              compatible = "fsl,fman-parser";
++              reg = <0xc7000 0x1000>;
++      };
++
++      vsps@dc000 {
++              compatible = "fsl,fman-vsps";
++              reg = <0xdc000 0x1000>;
+       };
+       mdio0: mdio@fc000 {
+@@ -77,7 +127,7 @@ fman0: fman@1a00000 {
+ };
+ ptp_timer0: ptp-timer@1afe000 {
+-      compatible = "fsl,fman-ptp-timer";
++      compatible = "fsl,fman-ptp-timer", "fsl,fman-rtc";
+       reg = <0x0 0x1afe000 0x0 0x1000>;
+       interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+       clocks = <&clockgen 3 0>;
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/qoriq-qman-portals-sdk.dtsi
+@@ -0,0 +1,38 @@
++/*
++ * QorIQ QMan SDK Portals device tree nodes
++ *
++ * Copyright 2011-2016 Freescale Semiconductor Inc.
++ * Copyright 2017 NXP
++ *
++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
++ */
++
++&qportals {
++      qman-fqids@0 {
++              compatible = "fsl,fqid-range";
++              fsl,fqid-range = <256 256>;
++      };
++
++      qman-fqids@1 {
++              compatible = "fsl,fqid-range";
++              fsl,fqid-range = <32768 32768>;
++      };
++
++      qman-pools@0 {
++              compatible = "fsl,pool-channel-range";
++              fsl,pool-channel-range = <0x401 0xf>;
++      };
++
++      qman-cgrids@0 {
++              compatible = "fsl,cgrid-range";
++              fsl,cgrid-range = <0 256>;
++      };
++
++      qman-ceetm@0 {
++              compatible = "fsl,qman-ceetm";
++              fsl,ceetm-lfqid-range = <0xf00000 0x1000>;
++              fsl,ceetm-sp-range = <0 16>;
++              fsl,ceetm-lni-range = <0 8>;
++              fsl,ceetm-channel-range = <0 32>;
++      };
++};
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0002-sdk-arm64-dts-add-DPAA1-SDK-flavor-dts-files.patch b/target/linux/layerscape/patches-5.4/302-dts-0002-sdk-arm64-dts-add-DPAA1-SDK-flavor-dts-files.patch
new file mode 100644 (file)
index 0000000..8a53e92
--- /dev/null
@@ -0,0 +1,626 @@
+From 7f3b260e937238632e523306089e856d0db1a4f9 Mon Sep 17 00:00:00 2001
+From: Li Yang <leoyang.li@nxp.com>
+Date: Fri, 5 Oct 2018 18:03:25 -0500
+Subject: [PATCH] sdk: arm64: dts: add DPAA1 SDK flavor dts files
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+Signed-off-by: Iordache Florinel-R70177 <florinel.iordache@nxp.com>
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+Signed-off-by: Li Yang <leoyang.li@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/Makefile             |   6 ++
+ .../boot/dts/freescale/fsl-ls1043a-qds-sdk.dts     |  71 +++++++++++++
+ .../boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts     |  71 +++++++++++++
+ .../boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts  | 117 +++++++++++++++++++++
+ .../boot/dts/freescale/fsl-ls1046a-qds-sdk.dts     |  79 ++++++++++++++
+ .../boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts     | 115 ++++++++++++++++++++
+ .../boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts  | 110 +++++++++++++++++++
+ 7 files changed, 569 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1043a-qds-sdk.dts
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1046a-qds-sdk.dts
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts
+
+--- a/arch/arm64/boot/dts/freescale/Makefile
++++ b/arch/arm64/boot/dts/freescale/Makefile
+@@ -7,10 +7,16 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds-sdk.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-sdk.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-usdpaa.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-frwy.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds-sdk.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-sdk.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-usdpaa.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1088a-qds.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1088a-rdb.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-qds.dtb
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds-sdk.dts
+@@ -0,0 +1,71 @@
++/*
++ * Device Tree Include file for Freescale Layerscape-1043A family SoC.
++ *
++ * Copyright 2014-2015 Freescale Semiconductor, Inc.
++ *
++ * Mingkai Hu <Mingkai.hu@freescale.com>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPLv2 or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This library is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This library is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++#include "fsl-ls1043a-qds.dts"
++#include "qoriq-qman-portals-sdk.dtsi"
++#include "qoriq-bman-portals-sdk.dtsi"
++
++&bman_fbpr {
++      compatible = "fsl,bman-fbpr";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++&qman_fqd {
++      compatible = "fsl,qman-fqd";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++&qman_pfdr {
++      compatible = "fsl,qman-pfdr";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++
++&soc {
++#include "qoriq-dpaa-eth.dtsi"
++#include "qoriq-fman3-0-6oh.dtsi"
++};
++
++&fman0 {
++      compatible = "fsl,fman", "simple-bus";
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts
+@@ -0,0 +1,71 @@
++/*
++ * Device Tree Include file for Freescale Layerscape-1043A family SoC.
++ *
++ * Copyright 2014-2015 Freescale Semiconductor, Inc.
++ *
++ * Mingkai Hu <Mingkai.hu@freescale.com>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPLv2 or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This library is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This library is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++#include "fsl-ls1043a-rdb.dts"
++#include "qoriq-qman-portals-sdk.dtsi"
++#include "qoriq-bman-portals-sdk.dtsi"
++
++&bman_fbpr {
++      compatible = "fsl,bman-fbpr";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++&qman_fqd {
++      compatible = "fsl,qman-fqd";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++&qman_pfdr {
++      compatible = "fsl,qman-pfdr";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++
++&soc {
++#include "qoriq-dpaa-eth.dtsi"
++#include "qoriq-fman3-0-6oh.dtsi"
++};
++
++&fman0 {
++      compatible = "fsl,fman", "simple-bus";
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts
+@@ -0,0 +1,117 @@
++/*
++ * Device Tree Include file for Freescale Layerscape-1043A family SoC.
++ *
++ * Copyright (C) 2014-2015, Freescale Semiconductor
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2.  This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include "fsl-ls1043a-rdb-sdk.dts"
++
++&soc {
++      bp7: buffer-pool@7 {
++              compatible = "fsl,p4080-bpool", "fsl,bpool";
++              fsl,bpid = <7>;
++              fsl,bpool-ethernet-cfg = <0 0 0 192 0 0xdeadbeef>;
++              fsl,bpool-thresholds = <0x400 0xc00 0x0 0x0>;
++      };
++
++      bp8: buffer-pool@8 {
++              compatible = "fsl,p4080-bpool", "fsl,bpool";
++              fsl,bpid = <8>;
++              fsl,bpool-ethernet-cfg = <0 0 0 576 0 0xabbaf00d>;
++              fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>;
++      };
++
++      bp9: buffer-pool@9 {
++              compatible = "fsl,p4080-bpool", "fsl,bpool";
++              fsl,bpid = <9>;
++              fsl,bpool-ethernet-cfg = <0 0 0 2048 0 0xfeedabba>;
++              fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>;
++      };
++
++      fsl,dpaa {
++              compatible = "fsl,ls1043a", "fsl,dpaa", "simple-bus";
++
++              ethernet@0 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x50 1 0x51 1>;
++                      fsl,qman-frame-queues-tx = <0x70 1 0x71 1>;
++              };
++
++              ethernet@1 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x52 1 0x53 1>;
++                      fsl,qman-frame-queues-tx = <0x72 1 0x73 1>;
++              };
++
++              ethernet@2 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x54 1 0x55 1>;
++                      fsl,qman-frame-queues-tx = <0x74 1 0x75 1>;
++              };
++
++              ethernet@3 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x56 1 0x57 1>;
++                      fsl,qman-frame-queues-tx = <0x76 1 0x77 1>;
++              };
++
++              ethernet@4 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x58 1 0x59 1>;
++                      fsl,qman-frame-queues-tx = <0x78 1 0x79 1>;
++              };
++
++              ethernet@5 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x60 1 0x61 1>;
++                      fsl,qman-frame-queues-tx = <0x80 1 0x81 1>;
++              };
++
++              ethernet@8 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x5c 1 0x5d 1>;
++                      fsl,qman-frame-queues-tx = <0x7c 1 0x7d 1>;
++
++              };
++              dpa-fman0-oh@2 {
++                      compatible = "fsl,dpa-oh";
++                      /* Define frame queues for the OH port*/
++                      /* <OH Rx error, OH Rx default> */
++                      fsl,qman-frame-queues-oh = <0x5a 1 0x5b 1>;
++                      fsl,fman-oh-port = <&fman0_oh2>;
++              };
++      };
++};
++/ {
++      reserved-memory {
++              #address-cells = <2>;
++              #size-cells = <2>;
++              ranges;
++
++              usdpaa_mem: usdpaa_mem {
++                      compatible = "fsl,usdpaa-mem";
++                      alloc-ranges = <0 0 0x10000 0>;
++                      size = <0 0x10000000>;
++                      alignment = <0 0x10000000>;
++              };
++      };
++};
++
++&fman0 {
++      fman0_oh2: port@83000 {
++              cell-index = <1>;
++              compatible = "fsl,fman-port-oh";
++              reg = <0x83000 0x1000>;
++      };
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds-sdk.dts
+@@ -0,0 +1,79 @@
++/*
++ * Device Tree Include file for Freescale Layerscape-1046A family SoC.
++ *
++ * Copyright 2014-2015 Freescale Semiconductor, Inc.
++ *
++ * Mingkai Hu <Mingkai.hu@freescale.com>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPLv2 or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This library is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This library is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++#include "fsl-ls1046a-qds.dts"
++#include "qoriq-qman-portals-sdk.dtsi"
++#include "qoriq-bman-portals-sdk.dtsi"
++
++&bman_fbpr {
++      compatible = "fsl,bman-fbpr";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++&qman_fqd {
++      compatible = "fsl,qman-fqd";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++&qman_pfdr {
++      compatible = "fsl,qman-pfdr";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++
++&soc {
++#include "qoriq-dpaa-eth.dtsi"
++#include "qoriq-fman3-0-6oh.dtsi"
++};
++
++&fsldpaa {
++      ethernet@9 {
++              compatible = "fsl,dpa-ethernet";
++              fsl,fman-mac = <&enet7>;
++              dma-coherent;
++      };
++};
++
++&fman0 {
++      compatible = "fsl,fman", "simple-bus";
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts
+@@ -0,0 +1,115 @@
++/*
++ * Device Tree Include file for Freescale Layerscape-1046A family SoC.
++ *
++ * Copyright 2014-2015 Freescale Semiconductor, Inc.
++ *
++ * Mingkai Hu <Mingkai.hu@freescale.com>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPLv2 or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This library is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This library is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++#include "fsl-ls1046a-rdb.dts"
++#include "qoriq-qman-portals-sdk.dtsi"
++#include "qoriq-bman-portals-sdk.dtsi"
++
++&bman_fbpr {
++      compatible = "fsl,bman-fbpr";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++&qman_fqd {
++      compatible = "fsl,qman-fqd";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++&qman_pfdr {
++      compatible = "fsl,qman-pfdr";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++
++&soc {
++#include "qoriq-dpaa-eth.dtsi"
++#include "qoriq-fman3-0-6oh.dtsi"
++};
++
++&fsldpaa {
++      ethernet@0 {
++              status = "disabled";
++      };
++      ethernet@1 {
++              status = "disabled";
++      };
++      ethernet@9 {
++              compatible = "fsl,dpa-ethernet";
++              fsl,fman-mac = <&enet7>;
++              dma-coherent;
++      };
++};
++
++&fman0 {
++      compatible = "fsl,fman", "simple-bus";
++};
++
++&mdio9 {
++      pcsphy6: ethernet-phy@0 {
++              backplane-mode = "10gbase-kr";
++              compatible = "ethernet-phy-ieee802.3-c45";
++              reg = <0x0>;
++              fsl,lane-handle = <&serdes1>;
++              fsl,lane-reg = <0x8C0 0x40>;   /* lane D */
++      };
++};
++
++&mdio10 {
++      pcsphy7: ethernet-phy@0 {
++              backplane-mode = "10gbase-kr";
++              compatible = "ethernet-phy-ieee802.3-c45";
++              reg = <0x0>;
++              fsl,lane-handle = <&serdes1>;
++              fsl,lane-reg = <0x880 0x40>;   /* lane C */
++      };
++};
++
++/* Update MAC connections to backplane PHYs
++ * &mac9 {
++ *    phy-handle = <&pcsphy6>;
++ *};
++ *
++ *&mac10 {
++ *    phy-handle = <&pcsphy7>;
++ *};
++*/
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts
+@@ -0,0 +1,110 @@
++/*
++ * Device Tree Include file for Freescale Layerscape-1046A family SoC.
++ *
++ * Copyright (C) 2016, Freescale Semiconductor
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2.  This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include "fsl-ls1046a-rdb-sdk.dts"
++
++&soc {
++      bp7: buffer-pool@7 {
++              compatible = "fsl,ls1046a-bpool", "fsl,bpool";
++              fsl,bpid = <7>;
++              fsl,bpool-ethernet-cfg = <0 0 0 192 0 0xdeadbeef>;
++              fsl,bpool-thresholds = <0x400 0xc00 0x0 0x0>;
++      };
++
++      bp8: buffer-pool@8 {
++              compatible = "fsl,ls1046a-bpool", "fsl,bpool";
++              fsl,bpid = <8>;
++              fsl,bpool-ethernet-cfg = <0 0 0 576 0 0xabbaf00d>;
++              fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>;
++      };
++
++      bp9: buffer-pool@9 {
++              compatible = "fsl,ls1046a-bpool", "fsl,bpool";
++              fsl,bpid = <9>;
++              fsl,bpool-ethernet-cfg = <0 0 0 2048 0 0xfeedabba>;
++              fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>;
++      };
++
++      fsl,dpaa {
++              compatible = "fsl,ls1046a", "fsl,dpaa", "simple-bus";
++
++              ethernet@2 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x54 1 0x55 1>;
++                      fsl,qman-frame-queues-tx = <0x74 1 0x75 1>;
++              };
++
++              ethernet@3 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x56 1 0x57 1>;
++                      fsl,qman-frame-queues-tx = <0x76 1 0x77 1>;
++              };
++
++              ethernet@4 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x58 1 0x59 1>;
++                      fsl,qman-frame-queues-tx = <0x78 1 0x79 1>;
++              };
++
++              ethernet@5 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x5a 1 0x5b 1>;
++                      fsl,qman-frame-queues-tx = <0x7a 1 0x7b 1>;
++              };
++
++              ethernet@8 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x5c 1 0x5d 1>;
++                      fsl,qman-frame-queues-tx = <0x7c 1 0x7d 1>;
++              };
++
++              ethernet@9 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x5e 1 0x5f 1>;
++                      fsl,qman-frame-queues-tx = <0x7e 1 0x7f 1>;
++              };
++
++              dpa-fman0-oh@2 {
++                      compatible = "fsl,dpa-oh";
++                      /* Define frame queues for the OH port*/
++                      /* <OH Rx error, OH Rx default> */
++                      fsl,qman-frame-queues-oh = <0x60 1 0x61 1>;
++                      fsl,fman-oh-port = <&fman0_oh2>;
++              };
++      };
++};
++/ {
++      reserved-memory {
++              #address-cells = <2>;
++              #size-cells = <2>;
++              ranges;
++
++              usdpaa_mem: usdpaa_mem {
++                      compatible = "fsl,usdpaa-mem";
++                      alloc-ranges = <0 0 0x10000 0>;
++                      size = <0 0x10000000>;
++                      alignment = <0 0x10000000>;
++              };
++      };
++};
++
++&fman0 {
++      fman0_oh2: port@83000 {
++              cell-index = <1>;
++              compatible = "fsl,fman-port-oh";
++              reg = <0x83000 0x1000>;
++      };
++};
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0003-arm64-dts-ls1012a-Add-LS1012A-2G5RDB-board-support.patch b/target/linux/layerscape/patches-5.4/302-dts-0003-arm64-dts-ls1012a-Add-LS1012A-2G5RDB-board-support.patch
new file mode 100644 (file)
index 0000000..56501c3
--- /dev/null
@@ -0,0 +1,114 @@
+From 3261cabf5607c9f434faa4930ab5c2b0150579c4 Mon Sep 17 00:00:00 2001
+From: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+Date: Wed, 29 Nov 2017 06:23:14 +0530
+Subject: [PATCH] arm64: dts: ls1012a: Add LS1012A-2G5RDB board support
+
+LS1012A-2G5RDB is a different design from LS1012ARDB,
+but has some common SoC features. Key feature on this
+board is 2.5Gbps SGMII.
+
+Signed-off-by: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+Signed-off-by: Li Yang <leoyang.li@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/Makefile             |  1 +
+ .../boot/dts/freescale/fsl-ls1012a-2g5rdb.dts      | 86 ++++++++++++++++++++++
+ 2 files changed, 87 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1012a-2g5rdb.dts
+
+--- a/arch/arm64/boot/dts/freescale/Makefile
++++ b/arch/arm64/boot/dts/freescale/Makefile
+@@ -1,4 +1,5 @@
+ # SPDX-License-Identifier: GPL-2.0
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-2g5rdb.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-frdm.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-frwy.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-oxalis.dtb
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-2g5rdb.dts
+@@ -0,0 +1,86 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree file for NXP LS1012A 2G5RDB Board.
++ *
++ * Copyright 2017 NXP
++ *
++ * Bhaskar Upadhaya <bhaskar.upadhaya@nxp.com>
++ */
++/dts-v1/;
++
++#include "fsl-ls1012a.dtsi"
++
++/ {
++      model = "LS1012A 2G5RDB Board";
++      compatible = "fsl,ls1012a-rdb", "fsl,ls1012a";
++
++      aliases {
++              ethernet0 = &pfe_mac0;
++              ethernet1 = &pfe_mac1;
++      };
++};
++
++&duart0 {
++      status = "okay";
++};
++
++&i2c0 {
++      status = "okay";
++};
++
++&qspi {
++      num-cs = <2>;
++      bus-num = <0>;
++      status = "okay";
++
++      qflash0: s25fs512s@0 {
++              compatible = "spansion,m25p80";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              spi-max-frequency = <20000000>;
++              m25p,fast-read;
++              reg = <0>;
++      };
++};
++
++&sata {
++      status = "okay";
++};
++
++&pfe {
++      status = "okay";
++      #address-cells = <1>;
++      #size-cells = <0>;
++
++      ethernet@0 {
++              compatible = "fsl,pfe-gemac-port";
++              #address-cells = <1>;
++              #size-cells = <0>;
++              reg = <0x0>;    /* GEM_ID */
++              fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
++              fsl,gemac-phy-id = <0x1>;       /* PHY_ID */
++              fsl,mdio-mux-val = <0x0>;
++              phy-mode = "sgmii-2500";
++              fsl,pfe-phy-if-flags = <0x0>;
++
++              mdio@0 {
++                      reg = <0x1>; /* enabled/disabled */
++              };
++      };
++
++      ethernet@1 {
++              compatible = "fsl,pfe-gemac-port";
++              #address-cells = <1>;
++              #size-cells = <0>;
++              reg = <0x1>;    /* GEM_ID */
++              fsl,gemac-bus-id = < 0x0>;      /* BUS_ID */
++              fsl,gemac-phy-id = < 0x2>;      /* PHY_ID */
++              fsl,mdio-mux-val = <0x0>;
++              phy-mode = "sgmii-2500";
++              fsl,pfe-phy-if-flags = <0x0>;
++
++              mdio@0 {
++                      reg = <0x0>; /* enabled/disabled */
++              };
++      };
++};
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0004-arm64-dts-ls1012a-Add-more-nodes-to-LS1012A-FRWY-boa.patch b/target/linux/layerscape/patches-5.4/302-dts-0004-arm64-dts-ls1012a-Add-more-nodes-to-LS1012A-FRWY-boa.patch
new file mode 100644 (file)
index 0000000..9734813
--- /dev/null
@@ -0,0 +1,149 @@
+From 9ba5a56b7241c46aa47544f8414ad1f3d445f3c1 Mon Sep 17 00:00:00 2001
+From: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+Date: Mon, 7 May 2018 11:52:04 +0530
+Subject: [PATCH] arm64: dts: ls1012a: Add more nodes to LS1012A-FRWY board
+ support
+
+LS1012A-FRWY is a different design from LS1012A-FRDM,
+but has some common SoC features. Key feature on this
+board is 2x1G SGMII PFE MAC, Micro SD, USB 3.0, DDR,
+QuadSPI, Audio, UART.
+
+Signed-off-by: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+Signed-off-by: Li Yang <leoyang.li@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts | 118 +++++++++++++++++++++
+ 1 file changed, 118 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts
+@@ -14,6 +14,58 @@
+ / {
+       model = "LS1012A FRWY Board";
+       compatible = "fsl,ls1012a-frwy", "fsl,ls1012a";
++
++      aliases {
++              ethernet0 = &pfe_mac0;
++              ethernet1 = &pfe_mac1;
++      };
++
++      sys_mclk: clock-mclk {
++              compatible = "fixed-clock";
++              #clock-cells = <0>;
++              clock-frequency = <25000000>;
++      };
++
++      reg_1p8v: regulator-1p8v {
++              compatible = "regulator-fixed";
++              regulator-name = "1P8V";
++              regulator-min-microvolt = <1800000>;
++              regulator-max-microvolt = <1800000>;
++              regulator-always-on;
++      };
++
++      sound {
++              compatible = "simple-audio-card";
++              simple-audio-card,format = "i2s";
++              simple-audio-card,widgets =
++                      "Microphone", "Microphone Jack",
++                      "Headphone", "Headphone Jack",
++                      "Speaker", "Speaker Ext",
++                      "Line", "Line In Jack";
++              simple-audio-card,routing =
++                      "MIC_IN", "Microphone Jack",
++                      "Microphone Jack", "Mic Bias",
++                      "LINE_IN", "Line In Jack",
++                      "Headphone Jack", "HP_OUT",
++                      "Speaker Ext", "LINE_OUT";
++
++              simple-audio-card,cpu {
++                      sound-dai = <&sai2>;
++                      frame-master;
++                      bitclock-master;
++              };
++
++              simple-audio-card,codec {
++                      sound-dai = <&codec>;
++                      frame-master;
++                      bitclock-master;
++                      system-clock-frequency = <25000000>;
++              };
++      };
++};
++
++&pcie {
++      status = "okay";
+ };
+ &duart0 {
+@@ -22,4 +74,70 @@
+ &i2c0 {
+       status = "okay";
++
++      codec: sgtl5000@a {
++              compatible = "fsl,sgtl5000";
++              #sound-dai-cells = <0>;
++              reg = <0xa>;
++              VDDA-supply = <&reg_1p8v>;
++              VDDIO-supply = <&reg_1p8v>;
++              clocks = <&sys_mclk>;
++      };
++};
++
++&qspi {
++      num-cs = <1>;
++      bus-num = <0>;
++      status = "okay";
++
++      qflash0: w25q16dw@0 {
++              compatible = "spansion,m25p80";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              m25p,fast-read;
++              spi-max-frequency = <20000000>;
++              reg = <0>;
++      };
++};
++
++&pfe {
++      status = "okay";
++      #address-cells = <1>;
++      #size-cells = <0>;
++
++      ethernet@0 {
++              compatible = "fsl,pfe-gemac-port";
++              #address-cells = <1>;
++              #size-cells = <0>;
++              reg = <0x0>;    /* GEM_ID */
++              fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
++              fsl,gemac-phy-id = <0x2>;       /* PHY_ID */
++              fsl,mdio-mux-val = <0x0>;
++              phy-mode = "sgmii";
++              fsl,pfe-phy-if-flags = <0x0>;
++
++              mdio@0 {
++                      reg = <0x1>; /* enabled/disabled */
++              };
++      };
++
++      ethernet@1 {
++              compatible = "fsl,pfe-gemac-port";
++              #address-cells = <1>;
++              #size-cells = <0>;
++              reg = <0x1>;    /* GEM_ID */
++              fsl,gemac-bus-id = <0x1>;       /* BUS_ID */
++              fsl,gemac-phy-id = <0x1>;       /* PHY_ID */
++              fsl,mdio-mux-val = <0x0>;
++              phy-mode = "sgmii";
++              fsl,pfe-phy-if-flags = <0x0>;
++
++              mdio@0 {
++                      reg = <0x0>; /* enabled/disabled */
++              };
++      };
++};
++
++&sai2 {
++      status = "okay";
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0005-arm64-dts-ls2081ardb-Add-DTS-support-for-NXP-LS2081A.patch b/target/linux/layerscape/patches-5.4/302-dts-0005-arm64-dts-ls2081ardb-Add-DTS-support-for-NXP-LS2081A.patch
new file mode 100644 (file)
index 0000000..3894172
--- /dev/null
@@ -0,0 +1,164 @@
+From 5508bc9764760ca32990d5f7fa494be78e711ff6 Mon Sep 17 00:00:00 2001
+From: Li Yang <leoyang.li@nxp.com>
+Date: Fri, 5 Oct 2018 18:22:46 -0500
+Subject: [PATCH] arm64: dts: ls2081ardb: Add DTS support for NXP LS2081ARDB
+
+This patch add support for NXP LS2081ARDB board which has
+LS2081A SoC.
+
+LS2081A SoC is 40-pin derivative of LS2088A SoC
+So, from functional perspective both are same.
+Hence,ls2088a SoC dtsi files are included from ls2081ARDB dts
+
+Signed-off-by: Priyanka Jain <priyanka.jain@nxp.com>
+Signed-off-by: Santan Kumar <santan.kumar@nxp.com>
+Signed-off-by: Tao Yang <b31903@freescale.com>
+Signed-off-by: Yogesh Gaur <yogeshnarayan.gaur@nxp.com>
+Signed-off-by: Abhimanyu Saini <abhimanyu.saini@nxp.com>
+Signed-off-by: Li Yang <leoyang.li@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/Makefile            |   1 +
+ arch/arm64/boot/dts/freescale/fsl-ls2081a-rdb.dts | 127 ++++++++++++++++++++++
+ 2 files changed, 128 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls2081a-rdb.dts
+
+--- a/arch/arm64/boot/dts/freescale/Makefile
++++ b/arch/arm64/boot/dts/freescale/Makefile
+@@ -22,6 +22,7 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1088a-rdb.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-qds.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-rdb.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2081a-rdb.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-simu.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2088a-qds.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2088a-rdb.dtb
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls2081a-rdb.dts
+@@ -0,0 +1,127 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree file for NXP LS2081A RDB Board.
++ *
++ * Copyright 2017 NXP
++ *
++ * Priyanka Jain <priyanka.jain@nxp.com>
++ *
++ */
++
++/dts-v1/;
++
++#include "fsl-ls2088a.dtsi"
++
++/ {
++      model = "NXP Layerscape 2081A RDB Board";
++      compatible = "fsl,ls2081a-rdb", "fsl,ls2081a";
++
++      aliases {
++              serial0 = &serial0;
++              serial1 = &serial1;
++      };
++
++      chosen {
++              stdout-path = "serial1:115200n8";
++      };
++};
++
++&esdhc {
++      status = "okay";
++};
++
++&ifc {
++      status = "disabled";
++};
++
++&i2c0 {
++      status = "okay";
++      pca9547@75 {
++              compatible = "nxp,pca9547";
++              reg = <0x75>;
++              #address-cells = <1>;
++              #size-cells = <0>;
++              i2c@1 {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      reg = <0x01>;
++                      rtc@51 {
++                              compatible = "nxp,pcf2129";
++                              reg = <0x51>;
++                      };
++              };
++
++              i2c@2 {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      reg = <0x02>;
++
++                      ina220@40 {
++                              compatible = "ti,ina220";
++                              reg = <0x40>;
++                              shunt-resistor = <500>;
++                      };
++              };
++
++              i2c@3 {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      reg = <0x3>;
++
++                      adt7481@4c {
++                              compatible = "adi,adt7461";
++                              reg = <0x4c>;
++                      };
++              };
++      };
++};
++
++&dspi {
++      status = "okay";
++      dflash0: n25q512a@0 {
++              #address-cells = <1>;
++              #size-cells = <1>;
++              compatible = "st,m25p80";
++              spi-max-frequency = <3000000>;
++              reg = <0>;
++      };
++};
++
++&qspi {
++      status = "okay";
++      fsl,qspi-has-second-chip;
++      flash0: s25fs512s@0 {
++              #address-cells = <1>;
++              #size-cells = <1>;
++              compatible = "spansion,m25p80";
++              spi-rx-bus-width = <4>;
++              spi-tx-bus-width = <4>;
++              spi-max-frequency = <20000000>;
++              reg = <0>;
++      };
++      flash1: s25fs512s@1 {
++              #address-cells = <1>;
++              #size-cells = <1>;
++              spi-rx-bus-width = <4>;
++              spi-tx-bus-width = <4>;
++              compatible = "spansion,m25p80";
++              spi-max-frequency = <20000000>;
++              reg = <1>;
++      };
++};
++
++&sata0 {
++      status = "okay";
++};
++
++&sata1 {
++      status = "okay";
++};
++
++&usb0 {
++      status = "okay";
++};
++
++&usb1 {
++      status = "okay";
++};
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0006-arm64-dts-ls1012a-accumulated-change-for-ls1012a-boa.patch b/target/linux/layerscape/patches-5.4/302-dts-0006-arm64-dts-ls1012a-accumulated-change-for-ls1012a-boa.patch
new file mode 100644 (file)
index 0000000..9c7626a
--- /dev/null
@@ -0,0 +1,461 @@
+From 8fd1ab38e922383fa87db60c48c44ab0d5e6f1c1 Mon Sep 17 00:00:00 2001
+From: Li Yang <leoyang.li@nxp.com>
+Date: Thu, 2 May 2019 15:52:49 -0500
+Subject: [PATCH] arm64: dts: ls1012a: accumulated change for ls1012a boards
+
+commit 65c558ec270003e8e99cb58c940d3b913d08fa39
+Author: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date:   Tue May 15 08:47:19 2018 +0800
+
+    arm64: dts: ls1012a: correct the register range of dcfg
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit 8f7b4cded4ea1fca53516ae8f5d5bc89af291f26
+Author: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+Date:   Mon May 7 11:52:04 2018 +0530
+
+    arm64: dts: ls1012a: Add LS1012A-FRWY board support
+
+    LS1012A-FRWY is a different design from LS1012A-FRDM,
+    but has some common SoC features. Key feature on this
+    board is 2x1G SGMII PFE MAC, Micro SD, USB 3.0, DDR,
+    QuadSPI, Audio, UART.
+
+    Signed-off-by: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+
+commit 94fc77837b3b6f4213a49b29ddc3e09e38ae5fbb
+Author: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date:   Mon Apr 2 16:16:47 2018 +0800
+
+    arm64: dts: ls1012a: add dts entry for A-010650
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit d4164a6d8cffd8f09c451073754834d58b7ace19
+Author: Suresh Gupta <suresh.gupta@nxp.com>
+Date:   Thu Feb 1 23:44:15 2018 +0530
+
+    arm64: dts: freescale: ls1012a: Add DT nodes for qspi
+
+    Signed-off-by: Abhimanyu Saini <abhimanyu.saini@nxp.com>
+    Signed-off-by: Suresh Gupta <suresh.gupta@nxp.com>
+
+commit 4fdc98a03492b732a48426a4180f7d6a36847e71
+Author: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date:   Wed Nov 1 10:31:47 2017 +0800
+
+    arm64: dts: ls1012a: correct the i2c clock to 1/4 platform pll
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit bb534725996b92aff853a4dee43738629fd4ac08
+Author: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+Date:   Wed Nov 29 06:31:23 2017 +0530
+
+    arm64: dts: freescale: ls1012a: Disable PCIe node as default
+
+    Keep PCIe node in "disabled" status as SoC default.
+    Only enable it for boards with PCIe circuit designed,
+    such as LS1012ARDB and LS1012AQDS.
+
+    Signed-off-by: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+
+commit 6b9a3244baba2c5126f349800ecaad83ba97ee47
+Author: Calvin Johnson <calvin.johnson@nxp.com>
+Date:   Mon Oct 16 12:25:19 2017 +0530
+
+    arm64: dts: freescale: ls1012a: fix RGMII tx delay issue
+
+    Recently logic to enable RGMII tx delay was changed by
+    below patch.
+
+    https://patchwork.kernel.org/patch/9447581/
+
+    Based on the patch, enabling tx delay again using rgmii-txid.
+
+    Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+    Signed-off-by: Anjaneyulu Jagarlmudi <anji.jagarlmudi@nxp.com>
+
+commit 1e17e247088f6e2c08041559e38053b70a9d2bbe
+Author: Calvin Johnson <calvin.johnson@nxp.com>
+Date:   Sat Sep 16 14:20:23 2017 +0530
+
+    arm64: dts: freescale: ls1012a: update with pppfe support
+
+            Update ls1012a dtsi and platform dts files with
+    support for ppfe.
+
+    Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+    Signed-off-by: Anjaneyulu Jagarlmudi <anji.jagarlmudi@nxp.com>
+
+commit e9661ed864d2a9d437057f97729410bb9af994f2
+Author: Suresh Gupta <suresh.gupta@nxp.com>
+Date:   Tue May 16 17:17:21 2017 +0530
+
+    arm64: dts: ls1012a: add the DTS node for QSPI support
+
+    There is a s25fs512s qspi flash on QDS, RDB and FRDM board.
+
+    Signed-off-by: Yuan Yao <yao.yuan@nxp.com>
+
+commit ed9c51239461fe0322da2e93f50033ea0d05bc4f
+Author: Chenhui Zhao <chenhui.zhao@nxp.com>
+Date:   Fri May 5 17:45:15 2017 +0800
+
+    arm64: dts: ls1012a: add ftm0 node
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts | 58 ++++++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts  | 62 ++++++++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts  | 62 ++++++++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi     | 68 +++++++++++++++++++++-
+ 4 files changed, 248 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts
+@@ -13,6 +13,11 @@
+       model = "LS1012A Freedom Board";
+       compatible = "fsl,ls1012a-frdm", "fsl,ls1012a";
++      aliases {
++              ethernet0 = &pfe_mac0;
++              ethernet1 = &pfe_mac1;
++      };
++
+       sys_mclk: clock-mclk {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+@@ -74,6 +79,44 @@
+       };
+ };
++&pfe {
++      status = "okay";
++      #address-cells = <1>;
++      #size-cells = <0>;
++
++      ethernet@0 {
++              compatible = "fsl,pfe-gemac-port";
++              #address-cells = <1>;
++              #size-cells = <0>;
++              reg = <0x0>;    /* GEM_ID */
++              fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
++              fsl,gemac-phy-id = <0x2>;       /* PHY_ID */
++              fsl,mdio-mux-val = <0x0>;
++              phy-mode = "sgmii";
++              fsl,pfe-phy-if-flags = <0x0>;
++
++              mdio@0 {
++                      reg = <0x1>; /* enabled/disabled */
++              };
++      };
++
++      ethernet@1 {
++              compatible = "fsl,pfe-gemac-port";
++              #address-cells = <1>;
++              #size-cells = <0>;
++              reg = <0x1>;    /* GEM_ID */
++              fsl,gemac-bus-id = <0x1>;       /* BUS_ID */
++              fsl,gemac-phy-id = <0x1>;       /* PHY_ID */
++              fsl,mdio-mux-val = <0x0>;
++              phy-mode = "sgmii";
++              fsl,pfe-phy-if-flags = <0x0>;
++
++              mdio@0 {
++                      reg = <0x0>; /* enabled/disabled */
++              };
++      };
++};
++
+ &sai2 {
+       status = "okay";
+ };
+@@ -81,3 +124,18 @@
+ &sata {
+       status = "okay";
+ };
++
++&qspi {
++      status = "okay";
++      qflash0: s25fs512s@0 {
++              compatible = "spansion,m25p80";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              spi-max-frequency = <20000000>;
++              m25p,fast-read;
++              reg = <0>;
++              spi-rx-bus-width = <2>;
++              spi-tx-bus-width = <2>;
++      };
++
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts
+@@ -13,6 +13,11 @@
+       model = "LS1012A QDS Board";
+       compatible = "fsl,ls1012a-qds", "fsl,ls1012a";
++      aliases {
++              ethernet0 = &pfe_mac0;
++              ethernet1 = &pfe_mac1;
++      };
++
+       sys_mclk: clock-mclk {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+@@ -57,6 +62,10 @@
+       };
+ };
++&pcie {
++      status = "okay";
++};
++
+ &dspi {
+       bus-num = <0>;
+       status = "okay";
+@@ -128,6 +137,44 @@
+       };
+ };
++&pfe {
++      status = "okay";
++      #address-cells = <1>;
++      #size-cells = <0>;
++
++      ethernet@0 {
++              compatible = "fsl,pfe-gemac-port";
++              #address-cells = <1>;
++              #size-cells = <0>;
++              reg = <0x0>;    /* GEM_ID */
++              fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
++              fsl,gemac-phy-id = <0x1>;       /* PHY_ID */
++              fsl,mdio-mux-val = <0x2>;
++              phy-mode = "sgmii-2500";
++              fsl,pfe-phy-if-flags = <0x0>;
++
++              mdio@0 {
++                      reg = <0x1>; /* enabled/disabled */
++              };
++      };
++
++      ethernet@1 {
++              compatible = "fsl,pfe-gemac-port";
++              #address-cells = <1>;
++              #size-cells = <0>;
++              reg = <0x1>;    /* GEM_ID */
++              fsl,gemac-bus-id = <0x1>;       /* BUS_ID */
++              fsl,gemac-phy-id = <0x2>;       /* PHY_ID */
++              fsl,mdio-mux-val = <0x3>;
++              phy-mode = "sgmii-2500";
++              fsl,pfe-phy-if-flags = <0x0>;
++
++              mdio@0 {
++                      reg = <0x0>; /* enabled/disabled */
++              };
++      };
++};
++
+ &sai2 {
+       status = "okay";
+ };
+@@ -135,3 +182,18 @@
+ &sata {
+       status = "okay";
+ };
++
++&qspi {
++      status = "okay";
++      qflash0: s25fs512s@0 {
++              compatible = "spansion,m25p80";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              spi-max-frequency = <20000000>;
++              m25p,fast-read;
++              reg = <0>;
++              spi-rx-bus-width = <2>;
++              spi-tx-bus-width = <2>;
++      };
++
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
+@@ -12,6 +12,15 @@
+ / {
+       model = "LS1012A RDB Board";
+       compatible = "fsl,ls1012a-rdb", "fsl,ls1012a";
++
++      aliases {
++              ethernet0 = &pfe_mac0;
++              ethernet1 = &pfe_mac1;
++      };
++};
++
++&pcie {
++      status = "okay";
+ };
+ &duart0 {
+@@ -38,3 +47,56 @@
+ &sata {
+       status = "okay";
+ };
++
++&pfe {
++      status = "okay";
++      #address-cells = <1>;
++      #size-cells = <0>;
++
++      ethernet@0 {
++              compatible = "fsl,pfe-gemac-port";
++              #address-cells = <1>;
++              #size-cells = <0>;
++              reg = <0x0>;    /* GEM_ID */
++              fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
++              fsl,gemac-phy-id = <0x2>;       /* PHY_ID */
++              fsl,mdio-mux-val = <0x0>;
++              phy-mode = "sgmii";
++              fsl,pfe-phy-if-flags = <0x0>;
++
++              mdio@0 {
++                      reg = <0x1>; /* enabled/disabled */
++              };
++      };
++
++      ethernet@1 {
++              compatible = "fsl,pfe-gemac-port";
++              #address-cells = <1>;
++              #size-cells = <0>;
++              reg = <0x1>;    /* GEM_ID */
++              fsl,gemac-bus-id = < 0x1 >;     /* BUS_ID */
++              fsl,gemac-phy-id = < 0x1 >;     /* PHY_ID */
++              fsl,mdio-mux-val = <0x0>;
++              phy-mode = "rgmii-txid";
++              fsl,pfe-phy-if-flags = <0x0>;
++
++              mdio@0 {
++                      reg = <0x0>; /* enabled/disabled */
++              };
++      };
++};
++
++&qspi {
++      status = "okay";
++      qflash0: s25fs512s@0 {
++              compatible = "spansion,m25p80";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              spi-max-frequency = <20000000>;
++              m25p,fast-read;
++              reg = <0>;
++              spi-rx-bus-width = <2>;
++              spi-tx-bus-width = <2>;
++      };
++
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+@@ -260,7 +260,7 @@
+               dcfg: dcfg@1ee0000 {
+                       compatible = "fsl,ls1012a-dcfg",
+                                    "syscon";
+-                      reg = <0x0 0x1ee0000 0x0 0x10000>;
++                      reg = <0x0 0x1ee0000 0x0 0x1000>;
+                       big-endian;
+               };
+@@ -317,13 +317,23 @@
+                       #thermal-sensor-cells = <1>;
+               };
++              ftm0: ftm0@29d0000 {
++                      compatible = "fsl,ftm-alarm";
++                      reg = <0x0 0x29d0000 0x0 0x10000>,
++                            <0x0 0x1ee2140 0x0 0x4>;
++                      reg-names = "ftm", "FlexTimer1";
++                      interrupts = <0 86 0x4>;
++                      big-endian;
++              };
++
+               i2c0: i2c@2180000 {
+-                      compatible = "fsl,vf610-i2c";
++                      compatible = "fsl,vf610-i2c", "fsl,ls1012a-vf610-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0 0x2180000 0x0 0x10000>;
+                       interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 3>;
++                      scl-gpios = <&gpio0 13 0>;
+                       status = "disabled";
+               };
+@@ -395,6 +405,20 @@
+                       big-endian;
+               };
++              qspi: spi@1550000 {
++                      compatible = "fsl,ls1012a-qspi", "fsl,ls1021a-qspi";
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      reg = <0x0 0x1550000 0x0 0x10000>,
++                              <0x0 0x40000000 0x0 0x10000000>;
++                      reg-names = "QuadSPI", "QuadSPI-memory";
++                      interrupts = <0 99 IRQ_TYPE_LEVEL_HIGH>;
++                      clock-names = "qspi_en", "qspi";
++                      clocks = <&clockgen 4 0>, <&clockgen 4 0>;
++                      big-endian;
++                      status = "disabled";
++              };
++
+               sai1: sai@2b50000 {
+                       #sound-dai-cells = <0>;
+                       compatible = "fsl,vf610-sai";
+@@ -499,6 +523,46 @@
+                                       <0000 0 0 4 &gic 0 113 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "disabled";
+               };
++
++              rcpm: rcpm@1ee2000 {
++                      compatible = "fsl,ls1012a-rcpm", "fsl,qoriq-rcpm-2.1";
++                      reg = <0x0 0x1ee2000 0x0 0x1000>;
++                      fsl,#rcpm-wakeup-cells = <1>;
++              };
++      };
++
++      reserved-memory {
++              #address-cells = <2>;
++              #size-cells = <2>;
++              ranges;
++
++              pfe_reserved: packetbuffer@83400000 {
++                      reg = <0 0x83400000 0 0xc00000>;
++              };
++      };
++
++      pfe: pfe@04000000 {
++              compatible = "fsl,pfe";
++              reg =   <0x0 0x04000000 0x0 0xc00000>,  /* AXI 16M */
++                      <0x0 0x83400000 0x0 0xc00000>;  /* PFE DDR 12M */
++              reg-names = "pfe", "pfe-ddr";
++              fsl,pfe-num-interfaces = <0x2>;
++              interrupts = <0 172 0x4>,    /* HIF interrupt */
++                           <0 173 0x4>,    /*HIF_NOCPY interrupt */
++                           <0 174 0x4>;    /* WoL interrupt */
++              interrupt-names = "pfe_hif", "pfe_hif_nocpy", "pfe_wol";
++              memory-region = <&pfe_reserved>;
++              fsl,pfe-scfg = <&scfg 0>;
++              fsl,rcpm-wakeup = <&rcpm 0xf0000020>;
++              clocks = <&clockgen 4 0>;
++              clock-names = "pfe";
++
++              status = "okay";
++              pfe_mac0: ethernet@0 {
++              };
++
++              pfe_mac1: ethernet@1 {
++              };
+       };
+       firmware {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0007-arm64-dts-ls1043a-accumulated-change-for-ls1043a-boa.patch b/target/linux/layerscape/patches-5.4/302-dts-0007-arm64-dts-ls1043a-accumulated-change-for-ls1043a-boa.patch
new file mode 100644 (file)
index 0000000..3455811
--- /dev/null
@@ -0,0 +1,574 @@
+From 794b9e55c77bf0ef34dfdb3b151a845c004b3ce3 Mon Sep 17 00:00:00 2001
+From: Li Yang <leoyang.li@nxp.com>
+Date: Thu, 2 May 2019 16:01:01 -0500
+Subject: [PATCH] arm64: dts: ls1043a: accumulated change for ls1043a boards
+
+commit 118e2f48ee8da3f5547c24888bd6fdb78f03b7ce
+Author: Peng Ma <peng.ma@nxp.com>
+Date:   Wed Jul 25 08:53:07 2018 +0000
+
+    dts: fsl-ls1021a, fsl-ls1043a, fsl-ls1046a: add multi block node
+support
+
+    add block-offset to support different virtual block offset for qdma
+    base on soc;
+    the interrupt named "qdma-queueN(N:0,1,2,3)" correspond to a virtual
+    block,N based on block number of qdma;
+
+    Signed-off-by: Peng Ma <peng.ma@nxp.com>
+
+Author: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date:   Mon Apr 2 16:22:40 2018 +0800
+
+    arm64: dts: ls1043a: add dts entry for A-010650
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit a47e4bd0b5d076feb6d81601c16d5b79e53a92c8
+Author: Rajesh Bhagat <rajesh.bhagat@freescale.com>
+Date:   Wed Jan 27 11:37:25 2016 +0530
+
+    arm64: dts: ls1043a: Add configure-gfladj property to USB3 node
+
+    Add "configure-gfladj" boolean property to USB3 node. This property
+    is used to determine whether frame length adjustent is required
+    or not
+
+    Signed-off-by: Rajesh Bhagat <rajesh.bhagat@nxp.com>
+    Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+
+commit 38566bbd5ca6747b30d2f0c251bbcfe0723df8c6
+Author: Changming Huang <jerry.huang@nxp.com>
+Date:   Wed Apr 19 12:49:50 2017 +0800
+
+    arm/arm64: dts: Add property snps incr burst type adjustment for
+INCR burst type for dwc3
+
+    Signed-off-by: yinbo.zhu <yinbo.zhu@nxp.com>
+    Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+
+commit 8632d84e0fe187aa023a24f0dad0040c53e12450
+Author: Abhimanyu Saini <abhimanyu.saini@nxp.com>
+Date:   Thu Jan 25 11:31:13 2018 +0530
+
+    arm64: dts: freescale: ls1043a: Modify DT nodes for qspi
+
+    Signed-off-by: Abhimanyu Saini <abhimanyu.saini@nxp.com>
+
+commit b1dc1ebed79e9aaab75fd06837d794ec2f1b624d
+Author: Ran Wang <ran.wang_1@nxp.com>
+Date:   Fri Jan 5 15:14:48 2018 +0800
+
+    arm64: dts: ls1043a: Enable usb3-lpm-capable for usb3 node
+
+    Enable USB3 HW LPM feature for ls1043a and active patch for
+    snps erratum A-010131. It will disable U1/U2 temperary when
+    initiate U3 request.
+
+    Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+
+commit 9b17a5fcf8da5656ff99ebef3d63ba040e9f676d
+Author: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date:   Tue Jun 13 13:14:26 2017 +0800
+
+    arm64: dts: correct the register range of dcfg
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit f60e39fd51ad702e3a2613faaca40871a4763735
+Author: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date:   Tue Aug 22 18:04:02 2017 +0800
+
+    arm64: dts: ls1043a: add pcf85263 rtc nodes
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit 67c82e3c7b376139d7cee624589bedbc311f8868
+Author: jiaheng.fan <jiaheng.fan@nxp.com>
+Date:   Thu May 11 17:36:33 2017 +0800
+
+    arm64: dts: ls1021/ls1043/ls1046: add qdma nodes
+    Signed-off-by: jiaheng.fan <jiaheng.fan@nxp.com>
+
+commit c6d9c2498ee83669f9853100301edff9a5905caf
+Author: Wang Dongsheng <dongsheng.wang@nxp.com>
+Date:   Fri Apr 21 13:26:07 2017 +0800
+
+    arm64: dts: ls1043a: add ftm0 nodes
+
+    Add rcpm and ftm0 nodes. The Power Management related features
+    need these nodes.
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit 3bcdc4de0a1c9e6f4a4ddc916e8efe8044d8bbfd
+Author: Po Liu <po.liu@nxp.com>
+Date:   Fri Sep 30 17:11:36 2016 +0800
+
+    arm64: dts: ls1043/ls2080: add pcie aer/pme interrupt-name property
+
+    Some platforms(NXP Layerscape for example) aer/pme interrupts was
+not
+    MSI/MSI-X/INTx but using interrupt line independently. This patch
+    add "aer", "pme" interrupt-names for aer/pme interrupt.
+
+    With the interrupt-names "aer", "pme" code could probe aer/pme
+interrupt
+    line for pcie root port, replace the aer/pme interrupt service irqs.
+
+    This is intend to fixup the Layerscape platforms which aer/pmes
+interrupts
+    was not MSI/MSI-X/INTx, but using interrupt line independently.
+
+    Since the interrupt-names "intr" never been used. Remove it.
+
+    Signed-off-by: Po Liu <po.liu@nxp.com>
+    Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+
+commit 4d20ecf029f1255520b30c103e1724c618b981c7
+Author: Zhao Qiang <qiang.zhao@nxp.com>
+Date:   Sun Jun 12 15:51:44 2016 +0800
+
+    arm64: dts: ls1043ardb: add ds26522 node
+
+    add ds26522 node to fsl-ls1043a-rdb.dts
+
+    Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
+
+commit ca470562646ab058814fc4a1195016fb3266cdf5
+Author: Zhao Qiang <qiang.zhao@nxp.com>
+Date:   Sun Jun 12 15:44:11 2016 +0800
+
+    arm64: dts: ls1043ardb: add qe node
+
+    Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts | 162 ++++++++++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts |  36 +++++
+ arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi    | 108 +++++++++++++--
+ 3 files changed, 295 insertions(+), 11 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts
+@@ -24,6 +24,22 @@
+               serial1 = &duart1;
+               serial2 = &duart2;
+               serial3 = &duart3;
++              sgmii_riser_s1_p1 = &sgmii_phy_s1_p1;
++              sgmii_riser_s2_p1 = &sgmii_phy_s2_p1;
++              sgmii_riser_s3_p1 = &sgmii_phy_s3_p1;
++              sgmii_riser_s4_p1 = &sgmii_phy_s4_p1;
++              qsgmii_s1_p1 = &qsgmii_phy_s1_p1;
++              qsgmii_s1_p2 = &qsgmii_phy_s1_p2;
++              qsgmii_s1_p3 = &qsgmii_phy_s1_p3;
++              qsgmii_s1_p4 = &qsgmii_phy_s1_p4;
++              qsgmii_s2_p1 = &qsgmii_phy_s2_p1;
++              qsgmii_s2_p2 = &qsgmii_phy_s2_p2;
++              qsgmii_s2_p3 = &qsgmii_phy_s2_p3;
++              qsgmii_s2_p4 = &qsgmii_phy_s2_p4;
++              emi1_slot1 = &ls1043mdio_s1;
++              emi1_slot2 = &ls1043mdio_s2;
++              emi1_slot3 = &ls1043mdio_s3;
++              emi1_slot4 = &ls1043mdio_s4;
+       };
+       chosen {
+@@ -64,6 +80,8 @@
+       fpga: board-control@2,0 {
+               compatible = "fsl,ls1043aqds-fpga", "fsl,fpga-qixis";
+               reg = <0x2 0x0 0x0000100>;
++              #address-cells = <1>;
++              #size-cells = <1>;
+       };
+ };
+@@ -149,3 +167,147 @@
+ };
+ #include "fsl-ls1043-post.dtsi"
++
++&fman0 {
++      ethernet@e0000 {
++              phy-handle = <&qsgmii_phy_s2_p1>;
++              phy-connection-type = "sgmii";
++      };
++
++      ethernet@e2000 {
++              phy-handle = <&qsgmii_phy_s2_p2>;
++              phy-connection-type = "sgmii";
++      };
++
++      ethernet@e4000 {
++              phy-handle = <&rgmii_phy1>;
++              phy-connection-type = "rgmii";
++      };
++
++      ethernet@e6000 {
++              phy-handle = <&rgmii_phy2>;
++              phy-connection-type = "rgmii";
++      };
++
++      ethernet@e8000 {
++              phy-handle = <&qsgmii_phy_s2_p3>;
++              phy-connection-type = "sgmii";
++      };
++
++      ethernet@ea000 {
++              phy-handle = <&qsgmii_phy_s2_p4>;
++              phy-connection-type = "sgmii";
++      };
++
++      ethernet@f0000 { /* DTSEC9/10GEC1 */
++              fixed-link = <1 1 10000 0 0>;
++              phy-connection-type = "xgmii";
++      };
++};
++
++&fpga {
++      mdio-mux-emi1 {
++              compatible = "mdio-mux-mmioreg", "mdio-mux";
++              mdio-parent-bus = <&mdio0>;
++              #address-cells = <1>;
++              #size-cells = <0>;
++              reg = <0x54 1>;    /* BRDCFG4 */
++              mux-mask = <0xe0>; /* EMI1 */
++
++              /* On-board RGMII1 PHY */
++              ls1043mdio0: mdio@0 {
++                      reg = <0>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++
++                      rgmii_phy1: ethernet-phy@1 { /* MAC3 */
++                              reg = <0x1>;
++                      };
++              };
++
++              /* On-board RGMII2 PHY */
++              ls1043mdio1: mdio@1 {
++                      reg = <0x20>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++
++                      rgmii_phy2: ethernet-phy@2 { /* MAC4 */
++                              reg = <0x2>;
++                      };
++              };
++
++              /* Slot 1 */
++              ls1043mdio_s1: mdio@2 {
++                      reg = <0x40>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      status = "disabled";
++
++                      qsgmii_phy_s1_p1: ethernet-phy@4 {
++                              reg = <0x4>;
++                      };
++                      qsgmii_phy_s1_p2: ethernet-phy@5 {
++                              reg = <0x5>;
++                      };
++                      qsgmii_phy_s1_p3: ethernet-phy@6 {
++                              reg = <0x6>;
++                      };
++                      qsgmii_phy_s1_p4: ethernet-phy@7 {
++                              reg = <0x7>;
++                      };
++
++                      sgmii_phy_s1_p1: ethernet-phy@1c {
++                              reg = <0x1c>;
++                      };
++              };
++
++              /* Slot 2 */
++              ls1043mdio_s2: mdio@3 {
++                      reg = <0x60>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      status = "disabled";
++
++                      qsgmii_phy_s2_p1: ethernet-phy@8 {
++                              reg = <0x8>;
++                      };
++                      qsgmii_phy_s2_p2: ethernet-phy@9 {
++                              reg = <0x9>;
++                      };
++                      qsgmii_phy_s2_p3: ethernet-phy@a {
++                              reg = <0xa>;
++                      };
++                      qsgmii_phy_s2_p4: ethernet-phy@b {
++                              reg = <0xb>;
++                      };
++
++                      sgmii_phy_s2_p1: ethernet-phy@1c {
++                              reg = <0x1c>;
++                      };
++              };
++
++              /* Slot 3 */
++              ls1043mdio_s3: mdio@4 {
++                      reg = <0x80>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      status = "disabled";
++
++                      sgmii_phy_s3_p1: ethernet-phy@1c {
++                              reg = <0x1c>;
++                      };
++              };
++
++              /* Slot 4 */
++              ls1043mdio_s4: mdio@5 {
++                      reg = <0xa0>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      status = "disabled";
++
++                      sgmii_phy_s4_p1: ethernet-phy@1c {
++                              reg = <0x1c>;
++                      };
++              };
++      };
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts
+@@ -49,6 +49,10 @@
+               compatible = "pericom,pt7c4338";
+               reg = <0x68>;
+       };
++      rtc@51 {
++              compatible = "nxp,pcf85263";
++              reg = <0x51>;
++      };
+ };
+ &ifc {
+@@ -94,6 +98,38 @@
+               reg = <0>;
+               spi-max-frequency = <1000000>; /* input clock */
+       };
++
++      slic@2 {
++              compatible = "maxim,ds26522";
++              reg = <2>;
++              spi-max-frequency = <2000000>;
++              fsl,spi-cs-sck-delay = <100>;
++              fsl,spi-sck-cs-delay = <50>;
++      };
++
++      slic@3 {
++              compatible = "maxim,ds26522";
++              reg = <3>;
++              spi-max-frequency = <2000000>;
++              fsl,spi-cs-sck-delay = <100>;
++              fsl,spi-sck-cs-delay = <50>;
++      };
++};
++
++&uqe {
++      ucc_hdlc: ucc@2000 {
++              compatible = "fsl,ucc-hdlc";
++              rx-clock-name = "clk8";
++              tx-clock-name = "clk9";
++              fsl,rx-sync-clock = "rsync_pin";
++              fsl,tx-sync-clock = "tsync_pin";
++              fsl,tx-timeslot-mask = <0xfffffffe>;
++              fsl,rx-timeslot-mask = <0xfffffffe>;
++              fsl,tdm-framer-type = "e1";
++              fsl,tdm-id = <0>;
++              fsl,siram-entry-id = <0>;
++              fsl,tdm-interface;
++      };
+ };
+ &duart0 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+@@ -277,7 +277,7 @@
+               dcfg: dcfg@1ee0000 {
+                       compatible = "fsl,ls1043a-dcfg", "syscon";
+-                      reg = <0x0 0x1ee0000 0x0 0x10000>;
++                      reg = <0x0 0x1ee0000 0x0 0x1000>;
+                       big-endian;
+               };
+@@ -411,7 +411,7 @@
+               };
+               i2c0: i2c@2180000 {
+-                      compatible = "fsl,vf610-i2c";
++                      compatible = "fsl,vf610-i2c", "fsl,ls1043a-vf610-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0 0x2180000 0x0 0x10000>;
+@@ -421,6 +421,7 @@
+                       dmas = <&edma0 1 39>,
+                              <&edma0 1 38>;
+                       dma-names = "tx", "rx";
++                      scl-gpios = <&gpio4 12 0>;
+                       status = "disabled";
+               };
+@@ -525,6 +526,72 @@
+                       #interrupt-cells = <2>;
+               };
++              uqe: uqe@2400000 {
++                      #address-cells = <1>;
++                      #size-cells = <1>;
++                      device_type = "qe";
++                      compatible = "fsl,qe", "simple-bus";
++                      ranges = <0x0 0x0 0x2400000 0x40000>;
++                      reg = <0x0 0x2400000 0x0 0x480>;
++                      brg-frequency = <100000000>;
++                      bus-frequency = <200000000>;
++
++                      fsl,qe-num-riscs = <1>;
++                      fsl,qe-num-snums = <28>;
++
++                      qeic: qeic@80 {
++                              compatible = "fsl,qe-ic";
++                              reg = <0x80 0x80>;
++                              #address-cells = <0>;
++                              interrupt-controller;
++                              #interrupt-cells = <1>;
++                              interrupts = <0 77 0x04 0 77 0x04>;
++                      };
++
++                      si1: si@700 {
++                              #address-cells = <1>;
++                              #size-cells = <0>;
++                              compatible = "fsl,ls1043-qe-si",
++                                              "fsl,t1040-qe-si";
++                              reg = <0x700 0x80>;
++                      };
++
++                      siram1: siram@1000 {
++                              #address-cells = <1>;
++                              #size-cells = <1>;
++                              compatible = "fsl,ls1043-qe-siram",
++                                              "fsl,t1040-qe-siram";
++                              reg = <0x1000 0x800>;
++                      };
++
++                      ucc@2000 {
++                              cell-index = <1>;
++                              reg = <0x2000 0x200>;
++                              interrupts = <32>;
++                              interrupt-parent = <&qeic>;
++                      };
++
++                      ucc@2200 {
++                              cell-index = <3>;
++                              reg = <0x2200 0x200>;
++                              interrupts = <34>;
++                              interrupt-parent = <&qeic>;
++                      };
++
++                      muram@10000 {
++                              #address-cells = <1>;
++                              #size-cells = <1>;
++                              compatible = "fsl,qe-muram", "fsl,cpm-muram";
++                              ranges = <0x0 0x10000 0x6000>;
++
++                              data-only@0 {
++                                      compatible = "fsl,qe-muram-data",
++                                      "fsl,cpm-muram-data";
++                                      reg = <0x0 0x6000>;
++                              };
++                      };
++              };
++
+               lpuart0: serial@2950000 {
+                       compatible = "fsl,ls1021a-lpuart";
+                       reg = <0x0 0x2950000 0x0 0x1000>;
+@@ -579,6 +646,16 @@
+                       status = "disabled";
+               };
++              ftm0: ftm0@29d0000 {
++                      compatible = "fsl,ftm-alarm";
++                      reg = <0x0 0x29d0000 0x0 0x10000>,
++                            <0x0 0x1ee2140 0x0 0x4>;
++                      reg-names = "ftm", "FlexTimer1";
++                      interrupts = <0 86 0x4>;
++                      big-endian;
++                      status = "okay";
++              };
++
+               wdog0: wdog@2ad0000 {
+                       compatible = "fsl,ls1043a-wdt", "fsl,imx21-wdt";
+                       reg = <0x0 0x2ad0000 0x0 0x10000>;
+@@ -611,7 +688,10 @@
+                       dr_mode = "host";
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,dis_rxdet_inp3_quirk;
++                      usb3-lpm-capable;
++                      snps,dis-u1u2-when-u3-quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      configure-gfladj;
+               };
+               usb1: usb3@3000000 {
+@@ -621,7 +701,10 @@
+                       dr_mode = "host";
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,dis_rxdet_inp3_quirk;
++                      usb3-lpm-capable;
++                      snps,dis-u1u2-when-u3-quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      configure-gfladj;
+               };
+               usb2: usb3@3100000 {
+@@ -631,7 +714,10 @@
+                       dr_mode = "host";
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,dis_rxdet_inp3_quirk;
++                      usb3-lpm-capable;
++                      snps,dis-u1u2-when-u3-quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      configure-gfladj;
+               };
+               sata: sata@3200000 {
+@@ -670,9 +756,9 @@
+                       reg = <0x00 0x03400000 0x0 0x00100000   /* controller registers */
+                              0x40 0x00000000 0x0 0x00002000>; /* configuration space */
+                       reg-names = "regs", "config";
+-                      interrupts = <0 118 0x4>, /* controller interrupt */
+-                                   <0 117 0x4>; /* PME interrupt */
+-                      interrupt-names = "intr", "pme";
++                      interrupts = <0 117 0x4>, /* PME interrupt */
++                                   <0 118 0x4>; /* aer interrupt */
++                      interrupt-names = "pme", "aer";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+@@ -696,9 +782,9 @@
+                       reg = <0x00 0x03500000 0x0 0x00100000   /* controller registers */
+                              0x48 0x00000000 0x0 0x00002000>; /* configuration space */
+                       reg-names = "regs", "config";
+-                      interrupts = <0 128 0x4>,
+-                                   <0 127 0x4>;
+-                      interrupt-names = "intr", "pme";
++                      interrupts = <0 127 0x4>,
++                                   <0 128 0x4>;
++                      interrupt-names = "pme", "aer";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+@@ -722,9 +808,9 @@
+                       reg = <0x00 0x03600000 0x0 0x00100000   /* controller registers */
+                              0x50 0x00000000 0x0 0x00002000>; /* configuration space */
+                       reg-names = "regs", "config";
+-                      interrupts = <0 162 0x4>,
+-                                   <0 161 0x4>;
+-                      interrupt-names = "intr", "pme";
++                      interrupts = <0 161 0x4>,
++                                   <0 162 0x4>;
++                      interrupt-names = "pme", "aer";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0008-arm64-dts-ls1046a-accumulated-change-to-ls1046a-boar.patch b/target/linux/layerscape/patches-5.4/302-dts-0008-arm64-dts-ls1046a-accumulated-change-to-ls1046a-boar.patch
new file mode 100644 (file)
index 0000000..ae46d59
--- /dev/null
@@ -0,0 +1,375 @@
+From 229d32330c7d941b8e04501ad75bc527f6cf1b1c Mon Sep 17 00:00:00 2001
+From: Li Yang <leoyang.li@nxp.com>
+Date: Thu, 2 May 2019 16:06:42 -0500
+Subject: [PATCH] arm64: dts: ls1046a: accumulated change to ls1046a boards
+
+commit 118e2f48ee8da3f5547c24888bd6fdb78f03b7ce
+Author: Peng Ma <peng.ma@nxp.com>
+Date:   Wed Jul 25 08:53:07 2018 +0000
+
+    dts: fsl-ls1021a, fsl-ls1043a, fsl-ls1046a: add multi block node
+support
+
+    add block-offset to support different virtual block offset for qdma
+    base on soc;
+    the interrupt named "qdma-queueN(N:0,1,2,3)" correspond to a virtual
+    block,N based on block number of qdma;
+
+    Signed-off-by: Peng Ma <peng.ma@nxp.com>
+
+commit 46123df3a174f0d76c8b954a0386e64841453836
+Author: Florinel Iordache <florinel.iordache@nxp.com>
+Date:   Thu Aug 9 12:29:18 2018 +0300
+
+    arm64: dts: updates for Unified Backplane driver
+
+    Signed-off-by: Florinel Iordache <florinel.iordache@nxp.com>
+
+commit c08136017e8b18eb58b153129487c5dc760afd20
+Author: Florinel Iordache <florinel.iordache@nxp.com>
+Date:   Thu Aug 9 12:23:42 2018 +0300
+
+    arm64: dts: ls1046: add support for 10GBase-KR
+
+    Signed-off-by: Florinel Iordache <florinel.iordache@nxp.com>
+
+commit 8473f478783f6f601e1c6d7e6afba49a13f3a6a3
+Author: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date:   Mon Apr 2 16:24:33 2018 +0800
+
+    arm64: dts: ls1046a: add dts entry for A-010650
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit 3159fe9263fb145601ccb07fcb9336a68fba4e08
+Author: Bao Xiaowei <xiaowei.bao@nxp.com>
+Date:   Fri Oct 13 11:04:39 2017 +0800
+
+    arm64: dts: ls1046a: add the property of IB and OB
+
+    Add the property of inbound and outbound windows number for ep
+    driver.
+
+    Signed-off-by: Bao Xiaowei <xiaowei.bao@nxp.com>
+
+    Acked-by: Minghuan Lian <minghuan.Lian@nxp.com>
+    Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+
+commit c8fed58f3c9a0219fda0467791f61abd86eb97f3
+Author: Abhimanyu Saini <abhimanyu.saini@nxp.com>
+Date:   Wed Jan 24 22:56:48 2018 +0530
+
+    arm64: dts: freescale: ls1046a: Modify DT nodes for qspi
+
+    Signed-off-by: Abhimanyu Saini <abhimanyu.saini@nxp.com>
+
+commit 96558859ea3a4af44c0b25441f7574ae6222509a
+Author: Ran Wang <ran.wang_1@nxp.com>
+Date:   Fri Jan 5 15:17:23 2018 +0800
+
+    arm64: dts: ls1046a: Enable usb3-lpm-capable for usb3 node
+
+    Enable USB3 HW LPM feature for ls1046a and active patch for
+    snps erratum A-010131. It will disable U1/U2 temperary when
+    initiate U3 request.
+
+    Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+
+commit 9b17a5fcf8da5656ff99ebef3d63ba040e9f676d
+Author: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date:   Tue Jun 13 13:14:26 2017 +0800
+
+    arm64: dts: correct the register range of dcfg
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit 67c82e3c7b376139d7cee624589bedbc311f8868
+Author: jiaheng.fan <jiaheng.fan@nxp.com>
+Date:   Thu May 11 17:36:33 2017 +0800
+
+    arm64: dts: ls1021/ls1043/ls1046: add qdma nodes
+
+    Signed-off-by: jiaheng.fan <jiaheng.fan@nxp.com>
+
+commit 4a6cef0c83748ee4f6641489fc324bd64095485d
+Author: Chenhui Zhao <chenhui.zhao@nxp.com>
+Date:   Fri May 5 17:53:27 2017 +0800
+
+    arm64: dts: ls1046a: add ftm0 node
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts | 148 ++++++++++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts |   1 +
+ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi    |  28 +++-
+ 3 files changed, 174 insertions(+), 3 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts
+@@ -25,6 +25,20 @@
+               serial1 = &duart1;
+               serial2 = &duart2;
+               serial3 = &duart3;
++
++              emi1_slot1 = &ls1046mdio_s1;
++              emi1_slot2 = &ls1046mdio_s2;
++              emi1_slot4 = &ls1046mdio_s4;
++
++              sgmii_s1_p1 = &sgmii_phy_s1_p1;
++              sgmii_s1_p2 = &sgmii_phy_s1_p2;
++              sgmii_s1_p3 = &sgmii_phy_s1_p3;
++              sgmii_s1_p4 = &sgmii_phy_s1_p4;
++              sgmii_s4_p1 = &sgmii_phy_s4_p1;
++              qsgmii_s2_p1 = &qsgmii_phy_s2_p1;
++              qsgmii_s2_p2 = &qsgmii_phy_s2_p2;
++              qsgmii_s2_p3 = &qsgmii_phy_s2_p3;
++              qsgmii_s2_p4 = &qsgmii_phy_s2_p4;
+       };
+       chosen {
+@@ -177,3 +191,137 @@
+ };
+ #include "fsl-ls1046-post.dtsi"
++
++&fman0 {
++      ethernet@e0000 {
++              phy-handle = <&qsgmii_phy_s2_p1>;
++              phy-connection-type = "sgmii";
++      };
++
++      ethernet@e2000 {
++              phy-handle = <&sgmii_phy_s4_p1>;
++              phy-connection-type = "sgmii";
++      };
++
++      ethernet@e4000 {
++              phy-handle = <&rgmii_phy1>;
++              phy-connection-type = "rgmii";
++      };
++
++      ethernet@e6000 {
++              phy-handle = <&rgmii_phy2>;
++              phy-connection-type = "rgmii";
++      };
++
++      ethernet@e8000 {
++              phy-handle = <&sgmii_phy_s1_p3>;
++              phy-connection-type = "sgmii";
++      };
++
++      ethernet@ea000 {
++              phy-handle = <&sgmii_phy_s1_p4>;
++              phy-connection-type = "sgmii";
++      };
++
++      ethernet@f0000 { /* DTSEC9/10GEC1 */
++              phy-handle = <&sgmii_phy_s1_p1>;
++              phy-connection-type = "xgmii";
++      };
++
++      ethernet@f2000 { /* DTSEC10/10GEC2 */
++              phy-handle = <&sgmii_phy_s1_p2>;
++              phy-connection-type = "xgmii";
++      };
++};
++
++&fpga {
++      #address-cells = <1>;
++      #size-cells = <1>;
++      mdio-mux-emi1 {
++              compatible = "mdio-mux-mmioreg", "mdio-mux";
++              mdio-parent-bus = <&mdio0>;
++              #address-cells = <1>;
++              #size-cells = <0>;
++              reg = <0x54 1>;    /* BRDCFG4 */
++              mux-mask = <0xe0>; /* EMI1 */
++
++              /* On-board RGMII1 PHY */
++              ls1046mdio0: mdio@0 {
++                      reg = <0>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++
++                      rgmii_phy1: ethernet-phy@1 { /* MAC3 */
++                              reg = <0x1>;
++                      };
++              };
++
++              /* On-board RGMII2 PHY */
++              ls1046mdio1: mdio@1 {
++                      reg = <0x20>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++
++                      rgmii_phy2: ethernet-phy@2 { /* MAC4 */
++                              reg = <0x2>;
++                      };
++              };
++
++              /* Slot 1 */
++              ls1046mdio_s1: mdio@2 {
++                      reg = <0x40>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      status = "disabled";
++
++                      sgmii_phy_s1_p1: ethernet-phy@1c {
++                              reg = <0x1c>;
++                      };
++
++                      sgmii_phy_s1_p2: ethernet-phy@1d {
++                              reg = <0x1d>;
++                      };
++
++                      sgmii_phy_s1_p3: ethernet-phy@1e {
++                              reg = <0x1e>;
++                      };
++
++                      sgmii_phy_s1_p4: ethernet-phy@1f {
++                              reg = <0x1f>;
++                      };
++              };
++
++              /* Slot 2 */
++              ls1046mdio_s2: mdio@3 {
++                      reg = <0x60>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      status = "disabled";
++
++                      qsgmii_phy_s2_p1: ethernet-phy@8 {
++                              reg = <0x8>;
++                      };
++                      qsgmii_phy_s2_p2: ethernet-phy@9 {
++                              reg = <0x9>;
++                      };
++                      qsgmii_phy_s2_p3: ethernet-phy@a {
++                              reg = <0xa>;
++                      };
++                      qsgmii_phy_s2_p4: ethernet-phy@b {
++                              reg = <0xb>;
++                      };
++              };
++
++              /* Slot 4 */
++              ls1046mdio_s4: mdio@5 {
++                      reg = <0x80>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      status = "disabled";
++
++                      sgmii_phy_s4_p1: ethernet-phy@1c {
++                              reg = <0x1c>;
++                      };
++              };
++      };
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts
+@@ -100,6 +100,7 @@
+ &qspi {
+       status = "okay";
++      fsl,qspi-has-second-chip;
+       qflash0: flash@0 {
+               compatible = "spansion,m25p80";
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+@@ -304,7 +304,7 @@
+               dcfg: dcfg@1ee0000 {
+                       compatible = "fsl,ls1046a-dcfg", "syscon";
+-                      reg = <0x0 0x1ee0000 0x0 0x10000>;
++                      reg = <0x0 0x1ee0000 0x0 0x1000>;
+                       big-endian;
+               };
+@@ -376,7 +376,7 @@
+               };
+               i2c0: i2c@2180000 {
+-                      compatible = "fsl,vf610-i2c";
++                      compatible = "fsl,vf610-i2c", "fsl,ls1046a-vf610-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0 0x2180000 0x0 0x10000>;
+@@ -385,6 +385,7 @@
+                       dmas = <&edma0 1 39>,
+                              <&edma0 1 38>;
+                       dma-names = "tx", "rx";
++                      scl-gpios = <&gpio3 12 0>;
+                       status = "disabled";
+               };
+@@ -409,12 +410,13 @@
+               };
+               i2c3: i2c@21b0000 {
+-                      compatible = "fsl,vf610-i2c";
++                      compatible = "fsl,vf610-i2c", "fsl,ls1046a-vf610-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0 0x21b0000 0x0 0x10000>;
+                       interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 1>;
++                      scl-gpios = <&gpio3 12 0>;
+                       status = "disabled";
+               };
+@@ -544,6 +546,15 @@
+                       status = "disabled";
+               };
++              ftm0: ftm0@29d0000 {
++                      compatible = "fsl,ftm-alarm";
++                      reg = <0x0 0x29d0000 0x0 0x10000>,
++                            <0x0 0x1ee2140 0x0 0x4>;
++                      reg-names = "ftm", "FlexTimer1";
++                      interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
++                      big-endian;
++              };
++
+               wdog0: watchdog@2ad0000 {
+                       compatible = "fsl,imx21-wdt";
+                       reg = <0x0 0x2ad0000 0x0 0x10000>;
+@@ -576,6 +587,8 @@
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      usb3-lpm-capable;
++                      snps,dis-u1u2-when-u3-quirk;
+               };
+               usb1: usb@3000000 {
+@@ -586,6 +599,8 @@
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      usb3-lpm-capable;
++                      snps,dis-u1u2-when-u3-quirk;
+               };
+               usb2: usb@3100000 {
+@@ -596,6 +611,8 @@
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      usb3-lpm-capable;
++                      snps,dis-u1u2-when-u3-quirk;
+               };
+               sata: sata@3200000 {
+@@ -637,6 +654,11 @@
+                                    <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
+               };
++              serdes1: serdes@1ea0000 {
++                      reg = <0x0 0x1ea0000 0 0x00002000>;
++                      compatible = "fsl,serdes-10g";
++              };
++
+               pcie@3400000 {
+                       compatible = "fsl,ls1046a-pcie";
+                       reg = <0x00 0x03400000 0x0 0x00100000   /* controller registers */
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0009-arm64-dts-ls1088a-accumulated-change-to-ls1088a-boar.patch b/target/linux/layerscape/patches-5.4/302-dts-0009-arm64-dts-ls1088a-accumulated-change-to-ls1088a-boar.patch
new file mode 100644 (file)
index 0000000..48fbfa7
--- /dev/null
@@ -0,0 +1,540 @@
+From 2790ba4aa3e487ac29d6027eb226ed986f0e2769 Mon Sep 17 00:00:00 2001
+From: Li Yang <leoyang.li@nxp.com>
+Date: Thu, 2 May 2019 16:10:03 -0500
+Subject: [PATCH] arm64: dts: ls1088a: accumulated change to ls1088a boards
+
+commit f967940f2fb73bc7ec676dbad9f32fbf4e7fea2b
+Author: Pengbo Mu <pengbo.mu@nxp.com>
+Date:   Fri Jul 13 16:19:36 2018 +0800
+
+    arm64: dts: ls1088a: add snps incr burst type adjustment in usb0 &
+usb1
+
+    This property could fix the defect that external usb device always
+    prints this error log --- 'reset SuperSpeed USB device number n
+using
+    xhci_hcd' when system power on.
+
+    Signed-off-by: Pengbo Mu <pengbo.mu@nxp.com>
+
+commit 46123df3a174f0d76c8b954a0386e64841453836
+Author: Florinel Iordache <florinel.iordache@nxp.com>
+Date:   Thu Aug 9 12:29:18 2018 +0300
+
+    arm64: dts: updates for Unified Backplane driver
+
+    Signed-off-by: Florinel Iordache <florinel.iordache@nxp.com>
+
+commit 3b214bd42d47ebe7b6af925a3ffcf09aaaaabfb9
+Author: Nipun Gupta <nipun.gupta@nxp.com>
+Date:   Sat Apr 28 00:20:48 2018 +0530
+
+    arm64: dts: ls1088: add dma-cohernet property in fsl-mc node
+
+    Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
+
+commit 240b04a98171f6774d1c3c498f8cb21f4411ac5f
+Author: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date:   Thu Apr 26 12:26:54 2018 +0300
+
+    arm64: dts: ls1088a: move fsl-mc node as a child of soc
+
+    Move the fsl-mc hardware manager node in the soc node because all
+the
+    soc settings (such as 'dma-ranges') also apply to the fsl-mc and
+need
+    to be propagated to it.
+
+    Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+
+commit 3f2f50950f763d1335181ce374a11ed118abf0fa
+Author: Nipun Gupta <nipun.gupta@nxp.com>
+Date:   Wed Apr 25 09:43:47 2018 +0530
+
+    arm64: dts: ls1088: add dma ranges property
+
+    Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
+
+commit 6afd0157e8fa2510790537855c86f8a7c1431abe
+Author: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date:   Mon Apr 2 16:25:38 2018 +0800
+
+    arm64: dts: ls1088a: add dts entry for A-010650
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit 0f8432c30c44771f9180aa7bf7580ad1d7e7c9d3
+Author: Nipun Gupta <nipun.gupta@nxp.com>
+Date:   Mon Feb 26 10:40:37 2018 +0530
+
+    arm64: dts: ls1088a: add dma coherent property in smmu node
+
+    Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
+
+commit 6417c66b823ab380cf73ee252a998d98b28f0180
+Author: Suresh Gupta <suresh.gupta@nxp.com>
+Date:   Fri Feb 2 00:04:41 2018 +0530
+
+    arm64: dts: freescale: ls1088a: Modify DT nodes for qspi
+
+    Signed-off-by: Suresh Gupta <suresh.gupta@nxp.com>
+    Signed-off-by: Yogesh Gaur <yogeshnarayan.gaur@nxp.com>
+
+commit 01a1ea9e781d307ab87da95043ec898736495fff
+Author: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date:   Thu Nov 2 10:36:48 2017 +0800
+
+    arm64: dts: ls1088a: correct the i2c clock to 1/8 platform pll
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit 60122f1192e1cc23e5952468cc5a884287d64907
+Author: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Date:   Thu Sep 7 10:08:31 2017 +0530
+
+    arm64: dts: ls1088a: Add iommu-map property for pci
+
+    This patch adds iommu-map property for PCIe, which enables
+    SMMU for these devices on LS1088.
+
+    Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+
+commit 43c4d0cf074106b411280c5b2be75d5d6e63fb01
+Author: Iordache Florinel-R70177 <florinel.iordache@nxp.com>
+Date:   Mon Aug 21 11:43:07 2017 +0300
+
+    arm64: dts: ls1088a: add backplane support
+
+    Signed-off-by: Iordache Florinel-R70177 <florinel.iordache@nxp.com>
+
+commit 57d49424694f72adbf7cf1dbeff38704f0d65359
+Author: Ashish Kumar <Ashish.Kumar@nxp.com>
+Date:   Mon Jun 19 18:32:13 2017 +0530
+
+    arm64: dts: ls1088: Add Reboot node in dtsi
+
+    Signed-off-by: Ashish Kumar <Ashish.Kumar@nxp.com>
+
+commit ee950989a7babc240153a20fe468573e13d61f98
+Author: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date:   Thu May 11 14:59:28 2017 +0800
+
+    arm64: dts: ls1088a: add ftm0 nodes
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit 6d3a96446a7ffccb0b9936b616d855c8d5572bce
+Author: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+Date:   Wed May 3 14:26:35 2017 +0000
+
+    arm64: dts: fsl/ls1088,ls208x: Add mdio and phy nodes
+
+    Add mdio and phy nodes for the following FSL platforms:
+    - LS1088A RDB
+    - LS2080A QDS & RDB
+    - LS2088A QDS, RDB & simu
+
+    Contains contributions from patches by the following authors:
+    Signed-off-by: Shaohui Xie <Shaohui.Xie@nxp.com>
+    Signed-off-by: Rai Harninder <harninder.rai@nxp.com>
+    Signed-off-by: Pratiyush Mohan Srivastava
+<pratiyush.srivastava@nxp.com>
+    Signed-off-by: Raghav Dogra <raghav.dogra@nxp.com>
+    Signed-off-by: Santan Kumar <santan.kumar@nxp.com>
+    Signed-off-by: Priyanka Jain <priyanka.jain@nxp.com>
+    Signed-off-by: Ashish Kumar <ashish.kumar@nxp.com>
+    Signed-off-by: Abhimanyu Saini <abhimanyu.saini@nxp.com>
+    Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+    Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+
+commit 971ff2e74cfebb84286ec3e191f5910dded4bd41
+Author: Suresh Gupta <suresh.gupta@nxp.com>
+Date:   Thu May 4 18:04:44 2017 +0530
+
+    arm64: dts: ls1088a: Add QSPI node for QDS, RDB
+
+    This is temporary patch, will rewrite for open source
+
+    Signed-off-by: Prabhakar Kushwaha <prabhakar.kushwaha@nxp.com>
+    Signed-off-by: Suresh Gupta <suresh.gupta@nxp.com>
+
+commit c61036e6dfe264d61cc213293040d873d863e8ac
+Author: Nipun Gupta <nipun.gupta@nxp.com>
+Date:   Thu Apr 27 23:35:15 2017 +0530
+
+    arm64: dts: add iommu-map property in fsl-mc node
+
+    Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
+
+commit a4412cc510162a900d10c8ca4add71defb3f2d97
+Author: Nipun Gupta <nipun.gupta@nxp.com>
+Date:   Wed Apr 19 22:26:15 2017 +0530
+
+    arm64: dts: add smmu device node in LS1088 devicetree
+
+    Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts |  50 ++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts | 104 +++++++++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi    | 108 +++++++++++++++++++++-
+ 3 files changed, 261 insertions(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts
+@@ -131,6 +131,30 @@
+       };
+ };
++&qspi {
++      status = "okay";
++      fsl,qspi-has-second-chip;
++      qflash0: s25fs512s@0 {
++              compatible = "spansion,m25p80";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              spi-max-frequency = <20000000>;
++              reg = <0>;
++              spi-rx-bus-width = <4>;
++              spi-tx-bus-width = <4>;
++      };
++
++      qflash1: s25fs512s@1 {
++              compatible = "spansion,m25p80";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              spi-max-frequency = <20000000>;
++              reg = <1>;
++              spi-rx-bus-width = <4>;
++              spi-tx-bus-width = <4>;
++      };
++};
++
+ &duart0 {
+       status = "okay";
+ };
+@@ -146,3 +170,29 @@
+ &sata {
+       status = "okay";
+ };
++
++&pcs_mdio1 {
++              pcs_phy1: ethernet-phy@0 {
++              backplane-mode = "10gbase-kr";
++              compatible = "ethernet-phy-ieee802.3-c45";
++              reg = <0x0>;
++              fsl,lane-handle = <&serdes1>;
++              fsl,lane-reg = <0x840 0x40>;/* lane B */
++      };
++};
++
++&pcs_mdio2 {
++              pcs_phy2: ethernet-phy@0 {
++              backplane-mode = "10gbase-kr";
++              compatible = "ethernet-phy-ieee802.3-c45";
++              reg = <0x0>;
++              fsl,lane-handle = <&serdes1>;
++              fsl,lane-reg = <0x800 0x40>;/* lane A */
++      };
++};
++
++/* Update DPMAC connections to backplane PHYs, under SerDes 0x1D_0xXX.
++ * &dpmac1 {
++ *    phy-handle = <&pcs_phy1>;
++ * };
++ */
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts
+@@ -74,6 +74,31 @@
+       };
+ };
++&qspi {
++      status = "okay";
++      fsl,qspi-has-second-chip;
++      qflash0: s25fs512s@0 {
++              compatible = "spansion,m25p80";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              spi-max-frequency = <20000000>;
++              reg = <0>;
++              spi-rx-bus-width = <4>;
++              spi-tx-bus-width = <4>;
++      };
++
++      qflash1: s25fs512s@1 {
++              compatible = "spansion,m25p80";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              spi-max-frequency = <20000000>;
++              reg = <1>;
++              spi-rx-bus-width = <4>;
++              spi-tx-bus-width = <4>;
++      };
++
++};
++
+ &duart0 {
+       status = "okay";
+ };
+@@ -97,3 +122,82 @@
+ &usb1 {
+       status = "okay";
+ };
++
++&emdio1 {
++      /* Freescale F104 PHY1 */
++      mdio1_phy1: emdio1_phy@1 {
++              reg = <0x1c>;
++              phy-connection-type = "qsgmii";
++      };
++      mdio1_phy2: emdio1_phy@2 {
++              reg = <0x1d>;
++              phy-connection-type = "qsgmii";
++      };
++      mdio1_phy3: emdio1_phy@3 {
++              reg = <0x1e>;
++              phy-connection-type = "qsgmii";
++      };
++      mdio1_phy4: emdio1_phy@4 {
++              reg = <0x1f>;
++              phy-connection-type = "qsgmii";
++      };
++      /* F104 PHY2 */
++      mdio1_phy5: emdio1_phy@5 {
++              reg = <0x0c>;
++              phy-connection-type = "qsgmii";
++      };
++      mdio1_phy6: emdio1_phy@6 {
++              reg = <0x0d>;
++              phy-connection-type = "qsgmii";
++      };
++      mdio1_phy7: emdio1_phy@7 {
++              reg = <0x0e>;
++              phy-connection-type = "qsgmii";
++      };
++      mdio1_phy8: emdio1_phy@8 {
++              reg = <0x0f>;
++              phy-connection-type = "qsgmii";
++      };
++};
++
++&emdio2 {
++      /* Aquantia AQR105 10G PHY */
++      mdio2_phy1: emdio2_phy@1 {
++              compatible = "ethernet-phy-ieee802.3-c45";
++              interrupts = <0 2 0x4>;
++              reg = <0x0>;
++              phy-connection-type = "xfi";
++      };
++};
++
++/* DPMAC connections to external PHYs
++ * based on LS1088A RM RevC - $24.1.2 SerDes Options
++ */
++/* DPMAC1 is 10G SFP+, fixed link */
++&dpmac2 {
++      phy-handle = <&mdio2_phy1>;
++};
++&dpmac3 {
++      phy-handle = <&mdio1_phy5>;
++};
++&dpmac4 {
++      phy-handle = <&mdio1_phy6>;
++};
++&dpmac5 {
++      phy-handle = <&mdio1_phy7>;
++};
++&dpmac6 {
++      phy-handle = <&mdio1_phy8>;
++};
++&dpmac7 {
++      phy-handle = <&mdio1_phy1>;
++};
++&dpmac8 {
++      phy-handle = <&mdio1_phy2>;
++};
++&dpmac9 {
++      phy-handle = <&mdio1_phy3>;
++};
++&dpmac10 {
++      phy-handle = <&mdio1_phy4>;
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+@@ -185,6 +185,19 @@
+               clock-output-names = "sysclk";
+       };
++      rstcr: syscon@1e60000 {
++              compatible = "fsl,ls1088a-rstcr", "syscon";
++              reg = <0x0 0x1e60000 0x0 0x4>;
++      };
++
++      reboot {
++              compatible = "syscon-reboot";
++              regmap = <&rstcr>;
++              offset = <0x0>;
++              mask = <0x02>;
++      };
++
++
+       soc {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+@@ -205,6 +218,11 @@
+                       little-endian;
+               };
++              serdes1: serdes@1ea0000 {
++                              reg = <0x0 0x1ea0000 0 0x00002000>;
++                              compatible = "fsl,serdes-10g";
++              };
++
+               tmu: tmu@1f80000 {
+                       compatible = "fsl,qoriq-tmu";
+                       reg = <0x0 0x1f80000 0x0 0x10000>;
+@@ -325,6 +343,72 @@
+                       #interrupt-cells = <2>;
+               };
++              /* TODO: WRIOP (CCSR?) */
++              emdio1: mdio@0x8B96000 { /* WRIOP0: 0x8B8_0000,
++                                        * E-MDIO1: 0x1_6000
++                                        */
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8B96000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;  /* force the driver in LE mode */
++
++                      /* Not necessary on the QDS, but needed on the RDB */
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              emdio2: mdio@0x8B97000 { /* WRIOP0: 0x8B8_0000,
++                                        * E-MDIO2: 0x1_7000
++                                        */
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8B97000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;  /* force the driver in LE mode */
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio1: mdio@0x8c07000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c07000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio2: mdio@0x8c0b000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c0b000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio3: mdio@0x8c0f000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c0f000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio4: mdio@0x8c13000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c13000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
+               ifc: ifc@2240000 {
+                       compatible = "fsl,ifc", "simple-bus";
+                       reg = <0x0 0x2240000 0x0 0x20000>;
+@@ -335,13 +419,20 @@
+                       status = "disabled";
+               };
++              ftm0: ftm0@2800000 {
++                      compatible = "fsl,ftm-alarm";
++                      reg = <0x0 0x2800000 0x0 0x10000>;
++                      interrupts = <0 44 4>;
++              };
++
+               i2c0: i2c@2000000 {
+-                      compatible = "fsl,vf610-i2c";
++                      compatible = "fsl,vf610-i2c", "fsl,ls1088a-vf610-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0 0x2000000 0x0 0x10000>;
+                       interrupts = <0 34 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 7>;
++                      scl-gpios = <&gpio3 30 0>;
+                       status = "disabled";
+               };
+@@ -405,6 +496,7 @@
+                       dr_mode = "host";
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,dis_rxdet_inp3_quirk;
++                      snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                       status = "disabled";
+               };
+@@ -418,6 +510,17 @@
+                       dma-coherent;
+                       status = "disabled";
+               };
++              qspi: spi@20c0000 {
++                      compatible = "fsl,ls2080a-qspi", "fsl,ls1088a-qspi";
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      reg = <0x0 0x20c0000 0x0 0x10000>,
++                              <0x0 0x20000000 0x0 0x10000000>;
++                      reg-names = "QuadSPI", "QuadSPI-memory";
++                      interrupts = <0 25 0x4>; /* Level high type */
++                      clocks = <&clockgen 4 3>, <&clockgen 4 3>;
++                      clock-names = "qspi_en", "qspi";
++              };
+               crypto: crypto@8000000 {
+                       compatible = "fsl,sec-v5.0", "fsl,sec-v4.0";
+@@ -474,6 +577,7 @@
+                       ranges = <0x81000000 0x0 0x00000000 0x20 0x00010000 0x0 0x00010000   /* downstream I/O */
+                                 0x82000000 0x0 0x40000000 0x20 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+                       msi-parent = <&its>;
++                      iommu-map = <0 &smmu 0 1>;      /* This is fixed-up by u-boot */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic 0 0 0 109 IRQ_TYPE_LEVEL_HIGH>,
+@@ -499,6 +603,7 @@
+                       ranges = <0x81000000 0x0 0x00000000 0x28 0x00010000 0x0 0x00010000   /* downstream I/O */
+                                 0x82000000 0x0 0x40000000 0x28 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+                       msi-parent = <&its>;
++                      iommu-map = <0 &smmu 0 1>;      /* This is fixed-up by u-boot */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic 0 0 0 114 IRQ_TYPE_LEVEL_HIGH>,
+@@ -524,6 +629,7 @@
+                       ranges = <0x81000000 0x0 0x00000000 0x30 0x00010000 0x0 0x00010000   /* downstream I/O */
+                                 0x82000000 0x0 0x40000000 0x30 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+                       msi-parent = <&its>;
++                      iommu-map = <0 &smmu 0 1>;      /* This is fixed-up by u-boot */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic 0 0 0 119 IRQ_TYPE_LEVEL_HIGH>,
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0010-arm64-dts-ls208xa-accumulated-change-to-ls208xa-boar.patch b/target/linux/layerscape/patches-5.4/302-dts-0010-arm64-dts-ls208xa-accumulated-change-to-ls208xa-boar.patch
new file mode 100644 (file)
index 0000000..2b1bd82
--- /dev/null
@@ -0,0 +1,959 @@
+From 9d8de47b617baa4fa92d9a1502904c0373f80384 Mon Sep 17 00:00:00 2001
+From: Li Yang <leoyang.li@nxp.com>
+Date: Thu, 2 May 2019 16:12:40 -0500
+Subject: [PATCH] arm64: dts: ls208xa: accumulated change to ls208xa boards
+
+commit 46123df3a174f0d76c8b954a0386e64841453836
+Author: Florinel Iordache <florinel.iordache@nxp.com>
+Date:   Thu Aug 9 12:29:18 2018 +0300
+
+    arm64: dts: updates for Unified Backplane driver
+
+    Signed-off-by: Florinel Iordache <florinel.iordache@nxp.com>
+
+commit 76a741dbb9b93ea9ab2f6122b8df5bc4f0db7676
+Author: Nipun Gupta <nipun.gupta@nxp.com>
+Date:   Sat Apr 28 00:20:16 2018 +0530
+
+    arm64: dts: ls208x: add dma-cohernet property in fsl-mc node
+
+    Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
+
+commit f6309e9dc8e0c6171a43fd6759123b5de1c574aa
+Author: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date:   Mon Apr 2 16:27:23 2018 +0800
+
+    arm64: dts: ls208xa: add dts entry for A-010650
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit 8c37bad2038a210a4f0a369fd946aaae4317eac4
+Author: Nipun Gupta <nipun.gupta@nxp.com>
+Date:   Fri Apr 20 17:14:10 2018 +0530
+
+    arm64: dts: ls208x: add dma ranges property
+
+    Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
+
+commit 38566bbd5ca6747b30d2f0c251bbcfe0723df8c6
+Author: Changming Huang <jerry.huang@nxp.com>
+Date:   Wed Apr 19 12:49:50 2017 +0800
+
+    arm/arm64: dts: Add property snps incr burst type adjustment for
+INCR burst type for dwc3
+
+    Signed-off-by: yinbo.zhu <yinbo.zhu@nxp.com>
+    Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+
+commit dbb65ea8ee1d46067e756c6d64c7fe66a0058f49
+Author: Pankaj Bansal <pankaj.bansal@nxp.com>
+Date:   Mon Mar 5 12:37:04 2018 +0530
+
+    arm64: dts: ls208x: remove NXP Erratum A008585 from LS2088A.
+
+    NXP Erratum A008585 affects A57 core cluster used in LS2085rev1.
+    However this problem has been fixed in A72 core cluster used in
+LS2088.
+    Therefore remove the erratum from LS2088A. Keeping it only in
+LS2085.
+
+    Cc: <stable@vger.kernel.org> # 4.14
+    Signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com>
+    Reviewed-by: Sandeep Malik <sandeep.malik@nxp.com>
+    Acked-by: Priyanka Jain <priyanka.jain@nxp.com>
+
+commit 85f41b0f6abe6b9d7d303790bb3712ed559890e9
+Author: Nipun Gupta <nipun.gupta@nxp.com>
+Date:   Mon Feb 26 10:39:54 2018 +0530
+
+    arm64: dts: ls208xa: add dma coherent property in smmu node
+
+    Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
+
+commit e910d8b78b823a625451b1da7ae7499dadde2ae9
+Author: Suresh Gupta <suresh.gupta@nxp.com>
+Date:   Thu Feb 1 23:49:56 2018 +0530
+
+    arm64: dts: freescale: ls208xa: Modify DT nodes for qspi
+
+    Signed-off-by: Abhimanyu Saini <abhimanyu.saini@nxp.com>
+
+commit 7654ef78c8c85de3a43dfa0dffd572d589ea1332
+Author: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date:   Wed Nov 1 10:34:04 2017 +0800
+
+    arm64: dts: ls208xa: correct the i2c clock to 1/2 platform pll
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit efdb129228baa6a999c06072338b979d783d7b60
+Author: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Date:   Thu Aug 31 14:45:02 2017 +0530
+
+    arm64: dts: ls208xa: Add iommu-map property for pci
+
+    This patch adds iommu-map property for PCIe, which enables
+    SMMU for these devices on LS208xA devices.
+
+    Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+
+commit 45af5d025eafaf4a85000e16e5f47992de663ff6
+Author: Iordache Florinel-R70177 <florinel.iordache@nxp.com>
+Date:   Mon Aug 21 11:46:59 2017 +0300
+
+    arm64: dts: ls2088a: update backplane support with dpmac connections
+
+    Signed-off-by: Iordache Florinel-R70177 <florinel.iordache@nxp.com>
+
+commit b2ede6c088a883fceb348e8659253b2c7cdeeff8
+Author: Santan Kumar <santan.kumar@nxp.com>
+Date:   Thu Jun 22 13:04:00 2017 +0530
+
+    arm64: dts: ls2088ardb: Update nodes for QSPI
+
+    -As per board design, different QSPI flash is connected on
+      boards, hence change QSPI flash node from s25fl256s1 to s25fs512ss
+in
+      device tree.
+    -Enable fast-read support in QSPI node.
+
+    Signed-off-by: Santan Kumar <santan.kumar@nxp.com>
+
+commit d5324a75c56e9f9210113e51cffa846a86b50fbd
+Author: Santan Kumar <santan.kumar@nxp.com>
+Date:   Mon Jun 19 15:26:03 2017 +0530
+
+    arm64: dts: ls2081ardb: Update nodes for QSPI, SATA, INA220
+
+    Update ls2081ardb.dts for below nodes:
+     -As per updated board design, different QSPI flash is connected on
+      boards, hence change QSPI flash node from n25q512a to s25fs512ss
+in
+      device tree.
+     -Enable dual flash support in QSPI node.
+     -Add DTS node for INA220.
+     -Enable SATA node.
+
+    Signed-off-by: Santan Kumar <santan.kumar@nxp.com>
+    Signed-off-by: Tao Yang <b31903@freescale.com>
+    Signed-off-by: Yogesh Gaur <yogeshnarayan.gaur@nxp.com>
+
+commit 43d506fa19e1e50e4c2e4f9689ad3c60d9a06d71
+Author: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date:   Thu May 11 08:42:19 2017 +0800
+
+    arm64: dts: ls208x: add property for PCA954x Mux device
+
+    PCA954x Mux device should never be turned-off after power-on. if
+    device tree contians "i2c-mux-never-disable" property for pca954x
+    device node, it can ensure that skip disabling PCA954x Mux device.
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit 6d3a96446a7ffccb0b9936b616d855c8d5572bce
+Author: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+Date:   Wed May 3 14:26:35 2017 +0000
+
+    arm64: dts: fsl/ls1088,ls208x: Add mdio and phy nodes
+
+    Add mdio and phy nodes for the following FSL platforms:
+    - LS1088A RDB
+    - LS2080A QDS & RDB
+    - LS2088A QDS, RDB & simu
+
+    Contains contributions from patches by the following authors:
+    Signed-off-by: Shaohui Xie <Shaohui.Xie@nxp.com>
+    Signed-off-by: Rai Harninder <harninder.rai@nxp.com>
+    Signed-off-by: Pratiyush Mohan Srivastava
+<pratiyush.srivastava@nxp.com>
+    Signed-off-by: Raghav Dogra <raghav.dogra@nxp.com>
+    Signed-off-by: Santan Kumar <santan.kumar@nxp.com>
+    Signed-off-by: Priyanka Jain <priyanka.jain@nxp.com>
+    Signed-off-by: Ashish Kumar <ashish.kumar@nxp.com>
+    Signed-off-by: Abhimanyu Saini <abhimanyu.saini@nxp.com>
+    Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+    Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+
+commit 0443625ea24bc4ea315c30b718712254c588bd18
+Author: Suresh Gupta <suresh.gupta@nxp.com>
+Date:   Fri May 5 13:54:22 2017 +0530
+
+    arm64: dts: ls208xa: Add QSPI Flash node for RDB
+
+    This is temporary patch, will rewrite for open source
+
+    Signed-off-by: Suresh Gupta <suresh.gupta@nxp.com>
+
+commit ed0ce1d49aa72d12ea54f82d3771a377c68af37e
+Author: Priyanka Jain <priyanka.jain@nxp.com>
+Date:   Thu Apr 13 16:49:40 2017 +0530
+
+    arm64: dts: ls2081ardb: Add DTS support for NXP LS2081ARDB
+
+    This patch add support for NXP LS2081ARDB board which has
+    LS2081A SoC.
+
+    LS2081A SoC is 40-pin derivative of LS2088A SoC
+    So, from functional perspective both are same.
+    Hence,ls2088a SoC dtsi files are included from ls2081ARDB dts
+
+    Signed-off-by: Priyanka Jain <priyanka.jain@nxp.com>
+
+commit e4fb842554a5e7b8c3f6e3c243222dbe4515aee3
+Author: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date:   Thu Apr 27 15:01:54 2017 +0800
+
+    arm64: dts: ls208xa: add ftm0 nodes
+
+    Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+
+commit 64c3e2c3a7ddc89c3c23c012ee364f2c014524d2
+Author: costi <constantin.tudor@freescale.com>
+Date:   Fri Mar 3 18:08:28 2017 +0200
+
+    arm64: dts: fsl-ls2088: Add mdio/phy devices
+
+    Signed-off-by: Constantin Tudor <constantin.tudor@nxp.com>
+
+commit 3bcdc4de0a1c9e6f4a4ddc916e8efe8044d8bbfd
+Author: Po Liu <po.liu@nxp.com>
+Date:   Fri Sep 30 17:11:36 2016 +0800
+
+    arm64: dts: ls1043/ls2080: add pcie aer/pme interrupt-name property
+
+    Some platforms(NXP Layerscape for example) aer/pme interrupts was
+not
+    MSI/MSI-X/INTx but using interrupt line independently. This patch
+    add "aer", "pme" interrupt-names for aer/pme interrupt.
+
+    With the interrupt-names "aer", "pme" code could probe aer/pme
+interrupt
+    line for pcie root port, replace the aer/pme interrupt service irqs.
+
+    This is intend to fixup the Layerscape platforms which aer/pmes
+interrupts
+    was not MSI/MSI-X/INTx, but using interrupt line independently.
+
+    Since the interrupt-names "intr" never been used. Remove it.
+
+    Signed-off-by: Po Liu <po.liu@nxp.com>
+    Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+
+commit 64d859836d3d194e8bc926bb951fd21859689824
+Author: Nipun Gupta <nipun.gupta@nxp.com>
+Date:   Mon Dec 5 05:20:51 2016 +0530
+
+    arm64: dts: ls208xa: Comply with the new iommu binding for fsl_mc
+
+    fsl-mc bus support the new iommu-map property. Comply to this
+binding
+    for fsl_mc bus.
+
+    Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts  |  62 +++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts  |  80 +++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi     |  12 ++
+ arch/arm64/boot/dts/freescale/fsl-ls2088a-qds.dts  | 120 ++++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls2088a-rdb.dts  |  80 +++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi |   1 +
+ arch/arm64/boot/dts/freescale/fsl-ls208xa-rdb.dtsi |  11 +-
+ arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi     | 155 +++++++++++++++++++--
+ 8 files changed, 505 insertions(+), 16 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts
+@@ -23,3 +23,65 @@
+               stdout-path = "serial0:115200n8";
+       };
+ };
++
++&ifc {
++      boardctrl: board-control@3,0 {
++              #address-cells = <1>;
++              #size-cells = <1>;
++              compatible = "fsl,tetra-fpga", "fsl,fpga-qixis", "simple-bus";
++              reg = <3 0 0x300>;              /* TODO check address */
++              ranges = <0 3 0 0x300>;
++
++              mdio_mux_emi1 {
++                      compatible = "mdio-mux-mmioreg", "mdio-mux";
++                      mdio-parent-bus = <&emdio1>;
++                      reg = <0x54 1>;         /* BRDCFG4 */
++                      mux-mask = <0xe0>;      /* EMI1_MDIO */
++
++                      #address-cells=<1>;
++                      #size-cells = <0>;
++
++                      /* Child MDIO buses, one for each riser card:
++                       * reg = 0x0, 0x20, 0x40, 0x60, 0x80, 0xa0.
++                       * VSC8234 PHYs on the riser cards.
++                       */
++
++                      mdio_mux3: mdio@60 {
++                              reg = <0x60>;
++                              #address-cells = <1>;
++                              #size-cells = <0>;
++
++                              mdio0_phy12: mdio_phy0@1c {
++                                      reg = <0x1c>;
++                                      phy-connection-type = "sgmii";
++                              };
++                              mdio0_phy13: mdio_phy1@1d {
++                                      reg = <0x1d>;
++                                      phy-connection-type = "sgmii";
++                              };
++                              mdio0_phy14: mdio_phy2@1e {
++                                      reg = <0x1e>;
++                                      phy-connection-type = "sgmii";
++                              };
++                              mdio0_phy15: mdio_phy3@1f {
++                                      reg = <0x1f>;
++                                      phy-connection-type = "sgmii";
++                              };
++                      };
++              };
++      };
++};
++
++/* Update DPMAC connections to external PHYs, under SerDes 0x2a_0x49. */
++&dpmac9 {
++      phy-handle = <&mdio0_phy12>;
++};
++&dpmac10 {
++      phy-handle = <&mdio0_phy13>;
++};
++&dpmac11 {
++      phy-handle = <&mdio0_phy14>;
++};
++&dpmac12 {
++      phy-handle = <&mdio0_phy15>;
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts
+@@ -23,3 +23,83 @@
+               stdout-path = "serial1:115200n8";
+       };
+ };
++
++&emdio1 {
++      status = "disabled";
++      /* CS4340 PHYs */
++      mdio1_phy1: emdio1_phy@1 {
++              reg = <0x10>;
++              phy-connection-type = "xfi";
++      };
++      mdio1_phy2: emdio1_phy@2 {
++              reg = <0x11>;
++              phy-connection-type = "xfi";
++      };
++      mdio1_phy3: emdio1_phy@3 {
++              reg = <0x12>;
++              phy-connection-type = "xfi";
++      };
++      mdio1_phy4: emdio1_phy@4 {
++              reg = <0x13>;
++              phy-connection-type = "xfi";
++      };
++};
++
++&emdio2 {
++      /* AQR405 PHYs */
++      mdio2_phy1: emdio2_phy@1 {
++              compatible = "ethernet-phy-ieee802.3-c45";
++              interrupts = <0 1 0x4>; /* Level high type */
++              reg = <0x0>;
++              phy-connection-type = "xfi";
++      };
++      mdio2_phy2: emdio2_phy@2 {
++              compatible = "ethernet-phy-ieee802.3-c45";
++              interrupts = <0 2 0x4>; /* Level high type */
++              reg = <0x1>;
++              phy-connection-type = "xfi";
++      };
++      mdio2_phy3: emdio2_phy@3 {
++              compatible = "ethernet-phy-ieee802.3-c45";
++              interrupts = <0 4 0x4>; /* Level high type */
++              reg = <0x2>;
++              phy-connection-type = "xfi";
++      };
++      mdio2_phy4: emdio2_phy@4 {
++              compatible = "ethernet-phy-ieee802.3-c45";
++              interrupts = <0 5 0x4>; /* Level high type */
++              reg = <0x3>;
++              phy-connection-type = "xfi";
++      };
++};
++
++/* Update DPMAC connections to external PHYs, under the assumption of
++ * SerDes 0x2a_0x41. This is currently the only SerDes supported on the board.
++ */
++/* Leave Cortina nodes commented out until driver is integrated
++ *&dpmac1 {
++ *    phy-handle = <&mdio1_phy1>;
++ *};
++ *&dpmac2 {
++ *    phy-handle = <&mdio1_phy2>;
++ *};
++ *&dpmac3 {
++ *    phy-handle = <&mdio1_phy3>;
++ *};
++ *&dpmac4 {
++ *    phy-handle = <&mdio1_phy4>;
++ *};
++ */
++
++&dpmac5 {
++      phy-handle = <&mdio2_phy1>;
++};
++&dpmac6 {
++      phy-handle = <&mdio2_phy2>;
++};
++&dpmac7 {
++      phy-handle = <&mdio2_phy3>;
++};
++&dpmac8 {
++      phy-handle = <&mdio2_phy4>;
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
+@@ -118,6 +118,18 @@
+       };
+ };
++&timer {
++      fsl,erratum-a008585;
++};
++
++&usb0 {
++      snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++};
++
++&usb1 {
++      snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++};
++
+ &pcie1 {
+       reg = <0x00 0x03400000 0x0 0x00100000   /* controller registers */
+              0x10 0x00000000 0x0 0x00002000>; /* configuration space */
+--- a/arch/arm64/boot/dts/freescale/fsl-ls2088a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls2088a-qds.dts
+@@ -22,3 +22,123 @@
+               stdout-path = "serial0:115200n8";
+       };
+ };
++
++&ifc {
++      boardctrl: board-control@3,0 {
++              #address-cells = <1>;
++              #size-cells = <1>;
++              compatible = "fsl,tetra-fpga", "fsl,fpga-qixis", "simple-bus";
++              reg = <3 0 0x300>;              /* TODO check address */
++              ranges = <0 3 0 0x300>;
++
++              mdio_mux_emi1 {
++                      compatible = "mdio-mux-mmioreg", "mdio-mux";
++                      mdio-parent-bus = <&emdio1>;
++                      reg = <0x54 1>;         /* BRDCFG4 */
++                      mux-mask = <0xe0>;      /* EMI1_MDIO */
++
++                      #address-cells=<1>;
++                      #size-cells = <0>;
++
++                      /* Child MDIO buses, one for each riser card:
++                       * reg = 0x0, 0x20, 0x40, 0x60, 0x80, 0xa0.
++                       * VSC8234 PHYs on the riser cards.
++                       */
++
++                      mdio_mux3: mdio@60 {
++                              reg = <0x60>;
++                              #address-cells = <1>;
++                              #size-cells = <0>;
++
++                              mdio0_phy12: mdio_phy0@1c {
++                                      reg = <0x1c>;
++                                      phy-connection-type = "sgmii";
++                              };
++                              mdio0_phy13: mdio_phy1@1d {
++                                      reg = <0x1d>;
++                                      phy-connection-type = "sgmii";
++                              };
++                              mdio0_phy14: mdio_phy2@1e {
++                                      reg = <0x1e>;
++                                      phy-connection-type = "sgmii";
++                              };
++                              mdio0_phy15: mdio_phy3@1f {
++                                      reg = <0x1f>;
++                                      phy-connection-type = "sgmii";
++                              };
++                      };
++              };
++      };
++};
++
++&pcs_mdio1 {
++              pcs_phy1: ethernet-phy@0 {
++              backplane-mode = "10gbase-kr";
++              compatible = "ethernet-phy-ieee802.3-c45";
++              reg = <0x0>;
++              fsl,lane-handle = <&serdes1>;
++              fsl,lane-reg = <0x9C0 0x40>;/* lane H */
++      };
++};
++
++&pcs_mdio2 {
++              pcs_phy2: ethernet-phy@0 {
++              backplane-mode = "10gbase-kr";
++              compatible = "ethernet-phy-ieee802.3-c45";
++              reg = <0x0>;
++              fsl,lane-handle = <&serdes1>;
++              fsl,lane-reg = <0x980 0x40>;/* lane G */
++      };
++};
++
++&pcs_mdio3 {
++              pcs_phy3: ethernet-phy@0 {
++              backplane-mode = "10gbase-kr";
++              compatible = "ethernet-phy-ieee802.3-c45";
++              reg = <0x0>;
++              fsl,lane-handle = <&serdes1>;
++              fsl,lane-reg = <0x940 0x40>;/* lane F */
++      };
++};
++
++&pcs_mdio4 {
++              pcs_phy4: ethernet-phy@0 {
++              backplane-mode = "10gbase-kr";
++              compatible = "ethernet-phy-ieee802.3-c45";
++              reg = <0x0>;
++              fsl,lane-handle = <&serdes1>;
++              fsl,lane-reg = <0x900 0x40>;/* lane E */
++      };
++};
++
++/* Update DPMAC connections to backplane PHYs, under SerDes 0x2a_0xXX.
++ * &dpmac1 {
++ *    phy-handle = <&pcs_phy1>;
++ * };
++ *
++ * &dpmac2 {
++ *    phy-handle = <&pcs_phy2>;
++ * };
++ *
++ * &dpmac3 {
++ *    phy-handle = <&pcs_phy3>;
++ * };
++ *
++ * &dpmac4 {
++ *    phy-handle = <&pcs_phy4>;
++ * };
++ */
++
++/* Update DPMAC connections to external PHYs, under SerDes 0x2a_0x49. */
++&dpmac9 {
++      phy-handle = <&mdio0_phy12>;
++};
++&dpmac10 {
++      phy-handle = <&mdio0_phy13>;
++};
++&dpmac11 {
++      phy-handle = <&mdio0_phy14>;
++};
++&dpmac12 {
++      phy-handle = <&mdio0_phy15>;
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls2088a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls2088a-rdb.dts
+@@ -22,3 +22,83 @@
+               stdout-path = "serial1:115200n8";
+       };
+ };
++
++&emdio1 {
++      status = "disabled";
++      /* CS4340 PHYs */
++      mdio1_phy1: emdio1_phy@1 {
++              reg = <0x10>;
++              phy-connection-type = "xfi";
++      };
++      mdio1_phy2: emdio1_phy@2 {
++              reg = <0x11>;
++              phy-connection-type = "xfi";
++      };
++      mdio1_phy3: emdio1_phy@3 {
++              reg = <0x12>;
++              phy-connection-type = "xfi";
++      };
++      mdio1_phy4: emdio1_phy@4 {
++              reg = <0x13>;
++              phy-connection-type = "xfi";
++      };
++};
++
++&emdio2 {
++      /* AQR405 PHYs */
++      mdio2_phy1: emdio2_phy@1 {
++              compatible = "ethernet-phy-ieee802.3-c45";
++              interrupts = <0 1 0x4>; /* Level high type */
++              reg = <0x0>;
++              phy-connection-type = "xfi";
++      };
++      mdio2_phy2: emdio2_phy@2 {
++              compatible = "ethernet-phy-ieee802.3-c45";
++              interrupts = <0 2 0x4>; /* Level high type */
++              reg = <0x1>;
++              phy-connection-type = "xfi";
++      };
++      mdio2_phy3: emdio2_phy@3 {
++              compatible = "ethernet-phy-ieee802.3-c45";
++              interrupts = <0 4 0x4>; /* Level high type */
++              reg = <0x2>;
++              phy-connection-type = "xfi";
++      };
++      mdio2_phy4: emdio2_phy@4 {
++              compatible = "ethernet-phy-ieee802.3-c45";
++              interrupts = <0 5 0x4>; /* Level high type */
++              reg = <0x3>;
++              phy-connection-type = "xfi";
++      };
++};
++
++/* Update DPMAC connections to external PHYs, under the assumption of
++ * SerDes 0x2a_0x41. This is currently the only SerDes supported on the board.
++ */
++/* Leave Cortina PHYs commented out until proper driver is integrated
++ *&dpmac1 {
++ *    phy-handle = <&mdio1_phy1>;
++ *};
++ *&dpmac2 {
++ *    phy-handle = <&mdio1_phy2>;
++ *};
++ *&dpmac3 {
++ *    phy-handle = <&mdio1_phy3>;
++ *};
++ *&dpmac4 {
++ *    phy-handle = <&mdio1_phy4>;
++ *};
++ */
++
++&dpmac5 {
++      phy-handle = <&mdio2_phy1>;
++};
++&dpmac6 {
++      phy-handle = <&mdio2_phy2>;
++};
++&dpmac7 {
++      phy-handle = <&mdio2_phy3>;
++};
++&dpmac8 {
++      phy-handle = <&mdio2_phy4>;
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi
+@@ -129,6 +129,7 @@
+ &qspi {
+       status = "okay";
++      fsl,qspi-has-second-chip;
+       flash0: s25fl256s1@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa-rdb.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa-rdb.dtsi
+@@ -49,6 +49,7 @@
+               reg = <0x75>;
+               #address-cells = <1>;
+               #size-cells = <0>;
++              i2c-mux-never-disable;
+               i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+@@ -108,7 +109,15 @@
+ };
+ &qspi {
+-      status = "disabled";
++      status = "okay";
++      flash0: s25fs512s@0 {
++              #address-cells = <1>;
++              #size-cells = <1>;
++              compatible = "spansion,m25p80";
++              m25p,fast-read;
++              spi-max-frequency = <20000000>;
++              reg = <0>;
++      };
+ };
+ &sata0 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+@@ -114,13 +114,12 @@
+               };
+       };
+-      timer {
++      timer: timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <1 13 4>, /* Physical Secure PPI, active-low */
+                            <1 14 4>, /* Physical Non-Secure PPI, active-low */
+                            <1 11 4>, /* Virtual PPI, active-low */
+                            <1 10 4>; /* Hypervisor PPI, active-low */
+-              fsl,erratum-a008585;
+       };
+       pmu {
+@@ -560,15 +559,126 @@
+                       #interrupt-cells = <2>;
+               };
++              /* TODO: WRIOP (CCSR?) */
++              emdio1: mdio@0x8B96000 { /* WRIOP0: 0x8B8_0000,
++                                        * E-MDIO1: 0x1_6000
++                                        */
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8B96000 0x0 0x1000>;
++                      device_type = "mdio";   /* TODO: is this necessary? */
++                      little-endian;  /* force the driver in LE mode */
++
++                      /* Not necessary on the QDS, but needed on the RDB */
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              emdio2: mdio@0x8B97000 { /* WRIOP0: 0x8B8_0000,
++                                        * E-MDIO2: 0x1_7000
++                                        */
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8B97000 0x0 0x1000>;
++                      device_type = "mdio";   /* TODO: is this necessary? */
++                      little-endian;  /* force the driver in LE mode */
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio1: mdio@0x8c07000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c07000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio2: mdio@0x8c0b000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c0b000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio3: mdio@0x8c0f000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c0f000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio4: mdio@0x8c13000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c13000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio5: mdio@0x8c17000 {
++                      status = "disabled";
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c17000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio6: mdio@0x8c1b000 {
++                      status = "disabled";
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c1b000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio7: mdio@0x8c1f000 {
++                      status = "disabled";
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c1f000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio8: mdio@0x8c23000 {
++                      status = "disabled";
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c23000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
+               i2c0: i2c@2000000 {
+                       status = "disabled";
+-                      compatible = "fsl,vf610-i2c";
++                      compatible = "fsl,vf610-i2c", "fsl,ls208xa-vf610-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0 0x2000000 0x0 0x10000>;
+                       interrupts = <0 34 0x4>; /* Level high type */
+                       clock-names = "i2c";
+-                      clocks = <&clockgen 4 3>;
++                      clocks = <&clockgen 4 1>;
++                      scl-gpios = <&gpio3 10 0>;
+               };
+               i2c1: i2c@2010000 {
+@@ -579,7 +689,7 @@
+                       reg = <0x0 0x2010000 0x0 0x10000>;
+                       interrupts = <0 34 0x4>; /* Level high type */
+                       clock-names = "i2c";
+-                      clocks = <&clockgen 4 3>;
++                      clocks = <&clockgen 4 1>;
+               };
+               i2c2: i2c@2020000 {
+@@ -590,7 +700,7 @@
+                       reg = <0x0 0x2020000 0x0 0x10000>;
+                       interrupts = <0 35 0x4>; /* Level high type */
+                       clock-names = "i2c";
+-                      clocks = <&clockgen 4 3>;
++                      clocks = <&clockgen 4 1>;
+               };
+               i2c3: i2c@2030000 {
+@@ -601,7 +711,7 @@
+                       reg = <0x0 0x2030000 0x0 0x10000>;
+                       interrupts = <0 35 0x4>; /* Level high type */
+                       clock-names = "i2c";
+-                      clocks = <&clockgen 4 3>;
++                      clocks = <&clockgen 4 1>;
+               };
+               ifc: ifc@2240000 {
+@@ -633,8 +743,8 @@
+               pcie1: pcie@3400000 {
+                       compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie";
+                       reg-names = "regs", "config";
+-                      interrupts = <0 108 0x4>; /* Level high type */
+-                      interrupt-names = "intr";
++                      interrupts = <0 108 0x4>; /* aer interrupt */
++                      interrupt-names = "aer";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+@@ -642,6 +752,7 @@
+                       num-viewport = <6>;
+                       bus-range = <0x0 0xff>;
+                       msi-parent = <&its>;
++                      iommu-map = <0 &smmu 0 1>;      /* This is fixed-up by u-boot */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic 0 0 0 109 4>,
+@@ -654,8 +765,8 @@
+               pcie2: pcie@3500000 {
+                       compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie";
+                       reg-names = "regs", "config";
+-                      interrupts = <0 113 0x4>; /* Level high type */
+-                      interrupt-names = "intr";
++                      interrupts = <0 113 0x4>; /* aer interrupt */
++                      interrupt-names = "aer";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+@@ -663,6 +774,7 @@
+                       num-viewport = <6>;
+                       bus-range = <0x0 0xff>;
+                       msi-parent = <&its>;
++                      iommu-map = <0 &smmu 0 1>;      /* This is fixed-up by u-boot */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic 0 0 0 114 4>,
+@@ -675,8 +787,8 @@
+               pcie3: pcie@3600000 {
+                       compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie";
+                       reg-names = "regs", "config";
+-                      interrupts = <0 118 0x4>; /* Level high type */
+-                      interrupt-names = "intr";
++                      interrupts = <0 118 0x4>; /* aer interrupt */
++                      interrupt-names = "aer";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+@@ -684,6 +796,7 @@
+                       num-viewport = <256>;
+                       bus-range = <0x0 0xff>;
+                       msi-parent = <&its>;
++                      iommu-map = <0 &smmu 0 1>;      /* This is fixed-up by u-boot */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic 0 0 0 119 4>,
+@@ -696,8 +809,8 @@
+               pcie4: pcie@3700000 {
+                       compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie";
+                       reg-names = "regs", "config";
+-                      interrupts = <0 123 0x4>; /* Level high type */
+-                      interrupt-names = "intr";
++                      interrupts = <0 123 0x4>; /* aer interrupt */
++                      interrupt-names = "aer";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+@@ -705,6 +818,7 @@
+                       num-viewport = <6>;
+                       bus-range = <0x0 0xff>;
+                       msi-parent = <&its>;
++                      iommu-map = <0 &smmu 0 1>;      /* This is fixed-up by u-boot */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic 0 0 0 124 4>,
+@@ -754,11 +868,22 @@
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+               };
++              serdes1: serdes@1ea0000 {
++                              reg = <0x0 0x1ea0000 0 0x00002000>;
++                              compatible = "fsl,serdes-10g";
++              };
++
+               ccn@4000000 {
+                       compatible = "arm,ccn-504";
+                       reg = <0x0 0x04000000 0x0 0x01000000>;
+                       interrupts = <0 12 4>;
+               };
++
++              ftm0: ftm0@2800000 {
++                      compatible = "fsl,ftm-alarm";
++                      reg = <0x0 0x2800000 0x0 0x10000>;
++                      interrupts = <0 44 4>;
++              };
+       };
+       ddr1: memory-controller@1080000 {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0011-ARM-dts-accumulated-change.patch b/target/linux/layerscape/patches-5.4/302-dts-0011-ARM-dts-accumulated-change.patch
new file mode 100644 (file)
index 0000000..c49c4db
--- /dev/null
@@ -0,0 +1,156 @@
+From a9f1c1d3e410596d0a39fd92562cc48ef960b1b7 Mon Sep 17 00:00:00 2001
+From: Li Yang <leoyang.li@nxp.com>
+Date: Fri, 5 Oct 2018 18:33:49 -0500
+Subject: [PATCH] ARM: dts: accumulated change
+
+Signed-off-by: Li Yang <leoyang.li@nxp.com>
+---
+ arch/arm/boot/dts/ls1021a-qds.dts | 15 +++++++++++++++
+ arch/arm/boot/dts/ls1021a-twr.dts | 15 +++++++++++++++
+ arch/arm/boot/dts/ls1021a.dtsi    | 29 ++++++++++++++++++++++++-----
+ 3 files changed, 54 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/boot/dts/ls1021a-qds.dts
++++ b/arch/arm/boot/dts/ls1021a-qds.dts
+@@ -126,6 +126,21 @@
+       };
+ };
++&qspi {
++      num-cs = <2>;
++      status = "okay";
++
++      qflash0: s25fl128s@0 {
++              compatible = "spansion,m25p80";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              spi-max-frequency = <20000000>;
++              reg = <0>;
++              spi-rx-bus-width = <4>;
++              spi-tx-bus-width = <4>;
++      };
++};
++
+ &enet0 {
+       tbi-handle = <&tbi0>;
+       phy-handle = <&sgmii_phy1c>;
+--- a/arch/arm/boot/dts/ls1021a-twr.dts
++++ b/arch/arm/boot/dts/ls1021a-twr.dts
+@@ -144,6 +144,21 @@
+       };
+ };
++&qspi {
++      num-cs = <2>;
++      status = "okay";
++
++      qflash0: n25q128a13@0 {
++              compatible = "n25q128a13", "jedec,spi-nor";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              spi-max-frequency = <20000000>;
++              reg = <0>;
++              spi-rx-bus-width = <4>;
++              spi-tx-bus-width = <4>;
++      };
++};
++
+ &enet0 {
+       tbi-handle = <&tbi0>;
+       phy-handle = <&sgmii_phy2>;
+--- a/arch/arm/boot/dts/ls1021a.dtsi
++++ b/arch/arm/boot/dts/ls1021a.dtsi
+@@ -167,12 +167,13 @@
+               ifc: ifc@1530000 {
+                       compatible = "fsl,ifc", "simple-bus";
+                       reg = <0x0 0x1530000 0x0 0x10000>;
++                      big-endian;
+                       interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+               };
+               dcfg: dcfg@1ee0000 {
+                       compatible = "fsl,ls1021a-dcfg", "syscon";
+-                      reg = <0x0 0x1ee0000 0x0 0x10000>;
++                      reg = <0x0 0x1ee0000 0x0 0x1000>;
+                       big-endian;
+               };
+@@ -371,7 +372,7 @@
+               };
+               i2c0: i2c@2180000 {
+-                      compatible = "fsl,vf610-i2c";
++                      compatible = "fsl,vf610-i2c", "fsl,ls1021a-vf610-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0 0x2180000 0x0 0x10000>;
+@@ -380,11 +381,12 @@
+                       clocks = <&clockgen 4 1>;
+                       dma-names = "tx", "rx";
+                       dmas = <&edma0 1 39>, <&edma0 1 38>;
++                      fsl-scl-gpio = <&gpio3 23 0>;
+                       status = "disabled";
+               };
+               i2c1: i2c@2190000 {
+-                      compatible = "fsl,vf610-i2c";
++                      compatible = "fsl,vf610-i2c", "fsl,ls1021a-vf610-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0 0x2190000 0x0 0x10000>;
+@@ -393,6 +395,7 @@
+                       clocks = <&clockgen 4 1>;
+                       dma-names = "tx", "rx";
+                       dmas = <&edma0 1 37>, <&edma0 1 36>;
++                      fsl-scl-gpio = <&gpio3 23 0>;
+                       status = "disabled";
+               };
+@@ -579,6 +582,16 @@
+                       status = "disabled";
+               };
++              ftm0: ftm0@29d0000 {
++                      compatible = "fsl,ftm-alarm";
++                      reg = <0x0 0x29d0000 0x0 0x10000>,
++                            <0x0 0x1ee2140 0x0 0x4>;
++                      reg-names = "ftm", "FlexTimer1";
++                      interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++                      big-endian;
++                      status = "okay";
++              };
++
+               pwm1: pwm@29e0000 {
+                       compatible = "fsl,vf610-ftm-pwm";
+                       #pwm-cells = <3>;
+@@ -861,6 +874,8 @@
+                       dr_mode = "host";
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,dis_rxdet_inp3_quirk;
++                      usb3-lpm-capable;
++                      snps,dis-u1u2-when-u3-quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+               };
+@@ -869,7 +884,9 @@
+                       reg = <0x00 0x03400000 0x0 0x00010000   /* controller registers */
+                              0x40 0x00000000 0x0 0x00002000>; /* configuration space */
+                       reg-names = "regs", "config";
+-                      interrupts = <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>; /* controller interrupt */
++                      interrupts = <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>,
++                                         <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>; /* aer interrupt */
++                      interrupt-names = "pme", "aer";
+                       fsl,pcie-scfg = <&scfg 0>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+@@ -893,7 +910,9 @@
+                       reg = <0x00 0x03500000 0x0 0x00010000   /* controller registers */
+                              0x48 0x00000000 0x0 0x00002000>; /* configuration space */
+                       reg-names = "regs", "config";
+-                      interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
++                      interrupts = <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>,
++                                         <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>; /* aer interrupt */
++                      interrupt-names = "pme", "aer";
+                       fsl,pcie-scfg = <&scfg 1>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0012-arm64-dts-ls1046a-add-smmu-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0012-arm64-dts-ls1046a-add-smmu-node.patch
new file mode 100644 (file)
index 0000000..17f4024
--- /dev/null
@@ -0,0 +1,63 @@
+From 233d5936fb01dc7b47641e10354f7cc34124c592 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 6 Feb 2018 14:27:41 +0200
+Subject: [PATCH] arm64: dts: ls1046a: add smmu node
+
+This allows for the SMMU device to be probed by the SMMU kernel driver.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 42 ++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+@@ -229,6 +229,48 @@
+                       bus-width = <4>;
+               };
++              smmu: iommu@9000000 {
++                      compatible = "arm,mmu-500";
++                      reg = <0 0x9000000 0 0x400000>;
++                      dma-coherent;
++                      #global-interrupts = <2>;
++                      #iommu-cells = <1>;
++                      interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
+               scfg: scfg@1570000 {
+                       compatible = "fsl,ls1046a-scfg", "syscon";
+                       reg = <0x0 0x1570000 0x0 0x10000>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0013-arm64-dts-ls1043a-add-smmu-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0013-arm64-dts-ls1043a-add-smmu-node.patch
new file mode 100644 (file)
index 0000000..19c0bcb
--- /dev/null
@@ -0,0 +1,63 @@
+From 6b81f85d194bf15cf91ed3b4a8aec2d1ed2849a8 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 3 Apr 2018 17:15:44 +0300
+Subject: [PATCH] arm64: dts: ls1043a: add smmu node
+
+This allows for the SMMU device to be probed by the SMMU kernel driver.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 42 ++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+@@ -226,6 +226,48 @@
+                       clocks = <&sysclk>;
+               };
++              smmu: iommu@9000000 {
++                      compatible = "arm,mmu-500";
++                      reg = <0 0x9000000 0 0x400000>;
++                      dma-coherent;
++                      #global-interrupts = <2>;
++                      #iommu-cells = <1>;
++                      interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
+               scfg: scfg@1570000 {
+                       compatible = "fsl,ls1043a-scfg", "syscon";
+                       reg = <0x0 0x1570000 0x0 0x10000>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0014-arm64-dts-ls104xa-set-mask-to-drop-TBU-ID-from-Strea.patch b/target/linux/layerscape/patches-5.4/302-dts-0014-arm64-dts-ls104xa-set-mask-to-drop-TBU-ID-from-Strea.patch
new file mode 100644 (file)
index 0000000..2120639
--- /dev/null
@@ -0,0 +1,38 @@
+From 66307f9e693bd4822a683fac8cf1f63533822c18 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Thu, 3 May 2018 18:05:43 +0300
+Subject: [PATCH] arm64: dts: ls104xa: set mask to drop TBU ID from StreamID
+
+The StreamID entering the SMMU is actually a concatenation of the
+SMMU TBU ID and the ICID configured in software.
+Since the TBU ID is internal to the SoC and since we want that the
+actual the ICID configured in software to enter the SMMU witout any
+additional set bits, mask out the TBU ID bits and leave only the
+relevant ICID bits to enter SMMU.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 1 +
+ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+@@ -230,6 +230,7 @@
+                       compatible = "arm,mmu-500";
+                       reg = <0 0x9000000 0 0x400000>;
+                       dma-coherent;
++                      stream-match-mask = <0x7f00>;
+                       #global-interrupts = <2>;
+                       #iommu-cells = <1>;
+                       interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+@@ -233,6 +233,7 @@
+                       compatible = "arm,mmu-500";
+                       reg = <0 0x9000000 0 0x400000>;
+                       dma-coherent;
++                      stream-match-mask = <0x7f00>;
+                       #global-interrupts = <2>;
+                       #iommu-cells = <1>;
+                       interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0015-arm64-dts-ls104x-add-missing-dma-ranges-property.patch b/target/linux/layerscape/patches-5.4/302-dts-0015-arm64-dts-ls104x-add-missing-dma-ranges-property.patch
new file mode 100644 (file)
index 0000000..ebcbf36
--- /dev/null
@@ -0,0 +1,35 @@
+From f656c67b9522f18e38394fe5b6e00302c0c8ceb8 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Thu, 17 May 2018 11:40:07 +0300
+Subject: [PATCH] arm64: dts: ls104x: add missing dma ranges property
+
+These chips have a 48-bit address size so make sure that the dma-ranges
+reflects this. Otherwise the linux kernel's dma sub-system will set
+the default dma masks to full 64-bit, badly breaking dmas.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 1 +
+ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+@@ -218,6 +218,7 @@
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
++              dma-ranges = <0x0 0x0 0x0 0x0 0x10000 0x00000000>;
+               clockgen: clocking@1ee1000 {
+                       compatible = "fsl,ls1043a-clockgen";
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+@@ -190,6 +190,7 @@
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
++              dma-ranges = <0x0 0x0 0x0 0x0 0x10000 0x00000000>;
+               ddr: memory-controller@1080000 {
+                       compatible = "fsl,qoriq-memory-controller";
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0016-arm64-dts-ls104x-add-iommu-map-to-pci-controllers.patch b/target/linux/layerscape/patches-5.4/302-dts-0016-arm64-dts-ls104x-add-iommu-map-to-pci-controllers.patch
new file mode 100644 (file)
index 0000000..7f6e4c6
--- /dev/null
@@ -0,0 +1,67 @@
+From 317d4e577ede33f226d24bd12a8edbaafee22e57 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Thu, 17 May 2018 11:56:27 +0300
+Subject: [PATCH] arm64: dts: ls104x: add iommu-map to pci controllers
+
+The pci controllers are also behind the smmu so add the iommu-map
+property to reflect this. The bootloader needs to patch the stream id
+ranges to some sane values.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++
+ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 3 +++
+ 2 files changed, 6 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+@@ -807,6 +807,7 @@
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       dma-coherent;
++                      iommu-map = <0 &smmu 0 1>;      /* update by bootloader */
+                       num-viewport = <6>;
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000   /* downstream I/O */
+@@ -833,6 +834,7 @@
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       dma-coherent;
++                      iommu-map = <0 &smmu 0 1>;      /* update by bootloader */
+                       num-viewport = <6>;
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000   /* downstream I/O */
+@@ -859,6 +861,7 @@
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       dma-coherent;
++                      iommu-map = <0 &smmu 0 1>;      /* update by bootloader */
+                       num-viewport = <6>;
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0x00000000 0x50 0x00010000 0x0 0x00010000   /* downstream I/O */
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+@@ -715,6 +715,7 @@
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       dma-coherent;
++                      iommu-map = <0 &smmu 0 1>;      /* update by bootloader */
+                       num-viewport = <8>;
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000   /* downstream I/O */
+@@ -751,6 +752,7 @@
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       dma-coherent;
++                      iommu-map = <0 &smmu 0 1>;      /* update by bootloader */
+                       num-viewport = <8>;
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000   /* downstream I/O */
+@@ -787,6 +789,7 @@
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       dma-coherent;
++                      iommu-map = <0 &smmu 0 1>;      /* update by bootloader */
+                       num-viewport = <8>;
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0x00000000 0x50 0x00010000 0x0 0x00010000   /* downstream I/O */
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0017-arm64-dts-ls104x-make-dma-coherent-global-to-the-SoC.patch b/target/linux/layerscape/patches-5.4/302-dts-0017-arm64-dts-ls104x-make-dma-coherent-global-to-the-SoC.patch
new file mode 100644 (file)
index 0000000..c29b35b
--- /dev/null
@@ -0,0 +1,67 @@
+From b1e679aba75e5e137c70bc76169c34835ef0e474 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 24 Jul 2018 13:11:03 +0300
+Subject: [PATCH] arm64: dts: ls104x: make dma-coherent global to the SoC
+
+These SoCs are really completely dma coherent in their entirety so add
+the dma-coherent property at the soc level in the device tree and drop
+the instances where it's specifically added to a few select devices.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 5 +----
+ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 1 +
+ 2 files changed, 2 insertions(+), 4 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+@@ -219,6 +219,7 @@
+               #size-cells = <2>;
+               ranges;
+               dma-ranges = <0x0 0x0 0x0 0x0 0x10000 0x00000000>;
++              dma-coherent;
+               clockgen: clocking@1ee1000 {
+                       compatible = "fsl,ls1043a-clockgen";
+@@ -771,7 +772,6 @@
+                       reg-names = "ahci", "sata-ecc";
+                       interrupts = <0 69 0x4>;
+                       clocks = <&clockgen 4 0>;
+-                      dma-coherent;
+               };
+               msi1: msi-controller1@1571000 {
+@@ -806,7 +806,6 @@
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+-                      dma-coherent;
+                       iommu-map = <0 &smmu 0 1>;      /* update by bootloader */
+                       num-viewport = <6>;
+                       bus-range = <0x0 0xff>;
+@@ -833,7 +832,6 @@
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+-                      dma-coherent;
+                       iommu-map = <0 &smmu 0 1>;      /* update by bootloader */
+                       num-viewport = <6>;
+                       bus-range = <0x0 0xff>;
+@@ -860,7 +858,6 @@
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+-                      dma-coherent;
+                       iommu-map = <0 &smmu 0 1>;      /* update by bootloader */
+                       num-viewport = <6>;
+                       bus-range = <0x0 0xff>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+@@ -191,6 +191,7 @@
+               #size-cells = <2>;
+               ranges;
+               dma-ranges = <0x0 0x0 0x0 0x0 0x10000 0x00000000>;
++              dma-coherent;
+               ddr: memory-controller@1080000 {
+                       compatible = "fsl,qoriq-memory-controller";
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0018-arm64-dts-ls104x-use-a-pseudo-bus-to-constrain-usb-d.patch b/target/linux/layerscape/patches-5.4/302-dts-0018-arm64-dts-ls104x-use-a-pseudo-bus-to-constrain-usb-d.patch
new file mode 100644 (file)
index 0000000..ef610cb
--- /dev/null
@@ -0,0 +1,193 @@
+From a6a86473350c7dcbae61afa1e926941d76ca17ed Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Thu, 20 Sep 2018 13:46:54 +0300
+Subject: [PATCH] arm64: dts: ls104x: use a pseudo-bus to constrain usb dma
+ size
+
+Wrap the usb controllers in an intermediate simple-bus and use it to
+constrain the dma address size of these usb controllers to the 40 bits
+that they generate toward the interconnect.
+This is required because the SoC uses 48 bits address sizes and this
+mismatch would lead to smmu context faults because the usb generates
+40-bit addresses while the smmu page tables are populated with 48-bit
+wide addresses.
+
+Suggested-by: Robin Murphy <robin.murphy@arm.com>
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 82 ++++++++++++++------------
+ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 76 +++++++++++++-----------
+ 2 files changed, 87 insertions(+), 71 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+@@ -726,43 +726,51 @@
+                                <&clockgen 4 0>;
+               };
+-              usb0: usb3@2f00000 {
+-                      compatible = "snps,dwc3";
+-                      reg = <0x0 0x2f00000 0x0 0x10000>;
+-                      interrupts = <0 60 0x4>;
+-                      dr_mode = "host";
+-                      snps,quirk-frame-length-adjustment = <0x20>;
+-                      snps,dis_rxdet_inp3_quirk;
+-                      usb3-lpm-capable;
+-                      snps,dis-u1u2-when-u3-quirk;
+-                      snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+-                      configure-gfladj;
+-              };
++              usb_aux_bus: usb_aux_bus {
++                      #address-cells = <2>;
++                      #size-cells = <2>;
++                      compatible = "simple-bus";
++                      ranges;
++                      dma-ranges = <0x0 0x0 0x0 0x0 0x100 0x00000000>;
+-              usb1: usb3@3000000 {
+-                      compatible = "snps,dwc3";
+-                      reg = <0x0 0x3000000 0x0 0x10000>;
+-                      interrupts = <0 61 0x4>;
+-                      dr_mode = "host";
+-                      snps,quirk-frame-length-adjustment = <0x20>;
+-                      snps,dis_rxdet_inp3_quirk;
+-                      usb3-lpm-capable;
+-                      snps,dis-u1u2-when-u3-quirk;
+-                      snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+-                      configure-gfladj;
+-              };
++                      usb0: usb3@2f00000 {
++                              compatible = "snps,dwc3";
++                              reg = <0x0 0x2f00000 0x0 0x10000>;
++                              interrupts = <0 60 0x4>;
++                              dr_mode = "host";
++                              snps,quirk-frame-length-adjustment = <0x20>;
++                              snps,dis_rxdet_inp3_quirk;
++                              usb3-lpm-capable;
++                              snps,dis-u1u2-when-u3-quirk;
++                              snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                              configure-gfladj;
++                      };
++
++                      usb1: usb3@3000000 {
++                              compatible = "snps,dwc3";
++                              reg = <0x0 0x3000000 0x0 0x10000>;
++                              interrupts = <0 61 0x4>;
++                              dr_mode = "host";
++                              snps,quirk-frame-length-adjustment = <0x20>;
++                              snps,dis_rxdet_inp3_quirk;
++                              usb3-lpm-capable;
++                              snps,dis-u1u2-when-u3-quirk;
++                              snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                              configure-gfladj;
++                      };
+-              usb2: usb3@3100000 {
+-                      compatible = "snps,dwc3";
+-                      reg = <0x0 0x3100000 0x0 0x10000>;
+-                      interrupts = <0 63 0x4>;
+-                      dr_mode = "host";
+-                      snps,quirk-frame-length-adjustment = <0x20>;
+-                      snps,dis_rxdet_inp3_quirk;
+-                      usb3-lpm-capable;
+-                      snps,dis-u1u2-when-u3-quirk;
+-                      snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+-                      configure-gfladj;
++                      usb2: usb3@3100000 {
++                              compatible = "snps,dwc3";
++                              reg = <0x0 0x3100000 0x0 0x10000>;
++                              interrupts = <0 63 0x4>;
++                              dr_mode = "host";
++                              snps,quirk-frame-length-adjustment = <0x20>;
++                              snps,dis_rxdet_inp3_quirk;
++                              usb3-lpm-capable;
++                              snps,dis-u1u2-when-u3-quirk;
++                              snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                              configure-gfladj;
++                      };
+               };
+               sata: sata@3200000 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+@@ -624,40 +624,48 @@
+                                <&clockgen 4 1>;
+               };
+-              usb0: usb@2f00000 {
+-                      compatible = "snps,dwc3";
+-                      reg = <0x0 0x2f00000 0x0 0x10000>;
+-                      interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+-                      dr_mode = "host";
+-                      snps,quirk-frame-length-adjustment = <0x20>;
+-                      snps,dis_rxdet_inp3_quirk;
+-                      snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+-                      usb3-lpm-capable;
+-                      snps,dis-u1u2-when-u3-quirk;
+-              };
++              usb_aux_bus: usb_aux_bus {
++                      #address-cells = <2>;
++                      #size-cells = <2>;
++                      compatible = "simple-bus";
++                      ranges;
++                      dma-ranges = <0x0 0x0 0x0 0x0 0x100 0x00000000>;
+-              usb1: usb@3000000 {
+-                      compatible = "snps,dwc3";
+-                      reg = <0x0 0x3000000 0x0 0x10000>;
+-                      interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
+-                      dr_mode = "host";
+-                      snps,quirk-frame-length-adjustment = <0x20>;
+-                      snps,dis_rxdet_inp3_quirk;
+-                      snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+-                      usb3-lpm-capable;
+-                      snps,dis-u1u2-when-u3-quirk;
+-              };
++                      usb0: usb@2f00000 {
++                              compatible = "snps,dwc3";
++                              reg = <0x0 0x2f00000 0x0 0x10000>;
++                              interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
++                              dr_mode = "host";
++                              snps,quirk-frame-length-adjustment = <0x20>;
++                              snps,dis_rxdet_inp3_quirk;
++                              snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                              usb3-lpm-capable;
++                              snps,dis-u1u2-when-u3-quirk;
++                      };
++
++                      usb1: usb@3000000 {
++                              compatible = "snps,dwc3";
++                              reg = <0x0 0x3000000 0x0 0x10000>;
++                              interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
++                              dr_mode = "host";
++                              snps,quirk-frame-length-adjustment = <0x20>;
++                              snps,dis_rxdet_inp3_quirk;
++                              snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                              usb3-lpm-capable;
++                              snps,dis-u1u2-when-u3-quirk;
++                      };
+-              usb2: usb@3100000 {
+-                      compatible = "snps,dwc3";
+-                      reg = <0x0 0x3100000 0x0 0x10000>;
+-                      interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+-                      dr_mode = "host";
+-                      snps,quirk-frame-length-adjustment = <0x20>;
+-                      snps,dis_rxdet_inp3_quirk;
+-                      snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+-                      usb3-lpm-capable;
+-                      snps,dis-u1u2-when-u3-quirk;
++                      usb2: usb@3100000 {
++                              compatible = "snps,dwc3";
++                              reg = <0x0 0x3100000 0x0 0x10000>;
++                              interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
++                              dr_mode = "host";
++                              snps,quirk-frame-length-adjustment = <0x20>;
++                              snps,dis_rxdet_inp3_quirk;
++                              snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                              usb3-lpm-capable;
++                              snps,dis-u1u2-when-u3-quirk;
++                      };
+               };
+               sata: sata@3200000 {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0019-sdk-dts-ls104x-drop-smmu-from-the-sdk-device-trees.patch b/target/linux/layerscape/patches-5.4/302-dts-0019-sdk-dts-ls104x-drop-smmu-from-the-sdk-device-trees.patch
new file mode 100644 (file)
index 0000000..bdf69a6
--- /dev/null
@@ -0,0 +1,60 @@
+From 9c0090519c422600596a9d7c1e6e33a5268dfce4 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Thu, 2 Aug 2018 17:54:28 +0300
+Subject: [PATCH] sdk: dts: ls104x: drop smmu from the sdk device trees
+
+SMMU is not supported for the SDK version of the dpaa ethernet
+drivers so remove the SMMU node from the device tree.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts | 14 ++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts | 14 ++++++++++++++
+ 2 files changed, 28 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts
+@@ -64,6 +64,20 @@
+ &soc {
+ #include "qoriq-dpaa-eth.dtsi"
+ #include "qoriq-fman3-0-6oh.dtsi"
++
++pcie@3400000 {
++      /delete-property/ iommu-map;
++};
++
++pcie@3500000 {
++      /delete-property/ iommu-map;
++};
++
++pcie@3600000 {
++      /delete-property/ iommu-map;
++};
++
++/delete-node/ iommu@9000000;
+ };
+ &fman0 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts
+@@ -64,6 +64,20 @@
+ &soc {
+ #include "qoriq-dpaa-eth.dtsi"
+ #include "qoriq-fman3-0-6oh.dtsi"
++
++pcie@3400000 {
++      /delete-property/ iommu-map;
++};
++
++pcie@3500000 {
++      /delete-property/ iommu-map;
++};
++
++pcie@3600000 {
++      /delete-property/ iommu-map;
++};
++
++/delete-node/ iommu@9000000;
+ };
+ &fsldpaa {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0020-arm64-dts-lx2160a-add-MDIO-device-tree-nodes.patch b/target/linux/layerscape/patches-5.4/302-dts-0020-arm64-dts-lx2160a-add-MDIO-device-tree-nodes.patch
new file mode 100644 (file)
index 0000000..0232c40
--- /dev/null
@@ -0,0 +1,41 @@
+From 5fb032ca86c078429ecdde3cbd9040702bb86954 Mon Sep 17 00:00:00 2001
+From: Vicentiu Galanopulo <vicentiu.galanopulo@nxp.com>
+Date: Fri, 20 Apr 2018 11:00:09 +0300
+Subject: [PATCH] arm64: dts: lx2160a: add MDIO device-tree nodes
+
+Signed-off-by: Vicentiu Galanopulo <vicentiu.galanopulo@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -478,6 +478,28 @@
+                       little-endian;
+               };
++              /* TODO: WRIOP (CCSR?) */
++              emdio1: mdio@0x8B96000 { /* WRIOP0: 0x8B8_0000, E-MDIO1: 0x1_6000 */
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8B96000 0x0 0x1000>;
++                      device_type = "mdio";                   /* TODO: is this necessary? */
++                      little-endian;  /* force the driver in LE mode */
++
++                      /* Not necessary on the QDS, but needed on the RDB */
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              emdio2: mdio@0x8B97000 { /* WRIOP0: 0x8B8_0000, E-MDIO2: 0x1_7000 */
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8B97000 0x0 0x1000>;
++                      device_type = "mdio";                   /* TODO: is this necessary? */
++                      little-endian;  /* force the driver in LE mode */
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
+               i2c0: i2c@2000000 {
+                       compatible = "fsl,vf610-i2c";
+                       #address-cells = <1>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0021-arm64-dts-lx2160a-rdb-Add-RGMII-PHY-nodes-for-dpmac-.patch b/target/linux/layerscape/patches-5.4/302-dts-0021-arm64-dts-lx2160a-rdb-Add-RGMII-PHY-nodes-for-dpmac-.patch
new file mode 100644 (file)
index 0000000..85fa5b8
--- /dev/null
@@ -0,0 +1,44 @@
+From 08726d24b8552e4a986631090e063d38cd2d82cf Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Tue, 10 Jul 2018 13:56:56 +0300
+Subject: [PATCH] arm64: dts: lx2160a-rdb: Add RGMII PHY nodes for dpmac 17 and
+ 18
+
+* Both are AR8035 chips
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts | 25 +++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
+@@ -159,3 +159,28 @@
+ &usb1 {
+       status = "okay";
+ };
++
++&emdio1 {
++      rgmii_phy1: ethernet-phy@1 {
++              /* AR8035 PHY - "compatible" property not strictly needed */
++              compatible = "ethernet-phy-id004d.d072";
++              reg = <0x1>;
++              /* Poll mode - no "interrupts" property defined */
++      };
++      rgmii_phy2: ethernet-phy@2 {
++              /* AR8035 PHY - "compatible" property not strictly needed */
++              compatible = "ethernet-phy-id004d.d072";
++              reg = <0x2>;
++              /* Poll mode - no "interrupts" property defined */
++      };
++};
++
++&dpmac17 {
++      phy-handle = <&rgmii_phy1>;
++      phy-connection-type = "rgmii-id";
++};
++
++&dpmac18 {
++      phy-handle = <&rgmii_phy2>;
++      phy-connection-type = "rgmii-id";
++};
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0022-arm64-dts-lx2160a-correct-scl-gpios-property.patch b/target/linux/layerscape/patches-5.4/302-dts-0022-arm64-dts-lx2160a-correct-scl-gpios-property.patch
new file mode 100644 (file)
index 0000000..991c5f5
--- /dev/null
@@ -0,0 +1,30 @@
+From a99acc11751ea640c7687155e964612b232bc492 Mon Sep 17 00:00:00 2001
+From: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date: Mon, 29 Oct 2018 10:37:03 +0800
+Subject: [PATCH] arm64: dts: lx2160a: correct scl-gpios property
+
+Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -508,7 +508,7 @@
+                       interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+                       clock-names = "i2c";
+                       clocks = <&clockgen 4 15>;
+-                      scl-gpio = <&gpio2 15 GPIO_ACTIVE_HIGH>;
++                      scl-gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>;
+                       status = "disabled";
+               };
+@@ -553,7 +553,7 @@
+                       interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+                       clock-names = "i2c";
+                       clocks = <&clockgen 4 15>;
+-                      scl-gpio = <&gpio2 16 GPIO_ACTIVE_HIGH>;
++                      scl-gpios = <&gpio2 16 GPIO_ACTIVE_HIGH>;
+                       status = "disabled";
+               };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0023-arm64-dts-lx2160a-add-dspi-controller-DT-nodes.patch b/target/linux/layerscape/patches-5.4/302-dts-0023-arm64-dts-lx2160a-add-dspi-controller-DT-nodes.patch
new file mode 100644 (file)
index 0000000..74fe605
--- /dev/null
@@ -0,0 +1,62 @@
+From df8cea437a14a4a412a32058ca49a2b30b48cc71 Mon Sep 17 00:00:00 2001
+From: Chuanhua Han <chuanhua.han@nxp.com>
+Date: Fri, 26 Oct 2018 12:08:55 +0800
+Subject: [PATCH] arm64: dts: lx2160a: add dspi controller DT nodes
+
+Add the dspi support on lx2160
+
+Signed-off-by: Chuanhua Han <chuanhua.han@nxp.com>
+Signed-off-by: Bao Xiaowei <xiaowei.bao@nxp.com>
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 39 ++++++++++++++++++++++++++
+ 1 file changed, 39 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -603,6 +603,45 @@
+                       status = "disabled";
+               };
++              dspi0: spi@2100000 {
++                      compatible = "fsl,lx2160a-dspi", "fsl,ls2085a-dspi";
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      reg = <0x0 0x2100000 0x0 0x10000>;
++                      interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&clockgen 4 7>;
++                      clock-names = "dspi";
++                      spi-num-chipselects = <5>;
++                      bus-num = <0>;
++                      status = "disabled";
++              };
++
++              dspi1: spi@2110000 {
++                      compatible = "fsl,lx2160a-dspi", "fsl,ls2085a-dspi";
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      reg = <0x0 0x2110000 0x0 0x10000>;
++                      interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&clockgen 4 7>;
++                      clock-names = "dspi";
++                      spi-num-chipselects = <5>;
++                      bus-num = <1>;
++                      status = "disabled";
++              };
++
++              dspi2: spi@2120000 {
++                      compatible = "fsl,lx2160a-dspi", "fsl,ls2085a-dspi";
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      reg = <0x0 0x2120000 0x0 0x10000>;
++                      interrupts = <GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&clockgen 4 7>;
++                      clock-names = "dspi";
++                      spi-num-chipselects = <5>;
++                      bus-num = <2>;
++                      status = "disabled";
++              };
++
+               esdhc0: esdhc@2140000 {
+                       compatible = "fsl,esdhc";
+                       reg = <0x0 0x2140000 0x0 0x10000>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0024-arm64-dts-lx2160a-add-DT-node-for-all-DSPI-controlle.patch b/target/linux/layerscape/patches-5.4/302-dts-0024-arm64-dts-lx2160a-add-DT-node-for-all-DSPI-controlle.patch
new file mode 100644 (file)
index 0000000..bb931fb
--- /dev/null
@@ -0,0 +1,59 @@
+From 3f304579d634bcbef18fec939e407c8e789637c8 Mon Sep 17 00:00:00 2001
+From: Chuanhua Han <chuanhua.han@nxp.com>
+Date: Fri, 26 Oct 2018 12:11:25 +0800
+Subject: [PATCH] arm64: dts: lx2160a: add DT node for all DSPI controller
+
+Add device tree node for first flash (CS0) connected
+to all dspi controller.
+
+Signed-off-by: Chuanhua Han <chuanhua.han@nxp.com>
+Signed-off-by: Wasim Khan <wasim.khan@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts | 36 +++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
+@@ -35,6 +35,42 @@
+       status = "okay";
+ };
++&dspi0 {
++      status = "okay";
++
++      dflash0: flash@0 {
++              #address-cells = <1>;
++              #size-cells = <1>;
++              compatible = "jedec,spi-nor";
++              reg = <0>;
++              spi-max-frequency = <1000000>;
++      };
++};
++
++&dspi1 {
++      status = "okay";
++
++      dflash1: flash@0 {
++              #address-cells = <1>;
++              #size-cells = <1>;
++              compatible = "jedec,spi-nor";
++              reg = <0>;
++              spi-max-frequency = <1000000>;
++      };
++};
++
++&dspi2 {
++      status = "okay";
++
++      dflash2: flash@0 {
++              #address-cells = <1>;
++              #size-cells = <1>;
++              compatible = "jedec,spi-nor";
++              reg = <0>;
++              spi-max-frequency = <1000000>;
++      };
++};
++
+ &esdhc0 {
+       status = "okay";
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0025-arm64-dts-nxp-ls208xa-add-more-thermal-zone-support.patch b/target/linux/layerscape/patches-5.4/302-dts-0025-arm64-dts-nxp-ls208xa-add-more-thermal-zone-support.patch
new file mode 100644 (file)
index 0000000..42deb82
--- /dev/null
@@ -0,0 +1,745 @@
+From d05cf625f27335320a2ad883b7f7c4cd638dca99 Mon Sep 17 00:00:00 2001
+From: Yuantian Tang <andy.tang@nxp.com>
+Date: Mon, 5 Nov 2018 17:25:32 +0800
+Subject: [PATCH] arm64: dts: nxp: ls208xa: add more thermal zone support
+
+Ls208xa has several thermal sensors. Add all the sensor id to dts
+to enable them.
+
+To make the dts cleaner, re-organize the nodes to split out the
+common part so that it can be shared with other SoCs.
+
+Signed-off-by: Yuantian Tang <andy.tang@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi  |   8 +-
+ arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi  |   8 +-
+ arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi  |  70 ++++---
+ arch/arm64/boot/dts/freescale/fsl-tmu-map1.dtsi |  99 ++++++++++
+ arch/arm64/boot/dts/freescale/fsl-tmu-map2.dtsi |  99 ++++++++++
+ arch/arm64/boot/dts/freescale/fsl-tmu-map3.dtsi |  99 ++++++++++
+ arch/arm64/boot/dts/freescale/fsl-tmu.dtsi      | 251 ++++++++++++++++++++++++
+ 7 files changed, 590 insertions(+), 44 deletions(-)
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-tmu-map1.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-tmu-map2.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-tmu-map3.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-tmu.dtsi
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
+@@ -12,7 +12,7 @@
+ #include "fsl-ls208xa.dtsi"
+ &cpu {
+-      cpu0: cpu@0 {
++      cooling_map0: cpu0: cpu@0 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x0>;
+@@ -32,7 +32,7 @@
+               #cooling-cells = <2>;
+       };
+-      cpu2: cpu@100 {
++      cooling_map1: cpu2: cpu@100 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x100>;
+@@ -52,7 +52,7 @@
+               #cooling-cells = <2>;
+       };
+-      cpu4: cpu@200 {
++      cooling_map2: cpu4: cpu@200 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x200>;
+@@ -72,7 +72,7 @@
+               #cooling-cells = <2>;
+       };
+-      cpu6: cpu@300 {
++      cooling_map3: cpu6: cpu@300 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x300>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi
+@@ -12,7 +12,7 @@
+ #include "fsl-ls208xa.dtsi"
+ &cpu {
+-      cpu0: cpu@0 {
++      cooling_map0: cpu0: cpu@0 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a72";
+               reg = <0x0>;
+@@ -32,7 +32,7 @@
+               #cooling-cells = <2>;
+       };
+-      cpu2: cpu@100 {
++      cooling_map1: cpu2: cpu@100 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a72";
+               reg = <0x100>;
+@@ -52,7 +52,7 @@
+               #cooling-cells = <2>;
+       };
+-      cpu4: cpu@200 {
++      cooling_map2: cpu4: cpu@200 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a72";
+               reg = <0x200>;
+@@ -72,7 +72,7 @@
+               #cooling-cells = <2>;
+       };
+-      cpu6: cpu@300 {
++      cooling_map3: cpu6: cpu@300 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a72";
+               reg = <0x300>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+@@ -77,42 +77,7 @@
+               mask = <0x2>;
+       };
+-      thermal-zones {
+-              cpu_thermal: cpu-thermal {
+-                      polling-delay-passive = <1000>;
+-                      polling-delay = <5000>;
+-
+-                      thermal-sensors = <&tmu 4>;
+-
+-                      trips {
+-                              cpu_alert: cpu-alert {
+-                                      temperature = <75000>;
+-                                      hysteresis = <2000>;
+-                                      type = "passive";
+-                              };
+-                              cpu_crit: cpu-crit {
+-                                      temperature = <85000>;
+-                                      hysteresis = <2000>;
+-                                      type = "critical";
+-                              };
+-                      };
+-
+-                      cooling-maps {
+-                              map0 {
+-                                      trip = <&cpu_alert>;
+-                                      cooling-device =
+-                                              <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+-                              };
+-                      };
+-              };
+-      };
++      #include "fsl-tmu.dtsi"
+       timer: timer {
+               compatible = "arm,armv8-timer";
+@@ -907,3 +872,36 @@
+               };
+       };
+ };
++
++#include "fsl-tmu-map1.dtsi"
++#include "fsl-tmu-map2.dtsi"
++#include "fsl-tmu-map3.dtsi"
++&thermal_zones {
++      thermal-zone1 {
++              status = "okay";
++      };
++
++      thermal-zone2{
++              status = "okay";
++      };
++
++      thermal-zone3{
++              status = "okay";
++      };
++
++      thermal-zone4{
++              status = "okay";
++      };
++
++      thermal-zone5{
++              status = "okay";
++      };
++
++      thermal-zone6{
++              status = "okay";
++      };
++
++      thermal-zone7 {
++              status = "okay";
++      };
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-tmu-map1.dtsi
+@@ -0,0 +1,99 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree Include file for Thermal Monitor Unit.
++ *
++ * Copyright 2018 NXP
++ *
++ * Tang Yuantian <andy.tang@nxp.com>
++ *
++ */
++
++&thermal_zones {
++      thermal-zone0 {
++              cooling-maps {
++                      map1 {
++                              trip = <&alert0>;
++                              cooling-device =
++                                      <&cooling_map1 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone1 {
++              cooling-maps {
++                      map1 {
++                              trip = <&alert1>;
++                              cooling-device =
++                                      <&cooling_map1 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone2 {
++              cooling-maps {
++                      map1 {
++                              trip = <&alert2>;
++                              cooling-device =
++                                      <&cooling_map1 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone3 {
++              cooling-maps {
++                      map1 {
++                              trip = <&alert3>;
++                              cooling-device =
++                                      <&cooling_map1 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone4 {
++              cooling-maps {
++                      map1 {
++                              trip = <&alert4>;
++                              cooling-device =
++                                      <&cooling_map1 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone5 {
++              cooling-maps {
++                      map1 {
++                              trip = <&alert5>;
++                              cooling-device =
++                                      <&cooling_map1 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone6 {
++              cooling-maps {
++                      map1 {
++                              trip = <&alert6>;
++                              cooling-device =
++                                      <&cooling_map1 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone7 {
++              cooling-maps {
++                      map1 {
++                              trip = <&alert7>;
++                              cooling-device =
++                                      <&cooling_map1 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-tmu-map2.dtsi
+@@ -0,0 +1,99 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree Include file for Thermal Monitor Unit.
++ *
++ * Copyright 2018 NXP
++ *
++ * Tang Yuantian <andy.tang@nxp.com>
++ *
++ */
++
++&thermal_zones {
++      thermal-zone0 {
++              cooling-maps {
++                      map2 {
++                              trip = <&alert0>;
++                              cooling-device =
++                                      <&cooling_map2 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone1 {
++              cooling-maps {
++                      map2 {
++                              trip = <&alert1>;
++                              cooling-device =
++                                      <&cooling_map2 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone2 {
++              cooling-maps {
++                      map2 {
++                              trip = <&alert2>;
++                              cooling-device =
++                                      <&cooling_map2 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone3 {
++              cooling-maps {
++                      map2 {
++                              trip = <&alert3>;
++                              cooling-device =
++                                      <&cooling_map2 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone4 {
++              cooling-maps {
++                      map2 {
++                              trip = <&alert4>;
++                              cooling-device =
++                                      <&cooling_map2 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone5 {
++              cooling-maps {
++                      map2 {
++                              trip = <&alert5>;
++                              cooling-device =
++                                      <&cooling_map2 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone6 {
++              cooling-maps {
++                      map2 {
++                              trip = <&alert6>;
++                              cooling-device =
++                                      <&cooling_map2 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone7 {
++              cooling-maps {
++                      map2 {
++                              trip = <&alert7>;
++                              cooling-device =
++                                      <&cooling_map2 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-tmu-map3.dtsi
+@@ -0,0 +1,99 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree Include file for Thermal Monitor Unit.
++ *
++ * Copyright 2018 NXP
++ *
++ * Tang Yuantian <andy.tang@nxp.com>
++ *
++ */
++
++&thermal_zones {
++      thermal-zone0 {
++              cooling-maps {
++                      map3 {
++                              trip = <&alert0>;
++                              cooling-device =
++                                      <&cooling_map3 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone1 {
++              cooling-maps {
++                      map3 {
++                              trip = <&alert1>;
++                              cooling-device =
++                                      <&cooling_map3 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone2 {
++              cooling-maps {
++                      map3 {
++                              trip = <&alert2>;
++                              cooling-device =
++                                      <&cooling_map3 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone3 {
++              cooling-maps {
++                      map3 {
++                              trip = <&alert3>;
++                              cooling-device =
++                                      <&cooling_map3 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone4 {
++              cooling-maps {
++                      map3 {
++                              trip = <&alert4>;
++                              cooling-device =
++                                      <&cooling_map3 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone5 {
++              cooling-maps {
++                      map3 {
++                              trip = <&alert5>;
++                              cooling-device =
++                                      <&cooling_map3 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone6 {
++              cooling-maps {
++                      map3 {
++                              trip = <&alert6>;
++                              cooling-device =
++                                      <&cooling_map3 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone7 {
++              cooling-maps {
++                      map3 {
++                              trip = <&alert7>;
++                              cooling-device =
++                                      <&cooling_map3 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-tmu.dtsi
+@@ -0,0 +1,251 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree Include file for Thermal Monitor Unit.
++ *
++ * Copyright 2018 NXP
++ *
++ * Tang Yuantian <andy.tang@nxp.com>
++ *
++ */
++
++thermal_zones: thermal-zones {
++      thermal_zone0: thermal-zone0 {
++              polling-delay-passive = <1000>;
++              polling-delay = <5000>;
++              thermal-sensors = <&tmu 0>;
++              status = "disabled";
++
++              trips {
++                      alert0: alert0 {
++                              temperature = <75000>;
++                              hysteresis = <2000>;
++                              type = "passive";
++                      };
++
++                      crit0: crit0 {
++                              temperature = <85000>;
++                              hysteresis = <2000>;
++                              type = "critical";
++                      };
++              };
++
++              cooling-maps {
++                      map0 {
++                              trip = <&alert0>;
++                              cooling-device =
++                                      <&cooling_map0 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone1 {
++              polling-delay-passive = <1000>;
++              polling-delay = <5000>;
++              thermal-sensors = <&tmu 1>;
++              status = "disabled";
++
++              trips {
++                      alert1: alert1 {
++                              temperature = <75000>;
++                              hysteresis = <2000>;
++                              type = "passive";
++                      };
++
++                      crit1: crit1 {
++                              temperature = <85000>;
++                              hysteresis = <2000>;
++                              type = "critical";
++                      };
++              };
++
++              cooling-maps {
++                      map0 {
++                              trip = <&alert1>;
++                              cooling-device =
++                                      <&cooling_map0 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone2 {
++              polling-delay-passive = <1000>;
++              polling-delay = <5000>;
++              thermal-sensors = <&tmu 2>;
++              status = "disabled";
++
++              trips {
++                      alert2: alert2 {
++                              temperature = <75000>;
++                              hysteresis = <2000>;
++                              type = "passive";
++                      };
++
++                      crit2: crit2 {
++                              temperature = <85000>;
++                              hysteresis = <2000>;
++                              type = "critical";
++                      };
++              };
++
++              cooling-maps {
++                      map0 {
++                              trip = <&alert2>;
++                              cooling-device =
++                                      <&cooling_map0 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone3 {
++              polling-delay-passive = <1000>;
++              polling-delay = <5000>;
++              thermal-sensors = <&tmu 3>;
++              status = "disabled";
++
++              trips {
++                      alert3: alert3 {
++                              temperature = <75000>;
++                              hysteresis = <2000>;
++                              type = "passive";
++                      };
++
++                      crit3: crit3 {
++                              temperature = <85000>;
++                              hysteresis = <2000>;
++                              type = "critical";
++                      };
++              };
++
++              cooling-maps {
++                      map0 {
++                              trip = <&alert3>;
++                              cooling-device =
++                                      <&cooling_map0 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone4 {
++              polling-delay-passive = <1000>;
++              polling-delay = <5000>;
++              thermal-sensors = <&tmu 4>;
++              status = "disabled";
++
++              trips {
++                      alert4: alert4 {
++                              temperature = <75000>;
++                              hysteresis = <2000>;
++                              type = "passive";
++                      };
++
++                      crit4: crit4 {
++                              temperature = <85000>;
++                              hysteresis = <2000>;
++                              type = "critical";
++                      };
++              };
++
++              cooling-maps {
++                      map0 {
++                              trip = <&alert4>;
++                              cooling-device =
++                                      <&cooling_map0 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone5 {
++              polling-delay-passive = <1000>;
++              polling-delay = <5000>;
++              thermal-sensors = <&tmu 5>;
++              status = "disabled";
++
++              trips {
++                      alert5: alert5 {
++                              temperature = <75000>;
++                              hysteresis = <2000>;
++                              type = "passive";
++                      };
++
++                      crit5: crit5 {
++                              temperature = <85000>;
++                              hysteresis = <2000>;
++                              type = "critical";
++                      };
++              };
++
++              cooling-maps {
++                      map0 {
++                              trip = <&alert5>;
++                              cooling-device =
++                                      <&cooling_map0 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone6 {
++              polling-delay-passive = <1000>;
++              polling-delay = <5000>;
++              thermal-sensors = <&tmu 6>;
++              status = "disabled";
++
++              trips {
++                      alert6: alert6 {
++                              temperature = <75000>;
++                              hysteresis = <2000>;
++                              type = "passive";
++                      };
++
++                      crit6: crit6 {
++                              temperature = <85000>;
++                              hysteresis = <2000>;
++                              type = "critical";
++                      };
++              };
++
++              cooling-maps {
++                      map0 {
++                              trip = <&alert6>;
++                              cooling-device =
++                                      <&cooling_map0 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++
++      thermal-zone7 {
++              polling-delay-passive = <1000>;
++              polling-delay = <5000>;
++              thermal-sensors = <&tmu 7>;
++              status = "disabled";
++
++              trips {
++                      alert7: alert7 {
++                              temperature = <75000>;
++                              hysteresis = <2000>;
++                              type = "passive";
++                      };
++
++                      crit7: crit7 {
++                              temperature = <85000>;
++                              hysteresis = <2000>;
++                              type = "critical";
++                      };
++              };
++
++              cooling-maps {
++                      map0 {
++                              trip = <&alert7>;
++                              cooling-device =
++                                      <&cooling_map0 THERMAL_NO_LIMIT
++                                      THERMAL_NO_LIMIT>;
++                      };
++              };
++      };
++};
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0026-arm64-dts-nxp-add-more-thermal-zone-support.patch b/target/linux/layerscape/patches-5.4/302-dts-0026-arm64-dts-nxp-add-more-thermal-zone-support.patch
new file mode 100644 (file)
index 0000000..6eba875
--- /dev/null
@@ -0,0 +1,314 @@
+From 314a3a062e5e8fe76b3c43a8731ffe4bd58bc1be Mon Sep 17 00:00:00 2001
+From: Yuantian Tang <andy.tang@nxp.com>
+Date: Mon, 5 Nov 2018 17:40:20 +0800
+Subject: [PATCH] arm64: dts: nxp: add more thermal zone support
+
+To enable all the supported thermal sensors, add sensor id information
+to thermal zone node.
+Dts for ls1012a, ls1046a, ls1043a, ls1088a are updated.
+
+Signed-off-by: Yuantian Tang <andy.tang@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 39 ++++------------
+ arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 61 ++++++++++++--------------
+ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 57 ++++++++++--------------
+ arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 53 +++++++---------------
+ 4 files changed, 75 insertions(+), 135 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+@@ -28,7 +28,7 @@
+               #address-cells = <1>;
+               #size-cells = <0>;
+-              cpu0: cpu@0 {
++              cooling_map0: cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x0>;
+@@ -100,36 +100,7 @@
+               mask = <0x02>;
+       };
+-      thermal-zones {
+-              cpu_thermal: cpu-thermal {
+-                      polling-delay-passive = <1000>;
+-                      polling-delay = <5000>;
+-                      thermal-sensors = <&tmu 0>;
+-
+-                      trips {
+-                              cpu_alert: cpu-alert {
+-                                      temperature = <85000>;
+-                                      hysteresis = <2000>;
+-                                      type = "passive";
+-                              };
+-
+-                              cpu_crit: cpu-crit {
+-                                      temperature = <95000>;
+-                                      hysteresis = <2000>;
+-                                      type = "critical";
+-                              };
+-                      };
+-
+-                      cooling-maps {
+-                              map0 {
+-                                      trip = <&cpu_alert>;
+-                                      cooling-device =
+-                                              <&cpu0 THERMAL_NO_LIMIT
+-                                              THERMAL_NO_LIMIT>;
+-                              };
+-                      };
+-              };
+-      };
++      #include "fsl-tmu.dtsi"
+       soc {
+               compatible = "simple-bus";
+@@ -572,3 +543,9 @@
+               };
+       };
+ };
++
++&thermal_zones {
++      thermal-zone0 {
++              status = "okay";
++      };
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+@@ -39,7 +39,7 @@
+                *
+                * Currently supported enable-method is psci v0.2
+                */
+-              cpu0: cpu@0 {
++              cooling_map0: cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x0>;
+@@ -148,38 +148,7 @@
+               mask = <0x02>;
+       };
+-      thermal-zones {
+-              cpu_thermal: cpu-thermal {
+-                      polling-delay-passive = <1000>;
+-                      polling-delay = <5000>;
+-
+-                      thermal-sensors = <&tmu 3>;
+-
+-                      trips {
+-                              cpu_alert: cpu-alert {
+-                                      temperature = <85000>;
+-                                      hysteresis = <2000>;
+-                                      type = "passive";
+-                              };
+-                              cpu_crit: cpu-crit {
+-                                      temperature = <95000>;
+-                                      hysteresis = <2000>;
+-                                      type = "critical";
+-                              };
+-                      };
+-
+-                      cooling-maps {
+-                              map0 {
+-                                      trip = <&cpu_alert>;
+-                                      cooling-device =
+-                                              <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+-                              };
+-                      };
+-              };
+-      };
++      #include "fsl-tmu.dtsi"
+       timer {
+               compatible = "arm,armv8-timer";
+@@ -915,3 +884,29 @@
+ #include "qoriq-qman-portals.dtsi"
+ #include "qoriq-bman-portals.dtsi"
++
++&thermal_zones {
++      thermal-zone0 {
++              status = "okay";
++      };
++
++      thermal-zone1 {
++              status = "okay";
++      };
++
++      thermal-zone2 {
++              status = "okay";
++      };
++
++      thermal-zone3 {
++              status = "okay";
++      };
++
++      thermal-zone4 {
++              status = "okay";
++      };
++
++      thermal-zone5 {
++              status = "okay";
++      };
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+@@ -34,7 +34,7 @@
+               #address-cells = <1>;
+               #size-cells = <0>;
+-              cpu0: cpu@0 {
++              cooling_map0: cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       reg = <0x0>;
+@@ -116,38 +116,7 @@
+               mask = <0x02>;
+       };
+-      thermal-zones {
+-              cpu_thermal: cpu-thermal {
+-                      polling-delay-passive = <1000>;
+-                      polling-delay = <5000>;
+-                      thermal-sensors = <&tmu 3>;
+-
+-                      trips {
+-                              cpu_alert: cpu-alert {
+-                                      temperature = <85000>;
+-                                      hysteresis = <2000>;
+-                                      type = "passive";
+-                              };
+-
+-                              cpu_crit: cpu-crit {
+-                                      temperature = <95000>;
+-                                      hysteresis = <2000>;
+-                                      type = "critical";
+-                              };
+-                      };
+-
+-                      cooling-maps {
+-                              map0 {
+-                                      trip = <&cpu_alert>;
+-                                      cooling-device =
+-                                              <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+-                              };
+-                      };
+-              };
+-      };
++      #include "fsl-tmu.dtsi"
+       timer {
+               compatible = "arm,armv8-timer";
+@@ -882,3 +851,25 @@
+ #include "qoriq-qman-portals.dtsi"
+ #include "qoriq-bman-portals.dtsi"
++
++&thermal_zones {
++      thermal-zone0 {
++              status = "okay";
++      };
++
++      thermal-zone1 {
++              status = "okay";
++      };
++
++      thermal-zone2 {
++              status = "okay";
++      };
++
++      thermal-zone3 {
++              status = "okay";
++      };
++
++      thermal-zone4 {
++              status = "okay";
++      };
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+@@ -25,7 +25,7 @@
+               #size-cells = <0>;
+               /* We have 2 clusters having 4 Cortex-A53 cores each */
+-              cpu0: cpu@0 {
++              cooling_map0: cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x0>;
+@@ -61,7 +61,7 @@
+                       #cooling-cells = <2>;
+               };
+-              cpu4: cpu@100 {
++              cooling_map1: cpu4: cpu@100 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x100>;
+@@ -128,42 +128,7 @@
+               };
+       };
+-      thermal-zones {
+-              cpu_thermal: cpu-thermal {
+-                      polling-delay-passive = <1000>;
+-                      polling-delay = <5000>;
+-                      thermal-sensors = <&tmu 0>;
+-
+-                      trips {
+-                              cpu_alert: cpu-alert {
+-                                      temperature = <85000>;
+-                                      hysteresis = <2000>;
+-                                      type = "passive";
+-                              };
+-
+-                              cpu_crit: cpu-crit {
+-                                      temperature = <95000>;
+-                                      hysteresis = <2000>;
+-                                      type = "critical";
+-                              };
+-                      };
+-
+-                      cooling-maps {
+-                              map0 {
+-                                      trip = <&cpu_alert>;
+-                                      cooling-device =
+-                                              <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-                                              <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+-                              };
+-                      };
+-              };
+-      };
++      #include "fsl-tmu.dtsi"
+       timer {
+               compatible = "arm,armv8-timer";
+@@ -879,3 +844,15 @@
+               };
+       };
+ };
++
++#include "fsl-tmu-map1.dtsi"
++
++&thermal_zones {
++      thermal-zone0 {
++              status = "okay";
++      };
++
++      thermal-zone1 {
++              status = "okay";
++      };
++};
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0027-arm64-dts-lx2160a-rdb-Add-Inphi-PHY-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0027-arm64-dts-lx2160a-rdb-Add-Inphi-PHY-node.patch
new file mode 100644 (file)
index 0000000..90f0e3c
--- /dev/null
@@ -0,0 +1,40 @@
+From 7ff4d2213c5b21008bebf43ae5a60b4275f91c55 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Mon, 29 Oct 2018 18:41:07 +0200
+Subject: [PATCH] arm64: dts: lx2160a-rdb: Add Inphi PHY node
+
+DPMAC5 and DPMAC6 are connected to 25G Inphi PHY
+
+Signed-off-by: Vicentiu Galanopulo <vicentiu.galanopulo@nxp.com>
+Signed-off-by: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
+@@ -175,6 +175,23 @@
+       };
+ };
++&emdio2 {
++      inphi_phy: emdio2_phy@0 {
++              compatible = "ethernet-phy-ieee802.3-c45";
++              reg = <0x0>;
++              interrupts = <0 9 IRQ_TYPE_EDGE_FALLING>,
++                      <0 10 IRQ_TYPE_EDGE_FALLING>;
++      };
++};
++
++&dpmac5 {
++      phy-handle = <&inphi_phy>;
++};
++
++&dpmac6 {
++      phy-handle = <&inphi_phy>;
++};
++
+ &dpmac17 {
+       phy-handle = <&rgmii_phy1>;
+       phy-connection-type = "rgmii-id";
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0028-arm64-dts-lx2160a-rdb-Add-Aquantia-PHY-nodes.patch b/target/linux/layerscape/patches-5.4/302-dts-0028-arm64-dts-lx2160a-rdb-Add-Aquantia-PHY-nodes.patch
new file mode 100644 (file)
index 0000000..f2d4f49
--- /dev/null
@@ -0,0 +1,51 @@
+From 917e2edbf55e5bc6c98802a610d8b7c05c4e9c78 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Mon, 29 Oct 2018 18:54:05 +0200
+Subject: [PATCH] arm64: dts: lx2160a-rdb: Add Aquantia PHY nodes
+
+DPMAC3 and DPMAC4 are connected to 10G Aquantia PHYs
+
+Signed-off-by: Catalin Neacsu <valentin-catalin.neacsu@nxp.com>
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
+@@ -173,6 +173,18 @@
+               reg = <0x2>;
+               /* Poll mode - no "interrupts" property defined */
+       };
++      aquantia_phy1: ethernet-phy@4 {
++              /* AQR107 PHY - "compatible" property not strictly needed */
++              compatible = "ethernet-phy-ieee802.3-c45";
++              reg = <0x4>;
++              /* Poll mode - no "interrupts" property defined */
++      };
++      aquantia_phy2: ethernet-phy@5 {
++              /* AQR107 PHY - "compatible" property not strictly needed */
++              compatible = "ethernet-phy-ieee802.3-c45";
++              reg = <0x5>;
++              /* Poll mode - no "interrupts" property defined */
++      };
+ };
+ &emdio2 {
+@@ -184,6 +196,16 @@
+       };
+ };
++&dpmac3 {
++      phy-handle = <&aquantia_phy1>;
++      phy-connection-type = "xgmii";
++};
++
++&dpmac4 {
++      phy-handle = <&aquantia_phy2>;
++      phy-connection-type = "xgmii";
++};
++
+ &dpmac5 {
+       phy-handle = <&inphi_phy>;
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0029-arm64-dts-lx2160-Add-all-pcs-mdio-definitions-accord.patch b/target/linux/layerscape/patches-5.4/302-dts-0029-arm64-dts-lx2160-Add-all-pcs-mdio-definitions-accord.patch
new file mode 100644 (file)
index 0000000..de19975
--- /dev/null
@@ -0,0 +1,107 @@
+From 39c8c9b6e4db9694935fe4a856ea66ff36ace7d0 Mon Sep 17 00:00:00 2001
+From: Florinel Iordache <florinel.iordache@nxp.com>
+Date: Tue, 30 Oct 2018 09:42:39 +0200
+Subject: [PATCH] arm64: dts: lx2160: Add all pcs mdio definitions according to
+ RM
+
+This change is required in preparation for adding 40GBase-KR support in DTS for LX2160
+
+Signed-off-by: Florinel Iordache <florinel.iordache@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 85 ++++++++++++++++++++++++++
+ 1 file changed, 85 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -500,6 +500,91 @@
+                       #size-cells = <0>;
+               };
++              pcs_mdio1: mdio@0x8c07000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c07000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio2: mdio@0x8c0b000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c0b000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio3: mdio@0x8c0f000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c0f000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio4: mdio@0x8c13000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c13000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio5: mdio@0x8c17000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c17000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio6: mdio@0x8c1b000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c1b000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio7: mdio@0x8c1f000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c1f000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              pcs_mdio8: mdio@0x8c23000 {
++                      compatible = "fsl,fman-memac-mdio";
++                      reg = <0x0 0x8c23000 0x0 0x1000>;
++                      device_type = "mdio";
++                      little-endian;
++
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              serdes1: serdes@1ea0000 {
++                              reg = <0x0 0x1ea0000 0 0x00002000>;
++                              compatible = "fsl,serdes-28g";
++              };
++
+               i2c0: i2c@2000000 {
+                       compatible = "fsl,vf610-i2c";
+                       #address-cells = <1>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0030-arm64-dts-lx2160-PCS-PHY-definitions-for-10GBase-KR-.patch b/target/linux/layerscape/patches-5.4/302-dts-0030-arm64-dts-lx2160-PCS-PHY-definitions-for-10GBase-KR-.patch
new file mode 100644 (file)
index 0000000..22b2b64
--- /dev/null
@@ -0,0 +1,57 @@
+From c1619d9de2da093a585426e9cef353ca1789236d Mon Sep 17 00:00:00 2001
+From: Florinel Iordache <florinel.iordache@nxp.com>
+Date: Mon, 5 Nov 2018 17:02:19 +0200
+Subject: [PATCH] arm64: dts: lx2160: PCS PHY definitions for 10GBase-KR and
+ 40GBase-KR backplane modes
+
+Signed-off-by: Florinel Iordache <florinel.iordache@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts | 40 +++++++++++++++++++++++
+ 1 file changed, 40 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
+@@ -162,3 +162,43 @@
+ &usb1 {
+       status = "okay";
+ };
++
++&pcs_mdio1 {
++      pcs_phy1: ethernet-phy@0 {
++              compatible = "ethernet-phy-ieee802.3-c45";
++              backplane-mode = "40gbase-kr";
++              reg = <0x0>;
++              fsl,lane-handle = <&serdes1>;
++              fsl,lane-reg = <0xF00 0xE00 0xD00 0xC00>; /* lanes H, G, F, E */
++      };
++};
++
++&pcs_mdio2 {
++      pcs_phy2: ethernet-phy@0 {
++              compatible = "ethernet-phy-ieee802.3-c45";
++              backplane-mode = "40gbase-kr";
++              reg = <0x0>;
++              fsl,lane-handle = <&serdes1>;
++              fsl,lane-reg = <0xB00 0xA00 0x900 0x800>; /* lanes D, C, B, A */
++      };
++};
++
++&pcs_mdio3 {
++      pcs_phy3: ethernet-phy@0 {
++              compatible = "ethernet-phy-ieee802.3-c45";
++              backplane-mode = "10gbase-kr";
++              reg = <0x0>;
++              fsl,lane-handle = <&serdes1>;
++              fsl,lane-reg = <0xF00 0x100>; /* lane H */
++      };
++};
++
++&pcs_mdio4 {
++      pcs_phy4: ethernet-phy@0 {
++              compatible = "ethernet-phy-ieee802.3-c45";
++              backplane-mode = "10gbase-kr";
++              reg = <0x0>;
++              fsl,lane-handle = <&serdes1>;
++              fsl,lane-reg = <0xE00 0x100>; /* lane G */
++      };
++};
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0031-arm64-dts-lx2160-DPMAC-connections-to-backplane-PHYs.patch b/target/linux/layerscape/patches-5.4/302-dts-0031-arm64-dts-lx2160-DPMAC-connections-to-backplane-PHYs.patch
new file mode 100644 (file)
index 0000000..d054745
--- /dev/null
@@ -0,0 +1,39 @@
+From 01af235657e4d8f5f87b5e06bcf42baf53e1ff8d Mon Sep 17 00:00:00 2001
+From: Florinel Iordache <florinel.iordache@nxp.com>
+Date: Mon, 5 Nov 2018 17:03:04 +0200
+Subject: [PATCH] arm64: dts: lx2160: DPMAC connections to backplane PHYs
+ example
+
+This is an example of device tree nodes required to enable 10GBase-KR and 40GBase-KR on LX2160
+
+Signed-off-by: Florinel Iordache <florinel.iordache@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
+@@ -202,3 +202,23 @@
+               fsl,lane-reg = <0xE00 0x100>; /* lane G */
+       };
+ };
++
++/* Update DPMAC connections to 40G backplane PHYs
++ * &dpmac1 {
++ *    phy-handle = <&pcs_phy1>;
++ * };
++ * 
++ * &dpmac2 {
++ *    phy-handle = <&pcs_phy2>;
++ * };
++ */
++
++/* Update DPMAC connections to 10G backplane PHYs
++ * &dpmac3 {
++ *    phy-handle = <&pcs_phy3>;
++ * };
++ * 
++ * &dpmac4 {
++ *    phy-handle = <&pcs_phy4>;
++ * };
++ */
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0032-arm64-dts-Added-endianness-information-to-dts-serdes.patch b/target/linux/layerscape/patches-5.4/302-dts-0032-arm64-dts-Added-endianness-information-to-dts-serdes.patch
new file mode 100644 (file)
index 0000000..2552506
--- /dev/null
@@ -0,0 +1,53 @@
+From d783144d6738af1d2ef3a91ef3cb2ef8529bb041 Mon Sep 17 00:00:00 2001
+From: Florinel Iordache <florinel.iordache@nxp.com>
+Date: Mon, 5 Nov 2018 17:04:05 +0200
+Subject: [PATCH] arm64: dts: Added endianness information to dts serdes node
+
+This change is required to specify that serdes HW peripheral is little-endian.
+
+Signed-off-by: Florinel Iordache <florinel.iordache@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 3 ++-
+ arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 3 ++-
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 3 ++-
+ 3 files changed, 6 insertions(+), 3 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+@@ -184,8 +184,9 @@
+               };
+               serdes1: serdes@1ea0000 {
+-                              reg = <0x0 0x1ea0000 0 0x00002000>;
+                               compatible = "fsl,serdes-10g";
++                              reg = <0x0 0x1ea0000 0 0x00002000>;
++                              little-endian;
+               };
+               tmu: tmu@1f80000 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+@@ -834,8 +834,9 @@
+               };
+               serdes1: serdes@1ea0000 {
+-                              reg = <0x0 0x1ea0000 0 0x00002000>;
+                               compatible = "fsl,serdes-10g";
++                              reg = <0x0 0x1ea0000 0 0x00002000>;
++                              little-endian;
+               };
+               ccn@4000000 {
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -581,8 +581,9 @@
+               };
+               serdes1: serdes@1ea0000 {
+-                              reg = <0x0 0x1ea0000 0 0x00002000>;
+                               compatible = "fsl,serdes-28g";
++                              reg = <0x0 0x1ea0000 0 0x00002000>;
++                              little-endian;
+               };
+               i2c0: i2c@2000000 {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0033-arm64-dts-freescale-lx2160a-add-pcie-DT-nodes.patch b/target/linux/layerscape/patches-5.4/302-dts-0033-arm64-dts-freescale-lx2160a-add-pcie-DT-nodes.patch
new file mode 100644 (file)
index 0000000..26d484d
--- /dev/null
@@ -0,0 +1,183 @@
+From 86e03654997db1b70e71f717ab3e74b1df2f402c Mon Sep 17 00:00:00 2001
+From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Date: Thu, 13 Jul 2017 18:28:27 +0800
+Subject: [PATCH] arm64: dts: freescale: lx2160a: add pcie DT nodes
+
+The LX2160A integrated 6 PCIe Gen4 controllers.
+
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 162 +++++++++++++++++++++++++
+ 1 file changed, 162 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -903,6 +903,168 @@
+                       status = "disabled";
+               };
++              pcie@3400000 {
++                      compatible = "fsl,lx2160a-pcie";
++                      reg = <0x00 0x03400000 0x0 0x00100000   /* controller registers */
++                             0x80 0x00000000 0x0 0x00001000>; /* configuration space */
++                      reg-names = "csr_axi_slave", "config_axi_slave";
++                      interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>, /* AER interrupt */
++                                   <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>, /* PME interrupt */
++                                   <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; /* controller interrupt */
++                      interrupt-names = "aer", "pme", "intr";
++                      #address-cells = <3>;
++                      #size-cells = <2>;
++                      device_type = "pci";
++                      dma-coherent;
++                      apio-wins = <8>;
++                      ppio-wins = <8>;
++                      bus-range = <0x0 0xff>;
++                      ranges = <0x82000000 0x0 0x40000000 0x80 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
++                      msi-parent = <&its>;
++                      #interrupt-cells = <1>;
++                      interrupt-map-mask = <0 0 0 7>;
++                      interrupt-map = <0000 0 0 1 &gic 0 0 GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 2 &gic 0 0 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 3 &gic 0 0 GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 4 &gic 0 0 GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              pcie@3500000 {
++                      compatible = "fsl,lx2160a-pcie";
++                      reg = <0x00 0x03500000 0x0 0x00100000   /* controller registers */
++                             0x88 0x00000000 0x0 0x00001000>; /* configuration space */
++                      reg-names = "csr_axi_slave", "config_axi_slave";
++                      interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>, /* AER interrupt */
++                                   <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>, /* PME interrupt */
++                                   <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>; /* controller interrupt */
++                      interrupt-names = "aer", "pme", "intr";
++                      #address-cells = <3>;
++                      #size-cells = <2>;
++                      device_type = "pci";
++                      dma-coherent;
++                      apio-wins = <8>;
++                      ppio-wins = <8>;
++                      bus-range = <0x0 0xff>;
++                      ranges = <0x82000000 0x0 0x40000000 0x88 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
++                      msi-parent = <&its>;
++                      #interrupt-cells = <1>;
++                      interrupt-map-mask = <0 0 0 7>;
++                      interrupt-map = <0000 0 0 1 &gic 0 0 GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 2 &gic 0 0 GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 3 &gic 0 0 GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 4 &gic 0 0 GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              pcie@3600000 {
++                      compatible = "fsl,lx2160a-pcie";
++                      reg = <0x00 0x03600000 0x0 0x00100000   /* controller registers */
++                             0x90 0x00000000 0x0 0x00001000>; /* configuration space */
++                      reg-names = "csr_axi_slave", "config_axi_slave";
++                      interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>, /* AER interrupt */
++                                   <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>, /* PME interrupt */
++                                   <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>; /* controller interrupt */
++                      interrupt-names = "aer", "pme", "intr";
++                      #address-cells = <3>;
++                      #size-cells = <2>;
++                      device_type = "pci";
++                      dma-coherent;
++                      apio-wins = <8>;
++                      ppio-wins = <8>;
++                      bus-range = <0x0 0xff>;
++                      ranges = <0x82000000 0x0 0x40000000 0x90 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
++                      msi-parent = <&its>;
++                      #interrupt-cells = <1>;
++                      interrupt-map-mask = <0 0 0 7>;
++                      interrupt-map = <0000 0 0 1 &gic 0 0 GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 2 &gic 0 0 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 3 &gic 0 0 GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 4 &gic 0 0 GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              pcie@3700000 {
++                      compatible = "fsl,lx2160a-pcie";
++                      reg = <0x00 0x03700000 0x0 0x00100000   /* controller registers */
++                             0x98 0x00000000 0x0 0x00001000>; /* configuration space */
++                      reg-names = "csr_axi_slave", "config_axi_slave";
++                      interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, /* AER interrupt */
++                                   <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, /* PME interrupt */
++                                   <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>; /* controller interrupt */
++                      interrupt-names = "aer", "pme", "intr";
++                      #address-cells = <3>;
++                      #size-cells = <2>;
++                      device_type = "pci";
++                      dma-coherent;
++                      apio-wins = <8>;
++                      ppio-wins = <8>;
++                      bus-range = <0x0 0xff>;
++                      ranges = <0x82000000 0x0 0x40000000 0x98 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
++                      msi-parent = <&its>;
++                      #interrupt-cells = <1>;
++                      interrupt-map-mask = <0 0 0 7>;
++                      interrupt-map = <0000 0 0 1 &gic 0 0 GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 2 &gic 0 0 GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 3 &gic 0 0 GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 4 &gic 0 0 GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              pcie@3800000 {
++                      compatible = "fsl,lx2160a-pcie";
++                      reg = <0x00 0x03800000 0x0 0x00100000   /* controller registers */
++                             0xa0 0x00000000 0x0 0x00001000>; /* configuration space */
++                      reg-names = "csr_axi_slave", "config_axi_slave";
++                      interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>, /* AER interrupt */
++                                   <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>, /* PME interrupt */
++                                   <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>; /* controller interrupt */
++                      interrupt-names = "aer", "pme", "intr";
++                      #address-cells = <3>;
++                      #size-cells = <2>;
++                      device_type = "pci";
++                      dma-coherent;
++                      apio-wins = <8>;
++                      ppio-wins = <8>;
++                      bus-range = <0x0 0xff>;
++                      ranges = <0x82000000 0x0 0x40000000 0xa0 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
++                      msi-parent = <&its>;
++                      #interrupt-cells = <1>;
++                      interrupt-map-mask = <0 0 0 7>;
++                      interrupt-map = <0000 0 0 1 &gic 0 0 GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 2 &gic 0 0 GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 3 &gic 0 0 GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 4 &gic 0 0 GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              pcie@3900000 {
++                      compatible = "fsl,lx2160a-pcie";
++                      reg = <0x00 0x03900000 0x0 0x00100000   /* controller registers */
++                             0xa8 0x00000000 0x0 0x00001000>; /* configuration space */
++                      reg-names = "csr_axi_slave", "config_axi_slave";
++                      interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>, /* AER interrupt */
++                                   <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>, /* PME interrupt */
++                                   <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>; /* controller interrupt */
++                      interrupt-names = "aer", "pme", "intr";
++                      #address-cells = <3>;
++                      #size-cells = <2>;
++                      device_type = "pci";
++                      dma-coherent;
++                      apio-wins = <8>;
++                      ppio-wins = <8>;
++                      bus-range = <0x0 0xff>;
++                      ranges = <0x82000000 0x0 0x40000000 0xa8 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
++                      msi-parent = <&its>;
++                      #interrupt-cells = <1>;
++                      interrupt-map-mask = <0 0 0 7>;
++                      interrupt-map = <0000 0 0 1 &gic 0 0 GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 2 &gic 0 0 GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 3 &gic 0 0 GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 4 &gic 0 0 GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
+               smmu: iommu@5000000 {
+                       compatible = "arm,mmu-500";
+                       reg = <0 0x5000000 0 0x800000>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0034-arm64-dts-freescale-lx2160a-Inphi-in112525_s03-mdio-.patch b/target/linux/layerscape/patches-5.4/302-dts-0034-arm64-dts-freescale-lx2160a-Inphi-in112525_s03-mdio-.patch
new file mode 100644 (file)
index 0000000..7e3cdb6
--- /dev/null
@@ -0,0 +1,29 @@
+From fa7b2d215b494f912b591f28c1205593bccfc2cc Mon Sep 17 00:00:00 2001
+From: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
+Date: Sun, 16 Dec 2018 23:05:12 +0200
+Subject: [PATCH] arm64: dts: freescale: lx2160a: Inphi in112525_s03 mdio node
+
+Add Inphi retimer phyid in the mdio node, solving the probe issue
+for this non-standard clause-45 device.
+
+Signed-off-by: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
+@@ -188,11 +188,9 @@
+ };
+ &emdio2 {
+-      inphi_phy: emdio2_phy@0 {
+-              compatible = "ethernet-phy-ieee802.3-c45";
++      inphi_phy: ethernet-phy@0 {
++              compatible = "ethernet-phy-id0210.7440";
+               reg = <0x0>;
+-              interrupts = <0 9 IRQ_TYPE_EDGE_FALLING>,
+-                      <0 10 IRQ_TYPE_EDGE_FALLING>;
+       };
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0035-arm64-dts-lx2160a-add-optee-tz-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0035-arm64-dts-lx2160a-add-optee-tz-node.patch
new file mode 100644 (file)
index 0000000..da82d44
--- /dev/null
@@ -0,0 +1,24 @@
+From 9ab6cc70cd84ca4a140b30b8a0a2371a3585a72a Mon Sep 17 00:00:00 2001
+From: Pankaj Gupta <pankaj.gupta@nxp.com>
+Date: Tue, 27 Nov 2018 15:33:08 +0530
+Subject: [PATCH] arm64: dts: lx2160a: add optee-tz node
+
+Signed-off-by: Pankaj Gupta <pankaj.gupta@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -1287,4 +1287,11 @@
+                       };
+               };
+       };
++
++      firmware {
++              optee {
++                      compatible = "linaro,optee-tz";
++                      method = "smc";
++              };
++      };
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0036-arm64-dts-ls104x-constrain-sata-dma-address-size.patch b/target/linux/layerscape/patches-5.4/302-dts-0036-arm64-dts-ls104x-constrain-sata-dma-address-size.patch
new file mode 100644 (file)
index 0000000..00bda3d
--- /dev/null
@@ -0,0 +1,86 @@
+From 4a7dcac3fd18b182f882b65161267612713f72dc Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 11 Dec 2018 13:32:31 +0200
+Subject: [PATCH] arm64: dts: ls104x: constrain sata dma address size
+
+Limit the dma mask size for sata to 40 bits to match the actual address
+size generated towards the interconnect. Re-use the already existing
+auxiliary simple bus meant for usb but drop the usb reference from the
+node name.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 18 +++++++++---------
+ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 18 +++++++++---------
+ 2 files changed, 18 insertions(+), 18 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+@@ -695,7 +695,7 @@
+                                <&clockgen 4 0>;
+               };
+-              usb_aux_bus: usb_aux_bus {
++              aux_bus: aux_bus {
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       compatible = "simple-bus";
+@@ -740,15 +740,15 @@
+                               snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                               configure-gfladj;
+                       };
+-              };
+-              sata: sata@3200000 {
+-                      compatible = "fsl,ls1043a-ahci";
+-                      reg = <0x0 0x3200000 0x0 0x10000>,
+-                              <0x0 0x20140520 0x0 0x4>;
+-                      reg-names = "ahci", "sata-ecc";
+-                      interrupts = <0 69 0x4>;
+-                      clocks = <&clockgen 4 0>;
++                      sata: sata@3200000 {
++                              compatible = "fsl,ls1043a-ahci";
++                              reg = <0x0 0x3200000 0x0 0x10000>,
++                                      <0x0 0x20140520 0x0 0x4>;
++                              reg-names = "ahci", "sata-ecc";
++                              interrupts = <0 69 0x4>;
++                              clocks = <&clockgen 4 0>;
++                      };
+               };
+               msi1: msi-controller1@1571000 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+@@ -593,7 +593,7 @@
+                                <&clockgen 4 1>;
+               };
+-              usb_aux_bus: usb_aux_bus {
++              aux_bus: aux_bus {
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       compatible = "simple-bus";
+@@ -635,15 +635,15 @@
+                               usb3-lpm-capable;
+                               snps,dis-u1u2-when-u3-quirk;
+                       };
+-              };
+-              sata: sata@3200000 {
+-                      compatible = "fsl,ls1046a-ahci";
+-                      reg = <0x0 0x3200000 0x0 0x10000>,
+-                              <0x0 0x20140520 0x0 0x4>;
+-                      reg-names = "ahci", "sata-ecc";
+-                      interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+-                      clocks = <&clockgen 4 1>;
++                      sata: sata@3200000 {
++                              compatible = "fsl,ls1046a-ahci";
++                              reg = <0x0 0x3200000 0x0 0x10000>,
++                                      <0x0 0x20140520 0x0 0x4>;
++                              reg-names = "ahci", "sata-ecc";
++                              interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
++                              clocks = <&clockgen 4 1>;
++                      };
+               };
+               msi1: msi-controller@1580000 {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0037-arm64-dts-lx2160a-qds-add-sata-node-support.patch b/target/linux/layerscape/patches-5.4/302-dts-0037-arm64-dts-lx2160a-qds-add-sata-node-support.patch
new file mode 100644 (file)
index 0000000..b8a4483
--- /dev/null
@@ -0,0 +1,37 @@
+From 4551b9c547f7bf7b40d83f8762c77cee0041f5eb Mon Sep 17 00:00:00 2001
+From: Peng Ma <peng.ma@nxp.com>
+Date: Mon, 14 Jan 2019 08:26:40 +0000
+Subject: [PATCH] arm64: dts: lx2160a-qds: add sata node support
+
+Add sata node support and Enable sata support
+
+Signed-off-by: Peng Ma <peng.ma@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
+@@ -203,6 +203,22 @@
+       };
+ };
++&sata0 {
++      status = "okay";
++};
++
++&sata1 {
++      status = "okay";
++};
++
++&sata2 {
++      status = "okay";
++};
++
++&sata3 {
++      status = "okay";
++};
++
+ /* Update DPMAC connections to 40G backplane PHYs
+  * &dpmac1 {
+  *    phy-handle = <&pcs_phy1>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0038-arm64-dts-ls1012a-use-phy-handle-to-handle-phy-param.patch b/target/linux/layerscape/patches-5.4/302-dts-0038-arm64-dts-ls1012a-use-phy-handle-to-handle-phy-param.patch
new file mode 100644 (file)
index 0000000..f6e7bf0
--- /dev/null
@@ -0,0 +1,242 @@
+From 203a34f815c7e9320140bb2259ae5884575f0658 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Tue, 20 Nov 2018 21:52:03 +0530
+Subject: [PATCH] arm64: dts: ls1012a: use phy-handle to handle phy params
+
+Replace properties "fsl,gemac-phy-id" and "fsl,pfe-phy-if-flags"
+and use phy-handle instead.
+Create mdio node with phy-handles defining PHYs available on the
+mdio bus.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ .../boot/dts/freescale/fsl-ls1012a-2g5rdb.dts      | 25 +++++++++++++---------
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts | 23 +++++++++++---------
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts | 23 +++++++++++---------
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts  | 25 +++++++++++++---------
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts  | 22 ++++++++++---------
+ 5 files changed, 68 insertions(+), 50 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-2g5rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-2g5rdb.dts
+@@ -58,14 +58,9 @@
+               #size-cells = <0>;
+               reg = <0x0>;    /* GEM_ID */
+               fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
+-              fsl,gemac-phy-id = <0x1>;       /* PHY_ID */
+               fsl,mdio-mux-val = <0x0>;
+               phy-mode = "sgmii-2500";
+-              fsl,pfe-phy-if-flags = <0x0>;
+-
+-              mdio@0 {
+-                      reg = <0x1>; /* enabled/disabled */
+-              };
++              phy-handle = <&sgmii_phy1>;
+       };
+       ethernet@1 {
+@@ -74,13 +69,23 @@
+               #size-cells = <0>;
+               reg = <0x1>;    /* GEM_ID */
+               fsl,gemac-bus-id = < 0x0>;      /* BUS_ID */
+-              fsl,gemac-phy-id = < 0x2>;      /* PHY_ID */
+               fsl,mdio-mux-val = <0x0>;
+               phy-mode = "sgmii-2500";
+-              fsl,pfe-phy-if-flags = <0x0>;
++              phy-handle = <&sgmii_phy2>;
++      };
++
++      mdio@0 {
++              #address-cells = <1>;
++              #size-cells = <0>;
++
++              sgmii_phy1: ethernet-phy@1 {
++                      compatible = "ethernet-phy-ieee802.3-c45";
++                      reg = <0x1>;
++              };
+-              mdio@0 {
+-                      reg = <0x0>; /* enabled/disabled */
++              sgmii_phy2: ethernet-phy@2 {
++                      compatible = "ethernet-phy-ieee802.3-c45";
++                      reg = <0x2>;
+               };
+       };
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts
+@@ -90,14 +90,9 @@
+               #size-cells = <0>;
+               reg = <0x0>;    /* GEM_ID */
+               fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
+-              fsl,gemac-phy-id = <0x2>;       /* PHY_ID */
+               fsl,mdio-mux-val = <0x0>;
+               phy-mode = "sgmii";
+-              fsl,pfe-phy-if-flags = <0x0>;
+-
+-              mdio@0 {
+-                      reg = <0x1>; /* enabled/disabled */
+-              };
++              phy-handle = <&sgmii_phy1>;
+       };
+       ethernet@1 {
+@@ -106,13 +101,21 @@
+               #size-cells = <0>;
+               reg = <0x1>;    /* GEM_ID */
+               fsl,gemac-bus-id = <0x1>;       /* BUS_ID */
+-              fsl,gemac-phy-id = <0x1>;       /* PHY_ID */
+               fsl,mdio-mux-val = <0x0>;
+               phy-mode = "sgmii";
+-              fsl,pfe-phy-if-flags = <0x0>;
++              phy-handle = <&sgmii_phy2>;
++      };
++
++      mdio@0 {
++              #address-cells = <1>;
++              #size-cells = <0>;
++
++              sgmii_phy1: ethernet-phy@2 {
++                      reg = <0x2>;
++              };
+-              mdio@0 {
+-                      reg = <0x0>; /* enabled/disabled */
++              sgmii_phy2: ethernet-phy@1 {
++                      reg = <0x1>;
+               };
+       };
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts
+@@ -111,14 +111,9 @@
+               #size-cells = <0>;
+               reg = <0x0>;    /* GEM_ID */
+               fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
+-              fsl,gemac-phy-id = <0x2>;       /* PHY_ID */
+               fsl,mdio-mux-val = <0x0>;
+               phy-mode = "sgmii";
+-              fsl,pfe-phy-if-flags = <0x0>;
+-
+-              mdio@0 {
+-                      reg = <0x1>; /* enabled/disabled */
+-              };
++              phy-handle = <&sgmii_phy1>;
+       };
+       ethernet@1 {
+@@ -127,13 +122,21 @@
+               #size-cells = <0>;
+               reg = <0x1>;    /* GEM_ID */
+               fsl,gemac-bus-id = <0x1>;       /* BUS_ID */
+-              fsl,gemac-phy-id = <0x1>;       /* PHY_ID */
+               fsl,mdio-mux-val = <0x0>;
+               phy-mode = "sgmii";
+-              fsl,pfe-phy-if-flags = <0x0>;
++              phy-handle = <&sgmii_phy2>;
++      };
++
++      mdio@0 {
++              #address-cells = <1>;
++              #size-cells = <0>;
++
++              sgmii_phy1: ethernet-phy@2 {
++                      reg = <0x2>;
++              };
+-              mdio@0 {
+-                      reg = <0x0>; /* enabled/disabled */
++              sgmii_phy2: ethernet-phy@1 {
++                      reg = <0x1>;
+               };
+       };
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts
+@@ -148,14 +148,9 @@
+               #size-cells = <0>;
+               reg = <0x0>;    /* GEM_ID */
+               fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
+-              fsl,gemac-phy-id = <0x1>;       /* PHY_ID */
+               fsl,mdio-mux-val = <0x2>;
+               phy-mode = "sgmii-2500";
+-              fsl,pfe-phy-if-flags = <0x0>;
+-
+-              mdio@0 {
+-                      reg = <0x1>; /* enabled/disabled */
+-              };
++              phy-handle = <&sgmii_phy1>;
+       };
+       ethernet@1 {
+@@ -164,13 +159,23 @@
+               #size-cells = <0>;
+               reg = <0x1>;    /* GEM_ID */
+               fsl,gemac-bus-id = <0x1>;       /* BUS_ID */
+-              fsl,gemac-phy-id = <0x2>;       /* PHY_ID */
+               fsl,mdio-mux-val = <0x3>;
+               phy-mode = "sgmii-2500";
+-              fsl,pfe-phy-if-flags = <0x0>;
++              phy-handle = <&sgmii_phy2>;
++      };
++
++      mdio@0 {
++              #address-cells = <1>;
++              #size-cells = <0>;
++
++              sgmii_phy1: ethernet-phy@1 {
++                      compatible = "ethernet-phy-ieee802.3-c45";
++                      reg = <0x1>;
++              };
+-              mdio@0 {
+-                      reg = <0x0>; /* enabled/disabled */
++              sgmii_phy2: ethernet-phy@2 {
++                      compatible = "ethernet-phy-ieee802.3-c45";
++                      reg = <0x2>;
+               };
+       };
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
+@@ -59,14 +59,9 @@
+               #size-cells = <0>;
+               reg = <0x0>;    /* GEM_ID */
+               fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
+-              fsl,gemac-phy-id = <0x2>;       /* PHY_ID */
+               fsl,mdio-mux-val = <0x0>;
+               phy-mode = "sgmii";
+-              fsl,pfe-phy-if-flags = <0x0>;
+-
+-              mdio@0 {
+-                      reg = <0x1>; /* enabled/disabled */
+-              };
++              phy-handle = <&sgmii_phy>;
+       };
+       ethernet@1 {
+@@ -75,13 +70,20 @@
+               #size-cells = <0>;
+               reg = <0x1>;    /* GEM_ID */
+               fsl,gemac-bus-id = < 0x1 >;     /* BUS_ID */
+-              fsl,gemac-phy-id = < 0x1 >;     /* PHY_ID */
+               fsl,mdio-mux-val = <0x0>;
+               phy-mode = "rgmii-txid";
+-              fsl,pfe-phy-if-flags = <0x0>;
++              phy-handle = <&rgmii_phy>;
++      };
++      mdio@0 {
++              #address-cells = <1>;
++              #size-cells = <0>;
++
++              sgmii_phy: ethernet-phy@2 {
++                      reg = <0x2>;
++              };
+-              mdio@0 {
+-                      reg = <0x0>; /* enabled/disabled */
++              rgmii_phy: ethernet-phy@1 {
++                      reg = <0x1>;
+               };
+       };
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0039-arm64-dts-ls1012a-remove-unused-gemac-bus-id.patch b/target/linux/layerscape/patches-5.4/302-dts-0039-arm64-dts-ls1012a-remove-unused-gemac-bus-id.patch
new file mode 100644 (file)
index 0000000..aaac126
--- /dev/null
@@ -0,0 +1,98 @@
+From 4ae484235c6b0994e223e802b7fc465ce3b8c4ba Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Thu, 3 Jan 2019 11:07:24 +0530
+Subject: [PATCH] arm64: dts: ls1012a: remove unused gemac-bus-id
+
+gemac-bus-id is unused property and is removed.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-2g5rdb.dts | 2 --
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts   | 2 --
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts   | 1 -
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts    | 2 --
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts    | 2 --
+ 5 files changed, 9 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-2g5rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-2g5rdb.dts
+@@ -57,7 +57,6 @@
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x0>;    /* GEM_ID */
+-              fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
+               fsl,mdio-mux-val = <0x0>;
+               phy-mode = "sgmii-2500";
+               phy-handle = <&sgmii_phy1>;
+@@ -68,7 +67,6 @@
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x1>;    /* GEM_ID */
+-              fsl,gemac-bus-id = < 0x0>;      /* BUS_ID */
+               fsl,mdio-mux-val = <0x0>;
+               phy-mode = "sgmii-2500";
+               phy-handle = <&sgmii_phy2>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts
+@@ -89,7 +89,6 @@
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x0>;    /* GEM_ID */
+-              fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
+               fsl,mdio-mux-val = <0x0>;
+               phy-mode = "sgmii";
+               phy-handle = <&sgmii_phy1>;
+@@ -100,7 +99,6 @@
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x1>;    /* GEM_ID */
+-              fsl,gemac-bus-id = <0x1>;       /* BUS_ID */
+               fsl,mdio-mux-val = <0x0>;
+               phy-mode = "sgmii";
+               phy-handle = <&sgmii_phy2>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts
+@@ -121,7 +121,6 @@
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x1>;    /* GEM_ID */
+-              fsl,gemac-bus-id = <0x1>;       /* BUS_ID */
+               fsl,mdio-mux-val = <0x0>;
+               phy-mode = "sgmii";
+               phy-handle = <&sgmii_phy2>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts
+@@ -147,7 +147,6 @@
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x0>;    /* GEM_ID */
+-              fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
+               fsl,mdio-mux-val = <0x2>;
+               phy-mode = "sgmii-2500";
+               phy-handle = <&sgmii_phy1>;
+@@ -158,7 +157,6 @@
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x1>;    /* GEM_ID */
+-              fsl,gemac-bus-id = <0x1>;       /* BUS_ID */
+               fsl,mdio-mux-val = <0x3>;
+               phy-mode = "sgmii-2500";
+               phy-handle = <&sgmii_phy2>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
+@@ -58,7 +58,6 @@
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x0>;    /* GEM_ID */
+-              fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
+               fsl,mdio-mux-val = <0x0>;
+               phy-mode = "sgmii";
+               phy-handle = <&sgmii_phy>;
+@@ -69,7 +68,6 @@
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x1>;    /* GEM_ID */
+-              fsl,gemac-bus-id = < 0x1 >;     /* BUS_ID */
+               fsl,mdio-mux-val = <0x0>;
+               phy-mode = "rgmii-txid";
+               phy-handle = <&rgmii_phy>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0040-arm64-dts-ls1012a-reorganize-pfe_mac-nodes.patch b/target/linux/layerscape/patches-5.4/302-dts-0040-arm64-dts-ls1012a-reorganize-pfe_mac-nodes.patch
new file mode 100644 (file)
index 0000000..e410c20
--- /dev/null
@@ -0,0 +1,132 @@
+From 4ed0fefb58b5788368fea2c69d646ee4f2e9e012 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Mon, 10 Dec 2018 10:03:51 +0530
+Subject: [PATCH] arm64: dts: ls1012a: reorganize pfe_mac nodes
+
+To keep platform specific properties in the platform dts files,
+remove pfe_mac nodes from dtsi and define them in dts files.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-2g5rdb.dts | 4 ++--
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts   | 4 ++--
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts   | 4 ++--
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts    | 4 ++--
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts    | 4 ++--
+ arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi       | 5 -----
+ 6 files changed, 10 insertions(+), 15 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-2g5rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-2g5rdb.dts
+@@ -52,7 +52,7 @@
+       #address-cells = <1>;
+       #size-cells = <0>;
+-      ethernet@0 {
++      pfe_mac0: ethernet@0 {
+               compatible = "fsl,pfe-gemac-port";
+               #address-cells = <1>;
+               #size-cells = <0>;
+@@ -62,7 +62,7 @@
+               phy-handle = <&sgmii_phy1>;
+       };
+-      ethernet@1 {
++      pfe_mac1: ethernet@1 {
+               compatible = "fsl,pfe-gemac-port";
+               #address-cells = <1>;
+               #size-cells = <0>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts
+@@ -84,7 +84,7 @@
+       #address-cells = <1>;
+       #size-cells = <0>;
+-      ethernet@0 {
++      pfe_mac0: ethernet@0 {
+               compatible = "fsl,pfe-gemac-port";
+               #address-cells = <1>;
+               #size-cells = <0>;
+@@ -94,7 +94,7 @@
+               phy-handle = <&sgmii_phy1>;
+       };
+-      ethernet@1 {
++      pfe_mac1: ethernet@1 {
+               compatible = "fsl,pfe-gemac-port";
+               #address-cells = <1>;
+               #size-cells = <0>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts
+@@ -105,7 +105,7 @@
+       #address-cells = <1>;
+       #size-cells = <0>;
+-      ethernet@0 {
++      pfe_mac0: ethernet@0 {
+               compatible = "fsl,pfe-gemac-port";
+               #address-cells = <1>;
+               #size-cells = <0>;
+@@ -116,7 +116,7 @@
+               phy-handle = <&sgmii_phy1>;
+       };
+-      ethernet@1 {
++      pfe_mac1: ethernet@1 {
+               compatible = "fsl,pfe-gemac-port";
+               #address-cells = <1>;
+               #size-cells = <0>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts
+@@ -142,7 +142,7 @@
+       #address-cells = <1>;
+       #size-cells = <0>;
+-      ethernet@0 {
++      pfe_mac0: ethernet@0 {
+               compatible = "fsl,pfe-gemac-port";
+               #address-cells = <1>;
+               #size-cells = <0>;
+@@ -152,7 +152,7 @@
+               phy-handle = <&sgmii_phy1>;
+       };
+-      ethernet@1 {
++      pfe_mac1: ethernet@1 {
+               compatible = "fsl,pfe-gemac-port";
+               #address-cells = <1>;
+               #size-cells = <0>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
+@@ -53,7 +53,7 @@
+       #address-cells = <1>;
+       #size-cells = <0>;
+-      ethernet@0 {
++      pfe_mac0: ethernet@0 {
+               compatible = "fsl,pfe-gemac-port";
+               #address-cells = <1>;
+               #size-cells = <0>;
+@@ -63,7 +63,7 @@
+               phy-handle = <&sgmii_phy>;
+       };
+-      ethernet@1 {
++      pfe_mac1: ethernet@1 {
+               compatible = "fsl,pfe-gemac-port";
+               #address-cells = <1>;
+               #size-cells = <0>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+@@ -529,11 +529,6 @@
+               clock-names = "pfe";
+               status = "okay";
+-              pfe_mac0: ethernet@0 {
+-              };
+-
+-              pfe_mac1: ethernet@1 {
+-              };
+       };
+       firmware {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0041-sdk-dts-ls104x-drop-smmu-from-the-qds-and-usdpaa-sdk.patch b/target/linux/layerscape/patches-5.4/302-dts-0041-sdk-dts-ls104x-drop-smmu-from-the-qds-and-usdpaa-sdk.patch
new file mode 100644 (file)
index 0000000..8cbb00f
--- /dev/null
@@ -0,0 +1,109 @@
+From 6119ca5f113320d848ead38b141238b013f538c6 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Wed, 23 Jan 2019 16:28:36 +0200
+Subject: [PATCH] sdk: dts: ls104x: drop smmu from the qds and usdpaa sdk dts
+
+Also drop the smmu from the qds and usdpaa versions of the
+SDK device trees because SMMU is supported only for the
+upstream version of the dpaa ethernet drivers.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1043a-qds-sdk.dts    | 14 ++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts | 14 ++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls1046a-qds-sdk.dts    | 14 ++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts | 14 ++++++++++++++
+ 4 files changed, 56 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds-sdk.dts
+@@ -64,6 +64,20 @@
+ &soc {
+ #include "qoriq-dpaa-eth.dtsi"
+ #include "qoriq-fman3-0-6oh.dtsi"
++
++pcie@3400000 {
++       /delete-property/ iommu-map;
++};
++
++pcie@3500000 {
++       /delete-property/ iommu-map;
++};
++
++pcie@3600000 {
++       /delete-property/ iommu-map;
++};
++
++/delete-node/ iommu@9000000;
+ };
+ &fman0 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts
+@@ -92,6 +92,20 @@
+                       fsl,fman-oh-port = <&fman0_oh2>;
+               };
+       };
++
++      pcie@3400000 {
++             /delete-property/ iommu-map;
++      };
++
++      pcie@3500000 {
++             /delete-property/ iommu-map;
++      };
++
++      pcie@3600000 {
++             /delete-property/ iommu-map;
++      };
++
++      /delete-node/ iommu@9000000;
+ };
+ / {
+       reserved-memory {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds-sdk.dts
+@@ -64,6 +64,20 @@
+ &soc {
+ #include "qoriq-dpaa-eth.dtsi"
+ #include "qoriq-fman3-0-6oh.dtsi"
++
++pcie@3400000 {
++       /delete-property/ iommu-map;
++};
++
++pcie@3500000 {
++       /delete-property/ iommu-map;
++};
++
++pcie@3600000 {
++       /delete-property/ iommu-map;
++};
++
++/delete-node/ iommu@9000000;
+ };
+ &fsldpaa {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts
+@@ -85,6 +85,20 @@
+                       fsl,fman-oh-port = <&fman0_oh2>;
+               };
+       };
++
++      pcie@3400000 {
++             /delete-property/ iommu-map;
++      };
++
++      pcie@3500000 {
++             /delete-property/ iommu-map;
++      };
++
++      pcie@3600000 {
++             /delete-property/ iommu-map;
++      };
++
++      /delete-node/ iommu@9000000;
+ };
+ / {
+       reserved-memory {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0042-arm64-dts-fix-the-LS104x-QDS-mdio-mux-support.patch b/target/linux/layerscape/patches-5.4/302-dts-0042-arm64-dts-fix-the-LS104x-QDS-mdio-mux-support.patch
new file mode 100644 (file)
index 0000000..b8d6c27
--- /dev/null
@@ -0,0 +1,42 @@
+From 3c6ae8f4d45701683e671ea34bdddd0bf3e37a4d Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 13 Feb 2019 17:52:00 +0200
+Subject: [PATCH] arm64: dts: fix the LS104x QDS mdio-mux support
+
+Set the "simple-bus" compatible and the fpga ranges in order to
+successfully probe the mdio-mux-emi1.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts | 3 ++-
+ arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts | 3 ++-
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts
+@@ -78,10 +78,11 @@
+       };
+       fpga: board-control@2,0 {
+-              compatible = "fsl,ls1043aqds-fpga", "fsl,fpga-qixis";
++              compatible = "fsl,ls1043aqds-fpga", "fsl,fpga-qixis", "simple-bus";
+               reg = <0x2 0x0 0x0000100>;
+               #address-cells = <1>;
+               #size-cells = <1>;
++              ranges = <0 2 0 0x100>;
+       };
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts
+@@ -167,8 +167,9 @@
+       };
+       fpga: board-control@2,0 {
+-              compatible = "fsl,ls1046aqds-fpga", "fsl,fpga-qixis";
++              compatible = "fsl,ls1046aqds-fpga", "fsl,fpga-qixis", "simple-bus";
+               reg = <0x2 0x0 0x0000100>;
++              ranges = <0 2 0 0x100>;
+       };
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0043-arm64-dts-lx2160aqds-Add-mdio-mux-nodes.patch b/target/linux/layerscape/patches-5.4/302-dts-0043-arm64-dts-lx2160aqds-Add-mdio-mux-nodes.patch
new file mode 100644 (file)
index 0000000..9a6b32b
--- /dev/null
@@ -0,0 +1,247 @@
+From c9be87f17c64d08c06e4858589a0014f73868867 Mon Sep 17 00:00:00 2001
+From: Pankaj Bansal <pankaj.bansal@nxp.com>
+Date: Thu, 28 Feb 2019 17:28:36 +0530
+Subject: [PATCH] arm64: dts: lx2160aqds: Add mdio mux nodes
+
+The two external MDIO buses used to communicate with phy devices that are
+external to SOC are muxed in LX2160AQDS board.
+These buses can be routed to any one of the eight IO slots on LX2160AQDS
+board depending on value in fpga register 0x54.
+Additionally the external MDIO1 is used to communicate to the onboard
+RGMII phy devices.
+The mdio1 is controlled by bits 4-7 of fpga register and mdio2 is
+controlled by bits 4-7 of fpga register.
+
+Signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts | 145 ++++++++++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts |   8 ++
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi    |  24 ++--
+ 3 files changed, 165 insertions(+), 12 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
+@@ -29,6 +29,130 @@
+               regulator-boot-on;
+               regulator-always-on;
+       };
++
++      mdio-mux-1 {
++              compatible = "mdio-mux-multiplexer";
++              mux-controls = <&mux 0>;
++              mdio-parent-bus = <&emdio1>;
++              #address-cells=<1>;
++              #size-cells = <0>;
++
++              mdio@0 { /* On-board PHY #1 RGMI1*/
++                      reg = <0x00>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@8 { /* On-board PHY #2 RGMI2*/
++                      reg = <0x8>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@18 { /* Slot #1 */
++                      reg = <0x18>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@19 { /* Slot #2 */
++                      reg = <0x19>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@1a { /* Slot #3 */
++                      reg = <0x1a>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@1b { /* Slot #4 */
++                      reg = <0x1b>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@1c { /* Slot #5 */
++                      reg = <0x1c>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@1d { /* Slot #6 */
++                      reg = <0x1d>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@1e { /* Slot #7 */
++                      reg = <0x1e>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@1f { /* Slot #8 */
++                      reg = <0x1f>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++      };
++
++      mdio-mux-2 {
++              compatible = "mdio-mux-multiplexer";
++              mux-controls = <&mux 1>;
++              mdio-parent-bus = <&emdio2>;
++              #address-cells=<1>;
++              #size-cells = <0>;
++
++              mdio@0 { /* Slot #1 (secondary EMI) */
++                      reg = <0x00>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@1 { /* Slot #2 (secondary EMI) */
++                      reg = <0x01>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@2 { /* Slot #3 (secondary EMI) */
++                      reg = <0x02>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@3 { /* Slot #4 (secondary EMI) */
++                      reg = <0x03>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@4 { /* Slot #5 (secondary EMI) */
++                      reg = <0x04>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@5 { /* Slot #6 (secondary EMI) */
++                      reg = <0x05>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@6 { /* Slot #7 (secondary EMI) */
++                      reg = <0x06>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              mdio@7 { /* Slot #8 (secondary EMI) */
++                      reg = <0x07>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++      };
+ };
+ &crypto {
+@@ -71,6 +195,14 @@
+       };
+ };
++&emdio1 {
++      status = "okay";
++};
++
++&emdio2 {
++      status = "okay";
++};
++
+ &esdhc0 {
+       status = "okay";
+ };
+@@ -82,6 +214,19 @@
+ &i2c0 {
+       status = "okay";
++      fpga@66 {
++              compatible = "fsl,lx2160aqds-fpga", "fsl,fpga-qixis-i2c",
++                           "simple-mfd";
++              reg = <0x66>;
++
++              mux: mux-controller {
++                      compatible = "reg-mux";
++                      #mux-control-cells = <1>;
++                      mux-reg-masks = <0x54 0xf8>, /* 0: reg 0x54, bits 7:3 */
++                                      <0x54 0x07>; /* 1: reg 0x54, bit 2:0 */
++              };
++      };
++
+       i2c-mux@77 {
+               compatible = "nxp,pca9547";
+               reg = <0x77>;
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
+@@ -35,6 +35,14 @@
+       status = "okay";
+ };
++&emdio1 {
++      status = "okay";
++};
++
++&emdio2 {
++      status = "okay";
++};
++
+ &esdhc0 {
+       sd-uhs-sdr104;
+       sd-uhs-sdr50;
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -478,26 +478,26 @@
+                       little-endian;
+               };
+-              /* TODO: WRIOP (CCSR?) */
+-              emdio1: mdio@0x8B96000 { /* WRIOP0: 0x8B8_0000, E-MDIO1: 0x1_6000 */
++              /* WRIOP0: 0x8b8_0000, E-MDIO1: 0x1_6000 */
++              emdio1: mdio@8b96000 {
+                       compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8B96000 0x0 0x1000>;
+-                      device_type = "mdio";                   /* TODO: is this necessary? */
+-                      little-endian;  /* force the driver in LE mode */
+-
+-                      /* Not necessary on the QDS, but needed on the RDB */
++                      reg = <0x0 0x8b96000 0x0 0x1000>;
++                      interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
++                      little-endian;  /* force the driver in LE mode */
++                      status = "disabled";
+               };
+-              emdio2: mdio@0x8B97000 { /* WRIOP0: 0x8B8_0000, E-MDIO2: 0x1_7000 */
++              /* WRIOP0: 0x8b8_0000, E-MDIO2: 0x1_7000 */
++              emdio2: mdio@8b97000 {
+                       compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8B97000 0x0 0x1000>;
+-                      device_type = "mdio";                   /* TODO: is this necessary? */
+-                      little-endian;  /* force the driver in LE mode */
+-
++                      reg = <0x0 0x8b97000 0x0 0x1000>;
++                      interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
++                      little-endian;  /* force the driver in LE mode */
++                      status = "disabled";
+               };
+               pcs_mdio1: mdio@0x8c07000 {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0044-sdk-arm64-dts-reduce-usdpaa-memory-to-4K-for-LS1046-.patch b/target/linux/layerscape/patches-5.4/302-dts-0044-sdk-arm64-dts-reduce-usdpaa-memory-to-4K-for-LS1046-.patch
new file mode 100644 (file)
index 0000000..f8a75d8
--- /dev/null
@@ -0,0 +1,56 @@
+From 97b563d9c0cf09897c1e7b793ef0fe677c66269a Mon Sep 17 00:00:00 2001
+From: Nipun Gupta <nipun.gupta@nxp.com>
+Date: Wed, 30 Jan 2019 19:18:13 +0530
+Subject: [PATCH] sdk: arm64: dts: reduce usdpaa memory to 4K for LS1046/43
+
+This patch reducing the USDPAA reseved memory to 4K.
+In case USDPAA is to be used, 256MB needs to be reserved in the DTS file.
+
+Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts | 9 +++++++--
+ arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts | 9 +++++++--
+ 2 files changed, 14 insertions(+), 4 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts
+@@ -113,11 +113,16 @@
+               #size-cells = <2>;
+               ranges;
++              /* For legacy usdpaa based use-cases, update the size and
++                 alignment parameters. e.g. to allocate 256 MB memory:
++                 size = <0 0x10000000>;
++                 alignment = <0 0x10000000>;
++              */
+               usdpaa_mem: usdpaa_mem {
+                       compatible = "fsl,usdpaa-mem";
+                       alloc-ranges = <0 0 0x10000 0>;
+-                      size = <0 0x10000000>;
+-                      alignment = <0 0x10000000>;
++                      size = <0 0x1000>;
++                      alignment = <0 0x1000>;
+               };
+       };
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts
+@@ -106,11 +106,16 @@
+               #size-cells = <2>;
+               ranges;
++              /* For legacy usdpaa based use-cases, update the size and
++                 alignment parameters. e.g. to allocate 256 MB memory:
++                 size = <0 0x10000000>;
++                 alignment = <0 0x10000000>;
++              */
+               usdpaa_mem: usdpaa_mem {
+                       compatible = "fsl,usdpaa-mem";
+                       alloc-ranges = <0 0 0x10000 0>;
+-                      size = <0 0x10000000>;
+-                      alignment = <0 0x10000000>;
++                      size = <0 0x1000>;
++                      alignment = <0 0x1000>;
+               };
+       };
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0045-arm64-dts-Fix-DWC3-IP-VBUS-glitch-issue-on-Layerscap.patch b/target/linux/layerscape/patches-5.4/302-dts-0045-arm64-dts-Fix-DWC3-IP-VBUS-glitch-issue-on-Layerscap.patch
new file mode 100644 (file)
index 0000000..ff12e44
--- /dev/null
@@ -0,0 +1,134 @@
+From 0c7e3f6f557c2a68527980e940e6a605da1f9e12 Mon Sep 17 00:00:00 2001
+From: Ran Wang <ran.wang_1@nxp.com>
+Date: Wed, 16 Jan 2019 15:40:33 +0800
+Subject: [PATCH] arm64: dts: Fix DWC3 IP VBUS glitch issue on Layerscape
+ platforms
+
+Cover LS1012A, LS1043A, LS1046A, LS1088A, LS208xA, LX2160A
+
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 1 +
+ arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++
+ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 3 +++
+ arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 2 ++
+ arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 2 ++
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 2 ++
+ 6 files changed, 13 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+@@ -442,6 +442,7 @@
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      snps,host-vbus-glitches;
+               };
+               sata: sata@3200000 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+@@ -712,6 +712,7 @@
+                               usb3-lpm-capable;
+                               snps,dis-u1u2-when-u3-quirk;
+                               snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                              snps,host-vbus-glitches;
+                               configure-gfladj;
+                       };
+@@ -725,6 +726,7 @@
+                               usb3-lpm-capable;
+                               snps,dis-u1u2-when-u3-quirk;
+                               snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                              snps,host-vbus-glitches;
+                               configure-gfladj;
+                       };
+@@ -738,6 +740,7 @@
+                               usb3-lpm-capable;
+                               snps,dis-u1u2-when-u3-quirk;
+                               snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                              snps,host-vbus-glitches;
+                               configure-gfladj;
+                       };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+@@ -610,6 +610,7 @@
+                               snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                               usb3-lpm-capable;
+                               snps,dis-u1u2-when-u3-quirk;
++                              snps,host-vbus-glitches;
+                       };
+                       usb1: usb@3000000 {
+@@ -622,6 +623,7 @@
+                               snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                               usb3-lpm-capable;
+                               snps,dis-u1u2-when-u3-quirk;
++                              snps,host-vbus-glitches;
+                       };
+                       usb2: usb@3100000 {
+@@ -634,6 +636,7 @@
+                               snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                               usb3-lpm-capable;
+                               snps,dis-u1u2-when-u3-quirk;
++                              snps,host-vbus-glitches;
+                       };
+                       sata: sata@3200000 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+@@ -452,6 +452,7 @@
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      snps,host-vbus-glitches;
+                       status = "disabled";
+               };
+@@ -463,6 +464,7 @@
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      snps,host-vbus-glitches;
+                       status = "disabled";
+               };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+@@ -820,6 +820,7 @@
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      snps,host-vbus-glitches;
+               };
+               usb1: usb3@3110000 {
+@@ -831,6 +832,7 @@
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      snps,host-vbus-glitches;
+               };
+               serdes1: serdes@1ea0000 {
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -845,6 +845,7 @@
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      snps,host-vbus-glitches;
+                       status = "disabled";
+               };
+@@ -856,6 +857,7 @@
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      snps,host-vbus-glitches;
+                       status = "disabled";
+               };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0046-ARM-dts-Fix-DWC3-IP-VBUS-glitch-issue-on-LS1021A.patch b/target/linux/layerscape/patches-5.4/302-dts-0046-ARM-dts-Fix-DWC3-IP-VBUS-glitch-issue-on-LS1021A.patch
new file mode 100644 (file)
index 0000000..de9de09
--- /dev/null
@@ -0,0 +1,20 @@
+From 3c1991fe18bca459d07dd78a2268e26008707f00 Mon Sep 17 00:00:00 2001
+From: Ran Wang <ran.wang_1@nxp.com>
+Date: Mon, 25 Feb 2019 13:38:01 +0800
+Subject: [PATCH] ARM: dts: Fix DWC3 IP VBUS glitch issue on LS1021A
+
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+---
+ arch/arm/boot/dts/ls1021a.dtsi | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/boot/dts/ls1021a.dtsi
++++ b/arch/arm/boot/dts/ls1021a.dtsi
+@@ -877,6 +877,7 @@
+                       usb3-lpm-capable;
+                       snps,dis-u1u2-when-u3-quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      snps,host-vbus-glitches;
+               };
+               pcie@3400000 {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0047-ARM-dts-ls1021aqds-enable-esdhc-controller.patch b/target/linux/layerscape/patches-5.4/302-dts-0047-ARM-dts-ls1021aqds-enable-esdhc-controller.patch
new file mode 100644 (file)
index 0000000..89f393f
--- /dev/null
@@ -0,0 +1,25 @@
+From 6c3655acaa5766efe81f60ac6d428b0d184daa0d Mon Sep 17 00:00:00 2001
+From: Yinbo Zhu <yinbo.zhu@nxp.com>
+Date: Fri, 21 Dec 2018 11:38:44 +0800
+Subject: [PATCH] ARM: dts: ls1021aqds: enable esdhc controller
+
+This patch is to enable esdhc controller in ls1021aqds
+
+Signed-off-by: Yinbo Zhu <yinbo.zhu@nxp.com>
+---
+ arch/arm/boot/dts/ls1021a-qds.dts | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/arm/boot/dts/ls1021a-qds.dts
++++ b/arch/arm/boot/dts/ls1021a-qds.dts
+@@ -165,6 +165,10 @@
+       status = "okay";
+ };
++&esdhc {
++      status = "okay";
++};
++
+ &i2c0 {
+       status = "okay";
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0048-arm64-dts-freescale-lx2160a-add-pcie-EP-mode-DT-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0048-arm64-dts-freescale-lx2160a-add-pcie-EP-mode-DT-node.patch
new file mode 100644 (file)
index 0000000..5a70597
--- /dev/null
@@ -0,0 +1,112 @@
+From 4de7a5e35eff9216fa5e6b138b0ffa75e045e397 Mon Sep 17 00:00:00 2001
+From: Xiaowei Bao <xiaowei.bao@nxp.com>
+Date: Thu, 28 Feb 2019 14:09:01 +0800
+Subject: [PATCH] arm64: dts: freescale: lx2160a: add pcie EP mode DT nodes
+
+The LX2160A PCIe EP mode node.
+
+Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 56 ++++++++++++++++++++++++++
+ 1 file changed, 56 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -932,6 +932,15 @@
+                       status = "disabled";
+               };
++              pcie_ep@3400000 {
++                      compatible = "fsl,lx2160a-pcie-ep";
++                      reg = <0x00 0x03400000 0x0 0x00100000
++                             0x80 0x00000000 0x8 0x00000000>;
++                      reg-names = "regs", "addr_space";
++                      num-ob-windows = <256>;
++                      status = "disabled";
++              };
++
+               pcie@3500000 {
+                       compatible = "fsl,lx2160a-pcie";
+                       reg = <0x00 0x03500000 0x0 0x00100000   /* controller registers */
+@@ -959,6 +968,15 @@
+                       status = "disabled";
+               };
++              pcie_ep@3500000 {
++                      compatible = "fsl,lx2160a-pcie-ep";
++                      reg = <0x00 0x03500000 0x0 0x00100000
++                             0x88 0x00000000 0x8 0x00000000>;
++                      reg-names = "regs", "addr_space";
++                      num-ob-windows = <256>;
++                      status = "disabled";
++              };
++
+               pcie@3600000 {
+                       compatible = "fsl,lx2160a-pcie";
+                       reg = <0x00 0x03600000 0x0 0x00100000   /* controller registers */
+@@ -986,6 +1004,16 @@
+                       status = "disabled";
+               };
++              pcie_ep@3600000 {
++                      compatible = "fsl,lx2160a-pcie-ep";
++                      reg = <0x00 0x03600000 0x0 0x00100000
++                             0x90 0x00000000 0x8 0x00000000>;
++                      reg-names = "regs", "addr_space";
++                      num-ob-windows = <256>;
++                      max-functions = <2>;
++                      status = "disabled";
++              };
++
+               pcie@3700000 {
+                       compatible = "fsl,lx2160a-pcie";
+                       reg = <0x00 0x03700000 0x0 0x00100000   /* controller registers */
+@@ -1013,6 +1041,15 @@
+                       status = "disabled";
+               };
++              pcie_ep@3700000 {
++                      compatible = "fsl,lx2160a-pcie-ep";
++                      reg = <0x00 0x03700000 0x0 0x00100000
++                             0x98 0x00000000 0x8 0x00000000>;
++                      reg-names = "regs", "addr_space";
++                      num-ob-windows = <256>;
++                      status = "disabled";
++              };
++
+               pcie@3800000 {
+                       compatible = "fsl,lx2160a-pcie";
+                       reg = <0x00 0x03800000 0x0 0x00100000   /* controller registers */
+@@ -1040,6 +1077,16 @@
+                       status = "disabled";
+               };
++              pcie_ep@3800000 {
++                      compatible = "fsl,lx2160a-pcie-ep";
++                      reg = <0x00 0x03800000 0x0 0x00100000
++                             0xa0 0x00000000 0x8 0x00000000>;
++                      reg-names = "regs", "addr_space";
++                      num-ob-windows = <256>;
++                      max-functions = <2>;
++                      status = "disabled";
++              };
++
+               pcie@3900000 {
+                       compatible = "fsl,lx2160a-pcie";
+                       reg = <0x00 0x03900000 0x0 0x00100000   /* controller registers */
+@@ -1067,6 +1114,15 @@
+                       status = "disabled";
+               };
++              pcie_ep@3900000 {
++                      compatible = "fsl,lx2160a-pcie-ep";
++                      reg = <0x00 0x03900000 0x0 0x00100000
++                             0xa8 0x00000000 0x8 0x00000000>;
++                      reg-names = "regs", "addr_space";
++                      num-ob-windows = <256>;
++                      status = "disabled";
++              };
++
+               smmu: iommu@5000000 {
+                       compatible = "arm,mmu-500";
+                       reg = <0 0x5000000 0 0x800000>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0049-sdk-dts-ls104x-move-dma-coherent-from-soc-to-its-chi.patch b/target/linux/layerscape/patches-5.4/302-dts-0049-sdk-dts-ls104x-move-dma-coherent-from-soc-to-its-chi.patch
new file mode 100644 (file)
index 0000000..838499a
--- /dev/null
@@ -0,0 +1,879 @@
+From 6795bab4281aa9ed8e0ba3fbba06de8dd369b17c Mon Sep 17 00:00:00 2001
+From: Ran Wang <ran.wang_1@nxp.com>
+Date: Thu, 21 Feb 2019 13:32:59 +0800
+Subject: [PATCH] sdk: dts: ls104x move dma-coherent from soc to its child
+ nodes
+
+Since SMMU is not supported for SDK version, USB function will down if
+still apply property 'dma-coherent' in scope of soc (USB driver is not
+ready to support it alone) in SDK device trees, decide to remove it.
+And add dma-coherent on other non-USB child nodes under soc.
+
+dma-coherent feature in dts node will cause issue that
+QE-HDLC received too little, when a lot of data is transmitted while
+just little data received, the Tx buffer will run out.
+
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
+---
+ .../boot/dts/freescale/fsl-ls1043a-qds-sdk.dts     | 184 ++++++++++++++++++++-
+ .../boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts     | 177 ++++++++++++++++++++
+ .../boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts  |   4 +
+ .../boot/dts/freescale/fsl-ls1046a-qds-sdk.dts     | 175 ++++++++++++++++++++
+ .../boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts     | 178 ++++++++++++++++++++
+ .../boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts  |   4 +
+ 6 files changed, 719 insertions(+), 3 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds-sdk.dts
+@@ -62,19 +62,24 @@
+ };
+ &soc {
++/delete-property/ dma-coherent;
++
+ #include "qoriq-dpaa-eth.dtsi"
+ #include "qoriq-fman3-0-6oh.dtsi"
+ pcie@3400000 {
+-       /delete-property/ iommu-map;
++      /delete-property/ iommu-map;
++      dma-coherent;
+ };
+ pcie@3500000 {
+-       /delete-property/ iommu-map;
++      /delete-property/ iommu-map;
++      dma-coherent;
+ };
+ pcie@3600000 {
+-       /delete-property/ iommu-map;
++      /delete-property/ iommu-map;
++      dma-coherent;
+ };
+ /delete-node/ iommu@9000000;
+@@ -82,4 +87,177 @@ pcie@3600000 {
+ &fman0 {
+       compatible = "fsl,fman", "simple-bus";
++      dma-coherent;
++};
++
++&clockgen {
++      dma-coherent;
++};
++
++&scfg {
++      dma-coherent;
++};
++
++&crypto {
++      dma-coherent;
++};
++
++&dcfg {
++      dma-coherent;
++};
++
++&ifc {
++      dma-coherent;
++};
++
++&qspi {
++      dma-coherent;
++};
++
++&esdhc {
++      dma-coherent;
++};
++
++&ddr {
++      dma-coherent;
++};
++
++&tmu {
++      dma-coherent;
++};
++
++&qman {
++      dma-coherent;
++};
++
++&bman {
++      dma-coherent;
++};
++
++&bportals {
++      dma-coherent;
++};
++
++&qportals {
++      dma-coherent;
++};
++
++&dspi0 {
++      dma-coherent;
++};
++
++&dspi1 {
++      dma-coherent;
++};
++
++&i2c0 {
++      dma-coherent;
++};
++
++&i2c1 {
++      dma-coherent;
++};
++
++&i2c2 {
++      dma-coherent;
++};
++
++&i2c3 {
++      dma-coherent;
++};
++
++&duart0 {
++      dma-coherent;
++};
++
++&duart1 {
++      dma-coherent;
++};
++
++&duart2 {
++      dma-coherent;
++};
++
++&duart3 {
++      dma-coherent;
++};
++
++&gpio1 {
++      dma-coherent;
++};
++
++&gpio2 {
++      dma-coherent;
++};
++
++&gpio3 {
++      dma-coherent;
++};
++
++&gpio4 {
++      dma-coherent;
++};
++
++&uqe {
++      dma-coherent;
++};
++
++&lpuart0 {
++      dma-coherent;
++};
++
++&lpuart1 {
++      dma-coherent;
++};
++
++&lpuart2 {
++      dma-coherent;
++};
++
++&lpuart3 {
++      dma-coherent;
++};
++
++&lpuart4 {
++      dma-coherent;
++};
++
++&lpuart5 {
++      dma-coherent;
++};
++
++&ftm0 {
++      dma-coherent;
++};
++
++&wdog0 {
++      dma-coherent;
++};
++
++&edma0 {
++      dma-coherent;
++};
++
++&qdma {
++      dma-coherent;
++};
++
++&msi1 {
++      dma-coherent;
++};
++
++&msi2 {
++      dma-coherent;
++};
++
++&msi3 {
++      dma-coherent;
++};
++
++&ptp_timer0 {
++      dma-coherent;
++};
++
++&fsldpaa {
++      dma-coherent;
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts
+@@ -62,19 +62,24 @@
+ };
+ &soc {
++/delete-property/ dma-coherent;
++
+ #include "qoriq-dpaa-eth.dtsi"
+ #include "qoriq-fman3-0-6oh.dtsi"
+ pcie@3400000 {
+       /delete-property/ iommu-map;
++      dma-coherent;
+ };
+ pcie@3500000 {
+       /delete-property/ iommu-map;
++      dma-coherent;
+ };
+ pcie@3600000 {
+       /delete-property/ iommu-map;
++      dma-coherent;
+ };
+ /delete-node/ iommu@9000000;
+@@ -83,3 +88,175 @@ pcie@3600000 {
+ &fman0 {
+       compatible = "fsl,fman", "simple-bus";
+ };
++
++&clockgen {
++      dma-coherent;
++};
++
++&scfg {
++      dma-coherent;
++};
++
++&crypto {
++      dma-coherent;
++};
++
++&dcfg {
++      dma-coherent;
++};
++
++&ifc {
++      dma-coherent;
++};
++
++&qspi {
++      dma-coherent;
++};
++
++&esdhc {
++      dma-coherent;
++};
++
++&ddr {
++      dma-coherent;
++};
++
++&tmu {
++      dma-coherent;
++};
++
++&qman {
++      dma-coherent;
++};
++
++&bman {
++      dma-coherent;
++};
++
++&bportals {
++      dma-coherent;
++};
++
++&qportals {
++      dma-coherent;
++};
++
++&dspi0 {
++      dma-coherent;
++};
++
++&dspi1 {
++      dma-coherent;
++};
++
++&i2c0 {
++      dma-coherent;
++};
++
++&i2c1 {
++      dma-coherent;
++};
++
++&i2c2 {
++      dma-coherent;
++};
++
++&i2c3 {
++      dma-coherent;
++};
++
++&duart0 {
++      dma-coherent;
++};
++
++&duart1 {
++      dma-coherent;
++};
++
++&duart2 {
++      dma-coherent;
++};
++
++&duart3 {
++      dma-coherent;
++};
++
++&gpio1 {
++      dma-coherent;
++};
++
++&gpio2 {
++      dma-coherent;
++};
++
++&gpio3 {
++      dma-coherent;
++};
++
++&gpio4 {
++      dma-coherent;
++};
++
++&lpuart0 {
++      dma-coherent;
++};
++
++&lpuart1 {
++      dma-coherent;
++};
++
++&lpuart2 {
++      dma-coherent;
++};
++
++&lpuart3 {
++      dma-coherent;
++};
++
++&lpuart4 {
++      dma-coherent;
++};
++
++&lpuart5 {
++      dma-coherent;
++};
++
++&ftm0 {
++      dma-coherent;
++};
++
++&wdog0 {
++      dma-coherent;
++};
++
++&edma0 {
++      dma-coherent;
++};
++
++&qdma {
++      dma-coherent;
++};
++
++&msi1 {
++      dma-coherent;
++};
++
++&msi2 {
++      dma-coherent;
++};
++
++&msi3 {
++      dma-coherent;
++};
++
++&fman0 {
++      dma-coherent;
++};
++
++&ptp_timer0 {
++      dma-coherent;
++};
++
++&fsldpaa {
++      dma-coherent;
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts
+@@ -16,6 +16,7 @@
+               fsl,bpid = <7>;
+               fsl,bpool-ethernet-cfg = <0 0 0 192 0 0xdeadbeef>;
+               fsl,bpool-thresholds = <0x400 0xc00 0x0 0x0>;
++              dma-coherent;
+       };
+       bp8: buffer-pool@8 {
+@@ -23,6 +24,7 @@
+               fsl,bpid = <8>;
+               fsl,bpool-ethernet-cfg = <0 0 0 576 0 0xabbaf00d>;
+               fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>;
++              dma-coherent;
+       };
+       bp9: buffer-pool@9 {
+@@ -30,10 +32,12 @@
+               fsl,bpid = <9>;
+               fsl,bpool-ethernet-cfg = <0 0 0 2048 0 0xfeedabba>;
+               fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>;
++              dma-coherent;
+       };
+       fsl,dpaa {
+               compatible = "fsl,ls1043a", "fsl,dpaa", "simple-bus";
++              dma-coherent;
+               ethernet@0 {
+                       compatible = "fsl,dpa-ethernet-init";
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds-sdk.dts
+@@ -62,6 +62,8 @@
+ };
+ &soc {
++/delete-property/ dma-coherent;
++
+ #include "qoriq-dpaa-eth.dtsi"
+ #include "qoriq-fman3-0-6oh.dtsi"
+@@ -90,4 +92,177 @@ pcie@3600000 {
+ &fman0 {
+       compatible = "fsl,fman", "simple-bus";
++      dma-coherent;
++};
++
++&clockgen {
++      dma-coherent;
++};
++
++&scfg {
++      dma-coherent;
++};
++
++&crypto {
++      dma-coherent;
++};
++
++&dcfg {
++      dma-coherent;
++};
++
++&ifc {
++      dma-coherent;
++};
++
++&qspi {
++      dma-coherent;
++};
++
++&esdhc {
++      dma-coherent;
++};
++
++&ddr {
++      dma-coherent;
++};
++
++&tmu {
++      dma-coherent;
++};
++
++&qman {
++      dma-coherent;
++};
++
++&bman {
++      dma-coherent;
++};
++
++&bportals {
++      dma-coherent;
++};
++
++&qportals {
++      dma-coherent;
++};
++
++&dspi {
++      dma-coherent;
++};
++
++&i2c0 {
++      dma-coherent;
++};
++
++&i2c1 {
++      dma-coherent;
++};
++
++&i2c2 {
++      dma-coherent;
++};
++
++&i2c3 {
++      dma-coherent;
++};
++
++&duart0 {
++      dma-coherent;
++};
++
++&duart1 {
++      dma-coherent;
++};
++
++&duart2 {
++      dma-coherent;
++};
++
++&duart3 {
++      dma-coherent;
++};
++
++&gpio0 {
++      dma-coherent;
++};
++
++&gpio1 {
++      dma-coherent;
++};
++
++&gpio2 {
++      dma-coherent;
++};
++
++&gpio3 {
++      dma-coherent;
++};
++
++&lpuart0 {
++      dma-coherent;
++};
++
++&lpuart1 {
++      dma-coherent;
++};
++
++&lpuart2 {
++      dma-coherent;
++};
++
++&lpuart3 {
++      dma-coherent;
++};
++
++&lpuart4 {
++      dma-coherent;
++};
++
++&lpuart5 {
++      dma-coherent;
++};
++
++&ftm0 {
++      dma-coherent;
++};
++
++&wdog0 {
++      dma-coherent;
++};
++
++&edma0 {
++      dma-coherent;
++};
++
++&sata {
++      dma-coherent;
++};
++
++&qdma {
++      dma-coherent;
++};
++
++&msi1 {
++      dma-coherent;
++};
++
++&msi2 {
++      dma-coherent;
++};
++
++&msi3 {
++      dma-coherent;
++};
++
++&ptp_timer0 {
++      dma-coherent;
++};
++
++&serdes1 {
++      dma-coherent;
++};
++
++&fsldpaa {
++      dma-coherent;
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts
+@@ -62,6 +62,8 @@
+ };
+ &soc {
++/delete-property/ dma-coherent;
++
+ #include "qoriq-dpaa-eth.dtsi"
+ #include "qoriq-fman3-0-6oh.dtsi"
+@@ -127,3 +129,179 @@ pcie@3600000 {
+  *    phy-handle = <&pcsphy7>;
+  *};
+ */
++
++&clockgen {
++      dma-coherent;
++};
++
++&scfg {
++      dma-coherent;
++};
++
++&crypto {
++      dma-coherent;
++};
++
++&dcfg {
++      dma-coherent;
++};
++
++&ifc {
++      dma-coherent;
++};
++
++&qspi {
++      dma-coherent;
++};
++
++&esdhc {
++      dma-coherent;
++};
++
++&ddr {
++      dma-coherent;
++};
++
++&tmu {
++      dma-coherent;
++};
++
++&qman {
++      dma-coherent;
++};
++
++&bman {
++      dma-coherent;
++};
++
++&bportals {
++      dma-coherent;
++};
++
++&qportals {
++      dma-coherent;
++};
++
++&dspi {
++      dma-coherent;
++};
++
++&i2c0 {
++      dma-coherent;
++};
++
++&i2c1 {
++      dma-coherent;
++};
++
++&i2c2 {
++      dma-coherent;
++};
++
++&i2c3 {
++      dma-coherent;
++};
++
++&duart0 {
++      dma-coherent;
++};
++
++&duart1 {
++      dma-coherent;
++};
++
++&duart2 {
++      dma-coherent;
++};
++
++&duart3 {
++      dma-coherent;
++};
++
++&gpio0 {
++      dma-coherent;
++};
++
++&gpio1 {
++      dma-coherent;
++};
++
++&gpio2 {
++      dma-coherent;
++};
++
++&gpio3 {
++      dma-coherent;
++};
++
++&lpuart0 {
++      dma-coherent;
++};
++
++&lpuart1 {
++      dma-coherent;
++};
++
++&lpuart2 {
++      dma-coherent;
++};
++
++&lpuart3 {
++      dma-coherent;
++};
++
++&lpuart4 {
++      dma-coherent;
++};
++
++&lpuart5 {
++      dma-coherent;
++};
++
++&ftm0 {
++      dma-coherent;
++};
++
++&wdog0 {
++      dma-coherent;
++};
++
++&edma0 {
++      dma-coherent;
++};
++
++&sata {
++      dma-coherent;
++};
++
++&qdma {
++      dma-coherent;
++};
++
++&msi1 {
++      dma-coherent;
++};
++
++&msi2 {
++      dma-coherent;
++};
++
++&msi3 {
++      dma-coherent;
++};
++
++&fman0 {
++      dma-coherent;
++};
++
++&ptp_timer0 {
++      dma-coherent;
++};
++
++&serdes1 {
++      dma-coherent;
++};
++
++&fsldpaa {
++      dma-coherent;
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts
+@@ -16,6 +16,7 @@
+               fsl,bpid = <7>;
+               fsl,bpool-ethernet-cfg = <0 0 0 192 0 0xdeadbeef>;
+               fsl,bpool-thresholds = <0x400 0xc00 0x0 0x0>;
++              dma-coherent;
+       };
+       bp8: buffer-pool@8 {
+@@ -23,6 +24,7 @@
+               fsl,bpid = <8>;
+               fsl,bpool-ethernet-cfg = <0 0 0 576 0 0xabbaf00d>;
+               fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>;
++              dma-coherent;
+       };
+       bp9: buffer-pool@9 {
+@@ -30,10 +32,12 @@
+               fsl,bpid = <9>;
+               fsl,bpool-ethernet-cfg = <0 0 0 2048 0 0xfeedabba>;
+               fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>;
++              dma-coherent;
+       };
+       fsl,dpaa {
+               compatible = "fsl,ls1046a", "fsl,dpaa", "simple-bus";
++              dma-coherent;
+               ethernet@2 {
+                       compatible = "fsl,dpa-ethernet-init";
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0050-arm64-dts-lx2160a-add-interrupt-property-for-aquanti.patch b/target/linux/layerscape/patches-5.4/302-dts-0050-arm64-dts-lx2160a-add-interrupt-property-for-aquanti.patch
new file mode 100644 (file)
index 0000000..7725311
--- /dev/null
@@ -0,0 +1,32 @@
+From e260d97c7875d5ef6aca11e49bf2784966a877c2 Mon Sep 17 00:00:00 2001
+From: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
+Date: Thu, 4 Apr 2019 17:44:46 +0300
+Subject: [PATCH] arm64: dts: lx2160a: add interrupt property for aquantia phy
+
+Add interrupt property for Aquantia AQR107 ethernet phy, currently
+working in polling mode.
+
+Signed-off-by: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
+@@ -184,14 +184,14 @@
+       aquantia_phy1: ethernet-phy@4 {
+               /* AQR107 PHY - "compatible" property not strictly needed */
+               compatible = "ethernet-phy-ieee802.3-c45";
++              interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+               reg = <0x4>;
+-              /* Poll mode - no "interrupts" property defined */
+       };
+       aquantia_phy2: ethernet-phy@5 {
+               /* AQR107 PHY - "compatible" property not strictly needed */
+               compatible = "ethernet-phy-ieee802.3-c45";
++              interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+               reg = <0x5>;
+-              /* Poll mode - no "interrupts" property defined */
+       };
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0051-arm64-dts-fsl-layerscape-fix-warnings-when-compiling.patch b/target/linux/layerscape/patches-5.4/302-dts-0051-arm64-dts-fsl-layerscape-fix-warnings-when-compiling.patch
new file mode 100644 (file)
index 0000000..2e68b8e
--- /dev/null
@@ -0,0 +1,292 @@
+From d949248dccef18f7257d8de0adfd67244955e7b7 Mon Sep 17 00:00:00 2001
+From: Pankaj Bansal <pankaj.bansal@nxp.com>
+Date: Mon, 22 Apr 2019 16:22:49 +0530
+Subject: [PATCH] arm64: dts: fsl: layerscape: fix warnings when compiling dts
+ files
+
+when compiling dts file using DTC_FLAG='-@', the device tree compiler
+reports these warnings:
+
+Warning (simple_bus_reg): /soc/mdio@0x8c0b000: simple-bus unit address
+format error, expected "8c0b000"
+Warning (unit_address_format): /pfe@04000000: unit name should not have
+leading 0s
+
+Fixed the node names to silence these warnings.
+
+Signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi |  3 ++-
+ arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 14 +++++++-------
+ arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 22 +++++++++++-----------
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 18 +++++++++---------
+ 4 files changed, 29 insertions(+), 28 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+@@ -3,6 +3,7 @@
+  * Device Tree Include file for Freescale Layerscape-1012A family SoC.
+  *
+  * Copyright 2016 Freescale Semiconductor, Inc.
++ * Copyright 2019 NXP
+  *
+  */
+@@ -513,7 +514,7 @@
+               };
+       };
+-      pfe: pfe@04000000 {
++      pfe: pfe@4000000 {
+               compatible = "fsl,pfe";
+               reg =   <0x0 0x04000000 0x0 0xc00000>,  /* AXI 16M */
+                       <0x0 0x83400000 0x0 0xc00000>;  /* PFE DDR 12M */
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+@@ -2,7 +2,7 @@
+ /*
+  * Device Tree Include file for NXP Layerscape-1088A family SoC.
+  *
+- * Copyright 2017 NXP
++ * Copyright 2017-2019 NXP
+  *
+  * Harninder Rai <harninder.rai@nxp.com>
+  *
+@@ -310,7 +310,7 @@
+               };
+               /* TODO: WRIOP (CCSR?) */
+-              emdio1: mdio@0x8B96000 { /* WRIOP0: 0x8B8_0000,
++              emdio1: mdio@8B96000 { /* WRIOP0: 0x8B8_0000,
+                                         * E-MDIO1: 0x1_6000
+                                         */
+                       compatible = "fsl,fman-memac-mdio";
+@@ -323,7 +323,7 @@
+                       #size-cells = <0>;
+               };
+-              emdio2: mdio@0x8B97000 { /* WRIOP0: 0x8B8_0000,
++              emdio2: mdio@8B97000 { /* WRIOP0: 0x8B8_0000,
+                                         * E-MDIO2: 0x1_7000
+                                         */
+                       compatible = "fsl,fman-memac-mdio";
+@@ -335,7 +335,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio1: mdio@0x8c07000 {
++              pcs_mdio1: mdio@8c07000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c07000 0x0 0x1000>;
+                       device_type = "mdio";
+@@ -345,7 +345,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio2: mdio@0x8c0b000 {
++              pcs_mdio2: mdio@8c0b000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c0b000 0x0 0x1000>;
+                       device_type = "mdio";
+@@ -355,7 +355,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio3: mdio@0x8c0f000 {
++              pcs_mdio3: mdio@8c0f000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c0f000 0x0 0x1000>;
+                       device_type = "mdio";
+@@ -365,7 +365,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio4: mdio@0x8c13000 {
++              pcs_mdio4: mdio@8c13000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c13000 0x0 0x1000>;
+                       device_type = "mdio";
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+@@ -3,7 +3,7 @@
+  * Device Tree Include file for Freescale Layerscape-2080A family SoC.
+  *
+  * Copyright 2016 Freescale Semiconductor, Inc.
+- * Copyright 2017 NXP
++ * Copyright 2017-2019 NXP
+  *
+  * Abhimanyu Saini <abhimanyu.saini@nxp.com>
+  *
+@@ -525,7 +525,7 @@
+               };
+               /* TODO: WRIOP (CCSR?) */
+-              emdio1: mdio@0x8B96000 { /* WRIOP0: 0x8B8_0000,
++              emdio1: mdio@8B96000 { /* WRIOP0: 0x8B8_0000,
+                                         * E-MDIO1: 0x1_6000
+                                         */
+                       compatible = "fsl,fman-memac-mdio";
+@@ -538,7 +538,7 @@
+                       #size-cells = <0>;
+               };
+-              emdio2: mdio@0x8B97000 { /* WRIOP0: 0x8B8_0000,
++              emdio2: mdio@8B97000 { /* WRIOP0: 0x8B8_0000,
+                                         * E-MDIO2: 0x1_7000
+                                         */
+                       compatible = "fsl,fman-memac-mdio";
+@@ -550,7 +550,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio1: mdio@0x8c07000 {
++              pcs_mdio1: mdio@8c07000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c07000 0x0 0x1000>;
+                       device_type = "mdio";
+@@ -560,7 +560,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio2: mdio@0x8c0b000 {
++              pcs_mdio2: mdio@8c0b000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c0b000 0x0 0x1000>;
+                       device_type = "mdio";
+@@ -570,7 +570,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio3: mdio@0x8c0f000 {
++              pcs_mdio3: mdio@8c0f000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c0f000 0x0 0x1000>;
+                       device_type = "mdio";
+@@ -580,7 +580,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio4: mdio@0x8c13000 {
++              pcs_mdio4: mdio@8c13000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c13000 0x0 0x1000>;
+                       device_type = "mdio";
+@@ -590,7 +590,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio5: mdio@0x8c17000 {
++              pcs_mdio5: mdio@8c17000 {
+                       status = "disabled";
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c17000 0x0 0x1000>;
+@@ -601,7 +601,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio6: mdio@0x8c1b000 {
++              pcs_mdio6: mdio@8c1b000 {
+                       status = "disabled";
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c1b000 0x0 0x1000>;
+@@ -612,7 +612,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio7: mdio@0x8c1f000 {
++              pcs_mdio7: mdio@8c1f000 {
+                       status = "disabled";
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c1f000 0x0 0x1000>;
+@@ -623,7 +623,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio8: mdio@0x8c23000 {
++              pcs_mdio8: mdio@8c23000 {
+                       status = "disabled";
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c23000 0x0 0x1000>;
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -2,7 +2,7 @@
+ //
+ // Device Tree Include file for Layerscape-LX2160A family SoC.
+ //
+-// Copyright 2018 NXP
++// Copyright 2018-2019 NXP
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+@@ -500,7 +500,7 @@
+                       status = "disabled";
+               };
+-              pcs_mdio1: mdio@0x8c07000 {
++              pcs_mdio1: mdio@8c07000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c07000 0x0 0x1000>;
+                       device_type = "mdio";
+@@ -510,7 +510,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio2: mdio@0x8c0b000 {
++              pcs_mdio2: mdio@8c0b000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c0b000 0x0 0x1000>;
+                       device_type = "mdio";
+@@ -520,7 +520,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio3: mdio@0x8c0f000 {
++              pcs_mdio3: mdio@8c0f000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c0f000 0x0 0x1000>;
+                       device_type = "mdio";
+@@ -530,7 +530,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio4: mdio@0x8c13000 {
++              pcs_mdio4: mdio@8c13000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c13000 0x0 0x1000>;
+                       device_type = "mdio";
+@@ -540,7 +540,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio5: mdio@0x8c17000 {
++              pcs_mdio5: mdio@8c17000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c17000 0x0 0x1000>;
+                       device_type = "mdio";
+@@ -550,7 +550,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio6: mdio@0x8c1b000 {
++              pcs_mdio6: mdio@8c1b000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c1b000 0x0 0x1000>;
+                       device_type = "mdio";
+@@ -560,7 +560,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio7: mdio@0x8c1f000 {
++              pcs_mdio7: mdio@8c1f000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c1f000 0x0 0x1000>;
+                       device_type = "mdio";
+@@ -570,7 +570,7 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio8: mdio@0x8c23000 {
++              pcs_mdio8: mdio@8c23000 {
+                       compatible = "fsl,fman-memac-mdio";
+                       reg = <0x0 0x8c23000 0x0 0x1000>;
+                       device_type = "mdio";
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0052-arm64-dts-fsl-layerscape-fix-warnings-when-compiling.patch b/target/linux/layerscape/patches-5.4/302-dts-0052-arm64-dts-fsl-layerscape-fix-warnings-when-compiling.patch
new file mode 100644 (file)
index 0000000..bfe9ce6
--- /dev/null
@@ -0,0 +1,114 @@
+From 92aff696c8708ff5293eb000e98456e23afe1cb3 Mon Sep 17 00:00:00 2001
+From: Pankaj Bansal <pankaj.bansal@nxp.com>
+Date: Mon, 22 Apr 2019 16:43:13 +0530
+Subject: [PATCH] arm64: dts: fsl: layerscape: fix warnings when compiling dts
+ files
+
+when compiling dts file using DTC_FLAG='-@', the device tree compiler
+reports these warnings:
+
+Warning (alias_paths): /aliases: aliases property name must include
+only lowercase and '-'
+
+Fixed the node aliases to silence these warnings.
+
+Signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts | 34 +++++++++++------------
+ arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts | 28 +++++++++----------
+ 2 files changed, 31 insertions(+), 31 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts
+@@ -3,7 +3,7 @@
+  * Device Tree Include file for Freescale Layerscape-1043A family SoC.
+  *
+  * Copyright 2014-2015 Freescale Semiconductor, Inc.
+- * Copyright 2018 NXP
++ * Copyright 2018-2019 NXP
+  *
+  * Mingkai Hu <Mingkai.hu@freescale.com>
+  */
+@@ -24,22 +24,22 @@
+               serial1 = &duart1;
+               serial2 = &duart2;
+               serial3 = &duart3;
+-              sgmii_riser_s1_p1 = &sgmii_phy_s1_p1;
+-              sgmii_riser_s2_p1 = &sgmii_phy_s2_p1;
+-              sgmii_riser_s3_p1 = &sgmii_phy_s3_p1;
+-              sgmii_riser_s4_p1 = &sgmii_phy_s4_p1;
+-              qsgmii_s1_p1 = &qsgmii_phy_s1_p1;
+-              qsgmii_s1_p2 = &qsgmii_phy_s1_p2;
+-              qsgmii_s1_p3 = &qsgmii_phy_s1_p3;
+-              qsgmii_s1_p4 = &qsgmii_phy_s1_p4;
+-              qsgmii_s2_p1 = &qsgmii_phy_s2_p1;
+-              qsgmii_s2_p2 = &qsgmii_phy_s2_p2;
+-              qsgmii_s2_p3 = &qsgmii_phy_s2_p3;
+-              qsgmii_s2_p4 = &qsgmii_phy_s2_p4;
+-              emi1_slot1 = &ls1043mdio_s1;
+-              emi1_slot2 = &ls1043mdio_s2;
+-              emi1_slot3 = &ls1043mdio_s3;
+-              emi1_slot4 = &ls1043mdio_s4;
++              sgmii-riser-s1-p1 = &sgmii_phy_s1_p1;
++              sgmii-riser-s2-p1 = &sgmii_phy_s2_p1;
++              sgmii-riser-s3-p1 = &sgmii_phy_s3_p1;
++              sgmii-riser-s4-p1 = &sgmii_phy_s4_p1;
++              qsgmii-s1-p1 = &qsgmii_phy_s1_p1;
++              qsgmii-s1-p2 = &qsgmii_phy_s1_p2;
++              qsgmii-s1-p3 = &qsgmii_phy_s1_p3;
++              qsgmii-s1-p4 = &qsgmii_phy_s1_p4;
++              qsgmii-s2-p1 = &qsgmii_phy_s2_p1;
++              qsgmii-s2-p2 = &qsgmii_phy_s2_p2;
++              qsgmii-s2-p3 = &qsgmii_phy_s2_p3;
++              qsgmii-s2-p4 = &qsgmii_phy_s2_p4;
++              emi1-slot1 = &ls1043mdio_s1;
++              emi1-slot2 = &ls1043mdio_s2;
++              emi1-slot3 = &ls1043mdio_s3;
++              emi1-slot4 = &ls1043mdio_s4;
+       };
+       chosen {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts
+@@ -3,7 +3,7 @@
+  * Device Tree Include file for Freescale Layerscape-1046A family SoC.
+  *
+  * Copyright 2016 Freescale Semiconductor, Inc.
+- * Copyright 2018 NXP
++ * Copyright 2018-2019 NXP
+  *
+  * Shaohui Xie <Shaohui.Xie@nxp.com>
+  */
+@@ -26,19 +26,19 @@
+               serial2 = &duart2;
+               serial3 = &duart3;
+-              emi1_slot1 = &ls1046mdio_s1;
+-              emi1_slot2 = &ls1046mdio_s2;
+-              emi1_slot4 = &ls1046mdio_s4;
+-
+-              sgmii_s1_p1 = &sgmii_phy_s1_p1;
+-              sgmii_s1_p2 = &sgmii_phy_s1_p2;
+-              sgmii_s1_p3 = &sgmii_phy_s1_p3;
+-              sgmii_s1_p4 = &sgmii_phy_s1_p4;
+-              sgmii_s4_p1 = &sgmii_phy_s4_p1;
+-              qsgmii_s2_p1 = &qsgmii_phy_s2_p1;
+-              qsgmii_s2_p2 = &qsgmii_phy_s2_p2;
+-              qsgmii_s2_p3 = &qsgmii_phy_s2_p3;
+-              qsgmii_s2_p4 = &qsgmii_phy_s2_p4;
++              emi1-slot1 = &ls1046mdio_s1;
++              emi1-slot2 = &ls1046mdio_s2;
++              emi1-slot4 = &ls1046mdio_s4;
++
++              sgmii-s1-p1 = &sgmii_phy_s1_p1;
++              sgmii-s1-p2 = &sgmii_phy_s1_p2;
++              sgmii-s1-p3 = &sgmii_phy_s1_p3;
++              sgmii-s1-p4 = &sgmii_phy_s1_p4;
++              sgmii-s4-p1 = &sgmii_phy_s4_p1;
++              qsgmii-s2-p1 = &qsgmii_phy_s2_p1;
++              qsgmii-s2-p2 = &qsgmii_phy_s2_p2;
++              qsgmii-s2-p3 = &qsgmii_phy_s2_p3;
++              qsgmii-s2-p4 = &qsgmii_phy_s2_p4;
+       };
+       chosen {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0053-sdk-arm64-dts-nxp-add-DPAA1-SDK-flavor-dts-files.patch b/target/linux/layerscape/patches-5.4/302-dts-0053-sdk-arm64-dts-nxp-add-DPAA1-SDK-flavor-dts-files.patch
new file mode 100644 (file)
index 0000000..1e1b805
--- /dev/null
@@ -0,0 +1,187 @@
+From 13fdde4dfdccd567ae459db6e439a53496732748 Mon Sep 17 00:00:00 2001
+From: Pramod Kumar <pramod.kumar_1@nxp.com>
+Date: Wed, 8 May 2019 18:25:16 +0530
+Subject: [PATCH] sdk: arm64: dts: nxp: add DPAA1 SDK flavor dts files
+
+dts fsl-ls1046a-frwy-sdk.dts which enables sdk specific entries
+dts fsl-ls1046a-frwy-usdpaa.dts which enables dpdk
+
+Signed-off-by: Vabhav Sharma <vabhav.sharma@nxp.com>
+Signed-off-by: Pramod Kumar <pramod.kumar_1@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/Makefile             |  2 +
+ .../boot/dts/freescale/fsl-ls1046a-frwy-sdk.dts    | 53 ++++++++++++
+ .../boot/dts/freescale/fsl-ls1046a-frwy-usdpaa.dts | 99 ++++++++++++++++++++++
+ 3 files changed, 154 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-sdk.dts
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-usdpaa.dts
+
+--- a/arch/arm64/boot/dts/freescale/Makefile
++++ b/arch/arm64/boot/dts/freescale/Makefile
+@@ -13,6 +13,8 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-sdk.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-usdpaa.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-frwy.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-frwy-sdk.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-frwy-usdpaa.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds-sdk.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb.dtb
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-sdk.dts
+@@ -0,0 +1,53 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree Include file for Freescale Layerscape-1046A family SoC.
++ *
++ * Copyright 2019 NXP.
++ *
++ */
++
++#include "fsl-ls1046a-frwy.dts"
++#include "qoriq-qman-portals-sdk.dtsi"
++#include "qoriq-bman-portals-sdk.dtsi"
++
++&bman_fbpr {
++      compatible = "fsl,bman-fbpr";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++&qman_fqd {
++      compatible = "fsl,qman-fqd";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++&qman_pfdr {
++      compatible = "fsl,qman-pfdr";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++
++&soc {
++#include "qoriq-dpaa-eth.dtsi"
++#include "qoriq-fman3-0-6oh.dtsi"
++};
++
++&fsldpaa {
++      ethernet@1 {
++              status = "disabled";
++      };
++      ethernet@2 {
++              status = "disabled";
++      };
++      ethernet@3 {
++              status = "disabled";
++      };
++      ethernet@6 {
++              status = "disabled";
++      };
++      ethernet@9 {
++              compatible = "fsl,dpa-ethernet";
++              fsl,fman-mac = <&enet7>;
++              dma-coherent;
++      };
++};
++
++&fman0 {
++      compatible = "fsl,fman", "simple-bus";
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-usdpaa.dts
+@@ -0,0 +1,99 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree Include file for Freescale Layerscape-1046A family SoC.
++ *
++ * Copyright 2019 NXP.
++ *
++ */
++
++#include "fsl-ls1046a-frwy-sdk.dts"
++
++&soc {
++      bp7: buffer-pool@7 {
++              compatible = "fsl,ls1046a-bpool", "fsl,bpool";
++              fsl,bpid = <7>;
++              fsl,bpool-ethernet-cfg = <0 0 0 192 0 0xdeadbeef>;
++              fsl,bpool-thresholds = <0x400 0xc00 0x0 0x0>;
++      };
++
++      bp8: buffer-pool@8 {
++              compatible = "fsl,ls1046a-bpool", "fsl,bpool";
++              fsl,bpid = <8>;
++              fsl,bpool-ethernet-cfg = <0 0 0 576 0 0xabbaf00d>;
++              fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>;
++      };
++
++      bp9: buffer-pool@9 {
++              compatible = "fsl,ls1046a-bpool", "fsl,bpool";
++              fsl,bpid = <9>;
++              fsl,bpool-ethernet-cfg = <0 0 0 2048 0 0xfeedabba>;
++              fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>;
++      };
++
++      fsl,dpaa {
++              compatible = "fsl,ls1046a", "fsl,dpaa", "simple-bus";
++
++              ethernet@0 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x50 1 0x51 1>;
++                      fsl,qman-frame-queues-tx = <0x70 1 0x71 1>;
++              };
++
++              ethernet@4 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x52 1 0x53 1>;
++                      fsl,qman-frame-queues-tx = <0x72 1 0x73 1>;
++              };
++
++              ethernet@5 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x54 1 0x55 1>;
++                      fsl,qman-frame-queues-tx = <0x74 1 0x75 1>;
++              };
++
++              ethernet@9 {
++                      compatible = "fsl,dpa-ethernet-init";
++                      fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>;
++                      fsl,qman-frame-queues-rx = <0x56 1 0x57 1>;
++                      fsl,qman-frame-queues-tx = <0x76 1 0x77 1>;
++              };
++
++              dpa-fman0-oh@2 {
++                      compatible = "fsl,dpa-oh";
++                      /* Define frame queues for the OH port*/
++                      /* <OH Rx error, OH Rx default> */
++                      fsl,qman-frame-queues-oh = <0x60 1 0x61 1>;
++                      fsl,fman-oh-port = <&fman0_oh2>;
++              };
++      };
++};
++/ {
++      reserved-memory {
++              #address-cells = <2>;
++              #size-cells = <2>;
++              ranges;
++              /* For legacy usdpaa based use-cases, update the size and
++                 alignment parameters. e.g. to allocate 256 MB memory:
++                 size = <0 0x10000000>;
++                 alignment = <0 0x10000000>;
++              */
++
++              usdpaa_mem: usdpaa_mem {
++                      compatible = "fsl,usdpaa-mem";
++                      alloc-ranges = <0 0 0x10000 0>;
++                      size = <0 0x1000>;
++                      alignment = <0 0x1000>;
++              };
++      };
++};
++
++&fman0 {
++      fman0_oh2: port@83000 {
++              cell-index = <1>;
++              compatible = "fsl,fman-port-oh";
++              reg = <0x83000 0x1000>;
++      };
++};
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0054-arm64-dts-nxp-frwy-ls1046a-add-support-for-micron-no.patch b/target/linux/layerscape/patches-5.4/302-dts-0054-arm64-dts-nxp-frwy-ls1046a-add-support-for-micron-no.patch
new file mode 100644 (file)
index 0000000..bb30049
--- /dev/null
@@ -0,0 +1,40 @@
+From 3c013ab682fe1e6ca0473141f03f26e2f47980ad Mon Sep 17 00:00:00 2001
+From: Pramod Kumar <pramod.kumar_1@nxp.com>
+Date: Fri, 10 May 2019 14:33:37 +0530
+Subject: [PATCH] arm64: dts: nxp: frwy-ls1046a: add support for micron nor
+ flash
+
+add micron nor flash support for ls1046a frwy board.
+
+Signed-off-by: Ashish Kumar <ashish.kumar@nxp.com>
+Signed-off-by: Pramod Kumar <pramod.kumar_1@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy.dts | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy.dts
+@@ -112,6 +112,23 @@
+ };
++
++&qspi {
++      num-cs = <1>;
++      bus-num = <0>;
++      status = "okay";
++
++      qflash0: flash@0 {
++              compatible = "jedec,spi-nor";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              spi-max-frequency = <50000000>;
++              reg = <0>;
++              spi-rx-bus-width = <4>;
++              spi-tx-bus-width = <4>;
++      };
++};
++
+ #include "fsl-ls1046-post.dtsi"
+ &fman0 {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0055-arm64-dts-ls1028a-Add-PCIe-controller-DT-nodes.patch b/target/linux/layerscape/patches-5.4/302-dts-0055-arm64-dts-ls1028a-Add-PCIe-controller-DT-nodes.patch
new file mode 100644 (file)
index 0000000..739f00e
--- /dev/null
@@ -0,0 +1,71 @@
+From 25291f86f449c4488a0a46b1e6b3ce3b83dbf1f9 Mon Sep 17 00:00:00 2001
+From: Xiaowei Bao <xiaowei.bao@nxp.com>
+Date: Wed, 15 May 2019 10:14:30 +0800
+Subject: [PATCH] arm64: dts: ls1028a: Add PCIe controller DT nodes
+
+LS1028a implements 2 PCIe 3.0 controllers.
+
+Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 50 ++++++++++++++++++++++++++
+ 1 file changed, 50 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -631,6 +631,56 @@
+                       };
+               };
++              pcie@3400000 {
++                      compatible = "fsl,ls1028a-pcie";
++                      reg = <0x00 0x03400000 0x0 0x00100000   /* controller registers */
++                             0x80 0x00000000 0x0 0x00002000>; /* configuration space */
++                      reg-names = "regs", "config";
++                      interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>, /* PME interrupt */
++                                   <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>; /* aer interrupt */
++                      interrupt-names = "pme", "aer";
++                      #address-cells = <3>;
++                      #size-cells = <2>;
++                      device_type = "pci";
++                      dma-coherent;
++                      bus-range = <0x0 0xff>;
++                      ranges = <0x81000000 0x0 0x00000000 0x80 0x00010000 0x0 0x00010000   /* downstream I/O */
++                                0x82000000 0x0 0x40000000 0x80 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
++                      msi-parent = <&its>;
++                      #interrupt-cells = <1>;
++                      interrupt-map-mask = <0 0 0 7>;
++                      interrupt-map = <0000 0 0 1 &gic GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 2 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 3 &gic GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 4 &gic GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
++              pcie@3500000 {
++                      compatible = "fsl,ls1028a-pcie";
++                      reg = <0x00 0x03500000 0x0 0x00100000   /* controller registers */
++                             0x88 0x00000000 0x0 0x00002000>; /* configuration space */
++                      reg-names = "regs", "config";
++                      interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
++                      interrupt-names = "pme", "aer";
++                      #address-cells = <3>;
++                      #size-cells = <2>;
++                      device_type = "pci";
++                      dma-coherent;
++                      bus-range = <0x0 0xff>;
++                      ranges = <0x81000000 0x0 0x00000000 0x88 0x00010000 0x0 0x00010000   /* downstream I/O */
++                                0x82000000 0x0 0x40000000 0x88 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
++                      msi-parent = <&its>;
++                      #interrupt-cells = <1>;
++                      interrupt-map-mask = <0 0 0 7>;
++                      interrupt-map = <0000 0 0 1 &gic GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 2 &gic GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 3 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 4 &gic GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++                      status = "disabled";
++              };
++
+               pcie@1f0000000 { /* Integrated Endpoint Root Complex */
+                       compatible = "pci-host-ecam-generic";
+                       reg = <0x01 0xf0000000 0x0 0x100000>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0056-arm64-dts-lx2160a-Enable-usb3-lpm-capable-for-usb3-n.patch b/target/linux/layerscape/patches-5.4/302-dts-0056-arm64-dts-lx2160a-Enable-usb3-lpm-capable-for-usb3-n.patch
new file mode 100644 (file)
index 0000000..1f8a9e6
--- /dev/null
@@ -0,0 +1,34 @@
+From 74f9f7ee3f4b2e88bd29e7ac3dbc6a8ffe2e97f9 Mon Sep 17 00:00:00 2001
+From: Ran Wang <ran.wang_1@nxp.com>
+Date: Wed, 15 May 2019 13:33:49 +0800
+Subject: [PATCH] arm64: dts: lx2160a: Enable usb3-lpm-capable for usb3 node
+
+Enable USB3 HW LPM feature for lx2160a and active patch for
+snps erratum A-010131. It will disable U1/U2 temperary when
+initiate U3 request.
+
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -843,6 +843,8 @@
+                       interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+                       dr_mode = "host";
+                       snps,quirk-frame-length-adjustment = <0x20>;
++                      usb3-lpm-capable;
++                      snps,dis-u1u2-when-u3-quirk;
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                       snps,host-vbus-glitches;
+@@ -855,6 +857,8 @@
+                       interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+                       dr_mode = "host";
+                       snps,quirk-frame-length-adjustment = <0x20>;
++                      usb3-lpm-capable;
++                      snps,dis-u1u2-when-u3-quirk;
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                       snps,host-vbus-glitches;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0057-arm64-dts-fsl-lx2160a-add-flexcan-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0057-arm64-dts-fsl-lx2160a-add-flexcan-node.patch
new file mode 100644 (file)
index 0000000..c85139f
--- /dev/null
@@ -0,0 +1,103 @@
+From c2046901f933b0e1c87c5cbdab4ba27a3b66317e Mon Sep 17 00:00:00 2001
+From: Pankaj Bansal <pankaj.bansal@nxp.com>
+Date: Wed, 8 May 2019 17:49:14 +0530
+Subject: [PATCH] arm64: dts: fsl: lx2160a: add flexcan node
+
+Add flexcan node in LX2160A SOC file as well as in QDS and RDB files.
+The device tree bindings used can be referred from
+Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
+
+Signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts | 10 +++++++++-
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts | 18 +++++++++++++++++-
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi    | 18 ++++++++++++++++++
+ 3 files changed, 44 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
+@@ -2,7 +2,7 @@
+ //
+ // Device Tree file for LX2160AQDS
+ //
+-// Copyright 2018 NXP
++// Copyright 2018-2019 NXP
+ /dts-v1/;
+@@ -155,6 +155,14 @@
+       };
+ };
++&can0 {
++      status = "okay";
++};
++
++&can1 {
++      status = "okay";
++};
++
+ &crypto {
+       status = "okay";
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
+@@ -2,7 +2,7 @@
+ //
+ // Device Tree file for LX2160ARDB
+ //
+-// Copyright 2018 NXP
++// Copyright 2018-2019 NXP
+ /dts-v1/;
+@@ -31,6 +31,22 @@
+       };
+ };
++&can0 {
++      status = "okay";
++
++      can-transceiver {
++              max-bitrate = <5000000>;
++      };
++};
++
++&can1 {
++      status = "okay";
++
++      can-transceiver {
++              max-bitrate = <5000000>;
++      };
++};
++
+ &crypto {
+       status = "okay";
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -753,6 +753,24 @@
+                       status = "disabled";
+               };
++              can0: can@2180000 {
++                      compatible = "fsl,lx2160ar1-flexcan";
++                      reg = <0x0 0x2180000 0x0 0x10000>;
++                      interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&sysclk>, <&clockgen 4 7>;
++                      clock-names = "ipg", "per";
++                      status = "disabled";
++              };
++
++              can1: can@2190000 {
++                      compatible = "fsl,lx2160ar1-flexcan";
++                      reg = <0x0 0x2190000 0x0 0x10000>;
++                      interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&sysclk>, <&clockgen 4 7>;
++                      clock-names = "ipg", "per";
++                      status = "disabled";
++              };
++
+               uart0: serial@21c0000 {
+                       compatible = "arm,sbsa-uart","arm,pl011";
+                       reg = <0x0 0x21c0000 0x0 0x1000>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0058-arm64-dts-fsl-ls1028a-add-flexcan-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0058-arm64-dts-fsl-ls1028a-add-flexcan-node.patch
new file mode 100644 (file)
index 0000000..dbd7ec8
--- /dev/null
@@ -0,0 +1,114 @@
+From 3724107421d95c5a46b19b950b04de2a05c1f757 Mon Sep 17 00:00:00 2001
+From: Pankaj Bansal <pankaj.bansal@nxp.com>
+Date: Wed, 8 May 2019 17:49:14 +0530
+Subject: [PATCH] arm64: dts: fsl: ls1028a: add flexcan node
+
+Add flexcan node in LS1028A SOC file as well as in QDS and RDB files.
+The device tree bindings used can be referred from
+Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
+
+Signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts | 10 +++++++++-
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts | 18 +++++++++++++++++-
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi    | 22 +++++++++++++++++++++-
+ 3 files changed, 47 insertions(+), 3 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
+@@ -2,7 +2,7 @@
+ /*
+  * Device Tree file for NXP LS1028A QDS Board.
+  *
+- * Copyright 2018 NXP
++ * Copyright 2018-2019 NXP
+  *
+  * Harninder Rai <harninder.rai@nxp.com>
+  *
+@@ -107,6 +107,14 @@
+       };
+ };
++&can0 {
++      status = "okay";
++};
++
++&can1 {
++      status = "okay";
++};
++
+ &duart0 {
+       status = "okay";
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
+@@ -2,7 +2,7 @@
+ /*
+  * Device Tree file for NXP LS1028A RDB Board.
+  *
+- * Copyright 2018 NXP
++ * Copyright 2018-2019 NXP
+  *
+  * Harninder Rai <harninder.rai@nxp.com>
+  *
+@@ -152,6 +152,22 @@
+       };
+ };
++&can0 {
++      status = "okay";
++
++      can-transceiver {
++              max-bitrate = <5000000>;
++      };
++};
++
++&can1 {
++      status = "okay";
++
++      can-transceiver {
++              max-bitrate = <5000000>;
++      };
++};
++
+ &duart0 {
+       status = "okay";
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -2,7 +2,7 @@
+ /*
+  * Device Tree Include file for NXP Layerscape-1028A family SoC.
+  *
+- * Copyright 2018 NXP
++ * Copyright 2018-2019 NXP
+  *
+  * Harninder Rai <harninder.rai@nxp.com>
+  *
+@@ -287,6 +287,26 @@
+                       status = "disabled";
+               };
++              can0: can@2180000 {
++                      compatible = "fsl,ls1028ar1-flexcan",
++                                   "fsl,lx2160ar1-flexcan";
++                      reg = <0x0 0x2180000 0x0 0x10000>;
++                      interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&sysclk>, <&clockgen 4 1>;
++                      clock-names = "ipg", "per";
++                      status = "disabled";
++              };
++
++              can1: can@2190000 {
++                      compatible = "fsl,ls1028ar1-flexcan",
++                                   "fsl,lx2160ar1-flexcan";
++                      reg = <0x0 0x2190000 0x0 0x10000>;
++                      interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&sysclk>, <&clockgen 4 1>;
++                      clock-names = "ipg", "per";
++                      status = "disabled";
++              };
++
+               duart0: serial@21c0500 {
+                       compatible = "fsl,ns16550", "ns16550a";
+                       reg = <0x00 0x21c0500 0x0 0x100>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0059-arm64-dts-fsl-ls1046-Modify-the-qspi-flash-frequency.patch b/target/linux/layerscape/patches-5.4/302-dts-0059-arm64-dts-fsl-ls1046-Modify-the-qspi-flash-frequency.patch
new file mode 100644 (file)
index 0000000..71ead4b
--- /dev/null
@@ -0,0 +1,55 @@
+From 0a4e4723a1765770bb04ec4a5ad427b2c97627b6 Mon Sep 17 00:00:00 2001
+From: Pankaj Bansal <pankaj.bansal@nxp.com>
+Date: Tue, 21 May 2019 20:26:29 +0530
+Subject: [PATCH] arm64: dts: fsl: ls1046: Modify the qspi flash frequency
+
+The qspi flash in ls1046a based QDS and RDB boards can operate
+at 50MHz frequency.
+Therefore, update the maximum supported freq in their respective
+dts files.
+
+Signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts | 2 +-
+ arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts | 5 +++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts
+@@ -184,7 +184,7 @@
+               compatible = "spansion,m25p80";
+               #address-cells = <1>;
+               #size-cells = <1>;
+-              spi-max-frequency = <20000000>;
++              spi-max-frequency = <50000000>;
+               spi-rx-bus-width = <4>;
+               spi-tx-bus-width = <4>;
+               reg = <0>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts
+@@ -3,6 +3,7 @@
+  * Device Tree Include file for Freescale Layerscape-1046A family SoC.
+  *
+  * Copyright 2016 Freescale Semiconductor, Inc.
++ * Copyright 2019 NXP
+  *
+  * Mingkai Hu <mingkai.hu@nxp.com>
+  */
+@@ -106,7 +107,7 @@
+               compatible = "spansion,m25p80";
+               #address-cells = <1>;
+               #size-cells = <1>;
+-              spi-max-frequency = <20000000>;
++              spi-max-frequency = <50000000>;
+               spi-rx-bus-width = <4>;
+               spi-tx-bus-width = <4>;
+               reg = <0>;
+@@ -116,7 +117,7 @@
+               compatible = "spansion,m25p80";
+               #address-cells = <1>;
+               #size-cells = <1>;
+-              spi-max-frequency = <20000000>;
++              spi-max-frequency = <50000000>;
+               spi-rx-bus-width = <4>;
+               spi-tx-bus-width = <4>;
+               reg = <1>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0060-arm64-dts-ls1028a-add-flexspi-nodes.patch b/target/linux/layerscape/patches-5.4/302-dts-0060-arm64-dts-ls1028a-add-flexspi-nodes.patch
new file mode 100644 (file)
index 0000000..3f7dc5b
--- /dev/null
@@ -0,0 +1,87 @@
+From b94cbaaa2facfdc6aa49d6f323da251f9e91d4ba Mon Sep 17 00:00:00 2001
+From: Xiaowei Bao <xiaowei.bao@nxp.com>
+Date: Tue, 14 May 2019 18:17:31 +0800
+Subject: [PATCH] arm64: dts: ls1028a: add flexspi nodes
+
+Add fspi node property for LS1028A SoC for FlexSPI driver.
+Property added for the FlexSPI controller and for the connected
+slave device for the LS1028ARDB and LS1028AQDS target.
+This is having one SPI-NOR flash device, mt35xu02g connected at
+CS0.
+
+Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts | 15 +++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts | 15 +++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi    | 12 ++++++++++++
+ 3 files changed, 42 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
+@@ -222,6 +222,21 @@
+       phy-connection-type = "rgmii-id";
+ };
++&fspi {
++      status = "okay";
++      mt35xu02g: flash@0 {
++              compatible = "spansion,m25p80";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              m25p,fast-read;
++              spi-max-frequency = <20000000>;
++              reg = <0>;
++              /* The following setting enables 1-1-8 (CMD-ADDR-DATA) mode */
++              spi-rx-bus-width = <8>; /* 8 SPI Rx lines */
++              spi-tx-bus-width = <1>; /* 1 SPI Tx line */
++      };
++};
++
+ &sai1 {
+       status = "okay";
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
+@@ -168,6 +168,21 @@
+       };
+ };
++&fspi {
++      status = "okay";
++      mt35xu02g: flash@0 {
++              compatible = "spansion,m25p80";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              m25p,fast-read;
++              spi-max-frequency = <20000000>;
++              reg = <0>;
++              /* The following setting enables 1-1-8 (CMD-ADDR-DATA) mode */
++              spi-rx-bus-width = <8>; /* 8 SPI Rx lines */
++              spi-tx-bus-width = <1>; /* 1 SPI Tx line */
++      };
++};
++
+ &duart0 {
+       status = "okay";
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -180,6 +180,18 @@
+                       clocks = <&sysclk>;
+               };
++              fspi: spi@20c0000 {
++                      compatible = "nxp,lx2160a-fspi";
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      reg = <0x0 0x20c0000 0x0 0x10000>,
++                            <0x0 0x20000000 0x0 0x10000000>;
++                      reg-names = "FSPI", "FSPI-memory";
++                      interrupts = <0 25 0x4>; /* Level high type */
++                      clocks = <&clockgen 4 3>, <&clockgen 4 3>;
++                      clock-names = "fspi_en", "fspi";
++              };
++
+               i2c0: i2c@2000000 {
+                       compatible = "fsl,vf610-i2c";
+                       #address-cells = <1>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0061-sdk-dts-ls1046-drop-smmu-from-the-frwy-sdk-dtses.patch b/target/linux/layerscape/patches-5.4/302-dts-0061-sdk-dts-ls1046-drop-smmu-from-the-frwy-sdk-dtses.patch
new file mode 100644 (file)
index 0000000..a29ca75
--- /dev/null
@@ -0,0 +1,61 @@
+From 68148cb462754f0f79b77aa56ea0e8ec899ead36 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 28 May 2019 13:35:56 +0300
+Subject: [PATCH] sdk: dts: ls1046: drop smmu from the frwy sdk dtses
+
+Drop the smmu from the frwy and frwy-usdpaa versions of the SDK device
+trees because SMMU is supported only for the upstream version of the
+dpaa ethernet drivers.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-sdk.dts    | 14 ++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-usdpaa.dts | 14 ++++++++++++++
+ 2 files changed, 28 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-sdk.dts
+@@ -26,6 +26,20 @@
+ &soc {
+ #include "qoriq-dpaa-eth.dtsi"
+ #include "qoriq-fman3-0-6oh.dtsi"
++
++      pcie@3400000 {
++              /delete-property/ iommu-map;
++      };
++
++      pcie@3500000 {
++              /delete-property/ iommu-map;
++      };
++
++      pcie@3600000 {
++              /delete-property/ iommu-map;
++      };
++
++      /delete-node/ iommu@9000000;
+ };
+ &fsldpaa {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-usdpaa.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-usdpaa.dts
+@@ -69,6 +69,20 @@
+                       fsl,fman-oh-port = <&fman0_oh2>;
+               };
+       };
++
++      pcie@3400000 {
++              /delete-property/ iommu-map;
++      };
++
++      pcie@3500000 {
++              /delete-property/ iommu-map;
++      };
++
++      pcie@3600000 {
++              /delete-property/ iommu-map;
++      };
++
++      /delete-node/ iommu@9000000;
+ };
+ / {
+       reserved-memory {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0062-sdk-dts-ls1046frwy-move-dma-coherent-from-soc-to-its.patch b/target/linux/layerscape/patches-5.4/302-dts-0062-sdk-dts-ls1046frwy-move-dma-coherent-from-soc-to-its.patch
new file mode 100644 (file)
index 0000000..c2e0873
--- /dev/null
@@ -0,0 +1,235 @@
+From 7d5fcedd45e066db0d2735a753a86af31ba44722 Mon Sep 17 00:00:00 2001
+From: Ran Wang <ran.wang_1@nxp.com>
+Date: Wed, 29 May 2019 16:18:06 +0800
+Subject: [PATCH] sdk: dts: ls1046frwy move dma-coherent from soc to its child
+ nodes
+
+Since SMMU is not supported for SDK version, USB function will down if
+still apply property 'dma-coherent' in scope of soc (USB driver is not
+ready to support it alone) in SDK device trees, decide to remove it.
+And add dma-coherent on other non-USB child nodes under soc.
+
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+---
+ .../boot/dts/freescale/fsl-ls1046a-frwy-sdk.dts    | 174 +++++++++++++++++++++
+ .../boot/dts/freescale/fsl-ls1046a-frwy-usdpaa.dts |   4 +
+ 2 files changed, 178 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-sdk.dts
+@@ -24,6 +24,8 @@
+ };
+ &soc {
++/delete-property/ dma-coherent;
++
+ #include "qoriq-dpaa-eth.dtsi"
+ #include "qoriq-fman3-0-6oh.dtsi"
+@@ -65,3 +67,175 @@
+ &fman0 {
+       compatible = "fsl,fman", "simple-bus";
+ };
++
++&clockgen {
++      dma-coherent;
++};
++
++&scfg {
++      dma-coherent;
++};
++
++&crypto {
++      dma-coherent;
++};
++
++&dcfg {
++      dma-coherent;
++};
++
++&ifc {
++      dma-coherent;
++};
++
++&qspi {
++      dma-coherent;
++};
++
++&esdhc {
++      dma-coherent;
++};
++
++&ddr {
++      dma-coherent;
++};
++
++&tmu {
++      dma-coherent;
++};
++
++&qman {
++      dma-coherent;
++};
++
++&bman {
++      dma-coherent;
++};
++
++&bportals {
++      dma-coherent;
++};
++
++&qportals {
++      dma-coherent;
++};
++
++&dspi {
++      dma-coherent;
++};
++
++&i2c0 {
++      dma-coherent;
++};
++
++&i2c1 {
++      dma-coherent;
++};
++
++&i2c2 {
++      dma-coherent;
++};
++
++&i2c3 {
++      dma-coherent;
++};
++
++&duart0 {
++      dma-coherent;
++};
++
++&duart1 {
++      dma-coherent;
++};
++
++&duart2 {
++      dma-coherent;
++};
++
++&duart3 {
++      dma-coherent;
++};
++
++&gpio0 {
++      dma-coherent;
++};
++
++&gpio1 {
++      dma-coherent;
++};
++
++&gpio2 {
++      dma-coherent;
++};
++
++&gpio3 {
++      dma-coherent;
++};
++
++&lpuart0 {
++      dma-coherent;
++};
++
++&lpuart1 {
++      dma-coherent;
++};
++
++&lpuart2 {
++      dma-coherent;
++};
++
++&lpuart3 {
++      dma-coherent;
++};
++
++&lpuart4 {
++      dma-coherent;
++};
++
++&lpuart5 {
++      dma-coherent;
++};
++
++&ftm0 {
++      dma-coherent;
++};
++
++&wdog0 {
++      dma-coherent;
++};
++
++&edma0 {
++      dma-coherent;
++};
++
++&sata {
++      dma-coherent;
++};
++
++&qdma {
++      dma-coherent;
++};
++
++&msi1 {
++      dma-coherent;
++};
++
++&msi2 {
++      dma-coherent;
++};
++
++&msi3 {
++      dma-coherent;
++};
++
++&fman0 {
++      dma-coherent;
++};
++
++&ptp_timer0 {
++      dma-coherent;
++};
++
++&fsldpaa {
++      dma-coherent;
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-usdpaa.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-usdpaa.dts
+@@ -14,6 +14,7 @@
+               fsl,bpid = <7>;
+               fsl,bpool-ethernet-cfg = <0 0 0 192 0 0xdeadbeef>;
+               fsl,bpool-thresholds = <0x400 0xc00 0x0 0x0>;
++              dma-coherent;
+       };
+       bp8: buffer-pool@8 {
+@@ -21,6 +22,7 @@
+               fsl,bpid = <8>;
+               fsl,bpool-ethernet-cfg = <0 0 0 576 0 0xabbaf00d>;
+               fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>;
++              dma-coherent;
+       };
+       bp9: buffer-pool@9 {
+@@ -28,10 +30,12 @@
+               fsl,bpid = <9>;
+               fsl,bpool-ethernet-cfg = <0 0 0 2048 0 0xfeedabba>;
+               fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>;
++              dma-coherent;
+       };
+       fsl,dpaa {
+               compatible = "fsl,ls1046a", "fsl,dpaa", "simple-bus";
++              dma-coherent;
+               ethernet@0 {
+                       compatible = "fsl,dpa-ethernet-init";
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0063-arm64-dts-fsl-remove-backplane-support.patch b/target/linux/layerscape/patches-5.4/302-dts-0063-arm64-dts-fsl-remove-backplane-support.patch
new file mode 100644 (file)
index 0000000..875dfc2
--- /dev/null
@@ -0,0 +1,574 @@
+From 278bacf54eabe391159cef3112f8e8bf0fa7b891 Mon Sep 17 00:00:00 2001
+From: Florinel Iordache <florinel.iordache@nxp.com>
+Date: Mon, 27 May 2019 15:57:05 +0300
+Subject: [PATCH] arm64: dts: fsl: remove backplane support
+
+Remove entire backplane support from device tree for all supported platforms
+
+Signed-off-by: Florinel Iordache <florinel.iordache@nxp.com>
+---
+ .../boot/dts/freescale/fsl-ls1046a-qds-sdk.dts     |  4 -
+ .../boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts     | 34 --------
+ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi     |  5 --
+ arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts  | 26 -------
+ arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi     | 46 -----------
+ arch/arm64/boot/dts/freescale/fsl-ls2088a-qds.dts  | 58 --------------
+ arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi     | 90 ----------------------
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts  | 60 ---------------
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi     | 86 ---------------------
+ .../boot/dts/freescale/qoriq-fman3-0-10g-0.dtsi    |  4 +-
+ .../boot/dts/freescale/qoriq-fman3-0-10g-1.dtsi    |  4 +-
+ 11 files changed, 4 insertions(+), 413 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds-sdk.dts
+@@ -259,10 +259,6 @@ pcie@3600000 {
+       dma-coherent;
+ };
+-&serdes1 {
+-      dma-coherent;
+-};
+-
+ &fsldpaa {
+       dma-coherent;
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts
+@@ -100,36 +100,6 @@ pcie@3600000 {
+       compatible = "fsl,fman", "simple-bus";
+ };
+-&mdio9 {
+-      pcsphy6: ethernet-phy@0 {
+-              backplane-mode = "10gbase-kr";
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-              reg = <0x0>;
+-              fsl,lane-handle = <&serdes1>;
+-              fsl,lane-reg = <0x8C0 0x40>;   /* lane D */
+-      };
+-};
+-
+-&mdio10 {
+-      pcsphy7: ethernet-phy@0 {
+-              backplane-mode = "10gbase-kr";
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-              reg = <0x0>;
+-              fsl,lane-handle = <&serdes1>;
+-              fsl,lane-reg = <0x880 0x40>;   /* lane C */
+-      };
+-};
+-
+-/* Update MAC connections to backplane PHYs
+- * &mac9 {
+- *    phy-handle = <&pcsphy6>;
+- *};
+- *
+- *&mac10 {
+- *    phy-handle = <&pcsphy7>;
+- *};
+-*/
+-
+ &clockgen {
+       dma-coherent;
+ };
+@@ -298,10 +268,6 @@ pcie@3600000 {
+       dma-coherent;
+ };
+-&serdes1 {
+-      dma-coherent;
+-};
+-
+ &fsldpaa {
+       dma-coherent;
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+@@ -679,11 +679,6 @@
+                                    <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
+               };
+-              serdes1: serdes@1ea0000 {
+-                      reg = <0x0 0x1ea0000 0 0x00002000>;
+-                      compatible = "fsl,serdes-10g";
+-              };
+-
+               pcie@3400000 {
+                       compatible = "fsl,ls1046a-pcie";
+                       reg = <0x00 0x03400000 0x0 0x00100000   /* controller registers */
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts
+@@ -170,29 +170,3 @@
+ &sata {
+       status = "okay";
+ };
+-
+-&pcs_mdio1 {
+-              pcs_phy1: ethernet-phy@0 {
+-              backplane-mode = "10gbase-kr";
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-              reg = <0x0>;
+-              fsl,lane-handle = <&serdes1>;
+-              fsl,lane-reg = <0x840 0x40>;/* lane B */
+-      };
+-};
+-
+-&pcs_mdio2 {
+-              pcs_phy2: ethernet-phy@0 {
+-              backplane-mode = "10gbase-kr";
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-              reg = <0x0>;
+-              fsl,lane-handle = <&serdes1>;
+-              fsl,lane-reg = <0x800 0x40>;/* lane A */
+-      };
+-};
+-
+-/* Update DPMAC connections to backplane PHYs, under SerDes 0x1D_0xXX.
+- * &dpmac1 {
+- *    phy-handle = <&pcs_phy1>;
+- * };
+- */
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+@@ -183,12 +183,6 @@
+                       little-endian;
+               };
+-              serdes1: serdes@1ea0000 {
+-                              compatible = "fsl,serdes-10g";
+-                              reg = <0x0 0x1ea0000 0 0x00002000>;
+-                              little-endian;
+-              };
+-
+               tmu: tmu@1f80000 {
+                       compatible = "fsl,qoriq-tmu";
+                       reg = <0x0 0x1f80000 0x0 0x10000>;
+@@ -333,46 +327,6 @@
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+-              };
+-
+-              pcs_mdio1: mdio@8c07000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c07000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio2: mdio@8c0b000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c0b000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio3: mdio@8c0f000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c0f000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio4: mdio@8c13000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c13000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+               };
+               ifc: ifc@2240000 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls2088a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls2088a-qds.dts
+@@ -71,64 +71,6 @@
+       };
+ };
+-&pcs_mdio1 {
+-              pcs_phy1: ethernet-phy@0 {
+-              backplane-mode = "10gbase-kr";
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-              reg = <0x0>;
+-              fsl,lane-handle = <&serdes1>;
+-              fsl,lane-reg = <0x9C0 0x40>;/* lane H */
+-      };
+-};
+-
+-&pcs_mdio2 {
+-              pcs_phy2: ethernet-phy@0 {
+-              backplane-mode = "10gbase-kr";
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-              reg = <0x0>;
+-              fsl,lane-handle = <&serdes1>;
+-              fsl,lane-reg = <0x980 0x40>;/* lane G */
+-      };
+-};
+-
+-&pcs_mdio3 {
+-              pcs_phy3: ethernet-phy@0 {
+-              backplane-mode = "10gbase-kr";
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-              reg = <0x0>;
+-              fsl,lane-handle = <&serdes1>;
+-              fsl,lane-reg = <0x940 0x40>;/* lane F */
+-      };
+-};
+-
+-&pcs_mdio4 {
+-              pcs_phy4: ethernet-phy@0 {
+-              backplane-mode = "10gbase-kr";
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-              reg = <0x0>;
+-              fsl,lane-handle = <&serdes1>;
+-              fsl,lane-reg = <0x900 0x40>;/* lane E */
+-      };
+-};
+-
+-/* Update DPMAC connections to backplane PHYs, under SerDes 0x2a_0xXX.
+- * &dpmac1 {
+- *    phy-handle = <&pcs_phy1>;
+- * };
+- *
+- * &dpmac2 {
+- *    phy-handle = <&pcs_phy2>;
+- * };
+- *
+- * &dpmac3 {
+- *    phy-handle = <&pcs_phy3>;
+- * };
+- *
+- * &dpmac4 {
+- *    phy-handle = <&pcs_phy4>;
+- * };
+- */
+-
+ /* Update DPMAC connections to external PHYs, under SerDes 0x2a_0x49. */
+ &dpmac9 {
+       phy-handle = <&mdio0_phy12>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+@@ -550,90 +550,6 @@
+                       #size-cells = <0>;
+               };
+-              pcs_mdio1: mdio@8c07000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c07000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio2: mdio@8c0b000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c0b000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio3: mdio@8c0f000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c0f000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio4: mdio@8c13000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c13000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio5: mdio@8c17000 {
+-                      status = "disabled";
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c17000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio6: mdio@8c1b000 {
+-                      status = "disabled";
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c1b000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio7: mdio@8c1f000 {
+-                      status = "disabled";
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c1f000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio8: mdio@8c23000 {
+-                      status = "disabled";
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c23000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+               i2c0: i2c@2000000 {
+                       status = "disabled";
+                       compatible = "fsl,vf610-i2c", "fsl,ls208xa-vf610-i2c";
+@@ -835,12 +751,6 @@
+                       snps,host-vbus-glitches;
+               };
+-              serdes1: serdes@1ea0000 {
+-                              compatible = "fsl,serdes-10g";
+-                              reg = <0x0 0x1ea0000 0 0x00002000>;
+-                              little-endian;
+-              };
+-
+               ccn@4000000 {
+                       compatible = "arm,ccn-504";
+                       reg = <0x0 0x04000000 0x0 0x01000000>;
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
+@@ -316,46 +316,6 @@
+       status = "okay";
+ };
+-&pcs_mdio1 {
+-      pcs_phy1: ethernet-phy@0 {
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-              backplane-mode = "40gbase-kr";
+-              reg = <0x0>;
+-              fsl,lane-handle = <&serdes1>;
+-              fsl,lane-reg = <0xF00 0xE00 0xD00 0xC00>; /* lanes H, G, F, E */
+-      };
+-};
+-
+-&pcs_mdio2 {
+-      pcs_phy2: ethernet-phy@0 {
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-              backplane-mode = "40gbase-kr";
+-              reg = <0x0>;
+-              fsl,lane-handle = <&serdes1>;
+-              fsl,lane-reg = <0xB00 0xA00 0x900 0x800>; /* lanes D, C, B, A */
+-      };
+-};
+-
+-&pcs_mdio3 {
+-      pcs_phy3: ethernet-phy@0 {
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-              backplane-mode = "10gbase-kr";
+-              reg = <0x0>;
+-              fsl,lane-handle = <&serdes1>;
+-              fsl,lane-reg = <0xF00 0x100>; /* lane H */
+-      };
+-};
+-
+-&pcs_mdio4 {
+-      pcs_phy4: ethernet-phy@0 {
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-              backplane-mode = "10gbase-kr";
+-              reg = <0x0>;
+-              fsl,lane-handle = <&serdes1>;
+-              fsl,lane-reg = <0xE00 0x100>; /* lane G */
+-      };
+-};
+-
+ &sata0 {
+       status = "okay";
+ };
+@@ -371,23 +331,3 @@
+ &sata3 {
+       status = "okay";
+ };
+-
+-/* Update DPMAC connections to 40G backplane PHYs
+- * &dpmac1 {
+- *    phy-handle = <&pcs_phy1>;
+- * };
+- * 
+- * &dpmac2 {
+- *    phy-handle = <&pcs_phy2>;
+- * };
+- */
+-
+-/* Update DPMAC connections to 10G backplane PHYs
+- * &dpmac3 {
+- *    phy-handle = <&pcs_phy3>;
+- * };
+- * 
+- * &dpmac4 {
+- *    phy-handle = <&pcs_phy4>;
+- * };
+- */
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -500,92 +500,6 @@
+                       status = "disabled";
+               };
+-              pcs_mdio1: mdio@8c07000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c07000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio2: mdio@8c0b000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c0b000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio3: mdio@8c0f000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c0f000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio4: mdio@8c13000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c13000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio5: mdio@8c17000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c17000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio6: mdio@8c1b000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c1b000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio7: mdio@8c1f000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c1f000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              pcs_mdio8: mdio@8c23000 {
+-                      compatible = "fsl,fman-memac-mdio";
+-                      reg = <0x0 0x8c23000 0x0 0x1000>;
+-                      device_type = "mdio";
+-                      little-endian;
+-
+-                      #address-cells = <1>;
+-                      #size-cells = <0>;
+-              };
+-
+-              serdes1: serdes@1ea0000 {
+-                              compatible = "fsl,serdes-28g";
+-                              reg = <0x0 0x1ea0000 0 0x00002000>;
+-                              little-endian;
+-              };
+-
+               i2c0: i2c@2000000 {
+                       compatible = "fsl,vf610-i2c";
+                       #address-cells = <1>;
+--- a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-0.dtsi
++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-0.dtsi
+@@ -22,7 +22,7 @@ fman@1a00000 {
+               fsl,qman-channel-id = <0x800>;
+       };
+-      mac9: ethernet@f0000 {
++      ethernet@f0000 {
+               cell-index = <0x8>;
+               compatible = "fsl,fman-memac";
+               reg = <0xf0000 0x1000>;
+@@ -30,7 +30,7 @@ fman@1a00000 {
+               pcsphy-handle = <&pcsphy6>;
+       };
+-      mdio9: mdio@f1000 {
++      mdio@f1000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
+--- a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-1.dtsi
++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-1.dtsi
+@@ -22,7 +22,7 @@ fman@1a00000 {
+               fsl,qman-channel-id = <0x801>;
+       };
+-      mac10: ethernet@f2000 {
++      ethernet@f2000 {
+               cell-index = <0x9>;
+               compatible = "fsl,fman-memac";
+               reg = <0xf2000 0x1000>;
+@@ -30,7 +30,7 @@ fman@1a00000 {
+               pcsphy-handle = <&pcsphy7>;
+       };
+-      mdio10: mdio@f3000 {
++      mdio@f3000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0064-arm64-dts-lx2160a-update-interrupt-property-for-Aqua.patch b/target/linux/layerscape/patches-5.4/302-dts-0064-arm64-dts-lx2160a-update-interrupt-property-for-Aqua.patch
new file mode 100644 (file)
index 0000000..e5abac7
--- /dev/null
@@ -0,0 +1,31 @@
+From e463f4a9d933d2d62a065bba356a9eb04a9f3ac0 Mon Sep 17 00:00:00 2001
+From: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
+Date: Tue, 11 Jun 2019 23:53:45 +0300
+Subject: [PATCH] arm64: dts: lx2160a: update interrupt property for Aquantia
+ phy
+
+Update Aquantia AQR107 nodes interrupt property.
+
+Signed-off-by: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
+@@ -200,13 +200,13 @@
+       aquantia_phy1: ethernet-phy@4 {
+               /* AQR107 PHY - "compatible" property not strictly needed */
+               compatible = "ethernet-phy-ieee802.3-c45";
+-              interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
++              interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+               reg = <0x4>;
+       };
+       aquantia_phy2: ethernet-phy@5 {
+               /* AQR107 PHY - "compatible" property not strictly needed */
+               compatible = "ethernet-phy-ieee802.3-c45";
+-              interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
++              interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+               reg = <0x5>;
+       };
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0065-arm64-dts-ls1028a-Update-fspi-reg-properties.patch b/target/linux/layerscape/patches-5.4/302-dts-0065-arm64-dts-ls1028a-Update-fspi-reg-properties.patch
new file mode 100644 (file)
index 0000000..577dd37
--- /dev/null
@@ -0,0 +1,21 @@
+From bfd089c26a8b3c1eb83c94dc0f72c0f80fb7e5ef Mon Sep 17 00:00:00 2001
+From: Kuldeep Singh <kuldeep.singh@nxp.com>
+Date: Fri, 14 Jun 2019 12:34:14 +0530
+Subject: [PATCH] arm64: dts: ls1028a: Update fspi reg properties
+
+Signed-off-by: Kuldeep Singh <kuldeep.singh@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -186,7 +186,7 @@
+                       #size-cells = <0>;
+                       reg = <0x0 0x20c0000 0x0 0x10000>,
+                             <0x0 0x20000000 0x0 0x10000000>;
+-                      reg-names = "FSPI", "FSPI-memory";
++                      reg-names = "fspi_base", "fspi_mmap";
+                       interrupts = <0 25 0x4>; /* Level high type */
+                       clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+                       clock-names = "fspi_en", "fspi";
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0066-arm64-dts-ls1028a-add-gpu-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0066-arm64-dts-ls1028a-add-gpu-node.patch
new file mode 100644 (file)
index 0000000..a1b3823
--- /dev/null
@@ -0,0 +1,31 @@
+From 3e04a861ff536927ede8e826b7c4a5bf6a80dda7 Mon Sep 17 00:00:00 2001
+From: Yuantian Tang <andy.tang@nxp.com>
+Date: Tue, 18 Jun 2019 01:29:49 -0400
+Subject: [PATCH] arm64: dts: ls1028a: add gpu node
+
+Add GPU dts node to enable GPU feature.
+
+Signed-off-by: Yuantian Tang <andy.tang@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -538,6 +538,16 @@
+                       clock-names = "apb_pclk", "wdog_clk";
+               };
++              gpu@f0c0000 {
++                      compatible = "fsl,ls1028a-gpu";
++                      reg = <0x0 0x0f0c0000 0x0 0x10000>,
++                              <0x0 0x80000000 0x0 0x80000000>,
++                              <0x0 0x0 0x0 0x3000000>;
++                      reg-names = "base", "phys_baseaddr",
++                              "contiguous_mem";
++                      interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
++              };
++
+               sai1: audio-controller@f100000 {
+                       #sound-dai-cells = <0>;
+                       compatible = "fsl,vf610-sai";
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0067-arm64-dts-fsl-add-optee-node-for-ls1028.patch b/target/linux/layerscape/patches-5.4/302-dts-0067-arm64-dts-fsl-add-optee-node-for-ls1028.patch
new file mode 100644 (file)
index 0000000..3b7a67d
--- /dev/null
@@ -0,0 +1,29 @@
+From 1021f327657a464fbe8bd9eab927f18b8cf7556e Mon Sep 17 00:00:00 2001
+From: Sahil Malhotra <sahil.malhotra@nxp.com>
+Date: Sat, 3 Aug 2019 09:45:28 +0530
+Subject: [PATCH] arm64: dts: fsl: add optee node for ls1028
+
+For enabling OP-TEE on LS1028, need to add optee node
+in DTS
+
+Signed-off-by: Sahil Malhotra <sahil.malhotra@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -771,6 +771,13 @@
+               };
+       };
++      firmware {
++              optee {
++                      compatible = "linaro,optee-tz";
++                      method = "smc";
++              };
++      };
++
+       malidp0: display@f080000 {
+               compatible = "arm,mali-dp500";
+               reg = <0x0 0xf080000 0x0 0x10000>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0068-arm64-dts-lx2160a-Update-phy-mode-for-Aquantia-PHYs.patch b/target/linux/layerscape/patches-5.4/302-dts-0068-arm64-dts-lx2160a-Update-phy-mode-for-Aquantia-PHYs.patch
new file mode 100644 (file)
index 0000000..f227f82
--- /dev/null
@@ -0,0 +1,30 @@
+From 6915b8ddc149601e6f0baf4836f0f9f18e3ee25f Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Wed, 24 Jul 2019 20:22:57 +0300
+Subject: [PATCH] arm64: dts: lx2160a: Update phy mode for Aquantia PHYs
+
+The Aquantia driver does not allow xgmii mode anymore for
+the AQR107 PHYs. Use the correct usxgmii mode instead.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
+@@ -220,12 +220,12 @@
+ &dpmac3 {
+       phy-handle = <&aquantia_phy1>;
+-      phy-connection-type = "xgmii";
++      phy-connection-type = "usxgmii";
+ };
+ &dpmac4 {
+       phy-handle = <&aquantia_phy2>;
+-      phy-connection-type = "xgmii";
++      phy-connection-type = "usxgmii";
+ };
+ &dpmac5 {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0069-arm64-dts-ls1028a-Add-ftm_alarm0-DT-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0069-arm64-dts-ls1028a-Add-ftm_alarm0-DT-node.patch
new file mode 100644 (file)
index 0000000..f79e932
--- /dev/null
@@ -0,0 +1,46 @@
+From cc4f01aa78bfbebd7bdb52b4d873b5c9a332319e Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Thu, 27 Jun 2019 14:24:29 +0800
+Subject: [PATCH] arm64: dts: ls1028a: Add ftm_alarm0 DT node
+
+The patch adds ftm_alarm0 DT node for LS1028ARDB board
+FlexTimer1 module is used to wakeup the system
+
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -17,6 +17,10 @@
+       #address-cells = <2>;
+       #size-cells = <2>;
++      aliases {
++              rtc1 = &ftm_alarm0;
++      };
++
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+@@ -769,6 +773,19 @@
+                               little-endian;
+                       };
+               };
++
++              rcpm: rcpm@1e34040 {
++                      compatible = "fsl,ls1028a-rcpm", "fsl,qoriq-rcpm-2.1+";
++                      reg = <0x0 0x1e34040 0x0 0x1c>;
++                      #fsl,rcpm-wakeup-cells = <7>;
++              };
++
++              ftm_alarm0: timer@2800000 {
++                      compatible = "fsl,ls1028a-ftm-alarm";
++                      reg = <0x0 0x2800000 0x0 0x10000>;
++                      fsl,rcpm-wakeup = <&rcpm 0x0 0x0 0x0 0x0 0x4000 0x0 0x0>;
++                      interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
++              };
+       };
+       firmware {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0070-arm64-dts-ls1012a-ls1043a-ls1046a-ls1088a-ls208xa-re.patch b/target/linux/layerscape/patches-5.4/302-dts-0070-arm64-dts-ls1012a-ls1043a-ls1046a-ls1088a-ls208xa-re.patch
new file mode 100644 (file)
index 0000000..b77b745
--- /dev/null
@@ -0,0 +1,297 @@
+From c97c6ebf6fd6a6ff72bd7d58a12de0c07f14953e Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Thu, 27 Jun 2019 15:02:44 +0800
+Subject: [PATCH] arm64: dts: ls1012a/ls1043a/ls1046a/ls1088a/ls208xa: replace
+ ftm0 with ftm_alarm0
+
+The patch replaces ftm0 with ftm_alarm0 DT node
+       - replace ftm0 with ftm_alarm0
+       - add new rcpm node
+       - remove old rcpm node
+       - aliases ftm_alarm0 as rtc1
+
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi     | 23 +++++++++++----------
+ .../boot/dts/freescale/fsl-ls1043a-qds-sdk.dts     |  2 +-
+ .../boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts     |  2 +-
+ arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi     | 24 +++++++++++++---------
+ .../boot/dts/freescale/fsl-ls1046a-frwy-sdk.dts    |  2 +-
+ .../boot/dts/freescale/fsl-ls1046a-qds-sdk.dts     |  2 +-
+ .../boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts     |  2 +-
+ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi     | 24 ++++++++++++++--------
+ arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi     | 20 ++++++++++++------
+ arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi     | 12 +++++++++--
+ 10 files changed, 70 insertions(+), 43 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+@@ -23,6 +23,7 @@
+               rtic-c = &rtic_c;
+               rtic-d = &rtic_d;
+               sec-mon = &sec_mon;
++              rtc1 = &ftm_alarm0;
+       };
+       cpus {
+@@ -289,15 +290,21 @@
+                       #thermal-sensor-cells = <1>;
+               };
+-              ftm0: ftm0@29d0000 {
+-                      compatible = "fsl,ftm-alarm";
+-                      reg = <0x0 0x29d0000 0x0 0x10000>,
+-                            <0x0 0x1ee2140 0x0 0x4>;
+-                      reg-names = "ftm", "FlexTimer1";
++              rcpm: rcpm@1ee2140 {
++                      compatible = "fsl,ls1012a-rcpm", "fsl,qoriq-rcpm-2.1+";
++                      reg = <0x0 0x1ee2140 0x0 0x4>;
++                      #fsl,rcpm-wakeup-cells = <1>;
++              };
++
++              ftm_alarm0: timer@29d0000 {
++                      compatible = "fsl,ls1012a-ftm-alarm";
++                      reg = <0x0 0x29d0000 0x0 0x10000>;
++                      fsl,rcpm-wakeup = <&rcpm 0x20000>;
+                       interrupts = <0 86 0x4>;
+                       big-endian;
+               };
++
+               i2c0: i2c@2180000 {
+                       compatible = "fsl,vf610-i2c", "fsl,ls1012a-vf610-i2c";
+                       #address-cells = <1>;
+@@ -496,12 +503,6 @@
+                                       <0000 0 0 4 &gic 0 113 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "disabled";
+               };
+-
+-              rcpm: rcpm@1ee2000 {
+-                      compatible = "fsl,ls1012a-rcpm", "fsl,qoriq-rcpm-2.1";
+-                      reg = <0x0 0x1ee2000 0x0 0x1000>;
+-                      fsl,#rcpm-wakeup-cells = <1>;
+-              };
+       };
+       reserved-memory {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds-sdk.dts
+@@ -226,7 +226,7 @@ pcie@3600000 {
+       dma-coherent;
+ };
+-&ftm0 {
++&ftm_alarm0 {
+       dma-coherent;
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts
+@@ -221,7 +221,7 @@ pcie@3600000 {
+       dma-coherent;
+ };
+-&ftm0 {
++&ftm_alarm0 {
+       dma-coherent;
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+@@ -27,6 +27,7 @@
+               ethernet4 = &enet4;
+               ethernet5 = &enet5;
+               ethernet6 = &enet6;
++              rtc1 = &ftm_alarm0;
+       };
+       cpus {
+@@ -660,16 +661,6 @@
+                       status = "disabled";
+               };
+-              ftm0: ftm0@29d0000 {
+-                      compatible = "fsl,ftm-alarm";
+-                      reg = <0x0 0x29d0000 0x0 0x10000>,
+-                            <0x0 0x1ee2140 0x0 0x4>;
+-                      reg-names = "ftm", "FlexTimer1";
+-                      interrupts = <0 86 0x4>;
+-                      big-endian;
+-                      status = "okay";
+-              };
+-
+               wdog0: wdog@2ad0000 {
+                       compatible = "fsl,ls1043a-wdt", "fsl,imx21-wdt";
+                       reg = <0x0 0x2ad0000 0x0 0x10000>;
+@@ -874,6 +865,19 @@
+                       big-endian;
+               };
++              rcpm: rcpm@1ee2140 {
++                      compatible = "fsl,ls1043a-rcpm", "fsl,qoriq-rcpm-2.1+";
++                      reg = <0x0 0x1ee2140 0x0 0x4>;
++                      #fsl,rcpm-wakeup-cells = <1>;
++              };
++
++              ftm_alarm0: timer@29d0000 {
++                      compatible = "fsl,ls1043a-ftm-alarm";
++                      reg = <0x0 0x29d0000 0x0 0x10000>;
++                      fsl,rcpm-wakeup = <&rcpm 0x20000>;
++                      interrupts = <0 86 0x4>;
++                      big-endian;
++              };
+       };
+       firmware {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy-sdk.dts
+@@ -196,7 +196,7 @@
+       dma-coherent;
+ };
+-&ftm0 {
++&ftm_alarm0 {
+       dma-coherent;
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds-sdk.dts
+@@ -223,7 +223,7 @@ pcie@3600000 {
+       dma-coherent;
+ };
+-&ftm0 {
++&ftm_alarm0 {
+       dma-coherent;
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts
+@@ -228,7 +228,7 @@ pcie@3600000 {
+       dma-coherent;
+ };
+-&ftm0 {
++&ftm_alarm0 {
+       dma-coherent;
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+@@ -28,6 +28,7 @@
+               ethernet5 = &enet5;
+               ethernet6 = &enet6;
+               ethernet7 = &enet7;
++              rtc1 = &ftm_alarm0;
+       };
+       cpus {
+@@ -560,15 +561,6 @@
+                       status = "disabled";
+               };
+-              ftm0: ftm0@29d0000 {
+-                      compatible = "fsl,ftm-alarm";
+-                      reg = <0x0 0x29d0000 0x0 0x10000>,
+-                            <0x0 0x1ee2140 0x0 0x4>;
+-                      reg-names = "ftm", "FlexTimer1";
+-                      interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+-                      big-endian;
+-              };
+-
+               wdog0: watchdog@2ad0000 {
+                       compatible = "fsl,imx21-wdt";
+                       reg = <0x0 0x2ad0000 0x0 0x10000>;
+@@ -810,6 +802,20 @@
+                       queue-sizes = <64 64>;
+                       big-endian;
+               };
++
++              rcpm: rcpm@1ee208c {
++                      compatible = "fsl,ls1046a-rcpm", "fsl,qoriq-rcpm-2.1+";
++                      reg = <0x0 0x1ee208c 0x0 0x4>;
++                      #fsl,rcpm-wakeup-cells = <1>;
++              };
++
++              ftm_alarm0: timer@29d0000 {
++                      compatible = "fsl,ls1046a-ftm-alarm";
++                      reg = <0x0 0x29d0000 0x0 0x10000>;
++                      fsl,rcpm-wakeup = <&rcpm 0x20000>;
++                      interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
++                      big-endian;
++              };
+       };
+       reserved-memory {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+@@ -18,6 +18,7 @@
+       aliases {
+               crypto = &crypto;
++              rtc1 = &ftm_alarm0;
+       };
+       cpus {
+@@ -339,12 +340,6 @@
+                       status = "disabled";
+               };
+-              ftm0: ftm0@2800000 {
+-                      compatible = "fsl,ftm-alarm";
+-                      reg = <0x0 0x2800000 0x0 0x10000>;
+-                      interrupts = <0 44 4>;
+-              };
+-
+               i2c0: i2c@2000000 {
+                       compatible = "fsl,vf610-i2c", "fsl,ls1088a-vf610-i2c";
+                       #address-cells = <1>;
+@@ -792,6 +787,19 @@
+                               };
+                       };
+               };
++
++              rcpm: rcpm@1e34040 {
++                      compatible = "fsl,ls1088a-rcpm", "fsl,qoriq-rcpm-2.1+";
++                      reg = <0x0 0x1e34040 0x0 0x18>;
++                      #fsl,rcpm-wakeup-cells = <6>;
++              };
++
++              ftm_alarm0: timer@2800000 {
++                      compatible = "fsl,ls1088a-ftm-alarm";
++                      reg = <0x0 0x2800000 0x0 0x10000>;
++                      fsl,rcpm-wakeup = <&rcpm 0x0 0x0 0x0 0x0 0x4000 0x0>;
++                      interrupts = <0 44 4>;
++              };
+       };
+       firmware {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+@@ -24,6 +24,7 @@
+               serial1 = &serial1;
+               serial2 = &serial2;
+               serial3 = &serial3;
++              rtc1 = &ftm_alarm0;
+       };
+       cpu: cpus {
+@@ -757,9 +758,16 @@
+                       interrupts = <0 12 4>;
+               };
+-              ftm0: ftm0@2800000 {
+-                      compatible = "fsl,ftm-alarm";
++              rcpm: rcpm@1e34040 {
++                      compatible = "fsl,ls208xa-rcpm", "fsl,qoriq-rcpm-2.1+";
++                      reg = <0x0 0x1e34040 0x0 0x18>;
++                      #fsl,rcpm-wakeup-cells = <6>;
++              };
++
++              ftm_alarm0: timer@2800000 {
++                      compatible = "fsl,ls208xa-ftm-alarm";
+                       reg = <0x0 0x2800000 0x0 0x10000>;
++                      fsl,rcpm-wakeup = <&rcpm 0x0 0x0 0x0 0x0 0x4000 0x0>;
+                       interrupts = <0 44 4>;
+               };
+       };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0071-arm-dts-ls1021a-replace-ftm0-with-ftm_alarm0-DT-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0071-arm-dts-ls1021a-replace-ftm0-with-ftm_alarm0-DT-node.patch
new file mode 100644 (file)
index 0000000..d8412c2
--- /dev/null
@@ -0,0 +1,62 @@
+From f3a115bd1372e774979ecb81919664279b81810e Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Fri, 28 Jun 2019 16:36:20 +0800
+Subject: [PATCH] arm: dts: ls1021a: replace ftm0 with ftm_alarm0 DT node
+
+The patch replaces ftm0 with ftm_alarm0 DT node
+       - remove old ftm0 node
+       - add rcpm node
+       - add ftm_alarm0 node
+       - aliases ftm_alarm0 as rtc1
+
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+---
+ arch/arm/boot/dts/ls1021a.dtsi | 24 ++++++++++++++----------
+ 1 file changed, 14 insertions(+), 10 deletions(-)
+
+--- a/arch/arm/boot/dts/ls1021a.dtsi
++++ b/arch/arm/boot/dts/ls1021a.dtsi
+@@ -66,6 +66,7 @@
+               serial4 = &lpuart4;
+               serial5 = &lpuart5;
+               sysclk = &sysclk;
++              rtc1 = &ftm_alarm0;
+       };
+       cpus {
+@@ -582,16 +583,6 @@
+                       status = "disabled";
+               };
+-              ftm0: ftm0@29d0000 {
+-                      compatible = "fsl,ftm-alarm";
+-                      reg = <0x0 0x29d0000 0x0 0x10000>,
+-                            <0x0 0x1ee2140 0x0 0x4>;
+-                      reg-names = "ftm", "FlexTimer1";
+-                      interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+-                      big-endian;
+-                      status = "okay";
+-              };
+-
+               pwm1: pwm@29e0000 {
+                       compatible = "fsl,vf610-ftm-pwm";
+                       #pwm-cells = <3>;
+@@ -1003,5 +994,18 @@
+                       big-endian;
+               };
++              rcpm: rcpm@1ee2140 {
++                      compatible = "fsl,ls1021a-rcpm", "fsl,qoriq-rcpm-2.1+";
++                      reg = <0x0 0x1ee2140 0x0 0x8>;
++                      #fsl,rcpm-wakeup-cells = <2>;
++              };
++
++              ftm_alarm0: timer0@29d0000 {
++                      compatible = "fsl,ls1021a-ftm-alarm";
++                      reg = <0x0 0x29d0000 0x0 0x10000>;
++                      fsl,rcpm-wakeup = <&rcpm 0x0 0x20000000>;
++                      interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++                      big-endian;
++              };
+       };
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0072-arm64-ls1028ardb-Add-support-DP-nodes-for-LS1028ARDB.patch b/target/linux/layerscape/patches-5.4/302-dts-0072-arm64-ls1028ardb-Add-support-DP-nodes-for-LS1028ARDB.patch
new file mode 100644 (file)
index 0000000..2b8564f
--- /dev/null
@@ -0,0 +1,31 @@
+From b778a15d8781263bb768c404965dd5ec4bbe80c8 Mon Sep 17 00:00:00 2001
+From: Wen He <wen.he_1@nxp.com>
+Date: Wed, 17 Jul 2019 15:04:13 +0800
+Subject: [PATCH] arm64: ls1028ardb: Add support DP nodes for LS1028ARDB
+
+This patch add HDP PHY Controller related nodes on the LS1028ARDB.
+
+Signed-off-by: Alison Wang <alison.wang@nxp.com>
+Signed-off-by: Wen He <wen.he_1@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
+@@ -215,3 +215,15 @@
+ &sata {
+       status = "okay";
+ };
++
++&hdptx0 {
++      fsl,no_edid;
++      resolution = "3840x2160@60",
++                 "1920x1080@60",
++                 "1280x720@60",
++                 "720x480@60";
++      lane_mapping = <0x4e>;
++      edp_link_rate = <0x6>;
++      edp_num_lanes = <0x4>;
++      status = "okay";
++};
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0073-arm64-ls1028aqds-Add-support-DP-nodes-for-LS1028AQDS.patch b/target/linux/layerscape/patches-5.4/302-dts-0073-arm64-ls1028aqds-Add-support-DP-nodes-for-LS1028AQDS.patch
new file mode 100644 (file)
index 0000000..e389a95
--- /dev/null
@@ -0,0 +1,31 @@
+From 3e4421bc3d2055d599c65d5519b1eb63c0b9468e Mon Sep 17 00:00:00 2001
+From: Wen He <wen.he_1@nxp.com>
+Date: Wed, 17 Jul 2019 15:06:06 +0800
+Subject: [PATCH] arm64: ls1028aqds: Add support DP nodes for LS1028AQDS
+
+This patch add HDP PHY Controller related nodes on the LS1028AQDS.
+
+Signed-off-by: Alison Wang <alison.wang@nxp.com>
+Signed-off-by: Wen He <wen.he_1@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
+@@ -244,3 +244,15 @@
+ &sata {
+       status = "okay";
+ };
++
++&hdptx0 {
++      fsl,no_edid;
++      resolution = "3840x2160@60",
++                 "1920x1080@60",
++                 "1280x720@60",
++                 "720x480@60";
++      lane_mapping = <0x4e>;
++      edp_link_rate = <0x6>;
++      edp_num_lanes = <0x4>;
++      status = "okay";
++};
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0074-arm64-dts-fsl-ls1028a-Add-Felix-switch-port-DT-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0074-arm64-dts-fsl-ls1028a-Add-Felix-switch-port-DT-node.patch
new file mode 100644 (file)
index 0000000..7a1aa87
--- /dev/null
@@ -0,0 +1,102 @@
+From f5f011742b6ec9ad1db54de9e8296f1d5a3ede8a Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Fri, 14 Jun 2019 19:24:27 +0300
+Subject: [PATCH] arm64: dts: fsl: ls1028a: Add Felix switch port DT node
+
+Add the switch device node, available on PF5, so that the
+switch port sub-nodes (net devices) can be linked to
+corresponding board specific phy nodes (external ports) or
+have their link mode defined (internal ports).
+The switch device features 6 ports, 4 with external links
+and 2 internally facing to the ls1028a SoC and connected via
+fixed links to 2 internal enetc ethernet contoller ports.
+Add the corresponding enetc internal port device nodes,
+mapped to PF2 and PF6 PCIe functions.
+And don't forget to enable the 4MB BAR4 in the root complex
+ECAM space, where the switch registers are mapped.
+
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 58 +++++++++++++++++++++++++-
+ 1 file changed, 57 insertions(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -750,7 +750,9 @@
+                                 /* PF1: VF0-1 BAR0 - non-prefetchable memory */
+                                 0x82000000 0x0 0x00000000  0x1 0xf8210000  0x0 0x020000
+                                 /* PF1: VF0-1 BAR2 - prefetchable memory */
+-                                0xc2000000 0x0 0x00000000  0x1 0xf8230000  0x0 0x020000>;
++                                0xc2000000 0x0 0x00000000  0x1 0xf8230000  0x0 0x020000
++                                /* BAR4 (PF5) - non-prefetchable memory */
++                                0x82000000 0x0 0x00000000  0x1 0xfc000000  0x0 0x400000>;
+                       enetc_port0: ethernet@0,0 {
+                               compatible = "fsl,enetc";
+@@ -766,12 +768,66 @@
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
++                      ethernet@0,2 {
++                              compatible = "fsl,enetc";
++                              reg = <0x000200 0 0 0 0>;
++                              fixed-link {
++                                      speed = <1000>;
++                                      full-duplex;
++                              };
++                      };
+                       ethernet@0,4 {
+                               compatible = "fsl,enetc-ptp";
+                               reg = <0x000400 0 0 0 0>;
+                               clocks = <&clockgen 4 0>;
+                               little-endian;
+                       };
++                      switch@0,5 {
++                              compatible = "mscc,felix-switch";
++                              reg = <0x000500 0 0 0 0>;
++
++                              ports {
++                                      #address-cells = <1>;
++                                      #size-cells = <0>;
++
++                                      /* external ports */
++                                      switch_port0: port@0 {
++                                              reg = <0>;
++                                      };
++                                      switch_port1: port@1 {
++                                              reg = <1>;
++                                      };
++                                      switch_port2: port@2 {
++                                              reg = <2>;
++                                      };
++                                      switch_port3: port@3 {
++                                              reg = <3>;
++                                      };
++                                      /* internal to-cpu ports */
++                                      port@4 {
++                                              reg = <4>;
++                                              fixed-link {
++                                                      speed = <1000>;
++                                                      full-duplex;
++                                              };
++                                      };
++                                      port@5 {
++                                              reg = <5>;
++                                              fixed-link {
++                                                      speed = <1000>;
++                                                      full-duplex;
++                                              };
++                                      };
++                              };
++                      };
++                      ethernet@0,6 {
++                              compatible = "fsl,enetc";
++                              reg = <0x000600 0 0 0 0>;
++                              fixed-link {
++                                      speed = <1000>;
++                                      full-duplex;
++                              };
++                      };
+               };
+               rcpm: rcpm@1e34040 {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0075-arm64-dts-fsl-ls1028a-Enable-switch-PHYs-on-RDB.patch b/target/linux/layerscape/patches-5.4/302-dts-0075-arm64-dts-fsl-ls1028a-Enable-switch-PHYs-on-RDB.patch
new file mode 100644 (file)
index 0000000..ff8dca6
--- /dev/null
@@ -0,0 +1,62 @@
+From aafb63a926b790b64a5ed83377f07b90ec7ba7c0 Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Thu, 20 Jun 2019 19:53:55 +0300
+Subject: [PATCH] arm64: dts: fsl: ls1028a: Enable switch PHYs on RDB
+
+Just link the switch PHY nodes to the central MDIO
+controller PCIe endpoint node on ls1028 (implemented
+as PF3) so that PHYs are configurable via MDIO.
+
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts | 39 +++++++++++++++++++++++
+ 1 file changed, 39 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
+@@ -208,6 +208,45 @@
+       status = "disabled";
+ };
++&enetc_mdio_pf3 {
++      qsgmii_phy1: ethernet-phy@4 {
++              reg = <0x10>;
++      };
++
++      qsgmii_phy2: ethernet-phy@5 {
++              reg = <0x11>;
++      };
++
++      qsgmii_phy3: ethernet-phy@6 {
++              reg = <0x12>;
++      };
++
++      qsgmii_phy4: ethernet-phy@7 {
++              reg = <0x13>;
++      };
++};
++
++/* l2switch ports */
++&switch_port0 {
++      phy-handle = <&qsgmii_phy1>;
++      phy-connection-type = "qsgmii";
++};
++
++&switch_port1 {
++      phy-handle = <&qsgmii_phy2>;
++      phy-connection-type = "qsgmii";
++};
++
++&switch_port2 {
++      phy-handle = <&qsgmii_phy3>;
++      phy-connection-type = "qsgmii";
++};
++
++&switch_port3 {
++      phy-handle = <&qsgmii_phy4>;
++      phy-connection-type = "qsgmii";
++};
++
+ &sai4 {
+       status = "okay";
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0076-arm64-dts-ls1028a-support-Felix-PF5-INTB-interrupt.patch b/target/linux/layerscape/patches-5.4/302-dts-0076-arm64-dts-ls1028a-support-Felix-PF5-INTB-interrupt.patch
new file mode 100644 (file)
index 0000000..9427662
--- /dev/null
@@ -0,0 +1,34 @@
+From 28aa7c7f0da70b7410926ec5f5737e2b78e0cdfa Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Thu, 18 Jul 2019 15:26:03 +0800
+Subject: [PATCH] arm64: dts: ls1028a: support Felix/PF5 INTB interrupt
+
+The INTB interrupt includes,
+- PTP timestamp ready in timestamp FIFO
+- TSN Preemption
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -732,7 +732,6 @@
+                       reg = <0x01 0xf0000000 0x0 0x100000>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+-                      #interrupt-cells = <1>;
+                       msi-parent = <&its>;
+                       device_type = "pci";
+                       bus-range = <0x0 0x0>;
+@@ -785,6 +784,8 @@
+                       switch@0,5 {
+                               compatible = "mscc,felix-switch";
+                               reg = <0x000500 0 0 0 0>;
++                              /* IEP INT_B */
++                              interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
+                               ports {
+                                       #address-cells = <1>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0077-arm64-dts-ls1028a-Add-ethernet-property-for-l2switch.patch b/target/linux/layerscape/patches-5.4/302-dts-0077-arm64-dts-ls1028a-Add-ethernet-property-for-l2switch.patch
new file mode 100644 (file)
index 0000000..b5bc421
--- /dev/null
@@ -0,0 +1,33 @@
+From 51efcd436c30e7085b36264771edce03316013d1 Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Thu, 1 Aug 2019 19:44:00 +0300
+Subject: [PATCH] arm64: dts: ls1028a: Add ethernet property for l2switch CPU
+ port
+
+This enables the CPU traffic for the l2 switch (aka the
+CPU frame injection/ extraction feature).
+
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -814,6 +814,7 @@
+                                       };
+                                       port@5 {
+                                               reg = <5>;
++                                              ethernet = <&enetc_port3>;
+                                               fixed-link {
+                                                       speed = <1000>;
+                                                       full-duplex;
+@@ -821,7 +822,7 @@
+                                       };
+                               };
+                       };
+-                      ethernet@0,6 {
++                      enetc_port3: ethernet@0,6 {
+                               compatible = "fsl,enetc";
+                               reg = <0x000600 0 0 0 0>;
+                               fixed-link {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0078-arm64-dts-fix-endianness-of-rcpm.patch b/target/linux/layerscape/patches-5.4/302-dts-0078-arm64-dts-fix-endianness-of-rcpm.patch
new file mode 100644 (file)
index 0000000..53a8a55
--- /dev/null
@@ -0,0 +1,44 @@
+From fdba7c7bc334f72bd8641bbd63f3596ba68650c1 Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Thu, 8 Aug 2019 12:13:02 +0800
+Subject: [PATCH] arm64: dts: fix endianness of rcpm
+
+Add little-endian property of rcpm for ls1028a,ls1088a,ls208xa
+
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 1 +
+ arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 1 +
+ arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 1 +
+ 3 files changed, 3 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -836,6 +836,7 @@
+                       compatible = "fsl,ls1028a-rcpm", "fsl,qoriq-rcpm-2.1+";
+                       reg = <0x0 0x1e34040 0x0 0x1c>;
+                       #fsl,rcpm-wakeup-cells = <7>;
++                      little-endian;
+               };
+               ftm_alarm0: timer@2800000 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+@@ -792,6 +792,7 @@
+                       compatible = "fsl,ls1088a-rcpm", "fsl,qoriq-rcpm-2.1+";
+                       reg = <0x0 0x1e34040 0x0 0x18>;
+                       #fsl,rcpm-wakeup-cells = <6>;
++                      little-endian;
+               };
+               ftm_alarm0: timer@2800000 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+@@ -762,6 +762,7 @@
+                       compatible = "fsl,ls208xa-rcpm", "fsl,qoriq-rcpm-2.1+";
+                       reg = <0x0 0x1e34040 0x0 0x18>;
+                       #fsl,rcpm-wakeup-cells = <6>;
++                      little-endian;
+               };
+               ftm_alarm0: timer@2800000 {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0079-arm64-dts-ls1028a-Fix-interrupt-map-property-of-PCIe.patch b/target/linux/layerscape/patches-5.4/302-dts-0079-arm64-dts-ls1028a-Fix-interrupt-map-property-of-PCIe.patch
new file mode 100644 (file)
index 0000000..c348626
--- /dev/null
@@ -0,0 +1,45 @@
+From e41ad4213ce6742646c9dfed661289e69d5af5c1 Mon Sep 17 00:00:00 2001
+From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Date: Fri, 2 Aug 2019 16:42:53 +0800
+Subject: [PATCH] arm64: dts: ls1028a: Fix interrupt-map property of PCIe nodes
+
+The current interrupt-map entries lost the 'parent unit address',
+it will result in fail to allocate legacy INTx interrupts.
+
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -695,10 +695,10 @@
+                       msi-parent = <&its>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+-                      interrupt-map = <0000 0 0 1 &gic GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+-                                      <0000 0 0 2 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+-                                      <0000 0 0 3 &gic GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
+-                                      <0000 0 0 4 &gic GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
++                      interrupt-map = <0000 0 0 1 &gic 0 0 GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 2 &gic 0 0 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 3 &gic 0 0 GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 4 &gic 0 0 GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "disabled";
+               };
+@@ -720,10 +720,10 @@
+                       msi-parent = <&its>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+-                      interrupt-map = <0000 0 0 1 &gic GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+-                                      <0000 0 0 2 &gic GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+-                                      <0000 0 0 3 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+-                                      <0000 0 0 4 &gic GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++                      interrupt-map = <0000 0 0 1 &gic 0 0 GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 2 &gic 0 0 GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 3 &gic 0 0 GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
++                                      <0000 0 0 4 &gic 0 0 GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "disabled";
+               };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0080-arm64-dts-ls1028a-rdb-enable-emmc-hs400-mode.patch b/target/linux/layerscape/patches-5.4/302-dts-0080-arm64-dts-ls1028a-rdb-enable-emmc-hs400-mode.patch
new file mode 100644 (file)
index 0000000..3528fc8
--- /dev/null
@@ -0,0 +1,23 @@
+From f1f32315bcb6b50e9af701d4504c2cfa11823c98 Mon Sep 17 00:00:00 2001
+From: Yinbo Zhu <yinbo.zhu@nxp.com>
+Date: Tue, 13 Aug 2019 17:01:44 +0800
+Subject: [PATCH] arm64: dts: ls1028a-rdb: enable emmc hs400 mode
+
+This patch is to enable emmc hs400 mode for ls1028ardb
+
+Signed-off-by: Yinbo Zhu <yinbo.zhu@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
+@@ -93,6 +93,8 @@
+ &esdhc1 {
+       mmc-hs200-1_8v;
++      mmc-hs400-1_8v;
++      bus-width = <8>;
+       status = "okay";
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0081-arm64-dts-lx2160a-add-ftm_alarm0-DT-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0081-arm64-dts-lx2160a-add-ftm_alarm0-DT-node.patch
new file mode 100644 (file)
index 0000000..e8db9f3
--- /dev/null
@@ -0,0 +1,47 @@
+From 31301e26a9d72fe2e4ecdf0999e9fda4c6832188 Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Thu, 1 Aug 2019 12:34:33 +0800
+Subject: [PATCH] arm64: dts: lx2160a: add ftm_alarm0 DT node
+
+The patch adds ftm_alarm0 DT node for Soc LX2160A
+FlexTimer1 module is used to wakeup the system in deep sleep
+
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -15,6 +15,10 @@
+       #address-cells = <2>;
+       #size-cells = <2>;
++      aliases {
++              rtc1 = &ftm_alarm0;
++      };
++
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+@@ -769,6 +773,20 @@
+                       timeout-sec = <30>;
+               };
++              rcpm: rcpm@1e34040 {
++                      compatible = "fsl,lx2160a-rcpm", "fsl,qoriq-rcpm-2.1+";
++                      reg = <0x0 0x1e34040 0x0 0x1c>;
++                      #fsl,rcpm-wakeup-cells = <7>;
++                      little-endian;
++              };
++
++              ftm_alarm0: timer@2800000 {
++                      compatible = "fsl,lx2160a-ftm-alarm";
++                      reg = <0x0 0x2800000 0x0 0x10000>;
++                      fsl,rcpm-wakeup = <&rcpm 0x0 0x0 0x0 0x0 0x4000 0x0 0x0>;
++                      interrupts = <0 44 4>;
++              };
++
+               usb0: usb@3100000 {
+                       compatible = "snps,dwc3";
+                       reg = <0x0 0x3100000 0x0 0x10000>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0082-arm64-dts-lx2160a-add-tmu-device-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0082-arm64-dts-lx2160a-add-tmu-device-node.patch
new file mode 100644 (file)
index 0000000..3e3a679
--- /dev/null
@@ -0,0 +1,293 @@
+From f6233242d21bb4cb973a7dfc61dcfbf6d9a5d22b Mon Sep 17 00:00:00 2001
+From: Yuantian Tang <andy.tang@nxp.com>
+Date: Mon, 2 Sep 2019 17:45:19 +0800
+Subject: [PATCH] arm64: dts: lx2160a: add tmu device node
+
+Add the TMU (Thermal Monitoring Unit) device node to enable
+TMU feature.
+
+Signed-off-by: Yuantian Tang <andy.tang@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 108 +++++++++++++++++++++----
+ 1 file changed, 92 insertions(+), 16 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -6,6 +6,7 @@
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
++#include <dt-bindings/thermal/thermal.h>
+ /memreserve/ 0x80000000 0x00010000;
+@@ -24,7 +25,7 @@
+               #size-cells = <0>;
+               // 8 clusters having 2 Cortex-A72 cores each
+-              cpu@0 {
++              cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -38,9 +39,10 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster0_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+-              cpu@1 {
++              cpu1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -54,9 +56,10 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster0_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+-              cpu@100 {
++              cpu100: cpu@100 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -70,9 +73,10 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster1_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+-              cpu@101 {
++              cpu101: cpu@101 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -86,9 +90,10 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster1_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+-              cpu@200 {
++              cpu200: cpu@200 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -102,9 +107,10 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster2_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+-              cpu@201 {
++              cpu201: cpu@201 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -118,9 +124,10 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster2_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+-              cpu@300 {
++              cpu300: cpu@300 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -134,9 +141,10 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster3_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+-              cpu@301 {
++              cpu301: cpu@301 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -150,9 +158,10 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster3_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+-              cpu@400 {
++              cpu400: cpu@400 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -166,9 +175,10 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster4_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+-              cpu@401 {
++              cpu401: cpu@401 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -182,9 +192,10 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster4_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+-              cpu@500 {
++              cpu500: cpu@500 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -198,9 +209,10 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster5_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+-              cpu@501 {
++              cpu501: cpu@501 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -214,9 +226,10 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster5_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+-              cpu@600 {
++              cpu600: cpu@600 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -230,9 +243,10 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster6_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+-              cpu@601 {
++              cpu601: cpu@601 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -246,9 +260,10 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster6_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+-              cpu@700 {
++              cpu700: cpu@700 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -262,9 +277,10 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster7_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+-              cpu@701 {
++              cpu701: cpu@701 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a72";
+                       enable-method = "psci";
+@@ -278,6 +294,7 @@
+                       i-cache-sets = <192>;
+                       next-level-cache = <&cluster7_l2>;
+                       cpu-idle-states = <&cpu_pw15>;
++                      #cooling-cells = <2>;
+               };
+               cluster0_l2: l2-cache0 {
+@@ -422,6 +439,51 @@
+               clock-output-names = "sysclk";
+       };
++      thermal-zones {
++              core_thermal1: core-thermal1 {
++                      polling-delay-passive = <1000>;
++                      polling-delay = <5000>;
++                      thermal-sensors = <&tmu 0>;
++
++                      trips {
++                              core_cluster_alert: core-cluster-alert {
++                                      temperature = <85000>;
++                                      hysteresis = <2000>;
++                                      type = "passive";
++                              };
++
++                              core_cluster_crit: core-cluster-crit {
++                                      temperature = <95000>;
++                                      hysteresis = <2000>;
++                                      type = "critical";
++                              };
++                      };
++
++                      cooling-maps {
++                              map0 {
++                                      trip = <&core_cluster_alert>;
++                                      cooling-device =
++                                              <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
++                                              <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
++                                              <&cpu100 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
++                                              <&cpu101 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
++                                              <&cpu200 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
++                                              <&cpu201 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
++                                              <&cpu300 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
++                                              <&cpu301 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
++                                              <&cpu400 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
++                                              <&cpu401 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
++                                              <&cpu500 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
++                                              <&cpu501 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
++                                              <&cpu600 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
++                                              <&cpu601 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
++                                              <&cpu700 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
++                                              <&cpu701 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
++                              };
++                      };
++              };
++      };
++
+       soc {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+@@ -689,6 +751,20 @@
+                       status = "disabled";
+               };
++              tmu: tmu@1f80000 {
++                      compatible = "fsl,qoriq-tmu";
++                      reg = <0x0 0x1f80000 0x0 0x10000>;
++                      interrupts = <0 23 0x4>;
++                      fsl,tmu-range = <0x800000E6 0x8001017D>;
++                      fsl,tmu-calibration =
++                              /* Calibration data group 1 */
++                              <0x00000000 0x00000035
++                              /* Calibration data group 2 */
++                              0x00010001 0x00000154>;
++                      little-endian;
++                      #thermal-sensor-cells = <1>;
++              };
++
+               uart0: serial@21c0000 {
+                       compatible = "arm,sbsa-uart","arm,pl011";
+                       reg = <0x0 0x21c0000 0x0 0x1000>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0083-arm64-ls1028a-qds-correct-bus-of-rtc.patch b/target/linux/layerscape/patches-5.4/302-dts-0083-arm64-ls1028a-qds-correct-bus-of-rtc.patch
new file mode 100644 (file)
index 0000000..d978377
--- /dev/null
@@ -0,0 +1,42 @@
+From d4c7270a63b1d78b89d91f74d782cce2a2bd9690 Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Wed, 4 Sep 2019 11:39:30 +0800
+Subject: [PATCH] arm64: ls1028a-qds: correct bus of rtc
+
+The rtc is on i2c2 bus(hardware), not on i2c1 channel 3,
+so correct it
+
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
+@@ -169,11 +169,6 @@
+                               vcc-supply = <&sb_3v3>;
+                       };
+-                      rtc@51 {
+-                              compatible = "nxp,pcf2129";
+-                              reg = <0x51>;
+-                      };
+-
+                       eeprom@56 {
+                               compatible = "atmel,24c512";
+                               reg = <0x56>;
+@@ -217,6 +212,14 @@
+ };
++&i2c1 {
++      status = "okay";
++      rtc@51 {
++              compatible = "nxp,pcf2129";
++              reg = <0x51>;
++      };
++};
++
+ &enetc_port1 {
+       phy-handle = <&qds_phy1>;
+       phy-connection-type = "rgmii-id";
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0084-arm64-dts-ls1028a-define-networking-options-for-QDS.patch b/target/linux/layerscape/patches-5.4/302-dts-0084-arm64-dts-ls1028a-define-networking-options-for-QDS.patch
new file mode 100644 (file)
index 0000000..68e8098
--- /dev/null
@@ -0,0 +1,355 @@
+From 0c767bcfe1b4d940f2889820f12d278cbba764b5 Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Tue, 27 Aug 2019 15:12:00 +0300
+Subject: [PATCH] arm64: dts: ls1028a: define networking options for QDS
+
+Defines connectivity for a few serdes protocol combinations (85xx, 65xx,
+13xx, 9999, 7777).
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ .../boot/dts/freescale/fsl-ls1028a-qds-1xxx.dtsi   | 20 ++++++++
+ .../boot/dts/freescale/fsl-ls1028a-qds-6xxx.dtsi   | 20 ++++++++
+ .../boot/dts/freescale/fsl-ls1028a-qds-7777.dtsi   | 56 ++++++++++++++++++++
+ .../boot/dts/freescale/fsl-ls1028a-qds-8xxx.dtsi   | 19 +++++++
+ .../boot/dts/freescale/fsl-ls1028a-qds-9999.dtsi   | 60 ++++++++++++++++++++++
+ .../boot/dts/freescale/fsl-ls1028a-qds-x3xx.dtsi   | 48 +++++++++++++++++
+ .../boot/dts/freescale/fsl-ls1028a-qds-x5xx.dtsi   | 44 ++++++++++++++++
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts  | 27 ++++++++++
+ 8 files changed, 294 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-1xxx.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-6xxx.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-7777.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-8xxx.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-9999.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-x3xx.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-x5xx.dtsi
+
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-1xxx.dtsi
+@@ -0,0 +1,20 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree Include file for LS1028A QDS board, serdes 1xxx
++ *
++ * Copyright 2019 NXP
++ *
++ */
++
++&mdio_slot1 {
++      slot1_sgmii: ethernet-phy@2 {
++              /* AQR112 */
++              reg = <0x2>;
++              compatible = "ethernet-phy-ieee802.3-c45";
++      };
++};
++
++&enetc_port0 {
++      phy-handle = <&slot1_sgmii>;
++      phy-connection-type = "usxgmii";
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-6xxx.dtsi
+@@ -0,0 +1,20 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree Include file for LS1028A QDS board, serdes 6xxx
++ *
++ * Copyright 2019 NXP
++ *
++ */
++
++&mdio_slot1 {
++      slot1_sgmii: ethernet-phy@2 {
++              /* AQR112 */
++              reg = <0x2>;
++              compatible = "ethernet-phy-ieee802.3-c45";
++      };
++};
++
++&enetc_port0 {
++      phy-handle = <&slot1_sgmii>;
++      phy-connection-type = "2500base-x";
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-7777.dtsi
+@@ -0,0 +1,56 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree Include file for LS1028A QDS board, serdes 9999
++ *
++ * Copyright 2019 NXP
++ *
++ */
++
++&mdio_slot1 {
++      /* two ports on AQR412 */
++      slot1_sxgmii2: ethernet-phy@2 {
++              reg = <0x2>;
++              compatible = "ethernet-phy-ieee802.3-c45";
++      };
++      slot1_sxgmii3: ethernet-phy@3 {
++              reg = <0x3>;
++              compatible = "ethernet-phy-ieee802.3-c45";
++      };
++};
++
++&mdio_slot2 {
++      slot2_sxgmii0: ethernet-phy@2 {
++              /* AQR112 */
++              reg = <0x2>;
++              compatible = "ethernet-phy-ieee802.3-c45";
++      };
++};
++
++&mdio_slot3 {
++      slot3_sxgmii0: ethernet-phy@2 {
++              /* AQR112 */
++              reg = <0x2>;
++              compatible = "ethernet-phy-ieee802.3-c45";
++      };
++};
++
++/* l2switch ports */
++&switch_port0 {
++      phy-handle = <&slot1_sxgmii2>;
++      phy-connection-type = "2500base-x";
++};
++
++&switch_port1 {
++      phy-handle = <&slot2_sxgmii0>;
++      phy-connection-type = "2500base-x";
++};
++
++&switch_port2 {
++      phy-handle = <&slot3_sxgmii0>;
++      phy-connection-type = "2500base-x";
++};
++
++&switch_port3 {
++      phy-handle = <&slot1_sxgmii3>;
++      phy-connection-type = "2500base-x";
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-8xxx.dtsi
+@@ -0,0 +1,19 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree Include file for LS1028A QDS board, serdes 8xxx
++ *
++ * Copyright 2019 NXP
++ *
++ */
++
++&mdio_slot1 {
++      slot1_sgmii: ethernet-phy@1c {
++              /* 1st port on VSC8234 */
++              reg = <0x1c>;
++      };
++};
++
++&enetc_port0 {
++      phy-handle = <&slot1_sgmii>;
++      phy-connection-type = "sgmii";
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-9999.dtsi
+@@ -0,0 +1,60 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree Include file for LS1028A QDS board, serdes 9999
++ *
++ * Copyright 2019 NXP
++ *
++ */
++
++&mdio_slot1 {
++      /* VSC8234 */
++      slot1_sgmii0: ethernet-phy@1c {
++              reg = <0x1c>;
++      };
++      slot1_sgmii1: ethernet-phy@1d {
++              reg = <0x1d>;
++      };
++      slot1_sgmii2: ethernet-phy@1e {
++              reg = <0x1e>;
++      };
++      slot1_sgmii3: ethernet-phy@1f {
++              reg = <0x1f>;
++      };
++};
++
++&mdio_slot2 {
++      /* VSC8234 */
++      slot2_sgmii0: ethernet-phy@1c {
++              reg = <0x1c>;
++      };
++      slot2_sgmii1: ethernet-phy@1d {
++              reg = <0x1d>;
++      };
++      slot2_sgmii2: ethernet-phy@1e {
++              reg = <0x1e>;
++      };
++      slot2_sgmii3: ethernet-phy@1f {
++              reg = <0x1f>;
++      };
++};
++
++/* l2switch ports */
++&switch_port0 {
++      phy-handle = <&slot1_sgmii0>;
++      phy-connection-type = "sgmii";
++};
++
++&switch_port1 {
++      phy-handle = <&slot2_sgmii0>;
++      phy-connection-type = "sgmii";
++};
++
++&switch_port2 {
++      phy-handle = <&slot1_sgmii2>;
++      phy-connection-type = "sgmii";
++};
++
++&switch_port3 {
++      phy-handle = <&slot1_sgmii3>;
++      phy-connection-type = "sgmii";
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-x3xx.dtsi
+@@ -0,0 +1,48 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree Include file for LS1028A QDS board, serdes x3xx
++ *
++ * Copyright 2019 NXP
++ *
++ */
++
++&mdio_slot2 {
++      /* 4 ports on AQR412 */
++      slot2_qsgmii0: ethernet-phy@0 {
++              reg = <0x0>;
++              compatible = "ethernet-phy-ieee802.3-c45";
++      };
++      slot2_qsgmii1: ethernet-phy@1 {
++              reg = <0x1>;
++              compatible = "ethernet-phy-ieee802.3-c45";
++      };
++      slot2_qsgmii2: ethernet-phy@2 {
++              reg = <0x2>;
++              compatible = "ethernet-phy-ieee802.3-c45";
++      };
++      slot2_qsgmii3: ethernet-phy@3 {
++              reg = <0x3>;
++              compatible = "ethernet-phy-ieee802.3-c45";
++      };
++};
++
++/* l2switch ports */
++&switch_port0 {
++      phy-handle = <&slot2_qsgmii0>;
++      phy-connection-type = "usxgmii";
++};
++
++&switch_port1 {
++      phy-handle = <&slot2_qsgmii1>;
++      phy-connection-type = "usxgmii";
++};
++
++&switch_port2 {
++      phy-handle = <&slot2_qsgmii2>;
++      phy-connection-type = "usxgmii";
++};
++
++&switch_port3 {
++      phy-handle = <&slot2_qsgmii3>;
++      phy-connection-type = "usxgmii";
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-x5xx.dtsi
+@@ -0,0 +1,44 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree Include file for LS1028A QDS board, serdes x5xx
++ *
++ * Copyright 2019 NXP
++ *
++ */
++
++&mdio_slot2 {
++      /* 4 ports on VSC8514 */
++      slot2_qsgmii0: ethernet-phy@8 {
++              reg = <0x8>;
++      };
++      slot2_qsgmii1: ethernet-phy@9 {
++              reg = <0x9>;
++      };
++      slot2_qsgmii2: ethernet-phy@a {
++              reg = <0xa>;
++      };
++      slot2_qsgmii3: ethernet-phy@b {
++              reg = <0xb>;
++      };
++};
++
++/* l2switch ports */
++&switch_port0 {
++      phy-handle = <&slot2_qsgmii0>;
++      phy-connection-type = "qsgmii";
++};
++
++&switch_port1 {
++      phy-handle = <&slot2_qsgmii1>;
++      phy-connection-type = "qsgmii";
++};
++
++&switch_port2 {
++      phy-handle = <&slot2_qsgmii2>;
++      phy-connection-type = "qsgmii";
++};
++
++&switch_port3 {
++      phy-handle = <&slot2_qsgmii3>;
++      phy-connection-type = "qsgmii";
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
+@@ -104,6 +104,30 @@
+                               reg = <5>;
+                       };
+               };
++
++              mdio_slot1: mdio@4 {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      reg = <4>;
++              };
++
++              mdio_slot2: mdio@5 {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      reg = <5>;
++              };
++
++              mdio_slot3: mdio@6 {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      reg = <6>;
++              };
++
++              mdio_slot4: mdio@7 {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      reg = <7>;
++              };
+       };
+ };
+@@ -259,3 +283,6 @@
+       edp_num_lanes = <0x4>;
+       status = "okay";
+ };
++
++#include "fsl-ls1028a-qds-8xxx.dtsi"
++#include "fsl-ls1028a-qds-x5xx.dtsi"
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0085-arm64-dts-LS1028a-rdb-use-Ethernet-PHY-interrupt.patch b/target/linux/layerscape/patches-5.4/302-dts-0085-arm64-dts-LS1028a-rdb-use-Ethernet-PHY-interrupt.patch
new file mode 100644 (file)
index 0000000..17286a8
--- /dev/null
@@ -0,0 +1,51 @@
+From 3dc3a4c6ac9e8a0940a9974b8fe2da7641bfa3dd Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Thu, 22 Aug 2019 12:47:12 +0300
+Subject: [PATCH] arm64: dts: LS1028a-rdb: use Ethernet PHY interrupt
+
+Use the PHY interrupt wired to GPIO pins as part of MDIO WA performance
+impact mitigation.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
+@@ -202,6 +202,8 @@
+               #size-cells = <0>;
+               sgmii_phy0: ethernet-phy@2 {
+                       reg = <0x2>;
++                      interrupt-parent = <&gpio1>;
++                      interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+               };
+       };
+ };
+@@ -213,18 +215,26 @@
+ &enetc_mdio_pf3 {
+       qsgmii_phy1: ethernet-phy@4 {
+               reg = <0x10>;
++              interrupt-parent = <&gpio1>;
++              interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+       };
+       qsgmii_phy2: ethernet-phy@5 {
+               reg = <0x11>;
++              interrupt-parent = <&gpio1>;
++              interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+       };
+       qsgmii_phy3: ethernet-phy@6 {
+               reg = <0x12>;
++              interrupt-parent = <&gpio1>;
++              interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+       };
+       qsgmii_phy4: ethernet-phy@7 {
+               reg = <0x13>;
++              interrupt-parent = <&gpio1>;
++              interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+       };
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0086-usb-dwc3-enable-otg-mode-for-dwc3-usb-ip-on-layersca.patch b/target/linux/layerscape/patches-5.4/302-dts-0086-usb-dwc3-enable-otg-mode-for-dwc3-usb-ip-on-layersca.patch
new file mode 100644 (file)
index 0000000..050c5d5
--- /dev/null
@@ -0,0 +1,53 @@
+From 411bee5b3e729e4dd691051e13f77dfb994e0da8 Mon Sep 17 00:00:00 2001
+From: Yinbo Zhu <yinbo.zhu@nxp.com>
+Date: Mon, 9 Sep 2019 15:57:52 +0800
+Subject: [PATCH] usb: dwc3: enable otg mode for dwc3 usb ip on layerscape
+
+layerscape otg function should be supported HNP SRP and ADP protocol
+accroing to rm doc, but dwc3 code not realize it and use id pin to
+detect who is host or device(0 is host 1 is device) this patch is to
+enable OTG mode on ls1028ardb ls1088ardb and ls1046ardb in dts
+
+Signed-off-by: Yinbo Zhu <yinbo.zhu@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts | 4 ++++
+ arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts | 4 ++++
+ arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts | 1 +
+ 3 files changed, 9 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
+@@ -98,6 +98,10 @@
+       status = "okay";
+ };
++&usb1 {
++      dr_mode = "otg";
++};
++
+ &i2c0 {
+       status = "okay";
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts
+@@ -44,6 +44,10 @@
+       sd-uhs-sdr12;
+ };
++&usb1 {
++      dr_mode = "otg";
++};
++
+ &i2c0 {
+       status = "okay";
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts
+@@ -120,6 +120,7 @@
+ };
+ &usb1 {
++      dr_mode = "otg";
+       status = "okay";
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0087-arm-dts-ls1021a-fix-that-FlexTimer-cannot-wakeup-sys.patch b/target/linux/layerscape/patches-5.4/302-dts-0087-arm-dts-ls1021a-fix-that-FlexTimer-cannot-wakeup-sys.patch
new file mode 100644 (file)
index 0000000..f677aba
--- /dev/null
@@ -0,0 +1,29 @@
+From c221e05b50ca68daf5a20069ee1928171ef43bae Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Sat, 14 Sep 2019 12:59:36 +0800
+Subject: [PATCH] arm: dts: ls1021a: fix that FlexTimer cannot wakeup system in
+ deep sleep
+
+The patch fixes a bug that FlexTimer cannot
+wakeup system in deep sleep.
+
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+---
+ arch/arm/boot/dts/ls1021a.dtsi | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/arch/arm/boot/dts/ls1021a.dtsi
++++ b/arch/arm/boot/dts/ls1021a.dtsi
+@@ -998,6 +998,12 @@
+                       compatible = "fsl,ls1021a-rcpm", "fsl,qoriq-rcpm-2.1+";
+                       reg = <0x0 0x1ee2140 0x0 0x8>;
+                       #fsl,rcpm-wakeup-cells = <2>;
++
++                      /*
++                       * The second and third entry compose an alt offset
++                       * address for IPPDEXPCR1(SCFG_SPARECR8)
++                       */
++                      fsl,ippdexpcr1-alt-addr = <&scfg 0x0 0x51c>;
+               };
+               ftm_alarm0: timer0@29d0000 {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0088-arm64-dts-ls1028a-fix-dwc-pci-over-smmu.patch b/target/linux/layerscape/patches-5.4/302-dts-0088-arm64-dts-ls1028a-fix-dwc-pci-over-smmu.patch
new file mode 100644 (file)
index 0000000..80ab53e
--- /dev/null
@@ -0,0 +1,34 @@
+From 127b30b66c3b48ee717ed7335987334e8dc769b5 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 1 Oct 2019 13:47:11 +0300
+Subject: [PATCH] arm64: dts: ls1028a: fix dwc pci over smmu
+
+In order for the dwc controller to work with SMMU it needs the
+bootloader to fixup it's iommu-map property. In the current
+implementation to bootloader will not perform the fixup if the
+property is not already in the device tree with dummy fields.
+Add it to fix DWC PCI over SMMU.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -689,6 +689,7 @@
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       dma-coherent;
++                      iommu-map = <0 &smmu 0 1>; /* Fixed-up by bootloader */
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0x00000000 0x80 0x00010000 0x0 0x00010000   /* downstream I/O */
+                                 0x82000000 0x0 0x40000000 0x80 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+@@ -714,6 +715,7 @@
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       dma-coherent;
++                      iommu-map = <0 &smmu 0 1>; /* Fixed-up by bootloader */
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0x00000000 0x88 0x00010000 0x0 0x00010000   /* downstream I/O */
+                                 0x82000000 0x0 0x40000000 0x88 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0089-arm64-dts-ls1028a-Update-the-clock-providers-for-the.patch b/target/linux/layerscape/patches-5.4/302-dts-0089-arm64-dts-ls1028a-Update-the-clock-providers-for-the.patch
new file mode 100644 (file)
index 0000000..31a8968
--- /dev/null
@@ -0,0 +1,55 @@
+From e13c24ef2f068e651b9996922a08843d53513cab Mon Sep 17 00:00:00 2001
+From: Wen He <wen.he_1@nxp.com>
+Date: Fri, 20 Sep 2019 16:34:18 +0800
+Subject: [PATCH] arm64: dts: ls1028a: Update the clock providers for the Mali
+ DP500
+
+In order to maximise performance of the LCD Controller's 64-bit AXI
+bus, for any give speed bin of the device, the AXI master interface
+clock(ACLK) clock can be up to CPU_frequency/2, which is already
+capable of optimal performance. In general, ACLK is always expected
+to be equal to CPU_frequency/2. APB slave interface clock(PCLK) and
+Main processing clock(PCLK) both are tied to the same clock as ACLK.
+
+This change followed the LS1028A Architecture Specification Manual.
+
+Signed-off-by: Wen He <wen.he_1@nxp.com>
+Acked-by: Li Yang <leoyang.li@nxp.com>
+Signed-off-by: Shawn Guo <shawnguo@kernel.org>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 17 ++---------------
+ 1 file changed, 2 insertions(+), 15 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -90,20 +90,6 @@
+               clocks = <&osc_27m>;
+       };
+-      aclk: clock-axi {
+-              compatible = "fixed-clock";
+-              #clock-cells = <0>;
+-              clock-frequency = <650000000>;
+-              clock-output-names= "aclk";
+-      };
+-
+-      pclk: clock-apb {
+-              compatible = "fixed-clock";
+-              #clock-cells = <0>;
+-              clock-frequency = <650000000>;
+-              clock-output-names= "pclk";
+-      };
+-
+       reboot {
+               compatible ="syscon-reboot";
+               regmap = <&rst>;
+@@ -862,7 +848,8 @@
+               interrupts = <0 222 IRQ_TYPE_LEVEL_HIGH>,
+                            <0 223 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "DE", "SE";
+-              clocks = <&dpclk 0>, <&aclk>, <&aclk>, <&pclk>;
++              clocks = <&dpclk 0>, <&clockgen 2 2>, <&clockgen 2 2>,
++                       <&clockgen 2 2>;
+               clock-names = "pxlclk", "mclk", "aclk", "pclk";
+               arm,malidp-output-port-lines = /bits/ 8 <8 8 8>;
+               arm,malidp-arqos-value = <0xd000d000>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0090-arm64-dts-ls1028a-Update-clock-cells-of-dpclk-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0090-arm64-dts-ls1028a-Update-clock-cells-of-dpclk-node.patch
new file mode 100644 (file)
index 0000000..861429e
--- /dev/null
@@ -0,0 +1,35 @@
+From 7e64c4e922cddea72dacd3f0d8f395d9182ea5bc Mon Sep 17 00:00:00 2001
+From: Wen He <wen.he_1@nxp.com>
+Date: Mon, 14 Oct 2019 15:13:27 +0800
+Subject: [PATCH] arm64: dts: ls1028a: Update #clock-cells of dpclk node
+
+Update the property #clock-cells = <1> to #clock-cells = <0> of the
+dpclk, since the Display output pixel clock driver provides single
+clock output.
+
+Signed-off-by: Wen He <wen.he_1@nxp.com>
+Signed-off-by: Shawn Guo <shawnguo@kernel.org>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -86,7 +86,7 @@
+       dpclk: clock-controller@f1f0000 {
+               compatible = "fsl,ls1028a-plldig";
+               reg = <0x0 0xf1f0000 0x0 0xffff>;
+-              #clock-cells = <1>;
++              #clock-cells = <0>;
+               clocks = <&osc_27m>;
+       };
+@@ -848,7 +848,7 @@
+               interrupts = <0 222 IRQ_TYPE_LEVEL_HIGH>,
+                            <0 223 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "DE", "SE";
+-              clocks = <&dpclk 0>, <&clockgen 2 2>, <&clockgen 2 2>,
++              clocks = <&dpclk>, <&clockgen 2 2>, <&clockgen 2 2>,
+                        <&clockgen 2 2>;
+               clock-names = "pxlclk", "mclk", "aclk", "pclk";
+               arm,malidp-output-port-lines = /bits/ 8 <8 8 8>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0091-arm64-dts-ls1028a-Add-properties-for-HD-Display-cont.patch b/target/linux/layerscape/patches-5.4/302-dts-0091-arm64-dts-ls1028a-Add-properties-for-HD-Display-cont.patch
new file mode 100644 (file)
index 0000000..96247ae
--- /dev/null
@@ -0,0 +1,43 @@
+From e0afa16cad94b26e13d673647b781dd336cb30bc Mon Sep 17 00:00:00 2001
+From: Wen He <wen.he_1@nxp.com>
+Date: Mon, 14 Oct 2019 14:25:42 +0800
+Subject: [PATCH] arm64: dts: ls1028a: Add properties for HD Display controller
+ node
+
+The HD Display controller includes DP TX CTRL and DPHY, their offers
+multi-protocol support of standards such as DisplayPort and eDP, with
+one of these standards supported at a time.
+
+This patch enables the HD Display controller driver on the LS1028A.
+
+Signed-off-by: Wen He <wen.he_1@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -856,7 +856,23 @@
+               port {
+                       dp0_out: endpoint {
++                              remote-endpoint = <&dp1_out>;
++                      };
++              };
++      };
++      hdptx0: display@f200000 {
++              compatible = "cdn,ls1028a-dp";
++              reg = <0x0 0xf200000 0x0 0xfffff>;
++              interrupts = <0 221 IRQ_TYPE_LEVEL_HIGH>;
++              clocks = <&clockgen 2 2>, <&clockgen 2 2>, <&clockgen 2 2>,
++                       <&clockgen 2 2>, <&clockgen 2 2>, <&dpclk>;
++              clock-names = "clk_core", "pclk", "sclk",
++                            "cclk", "clk_vif", "clk_pxl";
++
++              port {
++                      dp1_out: endpoint {
++                              remote-endpoint = <&dp0_out>;
+                       };
+               };
+       };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0092-arm64-dts-ls1028a-Add-DP-DT-nodes.patch b/target/linux/layerscape/patches-5.4/302-dts-0092-arm64-dts-ls1028a-Add-DP-DT-nodes.patch
new file mode 100644 (file)
index 0000000..a6d2253
--- /dev/null
@@ -0,0 +1,49 @@
+From 4de1f70135fa4b44eb5016e36ba08ffd0bc62414 Mon Sep 17 00:00:00 2001
+From: Wen He <wen.he_1@nxp.com>
+Date: Wed, 27 Nov 2019 17:48:17 +0800
+Subject: [PATCH] arm64: dts: ls1028a: Add DP DT nodes
+
+Add DP DT nodes for configure and enable the HD Display
+controller on LS1028ARDB and LS1028AQDS boards.
+
+Signed-off-by: Wen He <wen.he_1@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts | 9 +--------
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts | 9 +--------
+ 2 files changed, 2 insertions(+), 16 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
+@@ -273,14 +273,7 @@
+ };
+ &hdptx0 {
+-      fsl,no_edid;
+-      resolution = "3840x2160@60",
+-                 "1920x1080@60",
+-                 "1280x720@60",
+-                 "720x480@60";
+-      lane_mapping = <0x4e>;
+-      edp_link_rate = <0x6>;
+-      edp_num_lanes = <0x4>;
++      lane-mapping = <0x4e>;
+       status = "okay";
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
+@@ -272,13 +272,6 @@
+ };
+ &hdptx0 {
+-      fsl,no_edid;
+-      resolution = "3840x2160@60",
+-                 "1920x1080@60",
+-                 "1280x720@60",
+-                 "720x480@60";
+-      lane_mapping = <0x4e>;
+-      edp_link_rate = <0x6>;
+-      edp_num_lanes = <0x4>;
++      lane-mapping = <0x4e>;
+       status = "okay";
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0093-arm64-dts-fsl-Specify-phy-mode-for-CPU-ports.patch b/target/linux/layerscape/patches-5.4/302-dts-0093-arm64-dts-fsl-Specify-phy-mode-for-CPU-ports.patch
new file mode 100644 (file)
index 0000000..3cbb090
--- /dev/null
@@ -0,0 +1,35 @@
+From a55a0d71c2b1000c514f30573ced00879754f223 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 29 Nov 2019 03:07:14 +0200
+Subject: [PATCH] arm64: dts: fsl: Specify phy-mode for CPU ports
+
+PHYLINK requires that device tree nodes have a phy-mode or
+phy-connection-type property. The internal Felix ports really are
+connected to the ENETC via 2 back-to-back MACs, so the correct MII type
+is GMII (one of which is overclocked at 2.5Gbaud, but still GMII).
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -795,6 +795,8 @@
+                                       /* internal to-cpu ports */
+                                       port@4 {
+                                               reg = <4>;
++                                              phy-mode = "gmii";
++
+                                               fixed-link {
+                                                       speed = <1000>;
+                                                       full-duplex;
+@@ -803,6 +805,8 @@
+                                       port@5 {
+                                               reg = <5>;
+                                               ethernet = <&enetc_port3>;
++                                              phy-mode = "gmii";
++
+                                               fixed-link {
+                                                       speed = <1000>;
+                                                       full-duplex;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0094-arm64-dts-fsl-Drop-compatible-string-from-Felix-swit.patch b/target/linux/layerscape/patches-5.4/302-dts-0094-arm64-dts-fsl-Drop-compatible-string-from-Felix-swit.patch
new file mode 100644 (file)
index 0000000..21b133b
--- /dev/null
@@ -0,0 +1,24 @@
+From 21c535326436df93fd61c9bd029b8716d1ab94d0 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 29 Nov 2019 03:10:23 +0200
+Subject: [PATCH] arm64: dts: fsl: Drop "compatible" string from Felix switch
+
+Since Felix is not a platform device but a PCI device, the "compatible"
+string serves no purpose. The device driver is found by matching the PCI
+device/vendor ID to the ENETC PF.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -770,7 +770,6 @@
+                               little-endian;
+                       };
+                       switch@0,5 {
+-                              compatible = "mscc,felix-switch";
+                               reg = <0x000500 0 0 0 0>;
+                               /* IEP INT_B */
+                               interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0095-arm64-dts-fsl-ls1028a-Specify-that-the-Felix-port-4-.patch b/target/linux/layerscape/patches-5.4/302-dts-0095-arm64-dts-fsl-ls1028a-Specify-that-the-Felix-port-4-.patch
new file mode 100644 (file)
index 0000000..b97e83d
--- /dev/null
@@ -0,0 +1,33 @@
+From 5934fa0a0708b551211f63b8d91676df346e9821 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 29 Nov 2019 03:13:00 +0200
+Subject: [PATCH] arm64: dts: fsl: ls1028a: Specify that the Felix port 4 runs
+ at 2.5Gbps
+
+This is just an informative change, because all Felix MACs inside the
+LS1028A are hardwired in gigabit mode anyway.
+
+Only PHYLINK is able to understand fixed-link speeds higher than 1 Gbps.
+With PHYLIB, fixed-link interfaces are emulated as C22 PHYs by the swphy
+driver, and C22 does not specify settings for speeds higher than
+gigabit.
+
+This patch brings no functional change except for the messages printed
+during driver initialization.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -797,7 +797,7 @@
+                                               phy-mode = "gmii";
+                                               fixed-link {
+-                                                      speed = <1000>;
++                                                      speed = <2500>;
+                                                       full-duplex;
+                                               };
+                                       };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0096-arm64-dts-fsl-ls1028a-Disable-eno3-and-make-swp5-the.patch b/target/linux/layerscape/patches-5.4/302-dts-0096-arm64-dts-fsl-ls1028a-Disable-eno3-and-make-swp5-the.patch
new file mode 100644 (file)
index 0000000..4a3eaaa
--- /dev/null
@@ -0,0 +1,63 @@
+From 9344f58d60a0a53ec39e7c5d75021843e859970f Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 29 Nov 2019 03:18:32 +0200
+Subject: [PATCH] arm64: dts: fsl: ls1028a: Disable eno3 and make swp5 the
+ Felix CPU port
+
+This patch returns to the switch port setup from BSP 0.2, where the
+switch only had a single Ethernet connection to the CPU, via a tagging
+interface. Choose eno2 for this purpose, as it has higher bandwidth and
+also supports TSN offloads.
+
+The reason is that the switch is not able to do DSA tags on 2 CPU ports
+at the same time, and it is confusing to have so many ports with no
+clear indication which should be used for what (a "data" port and a
+"control" port).
+
+We don't revert to the BSP 0.2 RCW configuration, however. The ENETC
+port 3 is still enabled in the RCW, however it is not probed by Linux by
+default, since the large majority of use cases will not need it. For
+those that do (like originating 802.1CB traffic from the CPU), it can be
+enabled back by simply reverting this device tree change.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -755,7 +755,7 @@
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+-                      ethernet@0,2 {
++                      enetc_port2: ethernet@0,2 {
+                               compatible = "fsl,enetc";
+                               reg = <0x000200 0 0 0 0>;
+                               fixed-link {
+@@ -794,6 +794,7 @@
+                                       /* internal to-cpu ports */
+                                       port@4 {
+                                               reg = <4>;
++                                              ethernet = <&enetc_port2>;
+                                               phy-mode = "gmii";
+                                               fixed-link {
+@@ -803,7 +804,6 @@
+                                       };
+                                       port@5 {
+                                               reg = <5>;
+-                                              ethernet = <&enetc_port3>;
+                                               phy-mode = "gmii";
+                                               fixed-link {
+@@ -816,6 +816,8 @@
+                       enetc_port3: ethernet@0,6 {
+                               compatible = "fsl,enetc";
+                               reg = <0x000600 0 0 0 0>;
++                              status = "disabled";
++
+                               fixed-link {
+                                       speed = <1000>;
+                                       full-duplex;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0097-LF-387-5-arm64-dts-layerscape-add-chip-specific-comp.patch b/target/linux/layerscape/patches-5.4/302-dts-0097-LF-387-5-arm64-dts-layerscape-add-chip-specific-comp.patch
new file mode 100644 (file)
index 0000000..63f4372
--- /dev/null
@@ -0,0 +1,150 @@
+From 4cb6a451112308b2679c567ac680bc74ab93a92a Mon Sep 17 00:00:00 2001
+From: Ran Wang <ran.wang_1@nxp.com>
+Date: Fri, 22 Nov 2019 14:18:49 +0800
+Subject: [PATCH] LF-387-5 arm64: dts: layerscape: add chip-specific compatible
+ string to usb nodes
+
+To allow USB dwc3 driver to conduct some chip-scpeific configuring.
+Cover all arm64 based Layerscape SoCs.
+
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+Reviewed-by: Jun Li <jun.li@nxp.com>
+Reviewed-by: Leo Li <leo.li@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 2 +-
+ arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 +++---
+ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 6 +++---
+ arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 4 ++--
+ arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 4 ++--
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 4 ++--
+ 6 files changed, 13 insertions(+), 13 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+@@ -443,7 +443,7 @@
+               };
+               usb0: usb3@2f00000 {
+-                      compatible = "snps,dwc3";
++                      compatible = "fsl,ls1012a-dwc3", "snps,dwc3";
+                       reg = <0x0 0x2f00000 0x0 0x10000>;
+                       interrupts = <0 60 0x4>;
+                       dr_mode = "host";
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+@@ -694,7 +694,7 @@
+                       dma-ranges = <0x0 0x0 0x0 0x0 0x100 0x00000000>;
+                       usb0: usb3@2f00000 {
+-                              compatible = "snps,dwc3";
++                              compatible = "fsl,ls1043a-dwc3", "snps,dwc3";
+                               reg = <0x0 0x2f00000 0x0 0x10000>;
+                               interrupts = <0 60 0x4>;
+                               dr_mode = "host";
+@@ -708,7 +708,7 @@
+                       };
+                       usb1: usb3@3000000 {
+-                              compatible = "snps,dwc3";
++                              compatible = "fsl,ls1043a-dwc3", "snps,dwc3";
+                               reg = <0x0 0x3000000 0x0 0x10000>;
+                               interrupts = <0 61 0x4>;
+                               dr_mode = "host";
+@@ -722,7 +722,7 @@
+                       };
+                       usb2: usb3@3100000 {
+-                              compatible = "snps,dwc3";
++                              compatible = "fsl,ls1043a-dwc3", "snps,dwc3";
+                               reg = <0x0 0x3100000 0x0 0x10000>;
+                               interrupts = <0 63 0x4>;
+                               dr_mode = "host";
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+@@ -593,7 +593,7 @@
+                       dma-ranges = <0x0 0x0 0x0 0x0 0x100 0x00000000>;
+                       usb0: usb@2f00000 {
+-                              compatible = "snps,dwc3";
++                              compatible = "fsl,ls1046a-dwc3", "snps,dwc3";
+                               reg = <0x0 0x2f00000 0x0 0x10000>;
+                               interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+                               dr_mode = "host";
+@@ -606,7 +606,7 @@
+                       };
+                       usb1: usb@3000000 {
+-                              compatible = "snps,dwc3";
++                              compatible = "fsl,ls1046a-dwc3", "snps,dwc3";
+                               reg = <0x0 0x3000000 0x0 0x10000>;
+                               interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
+                               dr_mode = "host";
+@@ -619,7 +619,7 @@
+                       };
+                       usb2: usb@3100000 {
+-                              compatible = "snps,dwc3";
++                              compatible = "fsl,ls1046a-dwc3", "snps,dwc3";
+                               reg = <0x0 0x3100000 0x0 0x10000>;
+                               interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+                               dr_mode = "host";
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+@@ -394,7 +394,7 @@
+               };
+               usb0: usb3@3100000 {
+-                      compatible = "snps,dwc3";
++                      compatible = "fsl,ls1088a-dwc3", "snps,dwc3";
+                       reg = <0x0 0x3100000 0x0 0x10000>;
+                       interrupts = <0 80 IRQ_TYPE_LEVEL_HIGH>;
+                       dr_mode = "host";
+@@ -406,7 +406,7 @@
+               };
+               usb1: usb3@3110000 {
+-                      compatible = "snps,dwc3";
++                      compatible = "fsl,ls1088a-dwc3", "snps,dwc3";
+                       reg = <0x0 0x3110000 0x0 0x10000>;
+                       interrupts = <0 81 IRQ_TYPE_LEVEL_HIGH>;
+                       dr_mode = "host";
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+@@ -730,7 +730,7 @@
+               usb0: usb3@3100000 {
+                       status = "disabled";
+-                      compatible = "snps,dwc3";
++                      compatible = "fsl,ls2088a-dwc3", "snps,dwc3";
+                       reg = <0x0 0x3100000 0x0 0x10000>;
+                       interrupts = <0 80 0x4>; /* Level high type */
+                       dr_mode = "host";
+@@ -742,7 +742,7 @@
+               usb1: usb3@3110000 {
+                       status = "disabled";
+-                      compatible = "snps,dwc3";
++                      compatible = "fsl,ls2088a-dwc3", "snps,dwc3";
+                       reg = <0x0 0x3110000 0x0 0x10000>;
+                       interrupts = <0 81 0x4>; /* Level high type */
+                       dr_mode = "host";
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -864,7 +864,7 @@
+               };
+               usb0: usb@3100000 {
+-                      compatible = "snps,dwc3";
++                      compatible = "fsl,lx2160a-dwc3", "snps,dwc3";
+                       reg = <0x0 0x3100000 0x0 0x10000>;
+                       interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+                       dr_mode = "host";
+@@ -878,7 +878,7 @@
+               };
+               usb1: usb@3110000 {
+-                      compatible = "snps,dwc3";
++                      compatible = "fsl,lx2160a-dwc3", "snps,dwc3";
+                       reg = <0x0 0x3110000 0x0 0x10000>;
+                       interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+                       dr_mode = "host";
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0098-LF-403-ARM64-dts-fsl-Add-clock-names-mclk0-for-SAI-n.patch b/target/linux/layerscape/patches-5.4/302-dts-0098-LF-403-ARM64-dts-fsl-Add-clock-names-mclk0-for-SAI-n.patch
new file mode 100644 (file)
index 0000000..6001364
--- /dev/null
@@ -0,0 +1,105 @@
+From b3e78e4a087922566bc18171190e2eed8a9b7797 Mon Sep 17 00:00:00 2001
+From: Alison Wang <alison.wang@nxp.com>
+Date: Thu, 12 Dec 2019 15:35:32 +0800
+Subject: [PATCH] LF-403 ARM64: dts: fsl: Add clock-names mclk0 for SAI nodes
+
+This patch adds clock-names "mclk0" to match with the current SAI
+driver.
+
+Signed-off-by: Alison Wang <alison.wang@nxp.com>
+---
+ arch/arm/boot/dts/ls1021a.dtsi                 | 10 ++++++----
+ arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 10 ++++++----
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 15 +++++++++------
+ 3 files changed, 21 insertions(+), 14 deletions(-)
+
+--- a/arch/arm/boot/dts/ls1021a.dtsi
++++ b/arch/arm/boot/dts/ls1021a.dtsi
+@@ -682,8 +682,9 @@
+                       reg = <0x0 0x2b50000 0x0 0x10000>;
+                       interrupts = <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 1>, <&clockgen 4 1>,
+-                               <&clockgen 4 1>, <&clockgen 4 1>;
+-                      clock-names = "bus", "mclk1", "mclk2", "mclk3";
++                               <&clockgen 4 1>, <&clockgen 4 1>,
++                               <&clockgen 4 1>;
++                      clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+                       dma-names = "tx", "rx";
+                       dmas = <&edma0 1 47>,
+                              <&edma0 1 46>;
+@@ -696,8 +697,9 @@
+                       reg = <0x0 0x2b60000 0x0 0x10000>;
+                       interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 1>, <&clockgen 4 1>,
+-                               <&clockgen 4 1>, <&clockgen 4 1>;
+-                      clock-names = "bus", "mclk1", "mclk2", "mclk3";
++                               <&clockgen 4 1>, <&clockgen 4 1>,
++                               <&clockgen 4 1>;
++                      clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+                       dma-names = "tx", "rx";
+                       dmas = <&edma0 1 45>,
+                              <&edma0 1 44>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+@@ -404,8 +404,9 @@
+                       reg = <0x0 0x2b50000 0x0 0x10000>;
+                       interrupts = <0 148 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 3>, <&clockgen 4 3>,
+-                               <&clockgen 4 3>, <&clockgen 4 3>;
+-                      clock-names = "bus", "mclk1", "mclk2", "mclk3";
++                               <&clockgen 4 3>, <&clockgen 4 3>,
++                               <&clockgen 4 3>;
++                      clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+                       dma-names = "tx", "rx";
+                       dmas = <&edma0 1 47>,
+                              <&edma0 1 46>;
+@@ -418,8 +419,9 @@
+                       reg = <0x0 0x2b60000 0x0 0x10000>;
+                       interrupts = <0 149 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 3>, <&clockgen 4 3>,
+-                               <&clockgen 4 3>, <&clockgen 4 3>;
+-                      clock-names = "bus", "mclk1", "mclk2", "mclk3";
++                               <&clockgen 4 3>, <&clockgen 4 3>,
++                               <&clockgen 4 3>;
++                      clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+                       dma-names = "tx", "rx";
+                       dmas = <&edma0 1 45>,
+                              <&edma0 1 44>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -544,8 +544,9 @@
+                       reg = <0x0 0xf100000 0x0 0x10000>;
+                       interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 1>, <&clockgen 4 1>,
+-                               <&clockgen 4 1>, <&clockgen 4 1>;
+-                      clock-names = "bus", "mclk1", "mclk2", "mclk3";
++                               <&clockgen 4 1>, <&clockgen 4 1>,
++                               <&clockgen 4 1>;
++                      clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+                       dma-names = "tx", "rx";
+                       dmas = <&edma0 1 4>,
+                              <&edma0 1 3>;
+@@ -558,8 +559,9 @@
+                       reg = <0x0 0xf110000 0x0 0x10000>;
+                       interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 1>, <&clockgen 4 1>,
+-                               <&clockgen 4 1>, <&clockgen 4 1>;
+-                      clock-names = "bus", "mclk1", "mclk2", "mclk3";
++                               <&clockgen 4 1>, <&clockgen 4 1>,
++                               <&clockgen 4 1>;
++                      clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+                       dma-names = "tx", "rx";
+                       dmas = <&edma0 1 6>,
+                              <&edma0 1 5>;
+@@ -572,8 +574,9 @@
+                       reg = <0x0 0xf130000 0x0 0x10000>;
+                       interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 1>, <&clockgen 4 1>,
+-                               <&clockgen 4 1>, <&clockgen 4 1>;
+-                      clock-names = "bus", "mclk1", "mclk2", "mclk3";
++                               <&clockgen 4 1>, <&clockgen 4 1>,
++                               <&clockgen 4 1>;
++                      clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+                       dma-names = "tx", "rx";
+                       dmas = <&edma0 1 10>,
+                              <&edma0 1 9>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0099-arm64-dts-layerscape-apply-dma-coherent-for-dwc3-nod.patch b/target/linux/layerscape/patches-5.4/302-dts-0099-arm64-dts-layerscape-apply-dma-coherent-for-dwc3-nod.patch
new file mode 100644 (file)
index 0000000..182c8ae
--- /dev/null
@@ -0,0 +1,150 @@
+From 18219eaa3f37f375584789b95876967e97b8da3e Mon Sep 17 00:00:00 2001
+From: Ran Wang <ran.wang_1@nxp.com>
+Date: Wed, 25 Dec 2019 14:00:27 +0800
+Subject: [PATCH] arm64: dts: layerscape: apply dma-coherent for dwc3 nodes
+
+Since dwc3 cache type has been set to cacheable, apply dma-coherent to
+all dwc3 nodes accordingly.
+
+Note: For LS1043A and LS1046A, since QE-HDLC still doesn't support
+dma-coherent, we cannot directly revert cd1a4f3c (sdk: dts: ls104x move
+dma-coherent from soc to its child nodes) to recover dma-coherent for
+soc.
+
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 1 +
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 2 ++
+ arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++
+ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 3 +++
+ arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 2 ++
+ arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 2 ++
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 1 +
+ 7 files changed, 14 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+@@ -453,6 +453,7 @@
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                       snps,host-vbus-glitches;
++                      dma-coherent;
+               };
+               sata: sata@3200000 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -381,6 +381,7 @@
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      dma-coherent;
+               };
+               usb1: usb@3110000 {
+@@ -391,6 +392,7 @@
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,quirk-frame-length-adjustment = <0x20>;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
++                      dma-coherent;
+               };
+               sata: sata@3200000 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+@@ -705,6 +705,7 @@
+                               snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                               snps,host-vbus-glitches;
+                               configure-gfladj;
++                              dma-coherent;
+                       };
+                       usb1: usb3@3000000 {
+@@ -719,6 +720,7 @@
+                               snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                               snps,host-vbus-glitches;
+                               configure-gfladj;
++                              dma-coherent;
+                       };
+                       usb2: usb3@3100000 {
+@@ -733,6 +735,7 @@
+                               snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                               snps,host-vbus-glitches;
+                               configure-gfladj;
++                              dma-coherent;
+                       };
+                       sata: sata@3200000 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+@@ -603,6 +603,7 @@
+                               usb3-lpm-capable;
+                               snps,dis-u1u2-when-u3-quirk;
+                               snps,host-vbus-glitches;
++                              dma-coherent;
+                       };
+                       usb1: usb@3000000 {
+@@ -616,6 +617,7 @@
+                               usb3-lpm-capable;
+                               snps,dis-u1u2-when-u3-quirk;
+                               snps,host-vbus-glitches;
++                              dma-coherent;
+                       };
+                       usb2: usb@3100000 {
+@@ -629,6 +631,7 @@
+                               usb3-lpm-capable;
+                               snps,dis-u1u2-when-u3-quirk;
+                               snps,host-vbus-glitches;
++                              dma-coherent;
+                       };
+                       sata: sata@3200000 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+@@ -402,6 +402,7 @@
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                       snps,host-vbus-glitches;
++                      dma-coherent;
+                       status = "disabled";
+               };
+@@ -414,6 +415,7 @@
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                       snps,host-vbus-glitches;
++                      dma-coherent;
+                       status = "disabled";
+               };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+@@ -738,6 +738,7 @@
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                       snps,host-vbus-glitches;
++                      dma-coherent;
+               };
+               usb1: usb3@3110000 {
+@@ -750,6 +751,7 @@
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                       snps,host-vbus-glitches;
++                      dma-coherent;
+               };
+               ccn@4000000 {
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -874,6 +874,7 @@
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                       snps,host-vbus-glitches;
++                      dma-coherent;
+                       status = "disabled";
+               };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0100-arm64-dts-ls208xa-Update-qspi-node-properties-for-LS.patch b/target/linux/layerscape/patches-5.4/302-dts-0100-arm64-dts-ls208xa-Update-qspi-node-properties-for-LS.patch
new file mode 100644 (file)
index 0000000..0b2de32
--- /dev/null
@@ -0,0 +1,64 @@
+From 121cd10d9ec4466b09ac33986c7b4c1f8eff9363 Mon Sep 17 00:00:00 2001
+From: Kuldeep Singh <kuldeep.singh@nxp.com>
+Date: Wed, 18 Dec 2019 15:09:41 +0530
+Subject: [PATCH] arm64: dts: ls208xa: Update qspi node properties for
+ LS2088ARDB
+
+LS2088ADB has one spansion flash s25fs512s of size 64M.
+
+Update qspi dts entry for the board using compatibles as "jedec,spi-nor"
+to probe flash successfully. Also, align properties with other board dts
+properties.
+
+Since device properties are different, so remove fsl, ls1021a-qspi.
+ls1021a-qspi is to be used only for Big-endian verion of QSPI
+controller. Use dt-bindings constants in interrupts instead of using
+numbers.
+
+Signed-off-by: Kuldeep Singh <kuldeep.singh@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls208xa-rdb.dtsi | 8 ++++----
+ arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi     | 6 +++---
+ 2 files changed, 7 insertions(+), 7 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa-rdb.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa-rdb.dtsi
+@@ -110,12 +110,12 @@
+ &qspi {
+       status = "okay";
+-      flash0: s25fs512s@0 {
++
++      s25fs512s0: flash@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+-              compatible = "spansion,m25p80";
+-              m25p,fast-read;
+-              spi-max-frequency = <20000000>;
++              compatible = "jedec,spi-nor";
++              spi-max-frequency = <50000000>;
+               reg = <0>;
+       };
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+@@ -610,16 +610,16 @@
+               };
+               qspi: spi@20c0000 {
+-                      status = "disabled";
+-                      compatible = "fsl,ls2080a-qspi", "fsl,ls1021a-qspi";
++                      compatible = "fsl,ls2080a-qspi";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0 0x20c0000 0x0 0x10000>,
+                             <0x0 0x20000000 0x0 0x10000000>;
+                       reg-names = "QuadSPI", "QuadSPI-memory";
+-                      interrupts = <0 25 0x4>; /* Level high type */
++                      interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+                       clock-names = "qspi_en", "qspi";
++                      status = "disabled";
+               };
+               pcie1: pcie@3400000 {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0101-arm64-dts-ls208xa-Remove-dma-coherent-from-dwc3-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0101-arm64-dts-ls208xa-Remove-dma-coherent-from-dwc3-node.patch
new file mode 100644 (file)
index 0000000..dcd3bee
--- /dev/null
@@ -0,0 +1,36 @@
+From f12e1e289702b9828a2d7deba8744b212e7a6758 Mon Sep 17 00:00:00 2001
+From: Ran Wang <ran.wang_1@nxp.com>
+Date: Fri, 27 Dec 2019 18:20:23 +0800
+Subject: [PATCH] arm64: dts: ls208xa: Remove dma-coherent from dwc3 nodes
+
+ls208xa encounteded below USB failure when applying dma-coherent, remove it.
+[   11.087839] xhci-hcd xhci-hcd.1.auto: Error while assigning device slot ID
+[   11.094730] xhci-hcd xhci-hcd.1.auto: Max number of devices this xHCI host supports is 127.
+[   11.103103] xhci-hcd xhci-hcd.0.auto: Error while assigning device slot ID
+[   11.109985] xhci-hcd xhci-hcd.0.auto: Max number of devices this xHCI host supports is 127.
+[   11.118348] usb usb2-port1: couldn't allocate usb_device
+[   11.123680] usb usb4-port1: couldn't allocate usb_device
+
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+@@ -738,7 +738,6 @@
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                       snps,host-vbus-glitches;
+-                      dma-coherent;
+               };
+               usb1: usb3@3110000 {
+@@ -751,7 +750,6 @@
+                       snps,dis_rxdet_inp3_quirk;
+                       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                       snps,host-vbus-glitches;
+-                      dma-coherent;
+               };
+               ccn@4000000 {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0102-LF-20-1-arm64-dts-ls1012ardb-Update-qspi-node-dts-pr.patch b/target/linux/layerscape/patches-5.4/302-dts-0102-LF-20-1-arm64-dts-ls1012ardb-Update-qspi-node-dts-pr.patch
new file mode 100644 (file)
index 0000000..1f8462e
--- /dev/null
@@ -0,0 +1,60 @@
+From e642e6844bd4e6da28efab377f1a94e0eb9a3532 Mon Sep 17 00:00:00 2001
+From: Kuldeep Singh <kuldeep.singh@nxp.com>
+Date: Fri, 3 Jan 2020 14:47:59 +0530
+Subject: [PATCH] LF-20-1 arm64: dts: ls1012ardb: Update qspi node dts
+ properties
+
+Update rx and tx bus-width to 1.
+Use compatibles as "jedec,spi-nor" to probe flash without displaying warning:
+found s25fs512s, expected m25p80
+
+Remove property 'big-endian' as it is not used by new driver anymore.
+Also, update dtsi compatibles to use "fsl,ls1021a-qspi".
+
+Signed-off-by: Kuldeep Singh <kuldeep.singh@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts | 8 ++++----
+ arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi    | 3 +--
+ 2 files changed, 5 insertions(+), 6 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
+@@ -88,15 +88,15 @@
+ &qspi {
+       status = "okay";
++
+       qflash0: s25fs512s@0 {
+-              compatible = "spansion,m25p80";
++              compatible = "jedec,spi-nor";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               spi-max-frequency = <20000000>;
+-              m25p,fast-read;
+               reg = <0>;
+-              spi-rx-bus-width = <2>;
+-              spi-tx-bus-width = <2>;
++              spi-rx-bus-width = <1>;
++              spi-tx-bus-width = <1>;
+       };
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+@@ -385,7 +385,7 @@
+               };
+               qspi: spi@1550000 {
+-                      compatible = "fsl,ls1012a-qspi", "fsl,ls1021a-qspi";
++                      compatible = "fsl,ls1021a-qspi";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0 0x1550000 0x0 0x10000>,
+@@ -394,7 +394,6 @@
+                       interrupts = <0 99 IRQ_TYPE_LEVEL_HIGH>;
+                       clock-names = "qspi_en", "qspi";
+                       clocks = <&clockgen 4 0>, <&clockgen 4 0>;
+-                      big-endian;
+                       status = "disabled";
+               };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0103-arm64-dts-ls1028a-Update-edma-compatible-to-fit-eDMA.patch b/target/linux/layerscape/patches-5.4/302-dts-0103-arm64-dts-ls1028a-Update-edma-compatible-to-fit-eDMA.patch
new file mode 100644 (file)
index 0000000..b7e65c7
--- /dev/null
@@ -0,0 +1,25 @@
+From 0af4a990ad0ff2bb0df89a68a82023bb94653749 Mon Sep 17 00:00:00 2001
+From: Peng Ma <peng.ma@nxp.com>
+Date: Thu, 12 Dec 2019 11:13:44 +0800
+Subject: [PATCH] arm64: dts: ls1028a: Update edma compatible to fit eDMA
+ driver
+
+The eDMA of LS1028A soc has a little bit different from others, So we
+should distinguish them in driver by compatible.
+
+Signed-off-by: Peng Ma <peng.ma@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -327,7 +327,7 @@
+               edma0: dma-controller@22c0000 {
+                       #dma-cells = <2>;
+-                      compatible = "fsl,vf610-edma";
++                      compatible = "fsl,ls1028a-edma";
+                       reg = <0x0 0x22c0000 0x0 0x10000>,
+                             <0x0 0x22d0000 0x0 0x10000>,
+                             <0x0 0x22e0000 0x0 0x10000>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0104-arm64-dts-lx2160a-add-iommu-map-property-to-pci-node.patch b/target/linux/layerscape/patches-5.4/302-dts-0104-arm64-dts-lx2160a-add-iommu-map-property-to-pci-node.patch
new file mode 100644 (file)
index 0000000..02c46f5
--- /dev/null
@@ -0,0 +1,65 @@
+From ad5077a8da6e8aad01b7b6ad979b52c39118969d Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 17 Dec 2019 13:26:37 +0200
+Subject: [PATCH] arm64: dts: lx2160a: add iommu-map property to pci nodes
+
+Add the iommu-map property to the pci nodes so that the firmware
+fixes it up with the required values thus enabling iommu for
+devices connected over pci.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Acked-by: Li Yang <leoyang.li@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
+@@ -954,6 +954,7 @@
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x82000000 0x0 0x40000000 0x80 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+                       msi-parent = <&its>;
++                      iommu-map = <0 &smmu 0 1>; /* This is fixed-up by u-boot */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic 0 0 GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+@@ -990,6 +991,7 @@
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x82000000 0x0 0x40000000 0x88 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+                       msi-parent = <&its>;
++                      iommu-map = <0 &smmu 0 1>; /* This is fixed-up by u-boot */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic 0 0 GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+@@ -1026,6 +1028,7 @@
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x82000000 0x0 0x40000000 0x90 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+                       msi-parent = <&its>;
++                      iommu-map = <0 &smmu 0 1>; /* This is fixed-up by u-boot */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic 0 0 GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
+@@ -1063,6 +1066,7 @@
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x82000000 0x0 0x40000000 0x98 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+                       msi-parent = <&its>;
++                      iommu-map = <0 &smmu 0 1>; /* This is fixed-up by u-boot */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic 0 0 GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+@@ -1099,6 +1103,7 @@
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x82000000 0x0 0x40000000 0xa0 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+                       msi-parent = <&its>;
++                      iommu-map = <0 &smmu 0 1>; /* This is fixed-up by u-boot */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic 0 0 GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
+@@ -1136,6 +1141,7 @@
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x82000000 0x0 0x40000000 0xa8 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+                       msi-parent = <&its>;
++                      iommu-map = <0 &smmu 0 1>; /* This is fixed-up by u-boot */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0000 0 0 1 &gic 0 0 GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0105-LF-18-1-arm64-dts-ls1088ardb-Update-qspi-dts-node-pr.patch b/target/linux/layerscape/patches-5.4/302-dts-0105-LF-18-1-arm64-dts-ls1088ardb-Update-qspi-dts-node-pr.patch
new file mode 100644 (file)
index 0000000..bbe452b
--- /dev/null
@@ -0,0 +1,67 @@
+From 8f29fafb9c3b0936fb6f67212057127c13e17c1c Mon Sep 17 00:00:00 2001
+From: Kuldeep Singh <kuldeep.singh@nxp.com>
+Date: Tue, 7 Jan 2020 17:22:24 +0530
+Subject: [PATCH] LF-18-1 arm64: dts: ls1088ardb: Update qspi dts node
+ properties
+
+Use compatibles as "jedec,spi-nor" to probe flash without displaying
+warning: found s25fs512s, expected m25p80.
+Also remove "fsl,qspi-has-second-chip" property as new driver doesn't use
+it anymore.
+
+Update dtsi compatibles to use "fsl,ls2080a-qspi".
+
+Signed-off-by: Kuldeep Singh <kuldeep.singh@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts | 18 +++++++++---------
+ arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi    |  2 +-
+ 2 files changed, 10 insertions(+), 10 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts
+@@ -76,25 +76,25 @@
+ &qspi {
+       status = "okay";
+-      fsl,qspi-has-second-chip;
+-      qflash0: s25fs512s@0 {
+-              compatible = "spansion,m25p80";
++
++      s25fs512s0: flash@0 {
++              compatible = "jedec,spi-nor";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               spi-max-frequency = <20000000>;
+               reg = <0>;
+-              spi-rx-bus-width = <4>;
+-              spi-tx-bus-width = <4>;
++              spi-rx-bus-width = <1>;
++              spi-tx-bus-width = <1>;
+       };
+-      qflash1: s25fs512s@1 {
+-              compatible = "spansion,m25p80";
++      s25fs512s1: flash@1 {
++              compatible = "jedec,spi-nor";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               spi-max-frequency = <20000000>;
+               reg = <1>;
+-              spi-rx-bus-width = <4>;
+-              spi-tx-bus-width = <4>;
++              spi-rx-bus-width = <1>;
++              spi-tx-bus-width = <1>;
+       };
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+@@ -430,7 +430,7 @@
+                       status = "disabled";
+               };
+               qspi: spi@20c0000 {
+-                      compatible = "fsl,ls2080a-qspi", "fsl,ls1088a-qspi";
++                      compatible = "fsl,ls2080a-qspi";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0 0x20c0000 0x0 0x10000>,
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0106-LF-18-2-arm64-dts-ls1046ardb-Update-qspi-node-dts-pr.patch b/target/linux/layerscape/patches-5.4/302-dts-0106-LF-18-2-arm64-dts-ls1046ardb-Update-qspi-node-dts-pr.patch
new file mode 100644 (file)
index 0000000..ad2e4a7
--- /dev/null
@@ -0,0 +1,52 @@
+From ae5dad214ec109cdeffd3fac5ce4be6ab59a0283 Mon Sep 17 00:00:00 2001
+From: Kuldeep Singh <kuldeep.singh@nxp.com>
+Date: Fri, 3 Jan 2020 14:49:07 +0530
+Subject: [PATCH] LF-18-2 arm64: dts: ls1046ardb: Update qspi node dts
+ properties
+
+Use compatibles as "jedec,spi-nor" to probe flash without displaying
+warning: found s25fs512s, expected m25p80.
+Remove "fsl,qspi-has-second-chip" as new driver doesn't use it anymore.
+Update rx and tx width to 1.
+
+Signed-off-by: Kuldeep Singh <kuldeep.singh@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts | 17 ++++++++---------
+ 1 file changed, 8 insertions(+), 9 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts
+@@ -105,25 +105,24 @@
+ &qspi {
+       status = "okay";
+-      fsl,qspi-has-second-chip;
+-      qflash0: flash@0 {
+-              compatible = "spansion,m25p80";
++      s25fs512s0: flash@0 {
++              compatible = "jedec,spi-nor";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               spi-max-frequency = <50000000>;
+-              spi-rx-bus-width = <4>;
+-              spi-tx-bus-width = <4>;
++              spi-rx-bus-width = <1>;
++              spi-tx-bus-width = <1>;
+               reg = <0>;
+       };
+-      qflash1: flash@1 {
+-              compatible = "spansion,m25p80";
++      s25fs512s: flash@1 {
++              compatible = "jedec,spi-nor";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               spi-max-frequency = <50000000>;
+-              spi-rx-bus-width = <4>;
+-              spi-tx-bus-width = <4>;
++              spi-rx-bus-width = <1>;
++              spi-tx-bus-width = <1>;
+               reg = <1>;
+       };
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0107-arm64-dts-ls1012ardb-Update-qspi-node-property.patch b/target/linux/layerscape/patches-5.4/302-dts-0107-arm64-dts-ls1012ardb-Update-qspi-node-property.patch
new file mode 100644 (file)
index 0000000..7c4e91b
--- /dev/null
@@ -0,0 +1,43 @@
+From d870db86f12a69361472fc86bc516b89d9bf468c Mon Sep 17 00:00:00 2001
+From: Kuldeep Singh <kuldeep.singh@nxp.com>
+Date: Wed, 8 Jan 2020 15:50:44 +0530
+Subject: [PATCH] arm64: dts: ls1012ardb: Update qspi node property
+
+Use generic node name and specific label name.
+Add m25p,fast-read.
+
+Use dt-bindings constants in interrupts instead of using numbers.
+
+Signed-off-by: Kuldeep Singh <kuldeep.singh@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts | 3 ++-
+ arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi    | 2 +-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
+@@ -89,11 +89,12 @@
+ &qspi {
+       status = "okay";
+-      qflash0: s25fs512s@0 {
++      s25fs512s0: flash@0 {
+               compatible = "jedec,spi-nor";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               spi-max-frequency = <20000000>;
++              m25p,fast-read;
+               reg = <0>;
+               spi-rx-bus-width = <1>;
+               spi-tx-bus-width = <1>;
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+@@ -391,7 +391,7 @@
+                       reg = <0x0 0x1550000 0x0 0x10000>,
+                               <0x0 0x40000000 0x0 0x10000000>;
+                       reg-names = "QuadSPI", "QuadSPI-memory";
+-                      interrupts = <0 99 IRQ_TYPE_LEVEL_HIGH>;
++                      interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
+                       clock-names = "qspi_en", "qspi";
+                       clocks = <&clockgen 4 0>, <&clockgen 4 0>;
+                       status = "disabled";
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0108-Revert-arm64-dts-LS1028a-rdb-use-Ethernet-PHY-interr.patch b/target/linux/layerscape/patches-5.4/302-dts-0108-Revert-arm64-dts-LS1028a-rdb-use-Ethernet-PHY-interr.patch
new file mode 100644 (file)
index 0000000..efb5cb6
--- /dev/null
@@ -0,0 +1,85 @@
+From c57a0efc17627d0077408544ded02674aefdecae Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 6 Jan 2020 16:59:02 +0200
+Subject: [PATCH] Revert "arm64: dts: LS1028a-rdb: use Ethernet PHY interrupt"
+
+This reverts commit 841edb98671cfc4d6f010393ac429c78082ec4bd.
+
+There are 2 separate issues with interrupts on the LS1028A-RDB board:
+
+1. The GPIO1_DAT25 interrupt line is shared, so there is a real risk of
+   race conditions if used in edge-triggered mode, as we currently do.
+   This can be illustrated in the following setup:
+   - Take 2 LS1028A-RDB boards
+   - Connect swp0 to swp0, swp1 to swp1, swp2 to swp2
+   - Plug/unplug the power to board 2, 10 times in a row. This will make
+     the PHYs lose link simultaneously.
+   - Notice that at one point, the net devices on board 1 remain in a
+     state where not all the links are down (visible in "ip link"):
+
+     5: swp0: <BROADCAST,MULTICAST,UP> mtu 1468 qdisc pfifo_fast master br0 state UP mode DEFAULT group default qlen 1000
+         link/ether be:97:36:d3:3d:70 brd ff:ff:ff:ff:ff:ff
+     6: swp1: <BROADCAST,MULTICAST,UP> mtu 1468 qdisc pfifo_fast master br0 state UP mode DEFAULT group default qlen 1000
+         link/ether be:97:36:d3:3d:71 brd ff:ff:ff:ff:ff:ff
+     7: swp2: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1468 qdisc pfifo_fast master br0 state DOWN mode DEFAULT group default qlen 1000
+         link/ether be:97:36:d3:3d:72 brd ff:ff:ff:ff:ff:ff
+
+   This cannot be solved by making the interrupts level-triggered,
+   because the gpio-mpc8xxx controller only supports generating
+   edge-triggered interrupts. So the effective reality is that we
+   cannot not use shared interrupts connected to the gpio1
+   interrupt-parent.
+
+2. The uBUS1 and uBUS2 slots that share this interrupt line with the
+   Ethernet PHYs are not pulled up by default, they are left floating on
+   current revisions of the LS1028A-RDB boards. So sufficient electrical
+   noise on these lines will make the CPLD think there's an interrupt
+   request, so it asserts the GPIO1_DAT25 signal and leaves it asserted.
+   This means that the PHYs on those boards will never have link when
+   used in interrupt mode, because their IRQ will be masked by the uBUS
+   line that is erroneously kept asserted. In poll mode this issue does
+   not occur.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
+@@ -206,8 +206,6 @@
+               #size-cells = <0>;
+               sgmii_phy0: ethernet-phy@2 {
+                       reg = <0x2>;
+-                      interrupt-parent = <&gpio1>;
+-                      interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+               };
+       };
+ };
+@@ -219,26 +217,18 @@
+ &enetc_mdio_pf3 {
+       qsgmii_phy1: ethernet-phy@4 {
+               reg = <0x10>;
+-              interrupt-parent = <&gpio1>;
+-              interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+       };
+       qsgmii_phy2: ethernet-phy@5 {
+               reg = <0x11>;
+-              interrupt-parent = <&gpio1>;
+-              interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+       };
+       qsgmii_phy3: ethernet-phy@6 {
+               reg = <0x12>;
+-              interrupt-parent = <&gpio1>;
+-              interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+       };
+       qsgmii_phy4: ethernet-phy@7 {
+               reg = <0x13>;
+-              interrupt-parent = <&gpio1>;
+-              interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+       };
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0109-arm64-dts-ls1028a-rdb-Enable-SGMII-AN-for-the-QSGMII.patch b/target/linux/layerscape/patches-5.4/302-dts-0109-arm64-dts-ls1028a-rdb-Enable-SGMII-AN-for-the-QSGMII.patch
new file mode 100644 (file)
index 0000000..33d7109
--- /dev/null
@@ -0,0 +1,46 @@
+From 57c0539d99fed2252364b431de004f9110ac3d3f Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 6 Dec 2019 13:59:05 +0200
+Subject: [PATCH] arm64: dts: ls1028a-rdb: Enable SGMII AN for the QSGMII
+ switch ports
+
+This enables monitoring of link status and AN. It should also physically
+enable SGMII AN with the VSC8514 PHY, but in practice that is still
+hardcoded as "on" in the PHY driver, at the moment. So since Felix
+actually disables SGMII AN when this DT property is absent, this would
+result in an in-band AN mismatch between the MAC and the PHY. So this
+property is required for the moment for this MAC/PHY combination.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
+@@ -236,21 +236,25 @@
+ &switch_port0 {
+       phy-handle = <&qsgmii_phy1>;
+       phy-connection-type = "qsgmii";
++      managed = "in-band-status";
+ };
+ &switch_port1 {
+       phy-handle = <&qsgmii_phy2>;
+       phy-connection-type = "qsgmii";
++      managed = "in-band-status";
+ };
+ &switch_port2 {
+       phy-handle = <&qsgmii_phy3>;
+       phy-connection-type = "qsgmii";
++      managed = "in-band-status";
+ };
+ &switch_port3 {
+       phy-handle = <&qsgmii_phy4>;
+       phy-connection-type = "qsgmii";
++      managed = "in-band-status";
+ };
+ &sai4 {
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0110-arm64-dts-ls1028a-Disable-swp5-by-default.patch b/target/linux/layerscape/patches-5.4/302-dts-0110-arm64-dts-ls1028a-Disable-swp5-by-default.patch
new file mode 100644 (file)
index 0000000..b6c63c4
--- /dev/null
@@ -0,0 +1,22 @@
+From fd73bb7cf812fcb96116f70393d3e66aa4ddc1fa Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 6 Dec 2019 13:56:46 +0200
+Subject: [PATCH] arm64: dts: ls1028a: Disable swp5 by default
+
+This was missed when moving the CPU port and disabling eno3.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -810,6 +810,7 @@
+                                       port@5 {
+                                               reg = <5>;
+                                               phy-mode = "gmii";
++                                              status = "disabled";
+                                               fixed-link {
+                                                       speed = <1000>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0111-arm64-dts-fsl-ls1028a-rdb-fix-QSGMII-PHY-node-names.patch b/target/linux/layerscape/patches-5.4/302-dts-0111-arm64-dts-fsl-ls1028a-rdb-fix-QSGMII-PHY-node-names.patch
new file mode 100644 (file)
index 0000000..dbea8ab
--- /dev/null
@@ -0,0 +1,38 @@
+From 85252792bc07b398582e8dacf6ec6d09a5075195 Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Tue, 7 Jan 2020 15:15:29 +0200
+Subject: [PATCH] arm64: dts: fsl-ls1028a-rdb: fix QSGMII PHY node names
+
+Use ethernet-phy@ADDR, previously the numbers were wrong.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
+@@ -215,19 +215,19 @@
+ };
+ &enetc_mdio_pf3 {
+-      qsgmii_phy1: ethernet-phy@4 {
++      qsgmii_phy1: ethernet-phy@10 {
+               reg = <0x10>;
+       };
+-      qsgmii_phy2: ethernet-phy@5 {
++      qsgmii_phy2: ethernet-phy@11 {
+               reg = <0x11>;
+       };
+-      qsgmii_phy3: ethernet-phy@6 {
++      qsgmii_phy3: ethernet-phy@12 {
+               reg = <0x12>;
+       };
+-      qsgmii_phy4: ethernet-phy@7 {
++      qsgmii_phy4: ethernet-phy@13 {
+               reg = <0x13>;
+       };
+ };
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0112-arm64-dts-fsl-ls1028a-prepare-dts-for-overlay.patch b/target/linux/layerscape/patches-5.4/302-dts-0112-arm64-dts-fsl-ls1028a-prepare-dts-for-overlay.patch
new file mode 100644 (file)
index 0000000..ccadbf9
--- /dev/null
@@ -0,0 +1,452 @@
+From a5009b362d65c24e7b2a40824e351903d75a47dc Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Mon, 6 Jan 2020 16:36:44 +0200
+Subject: [PATCH] arm64: dts: fsl-ls1028a: prepare dts for overlay
+
+Named the ports node of the Felix Eth switch so it can be used in DT
+overlays to associate the ports with proper PHYs.
+Ports are now by default disabled in dtsi, so if the board dts doesn't
+do anything about them they stay disabled.
+Updated RDB and QDS dts files to match.
+Replaced all 'phy-connection-type' with 'phy-mode'.
+The set-up for protocol 7777 on QDS was changed to a single quad port card
+in slot 1.  This requires a QDS board with no lane B rework and a AQR412
+or similar PHY card without any lane rework done on it.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ .../boot/dts/freescale/fsl-ls1028a-qds-7777.dtsi   | 58 ++++++++++-----------
+ .../boot/dts/freescale/fsl-ls1028a-qds-9999.dtsi   | 59 ++++++++++------------
+ .../boot/dts/freescale/fsl-ls1028a-qds-x3xx.dtsi   | 51 ++++++++++++-------
+ .../boot/dts/freescale/fsl-ls1028a-qds-x5xx.dtsi   | 43 ++++++++++------
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts  | 44 +++++++++-------
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi     | 27 +++++++---
+ 6 files changed, 161 insertions(+), 121 deletions(-)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-7777.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-7777.dtsi
+@@ -7,50 +7,50 @@
+  */
+ &mdio_slot1 {
+-      /* two ports on AQR412 */
+-      slot1_sxgmii2: ethernet-phy@2 {
+-              reg = <0x2>;
++      slot1_sxgmii0: ethernet-phy@0 {
++              reg = <0x0>;
+               compatible = "ethernet-phy-ieee802.3-c45";
+       };
+-      slot1_sxgmii3: ethernet-phy@3 {
+-              reg = <0x3>;
++
++      slot1_sxgmii1: ethernet-phy@1 {
++              reg = <0x1>;
+               compatible = "ethernet-phy-ieee802.3-c45";
+       };
+-};
+-&mdio_slot2 {
+-      slot2_sxgmii0: ethernet-phy@2 {
+-              /* AQR112 */
++      slot1_sxgmii2: ethernet-phy@2 {
+               reg = <0x2>;
+               compatible = "ethernet-phy-ieee802.3-c45";
+       };
+-};
+-&mdio_slot3 {
+-      slot3_sxgmii0: ethernet-phy@2 {
+-              /* AQR112 */
+-              reg = <0x2>;
++      slot1_sxgmii3: ethernet-phy@3 {
++              reg = <0x3>;
+               compatible = "ethernet-phy-ieee802.3-c45";
+       };
+ };
+ /* l2switch ports */
+-&switch_port0 {
+-      phy-handle = <&slot1_sxgmii2>;
+-      phy-connection-type = "2500base-x";
+-};
++&mscc_felix_ports {
++      port@0 {
++              status = "okay";
++              phy-handle = <&slot1_sxgmii0>;
++              phy-mode = "2500base-x";
++      };
+-&switch_port1 {
+-      phy-handle = <&slot2_sxgmii0>;
+-      phy-connection-type = "2500base-x";
+-};
++      port@1 {
++              status = "okay";
++              phy-handle = <&slot1_sxgmii1>;
++              phy-mode = "2500base-x";
++      };
+-&switch_port2 {
+-      phy-handle = <&slot3_sxgmii0>;
+-      phy-connection-type = "2500base-x";
+-};
++      port@2 {
++              status = "okay";
++              phy-handle = <&slot1_sxgmii2>;
++              phy-mode = "2500base-x";
++      };
+-&switch_port3 {
+-      phy-handle = <&slot1_sxgmii3>;
+-      phy-connection-type = "2500base-x";
++      port@3 {
++              status = "okay";
++              phy-handle = <&slot1_sxgmii3>;
++              phy-mode = "2500base-x";
++      };
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-9999.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-9999.dtsi
+@@ -11,50 +11,47 @@
+       slot1_sgmii0: ethernet-phy@1c {
+               reg = <0x1c>;
+       };
++
+       slot1_sgmii1: ethernet-phy@1d {
+               reg = <0x1d>;
+       };
++
+       slot1_sgmii2: ethernet-phy@1e {
+               reg = <0x1e>;
+       };
+-      slot1_sgmii3: ethernet-phy@1f {
+-              reg = <0x1f>;
+-      };
+-};
+-&mdio_slot2 {
+-      /* VSC8234 */
+-      slot2_sgmii0: ethernet-phy@1c {
+-              reg = <0x1c>;
+-      };
+-      slot2_sgmii1: ethernet-phy@1d {
+-              reg = <0x1d>;
+-      };
+-      slot2_sgmii2: ethernet-phy@1e {
+-              reg = <0x1e>;
+-      };
+-      slot2_sgmii3: ethernet-phy@1f {
++      slot1_sgmii3: ethernet-phy@1f {
+               reg = <0x1f>;
+       };
+ };
+ /* l2switch ports */
+-&switch_port0 {
+-      phy-handle = <&slot1_sgmii0>;
+-      phy-connection-type = "sgmii";
+-};
++&mscc_felix_ports {
++      port@0 {
++              status = "okay";
++              phy-handle = <&slot1_sgmii0>;
++              phy-mode = "sgmii";
++              managed = "in-band-status";
++      };
+-&switch_port1 {
+-      phy-handle = <&slot2_sgmii0>;
+-      phy-connection-type = "sgmii";
+-};
++      port@1 {
++              status = "okay";
++              phy-handle = <&slot1_sgmii1>;
++              phy-mode = "sgmii";
++              managed = "in-band-status";
++      };
+-&switch_port2 {
+-      phy-handle = <&slot1_sgmii2>;
+-      phy-connection-type = "sgmii";
+-};
++      port@2 {
++              status = "okay";
++              phy-handle = <&slot1_sgmii2>;
++              phy-mode = "sgmii";
++              managed = "in-band-status";
++      };
+-&switch_port3 {
+-      phy-handle = <&slot1_sgmii3>;
+-      phy-connection-type = "sgmii";
++      port@3 {
++              status = "okay";
++              phy-handle = <&slot1_sgmii3>;
++              phy-mode = "sgmii";
++              managed = "in-band-status";
++      };
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-x3xx.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-x3xx.dtsi
+@@ -8,41 +8,54 @@
+ &mdio_slot2 {
+       /* 4 ports on AQR412 */
+-      slot2_qsgmii0: ethernet-phy@0 {
++      slot2_qxgmii0: ethernet-phy@0 {
+               reg = <0x0>;
+               compatible = "ethernet-phy-ieee802.3-c45";
+       };
+-      slot2_qsgmii1: ethernet-phy@1 {
++
++      slot2_qxgmii1: ethernet-phy@1 {
+               reg = <0x1>;
+               compatible = "ethernet-phy-ieee802.3-c45";
+       };
+-      slot2_qsgmii2: ethernet-phy@2 {
++
++      slot2_qxgmii2: ethernet-phy@2 {
+               reg = <0x2>;
+               compatible = "ethernet-phy-ieee802.3-c45";
+       };
+-      slot2_qsgmii3: ethernet-phy@3 {
++
++      slot2_qxgmii3: ethernet-phy@3 {
+               reg = <0x3>;
+               compatible = "ethernet-phy-ieee802.3-c45";
+       };
+ };
+ /* l2switch ports */
+-&switch_port0 {
+-      phy-handle = <&slot2_qsgmii0>;
+-      phy-connection-type = "usxgmii";
+-};
++&mscc_felix_ports {
++      port@0 {
++              status = "okay";
++              phy-handle = <&slot2_qxgmii0>;
++              phy-mode = "usxgmii";
++              managed = "in-band-status";
++      };
+-&switch_port1 {
+-      phy-handle = <&slot2_qsgmii1>;
+-      phy-connection-type = "usxgmii";
+-};
++      port@1 {
++              status = "okay";
++              phy-handle = <&slot2_qxgmii1>;
++              phy-mode = "usxgmii";
++              managed = "in-band-status";
++      };
+-&switch_port2 {
+-      phy-handle = <&slot2_qsgmii2>;
+-      phy-connection-type = "usxgmii";
+-};
++      port@2 {
++              status = "okay";
++              phy-handle = <&slot2_qxgmii2>;
++              phy-mode = "usxgmii";
++              managed = "in-band-status";
++      };
+-&switch_port3 {
+-      phy-handle = <&slot2_qsgmii3>;
+-      phy-connection-type = "usxgmii";
++      port@3 {
++              status = "okay";
++              phy-handle = <&slot2_qxgmii3>;
++              phy-mode = "usxgmii";
++              managed = "in-band-status";
++      };
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-x5xx.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-x5xx.dtsi
+@@ -11,34 +11,47 @@
+       slot2_qsgmii0: ethernet-phy@8 {
+               reg = <0x8>;
+       };
++
+       slot2_qsgmii1: ethernet-phy@9 {
+               reg = <0x9>;
+       };
++
+       slot2_qsgmii2: ethernet-phy@a {
+               reg = <0xa>;
+       };
++
+       slot2_qsgmii3: ethernet-phy@b {
+               reg = <0xb>;
+       };
+ };
+ /* l2switch ports */
+-&switch_port0 {
+-      phy-handle = <&slot2_qsgmii0>;
+-      phy-connection-type = "qsgmii";
+-};
++&mscc_felix_ports {
++      port@0 {
++              status = "okay";
++              phy-handle = <&slot2_qsgmii0>;
++              phy-mode = "qsgmii";
++              managed = "in-band-status";
++      };
+-&switch_port1 {
+-      phy-handle = <&slot2_qsgmii1>;
+-      phy-connection-type = "qsgmii";
+-};
++      port@1 {
++              status = "okay";
++              phy-handle = <&slot2_qsgmii1>;
++              phy-mode = "qsgmii";
++              managed = "in-band-status";
++      };
+-&switch_port2 {
+-      phy-handle = <&slot2_qsgmii2>;
+-      phy-connection-type = "qsgmii";
+-};
++      port@2 {
++              status = "okay";
++              phy-handle = <&slot2_qsgmii2>;
++              phy-mode = "qsgmii";
++              managed = "in-band-status";
++      };
+-&switch_port3 {
+-      phy-handle = <&slot2_qsgmii3>;
+-      phy-connection-type = "qsgmii";
++      port@3 {
++              status = "okay";
++              phy-handle = <&slot2_qsgmii3>;
++              phy-mode = "qsgmii";
++              managed = "in-band-status";
++      };
+ };
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
+@@ -233,28 +233,34 @@
+ };
+ /* l2switch ports */
+-&switch_port0 {
+-      phy-handle = <&qsgmii_phy1>;
+-      phy-connection-type = "qsgmii";
+-      managed = "in-band-status";
+-};
++&mscc_felix_ports {
++      port@0 {
++              status = "okay";
++              phy-handle = <&qsgmii_phy1>;
++              phy-mode = "qsgmii";
++              managed = "in-band-status";
++      };
+-&switch_port1 {
+-      phy-handle = <&qsgmii_phy2>;
+-      phy-connection-type = "qsgmii";
+-      managed = "in-band-status";
+-};
++      port@1 {
++              status = "okay";
++              phy-handle = <&qsgmii_phy2>;
++              phy-mode = "qsgmii";
++              managed = "in-band-status";
++      };
+-&switch_port2 {
+-      phy-handle = <&qsgmii_phy3>;
+-      phy-connection-type = "qsgmii";
+-      managed = "in-band-status";
+-};
++      port@2 {
++              status = "okay";
++              phy-handle = <&qsgmii_phy3>;
++              phy-mode = "qsgmii";
++              managed = "in-band-status";
++      };
+-&switch_port3 {
+-      phy-handle = <&qsgmii_phy4>;
+-      phy-connection-type = "qsgmii";
+-      managed = "in-band-status";
++      port@3 {
++              status = "okay";
++              phy-handle = <&qsgmii_phy4>;
++              phy-mode = "qsgmii";
++              managed = "in-band-status";
++      };
+ };
+ &sai4 {
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -774,30 +774,39 @@
+                               clocks = <&clockgen 4 0>;
+                               little-endian;
+                       };
+-                      switch@0,5 {
++
++                      ethernet-switch@0,5 {
+                               reg = <0x000500 0 0 0 0>;
+                               /* IEP INT_B */
+                               interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
+-                              ports {
++                              mscc_felix_ports: ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+                                       /* external ports */
+-                                      switch_port0: port@0 {
++                                      mscc_felix_port0: port@0 {
+                                               reg = <0>;
++                                              status = "disabled";
+                                       };
+-                                      switch_port1: port@1 {
++
++                                      mscc_felix_port1: port@1 {
+                                               reg = <1>;
++                                              status = "disabled";
+                                       };
+-                                      switch_port2: port@2 {
++
++                                      mscc_felix_port2: port@2 {
+                                               reg = <2>;
++                                              status = "disabled";
+                                       };
+-                                      switch_port3: port@3 {
++
++                                      mscc_felix_port3: port@3 {
+                                               reg = <3>;
++                                              status = "disabled";
+                                       };
++
+                                       /* internal to-cpu ports */
+-                                      port@4 {
++                                      mscc_felix_port4: port@4 {
+                                               reg = <4>;
+                                               ethernet = <&enetc_port2>;
+                                               phy-mode = "gmii";
+@@ -807,7 +816,8 @@
+                                                       full-duplex;
+                                               };
+                                       };
+-                                      port@5 {
++
++                                      mscc_felix_port5: port@5 {
+                                               reg = <5>;
+                                               phy-mode = "gmii";
+                                               status = "disabled";
+@@ -819,6 +829,7 @@
+                                       };
+                               };
+                       };
++
+                       enetc_port3: ethernet@0,6 {
+                               compatible = "fsl,enetc";
+                               reg = <0x000600 0 0 0 0>;
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0113-arm64-dts-fsl-ls1028a-qds-Add-overlays-for-various-s.patch b/target/linux/layerscape/patches-5.4/302-dts-0113-arm64-dts-fsl-ls1028a-qds-Add-overlays-for-various-s.patch
new file mode 100644 (file)
index 0000000..0d1b23c
--- /dev/null
@@ -0,0 +1,893 @@
+From d2333a40b00ba5fb5b9731f96ca663036f781411 Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Tue, 7 Jan 2020 14:48:20 +0200
+Subject: [PATCH] arm64: dts: fsl-ls1028a-qds: Add overlays for various serdes
+ protocols
+
+Adds overlays for various serdes protocols on LS1028A QDS board using
+different PHY cards.  These should be applied at boot, based on serdes
+configuration.  If no overlay is applied, only the RGMII interface on
+the QDS is available in Linux.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/Makefile             |   6 ++
+ .../boot/dts/freescale/fsl-ls1028a-qds-13bb.dts    | 100 +++++++++++++++++++++
+ .../boot/dts/freescale/fsl-ls1028a-qds-1xxx.dtsi   |  20 -----
+ .../boot/dts/freescale/fsl-ls1028a-qds-65bb.dts    |  94 +++++++++++++++++++
+ .../boot/dts/freescale/fsl-ls1028a-qds-6xxx.dtsi   |  20 -----
+ .../boot/dts/freescale/fsl-ls1028a-qds-7777.dts    |  73 +++++++++++++++
+ .../boot/dts/freescale/fsl-ls1028a-qds-7777.dtsi   |  56 ------------
+ .../boot/dts/freescale/fsl-ls1028a-qds-85bb.dts    |  93 +++++++++++++++++++
+ .../boot/dts/freescale/fsl-ls1028a-qds-899b.dts    |  66 ++++++++++++++
+ .../boot/dts/freescale/fsl-ls1028a-qds-8xxx.dtsi   |  19 ----
+ .../boot/dts/freescale/fsl-ls1028a-qds-9999.dts    |  71 +++++++++++++++
+ .../boot/dts/freescale/fsl-ls1028a-qds-9999.dtsi   |  57 ------------
+ .../boot/dts/freescale/fsl-ls1028a-qds-x3xx.dtsi   |  61 -------------
+ .../boot/dts/freescale/fsl-ls1028a-qds-x5xx.dtsi   |  57 ------------
+ arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts  |   3 -
+ 15 files changed, 503 insertions(+), 293 deletions(-)
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-13bb.dts
+ delete mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-1xxx.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-65bb.dts
+ delete mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-6xxx.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-7777.dts
+ delete mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-7777.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-85bb.dts
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-899b.dts
+ delete mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-8xxx.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-9999.dts
+ delete mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-9999.dtsi
+ delete mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-x3xx.dtsi
+ delete mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-x5xx.dtsi
+
+--- a/arch/arm64/boot/dts/freescale/Makefile
++++ b/arch/arm64/boot/dts/freescale/Makefile
+@@ -6,6 +6,12 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-qds.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-rdb.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds-13bb.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds-65bb.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds-7777.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds-85bb.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds-899b.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds-9999.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds-sdk.dtb
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-13bb.dts
+@@ -0,0 +1,100 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree fragment for LS1028A QDS board, serdes 13bb
++ *
++ * Copyright 2019 NXP
++ *
++ * Requires a LS1028A QDS board with lane B rework.
++ * Requires a SCH-30841 card with lane A of connector rewired to PHY lane C.
++ * Set-up is a SCH-30842 card in slot 1 and SCH-30841 in slot 2.
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++      fragment@0 {
++              target = <&mdio_slot1>;
++              __overlay__ {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++
++                      slot1_sgmii: ethernet-phy@2 {
++                              /* AQR112 */
++                              reg = <0x2>;
++                              compatible = "ethernet-phy-ieee802.3-c45";
++                      };
++              };
++      };
++
++      fragment@1 {
++              target = <&enetc_port0>;
++              __overlay__ {
++                      phy-handle = <&slot1_sgmii>;
++                      phy-mode = "usxgmii";
++              };
++      };
++
++      fragment@2 {
++              target = <&mdio_slot2>;
++              __overlay__ {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++
++                      /* 4 ports on AQR412 */
++                      slot2_qxgmii0: ethernet-phy@0 {
++                              reg = <0x0>;
++                              compatible = "ethernet-phy-ieee802.3-c45";
++                      };
++
++                      slot2_qxgmii1: ethernet-phy@1 {
++                              reg = <0x1>;
++                              compatible = "ethernet-phy-ieee802.3-c45";
++                      };
++
++                      slot2_qxgmii2: ethernet-phy@2 {
++                              reg = <0x2>;
++                              compatible = "ethernet-phy-ieee802.3-c45";
++                      };
++
++                      slot2_qxgmii3: ethernet-phy@3 {
++                              reg = <0x3>;
++                              compatible = "ethernet-phy-ieee802.3-c45";
++                      };
++              };
++      };
++
++      fragment@3 {
++              target = <&mscc_felix_ports>;
++              __overlay__ {
++                      port@0 {
++                              status = "okay";
++                              phy-handle = <&slot2_qxgmii0>;
++                              phy-mode = "usxgmii";
++                              managed = "in-band-status";
++                      };
++
++                      port@1 {
++                              status = "okay";
++                              phy-handle = <&slot2_qxgmii1>;
++                              phy-mode = "usxgmii";
++                              managed = "in-band-status";
++                      };
++
++                      port@2 {
++                              status = "okay";
++                              phy-handle = <&slot2_qxgmii2>;
++                              phy-mode = "usxgmii";
++                              managed = "in-band-status";
++                      };
++
++                      port@3 {
++                              status = "okay";
++                              phy-handle = <&slot2_qxgmii3>;
++                              phy-mode = "usxgmii";
++                              managed = "in-band-status";
++                      };
++              };
++      };
++};
++
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-1xxx.dtsi
++++ /dev/null
+@@ -1,20 +0,0 @@
+-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+-/*
+- * Device Tree Include file for LS1028A QDS board, serdes 1xxx
+- *
+- * Copyright 2019 NXP
+- *
+- */
+-
+-&mdio_slot1 {
+-      slot1_sgmii: ethernet-phy@2 {
+-              /* AQR112 */
+-              reg = <0x2>;
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-      };
+-};
+-
+-&enetc_port0 {
+-      phy-handle = <&slot1_sgmii>;
+-      phy-connection-type = "usxgmii";
+-};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-65bb.dts
+@@ -0,0 +1,94 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree fragment for LS1028A QDS board, serdes 69xx
++ *
++ * Copyright 2019 NXP
++ *
++ * Requires a LS1028A QDS board with lane B rework.
++ * Requires a SCH-30842 card in slot 1 and a SCH-28021 card in slot 2.
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++      fragment@0 {
++              target = <&mdio_slot1>;
++              __overlay__ {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++
++                      slot1_sgmii: ethernet-phy@2 {
++                              /* AQR112 */
++                              reg = <0x2>;
++                              compatible = "ethernet-phy-ieee802.3-c45";
++                      };
++              };
++      };
++
++      fragment@1 {
++              target = <&enetc_port0>;
++              __overlay__ {
++                      phy-handle = <&slot1_sgmii>;
++                      phy-mode = "2500base-x";
++              };
++      };
++
++      fragment@2 {
++              target = <&mdio_slot2>;
++              __overlay__ {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++
++                      /* 4 ports on VSC8514 */
++                      slot2_qsgmii0: ethernet-phy@8 {
++                              reg = <0x8>;
++                      };
++
++                      slot2_qsgmii1: ethernet-phy@9 {
++                              reg = <0x9>;
++                      };
++
++                      slot2_qsgmii2: ethernet-phy@a {
++                              reg = <0xa>;
++                      };
++
++                      slot2_qsgmii3: ethernet-phy@b {
++                              reg = <0xb>;
++                      };
++              };
++      };
++
++      fragment@3 {
++              target = <&mscc_felix_ports>;
++              __overlay__ {
++                      port@0 {
++                              status = "okay";
++                              phy-handle = <&slot2_qsgmii0>;
++                              phy-mode = "qsgmii";
++                              managed = "in-band-status";
++                      };
++
++                      port@1 {
++                              status = "okay";
++                              phy-handle = <&slot2_qsgmii1>;
++                              phy-mode = "qsgmii";
++                              managed = "in-band-status";
++                      };
++
++                      port@2 {
++                              status = "okay";
++                              phy-handle = <&slot2_qsgmii2>;
++                              phy-mode = "qsgmii";
++                              managed = "in-band-status";
++                      };
++
++                      port@3 {
++                              status = "okay";
++                              phy-handle = <&slot2_qsgmii3>;
++                              phy-mode = "qsgmii";
++                              managed = "in-band-status";
++                      };
++              };
++      };
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-6xxx.dtsi
++++ /dev/null
+@@ -1,20 +0,0 @@
+-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+-/*
+- * Device Tree Include file for LS1028A QDS board, serdes 6xxx
+- *
+- * Copyright 2019 NXP
+- *
+- */
+-
+-&mdio_slot1 {
+-      slot1_sgmii: ethernet-phy@2 {
+-              /* AQR112 */
+-              reg = <0x2>;
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-      };
+-};
+-
+-&enetc_port0 {
+-      phy-handle = <&slot1_sgmii>;
+-      phy-connection-type = "2500base-x";
+-};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-7777.dts
+@@ -0,0 +1,73 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree fragment for LS1028A QDS board, serdes 7777
++ *
++ * Copyright 2019 NXP
++ *
++ * Requires a LS1028A QDS board without lane B rework.
++ * Requires a SCH-30841 card without lane A/C rewire and with a FW with muxing
++ * disabled, plugged in slot 1.
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++      fragment@0 {
++              target = <&mdio_slot1>;
++              __overlay__ {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++
++                      /* 4 ports on AQR412 */
++                      slot1_sxgmii0: ethernet-phy@0 {
++                              reg = <0x0>;
++                              compatible = "ethernet-phy-ieee802.3-c45";
++                      };
++
++                      slot1_sxgmii1: ethernet-phy@1 {
++                              reg = <0x1>;
++                              compatible = "ethernet-phy-ieee802.3-c45";
++                      };
++
++                      slot1_sxgmii2: ethernet-phy@2 {
++                              reg = <0x2>;
++                              compatible = "ethernet-phy-ieee802.3-c45";
++                      };
++
++                      slot1_sxgmii3: ethernet-phy@3 {
++                              reg = <0x3>;
++                              compatible = "ethernet-phy-ieee802.3-c45";
++                      };
++              };
++      };
++
++      fragment@1 {
++              target = <&mscc_felix_ports>;
++              __overlay__ {
++                      port@0 {
++                              status = "okay";
++                              phy-handle = <&slot1_sxgmii0>;
++                              phy-mode = "2500base-x";
++                      };
++
++                      port@1 {
++                              status = "okay";
++                              phy-handle = <&slot1_sxgmii1>;
++                              phy-mode = "2500base-x";
++                      };
++
++                      port@2 {
++                              status = "okay";
++                              phy-handle = <&slot1_sxgmii2>;
++                              phy-mode = "2500base-x";
++                      };
++
++                      port@3 {
++                              status = "okay";
++                              phy-handle = <&slot1_sxgmii3>;
++                              phy-mode = "2500base-x";
++                      };
++              };
++      };
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-7777.dtsi
++++ /dev/null
+@@ -1,56 +0,0 @@
+-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+-/*
+- * Device Tree Include file for LS1028A QDS board, serdes 9999
+- *
+- * Copyright 2019 NXP
+- *
+- */
+-
+-&mdio_slot1 {
+-      slot1_sxgmii0: ethernet-phy@0 {
+-              reg = <0x0>;
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-      };
+-
+-      slot1_sxgmii1: ethernet-phy@1 {
+-              reg = <0x1>;
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-      };
+-
+-      slot1_sxgmii2: ethernet-phy@2 {
+-              reg = <0x2>;
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-      };
+-
+-      slot1_sxgmii3: ethernet-phy@3 {
+-              reg = <0x3>;
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-      };
+-};
+-
+-/* l2switch ports */
+-&mscc_felix_ports {
+-      port@0 {
+-              status = "okay";
+-              phy-handle = <&slot1_sxgmii0>;
+-              phy-mode = "2500base-x";
+-      };
+-
+-      port@1 {
+-              status = "okay";
+-              phy-handle = <&slot1_sxgmii1>;
+-              phy-mode = "2500base-x";
+-      };
+-
+-      port@2 {
+-              status = "okay";
+-              phy-handle = <&slot1_sxgmii2>;
+-              phy-mode = "2500base-x";
+-      };
+-
+-      port@3 {
+-              status = "okay";
+-              phy-handle = <&slot1_sxgmii3>;
+-              phy-mode = "2500base-x";
+-      };
+-};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-85bb.dts
+@@ -0,0 +1,93 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree fragment for LS1028A QDS board, serdes 85bb
++ *
++ * Copyright 2019 NXP
++ *
++ * Requires a LS1028A QDS board with lane B rework.
++ * Requires a SCH-24801 card in slot 1 and a SCH-28021 card in slot 2.
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++      fragment@0 {
++              target = <&mdio_slot1>;
++              __overlay__ {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++
++                      slot1_sgmii: ethernet-phy@1c {
++                              /* 1st port on VSC8234 */
++                              reg = <0x1c>;
++                      };
++              };
++      };
++
++      fragment@1 {
++              target = <&enetc_port0>;
++              __overlay__ {
++                      phy-handle = <&slot1_sgmii>;
++                      phy-mode = "sgmii";
++              };
++      };
++
++      fragment@2 {
++              target = <&mdio_slot2>;
++              __overlay__ {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++
++                      /* 4 ports on VSC8514 */
++                      slot2_qsgmii0: ethernet-phy@8 {
++                              reg = <0x8>;
++                      };
++
++                      slot2_qsgmii1: ethernet-phy@9 {
++                              reg = <0x9>;
++                      };
++
++                      slot2_qsgmii2: ethernet-phy@a {
++                              reg = <0xa>;
++                      };
++
++                      slot2_qsgmii3: ethernet-phy@b {
++                              reg = <0xb>;
++                      };
++              };
++      };
++
++      fragment@3 {
++              target = <&mscc_felix_ports>;
++              __overlay__ {
++                      port@0 {
++                              status = "okay";
++                              phy-handle = <&slot2_qsgmii0>;
++                              phy-mode = "qsgmii";
++                              managed = "in-band-status";
++                      };
++
++                      port@1 {
++                              status = "okay";
++                              phy-handle = <&slot2_qsgmii1>;
++                              phy-mode = "qsgmii";
++                              managed = "in-band-status";
++                      };
++
++                      port@2 {
++                              status = "okay";
++                              phy-handle = <&slot2_qsgmii2>;
++                              phy-mode = "qsgmii";
++                              managed = "in-band-status";
++                      };
++
++                      port@3 {
++                              status = "okay";
++                              phy-handle = <&slot2_qsgmii3>;
++                              phy-mode = "qsgmii";
++                              managed = "in-band-status";
++                      };
++              };
++      };
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-899b.dts
+@@ -0,0 +1,66 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree fragment for LS1028A QDS board, serdes 85xx
++ *
++ * Copyright 2019 NXP
++ *
++ * Requires a LS1028A QDS board without lane B rework.
++ * Requires a SCH-24801 card in slot 1.
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++      fragment@0 {
++              target = <&mdio_slot1>;
++              __overlay__ {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++
++                      /* VSC8234 */
++                      slot1_sgmii0: ethernet-phy@1c {
++                              reg = <0x1c>;
++                      };
++
++                      slot1_sgmii1: ethernet-phy@1d {
++                              reg = <0x1d>;
++                      };
++
++                      slot1_sgmii2: ethernet-phy@1e {
++                              reg = <0x1e>;
++                      };
++
++                      slot1_sgmii3: ethernet-phy@1f {
++                              reg = <0x1f>;
++                      };
++              };
++      };
++
++      fragment@1 {
++              target = <&enetc_port0>;
++              __overlay__ {
++                      phy-handle = <&slot1_sgmii0>;
++                      phy-mode = "sgmii";
++              };
++      };
++
++      fragment@2 {
++              target = <&mscc_felix_ports>;
++              __overlay__ {
++                      port@1 {
++                              status = "okay";
++                              phy-handle = <&slot1_sgmii1>;
++                              phy-mode = "sgmii";
++                              managed = "in-band-status";
++                      };
++
++                      port@2 {
++                              status = "okay";
++                              phy-handle = <&slot1_sgmii2>;
++                              phy-mode = "sgmii";
++                              managed = "in-band-status";
++                      };
++              };
++      };
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-8xxx.dtsi
++++ /dev/null
+@@ -1,19 +0,0 @@
+-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+-/*
+- * Device Tree Include file for LS1028A QDS board, serdes 8xxx
+- *
+- * Copyright 2019 NXP
+- *
+- */
+-
+-&mdio_slot1 {
+-      slot1_sgmii: ethernet-phy@1c {
+-              /* 1st port on VSC8234 */
+-              reg = <0x1c>;
+-      };
+-};
+-
+-&enetc_port0 {
+-      phy-handle = <&slot1_sgmii>;
+-      phy-connection-type = "sgmii";
+-};
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-9999.dts
+@@ -0,0 +1,71 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Device Tree fragment for LS1028A QDS board, serdes 85xx
++ *
++ * Copyright 2019 NXP
++ *
++ * Requires a LS1028A QDS board without lane B rework.
++ * Requires a SCH-24801 card in slot 1.
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++      fragment@0 {
++              target = <&mdio_slot1>;
++              __overlay__ {
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++
++                      /* VSC8234 */
++                      slot1_sgmii0: ethernet-phy@1c {
++                              reg = <0x1c>;
++                      };
++
++                      slot1_sgmii1: ethernet-phy@1d {
++                              reg = <0x1d>;
++                      };
++
++                      slot1_sgmii2: ethernet-phy@1e {
++                              reg = <0x1e>;
++                      };
++
++                      slot1_sgmii3: ethernet-phy@1f {
++                              reg = <0x1f>;
++                      };
++              };
++      };
++      fragment@1 {
++              target = <&mscc_felix_ports>;
++              __overlay__ {
++                      port@0 {
++                              status = "okay";
++                              phy-handle = <&slot1_sgmii0>;
++                              phy-mode = "sgmii";
++                              managed = "in-band-status";
++                      };
++
++                      port@1 {
++                              status = "okay";
++                              phy-handle = <&slot1_sgmii1>;
++                              phy-mode = "sgmii";
++                              managed = "in-band-status";
++                      };
++
++                      port@2 {
++                              status = "okay";
++                              phy-handle = <&slot1_sgmii2>;
++                              phy-mode = "sgmii";
++                              managed = "in-band-status";
++                      };
++
++                      port@3 {
++                              status = "okay";
++                              phy-handle = <&slot1_sgmii3>;
++                              phy-mode = "sgmii";
++                              managed = "in-band-status";
++                      };
++              };
++      };
++};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-9999.dtsi
++++ /dev/null
+@@ -1,57 +0,0 @@
+-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+-/*
+- * Device Tree Include file for LS1028A QDS board, serdes 9999
+- *
+- * Copyright 2019 NXP
+- *
+- */
+-
+-&mdio_slot1 {
+-      /* VSC8234 */
+-      slot1_sgmii0: ethernet-phy@1c {
+-              reg = <0x1c>;
+-      };
+-
+-      slot1_sgmii1: ethernet-phy@1d {
+-              reg = <0x1d>;
+-      };
+-
+-      slot1_sgmii2: ethernet-phy@1e {
+-              reg = <0x1e>;
+-      };
+-
+-      slot1_sgmii3: ethernet-phy@1f {
+-              reg = <0x1f>;
+-      };
+-};
+-
+-/* l2switch ports */
+-&mscc_felix_ports {
+-      port@0 {
+-              status = "okay";
+-              phy-handle = <&slot1_sgmii0>;
+-              phy-mode = "sgmii";
+-              managed = "in-band-status";
+-      };
+-
+-      port@1 {
+-              status = "okay";
+-              phy-handle = <&slot1_sgmii1>;
+-              phy-mode = "sgmii";
+-              managed = "in-band-status";
+-      };
+-
+-      port@2 {
+-              status = "okay";
+-              phy-handle = <&slot1_sgmii2>;
+-              phy-mode = "sgmii";
+-              managed = "in-band-status";
+-      };
+-
+-      port@3 {
+-              status = "okay";
+-              phy-handle = <&slot1_sgmii3>;
+-              phy-mode = "sgmii";
+-              managed = "in-band-status";
+-      };
+-};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-x3xx.dtsi
++++ /dev/null
+@@ -1,61 +0,0 @@
+-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+-/*
+- * Device Tree Include file for LS1028A QDS board, serdes x3xx
+- *
+- * Copyright 2019 NXP
+- *
+- */
+-
+-&mdio_slot2 {
+-      /* 4 ports on AQR412 */
+-      slot2_qxgmii0: ethernet-phy@0 {
+-              reg = <0x0>;
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-      };
+-
+-      slot2_qxgmii1: ethernet-phy@1 {
+-              reg = <0x1>;
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-      };
+-
+-      slot2_qxgmii2: ethernet-phy@2 {
+-              reg = <0x2>;
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-      };
+-
+-      slot2_qxgmii3: ethernet-phy@3 {
+-              reg = <0x3>;
+-              compatible = "ethernet-phy-ieee802.3-c45";
+-      };
+-};
+-
+-/* l2switch ports */
+-&mscc_felix_ports {
+-      port@0 {
+-              status = "okay";
+-              phy-handle = <&slot2_qxgmii0>;
+-              phy-mode = "usxgmii";
+-              managed = "in-band-status";
+-      };
+-
+-      port@1 {
+-              status = "okay";
+-              phy-handle = <&slot2_qxgmii1>;
+-              phy-mode = "usxgmii";
+-              managed = "in-band-status";
+-      };
+-
+-      port@2 {
+-              status = "okay";
+-              phy-handle = <&slot2_qxgmii2>;
+-              phy-mode = "usxgmii";
+-              managed = "in-band-status";
+-      };
+-
+-      port@3 {
+-              status = "okay";
+-              phy-handle = <&slot2_qxgmii3>;
+-              phy-mode = "usxgmii";
+-              managed = "in-band-status";
+-      };
+-};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-x5xx.dtsi
++++ /dev/null
+@@ -1,57 +0,0 @@
+-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+-/*
+- * Device Tree Include file for LS1028A QDS board, serdes x5xx
+- *
+- * Copyright 2019 NXP
+- *
+- */
+-
+-&mdio_slot2 {
+-      /* 4 ports on VSC8514 */
+-      slot2_qsgmii0: ethernet-phy@8 {
+-              reg = <0x8>;
+-      };
+-
+-      slot2_qsgmii1: ethernet-phy@9 {
+-              reg = <0x9>;
+-      };
+-
+-      slot2_qsgmii2: ethernet-phy@a {
+-              reg = <0xa>;
+-      };
+-
+-      slot2_qsgmii3: ethernet-phy@b {
+-              reg = <0xb>;
+-      };
+-};
+-
+-/* l2switch ports */
+-&mscc_felix_ports {
+-      port@0 {
+-              status = "okay";
+-              phy-handle = <&slot2_qsgmii0>;
+-              phy-mode = "qsgmii";
+-              managed = "in-band-status";
+-      };
+-
+-      port@1 {
+-              status = "okay";
+-              phy-handle = <&slot2_qsgmii1>;
+-              phy-mode = "qsgmii";
+-              managed = "in-band-status";
+-      };
+-
+-      port@2 {
+-              status = "okay";
+-              phy-handle = <&slot2_qsgmii2>;
+-              phy-mode = "qsgmii";
+-              managed = "in-band-status";
+-      };
+-
+-      port@3 {
+-              status = "okay";
+-              phy-handle = <&slot2_qsgmii3>;
+-              phy-mode = "qsgmii";
+-              managed = "in-band-status";
+-      };
+-};
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
+@@ -276,6 +276,3 @@
+       lane-mapping = <0x4e>;
+       status = "okay";
+ };
+-
+-#include "fsl-ls1028a-qds-8xxx.dtsi"
+-#include "fsl-ls1028a-qds-x5xx.dtsi"
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0114-arm64-dts-fsl-ls1028a-add-labels-to-Ethernet-switch-.patch b/target/linux/layerscape/patches-5.4/302-dts-0114-arm64-dts-fsl-ls1028a-add-labels-to-Ethernet-switch-.patch
new file mode 100644 (file)
index 0000000..0a1b548
--- /dev/null
@@ -0,0 +1,41 @@
+From e8f521154dbf16a91cba229f7514cca8e136702e Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Mon, 6 Jan 2020 11:48:42 +0200
+Subject: [PATCH] arm64: dts: fsl-ls1028a: add labels to Ethernet switch ports
+
+Labels are used to name switch port net devices in Linux, use more
+convenient names to make it simpler for users.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+@@ -788,21 +788,25 @@
+                                       mscc_felix_port0: port@0 {
+                                               reg = <0>;
+                                               status = "disabled";
++                                              label = "swp0";
+                                       };
+                                       mscc_felix_port1: port@1 {
+                                               reg = <1>;
+                                               status = "disabled";
++                                              label = "swp1";
+                                       };
+                                       mscc_felix_port2: port@2 {
+                                               reg = <2>;
+                                               status = "disabled";
++                                              label = "swp2";
+                                       };
+                                       mscc_felix_port3: port@3 {
+                                               reg = <3>;
+                                               status = "disabled";
++                                              label = "swp3";
+                                       };
+                                       /* internal to-cpu ports */
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0115-LF-789-2-arm64-dts-add-overlay-support-for-ls1028a-q.patch b/target/linux/layerscape/patches-5.4/302-dts-0115-LF-789-2-arm64-dts-add-overlay-support-for-ls1028a-q.patch
new file mode 100644 (file)
index 0000000..440e583
--- /dev/null
@@ -0,0 +1,36 @@
+From 911d3d1ea88ff6d56258d6173be7fc25290948a7 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Fri, 10 Jan 2020 12:51:49 +0800
+Subject: [PATCH] LF-789-2 arm64: dts: add overlay support for ls1028a-qds
+
+Now seems only ls1028a-qds using overlay by adding fragment dtbs.
+Add their support in Makefile.
+
+This is one of approach suggested by DT maintainer Rob here:
+https://lore.kernel.org/patchwork/patch/821645/
+
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+Signed-off-by: Jason Liu <jason.hui.liu@nxp.com>
+Reviewed-by: Alex Marginean <alexandru.marginean@nxp.com>
+Tested-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/Makefile | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/Makefile
++++ b/arch/arm64/boot/dts/freescale/Makefile
+@@ -1,4 +1,14 @@
+ # SPDX-License-Identifier: GPL-2.0
++
++# required for overlay support
++DTC_FLAGS_fsl-ls1028a-qds := -@
++DTC_FLAGS_fsl-ls1028a-qds-13bb := -@
++DTC_FLAGS_fsl-ls1028a-qds-65bb := -@
++DTC_FLAGS_fsl-ls1028a-qds-7777 := -@
++DTC_FLAGS_fsl-ls1028a-qds-85bb := -@
++DTC_FLAGS_fsl-ls1028a-qds-899b := -@
++DTC_FLAGS_fsl-ls1028a-qds-9999 := -@
++
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-2g5rdb.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-frdm.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-frwy.dtb
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0116-LF-881-arm64-dts-add-a-dts-file-for-dpdk.patch b/target/linux/layerscape/patches-5.4/302-dts-0116-LF-881-arm64-dts-add-a-dts-file-for-dpdk.patch
new file mode 100644 (file)
index 0000000..311d73b
--- /dev/null
@@ -0,0 +1,119 @@
+From f0f46229b2232595a1afde10f6f17e512c004042 Mon Sep 17 00:00:00 2001
+From: Gagandeep Singh <g.singh@nxp.com>
+Date: Thu, 6 Feb 2020 13:01:10 +0000
+Subject: [PATCH] LF-881: arm64: dts: add a dts file for dpdk
+
+A new device tree file fsl-ls1028a-rdb-dpdk.dts is added
+for user space networking.
+
+Signed-off-by: Gagandeep Singh <g.singh@nxp.com>
+Reviewed-by: Alex Marginean <alexandru.marginean@nxp.com>
+Reviewed-by: Li Yang <leoyang.li@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/Makefile             |  1 +
+ .../boot/dts/freescale/fsl-ls1028a-rdb-dpdk.dts    | 89 ++++++++++++++++++++++
+ 2 files changed, 90 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-dpdk.dts
+
+--- a/arch/arm64/boot/dts/freescale/Makefile
++++ b/arch/arm64/boot/dts/freescale/Makefile
+@@ -23,6 +23,7 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds-899b.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds-9999.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb-dpdk.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds-sdk.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb.dtb
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-dpdk.dts
+@@ -0,0 +1,89 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * NXP LS1028A RDB Board device tree file for DPDK
++ *
++ * Copyright 2018-2020 NXP
++ */
++
++/dts-v1/;
++#include "fsl-ls1028a-rdb.dts"
++
++&enetc_port0 {
++      status = "okay";
++      /delete-property/ phy-handle;
++      /delete-property/ phy-connection-type;
++      /delete-node/ mdio;
++
++      fixed-link {
++              speed = <1000>;
++              full-duplex;
++      };
++};
++
++/delete-node/ &enetc_mdio_pf3;
++
++/* l2switch ports */
++&mscc_felix_ports {
++      port@0 {
++              status = "okay";
++              phy-mode = "qsgmii";
++              /delete-property/ managed;
++              /delete-property/ phy-handle;
++
++              fixed-link {
++                      speed = <1000>;
++                      full-duplex;
++              };
++      };
++
++      port@1 {
++              status = "okay";
++              phy-mode = "qsgmii";
++              /delete-property/ managed;
++              /delete-property/ phy-handle;
++
++              fixed-link {
++                      speed = <1000>;
++                      full-duplex;
++              };
++      };
++
++      port@2 {
++              status = "okay";
++              phy-mode = "qsgmii";
++              /delete-property/ managed;
++              /delete-property/ phy-handle;
++
++              fixed-link {
++                      speed = <1000>;
++                      full-duplex;
++              };
++      };
++
++      port@3 {
++              status = "okay";
++              phy-mode = "qsgmii";
++              /delete-property/ managed;
++              /delete-property/ phy-handle;
++
++              fixed-link {
++                      speed = <1000>;
++                      full-duplex;
++              };
++      };
++
++      port@5 {
++              status = "okay";
++              /delete-property/ managed;
++              /delete-property/ phy-handle;
++
++              fixed-link {
++                      speed = <1000>;
++                      full-duplex;
++              };
++      };
++};
++
++&enetc_port3 {
++      status = "okay";
++};
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0117-arm-dts-ls1021a-Add-LS1021A-IOT-board-support.patch b/target/linux/layerscape/patches-5.4/302-dts-0117-arm-dts-ls1021a-Add-LS1021A-IOT-board-support.patch
new file mode 100644 (file)
index 0000000..9963062
--- /dev/null
@@ -0,0 +1,291 @@
+From 55e00e402d6143aeb153761f8144d9fee5f1f009 Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Fri, 26 Oct 2018 16:00:37 +0800
+Subject: [PATCH] arm: dts: ls1021a: Add LS1021A-IOT board support
+
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ arch/arm/boot/dts/Makefile        |   3 +-
+ arch/arm/boot/dts/ls1021a-iot.dts | 262 ++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 264 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/boot/dts/ls1021a-iot.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -611,7 +611,8 @@ dtb-$(CONFIG_SOC_LS1021A) += \
+       ls1021a-moxa-uc-8410a.dtb \
+       ls1021a-qds.dtb \
+       ls1021a-tsn.dtb \
+-      ls1021a-twr.dtb
++      ls1021a-twr.dtb \
++      ls1021a-iot.dtb
+ dtb-$(CONFIG_SOC_VF610) += \
+       vf500-colibri-eval-v3.dtb \
+       vf610-bk4.dtb \
+--- /dev/null
++++ b/arch/arm/boot/dts/ls1021a-iot.dts
+@@ -0,0 +1,262 @@
++/*
++ * Copyright 2013-2016 Freescale Semiconductor, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++/dts-v1/;
++#include "ls1021a.dtsi"
++
++/ {
++      model = "LS1021A IOT Board";
++
++      sys_mclk: clock-mclk {
++              compatible = "fixed-clock";
++              #clock-cells = <0>;
++              clock-frequency = <24576000>;
++      };
++
++      regulators {
++              compatible = "simple-bus";
++              #address-cells = <1>;
++              #size-cells = <0>;
++
++              reg_3p3v: regulator@0 {
++                      compatible = "regulator-fixed";
++                      reg = <0>;
++                      regulator-name = "3P3V";
++                      regulator-min-microvolt = <3300000>;
++                      regulator-max-microvolt = <3300000>;
++                      regulator-always-on;
++              };
++
++              reg_2p5v: regulator@1 {
++                      compatible = "regulator-fixed";
++                      reg = <1>;
++                      regulator-name = "2P5V";
++                      regulator-min-microvolt = <2500000>;
++                      regulator-max-microvolt = <2500000>;
++                      regulator-always-on;
++              };
++      };
++
++      sound {
++              compatible = "simple-audio-card";
++              simple-audio-card,format = "i2s";
++              simple-audio-card,widgets =
++                      "Microphone", "Microphone Jack",
++                      "Headphone", "Headphone Jack",
++                      "Speaker", "Speaker Ext",
++                      "Line", "Line In Jack";
++              simple-audio-card,routing =
++                      "MIC_IN", "Microphone Jack",
++                      "Microphone Jack", "Mic Bias",
++                      "LINE_IN", "Line In Jack",
++                      "Headphone Jack", "HP_OUT",
++                      "Speaker Ext", "LINE_OUT";
++
++              simple-audio-card,cpu {
++                      sound-dai = <&sai2>;
++                      frame-master;
++                      bitclock-master;
++              };
++
++              simple-audio-card,codec {
++                      sound-dai = <&codec>;
++                      frame-master;
++                      bitclock-master;
++              };
++      };
++
++      firmware {
++              optee {
++                      compatible = "linaro,optee-tz";
++                      method = "smc";
++                      };
++              };
++};
++
++&enet0 {
++      tbi-handle = <&tbi1>;
++      phy-handle = <&phy1>;
++      phy-connection-type = "sgmii";
++      status = "okay";
++};
++
++&enet1 {
++      tbi-handle = <&tbi1>;
++      phy-handle = <&phy3>;
++      phy-connection-type = "sgmii";
++      status = "okay";
++};
++
++&enet2 {
++      fixed-link = <0 1 1000 0 0>;
++      phy-connection-type = "rgmii-id";
++      status = "okay";
++};
++
++&can0{
++      status = "disabled";
++};
++
++&can1{
++      status = "disabled";
++};
++
++&can2{
++      status = "disabled";
++};
++
++&can3{
++      status = "okay";
++};
++
++&esdhc{
++      status = "okay";
++};
++
++&i2c0 {
++      status = "okay";
++
++      max1239@35 {
++              compatible = "maxim,max1239";
++              reg = <0x35>;
++              #io-channel-cells = <1>;
++      };
++
++      codec: sgtl5000@2a {
++               #sound-dai-cells=<0x0>;
++              compatible = "fsl,sgtl5000";
++              reg = <0x2a>;
++              VDDA-supply = <&reg_3p3v>;
++              VDDIO-supply = <&reg_2p5v>;
++              clocks = <&sys_mclk 1>;
++      };
++
++      pca9555: pca9555@23 {
++              compatible = "nxp,pca9555";
++              /*pinctrl-names = "default";*/
++              /*interrupt-parent = <&gpio2>;
++              interrupts = <19 0x2>;*/
++              gpio-controller;
++              #gpio-cells = <2>;
++              interrupt-controller;
++              #interrupt-cells = <2>;
++              reg = <0x23>;
++      };
++
++      ina220@44 {
++              compatible = "ti,ina220";
++              reg = <0x44>;
++              shunt-resistor = <1000>;
++      };
++
++      ina220@45 {
++              compatible = "ti,ina220";
++              reg = <0x45>;
++              shunt-resistor = <1000>;
++      };
++
++      lm75b@48 {
++                compatible = "nxp,lm75a";
++                reg = <0x48>;
++        };
++
++      adt7461a@4c {
++              compatible = "adt7461a";
++              reg = <0x4c>;
++      };
++
++      hdmi: sii9022a@39 {
++              compatible = "fsl,sii902x";
++              reg = <0x39>;
++              interrupts = <GIC_SPI 163 IRQ_TYPE_EDGE_RISING>;
++      };
++};
++
++&i2c1 {
++      status = "disabled";
++};
++
++&ifc {
++      status = "disabled";
++};
++
++&lpuart0 {
++      status = "okay";
++};
++
++&mdio0 {
++      phy0: ethernet-phy@0 {
++              reg = <0x0>;
++      };
++      phy1: ethernet-phy@1 {
++              reg = <0x1>;
++      };
++      phy2: ethernet-phy@2 {
++              reg = <0x2>;
++      };
++      phy3: ethernet-phy@3 {
++              reg = <0x3>;
++      };
++      tbi1: tbi-phy@1f {
++              reg = <0x1f>;
++              device_type = "tbi-phy";
++      };
++};
++
++&qspi {
++      num-cs = <2>;
++      status = "okay";
++
++      qflash0: s25fl128s@0 {
++              compatible = "spansion,s25fl129p1";
++              #address-cells = <1>;
++              #size-cells = <1>;
++              spi-max-frequency = <20000000>;
++              reg = <0>;
++      };
++};
++
++&sai2 {
++      status = "okay";
++};
++
++&uart0 {
++      status = "okay";
++};
++
++&uart1 {
++      status = "okay";
++};
++
++&dcu {
++      display = <&display>;
++      status = "okay";
++
++      display: display@0 {
++              bits-per-pixel = <24>;
++
++              display-timings {
++                      native-mode = <&timing0>;
++
++                      timing0: mode0 {
++                              clock-frequency = <25000000>;
++                              hactive = <640>;
++                              vactive = <480>;
++                              hback-porch = <80>;
++                              hfront-porch = <80>;
++                              vback-porch = <16>;
++                              vfront-porch = <16>;
++                              hsync-len = <12>;
++                              vsync-len = <2>;
++                              hsync-active = <1>;
++                              vsync-active = <1>;
++                      };
++              };
++      };
++};
diff --git a/target/linux/layerscape/patches-5.4/302-dts-0118-add-DTS-for-Traverse-LS1043-Boards.patch b/target/linux/layerscape/patches-5.4/302-dts-0118-add-DTS-for-Traverse-LS1043-Boards.patch
new file mode 100644 (file)
index 0000000..904774d
--- /dev/null
@@ -0,0 +1,96 @@
+From 5b35aae22b4ca2400e49561c9267aa01346f91d4 Mon Sep 17 00:00:00 2001
+From: Mathew McBride <matt@traverse.com.au>
+Date: Tue, 17 Apr 2018 10:01:03 +1000
+Subject: [PATCH] add DTS for Traverse LS1043 Boards
+
+Signed-off-by: Mathew McBride <matt@traverse.com.au>
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ arch/arm64/boot/dts/freescale/Makefile             |  3 +++
+ arch/arm64/boot/dts/freescale/traverse-ls1043s.dts | 29 ++++++++++++++++++++++
+ arch/arm64/boot/dts/freescale/traverse-ls1043v.dts | 29 ++++++++++++++++++++++
+ 3 files changed, 61 insertions(+)
+
+--- a/arch/arm64/boot/dts/freescale/Makefile
++++ b/arch/arm64/boot/dts/freescale/Makefile
+@@ -48,6 +48,9 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-qds.dtb
+ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-rdb.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += traverse-ls1043v.dtb
++dtb-$(CONFIG_ARCH_LAYERSCAPE) += traverse-ls1043s.dtb
++
+ dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk.dtb
+ dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr4-evk.dtb
+ dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb
+--- a/arch/arm64/boot/dts/freescale/traverse-ls1043s.dts
++++ b/arch/arm64/boot/dts/freescale/traverse-ls1043s.dts
+@@ -330,3 +330,32 @@
+ &sata {
+       status = "disabled";
+ };
++
++/* Additions for Layerscape SDK (4.4/4.9) Kernel only
++ * These kernels need additional setup for FMan/QMan DMA shared memory
++ */
++
++#include "qoriq-qman-portals-sdk.dtsi"
++#include "qoriq-bman-portals-sdk.dtsi"
++
++&bman_fbpr {
++      compatible = "fsl,bman-fbpr";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++&qman_fqd {
++      compatible = "fsl,qman-fqd";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++&qman_pfdr {
++      compatible = "fsl,qman-pfdr";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++
++&soc {
++#include "qoriq-dpaa-eth.dtsi"
++#include "qoriq-fman3-0-6oh.dtsi"
++};
++
++&fman0 {
++      compatible = "fsl,fman", "simple-bus";
++};
+--- a/arch/arm64/boot/dts/freescale/traverse-ls1043v.dts
++++ b/arch/arm64/boot/dts/freescale/traverse-ls1043v.dts
+@@ -251,3 +251,32 @@
+ &sata {
+       status = "disabled";
+ };
++
++/* Additions for Layerscape SDK (4.4/4.9) Kernel only
++ * These kernels need additional setup for FMan/QMan DMA shared memory
++ */
++
++#include "qoriq-qman-portals-sdk.dtsi"
++#include "qoriq-bman-portals-sdk.dtsi"
++
++&bman_fbpr {
++      compatible = "fsl,bman-fbpr";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++&qman_fqd {
++      compatible = "fsl,qman-fqd";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++&qman_pfdr {
++      compatible = "fsl,qman-pfdr";
++      alloc-ranges = <0 0 0x10000 0>;
++};
++
++&soc {
++#include "qoriq-dpaa-eth.dtsi"
++#include "qoriq-fman3-0-6oh.dtsi"
++};
++
++&fman0 {
++      compatible = "fsl,fman", "simple-bus";
++};
diff --git a/target/linux/layerscape/patches-5.4/303-core-0001-net-readd-skb_recycle.patch b/target/linux/layerscape/patches-5.4/303-core-0001-net-readd-skb_recycle.patch
new file mode 100644 (file)
index 0000000..cd52f66
--- /dev/null
@@ -0,0 +1,59 @@
+From 446a17652a69f749dd7a50b28e984c4904dc3aaf Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@freescale.com>
+Date: Tue, 5 Jan 2016 12:12:07 +0200
+Subject: [PATCH] net: readd skb_recycle()
+
+Adding back skb_recycle() as it's used by the DPAA Ethernet driver.
+This was removed from the upstream kernel because it was lacking users.
+
+Signed-off-by: Madalin Bucur <madalin.bucur@freescale.com>
+---
+ include/linux/skbuff.h |  1 +
+ net/core/skbuff.c      | 26 ++++++++++++++++++++++++++
+ 2 files changed, 27 insertions(+)
+
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -1025,6 +1025,7 @@ void skb_dump(const char *level, const s
+ void skb_tx_error(struct sk_buff *skb);
+ void consume_skb(struct sk_buff *skb);
+ void __consume_stateless_skb(struct sk_buff *skb);
++void skb_recycle(struct sk_buff *skb);
+ void  __kfree_skb(struct sk_buff *skb);
+ extern struct kmem_cache *skbuff_head_cache;
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -936,6 +936,32 @@ void napi_consume_skb(struct sk_buff *sk
+ }
+ EXPORT_SYMBOL(napi_consume_skb);
++/**
++ *    skb_recycle - clean up an skb for reuse
++ *    @skb: buffer
++ *
++ *    Recycles the skb to be reused as a receive buffer. This
++ *    function does any necessary reference count dropping, and
++ *    cleans up the skbuff as if it just came from __alloc_skb().
++ */
++void skb_recycle(struct sk_buff *skb)
++{
++      struct skb_shared_info *shinfo;
++      u8 head_frag = skb->head_frag;
++
++      skb_release_head_state(skb);
++
++      shinfo = skb_shinfo(skb);
++      memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
++      atomic_set(&shinfo->dataref, 1);
++
++      memset(skb, 0, offsetof(struct sk_buff, tail));
++      skb->data = skb->head + NET_SKB_PAD;
++      skb->head_frag = head_frag;
++      skb_reset_tail_pointer(skb);
++}
++EXPORT_SYMBOL(skb_recycle);
++
+ /* Make sure a field is enclosed inside headers_start/headers_end section */
+ #define CHECK_SKB_FIELD(field) \
+       BUILD_BUG_ON(offsetof(struct sk_buff, field) <          \
diff --git a/target/linux/layerscape/patches-5.4/303-core-0002-drivers-base-add-sysfs-entries-for-suppliers-and-con.patch b/target/linux/layerscape/patches-5.4/303-core-0002-drivers-base-add-sysfs-entries-for-suppliers-and-con.patch
new file mode 100644 (file)
index 0000000..1e45217
--- /dev/null
@@ -0,0 +1,99 @@
+From 4a84eacedc55e78c8f64a5a4f9ade6e285844b85 Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Mon, 25 Jun 2018 13:19:53 +0300
+Subject: [PATCH] drivers/base: add sysfs entries for suppliers and consumers
+
+Instead of scraping dmesg for messages such as 'Linked as a consumer to'
+or 'Dropping the link to' export two new sysfs entries in the device
+folder that list the consumer and supplier devices.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+---
+ Documentation/ABI/testing/sysfs-devices-links | 13 +++++++++
+ drivers/base/core.c                           | 42 +++++++++++++++++++++++++++
+ 2 files changed, 55 insertions(+)
+ create mode 100644 Documentation/ABI/testing/sysfs-devices-links
+
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-devices-links
+@@ -0,0 +1,13 @@
++What:         /sys/devices/.../consumers
++Date:         October 2018
++Contact:      Ioana Ciornei <ioana.ciornei@nxp.com>
++Description:
++              Read-only attribute that lists the current "consumers" of
++              a specific device.
++
++What:         /sys/devices/.../suppliers
++Date:         October 2018
++Contact:      Ioana Ciornei <ioana.ciornei@nxp.com>
++Description:
++              Read-only attribute that lists the current "suppliers" of
++              a specific device.
+--- a/drivers/base/core.c
++++ b/drivers/base/core.c
+@@ -1320,6 +1320,34 @@ static ssize_t online_store(struct devic
+ }
+ static DEVICE_ATTR_RW(online);
++static ssize_t suppliers_show(struct device *dev, struct device_attribute *attr,
++                            char *buf)
++{
++      struct device_link *link;
++      size_t count = 0;
++
++      list_for_each_entry(link, &dev->links.suppliers, c_node)
++              count += scnprintf(buf + count, PAGE_SIZE - count, "%s\n",
++                                 dev_name(link->supplier));
++
++      return count;
++}
++static DEVICE_ATTR_RO(suppliers);
++
++static ssize_t consumers_show(struct device *dev, struct device_attribute *attr,
++                            char *buf)
++{
++      struct device_link *link;
++      size_t count = 0;
++
++      list_for_each_entry(link, &dev->links.consumers, s_node)
++              count += scnprintf(buf + count, PAGE_SIZE - count, "%s\n",
++                                 dev_name(link->consumer));
++
++      return count;
++}
++static DEVICE_ATTR_RO(consumers);
++
+ int device_add_groups(struct device *dev, const struct attribute_group **groups)
+ {
+       return sysfs_create_groups(&dev->kobj, groups);
+@@ -1491,8 +1519,20 @@ static int device_add_attrs(struct devic
+                       goto err_remove_dev_groups;
+       }
++      error = device_create_file(dev, &dev_attr_suppliers);
++      if (error)
++              goto err_remove_online;
++
++      error = device_create_file(dev, &dev_attr_consumers);
++      if (error)
++              goto err_remove_suppliers;
++
+       return 0;
++ err_remove_suppliers:
++      device_remove_file(dev, &dev_attr_suppliers);
++ err_remove_online:
++      device_remove_file(dev, &dev_attr_online);
+  err_remove_dev_groups:
+       device_remove_groups(dev, dev->groups);
+  err_remove_type_groups:
+@@ -1510,6 +1550,8 @@ static void device_remove_attrs(struct d
+       struct class *class = dev->class;
+       const struct device_type *type = dev->type;
++      device_remove_file(dev, &dev_attr_consumers);
++      device_remove_file(dev, &dev_attr_suppliers);
+       device_remove_file(dev, &dev_attr_online);
+       device_remove_groups(dev, dev->groups);
diff --git a/target/linux/layerscape/patches-5.4/303-core-0003-cgroup-let-a-symlink-too-be-created-with-a-cftype-fi.patch b/target/linux/layerscape/patches-5.4/303-core-0003-cgroup-let-a-symlink-too-be-created-with-a-cftype-fi.patch
new file mode 100644 (file)
index 0000000..38f34ed
--- /dev/null
@@ -0,0 +1,112 @@
+From 3b4d888114a5f6c1e848f892a2236db4ccf8345f Mon Sep 17 00:00:00 2001
+From: Angelo Ruocco <angeloruocco90@gmail.com>
+Date: Tue, 21 May 2019 10:01:54 +0200
+Subject: [PATCH] cgroup: let a symlink too be created with a cftype file
+
+This commit enables a cftype to have a symlink (of any name) that
+points to the file associated with the cftype.
+
+Signed-off-by: Angelo Ruocco <angeloruocco90@gmail.com>
+Signed-off-by: Paolo Valente <paolo.valente@linaro.org>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+(cherry picked from commit 54b7b868e826b294687c439b68ec55fe20cafe5b)
+Signed-off-by: Li Yang <leoyang.li@nxp.com>
+---
+ include/linux/cgroup-defs.h |  3 +++
+ kernel/cgroup/cgroup.c      | 33 +++++++++++++++++++++++++++++----
+ 2 files changed, 32 insertions(+), 4 deletions(-)
+
+--- a/include/linux/cgroup-defs.h
++++ b/include/linux/cgroup-defs.h
+@@ -106,6 +106,8 @@ enum {
+       CFTYPE_WORLD_WRITABLE   = (1 << 4),     /* (DON'T USE FOR NEW FILES) S_IWUGO */
+       CFTYPE_DEBUG            = (1 << 5),     /* create when cgroup_debug */
++      CFTYPE_SYMLINKED        = (1 << 6),     /* pointed to by symlink too */
++
+       /* internal flags, do not use outside cgroup core proper */
+       __CFTYPE_ONLY_ON_DFL    = (1 << 16),    /* only on default hierarchy */
+       __CFTYPE_NOT_ON_DFL     = (1 << 17),    /* not on default hierarchy */
+@@ -544,6 +546,7 @@ struct cftype {
+        * end of cftype array.
+        */
+       char name[MAX_CFTYPE_NAME];
++      char link_name[MAX_CFTYPE_NAME];
+       unsigned long private;
+       /*
+--- a/kernel/cgroup/cgroup.c
++++ b/kernel/cgroup/cgroup.c
+@@ -1465,8 +1465,8 @@ struct cgroup *task_cgroup_from_root(str
+ static struct kernfs_syscall_ops cgroup_kf_syscall_ops;
+-static char *cgroup_file_name(struct cgroup *cgrp, const struct cftype *cft,
+-                            char *buf)
++static char *cgroup_fill_name(struct cgroup *cgrp, const struct cftype *cft,
++                            char *buf, bool write_link_name)
+ {
+       struct cgroup_subsys *ss = cft->ss;
+@@ -1476,13 +1476,26 @@ static char *cgroup_file_name(struct cgr
+               snprintf(buf, CGROUP_FILE_NAME_MAX, "%s%s.%s",
+                        dbg, cgroup_on_dfl(cgrp) ? ss->name : ss->legacy_name,
+-                       cft->name);
++                       write_link_name ? cft->link_name : cft->name);
+       } else {
+-              strscpy(buf, cft->name, CGROUP_FILE_NAME_MAX);
++              strscpy(buf, write_link_name ? cft->link_name : cft->name,
++                      CGROUP_FILE_NAME_MAX);
+       }
+       return buf;
+ }
++static char *cgroup_file_name(struct cgroup *cgrp, const struct cftype *cft,
++                            char *buf)
++{
++      return cgroup_fill_name(cgrp, cft, buf, false);
++}
++
++static char *cgroup_link_name(struct cgroup *cgrp, const struct cftype *cft,
++                            char *buf)
++{
++      return cgroup_fill_name(cgrp, cft, buf, true);
++}
++
+ /**
+  * cgroup_file_mode - deduce file mode of a control file
+  * @cft: the control file in question
+@@ -1641,6 +1654,9 @@ static void cgroup_rm_file(struct cgroup
+       }
+       kernfs_remove_by_name(cgrp->kn, cgroup_file_name(cgrp, cft, name));
++      if (cft->flags & CFTYPE_SYMLINKED)
++              kernfs_remove_by_name(cgrp->kn,
++                                    cgroup_link_name(cgrp, cft, name));
+ }
+ /**
+@@ -3871,6 +3887,7 @@ static int cgroup_add_file(struct cgroup
+ {
+       char name[CGROUP_FILE_NAME_MAX];
+       struct kernfs_node *kn;
++      struct kernfs_node *kn_link;
+       struct lock_class_key *key = NULL;
+       int ret;
+@@ -3901,6 +3918,14 @@ static int cgroup_add_file(struct cgroup
+               spin_unlock_irq(&cgroup_file_kn_lock);
+       }
++      if (cft->flags & CFTYPE_SYMLINKED) {
++              kn_link = kernfs_create_link(cgrp->kn,
++                                           cgroup_link_name(cgrp, cft, name),
++                                           kn);
++              if (IS_ERR(kn_link))
++                      return PTR_ERR(kn_link);
++      }
++
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/303-core-0004-cgroup-bfq-revert-bfq.weight-symlink-change.patch b/target/linux/layerscape/patches-5.4/303-core-0004-cgroup-bfq-revert-bfq.weight-symlink-change.patch
new file mode 100644 (file)
index 0000000..e82161a
--- /dev/null
@@ -0,0 +1,114 @@
+From b7f71899fbdba1cac6773a62ed4ea841b7eda6b0 Mon Sep 17 00:00:00 2001
+From: Jens Axboe <axboe@kernel.dk>
+Date: Mon, 10 Jun 2019 03:35:41 -0600
+Subject: [PATCH] cgroup/bfq: revert bfq.weight symlink change
+
+There's some discussion on how to do this the best, and Tejun prefers
+that BFQ just create the file itself instead of having cgroups support
+a symlink feature.
+
+Hence revert commit 54b7b868e826 and 19e9da9e86c4 for 5.2, and this
+can be done properly for 5.3.
+
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+(cherry picked from commit cf8929885de318c0bf73438c9e5dde59d6536f7c)
+Signed-off-by: Li Yang <leoyang.li@nxp.com>
+---
+ include/linux/cgroup-defs.h |  3 ---
+ kernel/cgroup/cgroup.c      | 33 ++++-----------------------------
+ 2 files changed, 4 insertions(+), 32 deletions(-)
+
+--- a/include/linux/cgroup-defs.h
++++ b/include/linux/cgroup-defs.h
+@@ -106,8 +106,6 @@ enum {
+       CFTYPE_WORLD_WRITABLE   = (1 << 4),     /* (DON'T USE FOR NEW FILES) S_IWUGO */
+       CFTYPE_DEBUG            = (1 << 5),     /* create when cgroup_debug */
+-      CFTYPE_SYMLINKED        = (1 << 6),     /* pointed to by symlink too */
+-
+       /* internal flags, do not use outside cgroup core proper */
+       __CFTYPE_ONLY_ON_DFL    = (1 << 16),    /* only on default hierarchy */
+       __CFTYPE_NOT_ON_DFL     = (1 << 17),    /* not on default hierarchy */
+@@ -546,7 +544,6 @@ struct cftype {
+        * end of cftype array.
+        */
+       char name[MAX_CFTYPE_NAME];
+-      char link_name[MAX_CFTYPE_NAME];
+       unsigned long private;
+       /*
+--- a/kernel/cgroup/cgroup.c
++++ b/kernel/cgroup/cgroup.c
+@@ -1465,8 +1465,8 @@ struct cgroup *task_cgroup_from_root(str
+ static struct kernfs_syscall_ops cgroup_kf_syscall_ops;
+-static char *cgroup_fill_name(struct cgroup *cgrp, const struct cftype *cft,
+-                            char *buf, bool write_link_name)
++static char *cgroup_file_name(struct cgroup *cgrp, const struct cftype *cft,
++                            char *buf)
+ {
+       struct cgroup_subsys *ss = cft->ss;
+@@ -1476,26 +1476,13 @@ static char *cgroup_fill_name(struct cgr
+               snprintf(buf, CGROUP_FILE_NAME_MAX, "%s%s.%s",
+                        dbg, cgroup_on_dfl(cgrp) ? ss->name : ss->legacy_name,
+-                       write_link_name ? cft->link_name : cft->name);
++                       cft->name);
+       } else {
+-              strscpy(buf, write_link_name ? cft->link_name : cft->name,
+-                      CGROUP_FILE_NAME_MAX);
++              strscpy(buf, cft->name, CGROUP_FILE_NAME_MAX);
+       }
+       return buf;
+ }
+-static char *cgroup_file_name(struct cgroup *cgrp, const struct cftype *cft,
+-                            char *buf)
+-{
+-      return cgroup_fill_name(cgrp, cft, buf, false);
+-}
+-
+-static char *cgroup_link_name(struct cgroup *cgrp, const struct cftype *cft,
+-                            char *buf)
+-{
+-      return cgroup_fill_name(cgrp, cft, buf, true);
+-}
+-
+ /**
+  * cgroup_file_mode - deduce file mode of a control file
+  * @cft: the control file in question
+@@ -1654,9 +1641,6 @@ static void cgroup_rm_file(struct cgroup
+       }
+       kernfs_remove_by_name(cgrp->kn, cgroup_file_name(cgrp, cft, name));
+-      if (cft->flags & CFTYPE_SYMLINKED)
+-              kernfs_remove_by_name(cgrp->kn,
+-                                    cgroup_link_name(cgrp, cft, name));
+ }
+ /**
+@@ -3887,7 +3871,6 @@ static int cgroup_add_file(struct cgroup
+ {
+       char name[CGROUP_FILE_NAME_MAX];
+       struct kernfs_node *kn;
+-      struct kernfs_node *kn_link;
+       struct lock_class_key *key = NULL;
+       int ret;
+@@ -3918,14 +3901,6 @@ static int cgroup_add_file(struct cgroup
+               spin_unlock_irq(&cgroup_file_kn_lock);
+       }
+-      if (cft->flags & CFTYPE_SYMLINKED) {
+-              kn_link = kernfs_create_link(cgrp->kn,
+-                                           cgroup_link_name(cgrp, cft, name),
+-                                           kn);
+-              if (IS_ERR(kn_link))
+-                      return PTR_ERR(kn_link);
+-      }
+-
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/303-core-0005-nand-raw-workaround-for-EDO-high-speed-mode.patch b/target/linux/layerscape/patches-5.4/303-core-0005-nand-raw-workaround-for-EDO-high-speed-mode.patch
new file mode 100644 (file)
index 0000000..aa4b8d3
--- /dev/null
@@ -0,0 +1,25 @@
+From e2c1ef18cddb426b9eea79599aec892717bead48 Mon Sep 17 00:00:00 2001
+From: Han Xu <han.xu@nxp.com>
+Date: Thu, 15 Aug 2019 21:45:50 -0500
+Subject: [PATCH] nand: raw: workaround for EDO high speed mode
+
+Found issue for EDO high speed mode, set to low speed mode as a
+workaround.
+
+Signed-off-by: Han Xu <han.xu@nxp.com>
+---
+ drivers/mtd/nand/raw/nand_base.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/nand/raw/nand_base.c
++++ b/drivers/mtd/nand/raw/nand_base.c
+@@ -934,7 +934,8 @@ static int nand_init_data_interface(stru
+               modes = GENMASK(chip->onfi_timing_mode_default, 0);
+       }
+-      for (mode = fls(modes) - 1; mode >= 0; mode--) {
++      /* for (mode = fls(modes) - 1; mode >= 0; mode--) { */
++      for (mode = 1; mode >= 0; mode--) {
+               ret = onfi_fill_data_interface(chip, NAND_SDR_IFACE, mode);
+               if (ret)
+                       continue;
diff --git a/target/linux/layerscape/patches-5.4/303-core-0006-mm-Re-export-ioremap_page_range.patch b/target/linux/layerscape/patches-5.4/303-core-0006-mm-Re-export-ioremap_page_range.patch
new file mode 100644 (file)
index 0000000..82e75a4
--- /dev/null
@@ -0,0 +1,21 @@
+From ca952acd72964dca53a9f50cf728dd1d31d48117 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Tue, 7 Feb 2017 17:52:00 +0100
+Subject: [PATCH] mm: Re-export ioremap_page_range
+
+We need this in Jailhouse to map at specific virtual addresses, at
+least for the moment.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit 94bb285491a9a9e15c82c0761505b1073d6b7a47)
+---
+ lib/ioremap.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/lib/ioremap.c
++++ b/lib/ioremap.c
+@@ -231,3 +231,4 @@ int ioremap_page_range(unsigned long add
+       return err;
+ }
++EXPORT_SYMBOL_GPL(ioremap_page_range);
diff --git a/target/linux/layerscape/patches-5.4/303-core-0007-of-of_reserved_mem-Ensure-cma-reserved-region-not-cr.patch b/target/linux/layerscape/patches-5.4/303-core-0007-of-of_reserved_mem-Ensure-cma-reserved-region-not-cr.patch
new file mode 100644 (file)
index 0000000..7c385ea
--- /dev/null
@@ -0,0 +1,85 @@
+From 6973ab95b9e0b0ce7b878c70c301bc5b3d11eca4 Mon Sep 17 00:00:00 2001
+From: Jason Liu <jason.hui.liu@nxp.com>
+Date: Mon, 11 Nov 2019 17:51:13 +0800
+Subject: [PATCH] of: of_reserved_mem: Ensure cma reserved region not cross the
+ low/high memory
+
+Need ensure the cma reserved region not cross the low/high memory boundary
+when using the dynamic allocation methond through device-tree, otherwise,
+kernel will fail to boot up when cma reserved region cross how/high mem.
+
+Signed-off-by: Jason Liu <jason.hui.liu@nxp.com>
+Cc: Laura Abbott <labbott@redhat.com>
+Cc: Frank Rowand <frowand.list@gmail.com>
+Cc: Rob Herring <robh+dt@kernel.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Arulpandiyan Vadivel <arulpandiyan_vadivel@mentor.com>
+---
+ drivers/of/of_reserved_mem.c | 33 ++++++++++++++++++++++++++-------
+ 1 file changed, 26 insertions(+), 7 deletions(-)
+
+--- a/drivers/of/of_reserved_mem.c
++++ b/drivers/of/of_reserved_mem.c
+@@ -26,11 +26,12 @@
+ static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
+ static int reserved_mem_count;
+-static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
+-      phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
+-      phys_addr_t *res_base)
++static int __init early_init_dt_alloc_reserved_memory_arch(unsigned long node,
++      phys_addr_t size, phys_addr_t align, phys_addr_t start,
++      phys_addr_t end, bool nomap, phys_addr_t *res_base)
+ {
+       phys_addr_t base;
++      phys_addr_t highmem_start = __pa(high_memory - 1) + 1;
+       end = !end ? MEMBLOCK_ALLOC_ANYWHERE : end;
+       align = !align ? SMP_CACHE_BYTES : align;
+@@ -38,6 +39,24 @@ static int __init early_init_dt_alloc_re
+       if (!base)
+               return -ENOMEM;
++
++      /*
++       * Sanity check for the cma reserved region:If the reserved region
++       * crosses the low/high memory boundary, try to fix it up and then
++       * fall back to allocate the cma region from the low mememory space.
++       */
++
++      if (IS_ENABLED(CONFIG_CMA)
++          && of_flat_dt_is_compatible(node, "shared-dma-pool")
++          && of_get_flat_dt_prop(node, "reusable", NULL) && !nomap) {
++              if (base < highmem_start && (base + size) > highmem_start) {
++                      base = memblock_find_in_range(start, highmem_start,
++                                                    size, align);
++                      if (!base)
++                              return -ENOMEM;
++              }
++      }
++
+       *res_base = base;
+       if (nomap)
+               return memblock_remove(base, size);
+@@ -131,8 +150,8 @@ static int __init __reserved_mem_alloc_s
+                       end = start + dt_mem_next_cell(dt_root_size_cells,
+                                                      &prop);
+-                      ret = early_init_dt_alloc_reserved_memory_arch(size,
+-                                      align, start, end, nomap, &base);
++                      ret = early_init_dt_alloc_reserved_memory_arch(node,
++                                      size, align, start, end, nomap, &base);
+                       if (ret == 0) {
+                               pr_debug("allocated memory for '%s' node: base %pa, size %ld MiB\n",
+                                       uname, &base,
+@@ -143,8 +162,8 @@ static int __init __reserved_mem_alloc_s
+               }
+       } else {
+-              ret = early_init_dt_alloc_reserved_memory_arch(size, align,
+-                                                      0, 0, nomap, &base);
++              ret = early_init_dt_alloc_reserved_memory_arch(node,
++                                      size, align, 0, 0, nomap, &base);
+               if (ret == 0)
+                       pr_debug("allocated memory for '%s' node: base %pa, size %ld MiB\n",
+                               uname, &base, (unsigned long)size / SZ_1M);
diff --git a/target/linux/layerscape/patches-5.4/303-core-0008-ENGR00279980-ubi-attach-do-not-return-EINVAL-if-the-.patch b/target/linux/layerscape/patches-5.4/303-core-0008-ENGR00279980-ubi-attach-do-not-return-EINVAL-if-the-.patch
new file mode 100644 (file)
index 0000000..c67cdb0
--- /dev/null
@@ -0,0 +1,46 @@
+From 17e6b7bb84649ffcbec11b3e3e933294d8856462 Mon Sep 17 00:00:00 2001
+From: Huang Shijie <b32955@freescale.com>
+Date: Wed, 18 Sep 2013 10:17:39 +0800
+Subject: [PATCH] ENGR00279980 ubi: attach: do not return -EINVAL if the
+ mtd->numeraseregions is 1
+
+If the master mtd does not have any slave mtd partitions,
+and its numeraseregions is one(only has one erease block), and
+we attach the master mtd with : ubiattach -m 0 -d 0
+
+We will meet the error:
+-------------------------------------------------------
+root@freescale ~$ ubiattach /dev/ubi_ctrl -m 0 -d 0
+UBI: attaching mtd0 to ubi0
+UBI error: io_init: multiple regions, not implemented
+ubiattach: error!: cannot attach mtd0
+           error 22 (Invalid argument)
+-------------------------------------------------------
+
+In fact, if there is only one "erase block", we should not
+prevent the attach.
+
+This patch fixes it.
+
+Signed-off-by: Huang Shijie <b32955@freescale.com>
+(cherry picked from commit 361cdc47fc4c4db31c5485560cdabd94f409bd81)
+(cherry picked from commit ebee7d74914fad3cf7223af84496811c9d2488a1)
+
+Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
+
+Signed-off-by: Han Xu <han.xu@nxp.com>
+---
+ drivers/mtd/ubi/build.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/mtd/ubi/build.c
++++ b/drivers/mtd/ubi/build.c
+@@ -576,7 +576,7 @@ static int io_init(struct ubi_device *ub
+       dbg_gen("sizeof(struct ubi_ainf_peb) %zu", sizeof(struct ubi_ainf_peb));
+       dbg_gen("sizeof(struct ubi_wl_entry) %zu", sizeof(struct ubi_wl_entry));
+-      if (ubi->mtd->numeraseregions != 0) {
++      if (ubi->mtd->numeraseregions > 1) {
+               /*
+                * Some flashes have several erase regions. Different regions
+                * may have different eraseblock size and other
diff --git a/target/linux/layerscape/patches-5.4/303-core-0009-arm64-move-elfcorehdr-reservation-early-for-crash-du.patch b/target/linux/layerscape/patches-5.4/303-core-0009-arm64-move-elfcorehdr-reservation-early-for-crash-du.patch
new file mode 100644 (file)
index 0000000..c6c9801
--- /dev/null
@@ -0,0 +1,34 @@
+From 67349176ca23f7525dee79665a880cde5aeeaf26 Mon Sep 17 00:00:00 2001
+From: Nikhil Gupta <nikhil.gupta@nxp.com>
+Date: Mon, 30 Dec 2019 15:11:23 +0530
+Subject: [PATCH] arm64:move elfcorehdr reservation early for crash dump kernel
+
+on some SOCs, elfcorehdr address may overlap with the address of reserved
+memory allocated using early_init_fdt_scan_reserved_mem
+
+Signed-off-by: Nikhil Gupta <nikhil.gupta@nxp.com>
+Signed-off-by: Poonam Aggrwal <poonam.aggrwal@nxp.com>
+---
+ arch/arm64/mm/init.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/mm/init.c
++++ b/arch/arm64/mm/init.c
+@@ -416,6 +416,8 @@ void __init arm64_memblock_init(void)
+               initrd_end = initrd_start + phys_initrd_size;
+       }
++      reserve_elfcorehdr();
++
+       early_init_fdt_scan_reserved_mem();
+       /* 4GB maximum for 32-bit only capable devices */
+@@ -426,8 +428,6 @@ void __init arm64_memblock_init(void)
+       reserve_crashkernel();
+-      reserve_elfcorehdr();
+-
+       high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
+       dma_contiguous_reserve(arm64_dma_phys_limit);
diff --git a/target/linux/layerscape/patches-5.4/303-core-0010-scripts-Makefile-Enable-creation-of-_symbols_-DT-nod.patch b/target/linux/layerscape/patches-5.4/303-core-0010-scripts-Makefile-Enable-creation-of-_symbols_-DT-nod.patch
new file mode 100644 (file)
index 0000000..801bde1
--- /dev/null
@@ -0,0 +1,28 @@
+From 71650b18b78f52e96512a7695a0d39762c1ee408 Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Mon, 6 Jan 2020 16:35:08 +0200
+Subject: [PATCH] scripts: Makefile: Enable creation of _symbols_ DT node for
+ overlays
+
+DT compiler supports -@ flag which indicates that _symbols_ node should be
+automatically created during compilation.  This node is required for
+using DT overlays.  The generated DTB is backward compatible, the _symbols_
+node can be safely ignored if overlays are not used.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ scripts/Makefile.lib | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/scripts/Makefile.lib
++++ b/scripts/Makefile.lib
+@@ -255,6 +255,9 @@ endif
+ DTC_FLAGS += $(DTC_FLAGS_$(basetarget))
++# Enable creation of _symbols_ node for DT overlays
++DTC_FLAGS += -@
++
+ # Generate an assembly file to wrap the output of the device tree compiler
+ quiet_cmd_dt_S_dtb= DTB     $@
+ cmd_dt_S_dtb=                                         \
diff --git a/target/linux/layerscape/patches-5.4/303-core-0011-LF-419-arm64-crash_core-Export-TCR_EL1.T1SZ-in-vmcor.patch b/target/linux/layerscape/patches-5.4/303-core-0011-LF-419-arm64-crash_core-Export-TCR_EL1.T1SZ-in-vmcor.patch
new file mode 100644 (file)
index 0000000..7bd8df6
--- /dev/null
@@ -0,0 +1,97 @@
+From 2e4c0c429526d88b96319d7bb08c51bfa70f6e27 Mon Sep 17 00:00:00 2001
+From: Bhupesh Sharma <bhsharma@redhat.com>
+Date: Fri, 29 Nov 2019 01:55:13 +0530
+Subject: [PATCH] LF-419 arm64/crash_core: Export TCR_EL1.T1SZ in vmcoreinfo
+
+vabits_actual variable on arm64 indicates the actual VA space size,
+and allows a single binary to support both 48-bit and 52-bit VA
+spaces.
+
+If the ARMv8.2-LVA optional feature is present, and we are running
+with a 64KB page size; then it is possible to use 52-bits of address
+space for both userspace and kernel addresses. However, any kernel
+binary that supports 52-bit must also be able to fall back to 48-bit
+at early boot time if the hardware feature is not present.
+
+Since TCR_EL1.T1SZ indicates the size offset of the memory region
+addressed by TTBR1_EL1 (and hence can be used for determining the
+vabits_actual value) it makes more sense to export the same in
+vmcoreinfo rather than vabits_actual variable, as the name of the
+variable can change in future kernel versions, but the architectural
+constructs like TCR_EL1.T1SZ can be used better to indicate intended
+specific fields to user-space.
+
+User-space utilities like makedumpfile and crash-utility, need to
+read/write this value from/to vmcoreinfo for determining if a virtual
+address lies in the linear map range.
+
+The user-space computation for determining whether an address lies in
+the linear map range is the same as we have in kernel-space:
+
+  #define __is_lm_address(addr)        (!(((u64)addr) & BIT(vabits_actual - 1)))
+
+I have sent out user-space patches for makedumpfile and crash-utility
+to add features for obtaining vabits_actual value from TCR_EL1.T1SZ (see
+[0] and [1]).
+
+Akashi reported that he was able to use this patchset and the user-space
+changes to get user-space working fine with the 52-bit kernel VA
+changes (see [2]).
+
+[0]. http://lists.infradead.org/pipermail/kexec/2019-November/023966.html
+[1]. http://lists.infradead.org/pipermail/kexec/2019-November/024006.html
+[2]. http://lists.infradead.org/pipermail/kexec/2019-November/023992.html
+
+Cc: James Morse <james.morse@arm.com>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Will Deacon <will@kernel.org>
+Cc: Steve Capper <steve.capper@arm.com>
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Cc: Dave Anderson <anderson@redhat.com>
+Cc: Kazuhito Hagio <k-hagio@ab.jp.nec.com>
+Cc: linux-arm-kernel@lists.infradead.org
+Cc: linux-kernel@vger.kernel.org
+Cc: kexec@lists.infradead.org
+Signed-off-by: Bhupesh Sharma <bhsharma@redhat.com>
+Tested-by: Poonam Aggrwal <poonam.aggrwal@nxp.com>
+Acked-by: Li Yang <leoyang.li@nxp.com>
+---
+ arch/arm64/include/asm/pgtable-hwdef.h | 1 +
+ arch/arm64/kernel/crash_core.c         | 9 +++++++++
+ 2 files changed, 10 insertions(+)
+
+--- a/arch/arm64/include/asm/pgtable-hwdef.h
++++ b/arch/arm64/include/asm/pgtable-hwdef.h
+@@ -215,6 +215,7 @@
+ #define TCR_TxSZ(x)           (TCR_T0SZ(x) | TCR_T1SZ(x))
+ #define TCR_TxSZ_WIDTH                6
+ #define TCR_T0SZ_MASK         (((UL(1) << TCR_TxSZ_WIDTH) - 1) << TCR_T0SZ_OFFSET)
++#define TCR_T1SZ_MASK         (((UL(1) << TCR_TxSZ_WIDTH) - 1) << TCR_T1SZ_OFFSET)
+ #define TCR_EPD0_SHIFT                7
+ #define TCR_EPD0_MASK         (UL(1) << TCR_EPD0_SHIFT)
+--- a/arch/arm64/kernel/crash_core.c
++++ b/arch/arm64/kernel/crash_core.c
+@@ -7,6 +7,13 @@
+ #include <linux/crash_core.h>
+ #include <asm/memory.h>
++static inline u64 get_tcr_el1_t1sz(void);
++
++static inline u64 get_tcr_el1_t1sz(void)
++{
++      return (read_sysreg(tcr_el1) & TCR_T1SZ_MASK) >> TCR_T1SZ_OFFSET;
++}
++
+ void arch_crash_save_vmcoreinfo(void)
+ {
+       VMCOREINFO_NUMBER(VA_BITS);
+@@ -15,5 +22,7 @@ void arch_crash_save_vmcoreinfo(void)
+                                               kimage_voffset);
+       vmcoreinfo_append_str("NUMBER(PHYS_OFFSET)=0x%llx\n",
+                                               PHYS_OFFSET);
++      vmcoreinfo_append_str("NUMBER(tcr_el1_t1sz)=0x%llx\n",
++                                              get_tcr_el1_t1sz());
+       vmcoreinfo_append_str("KERNELOFFSET=%lx\n", kaslr_offset());
+ }
diff --git a/target/linux/layerscape/patches-5.4/303-core-0012-LF-789-1-Revert-scripts-Makefile-Enable-creation-of-.patch b/target/linux/layerscape/patches-5.4/303-core-0012-LF-789-1-Revert-scripts-Makefile-Enable-creation-of-.patch
new file mode 100644 (file)
index 0000000..744930c
--- /dev/null
@@ -0,0 +1,58 @@
+From b13487a97b51a619b4e681a6091a1da9d6733058 Mon Sep 17 00:00:00 2001
+From: Jason Liu <jason.hui.liu@nxp.com>
+Date: Fri, 10 Jan 2020 11:38:05 +0800
+Subject: [PATCH] LF-789-1 Revert "scripts: Makefile: Enable creation of
+ _symbols_ DT node for overlays"
+
+This reverts commit 432071b7a106060fa4e451e10249cef021af0b7c.
+
+commit: 432071b7a106 scripts: Makefile: Enable creation of _symbols_ DT node for overlays
+changes the common Makefile and force creation of __symbols__ node on all platforms.
+
+This is not good and not acceptible under some cases due to this change will increase
+the final DTB size a lot and bring big impact for others who does not need creation
+of _symbols_ DT node for overlays.For example, on i.MX OP-TEE, the maxsize of DT is 1MB,
+this patch will break some of the i.MX6/i.MX7 boards to boot with OP-TEE enabled.
+
+BTW, community has the similar patch but rejected. The following post discuss about this:
+https://lore.kernel.org/patchwork/patch/821645/
+
+For specifc plaform/board which need the creation of _symbols_ DT node for overlays, user can
+define DTC_FLAGS_target either trough dtc build command line(#1) or with board specific Makefile(#2)
+
+For example:#1
+
+make DTC_FLAGS_fsl-ls1028a-qds=-@ freescale/fsl-ls1028a-qds.dtb
+
+For example:#2
+
+In arch/arm64/boot/dts/freescale/Makefile,
+
+ @@ -1,4 +1,7 @@
+  # SPDX-License-Identifier: GPL-2.0
+ +# required for overlay support
+ +#DTC_FLAGS_fsl-ls1028a-qds := -@
+ +
+
+Signed-off-by: Jason Liu <jason.hui.liu@nxp.com>
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+Reviewed-by: Alex Marginean <alexandru.marginean@nxp.com>
+Tested-by: Alex Marginean <alexandru.marginean@nxp.com>
+[fix commit message]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ scripts/Makefile.lib | 3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/scripts/Makefile.lib
++++ b/scripts/Makefile.lib
+@@ -255,9 +255,6 @@ endif
+ DTC_FLAGS += $(DTC_FLAGS_$(basetarget))
+-# Enable creation of _symbols_ node for DT overlays
+-DTC_FLAGS += -@
+-
+ # Generate an assembly file to wrap the output of the device tree compiler
+ quiet_cmd_dt_S_dtb= DTB     $@
+ cmd_dt_S_dtb=                                         \
diff --git a/target/linux/layerscape/patches-5.4/701-net-0001-soc-fsl-qman-fixup-liodns-only-on-ppc-targets.patch b/target/linux/layerscape/patches-5.4/701-net-0001-soc-fsl-qman-fixup-liodns-only-on-ppc-targets.patch
new file mode 100644 (file)
index 0000000..0ac4bee
--- /dev/null
@@ -0,0 +1,32 @@
+From cc0d30fc5931e76e83f5cd1f5c91a9b97abf39b9 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 6 Feb 2018 15:55:56 +0200
+Subject: [PATCH] soc/fsl/qman: fixup liodns only on ppc targets
+
+ARM SoCs use SMMU so the liodn fixup done in the qman driver is no
+longer making sense and it also breaks the ICID settings inherited
+from u-boot. Do the fixups only for PPC targets.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ drivers/soc/fsl/qbman/qman_ccsr.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/soc/fsl/qbman/qman_ccsr.c
++++ b/drivers/soc/fsl/qbman/qman_ccsr.c
+@@ -642,6 +642,7 @@ static int qman_init_ccsr(struct device
+ #define LIO_CFG_LIODN_MASK 0x0fff0000
+ void __qman_liodn_fixup(u16 channel)
+ {
++#ifdef CONFIG_PPC
+       static int done;
+       static u32 liodn_offset;
+       u32 before, after;
+@@ -661,6 +662,7 @@ void __qman_liodn_fixup(u16 channel)
+               qm_ccsr_out(REG_REV3_QCSP_LIO_CFG(idx), after);
+       else
+               qm_ccsr_out(REG_QCSP_LIO_CFG(idx), after);
++#endif
+ }
+ #define IO_CFG_SDEST_MASK 0x00ff0000
diff --git a/target/linux/layerscape/patches-5.4/701-net-0002-soc-fsl-bman-map-FBPR-area-in-the-iommu.patch b/target/linux/layerscape/patches-5.4/701-net-0002-soc-fsl-bman-map-FBPR-area-in-the-iommu.patch
new file mode 100644 (file)
index 0000000..afafe92
--- /dev/null
@@ -0,0 +1,47 @@
+From 55705ace9136e1c24d92d7ab23e513439eb766e7 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 3 Apr 2018 17:55:00 +0300
+Subject: [PATCH] soc/fsl/bman: map FBPR area in the iommu
+
+Add a one-to-one iommu mapping for bman private data memory (FBPR).
+This is required for BMAN to work without faults behind an iommu.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ drivers/soc/fsl/qbman/bman_ccsr.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/drivers/soc/fsl/qbman/bman_ccsr.c
++++ b/drivers/soc/fsl/qbman/bman_ccsr.c
+@@ -29,6 +29,7 @@
+  */
+ #include "bman_priv.h"
++#include <linux/iommu.h>
+ u16 bman_ip_rev;
+ EXPORT_SYMBOL(bman_ip_rev);
+@@ -210,6 +211,7 @@ static int fsl_bman_probe(struct platfor
+       int ret, err_irq;
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
++      struct iommu_domain *domain;
+       struct resource *res;
+       u16 id, bm_pool_cnt;
+       u8 major, minor;
+@@ -257,6 +259,15 @@ static int fsl_bman_probe(struct platfor
+       dev_dbg(dev, "Allocated FBPR 0x%llx 0x%zx\n", fbpr_a, fbpr_sz);
++      /* Create an 1-to-1 iommu mapping for FBPR area */
++      domain = iommu_get_domain_for_dev(dev);
++      if (domain) {
++              ret = iommu_map(domain, fbpr_a, fbpr_a, fbpr_sz,
++                              IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
++              if (ret)
++                      dev_warn(dev, "failed to iommu_map() %d\n", ret);
++      }
++
+       bm_set_memory(fbpr_a, fbpr_sz);
+       err_irq = platform_get_irq(pdev, 0);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0003-soc-fsl-qman-map-FQD-and-PFDR-areas-in-the-iommu.patch b/target/linux/layerscape/patches-5.4/701-net-0003-soc-fsl-qman-map-FQD-and-PFDR-areas-in-the-iommu.patch
new file mode 100644 (file)
index 0000000..03b8c22
--- /dev/null
@@ -0,0 +1,52 @@
+From 02638b2627104cd02aff7484bb250d029e05dc5f Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 3 Apr 2018 18:08:48 +0300
+Subject: [PATCH] soc/fsl/qman: map FQD and PFDR areas in the iommu
+
+Add a one-to-one iommu mapping for qman private data memory areas
+(FQD and PFDR). This is required for QMAN to work without faults
+behind an iommu.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ drivers/soc/fsl/qbman/qman_ccsr.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+--- a/drivers/soc/fsl/qbman/qman_ccsr.c
++++ b/drivers/soc/fsl/qbman/qman_ccsr.c
+@@ -29,6 +29,7 @@
+  */
+ #include "qman_priv.h"
++#include <linux/iommu.h>
+ u16 qman_ip_rev;
+ EXPORT_SYMBOL(qman_ip_rev);
+@@ -755,6 +756,7 @@ static int fsl_qman_probe(struct platfor
+ {
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
++      struct iommu_domain *domain;
+       struct resource *res;
+       int ret, err_irq;
+       u16 id;
+@@ -834,6 +836,19 @@ static int fsl_qman_probe(struct platfor
+       }
+       dev_dbg(dev, "Allocated PFDR 0x%llx 0x%zx\n", pfdr_a, pfdr_sz);
++      /* Create an 1-to-1 iommu mapping for fqd and pfdr areas */
++      domain = iommu_get_domain_for_dev(dev);
++      if (domain) {
++              ret = iommu_map(domain, fqd_a, fqd_a, fqd_sz,
++                              IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
++              if (ret)
++                      dev_warn(dev, "iommu_map(fqd) failed %d\n", ret);
++              ret = iommu_map(domain, pfdr_a, pfdr_a, pfdr_sz,
++                              IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
++              if (ret)
++                      dev_warn(dev, "iommu_map(pfdr) failed %d\n", ret);
++      }
++
+       ret = qman_init_ccsr(dev);
+       if (ret) {
+               dev_err(dev, "CCSR setup failed\n");
diff --git a/target/linux/layerscape/patches-5.4/701-net-0004-soc-fsl-qman-portal-map-CENA-area-in-the-iommu.patch b/target/linux/layerscape/patches-5.4/701-net-0004-soc-fsl-qman-portal-map-CENA-area-in-the-iommu.patch
new file mode 100644 (file)
index 0000000..b299642
--- /dev/null
@@ -0,0 +1,54 @@
+From 488b62aa444440690708e5ea823bb0d54c296c4f Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 3 Apr 2018 18:18:30 +0300
+Subject: [PATCH] soc/fsl/qman-portal: map CENA area in the iommu
+
+Add a one-to-one iommu mapping for qman portal CENA register area.
+This is required for QMAN stashing to work without faults behind
+an iommu.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ drivers/soc/fsl/qbman/qman_portal.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/drivers/soc/fsl/qbman/qman_portal.c
++++ b/drivers/soc/fsl/qbman/qman_portal.c
+@@ -29,6 +29,7 @@
+  */
+ #include "qman_priv.h"
++#include <linux/iommu.h>
+ struct qman_portal *qman_dma_portal;
+ EXPORT_SYMBOL(qman_dma_portal);
+@@ -231,6 +232,7 @@ static int qman_portal_probe(struct plat
+ {
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
++      struct iommu_domain *domain;
+       struct qm_portal_config *pcfg;
+       struct resource *addr_phys[2];
+       int irq, cpu, err, i;
+@@ -294,6 +296,21 @@ static int qman_portal_probe(struct plat
+               goto err_ioremap2;
+       }
++      /* Create an 1-to-1 iommu mapping for cena portal area */
++      domain = iommu_get_domain_for_dev(dev);
++      if (domain) {
++              /*
++               * Note: not mapping this as cacheable triggers the infamous
++               * QMan CIDE error.
++               */
++              err = iommu_map(domain,
++                              addr_phys[0]->start, addr_phys[0]->start,
++                              resource_size(addr_phys[0]),
++                              IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
++              if (err)
++                      dev_warn(dev, "failed to iommu_map() %d\n", err);
++      }
++
+       pcfg->pools = qm_get_pools_sdqcr();
+       spin_lock(&qman_lock);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0005-soc-fsl-qbman_portals-add-APIs-to-retrieve-the-probi.patch b/target/linux/layerscape/patches-5.4/701-net-0005-soc-fsl-qbman_portals-add-APIs-to-retrieve-the-probi.patch
new file mode 100644 (file)
index 0000000..a137e55
--- /dev/null
@@ -0,0 +1,71 @@
+From d43acc10c25f01a461a1cb1c1fd0cc72cd29dd42 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Thu, 2 Aug 2018 16:14:12 +0300
+Subject: [PATCH] soc/fsl/qbman_portals: add APIs to retrieve the probing
+ status
+
+Add a couple of new APIs to check the probing status of the required
+cpu bound qman and bman portals:
+ 'int bman_portals_probed()' and 'int qman_portals_probed()'.
+They return the following values.
+ *  1 if qman/bman portals were all probed correctly
+ *  0 if qman/bman portals were not yet probed
+ * -1 if probing of qman/bman portals failed
+Portals are considered successful probed if no error occurred during
+the probing of any of the portals and if enough portals were probed
+to have one available for each cpu.
+The error handling paths were slightly rearranged in order to fit this
+new functionality without being too intrusive.
+Drivers that use qman/bman portal driver services are required to use
+these APIs before calling any functions exported by these drivers or
+otherwise they will crash the kernel.
+First user will be the dpaa1 ethernet driver, coming in a subsequent
+patch.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ drivers/soc/fsl/qbman/bman_portal.c | 3 +++
+ drivers/soc/fsl/qbman/qman_portal.c | 3 +++
+ include/soc/fsl/qman.h              | 9 +++++++++
+ 3 files changed, 15 insertions(+)
+
+--- a/drivers/soc/fsl/qbman/bman_portal.c
++++ b/drivers/soc/fsl/qbman/bman_portal.c
+@@ -164,6 +164,9 @@ static int bman_portal_probe(struct plat
+       }
+       cpumask_set_cpu(cpu, &portal_cpus);
++      if (!__bman_portals_probed &&
++          cpumask_weight(&portal_cpus) == num_online_cpus())
++              __bman_portals_probed = 1;
+       spin_unlock(&bman_lock);
+       pcfg->cpu = cpu;
+--- a/drivers/soc/fsl/qbman/qman_portal.c
++++ b/drivers/soc/fsl/qbman/qman_portal.c
+@@ -323,6 +323,9 @@ static int qman_portal_probe(struct plat
+       }
+       cpumask_set_cpu(cpu, &portal_cpus);
++      if (!__qman_portals_probed &&
++          cpumask_weight(&portal_cpus) == num_online_cpus())
++              __qman_portals_probed = 1;
+       spin_unlock(&qman_lock);
+       pcfg->cpu = cpu;
+--- a/include/soc/fsl/qman.h
++++ b/include/soc/fsl/qman.h
+@@ -1235,4 +1235,13 @@ void qman_portal_get_iperiod(struct qman
+  */
+ int qman_portal_set_iperiod(struct qman_portal *portal, u32 iperiod);
++/**
++ * qman_portals_probed - Check if all cpu bound qman portals are probed
++ *
++ * Returns 1 if all the required cpu bound qman portals successfully probed,
++ * -1 if probe errors appeared or 0 if the qman portals did not yet finished
++ * probing.
++ */
++int qman_portals_probed(void);
++
+ #endif        /* __FSL_QMAN_H */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0006-soc-fsl-bqman-page-align-iommu-mapping-sizes.patch b/target/linux/layerscape/patches-5.4/701-net-0006-soc-fsl-bqman-page-align-iommu-mapping-sizes.patch
new file mode 100644 (file)
index 0000000..8e10ef1
--- /dev/null
@@ -0,0 +1,58 @@
+From 218274ea02e908846fabb5b9a2ab7409da06a85f Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Thu, 22 Nov 2018 12:32:13 +0200
+Subject: [PATCH] soc/fsl/bqman: page align iommu mapping sizes
+
+Prior to calling iommu_map()/iommu_unmap() page align the size or
+failures such as below could happen:
+
+iommu: unaligned: iova 0x... pa 0x... size 0x4000 min_pagesz 0x10000
+qman_portal 500000000.qman-portal: failed to iommu_map() -22
+
+Seen when booted a kernel compiled with 64K page size support.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ drivers/soc/fsl/qbman/bman_ccsr.c   | 2 +-
+ drivers/soc/fsl/qbman/qman_ccsr.c   | 4 ++--
+ drivers/soc/fsl/qbman/qman_portal.c | 2 +-
+ 3 files changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/soc/fsl/qbman/bman_ccsr.c
++++ b/drivers/soc/fsl/qbman/bman_ccsr.c
+@@ -262,7 +262,7 @@ static int fsl_bman_probe(struct platfor
+       /* Create an 1-to-1 iommu mapping for FBPR area */
+       domain = iommu_get_domain_for_dev(dev);
+       if (domain) {
+-              ret = iommu_map(domain, fbpr_a, fbpr_a, fbpr_sz,
++              ret = iommu_map(domain, fbpr_a, fbpr_a, PAGE_ALIGN(fbpr_sz),
+                               IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
+               if (ret)
+                       dev_warn(dev, "failed to iommu_map() %d\n", ret);
+--- a/drivers/soc/fsl/qbman/qman_ccsr.c
++++ b/drivers/soc/fsl/qbman/qman_ccsr.c
+@@ -839,11 +839,11 @@ static int fsl_qman_probe(struct platfor
+       /* Create an 1-to-1 iommu mapping for fqd and pfdr areas */
+       domain = iommu_get_domain_for_dev(dev);
+       if (domain) {
+-              ret = iommu_map(domain, fqd_a, fqd_a, fqd_sz,
++              ret = iommu_map(domain, fqd_a, fqd_a, PAGE_ALIGN(fqd_sz),
+                               IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
+               if (ret)
+                       dev_warn(dev, "iommu_map(fqd) failed %d\n", ret);
+-              ret = iommu_map(domain, pfdr_a, pfdr_a, pfdr_sz,
++              ret = iommu_map(domain, pfdr_a, pfdr_a, PAGE_ALIGN(pfdr_sz),
+                               IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
+               if (ret)
+                       dev_warn(dev, "iommu_map(pfdr) failed %d\n", ret);
+--- a/drivers/soc/fsl/qbman/qman_portal.c
++++ b/drivers/soc/fsl/qbman/qman_portal.c
+@@ -305,7 +305,7 @@ static int qman_portal_probe(struct plat
+                */
+               err = iommu_map(domain,
+                               addr_phys[0]->start, addr_phys[0]->start,
+-                              resource_size(addr_phys[0]),
++                              PAGE_ALIGN(resource_size(addr_phys[0])),
+                               IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
+               if (err)
+                       dev_warn(dev, "failed to iommu_map() %d\n", err);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0007-fsl_qbman-SDK-DPAA-1.x-QBMan-drivers.patch b/target/linux/layerscape/patches-5.4/701-net-0007-fsl_qbman-SDK-DPAA-1.x-QBMan-drivers.patch
new file mode 100644 (file)
index 0000000..b9e7667
--- /dev/null
@@ -0,0 +1,24880 @@
+From 772438d01bf57bc8939f53c3101a323fc774428f Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Wed, 10 May 2017 16:30:12 +0300
+Subject: [PATCH] fsl_qbman: SDK DPAA 1.x QBMan drivers
+
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/staging/fsl_qbman/Kconfig               |  228 +
+ drivers/staging/fsl_qbman/Makefile              |   28 +
+ drivers/staging/fsl_qbman/bman_config.c         |  720 +++
+ drivers/staging/fsl_qbman/bman_debugfs.c        |  119 +
+ drivers/staging/fsl_qbman/bman_driver.c         |  559 +++
+ drivers/staging/fsl_qbman/bman_high.c           | 1145 +++++
+ drivers/staging/fsl_qbman/bman_low.h            |  565 +++
+ drivers/staging/fsl_qbman/bman_private.h        |  166 +
+ drivers/staging/fsl_qbman/bman_test.c           |   56 +
+ drivers/staging/fsl_qbman/bman_test.h           |   44 +
+ drivers/staging/fsl_qbman/bman_test_high.c      |  183 +
+ drivers/staging/fsl_qbman/bman_test_thresh.c    |  196 +
+ drivers/staging/fsl_qbman/dpa_alloc.c           |  706 +++
+ drivers/staging/fsl_qbman/dpa_sys.h             |  259 ++
+ drivers/staging/fsl_qbman/dpa_sys_arm.h         |   95 +
+ drivers/staging/fsl_qbman/dpa_sys_arm64.h       |  102 +
+ drivers/staging/fsl_qbman/dpa_sys_ppc32.h       |   70 +
+ drivers/staging/fsl_qbman/dpa_sys_ppc64.h       |   79 +
+ drivers/staging/fsl_qbman/fsl_usdpaa.c          | 1984 ++++++++
+ drivers/staging/fsl_qbman/fsl_usdpaa_irq.c      |  289 ++
+ drivers/staging/fsl_qbman/qbman_driver.c        |   88 +
+ drivers/staging/fsl_qbman/qman_config.c         | 1224 +++++
+ drivers/staging/fsl_qbman/qman_debugfs.c        | 1594 +++++++
+ drivers/staging/fsl_qbman/qman_driver.c         |  961 ++++
+ drivers/staging/fsl_qbman/qman_high.c           | 5669 +++++++++++++++++++++++
+ drivers/staging/fsl_qbman/qman_low.h            | 1427 ++++++
+ drivers/staging/fsl_qbman/qman_private.h        |  398 ++
+ drivers/staging/fsl_qbman/qman_test.c           |   57 +
+ drivers/staging/fsl_qbman/qman_test.h           |   45 +
+ drivers/staging/fsl_qbman/qman_test_high.c      |  216 +
+ drivers/staging/fsl_qbman/qman_test_hotpotato.c |  502 ++
+ drivers/staging/fsl_qbman/qman_utility.c        |  129 +
+ include/linux/fsl_bman.h                        |  532 +++
+ include/linux/fsl_qman.h                        | 3888 ++++++++++++++++
+ include/linux/fsl_usdpaa.h                      |  372 ++
+ 35 files changed, 24695 insertions(+)
+ create mode 100644 drivers/staging/fsl_qbman/Kconfig
+ create mode 100644 drivers/staging/fsl_qbman/Makefile
+ create mode 100644 drivers/staging/fsl_qbman/bman_config.c
+ create mode 100644 drivers/staging/fsl_qbman/bman_debugfs.c
+ create mode 100644 drivers/staging/fsl_qbman/bman_driver.c
+ create mode 100644 drivers/staging/fsl_qbman/bman_high.c
+ create mode 100644 drivers/staging/fsl_qbman/bman_low.h
+ create mode 100644 drivers/staging/fsl_qbman/bman_private.h
+ create mode 100644 drivers/staging/fsl_qbman/bman_test.c
+ create mode 100644 drivers/staging/fsl_qbman/bman_test.h
+ create mode 100644 drivers/staging/fsl_qbman/bman_test_high.c
+ create mode 100644 drivers/staging/fsl_qbman/bman_test_thresh.c
+ create mode 100644 drivers/staging/fsl_qbman/dpa_alloc.c
+ create mode 100644 drivers/staging/fsl_qbman/dpa_sys.h
+ create mode 100644 drivers/staging/fsl_qbman/dpa_sys_arm.h
+ create mode 100644 drivers/staging/fsl_qbman/dpa_sys_arm64.h
+ create mode 100644 drivers/staging/fsl_qbman/dpa_sys_ppc32.h
+ create mode 100644 drivers/staging/fsl_qbman/dpa_sys_ppc64.h
+ create mode 100644 drivers/staging/fsl_qbman/fsl_usdpaa.c
+ create mode 100644 drivers/staging/fsl_qbman/fsl_usdpaa_irq.c
+ create mode 100644 drivers/staging/fsl_qbman/qbman_driver.c
+ create mode 100644 drivers/staging/fsl_qbman/qman_config.c
+ create mode 100644 drivers/staging/fsl_qbman/qman_debugfs.c
+ create mode 100644 drivers/staging/fsl_qbman/qman_driver.c
+ create mode 100644 drivers/staging/fsl_qbman/qman_high.c
+ create mode 100644 drivers/staging/fsl_qbman/qman_low.h
+ create mode 100644 drivers/staging/fsl_qbman/qman_private.h
+ create mode 100644 drivers/staging/fsl_qbman/qman_test.c
+ create mode 100644 drivers/staging/fsl_qbman/qman_test.h
+ create mode 100644 drivers/staging/fsl_qbman/qman_test_high.c
+ create mode 100644 drivers/staging/fsl_qbman/qman_test_hotpotato.c
+ create mode 100644 drivers/staging/fsl_qbman/qman_utility.c
+ create mode 100644 include/linux/fsl_bman.h
+ create mode 100644 include/linux/fsl_qman.h
+ create mode 100644 include/linux/fsl_usdpaa.h
+
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/Kconfig
+@@ -0,0 +1,228 @@
++config FSL_SDK_DPA
++      bool "Freescale Datapath Queue and Buffer management"
++      depends on !FSL_DPAA
++      select FSL_QMAN_FQ_LOOKUP if PPC64
++      select FSL_QMAN_FQ_LOOKUP if ARM64
++
++
++menu "Freescale Datapath QMan/BMan options"
++      depends on FSL_SDK_DPA
++
++config FSL_DPA_CHECKING
++      bool "additional driver checking"
++      default n
++      ---help---
++        Compiles in additional checks to sanity-check the drivers and any
++        use of it by other code. Not recommended for performance.
++
++config FSL_DPA_CAN_WAIT
++      bool
++      default y
++
++config FSL_DPA_CAN_WAIT_SYNC
++      bool
++      default y
++
++config FSL_DPA_PIRQ_FAST
++      bool
++      default y
++
++config FSL_DPA_PIRQ_SLOW
++      bool
++      default y
++
++config FSL_DPA_PORTAL_SHARE
++      bool
++      default y
++
++config FSL_SDK_BMAN
++      bool "Freescale Buffer Manager (BMan) support"
++      default y
++
++if FSL_SDK_BMAN
++
++config FSL_BMAN_CONFIG
++      bool "BMan device management"
++      default y
++      ---help---
++        If this linux image is running natively, you need this option. If this
++        linux image is running as a guest OS under the hypervisor, only one
++        guest OS ("the control plane") needs this option.
++
++config FSL_BMAN_TEST
++      tristate "BMan self-tests"
++      default n
++      ---help---
++        This option compiles self-test code for BMan.
++
++config FSL_BMAN_TEST_HIGH
++      bool "BMan high-level self-test"
++      depends on FSL_BMAN_TEST
++      default y
++      ---help---
++        This requires the presence of cpu-affine portals, and performs
++        high-level API testing with them (whichever portal(s) are affine to
++        the cpu(s) the test executes on).
++
++config FSL_BMAN_TEST_THRESH
++      bool "BMan threshold test"
++      depends on FSL_BMAN_TEST
++      default y
++      ---help---
++        Multi-threaded (SMP) test of BMan pool depletion. A pool is seeded
++        before multiple threads (one per cpu) create pool objects to track
++        depletion state changes. The pool is then drained to empty by a
++        "drainer" thread, and the other threads that they observe exactly
++        the depletion state changes that are expected.
++
++config FSL_BMAN_DEBUGFS
++      tristate "BMan debugfs interface"
++      depends on DEBUG_FS
++      default y
++      ---help---
++        This option compiles debugfs code for BMan.
++
++endif # FSL_SDK_BMAN
++
++config FSL_SDK_QMAN
++      bool "Freescale Queue Manager (QMan) support"
++      default y
++
++if FSL_SDK_QMAN
++
++config FSL_QMAN_POLL_LIMIT
++      int
++      default 32
++
++config FSL_QMAN_CONFIG
++      bool "QMan device management"
++      default y
++      ---help---
++        If this linux image is running natively, you need this option. If this
++        linux image is running as a guest OS under the hypervisor, only one
++        guest OS ("the control plane") needs this option.
++
++config FSL_QMAN_TEST
++      tristate "QMan self-tests"
++      default n
++      ---help---
++        This option compiles self-test code for QMan.
++
++config FSL_QMAN_TEST_STASH_POTATO
++      bool "QMan 'hot potato' data-stashing self-test"
++      depends on FSL_QMAN_TEST
++      default y
++      ---help---
++        This performs a "hot potato" style test enqueuing/dequeuing a frame
++        across a series of FQs scheduled to different portals (and cpus), with
++        DQRR, data and context stashing always on.
++
++config FSL_QMAN_TEST_HIGH
++      bool "QMan high-level self-test"
++      depends on FSL_QMAN_TEST
++      default y
++      ---help---
++        This requires the presence of cpu-affine portals, and performs
++        high-level API testing with them (whichever portal(s) are affine to
++        the cpu(s) the test executes on).
++
++config FSL_QMAN_DEBUGFS
++      tristate "QMan debugfs interface"
++      depends on DEBUG_FS
++      default y
++      ---help---
++        This option compiles debugfs code for QMan.
++
++# H/w settings that can be hard-coded for now.
++config FSL_QMAN_FQD_SZ
++      int "size of Frame Queue Descriptor region"
++      default 10
++      ---help---
++        This is the size of the FQD region defined as: PAGE_SIZE * (2^value)
++        ex: 10 => PAGE_SIZE * (2^10)
++        Note: Default device-trees now require minimum Kconfig setting of 10.
++
++config FSL_QMAN_PFDR_SZ
++      int "size of the PFDR pool"
++      default 13
++      ---help---
++        This is the size of the PFDR pool defined as: PAGE_SIZE * (2^value)
++        ex: 13 => PAGE_SIZE * (2^13)
++
++# Corenet initiator settings. Stash request queues are 4-deep to match cores'
++# ability to snart. Stash priority is 3, other priorities are 2.
++config FSL_QMAN_CI_SCHED_CFG_SRCCIV
++      int
++      depends on FSL_QMAN_CONFIG
++      default 4
++config FSL_QMAN_CI_SCHED_CFG_SRQ_W
++      int
++      depends on FSL_QMAN_CONFIG
++      default 3
++config FSL_QMAN_CI_SCHED_CFG_RW_W
++      int
++      depends on FSL_QMAN_CONFIG
++      default 2
++config FSL_QMAN_CI_SCHED_CFG_BMAN_W
++      int
++      depends on FSL_QMAN_CONFIG
++      default 2
++
++# portal interrupt settings
++config FSL_QMAN_PIRQ_DQRR_ITHRESH
++      int
++      default 12
++config FSL_QMAN_PIRQ_MR_ITHRESH
++      int
++      default 4
++config FSL_QMAN_PIRQ_IPERIOD
++      int
++      default 100
++
++# 64 bit kernel support
++config FSL_QMAN_FQ_LOOKUP
++      bool
++      default n
++
++config QMAN_CEETM_UPDATE_PERIOD
++      int "Token update period for shaping, in nanoseconds"
++      default 1000
++       ---help---
++      Traffic shaping works by performing token calculations (using
++      credits) on shaper instances periodically. This update period
++      sets the granularity for how often those token rate credit
++      updates are performed, and thus determines the accuracy and
++      range of traffic rates that can be configured by users. The
++      reference manual recommends a 1 microsecond period as providing
++      a good balance between granularity and range.
++
++      Unless you know what you are doing, leave this value at its default.
++
++config FSL_QMAN_INIT_TIMEOUT
++      int "timeout for qman init stage, in seconds"
++      default 10
++      ---help---
++      The timeout setting to quit the initialization loop for non-control
++      partition in case the control partition fails to boot-up.
++
++endif # FSL_SDK_QMAN
++
++config FSL_USDPAA
++        bool "Freescale USDPAA process driver"
++        depends on FSL_SDK_DPA
++        default y
++      ---help---
++        This driver provides user-space access to kernel-managed
++        resource interfaces for USDPAA applications, on the assumption
++        that each process will open this device once. Specifically, this
++        device exposes functionality that would be awkward if exposed
++        via the portal devices - ie. this device exposes functionality
++        that is inherently process-wide rather than portal-specific.
++        This device is necessary for obtaining access to DMA memory and
++        for allocation of Qman and Bman resources. In short, if you wish
++        to use USDPAA applications, you need this.
++
++        If unsure, say Y.
++
++
++endmenu
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/Makefile
+@@ -0,0 +1,28 @@
++subdir-ccflags-y := -Werror
++
++# Common
++obj-$(CONFIG_FSL_SDK_DPA)             += dpa_alloc.o
++obj-$(CONFIG_FSL_SDK_DPA)     += qbman_driver.o
++
++# Bman
++obj-$(CONFIG_FSL_SDK_BMAN)            += bman_high.o
++obj-$(CONFIG_FSL_BMAN_CONFIG) += bman_config.o bman_driver.o
++obj-$(CONFIG_FSL_BMAN_TEST)   += bman_tester.o
++obj-$(CONFIG_FSL_BMAN_DEBUGFS)  += bman_debugfs_interface.o
++bman_tester-y                  = bman_test.o
++bman_tester-$(CONFIG_FSL_BMAN_TEST_HIGH) += bman_test_high.o
++bman_tester-$(CONFIG_FSL_BMAN_TEST_THRESH) += bman_test_thresh.o
++bman_debugfs_interface-y       = bman_debugfs.o
++
++# Qman
++obj-$(CONFIG_FSL_SDK_QMAN)            += qman_high.o qman_utility.o
++obj-$(CONFIG_FSL_QMAN_CONFIG) += qman_config.o qman_driver.o
++obj-$(CONFIG_FSL_QMAN_TEST)   += qman_tester.o
++qman_tester-y                  = qman_test.o
++qman_tester-$(CONFIG_FSL_QMAN_TEST_STASH_POTATO) += qman_test_hotpotato.o
++qman_tester-$(CONFIG_FSL_QMAN_TEST_HIGH) += qman_test_high.o
++obj-$(CONFIG_FSL_QMAN_DEBUGFS)        += qman_debugfs_interface.o
++qman_debugfs_interface-y       = qman_debugfs.o
++
++# USDPAA
++obj-$(CONFIG_FSL_USDPAA)      += fsl_usdpaa.o fsl_usdpaa_irq.o
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/bman_config.c
+@@ -0,0 +1,720 @@
++/* Copyright (c) 2009-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <asm/cacheflush.h>
++#include "bman_private.h"
++#include <linux/of_reserved_mem.h>
++
++/* Last updated for v00.79 of the BG */
++
++struct bman;
++
++/* Register offsets */
++#define REG_POOL_SWDET(n)     (0x0000 + ((n) * 0x04))
++#define REG_POOL_HWDET(n)     (0x0100 + ((n) * 0x04))
++#define REG_POOL_SWDXT(n)     (0x0200 + ((n) * 0x04))
++#define REG_POOL_HWDXT(n)     (0x0300 + ((n) * 0x04))
++#define REG_POOL_CONTENT(n)   (0x0600 + ((n) * 0x04))
++#define REG_FBPR_FPC          0x0800
++#define REG_STATE_IDLE                0x960
++#define REG_STATE_STOP                0x964
++#define REG_ECSR              0x0a00
++#define REG_ECIR              0x0a04
++#define REG_EADR              0x0a08
++#define REG_EDATA(n)          (0x0a10 + ((n) * 0x04))
++#define REG_SBEC(n)           (0x0a80 + ((n) * 0x04))
++#define REG_IP_REV_1          0x0bf8
++#define REG_IP_REV_2          0x0bfc
++#define REG_FBPR_BARE         0x0c00
++#define REG_FBPR_BAR          0x0c04
++#define REG_FBPR_AR           0x0c10
++#define REG_SRCIDR            0x0d04
++#define REG_LIODNR            0x0d08
++#define REG_ERR_ISR           0x0e00  /* + "enum bm_isr_reg" */
++
++/* Used by all error interrupt registers except 'inhibit' */
++#define BM_EIRQ_IVCI  0x00000010      /* Invalid Command Verb */
++#define BM_EIRQ_FLWI  0x00000008      /* FBPR Low Watermark */
++#define BM_EIRQ_MBEI  0x00000004      /* Multi-bit ECC Error */
++#define BM_EIRQ_SBEI  0x00000002      /* Single-bit ECC Error */
++#define BM_EIRQ_BSCN  0x00000001      /* pool State Change Notification */
++
++/* BMAN_ECIR valid error bit */
++#define PORTAL_ECSR_ERR       (BM_EIRQ_IVCI)
++
++union bman_ecir {
++      u32 ecir_raw;
++      struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++              u32 __reserved1:4;
++              u32 portal_num:4;
++              u32 __reserved2:12;
++              u32 numb:4;
++              u32 __reserved3:2;
++              u32 pid:6;
++#else
++              u32 pid:6;
++              u32 __reserved3:2;
++              u32 numb:4;
++              u32 __reserved2:12;
++              u32 portal_num:4;
++              u32 __reserved1:4;
++#endif
++      } __packed info;
++};
++
++union bman_eadr {
++      u32 eadr_raw;
++      struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++              u32 __reserved1:5;
++              u32 memid:3;
++              u32 __reserved2:14;
++              u32 eadr:10;
++#else
++              u32 eadr:10;
++              u32 __reserved2:14;
++              u32 memid:3;
++              u32 __reserved1:5;
++#endif
++      } __packed info;
++};
++
++struct bman_hwerr_txt {
++      u32 mask;
++      const char *txt;
++};
++
++#define BMAN_HWE_TXT(a, b) { .mask = BM_EIRQ_##a, .txt = b }
++
++static const struct bman_hwerr_txt bman_hwerr_txts[] = {
++      BMAN_HWE_TXT(IVCI, "Invalid Command Verb"),
++      BMAN_HWE_TXT(FLWI, "FBPR Low Watermark"),
++      BMAN_HWE_TXT(MBEI, "Multi-bit ECC Error"),
++      BMAN_HWE_TXT(SBEI, "Single-bit ECC Error"),
++      BMAN_HWE_TXT(BSCN, "Pool State Change Notification"),
++};
++#define BMAN_HWE_COUNT (sizeof(bman_hwerr_txts)/sizeof(struct bman_hwerr_txt))
++
++struct bman_error_info_mdata {
++      u16 addr_mask;
++      u16 bits;
++      const char *txt;
++};
++
++#define BMAN_ERR_MDATA(a, b, c) { .addr_mask = a, .bits = b, .txt = c}
++static const struct bman_error_info_mdata error_mdata[] = {
++      BMAN_ERR_MDATA(0x03FF, 192, "Stockpile memory"),
++      BMAN_ERR_MDATA(0x00FF, 256, "SW portal ring memory port 1"),
++      BMAN_ERR_MDATA(0x00FF, 256, "SW portal ring memory port 2"),
++};
++#define BMAN_ERR_MDATA_COUNT \
++      (sizeof(error_mdata)/sizeof(struct bman_error_info_mdata))
++
++/* Add this in Kconfig */
++#define BMAN_ERRS_TO_UNENABLE (BM_EIRQ_FLWI)
++
++/**
++ * bm_err_isr_<reg>_<verb> - Manipulate global interrupt registers
++ * @v: for accessors that write values, this is the 32-bit value
++ *
++ * Manipulates BMAN_ERR_ISR, BMAN_ERR_IER, BMAN_ERR_ISDR, BMAN_ERR_IIR. All
++ * manipulations except bm_err_isr_[un]inhibit() use 32-bit masks composed of
++ * the BM_EIRQ_*** definitions. Note that "bm_err_isr_enable_write" means
++ * "write the enable register" rather than "enable the write register"!
++ */
++#define bm_err_isr_status_read(bm)    \
++              __bm_err_isr_read(bm, bm_isr_status)
++#define bm_err_isr_status_clear(bm, m)        \
++              __bm_err_isr_write(bm, bm_isr_status, m)
++#define bm_err_isr_enable_read(bm)    \
++              __bm_err_isr_read(bm, bm_isr_enable)
++#define bm_err_isr_enable_write(bm, v)        \
++              __bm_err_isr_write(bm, bm_isr_enable, v)
++#define bm_err_isr_disable_read(bm)   \
++              __bm_err_isr_read(bm, bm_isr_disable)
++#define bm_err_isr_disable_write(bm, v)       \
++              __bm_err_isr_write(bm, bm_isr_disable, v)
++#define bm_err_isr_inhibit(bm)                \
++              __bm_err_isr_write(bm, bm_isr_inhibit, 1)
++#define bm_err_isr_uninhibit(bm)      \
++              __bm_err_isr_write(bm, bm_isr_inhibit, 0)
++
++/*
++ * TODO: unimplemented registers
++ *
++ * BMAN_POOLk_SDCNT, BMAN_POOLk_HDCNT, BMAN_FULT,
++ * BMAN_VLDPL, BMAN_EECC, BMAN_SBET, BMAN_EINJ
++ */
++
++/* Encapsulate "struct bman *" as a cast of the register space address. */
++
++static struct bman *bm_create(void *regs)
++{
++      return (struct bman *)regs;
++}
++
++static inline u32 __bm_in(struct bman *bm, u32 offset)
++{
++      return in_be32((void *)bm + offset);
++}
++static inline void __bm_out(struct bman *bm, u32 offset, u32 val)
++{
++      out_be32((void *)bm + offset, val);
++}
++#define bm_in(reg)            __bm_in(bm, REG_##reg)
++#define bm_out(reg, val)      __bm_out(bm, REG_##reg, val)
++
++static u32 __bm_err_isr_read(struct bman *bm, enum bm_isr_reg n)
++{
++      return __bm_in(bm, REG_ERR_ISR + (n << 2));
++}
++
++static void __bm_err_isr_write(struct bman *bm, enum bm_isr_reg n, u32 val)
++{
++      __bm_out(bm, REG_ERR_ISR + (n << 2), val);
++}
++
++static void bm_get_version(struct bman *bm, u16 *id, u8 *major, u8 *minor)
++{
++      u32 v = bm_in(IP_REV_1);
++      *id = (v >> 16);
++      *major = (v >> 8) & 0xff;
++      *minor = v & 0xff;
++}
++
++static u32 __generate_thresh(u32 val, int roundup)
++{
++      u32 e = 0;      /* co-efficient, exponent */
++      int oddbit = 0;
++      while (val > 0xff) {
++              oddbit = val & 1;
++              val >>= 1;
++              e++;
++              if (roundup && oddbit)
++                      val++;
++      }
++      DPA_ASSERT(e < 0x10);
++      return val | (e << 8);
++}
++
++static void bm_set_pool(struct bman *bm, u8 pool, u32 swdet, u32 swdxt,
++                      u32 hwdet, u32 hwdxt)
++{
++      DPA_ASSERT(pool < bman_pool_max);
++      bm_out(POOL_SWDET(pool), __generate_thresh(swdet, 0));
++      bm_out(POOL_SWDXT(pool), __generate_thresh(swdxt, 1));
++      bm_out(POOL_HWDET(pool), __generate_thresh(hwdet, 0));
++      bm_out(POOL_HWDXT(pool), __generate_thresh(hwdxt, 1));
++}
++
++static void bm_set_memory(struct bman *bm, u64 ba, int prio, u32 size)
++{
++      u32 exp = ilog2(size);
++      /* choke if size isn't within range */
++      DPA_ASSERT((size >= 4096) && (size <= 1073741824) &&
++                      is_power_of_2(size));
++      /* choke if '[e]ba' has lower-alignment than 'size' */
++      DPA_ASSERT(!(ba & (size - 1)));
++      bm_out(FBPR_BARE, upper_32_bits(ba));
++      bm_out(FBPR_BAR, lower_32_bits(ba));
++      bm_out(FBPR_AR, (prio ? 0x40000000 : 0) | (exp - 1));
++}
++
++/*****************/
++/* Config driver */
++/*****************/
++
++/* TODO: Kconfig these? */
++#define DEFAULT_FBPR_SZ       (PAGE_SIZE << 12)
++
++/* We support only one of these. */
++static struct bman *bm;
++static struct device_node *bm_node;
++
++/* And this state belongs to 'bm'. It is set during fsl_bman_init(), but used
++ * during bman_init_ccsr(). */
++static dma_addr_t fbpr_a;
++static size_t fbpr_sz = DEFAULT_FBPR_SZ;
++
++static int bman_fbpr(struct reserved_mem *rmem)
++{
++      fbpr_a = rmem->base;
++      fbpr_sz = rmem->size;
++
++      WARN_ON(!(fbpr_a && fbpr_sz));
++
++      return 0;
++}
++RESERVEDMEM_OF_DECLARE(bman_fbpr, "fsl,bman-fbpr", bman_fbpr);
++
++static int __init fsl_bman_init(struct device_node *node)
++{
++      struct resource res;
++      u32 __iomem *regs;
++      const char *s;
++      int ret, standby = 0;
++      u16 id;
++      u8 major, minor;
++
++      ret = of_address_to_resource(node, 0, &res);
++      if (ret) {
++              pr_err("Can't get %s property 'reg'\n",
++                              node->full_name);
++              return ret;
++      }
++      s = of_get_property(node, "fsl,hv-claimable", &ret);
++      if (s && !strcmp(s, "standby"))
++              standby = 1;
++      /* Global configuration */
++      regs = ioremap(res.start, res.end - res.start + 1);
++      bm = bm_create(regs);
++      BUG_ON(!bm);
++      bm_node = node;
++      bm_get_version(bm, &id, &major, &minor);
++      pr_info("Bman ver:%04x,%02x,%02x\n", id, major, minor);
++      if ((major == 1) && (minor == 0)) {
++              bman_ip_rev = BMAN_REV10;
++              bman_pool_max = 64;
++      } else if ((major == 2) && (minor == 0)) {
++              bman_ip_rev = BMAN_REV20;
++              bman_pool_max = 8;
++      } else if ((major == 2) && (minor == 1)) {
++              bman_ip_rev = BMAN_REV21;
++              bman_pool_max = 64;
++      } else {
++              pr_warn("unknown Bman version, default to rev1.0\n");
++      }
++
++      if (standby) {
++              pr_info("  -> in standby mode\n");
++              return 0;
++      }
++      return 0;
++}
++
++int bman_have_ccsr(void)
++{
++      return bm ? 1 : 0;
++}
++
++int bm_pool_set(u32 bpid, const u32 *thresholds)
++{
++      if (!bm)
++              return -ENODEV;
++      bm_set_pool(bm, bpid, thresholds[0],
++                  thresholds[1], thresholds[2],
++                  thresholds[3]);
++      return 0;
++}
++EXPORT_SYMBOL(bm_pool_set);
++
++__init int bman_init_early(void)
++{
++      struct device_node *dn;
++      int ret;
++
++      for_each_compatible_node(dn, NULL, "fsl,bman") {
++              if (bm)
++                      pr_err("%s: only one 'fsl,bman' allowed\n",
++                              dn->full_name);
++              else {
++                      if (!of_device_is_available(dn))
++                              continue;
++
++                      ret = fsl_bman_init(dn);
++                      BUG_ON(ret);
++              }
++      }
++      return 0;
++}
++postcore_initcall_sync(bman_init_early);
++
++
++static void log_edata_bits(u32 bit_count)
++{
++      u32 i, j, mask = 0xffffffff;
++
++      pr_warn("Bman ErrInt, EDATA:\n");
++      i = bit_count/32;
++      if (bit_count%32) {
++              i++;
++              mask = ~(mask << bit_count%32);
++      }
++      j = 16-i;
++      pr_warn("  0x%08x\n", bm_in(EDATA(j)) & mask);
++      j++;
++      for (; j < 16; j++)
++              pr_warn("  0x%08x\n", bm_in(EDATA(j)));
++}
++
++static void log_additional_error_info(u32 isr_val, u32 ecsr_val)
++{
++      union bman_ecir ecir_val;
++      union bman_eadr eadr_val;
++
++      ecir_val.ecir_raw = bm_in(ECIR);
++      /* Is portal info valid */
++      if (ecsr_val & PORTAL_ECSR_ERR) {
++              pr_warn("Bman ErrInt: SWP id %d, numb %d, pid %d\n",
++                      ecir_val.info.portal_num, ecir_val.info.numb,
++                      ecir_val.info.pid);
++      }
++      if (ecsr_val & (BM_EIRQ_SBEI|BM_EIRQ_MBEI)) {
++              eadr_val.eadr_raw = bm_in(EADR);
++              pr_warn("Bman ErrInt: EADR Memory: %s, 0x%x\n",
++                      error_mdata[eadr_val.info.memid].txt,
++                      error_mdata[eadr_val.info.memid].addr_mask
++                              & eadr_val.info.eadr);
++              log_edata_bits(error_mdata[eadr_val.info.memid].bits);
++      }
++}
++
++/* Bman interrupt handler */
++static irqreturn_t bman_isr(int irq, void *ptr)
++{
++      u32 isr_val, ier_val, ecsr_val, isr_mask, i;
++
++      ier_val = bm_err_isr_enable_read(bm);
++      isr_val = bm_err_isr_status_read(bm);
++      ecsr_val = bm_in(ECSR);
++      isr_mask = isr_val & ier_val;
++
++      if (!isr_mask)
++              return IRQ_NONE;
++      for (i = 0; i < BMAN_HWE_COUNT; i++) {
++              if (bman_hwerr_txts[i].mask & isr_mask) {
++                      pr_warn("Bman ErrInt: %s\n", bman_hwerr_txts[i].txt);
++                      if (bman_hwerr_txts[i].mask & ecsr_val) {
++                              log_additional_error_info(isr_mask, ecsr_val);
++                              /* Re-arm error capture registers */
++                              bm_out(ECSR, ecsr_val);
++                      }
++                      if (bman_hwerr_txts[i].mask & BMAN_ERRS_TO_UNENABLE) {
++                              pr_devel("Bman un-enabling error 0x%x\n",
++                                      bman_hwerr_txts[i].mask);
++                              ier_val &= ~bman_hwerr_txts[i].mask;
++                              bm_err_isr_enable_write(bm, ier_val);
++                      }
++              }
++      }
++      bm_err_isr_status_clear(bm, isr_val);
++      return IRQ_HANDLED;
++}
++
++static int __bind_irq(void)
++{
++      int ret, err_irq;
++
++      err_irq = of_irq_to_resource(bm_node, 0, NULL);
++      if (err_irq == 0) {
++              pr_info("Can't get %s property '%s'\n", bm_node->full_name,
++                      "interrupts");
++              return -ENODEV;
++      }
++      ret = request_irq(err_irq, bman_isr, IRQF_SHARED, "bman-err", bm_node);
++      if (ret)  {
++              pr_err("request_irq() failed %d for '%s'\n", ret,
++                      bm_node->full_name);
++              return -ENODEV;
++      }
++      /* Disable Buffer Pool State Change */
++      bm_err_isr_disable_write(bm, BM_EIRQ_BSCN);
++      /* Write-to-clear any stale bits, (eg. starvation being asserted prior
++       * to resource allocation during driver init). */
++      bm_err_isr_status_clear(bm, 0xffffffff);
++      /* Enable Error Interrupts */
++      bm_err_isr_enable_write(bm, 0xffffffff);
++      return 0;
++}
++
++int bman_init_ccsr(struct device_node *node)
++{
++      int ret;
++      if (!bman_have_ccsr())
++              return 0;
++      if (node != bm_node)
++              return -EINVAL;
++      /* FBPR memory */
++      bm_set_memory(bm, fbpr_a, 0, fbpr_sz);
++      pr_info("bman-fbpr addr %pad size 0x%zx\n", &fbpr_a, fbpr_sz);
++
++      ret = __bind_irq();
++      if (ret)
++              return ret;
++      return 0;
++}
++
++u32 bm_pool_free_buffers(u32 bpid)
++{
++      return bm_in(POOL_CONTENT(bpid));
++}
++
++#ifdef CONFIG_SYSFS
++
++#define DRV_NAME "fsl-bman"
++#define SBEC_MAX_ID 1
++#define SBEC_MIN_ID 0
++
++static ssize_t show_fbpr_fpc(struct device *dev,
++      struct device_attribute *dev_attr, char *buf)
++{
++      return snprintf(buf, PAGE_SIZE, "%u\n", bm_in(FBPR_FPC));
++};
++
++static ssize_t show_pool_count(struct device *dev,
++      struct device_attribute *dev_attr, char *buf)
++{
++      u32 data;
++      int i;
++
++      if (!sscanf(dev_attr->attr.name, "%d", &i) || (i >= bman_pool_max))
++              return -EINVAL;
++      data = bm_in(POOL_CONTENT(i));
++      return snprintf(buf, PAGE_SIZE, "%d\n", data);
++};
++
++static ssize_t show_err_isr(struct device *dev,
++      struct device_attribute *dev_attr, char *buf)
++{
++      return snprintf(buf, PAGE_SIZE, "0x%08x\n", bm_in(ERR_ISR));
++};
++
++static ssize_t show_sbec(struct device *dev,
++      struct device_attribute *dev_attr, char *buf)
++{
++      int i;
++
++      if (!sscanf(dev_attr->attr.name, "sbec_%d", &i))
++              return -EINVAL;
++      if (i < SBEC_MIN_ID || i > SBEC_MAX_ID)
++              return -EINVAL;
++      return snprintf(buf, PAGE_SIZE, "%u\n", bm_in(SBEC(i)));
++};
++
++static DEVICE_ATTR(err_isr, S_IRUSR, show_err_isr, NULL);
++static DEVICE_ATTR(fbpr_fpc, S_IRUSR, show_fbpr_fpc, NULL);
++
++/* Didn't use DEVICE_ATTR as 64 of this would be required.
++ * Initialize them when needed. */
++static char *name_attrs_pool_count; /* "xx" + null-terminator */
++static struct device_attribute *dev_attr_buffer_pool_count;
++
++static DEVICE_ATTR(sbec_0, S_IRUSR, show_sbec, NULL);
++static DEVICE_ATTR(sbec_1, S_IRUSR, show_sbec, NULL);
++
++static struct attribute *bman_dev_attributes[] = {
++      &dev_attr_fbpr_fpc.attr,
++      &dev_attr_err_isr.attr,
++      NULL
++};
++
++static struct attribute *bman_dev_ecr_attributes[] = {
++      &dev_attr_sbec_0.attr,
++      &dev_attr_sbec_1.attr,
++      NULL
++};
++
++static struct attribute **bman_dev_pool_count_attributes;
++
++
++/* root level */
++static const struct attribute_group bman_dev_attr_grp = {
++      .name = NULL,
++      .attrs = bman_dev_attributes
++};
++static const struct attribute_group bman_dev_ecr_grp = {
++      .name = "error_capture",
++      .attrs = bman_dev_ecr_attributes
++};
++static struct attribute_group bman_dev_pool_countent_grp = {
++      .name = "pool_count",
++};
++
++static int of_fsl_bman_remove(struct platform_device *ofdev)
++{
++      sysfs_remove_group(&ofdev->dev.kobj, &bman_dev_attr_grp);
++      return 0;
++};
++
++static int of_fsl_bman_probe(struct platform_device *ofdev)
++{
++      int ret, i;
++
++      ret = sysfs_create_group(&ofdev->dev.kobj, &bman_dev_attr_grp);
++      if (ret)
++              goto done;
++      ret = sysfs_create_group(&ofdev->dev.kobj, &bman_dev_ecr_grp);
++      if (ret)
++              goto del_group_0;
++
++      name_attrs_pool_count = kmalloc(sizeof(char) * bman_pool_max * 3,
++                                                               GFP_KERNEL);
++      if (!name_attrs_pool_count) {
++              pr_err("Can't alloc name_attrs_pool_count\n");
++              goto del_group_1;
++      }
++
++      dev_attr_buffer_pool_count = kmalloc(sizeof(struct device_attribute) *
++                                      bman_pool_max, GFP_KERNEL);
++      if (!dev_attr_buffer_pool_count) {
++              pr_err("Can't alloc dev_attr-buffer_pool_count\n");
++              goto del_group_2;
++      }
++
++      bman_dev_pool_count_attributes = kmalloc(sizeof(struct attribute *) *
++                       (bman_pool_max + 1), GFP_KERNEL);
++      if (!bman_dev_pool_count_attributes) {
++                      pr_err("can't alloc bman_dev_pool_count_attributes\n");
++                      goto del_group_3;
++      }
++
++      for (i = 0; i < bman_pool_max; i++) {
++              ret = scnprintf((name_attrs_pool_count + i * 3), 3, "%d", i);
++              if (!ret)
++                      goto del_group_4;
++              dev_attr_buffer_pool_count[i].attr.name =
++                      (name_attrs_pool_count + i * 3);
++              dev_attr_buffer_pool_count[i].attr.mode = S_IRUSR;
++              dev_attr_buffer_pool_count[i].show = show_pool_count;
++              bman_dev_pool_count_attributes[i] =
++                      &dev_attr_buffer_pool_count[i].attr;
++              sysfs_attr_init(bman_dev_pool_count_attributes[i]);
++      }
++      bman_dev_pool_count_attributes[bman_pool_max] = NULL;
++
++      bman_dev_pool_countent_grp.attrs = bman_dev_pool_count_attributes;
++
++      ret = sysfs_create_group(&ofdev->dev.kobj, &bman_dev_pool_countent_grp);
++      if (ret)
++              goto del_group_4;
++
++      goto done;
++
++del_group_4:
++      kfree(bman_dev_pool_count_attributes);
++del_group_3:
++      kfree(dev_attr_buffer_pool_count);
++del_group_2:
++      kfree(name_attrs_pool_count);
++del_group_1:
++      sysfs_remove_group(&ofdev->dev.kobj, &bman_dev_ecr_grp);
++del_group_0:
++      sysfs_remove_group(&ofdev->dev.kobj, &bman_dev_attr_grp);
++done:
++      if (ret)
++              dev_err(&ofdev->dev,
++                      "Cannot create dev attributes ret=%d\n", ret);
++      return ret;
++};
++
++static struct of_device_id of_fsl_bman_ids[] = {
++      {
++              .compatible = "fsl,bman",
++      },
++      {}
++};
++MODULE_DEVICE_TABLE(of, of_fsl_bman_ids);
++
++#ifdef CONFIG_SUSPEND
++static u32 saved_isdr;
++
++static int bman_pm_suspend_noirq(struct device *dev)
++{
++      uint32_t idle_state;
++
++      suspend_unused_bportal();
++      /* save isdr, disable all, clear isr */
++      saved_isdr = bm_err_isr_disable_read(bm);
++      bm_err_isr_disable_write(bm, 0xffffffff);
++      bm_err_isr_status_clear(bm, 0xffffffff);
++
++      if (bman_ip_rev < BMAN_REV21) {
++#ifdef CONFIG_PM_DEBUG
++              pr_info("Bman version doesn't have STATE_IDLE\n");
++#endif
++              return 0;
++      }
++      idle_state = bm_in(STATE_IDLE);
++      if (!(idle_state & 0x1)) {
++              pr_err("Bman not idle 0x%x aborting\n", idle_state);
++              bm_err_isr_disable_write(bm, saved_isdr);
++              resume_unused_bportal();
++              return -EBUSY;
++      }
++#ifdef CONFIG_PM_DEBUG
++      pr_info("Bman suspend code, IDLE_STAT = 0x%x\n", idle_state);
++#endif
++      return 0;
++}
++
++static int bman_pm_resume_noirq(struct device *dev)
++{
++      /* restore isdr */
++      bm_err_isr_disable_write(bm, saved_isdr);
++      resume_unused_bportal();
++      return 0;
++}
++#else
++#define bman_pm_suspend_noirq NULL
++#define bman_pm_resume_noirq  NULL
++#endif
++
++static const struct dev_pm_ops bman_pm_ops = {
++      .suspend_noirq = bman_pm_suspend_noirq,
++      .resume_noirq = bman_pm_resume_noirq,
++};
++
++static struct platform_driver of_fsl_bman_driver = {
++      .driver = {
++              .owner = THIS_MODULE,
++              .name = DRV_NAME,
++              .of_match_table = of_fsl_bman_ids,
++              .pm = &bman_pm_ops,
++      },
++      .probe = of_fsl_bman_probe,
++      .remove = of_fsl_bman_remove,
++};
++
++static int bman_ctrl_init(void)
++{
++      return platform_driver_register(&of_fsl_bman_driver);
++}
++
++static void bman_ctrl_exit(void)
++{
++      platform_driver_unregister(&of_fsl_bman_driver);
++}
++
++module_init(bman_ctrl_init);
++module_exit(bman_ctrl_exit);
++
++#endif /* CONFIG_SYSFS */
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/bman_debugfs.c
+@@ -0,0 +1,119 @@
++/* Copyright 2010-2011 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++#include <linux/module.h>
++#include <linux/fsl_bman.h>
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
++#include <linux/uaccess.h>
++
++static struct dentry *dfs_root; /* debugfs root directory */
++
++/*******************************************************************************
++ *  Query Buffer Pool State
++ ******************************************************************************/
++static int query_bp_state_show(struct seq_file *file, void *offset)
++{
++      int ret;
++      struct bm_pool_state state;
++      int i, j;
++      u32 mask;
++
++      memset(&state, 0, sizeof(struct bm_pool_state));
++      ret = bman_query_pools(&state);
++      if (ret) {
++              seq_printf(file, "Error %d\n", ret);
++              return 0;
++      }
++      seq_puts(file, "bp_id  free_buffers_avail  bp_depleted\n");
++      for (i = 0; i < 2; i++) {
++              mask = 0x80000000;
++              for (j = 0; j < 32; j++) {
++                      seq_printf(file,
++                       "  %-2u           %-3s             %-3s\n",
++                       (i*32)+j,
++                       (state.as.state.__state[i] & mask) ? "no" : "yes",
++                       (state.ds.state.__state[i] & mask) ? "yes" : "no");
++                       mask >>= 1;
++              }
++      }
++      return 0;
++}
++
++static int query_bp_state_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, query_bp_state_show, NULL);
++}
++
++static const struct file_operations query_bp_state_fops = {
++      .owner          = THIS_MODULE,
++      .open           = query_bp_state_open,
++      .read           = seq_read,
++      .release        = single_release,
++};
++
++static int __init bman_debugfs_module_init(void)
++{
++      int ret = 0;
++      struct dentry *d;
++
++      dfs_root = debugfs_create_dir("bman", NULL);
++
++      if (dfs_root == NULL) {
++              ret = -ENOMEM;
++              pr_err("Cannot create bman debugfs dir\n");
++              goto _return;
++      }
++      d = debugfs_create_file("query_bp_state",
++              S_IRUGO,
++              dfs_root,
++              NULL,
++              &query_bp_state_fops);
++      if (d == NULL) {
++              ret = -ENOMEM;
++              pr_err("Cannot create query_bp_state\n");
++              goto _return;
++      }
++      return 0;
++
++_return:
++      debugfs_remove_recursive(dfs_root);
++      return ret;
++}
++
++static void __exit bman_debugfs_module_exit(void)
++{
++      debugfs_remove_recursive(dfs_root);
++}
++
++
++module_init(bman_debugfs_module_init);
++module_exit(bman_debugfs_module_exit);
++MODULE_LICENSE("Dual BSD/GPL");
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/bman_driver.c
+@@ -0,0 +1,559 @@
++/* Copyright 2008-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++#include "bman_low.h"
++#ifdef CONFIG_HOTPLUG_CPU
++#include <linux/cpu.h>
++#endif
++/*
++ * Global variables of the max portal/pool number this bman version supported
++ */
++u16 bman_ip_rev;
++EXPORT_SYMBOL(bman_ip_rev);
++u16 bman_pool_max;
++EXPORT_SYMBOL(bman_pool_max);
++static u16 bman_portal_max;
++
++/* After initialising cpus that own shared portal configs, we cache the
++ * resulting portals (ie. not just the configs) in this array. Then we
++ * initialise slave cpus that don't have their own portals, redirecting them to
++ * portals from this cache in a round-robin assignment. */
++static struct bman_portal *shared_portals[NR_CPUS];
++static int num_shared_portals;
++static int shared_portals_idx;
++static LIST_HEAD(unused_pcfgs);
++static DEFINE_SPINLOCK(unused_pcfgs_lock);
++static void *affine_bportals[NR_CPUS];
++
++static int __init fsl_bpool_init(struct device_node *node)
++{
++      int ret;
++      u32 *thresh, *bpid = (u32 *)of_get_property(node, "fsl,bpid", &ret);
++      if (!bpid || (ret != 4)) {
++              pr_err("Can't get %s property 'fsl,bpid'\n", node->full_name);
++              return -ENODEV;
++      }
++      thresh = (u32 *)of_get_property(node, "fsl,bpool-thresholds", &ret);
++      if (thresh) {
++              if (ret != 16) {
++                      pr_err("Invalid %s property '%s'\n",
++                              node->full_name, "fsl,bpool-thresholds");
++                      return -ENODEV;
++              }
++      }
++      if (thresh) {
++#ifdef CONFIG_FSL_BMAN_CONFIG
++              ret = bm_pool_set(be32_to_cpu(*bpid), thresh);
++              if (ret)
++                      pr_err("No CCSR node for %s property '%s'\n",
++                              node->full_name, "fsl,bpool-thresholds");
++              return ret;
++#else
++              pr_err("Ignoring %s property '%s', no CCSR support\n",
++                      node->full_name, "fsl,bpool-thresholds");
++#endif
++      }
++      return 0;
++}
++
++static int __init fsl_bpid_range_init(struct device_node *node)
++{
++      int ret;
++      u32 *range = (u32 *)of_get_property(node, "fsl,bpid-range", &ret);
++      if (!range) {
++              pr_err("No 'fsl,bpid-range' property in node %s\n",
++                      node->full_name);
++              return -EINVAL;
++      }
++      if (ret != 8) {
++              pr_err("'fsl,bpid-range' is not a 2-cell range in node %s\n",
++                      node->full_name);
++              return -EINVAL;
++      }
++      bman_seed_bpid_range(be32_to_cpu(range[0]), be32_to_cpu(range[1]));
++      pr_info("Bman: BPID allocator includes range %d:%d\n",
++              be32_to_cpu(range[0]), be32_to_cpu(range[1]));
++      return 0;
++}
++
++static struct bm_portal_config * __init parse_pcfg(struct device_node *node)
++{
++      struct bm_portal_config *pcfg;
++      const u32 *index;
++      int irq, ret;
++      resource_size_t len;
++
++      pcfg = kmalloc(sizeof(*pcfg), GFP_KERNEL);
++      if (!pcfg) {
++              pr_err("can't allocate portal config");
++              return NULL;
++      }
++
++      if (of_device_is_compatible(node, "fsl,bman-portal-1.0") ||
++              of_device_is_compatible(node, "fsl,bman-portal-1.0.0")) {
++              bman_ip_rev = BMAN_REV10;
++              bman_pool_max = 64;
++              bman_portal_max = 10;
++      } else if (of_device_is_compatible(node, "fsl,bman-portal-2.0") ||
++              of_device_is_compatible(node, "fsl,bman-portal-2.0.8")) {
++              bman_ip_rev = BMAN_REV20;
++              bman_pool_max = 8;
++              bman_portal_max = 3;
++      } else if (of_device_is_compatible(node, "fsl,bman-portal-2.1.0")) {
++              bman_ip_rev = BMAN_REV21;
++              bman_pool_max = 64;
++              bman_portal_max = 50;
++      } else if (of_device_is_compatible(node, "fsl,bman-portal-2.1.1")) {
++              bman_ip_rev = BMAN_REV21;
++              bman_pool_max = 64;
++              bman_portal_max = 25;
++      } else if (of_device_is_compatible(node, "fsl,bman-portal-2.1.2")) {
++              bman_ip_rev = BMAN_REV21;
++              bman_pool_max = 64;
++              bman_portal_max = 18;
++      } else if (of_device_is_compatible(node, "fsl,bman-portal-2.1.3")) {
++              bman_ip_rev = BMAN_REV21;
++              bman_pool_max = 64;
++              bman_portal_max = 10;
++      } else {
++              pr_warn("unknown BMan version in portal node,"
++                      "default to rev1.0\n");
++              bman_ip_rev = BMAN_REV10;
++              bman_pool_max = 64;
++              bman_portal_max = 10;
++      }
++
++      ret = of_address_to_resource(node, DPA_PORTAL_CE,
++                              &pcfg->addr_phys[DPA_PORTAL_CE]);
++      if (ret) {
++              pr_err("Can't get %s property 'reg::CE'\n", node->full_name);
++              goto err;
++      }
++      ret = of_address_to_resource(node, DPA_PORTAL_CI,
++                              &pcfg->addr_phys[DPA_PORTAL_CI]);
++      if (ret) {
++              pr_err("Can't get %s property 'reg::CI'\n", node->full_name);
++              goto err;
++      }
++
++      index = of_get_property(node, "cell-index", &ret);
++      if (!index || (ret != 4)) {
++              pr_err("Can't get %s property '%s'\n", node->full_name,
++                      "cell-index");
++              goto err;
++      }
++      if (be32_to_cpu(*index) >= bman_portal_max) {
++              pr_err("BMan portal cell index %d out of range, max %d\n",
++                     be32_to_cpu(*index), bman_portal_max);
++              goto err;
++      }
++
++      pcfg->public_cfg.cpu = -1;
++
++      irq = irq_of_parse_and_map(node, 0);
++      if (irq == 0) {
++              pr_err("Can't get %s property 'interrupts'\n", node->full_name);
++              goto err;
++      }
++      pcfg->public_cfg.irq = irq;
++      pcfg->public_cfg.index = be32_to_cpu(*index);
++      bman_depletion_fill(&pcfg->public_cfg.mask);
++
++      len = resource_size(&pcfg->addr_phys[DPA_PORTAL_CE]);
++      if (len != (unsigned long)len)
++              goto err;
++
++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++      pcfg->addr_virt[DPA_PORTAL_CE] = ioremap_cache_ns(
++                                pcfg->addr_phys[DPA_PORTAL_CE].start,
++                                resource_size(&pcfg->addr_phys[DPA_PORTAL_CE]));
++        pcfg->addr_virt[DPA_PORTAL_CI] = ioremap(
++                                pcfg->addr_phys[DPA_PORTAL_CI].start,
++                                resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]));
++
++#else
++      pcfg->addr_virt[DPA_PORTAL_CE] = ioremap_prot(
++                              pcfg->addr_phys[DPA_PORTAL_CE].start,
++                              (unsigned long)len,
++                              0);
++      pcfg->addr_virt[DPA_PORTAL_CI] = ioremap_prot(
++                              pcfg->addr_phys[DPA_PORTAL_CI].start,
++                              resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]),
++                              _PAGE_GUARDED | _PAGE_NO_CACHE);
++#endif
++      /* disable bp depletion */
++      __raw_writel(0x0, pcfg->addr_virt[DPA_PORTAL_CI] + BM_REG_SCN(0));
++      __raw_writel(0x0, pcfg->addr_virt[DPA_PORTAL_CI] + BM_REG_SCN(1));
++      return pcfg;
++err:
++      kfree(pcfg);
++      return NULL;
++}
++
++static struct bm_portal_config *get_pcfg(struct list_head *list)
++{
++      struct bm_portal_config *pcfg;
++      if (list_empty(list))
++              return NULL;
++      pcfg = list_entry(list->prev, struct bm_portal_config, list);
++      list_del(&pcfg->list);
++      return pcfg;
++}
++
++static struct bm_portal_config *get_pcfg_idx(struct list_head *list,
++                                           uint32_t idx)
++{
++      struct bm_portal_config *pcfg;
++      if (list_empty(list))
++              return NULL;
++      list_for_each_entry(pcfg, list, list) {
++              if (pcfg->public_cfg.index == idx) {
++                      list_del(&pcfg->list);
++                      return pcfg;
++              }
++      }
++      return NULL;
++}
++
++struct bm_portal_config *bm_get_unused_portal(void)
++{
++      return bm_get_unused_portal_idx(QBMAN_ANY_PORTAL_IDX);
++}
++
++struct bm_portal_config *bm_get_unused_portal_idx(uint32_t idx)
++{
++      struct bm_portal_config *ret;
++      spin_lock(&unused_pcfgs_lock);
++      if (idx == QBMAN_ANY_PORTAL_IDX)
++              ret = get_pcfg(&unused_pcfgs);
++      else
++              ret = get_pcfg_idx(&unused_pcfgs, idx);
++      spin_unlock(&unused_pcfgs_lock);
++      return ret;
++}
++
++void bm_put_unused_portal(struct bm_portal_config *pcfg)
++{
++      spin_lock(&unused_pcfgs_lock);
++      list_add(&pcfg->list, &unused_pcfgs);
++      spin_unlock(&unused_pcfgs_lock);
++}
++
++static struct bman_portal *init_pcfg(struct bm_portal_config *pcfg)
++{
++      struct bman_portal *p;
++      p = bman_create_affine_portal(pcfg);
++      if (p) {
++#ifdef CONFIG_FSL_DPA_PIRQ_SLOW
++              bman_p_irqsource_add(p, BM_PIRQ_RCRI | BM_PIRQ_BSCN);
++#endif
++              pr_info("Bman portal %sinitialised, cpu %d\n",
++                      pcfg->public_cfg.is_shared ? "(shared) " : "",
++                      pcfg->public_cfg.cpu);
++              affine_bportals[pcfg->public_cfg.cpu] = p;
++      } else
++              pr_crit("Bman portal failure on cpu %d\n",
++                      pcfg->public_cfg.cpu);
++      return p;
++}
++
++static void init_slave(int cpu)
++{
++      struct bman_portal *p;
++      p = bman_create_affine_slave(shared_portals[shared_portals_idx++], cpu);
++      if (!p)
++              pr_err("Bman slave portal failure on cpu %d\n", cpu);
++      else
++              pr_info("Bman portal %sinitialised, cpu %d\n", "(slave) ", cpu);
++      if (shared_portals_idx >= num_shared_portals)
++              shared_portals_idx = 0;
++      affine_bportals[cpu] = p;
++}
++
++/* Bootarg "bportals=[...]" has the same syntax as "qportals=", and so the
++ * parsing is in dpa_sys.h. The syntax is a comma-separated list of indexes
++ * and/or ranges of indexes, with each being optionally prefixed by "s" to
++ * explicitly mark it or them for sharing.
++ *    Eg;
++ *      bportals=s0,1-3,s4
++ * means that cpus 1,2,3 get "unshared" portals, cpus 0 and 4 get "shared"
++ * portals, and any remaining cpus share the portals that are assigned to cpus 0
++ * or 4, selected in a round-robin fashion. (In this example, cpu 5 would share
++ * cpu 0's portal, cpu 6 would share cpu4's portal, and cpu 7 would share cpu
++ * 0's portal.) */
++static struct cpumask want_unshared __initdata; /* cpus requested without "s" */
++static struct cpumask want_shared __initdata; /* cpus requested with "s" */
++
++static int __init parse_bportals(char *str)
++{
++      return parse_portals_bootarg(str, &want_shared, &want_unshared,
++                                   "bportals");
++}
++__setup("bportals=", parse_bportals);
++
++static int bman_offline_cpu(unsigned int cpu)
++{
++      struct bman_portal *p;
++      const struct bm_portal_config *pcfg;
++      p = (struct bman_portal *)affine_bportals[cpu];
++      if (p) {
++              pcfg = bman_get_bm_portal_config(p);
++              if (pcfg)
++                      irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(0));
++      }
++      return 0;
++}
++
++#ifdef CONFIG_HOTPLUG_CPU
++static int bman_online_cpu(unsigned int cpu)
++{
++      struct bman_portal *p;
++      const struct bm_portal_config *pcfg;
++      p = (struct bman_portal *)affine_bportals[cpu];
++      if (p) {
++              pcfg = bman_get_bm_portal_config(p);
++              if (pcfg)
++                      irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(cpu));
++      }
++      return 0;
++}
++#endif /* CONFIG_HOTPLUG_CPU */
++
++/* Initialise the Bman driver. The meat of this function deals with portals. The
++ * following describes the flow of portal-handling, the code "steps" refer to
++ * this description;
++ * 1. Portal configs are parsed from the device-tree into 'unused_pcfgs', with
++ *    ::cpu==-1. Regions and interrupts are mapped (but interrupts are not
++ *    bound).
++ * 2. The "want_shared" and "want_unshared" lists (as filled by the
++ *    "bportals=[...]" bootarg) are processed, allocating portals and assigning
++ *    them to cpus, placing them in the relevant list and setting ::cpu as
++ *    appropriate. If no "bportals" bootarg was present, the defaut is to try to
++ *    assign portals to all online cpus at the time of driver initialisation.
++ *    Any failure to allocate portals (when parsing the "want" lists or when
++ *    using default behaviour) will be silently tolerated (the "fixup" logic in
++ *    step 3 will determine what happens in this case).
++ * 3. Do fixups relative to cpu_online_mask(). If no portals are marked for
++ *    sharing and sharing is required (because not all cpus have been assigned
++ *    portals), then one portal will marked for sharing. Conversely if no
++ *    sharing is required, any portals marked for sharing will not be shared. It
++ *    may be that sharing occurs when it wasn't expected, if portal allocation
++ *    failed to honour all the requested assignments (including the default
++ *    assignments if no bootarg is present).
++ * 4. Unshared portals are initialised on their respective cpus.
++ * 5. Shared portals are initialised on their respective cpus.
++ * 6. Each remaining cpu is initialised to slave to one of the shared portals,
++ *    which are selected in a round-robin fashion.
++ * Any portal configs left unused are available for USDPAA allocation.
++ */
++__init int bman_init(void)
++{
++      struct cpumask slave_cpus;
++      struct cpumask unshared_cpus = *cpu_none_mask;
++      struct cpumask shared_cpus = *cpu_none_mask;
++      LIST_HEAD(unshared_pcfgs);
++      LIST_HEAD(shared_pcfgs);
++      struct device_node *dn;
++      struct bm_portal_config *pcfg;
++      struct bman_portal *p;
++      int cpu, ret;
++      struct cpumask offline_cpus;
++
++      /* Initialise the Bman (CCSR) device */
++      for_each_compatible_node(dn, NULL, "fsl,bman") {
++              if (!bman_init_ccsr(dn))
++                      pr_info("Bman err interrupt handler present\n");
++              else
++                      pr_err("Bman CCSR setup failed\n");
++      }
++      /* Initialise any declared buffer pools */
++      for_each_compatible_node(dn, NULL, "fsl,bpool") {
++              ret = fsl_bpool_init(dn);
++              if (ret)
++                      return ret;
++      }
++      /* Step 1. See comments at the beginning of the file. */
++      for_each_compatible_node(dn, NULL, "fsl,bman-portal") {
++              if (!of_device_is_available(dn))
++                      continue;
++              pcfg = parse_pcfg(dn);
++              if (pcfg)
++                      list_add_tail(&pcfg->list, &unused_pcfgs);
++      }
++      /* Step 2. */
++      for_each_possible_cpu(cpu) {
++              if (cpumask_test_cpu(cpu, &want_shared)) {
++                      pcfg = get_pcfg(&unused_pcfgs);
++                      if (!pcfg)
++                              break;
++                      pcfg->public_cfg.cpu = cpu;
++                      list_add_tail(&pcfg->list, &shared_pcfgs);
++                      cpumask_set_cpu(cpu, &shared_cpus);
++              }
++              if (cpumask_test_cpu(cpu, &want_unshared)) {
++                      if (cpumask_test_cpu(cpu, &shared_cpus))
++                              continue;
++                      pcfg = get_pcfg(&unused_pcfgs);
++                      if (!pcfg)
++                              break;
++                      pcfg->public_cfg.cpu = cpu;
++                      list_add_tail(&pcfg->list, &unshared_pcfgs);
++                      cpumask_set_cpu(cpu, &unshared_cpus);
++              }
++      }
++      if (list_empty(&shared_pcfgs) && list_empty(&unshared_pcfgs)) {
++              /* Default, give an unshared portal to each online cpu */
++              for_each_online_cpu(cpu) {
++                      pcfg = get_pcfg(&unused_pcfgs);
++                      if (!pcfg)
++                              break;
++                      pcfg->public_cfg.cpu = cpu;
++                      list_add_tail(&pcfg->list, &unshared_pcfgs);
++                      cpumask_set_cpu(cpu, &unshared_cpus);
++              }
++      }
++      /* Step 3. */
++      cpumask_andnot(&slave_cpus, cpu_possible_mask, &shared_cpus);
++      cpumask_andnot(&slave_cpus, &slave_cpus, &unshared_cpus);
++      if (cpumask_empty(&slave_cpus)) {
++              /* No sharing required */
++              if (!list_empty(&shared_pcfgs)) {
++                      /* Migrate "shared" to "unshared" */
++                      cpumask_or(&unshared_cpus, &unshared_cpus,
++                                 &shared_cpus);
++                      cpumask_clear(&shared_cpus);
++                      list_splice_tail(&shared_pcfgs, &unshared_pcfgs);
++                      INIT_LIST_HEAD(&shared_pcfgs);
++              }
++      } else {
++              /* Sharing required */
++              if (list_empty(&shared_pcfgs)) {
++                      /* Migrate one "unshared" to "shared" */
++                      pcfg = get_pcfg(&unshared_pcfgs);
++                      if (!pcfg) {
++                              pr_crit("No BMan portals available!\n");
++                              return 0;
++                      }
++                      cpumask_clear_cpu(pcfg->public_cfg.cpu, &unshared_cpus);
++                      cpumask_set_cpu(pcfg->public_cfg.cpu, &shared_cpus);
++                      list_add_tail(&pcfg->list, &shared_pcfgs);
++              }
++      }
++      /* Step 4. */
++      list_for_each_entry(pcfg, &unshared_pcfgs, list) {
++              pcfg->public_cfg.is_shared = 0;
++              p = init_pcfg(pcfg);
++              if (!p) {
++                      pr_crit("Unable to initialize bman portal\n");
++                      return 0;
++              }
++      }
++      /* Step 5. */
++      list_for_each_entry(pcfg, &shared_pcfgs, list) {
++              pcfg->public_cfg.is_shared = 1;
++              p = init_pcfg(pcfg);
++              if (p)
++                      shared_portals[num_shared_portals++] = p;
++      }
++      /* Step 6. */
++      if (!cpumask_empty(&slave_cpus))
++              for_each_cpu(cpu, &slave_cpus)
++                      init_slave(cpu);
++      pr_info("Bman portals initialised\n");
++      cpumask_andnot(&offline_cpus, cpu_possible_mask, cpu_online_mask);
++      for_each_cpu(cpu, &offline_cpus)
++              bman_offline_cpu(cpu);
++#ifdef CONFIG_HOTPLUG_CPU
++      ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
++                                      "soc/qbman_portal:online",
++                                      bman_online_cpu, bman_offline_cpu);
++      if (ret < 0) {
++              pr_err("bman: failed to register hotplug callbacks.\n");
++              return 0;
++      }
++#endif
++      return 0;
++}
++
++__init int bman_resource_init(void)
++{
++      struct device_node *dn;
++      int ret;
++
++      /* Initialise BPID allocation ranges */
++      for_each_compatible_node(dn, NULL, "fsl,bpid-range") {
++              ret = fsl_bpid_range_init(dn);
++              if (ret)
++                      return ret;
++      }
++      return 0;
++}
++
++#ifdef CONFIG_SUSPEND
++void suspend_unused_bportal(void)
++{
++      struct bm_portal_config *pcfg;
++
++      if (list_empty(&unused_pcfgs))
++              return;
++
++      list_for_each_entry(pcfg, &unused_pcfgs, list) {
++#ifdef CONFIG_PM_DEBUG
++              pr_info("Need to save bportal %d\n", pcfg->public_cfg.index);
++#endif
++              /* save isdr, disable all via isdr, clear isr */
++              pcfg->saved_isdr =
++                      __raw_readl(pcfg->addr_virt[DPA_PORTAL_CI] + 0xe08);
++              __raw_writel(0xffffffff, pcfg->addr_virt[DPA_PORTAL_CI] +
++                                      0xe08);
++              __raw_writel(0xffffffff, pcfg->addr_virt[DPA_PORTAL_CI] +
++                                      0xe00);
++      }
++      return;
++}
++
++void resume_unused_bportal(void)
++{
++      struct bm_portal_config *pcfg;
++
++      if (list_empty(&unused_pcfgs))
++              return;
++
++      list_for_each_entry(pcfg, &unused_pcfgs, list) {
++#ifdef CONFIG_PM_DEBUG
++              pr_info("Need to resume bportal %d\n", pcfg->public_cfg.index);
++#endif
++              /* restore isdr */
++              __raw_writel(pcfg->saved_isdr,
++                              pcfg->addr_virt[DPA_PORTAL_CI] + 0xe08);
++      }
++      return;
++}
++#endif
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/bman_high.c
+@@ -0,0 +1,1145 @@
++/* Copyright 2008-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "bman_low.h"
++
++/* Compilation constants */
++#define RCR_THRESH    2       /* reread h/w CI when running out of space */
++#define IRQNAME               "BMan portal %d"
++#define MAX_IRQNAME   16      /* big enough for "BMan portal %d" */
++
++struct bman_portal {
++      struct bm_portal p;
++      /* 2-element array. pools[0] is mask, pools[1] is snapshot. */
++      struct bman_depletion *pools;
++      int thresh_set;
++      unsigned long irq_sources;
++      u32 slowpoll;   /* only used when interrupts are off */
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      struct bman_pool *rcri_owned; /* only 1 release WAIT_SYNC at a time */
++#endif
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      raw_spinlock_t sharing_lock; /* only used if is_shared */
++      int is_shared;
++      struct bman_portal *sharing_redirect;
++#endif
++      /* When the cpu-affine portal is activated, this is non-NULL */
++      const struct bm_portal_config *config;
++      /* This is needed for power management */
++      struct platform_device *pdev;
++      /* 64-entry hash-table of pool objects that are tracking depletion
++       * entry/exit (ie. BMAN_POOL_FLAG_DEPLETION). This isn't fast-path, so
++       * we're not fussy about cache-misses and so forth - whereas the above
++       * members should all fit in one cacheline.
++       * BTW, with 64 entries in the hash table and 64 buffer pools to track,
++       * you'll never guess the hash-function ... */
++      struct bman_pool *cb[64];
++      char irqname[MAX_IRQNAME];
++      /* Track if the portal was alloced by the driver */
++      u8 alloced;
++      /* power management data */
++      u32 save_isdr;
++};
++
++/* For an explanation of the locking, redirection, or affine-portal logic,
++ * please consult the Qman driver for details. This is the same, only simpler
++ * (no fiddly Qman-specific bits.) */
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++#define PORTAL_IRQ_LOCK(p, irqflags) \
++      do { \
++              if ((p)->is_shared) \
++                      raw_spin_lock_irqsave(&(p)->sharing_lock, irqflags); \
++              else \
++                      local_irq_save(irqflags); \
++      } while (0)
++#define PORTAL_IRQ_UNLOCK(p, irqflags) \
++      do { \
++              if ((p)->is_shared) \
++                      raw_spin_unlock_irqrestore(&(p)->sharing_lock, \
++                                                 irqflags); \
++              else \
++                      local_irq_restore(irqflags); \
++      } while (0)
++#else
++#define PORTAL_IRQ_LOCK(p, irqflags) local_irq_save(irqflags)
++#define PORTAL_IRQ_UNLOCK(p, irqflags) local_irq_restore(irqflags)
++#endif
++
++static cpumask_t affine_mask;
++static DEFINE_SPINLOCK(affine_mask_lock);
++static DEFINE_PER_CPU(struct bman_portal, bman_affine_portal);
++static inline struct bman_portal *get_raw_affine_portal(void)
++{
++      return &get_cpu_var(bman_affine_portal);
++}
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++static inline struct bman_portal *get_affine_portal(void)
++{
++      struct bman_portal *p = get_raw_affine_portal();
++      if (p->sharing_redirect)
++              return p->sharing_redirect;
++      return p;
++}
++#else
++#define get_affine_portal() get_raw_affine_portal()
++#endif
++static inline void put_affine_portal(void)
++{
++      put_cpu_var(bman_affine_portal);
++}
++static inline struct bman_portal *get_poll_portal(void)
++{
++      return &get_cpu_var(bman_affine_portal);
++}
++#define put_poll_portal()
++
++/* GOTCHA: this object type refers to a pool, it isn't *the* pool. There may be
++ * more than one such object per Bman buffer pool, eg. if different users of the
++ * pool are operating via different portals. */
++struct bman_pool {
++      struct bman_pool_params params;
++      /* Used for hash-table admin when using depletion notifications. */
++      struct bman_portal *portal;
++      struct bman_pool *next;
++      /* stockpile state - NULL unless BMAN_POOL_FLAG_STOCKPILE is set */
++      struct bm_buffer *sp;
++      unsigned int sp_fill;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      atomic_t in_use;
++#endif
++};
++
++/* (De)Registration of depletion notification callbacks */
++static void depletion_link(struct bman_portal *portal, struct bman_pool *pool)
++{
++      __maybe_unused unsigned long irqflags;
++      pool->portal = portal;
++      PORTAL_IRQ_LOCK(portal, irqflags);
++      pool->next = portal->cb[pool->params.bpid];
++      portal->cb[pool->params.bpid] = pool;
++      if (!pool->next)
++              /* First object for that bpid on this portal, enable the BSCN
++               * mask bit. */
++              bm_isr_bscn_mask(&portal->p, pool->params.bpid, 1);
++      PORTAL_IRQ_UNLOCK(portal, irqflags);
++}
++static void depletion_unlink(struct bman_pool *pool)
++{
++      struct bman_pool *it, *last = NULL;
++      struct bman_pool **base = &pool->portal->cb[pool->params.bpid];
++      __maybe_unused unsigned long irqflags;
++      PORTAL_IRQ_LOCK(pool->portal, irqflags);
++      it = *base;     /* <-- gotcha, don't do this prior to the irq_save */
++      while (it != pool) {
++              last = it;
++              it = it->next;
++      }
++      if (!last)
++              *base = pool->next;
++      else
++              last->next = pool->next;
++      if (!last && !pool->next) {
++              /* Last object for that bpid on this portal, disable the BSCN
++               * mask bit. */
++              bm_isr_bscn_mask(&pool->portal->p, pool->params.bpid, 0);
++              /* And "forget" that we last saw this pool as depleted */
++              bman_depletion_unset(&pool->portal->pools[1],
++                                      pool->params.bpid);
++      }
++      PORTAL_IRQ_UNLOCK(pool->portal, irqflags);
++}
++
++/* In the case that the application's core loop calls qman_poll() and
++ * bman_poll(), we ought to balance how often we incur the overheads of the
++ * slow-path poll. We'll use two decrementer sources. The idle decrementer
++ * constant is used when the last slow-poll detected no work to do, and the busy
++ * decrementer constant when the last slow-poll had work to do. */
++#define SLOW_POLL_IDLE 1000
++#define SLOW_POLL_BUSY 10
++static u32 __poll_portal_slow(struct bman_portal *p, u32 is);
++
++/* Portal interrupt handler */
++static irqreturn_t portal_isr(__always_unused int irq, void *ptr)
++{
++      struct bman_portal *p = ptr;
++      u32 clear = p->irq_sources;
++      u32 is = bm_isr_status_read(&p->p) & p->irq_sources;
++      clear |= __poll_portal_slow(p, is);
++      bm_isr_status_clear(&p->p, clear);
++      return IRQ_HANDLED;
++}
++
++#ifdef CONFIG_SUSPEND
++static int _bman_portal_suspend_noirq(struct device *dev)
++{
++      struct bman_portal *p = (struct bman_portal *)dev->platform_data;
++#ifdef CONFIG_PM_DEBUG
++      struct platform_device *pdev = to_platform_device(dev);
++#endif
++      p->save_isdr = bm_isr_disable_read(&p->p);
++      bm_isr_disable_write(&p->p, 0xffffffff);
++      bm_isr_status_clear(&p->p, 0xffffffff);
++#ifdef CONFIG_PM_DEBUG
++      pr_info("Suspend for %s\n", pdev->name);
++#endif
++      return 0;
++}
++
++static int _bman_portal_resume_noirq(struct device *dev)
++{
++      struct bman_portal *p = (struct bman_portal *)dev->platform_data;
++
++      /* restore isdr */
++      bm_isr_disable_write(&p->p, p->save_isdr);
++      return 0;
++}
++#else
++#define _bman_portal_suspend_noirq NULL
++#define _bman_portal_resume_noirq NULL
++#endif
++
++struct dev_pm_domain bman_portal_device_pm_domain = {
++      .ops = {
++              USE_PLATFORM_PM_SLEEP_OPS
++              .suspend_noirq = _bman_portal_suspend_noirq,
++              .resume_noirq = _bman_portal_resume_noirq,
++      }
++};
++
++struct bman_portal *bman_create_portal(
++                                     struct bman_portal *portal,
++                                     const struct bm_portal_config *config)
++{
++      struct bm_portal *__p;
++      const struct bman_depletion *pools = &config->public_cfg.mask;
++      int ret;
++      u8 bpid = 0;
++      char buf[16];
++
++      if (!portal) {
++              portal = kmalloc(sizeof(*portal), GFP_KERNEL);
++              if (!portal)
++                      return portal;
++              portal->alloced = 1;
++      } else
++              portal->alloced = 0;
++
++      __p = &portal->p;
++
++      /* prep the low-level portal struct with the mapped addresses from the
++       * config, everything that follows depends on it and "config" is more
++       * for (de)reference... */
++      __p->addr.addr_ce = config->addr_virt[DPA_PORTAL_CE];
++      __p->addr.addr_ci = config->addr_virt[DPA_PORTAL_CI];
++      if (bm_rcr_init(__p, bm_rcr_pvb, bm_rcr_cce)) {
++              pr_err("Bman RCR initialisation failed\n");
++              goto fail_rcr;
++      }
++      if (bm_mc_init(__p)) {
++              pr_err("Bman MC initialisation failed\n");
++              goto fail_mc;
++      }
++      if (bm_isr_init(__p)) {
++              pr_err("Bman ISR initialisation failed\n");
++              goto fail_isr;
++      }
++      portal->pools = kmalloc(2 * sizeof(*pools), GFP_KERNEL);
++      if (!portal->pools)
++              goto fail_pools;
++      portal->pools[0] = *pools;
++      bman_depletion_init(portal->pools + 1);
++      while (bpid < bman_pool_max) {
++              /* Default to all BPIDs disabled, we enable as required at
++               * run-time. */
++              bm_isr_bscn_mask(__p, bpid, 0);
++              bpid++;
++      }
++      portal->slowpoll = 0;
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      portal->rcri_owned = NULL;
++#endif
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      raw_spin_lock_init(&portal->sharing_lock);
++      portal->is_shared = config->public_cfg.is_shared;
++      portal->sharing_redirect = NULL;
++#endif
++      sprintf(buf, "bportal-%u", config->public_cfg.index);
++      portal->pdev = platform_device_alloc(buf, -1);
++      if (!portal->pdev)
++              goto fail_devalloc;
++      portal->pdev->dev.pm_domain = &bman_portal_device_pm_domain;
++      portal->pdev->dev.platform_data = portal;
++      ret = platform_device_add(portal->pdev);
++      if (ret)
++              goto fail_devadd;
++      memset(&portal->cb, 0, sizeof(portal->cb));
++      /* Write-to-clear any stale interrupt status bits */
++      bm_isr_disable_write(__p, 0xffffffff);
++      portal->irq_sources = 0;
++      bm_isr_enable_write(__p, portal->irq_sources);
++      bm_isr_status_clear(__p, 0xffffffff);
++      snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, config->public_cfg.cpu);
++      if (request_irq(config->public_cfg.irq, portal_isr, 0, portal->irqname,
++                      portal)) {
++              pr_err("request_irq() failed\n");
++              goto fail_irq;
++      }
++      if ((config->public_cfg.cpu != -1) &&
++                      irq_can_set_affinity(config->public_cfg.irq) &&
++                      irq_set_affinity(config->public_cfg.irq,
++                              cpumask_of(config->public_cfg.cpu))) {
++              pr_err("irq_set_affinity() failed %s\n", portal->irqname);
++              goto fail_affinity;
++      }
++
++      /* Need RCR to be empty before continuing */
++      ret = bm_rcr_get_fill(__p);
++      if (ret) {
++              pr_err("Bman RCR unclean\n");
++              goto fail_rcr_empty;
++      }
++      /* Success */
++      portal->config = config;
++
++      bm_isr_disable_write(__p, 0);
++      bm_isr_uninhibit(__p);
++      return portal;
++fail_rcr_empty:
++fail_affinity:
++      free_irq(config->public_cfg.irq, portal);
++fail_irq:
++      platform_device_del(portal->pdev);
++fail_devadd:
++      platform_device_put(portal->pdev);
++fail_devalloc:
++      kfree(portal->pools);
++fail_pools:
++      bm_isr_finish(__p);
++fail_isr:
++      bm_mc_finish(__p);
++fail_mc:
++      bm_rcr_finish(__p);
++fail_rcr:
++      if (portal->alloced)
++              kfree(portal);
++      return NULL;
++}
++
++struct bman_portal *bman_create_affine_portal(
++                      const struct bm_portal_config *config)
++{
++      struct bman_portal *portal;
++
++      portal = &per_cpu(bman_affine_portal, config->public_cfg.cpu);
++      portal = bman_create_portal(portal, config);
++      if (portal) {
++              spin_lock(&affine_mask_lock);
++              cpumask_set_cpu(config->public_cfg.cpu, &affine_mask);
++              spin_unlock(&affine_mask_lock);
++      }
++      return portal;
++}
++
++
++struct bman_portal *bman_create_affine_slave(struct bman_portal *redirect,
++                                                              int cpu)
++{
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      struct bman_portal *p;
++      p = &per_cpu(bman_affine_portal, cpu);
++      BUG_ON(p->config);
++      BUG_ON(p->is_shared);
++      BUG_ON(!redirect->config->public_cfg.is_shared);
++      p->irq_sources = 0;
++      p->sharing_redirect = redirect;
++      return p;
++#else
++      BUG();
++      return NULL;
++#endif
++}
++
++void bman_destroy_portal(struct bman_portal *bm)
++{
++      const struct bm_portal_config *pcfg;
++      pcfg = bm->config;
++      bm_rcr_cce_update(&bm->p);
++      bm_rcr_cce_update(&bm->p);
++
++      free_irq(pcfg->public_cfg.irq, bm);
++
++      kfree(bm->pools);
++      bm_isr_finish(&bm->p);
++      bm_mc_finish(&bm->p);
++      bm_rcr_finish(&bm->p);
++      bm->config = NULL;
++      if (bm->alloced)
++              kfree(bm);
++}
++
++const struct bm_portal_config *bman_destroy_affine_portal(void)
++{
++      struct bman_portal *bm = get_raw_affine_portal();
++      const struct bm_portal_config *pcfg;
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      if (bm->sharing_redirect) {
++              bm->sharing_redirect = NULL;
++              put_affine_portal();
++              return NULL;
++      }
++      bm->is_shared = 0;
++#endif
++      pcfg = bm->config;
++      bman_destroy_portal(bm);
++      spin_lock(&affine_mask_lock);
++      cpumask_clear_cpu(pcfg->public_cfg.cpu, &affine_mask);
++      spin_unlock(&affine_mask_lock);
++      put_affine_portal();
++      return pcfg;
++}
++
++/* When release logic waits on available RCR space, we need a global waitqueue
++ * in the case of "affine" use (as the waits wake on different cpus which means
++ * different portals - so we can't wait on any per-portal waitqueue). */
++static DECLARE_WAIT_QUEUE_HEAD(affine_queue);
++
++static u32 __poll_portal_slow(struct bman_portal *p, u32 is)
++{
++      struct bman_depletion tmp;
++      u32 ret = is;
++
++      /* There is a gotcha to be aware of. If we do the query before clearing
++       * the status register, we may miss state changes that occur between the
++       * two. If we write to clear the status register before the query, the
++       * cache-enabled query command may overtake the status register write
++       * unless we use a heavyweight sync (which we don't want). Instead, we
++       * write-to-clear the status register then *read it back* before doing
++       * the query, hence the odd while loop with the 'is' accumulation. */
++      if (is & BM_PIRQ_BSCN) {
++              struct bm_mc_result *mcr;
++              __maybe_unused unsigned long irqflags;
++              unsigned int i, j;
++              u32 __is;
++              bm_isr_status_clear(&p->p, BM_PIRQ_BSCN);
++              while ((__is = bm_isr_status_read(&p->p)) & BM_PIRQ_BSCN) {
++                      is |= __is;
++                      bm_isr_status_clear(&p->p, BM_PIRQ_BSCN);
++              }
++              is &= ~BM_PIRQ_BSCN;
++              PORTAL_IRQ_LOCK(p, irqflags);
++              bm_mc_start(&p->p);
++              bm_mc_commit(&p->p, BM_MCC_VERB_CMD_QUERY);
++              while (!(mcr = bm_mc_result(&p->p)))
++                      cpu_relax();
++              tmp = mcr->query.ds.state;
++              tmp.__state[0] = be32_to_cpu(tmp.__state[0]);
++              tmp.__state[1] = be32_to_cpu(tmp.__state[1]);
++              PORTAL_IRQ_UNLOCK(p, irqflags);
++              for (i = 0; i < 2; i++) {
++                      int idx = i * 32;
++                      /* tmp is a mask of currently-depleted pools.
++                       * pools[0] is mask of those we care about.
++                       * pools[1] is our previous view (we only want to
++                       * be told about changes). */
++                      tmp.__state[i] &= p->pools[0].__state[i];
++                      if (tmp.__state[i] == p->pools[1].__state[i])
++                              /* fast-path, nothing to see, move along */
++                              continue;
++                      for (j = 0; j <= 31; j++, idx++) {
++                              struct bman_pool *pool = p->cb[idx];
++                              int b4 = bman_depletion_get(&p->pools[1], idx);
++                              int af = bman_depletion_get(&tmp, idx);
++                              if (b4 == af)
++                                      continue;
++                              while (pool) {
++                                      pool->params.cb(p, pool,
++                                              pool->params.cb_ctx, af);
++                                      pool = pool->next;
++                              }
++                      }
++              }
++              p->pools[1] = tmp;
++      }
++
++      if (is & BM_PIRQ_RCRI) {
++              __maybe_unused unsigned long irqflags;
++              PORTAL_IRQ_LOCK(p, irqflags);
++              bm_rcr_cce_update(&p->p);
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++              /* If waiting for sync, we only cancel the interrupt threshold
++               * when the ring utilisation hits zero. */
++              if (p->rcri_owned) {
++                      if (!bm_rcr_get_fill(&p->p)) {
++                              p->rcri_owned = NULL;
++                              bm_rcr_set_ithresh(&p->p, 0);
++                      }
++              } else
++#endif
++              bm_rcr_set_ithresh(&p->p, 0);
++              PORTAL_IRQ_UNLOCK(p, irqflags);
++              wake_up(&affine_queue);
++              bm_isr_status_clear(&p->p, BM_PIRQ_RCRI);
++              is &= ~BM_PIRQ_RCRI;
++      }
++
++      /* There should be no status register bits left undefined */
++      DPA_ASSERT(!is);
++      return ret;
++}
++
++const struct bman_portal_config *bman_get_portal_config(void)
++{
++      struct bman_portal *p = get_affine_portal();
++      const struct bman_portal_config *ret = &p->config->public_cfg;
++      put_affine_portal();
++      return ret;
++}
++EXPORT_SYMBOL(bman_get_portal_config);
++
++u32 bman_irqsource_get(void)
++{
++      struct bman_portal *p = get_raw_affine_portal();
++      u32 ret = p->irq_sources & BM_PIRQ_VISIBLE;
++      put_affine_portal();
++      return ret;
++}
++EXPORT_SYMBOL(bman_irqsource_get);
++
++int bman_p_irqsource_add(struct bman_portal *p, __maybe_unused u32 bits)
++{
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      if (p->sharing_redirect)
++              return -EINVAL;
++      else
++#endif
++      {
++              __maybe_unused unsigned long irqflags;
++              PORTAL_IRQ_LOCK(p, irqflags);
++              set_bits(bits & BM_PIRQ_VISIBLE, &p->irq_sources);
++              bm_isr_enable_write(&p->p, p->irq_sources);
++              PORTAL_IRQ_UNLOCK(p, irqflags);
++      }
++      return 0;
++}
++EXPORT_SYMBOL(bman_p_irqsource_add);
++
++int bman_irqsource_add(__maybe_unused u32 bits)
++{
++      struct bman_portal *p = get_raw_affine_portal();
++      int ret = 0;
++      ret = bman_p_irqsource_add(p, bits);
++      put_affine_portal();
++      return ret;
++}
++EXPORT_SYMBOL(bman_irqsource_add);
++
++int bman_irqsource_remove(u32 bits)
++{
++      struct bman_portal *p = get_raw_affine_portal();
++      __maybe_unused unsigned long irqflags;
++      u32 ier;
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      if (p->sharing_redirect) {
++              put_affine_portal();
++              return -EINVAL;
++      }
++#endif
++      /* Our interrupt handler only processes+clears status register bits that
++       * are in p->irq_sources. As we're trimming that mask, if one of them
++       * were to assert in the status register just before we remove it from
++       * the enable register, there would be an interrupt-storm when we
++       * release the IRQ lock. So we wait for the enable register update to
++       * take effect in h/w (by reading it back) and then clear all other bits
++       * in the status register. Ie. we clear them from ISR once it's certain
++       * IER won't allow them to reassert. */
++      PORTAL_IRQ_LOCK(p, irqflags);
++      bits &= BM_PIRQ_VISIBLE;
++      clear_bits(bits, &p->irq_sources);
++      bm_isr_enable_write(&p->p, p->irq_sources);
++      ier = bm_isr_enable_read(&p->p);
++      /* Using "~ier" (rather than "bits" or "~p->irq_sources") creates a
++       * data-dependency, ie. to protect against re-ordering. */
++      bm_isr_status_clear(&p->p, ~ier);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      return 0;
++}
++EXPORT_SYMBOL(bman_irqsource_remove);
++
++const cpumask_t *bman_affine_cpus(void)
++{
++      return &affine_mask;
++}
++EXPORT_SYMBOL(bman_affine_cpus);
++
++u32 bman_poll_slow(void)
++{
++      struct bman_portal *p = get_poll_portal();
++      u32 ret;
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      if (unlikely(p->sharing_redirect))
++              ret = (u32)-1;
++      else
++#endif
++      {
++              u32 is = bm_isr_status_read(&p->p) & ~p->irq_sources;
++              ret = __poll_portal_slow(p, is);
++              bm_isr_status_clear(&p->p, ret);
++      }
++      put_poll_portal();
++      return ret;
++}
++EXPORT_SYMBOL(bman_poll_slow);
++
++/* Legacy wrapper */
++void bman_poll(void)
++{
++      struct bman_portal *p = get_poll_portal();
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      if (unlikely(p->sharing_redirect))
++              goto done;
++#endif
++      if (!(p->slowpoll--)) {
++              u32 is = bm_isr_status_read(&p->p) & ~p->irq_sources;
++              u32 active = __poll_portal_slow(p, is);
++              if (active)
++                      p->slowpoll = SLOW_POLL_BUSY;
++              else
++                      p->slowpoll = SLOW_POLL_IDLE;
++      }
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++done:
++#endif
++      put_poll_portal();
++}
++EXPORT_SYMBOL(bman_poll);
++
++static const u32 zero_thresholds[4] = {0, 0, 0, 0};
++
++struct bman_pool *bman_new_pool(const struct bman_pool_params *params)
++{
++      struct bman_pool *pool = NULL;
++      u32 bpid;
++
++      if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID) {
++              int ret = bman_alloc_bpid(&bpid);
++              if (ret)
++                      return NULL;
++      } else {
++              if (params->bpid >= bman_pool_max)
++                      return NULL;
++              bpid = params->bpid;
++      }
++#ifdef CONFIG_FSL_BMAN_CONFIG
++      if (params->flags & BMAN_POOL_FLAG_THRESH) {
++              int ret = bm_pool_set(bpid, params->thresholds);
++              if (ret)
++                      goto err;
++      }
++#else
++      if (params->flags & BMAN_POOL_FLAG_THRESH)
++              goto err;
++#endif
++      pool = kmalloc(sizeof(*pool), GFP_KERNEL);
++      if (!pool)
++              goto err;
++      pool->sp = NULL;
++      pool->sp_fill = 0;
++      pool->params = *params;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      atomic_set(&pool->in_use, 1);
++#endif
++      if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID)
++              pool->params.bpid = bpid;
++      if (params->flags & BMAN_POOL_FLAG_STOCKPILE) {
++              pool->sp = kmalloc(sizeof(struct bm_buffer) * BMAN_STOCKPILE_SZ,
++                                      GFP_KERNEL);
++              if (!pool->sp)
++                      goto err;
++      }
++      if (pool->params.flags & BMAN_POOL_FLAG_DEPLETION) {
++              struct bman_portal *p = get_affine_portal();
++              if (!p->pools || !bman_depletion_get(&p->pools[0], bpid)) {
++                      pr_err("Depletion events disabled for bpid %d\n", bpid);
++                      goto err;
++              }
++              depletion_link(p, pool);
++              put_affine_portal();
++      }
++      return pool;
++err:
++#ifdef CONFIG_FSL_BMAN_CONFIG
++      if (params->flags & BMAN_POOL_FLAG_THRESH)
++              bm_pool_set(bpid, zero_thresholds);
++#endif
++      if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID)
++              bman_release_bpid(bpid);
++      if (pool) {
++              kfree(pool->sp);
++              kfree(pool);
++      }
++      return NULL;
++}
++EXPORT_SYMBOL(bman_new_pool);
++
++void bman_free_pool(struct bman_pool *pool)
++{
++#ifdef CONFIG_FSL_BMAN_CONFIG
++      if (pool->params.flags & BMAN_POOL_FLAG_THRESH)
++              bm_pool_set(pool->params.bpid, zero_thresholds);
++#endif
++      if (pool->params.flags & BMAN_POOL_FLAG_DEPLETION)
++              depletion_unlink(pool);
++      if (pool->params.flags & BMAN_POOL_FLAG_STOCKPILE) {
++              if (pool->sp_fill)
++                      pr_err("Stockpile not flushed, has %u in bpid %u.\n",
++                              pool->sp_fill, pool->params.bpid);
++              kfree(pool->sp);
++              pool->sp = NULL;
++              pool->params.flags ^= BMAN_POOL_FLAG_STOCKPILE;
++      }
++      if (pool->params.flags & BMAN_POOL_FLAG_DYNAMIC_BPID)
++              bman_release_bpid(pool->params.bpid);
++      kfree(pool);
++}
++EXPORT_SYMBOL(bman_free_pool);
++
++const struct bman_pool_params *bman_get_params(const struct bman_pool *pool)
++{
++      return &pool->params;
++}
++EXPORT_SYMBOL(bman_get_params);
++
++static noinline void update_rcr_ci(struct bman_portal *p, u8 avail)
++{
++      if (avail)
++              bm_rcr_cce_prefetch(&p->p);
++      else
++              bm_rcr_cce_update(&p->p);
++}
++
++int bman_rcr_is_empty(void)
++{
++      __maybe_unused unsigned long irqflags;
++      struct bman_portal *p = get_affine_portal();
++      u8 avail;
++
++      PORTAL_IRQ_LOCK(p, irqflags);
++      update_rcr_ci(p, 0);
++      avail = bm_rcr_get_fill(&p->p);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      return avail == 0;
++}
++EXPORT_SYMBOL(bman_rcr_is_empty);
++
++static inline struct bm_rcr_entry *try_rel_start(struct bman_portal **p,
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++                                      __maybe_unused struct bman_pool *pool,
++#endif
++                                      __maybe_unused unsigned long *irqflags,
++                                      __maybe_unused u32 flags)
++{
++      struct bm_rcr_entry *r;
++      u8 avail;
++
++      *p = get_affine_portal();
++      PORTAL_IRQ_LOCK(*p, (*irqflags));
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) &&
++                      (flags & BMAN_RELEASE_FLAG_WAIT_SYNC))) {
++              if ((*p)->rcri_owned) {
++                      PORTAL_IRQ_UNLOCK(*p, (*irqflags));
++                      put_affine_portal();
++                      return NULL;
++              }
++              (*p)->rcri_owned = pool;
++      }
++#endif
++      avail = bm_rcr_get_avail(&(*p)->p);
++      if (avail < 2)
++              update_rcr_ci(*p, avail);
++      r = bm_rcr_start(&(*p)->p);
++      if (unlikely(!r)) {
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++              if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) &&
++                              (flags & BMAN_RELEASE_FLAG_WAIT_SYNC)))
++                      (*p)->rcri_owned = NULL;
++#endif
++              PORTAL_IRQ_UNLOCK(*p, (*irqflags));
++              put_affine_portal();
++      }
++      return r;
++}
++
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++static noinline struct bm_rcr_entry *__wait_rel_start(struct bman_portal **p,
++                                      struct bman_pool *pool,
++                                      __maybe_unused unsigned long *irqflags,
++                                      u32 flags)
++{
++      struct bm_rcr_entry *rcr = try_rel_start(p, pool, irqflags, flags);
++      if (!rcr)
++              bm_rcr_set_ithresh(&(*p)->p, 1);
++      return rcr;
++}
++
++static noinline struct bm_rcr_entry *wait_rel_start(struct bman_portal **p,
++                                      struct bman_pool *pool,
++                                      __maybe_unused unsigned long *irqflags,
++                                      u32 flags)
++{
++      struct bm_rcr_entry *rcr;
++#ifndef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      pool = NULL;
++#endif
++      if (flags & BMAN_RELEASE_FLAG_WAIT_INT)
++              /* NB: return NULL if signal occurs before completion. Signal
++               * can occur during return. Caller must check for signal */
++              wait_event_interruptible(affine_queue,
++                      (rcr = __wait_rel_start(p, pool, irqflags, flags)));
++      else
++              wait_event(affine_queue,
++                      (rcr = __wait_rel_start(p, pool, irqflags, flags)));
++      return rcr;
++}
++#endif
++
++static inline int __bman_release(struct bman_pool *pool,
++                      const struct bm_buffer *bufs, u8 num, u32 flags)
++{
++      struct bman_portal *p;
++      struct bm_rcr_entry *r;
++      __maybe_unused unsigned long irqflags;
++      u32 i = num - 1;
++
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++      if (flags & BMAN_RELEASE_FLAG_WAIT)
++              r = wait_rel_start(&p, pool, &irqflags, flags);
++      else
++              r = try_rel_start(&p, pool, &irqflags, flags);
++#else
++      r = try_rel_start(&p, &irqflags, flags);
++#endif
++      if (!r)
++              return -EBUSY;
++      /* We can copy all but the first entry, as this can trigger badness
++       * with the valid-bit. Use the overlay to mask the verb byte. */
++      r->bufs[0].opaque =
++              ((cpu_to_be64((bufs[0].opaque |
++                            ((u64)pool->params.bpid<<48))
++                            & 0x00ffffffffffffff)));
++      if (i) {
++              for (i = 1; i < num; i++)
++                      r->bufs[i].opaque =
++                              cpu_to_be64(bufs[i].opaque);
++      }
++
++      bm_rcr_pvb_commit(&p->p, BM_RCR_VERB_CMD_BPID_SINGLE |
++                      (num & BM_RCR_VERB_BUFCOUNT_MASK));
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      /* if we wish to sync we need to set the threshold after h/w sees the
++       * new ring entry. As we're mixing cache-enabled and cache-inhibited
++       * accesses, this requires a heavy-weight sync. */
++      if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) &&
++                      (flags & BMAN_RELEASE_FLAG_WAIT_SYNC))) {
++              hwsync();
++              bm_rcr_set_ithresh(&p->p, 1);
++      }
++#endif
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) &&
++                      (flags & BMAN_RELEASE_FLAG_WAIT_SYNC))) {
++              if (flags & BMAN_RELEASE_FLAG_WAIT_INT)
++                      /* NB: return success even if signal occurs before
++                       * condition is true. pvb_commit guarantees success */
++                      wait_event_interruptible(affine_queue,
++                                      (p->rcri_owned != pool));
++              else
++                      wait_event(affine_queue, (p->rcri_owned != pool));
++      }
++#endif
++      return 0;
++}
++
++int bman_release(struct bman_pool *pool, const struct bm_buffer *bufs, u8 num,
++                      u32 flags)
++{
++      int ret;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      if (!num || (num > 8))
++              return -EINVAL;
++      if (pool->params.flags & BMAN_POOL_FLAG_NO_RELEASE)
++              return -EINVAL;
++#endif
++      /* Without stockpile, this API is a pass-through to the h/w operation */
++      if (!(pool->params.flags & BMAN_POOL_FLAG_STOCKPILE))
++              return __bman_release(pool, bufs, num, flags);
++#ifdef CONFIG_FSL_DPA_CHECKING
++      if (!atomic_dec_and_test(&pool->in_use)) {
++              pr_crit("Parallel attempts to enter bman_released() detected.");
++              panic("only one instance of bman_released/acquired allowed");
++      }
++#endif
++      /* Two movements of buffers are possible, and can occur in either order.
++       * A: moving buffers from the caller to the stockpile.
++       * B: moving buffers from the stockpile to hardware.
++       * Order 1: if there is already enough space in the stockpile for A
++       * then we want to do A first, and only do B if we trigger the
++       * stockpile-high threshold.
++       * Order 2: if there is not enough space in the stockpile for A, then
++       * we want to do B first, then do A if B had succeeded. However in this
++       * case B is dependent on how many buffers the user needs to release,
++       * not the stockpile-high threshold.
++       * Due to the different handling of B between the two cases, putting A
++       * and B in a while() loop would require quite obscure logic, so handle
++       * the different sequences explicitly. */
++      if ((pool->sp_fill + num) <= BMAN_STOCKPILE_SZ) {
++              /* Order 1: do A */
++              copy_words(pool->sp + pool->sp_fill, bufs,
++                         sizeof(struct bm_buffer) * num);
++              pool->sp_fill += num;
++              /* do B relative to STOCKPILE_HIGH */
++              while (pool->sp_fill >= BMAN_STOCKPILE_HIGH) {
++                      ret = __bman_release(pool,
++                                           pool->sp + (pool->sp_fill - 8), 8,
++                                           flags);
++                      if (ret >= 0)
++                              pool->sp_fill -= 8;
++              }
++      } else {
++              /* Order 2: do B relative to 'num' */
++              do {
++                      ret = __bman_release(pool,
++                                           pool->sp + (pool->sp_fill - 8), 8,
++                                           flags);
++                      if (ret < 0)
++                              /* failure */
++                              goto release_done;
++                      pool->sp_fill -= 8;
++              } while ((pool->sp_fill + num) > BMAN_STOCKPILE_SZ);
++              /* do A */
++              copy_words(pool->sp + pool->sp_fill, bufs,
++                         sizeof(struct bm_buffer) * num);
++              pool->sp_fill += num;
++      }
++      /* success */
++      ret = 0;
++release_done:
++#ifdef CONFIG_FSL_DPA_CHECKING
++      atomic_inc(&pool->in_use);
++#endif
++      return ret;
++}
++EXPORT_SYMBOL(bman_release);
++
++static inline int __bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs,
++                                      u8 num)
++{
++      struct bman_portal *p = get_affine_portal();
++      struct bm_mc_command *mcc;
++      struct bm_mc_result *mcr;
++      __maybe_unused unsigned long irqflags;
++      int ret, i;
++
++      PORTAL_IRQ_LOCK(p, irqflags);
++      mcc = bm_mc_start(&p->p);
++      mcc->acquire.bpid = pool->params.bpid;
++      bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE |
++                      (num & BM_MCC_VERB_ACQUIRE_BUFCOUNT));
++      while (!(mcr = bm_mc_result(&p->p)))
++              cpu_relax();
++      ret = mcr->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT;
++      if (bufs) {
++              for (i = 0; i < num; i++)
++                      bufs[i].opaque =
++                              be64_to_cpu(mcr->acquire.bufs[i].opaque);
++      }
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      if (ret != num)
++              ret = -ENOMEM;
++      return ret;
++}
++
++int bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num,
++                      u32 flags)
++{
++      int ret;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      if (!num || (num > 8))
++              return -EINVAL;
++      if (pool->params.flags & BMAN_POOL_FLAG_ONLY_RELEASE)
++              return -EINVAL;
++#endif
++      /* Without stockpile, this API is a pass-through to the h/w operation */
++      if (!(pool->params.flags & BMAN_POOL_FLAG_STOCKPILE))
++              return __bman_acquire(pool, bufs, num);
++#ifdef CONFIG_FSL_DPA_CHECKING
++      if (!atomic_dec_and_test(&pool->in_use)) {
++              pr_crit("Parallel attempts to enter bman_acquire() detected.");
++              panic("only one instance of bman_released/acquired allowed");
++      }
++#endif
++      /* Two movements of buffers are possible, and can occur in either order.
++       * A: moving buffers from stockpile to the caller.
++       * B: moving buffers from hardware to the stockpile.
++       * Order 1: if there are already enough buffers in the stockpile for A
++       * then we want to do A first, and only do B if we trigger the
++       * stockpile-low threshold.
++       * Order 2: if there are not enough buffers in the stockpile for A,
++       * then we want to do B first, then do A if B had succeeded. However in
++       * this case B is dependent on how many buffers the user needs, not the
++       * stockpile-low threshold.
++       * Due to the different handling of B between the two cases, putting A
++       * and B in a while() loop would require quite obscure logic, so handle
++       * the different sequences explicitly. */
++      if (num <= pool->sp_fill) {
++              /* Order 1: do A */
++              copy_words(bufs, pool->sp + (pool->sp_fill - num),
++                         sizeof(struct bm_buffer) * num);
++              pool->sp_fill -= num;
++              /* do B relative to STOCKPILE_LOW */
++              while (pool->sp_fill <= BMAN_STOCKPILE_LOW) {
++                      ret = __bman_acquire(pool, pool->sp + pool->sp_fill, 8);
++                      if (ret < 0)
++                              ret = __bman_acquire(pool,
++                                              pool->sp + pool->sp_fill, 1);
++                      if (ret < 0)
++                              break;
++                      pool->sp_fill += ret;
++              }
++      } else {
++              /* Order 2: do B relative to 'num' */
++              do {
++                      ret = __bman_acquire(pool, pool->sp + pool->sp_fill, 8);
++                      if (ret < 0)
++                              ret = __bman_acquire(pool,
++                                              pool->sp + pool->sp_fill, 1);
++                      if (ret < 0)
++                              /* failure */
++                              goto acquire_done;
++                      pool->sp_fill += ret;
++              } while (pool->sp_fill < num);
++              /* do A */
++              copy_words(bufs, pool->sp + (pool->sp_fill - num),
++                         sizeof(struct bm_buffer) * num);
++              pool->sp_fill -= num;
++      }
++      /* success */
++      ret = num;
++acquire_done:
++#ifdef CONFIG_FSL_DPA_CHECKING
++      atomic_inc(&pool->in_use);
++#endif
++      return ret;
++}
++EXPORT_SYMBOL(bman_acquire);
++
++int bman_flush_stockpile(struct bman_pool *pool, u32 flags)
++{
++      u8 num;
++      int ret;
++
++      while (pool->sp_fill) {
++              num = ((pool->sp_fill > 8) ? 8 : pool->sp_fill);
++              ret = __bman_release(pool, pool->sp + (pool->sp_fill - num),
++                                   num, flags);
++              if (ret)
++                      return ret;
++              pool->sp_fill -= num;
++      }
++      return 0;
++}
++EXPORT_SYMBOL(bman_flush_stockpile);
++
++int bman_query_pools(struct bm_pool_state *state)
++{
++      struct bman_portal *p = get_affine_portal();
++      struct bm_mc_result *mcr;
++      __maybe_unused unsigned long irqflags;
++
++      PORTAL_IRQ_LOCK(p, irqflags);
++      bm_mc_start(&p->p);
++      bm_mc_commit(&p->p, BM_MCC_VERB_CMD_QUERY);
++      while (!(mcr = bm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & BM_MCR_VERB_CMD_MASK) == BM_MCR_VERB_CMD_QUERY);
++      *state = mcr->query;
++      state->as.state.__state[0] = be32_to_cpu(state->as.state.__state[0]);
++      state->as.state.__state[1] = be32_to_cpu(state->as.state.__state[1]);
++      state->ds.state.__state[0] = be32_to_cpu(state->ds.state.__state[0]);
++      state->ds.state.__state[1] = be32_to_cpu(state->ds.state.__state[1]);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      return 0;
++}
++EXPORT_SYMBOL(bman_query_pools);
++
++#ifdef CONFIG_FSL_BMAN_CONFIG
++u32 bman_query_free_buffers(struct bman_pool *pool)
++{
++      return bm_pool_free_buffers(pool->params.bpid);
++}
++EXPORT_SYMBOL(bman_query_free_buffers);
++
++int bman_update_pool_thresholds(struct bman_pool *pool, const u32 *thresholds)
++{
++      u32 bpid;
++
++      bpid = bman_get_params(pool)->bpid;
++
++      return bm_pool_set(bpid, thresholds);
++}
++EXPORT_SYMBOL(bman_update_pool_thresholds);
++#endif
++
++int bman_shutdown_pool(u32 bpid)
++{
++      struct bman_portal *p = get_affine_portal();
++      __maybe_unused unsigned long irqflags;
++      int ret;
++
++      PORTAL_IRQ_LOCK(p, irqflags);
++      ret = bm_shutdown_pool(&p->p, bpid);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      return ret;
++}
++EXPORT_SYMBOL(bman_shutdown_pool);
++
++const struct bm_portal_config *bman_get_bm_portal_config(
++                                              struct bman_portal *portal)
++{
++      return portal->sharing_redirect ? NULL : portal->config;
++}
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/bman_low.h
+@@ -0,0 +1,565 @@
++/* Copyright 2008-2011 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "bman_private.h"
++
++/***************************/
++/* Portal register assists */
++/***************************/
++
++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
++
++/* Cache-inhibited register offsets */
++#define BM_REG_RCR_PI_CINH    0x0000
++#define BM_REG_RCR_CI_CINH    0x0004
++#define BM_REG_RCR_ITR                0x0008
++#define BM_REG_CFG            0x0100
++#define BM_REG_SCN(n)         (0x0200 + ((n) << 2))
++#define BM_REG_ISR            0x0e00
++#define BM_REG_IIR              0x0e0c
++
++/* Cache-enabled register offsets */
++#define BM_CL_CR              0x0000
++#define BM_CL_RR0             0x0100
++#define BM_CL_RR1             0x0140
++#define BM_CL_RCR             0x1000
++#define BM_CL_RCR_PI_CENA     0x3000
++#define BM_CL_RCR_CI_CENA     0x3100
++
++#endif
++
++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++
++/* Cache-inhibited register offsets */
++#define BM_REG_RCR_PI_CINH    0x3000
++#define BM_REG_RCR_CI_CINH    0x3100
++#define BM_REG_RCR_ITR                0x3200
++#define BM_REG_CFG            0x3300
++#define BM_REG_SCN(n)         (0x3400 + ((n) << 6))
++#define BM_REG_ISR            0x3e00
++#define BM_REG_IIR              0x3ec0
++
++/* Cache-enabled register offsets */
++#define BM_CL_CR              0x0000
++#define BM_CL_RR0             0x0100
++#define BM_CL_RR1             0x0140
++#define BM_CL_RCR             0x1000
++#define BM_CL_RCR_PI_CENA     0x3000
++#define BM_CL_RCR_CI_CENA     0x3100
++
++#endif
++
++/* BTW, the drivers (and h/w programming model) already obtain the required
++ * synchronisation for portal accesses via lwsync(), hwsync(), and
++ * data-dependencies. Use of barrier()s or other order-preserving primitives
++ * simply degrade performance. Hence the use of the __raw_*() interfaces, which
++ * simply ensure that the compiler treats the portal registers as volatile (ie.
++ * non-coherent). */
++
++/* Cache-inhibited register access. */
++#define __bm_in(bm, o)                be32_to_cpu(__raw_readl((bm)->addr_ci + (o)))
++#define __bm_out(bm, o, val)    __raw_writel(cpu_to_be32(val), \
++                                           (bm)->addr_ci + (o));
++#define bm_in(reg)            __bm_in(&portal->addr, BM_REG_##reg)
++#define bm_out(reg, val)      __bm_out(&portal->addr, BM_REG_##reg, val)
++
++/* Cache-enabled (index) register access */
++#define __bm_cl_touch_ro(bm, o) dcbt_ro((bm)->addr_ce + (o))
++#define __bm_cl_touch_rw(bm, o) dcbt_rw((bm)->addr_ce + (o))
++#define __bm_cl_in(bm, o)     be32_to_cpu(__raw_readl((bm)->addr_ce + (o)))
++#define __bm_cl_out(bm, o, val) \
++      do { \
++              u32 *__tmpclout = (bm)->addr_ce + (o); \
++              __raw_writel(cpu_to_be32(val), __tmpclout); \
++              dcbf(__tmpclout); \
++      } while (0)
++#define __bm_cl_invalidate(bm, o) dcbi((bm)->addr_ce + (o))
++#define bm_cl_touch_ro(reg) __bm_cl_touch_ro(&portal->addr, BM_CL_##reg##_CENA)
++#define bm_cl_touch_rw(reg) __bm_cl_touch_rw(&portal->addr, BM_CL_##reg##_CENA)
++#define bm_cl_in(reg)     __bm_cl_in(&portal->addr, BM_CL_##reg##_CENA)
++#define bm_cl_out(reg, val) __bm_cl_out(&portal->addr, BM_CL_##reg##_CENA, val)
++#define bm_cl_invalidate(reg)\
++      __bm_cl_invalidate(&portal->addr, BM_CL_##reg##_CENA)
++
++/* Cyclic helper for rings. FIXME: once we are able to do fine-grain perf
++ * analysis, look at using the "extra" bit in the ring index registers to avoid
++ * cyclic issues. */
++static inline u8 bm_cyc_diff(u8 ringsize, u8 first, u8 last)
++{
++      /* 'first' is included, 'last' is excluded */
++      if (first <= last)
++              return last - first;
++      return ringsize + last - first;
++}
++
++/* Portal modes.
++ *   Enum types;
++ *     pmode == production mode
++ *     cmode == consumption mode,
++ *   Enum values use 3 letter codes. First letter matches the portal mode,
++ *   remaining two letters indicate;
++ *     ci == cache-inhibited portal register
++ *     ce == cache-enabled portal register
++ *     vb == in-band valid-bit (cache-enabled)
++ */
++enum bm_rcr_pmode {           /* matches BCSP_CFG::RPM */
++      bm_rcr_pci = 0,         /* PI index, cache-inhibited */
++      bm_rcr_pce = 1,         /* PI index, cache-enabled */
++      bm_rcr_pvb = 2          /* valid-bit */
++};
++enum bm_rcr_cmode {           /* s/w-only */
++      bm_rcr_cci,             /* CI index, cache-inhibited */
++      bm_rcr_cce              /* CI index, cache-enabled */
++};
++
++
++/* ------------------------- */
++/* --- Portal structures --- */
++
++#define BM_RCR_SIZE           8
++
++struct bm_rcr {
++      struct bm_rcr_entry *ring, *cursor;
++      u8 ci, available, ithresh, vbit;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      u32 busy;
++      enum bm_rcr_pmode pmode;
++      enum bm_rcr_cmode cmode;
++#endif
++};
++
++struct bm_mc {
++      struct bm_mc_command *cr;
++      struct bm_mc_result *rr;
++      u8 rridx, vbit;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      enum {
++              /* Can only be _mc_start()ed */
++              mc_idle,
++              /* Can only be _mc_commit()ed or _mc_abort()ed */
++              mc_user,
++              /* Can only be _mc_retry()ed */
++              mc_hw
++      } state;
++#endif
++};
++
++struct bm_addr {
++      void __iomem *addr_ce;  /* cache-enabled */
++      void __iomem *addr_ci;  /* cache-inhibited */
++};
++
++struct bm_portal {
++      struct bm_addr addr;
++      struct bm_rcr rcr;
++      struct bm_mc mc;
++      struct bm_portal_config config;
++} ____cacheline_aligned;
++
++
++/* --------------- */
++/* --- RCR API --- */
++
++/* Bit-wise logic to wrap a ring pointer by clearing the "carry bit" */
++#define RCR_CARRYCLEAR(p) \
++      (void *)((unsigned long)(p) & (~(unsigned long)(BM_RCR_SIZE << 6)))
++
++/* Bit-wise logic to convert a ring pointer to a ring index */
++static inline u8 RCR_PTR2IDX(struct bm_rcr_entry *e)
++{
++      return ((uintptr_t)e >> 6) & (BM_RCR_SIZE - 1);
++}
++
++/* Increment the 'cursor' ring pointer, taking 'vbit' into account */
++static inline void RCR_INC(struct bm_rcr *rcr)
++{
++      /* NB: this is odd-looking, but experiments show that it generates
++       * fast code with essentially no branching overheads. We increment to
++       * the next RCR pointer and handle overflow and 'vbit'. */
++      struct bm_rcr_entry *partial = rcr->cursor + 1;
++      rcr->cursor = RCR_CARRYCLEAR(partial);
++      if (partial != rcr->cursor)
++              rcr->vbit ^= BM_RCR_VERB_VBIT;
++}
++
++static inline int bm_rcr_init(struct bm_portal *portal, enum bm_rcr_pmode pmode,
++              __maybe_unused enum bm_rcr_cmode cmode)
++{
++      /* This use of 'register', as well as all other occurrences, is because
++       * it has been observed to generate much faster code with gcc than is
++       * otherwise the case. */
++      register struct bm_rcr *rcr = &portal->rcr;
++      u32 cfg;
++      u8 pi;
++
++      rcr->ring = portal->addr.addr_ce + BM_CL_RCR;
++      rcr->ci = bm_in(RCR_CI_CINH) & (BM_RCR_SIZE - 1);
++
++      pi = bm_in(RCR_PI_CINH) & (BM_RCR_SIZE - 1);
++      rcr->cursor = rcr->ring + pi;
++      rcr->vbit = (bm_in(RCR_PI_CINH) & BM_RCR_SIZE) ?  BM_RCR_VERB_VBIT : 0;
++      rcr->available = BM_RCR_SIZE - 1
++              - bm_cyc_diff(BM_RCR_SIZE, rcr->ci, pi);
++      rcr->ithresh = bm_in(RCR_ITR);
++#ifdef CONFIG_FSL_DPA_CHECKING
++      rcr->busy = 0;
++      rcr->pmode = pmode;
++      rcr->cmode = cmode;
++#endif
++      cfg = (bm_in(CFG) & 0xffffffe0) | (pmode & 0x3); /* BCSP_CFG::RPM */
++      bm_out(CFG, cfg);
++      return 0;
++}
++
++static inline void bm_rcr_finish(struct bm_portal *portal)
++{
++      register struct bm_rcr *rcr = &portal->rcr;
++      u8 pi = bm_in(RCR_PI_CINH) & (BM_RCR_SIZE - 1);
++      u8 ci = bm_in(RCR_CI_CINH) & (BM_RCR_SIZE - 1);
++      DPA_ASSERT(!rcr->busy);
++      if (pi != RCR_PTR2IDX(rcr->cursor))
++              pr_crit("losing uncommited RCR entries\n");
++      if (ci != rcr->ci)
++              pr_crit("missing existing RCR completions\n");
++      if (rcr->ci != RCR_PTR2IDX(rcr->cursor))
++              pr_crit("RCR destroyed unquiesced\n");
++}
++
++static inline struct bm_rcr_entry *bm_rcr_start(struct bm_portal *portal)
++{
++      register struct bm_rcr *rcr = &portal->rcr;
++      DPA_ASSERT(!rcr->busy);
++      if (!rcr->available)
++              return NULL;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      rcr->busy = 1;
++#endif
++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
++      dcbz_64(rcr->cursor);
++#endif
++      return rcr->cursor;
++}
++
++static inline void bm_rcr_abort(struct bm_portal *portal)
++{
++      __maybe_unused register struct bm_rcr *rcr = &portal->rcr;
++      DPA_ASSERT(rcr->busy);
++#ifdef CONFIG_FSL_DPA_CHECKING
++      rcr->busy = 0;
++#endif
++}
++
++static inline struct bm_rcr_entry *bm_rcr_pend_and_next(
++                                      struct bm_portal *portal, u8 myverb)
++{
++      register struct bm_rcr *rcr = &portal->rcr;
++      DPA_ASSERT(rcr->busy);
++      DPA_ASSERT(rcr->pmode != bm_rcr_pvb);
++      if (rcr->available == 1)
++              return NULL;
++      rcr->cursor->__dont_write_directly__verb = myverb | rcr->vbit;
++      dcbf_64(rcr->cursor);
++      RCR_INC(rcr);
++      rcr->available--;
++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
++      dcbz_64(rcr->cursor);
++#endif
++      return rcr->cursor;
++}
++
++static inline void bm_rcr_pci_commit(struct bm_portal *portal, u8 myverb)
++{
++      register struct bm_rcr *rcr = &portal->rcr;
++      DPA_ASSERT(rcr->busy);
++      DPA_ASSERT(rcr->pmode == bm_rcr_pci);
++      rcr->cursor->__dont_write_directly__verb = myverb | rcr->vbit;
++      RCR_INC(rcr);
++      rcr->available--;
++      hwsync();
++      bm_out(RCR_PI_CINH, RCR_PTR2IDX(rcr->cursor));
++#ifdef CONFIG_FSL_DPA_CHECKING
++      rcr->busy = 0;
++#endif
++}
++
++static inline void bm_rcr_pce_prefetch(struct bm_portal *portal)
++{
++      __maybe_unused register struct bm_rcr *rcr = &portal->rcr;
++      DPA_ASSERT(rcr->pmode == bm_rcr_pce);
++      bm_cl_invalidate(RCR_PI);
++      bm_cl_touch_rw(RCR_PI);
++}
++
++static inline void bm_rcr_pce_commit(struct bm_portal *portal, u8 myverb)
++{
++      register struct bm_rcr *rcr = &portal->rcr;
++      DPA_ASSERT(rcr->busy);
++      DPA_ASSERT(rcr->pmode == bm_rcr_pce);
++      rcr->cursor->__dont_write_directly__verb = myverb | rcr->vbit;
++      RCR_INC(rcr);
++      rcr->available--;
++      lwsync();
++      bm_cl_out(RCR_PI, RCR_PTR2IDX(rcr->cursor));
++#ifdef CONFIG_FSL_DPA_CHECKING
++      rcr->busy = 0;
++#endif
++}
++
++static inline void bm_rcr_pvb_commit(struct bm_portal *portal, u8 myverb)
++{
++      register struct bm_rcr *rcr = &portal->rcr;
++      struct bm_rcr_entry *rcursor;
++      DPA_ASSERT(rcr->busy);
++      DPA_ASSERT(rcr->pmode == bm_rcr_pvb);
++      lwsync();
++      rcursor = rcr->cursor;
++      rcursor->__dont_write_directly__verb = myverb | rcr->vbit;
++      dcbf_64(rcursor);
++      RCR_INC(rcr);
++      rcr->available--;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      rcr->busy = 0;
++#endif
++}
++
++static inline u8 bm_rcr_cci_update(struct bm_portal *portal)
++{
++      register struct bm_rcr *rcr = &portal->rcr;
++      u8 diff, old_ci = rcr->ci;
++      DPA_ASSERT(rcr->cmode == bm_rcr_cci);
++      rcr->ci = bm_in(RCR_CI_CINH) & (BM_RCR_SIZE - 1);
++      diff = bm_cyc_diff(BM_RCR_SIZE, old_ci, rcr->ci);
++      rcr->available += diff;
++      return diff;
++}
++
++static inline void bm_rcr_cce_prefetch(struct bm_portal *portal)
++{
++      __maybe_unused register struct bm_rcr *rcr = &portal->rcr;
++      DPA_ASSERT(rcr->cmode == bm_rcr_cce);
++      bm_cl_touch_ro(RCR_CI);
++}
++
++static inline u8 bm_rcr_cce_update(struct bm_portal *portal)
++{
++      register struct bm_rcr *rcr = &portal->rcr;
++      u8 diff, old_ci = rcr->ci;
++      DPA_ASSERT(rcr->cmode == bm_rcr_cce);
++      rcr->ci = bm_cl_in(RCR_CI) & (BM_RCR_SIZE - 1);
++      bm_cl_invalidate(RCR_CI);
++      diff = bm_cyc_diff(BM_RCR_SIZE, old_ci, rcr->ci);
++      rcr->available += diff;
++      return diff;
++}
++
++static inline u8 bm_rcr_get_ithresh(struct bm_portal *portal)
++{
++      register struct bm_rcr *rcr = &portal->rcr;
++      return rcr->ithresh;
++}
++
++static inline void bm_rcr_set_ithresh(struct bm_portal *portal, u8 ithresh)
++{
++      register struct bm_rcr *rcr = &portal->rcr;
++      rcr->ithresh = ithresh;
++      bm_out(RCR_ITR, ithresh);
++}
++
++static inline u8 bm_rcr_get_avail(struct bm_portal *portal)
++{
++      register struct bm_rcr *rcr = &portal->rcr;
++      return rcr->available;
++}
++
++static inline u8 bm_rcr_get_fill(struct bm_portal *portal)
++{
++      register struct bm_rcr *rcr = &portal->rcr;
++      return BM_RCR_SIZE - 1 - rcr->available;
++}
++
++
++/* ------------------------------ */
++/* --- Management command API --- */
++
++static inline int bm_mc_init(struct bm_portal *portal)
++{
++      register struct bm_mc *mc = &portal->mc;
++      mc->cr = portal->addr.addr_ce + BM_CL_CR;
++      mc->rr = portal->addr.addr_ce + BM_CL_RR0;
++      mc->rridx = (__raw_readb(&mc->cr->__dont_write_directly__verb) &
++                      BM_MCC_VERB_VBIT) ?  0 : 1;
++      mc->vbit = mc->rridx ? BM_MCC_VERB_VBIT : 0;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      mc->state = mc_idle;
++#endif
++      return 0;
++}
++
++static inline void bm_mc_finish(struct bm_portal *portal)
++{
++      __maybe_unused register struct bm_mc *mc = &portal->mc;
++      DPA_ASSERT(mc->state == mc_idle);
++#ifdef CONFIG_FSL_DPA_CHECKING
++      if (mc->state != mc_idle)
++              pr_crit("Losing incomplete MC command\n");
++#endif
++}
++
++static inline struct bm_mc_command *bm_mc_start(struct bm_portal *portal)
++{
++      register struct bm_mc *mc = &portal->mc;
++      DPA_ASSERT(mc->state == mc_idle);
++#ifdef CONFIG_FSL_DPA_CHECKING
++      mc->state = mc_user;
++#endif
++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
++      dcbz_64(mc->cr);
++#endif
++      return mc->cr;
++}
++
++static inline void bm_mc_abort(struct bm_portal *portal)
++{
++      __maybe_unused register struct bm_mc *mc = &portal->mc;
++      DPA_ASSERT(mc->state == mc_user);
++#ifdef CONFIG_FSL_DPA_CHECKING
++      mc->state = mc_idle;
++#endif
++}
++
++static inline void bm_mc_commit(struct bm_portal *portal, u8 myverb)
++{
++      register struct bm_mc *mc = &portal->mc;
++      struct bm_mc_result *rr = mc->rr + mc->rridx;
++      DPA_ASSERT(mc->state == mc_user);
++      lwsync();
++      mc->cr->__dont_write_directly__verb = myverb | mc->vbit;
++      dcbf(mc->cr);
++      dcbit_ro(rr);
++#ifdef CONFIG_FSL_DPA_CHECKING
++      mc->state = mc_hw;
++#endif
++}
++
++static inline struct bm_mc_result *bm_mc_result(struct bm_portal *portal)
++{
++      register struct bm_mc *mc = &portal->mc;
++      struct bm_mc_result *rr = mc->rr + mc->rridx;
++      DPA_ASSERT(mc->state == mc_hw);
++      /* The inactive response register's verb byte always returns zero until
++       * its command is submitted and completed. This includes the valid-bit,
++       * in case you were wondering... */
++      if (!__raw_readb(&rr->verb)) {
++              dcbit_ro(rr);
++              return NULL;
++      }
++      mc->rridx ^= 1;
++      mc->vbit ^= BM_MCC_VERB_VBIT;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      mc->state = mc_idle;
++#endif
++      return rr;
++}
++
++
++/* ------------------------------------- */
++/* --- Portal interrupt register API --- */
++
++static inline int bm_isr_init(__always_unused struct bm_portal *portal)
++{
++      return 0;
++}
++
++static inline void bm_isr_finish(__always_unused struct bm_portal *portal)
++{
++}
++
++#define SCN_REG(bpid) BM_REG_SCN((bpid) / 32)
++#define SCN_BIT(bpid) (0x80000000 >> (bpid & 31))
++static inline void bm_isr_bscn_mask(struct bm_portal *portal, u8 bpid,
++                                      int enable)
++{
++      u32 val;
++      DPA_ASSERT(bpid < bman_pool_max);
++      /* REG_SCN for bpid=0..31, REG_SCN+4 for bpid=32..63 */
++      val = __bm_in(&portal->addr, SCN_REG(bpid));
++      if (enable)
++              val |= SCN_BIT(bpid);
++      else
++              val &= ~SCN_BIT(bpid);
++      __bm_out(&portal->addr, SCN_REG(bpid), val);
++}
++
++static inline u32 __bm_isr_read(struct bm_portal *portal, enum bm_isr_reg n)
++{
++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++      return __bm_in(&portal->addr, BM_REG_ISR + (n << 6));
++#else
++      return __bm_in(&portal->addr, BM_REG_ISR + (n << 2));
++#endif
++}
++
++static inline void __bm_isr_write(struct bm_portal *portal, enum bm_isr_reg n,
++                                      u32 val)
++{
++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++      __bm_out(&portal->addr, BM_REG_ISR + (n << 6), val);
++#else
++      __bm_out(&portal->addr, BM_REG_ISR + (n << 2), val);
++#endif
++}
++
++/* Buffer Pool Cleanup */
++static inline int bm_shutdown_pool(struct bm_portal *p, u32 bpid)
++{
++      struct bm_mc_command *bm_cmd;
++      struct bm_mc_result *bm_res;
++
++      int aq_count = 0;
++      bool stop = false;
++      while (!stop) {
++              /* Acquire buffers until empty */
++              bm_cmd = bm_mc_start(p);
++              bm_cmd->acquire.bpid = bpid;
++              bm_mc_commit(p, BM_MCC_VERB_CMD_ACQUIRE |  1);
++              while (!(bm_res = bm_mc_result(p)))
++                      cpu_relax();
++              if (!(bm_res->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT)) {
++                      /* Pool is empty */
++                      /* TBD : Should we do a few extra iterations in
++                         case some other some blocks keep buffers 'on deck',
++                         which may also be problematic */
++                      stop = true;
++              } else
++                      ++aq_count;
++      }
++      return 0;
++}
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/bman_private.h
+@@ -0,0 +1,166 @@
++/* Copyright 2008-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "dpa_sys.h"
++#include <linux/fsl_bman.h>
++
++/* Revision info (for errata and feature handling) */
++#define BMAN_REV10 0x0100
++#define BMAN_REV20 0x0200
++#define BMAN_REV21 0x0201
++#define QBMAN_ANY_PORTAL_IDX 0xffffffff
++extern u16 bman_ip_rev; /* 0 if uninitialised, otherwise QMAN_REVx */
++
++/*
++ * Global variables of the max portal/pool number this bman version supported
++ */
++extern u16 bman_pool_max;
++
++/* used by CCSR and portal interrupt code */
++enum bm_isr_reg {
++      bm_isr_status = 0,
++      bm_isr_enable = 1,
++      bm_isr_disable = 2,
++      bm_isr_inhibit = 3
++};
++
++struct bm_portal_config {
++      /* Corenet portal addresses;
++       * [0]==cache-enabled, [1]==cache-inhibited. */
++      __iomem void *addr_virt[2];
++      struct resource addr_phys[2];
++      /* Allow these to be joined in lists */
++      struct list_head list;
++      /* User-visible portal configuration settings */
++      struct bman_portal_config public_cfg;
++      /* power management saved data */
++      u32 saved_isdr;
++};
++
++#ifdef CONFIG_FSL_BMAN_CONFIG
++/* Hooks from bman_driver.c to bman_config.c */
++int bman_init_ccsr(struct device_node *node);
++#endif
++
++/* Hooks from bman_driver.c in to bman_high.c */
++struct bman_portal *bman_create_portal(
++                                     struct bman_portal *portal,
++                                     const struct bm_portal_config *config);
++struct bman_portal *bman_create_affine_portal(
++                      const struct bm_portal_config *config);
++struct bman_portal *bman_create_affine_slave(struct bman_portal *redirect,
++                                                              int cpu);
++void bman_destroy_portal(struct bman_portal *bm);
++
++const struct bm_portal_config *bman_destroy_affine_portal(void);
++
++/* Hooks from fsl_usdpaa.c to bman_driver.c */
++struct bm_portal_config *bm_get_unused_portal(void);
++struct bm_portal_config *bm_get_unused_portal_idx(uint32_t idx);
++void bm_put_unused_portal(struct bm_portal_config *pcfg);
++void bm_set_liodns(struct bm_portal_config *pcfg);
++
++/* Pool logic in the portal driver, during initialisation, needs to know if
++ * there's access to CCSR or not (if not, it'll cripple the pool allocator). */
++#ifdef CONFIG_FSL_BMAN_CONFIG
++int bman_have_ccsr(void);
++#else
++#define bman_have_ccsr() 0
++#endif
++
++/* Stockpile build constants. The _LOW value: when bman_acquire() is called and
++ * the stockpile fill-level is <= _LOW, an acquire is attempted from h/w but it
++ * might fail (if the buffer pool is depleted). So this value provides some
++ * "stagger" in that the bman_acquire() function will only fail if lots of bufs
++ * are requested at once or if h/w has been tested a couple of times without
++ * luck. The _HIGH value: when bman_release() is called and the stockpile
++ * fill-level is >= _HIGH, a release is attempted to h/w but it might fail (if
++ * the release ring is full). So this value provides some "stagger" so that
++ * ring-access is retried a couple of times prior to the API returning a
++ * failure. The following *must* be true;
++ *   BMAN_STOCKPILE_HIGH-BMAN_STOCKPILE_LOW > 8
++ *     (to avoid thrashing)
++ *   BMAN_STOCKPILE_SZ >= 16
++ *     (as the release logic expects to either send 8 buffers to hw prior to
++ *     adding the given buffers to the stockpile or add the buffers to the
++ *     stockpile before sending 8 to hw, as the API must be an all-or-nothing
++ *     success/fail.)
++ */
++#define BMAN_STOCKPILE_SZ   16u /* number of bufs in per-pool cache */
++#define BMAN_STOCKPILE_LOW  2u  /* when fill is <= this, acquire from hw */
++#define BMAN_STOCKPILE_HIGH 14u /* when fill is >= this, release to hw */
++
++/*************************************************/
++/*   BMan s/w corenet portal, low-level i/face   */
++/*************************************************/
++
++/* Used by all portal interrupt registers except 'inhibit'
++ * This mask contains all the "irqsource" bits visible to API users
++ */
++#define BM_PIRQ_VISIBLE       (BM_PIRQ_RCRI | BM_PIRQ_BSCN)
++
++/* These are bm_<reg>_<verb>(). So for example, bm_disable_write() means "write
++ * the disable register" rather than "disable the ability to write". */
++#define bm_isr_status_read(bm)                __bm_isr_read(bm, bm_isr_status)
++#define bm_isr_status_clear(bm, m)    __bm_isr_write(bm, bm_isr_status, m)
++#define bm_isr_enable_read(bm)                __bm_isr_read(bm, bm_isr_enable)
++#define bm_isr_enable_write(bm, v)    __bm_isr_write(bm, bm_isr_enable, v)
++#define bm_isr_disable_read(bm)               __bm_isr_read(bm, bm_isr_disable)
++#define bm_isr_disable_write(bm, v)   __bm_isr_write(bm, bm_isr_disable, v)
++#define bm_isr_inhibit(bm)            __bm_isr_write(bm, bm_isr_inhibit, 1)
++#define bm_isr_uninhibit(bm)          __bm_isr_write(bm, bm_isr_inhibit, 0)
++
++#ifdef CONFIG_FSL_BMAN_CONFIG
++/* Set depletion thresholds associated with a buffer pool. Requires that the
++ * operating system have access to Bman CCSR (ie. compiled in support and
++ * run-time access courtesy of the device-tree). */
++int bm_pool_set(u32 bpid, const u32 *thresholds);
++#define BM_POOL_THRESH_SW_ENTER 0
++#define BM_POOL_THRESH_SW_EXIT  1
++#define BM_POOL_THRESH_HW_ENTER 2
++#define BM_POOL_THRESH_HW_EXIT  3
++
++/* Read the free buffer count for a given buffer */
++u32 bm_pool_free_buffers(u32 bpid);
++
++__init int bman_init(void);
++__init int bman_resource_init(void);
++
++const struct bm_portal_config *bman_get_bm_portal_config(
++                                              struct bman_portal *portal);
++
++/* power management */
++#ifdef CONFIG_SUSPEND
++void suspend_unused_bportal(void);
++void resume_unused_bportal(void);
++#endif
++
++#endif /* CONFIG_FSL_BMAN_CONFIG */
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/bman_test.c
+@@ -0,0 +1,56 @@
++/* Copyright 2008-2011 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "bman_test.h"
++
++MODULE_AUTHOR("Geoff Thorpe");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_DESCRIPTION("Bman testing");
++
++static int test_init(void)
++{
++#ifdef CONFIG_FSL_BMAN_TEST_HIGH
++      int loop = 1;
++      while (loop--)
++              bman_test_high();
++#endif
++#ifdef CONFIG_FSL_BMAN_TEST_THRESH
++      bman_test_thresh();
++#endif
++      return 0;
++}
++
++static void test_exit(void)
++{
++}
++
++module_init(test_init);
++module_exit(test_exit);
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/bman_test.h
+@@ -0,0 +1,44 @@
++/* Copyright 2008-2011 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/io.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/kthread.h>
++
++#include <linux/fsl_bman.h>
++
++void bman_test_high(void);
++void bman_test_thresh(void);
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/bman_test_high.c
+@@ -0,0 +1,183 @@
++/* Copyright 2008-2011 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "bman_test.h"
++#include "bman_private.h"
++
++/*************/
++/* constants */
++/*************/
++
++#define PORTAL_OPAQUE ((void *)0xf00dbeef)
++#define POOL_OPAQUE   ((void *)0xdeadabba)
++#define NUM_BUFS      93
++#define LOOPS         3
++#define BMAN_TOKEN_MASK 0x00FFFFFFFFFFLLU
++
++/***************/
++/* global vars */
++/***************/
++
++static struct bman_pool *pool;
++static int depleted;
++static struct bm_buffer bufs_in[NUM_BUFS] ____cacheline_aligned;
++static struct bm_buffer bufs_out[NUM_BUFS] ____cacheline_aligned;
++static int bufs_received;
++
++/* Predeclare the callback so we can instantiate pool parameters */
++static void depletion_cb(struct bman_portal *, struct bman_pool *, void *, int);
++
++/**********************/
++/* internal functions */
++/**********************/
++
++static void bufs_init(void)
++{
++      int i;
++      for (i = 0; i < NUM_BUFS; i++)
++              bm_buffer_set64(&bufs_in[i], 0xfedc01234567LLU * i);
++      bufs_received = 0;
++}
++
++static inline int bufs_cmp(const struct bm_buffer *a, const struct bm_buffer *b)
++{
++      if ((bman_ip_rev == BMAN_REV20) || (bman_ip_rev == BMAN_REV21)) {
++
++              /* On SoCs with Bman revison 2.0, Bman only respects the 40
++               * LS-bits of buffer addresses, masking off the upper 8-bits on
++               * release commands. The API provides for 48-bit addresses
++               * because some SoCs support all 48-bits. When generating
++               * garbage addresses for testing, we either need to zero the
++               * upper 8-bits when releasing to Bman (otherwise we'll be
++               * disappointed when the buffers we acquire back from Bman
++               * don't match), or we need to mask the upper 8-bits off when
++               * comparing. We do the latter.
++               */
++              if ((bm_buffer_get64(a) & BMAN_TOKEN_MASK)
++                              < (bm_buffer_get64(b) & BMAN_TOKEN_MASK))
++                      return -1;
++              if ((bm_buffer_get64(a) & BMAN_TOKEN_MASK)
++                              > (bm_buffer_get64(b) & BMAN_TOKEN_MASK))
++                      return 1;
++      } else {
++              if (bm_buffer_get64(a) < bm_buffer_get64(b))
++                      return -1;
++              if (bm_buffer_get64(a) > bm_buffer_get64(b))
++                      return 1;
++      }
++
++      return 0;
++}
++
++static void bufs_confirm(void)
++{
++      int i, j;
++      for (i = 0; i < NUM_BUFS; i++) {
++              int matches = 0;
++              for (j = 0; j < NUM_BUFS; j++)
++                      if (!bufs_cmp(&bufs_in[i], &bufs_out[j]))
++                              matches++;
++              BUG_ON(matches != 1);
++      }
++}
++
++/********/
++/* test */
++/********/
++
++static void depletion_cb(struct bman_portal *__portal, struct bman_pool *__pool,
++                      void *pool_ctx, int __depleted)
++{
++      BUG_ON(__pool != pool);
++      BUG_ON(pool_ctx != POOL_OPAQUE);
++      depleted = __depleted;
++}
++
++void bman_test_high(void)
++{
++      struct bman_pool_params pparams = {
++              .flags = BMAN_POOL_FLAG_DEPLETION | BMAN_POOL_FLAG_DYNAMIC_BPID,
++              .cb = depletion_cb,
++              .cb_ctx = POOL_OPAQUE,
++      };
++      int i, loops = LOOPS;
++      struct bm_buffer tmp_buf;
++
++      bufs_init();
++
++      pr_info("BMAN:  --- starting high-level test ---\n");
++
++      pool = bman_new_pool(&pparams);
++      BUG_ON(!pool);
++
++      /*******************/
++      /* Release buffers */
++      /*******************/
++do_loop:
++      i = 0;
++      while (i < NUM_BUFS) {
++              u32 flags = BMAN_RELEASE_FLAG_WAIT;
++              int num = 8;
++              if ((i + num) > NUM_BUFS)
++                      num = NUM_BUFS - i;
++              if ((i + num) == NUM_BUFS)
++                      flags |= BMAN_RELEASE_FLAG_WAIT_SYNC;
++              if (bman_release(pool, bufs_in + i, num, flags))
++                      panic("bman_release() failed\n");
++              i += num;
++      }
++
++      /*******************/
++      /* Acquire buffers */
++      /*******************/
++      while (i > 0) {
++              int tmp, num = 8;
++              if (num > i)
++                      num = i;
++              tmp = bman_acquire(pool, bufs_out + i - num, num, 0);
++              BUG_ON(tmp != num);
++              i -= num;
++      }
++
++      i = bman_acquire(pool, &tmp_buf, 1, 0);
++      BUG_ON(i > 0);
++
++      bufs_confirm();
++
++      if (--loops)
++              goto do_loop;
++
++      /************/
++      /* Clean up */
++      /************/
++      bman_free_pool(pool);
++      pr_info("BMAN:  --- finished high-level test ---\n");
++}
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/bman_test_thresh.c
+@@ -0,0 +1,196 @@
++/* Copyright 2010-2011 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "bman_test.h"
++
++/* Test constants */
++#define TEST_NUMBUFS  129728
++#define TEST_EXIT     129536
++#define TEST_ENTRY    129024
++
++struct affine_test_data {
++      struct task_struct *t;
++      int cpu;
++      int expect_affinity;
++      int drain;
++      int num_enter;
++      int num_exit;
++      struct list_head node;
++      struct completion wakethread;
++      struct completion wakeparent;
++};
++
++static void cb_depletion(struct bman_portal *portal,
++                      struct bman_pool *pool,
++                      void *opaque,
++                      int depleted)
++{
++      struct affine_test_data *data = opaque;
++      int c = smp_processor_id();
++      pr_info("cb_depletion: bpid=%d, depleted=%d, cpu=%d, original=%d\n",
++              bman_get_params(pool)->bpid, !!depleted, c, data->cpu);
++      /* We should be executing on the CPU of the thread that owns the pool if
++       * and that CPU has an affine portal (ie. it isn't slaved). */
++      BUG_ON((c != data->cpu) && data->expect_affinity);
++      BUG_ON((c == data->cpu) && !data->expect_affinity);
++      if (depleted)
++              data->num_enter++;
++      else
++              data->num_exit++;
++}
++
++/* Params used to set up a pool, this also dynamically allocates a BPID */
++static const struct bman_pool_params params_nocb = {
++      .flags = BMAN_POOL_FLAG_DYNAMIC_BPID | BMAN_POOL_FLAG_THRESH,
++      .thresholds = { TEST_ENTRY, TEST_EXIT, 0, 0 }
++};
++
++/* Params used to set up each cpu's pool with callbacks enabled */
++static struct bman_pool_params params_cb = {
++      .bpid = 0, /* will be replaced to match pool_nocb */
++      .flags = BMAN_POOL_FLAG_DEPLETION,
++      .cb = cb_depletion
++};
++
++static struct bman_pool *pool_nocb;
++static LIST_HEAD(threads);
++
++static int affine_test(void *__data)
++{
++      struct bman_pool *pool;
++      struct affine_test_data *data = __data;
++      struct bman_pool_params my_params = params_cb;
++
++      pr_info("thread %d: starting\n", data->cpu);
++      /* create the pool */
++      my_params.cb_ctx = data;
++      pool = bman_new_pool(&my_params);
++      BUG_ON(!pool);
++      complete(&data->wakeparent);
++      wait_for_completion(&data->wakethread);
++      init_completion(&data->wakethread);
++
++      /* if we're the drainer, we get signalled for that */
++      if (data->drain) {
++              struct bm_buffer buf;
++              int ret;
++              pr_info("thread %d: draining...\n", data->cpu);
++              do {
++                      ret = bman_acquire(pool, &buf, 1, 0);
++              } while (ret > 0);
++              pr_info("thread %d: draining done.\n", data->cpu);
++              complete(&data->wakeparent);
++              wait_for_completion(&data->wakethread);
++              init_completion(&data->wakethread);
++      }
++
++      /* cleanup */
++      bman_free_pool(pool);
++      while (!kthread_should_stop())
++              cpu_relax();
++      pr_info("thread %d: exiting\n", data->cpu);
++      return 0;
++}
++
++static struct affine_test_data *start_affine_test(int cpu, int drain)
++{
++      struct affine_test_data *data = kmalloc(sizeof(*data), GFP_KERNEL);
++
++      if (!data)
++              return NULL;
++      data->cpu = cpu;
++      data->expect_affinity = cpumask_test_cpu(cpu, bman_affine_cpus());
++      data->drain = drain;
++      data->num_enter = 0;
++      data->num_exit = 0;
++      init_completion(&data->wakethread);
++      init_completion(&data->wakeparent);
++      list_add_tail(&data->node, &threads);
++      data->t = kthread_create(affine_test, data, "threshtest%d", cpu);
++      BUG_ON(IS_ERR(data->t));
++      kthread_bind(data->t, cpu);
++      wake_up_process(data->t);
++      return data;
++}
++
++void bman_test_thresh(void)
++{
++      int loop = TEST_NUMBUFS;
++      int ret, num_cpus = 0;
++      struct affine_test_data *data, *drainer = NULL;
++
++      pr_info("bman_test_thresh: start\n");
++
++      /* allocate a BPID and seed it */
++      pool_nocb = bman_new_pool(&params_nocb);
++      BUG_ON(!pool_nocb);
++      while (loop--) {
++              struct bm_buffer buf;
++              bm_buffer_set64(&buf, 0x0badbeef + loop);
++              ret = bman_release(pool_nocb, &buf, 1,
++                                      BMAN_RELEASE_FLAG_WAIT);
++              BUG_ON(ret);
++      }
++      while (!bman_rcr_is_empty())
++              cpu_relax();
++      pr_info("bman_test_thresh: buffers are in\n");
++
++      /* create threads and wait for them to create pools */
++      params_cb.bpid = bman_get_params(pool_nocb)->bpid;
++      for_each_cpu(loop, cpu_online_mask) {
++              data = start_affine_test(loop, drainer ? 0 : 1);
++              BUG_ON(!data);
++              if (!drainer)
++                      drainer = data;
++              num_cpus++;
++              wait_for_completion(&data->wakeparent);
++      }
++
++      /* signal the drainer to start draining */
++      complete(&drainer->wakethread);
++      wait_for_completion(&drainer->wakeparent);
++      init_completion(&drainer->wakeparent);
++
++      /* tear down */
++      list_for_each_entry_safe(data, drainer, &threads, node) {
++              complete(&data->wakethread);
++              ret = kthread_stop(data->t);
++              BUG_ON(ret);
++              list_del(&data->node);
++              /* check that we get the expected callbacks (and no others) */
++              BUG_ON(data->num_enter != 1);
++              BUG_ON(data->num_exit != 0);
++              kfree(data);
++      }
++      bman_free_pool(pool_nocb);
++
++      pr_info("bman_test_thresh: done\n");
++}
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/dpa_alloc.c
+@@ -0,0 +1,706 @@
++/* Copyright 2009-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "dpa_sys.h"
++#include <linux/fsl_qman.h>
++#include <linux/fsl_bman.h>
++
++/* Qman and Bman APIs are front-ends to the common code; */
++
++static DECLARE_DPA_ALLOC(bpalloc); /* BPID allocator */
++static DECLARE_DPA_ALLOC(fqalloc); /* FQID allocator */
++static DECLARE_DPA_ALLOC(qpalloc); /* pool-channel allocator */
++static DECLARE_DPA_ALLOC(cgralloc); /* CGR ID allocator */
++static DECLARE_DPA_ALLOC(ceetm0_challoc); /* CEETM Channel ID allocator */
++static DECLARE_DPA_ALLOC(ceetm0_lfqidalloc); /* CEETM LFQID allocator */
++static DECLARE_DPA_ALLOC(ceetm1_challoc); /* CEETM Channel ID allocator */
++static DECLARE_DPA_ALLOC(ceetm1_lfqidalloc); /* CEETM LFQID allocator */
++
++/* This is a sort-of-conditional dpa_alloc_free() routine. Eg. when releasing
++ * FQIDs (probably from user-space), it can filter out those that aren't in the
++ * OOS state (better to leak a h/w resource than to crash). This function
++ * returns the number of invalid IDs that were not released. */
++static u32 release_id_range(struct dpa_alloc *alloc, u32 id, u32 count,
++                           int (*is_valid)(u32 id))
++{
++      int valid_mode = 0;
++      u32 loop = id, total_invalid = 0;
++      while (loop < (id + count)) {
++              int isvalid = is_valid ? is_valid(loop) : 1;
++              if (!valid_mode) {
++                      /* We're looking for a valid ID to terminate an invalid
++                       * range */
++                      if (isvalid) {
++                              /* We finished a range of invalid IDs, a valid
++                               * range is now underway */
++                              valid_mode = 1;
++                              count -= (loop - id);
++                              id = loop;
++                      } else
++                              total_invalid++;
++              } else {
++                      /* We're looking for an invalid ID to terminate a
++                       * valid range */
++                      if (!isvalid) {
++                              /* Release the range of valid IDs, an unvalid
++                               * range is now underway */
++                              if (loop > id)
++                                      dpa_alloc_free(alloc, id, loop - id);
++                              valid_mode = 0;
++                      }
++              }
++              loop++;
++      }
++      /* Release any unterminated range of valid IDs */
++      if (valid_mode && count)
++              dpa_alloc_free(alloc, id, count);
++      return total_invalid;
++}
++
++/* BPID allocator front-end */
++
++int bman_alloc_bpid_range(u32 *result, u32 count, u32 align, int partial)
++{
++      return dpa_alloc_new(&bpalloc, result, count, align, partial);
++}
++EXPORT_SYMBOL(bman_alloc_bpid_range);
++
++static int bp_cleanup(u32 bpid)
++{
++      return bman_shutdown_pool(bpid) == 0;
++}
++void bman_release_bpid_range(u32 bpid, u32 count)
++{
++      u32 total_invalid = release_id_range(&bpalloc, bpid, count, bp_cleanup);
++      if (total_invalid)
++              pr_err("BPID range [%d..%d] (%d) had %d leaks\n",
++                      bpid, bpid + count - 1, count, total_invalid);
++}
++EXPORT_SYMBOL(bman_release_bpid_range);
++
++void bman_seed_bpid_range(u32 bpid, u32 count)
++{
++      dpa_alloc_seed(&bpalloc, bpid, count);
++}
++EXPORT_SYMBOL(bman_seed_bpid_range);
++
++int bman_reserve_bpid_range(u32 bpid, u32 count)
++{
++      return dpa_alloc_reserve(&bpalloc, bpid, count);
++}
++EXPORT_SYMBOL(bman_reserve_bpid_range);
++
++
++/* FQID allocator front-end */
++
++int qman_alloc_fqid_range(u32 *result, u32 count, u32 align, int partial)
++{
++      return dpa_alloc_new(&fqalloc, result, count, align, partial);
++}
++EXPORT_SYMBOL(qman_alloc_fqid_range);
++
++static int fq_cleanup(u32 fqid)
++{
++      return qman_shutdown_fq(fqid) == 0;
++}
++void qman_release_fqid_range(u32 fqid, u32 count)
++{
++      u32 total_invalid = release_id_range(&fqalloc, fqid, count, fq_cleanup);
++      if (total_invalid)
++              pr_err("FQID range [%d..%d] (%d) had %d leaks\n",
++                      fqid, fqid + count - 1, count, total_invalid);
++}
++EXPORT_SYMBOL(qman_release_fqid_range);
++
++int qman_reserve_fqid_range(u32 fqid, u32 count)
++{
++      return dpa_alloc_reserve(&fqalloc, fqid, count);
++}
++EXPORT_SYMBOL(qman_reserve_fqid_range);
++
++void qman_seed_fqid_range(u32 fqid, u32 count)
++{
++      dpa_alloc_seed(&fqalloc, fqid, count);
++}
++EXPORT_SYMBOL(qman_seed_fqid_range);
++
++/* Pool-channel allocator front-end */
++
++int qman_alloc_pool_range(u32 *result, u32 count, u32 align, int partial)
++{
++      return dpa_alloc_new(&qpalloc, result, count, align, partial);
++}
++EXPORT_SYMBOL(qman_alloc_pool_range);
++
++static int qpool_cleanup(u32 qp)
++{
++      /* We query all FQDs starting from
++       * FQID 1 until we get an "invalid FQID" error, looking for non-OOS FQDs
++       * whose destination channel is the pool-channel being released.
++       * When a non-OOS FQD is found we attempt to clean it up */
++      struct qman_fq fq = {
++              .fqid = 1
++      };
++      int err;
++      do {
++              struct qm_mcr_queryfq_np np;
++              err = qman_query_fq_np(&fq, &np);
++              if (err)
++                      /* FQID range exceeded, found no problems */
++                      return 1;
++              if ((np.state & QM_MCR_NP_STATE_MASK) != QM_MCR_NP_STATE_OOS) {
++                      struct qm_fqd fqd;
++                      err = qman_query_fq(&fq, &fqd);
++                      BUG_ON(err);
++                      if (fqd.dest.channel == qp) {
++                              /* The channel is the FQ's target, clean it */
++                              if (qman_shutdown_fq(fq.fqid) != 0)
++                                      /* Couldn't shut down the FQ
++                                         so the pool must be leaked */
++                                      return 0;
++                      }
++              }
++              /* Move to the next FQID */
++              fq.fqid++;
++      } while (1);
++}
++void qman_release_pool_range(u32 qp, u32 count)
++{
++      u32 total_invalid = release_id_range(&qpalloc, qp,
++                                           count, qpool_cleanup);
++      if (total_invalid) {
++              /* Pool channels are almost always used individually */
++              if (count == 1)
++                      pr_err("Pool channel 0x%x had %d leaks\n",
++                              qp, total_invalid);
++              else
++                      pr_err("Pool channels [%d..%d] (%d) had %d leaks\n",
++                              qp, qp + count - 1, count, total_invalid);
++      }
++}
++EXPORT_SYMBOL(qman_release_pool_range);
++
++
++void qman_seed_pool_range(u32 poolid, u32 count)
++{
++      dpa_alloc_seed(&qpalloc, poolid, count);
++
++}
++EXPORT_SYMBOL(qman_seed_pool_range);
++
++int qman_reserve_pool_range(u32 poolid, u32 count)
++{
++      return dpa_alloc_reserve(&qpalloc, poolid, count);
++}
++EXPORT_SYMBOL(qman_reserve_pool_range);
++
++
++/* CGR ID allocator front-end */
++
++int qman_alloc_cgrid_range(u32 *result, u32 count, u32 align, int partial)
++{
++      return dpa_alloc_new(&cgralloc, result, count, align, partial);
++}
++EXPORT_SYMBOL(qman_alloc_cgrid_range);
++
++static int cqr_cleanup(u32 cgrid)
++{
++      /* We query all FQDs starting from
++       * FQID 1 until we get an "invalid FQID" error, looking for non-OOS FQDs
++       * whose CGR is the CGR being released.
++       */
++      struct qman_fq fq = {
++              .fqid = 1
++      };
++      int err;
++      do {
++              struct qm_mcr_queryfq_np np;
++              err = qman_query_fq_np(&fq, &np);
++              if (err)
++                      /* FQID range exceeded, found no problems */
++                      return 1;
++              if ((np.state & QM_MCR_NP_STATE_MASK) != QM_MCR_NP_STATE_OOS) {
++                      struct qm_fqd fqd;
++                      err = qman_query_fq(&fq, &fqd);
++                      BUG_ON(err);
++                      if ((fqd.fq_ctrl & QM_FQCTRL_CGE) &&
++                          (fqd.cgid == cgrid)) {
++                              pr_err("CRGID 0x%x is being used by FQID 0x%x,"
++                                     " CGR will be leaked\n",
++                                     cgrid, fq.fqid);
++                              return 1;
++                      }
++              }
++              /* Move to the next FQID */
++              fq.fqid++;
++      } while (1);
++}
++
++void qman_release_cgrid_range(u32 cgrid, u32 count)
++{
++      u32 total_invalid = release_id_range(&cgralloc, cgrid,
++                                           count, cqr_cleanup);
++      if (total_invalid)
++              pr_err("CGRID range [%d..%d] (%d) had %d leaks\n",
++                      cgrid, cgrid + count - 1, count, total_invalid);
++}
++EXPORT_SYMBOL(qman_release_cgrid_range);
++
++void qman_seed_cgrid_range(u32 cgrid, u32 count)
++{
++      dpa_alloc_seed(&cgralloc, cgrid, count);
++
++}
++EXPORT_SYMBOL(qman_seed_cgrid_range);
++
++/* CEETM CHANNEL ID allocator front-end */
++int qman_alloc_ceetm0_channel_range(u32 *result, u32 count, u32 align,
++                                                               int partial)
++{
++      return dpa_alloc_new(&ceetm0_challoc, result, count, align, partial);
++}
++EXPORT_SYMBOL(qman_alloc_ceetm0_channel_range);
++
++int qman_alloc_ceetm1_channel_range(u32 *result, u32 count, u32 align,
++                                                               int partial)
++{
++      return dpa_alloc_new(&ceetm1_challoc, result, count, align, partial);
++}
++EXPORT_SYMBOL(qman_alloc_ceetm1_channel_range);
++
++void qman_release_ceetm0_channel_range(u32 channelid, u32 count)
++{
++      u32 total_invalid;
++
++      total_invalid = release_id_range(&ceetm0_challoc, channelid, count,
++                                                                       NULL);
++      if (total_invalid)
++              pr_err("CEETM channel range [%d..%d] (%d) had %d leaks\n",
++                      channelid, channelid + count - 1, count, total_invalid);
++}
++EXPORT_SYMBOL(qman_release_ceetm0_channel_range);
++
++void qman_seed_ceetm0_channel_range(u32 channelid, u32 count)
++{
++      dpa_alloc_seed(&ceetm0_challoc, channelid, count);
++
++}
++EXPORT_SYMBOL(qman_seed_ceetm0_channel_range);
++
++void qman_release_ceetm1_channel_range(u32 channelid, u32 count)
++{
++      u32 total_invalid;
++      total_invalid = release_id_range(&ceetm1_challoc, channelid, count,
++                                                                       NULL);
++      if (total_invalid)
++              pr_err("CEETM channel range [%d..%d] (%d) had %d leaks\n",
++                      channelid, channelid + count - 1, count, total_invalid);
++}
++EXPORT_SYMBOL(qman_release_ceetm1_channel_range);
++
++void qman_seed_ceetm1_channel_range(u32 channelid, u32 count)
++{
++      dpa_alloc_seed(&ceetm1_challoc, channelid, count);
++
++}
++EXPORT_SYMBOL(qman_seed_ceetm1_channel_range);
++
++/* CEETM LFQID allocator front-end */
++int qman_alloc_ceetm0_lfqid_range(u32 *result, u32 count, u32 align,
++                                                               int partial)
++{
++      return dpa_alloc_new(&ceetm0_lfqidalloc, result, count, align, partial);
++}
++EXPORT_SYMBOL(qman_alloc_ceetm0_lfqid_range);
++
++int qman_alloc_ceetm1_lfqid_range(u32 *result, u32 count, u32 align,
++                                                               int partial)
++{
++      return dpa_alloc_new(&ceetm1_lfqidalloc, result, count, align, partial);
++}
++EXPORT_SYMBOL(qman_alloc_ceetm1_lfqid_range);
++
++void qman_release_ceetm0_lfqid_range(u32 lfqid, u32 count)
++{
++      u32 total_invalid;
++
++      total_invalid = release_id_range(&ceetm0_lfqidalloc, lfqid, count,
++                                                                      NULL);
++      if (total_invalid)
++              pr_err("CEETM LFQID range [0x%x..0x%x] (%d) had %d leaks\n",
++                      lfqid, lfqid + count - 1, count, total_invalid);
++}
++EXPORT_SYMBOL(qman_release_ceetm0_lfqid_range);
++
++void qman_seed_ceetm0_lfqid_range(u32 lfqid, u32 count)
++{
++      dpa_alloc_seed(&ceetm0_lfqidalloc, lfqid, count);
++
++}
++EXPORT_SYMBOL(qman_seed_ceetm0_lfqid_range);
++
++void qman_release_ceetm1_lfqid_range(u32 lfqid, u32 count)
++{
++      u32 total_invalid;
++
++      total_invalid = release_id_range(&ceetm1_lfqidalloc, lfqid, count,
++                                                                      NULL);
++      if (total_invalid)
++              pr_err("CEETM LFQID range [0x%x..0x%x] (%d) had %d leaks\n",
++                      lfqid, lfqid + count - 1, count, total_invalid);
++}
++EXPORT_SYMBOL(qman_release_ceetm1_lfqid_range);
++
++void qman_seed_ceetm1_lfqid_range(u32 lfqid, u32 count)
++{
++      dpa_alloc_seed(&ceetm1_lfqidalloc, lfqid, count);
++
++}
++EXPORT_SYMBOL(qman_seed_ceetm1_lfqid_range);
++
++
++/* Everything else is the common backend to all the allocators */
++
++/* The allocator is a (possibly-empty) list of these; */
++struct alloc_node {
++      struct list_head list;
++      u32 base;
++      u32 num;
++      /* refcount and is_alloced are only set
++         when the node is in the used list */
++      unsigned int refcount;
++      int is_alloced;
++};
++
++/* #define DPA_ALLOC_DEBUG */
++
++#ifdef DPA_ALLOC_DEBUG
++#define DPRINT pr_info
++static void DUMP(struct dpa_alloc *alloc)
++{
++      int off = 0;
++      char buf[256];
++      struct alloc_node *p;
++      pr_info("Free Nodes\n");
++      list_for_each_entry(p, &alloc->free, list) {
++              if (off < 255)
++                      off += snprintf(buf + off, 255-off, "{%d,%d}",
++                              p->base, p->base + p->num - 1);
++      }
++      pr_info("%s\n", buf);
++
++      off = 0;
++      pr_info("Used Nodes\n");
++      list_for_each_entry(p, &alloc->used, list) {
++              if (off < 255)
++                      off += snprintf(buf + off, 255-off, "{%d,%d}",
++                              p->base, p->base + p->num - 1);
++      }
++      pr_info("%s\n", buf);
++
++
++
++}
++#else
++#define DPRINT(x...)
++#define DUMP(a)
++#endif
++
++int dpa_alloc_new(struct dpa_alloc *alloc, u32 *result, u32 count, u32 align,
++                int partial)
++{
++      struct alloc_node *i = NULL, *next_best = NULL, *used_node = NULL;
++      u32 base, next_best_base = 0, num = 0, next_best_num = 0;
++      struct alloc_node *margin_left, *margin_right;
++
++      *result = (u32)-1;
++      DPRINT("alloc_range(%d,%d,%d)\n", count, align, partial);
++      DUMP(alloc);
++      /* If 'align' is 0, it should behave as though it was 1 */
++      if (!align)
++              align = 1;
++      margin_left = kmalloc(sizeof(*margin_left), GFP_KERNEL);
++      if (!margin_left)
++              goto err;
++      margin_right = kmalloc(sizeof(*margin_right), GFP_KERNEL);
++      if (!margin_right) {
++              kfree(margin_left);
++              goto err;
++      }
++      spin_lock_irq(&alloc->lock);
++      list_for_each_entry(i, &alloc->free, list) {
++              base = (i->base + align - 1) / align;
++              base *= align;
++              if ((base - i->base) >= i->num)
++                      /* alignment is impossible, regardless of count */
++                      continue;
++              num = i->num - (base - i->base);
++              if (num >= count) {
++                      /* this one will do nicely */
++                      num = count;
++                      goto done;
++              }
++              if (num > next_best_num) {
++                      next_best = i;
++                      next_best_base = base;
++                      next_best_num = num;
++              }
++      }
++      if (partial && next_best) {
++              i = next_best;
++              base = next_best_base;
++              num = next_best_num;
++      } else
++              i = NULL;
++done:
++      if (i) {
++              if (base != i->base) {
++                      margin_left->base = i->base;
++                      margin_left->num = base - i->base;
++                      list_add_tail(&margin_left->list, &i->list);
++              } else
++                      kfree(margin_left);
++              if ((base + num) < (i->base + i->num)) {
++                      margin_right->base = base + num;
++                      margin_right->num = (i->base + i->num) -
++                                              (base + num);
++                      list_add(&margin_right->list, &i->list);
++              } else
++                      kfree(margin_right);
++              list_del(&i->list);
++              kfree(i);
++              *result = base;
++      } else {
++              spin_unlock_irq(&alloc->lock);
++              kfree(margin_left);
++              kfree(margin_right);
++      }
++
++err:
++      DPRINT("returning %d\n", i ? num : -ENOMEM);
++      DUMP(alloc);
++      if (!i)
++              return -ENOMEM;
++
++      /* Add the allocation to the used list with a refcount of 1 */
++      used_node = kmalloc(sizeof(*used_node), GFP_KERNEL);
++      if (!used_node) {
++              spin_unlock_irq(&alloc->lock);
++              return -ENOMEM;
++      }
++      used_node->base = *result;
++      used_node->num = num;
++      used_node->refcount = 1;
++      used_node->is_alloced = 1;
++      list_add_tail(&used_node->list, &alloc->used);
++      spin_unlock_irq(&alloc->lock);
++      return (int)num;
++}
++
++/* Allocate the list node using GFP_ATOMIC, because we *really* want to avoid
++ * forcing error-handling on to users in the deallocation path. */
++static void _dpa_alloc_free(struct dpa_alloc *alloc, u32 base_id, u32 count)
++{
++      struct alloc_node *i, *node = kmalloc(sizeof(*node), GFP_ATOMIC);
++      BUG_ON(!node);
++      DPRINT("release_range(%d,%d)\n", base_id, count);
++      DUMP(alloc);
++      BUG_ON(!count);
++      spin_lock_irq(&alloc->lock);
++
++
++      node->base = base_id;
++      node->num = count;
++      list_for_each_entry(i, &alloc->free, list) {
++              if (i->base >= node->base) {
++                      /* BUG_ON(any overlapping) */
++                      BUG_ON(i->base < (node->base + node->num));
++                      list_add_tail(&node->list, &i->list);
++                      goto done;
++              }
++      }
++      list_add_tail(&node->list, &alloc->free);
++done:
++      /* Merge to the left */
++      i = list_entry(node->list.prev, struct alloc_node, list);
++      if (node->list.prev != &alloc->free) {
++              BUG_ON((i->base + i->num) > node->base);
++              if ((i->base + i->num) == node->base) {
++                      node->base = i->base;
++                      node->num += i->num;
++                      list_del(&i->list);
++                      kfree(i);
++              }
++      }
++      /* Merge to the right */
++      i = list_entry(node->list.next, struct alloc_node, list);
++      if (node->list.next != &alloc->free) {
++              BUG_ON((node->base + node->num) > i->base);
++              if ((node->base + node->num) == i->base) {
++                      node->num += i->num;
++                      list_del(&i->list);
++                      kfree(i);
++              }
++      }
++      spin_unlock_irq(&alloc->lock);
++      DUMP(alloc);
++}
++
++
++void dpa_alloc_free(struct dpa_alloc *alloc, u32 base_id, u32 count)
++{
++      struct alloc_node *i = NULL;
++      spin_lock_irq(&alloc->lock);
++
++      /* First find the node in the used list and decrement its ref count */
++      list_for_each_entry(i, &alloc->used, list) {
++              if (i->base == base_id && i->num == count) {
++                      --i->refcount;
++                      if (i->refcount == 0) {
++                              list_del(&i->list);
++                              spin_unlock_irq(&alloc->lock);
++                              if (i->is_alloced)
++                                      _dpa_alloc_free(alloc, base_id, count);
++                              kfree(i);
++                              return;
++                      }
++                      spin_unlock_irq(&alloc->lock);
++                      return;
++              }
++      }
++      /* Couldn't find the allocation */
++      pr_err("Attempt to free ID 0x%x COUNT %d that wasn't alloc'd or reserved\n",
++             base_id, count);
++      spin_unlock_irq(&alloc->lock);
++}
++
++void dpa_alloc_seed(struct dpa_alloc *alloc, u32 base_id, u32 count)
++{
++      /* Same as free but no previous allocation checking is needed */
++      _dpa_alloc_free(alloc, base_id, count);
++}
++
++
++int dpa_alloc_reserve(struct dpa_alloc *alloc, u32 base, u32 num)
++{
++      struct alloc_node *i = NULL, *used_node;
++
++      DPRINT("alloc_reserve(%d,%d)\n", base, num);
++      DUMP(alloc);
++
++      spin_lock_irq(&alloc->lock);
++
++      /* Check for the node in the used list.
++         If found, increase it's refcount */
++      list_for_each_entry(i, &alloc->used, list) {
++              if ((i->base == base) && (i->num == num)) {
++                      ++i->refcount;
++                      spin_unlock_irq(&alloc->lock);
++                      return 0;
++              }
++              if ((base >= i->base) && (base < (i->base + i->num))) {
++                      /* This is an attempt to reserve a region that was
++                         already reserved or alloced with a different
++                         base or num */
++                      pr_err("Cannot reserve %d - %d, it overlaps with"
++                             " existing reservation from %d - %d\n",
++                             base, base + num - 1, i->base,
++                             i->base + i->num - 1);
++                      spin_unlock_irq(&alloc->lock);
++                      return -1;
++              }
++      }
++      /* Check to make sure this ID isn't in the free list */
++      list_for_each_entry(i, &alloc->free, list) {
++              if ((base >= i->base) && (base < (i->base + i->num))) {
++                      /* yep, the reservation is within this node */
++                      pr_err("Cannot reserve %d - %d, it overlaps with"
++                             " free range %d - %d and must be alloced\n",
++                             base, base + num - 1,
++                             i->base, i->base + i->num - 1);
++                      spin_unlock_irq(&alloc->lock);
++                      return -1;
++              }
++      }
++      /* Add the allocation to the used list with a refcount of 1 */
++      used_node = kmalloc(sizeof(*used_node), GFP_KERNEL);
++      if (!used_node) {
++              spin_unlock_irq(&alloc->lock);
++              return -ENOMEM;
++
++      }
++      used_node->base = base;
++      used_node->num = num;
++      used_node->refcount = 1;
++      used_node->is_alloced = 0;
++      list_add_tail(&used_node->list, &alloc->used);
++      spin_unlock_irq(&alloc->lock);
++      return 0;
++}
++
++
++int dpa_alloc_pop(struct dpa_alloc *alloc, u32 *result, u32 *count)
++{
++      struct alloc_node *i = NULL;
++      DPRINT("alloc_pop()\n");
++      DUMP(alloc);
++      spin_lock_irq(&alloc->lock);
++      if (!list_empty(&alloc->free)) {
++              i = list_entry(alloc->free.next, struct alloc_node, list);
++              list_del(&i->list);
++      }
++      spin_unlock_irq(&alloc->lock);
++      DPRINT("returning %d\n", i ? 0 : -ENOMEM);
++      DUMP(alloc);
++      if (!i)
++              return -ENOMEM;
++      *result = i->base;
++      *count = i->num;
++      kfree(i);
++      return 0;
++}
++
++int dpa_alloc_check(struct dpa_alloc *list_head, u32 item)
++{
++      struct alloc_node *i = NULL;
++      int res = 0;
++      DPRINT("alloc_check()\n");
++      spin_lock_irq(&list_head->lock);
++
++      list_for_each_entry(i, &list_head->free, list) {
++              if ((item >= i->base) && (item < (i->base + i->num))) {
++                      res = 1;
++                      break;
++              }
++      }
++      spin_unlock_irq(&list_head->lock);
++      return res;
++}
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/dpa_sys.h
+@@ -0,0 +1,259 @@
++/* Copyright 2008-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef DPA_SYS_H
++#define DPA_SYS_H
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/io.h>
++#include <linux/dma-mapping.h>
++#include <linux/bootmem.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/of_platform.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/kthread.h>
++#include <linux/memblock.h>
++#include <linux/completion.h>
++#include <linux/log2.h>
++#include <linux/types.h>
++#include <linux/ioctl.h>
++#include <linux/miscdevice.h>
++#include <linux/uaccess.h>
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
++#include <linux/device.h>
++#include <linux/uio_driver.h>
++#include <linux/smp.h>
++#include <linux/fsl_hypervisor.h>
++#include <linux/vmalloc.h>
++#include <linux/ctype.h>
++#include <linux/math64.h>
++#include <linux/bitops.h>
++
++#include <linux/fsl_usdpaa.h>
++
++/* When copying aligned words or shorts, try to avoid memcpy() */
++#define CONFIG_TRY_BETTER_MEMCPY
++
++/* For 2-element tables related to cache-inhibited and cache-enabled mappings */
++#define DPA_PORTAL_CE 0
++#define DPA_PORTAL_CI 1
++
++/***********************/
++/* Misc inline assists */
++/***********************/
++
++#if defined CONFIG_PPC32
++#include "dpa_sys_ppc32.h"
++#elif defined CONFIG_PPC64
++#include "dpa_sys_ppc64.h"
++#elif defined CONFIG_ARM
++#include "dpa_sys_arm.h"
++#elif defined CONFIG_ARM64
++#include "dpa_sys_arm64.h"
++#endif
++
++
++#ifdef CONFIG_FSL_DPA_CHECKING
++#define DPA_ASSERT(x) \
++      do { \
++              if (!(x)) { \
++                      pr_crit("ASSERT: (%s:%d) %s\n", __FILE__, __LINE__, \
++                              __stringify_1(x)); \
++                      dump_stack(); \
++                      panic("assertion failure"); \
++              } \
++      } while (0)
++#else
++#define DPA_ASSERT(x)
++#endif
++
++/* memcpy() stuff - when you know alignments in advance */
++#ifdef CONFIG_TRY_BETTER_MEMCPY
++static inline void copy_words(void *dest, const void *src, size_t sz)
++{
++      u32 *__dest = dest;
++      const u32 *__src = src;
++      size_t __sz = sz >> 2;
++      BUG_ON((unsigned long)dest & 0x3);
++      BUG_ON((unsigned long)src & 0x3);
++      BUG_ON(sz & 0x3);
++      while (__sz--)
++              *(__dest++) = *(__src++);
++}
++static inline void copy_shorts(void *dest, const void *src, size_t sz)
++{
++      u16 *__dest = dest;
++      const u16 *__src = src;
++      size_t __sz = sz >> 1;
++      BUG_ON((unsigned long)dest & 0x1);
++      BUG_ON((unsigned long)src & 0x1);
++      BUG_ON(sz & 0x1);
++      while (__sz--)
++              *(__dest++) = *(__src++);
++}
++static inline void copy_bytes(void *dest, const void *src, size_t sz)
++{
++      u8 *__dest = dest;
++      const u8 *__src = src;
++      while (sz--)
++              *(__dest++) = *(__src++);
++}
++#else
++#define copy_words memcpy
++#define copy_shorts memcpy
++#define copy_bytes memcpy
++#endif
++
++/************/
++/* RB-trees */
++/************/
++
++/* We encapsulate RB-trees so that its easier to use non-linux forms in
++ * non-linux systems. This also encapsulates the extra plumbing that linux code
++ * usually provides when using RB-trees. This encapsulation assumes that the
++ * data type held by the tree is u32. */
++
++struct dpa_rbtree {
++      struct rb_root root;
++};
++#define DPA_RBTREE { .root = RB_ROOT }
++
++static inline void dpa_rbtree_init(struct dpa_rbtree *tree)
++{
++      tree->root = RB_ROOT;
++}
++
++#define IMPLEMENT_DPA_RBTREE(name, type, node_field, val_field) \
++static inline int name##_push(struct dpa_rbtree *tree, type *obj) \
++{ \
++      struct rb_node *parent = NULL, **p = &tree->root.rb_node; \
++      while (*p) { \
++              u32 item; \
++              parent = *p; \
++              item = rb_entry(parent, type, node_field)->val_field; \
++              if (obj->val_field < item) \
++                      p = &parent->rb_left; \
++              else if (obj->val_field > item) \
++                      p = &parent->rb_right; \
++              else \
++                      return -EBUSY; \
++      } \
++      rb_link_node(&obj->node_field, parent, p); \
++      rb_insert_color(&obj->node_field, &tree->root); \
++      return 0; \
++} \
++static inline void name##_del(struct dpa_rbtree *tree, type *obj) \
++{ \
++      rb_erase(&obj->node_field, &tree->root); \
++} \
++static inline type *name##_find(struct dpa_rbtree *tree, u32 val) \
++{ \
++      type *ret; \
++      struct rb_node *p = tree->root.rb_node; \
++      while (p) { \
++              ret = rb_entry(p, type, node_field); \
++              if (val < ret->val_field) \
++                      p = p->rb_left; \
++              else if (val > ret->val_field) \
++                      p = p->rb_right; \
++              else \
++                      return ret; \
++      } \
++      return NULL; \
++}
++
++/************/
++/* Bootargs */
++/************/
++
++/* Qman has "qportals=" and Bman has "bportals=", they use the same syntax
++ * though; a comma-separated list of items, each item being a cpu index and/or a
++ * range of cpu indices, and each item optionally be prefixed by "s" to indicate
++ * that the portal associated with that cpu should be shared. See bman_driver.c
++ * for more specifics. */
++static int __parse_portals_cpu(const char **s, unsigned int *cpu)
++{
++      *cpu = 0;
++      if (!isdigit(**s))
++              return -EINVAL;
++      while (isdigit(**s))
++              *cpu = *cpu * 10 + (*((*s)++) - '0');
++      return 0;
++}
++static inline int parse_portals_bootarg(char *str, struct cpumask *want_shared,
++                                      struct cpumask *want_unshared,
++                                      const char *argname)
++{
++      const char *s = str;
++      unsigned int shared, cpu1, cpu2, loop;
++
++keep_going:
++      if (*s == 's') {
++              shared = 1;
++              s++;
++      } else
++              shared = 0;
++      if (__parse_portals_cpu(&s, &cpu1))
++              goto err;
++      if (*s == '-') {
++              s++;
++              if (__parse_portals_cpu(&s, &cpu2))
++                      goto err;
++              if (cpu2 < cpu1)
++                      goto err;
++      } else
++              cpu2 = cpu1;
++      for (loop = cpu1; loop <= cpu2; loop++)
++              cpumask_set_cpu(loop, shared ? want_shared : want_unshared);
++      if (*s == ',') {
++              s++;
++              goto keep_going;
++      } else if ((*s == '\0') || isspace(*s))
++              return 0;
++err:
++      pr_crit("Malformed %s argument: %s, offset: %lu\n", argname, str,
++              (unsigned long)s - (unsigned long)str);
++      return -EINVAL;
++}
++#ifdef CONFIG_FSL_USDPAA
++/* Hooks from fsl_usdpaa_irq.c to fsl_usdpaa.c */
++int usdpaa_get_portal_config(struct file *filp, void *cinh,
++                           enum usdpaa_portal_type ptype, unsigned int *irq,
++                           void **iir_reg);
++#endif
++#endif /* DPA_SYS_H */
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/dpa_sys_arm.h
+@@ -0,0 +1,95 @@
++/* Copyright 2016 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef DPA_SYS_ARM_H
++#define DPA_SYS_ARM_H
++
++#include <asm/cacheflush.h>
++#include <asm/barrier.h>
++
++/* Implementation of ARM specific routines */
++
++/* TODO: NB, we currently assume that hwsync() and lwsync() imply compiler
++ * barriers and that dcb*() won't fall victim to compiler or execution
++ * reordering with respect to other code/instructions that manipulate the same
++ * cacheline. */
++#define hwsync() { asm volatile("dmb st" : : : "memory"); }
++#define lwsync() { asm volatile("dmb st" : : : "memory"); }
++#define dcbf(p) { asm volatile("mcr p15, 0, %0, c7, c10, 1" : : "r" (p) : "memory"); }
++#define dcbt_ro(p) { asm volatile("pld [%0, #64];": : "r" (p)); }
++#define dcbt_rw(p) { asm volatile("pldw [%0, #64];": : "r" (p)); }
++#define dcbi(p) { asm volatile("mcr p15, 0, %0, c7, c6, 1" : : "r" (p) : "memory"); }
++
++#define dcbz_64(p) { memset(p, 0, sizeof(*p)); }
++
++#define dcbf_64(p) \
++      do { \
++              dcbf((u32)p); \
++      } while (0)
++/* Commonly used combo */
++#define dcbit_ro(p) \
++      do { \
++              dcbi((u32)p); \
++              dcbt_ro((u32)p); \
++      } while (0)
++
++static inline u64 mfatb(void)
++{
++      return get_cycles();
++}
++
++static inline u32 in_be32(volatile void *addr)
++{
++      return be32_to_cpu(*((volatile u32 *) addr));
++}
++
++static inline void out_be32(void *addr, u32 val)
++{
++      *((u32 *) addr) = cpu_to_be32(val);
++}
++
++
++static inline void set_bits(unsigned long mask, volatile unsigned long *p)
++{
++      *p |= mask;
++}
++static inline void clear_bits(unsigned long mask, volatile unsigned long *p)
++{
++      *p &= ~mask;
++}
++
++static inline void flush_dcache_range(unsigned long start, unsigned long stop)
++{
++      __cpuc_flush_dcache_area((void *) start, stop - start);
++}
++
++#define hard_smp_processor_id() raw_smp_processor_id()
++#endif
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/dpa_sys_arm64.h
+@@ -0,0 +1,102 @@
++/* Copyright 2014 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef DPA_SYS_ARM64_H
++#define DPA_SYS_ARM64_H
++
++#include <asm/cacheflush.h>
++#include <asm/barrier.h>
++
++/* Implementation of ARM 64 bit specific routines */
++
++/* TODO: NB, we currently assume that hwsync() and lwsync() imply compiler
++ * barriers and that dcb*() won't fall victim to compiler or execution
++ * reordering with respect to other code/instructions that manipulate the same
++ * cacheline. */
++#define hwsync() { asm volatile("dmb st" : : : "memory"); }
++#define lwsync() { asm volatile("dmb st" : : : "memory"); }
++#define dcbf(p) { asm volatile("dc cvac, %0;" : : "r" (p) : "memory"); }
++#define dcbt_ro(p) { asm volatile("prfm pldl1keep, [%0, #0]" : : "r" (p)); }
++#define dcbt_rw(p) { asm volatile("prfm pstl1keep, [%0, #0]" : : "r" (p)); }
++#define dcbi(p) { asm volatile("dc ivac, %0" : : "r"(p) : "memory"); }
++#define dcbz(p) { asm volatile("dc zva, %0" : : "r" (p) : "memory"); }
++
++#define dcbz_64(p) \
++      do { \
++              dcbz(p);        \
++      } while (0)
++
++#define dcbf_64(p) \
++      do { \
++              dcbf(p); \
++      } while (0)
++/* Commonly used combo */
++#define dcbit_ro(p) \
++      do { \
++              dcbi(p); \
++              dcbt_ro(p); \
++      } while (0)
++
++static inline u64 mfatb(void)
++{
++      return get_cycles();
++}
++
++static inline u32 in_be32(volatile void *addr)
++{
++      return be32_to_cpu(*((volatile u32 *) addr));
++}
++
++static inline void out_be32(void *addr, u32 val)
++{
++      *((u32 *) addr) = cpu_to_be32(val);
++}
++
++
++static inline void set_bits(unsigned long mask, volatile unsigned long *p)
++{
++      *p |= mask;
++}
++static inline void clear_bits(unsigned long mask, volatile unsigned long *p)
++{
++      *p &= ~mask;
++}
++
++static inline void flush_dcache_range(unsigned long start, unsigned long stop)
++{
++      __flush_dcache_area((void *) start, stop - start);
++}
++
++#define hard_smp_processor_id() raw_smp_processor_id()
++
++
++
++#endif
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/dpa_sys_ppc32.h
+@@ -0,0 +1,70 @@
++/* Copyright 2014 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef DPA_SYS_PPC32_H
++#define DPA_SYS_PPC32_H
++
++/* Implementation of PowerPC 32 bit specific routines */
++
++/* TODO: NB, we currently assume that hwsync() and lwsync() imply compiler
++ * barriers and that dcb*() won't fall victim to compiler or execution
++ * reordering with respect to other code/instructions that manipulate the same
++ * cacheline. */
++#define hwsync() __asm__ __volatile__ ("sync" : : : "memory")
++#define lwsync() __asm__ __volatile__ (stringify_in_c(LWSYNC) : : : "memory")
++#define dcbf(p) __asm__ __volatile__ ("dcbf 0,%0" : : "r" (p) : "memory")
++#define dcbt_ro(p) __asm__ __volatile__ ("dcbt 0,%0" : : "r" (p))
++#define dcbt_rw(p) __asm__ __volatile__ ("dcbtst 0,%0" : : "r" (p))
++#define dcbi(p) dcbf(p)
++
++#define dcbzl(p) __asm__ __volatile__ ("dcbzl 0,%0" : : "r" (p))
++#define dcbz_64(p) dcbzl(p)
++#define dcbf_64(p) dcbf(p)
++
++/* Commonly used combo */
++#define dcbit_ro(p) \
++      do { \
++              dcbi(p); \
++              dcbt_ro(p); \
++      } while (0)
++
++static inline u64 mfatb(void)
++{
++      u32 hi, lo, chk;
++      do {
++              hi = mfspr(SPRN_ATBU);
++              lo = mfspr(SPRN_ATBL);
++              chk = mfspr(SPRN_ATBU);
++      } while (unlikely(hi != chk));
++      return ((u64)hi << 32) | (u64)lo;
++}
++
++#endif
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/dpa_sys_ppc64.h
+@@ -0,0 +1,79 @@
++/* Copyright 2014 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef DPA_SYS_PPC64_H
++#define DPA_SYS_PPC64_H
++
++/* Implementation of PowerPC 64 bit specific routines */
++
++/* TODO: NB, we currently assume that hwsync() and lwsync() imply compiler
++ * barriers and that dcb*() won't fall victim to compiler or execution
++ * reordering with respect to other code/instructions that manipulate the same
++ * cacheline. */
++#define hwsync() __asm__ __volatile__ ("sync" : : : "memory")
++#define lwsync() __asm__ __volatile__ (stringify_in_c(LWSYNC) : : : "memory")
++#define dcbf(p) __asm__ __volatile__ ("dcbf 0,%0" : : "r" (p) : "memory")
++#define dcbt_ro(p) __asm__ __volatile__ ("dcbt 0,%0" : : "r" (p))
++#define dcbt_rw(p) __asm__ __volatile__ ("dcbtst 0,%0" : : "r" (p))
++#define dcbi(p) dcbf(p)
++
++#define dcbz(p) __asm__ __volatile__ ("dcbz 0,%0" : : "r" (p))
++#define dcbz_64(p) \
++      do { \
++              dcbz((void*)p + 32);    \
++              dcbz(p);        \
++      } while (0)
++#define dcbf_64(p) \
++      do { \
++              dcbf((void*)p + 32); \
++              dcbf(p); \
++      } while (0)
++/* Commonly used combo */
++#define dcbit_ro(p) \
++      do { \
++              dcbi(p); \
++              dcbi((void*)p + 32); \
++              dcbt_ro(p); \
++              dcbt_ro((void*)p + 32); \
++      } while (0)
++
++static inline u64 mfatb(void)
++{
++      u32 hi, lo, chk;
++      do {
++              hi = mfspr(SPRN_ATBU);
++              lo = mfspr(SPRN_ATBL);
++              chk = mfspr(SPRN_ATBU);
++      } while (unlikely(hi != chk));
++      return ((u64)hi << 32) | (u64)lo;
++}
++
++#endif
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/fsl_usdpaa.c
+@@ -0,0 +1,1984 @@
++/* Copyright (C) 2008-2012 Freescale Semiconductor, Inc.
++ * Authors: Andy Fleming <afleming@freescale.com>
++ *        Timur Tabi <timur@freescale.com>
++ *        Geoff Thorpe <Geoff.Thorpe@freescale.com>
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2.  This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++
++#include <linux/miscdevice.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/mm.h>
++#include <linux/of.h>
++#include <linux/memblock.h>
++#include <linux/slab.h>
++#include <linux/mman.h>
++#include <linux/of_reserved_mem.h>
++
++#if !(defined(CONFIG_ARM) || defined(CONFIG_ARM64))
++#include <mm/mmu_decl.h>
++#endif
++
++#include "dpa_sys.h"
++#include <linux/fsl_usdpaa.h>
++#include "bman_low.h"
++#include "qman_low.h"
++
++/* Physical address range of the memory reservation, exported for mm/mem.c */
++static u64 phys_start;
++static u64 phys_size;
++static u64 arg_phys_size;
++
++/* PFN versions of the above */
++static unsigned long pfn_start;
++static unsigned long pfn_size;
++
++/* Memory reservations are manipulated under this spinlock (which is why 'refs'
++ * isn't atomic_t). */
++static DEFINE_SPINLOCK(mem_lock);
++
++/* The range of TLB1 indices */
++static unsigned int first_tlb;
++static unsigned int num_tlb = 1;
++static unsigned int current_tlb; /* loops around for fault handling */
++
++/* Memory reservation is represented as a list of 'mem_fragment's, some of which
++ * may be mapped. Unmapped fragments are always merged where possible. */
++static LIST_HEAD(mem_list);
++
++struct mem_mapping;
++
++/* Memory fragments are in 'mem_list'. */
++struct mem_fragment {
++      u64 base;
++      u64 len;
++      unsigned long pfn_base; /* PFN version of 'base' */
++      unsigned long pfn_len; /* PFN version of 'len' */
++      unsigned int refs; /* zero if unmapped */
++      u64 root_len; /* Size of the orignal fragment */
++      unsigned long root_pfn; /* PFN of the orignal fragment */
++      struct list_head list;
++      /* if mapped, flags+name captured at creation time */
++      u32 flags;
++      char name[USDPAA_DMA_NAME_MAX];
++      u64 map_len;
++      /* support multi-process locks per-memory-fragment. */
++      int has_locking;
++      wait_queue_head_t wq;
++      struct mem_mapping *owner;
++};
++
++/* Mappings of memory fragments in 'struct ctx'. These are created from
++ * ioctl(USDPAA_IOCTL_DMA_MAP), though the actual mapping then happens via a
++ * mmap(). */
++struct mem_mapping {
++      struct mem_fragment *root_frag;
++      u32 frag_count;
++      u64 total_size;
++      struct list_head list;
++      int refs;
++      void *virt_addr;
++};
++
++struct portal_mapping {
++      struct usdpaa_ioctl_portal_map user;
++      union {
++              struct qm_portal_config *qportal;
++              struct bm_portal_config *bportal;
++      };
++      /* Declare space for the portals in case the process
++         exits unexpectedly and needs to be cleaned by the kernel */
++      union {
++              struct qm_portal qman_portal_low;
++              struct bm_portal bman_portal_low;
++      };
++      struct list_head list;
++      struct resource *phys;
++      struct iommu_domain *iommu_domain;
++};
++
++/* Track the DPAA resources the process is using */
++struct active_resource {
++      struct list_head list;
++      u32 id;
++      u32 num;
++      unsigned int refcount;
++};
++
++/* Per-FD state (which should also be per-process but we don't enforce that) */
++struct ctx {
++      /* Lock to protect the context */
++      spinlock_t lock;
++      /* Allocated resources get put here for accounting */
++      struct list_head resources[usdpaa_id_max];
++      /* list of DMA maps */
++      struct list_head maps;
++      /* list of portal maps */
++      struct list_head portals;
++};
++
++/* Different resource classes */
++static const struct alloc_backend {
++      enum usdpaa_id_type id_type;
++      int (*alloc)(u32 *, u32, u32, int);
++      void (*release)(u32 base, unsigned int count);
++      int (*reserve)(u32 base, unsigned int count);
++      const char *acronym;
++} alloc_backends[] = {
++      {
++              .id_type = usdpaa_id_fqid,
++              .alloc = qman_alloc_fqid_range,
++              .release = qman_release_fqid_range,
++              .reserve = qman_reserve_fqid_range,
++              .acronym = "FQID"
++      },
++      {
++              .id_type = usdpaa_id_bpid,
++              .alloc = bman_alloc_bpid_range,
++              .release = bman_release_bpid_range,
++              .reserve = bman_reserve_bpid_range,
++              .acronym = "BPID"
++      },
++      {
++              .id_type = usdpaa_id_qpool,
++              .alloc = qman_alloc_pool_range,
++              .release = qman_release_pool_range,
++              .reserve = qman_reserve_pool_range,
++              .acronym = "QPOOL"
++      },
++      {
++              .id_type = usdpaa_id_cgrid,
++              .alloc = qman_alloc_cgrid_range,
++              .release = qman_release_cgrid_range,
++              .acronym = "CGRID"
++      },
++      {
++              .id_type = usdpaa_id_ceetm0_lfqid,
++              .alloc = qman_alloc_ceetm0_lfqid_range,
++              .release = qman_release_ceetm0_lfqid_range,
++              .acronym = "CEETM0_LFQID"
++      },
++      {
++              .id_type = usdpaa_id_ceetm0_channelid,
++              .alloc = qman_alloc_ceetm0_channel_range,
++              .release = qman_release_ceetm0_channel_range,
++              .acronym = "CEETM0_LFQID"
++      },
++      {
++              .id_type = usdpaa_id_ceetm1_lfqid,
++              .alloc = qman_alloc_ceetm1_lfqid_range,
++              .release = qman_release_ceetm1_lfqid_range,
++              .acronym = "CEETM1_LFQID"
++      },
++      {
++              .id_type = usdpaa_id_ceetm1_channelid,
++              .alloc = qman_alloc_ceetm1_channel_range,
++              .release = qman_release_ceetm1_channel_range,
++              .acronym = "CEETM1_LFQID"
++      },
++      {
++              /* This terminates the array */
++              .id_type = usdpaa_id_max
++      }
++};
++
++/* Determines the largest acceptable page size for a given size
++   The sizes are determined by what the TLB1 acceptable page sizes are */
++static u32 largest_page_size(u32 size)
++{
++      int shift = 30; /* Start at 1G size */
++      if (size < 4096)
++              return 0;
++      do {
++              if (size >= (1<<shift))
++                      return 1<<shift;
++              shift -= 2;
++      } while (shift >= 12); /* Up to 4k */
++      return 0;
++}
++
++/* Determine if value is power of 4 */
++static inline bool is_power_of_4(u64 x)
++{
++      if (x == 0 || ((x & (x - 1)) != 0))
++              return false;
++      return !!(x & 0x5555555555555555ull);
++}
++
++/* Helper for ioctl_dma_map() when we have a larger fragment than we need. This
++ * splits the fragment into 4 and returns the upper-most. (The caller can loop
++ * until it has a suitable fragment size.) */
++static struct mem_fragment *split_frag(struct mem_fragment *frag)
++{
++      struct mem_fragment *x[3];
++
++      x[0] = kmalloc(sizeof(struct mem_fragment), GFP_ATOMIC);
++      x[1] = kmalloc(sizeof(struct mem_fragment), GFP_ATOMIC);
++      x[2] = kmalloc(sizeof(struct mem_fragment), GFP_ATOMIC);
++      if (!x[0] || !x[1] || !x[2]) {
++              kfree(x[0]);
++              kfree(x[1]);
++              kfree(x[2]);
++              return NULL;
++      }
++      BUG_ON(frag->refs);
++      frag->len >>= 2;
++      frag->pfn_len >>= 2;
++      x[0]->base = frag->base + frag->len;
++      x[1]->base = x[0]->base + frag->len;
++      x[2]->base = x[1]->base + frag->len;
++      x[0]->len = x[1]->len = x[2]->len = frag->len;
++      x[0]->pfn_base = frag->pfn_base + frag->pfn_len;
++      x[1]->pfn_base = x[0]->pfn_base + frag->pfn_len;
++      x[2]->pfn_base = x[1]->pfn_base + frag->pfn_len;
++      x[0]->pfn_len = x[1]->pfn_len = x[2]->pfn_len = frag->pfn_len;
++      x[0]->refs = x[1]->refs = x[2]->refs = 0;
++      x[0]->root_len = x[1]->root_len = x[2]->root_len = frag->root_len;
++      x[0]->root_pfn = x[1]->root_pfn = x[2]->root_pfn = frag->root_pfn;
++      x[0]->name[0] = x[1]->name[0] = x[2]->name[0] = 0;
++      list_add_tail(&x[0]->list, &frag->list);
++      list_add_tail(&x[1]->list, &x[0]->list);
++      list_add_tail(&x[2]->list, &x[1]->list);
++      return x[2];
++}
++
++static __maybe_unused void dump_frags(void)
++{
++      struct mem_fragment *frag;
++      int i = 0;
++      list_for_each_entry(frag, &mem_list, list) {
++              pr_info("FRAG %d: base 0x%llx pfn_base 0x%lx len 0x%llx root_len 0x%llx root_pfn 0x%lx refs %d name %s\n",
++                      i, frag->base, frag->pfn_base,
++                      frag->len, frag->root_len, frag->root_pfn,
++                      frag->refs, frag->name);
++              ++i;
++      }
++}
++
++/* Walk the list of fragments and adjoin neighbouring segments if possible */
++static void compress_frags(void)
++{
++      /* Walk the fragment list and combine fragments */
++      struct mem_fragment *frag, *nxtfrag;
++      u64 len = 0;
++
++      int i, numfrags;
++
++
++      frag = list_entry(mem_list.next, struct mem_fragment, list);
++
++      while (&frag->list != &mem_list) {
++              /* Must combine consecutive fragemenst with
++                 same root_pfn such that they are power of 4 */
++              if (frag->refs != 0) {
++                      frag = list_entry(frag->list.next,
++                                        struct mem_fragment, list);
++                      continue; /* Not this window */
++              }
++              len = frag->len;
++              numfrags = 0;
++              nxtfrag =  list_entry(frag->list.next,
++                                    struct mem_fragment, list);
++              while (true) {
++                      if (&nxtfrag->list == &mem_list) {
++                              numfrags = 0;
++                              break; /* End of list */
++                      }
++                      if (nxtfrag->refs) {
++                              numfrags = 0;
++                              break; /* In use still */
++                      }
++                      if (nxtfrag->root_pfn != frag->root_pfn) {
++                              numfrags = 0;
++                              break; /* Crosses root fragment boundary */
++                      }
++                      len += nxtfrag->len;
++                      numfrags++;
++                      if (is_power_of_4(len)) {
++                              /* These fragments can be combined */
++                              break;
++                      }
++                      nxtfrag =  list_entry(nxtfrag->list.next,
++                                            struct mem_fragment, list);
++              }
++              if (numfrags == 0) {
++                      frag = list_entry(frag->list.next,
++                                        struct mem_fragment, list);
++                      continue; /* try the next window */
++              }
++              for (i = 0; i < numfrags; i++) {
++                      struct mem_fragment *todel =
++                              list_entry(nxtfrag->list.prev,
++                                         struct mem_fragment, list);
++                      nxtfrag->len += todel->len;
++                      nxtfrag->pfn_len += todel->pfn_len;
++                      list_del(&todel->list);
++              }
++              /* Re evaluate the list, things may merge now */
++              frag = list_entry(mem_list.next, struct mem_fragment, list);
++      }
++}
++
++/* Hook from arch/powerpc/mm/mem.c */
++int usdpaa_test_fault(unsigned long pfn, u64 *phys_addr, u64 *size)
++{
++      struct mem_fragment *frag;
++      int idx = -1;
++      if ((pfn < pfn_start) || (pfn >= (pfn_start + pfn_size)))
++              return -1;
++      /* It's in-range, we need to find the fragment */
++      spin_lock(&mem_lock);
++      list_for_each_entry(frag, &mem_list, list) {
++              if ((pfn >= frag->pfn_base) && (pfn < (frag->pfn_base +
++                                                     frag->pfn_len))) {
++                      *phys_addr = frag->base;
++                      *size = frag->len;
++                      idx = current_tlb++;
++                      if (current_tlb >= (first_tlb + num_tlb))
++                              current_tlb = first_tlb;
++                      break;
++              }
++      }
++      spin_unlock(&mem_lock);
++      return idx;
++}
++
++static int usdpaa_open(struct inode *inode, struct file *filp)
++{
++      const struct alloc_backend *backend = &alloc_backends[0];
++      struct ctx *ctx = kmalloc(sizeof(struct ctx), GFP_KERNEL);
++      if (!ctx)
++              return -ENOMEM;
++      filp->private_data = ctx;
++
++      while (backend->id_type != usdpaa_id_max) {
++              INIT_LIST_HEAD(&ctx->resources[backend->id_type]);
++              backend++;
++      }
++
++      INIT_LIST_HEAD(&ctx->maps);
++      INIT_LIST_HEAD(&ctx->portals);
++      spin_lock_init(&ctx->lock);
++
++      //filp->f_mapping->backing_dev_info = &directly_mappable_cdev_bdi;
++
++      return 0;
++}
++
++#define DQRR_MAXFILL 15
++
++/* Reset a QMan portal to its default state */
++static int init_qm_portal(struct qm_portal_config *config,
++                        struct qm_portal *portal)
++{
++      const struct qm_dqrr_entry *dqrr = NULL;
++      int i;
++
++      portal->addr.addr_ce = config->addr_virt[DPA_PORTAL_CE];
++      portal->addr.addr_ci = config->addr_virt[DPA_PORTAL_CI];
++
++      /* Make sure interrupts are inhibited */
++      qm_out(IIR, 1);
++
++      /* Initialize the DQRR.  This will stop any dequeue
++         commands that are in progress */
++      if (qm_dqrr_init(portal, config, qm_dqrr_dpush, qm_dqrr_pvb,
++                       qm_dqrr_cdc, DQRR_MAXFILL)) {
++              pr_err("qm_dqrr_init() failed when trying to"
++                     " recover portal, portal will be leaked\n");
++              return 1;
++      }
++
++      /* Discard any entries on the DQRR */
++      /* If we consume the ring twice something is wrong */
++      for (i = 0; i < DQRR_MAXFILL * 2; i++) {
++              qm_dqrr_pvb_update(portal);
++              dqrr = qm_dqrr_current(portal);
++              if (!dqrr)
++                      break;
++              qm_dqrr_cdc_consume_1ptr(portal, dqrr, 0);
++              qm_dqrr_pvb_update(portal);
++              qm_dqrr_next(portal);
++      }
++      /* Initialize the EQCR */
++      if (qm_eqcr_init(portal, qm_eqcr_pvb,
++                      qm_eqcr_get_ci_stashing(portal), 1)) {
++              pr_err("Qman EQCR initialisation failed\n");
++              return 1;
++      }
++      /* initialize the MR */
++      if (qm_mr_init(portal, qm_mr_pvb, qm_mr_cci)) {
++              pr_err("Qman MR initialisation failed\n");
++              return 1;
++      }
++      qm_mr_pvb_update(portal);
++      while (qm_mr_current(portal)) {
++              qm_mr_next(portal);
++              qm_mr_cci_consume_to_current(portal);
++              qm_mr_pvb_update(portal);
++      }
++
++      if (qm_mc_init(portal)) {
++              pr_err("Qman MC initialisation failed\n");
++              return 1;
++      }
++      return 0;
++}
++
++static int init_bm_portal(struct bm_portal_config *config,
++                        struct bm_portal *portal)
++{
++      portal->addr.addr_ce = config->addr_virt[DPA_PORTAL_CE];
++      portal->addr.addr_ci = config->addr_virt[DPA_PORTAL_CI];
++
++      if (bm_rcr_init(portal, bm_rcr_pvb, bm_rcr_cce)) {
++              pr_err("Bman RCR initialisation failed\n");
++      return 1;
++      }
++      if (bm_mc_init(portal)) {
++              pr_err("Bman MC initialisation failed\n");
++              return 1;
++      }
++      return 0;
++}
++
++/* Function that will scan all FQ's in the system.  For each FQ that is not
++   OOS it will call the check_channel helper to determine if the FQ should
++   be torn down.  If the check_channel helper returns true the FQ will be
++   transitioned to the OOS state */
++static int qm_check_and_destroy_fqs(struct qm_portal *portal, void *ctx,
++                                  bool (*check_channel)(void*, u32))
++{
++      u32 fq_id = 0;
++      while (1) {
++              struct qm_mc_command *mcc;
++              struct qm_mc_result *mcr;
++              u8 state;
++              u32 channel;
++
++              /* Determine the channel for the FQID */
++              mcc = qm_mc_start(portal);
++              mcc->queryfq.fqid = fq_id;
++              qm_mc_commit(portal, QM_MCC_VERB_QUERYFQ);
++              while (!(mcr = qm_mc_result(portal)))
++                      cpu_relax();
++              DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK)
++                         == QM_MCR_VERB_QUERYFQ);
++              if (mcr->result != QM_MCR_RESULT_OK)
++                      break; /* End of valid FQIDs */
++
++              channel = mcr->queryfq.fqd.dest.channel;
++              /* Determine the state of the FQID */
++              mcc = qm_mc_start(portal);
++              mcc->queryfq_np.fqid = fq_id;
++              qm_mc_commit(portal, QM_MCC_VERB_QUERYFQ_NP);
++              while (!(mcr = qm_mc_result(portal)))
++                      cpu_relax();
++              DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK)
++                         == QM_MCR_VERB_QUERYFQ_NP);
++              state = mcr->queryfq_np.state & QM_MCR_NP_STATE_MASK;
++              if (state == QM_MCR_NP_STATE_OOS)
++                      /* Already OOS, no need to do anymore checks */
++                      goto next;
++
++              if (check_channel(ctx, channel))
++                      qm_shutdown_fq(&portal, 1, fq_id);
++ next:
++              ++fq_id;
++      }
++      return 0;
++}
++
++static bool check_channel_device(void *_ctx, u32 channel)
++{
++      struct ctx *ctx = _ctx;
++      struct portal_mapping *portal, *tmpportal;
++      struct active_resource *res;
++
++      /* See if the FQ is destined for one of the portals we're cleaning up */
++      list_for_each_entry_safe(portal, tmpportal, &ctx->portals, list) {
++              if (portal->user.type == usdpaa_portal_qman) {
++                      if (portal->qportal->public_cfg.channel == channel) {
++                              /* This FQs destination is a portal
++                                 we're cleaning, send a retire */
++                              return true;
++                      }
++              }
++      }
++
++      /* Check the pool channels that will be released as well */
++      list_for_each_entry(res, &ctx->resources[usdpaa_id_qpool], list) {
++              if ((res->id >= channel) &&
++                  ((res->id + res->num - 1) <= channel))
++                      return true;
++      }
++      return false;
++}
++
++static bool check_portal_channel(void *ctx, u32 channel)
++{
++      u32 portal_channel = *(u32 *)ctx;
++      if (portal_channel == channel) {
++              /* This FQs destination is a portal
++                 we're cleaning, send a retire */
++              return true;
++      }
++      return false;
++}
++
++
++
++
++static int usdpaa_release(struct inode *inode, struct file *filp)
++{
++      struct ctx *ctx = filp->private_data;
++      struct mem_mapping *map, *tmpmap;
++      struct portal_mapping *portal, *tmpportal;
++      const struct alloc_backend *backend = &alloc_backends[0];
++      struct active_resource *res;
++      struct qm_portal *qm_cleanup_portal = NULL;
++      struct bm_portal *bm_cleanup_portal = NULL;
++      struct qm_portal_config *qm_alloced_portal = NULL;
++      struct bm_portal_config *bm_alloced_portal = NULL;
++
++      struct qm_portal *portal_array[qman_portal_max];
++      int portal_count = 0;
++
++      /* Ensure the release operation cannot be migrated to another
++         CPU as CPU specific variables may be needed during cleanup */
++#ifdef CONFIG_PREEMPT_RT_FULL
++      migrate_disable();
++#endif
++      /* The following logic is used to recover resources that were not
++         correctly released by the process that is closing the FD.
++         Step 1: syncronize the HW with the qm_portal/bm_portal structures
++         in the kernel
++      */
++
++      list_for_each_entry_safe(portal, tmpportal, &ctx->portals, list) {
++              /* Try to recover any portals that weren't shut down */
++              if (portal->user.type == usdpaa_portal_qman) {
++                      portal_array[portal_count] = &portal->qman_portal_low;
++                      ++portal_count;
++                      init_qm_portal(portal->qportal,
++                                     &portal->qman_portal_low);
++                      if (!qm_cleanup_portal) {
++                              qm_cleanup_portal = &portal->qman_portal_low;
++                      } else {
++                              /* Clean FQs on the dedicated channel */
++                              u32 chan = portal->qportal->public_cfg.channel;
++                              qm_check_and_destroy_fqs(
++                                      &portal->qman_portal_low, &chan,
++                                      check_portal_channel);
++                      }
++              } else {
++                      /* BMAN */
++                      init_bm_portal(portal->bportal,
++                                     &portal->bman_portal_low);
++                      if (!bm_cleanup_portal)
++                              bm_cleanup_portal = &portal->bman_portal_low;
++              }
++      }
++      /* If no portal was found, allocate one for cleanup */
++      if (!qm_cleanup_portal) {
++              qm_alloced_portal = qm_get_unused_portal();
++              if (!qm_alloced_portal) {
++                      pr_crit("No QMan portal avalaible for cleanup\n");
++#ifdef CONFIG_PREEMPT_RT_FULL
++                      migrate_enable();
++#endif
++                      return -1;
++              }
++              qm_cleanup_portal = kmalloc(sizeof(struct qm_portal),
++                                          GFP_KERNEL);
++              if (!qm_cleanup_portal) {
++#ifdef CONFIG_PREEMPT_RT_FULL
++                      migrate_enable();
++#endif
++                      return -ENOMEM;
++              }
++              init_qm_portal(qm_alloced_portal, qm_cleanup_portal);
++              portal_array[portal_count] = qm_cleanup_portal;
++              ++portal_count;
++      }
++      if (!bm_cleanup_portal) {
++              bm_alloced_portal = bm_get_unused_portal();
++              if (!bm_alloced_portal) {
++                      pr_crit("No BMan portal avalaible for cleanup\n");
++#ifdef CONFIG_PREEMPT_RT_FULL
++                      migrate_enable();
++#endif
++                      return -1;
++              }
++              bm_cleanup_portal = kmalloc(sizeof(struct bm_portal),
++                                          GFP_KERNEL);
++              if (!bm_cleanup_portal) {
++#ifdef CONFIG_PREEMPT_RT_FULL
++                      migrate_enable();
++#endif
++                      return -ENOMEM;
++              }
++              init_bm_portal(bm_alloced_portal, bm_cleanup_portal);
++      }
++
++      /* OOS the FQs associated with this process */
++      qm_check_and_destroy_fqs(qm_cleanup_portal, ctx, check_channel_device);
++
++      while (backend->id_type != usdpaa_id_max) {
++              int leaks = 0;
++              list_for_each_entry(res, &ctx->resources[backend->id_type],
++                                  list) {
++                      if (backend->id_type == usdpaa_id_fqid) {
++                              int i = 0;
++                              for (; i < res->num; i++) {
++                                      /* Clean FQs with the cleanup portal */
++                                      qm_shutdown_fq(portal_array,
++                                                     portal_count,
++                                                     res->id + i);
++                              }
++                      }
++                      leaks += res->num;
++                      backend->release(res->id, res->num);
++              }
++              if (leaks)
++                      pr_crit("USDPAA process leaking %d %s%s\n", leaks,
++                              backend->acronym, (leaks > 1) ? "s" : "");
++              backend++;
++      }
++      /* Release any DMA regions */
++      spin_lock(&mem_lock);
++      list_for_each_entry_safe(map, tmpmap, &ctx->maps, list) {
++              struct mem_fragment *current_frag = map->root_frag;
++              int i;
++              if (map->root_frag->has_locking &&
++                  (map->root_frag->owner == map)) {
++                      map->root_frag->owner = NULL;
++                      wake_up(&map->root_frag->wq);
++              }
++              /* Check each fragment and merge if the ref count is 0 */
++              for (i = 0; i < map->frag_count; i++) {
++                      --current_frag->refs;
++                      current_frag = list_entry(current_frag->list.prev,
++                                                struct mem_fragment, list);
++              }
++
++              compress_frags();
++              list_del(&map->list);
++              kfree(map);
++      }
++      spin_unlock(&mem_lock);
++
++      /* Return portals */
++      list_for_each_entry_safe(portal, tmpportal, &ctx->portals, list) {
++              if (portal->user.type == usdpaa_portal_qman) {
++                      /* Give the portal back to the allocator */
++                      init_qm_portal(portal->qportal,
++                                     &portal->qman_portal_low);
++                      qm_put_unused_portal(portal->qportal);
++              } else {
++                      init_bm_portal(portal->bportal,
++                                     &portal->bman_portal_low);
++                      bm_put_unused_portal(portal->bportal);
++              }
++              list_del(&portal->list);
++              kfree(portal);
++      }
++      if (qm_alloced_portal) {
++              qm_put_unused_portal(qm_alloced_portal);
++              kfree(qm_cleanup_portal);
++      }
++      if (bm_alloced_portal) {
++              bm_put_unused_portal(bm_alloced_portal);
++              kfree(bm_cleanup_portal);
++      }
++
++      kfree(ctx);
++#ifdef CONFIG_PREEMPT_RT_FULL
++      migrate_enable();
++#endif
++      return 0;
++}
++
++static int check_mmap_dma(struct ctx *ctx, struct vm_area_struct *vma,
++                        int *match, unsigned long *pfn)
++{
++      struct mem_mapping *map;
++
++      list_for_each_entry(map, &ctx->maps, list) {
++              int i;
++              struct mem_fragment *frag = map->root_frag;
++
++              for (i = 0; i < map->frag_count; i++) {
++                      if (frag->pfn_base == vma->vm_pgoff) {
++                              *match = 1;
++                              *pfn = frag->pfn_base;
++                              return 0;
++                      }
++                      frag = list_entry(frag->list.next, struct mem_fragment,
++                                        list);
++              }
++      }
++      *match = 0;
++      return 0;
++}
++
++static int check_mmap_resource(struct resource *res, struct vm_area_struct *vma,
++                             int *match, unsigned long *pfn)
++{
++      *pfn = res->start >> PAGE_SHIFT;
++      if (*pfn == vma->vm_pgoff) {
++              *match = 1;
++              if ((vma->vm_end - vma->vm_start) != resource_size(res))
++                      return -EINVAL;
++      } else
++              *match = 0;
++      return 0;
++}
++
++static int check_mmap_portal(struct ctx *ctx, struct vm_area_struct *vma,
++                            int *match, unsigned long *pfn)
++{
++      struct portal_mapping *portal;
++      int ret;
++
++      list_for_each_entry(portal, &ctx->portals, list) {
++              ret = check_mmap_resource(&portal->phys[DPA_PORTAL_CE], vma,
++                                        match, pfn);
++              if (*match) {
++                      vma->vm_page_prot =
++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++                              pgprot_cached_ns(vma->vm_page_prot);
++#else
++                              pgprot_cached_noncoherent(vma->vm_page_prot);
++#endif
++                      return ret;
++              }
++              ret = check_mmap_resource(&portal->phys[DPA_PORTAL_CI], vma,
++                                        match, pfn);
++              if (*match) {
++                      vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++                      return ret;
++              }
++      }
++      *match = 0;
++      return 0;
++}
++
++static int usdpaa_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++      struct ctx *ctx = filp->private_data;
++      unsigned long pfn = 0;
++      int match, ret;
++
++      spin_lock(&mem_lock);
++      ret = check_mmap_dma(ctx, vma, &match, &pfn);
++      if (!match)
++              ret = check_mmap_portal(ctx, vma, &match, &pfn);
++      spin_unlock(&mem_lock);
++      if (!match)
++              return -EINVAL;
++      if (!ret)
++              ret = remap_pfn_range(vma, vma->vm_start, pfn,
++                                    vma->vm_end - vma->vm_start,
++                                    vma->vm_page_prot);
++      return ret;
++}
++
++/* Return the nearest rounded-up address >= 'addr' that is 'sz'-aligned. 'sz'
++ * must be a power of 2, but both 'addr' and 'sz' can be expressions. */
++#define USDPAA_MEM_ROUNDUP(addr, sz) \
++      ({ \
++              unsigned long foo_align = (sz) - 1; \
++              ((addr) + foo_align) & ~foo_align; \
++      })
++/* Searching for a size-aligned virtual address range starting from 'addr' */
++static unsigned long usdpaa_get_unmapped_area(struct file *file,
++                                            unsigned long addr,
++                                            unsigned long len,
++                                            unsigned long pgoff,
++                                            unsigned long flags)
++{
++      struct vm_area_struct *vma;
++
++      if (len % PAGE_SIZE)
++              return -EINVAL;
++      if (!len)
++              return -EINVAL;
++
++      /* Need to align the address to the largest pagesize of the mapping
++       * because the MMU requires the virtual address to have the same
++       * alignment as the physical address */
++      addr = USDPAA_MEM_ROUNDUP(addr, largest_page_size(len));
++      vma = find_vma(current->mm, addr);
++      /* Keep searching until we reach the end of currently-used virtual
++       * address-space or we find a big enough gap. */
++      while (vma) {
++              if ((addr + len) < vma->vm_start)
++                      return addr;
++
++              addr = USDPAA_MEM_ROUNDUP(vma->vm_end,  largest_page_size(len));
++              vma = vma->vm_next;
++      }
++      if ((TASK_SIZE - len) < addr)
++              return -ENOMEM;
++      return addr;
++}
++
++static long ioctl_id_alloc(struct ctx *ctx, void __user *arg)
++{
++      struct usdpaa_ioctl_id_alloc i;
++      const struct alloc_backend *backend;
++      struct active_resource *res;
++      int ret = copy_from_user(&i, arg, sizeof(i));
++      if (ret)
++              return ret;
++      if ((i.id_type >= usdpaa_id_max) || !i.num)
++              return -EINVAL;
++      backend = &alloc_backends[i.id_type];
++      /* Allocate the required resource type */
++      ret = backend->alloc(&i.base, i.num, i.align, i.partial);
++      if (ret < 0)
++              return ret;
++      i.num = ret;
++      /* Copy the result to user-space */
++      ret = copy_to_user(arg, &i, sizeof(i));
++      if (ret) {
++              backend->release(i.base, i.num);
++              return ret;
++      }
++      /* Assign the allocated range to the FD accounting */
++      res = kmalloc(sizeof(*res), GFP_KERNEL);
++      if (!res) {
++              backend->release(i.base, i.num);
++              return -ENOMEM;
++      }
++      spin_lock(&ctx->lock);
++      res->id = i.base;
++      res->num = i.num;
++      res->refcount = 1;
++      list_add(&res->list, &ctx->resources[i.id_type]);
++      spin_unlock(&ctx->lock);
++      return 0;
++}
++
++static long ioctl_id_release(struct ctx *ctx, void __user *arg)
++{
++      struct usdpaa_ioctl_id_release i;
++      const struct alloc_backend *backend;
++      struct active_resource *tmp, *pos;
++
++      int ret = copy_from_user(&i, arg, sizeof(i));
++      if (ret)
++              return ret;
++      if ((i.id_type >= usdpaa_id_max) || !i.num)
++              return -EINVAL;
++      backend = &alloc_backends[i.id_type];
++      /* Pull the range out of the FD accounting - the range is valid iff this
++       * succeeds. */
++      spin_lock(&ctx->lock);
++      list_for_each_entry_safe(pos, tmp, &ctx->resources[i.id_type], list) {
++              if (pos->id == i.base && pos->num == i.num) {
++                      pos->refcount--;
++                      if (pos->refcount) {
++                              spin_unlock(&ctx->lock);
++                              return 0; /* Still being used */
++                      }
++                      list_del(&pos->list);
++                      kfree(pos);
++                      spin_unlock(&ctx->lock);
++                      goto found;
++              }
++      }
++      /* Failed to find the resource */
++      spin_unlock(&ctx->lock);
++      pr_err("Couldn't find resource type %d base 0x%x num %d\n",
++             i.id_type, i.base, i.num);
++      return -EINVAL;
++found:
++      /* Release the resource to the backend */
++      backend->release(i.base, i.num);
++      return 0;
++}
++
++static long ioctl_id_reserve(struct ctx *ctx, void __user *arg)
++{
++      struct usdpaa_ioctl_id_reserve i;
++      const struct alloc_backend *backend;
++      struct active_resource *tmp, *pos;
++
++      int ret = copy_from_user(&i, arg, sizeof(i));
++      if (ret)
++              return ret;
++      if ((i.id_type >= usdpaa_id_max) || !i.num)
++              return -EINVAL;
++      backend = &alloc_backends[i.id_type];
++      if (!backend->reserve)
++              return -EINVAL;
++      /* Pull the range out of the FD accounting - the range is valid iff this
++       * succeeds. */
++      spin_lock(&ctx->lock);
++      list_for_each_entry_safe(pos, tmp, &ctx->resources[i.id_type], list) {
++              if (pos->id == i.base && pos->num == i.num) {
++                      pos->refcount++;
++                      spin_unlock(&ctx->lock);
++                      return 0;
++              }
++      }
++
++      /* Failed to find the resource */
++      spin_unlock(&ctx->lock);
++
++      /* Reserve the resource in the backend */
++      ret = backend->reserve(i.base, i.num);
++      if (ret)
++              return ret;
++      /* Assign the reserved range to the FD accounting */
++      pos = kmalloc(sizeof(*pos), GFP_KERNEL);
++      if (!pos) {
++              backend->release(i.base, i.num);
++              return -ENOMEM;
++      }
++      spin_lock(&ctx->lock);
++      pos->id = i.base;
++      pos->num = i.num;
++      pos->refcount = 1;
++      list_add(&pos->list, &ctx->resources[i.id_type]);
++      spin_unlock(&ctx->lock);
++      return 0;
++}
++
++static long ioctl_dma_map(struct file *fp, struct ctx *ctx,
++                        struct usdpaa_ioctl_dma_map *i)
++{
++      struct mem_fragment *frag, *start_frag, *next_frag;
++      struct mem_mapping *map, *tmp;
++      int ret = 0;
++      u32 largest_page, so_far = 0;
++      int frag_count = 0;
++      unsigned long next_addr = PAGE_SIZE, populate;
++
++      /* error checking to ensure values copied from user space are valid */
++      if (i->len % PAGE_SIZE)
++              return -EINVAL;
++
++      map = kmalloc(sizeof(*map), GFP_KERNEL);
++      if (!map)
++              return -ENOMEM;
++
++      spin_lock(&mem_lock);
++      if (i->flags & USDPAA_DMA_FLAG_SHARE) {
++              list_for_each_entry(frag, &mem_list, list) {
++                      if (frag->refs && (frag->flags &
++                                         USDPAA_DMA_FLAG_SHARE) &&
++                                      !strncmp(i->name, frag->name,
++                                               USDPAA_DMA_NAME_MAX)) {
++                              /* Matching entry */
++                              if ((i->flags & USDPAA_DMA_FLAG_CREATE) &&
++                                  !(i->flags & USDPAA_DMA_FLAG_LAZY)) {
++                                      ret = -EBUSY;
++                                      goto out;
++                              }
++
++                              /* Check to ensure size matches record */
++                              if (i->len != frag->map_len && i->len) {
++                                      pr_err("ioctl_dma_map() Size requested does not match %s and is none zero\n",
++                                      frag->name);
++                                      return -EINVAL;
++                              }
++
++                              /* Check if this has already been mapped
++                                 to this process */
++                              list_for_each_entry(tmp, &ctx->maps, list)
++                                      if (tmp->root_frag == frag) {
++                                              /* Already mapped, just need to
++                                                 inc ref count */
++                                              tmp->refs++;
++                                              kfree(map);
++                                              i->did_create = 0;
++                                              i->len = tmp->total_size;
++                                              i->phys_addr = frag->base;
++                                              i->ptr = tmp->virt_addr;
++                                              spin_unlock(&mem_lock);
++                                              return 0;
++                                      }
++                              /* Matching entry - just need to map */
++                              i->has_locking = frag->has_locking;
++                              i->did_create = 0;
++                              i->len = frag->map_len;
++                              start_frag = frag;
++                              goto do_map;
++                      }
++              }
++              /* No matching entry */
++              if (!(i->flags & USDPAA_DMA_FLAG_CREATE)) {
++                      pr_err("ioctl_dma_map() No matching entry\n");
++                      ret = -ENOMEM;
++                      goto out;
++              }
++      }
++      /* New fragment required, size must be provided. */
++      if (!i->len) {
++              ret = -EINVAL;
++              goto out;
++      }
++
++      /* Find one of more contiguous fragments that satisfy the total length
++         trying to minimize the number of fragments
++         compute the largest page size that the allocation could use */
++      largest_page = largest_page_size(i->len);
++      start_frag = NULL;
++      while (largest_page &&
++             largest_page <= largest_page_size(phys_size) &&
++             start_frag == NULL) {
++              /* Search the list for a frag of that size */
++              list_for_each_entry(frag, &mem_list, list) {
++                      if (!frag->refs && (frag->len == largest_page)) {
++                              /* See if the next x fragments are free
++                                 and can accomidate the size */
++                              u32 found_size = largest_page;
++                              next_frag = list_entry(frag->list.prev,
++                                                     struct mem_fragment,
++                                                     list);
++                              /* If the fragement is too small check
++                                 if the neighbours cab support it */
++                              while (found_size < i->len) {
++                                      if (&mem_list == &next_frag->list)
++                                              break; /* End of list */
++                                      if (next_frag->refs != 0 ||
++                                          next_frag->len == 0)
++                                              break; /* not enough space */
++                                      found_size += next_frag->len;
++                                      next_frag = list_entry(
++                                              next_frag->list.prev,
++                                              struct mem_fragment,
++                                              list);
++                              }
++                              if (found_size >= i->len) {
++                                      /* Success! there is enough contigous
++                                         free space */
++                                      start_frag = frag;
++                                      break;
++                              }
++                      }
++              } /* next frag loop */
++              /* Couldn't statisfy the request with this
++                 largest page size, try a smaller one */
++              largest_page <<= 2;
++      }
++      if (start_frag == NULL) {
++              /* Couldn't find proper amount of space */
++              ret = -ENOMEM;
++              goto out;
++      }
++      i->did_create = 1;
++do_map:
++      /* Verify there is sufficient space to do the mapping */
++      down_write(&current->mm->mmap_sem);
++      next_addr = usdpaa_get_unmapped_area(fp, next_addr, i->len, 0, 0);
++      up_write(&current->mm->mmap_sem);
++
++      if (next_addr & ~PAGE_MASK) {
++              ret = -ENOMEM;
++              goto out;
++      }
++
++      /* We may need to divide the final fragment to accomidate the mapping */
++      next_frag = start_frag;
++      while (so_far != i->len) {
++              BUG_ON(next_frag->len == 0);
++              while ((next_frag->len + so_far) > i->len) {
++                      /* Split frag until they match */
++                      split_frag(next_frag);
++              }
++              so_far += next_frag->len;
++              next_frag->refs++;
++              ++frag_count;
++              next_frag = list_entry(next_frag->list.prev,
++                                     struct mem_fragment, list);
++      }
++      if (i->did_create) {
++              size_t name_len = 0;
++              start_frag->flags = i->flags;
++              strncpy(start_frag->name, i->name, USDPAA_DMA_NAME_MAX);
++              name_len = strnlen(start_frag->name, USDPAA_DMA_NAME_MAX);
++              if (name_len >= USDPAA_DMA_NAME_MAX) {
++                      ret = -EFAULT;
++                      goto out;
++              }
++              start_frag->map_len = i->len;
++              start_frag->has_locking = i->has_locking;
++              init_waitqueue_head(&start_frag->wq);
++              start_frag->owner = NULL;
++      }
++
++      /* Setup the map entry */
++      map->root_frag = start_frag;
++      map->total_size = i->len;
++      map->frag_count = frag_count;
++      map->refs = 1;
++      list_add(&map->list, &ctx->maps);
++      i->phys_addr = start_frag->base;
++out:
++      spin_unlock(&mem_lock);
++
++      if (!ret) {
++              unsigned long longret;
++              down_write(&current->mm->mmap_sem);
++              longret = do_mmap_pgoff(fp, next_addr, map->total_size,
++                                      PROT_READ |
++                                      (i->flags &
++                                       USDPAA_DMA_FLAG_RDONLY ? 0
++                                       : PROT_WRITE),
++                                      MAP_SHARED,
++                                      start_frag->pfn_base,
++                                      &populate,
++                                      NULL);
++              up_write(&current->mm->mmap_sem);
++              if (longret & ~PAGE_MASK) {
++                      ret = (int)longret;
++              } else {
++                      i->ptr = (void *)longret;
++                      map->virt_addr = i->ptr;
++              }
++      } else
++              kfree(map);
++      return ret;
++}
++
++static long ioctl_dma_unmap(struct ctx *ctx, void __user *arg)
++{
++      struct mem_mapping *map;
++      struct vm_area_struct *vma;
++      int ret, i;
++      struct mem_fragment *current_frag;
++      size_t sz;
++      unsigned long base;
++      unsigned long vaddr;
++
++      down_write(&current->mm->mmap_sem);
++      vma = find_vma(current->mm, (unsigned long)arg);
++      if (!vma || (vma->vm_start > (unsigned long)arg)) {
++              up_write(&current->mm->mmap_sem);
++              return -EFAULT;
++      }
++      spin_lock(&mem_lock);
++      list_for_each_entry(map, &ctx->maps, list) {
++              if (map->root_frag->pfn_base == vma->vm_pgoff) {
++                      /* Drop the map lock if we hold it */
++                      if (map->root_frag->has_locking &&
++                                      (map->root_frag->owner == map)) {
++                              map->root_frag->owner = NULL;
++                              wake_up(&map->root_frag->wq);
++                      }
++                      goto map_match;
++              }
++      }
++      /* Failed to find a matching mapping for this process */
++      ret = -EFAULT;
++      spin_unlock(&mem_lock);
++      goto out;
++map_match:
++      map->refs--;
++      if (map->refs != 0) {
++              /* Another call the dma_map is referencing this */
++              ret = 0;
++              spin_unlock(&mem_lock);
++              goto out;
++      }
++
++      current_frag = map->root_frag;
++      vaddr = (unsigned long) map->virt_addr;
++      for (i = 0; i < map->frag_count; i++) {
++              DPA_ASSERT(current_frag->refs > 0);
++              --current_frag->refs;
++#if !(defined(CONFIG_ARM) || defined(CONFIG_ARM64))
++              /*
++               * Make sure we invalidate the TLB entry for
++               * this fragment, otherwise a remap of a different
++               * page to this vaddr would give acces to an
++               * incorrect piece of memory
++               */
++              cleartlbcam(vaddr, mfspr(SPRN_PID));
++#endif
++              vaddr += current_frag->len;
++              current_frag = list_entry(current_frag->list.prev,
++                                        struct mem_fragment, list);
++      }
++      map->root_frag->name[0] = 0;
++      list_del(&map->list);
++      compress_frags();
++      spin_unlock(&mem_lock);
++
++      base = vma->vm_start;
++      sz = vma->vm_end - vma->vm_start;
++      do_munmap(current->mm, base, sz, NULL);
++      ret = 0;
++ out:
++      up_write(&current->mm->mmap_sem);
++      return ret;
++}
++
++static long ioctl_dma_stats(struct ctx *ctx, void __user *arg)
++{
++      struct mem_fragment *frag;
++      struct usdpaa_ioctl_dma_used result;
++
++      result.free_bytes = 0;
++      result.total_bytes = phys_size;
++
++      list_for_each_entry(frag, &mem_list, list) {
++              if (frag->refs == 0)
++                      result.free_bytes += frag->len;
++      }
++
++      return copy_to_user(arg, &result, sizeof(result)); }
++
++static int test_lock(struct mem_mapping *map)
++{
++      int ret = 0;
++      spin_lock(&mem_lock);
++      if (!map->root_frag->owner) {
++              map->root_frag->owner = map;
++              ret = 1;
++      }
++      spin_unlock(&mem_lock);
++      return ret;
++}
++
++static long ioctl_dma_lock(struct ctx *ctx, void __user *arg)
++{
++      struct mem_mapping *map;
++      struct vm_area_struct *vma;
++
++      down_read(&current->mm->mmap_sem);
++      vma = find_vma(current->mm, (unsigned long)arg);
++      if (!vma || (vma->vm_start > (unsigned long)arg)) {
++              up_read(&current->mm->mmap_sem);
++              return -EFAULT;
++      }
++      spin_lock(&mem_lock);
++      list_for_each_entry(map, &ctx->maps, list) {
++              if (map->root_frag->pfn_base == vma->vm_pgoff)
++                      goto map_match;
++      }
++      map = NULL;
++map_match:
++      spin_unlock(&mem_lock);
++      up_read(&current->mm->mmap_sem);
++
++      if (!map)
++              return -EFAULT;
++      if (!map->root_frag->has_locking)
++              return -ENODEV;
++      return wait_event_interruptible(map->root_frag->wq, test_lock(map));
++}
++
++static long ioctl_dma_unlock(struct ctx *ctx, void __user *arg)
++{
++      struct mem_mapping *map;
++      struct vm_area_struct *vma;
++      int ret;
++
++      down_read(&current->mm->mmap_sem);
++      vma = find_vma(current->mm, (unsigned long)arg);
++      if (!vma || (vma->vm_start > (unsigned long)arg))
++              ret = -EFAULT;
++      else {
++              spin_lock(&mem_lock);
++              list_for_each_entry(map, &ctx->maps, list) {
++                      if (map->root_frag->pfn_base == vma->vm_pgoff) {
++                              if (!map->root_frag->has_locking)
++                                      ret = -ENODEV;
++                              else if (map->root_frag->owner == map) {
++                                      map->root_frag->owner = NULL;
++                                      wake_up(&map->root_frag->wq);
++                                      ret = 0;
++                              } else
++                                      ret = -EBUSY;
++                              goto map_match;
++                      }
++              }
++              ret = -EINVAL;
++map_match:
++              spin_unlock(&mem_lock);
++      }
++      up_read(&current->mm->mmap_sem);
++      return ret;
++}
++
++static int portal_mmap(struct file *fp, struct resource *res, void **ptr)
++{
++      unsigned long longret = 0, populate;
++      resource_size_t len;
++
++      down_write(&current->mm->mmap_sem);
++      len = resource_size(res);
++      if (len != (unsigned long)len)
++              return -EINVAL;
++      longret = do_mmap_pgoff(fp, PAGE_SIZE, (unsigned long)len,
++                              PROT_READ | PROT_WRITE, MAP_SHARED,
++                              res->start >> PAGE_SHIFT, &populate, NULL);
++      up_write(&current->mm->mmap_sem);
++
++      if (longret & ~PAGE_MASK)
++              return (int)longret;
++
++      *ptr = (void *) longret;
++      return 0;
++}
++
++static void portal_munmap(struct resource *res, void  *ptr)
++{
++      down_write(&current->mm->mmap_sem);
++      do_munmap(current->mm, (unsigned long)ptr, resource_size(res), NULL);
++      up_write(&current->mm->mmap_sem);
++}
++
++static long ioctl_portal_map(struct file *fp, struct ctx *ctx,
++                           struct usdpaa_ioctl_portal_map  *arg)
++{
++      struct portal_mapping *mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
++      int ret;
++
++      if (!mapping)
++              return -ENOMEM;
++
++      mapping->user = *arg;
++      mapping->iommu_domain = NULL;
++
++      if (mapping->user.type == usdpaa_portal_qman) {
++              mapping->qportal =
++                      qm_get_unused_portal_idx(mapping->user.index);
++              if (!mapping->qportal) {
++                      ret = -ENODEV;
++                      goto err_get_portal;
++              }
++              mapping->phys = &mapping->qportal->addr_phys[0];
++              mapping->user.channel = mapping->qportal->public_cfg.channel;
++              mapping->user.pools = mapping->qportal->public_cfg.pools;
++              mapping->user.index = mapping->qportal->public_cfg.index;
++      } else if (mapping->user.type == usdpaa_portal_bman) {
++              mapping->bportal =
++                      bm_get_unused_portal_idx(mapping->user.index);
++              if (!mapping->bportal) {
++                      ret = -ENODEV;
++                      goto err_get_portal;
++              }
++              mapping->phys = &mapping->bportal->addr_phys[0];
++              mapping->user.index = mapping->bportal->public_cfg.index;
++      } else {
++              ret = -EINVAL;
++              goto err_copy_from_user;
++      }
++      /* Need to put pcfg in ctx's list before the mmaps because the mmap
++       * handlers look it up. */
++      spin_lock(&mem_lock);
++      list_add(&mapping->list, &ctx->portals);
++      spin_unlock(&mem_lock);
++      ret = portal_mmap(fp, &mapping->phys[DPA_PORTAL_CE],
++                        &mapping->user.addr.cena);
++      if (ret)
++              goto err_mmap_cena;
++      ret = portal_mmap(fp, &mapping->phys[DPA_PORTAL_CI],
++                        &mapping->user.addr.cinh);
++      if (ret)
++              goto err_mmap_cinh;
++      *arg = mapping->user;
++      return ret;
++
++err_mmap_cinh:
++      portal_munmap(&mapping->phys[DPA_PORTAL_CE], mapping->user.addr.cena);
++err_mmap_cena:
++      if ((mapping->user.type == usdpaa_portal_qman) && mapping->qportal)
++              qm_put_unused_portal(mapping->qportal);
++      else if ((mapping->user.type == usdpaa_portal_bman) && mapping->bportal)
++              bm_put_unused_portal(mapping->bportal);
++      spin_lock(&mem_lock);
++      list_del(&mapping->list);
++      spin_unlock(&mem_lock);
++err_get_portal:
++err_copy_from_user:
++      kfree(mapping);
++      return ret;
++}
++
++static long ioctl_portal_unmap(struct ctx *ctx, struct usdpaa_portal_map *i)
++{
++      struct portal_mapping *mapping;
++      struct vm_area_struct *vma;
++      unsigned long pfn;
++      u32 channel;
++
++      /* Get the PFN corresponding to one of the virt addresses */
++      down_read(&current->mm->mmap_sem);
++      vma = find_vma(current->mm, (unsigned long)i->cinh);
++      if (!vma || (vma->vm_start > (unsigned long)i->cinh)) {
++              up_read(&current->mm->mmap_sem);
++              return -EFAULT;
++      }
++      pfn = vma->vm_pgoff;
++      up_read(&current->mm->mmap_sem);
++
++      /* Find the corresponding portal */
++      spin_lock(&mem_lock);
++      list_for_each_entry(mapping, &ctx->portals, list) {
++              if (pfn == (mapping->phys[DPA_PORTAL_CI].start >> PAGE_SHIFT))
++                      goto found;
++      }
++      mapping = NULL;
++found:
++      if (mapping)
++              list_del(&mapping->list);
++      spin_unlock(&mem_lock);
++      if (!mapping)
++              return -ENODEV;
++      portal_munmap(&mapping->phys[DPA_PORTAL_CI], mapping->user.addr.cinh);
++      portal_munmap(&mapping->phys[DPA_PORTAL_CE], mapping->user.addr.cena);
++      if (mapping->user.type == usdpaa_portal_qman) {
++              init_qm_portal(mapping->qportal,
++                                     &mapping->qman_portal_low);
++
++              /* Tear down any FQs this portal is referencing */
++              channel = mapping->qportal->public_cfg.channel;
++              qm_check_and_destroy_fqs(&mapping->qman_portal_low,
++                                       &channel,
++                                       check_portal_channel);
++              qm_put_unused_portal(mapping->qportal);
++      } else if (mapping->user.type == usdpaa_portal_bman) {
++              init_bm_portal(mapping->bportal,
++                             &mapping->bman_portal_low);
++              bm_put_unused_portal(mapping->bportal);
++      }
++      kfree(mapping);
++      return 0;
++}
++
++static void portal_config_pamu(struct qm_portal_config *pcfg, uint8_t sdest,
++                             uint32_t cpu, uint32_t cache, uint32_t window)
++{
++#ifdef CONFIG_FSL_PAMU
++      int ret;
++      int window_count = 1;
++      struct iommu_domain_geometry geom_attr;
++      struct pamu_stash_attribute stash_attr;
++
++      pcfg->iommu_domain = iommu_domain_alloc(&platform_bus_type);
++      if (!pcfg->iommu_domain) {
++              pr_err(KBUILD_MODNAME ":%s(): iommu_domain_alloc() failed",
++                         __func__);
++              goto _no_iommu;
++      }
++      geom_attr.aperture_start = 0;
++      geom_attr.aperture_end =
++              ((dma_addr_t)1 << min(8 * sizeof(dma_addr_t), (size_t)36)) - 1;
++      geom_attr.force_aperture = true;
++      ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_GEOMETRY,
++                                  &geom_attr);
++      if (ret < 0) {
++              pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
++                         __func__, ret);
++              goto _iommu_domain_free;
++      }
++      ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_WINDOWS,
++                                  &window_count);
++      if (ret < 0) {
++              pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
++                         __func__, ret);
++              goto _iommu_domain_free;
++      }
++      stash_attr.cpu = cpu;
++      stash_attr.cache = cache;
++      /* set stash information for the window */
++      stash_attr.window = 0;
++
++      ret = iommu_domain_set_attr(pcfg->iommu_domain,
++                                  DOMAIN_ATTR_FSL_PAMU_STASH,
++                                  &stash_attr);
++      if (ret < 0) {
++              pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
++                         __func__, ret);
++              goto _iommu_domain_free;
++      }
++      ret = iommu_domain_window_enable(pcfg->iommu_domain, 0, 0, 1ULL << 36,
++                                       IOMMU_READ | IOMMU_WRITE);
++      if (ret < 0) {
++              pr_err(KBUILD_MODNAME ":%s(): iommu_domain_window_enable() = %d",
++                         __func__, ret);
++              goto _iommu_domain_free;
++      }
++      ret = iommu_attach_device(pcfg->iommu_domain, &pcfg->dev);
++      if (ret < 0) {
++              pr_err(KBUILD_MODNAME ":%s(): iommu_device_attach() = %d",
++                         __func__, ret);
++              goto _iommu_domain_free;
++      }
++      ret = iommu_domain_set_attr(pcfg->iommu_domain,
++                                  DOMAIN_ATTR_FSL_PAMU_ENABLE,
++                                  &window_count);
++      if (ret < 0) {
++              pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
++                         __func__, ret);
++              goto _iommu_detach_device;
++      }
++_no_iommu:
++#endif
++
++#ifdef CONFIG_FSL_QMAN_CONFIG
++      if (qman_set_sdest(pcfg->public_cfg.channel, sdest))
++#endif
++              pr_warn("Failed to set QMan portal's stash request queue\n");
++
++      return;
++
++#ifdef CONFIG_FSL_PAMU
++_iommu_detach_device:
++      iommu_detach_device(pcfg->iommu_domain, NULL);
++_iommu_domain_free:
++      iommu_domain_free(pcfg->iommu_domain);
++#endif
++}
++
++static long ioctl_allocate_raw_portal(struct file *fp, struct ctx *ctx,
++                                    struct usdpaa_ioctl_raw_portal *arg)
++{
++      struct portal_mapping *mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
++      int ret;
++
++      if (!mapping)
++              return -ENOMEM;
++
++      mapping->user.type = arg->type;
++      mapping->iommu_domain = NULL;
++      if (arg->type == usdpaa_portal_qman) {
++              mapping->qportal = qm_get_unused_portal_idx(arg->index);
++              if (!mapping->qportal) {
++                      ret = -ENODEV;
++                      goto err;
++              }
++              mapping->phys = &mapping->qportal->addr_phys[0];
++              arg->index = mapping->qportal->public_cfg.index;
++              arg->cinh = mapping->qportal->addr_phys[DPA_PORTAL_CI].start;
++              arg->cena = mapping->qportal->addr_phys[DPA_PORTAL_CE].start;
++              if (arg->enable_stash) {
++                      /* Setup the PAMU with the supplied parameters */
++                      portal_config_pamu(mapping->qportal, arg->sdest,
++                                         arg->cpu, arg->cache, arg->window);
++              }
++      } else if (mapping->user.type == usdpaa_portal_bman) {
++              mapping->bportal =
++                      bm_get_unused_portal_idx(arg->index);
++              if (!mapping->bportal) {
++                      ret = -ENODEV;
++                      goto err;
++              }
++              mapping->phys = &mapping->bportal->addr_phys[0];
++              arg->index = mapping->bportal->public_cfg.index;
++              arg->cinh = mapping->bportal->addr_phys[DPA_PORTAL_CI].start;
++              arg->cena = mapping->bportal->addr_phys[DPA_PORTAL_CE].start;
++      } else {
++              ret = -EINVAL;
++              goto err;
++      }
++      /* Need to put pcfg in ctx's list before the mmaps because the mmap
++       * handlers look it up. */
++      spin_lock(&mem_lock);
++      list_add(&mapping->list, &ctx->portals);
++      spin_unlock(&mem_lock);
++      return 0;
++err:
++      kfree(mapping);
++      return ret;
++}
++
++static long ioctl_free_raw_portal(struct file *fp, struct ctx *ctx,
++                                    struct usdpaa_ioctl_raw_portal *arg)
++{
++      struct portal_mapping *mapping;
++      u32 channel;
++
++      /* Find the corresponding portal */
++      spin_lock(&mem_lock);
++      list_for_each_entry(mapping, &ctx->portals, list) {
++              if (mapping->phys[DPA_PORTAL_CI].start == arg->cinh)
++                      goto found;
++      }
++      mapping = NULL;
++found:
++      if (mapping)
++              list_del(&mapping->list);
++      spin_unlock(&mem_lock);
++      if (!mapping)
++              return -ENODEV;
++      if (mapping->user.type == usdpaa_portal_qman) {
++              init_qm_portal(mapping->qportal,
++                                     &mapping->qman_portal_low);
++
++              /* Tear down any FQs this portal is referencing */
++              channel = mapping->qportal->public_cfg.channel;
++              qm_check_and_destroy_fqs(&mapping->qman_portal_low,
++                                       &channel,
++                                       check_portal_channel);
++              qm_put_unused_portal(mapping->qportal);
++      } else if (mapping->user.type == usdpaa_portal_bman) {
++              init_bm_portal(mapping->bportal,
++                             &mapping->bman_portal_low);
++              bm_put_unused_portal(mapping->bportal);
++      }
++      kfree(mapping);
++      return 0;
++}
++
++static long usdpaa_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
++{
++      struct ctx *ctx = fp->private_data;
++      void __user *a = (void __user *)arg;
++      switch (cmd) {
++      case USDPAA_IOCTL_ID_ALLOC:
++              return ioctl_id_alloc(ctx, a);
++      case USDPAA_IOCTL_ID_RELEASE:
++              return ioctl_id_release(ctx, a);
++      case USDPAA_IOCTL_ID_RESERVE:
++              return ioctl_id_reserve(ctx, a);
++      case USDPAA_IOCTL_DMA_MAP:
++      {
++              struct usdpaa_ioctl_dma_map input;
++              int ret;
++              if (copy_from_user(&input, a, sizeof(input)))
++                      return -EFAULT;
++              ret = ioctl_dma_map(fp, ctx, &input);
++              if (copy_to_user(a, &input, sizeof(input)))
++                      return -EFAULT;
++              return ret;
++      }
++      case USDPAA_IOCTL_DMA_UNMAP:
++              return ioctl_dma_unmap(ctx, a);
++      case USDPAA_IOCTL_DMA_LOCK:
++              return ioctl_dma_lock(ctx, a);
++      case USDPAA_IOCTL_DMA_UNLOCK:
++              return ioctl_dma_unlock(ctx, a);
++      case USDPAA_IOCTL_PORTAL_MAP:
++      {
++              struct usdpaa_ioctl_portal_map input;
++              int ret;
++              if (copy_from_user(&input, a, sizeof(input)))
++                      return -EFAULT;
++              ret =  ioctl_portal_map(fp, ctx, &input);
++              if (copy_to_user(a, &input, sizeof(input)))
++                      return -EFAULT;
++              return ret;
++      }
++      case USDPAA_IOCTL_PORTAL_UNMAP:
++      {
++              struct usdpaa_portal_map input;
++              if (copy_from_user(&input, a, sizeof(input)))
++                      return -EFAULT;
++              return ioctl_portal_unmap(ctx, &input);
++      }
++      case USDPAA_IOCTL_DMA_USED:
++              return ioctl_dma_stats(ctx, a);
++      case USDPAA_IOCTL_ALLOC_RAW_PORTAL:
++      {
++              struct usdpaa_ioctl_raw_portal input;
++              int ret;
++              if (copy_from_user(&input, a, sizeof(input)))
++                      return -EFAULT;
++              ret = ioctl_allocate_raw_portal(fp, ctx, &input);
++              if (copy_to_user(a, &input, sizeof(input)))
++                      return -EFAULT;
++              return ret;
++      }
++      case USDPAA_IOCTL_FREE_RAW_PORTAL:
++      {
++              struct usdpaa_ioctl_raw_portal input;
++              if (copy_from_user(&input, a, sizeof(input)))
++                      return -EFAULT;
++              return ioctl_free_raw_portal(fp, ctx, &input);
++      }
++      }
++      return -EINVAL;
++}
++
++static long usdpaa_ioctl_compat(struct file *fp, unsigned int cmd,
++                              unsigned long arg)
++{
++#ifdef CONFIG_COMPAT
++      struct ctx *ctx = fp->private_data;
++      void __user *a = (void __user *)arg;
++#endif
++      switch (cmd) {
++#ifdef CONFIG_COMPAT
++      case USDPAA_IOCTL_DMA_MAP_COMPAT:
++      {
++              int ret;
++              struct usdpaa_ioctl_dma_map_compat input;
++              struct usdpaa_ioctl_dma_map converted;
++
++              if (copy_from_user(&input, a, sizeof(input)))
++                      return -EFAULT;
++
++              converted.ptr = compat_ptr(input.ptr);
++              converted.phys_addr = input.phys_addr;
++              converted.len = input.len;
++              converted.flags = input.flags;
++              strncpy(converted.name, input.name, USDPAA_DMA_NAME_MAX);
++              converted.has_locking = input.has_locking;
++              converted.did_create = input.did_create;
++
++              ret = ioctl_dma_map(fp, ctx, &converted);
++              input.ptr = ptr_to_compat(converted.ptr);
++              input.phys_addr = converted.phys_addr;
++              input.len = converted.len;
++              input.flags = converted.flags;
++              strncpy(input.name, converted.name, USDPAA_DMA_NAME_MAX);
++              input.has_locking = converted.has_locking;
++              input.did_create = converted.did_create;
++              if (copy_to_user(a, &input, sizeof(input)))
++                      return -EFAULT;
++              return ret;
++      }
++      case USDPAA_IOCTL_PORTAL_MAP_COMPAT:
++      {
++              int ret;
++              struct compat_usdpaa_ioctl_portal_map input;
++              struct usdpaa_ioctl_portal_map converted;
++              if (copy_from_user(&input, a, sizeof(input)))
++                      return -EFAULT;
++              converted.type = input.type;
++              converted.index = input.index;
++              ret = ioctl_portal_map(fp, ctx, &converted);
++              input.addr.cinh = ptr_to_compat(converted.addr.cinh);
++              input.addr.cena = ptr_to_compat(converted.addr.cena);
++              input.channel = converted.channel;
++              input.pools = converted.pools;
++              input.index = converted.index;
++              if (copy_to_user(a, &input, sizeof(input)))
++                      return -EFAULT;
++              return ret;
++      }
++      case USDPAA_IOCTL_PORTAL_UNMAP_COMPAT:
++      {
++              struct usdpaa_portal_map_compat input;
++              struct usdpaa_portal_map converted;
++
++              if (copy_from_user(&input, a, sizeof(input)))
++                      return -EFAULT;
++              converted.cinh = compat_ptr(input.cinh);
++              converted.cena = compat_ptr(input.cena);
++              return ioctl_portal_unmap(ctx, &converted);
++      }
++      case USDPAA_IOCTL_ALLOC_RAW_PORTAL_COMPAT:
++      {
++              int ret;
++              struct usdpaa_ioctl_raw_portal converted;
++              struct compat_ioctl_raw_portal input;
++              if (copy_from_user(&input, a, sizeof(input)))
++                      return -EFAULT;
++              converted.type = input.type;
++              converted.index = input.index;
++              converted.enable_stash = input.enable_stash;
++              converted.cpu = input.cpu;
++              converted.cache = input.cache;
++              converted.window = input.window;
++              converted.sdest = input.sdest;
++              ret = ioctl_allocate_raw_portal(fp, ctx, &converted);
++
++              input.cinh = converted.cinh;
++              input.cena = converted.cena;
++              input.index = converted.index;
++
++              if (copy_to_user(a, &input, sizeof(input)))
++                      return -EFAULT;
++              return ret;
++      }
++      case USDPAA_IOCTL_FREE_RAW_PORTAL_COMPAT:
++      {
++              struct usdpaa_ioctl_raw_portal converted;
++              struct compat_ioctl_raw_portal input;
++              if (copy_from_user(&input, a, sizeof(input)))
++                      return -EFAULT;
++              converted.type = input.type;
++              converted.index = input.index;
++              converted.cinh = input.cinh;
++              converted.cena = input.cena;
++              return ioctl_free_raw_portal(fp, ctx, &converted);
++      }
++#endif
++      default:
++              return usdpaa_ioctl(fp, cmd, arg);
++      }
++      return -EINVAL;
++}
++
++int usdpaa_get_portal_config(struct file *filp, void *cinh,
++                           enum usdpaa_portal_type ptype, unsigned int *irq,
++                           void **iir_reg)
++{
++      /* Walk the list of portals for filp and return the config
++         for the portal that matches the hint */
++      struct ctx *context;
++      struct portal_mapping *portal;
++
++      /* First sanitize the filp */
++      if (filp->f_op->open != usdpaa_open)
++              return -ENODEV;
++      context = filp->private_data;
++      spin_lock(&context->lock);
++      list_for_each_entry(portal, &context->portals, list) {
++              if (portal->user.type == ptype &&
++                  portal->user.addr.cinh == cinh) {
++                      if (ptype == usdpaa_portal_qman) {
++                              *irq = portal->qportal->public_cfg.irq;
++                              *iir_reg = portal->qportal->addr_virt[1] +
++                                      QM_REG_IIR;
++                      } else {
++                              *irq = portal->bportal->public_cfg.irq;
++                              *iir_reg = portal->bportal->addr_virt[1] +
++                                      BM_REG_IIR;
++                      }
++                      spin_unlock(&context->lock);
++                      return 0;
++              }
++      }
++      spin_unlock(&context->lock);
++      return -EINVAL;
++}
++
++static const struct file_operations usdpaa_fops = {
++      .open              = usdpaa_open,
++      .release           = usdpaa_release,
++      .mmap              = usdpaa_mmap,
++      .get_unmapped_area = usdpaa_get_unmapped_area,
++      .unlocked_ioctl    = usdpaa_ioctl,
++      .compat_ioctl      = usdpaa_ioctl_compat
++};
++
++static struct miscdevice usdpaa_miscdev = {
++      .name = "fsl-usdpaa",
++      .fops = &usdpaa_fops,
++      .minor = MISC_DYNAMIC_MINOR,
++};
++
++/* Early-boot memory allocation. The boot-arg "usdpaa_mem=<x>" is used to
++ * indicate how much memory (if any) to allocate during early boot. If the
++ * format "usdpaa_mem=<x>,<y>" is used, then <y> will be interpreted as the
++ * number of TLB1 entries to reserve (default is 1). If there are more mappings
++ * than there are TLB1 entries, fault-handling will occur. */
++
++static __init int usdpaa_mem(char *arg)
++{
++      pr_warn("uspdaa_mem argument is depracated\n");
++      arg_phys_size = memparse(arg, &arg);
++      num_tlb = 1;
++      if (*arg == ',') {
++              unsigned long ul;
++              int err = kstrtoul(arg + 1, 0, &ul);
++              if (err < 0) {
++                      num_tlb = 1;
++                      pr_warn("ERROR, usdpaa_mem arg is invalid\n");
++              } else
++                      num_tlb = (unsigned int)ul;
++      }
++      return 0;
++}
++early_param("usdpaa_mem", usdpaa_mem);
++
++static int usdpaa_mem_init(struct reserved_mem *rmem)
++{
++      phys_start = rmem->base;
++      phys_size = rmem->size;
++
++      WARN_ON(!(phys_start && phys_size));
++
++      return 0;
++}
++RESERVEDMEM_OF_DECLARE(usdpaa_mem_init, "fsl,usdpaa-mem", usdpaa_mem_init);
++
++__init int fsl_usdpaa_init_early(void)
++{
++      if (!phys_size || !phys_start) {
++              pr_info("No USDPAA memory, no 'fsl,usdpaa-mem' in device-tree\n");
++              return 0;
++      }
++      if (phys_size % PAGE_SIZE) {
++              pr_err("'fsl,usdpaa-mem' size must be a multiple of page size\n");
++              phys_size = 0;
++              return 0;
++      }
++      if (arg_phys_size && phys_size != arg_phys_size) {
++              pr_err("'usdpaa_mem argument size (0x%llx) does not match device tree size (0x%llx)\n",
++                     arg_phys_size, phys_size);
++              phys_size = 0;
++              return 0;
++      }
++      pfn_start = phys_start >> PAGE_SHIFT;
++      pfn_size = phys_size >> PAGE_SHIFT;
++#ifdef CONFIG_PPC
++      first_tlb = current_tlb = tlbcam_index;
++      tlbcam_index += num_tlb;
++#endif
++      pr_info("USDPAA region at %llx:%llx(%lx:%lx), %d TLB1 entries)\n",
++              phys_start, phys_size, pfn_start, pfn_size, num_tlb);
++      return 0;
++}
++subsys_initcall(fsl_usdpaa_init_early);
++
++
++static int __init usdpaa_init(void)
++{
++      struct mem_fragment *frag;
++      int ret;
++      u64 tmp_size = phys_size;
++      u64 tmp_start = phys_start;
++      u64 tmp_pfn_size = pfn_size;
++      u64 tmp_pfn_start = pfn_start;
++
++      pr_info("Freescale USDPAA process driver\n");
++      if (!phys_start) {
++              pr_warn("fsl-usdpaa: no region found\n");
++              return 0;
++      }
++
++      while (tmp_size != 0) {
++              u32 frag_size = largest_page_size(tmp_size);
++              frag = kmalloc(sizeof(*frag), GFP_KERNEL);
++              if (!frag) {
++                      pr_err("Failed to setup USDPAA memory accounting\n");
++                      return -ENOMEM;
++              }
++              frag->base = tmp_start;
++              frag->len = frag->root_len = frag_size;
++              frag->root_pfn = tmp_pfn_start;
++              frag->pfn_base = tmp_pfn_start;
++              frag->pfn_len = frag_size / PAGE_SIZE;
++              frag->refs = 0;
++              init_waitqueue_head(&frag->wq);
++              frag->owner = NULL;
++              list_add(&frag->list, &mem_list);
++
++              /* Adjust for this frag */
++              tmp_start += frag_size;
++              tmp_size -= frag_size;
++              tmp_pfn_start += frag_size / PAGE_SIZE;
++              tmp_pfn_size -= frag_size / PAGE_SIZE;
++      }
++      ret = misc_register(&usdpaa_miscdev);
++      if (ret)
++              pr_err("fsl-usdpaa: failed to register misc device\n");
++      return ret;
++}
++
++static void __exit usdpaa_exit(void)
++{
++      misc_deregister(&usdpaa_miscdev);
++}
++
++module_init(usdpaa_init);
++module_exit(usdpaa_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Freescale Semiconductor");
++MODULE_DESCRIPTION("Freescale USDPAA process driver");
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/fsl_usdpaa_irq.c
+@@ -0,0 +1,289 @@
++/* Copyright (c) 2013 Freescale Semiconductor, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* define a device that allows USPDAA processes to open a file
++   descriptor and specify which IRQ it wants to montior using an ioctl()
++   When an IRQ is received, the device becomes readable so that a process
++   can use read() or select() type calls to monitor for IRQs */
++
++#include <linux/miscdevice.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/poll.h>
++#include <linux/uaccess.h>
++#include <linux/fsl_usdpaa.h>
++#include <linux/module.h>
++#include <linux/fdtable.h>
++#include <linux/file.h>
++
++#include "qman_low.h"
++#include "bman_low.h"
++
++struct usdpaa_irq_ctx {
++      int irq_set; /* Set to true once the irq is set via ioctl */
++      unsigned int irq_num;
++      u32 last_irq_count; /* Last value returned from read */
++      u32 irq_count; /* Number of irqs since last read */
++      wait_queue_head_t wait_queue; /* Waiting processes */
++      spinlock_t lock;
++      void *inhibit_addr; /* inhibit register address */
++      struct file *usdpaa_filp;
++      char irq_name[128];
++};
++
++static int usdpaa_irq_open(struct inode *inode, struct file *filp)
++{
++      struct usdpaa_irq_ctx *ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
++      if (!ctx)
++              return -ENOMEM;
++      ctx->irq_set = 0;
++      ctx->irq_count = 0;
++      ctx->last_irq_count = 0;
++      init_waitqueue_head(&ctx->wait_queue);
++      spin_lock_init(&ctx->lock);
++      filp->private_data = ctx;
++      return 0;
++}
++
++static int usdpaa_irq_release(struct inode *inode, struct file *filp)
++{
++      struct usdpaa_irq_ctx *ctx = filp->private_data;
++      if (ctx->irq_set) {
++              /* Inhibit the IRQ */
++              out_be32(ctx->inhibit_addr, 0x1);
++              irq_set_affinity_hint(ctx->irq_num, NULL);
++              free_irq(ctx->irq_num, ctx);
++              ctx->irq_set = 0;
++              fput(ctx->usdpaa_filp);
++      }
++      kfree(filp->private_data);
++      return 0;
++}
++
++static irqreturn_t usdpaa_irq_handler(int irq, void *_ctx)
++{
++      unsigned long flags;
++      struct usdpaa_irq_ctx *ctx = _ctx;
++      spin_lock_irqsave(&ctx->lock, flags);
++      ++ctx->irq_count;
++      spin_unlock_irqrestore(&ctx->lock, flags);
++      wake_up_all(&ctx->wait_queue);
++      /* Set the inhibit register.  This will be reenabled
++         once the USDPAA code handles the IRQ */
++      out_be32(ctx->inhibit_addr, 0x1);
++      pr_info("Inhibit at %p count %d", ctx->inhibit_addr, ctx->irq_count);
++      return IRQ_HANDLED;
++}
++
++static int map_irq(struct file *fp, struct usdpaa_ioctl_irq_map *irq_map)
++{
++      struct usdpaa_irq_ctx *ctx = fp->private_data;
++      int ret;
++
++      if (ctx->irq_set) {
++              pr_debug("Setting USDPAA IRQ when it was already set!\n");
++              return -EBUSY;
++      }
++
++      ctx->usdpaa_filp = fget(irq_map->fd);
++      if (!ctx->usdpaa_filp) {
++              pr_debug("USDPAA fget(%d) returned NULL\n", irq_map->fd);
++              return -EINVAL;
++      }
++
++      ret = usdpaa_get_portal_config(ctx->usdpaa_filp, irq_map->portal_cinh,
++                                     irq_map->type, &ctx->irq_num,
++                                     &ctx->inhibit_addr);
++      if (ret) {
++              pr_debug("USDPAA IRQ couldn't identify portal\n");
++              fput(ctx->usdpaa_filp);
++              return ret;
++      }
++
++      ctx->irq_set = 1;
++
++      snprintf(ctx->irq_name, sizeof(ctx->irq_name),
++               "usdpaa_irq %d", ctx->irq_num);
++
++      ret = request_irq(ctx->irq_num, usdpaa_irq_handler, 0,
++                        ctx->irq_name, ctx);
++      if (ret) {
++              pr_err("USDPAA request_irq(%d) failed, ret= %d\n",
++                     ctx->irq_num, ret);
++              ctx->irq_set = 0;
++              fput(ctx->usdpaa_filp);
++              return ret;
++      }
++      ret = irq_set_affinity(ctx->irq_num, &current->cpus_allowed);
++      if (ret)
++              pr_err("USDPAA irq_set_affinity() failed, ret= %d\n", ret);
++
++      ret = irq_set_affinity_hint(ctx->irq_num, &current->cpus_allowed);
++      if (ret)
++              pr_err("USDPAA irq_set_affinity_hint() failed, ret= %d\n", ret);
++
++      return 0;
++}
++
++static long usdpaa_irq_ioctl(struct file *fp, unsigned int cmd,
++                           unsigned long arg)
++{
++      int ret;
++      struct usdpaa_ioctl_irq_map irq_map;
++
++      if (cmd != USDPAA_IOCTL_PORTAL_IRQ_MAP) {
++              pr_debug("USDPAA IRQ unknown command 0x%x\n", cmd);
++              return -EINVAL;
++      }
++
++      ret = copy_from_user(&irq_map, (void __user *)arg,
++                           sizeof(irq_map));
++      if (ret)
++              return ret;
++      return map_irq(fp, &irq_map);
++}
++
++static ssize_t usdpaa_irq_read(struct file *filp, char __user *buff,
++                             size_t count, loff_t *offp)
++{
++      struct usdpaa_irq_ctx *ctx = filp->private_data;
++      int ret;
++
++      if (!ctx->irq_set) {
++              pr_debug("Reading USDPAA IRQ before it was set\n");
++              return -EINVAL;
++      }
++
++      if (count < sizeof(ctx->irq_count)) {
++              pr_debug("USDPAA IRQ Read too small\n");
++              return -EINVAL;
++      }
++      if (ctx->irq_count == ctx->last_irq_count) {
++              if (filp->f_flags & O_NONBLOCK)
++                      return -EAGAIN;
++
++              ret = wait_event_interruptible(ctx->wait_queue,
++                                     ctx->irq_count != ctx->last_irq_count);
++              if (ret == -ERESTARTSYS)
++                      return ret;
++      }
++
++      ctx->last_irq_count = ctx->irq_count;
++
++      if (copy_to_user(buff, &ctx->last_irq_count,
++                       sizeof(ctx->last_irq_count)))
++              return -EFAULT;
++      return sizeof(ctx->irq_count);
++}
++
++static unsigned int usdpaa_irq_poll(struct file *filp, poll_table *wait)
++{
++      struct usdpaa_irq_ctx *ctx = filp->private_data;
++      unsigned int ret = 0;
++      unsigned long flags;
++
++      if (!ctx->irq_set)
++              return POLLHUP;
++
++      poll_wait(filp, &ctx->wait_queue, wait);
++
++      spin_lock_irqsave(&ctx->lock, flags);
++      if (ctx->irq_count != ctx->last_irq_count)
++              ret |= POLLIN | POLLRDNORM;
++      spin_unlock_irqrestore(&ctx->lock, flags);
++      return ret;
++}
++
++static long usdpaa_irq_ioctl_compat(struct file *fp, unsigned int cmd,
++                              unsigned long arg)
++{
++#ifdef CONFIG_COMPAT
++      void __user *a = (void __user *)arg;
++#endif
++      switch (cmd) {
++#ifdef CONFIG_COMPAT
++      case  USDPAA_IOCTL_PORTAL_IRQ_MAP_COMPAT:
++      {
++              struct compat_ioctl_irq_map input;
++              struct usdpaa_ioctl_irq_map converted;
++              if (copy_from_user(&input, a, sizeof(input)))
++                      return -EFAULT;
++              converted.type = input.type;
++              converted.fd = input.fd;
++              converted.portal_cinh = compat_ptr(input.portal_cinh);
++              return map_irq(fp, &converted);
++      }
++#endif
++      default:
++              return usdpaa_irq_ioctl(fp, cmd, arg);
++      }
++}
++
++static const struct file_operations usdpaa_irq_fops = {
++      .open              = usdpaa_irq_open,
++      .release           = usdpaa_irq_release,
++      .unlocked_ioctl    = usdpaa_irq_ioctl,
++      .compat_ioctl      = usdpaa_irq_ioctl_compat,
++      .read              = usdpaa_irq_read,
++      .poll              = usdpaa_irq_poll
++};
++
++static struct miscdevice usdpaa_miscdev = {
++      .name = "fsl-usdpaa-irq",
++      .fops = &usdpaa_irq_fops,
++      .minor = MISC_DYNAMIC_MINOR,
++};
++
++static int __init usdpaa_irq_init(void)
++{
++      int ret;
++
++      pr_info("Freescale USDPAA process IRQ driver\n");
++      ret = misc_register(&usdpaa_miscdev);
++      if (ret)
++              pr_err("fsl-usdpaa-irq: failed to register misc device\n");
++      return ret;
++}
++
++static void __exit usdpaa_irq_exit(void)
++{
++      misc_deregister(&usdpaa_miscdev);
++}
++
++module_init(usdpaa_irq_init);
++module_exit(usdpaa_irq_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Freescale Semiconductor");
++MODULE_DESCRIPTION("Freescale USDPAA process IRQ driver");
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/qbman_driver.c
+@@ -0,0 +1,88 @@
++/* Copyright 2013 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/time.h>
++#include "qman_private.h"
++#include "bman_private.h"
++__init void qman_init_early(void);
++__init void bman_init_early(void);
++
++static __init int qbman_init(void)
++{
++      struct device_node *dn;
++      u32 is_portal_available;
++
++      bman_init();
++      qman_init();
++
++      is_portal_available = 0;
++      for_each_compatible_node(dn, NULL, "fsl,qman-portal") {
++              if (!of_device_is_available(dn))
++                      continue;
++              else
++                      is_portal_available = 1;
++      }
++
++      if (!qman_have_ccsr() && is_portal_available) {
++              struct qman_fq fq = {
++                              .fqid = 1
++              };
++              struct qm_mcr_queryfq_np np;
++              int err, retry = CONFIG_FSL_QMAN_INIT_TIMEOUT;
++              struct timespec nowts, diffts, startts = current_kernel_time();
++              /* Loop while querying given fqid succeeds or time out */
++              while (1) {
++                      err = qman_query_fq_np(&fq, &np);
++                      if (!err) {
++                              /* success, control-plane has configured QMan */
++                              break;
++                      } else if (err != -ERANGE) {
++                              pr_err("QMan: I/O error, continuing anyway\n");
++                              break;
++                      }
++                      nowts = current_kernel_time();
++                      diffts = timespec_sub(nowts, startts);
++                      if (diffts.tv_sec > 0) {
++                              if (!retry--) {
++                                      pr_err("QMan: time out, control-plane"
++                                                              " dead?\n");
++                                      break;
++                              }
++                              pr_warn("QMan: polling for the control-plane"
++                                                      " (%d)\n", retry);
++                      }
++              }
++      }
++      bman_resource_init();
++      qman_resource_init();
++      return 0;
++}
++subsys_initcall(qbman_init);
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/qman_config.c
+@@ -0,0 +1,1224 @@
++/* Copyright 2008-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <asm/cacheflush.h>
++#include "qman_private.h"
++#include <linux/highmem.h>
++#include <linux/of_reserved_mem.h>
++
++/* Last updated for v00.800 of the BG */
++
++/* Register offsets */
++#define REG_QCSP_LIO_CFG(n)   (0x0000 + ((n) * 0x10))
++#define REG_QCSP_IO_CFG(n)    (0x0004 + ((n) * 0x10))
++#define REG_QCSP_DD_CFG(n)    (0x000c + ((n) * 0x10))
++#define REG_DD_CFG            0x0200
++#define REG_DCP_CFG(n)                (0x0300 + ((n) * 0x10))
++#define REG_DCP_DD_CFG(n)     (0x0304 + ((n) * 0x10))
++#define REG_DCP_DLM_AVG(n)    (0x030c + ((n) * 0x10))
++#define REG_PFDR_FPC          0x0400
++#define REG_PFDR_FP_HEAD      0x0404
++#define REG_PFDR_FP_TAIL      0x0408
++#define REG_PFDR_FP_LWIT      0x0410
++#define REG_PFDR_CFG          0x0414
++#define REG_SFDR_CFG          0x0500
++#define REG_SFDR_IN_USE               0x0504
++#define REG_WQ_CS_CFG(n)      (0x0600 + ((n) * 0x04))
++#define REG_WQ_DEF_ENC_WQID   0x0630
++#define REG_WQ_SC_DD_CFG(n)   (0x640 + ((n) * 0x04))
++#define REG_WQ_PC_DD_CFG(n)   (0x680 + ((n) * 0x04))
++#define REG_WQ_DC0_DD_CFG(n)  (0x6c0 + ((n) * 0x04))
++#define REG_WQ_DC1_DD_CFG(n)  (0x700 + ((n) * 0x04))
++#define REG_WQ_DCn_DD_CFG(n)  (0x6c0 + ((n) * 0x40)) /* n=2,3 */
++#define REG_CM_CFG            0x0800
++#define REG_ECSR              0x0a00
++#define REG_ECIR              0x0a04
++#define REG_EADR              0x0a08
++#define REG_ECIR2             0x0a0c
++#define REG_EDATA(n)          (0x0a10 + ((n) * 0x04))
++#define REG_SBEC(n)           (0x0a80 + ((n) * 0x04))
++#define REG_MCR                       0x0b00
++#define REG_MCP(n)            (0x0b04 + ((n) * 0x04))
++#define REG_MISC_CFG          0x0be0
++#define REG_HID_CFG           0x0bf0
++#define REG_IDLE_STAT         0x0bf4
++#define REG_IP_REV_1          0x0bf8
++#define REG_IP_REV_2          0x0bfc
++#define REG_FQD_BARE          0x0c00
++#define REG_PFDR_BARE         0x0c20
++#define REG_offset_BAR                0x0004  /* relative to REG_[FQD|PFDR]_BARE */
++#define REG_offset_AR         0x0010  /* relative to REG_[FQD|PFDR]_BARE */
++#define REG_QCSP_BARE         0x0c80
++#define REG_QCSP_BAR          0x0c84
++#define REG_CI_SCHED_CFG      0x0d00
++#define REG_SRCIDR            0x0d04
++#define REG_LIODNR            0x0d08
++#define REG_CI_RLM_AVG                0x0d14
++#define REG_ERR_ISR           0x0e00  /* + "enum qm_isr_reg" */
++#define REG_REV3_QCSP_LIO_CFG(n)      (0x1000 + ((n) * 0x10))
++#define REG_REV3_QCSP_IO_CFG(n)       (0x1004 + ((n) * 0x10))
++#define REG_REV3_QCSP_DD_CFG(n)       (0x100c + ((n) * 0x10))
++#define REG_CEETM_CFG_IDX     0x900
++#define REG_CEETM_CFG_PRES    0x904
++#define REG_CEETM_XSFDR_IN_USE        0x908
++
++/* Assists for QMAN_MCR */
++#define MCR_INIT_PFDR         0x01000000
++#define MCR_get_rslt(v)               (u8)((v) >> 24)
++#define MCR_rslt_idle(r)      (!rslt || (rslt >= 0xf0))
++#define MCR_rslt_ok(r)                (rslt == 0xf0)
++#define MCR_rslt_eaccess(r)   (rslt == 0xf8)
++#define MCR_rslt_inval(r)     (rslt == 0xff)
++
++struct qman;
++
++/* Follows WQ_CS_CFG0-5 */
++enum qm_wq_class {
++      qm_wq_portal = 0,
++      qm_wq_pool = 1,
++      qm_wq_fman0 = 2,
++      qm_wq_fman1 = 3,
++      qm_wq_caam = 4,
++      qm_wq_pme = 5,
++      qm_wq_first = qm_wq_portal,
++      qm_wq_last = qm_wq_pme
++};
++
++/* Follows FQD_[BARE|BAR|AR] and PFDR_[BARE|BAR|AR] */
++enum qm_memory {
++      qm_memory_fqd,
++      qm_memory_pfdr
++};
++
++/* Used by all error interrupt registers except 'inhibit' */
++#define QM_EIRQ_CIDE  0x20000000      /* Corenet Initiator Data Error */
++#define QM_EIRQ_CTDE  0x10000000      /* Corenet Target Data Error */
++#define QM_EIRQ_CITT  0x08000000      /* Corenet Invalid Target Transaction */
++#define QM_EIRQ_PLWI  0x04000000      /* PFDR Low Watermark */
++#define QM_EIRQ_MBEI  0x02000000      /* Multi-bit ECC Error */
++#define QM_EIRQ_SBEI  0x01000000      /* Single-bit ECC Error */
++#define QM_EIRQ_PEBI  0x00800000      /* PFDR Enqueues Blocked Interrupt */
++#define QM_EIRQ_IFSI  0x00020000      /* Invalid FQ Flow Control State */
++#define QM_EIRQ_ICVI  0x00010000      /* Invalid Command Verb */
++#define QM_EIRQ_IDDI  0x00000800      /* Invalid Dequeue (Direct-connect) */
++#define QM_EIRQ_IDFI  0x00000400      /* Invalid Dequeue FQ */
++#define QM_EIRQ_IDSI  0x00000200      /* Invalid Dequeue Source */
++#define QM_EIRQ_IDQI  0x00000100      /* Invalid Dequeue Queue */
++#define QM_EIRQ_IECE  0x00000010      /* Invalid Enqueue Configuration */
++#define QM_EIRQ_IEOI  0x00000008      /* Invalid Enqueue Overflow */
++#define QM_EIRQ_IESI  0x00000004      /* Invalid Enqueue State */
++#define QM_EIRQ_IECI  0x00000002      /* Invalid Enqueue Channel */
++#define QM_EIRQ_IEQI  0x00000001      /* Invalid Enqueue Queue */
++
++/* QMAN_ECIR valid error bit */
++#define PORTAL_ECSR_ERR       (QM_EIRQ_IEQI | QM_EIRQ_IESI | QM_EIRQ_IEOI | \
++                              QM_EIRQ_IDQI | QM_EIRQ_IDSI | QM_EIRQ_IDFI | \
++                              QM_EIRQ_IDDI | QM_EIRQ_ICVI | QM_EIRQ_IFSI)
++#define FQID_ECSR_ERR (QM_EIRQ_IEQI | QM_EIRQ_IECI | QM_EIRQ_IESI | \
++                      QM_EIRQ_IEOI | QM_EIRQ_IDQI | QM_EIRQ_IDFI | \
++                      QM_EIRQ_IFSI)
++
++union qman_ecir {
++      u32 ecir_raw;
++      struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++              u32 __reserved:2;
++              u32 portal_type:1;
++              u32 portal_num:5;
++              u32 fqid:24;
++#else
++              u32 fqid:24;
++              u32 portal_num:5;
++              u32 portal_type:1;
++              u32 __reserved:2;
++#endif
++      } __packed info;
++};
++
++union qman_ecir2 {
++      u32 ecir2_raw;
++      struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++              u32 portal_type:1;
++              u32 __reserved:21;
++              u32 portal_num:10;
++#else
++              u32 portal_num:10;
++              u32 __reserved:21;
++              u32 portal_type:1;
++#endif
++      } __packed info;
++};
++
++union qman_eadr {
++      u32 eadr_raw;
++      struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++              u32 __reserved1:4;
++              u32 memid:4;
++              u32 __reserved2:12;
++              u32 eadr:12;
++#else
++              u32 eadr:12;
++              u32 __reserved2:12;
++              u32 memid:4;
++              u32 __reserved1:4;
++#endif
++      } __packed info;
++      struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++              u32 __reserved1:3;
++              u32 memid:5;
++              u32 __reserved:8;
++              u32 eadr:16;
++#else
++              u32 eadr:16;
++              u32 __reserved:8;
++              u32 memid:5;
++              u32 __reserved1:3;
++#endif
++      } __packed info_rev3;
++};
++
++struct qman_hwerr_txt {
++      u32 mask;
++      const char *txt;
++};
++
++#define QMAN_HWE_TXT(a, b) { .mask = QM_EIRQ_##a, .txt = b }
++
++static const struct qman_hwerr_txt qman_hwerr_txts[] = {
++      QMAN_HWE_TXT(CIDE, "Corenet Initiator Data Error"),
++      QMAN_HWE_TXT(CTDE, "Corenet Target Data Error"),
++      QMAN_HWE_TXT(CITT, "Corenet Invalid Target Transaction"),
++      QMAN_HWE_TXT(PLWI, "PFDR Low Watermark"),
++      QMAN_HWE_TXT(MBEI, "Multi-bit ECC Error"),
++      QMAN_HWE_TXT(SBEI, "Single-bit ECC Error"),
++      QMAN_HWE_TXT(PEBI, "PFDR Enqueues Blocked Interrupt"),
++      QMAN_HWE_TXT(ICVI, "Invalid Command Verb"),
++      QMAN_HWE_TXT(IFSI, "Invalid Flow Control State"),
++      QMAN_HWE_TXT(IDDI, "Invalid Dequeue (Direct-connect)"),
++      QMAN_HWE_TXT(IDFI, "Invalid Dequeue FQ"),
++      QMAN_HWE_TXT(IDSI, "Invalid Dequeue Source"),
++      QMAN_HWE_TXT(IDQI, "Invalid Dequeue Queue"),
++      QMAN_HWE_TXT(IECE, "Invalid Enqueue Configuration"),
++      QMAN_HWE_TXT(IEOI, "Invalid Enqueue Overflow"),
++      QMAN_HWE_TXT(IESI, "Invalid Enqueue State"),
++      QMAN_HWE_TXT(IECI, "Invalid Enqueue Channel"),
++      QMAN_HWE_TXT(IEQI, "Invalid Enqueue Queue")
++};
++#define QMAN_HWE_COUNT (sizeof(qman_hwerr_txts)/sizeof(struct qman_hwerr_txt))
++
++struct qman_error_info_mdata {
++      u16 addr_mask;
++      u16 bits;
++      const char *txt;
++};
++
++#define QMAN_ERR_MDATA(a, b, c) { .addr_mask = a, .bits = b, .txt = c}
++static const struct qman_error_info_mdata error_mdata[] = {
++      QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 0"),
++      QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 1"),
++      QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 2"),
++      QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 3"),
++      QMAN_ERR_MDATA(0x0FFF, 512, "FQD cache memory"),
++      QMAN_ERR_MDATA(0x07FF, 128, "SFDR memory"),
++      QMAN_ERR_MDATA(0x01FF, 72, "WQ context memory"),
++      QMAN_ERR_MDATA(0x00FF, 240, "CGR memory"),
++      QMAN_ERR_MDATA(0x00FF, 302, "Internal Order Restoration List memory"),
++      QMAN_ERR_MDATA(0x01FF, 256, "SW portal ring memory"),
++      QMAN_ERR_MDATA(0x07FF, 181, "CEETM class queue descriptor memory"),
++      QMAN_ERR_MDATA(0x0FFF, 140, "CEETM extended SFDR memory"),
++      QMAN_ERR_MDATA(0x0FFF, 25, "CEETM logical FQ mapping memory"),
++      QMAN_ERR_MDATA(0x0FFF, 96, "CEETM dequeue context memory"),
++      QMAN_ERR_MDATA(0x07FF, 396, "CEETM ccgr memory"),
++      QMAN_ERR_MDATA(0x00FF, 146, "CEETM CQ channel shaping memory"),
++      QMAN_ERR_MDATA(0x007F, 256, "CEETM CQ channel scheduling memory"),
++      QMAN_ERR_MDATA(0x01FF, 88, "CEETM dequeue statistics memory"),
++};
++#define QMAN_ERR_MDATA_COUNT \
++      (sizeof(error_mdata)/sizeof(struct qman_error_info_mdata))
++
++/* Add this in Kconfig */
++#define QMAN_ERRS_TO_UNENABLE (QM_EIRQ_PLWI | QM_EIRQ_PEBI)
++
++/**
++ * qm_err_isr_<reg>_<verb> - Manipulate global interrupt registers
++ * @v: for accessors that write values, this is the 32-bit value
++ *
++ * Manipulates QMAN_ERR_ISR, QMAN_ERR_IER, QMAN_ERR_ISDR, QMAN_ERR_IIR. All
++ * manipulations except qm_err_isr_[un]inhibit() use 32-bit masks composed of
++ * the QM_EIRQ_*** definitions. Note that "qm_err_isr_enable_write" means
++ * "write the enable register" rather than "enable the write register"!
++ */
++#define qm_err_isr_status_read(qm)    \
++              __qm_err_isr_read(qm, qm_isr_status)
++#define qm_err_isr_status_clear(qm, m)        \
++              __qm_err_isr_write(qm, qm_isr_status, m)
++#define qm_err_isr_enable_read(qm)    \
++              __qm_err_isr_read(qm, qm_isr_enable)
++#define qm_err_isr_enable_write(qm, v)        \
++              __qm_err_isr_write(qm, qm_isr_enable, v)
++#define qm_err_isr_disable_read(qm)   \
++              __qm_err_isr_read(qm, qm_isr_disable)
++#define qm_err_isr_disable_write(qm, v)       \
++              __qm_err_isr_write(qm, qm_isr_disable, v)
++#define qm_err_isr_inhibit(qm)                \
++              __qm_err_isr_write(qm, qm_isr_inhibit, 1)
++#define qm_err_isr_uninhibit(qm)      \
++              __qm_err_isr_write(qm, qm_isr_inhibit, 0)
++
++/*
++ * TODO: unimplemented registers
++ *
++ * Keeping a list here of Qman registers I have not yet covered;
++ * QCSP_DD_IHRSR, QCSP_DD_IHRFR, QCSP_DD_HASR,
++ * DCP_DD_IHRSR, DCP_DD_IHRFR, DCP_DD_HASR, CM_CFG,
++ * QMAN_EECC, QMAN_SBET, QMAN_EINJ, QMAN_SBEC0-12
++ */
++
++/* Encapsulate "struct qman *" as a cast of the register space address. */
++
++static struct qman *qm_create(void *regs)
++{
++      return (struct qman *)regs;
++}
++
++static inline u32 __qm_in(struct qman *qm, u32 offset)
++{
++      return in_be32((void *)qm + offset);
++}
++static inline void __qm_out(struct qman *qm, u32 offset, u32 val)
++{
++      out_be32((void *)qm + offset, val);
++}
++#define qm_in(reg)            __qm_in(qm, REG_##reg)
++#define qm_out(reg, val)      __qm_out(qm, REG_##reg, val)
++
++static u32 __qm_err_isr_read(struct qman *qm, enum qm_isr_reg n)
++{
++      return __qm_in(qm, REG_ERR_ISR + (n << 2));
++}
++
++static void __qm_err_isr_write(struct qman *qm, enum qm_isr_reg n, u32 val)
++{
++      __qm_out(qm, REG_ERR_ISR + (n << 2), val);
++}
++
++static void qm_set_dc(struct qman *qm, enum qm_dc_portal portal,
++                      int ed, u8 sernd)
++{
++      DPA_ASSERT(!ed || (portal == qm_dc_portal_fman0) ||
++                      (portal == qm_dc_portal_fman1));
++      if ((qman_ip_rev & 0xFF00) >= QMAN_REV30)
++              qm_out(DCP_CFG(portal), (ed ? 0x1000 : 0) | (sernd & 0x3ff));
++      else
++              qm_out(DCP_CFG(portal), (ed ? 0x100 : 0) | (sernd & 0x1f));
++}
++
++static void qm_set_wq_scheduling(struct qman *qm, enum qm_wq_class wq_class,
++                      u8 cs_elev, u8 csw2, u8 csw3, u8 csw4, u8 csw5,
++                      u8 csw6, u8 csw7)
++{
++      qm_out(WQ_CS_CFG(wq_class), ((cs_elev & 0xff) << 24) |
++              ((csw2 & 0x7) << 20) | ((csw3 & 0x7) << 16) |
++              ((csw4 & 0x7) << 12) | ((csw5 & 0x7) << 8) |
++              ((csw6 & 0x7) << 4) | (csw7 & 0x7));
++}
++
++static void qm_set_hid(struct qman *qm)
++{
++      qm_out(HID_CFG, 0);
++}
++
++static void qm_set_corenet_initiator(struct qman *qm)
++{
++      qm_out(CI_SCHED_CFG,
++              0x80000000 | /* write srcciv enable */
++              (CONFIG_FSL_QMAN_CI_SCHED_CFG_SRCCIV << 24) |
++              (CONFIG_FSL_QMAN_CI_SCHED_CFG_SRQ_W << 8) |
++              (CONFIG_FSL_QMAN_CI_SCHED_CFG_RW_W << 4) |
++              CONFIG_FSL_QMAN_CI_SCHED_CFG_BMAN_W);
++}
++
++static void qm_get_version(struct qman *qm, u16 *id, u8 *major, u8 *minor,
++                      u8 *cfg)
++{
++      u32 v = qm_in(IP_REV_1);
++      u32 v2 = qm_in(IP_REV_2);
++      *id = (v >> 16);
++      *major = (v >> 8) & 0xff;
++      *minor = v & 0xff;
++      *cfg = v2 & 0xff;
++}
++
++static void qm_set_memory(struct qman *qm, enum qm_memory memory, u64 ba,
++                      int enable, int prio, int stash, u32 size)
++{
++      u32 offset = (memory == qm_memory_fqd) ? REG_FQD_BARE : REG_PFDR_BARE;
++      u32 exp = ilog2(size);
++      /* choke if size isn't within range */
++      DPA_ASSERT((size >= 4096) && (size <= 1073741824) &&
++                      is_power_of_2(size));
++      /* choke if 'ba' has lower-alignment than 'size' */
++      DPA_ASSERT(!(ba & (size - 1)));
++      __qm_out(qm, offset, upper_32_bits(ba));
++      __qm_out(qm, offset + REG_offset_BAR, lower_32_bits(ba));
++      __qm_out(qm, offset + REG_offset_AR,
++              (enable ? 0x80000000 : 0) |
++              (prio ? 0x40000000 : 0) |
++              (stash ? 0x20000000 : 0) |
++              (exp - 1));
++}
++
++static void qm_set_pfdr_threshold(struct qman *qm, u32 th, u8 k)
++{
++      qm_out(PFDR_FP_LWIT, th & 0xffffff);
++      qm_out(PFDR_CFG, k);
++}
++
++static void qm_set_sfdr_threshold(struct qman *qm, u16 th)
++{
++      qm_out(SFDR_CFG, th & 0x3ff);
++}
++
++static int qm_init_pfdr(struct qman *qm, u32 pfdr_start, u32 num)
++{
++      u8 rslt = MCR_get_rslt(qm_in(MCR));
++
++      DPA_ASSERT(pfdr_start && !(pfdr_start & 7) && !(num & 7) && num);
++      /* Make sure the command interface is 'idle' */
++      if (!MCR_rslt_idle(rslt))
++              panic("QMAN_MCR isn't idle");
++
++      /* Write the MCR command params then the verb */
++      qm_out(MCP(0), pfdr_start);
++      /* TODO: remove this - it's a workaround for a model bug that is
++       * corrected in more recent versions. We use the workaround until
++       * everyone has upgraded. */
++      qm_out(MCP(1), (pfdr_start + num - 16));
++      lwsync();
++      qm_out(MCR, MCR_INIT_PFDR);
++      /* Poll for the result */
++      do {
++              rslt = MCR_get_rslt(qm_in(MCR));
++      } while (!MCR_rslt_idle(rslt));
++      if (MCR_rslt_ok(rslt))
++              return 0;
++      if (MCR_rslt_eaccess(rslt))
++              return -EACCES;
++      if (MCR_rslt_inval(rslt))
++              return -EINVAL;
++      pr_crit("Unexpected result from MCR_INIT_PFDR: %02x\n", rslt);
++      return -ENOSYS;
++}
++
++/*****************/
++/* Config driver */
++/*****************/
++
++#define DEFAULT_FQD_SZ        (PAGE_SIZE << CONFIG_FSL_QMAN_FQD_SZ)
++#define DEFAULT_PFDR_SZ       (PAGE_SIZE << CONFIG_FSL_QMAN_PFDR_SZ)
++
++/* We support only one of these */
++static struct qman *qm;
++static struct device_node *qm_node;
++
++/* And this state belongs to 'qm'. It is set during fsl_qman_init(), but used
++ * during qman_init_ccsr(). */
++static dma_addr_t fqd_a, pfdr_a;
++static size_t fqd_sz = DEFAULT_FQD_SZ, pfdr_sz = DEFAULT_PFDR_SZ;
++
++static int qman_fqd(struct reserved_mem *rmem)
++{
++      fqd_a = rmem->base;
++      fqd_sz = rmem->size;
++
++      WARN_ON(!(fqd_a && fqd_sz));
++
++      return 0;
++}
++RESERVEDMEM_OF_DECLARE(qman_fqd, "fsl,qman-fqd", qman_fqd);
++
++static int qman_pfdr(struct reserved_mem *rmem)
++{
++      pfdr_a = rmem->base;
++      pfdr_sz = rmem->size;
++
++      WARN_ON(!(pfdr_a && pfdr_sz));
++
++      return 0;
++}
++RESERVEDMEM_OF_DECLARE(qman_fbpr, "fsl,qman-pfdr", qman_pfdr);
++
++size_t get_qman_fqd_size()
++{
++      return fqd_sz;
++}
++
++/* Parse the <name> property to extract the memory location and size and
++ * memblock_reserve() it. If it isn't supplied, memblock_alloc() the default
++ * size. Also flush this memory range from data cache so that QMAN originated
++ * transactions for this memory region could be marked non-coherent.
++ */
++static __init int parse_mem_property(struct device_node *node, const char *name,
++                              dma_addr_t *addr, size_t *sz, int zero)
++{
++      int ret;
++
++      /* If using a "zero-pma", don't try to zero it, even if you asked */
++      if (zero && of_find_property(node, "zero-pma", &ret)) {
++              pr_info("  it's a 'zero-pma', not zeroing from s/w\n");
++              zero = 0;
++      }
++
++      if (zero) {
++              /* map as cacheable, non-guarded */
++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++              void __iomem *tmpp = ioremap_cache(*addr, *sz);
++#else
++              void __iomem *tmpp = ioremap(*addr, *sz);
++#endif
++
++              if (!tmpp)
++                      return -ENOMEM;
++              memset_io(tmpp, 0, *sz);
++              flush_dcache_range((unsigned long)tmpp,
++                                 (unsigned long)tmpp + *sz);
++              iounmap(tmpp);
++      }
++
++      return 0;
++}
++
++/* TODO:
++ * - there is obviously no handling of errors,
++ * - the calls to qm_set_memory() hard-code the priority and CPC-stashing for
++ *   both memory resources to zero.
++ */
++static int __init fsl_qman_init(struct device_node *node)
++{
++      struct resource res;
++      resource_size_t len;
++      u32 __iomem *regs;
++      const char *s;
++      int ret, standby = 0;
++      u16 id;
++      u8 major, minor, cfg;
++      ret = of_address_to_resource(node, 0, &res);
++      if (ret) {
++              pr_err("Can't get %s property '%s'\n", node->full_name, "reg");
++              return ret;
++      }
++      s = of_get_property(node, "fsl,hv-claimable", &ret);
++      if (s && !strcmp(s, "standby"))
++              standby = 1;
++      if (!standby) {
++              ret = parse_mem_property(node, "fsl,qman-fqd",
++                                      &fqd_a, &fqd_sz, 1);
++              pr_info("qman-fqd addr %pad size 0x%zx\n", &fqd_a, fqd_sz);
++              BUG_ON(ret);
++              ret = parse_mem_property(node, "fsl,qman-pfdr",
++                                      &pfdr_a, &pfdr_sz, 0);
++              pr_info("qman-pfdr addr %pad size 0x%zx\n", &pfdr_a, pfdr_sz);
++              BUG_ON(ret);
++      }
++      /* Global configuration */
++      len = resource_size(&res);
++      if (len != (unsigned long)len)
++              return -EINVAL;
++      regs = ioremap(res.start, (unsigned long)len);
++      qm = qm_create(regs);
++      qm_node = node;
++      qm_get_version(qm, &id, &major, &minor, &cfg);
++      pr_info("Qman ver:%04x,%02x,%02x,%02x\n", id, major, minor, cfg);
++      if (!qman_ip_rev) {
++              if ((major == 1) && (minor == 0)) {
++                      pr_err("QMAN rev1.0 on P4080 rev1 is not supported!\n");
++                      iounmap(regs);
++                      return -ENODEV;
++              } else if ((major == 1) && (minor == 1))
++                      qman_ip_rev = QMAN_REV11;
++              else if ((major == 1) && (minor == 2))
++                      qman_ip_rev = QMAN_REV12;
++              else if ((major == 2) && (minor == 0))
++                      qman_ip_rev = QMAN_REV20;
++              else if ((major == 3) && (minor == 0))
++                      qman_ip_rev = QMAN_REV30;
++              else if ((major == 3) && (minor == 1))
++                      qman_ip_rev = QMAN_REV31;
++              else if ((major == 3) && (minor == 2))
++                      qman_ip_rev = QMAN_REV32;
++              else {
++                      pr_warn("unknown Qman version, default to rev1.1\n");
++                      qman_ip_rev = QMAN_REV11;
++              }
++              qman_ip_cfg = cfg;
++      }
++
++      if (standby) {
++              pr_info("  -> in standby mode\n");
++              return 0;
++      }
++      return 0;
++}
++
++int qman_have_ccsr(void)
++{
++      return qm ? 1 : 0;
++}
++
++__init int qman_init_early(void)
++{
++      struct device_node *dn;
++      int ret;
++
++      for_each_compatible_node(dn, NULL, "fsl,qman") {
++              if (qm)
++                      pr_err("%s: only one 'fsl,qman' allowed\n",
++                              dn->full_name);
++              else {
++                      if (!of_device_is_available(dn))
++                              continue;
++
++                      ret = fsl_qman_init(dn);
++                      BUG_ON(ret);
++              }
++      }
++      return 0;
++}
++postcore_initcall_sync(qman_init_early);
++
++static void log_edata_bits(u32 bit_count)
++{
++      u32 i, j, mask = 0xffffffff;
++
++      pr_warn("Qman ErrInt, EDATA:\n");
++      i = bit_count/32;
++      if (bit_count%32) {
++              i++;
++              mask = ~(mask << bit_count%32);
++      }
++      j = 16-i;
++      pr_warn("  0x%08x\n", qm_in(EDATA(j)) & mask);
++      j++;
++      for (; j < 16; j++)
++              pr_warn("  0x%08x\n", qm_in(EDATA(j)));
++}
++
++static void log_additional_error_info(u32 isr_val, u32 ecsr_val)
++{
++      union qman_ecir ecir_val;
++      union qman_eadr eadr_val;
++
++      ecir_val.ecir_raw = qm_in(ECIR);
++      /* Is portal info valid */
++      if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) {
++              union qman_ecir2 ecir2_val;
++              ecir2_val.ecir2_raw = qm_in(ECIR2);
++              if (ecsr_val & PORTAL_ECSR_ERR) {
++                      pr_warn("Qman ErrInt: %s id %d\n",
++                              (ecir2_val.info.portal_type) ?
++                              "DCP" : "SWP", ecir2_val.info.portal_num);
++              }
++              if (ecsr_val & (FQID_ECSR_ERR | QM_EIRQ_IECE)) {
++                      pr_warn("Qman ErrInt: ecir.fqid 0x%x\n",
++                              ecir_val.info.fqid);
++              }
++              if (ecsr_val & (QM_EIRQ_SBEI|QM_EIRQ_MBEI)) {
++                      eadr_val.eadr_raw = qm_in(EADR);
++                      pr_warn("Qman ErrInt: EADR Memory: %s, 0x%x\n",
++                              error_mdata[eadr_val.info_rev3.memid].txt,
++                              error_mdata[eadr_val.info_rev3.memid].addr_mask
++                                      & eadr_val.info_rev3.eadr);
++                      log_edata_bits(
++                              error_mdata[eadr_val.info_rev3.memid].bits);
++              }
++      } else {
++              if (ecsr_val & PORTAL_ECSR_ERR) {
++                      pr_warn("Qman ErrInt: %s id %d\n",
++                              (ecir_val.info.portal_type) ?
++                              "DCP" : "SWP", ecir_val.info.portal_num);
++              }
++              if (ecsr_val & FQID_ECSR_ERR) {
++                      pr_warn("Qman ErrInt: ecir.fqid 0x%x\n",
++                              ecir_val.info.fqid);
++              }
++              if (ecsr_val & (QM_EIRQ_SBEI|QM_EIRQ_MBEI)) {
++                      eadr_val.eadr_raw = qm_in(EADR);
++                      pr_warn("Qman ErrInt: EADR Memory: %s, 0x%x\n",
++                              error_mdata[eadr_val.info.memid].txt,
++                              error_mdata[eadr_val.info.memid].addr_mask
++                                      & eadr_val.info.eadr);
++                      log_edata_bits(error_mdata[eadr_val.info.memid].bits);
++              }
++      }
++}
++
++/* Qman interrupt handler */
++static irqreturn_t qman_isr(int irq, void *ptr)
++{
++      u32 isr_val, ier_val, ecsr_val, isr_mask, i;
++
++      ier_val = qm_err_isr_enable_read(qm);
++      isr_val = qm_err_isr_status_read(qm);
++      ecsr_val = qm_in(ECSR);
++      isr_mask = isr_val & ier_val;
++
++      if (!isr_mask)
++              return IRQ_NONE;
++      for (i = 0; i < QMAN_HWE_COUNT; i++) {
++              if (qman_hwerr_txts[i].mask & isr_mask) {
++                      pr_warn("Qman ErrInt: %s\n", qman_hwerr_txts[i].txt);
++                      if (qman_hwerr_txts[i].mask & ecsr_val) {
++                              log_additional_error_info(isr_mask, ecsr_val);
++                              /* Re-arm error capture registers */
++                              qm_out(ECSR, ecsr_val);
++                      }
++                      if (qman_hwerr_txts[i].mask & QMAN_ERRS_TO_UNENABLE) {
++                              pr_devel("Qman un-enabling error 0x%x\n",
++                                      qman_hwerr_txts[i].mask);
++                              ier_val &= ~qman_hwerr_txts[i].mask;
++                              qm_err_isr_enable_write(qm, ier_val);
++                      }
++              }
++      }
++      qm_err_isr_status_clear(qm, isr_val);
++      return IRQ_HANDLED;
++}
++
++static int __bind_irq(void)
++{
++      int ret, err_irq;
++
++      err_irq = of_irq_to_resource(qm_node, 0, NULL);
++      if (err_irq == 0) {
++              pr_info("Can't get %s property '%s'\n", qm_node->full_name,
++                      "interrupts");
++              return -ENODEV;
++      }
++      ret = request_irq(err_irq, qman_isr, IRQF_SHARED, "qman-err", qm_node);
++      if (ret)  {
++              pr_err("request_irq() failed %d for '%s'\n", ret,
++                      qm_node->full_name);
++              return -ENODEV;
++      }
++      /* Write-to-clear any stale bits, (eg. starvation being asserted prior
++       * to resource allocation during driver init). */
++      qm_err_isr_status_clear(qm, 0xffffffff);
++      /* Enable Error Interrupts */
++      qm_err_isr_enable_write(qm, 0xffffffff);
++      return 0;
++}
++
++int qman_init_ccsr(struct device_node *node)
++{
++      int ret;
++      if (!qman_have_ccsr())
++              return 0;
++      if (node != qm_node)
++              return -EINVAL;
++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++      /* TEMP for LS1043 : should be done in uboot */
++      qm_out(QCSP_BARE, 0x5);
++      qm_out(QCSP_BAR, 0x0);
++#endif
++      /* FQD memory */
++      qm_set_memory(qm, qm_memory_fqd, fqd_a, 1, 0, 0, fqd_sz);
++      /* PFDR memory */
++      qm_set_memory(qm, qm_memory_pfdr, pfdr_a, 1, 0, 0, pfdr_sz);
++      qm_init_pfdr(qm, 8, pfdr_sz / 64 - 8);
++      /* thresholds */
++      qm_set_pfdr_threshold(qm, 512, 64);
++      qm_set_sfdr_threshold(qm, 128);
++      /* clear stale PEBI bit from interrupt status register */
++      qm_err_isr_status_clear(qm, QM_EIRQ_PEBI);
++      /* corenet initiator settings */
++      qm_set_corenet_initiator(qm);
++      /* HID settings */
++      qm_set_hid(qm);
++      /* Set scheduling weights to defaults */
++      for (ret = qm_wq_first; ret <= qm_wq_last; ret++)
++              qm_set_wq_scheduling(qm, ret, 0, 0, 0, 0, 0, 0, 0);
++      /* We are not prepared to accept ERNs for hardware enqueues */
++      qm_set_dc(qm, qm_dc_portal_fman0, 1, 0);
++      qm_set_dc(qm, qm_dc_portal_fman1, 1, 0);
++      /* Initialise Error Interrupt Handler */
++      ret = __bind_irq();
++      if (ret)
++              return ret;
++      return 0;
++}
++
++#define LIO_CFG_LIODN_MASK 0x0fff0000
++void qman_liodn_fixup(u16 channel)
++{
++      static int done;
++      static u32 liodn_offset;
++      u32 before, after;
++      int idx = channel - QM_CHANNEL_SWPORTAL0;
++
++      if (!qman_have_ccsr())
++              return;
++      if ((qman_ip_rev & 0xFF00) >= QMAN_REV30)
++              before = qm_in(REV3_QCSP_LIO_CFG(idx));
++      else
++              before = qm_in(QCSP_LIO_CFG(idx));
++      if (!done) {
++              liodn_offset = before & LIO_CFG_LIODN_MASK;
++              done = 1;
++              return;
++      }
++      after = (before & (~LIO_CFG_LIODN_MASK)) | liodn_offset;
++      if ((qman_ip_rev & 0xFF00) >= QMAN_REV30)
++              qm_out(REV3_QCSP_LIO_CFG(idx), after);
++      else
++              qm_out(QCSP_LIO_CFG(idx), after);
++}
++
++#define IO_CFG_SDEST_MASK 0x00ff0000
++int qman_set_sdest(u16 channel, unsigned int cpu_idx)
++{
++      int idx = channel - QM_CHANNEL_SWPORTAL0;
++      u32 before, after;
++
++      if (!qman_have_ccsr())
++              return -ENODEV;
++      if ((qman_ip_rev & 0xFF00) == QMAN_REV31) {
++              /* LS1043A - only one L2 cache */
++              cpu_idx = 0;
++      }
++
++      if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) {
++              before = qm_in(REV3_QCSP_IO_CFG(idx));
++              /* Each pair of vcpu share the same SRQ(SDEST) */
++              cpu_idx /= 2;
++              after = (before & (~IO_CFG_SDEST_MASK)) | (cpu_idx << 16);
++              qm_out(REV3_QCSP_IO_CFG(idx), after);
++      } else {
++              before = qm_in(QCSP_IO_CFG(idx));
++              after = (before & (~IO_CFG_SDEST_MASK)) | (cpu_idx << 16);
++              qm_out(QCSP_IO_CFG(idx), after);
++      }
++      return 0;
++}
++
++#define MISC_CFG_WPM_MASK 0x00000002
++int qm_set_wpm(int wpm)
++{
++      u32 before;
++      u32 after;
++
++      if (!qman_have_ccsr())
++              return -ENODEV;
++
++      before = qm_in(MISC_CFG);
++      after = (before & (~MISC_CFG_WPM_MASK)) | (wpm << 1);
++      qm_out(MISC_CFG, after);
++      return 0;
++}
++
++int qm_get_wpm(int *wpm)
++{
++      u32 before;
++
++      if (!qman_have_ccsr())
++              return -ENODEV;
++
++      before = qm_in(MISC_CFG);
++      *wpm = (before & MISC_CFG_WPM_MASK) >> 1;
++      return 0;
++}
++
++/* CEETM_CFG_PRES register has PRES field which is calculated by:
++ *    PRES = (2^22 / credit update reference period) * QMan clock period
++ *         = (2^22 * 10^9)/ CONFIG_QMAN_CEETM_UPDATE_PERIOD) / qman_clk
++ */
++
++int qman_ceetm_set_prescaler(enum qm_dc_portal portal)
++{
++      u64 temp;
++      u16 pres;
++
++      if (!qman_have_ccsr())
++              return -ENODEV;
++
++      temp = 0x400000 * 100;
++      do_div(temp, CONFIG_QMAN_CEETM_UPDATE_PERIOD);
++      temp *= 10000000;
++      do_div(temp, qman_clk);
++      pres = (u16) temp;
++      qm_out(CEETM_CFG_IDX, portal);
++      qm_out(CEETM_CFG_PRES, pres);
++      return 0;
++}
++
++int qman_ceetm_get_prescaler(u16 *pres)
++{
++      if (!qman_have_ccsr())
++              return -ENODEV;
++      *pres = (u16)qm_in(CEETM_CFG_PRES);
++      return 0;
++}
++
++#define DCP_CFG_CEETME_MASK 0xFFFF0000
++#define QM_SP_ENABLE_CEETM(n) (0x80000000 >> (n))
++int qman_sp_enable_ceetm_mode(enum qm_dc_portal portal, u16 sub_portal)
++{
++      u32 dcp_cfg;
++
++      if (!qman_have_ccsr())
++              return -ENODEV;
++
++      dcp_cfg = qm_in(DCP_CFG(portal));
++      dcp_cfg |= QM_SP_ENABLE_CEETM(sub_portal);
++      qm_out(DCP_CFG(portal), dcp_cfg);
++      return 0;
++}
++
++int qman_sp_disable_ceetm_mode(enum qm_dc_portal portal, u16 sub_portal)
++{
++      u32 dcp_cfg;
++
++      if (!qman_have_ccsr())
++              return -ENODEV;
++      dcp_cfg = qm_in(DCP_CFG(portal));
++      dcp_cfg &= ~(QM_SP_ENABLE_CEETM(sub_portal));
++      qm_out(DCP_CFG(portal), dcp_cfg);
++      return 0;
++}
++
++int qman_ceetm_get_xsfdr(enum qm_dc_portal portal, unsigned int *num)
++{
++      if (!qman_have_ccsr())
++              return -ENODEV;
++      *num = qm_in(CEETM_XSFDR_IN_USE);
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_get_xsfdr);
++
++#ifdef CONFIG_SYSFS
++
++#define DRV_NAME      "fsl-qman"
++#define DCP_MAX_ID    3
++#define DCP_MIN_ID    0
++
++static ssize_t show_pfdr_fpc(struct device *dev,
++      struct device_attribute *dev_attr, char *buf)
++{
++      return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(PFDR_FPC));
++};
++
++static ssize_t show_dlm_avg(struct device *dev,
++      struct device_attribute *dev_attr, char *buf)
++{
++      u32 data;
++      int i;
++
++      if (!sscanf(dev_attr->attr.name, "dcp%d_dlm_avg", &i))
++              return -EINVAL;
++      if (i < DCP_MIN_ID || i > DCP_MAX_ID)
++              return -EINVAL;
++      data = qm_in(DCP_DLM_AVG(i));
++      return snprintf(buf, PAGE_SIZE, "%d.%08d\n", data>>8,
++                      (data & 0x000000ff)*390625);
++};
++
++static ssize_t set_dlm_avg(struct device *dev,
++      struct device_attribute *dev_attr, const char *buf, size_t count)
++{
++      unsigned long val;
++      int i;
++
++      if (!sscanf(dev_attr->attr.name, "dcp%d_dlm_avg", &i))
++              return -EINVAL;
++      if (i < DCP_MIN_ID || i > DCP_MAX_ID)
++              return -EINVAL;
++      if (kstrtoul(buf, 0, &val)) {
++              dev_dbg(dev, "invalid input %s\n", buf);
++              return -EINVAL;
++      }
++      qm_out(DCP_DLM_AVG(i), val);
++      return count;
++};
++
++static ssize_t show_pfdr_cfg(struct device *dev,
++      struct device_attribute *dev_attr, char *buf)
++{
++      return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(PFDR_CFG));
++};
++
++static ssize_t set_pfdr_cfg(struct device *dev,
++      struct device_attribute *dev_attr, const char *buf, size_t count)
++{
++      unsigned long val;
++
++      if (kstrtoul(buf, 0, &val)) {
++              dev_dbg(dev, "invalid input %s\n", buf);
++              return -EINVAL;
++      }
++      qm_out(PFDR_CFG, val);
++      return count;
++};
++
++static ssize_t show_sfdr_in_use(struct device *dev,
++      struct device_attribute *dev_attr, char *buf)
++{
++      return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(SFDR_IN_USE));
++};
++
++static ssize_t show_idle_stat(struct device *dev,
++      struct device_attribute *dev_attr, char *buf)
++{
++      return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(IDLE_STAT));
++};
++
++static ssize_t show_ci_rlm_avg(struct device *dev,
++      struct device_attribute *dev_attr, char *buf)
++{
++      u32 data = qm_in(CI_RLM_AVG);
++      return snprintf(buf, PAGE_SIZE, "%d.%08d\n", data>>8,
++                      (data & 0x000000ff)*390625);
++};
++
++static ssize_t set_ci_rlm_avg(struct device *dev,
++      struct device_attribute *dev_attr, const char *buf, size_t count)
++{
++      unsigned long val;
++
++      if (kstrtoul(buf, 0, &val)) {
++              dev_dbg(dev, "invalid input %s\n", buf);
++              return -EINVAL;
++      }
++      qm_out(CI_RLM_AVG, val);
++      return count;
++};
++
++static ssize_t show_err_isr(struct device *dev,
++      struct device_attribute *dev_attr, char *buf)
++{
++      return snprintf(buf, PAGE_SIZE, "0x%08x\n", qm_in(ERR_ISR));
++};
++
++#define SBEC_MAX_ID   14
++#define SBEC_MIN_ID   0
++
++static ssize_t show_sbec(struct device *dev,
++      struct device_attribute *dev_attr, char *buf)
++{
++      int i;
++
++      if (!sscanf(dev_attr->attr.name, "sbec_%d", &i))
++              return -EINVAL;
++      if (i < SBEC_MIN_ID || i > SBEC_MAX_ID)
++              return -EINVAL;
++      return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(SBEC(i)));
++};
++
++static DEVICE_ATTR(pfdr_fpc, S_IRUSR, show_pfdr_fpc, NULL);
++static DEVICE_ATTR(pfdr_cfg, S_IRUSR, show_pfdr_cfg, set_pfdr_cfg);
++static DEVICE_ATTR(idle_stat, S_IRUSR, show_idle_stat, NULL);
++static DEVICE_ATTR(ci_rlm_avg, (S_IRUSR|S_IWUSR),
++              show_ci_rlm_avg, set_ci_rlm_avg);
++static DEVICE_ATTR(err_isr, S_IRUSR, show_err_isr, NULL);
++static DEVICE_ATTR(sfdr_in_use, S_IRUSR, show_sfdr_in_use, NULL);
++
++static DEVICE_ATTR(dcp0_dlm_avg, (S_IRUSR|S_IWUSR), show_dlm_avg, set_dlm_avg);
++static DEVICE_ATTR(dcp1_dlm_avg, (S_IRUSR|S_IWUSR), show_dlm_avg, set_dlm_avg);
++static DEVICE_ATTR(dcp2_dlm_avg, (S_IRUSR|S_IWUSR), show_dlm_avg, set_dlm_avg);
++static DEVICE_ATTR(dcp3_dlm_avg, (S_IRUSR|S_IWUSR), show_dlm_avg, set_dlm_avg);
++
++static DEVICE_ATTR(sbec_0, S_IRUSR, show_sbec, NULL);
++static DEVICE_ATTR(sbec_1, S_IRUSR, show_sbec, NULL);
++static DEVICE_ATTR(sbec_2, S_IRUSR, show_sbec, NULL);
++static DEVICE_ATTR(sbec_3, S_IRUSR, show_sbec, NULL);
++static DEVICE_ATTR(sbec_4, S_IRUSR, show_sbec, NULL);
++static DEVICE_ATTR(sbec_5, S_IRUSR, show_sbec, NULL);
++static DEVICE_ATTR(sbec_6, S_IRUSR, show_sbec, NULL);
++static DEVICE_ATTR(sbec_7, S_IRUSR, show_sbec, NULL);
++static DEVICE_ATTR(sbec_8, S_IRUSR, show_sbec, NULL);
++static DEVICE_ATTR(sbec_9, S_IRUSR, show_sbec, NULL);
++static DEVICE_ATTR(sbec_10, S_IRUSR, show_sbec, NULL);
++static DEVICE_ATTR(sbec_11, S_IRUSR, show_sbec, NULL);
++static DEVICE_ATTR(sbec_12, S_IRUSR, show_sbec, NULL);
++static DEVICE_ATTR(sbec_13, S_IRUSR, show_sbec, NULL);
++static DEVICE_ATTR(sbec_14, S_IRUSR, show_sbec, NULL);
++
++static struct attribute *qman_dev_attributes[] = {
++      &dev_attr_pfdr_fpc.attr,
++      &dev_attr_pfdr_cfg.attr,
++      &dev_attr_idle_stat.attr,
++      &dev_attr_ci_rlm_avg.attr,
++      &dev_attr_err_isr.attr,
++      &dev_attr_dcp0_dlm_avg.attr,
++      &dev_attr_dcp1_dlm_avg.attr,
++      &dev_attr_dcp2_dlm_avg.attr,
++      &dev_attr_dcp3_dlm_avg.attr,
++      /* sfdr_in_use will be added if necessary */
++      NULL
++};
++
++static struct attribute *qman_dev_ecr_attributes[] = {
++      &dev_attr_sbec_0.attr,
++      &dev_attr_sbec_1.attr,
++      &dev_attr_sbec_2.attr,
++      &dev_attr_sbec_3.attr,
++      &dev_attr_sbec_4.attr,
++      &dev_attr_sbec_5.attr,
++      &dev_attr_sbec_6.attr,
++      &dev_attr_sbec_7.attr,
++      &dev_attr_sbec_8.attr,
++      &dev_attr_sbec_9.attr,
++      &dev_attr_sbec_10.attr,
++      &dev_attr_sbec_11.attr,
++      &dev_attr_sbec_12.attr,
++      &dev_attr_sbec_13.attr,
++      &dev_attr_sbec_14.attr,
++      NULL
++};
++
++/* root level */
++static const struct attribute_group qman_dev_attr_grp = {
++      .name = NULL,
++      .attrs = qman_dev_attributes
++};
++static const struct attribute_group qman_dev_ecr_grp = {
++      .name = "error_capture",
++      .attrs = qman_dev_ecr_attributes
++};
++
++static int of_fsl_qman_remove(struct platform_device *ofdev)
++{
++      sysfs_remove_group(&ofdev->dev.kobj, &qman_dev_attr_grp);
++      return 0;
++};
++
++static int of_fsl_qman_probe(struct platform_device *ofdev)
++{
++      int ret;
++
++      ret = sysfs_create_group(&ofdev->dev.kobj, &qman_dev_attr_grp);
++      if (ret)
++              goto done;
++      ret = sysfs_add_file_to_group(&ofdev->dev.kobj,
++              &dev_attr_sfdr_in_use.attr, qman_dev_attr_grp.name);
++      if (ret)
++              goto del_group_0;
++      ret = sysfs_create_group(&ofdev->dev.kobj, &qman_dev_ecr_grp);
++      if (ret)
++              goto del_group_0;
++
++      goto done;
++
++del_group_0:
++      sysfs_remove_group(&ofdev->dev.kobj, &qman_dev_attr_grp);
++done:
++      if (ret)
++              dev_err(&ofdev->dev,
++                              "Cannot create dev attributes ret=%d\n", ret);
++      return ret;
++};
++
++static struct of_device_id of_fsl_qman_ids[] = {
++      {
++              .compatible = "fsl,qman",
++      },
++      {}
++};
++MODULE_DEVICE_TABLE(of, of_fsl_qman_ids);
++
++#ifdef CONFIG_SUSPEND
++
++static u32 saved_isdr;
++static int qman_pm_suspend_noirq(struct device *dev)
++{
++      uint32_t idle_state;
++
++      suspend_unused_qportal();
++      /* save isdr, disable all, clear isr */
++      saved_isdr = qm_err_isr_disable_read(qm);
++      qm_err_isr_disable_write(qm, 0xffffffff);
++      qm_err_isr_status_clear(qm, 0xffffffff);
++      idle_state = qm_in(IDLE_STAT);
++      if (!(idle_state & 0x1)) {
++              pr_err("Qman not idle 0x%x aborting\n", idle_state);
++              qm_err_isr_disable_write(qm, saved_isdr);
++              resume_unused_qportal();
++              return -EBUSY;
++      }
++#ifdef CONFIG_PM_DEBUG
++      pr_info("Qman suspend code, IDLE_STAT = 0x%x\n", idle_state);
++#endif
++      return 0;
++}
++
++static int qman_pm_resume_noirq(struct device *dev)
++{
++      /* restore isdr */
++      qm_err_isr_disable_write(qm, saved_isdr);
++      resume_unused_qportal();
++      return 0;
++}
++#else
++#define qman_pm_suspend_noirq NULL
++#define qman_pm_resume_noirq  NULL
++#endif
++
++static const struct dev_pm_ops qman_pm_ops = {
++      .suspend_noirq = qman_pm_suspend_noirq,
++      .resume_noirq = qman_pm_resume_noirq,
++};
++
++static struct platform_driver of_fsl_qman_driver = {
++      .driver = {
++              .owner = THIS_MODULE,
++              .name = DRV_NAME,
++              .of_match_table = of_fsl_qman_ids,
++              .pm = &qman_pm_ops,
++      },
++      .probe = of_fsl_qman_probe,
++      .remove      = of_fsl_qman_remove,
++};
++
++static int qman_ctrl_init(void)
++{
++      return platform_driver_register(&of_fsl_qman_driver);
++}
++
++static void qman_ctrl_exit(void)
++{
++      platform_driver_unregister(&of_fsl_qman_driver);
++}
++
++module_init(qman_ctrl_init);
++module_exit(qman_ctrl_exit);
++
++#endif /* CONFIG_SYSFS */
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/qman_debugfs.c
+@@ -0,0 +1,1594 @@
++/* Copyright 2010-2011 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++#include "qman_private.h"
++
++#define MAX_FQID (0x00ffffff)
++#define QM_FQD_BLOCK_SIZE     64
++#define QM_FQD_AR             (0xC10)
++
++static u32 fqid_max;
++static u64 qman_ccsr_start;
++static u64 qman_ccsr_size;
++
++static const char * const state_txt[] = {
++      "Out of Service",
++      "Retired",
++      "Tentatively Scheduled",
++      "Truly Scheduled",
++      "Parked",
++      "Active, Active Held or Held Suspended",
++      "Unknown State 6",
++      "Unknown State 7",
++      NULL,
++};
++
++static const u8 fqd_states[] = {
++      QM_MCR_NP_STATE_OOS, QM_MCR_NP_STATE_RETIRED, QM_MCR_NP_STATE_TEN_SCHED,
++      QM_MCR_NP_STATE_TRU_SCHED, QM_MCR_NP_STATE_PARKED,
++      QM_MCR_NP_STATE_ACTIVE};
++
++struct mask_to_text {
++      u16 mask;
++      const char *txt;
++};
++
++struct mask_filter_s {
++      u16 mask;
++      u8 filter;
++};
++
++static const struct mask_filter_s mask_filter[] = {
++      {QM_FQCTRL_PREFERINCACHE, 0},
++      {QM_FQCTRL_PREFERINCACHE, 1},
++      {QM_FQCTRL_HOLDACTIVE, 0},
++      {QM_FQCTRL_HOLDACTIVE, 1},
++      {QM_FQCTRL_AVOIDBLOCK, 0},
++      {QM_FQCTRL_AVOIDBLOCK, 1},
++      {QM_FQCTRL_FORCESFDR, 0},
++      {QM_FQCTRL_FORCESFDR, 1},
++      {QM_FQCTRL_CPCSTASH, 0},
++      {QM_FQCTRL_CPCSTASH, 1},
++      {QM_FQCTRL_CTXASTASHING, 0},
++      {QM_FQCTRL_CTXASTASHING, 1},
++      {QM_FQCTRL_ORP, 0},
++      {QM_FQCTRL_ORP, 1},
++      {QM_FQCTRL_TDE, 0},
++      {QM_FQCTRL_TDE, 1},
++      {QM_FQCTRL_CGE, 0},
++      {QM_FQCTRL_CGE, 1}
++};
++
++static const struct mask_to_text fq_ctrl_text_list[] = {
++      {
++              .mask = QM_FQCTRL_PREFERINCACHE,
++              .txt = "Prefer in cache",
++      },
++      {
++              .mask = QM_FQCTRL_HOLDACTIVE,
++              .txt =  "Hold active in portal",
++      },
++      {
++              .mask = QM_FQCTRL_AVOIDBLOCK,
++              .txt = "Avoid Blocking",
++      },
++      {
++              .mask = QM_FQCTRL_FORCESFDR,
++              .txt = "High-priority SFDRs",
++      },
++      {
++              .mask = QM_FQCTRL_CPCSTASH,
++              .txt = "CPC Stash Enable",
++      },
++      {
++              .mask = QM_FQCTRL_CTXASTASHING,
++              .txt =  "Context-A stashing",
++      },
++      {
++              .mask = QM_FQCTRL_ORP,
++              .txt =  "ORP Enable",
++      },
++      {
++              .mask = QM_FQCTRL_TDE,
++              .txt = "Tail-Drop Enable",
++      },
++      {
++              .mask = QM_FQCTRL_CGE,
++              .txt = "Congestion Group Enable",
++      },
++      {
++              .mask = 0,
++              .txt = NULL,
++      }
++};
++
++static const char *get_fqd_ctrl_text(u16 mask)
++{
++      int i = 0;
++
++      while (fq_ctrl_text_list[i].txt != NULL) {
++              if (fq_ctrl_text_list[i].mask == mask)
++                      return fq_ctrl_text_list[i].txt;
++              i++;
++      }
++      return NULL;
++}
++
++static const struct mask_to_text stashing_text_list[] = {
++      {
++              .mask = QM_STASHING_EXCL_CTX,
++              .txt = "FQ Ctx Stash"
++      },
++      {
++              .mask = QM_STASHING_EXCL_DATA,
++              .txt =  "Frame Data Stash",
++      },
++      {
++              .mask = QM_STASHING_EXCL_ANNOTATION,
++              .txt = "Frame Annotation Stash",
++      },
++      {
++              .mask = 0,
++              .txt = NULL,
++      },
++};
++
++static int user_input_convert(const char __user *user_buf, size_t count,
++                              unsigned long *val)
++{
++      char buf[12];
++
++      if (count > sizeof(buf) - 1)
++              return -EINVAL;
++      if (copy_from_user(buf, user_buf, count))
++              return -EFAULT;
++      buf[count] = '\0';
++      if (kstrtoul(buf, 0, val))
++              return -EINVAL;
++      return 0;
++}
++
++struct line_buffer_fq {
++      u32 buf[8];
++      u32 buf_cnt;
++      int line_cnt;
++};
++
++static void add_to_line_buffer(struct line_buffer_fq *line_buf, u32 fqid,
++                      struct seq_file *file)
++{
++      line_buf->buf[line_buf->buf_cnt] = fqid;
++      line_buf->buf_cnt++;
++      if (line_buf->buf_cnt == 8) {
++              /* Buffer is full, flush it */
++              if (line_buf->line_cnt != 0)
++                      seq_puts(file, ",\n");
++              seq_printf(file, "0x%06x,0x%06x,0x%06x,0x%06x,0x%06x,"
++                      "0x%06x,0x%06x,0x%06x",
++                      line_buf->buf[0], line_buf->buf[1], line_buf->buf[2],
++                      line_buf->buf[3], line_buf->buf[4], line_buf->buf[5],
++                      line_buf->buf[6], line_buf->buf[7]);
++              line_buf->buf_cnt = 0;
++              line_buf->line_cnt++;
++      }
++}
++
++static void flush_line_buffer(struct line_buffer_fq *line_buf,
++                              struct seq_file *file)
++{
++      if (line_buf->buf_cnt) {
++              int y = 0;
++              if (line_buf->line_cnt != 0)
++                      seq_puts(file, ",\n");
++              while (y != line_buf->buf_cnt) {
++                      if (y+1 == line_buf->buf_cnt)
++                              seq_printf(file, "0x%06x", line_buf->buf[y]);
++                      else
++                              seq_printf(file, "0x%06x,", line_buf->buf[y]);
++                      y++;
++              }
++              line_buf->line_cnt++;
++      }
++      if (line_buf->line_cnt)
++              seq_putc(file, '\n');
++}
++
++static struct dentry *dfs_root; /* debugfs root directory */
++
++/*******************************************************************************
++ *  Query Frame Queue Non Programmable Fields
++ ******************************************************************************/
++struct query_fq_np_fields_data_s {
++      u32 fqid;
++};
++static struct query_fq_np_fields_data_s query_fq_np_fields_data = {
++      .fqid = 1,
++};
++
++static int query_fq_np_fields_show(struct seq_file *file, void *offset)
++{
++      int ret;
++      struct qm_mcr_queryfq_np np;
++      struct qman_fq fq;
++
++      fq.fqid = query_fq_np_fields_data.fqid;
++      ret = qman_query_fq_np(&fq, &np);
++      if (ret)
++              return ret;
++      /* Print state */
++      seq_printf(file, "Query FQ Non Programmable Fields Result fqid 0x%x\n",
++                      fq.fqid);
++      seq_printf(file, " force eligible pending: %s\n",
++              (np.state & QM_MCR_NP_STATE_FE) ? "yes" : "no");
++      seq_printf(file, " retirement pending: %s\n",
++              (np.state & QM_MCR_NP_STATE_R) ? "yes" : "no");
++      seq_printf(file, " state: %s\n",
++              state_txt[np.state & QM_MCR_NP_STATE_MASK]);
++      seq_printf(file, " fq_link: 0x%x\n", np.fqd_link);
++      seq_printf(file, " odp_seq: %u\n", np.odp_seq);
++      seq_printf(file, " orp_nesn: %u\n", np.orp_nesn);
++      seq_printf(file, " orp_ea_hseq: %u\n", np.orp_ea_hseq);
++      seq_printf(file, " orp_ea_tseq: %u\n", np.orp_ea_tseq);
++      seq_printf(file, " orp_ea_hptr: 0x%x\n", np.orp_ea_hptr);
++      seq_printf(file, " orp_ea_tptr: 0x%x\n", np.orp_ea_tptr);
++      seq_printf(file, " pfdr_hptr: 0x%x\n", np.pfdr_hptr);
++      seq_printf(file, " pfdr_tptr: 0x%x\n", np.pfdr_tptr);
++      seq_printf(file, " is: ics_surp contains a %s\n",
++              (np.is) ? "deficit" : "surplus");
++      seq_printf(file, " ics_surp: %u\n", np.ics_surp);
++      seq_printf(file, " byte_cnt: %u\n", np.byte_cnt);
++      seq_printf(file, " frm_cnt: %u\n", np.frm_cnt);
++      seq_printf(file, " ra1_sfdr: 0x%x\n", np.ra1_sfdr);
++      seq_printf(file, " ra2_sfdr: 0x%x\n", np.ra2_sfdr);
++      seq_printf(file, " od1_sfdr: 0x%x\n", np.od1_sfdr);
++      seq_printf(file, " od2_sfdr: 0x%x\n", np.od2_sfdr);
++      seq_printf(file, " od3_sfdr: 0x%x\n", np.od3_sfdr);
++      return 0;
++}
++
++static int query_fq_np_fields_open(struct inode *inode,
++                                      struct file *file)
++{
++      return single_open(file, query_fq_np_fields_show, NULL);
++}
++
++static ssize_t query_fq_np_fields_write(struct file *f,
++                      const char __user *buf, size_t count, loff_t *off)
++{
++      int ret;
++      unsigned long val;
++
++      ret = user_input_convert(buf, count, &val);
++      if (ret)
++              return ret;
++      if (val > MAX_FQID)
++              return -EINVAL;
++      query_fq_np_fields_data.fqid = (u32)val;
++      return count;
++}
++
++static const struct file_operations query_fq_np_fields_fops = {
++      .owner          = THIS_MODULE,
++      .open           = query_fq_np_fields_open,
++      .read           = seq_read,
++      .write          = query_fq_np_fields_write,
++      .release        = single_release,
++};
++
++/*******************************************************************************
++ *  Frame Queue Programmable Fields
++ ******************************************************************************/
++struct query_fq_fields_data_s {
++      u32 fqid;
++};
++
++static struct query_fq_fields_data_s query_fq_fields_data = {
++      .fqid = 1,
++};
++
++static int query_fq_fields_show(struct seq_file *file, void *offset)
++{
++      int ret;
++      struct qm_fqd fqd;
++      struct qman_fq fq;
++      int i = 0;
++
++      memset(&fqd, 0, sizeof(struct qm_fqd));
++      fq.fqid = query_fq_fields_data.fqid;
++      ret = qman_query_fq(&fq, &fqd);
++      if (ret)
++              return ret;
++      seq_printf(file, "Query FQ Programmable Fields Result fqid 0x%x\n",
++                      fq.fqid);
++      seq_printf(file, " orprws: %u\n", fqd.orprws);
++      seq_printf(file, " oa: %u\n", fqd.oa);
++      seq_printf(file, " olws: %u\n", fqd.olws);
++
++      seq_printf(file, " cgid: %u\n", fqd.cgid);
++
++      if ((fqd.fq_ctrl & QM_FQCTRL_MASK) == 0)
++              seq_puts(file, " fq_ctrl: None\n");
++      else {
++              i = 0;
++              seq_puts(file, " fq_ctrl:\n");
++              while (fq_ctrl_text_list[i].txt != NULL) {
++                      if ((fqd.fq_ctrl & QM_FQCTRL_MASK) &
++                                      fq_ctrl_text_list[i].mask)
++                              seq_printf(file, "  %s\n",
++                                      fq_ctrl_text_list[i].txt);
++                      i++;
++              }
++      }
++      seq_printf(file, " dest_channel: %u\n", fqd.dest.channel);
++      seq_printf(file, " dest_wq: %u\n", fqd.dest.wq);
++      seq_printf(file, " ics_cred: %u\n", fqd.ics_cred);
++      seq_printf(file, " td_mant: %u\n", fqd.td.mant);
++      seq_printf(file, " td_exp: %u\n", fqd.td.exp);
++
++      seq_printf(file, " ctx_b: 0x%x\n", fqd.context_b);
++
++      seq_printf(file, " ctx_a: 0x%llx\n", qm_fqd_stashing_get64(&fqd));
++      /* Any stashing configured */
++      if ((fqd.context_a.stashing.exclusive & 0x7) == 0)
++              seq_puts(file, " ctx_a_stash_exclusive: None\n");
++      else {
++              seq_puts(file, " ctx_a_stash_exclusive:\n");
++              i = 0;
++              while (stashing_text_list[i].txt != NULL) {
++                      if ((fqd.fq_ctrl & 0x7) & stashing_text_list[i].mask)
++                              seq_printf(file, "  %s\n",
++                                      stashing_text_list[i].txt);
++                      i++;
++              }
++      }
++      seq_printf(file, " ctx_a_stash_annotation_cl: %u\n",
++                      fqd.context_a.stashing.annotation_cl);
++      seq_printf(file, " ctx_a_stash_data_cl: %u\n",
++                      fqd.context_a.stashing.data_cl);
++      seq_printf(file, " ctx_a_stash_context_cl: %u\n",
++                      fqd.context_a.stashing.context_cl);
++      return 0;
++}
++
++static int query_fq_fields_open(struct inode *inode,
++                                      struct file *file)
++{
++      return single_open(file, query_fq_fields_show, NULL);
++}
++
++static ssize_t query_fq_fields_write(struct file *f,
++                      const char __user *buf, size_t count, loff_t *off)
++{
++      int ret;
++      unsigned long val;
++
++      ret = user_input_convert(buf, count, &val);
++      if (ret)
++              return ret;
++      if (val > MAX_FQID)
++              return -EINVAL;
++      query_fq_fields_data.fqid = (u32)val;
++      return count;
++}
++
++static const struct file_operations query_fq_fields_fops = {
++      .owner          = THIS_MODULE,
++      .open           = query_fq_fields_open,
++      .read           = seq_read,
++      .write          = query_fq_fields_write,
++      .release        = single_release,
++};
++
++/*******************************************************************************
++ * Query WQ lengths
++ ******************************************************************************/
++struct query_wq_lengths_data_s {
++      union {
++              u16 channel_wq; /* ignores wq (3 lsbits) */
++              struct {
++                      u16 id:13; /* qm_channel */
++                      u16 __reserved:3;
++              } __packed channel;
++      };
++};
++static struct query_wq_lengths_data_s query_wq_lengths_data;
++static int query_wq_lengths_show(struct seq_file *file, void *offset)
++{
++      int ret;
++      struct qm_mcr_querywq wq;
++      int i;
++
++      memset(&wq, 0, sizeof(struct qm_mcr_querywq));
++      wq.channel.id = query_wq_lengths_data.channel.id;
++      ret = qman_query_wq(0, &wq);
++      if (ret)
++              return ret;
++      seq_printf(file, "Query Result For Channel: 0x%x\n", wq.channel.id);
++      for (i = 0; i < 8; i++)
++              /* mask out upper 4 bits since they are not part of length */
++              seq_printf(file, " wq%d_len : %u\n", i, wq.wq_len[i] & 0x0fff);
++      return 0;
++}
++
++static int query_wq_lengths_open(struct inode *inode,
++                                      struct file *file)
++{
++      return single_open(file, query_wq_lengths_show, NULL);
++}
++
++static ssize_t query_wq_lengths_write(struct file *f,
++                      const char __user *buf, size_t count, loff_t *off)
++{
++      int ret;
++      unsigned long val;
++
++      ret = user_input_convert(buf, count, &val);
++      if (ret)
++              return ret;
++      if (val > 0xfff8)
++              return -EINVAL;
++      query_wq_lengths_data.channel.id = (u16)val;
++      return count;
++}
++
++static const struct file_operations query_wq_lengths_fops = {
++      .owner          = THIS_MODULE,
++      .open           = query_wq_lengths_open,
++      .read           = seq_read,
++      .write          = query_wq_lengths_write,
++      .release        = single_release,
++};
++
++/*******************************************************************************
++ *  Query CGR
++ ******************************************************************************/
++struct query_cgr_s {
++      u8 cgid;
++};
++static struct query_cgr_s query_cgr_data;
++
++static int query_cgr_show(struct seq_file *file, void *offset)
++{
++      int ret;
++      struct qm_mcr_querycgr cgrd;
++      struct qman_cgr cgr;
++      int i, j;
++      u32 mask;
++
++      memset(&cgr, 0, sizeof(cgr));
++      memset(&cgrd, 0, sizeof(cgrd));
++      cgr.cgrid = query_cgr_data.cgid;
++      ret = qman_query_cgr(&cgr, &cgrd);
++      if (ret)
++              return ret;
++      seq_printf(file, "Query CGR id 0x%x\n", cgr.cgrid);
++      seq_printf(file, " wr_parm_g MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
++              cgrd.cgr.wr_parm_g.MA, cgrd.cgr.wr_parm_g.Mn,
++              cgrd.cgr.wr_parm_g.SA, cgrd.cgr.wr_parm_g.Sn,
++              cgrd.cgr.wr_parm_g.Pn);
++
++      seq_printf(file, " wr_parm_y MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
++              cgrd.cgr.wr_parm_y.MA, cgrd.cgr.wr_parm_y.Mn,
++              cgrd.cgr.wr_parm_y.SA, cgrd.cgr.wr_parm_y.Sn,
++              cgrd.cgr.wr_parm_y.Pn);
++
++      seq_printf(file, " wr_parm_r MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
++              cgrd.cgr.wr_parm_r.MA, cgrd.cgr.wr_parm_r.Mn,
++              cgrd.cgr.wr_parm_r.SA, cgrd.cgr.wr_parm_r.Sn,
++              cgrd.cgr.wr_parm_r.Pn);
++
++      seq_printf(file, " wr_en_g: %u, wr_en_y: %u, we_en_r: %u\n",
++              cgrd.cgr.wr_en_g, cgrd.cgr.wr_en_y, cgrd.cgr.wr_en_r);
++
++      seq_printf(file, " cscn_en: %u\n", cgrd.cgr.cscn_en);
++      if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) {
++              seq_puts(file, " cscn_targ_dcp:\n");
++              mask = 0x80000000;
++              for (i = 0; i < 32; i++) {
++                      if (cgrd.cgr.cscn_targ & mask)
++                              seq_printf(file, "  send CSCN to dcp %u\n",
++                                                              (31 - i));
++                      mask >>= 1;
++              }
++
++              seq_puts(file, " cscn_targ_swp:\n");
++              for (i = 0; i < 4; i++) {
++                      mask = 0x80000000;
++                      for (j = 0; j < 32; j++) {
++                              if (cgrd.cscn_targ_swp[i] & mask)
++                                      seq_printf(file, "  send CSCN to swp"
++                                              " %u\n", (127 - (i * 32) - j));
++                              mask >>= 1;
++                      }
++              }
++      } else {
++              seq_printf(file, " cscn_targ: %u\n", cgrd.cgr.cscn_targ);
++      }
++      seq_printf(file, " cstd_en: %u\n", cgrd.cgr.cstd_en);
++      seq_printf(file, " cs: %u\n", cgrd.cgr.cs);
++
++      seq_printf(file, " cs_thresh_TA: %u, cs_thresh_Tn: %u\n",
++              cgrd.cgr.cs_thres.TA, cgrd.cgr.cs_thres.Tn);
++
++      seq_printf(file, " mode: %s\n",
++              (cgrd.cgr.mode & QMAN_CGR_MODE_FRAME) ?
++              "frame count" : "byte count");
++      seq_printf(file, " i_bcnt: %llu\n", qm_mcr_querycgr_i_get64(&cgrd));
++      seq_printf(file, " a_bcnt: %llu\n", qm_mcr_querycgr_a_get64(&cgrd));
++
++      return 0;
++}
++
++static int query_cgr_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, query_cgr_show, NULL);
++}
++
++static ssize_t query_cgr_write(struct file *f, const char __user *buf,
++                              size_t count, loff_t *off)
++{
++      int ret;
++      unsigned long val;
++
++      ret = user_input_convert(buf, count, &val);
++      if (ret)
++              return ret;
++      if (val > 0xff)
++              return -EINVAL;
++      query_cgr_data.cgid = (u8)val;
++      return count;
++}
++
++static const struct file_operations query_cgr_fops = {
++      .owner          = THIS_MODULE,
++      .open           = query_cgr_open,
++      .read           = seq_read,
++      .write          = query_cgr_write,
++      .release        = single_release,
++};
++
++/*******************************************************************************
++ *  Test Write CGR
++ ******************************************************************************/
++struct test_write_cgr_s {
++      u64 i_bcnt;
++      u8 cgid;
++};
++static struct test_write_cgr_s test_write_cgr_data;
++
++static int testwrite_cgr_show(struct seq_file *file, void *offset)
++{
++      int ret;
++      struct qm_mcr_cgrtestwrite result;
++      struct qman_cgr cgr;
++      u64 i_bcnt;
++
++      memset(&cgr, 0, sizeof(struct qman_cgr));
++      memset(&result, 0, sizeof(struct qm_mcr_cgrtestwrite));
++      cgr.cgrid = test_write_cgr_data.cgid;
++      i_bcnt = test_write_cgr_data.i_bcnt;
++      ret = qman_testwrite_cgr(&cgr, i_bcnt, &result);
++      if (ret)
++              return ret;
++      seq_printf(file, "CGR Test Write CGR id 0x%x\n", cgr.cgrid);
++      seq_printf(file, " wr_parm_g MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
++              result.cgr.wr_parm_g.MA, result.cgr.wr_parm_g.Mn,
++              result.cgr.wr_parm_g.SA, result.cgr.wr_parm_g.Sn,
++              result.cgr.wr_parm_g.Pn);
++      seq_printf(file, " wr_parm_y MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
++              result.cgr.wr_parm_y.MA, result.cgr.wr_parm_y.Mn,
++              result.cgr.wr_parm_y.SA, result.cgr.wr_parm_y.Sn,
++              result.cgr.wr_parm_y.Pn);
++      seq_printf(file, " wr_parm_r MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
++              result.cgr.wr_parm_r.MA, result.cgr.wr_parm_r.Mn,
++              result.cgr.wr_parm_r.SA, result.cgr.wr_parm_r.Sn,
++              result.cgr.wr_parm_r.Pn);
++      seq_printf(file, " wr_en_g: %u, wr_en_y: %u, we_en_r: %u\n",
++              result.cgr.wr_en_g, result.cgr.wr_en_y, result.cgr.wr_en_r);
++      seq_printf(file, " cscn_en: %u\n", result.cgr.cscn_en);
++      seq_printf(file, " cscn_targ: %u\n", result.cgr.cscn_targ);
++      seq_printf(file, " cstd_en: %u\n", result.cgr.cstd_en);
++      seq_printf(file, " cs: %u\n", result.cgr.cs);
++      seq_printf(file, " cs_thresh_TA: %u, cs_thresh_Tn: %u\n",
++              result.cgr.cs_thres.TA, result.cgr.cs_thres.Tn);
++
++      /* Add Mode for Si 2 */
++      seq_printf(file, " mode: %s\n",
++              (result.cgr.mode & QMAN_CGR_MODE_FRAME) ?
++              "frame count" : "byte count");
++
++      seq_printf(file, " i_bcnt: %llu\n",
++              qm_mcr_cgrtestwrite_i_get64(&result));
++      seq_printf(file, " a_bcnt: %llu\n",
++              qm_mcr_cgrtestwrite_a_get64(&result));
++      seq_printf(file, " wr_prob_g: %u\n", result.wr_prob_g);
++      seq_printf(file, " wr_prob_y: %u\n", result.wr_prob_y);
++      seq_printf(file, " wr_prob_r: %u\n", result.wr_prob_r);
++      return 0;
++}
++
++static int testwrite_cgr_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, testwrite_cgr_show, NULL);
++}
++
++static const struct file_operations testwrite_cgr_fops = {
++      .owner          = THIS_MODULE,
++      .open           = testwrite_cgr_open,
++      .read           = seq_read,
++      .release        = single_release,
++};
++
++
++static int testwrite_cgr_ibcnt_show(struct seq_file *file, void *offset)
++{
++      seq_printf(file, "i_bcnt: %llu\n", test_write_cgr_data.i_bcnt);
++      return 0;
++}
++static int testwrite_cgr_ibcnt_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, testwrite_cgr_ibcnt_show, NULL);
++}
++
++static ssize_t testwrite_cgr_ibcnt_write(struct file *f, const char __user *buf,
++                              size_t count, loff_t *off)
++{
++      int ret;
++      unsigned long val;
++
++      ret = user_input_convert(buf, count, &val);
++      if (ret)
++              return ret;
++      test_write_cgr_data.i_bcnt = val;
++      return count;
++}
++
++static const struct file_operations teswrite_cgr_ibcnt_fops = {
++      .owner          = THIS_MODULE,
++      .open           = testwrite_cgr_ibcnt_open,
++      .read           = seq_read,
++      .write          = testwrite_cgr_ibcnt_write,
++      .release        = single_release,
++};
++
++static int testwrite_cgr_cgrid_show(struct seq_file *file, void *offset)
++{
++      seq_printf(file, "cgrid: %u\n", (u32)test_write_cgr_data.cgid);
++      return 0;
++}
++static int testwrite_cgr_cgrid_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, testwrite_cgr_cgrid_show, NULL);
++}
++
++static ssize_t testwrite_cgr_cgrid_write(struct file *f, const char __user *buf,
++                              size_t count, loff_t *off)
++{
++      int ret;
++      unsigned long val;
++
++      ret = user_input_convert(buf, count, &val);
++      if (ret)
++              return ret;
++      if (val > 0xff)
++              return -EINVAL;
++      test_write_cgr_data.cgid = (u8)val;
++      return count;
++}
++
++static const struct file_operations teswrite_cgr_cgrid_fops = {
++      .owner          = THIS_MODULE,
++      .open           = testwrite_cgr_cgrid_open,
++      .read           = seq_read,
++      .write          = testwrite_cgr_cgrid_write,
++      .release        = single_release,
++};
++
++/*******************************************************************************
++ *  Query Congestion State
++ ******************************************************************************/
++static int query_congestion_show(struct seq_file *file, void *offset)
++{
++      int ret;
++      struct qm_mcr_querycongestion cs;
++      int i, j, in_cong = 0;
++      u32 mask;
++
++      memset(&cs, 0, sizeof(struct qm_mcr_querycongestion));
++      ret = qman_query_congestion(&cs);
++      if (ret)
++              return ret;
++      seq_puts(file, "Query Congestion Result\n");
++      for (i = 0; i < 8; i++) {
++              mask = 0x80000000;
++              for (j = 0; j < 32; j++) {
++                      if (cs.state.__state[i] & mask) {
++                              in_cong = 1;
++                              seq_printf(file, " cg %u: %s\n", (i*32)+j,
++                                      "in congestion");
++                      }
++                      mask >>= 1;
++              }
++      }
++      if (!in_cong)
++              seq_puts(file, " All congestion groups not congested.\n");
++      return 0;
++}
++
++static int query_congestion_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, query_congestion_show, NULL);
++}
++
++static const struct file_operations query_congestion_fops = {
++      .owner          = THIS_MODULE,
++      .open           = query_congestion_open,
++      .read           = seq_read,
++      .release        = single_release,
++};
++
++/*******************************************************************************
++ *  Query CCGR
++ ******************************************************************************/
++struct query_ccgr_s {
++      u32 ccgid;
++};
++static struct query_ccgr_s query_ccgr_data;
++
++static int query_ccgr_show(struct seq_file *file, void *offset)
++{
++      int ret;
++      struct qm_mcr_ceetm_ccgr_query ccgr_query;
++      struct qm_mcc_ceetm_ccgr_query query_opts;
++      int i, j;
++      u32 mask;
++
++      memset(&ccgr_query, 0, sizeof(struct qm_mcr_ceetm_ccgr_query));
++      memset(&query_opts, 0, sizeof(struct qm_mcc_ceetm_ccgr_query));
++
++      if ((qman_ip_rev & 0xFF00) < QMAN_REV30)
++              return -EINVAL;
++
++      seq_printf(file, "Query CCGID %x\n", query_ccgr_data.ccgid);
++      query_opts.dcpid = ((query_ccgr_data.ccgid & 0xFF000000) >> 24);
++      query_opts.ccgrid = query_ccgr_data.ccgid & 0x000001FF;
++      ret = qman_ceetm_query_ccgr(&query_opts, &ccgr_query);
++      if (ret)
++              return ret;
++      seq_printf(file, "Query CCGR id %x in DCP %d\n", query_opts.ccgrid,
++                                              query_opts.dcpid);
++      seq_printf(file, " wr_parm_g MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
++              ccgr_query.cm_query.wr_parm_g.MA,
++              ccgr_query.cm_query.wr_parm_g.Mn,
++              ccgr_query.cm_query.wr_parm_g.SA,
++              ccgr_query.cm_query.wr_parm_g.Sn,
++              ccgr_query.cm_query.wr_parm_g.Pn);
++
++      seq_printf(file, " wr_parm_y MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
++              ccgr_query.cm_query.wr_parm_y.MA,
++              ccgr_query.cm_query.wr_parm_y.Mn,
++              ccgr_query.cm_query.wr_parm_y.SA,
++              ccgr_query.cm_query.wr_parm_y.Sn,
++              ccgr_query.cm_query.wr_parm_y.Pn);
++
++      seq_printf(file, " wr_parm_r MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
++              ccgr_query.cm_query.wr_parm_r.MA,
++              ccgr_query.cm_query.wr_parm_r.Mn,
++              ccgr_query.cm_query.wr_parm_r.SA,
++              ccgr_query.cm_query.wr_parm_r.Sn,
++              ccgr_query.cm_query.wr_parm_r.Pn);
++
++      seq_printf(file, " wr_en_g: %u, wr_en_y: %u, we_en_r: %u\n",
++              ccgr_query.cm_query.ctl_wr_en_g,
++              ccgr_query.cm_query.ctl_wr_en_y,
++              ccgr_query.cm_query.ctl_wr_en_r);
++
++      seq_printf(file, " cscn_en: %u\n", ccgr_query.cm_query.ctl_cscn_en);
++      seq_puts(file, " cscn_targ_dcp:\n");
++      mask = 0x80000000;
++      for (i = 0; i < 32; i++) {
++              if (ccgr_query.cm_query.cscn_targ_dcp & mask)
++                      seq_printf(file, "  send CSCN to dcp %u\n", (31 - i));
++              mask >>= 1;
++      }
++
++      seq_puts(file, " cscn_targ_swp:\n");
++      for (i = 0; i < 4; i++) {
++              mask = 0x80000000;
++              for (j = 0; j < 32; j++) {
++                      if (ccgr_query.cm_query.cscn_targ_swp[i] & mask)
++                              seq_printf(file, "  send CSCN to swp"
++                                      "%u\n", (127 - (i * 32) - j));
++                      mask >>= 1;
++              }
++      }
++
++      seq_printf(file, " td_en: %u\n", ccgr_query.cm_query.ctl_td_en);
++
++      seq_printf(file, " cs_thresh_in_TA: %u, cs_thresh_in_Tn: %u\n",
++                      ccgr_query.cm_query.cs_thres.TA,
++                      ccgr_query.cm_query.cs_thres.Tn);
++
++      seq_printf(file, " cs_thresh_out_TA: %u, cs_thresh_out_Tn: %u\n",
++                      ccgr_query.cm_query.cs_thres_x.TA,
++                      ccgr_query.cm_query.cs_thres_x.Tn);
++
++      seq_printf(file, " td_thresh_TA: %u, td_thresh_Tn: %u\n",
++                      ccgr_query.cm_query.td_thres.TA,
++                      ccgr_query.cm_query.td_thres.Tn);
++
++      seq_printf(file, " mode: %s\n",
++                      (ccgr_query.cm_query.ctl_mode &
++                      QMAN_CGR_MODE_FRAME) ?
++                      "frame count" : "byte count");
++      seq_printf(file, " i_cnt: %llu\n", (u64)ccgr_query.cm_query.i_cnt);
++      seq_printf(file, " a_cnt: %llu\n", (u64)ccgr_query.cm_query.a_cnt);
++
++      return 0;
++}
++
++static int query_ccgr_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, query_ccgr_show, NULL);
++}
++
++static ssize_t query_ccgr_write(struct file *f, const char __user *buf,
++                              size_t count, loff_t *off)
++{
++      int ret;
++      unsigned long val;
++
++      ret = user_input_convert(buf, count, &val);
++      if (ret)
++              return ret;
++      query_ccgr_data.ccgid = val;
++      return count;
++}
++
++static const struct file_operations query_ccgr_fops = {
++      .owner          = THIS_MODULE,
++      .open           = query_ccgr_open,
++      .read           = seq_read,
++      .write          = query_ccgr_write,
++      .release        = single_release,
++};
++/*******************************************************************************
++ *  QMan register
++ ******************************************************************************/
++struct qman_register_s {
++      u32 val;
++};
++static struct qman_register_s qman_register_data;
++
++static void init_ccsrmempeek(void)
++{
++      struct device_node *dn;
++      const u32 *regaddr_p;
++
++      dn = of_find_compatible_node(NULL, NULL, "fsl,qman");
++      if (!dn) {
++              pr_info("No fsl,qman node\n");
++              return;
++      }
++      regaddr_p = of_get_address(dn, 0, &qman_ccsr_size, NULL);
++      if (!regaddr_p) {
++              of_node_put(dn);
++              return;
++      }
++      qman_ccsr_start = of_translate_address(dn, regaddr_p);
++      of_node_put(dn);
++}
++/* This function provides access to QMan ccsr memory map */
++static int qman_ccsrmempeek(u32 *val, u32 offset)
++{
++      void __iomem *addr;
++      u64 phys_addr;
++
++      if (!qman_ccsr_start)
++              return -EINVAL;
++
++      if (offset > (qman_ccsr_size - sizeof(u32)))
++              return -EINVAL;
++
++      phys_addr = qman_ccsr_start + offset;
++      addr = ioremap(phys_addr, sizeof(u32));
++      if (!addr) {
++              pr_err("ccsrmempeek, ioremap failed\n");
++              return -EINVAL;
++      }
++      *val = in_be32(addr);
++      iounmap(addr);
++      return 0;
++}
++
++static int qman_ccsrmempeek_show(struct seq_file *file, void *offset)
++{
++      u32 b;
++
++      qman_ccsrmempeek(&b, qman_register_data.val);
++      seq_printf(file, "QMan register offset = 0x%x\n",
++                 qman_register_data.val);
++      seq_printf(file, "value = 0x%08x\n", b);
++
++      return 0;
++}
++
++static int qman_ccsrmempeek_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, qman_ccsrmempeek_show, NULL);
++}
++
++static ssize_t qman_ccsrmempeek_write(struct file *f, const char __user *buf,
++                              size_t count, loff_t *off)
++{
++      int ret;
++      unsigned long val;
++
++      ret = user_input_convert(buf, count, &val);
++      if (ret)
++              return ret;
++      /* multiple of 4 */
++      if (val > (qman_ccsr_size - sizeof(u32))) {
++              pr_info("Input 0x%lx > 0x%llx\n",
++                      val, (qman_ccsr_size - sizeof(u32)));
++              return -EINVAL;
++      }
++      if (val & 0x3) {
++              pr_info("Input 0x%lx not multiple of 4\n", val);
++              return -EINVAL;
++      }
++      qman_register_data.val = val;
++      return count;
++}
++
++static const struct file_operations qman_ccsrmempeek_fops = {
++      .owner          = THIS_MODULE,
++      .open           = qman_ccsrmempeek_open,
++      .read           = seq_read,
++      .write          = qman_ccsrmempeek_write,
++};
++
++/*******************************************************************************
++ *  QMan state
++ ******************************************************************************/
++static int qman_fqd_state_show(struct seq_file *file, void *offset)
++{
++      struct qm_mcr_queryfq_np np;
++      struct qman_fq fq;
++      struct line_buffer_fq line_buf;
++      int ret, i;
++      u8 *state = file->private;
++      u32 qm_fq_state_cnt[ARRAY_SIZE(fqd_states)];
++
++      memset(qm_fq_state_cnt, 0, sizeof(qm_fq_state_cnt));
++      memset(&line_buf, 0, sizeof(line_buf));
++
++      seq_printf(file, "List of fq ids in state: %s\n", state_txt[*state]);
++
++      for (i = 1; i < fqid_max; i++) {
++              fq.fqid = i;
++              ret = qman_query_fq_np(&fq, &np);
++              if (ret)
++                      return ret;
++              if (*state == (np.state & QM_MCR_NP_STATE_MASK))
++                      add_to_line_buffer(&line_buf, fq.fqid, file);
++              /* Keep a summary count of all states */
++              if ((np.state & QM_MCR_NP_STATE_MASK) < ARRAY_SIZE(fqd_states))
++                      qm_fq_state_cnt[(np.state & QM_MCR_NP_STATE_MASK)]++;
++      }
++      flush_line_buffer(&line_buf, file);
++
++      for (i = 0; i < ARRAY_SIZE(fqd_states); i++) {
++              seq_printf(file, "%s count = %u\n", state_txt[i],
++                         qm_fq_state_cnt[i]);
++      }
++      return 0;
++}
++
++static int qman_fqd_state_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, qman_fqd_state_show, inode->i_private);
++}
++
++static const struct file_operations qman_fqd_state_fops =  {
++      .owner          = THIS_MODULE,
++      .open           = qman_fqd_state_open,
++      .read           = seq_read,
++};
++
++static int qman_fqd_ctrl_show(struct seq_file *file, void *offset)
++{
++      struct qm_fqd fqd;
++      struct qman_fq fq;
++      u32 fq_en_cnt = 0, fq_di_cnt = 0;
++      int ret, i;
++      struct mask_filter_s *data = file->private;
++      const char *ctrl_txt = get_fqd_ctrl_text(data->mask);
++      struct line_buffer_fq line_buf;
++
++      memset(&line_buf, 0, sizeof(line_buf));
++      seq_printf(file, "List of fq ids with: %s :%s\n",
++              ctrl_txt, (data->filter) ? "enabled" : "disabled");
++      for (i = 1; i < fqid_max; i++) {
++              fq.fqid = i;
++              memset(&fqd, 0, sizeof(struct qm_fqd));
++              ret = qman_query_fq(&fq, &fqd);
++              if (ret)
++                      return ret;
++              if (data->filter) {
++                      if (fqd.fq_ctrl & data->mask)
++                              add_to_line_buffer(&line_buf, fq.fqid, file);
++              } else {
++                      if (!(fqd.fq_ctrl & data->mask))
++                              add_to_line_buffer(&line_buf, fq.fqid, file);
++              }
++              if (fqd.fq_ctrl & data->mask)
++                      fq_en_cnt++;
++              else
++                      fq_di_cnt++;
++      }
++      flush_line_buffer(&line_buf, file);
++
++      seq_printf(file, "Total FQD with: %s :  enabled = %u\n",
++                 ctrl_txt, fq_en_cnt);
++      seq_printf(file, "Total FQD with: %s : disabled = %u\n",
++                 ctrl_txt, fq_di_cnt);
++      return 0;
++}
++
++/*******************************************************************************
++ *  QMan ctrl CGE, TDE, ORP, CTX, CPC, SFDR, BLOCK, HOLD, CACHE
++ ******************************************************************************/
++static int qman_fqd_ctrl_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, qman_fqd_ctrl_show, inode->i_private);
++}
++
++static const struct file_operations qman_fqd_ctrl_fops =  {
++      .owner          = THIS_MODULE,
++      .open           = qman_fqd_ctrl_open,
++      .read           = seq_read,
++};
++
++/*******************************************************************************
++ *  QMan ctrl summary
++ ******************************************************************************/
++/*******************************************************************************
++ *  QMan summary state
++ ******************************************************************************/
++static int qman_fqd_non_prog_summary_show(struct seq_file *file, void *offset)
++{
++      struct qm_mcr_queryfq_np np;
++      struct qman_fq fq;
++      int ret, i;
++      u32 qm_fq_state_cnt[ARRAY_SIZE(fqd_states)];
++
++      memset(qm_fq_state_cnt, 0, sizeof(qm_fq_state_cnt));
++
++      for (i = 1; i < fqid_max; i++) {
++              fq.fqid = i;
++              ret = qman_query_fq_np(&fq, &np);
++              if (ret)
++                      return ret;
++              /* Keep a summary count of all states */
++              if ((np.state & QM_MCR_NP_STATE_MASK) < ARRAY_SIZE(fqd_states))
++                      qm_fq_state_cnt[(np.state & QM_MCR_NP_STATE_MASK)]++;
++      }
++
++      for (i = 0; i < ARRAY_SIZE(fqd_states); i++) {
++              seq_printf(file, "%s count = %u\n", state_txt[i],
++                         qm_fq_state_cnt[i]);
++      }
++      return 0;
++}
++
++static int qman_fqd_prog_summary_show(struct seq_file *file, void *offset)
++{
++      struct qm_fqd fqd;
++      struct qman_fq fq;
++      int ret, i , j;
++      u32 qm_prog_cnt[ARRAY_SIZE(mask_filter)/2];
++
++      memset(qm_prog_cnt, 0, sizeof(qm_prog_cnt));
++
++      for (i = 1; i < fqid_max; i++) {
++              memset(&fqd, 0, sizeof(struct qm_fqd));
++              fq.fqid = i;
++              ret = qman_query_fq(&fq, &fqd);
++              if (ret)
++                      return ret;
++              /* Keep a summary count of all states */
++              for (j = 0; j < ARRAY_SIZE(mask_filter); j += 2)
++                      if ((fqd.fq_ctrl & QM_FQCTRL_MASK) &
++                                      mask_filter[j].mask)
++                              qm_prog_cnt[j/2]++;
++      }
++      for (i = 0; i < ARRAY_SIZE(mask_filter) / 2; i++) {
++              seq_printf(file, "%s count = %u\n",
++                      get_fqd_ctrl_text(mask_filter[i*2].mask),
++                         qm_prog_cnt[i]);
++      }
++      return 0;
++}
++
++static int qman_fqd_summary_show(struct seq_file *file, void *offset)
++{
++      int ret;
++
++      /* Display summary of non programmable fields */
++      ret = qman_fqd_non_prog_summary_show(file, offset);
++      if (ret)
++              return ret;
++      seq_puts(file, "-----------------------------------------\n");
++      /* Display programmable fields */
++      ret = qman_fqd_prog_summary_show(file, offset);
++      if (ret)
++              return ret;
++      return 0;
++}
++
++static int qman_fqd_summary_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, qman_fqd_summary_show, NULL);
++}
++
++static const struct file_operations qman_fqd_summary_fops =  {
++      .owner          = THIS_MODULE,
++      .open           = qman_fqd_summary_open,
++      .read           = seq_read,
++};
++
++/*******************************************************************************
++ *  QMan destination work queue
++ ******************************************************************************/
++struct qman_dest_wq_s {
++      u16 wq_id;
++};
++static struct qman_dest_wq_s qman_dest_wq_data = {
++      .wq_id = 0,
++};
++
++static int qman_fqd_dest_wq_show(struct seq_file *file, void *offset)
++{
++      struct qm_fqd fqd;
++      struct qman_fq fq;
++      int ret, i;
++      u16 *wq, wq_id = qman_dest_wq_data.wq_id;
++      struct line_buffer_fq line_buf;
++
++      memset(&line_buf, 0, sizeof(line_buf));
++      /* use vmalloc : need to allocate large memory region and don't
++       * require the memory to be physically contiguous. */
++      wq = vzalloc(sizeof(u16) * (0xFFFF+1));
++      if (!wq)
++              return -ENOMEM;
++
++      seq_printf(file, "List of fq ids with destination work queue id"
++                      " = 0x%x\n", wq_id);
++
++      for (i = 1; i < fqid_max; i++) {
++              fq.fqid = i;
++              memset(&fqd, 0, sizeof(struct qm_fqd));
++              ret = qman_query_fq(&fq, &fqd);
++              if (ret) {
++                      vfree(wq);
++                      return ret;
++              }
++              if (wq_id == fqd.dest_wq)
++                      add_to_line_buffer(&line_buf, fq.fqid, file);
++              wq[fqd.dest_wq]++;
++      }
++      flush_line_buffer(&line_buf, file);
++
++      seq_puts(file, "Summary of all FQD destination work queue values\n");
++      for (i = 0; i < 0xFFFF; i++) {
++              if (wq[i])
++                      seq_printf(file, "Channel: 0x%x WQ: 0x%x WQ_ID: 0x%x, "
++                              "count = %u\n", i >> 3, i & 0x3, i, wq[i]);
++      }
++      vfree(wq);
++      return 0;
++}
++
++static ssize_t qman_fqd_dest_wq_write(struct file *f, const char __user *buf,
++                                    size_t count, loff_t *off)
++{
++      int ret;
++      unsigned long val;
++
++      ret = user_input_convert(buf, count, &val);
++      if (ret)
++              return ret;
++      if (val > 0xFFFF)
++              return -EINVAL;
++      qman_dest_wq_data.wq_id = val;
++      return count;
++}
++
++static int qman_fqd_dest_wq_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, qman_fqd_dest_wq_show, NULL);
++}
++
++static const struct file_operations qman_fqd_dest_wq_fops =  {
++      .owner          = THIS_MODULE,
++      .open           = qman_fqd_dest_wq_open,
++      .read           = seq_read,
++      .write          = qman_fqd_dest_wq_write,
++};
++
++/*******************************************************************************
++ *  QMan Intra-Class Scheduling Credit
++ ******************************************************************************/
++static int qman_fqd_cred_show(struct seq_file *file, void *offset)
++{
++      struct qm_fqd fqd;
++      struct qman_fq fq;
++      int ret, i;
++      u32 fq_cnt = 0;
++      struct line_buffer_fq line_buf;
++
++      memset(&line_buf, 0, sizeof(line_buf));
++      seq_puts(file, "List of fq ids with Intra-Class Scheduling Credit > 0"
++                      "\n");
++
++      for (i = 1; i < fqid_max; i++) {
++              fq.fqid = i;
++              memset(&fqd, 0, sizeof(struct qm_fqd));
++              ret = qman_query_fq(&fq, &fqd);
++              if (ret)
++                      return ret;
++              if (fqd.ics_cred > 0) {
++                      add_to_line_buffer(&line_buf, fq.fqid, file);
++                      fq_cnt++;
++              }
++      }
++      flush_line_buffer(&line_buf, file);
++
++      seq_printf(file, "Total FQD with ics_cred > 0 = %d\n", fq_cnt);
++      return 0;
++}
++
++static int qman_fqd_cred_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, qman_fqd_cred_show, NULL);
++}
++
++static const struct file_operations qman_fqd_cred_fops =  {
++      .owner          = THIS_MODULE,
++      .open           = qman_fqd_cred_open,
++      .read           = seq_read,
++};
++
++/*******************************************************************************
++ *  Class Queue Fields
++ ******************************************************************************/
++struct query_cq_fields_data_s {
++      u32 cqid;
++};
++
++static struct query_cq_fields_data_s query_cq_fields_data = {
++      .cqid = 1,
++};
++
++static int query_cq_fields_show(struct seq_file *file, void *offset)
++{
++      int ret;
++      struct qm_mcr_ceetm_cq_query query_result;
++      unsigned int cqid;
++      unsigned int portal;
++
++      if ((qman_ip_rev & 0xFF00) < QMAN_REV30)
++              return -EINVAL;
++
++      cqid = query_cq_fields_data.cqid & 0x00FFFFFF;
++      portal = query_cq_fields_data.cqid >> 24;
++      if (portal > qm_dc_portal_fman1)
++              return -EINVAL;
++
++      ret = qman_ceetm_query_cq(cqid, portal, &query_result);
++      if (ret)
++              return ret;
++      seq_printf(file, "Query CQ Fields Result cqid 0x%x on DCP %d\n",
++                                                              cqid, portal);
++      seq_printf(file, " ccgid: %u\n", query_result.ccgid);
++      seq_printf(file, " state: %u\n", query_result.state);
++      seq_printf(file, " pfdr_hptr: %u\n", query_result.pfdr_hptr);
++      seq_printf(file, " pfdr_tptr: %u\n", query_result.pfdr_tptr);
++      seq_printf(file, " od1_xsfdr: %u\n", query_result.od1_xsfdr);
++      seq_printf(file, " od2_xsfdr: %u\n", query_result.od2_xsfdr);
++      seq_printf(file, " od3_xsfdr: %u\n", query_result.od3_xsfdr);
++      seq_printf(file, " od4_xsfdr: %u\n", query_result.od4_xsfdr);
++      seq_printf(file, " od5_xsfdr: %u\n", query_result.od5_xsfdr);
++      seq_printf(file, " od6_xsfdr: %u\n", query_result.od6_xsfdr);
++      seq_printf(file, " ra1_xsfdr: %u\n", query_result.ra1_xsfdr);
++      seq_printf(file, " ra2_xsfdr: %u\n", query_result.ra2_xsfdr);
++      seq_printf(file, " frame_count: %u\n", query_result.frm_cnt);
++
++      return 0;
++}
++
++static int query_cq_fields_open(struct inode *inode,
++                                      struct file *file)
++{
++      return single_open(file, query_cq_fields_show, NULL);
++}
++
++static ssize_t query_cq_fields_write(struct file *f,
++                      const char __user *buf, size_t count, loff_t *off)
++{
++      int ret;
++      unsigned long val;
++
++      ret = user_input_convert(buf, count, &val);
++      if (ret)
++              return ret;
++      query_cq_fields_data.cqid = (u32)val;
++      return count;
++}
++
++static const struct file_operations query_cq_fields_fops = {
++      .owner          = THIS_MODULE,
++      .open           = query_cq_fields_open,
++      .read           = seq_read,
++      .write          = query_cq_fields_write,
++      .release        = single_release,
++};
++
++/*******************************************************************************
++ *  READ CEETM_XSFDR_IN_USE
++ ******************************************************************************/
++struct query_ceetm_xsfdr_data_s {
++      enum qm_dc_portal dcp_portal;
++};
++
++static struct query_ceetm_xsfdr_data_s query_ceetm_xsfdr_data;
++
++static int query_ceetm_xsfdr_show(struct seq_file *file, void *offset)
++{
++      int ret;
++      unsigned int xsfdr_in_use;
++      enum qm_dc_portal portal;
++
++
++      if (qman_ip_rev < QMAN_REV31)
++              return -EINVAL;
++
++      portal = query_ceetm_xsfdr_data.dcp_portal;
++      ret = qman_ceetm_get_xsfdr(portal, &xsfdr_in_use);
++      if (ret) {
++              seq_printf(file, "Read CEETM_XSFDR_IN_USE on DCP %d failed\n",
++                                                              portal);
++              return ret;
++      }
++
++      seq_printf(file, "DCP%d: CEETM_XSFDR_IN_USE number is %u\n", portal,
++                                              (xsfdr_in_use & 0x1FFF));
++      return 0;
++}
++
++static int query_ceetm_xsfdr_open(struct inode *inode,
++                                      struct file *file)
++{
++      return single_open(file, query_ceetm_xsfdr_show, NULL);
++}
++
++static ssize_t query_ceetm_xsfdr_write(struct file *f,
++                      const char __user *buf, size_t count, loff_t *off)
++{
++      int ret;
++      unsigned long val;
++
++      ret = user_input_convert(buf, count, &val);
++      if (ret)
++              return ret;
++      if (val > qm_dc_portal_fman1)
++              return -EINVAL;
++      query_ceetm_xsfdr_data.dcp_portal = (u32)val;
++      return count;
++}
++
++static const struct file_operations query_ceetm_xsfdr_fops = {
++      .owner          = THIS_MODULE,
++      .open           = query_ceetm_xsfdr_open,
++      .read           = seq_read,
++      .write          = query_ceetm_xsfdr_write,
++      .release        = single_release,
++};
++
++/* helper macros used in qman_debugfs_module_init */
++#define QMAN_DBGFS_ENTRY(name, mode, parent, data, fops) \
++      do { \
++              d = debugfs_create_file(name, \
++                      mode, parent, \
++                      data, \
++                      fops); \
++              if (d == NULL) { \
++                      ret = -ENOMEM; \
++                      goto _return; \
++              } \
++      } while (0)
++
++/* dfs_root as parent */
++#define QMAN_DBGFS_ENTRY_ROOT(name, mode, data, fops) \
++      QMAN_DBGFS_ENTRY(name, mode, dfs_root, data, fops)
++
++/* fqd_root as parent */
++#define QMAN_DBGFS_ENTRY_FQDROOT(name, mode, data, fops) \
++      QMAN_DBGFS_ENTRY(name, mode, fqd_root, data, fops)
++
++/* fqd state */
++#define QMAN_DBGFS_ENTRY_FQDSTATE(name, index) \
++      QMAN_DBGFS_ENTRY_FQDROOT(name, S_IRUGO, \
++      (void *)&mask_filter[index], &qman_fqd_ctrl_fops)
++
++static int __init qman_debugfs_module_init(void)
++{
++      int ret = 0;
++      struct dentry *d, *fqd_root;
++      u32 reg;
++
++      fqid_max = 0;
++      init_ccsrmempeek();
++      if (qman_ccsr_start) {
++              if (!qman_ccsrmempeek(&reg, QM_FQD_AR)) {
++                      /* extract the size of the FQD window */
++                      reg = reg & 0x3f;
++                      /* calculate valid frame queue descriptor range */
++                      fqid_max = (1 << (reg + 1)) / QM_FQD_BLOCK_SIZE;
++              }
++      }
++      dfs_root = debugfs_create_dir("qman", NULL);
++      fqd_root = debugfs_create_dir("fqd", dfs_root);
++      if (dfs_root == NULL || fqd_root == NULL) {
++              ret = -ENOMEM;
++              pr_err("Cannot create qman/fqd debugfs dir\n");
++              goto _return;
++      }
++      if (fqid_max) {
++              QMAN_DBGFS_ENTRY_ROOT("ccsrmempeek", S_IRUGO | S_IWUGO,
++                              NULL, &qman_ccsrmempeek_fops);
++      }
++      QMAN_DBGFS_ENTRY_ROOT("query_fq_np_fields", S_IRUGO | S_IWUGO,
++              &query_fq_np_fields_data, &query_fq_np_fields_fops);
++
++      QMAN_DBGFS_ENTRY_ROOT("query_fq_fields", S_IRUGO | S_IWUGO,
++              &query_fq_fields_data, &query_fq_fields_fops);
++
++      QMAN_DBGFS_ENTRY_ROOT("query_wq_lengths", S_IRUGO | S_IWUGO,
++              &query_wq_lengths_data, &query_wq_lengths_fops);
++
++      QMAN_DBGFS_ENTRY_ROOT("query_cgr", S_IRUGO | S_IWUGO,
++              &query_cgr_data, &query_cgr_fops);
++
++      QMAN_DBGFS_ENTRY_ROOT("query_congestion", S_IRUGO,
++              NULL, &query_congestion_fops);
++
++      QMAN_DBGFS_ENTRY_ROOT("testwrite_cgr", S_IRUGO,
++              NULL, &testwrite_cgr_fops);
++
++      QMAN_DBGFS_ENTRY_ROOT("testwrite_cgr_cgrid", S_IRUGO | S_IWUGO,
++              NULL, &teswrite_cgr_cgrid_fops);
++
++      QMAN_DBGFS_ENTRY_ROOT("testwrite_cgr_ibcnt", S_IRUGO | S_IWUGO,
++              NULL, &teswrite_cgr_ibcnt_fops);
++
++      QMAN_DBGFS_ENTRY_ROOT("query_ceetm_ccgr", S_IRUGO | S_IWUGO,
++              &query_ccgr_data, &query_ccgr_fops);
++      /* Create files with fqd_root as parent */
++
++      QMAN_DBGFS_ENTRY_FQDROOT("stateoos", S_IRUGO,
++              (void *)&fqd_states[QM_MCR_NP_STATE_OOS], &qman_fqd_state_fops);
++
++      QMAN_DBGFS_ENTRY_FQDROOT("state_retired", S_IRUGO,
++              (void *)&fqd_states[QM_MCR_NP_STATE_RETIRED],
++              &qman_fqd_state_fops);
++
++      QMAN_DBGFS_ENTRY_FQDROOT("state_tentatively_sched", S_IRUGO,
++              (void *)&fqd_states[QM_MCR_NP_STATE_TEN_SCHED],
++              &qman_fqd_state_fops);
++
++      QMAN_DBGFS_ENTRY_FQDROOT("state_truly_sched", S_IRUGO,
++              (void *)&fqd_states[QM_MCR_NP_STATE_TRU_SCHED],
++              &qman_fqd_state_fops);
++
++      QMAN_DBGFS_ENTRY_FQDROOT("state_parked", S_IRUGO,
++              (void *)&fqd_states[QM_MCR_NP_STATE_PARKED],
++              &qman_fqd_state_fops);
++
++      QMAN_DBGFS_ENTRY_FQDROOT("state_active", S_IRUGO,
++              (void *)&fqd_states[QM_MCR_NP_STATE_ACTIVE],
++              &qman_fqd_state_fops);
++      QMAN_DBGFS_ENTRY_ROOT("query_cq_fields", S_IRUGO | S_IWUGO,
++              &query_cq_fields_data, &query_cq_fields_fops);
++      QMAN_DBGFS_ENTRY_ROOT("query_ceetm_xsfdr_in_use", S_IRUGO | S_IWUGO,
++              &query_ceetm_xsfdr_data, &query_ceetm_xsfdr_fops);
++
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("cge_enable", 17);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("cge_disable", 16);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("tde_enable", 15);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("tde_disable", 14);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("orp_enable", 13);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("orp_disable", 12);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("ctx_a_stashing_enable", 11);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("ctx_a_stashing_disable", 10);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("cpc_enable", 9);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("cpc_disable", 8);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("sfdr_enable", 7);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("sfdr_disable", 6);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("avoid_blocking_enable", 5);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("avoid_blocking_disable", 4);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("hold_active_enable", 3);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("hold_active_disable", 2);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("prefer_in_cache_enable", 1);
++
++      QMAN_DBGFS_ENTRY_FQDSTATE("prefer_in_cache_disable", 0);
++
++      QMAN_DBGFS_ENTRY_FQDROOT("summary", S_IRUGO,
++              NULL, &qman_fqd_summary_fops);
++
++      QMAN_DBGFS_ENTRY_FQDROOT("wq", S_IRUGO | S_IWUGO,
++              NULL, &qman_fqd_dest_wq_fops);
++
++      QMAN_DBGFS_ENTRY_FQDROOT("cred", S_IRUGO,
++              NULL, &qman_fqd_cred_fops);
++
++      return 0;
++
++_return:
++      debugfs_remove_recursive(dfs_root);
++      return ret;
++}
++
++static void __exit qman_debugfs_module_exit(void)
++{
++      debugfs_remove_recursive(dfs_root);
++}
++
++module_init(qman_debugfs_module_init);
++module_exit(qman_debugfs_module_exit);
++MODULE_LICENSE("Dual BSD/GPL");
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/qman_driver.c
+@@ -0,0 +1,961 @@
++/* Copyright 2008-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "qman_private.h"
++
++#include <asm/smp.h>  /* hard_smp_processor_id() if !CONFIG_SMP */
++#ifdef CONFIG_HOTPLUG_CPU
++#include <linux/cpu.h>
++#endif
++
++/* Global variable containing revision id (even on non-control plane systems
++ * where CCSR isn't available) */
++u16 qman_ip_rev;
++EXPORT_SYMBOL(qman_ip_rev);
++u8 qman_ip_cfg;
++EXPORT_SYMBOL(qman_ip_cfg);
++u16 qm_channel_pool1 = QMAN_CHANNEL_POOL1;
++EXPORT_SYMBOL(qm_channel_pool1);
++u16 qm_channel_caam = QMAN_CHANNEL_CAAM;
++EXPORT_SYMBOL(qm_channel_caam);
++u16 qm_channel_pme = QMAN_CHANNEL_PME;
++EXPORT_SYMBOL(qm_channel_pme);
++u16 qm_channel_dce = QMAN_CHANNEL_DCE;
++EXPORT_SYMBOL(qm_channel_dce);
++u16 qman_portal_max;
++EXPORT_SYMBOL(qman_portal_max);
++
++u32 qman_clk;
++struct qm_ceetm qman_ceetms[QMAN_CEETM_MAX];
++/* the qman ceetm instances on the given SoC */
++u8 num_ceetms;
++
++/* For these variables, and the portal-initialisation logic, the
++ * comments in bman_driver.c apply here so won't be repeated. */
++static struct qman_portal *shared_portals[NR_CPUS];
++static int num_shared_portals;
++static int shared_portals_idx;
++static LIST_HEAD(unused_pcfgs);
++static DEFINE_SPINLOCK(unused_pcfgs_lock);
++
++/* A SDQCR mask comprising all the available/visible pool channels */
++static u32 pools_sdqcr;
++
++#define STR_ERR_NOPROP            "No '%s' property in node %s\n"
++#define STR_ERR_CELL      "'%s' is not a %d-cell range in node %s\n"
++#define STR_FQID_RANGE            "fsl,fqid-range"
++#define STR_POOL_CHAN_RANGE "fsl,pool-channel-range"
++#define STR_CGRID_RANGE            "fsl,cgrid-range"
++
++/* A "fsl,fqid-range" node; release the given range to the allocator */
++static __init int fsl_fqid_range_init(struct device_node *node)
++{
++      int ret;
++      const u32 *range = of_get_property(node, STR_FQID_RANGE, &ret);
++      if (!range) {
++              pr_err(STR_ERR_NOPROP, STR_FQID_RANGE, node->full_name);
++              return -EINVAL;
++      }
++      if (ret != 8) {
++              pr_err(STR_ERR_CELL, STR_FQID_RANGE, 2, node->full_name);
++              return -EINVAL;
++      }
++      qman_seed_fqid_range(be32_to_cpu(range[0]), be32_to_cpu(range[1]));
++      pr_info("Qman: FQID allocator includes range %d:%d\n",
++              be32_to_cpu(range[0]), be32_to_cpu(range[1]));
++      return 0;
++}
++
++/* A "fsl,pool-channel-range" node; add to the SDQCR mask only */
++static __init int fsl_pool_channel_range_sdqcr(struct device_node *node)
++{
++      int ret;
++      const u32 *chanid = of_get_property(node, STR_POOL_CHAN_RANGE, &ret);
++      if (!chanid) {
++              pr_err(STR_ERR_NOPROP, STR_POOL_CHAN_RANGE, node->full_name);
++              return -EINVAL;
++      }
++      if (ret != 8) {
++              pr_err(STR_ERR_CELL, STR_POOL_CHAN_RANGE, 1, node->full_name);
++              return -EINVAL;
++      }
++      for (ret = 0; ret < be32_to_cpu(chanid[1]); ret++)
++              pools_sdqcr |= QM_SDQCR_CHANNELS_POOL_CONV(be32_to_cpu(chanid[0]) + ret);
++      return 0;
++}
++
++/* A "fsl,pool-channel-range" node; release the given range to the allocator */
++static __init int fsl_pool_channel_range_init(struct device_node *node)
++{
++      int ret;
++      const u32 *chanid = of_get_property(node, STR_POOL_CHAN_RANGE, &ret);
++      if (!chanid) {
++              pr_err(STR_ERR_NOPROP, STR_POOL_CHAN_RANGE, node->full_name);
++              return -EINVAL;
++      }
++      if (ret != 8) {
++              pr_err(STR_ERR_CELL, STR_POOL_CHAN_RANGE, 1, node->full_name);
++              return -EINVAL;
++      }
++      qman_seed_pool_range(be32_to_cpu(chanid[0]), be32_to_cpu(chanid[1]));
++      pr_info("Qman: pool channel allocator includes range %d:%d\n",
++              be32_to_cpu(chanid[0]), be32_to_cpu(chanid[1]));
++      return 0;
++}
++
++/* A "fsl,cgrid-range" node; release the given range to the allocator */
++static __init int fsl_cgrid_range_init(struct device_node *node)
++{
++      struct qman_cgr cgr;
++      int ret, errors = 0;
++      const u32 *range = of_get_property(node, STR_CGRID_RANGE, &ret);
++      if (!range) {
++              pr_err(STR_ERR_NOPROP, STR_CGRID_RANGE, node->full_name);
++              return -EINVAL;
++      }
++      if (ret != 8) {
++              pr_err(STR_ERR_CELL, STR_CGRID_RANGE, 2, node->full_name);
++              return -EINVAL;
++      }
++      qman_seed_cgrid_range(be32_to_cpu(range[0]), be32_to_cpu(range[1]));
++      pr_info("Qman: CGRID allocator includes range %d:%d\n",
++              be32_to_cpu(range[0]), be32_to_cpu(range[1]));
++      for (cgr.cgrid = 0; cgr.cgrid < __CGR_NUM; cgr.cgrid++) {
++              ret = qman_modify_cgr(&cgr, QMAN_CGR_FLAG_USE_INIT, NULL);
++              if (ret)
++                      errors++;
++      }
++      if (errors)
++              pr_err("Warning: %d error%s while initialising CGRs %d:%d\n",
++                      errors, (errors > 1) ? "s" : "", range[0], range[1]);
++      return 0;
++}
++
++static __init int fsl_ceetm_init(struct device_node *node)
++{
++      enum qm_dc_portal dcp_portal;
++      struct qm_ceetm_sp *sp;
++      struct qm_ceetm_lni *lni;
++      int ret, i;
++      const u32 *range;
++
++      /* Find LFQID range */
++      range = of_get_property(node, "fsl,ceetm-lfqid-range", &ret);
++      if (!range) {
++              pr_err("No fsl,ceetm-lfqid-range in node %s\n",
++                                                      node->full_name);
++              return -EINVAL;
++      }
++      if (ret != 8) {
++              pr_err("fsl,ceetm-lfqid-range is not a 2-cell range in node"
++                                      " %s\n", node->full_name);
++              return -EINVAL;
++      }
++
++      dcp_portal = (be32_to_cpu(range[0]) & 0x0F0000) >> 16;
++      if (dcp_portal > qm_dc_portal_fman1) {
++              pr_err("The DCP portal %d doesn't support CEETM\n", dcp_portal);
++              return -EINVAL;
++      }
++
++      if (dcp_portal == qm_dc_portal_fman0)
++              qman_seed_ceetm0_lfqid_range(be32_to_cpu(range[0]), be32_to_cpu(range[1]));
++      if (dcp_portal == qm_dc_portal_fman1)
++              qman_seed_ceetm1_lfqid_range(be32_to_cpu(range[0]), be32_to_cpu(range[1]));
++      pr_debug("Qman: The lfqid allocator of CEETM %d includes range"
++               " 0x%x:0x%x\n", dcp_portal, be32_to_cpu(range[0]), be32_to_cpu(range[1]));
++
++      qman_ceetms[dcp_portal].idx = dcp_portal;
++      INIT_LIST_HEAD(&qman_ceetms[dcp_portal].sub_portals);
++      INIT_LIST_HEAD(&qman_ceetms[dcp_portal].lnis);
++
++      /* Find Sub-portal range */
++      range = of_get_property(node, "fsl,ceetm-sp-range", &ret);
++      if (!range) {
++              pr_err("No fsl,ceetm-sp-range in node %s\n", node->full_name);
++              return -EINVAL;
++      }
++      if (ret != 8) {
++              pr_err("fsl,ceetm-sp-range is not a 2-cell range in node %s\n",
++                                                      node->full_name);
++              return -EINVAL;
++      }
++
++      for (i = 0; i < be32_to_cpu(range[1]); i++) {
++              sp = kzalloc(sizeof(*sp), GFP_KERNEL);
++              if (!sp) {
++                      pr_err("Can't alloc memory for sub-portal %d\n",
++                                                      range[0] + i);
++                      return -ENOMEM;
++              }
++              sp->idx = be32_to_cpu(range[0]) + i;
++              sp->dcp_idx = dcp_portal;
++              sp->is_claimed = 0;
++              list_add_tail(&sp->node, &qman_ceetms[dcp_portal].sub_portals);
++              sp++;
++      }
++      pr_debug("Qman: Reserve sub-portal %d:%d for CEETM %d\n",
++               be32_to_cpu(range[0]), be32_to_cpu(range[1]), dcp_portal);
++      qman_ceetms[dcp_portal].sp_range[0] = be32_to_cpu(range[0]);
++      qman_ceetms[dcp_portal].sp_range[1] = be32_to_cpu(range[1]);
++
++      /* Find LNI range */
++      range = of_get_property(node, "fsl,ceetm-lni-range", &ret);
++      if (!range) {
++              pr_err("No fsl,ceetm-lni-range in node %s\n", node->full_name);
++              return -EINVAL;
++      }
++      if (ret != 8) {
++              pr_err("fsl,ceetm-lni-range is not a 2-cell range in node %s\n",
++                                                      node->full_name);
++              return -EINVAL;
++      }
++
++      for (i = 0; i < be32_to_cpu(range[1]); i++) {
++              lni = kzalloc(sizeof(*lni), GFP_KERNEL);
++              if (!lni) {
++                      pr_err("Can't alloc memory for LNI %d\n",
++                                                      range[0] + i);
++                      return -ENOMEM;
++              }
++              lni->idx = be32_to_cpu(range[0]) + i;
++              lni->dcp_idx = dcp_portal;
++              lni->is_claimed = 0;
++              INIT_LIST_HEAD(&lni->channels);
++              list_add_tail(&lni->node, &qman_ceetms[dcp_portal].lnis);
++              lni++;
++      }
++      pr_debug("Qman: Reserve LNI %d:%d for CEETM %d\n",
++               be32_to_cpu(range[0]), be32_to_cpu(range[1]), dcp_portal);
++      qman_ceetms[dcp_portal].lni_range[0] = be32_to_cpu(range[0]);
++      qman_ceetms[dcp_portal].lni_range[1] = be32_to_cpu(range[1]);
++
++      /* Find CEETM channel range */
++      range = of_get_property(node, "fsl,ceetm-channel-range", &ret);
++      if (!range) {
++              pr_err("No fsl,ceetm-channel-range in node %s\n",
++                                                      node->full_name);
++              return -EINVAL;
++      }
++      if (ret != 8) {
++              pr_err("fsl,ceetm-channel-range is not a 2-cell range in node"
++                                              "%s\n", node->full_name);
++              return -EINVAL;
++      }
++
++      if (dcp_portal == qm_dc_portal_fman0)
++              qman_seed_ceetm0_channel_range(be32_to_cpu(range[0]), be32_to_cpu(range[1]));
++      if (dcp_portal == qm_dc_portal_fman1)
++              qman_seed_ceetm1_channel_range(be32_to_cpu(range[0]), be32_to_cpu(range[1]));
++      pr_debug("Qman: The channel allocator of CEETM %d includes"
++               " range %d:%d\n", dcp_portal, be32_to_cpu(range[0]), be32_to_cpu(range[1]));
++
++      /* Set CEETM PRES register */
++      ret = qman_ceetm_set_prescaler(dcp_portal);
++      if (ret)
++              return ret;
++      return 0;
++}
++
++static void qman_get_ip_revision(struct device_node *dn)
++{
++      u16 ip_rev = 0;
++      u8 ip_cfg = QMAN_REV_CFG_0;
++      for_each_compatible_node(dn, NULL, "fsl,qman-portal") {
++              if (!of_device_is_available(dn))
++                      continue;
++              if (of_device_is_compatible(dn, "fsl,qman-portal-1.0") ||
++                      of_device_is_compatible(dn, "fsl,qman-portal-1.0.0")) {
++                      pr_err("QMAN rev1.0 on P4080 rev1 is not supported!\n");
++                      BUG_ON(1);
++              } else if (of_device_is_compatible(dn, "fsl,qman-portal-1.1") ||
++                      of_device_is_compatible(dn, "fsl,qman-portal-1.1.0")) {
++                      ip_rev = QMAN_REV11;
++                      qman_portal_max = 10;
++              } else if (of_device_is_compatible(dn, "fsl,qman-portal-1.2") ||
++                      of_device_is_compatible(dn, "fsl,qman-portal-1.2.0")) {
++                      ip_rev = QMAN_REV12;
++                      qman_portal_max = 10;
++              } else if (of_device_is_compatible(dn, "fsl,qman-portal-2.0") ||
++                      of_device_is_compatible(dn, "fsl,qman-portal-2.0.0")) {
++                      ip_rev = QMAN_REV20;
++                      qman_portal_max = 3;
++              } else if (of_device_is_compatible(dn,
++                                              "fsl,qman-portal-3.0.0")) {
++                      ip_rev = QMAN_REV30;
++                      qman_portal_max = 50;
++              } else if (of_device_is_compatible(dn,
++                                              "fsl,qman-portal-3.0.1")) {
++                      ip_rev = QMAN_REV30;
++                      qman_portal_max = 25;
++                      ip_cfg = QMAN_REV_CFG_1;
++              } else if (of_device_is_compatible(dn,
++                                              "fsl,qman-portal-3.1.0")) {
++                      ip_rev = QMAN_REV31;
++                      qman_portal_max = 50;
++              } else if (of_device_is_compatible(dn,
++                                              "fsl,qman-portal-3.1.1")) {
++                      ip_rev = QMAN_REV31;
++                      qman_portal_max = 25;
++                      ip_cfg = QMAN_REV_CFG_1;
++              } else if (of_device_is_compatible(dn,
++                                              "fsl,qman-portal-3.1.2")) {
++                      ip_rev = QMAN_REV31;
++                      qman_portal_max = 18;
++                      ip_cfg = QMAN_REV_CFG_2;
++              } else if (of_device_is_compatible(dn,
++                                              "fsl,qman-portal-3.1.3")) {
++                      ip_rev = QMAN_REV31;
++                      qman_portal_max = 10;
++                      ip_cfg = QMAN_REV_CFG_3;
++              } else if (of_device_is_compatible(dn,
++                                              "fsl,qman-portal-3.2.0")) {
++                      ip_rev = QMAN_REV32;
++                      qman_portal_max = 10;
++                      ip_cfg = QMAN_REV_CFG_3; // TODO: Verify for ls1043
++              } else if (of_device_is_compatible(dn,
++                                              "fsl,qman-portal-3.2.1")) {
++                      ip_rev = QMAN_REV32;
++                      qman_portal_max = 10;
++                      ip_cfg = QMAN_REV_CFG_3;
++              } else {
++                      pr_warn("unknown QMan version in portal node,"
++                              "default to rev1.1\n");
++                      ip_rev = QMAN_REV11;
++                      qman_portal_max = 10;
++              }
++
++              if (!qman_ip_rev) {
++                      if (ip_rev) {
++                              qman_ip_rev = ip_rev;
++                              qman_ip_cfg = ip_cfg;
++                      } else {
++                              pr_warn("unknown Qman version,"
++                                      " default to rev1.1\n");
++                              qman_ip_rev = QMAN_REV11;
++                              qman_ip_cfg = QMAN_REV_CFG_0;
++                      }
++              } else if (ip_rev && (qman_ip_rev != ip_rev))
++                      pr_warn("Revision=0x%04x, but portal '%s' has"
++                                                      " 0x%04x\n",
++                      qman_ip_rev, dn->full_name, ip_rev);
++              if (qman_ip_rev == ip_rev)
++                      break;
++      }
++}
++
++/* Parse a portal node, perform generic mapping duties and return the config. It
++ * is not known at this stage for what purpose (or even if) the portal will be
++ * used. */
++static struct qm_portal_config * __init parse_pcfg(struct device_node *node)
++{
++      struct qm_portal_config *pcfg;
++      const u32 *index_p;
++      u32 index, channel;
++      int irq, ret;
++      resource_size_t len;
++
++      pcfg = kmalloc(sizeof(*pcfg), GFP_KERNEL);
++      if (!pcfg) {
++              pr_err("can't allocate portal config");
++              return NULL;
++      }
++
++      /*
++       * This is a *horrible hack*, but the IOMMU/PAMU driver needs a
++       * 'struct device' in order to get the PAMU stashing setup and the QMan
++       * portal [driver] won't function at all without ring stashing
++       *
++       * Making the QMan portal driver nice and proper is part of the
++       * upstreaming effort
++       */
++      pcfg->dev.bus = &platform_bus_type;
++      pcfg->dev.of_node = node;
++#ifdef CONFIG_FSL_PAMU
++      pcfg->dev.archdata.iommu_domain = NULL;
++#endif
++
++      ret = of_address_to_resource(node, DPA_PORTAL_CE,
++                              &pcfg->addr_phys[DPA_PORTAL_CE]);
++      if (ret) {
++              pr_err("Can't get %s property '%s'\n", node->full_name,
++                      "reg::CE");
++              goto err;
++      }
++      ret = of_address_to_resource(node, DPA_PORTAL_CI,
++                              &pcfg->addr_phys[DPA_PORTAL_CI]);
++      if (ret) {
++              pr_err("Can't get %s property '%s'\n", node->full_name,
++                      "reg::CI");
++              goto err;
++      }
++      index_p = of_get_property(node, "cell-index", &ret);
++      if (!index_p || (ret != 4)) {
++              pr_err("Can't get %s property '%s'\n", node->full_name,
++                      "cell-index");
++              goto err;
++      }
++      index = be32_to_cpu(*index_p);
++      if (index >= qman_portal_max) {
++              pr_err("QMan portal index %d is beyond max (%d)\n",
++                     index, qman_portal_max);
++              goto err;
++      }
++
++      channel = index + QM_CHANNEL_SWPORTAL0;
++      pcfg->public_cfg.channel = channel;
++      pcfg->public_cfg.cpu = -1;
++      irq = irq_of_parse_and_map(node, 0);
++      if (irq == 0) {
++              pr_err("Can't get %s property '%s'\n", node->full_name,
++                      "interrupts");
++              goto err;
++      }
++      pcfg->public_cfg.irq = irq;
++      pcfg->public_cfg.index = index;
++#ifdef CONFIG_FSL_QMAN_CONFIG
++      /* We need the same LIODN offset for all portals */
++      qman_liodn_fixup(pcfg->public_cfg.channel);
++#endif
++
++      len = resource_size(&pcfg->addr_phys[DPA_PORTAL_CE]);
++      if (len != (unsigned long)len)
++              goto err;
++
++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++      pcfg->addr_virt[DPA_PORTAL_CE] = ioremap_cache_ns(
++                                pcfg->addr_phys[DPA_PORTAL_CE].start,
++                                resource_size(&pcfg->addr_phys[DPA_PORTAL_CE]));
++
++        pcfg->addr_virt[DPA_PORTAL_CI] = ioremap(
++                                pcfg->addr_phys[DPA_PORTAL_CI].start,
++                                resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]));
++#else
++      pcfg->addr_virt[DPA_PORTAL_CE] = ioremap_prot(
++                              pcfg->addr_phys[DPA_PORTAL_CE].start,
++                              (unsigned long)len,
++                              0);
++      pcfg->addr_virt[DPA_PORTAL_CI] = ioremap_prot(
++                              pcfg->addr_phys[DPA_PORTAL_CI].start,
++                              resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]),
++                              _PAGE_GUARDED | _PAGE_NO_CACHE);
++#endif
++      return pcfg;
++err:
++      kfree(pcfg);
++      return NULL;
++}
++
++static struct qm_portal_config *get_pcfg(struct list_head *list)
++{
++      struct qm_portal_config *pcfg;
++      if (list_empty(list))
++              return NULL;
++      pcfg = list_entry(list->prev, struct qm_portal_config, list);
++      list_del(&pcfg->list);
++      return pcfg;
++}
++
++static struct qm_portal_config *get_pcfg_idx(struct list_head *list, u32 idx)
++{
++      struct qm_portal_config *pcfg;
++      if (list_empty(list))
++              return NULL;
++      list_for_each_entry(pcfg, list, list) {
++              if (pcfg->public_cfg.index == idx) {
++                      list_del(&pcfg->list);
++                      return pcfg;
++              }
++      }
++      return NULL;
++}
++
++static void portal_set_cpu(struct qm_portal_config *pcfg, int cpu)
++{
++#ifdef CONFIG_FSL_PAMU
++      int ret;
++      int window_count = 1;
++      struct iommu_domain_geometry geom_attr;
++      struct pamu_stash_attribute stash_attr;
++
++      pcfg->iommu_domain = iommu_domain_alloc(&platform_bus_type);
++      if (!pcfg->iommu_domain) {
++              pr_err(KBUILD_MODNAME ":%s(): iommu_domain_alloc() failed",
++                         __func__);
++              goto _no_iommu;
++      }
++      geom_attr.aperture_start = 0;
++      geom_attr.aperture_end =
++              ((dma_addr_t)1 << min(8 * sizeof(dma_addr_t), (size_t)36)) - 1;
++      geom_attr.force_aperture = true;
++      ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_GEOMETRY,
++                                  &geom_attr);
++      if (ret < 0) {
++              pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
++                         __func__, ret);
++              goto _iommu_domain_free;
++      }
++      ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_WINDOWS,
++                                  &window_count);
++      if (ret < 0) {
++              pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
++                         __func__, ret);
++              goto _iommu_domain_free;
++      }
++      stash_attr.cpu = cpu;
++      stash_attr.cache = PAMU_ATTR_CACHE_L1;
++      /* set stash information for the window */
++      stash_attr.window = 0;
++      ret = iommu_domain_set_attr(pcfg->iommu_domain,
++                                  DOMAIN_ATTR_FSL_PAMU_STASH,
++                                  &stash_attr);
++      if (ret < 0) {
++              pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
++                         __func__, ret);
++              goto _iommu_domain_free;
++      }
++      ret = iommu_domain_window_enable(pcfg->iommu_domain, 0, 0, 1ULL << 36,
++                                       IOMMU_READ | IOMMU_WRITE);
++      if (ret < 0) {
++              pr_err(KBUILD_MODNAME ":%s(): iommu_domain_window_enable() = %d",
++                         __func__, ret);
++              goto _iommu_domain_free;
++      }
++      ret = iommu_attach_device(pcfg->iommu_domain, &pcfg->dev);
++      if (ret < 0) {
++              pr_err(KBUILD_MODNAME ":%s(): iommu_device_attach() = %d",
++                         __func__, ret);
++              goto _iommu_domain_free;
++      }
++      ret = iommu_domain_set_attr(pcfg->iommu_domain,
++                                  DOMAIN_ATTR_FSL_PAMU_ENABLE,
++                                  &window_count);
++      if (ret < 0) {
++              pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
++                         __func__, ret);
++              goto _iommu_detach_device;
++      }
++
++_no_iommu:
++#endif
++#ifdef CONFIG_FSL_QMAN_CONFIG
++      if (qman_set_sdest(pcfg->public_cfg.channel, cpu))
++#endif
++              pr_warn("Failed to set QMan portal's stash request queue\n");
++
++      return;
++
++#ifdef CONFIG_FSL_PAMU
++_iommu_detach_device:
++      iommu_detach_device(pcfg->iommu_domain, NULL);
++_iommu_domain_free:
++      iommu_domain_free(pcfg->iommu_domain);
++#endif
++}
++
++struct qm_portal_config *qm_get_unused_portal_idx(u32 idx)
++{
++      struct qm_portal_config *ret;
++      spin_lock(&unused_pcfgs_lock);
++      if (idx == QBMAN_ANY_PORTAL_IDX)
++              ret = get_pcfg(&unused_pcfgs);
++      else
++              ret = get_pcfg_idx(&unused_pcfgs, idx);
++      spin_unlock(&unused_pcfgs_lock);
++      /* Bind stashing LIODNs to the CPU we are currently executing on, and
++       * set the portal to use the stashing request queue corresonding to the
++       * cpu as well. The user-space driver assumption is that the pthread has
++       * to already be affine to one cpu only before opening a portal. If that
++       * check is circumvented, the only risk is a performance degradation -
++       * stashing will go to whatever cpu they happened to be running on when
++       * opening the device file, and if that isn't the cpu they subsequently
++       * bind to and do their polling on, tough. */
++      if (ret)
++              portal_set_cpu(ret, hard_smp_processor_id());
++      return ret;
++}
++
++struct qm_portal_config *qm_get_unused_portal(void)
++{
++      return qm_get_unused_portal_idx(QBMAN_ANY_PORTAL_IDX);
++}
++
++void qm_put_unused_portal(struct qm_portal_config *pcfg)
++{
++      spin_lock(&unused_pcfgs_lock);
++      list_add(&pcfg->list, &unused_pcfgs);
++      spin_unlock(&unused_pcfgs_lock);
++}
++
++static struct qman_portal *init_pcfg(struct qm_portal_config *pcfg)
++{
++      struct qman_portal *p;
++
++      pcfg->iommu_domain = NULL;
++      portal_set_cpu(pcfg, pcfg->public_cfg.cpu);
++      p = qman_create_affine_portal(pcfg, NULL);
++      if (p) {
++              u32 irq_sources = 0;
++              /* Determine what should be interrupt-vs-poll driven */
++#ifdef CONFIG_FSL_DPA_PIRQ_SLOW
++              irq_sources |= QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI |
++                             QM_PIRQ_CSCI | QM_PIRQ_CCSCI;
++#endif
++#ifdef CONFIG_FSL_DPA_PIRQ_FAST
++              irq_sources |= QM_PIRQ_DQRI;
++#endif
++              qman_p_irqsource_add(p, irq_sources);
++              pr_info("Qman portal %sinitialised, cpu %d\n",
++                      pcfg->public_cfg.is_shared ? "(shared) " : "",
++                      pcfg->public_cfg.cpu);
++      } else
++              pr_crit("Qman portal failure on cpu %d\n",
++                      pcfg->public_cfg.cpu);
++      return p;
++}
++
++static void init_slave(int cpu)
++{
++      struct qman_portal *p;
++      struct cpumask oldmask = current->cpus_allowed;
++      set_cpus_allowed_ptr(current, get_cpu_mask(cpu));
++      p = qman_create_affine_slave(shared_portals[shared_portals_idx++], cpu);
++      if (!p)
++              pr_err("Qman slave portal failure on cpu %d\n", cpu);
++      else
++              pr_info("Qman portal %sinitialised, cpu %d\n", "(slave) ", cpu);
++      set_cpus_allowed_ptr(current, &oldmask);
++      if (shared_portals_idx >= num_shared_portals)
++              shared_portals_idx = 0;
++}
++
++static struct cpumask want_unshared __initdata;
++static struct cpumask want_shared __initdata;
++
++static int __init parse_qportals(char *str)
++{
++      return parse_portals_bootarg(str, &want_shared, &want_unshared,
++                                   "qportals");
++}
++__setup("qportals=", parse_qportals);
++
++static void qman_portal_update_sdest(const struct qm_portal_config *pcfg,
++                                                      unsigned int cpu)
++{
++#ifdef CONFIG_FSL_PAMU
++      struct pamu_stash_attribute stash_attr;
++      int ret;
++
++      if (pcfg->iommu_domain) {
++              stash_attr.cpu = cpu;
++              stash_attr.cache = PAMU_ATTR_CACHE_L1;
++              /* set stash information for the window */
++              stash_attr.window = 0;
++              ret = iommu_domain_set_attr(pcfg->iommu_domain,
++                              DOMAIN_ATTR_FSL_PAMU_STASH, &stash_attr);
++              if (ret < 0) {
++                      pr_err("Failed to update pamu stash setting\n");
++                      return;
++              }
++      }
++#endif
++#ifdef CONFIG_FSL_QMAN_CONFIG
++      if (qman_set_sdest(pcfg->public_cfg.channel, cpu))
++              pr_warn("Failed to update portal's stash request queue\n");
++#endif
++}
++
++static int qman_offline_cpu(unsigned int cpu)
++{
++      struct qman_portal *p;
++      const struct qm_portal_config *pcfg;
++      p = (struct qman_portal *)affine_portals[cpu];
++      if (p) {
++              pcfg = qman_get_qm_portal_config(p);
++              if (pcfg) {
++                      irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(0));
++                      qman_portal_update_sdest(pcfg, 0);
++              }
++      }
++      return 0;
++}
++
++#ifdef CONFIG_HOTPLUG_CPU
++static int qman_online_cpu(unsigned int cpu)
++{
++      struct qman_portal *p;
++      const struct qm_portal_config *pcfg;
++      p = (struct qman_portal *)affine_portals[cpu];
++      if (p) {
++              pcfg = qman_get_qm_portal_config(p);
++              if (pcfg) {
++                      irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(cpu));
++                      qman_portal_update_sdest(pcfg, cpu);
++              }
++      }
++      return 0;
++}
++
++#endif /* CONFIG_HOTPLUG_CPU */
++
++__init int qman_init(void)
++{
++      struct cpumask slave_cpus;
++      struct cpumask unshared_cpus = *cpu_none_mask;
++      struct cpumask shared_cpus = *cpu_none_mask;
++      LIST_HEAD(unshared_pcfgs);
++      LIST_HEAD(shared_pcfgs);
++      struct device_node *dn;
++      struct qm_portal_config *pcfg;
++      struct qman_portal *p;
++      int cpu, ret;
++      const u32 *clk;
++      struct cpumask offline_cpus;
++
++      /* Initialise the Qman (CCSR) device */
++      for_each_compatible_node(dn, NULL, "fsl,qman") {
++              if (!qman_init_ccsr(dn))
++                      pr_info("Qman err interrupt handler present\n");
++              else
++                      pr_err("Qman CCSR setup failed\n");
++
++              clk = of_get_property(dn, "clock-frequency", NULL);
++              if (!clk)
++                      pr_warn("Can't find Qman clock frequency\n");
++              else
++                      qman_clk = be32_to_cpu(*clk);
++      }
++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
++      /* Setup lookup table for FQ demux */
++      ret = qman_setup_fq_lookup_table(get_qman_fqd_size()/64);
++      if (ret)
++              return ret;
++#endif
++
++      /* Get qman ip revision */
++      qman_get_ip_revision(dn);
++      if ((qman_ip_rev & 0xff00) >= QMAN_REV30) {
++              qm_channel_pool1 = QMAN_CHANNEL_POOL1_REV3;
++              qm_channel_caam = QMAN_CHANNEL_CAAM_REV3;
++              qm_channel_pme = QMAN_CHANNEL_PME_REV3;
++      }
++
++      if ((qman_ip_rev == QMAN_REV31) && (qman_ip_cfg == QMAN_REV_CFG_2))
++              qm_channel_dce = QMAN_CHANNEL_DCE_QMANREV312;
++
++      /*
++       * Parse the ceetm node to get how many ceetm instances are supported
++       * on the current silicon. num_ceetms must be confirmed before portals
++       * are intiailized.
++       */
++      num_ceetms = 0;
++      for_each_compatible_node(dn, NULL, "fsl,qman-ceetm")
++              num_ceetms++;
++
++      /* Parse pool channels into the SDQCR mask. (Must happen before portals
++       * are initialised.) */
++      for_each_compatible_node(dn, NULL, "fsl,pool-channel-range") {
++              ret = fsl_pool_channel_range_sdqcr(dn);
++              if (ret)
++                      return ret;
++      }
++
++      memset(affine_portals, 0, sizeof(void *) * num_possible_cpus());
++      /* Initialise portals. See bman_driver.c for comments */
++      for_each_compatible_node(dn, NULL, "fsl,qman-portal") {
++              if (!of_device_is_available(dn))
++                      continue;
++              pcfg = parse_pcfg(dn);
++              if (pcfg) {
++                      pcfg->public_cfg.pools = pools_sdqcr;
++                      list_add_tail(&pcfg->list, &unused_pcfgs);
++              }
++      }
++      for_each_possible_cpu(cpu) {
++              if (cpumask_test_cpu(cpu, &want_shared)) {
++                      pcfg = get_pcfg(&unused_pcfgs);
++                      if (!pcfg)
++                              break;
++                      pcfg->public_cfg.cpu = cpu;
++                      list_add_tail(&pcfg->list, &shared_pcfgs);
++                      cpumask_set_cpu(cpu, &shared_cpus);
++              }
++              if (cpumask_test_cpu(cpu, &want_unshared)) {
++                      if (cpumask_test_cpu(cpu, &shared_cpus))
++                              continue;
++                      pcfg = get_pcfg(&unused_pcfgs);
++                      if (!pcfg)
++                              break;
++                      pcfg->public_cfg.cpu = cpu;
++                      list_add_tail(&pcfg->list, &unshared_pcfgs);
++                      cpumask_set_cpu(cpu, &unshared_cpus);
++              }
++      }
++      if (list_empty(&shared_pcfgs) && list_empty(&unshared_pcfgs)) {
++              for_each_online_cpu(cpu) {
++                      pcfg = get_pcfg(&unused_pcfgs);
++                      if (!pcfg)
++                              break;
++                      pcfg->public_cfg.cpu = cpu;
++                      list_add_tail(&pcfg->list, &unshared_pcfgs);
++                      cpumask_set_cpu(cpu, &unshared_cpus);
++              }
++      }
++      cpumask_andnot(&slave_cpus, cpu_possible_mask, &shared_cpus);
++      cpumask_andnot(&slave_cpus, &slave_cpus, &unshared_cpus);
++      if (cpumask_empty(&slave_cpus)) {
++              if (!list_empty(&shared_pcfgs)) {
++                      cpumask_or(&unshared_cpus, &unshared_cpus,
++                                 &shared_cpus);
++                      cpumask_clear(&shared_cpus);
++                      list_splice_tail(&shared_pcfgs, &unshared_pcfgs);
++                      INIT_LIST_HEAD(&shared_pcfgs);
++              }
++      } else {
++              if (list_empty(&shared_pcfgs)) {
++                      pcfg = get_pcfg(&unshared_pcfgs);
++                      if (!pcfg) {
++                              pr_crit("No QMan portals available!\n");
++                              return 0;
++                      }
++                      cpumask_clear_cpu(pcfg->public_cfg.cpu, &unshared_cpus);
++                      cpumask_set_cpu(pcfg->public_cfg.cpu, &shared_cpus);
++                      list_add_tail(&pcfg->list, &shared_pcfgs);
++              }
++      }
++      list_for_each_entry(pcfg, &unshared_pcfgs, list) {
++              pcfg->public_cfg.is_shared = 0;
++              p = init_pcfg(pcfg);
++              if (!p) {
++                      pr_crit("Unable to configure portals\n");
++                      return 0;
++              }
++      }
++      list_for_each_entry(pcfg, &shared_pcfgs, list) {
++              pcfg->public_cfg.is_shared = 1;
++              p = init_pcfg(pcfg);
++              if (p)
++                      shared_portals[num_shared_portals++] = p;
++      }
++      if (!cpumask_empty(&slave_cpus))
++              for_each_cpu(cpu, &slave_cpus)
++                      init_slave(cpu);
++      pr_info("Qman portals initialised\n");
++      cpumask_andnot(&offline_cpus, cpu_possible_mask, cpu_online_mask);
++      for_each_cpu(cpu, &offline_cpus)
++              qman_offline_cpu(cpu);
++#ifdef CONFIG_HOTPLUG_CPU
++      ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
++                                      "soc/qman_portal:online",
++                                      qman_online_cpu, qman_offline_cpu);
++      if (ret < 0) {
++              pr_err("qman: failed to register hotplug callbacks.\n");
++              return ret;
++      }
++#endif
++      return 0;
++}
++
++__init int qman_resource_init(void)
++{
++      struct device_node *dn;
++      int ret;
++
++      /* Initialise FQID allocation ranges */
++      for_each_compatible_node(dn, NULL, "fsl,fqid-range") {
++              ret = fsl_fqid_range_init(dn);
++              if (ret)
++                      return ret;
++      }
++      /* Initialise CGRID allocation ranges */
++      for_each_compatible_node(dn, NULL, "fsl,cgrid-range") {
++              ret = fsl_cgrid_range_init(dn);
++              if (ret)
++                      return ret;
++      }
++      /* Parse pool channels into the allocator. (Must happen after portals
++       * are initialised.) */
++      for_each_compatible_node(dn, NULL, "fsl,pool-channel-range") {
++              ret = fsl_pool_channel_range_init(dn);
++              if (ret)
++                      return ret;
++      }
++
++      /* Parse CEETM */
++      for_each_compatible_node(dn, NULL, "fsl,qman-ceetm") {
++              ret = fsl_ceetm_init(dn);
++              if (ret)
++                      return ret;
++      }
++      return 0;
++}
++
++#ifdef CONFIG_SUSPEND
++void suspend_unused_qportal(void)
++{
++      struct qm_portal_config *pcfg;
++
++      if (list_empty(&unused_pcfgs))
++              return;
++
++      list_for_each_entry(pcfg, &unused_pcfgs, list) {
++#ifdef CONFIG_PM_DEBUG
++              pr_info("Need to save qportal %d\n", pcfg->public_cfg.index);
++#endif
++              /* save isdr, disable all via isdr, clear isr */
++              pcfg->saved_isdr =
++                      __raw_readl(pcfg->addr_virt[DPA_PORTAL_CI] + 0xe08);
++              __raw_writel(0xffffffff, pcfg->addr_virt[DPA_PORTAL_CI] +
++                                      0xe08);
++              __raw_writel(0xffffffff, pcfg->addr_virt[DPA_PORTAL_CI] +
++                                      0xe00);
++      }
++      return;
++}
++
++void resume_unused_qportal(void)
++{
++      struct qm_portal_config *pcfg;
++
++      if (list_empty(&unused_pcfgs))
++              return;
++
++      list_for_each_entry(pcfg, &unused_pcfgs, list) {
++#ifdef CONFIG_PM_DEBUG
++              pr_info("Need to resume qportal %d\n", pcfg->public_cfg.index);
++#endif
++              /* restore isdr */
++              __raw_writel(pcfg->saved_isdr,
++                              pcfg->addr_virt[DPA_PORTAL_CI] + 0xe08);
++      }
++      return;
++}
++#endif
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/qman_high.c
+@@ -0,0 +1,5669 @@
++/* Copyright 2008-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "qman_low.h"
++
++/* Compilation constants */
++#define DQRR_MAXFILL  15
++#define EQCR_ITHRESH  4       /* if EQCR congests, interrupt threshold */
++#define IRQNAME               "QMan portal %d"
++#define MAX_IRQNAME   16      /* big enough for "QMan portal %d" */
++
++/* Divide 'n' by 'd', rounding down if 'r' is negative, rounding up if it's
++ * positive, and rounding to the closest value if it's zero. NB, this macro
++ * implicitly upgrades parameters to unsigned 64-bit, so feed it with types
++ * that are compatible with this. NB, these arguments should not be expressions
++ * unless it is safe for them to be evaluated multiple times. Eg. do not pass
++ * in "some_value++" as a parameter to the macro! */
++#define ROUNDING(n, d, r) \
++      (((r) < 0) ? div64_u64((n), (d)) : \
++      (((r) > 0) ? div64_u64(((n) + (d) - 1), (d)) : \
++      div64_u64(((n) + ((d) / 2)), (d))))
++
++/* Lock/unlock frame queues, subject to the "LOCKED" flag. This is about
++ * inter-processor locking only. Note, FQLOCK() is always called either under a
++ * local_irq_save() or from interrupt context - hence there's no need for irq
++ * protection (and indeed, attempting to nest irq-protection doesn't work, as
++ * the "irq en/disable" machinery isn't recursive...). */
++#define FQLOCK(fq) \
++      do { \
++              struct qman_fq *__fq478 = (fq); \
++              if (fq_isset(__fq478, QMAN_FQ_FLAG_LOCKED)) \
++                      spin_lock(&__fq478->fqlock); \
++      } while (0)
++#define FQUNLOCK(fq) \
++      do { \
++              struct qman_fq *__fq478 = (fq); \
++              if (fq_isset(__fq478, QMAN_FQ_FLAG_LOCKED)) \
++                      spin_unlock(&__fq478->fqlock); \
++      } while (0)
++
++static inline void fq_set(struct qman_fq *fq, u32 mask)
++{
++      set_bits(mask, &fq->flags);
++}
++static inline void fq_clear(struct qman_fq *fq, u32 mask)
++{
++      clear_bits(mask, &fq->flags);
++}
++static inline int fq_isset(struct qman_fq *fq, u32 mask)
++{
++      return fq->flags & mask;
++}
++static inline int fq_isclear(struct qman_fq *fq, u32 mask)
++{
++      return !(fq->flags & mask);
++}
++
++struct qman_portal {
++      struct qm_portal p;
++      unsigned long bits; /* PORTAL_BITS_*** - dynamic, strictly internal */
++      unsigned long irq_sources;
++      u32 use_eqcr_ci_stashing;
++      u32 slowpoll;   /* only used when interrupts are off */
++      struct qman_fq *vdqcr_owned; /* only 1 volatile dequeue at a time */
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      struct qman_fq *eqci_owned; /* only 1 enqueue WAIT_SYNC at a time */
++#endif
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      raw_spinlock_t sharing_lock; /* only used if is_shared */
++      int is_shared;
++      struct qman_portal *sharing_redirect;
++#endif
++      u32 sdqcr;
++      int dqrr_disable_ref;
++      /* A portal-specific handler for DCP ERNs. If this is NULL, the global
++       * handler is called instead. */
++      qman_cb_dc_ern cb_dc_ern;
++      /* When the cpu-affine portal is activated, this is non-NULL */
++      const struct qm_portal_config *config;
++      /* This is needed for providing a non-NULL device to dma_map_***() */
++      struct platform_device *pdev;
++      struct dpa_rbtree retire_table;
++      char irqname[MAX_IRQNAME];
++      /* 2-element array. cgrs[0] is mask, cgrs[1] is snapshot. */
++      struct qman_cgrs *cgrs;
++      /* linked-list of CSCN handlers. */
++      struct list_head cgr_cbs;
++      /* list lock */
++      spinlock_t cgr_lock;
++      /* 2-element array. ccgrs[0] is mask, ccgrs[1] is snapshot. */
++      struct qman_ccgrs *ccgrs[QMAN_CEETM_MAX];
++      /* 256-element array, each is a linked-list of CCSCN handlers. */
++      struct list_head ccgr_cbs[QMAN_CEETM_MAX];
++      /* list lock */
++      spinlock_t ccgr_lock;
++      /* track if memory was allocated by the driver */
++      u8 alloced;
++      /* power management data */
++      u32 save_isdr;
++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
++      /* Keep a shadow copy of the DQRR on LE systems as the SW needs to
++       * do byte swaps of DQRR read only memory.  First entry must be aligned
++       * to 2 ** 10 to ensure DQRR index calculations based shadow copy
++       * address (6 bits for address shift + 4 bits for the DQRR size).
++       */
++      struct qm_dqrr_entry shadow_dqrr[QM_DQRR_SIZE] __aligned(1024);
++#endif
++};
++
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++#define PORTAL_IRQ_LOCK(p, irqflags) \
++      do { \
++              if ((p)->is_shared) \
++                      raw_spin_lock_irqsave(&(p)->sharing_lock, irqflags); \
++              else \
++                      local_irq_save(irqflags); \
++      } while (0)
++#define PORTAL_IRQ_UNLOCK(p, irqflags) \
++      do { \
++              if ((p)->is_shared) \
++                      raw_spin_unlock_irqrestore(&(p)->sharing_lock, \
++                                                 irqflags); \
++              else \
++                      local_irq_restore(irqflags); \
++      } while (0)
++#else
++#define PORTAL_IRQ_LOCK(p, irqflags) local_irq_save(irqflags)
++#define PORTAL_IRQ_UNLOCK(p, irqflags) local_irq_restore(irqflags)
++#endif
++
++/* Global handler for DCP ERNs. Used when the portal receiving the message does
++ * not have a portal-specific handler. */
++static qman_cb_dc_ern cb_dc_ern;
++
++static cpumask_t affine_mask;
++static DEFINE_SPINLOCK(affine_mask_lock);
++static u16 affine_channels[NR_CPUS];
++static DEFINE_PER_CPU(struct qman_portal, qman_affine_portal);
++void *affine_portals[NR_CPUS];
++
++/* "raw" gets the cpu-local struct whether it's a redirect or not. */
++static inline struct qman_portal *get_raw_affine_portal(void)
++{
++      return &get_cpu_var(qman_affine_portal);
++}
++/* For ops that can redirect, this obtains the portal to use */
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++static inline struct qman_portal *get_affine_portal(void)
++{
++      struct qman_portal *p = get_raw_affine_portal();
++      if (p->sharing_redirect)
++              return p->sharing_redirect;
++      return p;
++}
++#else
++#define get_affine_portal() get_raw_affine_portal()
++#endif
++/* For every "get", there must be a "put" */
++static inline void put_affine_portal(void)
++{
++      put_cpu_var(qman_affine_portal);
++}
++/* Exception: poll functions assume the caller is cpu-affine and in no risk of
++ * re-entrance, which are the two reasons we usually use the get/put_cpu_var()
++ * semantic - ie. to disable pre-emption. Some use-cases expect the execution
++ * context to remain as non-atomic during poll-triggered callbacks as it was
++ * when the poll API was first called (eg. NAPI), so we go out of our way in
++ * this case to not disable pre-emption. */
++static inline struct qman_portal *get_poll_portal(void)
++{
++      return &get_cpu_var(qman_affine_portal);
++}
++#define put_poll_portal()
++
++/* This gives a FQID->FQ lookup to cover the fact that we can't directly demux
++ * retirement notifications (the fact they are sometimes h/w-consumed means that
++ * contextB isn't always a s/w demux - and as we can't know which case it is
++ * when looking at the notification, we have to use the slow lookup for all of
++ * them). NB, it's possible to have multiple FQ objects refer to the same FQID
++ * (though at most one of them should be the consumer), so this table isn't for
++ * all FQs - FQs are added when retirement commands are issued, and removed when
++ * they complete, which also massively reduces the size of this table. */
++IMPLEMENT_DPA_RBTREE(fqtree, struct qman_fq, node, fqid);
++
++/* This is what everything can wait on, even if it migrates to a different cpu
++ * to the one whose affine portal it is waiting on. */
++static DECLARE_WAIT_QUEUE_HEAD(affine_queue);
++
++static inline int table_push_fq(struct qman_portal *p, struct qman_fq *fq)
++{
++      int ret = fqtree_push(&p->retire_table, fq);
++      if (ret)
++              pr_err("ERROR: double FQ-retirement %d\n", fq->fqid);
++      return ret;
++}
++
++static inline void table_del_fq(struct qman_portal *p, struct qman_fq *fq)
++{
++      fqtree_del(&p->retire_table, fq);
++}
++
++static inline struct qman_fq *table_find_fq(struct qman_portal *p, u32 fqid)
++{
++      return fqtree_find(&p->retire_table, fqid);
++}
++
++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
++static void **qman_fq_lookup_table;
++static size_t qman_fq_lookup_table_size;
++
++int qman_setup_fq_lookup_table(size_t num_entries)
++{
++      num_entries++;
++      /* Allocate 1 more entry since the first entry is not used */
++      qman_fq_lookup_table = vzalloc((num_entries * sizeof(void *)));
++      if (!qman_fq_lookup_table) {
++              pr_err("QMan: Could not allocate fq lookup table\n");
++              return -ENOMEM;
++      }
++      qman_fq_lookup_table_size = num_entries;
++      pr_info("QMan: Allocated lookup table at %p, entry count %lu\n",
++                      qman_fq_lookup_table,
++                      (unsigned long)qman_fq_lookup_table_size);
++      return 0;
++}
++
++/* global structure that maintains fq object mapping */
++static DEFINE_SPINLOCK(fq_hash_table_lock);
++
++static int find_empty_fq_table_entry(u32 *entry, struct qman_fq *fq)
++{
++      u32 i;
++
++      spin_lock(&fq_hash_table_lock);
++      /* Can't use index zero because this has special meaning
++       * in context_b field. */
++      for (i = 1; i < qman_fq_lookup_table_size; i++) {
++              if (qman_fq_lookup_table[i] == NULL) {
++                      *entry = i;
++                      qman_fq_lookup_table[i] = fq;
++                      spin_unlock(&fq_hash_table_lock);
++                      return 0;
++              }
++      }
++      spin_unlock(&fq_hash_table_lock);
++      return -ENOMEM;
++}
++
++static void clear_fq_table_entry(u32 entry)
++{
++      spin_lock(&fq_hash_table_lock);
++      BUG_ON(entry >= qman_fq_lookup_table_size);
++      qman_fq_lookup_table[entry] = NULL;
++      spin_unlock(&fq_hash_table_lock);
++}
++
++static inline struct qman_fq *get_fq_table_entry(u32 entry)
++{
++      BUG_ON(entry >= qman_fq_lookup_table_size);
++      return qman_fq_lookup_table[entry];
++}
++#endif
++
++static inline void cpu_to_hw_fqd(struct qm_fqd *fqd)
++{
++      /* Byteswap the FQD to HW format */
++      fqd->fq_ctrl = cpu_to_be16(fqd->fq_ctrl);
++      fqd->dest_wq = cpu_to_be16(fqd->dest_wq);
++      fqd->ics_cred = cpu_to_be16(fqd->ics_cred);
++      fqd->context_b = cpu_to_be32(fqd->context_b);
++      fqd->context_a.opaque = cpu_to_be64(fqd->context_a.opaque);
++}
++
++static inline void hw_fqd_to_cpu(struct qm_fqd *fqd)
++{
++      /* Byteswap the FQD to CPU format */
++      fqd->fq_ctrl = be16_to_cpu(fqd->fq_ctrl);
++      fqd->dest_wq = be16_to_cpu(fqd->dest_wq);
++      fqd->ics_cred = be16_to_cpu(fqd->ics_cred);
++      fqd->context_b = be32_to_cpu(fqd->context_b);
++      fqd->context_a.opaque = be64_to_cpu(fqd->context_a.opaque);
++}
++
++/* Swap a 40 bit address */
++static inline u64 cpu_to_be40(u64 in)
++{
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++      return in;
++#else
++      u64 out = 0;
++      u8 *p = (u8 *) &out;
++      p[0] = in >> 32;
++      p[1] = in >> 24;
++      p[2] = in >> 16;
++      p[3] = in >> 8;
++      p[4] = in >> 0;
++      return out;
++#endif
++}
++static inline u64 be40_to_cpu(u64 in)
++{
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++      return in;
++#else
++      u64 out = 0;
++      u8 *pout = (u8 *) &out;
++      u8 *pin = (u8 *) &in;
++      pout[0] = pin[4];
++      pout[1] = pin[3];
++      pout[2] = pin[2];
++      pout[3] = pin[1];
++      pout[4] = pin[0];
++      return out;
++#endif
++}
++
++/* Swap a 24 bit value */
++static inline u32 cpu_to_be24(u32 in)
++{
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++      return in;
++#else
++      u32 out = 0;
++      u8 *p = (u8 *) &out;
++      p[0] = in >> 16;
++      p[1] = in >> 8;
++      p[2] = in >> 0;
++      return out;
++#endif
++}
++
++static inline u32 be24_to_cpu(u32 in)
++{
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++      return in;
++#else
++      u32 out = 0;
++      u8 *pout = (u8 *) &out;
++      u8 *pin = (u8 *) &in;
++      pout[0] = pin[2];
++      pout[1] = pin[1];
++      pout[2] = pin[0];
++      return out;
++#endif
++}
++
++static inline u64 be48_to_cpu(u64 in)
++{
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++      return in;
++#else
++      u64 out = 0;
++      u8 *pout = (u8 *) &out;
++      u8 *pin = (u8 *) &in;
++
++      pout[0] = pin[5];
++      pout[1] = pin[4];
++      pout[2] = pin[3];
++      pout[3] = pin[2];
++      pout[4] = pin[1];
++      pout[5] = pin[0];
++      return out;
++#endif
++}
++static inline void cpu_to_hw_fd(struct qm_fd *fd)
++{
++      fd->opaque_addr = cpu_to_be64(fd->opaque_addr);
++      fd->status = cpu_to_be32(fd->status);
++      fd->opaque = cpu_to_be32(fd->opaque);
++}
++
++static inline void hw_fd_to_cpu(struct qm_fd *fd)
++{
++      fd->opaque_addr = be64_to_cpu(fd->opaque_addr);
++      fd->status = be32_to_cpu(fd->status);
++      fd->opaque = be32_to_cpu(fd->opaque);
++}
++
++static inline void hw_cq_query_to_cpu(struct qm_mcr_ceetm_cq_query *cq_query)
++{
++      cq_query->ccgid = be16_to_cpu(cq_query->ccgid);
++      cq_query->state = be16_to_cpu(cq_query->state);
++      cq_query->pfdr_hptr = be24_to_cpu(cq_query->pfdr_hptr);
++      cq_query->pfdr_tptr = be24_to_cpu(cq_query->pfdr_tptr);
++      cq_query->od1_xsfdr = be16_to_cpu(cq_query->od1_xsfdr);
++      cq_query->od2_xsfdr = be16_to_cpu(cq_query->od2_xsfdr);
++      cq_query->od3_xsfdr = be16_to_cpu(cq_query->od3_xsfdr);
++      cq_query->od4_xsfdr = be16_to_cpu(cq_query->od4_xsfdr);
++      cq_query->od5_xsfdr = be16_to_cpu(cq_query->od5_xsfdr);
++      cq_query->od6_xsfdr = be16_to_cpu(cq_query->od6_xsfdr);
++      cq_query->ra1_xsfdr = be16_to_cpu(cq_query->ra1_xsfdr);
++      cq_query->ra2_xsfdr = be16_to_cpu(cq_query->ra2_xsfdr);
++      cq_query->frm_cnt = be24_to_cpu(cq_query->frm_cnt);
++}
++
++static inline void hw_ccgr_query_to_cpu(struct qm_mcr_ceetm_ccgr_query *ccgr_q)
++{
++      int i;
++
++      ccgr_q->cm_query.cs_thres.hword =
++              be16_to_cpu(ccgr_q->cm_query.cs_thres.hword);
++      ccgr_q->cm_query.cs_thres_x.hword =
++              be16_to_cpu(ccgr_q->cm_query.cs_thres_x.hword);
++      ccgr_q->cm_query.td_thres.hword =
++              be16_to_cpu(ccgr_q->cm_query.td_thres.hword);
++      ccgr_q->cm_query.wr_parm_g.word =
++             be32_to_cpu(ccgr_q->cm_query.wr_parm_g.word);
++      ccgr_q->cm_query.wr_parm_y.word =
++              be32_to_cpu(ccgr_q->cm_query.wr_parm_y.word);
++      ccgr_q->cm_query.wr_parm_r.word =
++              be32_to_cpu(ccgr_q->cm_query.wr_parm_r.word);
++      ccgr_q->cm_query.cscn_targ_dcp =
++              be16_to_cpu(ccgr_q->cm_query.cscn_targ_dcp);
++      ccgr_q->cm_query.i_cnt = be40_to_cpu(ccgr_q->cm_query.i_cnt);
++      ccgr_q->cm_query.a_cnt = be40_to_cpu(ccgr_q->cm_query.a_cnt);
++      for (i = 0; i < ARRAY_SIZE(ccgr_q->cm_query.cscn_targ_swp); i++)
++              ccgr_q->cm_query.cscn_targ_swp[i] =
++                      be32_to_cpu(ccgr_q->cm_query.cscn_targ_swp[i]);
++}
++
++/* In the case that slow- and fast-path handling are both done by qman_poll()
++ * (ie. because there is no interrupt handling), we ought to balance how often
++ * we do the fast-path poll versus the slow-path poll. We'll use two decrementer
++ * sources, so we call the fast poll 'n' times before calling the slow poll
++ * once. The idle decrementer constant is used when the last slow-poll detected
++ * no work to do, and the busy decrementer constant when the last slow-poll had
++ * work to do. */
++#define SLOW_POLL_IDLE   1000
++#define SLOW_POLL_BUSY   10
++static u32 __poll_portal_slow(struct qman_portal *p, u32 is);
++static inline unsigned int __poll_portal_fast(struct qman_portal *p,
++                                      unsigned int poll_limit);
++
++/* Portal interrupt handler */
++static irqreturn_t portal_isr(__always_unused int irq, void *ptr)
++{
++      struct qman_portal *p = ptr;
++      /*
++       * The CSCI/CCSCI source is cleared inside __poll_portal_slow(), because
++       * it could race against a Query Congestion State command also given
++       * as part of the handling of this interrupt source. We mustn't
++       * clear it a second time in this top-level function.
++       */
++      u32 clear = QM_DQAVAIL_MASK | (p->irq_sources &
++              ~(QM_PIRQ_CSCI | QM_PIRQ_CCSCI));
++      u32 is = qm_isr_status_read(&p->p) & p->irq_sources;
++      /* DQRR-handling if it's interrupt-driven */
++      if (is & QM_PIRQ_DQRI)
++              __poll_portal_fast(p, CONFIG_FSL_QMAN_POLL_LIMIT);
++      /* Handling of anything else that's interrupt-driven */
++      clear |= __poll_portal_slow(p, is);
++      qm_isr_status_clear(&p->p, clear);
++      return IRQ_HANDLED;
++}
++
++/* This inner version is used privately by qman_create_affine_portal(), as well
++ * as by the exported qman_stop_dequeues(). */
++static inline void qman_stop_dequeues_ex(struct qman_portal *p)
++{
++      unsigned long irqflags __maybe_unused;
++      PORTAL_IRQ_LOCK(p, irqflags);
++      if (!(p->dqrr_disable_ref++))
++              qm_dqrr_set_maxfill(&p->p, 0);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++}
++
++static int drain_mr_fqrni(struct qm_portal *p)
++{
++      const struct qm_mr_entry *msg;
++loop:
++      msg = qm_mr_current(p);
++      if (!msg) {
++              /* if MR was full and h/w had other FQRNI entries to produce, we
++               * need to allow it time to produce those entries once the
++               * existing entries are consumed. A worst-case situation
++               * (fully-loaded system) means h/w sequencers may have to do 3-4
++               * other things before servicing the portal's MR pump, each of
++               * which (if slow) may take ~50 qman cycles (which is ~200
++               * processor cycles). So rounding up and then multiplying this
++               * worst-case estimate by a factor of 10, just to be
++               * ultra-paranoid, goes as high as 10,000 cycles. NB, we consume
++               * one entry at a time, so h/w has an opportunity to produce new
++               * entries well before the ring has been fully consumed, so
++               * we're being *really* paranoid here. */
++              u64 now, then = mfatb();
++              do {
++                      now = mfatb();
++              } while ((then + 10000) > now);
++              msg = qm_mr_current(p);
++              if (!msg)
++                      return 0;
++      }
++      if ((msg->verb & QM_MR_VERB_TYPE_MASK) != QM_MR_VERB_FQRNI) {
++              /* We aren't draining anything but FQRNIs */
++              pr_err("QMan found verb 0x%x in MR\n", msg->verb);
++              return -1;
++      }
++      qm_mr_next(p);
++      qm_mr_cci_consume(p, 1);
++      goto loop;
++}
++
++#ifdef CONFIG_SUSPEND
++static int _qman_portal_suspend_noirq(struct device *dev)
++{
++      struct qman_portal *p = (struct qman_portal *)dev->platform_data;
++#ifdef CONFIG_PM_DEBUG
++      struct platform_device *pdev = to_platform_device(dev);
++#endif
++
++      p->save_isdr = qm_isr_disable_read(&p->p);
++      qm_isr_disable_write(&p->p, 0xffffffff);
++      qm_isr_status_clear(&p->p, 0xffffffff);
++#ifdef CONFIG_PM_DEBUG
++      pr_info("Suspend for %s\n", pdev->name);
++#endif
++      return 0;
++}
++
++static int _qman_portal_resume_noirq(struct device *dev)
++{
++      struct qman_portal *p = (struct qman_portal *)dev->platform_data;
++
++      /* restore isdr */
++      qm_isr_disable_write(&p->p, p->save_isdr);
++      return 0;
++}
++#else
++#define _qman_portal_suspend_noirq NULL
++#define _qman_portal_resume_noirq NULL
++#endif
++
++struct dev_pm_domain qman_portal_device_pm_domain = {
++      .ops = {
++              USE_PLATFORM_PM_SLEEP_OPS
++              .suspend_noirq = _qman_portal_suspend_noirq,
++              .resume_noirq = _qman_portal_resume_noirq,
++      }
++};
++
++struct qman_portal *qman_create_portal(
++                      struct qman_portal *portal,
++                      const struct qm_portal_config *config,
++                      const struct qman_cgrs *cgrs)
++{
++      struct qm_portal *__p;
++      char buf[16];
++      int ret;
++      u32 isdr;
++
++      if (!portal) {
++              portal = kmalloc(sizeof(*portal), GFP_KERNEL);
++              if (!portal)
++                      return portal;
++              portal->alloced = 1;
++      } else
++              portal->alloced = 0;
++
++      __p = &portal->p;
++
++#if (defined CONFIG_PPC || defined CONFIG_PPC64) && defined CONFIG_FSL_PAMU
++        /* PAMU is required for stashing */
++        portal->use_eqcr_ci_stashing = ((qman_ip_rev >= QMAN_REV30) ?
++                                      1 : 0);
++#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++      portal->use_eqcr_ci_stashing = 1;
++#else
++        portal->use_eqcr_ci_stashing = 0;
++#endif
++
++      /* prep the low-level portal struct with the mapped addresses from the
++       * config, everything that follows depends on it and "config" is more
++       * for (de)reference... */
++      __p->addr.addr_ce = config->addr_virt[DPA_PORTAL_CE];
++      __p->addr.addr_ci = config->addr_virt[DPA_PORTAL_CI];
++      /*
++       * If CI-stashing is used, the current defaults use a threshold of 3,
++       * and stash with high-than-DQRR priority.
++       */
++      if (qm_eqcr_init(__p, qm_eqcr_pvb,
++                      portal->use_eqcr_ci_stashing ? 3 : 0, 1)) {
++              pr_err("Qman EQCR initialisation failed\n");
++              goto fail_eqcr;
++      }
++      if (qm_dqrr_init(__p, config, qm_dqrr_dpush, qm_dqrr_pvb,
++                      qm_dqrr_cdc, DQRR_MAXFILL)) {
++              pr_err("Qman DQRR initialisation failed\n");
++              goto fail_dqrr;
++      }
++      if (qm_mr_init(__p, qm_mr_pvb, qm_mr_cci)) {
++              pr_err("Qman MR initialisation failed\n");
++              goto fail_mr;
++      }
++      if (qm_mc_init(__p)) {
++              pr_err("Qman MC initialisation failed\n");
++              goto fail_mc;
++      }
++      if (qm_isr_init(__p)) {
++              pr_err("Qman ISR initialisation failed\n");
++              goto fail_isr;
++      }
++      /* static interrupt-gating controls */
++      qm_dqrr_set_ithresh(__p, CONFIG_FSL_QMAN_PIRQ_DQRR_ITHRESH);
++      qm_mr_set_ithresh(__p, CONFIG_FSL_QMAN_PIRQ_MR_ITHRESH);
++      qm_isr_set_iperiod(__p, CONFIG_FSL_QMAN_PIRQ_IPERIOD);
++      portal->cgrs = kmalloc(2 * sizeof(*cgrs), GFP_KERNEL);
++      if (!portal->cgrs)
++              goto fail_cgrs;
++      /* initial snapshot is no-depletion */
++      qman_cgrs_init(&portal->cgrs[1]);
++      if (cgrs)
++              portal->cgrs[0] = *cgrs;
++      else
++              /* if the given mask is NULL, assume all CGRs can be seen */
++              qman_cgrs_fill(&portal->cgrs[0]);
++      INIT_LIST_HEAD(&portal->cgr_cbs);
++      spin_lock_init(&portal->cgr_lock);
++      if (num_ceetms) {
++              for (ret = 0; ret < num_ceetms; ret++) {
++                      portal->ccgrs[ret] = kmalloc(2 *
++                              sizeof(struct qman_ccgrs), GFP_KERNEL);
++                      if (!portal->ccgrs[ret])
++                              goto fail_ccgrs;
++                      qman_ccgrs_init(&portal->ccgrs[ret][1]);
++                      qman_ccgrs_fill(&portal->ccgrs[ret][0]);
++                      INIT_LIST_HEAD(&portal->ccgr_cbs[ret]);
++              }
++      }
++      spin_lock_init(&portal->ccgr_lock);
++      portal->bits = 0;
++      portal->slowpoll = 0;
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      portal->eqci_owned = NULL;
++#endif
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      raw_spin_lock_init(&portal->sharing_lock);
++      portal->is_shared = config->public_cfg.is_shared;
++      portal->sharing_redirect = NULL;
++#endif
++      portal->sdqcr = QM_SDQCR_SOURCE_CHANNELS | QM_SDQCR_COUNT_UPTO3 |
++                      QM_SDQCR_DEDICATED_PRECEDENCE | QM_SDQCR_TYPE_PRIO_QOS |
++                      QM_SDQCR_TOKEN_SET(0xab) | QM_SDQCR_CHANNELS_DEDICATED;
++      portal->dqrr_disable_ref = 0;
++      portal->cb_dc_ern = NULL;
++      sprintf(buf, "qportal-%d", config->public_cfg.channel);
++      portal->pdev = platform_device_alloc(buf, -1);
++      if (!portal->pdev) {
++              pr_err("qman_portal - platform_device_alloc() failed\n");
++              goto fail_devalloc;
++      }
++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++      portal->pdev->dev.coherent_dma_mask = DMA_BIT_MASK(40);
++      portal->pdev->dev.dma_mask = &portal->pdev->dev.coherent_dma_mask;
++#else
++      if (dma_set_mask(&portal->pdev->dev, DMA_BIT_MASK(40))) {
++              pr_err("qman_portal - dma_set_mask() failed\n");
++              goto fail_devadd;
++      }
++#endif
++      portal->pdev->dev.pm_domain = &qman_portal_device_pm_domain;
++      portal->pdev->dev.platform_data = portal;
++      ret = platform_device_add(portal->pdev);
++      if (ret) {
++              pr_err("qman_portal - platform_device_add() failed\n");
++              goto fail_devadd;
++      }
++      dpa_rbtree_init(&portal->retire_table);
++      isdr = 0xffffffff;
++      qm_isr_disable_write(__p, isdr);
++      portal->irq_sources = 0;
++      qm_isr_enable_write(__p, portal->irq_sources);
++      qm_isr_status_clear(__p, 0xffffffff);
++      snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, config->public_cfg.cpu);
++      if (request_irq(config->public_cfg.irq, portal_isr, 0, portal->irqname,
++                              portal)) {
++              pr_err("request_irq() failed\n");
++              goto fail_irq;
++      }
++      if ((config->public_cfg.cpu != -1) &&
++                      irq_can_set_affinity(config->public_cfg.irq) &&
++                      irq_set_affinity(config->public_cfg.irq,
++                              cpumask_of(config->public_cfg.cpu))) {
++              pr_err("irq_set_affinity() failed\n");
++              goto fail_affinity;
++      }
++
++      /* Need EQCR to be empty before continuing */
++      isdr ^= QM_PIRQ_EQCI;
++      qm_isr_disable_write(__p, isdr);
++      ret = qm_eqcr_get_fill(__p);
++      if (ret) {
++              pr_err("Qman EQCR unclean\n");
++              goto fail_eqcr_empty;
++      }
++      isdr ^= (QM_PIRQ_DQRI | QM_PIRQ_MRI);
++      qm_isr_disable_write(__p, isdr);
++      if (qm_dqrr_current(__p) != NULL) {
++              pr_err("Qman DQRR unclean\n");
++              qm_dqrr_cdc_consume_n(__p, 0xffff);
++      }
++      if (qm_mr_current(__p) != NULL) {
++              /* special handling, drain just in case it's a few FQRNIs */
++              if (drain_mr_fqrni(__p)) {
++                      const struct qm_mr_entry *e = qm_mr_current(__p);
++                      /*
++                       * Message ring cannot be empty no need to check
++                       * qm_mr_current returned successfully
++                       */
++                      pr_err("Qman MR unclean, MR VERB 0x%x, rc 0x%x\n, addr 0x%x",
++                              e->verb, e->ern.rc, e->ern.fd.addr_lo);
++                      goto fail_dqrr_mr_empty;
++              }
++      }
++      /* Success */
++      portal->config = config;
++      qm_isr_disable_write(__p, 0);
++      qm_isr_uninhibit(__p);
++      /* Write a sane SDQCR */
++      qm_dqrr_sdqcr_set(__p, portal->sdqcr);
++      return portal;
++fail_dqrr_mr_empty:
++fail_eqcr_empty:
++fail_affinity:
++      free_irq(config->public_cfg.irq, portal);
++fail_irq:
++      platform_device_del(portal->pdev);
++fail_devadd:
++      platform_device_put(portal->pdev);
++fail_devalloc:
++      if (num_ceetms)
++              for (ret = 0; ret < num_ceetms; ret++)
++                      kfree(portal->ccgrs[ret]);
++fail_ccgrs:
++      kfree(portal->cgrs);
++fail_cgrs:
++      qm_isr_finish(__p);
++fail_isr:
++      qm_mc_finish(__p);
++fail_mc:
++      qm_mr_finish(__p);
++fail_mr:
++      qm_dqrr_finish(__p);
++fail_dqrr:
++      qm_eqcr_finish(__p);
++fail_eqcr:
++      if (portal->alloced)
++              kfree(portal);
++      return NULL;
++}
++
++struct qman_portal *qman_create_affine_portal(
++                      const struct qm_portal_config *config,
++                      const struct qman_cgrs *cgrs)
++{
++      struct qman_portal *res;
++      struct qman_portal *portal;
++
++      portal = &per_cpu(qman_affine_portal, config->public_cfg.cpu);
++      res = qman_create_portal(portal, config, cgrs);
++      if (res) {
++              spin_lock(&affine_mask_lock);
++              cpumask_set_cpu(config->public_cfg.cpu, &affine_mask);
++              affine_channels[config->public_cfg.cpu] =
++                      config->public_cfg.channel;
++              affine_portals[config->public_cfg.cpu] = portal;
++              spin_unlock(&affine_mask_lock);
++      }
++      return res;
++}
++
++/* These checks are BUG_ON()s because the driver is already supposed to avoid
++ * these cases. */
++struct qman_portal *qman_create_affine_slave(struct qman_portal *redirect,
++                                                              int cpu)
++{
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      struct qman_portal *p;
++      p = &per_cpu(qman_affine_portal, cpu);
++      /* Check that we don't already have our own portal */
++      BUG_ON(p->config);
++      /* Check that we aren't already slaving to another portal */
++      BUG_ON(p->is_shared);
++      /* Check that 'redirect' is prepared to have us */
++      BUG_ON(!redirect->config->public_cfg.is_shared);
++      /* These are the only elements to initialise when redirecting */
++      p->irq_sources = 0;
++      p->sharing_redirect = redirect;
++      affine_portals[cpu] = p;
++      return p;
++#else
++      BUG();
++      return NULL;
++#endif
++}
++
++void qman_destroy_portal(struct qman_portal *qm)
++{
++      const struct qm_portal_config *pcfg;
++      int i;
++
++      /* Stop dequeues on the portal */
++      qm_dqrr_sdqcr_set(&qm->p, 0);
++
++      /* NB we do this to "quiesce" EQCR. If we add enqueue-completions or
++       * something related to QM_PIRQ_EQCI, this may need fixing.
++       * Also, due to the prefetching model used for CI updates in the enqueue
++       * path, this update will only invalidate the CI cacheline *after*
++       * working on it, so we need to call this twice to ensure a full update
++       * irrespective of where the enqueue processing was at when the teardown
++       * began. */
++      qm_eqcr_cce_update(&qm->p);
++      qm_eqcr_cce_update(&qm->p);
++      pcfg = qm->config;
++
++      free_irq(pcfg->public_cfg.irq, qm);
++
++      kfree(qm->cgrs);
++      if (num_ceetms)
++              for (i = 0; i < num_ceetms; i++)
++                      kfree(qm->ccgrs[i]);
++      qm_isr_finish(&qm->p);
++      qm_mc_finish(&qm->p);
++      qm_mr_finish(&qm->p);
++      qm_dqrr_finish(&qm->p);
++      qm_eqcr_finish(&qm->p);
++
++      platform_device_del(qm->pdev);
++      platform_device_put(qm->pdev);
++
++      qm->config = NULL;
++      if (qm->alloced)
++              kfree(qm);
++}
++
++const struct qm_portal_config *qman_destroy_affine_portal(void)
++{
++      /* We don't want to redirect if we're a slave, use "raw" */
++      struct qman_portal *qm = get_raw_affine_portal();
++      const struct qm_portal_config *pcfg;
++      int cpu;
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      if (qm->sharing_redirect) {
++              qm->sharing_redirect = NULL;
++              put_affine_portal();
++              return NULL;
++      }
++      qm->is_shared = 0;
++#endif
++      pcfg = qm->config;
++      cpu = pcfg->public_cfg.cpu;
++
++      qman_destroy_portal(qm);
++
++      spin_lock(&affine_mask_lock);
++      cpumask_clear_cpu(cpu, &affine_mask);
++      spin_unlock(&affine_mask_lock);
++      put_affine_portal();
++      return pcfg;
++}
++
++const struct qman_portal_config *qman_p_get_portal_config(struct qman_portal *p)
++{
++      return &p->config->public_cfg;
++}
++EXPORT_SYMBOL(qman_p_get_portal_config);
++
++const struct qman_portal_config *qman_get_portal_config(void)
++{
++      struct qman_portal *p = get_affine_portal();
++      const struct qman_portal_config *ret = qman_p_get_portal_config(p);
++      put_affine_portal();
++      return ret;
++}
++EXPORT_SYMBOL(qman_get_portal_config);
++
++/* Inline helper to reduce nesting in __poll_portal_slow() */
++static inline void fq_state_change(struct qman_portal *p, struct qman_fq *fq,
++                              const struct qm_mr_entry *msg, u8 verb)
++{
++      FQLOCK(fq);
++      switch (verb) {
++      case QM_MR_VERB_FQRL:
++              DPA_ASSERT(fq_isset(fq, QMAN_FQ_STATE_ORL));
++              fq_clear(fq, QMAN_FQ_STATE_ORL);
++              table_del_fq(p, fq);
++              break;
++      case QM_MR_VERB_FQRN:
++              DPA_ASSERT((fq->state == qman_fq_state_parked) ||
++                      (fq->state == qman_fq_state_sched));
++              DPA_ASSERT(fq_isset(fq, QMAN_FQ_STATE_CHANGING));
++              fq_clear(fq, QMAN_FQ_STATE_CHANGING);
++              if (msg->fq.fqs & QM_MR_FQS_NOTEMPTY)
++                      fq_set(fq, QMAN_FQ_STATE_NE);
++              if (msg->fq.fqs & QM_MR_FQS_ORLPRESENT)
++                      fq_set(fq, QMAN_FQ_STATE_ORL);
++              else
++                      table_del_fq(p, fq);
++              fq->state = qman_fq_state_retired;
++              break;
++      case QM_MR_VERB_FQPN:
++              DPA_ASSERT(fq->state == qman_fq_state_sched);
++              DPA_ASSERT(fq_isclear(fq, QMAN_FQ_STATE_CHANGING));
++              fq->state = qman_fq_state_parked;
++      }
++      FQUNLOCK(fq);
++}
++
++static u32 __poll_portal_slow(struct qman_portal *p, u32 is)
++{
++      const struct qm_mr_entry *msg;
++      struct qm_mr_entry swapped_msg;
++      int k;
++
++      if (is & QM_PIRQ_CSCI) {
++              struct qman_cgrs rr, c;
++              struct qm_mc_result *mcr;
++              struct qman_cgr *cgr;
++              unsigned long irqflags __maybe_unused;
++
++              spin_lock_irqsave(&p->cgr_lock, irqflags);
++              /*
++               * The CSCI bit must be cleared _before_ issuing the
++               * Query Congestion State command, to ensure that a long
++               * CGR State Change callback cannot miss an intervening
++               * state change.
++               */
++              qm_isr_status_clear(&p->p, QM_PIRQ_CSCI);
++              qm_mc_start(&p->p);
++              qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCONGESTION);
++              while (!(mcr = qm_mc_result(&p->p)))
++                      cpu_relax();
++              for (k = 0; k < 8; k++)
++                      mcr->querycongestion.state.__state[k] = be32_to_cpu(
++                                      mcr->querycongestion.state.__state[k]);
++              /* mask out the ones I'm not interested in */
++              qman_cgrs_and(&rr, (const struct qman_cgrs *)
++                      &mcr->querycongestion.state, &p->cgrs[0]);
++              /* check previous snapshot for delta, enter/exit congestion */
++              qman_cgrs_xor(&c, &rr, &p->cgrs[1]);
++              /* update snapshot */
++              qman_cgrs_cp(&p->cgrs[1], &rr);
++              /* Invoke callback */
++              list_for_each_entry(cgr, &p->cgr_cbs, node)
++                      if (cgr->cb && qman_cgrs_get(&c, cgr->cgrid))
++                              cgr->cb(p, cgr, qman_cgrs_get(&rr, cgr->cgrid));
++              spin_unlock_irqrestore(&p->cgr_lock, irqflags);
++      }
++      if (is & QM_PIRQ_CCSCI) {
++              struct qman_ccgrs rr, c, congestion_result;
++              struct qm_mc_result *mcr;
++              struct qm_mc_command *mcc;
++              struct qm_ceetm_ccg *ccg;
++              unsigned long irqflags __maybe_unused;
++              int i, j;
++
++              spin_lock_irqsave(&p->ccgr_lock, irqflags);
++              /*
++               * The CCSCI bit must be cleared _before_ issuing the
++               * Query Congestion State command, to ensure that a long
++               * CCGR State Change callback cannot miss an intervening
++               * state change.
++               */
++              qm_isr_status_clear(&p->p, QM_PIRQ_CCSCI);
++
++              for (i = 0; i < num_ceetms; i++) {
++                      for (j = 0; j < 2; j++) {
++                              mcc = qm_mc_start(&p->p);
++                              mcc->ccgr_query.ccgrid = cpu_to_be16(
++                                      CEETM_QUERY_CONGESTION_STATE | j);
++                              mcc->ccgr_query.dcpid = i;
++                              qm_mc_commit(&p->p, QM_CEETM_VERB_CCGR_QUERY);
++                              while (!(mcr = qm_mc_result(&p->p)))
++                                      cpu_relax();
++                              for (k = 0; k < 8; k++)
++                                      mcr->ccgr_query.congestion_state.state.
++                                              __state[k] = be32_to_cpu(
++                                              mcr->ccgr_query.
++                                              congestion_state.state.
++                                              __state[k]);
++                              congestion_result.q[j] =
++                                      mcr->ccgr_query.congestion_state.state;
++                      }
++                      /* mask out the ones I'm not interested in */
++                      qman_ccgrs_and(&rr, &congestion_result,
++                                                      &p->ccgrs[i][0]);
++                      /*
++                       * check previous snapshot for delta, enter/exit
++                       * congestion.
++                       */
++                      qman_ccgrs_xor(&c, &rr, &p->ccgrs[i][1]);
++                      /* update snapshot */
++                      qman_ccgrs_cp(&p->ccgrs[i][1], &rr);
++                      /* Invoke callback */
++                      list_for_each_entry(ccg, &p->ccgr_cbs[i], cb_node)
++                              if (ccg->cb && qman_ccgrs_get(&c,
++                                      (ccg->parent->idx << 4) | ccg->idx))
++                                      ccg->cb(ccg, ccg->cb_ctx,
++                                              qman_ccgrs_get(&rr,
++                                                      (ccg->parent->idx << 4)
++                                                      | ccg->idx));
++              }
++              spin_unlock_irqrestore(&p->ccgr_lock, irqflags);
++      }
++
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      if (is & QM_PIRQ_EQCI) {
++              unsigned long irqflags;
++              PORTAL_IRQ_LOCK(p, irqflags);
++              p->eqci_owned = NULL;
++              PORTAL_IRQ_UNLOCK(p, irqflags);
++              wake_up(&affine_queue);
++      }
++#endif
++
++      if (is & QM_PIRQ_EQRI) {
++              unsigned long irqflags __maybe_unused;
++              PORTAL_IRQ_LOCK(p, irqflags);
++              qm_eqcr_cce_update(&p->p);
++              qm_eqcr_set_ithresh(&p->p, 0);
++              PORTAL_IRQ_UNLOCK(p, irqflags);
++              wake_up(&affine_queue);
++      }
++
++      if (is & QM_PIRQ_MRI) {
++              struct qman_fq *fq;
++              u8 verb, num = 0;
++mr_loop:
++              qm_mr_pvb_update(&p->p);
++              msg = qm_mr_current(&p->p);
++              if (!msg)
++                      goto mr_done;
++              swapped_msg = *msg;
++              hw_fd_to_cpu(&swapped_msg.ern.fd);
++              verb = msg->verb & QM_MR_VERB_TYPE_MASK;
++              /* The message is a software ERN iff the 0x20 bit is set */
++              if (verb & 0x20) {
++                      switch (verb) {
++                      case QM_MR_VERB_FQRNI:
++                              /* nada, we drop FQRNIs on the floor */
++                              break;
++                      case QM_MR_VERB_FQRN:
++                      case QM_MR_VERB_FQRL:
++                              /* Lookup in the retirement table */
++                              fq = table_find_fq(p, be32_to_cpu(msg->fq.fqid));
++                              BUG_ON(!fq);
++                              fq_state_change(p, fq, &swapped_msg, verb);
++                              if (fq->cb.fqs)
++                                      fq->cb.fqs(p, fq, &swapped_msg);
++                              break;
++                      case QM_MR_VERB_FQPN:
++                              /* Parked */
++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
++                              fq = get_fq_table_entry(
++                                      be32_to_cpu(msg->fq.contextB));
++#else
++                              fq = (void *)(uintptr_t)
++                                      be32_to_cpu(msg->fq.contextB);
++#endif
++                              fq_state_change(p, fq, msg, verb);
++                              if (fq->cb.fqs)
++                                      fq->cb.fqs(p, fq, &swapped_msg);
++                              break;
++                      case QM_MR_VERB_DC_ERN:
++                              /* DCP ERN */
++                              if (p->cb_dc_ern)
++                                      p->cb_dc_ern(p, msg);
++                              else if (cb_dc_ern)
++                                      cb_dc_ern(p, msg);
++                              else {
++                                      static int warn_once;
++                                      if (!warn_once) {
++                                              pr_crit("Leaking DCP ERNs!\n");
++                                              warn_once = 1;
++                                      }
++                              }
++                              break;
++                      default:
++                              pr_crit("Invalid MR verb 0x%02x\n", verb);
++                      }
++              } else {
++                      /* Its a software ERN */
++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
++                      fq = get_fq_table_entry(be32_to_cpu(msg->ern.tag));
++#else
++                      fq = (void *)(uintptr_t)be32_to_cpu(msg->ern.tag);
++#endif
++                      fq->cb.ern(p, fq, &swapped_msg);
++              }
++              num++;
++              qm_mr_next(&p->p);
++              goto mr_loop;
++mr_done:
++              qm_mr_cci_consume(&p->p, num);
++      }
++      /*
++       * QM_PIRQ_CSCI/CCSCI has already been cleared, as part of its specific
++       * processing. If that interrupt source has meanwhile been re-asserted,
++       * we mustn't clear it here (or in the top-level interrupt handler).
++       */
++      return is & (QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI);
++}
++
++/* remove some slowish-path stuff from the "fast path" and make sure it isn't
++ * inlined. */
++static noinline void clear_vdqcr(struct qman_portal *p, struct qman_fq *fq)
++{
++      p->vdqcr_owned = NULL;
++      FQLOCK(fq);
++      fq_clear(fq, QMAN_FQ_STATE_VDQCR);
++      FQUNLOCK(fq);
++      wake_up(&affine_queue);
++}
++
++/* Copy a DQRR entry ensuring reads reach QBMan in order */
++static inline void safe_copy_dqrr(struct qm_dqrr_entry *dst,
++                                const struct qm_dqrr_entry *src)
++{
++      int i = 0;
++      const u64 *s64 = (u64*)src;
++      u64 *d64 = (u64*)dst;
++
++      /* DQRR only has 32 bytes of valid data so only need to
++       * copy 4 - 64 bit values */
++      *d64 = *s64;
++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++      {
++              u32 res, zero = 0;
++              /* Create a dependancy after copying first bytes ensures no wrap
++                 transaction generated to QBMan */
++              /* Logical AND the value pointed to by s64 with 0x0 and
++                 store the result in res */
++              asm volatile("and %[result], %[in1], %[in2]"
++                           : [result] "=r" (res)
++                           : [in1] "r" (zero), [in2] "r" (*s64)
++                           : "memory");
++              /* Add res to s64 - this creates a dependancy on the result of
++                 reading the value of s64 before the next read. The side
++                 effect of this is that the core must stall until the first
++                 aligned read is complete therefore preventing a WRAP
++                 transaction to be seen by the QBMan */
++              asm volatile("add %[result], %[in1], %[in2]"
++                           : [result] "=r" (s64)
++                           : [in1] "r" (res), [in2] "r" (s64)
++                           : "memory");
++      }
++#endif
++      /* Copy the last 3 64 bit parts */
++      d64++; s64++;
++      for (;i<3; i++)
++              *d64++ = *s64++;
++}
++
++/* Look: no locks, no irq_save()s, no preempt_disable()s! :-) The only states
++ * that would conflict with other things if they ran at the same time on the
++ * same cpu are;
++ *
++ *   (i) setting/clearing vdqcr_owned, and
++ *  (ii) clearing the NE (Not Empty) flag.
++ *
++ * Both are safe. Because;
++ *
++ *   (i) this clearing can only occur after qman_volatile_dequeue() has set the
++ *       vdqcr_owned field (which it does before setting VDQCR), and
++ *       qman_volatile_dequeue() blocks interrupts and preemption while this is
++ *       done so that we can't interfere.
++ *  (ii) the NE flag is only cleared after qman_retire_fq() has set it, and as
++ *       with (i) that API prevents us from interfering until it's safe.
++ *
++ * The good thing is that qman_volatile_dequeue() and qman_retire_fq() run far
++ * less frequently (ie. per-FQ) than __poll_portal_fast() does, so the nett
++ * advantage comes from this function not having to "lock" anything at all.
++ *
++ * Note also that the callbacks are invoked at points which are safe against the
++ * above potential conflicts, but that this function itself is not re-entrant
++ * (this is because the function tracks one end of each FIFO in the portal and
++ * we do *not* want to lock that). So the consequence is that it is safe for
++ * user callbacks to call into any Qman API *except* qman_poll() (as that's the
++ * sole API that could be invoking the callback through this function).
++ */
++static inline unsigned int __poll_portal_fast(struct qman_portal *p,
++                                      unsigned int poll_limit)
++{
++      const struct qm_dqrr_entry *dq;
++      struct qman_fq *fq;
++      enum qman_cb_dqrr_result res;
++      unsigned int limit = 0;
++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
++      struct qm_dqrr_entry *shadow;
++      const struct qm_dqrr_entry *orig_dq;
++#endif
++loop:
++      qm_dqrr_pvb_update(&p->p);
++      dq = qm_dqrr_current(&p->p);
++      if (!dq)
++              goto done;
++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
++      /* If running on an LE system the fields of the
++         dequeue entry must be swapped.  Because the
++         QMan HW will ignore writes the DQRR entry is
++         copied and the index stored within the copy */
++      shadow = &p->shadow_dqrr[DQRR_PTR2IDX(dq)];
++      /* Use safe copy here to avoid WRAP transaction */
++      safe_copy_dqrr(shadow, dq);
++      orig_dq = dq;
++      dq = shadow;
++      shadow->fqid = be32_to_cpu(shadow->fqid);
++      shadow->contextB = be32_to_cpu(shadow->contextB);
++      shadow->seqnum = be16_to_cpu(shadow->seqnum);
++      hw_fd_to_cpu(&shadow->fd);
++#endif
++      if (dq->stat & QM_DQRR_STAT_UNSCHEDULED) {
++              /* VDQCR: don't trust contextB as the FQ may have been
++               * configured for h/w consumption and we're draining it
++               * post-retirement. */
++              fq = p->vdqcr_owned;
++              /* We only set QMAN_FQ_STATE_NE when retiring, so we only need
++               * to check for clearing it when doing volatile dequeues. It's
++               * one less thing to check in the critical path (SDQCR). */
++              if (dq->stat & QM_DQRR_STAT_FQ_EMPTY)
++                      fq_clear(fq, QMAN_FQ_STATE_NE);
++              /* this is duplicated from the SDQCR code, but we have stuff to
++               * do before *and* after this callback, and we don't want
++               * multiple if()s in the critical path (SDQCR). */
++              res = fq->cb.dqrr(p, fq, dq);
++              if (res == qman_cb_dqrr_stop)
++                      goto done;
++              /* Check for VDQCR completion */
++              if (dq->stat & QM_DQRR_STAT_DQCR_EXPIRED)
++                      clear_vdqcr(p, fq);
++      } else {
++              /* SDQCR: contextB points to the FQ */
++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
++              fq = get_fq_table_entry(dq->contextB);
++#else
++              fq = (void *)(uintptr_t)dq->contextB;
++#endif
++              /* Now let the callback do its stuff */
++              res = fq->cb.dqrr(p, fq, dq);
++
++              /* The callback can request that we exit without consuming this
++               * entry nor advancing; */
++              if (res == qman_cb_dqrr_stop)
++                      goto done;
++      }
++      /* Interpret 'dq' from a driver perspective. */
++      /* Parking isn't possible unless HELDACTIVE was set. NB,
++       * FORCEELIGIBLE implies HELDACTIVE, so we only need to
++       * check for HELDACTIVE to cover both. */
++      DPA_ASSERT((dq->stat & QM_DQRR_STAT_FQ_HELDACTIVE) ||
++              (res != qman_cb_dqrr_park));
++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
++      if (res != qman_cb_dqrr_defer)
++              qm_dqrr_cdc_consume_1ptr(&p->p, orig_dq,
++                                       (res == qman_cb_dqrr_park));
++#else
++      /* Defer just means "skip it, I'll consume it myself later on" */
++      if (res != qman_cb_dqrr_defer)
++              qm_dqrr_cdc_consume_1ptr(&p->p, dq, (res == qman_cb_dqrr_park));
++#endif
++      /* Move forward */
++      qm_dqrr_next(&p->p);
++      /* Entry processed and consumed, increment our counter. The callback can
++       * request that we exit after consuming the entry, and we also exit if
++       * we reach our processing limit, so loop back only if neither of these
++       * conditions is met. */
++      if ((++limit < poll_limit) && (res != qman_cb_dqrr_consume_stop))
++              goto loop;
++done:
++      return limit;
++}
++
++u32 qman_irqsource_get(void)
++{
++      /* "irqsource" and "poll" APIs mustn't redirect when sharing, they
++       * should shut the user out if they are not the primary CPU hosting the
++       * portal. That's why we use the "raw" interface. */
++      struct qman_portal *p = get_raw_affine_portal();
++      u32 ret = p->irq_sources & QM_PIRQ_VISIBLE;
++      put_affine_portal();
++      return ret;
++}
++EXPORT_SYMBOL(qman_irqsource_get);
++
++int qman_p_irqsource_add(struct qman_portal *p, u32 bits __maybe_unused)
++{
++      __maybe_unused unsigned long irqflags;
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      if (p->sharing_redirect)
++              return -EINVAL;
++      else
++#endif
++      {
++              bits = bits & QM_PIRQ_VISIBLE;
++              PORTAL_IRQ_LOCK(p, irqflags);
++
++              /* Clear any previously remaining interrupt conditions in
++               * QCSP_ISR. This prevents raising a false interrupt when
++               * interrupt conditions are enabled in QCSP_IER.
++               */
++              qm_isr_status_clear(&p->p, bits);
++              set_bits(bits, &p->irq_sources);
++              qm_isr_enable_write(&p->p, p->irq_sources);
++              PORTAL_IRQ_UNLOCK(p, irqflags);
++      }
++      return 0;
++}
++EXPORT_SYMBOL(qman_p_irqsource_add);
++
++int qman_irqsource_add(u32 bits __maybe_unused)
++{
++      struct qman_portal *p = get_raw_affine_portal();
++      int ret;
++      ret = qman_p_irqsource_add(p, bits);
++      put_affine_portal();
++      return ret;
++}
++EXPORT_SYMBOL(qman_irqsource_add);
++
++int qman_p_irqsource_remove(struct qman_portal *p, u32 bits)
++{
++      __maybe_unused unsigned long irqflags;
++      u32 ier;
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      if (p->sharing_redirect) {
++              put_affine_portal();
++              return -EINVAL;
++      }
++#endif
++      /* Our interrupt handler only processes+clears status register bits that
++       * are in p->irq_sources. As we're trimming that mask, if one of them
++       * were to assert in the status register just before we remove it from
++       * the enable register, there would be an interrupt-storm when we
++       * release the IRQ lock. So we wait for the enable register update to
++       * take effect in h/w (by reading it back) and then clear all other bits
++       * in the status register. Ie. we clear them from ISR once it's certain
++       * IER won't allow them to reassert. */
++      PORTAL_IRQ_LOCK(p, irqflags);
++      bits &= QM_PIRQ_VISIBLE;
++      clear_bits(bits, &p->irq_sources);
++      qm_isr_enable_write(&p->p, p->irq_sources);
++
++      ier = qm_isr_enable_read(&p->p);
++      /* Using "~ier" (rather than "bits" or "~p->irq_sources") creates a
++       * data-dependency, ie. to protect against re-ordering. */
++      qm_isr_status_clear(&p->p, ~ier);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      return 0;
++}
++EXPORT_SYMBOL(qman_p_irqsource_remove);
++
++int qman_irqsource_remove(u32 bits)
++{
++      struct qman_portal *p = get_raw_affine_portal();
++      int ret;
++      ret = qman_p_irqsource_remove(p, bits);
++      put_affine_portal();
++      return ret;
++}
++EXPORT_SYMBOL(qman_irqsource_remove);
++
++const cpumask_t *qman_affine_cpus(void)
++{
++      return &affine_mask;
++}
++EXPORT_SYMBOL(qman_affine_cpus);
++
++u16 qman_affine_channel(int cpu)
++{
++      if (cpu < 0) {
++              struct qman_portal *portal = get_raw_affine_portal();
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++              BUG_ON(portal->sharing_redirect);
++#endif
++              cpu = portal->config->public_cfg.cpu;
++              put_affine_portal();
++      }
++      BUG_ON(!cpumask_test_cpu(cpu, &affine_mask));
++      return affine_channels[cpu];
++}
++EXPORT_SYMBOL(qman_affine_channel);
++
++void *qman_get_affine_portal(int cpu)
++{
++      return affine_portals[cpu];
++}
++EXPORT_SYMBOL(qman_get_affine_portal);
++
++int qman_p_poll_dqrr(struct qman_portal *p, unsigned int limit)
++{
++      int ret;
++
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      if (unlikely(p->sharing_redirect))
++              ret = -EINVAL;
++      else
++#endif
++      {
++              BUG_ON(p->irq_sources & QM_PIRQ_DQRI);
++              ret = __poll_portal_fast(p, limit);
++      }
++      return ret;
++}
++EXPORT_SYMBOL(qman_p_poll_dqrr);
++
++int qman_poll_dqrr(unsigned int limit)
++{
++      struct qman_portal *p = get_poll_portal();
++      int ret;
++      ret = qman_p_poll_dqrr(p, limit);
++      put_poll_portal();
++      return ret;
++}
++EXPORT_SYMBOL(qman_poll_dqrr);
++
++u32 qman_p_poll_slow(struct qman_portal *p)
++{
++      u32 ret;
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      if (unlikely(p->sharing_redirect))
++              ret = (u32)-1;
++      else
++#endif
++      {
++              u32 is = qm_isr_status_read(&p->p) & ~p->irq_sources;
++              ret = __poll_portal_slow(p, is);
++              qm_isr_status_clear(&p->p, ret);
++      }
++      return ret;
++}
++EXPORT_SYMBOL(qman_p_poll_slow);
++
++u32 qman_poll_slow(void)
++{
++      struct qman_portal *p = get_poll_portal();
++      u32 ret;
++      ret = qman_p_poll_slow(p);
++      put_poll_portal();
++      return ret;
++}
++EXPORT_SYMBOL(qman_poll_slow);
++
++/* Legacy wrapper */
++void qman_p_poll(struct qman_portal *p)
++{
++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
++      if (unlikely(p->sharing_redirect))
++              return;
++#endif
++      if ((~p->irq_sources) & QM_PIRQ_SLOW) {
++              if (!(p->slowpoll--)) {
++                      u32 is = qm_isr_status_read(&p->p) & ~p->irq_sources;
++                      u32 active = __poll_portal_slow(p, is);
++                      if (active) {
++                              qm_isr_status_clear(&p->p, active);
++                              p->slowpoll = SLOW_POLL_BUSY;
++                      } else
++                              p->slowpoll = SLOW_POLL_IDLE;
++              }
++      }
++      if ((~p->irq_sources) & QM_PIRQ_DQRI)
++              __poll_portal_fast(p, CONFIG_FSL_QMAN_POLL_LIMIT);
++}
++EXPORT_SYMBOL(qman_p_poll);
++
++void qman_poll(void)
++{
++      struct qman_portal *p = get_poll_portal();
++      qman_p_poll(p);
++      put_poll_portal();
++}
++EXPORT_SYMBOL(qman_poll);
++
++void qman_p_stop_dequeues(struct qman_portal *p)
++{
++      qman_stop_dequeues_ex(p);
++}
++EXPORT_SYMBOL(qman_p_stop_dequeues);
++
++void qman_stop_dequeues(void)
++{
++      struct qman_portal *p = get_affine_portal();
++      qman_p_stop_dequeues(p);
++      put_affine_portal();
++}
++EXPORT_SYMBOL(qman_stop_dequeues);
++
++void qman_p_start_dequeues(struct qman_portal *p)
++{
++      unsigned long irqflags __maybe_unused;
++      PORTAL_IRQ_LOCK(p, irqflags);
++      DPA_ASSERT(p->dqrr_disable_ref > 0);
++      if (!(--p->dqrr_disable_ref))
++              qm_dqrr_set_maxfill(&p->p, DQRR_MAXFILL);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++}
++EXPORT_SYMBOL(qman_p_start_dequeues);
++
++void qman_start_dequeues(void)
++{
++      struct qman_portal *p = get_affine_portal();
++      qman_p_start_dequeues(p);
++      put_affine_portal();
++}
++EXPORT_SYMBOL(qman_start_dequeues);
++
++void qman_p_static_dequeue_add(struct qman_portal *p, u32 pools)
++{
++      unsigned long irqflags __maybe_unused;
++      PORTAL_IRQ_LOCK(p, irqflags);
++      pools &= p->config->public_cfg.pools;
++      p->sdqcr |= pools;
++      qm_dqrr_sdqcr_set(&p->p, p->sdqcr);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++}
++EXPORT_SYMBOL(qman_p_static_dequeue_add);
++
++void qman_static_dequeue_add(u32 pools)
++{
++      struct qman_portal *p = get_affine_portal();
++      qman_p_static_dequeue_add(p, pools);
++      put_affine_portal();
++}
++EXPORT_SYMBOL(qman_static_dequeue_add);
++
++void qman_p_static_dequeue_del(struct qman_portal *p, u32 pools)
++{
++      unsigned long irqflags __maybe_unused;
++      PORTAL_IRQ_LOCK(p, irqflags);
++      pools &= p->config->public_cfg.pools;
++      p->sdqcr &= ~pools;
++      qm_dqrr_sdqcr_set(&p->p, p->sdqcr);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++}
++EXPORT_SYMBOL(qman_p_static_dequeue_del);
++
++void qman_static_dequeue_del(u32 pools)
++{
++      struct qman_portal *p = get_affine_portal();
++      qman_p_static_dequeue_del(p, pools);
++      put_affine_portal();
++}
++EXPORT_SYMBOL(qman_static_dequeue_del);
++
++u32 qman_p_static_dequeue_get(struct qman_portal *p)
++{
++      return p->sdqcr;
++}
++EXPORT_SYMBOL(qman_p_static_dequeue_get);
++
++u32 qman_static_dequeue_get(void)
++{
++      struct qman_portal *p = get_affine_portal();
++      u32 ret = qman_p_static_dequeue_get(p);
++      put_affine_portal();
++      return ret;
++}
++EXPORT_SYMBOL(qman_static_dequeue_get);
++
++void qman_p_dca(struct qman_portal *p, struct qm_dqrr_entry *dq,
++                                              int park_request)
++{
++      qm_dqrr_cdc_consume_1ptr(&p->p, dq, park_request);
++}
++EXPORT_SYMBOL(qman_p_dca);
++
++void qman_dca(struct qm_dqrr_entry *dq, int park_request)
++{
++      struct qman_portal *p = get_affine_portal();
++      qman_p_dca(p, dq, park_request);
++      put_affine_portal();
++}
++EXPORT_SYMBOL(qman_dca);
++
++/*******************/
++/* Frame queue API */
++/*******************/
++
++static const char *mcr_result_str(u8 result)
++{
++      switch (result) {
++      case QM_MCR_RESULT_NULL:
++              return "QM_MCR_RESULT_NULL";
++      case QM_MCR_RESULT_OK:
++              return "QM_MCR_RESULT_OK";
++      case QM_MCR_RESULT_ERR_FQID:
++              return "QM_MCR_RESULT_ERR_FQID";
++      case QM_MCR_RESULT_ERR_FQSTATE:
++              return "QM_MCR_RESULT_ERR_FQSTATE";
++      case QM_MCR_RESULT_ERR_NOTEMPTY:
++              return "QM_MCR_RESULT_ERR_NOTEMPTY";
++      case QM_MCR_RESULT_PENDING:
++              return "QM_MCR_RESULT_PENDING";
++      case QM_MCR_RESULT_ERR_BADCOMMAND:
++              return "QM_MCR_RESULT_ERR_BADCOMMAND";
++      }
++      return "<unknown MCR result>";
++}
++
++int qman_create_fq(u32 fqid, u32 flags, struct qman_fq *fq)
++{
++      struct qm_fqd fqd;
++      struct qm_mcr_queryfq_np np;
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++
++      if (flags & QMAN_FQ_FLAG_DYNAMIC_FQID) {
++              int ret = qman_alloc_fqid(&fqid);
++              if (ret)
++                      return ret;
++      }
++      spin_lock_init(&fq->fqlock);
++      fq->fqid = fqid;
++      fq->flags = flags;
++      fq->state = qman_fq_state_oos;
++      fq->cgr_groupid = 0;
++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
++      if (unlikely(find_empty_fq_table_entry(&fq->key, fq)))
++              return -ENOMEM;
++#endif
++      if (!(flags & QMAN_FQ_FLAG_AS_IS) || (flags & QMAN_FQ_FLAG_NO_MODIFY))
++              return 0;
++      /* Everything else is AS_IS support */
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++      mcc = qm_mc_start(&p->p);
++      mcc->queryfq.fqid = cpu_to_be32(fqid);
++      qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYFQ);
++      if (mcr->result != QM_MCR_RESULT_OK) {
++              pr_err("QUERYFQ failed: %s\n", mcr_result_str(mcr->result));
++              goto err;
++      }
++      fqd = mcr->queryfq.fqd;
++      hw_fqd_to_cpu(&fqd);
++      mcc = qm_mc_start(&p->p);
++      mcc->queryfq_np.fqid = cpu_to_be32(fqid);
++      qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYFQ_NP);
++      if (mcr->result != QM_MCR_RESULT_OK) {
++              pr_err("QUERYFQ_NP failed: %s\n", mcr_result_str(mcr->result));
++              goto err;
++      }
++      np = mcr->queryfq_np;
++      /* Phew, have queryfq and queryfq_np results, stitch together
++       * the FQ object from those. */
++      fq->cgr_groupid = fqd.cgid;
++      switch (np.state & QM_MCR_NP_STATE_MASK) {
++      case QM_MCR_NP_STATE_OOS:
++              break;
++      case QM_MCR_NP_STATE_RETIRED:
++              fq->state = qman_fq_state_retired;
++              if (np.frm_cnt)
++                      fq_set(fq, QMAN_FQ_STATE_NE);
++              break;
++      case QM_MCR_NP_STATE_TEN_SCHED:
++      case QM_MCR_NP_STATE_TRU_SCHED:
++      case QM_MCR_NP_STATE_ACTIVE:
++              fq->state = qman_fq_state_sched;
++              if (np.state & QM_MCR_NP_STATE_R)
++                      fq_set(fq, QMAN_FQ_STATE_CHANGING);
++              break;
++      case QM_MCR_NP_STATE_PARKED:
++              fq->state = qman_fq_state_parked;
++              break;
++      default:
++              DPA_ASSERT(NULL == "invalid FQ state");
++      }
++      if (fqd.fq_ctrl & QM_FQCTRL_CGE)
++              fq->state |= QMAN_FQ_STATE_CGR_EN;
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      return 0;
++err:
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      if (flags & QMAN_FQ_FLAG_DYNAMIC_FQID)
++              qman_release_fqid(fqid);
++      return -EIO;
++}
++EXPORT_SYMBOL(qman_create_fq);
++
++void qman_destroy_fq(struct qman_fq *fq, u32 flags __maybe_unused)
++{
++
++      /* We don't need to lock the FQ as it is a pre-condition that the FQ be
++       * quiesced. Instead, run some checks. */
++      switch (fq->state) {
++      case qman_fq_state_parked:
++              DPA_ASSERT(flags & QMAN_FQ_DESTROY_PARKED);
++      case qman_fq_state_oos:
++              if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID))
++                      qman_release_fqid(fq->fqid);
++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
++              clear_fq_table_entry(fq->key);
++#endif
++              return;
++      default:
++              break;
++      }
++      DPA_ASSERT(NULL == "qman_free_fq() on unquiesced FQ!");
++}
++EXPORT_SYMBOL(qman_destroy_fq);
++
++u32 qman_fq_fqid(struct qman_fq *fq)
++{
++      return fq->fqid;
++}
++EXPORT_SYMBOL(qman_fq_fqid);
++
++void qman_fq_state(struct qman_fq *fq, enum qman_fq_state *state, u32 *flags)
++{
++      if (state)
++              *state = fq->state;
++      if (flags)
++              *flags = fq->flags;
++}
++EXPORT_SYMBOL(qman_fq_state);
++
++int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res, myverb = (flags & QMAN_INITFQ_FLAG_SCHED) ?
++              QM_MCC_VERB_INITFQ_SCHED : QM_MCC_VERB_INITFQ_PARKED;
++
++      if ((fq->state != qman_fq_state_oos) &&
++                      (fq->state != qman_fq_state_parked))
++              return -EINVAL;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)))
++              return -EINVAL;
++#endif
++      if (opts && (opts->we_mask & QM_INITFQ_WE_OAC)) {
++              /* And can't be set at the same time as TDTHRESH */
++              if (opts->we_mask & QM_INITFQ_WE_TDTHRESH)
++                      return -EINVAL;
++      }
++      /* Issue an INITFQ_[PARKED|SCHED] management command */
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++      FQLOCK(fq);
++      if (unlikely((fq_isset(fq, QMAN_FQ_STATE_CHANGING)) ||
++                      ((fq->state != qman_fq_state_oos) &&
++                              (fq->state != qman_fq_state_parked)))) {
++              FQUNLOCK(fq);
++              PORTAL_IRQ_UNLOCK(p, irqflags);
++              put_affine_portal();
++              return -EBUSY;
++      }
++      mcc = qm_mc_start(&p->p);
++      if (opts)
++              mcc->initfq = *opts;
++      mcc->initfq.fqid = cpu_to_be32(fq->fqid);
++      mcc->initfq.count = 0;
++
++      /* If the FQ does *not* have the TO_DCPORTAL flag, contextB is set as a
++       * demux pointer. Otherwise, the caller-provided value is allowed to
++       * stand, don't overwrite it. */
++      if (fq_isclear(fq, QMAN_FQ_FLAG_TO_DCPORTAL)) {
++              dma_addr_t phys_fq;
++              mcc->initfq.we_mask |= QM_INITFQ_WE_CONTEXTB;
++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
++              mcc->initfq.fqd.context_b = fq->key;
++#else
++              mcc->initfq.fqd.context_b = (u32)(uintptr_t)fq;
++#endif
++              /* and the physical address - NB, if the user wasn't trying to
++               * set CONTEXTA, clear the stashing settings. */
++              if (!(mcc->initfq.we_mask & QM_INITFQ_WE_CONTEXTA)) {
++                      mcc->initfq.we_mask |= QM_INITFQ_WE_CONTEXTA;
++                      memset(&mcc->initfq.fqd.context_a, 0,
++                              sizeof(mcc->initfq.fqd.context_a));
++              } else {
++                      phys_fq = dma_map_single(&p->pdev->dev, fq, sizeof(*fq),
++                                              DMA_TO_DEVICE);
++                      qm_fqd_stashing_set64(&mcc->initfq.fqd, phys_fq);
++              }
++      }
++      if (flags & QMAN_INITFQ_FLAG_LOCAL) {
++              mcc->initfq.fqd.dest.channel = p->config->public_cfg.channel;
++              if (!(mcc->initfq.we_mask & QM_INITFQ_WE_DESTWQ)) {
++                      mcc->initfq.we_mask |= QM_INITFQ_WE_DESTWQ;
++                      mcc->initfq.fqd.dest.wq = 4;
++              }
++      }
++      mcc->initfq.we_mask = cpu_to_be16(mcc->initfq.we_mask);
++      cpu_to_hw_fqd(&mcc->initfq.fqd);
++      qm_mc_commit(&p->p, myverb);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == myverb);
++      res = mcr->result;
++      if (res != QM_MCR_RESULT_OK) {
++              FQUNLOCK(fq);
++              PORTAL_IRQ_UNLOCK(p, irqflags);
++              put_affine_portal();
++              return -EIO;
++      }
++      if (opts) {
++              if (opts->we_mask & QM_INITFQ_WE_FQCTRL) {
++                      if (opts->fqd.fq_ctrl & QM_FQCTRL_CGE)
++                              fq_set(fq, QMAN_FQ_STATE_CGR_EN);
++                      else
++                              fq_clear(fq, QMAN_FQ_STATE_CGR_EN);
++              }
++              if (opts->we_mask & QM_INITFQ_WE_CGID)
++                      fq->cgr_groupid = opts->fqd.cgid;
++      }
++      fq->state = (flags & QMAN_INITFQ_FLAG_SCHED) ?
++                      qman_fq_state_sched : qman_fq_state_parked;
++      FQUNLOCK(fq);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      return 0;
++}
++EXPORT_SYMBOL(qman_init_fq);
++
++int qman_schedule_fq(struct qman_fq *fq)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      int ret = 0;
++      u8 res;
++
++      if (fq->state != qman_fq_state_parked)
++              return -EINVAL;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)))
++              return -EINVAL;
++#endif
++      /* Issue a ALTERFQ_SCHED management command */
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++      FQLOCK(fq);
++      if (unlikely((fq_isset(fq, QMAN_FQ_STATE_CHANGING)) ||
++                      (fq->state != qman_fq_state_parked))) {
++              ret = -EBUSY;
++              goto out;
++      }
++      mcc = qm_mc_start(&p->p);
++      mcc->alterfq.fqid = cpu_to_be32(fq->fqid);
++      qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_SCHED);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_SCHED);
++      res = mcr->result;
++      if (res != QM_MCR_RESULT_OK) {
++              ret = -EIO;
++              goto out;
++      }
++      fq->state = qman_fq_state_sched;
++out:
++      FQUNLOCK(fq);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      return ret;
++}
++EXPORT_SYMBOL(qman_schedule_fq);
++
++int qman_retire_fq(struct qman_fq *fq, u32 *flags)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      int rval;
++      u8 res;
++
++      if ((fq->state != qman_fq_state_parked) &&
++                      (fq->state != qman_fq_state_sched))
++              return -EINVAL;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)))
++              return -EINVAL;
++#endif
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++      FQLOCK(fq);
++      if (unlikely((fq_isset(fq, QMAN_FQ_STATE_CHANGING)) ||
++                      (fq->state == qman_fq_state_retired) ||
++                              (fq->state == qman_fq_state_oos))) {
++              rval = -EBUSY;
++              goto out;
++      }
++      rval = table_push_fq(p, fq);
++      if (rval)
++              goto out;
++      mcc = qm_mc_start(&p->p);
++      mcc->alterfq.fqid = cpu_to_be32(fq->fqid);
++      qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_RETIRE);
++      res = mcr->result;
++      /* "Elegant" would be to treat OK/PENDING the same way; set CHANGING,
++       * and defer the flags until FQRNI or FQRN (respectively) show up. But
++       * "Friendly" is to process OK immediately, and not set CHANGING. We do
++       * friendly, otherwise the caller doesn't necessarily have a fully
++       * "retired" FQ on return even if the retirement was immediate. However
++       * this does mean some code duplication between here and
++       * fq_state_change(). */
++      if (likely(res == QM_MCR_RESULT_OK)) {
++              rval = 0;
++              /* Process 'fq' right away, we'll ignore FQRNI */
++              if (mcr->alterfq.fqs & QM_MCR_FQS_NOTEMPTY)
++                      fq_set(fq, QMAN_FQ_STATE_NE);
++              if (mcr->alterfq.fqs & QM_MCR_FQS_ORLPRESENT)
++                      fq_set(fq, QMAN_FQ_STATE_ORL);
++              else
++                      table_del_fq(p, fq);
++              if (flags)
++                      *flags = fq->flags;
++              fq->state = qman_fq_state_retired;
++              if (fq->cb.fqs) {
++                      /* Another issue with supporting "immediate" retirement
++                       * is that we're forced to drop FQRNIs, because by the
++                       * time they're seen it may already be "too late" (the
++                       * fq may have been OOS'd and free()'d already). But if
++                       * the upper layer wants a callback whether it's
++                       * immediate or not, we have to fake a "MR" entry to
++                       * look like an FQRNI... */
++                      struct qm_mr_entry msg;
++                      msg.verb = QM_MR_VERB_FQRNI;
++                      msg.fq.fqs = mcr->alterfq.fqs;
++                      msg.fq.fqid = fq->fqid;
++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
++                      msg.fq.contextB = fq->key;
++#else
++                      msg.fq.contextB = (u32)(uintptr_t)fq;
++#endif
++                      fq->cb.fqs(p, fq, &msg);
++              }
++      } else if (res == QM_MCR_RESULT_PENDING) {
++              rval = 1;
++              fq_set(fq, QMAN_FQ_STATE_CHANGING);
++      } else {
++              rval = -EIO;
++              table_del_fq(p, fq);
++      }
++out:
++      FQUNLOCK(fq);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      return rval;
++}
++EXPORT_SYMBOL(qman_retire_fq);
++
++int qman_oos_fq(struct qman_fq *fq)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      int ret = 0;
++      u8 res;
++
++      if (fq->state != qman_fq_state_retired)
++              return -EINVAL;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)))
++              return -EINVAL;
++#endif
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++      FQLOCK(fq);
++      if (unlikely((fq_isset(fq, QMAN_FQ_STATE_BLOCKOOS)) ||
++                      (fq->state != qman_fq_state_retired))) {
++              ret = -EBUSY;
++              goto out;
++      }
++      mcc = qm_mc_start(&p->p);
++      mcc->alterfq.fqid = cpu_to_be32(fq->fqid);
++      qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_OOS);
++      res = mcr->result;
++      if (res != QM_MCR_RESULT_OK) {
++              ret = -EIO;
++              goto out;
++      }
++      fq->state = qman_fq_state_oos;
++out:
++      FQUNLOCK(fq);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      return ret;
++}
++EXPORT_SYMBOL(qman_oos_fq);
++
++int qman_fq_flow_control(struct qman_fq *fq, int xon)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      int ret = 0;
++      u8 res;
++      u8 myverb;
++
++      if ((fq->state == qman_fq_state_oos) ||
++              (fq->state == qman_fq_state_retired) ||
++              (fq->state == qman_fq_state_parked))
++              return -EINVAL;
++
++#ifdef CONFIG_FSL_DPA_CHECKING
++      if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)))
++              return -EINVAL;
++#endif
++      /* Issue a ALTER_FQXON or ALTER_FQXOFF management command */
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++      FQLOCK(fq);
++      if (unlikely((fq_isset(fq, QMAN_FQ_STATE_CHANGING)) ||
++                      (fq->state == qman_fq_state_parked) ||
++                      (fq->state == qman_fq_state_oos) ||
++                      (fq->state == qman_fq_state_retired))) {
++              ret = -EBUSY;
++              goto out;
++      }
++      mcc = qm_mc_start(&p->p);
++      mcc->alterfq.fqid = fq->fqid;
++      mcc->alterfq.count = 0;
++      myverb = xon ? QM_MCC_VERB_ALTER_FQXON : QM_MCC_VERB_ALTER_FQXOFF;
++
++      qm_mc_commit(&p->p, myverb);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == myverb);
++
++      res = mcr->result;
++      if (res != QM_MCR_RESULT_OK) {
++              ret = -EIO;
++              goto out;
++      }
++out:
++      FQUNLOCK(fq);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      return ret;
++}
++EXPORT_SYMBOL(qman_fq_flow_control);
++
++int qman_query_fq(struct qman_fq *fq, struct qm_fqd *fqd)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p = get_affine_portal();
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      PORTAL_IRQ_LOCK(p, irqflags);
++      mcc = qm_mc_start(&p->p);
++      mcc->queryfq.fqid = cpu_to_be32(fq->fqid);
++      qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ);
++      res = mcr->result;
++      if (res == QM_MCR_RESULT_OK)
++              *fqd = mcr->queryfq.fqd;
++      hw_fqd_to_cpu(fqd);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      if (res != QM_MCR_RESULT_OK)
++              return -EIO;
++      return 0;
++}
++EXPORT_SYMBOL(qman_query_fq);
++
++int qman_query_fq_np(struct qman_fq *fq, struct qm_mcr_queryfq_np *np)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p = get_affine_portal();
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      PORTAL_IRQ_LOCK(p, irqflags);
++      mcc = qm_mc_start(&p->p);
++      mcc->queryfq.fqid = cpu_to_be32(fq->fqid);
++      qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ_NP);
++      res = mcr->result;
++      if (res == QM_MCR_RESULT_OK) {
++              *np = mcr->queryfq_np;
++              np->fqd_link = be24_to_cpu(np->fqd_link);
++              np->odp_seq = be16_to_cpu(np->odp_seq);
++              np->orp_nesn = be16_to_cpu(np->orp_nesn);
++              np->orp_ea_hseq  = be16_to_cpu(np->orp_ea_hseq);
++              np->orp_ea_tseq  = be16_to_cpu(np->orp_ea_tseq);
++              np->orp_ea_hptr = be24_to_cpu(np->orp_ea_hptr);
++              np->orp_ea_tptr = be24_to_cpu(np->orp_ea_tptr);
++              np->pfdr_hptr = be24_to_cpu(np->pfdr_hptr);
++              np->pfdr_tptr = be24_to_cpu(np->pfdr_tptr);
++              np->ics_surp = be16_to_cpu(np->ics_surp);
++              np->byte_cnt = be32_to_cpu(np->byte_cnt);
++              np->frm_cnt = be24_to_cpu(np->frm_cnt);
++              np->ra1_sfdr = be16_to_cpu(np->ra1_sfdr);
++              np->ra2_sfdr = be16_to_cpu(np->ra2_sfdr);
++              np->od1_sfdr = be16_to_cpu(np->od1_sfdr);
++              np->od2_sfdr = be16_to_cpu(np->od2_sfdr);
++              np->od3_sfdr = be16_to_cpu(np->od3_sfdr);
++      }
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      if (res == QM_MCR_RESULT_ERR_FQID)
++              return -ERANGE;
++      else if (res != QM_MCR_RESULT_OK)
++              return -EIO;
++      return 0;
++}
++EXPORT_SYMBOL(qman_query_fq_np);
++
++int qman_query_wq(u8 query_dedicated, struct qm_mcr_querywq *wq)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p = get_affine_portal();
++      unsigned long irqflags __maybe_unused;
++      u8 res, myverb;
++
++      PORTAL_IRQ_LOCK(p, irqflags);
++      myverb = (query_dedicated) ? QM_MCR_VERB_QUERYWQ_DEDICATED :
++                               QM_MCR_VERB_QUERYWQ;
++      mcc = qm_mc_start(&p->p);
++      mcc->querywq.channel.id = cpu_to_be16(wq->channel.id);
++      qm_mc_commit(&p->p, myverb);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == myverb);
++      res = mcr->result;
++      if (res == QM_MCR_RESULT_OK) {
++              int i, array_len;
++              wq->channel.id = be16_to_cpu(mcr->querywq.channel.id);
++              array_len = ARRAY_SIZE(mcr->querywq.wq_len);
++              for (i = 0; i < array_len; i++)
++                      wq->wq_len[i] = be32_to_cpu(mcr->querywq.wq_len[i]);
++      }
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("QUERYWQ failed: %s\n", mcr_result_str(res));
++              return -EIO;
++      }
++      return 0;
++}
++EXPORT_SYMBOL(qman_query_wq);
++
++int qman_testwrite_cgr(struct qman_cgr *cgr, u64 i_bcnt,
++                      struct qm_mcr_cgrtestwrite *result)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p = get_affine_portal();
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      PORTAL_IRQ_LOCK(p, irqflags);
++      mcc = qm_mc_start(&p->p);
++      mcc->cgrtestwrite.cgid = cgr->cgrid;
++      mcc->cgrtestwrite.i_bcnt_hi = (u8)(i_bcnt >> 32);
++      mcc->cgrtestwrite.i_bcnt_lo = (u32)i_bcnt;
++      qm_mc_commit(&p->p, QM_MCC_VERB_CGRTESTWRITE);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_CGRTESTWRITE);
++      res = mcr->result;
++      if (res == QM_MCR_RESULT_OK)
++              *result = mcr->cgrtestwrite;
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CGR TEST WRITE failed: %s\n", mcr_result_str(res));
++              return -EIO;
++      }
++      return 0;
++}
++EXPORT_SYMBOL(qman_testwrite_cgr);
++
++int qman_query_cgr(struct qman_cgr *cgr, struct qm_mcr_querycgr *cgrd)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p = get_affine_portal();
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++      int i;
++
++      PORTAL_IRQ_LOCK(p, irqflags);
++      mcc = qm_mc_start(&p->p);
++      mcc->querycgr.cgid = cgr->cgrid;
++      qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCGR);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYCGR);
++      res = mcr->result;
++      if (res == QM_MCR_RESULT_OK)
++              *cgrd = mcr->querycgr;
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("QUERY_CGR failed: %s\n", mcr_result_str(res));
++              return -EIO;
++      }
++      cgrd->cgr.wr_parm_g.word =
++              be32_to_cpu(cgrd->cgr.wr_parm_g.word);
++      cgrd->cgr.wr_parm_y.word =
++              be32_to_cpu(cgrd->cgr.wr_parm_y.word);
++      cgrd->cgr.wr_parm_r.word =
++              be32_to_cpu(cgrd->cgr.wr_parm_r.word);
++      cgrd->cgr.cscn_targ =  be32_to_cpu(cgrd->cgr.cscn_targ);
++      cgrd->cgr.__cs_thres = be16_to_cpu(cgrd->cgr.__cs_thres);
++      for (i = 0; i < ARRAY_SIZE(cgrd->cscn_targ_swp); i++)
++                      be32_to_cpus(&cgrd->cscn_targ_swp[i]);
++      return 0;
++}
++EXPORT_SYMBOL(qman_query_cgr);
++
++int qman_query_congestion(struct qm_mcr_querycongestion *congestion)
++{
++      struct qm_mc_result *mcr;
++      struct qman_portal *p = get_affine_portal();
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++      int i;
++
++      PORTAL_IRQ_LOCK(p, irqflags);
++      qm_mc_start(&p->p);
++      qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCONGESTION);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
++                      QM_MCC_VERB_QUERYCONGESTION);
++      res = mcr->result;
++      if (res == QM_MCR_RESULT_OK)
++              memcpy_fromio(congestion, &mcr->querycongestion,
++                            sizeof(*congestion));
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("QUERY_CONGESTION failed: %s\n", mcr_result_str(res));
++              return -EIO;
++      }
++
++      for (i = 0; i < ARRAY_SIZE(congestion->state.__state); i++)
++                      be32_to_cpus(&congestion->state.__state[i]);
++      return 0;
++}
++EXPORT_SYMBOL(qman_query_congestion);
++
++/* internal function used as a wait_event() expression */
++static int set_p_vdqcr(struct qman_portal *p, struct qman_fq *fq, u32 vdqcr)
++{
++      unsigned long irqflags __maybe_unused;
++      int ret = -EBUSY;
++      PORTAL_IRQ_LOCK(p, irqflags);
++      if (!p->vdqcr_owned) {
++              FQLOCK(fq);
++              if (fq_isset(fq, QMAN_FQ_STATE_VDQCR))
++                      goto escape;
++              fq_set(fq, QMAN_FQ_STATE_VDQCR);
++              FQUNLOCK(fq);
++              p->vdqcr_owned = fq;
++              ret = 0;
++      }
++escape:
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      if (!ret)
++              qm_dqrr_vdqcr_set(&p->p, vdqcr);
++      return ret;
++}
++
++static int set_vdqcr(struct qman_portal **p, struct qman_fq *fq, u32 vdqcr)
++{
++      int ret;
++      *p = get_affine_portal();
++      ret = set_p_vdqcr(*p, fq, vdqcr);
++      put_affine_portal();
++      return ret;
++}
++
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++static int wait_p_vdqcr_start(struct qman_portal *p, struct qman_fq *fq,
++                              u32 vdqcr, u32 flags)
++{
++      int ret = 0;
++      if (flags & QMAN_VOLATILE_FLAG_WAIT_INT)
++              ret = wait_event_interruptible(affine_queue,
++                              !(ret = set_p_vdqcr(p, fq, vdqcr)));
++      else
++              wait_event(affine_queue, !(ret = set_p_vdqcr(p, fq, vdqcr)));
++      return ret;
++}
++
++static int wait_vdqcr_start(struct qman_portal **p, struct qman_fq *fq,
++                              u32 vdqcr, u32 flags)
++{
++      int ret = 0;
++      if (flags & QMAN_VOLATILE_FLAG_WAIT_INT)
++              ret = wait_event_interruptible(affine_queue,
++                              !(ret = set_vdqcr(p, fq, vdqcr)));
++      else
++              wait_event(affine_queue, !(ret = set_vdqcr(p, fq, vdqcr)));
++      return ret;
++}
++#endif
++
++int qman_p_volatile_dequeue(struct qman_portal *p, struct qman_fq *fq,
++                                      u32 flags __maybe_unused, u32 vdqcr)
++{
++      int ret;
++
++      if ((fq->state != qman_fq_state_parked) &&
++                      (fq->state != qman_fq_state_retired))
++              return -EINVAL;
++      if (vdqcr & QM_VDQCR_FQID_MASK)
++              return -EINVAL;
++      if (fq_isset(fq, QMAN_FQ_STATE_VDQCR))
++              return -EBUSY;
++      vdqcr = (vdqcr & ~QM_VDQCR_FQID_MASK) | fq->fqid;
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++      if (flags & QMAN_VOLATILE_FLAG_WAIT)
++              ret = wait_p_vdqcr_start(p, fq, vdqcr, flags);
++      else
++#endif
++              ret = set_p_vdqcr(p, fq, vdqcr);
++      if (ret)
++              return ret;
++      /* VDQCR is set */
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++      if (flags & QMAN_VOLATILE_FLAG_FINISH) {
++              if (flags & QMAN_VOLATILE_FLAG_WAIT_INT)
++                      /* NB: don't propagate any error - the caller wouldn't
++                       * know whether the VDQCR was issued or not. A signal
++                       * could arrive after returning anyway, so the caller
++                       * can check signal_pending() if that's an issue. */
++                      wait_event_interruptible(affine_queue,
++                              !fq_isset(fq, QMAN_FQ_STATE_VDQCR));
++              else
++                      wait_event(affine_queue,
++                              !fq_isset(fq, QMAN_FQ_STATE_VDQCR));
++      }
++#endif
++      return 0;
++}
++EXPORT_SYMBOL(qman_p_volatile_dequeue);
++
++int qman_volatile_dequeue(struct qman_fq *fq, u32 flags __maybe_unused,
++                              u32 vdqcr)
++{
++      struct qman_portal *p;
++      int ret;
++
++      if ((fq->state != qman_fq_state_parked) &&
++                      (fq->state != qman_fq_state_retired))
++              return -EINVAL;
++      if (vdqcr & QM_VDQCR_FQID_MASK)
++              return -EINVAL;
++      if (fq_isset(fq, QMAN_FQ_STATE_VDQCR))
++              return -EBUSY;
++      vdqcr = (vdqcr & ~QM_VDQCR_FQID_MASK) | fq->fqid;
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++      if (flags & QMAN_VOLATILE_FLAG_WAIT)
++              ret = wait_vdqcr_start(&p, fq, vdqcr, flags);
++      else
++#endif
++              ret = set_vdqcr(&p, fq, vdqcr);
++      if (ret)
++              return ret;
++      /* VDQCR is set */
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++      if (flags & QMAN_VOLATILE_FLAG_FINISH) {
++              if (flags & QMAN_VOLATILE_FLAG_WAIT_INT)
++                      /* NB: don't propagate any error - the caller wouldn't
++                       * know whether the VDQCR was issued or not. A signal
++                       * could arrive after returning anyway, so the caller
++                       * can check signal_pending() if that's an issue. */
++                      wait_event_interruptible(affine_queue,
++                              !fq_isset(fq, QMAN_FQ_STATE_VDQCR));
++              else
++                      wait_event(affine_queue,
++                              !fq_isset(fq, QMAN_FQ_STATE_VDQCR));
++      }
++#endif
++      return 0;
++}
++EXPORT_SYMBOL(qman_volatile_dequeue);
++
++static noinline void update_eqcr_ci(struct qman_portal *p, u8 avail)
++{
++      if (avail)
++              qm_eqcr_cce_prefetch(&p->p);
++      else
++              qm_eqcr_cce_update(&p->p);
++}
++
++int qman_eqcr_is_empty(void)
++{
++      unsigned long irqflags __maybe_unused;
++      struct qman_portal *p = get_affine_portal();
++      u8 avail;
++
++      PORTAL_IRQ_LOCK(p, irqflags);
++      update_eqcr_ci(p, 0);
++      avail = qm_eqcr_get_fill(&p->p);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      return avail == 0;
++}
++EXPORT_SYMBOL(qman_eqcr_is_empty);
++
++void qman_set_dc_ern(qman_cb_dc_ern handler, int affine)
++{
++      if (affine) {
++              unsigned long irqflags __maybe_unused;
++              struct qman_portal *p = get_affine_portal();
++              PORTAL_IRQ_LOCK(p, irqflags);
++              p->cb_dc_ern = handler;
++              PORTAL_IRQ_UNLOCK(p, irqflags);
++              put_affine_portal();
++      } else
++              cb_dc_ern = handler;
++}
++EXPORT_SYMBOL(qman_set_dc_ern);
++
++static inline struct qm_eqcr_entry *try_p_eq_start(struct qman_portal *p,
++                                      unsigned long *irqflags __maybe_unused,
++                                      struct qman_fq *fq,
++                                      const struct qm_fd *fd,
++                                      u32 flags)
++{
++      struct qm_eqcr_entry *eq;
++      u8 avail;
++      PORTAL_IRQ_LOCK(p, (*irqflags));
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
++                      (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) {
++              if (p->eqci_owned) {
++                      PORTAL_IRQ_UNLOCK(p, (*irqflags));
++                      return NULL;
++              }
++              p->eqci_owned = fq;
++      }
++#endif
++      if (p->use_eqcr_ci_stashing) {
++              /*
++               * The stashing case is easy, only update if we need to in
++               * order to try and liberate ring entries.
++               */
++              eq = qm_eqcr_start_stash(&p->p);
++      } else {
++              /*
++               * The non-stashing case is harder, need to prefetch ahead of
++               * time.
++               */
++              avail = qm_eqcr_get_avail(&p->p);
++              if (avail < 2)
++                      update_eqcr_ci(p, avail);
++              eq = qm_eqcr_start_no_stash(&p->p);
++      }
++
++      if (unlikely(!eq)) {
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++              if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
++                              (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC)))
++                      p->eqci_owned = NULL;
++#endif
++              PORTAL_IRQ_UNLOCK(p, (*irqflags));
++              return NULL;
++      }
++      if (flags & QMAN_ENQUEUE_FLAG_DCA)
++              eq->dca = QM_EQCR_DCA_ENABLE |
++                      ((flags & QMAN_ENQUEUE_FLAG_DCA_PARK) ?
++                                      QM_EQCR_DCA_PARK : 0) |
++                      ((flags >> 8) & QM_EQCR_DCA_IDXMASK);
++      eq->fqid = cpu_to_be32(fq->fqid);
++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
++      eq->tag = cpu_to_be32(fq->key);
++#else
++      eq->tag = cpu_to_be32((u32)(uintptr_t)fq);
++#endif
++      eq->fd = *fd;
++      cpu_to_hw_fd(&eq->fd);
++      return eq;
++}
++
++static inline struct qm_eqcr_entry *try_eq_start(struct qman_portal **p,
++                                      unsigned long *irqflags __maybe_unused,
++                                      struct qman_fq *fq,
++                                      const struct qm_fd *fd,
++                                      u32 flags)
++{
++      struct qm_eqcr_entry *eq;
++      *p = get_affine_portal();
++      eq = try_p_eq_start(*p, irqflags, fq, fd, flags);
++      if (!eq)
++              put_affine_portal();
++      return eq;
++}
++
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++static noinline struct qm_eqcr_entry *__wait_eq_start(struct qman_portal **p,
++                                      unsigned long *irqflags __maybe_unused,
++                                      struct qman_fq *fq,
++                                      const struct qm_fd *fd,
++                                      u32 flags)
++{
++      struct qm_eqcr_entry *eq = try_eq_start(p, irqflags, fq, fd, flags);
++      if (!eq)
++              qm_eqcr_set_ithresh(&(*p)->p, EQCR_ITHRESH);
++      return eq;
++}
++static noinline struct qm_eqcr_entry *wait_eq_start(struct qman_portal **p,
++                                      unsigned long *irqflags __maybe_unused,
++                                      struct qman_fq *fq,
++                                      const struct qm_fd *fd,
++                                      u32 flags)
++{
++      struct qm_eqcr_entry *eq;
++      if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
++              /* NB: return NULL if signal occurs before completion. Signal
++               * can occur during return. Caller must check for signal */
++              wait_event_interruptible(affine_queue,
++                      (eq = __wait_eq_start(p, irqflags, fq, fd, flags)));
++      else
++              wait_event(affine_queue,
++                      (eq = __wait_eq_start(p, irqflags, fq, fd, flags)));
++      return eq;
++}
++static noinline struct qm_eqcr_entry *__wait_p_eq_start(struct qman_portal *p,
++                                      unsigned long *irqflags __maybe_unused,
++                                      struct qman_fq *fq,
++                                      const struct qm_fd *fd,
++                                      u32 flags)
++{
++      struct qm_eqcr_entry *eq = try_p_eq_start(p, irqflags, fq, fd, flags);
++      if (!eq)
++              qm_eqcr_set_ithresh(&p->p, EQCR_ITHRESH);
++      return eq;
++}
++static noinline struct qm_eqcr_entry *wait_p_eq_start(struct qman_portal *p,
++                                      unsigned long *irqflags __maybe_unused,
++                                      struct qman_fq *fq,
++                                      const struct qm_fd *fd,
++                                      u32 flags)
++{
++      struct qm_eqcr_entry *eq;
++      if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
++              /* NB: return NULL if signal occurs before completion. Signal
++               * can occur during return. Caller must check for signal */
++              wait_event_interruptible(affine_queue,
++                      (eq = __wait_p_eq_start(p, irqflags, fq, fd, flags)));
++      else
++              wait_event(affine_queue,
++                      (eq = __wait_p_eq_start(p, irqflags, fq, fd, flags)));
++      return eq;
++}
++#endif
++
++int qman_p_enqueue(struct qman_portal *p, struct qman_fq *fq,
++                              const struct qm_fd *fd, u32 flags)
++{
++      struct qm_eqcr_entry *eq;
++      unsigned long irqflags __maybe_unused;
++
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++      if (flags & QMAN_ENQUEUE_FLAG_WAIT)
++              eq = wait_p_eq_start(p, &irqflags, fq, fd, flags);
++      else
++#endif
++      eq = try_p_eq_start(p, &irqflags, fq, fd, flags);
++      if (!eq)
++              return -EBUSY;
++      /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */
++      qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE |
++              (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT)));
++      /* Factor the below out, it's used from qman_enqueue_orp() too */
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
++                      (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) {
++              if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
++                      /* NB: return success even if signal occurs before
++                       * condition is true. pvb_commit guarantees success */
++                      wait_event_interruptible(affine_queue,
++                                      (p->eqci_owned != fq));
++              else
++                      wait_event(affine_queue, (p->eqci_owned != fq));
++      }
++#endif
++      return 0;
++}
++EXPORT_SYMBOL(qman_p_enqueue);
++
++int qman_enqueue(struct qman_fq *fq, const struct qm_fd *fd, u32 flags)
++{
++      struct qman_portal *p;
++      struct qm_eqcr_entry *eq;
++      unsigned long irqflags __maybe_unused;
++
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++      if (flags & QMAN_ENQUEUE_FLAG_WAIT)
++              eq = wait_eq_start(&p, &irqflags, fq, fd, flags);
++      else
++#endif
++      eq = try_eq_start(&p, &irqflags, fq, fd, flags);
++      if (!eq)
++              return -EBUSY;
++      /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */
++      qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE |
++              (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT)));
++      /* Factor the below out, it's used from qman_enqueue_orp() too */
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
++                      (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) {
++              if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
++                      /* NB: return success even if signal occurs before
++                       * condition is true. pvb_commit guarantees success */
++                      wait_event_interruptible(affine_queue,
++                                      (p->eqci_owned != fq));
++              else
++                      wait_event(affine_queue, (p->eqci_owned != fq));
++      }
++#endif
++      return 0;
++}
++EXPORT_SYMBOL(qman_enqueue);
++
++int qman_p_enqueue_orp(struct qman_portal *p, struct qman_fq *fq,
++                              const struct qm_fd *fd, u32 flags,
++                              struct qman_fq *orp, u16 orp_seqnum)
++{
++      struct qm_eqcr_entry *eq;
++      unsigned long irqflags __maybe_unused;
++
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++      if (flags & QMAN_ENQUEUE_FLAG_WAIT)
++              eq = wait_p_eq_start(p, &irqflags, fq, fd, flags);
++      else
++#endif
++      eq = try_p_eq_start(p, &irqflags, fq, fd, flags);
++      if (!eq)
++              return -EBUSY;
++      /* Process ORP-specifics here */
++      if (flags & QMAN_ENQUEUE_FLAG_NLIS)
++              orp_seqnum |= QM_EQCR_SEQNUM_NLIS;
++      else {
++              orp_seqnum &= ~QM_EQCR_SEQNUM_NLIS;
++              if (flags & QMAN_ENQUEUE_FLAG_NESN)
++                      orp_seqnum |= QM_EQCR_SEQNUM_NESN;
++              else
++                      /* No need to check 4 QMAN_ENQUEUE_FLAG_HOLE */
++                      orp_seqnum &= ~QM_EQCR_SEQNUM_NESN;
++      }
++      eq->seqnum = cpu_to_be16(orp_seqnum);
++      eq->orp = cpu_to_be32(orp->fqid);
++      /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */
++      qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_ORP |
++              ((flags & (QMAN_ENQUEUE_FLAG_HOLE | QMAN_ENQUEUE_FLAG_NESN)) ?
++                              0 : QM_EQCR_VERB_CMD_ENQUEUE) |
++              (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT)));
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
++                      (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) {
++              if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
++                      /* NB: return success even if signal occurs before
++                       * condition is true. pvb_commit guarantees success */
++                      wait_event_interruptible(affine_queue,
++                                      (p->eqci_owned != fq));
++              else
++                      wait_event(affine_queue, (p->eqci_owned != fq));
++      }
++#endif
++      return 0;
++}
++EXPORT_SYMBOL(qman_p_enqueue_orp);
++
++int qman_enqueue_orp(struct qman_fq *fq, const struct qm_fd *fd, u32 flags,
++                      struct qman_fq *orp, u16 orp_seqnum)
++{
++      struct qman_portal *p;
++      struct qm_eqcr_entry *eq;
++      unsigned long irqflags __maybe_unused;
++
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++      if (flags & QMAN_ENQUEUE_FLAG_WAIT)
++              eq = wait_eq_start(&p, &irqflags, fq, fd, flags);
++      else
++#endif
++      eq = try_eq_start(&p, &irqflags, fq, fd, flags);
++      if (!eq)
++              return -EBUSY;
++      /* Process ORP-specifics here */
++      if (flags & QMAN_ENQUEUE_FLAG_NLIS)
++              orp_seqnum |= QM_EQCR_SEQNUM_NLIS;
++      else {
++              orp_seqnum &= ~QM_EQCR_SEQNUM_NLIS;
++              if (flags & QMAN_ENQUEUE_FLAG_NESN)
++                      orp_seqnum |= QM_EQCR_SEQNUM_NESN;
++              else
++                      /* No need to check 4 QMAN_ENQUEUE_FLAG_HOLE */
++                      orp_seqnum &= ~QM_EQCR_SEQNUM_NESN;
++      }
++      eq->seqnum = cpu_to_be16(orp_seqnum);
++      eq->orp = cpu_to_be32(orp->fqid);
++      /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */
++      qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_ORP |
++              ((flags & (QMAN_ENQUEUE_FLAG_HOLE | QMAN_ENQUEUE_FLAG_NESN)) ?
++                              0 : QM_EQCR_VERB_CMD_ENQUEUE) |
++              (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT)));
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
++                      (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) {
++              if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
++                      /* NB: return success even if signal occurs before
++                       * condition is true. pvb_commit guarantees success */
++                      wait_event_interruptible(affine_queue,
++                                      (p->eqci_owned != fq));
++              else
++                      wait_event(affine_queue, (p->eqci_owned != fq));
++      }
++#endif
++      return 0;
++}
++EXPORT_SYMBOL(qman_enqueue_orp);
++
++int qman_p_enqueue_precommit(struct qman_portal *p, struct qman_fq *fq,
++                              const struct qm_fd *fd, u32 flags,
++                              qman_cb_precommit cb, void *cb_arg)
++{
++      struct qm_eqcr_entry *eq;
++      unsigned long irqflags __maybe_unused;
++
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++      if (flags & QMAN_ENQUEUE_FLAG_WAIT)
++              eq = wait_p_eq_start(p, &irqflags, fq, fd, flags);
++      else
++#endif
++      eq = try_p_eq_start(p, &irqflags, fq, fd, flags);
++      if (!eq)
++              return -EBUSY;
++      /* invoke user supplied callback function before writing commit verb */
++      if (cb(cb_arg)) {
++              PORTAL_IRQ_UNLOCK(p, irqflags);
++              return -EINVAL;
++      }
++      /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */
++      qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE |
++              (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT)));
++      /* Factor the below out, it's used from qman_enqueue_orp() too */
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
++                      (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) {
++              if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
++                      /* NB: return success even if signal occurs before
++                       * condition is true. pvb_commit guarantees success */
++                      wait_event_interruptible(affine_queue,
++                                      (p->eqci_owned != fq));
++              else
++                      wait_event(affine_queue, (p->eqci_owned != fq));
++      }
++#endif
++      return 0;
++}
++EXPORT_SYMBOL(qman_p_enqueue_precommit);
++
++int qman_enqueue_precommit(struct qman_fq *fq, const struct qm_fd *fd,
++              u32 flags, qman_cb_precommit cb, void *cb_arg)
++{
++      struct qman_portal *p;
++      struct qm_eqcr_entry *eq;
++      unsigned long irqflags __maybe_unused;
++
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++      if (flags & QMAN_ENQUEUE_FLAG_WAIT)
++              eq = wait_eq_start(&p, &irqflags, fq, fd, flags);
++      else
++#endif
++      eq = try_eq_start(&p, &irqflags, fq, fd, flags);
++      if (!eq)
++              return -EBUSY;
++      /* invoke user supplied callback function before writing commit verb */
++      if (cb(cb_arg)) {
++              PORTAL_IRQ_UNLOCK(p, irqflags);
++              put_affine_portal();
++              return -EINVAL;
++      }
++      /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */
++      qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE |
++              (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT)));
++      /* Factor the below out, it's used from qman_enqueue_orp() too */
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++      if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
++                      (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) {
++              if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
++                      /* NB: return success even if signal occurs before
++                       * condition is true. pvb_commit guarantees success */
++                      wait_event_interruptible(affine_queue,
++                                      (p->eqci_owned != fq));
++              else
++                      wait_event(affine_queue, (p->eqci_owned != fq));
++      }
++#endif
++      return 0;
++}
++EXPORT_SYMBOL(qman_enqueue_precommit);
++
++int qman_modify_cgr(struct qman_cgr *cgr, u32 flags,
++                      struct qm_mcc_initcgr *opts)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p = get_affine_portal();
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++      u8 verb = QM_MCC_VERB_MODIFYCGR;
++
++      PORTAL_IRQ_LOCK(p, irqflags);
++      mcc = qm_mc_start(&p->p);
++      if (opts)
++              mcc->initcgr = *opts;
++      mcc->initcgr.we_mask = cpu_to_be16(mcc->initcgr.we_mask);
++      mcc->initcgr.cgr.wr_parm_g.word =
++              cpu_to_be32(mcc->initcgr.cgr.wr_parm_g.word);
++      mcc->initcgr.cgr.wr_parm_y.word =
++              cpu_to_be32(mcc->initcgr.cgr.wr_parm_y.word);
++      mcc->initcgr.cgr.wr_parm_r.word =
++              cpu_to_be32(mcc->initcgr.cgr.wr_parm_r.word);
++      mcc->initcgr.cgr.cscn_targ =  cpu_to_be32(mcc->initcgr.cgr.cscn_targ);
++      mcc->initcgr.cgr.__cs_thres = cpu_to_be16(mcc->initcgr.cgr.__cs_thres);
++
++      mcc->initcgr.cgid = cgr->cgrid;
++      if (flags & QMAN_CGR_FLAG_USE_INIT)
++              verb = QM_MCC_VERB_INITCGR;
++      qm_mc_commit(&p->p, verb);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == verb);
++      res = mcr->result;
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      return (res == QM_MCR_RESULT_OK) ? 0 : -EIO;
++}
++EXPORT_SYMBOL(qman_modify_cgr);
++
++#define TARG_MASK(n) (0x80000000 >> (n->config->public_cfg.channel - \
++                                      QM_CHANNEL_SWPORTAL0))
++#define TARG_DCP_MASK(n) (0x80000000 >> (10 + n))
++#define PORTAL_IDX(n) (n->config->public_cfg.channel - QM_CHANNEL_SWPORTAL0)
++
++static u8 qman_cgr_cpus[__CGR_NUM];
++
++int qman_create_cgr(struct qman_cgr *cgr, u32 flags,
++                      struct qm_mcc_initcgr *opts)
++{
++      unsigned long irqflags __maybe_unused;
++      struct qm_mcr_querycgr cgr_state;
++      struct qm_mcc_initcgr local_opts;
++      int ret;
++      struct qman_portal *p;
++
++      /* We have to check that the provided CGRID is within the limits of the
++       * data-structures, for obvious reasons. However we'll let h/w take
++       * care of determining whether it's within the limits of what exists on
++       * the SoC. */
++      if (cgr->cgrid >= __CGR_NUM)
++              return -EINVAL;
++
++      preempt_disable();
++      p = get_affine_portal();
++      qman_cgr_cpus[cgr->cgrid] = smp_processor_id();
++      preempt_enable();
++
++      memset(&local_opts, 0, sizeof(struct qm_mcc_initcgr));
++      cgr->chan = p->config->public_cfg.channel;
++      spin_lock_irqsave(&p->cgr_lock, irqflags);
++
++      /* if no opts specified, just add it to the list */
++      if (!opts)
++              goto add_list;
++
++      ret = qman_query_cgr(cgr, &cgr_state);
++      if (ret)
++              goto release_lock;
++      if (opts)
++              local_opts = *opts;
++      if ((qman_ip_rev & 0xFF00) >= QMAN_REV30)
++              local_opts.cgr.cscn_targ_upd_ctrl =
++                      QM_CGR_TARG_UDP_CTRL_WRITE_BIT | PORTAL_IDX(p);
++      else
++              /* Overwrite TARG */
++              local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ |
++                                                      TARG_MASK(p);
++      local_opts.we_mask |= QM_CGR_WE_CSCN_TARG;
++
++      /* send init if flags indicate so */
++      if (opts && (flags & QMAN_CGR_FLAG_USE_INIT))
++              ret = qman_modify_cgr(cgr, QMAN_CGR_FLAG_USE_INIT, &local_opts);
++      else
++              ret = qman_modify_cgr(cgr, 0, &local_opts);
++      if (ret)
++              goto release_lock;
++add_list:
++      list_add(&cgr->node, &p->cgr_cbs);
++
++      /* Determine if newly added object requires its callback to be called */
++      ret = qman_query_cgr(cgr, &cgr_state);
++      if (ret) {
++              /* we can't go back, so proceed and return success, but screen
++               * and wail to the log file */
++              pr_crit("CGR HW state partially modified\n");
++              ret = 0;
++              goto release_lock;
++      }
++      if (cgr->cb && cgr_state.cgr.cscn_en && qman_cgrs_get(&p->cgrs[1],
++                                                      cgr->cgrid))
++              cgr->cb(p, cgr, 1);
++release_lock:
++      spin_unlock_irqrestore(&p->cgr_lock, irqflags);
++      put_affine_portal();
++      return ret;
++}
++EXPORT_SYMBOL(qman_create_cgr);
++
++int qman_create_cgr_to_dcp(struct qman_cgr *cgr, u32 flags, u16 dcp_portal,
++                                      struct qm_mcc_initcgr *opts)
++{
++      unsigned long irqflags __maybe_unused;
++      struct qm_mcc_initcgr local_opts;
++      struct qm_mcr_querycgr cgr_state;
++      int ret;
++
++      if ((qman_ip_rev & 0xFF00) < QMAN_REV30) {
++              pr_warn("This QMan version doesn't support to send CSCN to DCP portal\n");
++              return -EINVAL;
++      }
++      /* We have to check that the provided CGRID is within the limits of the
++       * data-structures, for obvious reasons. However we'll let h/w take
++       * care of determining whether it's within the limits of what exists on
++       * the SoC.
++       */
++      if (cgr->cgrid >= __CGR_NUM)
++              return -EINVAL;
++
++      ret = qman_query_cgr(cgr, &cgr_state);
++      if (ret)
++              return ret;
++
++      memset(&local_opts, 0, sizeof(struct qm_mcc_initcgr));
++      if (opts)
++              local_opts = *opts;
++
++      if ((qman_ip_rev & 0xFF00) >= QMAN_REV30)
++              local_opts.cgr.cscn_targ_upd_ctrl =
++                              QM_CGR_TARG_UDP_CTRL_WRITE_BIT |
++                              QM_CGR_TARG_UDP_CTRL_DCP | dcp_portal;
++      else
++              local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ |
++                                      TARG_DCP_MASK(dcp_portal);
++      local_opts.we_mask |= QM_CGR_WE_CSCN_TARG;
++
++      /* send init if flags indicate so */
++      if (opts && (flags & QMAN_CGR_FLAG_USE_INIT))
++              ret = qman_modify_cgr(cgr, QMAN_CGR_FLAG_USE_INIT,
++                                                      &local_opts);
++      else
++              ret = qman_modify_cgr(cgr, 0, &local_opts);
++
++      return ret;
++}
++EXPORT_SYMBOL(qman_create_cgr_to_dcp);
++
++int qman_delete_cgr(struct qman_cgr *cgr)
++{
++      unsigned long irqflags __maybe_unused;
++      struct qm_mcr_querycgr cgr_state;
++      struct qm_mcc_initcgr local_opts;
++      int ret = 0;
++      struct qman_cgr *i;
++      struct qman_portal *p = get_affine_portal();
++
++      if (cgr->chan != p->config->public_cfg.channel) {
++              pr_crit("Attempting to delete cgr from different portal "
++                      "than it was create: create 0x%x, delete 0x%x\n",
++                      cgr->chan, p->config->public_cfg.channel);
++              ret = -EINVAL;
++              goto put_portal;
++      }
++      memset(&local_opts, 0, sizeof(struct qm_mcc_initcgr));
++      spin_lock_irqsave(&p->cgr_lock, irqflags);
++      list_del(&cgr->node);
++      /*
++       * If there are no other CGR objects for this CGRID in the list, update
++       * CSCN_TARG accordingly
++       */
++      list_for_each_entry(i, &p->cgr_cbs, node)
++              if ((i->cgrid == cgr->cgrid) && i->cb)
++                      goto release_lock;
++      ret = qman_query_cgr(cgr, &cgr_state);
++      if (ret)  {
++              /* add back to the list */
++              list_add(&cgr->node, &p->cgr_cbs);
++              goto release_lock;
++      }
++      /* Overwrite TARG */
++      local_opts.we_mask = QM_CGR_WE_CSCN_TARG;
++      if ((qman_ip_rev & 0xFF00) >= QMAN_REV30)
++              local_opts.cgr.cscn_targ_upd_ctrl = PORTAL_IDX(p);
++      else
++              local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ &
++                                                       ~(TARG_MASK(p));
++      ret = qman_modify_cgr(cgr, 0, &local_opts);
++      if (ret)
++              /* add back to the list */
++              list_add(&cgr->node, &p->cgr_cbs);
++release_lock:
++      spin_unlock_irqrestore(&p->cgr_lock, irqflags);
++put_portal:
++      put_affine_portal();
++      return ret;
++}
++EXPORT_SYMBOL(qman_delete_cgr);
++
++struct cgr_comp {
++      struct qman_cgr *cgr;
++      struct completion completion;
++};
++
++static int qman_delete_cgr_thread(void *p)
++{
++      struct cgr_comp *cgr_comp = (struct cgr_comp *)p;
++      int res;
++
++      res = qman_delete_cgr((struct qman_cgr *)cgr_comp->cgr);
++      complete(&cgr_comp->completion);
++
++      return res;
++}
++
++void qman_delete_cgr_safe(struct qman_cgr *cgr)
++{
++      struct task_struct *thread;
++      struct cgr_comp cgr_comp;
++
++      preempt_disable();
++      if (qman_cgr_cpus[cgr->cgrid] != smp_processor_id()) {
++              init_completion(&cgr_comp.completion);
++              cgr_comp.cgr = cgr;
++              thread = kthread_create(qman_delete_cgr_thread, &cgr_comp,
++                                      "cgr_del");
++
++              if (likely(!IS_ERR(thread))) {
++                      kthread_bind(thread, qman_cgr_cpus[cgr->cgrid]);
++                      wake_up_process(thread);
++                      wait_for_completion(&cgr_comp.completion);
++                      preempt_enable();
++                      return;
++              }
++      }
++      qman_delete_cgr(cgr);
++      preempt_enable();
++}
++EXPORT_SYMBOL(qman_delete_cgr_safe);
++
++int qm_get_clock(u64 *clock_hz)
++{
++      if (!qman_clk) {
++              pr_warn("Qman clock speed is unknown\n");
++              return  -EINVAL;
++      }
++      *clock_hz = (u64)qman_clk;
++      return 0;
++}
++EXPORT_SYMBOL(qm_get_clock);
++
++int qm_set_clock(u64 clock_hz)
++{
++      if (qman_clk)
++              return -1;
++      qman_clk = (u32)clock_hz;
++              return 0;
++}
++EXPORT_SYMBOL(qm_set_clock);
++
++/* CEETM management command */
++static int qman_ceetm_configure_lfqmt(struct qm_mcc_ceetm_lfqmt_config *opts)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      mcc->lfqmt_config = *opts;
++      qm_mc_commit(&p->p, QM_CEETM_VERB_LFQMT_CONFIG);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
++                                       QM_CEETM_VERB_LFQMT_CONFIG);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++
++      res = mcr->result;
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CEETM: CONFIGURE LFQMT failed\n");
++              return -EIO;
++      }
++      return 0;
++}
++
++int qman_ceetm_query_lfqmt(int lfqid,
++                         struct qm_mcr_ceetm_lfqmt_query *lfqmt_query)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      mcc->lfqmt_query.lfqid = lfqid;
++      qm_mc_commit(&p->p, QM_CEETM_VERB_LFQMT_QUERY);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_LFQMT_QUERY);
++      res = mcr->result;
++      if (res == QM_MCR_RESULT_OK)
++              *lfqmt_query = mcr->lfqmt_query;
++
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CEETM: QUERY LFQMT failed\n");
++              return -EIO;
++      }
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_query_lfqmt);
++
++static int qman_ceetm_configure_cq(struct qm_mcc_ceetm_cq_config *opts)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      mcc->cq_config = *opts;
++      qm_mc_commit(&p->p, QM_CEETM_VERB_CQ_CONFIG);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      res = mcr->result;
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_CQ_CONFIG);
++
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CEETM: CONFIGURE CQ failed\n");
++              return -EIO;
++      }
++      return 0;
++}
++
++int qman_ceetm_query_cq(unsigned int cqid, unsigned int dcpid,
++                              struct qm_mcr_ceetm_cq_query *cq_query)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      mcc->cq_query.cqid = cpu_to_be16(cqid);
++      mcc->cq_query.dcpid = dcpid;
++      qm_mc_commit(&p->p, QM_CEETM_VERB_CQ_QUERY);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_CQ_QUERY);
++      res = mcr->result;
++      if (res == QM_MCR_RESULT_OK) {
++              *cq_query = mcr->cq_query;
++              hw_cq_query_to_cpu(cq_query);
++      }
++
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CEETM: QUERY CQ failed\n");
++              return -EIO;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_query_cq);
++
++static int qman_ceetm_configure_dct(struct qm_mcc_ceetm_dct_config *opts)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      mcc->dct_config = *opts;
++      qm_mc_commit(&p->p, QM_CEETM_VERB_DCT_CONFIG);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_DCT_CONFIG);
++      res = mcr->result;
++
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CEETM: CONFIGURE DCT failed\n");
++              return -EIO;
++      }
++      return 0;
++}
++
++static int qman_ceetm_query_dct(struct qm_mcc_ceetm_dct_query *opts,
++                       struct qm_mcr_ceetm_dct_query *dct_query)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p = get_affine_portal();
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      mcc->dct_query = *opts;
++      qm_mc_commit(&p->p, QM_CEETM_VERB_DCT_QUERY);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_DCT_QUERY);
++      res = mcr->result;
++
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CEETM: QUERY DCT failed\n");
++              return -EIO;
++      }
++
++      *dct_query = mcr->dct_query;
++      return 0;
++}
++
++static int qman_ceetm_configure_class_scheduler(
++                      struct qm_mcc_ceetm_class_scheduler_config *opts)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      mcc->csch_config = *opts;
++      qm_mc_commit(&p->p, QM_CEETM_VERB_CLASS_SCHEDULER_CONFIG);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
++                                      QM_CEETM_VERB_CLASS_SCHEDULER_CONFIG);
++      res = mcr->result;
++
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CEETM: CONFIGURE CLASS SCHEDULER failed\n");
++              return -EIO;
++      }
++      return 0;
++}
++
++static int qman_ceetm_query_class_scheduler(struct qm_ceetm_channel *channel,
++                      struct qm_mcr_ceetm_class_scheduler_query *query)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      mcc->csch_query.cqcid = cpu_to_be16(channel->idx);
++      mcc->csch_query.dcpid = channel->dcp_idx;
++      qm_mc_commit(&p->p, QM_CEETM_VERB_CLASS_SCHEDULER_QUERY);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
++                              QM_CEETM_VERB_CLASS_SCHEDULER_QUERY);
++      res = mcr->result;
++
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CEETM: QUERY CLASS SCHEDULER failed\n");
++              return -EIO;
++      }
++      *query = mcr->csch_query;
++      return 0;
++}
++
++static int qman_ceetm_configure_mapping_shaper_tcfc(
++              struct qm_mcc_ceetm_mapping_shaper_tcfc_config *opts)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      mcc->mst_config = *opts;
++      qm_mc_commit(&p->p, QM_CEETM_VERB_MAPPING_SHAPER_TCFC_CONFIG);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
++                              QM_CEETM_VERB_MAPPING_SHAPER_TCFC_CONFIG);
++      res = mcr->result;
++
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CEETM: CONFIGURE CHANNEL MAPPING failed\n");
++              return -EIO;
++      }
++      return 0;
++}
++
++static int qman_ceetm_query_mapping_shaper_tcfc(
++              struct qm_mcc_ceetm_mapping_shaper_tcfc_query *opts,
++              struct qm_mcr_ceetm_mapping_shaper_tcfc_query *response)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      mcc->mst_query = *opts;
++      qm_mc_commit(&p->p, QM_CEETM_VERB_MAPPING_SHAPER_TCFC_QUERY);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
++                              QM_CEETM_VERB_MAPPING_SHAPER_TCFC_QUERY);
++      res = mcr->result;
++
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CEETM: QUERY CHANNEL MAPPING failed\n");
++              return -EIO;
++      }
++
++      *response = mcr->mst_query;
++      return 0;
++}
++
++static int qman_ceetm_configure_ccgr(struct qm_mcc_ceetm_ccgr_config *opts)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      mcc->ccgr_config = *opts;
++
++      qm_mc_commit(&p->p, QM_CEETM_VERB_CCGR_CONFIG);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_CCGR_CONFIG);
++
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++
++      res = mcr->result;
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CEETM: CONFIGURE CCGR failed\n");
++              return -EIO;
++      }
++      return 0;
++}
++
++int qman_ceetm_query_ccgr(struct qm_mcc_ceetm_ccgr_query *ccgr_query,
++                              struct qm_mcr_ceetm_ccgr_query *response)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      mcc->ccgr_query.ccgrid = cpu_to_be16(ccgr_query->ccgrid);
++      mcc->ccgr_query.dcpid = ccgr_query->dcpid;
++      qm_mc_commit(&p->p, QM_CEETM_VERB_CCGR_QUERY);
++
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_CCGR_QUERY);
++      res = mcr->result;
++      if (res == QM_MCR_RESULT_OK) {
++              *response = mcr->ccgr_query;
++              hw_ccgr_query_to_cpu(response);
++      }
++
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CEETM: QUERY CCGR failed\n");
++              return -EIO;
++      }
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_query_ccgr);
++
++static int qman_ceetm_cq_peek_pop_xsfdrread(struct qm_ceetm_cq *cq,
++                      u8 command_type, u16 xsfdr,
++                      struct qm_mcr_ceetm_cq_peek_pop_xsfdrread *cq_ppxr)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      switch (command_type) {
++      case 0:
++      case 1:
++              mcc->cq_ppxr.cqid = (cq->parent->idx << 4) | cq->idx;
++              break;
++      case 2:
++              mcc->cq_ppxr.xsfdr = xsfdr;
++              break;
++      default:
++              break;
++      }
++      mcc->cq_ppxr.ct = command_type;
++      mcc->cq_ppxr.dcpid = cq->parent->dcp_idx;
++      qm_mc_commit(&p->p, QM_CEETM_VERB_CQ_PEEK_POP_XFDRREAD);
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
++                              QM_CEETM_VERB_CQ_PEEK_POP_XFDRREAD);
++
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++
++      res = mcr->result;
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CEETM: CQ PEEK/POP/XSFDR READ failed\n");
++              return -EIO;
++      }
++      *cq_ppxr = mcr->cq_ppxr;
++      return 0;
++}
++
++static int qman_ceetm_query_statistics(u16 cid,
++                      enum qm_dc_portal dcp_idx,
++                      u16 command_type,
++                      struct qm_mcr_ceetm_statistics_query *query_result)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      mcc->stats_query_write.cid = cid;
++      mcc->stats_query_write.dcpid = dcp_idx;
++      mcc->stats_query_write.ct = command_type;
++      qm_mc_commit(&p->p, QM_CEETM_VERB_STATISTICS_QUERY_WRITE);
++
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
++                                       QM_CEETM_VERB_STATISTICS_QUERY_WRITE);
++
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++
++      res = mcr->result;
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CEETM: STATISTICS QUERY failed\n");
++              return -EIO;
++      }
++      *query_result = mcr->stats_query;
++      return 0;
++}
++
++int qman_ceetm_query_write_statistics(u16 cid, enum qm_dc_portal dcp_idx,
++                                    u16 command_type, u64 frame_count,
++                                    u64 byte_count)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      mcc->stats_query_write.cid = cid;
++      mcc->stats_query_write.dcpid = dcp_idx;
++      mcc->stats_query_write.ct = command_type;
++      mcc->stats_query_write.frm_cnt = frame_count;
++      mcc->stats_query_write.byte_cnt = byte_count;
++      qm_mc_commit(&p->p, QM_CEETM_VERB_STATISTICS_QUERY_WRITE);
++
++      while (!(mcr = qm_mc_result(&p->p)))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
++                                       QM_CEETM_VERB_STATISTICS_QUERY_WRITE);
++
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++
++      res = mcr->result;
++      if (res != QM_MCR_RESULT_OK) {
++              pr_err("CEETM: STATISTICS WRITE failed\n");
++              return -EIO;
++      }
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_query_write_statistics);
++
++int qman_ceetm_bps2tokenrate(u64 bps, struct qm_ceetm_rate *token_rate,
++                                                      int rounding)
++{
++      u16 pres;
++      u64 temp;
++      u64 qman_freq;
++      int ret;
++
++      /* Read PRES from CEET_CFG_PRES register */
++      ret = qman_ceetm_get_prescaler(&pres);
++      if (ret)
++              return -EINVAL;
++
++      ret = qm_get_clock(&qman_freq);
++      if (ret)
++              return -EINVAL;
++
++      /* token-rate = bytes-per-second * update-reference-period
++       *
++       * Where token-rate is N/8192 for a integer N, and
++       * update-reference-period is (2^22)/(PRES*QHz), where PRES
++       * is the prescalar value and QHz is the QMan clock frequency.
++       * So:
++       *
++       * token-rate = (byte-per-second*2^22)/PRES*QHZ)
++       *
++       * Converting to bits-per-second gives;
++       *
++       *      token-rate = (bps*2^19) / (PRES*QHZ)
++       *      N = (bps*2^32) / (PRES*QHz)
++       *
++       * And to avoid 64-bit overflow if 'bps' is larger than 4Gbps
++       * (yet minimise rounding error if 'bps' is small), we reorganise
++       * the formula to use two 16-bit shifts rather than 1 32-bit shift.
++       *      N = (((bps*2^16)/PRES)*2^16)/QHz
++       */
++      temp = ROUNDING((bps << 16), pres, rounding);
++      temp = ROUNDING((temp << 16), qman_freq, rounding);
++      token_rate->whole = temp >> 13;
++      token_rate->fraction = temp & (((u64)1 << 13) - 1);
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_bps2tokenrate);
++
++int qman_ceetm_tokenrate2bps(const struct qm_ceetm_rate *token_rate, u64 *bps,
++                                                      int rounding)
++{
++      u16 pres;
++      u64 temp;
++      u64 qman_freq;
++      int ret;
++
++      /* Read PRES from CEET_CFG_PRES register */
++      ret = qman_ceetm_get_prescaler(&pres);
++      if (ret)
++              return -EINVAL;
++
++      ret = qm_get_clock(&qman_freq);
++      if (ret)
++              return -EINVAL;
++
++      /* bytes-per-second = token-rate / update-reference-period
++       *
++       * where "token-rate" is N/8192 for an integer N, and
++       * "update-reference-period" is (2^22)/(PRES*QHz), where PRES is
++       * the prescalar value and QHz is the QMan clock frequency. So;
++       *
++       * bytes-per-second = (N/8192) / (4194304/PRES*QHz)
++       *                  = N*PRES*QHz / (4194304*8192)
++       *                  = N*PRES*QHz / (2^35)
++       *
++       * Converting to bits-per-second gives;
++       *
++       *             bps = N*PRES*QHZ / (2^32)
++       *
++       * Note, the numerator has a maximum width of 72 bits! So to
++       * avoid 64-bit overflow errors, we calculate PRES*QHZ (maximum
++       * width 48 bits) divided by 2^9 (reducing to maximum 39 bits), before
++       * multiplying by N (goes to maximum of 63 bits).
++       *
++       *             temp = PRES*QHZ / (2^16)
++       *             kbps = temp*N / (2^16)
++       */
++      temp = ROUNDING(qman_freq * pres, (u64)1 << 16 , rounding);
++      temp *= ((token_rate->whole << 13) + token_rate->fraction);
++      *bps = ROUNDING(temp, (u64)(1) << 16, rounding);
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_tokenrate2bps);
++
++int qman_ceetm_sp_claim(struct qm_ceetm_sp **sp, enum qm_dc_portal dcp_idx,
++                                              unsigned int sp_idx)
++{
++      struct qm_ceetm_sp *p;
++
++      DPA_ASSERT((dcp_idx ==  qm_dc_portal_fman0) ||
++                      (dcp_idx == qm_dc_portal_fman1));
++
++      if ((sp_idx < qman_ceetms[dcp_idx].sp_range[0]) ||
++              (sp_idx >= (qman_ceetms[dcp_idx].sp_range[0] +
++              qman_ceetms[dcp_idx].sp_range[1]))) {
++              pr_err("Sub-portal index doesn't exist\n");
++              return -EINVAL;
++      }
++
++      list_for_each_entry(p, &qman_ceetms[dcp_idx].sub_portals, node) {
++              if ((p->idx == sp_idx) && (p->is_claimed == 0)) {
++                      p->is_claimed = 1;
++                      *sp = p;
++                      return 0;
++              }
++      }
++      pr_err("The sub-portal#%d is not available!\n", sp_idx);
++      return -ENODEV;
++}
++EXPORT_SYMBOL(qman_ceetm_sp_claim);
++
++int qman_ceetm_sp_release(struct qm_ceetm_sp *sp)
++{
++      struct qm_ceetm_sp *p;
++
++      if (sp->lni && sp->lni->is_claimed == 1) {
++              pr_err("The dependency of sub-portal has not been released!\n");
++              return -EBUSY;
++      }
++
++      list_for_each_entry(p, &qman_ceetms[sp->dcp_idx].sub_portals, node) {
++              if (p->idx == sp->idx) {
++                      p->is_claimed = 0;
++                      p->lni = NULL;
++              }
++      }
++      /* Disable CEETM mode of this sub-portal */
++      qman_sp_disable_ceetm_mode(sp->dcp_idx, sp->idx);
++
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_sp_release);
++
++int qman_ceetm_lni_claim(struct qm_ceetm_lni **lni, enum qm_dc_portal dcp_idx,
++                                                      unsigned int lni_idx)
++{
++      struct qm_ceetm_lni *p;
++
++      if ((lni_idx < qman_ceetms[dcp_idx].lni_range[0]) ||
++              (lni_idx >= (qman_ceetms[dcp_idx].lni_range[0] +
++              qman_ceetms[dcp_idx].lni_range[1]))) {
++              pr_err("The lni index is out of range\n");
++              return -EINVAL;
++      }
++
++      list_for_each_entry(p, &qman_ceetms[dcp_idx].lnis, node) {
++              if ((p->idx == lni_idx) && (p->is_claimed == 0)) {
++                      *lni = p;
++                      p->is_claimed = 1;
++                      return 0;
++              }
++      }
++
++      pr_err("The LNI#%d is not available!\n", lni_idx);
++      return -EINVAL;
++}
++EXPORT_SYMBOL(qman_ceetm_lni_claim);
++
++int qman_ceetm_lni_release(struct qm_ceetm_lni *lni)
++{
++      struct qm_ceetm_lni *p;
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
++
++      if (!list_empty(&lni->channels)) {
++              pr_err("The LNI dependencies are not released!\n");
++              return -EBUSY;
++      }
++
++      list_for_each_entry(p, &qman_ceetms[lni->dcp_idx].lnis, node) {
++              if (p->idx == lni->idx) {
++                      p->shaper_enable = 0;
++                      p->shaper_couple = 0;
++                      p->cr_token_rate.whole = 0;
++                      p->cr_token_rate.fraction = 0;
++                      p->er_token_rate.whole = 0;
++                      p->er_token_rate.fraction = 0;
++                      p->cr_token_bucket_limit = 0;
++                      p->er_token_bucket_limit = 0;
++                      p->is_claimed = 0;
++              }
++      }
++      config_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
++      config_opts.dcpid = lni->dcp_idx;
++      memset(&config_opts.shaper_config, 0,
++                              sizeof(config_opts.shaper_config));
++      return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
++}
++EXPORT_SYMBOL(qman_ceetm_lni_release);
++
++int qman_ceetm_sp_set_lni(struct qm_ceetm_sp *sp, struct qm_ceetm_lni *lni)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
++
++      config_opts.cid = cpu_to_be16(CEETM_COMMAND_SP_MAPPING | sp->idx);
++      config_opts.dcpid = sp->dcp_idx;
++      config_opts.sp_mapping.map_lni_id = lni->idx;
++      sp->lni = lni;
++
++      if (qman_ceetm_configure_mapping_shaper_tcfc(&config_opts))
++              return -EINVAL;
++
++      /* Enable CEETM mode for this sub-portal */
++      return qman_sp_enable_ceetm_mode(sp->dcp_idx, sp->idx);
++}
++EXPORT_SYMBOL(qman_ceetm_sp_set_lni);
++
++int qman_ceetm_sp_get_lni(struct qm_ceetm_sp *sp, unsigned int *lni_idx)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
++      struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
++
++      query_opts.cid = cpu_to_be16(CEETM_COMMAND_SP_MAPPING | sp->idx);
++      query_opts.dcpid = sp->dcp_idx;
++      if (qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result)) {
++              pr_err("Can't get SP <-> LNI mapping\n");
++              return -EINVAL;
++      }
++      *lni_idx = query_result.sp_mapping_query.map_lni_id;
++      sp->lni->idx = query_result.sp_mapping_query.map_lni_id;
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_sp_get_lni);
++
++int qman_ceetm_lni_enable_shaper(struct qm_ceetm_lni *lni, int coupled,
++                                                              int oal)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
++
++      if (lni->shaper_enable) {
++              pr_err("The shaper has already been enabled\n");
++              return -EINVAL;
++      }
++      lni->shaper_enable = 1;
++      lni->shaper_couple = coupled;
++      lni->oal = oal;
++
++      config_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
++      config_opts.dcpid = lni->dcp_idx;
++      config_opts.shaper_config.cpl = coupled;
++      config_opts.shaper_config.oal = oal;
++      config_opts.shaper_config.crtcr = cpu_to_be24((lni->cr_token_rate.whole
++                                      << 13) | lni->cr_token_rate.fraction);
++      config_opts.shaper_config.ertcr = cpu_to_be24((lni->er_token_rate.whole
++                                      << 13) | lni->er_token_rate.fraction);
++      config_opts.shaper_config.crtbl =
++                                      cpu_to_be16(lni->cr_token_bucket_limit);
++      config_opts.shaper_config.ertbl =
++                                      cpu_to_be16(lni->er_token_bucket_limit);
++      config_opts.shaper_config.mps = 60;
++
++      return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
++}
++EXPORT_SYMBOL(qman_ceetm_lni_enable_shaper);
++
++int qman_ceetm_lni_disable_shaper(struct qm_ceetm_lni *lni)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
++
++      if (!lni->shaper_enable) {
++              pr_err("The shaper has been disabled\n");
++              return -EINVAL;
++      }
++
++      config_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
++      config_opts.dcpid = lni->dcp_idx;
++      config_opts.shaper_config.cpl = lni->shaper_couple;
++      config_opts.shaper_config.oal = lni->oal;
++      config_opts.shaper_config.crtbl =
++                                      cpu_to_be16(lni->cr_token_bucket_limit);
++      config_opts.shaper_config.ertbl =
++                                      cpu_to_be16(lni->er_token_bucket_limit);
++      /* Set CR/ER rate with all 1's to configure an infinite rate, thus
++       * disable the shaping.
++       */
++      config_opts.shaper_config.crtcr = 0xFFFFFF;
++      config_opts.shaper_config.ertcr = 0xFFFFFF;
++      config_opts.shaper_config.mps = 60;
++      lni->shaper_enable = 0;
++      return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
++}
++EXPORT_SYMBOL(qman_ceetm_lni_disable_shaper);
++
++int qman_ceetm_lni_is_shaper_enabled(struct qm_ceetm_lni *lni)
++{
++      return lni->shaper_enable;
++}
++EXPORT_SYMBOL(qman_ceetm_lni_is_shaper_enabled);
++
++int qman_ceetm_lni_set_commit_rate(struct qm_ceetm_lni *lni,
++                              const struct qm_ceetm_rate *token_rate,
++                              u16 token_limit)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
++      struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
++      int ret;
++
++      lni->cr_token_rate.whole = token_rate->whole;
++      lni->cr_token_rate.fraction = token_rate->fraction;
++      lni->cr_token_bucket_limit = token_limit;
++      if (!lni->shaper_enable)
++              return 0;
++      query_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
++      query_opts.dcpid = lni->dcp_idx;
++      ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts,
++                                                 &query_result);
++      if (ret) {
++              pr_err("Fail to get current LNI shaper setting\n");
++              return -EINVAL;
++      }
++
++      config_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
++      config_opts.dcpid = lni->dcp_idx;
++      config_opts.shaper_config.crtcr = cpu_to_be24((token_rate->whole << 13)
++                                                    | (token_rate->fraction));
++      config_opts.shaper_config.crtbl = cpu_to_be16(token_limit);
++      config_opts.shaper_config.cpl = query_result.shaper_query.cpl;
++      config_opts.shaper_config.oal = query_result.shaper_query.oal;
++      config_opts.shaper_config.ertcr = query_result.shaper_query.ertcr;
++      config_opts.shaper_config.ertbl = query_result.shaper_query.ertbl;
++      config_opts.shaper_config.mps = query_result.shaper_query.mps;
++      return  qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
++}
++EXPORT_SYMBOL(qman_ceetm_lni_set_commit_rate);
++
++int qman_ceetm_lni_set_commit_rate_bps(struct qm_ceetm_lni *lni,
++                                     u64 bps,
++                                     u16 token_limit)
++{
++      struct qm_ceetm_rate token_rate;
++      int ret;
++
++      ret = qman_ceetm_bps2tokenrate(bps, &token_rate, 0);
++      if (ret) {
++              pr_err("Can not convert bps to token rate\n");
++              return -EINVAL;
++      }
++
++      return qman_ceetm_lni_set_commit_rate(lni, &token_rate, token_limit);
++}
++EXPORT_SYMBOL(qman_ceetm_lni_set_commit_rate_bps);
++
++int qman_ceetm_lni_get_commit_rate(struct qm_ceetm_lni *lni,
++                              struct qm_ceetm_rate *token_rate,
++                              u16 *token_limit)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
++      struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
++      int ret;
++
++      query_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
++      query_opts.dcpid = lni->dcp_idx;
++
++      ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
++      if (ret) {
++              pr_err("The LNI CR rate or limit is not set\n");
++              return -EINVAL;
++      }
++      token_rate->whole = be24_to_cpu(query_result.shaper_query.crtcr) >> 13;
++      token_rate->fraction = be24_to_cpu(query_result.shaper_query.crtcr) &
++                               0x1FFF;
++      *token_limit = be16_to_cpu(query_result.shaper_query.crtbl);
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_lni_get_commit_rate);
++
++int qman_ceetm_lni_get_commit_rate_bps(struct qm_ceetm_lni *lni,
++                                     u64 *bps, u16 *token_limit)
++{
++      struct qm_ceetm_rate token_rate;
++      int ret;
++
++      ret = qman_ceetm_lni_get_commit_rate(lni, &token_rate, token_limit);
++      if (ret) {
++              pr_err("The LNI CR rate or limit is not available\n");
++              return -EINVAL;
++      }
++
++      return qman_ceetm_tokenrate2bps(&token_rate, bps, 0);
++}
++EXPORT_SYMBOL(qman_ceetm_lni_get_commit_rate_bps);
++
++int qman_ceetm_lni_set_excess_rate(struct qm_ceetm_lni *lni,
++                                      const struct qm_ceetm_rate *token_rate,
++                                      u16 token_limit)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
++      struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
++      int ret;
++
++      lni->er_token_rate.whole = token_rate->whole;
++      lni->er_token_rate.fraction = token_rate->fraction;
++      lni->er_token_bucket_limit = token_limit;
++      if (!lni->shaper_enable)
++              return 0;
++
++      query_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
++      query_opts.dcpid = lni->dcp_idx;
++      ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts,
++                                                 &query_result);
++      if (ret) {
++              pr_err("Fail to get current LNI shaper setting\n");
++              return -EINVAL;
++      }
++
++      config_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
++      config_opts.dcpid = lni->dcp_idx;
++      config_opts.shaper_config.ertcr = cpu_to_be24(
++              (token_rate->whole << 13) | (token_rate->fraction));
++      config_opts.shaper_config.ertbl = cpu_to_be16(token_limit);
++      config_opts.shaper_config.cpl = query_result.shaper_query.cpl;
++      config_opts.shaper_config.oal = query_result.shaper_query.oal;
++      config_opts.shaper_config.crtcr = query_result.shaper_query.crtcr;
++      config_opts.shaper_config.crtbl = query_result.shaper_query.crtbl;
++      config_opts.shaper_config.mps = query_result.shaper_query.mps;
++      return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
++}
++EXPORT_SYMBOL(qman_ceetm_lni_set_excess_rate);
++
++int qman_ceetm_lni_set_excess_rate_bps(struct qm_ceetm_lni *lni,
++                                     u64 bps,
++                                     u16 token_limit)
++{
++      struct qm_ceetm_rate token_rate;
++      int ret;
++
++      ret = qman_ceetm_bps2tokenrate(bps, &token_rate, 0);
++      if (ret) {
++              pr_err("Can not convert bps to token rate\n");
++              return -EINVAL;
++      }
++      return qman_ceetm_lni_set_excess_rate(lni, &token_rate, token_limit);
++}
++EXPORT_SYMBOL(qman_ceetm_lni_set_excess_rate_bps);
++
++int qman_ceetm_lni_get_excess_rate(struct qm_ceetm_lni *lni,
++                                      struct qm_ceetm_rate *token_rate,
++                                      u16 *token_limit)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
++      struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
++      int ret;
++
++      query_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
++      query_opts.dcpid = lni->dcp_idx;
++      ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
++      if (ret) {
++              pr_err("The LNI ER rate or limit is not set\n");
++              return -EINVAL;
++      }
++      token_rate->whole = be24_to_cpu(query_result.shaper_query.ertcr) >> 13;
++      token_rate->fraction = be24_to_cpu(query_result.shaper_query.ertcr) &
++                                                               0x1FFF;
++      *token_limit = be16_to_cpu(query_result.shaper_query.ertbl);
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_lni_get_excess_rate);
++
++int qman_ceetm_lni_get_excess_rate_bps(struct qm_ceetm_lni *lni,
++                                     u64 *bps, u16 *token_limit)
++{
++      struct qm_ceetm_rate token_rate;
++      int ret;
++
++      ret = qman_ceetm_lni_get_excess_rate(lni, &token_rate, token_limit);
++      if (ret) {
++              pr_err("The LNI ER rate or limit is not available\n");
++              return -EINVAL;
++      }
++
++      return qman_ceetm_tokenrate2bps(&token_rate, bps, 0);
++}
++EXPORT_SYMBOL(qman_ceetm_lni_get_excess_rate_bps);
++
++#define QMAN_CEETM_LNITCFCC_CQ_LEVEL_SHIFT(n) ((15 - n) * 4)
++#define QMAN_CEETM_LNITCFCC_ENABLE 0x8
++int qman_ceetm_lni_set_tcfcc(struct qm_ceetm_lni *lni,
++                              unsigned int cq_level,
++                              int traffic_class)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
++      struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
++      u64 lnitcfcc;
++
++      if ((cq_level > 15) | (traffic_class > 7)) {
++              pr_err("The CQ or traffic class id is out of range\n");
++              return -EINVAL;
++      }
++
++      query_opts.cid = cpu_to_be16(CEETM_COMMAND_TCFC | lni->idx);
++      query_opts.dcpid = lni->dcp_idx;
++      if (qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result)) {
++              pr_err("Fail to query tcfcc\n");
++              return -EINVAL;
++      }
++
++      lnitcfcc = be64_to_cpu(query_result.tcfc_query.lnitcfcc);
++      if (traffic_class == -1) {
++              /* disable tcfc for this CQ */
++              lnitcfcc &= ~((u64)QMAN_CEETM_LNITCFCC_ENABLE <<
++                              QMAN_CEETM_LNITCFCC_CQ_LEVEL_SHIFT(cq_level));
++      } else {
++              lnitcfcc &= ~((u64)0xF <<
++                              QMAN_CEETM_LNITCFCC_CQ_LEVEL_SHIFT(cq_level));
++              lnitcfcc |= ((u64)(QMAN_CEETM_LNITCFCC_ENABLE |
++                              traffic_class)) <<
++                              QMAN_CEETM_LNITCFCC_CQ_LEVEL_SHIFT(cq_level);
++      }
++      config_opts.tcfc_config.lnitcfcc = cpu_to_be64(lnitcfcc);
++      config_opts.cid = cpu_to_be16(CEETM_COMMAND_TCFC | lni->idx);
++      config_opts.dcpid = lni->dcp_idx;
++      return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
++}
++EXPORT_SYMBOL(qman_ceetm_lni_set_tcfcc);
++
++#define QMAN_CEETM_LNITCFCC_TC_MASK 0x7
++int qman_ceetm_lni_get_tcfcc(struct qm_ceetm_lni *lni, unsigned int cq_level,
++                                              int *traffic_class)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
++      struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
++      int ret;
++      u8 lnitcfcc;
++
++      if (cq_level > 15) {
++              pr_err("the CQ level is out of range\n");
++              return -EINVAL;
++      }
++
++      query_opts.cid = cpu_to_be16(CEETM_COMMAND_TCFC | lni->idx);
++      query_opts.dcpid = lni->dcp_idx;
++      ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
++      if (ret)
++              return ret;
++      lnitcfcc = (u8)be64_to_cpu((query_result.tcfc_query.lnitcfcc) >>
++                              QMAN_CEETM_LNITCFCC_CQ_LEVEL_SHIFT(cq_level));
++      if (lnitcfcc & QMAN_CEETM_LNITCFCC_ENABLE)
++              *traffic_class = lnitcfcc & QMAN_CEETM_LNITCFCC_TC_MASK;
++      else
++              *traffic_class = -1;
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_lni_get_tcfcc);
++
++int qman_ceetm_channel_claim(struct qm_ceetm_channel **channel,
++                              struct qm_ceetm_lni *lni)
++{
++      struct qm_ceetm_channel *p;
++      u32 channel_idx;
++      int ret = 0;
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
++
++      if (lni->dcp_idx == qm_dc_portal_fman0) {
++              ret = qman_alloc_ceetm0_channel(&channel_idx);
++      } else if (lni->dcp_idx == qm_dc_portal_fman1) {
++              ret = qman_alloc_ceetm1_channel(&channel_idx);
++      } else {
++              pr_err("dcp_idx %u does not correspond to a known fman in this driver\n",
++                      lni->dcp_idx);
++              return -EINVAL;
++      }
++
++      if (ret) {
++              pr_err("The is no channel available for LNI#%d\n", lni->idx);
++              return -ENODEV;
++      }
++
++      p = kzalloc(sizeof(*p), GFP_KERNEL);
++      if (!p)
++              return -ENOMEM;
++      p->idx = channel_idx;
++      p->dcp_idx = lni->dcp_idx;
++      p->lni_idx = lni->idx;
++      list_add_tail(&p->node, &lni->channels);
++      INIT_LIST_HEAD(&p->class_queues);
++      INIT_LIST_HEAD(&p->ccgs);
++      config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING |
++                                              channel_idx);
++      config_opts.dcpid = lni->dcp_idx;
++      config_opts.channel_mapping.map_lni_id = lni->idx;
++      config_opts.channel_mapping.map_shaped = 0;
++      if (qman_ceetm_configure_mapping_shaper_tcfc(&config_opts)) {
++              pr_err("Can't map channel#%d for LNI#%d\n",
++                                              channel_idx, lni->idx);
++              return -EINVAL;
++      }
++      *channel = p;
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_channel_claim);
++
++int qman_ceetm_channel_release(struct qm_ceetm_channel *channel)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
++      if (!list_empty(&channel->class_queues)) {
++              pr_err("CEETM channel#%d has class queue unreleased!\n",
++                                              channel->idx);
++              return -EBUSY;
++      }
++      if (!list_empty(&channel->ccgs)) {
++              pr_err("CEETM channel#%d has ccg unreleased!\n",
++                                              channel->idx);
++              return -EBUSY;
++      }
++
++      /* channel->dcp_idx corresponds to known fman validation */
++      if ((channel->dcp_idx != qm_dc_portal_fman0) &&
++          (channel->dcp_idx != qm_dc_portal_fman1)) {
++              pr_err("dcp_idx %u does not correspond to a known fman in this driver\n",
++                      channel->dcp_idx);
++              return -EINVAL;
++      }
++
++      config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
++                                    channel->idx);
++      config_opts.dcpid = channel->dcp_idx;
++      memset(&config_opts.shaper_config, 0,
++                              sizeof(config_opts.shaper_config));
++      if (qman_ceetm_configure_mapping_shaper_tcfc(&config_opts)) {
++              pr_err("Can't reset channel shapping parameters\n");
++              return -EINVAL;
++      }
++
++      if (channel->dcp_idx == qm_dc_portal_fman0) {
++              qman_release_ceetm0_channelid(channel->idx);
++      } else if (channel->dcp_idx == qm_dc_portal_fman1) {
++              qman_release_ceetm1_channelid(channel->idx);
++      } else {
++              pr_err("dcp_idx %u does not correspond to a known fman in this driver\n",
++                      channel->dcp_idx);
++              return -EINVAL;
++      }
++      list_del(&channel->node);
++      kfree(channel);
++
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_channel_release);
++
++int qman_ceetm_channel_enable_shaper(struct qm_ceetm_channel *channel,
++                                                              int coupled)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
++      struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
++
++      if (channel->shaper_enable == 1) {
++              pr_err("This channel shaper has been enabled!\n");
++              return -EINVAL;
++      }
++
++      channel->shaper_enable = 1;
++      channel->shaper_couple = coupled;
++
++      query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING |
++                                              channel->idx);
++      query_opts.dcpid = channel->dcp_idx;
++
++      if (qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result)) {
++              pr_err("Can't query channel mapping\n");
++              return -EINVAL;
++      }
++
++      config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING |
++                                              channel->idx);
++      config_opts.dcpid = channel->dcp_idx;
++      config_opts.channel_mapping.map_lni_id =
++                              query_result.channel_mapping_query.map_lni_id;
++      config_opts.channel_mapping.map_shaped = 1;
++      if (qman_ceetm_configure_mapping_shaper_tcfc(&config_opts)) {
++              pr_err("Can't enable shaper for channel #%d\n", channel->idx);
++              return -EINVAL;
++      }
++
++      config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
++                                              channel->idx);
++      config_opts.shaper_config.cpl = coupled;
++      config_opts.shaper_config.crtcr =
++                              cpu_to_be24((channel->cr_token_rate.whole
++                              << 13) |
++                              channel->cr_token_rate.fraction);
++      config_opts.shaper_config.ertcr =
++                              cpu_to_be24(channel->er_token_rate.whole
++                              << 13 |
++                              channel->er_token_rate.fraction);
++      config_opts.shaper_config.crtbl =
++                              cpu_to_be16(channel->cr_token_bucket_limit);
++      config_opts.shaper_config.ertbl =
++                              cpu_to_be16(channel->er_token_bucket_limit);
++
++      return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
++}
++EXPORT_SYMBOL(qman_ceetm_channel_enable_shaper);
++
++int qman_ceetm_channel_disable_shaper(struct qm_ceetm_channel *channel)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
++      struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
++
++
++      query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING |
++                                              channel->idx);
++      query_opts.dcpid = channel->dcp_idx;
++
++      if (qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result)) {
++              pr_err("Can't query channel mapping\n");
++              return -EINVAL;
++      }
++
++      config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING |
++                                              channel->idx);
++      config_opts.dcpid = channel->dcp_idx;
++      config_opts.channel_mapping.map_shaped = 0;
++      config_opts.channel_mapping.map_lni_id =
++                              query_result.channel_mapping_query.map_lni_id;
++
++      return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
++}
++EXPORT_SYMBOL(qman_ceetm_channel_disable_shaper);
++
++int qman_ceetm_channel_is_shaper_enabled(struct qm_ceetm_channel *channel)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
++      struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
++
++      query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING |
++                                              channel->idx);
++      query_opts.dcpid = channel->dcp_idx;
++
++      if (qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result)) {
++              pr_err("Can't query channel mapping\n");
++              return -EINVAL;
++      }
++
++      return query_result.channel_mapping_query.map_shaped;
++}
++EXPORT_SYMBOL(qman_ceetm_channel_is_shaper_enabled);
++
++int qman_ceetm_channel_set_commit_rate(struct qm_ceetm_channel *channel,
++                              const struct qm_ceetm_rate *token_rate,
++                              u16 token_limit)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
++      struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
++      int ret;
++
++      query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
++                                              channel->idx);
++      query_opts.dcpid = channel->dcp_idx;
++
++      ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
++      if (ret) {
++              pr_err("Fail to get the current channel shaper setting\n");
++              return -EINVAL;
++      }
++
++      channel->cr_token_rate.whole = token_rate->whole;
++      channel->cr_token_rate.fraction = token_rate->fraction;
++      channel->cr_token_bucket_limit = token_limit;
++      config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
++                                                      channel->idx);
++      config_opts.dcpid = channel->dcp_idx;
++      config_opts.shaper_config.crtcr = cpu_to_be24((token_rate->whole
++                                      << 13) | (token_rate->fraction));
++      config_opts.shaper_config.crtbl = cpu_to_be16(token_limit);
++      config_opts.shaper_config.cpl = query_result.shaper_query.cpl;
++      config_opts.shaper_config.ertcr = query_result.shaper_query.ertcr;
++      config_opts.shaper_config.ertbl = query_result.shaper_query.ertbl;
++      return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
++}
++EXPORT_SYMBOL(qman_ceetm_channel_set_commit_rate);
++
++int qman_ceetm_channel_set_commit_rate_bps(struct qm_ceetm_channel *channel,
++                                         u64 bps, u16 token_limit)
++{
++      struct qm_ceetm_rate token_rate;
++      int ret;
++
++      ret = qman_ceetm_bps2tokenrate(bps, &token_rate, 0);
++      if (ret) {
++              pr_err("Can not convert bps to token rate\n");
++              return -EINVAL;
++      }
++      return qman_ceetm_channel_set_commit_rate(channel, &token_rate,
++                                                token_limit);
++}
++EXPORT_SYMBOL(qman_ceetm_channel_set_commit_rate_bps);
++
++int qman_ceetm_channel_get_commit_rate(struct qm_ceetm_channel *channel,
++                              struct qm_ceetm_rate *token_rate,
++                              u16 *token_limit)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
++      struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
++      int ret;
++
++      query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
++                                              channel->idx);
++      query_opts.dcpid = channel->dcp_idx;
++
++      ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
++      if (ret | !query_result.shaper_query.crtcr |
++                       !query_result.shaper_query.crtbl) {
++              pr_err("The channel commit rate or limit is not set\n");
++              return -EINVAL;
++      }
++      token_rate->whole = be24_to_cpu(query_result.shaper_query.crtcr) >> 13;
++      token_rate->fraction = be24_to_cpu(query_result.shaper_query.crtcr) &
++                                                      0x1FFF;
++      *token_limit = be16_to_cpu(query_result.shaper_query.crtbl);
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_channel_get_commit_rate);
++
++int qman_ceetm_channel_get_commit_rate_bps(struct qm_ceetm_channel *channel,
++                                         u64 *bps, u16 *token_limit)
++{
++      struct qm_ceetm_rate token_rate;
++      int ret;
++
++      ret = qman_ceetm_channel_get_commit_rate(channel, &token_rate,
++                                               token_limit);
++      if (ret) {
++              pr_err("The channel CR rate or limit is not available\n");
++              return -EINVAL;
++      }
++
++      return qman_ceetm_tokenrate2bps(&token_rate, bps, 0);
++}
++EXPORT_SYMBOL(qman_ceetm_channel_get_commit_rate_bps);
++
++int qman_ceetm_channel_set_excess_rate(struct qm_ceetm_channel *channel,
++                                      const struct qm_ceetm_rate *token_rate,
++                                      u16 token_limit)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
++      struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
++      int ret;
++
++      query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
++                                                      channel->idx);
++      query_opts.dcpid = channel->dcp_idx;
++      ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
++      if (ret) {
++              pr_err("Fail to get the current channel shaper setting\n");
++              return -EINVAL;
++      }
++
++      channel->er_token_rate.whole = token_rate->whole;
++      channel->er_token_rate.fraction = token_rate->fraction;
++      channel->er_token_bucket_limit = token_limit;
++      config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
++                                                      channel->idx);
++      config_opts.dcpid = channel->dcp_idx;
++      config_opts.shaper_config.ertcr = cpu_to_be24(
++                       (token_rate->whole << 13) | (token_rate->fraction));
++      config_opts.shaper_config.ertbl = cpu_to_be16(token_limit);
++      config_opts.shaper_config.cpl = query_result.shaper_query.cpl;
++      config_opts.shaper_config.crtcr = query_result.shaper_query.crtcr;
++      config_opts.shaper_config.crtbl = query_result.shaper_query.crtbl;
++      return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
++}
++EXPORT_SYMBOL(qman_ceetm_channel_set_excess_rate);
++
++int qman_ceetm_channel_set_excess_rate_bps(struct qm_ceetm_channel *channel,
++                                         u64 bps, u16 token_limit)
++{
++      struct qm_ceetm_rate token_rate;
++      int ret;
++
++      ret = qman_ceetm_bps2tokenrate(bps, &token_rate, 0);
++      if (ret) {
++              pr_err("Can not convert bps to token rate\n");
++              return -EINVAL;
++      }
++      return qman_ceetm_channel_set_excess_rate(channel, &token_rate,
++                                                token_limit);
++}
++EXPORT_SYMBOL(qman_ceetm_channel_set_excess_rate_bps);
++
++int qman_ceetm_channel_get_excess_rate(struct qm_ceetm_channel *channel,
++                                      struct qm_ceetm_rate *token_rate,
++                                      u16 *token_limit)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
++      struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
++      int ret;
++
++      query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
++                                                      channel->idx);
++      query_opts.dcpid = channel->dcp_idx;
++      ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
++      if (ret | !query_result.shaper_query.ertcr |
++                       !query_result.shaper_query.ertbl) {
++              pr_err("The channel excess rate or limit is not set\n");
++              return -EINVAL;
++      }
++      token_rate->whole = be24_to_cpu(query_result.shaper_query.ertcr) >> 13;
++      token_rate->fraction = be24_to_cpu(query_result.shaper_query.ertcr) &
++                                                              0x1FFF;
++      *token_limit = be16_to_cpu(query_result.shaper_query.ertbl);
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_channel_get_excess_rate);
++
++int qman_ceetm_channel_get_excess_rate_bps(struct qm_ceetm_channel *channel,
++                                         u64 *bps, u16 *token_limit)
++{
++      struct qm_ceetm_rate token_rate;
++      int ret;
++
++      ret = qman_ceetm_channel_get_excess_rate(channel, &token_rate,
++                                               token_limit);
++      if (ret) {
++              pr_err("The channel ER rate or limit is not available\n");
++              return -EINVAL;
++      }
++
++      return qman_ceetm_tokenrate2bps(&token_rate, bps, 0);
++}
++EXPORT_SYMBOL(qman_ceetm_channel_get_excess_rate_bps);
++
++int qman_ceetm_channel_set_weight(struct qm_ceetm_channel *channel,
++                                              u16 token_limit)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
++
++      if (channel->shaper_enable) {
++              pr_err("This channel is a shaped one\n");
++              return -EINVAL;
++      }
++
++      channel->cr_token_bucket_limit = token_limit;
++      config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
++                                              channel->idx);
++      config_opts.dcpid = channel->dcp_idx;
++      config_opts.shaper_config.crtbl = cpu_to_be16(token_limit);
++      return  qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
++}
++EXPORT_SYMBOL(qman_ceetm_channel_set_weight);
++
++int qman_ceetm_channel_get_weight(struct qm_ceetm_channel *channel,
++                                      u16 *token_limit)
++{
++      struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
++      struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
++      int ret;
++
++      query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
++                                              channel->idx);
++      query_opts.dcpid = channel->dcp_idx;
++      ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
++      if (ret | !query_result.shaper_query.crtbl) {
++              pr_err("This unshaped channel's uFQ wight is unavailable\n");
++              return -EINVAL;
++      }
++      *token_limit = be16_to_cpu(query_result.shaper_query.crtbl);
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_channel_get_weight);
++
++int qman_ceetm_channel_set_group(struct qm_ceetm_channel *channel, int group_b,
++                              unsigned int prio_a, unsigned int prio_b)
++{
++      struct qm_mcc_ceetm_class_scheduler_config config_opts;
++      struct qm_mcr_ceetm_class_scheduler_query query_result;
++      int i;
++
++      if (prio_a > 7) {
++              pr_err("The priority of group A is out of range\n");
++              return -EINVAL;
++      }
++      if (group_b && (prio_b > 7)) {
++              pr_err("The priority of group B is out of range\n");
++              return -EINVAL;
++      }
++
++      if (qman_ceetm_query_class_scheduler(channel, &query_result)) {
++              pr_err("Can't query channel#%d's scheduler!\n", channel->idx);
++              return -EINVAL;
++      }
++
++      config_opts.cqcid = cpu_to_be16(channel->idx);
++      config_opts.dcpid = channel->dcp_idx;
++      config_opts.gpc_combine_flag = !group_b;
++      config_opts.gpc_prio_a = prio_a;
++      config_opts.gpc_prio_b = prio_b;
++
++      for (i = 0; i < 8; i++)
++              config_opts.w[i] = query_result.w[i];
++      config_opts.crem = query_result.crem;
++      config_opts.erem = query_result.erem;
++
++      return qman_ceetm_configure_class_scheduler(&config_opts);
++}
++EXPORT_SYMBOL(qman_ceetm_channel_set_group);
++
++int qman_ceetm_channel_get_group(struct qm_ceetm_channel *channel, int *group_b,
++                              unsigned int *prio_a, unsigned int *prio_b)
++{
++      struct qm_mcr_ceetm_class_scheduler_query query_result;
++
++      if (qman_ceetm_query_class_scheduler(channel, &query_result)) {
++              pr_err("Can't query channel#%d's scheduler!\n", channel->idx);
++              return -EINVAL;
++      }
++      *group_b = !query_result.gpc_combine_flag;
++      *prio_a = query_result.gpc_prio_a;
++      *prio_b = query_result.gpc_prio_b;
++
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_channel_get_group);
++
++#define GROUP_A_ELIGIBILITY_SET               (1 << 8)
++#define GROUP_B_ELIGIBILITY_SET               (1 << 9)
++#define CQ_ELIGIBILITY_SET(n)         (1 << (7 - n))
++int qman_ceetm_channel_set_group_cr_eligibility(struct qm_ceetm_channel
++                              *channel, int group_b, int cre)
++{
++      struct qm_mcc_ceetm_class_scheduler_config csch_config;
++      struct qm_mcr_ceetm_class_scheduler_query csch_query;
++      int i;
++
++      if (qman_ceetm_query_class_scheduler(channel, &csch_query)) {
++              pr_err("Cannot get the channel %d scheduler setting.\n",
++                                              channel->idx);
++              return -EINVAL;
++      }
++      csch_config.cqcid = cpu_to_be16(channel->idx);
++      csch_config.dcpid = channel->dcp_idx;
++      csch_config.gpc_combine_flag = csch_query.gpc_combine_flag;
++      csch_config.gpc_prio_a = csch_query.gpc_prio_a;
++      csch_config.gpc_prio_b = csch_query.gpc_prio_b;
++
++      for (i = 0; i < 8; i++)
++              csch_config.w[i] = csch_query.w[i];
++      csch_config.erem = csch_query.erem;
++      if (group_b)
++              csch_config.crem = (be16_to_cpu(csch_query.crem)
++                                      & ~GROUP_B_ELIGIBILITY_SET)
++                                      | (cre ? GROUP_B_ELIGIBILITY_SET : 0);
++      else
++              csch_config.crem = (be16_to_cpu(csch_query.crem)
++                                      & ~GROUP_A_ELIGIBILITY_SET)
++                                      | (cre ? GROUP_A_ELIGIBILITY_SET : 0);
++
++      csch_config.crem = cpu_to_be16(csch_config.crem);
++
++      if (qman_ceetm_configure_class_scheduler(&csch_config)) {
++              pr_err("Cannot config channel %d's scheduler with "
++                      "group_%c's cr eligibility\n", channel->idx,
++                      group_b ? 'b' : 'a');
++              return -EINVAL;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_channel_set_group_cr_eligibility);
++
++int qman_ceetm_channel_set_group_er_eligibility(struct qm_ceetm_channel
++                              *channel, int group_b, int ere)
++{
++      struct qm_mcc_ceetm_class_scheduler_config csch_config;
++      struct qm_mcr_ceetm_class_scheduler_query csch_query;
++      int i;
++
++      if (qman_ceetm_query_class_scheduler(channel, &csch_query)) {
++              pr_err("Cannot get the channel %d scheduler setting.\n",
++                                              channel->idx);
++              return -EINVAL;
++      }
++      csch_config.cqcid = cpu_to_be16(channel->idx);
++      csch_config.dcpid = channel->dcp_idx;
++      csch_config.gpc_combine_flag = csch_query.gpc_combine_flag;
++      csch_config.gpc_prio_a = csch_query.gpc_prio_a;
++      csch_config.gpc_prio_b = csch_query.gpc_prio_b;
++
++      for (i = 0; i < 8; i++)
++              csch_config.w[i] = csch_query.w[i];
++      csch_config.crem = csch_query.crem;
++      if (group_b)
++              csch_config.erem = (be16_to_cpu(csch_query.erem)
++                                      & ~GROUP_B_ELIGIBILITY_SET)
++                                      | (ere ? GROUP_B_ELIGIBILITY_SET : 0);
++      else
++              csch_config.erem = (be16_to_cpu(csch_query.erem)
++                                      & ~GROUP_A_ELIGIBILITY_SET)
++                                      | (ere ? GROUP_A_ELIGIBILITY_SET : 0);
++
++      csch_config.erem = cpu_to_be16(csch_config.erem);
++
++      if (qman_ceetm_configure_class_scheduler(&csch_config)) {
++              pr_err("Cannot config channel %d's scheduler with "
++                      "group_%c's er eligibility\n", channel->idx,
++                      group_b ? 'b' : 'a');
++              return -EINVAL;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_channel_set_group_er_eligibility);
++
++int qman_ceetm_channel_set_cq_cr_eligibility(struct qm_ceetm_channel *channel,
++                                              unsigned int idx, int cre)
++{
++      struct qm_mcc_ceetm_class_scheduler_config csch_config;
++      struct qm_mcr_ceetm_class_scheduler_query csch_query;
++      int i;
++
++      if (idx > 7) {
++              pr_err("CQ index is out of range\n");
++              return -EINVAL;
++      }
++      if (qman_ceetm_query_class_scheduler(channel, &csch_query)) {
++              pr_err("Cannot get the channel %d scheduler setting.\n",
++                                              channel->idx);
++              return -EINVAL;
++      }
++      csch_config.cqcid = cpu_to_be16(channel->idx);
++      csch_config.dcpid = channel->dcp_idx;
++      csch_config.gpc_combine_flag = csch_query.gpc_combine_flag;
++      csch_config.gpc_prio_a = csch_query.gpc_prio_a;
++      csch_config.gpc_prio_b = csch_query.gpc_prio_b;
++      for (i = 0; i < 8; i++)
++              csch_config.w[i] = csch_query.w[i];
++      csch_config.erem = csch_query.erem;
++      csch_config.crem = (be16_to_cpu(csch_query.crem)
++                                      & ~CQ_ELIGIBILITY_SET(idx)) |
++                                      (cre ? CQ_ELIGIBILITY_SET(idx) : 0);
++      csch_config.crem = cpu_to_be16(csch_config.crem);
++      if (qman_ceetm_configure_class_scheduler(&csch_config)) {
++              pr_err("Cannot config channel scheduler to set "
++                      "cr eligibility mask for CQ#%d\n", idx);
++              return -EINVAL;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_channel_set_cq_cr_eligibility);
++
++int qman_ceetm_channel_set_cq_er_eligibility(struct qm_ceetm_channel *channel,
++                                              unsigned int idx, int ere)
++{
++      struct qm_mcc_ceetm_class_scheduler_config csch_config;
++      struct qm_mcr_ceetm_class_scheduler_query csch_query;
++      int i;
++
++      if (idx > 7) {
++              pr_err("CQ index is out of range\n");
++              return -EINVAL;
++      }
++      if (qman_ceetm_query_class_scheduler(channel, &csch_query)) {
++              pr_err("Cannot get the channel %d scheduler setting.\n",
++                                              channel->idx);
++              return -EINVAL;
++      }
++      csch_config.cqcid = cpu_to_be16(channel->idx);
++      csch_config.dcpid = channel->dcp_idx;
++      csch_config.gpc_combine_flag = csch_query.gpc_combine_flag;
++      csch_config.gpc_prio_a = csch_query.gpc_prio_a;
++      csch_config.gpc_prio_b = csch_query.gpc_prio_b;
++      for (i = 0; i < 8; i++)
++              csch_config.w[i] = csch_query.w[i];
++      csch_config.crem = csch_query.crem;
++      csch_config.erem = (be16_to_cpu(csch_query.erem)
++                                      & ~CQ_ELIGIBILITY_SET(idx)) |
++                                      (ere ? CQ_ELIGIBILITY_SET(idx) : 0);
++      csch_config.erem = cpu_to_be16(csch_config.erem);
++      if (qman_ceetm_configure_class_scheduler(&csch_config)) {
++              pr_err("Cannot config channel scheduler to set "
++                      "er eligibility mask for CQ#%d\n", idx);
++              return -EINVAL;
++      }
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_channel_set_cq_er_eligibility);
++
++int qman_ceetm_cq_claim(struct qm_ceetm_cq **cq,
++              struct qm_ceetm_channel *channel, unsigned int idx,
++              struct qm_ceetm_ccg *ccg)
++{
++      struct qm_ceetm_cq *p;
++      struct qm_mcc_ceetm_cq_config cq_config;
++
++      if (idx > 7) {
++              pr_err("The independent class queue id is out of range\n");
++              return -EINVAL;
++      }
++
++      list_for_each_entry(p, &channel->class_queues, node) {
++              if (p->idx == idx) {
++                      pr_err("The CQ#%d has been claimed!\n", idx);
++                      return -EINVAL;
++              }
++      }
++
++      p = kmalloc(sizeof(*p), GFP_KERNEL);
++      if (!p) {
++              pr_err("Can't allocate memory for CQ#%d!\n", idx);
++              return -ENOMEM;
++      }
++
++      list_add_tail(&p->node, &channel->class_queues);
++      p->idx = idx;
++      p->is_claimed = 1;
++      p->parent = channel;
++      INIT_LIST_HEAD(&p->bound_lfqids);
++
++      if (ccg) {
++              cq_config.cqid = cpu_to_be16((channel->idx << 4) | idx);
++              cq_config.dcpid = channel->dcp_idx;
++              cq_config.ccgid = cpu_to_be16(ccg->idx);
++              if (qman_ceetm_configure_cq(&cq_config)) {
++                      pr_err("Can't configure the CQ#%d with CCGRID#%d\n",
++                                               idx, ccg->idx);
++                      list_del(&p->node);
++                      kfree(p);
++                      return -EINVAL;
++              }
++      }
++
++      *cq = p;
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_cq_claim);
++
++int qman_ceetm_cq_claim_A(struct qm_ceetm_cq **cq,
++              struct qm_ceetm_channel *channel, unsigned int idx,
++              struct qm_ceetm_ccg *ccg)
++{
++      struct qm_ceetm_cq *p;
++      struct qm_mcc_ceetm_cq_config cq_config;
++
++      if ((idx < 8) || (idx > 15)) {
++              pr_err("This grouped class queue id is out of range\n");
++              return -EINVAL;
++      }
++
++      list_for_each_entry(p, &channel->class_queues, node) {
++              if (p->idx == idx) {
++                      pr_err("The CQ#%d has been claimed!\n", idx);
++                      return -EINVAL;
++              }
++      }
++
++      p = kmalloc(sizeof(*p), GFP_KERNEL);
++      if (!p) {
++              pr_err("Can't allocate memory for CQ#%d!\n", idx);
++              return -ENOMEM;
++      }
++
++      list_add_tail(&p->node, &channel->class_queues);
++      p->idx = idx;
++      p->is_claimed = 1;
++      p->parent = channel;
++      INIT_LIST_HEAD(&p->bound_lfqids);
++
++      if (ccg) {
++              cq_config.cqid = cpu_to_be16((channel->idx << 4) | idx);
++              cq_config.dcpid = channel->dcp_idx;
++              cq_config.ccgid = cpu_to_be16(ccg->idx);
++              if (qman_ceetm_configure_cq(&cq_config)) {
++                      pr_err("Can't configure the CQ#%d with CCGRID#%d\n",
++                                               idx, ccg->idx);
++                      list_del(&p->node);
++                      kfree(p);
++                      return -EINVAL;
++              }
++      }
++      *cq = p;
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_cq_claim_A);
++
++int qman_ceetm_cq_claim_B(struct qm_ceetm_cq **cq,
++              struct qm_ceetm_channel *channel, unsigned int idx,
++              struct qm_ceetm_ccg *ccg)
++{
++      struct qm_ceetm_cq *p;
++      struct qm_mcc_ceetm_cq_config cq_config;
++
++      if ((idx < 12) || (idx > 15)) {
++              pr_err("This grouped class queue id is out of range\n");
++              return -EINVAL;
++      }
++
++      list_for_each_entry(p, &channel->class_queues, node) {
++              if (p->idx == idx) {
++                      pr_err("The CQ#%d has been claimed!\n", idx);
++                      return -EINVAL;
++              }
++      }
++
++      p = kmalloc(sizeof(*p), GFP_KERNEL);
++      if (!p) {
++              pr_err("Can't allocate memory for CQ#%d!\n", idx);
++              return -ENOMEM;
++      }
++
++      list_add_tail(&p->node, &channel->class_queues);
++      p->idx = idx;
++      p->is_claimed = 1;
++      p->parent = channel;
++      INIT_LIST_HEAD(&p->bound_lfqids);
++
++      if (ccg) {
++              cq_config.cqid = cpu_to_be16((channel->idx << 4) | idx);
++              cq_config.dcpid = channel->dcp_idx;
++              cq_config.ccgid = cpu_to_be16(ccg->idx);
++              if (qman_ceetm_configure_cq(&cq_config)) {
++                      pr_err("Can't configure the CQ#%d with CCGRID#%d\n",
++                                       idx, ccg->idx);
++                      list_del(&p->node);
++                      kfree(p);
++                      return -EINVAL;
++              }
++      }
++      *cq = p;
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_cq_claim_B);
++
++int qman_ceetm_cq_release(struct qm_ceetm_cq *cq)
++{
++      if (!list_empty(&cq->bound_lfqids)) {
++              pr_err("The CQ#%d has unreleased LFQID\n", cq->idx);
++              return -EBUSY;
++      }
++      list_del(&cq->node);
++      qman_ceetm_drain_cq(cq);
++      kfree(cq);
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_cq_release);
++
++int qman_ceetm_set_queue_weight(struct qm_ceetm_cq *cq,
++                              struct qm_ceetm_weight_code *weight_code)
++{
++      struct qm_mcc_ceetm_class_scheduler_config config_opts;
++      struct qm_mcr_ceetm_class_scheduler_query query_result;
++      int i;
++
++      if (cq->idx < 8) {
++              pr_err("Can not set weight for ungrouped class queue\n");
++              return -EINVAL;
++      }
++
++      if (qman_ceetm_query_class_scheduler(cq->parent, &query_result)) {
++              pr_err("Can't query channel#%d's scheduler!\n",
++                                              cq->parent->idx);
++              return -EINVAL;
++      }
++
++      config_opts.cqcid = cpu_to_be16(cq->parent->idx);
++      config_opts.dcpid = cq->parent->dcp_idx;
++      config_opts.crem = query_result.crem;
++      config_opts.erem = query_result.erem;
++      config_opts.gpc_combine_flag = query_result.gpc_combine_flag;
++      config_opts.gpc_prio_a = query_result.gpc_prio_a;
++      config_opts.gpc_prio_b = query_result.gpc_prio_b;
++
++      for (i = 0; i < 8; i++)
++              config_opts.w[i] = query_result.w[i];
++      config_opts.w[cq->idx - 8] = ((weight_code->y << 3) |
++                                              (weight_code->x & 0x7));
++      return qman_ceetm_configure_class_scheduler(&config_opts);
++}
++EXPORT_SYMBOL(qman_ceetm_set_queue_weight);
++
++int qman_ceetm_get_queue_weight(struct qm_ceetm_cq *cq,
++                              struct qm_ceetm_weight_code *weight_code)
++{
++      struct qm_mcr_ceetm_class_scheduler_query query_result;
++
++      if (cq->idx < 8) {
++              pr_err("Can not get weight for ungrouped class queue\n");
++              return -EINVAL;
++      }
++
++      if (qman_ceetm_query_class_scheduler(cq->parent,
++                                              &query_result)) {
++              pr_err("Can't get the weight code for CQ#%d!\n", cq->idx);
++              return -EINVAL;
++      }
++      weight_code->y = query_result.w[cq->idx - 8] >> 3;
++      weight_code->x = query_result.w[cq->idx - 8] & 0x7;
++
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_get_queue_weight);
++
++/* The WBFS code is represent as {x,y}, the effect wieght can be calculated as:
++ *    effective weight = 2^x / (1 - (y/64))
++ *                     = 2^(x+6) / (64 - y)
++ */
++static void reduce_fraction(u32 *n, u32 *d)
++{
++      u32 factor = 2;
++      u32 lesser = (*n < *d) ? *n : *d;
++      /* If factor exceeds the square-root of the lesser of *n and *d,
++       * then there's no point continuing. Proof: if there was a factor
++       * bigger than the square root, that would imply there exists
++       * another factor smaller than the square-root with which it
++       * multiplies to give 'lesser' - but that's a contradiction
++       * because the other factor would have already been found and
++       * divided out.
++       */
++      while ((factor * factor) <= lesser) {
++              /* If 'factor' is a factor of *n and *d, divide them both
++               * by 'factor' as many times as possible.
++               */
++              while (!(*n % factor) && !(*d % factor)) {
++                      *n /= factor;
++                      *d /= factor;
++                      lesser /= factor;
++              }
++              if (factor == 2)
++                      factor = 3;
++              else
++                      factor += 2;
++      }
++}
++
++int qman_ceetm_wbfs2ratio(struct qm_ceetm_weight_code *weight_code,
++                              u32 *numerator,
++                              u32 *denominator)
++{
++      *numerator = (u32) 1 << (weight_code->x + 6);
++      *denominator = 64 - weight_code->y;
++      reduce_fraction(numerator, denominator);
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_wbfs2ratio);
++
++/* For a given x, the weight is between 2^x (inclusive) and 2^(x+1) (exclusive).
++ * So find 'x' by range, and then estimate 'y' using:
++ *            64 - y  = 2^(x + 6) / weight
++ *                    = 2^(x + 6) / (n/d)
++ *                    = d * 2^(x+6) / n
++ *            y = 64 - (d * 2^(x+6) / n)
++ */
++int qman_ceetm_ratio2wbfs(u32 numerator,
++                              u32 denominator,
++                              struct qm_ceetm_weight_code *weight_code,
++                              int rounding)
++{
++      unsigned int y, x = 0;
++      /* search incrementing 'x' until:
++       * weight < 2^(x+1)
++       *    n/d < 2^(x+1)
++       *      n < d * 2^(x+1)
++       */
++      while ((x < 8) && (numerator >= (denominator << (x + 1))))
++              x++;
++      if (x >= 8)
++              return -ERANGE;
++      /* because of the subtraction, use '-rounding' */
++      y = 64 - ROUNDING(denominator << (x + 6), numerator, -rounding);
++      if (y >= 32)
++              return -ERANGE;
++      weight_code->x = x;
++      weight_code->y = y;
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_ratio2wbfs);
++
++int qman_ceetm_set_queue_weight_in_ratio(struct qm_ceetm_cq *cq, u32 ratio)
++{
++      struct qm_ceetm_weight_code weight_code;
++
++      if (qman_ceetm_ratio2wbfs(ratio, 100, &weight_code, 0)) {
++              pr_err("Cannot get wbfs code for cq %x\n", cq->idx);
++              return -EINVAL;
++      }
++      return qman_ceetm_set_queue_weight(cq, &weight_code);
++}
++EXPORT_SYMBOL(qman_ceetm_set_queue_weight_in_ratio);
++
++int qman_ceetm_get_queue_weight_in_ratio(struct qm_ceetm_cq *cq, u32 *ratio)
++{
++      struct qm_ceetm_weight_code weight_code;
++      u32 n, d;
++
++      if (qman_ceetm_get_queue_weight(cq, &weight_code)) {
++              pr_err("Cannot query the weight code for cq%x\n", cq->idx);
++              return -EINVAL;
++      }
++
++      if (qman_ceetm_wbfs2ratio(&weight_code, &n, &d)) {
++              pr_err("Cannot get the ratio with wbfs code\n");
++              return -EINVAL;
++      }
++
++      *ratio = (n * 100) / d;
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_get_queue_weight_in_ratio);
++
++int qman_ceetm_cq_get_dequeue_statistics(struct qm_ceetm_cq *cq, u32 flags,
++                                      u64 *frame_count, u64 *byte_count)
++{
++      struct qm_mcr_ceetm_statistics_query result;
++      u16 cid, command_type;
++      enum qm_dc_portal dcp_idx;
++      int ret;
++
++      cid = cpu_to_be16((cq->parent->idx << 4) | cq->idx);
++      dcp_idx = cq->parent->dcp_idx;
++      if (flags == QMAN_CEETM_FLAG_CLEAR_STATISTICS_COUNTER)
++              command_type = CEETM_QUERY_DEQUEUE_CLEAR_STATISTICS;
++      else
++              command_type = CEETM_QUERY_DEQUEUE_STATISTICS;
++
++      ret = qman_ceetm_query_statistics(cid, dcp_idx, command_type, &result);
++      if (ret) {
++              pr_err("Can't query the statistics of CQ#%d!\n", cq->idx);
++              return -EINVAL;
++      }
++
++      *frame_count = be40_to_cpu(result.frm_cnt);
++      *byte_count = be48_to_cpu(result.byte_cnt);
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_cq_get_dequeue_statistics);
++
++int qman_ceetm_drain_cq(struct qm_ceetm_cq *cq)
++{
++      struct qm_mcr_ceetm_cq_peek_pop_xsfdrread ppxr;
++      int ret;
++
++      do {
++              ret = qman_ceetm_cq_peek_pop_xsfdrread(cq, 1, 0, &ppxr);
++              if (ret) {
++                      pr_err("Failed to pop frame from CQ\n");
++                      return -EINVAL;
++              }
++      } while (!(ppxr.stat & 0x2));
++
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_drain_cq);
++
++#define CEETM_LFQMT_LFQID_MSB 0xF00000
++#define CEETM_LFQMT_LFQID_LSB 0x000FFF
++int qman_ceetm_lfq_claim(struct qm_ceetm_lfq **lfq,
++                                      struct qm_ceetm_cq *cq)
++{
++      struct qm_ceetm_lfq *p;
++      u32 lfqid;
++      int ret = 0;
++      struct qm_mcc_ceetm_lfqmt_config lfqmt_config;
++
++      if (cq->parent->dcp_idx == qm_dc_portal_fman0) {
++              ret = qman_alloc_ceetm0_lfqid(&lfqid);
++      } else if (cq->parent->dcp_idx == qm_dc_portal_fman1) {
++              ret = qman_alloc_ceetm1_lfqid(&lfqid);
++      } else {
++              pr_err("dcp_idx %u does not correspond to a known fman in this driver\n",
++                      cq->parent->dcp_idx);
++              return -EINVAL;
++      }
++
++      if (ret) {
++              pr_err("There is no lfqid avalaible for CQ#%d!\n", cq->idx);
++              return -ENODEV;
++      }
++      p = kmalloc(sizeof(*p), GFP_KERNEL);
++      if (!p)
++              return -ENOMEM;
++      p->idx = lfqid;
++      p->dctidx = (u16)(lfqid & CEETM_LFQMT_LFQID_LSB);
++      p->parent = cq->parent;
++      list_add_tail(&p->node, &cq->bound_lfqids);
++
++      lfqmt_config.lfqid = cpu_to_be24(CEETM_LFQMT_LFQID_MSB |
++                              (cq->parent->dcp_idx << 16) |
++                              (lfqid & CEETM_LFQMT_LFQID_LSB));
++      lfqmt_config.cqid = cpu_to_be16((cq->parent->idx << 4) | (cq->idx));
++      lfqmt_config.dctidx = cpu_to_be16(p->dctidx);
++      if (qman_ceetm_configure_lfqmt(&lfqmt_config)) {
++              pr_err("Can't configure LFQMT for LFQID#%d @ CQ#%d\n",
++                              lfqid, cq->idx);
++              list_del(&p->node);
++              kfree(p);
++              return -EINVAL;
++      }
++      *lfq = p;
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_lfq_claim);
++
++int qman_ceetm_lfq_release(struct qm_ceetm_lfq *lfq)
++{
++      if (lfq->parent->dcp_idx == qm_dc_portal_fman0) {
++              qman_release_ceetm0_lfqid(lfq->idx);
++      } else if (lfq->parent->dcp_idx == qm_dc_portal_fman1) {
++              qman_release_ceetm1_lfqid(lfq->idx);
++      } else {
++              pr_err("dcp_idx %u does not correspond to a known fman in this driver\n",
++                      lfq->parent->dcp_idx);
++              return -EINVAL;
++      }
++      list_del(&lfq->node);
++      kfree(lfq);
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_lfq_release);
++
++int qman_ceetm_lfq_set_context(struct qm_ceetm_lfq *lfq, u64 context_a,
++                                                      u32 context_b)
++{
++      struct qm_mcc_ceetm_dct_config dct_config;
++      lfq->context_a = context_a;
++      lfq->context_b = context_b;
++      dct_config.dctidx = cpu_to_be16((u16)lfq->dctidx);
++      dct_config.dcpid = lfq->parent->dcp_idx;
++      dct_config.context_b = cpu_to_be32(context_b);
++      dct_config.context_a = cpu_to_be64(context_a);
++
++      return qman_ceetm_configure_dct(&dct_config);
++}
++EXPORT_SYMBOL(qman_ceetm_lfq_set_context);
++
++int qman_ceetm_lfq_get_context(struct qm_ceetm_lfq *lfq, u64 *context_a,
++                                                      u32 *context_b)
++{
++      struct qm_mcc_ceetm_dct_query dct_query;
++      struct qm_mcr_ceetm_dct_query query_result;
++
++      dct_query.dctidx = cpu_to_be16(lfq->dctidx);
++      dct_query.dcpid = lfq->parent->dcp_idx;
++      if (qman_ceetm_query_dct(&dct_query, &query_result)) {
++              pr_err("Can't query LFQID#%d's context!\n", lfq->idx);
++              return -EINVAL;
++      }
++      *context_a = be64_to_cpu(query_result.context_a);
++      *context_b = be32_to_cpu(query_result.context_b);
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_lfq_get_context);
++
++int qman_ceetm_create_fq(struct qm_ceetm_lfq *lfq, struct qman_fq *fq)
++{
++      spin_lock_init(&fq->fqlock);
++      fq->fqid = lfq->idx;
++      fq->flags = QMAN_FQ_FLAG_NO_MODIFY;
++      if (lfq->ern)
++              fq->cb.ern = lfq->ern;
++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
++      if (unlikely(find_empty_fq_table_entry(&fq->key, fq)))
++              return -ENOMEM;
++#endif
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_create_fq);
++
++#define MAX_CCG_IDX 0x000F
++int qman_ceetm_ccg_claim(struct qm_ceetm_ccg **ccg,
++                              struct qm_ceetm_channel *channel,
++                              unsigned int idx,
++                              void (*cscn)(struct qm_ceetm_ccg *,
++                                      void *cb_ctx,
++                                      int congested),
++                              void *cb_ctx)
++{
++      struct qm_ceetm_ccg *p;
++
++      if (idx > MAX_CCG_IDX) {
++              pr_err("The given ccg index is out of range\n");
++              return -EINVAL;
++      }
++
++      list_for_each_entry(p, &channel->ccgs, node) {
++              if (p->idx == idx) {
++                      pr_err("The CCG#%d has been claimed\n", idx);
++                      return -EINVAL;
++              }
++      }
++
++      p = kmalloc(sizeof(*p), GFP_KERNEL);
++      if (!p) {
++              pr_err("Can't allocate memory for CCG#%d!\n", idx);
++              return -ENOMEM;
++      }
++
++      list_add_tail(&p->node, &channel->ccgs);
++
++      p->idx = idx;
++      p->parent = channel;
++      p->cb = cscn;
++      p->cb_ctx = cb_ctx;
++      INIT_LIST_HEAD(&p->cb_node);
++
++      *ccg = p;
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_ccg_claim);
++
++int qman_ceetm_ccg_release(struct qm_ceetm_ccg *ccg)
++{
++      unsigned long irqflags __maybe_unused;
++      struct qm_mcc_ceetm_ccgr_config config_opts;
++      int ret = 0;
++      struct qman_portal *p = get_affine_portal();
++
++      memset(&config_opts, 0, sizeof(struct qm_mcc_ceetm_ccgr_config));
++      spin_lock_irqsave(&p->ccgr_lock, irqflags);
++      if (!list_empty(&ccg->cb_node))
++              list_del(&ccg->cb_node);
++      config_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_CONFIGURE |
++                              (ccg->parent->idx << 4) | ccg->idx);
++      config_opts.dcpid = ccg->parent->dcp_idx;
++      config_opts.we_mask = cpu_to_be16(QM_CCGR_WE_CSCN_TUPD);
++      config_opts.cm_config.cscn_tupd = cpu_to_be16(PORTAL_IDX(p));
++      ret = qman_ceetm_configure_ccgr(&config_opts);
++      spin_unlock_irqrestore(&p->ccgr_lock, irqflags);
++      put_affine_portal();
++
++      list_del(&ccg->node);
++      kfree(ccg);
++      return ret;
++}
++EXPORT_SYMBOL(qman_ceetm_ccg_release);
++
++int qman_ceetm_ccg_set(struct qm_ceetm_ccg *ccg, u16 we_mask,
++                              const struct qm_ceetm_ccg_params *params)
++{
++      struct qm_mcc_ceetm_ccgr_config config_opts;
++      unsigned long irqflags __maybe_unused;
++      int ret;
++      struct qman_portal *p;
++
++      if (((ccg->parent->idx << 4) | ccg->idx) >= (2 * __CGR_NUM))
++              return -EINVAL;
++
++      p = get_affine_portal();
++
++      memset(&config_opts, 0, sizeof(struct qm_mcc_ceetm_ccgr_config));
++      spin_lock_irqsave(&p->ccgr_lock, irqflags);
++
++      config_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_CONFIGURE |
++                              (ccg->parent->idx << 4) | ccg->idx);
++      config_opts.dcpid = ccg->parent->dcp_idx;
++      config_opts.we_mask = we_mask;
++      if (we_mask & QM_CCGR_WE_CSCN_EN) {
++              config_opts.we_mask |= QM_CCGR_WE_CSCN_TUPD;
++              config_opts.cm_config.cscn_tupd = cpu_to_be16(
++                      QM_CGR_TARG_UDP_CTRL_WRITE_BIT | PORTAL_IDX(p));
++      }
++      config_opts.we_mask = cpu_to_be16(config_opts.we_mask);
++      config_opts.cm_config.ctl_wr_en_g = params->wr_en_g;
++      config_opts.cm_config.ctl_wr_en_y = params->wr_en_y;
++      config_opts.cm_config.ctl_wr_en_r = params->wr_en_r;
++      config_opts.cm_config.ctl_td_en = params->td_en;
++      config_opts.cm_config.ctl_td_mode = params->td_mode;
++      config_opts.cm_config.ctl_cscn_en = params->cscn_en;
++      config_opts.cm_config.ctl_mode = params->mode;
++      config_opts.cm_config.oal = params->oal;
++      config_opts.cm_config.cs_thres.hword =
++                                      cpu_to_be16(params->cs_thres_in.hword);
++      config_opts.cm_config.cs_thres_x.hword =
++                                      cpu_to_be16(params->cs_thres_out.hword);
++      config_opts.cm_config.td_thres.hword =
++                                      cpu_to_be16(params->td_thres.hword);
++      config_opts.cm_config.wr_parm_g.word =
++                                      cpu_to_be32(params->wr_parm_g.word);
++      config_opts.cm_config.wr_parm_y.word =
++                                      cpu_to_be32(params->wr_parm_y.word);
++      config_opts.cm_config.wr_parm_r.word =
++                                      cpu_to_be32(params->wr_parm_r.word);
++      ret = qman_ceetm_configure_ccgr(&config_opts);
++      if (ret) {
++              pr_err("Configure CCGR CM failed!\n");
++              goto release_lock;
++      }
++
++      if (we_mask & QM_CCGR_WE_CSCN_EN)
++              if (list_empty(&ccg->cb_node))
++                      list_add(&ccg->cb_node,
++                              &p->ccgr_cbs[ccg->parent->dcp_idx]);
++release_lock:
++      spin_unlock_irqrestore(&p->ccgr_lock, irqflags);
++      put_affine_portal();
++      return ret;
++}
++EXPORT_SYMBOL(qman_ceetm_ccg_set);
++
++#define CEETM_CCGR_CTL_MASK 0x01
++int qman_ceetm_ccg_get(struct qm_ceetm_ccg *ccg,
++                              struct qm_ceetm_ccg_params *params)
++{
++      struct qm_mcc_ceetm_ccgr_query query_opts;
++      struct qm_mcr_ceetm_ccgr_query query_result;
++
++      query_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_QUERY |
++                              (ccg->parent->idx << 4) | ccg->idx);
++      query_opts.dcpid = ccg->parent->dcp_idx;
++
++      if (qman_ceetm_query_ccgr(&query_opts, &query_result)) {
++              pr_err("Can't query CCGR#%d\n", ccg->idx);
++              return -EINVAL;
++      }
++
++      params->wr_parm_r.word = query_result.cm_query.wr_parm_r.word;
++      params->wr_parm_y.word = query_result.cm_query.wr_parm_y.word;
++      params->wr_parm_g.word = query_result.cm_query.wr_parm_g.word;
++      params->td_thres.hword = query_result.cm_query.td_thres.hword;
++      params->cs_thres_out.hword = query_result.cm_query.cs_thres_x.hword;
++      params->cs_thres_in.hword = query_result.cm_query.cs_thres.hword;
++      params->oal = query_result.cm_query.oal;
++      params->wr_en_g = query_result.cm_query.ctl_wr_en_g;
++      params->wr_en_y = query_result.cm_query.ctl_wr_en_y;
++      params->wr_en_r = query_result.cm_query.ctl_wr_en_r;
++      params->td_en = query_result.cm_query.ctl_td_en;
++      params->td_mode = query_result.cm_query.ctl_td_mode;
++      params->cscn_en = query_result.cm_query.ctl_cscn_en;
++      params->mode = query_result.cm_query.ctl_mode;
++
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_ccg_get);
++
++int qman_ceetm_ccg_get_reject_statistics(struct qm_ceetm_ccg *ccg, u32 flags,
++                                      u64 *frame_count, u64 *byte_count)
++{
++      struct qm_mcr_ceetm_statistics_query result;
++      u16 cid, command_type;
++      enum qm_dc_portal dcp_idx;
++      int ret;
++
++      cid = cpu_to_be16((ccg->parent->idx << 4) | ccg->idx);
++      dcp_idx = ccg->parent->dcp_idx;
++      if (flags == QMAN_CEETM_FLAG_CLEAR_STATISTICS_COUNTER)
++              command_type = CEETM_QUERY_REJECT_CLEAR_STATISTICS;
++      else
++              command_type = CEETM_QUERY_REJECT_STATISTICS;
++
++      ret = qman_ceetm_query_statistics(cid, dcp_idx, command_type, &result);
++      if (ret) {
++              pr_err("Can't query the statistics of CCG#%d!\n", ccg->idx);
++              return -EINVAL;
++      }
++
++      *frame_count = be40_to_cpu(result.frm_cnt);
++      *byte_count = be48_to_cpu(result.byte_cnt);
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_ccg_get_reject_statistics);
++
++int qman_ceetm_cscn_swp_get(struct qm_ceetm_ccg *ccg,
++                                      u16 swp_idx,
++                                      unsigned int *cscn_enabled)
++{
++      struct qm_mcc_ceetm_ccgr_query query_opts;
++      struct qm_mcr_ceetm_ccgr_query query_result;
++      int i;
++
++      DPA_ASSERT(swp_idx < 127);
++      query_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_QUERY |
++                              (ccg->parent->idx << 4) | ccg->idx);
++      query_opts.dcpid = ccg->parent->dcp_idx;
++
++      if (qman_ceetm_query_ccgr(&query_opts, &query_result)) {
++              pr_err("Can't query CCGR#%d\n", ccg->idx);
++              return -EINVAL;
++      }
++
++      i = swp_idx / 32;
++      i = 3 - i;
++      *cscn_enabled = query_result.cm_query.cscn_targ_swp[i] >>
++                                                      (31 - swp_idx % 32);
++
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_cscn_swp_get);
++
++int qman_ceetm_cscn_dcp_set(struct qm_ceetm_ccg *ccg,
++                              u16 dcp_idx,
++                              u8 vcgid,
++                              unsigned int cscn_enabled,
++                              u16 we_mask,
++                              const struct qm_ceetm_ccg_params *params)
++{
++      struct qm_mcc_ceetm_ccgr_config config_opts;
++      int ret;
++
++      config_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_CONFIGURE |
++                              (ccg->parent->idx << 4) | ccg->idx);
++      config_opts.dcpid = ccg->parent->dcp_idx;
++      config_opts.we_mask = cpu_to_be16(we_mask | QM_CCGR_WE_CSCN_TUPD |
++                                               QM_CCGR_WE_CDV);
++      config_opts.cm_config.cdv = vcgid;
++      config_opts.cm_config.cscn_tupd = cpu_to_be16((cscn_enabled << 15) |
++                                      QM_CGR_TARG_UDP_CTRL_DCP | dcp_idx);
++      config_opts.cm_config.ctl_wr_en_g = params->wr_en_g;
++      config_opts.cm_config.ctl_wr_en_y = params->wr_en_y;
++      config_opts.cm_config.ctl_wr_en_r = params->wr_en_r;
++      config_opts.cm_config.ctl_td_en = params->td_en;
++      config_opts.cm_config.ctl_td_mode = params->td_mode;
++      config_opts.cm_config.ctl_cscn_en = params->cscn_en;
++      config_opts.cm_config.ctl_mode = params->mode;
++      config_opts.cm_config.cs_thres.hword =
++                                      cpu_to_be16(params->cs_thres_in.hword);
++      config_opts.cm_config.cs_thres_x.hword =
++                                      cpu_to_be16(params->cs_thres_out.hword);
++      config_opts.cm_config.td_thres.hword =
++                                      cpu_to_be16(params->td_thres.hword);
++      config_opts.cm_config.wr_parm_g.word =
++                                      cpu_to_be32(params->wr_parm_g.word);
++      config_opts.cm_config.wr_parm_y.word =
++                                      cpu_to_be32(params->wr_parm_y.word);
++      config_opts.cm_config.wr_parm_r.word =
++                                      cpu_to_be32(params->wr_parm_r.word);
++
++      ret = qman_ceetm_configure_ccgr(&config_opts);
++      if (ret) {
++              pr_err("Configure CSCN_TARG_DCP failed!\n");
++              return -EINVAL;
++      }
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_cscn_dcp_set);
++
++int qman_ceetm_cscn_dcp_get(struct qm_ceetm_ccg *ccg,
++                              u16 dcp_idx,
++                              u8 *vcgid,
++                              unsigned int *cscn_enabled)
++{
++      struct qm_mcc_ceetm_ccgr_query query_opts;
++      struct qm_mcr_ceetm_ccgr_query query_result;
++
++      query_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_QUERY |
++                              (ccg->parent->idx << 4) | ccg->idx);
++      query_opts.dcpid = ccg->parent->dcp_idx;
++
++      if (qman_ceetm_query_ccgr(&query_opts, &query_result)) {
++              pr_err("Can't query CCGR#%d\n", ccg->idx);
++              return -EINVAL;
++      }
++
++      *vcgid = query_result.cm_query.cdv;
++      *cscn_enabled = (query_result.cm_query.cscn_targ_dcp >> dcp_idx) & 0x1;
++      return 0;
++}
++EXPORT_SYMBOL(qman_ceetm_cscn_dcp_get);
++
++int qman_ceetm_querycongestion(struct __qm_mcr_querycongestion *ccg_state,
++                                                      unsigned int dcp_idx)
++{
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      u8 res;
++      int i, j;
++
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++
++      mcc = qm_mc_start(&p->p);
++      for (i = 0; i < 2; i++) {
++              mcc->ccgr_query.ccgrid =
++                              cpu_to_be16(CEETM_QUERY_CONGESTION_STATE | i);
++              mcc->ccgr_query.dcpid = dcp_idx;
++              qm_mc_commit(&p->p, QM_CEETM_VERB_CCGR_QUERY);
++
++              while (!(mcr = qm_mc_result(&p->p)))
++                      cpu_relax();
++              DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
++                                              QM_CEETM_VERB_CCGR_QUERY);
++              res = mcr->result;
++              if (res == QM_MCR_RESULT_OK) {
++                      for (j = 0; j < 8; j++)
++                              mcr->ccgr_query.congestion_state.state.
++                              __state[j] = be32_to_cpu(mcr->ccgr_query.
++                                      congestion_state.state.__state[j]);
++                      *(ccg_state + i) =
++                              mcr->ccgr_query.congestion_state.state;
++              } else {
++                      pr_err("QUERY CEETM CONGESTION STATE failed\n");
++                      PORTAL_IRQ_UNLOCK(p, irqflags);
++                      return -EIO;
++              }
++      }
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      return 0;
++}
++
++int qman_set_wpm(int wpm_enable)
++{
++      return qm_set_wpm(wpm_enable);
++}
++EXPORT_SYMBOL(qman_set_wpm);
++
++int qman_get_wpm(int *wpm_enable)
++{
++      return qm_get_wpm(wpm_enable);
++}
++EXPORT_SYMBOL(qman_get_wpm);
++
++int qman_shutdown_fq(u32 fqid)
++{
++      struct qman_portal *p;
++      unsigned long irqflags __maybe_unused;
++      int ret;
++      struct qm_portal *low_p;
++      p = get_affine_portal();
++      PORTAL_IRQ_LOCK(p, irqflags);
++      low_p = &p->p;
++      ret = qm_shutdown_fq(&low_p, 1, fqid);
++      PORTAL_IRQ_UNLOCK(p, irqflags);
++      put_affine_portal();
++      return ret;
++}
++
++const struct qm_portal_config *qman_get_qm_portal_config(
++                                              struct qman_portal *portal)
++{
++      return portal->sharing_redirect ? NULL : portal->config;
++}
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/qman_low.h
+@@ -0,0 +1,1427 @@
++/* Copyright 2008-2011 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "qman_private.h"
++
++/***************************/
++/* Portal register assists */
++/***************************/
++
++/* Cache-inhibited register offsets */
++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
++
++#define QM_REG_EQCR_PI_CINH   0x0000
++#define QM_REG_EQCR_CI_CINH   0x0004
++#define QM_REG_EQCR_ITR               0x0008
++#define QM_REG_DQRR_PI_CINH   0x0040
++#define QM_REG_DQRR_CI_CINH   0x0044
++#define QM_REG_DQRR_ITR               0x0048
++#define QM_REG_DQRR_DCAP      0x0050
++#define QM_REG_DQRR_SDQCR     0x0054
++#define QM_REG_DQRR_VDQCR     0x0058
++#define QM_REG_DQRR_PDQCR     0x005c
++#define QM_REG_MR_PI_CINH     0x0080
++#define QM_REG_MR_CI_CINH     0x0084
++#define QM_REG_MR_ITR         0x0088
++#define QM_REG_CFG            0x0100
++#define QM_REG_ISR            0x0e00
++#define QM_REG_IIR              0x0e0c
++#define QM_REG_ITPR           0x0e14
++
++/* Cache-enabled register offsets */
++#define QM_CL_EQCR            0x0000
++#define QM_CL_DQRR            0x1000
++#define QM_CL_MR              0x2000
++#define QM_CL_EQCR_PI_CENA    0x3000
++#define QM_CL_EQCR_CI_CENA    0x3100
++#define QM_CL_DQRR_PI_CENA    0x3200
++#define QM_CL_DQRR_CI_CENA    0x3300
++#define QM_CL_MR_PI_CENA      0x3400
++#define QM_CL_MR_CI_CENA      0x3500
++#define QM_CL_CR              0x3800
++#define QM_CL_RR0             0x3900
++#define QM_CL_RR1             0x3940
++
++#endif
++
++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++
++#define QM_REG_EQCR_PI_CINH   0x3000
++#define QM_REG_EQCR_CI_CINH   0x3040
++#define QM_REG_EQCR_ITR               0x3080
++#define QM_REG_DQRR_PI_CINH   0x3100
++#define QM_REG_DQRR_CI_CINH   0x3140
++#define QM_REG_DQRR_ITR               0x3180
++#define QM_REG_DQRR_DCAP      0x31C0
++#define QM_REG_DQRR_SDQCR     0x3200
++#define QM_REG_DQRR_VDQCR     0x3240
++#define QM_REG_DQRR_PDQCR     0x3280
++#define QM_REG_MR_PI_CINH     0x3300
++#define QM_REG_MR_CI_CINH     0x3340
++#define QM_REG_MR_ITR         0x3380
++#define QM_REG_CFG            0x3500
++#define QM_REG_ISR            0x3600
++#define QM_REG_IIR              0x36C0
++#define QM_REG_ITPR           0x3740
++
++/* Cache-enabled register offsets */
++#define QM_CL_EQCR            0x0000
++#define QM_CL_DQRR            0x1000
++#define QM_CL_MR              0x2000
++#define QM_CL_EQCR_PI_CENA    0x3000
++#define QM_CL_EQCR_CI_CENA    0x3040
++#define QM_CL_DQRR_PI_CENA    0x3100
++#define QM_CL_DQRR_CI_CENA    0x3140
++#define QM_CL_MR_PI_CENA      0x3300
++#define QM_CL_MR_CI_CENA      0x3340
++#define QM_CL_CR              0x3800
++#define QM_CL_RR0             0x3900
++#define QM_CL_RR1             0x3940
++
++#endif
++
++
++/* BTW, the drivers (and h/w programming model) already obtain the required
++ * synchronisation for portal accesses via lwsync(), hwsync(), and
++ * data-dependencies. Use of barrier()s or other order-preserving primitives
++ * simply degrade performance. Hence the use of the __raw_*() interfaces, which
++ * simply ensure that the compiler treats the portal registers as volatile (ie.
++ * non-coherent). */
++
++/* Cache-inhibited register access. */
++#define __qm_in(qm, o)                be32_to_cpu(__raw_readl((qm)->addr_ci  + (o)))
++#define __qm_out(qm, o, val)  __raw_writel((cpu_to_be32(val)), \
++                                           (qm)->addr_ci + (o));
++#define qm_in(reg)            __qm_in(&portal->addr, QM_REG_##reg)
++#define qm_out(reg, val)      __qm_out(&portal->addr, QM_REG_##reg, val)
++
++/* Cache-enabled (index) register access */
++#define __qm_cl_touch_ro(qm, o) dcbt_ro((qm)->addr_ce + (o))
++#define __qm_cl_touch_rw(qm, o) dcbt_rw((qm)->addr_ce + (o))
++#define __qm_cl_in(qm, o)     be32_to_cpu(__raw_readl((qm)->addr_ce + (o)))
++#define __qm_cl_out(qm, o, val) \
++      do { \
++              u32 *__tmpclout = (qm)->addr_ce + (o); \
++              __raw_writel(cpu_to_be32(val), __tmpclout); \
++              dcbf(__tmpclout); \
++      } while (0)
++#define __qm_cl_invalidate(qm, o) dcbi((qm)->addr_ce + (o))
++#define qm_cl_touch_ro(reg) __qm_cl_touch_ro(&portal->addr, QM_CL_##reg##_CENA)
++#define qm_cl_touch_rw(reg) __qm_cl_touch_rw(&portal->addr, QM_CL_##reg##_CENA)
++#define qm_cl_in(reg)     __qm_cl_in(&portal->addr, QM_CL_##reg##_CENA)
++#define qm_cl_out(reg, val) __qm_cl_out(&portal->addr, QM_CL_##reg##_CENA, val)
++#define qm_cl_invalidate(reg)\
++      __qm_cl_invalidate(&portal->addr, QM_CL_##reg##_CENA)
++
++/* Cache-enabled ring access */
++#define qm_cl(base, idx)      ((void *)base + ((idx) << 6))
++
++/* Cyclic helper for rings. FIXME: once we are able to do fine-grain perf
++ * analysis, look at using the "extra" bit in the ring index registers to avoid
++ * cyclic issues. */
++static inline u8 qm_cyc_diff(u8 ringsize, u8 first, u8 last)
++{
++      /* 'first' is included, 'last' is excluded */
++      if (first <= last)
++              return last - first;
++      return ringsize + last - first;
++}
++
++/* Portal modes.
++ *   Enum types;
++ *     pmode == production mode
++ *     cmode == consumption mode,
++ *     dmode == h/w dequeue mode.
++ *   Enum values use 3 letter codes. First letter matches the portal mode,
++ *   remaining two letters indicate;
++ *     ci == cache-inhibited portal register
++ *     ce == cache-enabled portal register
++ *     vb == in-band valid-bit (cache-enabled)
++ *     dc == DCA (Discrete Consumption Acknowledgement), DQRR-only
++ *   As for "enum qm_dqrr_dmode", it should be self-explanatory.
++ */
++enum qm_eqcr_pmode {          /* matches QCSP_CFG::EPM */
++      qm_eqcr_pci = 0,        /* PI index, cache-inhibited */
++      qm_eqcr_pce = 1,        /* PI index, cache-enabled */
++      qm_eqcr_pvb = 2         /* valid-bit */
++};
++enum qm_dqrr_dmode {          /* matches QCSP_CFG::DP */
++      qm_dqrr_dpush = 0,      /* SDQCR  + VDQCR */
++      qm_dqrr_dpull = 1       /* PDQCR */
++};
++enum qm_dqrr_pmode {          /* s/w-only */
++      qm_dqrr_pci,            /* reads DQRR_PI_CINH */
++      qm_dqrr_pce,            /* reads DQRR_PI_CENA */
++      qm_dqrr_pvb             /* reads valid-bit */
++};
++enum qm_dqrr_cmode {          /* matches QCSP_CFG::DCM */
++      qm_dqrr_cci = 0,        /* CI index, cache-inhibited */
++      qm_dqrr_cce = 1,        /* CI index, cache-enabled */
++      qm_dqrr_cdc = 2         /* Discrete Consumption Acknowledgement */
++};
++enum qm_mr_pmode {            /* s/w-only */
++      qm_mr_pci,              /* reads MR_PI_CINH */
++      qm_mr_pce,              /* reads MR_PI_CENA */
++      qm_mr_pvb               /* reads valid-bit */
++};
++enum qm_mr_cmode {            /* matches QCSP_CFG::MM */
++      qm_mr_cci = 0,          /* CI index, cache-inhibited */
++      qm_mr_cce = 1           /* CI index, cache-enabled */
++};
++
++
++/* ------------------------- */
++/* --- Portal structures --- */
++
++#define QM_EQCR_SIZE          8
++#define QM_DQRR_SIZE          16
++#define QM_MR_SIZE            8
++
++struct qm_eqcr {
++      struct qm_eqcr_entry *ring, *cursor;
++      u8 ci, available, ithresh, vbit;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      u32 busy;
++      enum qm_eqcr_pmode pmode;
++#endif
++};
++
++struct qm_dqrr {
++      const struct qm_dqrr_entry *ring, *cursor;
++      u8 pi, ci, fill, ithresh, vbit;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      enum qm_dqrr_dmode dmode;
++      enum qm_dqrr_pmode pmode;
++      enum qm_dqrr_cmode cmode;
++#endif
++};
++
++struct qm_mr {
++      const struct qm_mr_entry *ring, *cursor;
++      u8 pi, ci, fill, ithresh, vbit;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      enum qm_mr_pmode pmode;
++      enum qm_mr_cmode cmode;
++#endif
++};
++
++struct qm_mc {
++      struct qm_mc_command *cr;
++      struct qm_mc_result *rr;
++      u8 rridx, vbit;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      enum {
++              /* Can be _mc_start()ed */
++              qman_mc_idle,
++              /* Can be _mc_commit()ed or _mc_abort()ed */
++              qman_mc_user,
++              /* Can only be _mc_retry()ed */
++              qman_mc_hw
++      } state;
++#endif
++};
++
++#define QM_PORTAL_ALIGNMENT ____cacheline_aligned
++
++struct qm_addr {
++      void __iomem *addr_ce;  /* cache-enabled */
++      void __iomem *addr_ci;  /* cache-inhibited */
++};
++
++struct qm_portal {
++      /* In the non-CONFIG_FSL_DPA_CHECKING case, the following stuff up to
++       * and including 'mc' fits within a cacheline (yay!). The 'config' part
++       * is setup-only, so isn't a cause for a concern. In other words, don't
++       * rearrange this structure on a whim, there be dragons ... */
++      struct qm_addr addr;
++      struct qm_eqcr eqcr;
++      struct qm_dqrr dqrr;
++      struct qm_mr mr;
++      struct qm_mc mc;
++} QM_PORTAL_ALIGNMENT;
++
++
++/* ---------------- */
++/* --- EQCR API --- */
++
++/* Bit-wise logic to wrap a ring pointer by clearing the "carry bit" */
++#define EQCR_CARRYCLEAR(p) \
++      (void *)((unsigned long)(p) & (~(unsigned long)(QM_EQCR_SIZE << 6)))
++
++/* Bit-wise logic to convert a ring pointer to a ring index */
++static inline u8 EQCR_PTR2IDX(struct qm_eqcr_entry *e)
++{
++      return ((uintptr_t)e >> 6) & (QM_EQCR_SIZE - 1);
++}
++
++/* Increment the 'cursor' ring pointer, taking 'vbit' into account */
++static inline void EQCR_INC(struct qm_eqcr *eqcr)
++{
++      /* NB: this is odd-looking, but experiments show that it generates fast
++       * code with essentially no branching overheads. We increment to the
++       * next EQCR pointer and handle overflow and 'vbit'. */
++      struct qm_eqcr_entry *partial = eqcr->cursor + 1;
++      eqcr->cursor = EQCR_CARRYCLEAR(partial);
++      if (partial != eqcr->cursor)
++              eqcr->vbit ^= QM_EQCR_VERB_VBIT;
++}
++
++static inline int qm_eqcr_init(struct qm_portal *portal,
++                              enum qm_eqcr_pmode pmode,
++                              unsigned int eq_stash_thresh,
++                              int eq_stash_prio)
++{
++      /* This use of 'register', as well as all other occurrences, is because
++       * it has been observed to generate much faster code with gcc than is
++       * otherwise the case. */
++      register struct qm_eqcr *eqcr = &portal->eqcr;
++      u32 cfg;
++      u8 pi;
++
++      eqcr->ring = portal->addr.addr_ce + QM_CL_EQCR;
++      eqcr->ci = qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1);
++      qm_cl_invalidate(EQCR_CI);
++      pi = qm_in(EQCR_PI_CINH) & (QM_EQCR_SIZE - 1);
++      eqcr->cursor = eqcr->ring + pi;
++      eqcr->vbit = (qm_in(EQCR_PI_CINH) & QM_EQCR_SIZE) ?
++                      QM_EQCR_VERB_VBIT : 0;
++      eqcr->available = QM_EQCR_SIZE - 1 -
++                      qm_cyc_diff(QM_EQCR_SIZE, eqcr->ci, pi);
++      eqcr->ithresh = qm_in(EQCR_ITR);
++#ifdef CONFIG_FSL_DPA_CHECKING
++      eqcr->busy = 0;
++      eqcr->pmode = pmode;
++#endif
++      cfg = (qm_in(CFG) & 0x00ffffff) |
++              (eq_stash_thresh << 28) | /* QCSP_CFG: EST */
++              (eq_stash_prio << 26)   | /* QCSP_CFG: EP */
++              ((pmode & 0x3) << 24);  /* QCSP_CFG::EPM */
++      qm_out(CFG, cfg);
++      return 0;
++}
++
++static inline unsigned int qm_eqcr_get_ci_stashing(struct qm_portal *portal)
++{
++      return (qm_in(CFG) >> 28) & 0x7;
++}
++
++static inline void qm_eqcr_finish(struct qm_portal *portal)
++{
++      register struct qm_eqcr *eqcr = &portal->eqcr;
++      u8 pi, ci;
++      u32 cfg;
++
++      /*
++       * Disable EQCI stashing because the QMan only
++       * presents the value it previously stashed to
++       * maintain coherency.  Setting the stash threshold
++       * to 1 then 0 ensures that QMan has resyncronized
++       * its internal copy so that the portal is clean
++       * when it is reinitialized in the future
++       */
++      cfg = (qm_in(CFG) & 0x0fffffff) |
++              (1 << 28); /* QCSP_CFG: EST */
++      qm_out(CFG, cfg);
++      cfg &= 0x0fffffff; /* stash threshold = 0 */
++      qm_out(CFG, cfg);
++
++      pi = qm_in(EQCR_PI_CINH) & (QM_EQCR_SIZE - 1);
++      ci = qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1);
++
++      /* Refresh EQCR CI cache value */
++      qm_cl_invalidate(EQCR_CI);
++      eqcr->ci = qm_cl_in(EQCR_CI) & (QM_EQCR_SIZE - 1);
++
++      DPA_ASSERT(!eqcr->busy);
++      if (pi != EQCR_PTR2IDX(eqcr->cursor))
++              pr_crit("losing uncommited EQCR entries\n");
++      if (ci != eqcr->ci)
++              pr_crit("missing existing EQCR completions\n");
++      if (eqcr->ci != EQCR_PTR2IDX(eqcr->cursor))
++              pr_crit("EQCR destroyed unquiesced\n");
++}
++
++static inline struct qm_eqcr_entry *qm_eqcr_start_no_stash(struct qm_portal
++                                                               *portal)
++{
++      register struct qm_eqcr *eqcr = &portal->eqcr;
++      DPA_ASSERT(!eqcr->busy);
++      if (!eqcr->available)
++              return NULL;
++
++
++#ifdef CONFIG_FSL_DPA_CHECKING
++      eqcr->busy = 1;
++#endif
++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
++      dcbz_64(eqcr->cursor);
++#endif
++      return eqcr->cursor;
++}
++
++static inline struct qm_eqcr_entry *qm_eqcr_start_stash(struct qm_portal
++                                                              *portal)
++{
++      register struct qm_eqcr *eqcr = &portal->eqcr;
++      u8 diff, old_ci;
++
++      DPA_ASSERT(!eqcr->busy);
++      if (!eqcr->available) {
++              old_ci = eqcr->ci;
++              eqcr->ci = qm_cl_in(EQCR_CI) & (QM_EQCR_SIZE - 1);
++              diff = qm_cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci);
++              eqcr->available += diff;
++              if (!diff)
++                      return NULL;
++      }
++#ifdef CONFIG_FSL_DPA_CHECKING
++      eqcr->busy = 1;
++#endif
++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
++      dcbz_64(eqcr->cursor);
++#endif
++      return eqcr->cursor;
++}
++
++static inline void qm_eqcr_abort(struct qm_portal *portal)
++{
++      __maybe_unused register struct qm_eqcr *eqcr = &portal->eqcr;
++      DPA_ASSERT(eqcr->busy);
++#ifdef CONFIG_FSL_DPA_CHECKING
++      eqcr->busy = 0;
++#endif
++}
++
++static inline struct qm_eqcr_entry *qm_eqcr_pend_and_next(
++                                      struct qm_portal *portal, u8 myverb)
++{
++      register struct qm_eqcr *eqcr = &portal->eqcr;
++      DPA_ASSERT(eqcr->busy);
++      DPA_ASSERT(eqcr->pmode != qm_eqcr_pvb);
++      if (eqcr->available == 1)
++              return NULL;
++      eqcr->cursor->__dont_write_directly__verb = myverb | eqcr->vbit;
++      dcbf(eqcr->cursor);
++      EQCR_INC(eqcr);
++      eqcr->available--;
++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
++      dcbz_64(eqcr->cursor);
++#endif
++      return eqcr->cursor;
++}
++
++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
++#define EQCR_COMMIT_CHECKS(eqcr) \
++do { \
++      DPA_ASSERT(eqcr->busy); \
++      DPA_ASSERT(eqcr->cursor->orp == (eqcr->cursor->orp & 0xffffff00)); \
++      DPA_ASSERT(eqcr->cursor->fqid == (eqcr->cursor->fqid & 0xffffff00)); \
++} while (0)
++#else
++#define EQCR_COMMIT_CHECKS(eqcr) \
++do { \
++      DPA_ASSERT(eqcr->busy); \
++      DPA_ASSERT(eqcr->cursor->orp == (eqcr->cursor->orp & \
++                                      cpu_to_be32(0x00ffffff))); \
++      DPA_ASSERT(eqcr->cursor->fqid == (eqcr->cursor->fqid & \
++                                      cpu_to_be32(0x00ffffff))); \
++} while (0)
++#endif
++
++static inline void qm_eqcr_pci_commit(struct qm_portal *portal, u8 myverb)
++{
++      register struct qm_eqcr *eqcr = &portal->eqcr;
++      EQCR_COMMIT_CHECKS(eqcr);
++      DPA_ASSERT(eqcr->pmode == qm_eqcr_pci);
++      eqcr->cursor->__dont_write_directly__verb = myverb | eqcr->vbit;
++      EQCR_INC(eqcr);
++      eqcr->available--;
++      dcbf(eqcr->cursor);
++      hwsync();
++      qm_out(EQCR_PI_CINH, EQCR_PTR2IDX(eqcr->cursor));
++#ifdef CONFIG_FSL_DPA_CHECKING
++      eqcr->busy = 0;
++#endif
++}
++
++static inline void qm_eqcr_pce_prefetch(struct qm_portal *portal)
++{
++      __maybe_unused register struct qm_eqcr *eqcr = &portal->eqcr;
++      DPA_ASSERT(eqcr->pmode == qm_eqcr_pce);
++      qm_cl_invalidate(EQCR_PI);
++      qm_cl_touch_rw(EQCR_PI);
++}
++
++static inline void qm_eqcr_pce_commit(struct qm_portal *portal, u8 myverb)
++{
++      register struct qm_eqcr *eqcr = &portal->eqcr;
++      EQCR_COMMIT_CHECKS(eqcr);
++      DPA_ASSERT(eqcr->pmode == qm_eqcr_pce);
++      eqcr->cursor->__dont_write_directly__verb = myverb | eqcr->vbit;
++      EQCR_INC(eqcr);
++      eqcr->available--;
++      dcbf(eqcr->cursor);
++      lwsync();
++      qm_cl_out(EQCR_PI, EQCR_PTR2IDX(eqcr->cursor));
++#ifdef CONFIG_FSL_DPA_CHECKING
++      eqcr->busy = 0;
++#endif
++}
++
++static inline void qm_eqcr_pvb_commit(struct qm_portal *portal, u8 myverb)
++{
++      register struct qm_eqcr *eqcr = &portal->eqcr;
++      struct qm_eqcr_entry *eqcursor;
++      EQCR_COMMIT_CHECKS(eqcr);
++      DPA_ASSERT(eqcr->pmode == qm_eqcr_pvb);
++      lwsync();
++      eqcursor = eqcr->cursor;
++      eqcursor->__dont_write_directly__verb = myverb | eqcr->vbit;
++      dcbf(eqcursor);
++      EQCR_INC(eqcr);
++      eqcr->available--;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      eqcr->busy = 0;
++#endif
++}
++
++static inline u8 qm_eqcr_cci_update(struct qm_portal *portal)
++{
++      register struct qm_eqcr *eqcr = &portal->eqcr;
++      u8 diff, old_ci = eqcr->ci;
++      eqcr->ci = qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1);
++      diff = qm_cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci);
++      eqcr->available += diff;
++      return diff;
++}
++
++static inline void qm_eqcr_cce_prefetch(struct qm_portal *portal)
++{
++      __maybe_unused register struct qm_eqcr *eqcr = &portal->eqcr;
++      qm_cl_touch_ro(EQCR_CI);
++}
++
++static inline u8 qm_eqcr_cce_update(struct qm_portal *portal)
++{
++      register struct qm_eqcr *eqcr = &portal->eqcr;
++      u8 diff, old_ci = eqcr->ci;
++      eqcr->ci = qm_cl_in(EQCR_CI) & (QM_EQCR_SIZE - 1);
++      qm_cl_invalidate(EQCR_CI);
++      diff = qm_cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci);
++      eqcr->available += diff;
++      return diff;
++}
++
++static inline u8 qm_eqcr_get_ithresh(struct qm_portal *portal)
++{
++      register struct qm_eqcr *eqcr = &portal->eqcr;
++      return eqcr->ithresh;
++}
++
++static inline void qm_eqcr_set_ithresh(struct qm_portal *portal, u8 ithresh)
++{
++      register struct qm_eqcr *eqcr = &portal->eqcr;
++      eqcr->ithresh = ithresh;
++      qm_out(EQCR_ITR, ithresh);
++}
++
++static inline u8 qm_eqcr_get_avail(struct qm_portal *portal)
++{
++      register struct qm_eqcr *eqcr = &portal->eqcr;
++      return eqcr->available;
++}
++
++static inline u8 qm_eqcr_get_fill(struct qm_portal *portal)
++{
++      register struct qm_eqcr *eqcr = &portal->eqcr;
++      return QM_EQCR_SIZE - 1 - eqcr->available;
++}
++
++
++/* ---------------- */
++/* --- DQRR API --- */
++
++/* FIXME: many possible improvements;
++ * - look at changing the API to use pointer rather than index parameters now
++ *   that 'cursor' is a pointer,
++ * - consider moving other parameters to pointer if it could help (ci)
++ */
++
++#define DQRR_CARRYCLEAR(p) \
++      (void *)((unsigned long)(p) & (~(unsigned long)(QM_DQRR_SIZE << 6)))
++
++static inline u8 DQRR_PTR2IDX(const struct qm_dqrr_entry *e)
++{
++      return ((uintptr_t)e >> 6) & (QM_DQRR_SIZE - 1);
++}
++
++static inline const struct qm_dqrr_entry *DQRR_INC(
++                                              const struct qm_dqrr_entry *e)
++{
++      return DQRR_CARRYCLEAR(e + 1);
++}
++
++static inline void qm_dqrr_set_maxfill(struct qm_portal *portal, u8 mf)
++{
++      qm_out(CFG, (qm_in(CFG) & 0xff0fffff) |
++              ((mf & (QM_DQRR_SIZE - 1)) << 20));
++}
++
++static inline void qm_dqrr_cci_consume(struct qm_portal *portal, u8 num)
++{
++      register struct qm_dqrr *dqrr = &portal->dqrr;
++      DPA_ASSERT(dqrr->cmode == qm_dqrr_cci);
++      dqrr->ci = (dqrr->ci + num) & (QM_DQRR_SIZE - 1);
++      qm_out(DQRR_CI_CINH, dqrr->ci);
++}
++
++static inline void qm_dqrr_cce_consume(struct qm_portal *portal, u8 num)
++{
++      register struct qm_dqrr *dqrr = &portal->dqrr;
++      DPA_ASSERT(dqrr->cmode == qm_dqrr_cce);
++      dqrr->ci = (dqrr->ci + num) & (QM_DQRR_SIZE - 1);
++      qm_cl_out(DQRR_CI, dqrr->ci);
++}
++
++static inline void qm_dqrr_cdc_consume_n(struct qm_portal *portal, u16 bitmask)
++{
++      __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
++      DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc);
++      qm_out(DQRR_DCAP, (1 << 8) |            /* DQRR_DCAP::S */
++              ((u32)bitmask << 16));          /* DQRR_DCAP::DCAP_CI */
++      dqrr->ci = qm_in(DQRR_CI_CINH) & (QM_DQRR_SIZE - 1);
++      dqrr->fill = qm_cyc_diff(QM_DQRR_SIZE, dqrr->ci, dqrr->pi);
++}
++
++static inline int qm_dqrr_init(struct qm_portal *portal,
++                              const struct qm_portal_config *config,
++                              enum qm_dqrr_dmode dmode,
++                              __maybe_unused enum qm_dqrr_pmode pmode,
++                              enum qm_dqrr_cmode cmode, u8 max_fill)
++{
++      register struct qm_dqrr *dqrr = &portal->dqrr;
++      u32 cfg;
++
++      /* Make sure the DQRR will be idle when we enable */
++      qm_out(DQRR_SDQCR, 0);
++      qm_out(DQRR_VDQCR, 0);
++      qm_out(DQRR_PDQCR, 0);
++      dqrr->ring = portal->addr.addr_ce + QM_CL_DQRR;
++      dqrr->pi = qm_in(DQRR_PI_CINH) & (QM_DQRR_SIZE - 1);
++      dqrr->ci = qm_in(DQRR_CI_CINH) & (QM_DQRR_SIZE - 1);
++      dqrr->cursor = dqrr->ring + dqrr->ci;
++      dqrr->fill = qm_cyc_diff(QM_DQRR_SIZE, dqrr->ci, dqrr->pi);
++      dqrr->vbit = (qm_in(DQRR_PI_CINH) & QM_DQRR_SIZE) ?
++                      QM_DQRR_VERB_VBIT : 0;
++      dqrr->ithresh = qm_in(DQRR_ITR);
++
++      /* Free up pending DQRR entries if any as per current DCM */
++      if (dqrr->fill) {
++              enum qm_dqrr_cmode dcm = (qm_in(CFG) >> 16) & 3;
++
++#ifdef CONFIG_FSL_DPA_CHECKING
++              dqrr->cmode = dcm;
++#endif
++              switch (dcm) {
++              case qm_dqrr_cci:
++                      qm_dqrr_cci_consume(portal, dqrr->fill);
++                      break;
++              case qm_dqrr_cce:
++                      qm_dqrr_cce_consume(portal, dqrr->fill);
++                      break;
++              case qm_dqrr_cdc:
++                      qm_dqrr_cdc_consume_n(portal, (QM_DQRR_SIZE - 1));
++                      break;
++              default:
++                      DPA_ASSERT(0);
++              }
++      }
++
++#ifdef CONFIG_FSL_DPA_CHECKING
++      dqrr->dmode = dmode;
++      dqrr->pmode = pmode;
++      dqrr->cmode = cmode;
++#endif
++      /* Invalidate every ring entry before beginning */
++      for (cfg = 0; cfg < QM_DQRR_SIZE; cfg++)
++              dcbi(qm_cl(dqrr->ring, cfg));
++      cfg = (qm_in(CFG) & 0xff000f00) |
++              ((max_fill & (QM_DQRR_SIZE - 1)) << 20) | /* DQRR_MF */
++              ((dmode & 1) << 18) |                   /* DP */
++              ((cmode & 3) << 16) |                   /* DCM */
++              0xa0 |                                  /* RE+SE */
++              (0 ? 0x40 : 0) |                        /* Ignore RP */
++              (0 ? 0x10 : 0);                         /* Ignore SP */
++      qm_out(CFG, cfg);
++      qm_dqrr_set_maxfill(portal, max_fill);
++      return 0;
++}
++
++static inline void qm_dqrr_finish(struct qm_portal *portal)
++{
++      __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      if ((dqrr->cmode != qm_dqrr_cdc) &&
++                      (dqrr->ci != DQRR_PTR2IDX(dqrr->cursor)))
++              pr_crit("Ignoring completed DQRR entries\n");
++#endif
++}
++
++static inline const struct qm_dqrr_entry *qm_dqrr_current(
++                                              struct qm_portal *portal)
++{
++      register struct qm_dqrr *dqrr = &portal->dqrr;
++      if (!dqrr->fill)
++              return NULL;
++      return dqrr->cursor;
++}
++
++static inline u8 qm_dqrr_cursor(struct qm_portal *portal)
++{
++      register struct qm_dqrr *dqrr = &portal->dqrr;
++      return DQRR_PTR2IDX(dqrr->cursor);
++}
++
++static inline u8 qm_dqrr_next(struct qm_portal *portal)
++{
++      register struct qm_dqrr *dqrr = &portal->dqrr;
++      DPA_ASSERT(dqrr->fill);
++      dqrr->cursor = DQRR_INC(dqrr->cursor);
++      return --dqrr->fill;
++}
++
++static inline u8 qm_dqrr_pci_update(struct qm_portal *portal)
++{
++      register struct qm_dqrr *dqrr = &portal->dqrr;
++      u8 diff, old_pi = dqrr->pi;
++      DPA_ASSERT(dqrr->pmode == qm_dqrr_pci);
++      dqrr->pi = qm_in(DQRR_PI_CINH) & (QM_DQRR_SIZE - 1);
++      diff = qm_cyc_diff(QM_DQRR_SIZE, old_pi, dqrr->pi);
++      dqrr->fill += diff;
++      return diff;
++}
++
++static inline void qm_dqrr_pce_prefetch(struct qm_portal *portal)
++{
++      __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
++      DPA_ASSERT(dqrr->pmode == qm_dqrr_pce);
++      qm_cl_invalidate(DQRR_PI);
++      qm_cl_touch_ro(DQRR_PI);
++}
++
++static inline u8 qm_dqrr_pce_update(struct qm_portal *portal)
++{
++      register struct qm_dqrr *dqrr = &portal->dqrr;
++      u8 diff, old_pi = dqrr->pi;
++      DPA_ASSERT(dqrr->pmode == qm_dqrr_pce);
++      dqrr->pi = qm_cl_in(DQRR_PI) & (QM_DQRR_SIZE - 1);
++      diff = qm_cyc_diff(QM_DQRR_SIZE, old_pi, dqrr->pi);
++      dqrr->fill += diff;
++      return diff;
++}
++
++static inline void qm_dqrr_pvb_update(struct qm_portal *portal)
++{
++      register struct qm_dqrr *dqrr = &portal->dqrr;
++      const struct qm_dqrr_entry *res = qm_cl(dqrr->ring, dqrr->pi);
++      DPA_ASSERT(dqrr->pmode == qm_dqrr_pvb);
++#if (defined CONFIG_PPC || defined CONFIG_PPC64) && !defined CONFIG_FSL_PAMU
++      /*
++       * On PowerPC platforms if PAMU is not available we need to
++       * manually invalidate the cache. When PAMU is available the
++       * cache is updated by stashing operations generated by QMan
++       */
++      dcbi(res);
++      dcbt_ro(res);
++#endif
++
++      /* when accessing 'verb', use __raw_readb() to ensure that compiler
++       * inlining doesn't try to optimise out "excess reads". */
++      if ((__raw_readb(&res->verb) & QM_DQRR_VERB_VBIT) == dqrr->vbit) {
++              dqrr->pi = (dqrr->pi + 1) & (QM_DQRR_SIZE - 1);
++              if (!dqrr->pi)
++                      dqrr->vbit ^= QM_DQRR_VERB_VBIT;
++              dqrr->fill++;
++      }
++}
++
++
++static inline void qm_dqrr_cci_consume_to_current(struct qm_portal *portal)
++{
++      register struct qm_dqrr *dqrr = &portal->dqrr;
++      DPA_ASSERT(dqrr->cmode == qm_dqrr_cci);
++      dqrr->ci = DQRR_PTR2IDX(dqrr->cursor);
++      qm_out(DQRR_CI_CINH, dqrr->ci);
++}
++
++static inline void qm_dqrr_cce_prefetch(struct qm_portal *portal)
++{
++      __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
++      DPA_ASSERT(dqrr->cmode == qm_dqrr_cce);
++      qm_cl_invalidate(DQRR_CI);
++      qm_cl_touch_rw(DQRR_CI);
++}
++
++static inline void qm_dqrr_cce_consume_to_current(struct qm_portal *portal)
++{
++      register struct qm_dqrr *dqrr = &portal->dqrr;
++      DPA_ASSERT(dqrr->cmode == qm_dqrr_cce);
++      dqrr->ci = DQRR_PTR2IDX(dqrr->cursor);
++      qm_cl_out(DQRR_CI, dqrr->ci);
++}
++
++static inline void qm_dqrr_cdc_consume_1(struct qm_portal *portal, u8 idx,
++                                      int park)
++{
++      __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
++      DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc);
++      DPA_ASSERT(idx < QM_DQRR_SIZE);
++      qm_out(DQRR_DCAP, (0 << 8) |    /* S */
++              ((park ? 1 : 0) << 6) | /* PK */
++              idx);                   /* DCAP_CI */
++}
++
++static inline void qm_dqrr_cdc_consume_1ptr(struct qm_portal *portal,
++                                      const struct qm_dqrr_entry *dq,
++                                      int park)
++{
++      __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
++      u8 idx = DQRR_PTR2IDX(dq);
++      DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc);
++      DPA_ASSERT((dqrr->ring + idx) == dq);
++      DPA_ASSERT(idx < QM_DQRR_SIZE);
++      qm_out(DQRR_DCAP, (0 << 8) |            /* DQRR_DCAP::S */
++              ((park ? 1 : 0) << 6) |         /* DQRR_DCAP::PK */
++              idx);                           /* DQRR_DCAP::DCAP_CI */
++}
++
++static inline u8 qm_dqrr_cdc_cci(struct qm_portal *portal)
++{
++      __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
++      DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc);
++      return qm_in(DQRR_CI_CINH) & (QM_DQRR_SIZE - 1);
++}
++
++static inline void qm_dqrr_cdc_cce_prefetch(struct qm_portal *portal)
++{
++      __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
++      DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc);
++      qm_cl_invalidate(DQRR_CI);
++      qm_cl_touch_ro(DQRR_CI);
++}
++
++static inline u8 qm_dqrr_cdc_cce(struct qm_portal *portal)
++{
++      __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
++      DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc);
++      return qm_cl_in(DQRR_CI) & (QM_DQRR_SIZE - 1);
++}
++
++static inline u8 qm_dqrr_get_ci(struct qm_portal *portal)
++{
++      register struct qm_dqrr *dqrr = &portal->dqrr;
++      DPA_ASSERT(dqrr->cmode != qm_dqrr_cdc);
++      return dqrr->ci;
++}
++
++static inline void qm_dqrr_park(struct qm_portal *portal, u8 idx)
++{
++      __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
++      DPA_ASSERT(dqrr->cmode != qm_dqrr_cdc);
++      qm_out(DQRR_DCAP, (0 << 8) |            /* S */
++              (1 << 6) |                      /* PK */
++              (idx & (QM_DQRR_SIZE - 1)));    /* DCAP_CI */
++}
++
++static inline void qm_dqrr_park_current(struct qm_portal *portal)
++{
++      register struct qm_dqrr *dqrr = &portal->dqrr;
++      DPA_ASSERT(dqrr->cmode != qm_dqrr_cdc);
++      qm_out(DQRR_DCAP, (0 << 8) |            /* S */
++              (1 << 6) |                      /* PK */
++              DQRR_PTR2IDX(dqrr->cursor));    /* DCAP_CI */
++}
++
++static inline void qm_dqrr_sdqcr_set(struct qm_portal *portal, u32 sdqcr)
++{
++      qm_out(DQRR_SDQCR, sdqcr);
++}
++
++static inline u32 qm_dqrr_sdqcr_get(struct qm_portal *portal)
++{
++      return qm_in(DQRR_SDQCR);
++}
++
++static inline void qm_dqrr_vdqcr_set(struct qm_portal *portal, u32 vdqcr)
++{
++      qm_out(DQRR_VDQCR, vdqcr);
++}
++
++static inline u32 qm_dqrr_vdqcr_get(struct qm_portal *portal)
++{
++      return qm_in(DQRR_VDQCR);
++}
++
++static inline void qm_dqrr_pdqcr_set(struct qm_portal *portal, u32 pdqcr)
++{
++      qm_out(DQRR_PDQCR, pdqcr);
++}
++
++static inline u32 qm_dqrr_pdqcr_get(struct qm_portal *portal)
++{
++      return qm_in(DQRR_PDQCR);
++}
++
++static inline u8 qm_dqrr_get_ithresh(struct qm_portal *portal)
++{
++      register struct qm_dqrr *dqrr = &portal->dqrr;
++      return dqrr->ithresh;
++}
++
++static inline void qm_dqrr_set_ithresh(struct qm_portal *portal, u8 ithresh)
++{
++      qm_out(DQRR_ITR, ithresh);
++}
++
++static inline u8 qm_dqrr_get_maxfill(struct qm_portal *portal)
++{
++      return (qm_in(CFG) & 0x00f00000) >> 20;
++}
++
++
++/* -------------- */
++/* --- MR API --- */
++
++#define MR_CARRYCLEAR(p) \
++      (void *)((unsigned long)(p) & (~(unsigned long)(QM_MR_SIZE << 6)))
++
++static inline u8 MR_PTR2IDX(const struct qm_mr_entry *e)
++{
++      return ((uintptr_t)e >> 6) & (QM_MR_SIZE - 1);
++}
++
++static inline const struct qm_mr_entry *MR_INC(const struct qm_mr_entry *e)
++{
++      return MR_CARRYCLEAR(e + 1);
++}
++
++static inline int qm_mr_init(struct qm_portal *portal, enum qm_mr_pmode pmode,
++              enum qm_mr_cmode cmode)
++{
++      register struct qm_mr *mr = &portal->mr;
++      u32 cfg;
++
++      mr->ring = portal->addr.addr_ce + QM_CL_MR;
++      mr->pi = qm_in(MR_PI_CINH) & (QM_MR_SIZE - 1);
++      mr->ci = qm_in(MR_CI_CINH) & (QM_MR_SIZE - 1);
++      mr->cursor = mr->ring + mr->ci;
++      mr->fill = qm_cyc_diff(QM_MR_SIZE, mr->ci, mr->pi);
++      mr->vbit = (qm_in(MR_PI_CINH) & QM_MR_SIZE) ? QM_MR_VERB_VBIT : 0;
++      mr->ithresh = qm_in(MR_ITR);
++#ifdef CONFIG_FSL_DPA_CHECKING
++      mr->pmode = pmode;
++      mr->cmode = cmode;
++#endif
++      cfg = (qm_in(CFG) & 0xfffff0ff) |
++              ((cmode & 1) << 8);             /* QCSP_CFG:MM */
++      qm_out(CFG, cfg);
++      return 0;
++}
++
++static inline void qm_mr_finish(struct qm_portal *portal)
++{
++      register struct qm_mr *mr = &portal->mr;
++      if (mr->ci != MR_PTR2IDX(mr->cursor))
++              pr_crit("Ignoring completed MR entries\n");
++}
++
++static inline const struct qm_mr_entry *qm_mr_current(struct qm_portal *portal)
++{
++      register struct qm_mr *mr = &portal->mr;
++      if (!mr->fill)
++              return NULL;
++      return mr->cursor;
++}
++
++static inline u8 qm_mr_cursor(struct qm_portal *portal)
++{
++      register struct qm_mr *mr = &portal->mr;
++      return MR_PTR2IDX(mr->cursor);
++}
++
++static inline u8 qm_mr_next(struct qm_portal *portal)
++{
++      register struct qm_mr *mr = &portal->mr;
++      DPA_ASSERT(mr->fill);
++      mr->cursor = MR_INC(mr->cursor);
++      return --mr->fill;
++}
++
++static inline u8 qm_mr_pci_update(struct qm_portal *portal)
++{
++      register struct qm_mr *mr = &portal->mr;
++      u8 diff, old_pi = mr->pi;
++      DPA_ASSERT(mr->pmode == qm_mr_pci);
++      mr->pi = qm_in(MR_PI_CINH);
++      diff = qm_cyc_diff(QM_MR_SIZE, old_pi, mr->pi);
++      mr->fill += diff;
++      return diff;
++}
++
++static inline void qm_mr_pce_prefetch(struct qm_portal *portal)
++{
++      __maybe_unused register struct qm_mr *mr = &portal->mr;
++      DPA_ASSERT(mr->pmode == qm_mr_pce);
++      qm_cl_invalidate(MR_PI);
++      qm_cl_touch_ro(MR_PI);
++}
++
++static inline u8 qm_mr_pce_update(struct qm_portal *portal)
++{
++      register struct qm_mr *mr = &portal->mr;
++      u8 diff, old_pi = mr->pi;
++      DPA_ASSERT(mr->pmode == qm_mr_pce);
++      mr->pi = qm_cl_in(MR_PI) & (QM_MR_SIZE - 1);
++      diff = qm_cyc_diff(QM_MR_SIZE, old_pi, mr->pi);
++      mr->fill += diff;
++      return diff;
++}
++
++static inline void qm_mr_pvb_update(struct qm_portal *portal)
++{
++      register struct qm_mr *mr = &portal->mr;
++      const struct qm_mr_entry *res = qm_cl(mr->ring, mr->pi);
++      DPA_ASSERT(mr->pmode == qm_mr_pvb);
++      /* when accessing 'verb', use __raw_readb() to ensure that compiler
++       * inlining doesn't try to optimise out "excess reads". */
++      if ((__raw_readb(&res->verb) & QM_MR_VERB_VBIT) == mr->vbit) {
++              mr->pi = (mr->pi + 1) & (QM_MR_SIZE - 1);
++              if (!mr->pi)
++                      mr->vbit ^= QM_MR_VERB_VBIT;
++              mr->fill++;
++              res = MR_INC(res);
++      }
++      dcbit_ro(res);
++}
++
++static inline void qm_mr_cci_consume(struct qm_portal *portal, u8 num)
++{
++      register struct qm_mr *mr = &portal->mr;
++      DPA_ASSERT(mr->cmode == qm_mr_cci);
++      mr->ci = (mr->ci + num) & (QM_MR_SIZE - 1);
++      qm_out(MR_CI_CINH, mr->ci);
++}
++
++static inline void qm_mr_cci_consume_to_current(struct qm_portal *portal)
++{
++      register struct qm_mr *mr = &portal->mr;
++      DPA_ASSERT(mr->cmode == qm_mr_cci);
++      mr->ci = MR_PTR2IDX(mr->cursor);
++      qm_out(MR_CI_CINH, mr->ci);
++}
++
++static inline void qm_mr_cce_prefetch(struct qm_portal *portal)
++{
++      __maybe_unused register struct qm_mr *mr = &portal->mr;
++      DPA_ASSERT(mr->cmode == qm_mr_cce);
++      qm_cl_invalidate(MR_CI);
++      qm_cl_touch_rw(MR_CI);
++}
++
++static inline void qm_mr_cce_consume(struct qm_portal *portal, u8 num)
++{
++      register struct qm_mr *mr = &portal->mr;
++      DPA_ASSERT(mr->cmode == qm_mr_cce);
++      mr->ci = (mr->ci + num) & (QM_MR_SIZE - 1);
++      qm_cl_out(MR_CI, mr->ci);
++}
++
++static inline void qm_mr_cce_consume_to_current(struct qm_portal *portal)
++{
++      register struct qm_mr *mr = &portal->mr;
++      DPA_ASSERT(mr->cmode == qm_mr_cce);
++      mr->ci = MR_PTR2IDX(mr->cursor);
++      qm_cl_out(MR_CI, mr->ci);
++}
++
++static inline u8 qm_mr_get_ci(struct qm_portal *portal)
++{
++      register struct qm_mr *mr = &portal->mr;
++      return mr->ci;
++}
++
++static inline u8 qm_mr_get_ithresh(struct qm_portal *portal)
++{
++      register struct qm_mr *mr = &portal->mr;
++      return mr->ithresh;
++}
++
++static inline void qm_mr_set_ithresh(struct qm_portal *portal, u8 ithresh)
++{
++      qm_out(MR_ITR, ithresh);
++}
++
++
++/* ------------------------------ */
++/* --- Management command API --- */
++
++static inline int qm_mc_init(struct qm_portal *portal)
++{
++      register struct qm_mc *mc = &portal->mc;
++      mc->cr = portal->addr.addr_ce + QM_CL_CR;
++      mc->rr = portal->addr.addr_ce + QM_CL_RR0;
++      mc->rridx = (__raw_readb(&mc->cr->__dont_write_directly__verb) &
++                      QM_MCC_VERB_VBIT) ?  0 : 1;
++      mc->vbit = mc->rridx ? QM_MCC_VERB_VBIT : 0;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      mc->state = qman_mc_idle;
++#endif
++      return 0;
++}
++
++static inline void qm_mc_finish(struct qm_portal *portal)
++{
++      __maybe_unused register struct qm_mc *mc = &portal->mc;
++      DPA_ASSERT(mc->state == qman_mc_idle);
++#ifdef CONFIG_FSL_DPA_CHECKING
++      if (mc->state != qman_mc_idle)
++              pr_crit("Losing incomplete MC command\n");
++#endif
++}
++
++static inline struct qm_mc_command *qm_mc_start(struct qm_portal *portal)
++{
++      register struct qm_mc *mc = &portal->mc;
++      DPA_ASSERT(mc->state == qman_mc_idle);
++#ifdef CONFIG_FSL_DPA_CHECKING
++      mc->state = qman_mc_user;
++#endif
++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
++      dcbz_64(mc->cr);
++#endif
++      return mc->cr;
++}
++
++static inline void qm_mc_abort(struct qm_portal *portal)
++{
++      __maybe_unused register struct qm_mc *mc = &portal->mc;
++      DPA_ASSERT(mc->state == qman_mc_user);
++#ifdef CONFIG_FSL_DPA_CHECKING
++      mc->state = qman_mc_idle;
++#endif
++}
++
++static inline void qm_mc_commit(struct qm_portal *portal, u8 myverb)
++{
++      register struct qm_mc *mc = &portal->mc;
++      struct qm_mc_result *rr = mc->rr + mc->rridx;
++      DPA_ASSERT(mc->state == qman_mc_user);
++      lwsync();
++      mc->cr->__dont_write_directly__verb = myverb | mc->vbit;
++      dcbf(mc->cr);
++      dcbit_ro(rr);
++#ifdef CONFIG_FSL_DPA_CHECKING
++      mc->state = qman_mc_hw;
++#endif
++}
++
++static inline struct qm_mc_result *qm_mc_result(struct qm_portal *portal)
++{
++      register struct qm_mc *mc = &portal->mc;
++      struct qm_mc_result *rr = mc->rr + mc->rridx;
++      DPA_ASSERT(mc->state == qman_mc_hw);
++      /* The inactive response register's verb byte always returns zero until
++       * its command is submitted and completed. This includes the valid-bit,
++       * in case you were wondering... */
++      if (!__raw_readb(&rr->verb)) {
++              dcbit_ro(rr);
++              return NULL;
++      }
++      mc->rridx ^= 1;
++      mc->vbit ^= QM_MCC_VERB_VBIT;
++#ifdef CONFIG_FSL_DPA_CHECKING
++      mc->state = qman_mc_idle;
++#endif
++      return rr;
++}
++
++
++/* ------------------------------------- */
++/* --- Portal interrupt register API --- */
++
++static inline int qm_isr_init(__always_unused struct qm_portal *portal)
++{
++      return 0;
++}
++
++static inline void qm_isr_finish(__always_unused struct qm_portal *portal)
++{
++}
++
++static inline void qm_isr_set_iperiod(struct qm_portal *portal, u16 iperiod)
++{
++      qm_out(ITPR, iperiod);
++}
++
++static inline u32 __qm_isr_read(struct qm_portal *portal, enum qm_isr_reg n)
++{
++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++      return __qm_in(&portal->addr, QM_REG_ISR + (n << 6));
++#else
++      return __qm_in(&portal->addr, QM_REG_ISR + (n << 2));
++#endif
++}
++
++static inline void __qm_isr_write(struct qm_portal *portal, enum qm_isr_reg n,
++                                      u32 val)
++{
++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++      __qm_out(&portal->addr, QM_REG_ISR + (n << 6), val);
++#else
++      __qm_out(&portal->addr, QM_REG_ISR + (n << 2), val);
++#endif
++}
++
++/* Cleanup FQs */
++static inline int qm_shutdown_fq(struct qm_portal **portal, int portal_count,
++                               u32 fqid)
++{
++
++      struct qm_mc_command *mcc;
++      struct qm_mc_result *mcr;
++      u8 state;
++      int orl_empty, fq_empty, i, drain = 0;
++      u32 result;
++      u32 channel, wq;
++      u16 dest_wq;
++
++      /* Determine the state of the FQID */
++      mcc = qm_mc_start(portal[0]);
++      mcc->queryfq_np.fqid = cpu_to_be32(fqid);
++      qm_mc_commit(portal[0], QM_MCC_VERB_QUERYFQ_NP);
++      while (!(mcr = qm_mc_result(portal[0])))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ_NP);
++      state = mcr->queryfq_np.state & QM_MCR_NP_STATE_MASK;
++      if (state == QM_MCR_NP_STATE_OOS)
++              return 0; /* Already OOS, no need to do anymore checks */
++
++      /* Query which channel the FQ is using */
++      mcc = qm_mc_start(portal[0]);
++      mcc->queryfq.fqid = cpu_to_be32(fqid);
++      qm_mc_commit(portal[0], QM_MCC_VERB_QUERYFQ);
++      while (!(mcr = qm_mc_result(portal[0])))
++              cpu_relax();
++      DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ);
++
++      /* Need to store these since the MCR gets reused */
++      dest_wq = be16_to_cpu(mcr->queryfq.fqd.dest_wq);
++      wq = dest_wq & 0x7;
++      channel = dest_wq>>3;
++
++      switch (state) {
++      case QM_MCR_NP_STATE_TEN_SCHED:
++      case QM_MCR_NP_STATE_TRU_SCHED:
++      case QM_MCR_NP_STATE_ACTIVE:
++      case QM_MCR_NP_STATE_PARKED:
++              orl_empty = 0;
++              mcc = qm_mc_start(portal[0]);
++              mcc->alterfq.fqid = cpu_to_be32(fqid);
++              qm_mc_commit(portal[0], QM_MCC_VERB_ALTER_RETIRE);
++              while (!(mcr = qm_mc_result(portal[0])))
++                      cpu_relax();
++              DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
++                         QM_MCR_VERB_ALTER_RETIRE);
++              result = mcr->result; /* Make a copy as we reuse MCR below */
++
++              if (result == QM_MCR_RESULT_PENDING) {
++                      /* Need to wait for the FQRN in the message ring, which
++                         will only occur once the FQ has been drained.  In
++                         order for the FQ to drain the portal needs to be set
++                         to dequeue from the channel the FQ is scheduled on */
++                      const struct qm_mr_entry *msg;
++                      const struct qm_dqrr_entry *dqrr = NULL;
++                      int found_fqrn = 0;
++                      u16 dequeue_wq = 0;
++
++                      /* Flag that we need to drain FQ */
++                      drain = 1;
++
++                      if (channel >= qm_channel_pool1 &&
++                          channel < (qm_channel_pool1 + 15)) {
++                              /* Pool channel, enable the bit in the portal */
++                              dequeue_wq = (channel -
++                                            qm_channel_pool1 + 1)<<4 | wq;
++                      } else if (channel < qm_channel_pool1) {
++                              /* Dedicated channel */
++                              dequeue_wq = wq;
++                      } else {
++                              pr_info("Cannot recover FQ 0x%x, it is "
++                                      "scheduled on channel 0x%x",
++                                      fqid, channel);
++                              return -EBUSY;
++                      }
++                      /* Set the sdqcr to drain this channel */
++                      if (channel < qm_channel_pool1)
++                              for (i = 0; i < portal_count; i++)
++                                      qm_dqrr_sdqcr_set(portal[i],
++                                                QM_SDQCR_TYPE_ACTIVE |
++                                                QM_SDQCR_CHANNELS_DEDICATED);
++                      else
++                              for (i = 0; i < portal_count; i++)
++                                      qm_dqrr_sdqcr_set(
++                                              portal[i],
++                                              QM_SDQCR_TYPE_ACTIVE |
++                                              QM_SDQCR_CHANNELS_POOL_CONV
++                                              (channel));
++                      while (!found_fqrn) {
++                              /* Keep draining DQRR while checking the MR*/
++                              for (i = 0; i < portal_count; i++) {
++                                      qm_dqrr_pvb_update(portal[i]);
++                                      dqrr = qm_dqrr_current(portal[i]);
++                                      while (dqrr) {
++                                              qm_dqrr_cdc_consume_1ptr(
++                                                      portal[i], dqrr, 0);
++                                              qm_dqrr_pvb_update(portal[i]);
++                                              qm_dqrr_next(portal[i]);
++                                              dqrr = qm_dqrr_current(
++                                                      portal[i]);
++                                      }
++                                      /* Process message ring too */
++                                      qm_mr_pvb_update(portal[i]);
++                                      msg = qm_mr_current(portal[i]);
++                                      while (msg) {
++                                              if ((msg->verb &
++                                                   QM_MR_VERB_TYPE_MASK)
++                                                  == QM_MR_VERB_FQRN)
++                                                      found_fqrn = 1;
++                                              qm_mr_next(portal[i]);
++                                              qm_mr_cci_consume_to_current(
++                                                      portal[i]);
++                                              qm_mr_pvb_update(portal[i]);
++                                              msg = qm_mr_current(portal[i]);
++                                      }
++                                      cpu_relax();
++                              }
++                      }
++              }
++              if (result != QM_MCR_RESULT_OK &&
++                  result !=  QM_MCR_RESULT_PENDING) {
++                      /* error */
++                      pr_err("qman_retire_fq failed on FQ 0x%x, result=0x%x\n",
++                             fqid, result);
++                      return -1;
++              }
++              if (!(mcr->alterfq.fqs & QM_MCR_FQS_ORLPRESENT)) {
++                      /* ORL had no entries, no need to wait until the
++                         ERNs come in */
++                      orl_empty = 1;
++              }
++              /* Retirement succeeded, check to see if FQ needs
++                 to be drained */
++              if (drain || mcr->alterfq.fqs & QM_MCR_FQS_NOTEMPTY) {
++                      /* FQ is Not Empty, drain using volatile DQ commands */
++                      fq_empty = 0;
++                      do {
++                              const struct qm_dqrr_entry *dqrr = NULL;
++                              u32 vdqcr = fqid | QM_VDQCR_NUMFRAMES_SET(3);
++                              qm_dqrr_vdqcr_set(portal[0], vdqcr);
++
++                              /* Wait for a dequeue to occur */
++                              while (dqrr == NULL) {
++                                      qm_dqrr_pvb_update(portal[0]);
++                                      dqrr = qm_dqrr_current(portal[0]);
++                                      if (!dqrr)
++                                              cpu_relax();
++                              }
++                              /* Process the dequeues, making sure to
++                                 empty the ring completely */
++                              while (dqrr) {
++                                      if (be32_to_cpu(dqrr->fqid) == fqid &&
++                                          dqrr->stat & QM_DQRR_STAT_FQ_EMPTY)
++                                              fq_empty = 1;
++                                      qm_dqrr_cdc_consume_1ptr(portal[0],
++                                                               dqrr, 0);
++                                      qm_dqrr_pvb_update(portal[0]);
++                                      qm_dqrr_next(portal[0]);
++                                      dqrr = qm_dqrr_current(portal[0]);
++                              }
++                      } while (fq_empty == 0);
++              }
++              for (i = 0; i < portal_count; i++)
++                      qm_dqrr_sdqcr_set(portal[i], 0);
++
++              /* Wait for the ORL to have been completely drained */
++              while (orl_empty == 0) {
++                      const struct qm_mr_entry *msg;
++                      qm_mr_pvb_update(portal[0]);
++                      msg = qm_mr_current(portal[0]);
++                      while (msg) {
++                              if ((msg->verb & QM_MR_VERB_TYPE_MASK) ==
++                                  QM_MR_VERB_FQRL)
++                                      orl_empty = 1;
++                              qm_mr_next(portal[0]);
++                              qm_mr_cci_consume_to_current(portal[0]);
++                              qm_mr_pvb_update(portal[0]);
++                              msg = qm_mr_current(portal[0]);
++                      }
++                      cpu_relax();
++              }
++              mcc = qm_mc_start(portal[0]);
++              mcc->alterfq.fqid = cpu_to_be32(fqid);
++              qm_mc_commit(portal[0], QM_MCC_VERB_ALTER_OOS);
++              while (!(mcr = qm_mc_result(portal[0])))
++                      cpu_relax();
++              DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
++                         QM_MCR_VERB_ALTER_OOS);
++              if (mcr->result != QM_MCR_RESULT_OK) {
++                      pr_err("OOS after drain Failed on FQID 0x%x, result 0x%x\n",
++                             fqid, mcr->result);
++                      return -1;
++              }
++              return 0;
++      case QM_MCR_NP_STATE_RETIRED:
++              /* Send OOS Command */
++              mcc = qm_mc_start(portal[0]);
++              mcc->alterfq.fqid = cpu_to_be32(fqid);
++              qm_mc_commit(portal[0], QM_MCC_VERB_ALTER_OOS);
++              while (!(mcr = qm_mc_result(portal[0])))
++                      cpu_relax();
++              DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
++                         QM_MCR_VERB_ALTER_OOS);
++              if (mcr->result) {
++                      pr_err("OOS Failed on FQID 0x%x\n", fqid);
++                      return -1;
++              }
++              return 0;
++      }
++      return -1;
++}
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/qman_private.h
+@@ -0,0 +1,398 @@
++/* Copyright 2008-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "dpa_sys.h"
++#include <linux/fsl_qman.h>
++#include <linux/iommu.h>
++
++#if defined(CONFIG_FSL_PAMU)
++#include <asm/fsl_pamu_stash.h>
++#endif
++
++#if !defined(CONFIG_FSL_QMAN_FQ_LOOKUP) && defined(CONFIG_PPC64)
++#error "_PPC64 requires _FSL_QMAN_FQ_LOOKUP"
++#endif
++
++#define QBMAN_ANY_PORTAL_IDX 0xffffffff
++      /* ----------------- */
++      /* Congestion Groups */
++      /* ----------------- */
++/* This wrapper represents a bit-array for the state of the 256 Qman congestion
++ * groups. Is also used as a *mask* for congestion groups, eg. so we ignore
++ * those that don't concern us. We harness the structure and accessor details
++ * already used in the management command to query congestion groups. */
++struct qman_cgrs {
++      struct __qm_mcr_querycongestion q;
++};
++static inline void qman_cgrs_init(struct qman_cgrs *c)
++{
++      memset(c, 0, sizeof(*c));
++}
++static inline void qman_cgrs_fill(struct qman_cgrs *c)
++{
++      memset(c, 0xff, sizeof(*c));
++}
++static inline int qman_cgrs_get(struct qman_cgrs *c, int num)
++{
++      return QM_MCR_QUERYCONGESTION(&c->q, num);
++}
++static inline void qman_cgrs_set(struct qman_cgrs *c, int num)
++{
++      c->q.__state[__CGR_WORD(num)] |= (0x80000000 >> __CGR_SHIFT(num));
++}
++static inline void qman_cgrs_unset(struct qman_cgrs *c, int num)
++{
++      c->q.__state[__CGR_WORD(num)] &= ~(0x80000000 >> __CGR_SHIFT(num));
++}
++static inline int qman_cgrs_next(struct qman_cgrs *c, int num)
++{
++      while ((++num < __CGR_NUM) && !qman_cgrs_get(c, num))
++              ;
++      return num;
++}
++static inline void qman_cgrs_cp(struct qman_cgrs *dest,
++                              const struct qman_cgrs *src)
++{
++      *dest = *src;
++}
++static inline void qman_cgrs_and(struct qman_cgrs *dest,
++                      const struct qman_cgrs *a, const struct qman_cgrs *b)
++{
++      int ret;
++      u32 *_d = dest->q.__state;
++      const u32 *_a = a->q.__state;
++      const u32 *_b = b->q.__state;
++      for (ret = 0; ret < 8; ret++)
++              *(_d++) = *(_a++) & *(_b++);
++}
++static inline void qman_cgrs_xor(struct qman_cgrs *dest,
++                      const struct qman_cgrs *a, const struct qman_cgrs *b)
++{
++      int ret;
++      u32 *_d = dest->q.__state;
++      const u32 *_a = a->q.__state;
++      const u32 *_b = b->q.__state;
++      for (ret = 0; ret < 8; ret++)
++              *(_d++) = *(_a++) ^ *(_b++);
++}
++
++      /* ----------------------- */
++      /* CEETM Congestion Groups */
++      /* ----------------------- */
++/* This wrapper represents a bit-array for the state of the 512 Qman CEETM
++ * congestion groups.
++ */
++struct qman_ccgrs {
++      struct __qm_mcr_querycongestion q[2];
++};
++static inline void qman_ccgrs_init(struct qman_ccgrs *c)
++{
++      memset(c, 0, sizeof(*c));
++}
++static inline void qman_ccgrs_fill(struct qman_ccgrs *c)
++{
++      memset(c, 0xff, sizeof(*c));
++}
++static inline int qman_ccgrs_get(struct qman_ccgrs *c, int num)
++{
++      if (num < __CGR_NUM)
++              return QM_MCR_QUERYCONGESTION(&c->q[0], num);
++      else
++              return QM_MCR_QUERYCONGESTION(&c->q[1], (num - __CGR_NUM));
++}
++static inline int qman_ccgrs_next(struct qman_ccgrs *c, int num)
++{
++      while ((++num < __CGR_NUM) && !qman_ccgrs_get(c, num))
++              ;
++      return num;
++}
++static inline void qman_ccgrs_cp(struct qman_ccgrs *dest,
++                                      const struct qman_ccgrs *src)
++{
++      *dest = *src;
++}
++static inline void qman_ccgrs_and(struct qman_ccgrs *dest,
++                      const struct qman_ccgrs *a, const struct qman_ccgrs *b)
++{
++      int ret, i;
++      u32 *_d;
++      const u32 *_a, *_b;
++      for (i = 0; i < 2; i++) {
++              _d = dest->q[i].__state;
++              _a = a->q[i].__state;
++              _b = b->q[i].__state;
++              for (ret = 0; ret < 8; ret++)
++                      *(_d++) = *(_a++) & *(_b++);
++      }
++}
++static inline void qman_ccgrs_xor(struct qman_ccgrs *dest,
++                      const struct qman_ccgrs *a, const struct qman_ccgrs *b)
++{
++      int ret, i;
++      u32 *_d;
++      const u32 *_a, *_b;
++      for (i = 0; i < 2; i++) {
++              _d = dest->q[i].__state;
++              _a = a->q[i].__state;
++              _b = b->q[i].__state;
++              for (ret = 0; ret < 8; ret++)
++                      *(_d++) = *(_a++) ^ *(_b++);
++      }
++}
++
++/* used by CCSR and portal interrupt code */
++enum qm_isr_reg {
++      qm_isr_status = 0,
++      qm_isr_enable = 1,
++      qm_isr_disable = 2,
++      qm_isr_inhibit = 3
++};
++
++struct qm_portal_config {
++      /* Corenet portal addresses;
++       * [0]==cache-enabled, [1]==cache-inhibited. */
++      __iomem void *addr_virt[2];
++      struct resource addr_phys[2];
++      struct device dev;
++      struct iommu_domain *iommu_domain;
++      /* Allow these to be joined in lists */
++      struct list_head list;
++      /* User-visible portal configuration settings */
++      struct qman_portal_config public_cfg;
++      /* power management saved data */
++      u32 saved_isdr;
++};
++
++/* Revision info (for errata and feature handling) */
++#define QMAN_REV11 0x0101
++#define QMAN_REV12 0x0102
++#define QMAN_REV20 0x0200
++#define QMAN_REV30 0x0300
++#define QMAN_REV31 0x0301
++#define QMAN_REV32 0x0302
++
++/* QMan REV_2 register contains the Cfg option */
++#define QMAN_REV_CFG_0 0x0
++#define QMAN_REV_CFG_1 0x1
++#define QMAN_REV_CFG_2 0x2
++#define QMAN_REV_CFG_3 0x3
++
++extern u16 qman_ip_rev; /* 0 if uninitialised, otherwise QMAN_REVx */
++extern u8 qman_ip_cfg;
++extern u32 qman_clk;
++extern u16 qman_portal_max;
++
++#ifdef CONFIG_FSL_QMAN_CONFIG
++/* Hooks from qman_driver.c to qman_config.c */
++int qman_init_ccsr(struct device_node *node);
++void qman_liodn_fixup(u16 channel);
++int qman_set_sdest(u16 channel, unsigned int cpu_idx);
++size_t get_qman_fqd_size(void);
++#else
++static inline size_t get_qman_fqd_size(void)
++{
++      return (PAGE_SIZE << CONFIG_FSL_QMAN_FQD_SZ);
++}
++#endif
++
++int qm_set_wpm(int wpm);
++int qm_get_wpm(int *wpm);
++
++/* Hooks from qman_driver.c in to qman_high.c */
++struct qman_portal *qman_create_portal(
++                      struct qman_portal *portal,
++                      const struct qm_portal_config *config,
++                      const struct qman_cgrs *cgrs);
++
++struct qman_portal *qman_create_affine_portal(
++                      const struct qm_portal_config *config,
++                      const struct qman_cgrs *cgrs);
++struct qman_portal *qman_create_affine_slave(struct qman_portal *redirect,
++                                                              int cpu);
++const struct qm_portal_config *qman_destroy_affine_portal(void);
++void qman_destroy_portal(struct qman_portal *qm);
++
++/* Hooks from fsl_usdpaa.c to qman_driver.c */
++struct qm_portal_config *qm_get_unused_portal(void);
++struct qm_portal_config *qm_get_unused_portal_idx(uint32_t idx);
++
++void qm_put_unused_portal(struct qm_portal_config *pcfg);
++void qm_set_liodns(struct qm_portal_config *pcfg);
++
++/* This CGR feature is supported by h/w and required by unit-tests and the
++ * debugfs hooks, so is implemented in the driver. However it allows an explicit
++ * corruption of h/w fields by s/w that are usually incorruptible (because the
++ * counters are usually maintained entirely within h/w). As such, we declare
++ * this API internally. */
++int qman_testwrite_cgr(struct qman_cgr *cgr, u64 i_bcnt,
++      struct qm_mcr_cgrtestwrite *result);
++
++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
++/* If the fq object pointer is greater than the size of context_b field,
++ * than a lookup table is required. */
++int qman_setup_fq_lookup_table(size_t num_entries);
++#endif
++
++
++/*************************************************/
++/*   QMan s/w corenet portal, low-level i/face   */
++/*************************************************/
++
++/* Note: most functions are only used by the high-level interface, so are
++ * inlined from qman_low.h. The stuff below is for use by other parts of the
++ * driver. */
++
++/* For qm_dqrr_sdqcr_set(); Choose one SOURCE. Choose one COUNT. Choose one
++ * dequeue TYPE. Choose TOKEN (8-bit).
++ * If SOURCE == CHANNELS,
++ *   Choose CHANNELS_DEDICATED and/or CHANNELS_POOL(n).
++ *   You can choose DEDICATED_PRECEDENCE if the portal channel should have
++ *   priority.
++ * If SOURCE == SPECIFICWQ,
++ *     Either select the work-queue ID with SPECIFICWQ_WQ(), or select the
++ *     channel (SPECIFICWQ_DEDICATED or SPECIFICWQ_POOL()) and specify the
++ *     work-queue priority (0-7) with SPECIFICWQ_WQ() - either way, you get the
++ *     same value.
++ */
++#define QM_SDQCR_SOURCE_CHANNELS      0x0
++#define QM_SDQCR_SOURCE_SPECIFICWQ    0x40000000
++#define QM_SDQCR_COUNT_EXACT1         0x0
++#define QM_SDQCR_COUNT_UPTO3          0x20000000
++#define QM_SDQCR_DEDICATED_PRECEDENCE 0x10000000
++#define QM_SDQCR_TYPE_MASK            0x03000000
++#define QM_SDQCR_TYPE_NULL            0x0
++#define QM_SDQCR_TYPE_PRIO_QOS                0x01000000
++#define QM_SDQCR_TYPE_ACTIVE_QOS      0x02000000
++#define QM_SDQCR_TYPE_ACTIVE          0x03000000
++#define QM_SDQCR_TOKEN_MASK           0x00ff0000
++#define QM_SDQCR_TOKEN_SET(v)         (((v) & 0xff) << 16)
++#define QM_SDQCR_TOKEN_GET(v)         (((v) >> 16) & 0xff)
++#define QM_SDQCR_CHANNELS_DEDICATED   0x00008000
++#define QM_SDQCR_SPECIFICWQ_MASK      0x000000f7
++#define QM_SDQCR_SPECIFICWQ_DEDICATED 0x00000000
++#define QM_SDQCR_SPECIFICWQ_POOL(n)   ((n) << 4)
++#define QM_SDQCR_SPECIFICWQ_WQ(n)     (n)
++
++/* For qm_dqrr_vdqcr_set(): use FQID(n) to fill in the frame queue ID */
++#define QM_VDQCR_FQID_MASK            0x00ffffff
++#define QM_VDQCR_FQID(n)              ((n) & QM_VDQCR_FQID_MASK)
++
++/* For qm_dqrr_pdqcr_set(); Choose one MODE. Choose one COUNT.
++ * If MODE==SCHEDULED
++ *   Choose SCHEDULED_CHANNELS or SCHEDULED_SPECIFICWQ. Choose one dequeue TYPE.
++ *   If CHANNELS,
++ *     Choose CHANNELS_DEDICATED and/or CHANNELS_POOL() channels.
++ *     You can choose DEDICATED_PRECEDENCE if the portal channel should have
++ *     priority.
++ *   If SPECIFICWQ,
++ *     Either select the work-queue ID with SPECIFICWQ_WQ(), or select the
++ *     channel (SPECIFICWQ_DEDICATED or SPECIFICWQ_POOL()) and specify the
++ *     work-queue priority (0-7) with SPECIFICWQ_WQ() - either way, you get the
++ *     same value.
++ * If MODE==UNSCHEDULED
++ *     Choose FQID().
++ */
++#define QM_PDQCR_MODE_SCHEDULED               0x0
++#define QM_PDQCR_MODE_UNSCHEDULED     0x80000000
++#define QM_PDQCR_SCHEDULED_CHANNELS   0x0
++#define QM_PDQCR_SCHEDULED_SPECIFICWQ 0x40000000
++#define QM_PDQCR_COUNT_EXACT1         0x0
++#define QM_PDQCR_COUNT_UPTO3          0x20000000
++#define QM_PDQCR_DEDICATED_PRECEDENCE 0x10000000
++#define QM_PDQCR_TYPE_MASK            0x03000000
++#define QM_PDQCR_TYPE_NULL            0x0
++#define QM_PDQCR_TYPE_PRIO_QOS                0x01000000
++#define QM_PDQCR_TYPE_ACTIVE_QOS      0x02000000
++#define QM_PDQCR_TYPE_ACTIVE          0x03000000
++#define QM_PDQCR_CHANNELS_DEDICATED   0x00008000
++#define QM_PDQCR_CHANNELS_POOL(n)     (0x00008000 >> (n))
++#define QM_PDQCR_SPECIFICWQ_MASK      0x000000f7
++#define QM_PDQCR_SPECIFICWQ_DEDICATED 0x00000000
++#define QM_PDQCR_SPECIFICWQ_POOL(n)   ((n) << 4)
++#define QM_PDQCR_SPECIFICWQ_WQ(n)     (n)
++#define QM_PDQCR_FQID(n)              ((n) & 0xffffff)
++
++/* Used by all portal interrupt registers except 'inhibit'
++ * Channels with frame availability
++ */
++#define QM_PIRQ_DQAVAIL       0x0000ffff
++
++/* The DQAVAIL interrupt fields break down into these bits; */
++#define QM_DQAVAIL_PORTAL     0x8000          /* Portal channel */
++#define QM_DQAVAIL_POOL(n)    (0x8000 >> (n)) /* Pool channel, n==[1..15] */
++#define QM_DQAVAIL_MASK               0xffff
++/* This mask contains all the "irqsource" bits visible to API users */
++#define QM_PIRQ_VISIBLE       (QM_PIRQ_SLOW | QM_PIRQ_DQRI)
++
++/* These are qm_<reg>_<verb>(). So for example, qm_disable_write() means "write
++ * the disable register" rather than "disable the ability to write". */
++#define qm_isr_status_read(qm)                __qm_isr_read(qm, qm_isr_status)
++#define qm_isr_status_clear(qm, m)    __qm_isr_write(qm, qm_isr_status, m)
++#define qm_isr_enable_read(qm)                __qm_isr_read(qm, qm_isr_enable)
++#define qm_isr_enable_write(qm, v)    __qm_isr_write(qm, qm_isr_enable, v)
++#define qm_isr_disable_read(qm)               __qm_isr_read(qm, qm_isr_disable)
++#define qm_isr_disable_write(qm, v)   __qm_isr_write(qm, qm_isr_disable, v)
++/* TODO: unfortunate name-clash here, reword? */
++#define qm_isr_inhibit(qm)            __qm_isr_write(qm, qm_isr_inhibit, 1)
++#define qm_isr_uninhibit(qm)          __qm_isr_write(qm, qm_isr_inhibit, 0)
++
++#ifdef CONFIG_FSL_QMAN_CONFIG
++int qman_have_ccsr(void);
++#else
++#define qman_have_ccsr        0
++#endif
++
++__init int qman_init(void);
++__init int qman_resource_init(void);
++
++/* CEETM related */
++#define QMAN_CEETM_MAX        2
++extern u8 num_ceetms;
++extern struct qm_ceetm qman_ceetms[QMAN_CEETM_MAX];
++int qman_sp_enable_ceetm_mode(enum qm_dc_portal portal, u16 sub_portal);
++int qman_sp_disable_ceetm_mode(enum qm_dc_portal portal, u16 sub_portal);
++int qman_ceetm_set_prescaler(enum qm_dc_portal portal);
++int qman_ceetm_get_prescaler(u16 *pres);
++int qman_ceetm_query_cq(unsigned int cqid, unsigned int dcpid,
++                      struct qm_mcr_ceetm_cq_query *cq_query);
++int qman_ceetm_query_ccgr(struct qm_mcc_ceetm_ccgr_query *ccgr_query,
++                              struct qm_mcr_ceetm_ccgr_query *response);
++int qman_ceetm_get_xsfdr(enum qm_dc_portal portal, unsigned int *num);
++
++extern void *affine_portals[NR_CPUS];
++const struct qm_portal_config *qman_get_qm_portal_config(
++                                              struct qman_portal *portal);
++
++/* power management */
++#ifdef CONFIG_SUSPEND
++void suspend_unused_qportal(void);
++void resume_unused_qportal(void);
++#endif
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/qman_test.c
+@@ -0,0 +1,57 @@
++/* Copyright 2008-2011 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "qman_test.h"
++
++MODULE_AUTHOR("Geoff Thorpe");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_DESCRIPTION("Qman testing");
++
++static int test_init(void)
++{
++      int loop = 1;
++      while (loop--) {
++#ifdef CONFIG_FSL_QMAN_TEST_STASH_POTATO
++              qman_test_hotpotato();
++#endif
++#ifdef CONFIG_FSL_QMAN_TEST_HIGH
++              qman_test_high();
++#endif
++      }
++      return 0;
++}
++
++static void test_exit(void)
++{
++}
++
++module_init(test_init);
++module_exit(test_exit);
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/qman_test.h
+@@ -0,0 +1,45 @@
++/* Copyright 2008-2011 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/io.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++
++#include <linux/fsl_qman.h>
++
++void qman_test_hotpotato(void);
++void qman_test_high(void);
++
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/qman_test_high.c
+@@ -0,0 +1,216 @@
++/* Copyright 2008-2011 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "qman_test.h"
++
++/*************/
++/* constants */
++/*************/
++
++#define CGR_ID                27
++#define POOL_ID               2
++#define FQ_FLAGS      QMAN_FQ_FLAG_DYNAMIC_FQID
++#define NUM_ENQUEUES  10
++#define NUM_PARTIAL   4
++#define PORTAL_SDQCR  (QM_SDQCR_SOURCE_CHANNELS | \
++                      QM_SDQCR_TYPE_PRIO_QOS | \
++                      QM_SDQCR_TOKEN_SET(0x98) | \
++                      QM_SDQCR_CHANNELS_DEDICATED | \
++                      QM_SDQCR_CHANNELS_POOL(POOL_ID))
++#define PORTAL_OPAQUE ((void *)0xf00dbeef)
++#define VDQCR_FLAGS   (QMAN_VOLATILE_FLAG_WAIT | QMAN_VOLATILE_FLAG_FINISH)
++
++/*************************************/
++/* Predeclarations (eg. for fq_base) */
++/*************************************/
++
++static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *,
++                                      struct qman_fq *,
++                                      const struct qm_dqrr_entry *);
++static void cb_ern(struct qman_portal *, struct qman_fq *,
++                      const struct qm_mr_entry *);
++static void cb_fqs(struct qman_portal *, struct qman_fq *,
++                      const struct qm_mr_entry *);
++
++/***************/
++/* global vars */
++/***************/
++
++static struct qm_fd fd, fd_dq;
++static struct qman_fq fq_base = {
++      .cb.dqrr = cb_dqrr,
++      .cb.ern = cb_ern,
++      .cb.fqs = cb_fqs
++};
++static DECLARE_WAIT_QUEUE_HEAD(waitqueue);
++static int retire_complete, sdqcr_complete;
++
++/**********************/
++/* internal functions */
++/**********************/
++
++/* Helpers for initialising and "incrementing" a frame descriptor */
++static void fd_init(struct qm_fd *__fd)
++{
++      qm_fd_addr_set64(__fd, 0xabdeadbeefLLU);
++      __fd->format = qm_fd_contig_big;
++      __fd->length29 = 0x0000ffff;
++      __fd->cmd = 0xfeedf00d;
++}
++
++static void fd_inc(struct qm_fd *__fd)
++{
++      u64 t = qm_fd_addr_get64(__fd);
++      int z = t >> 40;
++      t <<= 1;
++      if (z)
++              t |= 1;
++      qm_fd_addr_set64(__fd, t);
++      __fd->length29--;
++      __fd->cmd++;
++}
++
++/* The only part of the 'fd' we can't memcmp() is the ppid */
++static int fd_cmp(const struct qm_fd *a, const struct qm_fd *b)
++{
++      int r = (qm_fd_addr_get64(a) == qm_fd_addr_get64(b)) ? 0 : -1;
++      if (!r)
++              r = a->format - b->format;
++      if (!r)
++              r = a->opaque - b->opaque;
++      if (!r)
++              r = a->cmd - b->cmd;
++      return r;
++}
++
++/********/
++/* test */
++/********/
++
++static void do_enqueues(struct qman_fq *fq)
++{
++      unsigned int loop;
++      for (loop = 0; loop < NUM_ENQUEUES; loop++) {
++              if (qman_enqueue(fq, &fd, QMAN_ENQUEUE_FLAG_WAIT |
++                              (((loop + 1) == NUM_ENQUEUES) ?
++                              QMAN_ENQUEUE_FLAG_WAIT_SYNC : 0)))
++                      panic("qman_enqueue() failed\n");
++              fd_inc(&fd);
++      }
++}
++
++void qman_test_high(void)
++{
++      unsigned int flags;
++      int res;
++      struct qman_fq *fq = &fq_base;
++
++      pr_info("qman_test_high starting\n");
++      fd_init(&fd);
++      fd_init(&fd_dq);
++
++      /* Initialise (parked) FQ */
++      if (qman_create_fq(0, FQ_FLAGS, fq))
++              panic("qman_create_fq() failed\n");
++      if (qman_init_fq(fq, QMAN_INITFQ_FLAG_LOCAL, NULL))
++              panic("qman_init_fq() failed\n");
++
++      /* Do enqueues + VDQCR, twice. (Parked FQ) */
++      do_enqueues(fq);
++      pr_info("VDQCR (till-empty);\n");
++      if (qman_volatile_dequeue(fq, VDQCR_FLAGS,
++                      QM_VDQCR_NUMFRAMES_TILLEMPTY))
++              panic("qman_volatile_dequeue() failed\n");
++      do_enqueues(fq);
++      pr_info("VDQCR (%d of %d);\n", NUM_PARTIAL, NUM_ENQUEUES);
++      if (qman_volatile_dequeue(fq, VDQCR_FLAGS,
++                      QM_VDQCR_NUMFRAMES_SET(NUM_PARTIAL)))
++              panic("qman_volatile_dequeue() failed\n");
++      pr_info("VDQCR (%d of %d);\n", NUM_ENQUEUES - NUM_PARTIAL,
++                                      NUM_ENQUEUES);
++      if (qman_volatile_dequeue(fq, VDQCR_FLAGS,
++                      QM_VDQCR_NUMFRAMES_SET(NUM_ENQUEUES - NUM_PARTIAL)))
++              panic("qman_volatile_dequeue() failed\n");
++
++      do_enqueues(fq);
++      pr_info("scheduled dequeue (till-empty)\n");
++      if (qman_schedule_fq(fq))
++              panic("qman_schedule_fq() failed\n");
++      wait_event(waitqueue, sdqcr_complete);
++
++      /* Retire and OOS the FQ */
++      res = qman_retire_fq(fq, &flags);
++      if (res < 0)
++              panic("qman_retire_fq() failed\n");
++      wait_event(waitqueue, retire_complete);
++      if (flags & QMAN_FQ_STATE_BLOCKOOS)
++              panic("leaking frames\n");
++      if (qman_oos_fq(fq))
++              panic("qman_oos_fq() failed\n");
++      qman_destroy_fq(fq, 0);
++      pr_info("qman_test_high finished\n");
++}
++
++static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *p,
++                                      struct qman_fq *fq,
++                                      const struct qm_dqrr_entry *dq)
++{
++      if (fd_cmp(&fd_dq, &dq->fd)) {
++              pr_err("BADNESS: dequeued frame doesn't match;\n");
++              pr_err("Expected 0x%llx, got 0x%llx\n",
++                     (unsigned long long)fd_dq.length29,
++                     (unsigned long long)dq->fd.length29);
++              BUG();
++      }
++      fd_inc(&fd_dq);
++      if (!(dq->stat & QM_DQRR_STAT_UNSCHEDULED) && !fd_cmp(&fd_dq, &fd)) {
++              sdqcr_complete = 1;
++              wake_up(&waitqueue);
++      }
++      return qman_cb_dqrr_consume;
++}
++
++static void cb_ern(struct qman_portal *p, struct qman_fq *fq,
++                      const struct qm_mr_entry *msg)
++{
++      panic("cb_ern() unimplemented");
++}
++
++static void cb_fqs(struct qman_portal *p, struct qman_fq *fq,
++                      const struct qm_mr_entry *msg)
++{
++      u8 verb = (msg->verb & QM_MR_VERB_TYPE_MASK);
++      if ((verb != QM_MR_VERB_FQRN) && (verb != QM_MR_VERB_FQRNI))
++              panic("unexpected FQS message");
++      pr_info("Retirement message received\n");
++      retire_complete = 1;
++      wake_up(&waitqueue);
++}
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/qman_test_hotpotato.c
+@@ -0,0 +1,502 @@
++/* Copyright 2009-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kthread.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include "qman_test.h"
++
++/* Algorithm:
++ *
++ * Each cpu will have HP_PER_CPU "handlers" set up, each of which incorporates
++ * an rx/tx pair of FQ objects (both of which are stashed on dequeue). The
++ * organisation of FQIDs is such that the HP_PER_CPU*NUM_CPUS handlers will
++ * shuttle a "hot potato" frame around them such that every forwarding action
++ * moves it from one cpu to another. (The use of more than one handler per cpu
++ * is to allow enough handlers/FQs to truly test the significance of caching -
++ * ie. when cache-expiries are occurring.)
++ *
++ * The "hot potato" frame content will be HP_NUM_WORDS*4 bytes in size, and the
++ * first and last words of the frame data will undergo a transformation step on
++ * each forwarding action. To achieve this, each handler will be assigned a
++ * 32-bit "mixer", that is produced using a 32-bit LFSR. When a frame is
++ * received by a handler, the mixer of the expected sender is XOR'd into all
++ * words of the entire frame, which is then validated against the original
++ * values. Then, before forwarding, the entire frame is XOR'd with the mixer of
++ * the current handler. Apart from validating that the frame is taking the
++ * expected path, this also provides some quasi-realistic overheads to each
++ * forwarding action - dereferencing *all* the frame data, computation, and
++ * conditional branching. There is a "special" handler designated to act as the
++ * instigator of the test by creating an enqueuing the "hot potato" frame, and
++ * to determine when the test has completed by counting HP_LOOPS iterations.
++ *
++ * Init phases:
++ *
++ * 1. prepare each cpu's 'hp_cpu' struct using on_each_cpu(,,1) and link them
++ *    into 'hp_cpu_list'. Specifically, set processor_id, allocate HP_PER_CPU
++ *    handlers and link-list them (but do no other handler setup).
++ *
++ * 2. scan over 'hp_cpu_list' HP_PER_CPU times, the first time sets each
++ *    hp_cpu's 'iterator' to point to its first handler. With each loop,
++ *    allocate rx/tx FQIDs and mixer values to the hp_cpu's iterator handler
++ *    and advance the iterator for the next loop. This includes a final fixup,
++ *    which connects the last handler to the first (and which is why phase 2
++ *    and 3 are separate).
++ *
++ * 3. scan over 'hp_cpu_list' HP_PER_CPU times, the first time sets each
++ *    hp_cpu's 'iterator' to point to its first handler. With each loop,
++ *    initialise FQ objects and advance the iterator for the next loop.
++ *    Moreover, do this initialisation on the cpu it applies to so that Rx FQ
++ *    initialisation targets the correct cpu.
++ */
++
++/* helper to run something on all cpus (can't use on_each_cpu(), as that invokes
++ * the fn from irq context, which is too restrictive). */
++struct bstrap {
++      void (*fn)(void);
++      atomic_t started;
++};
++static int bstrap_fn(void *__bstrap)
++{
++      struct bstrap *bstrap = __bstrap;
++      atomic_inc(&bstrap->started);
++      bstrap->fn();
++      while (!kthread_should_stop())
++              msleep(1);
++      return 0;
++}
++static int on_all_cpus(void (*fn)(void))
++{
++      int cpu;
++      for_each_cpu(cpu, cpu_online_mask) {
++              struct bstrap bstrap = {
++                      .fn = fn,
++                      .started = ATOMIC_INIT(0)
++              };
++              struct task_struct *k = kthread_create(bstrap_fn, &bstrap,
++                      "hotpotato%d", cpu);
++              int ret;
++              if (IS_ERR(k))
++                      return -ENOMEM;
++              kthread_bind(k, cpu);
++              wake_up_process(k);
++              /* If we call kthread_stop() before the "wake up" has had an
++               * effect, then the thread may exit with -EINTR without ever
++               * running the function. So poll until it's started before
++               * requesting it to stop. */
++              while (!atomic_read(&bstrap.started))
++                      msleep(10);
++              ret = kthread_stop(k);
++              if (ret)
++                      return ret;
++      }
++      return 0;
++}
++
++struct hp_handler {
++
++      /* The following data is stashed when 'rx' is dequeued; */
++      /* -------------- */
++      /* The Rx FQ, dequeues of which will stash the entire hp_handler */
++      struct qman_fq rx;
++      /* The Tx FQ we should forward to */
++      struct qman_fq tx;
++      /* The value we XOR post-dequeue, prior to validating */
++      u32 rx_mixer;
++      /* The value we XOR pre-enqueue, after validating */
++      u32 tx_mixer;
++      /* what the hotpotato address should be on dequeue */
++      dma_addr_t addr;
++      u32 *frame_ptr;
++
++      /* The following data isn't (necessarily) stashed on dequeue; */
++      /* -------------- */
++      u32 fqid_rx, fqid_tx;
++      /* list node for linking us into 'hp_cpu' */
++      struct list_head node;
++      /* Just to check ... */
++      unsigned int processor_id;
++} ____cacheline_aligned;
++
++struct hp_cpu {
++      /* identify the cpu we run on; */
++      unsigned int processor_id;
++      /* root node for the per-cpu list of handlers */
++      struct list_head handlers;
++      /* list node for linking us into 'hp_cpu_list' */
++      struct list_head node;
++      /* when repeatedly scanning 'hp_list', each time linking the n'th
++       * handlers together, this is used as per-cpu iterator state */
++      struct hp_handler *iterator;
++};
++
++/* Each cpu has one of these */
++static DEFINE_PER_CPU(struct hp_cpu, hp_cpus);
++
++/* links together the hp_cpu structs, in first-come first-serve order. */
++static LIST_HEAD(hp_cpu_list);
++static spinlock_t hp_lock = __SPIN_LOCK_UNLOCKED(hp_lock);
++
++static unsigned int hp_cpu_list_length;
++
++/* the "special" handler, that starts and terminates the test. */
++static struct hp_handler *special_handler;
++static int loop_counter;
++
++/* handlers are allocated out of this, so they're properly aligned. */
++static struct kmem_cache *hp_handler_slab;
++
++/* this is the frame data */
++static void *__frame_ptr;
++static u32 *frame_ptr;
++static dma_addr_t frame_dma;
++
++/* the main function waits on this */
++static DECLARE_WAIT_QUEUE_HEAD(queue);
++
++#define HP_PER_CPU    2
++#define HP_LOOPS      8
++/* 80 bytes, like a small ethernet frame, and bleeds into a second cacheline */
++#define HP_NUM_WORDS  80
++/* First word of the LFSR-based frame data */
++#define HP_FIRST_WORD 0xabbaf00d
++
++static inline u32 do_lfsr(u32 prev)
++{
++      return (prev >> 1) ^ (-(prev & 1u) & 0xd0000001u);
++}
++
++static void allocate_frame_data(void)
++{
++      u32 lfsr = HP_FIRST_WORD;
++      int loop;
++      struct platform_device *pdev = platform_device_alloc("foobar", -1);
++      if (!pdev)
++              panic("platform_device_alloc() failed");
++      if (platform_device_add(pdev))
++              panic("platform_device_add() failed");
++      __frame_ptr = kmalloc(4 * HP_NUM_WORDS, GFP_KERNEL);
++      if (!__frame_ptr)
++              panic("kmalloc() failed");
++      frame_ptr = (void *)(((unsigned long)__frame_ptr + 63) &
++                              ~(unsigned long)63);
++      for (loop = 0; loop < HP_NUM_WORDS; loop++) {
++              frame_ptr[loop] = lfsr;
++              lfsr = do_lfsr(lfsr);
++      }
++      frame_dma = dma_map_single(&pdev->dev, frame_ptr, 4 * HP_NUM_WORDS,
++                                      DMA_BIDIRECTIONAL);
++      platform_device_del(pdev);
++      platform_device_put(pdev);
++}
++
++static void deallocate_frame_data(void)
++{
++      kfree(__frame_ptr);
++}
++
++static inline void process_frame_data(struct hp_handler *handler,
++                              const struct qm_fd *fd)
++{
++      u32 *p = handler->frame_ptr;
++      u32 lfsr = HP_FIRST_WORD;
++      int loop;
++      if (qm_fd_addr_get64(fd) != (handler->addr & 0xffffffffff)) {
++              pr_err("Got 0x%llx expected 0x%llx\n",
++                     qm_fd_addr_get64(fd), handler->addr);
++              panic("bad frame address");
++      }
++      for (loop = 0; loop < HP_NUM_WORDS; loop++, p++) {
++              *p ^= handler->rx_mixer;
++              if (*p != lfsr)
++                      panic("corrupt frame data");
++              *p ^= handler->tx_mixer;
++              lfsr = do_lfsr(lfsr);
++      }
++}
++
++static enum qman_cb_dqrr_result normal_dqrr(struct qman_portal *portal,
++                                      struct qman_fq *fq,
++                                      const struct qm_dqrr_entry *dqrr)
++{
++      struct hp_handler *handler = (struct hp_handler *)fq;
++
++      process_frame_data(handler, &dqrr->fd);
++      if (qman_enqueue(&handler->tx, &dqrr->fd, 0))
++              panic("qman_enqueue() failed");
++      return qman_cb_dqrr_consume;
++}
++
++static enum qman_cb_dqrr_result special_dqrr(struct qman_portal *portal,
++                                      struct qman_fq *fq,
++                                      const struct qm_dqrr_entry *dqrr)
++{
++      struct hp_handler *handler = (struct hp_handler *)fq;
++
++      process_frame_data(handler, &dqrr->fd);
++      if (++loop_counter < HP_LOOPS) {
++              if (qman_enqueue(&handler->tx, &dqrr->fd, 0))
++                      panic("qman_enqueue() failed");
++      } else {
++              pr_info("Received final (%dth) frame\n", loop_counter);
++              wake_up(&queue);
++      }
++      return qman_cb_dqrr_consume;
++}
++
++static void create_per_cpu_handlers(void)
++{
++      struct hp_handler *handler;
++      int loop;
++      struct hp_cpu *hp_cpu = &get_cpu_var(hp_cpus);
++
++      hp_cpu->processor_id = smp_processor_id();
++      spin_lock(&hp_lock);
++      list_add_tail(&hp_cpu->node, &hp_cpu_list);
++      hp_cpu_list_length++;
++      spin_unlock(&hp_lock);
++      INIT_LIST_HEAD(&hp_cpu->handlers);
++      for (loop = 0; loop < HP_PER_CPU; loop++) {
++              handler = kmem_cache_alloc(hp_handler_slab, GFP_KERNEL);
++              if (!handler)
++                      panic("kmem_cache_alloc() failed");
++              handler->processor_id = hp_cpu->processor_id;
++              handler->addr = frame_dma;
++              handler->frame_ptr = frame_ptr;
++              list_add_tail(&handler->node, &hp_cpu->handlers);
++      }
++      put_cpu_var(hp_cpus);
++}
++
++static void destroy_per_cpu_handlers(void)
++{
++      struct list_head *loop, *tmp;
++      struct hp_cpu *hp_cpu = &get_cpu_var(hp_cpus);
++
++      spin_lock(&hp_lock);
++      list_del(&hp_cpu->node);
++      spin_unlock(&hp_lock);
++      list_for_each_safe(loop, tmp, &hp_cpu->handlers) {
++              u32 flags;
++              struct hp_handler *handler = list_entry(loop, struct hp_handler,
++                                                      node);
++              if (qman_retire_fq(&handler->rx, &flags))
++                      panic("qman_retire_fq(rx) failed");
++              BUG_ON(flags & QMAN_FQ_STATE_BLOCKOOS);
++              if (qman_oos_fq(&handler->rx))
++                      panic("qman_oos_fq(rx) failed");
++              qman_destroy_fq(&handler->rx, 0);
++              qman_destroy_fq(&handler->tx, 0);
++              qman_release_fqid(handler->fqid_rx);
++              list_del(&handler->node);
++              kmem_cache_free(hp_handler_slab, handler);
++      }
++      put_cpu_var(hp_cpus);
++}
++
++static inline u8 num_cachelines(u32 offset)
++{
++      u8 res = (offset + (L1_CACHE_BYTES - 1))
++                       / (L1_CACHE_BYTES);
++      if (res > 3)
++              return 3;
++      return res;
++}
++#define STASH_DATA_CL \
++      num_cachelines(HP_NUM_WORDS * 4)
++#define STASH_CTX_CL \
++      num_cachelines(offsetof(struct hp_handler, fqid_rx))
++
++static void init_handler(void *__handler)
++{
++      struct qm_mcc_initfq opts;
++      struct hp_handler *handler = __handler;
++      BUG_ON(handler->processor_id != smp_processor_id());
++      /* Set up rx */
++      memset(&handler->rx, 0, sizeof(handler->rx));
++      if (handler == special_handler)
++              handler->rx.cb.dqrr = special_dqrr;
++      else
++              handler->rx.cb.dqrr = normal_dqrr;
++      if (qman_create_fq(handler->fqid_rx, 0, &handler->rx))
++              panic("qman_create_fq(rx) failed");
++      memset(&opts, 0, sizeof(opts));
++      opts.we_mask = QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_CONTEXTA;
++      opts.fqd.fq_ctrl = QM_FQCTRL_CTXASTASHING;
++      opts.fqd.context_a.stashing.data_cl = STASH_DATA_CL;
++      opts.fqd.context_a.stashing.context_cl = STASH_CTX_CL;
++      if (qman_init_fq(&handler->rx, QMAN_INITFQ_FLAG_SCHED |
++                              QMAN_INITFQ_FLAG_LOCAL, &opts))
++              panic("qman_init_fq(rx) failed");
++      /* Set up tx */
++      memset(&handler->tx, 0, sizeof(handler->tx));
++      if (qman_create_fq(handler->fqid_tx, QMAN_FQ_FLAG_NO_MODIFY,
++                              &handler->tx))
++              panic("qman_create_fq(tx) failed");
++}
++
++static void init_phase2(void)
++{
++      int loop;
++      u32 fqid = 0;
++      u32 lfsr = 0xdeadbeef;
++      struct hp_cpu *hp_cpu;
++      struct hp_handler *handler;
++
++      for (loop = 0; loop < HP_PER_CPU; loop++) {
++              list_for_each_entry(hp_cpu, &hp_cpu_list, node) {
++                      int ret;
++                      if (!loop)
++                              hp_cpu->iterator = list_first_entry(
++                                              &hp_cpu->handlers,
++                                              struct hp_handler, node);
++                      else
++                              hp_cpu->iterator = list_entry(
++                                              hp_cpu->iterator->node.next,
++                                              struct hp_handler, node);
++                      /* Rx FQID is the previous handler's Tx FQID */
++                      hp_cpu->iterator->fqid_rx = fqid;
++                      /* Allocate new FQID for Tx */
++                      ret = qman_alloc_fqid(&fqid);
++                      if (ret)
++                              panic("qman_alloc_fqid() failed");
++                      hp_cpu->iterator->fqid_tx = fqid;
++                      /* Rx mixer is the previous handler's Tx mixer */
++                      hp_cpu->iterator->rx_mixer = lfsr;
++                      /* Get new mixer for Tx */
++                      lfsr = do_lfsr(lfsr);
++                      hp_cpu->iterator->tx_mixer = lfsr;
++              }
++      }
++      /* Fix up the first handler (fqid_rx==0, rx_mixer=0xdeadbeef) */
++      hp_cpu = list_first_entry(&hp_cpu_list, struct hp_cpu, node);
++      handler = list_first_entry(&hp_cpu->handlers, struct hp_handler, node);
++      BUG_ON((handler->fqid_rx != 0) || (handler->rx_mixer != 0xdeadbeef));
++      handler->fqid_rx = fqid;
++      handler->rx_mixer = lfsr;
++      /* and tag it as our "special" handler */
++      special_handler = handler;
++}
++
++static void init_phase3(void)
++{
++      int loop;
++      struct hp_cpu *hp_cpu;
++
++      for (loop = 0; loop < HP_PER_CPU; loop++) {
++              list_for_each_entry(hp_cpu, &hp_cpu_list, node) {
++                      if (!loop)
++                              hp_cpu->iterator = list_first_entry(
++                                              &hp_cpu->handlers,
++                                              struct hp_handler, node);
++                      else
++                              hp_cpu->iterator = list_entry(
++                                              hp_cpu->iterator->node.next,
++                                              struct hp_handler, node);
++                      preempt_disable();
++                      if (hp_cpu->processor_id == smp_processor_id())
++                              init_handler(hp_cpu->iterator);
++                      else
++                              smp_call_function_single(hp_cpu->processor_id,
++                                      init_handler, hp_cpu->iterator, 1);
++                      preempt_enable();
++              }
++      }
++}
++
++static void send_first_frame(void *ignore)
++{
++      u32 *p = special_handler->frame_ptr;
++      u32 lfsr = HP_FIRST_WORD;
++      int loop;
++      struct qm_fd fd;
++
++      BUG_ON(special_handler->processor_id != smp_processor_id());
++      memset(&fd, 0, sizeof(fd));
++      qm_fd_addr_set64(&fd, special_handler->addr);
++      fd.format = qm_fd_contig_big;
++      fd.length29 = HP_NUM_WORDS * 4;
++      for (loop = 0; loop < HP_NUM_WORDS; loop++, p++) {
++              if (*p != lfsr)
++                      panic("corrupt frame data");
++              *p ^= special_handler->tx_mixer;
++              lfsr = do_lfsr(lfsr);
++      }
++      pr_info("Sending first frame\n");
++      if (qman_enqueue(&special_handler->tx, &fd, 0))
++              panic("qman_enqueue() failed");
++}
++
++void qman_test_hotpotato(void)
++{
++      if (cpumask_weight(cpu_online_mask) < 2) {
++              pr_info("qman_test_hotpotato, skip - only 1 CPU\n");
++              return;
++      }
++
++      pr_info("qman_test_hotpotato starting\n");
++
++      hp_cpu_list_length = 0;
++      loop_counter = 0;
++      hp_handler_slab = kmem_cache_create("hp_handler_slab",
++                      sizeof(struct hp_handler), L1_CACHE_BYTES,
++                      SLAB_HWCACHE_ALIGN, NULL);
++      if (!hp_handler_slab)
++              panic("kmem_cache_create() failed");
++
++      allocate_frame_data();
++
++      /* Init phase 1 */
++      pr_info("Creating %d handlers per cpu...\n", HP_PER_CPU);
++      if (on_all_cpus(create_per_cpu_handlers))
++              panic("on_each_cpu() failed");
++      pr_info("Number of cpus: %d, total of %d handlers\n",
++              hp_cpu_list_length, hp_cpu_list_length * HP_PER_CPU);
++
++      init_phase2();
++
++      init_phase3();
++
++      preempt_disable();
++      if (special_handler->processor_id == smp_processor_id())
++              send_first_frame(NULL);
++      else
++              smp_call_function_single(special_handler->processor_id,
++                      send_first_frame, NULL, 1);
++      preempt_enable();
++
++      wait_event(queue, loop_counter == HP_LOOPS);
++      deallocate_frame_data();
++      if (on_all_cpus(destroy_per_cpu_handlers))
++              panic("on_each_cpu() failed");
++      kmem_cache_destroy(hp_handler_slab);
++      pr_info("qman_test_hotpotato finished\n");
++}
+--- /dev/null
++++ b/drivers/staging/fsl_qbman/qman_utility.c
+@@ -0,0 +1,129 @@
++/* Copyright 2008-2011 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "qman_private.h"
++
++/* ----------------- */
++/* --- FQID Pool --- */
++
++struct qman_fqid_pool {
++      /* Base and size of the FQID range */
++      u32 fqid_base;
++      u32 total;
++      /* Number of FQIDs currently "allocated" */
++      u32 used;
++      /* Allocation optimisation. When 'used<total', it is the index of an
++       * available FQID. Otherwise there are no available FQIDs, and this
++       * will be set when the next deallocation occurs. */
++      u32 next;
++      /* A bit-field representation of the FQID range. */
++      unsigned long *bits;
++};
++
++#define QLONG_BYTES   sizeof(unsigned long)
++#define QLONG_BITS    (QLONG_BYTES * 8)
++/* Number of 'longs' required for the given number of bits */
++#define QNUM_LONGS(b) (((b) + QLONG_BITS - 1) / QLONG_BITS)
++/* Shorthand for the number of bytes of same (kmalloc, memset, etc) */
++#define QNUM_BYTES(b) (QNUM_LONGS(b) * QLONG_BYTES)
++/* And in bits */
++#define QNUM_BITS(b)  (QNUM_LONGS(b) * QLONG_BITS)
++
++struct qman_fqid_pool *qman_fqid_pool_create(u32 fqid_start, u32 num)
++{
++      struct qman_fqid_pool *pool = kmalloc(sizeof(*pool), GFP_KERNEL);
++      unsigned int i;
++
++      BUG_ON(!num);
++      if (!pool)
++              return NULL;
++      pool->fqid_base = fqid_start;
++      pool->total = num;
++      pool->used = 0;
++      pool->next = 0;
++      pool->bits = kzalloc(QNUM_BYTES(num), GFP_KERNEL);
++      if (!pool->bits) {
++              kfree(pool);
++              return NULL;
++      }
++      /* If num is not an even multiple of QLONG_BITS (or even 8, for
++       * byte-oriented searching) then we fill the trailing bits with 1, to
++       * make them look allocated (permanently). */
++      for (i = num + 1; i < QNUM_BITS(num); i++)
++              set_bit(i, pool->bits);
++      return pool;
++}
++EXPORT_SYMBOL(qman_fqid_pool_create);
++
++int qman_fqid_pool_destroy(struct qman_fqid_pool *pool)
++{
++      int ret = pool->used;
++      kfree(pool->bits);
++      kfree(pool);
++      return ret;
++}
++EXPORT_SYMBOL(qman_fqid_pool_destroy);
++
++int qman_fqid_pool_alloc(struct qman_fqid_pool *pool, u32 *fqid)
++{
++      int ret;
++      if (pool->used == pool->total)
++              return -ENOMEM;
++      *fqid = pool->fqid_base + pool->next;
++      ret = test_and_set_bit(pool->next, pool->bits);
++      BUG_ON(ret);
++      if (++pool->used == pool->total)
++              return 0;
++      pool->next = find_next_zero_bit(pool->bits, pool->total, pool->next);
++      if (pool->next >= pool->total)
++              pool->next = find_first_zero_bit(pool->bits, pool->total);
++      BUG_ON(pool->next >= pool->total);
++      return 0;
++}
++EXPORT_SYMBOL(qman_fqid_pool_alloc);
++
++void qman_fqid_pool_free(struct qman_fqid_pool *pool, u32 fqid)
++{
++      int ret;
++
++      fqid -= pool->fqid_base;
++      ret = test_and_clear_bit(fqid, pool->bits);
++      BUG_ON(!ret);
++      if (pool->used-- == pool->total)
++              pool->next = fqid;
++}
++EXPORT_SYMBOL(qman_fqid_pool_free);
++
++u32 qman_fqid_pool_used(struct qman_fqid_pool *pool)
++{
++      return pool->used;
++}
++EXPORT_SYMBOL(qman_fqid_pool_used);
+--- /dev/null
++++ b/include/linux/fsl_bman.h
+@@ -0,0 +1,532 @@
++/* Copyright 2008-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef FSL_BMAN_H
++#define FSL_BMAN_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* Last updated for v00.79 of the BG */
++
++/* Portal processing (interrupt) sources */
++#define BM_PIRQ_RCRI  0x00000002      /* RCR Ring (below threshold) */
++#define BM_PIRQ_BSCN  0x00000001      /* Buffer depletion State Change */
++
++/* This wrapper represents a bit-array for the depletion state of the 64 Bman
++ * buffer pools. */
++struct bman_depletion {
++      u32 __state[2];
++};
++#define BMAN_DEPLETION_EMPTY { { 0x00000000, 0x00000000 } }
++#define BMAN_DEPLETION_FULL { { 0xffffffff, 0xffffffff } }
++#define __bmdep_word(x) ((x) >> 5)
++#define __bmdep_shift(x) ((x) & 0x1f)
++#define __bmdep_bit(x) (0x80000000 >> __bmdep_shift(x))
++static inline void bman_depletion_init(struct bman_depletion *c)
++{
++      c->__state[0] = c->__state[1] = 0;
++}
++static inline void bman_depletion_fill(struct bman_depletion *c)
++{
++      c->__state[0] = c->__state[1] = ~0;
++}
++static inline int bman_depletion_get(const struct bman_depletion *c, u8 bpid)
++{
++      return c->__state[__bmdep_word(bpid)] & __bmdep_bit(bpid);
++}
++static inline void bman_depletion_set(struct bman_depletion *c, u8 bpid)
++{
++      c->__state[__bmdep_word(bpid)] |= __bmdep_bit(bpid);
++}
++static inline void bman_depletion_unset(struct bman_depletion *c, u8 bpid)
++{
++      c->__state[__bmdep_word(bpid)] &= ~__bmdep_bit(bpid);
++}
++
++/* ------------------------------------------------------- */
++/* --- Bman data structures (and associated constants) --- */
++
++/* Represents s/w corenet portal mapped data structures */
++struct bm_rcr_entry;  /* RCR (Release Command Ring) entries */
++struct bm_mc_command; /* MC (Management Command) command */
++struct bm_mc_result;  /* MC result */
++
++/* Code-reduction, define a wrapper for 48-bit buffers. In cases where a buffer
++ * pool id specific to this buffer is needed (BM_RCR_VERB_CMD_BPID_MULTI,
++ * BM_MCC_VERB_ACQUIRE), the 'bpid' field is used. */
++struct bm_buffer {
++      union {
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u8 __reserved1;
++                      u8 bpid;
++                      u16 hi; /* High 16-bits of 48-bit address */
++                      u32 lo; /* Low 32-bits of 48-bit address */
++#else
++                      u32 lo;
++                      u16 hi;
++                      u8 bpid;
++                      u8 __reserved;
++#endif
++              };
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u64 __notaddress:16;
++                      u64 addr:48;
++#else
++                      u64 addr:48;
++                      u64 __notaddress:16;
++#endif
++              };
++              u64 opaque;
++      };
++} __aligned(8);
++static inline u64 bm_buffer_get64(const struct bm_buffer *buf)
++{
++      return buf->addr;
++}
++static inline dma_addr_t bm_buf_addr(const struct bm_buffer *buf)
++{
++      return (dma_addr_t)buf->addr;
++}
++/* Macro, so we compile better if 'v' isn't always 64-bit */
++#define bm_buffer_set64(buf, v) \
++      do { \
++              struct bm_buffer *__buf931 = (buf); \
++              __buf931->hi = upper_32_bits(v); \
++              __buf931->lo = lower_32_bits(v); \
++      } while (0)
++
++/* See 1.5.3.5.4: "Release Command" */
++struct bm_rcr_entry {
++      union {
++              struct {
++                      u8 __dont_write_directly__verb;
++                      u8 bpid; /* used with BM_RCR_VERB_CMD_BPID_SINGLE */
++                      u8 __reserved1[62];
++              };
++              struct bm_buffer bufs[8];
++      };
++} __packed;
++#define BM_RCR_VERB_VBIT              0x80
++#define BM_RCR_VERB_CMD_MASK          0x70    /* one of two values; */
++#define BM_RCR_VERB_CMD_BPID_SINGLE   0x20
++#define BM_RCR_VERB_CMD_BPID_MULTI    0x30
++#define BM_RCR_VERB_BUFCOUNT_MASK     0x0f    /* values 1..8 */
++
++/* See 1.5.3.1: "Acquire Command" */
++/* See 1.5.3.2: "Query Command" */
++struct bm_mcc_acquire {
++      u8 bpid;
++      u8 __reserved1[62];
++} __packed;
++struct bm_mcc_query {
++      u8 __reserved2[63];
++} __packed;
++struct bm_mc_command {
++      u8 __dont_write_directly__verb;
++      union {
++              struct bm_mcc_acquire acquire;
++              struct bm_mcc_query query;
++      };
++} __packed;
++#define BM_MCC_VERB_VBIT              0x80
++#define BM_MCC_VERB_CMD_MASK          0x70    /* where the verb contains; */
++#define BM_MCC_VERB_CMD_ACQUIRE               0x10
++#define BM_MCC_VERB_CMD_QUERY         0x40
++#define BM_MCC_VERB_ACQUIRE_BUFCOUNT  0x0f    /* values 1..8 go here */
++
++/* See 1.5.3.3: "Acquire Response" */
++/* See 1.5.3.4: "Query Response" */
++struct bm_pool_state {
++      u8 __reserved1[32];
++      /* "availability state" and "depletion state" */
++      struct {
++              u8 __reserved1[8];
++              /* Access using bman_depletion_***() */
++              struct bman_depletion state;
++      } as, ds;
++};
++struct bm_mc_result {
++      union {
++              struct {
++                      u8 verb;
++                      u8 __reserved1[63];
++              };
++              union {
++                      struct {
++                              u8 __reserved1;
++                              u8 bpid;
++                              u8 __reserved2[62];
++                      };
++                      struct bm_buffer bufs[8];
++              } acquire;
++              struct bm_pool_state query;
++      };
++} __packed;
++#define BM_MCR_VERB_VBIT              0x80
++#define BM_MCR_VERB_CMD_MASK          BM_MCC_VERB_CMD_MASK
++#define BM_MCR_VERB_CMD_ACQUIRE               BM_MCC_VERB_CMD_ACQUIRE
++#define BM_MCR_VERB_CMD_QUERY         BM_MCC_VERB_CMD_QUERY
++#define BM_MCR_VERB_CMD_ERR_INVALID   0x60
++#define BM_MCR_VERB_CMD_ERR_ECC               0x70
++#define BM_MCR_VERB_ACQUIRE_BUFCOUNT  BM_MCC_VERB_ACQUIRE_BUFCOUNT /* 0..8 */
++/* Determine the "availability state" of pool 'p' from a query result 'r' */
++#define BM_MCR_QUERY_AVAILABILITY(r, p)       \
++              bman_depletion_get(&r->query.as.state, p)
++/* Determine the "depletion state" of pool 'p' from a query result 'r' */
++#define BM_MCR_QUERY_DEPLETION(r, p)  \
++              bman_depletion_get(&r->query.ds.state, p)
++
++/*******************************************************************/
++/* Managed (aka "shared" or "mux/demux") portal, high-level i/face */
++/*******************************************************************/
++
++      /* Portal and Buffer Pools */
++      /* ----------------------- */
++/* Represents a managed portal */
++struct bman_portal;
++
++/* This object type represents Bman buffer pools. */
++struct bman_pool;
++
++struct bman_portal_config {
++      /* This is used for any "core-affine" portals, ie. default portals
++       * associated to the corresponding cpu. -1 implies that there is no core
++       * affinity configured. */
++      int cpu;
++      /* portal interrupt line */
++      int irq;
++      /* the unique index of this portal */
++      u32 index;
++      /* Is this portal shared? (If so, it has coarser locking and demuxes
++       * processing on behalf of other CPUs.) */
++      int is_shared;
++      /* These are the buffer pool IDs that may be used via this portal. */
++      struct bman_depletion mask;
++};
++
++/* This callback type is used when handling pool depletion entry/exit. The
++ * 'cb_ctx' value is the opaque value associated with the pool object in
++ * bman_new_pool(). 'depleted' is non-zero on depletion-entry, and zero on
++ * depletion-exit. */
++typedef void (*bman_cb_depletion)(struct bman_portal *bm,
++                      struct bman_pool *pool, void *cb_ctx, int depleted);
++
++/* This struct specifies parameters for a bman_pool object. */
++struct bman_pool_params {
++      /* index of the buffer pool to encapsulate (0-63), ignored if
++       * BMAN_POOL_FLAG_DYNAMIC_BPID is set. */
++      u32 bpid;
++      /* bit-mask of BMAN_POOL_FLAG_*** options */
++      u32 flags;
++      /* depletion-entry/exit callback, if BMAN_POOL_FLAG_DEPLETION is set */
++      bman_cb_depletion cb;
++      /* opaque user value passed as a parameter to 'cb' */
++      void *cb_ctx;
++      /* depletion-entry/exit thresholds, if BMAN_POOL_FLAG_THRESH is set. NB:
++       * this is only allowed if BMAN_POOL_FLAG_DYNAMIC_BPID is used *and*
++       * when run in the control plane (which controls Bman CCSR). This array
++       * matches the definition of bm_pool_set(). */
++      u32 thresholds[4];
++};
++
++/* Flags to bman_new_pool() */
++#define BMAN_POOL_FLAG_NO_RELEASE    0x00000001 /* can't release to pool */
++#define BMAN_POOL_FLAG_ONLY_RELEASE  0x00000002 /* can only release to pool */
++#define BMAN_POOL_FLAG_DEPLETION     0x00000004 /* track depletion entry/exit */
++#define BMAN_POOL_FLAG_DYNAMIC_BPID  0x00000008 /* (de)allocate bpid */
++#define BMAN_POOL_FLAG_THRESH        0x00000010 /* set depletion thresholds */
++#define BMAN_POOL_FLAG_STOCKPILE     0x00000020 /* stockpile to reduce hw ops */
++
++/* Flags to bman_release() */
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++#define BMAN_RELEASE_FLAG_WAIT       0x00000001 /* wait if RCR is full */
++#define BMAN_RELEASE_FLAG_WAIT_INT   0x00000002 /* if we wait, interruptible? */
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++#define BMAN_RELEASE_FLAG_WAIT_SYNC  0x00000004 /* if wait, until consumed? */
++#endif
++#endif
++#define BMAN_RELEASE_FLAG_NOW        0x00000008 /* issue immediate release */
++
++/* Flags to bman_acquire() */
++#define BMAN_ACQUIRE_FLAG_STOCKPILE  0x00000001 /* no hw op, stockpile only */
++
++      /* Portal Management */
++      /* ----------------- */
++/**
++ * bman_get_portal_config - get portal configuration settings
++ *
++ * This returns a read-only view of the current cpu's affine portal settings.
++ */
++const struct bman_portal_config *bman_get_portal_config(void);
++
++/**
++ * bman_irqsource_get - return the portal work that is interrupt-driven
++ *
++ * Returns a bitmask of BM_PIRQ_**I processing sources that are currently
++ * enabled for interrupt handling on the current cpu's affine portal. These
++ * sources will trigger the portal interrupt and the interrupt handler (or a
++ * tasklet/bottom-half it defers to) will perform the corresponding processing
++ * work. The bman_poll_***() functions will only process sources that are not in
++ * this bitmask. If the current CPU is sharing a portal hosted on another CPU,
++ * this always returns zero.
++ */
++u32 bman_irqsource_get(void);
++
++/**
++ * bman_irqsource_add - add processing sources to be interrupt-driven
++ * @bits: bitmask of BM_PIRQ_**I processing sources
++ *
++ * Adds processing sources that should be interrupt-driven (rather than
++ * processed via bman_poll_***() functions). Returns zero for success, or
++ * -EINVAL if the current CPU is sharing a portal hosted on another CPU. */
++int bman_irqsource_add(u32 bits);
++
++/**
++ * bman_irqsource_remove - remove processing sources from being interrupt-driven
++ * @bits: bitmask of BM_PIRQ_**I processing sources
++ *
++ * Removes processing sources from being interrupt-driven, so that they will
++ * instead be processed via bman_poll_***() functions. Returns zero for success,
++ * or -EINVAL if the current CPU is sharing a portal hosted on another CPU. */
++int bman_irqsource_remove(u32 bits);
++
++/**
++ * bman_affine_cpus - return a mask of cpus that have affine portals
++ */
++const cpumask_t *bman_affine_cpus(void);
++
++/**
++ * bman_poll_slow - process anything that isn't interrupt-driven.
++ *
++ * This function does any portal processing that isn't interrupt-driven. If the
++ * current CPU is sharing a portal hosted on another CPU, this function will
++ * return -EINVAL, otherwise the return value is a bitmask of BM_PIRQ_* sources
++ * indicating what interrupt sources were actually processed by the call.
++ *
++ * NB, unlike the legacy wrapper bman_poll(), this function will
++ * deterministically check for the presence of portal processing work and do it,
++ * which implies some latency even if there's nothing to do. The bman_poll()
++ * wrapper on the other hand (like the qman_poll() wrapper) attenuates this by
++ * checking for (and doing) portal processing infrequently. Ie. such that
++ * qman_poll() and bman_poll() can be called from core-processing loops. Use
++ * bman_poll_slow() when you yourself are deciding when to incur the overhead of
++ * processing.
++ */
++u32 bman_poll_slow(void);
++
++/**
++ * bman_poll - process anything that isn't interrupt-driven.
++ *
++ * Dispatcher logic on a cpu can use this to trigger any maintenance of the
++ * affine portal. This function does whatever processing is not triggered by
++ * interrupts. This is a legacy wrapper that can be used in core-processing
++ * loops but mitigates the performance overhead of portal processing by
++ * adaptively bypassing true portal processing most of the time. (Processing is
++ * done once every 10 calls if the previous processing revealed that work needed
++ * to be done, or once very 1000 calls if the previous processing revealed no
++ * work needed doing.) If you wish to control this yourself, call
++ * bman_poll_slow() instead, which always checks for portal processing work.
++ */
++void bman_poll(void);
++
++/**
++ * bman_rcr_is_empty - Determine if portal's RCR is empty
++ *
++ * For use in situations where a cpu-affine caller needs to determine when all
++ * releases for the local portal have been processed by Bman but can't use the
++ * BMAN_RELEASE_FLAG_WAIT_SYNC flag to do this from the final bman_release().
++ * The function forces tracking of RCR consumption (which normally doesn't
++ * happen until release processing needs to find space to put new release
++ * commands), and returns zero if the ring still has unprocessed entries,
++ * non-zero if it is empty.
++ */
++int bman_rcr_is_empty(void);
++
++/**
++ * bman_alloc_bpid_range - Allocate a contiguous range of BPIDs
++ * @result: is set by the API to the base BPID of the allocated range
++ * @count: the number of BPIDs required
++ * @align: required alignment of the allocated range
++ * @partial: non-zero if the API can return fewer than @count BPIDs
++ *
++ * Returns the number of buffer pools allocated, or a negative error code. If
++ * @partial is non zero, the allocation request may return a smaller range of
++ * BPs than requested (though alignment will be as requested). If @partial is
++ * zero, the return value will either be 'count' or negative.
++ */
++int bman_alloc_bpid_range(u32 *result, u32 count, u32 align, int partial);
++static inline int bman_alloc_bpid(u32 *result)
++{
++      int ret = bman_alloc_bpid_range(result, 1, 0, 0);
++      return (ret > 0) ? 0 : ret;
++}
++
++/**
++ * bman_release_bpid_range - Release the specified range of buffer pool IDs
++ * @bpid: the base BPID of the range to deallocate
++ * @count: the number of BPIDs in the range
++ *
++ * This function can also be used to seed the allocator with ranges of BPIDs
++ * that it can subsequently allocate from.
++ */
++void bman_release_bpid_range(u32 bpid, unsigned int count);
++static inline void bman_release_bpid(u32 bpid)
++{
++      bman_release_bpid_range(bpid, 1);
++}
++
++int bman_reserve_bpid_range(u32 bpid, unsigned int count);
++static inline int bman_reserve_bpid(u32 bpid)
++{
++      return bman_reserve_bpid_range(bpid, 1);
++}
++
++void bman_seed_bpid_range(u32 bpid, unsigned int count);
++
++
++int bman_shutdown_pool(u32 bpid);
++
++      /* Pool management */
++      /* --------------- */
++/**
++ * bman_new_pool - Allocates a Buffer Pool object
++ * @params: parameters specifying the buffer pool ID and behaviour
++ *
++ * Creates a pool object for the given @params. A portal and the depletion
++ * callback field of @params are only used if the BMAN_POOL_FLAG_DEPLETION flag
++ * is set. NB, the fields from @params are copied into the new pool object, so
++ * the structure provided by the caller can be released or reused after the
++ * function returns.
++ */
++struct bman_pool *bman_new_pool(const struct bman_pool_params *params);
++
++/**
++ * bman_free_pool - Deallocates a Buffer Pool object
++ * @pool: the pool object to release
++ *
++ */
++void bman_free_pool(struct bman_pool *pool);
++
++/**
++ * bman_get_params - Returns a pool object's parameters.
++ * @pool: the pool object
++ *
++ * The returned pointer refers to state within the pool object so must not be
++ * modified and can no longer be read once the pool object is destroyed.
++ */
++const struct bman_pool_params *bman_get_params(const struct bman_pool *pool);
++
++/**
++ * bman_release - Release buffer(s) to the buffer pool
++ * @pool: the buffer pool object to release to
++ * @bufs: an array of buffers to release
++ * @num: the number of buffers in @bufs (1-8)
++ * @flags: bit-mask of BMAN_RELEASE_FLAG_*** options
++ *
++ * Adds the given buffers to RCR entries. If the portal @p was created with the
++ * "COMPACT" flag, then it will be using a compaction algorithm to improve
++ * utilisation of RCR. As such, these buffers may join an existing ring entry
++ * and/or it may not be issued right away so as to allow future releases to join
++ * the same ring entry. Use the BMAN_RELEASE_FLAG_NOW flag to override this
++ * behaviour by committing the RCR entry (or entries) right away. If the RCR
++ * ring is full, the function will return -EBUSY unless BMAN_RELEASE_FLAG_WAIT
++ * is selected, in which case it will sleep waiting for space to become
++ * available in RCR. If the function receives a signal before such time (and
++ * BMAN_RELEASE_FLAG_WAIT_INT is set), the function returns -EINTR. Otherwise,
++ * it returns zero.
++ */
++int bman_release(struct bman_pool *pool, const struct bm_buffer *bufs, u8 num,
++                      u32 flags);
++
++/**
++ * bman_acquire - Acquire buffer(s) from a buffer pool
++ * @pool: the buffer pool object to acquire from
++ * @bufs: array for storing the acquired buffers
++ * @num: the number of buffers desired (@bufs is at least this big)
++ *
++ * Issues an "Acquire" command via the portal's management command interface.
++ * The return value will be the number of buffers obtained from the pool, or a
++ * negative error code if a h/w error or pool starvation was encountered. In
++ * the latter case, the content of @bufs is undefined.
++ */
++int bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num,
++                      u32 flags);
++
++/**
++ * bman_flush_stockpile - Flush stockpile buffer(s) to the buffer pool
++ * @pool: the buffer pool object the stockpile belongs
++ * @flags: bit-mask of BMAN_RELEASE_FLAG_*** options
++ *
++ * Adds stockpile buffers to RCR entries until the stockpile is empty.
++ * The return value will be a negative error code if a h/w error occurred.
++ * If BMAN_RELEASE_FLAG_NOW flag is passed and RCR ring is full,
++ * -EAGAIN will be returned.
++ */
++int bman_flush_stockpile(struct bman_pool *pool, u32 flags);
++
++/**
++ * bman_query_pools - Query all buffer pool states
++ * @state: storage for the queried availability and depletion states
++ */
++int bman_query_pools(struct bm_pool_state *state);
++
++#ifdef CONFIG_FSL_BMAN_CONFIG
++/**
++ * bman_query_free_buffers - Query how many free buffers are in buffer pool
++ * @pool: the buffer pool object to query
++ *
++ * Return the number of the free buffers
++ */
++u32 bman_query_free_buffers(struct bman_pool *pool);
++
++/**
++ * bman_update_pool_thresholds - Change the buffer pool's depletion thresholds
++ * @pool: the buffer pool object to which the thresholds will be set
++ * @thresholds: the new thresholds
++ */
++int bman_update_pool_thresholds(struct bman_pool *pool, const u32 *thresholds);
++#endif
++
++/**
++ * The below bman_p_***() variant might be called in a situation that the cpu
++ * which the portal affine to is not online yet.
++ * @bman_portal specifies which portal the API will use.
++*/
++int bman_p_irqsource_add(struct bman_portal *p, __maybe_unused u32 bits);
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* FSL_BMAN_H */
+--- /dev/null
++++ b/include/linux/fsl_qman.h
+@@ -0,0 +1,3888 @@
++/* Copyright 2008-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef FSL_QMAN_H
++#define FSL_QMAN_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* Last updated for v00.800 of the BG */
++
++/* Hardware constants */
++#define QM_CHANNEL_SWPORTAL0 0
++#define QMAN_CHANNEL_POOL1 0x21
++#define QMAN_CHANNEL_CAAM 0x80
++#define QMAN_CHANNEL_PME 0xa0
++#define QMAN_CHANNEL_POOL1_REV3 0x401
++#define QMAN_CHANNEL_CAAM_REV3 0x840
++#define QMAN_CHANNEL_PME_REV3 0x860
++#define QMAN_CHANNEL_DCE 0x8a0
++#define QMAN_CHANNEL_DCE_QMANREV312 0x880
++extern u16 qm_channel_pool1;
++extern u16 qm_channel_caam;
++extern u16 qm_channel_pme;
++extern u16 qm_channel_dce;
++enum qm_dc_portal {
++      qm_dc_portal_fman0 = 0,
++      qm_dc_portal_fman1 = 1,
++      qm_dc_portal_caam = 2,
++      qm_dc_portal_pme = 3,
++      qm_dc_portal_rman = 4,
++      qm_dc_portal_dce = 5
++};
++
++/* Portal processing (interrupt) sources */
++#define QM_PIRQ_CCSCI 0x00200000      /* CEETM Congestion State Change */
++#define QM_PIRQ_CSCI  0x00100000      /* Congestion State Change */
++#define QM_PIRQ_EQCI  0x00080000      /* Enqueue Command Committed */
++#define QM_PIRQ_EQRI  0x00040000      /* EQCR Ring (below threshold) */
++#define QM_PIRQ_DQRI  0x00020000      /* DQRR Ring (non-empty) */
++#define QM_PIRQ_MRI   0x00010000      /* MR Ring (non-empty) */
++/* This mask contains all the interrupt sources that need handling except DQRI,
++ * ie. that if present should trigger slow-path processing. */
++#define QM_PIRQ_SLOW  (QM_PIRQ_CSCI | QM_PIRQ_EQCI | QM_PIRQ_EQRI | \
++                      QM_PIRQ_MRI | QM_PIRQ_CCSCI)
++
++/* --- Clock speed --- */
++/* A qman driver instance may or may not know the current qman clock speed.
++ * However, certain CEETM calculations may not be possible if this is not known.
++ * The 'set' function will only succeed (return zero) if the driver did not
++ * already know the clock speed. Likewise, the 'get' function will only succeed
++ * if the driver does know the clock speed (either because it knew when booting,
++ * or was told via 'set'). In cases where software is running on a driver
++ * instance that does not know the clock speed (eg. on a hypervised data-plane),
++ * and the user can obtain the current qman clock speed by other means (eg. from
++ * a message sent from the control-plane), then the 'set' function can be used
++ * to enable rate-calculations in a driver where it would otherwise not be
++ * possible. */
++int qm_get_clock(u64 *clock_hz);
++int qm_set_clock(u64 clock_hz);
++
++/* For qman_static_dequeue_*** APIs */
++#define QM_SDQCR_CHANNELS_POOL_MASK   0x00007fff
++/* for n in [1,15] */
++#define QM_SDQCR_CHANNELS_POOL(n)     (0x00008000 >> (n))
++/* for conversion from n of qm_channel */
++static inline u32 QM_SDQCR_CHANNELS_POOL_CONV(u16 channel)
++{
++      return QM_SDQCR_CHANNELS_POOL(channel + 1 - qm_channel_pool1);
++}
++
++/* For qman_volatile_dequeue(); Choose one PRECEDENCE. EXACT is optional. Use
++ * NUMFRAMES(n) (6-bit) or NUMFRAMES_TILLEMPTY to fill in the frame-count. Use
++ * FQID(n) to fill in the frame queue ID. */
++#define QM_VDQCR_PRECEDENCE_VDQCR     0x0
++#define QM_VDQCR_PRECEDENCE_SDQCR     0x80000000
++#define QM_VDQCR_EXACT                        0x40000000
++#define QM_VDQCR_NUMFRAMES_MASK               0x3f000000
++#define QM_VDQCR_NUMFRAMES_SET(n)     (((n) & 0x3f) << 24)
++#define QM_VDQCR_NUMFRAMES_GET(n)     (((n) >> 24) & 0x3f)
++#define QM_VDQCR_NUMFRAMES_TILLEMPTY  QM_VDQCR_NUMFRAMES_SET(0)
++
++
++/* ------------------------------------------------------- */
++/* --- Qman data structures (and associated constants) --- */
++
++/* Represents s/w corenet portal mapped data structures */
++struct qm_eqcr_entry; /* EQCR (EnQueue Command Ring) entries */
++struct qm_dqrr_entry; /* DQRR (DeQueue Response Ring) entries */
++struct qm_mr_entry;   /* MR (Message Ring) entries */
++struct qm_mc_command; /* MC (Management Command) command */
++struct qm_mc_result;  /* MC result */
++
++/* See David Lapp's "Frame formats" document, "dpateam", Jan 07, 2008 */
++#define QM_FD_FORMAT_SG               0x4
++#define QM_FD_FORMAT_LONG     0x2
++#define QM_FD_FORMAT_COMPOUND 0x1
++enum qm_fd_format {
++      /* 'contig' implies a contiguous buffer, whereas 'sg' implies a
++       * scatter-gather table. 'big' implies a 29-bit length with no offset
++       * field, otherwise length is 20-bit and offset is 9-bit. 'compound'
++       * implies a s/g-like table, where each entry itself represents a frame
++       * (contiguous or scatter-gather) and the 29-bit "length" is
++       * interpreted purely for congestion calculations, ie. a "congestion
++       * weight". */
++      qm_fd_contig = 0,
++      qm_fd_contig_big = QM_FD_FORMAT_LONG,
++      qm_fd_sg = QM_FD_FORMAT_SG,
++      qm_fd_sg_big = QM_FD_FORMAT_SG | QM_FD_FORMAT_LONG,
++      qm_fd_compound = QM_FD_FORMAT_COMPOUND
++};
++
++/* Capitalised versions are un-typed but can be used in static expressions */
++#define QM_FD_CONTIG  0
++#define QM_FD_CONTIG_BIG QM_FD_FORMAT_LONG
++#define QM_FD_SG      QM_FD_FORMAT_SG
++#define QM_FD_SG_BIG  (QM_FD_FORMAT_SG | QM_FD_FORMAT_LONG)
++#define QM_FD_COMPOUND        QM_FD_FORMAT_COMPOUND
++
++/* See 1.5.1.1: "Frame Descriptor (FD)" */
++struct qm_fd {
++      union {
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u8 dd:2;        /* dynamic debug */
++                      u8 liodn_offset:6;
++                      u8 bpid:8;      /* Buffer Pool ID */
++                      u8 eliodn_offset:4;
++                      u8 __reserved:4;
++                      u8 addr_hi;     /* high 8-bits of 40-bit address */
++                      u32 addr_lo;    /* low 32-bits of 40-bit address */
++#else
++                      u32 addr_lo;    /* low 32-bits of 40-bit address */
++                      u8 addr_hi;     /* high 8-bits of 40-bit address */
++                      u8 __reserved:4;
++                      u8 eliodn_offset:4;
++                      u8 bpid:8;      /* Buffer Pool ID */
++                      u8 liodn_offset:6;
++                      u8 dd:2;        /* dynamic debug */
++#endif
++              };
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u64 __notaddress:24;
++                      u64 addr:40;
++#else
++                      u64 addr:40;
++                      u64 __notaddress:24;
++#endif
++              };
++              u64 opaque_addr;
++      };
++      /* The 'format' field indicates the interpretation of the remaining 29
++       * bits of the 32-bit word. For packing reasons, it is duplicated in the
++       * other union elements. Note, union'd structs are difficult to use with
++       * static initialisation under gcc, in which case use the "opaque" form
++       * with one of the macros. */
++      union {
++              /* For easier/faster copying of this part of the fd (eg. from a
++               * DQRR entry to an EQCR entry) copy 'opaque' */
++              u32 opaque;
++              /* If 'format' is _contig or _sg, 20b length and 9b offset */
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      enum qm_fd_format format:3;
++                      u16 offset:9;
++                      u32 length20:20;
++#else
++                      u32 length20:20;
++                      u16 offset:9;
++                      enum qm_fd_format format:3;
++#endif
++              };
++              /* If 'format' is _contig_big or _sg_big, 29b length */
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      enum qm_fd_format _format1:3;
++                      u32 length29:29;
++#else
++                      u32 length29:29;
++                      enum qm_fd_format _format1:3;
++#endif
++              };
++              /* If 'format' is _compound, 29b "congestion weight" */
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      enum qm_fd_format _format2:3;
++                      u32 cong_weight:29;
++#else
++                      u32 cong_weight:29;
++                      enum qm_fd_format _format2:3;
++#endif
++              };
++      };
++      union {
++              u32 cmd;
++              u32 status;
++      };
++} __aligned(8);
++#define QM_FD_DD_NULL         0x00
++#define QM_FD_PID_MASK                0x3f
++static inline u64 qm_fd_addr_get64(const struct qm_fd *fd)
++{
++      return fd->addr;
++}
++
++static inline dma_addr_t qm_fd_addr(const struct qm_fd *fd)
++{
++      return (dma_addr_t)fd->addr;
++}
++/* Macro, so we compile better if 'v' isn't always 64-bit */
++#define qm_fd_addr_set64(fd, v) \
++      do { \
++              struct qm_fd *__fd931 = (fd); \
++              __fd931->addr = v; \
++      } while (0)
++
++/* For static initialisation of FDs (which is complicated by the use of unions
++ * in "struct qm_fd"), use the following macros. Note that;
++ * - 'dd', 'pid' and 'bpid' are ignored because there's no static initialisation
++ *   use-case),
++ * - use capitalised QM_FD_*** formats for static initialisation.
++ */
++#define QM_FD_FMT_20(cmd, addr_hi, addr_lo, fmt, off, len) \
++      { 0, 0, 0, 0, 0, addr_hi, addr_lo, \
++      { (((fmt)&0x7) << 29) | (((off)&0x1ff) << 20) | ((len)&0xfffff) }, \
++      { cmd } }
++#define QM_FD_FMT_29(cmd, addr_hi, addr_lo, fmt, len) \
++      { 0, 0, 0, 0, 0, addr_hi, addr_lo, \
++      { (((fmt)&0x7) << 29) | ((len)&0x1fffffff) }, \
++      { cmd } }
++
++/* See 2.2.1.3 Multi-Core Datapath Acceleration Architecture */
++#define QM_SG_OFFSET_MASK 0x1FFF
++struct qm_sg_entry {
++      union {
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u8 __reserved1[3];
++                      u8 addr_hi;     /* high 8-bits of 40-bit address */
++                      u32 addr_lo;    /* low 32-bits of 40-bit address */
++#else
++                      u32 addr_lo;    /* low 32-bits of 40-bit address */
++                      u8 addr_hi;     /* high 8-bits of 40-bit address */
++                      u8 __reserved1[3];
++#endif
++              };
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u64 __notaddress:24;
++                      u64 addr:40;
++#else
++                      u64 addr:40;
++                      u64 __notaddress:24;
++#endif
++              };
++              u64 opaque;
++      };
++      union {
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u32 extension:1;        /* Extension bit */
++                      u32 final:1;            /* Final bit */
++                      u32 length:30;
++#else
++                      u32 length:30;
++                      u32 final:1;            /* Final bit */
++                      u32 extension:1;        /* Extension bit */
++#endif
++              };
++              u32 sgt_efl;
++      };
++      u8 __reserved2;
++      u8 bpid;
++      union {
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u16 __reserved3:3;
++                      u16 offset:13;
++#else
++                      u16 offset:13;
++                      u16 __reserved3:3;
++#endif
++              };
++              u16 opaque_offset;
++      };
++} __packed;
++union qm_sg_efl {
++      struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++              u32 extension:1;        /* Extension bit */
++              u32 final:1;            /* Final bit */
++              u32 length:30;
++#else
++              u32 length:30;
++              u32 final:1;            /* Final bit */
++              u32 extension:1;        /* Extension bit */
++#endif
++      };
++      u32 efl;
++};
++static inline dma_addr_t qm_sg_addr(const struct qm_sg_entry *sg)
++{
++      return (dma_addr_t)be64_to_cpu(sg->opaque) & 0xffffffffffULL;
++}
++static inline u8 qm_sg_entry_get_ext(const struct qm_sg_entry *sg)
++{
++      union qm_sg_efl u;
++
++      u.efl = be32_to_cpu(sg->sgt_efl);
++      return u.extension;
++}
++static inline u8 qm_sg_entry_get_final(const struct qm_sg_entry *sg)
++{
++      union qm_sg_efl u;
++
++      u.efl = be32_to_cpu(sg->sgt_efl);
++      return u.final;
++}
++static inline u32 qm_sg_entry_get_len(const struct qm_sg_entry *sg)
++{
++      union qm_sg_efl u;
++
++      u.efl = be32_to_cpu(sg->sgt_efl);
++      return u.length;
++}
++static inline u8 qm_sg_entry_get_bpid(const struct qm_sg_entry *sg)
++{
++      return sg->bpid;
++}
++static inline u16 qm_sg_entry_get_offset(const struct qm_sg_entry *sg)
++{
++      u32 opaque_offset = be16_to_cpu(sg->opaque_offset);
++
++      return opaque_offset & 0x1fff;
++}
++
++/* Macro, so we compile better if 'v' isn't always 64-bit */
++#define qm_sg_entry_set64(sg, v) \
++      do { \
++              struct qm_sg_entry *__sg931 = (sg); \
++              __sg931->opaque = cpu_to_be64(v); \
++      } while (0)
++#define qm_sg_entry_set_ext(sg, v) \
++      do { \
++              union qm_sg_efl __u932; \
++              __u932.efl = be32_to_cpu((sg)->sgt_efl); \
++              __u932.extension = v; \
++              (sg)->sgt_efl = cpu_to_be32(__u932.efl); \
++      } while (0)
++#define qm_sg_entry_set_final(sg, v) \
++      do { \
++              union qm_sg_efl __u933; \
++              __u933.efl = be32_to_cpu((sg)->sgt_efl); \
++              __u933.final = v; \
++              (sg)->sgt_efl = cpu_to_be32(__u933.efl); \
++      } while (0)
++#define qm_sg_entry_set_len(sg, v) \
++      do { \
++              union qm_sg_efl __u934; \
++              __u934.efl = be32_to_cpu((sg)->sgt_efl); \
++              __u934.length = v; \
++              (sg)->sgt_efl = cpu_to_be32(__u934.efl); \
++      } while (0)
++#define qm_sg_entry_set_bpid(sg, v) \
++      do { \
++              struct qm_sg_entry *__u935 = (sg); \
++              __u935->bpid = v; \
++      } while (0)
++#define qm_sg_entry_set_offset(sg, v) \
++      do { \
++              struct qm_sg_entry *__u936 = (sg); \
++              __u936->opaque_offset = cpu_to_be16(v); \
++      } while (0)
++
++/* See 1.5.8.1: "Enqueue Command" */
++struct qm_eqcr_entry {
++      u8 __dont_write_directly__verb;
++      u8 dca;
++      u16 seqnum;
++      u32 orp;        /* 24-bit */
++      u32 fqid;       /* 24-bit */
++      u32 tag;
++      struct qm_fd fd;
++      u8 __reserved3[32];
++} __packed;
++#define QM_EQCR_VERB_VBIT             0x80
++#define QM_EQCR_VERB_CMD_MASK         0x61    /* but only one value; */
++#define QM_EQCR_VERB_CMD_ENQUEUE      0x01
++#define QM_EQCR_VERB_COLOUR_MASK      0x18    /* 4 possible values; */
++#define QM_EQCR_VERB_COLOUR_GREEN     0x00
++#define QM_EQCR_VERB_COLOUR_YELLOW    0x08
++#define QM_EQCR_VERB_COLOUR_RED               0x10
++#define QM_EQCR_VERB_COLOUR_OVERRIDE  0x18
++#define QM_EQCR_VERB_INTERRUPT                0x04    /* on command consumption */
++#define QM_EQCR_VERB_ORP              0x02    /* enable order restoration */
++#define QM_EQCR_DCA_ENABLE            0x80
++#define QM_EQCR_DCA_PARK              0x40
++#define QM_EQCR_DCA_IDXMASK           0x0f    /* "DQRR::idx" goes here */
++#define QM_EQCR_SEQNUM_NESN           0x8000  /* Advance NESN */
++#define QM_EQCR_SEQNUM_NLIS           0x4000  /* More fragments to come */
++#define QM_EQCR_SEQNUM_SEQMASK                0x3fff  /* sequence number goes here */
++#define QM_EQCR_FQID_NULL             0       /* eg. for an ORP seqnum hole */
++
++/* See 1.5.8.2: "Frame Dequeue Response" */
++struct qm_dqrr_entry {
++      u8 verb;
++      u8 stat;
++      u16 seqnum;     /* 15-bit */
++      u8 tok;
++      u8 __reserved2[3];
++      u32 fqid;       /* 24-bit */
++      u32 contextB;
++      struct qm_fd fd;
++      u8 __reserved4[32];
++};
++#define QM_DQRR_VERB_VBIT             0x80
++#define QM_DQRR_VERB_MASK             0x7f    /* where the verb contains; */
++#define QM_DQRR_VERB_FRAME_DEQUEUE    0x60    /* "this format" */
++#define QM_DQRR_STAT_FQ_EMPTY         0x80    /* FQ empty */
++#define QM_DQRR_STAT_FQ_HELDACTIVE    0x40    /* FQ held active */
++#define QM_DQRR_STAT_FQ_FORCEELIGIBLE 0x20    /* FQ was force-eligible'd */
++#define QM_DQRR_STAT_FD_VALID         0x10    /* has a non-NULL FD */
++#define QM_DQRR_STAT_UNSCHEDULED      0x02    /* Unscheduled dequeue */
++#define QM_DQRR_STAT_DQCR_EXPIRED     0x01    /* VDQCR or PDQCR expired*/
++
++/* See 1.5.8.3: "ERN Message Response" */
++/* See 1.5.8.4: "FQ State Change Notification" */
++struct qm_mr_entry {
++      u8 verb;
++      union {
++              struct {
++                      u8 dca;
++                      u16 seqnum;
++                      u8 rc;          /* Rejection Code */
++                      u32 orp:24;
++                      u32 fqid;       /* 24-bit */
++                      u32 tag;
++                      struct qm_fd fd;
++              } __packed ern;
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u8 colour:2;    /* See QM_MR_DCERN_COLOUR_* */
++                      u8 __reserved1:3;
++                      enum qm_dc_portal portal:3;
++#else
++                      enum qm_dc_portal portal:3;
++                      u8 __reserved1:3;
++                      u8 colour:2;    /* See QM_MR_DCERN_COLOUR_* */
++#endif
++                      u16 __reserved2;
++                      u8 rc;          /* Rejection Code */
++                      u32 __reserved3:24;
++                      u32 fqid;       /* 24-bit */
++                      u32 tag;
++                      struct qm_fd fd;
++              } __packed dcern;
++              struct {
++                      u8 fqs;         /* Frame Queue Status */
++                      u8 __reserved1[6];
++                      u32 fqid;       /* 24-bit */
++                      u32 contextB;
++                      u8 __reserved2[16];
++              } __packed fq;          /* FQRN/FQRNI/FQRL/FQPN */
++      };
++      u8 __reserved2[32];
++} __packed;
++#define QM_MR_VERB_VBIT                       0x80
++/* The "ern" VERB bits match QM_EQCR_VERB_*** so aren't reproduced here. ERNs
++ * originating from direct-connect portals ("dcern") use 0x20 as a verb which
++ * would be invalid as a s/w enqueue verb. A s/w ERN can be distinguished from
++ * the other MR types by noting if the 0x20 bit is unset. */
++#define QM_MR_VERB_TYPE_MASK          0x27
++#define QM_MR_VERB_DC_ERN             0x20
++#define QM_MR_VERB_FQRN                       0x21
++#define QM_MR_VERB_FQRNI              0x22
++#define QM_MR_VERB_FQRL                       0x23
++#define QM_MR_VERB_FQPN                       0x24
++#define QM_MR_RC_MASK                 0xf0    /* contains one of; */
++#define QM_MR_RC_CGR_TAILDROP         0x00
++#define QM_MR_RC_WRED                 0x10
++#define QM_MR_RC_ERROR                        0x20
++#define QM_MR_RC_ORPWINDOW_EARLY      0x30
++#define QM_MR_RC_ORPWINDOW_LATE               0x40
++#define QM_MR_RC_FQ_TAILDROP          0x50
++#define QM_MR_RC_ORPWINDOW_RETIRED    0x60
++#define QM_MR_RC_ORP_ZERO             0x70
++#define QM_MR_FQS_ORLPRESENT          0x02    /* ORL fragments to come */
++#define QM_MR_FQS_NOTEMPTY            0x01    /* FQ has enqueued frames */
++#define QM_MR_DCERN_COLOUR_GREEN      0x00
++#define QM_MR_DCERN_COLOUR_YELLOW     0x01
++#define QM_MR_DCERN_COLOUR_RED                0x02
++#define QM_MR_DCERN_COLOUR_OVERRIDE   0x03
++
++/* An identical structure of FQD fields is present in the "Init FQ" command and
++ * the "Query FQ" result, it's suctioned out into the "struct qm_fqd" type.
++ * Within that, the 'stashing' and 'taildrop' pieces are also factored out, the
++ * latter has two inlines to assist with converting to/from the mant+exp
++ * representation. */
++struct qm_fqd_stashing {
++      /* See QM_STASHING_EXCL_<...> */
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++      u8 exclusive;
++      u8 __reserved1:2;
++      /* Numbers of cachelines */
++      u8 annotation_cl:2;
++      u8 data_cl:2;
++      u8 context_cl:2;
++#else
++      u8 context_cl:2;
++      u8 data_cl:2;
++      u8 annotation_cl:2;
++      u8 __reserved1:2;
++      u8 exclusive;
++#endif
++} __packed;
++struct qm_fqd_taildrop {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++      u16 __reserved1:3;
++      u16 mant:8;
++      u16 exp:5;
++#else
++      u16 exp:5;
++      u16 mant:8;
++      u16 __reserved1:3;
++#endif
++} __packed;
++struct qm_fqd_oac {
++      /* See QM_OAC_<...> */
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++      u8 oac:2; /* "Overhead Accounting Control" */
++      u8 __reserved1:6;
++#else
++      u8 __reserved1:6;
++      u8 oac:2; /* "Overhead Accounting Control" */
++#endif
++      /* Two's-complement value (-128 to +127) */
++      signed char oal; /* "Overhead Accounting Length" */
++} __packed;
++struct qm_fqd {
++      union {
++              u8 orpc;
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u8 __reserved1:2;
++                      u8 orprws:3;
++                      u8 oa:1;
++                      u8 olws:2;
++#else
++                      u8 olws:2;
++                      u8 oa:1;
++                      u8 orprws:3;
++                      u8 __reserved1:2;
++#endif
++              } __packed;
++      };
++      u8 cgid;
++      u16 fq_ctrl;    /* See QM_FQCTRL_<...> */
++      union {
++              u16 dest_wq;
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u16 channel:13; /* qm_channel */
++                      u16 wq:3;
++#else
++                      u16 wq:3;
++                      u16 channel:13; /* qm_channel */
++#endif
++              } __packed dest;
++      };
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++      u16 __reserved2:1;
++      u16 ics_cred:15;
++#else
++      u16 __reserved2:1;
++      u16 ics_cred:15;
++#endif
++      /* For "Initialize Frame Queue" commands, the write-enable mask
++       * determines whether 'td' or 'oac_init' is observed. For query
++       * commands, this field is always 'td', and 'oac_query' (below) reflects
++       * the Overhead ACcounting values. */
++      union {
++              struct qm_fqd_taildrop td;
++              struct qm_fqd_oac oac_init;
++      };
++      u32 context_b;
++      union {
++              /* Treat it as 64-bit opaque */
++              u64 opaque;
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u32 hi;
++                      u32 lo;
++#else
++                      u32 lo;
++                      u32 hi;
++#endif
++              };
++              /* Treat it as s/w portal stashing config */
++              /* See 1.5.6.7.1: "FQD Context_A field used for [...] */
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      struct qm_fqd_stashing stashing;
++                      /* 48-bit address of FQ context to
++                       * stash, must be cacheline-aligned */
++                      u16 context_hi;
++                      u32 context_lo;
++#else
++                      u32 context_lo;
++                      u16 context_hi;
++                      struct qm_fqd_stashing stashing;
++#endif
++              } __packed;
++      } context_a;
++      struct qm_fqd_oac oac_query;
++} __packed;
++/* 64-bit converters for context_hi/lo */
++static inline u64 qm_fqd_stashing_get64(const struct qm_fqd *fqd)
++{
++      return ((u64)fqd->context_a.context_hi << 32) |
++              (u64)fqd->context_a.context_lo;
++}
++static inline dma_addr_t qm_fqd_stashing_addr(const struct qm_fqd *fqd)
++{
++      return (dma_addr_t)qm_fqd_stashing_get64(fqd);
++}
++static inline u64 qm_fqd_context_a_get64(const struct qm_fqd *fqd)
++{
++      return ((u64)fqd->context_a.hi << 32) |
++              (u64)fqd->context_a.lo;
++}
++/* Macro, so we compile better when 'v' isn't necessarily 64-bit */
++#define qm_fqd_stashing_set64(fqd, v) \
++      do { \
++              struct qm_fqd *__fqd931 = (fqd); \
++              __fqd931->context_a.context_hi = upper_32_bits(v); \
++              __fqd931->context_a.context_lo = lower_32_bits(v); \
++      } while (0)
++#define qm_fqd_context_a_set64(fqd, v) \
++      do { \
++              struct qm_fqd *__fqd931 = (fqd); \
++              __fqd931->context_a.hi = upper_32_bits(v); \
++              __fqd931->context_a.lo = lower_32_bits(v); \
++      } while (0)
++/* convert a threshold value into mant+exp representation */
++static inline int qm_fqd_taildrop_set(struct qm_fqd_taildrop *td, u32 val,
++                                      int roundup)
++{
++      u32 e = 0;
++      int oddbit = 0;
++      if (val > 0xe0000000)
++              return -ERANGE;
++      while (val > 0xff) {
++              oddbit = val & 1;
++              val >>= 1;
++              e++;
++              if (roundup && oddbit)
++                      val++;
++      }
++      td->exp = e;
++      td->mant = val;
++      return 0;
++}
++/* and the other direction */
++static inline u32 qm_fqd_taildrop_get(const struct qm_fqd_taildrop *td)
++{
++      return (u32)td->mant << td->exp;
++}
++
++/* See 1.5.2.2: "Frame Queue Descriptor (FQD)" */
++/* Frame Queue Descriptor (FQD) field 'fq_ctrl' uses these constants */
++#define QM_FQCTRL_MASK                0x07ff  /* 'fq_ctrl' flags; */
++#define QM_FQCTRL_CGE         0x0400  /* Congestion Group Enable */
++#define QM_FQCTRL_TDE         0x0200  /* Tail-Drop Enable */
++#define QM_FQCTRL_ORP         0x0100  /* ORP Enable */
++#define QM_FQCTRL_CTXASTASHING        0x0080  /* Context-A stashing */
++#define QM_FQCTRL_CPCSTASH    0x0040  /* CPC Stash Enable */
++#define QM_FQCTRL_FORCESFDR   0x0008  /* High-priority SFDRs */
++#define QM_FQCTRL_AVOIDBLOCK  0x0004  /* Don't block active */
++#define QM_FQCTRL_HOLDACTIVE  0x0002  /* Hold active in portal */
++#define QM_FQCTRL_PREFERINCACHE       0x0001  /* Aggressively cache FQD */
++#define QM_FQCTRL_LOCKINCACHE QM_FQCTRL_PREFERINCACHE /* older naming */
++
++/* See 1.5.6.7.1: "FQD Context_A field used for [...] */
++/* Frame Queue Descriptor (FQD) field 'CONTEXT_A' uses these constants */
++#define QM_STASHING_EXCL_ANNOTATION   0x04
++#define QM_STASHING_EXCL_DATA         0x02
++#define QM_STASHING_EXCL_CTX          0x01
++
++/* See 1.5.5.3: "Intra Class Scheduling" */
++/* FQD field 'OAC' (Overhead ACcounting) uses these constants */
++#define QM_OAC_ICS            0x2 /* Accounting for Intra-Class Scheduling */
++#define QM_OAC_CG             0x1 /* Accounting for Congestion Groups */
++
++/* See 1.5.8.4: "FQ State Change Notification" */
++/* This struct represents the 32-bit "WR_PARM_[GYR]" parameters in CGR fields
++ * and associated commands/responses. The WRED parameters are calculated from
++ * these fields as follows;
++ *   MaxTH = MA * (2 ^ Mn)
++ *   Slope = SA / (2 ^ Sn)
++ *    MaxP = 4 * (Pn + 1)
++ */
++struct qm_cgr_wr_parm {
++      union {
++              u32 word;
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u32 MA:8;
++                      u32 Mn:5;
++                      u32 SA:7; /* must be between 64-127 */
++                      u32 Sn:6;
++                      u32 Pn:6;
++#else
++                      u32 Pn:6;
++                      u32 Sn:6;
++                      u32 SA:7; /* must be between 64-127 */
++                      u32 Mn:5;
++                      u32 MA:8;
++#endif
++              } __packed;
++      };
++} __packed;
++/* This struct represents the 13-bit "CS_THRES" CGR field. In the corresponding
++ * management commands, this is padded to a 16-bit structure field, so that's
++ * how we represent it here. The congestion state threshold is calculated from
++ * these fields as follows;
++ *   CS threshold = TA * (2 ^ Tn)
++ */
++struct qm_cgr_cs_thres {
++      union {
++              u16 hword;
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u16 __reserved:3;
++                      u16 TA:8;
++                      u16 Tn:5;
++#else
++                      u16 Tn:5;
++                      u16 TA:8;
++                      u16 __reserved:3;
++#endif
++              } __packed;
++      };
++} __packed;
++/* This identical structure of CGR fields is present in the "Init/Modify CGR"
++ * commands and the "Query CGR" result. It's suctioned out here into its own
++ * struct. */
++struct __qm_mc_cgr {
++      struct qm_cgr_wr_parm wr_parm_g;
++      struct qm_cgr_wr_parm wr_parm_y;
++      struct qm_cgr_wr_parm wr_parm_r;
++      u8 wr_en_g;     /* boolean, use QM_CGR_EN */
++      u8 wr_en_y;     /* boolean, use QM_CGR_EN */
++      u8 wr_en_r;     /* boolean, use QM_CGR_EN */
++      u8 cscn_en;     /* boolean, use QM_CGR_EN */
++      union {
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u16 cscn_targ_upd_ctrl; /* use QM_CSCN_TARG_UDP_ */
++                      u16 cscn_targ_dcp_low;  /* CSCN_TARG_DCP low-16bits */
++#else
++                      u16 cscn_targ_dcp_low;  /* CSCN_TARG_DCP low-16bits */
++                      u16 cscn_targ_upd_ctrl; /* use QM_CSCN_TARG_UDP_ */
++#endif
++              };
++              u32 cscn_targ;  /* use QM_CGR_TARG_* */
++      };
++      u8 cstd_en;     /* boolean, use QM_CGR_EN */
++      u8 cs;          /* boolean, only used in query response */
++      union {
++              /* use qm_cgr_cs_thres_set64() */
++              struct qm_cgr_cs_thres cs_thres;
++              u16 __cs_thres;
++      };
++      u8 mode;        /* QMAN_CGR_MODE_FRAME not supported in rev1.0 */
++} __packed;
++#define QM_CGR_EN             0x01 /* For wr_en_*, cscn_en, cstd_en */
++#define QM_CGR_TARG_UDP_CTRL_WRITE_BIT        0x8000 /* value written to portal bit*/
++#define QM_CGR_TARG_UDP_CTRL_DCP      0x4000 /* 0: SWP, 1: DCP */
++#define QM_CGR_TARG_PORTAL(n) (0x80000000 >> (n)) /* s/w portal, 0-9 */
++#define QM_CGR_TARG_FMAN0     0x00200000 /* direct-connect portal: fman0 */
++#define QM_CGR_TARG_FMAN1     0x00100000 /*                      : fman1 */
++/* Convert CGR thresholds to/from "cs_thres" format */
++static inline u64 qm_cgr_cs_thres_get64(const struct qm_cgr_cs_thres *th)
++{
++      return (u64)th->TA << th->Tn;
++}
++static inline int qm_cgr_cs_thres_set64(struct qm_cgr_cs_thres *th, u64 val,
++                                      int roundup)
++{
++      u32 e = 0;
++      int oddbit = 0;
++      while (val > 0xff) {
++              oddbit = val & 1;
++              val >>= 1;
++              e++;
++              if (roundup && oddbit)
++                      val++;
++      }
++      th->Tn = e;
++      th->TA = val;
++      return 0;
++}
++
++/* See 1.5.8.5.1: "Initialize FQ" */
++/* See 1.5.8.5.2: "Query FQ" */
++/* See 1.5.8.5.3: "Query FQ Non-Programmable Fields" */
++/* See 1.5.8.5.4: "Alter FQ State Commands " */
++/* See 1.5.8.6.1: "Initialize/Modify CGR" */
++/* See 1.5.8.6.2: "CGR Test Write" */
++/* See 1.5.8.6.3: "Query CGR" */
++/* See 1.5.8.6.4: "Query Congestion Group State" */
++struct qm_mcc_initfq {
++      u8 __reserved1;
++      u16 we_mask;    /* Write Enable Mask */
++      u32 fqid;       /* 24-bit */
++      u16 count;      /* Initialises 'count+1' FQDs */
++      struct qm_fqd fqd; /* the FQD fields go here */
++      u8 __reserved3[30];
++} __packed;
++struct qm_mcc_queryfq {
++      u8 __reserved1[3];
++      u32 fqid;       /* 24-bit */
++      u8 __reserved2[56];
++} __packed;
++struct qm_mcc_queryfq_np {
++      u8 __reserved1[3];
++      u32 fqid;       /* 24-bit */
++      u8 __reserved2[56];
++} __packed;
++struct qm_mcc_alterfq {
++      u8 __reserved1[3];
++      u32 fqid;       /* 24-bit */
++      u8 __reserved2;
++      u8 count;       /* number of consecutive FQID */
++      u8 __reserved3[10];
++      u32 context_b;  /* frame queue context b */
++      u8 __reserved4[40];
++} __packed;
++struct qm_mcc_initcgr {
++      u8 __reserved1;
++      u16 we_mask;    /* Write Enable Mask */
++      struct __qm_mc_cgr cgr; /* CGR fields */
++      u8 __reserved2[2];
++      u8 cgid;
++      u8 __reserved4[32];
++} __packed;
++struct qm_mcc_cgrtestwrite {
++      u8 __reserved1[2];
++      u8 i_bcnt_hi:8;/* high 8-bits of 40-bit "Instant" */
++      u32 i_bcnt_lo;  /* low 32-bits of 40-bit */
++      u8 __reserved2[23];
++      u8 cgid;
++      u8 __reserved3[32];
++} __packed;
++struct qm_mcc_querycgr {
++      u8 __reserved1[30];
++      u8 cgid;
++      u8 __reserved2[32];
++} __packed;
++struct qm_mcc_querycongestion {
++      u8 __reserved[63];
++} __packed;
++struct qm_mcc_querywq {
++      u8 __reserved;
++      /* select channel if verb != QUERYWQ_DEDICATED */
++      union {
++              u16 channel_wq; /* ignores wq (3 lsbits) */
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u16 id:13; /* qm_channel */
++                      u16 __reserved1:3;
++#else
++                      u16 __reserved1:3;
++                      u16 id:13; /* qm_channel */
++#endif
++              } __packed channel;
++      };
++      u8 __reserved2[60];
++} __packed;
++
++struct qm_mcc_ceetm_lfqmt_config {
++      u8 __reserved1[4];
++      u32 lfqid:24;
++      u8 __reserved2[2];
++      u16 cqid;
++      u8 __reserved3[2];
++      u16 dctidx;
++      u8 __reserved4[48];
++} __packed;
++
++struct qm_mcc_ceetm_lfqmt_query {
++      u8 __reserved1[4];
++      u32 lfqid:24;
++      u8 __reserved2[56];
++} __packed;
++
++struct qm_mcc_ceetm_cq_config {
++      u8 __reserved1;
++      u16 cqid;
++      u8 dcpid;
++      u8 __reserved2;
++      u16 ccgid;
++      u8 __reserved3[56];
++} __packed;
++
++struct qm_mcc_ceetm_cq_query {
++      u8 __reserved1;
++      u16 cqid;
++      u8 dcpid;
++      u8 __reserved2[59];
++} __packed;
++
++struct qm_mcc_ceetm_dct_config {
++      u8 __reserved1;
++      u16 dctidx;
++      u8 dcpid;
++      u8 __reserved2[15];
++      u32 context_b;
++      u64 context_a;
++      u8 __reserved3[32];
++} __packed;
++
++struct qm_mcc_ceetm_dct_query {
++      u8 __reserved1;
++      u16 dctidx;
++      u8 dcpid;
++      u8 __reserved2[59];
++} __packed;
++
++struct qm_mcc_ceetm_class_scheduler_config {
++      u8 __reserved1;
++      u16 cqcid;
++      u8 dcpid;
++      u8 __reserved2[6];
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++      u8 gpc_reserved:1;
++      u8 gpc_combine_flag:1;
++      u8 gpc_prio_b:3;
++      u8 gpc_prio_a:3;
++#else
++      u8 gpc_prio_a:3;
++      u8 gpc_prio_b:3;
++      u8 gpc_combine_flag:1;
++      u8 gpc_reserved:1;
++#endif
++      u16 crem;
++      u16 erem;
++      u8 w[8];
++      u8 __reserved3[40];
++} __packed;
++
++struct qm_mcc_ceetm_class_scheduler_query {
++      u8 __reserved1;
++      u16 cqcid;
++      u8 dcpid;
++      u8 __reserved2[59];
++} __packed;
++
++#define CEETM_COMMAND_CHANNEL_MAPPING (0 << 12)
++#define CEETM_COMMAND_SP_MAPPING      (1 << 12)
++#define CEETM_COMMAND_CHANNEL_SHAPER  (2 << 12)
++#define CEETM_COMMAND_LNI_SHAPER      (3 << 12)
++#define CEETM_COMMAND_TCFC            (4 << 12)
++
++#define CEETM_CCGRID_MASK     0x01FF
++#define CEETM_CCGR_CM_CONFIGURE       (0 << 14)
++#define CEETM_CCGR_DN_CONFIGURE       (1 << 14)
++#define CEETM_CCGR_TEST_WRITE (2 << 14)
++#define CEETM_CCGR_CM_QUERY   (0 << 14)
++#define CEETM_CCGR_DN_QUERY   (1 << 14)
++#define CEETM_CCGR_DN_QUERY_FLUSH     (2 << 14)
++#define CEETM_QUERY_CONGESTION_STATE (3 << 14)
++
++struct qm_mcc_ceetm_mapping_shaper_tcfc_config {
++      u8 __reserved1;
++      u16 cid;
++      u8 dcpid;
++      union {
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u8 map_shaped:1;
++                      u8 map_reserved:4;
++                      u8 map_lni_id:3;
++#else
++                      u8 map_lni_id:3;
++                      u8 map_reserved:4;
++                      u8 map_shaped:1;
++#endif
++                      u8 __reserved2[58];
++              } __packed channel_mapping;
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u8 map_reserved:5;
++                      u8 map_lni_id:3;
++#else
++                      u8 map_lni_id:3;
++                      u8 map_reserved:5;
++#endif
++                      u8 __reserved2[58];
++              } __packed sp_mapping;
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u8 cpl:1;
++                      u8 cpl_reserved:2;
++                      u8 oal:5;
++#else
++                      u8 oal:5;
++                      u8 cpl_reserved:2;
++                      u8 cpl:1;
++#endif
++                      u32 crtcr:24;
++                      u32 ertcr:24;
++                      u16 crtbl;
++                      u16 ertbl;
++                      u8 mps; /* This will be hardcoded by driver with 60 */
++                      u8 __reserved2[47];
++              } __packed shaper_config;
++              struct {
++                      u8 __reserved2[11];
++                      u64 lnitcfcc;
++                      u8 __reserved3[40];
++              } __packed tcfc_config;
++      };
++} __packed;
++
++struct qm_mcc_ceetm_mapping_shaper_tcfc_query {
++      u8 __reserved1;
++      u16 cid;
++      u8 dcpid;
++      u8 __reserved2[59];
++} __packed;
++
++struct qm_mcc_ceetm_ccgr_config {
++      u8 __reserved1;
++      u16 ccgrid;
++      u8 dcpid;
++      u8 __reserved2;
++      u16 we_mask;
++      union {
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u8 ctl_reserved:1;
++                      u8 ctl_wr_en_g:1;
++                      u8 ctl_wr_en_y:1;
++                      u8 ctl_wr_en_r:1;
++                      u8 ctl_td_en:1;
++                      u8 ctl_td_mode:1;
++                      u8 ctl_cscn_en:1;
++                      u8 ctl_mode:1;
++#else
++                      u8 ctl_mode:1;
++                      u8 ctl_cscn_en:1;
++                      u8 ctl_td_mode:1;
++                      u8 ctl_td_en:1;
++                      u8 ctl_wr_en_r:1;
++                      u8 ctl_wr_en_y:1;
++                      u8 ctl_wr_en_g:1;
++                      u8 ctl_reserved:1;
++#endif
++                      u8 cdv;
++                      u16 cscn_tupd;
++                      u8 oal;
++                      u8 __reserved3;
++                      struct qm_cgr_cs_thres cs_thres;
++                      struct qm_cgr_cs_thres cs_thres_x;
++                      struct qm_cgr_cs_thres td_thres;
++                      struct qm_cgr_wr_parm wr_parm_g;
++                      struct qm_cgr_wr_parm wr_parm_y;
++                      struct qm_cgr_wr_parm wr_parm_r;
++              } __packed cm_config;
++              struct {
++                      u8 dnc;
++                      u8 dn0;
++                      u8 dn1;
++                      u64 dnba:40;
++                      u8 __reserved3[2];
++                      u16 dnth_0;
++                      u8 __reserved4[2];
++                      u16 dnth_1;
++                      u8 __reserved5[8];
++              } __packed dn_config;
++              struct {
++                      u8 __reserved3[3];
++                      u64 i_cnt:40;
++                      u8 __reserved4[16];
++              } __packed test_write;
++      };
++      u8 __reserved5[32];
++} __packed;
++
++struct qm_mcc_ceetm_ccgr_query {
++      u8 __reserved1;
++      u16 ccgrid;
++      u8 dcpid;
++      u8 __reserved2[59];
++} __packed;
++
++struct qm_mcc_ceetm_cq_peek_pop_xsfdrread {
++      u8 __reserved1;
++      u16 cqid;
++      u8 dcpid;
++      u8 ct;
++      u16 xsfdr;
++      u8 __reserved2[56];
++} __packed;
++
++#define CEETM_QUERY_DEQUEUE_STATISTICS 0x00
++#define CEETM_QUERY_DEQUEUE_CLEAR_STATISTICS 0x01
++#define CEETM_WRITE_DEQUEUE_STATISTICS 0x02
++#define CEETM_QUERY_REJECT_STATISTICS 0x03
++#define CEETM_QUERY_REJECT_CLEAR_STATISTICS 0x04
++#define CEETM_WRITE_REJECT_STATISTICS 0x05
++struct qm_mcc_ceetm_statistics_query_write {
++      u8 __reserved1;
++      u16 cid;
++      u8 dcpid;
++      u8 ct;
++      u8 __reserved2[13];
++      u64 frm_cnt:40;
++      u8 __reserved3[2];
++      u64 byte_cnt:48;
++      u8 __reserved[32];
++} __packed;
++
++struct qm_mc_command {
++      u8 __dont_write_directly__verb;
++      union {
++              struct qm_mcc_initfq initfq;
++              struct qm_mcc_queryfq queryfq;
++              struct qm_mcc_queryfq_np queryfq_np;
++              struct qm_mcc_alterfq alterfq;
++              struct qm_mcc_initcgr initcgr;
++              struct qm_mcc_cgrtestwrite cgrtestwrite;
++              struct qm_mcc_querycgr querycgr;
++              struct qm_mcc_querycongestion querycongestion;
++              struct qm_mcc_querywq querywq;
++              struct qm_mcc_ceetm_lfqmt_config lfqmt_config;
++              struct qm_mcc_ceetm_lfqmt_query lfqmt_query;
++              struct qm_mcc_ceetm_cq_config cq_config;
++              struct qm_mcc_ceetm_cq_query cq_query;
++              struct qm_mcc_ceetm_dct_config dct_config;
++              struct qm_mcc_ceetm_dct_query dct_query;
++              struct qm_mcc_ceetm_class_scheduler_config csch_config;
++              struct qm_mcc_ceetm_class_scheduler_query csch_query;
++              struct qm_mcc_ceetm_mapping_shaper_tcfc_config mst_config;
++              struct qm_mcc_ceetm_mapping_shaper_tcfc_query mst_query;
++              struct qm_mcc_ceetm_ccgr_config ccgr_config;
++              struct qm_mcc_ceetm_ccgr_query ccgr_query;
++              struct qm_mcc_ceetm_cq_peek_pop_xsfdrread cq_ppxr;
++              struct qm_mcc_ceetm_statistics_query_write stats_query_write;
++      };
++} __packed;
++#define QM_MCC_VERB_VBIT              0x80
++#define QM_MCC_VERB_MASK              0x7f    /* where the verb contains; */
++#define QM_MCC_VERB_INITFQ_PARKED     0x40
++#define QM_MCC_VERB_INITFQ_SCHED      0x41
++#define QM_MCC_VERB_QUERYFQ           0x44
++#define QM_MCC_VERB_QUERYFQ_NP                0x45    /* "non-programmable" fields */
++#define QM_MCC_VERB_QUERYWQ           0x46
++#define QM_MCC_VERB_QUERYWQ_DEDICATED 0x47
++#define QM_MCC_VERB_ALTER_SCHED               0x48    /* Schedule FQ */
++#define QM_MCC_VERB_ALTER_FE          0x49    /* Force Eligible FQ */
++#define QM_MCC_VERB_ALTER_RETIRE      0x4a    /* Retire FQ */
++#define QM_MCC_VERB_ALTER_OOS         0x4b    /* Take FQ out of service */
++#define QM_MCC_VERB_ALTER_FQXON               0x4d    /* FQ XON */
++#define QM_MCC_VERB_ALTER_FQXOFF      0x4e    /* FQ XOFF */
++#define QM_MCC_VERB_INITCGR           0x50
++#define QM_MCC_VERB_MODIFYCGR         0x51
++#define QM_MCC_VERB_CGRTESTWRITE      0x52
++#define QM_MCC_VERB_QUERYCGR          0x58
++#define QM_MCC_VERB_QUERYCONGESTION   0x59
++/* INITFQ-specific flags */
++#define QM_INITFQ_WE_MASK             0x01ff  /* 'Write Enable' flags; */
++#define QM_INITFQ_WE_OAC              0x0100
++#define QM_INITFQ_WE_ORPC             0x0080
++#define QM_INITFQ_WE_CGID             0x0040
++#define QM_INITFQ_WE_FQCTRL           0x0020
++#define QM_INITFQ_WE_DESTWQ           0x0010
++#define QM_INITFQ_WE_ICSCRED          0x0008
++#define QM_INITFQ_WE_TDTHRESH         0x0004
++#define QM_INITFQ_WE_CONTEXTB         0x0002
++#define QM_INITFQ_WE_CONTEXTA         0x0001
++/* INITCGR/MODIFYCGR-specific flags */
++#define QM_CGR_WE_MASK                        0x07ff  /* 'Write Enable Mask'; */
++#define QM_CGR_WE_WR_PARM_G           0x0400
++#define QM_CGR_WE_WR_PARM_Y           0x0200
++#define QM_CGR_WE_WR_PARM_R           0x0100
++#define QM_CGR_WE_WR_EN_G             0x0080
++#define QM_CGR_WE_WR_EN_Y             0x0040
++#define QM_CGR_WE_WR_EN_R             0x0020
++#define QM_CGR_WE_CSCN_EN             0x0010
++#define QM_CGR_WE_CSCN_TARG           0x0008
++#define QM_CGR_WE_CSTD_EN             0x0004
++#define QM_CGR_WE_CS_THRES            0x0002
++#define QM_CGR_WE_MODE                        0x0001
++
++/* See 1.5.9.7 CEETM Management Commands */
++#define QM_CEETM_VERB_LFQMT_CONFIG    0x70
++#define QM_CEETM_VERB_LFQMT_QUERY     0x71
++#define QM_CEETM_VERB_CQ_CONFIG               0x72
++#define QM_CEETM_VERB_CQ_QUERY                0x73
++#define QM_CEETM_VERB_DCT_CONFIG      0x74
++#define QM_CEETM_VERB_DCT_QUERY               0x75
++#define QM_CEETM_VERB_CLASS_SCHEDULER_CONFIG          0x76
++#define QM_CEETM_VERB_CLASS_SCHEDULER_QUERY           0x77
++#define QM_CEETM_VERB_MAPPING_SHAPER_TCFC_CONFIG      0x78
++#define QM_CEETM_VERB_MAPPING_SHAPER_TCFC_QUERY               0x79
++#define QM_CEETM_VERB_CCGR_CONFIG                     0x7A
++#define QM_CEETM_VERB_CCGR_QUERY                      0x7B
++#define QM_CEETM_VERB_CQ_PEEK_POP_XFDRREAD            0x7C
++#define QM_CEETM_VERB_STATISTICS_QUERY_WRITE          0x7D
++
++/* See 1.5.8.5.1: "Initialize FQ" */
++/* See 1.5.8.5.2: "Query FQ" */
++/* See 1.5.8.5.3: "Query FQ Non-Programmable Fields" */
++/* See 1.5.8.5.4: "Alter FQ State Commands " */
++/* See 1.5.8.6.1: "Initialize/Modify CGR" */
++/* See 1.5.8.6.2: "CGR Test Write" */
++/* See 1.5.8.6.3: "Query CGR" */
++/* See 1.5.8.6.4: "Query Congestion Group State" */
++struct qm_mcr_initfq {
++      u8 __reserved1[62];
++} __packed;
++struct qm_mcr_queryfq {
++      u8 __reserved1[8];
++      struct qm_fqd fqd;      /* the FQD fields are here */
++      u8 __reserved2[30];
++} __packed;
++struct qm_mcr_queryfq_np {
++      u8 __reserved1;
++      u8 state;       /* QM_MCR_NP_STATE_*** */
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++      u8 __reserved2;
++      u32 fqd_link:24;
++      u16 __reserved3:2;
++      u16 odp_seq:14;
++      u16 __reserved4:2;
++      u16 orp_nesn:14;
++      u16 __reserved5:1;
++      u16 orp_ea_hseq:15;
++      u16 __reserved6:1;
++      u16 orp_ea_tseq:15;
++      u8 __reserved7;
++      u32 orp_ea_hptr:24;
++      u8 __reserved8;
++      u32 orp_ea_tptr:24;
++      u8 __reserved9;
++      u32 pfdr_hptr:24;
++      u8 __reserved10;
++      u32 pfdr_tptr:24;
++      u8 __reserved11[5];
++      u8 __reserved12:7;
++      u8 is:1;
++      u16 ics_surp;
++      u32 byte_cnt;
++      u8 __reserved13;
++      u32 frm_cnt:24;
++      u32 __reserved14;
++      u16 ra1_sfdr;   /* QM_MCR_NP_RA1_*** */
++      u16 ra2_sfdr;   /* QM_MCR_NP_RA2_*** */
++      u16 __reserved15;
++      u16 od1_sfdr;   /* QM_MCR_NP_OD1_*** */
++      u16 od2_sfdr;   /* QM_MCR_NP_OD2_*** */
++      u16 od3_sfdr;   /* QM_MCR_NP_OD3_*** */
++#else
++      u8 __reserved2;
++      u32 fqd_link:24;
++
++      u16 odp_seq:14;
++      u16 __reserved3:2;
++
++      u16 orp_nesn:14;
++      u16 __reserved4:2;
++
++      u16 orp_ea_hseq:15;
++      u16 __reserved5:1;
++
++      u16 orp_ea_tseq:15;
++      u16 __reserved6:1;
++
++      u8 __reserved7;
++      u32 orp_ea_hptr:24;
++
++      u8 __reserved8;
++      u32 orp_ea_tptr:24;
++
++      u8 __reserved9;
++      u32 pfdr_hptr:24;
++
++      u8 __reserved10;
++      u32 pfdr_tptr:24;
++
++      u8 __reserved11[5];
++      u8 is:1;
++      u8 __reserved12:7;
++      u16 ics_surp;
++      u32 byte_cnt;
++      u8 __reserved13;
++      u32 frm_cnt:24;
++      u32 __reserved14;
++      u16 ra1_sfdr;   /* QM_MCR_NP_RA1_*** */
++      u16 ra2_sfdr;   /* QM_MCR_NP_RA2_*** */
++      u16 __reserved15;
++      u16 od1_sfdr;   /* QM_MCR_NP_OD1_*** */
++      u16 od2_sfdr;   /* QM_MCR_NP_OD2_*** */
++      u16 od3_sfdr;   /* QM_MCR_NP_OD3_*** */
++#endif
++} __packed;
++
++
++struct qm_mcr_alterfq {
++      u8 fqs;         /* Frame Queue Status */
++      u8 __reserved1[61];
++} __packed;
++struct qm_mcr_initcgr {
++      u8 __reserved1[62];
++} __packed;
++struct qm_mcr_cgrtestwrite {
++      u16 __reserved1;
++      struct __qm_mc_cgr cgr; /* CGR fields */
++      u8 __reserved2[3];
++      u32 __reserved3:24;
++      u32 i_bcnt_hi:8;/* high 8-bits of 40-bit "Instant" */
++      u32 i_bcnt_lo;  /* low 32-bits of 40-bit */
++      u32 __reserved4:24;
++      u32 a_bcnt_hi:8;/* high 8-bits of 40-bit "Average" */
++      u32 a_bcnt_lo;  /* low 32-bits of 40-bit */
++      u16 lgt;        /* Last Group Tick */
++      u16 wr_prob_g;
++      u16 wr_prob_y;
++      u16 wr_prob_r;
++      u8 __reserved5[8];
++} __packed;
++struct qm_mcr_querycgr {
++      u16 __reserved1;
++      struct __qm_mc_cgr cgr; /* CGR fields */
++      u8 __reserved2[3];
++      union {
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u32 __reserved3:24;
++                      u32 i_bcnt_hi:8;/* high 8-bits of 40-bit "Instant" */
++                      u32 i_bcnt_lo;  /* low 32-bits of 40-bit */
++#else
++                      u32 i_bcnt_lo;  /* low 32-bits of 40-bit */
++                      u32 i_bcnt_hi:8;/* high 8-bits of 40-bit "Instant" */
++                      u32 __reserved3:24;
++#endif
++              };
++              u64 i_bcnt;
++      };
++      union {
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u32 __reserved4:24;
++                      u32 a_bcnt_hi:8;/* high 8-bits of 40-bit "Average" */
++                      u32 a_bcnt_lo;  /* low 32-bits of 40-bit */
++#else
++                      u32 a_bcnt_lo;  /* low 32-bits of 40-bit */
++                      u32 a_bcnt_hi:8;/* high 8-bits of 40-bit "Average" */
++                      u32 __reserved4:24;
++#endif
++              };
++              u64 a_bcnt;
++      };
++      union {
++              u32 cscn_targ_swp[4];
++              u8 __reserved5[16];
++      };
++} __packed;
++static inline u64 qm_mcr_querycgr_i_get64(const struct qm_mcr_querycgr *q)
++{
++      return be64_to_cpu(q->i_bcnt);
++}
++static inline u64 qm_mcr_querycgr_a_get64(const struct qm_mcr_querycgr *q)
++{
++      return be64_to_cpu(q->a_bcnt);
++}
++static inline u64 qm_mcr_cgrtestwrite_i_get64(
++                                      const struct qm_mcr_cgrtestwrite *q)
++{
++      return be64_to_cpu(((u64)q->i_bcnt_hi << 32) | (u64)q->i_bcnt_lo);
++}
++static inline u64 qm_mcr_cgrtestwrite_a_get64(
++                                      const struct qm_mcr_cgrtestwrite *q)
++{
++      return be64_to_cpu(((u64)q->a_bcnt_hi << 32) | (u64)q->a_bcnt_lo);
++}
++/* Macro, so we compile better if 'v' isn't always 64-bit */
++#define qm_mcr_querycgr_i_set64(q, v) \
++      do { \
++              struct qm_mcr_querycgr *__q931 = (fd); \
++              __q931->i_bcnt_hi = upper_32_bits(v); \
++              __q931->i_bcnt_lo = lower_32_bits(v); \
++      } while (0)
++#define qm_mcr_querycgr_a_set64(q, v) \
++      do { \
++              struct qm_mcr_querycgr *__q931 = (fd); \
++              __q931->a_bcnt_hi = upper_32_bits(v); \
++              __q931->a_bcnt_lo = lower_32_bits(v); \
++      } while (0)
++struct __qm_mcr_querycongestion {
++      u32 __state[8];
++};
++struct qm_mcr_querycongestion {
++      u8 __reserved[30];
++      /* Access this struct using QM_MCR_QUERYCONGESTION() */
++      struct __qm_mcr_querycongestion state;
++} __packed;
++struct qm_mcr_querywq {
++      union {
++              u16 channel_wq; /* ignores wq (3 lsbits) */
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u16 id:13; /* qm_channel */
++                      u16 __reserved:3;
++#else
++                      u16 __reserved:3;
++                      u16 id:13; /* qm_channel */
++#endif
++              } __packed channel;
++      };
++      u8 __reserved[28];
++      u32 wq_len[8];
++} __packed;
++
++/* QMAN CEETM Management Command Response */
++struct qm_mcr_ceetm_lfqmt_config {
++      u8 __reserved1[62];
++} __packed;
++struct qm_mcr_ceetm_lfqmt_query {
++      u8 __reserved1[8];
++      u16 cqid;
++      u8 __reserved2[2];
++      u16 dctidx;
++      u8 __reserved3[2];
++      u16 ccgid;
++      u8 __reserved4[44];
++} __packed;
++
++struct qm_mcr_ceetm_cq_config {
++      u8 __reserved1[62];
++} __packed;
++
++struct qm_mcr_ceetm_cq_query {
++      u8 __reserved1[4];
++      u16 ccgid;
++      u16 state;
++      u32 pfdr_hptr:24;
++      u32 pfdr_tptr:24;
++      u16 od1_xsfdr;
++      u16 od2_xsfdr;
++      u16 od3_xsfdr;
++      u16 od4_xsfdr;
++      u16 od5_xsfdr;
++      u16 od6_xsfdr;
++      u16 ra1_xsfdr;
++      u16 ra2_xsfdr;
++      u8 __reserved2;
++      u32 frm_cnt:24;
++      u8 __reserved333[28];
++} __packed;
++
++struct qm_mcr_ceetm_dct_config {
++      u8 __reserved1[62];
++} __packed;
++
++struct qm_mcr_ceetm_dct_query {
++      u8 __reserved1[18];
++      u32 context_b;
++      u64 context_a;
++      u8 __reserved2[32];
++} __packed;
++
++struct qm_mcr_ceetm_class_scheduler_config {
++      u8 __reserved1[62];
++} __packed;
++
++struct qm_mcr_ceetm_class_scheduler_query {
++      u8 __reserved1[9];
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++      u8 gpc_reserved:1;
++      u8 gpc_combine_flag:1;
++      u8 gpc_prio_b:3;
++      u8 gpc_prio_a:3;
++#else
++      u8 gpc_prio_a:3;
++      u8 gpc_prio_b:3;
++      u8 gpc_combine_flag:1;
++      u8 gpc_reserved:1;
++#endif
++      u16 crem;
++      u16 erem;
++      u8 w[8];
++      u8 __reserved2[5];
++      u32 wbfslist:24;
++      u32 d8;
++      u32 d9;
++      u32 d10;
++      u32 d11;
++      u32 d12;
++      u32 d13;
++      u32 d14;
++      u32 d15;
++} __packed;
++
++struct qm_mcr_ceetm_mapping_shaper_tcfc_config {
++      u16 cid;
++      u8 __reserved2[60];
++} __packed;
++
++struct qm_mcr_ceetm_mapping_shaper_tcfc_query {
++      u16 cid;
++      u8 __reserved1;
++      union {
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u8 map_shaped:1;
++                      u8 map_reserved:4;
++                      u8 map_lni_id:3;
++#else
++                      u8 map_lni_id:3;
++                      u8 map_reserved:4;
++                      u8 map_shaped:1;
++#endif
++                      u8 __reserved2[58];
++              } __packed channel_mapping_query;
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u8 map_reserved:5;
++                      u8 map_lni_id:3;
++#else
++                      u8 map_lni_id:3;
++                      u8 map_reserved:5;
++#endif
++                      u8 __reserved2[58];
++              } __packed sp_mapping_query;
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u8 cpl:1;
++                      u8 cpl_reserved:2;
++                      u8 oal:5;
++#else
++                      u8 oal:5;
++                      u8 cpl_reserved:2;
++                      u8 cpl:1;
++#endif
++                      u32 crtcr:24;
++                      u32 ertcr:24;
++                      u16 crtbl;
++                      u16 ertbl;
++                      u8 mps;
++                      u8 __reserved2[15];
++                      u32 crat;
++                      u32 erat;
++                      u8 __reserved3[24];
++              } __packed shaper_query;
++              struct {
++                      u8 __reserved1[11];
++                      u64 lnitcfcc;
++                      u8 __reserved3[40];
++              } __packed tcfc_query;
++      };
++} __packed;
++
++struct qm_mcr_ceetm_ccgr_config {
++      u8 __reserved1[46];
++      union {
++              u8 __reserved2[8];
++              struct {
++                      u16 timestamp;
++                      u16 wr_porb_g;
++                      u16 wr_prob_y;
++                      u16 wr_prob_r;
++              } __packed test_write;
++      };
++      u8 __reserved3[8];
++} __packed;
++
++struct qm_mcr_ceetm_ccgr_query {
++      u8 __reserved1[6];
++      union {
++              struct {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++                      u8 ctl_reserved:1;
++                      u8 ctl_wr_en_g:1;
++                      u8 ctl_wr_en_y:1;
++                      u8 ctl_wr_en_r:1;
++                      u8 ctl_td_en:1;
++                      u8 ctl_td_mode:1;
++                      u8 ctl_cscn_en:1;
++                      u8 ctl_mode:1;
++#else
++                      u8 ctl_mode:1;
++                      u8 ctl_cscn_en:1;
++                      u8 ctl_td_mode:1;
++                      u8 ctl_td_en:1;
++                      u8 ctl_wr_en_r:1;
++                      u8 ctl_wr_en_y:1;
++                      u8 ctl_wr_en_g:1;
++                      u8 ctl_reserved:1;
++#endif
++                      u8 cdv;
++                      u8 __reserved2[2];
++                      u8 oal;
++                      u8 __reserved3;
++                      struct qm_cgr_cs_thres cs_thres;
++                      struct qm_cgr_cs_thres cs_thres_x;
++                      struct qm_cgr_cs_thres td_thres;
++                      struct qm_cgr_wr_parm wr_parm_g;
++                      struct qm_cgr_wr_parm wr_parm_y;
++                      struct qm_cgr_wr_parm wr_parm_r;
++                      u16 cscn_targ_dcp;
++                      u8 dcp_lsn;
++                      u64 i_cnt:40;
++                      u8 __reserved4[3];
++                      u64 a_cnt:40;
++                      u32 cscn_targ_swp[4];
++              } __packed cm_query;
++              struct {
++                      u8 dnc;
++                      u8 dn0;
++                      u8 dn1;
++                      u64 dnba:40;
++                      u8 __reserved2[2];
++                      u16 dnth_0;
++                      u8 __reserved3[2];
++                      u16 dnth_1;
++                      u8 __reserved4[10];
++                      u16 dnacc_0;
++                      u8 __reserved5[2];
++                      u16 dnacc_1;
++                      u8 __reserved6[24];
++              } __packed dn_query;
++              struct {
++                      u8 __reserved2[24];
++                      struct  __qm_mcr_querycongestion state;
++              } __packed congestion_state;
++
++      };
++} __packed;
++
++struct qm_mcr_ceetm_cq_peek_pop_xsfdrread {
++      u8 stat;
++      u8 __reserved1[11];
++      u16 dctidx;
++      struct qm_fd fd;
++      u8 __reserved2[32];
++} __packed;
++
++struct qm_mcr_ceetm_statistics_query {
++      u8 __reserved1[17];
++      u64 frm_cnt:40;
++      u8 __reserved2[2];
++      u64 byte_cnt:48;
++      u8 __reserved3[32];
++} __packed;
++
++struct qm_mc_result {
++      u8 verb;
++      u8 result;
++      union {
++              struct qm_mcr_initfq initfq;
++              struct qm_mcr_queryfq queryfq;
++              struct qm_mcr_queryfq_np queryfq_np;
++              struct qm_mcr_alterfq alterfq;
++              struct qm_mcr_initcgr initcgr;
++              struct qm_mcr_cgrtestwrite cgrtestwrite;
++              struct qm_mcr_querycgr querycgr;
++              struct qm_mcr_querycongestion querycongestion;
++              struct qm_mcr_querywq querywq;
++              struct qm_mcr_ceetm_lfqmt_config lfqmt_config;
++              struct qm_mcr_ceetm_lfqmt_query lfqmt_query;
++              struct qm_mcr_ceetm_cq_config cq_config;
++              struct qm_mcr_ceetm_cq_query cq_query;
++              struct qm_mcr_ceetm_dct_config dct_config;
++              struct qm_mcr_ceetm_dct_query dct_query;
++              struct qm_mcr_ceetm_class_scheduler_config csch_config;
++              struct qm_mcr_ceetm_class_scheduler_query csch_query;
++              struct qm_mcr_ceetm_mapping_shaper_tcfc_config mst_config;
++              struct qm_mcr_ceetm_mapping_shaper_tcfc_query mst_query;
++              struct qm_mcr_ceetm_ccgr_config ccgr_config;
++              struct qm_mcr_ceetm_ccgr_query ccgr_query;
++              struct qm_mcr_ceetm_cq_peek_pop_xsfdrread cq_ppxr;
++              struct qm_mcr_ceetm_statistics_query stats_query;
++      };
++} __packed;
++
++#define QM_MCR_VERB_RRID              0x80
++#define QM_MCR_VERB_MASK              QM_MCC_VERB_MASK
++#define QM_MCR_VERB_INITFQ_PARKED     QM_MCC_VERB_INITFQ_PARKED
++#define QM_MCR_VERB_INITFQ_SCHED      QM_MCC_VERB_INITFQ_SCHED
++#define QM_MCR_VERB_QUERYFQ           QM_MCC_VERB_QUERYFQ
++#define QM_MCR_VERB_QUERYFQ_NP                QM_MCC_VERB_QUERYFQ_NP
++#define QM_MCR_VERB_QUERYWQ           QM_MCC_VERB_QUERYWQ
++#define QM_MCR_VERB_QUERYWQ_DEDICATED QM_MCC_VERB_QUERYWQ_DEDICATED
++#define QM_MCR_VERB_ALTER_SCHED               QM_MCC_VERB_ALTER_SCHED
++#define QM_MCR_VERB_ALTER_FE          QM_MCC_VERB_ALTER_FE
++#define QM_MCR_VERB_ALTER_RETIRE      QM_MCC_VERB_ALTER_RETIRE
++#define QM_MCR_VERB_ALTER_OOS         QM_MCC_VERB_ALTER_OOS
++#define QM_MCR_RESULT_NULL            0x00
++#define QM_MCR_RESULT_OK              0xf0
++#define QM_MCR_RESULT_ERR_FQID                0xf1
++#define QM_MCR_RESULT_ERR_FQSTATE     0xf2
++#define QM_MCR_RESULT_ERR_NOTEMPTY    0xf3    /* OOS fails if FQ is !empty */
++#define QM_MCR_RESULT_ERR_BADCHANNEL  0xf4
++#define QM_MCR_RESULT_PENDING         0xf8
++#define QM_MCR_RESULT_ERR_BADCOMMAND  0xff
++#define QM_MCR_NP_STATE_FE            0x10
++#define QM_MCR_NP_STATE_R             0x08
++#define QM_MCR_NP_STATE_MASK          0x07    /* Reads FQD::STATE; */
++#define QM_MCR_NP_STATE_OOS           0x00
++#define QM_MCR_NP_STATE_RETIRED               0x01
++#define QM_MCR_NP_STATE_TEN_SCHED     0x02
++#define QM_MCR_NP_STATE_TRU_SCHED     0x03
++#define QM_MCR_NP_STATE_PARKED                0x04
++#define QM_MCR_NP_STATE_ACTIVE                0x05
++#define QM_MCR_NP_PTR_MASK            0x07ff  /* for RA[12] & OD[123] */
++#define QM_MCR_NP_RA1_NRA(v)          (((v) >> 14) & 0x3)     /* FQD::NRA */
++#define QM_MCR_NP_RA2_IT(v)           (((v) >> 14) & 0x1)     /* FQD::IT */
++#define QM_MCR_NP_OD1_NOD(v)          (((v) >> 14) & 0x3)     /* FQD::NOD */
++#define QM_MCR_NP_OD3_NPC(v)          (((v) >> 14) & 0x3)     /* FQD::NPC */
++#define QM_MCR_FQS_ORLPRESENT         0x02    /* ORL fragments to come */
++#define QM_MCR_FQS_NOTEMPTY           0x01    /* FQ has enqueued frames */
++/* This extracts the state for congestion group 'n' from a query response.
++ * Eg.
++ *   u8 cgr = [...];
++ *   struct qm_mc_result *res = [...];
++ *   printf("congestion group %d congestion state: %d\n", cgr,
++ *       QM_MCR_QUERYCONGESTION(&res->querycongestion.state, cgr));
++ */
++#define __CGR_WORD(num)               (num >> 5)
++#define __CGR_SHIFT(num)      (num & 0x1f)
++#define __CGR_NUM             (sizeof(struct __qm_mcr_querycongestion) << 3)
++static inline int QM_MCR_QUERYCONGESTION(struct __qm_mcr_querycongestion *p,
++                                      u8 cgr)
++{
++      return p->__state[__CGR_WORD(cgr)] & (0x80000000 >> __CGR_SHIFT(cgr));
++}
++
++
++/*********************/
++/* Utility interface */
++/*********************/
++
++/* Represents an allocator over a range of FQIDs. NB, accesses are not locked,
++ * spinlock them yourself if needed. */
++struct qman_fqid_pool;
++
++/* Create/destroy a FQID pool, num must be a multiple of 32. NB, _destroy()
++ * always succeeds, but returns non-zero if there were "leaked" FQID
++ * allocations. */
++struct qman_fqid_pool *qman_fqid_pool_create(u32 fqid_start, u32 num);
++int qman_fqid_pool_destroy(struct qman_fqid_pool *pool);
++/* Alloc/free a FQID from the range. _alloc() returns zero for success. */
++int qman_fqid_pool_alloc(struct qman_fqid_pool *pool, u32 *fqid);
++void qman_fqid_pool_free(struct qman_fqid_pool *pool, u32 fqid);
++u32 qman_fqid_pool_used(struct qman_fqid_pool *pool);
++
++/*******************************************************************/
++/* Managed (aka "shared" or "mux/demux") portal, high-level i/face */
++/*******************************************************************/
++
++      /* Portal and Frame Queues */
++      /* ----------------------- */
++/* Represents a managed portal */
++struct qman_portal;
++
++/* This object type represents Qman frame queue descriptors (FQD), it is
++ * cacheline-aligned, and initialised by qman_create_fq(). The structure is
++ * defined further down. */
++struct qman_fq;
++
++/* This object type represents a Qman congestion group, it is defined further
++ * down. */
++struct qman_cgr;
++
++struct qman_portal_config {
++      /* If the caller enables DQRR stashing (and thus wishes to operate the
++       * portal from only one cpu), this is the logical CPU that the portal
++       * will stash to. Whether stashing is enabled or not, this setting is
++       * also used for any "core-affine" portals, ie. default portals
++       * associated to the corresponding cpu. -1 implies that there is no core
++       * affinity configured. */
++      int cpu;
++      /* portal interrupt line */
++      int irq;
++      /* the unique index of this portal */
++      u32 index;
++      /* Is this portal shared? (If so, it has coarser locking and demuxes
++       * processing on behalf of other CPUs.) */
++      int is_shared;
++      /* The portal's dedicated channel id, use this value for initialising
++       * frame queues to target this portal when scheduled. */
++      u16 channel;
++      /* A mask of which pool channels this portal has dequeue access to
++       * (using QM_SDQCR_CHANNELS_POOL(n) for the bitmask) */
++      u32 pools;
++};
++
++/* This enum, and the callback type that returns it, are used when handling
++ * dequeued frames via DQRR. Note that for "null" callbacks registered with the
++ * portal object (for handling dequeues that do not demux because contextB is
++ * NULL), the return value *MUST* be qman_cb_dqrr_consume. */
++enum qman_cb_dqrr_result {
++      /* DQRR entry can be consumed */
++      qman_cb_dqrr_consume,
++      /* Like _consume, but requests parking - FQ must be held-active */
++      qman_cb_dqrr_park,
++      /* Does not consume, for DCA mode only. This allows out-of-order
++       * consumes by explicit calls to qman_dca() and/or the use of implicit
++       * DCA via EQCR entries. */
++      qman_cb_dqrr_defer,
++      /* Stop processing without consuming this ring entry. Exits the current
++       * qman_poll_dqrr() or interrupt-handling, as appropriate. If within an
++       * interrupt handler, the callback would typically call
++       * qman_irqsource_remove(QM_PIRQ_DQRI) before returning this value,
++       * otherwise the interrupt will reassert immediately. */
++      qman_cb_dqrr_stop,
++      /* Like qman_cb_dqrr_stop, but consumes the current entry. */
++      qman_cb_dqrr_consume_stop
++};
++typedef enum qman_cb_dqrr_result (*qman_cb_dqrr)(struct qman_portal *qm,
++                                      struct qman_fq *fq,
++                                      const struct qm_dqrr_entry *dqrr);
++
++/* This callback type is used when handling ERNs, FQRNs and FQRLs via MR. They
++ * are always consumed after the callback returns. */
++typedef void (*qman_cb_mr)(struct qman_portal *qm, struct qman_fq *fq,
++                              const struct qm_mr_entry *msg);
++
++/* This callback type is used when handling DCP ERNs */
++typedef void (*qman_cb_dc_ern)(struct qman_portal *qm,
++                              const struct qm_mr_entry *msg);
++
++/* s/w-visible states. Ie. tentatively scheduled + truly scheduled + active +
++ * held-active + held-suspended are just "sched". Things like "retired" will not
++ * be assumed until it is complete (ie. QMAN_FQ_STATE_CHANGING is set until
++ * then, to indicate it's completing and to gate attempts to retry the retire
++ * command). Note, park commands do not set QMAN_FQ_STATE_CHANGING because it's
++ * technically impossible in the case of enqueue DCAs (which refer to DQRR ring
++ * index rather than the FQ that ring entry corresponds to), so repeated park
++ * commands are allowed (if you're silly enough to try) but won't change FQ
++ * state, and the resulting park notifications move FQs from "sched" to
++ * "parked". */
++enum qman_fq_state {
++      qman_fq_state_oos,
++      qman_fq_state_parked,
++      qman_fq_state_sched,
++      qman_fq_state_retired
++};
++
++/* Frame queue objects (struct qman_fq) are stored within memory passed to
++ * qman_create_fq(), as this allows stashing of caller-provided demux callback
++ * pointers at no extra cost to stashing of (driver-internal) FQ state. If the
++ * caller wishes to add per-FQ state and have it benefit from dequeue-stashing,
++ * they should;
++ *
++ * (a) extend the qman_fq structure with their state; eg.
++ *
++ *     // myfq is allocated and driver_fq callbacks filled in;
++ *     struct my_fq {
++ *         struct qman_fq base;
++ *         int an_extra_field;
++ *         [ ... add other fields to be associated with each FQ ...]
++ *     } *myfq = some_my_fq_allocator();
++ *     struct qman_fq *fq = qman_create_fq(fqid, flags, &myfq->base);
++ *
++ *     // in a dequeue callback, access extra fields from 'fq' via a cast;
++ *     struct my_fq *myfq = (struct my_fq *)fq;
++ *     do_something_with(myfq->an_extra_field);
++ *     [...]
++ *
++ * (b) when and if configuring the FQ for context stashing, specify how ever
++ *     many cachelines are required to stash 'struct my_fq', to accelerate not
++ *     only the Qman driver but the callback as well.
++ */
++
++struct qman_fq_cb {
++      qman_cb_dqrr dqrr;      /* for dequeued frames */
++      qman_cb_mr ern;         /* for s/w ERNs */
++      qman_cb_mr fqs;         /* frame-queue state changes*/
++};
++
++struct qman_fq {
++      /* Caller of qman_create_fq() provides these demux callbacks */
++      struct qman_fq_cb cb;
++      /* These are internal to the driver, don't touch. In particular, they
++       * may change, be removed, or extended (so you shouldn't rely on
++       * sizeof(qman_fq) being a constant). */
++      spinlock_t fqlock;
++      u32 fqid;
++      volatile unsigned long flags;
++      enum qman_fq_state state;
++      int cgr_groupid;
++      struct rb_node node;
++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
++      u32 key;
++#endif
++};
++
++/* This callback type is used when handling congestion group entry/exit.
++ * 'congested' is non-zero on congestion-entry, and zero on congestion-exit. */
++typedef void (*qman_cb_cgr)(struct qman_portal *qm,
++                      struct qman_cgr *cgr, int congested);
++
++struct qman_cgr {
++      /* Set these prior to qman_create_cgr() */
++      u32 cgrid; /* 0..255, but u32 to allow specials like -1, 256, etc.*/
++      qman_cb_cgr cb;
++      /* These are private to the driver */
++      u16 chan; /* portal channel this object is created on */
++      struct list_head node;
++};
++
++/* Flags to qman_create_fq() */
++#define QMAN_FQ_FLAG_NO_ENQUEUE      0x00000001 /* can't enqueue */
++#define QMAN_FQ_FLAG_NO_MODIFY       0x00000002 /* can only enqueue */
++#define QMAN_FQ_FLAG_TO_DCPORTAL     0x00000004 /* consumed by CAAM/PME/Fman */
++#define QMAN_FQ_FLAG_LOCKED          0x00000008 /* multi-core locking */
++#define QMAN_FQ_FLAG_AS_IS           0x00000010 /* query h/w state */
++#define QMAN_FQ_FLAG_DYNAMIC_FQID    0x00000020 /* (de)allocate fqid */
++
++/* Flags to qman_destroy_fq() */
++#define QMAN_FQ_DESTROY_PARKED       0x00000001 /* FQ can be parked or OOS */
++
++/* Flags from qman_fq_state() */
++#define QMAN_FQ_STATE_CHANGING       0x80000000 /* 'state' is changing */
++#define QMAN_FQ_STATE_NE             0x40000000 /* retired FQ isn't empty */
++#define QMAN_FQ_STATE_ORL            0x20000000 /* retired FQ has ORL */
++#define QMAN_FQ_STATE_BLOCKOOS       0xe0000000 /* if any are set, no OOS */
++#define QMAN_FQ_STATE_CGR_EN         0x10000000 /* CGR enabled */
++#define QMAN_FQ_STATE_VDQCR          0x08000000 /* being volatile dequeued */
++
++/* Flags to qman_init_fq() */
++#define QMAN_INITFQ_FLAG_SCHED       0x00000001 /* schedule rather than park */
++#define QMAN_INITFQ_FLAG_LOCAL       0x00000004 /* set dest portal */
++
++/* Flags to qman_volatile_dequeue() */
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++#define QMAN_VOLATILE_FLAG_WAIT      0x00000001 /* wait if VDQCR is in use */
++#define QMAN_VOLATILE_FLAG_WAIT_INT  0x00000002 /* if wait, interruptible? */
++#define QMAN_VOLATILE_FLAG_FINISH    0x00000004 /* wait till VDQCR completes */
++#endif
++
++/* Flags to qman_enqueue(). NB, the strange numbering is to align with hardware,
++ * bit-wise. (NB: the PME API is sensitive to these precise numberings too, so
++ * any change here should be audited in PME.) */
++#ifdef CONFIG_FSL_DPA_CAN_WAIT
++#define QMAN_ENQUEUE_FLAG_WAIT       0x00010000 /* wait if EQCR is full */
++#define QMAN_ENQUEUE_FLAG_WAIT_INT   0x00020000 /* if wait, interruptible? */
++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
++#define QMAN_ENQUEUE_FLAG_WAIT_SYNC  0x00000004 /* if wait, until consumed? */
++#endif
++#endif
++#define QMAN_ENQUEUE_FLAG_WATCH_CGR  0x00080000 /* watch congestion state */
++#define QMAN_ENQUEUE_FLAG_DCA        0x00008000 /* perform enqueue-DCA */
++#define QMAN_ENQUEUE_FLAG_DCA_PARK   0x00004000 /* If DCA, requests park */
++#define QMAN_ENQUEUE_FLAG_DCA_PTR(p)          /* If DCA, p is DQRR entry */ \
++              (((u32)(p) << 2) & 0x00000f00)
++#define QMAN_ENQUEUE_FLAG_C_GREEN    0x00000000 /* choose one C_*** flag */
++#define QMAN_ENQUEUE_FLAG_C_YELLOW   0x00000008
++#define QMAN_ENQUEUE_FLAG_C_RED      0x00000010
++#define QMAN_ENQUEUE_FLAG_C_OVERRIDE 0x00000018
++/* For the ORP-specific qman_enqueue_orp() variant;
++ * - this flag indicates "Not Last In Sequence", ie. all but the final fragment
++ *   of a frame. */
++#define QMAN_ENQUEUE_FLAG_NLIS       0x01000000
++/* - this flag performs no enqueue but fills in an ORP sequence number that
++ *   would otherwise block it (eg. if a frame has been dropped). */
++#define QMAN_ENQUEUE_FLAG_HOLE       0x02000000
++/* - this flag performs no enqueue but advances NESN to the given sequence
++ *   number. */
++#define QMAN_ENQUEUE_FLAG_NESN       0x04000000
++
++/* Flags to qman_modify_cgr() */
++#define QMAN_CGR_FLAG_USE_INIT       0x00000001
++#define QMAN_CGR_MODE_FRAME          0x00000001
++
++      /* Portal Management */
++      /* ----------------- */
++/**
++ * qman_get_portal_config - get portal configuration settings
++ *
++ * This returns a read-only view of the current cpu's affine portal settings.
++ */
++const struct qman_portal_config *qman_get_portal_config(void);
++
++/**
++ * qman_irqsource_get - return the portal work that is interrupt-driven
++ *
++ * Returns a bitmask of QM_PIRQ_**I processing sources that are currently
++ * enabled for interrupt handling on the current cpu's affine portal. These
++ * sources will trigger the portal interrupt and the interrupt handler (or a
++ * tasklet/bottom-half it defers to) will perform the corresponding processing
++ * work. The qman_poll_***() functions will only process sources that are not in
++ * this bitmask. If the current CPU is sharing a portal hosted on another CPU,
++ * this always returns zero.
++ */
++u32 qman_irqsource_get(void);
++
++/**
++ * qman_irqsource_add - add processing sources to be interrupt-driven
++ * @bits: bitmask of QM_PIRQ_**I processing sources
++ *
++ * Adds processing sources that should be interrupt-driven (rather than
++ * processed via qman_poll_***() functions). Returns zero for success, or
++ * -EINVAL if the current CPU is sharing a portal hosted on another CPU.
++ */
++int qman_irqsource_add(u32 bits);
++
++/**
++ * qman_irqsource_remove - remove processing sources from being interrupt-driven
++ * @bits: bitmask of QM_PIRQ_**I processing sources
++ *
++ * Removes processing sources from being interrupt-driven, so that they will
++ * instead be processed via qman_poll_***() functions. Returns zero for success,
++ * or -EINVAL if the current CPU is sharing a portal hosted on another CPU.
++ */
++int qman_irqsource_remove(u32 bits);
++
++/**
++ * qman_affine_cpus - return a mask of cpus that have affine portals
++ */
++const cpumask_t *qman_affine_cpus(void);
++
++/**
++ * qman_affine_channel - return the channel ID of an portal
++ * @cpu: the cpu whose affine portal is the subject of the query
++ *
++ * If @cpu is -1, the affine portal for the current CPU will be used. It is a
++ * bug to call this function for any value of @cpu (other than -1) that is not a
++ * member of the mask returned from qman_affine_cpus().
++ */
++u16 qman_affine_channel(int cpu);
++
++/**
++ * qman_get_affine_portal - return the portal pointer affine to cpu
++ * @cpu: the cpu whose affine portal is the subject of the query
++ *
++ */
++void *qman_get_affine_portal(int cpu);
++
++/**
++ * qman_poll_dqrr - process DQRR (fast-path) entries
++ * @limit: the maximum number of DQRR entries to process
++ *
++ * Use of this function requires that DQRR processing not be interrupt-driven.
++ * Ie. the value returned by qman_irqsource_get() should not include
++ * QM_PIRQ_DQRI. If the current CPU is sharing a portal hosted on another CPU,
++ * this function will return -EINVAL, otherwise the return value is >=0 and
++ * represents the number of DQRR entries processed.
++ */
++int qman_poll_dqrr(unsigned int limit);
++
++/**
++ * qman_poll_slow - process anything (except DQRR) that isn't interrupt-driven.
++ *
++ * This function does any portal processing that isn't interrupt-driven. If the
++ * current CPU is sharing a portal hosted on another CPU, this function will
++ * return (u32)-1, otherwise the return value is a bitmask of QM_PIRQ_* sources
++ * indicating what interrupt sources were actually processed by the call.
++ */
++u32 qman_poll_slow(void);
++
++/**
++ * qman_poll - legacy wrapper for qman_poll_dqrr() and qman_poll_slow()
++ *
++ * Dispatcher logic on a cpu can use this to trigger any maintenance of the
++ * affine portal. There are two classes of portal processing in question;
++ * fast-path (which involves demuxing dequeue ring (DQRR) entries and tracking
++ * enqueue ring (EQCR) consumption), and slow-path (which involves EQCR
++ * thresholds, congestion state changes, etc). This function does whatever
++ * processing is not triggered by interrupts.
++ *
++ * Note, if DQRR and some slow-path processing are poll-driven (rather than
++ * interrupt-driven) then this function uses a heuristic to determine how often
++ * to run slow-path processing - as slow-path processing introduces at least a
++ * minimum latency each time it is run, whereas fast-path (DQRR) processing is
++ * close to zero-cost if there is no work to be done. Applications can tune this
++ * behaviour themselves by using qman_poll_dqrr() and qman_poll_slow() directly
++ * rather than going via this wrapper.
++ */
++void qman_poll(void);
++
++/**
++ * qman_stop_dequeues - Stop h/w dequeuing to the s/w portal
++ *
++ * Disables DQRR processing of the portal. This is reference-counted, so
++ * qman_start_dequeues() must be called as many times as qman_stop_dequeues() to
++ * truly re-enable dequeuing.
++ */
++void qman_stop_dequeues(void);
++
++/**
++ * qman_start_dequeues - (Re)start h/w dequeuing to the s/w portal
++ *
++ * Enables DQRR processing of the portal. This is reference-counted, so
++ * qman_start_dequeues() must be called as many times as qman_stop_dequeues() to
++ * truly re-enable dequeuing.
++ */
++void qman_start_dequeues(void);
++
++/**
++ * qman_static_dequeue_add - Add pool channels to the portal SDQCR
++ * @pools: bit-mask of pool channels, using QM_SDQCR_CHANNELS_POOL(n)
++ *
++ * Adds a set of pool channels to the portal's static dequeue command register
++ * (SDQCR). The requested pools are limited to those the portal has dequeue
++ * access to.
++ */
++void qman_static_dequeue_add(u32 pools);
++
++/**
++ * qman_static_dequeue_del - Remove pool channels from the portal SDQCR
++ * @pools: bit-mask of pool channels, using QM_SDQCR_CHANNELS_POOL(n)
++ *
++ * Removes a set of pool channels from the portal's static dequeue command
++ * register (SDQCR). The requested pools are limited to those the portal has
++ * dequeue access to.
++ */
++void qman_static_dequeue_del(u32 pools);
++
++/**
++ * qman_static_dequeue_get - return the portal's current SDQCR
++ *
++ * Returns the portal's current static dequeue command register (SDQCR). The
++ * entire register is returned, so if only the currently-enabled pool channels
++ * are desired, mask the return value with QM_SDQCR_CHANNELS_POOL_MASK.
++ */
++u32 qman_static_dequeue_get(void);
++
++/**
++ * qman_dca - Perform a Discrete Consumption Acknowledgement
++ * @dq: the DQRR entry to be consumed
++ * @park_request: indicates whether the held-active @fq should be parked
++ *
++ * Only allowed in DCA-mode portals, for DQRR entries whose handler callback had
++ * previously returned 'qman_cb_dqrr_defer'. NB, as with the other APIs, this
++ * does not take a 'portal' argument but implies the core affine portal from the
++ * cpu that is currently executing the function. For reasons of locking, this
++ * function must be called from the same CPU as that which processed the DQRR
++ * entry in the first place.
++ */
++void qman_dca(struct qm_dqrr_entry *dq, int park_request);
++
++/**
++ * qman_eqcr_is_empty - Determine if portal's EQCR is empty
++ *
++ * For use in situations where a cpu-affine caller needs to determine when all
++ * enqueues for the local portal have been processed by Qman but can't use the
++ * QMAN_ENQUEUE_FLAG_WAIT_SYNC flag to do this from the final qman_enqueue().
++ * The function forces tracking of EQCR consumption (which normally doesn't
++ * happen until enqueue processing needs to find space to put new enqueue
++ * commands), and returns zero if the ring still has unprocessed entries,
++ * non-zero if it is empty.
++ */
++int qman_eqcr_is_empty(void);
++
++/**
++ * qman_set_dc_ern - Set the handler for DCP enqueue rejection notifications
++ * @handler: callback for processing DCP ERNs
++ * @affine: whether this handler is specific to the locally affine portal
++ *
++ * If a hardware block's interface to Qman (ie. its direct-connect portal, or
++ * DCP) is configured not to receive enqueue rejections, then any enqueues
++ * through that DCP that are rejected will be sent to a given software portal.
++ * If @affine is non-zero, then this handler will only be used for DCP ERNs
++ * received on the portal affine to the current CPU. If multiple CPUs share a
++ * portal and they all call this function, they will be setting the handler for
++ * the same portal! If @affine is zero, then this handler will be global to all
++ * portals handled by this instance of the driver. Only those portals that do
++ * not have their own affine handler will use the global handler.
++ */
++void qman_set_dc_ern(qman_cb_dc_ern handler, int affine);
++
++      /* FQ management */
++      /* ------------- */
++/**
++ * qman_create_fq - Allocates a FQ
++ * @fqid: the index of the FQD to encapsulate, must be "Out of Service"
++ * @flags: bit-mask of QMAN_FQ_FLAG_*** options
++ * @fq: memory for storing the 'fq', with callbacks filled in
++ *
++ * Creates a frame queue object for the given @fqid, unless the
++ * QMAN_FQ_FLAG_DYNAMIC_FQID flag is set in @flags, in which case a FQID is
++ * dynamically allocated (or the function fails if none are available). Once
++ * created, the caller should not touch the memory at 'fq' except as extended to
++ * adjacent memory for user-defined fields (see the definition of "struct
++ * qman_fq" for more info). NO_MODIFY is only intended for enqueuing to
++ * pre-existing frame-queues that aren't to be otherwise interfered with, it
++ * prevents all other modifications to the frame queue. The TO_DCPORTAL flag
++ * causes the driver to honour any contextB modifications requested in the
++ * qm_init_fq() API, as this indicates the frame queue will be consumed by a
++ * direct-connect portal (PME, CAAM, or Fman). When frame queues are consumed by
++ * software portals, the contextB field is controlled by the driver and can't be
++ * modified by the caller. If the AS_IS flag is specified, management commands
++ * will be used on portal @p to query state for frame queue @fqid and construct
++ * a frame queue object based on that, rather than assuming/requiring that it be
++ * Out of Service.
++ */
++int qman_create_fq(u32 fqid, u32 flags, struct qman_fq *fq);
++
++/**
++ * qman_destroy_fq - Deallocates a FQ
++ * @fq: the frame queue object to release
++ * @flags: bit-mask of QMAN_FQ_FREE_*** options
++ *
++ * The memory for this frame queue object ('fq' provided in qman_create_fq()) is
++ * not deallocated but the caller regains ownership, to do with as desired. The
++ * FQ must be in the 'out-of-service' state unless the QMAN_FQ_FREE_PARKED flag
++ * is specified, in which case it may also be in the 'parked' state.
++ */
++void qman_destroy_fq(struct qman_fq *fq, u32 flags);
++
++/**
++ * qman_fq_fqid - Queries the frame queue ID of a FQ object
++ * @fq: the frame queue object to query
++ */
++u32 qman_fq_fqid(struct qman_fq *fq);
++
++/**
++ * qman_fq_state - Queries the state of a FQ object
++ * @fq: the frame queue object to query
++ * @state: pointer to state enum to return the FQ scheduling state
++ * @flags: pointer to state flags to receive QMAN_FQ_STATE_*** bitmask
++ *
++ * Queries the state of the FQ object, without performing any h/w commands.
++ * This captures the state, as seen by the driver, at the time the function
++ * executes.
++ */
++void qman_fq_state(struct qman_fq *fq, enum qman_fq_state *state, u32 *flags);
++
++/**
++ * qman_init_fq - Initialises FQ fields, leaves the FQ "parked" or "scheduled"
++ * @fq: the frame queue object to modify, must be 'parked' or new.
++ * @flags: bit-mask of QMAN_INITFQ_FLAG_*** options
++ * @opts: the FQ-modification settings, as defined in the low-level API
++ *
++ * The @opts parameter comes from the low-level portal API. Select
++ * QMAN_INITFQ_FLAG_SCHED in @flags to cause the frame queue to be scheduled
++ * rather than parked. NB, @opts can be NULL.
++ *
++ * Note that some fields and options within @opts may be ignored or overwritten
++ * by the driver;
++ * 1. the 'count' and 'fqid' fields are always ignored (this operation only
++ * affects one frame queue: @fq).
++ * 2. the QM_INITFQ_WE_CONTEXTB option of the 'we_mask' field and the associated
++ * 'fqd' structure's 'context_b' field are sometimes overwritten;
++ *   - if @fq was not created with QMAN_FQ_FLAG_TO_DCPORTAL, then context_b is
++ *     initialised to a value used by the driver for demux.
++ *   - if context_b is initialised for demux, so is context_a in case stashing
++ *     is requested (see item 4).
++ * (So caller control of context_b is only possible for TO_DCPORTAL frame queue
++ * objects.)
++ * 3. if @flags contains QMAN_INITFQ_FLAG_LOCAL, the 'fqd' structure's
++ * 'dest::channel' field will be overwritten to match the portal used to issue
++ * the command. If the WE_DESTWQ write-enable bit had already been set by the
++ * caller, the channel workqueue will be left as-is, otherwise the write-enable
++ * bit is set and the workqueue is set to a default of 4. If the "LOCAL" flag
++ * isn't set, the destination channel/workqueue fields and the write-enable bit
++ * are left as-is.
++ * 4. if the driver overwrites context_a/b for demux, then if
++ * QM_INITFQ_WE_CONTEXTA is set, the driver will only overwrite
++ * context_a.address fields and will leave the stashing fields provided by the
++ * user alone, otherwise it will zero out the context_a.stashing fields.
++ */
++int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts);
++
++/**
++ * qman_schedule_fq - Schedules a FQ
++ * @fq: the frame queue object to schedule, must be 'parked'
++ *
++ * Schedules the frame queue, which must be Parked, which takes it to
++ * Tentatively-Scheduled or Truly-Scheduled depending on its fill-level.
++ */
++int qman_schedule_fq(struct qman_fq *fq);
++
++/**
++ * qman_retire_fq - Retires a FQ
++ * @fq: the frame queue object to retire
++ * @flags: FQ flags (as per qman_fq_state) if retirement completes immediately
++ *
++ * Retires the frame queue. This returns zero if it succeeds immediately, +1 if
++ * the retirement was started asynchronously, otherwise it returns negative for
++ * failure. When this function returns zero, @flags is set to indicate whether
++ * the retired FQ is empty and/or whether it has any ORL fragments (to show up
++ * as ERNs). Otherwise the corresponding flags will be known when a subsequent
++ * FQRN message shows up on the portal's message ring.
++ *
++ * NB, if the retirement is asynchronous (the FQ was in the Truly Scheduled or
++ * Active state), the completion will be via the message ring as a FQRN - but
++ * the corresponding callback may occur before this function returns!! Ie. the
++ * caller should be prepared to accept the callback as the function is called,
++ * not only once it has returned.
++ */
++int qman_retire_fq(struct qman_fq *fq, u32 *flags);
++
++/**
++ * qman_oos_fq - Puts a FQ "out of service"
++ * @fq: the frame queue object to be put out-of-service, must be 'retired'
++ *
++ * The frame queue must be retired and empty, and if any order restoration list
++ * was released as ERNs at the time of retirement, they must all be consumed.
++ */
++int qman_oos_fq(struct qman_fq *fq);
++
++/**
++ * qman_fq_flow_control - Set the XON/XOFF state of a FQ
++ * @fq: the frame queue object to be set to XON/XOFF state, must not be 'oos',
++ * or 'retired' or 'parked' state
++ * @xon: boolean to set fq in XON or XOFF state
++ *
++ * The frame should be in Tentatively Scheduled state or Truly Schedule sate,
++ * otherwise the IFSI interrupt will be asserted.
++ */
++int qman_fq_flow_control(struct qman_fq *fq, int xon);
++
++/**
++ * qman_query_fq - Queries FQD fields (via h/w query command)
++ * @fq: the frame queue object to be queried
++ * @fqd: storage for the queried FQD fields
++ */
++int qman_query_fq(struct qman_fq *fq, struct qm_fqd *fqd);
++
++/**
++ * qman_query_fq_np - Queries non-programmable FQD fields
++ * @fq: the frame queue object to be queried
++ * @np: storage for the queried FQD fields
++ */
++int qman_query_fq_np(struct qman_fq *fq, struct qm_mcr_queryfq_np *np);
++
++/**
++ * qman_query_wq - Queries work queue lengths
++ * @query_dedicated: If non-zero, query length of WQs in the channel dedicated
++ *            to this software portal. Otherwise, query length of WQs in a
++ *            channel  specified in wq.
++ * @wq: storage for the queried WQs lengths. Also specified the channel to
++ *    to query if query_dedicated is zero.
++ */
++int qman_query_wq(u8 query_dedicated, struct qm_mcr_querywq *wq);
++
++/**
++ * qman_volatile_dequeue - Issue a volatile dequeue command
++ * @fq: the frame queue object to dequeue from
++ * @flags: a bit-mask of QMAN_VOLATILE_FLAG_*** options
++ * @vdqcr: bit mask of QM_VDQCR_*** options, as per qm_dqrr_vdqcr_set()
++ *
++ * Attempts to lock access to the portal's VDQCR volatile dequeue functionality.
++ * The function will block and sleep if QMAN_VOLATILE_FLAG_WAIT is specified and
++ * the VDQCR is already in use, otherwise returns non-zero for failure. If
++ * QMAN_VOLATILE_FLAG_FINISH is specified, the function will only return once
++ * the VDQCR command has finished executing (ie. once the callback for the last
++ * DQRR entry resulting from the VDQCR command has been called). If not using
++ * the FINISH flag, completion can be determined either by detecting the
++ * presence of the QM_DQRR_STAT_UNSCHEDULED and QM_DQRR_STAT_DQCR_EXPIRED bits
++ * in the "stat" field of the "struct qm_dqrr_entry" passed to the FQ's dequeue
++ * callback, or by waiting for the QMAN_FQ_STATE_VDQCR bit to disappear from the
++ * "flags" retrieved from qman_fq_state().
++ */
++int qman_volatile_dequeue(struct qman_fq *fq, u32 flags, u32 vdqcr);
++
++/**
++ * qman_enqueue - Enqueue a frame to a frame queue
++ * @fq: the frame queue object to enqueue to
++ * @fd: a descriptor of the frame to be enqueued
++ * @flags: bit-mask of QMAN_ENQUEUE_FLAG_*** options
++ *
++ * Fills an entry in the EQCR of portal @qm to enqueue the frame described by
++ * @fd. The descriptor details are copied from @fd to the EQCR entry, the 'pid'
++ * field is ignored. The return value is non-zero on error, such as ring full
++ * (and FLAG_WAIT not specified), congestion avoidance (FLAG_WATCH_CGR
++ * specified), etc. If the ring is full and FLAG_WAIT is specified, this
++ * function will block. If FLAG_INTERRUPT is set, the EQCI bit of the portal
++ * interrupt will assert when Qman consumes the EQCR entry (subject to "status
++ * disable", "enable", and "inhibit" registers). If FLAG_DCA is set, Qman will
++ * perform an implied "discrete consumption acknowledgement" on the dequeue
++ * ring's (DQRR) entry, at the ring index specified by the FLAG_DCA_IDX(x)
++ * macro. (As an alternative to issuing explicit DCA actions on DQRR entries,
++ * this implicit DCA can delay the release of a "held active" frame queue
++ * corresponding to a DQRR entry until Qman consumes the EQCR entry - providing
++ * order-preservation semantics in packet-forwarding scenarios.) If FLAG_DCA is
++ * set, then FLAG_DCA_PARK can also be set to imply that the DQRR consumption
++ * acknowledgement should "park request" the "held active" frame queue. Ie.
++ * when the portal eventually releases that frame queue, it will be left in the
++ * Parked state rather than Tentatively Scheduled or Truly Scheduled. If the
++ * portal is watching congestion groups, the QMAN_ENQUEUE_FLAG_WATCH_CGR flag
++ * is requested, and the FQ is a member of a congestion group, then this
++ * function returns -EAGAIN if the congestion group is currently congested.
++ * Note, this does not eliminate ERNs, as the async interface means we can be
++ * sending enqueue commands to an un-congested FQ that becomes congested before
++ * the enqueue commands are processed, but it does minimise needless thrashing
++ * of an already busy hardware resource by throttling many of the to-be-dropped
++ * enqueues "at the source".
++ */
++int qman_enqueue(struct qman_fq *fq, const struct qm_fd *fd, u32 flags);
++
++typedef int (*qman_cb_precommit) (void *arg);
++/**
++ * qman_enqueue_precommit - Enqueue a frame to a frame queue and call cb
++ * @fq: the frame queue object to enqueue to
++ * @fd: a descriptor of the frame to be enqueued
++ * @flags: bit-mask of QMAN_ENQUEUE_FLAG_*** options
++ * @cb: user supplied callback function to invoke before writing commit verb.
++ * @cb_arg: callback function argument
++ *
++ * This is similar to qman_enqueue except that it will invoke a user supplied
++ * callback function just before writng the commit verb. This is useful
++ * when the user want to do something *just before* enqueuing the request and
++ * the enqueue can't fail.
++ */
++int qman_enqueue_precommit(struct qman_fq *fq, const struct qm_fd *fd,
++              u32 flags, qman_cb_precommit cb, void *cb_arg);
++
++/**
++ * qman_enqueue_orp - Enqueue a frame to a frame queue using an ORP
++ * @fq: the frame queue object to enqueue to
++ * @fd: a descriptor of the frame to be enqueued
++ * @flags: bit-mask of QMAN_ENQUEUE_FLAG_*** options
++ * @orp: the frame queue object used as an order restoration point.
++ * @orp_seqnum: the sequence number of this frame in the order restoration path
++ *
++ * Similar to qman_enqueue(), but with the addition of an Order Restoration
++ * Point (@orp) and corresponding sequence number (@orp_seqnum) for this
++ * enqueue operation to employ order restoration. Each frame queue object acts
++ * as an Order Definition Point (ODP) by providing each frame dequeued from it
++ * with an incrementing sequence number, this value is generally ignored unless
++ * that sequence of dequeued frames will need order restoration later. Each
++ * frame queue object also encapsulates an Order Restoration Point (ORP), which
++ * is a re-assembly context for re-ordering frames relative to their sequence
++ * numbers as they are enqueued. The ORP does not have to be within the frame
++ * queue that receives the enqueued frame, in fact it is usually the frame
++ * queue from which the frames were originally dequeued. For the purposes of
++ * order restoration, multiple frames (or "fragments") can be enqueued for a
++ * single sequence number by setting the QMAN_ENQUEUE_FLAG_NLIS flag for all
++ * enqueues except the final fragment of a given sequence number. Ordering
++ * between sequence numbers is guaranteed, even if fragments of different
++ * sequence numbers are interlaced with one another. Fragments of the same
++ * sequence number will retain the order in which they are enqueued. If no
++ * enqueue is to performed, QMAN_ENQUEUE_FLAG_HOLE indicates that the given
++ * sequence number is to be "skipped" by the ORP logic (eg. if a frame has been
++ * dropped from a sequence), or QMAN_ENQUEUE_FLAG_NESN indicates that the given
++ * sequence number should become the ORP's "Next Expected Sequence Number".
++ *
++ * Side note: a frame queue object can be used purely as an ORP, without
++ * carrying any frames at all. Care should be taken not to deallocate a frame
++ * queue object that is being actively used as an ORP, as a future allocation
++ * of the frame queue object may start using the internal ORP before the
++ * previous use has finished.
++ */
++int qman_enqueue_orp(struct qman_fq *fq, const struct qm_fd *fd, u32 flags,
++                      struct qman_fq *orp, u16 orp_seqnum);
++
++/**
++ * qman_alloc_fqid_range - Allocate a contiguous range of FQIDs
++ * @result: is set by the API to the base FQID of the allocated range
++ * @count: the number of FQIDs required
++ * @align: required alignment of the allocated range
++ * @partial: non-zero if the API can return fewer than @count FQIDs
++ *
++ * Returns the number of frame queues allocated, or a negative error code. If
++ * @partial is non zero, the allocation request may return a smaller range of
++ * FQs than requested (though alignment will be as requested). If @partial is
++ * zero, the return value will either be 'count' or negative.
++ */
++int qman_alloc_fqid_range(u32 *result, u32 count, u32 align, int partial);
++static inline int qman_alloc_fqid(u32 *result)
++{
++      int ret = qman_alloc_fqid_range(result, 1, 0, 0);
++      return (ret > 0) ? 0 : ret;
++}
++
++/**
++ * qman_release_fqid_range - Release the specified range of frame queue IDs
++ * @fqid: the base FQID of the range to deallocate
++ * @count: the number of FQIDs in the range
++ *
++ * This function can also be used to seed the allocator with ranges of FQIDs
++ * that it can subsequently allocate from.
++ */
++void qman_release_fqid_range(u32 fqid, unsigned int count);
++static inline void qman_release_fqid(u32 fqid)
++{
++      qman_release_fqid_range(fqid, 1);
++}
++
++void qman_seed_fqid_range(u32 fqid, unsigned int count);
++
++
++int qman_shutdown_fq(u32 fqid);
++
++/**
++ * qman_reserve_fqid_range - Reserve the specified range of frame queue IDs
++ * @fqid: the base FQID of the range to deallocate
++ * @count: the number of FQIDs in the range
++ */
++int qman_reserve_fqid_range(u32 fqid, unsigned int count);
++static inline int qman_reserve_fqid(u32 fqid)
++{
++      return qman_reserve_fqid_range(fqid, 1);
++}
++
++      /* Pool-channel management */
++      /* ----------------------- */
++/**
++ * qman_alloc_pool_range - Allocate a contiguous range of pool-channel IDs
++ * @result: is set by the API to the base pool-channel ID of the allocated range
++ * @count: the number of pool-channel IDs required
++ * @align: required alignment of the allocated range
++ * @partial: non-zero if the API can return fewer than @count
++ *
++ * Returns the number of pool-channel IDs allocated, or a negative error code.
++ * If @partial is non zero, the allocation request may return a smaller range of
++ * than requested (though alignment will be as requested). If @partial is zero,
++ * the return value will either be 'count' or negative.
++ */
++int qman_alloc_pool_range(u32 *result, u32 count, u32 align, int partial);
++static inline int qman_alloc_pool(u32 *result)
++{
++      int ret = qman_alloc_pool_range(result, 1, 0, 0);
++      return (ret > 0) ? 0 : ret;
++}
++
++/**
++ * qman_release_pool_range - Release the specified range of pool-channel IDs
++ * @id: the base pool-channel ID of the range to deallocate
++ * @count: the number of pool-channel IDs in the range
++ */
++void qman_release_pool_range(u32 id, unsigned int count);
++static inline void qman_release_pool(u32 id)
++{
++      qman_release_pool_range(id, 1);
++}
++
++/**
++ * qman_reserve_pool_range - Reserve the specified range of pool-channel IDs
++ * @id: the base pool-channel ID of the range to reserve
++ * @count: the number of pool-channel IDs in the range
++ */
++int qman_reserve_pool_range(u32 id, unsigned int count);
++static inline int qman_reserve_pool(u32 id)
++{
++      return qman_reserve_pool_range(id, 1);
++}
++
++void qman_seed_pool_range(u32 id, unsigned int count);
++
++      /* CGR management */
++      /* -------------- */
++/**
++ * qman_create_cgr - Register a congestion group object
++ * @cgr: the 'cgr' object, with fields filled in
++ * @flags: QMAN_CGR_FLAG_* values
++ * @opts: optional state of CGR settings
++ *
++ * Registers this object to receiving congestion entry/exit callbacks on the
++ * portal affine to the cpu portal on which this API is executed. If opts is
++ * NULL then only the callback (cgr->cb) function is registered. If @flags
++ * contains QMAN_CGR_FLAG_USE_INIT, then an init hw command (which will reset
++ * any unspecified parameters) will be used rather than a modify hw hardware
++ * (which only modifies the specified parameters).
++ */
++int qman_create_cgr(struct qman_cgr *cgr, u32 flags,
++                      struct qm_mcc_initcgr *opts);
++
++/**
++ * qman_create_cgr_to_dcp - Register a congestion group object to DCP portal
++ * @cgr: the 'cgr' object, with fields filled in
++ * @flags: QMAN_CGR_FLAG_* values
++ * @dcp_portal: the DCP portal to which the cgr object is registered.
++ * @opts: optional state of CGR settings
++ *
++ */
++int qman_create_cgr_to_dcp(struct qman_cgr *cgr, u32 flags, u16 dcp_portal,
++                              struct qm_mcc_initcgr *opts);
++
++/**
++ * qman_delete_cgr - Deregisters a congestion group object
++ * @cgr: the 'cgr' object to deregister
++ *
++ * "Unplugs" this CGR object from the portal affine to the cpu on which this API
++ * is executed. This must be excuted on the same affine portal on which it was
++ * created.
++ */
++int qman_delete_cgr(struct qman_cgr *cgr);
++
++/**
++ * qman_delete_cgr_safe - Deregisters a congestion group object from any CPU
++ * @cgr: the 'cgr' object to deregister
++ *
++ * This will select the proper CPU and run there qman_delete_cgr().
++ */
++void qman_delete_cgr_safe(struct qman_cgr *cgr);
++
++/**
++ * qman_modify_cgr - Modify CGR fields
++ * @cgr: the 'cgr' object to modify
++ * @flags: QMAN_CGR_FLAG_* values
++ * @opts: the CGR-modification settings
++ *
++ * The @opts parameter comes from the low-level portal API, and can be NULL.
++ * Note that some fields and options within @opts may be ignored or overwritten
++ * by the driver, in particular the 'cgrid' field is ignored (this operation
++ * only affects the given CGR object). If @flags contains
++ * QMAN_CGR_FLAG_USE_INIT, then an init hw command (which will reset any
++ * unspecified parameters) will be used rather than a modify hw hardware (which
++ * only modifies the specified parameters).
++ */
++int qman_modify_cgr(struct qman_cgr *cgr, u32 flags,
++                      struct qm_mcc_initcgr *opts);
++
++/**
++* qman_query_cgr - Queries CGR fields
++* @cgr: the 'cgr' object to query
++* @result: storage for the queried congestion group record
++*/
++int qman_query_cgr(struct qman_cgr *cgr, struct qm_mcr_querycgr *result);
++
++/**
++ * qman_query_congestion - Queries the state of all congestion groups
++ * @congestion: storage for the queried state of all congestion groups
++ */
++int qman_query_congestion(struct qm_mcr_querycongestion *congestion);
++
++/**
++ * qman_alloc_cgrid_range - Allocate a contiguous range of CGR IDs
++ * @result: is set by the API to the base CGR ID of the allocated range
++ * @count: the number of CGR IDs required
++ * @align: required alignment of the allocated range
++ * @partial: non-zero if the API can return fewer than @count
++ *
++ * Returns the number of CGR IDs allocated, or a negative error code.
++ * If @partial is non zero, the allocation request may return a smaller range of
++ * than requested (though alignment will be as requested). If @partial is zero,
++ * the return value will either be 'count' or negative.
++ */
++int qman_alloc_cgrid_range(u32 *result, u32 count, u32 align, int partial);
++static inline int qman_alloc_cgrid(u32 *result)
++{
++      int ret = qman_alloc_cgrid_range(result, 1, 0, 0);
++      return (ret > 0) ? 0 : ret;
++}
++
++/**
++ * qman_release_cgrid_range - Release the specified range of CGR IDs
++ * @id: the base CGR ID of the range to deallocate
++ * @count: the number of CGR IDs in the range
++ */
++void qman_release_cgrid_range(u32 id, unsigned int count);
++static inline void qman_release_cgrid(u32 id)
++{
++      qman_release_cgrid_range(id, 1);
++}
++
++/**
++ * qman_reserve_cgrid_range - Reserve the specified range of CGR ID
++ * @id: the base CGR ID of the range to reserve
++ * @count: the number of CGR IDs in the range
++ */
++int qman_reserve_cgrid_range(u32 id, unsigned int count);
++static inline int qman_reserve_cgrid(u32 id)
++{
++      return qman_reserve_cgrid_range(id, 1);
++}
++
++void qman_seed_cgrid_range(u32 id, unsigned int count);
++
++
++      /* Helpers */
++      /* ------- */
++/**
++ * qman_poll_fq_for_init - Check if an FQ has been initialised from OOS
++ * @fqid: the FQID that will be initialised by other s/w
++ *
++ * In many situations, a FQID is provided for communication between s/w
++ * entities, and whilst the consumer is responsible for initialising and
++ * scheduling the FQ, the producer(s) generally create a wrapper FQ object using
++ * and only call qman_enqueue() (no FQ initialisation, scheduling, etc). Ie;
++ *     qman_create_fq(..., QMAN_FQ_FLAG_NO_MODIFY, ...);
++ * However, data can not be enqueued to the FQ until it is initialised out of
++ * the OOS state - this function polls for that condition. It is particularly
++ * useful for users of IPC functions - each endpoint's Rx FQ is the other
++ * endpoint's Tx FQ, so each side can initialise and schedule their Rx FQ object
++ * and then use this API on the (NO_MODIFY) Tx FQ object in order to
++ * synchronise. The function returns zero for success, +1 if the FQ is still in
++ * the OOS state, or negative if there was an error.
++ */
++static inline int qman_poll_fq_for_init(struct qman_fq *fq)
++{
++      struct qm_mcr_queryfq_np np;
++      int err;
++      err = qman_query_fq_np(fq, &np);
++      if (err)
++              return err;
++      if ((np.state & QM_MCR_NP_STATE_MASK) == QM_MCR_NP_STATE_OOS)
++              return 1;
++      return 0;
++}
++
++      /* -------------- */
++      /* CEETM :: types */
++      /* -------------- */
++/**
++ * Token Rate Structure
++ * Shaping rates are based on a "credit" system and a pre-configured h/w
++ * internal timer. The following type represents a shaper "rate" parameter as a
++ * fractional number of "tokens". Here's how it works. This (fractional) number
++ * of tokens is added to the shaper's "credit" every time the h/w timer elapses
++ * (up to a limit which is set by another shaper parameter). Every time a frame
++ * is enqueued through a shaper, the shaper deducts as many tokens as there are
++ * bytes of data in the enqueued frame. A shaper will not allow itself to
++ * enqueue any frames if its token count is negative. As such;
++ *
++ *         The rate at which data is enqueued is limited by the
++ *         rate at which tokens are added.
++ *
++ * Therefore if the user knows the period between these h/w timer updates in
++ * seconds, they can calculate the maximum traffic rate of the shaper (in
++ * bytes-per-second) from the token rate. And vice versa, they can calculate
++ * the token rate to use in order to achieve a given traffic rate.
++ */
++struct qm_ceetm_rate {
++      /* The token rate is; whole + (fraction/8192) */
++      u32 whole:11; /* 0..2047 */
++      u32 fraction:13; /* 0..8191 */
++};
++
++struct qm_ceetm_weight_code {
++      /* The weight code is; 5 msbits + 3 lsbits */
++      u8 y:5;
++      u8 x:3;
++};
++
++struct qm_ceetm {
++      unsigned int idx;
++      struct list_head sub_portals;
++      struct list_head lnis;
++      unsigned int sp_range[2];
++      unsigned int lni_range[2];
++};
++
++struct qm_ceetm_sp {
++      struct list_head node;
++      unsigned int idx;
++      unsigned int dcp_idx;
++      int is_claimed;
++      struct qm_ceetm_lni *lni;
++};
++
++/* Logical Network Interface */
++struct qm_ceetm_lni {
++      struct list_head node;
++      unsigned int idx;
++      unsigned int dcp_idx;
++      int is_claimed;
++      struct qm_ceetm_sp *sp;
++      struct list_head channels;
++      int shaper_enable;
++      int shaper_couple;
++      int oal;
++      struct qm_ceetm_rate cr_token_rate;
++      struct qm_ceetm_rate er_token_rate;
++      u16 cr_token_bucket_limit;
++      u16 er_token_bucket_limit;
++};
++
++/* Class Queue Channel */
++struct qm_ceetm_channel {
++      struct list_head node;
++      unsigned int idx;
++      unsigned int lni_idx;
++      unsigned int dcp_idx;
++      struct list_head class_queues;
++      struct list_head ccgs;
++      u8 shaper_enable;
++      u8 shaper_couple;
++      struct qm_ceetm_rate cr_token_rate;
++      struct qm_ceetm_rate er_token_rate;
++      u16 cr_token_bucket_limit;
++      u16 er_token_bucket_limit;
++};
++
++struct qm_ceetm_ccg;
++
++/* This callback type is used when handling congestion entry/exit. The
++ * 'cb_ctx' value is the opaque value associated with ccg object.
++ * 'congested' is non-zero on congestion-entry, and zero on congestion-exit.
++ */
++typedef void (*qman_cb_ccgr)(struct qm_ceetm_ccg *ccg, void *cb_ctx,
++                                                      int congested);
++
++/* Class Congestion Group */
++struct qm_ceetm_ccg {
++      struct qm_ceetm_channel *parent;
++      struct list_head node;
++      struct list_head cb_node;
++      qman_cb_ccgr cb;
++      void *cb_ctx;
++      unsigned int idx;
++};
++
++/* Class Queue */
++struct qm_ceetm_cq {
++      struct qm_ceetm_channel *parent;
++      struct qm_ceetm_ccg *ccg;
++      struct list_head node;
++      unsigned int idx;
++      int is_claimed;
++      struct list_head bound_lfqids;
++      struct list_head binding_node;
++};
++
++/* Logical Frame Queue */
++struct qm_ceetm_lfq {
++      struct qm_ceetm_channel *parent;
++      struct list_head node;
++      unsigned int idx;
++      unsigned int dctidx;
++      u64 context_a;
++      u32 context_b;
++      qman_cb_mr ern;
++};
++
++/**
++ * qman_ceetm_bps2tokenrate - Given a desired rate 'bps' measured in bps
++ * (ie. bits-per-second), compute the 'token_rate' fraction that best
++ * approximates that rate.
++ * @bps: the desired shaper rate in bps.
++ * @token_rate: the output token rate computed with the given kbps.
++ * @rounding: dictates how to round if an exact conversion is not possible; if
++ * it is negative then 'token_rate' will round down to the highest value that
++ * does not exceed the desired rate, if it is positive then 'token_rate' will
++ * round up to the lowest value that is greater than or equal to the desired
++ * rate, and if it is zero then it will round to the nearest approximation,
++ * whether that be up or down.
++ *
++ * Return 0 for success, or -EINVAL if prescaler or qman clock is not available.
++  */
++int qman_ceetm_bps2tokenrate(u64 bps,
++                              struct qm_ceetm_rate *token_rate,
++                              int rounding);
++
++/**
++ * qman_ceetm_tokenrate2bps - Given a 'token_rate', compute the
++ * corresponding number of 'bps'.
++ * @token_rate: the input desired token_rate fraction.
++ * @bps: the output shaper rate in bps computed with the give token rate.
++ * @rounding: has the same semantics as the previous function.
++ *
++ * Return 0 for success, or -EINVAL if prescaler or qman clock is not available.
++ */
++int qman_ceetm_tokenrate2bps(const struct qm_ceetm_rate *token_rate,
++                            u64 *bps,
++                            int rounding);
++
++int qman_alloc_ceetm0_channel_range(u32 *result, u32 count, u32 align,
++                                                              int partial);
++static inline int qman_alloc_ceetm0_channel(u32 *result)
++{
++      int ret = qman_alloc_ceetm0_channel_range(result, 1, 0, 0);
++      return (ret > 0) ? 0 : ret;
++}
++void qman_release_ceetm0_channel_range(u32 channelid, u32 count);
++static inline void qman_release_ceetm0_channelid(u32 channelid)
++{
++      qman_release_ceetm0_channel_range(channelid, 1);
++}
++
++int qman_reserve_ceetm0_channel_range(u32 channelid, u32 count);
++static inline int qman_reserve_ceetm0_channelid(u32 channelid)
++{
++      return qman_reserve_ceetm0_channel_range(channelid, 1);
++}
++
++void qman_seed_ceetm0_channel_range(u32 channelid, u32 count);
++
++
++int qman_alloc_ceetm1_channel_range(u32 *result, u32 count, u32 align,
++                                                              int partial);
++static inline int qman_alloc_ceetm1_channel(u32 *result)
++{
++      int ret = qman_alloc_ceetm1_channel_range(result, 1, 0, 0);
++      return (ret > 0) ? 0 : ret;
++}
++void qman_release_ceetm1_channel_range(u32 channelid, u32 count);
++static inline void qman_release_ceetm1_channelid(u32 channelid)
++{
++      qman_release_ceetm1_channel_range(channelid, 1);
++}
++int qman_reserve_ceetm1_channel_range(u32 channelid, u32 count);
++static inline int qman_reserve_ceetm1_channelid(u32 channelid)
++{
++      return qman_reserve_ceetm1_channel_range(channelid, 1);
++}
++
++void qman_seed_ceetm1_channel_range(u32 channelid, u32 count);
++
++
++int qman_alloc_ceetm0_lfqid_range(u32 *result, u32 count, u32 align,
++                                                              int partial);
++static inline int qman_alloc_ceetm0_lfqid(u32 *result)
++{
++      int ret = qman_alloc_ceetm0_lfqid_range(result, 1, 0, 0);
++      return (ret > 0) ? 0 : ret;
++}
++void qman_release_ceetm0_lfqid_range(u32 lfqid, u32 count);
++static inline void qman_release_ceetm0_lfqid(u32 lfqid)
++{
++      qman_release_ceetm0_lfqid_range(lfqid, 1);
++}
++int qman_reserve_ceetm0_lfqid_range(u32 lfqid, u32 count);
++static inline int qman_reserve_ceetm0_lfqid(u32 lfqid)
++{
++      return qman_reserve_ceetm0_lfqid_range(lfqid, 1);
++}
++
++void qman_seed_ceetm0_lfqid_range(u32 lfqid, u32 count);
++
++
++int qman_alloc_ceetm1_lfqid_range(u32 *result, u32 count, u32 align,
++                                                              int partial);
++static inline int qman_alloc_ceetm1_lfqid(u32 *result)
++{
++      int ret = qman_alloc_ceetm1_lfqid_range(result, 1, 0, 0);
++      return (ret > 0) ? 0 : ret;
++}
++void qman_release_ceetm1_lfqid_range(u32 lfqid, u32 count);
++static inline void qman_release_ceetm1_lfqid(u32 lfqid)
++{
++      qman_release_ceetm1_lfqid_range(lfqid, 1);
++}
++int qman_reserve_ceetm1_lfqid_range(u32 lfqid, u32 count);
++static inline int qman_reserve_ceetm1_lfqid(u32 lfqid)
++{
++      return qman_reserve_ceetm1_lfqid_range(lfqid, 1);
++}
++
++void qman_seed_ceetm1_lfqid_range(u32 lfqid, u32 count);
++
++
++      /* ----------------------------- */
++      /* CEETM :: sub-portals          */
++      /* ----------------------------- */
++
++/**
++ * qman_ceetm_sp_claim - Claims the given sub-portal, provided it is available
++ * to us and configured for traffic-management.
++ * @sp: the returned sub-portal object, if successful.
++ * @dcp_id: specifies the desired Fman block (and thus the relevant CEETM
++ * instance),
++ * @sp_idx" is the desired sub-portal index from 0 to 15.
++ *
++ * Returns zero for success, or -ENODEV if the sub-portal is in use,  or -EINVAL
++ * if the sp_idx is out of range.
++ *
++ * Note that if there are multiple driver domains (eg. a linux kernel versus
++ * user-space drivers in USDPAA, or multiple guests running under a hypervisor)
++ * then a sub-portal may be accessible by more than one instance of a qman
++ * driver and so it may be claimed multiple times. If this is the case, it is
++ * up to the system architect to prevent conflicting configuration actions
++ * coming from the different driver domains. The qman drivers do not have any
++ * behind-the-scenes coordination to prevent this from happening.
++ */
++int qman_ceetm_sp_claim(struct qm_ceetm_sp **sp,
++                      enum qm_dc_portal dcp_idx,
++                      unsigned int sp_idx);
++
++/**
++ * qman_ceetm_sp_release - Releases a previously claimed sub-portal.
++ * @sp: the sub-portal to be released.
++ *
++ * Returns 0 for success, or -EBUSY for failure if the dependencies are not
++ * released.
++ */
++int qman_ceetm_sp_release(struct qm_ceetm_sp *sp);
++
++      /* ----------------------------------- */
++      /* CEETM :: logical network interfaces */
++      /* ----------------------------------- */
++
++/**
++ * qman_ceetm_lni_claim - Claims an unclaimed LNI.
++ * @lni: the returned LNI object, if successful.
++ * @dcp_id: specifies the desired Fman block (and thus the relevant CEETM
++ * instance)
++ * @lni_idx: is the desired LNI index.
++ *
++ * Returns zero for success, or -EINVAL on failure, which will happen if the LNI
++ * is not available or has already been claimed (and not yet successfully
++ * released), or lni_dix is out of range.
++ *
++ * Note that there may be multiple driver domains (or instances) that need to
++ * transmit out the same LNI, so this claim is only guaranteeing exclusivity
++ * within the domain of the driver being called. See qman_ceetm_sp_claim() and
++ * qman_ceetm_sp_get_lni() for more information.
++ */
++int qman_ceetm_lni_claim(struct qm_ceetm_lni **lni,
++                       enum qm_dc_portal dcp_id,
++                       unsigned int lni_idx);
++
++/**
++ * qman_ceetm_lni_releaes - Releases a previously claimed LNI.
++ * @lni: the lni needs to be released.
++ *
++ * This will only succeed if all dependent objects have been released.
++ * Returns zero for success, or -EBUSY if the dependencies are not released.
++ */
++int qman_ceetm_lni_release(struct qm_ceetm_lni *lni);
++
++/**
++ * qman_ceetm_sp_set_lni
++ * qman_ceetm_sp_get_lni - Set/get the LNI that the sub-portal is currently
++ * mapped to.
++ * @sp: the given sub-portal.
++ * @lni(in "set"function): the LNI object which the sp will be mappaed to.
++ * @lni_idx(in "get" function): the LNI index which the sp is mapped to.
++ *
++ * Returns zero for success, or -EINVAL for the "set" function when this sp-lni
++ * mapping has been set, or configure mapping command returns error, and
++ * -EINVAL for "get" function when this sp-lni mapping is not set or the query
++ * mapping command returns error.
++ *
++ * This may be useful in situations where multiple driver domains have access
++ * to the same sub-portals in order to all be able to transmit out the same
++ * physical interface (perhaps they're on different IP addresses or VPNs, so
++ * Fman is splitting Rx traffic and here we need to converge Tx traffic). In
++ * that case, a control-plane is likely to use qman_ceetm_lni_claim() followed
++ * by qman_ceetm_sp_set_lni() to configure the sub-portal, and other domains
++ * are likely to use qman_ceetm_sp_get_lni() followed by qman_ceetm_lni_claim()
++ * in order to determine the LNI that the control-plane had assigned. This is
++ * why the "get" returns an index, whereas the "set" takes an (already claimed)
++ * LNI object.
++ */
++int qman_ceetm_sp_set_lni(struct qm_ceetm_sp *sp,
++                        struct qm_ceetm_lni *lni);
++int qman_ceetm_sp_get_lni(struct qm_ceetm_sp *sp,
++                        unsigned int *lni_idx);
++
++/**
++ * qman_ceetm_lni_enable_shaper
++ * qman_ceetm_lni_disable_shaper - Enables/disables shaping on the LNI.
++ * @lni: the given LNI.
++ * @coupled: indicates whether CR and ER are coupled.
++ * @oal: the overhead accounting length which is added to the actual length of
++ * each frame when performing shaper calculations.
++ *
++ * When the number of (unused) committed-rate tokens reach the committed-rate
++ * token limit, 'coupled' indicates whether surplus tokens should be added to
++ * the excess-rate token count (up to the excess-rate token limit).
++ * When LNI is claimed, the shaper is disabled by default. The enable function
++ * will turn on this shaper for this lni.
++ * Whenever a claimed LNI is first enabled for shaping, its committed and
++ * excess token rates and limits are zero, so will need to be changed to do
++ * anything useful. The shaper can subsequently be enabled/disabled without
++ * resetting the shaping parameters, but the shaping parameters will be reset
++ * when the LNI is released.
++ *
++ * Returns zero for success, or  errno for "enable" function in the cases as:
++ * a) -EINVAL if the shaper is already enabled,
++ * b) -EIO if the configure shaper command returns error.
++ * For "disable" function, returns:
++ * a) -EINVAL if the shaper is has already disabled.
++ * b) -EIO if calling configure shaper command returns error.
++ */
++int qman_ceetm_lni_enable_shaper(struct qm_ceetm_lni *lni, int coupled,
++                                                              int oal);
++int qman_ceetm_lni_disable_shaper(struct qm_ceetm_lni *lni);
++
++/**
++ * qman_ceetm_lni_is_shaper_enabled - Check LNI shaper status
++ * @lni: the give LNI
++ */
++int qman_ceetm_lni_is_shaper_enabled(struct qm_ceetm_lni *lni);
++
++/**
++ * qman_ceetm_lni_set_commit_rate
++ * qman_ceetm_lni_get_commit_rate
++ * qman_ceetm_lni_set_excess_rate
++ * qman_ceetm_lni_get_excess_rate - Set/get the shaper CR/ER token rate and
++ * token limit for the given LNI.
++ * @lni: the given LNI.
++ * @token_rate: the desired token rate for "set" fuction, or the token rate of
++ * the LNI queried by "get" function.
++ * @token_limit: the desired token bucket limit for "set" function, or the token
++ * limit of the given LNI queried by "get" function.
++ *
++ * Returns zero for success. The "set" function returns -EINVAL if the given
++ * LNI is unshapped or -EIO if the configure shaper command returns error.
++ * The "get" function returns -EINVAL if the token rate or the token limit is
++ * not set or the query command returns error.
++ */
++int qman_ceetm_lni_set_commit_rate(struct qm_ceetm_lni *lni,
++                                 const struct qm_ceetm_rate *token_rate,
++                                 u16 token_limit);
++int qman_ceetm_lni_get_commit_rate(struct qm_ceetm_lni *lni,
++                                 struct qm_ceetm_rate *token_rate,
++                                 u16 *token_limit);
++int qman_ceetm_lni_set_excess_rate(struct qm_ceetm_lni *lni,
++                                 const struct qm_ceetm_rate *token_rate,
++                                 u16 token_limit);
++int qman_ceetm_lni_get_excess_rate(struct qm_ceetm_lni *lni,
++                                 struct qm_ceetm_rate *token_rate,
++                                 u16 *token_limit);
++/**
++ * qman_ceetm_lni_set_commit_rate_bps
++ * qman_ceetm_lni_get_commit_rate_bps
++ * qman_ceetm_lni_set_excess_rate_bps
++ * qman_ceetm_lni_get_excess_rate_bps - Set/get the shaper CR/ER rate
++ * and token limit for the given LNI.
++ * @lni: the given LNI.
++ * @bps: the desired shaping rate in bps for "set" fuction, or the shaping rate
++ * of the LNI queried by "get" function.
++ * @token_limit: the desired token bucket limit for "set" function, or the token
++ * limit of the given LNI queried by "get" function.
++ *
++ * Returns zero for success. The "set" function returns -EINVAL if the given
++ * LNI is unshapped or -EIO if the configure shaper command returns error.
++ * The "get" function returns -EINVAL if the token rate or the token limit is
++ * not set or the query command returns error.
++ */
++int qman_ceetm_lni_set_commit_rate_bps(struct qm_ceetm_lni *lni,
++                                     u64 bps,
++                                     u16 token_limit);
++int qman_ceetm_lni_get_commit_rate_bps(struct qm_ceetm_lni *lni,
++                                     u64 *bps, u16 *token_limit);
++int qman_ceetm_lni_set_excess_rate_bps(struct qm_ceetm_lni *lni,
++                                     u64 bps,
++                                     u16 token_limit);
++int qman_ceetm_lni_get_excess_rate_bps(struct qm_ceetm_lni *lni,
++                                     u64 *bps, u16 *token_limit);
++
++/**
++ * qman_ceetm_lni_set_tcfcc
++ * qman_ceetm_lni_get_tcfcc - Configure/query "Traffic Class Flow Control".
++ * @lni: the given LNI.
++ * @cq_level: is between 0 and 15, representing individual class queue levels
++ * (CQ0 to CQ7 for every channel) and grouped class queue levels (CQ8 to CQ15
++ * for every channel).
++ * @traffic_class: is between 0 and 7 when associating a given class queue level
++ * to a traffic class, or -1 when disabling traffic class flow control for this
++ * class queue level.
++ *
++ * Return zero for success, or -EINVAL if the cq_level or traffic_class is out
++ * of range as indicated above, or -EIO if the configure/query tcfcc command
++ * returns error.
++ *
++ * Refer to the section of QMan CEETM traffic class flow control in the
++ * Reference Manual.
++ */
++int qman_ceetm_lni_set_tcfcc(struct qm_ceetm_lni *lni,
++                           unsigned int cq_level,
++                           int traffic_class);
++int qman_ceetm_lni_get_tcfcc(struct qm_ceetm_lni *lni,
++                           unsigned int cq_level,
++                           int *traffic_class);
++
++      /* ----------------------------- */
++      /* CEETM :: class queue channels */
++      /* ----------------------------- */
++
++/**
++ * qman_ceetm_channel_claim - Claims an unclaimed CQ channel that is mapped to
++ * the given LNI.
++ * @channel: the returned class queue channel object, if successful.
++ * @lni: the LNI that the channel belongs to.
++ *
++ * Channels are always initially "unshaped".
++ *
++ * Return zero for success, or -ENODEV if there is no channel available(all 32
++ * channels are claimed) or -EINVAL if the channel mapping command returns
++ * error.
++ */
++int qman_ceetm_channel_claim(struct qm_ceetm_channel **channel,
++                           struct qm_ceetm_lni *lni);
++
++/**
++ * qman_ceetm_channel_release - Releases a previously claimed CQ channel.
++ * @channel: the channel needs to be released.
++ *
++ * Returns zero for success, or -EBUSY if the dependencies are still in use.
++ *
++ * Note any shaping of the channel will be cleared to leave it in an unshaped
++ * state.
++ */
++int qman_ceetm_channel_release(struct qm_ceetm_channel *channel);
++
++/**
++ * qman_ceetm_channel_enable_shaper
++ * qman_ceetm_channel_disable_shaper - Enables/disables shaping on the channel.
++ * @channel: the given channel.
++ * @coupled: indicates whether surplus CR tokens should be added to the
++ * excess-rate token count (up to the excess-rate token limit) when the number
++ * of (unused) committed-rate tokens reach the committed_rate token limit.
++ *
++ * Whenever a claimed channel is first enabled for shaping, its committed and
++ * excess token rates and limits are zero, so will need to be changed to do
++ * anything useful. The shaper can subsequently be enabled/disabled without
++ * resetting the shaping parameters, but the shaping parameters will be reset
++ * when the channel is released.
++ *
++ * Return 0 for success, or -EINVAL for failure, in the case that the channel
++ * shaper has been enabled/disabled or the management command returns error.
++ */
++int qman_ceetm_channel_enable_shaper(struct qm_ceetm_channel *channel,
++                                                       int coupled);
++int qman_ceetm_channel_disable_shaper(struct qm_ceetm_channel *channel);
++
++/**
++ * qman_ceetm_channel_is_shaper_enabled - Check channel shaper status.
++ * @channel: the give channel.
++ */
++int qman_ceetm_channel_is_shaper_enabled(struct qm_ceetm_channel *channel);
++
++/**
++ * qman_ceetm_channel_set_commit_rate
++ * qman_ceetm_channel_get_commit_rate
++ * qman_ceetm_channel_set_excess_rate
++ * qman_ceetm_channel_get_excess_rate - Set/get channel CR/ER shaper parameters.
++ * @channel: the given channel.
++ * @token_rate: the desired token rate for "set" function, or the queried token
++ * rate for "get" function.
++ * @token_limit: the desired token limit for "set" function, or the queried
++ * token limit for "get" function.
++ *
++ * Return zero for success. The "set" function returns -EINVAL if the channel
++ * is unshaped, or -EIO if the configure shapper command returns error. The
++ * "get" function returns -EINVAL if token rate of token limit is not set, or
++ * the query shaper command returns error.
++ */
++int qman_ceetm_channel_set_commit_rate(struct qm_ceetm_channel *channel,
++                                 const struct qm_ceetm_rate *token_rate,
++                                 u16 token_limit);
++int qman_ceetm_channel_get_commit_rate(struct qm_ceetm_channel *channel,
++                                 struct qm_ceetm_rate *token_rate,
++                                 u16 *token_limit);
++int qman_ceetm_channel_set_excess_rate(struct qm_ceetm_channel *channel,
++                                 const struct qm_ceetm_rate *token_rate,
++                                 u16 token_limit);
++int qman_ceetm_channel_get_excess_rate(struct qm_ceetm_channel *channel,
++                                 struct qm_ceetm_rate *token_rate,
++                                 u16 *token_limit);
++/**
++ * qman_ceetm_channel_set_commit_rate_bps
++ * qman_ceetm_channel_get_commit_rate_bps
++ * qman_ceetm_channel_set_excess_rate_bps
++ * qman_ceetm_channel_get_excess_rate_bps - Set/get channel CR/ER shaper
++ * parameters.
++ * @channel: the given channel.
++ * @token_rate: the desired shaper rate in bps for "set" function, or the
++ * shaper rate in bps for "get" function.
++ * @token_limit: the desired token limit for "set" function, or the queried
++ * token limit for "get" function.
++ *
++ * Return zero for success. The "set" function returns -EINVAL if the channel
++ * is unshaped, or -EIO if the configure shapper command returns error. The
++ * "get" function returns -EINVAL if token rate of token limit is not set, or
++ * the query shaper command returns error.
++ */
++int qman_ceetm_channel_set_commit_rate_bps(struct qm_ceetm_channel *channel,
++                                         u64 bps, u16 token_limit);
++int qman_ceetm_channel_get_commit_rate_bps(struct qm_ceetm_channel *channel,
++                                         u64 *bps, u16 *token_limit);
++int qman_ceetm_channel_set_excess_rate_bps(struct qm_ceetm_channel *channel,
++                                         u64 bps, u16 token_limit);
++int qman_ceetm_channel_get_excess_rate_bps(struct qm_ceetm_channel *channel,
++                                         u64 *bps, u16 *token_limit);
++
++/**
++ * qman_ceetm_channel_set_weight
++ * qman_ceetm_channel_get_weight - Set/get the weight for unshaped channel
++ * @channel: the given channel.
++ * @token_limit: the desired token limit as the weight of the unshaped channel
++ * for "set" function, or the queried token limit for "get" function.
++ *
++ * The algorithm of unshaped fair queuing (uFQ) is used for unshaped channel.
++ * It allows the unshaped channels to be included in the CR time eligible list,
++ * and thus use the configured CR token limit value as their fair queuing
++ * weight.
++ *
++ * Return zero for success, or -EINVAL if the channel is a shaped channel or
++ * the management command returns error.
++ */
++int qman_ceetm_channel_set_weight(struct qm_ceetm_channel *channel,
++                                u16 token_limit);
++int qman_ceetm_channel_get_weight(struct qm_ceetm_channel *channel,
++                                u16 *token_limit);
++
++/**
++ * qman_ceetm_channel_set_group
++ * qman_ceetm_channel_get_group - Set/get the grouping of the class scheduler.
++ * @channel: the given channel.
++ * @group_b: indicates whether there is group B in this channel.
++ * @prio_a: the priority of group A.
++ * @prio_b: the priority of group B.
++ *
++ * There are 8 individual class queues (CQ0-CQ7), and 8 grouped class queues
++ * (CQ8-CQ15). If 'group_b' is zero, then all the grouped class queues are in
++ * group A, otherwise they are split into group A (CQ8-11) and group B
++ * (CQ12-C15). The individual class queues and the group(s) are in strict
++ * priority order relative to each other. Within the group(s), the scheduling
++ * is not strict priority order, but the result of scheduling within a group
++ * is in strict priority order relative to the other class queues in the
++ * channel. 'prio_a' and 'prio_b' control the priority order of the groups
++ * relative to the individual class queues, and take values from 0-7. Eg. if
++ * 'group_b' is non-zero, 'prio_a' is 2 and 'prio_b' is 6, then the strict
++ * priority order would be;
++ *      CQ0, CQ1, CQ2, GROUPA, CQ3, CQ4, CQ5, CQ6, GROUPB, CQ7
++ *
++ * Return 0 for success. For "set" function, returns -EINVAL if prio_a or
++ * prio_b are out of the range 0 - 7 (priority of group A or group B can not
++ * be 0, CQ0 is always the highest class queue in this channel.), or -EIO if
++ * the configure scheduler command returns error. For "get" function, return
++ * -EINVAL if the query scheduler command returns error.
++ */
++int qman_ceetm_channel_set_group(struct qm_ceetm_channel *channel,
++                           int group_b,
++                           unsigned int prio_a,
++                           unsigned int prio_b);
++int qman_ceetm_channel_get_group(struct qm_ceetm_channel *channel,
++                           int *group_b,
++                           unsigned int *prio_a,
++                           unsigned int *prio_b);
++
++/**
++ * qman_ceetm_channel_set_group_cr_eligibility
++ * qman_ceetm_channel_set_group_er_eligibility - Set channel group eligibility
++ * @channel: the given channel object
++ * @group_b: indicates whether there is group B in this channel.
++ * @cre: the commit rate eligibility, 1 for enable, 0 for disable.
++ *
++ * Return zero for success, or -EINVAL if eligibility setting fails.
++*/
++int qman_ceetm_channel_set_group_cr_eligibility(struct qm_ceetm_channel
++                              *channel, int group_b, int cre);
++int qman_ceetm_channel_set_group_er_eligibility(struct qm_ceetm_channel
++                              *channel, int group_b, int ere);
++
++/**
++ * qman_ceetm_channel_set_cq_cr_eligibility
++ * qman_ceetm_channel_set_cq_er_eligibility - Set channel cq eligibility
++ * @channel: the given channel object
++ * @idx: is from 0 to 7 (representing CQ0 to CQ7).
++ * @cre: the commit rate eligibility, 1 for enable, 0 for disable.
++ *
++ * Return zero for success, or -EINVAL if eligibility setting fails.
++*/
++int qman_ceetm_channel_set_cq_cr_eligibility(struct qm_ceetm_channel *channel,
++                                      unsigned int idx, int cre);
++int qman_ceetm_channel_set_cq_er_eligibility(struct qm_ceetm_channel *channel,
++                                      unsigned int idx, int ere);
++
++      /* --------------------- */
++      /* CEETM :: class queues */
++      /* --------------------- */
++
++/**
++ * qman_ceetm_cq_claim - Claims an individual class queue.
++ * @cq: the returned class queue object, if successful.
++ * @channel: the class queue channel.
++ * @idx: is from 0 to 7 (representing CQ0 to CQ7).
++ * @ccg: represents the class congestion group that this class queue should be
++ * subscribed to, or NULL if no congestion group membership is desired.
++ *
++ * Returns zero for success, or -EINVAL if @idx is out of range 0 - 7 or
++ * if this class queue has been claimed, or configure class queue command
++ * returns error, or returns -ENOMEM if allocating CQ memory fails.
++ */
++int qman_ceetm_cq_claim(struct qm_ceetm_cq **cq,
++                      struct qm_ceetm_channel *channel,
++                      unsigned int idx,
++                      struct qm_ceetm_ccg *ccg);
++
++/**
++ * qman_ceetm_cq_claim_A - Claims a class queue group A.
++ * @cq: the returned class queue object, if successful.
++ * @channel: the class queue channel.
++ * @idx: is from 8 to 15 if only group A exits, otherwise, it is from 8 to 11.
++ * @ccg: represents the class congestion group that this class queue should be
++ * subscribed to, or NULL if no congestion group membership is desired.
++ *
++ * Return zero for success, or -EINVAL if @idx is out the range or if
++ * this class queue has been claimed or configure class queue command returns
++ * error, or returns -ENOMEM if allocating CQ memory fails.
++ */
++int qman_ceetm_cq_claim_A(struct qm_ceetm_cq **cq,
++                              struct qm_ceetm_channel *channel,
++                              unsigned int idx,
++                              struct qm_ceetm_ccg *ccg);
++
++/**
++ * qman_ceetm_cq_claim_B - Claims a class queue group B.
++ * @cq: the returned class queue object, if successful.
++ * @channel: the class queue channel.
++ * @idx: is from 0 to 3 (CQ12 to CQ15).
++ * @ccg: represents the class congestion group that this class queue should be
++ * subscribed to, or NULL if no congestion group membership is desired.
++ *
++ * Return zero for success, or -EINVAL if @idx is out the range or if
++ * this class queue has been claimed or configure class queue command returns
++ * error, or returns -ENOMEM if allocating CQ memory fails.
++ */
++int qman_ceetm_cq_claim_B(struct qm_ceetm_cq **cq,
++                              struct qm_ceetm_channel *channel,
++                              unsigned int idx,
++                              struct qm_ceetm_ccg *ccg);
++
++/**
++ * qman_ceetm_cq_release - Releases a previously claimed class queue.
++ * @cq: The class queue to be released.
++ *
++ * Return zero for success, or -EBUSY if the dependent objects (eg. logical
++ * FQIDs) have not been released.
++ */
++int qman_ceetm_cq_release(struct qm_ceetm_cq *cq);
++
++/**
++ * qman_ceetm_set_queue_weight
++ * qman_ceetm_get_queue_weight - Configure/query the weight of a grouped class
++ * queue.
++ * @cq: the given class queue.
++ * @weight_code: the desired weight code to set for the given class queue for
++ * "set" function or the queired weight code for "get" function.
++ *
++ * Grouped class queues have a default weight code of zero, which corresponds to
++ * a scheduler weighting of 1. This function can be used to modify a grouped
++ * class queue to another weight, (Use the helpers qman_ceetm_wbfs2ratio()
++ * and qman_ceetm_ratio2wbfs() to convert between these 'weight_code' values
++ * and the corresponding sharing weight.)
++ *
++ * Returns zero for success, or -EIO if the configure weight command returns
++ * error for "set" function, or -EINVAL if the query command returns
++ * error for "get" function.
++ * See section "CEETM Weighted Scheduling among Grouped Classes" in Reference
++ * Manual for weight and weight code.
++ */
++int qman_ceetm_set_queue_weight(struct qm_ceetm_cq *cq,
++                              struct qm_ceetm_weight_code *weight_code);
++int qman_ceetm_get_queue_weight(struct qm_ceetm_cq *cq,
++                              struct qm_ceetm_weight_code *weight_code);
++
++/**
++ * qman_ceetm_set_queue_weight_in_ratio
++ * qman_ceetm_get_queue_weight_in_ratio - Configure/query the weight of a
++ * grouped class queue.
++ * @cq: the given class queue.
++ * @ratio: the weight in ratio. It should be the real ratio number multiplied
++ * by 100 to get rid of fraction.
++ *
++ * Returns zero for success, or -EIO if the configure weight command returns
++ * error for "set" function, or -EINVAL if the query command returns
++ * error for "get" function.
++ */
++int qman_ceetm_set_queue_weight_in_ratio(struct qm_ceetm_cq *cq, u32 ratio);
++int qman_ceetm_get_queue_weight_in_ratio(struct qm_ceetm_cq *cq, u32 *ratio);
++
++/* Weights are encoded using a pseudo-exponential scheme. The weight codes 0,
++ * 32, 64, [...] correspond to weights of 1, 2, 4, [...]. The weights
++ * corresponding to intermediate weight codes are calculated using linear
++ * interpolation on the inverted values. Or put another way, the inverse weights
++ * for each 32nd weight code are 1, 1/2, 1/4, [...], and so the intervals
++ * between these are divided linearly into 32 intermediate values, the inverses
++ * of which form the remaining weight codes.
++ *
++ * The Weighted Bandwidth Fair Scheduling (WBFS) algorithm provides a form of
++ * scheduling within a group of class queues (group A or B). Weights are used to
++ * normalise the class queues to an underlying BFS algorithm where all class
++ * queues are assumed to require "equal bandwidth". So the weights referred to
++ * by the weight codes act as divisors on the size of frames being enqueued. Ie.
++ * one class queue in a group is assigned a weight of 2 whilst the other class
++ * queues in the group keep the default weight of 1, then the WBFS scheduler
++ * will effectively treat all frames enqueued on the weight-2 class queue as
++ * having half the number of bytes they really have. Ie. if all other things are
++ * equal, that class queue would get twice as much bytes-per-second bandwidth as
++ * the others. So weights should be chosen to provide bandwidth ratios between
++ * members of the same class queue group. These weights have no bearing on
++ * behaviour outside that group's WBFS mechanism though.
++ */
++
++/**
++ * qman_ceetm_wbfs2ratio - Given a weight code ('wbfs'), an accurate fractional
++ * representation of the corresponding weight is given (in order to not lose
++ * any precision).
++ * @weight_code: The given weight code in WBFS.
++ * @numerator: the numerator part of the weight computed by the weight code.
++ * @denominator: the denominator part of the weight computed by the weight code
++ *
++ * Returns zero for success or -EINVAL if the given weight code is illegal.
++ */
++int qman_ceetm_wbfs2ratio(struct qm_ceetm_weight_code *weight_code,
++                         u32 *numerator,
++                         u32 *denominator);
++/**
++ * qman_ceetm_ratio2wbfs - Given a weight, find the nearest possible weight code
++ * If the user needs to know how close this is, convert the resulting weight
++ * code back to a weight and compare.
++ * @numerator: numerator part of the given weight.
++ * @denominator: denominator part of the given weight.
++ * @weight_code: the weight code computed from the given weight.
++ *
++ * Returns zero for success, or -ERANGE if "numerator/denominator" is outside
++ * the range of weights.
++ */
++int qman_ceetm_ratio2wbfs(u32 numerator,
++                         u32 denominator,
++                         struct qm_ceetm_weight_code *weight_code,
++                         int rounding);
++
++#define QMAN_CEETM_FLAG_CLEAR_STATISTICS_COUNTER      0x1
++/**
++ * qman_ceetm_cq_get_dequeue_statistics - Get the statistics provided by CEETM
++ * CQ counters.
++ * @cq: the given CQ object.
++ * @flags: indicates whether the statistics counter will be cleared after query.
++ * @frame_count: The number of the frames that have been counted since the
++ * counter was cleared last time.
++ * @byte_count: the number of bytes in all frames that have been counted.
++ *
++ * Return zero for success or -EINVAL if query statistics command returns error.
++ *
++ */
++int qman_ceetm_cq_get_dequeue_statistics(struct qm_ceetm_cq *cq, u32 flags,
++                                      u64 *frame_count, u64 *byte_count);
++
++/**
++ * qman_ceetm_drain_cq - drain the CQ till it is empty.
++ * @cq: the give CQ object.
++ * Return 0 for success or -EINVAL for unsuccessful command to empty CQ.
++ */
++int qman_ceetm_drain_cq(struct qm_ceetm_cq *cq);
++
++      /* ---------------------- */
++      /* CEETM :: logical FQIDs */
++      /* ---------------------- */
++/**
++ * qman_ceetm_lfq_claim - Claims an unused logical FQID, associates it with
++ * the given class queue.
++ * @lfq: the returned lfq object, if successful.
++ * @cq: the class queue which needs to claim a LFQID.
++ *
++ * Return zero for success, or -ENODEV if no LFQID is available or -ENOMEM if
++ * allocating memory for lfq fails, or -EINVAL if configuring LFQMT fails.
++ */
++int qman_ceetm_lfq_claim(struct qm_ceetm_lfq **lfq,
++                              struct qm_ceetm_cq *cq);
++
++/**
++ * qman_ceetm_lfq_release - Releases a previously claimed logical FQID.
++ * @lfq: the lfq to be released.
++ *
++ * Return zero for success.
++ */
++int qman_ceetm_lfq_release(struct qm_ceetm_lfq *lfq);
++
++/**
++ * qman_ceetm_lfq_set_context
++ * qman_ceetm_lfq_get_context - Set/get the context_a/context_b pair to the
++ * "dequeue context table" associated with the logical FQID.
++ * @lfq: the given logical FQ object.
++ * @context_a: contextA of the dequeue context.
++ * @context_b: contextB of the dequeue context.
++ *
++ * Returns zero for success, or -EINVAL if there is error to set/get the
++ * context pair.
++ */
++int qman_ceetm_lfq_set_context(struct qm_ceetm_lfq *lfq,
++                              u64 context_a,
++                              u32 context_b);
++int qman_ceetm_lfq_get_context(struct qm_ceetm_lfq *lfq,
++                              u64 *context_a,
++                              u32 *context_b);
++
++/**
++ * qman_ceetm_create_fq - Initialise a FQ object for the LFQ.
++ * @lfq: the given logic fq.
++ * @fq: the fq object created for the given logic fq.
++ *
++ * The FQ object can be used in qman_enqueue() and qman_enqueue_orp() APIs to
++ * target a logical FQID (and the class queue it is associated with).
++ * Note that this FQ object can only be used for enqueues, and
++ * in the case of qman_enqueue_orp() it can not be used as the 'orp' parameter,
++ * only as 'fq'. This FQ object can not (and shouldn't) be destroyed, it is only
++ * valid as long as the underlying 'lfq' remains claimed. It is the user's
++ * responsibility to ensure that the underlying 'lfq' is not released until any
++ * enqueues to this FQ object have completed. The only field the user needs to
++ * fill in is fq->cb.ern, as that enqueue rejection handler is the callback that
++ * could conceivably be called on this FQ object. This API can be called
++ * multiple times to create multiple FQ objects referring to the same logical
++ * FQID, and any enqueue rejections will respect the callback of the object that
++ * issued the enqueue (and will identify the object via the parameter passed to
++ * the callback too). There is no 'flags' parameter to this API as there is for
++ * qman_create_fq() - the created FQ object behaves as though qman_create_fq()
++ * had been called with the single flag QMAN_FQ_FLAG_NO_MODIFY.
++ *
++ * Returns 0 for success.
++ */
++int qman_ceetm_create_fq(struct qm_ceetm_lfq *lfq, struct qman_fq *fq);
++
++      /* -------------------------------- */
++      /* CEETM :: class congestion groups */
++      /* -------------------------------- */
++
++/**
++ * qman_ceetm_ccg_claim - Claims an unused CCG.
++ * @ccg: the returned CCG object, if successful.
++ * @channel: the given class queue channel
++ * @cscn: the callback function of this CCG.
++ * @cb_ctx: the corresponding context to be used used if state change
++ * notifications are later enabled for this CCG.
++ *
++ * The congestion group is local to the given class queue channel, so only
++ * class queues within the channel can be associated with that congestion group.
++ * The association of class queues to congestion groups occurs  when the class
++ * queues are claimed, see qman_ceetm_cq_claim() and related functions.
++ * Congestion groups are in a "zero" state when initially claimed, and they are
++ * returned to that state when released.
++ *
++ * Return zero for success, or -EINVAL if no CCG in the channel is available.
++ */
++int qman_ceetm_ccg_claim(struct qm_ceetm_ccg **ccg,
++                       struct qm_ceetm_channel *channel,
++                       unsigned int idx,
++                       void (*cscn)(struct qm_ceetm_ccg *,
++                                     void *cb_ctx,
++                                     int congested),
++                       void *cb_ctx);
++
++/**
++ * qman_ceetm_ccg_release - Releases a previously claimed CCG.
++ * @ccg: the given ccg.
++ *
++ * Returns zero for success, or -EBUSY if the given ccg's dependent objects
++ * (class queues that are associated with the CCG) have not been released.
++ */
++int qman_ceetm_ccg_release(struct qm_ceetm_ccg *ccg);
++
++/* This struct is used to specify attributes for a CCG. The 'we_mask' field
++ * controls which CCG attributes are to be updated, and the remainder specify
++ * the values for those attributes. A CCG counts either frames or the bytes
++ * within those frames, but not both ('mode'). A CCG can optionally cause
++ * enqueues to be rejected, due to tail-drop or WRED, or both (they are
++ * independent options, 'td_en' and 'wr_en_g,wr_en_y,wr_en_r'). Tail-drop can be
++ * level-triggered due to a single threshold ('td_thres') or edge-triggered due
++ * to a "congestion state", but not both ('td_mode'). Congestion state has
++ * distinct entry and exit thresholds ('cs_thres_in' and 'cs_thres_out'), and
++ * notifications can be sent to software the CCG goes in to and out of this
++ * congested state ('cscn_en'). */
++struct qm_ceetm_ccg_params {
++      /* Boolean fields together in a single bitfield struct */
++      struct {
++              /* Whether to count bytes or frames. 1==frames */
++              u8 mode:1;
++              /* En/disable tail-drop. 1==enable */
++              u8 td_en:1;
++              /* Tail-drop on congestion-state or threshold. 1=threshold */
++              u8 td_mode:1;
++              /* Generate congestion state change notifications. 1==enable */
++              u8 cscn_en:1;
++              /* Enable WRED rejections (per colour). 1==enable */
++              u8 wr_en_g:1;
++              u8 wr_en_y:1;
++              u8 wr_en_r:1;
++      } __packed;
++      /* Tail-drop threshold. See qm_cgr_thres_[gs]et64(). */
++      struct qm_cgr_cs_thres td_thres;
++      /* Congestion state thresholds, for entry and exit. */
++      struct qm_cgr_cs_thres cs_thres_in;
++      struct qm_cgr_cs_thres cs_thres_out;
++      /* Overhead accounting length. Per-packet "tax", from -128 to +127 */
++      signed char oal;
++      /* Congestion state change notification for DCP portal, virtual CCGID*/
++      /* WRED parameters. */
++      struct qm_cgr_wr_parm wr_parm_g;
++      struct qm_cgr_wr_parm wr_parm_y;
++      struct qm_cgr_wr_parm wr_parm_r;
++};
++/* Bits used in 'we_mask' to qman_ceetm_ccg_set(), controls which attributes of
++ * the CCGR are to be updated. */
++#define QM_CCGR_WE_MODE         0x0001 /* mode (bytes/frames) */
++#define QM_CCGR_WE_CS_THRES_IN  0x0002 /* congestion state entry threshold */
++#define QM_CCGR_WE_TD_EN        0x0004 /* congestion state tail-drop enable */
++#define QM_CCGR_WE_CSCN_TUPD  0x0008 /* CSCN target update */
++#define QM_CCGR_WE_CSCN_EN      0x0010 /* congestion notification enable */
++#define QM_CCGR_WE_WR_EN_R      0x0020 /* WRED enable - red */
++#define QM_CCGR_WE_WR_EN_Y      0x0040 /* WRED enable - yellow */
++#define QM_CCGR_WE_WR_EN_G      0x0080 /* WRED enable - green */
++#define QM_CCGR_WE_WR_PARM_R    0x0100 /* WRED parameters - red */
++#define QM_CCGR_WE_WR_PARM_Y    0x0200 /* WRED parameters - yellow */
++#define QM_CCGR_WE_WR_PARM_G    0x0400 /* WRED parameters - green */
++#define QM_CCGR_WE_OAL          0x0800 /* overhead accounting length */
++#define QM_CCGR_WE_CS_THRES_OUT 0x1000 /* congestion state exit threshold */
++#define QM_CCGR_WE_TD_THRES     0x2000 /* tail-drop threshold */
++#define QM_CCGR_WE_TD_MODE      0x4000 /* tail-drop mode (state/threshold) */
++#define QM_CCGR_WE_CDV                0x8000 /* cdv */
++
++/**
++ * qman_ceetm_ccg_set
++ * qman_ceetm_ccg_get - Configure/query a subset of CCG attributes.
++ * @ccg: the given CCG object.
++ * @we_mask: the write enable mask.
++ * @params: the parameters setting for this ccg
++ *
++ * Return 0 for success, or -EIO if configure ccg command returns error for
++ * "set" function, or -EINVAL if query ccg command returns error for "get"
++ * function.
++ */
++int qman_ceetm_ccg_set(struct qm_ceetm_ccg *ccg,
++                      u16 we_mask,
++                      const struct qm_ceetm_ccg_params *params);
++int qman_ceetm_ccg_get(struct qm_ceetm_ccg *ccg,
++                      struct qm_ceetm_ccg_params *params);
++
++/** qman_ceetm_cscn_swp_set - Add or remove a software portal from the target
++ * mask.
++ * qman_ceetm_cscn_swp_get - Query whether a given software portal index is
++ * in the cscn target mask.
++ * @ccg: the give CCG object.
++ * @swp_idx: the index of the software portal.
++ * @cscn_enabled: 1: Set the swp to be cscn target. 0: remove the swp from
++ * the target mask.
++ * @we_mask: the write enable mask.
++ * @params: the parameters setting for this ccg
++ *
++ * Return 0 for success, or -EINVAL if command in set/get function fails.
++ */
++int qman_ceetm_cscn_swp_set(struct qm_ceetm_ccg *ccg,
++                              u16 swp_idx,
++                              unsigned int cscn_enabled,
++                              u16 we_mask,
++                              const struct qm_ceetm_ccg_params *params);
++int qman_ceetm_cscn_swp_get(struct qm_ceetm_ccg *ccg,
++                              u16 swp_idx,
++                              unsigned int *cscn_enabled);
++
++/** qman_ceetm_cscn_dcp_set - Add or remove a direct connect portal from the\
++ * target mask.
++ * qman_ceetm_cscn_dcp_get - Query whether a given direct connect portal index
++ * is in the cscn target mask.
++ * @ccg: the give CCG object.
++ * @dcp_idx: the index of the direct connect portal.
++ * @vcgid: congestion state change notification for dcp portal, virtual CGID.
++ * @cscn_enabled: 1: Set the dcp to be cscn target. 0: remove the dcp from
++ * the target mask.
++ * @we_mask: the write enable mask.
++ * @params: the parameters setting for this ccg
++ *
++ * Return 0 for success, or -EINVAL if command in set/get function fails.
++  */
++int qman_ceetm_cscn_dcp_set(struct qm_ceetm_ccg *ccg,
++                              u16 dcp_idx,
++                              u8 vcgid,
++                              unsigned int cscn_enabled,
++                              u16 we_mask,
++                              const struct qm_ceetm_ccg_params *params);
++int qman_ceetm_cscn_dcp_get(struct qm_ceetm_ccg *ccg,
++                              u16 dcp_idx,
++                              u8 *vcgid,
++                              unsigned int *cscn_enabled);
++
++/**
++ * qman_ceetm_ccg_get_reject_statistics - Get the statistics provided by
++ * CEETM CCG counters.
++ * @ccg: the given CCG object.
++ * @flags: indicates whether the statistics counter will be cleared after query.
++ * @frame_count: The number of the frames that have been counted since the
++ * counter was cleared last time.
++ * @byte_count: the number of bytes in all frames that have been counted.
++ *
++ * Return zero for success or -EINVAL if query statistics command returns error.
++ *
++ */
++int qman_ceetm_ccg_get_reject_statistics(struct qm_ceetm_ccg *ccg, u32 flags,
++                                      u64 *frame_count, u64 *byte_count);
++
++/**
++ * qman_ceetm_query_lfqmt - Query the logical frame queue mapping table
++ * @lfqid: Logical Frame Queue ID
++ * @lfqmt_query: Results of the query command
++ *
++ * Returns zero for success or -EIO if the query command returns error.
++ *
++ */
++int qman_ceetm_query_lfqmt(int lfqid,
++                         struct qm_mcr_ceetm_lfqmt_query *lfqmt_query);
++
++/**
++ * qman_ceetm_query_write_statistics - Query (and optionally write) statistics
++ * @cid: Target ID (CQID or CCGRID)
++ * @dcp_idx: CEETM portal ID
++ * @command_type: One of the following:
++ *   0 = Query dequeue statistics. CID carries the CQID to be queried.
++ *   1 = Query and clear dequeue statistics. CID carries the CQID to be queried
++ *   2 = Write dequeue statistics. CID carries the CQID to be written.
++ *   3 = Query reject statistics. CID carries the CCGRID to be queried.
++ *   4 = Query and clear reject statistics. CID carries the CCGRID to be queried
++ *   5 = Write reject statistics. CID carries the CCGRID to be written
++ * @frame_count: Frame count value to be written if this is a write command
++ * @byte_count: Bytes count value to be written if this is a write command
++ *
++ * Returns zero for success or -EIO if the query command returns error.
++ */
++int qman_ceetm_query_write_statistics(u16 cid, enum qm_dc_portal dcp_idx,
++                                    u16 command_type, u64 frame_count,
++                                    u64 byte_count);
++
++/**
++ * qman_set_wpm - Set waterfall power management
++ *
++ * @wpm_enable: boolean, 1 = enable wpm, 0 = disable wpm.
++ *
++ * Return 0 for success, return -ENODEV if QMan misc_cfg register is not
++ * accessible.
++ */
++int qman_set_wpm(int wpm_enable);
++
++/**
++ * qman_get_wpm - Query the waterfall power management setting
++ *
++ * @wpm_enable: boolean, 1 = enable wpm, 0 = disable wpm.
++ *
++ * Return 0 for success, return -ENODEV if QMan misc_cfg register is not
++ * accessible.
++ */
++int qman_get_wpm(int *wpm_enable);
++
++/* The below qman_p_***() variants might be called in a migration situation
++ * (e.g. cpu hotplug). They are used to continue accessing the portal that
++ * execution was affine to prior to migration.
++ * @qman_portal specifies which portal the APIs will use.
++*/
++const struct qman_portal_config *qman_p_get_portal_config(struct qman_portal
++                                                                       *p);
++int qman_p_irqsource_add(struct qman_portal *p, u32 bits);
++int qman_p_irqsource_remove(struct qman_portal *p, u32 bits);
++int qman_p_poll_dqrr(struct qman_portal *p, unsigned int limit);
++u32 qman_p_poll_slow(struct qman_portal *p);
++void qman_p_poll(struct qman_portal *p);
++void qman_p_stop_dequeues(struct qman_portal *p);
++void qman_p_start_dequeues(struct qman_portal *p);
++void qman_p_static_dequeue_add(struct qman_portal *p, u32 pools);
++void qman_p_static_dequeue_del(struct qman_portal *p, u32 pools);
++u32 qman_p_static_dequeue_get(struct qman_portal *p);
++void qman_p_dca(struct qman_portal *p, struct qm_dqrr_entry *dq,
++                                              int park_request);
++int qman_p_volatile_dequeue(struct qman_portal *p, struct qman_fq *fq,
++                              u32 flags __maybe_unused, u32 vdqcr);
++int qman_p_enqueue(struct qman_portal *p, struct qman_fq *fq,
++                                      const struct qm_fd *fd, u32 flags);
++int qman_p_enqueue_orp(struct qman_portal *p, struct qman_fq *fq,
++                              const struct qm_fd *fd, u32 flags,
++                              struct qman_fq *orp, u16 orp_seqnum);
++int qman_p_enqueue_precommit(struct qman_portal *p, struct qman_fq *fq,
++                              const struct qm_fd *fd, u32 flags,
++                              qman_cb_precommit cb, void *cb_arg);
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* FSL_QMAN_H */
+--- /dev/null
++++ b/include/linux/fsl_usdpaa.h
+@@ -0,0 +1,372 @@
++/* Copyright 2011-2012 Freescale Semiconductor, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2.  This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#ifndef FSL_USDPAA_H
++#define FSL_USDPAA_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include <linux/uaccess.h>
++#include <linux/ioctl.h>
++#include <linux/fsl_qman.h> /* For "enum qm_channel" */
++#include <linux/compat.h>
++
++#ifdef CONFIG_FSL_USDPAA
++
++/******************************/
++/* Allocation of resource IDs */
++/******************************/
++
++/* This enum is used to distinguish between the type of underlying object being
++ * manipulated. */
++enum usdpaa_id_type {
++      usdpaa_id_fqid,
++      usdpaa_id_bpid,
++      usdpaa_id_qpool,
++      usdpaa_id_cgrid,
++      usdpaa_id_ceetm0_lfqid,
++      usdpaa_id_ceetm0_channelid,
++      usdpaa_id_ceetm1_lfqid,
++      usdpaa_id_ceetm1_channelid,
++      usdpaa_id_max /* <-- not a valid type, represents the number of types */
++};
++#define USDPAA_IOCTL_MAGIC 'u'
++struct usdpaa_ioctl_id_alloc {
++      uint32_t base; /* Return value, the start of the allocated range */
++      enum usdpaa_id_type id_type; /* what kind of resource(s) to allocate */
++      uint32_t num; /* how many IDs to allocate (and return value) */
++      uint32_t align; /* must be a power of 2, 0 is treated like 1 */
++      int partial; /* whether to allow less than 'num' */
++};
++struct usdpaa_ioctl_id_release {
++      /* Input; */
++      enum usdpaa_id_type id_type;
++      uint32_t base;
++      uint32_t num;
++};
++struct usdpaa_ioctl_id_reserve {
++      enum usdpaa_id_type id_type;
++      uint32_t base;
++      uint32_t num;
++};
++
++
++/* ioctl() commands */
++#define USDPAA_IOCTL_ID_ALLOC \
++      _IOWR(USDPAA_IOCTL_MAGIC, 0x01, struct usdpaa_ioctl_id_alloc)
++#define USDPAA_IOCTL_ID_RELEASE \
++      _IOW(USDPAA_IOCTL_MAGIC, 0x02, struct usdpaa_ioctl_id_release)
++#define USDPAA_IOCTL_ID_RESERVE \
++      _IOW(USDPAA_IOCTL_MAGIC, 0x0A, struct usdpaa_ioctl_id_reserve)
++
++/**********************/
++/* Mapping DMA memory */
++/**********************/
++
++/* Maximum length for a map name, including NULL-terminator */
++#define USDPAA_DMA_NAME_MAX 16
++/* Flags for requesting DMA maps. Maps are private+unnamed or sharable+named.
++ * For a sharable and named map, specify _SHARED (whether creating one or
++ * binding to an existing one). If _SHARED is specified and _CREATE is not, then
++ * the mapping must already exist. If _SHARED and _CREATE are specified and the
++ * mapping doesn't already exist, it will be created. If _SHARED and _CREATE are
++ * specified and the mapping already exists, the mapping will fail unless _LAZY
++ * is specified. When mapping to a pre-existing sharable map, the length must be
++ * an exact match. Lengths must be a power-of-4 multiple of page size.
++ *
++ * Note that this does not actually map the memory to user-space, that is done
++ * by a subsequent mmap() using the page offset returned from this ioctl(). The
++ * ioctl() is what gives the process permission to do this, and a page-offset
++ * with which to do so.
++ */
++#define USDPAA_DMA_FLAG_SHARE    0x01
++#define USDPAA_DMA_FLAG_CREATE   0x02
++#define USDPAA_DMA_FLAG_LAZY     0x04
++#define USDPAA_DMA_FLAG_RDONLY   0x08
++struct usdpaa_ioctl_dma_map {
++      /* Output parameters - virtual and physical addresses */
++      void *ptr;
++      uint64_t phys_addr;
++      /* Input parameter, the length of the region to be created (or if
++       * mapping an existing region, this must match it). Must be a power-of-4
++       * multiple of page size. */
++      uint64_t len;
++      /* Input parameter, the USDPAA_DMA_FLAG_* settings. */
++      uint32_t flags;
++      /* If _FLAG_SHARE is specified, the name of the region to be created (or
++       * of the existing mapping to use). */
++      char name[USDPAA_DMA_NAME_MAX];
++      /* If this ioctl() creates the mapping, this is an input parameter
++       * stating whether the region supports locking. If mapping an existing
++       * region, this is a return value indicating the same thing. */
++      int has_locking;
++      /* In the case of a successful map with _CREATE and _LAZY, this return
++       * value indicates whether we created the mapped region or whether it
++       * already existed. */
++      int did_create;
++};
++
++#ifdef CONFIG_COMPAT
++struct usdpaa_ioctl_dma_map_compat {
++      /* Output parameters - virtual and physical addresses */
++      compat_uptr_t ptr;
++      uint64_t phys_addr;
++      /* Input parameter, the length of the region to be created (or if
++       * mapping an existing region, this must match it). Must be a power-of-4
++       * multiple of page size. */
++      uint64_t len;
++      /* Input parameter, the USDPAA_DMA_FLAG_* settings. */
++      uint32_t flags;
++      /* If _FLAG_SHARE is specified, the name of the region to be created (or
++       * of the existing mapping to use). */
++      char name[USDPAA_DMA_NAME_MAX];
++      /* If this ioctl() creates the mapping, this is an input parameter
++       * stating whether the region supports locking. If mapping an existing
++       * region, this is a return value indicating the same thing. */
++      int has_locking;
++      /* In the case of a successful map with _CREATE and _LAZY, this return
++       * value indicates whether we created the mapped region or whether it
++       * already existed. */
++      int did_create;
++};
++
++#define USDPAA_IOCTL_DMA_MAP_COMPAT \
++      _IOWR(USDPAA_IOCTL_MAGIC, 0x03, struct usdpaa_ioctl_dma_map_compat)
++#endif
++
++
++#define USDPAA_IOCTL_DMA_MAP \
++      _IOWR(USDPAA_IOCTL_MAGIC, 0x03, struct usdpaa_ioctl_dma_map)
++/* munmap() does not remove the DMA map, just the user-space mapping to it.
++ * This ioctl will do both (though you can munmap() before calling the ioctl
++ * too). */
++#define USDPAA_IOCTL_DMA_UNMAP \
++      _IOW(USDPAA_IOCTL_MAGIC, 0x04, unsigned char)
++/* We implement a cross-process locking scheme per DMA map. Call this ioctl()
++ * with a mmap()'d address, and the process will (interruptible) sleep if the
++ * lock is already held by another process. Process destruction will
++ * automatically clean up any held locks. */
++#define USDPAA_IOCTL_DMA_LOCK \
++      _IOW(USDPAA_IOCTL_MAGIC, 0x05, unsigned char)
++#define USDPAA_IOCTL_DMA_UNLOCK \
++      _IOW(USDPAA_IOCTL_MAGIC, 0x06, unsigned char)
++
++/***************************************/
++/* Mapping and using QMan/BMan portals */
++/***************************************/
++enum usdpaa_portal_type {
++       usdpaa_portal_qman,
++       usdpaa_portal_bman,
++};
++
++#define QBMAN_ANY_PORTAL_IDX 0xffffffff
++
++struct usdpaa_ioctl_portal_map {
++      /* Input parameter, is a qman or bman portal required. */
++
++      enum usdpaa_portal_type type;
++      /* Specifes a specific portal index to map or QBMAN_ANY_PORTAL_IDX
++         for don't care.  The portal index will be populated by the
++         driver when the ioctl() successfully completes */
++      uint32_t index;
++
++      /* Return value if the map succeeds, this gives the mapped
++       * cache-inhibited (cinh) and cache-enabled (cena) addresses. */
++      struct usdpaa_portal_map {
++              void *cinh;
++              void *cena;
++      } addr;
++      /* Qman-specific return values */
++      uint16_t channel;
++      uint32_t pools;
++};
++
++#ifdef CONFIG_COMPAT
++struct compat_usdpaa_ioctl_portal_map {
++      /* Input parameter, is a qman or bman portal required. */
++      enum usdpaa_portal_type type;
++      /* Specifes a specific portal index to map or QBMAN_ANY_PORTAL_IDX
++         for don't care.  The portal index will be populated by the
++         driver when the ioctl() successfully completes */
++      uint32_t index;
++      /* Return value if the map succeeds, this gives the mapped
++       * cache-inhibited (cinh) and cache-enabled (cena) addresses. */
++      struct usdpaa_portal_map_compat {
++              compat_uptr_t cinh;
++              compat_uptr_t cena;
++      } addr;
++      /* Qman-specific return values */
++      uint16_t channel;
++      uint32_t pools;
++};
++#define USDPAA_IOCTL_PORTAL_MAP_COMPAT \
++      _IOWR(USDPAA_IOCTL_MAGIC, 0x07, struct compat_usdpaa_ioctl_portal_map)
++#define USDPAA_IOCTL_PORTAL_UNMAP_COMPAT \
++      _IOW(USDPAA_IOCTL_MAGIC, 0x08, struct usdpaa_portal_map_compat)
++#endif
++
++#define USDPAA_IOCTL_PORTAL_MAP \
++      _IOWR(USDPAA_IOCTL_MAGIC, 0x07, struct usdpaa_ioctl_portal_map)
++#define USDPAA_IOCTL_PORTAL_UNMAP \
++      _IOW(USDPAA_IOCTL_MAGIC, 0x08, struct usdpaa_portal_map)
++
++struct usdpaa_ioctl_irq_map {
++      enum usdpaa_portal_type type; /* Type of portal to map */
++      int fd; /* File descriptor that contains the portal */
++      void *portal_cinh; /* Cache inhibited area to identify the portal */
++};
++
++#define USDPAA_IOCTL_PORTAL_IRQ_MAP \
++      _IOW(USDPAA_IOCTL_MAGIC, 0x09, struct usdpaa_ioctl_irq_map)
++
++#ifdef CONFIG_COMPAT
++
++struct compat_ioctl_irq_map {
++      enum usdpaa_portal_type type; /* Type of portal to map */
++      compat_int_t fd; /* File descriptor that contains the portal */
++      compat_uptr_t portal_cinh; /* Used identify the portal */};
++
++#define USDPAA_IOCTL_PORTAL_IRQ_MAP_COMPAT \
++      _IOW(USDPAA_IOCTL_MAGIC, 0x09, struct compat_ioctl_irq_map)
++#endif
++
++/* ioctl to query the amount of DMA memory used in the system */
++struct usdpaa_ioctl_dma_used {
++      uint64_t free_bytes;
++      uint64_t total_bytes;
++};
++#define USDPAA_IOCTL_DMA_USED \
++      _IOR(USDPAA_IOCTL_MAGIC, 0x0B, struct usdpaa_ioctl_dma_used)
++
++/* ioctl to allocate a raw portal */
++struct usdpaa_ioctl_raw_portal {
++      /* inputs */
++      enum usdpaa_portal_type type; /* Type of portal to allocate */
++
++       /* set to non zero to turn on stashing */
++      uint8_t enable_stash;
++      /* Stashing attributes for the portal */
++      uint32_t cpu;
++      uint32_t cache;
++      uint32_t window;
++
++      /* Specifies the stash request queue this portal should use */
++      uint8_t sdest;
++
++      /* Specifes a specific portal index to map or QBMAN_ANY_PORTAL_IDX
++       * for don't care.  The portal index will be populated by the
++       * driver when the ioctl() successfully completes */
++      uint32_t index;
++
++      /* outputs */
++      uint64_t cinh;
++      uint64_t cena;
++};
++
++#define USDPAA_IOCTL_ALLOC_RAW_PORTAL \
++      _IOWR(USDPAA_IOCTL_MAGIC, 0x0C, struct usdpaa_ioctl_raw_portal)
++
++#define USDPAA_IOCTL_FREE_RAW_PORTAL \
++      _IOR(USDPAA_IOCTL_MAGIC, 0x0D, struct usdpaa_ioctl_raw_portal)
++
++#ifdef CONFIG_COMPAT
++
++struct compat_ioctl_raw_portal {
++      /* inputs */
++      enum usdpaa_portal_type type; /* Type of portal to allocate */
++
++       /* set to non zero to turn on stashing */
++      uint8_t enable_stash;
++      /* Stashing attributes for the portal */
++      uint32_t cpu;
++      uint32_t cache;
++      uint32_t window;
++      /* Specifies the stash request queue this portal should use */
++      uint8_t sdest;
++
++      /* Specifes a specific portal index to map or QBMAN_ANY_PORTAL_IDX
++       * for don't care.  The portal index will be populated by the
++       * driver when the ioctl() successfully completes */
++      uint32_t index;
++
++      /* outputs */
++      uint64_t cinh;
++      uint64_t cena;
++};
++
++#define USDPAA_IOCTL_ALLOC_RAW_PORTAL_COMPAT \
++      _IOWR(USDPAA_IOCTL_MAGIC, 0x0C, struct compat_ioctl_raw_portal)
++
++#define USDPAA_IOCTL_FREE_RAW_PORTAL_COMPAT \
++      _IOR(USDPAA_IOCTL_MAGIC, 0x0D, struct compat_ioctl_raw_portal)
++
++#endif
++
++#ifdef __KERNEL__
++
++/* Early-boot hook */
++int __init fsl_usdpaa_init_early(void);
++
++/* Fault-handling in arch/powerpc/mm/mem.c gives USDPAA an opportunity to detect
++ * faults within its ranges via this hook. */
++int usdpaa_test_fault(unsigned long pfn, u64 *phys_addr, u64 *size);
++
++#endif /* __KERNEL__ */
++
++#endif /* CONFIG_FSL_USDPAA */
++
++#ifdef __KERNEL__
++/* This interface is needed in a few places and though it's not specific to
++ * USDPAA as such, creating a new header for it doesn't make any sense. The
++ * qbman kernel driver implements this interface and uses it as the backend for
++ * both the FQID and BPID allocators. The fsl_usdpaa driver also uses this
++ * interface for tracking per-process allocations handed out to user-space. */
++struct dpa_alloc {
++      struct list_head free;
++      spinlock_t lock;
++      struct list_head used;
++};
++#define DECLARE_DPA_ALLOC(name) \
++      struct dpa_alloc name = { \
++              .free = { \
++                      .prev = &name.free, \
++                      .next = &name.free \
++              }, \
++              .lock = __SPIN_LOCK_UNLOCKED(name.lock), \
++              .used = { \
++                       .prev = &name.used, \
++                       .next = &name.used \
++               } \
++      }
++static inline void dpa_alloc_init(struct dpa_alloc *alloc)
++{
++      INIT_LIST_HEAD(&alloc->free);
++      INIT_LIST_HEAD(&alloc->used);
++      spin_lock_init(&alloc->lock);
++}
++int dpa_alloc_new(struct dpa_alloc *alloc, u32 *result, u32 count, u32 align,
++                int partial);
++void dpa_alloc_free(struct dpa_alloc *alloc, u32 base_id, u32 count);
++void dpa_alloc_seed(struct dpa_alloc *alloc, u32 fqid, u32 count);
++
++/* Like 'new' but specifies the desired range, returns -ENOMEM if the entire
++ * desired range is not available, or 0 for success. */
++int dpa_alloc_reserve(struct dpa_alloc *alloc, u32 base_id, u32 count);
++/* Pops and returns contiguous ranges from the allocator. Returns -ENOMEM when
++ * 'alloc' is empty. */
++int dpa_alloc_pop(struct dpa_alloc *alloc, u32 *result, u32 *count);
++/* Returns 1 if the specified id is alloced, 0 otherwise */
++int dpa_alloc_check(struct dpa_alloc *list, u32 id);
++#endif /* __KERNEL__ */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* FSL_USDPAA_H */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0008-fmd-SDK-DPAA-1.x-FMan-driver.patch b/target/linux/layerscape/patches-5.4/701-net-0008-fmd-SDK-DPAA-1.x-FMan-driver.patch
new file mode 100644 (file)
index 0000000..6401ba1
--- /dev/null
@@ -0,0 +1,116456 @@
+From 2701a01f8da8321d3fb8b2e99240fbc5c093a27b Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Wed, 10 May 2017 16:36:36 +0300
+Subject: [PATCH] fmd: SDK DPAA 1.x FMan driver
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_fman/Kconfig    |  153 +
+ drivers/net/ethernet/freescale/sdk_fman/Makefile   |   11 +
+ .../freescale/sdk_fman/Peripherals/FM/HC/Makefile  |   15 +
+ .../freescale/sdk_fman/Peripherals/FM/HC/hc.c      | 1232 ++++
+ .../freescale/sdk_fman/Peripherals/FM/MAC/Makefile |   28 +
+ .../freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c  | 1464 ++++
+ .../freescale/sdk_fman/Peripherals/FM/MAC/dtsec.h  |  228 +
+ .../sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.c    |   97 +
+ .../sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.h    |   42 +
+ .../freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c |  658 ++
+ .../freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h |  225 +
+ .../sdk_fman/Peripherals/FM/MAC/fman_crc32.c       |  119 +
+ .../sdk_fman/Peripherals/FM/MAC/fman_crc32.h       |   43 +
+ .../sdk_fman/Peripherals/FM/MAC/fman_dtsec.c       |  845 +++
+ .../Peripherals/FM/MAC/fman_dtsec_mii_acc.c        |  163 +
+ .../sdk_fman/Peripherals/FM/MAC/fman_memac.c       |  511 ++
+ .../Peripherals/FM/MAC/fman_memac_mii_acc.c        |  213 +
+ .../sdk_fman/Peripherals/FM/MAC/fman_tgec.c        |  367 +
+ .../freescale/sdk_fman/Peripherals/FM/MAC/memac.c  | 1096 +++
+ .../freescale/sdk_fman/Peripherals/FM/MAC/memac.h  |  110 +
+ .../sdk_fman/Peripherals/FM/MAC/memac_mii_acc.c    |   78 +
+ .../sdk_fman/Peripherals/FM/MAC/memac_mii_acc.h    |   73 +
+ .../freescale/sdk_fman/Peripherals/FM/MAC/tgec.c   |  975 +++
+ .../freescale/sdk_fman/Peripherals/FM/MAC/tgec.h   |  151 +
+ .../sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.c     |  139 +
+ .../sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.h     |   80 +
+ .../sdk_fman/Peripherals/FM/MACSEC/Makefile        |   15 +
+ .../sdk_fman/Peripherals/FM/MACSEC/fm_macsec.c     |  237 +
+ .../sdk_fman/Peripherals/FM/MACSEC/fm_macsec.h     |  203 +
+ .../Peripherals/FM/MACSEC/fm_macsec_guest.c        |   59 +
+ .../Peripherals/FM/MACSEC/fm_macsec_master.c       | 1031 +++
+ .../Peripherals/FM/MACSEC/fm_macsec_master.h       |  479 ++
+ .../Peripherals/FM/MACSEC/fm_macsec_secy.c         |  883 +++
+ .../Peripherals/FM/MACSEC/fm_macsec_secy.h         |  144 +
+ .../freescale/sdk_fman/Peripherals/FM/Makefile     |   23 +
+ .../freescale/sdk_fman/Peripherals/FM/Pcd/Makefile |   26 +
+ .../freescale/sdk_fman/Peripherals/FM/Pcd/crc64.h  |  360 +
+ .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c  | 7582 ++++++++++++++++++++
+ .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.h  |  399 +
+ .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c  | 3242 +++++++++
+ .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.h  |  206 +
+ .../sdk_fman/Peripherals/FM/Pcd/fm_manip.c         | 5571 ++++++++++++++
+ .../sdk_fman/Peripherals/FM/Pcd/fm_manip.h         |  555 ++
+ .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.c | 2095 ++++++
+ .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.h |  543 ++
+ .../sdk_fman/Peripherals/FM/Pcd/fm_pcd_ipc.h       |  280 +
+ .../sdk_fman/Peripherals/FM/Pcd/fm_plcr.c          | 1847 +++++
+ .../sdk_fman/Peripherals/FM/Pcd/fm_plcr.h          |  165 +
+ .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.c |  423 ++
+ .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.h |  316 +
+ .../sdk_fman/Peripherals/FM/Pcd/fm_replic.c        |  984 +++
+ .../sdk_fman/Peripherals/FM/Pcd/fm_replic.h        |  101 +
+ .../sdk_fman/Peripherals/FM/Pcd/fman_kg.c          |  888 +++
+ .../sdk_fman/Peripherals/FM/Pcd/fman_prs.c         |  129 +
+ .../sdk_fman/Peripherals/FM/Port/Makefile          |   15 +
+ .../sdk_fman/Peripherals/FM/Port/fm_port.c         | 6436 +++++++++++++++++
+ .../sdk_fman/Peripherals/FM/Port/fm_port.h         |  999 +++
+ .../sdk_fman/Peripherals/FM/Port/fm_port_dsar.h    |  494 ++
+ .../sdk_fman/Peripherals/FM/Port/fm_port_im.c      |  753 ++
+ .../sdk_fman/Peripherals/FM/Port/fman_port.c       | 1568 ++++
+ .../freescale/sdk_fman/Peripherals/FM/Rtc/Makefile |   15 +
+ .../freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.c |  692 ++
+ .../freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.h |   96 +
+ .../sdk_fman/Peripherals/FM/Rtc/fman_rtc.c         |  334 +
+ .../freescale/sdk_fman/Peripherals/FM/SP/Makefile  |   15 +
+ .../freescale/sdk_fman/Peripherals/FM/SP/fm_sp.c   |  757 ++
+ .../freescale/sdk_fman/Peripherals/FM/SP/fm_sp.h   |   85 +
+ .../freescale/sdk_fman/Peripherals/FM/SP/fman_sp.c |  197 +
+ .../freescale/sdk_fman/Peripherals/FM/fm.c         | 5216 ++++++++++++++
+ .../freescale/sdk_fman/Peripherals/FM/fm.h         |  648 ++
+ .../freescale/sdk_fman/Peripherals/FM/fm_ipc.h     |  465 ++
+ .../freescale/sdk_fman/Peripherals/FM/fm_muram.c   |  174 +
+ .../freescale/sdk_fman/Peripherals/FM/fman.c       | 1398 ++++
+ .../sdk_fman/Peripherals/FM/inc/fm_common.h        | 1214 ++++
+ .../freescale/sdk_fman/Peripherals/FM/inc/fm_hc.h  |   93 +
+ .../sdk_fman/Peripherals/FM/inc/fm_sp_common.h     |  117 +
+ .../net/ethernet/freescale/sdk_fman/etc/Makefile   |   12 +
+ .../net/ethernet/freescale/sdk_fman/etc/error.c    |   95 +
+ drivers/net/ethernet/freescale/sdk_fman/etc/list.c |   71 +
+ .../net/ethernet/freescale/sdk_fman/etc/memcpy.c   |  620 ++
+ drivers/net/ethernet/freescale/sdk_fman/etc/mm.c   | 1155 +++
+ drivers/net/ethernet/freescale/sdk_fman/etc/mm.h   |  105 +
+ .../net/ethernet/freescale/sdk_fman/etc/sprint.c   |   81 +
+ .../ethernet/freescale/sdk_fman/fmanv3h_dflags.h   |   57 +
+ .../ethernet/freescale/sdk_fman/fmanv3l_dflags.h   |   56 +
+ .../sdk_fman/inc/Peripherals/crc_mac_addr_ext.h    |  364 +
+ .../freescale/sdk_fman/inc/Peripherals/dpaa_ext.h  |  210 +
+ .../freescale/sdk_fman/inc/Peripherals/fm_ext.h    | 1731 +++++
+ .../sdk_fman/inc/Peripherals/fm_mac_ext.h          |  859 +++
+ .../sdk_fman/inc/Peripherals/fm_macsec_ext.h       | 1271 ++++
+ .../sdk_fman/inc/Peripherals/fm_muram_ext.h        |  170 +
+ .../sdk_fman/inc/Peripherals/fm_pcd_ext.h          | 3974 ++++++++++
+ .../sdk_fman/inc/Peripherals/fm_port_ext.h         | 2608 +++++++
+ .../sdk_fman/inc/Peripherals/fm_rtc_ext.h          |  619 ++
+ .../sdk_fman/inc/Peripherals/fm_vsp_ext.h          |  411 ++
+ .../sdk_fman/inc/Peripherals/mii_acc_ext.h         |   76 +
+ .../net/ethernet/freescale/sdk_fman/inc/core_ext.h |   90 +
+ .../freescale/sdk_fman/inc/cores/arm_ext.h         |   55 +
+ .../freescale/sdk_fman/inc/cores/e500v2_ext.h      |  476 ++
+ .../freescale/sdk_fman/inc/cores/ppc_ext.h         |  141 +
+ .../ethernet/freescale/sdk_fman/inc/ddr_std_ext.h  |   77 +
+ .../ethernet/freescale/sdk_fman/inc/debug_ext.h    |  233 +
+ .../ethernet/freescale/sdk_fman/inc/endian_ext.h   |  447 ++
+ .../net/ethernet/freescale/sdk_fman/inc/enet_ext.h |  205 +
+ .../ethernet/freescale/sdk_fman/inc/error_ext.h    |  529 ++
+ .../ethernet/freescale/sdk_fman/inc/etc/list_ext.h |  358 +
+ .../ethernet/freescale/sdk_fman/inc/etc/mem_ext.h  |  318 +
+ .../freescale/sdk_fman/inc/etc/memcpy_ext.h        |  208 +
+ .../ethernet/freescale/sdk_fman/inc/etc/mm_ext.h   |  310 +
+ .../freescale/sdk_fman/inc/etc/sprint_ext.h        |  118 +
+ .../sdk_fman/inc/flib/common/arch/ppc_access.h     |   37 +
+ .../freescale/sdk_fman/inc/flib/common/general.h   |   52 +
+ .../freescale/sdk_fman/inc/flib/fman_common.h      |   78 +
+ .../freescale/sdk_fman/inc/flib/fsl_enet.h         |  273 +
+ .../freescale/sdk_fman/inc/flib/fsl_fman.h         |  825 +++
+ .../freescale/sdk_fman/inc/flib/fsl_fman_dtsec.h   | 1096 +++
+ .../sdk_fman/inc/flib/fsl_fman_dtsec_mii_acc.h     |  107 +
+ .../freescale/sdk_fman/inc/flib/fsl_fman_kg.h      |  514 ++
+ .../freescale/sdk_fman/inc/flib/fsl_fman_memac.h   |  427 ++
+ .../sdk_fman/inc/flib/fsl_fman_memac_mii_acc.h     |   78 +
+ .../freescale/sdk_fman/inc/flib/fsl_fman_port.h    |  593 ++
+ .../freescale/sdk_fman/inc/flib/fsl_fman_prs.h     |  102 +
+ .../freescale/sdk_fman/inc/flib/fsl_fman_rtc.h     |  449 ++
+ .../freescale/sdk_fman/inc/flib/fsl_fman_sp.h      |  138 +
+ .../freescale/sdk_fman/inc/flib/fsl_fman_tgec.h    |  479 ++
+ .../integrations/FMANV3H/dpaa_integration_ext.h    |  291 +
+ .../sdk_fman/inc/integrations/FMANV3H/part_ext.h   |   71 +
+ .../integrations/FMANV3H/part_integration_ext.h    |  304 +
+ .../integrations/FMANV3L/dpaa_integration_ext.h    |  293 +
+ .../sdk_fman/inc/integrations/FMANV3L/part_ext.h   |   59 +
+ .../integrations/FMANV3L/part_integration_ext.h    |  304 +
+ .../inc/integrations/LS1043/dpaa_integration_ext.h |  291 +
+ .../sdk_fman/inc/integrations/LS1043/part_ext.h    |   64 +
+ .../inc/integrations/LS1043/part_integration_ext.h |  185 +
+ .../inc/integrations/P1023/dpaa_integration_ext.h  |  213 +
+ .../sdk_fman/inc/integrations/P1023/part_ext.h     |   82 +
+ .../inc/integrations/P1023/part_integration_ext.h  |  635 ++
+ .../P3040_P4080_P5020/dpaa_integration_ext.h       |  276 +
+ .../inc/integrations/P3040_P4080_P5020/part_ext.h  |   83 +
+ .../P3040_P4080_P5020/part_integration_ext.h       |  336 +
+ .../net/ethernet/freescale/sdk_fman/inc/math_ext.h |  100 +
+ .../net/ethernet/freescale/sdk_fman/inc/ncsw_ext.h |  435 ++
+ .../net/ethernet/freescale/sdk_fman/inc/net_ext.h  |  430 ++
+ .../net/ethernet/freescale/sdk_fman/inc/std_ext.h  |   48 +
+ .../ethernet/freescale/sdk_fman/inc/stdarg_ext.h   |   49 +
+ .../ethernet/freescale/sdk_fman/inc/stdlib_ext.h   |  162 +
+ .../ethernet/freescale/sdk_fman/inc/string_ext.h   |   56 +
+ .../ethernet/freescale/sdk_fman/inc/types_ext.h    |   62 +
+ .../ethernet/freescale/sdk_fman/inc/xx_common.h    |   56 +
+ .../net/ethernet/freescale/sdk_fman/inc/xx_ext.h   |  791 ++
+ .../ethernet/freescale/sdk_fman/ls1043_dflags.h    |   56 +
+ .../net/ethernet/freescale/sdk_fman/ncsw_config.mk |   53 +
+ .../net/ethernet/freescale/sdk_fman/p1023_dflags.h |   65 +
+ .../freescale/sdk_fman/p3040_4080_5020_dflags.h    |   62 +
+ .../net/ethernet/freescale/sdk_fman/src/Makefile   |   11 +
+ .../freescale/sdk_fman/src/inc/system/sys_ext.h    |  118 +
+ .../freescale/sdk_fman/src/inc/system/sys_io_ext.h |   46 +
+ .../freescale/sdk_fman/src/inc/types_linux.h       |  208 +
+ .../sdk_fman/src/inc/wrapper/fsl_fman_test.h       |   84 +
+ .../sdk_fman/src/inc/wrapper/lnxwrp_exp_sym.h      |  128 +
+ .../sdk_fman/src/inc/wrapper/lnxwrp_fm_ext.h       |  163 +
+ .../sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h     |  921 +++
+ .../ethernet/freescale/sdk_fman/src/inc/xx/xx.h    |   50 +
+ .../freescale/sdk_fman/src/system/Makefile         |   10 +
+ .../freescale/sdk_fman/src/system/sys_io.c         |  171 +
+ .../freescale/sdk_fman/src/wrapper/Makefile        |   19 +
+ .../freescale/sdk_fman/src/wrapper/fman_test.c     | 1665 +++++
+ .../freescale/sdk_fman/src/wrapper/lnxwrp_fm.c     | 2908 ++++++++
+ .../freescale/sdk_fman/src/wrapper/lnxwrp_fm.h     |  294 +
+ .../sdk_fman/src/wrapper/lnxwrp_fm_port.c          | 1480 ++++
+ .../sdk_fman/src/wrapper/lnxwrp_ioctls_fm.c        | 4813 +++++++++++++
+ .../sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c | 1297 ++++
+ .../sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.h |  755 ++
+ .../sdk_fman/src/wrapper/lnxwrp_resources.h        |  121 +
+ .../sdk_fman/src/wrapper/lnxwrp_resources_ut.c     |  191 +
+ .../sdk_fman/src/wrapper/lnxwrp_resources_ut.h     |  144 +
+ .../sdk_fman/src/wrapper/lnxwrp_resources_ut.make  |   28 +
+ .../freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.c  |   60 +
+ .../freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.h  |   60 +
+ .../sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c         | 1855 +++++
+ .../sdk_fman/src/wrapper/lnxwrp_sysfs_fm.h         |  136 +
+ .../sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.c    | 1268 ++++
+ .../sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.h    |   56 +
+ .../ethernet/freescale/sdk_fman/src/xx/Makefile    |   18 +
+ .../freescale/sdk_fman/src/xx/module_strings.c     |   46 +
+ .../freescale/sdk_fman/src/xx/xx_arm_linux.c       |  905 +++
+ .../ethernet/freescale/sdk_fman/src/xx/xx_linux.c  |  918 +++
+ include/linux/fsl/svr.h                            |   97 +
+ include/uapi/linux/fmd/Kbuild                      |    5 +
+ include/uapi/linux/fmd/Peripherals/Kbuild          |    4 +
+ include/uapi/linux/fmd/Peripherals/fm_ioctls.h     |  628 ++
+ include/uapi/linux/fmd/Peripherals/fm_pcd_ioctls.h | 3084 ++++++++
+ .../uapi/linux/fmd/Peripherals/fm_port_ioctls.h    |  948 +++
+ .../uapi/linux/fmd/Peripherals/fm_test_ioctls.h    |  208 +
+ include/uapi/linux/fmd/integrations/Kbuild         |    1 +
+ .../linux/fmd/integrations/integration_ioctls.h    |   56 +
+ include/uapi/linux/fmd/ioctls.h                    |   96 +
+ include/uapi/linux/fmd/net_ioctls.h                |  430 ++
+ 198 files changed, 115457 insertions(+)
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Kconfig
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Makefile
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/Makefile
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/Makefile
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac.c
+ create mode 100755 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_tgec.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/Makefile
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_guest.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Makefile
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/Makefile
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/crc64.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd_ipc.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_prs.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h
+ create mode 100755 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c
+ create mode 100755 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/Makefile
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.h
+ create mode 100755 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fman_rtc.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/Makefile
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.h
+ create mode 100755 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fman_sp.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_ipc.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_muram.c
+ create mode 100755 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_common.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_hc.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_sp_common.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/etc/Makefile
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/etc/error.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/etc/list.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/etc/memcpy.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/etc/mm.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/etc/mm.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/etc/sprint.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/fmanv3h_dflags.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/fmanv3l_dflags.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/crc_mac_addr_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/dpaa_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_mac_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_macsec_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_muram_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_pcd_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_port_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_rtc_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_vsp_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/mii_acc_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/core_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/cores/arm_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/cores/e500v2_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/cores/ppc_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/ddr_std_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/debug_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/endian_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/enet_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/error_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/etc/list_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/etc/mem_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/etc/memcpy_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/etc/mm_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/etc/sprint_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/arch/ppc_access.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/general.h
+ create mode 100755 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fman_common.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_enet.h
+ create mode 100755 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec_mii_acc.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_kg.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac.h
+ create mode 100755 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac_mii_acc.h
+ create mode 100755 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_port.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_prs.h
+ create mode 100755 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_rtc.h
+ create mode 100755 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_sp.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_tgec.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/dpaa_integration_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_integration_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/dpaa_integration_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_integration_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/dpaa_integration_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_integration_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/dpaa_integration_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_integration_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/dpaa_integration_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_integration_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/math_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/ncsw_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/net_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/std_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/stdarg_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/stdlib_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/string_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/types_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/xx_common.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/xx_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/ls1043_dflags.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/p1023_dflags.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/p3040_4080_5020_dflags.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/Makefile
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_io_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/types_linux.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/fsl_fman_test.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_exp_sym.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fm_ext.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/xx/xx.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/system/Makefile
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/system/sys_io.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/Makefile
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/fman_test.c
+ create mode 100755 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.make
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/xx/Makefile
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/xx/module_strings.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_arm_linux.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_linux.c
+ create mode 100644 include/linux/fsl/svr.h
+ create mode 100644 include/uapi/linux/fmd/Kbuild
+ create mode 100644 include/uapi/linux/fmd/Peripherals/Kbuild
+ create mode 100644 include/uapi/linux/fmd/Peripherals/fm_ioctls.h
+ create mode 100644 include/uapi/linux/fmd/Peripherals/fm_pcd_ioctls.h
+ create mode 100644 include/uapi/linux/fmd/Peripherals/fm_port_ioctls.h
+ create mode 100644 include/uapi/linux/fmd/Peripherals/fm_test_ioctls.h
+ create mode 100644 include/uapi/linux/fmd/integrations/Kbuild
+ create mode 100644 include/uapi/linux/fmd/integrations/integration_ioctls.h
+ create mode 100644 include/uapi/linux/fmd/ioctls.h
+ create mode 100644 include/uapi/linux/fmd/net_ioctls.h
+
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Kconfig
+@@ -0,0 +1,153 @@
++menu "Frame Manager support"
++
++menuconfig FSL_SDK_FMAN
++      bool "Freescale Frame Manager (datapath) support - SDK driver"
++      depends on (FSL_SOC || ARM64 || ARM) && FSL_SDK_BMAN && FSL_SDK_QMAN && !FSL_FMAN
++      default y
++      ---help---
++              If unsure, say Y.
++
++if FSL_SDK_FMAN
++
++config FSL_SDK_FMAN_TEST
++      bool "FMan test module"
++      default n
++      select FSL_DPAA_HOOKS
++      ---help---
++              This option compiles test code for FMan.
++
++menu "FMAN Processor support"
++choice
++      depends on FSL_SDK_FMAN
++      prompt "Processor Type"
++
++config FMAN_ARM
++      bool "LS1043"
++      depends on ARM64 || ARM
++      ---help---
++        Choose "LS1043" for the ARM platforms:
++        LS1043
++
++config FMAN_P3040_P4080_P5020
++      bool "P3040 P4080 5020"
++
++config FMAN_P1023
++      bool "P1023"
++
++config FMAN_V3H
++      bool "FmanV3H"
++      ---help---
++        Choose "FmanV3H" for Fman rev3H:
++        B4860, T4240, T4160, etc
++
++config FMAN_V3L
++      bool "FmanV3L"
++      ---help---
++        Choose "FmanV3L" for Fman rev3L:
++        T1040, T1042, T1020, T1022, T1023, T1024, etc
++
++endchoice
++endmenu
++
++config FMAN_MIB_CNT_OVF_IRQ_EN
++      bool "Enable the dTSEC MIB counters overflow interrupt"
++      default n
++      ---help---
++              Enable the dTSEC MIB counters overflow interrupt to get
++              accurate MIB counters values. Enabled it compensates
++              for the counters overflow but reduces performance and
++              triggers error messages in HV setups.
++
++config FSL_FM_MAX_FRAME_SIZE
++      int "Maximum L2 frame size"
++      depends on FSL_SDK_FMAN
++      range 64 9600
++      default "1522"
++      help
++              Configure this in relation to the maximum possible MTU of your
++              network configuration. In particular, one would need to
++              increase this value in order to use jumbo frames.
++              FSL_FM_MAX_FRAME_SIZE must accommodate the Ethernet FCS (4 bytes)
++              and one ETH+VLAN header (18 bytes), to a total of 22 bytes in
++              excess of the desired L3 MTU.
++
++              Note that having too large a FSL_FM_MAX_FRAME_SIZE (much larger
++              than the actual MTU) may lead to buffer exhaustion, especially
++              in the case of badly fragmented datagrams on the Rx path.
++              Conversely, having a FSL_FM_MAX_FRAME_SIZE smaller than the actual
++              MTU will lead to frames being dropped.
++
++              This can be overridden by specifying "fsl_fm_max_frm" in
++              the kernel bootargs:
++               * in Hypervisor-based scenarios, by adding a "chosen" node
++              with the "bootargs" property specifying
++              "fsl_fm_max_frm=<YourValue>";
++               * in non-Hypervisor-based scenarios, via u-boot's env, by
++              modifying the "bootargs" env variable.
++
++config FSL_FM_RX_EXTRA_HEADROOM
++      int "Add extra headroom at beginning of data buffers"
++      depends on FSL_SDK_FMAN
++      range 16 384
++      default "64"
++      help
++              Configure this to tell the Frame Manager to reserve some extra
++              space at the beginning of a data buffer on the receive path,
++              before Internal Context fields are copied. This is in addition
++              to the private data area already reserved for driver internal
++              use. The provided value must be a multiple of 16.
++
++              This setting can be overridden by specifying
++              "fsl_fm_rx_extra_headroom" in the kernel bootargs:
++               * in Hypervisor-based scenarios, by adding a "chosen" node
++              with the "bootargs" property specifying
++              "fsl_fm_rx_extra_headroom=<YourValue>";
++               * in non-Hypervisor-based scenarios, via u-boot's env, by
++              modifying the "bootargs" env variable.
++
++config FMAN_PFC
++      bool "FMan PFC support (EXPERIMENTAL)"
++      depends on ( FMAN_V3H || FMAN_V3L || FMAN_ARM) && FSL_SDK_FMAN
++      default n
++      help
++              This option enables PFC support on FMan v3 ports.
++              Data Center Bridging defines Classes of Service that are
++              flow-controlled using PFC pause frames.
++
++if FMAN_PFC
++config FMAN_PFC_COS_COUNT
++      int "Number of PFC Classes of Service"
++      depends on FMAN_PFC && FSL_SDK_FMAN
++      range 1 4
++      default "3"
++      help
++              The number of Classes of Service controlled by PFC.
++
++config FMAN_PFC_QUANTA_0
++      int "The pause quanta for PFC CoS 0"
++      depends on FMAN_PFC && FSL_SDK_FMAN
++      range 0 65535
++      default "65535"
++
++config FMAN_PFC_QUANTA_1
++      int "The pause quanta for PFC CoS 1"
++      depends on FMAN_PFC && FSL_SDK_FMAN
++      range 0 65535
++      default "65535"
++
++config FMAN_PFC_QUANTA_2
++      int "The pause quanta for PFC CoS 2"
++      depends on FMAN_PFC && FSL_SDK_FMAN
++      range 0 65535
++      default "65535"
++
++config FMAN_PFC_QUANTA_3
++      int "The pause quanta for PFC CoS 3"
++      depends on FMAN_PFC && FSL_SDK_FMAN
++      range 0 65535
++      default "65535"
++endif
++
++endif # FSL_SDK_FMAN
++
++endmenu
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Makefile
+@@ -0,0 +1,11 @@
++#
++# Makefile for the Freescale Ethernet controllers
++#
++ccflags-y           += -DVERSION=\"\"
++#
++#Include netcomm SW specific definitions
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++#
++obj-y         += etc/
++obj-y         += Peripherals/FM/
++obj-y         += src/
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/Makefile
+@@ -0,0 +1,15 @@
++#
++# Makefile for the Freescale Ethernet controllers
++#
++ccflags-y           += -DVERSION=\"\"
++#
++#Include netcomm SW specific definitions
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++
++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
++
++ccflags-y += -I$(NCSW_FM_INC)
++
++obj-y         += fsl-ncsw-Hc.o
++
++fsl-ncsw-Hc-objs      :=   hc.o
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c
+@@ -0,0 +1,1232 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "sprint_ext.h"
++#include "string_ext.h"
++
++#include "fm_common.h"
++#include "fm_hc.h"
++
++
++/**************************************************************************//**
++ @Description       defaults
++*//***************************************************************************/
++#define DEFAULT_dataMemId                                       0
++
++#define HC_HCOR_OPCODE_PLCR_PRFL                                0x0
++#define HC_HCOR_OPCODE_KG_SCM                                   0x1
++#define HC_HCOR_OPCODE_SYNC                                     0x2
++#define HC_HCOR_OPCODE_CC                                       0x3
++#define HC_HCOR_OPCODE_CC_AGE_MASK                              0x4
++#define HC_HCOR_OPCODE_CC_CAPWAP_REASSM_TIMEOUT                 0x5
++#define HC_HCOR_OPCODE_CC_REASSM_TIMEOUT                        0x10
++#define HC_HCOR_OPCODE_CC_IP_FRAG_INITIALIZATION                0x11
++#define HC_HCOR_OPCODE_CC_UPDATE_WITH_AGING                     0x13
++#define HC_HCOR_ACTION_REG_REASSM_TIMEOUT_ACTIVE_SHIFT          24
++#define HC_HCOR_EXTRA_REG_REASSM_TIMEOUT_TSBS_SHIFT             24
++#define HC_HCOR_EXTRA_REG_CC_AGING_ADD                          0x80000000
++#define HC_HCOR_EXTRA_REG_CC_AGING_REMOVE                       0x40000000
++#define HC_HCOR_EXTRA_REG_CC_AGING_CHANGE_MASK                  0xC0000000
++#define HC_HCOR_EXTRA_REG_CC_REMOVE_INDX_SHIFT                  24
++#define HC_HCOR_EXTRA_REG_CC_REMOVE_INDX_MASK                   0x1F000000
++#define HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_SHIFT             16
++#define HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_MASK              0xF
++#define HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_CMD_SHIFT       24
++#define HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_BPID            16
++
++#define HC_HCOR_GBL                         0x20000000
++
++#define HC_HCOR_KG_SCHEME_COUNTER           0x00000400
++
++#if (DPAA_VERSION == 10)
++#define HC_HCOR_KG_SCHEME_REGS_MASK         0xFFFFF800
++#else
++#define HC_HCOR_KG_SCHEME_REGS_MASK         0xFFFFFE00
++#endif /* (DPAA_VERSION == 10) */
++
++#define SIZE_OF_HC_FRAME_PORT_REGS          (sizeof(t_HcFrame)-sizeof(struct fman_kg_scheme_regs)+sizeof(t_FmPcdKgPortRegs))
++#define SIZE_OF_HC_FRAME_SCHEME_REGS        sizeof(t_HcFrame)
++#define SIZE_OF_HC_FRAME_PROFILES_REGS      (sizeof(t_HcFrame)-sizeof(struct fman_kg_scheme_regs)+sizeof(t_FmPcdPlcrProfileRegs))
++#define SIZE_OF_HC_FRAME_PROFILE_CNT        (sizeof(t_HcFrame)-sizeof(t_FmPcdPlcrProfileRegs)+sizeof(uint32_t))
++#define SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC 16
++
++#define HC_CMD_POOL_SIZE                    (INTG_MAX_NUM_OF_CORES)
++
++#define BUILD_FD(len)                     \
++do {                                      \
++    memset(&fmFd, 0, sizeof(t_DpaaFD));   \
++    DPAA_FD_SET_ADDR(&fmFd, p_HcFrame);   \
++    DPAA_FD_SET_OFFSET(&fmFd, 0);         \
++    DPAA_FD_SET_LENGTH(&fmFd, len);       \
++} while (0)
++
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(push,1)
++#endif /* defined(__MWERKS__) && ... */
++
++typedef struct t_FmPcdKgPortRegs {
++    volatile uint32_t                       spReg;
++    volatile uint32_t                       cppReg;
++} t_FmPcdKgPortRegs;
++
++typedef struct t_HcFrame {
++    volatile uint32_t                           opcode;
++    volatile uint32_t                           actionReg;
++    volatile uint32_t                           extraReg;
++    volatile uint32_t                           commandSequence;
++    union {
++        struct fman_kg_scheme_regs              schemeRegs;
++        struct fman_kg_scheme_regs              schemeRegsWithoutCounter;
++        t_FmPcdPlcrProfileRegs                  profileRegs;
++        volatile uint32_t                       singleRegForWrite;    /* for writing SP, CPP, profile counter */
++        t_FmPcdKgPortRegs                       portRegsForRead;
++        volatile uint32_t                       clsPlanEntries[CLS_PLAN_NUM_PER_GRP];
++        t_FmPcdCcCapwapReassmTimeoutParams      ccCapwapReassmTimeout;
++        t_FmPcdCcReassmTimeoutParams            ccReassmTimeout;
++    } hcSpecificData;
++} t_HcFrame;
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(pop)
++#endif /* defined(__MWERKS__) && ... */
++
++
++typedef struct t_FmHc {
++    t_Handle                    h_FmPcd;
++    t_Handle                    h_HcPortDev;
++    t_FmPcdQmEnqueueCallback    *f_QmEnqueue;     /**< A callback for enqueuing frames to the QM */
++    t_Handle                    h_QmArg;          /**< A handle to the QM module */
++    uint8_t                     dataMemId;        /**< Memory partition ID for data buffers */
++
++    uint32_t                    seqNum[HC_CMD_POOL_SIZE];   /* FIFO of seqNum to use when
++                                                               taking buffer */
++    uint32_t                    nextSeqNumLocation;         /* seqNum location in seqNum[] for next buffer */
++    volatile bool               enqueued[HC_CMD_POOL_SIZE]; /* HC is active - frame is enqueued
++                                                               and not confirmed yet */
++    t_HcFrame                   *p_Frm[HC_CMD_POOL_SIZE];
++} t_FmHc;
++
++
++static t_Error FillBufPool(t_FmHc *p_FmHc)
++{
++    uint32_t i;
++
++    ASSERT_COND(p_FmHc);
++
++    for (i = 0; i < HC_CMD_POOL_SIZE; i++)
++    {
++#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004
++        p_FmHc->p_Frm[i] = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + (16 - (sizeof(t_FmHc) % 16))),
++                                                       p_FmHc->dataMemId,
++                                                       16);
++#else
++        p_FmHc->p_Frm[i] = (t_HcFrame *)XX_MallocSmart(sizeof(t_HcFrame),
++                                                       p_FmHc->dataMemId,
++                                                       16);
++#endif /* FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 */
++        if (!p_FmHc->p_Frm[i])
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM HC frames!"));
++    }
++
++    /* Initialize FIFO of seqNum to use during GetBuf */
++    for (i = 0; i < HC_CMD_POOL_SIZE; i++)
++    {
++        p_FmHc->seqNum[i] = i;
++    }
++    p_FmHc->nextSeqNumLocation = 0;
++
++    return E_OK;
++}
++
++static __inline__ t_HcFrame * GetBuf(t_FmHc *p_FmHc, uint32_t *p_SeqNum)
++{
++    uint32_t    intFlags;
++
++    ASSERT_COND(p_FmHc);
++
++    intFlags = FmPcdLock(p_FmHc->h_FmPcd);
++
++    if (p_FmHc->nextSeqNumLocation == HC_CMD_POOL_SIZE)
++    {
++        /* No more buffers */
++        FmPcdUnlock(p_FmHc->h_FmPcd, intFlags);
++        return NULL;
++    }
++
++    *p_SeqNum = p_FmHc->seqNum[p_FmHc->nextSeqNumLocation];
++    p_FmHc->nextSeqNumLocation++;
++
++    FmPcdUnlock(p_FmHc->h_FmPcd, intFlags);
++    return p_FmHc->p_Frm[*p_SeqNum];
++}
++
++static __inline__ void PutBuf(t_FmHc *p_FmHc, t_HcFrame *p_Buf, uint32_t seqNum)
++{
++    uint32_t    intFlags;
++
++    UNUSED(p_Buf);
++
++    intFlags = FmPcdLock(p_FmHc->h_FmPcd);
++    ASSERT_COND(p_FmHc->nextSeqNumLocation);
++    p_FmHc->nextSeqNumLocation--;
++    p_FmHc->seqNum[p_FmHc->nextSeqNumLocation] = seqNum;
++    FmPcdUnlock(p_FmHc->h_FmPcd, intFlags);
++}
++
++static __inline__ t_Error EnQFrm(t_FmHc *p_FmHc, t_DpaaFD *p_FmFd, uint32_t seqNum)
++{
++    t_Error     err = E_OK;
++    uint32_t    intFlags;
++    uint32_t    timeout=100;
++
++    intFlags = FmPcdLock(p_FmHc->h_FmPcd);
++    ASSERT_COND(!p_FmHc->enqueued[seqNum]);
++    p_FmHc->enqueued[seqNum] = TRUE;
++    FmPcdUnlock(p_FmHc->h_FmPcd, intFlags);
++    DBG(TRACE, ("Send Hc, SeqNum %d, buff@0x%x, fd offset 0x%x",
++                seqNum,
++                DPAA_FD_GET_ADDR(p_FmFd),
++                DPAA_FD_GET_OFFSET(p_FmFd)));
++    err = p_FmHc->f_QmEnqueue(p_FmHc->h_QmArg, (void *)p_FmFd);
++    if (err)
++        RETURN_ERROR(MINOR, err, ("HC enqueue failed"));
++
++    while (p_FmHc->enqueued[seqNum] && --timeout)
++        XX_UDelay(100);
++
++    if (!timeout)
++        RETURN_ERROR(MINOR, E_TIMEOUT, ("HC Callback, timeout exceeded"));
++
++    return err;
++}
++
++
++t_Handle FmHcConfigAndInit(t_FmHcParams *p_FmHcParams)
++{
++    t_FmHc          *p_FmHc;
++    t_FmPortParams  fmPortParam;
++    t_Error         err;
++
++    p_FmHc = (t_FmHc *)XX_Malloc(sizeof(t_FmHc));
++    if (!p_FmHc)
++    {
++        REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC obj"));
++        return NULL;
++    }
++    memset(p_FmHc,0,sizeof(t_FmHc));
++
++    p_FmHc->h_FmPcd             = p_FmHcParams->h_FmPcd;
++    p_FmHc->f_QmEnqueue         = p_FmHcParams->params.f_QmEnqueue;
++    p_FmHc->h_QmArg             = p_FmHcParams->params.h_QmArg;
++    p_FmHc->dataMemId           = DEFAULT_dataMemId;
++
++    err = FillBufPool(p_FmHc);
++    if (err != E_OK)
++    {
++        REPORT_ERROR(MAJOR, err, NO_MSG);
++        FmHcFree(p_FmHc);
++        return NULL;
++    }
++
++    if (!FmIsMaster(p_FmHcParams->h_Fm))
++        return (t_Handle)p_FmHc;
++
++    memset(&fmPortParam, 0, sizeof(fmPortParam));
++    fmPortParam.baseAddr    = p_FmHcParams->params.portBaseAddr;
++    fmPortParam.portType    = e_FM_PORT_TYPE_OH_HOST_COMMAND;
++    fmPortParam.portId      = p_FmHcParams->params.portId;
++    fmPortParam.liodnBase   = p_FmHcParams->params.liodnBase;
++    fmPortParam.h_Fm        = p_FmHcParams->h_Fm;
++
++    fmPortParam.specificParams.nonRxParams.errFqid      = p_FmHcParams->params.errFqid;
++    fmPortParam.specificParams.nonRxParams.dfltFqid     = p_FmHcParams->params.confFqid;
++    fmPortParam.specificParams.nonRxParams.qmChannel    = p_FmHcParams->params.qmChannel;
++
++    p_FmHc->h_HcPortDev = FM_PORT_Config(&fmPortParam);
++    if (!p_FmHc->h_HcPortDev)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("FM HC port!"));
++        XX_Free(p_FmHc);
++        return NULL;
++    }
++
++    err = FM_PORT_ConfigMaxFrameLength(p_FmHc->h_HcPortDev,
++                                       (uint16_t)sizeof(t_HcFrame));
++
++    if (err != E_OK)
++    {
++        REPORT_ERROR(MAJOR, err, ("FM HC port init!"));
++        FmHcFree(p_FmHc);
++        return NULL;
++    }
++
++    /* final init */
++    err = FM_PORT_Init(p_FmHc->h_HcPortDev);
++    if (err != E_OK)
++    {
++        REPORT_ERROR(MAJOR, err, ("FM HC port init!"));
++        FmHcFree(p_FmHc);
++        return NULL;
++    }
++
++    err = FM_PORT_Enable(p_FmHc->h_HcPortDev);
++    if (err != E_OK)
++    {
++        REPORT_ERROR(MAJOR, err, ("FM HC port enable!"));
++        FmHcFree(p_FmHc);
++        return NULL;
++    }
++
++    return (t_Handle)p_FmHc;
++}
++
++void FmHcFree(t_Handle h_FmHc)
++{
++    t_FmHc  *p_FmHc = (t_FmHc*)h_FmHc;
++    int     i;
++
++    if (!p_FmHc)
++        return;
++
++    for (i=0; i<HC_CMD_POOL_SIZE; i++)
++        if (p_FmHc->p_Frm[i])
++            XX_FreeSmart(p_FmHc->p_Frm[i]);
++        else
++            break;
++
++    if (p_FmHc->h_HcPortDev)
++        FM_PORT_Free(p_FmHc->h_HcPortDev);
++
++    XX_Free(p_FmHc);
++}
++
++/*****************************************************************************/
++t_Error FmHcSetFramesDataMemory(t_Handle h_FmHc,
++                                uint8_t  memId)
++{
++    t_FmHc  *p_FmHc = (t_FmHc*)h_FmHc;
++    int     i;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmHc, E_INVALID_HANDLE);
++
++    p_FmHc->dataMemId            = memId;
++
++    for (i=0; i<HC_CMD_POOL_SIZE; i++)
++        if (p_FmHc->p_Frm[i])
++            XX_FreeSmart(p_FmHc->p_Frm[i]);
++
++    return FillBufPool(p_FmHc);
++}
++
++void FmHcTxConf(t_Handle h_FmHc, t_DpaaFD *p_Fd)
++{
++    t_FmHc      *p_FmHc = (t_FmHc*)h_FmHc;
++    t_HcFrame   *p_HcFrame;
++    uint32_t    intFlags;
++
++    ASSERT_COND(p_FmHc);
++
++    intFlags = FmPcdLock(p_FmHc->h_FmPcd);
++    p_HcFrame  = (t_HcFrame *)PTR_MOVE(DPAA_FD_GET_ADDR(p_Fd), DPAA_FD_GET_OFFSET(p_Fd));
++
++    DBG(TRACE, ("Hc Conf, SeqNum %d, FD@0x%x, fd offset 0x%x",
++                p_HcFrame->commandSequence, DPAA_FD_GET_ADDR(p_Fd), DPAA_FD_GET_OFFSET(p_Fd)));
++
++    if (!(p_FmHc->enqueued[p_HcFrame->commandSequence]))
++        REPORT_ERROR(MINOR, E_INVALID_FRAME, ("Not an Host-Command frame received!"));
++    else
++        p_FmHc->enqueued[p_HcFrame->commandSequence] = FALSE;
++    FmPcdUnlock(p_FmHc->h_FmPcd, intFlags);
++}
++
++t_Error FmHcPcdKgSetScheme(t_Handle                    h_FmHc,
++                           t_Handle                    h_Scheme,
++                           struct fman_kg_scheme_regs  *p_SchemeRegs,
++                           bool                        updateCounter)
++{
++    t_FmHc                              *p_FmHc = (t_FmHc*)h_FmHc;
++    t_Error                             err = E_OK;
++    t_HcFrame                           *p_HcFrame;
++    t_DpaaFD                            fmFd;
++    uint8_t                             physicalSchemeId;
++    uint32_t                            seqNum;
++
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++
++    physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme);
++
++    memset(p_HcFrame, 0, sizeof(t_HcFrame));
++    p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
++    p_HcFrame->actionReg  = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, updateCounter);
++    p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
++    memcpy(&p_HcFrame->hcSpecificData.schemeRegs, p_SchemeRegs, sizeof(struct fman_kg_scheme_regs));
++    if (!updateCounter)
++    {
++        p_HcFrame->hcSpecificData.schemeRegs.kgse_dv0   = p_SchemeRegs->kgse_dv0;
++        p_HcFrame->hcSpecificData.schemeRegs.kgse_dv1   = p_SchemeRegs->kgse_dv1;
++        p_HcFrame->hcSpecificData.schemeRegs.kgse_ccbs  = p_SchemeRegs->kgse_ccbs;
++        p_HcFrame->hcSpecificData.schemeRegs.kgse_mv    = p_SchemeRegs->kgse_mv;
++    }
++    p_HcFrame->commandSequence = seqNum;
++
++    BUILD_FD(sizeof(t_HcFrame));
++
++    err = EnQFrm(p_FmHc, &fmFd, seqNum);
++
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++
++    if (err != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++t_Error FmHcPcdKgDeleteScheme(t_Handle h_FmHc, t_Handle h_Scheme)
++{
++    t_FmHc      *p_FmHc = (t_FmHc*)h_FmHc;
++    t_Error     err = E_OK;
++    t_HcFrame   *p_HcFrame;
++    t_DpaaFD    fmFd;
++    uint8_t     physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme);
++    uint32_t    seqNum;
++
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++
++    memset(p_HcFrame, 0, sizeof(t_HcFrame));
++    p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
++    p_HcFrame->actionReg  = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE);
++    p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
++    memset(&p_HcFrame->hcSpecificData.schemeRegs, 0, sizeof(struct fman_kg_scheme_regs));
++    p_HcFrame->commandSequence = seqNum;
++
++    BUILD_FD(sizeof(t_HcFrame));
++
++    err = EnQFrm(p_FmHc, &fmFd, seqNum);
++
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++
++    if (err != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++t_Error FmHcPcdKgCcGetSetParams(t_Handle h_FmHc, t_Handle  h_Scheme, uint32_t requiredAction, uint32_t value)
++{
++    t_FmHc      *p_FmHc = (t_FmHc*)h_FmHc;
++    t_Error     err = E_OK;
++    t_HcFrame   *p_HcFrame;
++    t_DpaaFD    fmFd;
++    uint8_t     relativeSchemeId;
++    uint8_t     physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme);
++    uint32_t    tmpReg32 = 0;
++    uint32_t    seqNum;
++
++    /* Scheme is locked by calling routine */
++    /* WARNING - this lock will not be efficient if other HC routine will attempt to change
++     * "kgse_mode" or "kgse_om" without locking scheme !
++     */
++
++    relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId);
++    if ( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES)
++        RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
++
++    if (!FmPcdKgGetRequiredActionFlag(p_FmHc->h_FmPcd, relativeSchemeId) ||
++       !(FmPcdKgGetRequiredAction(p_FmHc->h_FmPcd, relativeSchemeId) & requiredAction))
++    {
++        if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) &&
++            (FmPcdKgGetNextEngine(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_PLCR))
++            {
++                if ((FmPcdKgIsDirectPlcr(p_FmHc->h_FmPcd, relativeSchemeId) == FALSE) ||
++                    (FmPcdKgIsDistrOnPlcrProfile(p_FmHc->h_FmPcd, relativeSchemeId) == TRUE))
++                    RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("In this situation PP can not be with distribution and has to be shared"));
++                err = FmPcdPlcrCcGetSetParams(p_FmHc->h_FmPcd, FmPcdKgGetRelativeProfileId(p_FmHc->h_FmPcd, relativeSchemeId), requiredAction);
++                if (err)
++                    RETURN_ERROR(MAJOR, err, NO_MSG);
++            }
++        else /* From here we deal with KG-Schemes only */
++        {
++            /* Pre change general code */
++            p_HcFrame = GetBuf(p_FmHc, &seqNum);
++            if (!p_HcFrame)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++            memset(p_HcFrame, 0, sizeof(t_HcFrame));
++            p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
++            p_HcFrame->actionReg  = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
++            p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
++            p_HcFrame->commandSequence = seqNum;
++            BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC);
++            if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
++            {
++                PutBuf(p_FmHc, p_HcFrame, seqNum);
++                RETURN_ERROR(MINOR, err, NO_MSG);
++            }
++
++            /* specific change */
++            if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) &&
++                ((FmPcdKgGetNextEngine(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_DONE) &&
++                 (FmPcdKgGetDoneAction(p_FmHc->h_FmPcd, relativeSchemeId) ==  e_FM_PCD_ENQ_FRAME)))
++            {
++                tmpReg32 = p_HcFrame->hcSpecificData.schemeRegs.kgse_mode;
++                ASSERT_COND(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME));
++                p_HcFrame->hcSpecificData.schemeRegs.kgse_mode =  tmpReg32 | NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
++            }
++
++            if ((requiredAction & UPDATE_KG_NIA_CC_WA) &&
++                (FmPcdKgGetNextEngine(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_CC))
++            {
++                tmpReg32 = p_HcFrame->hcSpecificData.schemeRegs.kgse_mode;
++                ASSERT_COND(tmpReg32 & (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC));
++                tmpReg32 &= ~NIA_FM_CTL_AC_CC;
++                p_HcFrame->hcSpecificData.schemeRegs.kgse_mode =  tmpReg32 | NIA_FM_CTL_AC_PRE_CC;
++            }
++
++            if (requiredAction & UPDATE_KG_OPT_MODE)
++                p_HcFrame->hcSpecificData.schemeRegs.kgse_om = value;
++
++            if (requiredAction & UPDATE_KG_NIA)
++            {
++                tmpReg32 = p_HcFrame->hcSpecificData.schemeRegs.kgse_mode;
++                tmpReg32 &= ~(NIA_ENG_MASK | NIA_AC_MASK);
++                tmpReg32 |= value;
++                p_HcFrame->hcSpecificData.schemeRegs.kgse_mode = tmpReg32;
++            }
++
++            /* Post change general code */
++            p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
++            p_HcFrame->actionReg  = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE);
++            p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
++
++            BUILD_FD(sizeof(t_HcFrame));
++            err = EnQFrm(p_FmHc, &fmFd, seqNum);
++
++            PutBuf(p_FmHc, p_HcFrame, seqNum);
++
++            if (err != E_OK)
++                RETURN_ERROR(MINOR, err, NO_MSG);
++        }
++    }
++
++    return E_OK;
++}
++
++uint32_t  FmHcPcdKgGetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme)
++{
++    t_FmHc      *p_FmHc = (t_FmHc*)h_FmHc;
++    t_Error     err;
++    t_HcFrame   *p_HcFrame;
++    t_DpaaFD    fmFd;
++    uint32_t    retVal;
++    uint8_t     relativeSchemeId;
++    uint8_t     physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme);
++    uint32_t    seqNum;
++
++    relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId);
++    if ( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES)
++    {
++        REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
++        return 0;
++    }
++
++    /* first read scheme and check that it is valid */
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++    {
++        REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++        return 0;
++    }
++    memset(p_HcFrame, 0, sizeof(t_HcFrame));
++    p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
++    p_HcFrame->actionReg  = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
++    p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
++    p_HcFrame->commandSequence = seqNum;
++
++    BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC);
++
++    err = EnQFrm(p_FmHc, &fmFd, seqNum);
++    if (err != E_OK)
++    {
++        PutBuf(p_FmHc, p_HcFrame, seqNum);
++        REPORT_ERROR(MINOR, err, NO_MSG);
++        return 0;
++    }
++
++    if (!FmPcdKgHwSchemeIsValid(p_HcFrame->hcSpecificData.schemeRegs.kgse_mode))
++    {
++        PutBuf(p_FmHc, p_HcFrame, seqNum);
++        REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is invalid"));
++        return 0;
++    }
++
++    retVal = p_HcFrame->hcSpecificData.schemeRegs.kgse_spc;
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++
++    return retVal;
++}
++
++t_Error  FmHcPcdKgSetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t value)
++{
++    t_FmHc      *p_FmHc = (t_FmHc*)h_FmHc;
++    t_Error     err = E_OK;
++    t_HcFrame   *p_HcFrame;
++    t_DpaaFD    fmFd;
++    uint8_t     relativeSchemeId, physicalSchemeId;
++    uint32_t    seqNum;
++
++    physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme);
++    relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId);
++    if ( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES)
++        RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
++
++    /* first read scheme and check that it is valid */
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++    memset(p_HcFrame, 0, sizeof(t_HcFrame));
++    p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
++    p_HcFrame->actionReg  = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE);
++    p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_COUNTER;
++    /* write counter */
++    p_HcFrame->hcSpecificData.singleRegForWrite = value;
++    p_HcFrame->commandSequence = seqNum;
++
++    BUILD_FD(sizeof(t_HcFrame));
++
++    err = EnQFrm(p_FmHc, &fmFd, seqNum);
++
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++    return err;
++}
++
++t_Error FmHcPcdKgSetClsPlan(t_Handle h_FmHc, t_FmPcdKgInterModuleClsPlanSet *p_Set)
++{
++    t_FmHc                  *p_FmHc = (t_FmHc*)h_FmHc;
++    t_HcFrame               *p_HcFrame;
++    t_DpaaFD                fmFd;
++    uint8_t                 i, idx;
++    uint32_t                seqNum;
++    t_Error                 err = E_OK;
++
++    ASSERT_COND(p_FmHc);
++
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++
++    for (i = p_Set->baseEntry; i < (p_Set->baseEntry+p_Set->numOfClsPlanEntries); i+=8)
++    {
++        memset(p_HcFrame, 0, sizeof(t_HcFrame));
++        p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
++        p_HcFrame->actionReg  = FmPcdKgBuildWriteClsPlanBlockActionReg((uint8_t)(i / CLS_PLAN_NUM_PER_GRP));
++        p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
++
++        idx = (uint8_t)(i - p_Set->baseEntry);
++        ASSERT_COND(idx < FM_PCD_MAX_NUM_OF_CLS_PLANS);
++        memcpy(&p_HcFrame->hcSpecificData.clsPlanEntries, &p_Set->vectors[idx], CLS_PLAN_NUM_PER_GRP*sizeof(uint32_t));
++        p_HcFrame->commandSequence = seqNum;
++
++        BUILD_FD(sizeof(t_HcFrame));
++
++        if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
++        {
++            PutBuf(p_FmHc, p_HcFrame, seqNum);
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        }
++    }
++
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++    return err;
++}
++
++t_Error FmHcPcdKgDeleteClsPlan(t_Handle h_FmHc, uint8_t  grpId)
++{
++    t_FmHc                              *p_FmHc = (t_FmHc*)h_FmHc;
++    t_FmPcdKgInterModuleClsPlanSet      *p_ClsPlanSet;
++
++    p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet));
++    if (!p_ClsPlanSet)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Classification plan set"));
++
++    memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet));
++
++    p_ClsPlanSet->baseEntry = FmPcdKgGetClsPlanGrpBase(p_FmHc->h_FmPcd, grpId);
++    p_ClsPlanSet->numOfClsPlanEntries = FmPcdKgGetClsPlanGrpSize(p_FmHc->h_FmPcd, grpId);
++    ASSERT_COND(p_ClsPlanSet->numOfClsPlanEntries <= FM_PCD_MAX_NUM_OF_CLS_PLANS);
++
++    if (FmHcPcdKgSetClsPlan(p_FmHc, p_ClsPlanSet) != E_OK)
++    {
++        XX_Free(p_ClsPlanSet);
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++    }
++
++    XX_Free(p_ClsPlanSet);
++    FmPcdKgDestroyClsPlanGrp(p_FmHc->h_FmPcd, grpId);
++
++    return E_OK;
++}
++
++t_Error FmHcPcdCcCapwapTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcCapwapReassmTimeoutParams *p_CcCapwapReassmTimeoutParams )
++{
++    t_FmHc                              *p_FmHc = (t_FmHc*)h_FmHc;
++    t_HcFrame                           *p_HcFrame;
++    t_DpaaFD                            fmFd;
++    t_Error                             err;
++    uint32_t                            seqNum;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0);
++
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++
++    memset(p_HcFrame, 0, sizeof(t_HcFrame));
++    p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC_CAPWAP_REASSM_TIMEOUT);
++    memcpy(&p_HcFrame->hcSpecificData.ccCapwapReassmTimeout, p_CcCapwapReassmTimeoutParams, sizeof(t_FmPcdCcCapwapReassmTimeoutParams));
++    p_HcFrame->commandSequence = seqNum;
++    BUILD_FD(sizeof(t_HcFrame));
++
++    err = EnQFrm(p_FmHc, &fmFd, seqNum);
++
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++    return err;
++}
++
++t_Error FmHcPcdCcIpFragScratchPollCmd(t_Handle h_FmHc, bool fill, t_FmPcdCcFragScratchPoolCmdParams *p_FmPcdCcFragScratchPoolCmdParams)
++{
++    t_FmHc                              *p_FmHc = (t_FmHc*)h_FmHc;
++    t_HcFrame                           *p_HcFrame;
++    t_DpaaFD                            fmFd;
++    t_Error                             err;
++    uint32_t                            seqNum;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0);
++
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++
++    memset(p_HcFrame, 0, sizeof(t_HcFrame));
++
++    p_HcFrame->opcode     = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC_IP_FRAG_INITIALIZATION);
++    p_HcFrame->actionReg  = (uint32_t)(((fill == TRUE) ? 0 : 1) << HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_CMD_SHIFT);
++    p_HcFrame->actionReg |= p_FmPcdCcFragScratchPoolCmdParams->bufferPoolId << HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_BPID;
++    if (fill == TRUE)
++    {
++        p_HcFrame->extraReg   = p_FmPcdCcFragScratchPoolCmdParams->numOfBuffers;
++    }
++    p_HcFrame->commandSequence = seqNum;
++
++    BUILD_FD(sizeof(t_HcFrame));
++    if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
++    {
++        PutBuf(p_FmHc, p_HcFrame, seqNum);
++        RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++
++    p_FmPcdCcFragScratchPoolCmdParams->numOfBuffers = p_HcFrame->extraReg;
++
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++    return E_OK;
++}
++
++t_Error FmHcPcdCcTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcReassmTimeoutParams *p_CcReassmTimeoutParams, uint8_t *p_Result)
++{
++    t_FmHc                              *p_FmHc = (t_FmHc*)h_FmHc;
++    t_HcFrame                           *p_HcFrame;
++    t_DpaaFD                            fmFd;
++    t_Error                             err;
++    uint32_t                            seqNum;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0);
++
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++
++    memset(p_HcFrame, 0, sizeof(t_HcFrame));
++    p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC_REASSM_TIMEOUT);
++    p_HcFrame->actionReg = (uint32_t)((p_CcReassmTimeoutParams->activate ? 0 : 1) << HC_HCOR_ACTION_REG_REASSM_TIMEOUT_ACTIVE_SHIFT);
++    p_HcFrame->extraReg = (p_CcReassmTimeoutParams->tsbs << HC_HCOR_EXTRA_REG_REASSM_TIMEOUT_TSBS_SHIFT) | p_CcReassmTimeoutParams->iprcpt;
++    p_HcFrame->commandSequence = seqNum;
++
++    BUILD_FD(sizeof(t_HcFrame));
++    if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
++    {
++        PutBuf(p_FmHc, p_HcFrame, seqNum);
++        RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++
++    *p_Result = (uint8_t)
++        ((p_HcFrame->actionReg >> HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_SHIFT) & HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_MASK);
++
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++    return E_OK;
++}
++
++t_Error FmHcPcdPlcrCcGetSetParams(t_Handle h_FmHc,uint16_t absoluteProfileId, uint32_t requiredAction)
++{
++    t_FmHc              *p_FmHc = (t_FmHc*)h_FmHc;
++    t_HcFrame           *p_HcFrame;
++    t_DpaaFD            fmFd;
++    t_Error             err;
++    uint32_t            tmpReg32 = 0;
++    uint32_t            requiredActionTmp, requiredActionFlag;
++    uint32_t            seqNum;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0);
++
++    /* Profile is locked by calling routine */
++    /* WARNING - this lock will not be efficient if other HC routine will attempt to change
++     * "fmpl_pegnia" "fmpl_peynia" or "fmpl_pernia" without locking Profile !
++     */
++
++    requiredActionTmp = FmPcdPlcrGetRequiredAction(p_FmHc->h_FmPcd, absoluteProfileId);
++    requiredActionFlag = FmPcdPlcrGetRequiredActionFlag(p_FmHc->h_FmPcd, absoluteProfileId);
++
++    if (!requiredActionFlag || !(requiredActionTmp & requiredAction))
++    {
++        if (requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA)
++        {
++            p_HcFrame = GetBuf(p_FmHc, &seqNum);
++            if (!p_HcFrame)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++            /* first read scheme and check that it is valid */
++            memset(p_HcFrame, 0, sizeof(t_HcFrame));
++            p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
++            p_HcFrame->actionReg  = FmPcdPlcrBuildReadPlcrActionReg(absoluteProfileId);
++            p_HcFrame->extraReg = 0x00008000;
++            p_HcFrame->commandSequence = seqNum;
++
++            BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC);
++
++            if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
++            {
++                PutBuf(p_FmHc, p_HcFrame, seqNum);
++                RETURN_ERROR(MINOR, err, NO_MSG);
++            }
++
++            tmpReg32 = p_HcFrame->hcSpecificData.profileRegs.fmpl_pegnia;
++            if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
++            {
++                PutBuf(p_FmHc, p_HcFrame, seqNum);
++                RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                             ("Next engine of this policer profile has to be assigned to FM_PCD_DONE"));
++            }
++
++            tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
++
++            p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
++            p_HcFrame->actionReg  = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId);
++            p_HcFrame->actionReg |= FmPcdPlcrBuildNiaProfileReg(TRUE, FALSE, FALSE);
++            p_HcFrame->extraReg = 0x00008000;
++            p_HcFrame->hcSpecificData.singleRegForWrite = tmpReg32;
++
++            BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT);
++
++            if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
++            {
++                PutBuf(p_FmHc, p_HcFrame, seqNum);
++                RETURN_ERROR(MINOR, err, NO_MSG);
++            }
++
++            tmpReg32 = p_HcFrame->hcSpecificData.profileRegs.fmpl_peynia;
++            if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
++            {
++                PutBuf(p_FmHc, p_HcFrame, seqNum);
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE"));
++            }
++
++            tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
++
++            p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
++            p_HcFrame->actionReg  = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId);
++            p_HcFrame->actionReg |= FmPcdPlcrBuildNiaProfileReg(FALSE, TRUE, FALSE);
++            p_HcFrame->extraReg = 0x00008000;
++            p_HcFrame->hcSpecificData.singleRegForWrite = tmpReg32;
++
++            BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT);
++
++            if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
++            {
++                PutBuf(p_FmHc, p_HcFrame, seqNum);
++                RETURN_ERROR(MINOR, err, NO_MSG);
++            }
++
++            tmpReg32 = p_HcFrame->hcSpecificData.profileRegs.fmpl_pernia;
++            if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
++            {
++                PutBuf(p_FmHc, p_HcFrame, seqNum);
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE"));
++            }
++
++            tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
++
++            p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
++            p_HcFrame->actionReg  = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId);
++            p_HcFrame->actionReg |= FmPcdPlcrBuildNiaProfileReg(FALSE, FALSE, TRUE);
++            p_HcFrame->extraReg = 0x00008000;
++            p_HcFrame->hcSpecificData.singleRegForWrite = tmpReg32;
++
++            BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT);
++
++            if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
++            {
++                PutBuf(p_FmHc, p_HcFrame, seqNum);
++                RETURN_ERROR(MINOR, err, NO_MSG);
++            }
++
++            PutBuf(p_FmHc, p_HcFrame, seqNum);
++        }
++    }
++
++    return E_OK;
++}
++
++t_Error FmHcPcdPlcrSetProfile(t_Handle h_FmHc, t_Handle h_Profile, t_FmPcdPlcrProfileRegs *p_PlcrRegs)
++{
++    t_FmHc                              *p_FmHc = (t_FmHc*)h_FmHc;
++    t_Error                             err = E_OK;
++    uint16_t                            profileIndx;
++    t_HcFrame                           *p_HcFrame;
++    t_DpaaFD                            fmFd;
++    uint32_t                            seqNum;
++
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++
++    profileIndx = FmPcdPlcrProfileGetAbsoluteId(h_Profile);
++
++    memset(p_HcFrame, 0, sizeof(t_HcFrame));
++    p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
++    p_HcFrame->actionReg  = FmPcdPlcrBuildWritePlcrActionRegs(profileIndx);
++    p_HcFrame->extraReg = 0x00008000;
++    memcpy(&p_HcFrame->hcSpecificData.profileRegs, p_PlcrRegs, sizeof(t_FmPcdPlcrProfileRegs));
++    p_HcFrame->commandSequence = seqNum;
++
++    BUILD_FD(sizeof(t_HcFrame));
++
++    err = EnQFrm(p_FmHc, &fmFd, seqNum);
++
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++
++    if (err != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++t_Error FmHcPcdPlcrDeleteProfile(t_Handle h_FmHc, t_Handle h_Profile)
++{
++    t_FmHc      *p_FmHc = (t_FmHc*)h_FmHc;
++    uint16_t    absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile);
++    t_Error     err = E_OK;
++    t_HcFrame   *p_HcFrame;
++    t_DpaaFD    fmFd;
++    uint32_t    seqNum;
++
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++    memset(p_HcFrame, 0, sizeof(t_HcFrame));
++    p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
++    p_HcFrame->actionReg  = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId);
++    p_HcFrame->actionReg  |= 0x00008000;
++    p_HcFrame->extraReg = 0x00008000;
++    memset(&p_HcFrame->hcSpecificData.profileRegs, 0, sizeof(t_FmPcdPlcrProfileRegs));
++    p_HcFrame->commandSequence = seqNum;
++
++    BUILD_FD(sizeof(t_HcFrame));
++
++    err = EnQFrm(p_FmHc, &fmFd, seqNum);
++
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++
++    if (err != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++t_Error  FmHcPcdPlcrSetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value)
++{
++
++    t_FmHc      *p_FmHc = (t_FmHc*)h_FmHc;
++    uint16_t    absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile);
++    t_Error     err = E_OK;
++    t_HcFrame   *p_HcFrame;
++    t_DpaaFD    fmFd;
++    uint32_t    seqNum;
++
++    /* first read scheme and check that it is valid */
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++    memset(p_HcFrame, 0, sizeof(t_HcFrame));
++    p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
++    p_HcFrame->actionReg  = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId);
++    p_HcFrame->actionReg |= FmPcdPlcrBuildCounterProfileReg(counter);
++    p_HcFrame->extraReg = 0x00008000;
++    p_HcFrame->hcSpecificData.singleRegForWrite = value;
++    p_HcFrame->commandSequence = seqNum;
++
++    BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT);
++
++    err = EnQFrm(p_FmHc, &fmFd, seqNum);
++
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++
++    if (err != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++uint32_t FmHcPcdPlcrGetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter)
++{
++    t_FmHc      *p_FmHc = (t_FmHc*)h_FmHc;
++    uint16_t    absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile);
++    t_Error     err;
++    t_HcFrame   *p_HcFrame;
++    t_DpaaFD    fmFd;
++    uint32_t    retVal = 0;
++    uint32_t    seqNum;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0);
++
++    /* first read scheme and check that it is valid */
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++    {
++        REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++        return 0;
++    }
++    memset(p_HcFrame, 0, sizeof(t_HcFrame));
++    p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
++    p_HcFrame->actionReg  = FmPcdPlcrBuildReadPlcrActionReg(absoluteProfileId);
++    p_HcFrame->extraReg = 0x00008000;
++    p_HcFrame->commandSequence = seqNum;
++
++    BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC);
++
++    err = EnQFrm(p_FmHc, &fmFd, seqNum);
++    if (err != E_OK)
++    {
++        PutBuf(p_FmHc, p_HcFrame, seqNum);
++        REPORT_ERROR(MINOR, err, NO_MSG);
++        return 0;
++    }
++
++    switch (counter)
++    {
++        case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER:
++            retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_pegpc;
++            break;
++        case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER:
++            retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_peypc;
++            break;
++        case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER:
++            retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_perpc;
++            break;
++        case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER:
++            retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_perypc;
++            break;
++        case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER:
++            retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_perrpc;
++            break;
++        default:
++            REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++    }
++
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++    return retVal;
++}
++
++t_Error FmHcKgWriteSp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t spReg, bool add)
++{
++    t_FmHc                  *p_FmHc = (t_FmHc*)h_FmHc;
++    t_HcFrame               *p_HcFrame;
++    t_DpaaFD                fmFd;
++    t_Error                 err = E_OK;
++    uint32_t                seqNum;
++
++    ASSERT_COND(p_FmHc);
++
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++    memset(p_HcFrame, 0, sizeof(t_HcFrame));
++    /* first read SP register */
++    p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
++    p_HcFrame->actionReg  = FmPcdKgBuildReadPortSchemeBindActionReg(hardwarePortId);
++    p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
++    p_HcFrame->commandSequence = seqNum;
++
++    BUILD_FD(SIZE_OF_HC_FRAME_PORT_REGS);
++
++    if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
++    {
++        PutBuf(p_FmHc, p_HcFrame, seqNum);
++        RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++
++    /* spReg is the first reg, so we can use it both for read and for write */
++    if (add)
++        p_HcFrame->hcSpecificData.portRegsForRead.spReg |= spReg;
++    else
++        p_HcFrame->hcSpecificData.portRegsForRead.spReg &= ~spReg;
++
++    p_HcFrame->actionReg  = FmPcdKgBuildWritePortSchemeBindActionReg(hardwarePortId);
++
++    BUILD_FD(sizeof(t_HcFrame));
++
++    err = EnQFrm(p_FmHc, &fmFd, seqNum);
++
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++
++    if (err != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++t_Error FmHcKgWriteCpp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t cppReg)
++{
++    t_FmHc                  *p_FmHc = (t_FmHc*)h_FmHc;
++    t_HcFrame               *p_HcFrame;
++    t_DpaaFD                fmFd;
++    t_Error                 err = E_OK;
++    uint32_t                seqNum;
++
++    ASSERT_COND(p_FmHc);
++
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++    memset(p_HcFrame, 0, sizeof(t_HcFrame));
++    /* first read SP register */
++    p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
++    p_HcFrame->actionReg  = FmPcdKgBuildWritePortClsPlanBindActionReg(hardwarePortId);
++    p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
++    p_HcFrame->hcSpecificData.singleRegForWrite = cppReg;
++    p_HcFrame->commandSequence = seqNum;
++
++    BUILD_FD(sizeof(t_HcFrame));
++
++    err = EnQFrm(p_FmHc, &fmFd, seqNum);
++
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++
++    if (err != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++t_Error FmHcPcdCcDoDynamicChange(t_Handle h_FmHc, uint32_t oldAdAddrOffset, uint32_t newAdAddrOffset)
++{
++    t_FmHc                  *p_FmHc = (t_FmHc*)h_FmHc;
++    t_HcFrame               *p_HcFrame;
++    t_DpaaFD                fmFd;
++    t_Error                 err = E_OK;
++    uint32_t                seqNum;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmHc, E_INVALID_HANDLE);
++
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++    memset(p_HcFrame, 0, sizeof(t_HcFrame));
++
++    p_HcFrame->opcode     = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC);
++    p_HcFrame->actionReg  = newAdAddrOffset;
++    p_HcFrame->actionReg |= 0xc0000000;
++    p_HcFrame->extraReg   = oldAdAddrOffset;
++    p_HcFrame->commandSequence = seqNum;
++
++    BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC);
++
++    err = EnQFrm(p_FmHc, &fmFd, seqNum);
++
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++
++    if (err != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++t_Error FmHcPcdSync(t_Handle h_FmHc)
++{
++    t_FmHc                  *p_FmHc = (t_FmHc*)h_FmHc;
++    t_HcFrame               *p_HcFrame;
++    t_DpaaFD                fmFd;
++    t_Error                 err = E_OK;
++    uint32_t                seqNum;
++
++    ASSERT_COND(p_FmHc);
++
++    p_HcFrame = GetBuf(p_FmHc, &seqNum);
++    if (!p_HcFrame)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
++    memset(p_HcFrame, 0, sizeof(t_HcFrame));
++    /* first read SP register */
++    p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_SYNC);
++    p_HcFrame->actionReg = 0;
++    p_HcFrame->extraReg = 0;
++    p_HcFrame->commandSequence = seqNum;
++
++    BUILD_FD(sizeof(t_HcFrame));
++
++    err = EnQFrm(p_FmHc, &fmFd, seqNum);
++
++    PutBuf(p_FmHc, p_HcFrame, seqNum);
++
++    if (err != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++t_Handle    FmHcGetPort(t_Handle h_FmHc)
++{
++    t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
++    return p_FmHc->h_HcPortDev;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/Makefile
+@@ -0,0 +1,28 @@
++#
++# Makefile for the Freescale Ethernet controllers
++#
++ccflags-y           += -DVERSION=\"\"
++#
++#Include netcomm SW specific definitions
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++
++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
++
++ccflags-y += -I$(NCSW_FM_INC)
++
++obj-y         += fsl-ncsw-MAC.o
++
++fsl-ncsw-MAC-objs     :=  dtsec.o dtsec_mii_acc.o fm_mac.o tgec.o tgec_mii_acc.o \
++                          fman_dtsec.o fman_dtsec_mii_acc.o fman_memac.o \
++                          fman_tgec.o fman_crc32.o
++
++ifeq ($(CONFIG_FMAN_V3H),y)
++fsl-ncsw-MAC-objs     +=  memac.o memac_mii_acc.o fman_memac_mii_acc.o
++endif
++ifeq ($(CONFIG_FMAN_V3L),y)
++fsl-ncsw-MAC-objs       +=  memac.o memac_mii_acc.o fman_memac_mii_acc.o
++endif
++ifeq ($(CONFIG_FMAN_ARM),y)
++fsl-ncsw-MAC-objs       +=  memac.o memac_mii_acc.o fman_memac_mii_acc.o
++endif
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c
+@@ -0,0 +1,1464 @@
++/*
++ * Copyright 2008-2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/******************************************************************************
++ @File          dtsec.c
++
++ @Description   FMan dTSEC driver
++*//***************************************************************************/
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "string_ext.h"
++#include "xx_ext.h"
++#include "endian_ext.h"
++#include "debug_ext.h"
++#include "crc_mac_addr_ext.h"
++
++#include "fm_common.h"
++#include "dtsec.h"
++#include "fsl_fman_dtsec.h"
++#include "fsl_fman_dtsec_mii_acc.h"
++
++/*****************************************************************************/
++/*                      Internal routines                                    */
++/*****************************************************************************/
++
++static t_Error CheckInitParameters(t_Dtsec *p_Dtsec)
++{
++    if (ENET_SPEED_FROM_MODE(p_Dtsec->enetMode) >= e_ENET_SPEED_10000)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 1G MAC driver only supports 1G or lower speeds"));
++    if (p_Dtsec->macId >= FM_MAX_NUM_OF_1G_MACS)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("macId can not be greater than the number of 1G MACs"));
++    if (p_Dtsec->addr == 0)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC Must have a valid MAC Address"));
++    if ((ENET_SPEED_FROM_MODE(p_Dtsec->enetMode) >= e_ENET_SPEED_1000) &&
++        p_Dtsec->p_DtsecDriverParam->halfdup_on)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC 1G can't work in half duplex"));
++    if (p_Dtsec->p_DtsecDriverParam->halfdup_on && (p_Dtsec->p_DtsecDriverParam)->loopback)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("LoopBack is not supported in halfDuplex mode"));
++#ifdef FM_RX_PREAM_4_ERRATA_DTSEC_A001
++    if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev <= 6) /* fixed for rev3 */
++        if (p_Dtsec->p_DtsecDriverParam->rx_preamble)
++            RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("preambleRxEn"));
++#endif /* FM_RX_PREAM_4_ERRATA_DTSEC_A001 */
++    if (((p_Dtsec->p_DtsecDriverParam)->tx_preamble || (p_Dtsec->p_DtsecDriverParam)->rx_preamble) &&( (p_Dtsec->p_DtsecDriverParam)->preamble_len != 0x7))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Preamble length should be 0x7 bytes"));
++    if ((p_Dtsec->p_DtsecDriverParam)->halfdup_on &&
++       (p_Dtsec->p_DtsecDriverParam->tx_time_stamp_en || p_Dtsec->p_DtsecDriverParam->rx_time_stamp_en))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dTSEC in half duplex mode has to be with 1588 timeStamping diable"));
++    if ((p_Dtsec->p_DtsecDriverParam)->rx_flow && (p_Dtsec->p_DtsecDriverParam)->rx_ctrl_acc )
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Receive control frame are not passed to the system memory so it can not be accept "));
++    if ((p_Dtsec->p_DtsecDriverParam)->rx_prepend  > MAX_PACKET_ALIGNMENT)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("packetAlignmentPadding can't be greater than %d ",MAX_PACKET_ALIGNMENT ));
++    if (((p_Dtsec->p_DtsecDriverParam)->non_back_to_back_ipg1  > MAX_INTER_PACKET_GAP) ||
++        ((p_Dtsec->p_DtsecDriverParam)->non_back_to_back_ipg2 > MAX_INTER_PACKET_GAP) ||
++        ((p_Dtsec->p_DtsecDriverParam)->back_to_back_ipg > MAX_INTER_PACKET_GAP))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inter packet gap can't be greater than %d ",MAX_INTER_PACKET_GAP ));
++    if ((p_Dtsec->p_DtsecDriverParam)->halfdup_alt_backoff_val > MAX_INTER_PALTERNATE_BEB)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("alternateBackoffVal can't be greater than %d ",MAX_INTER_PALTERNATE_BEB ));
++    if ((p_Dtsec->p_DtsecDriverParam)->halfdup_retransmit > MAX_RETRANSMISSION)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("maxRetransmission can't be greater than %d ",MAX_RETRANSMISSION ));
++    if ((p_Dtsec->p_DtsecDriverParam)->halfdup_coll_window > MAX_COLLISION_WINDOW)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("collisionWindow can't be greater than %d ",MAX_COLLISION_WINDOW ));
++
++    /*  If Auto negotiation process is disabled, need to */
++    /*  Set up the PHY using the MII Management Interface */
++    if (p_Dtsec->p_DtsecDriverParam->tbipa > MAX_PHYS)
++        RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ("PHY address (should be 0-%d)", MAX_PHYS));
++    if (!p_Dtsec->f_Exception)
++        RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("uninitialized f_Exception"));
++    if (!p_Dtsec->f_Event)
++        RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("uninitialized f_Event"));
++
++#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002
++    if (p_Dtsec->p_DtsecDriverParam->rx_len_check)
++       RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!"));
++#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static uint32_t GetMacAddrHashCode(uint64_t ethAddr)
++{
++    uint32_t crc;
++
++    /* CRC calculation */
++    GET_MAC_ADDR_CRC(ethAddr, crc);
++
++    crc = GetMirror32(crc);
++
++    return crc;
++}
++
++/* ......................................................................... */
++
++static void UpdateStatistics(t_Dtsec *p_Dtsec)
++{
++    uint32_t car1, car2;
++
++    fman_dtsec_get_clear_carry_regs(p_Dtsec->p_MemMap, &car1, &car2);
++
++    if (car1)
++    {
++        if (car1 & CAR1_TR64)
++            p_Dtsec->internalStatistics.tr64 += VAL22BIT;
++        if (car1 & CAR1_TR127)
++            p_Dtsec->internalStatistics.tr127 += VAL22BIT;
++        if (car1 & CAR1_TR255)
++            p_Dtsec->internalStatistics.tr255 += VAL22BIT;
++        if (car1 & CAR1_TR511)
++            p_Dtsec->internalStatistics.tr511 += VAL22BIT;
++        if (car1 & CAR1_TRK1)
++            p_Dtsec->internalStatistics.tr1k += VAL22BIT;
++        if (car1 & CAR1_TRMAX)
++            p_Dtsec->internalStatistics.trmax += VAL22BIT;
++        if (car1 & CAR1_TRMGV)
++            p_Dtsec->internalStatistics.trmgv += VAL22BIT;
++        if (car1 & CAR1_RBYT)
++            p_Dtsec->internalStatistics.rbyt += (uint64_t)VAL32BIT;
++        if (car1 & CAR1_RPKT)
++            p_Dtsec->internalStatistics.rpkt += VAL22BIT;
++        if (car1 & CAR1_RMCA)
++            p_Dtsec->internalStatistics.rmca += VAL22BIT;
++        if (car1 & CAR1_RBCA)
++            p_Dtsec->internalStatistics.rbca += VAL22BIT;
++        if (car1 & CAR1_RXPF)
++            p_Dtsec->internalStatistics.rxpf += VAL16BIT;
++        if (car1 & CAR1_RALN)
++            p_Dtsec->internalStatistics.raln += VAL16BIT;
++        if (car1 & CAR1_RFLR)
++            p_Dtsec->internalStatistics.rflr += VAL16BIT;
++        if (car1 & CAR1_RCDE)
++            p_Dtsec->internalStatistics.rcde += VAL16BIT;
++        if (car1 & CAR1_RCSE)
++            p_Dtsec->internalStatistics.rcse += VAL16BIT;
++        if (car1 & CAR1_RUND)
++            p_Dtsec->internalStatistics.rund += VAL16BIT;
++        if (car1 & CAR1_ROVR)
++            p_Dtsec->internalStatistics.rovr += VAL16BIT;
++        if (car1 & CAR1_RFRG)
++            p_Dtsec->internalStatistics.rfrg += VAL16BIT;
++        if (car1 & CAR1_RJBR)
++            p_Dtsec->internalStatistics.rjbr += VAL16BIT;
++        if (car1 & CAR1_RDRP)
++            p_Dtsec->internalStatistics.rdrp += VAL16BIT;
++    }
++    if (car2)
++    {
++        if (car2  & CAR2_TFCS)
++            p_Dtsec->internalStatistics.tfcs += VAL12BIT;
++        if (car2  & CAR2_TBYT)
++            p_Dtsec->internalStatistics.tbyt += (uint64_t)VAL32BIT;
++        if (car2  & CAR2_TPKT)
++            p_Dtsec->internalStatistics.tpkt += VAL22BIT;
++        if (car2  & CAR2_TMCA)
++            p_Dtsec->internalStatistics.tmca += VAL22BIT;
++        if (car2  & CAR2_TBCA)
++            p_Dtsec->internalStatistics.tbca += VAL22BIT;
++        if (car2  & CAR2_TXPF)
++            p_Dtsec->internalStatistics.txpf += VAL16BIT;
++        if (car2  & CAR2_TDRP)
++            p_Dtsec->internalStatistics.tdrp += VAL16BIT;
++    }
++}
++
++/* .............................................................................. */
++
++static uint16_t DtsecGetMaxFrameLength(t_Handle h_Dtsec)
++{
++    t_Dtsec     *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_VALUE(p_Dtsec, E_INVALID_HANDLE, 0);
++    SANITY_CHECK_RETURN_VALUE(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE, 0);
++
++    return fman_dtsec_get_max_frame_len(p_Dtsec->p_MemMap);
++}
++
++/* .............................................................................. */
++
++static void DtsecIsr(t_Handle h_Dtsec)
++{
++    t_Dtsec             *p_Dtsec = (t_Dtsec *)h_Dtsec;
++    uint32_t            event;
++    struct dtsec_regs   *p_DtsecMemMap = p_Dtsec->p_MemMap;
++
++    /* do not handle MDIO events */
++    event = fman_dtsec_get_event(p_DtsecMemMap, (uint32_t)(~(DTSEC_IMASK_MMRDEN | DTSEC_IMASK_MMWREN)));
++
++    event &= fman_dtsec_get_interrupt_mask(p_DtsecMemMap);
++
++    fman_dtsec_ack_event(p_DtsecMemMap, event);
++
++    if (event & DTSEC_IMASK_BREN)
++        p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_BAB_RX);
++    if (event & DTSEC_IMASK_RXCEN)
++        p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_RX_CTL);
++    if (event & DTSEC_IMASK_MSROEN)
++        UpdateStatistics(p_Dtsec);
++    if (event & DTSEC_IMASK_GTSCEN)
++        p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET);
++    if (event & DTSEC_IMASK_BTEN)
++        p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_BAB_TX);
++    if (event & DTSEC_IMASK_TXCEN)
++        p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_CTL);
++    if (event & DTSEC_IMASK_TXEEN)
++        p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_ERR);
++    if (event & DTSEC_IMASK_LCEN)
++        p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_LATE_COL);
++    if (event & DTSEC_IMASK_CRLEN)
++        p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_COL_RET_LMT);
++    if (event & DTSEC_IMASK_XFUNEN)
++    {
++#ifdef FM_TX_LOCKUP_ERRATA_DTSEC6
++        if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2)
++        {
++            uint32_t  tpkt1, tmpReg1, tpkt2, tmpReg2, i;
++            /* a. Write 0x00E0_0C00 to DTSEC_ID */
++            /* This is a read only regidter */
++
++            /* b. Read and save the value of TPKT */
++            tpkt1 = GET_UINT32(p_DtsecMemMap->tpkt);
++
++            /* c. Read the register at dTSEC address offset 0x32C */
++            tmpReg1 =  GET_UINT32(*(uint32_t*)((uint8_t*)p_DtsecMemMap + 0x32c));
++
++            /* d. Compare bits [9:15] to bits [25:31] of the register at address offset 0x32C. */
++            if ((tmpReg1 & 0x007F0000) != (tmpReg1 & 0x0000007F))
++            {
++                /* If they are not equal, save the value of this register and wait for at least
++                 * MAXFRM*16 ns */
++                XX_UDelay((uint32_t)(MIN(DtsecGetMaxFrameLength(p_Dtsec)*16/1000, 1)));
++            }
++
++            /* e. Read and save TPKT again and read the register at dTSEC address offset
++                0x32C again*/
++            tpkt2 = GET_UINT32(p_DtsecMemMap->tpkt);
++            tmpReg2 = GET_UINT32(*(uint32_t*)((uint8_t*)p_DtsecMemMap + 0x32c));
++
++            /* f. Compare the value of TPKT saved in step b to value read in step e. Also
++                compare bits [9:15] of the register at offset 0x32C saved in step d to the value
++                of bits [9:15] saved in step e. If the two registers values are unchanged, then
++                the transmit portion of the dTSEC controller is locked up and the user should
++                proceed to the recover sequence. */
++            if ((tpkt1 == tpkt2) && ((tmpReg1 & 0x007F0000) == (tmpReg2 & 0x007F0000)))
++            {
++                /* recover sequence */
++
++                /* a.Write a 1 to RCTRL[GRS]*/
++
++                WRITE_UINT32(p_DtsecMemMap->rctrl, GET_UINT32(p_DtsecMemMap->rctrl) | RCTRL_GRS);
++
++                /* b.Wait until IEVENT[GRSC]=1, or at least 100 us has elapsed. */
++                for (i = 0 ; i < 100 ; i++ )
++                {
++                    if (GET_UINT32(p_DtsecMemMap->ievent) & DTSEC_IMASK_GRSCEN)
++                        break;
++                    XX_UDelay(1);
++                }
++                if (GET_UINT32(p_DtsecMemMap->ievent) & DTSEC_IMASK_GRSCEN)
++                    WRITE_UINT32(p_DtsecMemMap->ievent, DTSEC_IMASK_GRSCEN);
++                else
++                    DBG(INFO,("Rx lockup due to dTSEC Tx lockup"));
++
++                /* c.Write a 1 to bit n of FM_RSTC (offset 0x0CC of FPM)*/
++                FmResetMac(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MAC_1G, p_Dtsec->fmMacControllerDriver.macId);
++
++                /* d.Wait 4 Tx clocks (32 ns) */
++                XX_UDelay(1);
++
++                /* e.Write a 0 to bit n of FM_RSTC. */
++                /* cleared by FMAN */
++            }
++        }
++#endif /* FM_TX_LOCKUP_ERRATA_DTSEC6 */
++
++        p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_FIFO_UNDRN);
++    }
++    if (event & DTSEC_IMASK_MAGEN)
++        p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_MAG_PCKT);
++    if (event & DTSEC_IMASK_GRSCEN)
++        p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET);
++    if (event & DTSEC_IMASK_TDPEEN)
++        p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_DATA_ERR);
++    if (event & DTSEC_IMASK_RDPEEN)
++        p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_RX_DATA_ERR);
++
++    /*  - masked interrupts */
++    ASSERT_COND(!(event & DTSEC_IMASK_ABRTEN));
++    ASSERT_COND(!(event & DTSEC_IMASK_IFERREN));
++}
++
++static void DtsecMdioIsr(t_Handle h_Dtsec)
++{
++    t_Dtsec             *p_Dtsec = (t_Dtsec *)h_Dtsec;
++    uint32_t            event;
++    struct dtsec_regs   *p_DtsecMemMap = p_Dtsec->p_MemMap;
++
++    event = GET_UINT32(p_DtsecMemMap->ievent);
++    /* handle only MDIO events */
++    event &= (DTSEC_IMASK_MMRDEN | DTSEC_IMASK_MMWREN);
++    if (event)
++    {
++        event &= GET_UINT32(p_DtsecMemMap->imask);
++
++        WRITE_UINT32(p_DtsecMemMap->ievent, event);
++
++        if (event & DTSEC_IMASK_MMRDEN)
++            p_Dtsec->f_Event(p_Dtsec->h_App, e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET);
++        if (event & DTSEC_IMASK_MMWREN)
++            p_Dtsec->f_Event(p_Dtsec->h_App, e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET);
++    }
++}
++
++static void Dtsec1588Isr(t_Handle h_Dtsec)
++{
++    t_Dtsec             *p_Dtsec = (t_Dtsec *)h_Dtsec;
++    uint32_t            event;
++    struct dtsec_regs   *p_DtsecMemMap = p_Dtsec->p_MemMap;
++
++    if (p_Dtsec->ptpTsuEnabled)
++    {
++        event = fman_dtsec_check_and_clear_tmr_event(p_DtsecMemMap);
++
++        if (event)
++        {
++            ASSERT_COND(event & TMR_PEVENT_TSRE);
++            p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_1588_TS_RX_ERR);
++        }
++    }
++}
++
++/* ........................................................................... */
++
++static void FreeInitResources(t_Dtsec *p_Dtsec)
++{
++    if (p_Dtsec->mdioIrq != NO_IRQ)
++    {
++        XX_DisableIntr(p_Dtsec->mdioIrq);
++        XX_FreeIntr(p_Dtsec->mdioIrq);
++    }
++    FmUnregisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Dtsec->macId, e_FM_INTR_TYPE_ERR);
++    FmUnregisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Dtsec->macId, e_FM_INTR_TYPE_NORMAL);
++
++    /* release the driver's group hash table */
++    FreeHashTable(p_Dtsec->p_MulticastAddrHash);
++    p_Dtsec->p_MulticastAddrHash =   NULL;
++
++    /* release the driver's individual hash table */
++    FreeHashTable(p_Dtsec->p_UnicastAddrHash);
++    p_Dtsec->p_UnicastAddrHash =     NULL;
++}
++
++/* ........................................................................... */
++
++static t_Error GracefulStop(t_Dtsec *p_Dtsec, e_CommMode mode)
++{
++    struct dtsec_regs *p_MemMap;
++
++    ASSERT_COND(p_Dtsec);
++
++    p_MemMap = p_Dtsec->p_MemMap;
++    ASSERT_COND(p_MemMap);
++
++    /* Assert the graceful transmit stop bit */
++    if (mode & e_COMM_MODE_RX)
++    {
++        fman_dtsec_stop_rx(p_MemMap);
++
++#ifdef FM_GRS_ERRATA_DTSEC_A002
++        if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2)
++            XX_UDelay(100);
++#else  /* FM_GRS_ERRATA_DTSEC_A002 */
++#ifdef FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839
++        XX_UDelay(10);
++#endif /* FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839 */
++#endif /* FM_GRS_ERRATA_DTSEC_A002 */
++    }
++
++    if (mode & e_COMM_MODE_TX)
++#if defined(FM_GTS_ERRATA_DTSEC_A004) || defined(FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012)
++    if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2)
++        DBG(INFO, ("GTS not supported due to DTSEC_A004 errata."));
++#else  /* not defined(FM_GTS_ERRATA_DTSEC_A004) ||... */
++#ifdef FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014
++        DBG(INFO, ("GTS not supported due to DTSEC_A0014 errata."));
++#else  /* FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 */
++        fman_dtsec_stop_tx(p_MemMap);
++#endif /* FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 */
++#endif /* defined(FM_GTS_ERRATA_DTSEC_A004) ||...  */
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error GracefulRestart(t_Dtsec *p_Dtsec, e_CommMode mode)
++{
++    struct dtsec_regs *p_MemMap;
++
++    ASSERT_COND(p_Dtsec);
++    p_MemMap = p_Dtsec->p_MemMap;
++    ASSERT_COND(p_MemMap);
++
++    /* clear the graceful receive stop bit */
++    if (mode & e_COMM_MODE_TX)
++        fman_dtsec_start_tx(p_MemMap);
++
++    if (mode & e_COMM_MODE_RX)
++        fman_dtsec_start_rx(p_MemMap);
++
++    return E_OK;
++}
++
++
++/*****************************************************************************/
++/*                      dTSEC Configs modification functions                 */
++/*****************************************************************************/
++
++/* .............................................................................. */
++
++static t_Error DtsecConfigLoopback(t_Handle h_Dtsec, bool newVal)
++{
++
++    t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    p_Dtsec->p_DtsecDriverParam->loopback = newVal;
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecConfigMaxFrameLength(t_Handle h_Dtsec, uint16_t newVal)
++{
++    t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    p_Dtsec->p_DtsecDriverParam->maximum_frame = newVal;
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecConfigPadAndCrc(t_Handle h_Dtsec, bool newVal)
++{
++    t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    p_Dtsec->p_DtsecDriverParam->tx_pad_crc = newVal;
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecConfigHalfDuplex(t_Handle h_Dtsec, bool newVal)
++{
++    t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    p_Dtsec->p_DtsecDriverParam->halfdup_on = newVal;
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecConfigTbiPhyAddr(t_Handle h_Dtsec, uint8_t newVal)
++{
++    t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    p_Dtsec->p_DtsecDriverParam->tbi_phy_addr = newVal;
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecConfigLengthCheck(t_Handle h_Dtsec, bool newVal)
++{
++    t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    p_Dtsec->p_DtsecDriverParam->rx_len_check = newVal;
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecConfigException(t_Handle h_Dtsec, e_FmMacExceptions exception, bool enable)
++{
++    t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
++    uint32_t    bitMask = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    if (exception != e_FM_MAC_EX_1G_1588_TS_RX_ERR)
++    {
++        GET_EXCEPTION_FLAG(bitMask, exception);
++        if (bitMask)
++        {
++            if (enable)
++                p_Dtsec->exceptions |= bitMask;
++            else
++                p_Dtsec->exceptions &= ~bitMask;
++        }
++        else
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
++    }
++    else
++    {
++        if (!p_Dtsec->ptpTsuEnabled)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exception valid for 1588 only"));
++
++        if (enable)
++            p_Dtsec->enTsuErrExeption = TRUE;
++        else
++            p_Dtsec->enTsuErrExeption = FALSE;
++    }
++
++    return E_OK;
++}
++
++
++/*****************************************************************************/
++/*                      dTSEC Run Time API functions                         */
++/*****************************************************************************/
++
++/* .............................................................................. */
++
++static t_Error DtsecEnable(t_Handle h_Dtsec,  e_CommMode mode)
++{
++    t_Dtsec     *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    fman_dtsec_enable(p_Dtsec->p_MemMap,
++                 (bool)!!(mode & e_COMM_MODE_RX),
++                 (bool)!!(mode & e_COMM_MODE_TX));
++
++    GracefulRestart(p_Dtsec, mode);
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecDisable (t_Handle h_Dtsec, e_CommMode mode)
++{
++    t_Dtsec     *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    GracefulStop(p_Dtsec, mode);
++
++    fman_dtsec_disable(p_Dtsec->p_MemMap,
++                  (bool)!!(mode & e_COMM_MODE_RX),
++                  (bool)!!(mode & e_COMM_MODE_TX));
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecSetTxPauseFrames(t_Handle h_Dtsec,
++                                     uint8_t  priority,
++                                     uint16_t pauseTime,
++                                     uint16_t threshTime)
++{
++    t_Dtsec     *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    UNUSED(priority);UNUSED(threshTime);
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++#ifdef FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003
++    if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2)
++        if (0 < pauseTime && pauseTime <= 320)
++            RETURN_ERROR(MINOR, E_INVALID_VALUE,
++                     ("This pause-time value of %d is illegal due to errata dTSEC-A003!"
++                      " value should be greater than 320."));
++#endif /* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 */
++
++    fman_dtsec_set_tx_pause_frames(p_Dtsec->p_MemMap, pauseTime);
++    return E_OK;
++}
++
++/* .............................................................................. */
++/* backward compatibility. will be removed in the future. */
++static t_Error DtsecTxMacPause(t_Handle h_Dtsec, uint16_t pauseTime)
++{
++    return DtsecSetTxPauseFrames(h_Dtsec, 0, pauseTime, 0);
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecRxIgnoreMacPause(t_Handle h_Dtsec, bool en)
++{
++    t_Dtsec         *p_Dtsec = (t_Dtsec *)h_Dtsec;
++    bool            accept_pause = !en;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    fman_dtsec_handle_rx_pause(p_Dtsec->p_MemMap, accept_pause);
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecEnable1588TimeStamp(t_Handle h_Dtsec)
++{
++    t_Dtsec     *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    p_Dtsec->ptpTsuEnabled = TRUE;
++    fman_dtsec_set_ts(p_Dtsec->p_MemMap, TRUE);
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecDisable1588TimeStamp(t_Handle h_Dtsec)
++{
++    t_Dtsec     *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    p_Dtsec->ptpTsuEnabled = FALSE;
++    fman_dtsec_set_ts(p_Dtsec->p_MemMap, FALSE);
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecGetStatistics(t_Handle h_Dtsec, t_FmMacStatistics *p_Statistics)
++{
++    t_Dtsec             *p_Dtsec = (t_Dtsec *)h_Dtsec;
++    struct dtsec_regs   *p_DtsecMemMap;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER);
++
++    p_DtsecMemMap = p_Dtsec->p_MemMap;
++
++    if (p_Dtsec->statisticsLevel == e_FM_MAC_NONE_STATISTICS)
++        RETURN_ERROR(MINOR, E_INVALID_STATE, ("Statistics disabled"));
++
++    memset(p_Statistics, 0xff, sizeof(t_FmMacStatistics));
++
++    if (p_Dtsec->statisticsLevel == e_FM_MAC_FULL_STATISTICS)
++    {
++        p_Statistics->eStatPkts64 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR64)
++                + p_Dtsec->internalStatistics.tr64;
++        p_Statistics->eStatPkts65to127 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR127)
++                + p_Dtsec->internalStatistics.tr127;
++        p_Statistics->eStatPkts128to255 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR255)
++                + p_Dtsec->internalStatistics.tr255;
++        p_Statistics->eStatPkts256to511 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR511)
++                + p_Dtsec->internalStatistics.tr511;
++        p_Statistics->eStatPkts512to1023 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR1K)
++                + p_Dtsec->internalStatistics.tr1k;
++        p_Statistics->eStatPkts1024to1518 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TRMAX)
++                + p_Dtsec->internalStatistics.trmax;
++        p_Statistics->eStatPkts1519to1522 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TRMGV)
++                + p_Dtsec->internalStatistics.trmgv;
++
++        /* MIB II */
++        p_Statistics->ifInOctets = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RBYT)
++                + p_Dtsec->internalStatistics.rbyt;
++        p_Statistics->ifInPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RPKT)
++                + p_Dtsec->internalStatistics.rpkt;
++        p_Statistics->ifInUcastPkts = 0;
++        p_Statistics->ifInMcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RMCA)
++                + p_Dtsec->internalStatistics.rmca;
++        p_Statistics->ifInBcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RBCA)
++                + p_Dtsec->internalStatistics.rbca;
++        p_Statistics->ifOutOctets = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TBYT)
++                + p_Dtsec->internalStatistics.tbyt;
++        p_Statistics->ifOutPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TPKT)
++                + p_Dtsec->internalStatistics.tpkt;
++        p_Statistics->ifOutUcastPkts = 0;
++        p_Statistics->ifOutMcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TMCA)
++                + p_Dtsec->internalStatistics.tmca;
++        p_Statistics->ifOutBcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TBCA)
++                + p_Dtsec->internalStatistics.tbca;
++    }
++
++    p_Statistics->eStatFragments = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RFRG)
++            + p_Dtsec->internalStatistics.rfrg;
++    p_Statistics->eStatJabbers = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RJBR)
++            + p_Dtsec->internalStatistics.rjbr;
++    p_Statistics->eStatsDropEvents = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RDRP)
++            + p_Dtsec->internalStatistics.rdrp;
++    p_Statistics->eStatCRCAlignErrors = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RALN)
++            + p_Dtsec->internalStatistics.raln;
++    p_Statistics->eStatUndersizePkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RUND)
++            + p_Dtsec->internalStatistics.rund;
++    p_Statistics->eStatOversizePkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_ROVR)
++            + p_Dtsec->internalStatistics.rovr;
++    p_Statistics->reStatPause = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RXPF)
++            + p_Dtsec->internalStatistics.rxpf;
++    p_Statistics->teStatPause = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TXPF)
++            + p_Dtsec->internalStatistics.txpf;
++    p_Statistics->ifInDiscards = p_Statistics->eStatsDropEvents;
++    p_Statistics->ifInErrors = p_Statistics->eStatsDropEvents + p_Statistics->eStatCRCAlignErrors
++            + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RFLR) + p_Dtsec->internalStatistics.rflr
++            + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RCDE) + p_Dtsec->internalStatistics.rcde
++            + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RCSE) + p_Dtsec->internalStatistics.rcse;
++
++    p_Statistics->ifOutDiscards = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TDRP)
++            + p_Dtsec->internalStatistics.tdrp;
++    p_Statistics->ifOutErrors = p_Statistics->ifOutDiscards                                           /**< Number of frames transmitted with error: */
++            + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_TFCS)
++            + p_Dtsec->internalStatistics.tfcs;
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecModifyMacAddress (t_Handle h_Dtsec, t_EnetAddr *p_EnetAddr)
++{
++    t_Dtsec     *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    /* Initialize MAC Station Address registers (1 & 2)    */
++    /* Station address have to be swapped (big endian to little endian */
++    p_Dtsec->addr = ENET_ADDR_TO_UINT64(*p_EnetAddr);
++    fman_dtsec_set_mac_address(p_Dtsec->p_MemMap, (uint8_t *)(*p_EnetAddr));
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecResetCounters (t_Handle h_Dtsec)
++{
++    t_Dtsec     *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    /* clear HW counters */
++    fman_dtsec_reset_stat(p_Dtsec->p_MemMap);
++
++    /* clear SW counters holding carries */
++    memset(&p_Dtsec->internalStatistics, 0, sizeof(t_InternalStatistics));
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecAddExactMatchMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr)
++{
++    t_Dtsec   *p_Dtsec = (t_Dtsec *) h_Dtsec;
++    uint64_t  ethAddr;
++    uint8_t   paddrNum;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
++
++    if (ethAddr & GROUP_ADDRESS)
++        /* Multicast address has no effect in PADDR */
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address"));
++
++    /* Make sure no PADDR contains this address */
++    for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++)
++        if (p_Dtsec->indAddrRegUsed[paddrNum])
++            if (p_Dtsec->paddr[paddrNum] == ethAddr)
++                RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
++
++    /* Find first unused PADDR */
++    for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++)
++        if (!(p_Dtsec->indAddrRegUsed[paddrNum]))
++        {
++            /* mark this PADDR as used */
++            p_Dtsec->indAddrRegUsed[paddrNum] = TRUE;
++            /* store address */
++            p_Dtsec->paddr[paddrNum] = ethAddr;
++
++            /* put in hardware */
++            fman_dtsec_add_addr_in_paddr(p_Dtsec->p_MemMap, (uint64_t)PTR_TO_UINT(&ethAddr), paddrNum);
++            p_Dtsec->numOfIndAddrInRegs++;
++
++            return E_OK;
++        }
++
++    /* No free PADDR */
++    RETURN_ERROR(MAJOR, E_FULL, NO_MSG);
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecDelExactMatchMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr)
++{
++    t_Dtsec   *p_Dtsec = (t_Dtsec *) h_Dtsec;
++    uint64_t  ethAddr;
++    uint8_t   paddrNum;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
++
++    /* Find used PADDR containing this address */
++    for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++)
++    {
++        if ((p_Dtsec->indAddrRegUsed[paddrNum]) &&
++            (p_Dtsec->paddr[paddrNum] == ethAddr))
++        {
++            /* mark this PADDR as not used */
++            p_Dtsec->indAddrRegUsed[paddrNum] = FALSE;
++            /* clear in hardware */
++            fman_dtsec_clear_addr_in_paddr(p_Dtsec->p_MemMap, paddrNum);
++            p_Dtsec->numOfIndAddrInRegs--;
++
++            return E_OK;
++        }
++    }
++
++    RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG);
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecAddHashMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr)
++{
++    t_Dtsec         *p_Dtsec = (t_Dtsec *)h_Dtsec;
++    t_EthHashEntry  *p_HashEntry;
++    uint64_t        ethAddr;
++    int32_t         bucket;
++    uint32_t        crc;
++    bool            mcast, ghtx;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
++
++    ghtx = (bool)((fman_dtsec_get_rctrl(p_Dtsec->p_MemMap) & RCTRL_GHTX) ? TRUE : FALSE);
++    mcast = (bool)((ethAddr & MAC_GROUP_ADDRESS) ? TRUE : FALSE);
++
++    if (ghtx && !mcast) /* Cannot handle unicast mac addr when GHTX is on */
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Could not compute hash bucket"));
++
++    crc = GetMacAddrHashCode(ethAddr);
++
++    /* considering the 9 highest order bits in crc H[8:0]:
++     * if ghtx = 0 H[8:6] (highest order 3 bits) identify the hash register
++     * and H[5:1] (next 5 bits) identify the hash bit
++     * if ghts = 1 H[8:5] (highest order 4 bits) identify the hash register
++     * and H[4:0] (next 5 bits) identify the hash bit.
++     *
++     * In bucket index output the low 5 bits identify the hash register bit,
++     * while the higher 4 bits identify the hash register
++     */
++
++    if (ghtx)
++        bucket = (int32_t)((crc >> 23) & 0x1ff);
++    else {
++        bucket = (int32_t)((crc >> 24) & 0xff);
++        /* if !ghtx and mcast the bit must be set in gaddr instead of igaddr. */
++        if (mcast)
++            bucket += 0x100;
++    }
++
++    fman_dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, TRUE);
++
++    /* Create element to be added to the driver hash table */
++    p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry));
++    p_HashEntry->addr = ethAddr;
++    INIT_LIST(&p_HashEntry->node);
++
++    if (ethAddr & MAC_GROUP_ADDRESS)
++        /* Group Address */
++        LIST_AddToTail(&(p_HashEntry->node), &(p_Dtsec->p_MulticastAddrHash->p_Lsts[bucket]));
++    else
++        LIST_AddToTail(&(p_HashEntry->node), &(p_Dtsec->p_UnicastAddrHash->p_Lsts[bucket]));
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecDelHashMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr)
++{
++    t_Dtsec         *p_Dtsec = (t_Dtsec *)h_Dtsec;
++    t_List          *p_Pos;
++    t_EthHashEntry  *p_HashEntry = NULL;
++    uint64_t        ethAddr;
++    int32_t         bucket;
++    uint32_t        crc;
++    bool            mcast, ghtx;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
++
++    ghtx = (bool)((fman_dtsec_get_rctrl(p_Dtsec->p_MemMap) & RCTRL_GHTX) ? TRUE : FALSE);
++    mcast = (bool)((ethAddr & MAC_GROUP_ADDRESS) ? TRUE : FALSE);
++
++    if (ghtx && !mcast) /* Cannot handle unicast mac addr when GHTX is on */
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Could not compute hash bucket"));
++
++    crc = GetMacAddrHashCode(ethAddr);
++
++    if (ghtx)
++        bucket = (int32_t)((crc >> 23) & 0x1ff);
++    else {
++        bucket = (int32_t)((crc >> 24) & 0xff);
++        /* if !ghtx and mcast the bit must be set in gaddr instead of igaddr. */
++        if (mcast)
++            bucket += 0x100;
++    }
++
++    if (ethAddr & MAC_GROUP_ADDRESS)
++    {
++        /* Group Address */
++        LIST_FOR_EACH(p_Pos, &(p_Dtsec->p_MulticastAddrHash->p_Lsts[bucket]))
++        {
++            p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos);
++            if (p_HashEntry->addr == ethAddr)
++            {
++                LIST_DelAndInit(&p_HashEntry->node);
++                XX_Free(p_HashEntry);
++                break;
++            }
++        }
++        if (LIST_IsEmpty(&p_Dtsec->p_MulticastAddrHash->p_Lsts[bucket]))
++            fman_dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, FALSE);
++    }
++    else
++    {
++        /* Individual Address */
++        LIST_FOR_EACH(p_Pos, &(p_Dtsec->p_UnicastAddrHash->p_Lsts[bucket]))
++        {
++            p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos);
++            if (p_HashEntry->addr == ethAddr)
++            {
++                LIST_DelAndInit(&p_HashEntry->node);
++                XX_Free(p_HashEntry);
++                break;
++            }
++        }
++        if (LIST_IsEmpty(&p_Dtsec->p_UnicastAddrHash->p_Lsts[bucket]))
++            fman_dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, FALSE);
++    }
++
++    /* address does not exist */
++    ASSERT_COND(p_HashEntry != NULL);
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecSetPromiscuous(t_Handle h_Dtsec, bool newVal)
++{
++    t_Dtsec     *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    fman_dtsec_set_uc_promisc(p_Dtsec->p_MemMap, newVal);
++    fman_dtsec_set_mc_promisc(p_Dtsec->p_MemMap, newVal);
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecSetStatistics(t_Handle h_Dtsec, e_FmMacStatisticsLevel statisticsLevel)
++{
++    t_Dtsec     *p_Dtsec = (t_Dtsec *)h_Dtsec;
++    t_Error     err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    p_Dtsec->statisticsLevel = statisticsLevel;
++
++    err = (t_Error)fman_dtsec_set_stat_level(p_Dtsec->p_MemMap,
++                                        (enum dtsec_stat_level)statisticsLevel);
++    if (err != E_OK)
++        return err;
++
++    switch (statisticsLevel)
++    {
++    case (e_FM_MAC_NONE_STATISTICS):
++            p_Dtsec->exceptions &= ~DTSEC_IMASK_MSROEN;
++            break;
++    case (e_FM_MAC_PARTIAL_STATISTICS):
++            p_Dtsec->exceptions |= DTSEC_IMASK_MSROEN;
++            break;
++    case (e_FM_MAC_FULL_STATISTICS):
++            p_Dtsec->exceptions |= DTSEC_IMASK_MSROEN;
++            break;
++        default:
++            RETURN_ERROR(MINOR, E_INVALID_SELECTION, NO_MSG);
++    }
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecSetWakeOnLan(t_Handle h_Dtsec, bool en)
++{
++    t_Dtsec         *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    fman_dtsec_set_wol(p_Dtsec->p_MemMap, en);
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecAdjustLink(t_Handle h_Dtsec, e_EnetSpeed speed, bool fullDuplex)
++{
++    t_Dtsec             *p_Dtsec = (t_Dtsec *)h_Dtsec;
++    int                 err;
++    enum enet_interface enet_interface;
++    enum enet_speed     enet_speed;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    p_Dtsec->enetMode = MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode), speed);
++    enet_interface = (enum enet_interface) ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode);
++    enet_speed = (enum enet_speed) ENET_SPEED_FROM_MODE(p_Dtsec->enetMode);
++    p_Dtsec->halfDuplex = !fullDuplex;
++
++    err = fman_dtsec_adjust_link(p_Dtsec->p_MemMap, enet_interface, enet_speed, fullDuplex);
++
++    if (err == -EINVAL)
++        RETURN_ERROR(MAJOR, E_CONFLICT, ("Ethernet interface does not support Half Duplex mode"));
++
++    return (t_Error)err;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecRestartAutoneg(t_Handle h_Dtsec)
++{
++    t_Dtsec      *p_Dtsec = (t_Dtsec *)h_Dtsec;
++    uint16_t     tmpReg16;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    DTSEC_MII_ReadPhyReg(p_Dtsec, p_Dtsec->tbi_phy_addr, 0, &tmpReg16);
++
++    tmpReg16 &= ~( PHY_CR_SPEED0 | PHY_CR_SPEED1 );
++    tmpReg16 |= (PHY_CR_ANE | PHY_CR_RESET_AN | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1);
++
++    DTSEC_MII_WritePhyReg(p_Dtsec, p_Dtsec->tbi_phy_addr, 0, tmpReg16);
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecGetId(t_Handle h_Dtsec, uint32_t *macId)
++{
++    t_Dtsec     *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    *macId = p_Dtsec->macId;
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecGetVersion(t_Handle h_Dtsec, uint32_t *macVersion)
++{
++    t_Dtsec     *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    *macVersion = fman_dtsec_get_revision(p_Dtsec->p_MemMap);
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error DtsecSetException(t_Handle h_Dtsec, e_FmMacExceptions exception, bool enable)
++{
++    t_Dtsec     *p_Dtsec = (t_Dtsec *)h_Dtsec;
++    uint32_t    bitMask = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++
++    if (exception != e_FM_MAC_EX_1G_1588_TS_RX_ERR)
++    {
++        GET_EXCEPTION_FLAG(bitMask, exception);
++        if (bitMask)
++        {
++            if (enable)
++                p_Dtsec->exceptions |= bitMask;
++            else
++                p_Dtsec->exceptions &= ~bitMask;
++        }
++        else
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
++
++        if (enable)
++            fman_dtsec_enable_interrupt(p_Dtsec->p_MemMap, bitMask);
++        else
++            fman_dtsec_disable_interrupt(p_Dtsec->p_MemMap, bitMask);
++    }
++    else
++    {
++        if (!p_Dtsec->ptpTsuEnabled)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exception valid for 1588 only"));
++
++        if (enable)
++        {
++            p_Dtsec->enTsuErrExeption = TRUE;
++            fman_dtsec_enable_tmr_interrupt(p_Dtsec->p_MemMap);
++        }
++        else
++        {
++            p_Dtsec->enTsuErrExeption = FALSE;
++            fman_dtsec_disable_tmr_interrupt(p_Dtsec->p_MemMap);
++        }
++    }
++
++    return E_OK;
++}
++
++
++/*****************************************************************************/
++/*                      dTSEC Init & Free API                                   */
++/*****************************************************************************/
++
++/* .............................................................................. */
++
++static t_Error DtsecInit(t_Handle h_Dtsec)
++{
++    t_Dtsec             *p_Dtsec = (t_Dtsec *)h_Dtsec;
++    struct dtsec_cfg    *p_DtsecDriverParam;
++    t_Error             err;
++    uint16_t            maxFrmLn;
++    enum enet_interface enet_interface;
++    enum enet_speed     enet_speed;
++    t_EnetAddr          ethAddr;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec->fmMacControllerDriver.h_Fm, E_INVALID_HANDLE);
++
++    FM_GetRevision(p_Dtsec->fmMacControllerDriver.h_Fm, &p_Dtsec->fmMacControllerDriver.fmRevInfo);
++    CHECK_INIT_PARAMETERS(p_Dtsec, CheckInitParameters);
++
++    p_DtsecDriverParam  = p_Dtsec->p_DtsecDriverParam;
++    p_Dtsec->halfDuplex = p_DtsecDriverParam->halfdup_on;
++
++    enet_interface = (enum enet_interface)ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode);
++    enet_speed = (enum enet_speed)ENET_SPEED_FROM_MODE(p_Dtsec->enetMode);
++    MAKE_ENET_ADDR_FROM_UINT64(p_Dtsec->addr, ethAddr);
++
++    err = (t_Error)fman_dtsec_init(p_Dtsec->p_MemMap,
++                              p_DtsecDriverParam,
++                              enet_interface,
++                              enet_speed,
++                              (uint8_t*)ethAddr,
++                              p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev,
++                              p_Dtsec->fmMacControllerDriver.fmRevInfo.minorRev,
++                              p_Dtsec->exceptions);
++    if (err)
++    {
++        FreeInitResources(p_Dtsec);
++        RETURN_ERROR(MAJOR, err, ("This DTSEC version does not support the required i/f mode"));
++    }
++
++    if (ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode) == e_ENET_IF_SGMII)
++    {
++        uint16_t            tmpReg16;
++
++        /* Configure the TBI PHY Control Register */
++        tmpReg16 = PHY_TBICON_CLK_SEL | PHY_TBICON_SRESET;
++        DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 17, tmpReg16);
++
++        tmpReg16 = PHY_TBICON_CLK_SEL;
++        DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 17, tmpReg16);
++
++        tmpReg16 = (PHY_CR_PHY_RESET | PHY_CR_ANE | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1);
++        DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 0, tmpReg16);
++
++        if (p_Dtsec->enetMode & ENET_IF_SGMII_BASEX)
++            tmpReg16 = PHY_TBIANA_1000X;
++        else
++            tmpReg16 = PHY_TBIANA_SGMII;
++        DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 4, tmpReg16);
++
++        tmpReg16 = (PHY_CR_ANE | PHY_CR_RESET_AN | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1);
++
++        DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 0, tmpReg16);
++    }
++
++    /* Max Frame Length */
++    maxFrmLn = fman_dtsec_get_max_frame_len(p_Dtsec->p_MemMap);
++    err = FmSetMacMaxFrame(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MAC_1G,
++            p_Dtsec->fmMacControllerDriver.macId, maxFrmLn);
++    if (err)
++        RETURN_ERROR(MINOR,err, NO_MSG);
++
++    p_Dtsec->p_MulticastAddrHash = AllocHashTable(EXTENDED_HASH_TABLE_SIZE);
++    if (!p_Dtsec->p_MulticastAddrHash) {
++        FreeInitResources(p_Dtsec);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MC hash table is FAILED"));
++    }
++
++    p_Dtsec->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE);
++    if (!p_Dtsec->p_UnicastAddrHash)
++    {
++        FreeInitResources(p_Dtsec);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("UC hash table is FAILED"));
++    }
++
++    /* register err intr handler for dtsec to FPM (err)*/
++    FmRegisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm,
++                   e_FM_MOD_1G_MAC,
++                   p_Dtsec->macId,
++                   e_FM_INTR_TYPE_ERR,
++                   DtsecIsr,
++                   p_Dtsec);
++    /* register 1588 intr handler for TMR to FPM (normal)*/
++    FmRegisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm,
++                   e_FM_MOD_1G_MAC,
++                   p_Dtsec->macId,
++                   e_FM_INTR_TYPE_NORMAL,
++                   Dtsec1588Isr,
++                   p_Dtsec);
++    /* register normal intr handler for dtsec to main interrupt controller. */
++    if (p_Dtsec->mdioIrq != NO_IRQ)
++    {
++        XX_SetIntr(p_Dtsec->mdioIrq, DtsecMdioIsr, p_Dtsec);
++        XX_EnableIntr(p_Dtsec->mdioIrq);
++    }
++
++    XX_Free(p_DtsecDriverParam);
++    p_Dtsec->p_DtsecDriverParam = NULL;
++
++    err = DtsecSetStatistics(h_Dtsec, e_FM_MAC_FULL_STATISTICS);
++    if (err)
++    {
++        FreeInitResources(p_Dtsec);
++        RETURN_ERROR(MAJOR, err, ("Undefined statistics level"));
++    }
++
++    return E_OK;
++}
++
++/* ........................................................................... */
++
++static t_Error DtsecFree(t_Handle h_Dtsec)
++{
++    t_Dtsec      *p_Dtsec = (t_Dtsec *)h_Dtsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++
++    if (p_Dtsec->p_DtsecDriverParam)
++    {
++        /* Called after config */
++        XX_Free(p_Dtsec->p_DtsecDriverParam);
++        p_Dtsec->p_DtsecDriverParam = NULL;
++    }
++    else
++        /* Called after init */
++        FreeInitResources(p_Dtsec);
++
++    XX_Free(p_Dtsec);
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver)
++{
++    p_FmMacControllerDriver->f_FM_MAC_Init                      = DtsecInit;
++    p_FmMacControllerDriver->f_FM_MAC_Free                      = DtsecFree;
++
++    p_FmMacControllerDriver->f_FM_MAC_SetStatistics             = DtsecSetStatistics;
++    p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback            = DtsecConfigLoopback;
++    p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength      = DtsecConfigMaxFrameLength;
++
++    p_FmMacControllerDriver->f_FM_MAC_ConfigWan                 = NULL; /* Not supported on dTSEC */
++
++    p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc           = DtsecConfigPadAndCrc;
++    p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex          = DtsecConfigHalfDuplex;
++    p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck         = DtsecConfigLengthCheck;
++    p_FmMacControllerDriver->f_FM_MAC_ConfigTbiPhyAddr          = DtsecConfigTbiPhyAddr;
++    p_FmMacControllerDriver->f_FM_MAC_ConfigException           = DtsecConfigException;
++    p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit         = NULL;
++
++    p_FmMacControllerDriver->f_FM_MAC_Enable                    = DtsecEnable;
++    p_FmMacControllerDriver->f_FM_MAC_Disable                   = DtsecDisable;
++    p_FmMacControllerDriver->f_FM_MAC_Resume                    = NULL;
++
++    p_FmMacControllerDriver->f_FM_MAC_SetException              = DtsecSetException;
++
++    p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous            = DtsecSetPromiscuous;
++    p_FmMacControllerDriver->f_FM_MAC_AdjustLink                = DtsecAdjustLink;
++    p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan              = DtsecSetWakeOnLan;
++    p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg            = DtsecRestartAutoneg;
++
++    p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp       = DtsecEnable1588TimeStamp;
++    p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp      = DtsecDisable1588TimeStamp;
++
++    p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames      = DtsecTxMacPause;
++    p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames          = DtsecSetTxPauseFrames;
++    p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames    = DtsecRxIgnoreMacPause;
++
++    p_FmMacControllerDriver->f_FM_MAC_ResetCounters             = DtsecResetCounters;
++    p_FmMacControllerDriver->f_FM_MAC_GetStatistics             = DtsecGetStatistics;
++
++    p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr             = DtsecModifyMacAddress;
++    p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr            = DtsecAddHashMacAddress;
++    p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr         = DtsecDelHashMacAddress;
++    p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr      = DtsecAddExactMatchMacAddress;
++    p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr  = DtsecDelExactMatchMacAddress;
++    p_FmMacControllerDriver->f_FM_MAC_GetId                     = DtsecGetId;
++    p_FmMacControllerDriver->f_FM_MAC_GetVersion                = DtsecGetVersion;
++    p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength         = DtsecGetMaxFrameLength;
++
++    p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg           = DTSEC_MII_WritePhyReg;
++    p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg            = DTSEC_MII_ReadPhyReg;
++
++}
++
++
++/*****************************************************************************/
++/*                      dTSEC Config Main Entry                             */
++/*****************************************************************************/
++
++/* .............................................................................. */
++
++t_Handle  DTSEC_Config(t_FmMacParams *p_FmMacParam)
++{
++    t_Dtsec             *p_Dtsec;
++    struct dtsec_cfg    *p_DtsecDriverParam;
++    uintptr_t           baseAddr;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL);
++
++    baseAddr = p_FmMacParam->baseAddr;
++
++    /* allocate memory for the UCC GETH data structure. */
++    p_Dtsec = (t_Dtsec *)XX_Malloc(sizeof(t_Dtsec));
++    if (!p_Dtsec)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("dTSEC driver structure"));
++        return NULL;
++    }
++    memset(p_Dtsec, 0, sizeof(t_Dtsec));
++    InitFmMacControllerDriver(&p_Dtsec->fmMacControllerDriver);
++
++    /* allocate memory for the dTSEC driver parameters data structure. */
++    p_DtsecDriverParam = (struct dtsec_cfg *) XX_Malloc(sizeof(struct dtsec_cfg));
++    if (!p_DtsecDriverParam)
++    {
++        XX_Free(p_Dtsec);
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("dTSEC driver parameters"));
++        return NULL;
++    }
++    memset(p_DtsecDriverParam, 0, sizeof(struct dtsec_cfg));
++
++    /* Plant parameter structure pointer */
++    p_Dtsec->p_DtsecDriverParam = p_DtsecDriverParam;
++
++    fman_dtsec_defconfig(p_DtsecDriverParam);
++
++    p_Dtsec->p_MemMap           = (struct dtsec_regs *)UINT_TO_PTR(baseAddr);
++    p_Dtsec->p_MiiMemMap        = (struct dtsec_mii_reg *)UINT_TO_PTR(baseAddr + DTSEC_TO_MII_OFFSET);
++    p_Dtsec->addr               = ENET_ADDR_TO_UINT64(p_FmMacParam->addr);
++    p_Dtsec->enetMode           = p_FmMacParam->enetMode;
++    p_Dtsec->macId              = p_FmMacParam->macId;
++    p_Dtsec->exceptions         = DEFAULT_exceptions;
++    p_Dtsec->mdioIrq            = p_FmMacParam->mdioIrq;
++    p_Dtsec->f_Exception        = p_FmMacParam->f_Exception;
++    p_Dtsec->f_Event            = p_FmMacParam->f_Event;
++    p_Dtsec->h_App              = p_FmMacParam->h_App;
++    p_Dtsec->ptpTsuEnabled      = p_Dtsec->p_DtsecDriverParam->ptp_tsu_en;
++    p_Dtsec->enTsuErrExeption   = p_Dtsec->p_DtsecDriverParam->ptp_exception_en;
++    p_Dtsec->tbi_phy_addr       = p_Dtsec->p_DtsecDriverParam->tbi_phy_addr;
++
++    return p_Dtsec;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.h
+@@ -0,0 +1,228 @@
++/*
++ * Copyright 2008-2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/******************************************************************************
++ @File          dtsec.h
++
++ @Description   FM dTSEC ...
++*//***************************************************************************/
++#ifndef __DTSEC_H
++#define __DTSEC_H
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "list_ext.h"
++#include "enet_ext.h"
++
++#include "dtsec_mii_acc.h"
++#include "fm_mac.h"
++
++
++#define DEFAULT_exceptions            \
++    ((uint32_t)(DTSEC_IMASK_BREN    | \
++                DTSEC_IMASK_RXCEN   | \
++                DTSEC_IMASK_BTEN    | \
++                DTSEC_IMASK_TXCEN   | \
++                DTSEC_IMASK_TXEEN   | \
++                DTSEC_IMASK_ABRTEN  | \
++                DTSEC_IMASK_LCEN    | \
++                DTSEC_IMASK_CRLEN   | \
++                DTSEC_IMASK_XFUNEN  | \
++                DTSEC_IMASK_IFERREN | \
++                DTSEC_IMASK_MAGEN   | \
++                DTSEC_IMASK_TDPEEN  | \
++                DTSEC_IMASK_RDPEEN))
++
++#define GET_EXCEPTION_FLAG(bitMask, exception)  switch (exception){ \
++    case e_FM_MAC_EX_1G_BAB_RX:                                     \
++        bitMask = DTSEC_IMASK_BREN; break;                          \
++    case e_FM_MAC_EX_1G_RX_CTL:                                     \
++        bitMask = DTSEC_IMASK_RXCEN; break;                         \
++    case e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET:                    \
++        bitMask = DTSEC_IMASK_GTSCEN ; break;                       \
++    case e_FM_MAC_EX_1G_BAB_TX:                                     \
++        bitMask = DTSEC_IMASK_BTEN   ; break;                       \
++    case e_FM_MAC_EX_1G_TX_CTL:                                     \
++        bitMask = DTSEC_IMASK_TXCEN  ; break;                       \
++    case e_FM_MAC_EX_1G_TX_ERR:                                     \
++        bitMask = DTSEC_IMASK_TXEEN  ; break;                       \
++    case e_FM_MAC_EX_1G_LATE_COL:                                   \
++        bitMask = DTSEC_IMASK_LCEN   ; break;                       \
++    case e_FM_MAC_EX_1G_COL_RET_LMT:                                \
++        bitMask = DTSEC_IMASK_CRLEN  ; break;                       \
++    case e_FM_MAC_EX_1G_TX_FIFO_UNDRN:                              \
++        bitMask = DTSEC_IMASK_XFUNEN ; break;                       \
++    case e_FM_MAC_EX_1G_MAG_PCKT:                                   \
++        bitMask = DTSEC_IMASK_MAGEN ; break;                        \
++    case e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET:                         \
++        bitMask = DTSEC_IMASK_MMRDEN; break;                        \
++    case e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET:                         \
++        bitMask = DTSEC_IMASK_MMWREN  ; break;                      \
++    case e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET:                    \
++        bitMask = DTSEC_IMASK_GRSCEN; break;                        \
++    case e_FM_MAC_EX_1G_TX_DATA_ERR:                                \
++        bitMask = DTSEC_IMASK_TDPEEN; break;                        \
++    case e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL:                            \
++        bitMask = DTSEC_IMASK_MSROEN ; break;                       \
++    default: bitMask = 0;break;}
++
++
++#define MAX_PACKET_ALIGNMENT        31
++#define MAX_INTER_PACKET_GAP        0x7f
++#define MAX_INTER_PALTERNATE_BEB    0x0f
++#define MAX_RETRANSMISSION          0x0f
++#define MAX_COLLISION_WINDOW        0x03ff
++
++
++/********************* From mac ext ******************************************/
++typedef  uint32_t t_ErrorDisable;
++
++#define ERROR_DISABLE_TRANSMIT              0x00400000
++#define ERROR_DISABLE_LATE_COLLISION        0x00040000
++#define ERROR_DISABLE_COLLISION_RETRY_LIMIT 0x00020000
++#define ERROR_DISABLE_TxFIFO_UNDERRUN       0x00010000
++#define ERROR_DISABLE_TxABORT               0x00008000
++#define ERROR_DISABLE_INTERFACE             0x00004000
++#define ERROR_DISABLE_TxDATA_PARITY         0x00000002
++#define ERROR_DISABLE_RxDATA_PARITY         0x00000001
++
++/*****************************************************************************/
++#define DTSEC_NUM_OF_PADDRS             15  /* number of pattern match registers (entries) */
++
++#define GROUP_ADDRESS                   0x0000010000000000LL /* Group address bit indication */
++
++#define HASH_TABLE_SIZE                 256 /* Hash table size (= 32 bits * 8 regs) */
++
++#define HASH_TABLE_SIZE                 256 /* Hash table size (32 bits * 8 regs) */
++#define EXTENDED_HASH_TABLE_SIZE        512 /* Extended Hash table size (32 bits * 16 regs) */
++
++#define DTSEC_TO_MII_OFFSET             0x1000  /* number of pattern match registers (entries) */
++
++#define MAX_PHYS                    32 /* maximum number of phys */
++
++#define     VAL32BIT    0x100000000LL
++#define     VAL22BIT    0x00400000
++#define     VAL16BIT    0x00010000
++#define     VAL12BIT    0x00001000
++
++/* CAR1/2 bits */
++#define CAR1_TR64   0x80000000
++#define CAR1_TR127  0x40000000
++#define CAR1_TR255  0x20000000
++#define CAR1_TR511  0x10000000
++#define CAR1_TRK1   0x08000000
++#define CAR1_TRMAX  0x04000000
++#define CAR1_TRMGV  0x02000000
++
++#define CAR1_RBYT   0x00010000
++#define CAR1_RPKT   0x00008000
++#define CAR1_RMCA   0x00002000
++#define CAR1_RBCA   0x00001000
++#define CAR1_RXPF   0x00000400
++#define CAR1_RALN   0x00000100
++#define CAR1_RFLR   0x00000080
++#define CAR1_RCDE   0x00000040
++#define CAR1_RCSE   0x00000020
++#define CAR1_RUND   0x00000010
++#define CAR1_ROVR   0x00000008
++#define CAR1_RFRG   0x00000004
++#define CAR1_RJBR   0x00000002
++#define CAR1_RDRP   0x00000001
++
++#define CAR2_TFCS   0x00040000
++#define CAR2_TBYT   0x00002000
++#define CAR2_TPKT   0x00001000
++#define CAR2_TMCA   0x00000800
++#define CAR2_TBCA   0x00000400
++#define CAR2_TXPF   0x00000200
++#define CAR2_TDRP   0x00000001
++
++typedef struct t_InternalStatistics
++{
++    uint64_t    tr64;
++    uint64_t    tr127;
++    uint64_t    tr255;
++    uint64_t    tr511;
++    uint64_t    tr1k;
++    uint64_t    trmax;
++    uint64_t    trmgv;
++    uint64_t    rfrg;
++    uint64_t    rjbr;
++    uint64_t    rdrp;
++    uint64_t    raln;
++    uint64_t    rund;
++    uint64_t    rovr;
++    uint64_t    rxpf;
++    uint64_t    txpf;
++    uint64_t    rbyt;
++    uint64_t    rpkt;
++    uint64_t    rmca;
++    uint64_t    rbca;
++    uint64_t    rflr;
++    uint64_t    rcde;
++    uint64_t    rcse;
++    uint64_t    tbyt;
++    uint64_t    tpkt;
++    uint64_t    tmca;
++    uint64_t    tbca;
++    uint64_t    tdrp;
++    uint64_t    tfcs;
++} t_InternalStatistics;
++
++typedef struct {
++    t_FmMacControllerDriver     fmMacControllerDriver;
++    t_Handle                    h_App;            /**< Handle to the upper layer application              */
++    struct dtsec_regs           *p_MemMap;        /**< pointer to dTSEC memory mapped registers.          */
++    struct dtsec_mii_reg        *p_MiiMemMap;     /**< pointer to dTSEC MII memory mapped registers.          */
++    uint64_t                    addr;             /**< MAC address of device;                             */
++    e_EnetMode                  enetMode;         /**< Ethernet physical interface  */
++    t_FmMacExceptionCallback    *f_Exception;
++    int                         mdioIrq;
++    t_FmMacExceptionCallback    *f_Event;
++    bool                        indAddrRegUsed[DTSEC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */
++    uint64_t                    paddr[DTSEC_NUM_OF_PADDRS]; /**< MAC address for particular individual address recognition register */
++    uint8_t                     numOfIndAddrInRegs; /**< Number of individual addresses in registers for this station. */
++    bool                        halfDuplex;
++    t_InternalStatistics        internalStatistics;
++    t_EthHash                   *p_MulticastAddrHash;      /* pointer to driver's global address hash table  */
++    t_EthHash                   *p_UnicastAddrHash;    /* pointer to driver's individual address hash table  */
++    uint8_t                     macId;
++    uint8_t                     tbi_phy_addr;
++    uint32_t                    exceptions;
++    bool                        ptpTsuEnabled;
++    bool                        enTsuErrExeption;
++    e_FmMacStatisticsLevel      statisticsLevel;
++    struct dtsec_cfg            *p_DtsecDriverParam;
++} t_Dtsec;
++
++
++#endif /* __DTSEC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.c
+@@ -0,0 +1,97 @@
++/*
++ * Copyright 2008-2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          dtsec_mii_acc.c
++
++ @Description   FM dtsec MII register access MAC ...
++*//***************************************************************************/
++
++#include "error_ext.h"
++#include "std_ext.h"
++#include "fm_mac.h"
++#include "dtsec.h"
++#include "fsl_fman_dtsec_mii_acc.h"
++
++
++/*****************************************************************************/
++t_Error DTSEC_MII_WritePhyReg(t_Handle    h_Dtsec,
++                              uint8_t     phyAddr,
++                              uint8_t     reg,
++                              uint16_t    data)
++{
++    t_Dtsec              *p_Dtsec = (t_Dtsec *)h_Dtsec;
++    struct dtsec_mii_reg *miiregs;
++    uint16_t              dtsec_freq;
++    t_Error                   err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MiiMemMap, E_INVALID_HANDLE);
++
++    dtsec_freq = (uint16_t)(p_Dtsec->fmMacControllerDriver.clkFreq >> 1);
++    miiregs = p_Dtsec->p_MiiMemMap;
++
++    err = (t_Error)fman_dtsec_mii_write_reg(miiregs, phyAddr, reg, data, dtsec_freq);
++
++    return err;
++}
++
++/*****************************************************************************/
++t_Error DTSEC_MII_ReadPhyReg(t_Handle h_Dtsec,
++                             uint8_t  phyAddr,
++                             uint8_t  reg,
++                             uint16_t *p_Data)
++{
++    t_Dtsec               *p_Dtsec = (t_Dtsec *)h_Dtsec;
++    struct dtsec_mii_reg  *miiregs;
++    uint16_t               dtsec_freq;
++    t_Error                    err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MiiMemMap, E_INVALID_HANDLE);
++
++    dtsec_freq = (uint16_t)(p_Dtsec->fmMacControllerDriver.clkFreq >> 1);
++    miiregs = p_Dtsec->p_MiiMemMap;
++
++    err = fman_dtsec_mii_read_reg(miiregs, phyAddr, reg, p_Data, dtsec_freq);
++
++    if (*p_Data == 0xffff)
++        RETURN_ERROR(MINOR, E_NO_DEVICE,
++                     ("Read wrong data (0xffff): phyAddr 0x%x, reg 0x%x",
++                      phyAddr, reg));
++    if (err)
++        RETURN_ERROR(MINOR, (t_Error)err, NO_MSG);
++
++    return E_OK;
++}
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.h
+@@ -0,0 +1,42 @@
++/*
++ * Copyright 2008-2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __DTSEC_MII_ACC_H
++#define __DTSEC_MII_ACC_H
++
++#include "std_ext.h"
++
++
++t_Error DTSEC_MII_WritePhyReg(t_Handle h_Dtsec, uint8_t phyAddr, uint8_t reg, uint16_t data);
++t_Error DTSEC_MII_ReadPhyReg(t_Handle  h_Dtsec, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data);
++
++#endif /* __DTSEC_MII_ACC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c
+@@ -0,0 +1,658 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_mac.c
++
++ @Description   FM MAC ...
++*//***************************************************************************/
++#include "std_ext.h"
++#include "string_ext.h"
++#include "sprint_ext.h"
++#include "error_ext.h"
++#include "fm_ext.h"
++
++#include "fm_common.h"
++#include "fm_mac.h"
++
++
++/* ......................................................................... */
++
++t_Handle FM_MAC_Config (t_FmMacParams *p_FmMacParam)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver;
++    uint16_t                fmClkFreq;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_INVALID_HANDLE, NULL);
++
++    fmClkFreq = FmGetClockFreq(p_FmMacParam->h_Fm);
++    if (fmClkFreq == 0)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Can't get clock for MAC!"));
++        return NULL;
++    }
++
++#if (DPAA_VERSION == 10)
++    if (ENET_SPEED_FROM_MODE(p_FmMacParam->enetMode) < e_ENET_SPEED_10000)
++        p_FmMacControllerDriver = (t_FmMacControllerDriver *)DTSEC_Config(p_FmMacParam);
++    else
++#if FM_MAX_NUM_OF_10G_MACS > 0
++        p_FmMacControllerDriver = (t_FmMacControllerDriver *)TGEC_Config(p_FmMacParam);
++#else
++        p_FmMacControllerDriver = NULL;
++#endif /* FM_MAX_NUM_OF_10G_MACS > 0 */
++#else
++    p_FmMacControllerDriver = (t_FmMacControllerDriver *)MEMAC_Config(p_FmMacParam);
++#endif /* (DPAA_VERSION == 10) */
++
++    if (!p_FmMacControllerDriver)
++        return NULL;
++
++    p_FmMacControllerDriver->h_Fm           = p_FmMacParam->h_Fm;
++    p_FmMacControllerDriver->enetMode       = p_FmMacParam->enetMode;
++    p_FmMacControllerDriver->macId          = p_FmMacParam->macId;
++    p_FmMacControllerDriver->resetOnInit    = DEFAULT_resetOnInit;
++
++    p_FmMacControllerDriver->clkFreq        = fmClkFreq;
++
++    return (t_Handle)p_FmMacControllerDriver;
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_Init (t_Handle h_FmMac)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->resetOnInit &&
++        !p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit &&
++        (FmResetMac(p_FmMacControllerDriver->h_Fm,
++                    ((ENET_INTERFACE_FROM_MODE(p_FmMacControllerDriver->enetMode) == e_ENET_IF_XGMII) ?
++                        e_FM_MAC_10G : e_FM_MAC_1G),
++                    p_FmMacControllerDriver->macId) != E_OK))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't reset MAC!"));
++
++    if (p_FmMacControllerDriver->f_FM_MAC_Init)
++        return p_FmMacControllerDriver->f_FM_MAC_Init(h_FmMac);
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_Free (t_Handle h_FmMac)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_Free)
++        return p_FmMacControllerDriver->f_FM_MAC_Free(h_FmMac);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_ConfigResetOnInit (t_Handle h_FmMac, bool enable)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit)
++        return p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit(h_FmMac, enable);
++
++    p_FmMacControllerDriver->resetOnInit = enable;
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_ConfigLoopback (t_Handle h_FmMac, bool newVal)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback)
++        return p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback(h_FmMac, newVal);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_ConfigMaxFrameLength (t_Handle h_FmMac, uint16_t newVal)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength)
++        return p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength(h_FmMac, newVal);
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_ConfigWan (t_Handle h_FmMac, bool flag)
++{
++   t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_ConfigWan)
++        return p_FmMacControllerDriver->f_FM_MAC_ConfigWan(h_FmMac, flag);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_ConfigPadAndCrc (t_Handle h_FmMac, bool newVal)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc)
++        return p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc(h_FmMac, newVal);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_ConfigHalfDuplex (t_Handle h_FmMac, bool newVal)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex)
++        return p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex(h_FmMac,newVal);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_ConfigTbiPhyAddr (t_Handle h_FmMac, uint8_t newVal)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_ConfigTbiPhyAddr)
++        return p_FmMacControllerDriver->f_FM_MAC_ConfigTbiPhyAddr(h_FmMac,newVal);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_ConfigLengthCheck (t_Handle h_FmMac, bool newVal)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck)
++        return p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck(h_FmMac,newVal);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_ConfigException (t_Handle h_FmMac, e_FmMacExceptions ex, bool enable)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_ConfigException)
++        return p_FmMacControllerDriver->f_FM_MAC_ConfigException(h_FmMac, ex, enable);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
++/* ......................................................................... */
++
++t_Error FM_MAC_ConfigSkipFman11Workaround (t_Handle h_FmMac)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround)
++        return p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround(h_FmMac);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
++
++
++/*****************************************************************************/
++/* Run Time Control                                                          */
++/*****************************************************************************/
++
++/* ......................................................................... */
++
++t_Error FM_MAC_Enable  (t_Handle h_FmMac,  e_CommMode mode)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_Enable)
++        return p_FmMacControllerDriver->f_FM_MAC_Enable(h_FmMac, mode);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_Disable (t_Handle h_FmMac, e_CommMode mode)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_Disable)
++        return p_FmMacControllerDriver->f_FM_MAC_Disable(h_FmMac, mode);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MAC_Resume (t_Handle h_FmMac)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_Resume)
++        return p_FmMacControllerDriver->f_FM_MAC_Resume(h_FmMac);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_Enable1588TimeStamp (t_Handle h_FmMac)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp)
++        return p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp(h_FmMac);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_Disable1588TimeStamp (t_Handle h_FmMac)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp)
++        return p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp(h_FmMac);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_SetTxAutoPauseFrames(t_Handle h_FmMac,
++                                    uint16_t pauseTime)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames)
++        return p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames(h_FmMac,
++                                                                      pauseTime);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_SetTxPauseFrames(t_Handle h_FmMac,
++                                uint8_t  priority,
++                                uint16_t pauseTime,
++                                uint16_t threshTime)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames)
++        return p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames(h_FmMac,
++                                                                  priority,
++                                                                  pauseTime,
++                                                                  threshTime);
++
++    RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_SetRxIgnorePauseFrames (t_Handle h_FmMac, bool en)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames)
++        return p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames(h_FmMac, en);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_SetWakeOnLan (t_Handle h_FmMac, bool en)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan)
++        return p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan(h_FmMac, en);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_ResetCounters (t_Handle h_FmMac)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_ResetCounters)
++        return p_FmMacControllerDriver->f_FM_MAC_ResetCounters(h_FmMac);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_SetException(t_Handle h_FmMac, e_FmMacExceptions ex, bool enable)
++{
++   t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_SetException)
++        return p_FmMacControllerDriver->f_FM_MAC_SetException(h_FmMac, ex, enable);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_SetStatistics (t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_SetStatistics)
++        return p_FmMacControllerDriver->f_FM_MAC_SetStatistics(h_FmMac, statisticsLevel);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_GetStatistics (t_Handle h_FmMac, t_FmMacStatistics *p_Statistics)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_GetStatistics)
++        return p_FmMacControllerDriver->f_FM_MAC_GetStatistics(h_FmMac, p_Statistics);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_ModifyMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr)
++        return p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr(h_FmMac, p_EnetAddr);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_AddHashMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr)
++        return p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr(h_FmMac, p_EnetAddr);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_RemoveHashMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr)
++        return p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr(h_FmMac, p_EnetAddr);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_AddExactMatchMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr)
++        return p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr(h_FmMac, p_EnetAddr);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_RemovelExactMatchMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr)
++        return p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr(h_FmMac, p_EnetAddr);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_GetVesrion (t_Handle h_FmMac, uint32_t *macVresion)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_GetVersion)
++        return p_FmMacControllerDriver->f_FM_MAC_GetVersion(h_FmMac, macVresion);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_GetId (t_Handle h_FmMac, uint32_t *macId)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_GetId)
++        return p_FmMacControllerDriver->f_FM_MAC_GetId(h_FmMac, macId);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_SetPromiscuous (t_Handle h_FmMac, bool newVal)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous)
++        return p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous(h_FmMac, newVal);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_AdjustLink(t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_AdjustLink)
++        return p_FmMacControllerDriver->f_FM_MAC_AdjustLink(h_FmMac, speed, fullDuplex);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_RestartAutoneg(t_Handle h_FmMac)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg)
++        return p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg(h_FmMac);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_MII_WritePhyReg (t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg)
++        return p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg(h_FmMac, phyAddr, reg, data);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++t_Error FM_MAC_MII_ReadPhyReg(t_Handle h_FmMac,  uint8_t phyAddr, uint8_t reg, uint16_t *p_Data)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg)
++        return p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg(h_FmMac, phyAddr, reg, p_Data);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
++uint16_t FM_MAC_GetMaxFrameLength(t_Handle h_FmMac)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmMacControllerDriver, E_INVALID_HANDLE, 0);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength)
++        return p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength(h_FmMac);
++
++    REPORT_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++    return 0;
++}
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++/*****************************************************************************/
++t_Error FM_MAC_DumpRegs(t_Handle h_FmMac)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacControllerDriver->f_FM_MAC_DumpRegs)
++         return p_FmMacControllerDriver->f_FM_MAC_DumpRegs(h_FmMac);
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++#endif /* (defined(DEBUG_ERRORS) && ... */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h
+@@ -0,0 +1,225 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_mac.h
++
++ @Description   FM MAC ...
++*//***************************************************************************/
++#ifndef __FM_MAC_H
++#define __FM_MAC_H
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "list_ext.h"
++#include "fm_mac_ext.h"
++#include "fm_common.h"
++
++
++#define __ERR_MODULE__  MODULE_FM_MAC
++
++/**************************************************************************//**
++ @Description       defaults
++*//***************************************************************************/
++
++
++#define DEFAULT_halfDuplex                  FALSE
++#define DEFAULT_padAndCrcEnable             TRUE
++#define DEFAULT_resetOnInit                 FALSE
++
++
++typedef struct {
++    uint64_t addr;      /* Ethernet Address  */
++    t_List   node;
++} t_EthHashEntry;
++#define ETH_HASH_ENTRY_OBJ(ptr) LIST_OBJECT(ptr, t_EthHashEntry, node)
++
++typedef struct {
++    uint16_t    size;
++    t_List      *p_Lsts;
++} t_EthHash;
++
++typedef struct {
++    t_Error (*f_FM_MAC_Init) (t_Handle h_FmMac);
++    t_Error (*f_FM_MAC_Free) (t_Handle h_FmMac);
++
++    t_Error (*f_FM_MAC_SetStatistics) (t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel);
++    t_Error (*f_FM_MAC_ConfigLoopback) (t_Handle h_FmMac, bool newVal);
++    t_Error (*f_FM_MAC_ConfigMaxFrameLength) (t_Handle h_FmMac, uint16_t newVal);
++    t_Error (*f_FM_MAC_ConfigWan) (t_Handle h_FmMac, bool flag);
++    t_Error (*f_FM_MAC_ConfigPadAndCrc) (t_Handle h_FmMac, bool newVal);
++    t_Error (*f_FM_MAC_ConfigHalfDuplex) (t_Handle h_FmMac, bool newVal);
++    t_Error (*f_FM_MAC_ConfigLengthCheck) (t_Handle h_FmMac, bool newVal);
++    t_Error (*f_FM_MAC_ConfigTbiPhyAddr) (t_Handle h_FmMac, uint8_t newVal);
++    t_Error (*f_FM_MAC_ConfigException) (t_Handle h_FmMac, e_FmMacExceptions, bool enable);
++    t_Error (*f_FM_MAC_ConfigResetOnInit) (t_Handle h_FmMac, bool enable);
++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
++    t_Error (*f_FM_MAC_ConfigSkipFman11Workaround) (t_Handle h_FmMac);
++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
++
++    t_Error (*f_FM_MAC_SetException) (t_Handle h_FmMac, e_FmMacExceptions ex, bool enable);
++
++    t_Error (*f_FM_MAC_Enable)  (t_Handle h_FmMac,  e_CommMode mode);
++    t_Error (*f_FM_MAC_Disable) (t_Handle h_FmMac, e_CommMode mode);
++    t_Error (*f_FM_MAC_Resume)  (t_Handle h_FmMac);
++    t_Error (*f_FM_MAC_Enable1588TimeStamp) (t_Handle h_FmMac);
++    t_Error (*f_FM_MAC_Disable1588TimeStamp) (t_Handle h_FmMac);
++    t_Error (*f_FM_MAC_Reset)   (t_Handle h_FmMac, bool wait);
++
++    t_Error (*f_FM_MAC_SetTxAutoPauseFrames) (t_Handle h_FmMac,
++                                              uint16_t pauseTime);
++    t_Error (*f_FM_MAC_SetTxPauseFrames) (t_Handle h_FmMac,
++                                          uint8_t  priority,
++                                          uint16_t pauseTime,
++                                          uint16_t threshTime);
++    t_Error (*f_FM_MAC_SetRxIgnorePauseFrames) (t_Handle h_FmMac, bool en);
++
++    t_Error (*f_FM_MAC_ResetCounters) (t_Handle h_FmMac);
++    t_Error (*f_FM_MAC_GetStatistics) (t_Handle h_FmMac, t_FmMacStatistics *p_Statistics);
++
++    t_Error (*f_FM_MAC_ModifyMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
++    t_Error (*f_FM_MAC_AddHashMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
++    t_Error (*f_FM_MAC_RemoveHashMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
++    t_Error (*f_FM_MAC_AddExactMatchMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
++    t_Error (*f_FM_MAC_RemovelExactMatchMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
++
++    t_Error (*f_FM_MAC_SetPromiscuous) (t_Handle h_FmMac, bool newVal);
++    t_Error (*f_FM_MAC_AdjustLink)     (t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex);
++    t_Error (*f_FM_MAC_RestartAutoneg) (t_Handle h_FmMac);
++
++    t_Error (*f_FM_MAC_SetWakeOnLan)   (t_Handle h_FmMac, bool en);
++
++    t_Error (*f_FM_MAC_GetId) (t_Handle h_FmMac, uint32_t *macId);
++
++    t_Error (*f_FM_MAC_GetVersion) (t_Handle h_FmMac, uint32_t *macVersion);
++
++    uint16_t (*f_FM_MAC_GetMaxFrameLength) (t_Handle h_FmMac);
++
++    t_Error (*f_FM_MAC_MII_WritePhyReg)(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data);
++    t_Error (*f_FM_MAC_MII_ReadPhyReg)(t_Handle h_FmMac,  uint8_t phyAddr, uint8_t reg, uint16_t *p_Data);
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++    t_Error (*f_FM_MAC_DumpRegs) (t_Handle h_FmMac);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++    t_Handle            h_Fm;
++    t_FmRevisionInfo    fmRevInfo;
++    e_EnetMode          enetMode;
++    uint8_t             macId;
++    bool                resetOnInit;
++    uint16_t            clkFreq;
++} t_FmMacControllerDriver;
++
++
++#if (DPAA_VERSION == 10)
++t_Handle    DTSEC_Config(t_FmMacParams *p_FmMacParam);
++t_Handle    TGEC_Config(t_FmMacParams *p_FmMacParams);
++#else
++t_Handle    MEMAC_Config(t_FmMacParams *p_FmMacParam);
++#endif /* (DPAA_VERSION == 10) */
++uint16_t    FM_MAC_GetMaxFrameLength(t_Handle FmMac);
++
++
++/* ........................................................................... */
++
++static __inline__ t_EthHashEntry *DequeueAddrFromHashEntry(t_List *p_AddrLst)
++{
++   t_EthHashEntry *p_HashEntry = NULL;
++    if (!LIST_IsEmpty(p_AddrLst))
++    {
++        p_HashEntry = ETH_HASH_ENTRY_OBJ(p_AddrLst->p_Next);
++        LIST_DelAndInit(&p_HashEntry->node);
++    }
++    return p_HashEntry;
++}
++
++/* ........................................................................... */
++
++static __inline__ void FreeHashTable(t_EthHash *p_Hash)
++{
++    t_EthHashEntry  *p_HashEntry;
++    int             i = 0;
++
++    if (p_Hash)
++    {
++        if  (p_Hash->p_Lsts)
++        {
++            for (i=0; i<p_Hash->size; i++)
++            {
++                p_HashEntry = DequeueAddrFromHashEntry(&p_Hash->p_Lsts[i]);
++                while (p_HashEntry)
++                {
++                    XX_Free(p_HashEntry);
++                    p_HashEntry = DequeueAddrFromHashEntry(&p_Hash->p_Lsts[i]);
++                }
++            }
++
++            XX_Free(p_Hash->p_Lsts);
++        }
++
++        XX_Free(p_Hash);
++    }
++}
++
++/* ........................................................................... */
++
++static __inline__ t_EthHash * AllocHashTable(uint16_t size)
++{
++    uint32_t    i;
++    t_EthHash *p_Hash;
++
++    /* Allocate address hash table */
++    p_Hash = (t_EthHash *)XX_Malloc(sizeof(t_EthHash));
++    if (!p_Hash)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Address hash table"));
++        return NULL;
++    }
++    p_Hash->size = size;
++
++    p_Hash->p_Lsts = (t_List *)XX_Malloc(p_Hash->size*sizeof(t_List));
++    if (!p_Hash->p_Lsts)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Address hash table"));
++        XX_Free(p_Hash);
++        return NULL;
++    }
++
++    for (i=0 ; i<p_Hash->size; i++)
++        INIT_LIST(&p_Hash->p_Lsts[i]);
++
++    return p_Hash;
++}
++
++
++#endif /* __FM_MAC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.c
+@@ -0,0 +1,119 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#include "fman_crc32.h"
++#include "common/general.h"
++
++
++/* precomputed CRC values for address hashing */
++static const uint32_t crc_tbl[256] = {
++      0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
++      0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
++      0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
++      0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
++      0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
++      0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
++      0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
++      0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
++      0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
++      0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
++      0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
++      0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
++      0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
++      0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
++      0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
++      0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
++      0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
++      0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
++      0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
++      0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
++      0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
++      0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
++      0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
++      0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
++      0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
++      0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
++      0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
++      0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
++      0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
++      0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
++      0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
++      0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
++      0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
++      0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
++      0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
++      0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
++      0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
++      0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
++      0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
++      0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
++      0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
++      0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
++      0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
++};
++
++/* Get the mirrored value of a byte size number. (0x11010011 --> 0x11001011) */
++static inline uint8_t get_mirror8(uint8_t n)
++{
++      uint8_t mirror[16] = {
++              0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e,
++              0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f
++      };
++      return (uint8_t)(((mirror[n & 0x0f] << 4) | (mirror[n >> 4])));
++}
++
++static inline uint32_t get_mirror32(uint32_t n)
++{
++      return ((uint32_t)get_mirror8((uint8_t)(n))<<24) |
++              ((uint32_t)get_mirror8((uint8_t)(n>>8))<<16) |
++              ((uint32_t)get_mirror8((uint8_t)(n>>16))<<8) |
++              ((uint32_t)get_mirror8((uint8_t)(n>>24)));
++}
++
++uint32_t get_mac_addr_crc(uint64_t _addr)
++{
++      uint32_t i;
++      uint8_t  data;
++      uint32_t crc;
++
++      /* CRC calculation */
++      crc = 0xffffffff;
++      for (i = 0; i < 6; i++) {
++              data = (uint8_t)(_addr >> ((5-i)*8));
++              crc = crc ^ data;
++              crc = crc_tbl[crc&0xff] ^ (crc>>8);
++      }
++
++      crc = get_mirror32(crc);
++      return crc;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.h
+@@ -0,0 +1,43 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#ifndef __FMAN_CRC32_H
++#define __FMAN_CRC32_H
++
++#include "common/general.h"
++
++
++uint32_t get_mac_addr_crc(uint64_t _addr);
++
++
++#endif /* __FMAN_CRC32_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c
+@@ -0,0 +1,845 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#include "fsl_fman_dtsec.h"
++
++
++void fman_dtsec_stop_rx(struct dtsec_regs *regs)
++{
++      /* Assert the graceful stop bit */
++      iowrite32be(ioread32be(&regs->rctrl) | RCTRL_GRS, &regs->rctrl);
++}
++
++void fman_dtsec_stop_tx(struct dtsec_regs *regs)
++{
++      /* Assert the graceful stop bit */
++      iowrite32be(ioread32be(&regs->tctrl) | DTSEC_TCTRL_GTS, &regs->tctrl);
++}
++
++void fman_dtsec_start_tx(struct dtsec_regs *regs)
++{
++      /* clear the graceful stop bit */
++      iowrite32be(ioread32be(&regs->tctrl) & ~DTSEC_TCTRL_GTS, &regs->tctrl);
++}
++
++void fman_dtsec_start_rx(struct dtsec_regs *regs)
++{
++      /* clear the graceful stop bit */
++      iowrite32be(ioread32be(&regs->rctrl) & ~RCTRL_GRS, &regs->rctrl);
++}
++
++void fman_dtsec_defconfig(struct dtsec_cfg *cfg)
++{
++      cfg->halfdup_on = DEFAULT_HALFDUP_ON;
++      cfg->halfdup_retransmit = DEFAULT_HALFDUP_RETRANSMIT;
++      cfg->halfdup_coll_window = DEFAULT_HALFDUP_COLL_WINDOW;
++      cfg->halfdup_excess_defer = DEFAULT_HALFDUP_EXCESS_DEFER;
++      cfg->halfdup_no_backoff = DEFAULT_HALFDUP_NO_BACKOFF;
++      cfg->halfdup_bp_no_backoff = DEFAULT_HALFDUP_BP_NO_BACKOFF;
++      cfg->halfdup_alt_backoff_val = DEFAULT_HALFDUP_ALT_BACKOFF_VAL;
++      cfg->halfdup_alt_backoff_en = DEFAULT_HALFDUP_ALT_BACKOFF_EN;
++      cfg->rx_drop_bcast = DEFAULT_RX_DROP_BCAST;
++      cfg->rx_short_frm = DEFAULT_RX_SHORT_FRM;
++      cfg->rx_len_check = DEFAULT_RX_LEN_CHECK;
++      cfg->tx_pad_crc = DEFAULT_TX_PAD_CRC;
++      cfg->tx_crc = DEFAULT_TX_CRC;
++      cfg->rx_ctrl_acc = DEFAULT_RX_CTRL_ACC;
++      cfg->tx_pause_time = DEFAULT_TX_PAUSE_TIME;
++      cfg->tbipa = DEFAULT_TBIPA; /* PHY address 0 is reserved (DPAA RM)*/
++      cfg->rx_prepend = DEFAULT_RX_PREPEND;
++      cfg->ptp_tsu_en = DEFAULT_PTP_TSU_EN;
++      cfg->ptp_exception_en = DEFAULT_PTP_EXCEPTION_EN;
++      cfg->preamble_len = DEFAULT_PREAMBLE_LEN;
++      cfg->rx_preamble = DEFAULT_RX_PREAMBLE;
++      cfg->tx_preamble = DEFAULT_TX_PREAMBLE;
++      cfg->loopback = DEFAULT_LOOPBACK;
++      cfg->rx_time_stamp_en = DEFAULT_RX_TIME_STAMP_EN;
++      cfg->tx_time_stamp_en = DEFAULT_TX_TIME_STAMP_EN;
++      cfg->rx_flow = DEFAULT_RX_FLOW;
++      cfg->tx_flow = DEFAULT_TX_FLOW;
++      cfg->rx_group_hash_exd = DEFAULT_RX_GROUP_HASH_EXD;
++      cfg->tx_pause_time_extd = DEFAULT_TX_PAUSE_TIME_EXTD;
++      cfg->rx_promisc = DEFAULT_RX_PROMISC;
++      cfg->non_back_to_back_ipg1 = DEFAULT_NON_BACK_TO_BACK_IPG1;
++      cfg->non_back_to_back_ipg2 = DEFAULT_NON_BACK_TO_BACK_IPG2;
++      cfg->min_ifg_enforcement = DEFAULT_MIN_IFG_ENFORCEMENT;
++      cfg->back_to_back_ipg = DEFAULT_BACK_TO_BACK_IPG;
++      cfg->maximum_frame = DEFAULT_MAXIMUM_FRAME;
++      cfg->tbi_phy_addr = DEFAULT_TBI_PHY_ADDR;
++      cfg->wake_on_lan = DEFAULT_WAKE_ON_LAN;
++}
++
++int fman_dtsec_init(struct dtsec_regs *regs, struct dtsec_cfg *cfg,
++              enum enet_interface iface_mode,
++              enum enet_speed iface_speed,
++              uint8_t *macaddr,
++              uint8_t fm_rev_maj,
++              uint8_t fm_rev_min,
++              uint32_t exception_mask)
++{
++      bool            is_rgmii = FALSE;
++      bool            is_sgmii = FALSE;
++      bool            is_qsgmii = FALSE;
++      int             i;
++      uint32_t        tmp;
++
++UNUSED(fm_rev_maj);UNUSED(fm_rev_min);
++
++      /* let's start with a soft reset */
++      iowrite32be(MACCFG1_SOFT_RESET, &regs->maccfg1);
++      iowrite32be(0, &regs->maccfg1);
++
++      /*************dtsec_id2******************/
++      tmp =  ioread32be(&regs->tsec_id2);
++
++      /* check RGMII support */
++      if (iface_mode == E_ENET_IF_RGMII ||
++                      iface_mode == E_ENET_IF_RMII)
++              if (tmp & DTSEC_ID2_INT_REDUCED_OFF)
++                      return -EINVAL;
++
++      if (iface_mode == E_ENET_IF_SGMII ||
++                      iface_mode == E_ENET_IF_MII)
++              if (tmp & DTSEC_ID2_INT_REDUCED_OFF)
++                      return -EINVAL;
++
++      /***************ECNTRL************************/
++
++      is_rgmii = (bool)((iface_mode == E_ENET_IF_RGMII) ? TRUE : FALSE);
++      is_sgmii = (bool)((iface_mode == E_ENET_IF_SGMII) ? TRUE : FALSE);
++      is_qsgmii = (bool)((iface_mode == E_ENET_IF_QSGMII) ? TRUE : FALSE);
++
++      tmp = 0;
++      if (is_rgmii || iface_mode == E_ENET_IF_GMII)
++              tmp |= DTSEC_ECNTRL_GMIIM;
++      if (is_sgmii)
++              tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM);
++      if (is_qsgmii)
++              tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM |
++                              DTSEC_ECNTRL_QSGMIIM);
++      if (is_rgmii)
++              tmp |= DTSEC_ECNTRL_RPM;
++      if (iface_speed == E_ENET_SPEED_100)
++              tmp |= DTSEC_ECNTRL_R100M;
++
++      iowrite32be(tmp, &regs->ecntrl);
++      /***************ECNTRL************************/
++
++      /***************TCTRL************************/
++      tmp = 0;
++      if (cfg->halfdup_on)
++              tmp |= DTSEC_TCTRL_THDF;
++      if (cfg->tx_time_stamp_en)
++              tmp |= DTSEC_TCTRL_TTSE;
++
++      iowrite32be(tmp, &regs->tctrl);
++
++      /***************TCTRL************************/
++
++      /***************PTV************************/
++      tmp = 0;
++
++#ifdef FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1
++      if ((fm_rev_maj == 1) && (fm_rev_min == 0))
++              cfg->tx_pause_time += 2;
++#endif /* FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1 */
++
++      if (cfg->tx_pause_time)
++              tmp |= cfg->tx_pause_time;
++      if (cfg->tx_pause_time_extd)
++              tmp |= cfg->tx_pause_time_extd << PTV_PTE_OFST;
++      iowrite32be(tmp, &regs->ptv);
++
++      /***************RCTRL************************/
++      tmp = 0;
++      tmp |= ((uint32_t)(cfg->rx_prepend & 0x0000001f)) << 16;
++      if (cfg->rx_ctrl_acc)
++              tmp |= RCTRL_CFA;
++      if (cfg->rx_group_hash_exd)
++              tmp |= RCTRL_GHTX;
++      if (cfg->rx_time_stamp_en)
++              tmp |= RCTRL_RTSE;
++      if (cfg->rx_drop_bcast)
++              tmp |= RCTRL_BC_REJ;
++      if (cfg->rx_short_frm)
++              tmp |= RCTRL_RSF;
++      if (cfg->rx_promisc)
++              tmp |= RCTRL_PROM;
++
++      iowrite32be(tmp, &regs->rctrl);
++      /***************RCTRL************************/
++
++      /*
++       * Assign a Phy Address to the TBI (TBIPA).
++       * Done also in cases where TBI is not selected to avoid conflict with
++       * the external PHY's Physical address
++       */
++      iowrite32be(cfg->tbipa, &regs->tbipa);
++
++      /***************TMR_CTL************************/
++      iowrite32be(0, &regs->tmr_ctrl);
++
++      if (cfg->ptp_tsu_en) {
++              tmp = 0;
++              tmp |= TMR_PEVENT_TSRE;
++              iowrite32be(tmp, &regs->tmr_pevent);
++
++              if (cfg->ptp_exception_en) {
++                      tmp = 0;
++                      tmp |= TMR_PEMASK_TSREEN;
++                      iowrite32be(tmp, &regs->tmr_pemask);
++              }
++      }
++
++      /***************MACCFG1***********************/
++      tmp = 0;
++      if (cfg->loopback)
++              tmp |= MACCFG1_LOOPBACK;
++      if (cfg->rx_flow)
++              tmp |= MACCFG1_RX_FLOW;
++      if (cfg->tx_flow)
++              tmp |= MACCFG1_TX_FLOW;
++      iowrite32be(tmp, &regs->maccfg1);
++
++      /***************MACCFG1***********************/
++
++      /***************MACCFG2***********************/
++      tmp = 0;
++
++      if (iface_speed < E_ENET_SPEED_1000)
++              tmp |= MACCFG2_NIBBLE_MODE;
++      else if (iface_speed == E_ENET_SPEED_1000)
++              tmp |= MACCFG2_BYTE_MODE;
++
++      tmp |= ((uint32_t) cfg->preamble_len & 0x0000000f)
++              << PREAMBLE_LENGTH_SHIFT;
++
++      if (cfg->rx_preamble)
++              tmp |= MACCFG2_PRE_AM_Rx_EN;
++      if (cfg->tx_preamble)
++              tmp |= MACCFG2_PRE_AM_Tx_EN;
++      if (cfg->rx_len_check)
++              tmp |= MACCFG2_LENGTH_CHECK;
++      if (cfg->tx_pad_crc)
++              tmp |= MACCFG2_PAD_CRC_EN;
++      if (cfg->tx_crc)
++              tmp |= MACCFG2_CRC_EN;
++      if (!cfg->halfdup_on)
++              tmp |= MACCFG2_FULL_DUPLEX;
++      iowrite32be(tmp, &regs->maccfg2);
++
++      /***************MACCFG2***********************/
++
++      /***************IPGIFG************************/
++      tmp = (((cfg->non_back_to_back_ipg1 <<
++              IPGIFG_NON_BACK_TO_BACK_IPG_1_SHIFT)
++              & IPGIFG_NON_BACK_TO_BACK_IPG_1)
++              | ((cfg->non_back_to_back_ipg2 <<
++              IPGIFG_NON_BACK_TO_BACK_IPG_2_SHIFT)
++              & IPGIFG_NON_BACK_TO_BACK_IPG_2)
++              | ((cfg->min_ifg_enforcement <<
++              IPGIFG_MIN_IFG_ENFORCEMENT_SHIFT)
++              & IPGIFG_MIN_IFG_ENFORCEMENT)
++              | (cfg->back_to_back_ipg & IPGIFG_BACK_TO_BACK_IPG));
++      iowrite32be(tmp, &regs->ipgifg);
++
++      /***************IPGIFG************************/
++
++      /***************HAFDUP************************/
++      tmp = 0;
++
++      if (cfg->halfdup_alt_backoff_en)
++              tmp = (uint32_t)(HAFDUP_ALT_BEB |
++                              ((cfg->halfdup_alt_backoff_val & 0x0000000f)
++                               << HAFDUP_ALTERNATE_BEB_TRUNCATION_SHIFT));
++      if (cfg->halfdup_bp_no_backoff)
++              tmp |= HAFDUP_BP_NO_BACKOFF;
++      if (cfg->halfdup_no_backoff)
++              tmp |= HAFDUP_NO_BACKOFF;
++      if (cfg->halfdup_excess_defer)
++              tmp |= HAFDUP_EXCESS_DEFER;
++      tmp |= ((cfg->halfdup_retransmit << HAFDUP_RETRANSMISSION_MAX_SHIFT)
++              & HAFDUP_RETRANSMISSION_MAX);
++      tmp |= (cfg->halfdup_coll_window & HAFDUP_COLLISION_WINDOW);
++
++      iowrite32be(tmp, &regs->hafdup);
++      /***************HAFDUP************************/
++
++      /***************MAXFRM************************/
++      /* Initialize MAXFRM */
++      iowrite32be(cfg->maximum_frame, &regs->maxfrm);
++
++      /***************MAXFRM************************/
++
++      /***************CAM1************************/
++      iowrite32be(0xffffffff, &regs->cam1);
++      iowrite32be(0xffffffff, &regs->cam2);
++
++      /***************IMASK************************/
++      iowrite32be(exception_mask, &regs->imask);
++      /***************IMASK************************/
++
++      /***************IEVENT************************/
++      iowrite32be(0xffffffff, &regs->ievent);
++
++      /***************MACSTNADDR1/2*****************/
++
++      tmp = (uint32_t)((macaddr[5] << 24) |
++                       (macaddr[4] << 16) |
++                       (macaddr[3] << 8) |
++                        macaddr[2]);
++      iowrite32be(tmp, &regs->macstnaddr1);
++
++      tmp = (uint32_t)((macaddr[1] << 24) |
++                       (macaddr[0] << 16));
++      iowrite32be(tmp, &regs->macstnaddr2);
++
++      /***************MACSTNADDR1/2*****************/
++
++      /*****************HASH************************/
++      for (i = 0; i < NUM_OF_HASH_REGS ; i++) {
++              /* Initialize IADDRx */
++              iowrite32be(0, &regs->igaddr[i]);
++              /* Initialize GADDRx */
++              iowrite32be(0, &regs->gaddr[i]);
++      }
++
++      fman_dtsec_reset_stat(regs);
++
++      return 0;
++}
++
++uint16_t fman_dtsec_get_max_frame_len(struct dtsec_regs *regs)
++{
++      return (uint16_t)ioread32be(&regs->maxfrm);
++}
++
++void fman_dtsec_set_max_frame_len(struct dtsec_regs *regs, uint16_t length)
++{
++      iowrite32be(length, &regs->maxfrm);
++}
++
++void fman_dtsec_set_mac_address(struct dtsec_regs *regs, uint8_t *adr)
++{
++      uint32_t tmp;
++
++      tmp = (uint32_t)((adr[5] << 24) |
++                       (adr[4] << 16) |
++                       (adr[3] << 8) |
++                        adr[2]);
++      iowrite32be(tmp, &regs->macstnaddr1);
++
++      tmp = (uint32_t)((adr[1] << 24) |
++                       (adr[0] << 16));
++      iowrite32be(tmp, &regs->macstnaddr2);
++}
++
++void fman_dtsec_get_mac_address(struct dtsec_regs *regs, uint8_t *macaddr)
++{
++      uint32_t tmp1, tmp2;
++
++      tmp1 = ioread32be(&regs->macstnaddr1);
++      tmp2 = ioread32be(&regs->macstnaddr2);
++
++      macaddr[0] = (uint8_t)((tmp2 & 0x00ff0000) >> 16);
++      macaddr[1] = (uint8_t)((tmp2 & 0xff000000) >> 24);
++      macaddr[2] = (uint8_t)(tmp1 & 0x000000ff);
++      macaddr[3] = (uint8_t)((tmp1 & 0x0000ff00) >> 8);
++      macaddr[4] = (uint8_t)((tmp1 & 0x00ff0000) >> 16);
++      macaddr[5] = (uint8_t)((tmp1 & 0xff000000) >> 24);
++}
++
++void fman_dtsec_set_hash_table(struct dtsec_regs *regs, uint32_t crc, bool mcast, bool ghtx)
++{
++    int32_t bucket;
++    if (ghtx)
++        bucket = (int32_t)((crc >> 23) & 0x1ff);
++    else {
++        bucket = (int32_t)((crc >> 24) & 0xff);
++        /* if !ghtx and mcast the bit must be set in gaddr instead of igaddr. */
++        if (mcast)
++            bucket += 0x100;
++    }
++    fman_dtsec_set_bucket(regs, bucket, TRUE);
++}
++
++void fman_dtsec_set_bucket(struct dtsec_regs *regs, int bucket, bool enable)
++{
++      int reg_idx = (bucket >> 5) & 0xf;
++      int bit_idx = bucket & 0x1f;
++      uint32_t bit_mask = 0x80000000 >> bit_idx;
++      uint32_t *reg;
++
++      if (reg_idx > 7)
++              reg = &regs->gaddr[reg_idx-8];
++      else
++              reg = &regs->igaddr[reg_idx];
++
++      if (enable)
++              iowrite32be(ioread32be(reg) | bit_mask, reg);
++      else
++              iowrite32be(ioread32be(reg) & (~bit_mask), reg);
++}
++
++void fman_dtsec_reset_filter_table(struct dtsec_regs *regs, bool mcast, bool ucast)
++{
++      int             i;
++      bool    ghtx;
++
++      ghtx = (bool)((ioread32be(&regs->rctrl) & RCTRL_GHTX) ? TRUE : FALSE);
++
++      if (ucast || (ghtx && mcast)) {
++              for (i = 0; i < NUM_OF_HASH_REGS; i++)
++                      iowrite32be(0, &regs->igaddr[i]);
++      }
++      if (mcast) {
++              for (i = 0; i < NUM_OF_HASH_REGS; i++)
++                      iowrite32be(0, &regs->gaddr[i]);
++      }
++}
++
++int fman_dtsec_set_tbi_phy_addr(struct dtsec_regs *regs,
++              uint8_t addr)
++{
++      if (addr > 0 && addr < 32)
++              iowrite32be(addr, &regs->tbipa);
++      else
++              return -EINVAL;
++
++      return 0;
++}
++
++void fman_dtsec_set_wol(struct dtsec_regs *regs, bool en)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&regs->maccfg2);
++      if (en)
++              tmp |= MACCFG2_MAGIC_PACKET_EN;
++      else
++              tmp &= ~MACCFG2_MAGIC_PACKET_EN;
++      iowrite32be(tmp, &regs->maccfg2);
++}
++
++int fman_dtsec_adjust_link(struct dtsec_regs *regs,
++              enum enet_interface iface_mode,
++              enum enet_speed speed, bool full_dx)
++{
++      uint32_t                tmp;
++
++      UNUSED(iface_mode);
++
++      if ((speed == E_ENET_SPEED_1000) && !full_dx)
++              return -EINVAL;
++
++      tmp = ioread32be(&regs->maccfg2);
++      if (!full_dx)
++              tmp &= ~MACCFG2_FULL_DUPLEX;
++      else
++              tmp |= MACCFG2_FULL_DUPLEX;
++
++      tmp &= ~(MACCFG2_NIBBLE_MODE | MACCFG2_BYTE_MODE);
++      if (speed < E_ENET_SPEED_1000)
++              tmp |= MACCFG2_NIBBLE_MODE;
++      else if (speed == E_ENET_SPEED_1000)
++              tmp |= MACCFG2_BYTE_MODE;
++      iowrite32be(tmp, &regs->maccfg2);
++
++      tmp = ioread32be(&regs->ecntrl);
++      if (speed == E_ENET_SPEED_100)
++              tmp |= DTSEC_ECNTRL_R100M;
++      else
++              tmp &= ~DTSEC_ECNTRL_R100M;
++      iowrite32be(tmp, &regs->ecntrl);
++
++      return 0;
++}
++
++void fman_dtsec_set_uc_promisc(struct dtsec_regs *regs, bool enable)
++{
++      uint32_t                tmp;
++
++      tmp = ioread32be(&regs->rctrl);
++
++      if (enable)
++              tmp |= RCTRL_UPROM;
++      else
++              tmp &= ~RCTRL_UPROM;
++
++      iowrite32be(tmp, &regs->rctrl);
++}
++
++void fman_dtsec_set_mc_promisc(struct dtsec_regs *regs, bool enable)
++{
++      uint32_t                tmp;
++
++      tmp = ioread32be(&regs->rctrl);
++
++      if (enable)
++              tmp |= RCTRL_MPROM;
++      else
++              tmp &= ~RCTRL_MPROM;
++
++      iowrite32be(tmp, &regs->rctrl);
++}
++
++bool fman_dtsec_get_clear_carry_regs(struct dtsec_regs *regs,
++                              uint32_t *car1, uint32_t *car2)
++{
++      /* read carry registers */
++      *car1 = ioread32be(&regs->car1);
++      *car2 = ioread32be(&regs->car2);
++      /* clear carry registers */
++      if (*car1)
++              iowrite32be(*car1, &regs->car1);
++      if (*car2)
++              iowrite32be(*car2, &regs->car2);
++
++      return (bool)((*car1 | *car2) ? TRUE : FALSE);
++}
++
++void fman_dtsec_reset_stat(struct dtsec_regs *regs)
++{
++      /* clear HW counters */
++      iowrite32be(ioread32be(&regs->ecntrl) |
++                      DTSEC_ECNTRL_CLRCNT, &regs->ecntrl);
++}
++
++int fman_dtsec_set_stat_level(struct dtsec_regs *regs, enum dtsec_stat_level level)
++{
++      switch (level) {
++      case E_MAC_STAT_NONE:
++              iowrite32be(0xffffffff, &regs->cam1);
++              iowrite32be(0xffffffff, &regs->cam2);
++              iowrite32be(ioread32be(&regs->ecntrl) & ~DTSEC_ECNTRL_STEN,
++                              &regs->ecntrl);
++              iowrite32be(ioread32be(&regs->imask) & ~DTSEC_IMASK_MSROEN,
++                              &regs->imask);
++              break;
++      case E_MAC_STAT_PARTIAL:
++              iowrite32be(CAM1_ERRORS_ONLY, &regs->cam1);
++              iowrite32be(CAM2_ERRORS_ONLY, &regs->cam2);
++              iowrite32be(ioread32be(&regs->ecntrl) | DTSEC_ECNTRL_STEN,
++                              &regs->ecntrl);
++              iowrite32be(ioread32be(&regs->imask) | DTSEC_IMASK_MSROEN,
++                              &regs->imask);
++              break;
++      case E_MAC_STAT_MIB_GRP1:
++              iowrite32be((uint32_t)~CAM1_MIB_GRP_1, &regs->cam1);
++              iowrite32be((uint32_t)~CAM2_MIB_GRP_1, &regs->cam2);
++              iowrite32be(ioread32be(&regs->ecntrl) | DTSEC_ECNTRL_STEN,
++                              &regs->ecntrl);
++              iowrite32be(ioread32be(&regs->imask) | DTSEC_IMASK_MSROEN,
++                              &regs->imask);
++              break;
++      case E_MAC_STAT_FULL:
++              iowrite32be(0, &regs->cam1);
++              iowrite32be(0, &regs->cam2);
++              iowrite32be(ioread32be(&regs->ecntrl) | DTSEC_ECNTRL_STEN,
++                              &regs->ecntrl);
++              iowrite32be(ioread32be(&regs->imask) | DTSEC_IMASK_MSROEN,
++                              &regs->imask);
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++void fman_dtsec_set_ts(struct dtsec_regs *regs, bool en)
++{
++      if (en) {
++              iowrite32be(ioread32be(&regs->rctrl) | RCTRL_RTSE,
++                              &regs->rctrl);
++              iowrite32be(ioread32be(&regs->tctrl) | DTSEC_TCTRL_TTSE,
++                              &regs->tctrl);
++      } else {
++              iowrite32be(ioread32be(&regs->rctrl) & ~RCTRL_RTSE,
++                              &regs->rctrl);
++              iowrite32be(ioread32be(&regs->tctrl) & ~DTSEC_TCTRL_TTSE,
++                              &regs->tctrl);
++      }
++}
++
++void fman_dtsec_enable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&regs->maccfg1);
++
++      if (apply_rx)
++              tmp |= MACCFG1_RX_EN ;
++
++      if (apply_tx)
++              tmp |= MACCFG1_TX_EN ;
++
++      iowrite32be(tmp, &regs->maccfg1);
++}
++
++void fman_dtsec_clear_addr_in_paddr(struct dtsec_regs *regs, uint8_t paddr_num)
++{
++    iowrite32be(0, &regs->macaddr[paddr_num].exact_match1);
++    iowrite32be(0, &regs->macaddr[paddr_num].exact_match2);
++}
++
++void fman_dtsec_add_addr_in_paddr(struct dtsec_regs *regs,
++                              uint64_t addr,
++                              uint8_t paddr_num)
++{
++      uint32_t tmp;
++
++      tmp = (uint32_t)(addr);
++      /* swap */
++      tmp = (((tmp & 0x000000FF) << 24) |
++              ((tmp & 0x0000FF00) <<  8) |
++              ((tmp & 0x00FF0000) >>  8) |
++              ((tmp & 0xFF000000) >> 24));
++      iowrite32be(tmp, &regs->macaddr[paddr_num].exact_match1);
++
++      tmp = (uint32_t)(addr>>32);
++      /* swap */
++      tmp = (((tmp & 0x000000FF) << 24) |
++              ((tmp & 0x0000FF00) <<  8) |
++              ((tmp & 0x00FF0000) >>  8) |
++              ((tmp & 0xFF000000) >> 24));
++      iowrite32be(tmp, &regs->macaddr[paddr_num].exact_match2);
++}
++
++void fman_dtsec_disable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&regs->maccfg1);
++
++      if (apply_rx)
++              tmp &= ~MACCFG1_RX_EN;
++
++      if (apply_tx)
++              tmp &= ~MACCFG1_TX_EN;
++
++      iowrite32be(tmp, &regs->maccfg1);
++}
++
++void fman_dtsec_set_tx_pause_frames(struct dtsec_regs *regs, uint16_t time)
++{
++      uint32_t ptv = 0;
++
++      /* fixme: don't enable tx pause for half-duplex */
++
++      if (time) {
++              ptv = ioread32be(&regs->ptv);
++              ptv &= 0xffff0000;
++              ptv |= time & 0x0000ffff;
++              iowrite32be(ptv, &regs->ptv);
++
++              /* trigger the transmission of a flow-control pause frame */
++              iowrite32be(ioread32be(&regs->maccfg1) | MACCFG1_TX_FLOW,
++                              &regs->maccfg1);
++      } else
++              iowrite32be(ioread32be(&regs->maccfg1) & ~MACCFG1_TX_FLOW,
++                              &regs->maccfg1);
++}
++
++void fman_dtsec_handle_rx_pause(struct dtsec_regs *regs, bool en)
++{
++      uint32_t tmp;
++
++      /* todo: check if mac is set to full-duplex */
++
++      tmp = ioread32be(&regs->maccfg1);
++      if (en)
++              tmp |= MACCFG1_RX_FLOW;
++      else
++              tmp &= ~MACCFG1_RX_FLOW;
++      iowrite32be(tmp, &regs->maccfg1);
++}
++
++uint32_t fman_dtsec_get_rctrl(struct dtsec_regs *regs)
++{
++      return ioread32be(&regs->rctrl);
++}
++
++uint32_t fman_dtsec_get_revision(struct dtsec_regs *regs)
++{
++      return ioread32be(&regs->tsec_id);
++}
++
++uint32_t fman_dtsec_get_event(struct dtsec_regs *regs, uint32_t ev_mask)
++{
++      return ioread32be(&regs->ievent) & ev_mask;
++}
++
++void fman_dtsec_ack_event(struct dtsec_regs *regs, uint32_t ev_mask)
++{
++      iowrite32be(ev_mask, &regs->ievent);
++}
++
++uint32_t fman_dtsec_get_interrupt_mask(struct dtsec_regs *regs)
++{
++      return ioread32be(&regs->imask);
++}
++
++uint32_t fman_dtsec_check_and_clear_tmr_event(struct dtsec_regs *regs)
++{
++      uint32_t event;
++
++      event = ioread32be(&regs->tmr_pevent);
++      event &= ioread32be(&regs->tmr_pemask);
++
++      if (event)
++              iowrite32be(event, &regs->tmr_pevent);
++      return event;
++}
++
++void fman_dtsec_enable_tmr_interrupt(struct dtsec_regs *regs)
++{
++      iowrite32be(ioread32be(&regs->tmr_pemask) | TMR_PEMASK_TSREEN,
++                      &regs->tmr_pemask);
++}
++
++void fman_dtsec_disable_tmr_interrupt(struct dtsec_regs *regs)
++{
++      iowrite32be(ioread32be(&regs->tmr_pemask) & ~TMR_PEMASK_TSREEN,
++                      &regs->tmr_pemask);
++}
++
++void fman_dtsec_enable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask)
++{
++      iowrite32be(ioread32be(&regs->imask) | ev_mask, &regs->imask);
++}
++
++void fman_dtsec_disable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask)
++{
++      iowrite32be(ioread32be(&regs->imask) & ~ev_mask, &regs->imask);
++}
++
++uint32_t fman_dtsec_get_stat_counter(struct dtsec_regs *regs,
++              enum dtsec_stat_counters reg_name)
++{
++      uint32_t ret_val;
++
++      switch (reg_name) {
++      case E_DTSEC_STAT_TR64:
++              ret_val = ioread32be(&regs->tr64);
++              break;
++      case E_DTSEC_STAT_TR127:
++              ret_val = ioread32be(&regs->tr127);
++              break;
++      case E_DTSEC_STAT_TR255:
++              ret_val = ioread32be(&regs->tr255);
++              break;
++      case E_DTSEC_STAT_TR511:
++              ret_val = ioread32be(&regs->tr511);
++              break;
++      case E_DTSEC_STAT_TR1K:
++              ret_val = ioread32be(&regs->tr1k);
++              break;
++      case E_DTSEC_STAT_TRMAX:
++              ret_val = ioread32be(&regs->trmax);
++              break;
++      case E_DTSEC_STAT_TRMGV:
++              ret_val = ioread32be(&regs->trmgv);
++              break;
++      case E_DTSEC_STAT_RBYT:
++              ret_val = ioread32be(&regs->rbyt);
++              break;
++      case E_DTSEC_STAT_RPKT:
++              ret_val = ioread32be(&regs->rpkt);
++              break;
++      case E_DTSEC_STAT_RMCA:
++              ret_val = ioread32be(&regs->rmca);
++              break;
++      case E_DTSEC_STAT_RBCA:
++              ret_val = ioread32be(&regs->rbca);
++              break;
++      case E_DTSEC_STAT_RXPF:
++              ret_val = ioread32be(&regs->rxpf);
++              break;
++      case E_DTSEC_STAT_RALN:
++              ret_val = ioread32be(&regs->raln);
++              break;
++      case E_DTSEC_STAT_RFLR:
++              ret_val = ioread32be(&regs->rflr);
++              break;
++      case E_DTSEC_STAT_RCDE:
++              ret_val = ioread32be(&regs->rcde);
++              break;
++      case E_DTSEC_STAT_RCSE:
++              ret_val = ioread32be(&regs->rcse);
++              break;
++      case E_DTSEC_STAT_RUND:
++              ret_val = ioread32be(&regs->rund);
++              break;
++      case E_DTSEC_STAT_ROVR:
++              ret_val = ioread32be(&regs->rovr);
++              break;
++      case E_DTSEC_STAT_RFRG:
++              ret_val = ioread32be(&regs->rfrg);
++              break;
++      case E_DTSEC_STAT_RJBR:
++              ret_val = ioread32be(&regs->rjbr);
++              break;
++      case E_DTSEC_STAT_RDRP:
++              ret_val = ioread32be(&regs->rdrp);
++              break;
++      case E_DTSEC_STAT_TFCS:
++              ret_val = ioread32be(&regs->tfcs);
++              break;
++      case E_DTSEC_STAT_TBYT:
++              ret_val = ioread32be(&regs->tbyt);
++              break;
++      case E_DTSEC_STAT_TPKT:
++              ret_val = ioread32be(&regs->tpkt);
++              break;
++      case E_DTSEC_STAT_TMCA:
++              ret_val = ioread32be(&regs->tmca);
++              break;
++      case E_DTSEC_STAT_TBCA:
++              ret_val = ioread32be(&regs->tbca);
++              break;
++      case E_DTSEC_STAT_TXPF:
++              ret_val = ioread32be(&regs->txpf);
++              break;
++      case E_DTSEC_STAT_TNCL:
++              ret_val = ioread32be(&regs->tncl);
++              break;
++      case E_DTSEC_STAT_TDRP:
++              ret_val = ioread32be(&regs->tdrp);
++              break;
++      default:
++              ret_val = 0;
++      }
++
++      return ret_val;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c
+@@ -0,0 +1,163 @@
++/*
++ * Copyright 2008-2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#include "common/general.h"
++#include "fsl_fman_dtsec_mii_acc.h"
++
++
++/**
++ * dtsec_mii_get_div() - calculates the value of the dtsec mii divider
++ * @dtsec_freq:               dtsec clock frequency (in Mhz)
++ *
++ * This function calculates the dtsec mii clock divider that determines
++ * the MII MDC clock. MII MDC clock will be set to work in the range
++ * of 1.5 to 2.5Mhz
++ * The output of this function is the value of MIIMCFG[MgmtClk] which
++ * implicitly determines the divider value.
++ * Note: the dTSEC system clock is equal to 1/2 of the FMan clock.
++ *
++ * The table below which reflects dtsec_mii_get_div() functionality
++ * shows the relations among dtsec_freq, MgmtClk, actual divider
++ * and the MII frequency:
++ *
++ * dtsec freq   MgmtClk     div        MII freq Mhz
++ * [0.....80]     1      (1/4)(1/8)    [0   to 2.5]
++ * [81...120]     2      (1/6)(1/8)    [1.6 to 2.5]
++ * [121..160]     3      (1/8)(1/8)    [1.8 to 2.5]
++ * [161..200]     4      (1/10)(1/8)   [2.0 to 2.5]
++ * [201..280]     5      (1/14)(1/8)   [1.8 to 2.5]
++ * [281..400]     6      (1/20)(1/8)   [1.1 to 2.5]
++ * [401..560]     7      (1/28)(1/8)   [1.8 to 2.5]
++ * [560..frq]     7      (1/28)(1/8)   [frq/224]
++ *
++ * Returns: the MIIMCFG[MgmtClk] appropriate value
++ */
++
++static uint8_t dtsec_mii_get_div(uint16_t dtsec_freq)
++{
++      uint16_t mgmt_clk;
++
++      if (dtsec_freq < 80) mgmt_clk = 1;
++      else if (dtsec_freq < 120) mgmt_clk = 2;
++      else if (dtsec_freq < 160) mgmt_clk = 3;
++      else if (dtsec_freq < 200) mgmt_clk = 4;
++      else if (dtsec_freq < 280) mgmt_clk = 5;
++      else if (dtsec_freq < 400) mgmt_clk = 6;
++      else mgmt_clk = 7;
++
++      return (uint8_t)mgmt_clk;
++}
++
++void fman_dtsec_mii_reset(struct dtsec_mii_reg *regs)
++{
++      /* Reset the management interface */
++      iowrite32be(ioread32be(&regs->miimcfg) | MIIMCFG_RESET_MGMT,
++                      &regs->miimcfg);
++      iowrite32be(ioread32be(&regs->miimcfg) & ~MIIMCFG_RESET_MGMT,
++                      &regs->miimcfg);
++}
++
++
++int fman_dtsec_mii_write_reg(struct dtsec_mii_reg *regs, uint8_t addr,
++              uint8_t reg, uint16_t data, uint16_t dtsec_freq)
++{
++      uint32_t        tmp;
++
++      /* Setup the MII Mgmt clock speed */
++      iowrite32be((uint32_t)dtsec_mii_get_div(dtsec_freq), &regs->miimcfg);
++      wmb();
++
++      /* Stop the MII management read cycle */
++      iowrite32be(0, &regs->miimcom);
++      /* Dummy read to make sure MIIMCOM is written */
++      tmp = ioread32be(&regs->miimcom);
++      wmb();
++
++      /* Setting up MII Management Address Register */
++      tmp = (uint32_t)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg);
++      iowrite32be(tmp, &regs->miimadd);
++      wmb();
++
++      /* Setting up MII Management Control Register with data */
++      iowrite32be((uint32_t)data, &regs->miimcon);
++      /* Dummy read to make sure MIIMCON is written */
++      tmp = ioread32be(&regs->miimcon);
++      wmb();
++
++      /* Wait until MII management write is complete */
++      /* todo: a timeout could be useful here */
++      while ((ioread32be(&regs->miimind)) & MIIMIND_BUSY)
++              /* busy wait */;
++
++      return 0;
++}
++
++int fman_dtsec_mii_read_reg(struct dtsec_mii_reg *regs, uint8_t  addr,
++              uint8_t reg, uint16_t *data, uint16_t dtsec_freq)
++{
++      uint32_t        tmp;
++
++      /* Setup the MII Mgmt clock speed */
++      iowrite32be((uint32_t)dtsec_mii_get_div(dtsec_freq), &regs->miimcfg);
++      wmb();
++
++      /* Setting up the MII Management Address Register */
++      tmp = (uint32_t)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg);
++      iowrite32be(tmp, &regs->miimadd);
++      wmb();
++
++      /* Perform an MII management read cycle */
++      iowrite32be(MIIMCOM_READ_CYCLE, &regs->miimcom);
++      /* Dummy read to make sure MIIMCOM is written */
++      tmp = ioread32be(&regs->miimcom);
++      wmb();
++
++      /* Wait until MII management read is complete */
++      /* todo: a timeout could be useful here */
++      while ((ioread32be(&regs->miimind)) & MIIMIND_BUSY)
++              /* busy wait */;
++
++      /* Read MII management status  */
++      *data = (uint16_t)ioread32be(&regs->miimstat);
++      wmb();
++
++      iowrite32be(0, &regs->miimcom);
++      /* Dummy read to make sure MIIMCOM is written */
++      tmp = ioread32be(&regs->miimcom);
++
++      if (*data == 0xffff)
++              return -ENXIO;
++
++      return 0;
++}
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac.c
+@@ -0,0 +1,511 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#include "fsl_fman_memac.h"
++
++
++uint32_t fman_memac_get_event(struct memac_regs *regs, uint32_t ev_mask)
++{
++    return ioread32be(&regs->ievent) & ev_mask;
++}
++
++uint32_t fman_memac_get_interrupt_mask(struct memac_regs *regs)
++{
++    return ioread32be(&regs->imask);
++}
++
++void fman_memac_ack_event(struct memac_regs *regs, uint32_t ev_mask)
++{
++    iowrite32be(ev_mask, &regs->ievent);
++}
++
++void fman_memac_set_promiscuous(struct memac_regs *regs, bool val)
++{
++    uint32_t tmp;
++
++    tmp = ioread32be(&regs->command_config);
++
++    if (val)
++        tmp |= CMD_CFG_PROMIS_EN;
++    else
++        tmp &= ~CMD_CFG_PROMIS_EN;
++
++    iowrite32be(tmp, &regs->command_config);
++}
++
++void fman_memac_clear_addr_in_paddr(struct memac_regs *regs,
++                    uint8_t paddr_num)
++{
++    if (paddr_num == 0) {
++        iowrite32be(0, &regs->mac_addr0.mac_addr_l);
++        iowrite32be(0, &regs->mac_addr0.mac_addr_u);
++    } else {
++        iowrite32be(0x0, &regs->mac_addr[paddr_num - 1].mac_addr_l);
++        iowrite32be(0x0, &regs->mac_addr[paddr_num - 1].mac_addr_u);
++    }
++}
++
++void fman_memac_add_addr_in_paddr(struct memac_regs *regs,
++                    uint8_t *adr,
++                    uint8_t paddr_num)
++{
++    uint32_t tmp0, tmp1;
++
++    tmp0 = (uint32_t)(adr[0] |
++            adr[1] << 8 |
++            adr[2] << 16 |
++            adr[3] << 24);
++    tmp1 = (uint32_t)(adr[4] | adr[5] << 8);
++
++    if (paddr_num == 0) {
++        iowrite32be(tmp0, &regs->mac_addr0.mac_addr_l);
++        iowrite32be(tmp1, &regs->mac_addr0.mac_addr_u);
++    } else {
++        iowrite32be(tmp0, &regs->mac_addr[paddr_num-1].mac_addr_l);
++        iowrite32be(tmp1, &regs->mac_addr[paddr_num-1].mac_addr_u);
++    }
++}
++
++void fman_memac_enable(struct memac_regs *regs, bool apply_rx, bool apply_tx)
++{
++    uint32_t tmp;
++
++    tmp = ioread32be(&regs->command_config);
++
++    if (apply_rx)
++        tmp |= CMD_CFG_RX_EN;
++
++    if (apply_tx)
++        tmp |= CMD_CFG_TX_EN;
++
++    iowrite32be(tmp, &regs->command_config);
++}
++
++void fman_memac_disable(struct memac_regs *regs, bool apply_rx, bool apply_tx)
++{
++    uint32_t tmp;
++
++    tmp = ioread32be(&regs->command_config);
++
++    if (apply_rx)
++        tmp &= ~CMD_CFG_RX_EN;
++
++    if (apply_tx)
++        tmp &= ~CMD_CFG_TX_EN;
++
++    iowrite32be(tmp, &regs->command_config);
++}
++
++void fman_memac_reset_stat(struct memac_regs *regs)
++{
++    uint32_t tmp;
++
++    tmp = ioread32be(&regs->statn_config);
++
++    tmp |= STATS_CFG_CLR;
++
++    iowrite32be(tmp, &regs->statn_config);
++
++    while (ioread32be(&regs->statn_config) & STATS_CFG_CLR);
++}
++
++void fman_memac_reset(struct memac_regs *regs)
++{
++    uint32_t tmp;
++
++    tmp = ioread32be(&regs->command_config);
++
++    tmp |= CMD_CFG_SW_RESET;
++
++    iowrite32be(tmp, &regs->command_config);
++
++    while (ioread32be(&regs->command_config) & CMD_CFG_SW_RESET);
++}
++
++int fman_memac_init(struct memac_regs *regs,
++        struct memac_cfg *cfg,
++        enum enet_interface enet_interface,
++        enum enet_speed enet_speed,
++      bool slow_10g_if,
++        uint32_t exceptions)
++{
++    uint32_t    tmp;
++
++    /* Config */
++    tmp = 0;
++    if (cfg->wan_mode_enable)
++        tmp |= CMD_CFG_WAN_MODE;
++    if (cfg->promiscuous_mode_enable)
++        tmp |= CMD_CFG_PROMIS_EN;
++    if (cfg->pause_forward_enable)
++        tmp |= CMD_CFG_PAUSE_FWD;
++    if (cfg->pause_ignore)
++        tmp |= CMD_CFG_PAUSE_IGNORE;
++    if (cfg->tx_addr_ins_enable)
++        tmp |= CMD_CFG_TX_ADDR_INS;
++    if (cfg->loopback_enable)
++        tmp |= CMD_CFG_LOOPBACK_EN;
++    if (cfg->cmd_frame_enable)
++        tmp |= CMD_CFG_CNT_FRM_EN;
++    if (cfg->send_idle_enable)
++        tmp |= CMD_CFG_SEND_IDLE;
++    if (cfg->no_length_check_enable)
++        tmp |= CMD_CFG_NO_LEN_CHK;
++    if (cfg->rx_sfd_any)
++        tmp |= CMD_CFG_SFD_ANY;
++    if (cfg->pad_enable)
++        tmp |= CMD_CFG_TX_PAD_EN;
++    if (cfg->wake_on_lan)
++        tmp |= CMD_CFG_MG;
++
++    tmp |= CMD_CFG_CRC_FWD;
++
++    iowrite32be(tmp, &regs->command_config);
++
++    /* Max Frame Length */
++    iowrite32be((uint32_t)cfg->max_frame_length, &regs->maxfrm);
++
++    /* Pause Time */
++    iowrite32be((uint32_t)cfg->pause_quanta, &regs->pause_quanta[0]);
++    iowrite32be((uint32_t)0, &regs->pause_thresh[0]);
++
++    /* IF_MODE */
++    tmp = 0;
++    switch (enet_interface) {
++    case E_ENET_IF_XGMII:
++    case E_ENET_IF_XFI:
++        tmp |= IF_MODE_XGMII;
++        break;
++    default:
++        tmp |= IF_MODE_GMII;
++        if (enet_interface == E_ENET_IF_RGMII && !cfg->loopback_enable)
++            tmp |= IF_MODE_RGMII | IF_MODE_RGMII_AUTO;
++    }
++    iowrite32be(tmp, &regs->if_mode);
++
++      /* TX_FIFO_SECTIONS */
++      tmp = 0;
++      if (enet_interface == E_ENET_IF_XGMII ||
++              enet_interface == E_ENET_IF_XFI) {
++              if(slow_10g_if) {
++                      tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_SLOW_10G |
++                              TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G);
++              } else {
++                      tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_10G |
++                              TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G);
++              }
++      } else {
++              tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_1G |
++                              TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G);
++      }
++      iowrite32be(tmp, &regs->tx_fifo_sections);
++
++    /* clear all pending events and set-up interrupts */
++    fman_memac_ack_event(regs, 0xffffffff);
++    fman_memac_set_exception(regs, exceptions, TRUE);
++
++    return 0;
++}
++
++void fman_memac_set_exception(struct memac_regs *regs, uint32_t val, bool enable)
++{
++    uint32_t tmp;
++
++    tmp = ioread32be(&regs->imask);
++    if (enable)
++        tmp |= val;
++    else
++        tmp &= ~val;
++
++    iowrite32be(tmp, &regs->imask);
++}
++
++void fman_memac_reset_filter_table(struct memac_regs *regs)
++{
++      uint32_t i;
++      for (i = 0; i < 64; i++)
++              iowrite32be(i & ~HASH_CTRL_MCAST_EN, &regs->hashtable_ctrl);
++}
++
++void fman_memac_set_hash_table_entry(struct memac_regs *regs, uint32_t crc)
++{
++      iowrite32be(crc | HASH_CTRL_MCAST_EN, &regs->hashtable_ctrl);
++}
++
++void fman_memac_set_hash_table(struct memac_regs *regs, uint32_t val)
++{
++    iowrite32be(val, &regs->hashtable_ctrl);
++}
++
++uint16_t fman_memac_get_max_frame_len(struct memac_regs *regs)
++{
++    uint32_t tmp;
++
++    tmp = ioread32be(&regs->maxfrm);
++
++    return(uint16_t)tmp;
++}
++
++
++void fman_memac_set_tx_pause_frames(struct memac_regs *regs,
++                uint8_t priority,
++                uint16_t pause_time,
++                uint16_t thresh_time)
++{
++    uint32_t tmp;
++
++      tmp = ioread32be(&regs->tx_fifo_sections);
++
++      if (priority == 0xff) {
++              GET_TX_EMPTY_DEFAULT_VALUE(tmp);
++              iowrite32be(tmp, &regs->tx_fifo_sections);
++
++              tmp = ioread32be(&regs->command_config);
++              tmp &= ~CMD_CFG_PFC_MODE;
++              priority = 0;
++      } else {
++              GET_TX_EMPTY_PFC_VALUE(tmp);
++              iowrite32be(tmp, &regs->tx_fifo_sections);
++
++              tmp = ioread32be(&regs->command_config);
++              tmp |= CMD_CFG_PFC_MODE;
++    }
++
++    iowrite32be(tmp, &regs->command_config);
++
++    tmp = ioread32be(&regs->pause_quanta[priority / 2]);
++    if (priority % 2)
++        tmp &= 0x0000FFFF;
++    else
++        tmp &= 0xFFFF0000;
++    tmp |= ((uint32_t)pause_time << (16 * (priority % 2)));
++    iowrite32be(tmp, &regs->pause_quanta[priority / 2]);
++
++    tmp = ioread32be(&regs->pause_thresh[priority / 2]);
++    if (priority % 2)
++            tmp &= 0x0000FFFF;
++    else
++            tmp &= 0xFFFF0000;
++    tmp |= ((uint32_t)thresh_time<<(16 * (priority % 2)));
++    iowrite32be(tmp, &regs->pause_thresh[priority / 2]);
++}
++
++void fman_memac_set_rx_ignore_pause_frames(struct memac_regs    *regs,bool enable)
++{
++    uint32_t tmp;
++
++    tmp = ioread32be(&regs->command_config);
++    if (enable)
++        tmp |= CMD_CFG_PAUSE_IGNORE;
++    else
++        tmp &= ~CMD_CFG_PAUSE_IGNORE;
++
++    iowrite32be(tmp, &regs->command_config);
++}
++
++void fman_memac_set_wol(struct memac_regs *regs, bool enable)
++{
++    uint32_t tmp;
++
++    tmp = ioread32be(&regs->command_config);
++
++    if (enable)
++        tmp |= CMD_CFG_MG;
++    else
++        tmp &= ~CMD_CFG_MG;
++
++    iowrite32be(tmp, &regs->command_config);
++}
++
++#define GET_MEMAC_CNTR_64(bn) \
++        (ioread32be(&regs->bn ## _l) | \
++        ((uint64_t)ioread32be(&regs->bn ## _u) << 32))
++
++uint64_t fman_memac_get_counter(struct memac_regs *regs,
++                enum memac_counters reg_name)
++{
++    uint64_t ret_val;
++
++    switch (reg_name) {
++    case E_MEMAC_COUNTER_R64:
++        ret_val = GET_MEMAC_CNTR_64(r64);
++        break;
++    case E_MEMAC_COUNTER_R127:
++        ret_val = GET_MEMAC_CNTR_64(r127);
++        break;
++    case E_MEMAC_COUNTER_R255:
++        ret_val = GET_MEMAC_CNTR_64(r255);
++        break;
++    case E_MEMAC_COUNTER_R511:
++        ret_val = GET_MEMAC_CNTR_64(r511);
++        break;
++    case E_MEMAC_COUNTER_R1023:
++        ret_val = GET_MEMAC_CNTR_64(r1023);
++        break;
++    case E_MEMAC_COUNTER_R1518:
++        ret_val = GET_MEMAC_CNTR_64(r1518);
++        break;
++    case E_MEMAC_COUNTER_R1519X:
++        ret_val = GET_MEMAC_CNTR_64(r1519x);
++        break;
++    case E_MEMAC_COUNTER_RFRG:
++        ret_val = GET_MEMAC_CNTR_64(rfrg);
++        break;
++    case E_MEMAC_COUNTER_RJBR:
++        ret_val = GET_MEMAC_CNTR_64(rjbr);
++        break;
++    case E_MEMAC_COUNTER_RDRP:
++        ret_val = GET_MEMAC_CNTR_64(rdrp);
++        break;
++    case E_MEMAC_COUNTER_RALN:
++        ret_val = GET_MEMAC_CNTR_64(raln);
++        break;
++    case E_MEMAC_COUNTER_TUND:
++        ret_val = GET_MEMAC_CNTR_64(tund);
++        break;
++    case E_MEMAC_COUNTER_ROVR:
++        ret_val = GET_MEMAC_CNTR_64(rovr);
++        break;
++    case E_MEMAC_COUNTER_RXPF:
++        ret_val = GET_MEMAC_CNTR_64(rxpf);
++        break;
++    case E_MEMAC_COUNTER_TXPF:
++        ret_val = GET_MEMAC_CNTR_64(txpf);
++        break;
++    case E_MEMAC_COUNTER_ROCT:
++        ret_val = GET_MEMAC_CNTR_64(roct);
++        break;
++    case E_MEMAC_COUNTER_RMCA:
++        ret_val = GET_MEMAC_CNTR_64(rmca);
++        break;
++    case E_MEMAC_COUNTER_RBCA:
++        ret_val = GET_MEMAC_CNTR_64(rbca);
++        break;
++    case E_MEMAC_COUNTER_RPKT:
++        ret_val = GET_MEMAC_CNTR_64(rpkt);
++        break;
++    case E_MEMAC_COUNTER_RUCA:
++        ret_val = GET_MEMAC_CNTR_64(ruca);
++        break;
++    case E_MEMAC_COUNTER_RERR:
++        ret_val = GET_MEMAC_CNTR_64(rerr);
++        break;
++    case E_MEMAC_COUNTER_TOCT:
++        ret_val = GET_MEMAC_CNTR_64(toct);
++        break;
++    case E_MEMAC_COUNTER_TMCA:
++        ret_val = GET_MEMAC_CNTR_64(tmca);
++        break;
++    case E_MEMAC_COUNTER_TBCA:
++        ret_val = GET_MEMAC_CNTR_64(tbca);
++        break;
++    case E_MEMAC_COUNTER_TUCA:
++        ret_val = GET_MEMAC_CNTR_64(tuca);
++        break;
++    case E_MEMAC_COUNTER_TERR:
++        ret_val = GET_MEMAC_CNTR_64(terr);
++        break;
++    default:
++        ret_val = 0;
++    }
++
++    return ret_val;
++}
++
++void fman_memac_adjust_link(struct memac_regs *regs,
++        enum enet_interface iface_mode,
++        enum enet_speed speed, bool full_dx)
++{
++    uint32_t    tmp;
++
++    tmp = ioread32be(&regs->if_mode);
++
++    if (full_dx)
++        tmp &= ~IF_MODE_HD;
++    else
++        tmp |= IF_MODE_HD;
++
++    if (iface_mode == E_ENET_IF_RGMII) {
++        /* Configure RGMII in manual mode */
++        tmp &= ~IF_MODE_RGMII_AUTO;
++        tmp &= ~IF_MODE_RGMII_SP_MASK;
++
++        if (full_dx)
++            tmp |= IF_MODE_RGMII_FD;
++        else
++            tmp &= ~IF_MODE_RGMII_FD;
++
++        switch (speed) {
++        case E_ENET_SPEED_1000:
++            tmp |= IF_MODE_RGMII_1000;
++            break;
++        case E_ENET_SPEED_100:
++            tmp |= IF_MODE_RGMII_100;
++            break;
++        case E_ENET_SPEED_10:
++            tmp |= IF_MODE_RGMII_10;
++            break;
++        default:
++            break;
++        }
++    }
++
++    iowrite32be(tmp, &regs->if_mode);
++}
++
++void fman_memac_defconfig(struct memac_cfg *cfg)
++{
++    cfg->reset_on_init                = FALSE;
++    cfg->wan_mode_enable              = FALSE;
++    cfg->promiscuous_mode_enable      = FALSE;
++    cfg->pause_forward_enable = FALSE;
++    cfg->pause_ignore         = FALSE;
++    cfg->tx_addr_ins_enable           = FALSE;
++    cfg->loopback_enable              = FALSE;
++    cfg->cmd_frame_enable             = FALSE;
++    cfg->rx_error_discard             = FALSE;
++    cfg->send_idle_enable             = FALSE;
++    cfg->no_length_check_enable       = TRUE;
++    cfg->lgth_check_nostdr            = FALSE;
++    cfg->time_stamp_enable            = FALSE;
++    cfg->tx_ipg_length                = DEFAULT_TX_IPG_LENGTH;
++    cfg->max_frame_length             = DEFAULT_FRAME_LENGTH;
++    cfg->pause_quanta         = DEFAULT_PAUSE_QUANTA;
++    cfg->pad_enable                   = TRUE;
++    cfg->phy_tx_ena_on                = FALSE;
++    cfg->rx_sfd_any                   = FALSE;
++    cfg->rx_pbl_fwd                   = FALSE;
++    cfg->tx_pbl_fwd                   = FALSE;
++    cfg->debug_mode                   = FALSE;
++    cfg->wake_on_lan        = FALSE;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c
+@@ -0,0 +1,213 @@
++/*
++ * Copyright 2008-2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#include "fsl_fman_memac_mii_acc.h"
++
++static void write_phy_reg_10g(struct memac_mii_access_mem_map *mii_regs,
++      uint8_t phy_addr, uint8_t reg, uint16_t data)
++{
++      uint32_t                tmp_reg;
++
++      tmp_reg = ioread32be(&mii_regs->mdio_cfg);
++      /* Leave only MDIO_CLK_DIV bits set on */
++      tmp_reg &= MDIO_CFG_CLK_DIV_MASK;
++      /* Set maximum MDIO_HOLD value to allow phy to see
++      change of data signal */
++      tmp_reg |= MDIO_CFG_HOLD_MASK;
++      /* Add 10G interface mode */
++      tmp_reg |= MDIO_CFG_ENC45;
++      iowrite32be(tmp_reg, &mii_regs->mdio_cfg);
++
++      /* Wait for command completion */
++      while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
++              udelay(1);
++
++      /* Specify phy and register to be accessed */
++      iowrite32be(phy_addr, &mii_regs->mdio_ctrl);
++      iowrite32be(reg, &mii_regs->mdio_addr);
++      wmb();
++
++      while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
++              udelay(1);
++
++      /* Write data */
++      iowrite32be(data, &mii_regs->mdio_data);
++      wmb();
++
++      /* Wait for write transaction end */
++      while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY)
++              udelay(1);
++}
++
++static uint32_t read_phy_reg_10g(struct memac_mii_access_mem_map *mii_regs,
++      uint8_t phy_addr, uint8_t reg, uint16_t *data)
++{
++      uint32_t                tmp_reg;
++
++      tmp_reg = ioread32be(&mii_regs->mdio_cfg);
++      /* Leave only MDIO_CLK_DIV bits set on */
++      tmp_reg &= MDIO_CFG_CLK_DIV_MASK;
++      /* Set maximum MDIO_HOLD value to allow phy to see
++      change of data signal */
++      tmp_reg |= MDIO_CFG_HOLD_MASK;
++      /* Add 10G interface mode */
++      tmp_reg |= MDIO_CFG_ENC45;
++      iowrite32be(tmp_reg, &mii_regs->mdio_cfg);
++
++      /* Wait for command completion */
++      while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
++              udelay(1);
++
++      /* Specify phy and register to be accessed */
++      iowrite32be(phy_addr, &mii_regs->mdio_ctrl);
++      iowrite32be(reg, &mii_regs->mdio_addr);
++      wmb();
++
++      while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
++              udelay(1);
++
++      /* Read cycle */
++      tmp_reg = phy_addr;
++      tmp_reg |= MDIO_CTL_READ;
++      iowrite32be(tmp_reg, &mii_regs->mdio_ctrl);
++      wmb();
++
++      /* Wait for data to be available */
++      while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY)
++              udelay(1);
++
++      *data =  (uint16_t)ioread32be(&mii_regs->mdio_data);
++
++      /* Check if there was an error */
++      return ioread32be(&mii_regs->mdio_cfg);
++}
++
++static void write_phy_reg_1g(struct memac_mii_access_mem_map *mii_regs,
++      uint8_t phy_addr, uint8_t reg, uint16_t data)
++{
++      uint32_t                tmp_reg;
++
++      /* Leave only MDIO_CLK_DIV and MDIO_HOLD bits set on */
++      tmp_reg = ioread32be(&mii_regs->mdio_cfg);
++      tmp_reg &= (MDIO_CFG_CLK_DIV_MASK | MDIO_CFG_HOLD_MASK);
++      iowrite32be(tmp_reg, &mii_regs->mdio_cfg);
++
++      /* Wait for command completion */
++      while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
++              udelay(1);
++
++      /* Write transaction */
++      tmp_reg = (phy_addr << MDIO_CTL_PHY_ADDR_SHIFT);
++      tmp_reg |= reg;
++      iowrite32be(tmp_reg, &mii_regs->mdio_ctrl);
++
++      while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
++              udelay(1);
++
++      iowrite32be(data, &mii_regs->mdio_data);
++
++      wmb();
++
++      /* Wait for write transaction to end */
++      while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY)
++              udelay(1);
++}
++
++static uint32_t read_phy_reg_1g(struct memac_mii_access_mem_map *mii_regs,
++      uint8_t phy_addr, uint8_t reg, uint16_t *data)
++{
++      uint32_t tmp_reg;
++
++      /* Leave only MDIO_CLK_DIV and MDIO_HOLD bits set on */
++      tmp_reg = ioread32be(&mii_regs->mdio_cfg);
++      tmp_reg &= (MDIO_CFG_CLK_DIV_MASK | MDIO_CFG_HOLD_MASK);
++      iowrite32be(tmp_reg, &mii_regs->mdio_cfg);
++
++      /* Wait for command completion */
++      while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
++              udelay(1);
++
++      /* Read transaction */
++      tmp_reg = (phy_addr << MDIO_CTL_PHY_ADDR_SHIFT);
++      tmp_reg |= reg;
++      tmp_reg |= MDIO_CTL_READ;
++      iowrite32be(tmp_reg, &mii_regs->mdio_ctrl);
++
++      while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
++              udelay(1);
++
++      /* Wait for data to be available */
++      while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY)
++              udelay(1);
++
++      *data =  (uint16_t)ioread32be(&mii_regs->mdio_data);
++
++      /* Check error */
++      return ioread32be(&mii_regs->mdio_cfg);
++}
++
++/*****************************************************************************/
++int fman_memac_mii_write_phy_reg(struct memac_mii_access_mem_map *mii_regs,
++      uint8_t phy_addr, uint8_t reg, uint16_t data,
++      enum enet_speed enet_speed)
++{
++      /* Figure out interface type - 10G vs 1G.
++      In 10G interface both phy_addr and devAddr present. */
++      if (enet_speed == E_ENET_SPEED_10000)
++              write_phy_reg_10g(mii_regs, phy_addr, reg, data);
++      else
++              write_phy_reg_1g(mii_regs, phy_addr, reg, data);
++
++      return 0;
++}
++
++/*****************************************************************************/
++int fman_memac_mii_read_phy_reg(struct memac_mii_access_mem_map *mii_regs,
++      uint8_t phy_addr, uint8_t reg, uint16_t *data,
++      enum enet_speed enet_speed)
++{
++      uint32_t ans;
++      /* Figure out interface type - 10G vs 1G.
++      In 10G interface both phy_addr and devAddr present. */
++      if (enet_speed == E_ENET_SPEED_10000)
++              ans = read_phy_reg_10g(mii_regs, phy_addr, reg, data);
++      else
++              ans = read_phy_reg_1g(mii_regs, phy_addr, reg, data);
++
++      if (ans & MDIO_CFG_READ_ERR)
++              return -EINVAL;
++      return 0;
++}
++
++/* ......................................................................... */
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_tgec.c
+@@ -0,0 +1,367 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#include "fsl_fman_tgec.h"
++
++
++void fman_tgec_set_mac_address(struct tgec_regs *regs, uint8_t *adr)
++{
++      uint32_t tmp0, tmp1;
++
++      tmp0 = (uint32_t)(adr[0] |
++                      adr[1] << 8 |
++                      adr[2] << 16 |
++                      adr[3] << 24);
++      tmp1 = (uint32_t)(adr[4] | adr[5] << 8);
++      iowrite32be(tmp0, &regs->mac_addr_0);
++      iowrite32be(tmp1, &regs->mac_addr_1);
++}
++
++void fman_tgec_reset_stat(struct tgec_regs *regs)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&regs->command_config);
++
++      tmp |= CMD_CFG_STAT_CLR;
++
++      iowrite32be(tmp, &regs->command_config);
++
++      while (ioread32be(&regs->command_config) & CMD_CFG_STAT_CLR) ;
++}
++
++#define GET_TGEC_CNTR_64(bn) \
++      (((uint64_t)ioread32be(&regs->bn ## _u) << 32) | \
++                      ioread32be(&regs->bn ## _l))
++
++uint64_t fman_tgec_get_counter(struct tgec_regs *regs, enum tgec_counters reg_name)
++{
++      uint64_t ret_val;
++
++      switch (reg_name) {
++      case E_TGEC_COUNTER_R64:
++              ret_val = GET_TGEC_CNTR_64(r64);
++              break;
++      case E_TGEC_COUNTER_R127:
++              ret_val = GET_TGEC_CNTR_64(r127);
++              break;
++      case E_TGEC_COUNTER_R255:
++              ret_val = GET_TGEC_CNTR_64(r255);
++              break;
++      case E_TGEC_COUNTER_R511:
++              ret_val = GET_TGEC_CNTR_64(r511);
++              break;
++      case E_TGEC_COUNTER_R1023:
++              ret_val = GET_TGEC_CNTR_64(r1023);
++              break;
++      case E_TGEC_COUNTER_R1518:
++              ret_val = GET_TGEC_CNTR_64(r1518);
++              break;
++      case E_TGEC_COUNTER_R1519X:
++              ret_val = GET_TGEC_CNTR_64(r1519x);
++              break;
++      case E_TGEC_COUNTER_TRFRG:
++              ret_val = GET_TGEC_CNTR_64(trfrg);
++              break;
++      case E_TGEC_COUNTER_TRJBR:
++              ret_val = GET_TGEC_CNTR_64(trjbr);
++              break;
++      case E_TGEC_COUNTER_RDRP:
++              ret_val = GET_TGEC_CNTR_64(rdrp);
++              break;
++      case E_TGEC_COUNTER_RALN:
++              ret_val = GET_TGEC_CNTR_64(raln);
++              break;
++      case E_TGEC_COUNTER_TRUND:
++              ret_val = GET_TGEC_CNTR_64(trund);
++              break;
++      case E_TGEC_COUNTER_TROVR:
++              ret_val = GET_TGEC_CNTR_64(trovr);
++              break;
++      case E_TGEC_COUNTER_RXPF:
++              ret_val = GET_TGEC_CNTR_64(rxpf);
++              break;
++      case E_TGEC_COUNTER_TXPF:
++              ret_val = GET_TGEC_CNTR_64(txpf);
++              break;
++      case E_TGEC_COUNTER_ROCT:
++              ret_val = GET_TGEC_CNTR_64(roct);
++              break;
++      case E_TGEC_COUNTER_RMCA:
++              ret_val = GET_TGEC_CNTR_64(rmca);
++              break;
++      case E_TGEC_COUNTER_RBCA:
++              ret_val = GET_TGEC_CNTR_64(rbca);
++              break;
++      case E_TGEC_COUNTER_RPKT:
++              ret_val = GET_TGEC_CNTR_64(rpkt);
++              break;
++      case E_TGEC_COUNTER_RUCA:
++              ret_val = GET_TGEC_CNTR_64(ruca);
++              break;
++      case E_TGEC_COUNTER_RERR:
++              ret_val = GET_TGEC_CNTR_64(rerr);
++              break;
++      case E_TGEC_COUNTER_TOCT:
++              ret_val = GET_TGEC_CNTR_64(toct);
++              break;
++      case E_TGEC_COUNTER_TMCA:
++              ret_val = GET_TGEC_CNTR_64(tmca);
++              break;
++      case E_TGEC_COUNTER_TBCA:
++              ret_val = GET_TGEC_CNTR_64(tbca);
++              break;
++      case E_TGEC_COUNTER_TUCA:
++              ret_val = GET_TGEC_CNTR_64(tuca);
++              break;
++      case E_TGEC_COUNTER_TERR:
++              ret_val = GET_TGEC_CNTR_64(terr);
++              break;
++      default:
++              ret_val = 0;
++      }
++
++      return ret_val;
++}
++
++void fman_tgec_enable(struct tgec_regs *regs, bool apply_rx, bool apply_tx)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&regs->command_config);
++      if (apply_rx)
++              tmp |= CMD_CFG_RX_EN;
++      if (apply_tx)
++              tmp |= CMD_CFG_TX_EN;
++      iowrite32be(tmp, &regs->command_config);
++}
++
++void fman_tgec_disable(struct tgec_regs *regs, bool apply_rx, bool apply_tx)
++{
++      uint32_t tmp_reg_32;
++
++      tmp_reg_32 = ioread32be(&regs->command_config);
++      if (apply_rx)
++              tmp_reg_32 &= ~CMD_CFG_RX_EN;
++      if (apply_tx)
++              tmp_reg_32 &= ~CMD_CFG_TX_EN;
++      iowrite32be(tmp_reg_32, &regs->command_config);
++}
++
++void fman_tgec_set_promiscuous(struct tgec_regs *regs, bool val)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&regs->command_config);
++      if (val)
++              tmp |= CMD_CFG_PROMIS_EN;
++      else
++              tmp &= ~CMD_CFG_PROMIS_EN;
++      iowrite32be(tmp, &regs->command_config);
++}
++
++void fman_tgec_reset_filter_table(struct tgec_regs *regs)
++{
++      uint32_t i;
++      for (i = 0; i < 512; i++)
++              iowrite32be(i & ~TGEC_HASH_MCAST_EN, &regs->hashtable_ctrl);
++}
++
++void fman_tgec_set_hash_table_entry(struct tgec_regs *regs, uint32_t crc)
++{
++    uint32_t hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK;        /* Take 9 MSB bits */
++      iowrite32be(hash | TGEC_HASH_MCAST_EN, &regs->hashtable_ctrl);
++}
++
++void fman_tgec_set_hash_table(struct tgec_regs *regs, uint32_t value)
++{
++      iowrite32be(value, &regs->hashtable_ctrl);
++}
++
++void fman_tgec_set_tx_pause_frames(struct tgec_regs *regs, uint16_t pause_time)
++{
++      iowrite32be((uint32_t)pause_time, &regs->pause_quant);
++}
++
++void fman_tgec_set_rx_ignore_pause_frames(struct tgec_regs *regs, bool en)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&regs->command_config);
++      if (en)
++              tmp |= CMD_CFG_PAUSE_IGNORE;
++      else
++              tmp &= ~CMD_CFG_PAUSE_IGNORE;
++      iowrite32be(tmp, &regs->command_config);
++}
++
++void fman_tgec_enable_1588_time_stamp(struct tgec_regs *regs, bool en)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&regs->command_config);
++      if (en)
++              tmp |= CMD_CFG_EN_TIMESTAMP;
++      else
++              tmp &= ~CMD_CFG_EN_TIMESTAMP;
++      iowrite32be(tmp, &regs->command_config);
++}
++
++uint32_t fman_tgec_get_event(struct tgec_regs *regs, uint32_t ev_mask)
++{
++      return ioread32be(&regs->ievent) & ev_mask;
++}
++
++void fman_tgec_ack_event(struct tgec_regs *regs, uint32_t ev_mask)
++{
++      iowrite32be(ev_mask, &regs->ievent);
++}
++
++uint32_t fman_tgec_get_interrupt_mask(struct tgec_regs *regs)
++{
++      return ioread32be(&regs->imask);
++}
++
++void fman_tgec_add_addr_in_paddr(struct tgec_regs *regs, uint8_t *adr)
++{
++      uint32_t tmp0, tmp1;
++
++      tmp0 = (uint32_t)(adr[0] |
++                      adr[1] << 8 |
++                      adr[2] << 16 |
++                      adr[3] << 24);
++      tmp1 = (uint32_t)(adr[4] | adr[5] << 8);
++      iowrite32be(tmp0, &regs->mac_addr_2);
++      iowrite32be(tmp1, &regs->mac_addr_3);
++}
++
++void fman_tgec_clear_addr_in_paddr(struct tgec_regs *regs)
++{
++      iowrite32be(0, &regs->mac_addr_2);
++      iowrite32be(0, &regs->mac_addr_3);
++}
++
++uint32_t fman_tgec_get_revision(struct tgec_regs *regs)
++{
++      return ioread32be(&regs->tgec_id);
++}
++
++void fman_tgec_enable_interrupt(struct tgec_regs *regs, uint32_t ev_mask)
++{
++      iowrite32be(ioread32be(&regs->imask) | ev_mask, &regs->imask);
++}
++
++void fman_tgec_disable_interrupt(struct tgec_regs *regs, uint32_t ev_mask)
++{
++      iowrite32be(ioread32be(&regs->imask) & ~ev_mask, &regs->imask);
++}
++
++uint16_t fman_tgec_get_max_frame_len(struct tgec_regs *regs)
++{
++      return (uint16_t) ioread32be(&regs->maxfrm);
++}
++
++void fman_tgec_defconfig(struct tgec_cfg *cfg)
++{
++      cfg->wan_mode_enable = DEFAULT_WAN_MODE_ENABLE;
++      cfg->promiscuous_mode_enable = DEFAULT_PROMISCUOUS_MODE_ENABLE;
++      cfg->pause_forward_enable = DEFAULT_PAUSE_FORWARD_ENABLE;
++      cfg->pause_ignore = DEFAULT_PAUSE_IGNORE;
++      cfg->tx_addr_ins_enable = DEFAULT_TX_ADDR_INS_ENABLE;
++      cfg->loopback_enable = DEFAULT_LOOPBACK_ENABLE;
++      cfg->cmd_frame_enable = DEFAULT_CMD_FRAME_ENABLE;
++      cfg->rx_error_discard = DEFAULT_RX_ERROR_DISCARD;
++      cfg->send_idle_enable = DEFAULT_SEND_IDLE_ENABLE;
++      cfg->no_length_check_enable = DEFAULT_NO_LENGTH_CHECK_ENABLE;
++      cfg->lgth_check_nostdr = DEFAULT_LGTH_CHECK_NOSTDR;
++      cfg->time_stamp_enable = DEFAULT_TIME_STAMP_ENABLE;
++      cfg->tx_ipg_length = DEFAULT_TX_IPG_LENGTH;
++      cfg->max_frame_length = DEFAULT_MAX_FRAME_LENGTH;
++      cfg->pause_quant = DEFAULT_PAUSE_QUANT;
++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
++      cfg->skip_fman11_workaround = FALSE;
++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
++}
++
++int fman_tgec_init(struct tgec_regs *regs, struct tgec_cfg *cfg,
++              uint32_t exception_mask)
++{
++      uint32_t tmp;
++
++      /* Config */
++      tmp = 0x40; /* CRC forward */
++      if (cfg->wan_mode_enable)
++              tmp |= CMD_CFG_WAN_MODE;
++      if (cfg->promiscuous_mode_enable)
++              tmp |= CMD_CFG_PROMIS_EN;
++      if (cfg->pause_forward_enable)
++              tmp |= CMD_CFG_PAUSE_FWD;
++      if (cfg->pause_ignore)
++              tmp |= CMD_CFG_PAUSE_IGNORE;
++      if (cfg->tx_addr_ins_enable)
++              tmp |= CMD_CFG_TX_ADDR_INS;
++      if (cfg->loopback_enable)
++              tmp |= CMD_CFG_LOOPBACK_EN;
++      if (cfg->cmd_frame_enable)
++              tmp |= CMD_CFG_CMD_FRM_EN;
++      if (cfg->rx_error_discard)
++              tmp |= CMD_CFG_RX_ER_DISC;
++      if (cfg->send_idle_enable)
++              tmp |= CMD_CFG_SEND_IDLE;
++      if (cfg->no_length_check_enable)
++              tmp |= CMD_CFG_NO_LEN_CHK;
++      if (cfg->time_stamp_enable)
++              tmp |= CMD_CFG_EN_TIMESTAMP;
++      iowrite32be(tmp, &regs->command_config);
++
++      /* Max Frame Length */
++      iowrite32be((uint32_t)cfg->max_frame_length, &regs->maxfrm);
++      /* Pause Time */
++      iowrite32be(cfg->pause_quant, &regs->pause_quant);
++
++      /* clear all pending events and set-up interrupts */
++      fman_tgec_ack_event(regs, 0xffffffff);
++      fman_tgec_enable_interrupt(regs, exception_mask);
++
++      return 0;
++}
++
++void fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(struct tgec_regs *regs)
++{
++      uint32_t tmp;
++
++      /* restore the default tx ipg Length */
++      tmp = (ioread32be(&regs->tx_ipg_len) & ~TGEC_TX_IPG_LENGTH_MASK) | 12;
++
++      iowrite32be(tmp, &regs->tx_ipg_len);
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c
+@@ -0,0 +1,1096 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          memac.c
++
++ @Description   FM mEMAC driver
++*//***************************************************************************/
++
++#include "std_ext.h"
++#include "string_ext.h"
++#include "error_ext.h"
++#include "xx_ext.h"
++#include "endian_ext.h"
++#include "debug_ext.h"
++
++#include "fm_common.h"
++#include "memac.h"
++
++
++/*****************************************************************************/
++/*                      Internal routines                                    */
++/*****************************************************************************/
++
++/* ......................................................................... */
++
++static uint32_t GetMacAddrHashCode(uint64_t ethAddr)
++{
++    uint64_t    mask1, mask2;
++    uint32_t    xorVal = 0;
++    uint8_t     i, j;
++
++    for (i=0; i<6; i++)
++    {
++        mask1 = ethAddr & (uint64_t)0x01;
++        ethAddr >>= 1;
++
++        for (j=0; j<7; j++)
++        {
++            mask2 = ethAddr & (uint64_t)0x01;
++            mask1 ^= mask2;
++            ethAddr >>= 1;
++        }
++
++        xorVal |= (mask1 << (5-i));
++    }
++
++    return xorVal;
++}
++
++/* ......................................................................... */
++
++static void SetupSgmiiInternalPhy(t_Memac *p_Memac, uint8_t phyAddr)
++{
++    uint16_t    tmpReg16;
++    e_EnetMode  enetMode;
++
++     /* In case the higher MACs are used (i.e. the MACs that should support 10G),
++        speed=10000 is provided for SGMII ports. Temporary modify enet mode
++        to 1G one, so MII functions can work correctly. */
++    enetMode = p_Memac->enetMode;
++
++    /* SGMII mode + AN enable */
++    tmpReg16 = PHY_SGMII_IF_MODE_AN | PHY_SGMII_IF_MODE_SGMII;
++    if ((p_Memac->enetMode) == e_ENET_MODE_SGMII_2500)
++        tmpReg16 = PHY_SGMII_CR_PHY_RESET | PHY_SGMII_IF_SPEED_GIGABIT | PHY_SGMII_IF_MODE_SGMII;
++
++    p_Memac->enetMode = MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_Memac->enetMode), e_ENET_SPEED_1000);
++    MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x14, tmpReg16);
++
++    /* Device ability according to SGMII specification */
++    tmpReg16 = PHY_SGMII_DEV_ABILITY_SGMII;
++    MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x4, tmpReg16);
++
++    /* Adjust link timer for SGMII  -
++       According to Cisco SGMII specification the timer should be 1.6 ms.
++       The link_timer register is configured in units of the clock.
++       - When running as 1G SGMII, Serdes clock is 125 MHz, so
++         unit = 1 / (125*10^6 Hz) = 8 ns.
++         1.6 ms in units of 8 ns = 1.6ms / 8ns = 2 * 10^5 = 0x30d40
++       - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so
++         unit = 1 / (312.5*10^6 Hz) = 3.2 ns.
++         1.6 ms in units of 3.2 ns = 1.6ms / 3.2ns = 5 * 10^5 = 0x7a120.
++       Since link_timer value of 1G SGMII will be too short for 2.5 SGMII,
++       we always set up here a value of 2.5 SGMII. */
++    MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x13, 0x0007);
++    MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x12, 0xa120);
++
++    /* Restart AN */
++    tmpReg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN;
++    MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x0, tmpReg16);
++
++    /* Restore original enet mode */
++    p_Memac->enetMode = enetMode;
++}
++
++/* ......................................................................... */
++
++static void SetupSgmiiInternalPhyBaseX(t_Memac *p_Memac, uint8_t phyAddr)
++{
++    uint16_t    tmpReg16;
++    e_EnetMode  enetMode;
++
++     /* In case the higher MACs are used (i.e. the MACs that should support 10G),
++        speed=10000 is provided for SGMII ports. Temporary modify enet mode
++        to 1G one, so MII functions can work correctly. */
++    enetMode = p_Memac->enetMode;
++    p_Memac->enetMode = MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_Memac->enetMode), e_ENET_SPEED_1000);
++
++    /* 1000BaseX mode */
++    tmpReg16 = PHY_SGMII_IF_MODE_1000X;
++    MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x14, tmpReg16);
++
++    /* AN Device capability  */
++    tmpReg16 = PHY_SGMII_DEV_ABILITY_1000X;
++    MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x4, tmpReg16);
++
++    /* Adjust link timer for SGMII  -
++       For Serdes 1000BaseX auto-negotiation the timer should be 10 ms.
++       The link_timer register is configured in units of the clock.
++       - When running as 1G SGMII, Serdes clock is 125 MHz, so
++         unit = 1 / (125*10^6 Hz) = 8 ns.
++         10 ms in units of 8 ns = 10ms / 8ns = 1250000 = 0x1312d0
++       - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so
++         unit = 1 / (312.5*10^6 Hz) = 3.2 ns.
++         10 ms in units of 3.2 ns = 10ms / 3.2ns = 3125000 = 0x2faf08.
++       Since link_timer value of 1G SGMII will be too short for 2.5 SGMII,
++       we always set up here a value of 2.5 SGMII. */
++    MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x13, 0x002f);
++    MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x12, 0xaf08);
++
++    /* Restart AN */
++    tmpReg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN;
++    MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x0, tmpReg16);
++
++    /* Restore original enet mode */
++    p_Memac->enetMode = enetMode;
++}
++
++/* ......................................................................... */
++
++static t_Error CheckInitParameters(t_Memac *p_Memac)
++{
++    e_FmMacType portType;
++
++    portType = ((ENET_SPEED_FROM_MODE(p_Memac->enetMode) < e_ENET_SPEED_10000) ? e_FM_MAC_1G : e_FM_MAC_10G);
++
++#if (FM_MAX_NUM_OF_10G_MACS > 0)
++    if ((portType == e_FM_MAC_10G) && (p_Memac->macId >= FM_MAX_NUM_OF_10G_MACS))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("10G MAC ID must be less than %d", FM_MAX_NUM_OF_10G_MACS));
++#endif /* (FM_MAX_NUM_OF_10G_MACS > 0) */
++
++    if ((portType == e_FM_MAC_1G) && (p_Memac->macId >= FM_MAX_NUM_OF_1G_MACS))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("1G MAC ID must be less than %d", FM_MAX_NUM_OF_1G_MACS));
++    if (p_Memac->addr == 0)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC must have a valid MAC address"));
++    if (!p_Memac->f_Exception)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Uninitialized f_Exception"));
++    if (!p_Memac->f_Event)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Uninitialized f_Event"));
++#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002
++    if (!p_Memac->p_MemacDriverParam->no_length_check_enable)
++       RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!"));
++#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */
++
++    return E_OK;
++}
++
++/* ........................................................................... */
++
++static void MemacErrException(t_Handle h_Memac)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++    uint32_t    event, imask;
++
++    event = fman_memac_get_event(p_Memac->p_MemMap, 0xffffffff);
++    imask = fman_memac_get_interrupt_mask(p_Memac->p_MemMap);
++
++    /* Imask include both error and notification/event bits.
++       Leaving only error bits enabled by imask.
++       The imask error bits are shifted by 16 bits offset from
++       their corresponding location in the ievent - hence the >> 16 */
++    event &= ((imask & MEMAC_ALL_ERRS_IMASK) >> 16);
++
++    fman_memac_ack_event(p_Memac->p_MemMap, event);
++
++    if (event & MEMAC_IEVNT_TS_ECC_ER)
++        p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_TS_FIFO_ECC_ERR);
++    if (event & MEMAC_IEVNT_TX_ECC_ER)
++        p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_10G_1TX_ECC_ER);
++    if (event & MEMAC_IEVNT_RX_ECC_ER)
++        p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_10G_RX_ECC_ER);
++}
++
++static void MemacException(t_Handle h_Memac)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++    uint32_t    event, imask;
++
++    event = fman_memac_get_event(p_Memac->p_MemMap, 0xffffffff);
++    imask = fman_memac_get_interrupt_mask(p_Memac->p_MemMap);
++
++    /* Imask include both error and notification/event bits.
++       Leaving only error bits enabled by imask.
++       The imask error bits are shifted by 16 bits offset from
++       their corresponding location in the ievent - hence the >> 16 */
++    event &= ((imask & MEMAC_ALL_ERRS_IMASK) >> 16);
++
++    fman_memac_ack_event(p_Memac->p_MemMap, event);
++
++    if (event & MEMAC_IEVNT_MGI)
++        p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_MAGIC_PACKET_INDICATION);
++}
++
++/* ......................................................................... */
++
++static void FreeInitResources(t_Memac *p_Memac)
++{
++    e_FmMacType portType;
++
++    portType =
++        ((ENET_SPEED_FROM_MODE(p_Memac->enetMode) < e_ENET_SPEED_10000) ? e_FM_MAC_1G : e_FM_MAC_10G);
++
++    if (portType == e_FM_MAC_10G)
++        FmUnregisterIntr(p_Memac->fmMacControllerDriver.h_Fm, e_FM_MOD_10G_MAC, p_Memac->macId, e_FM_INTR_TYPE_ERR);
++    else
++        FmUnregisterIntr(p_Memac->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Memac->macId, e_FM_INTR_TYPE_ERR);
++
++    /* release the driver's group hash table */
++    FreeHashTable(p_Memac->p_MulticastAddrHash);
++    p_Memac->p_MulticastAddrHash =   NULL;
++
++    /* release the driver's individual hash table */
++    FreeHashTable(p_Memac->p_UnicastAddrHash);
++    p_Memac->p_UnicastAddrHash =     NULL;
++}
++
++
++/*****************************************************************************/
++/*                     mEMAC API routines                                    */
++/*****************************************************************************/
++
++/* ......................................................................... */
++
++static t_Error MemacEnable(t_Handle h_Memac,  e_CommMode mode)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    fman_memac_enable(p_Memac->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX));
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error MemacDisable (t_Handle h_Memac, e_CommMode mode)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    fman_memac_disable(p_Memac->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX));
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error MemacSetPromiscuous(t_Handle h_Memac, bool newVal)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    fman_memac_set_promiscuous(p_Memac->p_MemMap, newVal);
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error MemacAdjustLink(t_Handle h_Memac, e_EnetSpeed speed, bool fullDuplex)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    if ((speed >= e_ENET_SPEED_1000) && (!fullDuplex))
++        RETURN_ERROR(MAJOR, E_CONFLICT,
++                     ("Ethernet MAC 1G or 10G does not support half-duplex"));
++
++    fman_memac_adjust_link(p_Memac->p_MemMap,
++                           (enum enet_interface)ENET_INTERFACE_FROM_MODE(p_Memac->enetMode),
++                           (enum enet_speed)speed,
++                           fullDuplex);
++    return E_OK;
++}
++
++
++/*****************************************************************************/
++/*                      Memac Configs modification functions                 */
++/*****************************************************************************/
++
++/* ......................................................................... */
++
++static t_Error MemacConfigLoopback(t_Handle h_Memac, bool newVal)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    p_Memac->p_MemacDriverParam->loopback_enable = newVal;
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error MemacConfigWan(t_Handle h_Memac, bool newVal)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    p_Memac->p_MemacDriverParam->wan_mode_enable = newVal;
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error MemacConfigMaxFrameLength(t_Handle h_Memac, uint16_t newVal)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    p_Memac->p_MemacDriverParam->max_frame_length = newVal;
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error MemacConfigPad(t_Handle h_Memac, bool newVal)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    p_Memac->p_MemacDriverParam->pad_enable = newVal;
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error MemacConfigLengthCheck(t_Handle h_Memac, bool newVal)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    p_Memac->p_MemacDriverParam->no_length_check_enable = !newVal;
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error MemacConfigException(t_Handle h_Memac, e_FmMacExceptions exception, bool enable)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++    uint32_t    bitMask = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    GET_EXCEPTION_FLAG(bitMask, exception);
++    if (bitMask)
++    {
++        if (enable)
++            p_Memac->exceptions |= bitMask;
++        else
++            p_Memac->exceptions &= ~bitMask;
++    }
++    else
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error MemacConfigResetOnInit(t_Handle h_Memac, bool enable)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    p_Memac->p_MemacDriverParam->reset_on_init = enable;
++
++    return E_OK;
++}
++
++
++/*****************************************************************************/
++/*                      Memac Run Time API functions                         */
++/*****************************************************************************/
++
++/* ......................................................................... */
++
++static t_Error MemacSetTxPauseFrames(t_Handle h_Memac,
++                                     uint8_t  priority,
++                                     uint16_t pauseTime,
++                                     uint16_t threshTime)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    if (priority != 0xFF)
++    {
++        bool   PortConfigured, PreFetchEnabled;
++
++        if (FmGetTnumAgingPeriod(p_Memac->fmMacControllerDriver.h_Fm) == 0)
++            RETURN_ERROR(MAJOR, E_CONFLICT, ("For PFC operation, TNUM aging must be enabled"));
++
++        FmGetPortPreFetchConfiguration(p_Memac->fmMacControllerDriver.h_Fm,
++                                       p_Memac->fmMacControllerDriver.macId,
++                                       &PortConfigured,
++                                       &PreFetchEnabled);
++
++        if ((ENET_SPEED_FROM_MODE(p_Memac->fmMacControllerDriver.enetMode) == e_ENET_SPEED_1000) && !PortConfigured)
++            DBG(INFO, ("For PFC correct operation, prefetch must be configured on the FM Tx PORT"));
++
++        if ((ENET_SPEED_FROM_MODE(p_Memac->fmMacControllerDriver.enetMode) == e_ENET_SPEED_1000) && PortConfigured && !PreFetchEnabled)
++            DBG(WARNING, ("For PFC correct operation, prefetch must be configured on the FM Tx PORT"));
++    }
++
++    fman_memac_set_tx_pause_frames(p_Memac->p_MemMap, priority, pauseTime, threshTime);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error MemacSetTxAutoPauseFrames(t_Handle h_Memac,
++                                         uint16_t pauseTime)
++{
++    return MemacSetTxPauseFrames(h_Memac, FM_MAC_NO_PFC, pauseTime, 0);
++}
++
++/* ......................................................................... */
++
++static t_Error MemacSetRxIgnorePauseFrames(t_Handle h_Memac, bool en)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    fman_memac_set_rx_ignore_pause_frames(p_Memac->p_MemMap, en);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error MemacSetWakeOnLan(t_Handle h_Memac, bool en)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    fman_memac_set_wol(p_Memac->p_MemMap, en);
++
++    return E_OK;
++}
++
++/* .............................................................................. */
++
++static t_Error MemacEnable1588TimeStamp(t_Handle h_Memac)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++UNUSED(p_Memac);
++DBG(WARNING, ("mEMAC has 1588 always enabled!"));
++
++    return E_OK;
++}
++
++/* Counters handling */
++/* ......................................................................... */
++
++static t_Error MemacGetStatistics(t_Handle h_Memac, t_FmMacStatistics *p_Statistics)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER);
++
++    p_Statistics->eStatPkts64           = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R64);
++    p_Statistics->eStatPkts65to127      = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R127);
++    p_Statistics->eStatPkts128to255     = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R255);
++    p_Statistics->eStatPkts256to511     = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R511);
++    p_Statistics->eStatPkts512to1023    = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1023);
++    p_Statistics->eStatPkts1024to1518   = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1518);
++    p_Statistics->eStatPkts1519to1522   = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1519X);
++/* */
++    p_Statistics->eStatFragments        = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RFRG);
++    p_Statistics->eStatJabbers          = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RJBR);
++
++    p_Statistics->eStatsDropEvents      = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RDRP);
++    p_Statistics->eStatCRCAlignErrors   = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RALN);
++
++    p_Statistics->eStatUndersizePkts    = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TUND);
++    p_Statistics->eStatOversizePkts     = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_ROVR);
++/* Pause */
++    p_Statistics->reStatPause           = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RXPF);
++    p_Statistics->teStatPause           = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TXPF);
++
++/* MIB II */
++    p_Statistics->ifInOctets            = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_ROCT);
++    p_Statistics->ifInUcastPkts         = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RUCA);
++    p_Statistics->ifInMcastPkts         = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RMCA);
++    p_Statistics->ifInBcastPkts         = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RBCA);
++    p_Statistics->ifInPkts              = p_Statistics->ifInUcastPkts
++                                        + p_Statistics->ifInMcastPkts
++                                        + p_Statistics->ifInBcastPkts;
++    p_Statistics->ifInDiscards          = 0;
++    p_Statistics->ifInErrors            = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RERR);
++
++    p_Statistics->ifOutOctets           = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TOCT);
++    p_Statistics->ifOutUcastPkts        = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TUCA);
++    p_Statistics->ifOutMcastPkts        = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TMCA);
++    p_Statistics->ifOutBcastPkts        = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TBCA);
++    p_Statistics->ifOutPkts             = p_Statistics->ifOutUcastPkts
++                                        + p_Statistics->ifOutMcastPkts
++                                        + p_Statistics->ifOutBcastPkts;
++    p_Statistics->ifOutDiscards         = 0;
++    p_Statistics->ifOutErrors           = fman_memac_get_counter(p_Memac->p_MemMap,  E_MEMAC_COUNTER_TERR);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error MemacModifyMacAddress (t_Handle h_Memac, t_EnetAddr *p_EnetAddr)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    fman_memac_add_addr_in_paddr(p_Memac->p_MemMap, (uint8_t *)(*p_EnetAddr), 0);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error MemacResetCounters (t_Handle h_Memac)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    fman_memac_reset_stat(p_Memac->p_MemMap);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error MemacAddExactMatchMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr)
++{
++    t_Memac     *p_Memac = (t_Memac *) h_Memac;
++    uint64_t    ethAddr;
++    uint8_t     paddrNum;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
++
++    if (ethAddr & GROUP_ADDRESS)
++        /* Multicast address has no effect in PADDR */
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address"));
++
++    /* Make sure no PADDR contains this address */
++    for (paddrNum = 0; paddrNum < MEMAC_NUM_OF_PADDRS; paddrNum++)
++        if (p_Memac->indAddrRegUsed[paddrNum])
++            if (p_Memac->paddr[paddrNum] == ethAddr)
++                RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
++
++    /* Find first unused PADDR */
++    for (paddrNum = 0; paddrNum < MEMAC_NUM_OF_PADDRS; paddrNum++)
++        if (!(p_Memac->indAddrRegUsed[paddrNum]))
++        {
++            /* mark this PADDR as used */
++            p_Memac->indAddrRegUsed[paddrNum] = TRUE;
++            /* store address */
++            p_Memac->paddr[paddrNum] = ethAddr;
++
++            /* put in hardware */
++            fman_memac_add_addr_in_paddr(p_Memac->p_MemMap, (uint8_t*)(*p_EthAddr), paddrNum);
++            p_Memac->numOfIndAddrInRegs++;
++
++            return E_OK;
++        }
++
++    /* No free PADDR */
++    RETURN_ERROR(MAJOR, E_FULL, NO_MSG);
++}
++
++/* ......................................................................... */
++
++static t_Error MemacDelExactMatchMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr)
++{
++    t_Memac     *p_Memac = (t_Memac *) h_Memac;
++    uint64_t    ethAddr;
++    uint8_t     paddrNum;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
++
++    /* Find used PADDR containing this address */
++    for (paddrNum = 0; paddrNum < MEMAC_NUM_OF_PADDRS; paddrNum++)
++    {
++        if ((p_Memac->indAddrRegUsed[paddrNum]) &&
++            (p_Memac->paddr[paddrNum] == ethAddr))
++        {
++            /* mark this PADDR as not used */
++            p_Memac->indAddrRegUsed[paddrNum] = FALSE;
++            /* clear in hardware */
++            fman_memac_clear_addr_in_paddr(p_Memac->p_MemMap, paddrNum);
++            p_Memac->numOfIndAddrInRegs--;
++
++            return E_OK;
++        }
++    }
++
++    RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG);
++}
++
++/* ......................................................................... */
++
++static t_Error MemacGetId(t_Handle h_Memac, uint32_t *macId)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    *macId = p_Memac->macId;
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++
++static t_Error MemacAddHashMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr)
++{
++    t_Memac             *p_Memac = (t_Memac *)h_Memac;
++    t_EthHashEntry      *p_HashEntry;
++    uint32_t            hash;
++    uint64_t            ethAddr;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
++
++    if (!(ethAddr & GROUP_ADDRESS))
++        /* Unicast addresses not supported in hash */
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unicast Address"));
++
++    hash = GetMacAddrHashCode(ethAddr) & HASH_CTRL_ADDR_MASK;
++
++    /* Create element to be added to the driver hash table */
++    p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry));
++    p_HashEntry->addr = ethAddr;
++    INIT_LIST(&p_HashEntry->node);
++
++    LIST_AddToTail(&(p_HashEntry->node), &(p_Memac->p_MulticastAddrHash->p_Lsts[hash]));
++    fman_memac_set_hash_table(p_Memac->p_MemMap, (hash | HASH_CTRL_MCAST_EN));
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error MemacDelHashMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr)
++{
++    t_Memac             *p_Memac = (t_Memac *)h_Memac;
++    t_EthHashEntry      *p_HashEntry = NULL;
++    t_List              *p_Pos;
++    uint32_t            hash;
++    uint64_t            ethAddr;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
++
++    hash = GetMacAddrHashCode(ethAddr) & HASH_CTRL_ADDR_MASK;
++
++    LIST_FOR_EACH(p_Pos, &(p_Memac->p_MulticastAddrHash->p_Lsts[hash]))
++    {
++        p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos);
++        if (p_HashEntry->addr == ethAddr)
++        {
++            LIST_DelAndInit(&p_HashEntry->node);
++            XX_Free(p_HashEntry);
++            break;
++        }
++    }
++    if (LIST_IsEmpty(&p_Memac->p_MulticastAddrHash->p_Lsts[hash]))
++        fman_memac_set_hash_table(p_Memac->p_MemMap, (hash & ~HASH_CTRL_MCAST_EN));
++
++    return E_OK;
++}
++
++
++/* ......................................................................... */
++
++static t_Error MemacSetException(t_Handle h_Memac, e_FmMacExceptions exception, bool enable)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++    uint32_t    bitMask = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++
++    GET_EXCEPTION_FLAG(bitMask, exception);
++    if (bitMask)
++    {
++        if (enable)
++            p_Memac->exceptions |= bitMask;
++        else
++            p_Memac->exceptions &= ~bitMask;
++    }
++    else
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
++
++    fman_memac_set_exception(p_Memac->p_MemMap, bitMask, enable);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static uint16_t MemacGetMaxFrameLength(t_Handle h_Memac)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_VALUE(p_Memac, E_INVALID_HANDLE, 0);
++    SANITY_CHECK_RETURN_VALUE(!p_Memac->p_MemacDriverParam, E_INVALID_STATE, 0);
++
++    return fman_memac_get_max_frame_len(p_Memac->p_MemMap);
++}
++
++static t_Error MemacInitInternalPhy(t_Handle h_Memac)
++{
++    t_Memac *p_Memac = (t_Memac *)h_Memac;
++    uint8_t i, phyAddr;
++
++    if (ENET_INTERFACE_FROM_MODE(p_Memac->enetMode) == e_ENET_IF_SGMII)
++    {
++        /* Configure internal SGMII PHY */
++        if (p_Memac->enetMode & ENET_IF_SGMII_BASEX)
++            SetupSgmiiInternalPhyBaseX(p_Memac, PHY_MDIO_ADDR);
++        else
++            SetupSgmiiInternalPhy(p_Memac, PHY_MDIO_ADDR);
++    }
++    else if (ENET_INTERFACE_FROM_MODE(p_Memac->enetMode) == e_ENET_IF_QSGMII)
++    {
++        /* Configure 4 internal SGMII PHYs */
++        for (i = 0; i < 4; i++)
++        {
++            /* QSGMII PHY address occupies 3 upper bits of 5-bit
++               phyAddress; the lower 2 bits are used to extend
++               register address space and access each one of 4
++               ports inside QSGMII. */
++            phyAddr = (uint8_t)((PHY_MDIO_ADDR << 2) | i);
++            if (p_Memac->enetMode & ENET_IF_SGMII_BASEX)
++                SetupSgmiiInternalPhyBaseX(p_Memac, phyAddr);
++            else
++                SetupSgmiiInternalPhy(p_Memac, phyAddr);
++        }
++    }
++    return E_OK;
++}
++
++/*****************************************************************************/
++/*                      mEMAC Init & Free API                                   */
++/*****************************************************************************/
++
++/* ......................................................................... */
++void *g_MemacRegs;
++static t_Error MemacInit(t_Handle h_Memac)
++{
++    t_Memac                 *p_Memac = (t_Memac *)h_Memac;
++    struct memac_cfg        *p_MemacDriverParam;
++    enum enet_interface     enet_interface;
++    enum enet_speed         enet_speed;
++    t_EnetAddr              ethAddr;
++    e_FmMacType             portType;
++    t_Error                 err;
++    bool                    slow_10g_if = FALSE;
++    if (p_Memac->macId == 3) /* This is a quick WA */
++              g_MemacRegs = p_Memac->p_MemMap;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_Memac->fmMacControllerDriver.h_Fm, E_INVALID_HANDLE);
++
++    FM_GetRevision(p_Memac->fmMacControllerDriver.h_Fm, &p_Memac->fmMacControllerDriver.fmRevInfo);
++    if (p_Memac->fmMacControllerDriver.fmRevInfo.majorRev == 6 &&
++        p_Memac->fmMacControllerDriver.fmRevInfo.minorRev == 4)
++        slow_10g_if = TRUE;
++
++    CHECK_INIT_PARAMETERS(p_Memac, CheckInitParameters);
++
++    p_MemacDriverParam = p_Memac->p_MemacDriverParam;
++
++    portType =
++        ((ENET_SPEED_FROM_MODE(p_Memac->enetMode) < e_ENET_SPEED_10000) ? e_FM_MAC_1G : e_FM_MAC_10G);
++
++    /* First, reset the MAC if desired. */
++    if (p_MemacDriverParam->reset_on_init)
++        fman_memac_reset(p_Memac->p_MemMap);
++
++    /* MAC Address */
++    MAKE_ENET_ADDR_FROM_UINT64(p_Memac->addr, ethAddr);
++    fman_memac_add_addr_in_paddr(p_Memac->p_MemMap, (uint8_t*)ethAddr, 0);
++
++    enet_interface = (enum enet_interface) ENET_INTERFACE_FROM_MODE(p_Memac->enetMode);
++    enet_speed = (enum enet_speed) ENET_SPEED_FROM_MODE(p_Memac->enetMode);
++
++    fman_memac_init(p_Memac->p_MemMap,
++               p_Memac->p_MemacDriverParam,
++               enet_interface,
++               enet_speed,
++               slow_10g_if,
++               p_Memac->exceptions);
++
++#ifdef FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320
++    {
++      uint32_t tmpReg = 0;
++
++      FM_GetRevision(p_Memac->fmMacControllerDriver.h_Fm, &p_Memac->fmMacControllerDriver.fmRevInfo);
++        /* check the FMAN version - the bug exists only in rev1 */
++        if ((p_Memac->fmMacControllerDriver.fmRevInfo.majorRev == 6) &&
++              (p_Memac->fmMacControllerDriver.fmRevInfo.minorRev == 0))
++        {
++              /* MAC strips CRC from received frames - this workaround should
++                 decrease the likelihood of bug appearance
++            */
++                      tmpReg = GET_UINT32(p_Memac->p_MemMap->command_config);
++                      tmpReg &= ~CMD_CFG_CRC_FWD;
++                      WRITE_UINT32(p_Memac->p_MemMap->command_config, tmpReg);
++                      /* DBG(WARNING, ("mEMAC strips CRC from received frames as part of A006320 errata workaround"));*/
++        }
++    }
++#endif /* FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 */
++
++    MemacInitInternalPhy(h_Memac);
++
++    /* Max Frame Length */
++    err = FmSetMacMaxFrame(p_Memac->fmMacControllerDriver.h_Fm,
++                           portType,
++                           p_Memac->fmMacControllerDriver.macId,
++                           p_MemacDriverParam->max_frame_length);
++    if (err)
++        RETURN_ERROR(MAJOR, err, ("settings Mac max frame length is FAILED"));
++
++    p_Memac->p_MulticastAddrHash = AllocHashTable(HASH_TABLE_SIZE);
++    if (!p_Memac->p_MulticastAddrHash)
++    {
++        FreeInitResources(p_Memac);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED"));
++    }
++
++    p_Memac->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE);
++    if (!p_Memac->p_UnicastAddrHash)
++    {
++        FreeInitResources(p_Memac);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED"));
++    }
++
++    FmRegisterIntr(p_Memac->fmMacControllerDriver.h_Fm,
++                   (portType == e_FM_MAC_10G) ? e_FM_MOD_10G_MAC : e_FM_MOD_1G_MAC,
++                   p_Memac->macId,
++                   e_FM_INTR_TYPE_ERR,
++                   MemacErrException,
++                   p_Memac);
++
++    FmRegisterIntr(p_Memac->fmMacControllerDriver.h_Fm,
++                   (portType == e_FM_MAC_10G) ? e_FM_MOD_10G_MAC : e_FM_MOD_1G_MAC,
++                   p_Memac->macId,
++                   e_FM_INTR_TYPE_NORMAL,
++                   MemacException,
++                   p_Memac);
++
++    XX_Free(p_MemacDriverParam);
++    p_Memac->p_MemacDriverParam = NULL;
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error MemacFree(t_Handle h_Memac)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++
++    if (p_Memac->p_MemacDriverParam)
++    {
++        /* Called after config */
++        XX_Free(p_Memac->p_MemacDriverParam);
++        p_Memac->p_MemacDriverParam = NULL;
++    }
++    else
++        /* Called after init */
++        FreeInitResources(p_Memac);
++
++    XX_Free(p_Memac);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver)
++{
++    p_FmMacControllerDriver->f_FM_MAC_Init                      = MemacInit;
++    p_FmMacControllerDriver->f_FM_MAC_Free                      = MemacFree;
++
++    p_FmMacControllerDriver->f_FM_MAC_SetStatistics             = NULL;
++    p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback            = MemacConfigLoopback;
++    p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength      = MemacConfigMaxFrameLength;
++
++    p_FmMacControllerDriver->f_FM_MAC_ConfigWan                 = MemacConfigWan;
++
++    p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc           = MemacConfigPad;
++    p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex          = NULL; /* half-duplex is detected automatically */
++    p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck         = MemacConfigLengthCheck;
++
++    p_FmMacControllerDriver->f_FM_MAC_ConfigException           = MemacConfigException;
++    p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit         = MemacConfigResetOnInit;
++
++    p_FmMacControllerDriver->f_FM_MAC_SetException              = MemacSetException;
++
++    p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp       = MemacEnable1588TimeStamp; /* always enabled */
++    p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp      = NULL;
++
++    p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous            = MemacSetPromiscuous;
++    p_FmMacControllerDriver->f_FM_MAC_AdjustLink                = MemacAdjustLink;
++    p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg            = NULL;
++
++    p_FmMacControllerDriver->f_FM_MAC_Enable                    = MemacEnable;
++    p_FmMacControllerDriver->f_FM_MAC_Disable                   = MemacDisable;
++    p_FmMacControllerDriver->f_FM_MAC_Resume                    = MemacInitInternalPhy;
++
++    p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames      = MemacSetTxAutoPauseFrames;
++    p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames          = MemacSetTxPauseFrames;
++    p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames    = MemacSetRxIgnorePauseFrames;
++
++    p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan              = MemacSetWakeOnLan;
++
++    p_FmMacControllerDriver->f_FM_MAC_ResetCounters             = MemacResetCounters;
++    p_FmMacControllerDriver->f_FM_MAC_GetStatistics             = MemacGetStatistics;
++
++    p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr             = MemacModifyMacAddress;
++    p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr            = MemacAddHashMacAddress;
++    p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr         = MemacDelHashMacAddress;
++    p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr      = MemacAddExactMatchMacAddress;
++    p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr  = MemacDelExactMatchMacAddress;
++    p_FmMacControllerDriver->f_FM_MAC_GetId                     = MemacGetId;
++    p_FmMacControllerDriver->f_FM_MAC_GetVersion                = NULL;
++    p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength         = MemacGetMaxFrameLength;
++
++    p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg           = MEMAC_MII_WritePhyReg;
++    p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg            = MEMAC_MII_ReadPhyReg;
++}
++
++
++/*****************************************************************************/
++/*                      mEMAC Config Main Entry                             */
++/*****************************************************************************/
++
++/* ......................................................................... */
++
++t_Handle MEMAC_Config(t_FmMacParams *p_FmMacParam)
++{
++    t_Memac             *p_Memac;
++    struct memac_cfg    *p_MemacDriverParam;
++    uintptr_t           baseAddr;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL);
++
++    baseAddr = p_FmMacParam->baseAddr;
++    /* Allocate memory for the mEMAC data structure */
++    p_Memac = (t_Memac *)XX_Malloc(sizeof(t_Memac));
++    if (!p_Memac)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("mEMAC driver structure"));
++        return NULL;
++    }
++    memset(p_Memac, 0, sizeof(t_Memac));
++    InitFmMacControllerDriver(&p_Memac->fmMacControllerDriver);
++
++    /* Allocate memory for the mEMAC driver parameters data structure */
++    p_MemacDriverParam = (struct memac_cfg *)XX_Malloc(sizeof(struct memac_cfg));
++    if (!p_MemacDriverParam)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("mEMAC driver parameters"));
++        XX_Free(p_Memac);
++        return NULL;
++    }
++    memset(p_MemacDriverParam, 0, sizeof(struct memac_cfg));
++
++    /* Plant parameter structure pointer */
++    p_Memac->p_MemacDriverParam = p_MemacDriverParam;
++
++    fman_memac_defconfig(p_MemacDriverParam);
++
++    p_Memac->addr           = ENET_ADDR_TO_UINT64(p_FmMacParam->addr);
++
++    p_Memac->p_MemMap       = (struct memac_regs *)UINT_TO_PTR(baseAddr);
++    p_Memac->p_MiiMemMap    = (struct memac_mii_access_mem_map*)UINT_TO_PTR(baseAddr + MEMAC_TO_MII_OFFSET);
++
++    p_Memac->enetMode       = p_FmMacParam->enetMode;
++    p_Memac->macId          = p_FmMacParam->macId;
++    p_Memac->exceptions     = MEMAC_default_exceptions;
++    p_Memac->f_Exception    = p_FmMacParam->f_Exception;
++    p_Memac->f_Event        = p_FmMacParam->f_Event;
++    p_Memac->h_App          = p_FmMacParam->h_App;
++
++    return p_Memac;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h
+@@ -0,0 +1,110 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          memac.h
++
++ @Description   FM Multirate Ethernet MAC (mEMAC)
++*//***************************************************************************/
++#ifndef __MEMAC_H
++#define __MEMAC_H
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "list_ext.h"
++
++#include "fsl_fman_memac_mii_acc.h"
++#include "fm_mac.h"
++#include "fsl_fman_memac.h"
++
++
++#define MEMAC_default_exceptions    \
++        ((uint32_t)(MEMAC_IMASK_TSECC_ER | MEMAC_IMASK_TECC_ER | MEMAC_IMASK_RECC_ER | MEMAC_IMASK_MGI))
++
++#define GET_EXCEPTION_FLAG(bitMask, exception)       switch (exception){    \
++    case e_FM_MAC_EX_10G_1TX_ECC_ER:                                        \
++        bitMask = MEMAC_IMASK_TECC_ER; break;                               \
++    case e_FM_MAC_EX_10G_RX_ECC_ER:                                         \
++        bitMask = MEMAC_IMASK_RECC_ER; break;                               \
++    case e_FM_MAC_EX_TS_FIFO_ECC_ERR:                                       \
++        bitMask = MEMAC_IMASK_TSECC_ER; break;                              \
++    case e_FM_MAC_EX_MAGIC_PACKET_INDICATION:                               \
++        bitMask = MEMAC_IMASK_MGI; break;                                   \
++    default: bitMask = 0;break;}
++
++
++typedef struct
++{
++    t_FmMacControllerDriver     fmMacControllerDriver;               /**< Upper Mac control block */
++    t_Handle                    h_App;                               /**< Handle to the upper layer application  */
++    struct memac_regs           *p_MemMap;                           /**< Pointer to MAC memory mapped registers */
++    struct memac_mii_access_mem_map *p_MiiMemMap;                        /**< Pointer to MII memory mapped registers */
++    uint64_t                    addr;                                /**< MAC address of device */
++    e_EnetMode                  enetMode;                            /**< Ethernet physical interface  */
++    t_FmMacExceptionCallback    *f_Exception;
++    int                         mdioIrq;
++    t_FmMacExceptionCallback    *f_Event;
++    bool                        indAddrRegUsed[MEMAC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */
++    uint64_t                    paddr[MEMAC_NUM_OF_PADDRS];          /**< MAC address for particular individual address recognition register */
++    uint8_t                     numOfIndAddrInRegs;                  /**< Number of individual addresses in registers for this station. */
++    t_EthHash                   *p_MulticastAddrHash;                /**< Pointer to driver's global address hash table  */
++    t_EthHash                   *p_UnicastAddrHash;                  /**< Pointer to driver's individual address hash table  */
++    bool                        debugMode;
++    uint8_t                     macId;
++    uint32_t                    exceptions;
++    struct memac_cfg            *p_MemacDriverParam;
++} t_Memac;
++
++
++/* Internal PHY access */
++#define PHY_MDIO_ADDR               0
++
++/* Internal PHY Registers - SGMII */
++#define PHY_SGMII_CR_PHY_RESET          0x8000
++#define PHY_SGMII_CR_RESET_AN           0x0200
++#define PHY_SGMII_CR_DEF_VAL            0x1140
++#define PHY_SGMII_DEV_ABILITY_SGMII     0x4001
++#define PHY_SGMII_DEV_ABILITY_1000X     0x01A0
++#define PHY_SGMII_IF_SPEED_GIGABIT    0x0008
++#define PHY_SGMII_IF_MODE_AN            0x0002
++#define PHY_SGMII_IF_MODE_SGMII         0x0001
++#define PHY_SGMII_IF_MODE_1000X         0x0000
++
++
++#define MEMAC_TO_MII_OFFSET         0x030       /* Offset from the MEM map to the MDIO mem map */
++
++t_Error MEMAC_MII_WritePhyReg(t_Handle h_Memac, uint8_t phyAddr, uint8_t reg, uint16_t data);
++t_Error MEMAC_MII_ReadPhyReg(t_Handle h_Memac,  uint8_t phyAddr, uint8_t reg, uint16_t *p_Data);
++
++
++#endif /* __MEMAC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.c
+@@ -0,0 +1,78 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#include "error_ext.h"
++#include "std_ext.h"
++#include "fm_mac.h"
++#include "memac.h"
++#include "xx_ext.h"
++
++#include "fm_common.h"
++#include "memac_mii_acc.h"
++
++
++/*****************************************************************************/
++t_Error MEMAC_MII_WritePhyReg(t_Handle  h_Memac,
++                             uint8_t    phyAddr,
++                             uint8_t    reg,
++                             uint16_t   data)
++{
++    t_Memac                 *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Memac->p_MiiMemMap, E_INVALID_HANDLE);
++
++    return (t_Error)fman_memac_mii_write_phy_reg(p_Memac->p_MiiMemMap,
++                                                 phyAddr,
++                                                 reg,
++                                                 data,
++                                                 (enum enet_speed)ENET_SPEED_FROM_MODE(p_Memac->enetMode));
++}
++
++/*****************************************************************************/
++t_Error MEMAC_MII_ReadPhyReg(t_Handle h_Memac,
++                            uint8_t   phyAddr,
++                            uint8_t   reg,
++                            uint16_t  *p_Data)
++{
++    t_Memac                 *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Memac->p_MiiMemMap, E_INVALID_HANDLE);
++
++    return fman_memac_mii_read_phy_reg(p_Memac->p_MiiMemMap,
++                                       phyAddr,
++                                       reg,
++                                       p_Data,
++                                       (enum enet_speed)ENET_SPEED_FROM_MODE(p_Memac->enetMode));
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.h
+@@ -0,0 +1,73 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#ifndef __MEMAC_MII_ACC_H
++#define __MEMAC_MII_ACC_H
++
++#include "std_ext.h"
++
++
++/* MII Management Registers */
++#define MDIO_CFG_CLK_DIV_MASK       0x0080ff80
++#define MDIO_CFG_CLK_DIV_SHIFT      7
++#define MDIO_CFG_HOLD_MASK          0x0000001c
++#define MDIO_CFG_ENC45              0x00000040
++#define MDIO_CFG_READ_ERR           0x00000002
++#define MDIO_CFG_BSY                0x00000001
++
++#define MDIO_CTL_PHY_ADDR_SHIFT     5
++#define MDIO_CTL_READ               0x00008000
++
++#define MDIO_DATA_BSY               0x80000000
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(push,1)
++#endif /* defined(__MWERKS__) && ... */
++
++/*----------------------------------------------------*/
++/* MII Configuration Control Memory Map Registers     */
++/*----------------------------------------------------*/
++typedef struct t_MemacMiiAccessMemMap
++{
++    volatile uint32_t   mdio_cfg;       /* 0x030  */
++    volatile uint32_t   mdio_ctrl;      /* 0x034  */
++    volatile uint32_t   mdio_data;      /* 0x038  */
++    volatile uint32_t   mdio_addr;      /* 0x03c  */
++} t_MemacMiiAccessMemMap ;
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(pop)
++#endif /* defined(__MWERKS__) && ... */
++
++
++#endif /* __MEMAC_MII_ACC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.c
+@@ -0,0 +1,975 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          tgec.c
++
++ @Description   FM 10G MAC ...
++*//***************************************************************************/
++
++#include "std_ext.h"
++#include "string_ext.h"
++#include "error_ext.h"
++#include "xx_ext.h"
++#include "endian_ext.h"
++#include "debug_ext.h"
++#include "crc_mac_addr_ext.h"
++
++#include "fm_common.h"
++#include "fsl_fman_tgec.h"
++#include "tgec.h"
++
++
++/*****************************************************************************/
++/*                      Internal routines                                    */
++/*****************************************************************************/
++
++static t_Error CheckInitParameters(t_Tgec    *p_Tgec)
++{
++    if (ENET_SPEED_FROM_MODE(p_Tgec->enetMode) < e_ENET_SPEED_10000)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 10G MAC driver only support 10G speed"));
++#if (FM_MAX_NUM_OF_10G_MACS > 0)
++    if (p_Tgec->macId >= FM_MAX_NUM_OF_10G_MACS)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("macId of 10G can not be greater than 0"));
++#endif /* (FM_MAX_NUM_OF_10G_MACS > 0) */
++
++    if (p_Tgec->addr == 0)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 10G MAC Must have a valid MAC Address"));
++    if (!p_Tgec->f_Exception)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("uninitialized f_Exception"));
++    if (!p_Tgec->f_Event)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("uninitialized f_Event"));
++#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002
++    if (!p_Tgec->p_TgecDriverParam->no_length_check_enable)
++       RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!"));
++#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static uint32_t GetMacAddrHashCode(uint64_t ethAddr)
++{
++    uint32_t crc;
++
++    /* CRC calculation */
++    GET_MAC_ADDR_CRC(ethAddr, crc);
++
++    crc = GetMirror32(crc);
++
++    return crc;
++}
++
++/* ......................................................................... */
++
++static void TgecErrException(t_Handle h_Tgec)
++{
++    t_Tgec              *p_Tgec = (t_Tgec *)h_Tgec;
++    uint32_t            event;
++    struct tgec_regs    *p_TgecMemMap = p_Tgec->p_MemMap;
++
++    /* do not handle MDIO events */
++    event = fman_tgec_get_event(p_TgecMemMap, ~(TGEC_IMASK_MDIO_SCAN_EVENT | TGEC_IMASK_MDIO_CMD_CMPL));
++    event &= fman_tgec_get_interrupt_mask(p_TgecMemMap);
++
++    fman_tgec_ack_event(p_TgecMemMap, event);
++
++    if (event & TGEC_IMASK_REM_FAULT)
++        p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_REM_FAULT);
++    if (event & TGEC_IMASK_LOC_FAULT)
++        p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_LOC_FAULT);
++    if (event & TGEC_IMASK_TX_ECC_ER)
++        p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_1TX_ECC_ER);
++    if (event & TGEC_IMASK_TX_FIFO_UNFL)
++        p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_FIFO_UNFL);
++    if (event & TGEC_IMASK_TX_FIFO_OVFL)
++        p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_FIFO_OVFL);
++    if (event & TGEC_IMASK_TX_ER)
++        p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_ER);
++    if (event & TGEC_IMASK_RX_FIFO_OVFL)
++        p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_FIFO_OVFL);
++    if (event & TGEC_IMASK_RX_ECC_ER)
++        p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_ECC_ER);
++    if (event & TGEC_IMASK_RX_JAB_FRM)
++        p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_JAB_FRM);
++    if (event & TGEC_IMASK_RX_OVRSZ_FRM)
++        p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_OVRSZ_FRM);
++    if (event & TGEC_IMASK_RX_RUNT_FRM)
++        p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_RUNT_FRM);
++    if (event & TGEC_IMASK_RX_FRAG_FRM)
++        p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_FRAG_FRM);
++    if (event & TGEC_IMASK_RX_LEN_ER)
++        p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_LEN_ER);
++    if (event & TGEC_IMASK_RX_CRC_ER)
++        p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_CRC_ER);
++    if (event & TGEC_IMASK_RX_ALIGN_ER)
++        p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_ALIGN_ER);
++}
++
++/* ......................................................................... */
++
++static void TgecException(t_Handle h_Tgec)
++{
++     t_Tgec             *p_Tgec = (t_Tgec *)h_Tgec;
++     uint32_t           event;
++     struct tgec_regs   *p_TgecMemMap = p_Tgec->p_MemMap;
++
++     /* handle only MDIO events */
++     event = fman_tgec_get_event(p_TgecMemMap, (TGEC_IMASK_MDIO_SCAN_EVENT | TGEC_IMASK_MDIO_CMD_CMPL));
++     event &= fman_tgec_get_interrupt_mask(p_TgecMemMap);
++
++     fman_tgec_ack_event(p_TgecMemMap, event);
++
++     if (event & TGEC_IMASK_MDIO_SCAN_EVENT)
++         p_Tgec->f_Event(p_Tgec->h_App, e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO);
++     if (event & TGEC_IMASK_MDIO_CMD_CMPL)
++         p_Tgec->f_Event(p_Tgec->h_App, e_FM_MAC_EX_10G_MDIO_CMD_CMPL);
++}
++
++/* ......................................................................... */
++
++static void FreeInitResources(t_Tgec *p_Tgec)
++{
++    if (p_Tgec->mdioIrq != NO_IRQ)
++    {
++        XX_DisableIntr(p_Tgec->mdioIrq);
++        XX_FreeIntr(p_Tgec->mdioIrq);
++    }
++
++    FmUnregisterIntr(p_Tgec->fmMacControllerDriver.h_Fm, e_FM_MOD_10G_MAC, p_Tgec->macId, e_FM_INTR_TYPE_ERR);
++
++    /* release the driver's group hash table */
++    FreeHashTable(p_Tgec->p_MulticastAddrHash);
++    p_Tgec->p_MulticastAddrHash =   NULL;
++
++    /* release the driver's individual hash table */
++    FreeHashTable(p_Tgec->p_UnicastAddrHash);
++    p_Tgec->p_UnicastAddrHash =     NULL;
++}
++
++
++/*****************************************************************************/
++/*                     10G MAC API routines                                  */
++/*****************************************************************************/
++
++/* ......................................................................... */
++
++static t_Error TgecEnable(t_Handle h_Tgec,  e_CommMode mode)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    fman_tgec_enable(p_Tgec->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX));
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecDisable (t_Handle h_Tgec, e_CommMode mode)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    fman_tgec_disable(p_Tgec->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX));
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecSetPromiscuous(t_Handle h_Tgec, bool newVal)
++{
++    t_Tgec       *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    fman_tgec_set_promiscuous(p_Tgec->p_MemMap, newVal);
++
++    return E_OK;
++}
++
++
++/*****************************************************************************/
++/*                      Tgec Configs modification functions                 */
++/*****************************************************************************/
++
++/* ......................................................................... */
++
++static t_Error TgecConfigLoopback(t_Handle h_Tgec, bool newVal)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    p_Tgec->p_TgecDriverParam->loopback_enable = newVal;
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecConfigWan(t_Handle h_Tgec, bool newVal)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    p_Tgec->p_TgecDriverParam->wan_mode_enable = newVal;
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecConfigMaxFrameLength(t_Handle h_Tgec, uint16_t newVal)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    p_Tgec->p_TgecDriverParam->max_frame_length = newVal;
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecConfigLengthCheck(t_Handle h_Tgec, bool newVal)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    UNUSED(newVal);
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    p_Tgec->p_TgecDriverParam->no_length_check_enable = !newVal;
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecConfigException(t_Handle h_Tgec, e_FmMacExceptions exception, bool enable)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++    uint32_t    bitMask = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    GET_EXCEPTION_FLAG(bitMask, exception);
++    if (bitMask)
++    {
++        if (enable)
++            p_Tgec->exceptions |= bitMask;
++        else
++            p_Tgec->exceptions &= ~bitMask;
++    }
++    else
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
++
++    return E_OK;
++}
++
++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
++/* ......................................................................... */
++
++static t_Error TgecConfigSkipFman11Workaround(t_Handle h_Tgec)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    p_Tgec->p_TgecDriverParam->skip_fman11_workaround = TRUE;
++
++    return E_OK;
++}
++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
++
++
++/*****************************************************************************/
++/*                      Tgec Run Time API functions                         */
++/*****************************************************************************/
++
++/* ......................................................................... */
++/* backward compatibility. will be removed in the future. */
++static t_Error TgecTxMacPause(t_Handle h_Tgec, uint16_t pauseTime)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++    fman_tgec_set_tx_pause_frames(p_Tgec->p_MemMap, pauseTime);
++
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecSetTxPauseFrames(t_Handle h_Tgec,
++                                    uint8_t  priority,
++                                    uint16_t pauseTime,
++                                    uint16_t threshTime)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    UNUSED(priority); UNUSED(threshTime);
++
++    fman_tgec_set_tx_pause_frames(p_Tgec->p_MemMap, pauseTime);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecRxIgnoreMacPause(t_Handle h_Tgec, bool en)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    fman_tgec_set_rx_ignore_pause_frames(p_Tgec->p_MemMap, en);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecGetStatistics(t_Handle h_Tgec, t_FmMacStatistics *p_Statistics)
++{
++    t_Tgec              *p_Tgec = (t_Tgec *)h_Tgec;
++    struct tgec_regs    *p_TgecMemMap;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER);
++
++    p_TgecMemMap = p_Tgec->p_MemMap;
++
++    p_Statistics->eStatPkts64           = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R64);
++    p_Statistics->eStatPkts65to127      = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R127);
++    p_Statistics->eStatPkts128to255     = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R255);
++    p_Statistics->eStatPkts256to511     = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R511);
++    p_Statistics->eStatPkts512to1023    = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1023);
++    p_Statistics->eStatPkts1024to1518   = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1518);
++    p_Statistics->eStatPkts1519to1522   = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1519X);
++/* */
++    p_Statistics->eStatFragments        = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TRFRG);
++    p_Statistics->eStatJabbers          = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TRJBR);
++
++    p_Statistics->eStatsDropEvents      = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RDRP);
++    p_Statistics->eStatCRCAlignErrors   = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RALN);
++
++    p_Statistics->eStatUndersizePkts    = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TRUND);
++    p_Statistics->eStatOversizePkts     = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TROVR);
++/* Pause */
++    p_Statistics->reStatPause           = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RXPF);
++    p_Statistics->teStatPause           = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TXPF);
++
++/* MIB II */
++    p_Statistics->ifInOctets            = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_ROCT);
++    p_Statistics->ifInUcastPkts         = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RUCA);
++    p_Statistics->ifInMcastPkts         = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RMCA);
++    p_Statistics->ifInBcastPkts         = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RBCA);
++    p_Statistics->ifInPkts              = p_Statistics->ifInUcastPkts
++                                        + p_Statistics->ifInMcastPkts
++                                        + p_Statistics->ifInBcastPkts;
++    p_Statistics->ifInDiscards          = 0;
++    p_Statistics->ifInErrors            = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RERR);
++
++    p_Statistics->ifOutOctets           = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TOCT);
++    p_Statistics->ifOutUcastPkts        = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TUCA);
++    p_Statistics->ifOutMcastPkts        = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TMCA);
++    p_Statistics->ifOutBcastPkts        = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TBCA);
++    p_Statistics->ifOutPkts             = p_Statistics->ifOutUcastPkts
++                                        + p_Statistics->ifOutMcastPkts
++                                        + p_Statistics->ifOutBcastPkts;
++    p_Statistics->ifOutDiscards         = 0;
++    p_Statistics->ifOutErrors           = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TERR);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecEnable1588TimeStamp(t_Handle h_Tgec)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    fman_tgec_enable_1588_time_stamp(p_Tgec->p_MemMap, 1);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecDisable1588TimeStamp(t_Handle h_Tgec)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    fman_tgec_enable_1588_time_stamp(p_Tgec->p_MemMap, 0);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecModifyMacAddress (t_Handle h_Tgec, t_EnetAddr *p_EnetAddr)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    p_Tgec->addr = ENET_ADDR_TO_UINT64(*p_EnetAddr);
++    fman_tgec_set_mac_address(p_Tgec->p_MemMap, (uint8_t *)(*p_EnetAddr));
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecResetCounters (t_Handle h_Tgec)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    fman_tgec_reset_stat(p_Tgec->p_MemMap);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecAddExactMatchMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *) h_Tgec;
++    uint64_t    ethAddr;
++    uint8_t     paddrNum;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
++
++    if (ethAddr & GROUP_ADDRESS)
++        /* Multicast address has no effect in PADDR */
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address"));
++
++    /* Make sure no PADDR contains this address */
++    for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++)
++        if (p_Tgec->indAddrRegUsed[paddrNum])
++            if (p_Tgec->paddr[paddrNum] == ethAddr)
++                RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
++
++    /* Find first unused PADDR */
++    for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++)
++    {
++        if (!(p_Tgec->indAddrRegUsed[paddrNum]))
++        {
++            /* mark this PADDR as used */
++            p_Tgec->indAddrRegUsed[paddrNum] = TRUE;
++            /* store address */
++            p_Tgec->paddr[paddrNum] = ethAddr;
++
++            /* put in hardware */
++            fman_tgec_add_addr_in_paddr(p_Tgec->p_MemMap, (uint8_t*)(*p_EthAddr)/* , paddrNum */);
++            p_Tgec->numOfIndAddrInRegs++;
++
++            return E_OK;
++        }
++    }
++
++    /* No free PADDR */
++    RETURN_ERROR(MAJOR, E_FULL, NO_MSG);
++}
++
++/* ......................................................................... */
++
++static t_Error TgecDelExactMatchMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *) h_Tgec;
++    uint64_t    ethAddr;
++    uint8_t     paddrNum;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
++
++    /* Find used PADDR containing this address */
++    for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++)
++    {
++        if ((p_Tgec->indAddrRegUsed[paddrNum]) &&
++            (p_Tgec->paddr[paddrNum] == ethAddr))
++        {
++            /* mark this PADDR as not used */
++            p_Tgec->indAddrRegUsed[paddrNum] = FALSE;
++            /* clear in hardware */
++            fman_tgec_clear_addr_in_paddr(p_Tgec->p_MemMap /*, paddrNum */);
++            p_Tgec->numOfIndAddrInRegs--;
++
++            return E_OK;
++        }
++    }
++
++    RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG);
++}
++
++/* ......................................................................... */
++
++static t_Error TgecAddHashMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr)
++{
++    t_Tgec          *p_Tgec = (t_Tgec *)h_Tgec;
++    t_EthHashEntry  *p_HashEntry;
++    uint32_t        crc;
++    uint32_t        hash;
++    uint64_t        ethAddr;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
++
++    if (!(ethAddr & GROUP_ADDRESS))
++        /* Unicast addresses not supported in hash */
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unicast Address"));
++
++    /* CRC calculation */
++    crc = GetMacAddrHashCode(ethAddr);
++
++    hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK;        /* Take 9 MSB bits */
++
++    /* Create element to be added to the driver hash table */
++    p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry));
++    p_HashEntry->addr = ethAddr;
++    INIT_LIST(&p_HashEntry->node);
++
++    LIST_AddToTail(&(p_HashEntry->node), &(p_Tgec->p_MulticastAddrHash->p_Lsts[hash]));
++    fman_tgec_set_hash_table(p_Tgec->p_MemMap, (hash | TGEC_HASH_MCAST_EN));
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecDelHashMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr)
++{
++    t_Tgec           *p_Tgec = (t_Tgec *)h_Tgec;
++    t_EthHashEntry   *p_HashEntry = NULL;
++    t_List           *p_Pos;
++    uint32_t         crc;
++    uint32_t         hash;
++    uint64_t         ethAddr;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    ethAddr = ((*(uint64_t *)p_EthAddr) >> 16);
++
++    /* CRC calculation */
++    crc = GetMacAddrHashCode(ethAddr);
++
++    hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK;        /* Take 9 MSB bits */
++
++    LIST_FOR_EACH(p_Pos, &(p_Tgec->p_MulticastAddrHash->p_Lsts[hash]))
++    {
++        p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos);
++        if (p_HashEntry->addr == ethAddr)
++        {
++            LIST_DelAndInit(&p_HashEntry->node);
++            XX_Free(p_HashEntry);
++            break;
++        }
++    }
++    if (LIST_IsEmpty(&p_Tgec->p_MulticastAddrHash->p_Lsts[hash]))
++        fman_tgec_set_hash_table(p_Tgec->p_MemMap, (hash & ~TGEC_HASH_MCAST_EN));
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecGetId(t_Handle h_Tgec, uint32_t *macId)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    UNUSED(p_Tgec);
++    UNUSED(macId);
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("TgecGetId Not Supported"));
++}
++
++/* ......................................................................... */
++
++static t_Error TgecGetVersion(t_Handle h_Tgec, uint32_t *macVersion)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    *macVersion = fman_tgec_get_revision(p_Tgec->p_MemMap);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecSetExcpetion(t_Handle h_Tgec, e_FmMacExceptions exception, bool enable)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++    uint32_t    bitMask = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++
++    GET_EXCEPTION_FLAG(bitMask, exception);
++    if (bitMask)
++    {
++        if (enable)
++            p_Tgec->exceptions |= bitMask;
++        else
++            p_Tgec->exceptions &= ~bitMask;
++   }
++    else
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
++
++    if (enable)
++        fman_tgec_enable_interrupt(p_Tgec->p_MemMap, bitMask);
++    else
++        fman_tgec_disable_interrupt(p_Tgec->p_MemMap, bitMask);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static uint16_t TgecGetMaxFrameLength(t_Handle h_Tgec)
++{
++    t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_VALUE(p_Tgec, E_INVALID_HANDLE, 0);
++    SANITY_CHECK_RETURN_VALUE(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE, 0);
++
++    return fman_tgec_get_max_frame_len(p_Tgec->p_MemMap);
++}
++
++/* ......................................................................... */
++
++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
++static t_Error TgecTxEccWorkaround(t_Tgec *p_Tgec)
++{
++    t_Error err;
++
++#if defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)
++    XX_Print("Applying 10G TX ECC workaround (10GMAC-A004) ... ");
++#endif /* (DEBUG_ERRORS > 0) */
++    /* enable and set promiscuous */
++    fman_tgec_enable(p_Tgec->p_MemMap, TRUE, TRUE);
++    fman_tgec_set_promiscuous(p_Tgec->p_MemMap, TRUE);
++    err = Fm10GTxEccWorkaround(p_Tgec->fmMacControllerDriver.h_Fm, p_Tgec->macId);
++    /* disable */
++    fman_tgec_set_promiscuous(p_Tgec->p_MemMap, FALSE);
++    fman_tgec_enable(p_Tgec->p_MemMap, FALSE, FALSE);
++    fman_tgec_reset_stat(p_Tgec->p_MemMap);
++    fman_tgec_ack_event(p_Tgec->p_MemMap, 0xffffffff);
++#if defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)
++    if (err)
++        XX_Print("FAILED!\n");
++    else
++        XX_Print("done.\n");
++#endif /* (DEBUG_ERRORS > 0) */
++
++    return err;
++}
++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
++
++/*****************************************************************************/
++/*                      FM Init & Free API                                   */
++/*****************************************************************************/
++
++/* ......................................................................... */
++
++static t_Error TgecInit(t_Handle h_Tgec)
++{
++    t_Tgec                  *p_Tgec = (t_Tgec *)h_Tgec;
++    struct tgec_cfg         *p_TgecDriverParam;
++    t_EnetAddr              ethAddr;
++    t_Error                 err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_Tgec->fmMacControllerDriver.h_Fm, E_INVALID_HANDLE);
++
++    FM_GetRevision(p_Tgec->fmMacControllerDriver.h_Fm, &p_Tgec->fmMacControllerDriver.fmRevInfo);
++    CHECK_INIT_PARAMETERS(p_Tgec, CheckInitParameters);
++
++    p_TgecDriverParam = p_Tgec->p_TgecDriverParam;
++
++    MAKE_ENET_ADDR_FROM_UINT64(p_Tgec->addr, ethAddr);
++    fman_tgec_set_mac_address(p_Tgec->p_MemMap, (uint8_t *)ethAddr);
++
++    /* interrupts */
++#ifdef FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005
++    {
++        if (p_Tgec->fmMacControllerDriver.fmRevInfo.majorRev <=2)
++            p_Tgec->exceptions &= ~(TGEC_IMASK_REM_FAULT | TGEC_IMASK_LOC_FAULT);
++    }
++#endif /* FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005 */
++
++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
++    if (!p_Tgec->p_TgecDriverParam->skip_fman11_workaround &&
++        ((err = TgecTxEccWorkaround(p_Tgec)) != E_OK))
++    {
++        FreeInitResources(p_Tgec);
++        REPORT_ERROR(MINOR, err, ("TgecTxEccWorkaround FAILED"));
++    }
++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
++
++    err = fman_tgec_init(p_Tgec->p_MemMap, p_TgecDriverParam, p_Tgec->exceptions);
++    if (err)
++    {
++        FreeInitResources(p_Tgec);
++        RETURN_ERROR(MAJOR, err, ("This TGEC version does not support the required i/f mode"));
++    }
++
++    /* Max Frame Length */
++    err = FmSetMacMaxFrame(p_Tgec->fmMacControllerDriver.h_Fm,
++                           e_FM_MAC_10G,
++                           p_Tgec->fmMacControllerDriver.macId,
++                           p_TgecDriverParam->max_frame_length);
++    if (err != E_OK)
++    {
++        FreeInitResources(p_Tgec);
++        RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++/* we consider having no IPC a non crasher... */
++
++#ifdef FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007
++    if (p_Tgec->fmMacControllerDriver.fmRevInfo.majorRev == 2)
++        fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(p_Tgec->p_MemMap);
++#endif /* FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 */
++
++    p_Tgec->p_MulticastAddrHash = AllocHashTable(HASH_TABLE_SIZE);
++    if (!p_Tgec->p_MulticastAddrHash)
++    {
++        FreeInitResources(p_Tgec);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED"));
++    }
++
++    p_Tgec->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE);
++    if (!p_Tgec->p_UnicastAddrHash)
++    {
++        FreeInitResources(p_Tgec);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED"));
++    }
++
++    FmRegisterIntr(p_Tgec->fmMacControllerDriver.h_Fm,
++                   e_FM_MOD_10G_MAC,
++                   p_Tgec->macId,
++                   e_FM_INTR_TYPE_ERR,
++                   TgecErrException,
++                   p_Tgec);
++    if (p_Tgec->mdioIrq != NO_IRQ)
++    {
++        XX_SetIntr(p_Tgec->mdioIrq, TgecException, p_Tgec);
++        XX_EnableIntr(p_Tgec->mdioIrq);
++    }
++
++    XX_Free(p_TgecDriverParam);
++    p_Tgec->p_TgecDriverParam = NULL;
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static t_Error TgecFree(t_Handle h_Tgec)
++{
++    t_Tgec       *p_Tgec = (t_Tgec *)h_Tgec;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++
++    if (p_Tgec->p_TgecDriverParam)
++    {
++        /* Called after config */
++        XX_Free(p_Tgec->p_TgecDriverParam);
++        p_Tgec->p_TgecDriverParam = NULL;
++    }
++    else
++        /* Called after init */
++        FreeInitResources(p_Tgec);
++
++    XX_Free(p_Tgec);
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
++static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver)
++{
++    p_FmMacControllerDriver->f_FM_MAC_Init                      = TgecInit;
++    p_FmMacControllerDriver->f_FM_MAC_Free                      = TgecFree;
++
++    p_FmMacControllerDriver->f_FM_MAC_SetStatistics             = NULL;
++    p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback            = TgecConfigLoopback;
++    p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength      = TgecConfigMaxFrameLength;
++
++    p_FmMacControllerDriver->f_FM_MAC_ConfigWan                 = TgecConfigWan;
++
++    p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc           = NULL; /* TGEC always works with pad+crc */
++    p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex          = NULL; /* half-duplex is not supported in xgec */
++    p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck         = TgecConfigLengthCheck;
++    p_FmMacControllerDriver->f_FM_MAC_ConfigException           = TgecConfigException;
++    p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit         = NULL;
++
++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
++    p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround= TgecConfigSkipFman11Workaround;
++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
++
++    p_FmMacControllerDriver->f_FM_MAC_SetException              = TgecSetExcpetion;
++
++    p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp       = TgecEnable1588TimeStamp;
++    p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp      = TgecDisable1588TimeStamp;
++
++    p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous            = TgecSetPromiscuous;
++    p_FmMacControllerDriver->f_FM_MAC_AdjustLink                = NULL;
++    p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan              = NULL;
++    p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg            = NULL;
++
++    p_FmMacControllerDriver->f_FM_MAC_Enable                    = TgecEnable;
++    p_FmMacControllerDriver->f_FM_MAC_Disable                   = TgecDisable;
++    p_FmMacControllerDriver->f_FM_MAC_Resume                    = NULL;
++
++    p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames      = TgecTxMacPause;
++    p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames          = TgecSetTxPauseFrames;
++    p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames    = TgecRxIgnoreMacPause;
++
++    p_FmMacControllerDriver->f_FM_MAC_ResetCounters             = TgecResetCounters;
++    p_FmMacControllerDriver->f_FM_MAC_GetStatistics             = TgecGetStatistics;
++
++    p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr             = TgecModifyMacAddress;
++    p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr            = TgecAddHashMacAddress;
++    p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr         = TgecDelHashMacAddress;
++    p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr      = TgecAddExactMatchMacAddress;
++    p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr  = TgecDelExactMatchMacAddress;
++    p_FmMacControllerDriver->f_FM_MAC_GetId                     = TgecGetId;
++    p_FmMacControllerDriver->f_FM_MAC_GetVersion                = TgecGetVersion;
++    p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength         = TgecGetMaxFrameLength;
++
++    p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg           = TGEC_MII_WritePhyReg;
++    p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg            = TGEC_MII_ReadPhyReg;
++}
++
++
++/*****************************************************************************/
++/*                      Tgec Config  Main Entry                             */
++/*****************************************************************************/
++
++/* ......................................................................... */
++
++t_Handle TGEC_Config(t_FmMacParams *p_FmMacParam)
++{
++    t_Tgec              *p_Tgec;
++    struct tgec_cfg     *p_TgecDriverParam;
++    uintptr_t           baseAddr;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL);
++
++    baseAddr = p_FmMacParam->baseAddr;
++    /* allocate memory for the UCC GETH data structure. */
++    p_Tgec = (t_Tgec *)XX_Malloc(sizeof(t_Tgec));
++    if (!p_Tgec)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("10G MAC driver structure"));
++        return NULL;
++    }
++    memset(p_Tgec, 0, sizeof(t_Tgec));
++    InitFmMacControllerDriver(&p_Tgec->fmMacControllerDriver);
++
++    /* allocate memory for the 10G MAC driver parameters data structure. */
++    p_TgecDriverParam = (struct tgec_cfg *) XX_Malloc(sizeof(struct tgec_cfg));
++    if (!p_TgecDriverParam)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("10G MAC driver parameters"));
++        XX_Free(p_Tgec);
++        return NULL;
++    }
++    memset(p_TgecDriverParam, 0, sizeof(struct tgec_cfg));
++
++    /* Plant parameter structure pointer */
++    p_Tgec->p_TgecDriverParam = p_TgecDriverParam;
++
++    fman_tgec_defconfig(p_TgecDriverParam);
++
++    p_Tgec->p_MemMap        = (struct tgec_regs *)UINT_TO_PTR(baseAddr);
++    p_Tgec->p_MiiMemMap     = (t_TgecMiiAccessMemMap *)UINT_TO_PTR(baseAddr + TGEC_TO_MII_OFFSET);
++    p_Tgec->addr            = ENET_ADDR_TO_UINT64(p_FmMacParam->addr);
++    p_Tgec->enetMode        = p_FmMacParam->enetMode;
++    p_Tgec->macId           = p_FmMacParam->macId;
++    p_Tgec->exceptions      = DEFAULT_exceptions;
++    p_Tgec->mdioIrq         = p_FmMacParam->mdioIrq;
++    p_Tgec->f_Exception     = p_FmMacParam->f_Exception;
++    p_Tgec->f_Event         = p_FmMacParam->f_Event;
++    p_Tgec->h_App           = p_FmMacParam->h_App;
++
++    return p_Tgec;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.h
+@@ -0,0 +1,151 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          tgec.h
++
++ @Description   FM 10G MAC ...
++*//***************************************************************************/
++#ifndef __TGEC_H
++#define __TGEC_H
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "list_ext.h"
++#include "enet_ext.h"
++
++#include "tgec_mii_acc.h"
++#include "fm_mac.h"
++
++
++#define DEFAULT_exceptions                        \
++    ((uint32_t)(TGEC_IMASK_MDIO_SCAN_EVENT     |  \
++                TGEC_IMASK_REM_FAULT           |  \
++                TGEC_IMASK_LOC_FAULT           |  \
++                TGEC_IMASK_TX_ECC_ER           |  \
++                TGEC_IMASK_TX_FIFO_UNFL        |  \
++                TGEC_IMASK_TX_FIFO_OVFL        |  \
++                TGEC_IMASK_TX_ER               |  \
++                TGEC_IMASK_RX_FIFO_OVFL        |  \
++                TGEC_IMASK_RX_ECC_ER           |  \
++                TGEC_IMASK_RX_JAB_FRM          |  \
++                TGEC_IMASK_RX_OVRSZ_FRM        |  \
++                TGEC_IMASK_RX_RUNT_FRM         |  \
++                TGEC_IMASK_RX_FRAG_FRM         |  \
++                TGEC_IMASK_RX_CRC_ER           |  \
++                TGEC_IMASK_RX_ALIGN_ER))
++
++#define GET_EXCEPTION_FLAG(bitMask, exception)      switch (exception){ \
++    case e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO:                           \
++        bitMask = TGEC_IMASK_MDIO_SCAN_EVENT    ; break;                \
++    case e_FM_MAC_EX_10G_MDIO_CMD_CMPL:                                 \
++        bitMask = TGEC_IMASK_MDIO_CMD_CMPL      ; break;                \
++    case e_FM_MAC_EX_10G_REM_FAULT:                                     \
++        bitMask = TGEC_IMASK_REM_FAULT          ; break;                \
++    case e_FM_MAC_EX_10G_LOC_FAULT:                                     \
++        bitMask = TGEC_IMASK_LOC_FAULT          ; break;                \
++    case e_FM_MAC_EX_10G_1TX_ECC_ER:                                    \
++        bitMask = TGEC_IMASK_TX_ECC_ER         ; break;                 \
++    case e_FM_MAC_EX_10G_TX_FIFO_UNFL:                                  \
++        bitMask = TGEC_IMASK_TX_FIFO_UNFL       ; break;                \
++    case e_FM_MAC_EX_10G_TX_FIFO_OVFL:                                  \
++        bitMask = TGEC_IMASK_TX_FIFO_OVFL       ; break;                \
++    case e_FM_MAC_EX_10G_TX_ER:                                         \
++        bitMask = TGEC_IMASK_TX_ER              ; break;                \
++    case e_FM_MAC_EX_10G_RX_FIFO_OVFL:                                  \
++        bitMask = TGEC_IMASK_RX_FIFO_OVFL       ; break;                \
++    case e_FM_MAC_EX_10G_RX_ECC_ER:                                     \
++        bitMask = TGEC_IMASK_RX_ECC_ER          ; break;                \
++    case e_FM_MAC_EX_10G_RX_JAB_FRM:                                    \
++        bitMask = TGEC_IMASK_RX_JAB_FRM         ; break;                \
++    case e_FM_MAC_EX_10G_RX_OVRSZ_FRM:                                  \
++        bitMask = TGEC_IMASK_RX_OVRSZ_FRM       ; break;                \
++    case e_FM_MAC_EX_10G_RX_RUNT_FRM:                                   \
++        bitMask = TGEC_IMASK_RX_RUNT_FRM        ; break;                \
++    case e_FM_MAC_EX_10G_RX_FRAG_FRM:                                   \
++        bitMask = TGEC_IMASK_RX_FRAG_FRM        ; break;                \
++    case e_FM_MAC_EX_10G_RX_LEN_ER:                                     \
++        bitMask = TGEC_IMASK_RX_LEN_ER          ; break;                \
++    case e_FM_MAC_EX_10G_RX_CRC_ER:                                     \
++        bitMask = TGEC_IMASK_RX_CRC_ER          ; break;                \
++    case e_FM_MAC_EX_10G_RX_ALIGN_ER:                                   \
++        bitMask = TGEC_IMASK_RX_ALIGN_ER        ; break;                \
++    default: bitMask = 0;break;}
++
++#define MAX_PACKET_ALIGNMENT        31
++#define MAX_INTER_PACKET_GAP        0x7f
++#define MAX_INTER_PALTERNATE_BEB    0x0f
++#define MAX_RETRANSMISSION          0x0f
++#define MAX_COLLISION_WINDOW        0x03ff
++
++#define TGEC_NUM_OF_PADDRS          1                   /* number of pattern match registers (entries) */
++
++#define GROUP_ADDRESS               0x0000010000000000LL /* Group address bit indication */
++
++#define HASH_TABLE_SIZE             512                 /* Hash table size (= 32 bits * 8 regs) */
++
++#define TGEC_TO_MII_OFFSET          0x1030              /* Offset from the MEM map to the MDIO mem map */
++
++/* 10-gigabit Ethernet MAC Controller ID (10GEC_ID) */
++#define TGEC_ID_ID                  0xffff0000
++#define TGEC_ID_MAC_VERSION         0x0000FF00
++#define TGEC_ID_MAC_REV             0x000000ff
++
++
++typedef struct {
++    t_FmMacControllerDriver     fmMacControllerDriver;              /**< Upper Mac control block */
++    t_Handle                    h_App;                              /**< Handle to the upper layer application  */
++    struct tgec_regs            *p_MemMap;                          /**< pointer to 10G memory mapped registers. */
++    t_TgecMiiAccessMemMap       *p_MiiMemMap;                       /**< pointer to MII memory mapped registers.          */
++    uint64_t                    addr;                               /**< MAC address of device; */
++    e_EnetMode                  enetMode;                           /**< Ethernet physical interface  */
++    t_FmMacExceptionCallback    *f_Exception;
++    int                         mdioIrq;
++    t_FmMacExceptionCallback    *f_Event;
++    bool                        indAddrRegUsed[TGEC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */
++    uint64_t                    paddr[TGEC_NUM_OF_PADDRS];          /**< MAC address for particular individual address recognition register */
++    uint8_t                     numOfIndAddrInRegs;                 /**< Number of individual addresses in registers for this station. */
++    t_EthHash                   *p_MulticastAddrHash;               /**< pointer to driver's global address hash table  */
++    t_EthHash                   *p_UnicastAddrHash;                 /**< pointer to driver's individual address hash table  */
++    bool                        debugMode;
++    uint8_t                     macId;
++    uint32_t                    exceptions;
++    struct tgec_cfg             *p_TgecDriverParam;
++} t_Tgec;
++
++
++t_Error TGEC_MII_WritePhyReg(t_Handle h_Tgec, uint8_t phyAddr, uint8_t reg, uint16_t data);
++t_Error TGEC_MII_ReadPhyReg(t_Handle h_Tgec,  uint8_t phyAddr, uint8_t reg, uint16_t *p_Data);
++
++
++#endif /* __TGEC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.c
+@@ -0,0 +1,139 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++
++#include "error_ext.h"
++#include "std_ext.h"
++#include "fm_mac.h"
++#include "tgec.h"
++#include "xx_ext.h"
++
++#include "fm_common.h"
++
++
++/*****************************************************************************/
++t_Error TGEC_MII_WritePhyReg(t_Handle   h_Tgec,
++                             uint8_t    phyAddr,
++                             uint8_t    reg,
++                             uint16_t   data)
++{
++    t_Tgec                  *p_Tgec = (t_Tgec *)h_Tgec;
++    t_TgecMiiAccessMemMap   *p_MiiAccess;
++    uint32_t                cfgStatusReg;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MiiMemMap, E_INVALID_HANDLE);
++
++    p_MiiAccess = p_Tgec->p_MiiMemMap;
++
++    /* Configure MII */
++    cfgStatusReg  = GET_UINT32(p_MiiAccess->mdio_cfg_status);
++    cfgStatusReg &= ~MIIMCOM_DIV_MASK;
++     /* (one half of fm clock => 2.5Mhz) */
++    cfgStatusReg |=((((p_Tgec->fmMacControllerDriver.clkFreq*10)/2)/25) << MIIMCOM_DIV_SHIFT);
++    WRITE_UINT32(p_MiiAccess->mdio_cfg_status, cfgStatusReg);
++
++    while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY)
++        XX_UDelay (1);
++
++    WRITE_UINT32(p_MiiAccess->mdio_command, phyAddr);
++
++    WRITE_UINT32(p_MiiAccess->mdio_regaddr, reg);
++
++    CORE_MemoryBarrier();
++
++    while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY)
++        XX_UDelay (1);
++
++    WRITE_UINT32(p_MiiAccess->mdio_data, data);
++
++    CORE_MemoryBarrier();
++
++    while ((GET_UINT32(p_MiiAccess->mdio_data)) & MIIDATA_BUSY)
++        XX_UDelay (1);
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error TGEC_MII_ReadPhyReg(t_Handle h_Tgec,
++                            uint8_t  phyAddr,
++                            uint8_t  reg,
++                            uint16_t *p_Data)
++{
++    t_Tgec                  *p_Tgec = (t_Tgec *)h_Tgec;
++    t_TgecMiiAccessMemMap   *p_MiiAccess;
++    uint32_t                cfgStatusReg;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MiiMemMap, E_INVALID_HANDLE);
++
++    p_MiiAccess = p_Tgec->p_MiiMemMap;
++
++    /* Configure MII */
++    cfgStatusReg  = GET_UINT32(p_MiiAccess->mdio_cfg_status);
++    cfgStatusReg &= ~MIIMCOM_DIV_MASK;
++     /* (one half of fm clock => 2.5Mhz) */
++    cfgStatusReg |=((((p_Tgec->fmMacControllerDriver.clkFreq*10)/2)/25) << MIIMCOM_DIV_SHIFT);
++    WRITE_UINT32(p_MiiAccess->mdio_cfg_status, cfgStatusReg);
++
++    while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY)
++        XX_UDelay (1);
++
++    WRITE_UINT32(p_MiiAccess->mdio_command, phyAddr);
++
++    WRITE_UINT32(p_MiiAccess->mdio_regaddr, reg);
++
++    CORE_MemoryBarrier();
++
++    while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY)
++        XX_UDelay (1);
++
++    WRITE_UINT32(p_MiiAccess->mdio_command, (uint32_t)(phyAddr | MIIMCOM_READ_CYCLE));
++
++    CORE_MemoryBarrier();
++
++    while ((GET_UINT32(p_MiiAccess->mdio_data)) & MIIDATA_BUSY)
++        XX_UDelay (1);
++
++    *p_Data =  (uint16_t)GET_UINT32(p_MiiAccess->mdio_data);
++
++    cfgStatusReg  = GET_UINT32(p_MiiAccess->mdio_cfg_status);
++
++    if (cfgStatusReg & MIIMIND_READ_ERROR)
++        RETURN_ERROR(MINOR, E_INVALID_VALUE,
++                     ("Read Error: phyAddr 0x%x, dev 0x%x, reg 0x%x, cfgStatusReg 0x%x",
++                      ((phyAddr & 0xe0)>>5), (phyAddr & 0x1f), reg, cfgStatusReg));
++
++    return E_OK;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.h
+@@ -0,0 +1,80 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#ifndef __TGEC_MII_ACC_H
++#define __TGEC_MII_ACC_H
++
++#include "std_ext.h"
++
++
++/* MII  Management Command Register */
++#define MIIMCOM_READ_POST_INCREMENT 0x00004000
++#define MIIMCOM_READ_CYCLE          0x00008000
++#define MIIMCOM_SCAN_CYCLE          0x00000800
++#define MIIMCOM_PREAMBLE_DISABLE    0x00000400
++
++#define MIIMCOM_MDIO_HOLD_1_REG_CLK 0
++#define MIIMCOM_MDIO_HOLD_2_REG_CLK 1
++#define MIIMCOM_MDIO_HOLD_3_REG_CLK 2
++#define MIIMCOM_MDIO_HOLD_4_REG_CLK 3
++
++#define MIIMCOM_DIV_MASK            0x0000ff00
++#define MIIMCOM_DIV_SHIFT           8
++
++/* MII Management Indicator Register */
++#define MIIMIND_BUSY                0x00000001
++#define MIIMIND_READ_ERROR          0x00000002
++
++#define MIIDATA_BUSY                0x80000000
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(push,1)
++#endif /* defined(__MWERKS__) && ... */
++
++/*----------------------------------------------------*/
++/* MII Configuration Control Memory Map Registers     */
++/*----------------------------------------------------*/
++typedef _Packed struct t_TgecMiiAccessMemMap
++{
++    volatile uint32_t   mdio_cfg_status;    /* 0x030  */
++    volatile uint32_t   mdio_command;       /* 0x034  */
++    volatile uint32_t   mdio_data;          /* 0x038  */
++    volatile uint32_t   mdio_regaddr;       /* 0x03c  */
++} _PackedType t_TgecMiiAccessMemMap ;
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(pop)
++#endif /* defined(__MWERKS__) && ... */
++
++
++#endif /* __TGEC_MII_ACC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/Makefile
+@@ -0,0 +1,15 @@
++#
++# Makefile for the Freescale Ethernet controllers
++#
++ccflags-y           += -DVERSION=\"\"
++#
++#Include netcomm SW specific definitions
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++
++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
++
++ccflags-y += -I$(NCSW_FM_INC)
++
++obj-y         += fsl-ncsw-macsec.o
++
++fsl-ncsw-macsec-objs  := fm_macsec.o fm_macsec_guest.o fm_macsec_master.o fm_macsec_secy.o
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.c
+@@ -0,0 +1,237 @@
++/*
++ * Copyright 2008-2015 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++/******************************************************************************
++
++ @File          fm_macsec.c
++
++ @Description   FM MACSEC driver routines implementation.
++*//***************************************************************************/
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "xx_ext.h"
++#include "string_ext.h"
++#include "sprint_ext.h"
++#include "debug_ext.h"
++
++#include "fm_macsec.h"
++
++
++/****************************************/
++/*       API Init unit functions        */
++/****************************************/
++t_Handle FM_MACSEC_Config(t_FmMacsecParams *p_FmMacsecParam)
++{
++    t_FmMacsecControllerDriver *p_FmMacsecControllerDriver;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmMacsecParam, E_INVALID_HANDLE, NULL);
++
++    if (p_FmMacsecParam->guestMode)
++        p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)FM_MACSEC_GUEST_Config(p_FmMacsecParam);
++    else
++        p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)FM_MACSEC_MASTER_Config(p_FmMacsecParam);
++
++    if (!p_FmMacsecControllerDriver)
++        return NULL;
++
++    return (t_Handle)p_FmMacsecControllerDriver;
++}
++
++t_Error FM_MACSEC_Init(t_Handle h_FmMacsec)
++{
++    t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacsecControllerDriver->f_FM_MACSEC_Init)
++        return p_FmMacsecControllerDriver->f_FM_MACSEC_Init(h_FmMacsec);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_Free(t_Handle h_FmMacsec)
++{
++    t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacsecControllerDriver->f_FM_MACSEC_Free)
++        return p_FmMacsecControllerDriver->f_FM_MACSEC_Free(h_FmMacsec);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_ConfigUnknownSciFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUnknownSciFrameTreatment treatMode)
++{
++    t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUnknownSciFrameTreatment)
++        return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUnknownSciFrameTreatment(h_FmMacsec, treatMode);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_ConfigInvalidTagsFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled)
++{
++    t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigInvalidTagsFrameTreatment)
++        return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigInvalidTagsFrameTreatment(h_FmMacsec, deliverUncontrolled);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment(t_Handle h_FmMacsec, bool discardUncontrolled)
++{
++    t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment)
++        return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment(h_FmMacsec, discardUncontrolled);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_ConfigUntagFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUntagFrameTreatment treatMode)
++{
++    t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUntagFrameTreatment)
++        return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUntagFrameTreatment(h_FmMacsec, treatMode);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_ConfigPnExhaustionThreshold(t_Handle h_FmMacsec, uint32_t pnExhThr)
++{
++    t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigPnExhaustionThreshold)
++        return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigPnExhaustionThreshold(h_FmMacsec, pnExhThr);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_ConfigKeysUnreadable(t_Handle h_FmMacsec)
++{
++    t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigKeysUnreadable)
++        return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigKeysUnreadable(h_FmMacsec);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_ConfigSectagWithoutSCI(t_Handle h_FmMacsec)
++{
++    t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigSectagWithoutSCI)
++        return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigSectagWithoutSCI(h_FmMacsec);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_ConfigException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable)
++{
++    t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigException)
++        return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigException(h_FmMacsec, exception, enable);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_GetRevision(t_Handle h_FmMacsec, uint32_t *p_MacsecRevision)
++{
++    t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacsecControllerDriver->f_FM_MACSEC_GetRevision)
++        return p_FmMacsecControllerDriver->f_FM_MACSEC_GetRevision(h_FmMacsec, p_MacsecRevision);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++
++t_Error FM_MACSEC_Enable(t_Handle h_FmMacsec)
++{
++    t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacsecControllerDriver->f_FM_MACSEC_Enable)
++        return p_FmMacsecControllerDriver->f_FM_MACSEC_Enable(h_FmMacsec);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_Disable(t_Handle h_FmMacsec)
++{
++    t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacsecControllerDriver->f_FM_MACSEC_Disable)
++        return p_FmMacsecControllerDriver->f_FM_MACSEC_Disable(h_FmMacsec);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_SetException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable)
++{
++    t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
++
++    if (p_FmMacsecControllerDriver->f_FM_MACSEC_SetException)
++        return p_FmMacsecControllerDriver->f_FM_MACSEC_SetException(h_FmMacsec, exception, enable);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.h
+@@ -0,0 +1,203 @@
++/*
++ * Copyright 2008-2015 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/******************************************************************************
++ @File          fm_macsec.h
++
++ @Description   FM MACSEC internal structures and definitions.
++*//***************************************************************************/
++#ifndef __FM_MACSEC_H
++#define __FM_MACSEC_H
++
++#include "error_ext.h"
++#include "std_ext.h"
++#include "fm_macsec_ext.h"
++
++#include "fm_common.h"
++
++
++#define __ERR_MODULE__  MODULE_FM_MACSEC
++
++
++typedef struct
++{
++    t_Error (*f_FM_MACSEC_Init) (t_Handle h_FmMacsec);
++    t_Error (*f_FM_MACSEC_Free) (t_Handle h_FmMacsec);
++
++    t_Error (*f_FM_MACSEC_ConfigUnknownSciFrameTreatment) (t_Handle h_FmMacsec, e_FmMacsecUnknownSciFrameTreatment treatMode);
++    t_Error (*f_FM_MACSEC_ConfigInvalidTagsFrameTreatment) (t_Handle h_FmMacsec, bool deliverUncontrolled);
++    t_Error (*f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment) (t_Handle h_FmMacsec, bool discardUncontrolled);
++    t_Error (*f_FM_MACSEC_ConfigChangedTextWithNoEncryptFrameTreatment) (t_Handle h_FmMacsec, bool deliverUncontrolled);
++    t_Error (*f_FM_MACSEC_ConfigUntagFrameTreatment) (t_Handle h_FmMacsec, e_FmMacsecUntagFrameTreatment treatMode);
++    t_Error (*f_FM_MACSEC_ConfigOnlyScbIsSetFrameTreatment) (t_Handle h_FmMacsec, bool deliverUncontrolled);
++    t_Error (*f_FM_MACSEC_ConfigPnExhaustionThreshold) (t_Handle h_FmMacsec, uint32_t pnExhThr);
++    t_Error (*f_FM_MACSEC_ConfigKeysUnreadable) (t_Handle h_FmMacsec);
++    t_Error (*f_FM_MACSEC_ConfigSectagWithoutSCI) (t_Handle h_FmMacsec);
++    t_Error (*f_FM_MACSEC_ConfigException) (t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable);
++
++    t_Error (*f_FM_MACSEC_GetRevision) (t_Handle h_FmMacsec, uint32_t *p_MacsecRevision);
++    t_Error (*f_FM_MACSEC_Enable) (t_Handle h_FmMacsec);
++    t_Error (*f_FM_MACSEC_Disable) (t_Handle h_FmMacsec);
++    t_Error (*f_FM_MACSEC_SetException) (t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable);
++
++} t_FmMacsecControllerDriver;
++
++t_Handle  FM_MACSEC_GUEST_Config(t_FmMacsecParams *p_FmMacsecParam);
++t_Handle  FM_MACSEC_MASTER_Config(t_FmMacsecParams *p_FmMacsecParams);
++
++/***********************************************************************/
++/*  MACSEC internal routines                                              */
++/***********************************************************************/
++
++/**************************************************************************//**
++
++ @Group         FM_MACSEC_InterModule_grp FM MACSEC Inter-Module Unit
++
++ @Description   FM MACSEC Inter Module functions -
++                These are not User API routines but routines that may be called
++                from other modules. This will be the case in a single core environment,
++                where instead of using the XX messaging mechanism, the routines may be
++                called from other modules. In a multicore environment, the other modules may
++                be run by other cores and therefore these routines may not be called directly.
++
++ @{
++*//***************************************************************************/
++
++#define MAX_NUM_OF_SA_PER_SC        4
++
++typedef enum
++{
++    e_SC_RX = 0,
++    e_SC_TX
++} e_ScType;
++
++typedef enum
++{
++    e_SC_SA_A = 0,
++    e_SC_SA_B ,
++    e_SC_SA_C ,
++    e_SC_SA_D
++} e_ScSaId;
++
++typedef struct
++{
++    uint32_t                        scId;
++    macsecSCI_t                     sci;
++    bool                            replayProtect;
++    uint32_t                        replayWindow;
++    e_FmMacsecValidFrameBehavior    validateFrames;
++    uint16_t                        confidentialityOffset;
++    e_FmMacsecSecYCipherSuite       cipherSuite;
++} t_RxScParams;
++
++typedef struct
++{
++    uint32_t                        scId;
++    macsecSCI_t                     sci;
++    bool                            protectFrames;
++    e_FmMacsecSciInsertionMode      sciInsertionMode;
++    bool                            confidentialityEnable;
++    uint16_t                        confidentialityOffset;
++    e_FmMacsecSecYCipherSuite       cipherSuite;
++} t_TxScParams;
++
++typedef enum e_FmMacsecGlobalExceptions {
++    e_FM_MACSEC_EX_TX_SC,               /**< Tx Sc 0 frame discarded error. */
++    e_FM_MACSEC_EX_ECC                  /**< MACSEC memory ECC multiple-bit error. */
++} e_FmMacsecGlobalExceptions;
++
++typedef enum e_FmMacsecGlobalEvents {
++    e_FM_MACSEC_EV_TX_SC_NEXT_PN        /**< Tx Sc 0 Next Pn exhaustion threshold reached. */
++} e_FmMacsecGlobalEvents;
++
++/**************************************************************************//**
++ @Description   Enum for inter-module interrupts registration
++*//***************************************************************************/
++typedef enum e_FmMacsecEventModules{
++    e_FM_MACSEC_MOD_SC_TX,
++    e_FM_MACSEC_MOD_DUMMY_LAST
++} e_FmMacsecEventModules;
++
++typedef enum e_FmMacsecInterModuleEvent {
++    e_FM_MACSEC_EV_SC_TX,
++    e_FM_MACSEC_EV_ERR_SC_TX,
++    e_FM_MACSEC_EV_DUMMY_LAST
++} e_FmMacsecInterModuleEvent;
++
++#define NUM_OF_INTER_MODULE_EVENTS (NUM_OF_TX_SC * 2)
++
++#define GET_MACSEC_MODULE_EVENT(mod, id, intrType, event) \
++    switch(mod){                                          \
++        case e_FM_MACSEC_MOD_SC_TX:                       \
++             event = (intrType == e_FM_INTR_TYPE_ERR) ?   \
++                        e_FM_MACSEC_EV_ERR_SC_TX:         \
++                        e_FM_MACSEC_EV_SC_TX;             \
++             event += (uint8_t)(2 * id);break;            \
++            break;                                        \
++        default:event = e_FM_MACSEC_EV_DUMMY_LAST;        \
++        break;}
++
++void FmMacsecRegisterIntr(t_Handle                h_FmMacsec,
++                          e_FmMacsecEventModules  module,
++                          uint8_t                 modId,
++                          e_FmIntrType            intrType,
++                          void (*f_Isr) (t_Handle h_Arg, uint32_t id),
++                          t_Handle                h_Arg);
++
++void FmMacsecUnregisterIntr(t_Handle                h_FmMacsec,
++                            e_FmMacsecEventModules  module,
++                            uint8_t                 modId,
++                            e_FmIntrType            intrType);
++
++t_Error FmMacsecAllocScs(t_Handle h_FmMacsec, e_ScType type, bool isPtp, uint32_t numOfScs, uint32_t *p_ScIds);
++t_Error FmMacsecFreeScs(t_Handle h_FmMacsec, e_ScType type, uint32_t numOfScs, uint32_t *p_ScIds);
++t_Error FmMacsecCreateRxSc(t_Handle h_FmMacsec, t_RxScParams *p_RxScParams);
++t_Error FmMacsecDeleteRxSc(t_Handle h_FmMacsec, uint32_t scId);
++t_Error FmMacsecCreateTxSc(t_Handle h_FmMacsec, t_TxScParams *p_RxScParams);
++t_Error FmMacsecDeleteTxSc(t_Handle h_FmMacsec, uint32_t scId);
++t_Error FmMacsecCreateRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an, uint32_t lowestPn, macsecSAKey_t key);
++t_Error FmMacsecCreateTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecSAKey_t key);
++t_Error FmMacsecDeleteRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId);
++t_Error FmMacsecDeleteTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId);
++t_Error FmMacsecRxSaSetReceive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, bool enableReceive);
++t_Error FmMacsecRxSaUpdateNextPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtNextPN);
++t_Error FmMacsecRxSaUpdateLowestPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtLowestPN);
++t_Error FmMacsecTxSaSetActive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an);
++t_Error FmMacsecTxSaGetActive(t_Handle h_FmMacsec, uint32_t scId, macsecAN_t *p_An);
++t_Error FmMacsecSetPTP(t_Handle h_FmMacsec, bool enable);
++
++t_Error FmMacsecSetException(t_Handle h_FmMacsec, e_FmMacsecGlobalExceptions exception, uint32_t scId, bool enable);
++t_Error FmMacsecSetEvent(t_Handle h_FmMacsec, e_FmMacsecGlobalEvents event, uint32_t scId, bool enable);
++
++
++
++#endif /* __FM_MACSEC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_guest.c
+@@ -0,0 +1,59 @@
++/*
++ * Copyright 2008-2015 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/******************************************************************************
++ @File          fm_macsec.c
++
++ @Description   FM MACSEC driver routines implementation.
++*//***************************************************************************/
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "xx_ext.h"
++#include "string_ext.h"
++#include "sprint_ext.h"
++#include "debug_ext.h"
++#include "fm_macsec.h"
++
++
++/****************************************/
++/*       static functions               */
++/****************************************/
++
++/****************************************/
++/*       API Init unit functions        */
++/****************************************/
++t_Handle FM_MACSEC_GUEST_Config(t_FmMacsecParams *p_FmMacsecParam)
++{
++    UNUSED(p_FmMacsecParam);
++    return NULL;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.c
+@@ -0,0 +1,1031 @@
++/*
++ * Copyright 2008-2015 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/******************************************************************************
++ @File          fm_macsec.c
++
++ @Description   FM MACSEC driver routines implementation.
++*//***************************************************************************/
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "xx_ext.h"
++#include "string_ext.h"
++#include "sprint_ext.h"
++#include "fm_mac_ext.h"
++
++#include "fm_macsec_master.h"
++
++
++extern uint16_t    FM_MAC_GetMaxFrameLength(t_Handle FmMac);
++
++
++/****************************************/
++/*       static functions               */
++/****************************************/
++static t_Error CheckFmMacsecParameters(t_FmMacsec *p_FmMacsec)
++{
++    if (!p_FmMacsec->f_Exception)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided"));
++
++    return E_OK;
++}
++
++static void UnimplementedIsr(t_Handle h_Arg, uint32_t id)
++{
++    UNUSED(h_Arg); UNUSED(id);
++
++    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unimplemented Isr!"));
++}
++
++static void MacsecEventIsr(t_Handle h_FmMacsec)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    uint32_t    events,event,i;
++
++    SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE);
++
++    events = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->evr);
++    events |= GET_UINT32(p_FmMacsec->p_FmMacsecRegs->ever);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->evr,events);
++
++    for (i=0; i<NUM_OF_TX_SC; i++)
++        if (events & FM_MACSEC_EV_TX_SC_NEXT_PN(i))
++        {
++            GET_MACSEC_MODULE_EVENT(e_FM_MACSEC_MOD_SC_TX, i, e_FM_INTR_TYPE_NORMAL, event);
++            p_FmMacsec->intrMng[event].f_Isr(p_FmMacsec->intrMng[event].h_SrcHandle, i);
++        }
++}
++
++static void MacsecErrorIsr(t_Handle h_FmMacsec)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    uint32_t    errors,error,i;
++
++    SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE);
++
++    errors = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->err);
++    errors |= GET_UINT32(p_FmMacsec->p_FmMacsecRegs->erer);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->err,errors);
++
++    for (i=0; i<NUM_OF_TX_SC; i++)
++        if (errors & FM_MACSEC_EX_TX_SC(i))
++        {
++            GET_MACSEC_MODULE_EVENT(e_FM_MACSEC_MOD_SC_TX, i, e_FM_INTR_TYPE_ERR, error);
++            p_FmMacsec->intrMng[error].f_Isr(p_FmMacsec->intrMng[error].h_SrcHandle, i);
++        }
++
++    if (errors & FM_MACSEC_EX_ECC)
++    {
++        uint8_t     eccType;
++        uint32_t    tmpReg;
++
++        tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->meec);
++        ASSERT_COND(tmpReg & MECC_CAP);
++        eccType = (uint8_t)((tmpReg & MECC_CET) >> MECC_CET_SHIFT);
++
++        if (!eccType && (p_FmMacsec->userExceptions & FM_MACSEC_USER_EX_SINGLE_BIT_ECC))
++            p_FmMacsec->f_Exception(p_FmMacsec->h_App,e_FM_MACSEC_EX_SINGLE_BIT_ECC);
++        else if (eccType && (p_FmMacsec->userExceptions & FM_MACSEC_USER_EX_MULTI_BIT_ECC))
++            p_FmMacsec->f_Exception(p_FmMacsec->h_App,e_FM_MACSEC_EX_MULTI_BIT_ECC);
++        else
++            WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->meec,tmpReg);
++    }
++}
++
++static t_Error MacsecInit(t_Handle h_FmMacsec)
++{
++    t_FmMacsec                  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_FmMacsecDriverParam       *p_FmMacsecDriverParam = NULL;
++    uint32_t                    tmpReg,i,macId;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    CHECK_INIT_PARAMETERS(p_FmMacsec, CheckFmMacsecParameters);
++
++    p_FmMacsecDriverParam = p_FmMacsec->p_FmMacsecDriverParam;
++
++    for (i=0;i<e_FM_MACSEC_EV_DUMMY_LAST;i++)
++        p_FmMacsec->intrMng[i].f_Isr = UnimplementedIsr;
++
++    tmpReg = 0;
++    tmpReg |= (p_FmMacsecDriverParam->changedTextWithNoEncryptDeliverUncontrolled << CFG_UECT_SHIFT)|
++              (p_FmMacsecDriverParam->onlyScbIsSetDeliverUncontrolled << CFG_ESCBT_SHIFT)           |
++              (p_FmMacsecDriverParam->unknownSciTreatMode << CFG_USFT_SHIFT)                        |
++              (p_FmMacsecDriverParam->invalidTagsDeliverUncontrolled << CFG_ITT_SHIFT)              |
++              (p_FmMacsecDriverParam->encryptWithNoChangedTextDiscardUncontrolled << CFG_KFT_SHIFT) |
++              (p_FmMacsecDriverParam->untagTreatMode << CFG_UFT_SHIFT)                              |
++              (p_FmMacsecDriverParam->keysUnreadable << CFG_KSS_SHIFT)                              |
++              (p_FmMacsecDriverParam->reservedSc0 << CFG_S0I_SHIFT)                                 |
++              (p_FmMacsecDriverParam->byPassMode << CFG_BYPN_SHIFT);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg, tmpReg);
++
++    tmpReg = FM_MAC_GetMaxFrameLength(p_FmMacsec->h_FmMac);
++    /* At least Ethernet FCS (4 bytes) overhead must be subtracted from MFL.
++     * In addition, the SCI (8 bytes) overhead might be subtracted as well. */
++    tmpReg -= p_FmMacsecDriverParam->mflSubtract;
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->mfl, tmpReg);
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->tpnet, p_FmMacsecDriverParam->pnExhThr);
++
++    if (!p_FmMacsec->userExceptions)
++        p_FmMacsec->exceptions &= ~FM_MACSEC_EX_ECC;
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->erer, p_FmMacsec->exceptions);
++
++    p_FmMacsec->numRxScAvailable = NUM_OF_RX_SC;
++    if (p_FmMacsecDriverParam->reservedSc0)
++        p_FmMacsec->numRxScAvailable --;
++    p_FmMacsec->numTxScAvailable = NUM_OF_TX_SC;
++
++    XX_Free(p_FmMacsecDriverParam);
++    p_FmMacsec->p_FmMacsecDriverParam = NULL;
++
++    FM_MAC_GetId(p_FmMacsec->h_FmMac, &macId);
++    FmRegisterIntr(p_FmMacsec->h_Fm,
++                   e_FM_MOD_MACSEC,
++                   (uint8_t)macId,
++                   e_FM_INTR_TYPE_NORMAL,
++                   MacsecEventIsr,
++                   p_FmMacsec);
++
++    FmRegisterIntr(p_FmMacsec->h_Fm,
++                   e_FM_MOD_MACSEC,
++                   0,
++                   e_FM_INTR_TYPE_ERR,
++                   MacsecErrorIsr,
++                   p_FmMacsec);
++
++    return E_OK;
++}
++
++static t_Error MacsecFree(t_Handle h_FmMacsec)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    uint32_t    macId;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    FM_MAC_GetId(p_FmMacsec->h_FmMac, &macId);
++    FmUnregisterIntr(p_FmMacsec->h_Fm,
++                   e_FM_MOD_MACSEC,
++                   (uint8_t)macId,
++                   e_FM_INTR_TYPE_NORMAL);
++
++    FmUnregisterIntr(p_FmMacsec->h_Fm,
++                   e_FM_MOD_MACSEC,
++                   0,
++                   e_FM_INTR_TYPE_ERR);
++
++    if (p_FmMacsec->rxScSpinLock)
++        XX_FreeSpinlock(p_FmMacsec->rxScSpinLock);
++    if (p_FmMacsec->txScSpinLock)
++        XX_FreeSpinlock(p_FmMacsec->txScSpinLock);
++
++    XX_Free(p_FmMacsec);
++
++    return E_OK;
++}
++
++static t_Error MacsecConfigUnknownSciFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUnknownSciFrameTreatment treatMode)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    p_FmMacsec->p_FmMacsecDriverParam->unknownSciTreatMode = treatMode;
++
++    return E_OK;
++}
++
++static t_Error MacsecConfigInvalidTagsFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    p_FmMacsec->p_FmMacsecDriverParam->invalidTagsDeliverUncontrolled = deliverUncontrolled;
++
++    return E_OK;
++}
++
++static t_Error MacsecConfigChangedTextWithNoEncryptFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    p_FmMacsec->p_FmMacsecDriverParam->changedTextWithNoEncryptDeliverUncontrolled = deliverUncontrolled;
++
++    return E_OK;
++}
++
++static t_Error MacsecConfigOnlyScbIsSetFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    p_FmMacsec->p_FmMacsecDriverParam->onlyScbIsSetDeliverUncontrolled = deliverUncontrolled;
++
++    return E_OK;
++}
++
++static t_Error MacsecConfigEncryptWithNoChangedTextFrameTreatment(t_Handle h_FmMacsec, bool discardUncontrolled)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    p_FmMacsec->p_FmMacsecDriverParam->encryptWithNoChangedTextDiscardUncontrolled = discardUncontrolled;
++
++    return E_OK;
++}
++
++static t_Error MacsecConfigUntagFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUntagFrameTreatment treatMode)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    p_FmMacsec->p_FmMacsecDriverParam->untagTreatMode = treatMode;
++
++    return E_OK;
++}
++
++static t_Error MacsecConfigPnExhaustionThreshold(t_Handle h_FmMacsec, uint32_t pnExhThr)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    p_FmMacsec->p_FmMacsecDriverParam->pnExhThr = pnExhThr;
++
++    return E_OK;
++}
++
++static t_Error MacsecConfigKeysUnreadable(t_Handle h_FmMacsec)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    p_FmMacsec->p_FmMacsecDriverParam->keysUnreadable = TRUE;
++
++    return E_OK;
++}
++
++static t_Error MacsecConfigSectagWithoutSCI(t_Handle h_FmMacsec)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    p_FmMacsec->p_FmMacsecDriverParam->sectagOverhead -= MACSEC_SCI_SIZE;
++    p_FmMacsec->p_FmMacsecDriverParam->mflSubtract += MACSEC_SCI_SIZE;
++
++    return E_OK;
++}
++
++static t_Error MacsecConfigException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    uint32_t    bitMask = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    GET_USER_EXCEPTION_FLAG(bitMask, exception);
++    if (bitMask)
++    {
++        if (enable)
++            p_FmMacsec->userExceptions |= bitMask;
++        else
++            p_FmMacsec->userExceptions &= ~bitMask;
++    }
++    else
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
++
++    return E_OK;
++}
++
++static t_Error MacsecGetRevision(t_Handle h_FmMacsec, uint32_t *p_MacsecRevision)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    *p_MacsecRevision = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->ip_rev1);
++
++    return E_OK;
++}
++
++static t_Error MacsecEnable(t_Handle h_FmMacsec)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    uint32_t    tmpReg;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    tmpReg  = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg);
++    tmpReg |= CFG_BYPN;
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg,tmpReg);
++
++    return E_OK;
++}
++
++static t_Error MacsecDisable(t_Handle h_FmMacsec)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    uint32_t    tmpReg;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    tmpReg  = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg);
++    tmpReg &= ~CFG_BYPN;
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg,tmpReg);
++
++    return E_OK;
++}
++
++static t_Error MacsecSetException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    uint32_t    bitMask;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    GET_USER_EXCEPTION_FLAG(bitMask, exception);
++    if (bitMask)
++    {
++        if (enable)
++            p_FmMacsec->userExceptions |= bitMask;
++        else
++            p_FmMacsec->userExceptions &= ~bitMask;
++    }
++    else
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
++
++    if (!p_FmMacsec->userExceptions)
++        p_FmMacsec->exceptions &= ~FM_MACSEC_EX_ECC;
++    else
++        p_FmMacsec->exceptions |= FM_MACSEC_EX_ECC;
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->erer, p_FmMacsec->exceptions);
++
++    return E_OK;
++}
++
++static void InitFmMacsecControllerDriver(t_FmMacsecControllerDriver *p_FmMacsecControllerDriver)
++{
++    p_FmMacsecControllerDriver->f_FM_MACSEC_Init                                            = MacsecInit;
++    p_FmMacsecControllerDriver->f_FM_MACSEC_Free                                            = MacsecFree;
++    p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUnknownSciFrameTreatment                  = MacsecConfigUnknownSciFrameTreatment;
++    p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigInvalidTagsFrameTreatment                 = MacsecConfigInvalidTagsFrameTreatment;
++    p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment    = MacsecConfigEncryptWithNoChangedTextFrameTreatment;
++    p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUntagFrameTreatment                       = MacsecConfigUntagFrameTreatment;
++    p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigChangedTextWithNoEncryptFrameTreatment    = MacsecConfigChangedTextWithNoEncryptFrameTreatment;
++    p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigOnlyScbIsSetFrameTreatment                = MacsecConfigOnlyScbIsSetFrameTreatment;
++    p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigPnExhaustionThreshold                     = MacsecConfigPnExhaustionThreshold;
++    p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigKeysUnreadable                            = MacsecConfigKeysUnreadable;
++    p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigSectagWithoutSCI                          = MacsecConfigSectagWithoutSCI;
++    p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigException                                 = MacsecConfigException;
++    p_FmMacsecControllerDriver->f_FM_MACSEC_GetRevision                                     = MacsecGetRevision;
++    p_FmMacsecControllerDriver->f_FM_MACSEC_Enable                                          = MacsecEnable;
++    p_FmMacsecControllerDriver->f_FM_MACSEC_Disable                                         = MacsecDisable;
++    p_FmMacsecControllerDriver->f_FM_MACSEC_SetException                                    = MacsecSetException;
++}
++
++/****************************************/
++/*       Inter-Module functions         */
++/****************************************/
++
++void FmMacsecRegisterIntr(t_Handle                h_FmMacsec,
++                          e_FmMacsecEventModules  module,
++                          uint8_t                 modId,
++                          e_FmIntrType            intrType,
++                          void (*f_Isr) (t_Handle h_Arg, uint32_t id),
++                          t_Handle                h_Arg)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    uint8_t     event= 0;
++
++    SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE);
++
++    GET_MACSEC_MODULE_EVENT(module, modId, intrType, event);
++
++    ASSERT_COND(event != e_FM_MACSEC_EV_DUMMY_LAST);
++    p_FmMacsec->intrMng[event].f_Isr = f_Isr;
++    p_FmMacsec->intrMng[event].h_SrcHandle = h_Arg;
++}
++
++void FmMacsecUnregisterIntr(t_Handle                h_FmMacsec,
++                            e_FmMacsecEventModules  module,
++                            uint8_t                 modId,
++                            e_FmIntrType            intrType)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    uint8_t     event= 0;
++
++    SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE);
++
++    GET_MACSEC_MODULE_EVENT(module, modId,intrType, event);
++
++    ASSERT_COND(event != e_FM_MACSEC_EV_DUMMY_LAST);
++    p_FmMacsec->intrMng[event].f_Isr = NULL;
++    p_FmMacsec->intrMng[event].h_SrcHandle = NULL;
++}
++
++t_Error FmMacsecAllocScs(t_Handle h_FmMacsec, e_ScType type, bool isPtp, uint32_t numOfScs, uint32_t *p_ScIds)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_Error     err = E_OK;
++    bool        *p_ScTable;
++    uint32_t    *p_ScAvailable,i;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_ScIds, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(numOfScs, E_INVALID_HANDLE);
++
++    if (type == e_SC_RX)
++    {
++        p_ScTable       = (bool *)p_FmMacsec->rxScTable;
++        p_ScAvailable   = &p_FmMacsec->numRxScAvailable;
++        i               = (NUM_OF_RX_SC - 1);
++    }
++    else
++    {
++        p_ScTable       = (bool *)p_FmMacsec->txScTable;
++        p_ScAvailable   = &p_FmMacsec->numTxScAvailable;
++        i               = (NUM_OF_TX_SC - 1);
++
++    }
++    if (*p_ScAvailable < numOfScs)
++        RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Not enough SCs available"));
++
++    if (isPtp)
++    {
++        i = 0;
++        if (p_ScTable[i])
++            RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Sc 0 Not available"));
++    }
++
++    for (;numOfScs;i--)
++    {
++        if (p_ScTable[i])
++            continue;
++        numOfScs --;
++        (*p_ScAvailable)--;
++        p_ScIds[numOfScs] = i;
++        p_ScTable[i] = TRUE;
++    }
++
++    return err;
++}
++
++t_Error FmMacsecFreeScs(t_Handle h_FmMacsec, e_ScType type, uint32_t numOfScs, uint32_t *p_ScIds)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_Error     err = E_OK;
++    bool        *p_ScTable;
++    uint32_t    *p_ScAvailable,maxNumOfSc,i;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_ScIds, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(numOfScs, E_INVALID_HANDLE);
++
++    if (type == e_SC_RX)
++    {
++        p_ScTable       = (bool *)p_FmMacsec->rxScTable;
++        p_ScAvailable   = &p_FmMacsec->numRxScAvailable;
++        maxNumOfSc      = NUM_OF_RX_SC;
++    }
++    else
++    {
++        p_ScTable       = (bool *)p_FmMacsec->txScTable;
++        p_ScAvailable   = &p_FmMacsec->numTxScAvailable;
++        maxNumOfSc      = NUM_OF_TX_SC;
++    }
++
++    if ((*p_ScAvailable + numOfScs) > maxNumOfSc)
++        RETURN_ERROR(MINOR, E_FULL, ("Too much SCs"));
++
++    for (i=0;i<numOfScs;i++)
++    {
++        p_ScTable[p_ScIds[i]] = FALSE;
++        (*p_ScAvailable)++;
++    }
++
++    return err;
++
++}
++
++t_Error FmMacsecSetPTP(t_Handle h_FmMacsec, bool enable)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    uint32_t    tmpReg = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++
++    tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg);
++    if (enable && (tmpReg & CFG_S0I))
++        RETURN_ERROR(MINOR, E_INVALID_STATE, ("MACSEC already in point-to-point mode"));
++
++    if (enable)
++        tmpReg |= CFG_S0I;
++    else
++        tmpReg &= ~CFG_S0I;
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg, tmpReg);
++
++    return E_OK;
++}
++
++t_Error FmMacsecCreateRxSc(t_Handle h_FmMacsec, t_RxScParams *p_RxScParams)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_Error     err = E_OK;
++    uint32_t    tmpReg = 0, intFlags;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_RxScParams, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_RxScParams->scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
++
++    intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock);
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, p_RxScParams->scId);
++    tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsccfg);
++    if (tmpReg & RX_SCCFG_SCI_EN_MASK)
++    {
++        XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
++        RETURN_ERROR(MINOR, E_INVALID_STATE, ("Rx Sc %d must be disable",p_RxScParams->scId));
++    }
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsci1h, GET_SCI_FIRST_HALF(p_RxScParams->sci));
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsci2h, GET_SCI_SECOND_HALF(p_RxScParams->sci));
++    tmpReg |= ((p_RxScParams->replayProtect << RX_SCCFG_RP_SHIFT) & RX_SCCFG_RP_MASK);
++    tmpReg |= ((p_RxScParams->validateFrames << RX_SCCFG_VF_SHIFT) & RX_SCCFG_VF_MASK);
++    tmpReg |= ((p_RxScParams->confidentialityOffset << RX_SCCFG_CO_SHIFT) & RX_SCCFG_CO_MASK);
++    tmpReg |= RX_SCCFG_SCI_EN_MASK;
++    tmpReg |= (p_RxScParams->cipherSuite << RX_SCCFG_CS_SHIFT);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsccfg, tmpReg);
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rpw, p_RxScParams->replayWindow);
++
++    XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
++
++    return err;
++}
++
++t_Error FmMacsecDeleteRxSc(t_Handle h_FmMacsec, uint32_t scId)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_Error     err = E_OK;
++    uint32_t    tmpReg = 0, intFlags;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
++
++    intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock);
++
++    tmpReg &= ~RX_SCCFG_SCI_EN_MASK;
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsccfg, tmpReg);
++
++    XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
++
++    return err;
++}
++
++t_Error FmMacsecCreateTxSc(t_Handle h_FmMacsec, t_TxScParams *p_TxScParams)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_Error     err = E_OK;
++    uint32_t    tmpReg = 0, intFlags;
++    bool        alwaysIncludeSCI = FALSE, useES = FALSE, useSCB = FALSE;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_TxScParams, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_TxScParams->scId < NUM_OF_TX_SC, E_INVALID_HANDLE);
++
++    intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock);
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, p_TxScParams->scId);
++
++    tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg);
++    if (tmpReg & TX_SCCFG_SCE_MASK)
++    {
++        XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags);
++        RETURN_ERROR(MINOR, E_INVALID_STATE, ("Tx Sc %d must be disable",p_TxScParams->scId));
++    }
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsci1h, GET_SCI_FIRST_HALF(p_TxScParams->sci));
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsci2h, GET_SCI_SECOND_HALF(p_TxScParams->sci));
++    alwaysIncludeSCI = (p_TxScParams->sciInsertionMode == e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_SECTAG);
++    useES            = (p_TxScParams->sciInsertionMode == e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_MAC_SA);
++
++    tmpReg |= ((p_TxScParams->protectFrames << TX_SCCFG_PF_SHIFT) & TX_SCCFG_PF_MASK);
++    tmpReg |= ((alwaysIncludeSCI << TX_SCCFG_AIS_SHIFT) & TX_SCCFG_AIS_MASK);
++    tmpReg |= ((useES << TX_SCCFG_UES_SHIFT) & TX_SCCFG_UES_MASK);
++    tmpReg |= ((useSCB << TX_SCCFG_USCB_SHIFT) & TX_SCCFG_USCB_MASK);
++    tmpReg |= ((p_TxScParams->confidentialityEnable << TX_SCCFG_CE_SHIFT) & TX_SCCFG_CE_MASK);
++    tmpReg |= ((p_TxScParams->confidentialityOffset << TX_SCCFG_CO_SHIFT) & TX_SCCFG_CO_MASK);
++    tmpReg |= TX_SCCFG_SCE_MASK;
++    tmpReg |= (p_TxScParams->cipherSuite << TX_SCCFG_CS_SHIFT);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg, tmpReg);
++
++    XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags);
++
++    return err;
++}
++
++t_Error FmMacsecDeleteTxSc(t_Handle h_FmMacsec, uint32_t scId)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_Error     err = E_OK;
++    uint32_t    tmpReg = 0, intFlags;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_TX_SC, E_INVALID_HANDLE);
++
++    intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock);
++
++    tmpReg &= ~TX_SCCFG_SCE_MASK;
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg, tmpReg);
++
++    XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags);
++
++    return err;
++}
++
++t_Error FmMacsecCreateRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an, uint32_t lowestPn, macsecSAKey_t key)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_Error     err = E_OK;
++    uint32_t    tmpReg = 0, intFlags;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE);
++
++    intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock);
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsanpn, DEFAULT_initNextPn);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsalpn, lowestPn);
++    MemCpy8((void*)p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsak, key, sizeof(macsecSAKey_t));
++
++    tmpReg |= RX_SACFG_ACTIVE;
++    tmpReg |= ((an << RX_SACFG_AN_SHIFT) & RX_SACFG_AN_MASK);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs, tmpReg);
++
++    XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
++
++    return err;
++}
++
++t_Error FmMacsecCreateTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecSAKey_t key)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_Error     err = E_OK;
++    uint32_t    tmpReg = 0, intFlags;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_TX_SC, E_INVALID_HANDLE);
++
++    intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock);
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsanpn, DEFAULT_initNextPn);
++    MemCpy8((void*)p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsak, key, sizeof(macsecSAKey_t));
++
++    tmpReg |= TX_SACFG_ACTIVE;
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsacs, tmpReg);
++
++    XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags);
++
++    return err;
++}
++
++t_Error FmMacsecDeleteRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_Error     err = E_OK;
++    uint32_t    tmpReg = 0, i, intFlags;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE);
++
++    intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock);
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsanpn, 0x0);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsalpn, 0x0);
++    for (i=0; i<4; i++)
++        WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsak[i], 0x0);
++
++    tmpReg |= RX_SACFG_ACTIVE;
++    tmpReg &= ~RX_SACFG_EN_MASK;
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs, tmpReg);
++
++    XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
++
++    return err;
++}
++
++t_Error FmMacsecDeleteTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_Error     err = E_OK;
++    uint32_t    tmpReg = 0, i, intFlags;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_TX_SC, E_INVALID_HANDLE);
++
++    intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock);
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsanpn, 0x0);
++    for (i=0; i<4; i++)
++        WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsak[i], 0x0);
++
++    tmpReg |= TX_SACFG_ACTIVE;
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsacs, tmpReg);
++
++    XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags);
++
++    return err;
++}
++
++t_Error FmMacsecRxSaSetReceive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, bool enableReceive)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_Error     err = E_OK;
++    uint32_t    tmpReg = 0, intFlags;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE);
++
++    intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock);
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId);
++    tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs);
++    if (enableReceive)
++        tmpReg |= RX_SACFG_EN_MASK;
++    else
++        tmpReg &= ~RX_SACFG_EN_MASK;
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs, tmpReg);
++
++    XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
++
++    return err;
++}
++
++t_Error FmMacsecRxSaUpdateNextPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtNextPN)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_Error     err = E_OK;
++    uint32_t    intFlags;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE);
++
++    intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock);
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsanpn, updtNextPN);
++
++    XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
++
++    return err;
++}
++
++t_Error FmMacsecRxSaUpdateLowestPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtLowestPN)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_Error     err = E_OK;
++    uint32_t    intFlags;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE);
++
++    intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock);
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId);
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsalpn, updtLowestPN);
++
++    XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
++
++    return err;
++}
++
++t_Error FmMacsecTxSaSetActive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_Error     err = E_OK;
++    uint32_t    tmpReg = 0, intFlags;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_TX_SC, E_INVALID_HANDLE);
++
++    intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock);
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId);
++
++    tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg);
++
++    tmpReg |= ((an << TX_SCCFG_AN_SHIFT) & TX_SCCFG_AN_MASK);
++    tmpReg |= ((saId << TX_SCCFG_ASA_SHIFT) & TX_SCCFG_ASA_MASK);
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg, tmpReg);
++
++    XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags);
++
++    return err;
++}
++
++t_Error FmMacsecTxSaGetActive(t_Handle h_FmMacsec, uint32_t scId, macsecAN_t *p_An)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    t_Error     err = E_OK;
++    uint32_t    tmpReg = 0, intFlags;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_An, E_INVALID_HANDLE);
++
++    intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock);
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId);
++
++    tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg);
++
++    XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags);
++
++    *p_An = (macsecAN_t)((tmpReg & TX_SCCFG_AN_MASK) >> TX_SCCFG_AN_SHIFT);
++
++    return err;
++}
++
++t_Error FmMacsecSetException(t_Handle h_FmMacsec, e_FmMacsecGlobalExceptions exception, uint32_t scId, bool enable)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    uint32_t    bitMask;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    GET_EXCEPTION_FLAG(bitMask, exception, scId);
++    if (bitMask)
++    {
++        if (enable)
++            p_FmMacsec->exceptions |= bitMask;
++        else
++            p_FmMacsec->exceptions &= ~bitMask;
++    }
++    else
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->erer, p_FmMacsec->exceptions);
++
++    return E_OK;
++}
++
++t_Error FmMacsecSetEvent(t_Handle h_FmMacsec, e_FmMacsecGlobalEvents event, uint32_t scId, bool enable)
++{
++    t_FmMacsec  *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
++    uint32_t    bitMask;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
++
++    GET_EVENT_FLAG(bitMask, event, scId);
++    if (bitMask)
++    {
++        if (enable)
++            p_FmMacsec->events |= bitMask;
++        else
++            p_FmMacsec->events &= ~bitMask;
++    }
++    else
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined event"));
++
++    WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->ever, p_FmMacsec->events);
++
++    return E_OK;
++}
++
++/****************************************/
++/*       API Init unit functions        */
++/****************************************/
++t_Handle FM_MACSEC_MASTER_Config(t_FmMacsecParams *p_FmMacsecParam)
++{
++    t_FmMacsec  *p_FmMacsec;
++    uint32_t    macId;
++
++    /* Allocate FM MACSEC structure */
++    p_FmMacsec = (t_FmMacsec *) XX_Malloc(sizeof(t_FmMacsec));
++    if (!p_FmMacsec)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC driver structure"));
++        return NULL;
++    }
++    memset(p_FmMacsec, 0, sizeof(t_FmMacsec));
++    InitFmMacsecControllerDriver(&p_FmMacsec->fmMacsecControllerDriver);
++
++    /* Allocate the FM MACSEC driver's parameters structure */
++    p_FmMacsec->p_FmMacsecDriverParam = (t_FmMacsecDriverParam *)XX_Malloc(sizeof(t_FmMacsecDriverParam));
++    if (!p_FmMacsec->p_FmMacsecDriverParam)
++    {
++        XX_Free(p_FmMacsec);
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC driver parameters"));
++        return NULL;
++    }
++    memset(p_FmMacsec->p_FmMacsecDriverParam, 0, sizeof(t_FmMacsecDriverParam));
++
++    /* Initialize FM MACSEC parameters which will be kept by the driver */
++    p_FmMacsec->h_Fm            = p_FmMacsecParam->h_Fm;
++    p_FmMacsec->h_FmMac         = p_FmMacsecParam->nonGuestParams.h_FmMac;
++    p_FmMacsec->p_FmMacsecRegs  = (t_FmMacsecRegs *)UINT_TO_PTR(p_FmMacsecParam->nonGuestParams.baseAddr);
++    p_FmMacsec->f_Exception     = p_FmMacsecParam->nonGuestParams.f_Exception;
++    p_FmMacsec->h_App           = p_FmMacsecParam->nonGuestParams.h_App;
++    p_FmMacsec->userExceptions  = DEFAULT_userExceptions;
++    p_FmMacsec->exceptions      = DEFAULT_exceptions;
++    p_FmMacsec->events          = DEFAULT_events;
++    p_FmMacsec->rxScSpinLock    = XX_InitSpinlock();
++    p_FmMacsec->txScSpinLock    = XX_InitSpinlock();
++
++    /* Initialize FM MACSEC driver parameters parameters (for initialization phase only) */
++    p_FmMacsec->p_FmMacsecDriverParam->unknownSciTreatMode                           = DEFAULT_unknownSciFrameTreatment;
++    p_FmMacsec->p_FmMacsecDriverParam->invalidTagsDeliverUncontrolled                = DEFAULT_invalidTagsFrameTreatment;
++    p_FmMacsec->p_FmMacsecDriverParam->encryptWithNoChangedTextDiscardUncontrolled   = DEFAULT_encryptWithNoChangedTextFrameTreatment;
++    p_FmMacsec->p_FmMacsecDriverParam->untagTreatMode                                = DEFAULT_untagFrameTreatment;
++    p_FmMacsec->p_FmMacsecDriverParam->keysUnreadable                                = DEFAULT_keysUnreadable;
++    p_FmMacsec->p_FmMacsecDriverParam->reservedSc0                                   = DEFAULT_sc0ReservedForPTP;
++    p_FmMacsec->p_FmMacsecDriverParam->byPassMode                                    = !DEFAULT_normalMode;
++    p_FmMacsec->p_FmMacsecDriverParam->pnExhThr                                      = DEFAULT_pnExhThr;
++    p_FmMacsec->p_FmMacsecDriverParam->sectagOverhead                                = DEFAULT_sectagOverhead;
++    p_FmMacsec->p_FmMacsecDriverParam->mflSubtract                                   = DEFAULT_mflSubtract;
++    /* build the FM MACSEC master IPC address */
++    memset(p_FmMacsec->fmMacsecModuleName, 0, (sizeof(char))*MODULE_NAME_SIZE);
++    FM_MAC_GetId(p_FmMacsec->h_FmMac,&macId);
++    if (Sprint (p_FmMacsec->fmMacsecModuleName, "FM-%d-MAC-%d-MACSEC-Master",
++        FmGetId(p_FmMacsec->h_Fm),macId) != 24)
++    {
++        XX_Free(p_FmMacsec->p_FmMacsecDriverParam);
++        XX_Free(p_FmMacsec);
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
++        return NULL;
++    }
++    return p_FmMacsec;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.h
+@@ -0,0 +1,479 @@
++/*
++ * Copyright 2008-2015 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/******************************************************************************
++ @File          fm_macsec_master.h
++
++ @Description   FM MACSEC internal structures and definitions.
++*//***************************************************************************/
++#ifndef __FM_MACSEC_MASTER_H
++#define __FM_MACSEC_MASTER_H
++
++#include "error_ext.h"
++#include "std_ext.h"
++
++#include "fm_macsec.h"
++
++
++#define MACSEC_ICV_SIZE             16
++#define MACSEC_SECTAG_SIZE          16
++#define MACSEC_SCI_SIZE             8
++#define MACSEC_FCS_SIZE             4
++
++/**************************************************************************//**
++ @Description       Exceptions
++*//***************************************************************************/
++
++#define FM_MACSEC_EX_TX_SC_0       0x80000000
++#define FM_MACSEC_EX_TX_SC(sc)     (FM_MACSEC_EX_TX_SC_0 >> (sc))
++#define FM_MACSEC_EX_ECC           0x00000001
++
++#define GET_EXCEPTION_FLAG(bitMask, exception, id)  switch (exception){     \
++    case e_FM_MACSEC_EX_TX_SC:                                              \
++        bitMask = FM_MACSEC_EX_TX_SC(id); break;                            \
++    case e_FM_MACSEC_EX_ECC:                                                \
++        bitMask = FM_MACSEC_EX_ECC; break;                                  \
++    default: bitMask = 0;break;}
++
++#define FM_MACSEC_USER_EX_SINGLE_BIT_ECC            0x80000000
++#define FM_MACSEC_USER_EX_MULTI_BIT_ECC             0x40000000
++
++#define GET_USER_EXCEPTION_FLAG(bitMask, exception)     switch (exception){ \
++    case e_FM_MACSEC_EX_SINGLE_BIT_ECC:                                     \
++        bitMask = FM_MACSEC_USER_EX_SINGLE_BIT_ECC; break;                  \
++    case e_FM_MACSEC_EX_MULTI_BIT_ECC:                                      \
++        bitMask = FM_MACSEC_USER_EX_MULTI_BIT_ECC; break;                   \
++    default: bitMask = 0;break;}
++
++/**************************************************************************//**
++ @Description       Events
++*//***************************************************************************/
++
++#define FM_MACSEC_EV_TX_SC_0_NEXT_PN                  0x80000000
++#define FM_MACSEC_EV_TX_SC_NEXT_PN(sc)                (FM_MACSEC_EV_TX_SC_0_NEXT_PN >> (sc))
++
++#define GET_EVENT_FLAG(bitMask, event, id)      switch (event){     \
++    case e_FM_MACSEC_EV_TX_SC_NEXT_PN:                              \
++        bitMask = FM_MACSEC_EV_TX_SC_NEXT_PN(id); break;            \
++    default: bitMask = 0;break;}
++
++/**************************************************************************//**
++ @Description       Defaults
++*//***************************************************************************/
++#define DEFAULT_userExceptions              (FM_MACSEC_USER_EX_SINGLE_BIT_ECC     |\
++                                            FM_MACSEC_USER_EX_MULTI_BIT_ECC)
++
++#define DEFAULT_exceptions                  (FM_MACSEC_EX_TX_SC(0)     |\
++                                            FM_MACSEC_EX_TX_SC(1)      |\
++                                            FM_MACSEC_EX_TX_SC(2)      |\
++                                            FM_MACSEC_EX_TX_SC(3)      |\
++                                            FM_MACSEC_EX_TX_SC(4)      |\
++                                            FM_MACSEC_EX_TX_SC(5)      |\
++                                            FM_MACSEC_EX_TX_SC(6)      |\
++                                            FM_MACSEC_EX_TX_SC(7)      |\
++                                            FM_MACSEC_EX_TX_SC(8)      |\
++                                            FM_MACSEC_EX_TX_SC(9)      |\
++                                            FM_MACSEC_EX_TX_SC(10)     |\
++                                            FM_MACSEC_EX_TX_SC(11)     |\
++                                            FM_MACSEC_EX_TX_SC(12)     |\
++                                            FM_MACSEC_EX_TX_SC(13)     |\
++                                            FM_MACSEC_EX_TX_SC(14)     |\
++                                            FM_MACSEC_EX_TX_SC(15)     |\
++                                            FM_MACSEC_EX_ECC          )
++
++#define DEFAULT_events                      (FM_MACSEC_EV_TX_SC_NEXT_PN(0)   |\
++                                            FM_MACSEC_EV_TX_SC_NEXT_PN(1)    |\
++                                            FM_MACSEC_EV_TX_SC_NEXT_PN(2)    |\
++                                            FM_MACSEC_EV_TX_SC_NEXT_PN(3)    |\
++                                            FM_MACSEC_EV_TX_SC_NEXT_PN(4)    |\
++                                            FM_MACSEC_EV_TX_SC_NEXT_PN(5)    |\
++                                            FM_MACSEC_EV_TX_SC_NEXT_PN(6)    |\
++                                            FM_MACSEC_EV_TX_SC_NEXT_PN(7)    |\
++                                            FM_MACSEC_EV_TX_SC_NEXT_PN(8)    |\
++                                            FM_MACSEC_EV_TX_SC_NEXT_PN(9)    |\
++                                            FM_MACSEC_EV_TX_SC_NEXT_PN(10)   |\
++                                            FM_MACSEC_EV_TX_SC_NEXT_PN(11)   |\
++                                            FM_MACSEC_EV_TX_SC_NEXT_PN(12)   |\
++                                            FM_MACSEC_EV_TX_SC_NEXT_PN(13)   |\
++                                            FM_MACSEC_EV_TX_SC_NEXT_PN(14)   |\
++                                            FM_MACSEC_EV_TX_SC_NEXT_PN(15)   )
++
++#define DEFAULT_unknownSciFrameTreatment                e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_BOTH
++#define DEFAULT_invalidTagsFrameTreatment               FALSE
++#define DEFAULT_encryptWithNoChangedTextFrameTreatment  FALSE
++#define DEFAULT_untagFrameTreatment                     e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED
++#define DEFAULT_changedTextWithNoEncryptFrameTreatment  FALSE
++#define DEFAULT_onlyScbIsSetFrameTreatment              FALSE
++#define DEFAULT_keysUnreadable                          FALSE
++#define DEFAULT_normalMode                              TRUE
++#define DEFAULT_sc0ReservedForPTP                       FALSE
++#define DEFAULT_initNextPn                              1
++#define DEFAULT_pnExhThr                                0xffffffff
++#define DEFAULT_sectagOverhead                          (MACSEC_ICV_SIZE + MACSEC_SECTAG_SIZE)
++#define DEFAULT_mflSubtract                             MACSEC_FCS_SIZE
++
++
++/**************************************************************************//**
++ @Description       Memory Mapped Registers
++*//***************************************************************************/
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(push,1)
++#endif /* defined(__MWERKS__) && ... */
++
++typedef _Packed struct
++{
++    /* MACsec configuration */
++    volatile uint32_t   cfg;            /**< MACsec configuration */
++    volatile uint32_t   et;             /**< MACsec EtherType */
++    volatile uint8_t    res1[56];       /**< reserved */
++    volatile uint32_t   mfl;            /**< Maximum Frame Length */
++    volatile uint32_t   tpnet;          /**< TX Packet Number exhaustion threshold */
++    volatile uint8_t    res2[56];       /**< reserved */
++    volatile uint32_t   rxsca;          /**< RX SC access select */
++    volatile uint8_t    res3[60];       /**< reserved */
++    volatile uint32_t   txsca;          /**< TX SC access select */
++    volatile uint8_t    res4[60];       /**< reserved */
++
++    /* RX configuration, status and statistic */
++    volatile uint32_t   rxsci1h;        /**< RX Secure Channel Identifier first half */
++    volatile uint32_t   rxsci2h;        /**< RX Secure Channel Identifier second half */
++    volatile uint8_t    res5[8];        /**< reserved */
++    volatile uint32_t   ifio1hs;        /**< ifInOctets first half Statistic */
++    volatile uint32_t   ifio2hs;        /**< ifInOctets second half Statistic */
++    volatile uint32_t   ifiups;         /**< ifInUcastPkts Statistic */
++    volatile uint8_t    res6[4];        /**< reserved */
++    volatile uint32_t   ifimps;         /**< ifInMulticastPkts Statistic */
++    volatile uint32_t   ifibps;         /**< ifInBroadcastPkts Statistic */
++    volatile uint32_t   rxsccfg;        /**< RX Secure Channel configuration */
++    volatile uint32_t   rpw;            /**< replayWindow */
++    volatile uint8_t    res7[16];       /**< reserved */
++    volatile uint32_t   inov1hs;        /**< InOctetsValidated first half Statistic */
++    volatile uint32_t   inov2hs;        /**< InOctetsValidated second half Statistic */
++    volatile uint32_t   inod1hs;        /**< InOctetsDecrypted first half Statistic */
++    volatile uint32_t   inod2hs;        /**< InOctetsDecrypted second half Statistic */
++    volatile uint32_t   rxscipus;       /**< RX Secure Channel InPktsUnchecked Statistic */
++    volatile uint32_t   rxscipds;       /**< RX Secure Channel InPktsDelayed Statistic */
++    volatile uint32_t   rxscipls;       /**< RX Secure Channel InPktsLate Statistic */
++    volatile uint8_t    res8[4];        /**< reserved */
++    volatile uint32_t   rxaninuss[MAX_NUM_OF_SA_PER_SC];   /**< RX AN 0-3 InNotUsingSA Statistic */
++    volatile uint32_t   rxanipuss[MAX_NUM_OF_SA_PER_SC];   /**< RX AN 0-3 InPktsUnusedSA Statistic */
++    _Packed struct
++    {
++        volatile uint32_t   rxsacs;     /**< RX Security Association configuration and status */
++        volatile uint32_t   rxsanpn;    /**< RX Security Association nextPN */
++        volatile uint32_t   rxsalpn;    /**< RX Security Association lowestPN */
++        volatile uint32_t   rxsaipos;   /**< RX Security Association InPktsOK Statistic */
++        volatile uint32_t   rxsak[4];   /**< RX Security Association key (128 bit) */
++        volatile uint32_t   rxsah[4];   /**< RX Security Association hash (128 bit) */
++        volatile uint32_t   rxsaipis;   /**< RX Security Association InPktsInvalid Statistic */
++        volatile uint32_t   rxsaipnvs;  /**< RX Security Association InPktsNotValid Statistic */
++        volatile uint8_t    res9[8];    /**< reserved */
++    } _PackedType fmMacsecRxScSa[NUM_OF_SA_PER_RX_SC];
++
++    /* TX configuration, status and statistic */
++    volatile uint32_t   txsci1h;        /**< TX Secure Channel Identifier first half */
++    volatile uint32_t   txsci2h;        /**< TX Secure Channel Identifier second half */
++    volatile uint8_t    res10[8];        /**< reserved */
++    volatile uint32_t   ifoo1hs;        /**< ifOutOctets first half Statistic */
++    volatile uint32_t   ifoo2hs;        /**< ifOutOctets second half Statistic */
++    volatile uint32_t   ifoups;         /**< ifOutUcastPkts Statistic */
++    volatile uint32_t   opus;           /**< OutPktsUntagged Statistic */
++    volatile uint32_t   ifomps;         /**< ifOutMulticastPkts Statistic */
++    volatile uint32_t   ifobps;         /**< ifOutBroadcastPkts Statistic */
++    volatile uint32_t   txsccfg;        /**< TX Secure Channel configuration */
++    volatile uint32_t   optls;          /**< OutPktsTooLong Statistic */
++    volatile uint8_t    res11[16];      /**< reserved */
++    volatile uint32_t   oop1hs;         /**< OutOctetsProtected first half Statistic */
++    volatile uint32_t   oop2hs;         /**< OutOctetsProtected second half Statistic */
++    volatile uint32_t   ooe1hs;         /**< OutOctetsEncrypted first half Statistic */
++    volatile uint32_t   ooe2hs;         /**< OutOctetsEncrypted second half Statistic */
++    volatile uint8_t    res12[48];      /**< reserved */
++    _Packed struct
++    {
++        volatile uint32_t   txsacs;     /**< TX Security Association configuration and status */
++        volatile uint32_t   txsanpn;    /**< TX Security Association nextPN */
++        volatile uint32_t   txsaopps;   /**< TX Security Association OutPktsProtected Statistic */
++        volatile uint32_t   txsaopes;   /**< TX Security Association OutPktsEncrypted Statistic */
++        volatile uint32_t   txsak[4];   /**< TX Security Association key (128 bit) */
++        volatile uint32_t   txsah[4];   /**< TX Security Association hash (128 bit) */
++        volatile uint8_t    res13[16];  /**< reserved */
++    } _PackedType fmMacsecTxScSa[NUM_OF_SA_PER_TX_SC];
++    volatile uint8_t    res14[248];     /**< reserved */
++
++    /* Global configuration and status */
++    volatile uint32_t   ip_rev1;        /**< MACsec IP Block Revision 1 register */
++    volatile uint32_t   ip_rev2;        /**< MACsec IP Block Revision 2 register */
++    volatile uint32_t   evr;            /**< MACsec Event Register */
++    volatile uint32_t   ever;           /**< MACsec Event Enable Register */
++    volatile uint32_t   evfr;           /**< MACsec Event Force Register */
++    volatile uint32_t   err;            /**< MACsec Error Register */
++    volatile uint32_t   erer;           /**< MACsec Error Enable Register */
++    volatile uint32_t   erfr;           /**< MACsec Error Force Register */
++    volatile uint8_t    res15[40];      /**< reserved */
++    volatile uint32_t   meec;           /**< MACsec Memory ECC Error Capture Register */
++    volatile uint32_t   idle;           /**< MACsec Idle status Register */
++    volatile uint8_t    res16[184];     /**< reserved */
++    /* DEBUG */
++    volatile uint32_t   rxec;           /**< MACsec RX error capture Register */
++    volatile uint8_t    res17[28];      /**< reserved */
++    volatile uint32_t   txec;           /**< MACsec TX error capture Register */
++    volatile uint8_t    res18[220];     /**< reserved */
++
++    /* Macsec Rx global statistic */
++    volatile uint32_t   ifiocp1hs;      /**< ifInOctetsCp first half Statistic */
++    volatile uint32_t   ifiocp2hs;      /**< ifInOctetsCp second half Statistic */
++    volatile uint32_t   ifiupcps;       /**< ifInUcastPktsCp Statistic */
++    volatile uint8_t    res19[4];       /**< reserved */
++    volatile uint32_t   ifioup1hs;      /**< ifInOctetsUp first half Statistic */
++    volatile uint32_t   ifioup2hs;      /**< ifInOctetsUp second half Statistic */
++    volatile uint32_t   ifiupups;       /**< ifInUcastPktsUp Statistic */
++    volatile uint8_t    res20[4];       /**< reserved */
++    volatile uint32_t   ifimpcps;       /**< ifInMulticastPktsCp Statistic */
++    volatile uint32_t   ifibpcps;       /**< ifInBroadcastPktsCp Statistic */
++    volatile uint32_t   ifimpups;       /**< ifInMulticastPktsUp Statistic */
++    volatile uint32_t   ifibpups;       /**< ifInBroadcastPktsUp Statistic */
++    volatile uint32_t   ipwts;          /**< InPktsWithoutTag Statistic */
++    volatile uint32_t   ipkays;         /**< InPktsKaY Statistic */
++    volatile uint32_t   ipbts;          /**< InPktsBadTag Statistic */
++    volatile uint32_t   ipsnfs;         /**< InPktsSCINotFound Statistic */
++    volatile uint32_t   ipuecs;         /**< InPktsUnsupportedEC Statistic */
++    volatile uint32_t   ipescbs;        /**< InPktsEponSingleCopyBroadcast Statistic */
++    volatile uint32_t   iptls;          /**< InPktsTooLong Statistic */
++    volatile uint8_t    res21[52];      /**< reserved */
++
++    /* Macsec Tx global statistic */
++    volatile uint32_t   opds;           /**< OutPktsDiscarded Statistic */
++#if (DPAA_VERSION >= 11)
++    volatile uint8_t    res22[124];     /**< reserved */
++    _Packed struct
++    {
++        volatile uint32_t   rxsak[8];   /**< RX Security Association key (128/256 bit) */
++        volatile uint8_t    res23[32];  /**< reserved */
++    } _PackedType rxScSaKey[NUM_OF_SA_PER_RX_SC];
++    _Packed struct
++    {
++        volatile uint32_t   txsak[8];   /**< TX Security Association key (128/256 bit) */
++        volatile uint8_t    res24[32];  /**< reserved */
++    } _PackedType txScSaKey[NUM_OF_SA_PER_TX_SC];
++#endif /* (DPAA_VERSION >= 11) */
++} _PackedType t_FmMacsecRegs;
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(pop)
++#endif /* defined(__MWERKS__) && ... */
++
++
++/**************************************************************************//**
++ @Description       General defines
++*//***************************************************************************/
++
++#define SCI_HIGH_MASK   0xffffffff00000000LL
++#define SCI_LOW_MASK    0x00000000ffffffffLL
++
++#define LONG_SHIFT      32
++
++#define GET_SCI_FIRST_HALF(sci)     (uint32_t)((macsecSCI_t)((macsecSCI_t)(sci) & SCI_HIGH_MASK) >> LONG_SHIFT)
++#define GET_SCI_SECOND_HALF(sci)    (uint32_t)((macsecSCI_t)(sci) & SCI_LOW_MASK)
++
++/**************************************************************************//**
++ @Description       Configuration defines
++*//***************************************************************************/
++
++/* masks */
++#define CFG_UECT                        0x00000800
++#define CFG_ESCBT                       0x00000400
++#define CFG_USFT                        0x00000300
++#define CFG_ITT                         0x00000080
++#define CFG_KFT                         0x00000040
++#define CFG_UFT                         0x00000030
++#define CFG_KSS                         0x00000004
++#define CFG_BYPN                        0x00000002
++#define CFG_S0I                         0x00000001
++
++#define ET_TYPE                         0x0000ffff
++
++#define MFL_MAX_LEN                     0x0000ffff
++
++#define RXSCA_SC_SEL                    0x0000000f
++
++#define TXSCA_SC_SEL                    0x0000000f
++
++#define IP_REV_1_IP_ID                  0xffff0000
++#define IP_REV_1_IP_MJ                  0x0000ff00
++#define IP_REV_1_IP_MM                  0x000000ff
++
++#define IP_REV_2_IP_INT                 0x00ff0000
++#define IP_REV_2_IP_ERR                 0x0000ff00
++#define IP_REV_2_IP_CFG                 0x000000ff
++
++#define MECC_CAP                        0x80000000
++#define MECC_CET                        0x40000000
++#define MECC_SERCNT                     0x00ff0000
++#define MECC_MEMADDR                    0x000001ff
++
++/* shifts */
++#define CFG_UECT_SHIFT                  (31-20)
++#define CFG_ESCBT_SHIFT                 (31-21)
++#define CFG_USFT_SHIFT                  (31-23)
++#define CFG_ITT_SHIFT                   (31-24)
++#define CFG_KFT_SHIFT                   (31-25)
++#define CFG_UFT_SHIFT                   (31-27)
++#define CFG_KSS_SHIFT                   (31-29)
++#define CFG_BYPN_SHIFT                  (31-30)
++#define CFG_S0I_SHIFT                   (31-31)
++
++#define IP_REV_1_IP_ID_SHIFT            (31-15)
++#define IP_REV_1_IP_MJ_SHIFT            (31-23)
++#define IP_REV_1_IP_MM_SHIFT            (31-31)
++
++#define IP_REV_2_IP_INT_SHIFT           (31-15)
++#define IP_REV_2_IP_ERR_SHIFT           (31-23)
++#define IP_REV_2_IP_CFG_SHIFT           (31-31)
++
++#define MECC_CAP_SHIFT                  (31-0)
++#define MECC_CET_SHIFT                  (31-1)
++#define MECC_SERCNT_SHIFT               (31-15)
++#define MECC_MEMADDR_SHIFT              (31-31)
++
++/**************************************************************************//**
++ @Description       RX SC defines
++*//***************************************************************************/
++
++/* masks */
++#define RX_SCCFG_SCI_EN_MASK            0x00000800
++#define RX_SCCFG_RP_MASK                0x00000400
++#define RX_SCCFG_VF_MASK                0x00000300
++#define RX_SCCFG_CO_MASK                0x0000003f
++
++/* shifts */
++#define RX_SCCFG_SCI_EN_SHIFT           (31-20)
++#define RX_SCCFG_RP_SHIFT               (31-21)
++#define RX_SCCFG_VF_SHIFT               (31-23)
++#define RX_SCCFG_CO_SHIFT               (31-31)
++#define RX_SCCFG_CS_SHIFT               (31-7)
++
++/**************************************************************************//**
++ @Description       RX SA defines
++*//***************************************************************************/
++
++/* masks */
++#define RX_SACFG_ACTIVE                 0x80000000
++#define RX_SACFG_AN_MASK                0x00000006
++#define RX_SACFG_EN_MASK                0x00000001
++
++/* shifts */
++#define RX_SACFG_AN_SHIFT               (31-30)
++#define RX_SACFG_EN_SHIFT               (31-31)
++
++/**************************************************************************//**
++ @Description       TX SC defines
++*//***************************************************************************/
++
++/* masks */
++#define TX_SCCFG_AN_MASK                0x000c0000
++#define TX_SCCFG_ASA_MASK               0x00020000
++#define TX_SCCFG_SCE_MASK               0x00010000
++#define TX_SCCFG_CO_MASK                0x00003f00
++#define TX_SCCFG_CE_MASK                0x00000010
++#define TX_SCCFG_PF_MASK                0x00000008
++#define TX_SCCFG_AIS_MASK               0x00000004
++#define TX_SCCFG_UES_MASK               0x00000002
++#define TX_SCCFG_USCB_MASK              0x00000001
++
++/* shifts */
++#define TX_SCCFG_AN_SHIFT               (31-13)
++#define TX_SCCFG_ASA_SHIFT              (31-14)
++#define TX_SCCFG_SCE_SHIFT              (31-15)
++#define TX_SCCFG_CO_SHIFT               (31-23)
++#define TX_SCCFG_CE_SHIFT               (31-27)
++#define TX_SCCFG_PF_SHIFT               (31-28)
++#define TX_SCCFG_AIS_SHIFT              (31-29)
++#define TX_SCCFG_UES_SHIFT              (31-30)
++#define TX_SCCFG_USCB_SHIFT             (31-31)
++#define TX_SCCFG_CS_SHIFT               (31-7)
++
++/**************************************************************************//**
++ @Description       TX SA defines
++*//***************************************************************************/
++
++/* masks */
++#define TX_SACFG_ACTIVE                 0x80000000
++
++
++typedef struct
++{
++    void        (*f_Isr) (t_Handle h_Arg, uint32_t id);
++    t_Handle    h_SrcHandle;
++} t_FmMacsecIntrSrc;
++
++typedef struct
++{
++    e_FmMacsecUnknownSciFrameTreatment  unknownSciTreatMode;
++    bool                                invalidTagsDeliverUncontrolled;
++    bool                                changedTextWithNoEncryptDeliverUncontrolled;
++    bool                                onlyScbIsSetDeliverUncontrolled;
++    bool                                encryptWithNoChangedTextDiscardUncontrolled;
++    e_FmMacsecUntagFrameTreatment       untagTreatMode;
++    uint32_t                            pnExhThr;
++    bool                                keysUnreadable;
++    bool                                byPassMode;
++    bool                                reservedSc0;
++    uint32_t                            sectagOverhead;
++    uint32_t                            mflSubtract;
++} t_FmMacsecDriverParam;
++
++typedef struct
++{
++    t_FmMacsecControllerDriver      fmMacsecControllerDriver;
++    t_Handle                        h_Fm;
++    t_FmMacsecRegs                  *p_FmMacsecRegs;
++    t_Handle                        h_FmMac;            /**< A handle to the FM MAC object  related to */
++    char                            fmMacsecModuleName[MODULE_NAME_SIZE];
++    t_FmMacsecIntrSrc               intrMng[NUM_OF_INTER_MODULE_EVENTS];
++    uint32_t                        events;
++    uint32_t                        exceptions;
++    uint32_t                        userExceptions;
++    t_FmMacsecExceptionsCallback    *f_Exception;       /**< Exception Callback Routine         */
++    t_Handle                        h_App;              /**< A handle to an application layer object; This handle will
++                                                             be passed by the driver upon calling the above callbacks */
++    bool                            rxScTable[NUM_OF_RX_SC];
++    uint32_t                        numRxScAvailable;
++    bool                            txScTable[NUM_OF_TX_SC];
++    uint32_t                        numTxScAvailable;
++    t_Handle                        rxScSpinLock;
++    t_Handle                        txScSpinLock;
++    t_FmMacsecDriverParam           *p_FmMacsecDriverParam;
++} t_FmMacsec;
++
++
++#endif /* __FM_MACSEC_MASTER_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.c
+@@ -0,0 +1,883 @@
++/*
++ * Copyright 2008-2015 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/******************************************************************************
++ @File          fm_macsec_secy.c
++
++ @Description   FM MACSEC SECY driver routines implementation.
++*//***************************************************************************/
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "xx_ext.h"
++#include "string_ext.h"
++#include "sprint_ext.h"
++
++#include "fm_macsec_secy.h"
++
++
++/****************************************/
++/*       static functions               */
++/****************************************/
++static void FmMacsecSecYExceptionsIsr(t_Handle h_FmMacsecSecY, uint32_t id)
++{
++    t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++
++    UNUSED(id);
++    SANITY_CHECK_RETURN(p_FmMacsecSecY, E_INVALID_HANDLE);
++
++    if (p_FmMacsecSecY->exceptions & FM_MACSEC_SECY_EX_FRAME_DISCARDED)
++        p_FmMacsecSecY->f_Exception(p_FmMacsecSecY->h_App, e_FM_MACSEC_SECY_EX_FRAME_DISCARDED);
++}
++
++static void FmMacsecSecYEventsIsr(t_Handle h_FmMacsecSecY, uint32_t id)
++{
++    t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++
++    UNUSED(id);
++    SANITY_CHECK_RETURN(p_FmMacsecSecY, E_INVALID_HANDLE);
++
++    if (p_FmMacsecSecY->events & FM_MACSEC_SECY_EV_NEXT_PN)
++        p_FmMacsecSecY->f_Event(p_FmMacsecSecY->h_App, e_FM_MACSEC_SECY_EV_NEXT_PN);
++}
++
++static t_Error CheckFmMacsecSecYParameters(t_FmMacsecSecY *p_FmMacsecSecY)
++{
++    if (!p_FmMacsecSecY->f_Exception)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided"));
++
++    if (!p_FmMacsecSecY->f_Event)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Events callback not provided"));
++
++    if (!p_FmMacsecSecY->numOfRxSc)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Num of Rx Scs must be greater than '0'"));
++
++
++    return E_OK;
++}
++
++static t_Handle FmMacsecSecYCreateSc(t_FmMacsecSecY             *p_FmMacsecSecY,
++                                     macsecSCI_t                sci,
++                                     e_FmMacsecSecYCipherSuite  cipherSuite,
++                                     e_ScType                   type)
++{
++    t_SecYSc        *p_ScTable;
++    void            *p_Params;
++    uint32_t        numOfSc,i;
++    t_Error         err = E_OK;
++    t_RxScParams    rxScParams;
++    t_TxScParams    txScParams;
++
++    ASSERT_COND(p_FmMacsecSecY);
++    ASSERT_COND(p_FmMacsecSecY->h_FmMacsec);
++
++    if (type == e_SC_RX)
++    {
++        memset(&rxScParams, 0, sizeof(rxScParams));
++        i                                   = (NUM_OF_RX_SC - 1);
++        p_ScTable                           = p_FmMacsecSecY->p_RxSc;
++        numOfSc                             = p_FmMacsecSecY->numOfRxSc;
++        rxScParams.confidentialityOffset    = p_FmMacsecSecY->confidentialityOffset;
++        rxScParams.replayProtect            = p_FmMacsecSecY->replayProtect;
++        rxScParams.replayWindow             = p_FmMacsecSecY->replayWindow;
++        rxScParams.validateFrames           = p_FmMacsecSecY->validateFrames;
++        rxScParams.cipherSuite              = cipherSuite;
++        p_Params = &rxScParams;
++    }
++    else
++    {
++        memset(&txScParams, 0, sizeof(txScParams));
++        i                                   = (NUM_OF_TX_SC - 1);
++        p_ScTable                           = p_FmMacsecSecY->p_TxSc;
++        numOfSc                             = p_FmMacsecSecY->numOfTxSc;
++        txScParams.sciInsertionMode         = p_FmMacsecSecY->sciInsertionMode;
++        txScParams.protectFrames            = p_FmMacsecSecY->protectFrames;
++        txScParams.confidentialityEnable    = p_FmMacsecSecY->confidentialityEnable;
++        txScParams.confidentialityOffset    = p_FmMacsecSecY->confidentialityOffset;
++        txScParams.cipherSuite              = cipherSuite;
++        p_Params = &txScParams;
++    }
++
++    for (i=0;i<numOfSc;i++)
++        if (!p_ScTable[i].inUse)
++            break;
++    if (i == numOfSc)
++    {
++        REPORT_ERROR(MAJOR, E_FULL, ("FM MACSEC SECY SC"));
++        return NULL;
++    }
++
++    if (type == e_SC_RX)
++    {
++        ((t_RxScParams *)p_Params)->scId = p_ScTable[i].scId;
++        ((t_RxScParams *)p_Params)->sci  = sci;
++        if ((err = FmMacsecCreateRxSc(p_FmMacsecSecY->h_FmMacsec, (t_RxScParams *)p_Params)) != E_OK)
++        {
++            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY RX SC"));
++            return NULL;
++        }
++    }
++    else
++    {
++        ((t_TxScParams *)p_Params)->scId = p_ScTable[i].scId;
++        ((t_TxScParams *)p_Params)->sci  = sci;
++        if ((err = FmMacsecCreateTxSc(p_FmMacsecSecY->h_FmMacsec, (t_TxScParams *)p_Params)) != E_OK)
++        {
++            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY TX SC"));
++            return NULL;
++        }
++    }
++
++    p_ScTable[i].inUse = TRUE;
++    return &p_ScTable[i];
++}
++
++static t_Error FmMacsecSecYDeleteSc(t_FmMacsecSecY *p_FmMacsecSecY, t_SecYSc *p_FmSecYSc, e_ScType type)
++{
++    t_Error         err = E_OK;
++
++    ASSERT_COND(p_FmMacsecSecY);
++    ASSERT_COND(p_FmMacsecSecY->h_FmMacsec);
++    ASSERT_COND(p_FmSecYSc);
++
++    if (type == e_SC_RX)
++    {
++        if ((err = FmMacsecDeleteRxSc(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++    else
++        if ((err = FmMacsecDeleteTxSc(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++
++    p_FmSecYSc->inUse = FALSE;
++
++    return err;
++}
++
++/****************************************/
++/*       API Init unit functions        */
++/****************************************/
++t_Handle FM_MACSEC_SECY_Config(t_FmMacsecSecYParams *p_FmMacsecSecYParam)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY;
++
++    /* Allocate FM MACSEC structure */
++    p_FmMacsecSecY = (t_FmMacsecSecY *) XX_Malloc(sizeof(t_FmMacsecSecY));
++    if (!p_FmMacsecSecY)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY driver structure"));
++        return NULL;
++    }
++    memset(p_FmMacsecSecY, 0, sizeof(t_FmMacsecSecY));
++
++    /* Allocate the FM MACSEC driver's parameters structure */
++    p_FmMacsecSecY->p_FmMacsecSecYDriverParam = (t_FmMacsecSecYDriverParam *)XX_Malloc(sizeof(t_FmMacsecSecYDriverParam));
++    if (!p_FmMacsecSecY->p_FmMacsecSecYDriverParam)
++    {
++        XX_Free(p_FmMacsecSecY);
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY driver parameters"));
++        return NULL;
++    }
++    memset(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, 0, sizeof(t_FmMacsecSecYDriverParam));
++
++    /* Initialize FM MACSEC SECY parameters which will be kept by the driver */
++    p_FmMacsecSecY->h_FmMacsec              = p_FmMacsecSecYParam->h_FmMacsec;
++    p_FmMacsecSecY->f_Event                 = p_FmMacsecSecYParam->f_Event;
++    p_FmMacsecSecY->f_Exception             = p_FmMacsecSecYParam->f_Exception;
++    p_FmMacsecSecY->h_App                   = p_FmMacsecSecYParam->h_App;
++    p_FmMacsecSecY->confidentialityEnable   = DEFAULT_confidentialityEnable;
++    p_FmMacsecSecY->confidentialityOffset   = DEFAULT_confidentialityOffset;
++    p_FmMacsecSecY->validateFrames          = DEFAULT_validateFrames;
++    p_FmMacsecSecY->replayProtect           = DEFAULT_replayEnable;
++    p_FmMacsecSecY->replayWindow            = DEFAULT_replayWindow;
++    p_FmMacsecSecY->protectFrames           = DEFAULT_protectFrames;
++    p_FmMacsecSecY->sciInsertionMode        = DEFAULT_sciInsertionMode;
++    p_FmMacsecSecY->isPointToPoint          = DEFAULT_ptp;
++    p_FmMacsecSecY->numOfRxSc               = p_FmMacsecSecYParam->numReceiveChannels;
++    p_FmMacsecSecY->numOfTxSc               = DEFAULT_numOfTxSc;
++    p_FmMacsecSecY->exceptions              = DEFAULT_exceptions;
++    p_FmMacsecSecY->events                  = DEFAULT_events;
++
++    memcpy(&p_FmMacsecSecY->p_FmMacsecSecYDriverParam->txScParams,
++           &p_FmMacsecSecYParam->txScParams,
++           sizeof(t_FmMacsecSecYSCParams));
++    return p_FmMacsecSecY;
++}
++
++t_Error FM_MACSEC_SECY_Init(t_Handle h_FmMacsecSecY)
++{
++    t_FmMacsecSecY              *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_FmMacsecSecYDriverParam   *p_FmMacsecSecYDriverParam = NULL;
++    uint32_t                    rxScIds[NUM_OF_RX_SC], txScIds[NUM_OF_TX_SC], i, j;
++    t_Error                     err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_HANDLE);
++
++    CHECK_INIT_PARAMETERS(p_FmMacsecSecY, CheckFmMacsecSecYParameters);
++
++    p_FmMacsecSecYDriverParam = p_FmMacsecSecY->p_FmMacsecSecYDriverParam;
++
++    if ((p_FmMacsecSecY->isPointToPoint) &&
++        ((err = FmMacsecSetPTP(p_FmMacsecSecY->h_FmMacsec, TRUE)) != E_OK))
++        RETURN_ERROR(MAJOR, err, ("Can't set Poin-to-Point"));
++
++    /* Rx Sc Allocation */
++    p_FmMacsecSecY->p_RxSc = (t_SecYSc *)XX_Malloc(sizeof(t_SecYSc) * p_FmMacsecSecY->numOfRxSc);
++    if (!p_FmMacsecSecY->p_RxSc)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY RX SC"));
++    memset(p_FmMacsecSecY->p_RxSc, 0, sizeof(t_SecYSc) * p_FmMacsecSecY->numOfRxSc);
++    if ((err = FmMacsecAllocScs(p_FmMacsecSecY->h_FmMacsec, e_SC_RX, p_FmMacsecSecY->isPointToPoint, p_FmMacsecSecY->numOfRxSc, rxScIds)) != E_OK)
++    {
++        if (p_FmMacsecSecY->p_TxSc)
++            XX_Free(p_FmMacsecSecY->p_TxSc);
++        if (p_FmMacsecSecY->p_RxSc)
++            XX_Free(p_FmMacsecSecY->p_RxSc);
++        return ERROR_CODE(err);
++    }
++    for (i=0; i<p_FmMacsecSecY->numOfRxSc; i++)
++    {
++        p_FmMacsecSecY->p_RxSc[i].scId  = rxScIds[i];
++        p_FmMacsecSecY->p_RxSc[i].type  = e_SC_RX;
++        for (j=0; j<MAX_NUM_OF_SA_PER_SC;j++)
++            p_FmMacsecSecY->p_RxSc[i].sa[j].saId = (e_ScSaId)SECY_AN_FREE_VALUE;
++    }
++
++    /* Tx Sc Allocation */
++    p_FmMacsecSecY->p_TxSc = (t_SecYSc *)XX_Malloc(sizeof(t_SecYSc) * p_FmMacsecSecY->numOfTxSc);
++    if (!p_FmMacsecSecY->p_TxSc)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY TX SC"));
++    memset(p_FmMacsecSecY->p_TxSc, 0, sizeof(t_SecYSc) * p_FmMacsecSecY->numOfTxSc);
++
++    if ((err = FmMacsecAllocScs(p_FmMacsecSecY->h_FmMacsec, e_SC_TX, p_FmMacsecSecY->isPointToPoint, p_FmMacsecSecY->numOfTxSc, txScIds)) != E_OK)
++    {
++        if (p_FmMacsecSecY->p_TxSc)
++            XX_Free(p_FmMacsecSecY->p_TxSc);
++        if (p_FmMacsecSecY->p_RxSc)
++            XX_Free(p_FmMacsecSecY->p_RxSc);
++        return ERROR_CODE(err);
++    }
++    for (i=0; i<p_FmMacsecSecY->numOfTxSc; i++)
++    {
++        p_FmMacsecSecY->p_TxSc[i].scId  = txScIds[i];
++        p_FmMacsecSecY->p_TxSc[i].type  = e_SC_TX;
++        for (j=0; j<MAX_NUM_OF_SA_PER_SC;j++)
++            p_FmMacsecSecY->p_TxSc[i].sa[j].saId = (e_ScSaId)SECY_AN_FREE_VALUE;
++        FmMacsecRegisterIntr(p_FmMacsecSecY->h_FmMacsec,
++                             e_FM_MACSEC_MOD_SC_TX,
++                             (uint8_t)txScIds[i],
++                             e_FM_INTR_TYPE_ERR,
++                             FmMacsecSecYExceptionsIsr,
++                             p_FmMacsecSecY);
++        FmMacsecRegisterIntr(p_FmMacsecSecY->h_FmMacsec,
++                             e_FM_MACSEC_MOD_SC_TX,
++                             (uint8_t)txScIds[i],
++                             e_FM_INTR_TYPE_NORMAL,
++                             FmMacsecSecYEventsIsr,
++                             p_FmMacsecSecY);
++
++        if (p_FmMacsecSecY->exceptions & FM_MACSEC_SECY_EX_FRAME_DISCARDED)
++            FmMacsecSetException(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EX_TX_SC, txScIds[i], TRUE);
++        if (p_FmMacsecSecY->events & FM_MACSEC_SECY_EV_NEXT_PN)
++            FmMacsecSetEvent(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EV_TX_SC_NEXT_PN, txScIds[i], TRUE);
++    }
++
++    FmMacsecSecYCreateSc(p_FmMacsecSecY,
++                         p_FmMacsecSecYDriverParam->txScParams.sci,
++                         p_FmMacsecSecYDriverParam->txScParams.cipherSuite,
++                         e_SC_TX);
++    XX_Free(p_FmMacsecSecYDriverParam);
++    p_FmMacsecSecY->p_FmMacsecSecYDriverParam = NULL;
++
++    return E_OK;
++}
++
++t_Error FM_MACSEC_SECY_Free(t_Handle h_FmMacsecSecY)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_Error         err             = E_OK;
++    uint32_t        rxScIds[NUM_OF_RX_SC], txScIds[NUM_OF_TX_SC], i;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++
++    if (p_FmMacsecSecY->isPointToPoint)
++        FmMacsecSetPTP(p_FmMacsecSecY->h_FmMacsec, FALSE);
++    if (p_FmMacsecSecY->p_RxSc)
++    {
++        for (i=0; i<p_FmMacsecSecY->numOfRxSc; i++)
++            rxScIds[i] = p_FmMacsecSecY->p_RxSc[i].scId;
++        if ((err = FmMacsecFreeScs(p_FmMacsecSecY->h_FmMacsec, e_SC_RX, p_FmMacsecSecY->numOfRxSc, rxScIds)) != E_OK)
++            return ERROR_CODE(err);
++        XX_Free(p_FmMacsecSecY->p_RxSc);
++    }
++    if (p_FmMacsecSecY->p_TxSc)
++    {
++       FmMacsecSecYDeleteSc(p_FmMacsecSecY, &p_FmMacsecSecY->p_TxSc[0], e_SC_TX);
++
++       for (i=0; i<p_FmMacsecSecY->numOfTxSc; i++) {
++             txScIds[i] = p_FmMacsecSecY->p_TxSc[i].scId;
++            FmMacsecUnregisterIntr(p_FmMacsecSecY->h_FmMacsec,
++                                 e_FM_MACSEC_MOD_SC_TX,
++                                 (uint8_t)txScIds[i],
++                                 e_FM_INTR_TYPE_ERR);
++            FmMacsecUnregisterIntr(p_FmMacsecSecY->h_FmMacsec,
++                                 e_FM_MACSEC_MOD_SC_TX,
++                                 (uint8_t)txScIds[i],
++                                 e_FM_INTR_TYPE_NORMAL);
++
++            if (p_FmMacsecSecY->exceptions & FM_MACSEC_SECY_EX_FRAME_DISCARDED)
++                FmMacsecSetException(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EX_TX_SC, txScIds[i], FALSE);
++            if (p_FmMacsecSecY->events & FM_MACSEC_SECY_EV_NEXT_PN)
++                FmMacsecSetEvent(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EV_TX_SC_NEXT_PN, txScIds[i], FALSE);
++       }
++
++        if ((err = FmMacsecFreeScs(p_FmMacsecSecY->h_FmMacsec, e_SC_TX, p_FmMacsecSecY->numOfTxSc, txScIds)) != E_OK)
++            return ERROR_CODE(err);
++        XX_Free(p_FmMacsecSecY->p_TxSc);
++    }
++
++    XX_Free(p_FmMacsecSecY);
++
++    return err;
++}
++
++t_Error FM_MACSEC_SECY_ConfigSciInsertionMode(t_Handle h_FmMacsecSecY, e_FmMacsecSciInsertionMode sciInsertionMode)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++
++    p_FmMacsecSecY->sciInsertionMode = sciInsertionMode;
++
++    return E_OK;
++}
++
++t_Error FM_MACSEC_SECY_ConfigProtectFrames(t_Handle h_FmMacsecSecY, bool protectFrames)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++
++    p_FmMacsecSecY->protectFrames = protectFrames;
++
++    return E_OK;
++}
++
++t_Error FM_MACSEC_SECY_ConfigReplayWindow(t_Handle h_FmMacsecSecY, bool replayProtect, uint32_t replayWindow)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++
++    p_FmMacsecSecY->replayProtect   = replayProtect;
++    p_FmMacsecSecY->replayWindow    = replayWindow;
++
++    return E_OK;
++}
++
++t_Error FM_MACSEC_SECY_ConfigValidationMode(t_Handle h_FmMacsecSecY, e_FmMacsecValidFrameBehavior validateFrames)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++
++    p_FmMacsecSecY->validateFrames = validateFrames;
++
++    return E_OK;
++}
++
++t_Error FM_MACSEC_SECY_ConfigConfidentiality(t_Handle h_FmMacsecSecY, bool confidentialityEnable, uint16_t confidentialityOffset)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++
++    p_FmMacsecSecY->confidentialityEnable = confidentialityEnable;
++    p_FmMacsecSecY->confidentialityOffset = confidentialityOffset;
++
++    return E_OK;
++}
++
++t_Error FM_MACSEC_SECY_ConfigPointToPoint(t_Handle h_FmMacsecSecY)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++
++    p_FmMacsecSecY->numOfRxSc = 1;
++    p_FmMacsecSecY->isPointToPoint = TRUE;
++    p_FmMacsecSecY->sciInsertionMode = e_FM_MACSEC_SCI_INSERTION_MODE_IMPLICT_PTP;
++
++    return E_OK;
++}
++
++t_Error FM_MACSEC_SECY_ConfigException(t_Handle h_FmMacsecSecY, e_FmMacsecSecYExceptions exception, bool enable)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    uint32_t        bitMask         = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++
++    GET_EXCEPTION_FLAG(bitMask, exception);
++    if (bitMask)
++    {
++        if (enable)
++            p_FmMacsecSecY->exceptions |= bitMask;
++        else
++            p_FmMacsecSecY->exceptions &= ~bitMask;
++    }
++    else
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
++
++    return E_OK;
++}
++
++t_Error FM_MACSEC_SECY_ConfigEvent(t_Handle h_FmMacsecSecY, e_FmMacsecSecYEvents event, bool enable)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    uint32_t        bitMask         = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++
++    GET_EVENT_FLAG(bitMask, event);
++    if (bitMask)
++    {
++        if (enable)
++            p_FmMacsecSecY->events |= bitMask;
++        else
++            p_FmMacsecSecY->events &= ~bitMask;
++    }
++    else
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined event"));
++
++    return E_OK;
++}
++
++t_Handle FM_MACSEC_SECY_CreateRxSc(t_Handle h_FmMacsecSecY, t_FmMacsecSecYSCParams *p_ScParams)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmMacsecSecY, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(p_ScParams, E_NULL_POINTER, NULL);
++    SANITY_CHECK_RETURN_VALUE(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE, NULL);
++
++    return FmMacsecSecYCreateSc(p_FmMacsecSecY, p_ScParams->sci, p_ScParams->cipherSuite, e_SC_RX);
++}
++
++t_Error FM_MACSEC_SECY_DeleteRxSc(t_Handle h_FmMacsecSecY, t_Handle h_Sc)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_SecYSc        *p_FmSecYSc     = (t_SecYSc *)h_Sc;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
++
++    return FmMacsecSecYDeleteSc(p_FmMacsecSecY, p_FmSecYSc, e_SC_RX);
++}
++
++t_Error FM_MACSEC_SECY_CreateRxSa(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t lowestPn, macsecSAKey_t key)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_SecYSc        *p_FmSecYSc     = (t_SecYSc *)h_Sc;
++    t_Error         err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
++
++    if (p_FmSecYSc->sa[an].saId != SECY_AN_FREE_VALUE)
++        RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is already assigned",an));
++
++    if ((err = FmMacsecCreateRxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, (e_ScSaId)p_FmSecYSc->numOfSa, an, lowestPn, key)) != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    p_FmSecYSc->sa[an].saId = (e_ScSaId)p_FmSecYSc->numOfSa++;
++    return err;
++}
++
++t_Error FM_MACSEC_SECY_DeleteRxSa(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_SecYSc        *p_FmSecYSc     = (t_SecYSc *)h_Sc;
++    t_Error         err             = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
++
++    if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
++        RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is already deleted",an));
++
++    if ((err = FmMacsecDeleteRxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId)) != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    p_FmSecYSc->numOfSa--;
++    p_FmSecYSc->sa[an].saId = (e_ScSaId)SECY_AN_FREE_VALUE;
++    /* TODO - check if statistics need to be read*/
++    return err;
++}
++
++t_Error FM_MACSEC_SECY_RxSaEnableReceive(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_SecYSc        *p_FmSecYSc     = (t_SecYSc *)h_Sc;
++    t_Error         err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
++
++    if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
++        RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an));
++
++    if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, TRUE)) != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    p_FmSecYSc->sa[an].active = TRUE;
++    return err;
++}
++
++t_Error FM_MACSEC_SECY_RxSaDisableReceive(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_SecYSc        *p_FmSecYSc     = (t_SecYSc *)h_Sc;
++    t_Error         err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
++
++    if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
++        RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an));
++
++    if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, FALSE)) != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    p_FmSecYSc->sa[an].active = FALSE;
++    return err;
++}
++
++t_Error FM_MACSEC_SECY_RxSaUpdateNextPn(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t updtNextPN)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_SecYSc        *p_FmSecYSc     = (t_SecYSc *)h_Sc;
++    t_Error         err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
++
++    if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
++        RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an));
++
++    if ((err = FmMacsecRxSaUpdateNextPn(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, updtNextPN)) != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    return err;
++}
++
++t_Error FM_MACSEC_SECY_RxSaUpdateLowestPn(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t updtLowestPN)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_SecYSc        *p_FmSecYSc     = (t_SecYSc *)h_Sc;
++    t_Error         err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
++
++    if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
++        RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an));
++
++    if ((err = FmMacsecRxSaUpdateLowestPn(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, updtLowestPN)) != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    return err;
++}
++
++t_Error FM_MACSEC_SECY_RxSaModifyKey(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, macsecSAKey_t key)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_SecYSc        *p_FmSecYSc     = (t_SecYSc *)h_Sc;
++    t_Error         err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
++
++    if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
++        RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an));
++
++    if (p_FmSecYSc->sa[an].active)
++        if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, FALSE)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++
++    /* TODO - statistics should be read */
++
++    if ((err = FmMacsecCreateRxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, an, 1, key)) != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    if (p_FmSecYSc->sa[an].active)
++        if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, TRUE)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++    return err;
++}
++
++
++t_Error FM_MACSEC_SECY_CreateTxSa(t_Handle h_FmMacsecSecY, macsecAN_t an, macsecSAKey_t key)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_SecYSc        *p_FmSecYSc;
++    t_Error         err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++    p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0];
++    SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
++
++    if (p_FmSecYSc->sa[an].saId != SECY_AN_FREE_VALUE)
++        RETURN_ERROR(MINOR, err, ("An %d is already assigned",an));
++
++    if ((err = FmMacsecCreateTxSa(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, (e_ScSaId)p_FmSecYSc->numOfSa, key)) != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    p_FmSecYSc->sa[an].saId = (e_ScSaId)p_FmSecYSc->numOfSa++;
++    return err;
++}
++
++t_Error FM_MACSEC_SECY_DeleteTxSa(t_Handle h_FmMacsecSecY, macsecAN_t an)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_SecYSc        *p_FmSecYSc;
++    t_Error         err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++    p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0];
++    SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
++
++    if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
++        RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is already deleted",an));
++
++    if ((err = FmMacsecDeleteTxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId)) != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    p_FmSecYSc->numOfSa--;
++    p_FmSecYSc->sa[an].saId = (e_ScSaId)SECY_AN_FREE_VALUE;
++    /* TODO - check if statistics need to be read*/
++    return err;
++}
++
++t_Error FM_MACSEC_SECY_TxSaModifyKey(t_Handle h_FmMacsecSecY, macsecAN_t nextActiveAn, macsecSAKey_t key)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_SecYSc        *p_FmSecYSc;
++    macsecAN_t      currentAn;
++    t_Error         err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++    p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0];
++    SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(nextActiveAn < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
++
++    if ((err = FmMacsecTxSaGetActive(p_FmMacsecSecY->h_FmMacsec,
++                                     p_FmSecYSc->scId,
++                                     &currentAn)) != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    if ((err = FmMacsecTxSaSetActive(p_FmMacsecSecY->h_FmMacsec,
++                                     p_FmSecYSc->scId,
++                                     p_FmSecYSc->sa[nextActiveAn].saId,
++                                     nextActiveAn)) != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    /* TODO - statistics should be read */
++
++    if ((err = FmMacsecCreateTxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[currentAn].saId, key)) != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    return err;
++}
++
++t_Error FM_MACSEC_SECY_TxSaSetActive(t_Handle h_FmMacsecSecY, macsecAN_t an)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_SecYSc        *p_FmSecYSc;
++    t_Error         err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++    p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0];
++    SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
++
++    if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
++        RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an));
++
++    if ((err = FmMacsecTxSaSetActive(p_FmMacsecSecY->h_FmMacsec,
++                                     p_FmSecYSc->scId,
++                                     p_FmSecYSc->sa[an].saId,
++                                     an)) != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    return err;
++}
++
++t_Error FM_MACSEC_SECY_TxSaGetActive(t_Handle h_FmMacsecSecY, macsecAN_t *p_An)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_SecYSc        *p_FmSecYSc;
++    t_Error         err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++    p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0];
++    SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_An, E_INVALID_HANDLE);
++
++    if ((err = FmMacsecTxSaGetActive(p_FmMacsecSecY->h_FmMacsec,
++                                     p_FmSecYSc->scId,
++                                     p_An)) != E_OK)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    return err;
++}
++
++t_Error FM_MACSEC_SECY_GetRxScPhysId(t_Handle h_FmMacsecSecY, t_Handle h_Sc, uint32_t *p_ScPhysId)
++{
++    t_SecYSc        *p_FmSecYSc = (t_SecYSc *)h_Sc;
++    t_Error         err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(((t_FmMacsecSecY *)h_FmMacsecSecY)->h_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!((t_FmMacsecSecY *)h_FmMacsecSecY)->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
++#ifdef DISABLE_SANITY_CHECKS
++    UNUSED(h_FmMacsecSecY);
++#endif /* DISABLE_SANITY_CHECKS */
++
++    *p_ScPhysId = p_FmSecYSc->scId;
++    return err;
++}
++
++t_Error FM_MACSEC_SECY_GetTxScPhysId(t_Handle h_FmMacsecSecY, uint32_t *p_ScPhysId)
++{
++    t_FmMacsecSecY  *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
++    t_SecYSc        *p_FmSecYSc;
++    t_Error         err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
++    p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0];
++    SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
++
++    *p_ScPhysId = p_FmSecYSc->scId;
++    return err;
++}
++
++t_Error FM_MACSEC_SECY_SetException(t_Handle h_FmMacsecSecY, e_FmMacsecExceptions exception, bool enable)
++{
++   UNUSED(h_FmMacsecSecY);UNUSED(exception);UNUSED(enable);
++   RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_SECY_SetEvent(t_Handle h_FmMacsecSecY, e_FmMacsecSecYEvents event, bool enable)
++{
++    UNUSED(h_FmMacsecSecY);UNUSED(event);UNUSED(enable);
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_SECY_GetStatistics(t_Handle h_FmMacsecSecY, t_FmMacsecSecYStatistics *p_Statistics)
++{
++    UNUSED(h_FmMacsecSecY);UNUSED(p_Statistics);
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_SECY_RxScGetStatistics(t_Handle h_FmMacsecSecY, t_Handle h_Sc, t_FmMacsecSecYRxScStatistics *p_Statistics)
++{
++    UNUSED(h_FmMacsecSecY);UNUSED(h_Sc);UNUSED(p_Statistics);
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_SECY_RxSaGetStatistics(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, t_FmMacsecSecYRxSaStatistics *p_Statistics)
++{
++    UNUSED(h_FmMacsecSecY);UNUSED(h_Sc);UNUSED(an);UNUSED(p_Statistics);
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_SECY_TxScGetStatistics(t_Handle h_FmMacsecSecY, t_FmMacsecSecYTxScStatistics *p_Statistics)
++{
++    UNUSED(h_FmMacsecSecY);UNUSED(p_Statistics);
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++t_Error FM_MACSEC_SECY_TxSaGetStatistics(t_Handle h_FmMacsecSecY, macsecAN_t an, t_FmMacsecSecYTxSaStatistics *p_Statistics)
++{
++    UNUSED(h_FmMacsecSecY);UNUSED(an);UNUSED(p_Statistics);
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.h
+@@ -0,0 +1,144 @@
++/*
++ * Copyright 2008-2015 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/******************************************************************************
++ @File          fm_macsec_secy.h
++
++ @Description   FM MACSEC SecY internal structures and definitions.
++*//***************************************************************************/
++#ifndef __FM_MACSEC_SECY_H
++#define __FM_MACSEC_SECY_H
++
++#include "error_ext.h"
++#include "std_ext.h"
++
++#include "fm_macsec.h"
++
++
++/**************************************************************************//**
++ @Description       Exceptions
++*//***************************************************************************/
++
++#define FM_MACSEC_SECY_EX_FRAME_DISCARDED           0x80000000
++
++#define GET_EXCEPTION_FLAG(bitMask, exception)  switch (exception){     \
++    case e_FM_MACSEC_SECY_EX_FRAME_DISCARDED:                           \
++        bitMask = FM_MACSEC_SECY_EX_FRAME_DISCARDED; break;             \
++    default: bitMask = 0;break;}
++
++/**************************************************************************//**
++ @Description       Events
++*//***************************************************************************/
++
++#define FM_MACSEC_SECY_EV_NEXT_PN                        0x80000000
++
++#define GET_EVENT_FLAG(bitMask, event)          switch (event){     \
++    case e_FM_MACSEC_SECY_EV_NEXT_PN:                               \
++        bitMask = FM_MACSEC_SECY_EV_NEXT_PN; break;                 \
++    default: bitMask = 0;break;}
++
++/**************************************************************************//**
++ @Description       Defaults
++*//***************************************************************************/
++
++#define DEFAULT_exceptions                  (FM_MACSEC_SECY_EX_FRAME_DISCARDED)
++#define DEFAULT_events                      (FM_MACSEC_SECY_EV_NEXT_PN)
++#define DEFAULT_numOfTxSc                   1
++#define DEFAULT_confidentialityEnable       FALSE
++#define DEFAULT_confidentialityOffset       0
++#define DEFAULT_sciInsertionMode            e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_SECTAG
++#define DEFAULT_validateFrames              e_FM_MACSEC_VALID_FRAME_BEHAVIOR_STRICT
++#define DEFAULT_replayEnable                FALSE
++#define DEFAULT_replayWindow                0
++#define DEFAULT_protectFrames               TRUE
++#define DEFAULT_ptp                         FALSE
++
++/**************************************************************************//**
++ @Description       General defines
++*//***************************************************************************/
++
++#define SECY_AN_FREE_VALUE              MAX_NUM_OF_SA_PER_SC
++
++
++typedef struct {
++    e_ScSaId                            saId;
++    bool                                active;
++    union {
++        t_FmMacsecSecYRxSaStatistics    rxSaStatistics;
++        t_FmMacsecSecYTxSaStatistics    txSaStatistics;
++    };
++} t_SecYSa;
++
++typedef struct {
++    bool                                inUse;
++    uint32_t                            scId;
++    e_ScType                            type;
++    uint8_t                             numOfSa;
++    t_SecYSa                            sa[MAX_NUM_OF_SA_PER_SC];
++    union {
++        t_FmMacsecSecYRxScStatistics    rxScStatistics;
++        t_FmMacsecSecYTxScStatistics    txScStatistics;
++    };
++} t_SecYSc;
++
++typedef struct {
++    t_FmMacsecSecYSCParams              txScParams;             /**< Tx SC Params */
++} t_FmMacsecSecYDriverParam;
++
++typedef struct {
++    t_Handle                            h_FmMacsec;
++    bool                                confidentialityEnable;  /**< TRUE  - confidentiality protection and integrity protection
++                                                                     FALSE - no confidentiality protection, only integrity protection*/
++    uint16_t                            confidentialityOffset;  /**< The number of initial octets of each MSDU without confidentiality protection
++                                                                     common values are 0, 30, and 50 */
++    bool                                replayProtect;          /**< replay protection function mode */
++    uint32_t                            replayWindow;           /**< the size of the replay window */
++    e_FmMacsecValidFrameBehavior        validateFrames;         /**< validation function mode */
++    e_FmMacsecSciInsertionMode          sciInsertionMode;
++    bool                                protectFrames;
++    bool                                isPointToPoint;
++    e_FmMacsecSecYCipherSuite           cipherSuite;            /**< Cipher suite to be used for this SecY */
++    uint32_t                            numOfRxSc;              /**< Number of receive channels */
++    uint32_t                            numOfTxSc;              /**< Number of transmit channels */
++    t_SecYSc                            *p_RxSc;
++    t_SecYSc                            *p_TxSc;
++    uint32_t                            events;
++    uint32_t                            exceptions;
++    t_FmMacsecSecYExceptionsCallback    *f_Exception;           /**< TODO */
++    t_FmMacsecSecYEventsCallback        *f_Event;               /**< TODO */
++    t_Handle                            h_App;
++    t_FmMacsecSecYStatistics            statistics;
++    t_FmMacsecSecYDriverParam           *p_FmMacsecSecYDriverParam;
++} t_FmMacsecSecY;
++
++
++#endif /* __FM_MACSEC_SECY_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Makefile
+@@ -0,0 +1,23 @@
++#
++# Makefile for the Freescale Ethernet controllers
++#
++ccflags-y           += -DVERSION=\"\"
++#
++#Include netcomm SW specific definitions
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
++
++ccflags-y += -I$(NCSW_FM_INC)
++
++
++obj-y         += fsl-ncsw-PFM1.o
++
++fsl-ncsw-PFM1-objs    :=   fm.o fm_muram.o fman.o
++
++obj-y         += MAC/
++obj-y         += Pcd/
++obj-y         += SP/
++obj-y         += Port/
++obj-y         += HC/
++obj-y         += Rtc/
++obj-y         += MACSEC/
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/Makefile
+@@ -0,0 +1,26 @@
++#
++# Makefile for the Freescale Ethernet controllers
++#
++ccflags-y           += -DVERSION=\"\"
++#
++#Include netcomm SW specific definitions
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++
++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
++
++ccflags-y += -I$(NCSW_FM_INC)
++
++obj-y         += fsl-ncsw-Pcd.o
++
++fsl-ncsw-Pcd-objs     := fman_kg.o fman_prs.o fm_cc.o fm_kg.o fm_pcd.o fm_plcr.o fm_prs.o fm_manip.o
++
++ifeq ($(CONFIG_FMAN_V3H),y)
++fsl-ncsw-Pcd-objs     += fm_replic.o
++endif
++ifeq ($(CONFIG_FMAN_V3L),y)
++fsl-ncsw-Pcd-objs       += fm_replic.o
++endif
++ifeq ($(CONFIG_FMAN_ARM),y)
++fsl-ncsw-Pcd-objs     += fm_replic.o
++endif
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/crc64.h
+@@ -0,0 +1,360 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++ /**************************************************************************//**
++ @File          crc64.h
++
++ @Description   brief This file contains the CRC64 Table, and __inline__
++                functions used for calculating crc.
++*//***************************************************************************/
++#ifndef __CRC64_H
++#define __CRC64_H
++
++#include "std_ext.h"
++
++
++#define BITS_PER_BYTE                   8
++
++#define CRC64_EXPON_ECMA_182            0xC96C5795D7870F42ULL
++#define CRC64_DEFAULT_INITVAL           0xFFFFFFFFFFFFFFFFULL
++
++#define CRC64_BYTE_MASK                 0xFF
++#define CRC64_TABLE_ENTRIES             ( 1 << BITS_PER_BYTE )
++#define CRC64_ODD_MASK                  1
++
++
++/**
++ \brief '64 bit crc' Table
++ */
++struct crc64_t {
++    uint64_t initial;                       /**< Initial seed */
++    uint64_t table[CRC64_TABLE_ENTRIES];    /**< CRC table entries */
++};
++
++
++static struct crc64_t CRC64_ECMA_182 = {
++    CRC64_DEFAULT_INITVAL,
++    {
++        0x0000000000000000ULL,
++        0xb32e4cbe03a75f6fULL,
++        0xf4843657a840a05bULL,
++        0x47aa7ae9abe7ff34ULL,
++        0x7bd0c384ff8f5e33ULL,
++        0xc8fe8f3afc28015cULL,
++        0x8f54f5d357cffe68ULL,
++        0x3c7ab96d5468a107ULL,
++        0xf7a18709ff1ebc66ULL,
++        0x448fcbb7fcb9e309ULL,
++        0x0325b15e575e1c3dULL,
++        0xb00bfde054f94352ULL,
++        0x8c71448d0091e255ULL,
++        0x3f5f08330336bd3aULL,
++        0x78f572daa8d1420eULL,
++        0xcbdb3e64ab761d61ULL,
++        0x7d9ba13851336649ULL,
++        0xceb5ed8652943926ULL,
++        0x891f976ff973c612ULL,
++        0x3a31dbd1fad4997dULL,
++        0x064b62bcaebc387aULL,
++        0xb5652e02ad1b6715ULL,
++        0xf2cf54eb06fc9821ULL,
++        0x41e11855055bc74eULL,
++        0x8a3a2631ae2dda2fULL,
++        0x39146a8fad8a8540ULL,
++        0x7ebe1066066d7a74ULL,
++        0xcd905cd805ca251bULL,
++        0xf1eae5b551a2841cULL,
++        0x42c4a90b5205db73ULL,
++        0x056ed3e2f9e22447ULL,
++        0xb6409f5cfa457b28ULL,
++        0xfb374270a266cc92ULL,
++        0x48190ecea1c193fdULL,
++        0x0fb374270a266cc9ULL,
++        0xbc9d3899098133a6ULL,
++        0x80e781f45de992a1ULL,
++        0x33c9cd4a5e4ecdceULL,
++        0x7463b7a3f5a932faULL,
++        0xc74dfb1df60e6d95ULL,
++        0x0c96c5795d7870f4ULL,
++        0xbfb889c75edf2f9bULL,
++        0xf812f32ef538d0afULL,
++        0x4b3cbf90f69f8fc0ULL,
++        0x774606fda2f72ec7ULL,
++        0xc4684a43a15071a8ULL,
++        0x83c230aa0ab78e9cULL,
++        0x30ec7c140910d1f3ULL,
++        0x86ace348f355aadbULL,
++        0x3582aff6f0f2f5b4ULL,
++        0x7228d51f5b150a80ULL,
++        0xc10699a158b255efULL,
++        0xfd7c20cc0cdaf4e8ULL,
++        0x4e526c720f7dab87ULL,
++        0x09f8169ba49a54b3ULL,
++        0xbad65a25a73d0bdcULL,
++        0x710d64410c4b16bdULL,
++        0xc22328ff0fec49d2ULL,
++        0x85895216a40bb6e6ULL,
++        0x36a71ea8a7ace989ULL,
++        0x0adda7c5f3c4488eULL,
++        0xb9f3eb7bf06317e1ULL,
++        0xfe5991925b84e8d5ULL,
++        0x4d77dd2c5823b7baULL,
++        0x64b62bcaebc387a1ULL,
++        0xd7986774e864d8ceULL,
++        0x90321d9d438327faULL,
++        0x231c512340247895ULL,
++        0x1f66e84e144cd992ULL,
++        0xac48a4f017eb86fdULL,
++        0xebe2de19bc0c79c9ULL,
++        0x58cc92a7bfab26a6ULL,
++        0x9317acc314dd3bc7ULL,
++        0x2039e07d177a64a8ULL,
++        0x67939a94bc9d9b9cULL,
++        0xd4bdd62abf3ac4f3ULL,
++        0xe8c76f47eb5265f4ULL,
++        0x5be923f9e8f53a9bULL,
++        0x1c4359104312c5afULL,
++        0xaf6d15ae40b59ac0ULL,
++        0x192d8af2baf0e1e8ULL,
++        0xaa03c64cb957be87ULL,
++        0xeda9bca512b041b3ULL,
++        0x5e87f01b11171edcULL,
++        0x62fd4976457fbfdbULL,
++        0xd1d305c846d8e0b4ULL,
++        0x96797f21ed3f1f80ULL,
++        0x2557339fee9840efULL,
++        0xee8c0dfb45ee5d8eULL,
++        0x5da24145464902e1ULL,
++        0x1a083bacedaefdd5ULL,
++        0xa9267712ee09a2baULL,
++        0x955cce7fba6103bdULL,
++        0x267282c1b9c65cd2ULL,
++        0x61d8f8281221a3e6ULL,
++        0xd2f6b4961186fc89ULL,
++        0x9f8169ba49a54b33ULL,
++        0x2caf25044a02145cULL,
++        0x6b055fede1e5eb68ULL,
++        0xd82b1353e242b407ULL,
++        0xe451aa3eb62a1500ULL,
++        0x577fe680b58d4a6fULL,
++        0x10d59c691e6ab55bULL,
++        0xa3fbd0d71dcdea34ULL,
++        0x6820eeb3b6bbf755ULL,
++        0xdb0ea20db51ca83aULL,
++        0x9ca4d8e41efb570eULL,
++        0x2f8a945a1d5c0861ULL,
++        0x13f02d374934a966ULL,
++        0xa0de61894a93f609ULL,
++        0xe7741b60e174093dULL,
++        0x545a57dee2d35652ULL,
++        0xe21ac88218962d7aULL,
++        0x5134843c1b317215ULL,
++        0x169efed5b0d68d21ULL,
++        0xa5b0b26bb371d24eULL,
++        0x99ca0b06e7197349ULL,
++        0x2ae447b8e4be2c26ULL,
++        0x6d4e3d514f59d312ULL,
++        0xde6071ef4cfe8c7dULL,
++        0x15bb4f8be788911cULL,
++        0xa6950335e42fce73ULL,
++        0xe13f79dc4fc83147ULL,
++        0x521135624c6f6e28ULL,
++        0x6e6b8c0f1807cf2fULL,
++        0xdd45c0b11ba09040ULL,
++        0x9aefba58b0476f74ULL,
++        0x29c1f6e6b3e0301bULL,
++        0xc96c5795d7870f42ULL,
++        0x7a421b2bd420502dULL,
++        0x3de861c27fc7af19ULL,
++        0x8ec62d7c7c60f076ULL,
++        0xb2bc941128085171ULL,
++        0x0192d8af2baf0e1eULL,
++        0x4638a2468048f12aULL,
++        0xf516eef883efae45ULL,
++        0x3ecdd09c2899b324ULL,
++        0x8de39c222b3eec4bULL,
++        0xca49e6cb80d9137fULL,
++        0x7967aa75837e4c10ULL,
++        0x451d1318d716ed17ULL,
++        0xf6335fa6d4b1b278ULL,
++        0xb199254f7f564d4cULL,
++        0x02b769f17cf11223ULL,
++        0xb4f7f6ad86b4690bULL,
++        0x07d9ba1385133664ULL,
++        0x4073c0fa2ef4c950ULL,
++        0xf35d8c442d53963fULL,
++        0xcf273529793b3738ULL,
++        0x7c0979977a9c6857ULL,
++        0x3ba3037ed17b9763ULL,
++        0x888d4fc0d2dcc80cULL,
++        0x435671a479aad56dULL,
++        0xf0783d1a7a0d8a02ULL,
++        0xb7d247f3d1ea7536ULL,
++        0x04fc0b4dd24d2a59ULL,
++        0x3886b22086258b5eULL,
++        0x8ba8fe9e8582d431ULL,
++        0xcc0284772e652b05ULL,
++        0x7f2cc8c92dc2746aULL,
++        0x325b15e575e1c3d0ULL,
++        0x8175595b76469cbfULL,
++        0xc6df23b2dda1638bULL,
++        0x75f16f0cde063ce4ULL,
++        0x498bd6618a6e9de3ULL,
++        0xfaa59adf89c9c28cULL,
++        0xbd0fe036222e3db8ULL,
++        0x0e21ac88218962d7ULL,
++        0xc5fa92ec8aff7fb6ULL,
++        0x76d4de52895820d9ULL,
++        0x317ea4bb22bfdfedULL,
++        0x8250e80521188082ULL,
++        0xbe2a516875702185ULL,
++        0x0d041dd676d77eeaULL,
++        0x4aae673fdd3081deULL,
++        0xf9802b81de97deb1ULL,
++        0x4fc0b4dd24d2a599ULL,
++        0xfceef8632775faf6ULL,
++        0xbb44828a8c9205c2ULL,
++        0x086ace348f355aadULL,
++        0x34107759db5dfbaaULL,
++        0x873e3be7d8faa4c5ULL,
++        0xc094410e731d5bf1ULL,
++        0x73ba0db070ba049eULL,
++        0xb86133d4dbcc19ffULL,
++        0x0b4f7f6ad86b4690ULL,
++        0x4ce50583738cb9a4ULL,
++        0xffcb493d702be6cbULL,
++        0xc3b1f050244347ccULL,
++        0x709fbcee27e418a3ULL,
++        0x3735c6078c03e797ULL,
++        0x841b8ab98fa4b8f8ULL,
++        0xadda7c5f3c4488e3ULL,
++        0x1ef430e13fe3d78cULL,
++        0x595e4a08940428b8ULL,
++        0xea7006b697a377d7ULL,
++        0xd60abfdbc3cbd6d0ULL,
++        0x6524f365c06c89bfULL,
++        0x228e898c6b8b768bULL,
++        0x91a0c532682c29e4ULL,
++        0x5a7bfb56c35a3485ULL,
++        0xe955b7e8c0fd6beaULL,
++        0xaeffcd016b1a94deULL,
++        0x1dd181bf68bdcbb1ULL,
++        0x21ab38d23cd56ab6ULL,
++        0x9285746c3f7235d9ULL,
++        0xd52f0e859495caedULL,
++        0x6601423b97329582ULL,
++        0xd041dd676d77eeaaULL,
++        0x636f91d96ed0b1c5ULL,
++        0x24c5eb30c5374ef1ULL,
++        0x97eba78ec690119eULL,
++        0xab911ee392f8b099ULL,
++        0x18bf525d915feff6ULL,
++        0x5f1528b43ab810c2ULL,
++        0xec3b640a391f4fadULL,
++        0x27e05a6e926952ccULL,
++        0x94ce16d091ce0da3ULL,
++        0xd3646c393a29f297ULL,
++        0x604a2087398eadf8ULL,
++        0x5c3099ea6de60cffULL,
++        0xef1ed5546e415390ULL,
++        0xa8b4afbdc5a6aca4ULL,
++        0x1b9ae303c601f3cbULL,
++        0x56ed3e2f9e224471ULL,
++        0xe5c372919d851b1eULL,
++        0xa26908783662e42aULL,
++        0x114744c635c5bb45ULL,
++        0x2d3dfdab61ad1a42ULL,
++        0x9e13b115620a452dULL,
++        0xd9b9cbfcc9edba19ULL,
++        0x6a978742ca4ae576ULL,
++        0xa14cb926613cf817ULL,
++        0x1262f598629ba778ULL,
++        0x55c88f71c97c584cULL,
++        0xe6e6c3cfcadb0723ULL,
++        0xda9c7aa29eb3a624ULL,
++        0x69b2361c9d14f94bULL,
++        0x2e184cf536f3067fULL,
++        0x9d36004b35545910ULL,
++        0x2b769f17cf112238ULL,
++        0x9858d3a9ccb67d57ULL,
++        0xdff2a94067518263ULL,
++        0x6cdce5fe64f6dd0cULL,
++        0x50a65c93309e7c0bULL,
++        0xe388102d33392364ULL,
++        0xa4226ac498dedc50ULL,
++        0x170c267a9b79833fULL,
++        0xdcd7181e300f9e5eULL,
++        0x6ff954a033a8c131ULL,
++        0x28532e49984f3e05ULL,
++        0x9b7d62f79be8616aULL,
++        0xa707db9acf80c06dULL,
++        0x14299724cc279f02ULL,
++        0x5383edcd67c06036ULL,
++        0xe0ada17364673f59ULL
++    }
++};
++
++
++/**
++ \brief Initializes the crc seed
++ */
++static __inline__ uint64_t crc64_init(void)
++{
++    return CRC64_ECMA_182.initial;
++}
++
++/**
++ \brief Computes 64 bit the crc
++ \param[in] data Pointer to the Data in the frame
++ \param[in] len Length of the Data
++ \param[in] crc seed
++ \return calculated crc
++ */
++static __inline__ uint64_t crc64_compute(void const *data,
++                                         uint32_t   len,
++                                         uint64_t   seed)
++{
++    uint32_t i;
++    uint64_t crc = seed;
++    uint8_t *bdata = (uint8_t *) data;
++
++    for (i = 0; i < len; i++)
++        crc =
++            CRC64_ECMA_182.
++            table[(crc ^ *bdata++) & CRC64_BYTE_MASK] ^ (crc >> 8);
++
++    return crc;
++}
++
++
++#endif /* __CRC64_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c
+@@ -0,0 +1,7582 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_cc.c
++
++ @Description   FM Coarse Classifier implementation
++ *//***************************************************************************/
++#include <linux/math64.h>
++#include "std_ext.h"
++#include "error_ext.h"
++#include "string_ext.h"
++#include "debug_ext.h"
++#include "fm_pcd_ext.h"
++#include "fm_muram_ext.h"
++
++#include "fm_common.h"
++#include "fm_pcd.h"
++#include "fm_hc.h"
++#include "fm_cc.h"
++#include "crc64.h"
++
++/****************************************/
++/*       static functions               */
++/****************************************/
++
++
++static t_Error CcRootTryLock(t_Handle h_FmPcdCcTree)
++{
++    t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree;
++
++    ASSERT_COND(h_FmPcdCcTree);
++
++    if (FmPcdLockTryLock(p_FmPcdCcTree->p_Lock))
++        return E_OK;
++
++    return ERROR_CODE(E_BUSY);
++}
++
++static void CcRootReleaseLock(t_Handle h_FmPcdCcTree)
++{
++    t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree;
++
++    ASSERT_COND(h_FmPcdCcTree);
++
++    FmPcdLockUnlock(p_FmPcdCcTree->p_Lock);
++}
++
++static void UpdateNodeOwner(t_FmPcdCcNode *p_CcNode, bool add)
++{
++    uint32_t intFlags;
++
++    ASSERT_COND(p_CcNode);
++
++    intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock);
++
++    if (add)
++        p_CcNode->owners++;
++    else
++    {
++        ASSERT_COND(p_CcNode->owners);
++        p_CcNode->owners--;
++    }
++
++    XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
++}
++
++static __inline__ t_FmPcdStatsObj* DequeueStatsObj(t_List *p_List)
++{
++    t_FmPcdStatsObj *p_StatsObj = NULL;
++    t_List *p_Next;
++
++    if (!LIST_IsEmpty(p_List))
++    {
++        p_Next = LIST_FIRST(p_List);
++        p_StatsObj = LIST_OBJECT(p_Next, t_FmPcdStatsObj, node);
++        ASSERT_COND(p_StatsObj);
++        LIST_DelAndInit(p_Next);
++    }
++
++    return p_StatsObj;
++}
++
++static __inline__ void EnqueueStatsObj(t_List *p_List,
++                                       t_FmPcdStatsObj *p_StatsObj)
++{
++    LIST_AddToTail(&p_StatsObj->node, p_List);
++}
++
++static void FreeStatObjects(t_List *p_List, t_Handle h_FmMuram)
++{
++    t_FmPcdStatsObj *p_StatsObj;
++
++    while (!LIST_IsEmpty(p_List))
++    {
++        p_StatsObj = DequeueStatsObj(p_List);
++        ASSERT_COND(p_StatsObj);
++
++        FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsAd);
++        FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsCounters);
++
++        XX_Free(p_StatsObj);
++    }
++}
++
++static t_FmPcdStatsObj* GetStatsObj(t_FmPcdCcNode *p_CcNode)
++{
++    t_FmPcdStatsObj* p_StatsObj;
++    t_Handle h_FmMuram;
++
++    ASSERT_COND(p_CcNode);
++
++    /* If 'maxNumOfKeys' was passed, all statistics object were preallocated
++     upon node initialization */
++    if (p_CcNode->maxNumOfKeys)
++    {
++        p_StatsObj = DequeueStatsObj(&p_CcNode->availableStatsLst);
++
++              /* Clean statistics counters & ADs */
++              MemSet8(p_StatsObj->h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++              MemSet8(p_StatsObj->h_StatsCounters, 0, p_CcNode->countersArraySize);
++    }
++    else
++    {
++        h_FmMuram = ((t_FmPcd *)(p_CcNode->h_FmPcd))->h_FmMuram;
++        ASSERT_COND(h_FmMuram);
++
++        p_StatsObj = XX_Malloc(sizeof(t_FmPcdStatsObj));
++        if (!p_StatsObj)
++        {
++            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("statistics object"));
++            return NULL;
++        }
++
++        p_StatsObj->h_StatsAd = (t_Handle)FM_MURAM_AllocMem(
++                h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE, FM_PCD_CC_AD_TABLE_ALIGN);
++        if (!p_StatsObj->h_StatsAd)
++        {
++            XX_Free(p_StatsObj);
++            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for statistics ADs"));
++            return NULL;
++        }
++        MemSet8(p_StatsObj->h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++        p_StatsObj->h_StatsCounters = (t_Handle)FM_MURAM_AllocMem(
++                h_FmMuram, p_CcNode->countersArraySize,
++                FM_PCD_CC_AD_TABLE_ALIGN);
++        if (!p_StatsObj->h_StatsCounters)
++        {
++            FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsAd);
++            XX_Free(p_StatsObj);
++            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for statistics counters"));
++            return NULL;
++        }
++        MemSet8(p_StatsObj->h_StatsCounters, 0, p_CcNode->countersArraySize);
++    }
++
++    return p_StatsObj;
++}
++
++static void PutStatsObj(t_FmPcdCcNode *p_CcNode, t_FmPcdStatsObj *p_StatsObj)
++{
++    t_Handle h_FmMuram;
++
++    ASSERT_COND(p_CcNode);
++    ASSERT_COND(p_StatsObj);
++
++    /* If 'maxNumOfKeys' was passed, all statistics object were preallocated
++     upon node initialization and now will be enqueued back to the list */
++    if (p_CcNode->maxNumOfKeys)
++    {
++              /* Clean statistics counters */
++              MemSet8(p_StatsObj->h_StatsCounters, 0, p_CcNode->countersArraySize);
++
++              /* Clean statistics ADs */
++              MemSet8(p_StatsObj->h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++        EnqueueStatsObj(&p_CcNode->availableStatsLst, p_StatsObj);
++    }
++    else
++    {
++        h_FmMuram = ((t_FmPcd *)(p_CcNode->h_FmPcd))->h_FmMuram;
++        ASSERT_COND(h_FmMuram);
++
++        FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsAd);
++        FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsCounters);
++
++        XX_Free(p_StatsObj);
++    }
++}
++
++static void SetStatsCounters(t_AdOfTypeStats *p_StatsAd,
++                             uint32_t statsCountersAddr)
++{
++    uint32_t tmp = (statsCountersAddr & FM_PCD_AD_STATS_COUNTERS_ADDR_MASK);
++
++    WRITE_UINT32(p_StatsAd->statsTableAddr, tmp);
++}
++
++
++static void UpdateStatsAd(t_FmPcdCcStatsParams *p_FmPcdCcStatsParams,
++                          t_Handle h_Ad, uint64_t physicalMuramBase)
++{
++    t_AdOfTypeStats *p_StatsAd;
++    uint32_t statsCountersAddr, nextActionAddr, tmp;
++#if (DPAA_VERSION >= 11)
++    uint32_t frameLengthRangesAddr;
++#endif /* (DPAA_VERSION >= 11) */
++
++    p_StatsAd = (t_AdOfTypeStats *)p_FmPcdCcStatsParams->h_StatsAd;
++
++    tmp = FM_PCD_AD_STATS_TYPE;
++
++#if (DPAA_VERSION >= 11)
++    if (p_FmPcdCcStatsParams->h_StatsFLRs)
++    {
++        frameLengthRangesAddr = (uint32_t)((XX_VirtToPhys(
++                p_FmPcdCcStatsParams->h_StatsFLRs) - physicalMuramBase));
++        tmp |= (frameLengthRangesAddr & FM_PCD_AD_STATS_FLR_ADDR_MASK);
++    }
++#endif /* (DPAA_VERSION >= 11) */
++    WRITE_UINT32(p_StatsAd->profileTableAddr, tmp);
++
++    nextActionAddr = (uint32_t)((XX_VirtToPhys(h_Ad) - physicalMuramBase));
++    tmp = 0;
++    tmp |= (uint32_t)((nextActionAddr << FM_PCD_AD_STATS_NEXT_ACTION_SHIFT)
++            & FM_PCD_AD_STATS_NEXT_ACTION_MASK);
++    tmp |= (FM_PCD_AD_STATS_NAD_EN | FM_PCD_AD_STATS_OP_CODE);
++
++#if (DPAA_VERSION >= 11)
++    if (p_FmPcdCcStatsParams->h_StatsFLRs)
++        tmp |= FM_PCD_AD_STATS_FLR_EN;
++#endif /* (DPAA_VERSION >= 11) */
++
++    WRITE_UINT32(p_StatsAd->nextActionIndx, tmp);
++
++    statsCountersAddr = (uint32_t)((XX_VirtToPhys(
++            p_FmPcdCcStatsParams->h_StatsCounters) - physicalMuramBase));
++    SetStatsCounters(p_StatsAd, statsCountersAddr);
++}
++
++static void FillAdOfTypeContLookup(t_Handle h_Ad,
++                                   t_FmPcdCcStatsParams *p_FmPcdCcStatsParams,
++                                   t_Handle h_FmPcd, t_Handle p_CcNode,
++                                   t_Handle h_Manip, t_Handle h_FrmReplic)
++{
++    t_FmPcdCcNode *p_Node = (t_FmPcdCcNode *)p_CcNode;
++    t_AdOfTypeContLookup *p_AdContLookup = (t_AdOfTypeContLookup *)h_Ad;
++    t_Handle h_TmpAd;
++    t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint32_t tmpReg32;
++    t_Handle p_AdNewPtr = NULL;
++
++    UNUSED(h_Manip);
++    UNUSED(h_FrmReplic);
++
++    /* there are 3 cases handled in this routine of building a "Continue lookup" type AD.
++     * Case 1: No Manip. The action descriptor is built within the match table.
++     *         p_AdResult = p_AdNewPtr;
++     * Case 2: Manip exists. A new AD is created - p_AdNewPtr. It is initialized
++     *         either in the FmPcdManipUpdateAdResultForCc routine or it was already
++     *         initialized and returned here.
++     *         p_AdResult (within the match table) will be initialized after
++     *         this routine returns and point to the existing AD.
++     * Case 3: Manip exists. The action descriptor is built within the match table.
++     *         FmPcdManipUpdateAdContLookupForCc returns a NULL p_AdNewPtr.
++     */
++
++    /* As default, the "new" ptr is the current one. i.e. the content of the result
++     * AD will be written into the match table itself (case (1))*/
++    p_AdNewPtr = p_AdContLookup;
++
++    /* Initialize an action descriptor, if current statistics mode requires an Ad */
++    if (p_FmPcdCcStatsParams)
++    {
++        ASSERT_COND(p_FmPcdCcStatsParams->h_StatsAd);
++        ASSERT_COND(p_FmPcdCcStatsParams->h_StatsCounters);
++
++        /* Swapping addresses between statistics Ad and the current lookup AD */
++        h_TmpAd = p_FmPcdCcStatsParams->h_StatsAd;
++        p_FmPcdCcStatsParams->h_StatsAd = h_Ad;
++        h_Ad = h_TmpAd;
++
++        p_AdNewPtr = h_Ad;
++        p_AdContLookup = h_Ad;
++
++        /* Init statistics Ad and connect current lookup AD as 'next action' from statistics Ad */
++        UpdateStatsAd(p_FmPcdCcStatsParams, h_Ad, p_FmPcd->physicalMuramBase);
++    }
++
++#if DPAA_VERSION >= 11
++    if (h_Manip && h_FrmReplic)
++        FmPcdManipUpdateAdContLookupForCc(
++                h_Manip,
++                h_Ad,
++                &p_AdNewPtr,
++                (uint32_t)((XX_VirtToPhys(
++                        FrmReplicGroupGetSourceTableDescriptor(h_FrmReplic))
++                        - p_FmPcd->physicalMuramBase)));
++    else
++        if (h_FrmReplic)
++            FrmReplicGroupUpdateAd(h_FrmReplic, h_Ad, &p_AdNewPtr);
++        else
++#endif /* (DPAA_VERSION >= 11) */
++            if (h_Manip)
++                FmPcdManipUpdateAdContLookupForCc(
++                        h_Manip,
++                        h_Ad,
++                        &p_AdNewPtr,
++
++#ifdef FM_CAPWAP_SUPPORT
++                        /*no check for opcode of manip - this step can be reached only with capwap_applic_specific*/
++                        (uint32_t)((XX_VirtToPhys(p_Node->h_AdTable) - p_FmPcd->physicalMuramBase))
++#else  /* not FM_CAPWAP_SUPPORT */
++                        (uint32_t)((XX_VirtToPhys(p_Node->h_Ad)
++                                - p_FmPcd->physicalMuramBase))
++#endif /* not FM_CAPWAP_SUPPORT */
++                        );
++
++    /* if (p_AdNewPtr = NULL) --> Done. (case (3)) */
++    if (p_AdNewPtr)
++    {
++        /* cases (1) & (2) */
++        tmpReg32 = 0;
++        tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
++        tmpReg32 |=
++                p_Node->sizeOfExtraction ? ((p_Node->sizeOfExtraction - 1) << 24) :
++                        0;
++        tmpReg32 |= (uint32_t)(XX_VirtToPhys(p_Node->h_AdTable)
++                - p_FmPcd->physicalMuramBase);
++        WRITE_UINT32(p_AdContLookup->ccAdBase, tmpReg32);
++
++        tmpReg32 = 0;
++        tmpReg32 |= p_Node->numOfKeys << 24;
++        tmpReg32 |= (p_Node->lclMask ? FM_PCD_AD_CONT_LOOKUP_LCL_MASK : 0);
++        tmpReg32 |=
++                p_Node->h_KeysMatchTable ? (uint32_t)(XX_VirtToPhys(
++                        p_Node->h_KeysMatchTable) - p_FmPcd->physicalMuramBase) :
++                        0;
++        WRITE_UINT32(p_AdContLookup->matchTblPtr, tmpReg32);
++
++        tmpReg32 = 0;
++        tmpReg32 |= p_Node->prsArrayOffset << 24;
++        tmpReg32 |= p_Node->offset << 16;
++        tmpReg32 |= p_Node->parseCode;
++        WRITE_UINT32(p_AdContLookup->pcAndOffsets, tmpReg32);
++
++        MemCpy8((void*)&p_AdContLookup->gmask, p_Node->p_GlblMask,
++                    CC_GLBL_MASK_SIZE);
++    }
++}
++
++static t_Error AllocAndFillAdForContLookupManip(t_Handle h_CcNode)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    uint32_t intFlags;
++
++    ASSERT_COND(p_CcNode);
++
++    intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock);
++
++    if (!p_CcNode->h_Ad)
++    {
++        if (p_CcNode->maxNumOfKeys)
++            p_CcNode->h_Ad = p_CcNode->h_TmpAd;
++        else
++            p_CcNode->h_Ad = (t_Handle)FM_MURAM_AllocMem(
++                    ((t_FmPcd *)(p_CcNode->h_FmPcd))->h_FmMuram,
++                    FM_PCD_CC_AD_ENTRY_SIZE, FM_PCD_CC_AD_TABLE_ALIGN);
++
++        XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
++
++        if (!p_CcNode->h_Ad)
++            RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                         ("MURAM allocation for CC action descriptor"));
++
++        MemSet8(p_CcNode->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++        FillAdOfTypeContLookup(p_CcNode->h_Ad, NULL, p_CcNode->h_FmPcd,
++                               p_CcNode, NULL, NULL);
++    }
++    else
++        XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
++
++    return E_OK;
++}
++
++static t_Error SetRequiredAction1(
++        t_Handle h_FmPcd, uint32_t requiredAction,
++        t_FmPcdCcKeyAndNextEngineParams *p_CcKeyAndNextEngineParamsTmp,
++        t_Handle h_AdTmp, uint16_t numOfEntries, t_Handle h_Tree)
++{
++    t_AdOfTypeResult *p_AdTmp = (t_AdOfTypeResult *)h_AdTmp;
++    uint32_t tmpReg32;
++    t_Error err;
++    t_FmPcdCcNode *p_CcNode;
++    int i = 0;
++    uint16_t tmp = 0;
++    uint16_t profileId;
++    uint8_t relativeSchemeId, physicalSchemeId;
++    t_CcNodeInformation ccNodeInfo;
++
++    for (i = 0; i < numOfEntries; i++)
++    {
++        if (i == 0)
++            h_AdTmp = PTR_MOVE(h_AdTmp, i*FM_PCD_CC_AD_ENTRY_SIZE);
++        else
++            h_AdTmp = PTR_MOVE(h_AdTmp, FM_PCD_CC_AD_ENTRY_SIZE);
++
++        switch (p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.nextEngine)
++        {
++            case (e_FM_PCD_CC):
++                if (requiredAction)
++                {
++                    p_CcNode =
++                            p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.ccParams.h_CcNode;
++                    ASSERT_COND(p_CcNode);
++                    if (p_CcNode->shadowAction == requiredAction)
++                        break;
++                    if ((requiredAction & UPDATE_CC_WITH_TREE)
++                            && !(p_CcNode->shadowAction & UPDATE_CC_WITH_TREE))
++                    {
++
++                        memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
++                        ccNodeInfo.h_CcNode = h_Tree;
++                        EnqueueNodeInfoToRelevantLst(&p_CcNode->ccTreesLst,
++                                                     &ccNodeInfo, NULL);
++                        p_CcKeyAndNextEngineParamsTmp[i].shadowAction |=
++                                UPDATE_CC_WITH_TREE;
++                    }
++                    if ((requiredAction & UPDATE_CC_SHADOW_CLEAR)
++                            && !(p_CcNode->shadowAction & UPDATE_CC_SHADOW_CLEAR))
++                    {
++
++                        p_CcNode->shadowAction = 0;
++                    }
++
++                    if ((requiredAction & UPDATE_CC_WITH_DELETE_TREE)
++                            && !(p_CcNode->shadowAction
++                                    & UPDATE_CC_WITH_DELETE_TREE))
++                    {
++                        DequeueNodeInfoFromRelevantLst(&p_CcNode->ccTreesLst,
++                                                       h_Tree, NULL);
++                        p_CcKeyAndNextEngineParamsTmp[i].shadowAction |=
++                                UPDATE_CC_WITH_DELETE_TREE;
++                    }
++                    if (p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine
++                            != e_FM_PCD_INVALID)
++                        tmp = (uint8_t)(p_CcNode->numOfKeys + 1);
++                    else
++                        tmp = p_CcNode->numOfKeys;
++                    err = SetRequiredAction1(h_FmPcd, requiredAction,
++                                             p_CcNode->keyAndNextEngineParams,
++                                             p_CcNode->h_AdTable, tmp, h_Tree);
++                    if (err != E_OK)
++                        return err;
++                    if (requiredAction != UPDATE_CC_SHADOW_CLEAR)
++                        p_CcNode->shadowAction |= requiredAction;
++                }
++                break;
++
++            case (e_FM_PCD_KG):
++                if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA)
++                        && !(p_CcKeyAndNextEngineParamsTmp[i].shadowAction
++                                & UPDATE_NIA_ENQ_WITHOUT_DMA))
++                {
++                    physicalSchemeId =
++                            FmPcdKgGetSchemeId(
++                                    p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.kgParams.h_DirectScheme);
++                    relativeSchemeId = FmPcdKgGetRelativeSchemeId(
++                            h_FmPcd, physicalSchemeId);
++                    if (relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES)
++                        RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
++                    if (!FmPcdKgIsSchemeValidSw(
++                            p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.kgParams.h_DirectScheme))
++                        RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                                     ("Invalid direct scheme."));
++                    if (!KgIsSchemeAlwaysDirect(h_FmPcd, relativeSchemeId))
++                        RETURN_ERROR(
++                                MAJOR, E_INVALID_STATE,
++                                ("For this action scheme has to be direct."));
++                    err =
++                            FmPcdKgCcGetSetParams(
++                                    h_FmPcd,
++                                    p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.kgParams.h_DirectScheme,
++                                    requiredAction, 0);
++                    if (err != E_OK)
++                        RETURN_ERROR(MAJOR, err, NO_MSG);
++                    p_CcKeyAndNextEngineParamsTmp[i].shadowAction |=
++                            requiredAction;
++                }
++                break;
++
++            case (e_FM_PCD_PLCR):
++                if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA)
++                        && !(p_CcKeyAndNextEngineParamsTmp[i].shadowAction
++                                & UPDATE_NIA_ENQ_WITHOUT_DMA))
++                {
++                    if (!p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.plcrParams.overrideParams)
++                        RETURN_ERROR(
++                                MAJOR,
++                                E_NOT_SUPPORTED,
++                                ("In this initialization only overrideFqid can be initialized"));
++                    if (!p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.plcrParams.sharedProfile)
++                        RETURN_ERROR(
++                                MAJOR,
++                                E_NOT_SUPPORTED,
++                                ("In this initialization only overrideFqid can be initialized"));
++                    err =
++                            FmPcdPlcrGetAbsoluteIdByProfileParams(
++                                    h_FmPcd,
++                                    e_FM_PCD_PLCR_SHARED,
++                                    NULL,
++                                    p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.plcrParams.newRelativeProfileId,
++                                    &profileId);
++                    if (err != E_OK)
++                        RETURN_ERROR(MAJOR, err, NO_MSG);
++                    err = FmPcdPlcrCcGetSetParams(h_FmPcd, profileId,
++                                                  requiredAction);
++                    if (err != E_OK)
++                        RETURN_ERROR(MAJOR, err, NO_MSG);
++                    p_CcKeyAndNextEngineParamsTmp[i].shadowAction |=
++                            requiredAction;
++                }
++                break;
++
++            case (e_FM_PCD_DONE):
++                if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA)
++                        && !(p_CcKeyAndNextEngineParamsTmp[i].shadowAction
++                                & UPDATE_NIA_ENQ_WITHOUT_DMA))
++                {
++                    tmpReg32 = GET_UINT32(p_AdTmp->nia);
++                    if ((tmpReg32 & GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd))
++                            != GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd))
++                        RETURN_ERROR(
++                                MAJOR,
++                                E_INVALID_STATE,
++                                ("Next engine was previously assigned not as PCD_DONE"));
++                    tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
++                    WRITE_UINT32(p_AdTmp->nia, tmpReg32);
++                    p_CcKeyAndNextEngineParamsTmp[i].shadowAction |=
++                            requiredAction;
++                }
++                break;
++
++            default:
++                break;
++        }
++    }
++
++    return E_OK;
++}
++
++static t_Error SetRequiredAction(
++        t_Handle h_FmPcd, uint32_t requiredAction,
++        t_FmPcdCcKeyAndNextEngineParams *p_CcKeyAndNextEngineParamsTmp,
++        t_Handle h_AdTmp, uint16_t numOfEntries, t_Handle h_Tree)
++{
++    t_Error err = SetRequiredAction1(h_FmPcd, requiredAction,
++                                     p_CcKeyAndNextEngineParamsTmp, h_AdTmp,
++                                     numOfEntries, h_Tree);
++    if (err != E_OK)
++        return err;
++    return SetRequiredAction1(h_FmPcd, UPDATE_CC_SHADOW_CLEAR,
++                              p_CcKeyAndNextEngineParamsTmp, h_AdTmp,
++                              numOfEntries, h_Tree);
++}
++
++static t_Error ReleaseModifiedDataStructure(
++        t_Handle h_FmPcd, t_List *h_FmPcdOldPointersLst,
++        t_List *h_FmPcdNewPointersLst,
++        t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalParams,
++        bool useShadowStructs)
++{
++    t_List *p_Pos;
++    t_Error err = E_OK;
++    t_CcNodeInformation ccNodeInfo, *p_CcNodeInformation;
++    t_Handle h_Muram;
++    t_FmPcdCcNode *p_FmPcdCcNextNode, *p_FmPcdCcWorkingOnNode;
++    t_List *p_UpdateLst;
++    uint32_t intFlags;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_AdditionalParams->h_CurrentNode,
++                              E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(h_FmPcdOldPointersLst, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(h_FmPcdNewPointersLst, E_INVALID_HANDLE);
++
++    /* We don't update subtree of the new node with new tree because it was done in the previous stage */
++    if (p_AdditionalParams->h_NodeForAdd)
++    {
++        p_FmPcdCcNextNode = (t_FmPcdCcNode*)p_AdditionalParams->h_NodeForAdd;
++
++        if (!p_AdditionalParams->tree)
++            p_UpdateLst = &p_FmPcdCcNextNode->ccPrevNodesLst;
++        else
++            p_UpdateLst = &p_FmPcdCcNextNode->ccTreeIdLst;
++
++        p_CcNodeInformation = FindNodeInfoInReleventLst(
++                p_UpdateLst, p_AdditionalParams->h_CurrentNode,
++                p_FmPcdCcNextNode->h_Spinlock);
++
++        if (p_CcNodeInformation)
++            p_CcNodeInformation->index++;
++        else
++        {
++            memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
++            ccNodeInfo.h_CcNode = (t_Handle)p_AdditionalParams->h_CurrentNode;
++            ccNodeInfo.index = 1;
++            EnqueueNodeInfoToRelevantLst(p_UpdateLst, &ccNodeInfo,
++                                         p_FmPcdCcNextNode->h_Spinlock);
++        }
++        if (p_AdditionalParams->h_ManipForAdd)
++        {
++            p_CcNodeInformation = FindNodeInfoInReleventLst(
++                    FmPcdManipGetNodeLstPointedOnThisManip(
++                            p_AdditionalParams->h_ManipForAdd),
++                    p_AdditionalParams->h_CurrentNode,
++                    FmPcdManipGetSpinlock(p_AdditionalParams->h_ManipForAdd));
++
++            if (p_CcNodeInformation)
++                p_CcNodeInformation->index++;
++            else
++            {
++                memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
++                ccNodeInfo.h_CcNode =
++                        (t_Handle)p_AdditionalParams->h_CurrentNode;
++                ccNodeInfo.index = 1;
++                EnqueueNodeInfoToRelevantLst(
++                        FmPcdManipGetNodeLstPointedOnThisManip(
++                                p_AdditionalParams->h_ManipForAdd),
++                        &ccNodeInfo,
++                        FmPcdManipGetSpinlock(
++                                p_AdditionalParams->h_ManipForAdd));
++            }
++        }
++    }
++
++    if (p_AdditionalParams->h_NodeForRmv)
++    {
++        p_FmPcdCcNextNode = (t_FmPcdCcNode*)p_AdditionalParams->h_NodeForRmv;
++
++        if (!p_AdditionalParams->tree)
++        {
++            p_UpdateLst = &p_FmPcdCcNextNode->ccPrevNodesLst;
++            p_FmPcdCcWorkingOnNode =
++                    (t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode);
++
++            for (p_Pos = LIST_FIRST(&p_FmPcdCcWorkingOnNode->ccTreesLst);
++                    p_Pos != (&p_FmPcdCcWorkingOnNode->ccTreesLst); p_Pos =
++                            LIST_NEXT(p_Pos))
++            {
++                p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos);
++
++                ASSERT_COND(p_CcNodeInformation->h_CcNode);
++
++                err =
++                        SetRequiredAction(
++                                h_FmPcd,
++                                UPDATE_CC_WITH_DELETE_TREE,
++                                &((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams[p_AdditionalParams->savedKeyIndex],
++                                PTR_MOVE(((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_AdTable, p_AdditionalParams->savedKeyIndex*FM_PCD_CC_AD_ENTRY_SIZE),
++                                1, p_CcNodeInformation->h_CcNode);
++            }
++        }
++        else
++        {
++            p_UpdateLst = &p_FmPcdCcNextNode->ccTreeIdLst;
++
++            err =
++                    SetRequiredAction(
++                            h_FmPcd,
++                            UPDATE_CC_WITH_DELETE_TREE,
++                            &((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams[p_AdditionalParams->savedKeyIndex],
++                            UINT_TO_PTR(((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->ccTreeBaseAddr + p_AdditionalParams->savedKeyIndex*FM_PCD_CC_AD_ENTRY_SIZE),
++                            1, p_AdditionalParams->h_CurrentNode);
++        }
++        if (err)
++            return err;
++
++        /* We remove from the subtree of the removed node tree because it wasn't done in the previous stage
++         Update ccPrevNodesLst or ccTreeIdLst of the removed node
++         Update of the node owner */
++        p_CcNodeInformation = FindNodeInfoInReleventLst(
++                p_UpdateLst, p_AdditionalParams->h_CurrentNode,
++                p_FmPcdCcNextNode->h_Spinlock);
++
++        ASSERT_COND(p_CcNodeInformation);
++        ASSERT_COND(p_CcNodeInformation->index);
++
++        p_CcNodeInformation->index--;
++
++        if (p_CcNodeInformation->index == 0)
++            DequeueNodeInfoFromRelevantLst(p_UpdateLst,
++                                           p_AdditionalParams->h_CurrentNode,
++                                           p_FmPcdCcNextNode->h_Spinlock);
++
++        UpdateNodeOwner(p_FmPcdCcNextNode, FALSE);
++
++        if (p_AdditionalParams->h_ManipForRmv)
++        {
++            p_CcNodeInformation = FindNodeInfoInReleventLst(
++                    FmPcdManipGetNodeLstPointedOnThisManip(
++                            p_AdditionalParams->h_ManipForRmv),
++                    p_AdditionalParams->h_CurrentNode,
++                    FmPcdManipGetSpinlock(p_AdditionalParams->h_ManipForRmv));
++
++            ASSERT_COND(p_CcNodeInformation);
++            ASSERT_COND(p_CcNodeInformation->index);
++
++            p_CcNodeInformation->index--;
++
++            if (p_CcNodeInformation->index == 0)
++                DequeueNodeInfoFromRelevantLst(
++                        FmPcdManipGetNodeLstPointedOnThisManip(
++                                p_AdditionalParams->h_ManipForRmv),
++                        p_AdditionalParams->h_CurrentNode,
++                        FmPcdManipGetSpinlock(
++                                p_AdditionalParams->h_ManipForRmv));
++        }
++    }
++
++    if (p_AdditionalParams->h_ManipForRmv)
++        FmPcdManipUpdateOwner(p_AdditionalParams->h_ManipForRmv, FALSE);
++
++    if (p_AdditionalParams->p_StatsObjForRmv)
++        PutStatsObj((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode),
++                    p_AdditionalParams->p_StatsObjForRmv);
++
++#if (DPAA_VERSION >= 11)
++    if (p_AdditionalParams->h_FrmReplicForRmv)
++        FrmReplicGroupUpdateOwner(p_AdditionalParams->h_FrmReplicForRmv,
++                                  FALSE/* remove */);
++#endif /* (DPAA_VERSION >= 11) */
++
++    if (!useShadowStructs)
++    {
++        h_Muram = FmPcdGetMuramHandle(h_FmPcd);
++        ASSERT_COND(h_Muram);
++
++        if ((p_AdditionalParams->tree && !((t_FmPcd *)h_FmPcd)->p_CcShadow)
++                || (!p_AdditionalParams->tree
++                        && !((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->maxNumOfKeys))
++        {
++            /* We release new AD which was allocated and updated for copy from to actual AD */
++            for (p_Pos = LIST_FIRST(h_FmPcdNewPointersLst);
++                    p_Pos != (h_FmPcdNewPointersLst); p_Pos = LIST_NEXT(p_Pos))
++            {
++
++                p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos);
++                ASSERT_COND(p_CcNodeInformation->h_CcNode);
++                FM_MURAM_FreeMem(h_Muram, p_CcNodeInformation->h_CcNode);
++            }
++        }
++
++        /* Free Old data structure if it has to be freed - new data structure was allocated*/
++        if (p_AdditionalParams->p_AdTableOld)
++            FM_MURAM_FreeMem(h_Muram, p_AdditionalParams->p_AdTableOld);
++
++        if (p_AdditionalParams->p_KeysMatchTableOld)
++            FM_MURAM_FreeMem(h_Muram, p_AdditionalParams->p_KeysMatchTableOld);
++    }
++
++    /* Update current modified node with changed fields if it's required*/
++    if (!p_AdditionalParams->tree)
++    {
++        if (p_AdditionalParams->p_AdTableNew)
++            ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_AdTable =
++                    p_AdditionalParams->p_AdTableNew;
++
++        if (p_AdditionalParams->p_KeysMatchTableNew)
++            ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_KeysMatchTable =
++                    p_AdditionalParams->p_KeysMatchTableNew;
++
++        /* Locking node's spinlock before updating 'keys and next engine' structure,
++         as it maybe used to retrieve keys statistics */
++        intFlags =
++                XX_LockIntrSpinlock(
++                        ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_Spinlock);
++
++        ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->numOfKeys =
++                p_AdditionalParams->numOfKeys;
++
++        memcpy(((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams,
++               &p_AdditionalParams->keyAndNextEngineParams,
++               sizeof(t_FmPcdCcKeyAndNextEngineParams) * (CC_MAX_NUM_OF_KEYS));
++
++        XX_UnlockIntrSpinlock(
++                ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_Spinlock,
++                intFlags);
++    }
++    else
++    {
++        uint8_t numEntries =
++                ((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->numOfEntries;
++        ASSERT_COND(numEntries < FM_PCD_MAX_NUM_OF_CC_GROUPS);
++        memcpy(&((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams,
++               &p_AdditionalParams->keyAndNextEngineParams,
++               sizeof(t_FmPcdCcKeyAndNextEngineParams) * numEntries);
++    }
++
++    ReleaseLst(h_FmPcdOldPointersLst);
++    ReleaseLst(h_FmPcdNewPointersLst);
++
++    XX_Free(p_AdditionalParams);
++
++    return E_OK;
++}
++
++static t_Handle BuildNewAd(
++        t_Handle h_Ad,
++        t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams,
++        t_FmPcdCcNode *p_CcNode,
++        t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
++{
++    t_FmPcdCcNode *p_FmPcdCcNodeTmp;
++    t_Handle h_OrigAd = NULL;
++
++    p_FmPcdCcNodeTmp = (t_FmPcdCcNode*)XX_Malloc(sizeof(t_FmPcdCcNode));
++    if (!p_FmPcdCcNodeTmp)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_FmPcdCcNodeTmp"));
++        return NULL;
++    }
++    memset(p_FmPcdCcNodeTmp, 0, sizeof(t_FmPcdCcNode));
++
++    p_FmPcdCcNodeTmp->numOfKeys = p_FmPcdModifyCcKeyAdditionalParams->numOfKeys;
++    p_FmPcdCcNodeTmp->h_KeysMatchTable =
++            p_FmPcdModifyCcKeyAdditionalParams->p_KeysMatchTableNew;
++    p_FmPcdCcNodeTmp->h_AdTable =
++            p_FmPcdModifyCcKeyAdditionalParams->p_AdTableNew;
++
++    p_FmPcdCcNodeTmp->lclMask = p_CcNode->lclMask;
++    p_FmPcdCcNodeTmp->parseCode = p_CcNode->parseCode;
++    p_FmPcdCcNodeTmp->offset = p_CcNode->offset;
++    p_FmPcdCcNodeTmp->prsArrayOffset = p_CcNode->prsArrayOffset;
++    p_FmPcdCcNodeTmp->ctrlFlow = p_CcNode->ctrlFlow;
++    p_FmPcdCcNodeTmp->ccKeySizeAccExtraction = p_CcNode->ccKeySizeAccExtraction;
++    p_FmPcdCcNodeTmp->sizeOfExtraction = p_CcNode->sizeOfExtraction;
++    p_FmPcdCcNodeTmp->glblMaskSize = p_CcNode->glblMaskSize;
++    p_FmPcdCcNodeTmp->p_GlblMask = p_CcNode->p_GlblMask;
++
++    if (p_FmPcdCcNextEngineParams->nextEngine == e_FM_PCD_CC)
++    {
++        if (p_FmPcdCcNextEngineParams->h_Manip)
++        {
++            h_OrigAd = p_CcNode->h_Ad;
++            if (AllocAndFillAdForContLookupManip(
++                    p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode)
++                    != E_OK)
++            {
++                REPORT_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++                XX_Free(p_FmPcdCcNodeTmp);
++                return NULL;
++            }
++        }
++        FillAdOfTypeContLookup(h_Ad, NULL, p_CcNode->h_FmPcd, p_FmPcdCcNodeTmp,
++                               h_OrigAd ? NULL : p_FmPcdCcNextEngineParams->h_Manip, NULL);
++    }
++
++#if (DPAA_VERSION >= 11)
++    if ((p_FmPcdCcNextEngineParams->nextEngine == e_FM_PCD_FR)
++            && (p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic))
++    {
++        FillAdOfTypeContLookup(
++                h_Ad, NULL, p_CcNode->h_FmPcd, p_FmPcdCcNodeTmp,
++                p_FmPcdCcNextEngineParams->h_Manip,
++                p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic);
++    }
++#endif /* (DPAA_VERSION >= 11) */
++
++    XX_Free(p_FmPcdCcNodeTmp);
++
++    return E_OK;
++}
++
++static t_Error DynamicChangeHc(
++        t_Handle h_FmPcd, t_List *h_OldPointersLst, t_List *h_NewPointersLst,
++        t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalParams,
++        bool useShadowStructs)
++{
++    t_List *p_PosOld, *p_PosNew;
++    uint32_t oldAdAddrOffset, newAdAddrOffset;
++    uint16_t i = 0;
++    t_Error err = E_OK;
++    uint8_t numOfModifiedPtr;
++
++    ASSERT_COND(h_FmPcd);
++    ASSERT_COND(h_OldPointersLst);
++    ASSERT_COND(h_NewPointersLst);
++
++    numOfModifiedPtr = (uint8_t)LIST_NumOfObjs(h_OldPointersLst);
++
++    if (numOfModifiedPtr)
++    {
++        p_PosNew = LIST_FIRST(h_NewPointersLst);
++        p_PosOld = LIST_FIRST(h_OldPointersLst);
++
++        /* Retrieve address of new AD */
++        newAdAddrOffset = FmPcdCcGetNodeAddrOffsetFromNodeInfo(h_FmPcd,
++                                                               p_PosNew);
++        if (newAdAddrOffset == (uint32_t)ILLEGAL_BASE)
++        {
++            ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst,
++                                         h_NewPointersLst,
++                                         p_AdditionalParams, useShadowStructs);
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("New AD address"));
++        }
++
++        for (i = 0; i < numOfModifiedPtr; i++)
++        {
++            /* Retrieve address of current AD */
++            oldAdAddrOffset = FmPcdCcGetNodeAddrOffsetFromNodeInfo(h_FmPcd,
++                                                                   p_PosOld);
++            if (oldAdAddrOffset == (uint32_t)ILLEGAL_BASE)
++            {
++                ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst,
++                                             h_NewPointersLst,
++                                             p_AdditionalParams,
++                                             useShadowStructs);
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Old AD address"));
++            }
++
++            /* Invoke host command to copy from new AD to old AD */
++            err = FmHcPcdCcDoDynamicChange(((t_FmPcd *)h_FmPcd)->h_Hc,
++                                           oldAdAddrOffset, newAdAddrOffset);
++            if (err)
++            {
++                ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst,
++                                             h_NewPointersLst,
++                                             p_AdditionalParams,
++                                             useShadowStructs);
++                RETURN_ERROR(
++                        MAJOR,
++                        err,
++                        ("For part of nodes changes are done - situation is danger"));
++            }
++
++            p_PosOld = LIST_NEXT(p_PosOld);
++        }
++    }
++    return E_OK;
++}
++
++static t_Error DoDynamicChange(
++        t_Handle h_FmPcd, t_List *h_OldPointersLst, t_List *h_NewPointersLst,
++        t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalParams,
++        bool useShadowStructs)
++{
++    t_FmPcdCcNode *p_CcNode =
++            (t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode);
++    t_List *p_PosNew;
++    t_CcNodeInformation *p_CcNodeInfo;
++    t_FmPcdCcNextEngineParams nextEngineParams;
++    t_Handle h_Ad;
++    uint32_t keySize;
++    t_Error err = E_OK;
++    uint8_t numOfModifiedPtr;
++
++    ASSERT_COND(h_FmPcd);
++
++    memset(&nextEngineParams, 0, sizeof(t_FmPcdCcNextEngineParams));
++
++    numOfModifiedPtr = (uint8_t)LIST_NumOfObjs(h_OldPointersLst);
++
++    if (numOfModifiedPtr)
++    {
++
++        p_PosNew = LIST_FIRST(h_NewPointersLst);
++
++        /* Invoke host-command to copy from the new Ad to existing Ads */
++        err = DynamicChangeHc(h_FmPcd, h_OldPointersLst, h_NewPointersLst,
++                              p_AdditionalParams, useShadowStructs);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++
++              if (useShadowStructs)
++              {
++                      /* When the host-command above has ended, the old structures are 'free'and we can update
++                       them by copying from the new shadow structures. */
++                      if (p_CcNode->lclMask)
++                              keySize = (uint32_t)(2 * p_CcNode->ccKeySizeAccExtraction);
++                      else
++                              keySize = p_CcNode->ccKeySizeAccExtraction;
++
++                      MemCpy8(p_AdditionalParams->p_KeysMatchTableOld,
++                                         p_AdditionalParams->p_KeysMatchTableNew,
++                                         p_CcNode->maxNumOfKeys * keySize * sizeof(uint8_t));
++
++                      MemCpy8(
++                                      p_AdditionalParams->p_AdTableOld,
++                                      p_AdditionalParams->p_AdTableNew,
++                                      (uint32_t)((p_CcNode->maxNumOfKeys + 1)
++                                                      * FM_PCD_CC_AD_ENTRY_SIZE));
++
++                      /* Retrieve the address of the allocated Ad */
++                      p_CcNodeInfo = CC_NODE_F_OBJECT(p_PosNew);
++                      h_Ad = p_CcNodeInfo->h_CcNode;
++
++                      /* Build a new Ad that holds the old (now updated) structures */
++                      p_AdditionalParams->p_KeysMatchTableNew =
++                                      p_AdditionalParams->p_KeysMatchTableOld;
++                      p_AdditionalParams->p_AdTableNew = p_AdditionalParams->p_AdTableOld;
++
++                      nextEngineParams.nextEngine = e_FM_PCD_CC;
++                      nextEngineParams.params.ccParams.h_CcNode = (t_Handle)p_CcNode;
++
++                      BuildNewAd(h_Ad, p_AdditionalParams, p_CcNode, &nextEngineParams);
++
++                      /* HC to copy from the new Ad (old updated structures) to current Ad (uses shadow structures) */
++                      err = DynamicChangeHc(h_FmPcd, h_OldPointersLst, h_NewPointersLst,
++                                                                p_AdditionalParams, useShadowStructs);
++                      if (err)
++                              RETURN_ERROR(MAJOR, err, NO_MSG);
++              }
++    }
++
++    err = ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst,
++                                       h_NewPointersLst,
++                                       p_AdditionalParams, useShadowStructs);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++#ifdef FM_CAPWAP_SUPPORT
++static bool IsCapwapApplSpecific(t_Handle h_Node)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_Node;
++    bool isManipForCapwapApplSpecificBuild = FALSE;
++    int i = 0;
++
++    ASSERT_COND(h_Node);
++    /* assumption that this function called only for INDEXED_FLOW_ID - so no miss*/
++    for (i = 0; i < p_CcNode->numOfKeys; i++)
++    {
++        if ( p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip &&
++                FmPcdManipIsCapwapApplSpecific(p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip))
++        {
++            isManipForCapwapApplSpecificBuild = TRUE;
++            break;
++        }
++    }
++    return isManipForCapwapApplSpecificBuild;
++
++}
++#endif /* FM_CAPWAP_SUPPORT */
++
++static t_Error CcUpdateParam(
++        t_Handle h_FmPcd, t_Handle h_PcdParams, t_Handle h_FmPort,
++        t_FmPcdCcKeyAndNextEngineParams *p_CcKeyAndNextEngineParams,
++        uint16_t numOfEntries, t_Handle h_Ad, bool validate, uint16_t level,
++        t_Handle h_FmTree, bool modify)
++{
++    t_FmPcdCcNode *p_CcNode;
++    t_Error err;
++    uint16_t tmp = 0;
++    int i = 0;
++    t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_FmTree;
++
++    level++;
++
++    if (p_CcTree->h_IpReassemblyManip)
++    {
++        err = FmPcdManipUpdate(h_FmPcd, h_PcdParams, h_FmPort,
++                               p_CcTree->h_IpReassemblyManip, NULL, validate,
++                               level, h_FmTree, modify);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    if (p_CcTree->h_CapwapReassemblyManip)
++    {
++        err = FmPcdManipUpdate(h_FmPcd, h_PcdParams, h_FmPort,
++                               p_CcTree->h_CapwapReassemblyManip, NULL, validate,
++                               level, h_FmTree, modify);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    if (numOfEntries)
++    {
++        for (i = 0; i < numOfEntries; i++)
++        {
++            if (i == 0)
++                h_Ad = PTR_MOVE(h_Ad, i*FM_PCD_CC_AD_ENTRY_SIZE);
++            else
++                h_Ad = PTR_MOVE(h_Ad, FM_PCD_CC_AD_ENTRY_SIZE);
++
++            if (p_CcKeyAndNextEngineParams[i].nextEngineParams.nextEngine
++                    == e_FM_PCD_CC)
++            {
++                p_CcNode =
++                        p_CcKeyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode;
++                ASSERT_COND(p_CcNode);
++
++                if (p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip)
++                {
++                    err =
++                            FmPcdManipUpdate(
++                                    h_FmPcd,
++                                    NULL,
++                                    h_FmPort,
++                                    p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip,
++                                    h_Ad, validate, level, h_FmTree, modify);
++                    if (err)
++                        RETURN_ERROR(MAJOR, err, NO_MSG);
++                }
++
++                if (p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine
++                        != e_FM_PCD_INVALID)
++                    tmp = (uint8_t)(p_CcNode->numOfKeys + 1);
++                else
++                    tmp = p_CcNode->numOfKeys;
++
++                err = CcUpdateParam(h_FmPcd, h_PcdParams, h_FmPort,
++                                    p_CcNode->keyAndNextEngineParams, tmp,
++                                    p_CcNode->h_AdTable, validate, level,
++                                    h_FmTree, modify);
++                if (err)
++                    RETURN_ERROR(MAJOR, err, NO_MSG);
++            }
++            else
++            {
++                if (p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip)
++                {
++                    err =
++                            FmPcdManipUpdate(
++                                    h_FmPcd,
++                                    NULL,
++                                    h_FmPort,
++                                    p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip,
++                                    h_Ad, validate, level, h_FmTree, modify);
++                    if (err)
++                        RETURN_ERROR(MAJOR, err, NO_MSG);
++                }
++            }
++        }
++    }
++
++    return E_OK;
++}
++
++static ccPrivateInfo_t IcDefineCode(t_FmPcdCcNodeParams *p_CcNodeParam)
++{
++    switch (p_CcNodeParam->extractCcParams.extractNonHdr.action)
++    {
++        case (e_FM_PCD_ACTION_EXACT_MATCH):
++            switch (p_CcNodeParam->extractCcParams.extractNonHdr.src)
++            {
++                case (e_FM_PCD_EXTRACT_FROM_KEY):
++                    return CC_PRIVATE_INFO_IC_KEY_EXACT_MATCH;
++                case (e_FM_PCD_EXTRACT_FROM_HASH):
++                    return CC_PRIVATE_INFO_IC_HASH_EXACT_MATCH;
++                default:
++                    return CC_PRIVATE_INFO_NONE;
++            }
++
++        case (e_FM_PCD_ACTION_INDEXED_LOOKUP):
++            switch (p_CcNodeParam->extractCcParams.extractNonHdr.src)
++            {
++                case (e_FM_PCD_EXTRACT_FROM_HASH):
++                    return CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP;
++                case (e_FM_PCD_EXTRACT_FROM_FLOW_ID):
++                    return CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP;
++                default:
++                    return CC_PRIVATE_INFO_NONE;
++            }
++
++        default:
++            break;
++    }
++
++    return CC_PRIVATE_INFO_NONE;
++}
++
++static t_CcNodeInformation * DequeueAdditionalInfoFromRelevantLst(
++        t_List *p_List)
++{
++    t_CcNodeInformation *p_CcNodeInfo = NULL;
++
++    if (!LIST_IsEmpty(p_List))
++    {
++        p_CcNodeInfo = CC_NODE_F_OBJECT(p_List->p_Next);
++        LIST_DelAndInit(&p_CcNodeInfo->node);
++    }
++
++    return p_CcNodeInfo;
++}
++
++void ReleaseLst(t_List *p_List)
++{
++    t_CcNodeInformation *p_CcNodeInfo = NULL;
++
++    if (!LIST_IsEmpty(p_List))
++    {
++        p_CcNodeInfo = DequeueAdditionalInfoFromRelevantLst(p_List);
++        while (p_CcNodeInfo)
++        {
++            XX_Free(p_CcNodeInfo);
++            p_CcNodeInfo = DequeueAdditionalInfoFromRelevantLst(p_List);
++        }
++    }
++
++    LIST_Del(p_List);
++}
++
++static void DeleteNode(t_FmPcdCcNode *p_CcNode)
++{
++    uint32_t i;
++
++    if (!p_CcNode)
++        return;
++
++    if (p_CcNode->p_GlblMask)
++    {
++        XX_Free(p_CcNode->p_GlblMask);
++        p_CcNode->p_GlblMask = NULL;
++    }
++
++    if (p_CcNode->h_KeysMatchTable)
++    {
++        FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd),
++                         p_CcNode->h_KeysMatchTable);
++        p_CcNode->h_KeysMatchTable = NULL;
++    }
++
++    if (p_CcNode->h_AdTable)
++    {
++        FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd),
++                         p_CcNode->h_AdTable);
++        p_CcNode->h_AdTable = NULL;
++    }
++
++    if (p_CcNode->h_Ad)
++    {
++        FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd),
++                         p_CcNode->h_Ad);
++        p_CcNode->h_Ad = NULL;
++        p_CcNode->h_TmpAd = NULL;
++    }
++
++    if (p_CcNode->h_StatsFLRs)
++    {
++        FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd),
++                         p_CcNode->h_StatsFLRs);
++        p_CcNode->h_StatsFLRs = NULL;
++    }
++
++    if (p_CcNode->h_Spinlock)
++    {
++        XX_FreeSpinlock(p_CcNode->h_Spinlock);
++        p_CcNode->h_Spinlock = NULL;
++    }
++
++    /* Restore the original counters pointer instead of the mutual pointer (mutual to all hash buckets) */
++    if (p_CcNode->isHashBucket
++            && (p_CcNode->statisticsMode != e_FM_PCD_CC_STATS_MODE_NONE))
++        p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].p_StatsObj->h_StatsCounters =
++                p_CcNode->h_PrivMissStatsCounters;
++
++    /* Releasing all currently used statistics objects, including 'miss' entry */
++    for (i = 0; i < p_CcNode->numOfKeys + 1; i++)
++        if (p_CcNode->keyAndNextEngineParams[i].p_StatsObj)
++            PutStatsObj(p_CcNode,
++                        p_CcNode->keyAndNextEngineParams[i].p_StatsObj);
++
++    if (!LIST_IsEmpty(&p_CcNode->availableStatsLst))
++    {
++        t_Handle h_FmMuram = FmPcdGetMuramHandle(p_CcNode->h_FmPcd);
++        ASSERT_COND(h_FmMuram);
++
++        FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram);
++    }
++
++    LIST_Del(&p_CcNode->availableStatsLst);
++
++      ReleaseLst(&p_CcNode->availableStatsLst);
++    ReleaseLst(&p_CcNode->ccPrevNodesLst);
++    ReleaseLst(&p_CcNode->ccTreeIdLst);
++    ReleaseLst(&p_CcNode->ccTreesLst);
++
++    XX_Free(p_CcNode);
++}
++
++static void DeleteTree(t_FmPcdCcTree *p_FmPcdTree, t_FmPcd *p_FmPcd)
++{
++    if (p_FmPcdTree)
++    {
++        if (p_FmPcdTree->ccTreeBaseAddr)
++        {
++            FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_FmPcd),
++                             UINT_TO_PTR(p_FmPcdTree->ccTreeBaseAddr));
++            p_FmPcdTree->ccTreeBaseAddr = 0;
++        }
++
++        ReleaseLst(&p_FmPcdTree->fmPortsLst);
++
++        XX_Free(p_FmPcdTree);
++    }
++}
++
++static void GetCcExtractKeySize(uint8_t parseCodeRealSize,
++                                uint8_t *parseCodeCcSize)
++{
++    if ((parseCodeRealSize > 0) && (parseCodeRealSize < 2))
++        *parseCodeCcSize = 1;
++    else
++        if (parseCodeRealSize == 2)
++            *parseCodeCcSize = 2;
++        else
++            if ((parseCodeRealSize > 2) && (parseCodeRealSize <= 4))
++                *parseCodeCcSize = 4;
++            else
++                if ((parseCodeRealSize > 4) && (parseCodeRealSize <= 8))
++                    *parseCodeCcSize = 8;
++                else
++                    if ((parseCodeRealSize > 8) && (parseCodeRealSize <= 16))
++                        *parseCodeCcSize = 16;
++                    else
++                        if ((parseCodeRealSize > 16)
++                                && (parseCodeRealSize <= 24))
++                            *parseCodeCcSize = 24;
++                        else
++                            if ((parseCodeRealSize > 24)
++                                    && (parseCodeRealSize <= 32))
++                                *parseCodeCcSize = 32;
++                            else
++                                if ((parseCodeRealSize > 32)
++                                        && (parseCodeRealSize <= 40))
++                                    *parseCodeCcSize = 40;
++                                else
++                                    if ((parseCodeRealSize > 40)
++                                            && (parseCodeRealSize <= 48))
++                                        *parseCodeCcSize = 48;
++                                    else
++                                        if ((parseCodeRealSize > 48)
++                                                && (parseCodeRealSize <= 56))
++                                            *parseCodeCcSize = 56;
++                                        else
++                                            *parseCodeCcSize = 0;
++}
++
++static void GetSizeHeaderField(e_NetHeaderType hdr, t_FmPcdFields field,
++                                     uint8_t *parseCodeRealSize)
++{
++    switch (hdr)
++    {
++        case (HEADER_TYPE_ETH):
++            switch (field.eth)
++            {
++                case (NET_HEADER_FIELD_ETH_DA):
++                    *parseCodeRealSize = 6;
++                    break;
++
++                case (NET_HEADER_FIELD_ETH_SA):
++                    *parseCodeRealSize = 6;
++                    break;
++
++                case (NET_HEADER_FIELD_ETH_TYPE):
++                    *parseCodeRealSize = 2;
++                    break;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported1"));
++                    *parseCodeRealSize = CC_SIZE_ILLEGAL;
++                    break;
++            }
++            break;
++
++        case (HEADER_TYPE_PPPoE):
++            switch (field.pppoe)
++            {
++                case (NET_HEADER_FIELD_PPPoE_PID):
++                    *parseCodeRealSize = 2;
++                    break;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported1"));
++                    *parseCodeRealSize = CC_SIZE_ILLEGAL;
++                    break;
++            }
++            break;
++
++        case (HEADER_TYPE_VLAN):
++            switch (field.vlan)
++            {
++                case (NET_HEADER_FIELD_VLAN_TCI):
++                    *parseCodeRealSize = 2;
++                    break;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported2"));
++                    *parseCodeRealSize = CC_SIZE_ILLEGAL;
++                    break;
++            }
++            break;
++
++        case (HEADER_TYPE_MPLS):
++            switch (field.mpls)
++            {
++                case (NET_HEADER_FIELD_MPLS_LABEL_STACK):
++                    *parseCodeRealSize = 4;
++                    break;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported3"));
++                    *parseCodeRealSize = CC_SIZE_ILLEGAL;
++                    break;
++            }
++            break;
++
++        case (HEADER_TYPE_IPv4):
++            switch (field.ipv4)
++            {
++                case (NET_HEADER_FIELD_IPv4_DST_IP):
++                case (NET_HEADER_FIELD_IPv4_SRC_IP):
++                    *parseCodeRealSize = 4;
++                    break;
++
++                case (NET_HEADER_FIELD_IPv4_TOS):
++                case (NET_HEADER_FIELD_IPv4_PROTO):
++                    *parseCodeRealSize = 1;
++                    break;
++
++                case (NET_HEADER_FIELD_IPv4_DST_IP
++                        | NET_HEADER_FIELD_IPv4_SRC_IP):
++                    *parseCodeRealSize = 8;
++                    break;
++
++                case (NET_HEADER_FIELD_IPv4_TTL):
++                    *parseCodeRealSize = 1;
++                    break;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported4"));
++                    *parseCodeRealSize = CC_SIZE_ILLEGAL;
++                    break;
++            }
++            break;
++
++        case (HEADER_TYPE_IPv6):
++            switch (field.ipv6)
++            {
++                case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL
++                        | NET_HEADER_FIELD_IPv6_TC):
++                    *parseCodeRealSize = 4;
++                    break;
++
++                case (NET_HEADER_FIELD_IPv6_NEXT_HDR):
++                case (NET_HEADER_FIELD_IPv6_HOP_LIMIT):
++                    *parseCodeRealSize = 1;
++                    break;
++
++                case (NET_HEADER_FIELD_IPv6_DST_IP):
++                case (NET_HEADER_FIELD_IPv6_SRC_IP):
++                    *parseCodeRealSize = 16;
++                    break;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported5"));
++                    *parseCodeRealSize = CC_SIZE_ILLEGAL;
++                    break;
++            }
++            break;
++
++        case (HEADER_TYPE_IP):
++            switch (field.ip)
++            {
++                case (NET_HEADER_FIELD_IP_DSCP):
++                case (NET_HEADER_FIELD_IP_PROTO):
++                    *parseCodeRealSize = 1;
++                    break;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported5"));
++                    *parseCodeRealSize = CC_SIZE_ILLEGAL;
++                    break;
++            }
++            break;
++
++        case (HEADER_TYPE_GRE):
++            switch (field.gre)
++            {
++                case (NET_HEADER_FIELD_GRE_TYPE):
++                    *parseCodeRealSize = 2;
++                    break;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported6"));
++                    *parseCodeRealSize = CC_SIZE_ILLEGAL;
++                    break;
++            }
++            break;
++
++        case (HEADER_TYPE_MINENCAP):
++            switch (field.minencap)
++            {
++                case (NET_HEADER_FIELD_MINENCAP_TYPE):
++                    *parseCodeRealSize = 1;
++                    break;
++
++                case (NET_HEADER_FIELD_MINENCAP_DST_IP):
++                case (NET_HEADER_FIELD_MINENCAP_SRC_IP):
++                    *parseCodeRealSize = 4;
++                    break;
++
++                case (NET_HEADER_FIELD_MINENCAP_SRC_IP
++                        | NET_HEADER_FIELD_MINENCAP_DST_IP):
++                    *parseCodeRealSize = 8;
++                    break;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported7"));
++                    *parseCodeRealSize = CC_SIZE_ILLEGAL;
++                    break;
++            }
++            break;
++
++        case (HEADER_TYPE_TCP):
++            switch (field.tcp)
++            {
++                case (NET_HEADER_FIELD_TCP_PORT_SRC):
++                case (NET_HEADER_FIELD_TCP_PORT_DST):
++                    *parseCodeRealSize = 2;
++                    break;
++
++                case (NET_HEADER_FIELD_TCP_PORT_SRC
++                        | NET_HEADER_FIELD_TCP_PORT_DST):
++                    *parseCodeRealSize = 4;
++                    break;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported8"));
++                    *parseCodeRealSize = CC_SIZE_ILLEGAL;
++                    break;
++            }
++            break;
++
++        case (HEADER_TYPE_UDP):
++            switch (field.udp)
++            {
++                case (NET_HEADER_FIELD_UDP_PORT_SRC):
++                case (NET_HEADER_FIELD_UDP_PORT_DST):
++                    *parseCodeRealSize = 2;
++                    break;
++
++                case (NET_HEADER_FIELD_UDP_PORT_SRC
++                        | NET_HEADER_FIELD_UDP_PORT_DST):
++                    *parseCodeRealSize = 4;
++                    break;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported9"));
++                    *parseCodeRealSize = CC_SIZE_ILLEGAL;
++                    break;
++            }
++            break;
++
++        default:
++            REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported10"));
++            *parseCodeRealSize = CC_SIZE_ILLEGAL;
++            break;
++    }
++}
++
++t_Error ValidateNextEngineParams(
++        t_Handle h_FmPcd, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams,
++        e_FmPcdCcStatsMode statsMode)
++{
++    uint16_t absoluteProfileId;
++    t_Error err = E_OK;
++    uint8_t relativeSchemeId;
++
++    if ((statsMode == e_FM_PCD_CC_STATS_MODE_NONE)
++            && (p_FmPcdCcNextEngineParams->statisticsEn))
++        RETURN_ERROR(
++                MAJOR,
++                E_CONFLICT,
++                ("Statistics are requested for a key, but statistics mode was set"
++                "to 'NONE' upon initialization"));
++
++    switch (p_FmPcdCcNextEngineParams->nextEngine)
++    {
++        case (e_FM_PCD_INVALID):
++            err = E_NOT_SUPPORTED;
++            break;
++
++        case (e_FM_PCD_DONE):
++            if ((p_FmPcdCcNextEngineParams->params.enqueueParams.action
++                    == e_FM_PCD_ENQ_FRAME)
++                    && p_FmPcdCcNextEngineParams->params.enqueueParams.overrideFqid)
++            {
++                if (!p_FmPcdCcNextEngineParams->params.enqueueParams.newFqid)
++                    RETURN_ERROR(
++                            MAJOR,
++                            E_CONFLICT,
++                            ("When overrideFqid is set, newFqid must not be zero"));
++                if (p_FmPcdCcNextEngineParams->params.enqueueParams.newFqid
++                        & ~0x00FFFFFF)
++                    RETURN_ERROR(
++                            MAJOR, E_INVALID_VALUE,
++                            ("fqidForCtrlFlow must be between 1 and 2^24-1"));
++            }
++            break;
++
++        case (e_FM_PCD_KG):
++            relativeSchemeId =
++                    FmPcdKgGetRelativeSchemeId(
++                            h_FmPcd,
++                            FmPcdKgGetSchemeId(
++                                    p_FmPcdCcNextEngineParams->params.kgParams.h_DirectScheme));
++            if (relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES)
++                RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
++            if (!FmPcdKgIsSchemeValidSw(
++                    p_FmPcdCcNextEngineParams->params.kgParams.h_DirectScheme))
++                RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                             ("not valid schemeIndex in KG next engine param"));
++            if (!KgIsSchemeAlwaysDirect(h_FmPcd, relativeSchemeId))
++                RETURN_ERROR(
++                        MAJOR,
++                        E_INVALID_STATE,
++                        ("CC Node may point only to a scheme that is always direct."));
++            break;
++
++        case (e_FM_PCD_PLCR):
++            if (p_FmPcdCcNextEngineParams->params.plcrParams.overrideParams)
++            {
++                /* if private policer profile, it may be uninitialized yet, therefore no checks are done at this stage */
++                if (p_FmPcdCcNextEngineParams->params.plcrParams.sharedProfile)
++                {
++                    err =
++                            FmPcdPlcrGetAbsoluteIdByProfileParams(
++                                    h_FmPcd,
++                                    e_FM_PCD_PLCR_SHARED,
++                                    NULL,
++                                    p_FmPcdCcNextEngineParams->params.plcrParams.newRelativeProfileId,
++                                    &absoluteProfileId);
++                    if (err)
++                        RETURN_ERROR(MAJOR, err,
++                                     ("Shared profile offset is out of range"));
++                    if (!FmPcdPlcrIsProfileValid(h_FmPcd, absoluteProfileId))
++                        RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                                     ("Invalid profile"));
++                }
++            }
++            break;
++
++        case (e_FM_PCD_HASH):
++            p_FmPcdCcNextEngineParams->nextEngine = e_FM_PCD_CC;
++        case (e_FM_PCD_CC):
++            if (!p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode)
++                RETURN_ERROR(MAJOR, E_NULL_POINTER,
++                             ("handler to next Node is NULL"));
++            break;
++
++#if (DPAA_VERSION >= 11)
++        case (e_FM_PCD_FR):
++            if (!p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic)
++                err = E_NOT_SUPPORTED;
++            break;
++#endif /* (DPAA_VERSION >= 11) */
++
++        default:
++            RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                         ("Next engine is not correct"));
++    }
++
++
++    return err;
++}
++
++static uint8_t GetGenParseCode(e_FmPcdExtractFrom src,
++                               uint32_t offset, bool glblMask,
++                               uint8_t *parseArrayOffset, bool fromIc,
++                               ccPrivateInfo_t icCode)
++{
++    if (!fromIc)
++    {
++        switch (src)
++        {
++            case (e_FM_PCD_EXTRACT_FROM_FRAME_START):
++                if (glblMask)
++                    return CC_PC_GENERIC_WITH_MASK;
++                else
++                    return CC_PC_GENERIC_WITHOUT_MASK;
++
++            case (e_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE):
++                *parseArrayOffset = CC_PC_PR_NEXT_HEADER_OFFSET;
++                if (offset)
++                    return CC_PR_OFFSET;
++                else
++                    return CC_PR_WITHOUT_OFFSET;
++
++            default:
++                REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 'extract from' src"));
++                return CC_PC_ILLEGAL;
++        }
++    }
++    else
++    {
++        switch (icCode)
++        {
++            case (CC_PRIVATE_INFO_IC_KEY_EXACT_MATCH):
++                *parseArrayOffset = 0x50;
++                return CC_PC_GENERIC_IC_GMASK;
++
++            case (CC_PRIVATE_INFO_IC_HASH_EXACT_MATCH):
++                *parseArrayOffset = 0x48;
++                return CC_PC_GENERIC_IC_GMASK;
++
++            case (CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP):
++                *parseArrayOffset = 0x48;
++                return CC_PC_GENERIC_IC_HASH_INDEXED;
++
++            case (CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP):
++                *parseArrayOffset = 0x16;
++                return CC_PC_GENERIC_IC_HASH_INDEXED;
++
++            default:
++                REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 'extract from' src"));
++                break;
++        }
++    }
++
++    return CC_PC_ILLEGAL;
++}
++
++static uint8_t GetFullFieldParseCode(e_NetHeaderType hdr, e_FmPcdHdrIndex index,
++                                     t_FmPcdFields field)
++{
++    switch (hdr)
++    {
++        case (HEADER_TYPE_NONE):
++            ASSERT_COND(FALSE);
++            return CC_PC_ILLEGAL;
++
++        case (HEADER_TYPE_ETH):
++            switch (field.eth)
++            {
++                case (NET_HEADER_FIELD_ETH_DA):
++                    return CC_PC_FF_MACDST;
++                case (NET_HEADER_FIELD_ETH_SA):
++                    return CC_PC_FF_MACSRC;
++                case (NET_HEADER_FIELD_ETH_TYPE):
++                    return CC_PC_FF_ETYPE;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return CC_PC_ILLEGAL;
++            }
++
++        case (HEADER_TYPE_VLAN):
++            switch (field.vlan)
++            {
++                case (NET_HEADER_FIELD_VLAN_TCI):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE)
++                            || (index == e_FM_PCD_HDR_INDEX_1))
++                        return CC_PC_FF_TCI1;
++                    if (index == e_FM_PCD_HDR_INDEX_LAST)
++                        return CC_PC_FF_TCI2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return CC_PC_ILLEGAL;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return CC_PC_ILLEGAL;
++            }
++
++        case (HEADER_TYPE_MPLS):
++            switch (field.mpls)
++            {
++                case (NET_HEADER_FIELD_MPLS_LABEL_STACK):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE)
++                            || (index == e_FM_PCD_HDR_INDEX_1))
++                        return CC_PC_FF_MPLS1;
++                    if (index == e_FM_PCD_HDR_INDEX_LAST)
++                        return CC_PC_FF_MPLS_LAST;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS index"));
++                    return CC_PC_ILLEGAL;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return CC_PC_ILLEGAL;
++            }
++
++        case (HEADER_TYPE_IPv4):
++            switch (field.ipv4)
++            {
++                case (NET_HEADER_FIELD_IPv4_DST_IP):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE)
++                            || (index == e_FM_PCD_HDR_INDEX_1))
++                        return CC_PC_FF_IPV4DST1;
++                    if (index == e_FM_PCD_HDR_INDEX_2)
++                        return CC_PC_FF_IPV4DST2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
++                    return CC_PC_ILLEGAL;
++                case (NET_HEADER_FIELD_IPv4_TOS):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE)
++                            || (index == e_FM_PCD_HDR_INDEX_1))
++                        return CC_PC_FF_IPV4IPTOS_TC1;
++                    if (index == e_FM_PCD_HDR_INDEX_2)
++                        return CC_PC_FF_IPV4IPTOS_TC2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
++                    return CC_PC_ILLEGAL;
++                case (NET_HEADER_FIELD_IPv4_PROTO):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE)
++                            || (index == e_FM_PCD_HDR_INDEX_1))
++                        return CC_PC_FF_IPV4PTYPE1;
++                    if (index == e_FM_PCD_HDR_INDEX_2)
++                        return CC_PC_FF_IPV4PTYPE2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
++                    return CC_PC_ILLEGAL;
++                case (NET_HEADER_FIELD_IPv4_SRC_IP):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE)
++                            || (index == e_FM_PCD_HDR_INDEX_1))
++                        return CC_PC_FF_IPV4SRC1;
++                    if (index == e_FM_PCD_HDR_INDEX_2)
++                        return CC_PC_FF_IPV4SRC2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
++                    return CC_PC_ILLEGAL;
++                case (NET_HEADER_FIELD_IPv4_SRC_IP
++                        | NET_HEADER_FIELD_IPv4_DST_IP):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE)
++                            || (index == e_FM_PCD_HDR_INDEX_1))
++                        return CC_PC_FF_IPV4SRC1_IPV4DST1;
++                    if (index == e_FM_PCD_HDR_INDEX_2)
++                        return CC_PC_FF_IPV4SRC2_IPV4DST2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
++                    return CC_PC_ILLEGAL;
++                case (NET_HEADER_FIELD_IPv4_TTL):
++                    return CC_PC_FF_IPV4TTL;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return CC_PC_ILLEGAL;
++            }
++
++        case (HEADER_TYPE_IPv6):
++            switch (field.ipv6)
++            {
++                case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL
++                        | NET_HEADER_FIELD_IPv6_TC):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE)
++                            || (index == e_FM_PCD_HDR_INDEX_1))
++                        return CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1;
++                    if (index == e_FM_PCD_HDR_INDEX_2)
++                        return CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
++                    return CC_PC_ILLEGAL;
++
++                case (NET_HEADER_FIELD_IPv6_NEXT_HDR):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE)
++                            || (index == e_FM_PCD_HDR_INDEX_1))
++                        return CC_PC_FF_IPV6PTYPE1;
++                    if (index == e_FM_PCD_HDR_INDEX_2)
++                        return CC_PC_FF_IPV6PTYPE2;
++                    if (index == e_FM_PCD_HDR_INDEX_LAST)
++                        return CC_PC_FF_IPPID;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
++                    return CC_PC_ILLEGAL;
++
++                case (NET_HEADER_FIELD_IPv6_DST_IP):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE)
++                            || (index == e_FM_PCD_HDR_INDEX_1))
++                        return CC_PC_FF_IPV6DST1;
++                    if (index == e_FM_PCD_HDR_INDEX_2)
++                        return CC_PC_FF_IPV6DST2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
++                    return CC_PC_ILLEGAL;
++
++                case (NET_HEADER_FIELD_IPv6_SRC_IP):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE)
++                            || (index == e_FM_PCD_HDR_INDEX_1))
++                        return CC_PC_FF_IPV6SRC1;
++                    if (index == e_FM_PCD_HDR_INDEX_2)
++                        return CC_PC_FF_IPV6SRC2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
++                    return CC_PC_ILLEGAL;
++
++                case (NET_HEADER_FIELD_IPv6_HOP_LIMIT):
++                    return CC_PC_FF_IPV6HOP_LIMIT;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return CC_PC_ILLEGAL;
++            }
++
++        case (HEADER_TYPE_IP):
++            switch (field.ip)
++            {
++                case (NET_HEADER_FIELD_IP_DSCP):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE)
++                            || (index == e_FM_PCD_HDR_INDEX_1))
++                        return CC_PC_FF_IPDSCP;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP index"));
++                    return CC_PC_ILLEGAL;
++
++                case (NET_HEADER_FIELD_IP_PROTO):
++                    if (index == e_FM_PCD_HDR_INDEX_LAST)
++                        return CC_PC_FF_IPPID;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP index"));
++                    return CC_PC_ILLEGAL;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return CC_PC_ILLEGAL;
++            }
++
++        case (HEADER_TYPE_GRE):
++            switch (field.gre)
++            {
++                case (NET_HEADER_FIELD_GRE_TYPE):
++                    return CC_PC_FF_GREPTYPE;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return CC_PC_ILLEGAL;
++            }
++
++        case (HEADER_TYPE_MINENCAP):
++            switch (field.minencap)
++            {
++                case (NET_HEADER_FIELD_MINENCAP_TYPE):
++                    return CC_PC_FF_MINENCAP_PTYPE;
++
++                case (NET_HEADER_FIELD_MINENCAP_DST_IP):
++                    return CC_PC_FF_MINENCAP_IPDST;
++
++                case (NET_HEADER_FIELD_MINENCAP_SRC_IP):
++                    return CC_PC_FF_MINENCAP_IPSRC;
++
++                case (NET_HEADER_FIELD_MINENCAP_SRC_IP
++                        | NET_HEADER_FIELD_MINENCAP_DST_IP):
++                    return CC_PC_FF_MINENCAP_IPSRC_IPDST;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return CC_PC_ILLEGAL;
++            }
++
++        case (HEADER_TYPE_TCP):
++            switch (field.tcp)
++            {
++                case (NET_HEADER_FIELD_TCP_PORT_SRC):
++                    return CC_PC_FF_L4PSRC;
++
++                case (NET_HEADER_FIELD_TCP_PORT_DST):
++                    return CC_PC_FF_L4PDST;
++
++                case (NET_HEADER_FIELD_TCP_PORT_DST
++                        | NET_HEADER_FIELD_TCP_PORT_SRC):
++                    return CC_PC_FF_L4PSRC_L4PDST;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return CC_PC_ILLEGAL;
++            }
++
++        case (HEADER_TYPE_PPPoE):
++            switch (field.pppoe)
++            {
++                case (NET_HEADER_FIELD_PPPoE_PID):
++                    return CC_PC_FF_PPPPID;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return CC_PC_ILLEGAL;
++            }
++
++        case (HEADER_TYPE_UDP):
++            switch (field.udp)
++            {
++                case (NET_HEADER_FIELD_UDP_PORT_SRC):
++                    return CC_PC_FF_L4PSRC;
++
++                case (NET_HEADER_FIELD_UDP_PORT_DST):
++                    return CC_PC_FF_L4PDST;
++
++                case (NET_HEADER_FIELD_UDP_PORT_DST
++                        | NET_HEADER_FIELD_UDP_PORT_SRC):
++                    return CC_PC_FF_L4PSRC_L4PDST;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return CC_PC_ILLEGAL;
++            }
++
++        default:
++            REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++            return CC_PC_ILLEGAL;
++    }
++}
++
++static uint8_t GetPrParseCode(e_NetHeaderType hdr, e_FmPcdHdrIndex hdrIndex,
++                              uint32_t offset, bool glblMask,
++                              uint8_t *parseArrayOffset)
++{
++    bool offsetRelevant = FALSE;
++
++    if (offset)
++        offsetRelevant = TRUE;
++
++    switch (hdr)
++    {
++        case (HEADER_TYPE_NONE):
++            ASSERT_COND(FALSE);
++            return CC_PC_ILLEGAL;
++
++        case (HEADER_TYPE_ETH):
++            *parseArrayOffset = (uint8_t)CC_PC_PR_ETH_OFFSET;
++            break;
++
++        case (HEADER_TYPE_USER_DEFINED_SHIM1):
++            if (offset || glblMask)
++                *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM1_OFFSET;
++            else
++                return CC_PC_PR_SHIM1;
++            break;
++
++        case (HEADER_TYPE_USER_DEFINED_SHIM2):
++            if (offset || glblMask)
++                *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM2_OFFSET;
++            else
++                return CC_PC_PR_SHIM2;
++            break;
++
++        case (HEADER_TYPE_LLC_SNAP):
++            *parseArrayOffset = CC_PC_PR_USER_LLC_SNAP_OFFSET;
++            break;
++
++        case (HEADER_TYPE_PPPoE):
++            *parseArrayOffset = CC_PC_PR_PPPOE_OFFSET;
++            break;
++
++        case (HEADER_TYPE_MPLS):
++            if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE)
++                    || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
++                *parseArrayOffset = CC_PC_PR_MPLS1_OFFSET;
++            else
++                if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
++                    *parseArrayOffset = CC_PC_PR_MPLS_LAST_OFFSET;
++                else
++                {
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS header index"));
++                    return CC_PC_ILLEGAL;
++                }
++            break;
++
++        case (HEADER_TYPE_IPv4):
++        case (HEADER_TYPE_IPv6):
++            if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE)
++                    || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
++                *parseArrayOffset = CC_PC_PR_IP1_OFFSET;
++            else
++                if (hdrIndex == e_FM_PCD_HDR_INDEX_2)
++                    *parseArrayOffset = CC_PC_PR_IP_LAST_OFFSET;
++                else
++                {
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP header index"));
++                    return CC_PC_ILLEGAL;
++                }
++            break;
++
++        case (HEADER_TYPE_MINENCAP):
++            *parseArrayOffset = CC_PC_PR_MINENC_OFFSET;
++            break;
++
++        case (HEADER_TYPE_GRE):
++            *parseArrayOffset = CC_PC_PR_GRE_OFFSET;
++            break;
++
++        case (HEADER_TYPE_TCP):
++        case (HEADER_TYPE_UDP):
++        case (HEADER_TYPE_IPSEC_AH):
++        case (HEADER_TYPE_IPSEC_ESP):
++        case (HEADER_TYPE_DCCP):
++        case (HEADER_TYPE_SCTP):
++            *parseArrayOffset = CC_PC_PR_L4_OFFSET;
++            break;
++
++        default:
++            REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP header for this type of operation"));
++            return CC_PC_ILLEGAL;
++    }
++
++    if (offsetRelevant)
++        return CC_PR_OFFSET;
++    else
++        return CC_PR_WITHOUT_OFFSET;
++}
++
++static uint8_t GetFieldParseCode(e_NetHeaderType hdr, t_FmPcdFields field,
++                                 uint32_t offset, uint8_t *parseArrayOffset,
++                                 e_FmPcdHdrIndex hdrIndex)
++{
++    bool offsetRelevant = FALSE;
++
++    if (offset)
++        offsetRelevant = TRUE;
++
++    switch (hdr)
++    {
++        case (HEADER_TYPE_NONE):
++            ASSERT_COND(FALSE);
++                break;
++        case (HEADER_TYPE_ETH):
++            switch (field.eth)
++            {
++                case (NET_HEADER_FIELD_ETH_TYPE):
++                    *parseArrayOffset = CC_PC_PR_ETYPE_LAST_OFFSET;
++                    break;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return CC_PC_ILLEGAL;
++            }
++            break;
++
++        case (HEADER_TYPE_VLAN):
++            switch (field.vlan)
++            {
++                case (NET_HEADER_FIELD_VLAN_TCI):
++                    if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE)
++                            || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
++                        *parseArrayOffset = CC_PC_PR_VLAN1_OFFSET;
++                    else
++                        if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
++                            *parseArrayOffset = CC_PC_PR_VLAN2_OFFSET;
++                    break;
++
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return CC_PC_ILLEGAL;
++            }
++            break;
++
++        default:
++            REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal header "));
++            return CC_PC_ILLEGAL;
++    }
++
++    if (offsetRelevant)
++        return CC_PR_OFFSET;
++    else
++        return CC_PR_WITHOUT_OFFSET;
++}
++
++static void FillAdOfTypeResult(t_Handle h_Ad,
++                               t_FmPcdCcStatsParams *p_FmPcdCcStatsParams,
++                               t_FmPcd *p_FmPcd,
++                               t_FmPcdCcNextEngineParams *p_CcNextEngineParams)
++{
++    t_AdOfTypeResult *p_AdResult = (t_AdOfTypeResult *)h_Ad;
++    t_Handle h_TmpAd;
++    uint32_t tmp = 0, tmpNia = 0;
++    uint16_t profileId;
++    t_Handle p_AdNewPtr = NULL;
++    t_Error err = E_OK;
++
++    /* There are 3 cases handled in this routine of building a "result" type AD.
++     * Case 1: No Manip. The action descriptor is built within the match table.
++     * Case 2: Manip exists. A new AD is created - p_AdNewPtr. It is initialized
++     *         either in the FmPcdManipUpdateAdResultForCc routine or it was already
++     *         initialized and returned here.
++     *         p_AdResult (within the match table) will be initialized after
++     *         this routine returns and point to the existing AD.
++     * Case 3: Manip exists. The action descriptor is built within the match table.
++     *         FmPcdManipUpdateAdResultForCc returns a NULL p_AdNewPtr.
++     *
++     * If statistics were enabled and the statistics mode of this node requires
++     * a statistics Ad, it will be placed after the result Ad and before the
++     * manip Ad, if manip Ad exists here.
++     */
++
++    /* As default, the "new" ptr is the current one. i.e. the content of the result
++     * AD will be written into the match table itself (case (1))*/
++    p_AdNewPtr = p_AdResult;
++
++    /* Initialize an action descriptor, if current statistics mode requires an Ad */
++    if (p_FmPcdCcStatsParams)
++    {
++        ASSERT_COND(p_FmPcdCcStatsParams->h_StatsAd);
++        ASSERT_COND(p_FmPcdCcStatsParams->h_StatsCounters);
++
++        /* Swapping addresses between statistics Ad and the current lookup AD addresses */
++        h_TmpAd = p_FmPcdCcStatsParams->h_StatsAd;
++        p_FmPcdCcStatsParams->h_StatsAd = h_Ad;
++        h_Ad = h_TmpAd;
++
++        p_AdNewPtr = h_Ad;
++        p_AdResult = h_Ad;
++
++        /* Init statistics Ad and connect current lookup AD as 'next action' from statistics Ad */
++        UpdateStatsAd(p_FmPcdCcStatsParams, h_Ad, p_FmPcd->physicalMuramBase);
++    }
++
++    /* Create manip and return p_AdNewPtr to either a new descriptor or NULL */
++    if (p_CcNextEngineParams->h_Manip)
++        FmPcdManipUpdateAdResultForCc(p_CcNextEngineParams->h_Manip,
++                                      p_CcNextEngineParams, h_Ad, &p_AdNewPtr);
++
++    /* if (p_AdNewPtr = NULL) --> Done. (case (3)) */
++    if (p_AdNewPtr)
++    {
++        /* case (1) and (2) */
++        switch (p_CcNextEngineParams->nextEngine)
++        {
++            case (e_FM_PCD_DONE):
++                if (p_CcNextEngineParams->params.enqueueParams.action
++                        == e_FM_PCD_ENQ_FRAME)
++                {
++                    if (p_CcNextEngineParams->params.enqueueParams.overrideFqid)
++                    {
++                        tmp = FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE;
++                        tmp |=
++                                p_CcNextEngineParams->params.enqueueParams.newFqid;
++#if (DPAA_VERSION >= 11)
++                        tmp |=
++                                (p_CcNextEngineParams->params.enqueueParams.newRelativeStorageProfileId
++                                        & FM_PCD_AD_RESULT_VSP_MASK)
++                                        << FM_PCD_AD_RESULT_VSP_SHIFT;
++#endif /* (DPAA_VERSION >= 11) */
++                    }
++                    else
++                    {
++                        tmp = FM_PCD_AD_RESULT_DATA_FLOW_TYPE;
++                        tmp |= FM_PCD_AD_RESULT_PLCR_DIS;
++                    }
++                }
++
++                if (p_CcNextEngineParams->params.enqueueParams.action
++                        == e_FM_PCD_DROP_FRAME)
++                    tmpNia |= GET_NIA_BMI_AC_DISCARD_FRAME(p_FmPcd);
++                else
++                    tmpNia |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd);
++                break;
++
++            case (e_FM_PCD_KG):
++                if (p_CcNextEngineParams->params.kgParams.overrideFqid)
++                {
++                    tmp = FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE;
++                    tmp |= p_CcNextEngineParams->params.kgParams.newFqid;
++#if (DPAA_VERSION >= 11)
++                    tmp |=
++                            (p_CcNextEngineParams->params.kgParams.newRelativeStorageProfileId
++                                    & FM_PCD_AD_RESULT_VSP_MASK)
++                                    << FM_PCD_AD_RESULT_VSP_SHIFT;
++#endif /* (DPAA_VERSION >= 11) */
++                }
++                else
++                {
++                    tmp = FM_PCD_AD_RESULT_DATA_FLOW_TYPE;
++                    tmp |= FM_PCD_AD_RESULT_PLCR_DIS;
++                }
++                tmpNia = NIA_KG_DIRECT;
++                tmpNia |= NIA_ENG_KG;
++                tmpNia |= NIA_KG_CC_EN;
++                tmpNia |= FmPcdKgGetSchemeId(
++                        p_CcNextEngineParams->params.kgParams.h_DirectScheme);
++                break;
++
++            case (e_FM_PCD_PLCR):
++                if (p_CcNextEngineParams->params.plcrParams.overrideParams)
++                {
++                    tmp = FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE;
++
++                    /* if private policer profile, it may be uninitialized yet, therefore no checks are done at this stage */
++                    if (p_CcNextEngineParams->params.plcrParams.sharedProfile)
++                    {
++                        tmpNia |= NIA_PLCR_ABSOLUTE;
++                        err = FmPcdPlcrGetAbsoluteIdByProfileParams(
++                                (t_Handle)p_FmPcd,
++                                e_FM_PCD_PLCR_SHARED,
++                                NULL,
++                                p_CcNextEngineParams->params.plcrParams.newRelativeProfileId,
++                                &profileId);
++
++                                              if (err != E_OK) {
++                                                      REPORT_ERROR(MAJOR, err, NO_MSG);
++                                                      return;
++                                              }
++
++                    }
++                    else
++                        profileId =
++                                p_CcNextEngineParams->params.plcrParams.newRelativeProfileId;
++
++                    tmp |= p_CcNextEngineParams->params.plcrParams.newFqid;
++#if (DPAA_VERSION >= 11)
++                    tmp |=
++                            (p_CcNextEngineParams->params.plcrParams.newRelativeStorageProfileId
++                                    & FM_PCD_AD_RESULT_VSP_MASK)
++                                    << FM_PCD_AD_RESULT_VSP_SHIFT;
++#endif /* (DPAA_VERSION >= 11) */
++                    WRITE_UINT32(
++                            p_AdResult->plcrProfile,
++                            (uint32_t)((uint32_t)profileId << FM_PCD_AD_PROFILEID_FOR_CNTRL_SHIFT));
++                }
++                else
++                    tmp = FM_PCD_AD_RESULT_DATA_FLOW_TYPE;
++
++                tmpNia |=
++                        NIA_ENG_PLCR
++                                | p_CcNextEngineParams->params.plcrParams.newRelativeProfileId;
++                break;
++
++            default:
++                return;
++        }WRITE_UINT32(p_AdResult->fqid, tmp);
++
++        if (p_CcNextEngineParams->h_Manip)
++        {
++            tmp = GET_UINT32(p_AdResult->plcrProfile);
++            tmp |= (uint32_t)(XX_VirtToPhys(p_AdNewPtr)
++                    - (p_FmPcd->physicalMuramBase)) >> 4;
++            WRITE_UINT32(p_AdResult->plcrProfile, tmp);
++
++            tmpNia |= FM_PCD_AD_RESULT_EXTENDED_MODE;
++            tmpNia |= FM_PCD_AD_RESULT_NADEN;
++        }
++
++#if (DPAA_VERSION >= 11)
++        tmpNia |= FM_PCD_AD_RESULT_NO_OM_VSPE;
++#endif /* (DPAA_VERSION >= 11) */
++        WRITE_UINT32(p_AdResult->nia, tmpNia);
++    }
++}
++
++static t_Error CcUpdateParams(t_Handle h_FmPcd, t_Handle h_PcdParams,
++                              t_Handle h_FmPort, t_Handle h_FmTree,
++                              bool validate)
++{
++    t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_FmTree;
++
++    return CcUpdateParam(h_FmPcd, h_PcdParams, h_FmPort,
++                         p_CcTree->keyAndNextEngineParams,
++                         p_CcTree->numOfEntries,
++                         UINT_TO_PTR(p_CcTree->ccTreeBaseAddr), validate, 0,
++                         h_FmTree, FALSE);
++}
++
++
++static void ReleaseNewNodeCommonPart(
++        t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo)
++{
++    if (p_AdditionalInfo->p_AdTableNew)
++        FM_MURAM_FreeMem(
++                FmPcdGetMuramHandle(
++                        ((t_FmPcdCcNode *)(p_AdditionalInfo->h_CurrentNode))->h_FmPcd),
++                p_AdditionalInfo->p_AdTableNew);
++
++    if (p_AdditionalInfo->p_KeysMatchTableNew)
++        FM_MURAM_FreeMem(
++                FmPcdGetMuramHandle(
++                        ((t_FmPcdCcNode *)(p_AdditionalInfo->h_CurrentNode))->h_FmPcd),
++                p_AdditionalInfo->p_KeysMatchTableNew);
++}
++
++static t_Error UpdateGblMask(t_FmPcdCcNode *p_CcNode, uint8_t keySize,
++                             uint8_t *p_Mask)
++{
++    uint8_t prvGlblMaskSize = p_CcNode->glblMaskSize;
++
++    if (p_Mask && !p_CcNode->glblMaskUpdated && (keySize <= 4)
++            && !p_CcNode->lclMask)
++    {
++        if (p_CcNode->parseCode && (p_CcNode->parseCode != CC_PC_FF_TCI1)
++                && (p_CcNode->parseCode != CC_PC_FF_TCI2)
++                && (p_CcNode->parseCode != CC_PC_FF_MPLS1)
++                && (p_CcNode->parseCode != CC_PC_FF_MPLS_LAST)
++                && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC1)
++                && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC2)
++                && (p_CcNode->parseCode != CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1)
++                && (p_CcNode->parseCode != CC_PC_FF_IPDSCP)
++                && (p_CcNode->parseCode != CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2))
++        {
++            p_CcNode->glblMaskSize = 0;
++            p_CcNode->lclMask = TRUE;
++        }
++        else
++        {
++            memcpy(p_CcNode->p_GlblMask, p_Mask, (sizeof(uint8_t)) * keySize);
++            p_CcNode->glblMaskUpdated = TRUE;
++            p_CcNode->glblMaskSize = 4;
++        }
++    }
++    else
++        if (p_Mask && (keySize <= 4) && !p_CcNode->lclMask)
++        {
++            if (memcmp(p_CcNode->p_GlblMask, p_Mask, keySize) != 0)
++            {
++                p_CcNode->lclMask = TRUE;
++                p_CcNode->glblMaskSize = 0;
++            }
++        }
++        else
++            if (!p_Mask && p_CcNode->glblMaskUpdated && (keySize <= 4))
++            {
++                uint32_t tmpMask = 0xffffffff;
++                if (memcmp(p_CcNode->p_GlblMask, &tmpMask, 4) != 0)
++                {
++                    p_CcNode->lclMask = TRUE;
++                    p_CcNode->glblMaskSize = 0;
++                }
++            }
++            else
++                if (p_Mask)
++                {
++                    p_CcNode->lclMask = TRUE;
++                    p_CcNode->glblMaskSize = 0;
++                }
++
++    /* In static mode (maxNumOfKeys > 0), local mask is supported
++     only is mask support was enabled at initialization */
++    if (p_CcNode->maxNumOfKeys && (!p_CcNode->maskSupport) && p_CcNode->lclMask)
++    {
++        p_CcNode->lclMask = FALSE;
++        p_CcNode->glblMaskSize = prvGlblMaskSize;
++        return ERROR_CODE(E_NOT_SUPPORTED);
++    }
++
++    return E_OK;
++}
++
++static __inline__ t_Handle GetNewAd(t_Handle h_FmPcdCcNodeOrTree, bool isTree)
++{
++    t_FmPcd *p_FmPcd;
++    t_Handle h_Ad;
++
++    if (isTree)
++        p_FmPcd = (t_FmPcd *)(((t_FmPcdCcTree *)h_FmPcdCcNodeOrTree)->h_FmPcd);
++    else
++        p_FmPcd = (t_FmPcd *)(((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->h_FmPcd);
++
++    if ((isTree && p_FmPcd->p_CcShadow)
++            || (!isTree && ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->maxNumOfKeys))
++    {
++        /* The allocated shadow is divided as follows:
++         0 . . .       16 . . .
++         ---------------------------------------------------
++         |   Shadow   |   Shadow Keys   |   Shadow Next    |
++         |     Ad     |   Match Table   |   Engine Table   |
++         | (16 bytes) | (maximal size)  |  (maximal size)  |
++         ---------------------------------------------------
++         */
++        if (!p_FmPcd->p_CcShadow)
++        {
++            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("CC Shadow not allocated"));
++            return NULL;
++        }
++
++        h_Ad = p_FmPcd->p_CcShadow;
++    }
++    else
++    {
++        h_Ad = (t_Handle)FM_MURAM_AllocMem(FmPcdGetMuramHandle(p_FmPcd),
++                                           FM_PCD_CC_AD_ENTRY_SIZE,
++                                           FM_PCD_CC_AD_TABLE_ALIGN);
++        if (!h_Ad)
++        {
++            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC node action descriptor"));
++            return NULL;
++        }
++    }
++
++    return h_Ad;
++}
++
++static t_Error BuildNewNodeCommonPart(
++        t_FmPcdCcNode *p_CcNode, int *size,
++        t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++
++    if (p_CcNode->lclMask)
++        *size = 2 * p_CcNode->ccKeySizeAccExtraction;
++    else
++        *size = p_CcNode->ccKeySizeAccExtraction;
++
++    if (p_CcNode->maxNumOfKeys == 0)
++    {
++        p_AdditionalInfo->p_AdTableNew = (t_Handle)FM_MURAM_AllocMem(
++                FmPcdGetMuramHandle(p_FmPcd),
++                (uint32_t)((p_AdditionalInfo->numOfKeys + 1)
++                        * FM_PCD_CC_AD_ENTRY_SIZE),
++                FM_PCD_CC_AD_TABLE_ALIGN);
++        if (!p_AdditionalInfo->p_AdTableNew)
++            RETURN_ERROR(
++                    MAJOR, E_NO_MEMORY,
++                    ("MURAM allocation for CC node action descriptors table"));
++
++        p_AdditionalInfo->p_KeysMatchTableNew = (t_Handle)FM_MURAM_AllocMem(
++                FmPcdGetMuramHandle(p_FmPcd),
++                (uint32_t)(*size * sizeof(uint8_t)
++                        * (p_AdditionalInfo->numOfKeys + 1)),
++                FM_PCD_CC_KEYS_MATCH_TABLE_ALIGN);
++        if (!p_AdditionalInfo->p_KeysMatchTableNew)
++        {
++            FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd),
++                             p_AdditionalInfo->p_AdTableNew);
++            p_AdditionalInfo->p_AdTableNew = NULL;
++            RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                         ("MURAM allocation for CC node key match table"));
++        }
++
++        MemSet8(
++                (uint8_t*)p_AdditionalInfo->p_AdTableNew,
++                0,
++                (uint32_t)((p_AdditionalInfo->numOfKeys + 1)
++                        * FM_PCD_CC_AD_ENTRY_SIZE));
++        MemSet8((uint8_t*)p_AdditionalInfo->p_KeysMatchTableNew, 0,
++                   *size * sizeof(uint8_t) * (p_AdditionalInfo->numOfKeys + 1));
++    }
++    else
++    {
++        /* The allocated shadow is divided as follows:
++         0 . . .       16 . . .
++         ---------------------------------------------------
++         |   Shadow   |   Shadow Keys   |   Shadow Next    |
++         |     Ad     |   Match Table   |   Engine Table   |
++         | (16 bytes) | (maximal size)  |  (maximal size)  |
++         ---------------------------------------------------
++         */
++
++        if (!p_FmPcd->p_CcShadow)
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("CC Shadow not allocated"));
++
++        p_AdditionalInfo->p_KeysMatchTableNew =
++                PTR_MOVE(p_FmPcd->p_CcShadow, FM_PCD_CC_AD_ENTRY_SIZE);
++        p_AdditionalInfo->p_AdTableNew =
++                PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, p_CcNode->keysMatchTableMaxSize);
++
++        MemSet8(
++                (uint8_t*)p_AdditionalInfo->p_AdTableNew,
++                0,
++                (uint32_t)((p_CcNode->maxNumOfKeys + 1)
++                        * FM_PCD_CC_AD_ENTRY_SIZE));
++        MemSet8((uint8_t*)p_AdditionalInfo->p_KeysMatchTableNew, 0,
++                   (*size) * sizeof(uint8_t) * (p_CcNode->maxNumOfKeys));
++    }
++
++    p_AdditionalInfo->p_AdTableOld = p_CcNode->h_AdTable;
++    p_AdditionalInfo->p_KeysMatchTableOld = p_CcNode->h_KeysMatchTable;
++
++    return E_OK;
++}
++
++static t_Error BuildNewNodeAddOrMdfyKeyAndNextEngine(
++        t_Handle h_FmPcd, t_FmPcdCcNode *p_CcNode, uint16_t keyIndex,
++        t_FmPcdCcKeyParams *p_KeyParams,
++        t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo, bool add)
++{
++    t_Error err = E_OK;
++    t_Handle p_AdTableNewTmp, p_KeysMatchTableNewTmp;
++    t_Handle p_KeysMatchTableOldTmp, p_AdTableOldTmp;
++    int size;
++    int i = 0, j = 0;
++    t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint32_t requiredAction = 0;
++    bool prvLclMask;
++    t_CcNodeInformation *p_CcNodeInformation;
++    t_FmPcdCcStatsParams statsParams = { 0 };
++    t_List *p_Pos;
++    t_FmPcdStatsObj *p_StatsObj;
++
++    /* Check that new NIA is legal */
++    err = ValidateNextEngineParams(h_FmPcd, &p_KeyParams->ccNextEngineParams,
++                                   p_CcNode->statisticsMode);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    prvLclMask = p_CcNode->lclMask;
++
++    /* Check that new key is not require update of localMask */
++    err = UpdateGblMask(p_CcNode, p_CcNode->ccKeySizeAccExtraction,
++                        p_KeyParams->p_Mask);
++    if (err)
++        RETURN_ERROR(MAJOR, err, (NO_MSG));
++
++    /* Update internal data structure with new next engine for the given index */
++    memcpy(&p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams,
++           &p_KeyParams->ccNextEngineParams, sizeof(t_FmPcdCcNextEngineParams));
++
++    memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].key,
++           p_KeyParams->p_Key, p_CcNode->userSizeOfExtraction);
++
++    if ((p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
++            == e_FM_PCD_CC)
++            && p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip)
++    {
++        err =
++                AllocAndFillAdForContLookupManip(
++                        p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode);
++        if (err)
++            RETURN_ERROR(MAJOR, err, (NO_MSG));
++    }
++
++    if (p_KeyParams->p_Mask)
++        memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask,
++               p_KeyParams->p_Mask, p_CcNode->userSizeOfExtraction);
++    else
++        memset(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask, 0xFF,
++               p_CcNode->userSizeOfExtraction);
++
++    /* Update numOfKeys */
++    if (add)
++        p_AdditionalInfo->numOfKeys = (uint8_t)(p_CcNode->numOfKeys + 1);
++    else
++        p_AdditionalInfo->numOfKeys = (uint8_t)p_CcNode->numOfKeys;
++
++    /* Allocate new tables in MURAM: keys match table and action descriptors table */
++    err = BuildNewNodeCommonPart(p_CcNode, &size, p_AdditionalInfo);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    /* Check that manip is legal and what requiredAction is necessary for this manip */
++    if (p_KeyParams->ccNextEngineParams.h_Manip)
++    {
++        err = FmPcdManipCheckParamsForCcNextEngine(
++                &p_KeyParams->ccNextEngineParams, &requiredAction);
++        if (err)
++            RETURN_ERROR(MAJOR, err, (NO_MSG));
++    }
++
++    p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction =
++            requiredAction;
++    p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction |=
++            UPDATE_CC_WITH_TREE;
++
++    /* Update new Ad and new Key Table according to new requirement */
++    i = 0;
++    for (j = 0; j < p_AdditionalInfo->numOfKeys; j++)
++    {
++        p_AdTableNewTmp =
++                PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j*FM_PCD_CC_AD_ENTRY_SIZE);
++
++        if (j == keyIndex)
++        {
++            if (p_KeyParams->ccNextEngineParams.statisticsEn)
++            {
++                /* Allocate a statistics object that holds statistics AD and counters.
++                 - For added key - New statistics AD and counters pointer need to be allocated
++                 new statistics object. If statistics were enabled, we need to replace the
++                 existing descriptor with a new descriptor with nullified counters.
++                 */
++                p_StatsObj = GetStatsObj(p_CcNode);
++                ASSERT_COND(p_StatsObj);
++
++                /* Store allocated statistics object */
++                ASSERT_COND(keyIndex < CC_MAX_NUM_OF_KEYS);
++                p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj =
++                        p_StatsObj;
++
++                statsParams.h_StatsAd = p_StatsObj->h_StatsAd;
++                statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters;
++#if (DPAA_VERSION >= 11)
++                statsParams.h_StatsFLRs = p_CcNode->h_StatsFLRs;
++
++#endif /* (DPAA_VERSION >= 11) */
++
++                /* Building action descriptor for the received new key */
++                NextStepAd(p_AdTableNewTmp, &statsParams,
++                           &p_KeyParams->ccNextEngineParams, p_FmPcd);
++            }
++            else
++            {
++                /* Building action descriptor for the received new key */
++                NextStepAd(p_AdTableNewTmp, NULL,
++                           &p_KeyParams->ccNextEngineParams, p_FmPcd);
++            }
++
++            /* Copy the received new key into keys match table */
++            p_KeysMatchTableNewTmp =
++                    PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j*size*sizeof(uint8_t));
++
++            MemCpy8((void*)p_KeysMatchTableNewTmp, p_KeyParams->p_Key,
++                        p_CcNode->userSizeOfExtraction);
++
++            /* Update mask for the received new key */
++            if (p_CcNode->lclMask)
++            {
++                if (p_KeyParams->p_Mask)
++                {
++                    MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp,
++                            p_CcNode->ccKeySizeAccExtraction),
++                                p_KeyParams->p_Mask,
++                                p_CcNode->userSizeOfExtraction);
++                }
++                else
++                    if (p_CcNode->ccKeySizeAccExtraction > 4)
++                    {
++                        MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp,
++                                p_CcNode->ccKeySizeAccExtraction),
++                                   0xff, p_CcNode->userSizeOfExtraction);
++                    }
++                    else
++                    {
++                        MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp,
++                                p_CcNode->ccKeySizeAccExtraction),
++                                    p_CcNode->p_GlblMask,
++                                    p_CcNode->userSizeOfExtraction);
++                    }
++            }
++
++            /* If key modification requested, the old entry is omitted and replaced by the new parameters */
++            if (!add)
++                i++;
++        }
++        else
++        {
++            /* Copy existing action descriptors to the newly allocated Ad table */
++            p_AdTableOldTmp =
++                    PTR_MOVE(p_AdditionalInfo->p_AdTableOld, i*FM_PCD_CC_AD_ENTRY_SIZE);
++            MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp,
++                       FM_PCD_CC_AD_ENTRY_SIZE);
++
++            /* Copy existing keys and their masks to the newly allocated keys match table */
++            p_KeysMatchTableNewTmp =
++                    PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j * size * sizeof(uint8_t));
++            p_KeysMatchTableOldTmp =
++                    PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableOld, i * size * sizeof(uint8_t));
++
++            if (p_CcNode->lclMask)
++            {
++                if (prvLclMask)
++                {
++                    MemCpy8(
++                            PTR_MOVE(p_KeysMatchTableNewTmp, p_CcNode->ccKeySizeAccExtraction),
++                            PTR_MOVE(p_KeysMatchTableOldTmp, p_CcNode->ccKeySizeAccExtraction),
++                            p_CcNode->ccKeySizeAccExtraction);
++                }
++                else
++                {
++                    p_KeysMatchTableOldTmp =
++                            PTR_MOVE(p_CcNode->h_KeysMatchTable,
++                                    i * (int)p_CcNode->ccKeySizeAccExtraction * sizeof(uint8_t));
++
++                    if (p_CcNode->ccKeySizeAccExtraction > 4)
++                    {
++                        MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp,
++                                p_CcNode->ccKeySizeAccExtraction),
++                                   0xff, p_CcNode->userSizeOfExtraction);
++                    }
++                    else
++                    {
++                        MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp,
++                                p_CcNode->ccKeySizeAccExtraction),
++                                   p_CcNode->p_GlblMask,
++                                   p_CcNode->userSizeOfExtraction);
++                    }
++                }
++            }
++
++            MemCpy8(p_KeysMatchTableNewTmp, p_KeysMatchTableOldTmp,
++                       p_CcNode->ccKeySizeAccExtraction);
++
++            i++;
++        }
++    }
++
++    /* Miss action descriptor */
++    p_AdTableNewTmp =
++            PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j * FM_PCD_CC_AD_ENTRY_SIZE);
++    p_AdTableOldTmp =
++            PTR_MOVE(p_AdditionalInfo->p_AdTableOld, i * FM_PCD_CC_AD_ENTRY_SIZE);
++    MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE);
++
++    if (!LIST_IsEmpty(&p_CcNode->ccTreesLst))
++    {
++        LIST_FOR_EACH(p_Pos, &p_CcNode->ccTreesLst)
++        {
++            p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos);
++            ASSERT_COND(p_CcNodeInformation->h_CcNode);
++            /* Update the manipulation which has to be updated from parameters of the port */
++            /* It's has to be updated with restrictions defined in the function */
++            err =
++                    SetRequiredAction(
++                            p_CcNode->h_FmPcd,
++                            p_CcNode->shadowAction
++                                    | p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction,
++                            &p_AdditionalInfo->keyAndNextEngineParams[keyIndex],
++                            PTR_MOVE(p_AdditionalInfo->p_AdTableNew, keyIndex*FM_PCD_CC_AD_ENTRY_SIZE),
++                            1, p_CcNodeInformation->h_CcNode);
++            if (err)
++                RETURN_ERROR(MAJOR, err, (NO_MSG));
++
++            err =
++                    CcUpdateParam(
++                            p_CcNode->h_FmPcd,
++                            NULL,
++                            NULL,
++                            &p_AdditionalInfo->keyAndNextEngineParams[keyIndex],
++                            1,
++                            PTR_MOVE(p_AdditionalInfo->p_AdTableNew, keyIndex*FM_PCD_CC_AD_ENTRY_SIZE),
++                            TRUE, p_CcNodeInformation->index,
++                            p_CcNodeInformation->h_CcNode, TRUE);
++            if (err)
++                RETURN_ERROR(MAJOR, err, (NO_MSG));
++        }
++    }
++
++    if (p_CcNode->lclMask)
++        memset(p_CcNode->p_GlblMask, 0xff, CC_GLBL_MASK_SIZE * sizeof(uint8_t));
++
++    if (p_KeyParams->ccNextEngineParams.nextEngine == e_FM_PCD_CC)
++        p_AdditionalInfo->h_NodeForAdd =
++                p_KeyParams->ccNextEngineParams.params.ccParams.h_CcNode;
++    if (p_KeyParams->ccNextEngineParams.h_Manip)
++        p_AdditionalInfo->h_ManipForAdd =
++                p_KeyParams->ccNextEngineParams.h_Manip;
++
++#if (DPAA_VERSION >= 11)
++    if ((p_KeyParams->ccNextEngineParams.nextEngine == e_FM_PCD_FR)
++            && (p_KeyParams->ccNextEngineParams.params.frParams.h_FrmReplic))
++        p_AdditionalInfo->h_FrmReplicForAdd =
++                p_KeyParams->ccNextEngineParams.params.frParams.h_FrmReplic;
++#endif /* (DPAA_VERSION >= 11) */
++
++    if (!add)
++    {
++        if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
++                == e_FM_PCD_CC)
++            p_AdditionalInfo->h_NodeForRmv =
++                    p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode;
++
++        if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip)
++            p_AdditionalInfo->h_ManipForRmv =
++                    p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip;
++
++        /* If statistics were previously enabled, store the old statistics object to be released */
++        if (p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj)
++        {
++            p_AdditionalInfo->p_StatsObjForRmv =
++                    p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj;
++        }
++
++#if (DPAA_VERSION >= 11)
++        if ((p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
++                == e_FM_PCD_FR)
++                && (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic))
++            p_AdditionalInfo->h_FrmReplicForRmv =
++                    p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic;
++#endif /* (DPAA_VERSION >= 11) */
++    }
++
++    return E_OK;
++}
++
++static t_Error BuildNewNodeRemoveKey(
++        t_FmPcdCcNode *p_CcNode, uint16_t keyIndex,
++        t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo)
++{
++    int i = 0, j = 0;
++    t_Handle p_AdTableNewTmp, p_KeysMatchTableNewTmp;
++    t_Handle p_KeysMatchTableOldTmp, p_AdTableOldTmp;
++    int size;
++    t_Error err = E_OK;
++
++    /*save new numOfKeys*/
++    p_AdditionalInfo->numOfKeys = (uint16_t)(p_CcNode->numOfKeys - 1);
++
++    /*function which allocates in the memory new KeyTbl, AdTbl*/
++    err = BuildNewNodeCommonPart(p_CcNode, &size, p_AdditionalInfo);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    /*update new Ad and new Key Table according to new requirement*/
++    for (i = 0, j = 0; j < p_CcNode->numOfKeys; i++, j++)
++    {
++        if (j == keyIndex)
++            j++;
++
++        if (j == p_CcNode->numOfKeys)
++            break;
++        p_AdTableNewTmp =
++                PTR_MOVE(p_AdditionalInfo->p_AdTableNew, i * FM_PCD_CC_AD_ENTRY_SIZE);
++        p_AdTableOldTmp =
++                PTR_MOVE(p_AdditionalInfo->p_AdTableOld, j * FM_PCD_CC_AD_ENTRY_SIZE);
++        MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE);
++
++        p_KeysMatchTableOldTmp =
++                PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableOld, j * size * sizeof(uint8_t));
++        p_KeysMatchTableNewTmp =
++                PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, i * size * sizeof(uint8_t));
++        MemCpy8(p_KeysMatchTableNewTmp, p_KeysMatchTableOldTmp,
++                   size * sizeof(uint8_t));
++    }
++
++    p_AdTableNewTmp =
++            PTR_MOVE(p_AdditionalInfo->p_AdTableNew, i * FM_PCD_CC_AD_ENTRY_SIZE);
++    p_AdTableOldTmp =
++            PTR_MOVE(p_AdditionalInfo->p_AdTableOld, j * FM_PCD_CC_AD_ENTRY_SIZE);
++    MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE);
++
++    if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
++            == e_FM_PCD_CC)
++        p_AdditionalInfo->h_NodeForRmv =
++                p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode;
++
++    if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip)
++        p_AdditionalInfo->h_ManipForRmv =
++                p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip;
++
++    /* If statistics were previously enabled, store the old statistics object to be released */
++    if (p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj)
++    {
++        p_AdditionalInfo->p_StatsObjForRmv =
++                p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj;
++    }
++
++#if (DPAA_VERSION >= 11)
++    if ((p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
++            == e_FM_PCD_FR)
++            && (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic))
++        p_AdditionalInfo->h_FrmReplicForRmv =
++                p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic;
++#endif /* (DPAA_VERSION >= 11) */
++
++    return E_OK;
++}
++
++static t_Error BuildNewNodeModifyKey(
++        t_FmPcdCcNode *p_CcNode, uint16_t keyIndex, uint8_t *p_Key,
++        uint8_t *p_Mask, t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++    t_Error err = E_OK;
++    t_Handle p_AdTableNewTmp, p_KeysMatchTableNewTmp;
++    t_Handle p_KeysMatchTableOldTmp, p_AdTableOldTmp;
++    int size;
++    int i = 0, j = 0;
++    bool prvLclMask;
++    t_FmPcdStatsObj *p_StatsObj, tmpStatsObj;
++    p_AdditionalInfo->numOfKeys = p_CcNode->numOfKeys;
++
++    prvLclMask = p_CcNode->lclMask;
++
++    /* Check that new key is not require update of localMask */
++    err = UpdateGblMask(p_CcNode, p_CcNode->ccKeySizeAccExtraction, p_Mask);
++    if (err)
++        RETURN_ERROR(MAJOR, err, (NO_MSG));
++
++    /* Update internal data structure with new next engine for the given index */
++    memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].key, p_Key,
++           p_CcNode->userSizeOfExtraction);
++
++    if (p_Mask)
++        memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask, p_Mask,
++               p_CcNode->userSizeOfExtraction);
++    else
++        memset(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask, 0xFF,
++               p_CcNode->userSizeOfExtraction);
++
++    /*function which build in the memory new KeyTbl, AdTbl*/
++    err = BuildNewNodeCommonPart(p_CcNode, &size, p_AdditionalInfo);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    /*fill the New AdTable and New KeyTable*/
++    for (j = 0, i = 0; j < p_AdditionalInfo->numOfKeys; j++, i++)
++    {
++        p_AdTableNewTmp =
++                PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j*FM_PCD_CC_AD_ENTRY_SIZE);
++        p_AdTableOldTmp =
++                PTR_MOVE(p_AdditionalInfo->p_AdTableOld, i*FM_PCD_CC_AD_ENTRY_SIZE);
++
++        MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE);
++
++        if (j == keyIndex)
++        {
++            ASSERT_COND(keyIndex < CC_MAX_NUM_OF_KEYS);
++            if (p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj)
++            {
++                /* As statistics were enabled, we need to update the existing
++                 statistics descriptor with a new nullified counters. */
++                p_StatsObj = GetStatsObj(p_CcNode);
++                ASSERT_COND(p_StatsObj);
++
++                SetStatsCounters(
++                        p_AdTableNewTmp,
++                        (uint32_t)((XX_VirtToPhys(p_StatsObj->h_StatsCounters)
++                                - p_FmPcd->physicalMuramBase)));
++
++                tmpStatsObj.h_StatsAd = p_StatsObj->h_StatsAd;
++                tmpStatsObj.h_StatsCounters = p_StatsObj->h_StatsCounters;
++
++                /* As we need to replace only the counters, we build a new statistics
++                 object that holds the old AD and the new counters - this will be the
++                 currently used statistics object.
++                 The newly allocated AD is not required and may be released back to
++                 the available objects with the previous counters pointer. */
++                p_StatsObj->h_StatsAd =
++                        p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsAd;
++
++                p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsAd =
++                        tmpStatsObj.h_StatsAd;
++
++                /* Store allocated statistics object */
++                p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj =
++                        p_StatsObj;
++
++                /* As statistics were previously enabled, store the old statistics object to be released */
++                p_AdditionalInfo->p_StatsObjForRmv =
++                        p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj;
++            }
++
++            p_KeysMatchTableNewTmp =
++                    PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j * size * sizeof(uint8_t));
++
++            MemCpy8(p_KeysMatchTableNewTmp, p_Key,
++                        p_CcNode->userSizeOfExtraction);
++
++            if (p_CcNode->lclMask)
++            {
++                if (p_Mask)
++                    MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp,
++                            p_CcNode->ccKeySizeAccExtraction),
++                                p_Mask, p_CcNode->userSizeOfExtraction);
++                else
++                    if (p_CcNode->ccKeySizeAccExtraction > 4)
++                        MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp,
++                                p_CcNode->ccKeySizeAccExtraction),
++                                   0xff, p_CcNode->userSizeOfExtraction);
++                    else
++                        MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp,
++                                p_CcNode->ccKeySizeAccExtraction),
++                                    p_CcNode->p_GlblMask,
++                                    p_CcNode->userSizeOfExtraction);
++            }
++        }
++        else
++        {
++            p_KeysMatchTableNewTmp =
++                    PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j * size * sizeof(uint8_t));
++            p_KeysMatchTableOldTmp =
++                    PTR_MOVE(p_CcNode->h_KeysMatchTable, i * size * sizeof(uint8_t));
++
++            if (p_CcNode->lclMask)
++            {
++                if (prvLclMask)
++                    MemCpy8(
++                            PTR_MOVE(p_KeysMatchTableNewTmp, p_CcNode->ccKeySizeAccExtraction),
++                            PTR_MOVE(p_KeysMatchTableOldTmp, p_CcNode->ccKeySizeAccExtraction),
++                            p_CcNode->userSizeOfExtraction);
++                else
++                {
++                    p_KeysMatchTableOldTmp =
++                            PTR_MOVE(p_CcNode->h_KeysMatchTable,
++                                     i * (int)p_CcNode->ccKeySizeAccExtraction * sizeof(uint8_t));
++
++                    if (p_CcNode->ccKeySizeAccExtraction > 4)
++                        MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp,
++                                p_CcNode->ccKeySizeAccExtraction),
++                                   0xff, p_CcNode->userSizeOfExtraction);
++                    else
++                        MemCpy8(
++                                PTR_MOVE(p_KeysMatchTableNewTmp, p_CcNode->ccKeySizeAccExtraction),
++                                p_CcNode->p_GlblMask,
++                                p_CcNode->userSizeOfExtraction);
++                }
++            }
++            MemCpy8((void*)p_KeysMatchTableNewTmp, p_KeysMatchTableOldTmp,
++                       p_CcNode->ccKeySizeAccExtraction);
++        }
++    }
++
++    p_AdTableNewTmp =
++            PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j * FM_PCD_CC_AD_ENTRY_SIZE);
++    p_AdTableOldTmp = PTR_MOVE(p_CcNode->h_AdTable, i * FM_PCD_CC_AD_ENTRY_SIZE);
++
++    MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE);
++
++    return E_OK;
++}
++
++static t_Error BuildNewNodeModifyNextEngine(
++        t_Handle h_FmPcd, t_Handle h_FmPcdCcNodeOrTree, uint16_t keyIndex,
++        t_FmPcdCcNextEngineParams *p_CcNextEngineParams, t_List *h_OldLst,
++        t_List *h_NewLst, t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo)
++{
++    t_Error err = E_OK;
++    uint32_t requiredAction = 0;
++    t_List *p_Pos;
++    t_CcNodeInformation *p_CcNodeInformation, ccNodeInfo;
++    t_Handle p_Ad;
++    t_FmPcdCcNode *p_FmPcdCcNode1 = NULL;
++    t_FmPcdCcTree *p_FmPcdCcTree = NULL;
++    t_FmPcdStatsObj *p_StatsObj;
++    t_FmPcdCcStatsParams statsParams = { 0 };
++
++    ASSERT_COND(p_CcNextEngineParams);
++
++    /* check that new NIA is legal */
++    if (!p_AdditionalInfo->tree)
++        err = ValidateNextEngineParams(
++                h_FmPcd, p_CcNextEngineParams,
++                ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->statisticsMode);
++    else
++        /* Statistics are not supported for CC root */
++        err = ValidateNextEngineParams(h_FmPcd, p_CcNextEngineParams,
++                                       e_FM_PCD_CC_STATS_MODE_NONE);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    /* Update internal data structure for next engine per index (index - key) */
++    memcpy(&p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams,
++           p_CcNextEngineParams, sizeof(t_FmPcdCcNextEngineParams));
++
++    /* Check that manip is legal and what requiredAction is necessary for this manip */
++    if (p_CcNextEngineParams->h_Manip)
++    {
++        err = FmPcdManipCheckParamsForCcNextEngine(p_CcNextEngineParams,
++                                                   &requiredAction);
++        if (err)
++            RETURN_ERROR(MAJOR, err, (NO_MSG));
++    }
++
++    if (!p_AdditionalInfo->tree)
++    {
++        p_FmPcdCcNode1 = (t_FmPcdCcNode *)h_FmPcdCcNodeOrTree;
++        p_AdditionalInfo->numOfKeys = p_FmPcdCcNode1->numOfKeys;
++        p_Ad = p_FmPcdCcNode1->h_AdTable;
++
++        if (p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
++                == e_FM_PCD_CC)
++            p_AdditionalInfo->h_NodeForRmv =
++                    p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode;
++
++        if (p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip)
++            p_AdditionalInfo->h_ManipForRmv =
++                    p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip;
++
++#if (DPAA_VERSION >= 11)
++        if ((p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
++                == e_FM_PCD_FR)
++                && (p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic))
++            p_AdditionalInfo->h_FrmReplicForRmv =
++                    p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic;
++#endif /* (DPAA_VERSION >= 11) */
++    }
++    else
++    {
++        p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcNodeOrTree;
++        p_Ad = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr);
++
++        if (p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
++                == e_FM_PCD_CC)
++            p_AdditionalInfo->h_NodeForRmv =
++                    p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode;
++
++        if (p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip)
++            p_AdditionalInfo->h_ManipForRmv =
++                    p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip;
++
++#if (DPAA_VERSION >= 11)
++        if ((p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
++                == e_FM_PCD_FR)
++                && (p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic))
++            p_AdditionalInfo->h_FrmReplicForRmv =
++                    p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic;
++#endif /* (DPAA_VERSION >= 11) */
++    }
++
++    if ((p_CcNextEngineParams->nextEngine == e_FM_PCD_CC)
++            && p_CcNextEngineParams->h_Manip)
++    {
++        err = AllocAndFillAdForContLookupManip(
++                p_CcNextEngineParams->params.ccParams.h_CcNode);
++        if (err)
++            RETURN_ERROR(MAJOR, err, (NO_MSG));
++    }
++
++    ASSERT_COND(p_Ad);
++
++    memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
++    ccNodeInfo.h_CcNode = PTR_MOVE(p_Ad, keyIndex * FM_PCD_CC_AD_ENTRY_SIZE);
++
++    /* If statistics were enabled, this Ad is the statistics Ad. Need to follow its
++     nextAction to retrieve the actual Nia-Ad. If statistics should remain enabled,
++     only the actual Nia-Ad should be modified. */
++    if ((!p_AdditionalInfo->tree)
++            && (((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj)
++            && (p_CcNextEngineParams->statisticsEn))
++        ccNodeInfo.h_CcNode =
++                ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsAd;
++
++    EnqueueNodeInfoToRelevantLst(h_OldLst, &ccNodeInfo, NULL);
++
++    memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
++    p_Ad = GetNewAd(h_FmPcdCcNodeOrTree, p_AdditionalInfo->tree);
++    if (!p_Ad)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                     ("MURAM allocation for CC node action descriptor"));
++    MemSet8((uint8_t *)p_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++    /* If statistics were not enabled before, but requested now -  Allocate a statistics
++     object that holds statistics AD and counters. */
++    if ((!p_AdditionalInfo->tree)
++            && (!((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj)
++            && (p_CcNextEngineParams->statisticsEn))
++    {
++        p_StatsObj = GetStatsObj((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree);
++        ASSERT_COND(p_StatsObj);
++
++        /* Store allocated statistics object */
++        p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj =
++                p_StatsObj;
++
++        statsParams.h_StatsAd = p_StatsObj->h_StatsAd;
++        statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters;
++
++#if (DPAA_VERSION >= 11)
++        statsParams.h_StatsFLRs =
++                ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->h_StatsFLRs;
++
++#endif /* (DPAA_VERSION >= 11) */
++
++        NextStepAd(p_Ad, &statsParams, p_CcNextEngineParams, h_FmPcd);
++    }
++    else
++        NextStepAd(p_Ad, NULL, p_CcNextEngineParams, h_FmPcd);
++
++    ccNodeInfo.h_CcNode = p_Ad;
++    EnqueueNodeInfoToRelevantLst(h_NewLst, &ccNodeInfo, NULL);
++
++    p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction =
++            requiredAction;
++    p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction |=
++            UPDATE_CC_WITH_TREE;
++
++    if (!p_AdditionalInfo->tree)
++    {
++        ASSERT_COND(p_FmPcdCcNode1);
++        if (!LIST_IsEmpty(&p_FmPcdCcNode1->ccTreesLst))
++        {
++            LIST_FOR_EACH(p_Pos, &p_FmPcdCcNode1->ccTreesLst)
++            {
++                p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos);
++
++                ASSERT_COND(p_CcNodeInformation->h_CcNode);
++                /* Update the manipulation which has to be updated from parameters of the port
++                 it's has to be updated with restrictions defined in the function */
++
++                err =
++                        SetRequiredAction(
++                                p_FmPcdCcNode1->h_FmPcd,
++                                p_FmPcdCcNode1->shadowAction
++                                        | p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction,
++                                &p_AdditionalInfo->keyAndNextEngineParams[keyIndex],
++                                p_Ad, 1, p_CcNodeInformation->h_CcNode);
++                if (err)
++                    RETURN_ERROR(MAJOR, err, (NO_MSG));
++
++                err = CcUpdateParam(
++                        p_FmPcdCcNode1->h_FmPcd, NULL, NULL,
++                        &p_AdditionalInfo->keyAndNextEngineParams[keyIndex], 1,
++                        p_Ad, TRUE, p_CcNodeInformation->index,
++                        p_CcNodeInformation->h_CcNode, TRUE);
++                if (err)
++                    RETURN_ERROR(MAJOR, err, (NO_MSG));
++            }
++        }
++    }
++    else
++    {
++        ASSERT_COND(p_FmPcdCcTree);
++
++        err =
++                SetRequiredAction(
++                        h_FmPcd,
++                        p_FmPcdCcTree->requiredAction
++                                | p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction,
++                        &p_AdditionalInfo->keyAndNextEngineParams[keyIndex],
++                        p_Ad, 1, (t_Handle)p_FmPcdCcTree);
++        if (err)
++            RETURN_ERROR(MAJOR, err, (NO_MSG));
++
++        err = CcUpdateParam(h_FmPcd, NULL, NULL,
++                            &p_AdditionalInfo->keyAndNextEngineParams[keyIndex],
++                            1, p_Ad, TRUE, 0, (t_Handle)p_FmPcdCcTree, TRUE);
++        if (err)
++            RETURN_ERROR(MAJOR, err, (NO_MSG));
++    }
++
++    if (p_CcNextEngineParams->nextEngine == e_FM_PCD_CC)
++        p_AdditionalInfo->h_NodeForAdd =
++                p_CcNextEngineParams->params.ccParams.h_CcNode;
++    if (p_CcNextEngineParams->h_Manip)
++        p_AdditionalInfo->h_ManipForAdd = p_CcNextEngineParams->h_Manip;
++
++    /* If statistics were previously enabled, but now are disabled,
++     store the old statistics object to be released */
++    if ((!p_AdditionalInfo->tree)
++            && (((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj)
++            && (!p_CcNextEngineParams->statisticsEn))
++    {
++        p_AdditionalInfo->p_StatsObjForRmv =
++                ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj;
++
++
++        p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj = NULL;
++    }
++#if (DPAA_VERSION >= 11)
++    if ((p_CcNextEngineParams->nextEngine == e_FM_PCD_FR)
++            && (p_CcNextEngineParams->params.frParams.h_FrmReplic))
++        p_AdditionalInfo->h_FrmReplicForAdd =
++                p_CcNextEngineParams->params.frParams.h_FrmReplic;
++#endif /* (DPAA_VERSION >= 11) */
++
++    return E_OK;
++}
++
++static void UpdateAdPtrOfNodesWhichPointsOnCrntMdfNode(
++        t_FmPcdCcNode *p_CrntMdfNode, t_List *h_OldLst,
++        t_FmPcdCcNextEngineParams **p_NextEngineParams)
++{
++    t_CcNodeInformation *p_CcNodeInformation;
++    t_FmPcdCcNode *p_NodePtrOnCurrentMdfNode = NULL;
++    t_List *p_Pos;
++    int i = 0;
++    t_Handle p_AdTablePtOnCrntCurrentMdfNode/*, p_AdTableNewModified*/;
++    t_CcNodeInformation ccNodeInfo;
++
++    LIST_FOR_EACH(p_Pos, &p_CrntMdfNode->ccPrevNodesLst)
++    {
++        p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos);
++        p_NodePtrOnCurrentMdfNode =
++                (t_FmPcdCcNode *)p_CcNodeInformation->h_CcNode;
++
++        ASSERT_COND(p_NodePtrOnCurrentMdfNode);
++
++        /* Search in the previous node which exact index points on this current modified node for getting AD */
++        for (i = 0; i < p_NodePtrOnCurrentMdfNode->numOfKeys + 1; i++)
++        {
++            if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine
++                    == e_FM_PCD_CC)
++            {
++                if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode
++                        == (t_Handle)p_CrntMdfNode)
++                {
++                    if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip)
++                        p_AdTablePtOnCrntCurrentMdfNode = p_CrntMdfNode->h_Ad;
++                    else
++                        if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].p_StatsObj)
++                            p_AdTablePtOnCrntCurrentMdfNode =
++                                    p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].p_StatsObj->h_StatsAd;
++                        else
++                            p_AdTablePtOnCrntCurrentMdfNode =
++                                    PTR_MOVE(p_NodePtrOnCurrentMdfNode->h_AdTable, i*FM_PCD_CC_AD_ENTRY_SIZE);
++
++                    memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
++                    ccNodeInfo.h_CcNode = p_AdTablePtOnCrntCurrentMdfNode;
++                    EnqueueNodeInfoToRelevantLst(h_OldLst, &ccNodeInfo, NULL);
++
++                    if (!(*p_NextEngineParams))
++                        *p_NextEngineParams =
++                                &p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams;
++                }
++            }
++        }
++
++        ASSERT_COND(i != p_NodePtrOnCurrentMdfNode->numOfKeys);
++    }
++}
++
++static void UpdateAdPtrOfTreesWhichPointsOnCrntMdfNode(
++        t_FmPcdCcNode *p_CrntMdfNode, t_List *h_OldLst,
++        t_FmPcdCcNextEngineParams **p_NextEngineParams)
++{
++    t_CcNodeInformation *p_CcNodeInformation;
++    t_FmPcdCcTree *p_TreePtrOnCurrentMdfNode = NULL;
++    t_List *p_Pos;
++    int i = 0;
++    t_Handle p_AdTableTmp;
++    t_CcNodeInformation ccNodeInfo;
++
++    LIST_FOR_EACH(p_Pos, &p_CrntMdfNode->ccTreeIdLst)
++    {
++        p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos);
++        p_TreePtrOnCurrentMdfNode =
++                (t_FmPcdCcTree *)p_CcNodeInformation->h_CcNode;
++
++        ASSERT_COND(p_TreePtrOnCurrentMdfNode);
++
++        /*search in the trees which exact index points on this current modified node for getting AD */
++        for (i = 0; i < p_TreePtrOnCurrentMdfNode->numOfEntries; i++)
++        {
++            if (p_TreePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine
++                    == e_FM_PCD_CC)
++            {
++                if (p_TreePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode
++                        == (t_Handle)p_CrntMdfNode)
++                {
++                    p_AdTableTmp =
++                            UINT_TO_PTR(p_TreePtrOnCurrentMdfNode->ccTreeBaseAddr + i*FM_PCD_CC_AD_ENTRY_SIZE);
++                    memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
++                    ccNodeInfo.h_CcNode = p_AdTableTmp;
++                    EnqueueNodeInfoToRelevantLst(h_OldLst, &ccNodeInfo, NULL);
++
++                    if (!(*p_NextEngineParams))
++                        *p_NextEngineParams =
++                                &p_TreePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams;
++                }
++            }
++        }
++
++        ASSERT_COND(i == p_TreePtrOnCurrentMdfNode->numOfEntries);
++    }
++}
++
++static t_FmPcdModifyCcKeyAdditionalParams * ModifyNodeCommonPart(
++        t_Handle h_FmPcdCcNodeOrTree, uint16_t keyIndex,
++        e_ModifyState modifyState, bool ttlCheck, bool hashCheck, bool tree)
++{
++    t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams;
++    int i = 0, j = 0;
++    bool wasUpdate = FALSE;
++    t_FmPcdCcNode *p_CcNode = NULL;
++    t_FmPcdCcTree *p_FmPcdCcTree;
++    uint16_t numOfKeys;
++    t_FmPcdCcKeyAndNextEngineParams *p_KeyAndNextEngineParams;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmPcdCcNodeOrTree, E_INVALID_HANDLE, NULL);
++
++    if (!tree)
++    {
++        p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNodeOrTree;
++        numOfKeys = p_CcNode->numOfKeys;
++
++        /* node has to be pointed by another node or tree */
++
++        p_KeyAndNextEngineParams = (t_FmPcdCcKeyAndNextEngineParams *)XX_Malloc(
++                sizeof(t_FmPcdCcKeyAndNextEngineParams) * (numOfKeys + 1));
++        if (!p_KeyAndNextEngineParams)
++        {
++            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Next engine and required action structure"));
++            return NULL;
++        }
++        memcpy(p_KeyAndNextEngineParams, p_CcNode->keyAndNextEngineParams,
++               (numOfKeys + 1) * sizeof(t_FmPcdCcKeyAndNextEngineParams));
++
++        if (ttlCheck)
++        {
++            if ((p_CcNode->parseCode == CC_PC_FF_IPV4TTL)
++                    || (p_CcNode->parseCode == CC_PC_FF_IPV6HOP_LIMIT))
++            {
++                XX_Free(p_KeyAndNextEngineParams);
++                REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("nodeId of CC_PC_FF_IPV4TTL or CC_PC_FF_IPV6HOP_LIMIT can not be used for this operation"));
++                return NULL;
++            }
++        }
++
++        if (hashCheck)
++        {
++            if (p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED)
++            {
++                XX_Free(p_KeyAndNextEngineParams);
++                REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("nodeId of CC_PC_GENERIC_IC_HASH_INDEXED can not be used for this operation"));
++                return NULL;
++            }
++        }
++    }
++    else
++    {
++        p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcNodeOrTree;
++        numOfKeys = p_FmPcdCcTree->numOfEntries;
++
++        p_KeyAndNextEngineParams = (t_FmPcdCcKeyAndNextEngineParams *)XX_Malloc(
++                sizeof(t_FmPcdCcKeyAndNextEngineParams)
++                        * FM_PCD_MAX_NUM_OF_CC_GROUPS);
++        if (!p_KeyAndNextEngineParams)
++        {
++            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Next engine and required action structure"));
++            return NULL;
++        }
++        memcpy(p_KeyAndNextEngineParams,
++               p_FmPcdCcTree->keyAndNextEngineParams,
++               FM_PCD_MAX_NUM_OF_CC_GROUPS
++                       * sizeof(t_FmPcdCcKeyAndNextEngineParams));
++    }
++
++    p_FmPcdModifyCcKeyAdditionalParams =
++            (t_FmPcdModifyCcKeyAdditionalParams *)XX_Malloc(
++                    sizeof(t_FmPcdModifyCcKeyAdditionalParams));
++    if (!p_FmPcdModifyCcKeyAdditionalParams)
++    {
++        XX_Free(p_KeyAndNextEngineParams);
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Allocation of internal data structure FAILED"));
++        return NULL;
++    }
++    memset(p_FmPcdModifyCcKeyAdditionalParams, 0,
++           sizeof(t_FmPcdModifyCcKeyAdditionalParams));
++
++    p_FmPcdModifyCcKeyAdditionalParams->h_CurrentNode = h_FmPcdCcNodeOrTree;
++    p_FmPcdModifyCcKeyAdditionalParams->savedKeyIndex = keyIndex;
++
++    while (i < numOfKeys)
++    {
++        if ((j == keyIndex) && !wasUpdate)
++        {
++            if (modifyState == e_MODIFY_STATE_ADD)
++                j++;
++            else
++                if (modifyState == e_MODIFY_STATE_REMOVE)
++                    i++;
++            wasUpdate = TRUE;
++        }
++        else
++        {
++            memcpy(&p_FmPcdModifyCcKeyAdditionalParams->keyAndNextEngineParams[j],
++                   p_KeyAndNextEngineParams + i,
++                   sizeof(t_FmPcdCcKeyAndNextEngineParams));
++            i++;
++            j++;
++        }
++    }
++
++    if (keyIndex == numOfKeys)
++    {
++        if (modifyState == e_MODIFY_STATE_ADD)
++            j++;
++    }
++
++    memcpy(&p_FmPcdModifyCcKeyAdditionalParams->keyAndNextEngineParams[j],
++           p_KeyAndNextEngineParams + numOfKeys,
++           sizeof(t_FmPcdCcKeyAndNextEngineParams));
++
++    XX_Free(p_KeyAndNextEngineParams);
++
++    return p_FmPcdModifyCcKeyAdditionalParams;
++}
++
++static t_Error UpdatePtrWhichPointOnCrntMdfNode(
++        t_FmPcdCcNode *p_CcNode,
++        t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams,
++        t_List *h_OldLst, t_List *h_NewLst)
++{
++    t_FmPcdCcNextEngineParams *p_NextEngineParams = NULL;
++    t_CcNodeInformation ccNodeInfo = { 0 };
++    t_Handle h_NewAd;
++    t_Handle h_OrigAd = NULL;
++
++    /* Building a list of all action descriptors that point to the previous node */
++    if (!LIST_IsEmpty(&p_CcNode->ccPrevNodesLst))
++        UpdateAdPtrOfNodesWhichPointsOnCrntMdfNode(p_CcNode, h_OldLst,
++                                                   &p_NextEngineParams);
++
++    if (!LIST_IsEmpty(&p_CcNode->ccTreeIdLst))
++        UpdateAdPtrOfTreesWhichPointsOnCrntMdfNode(p_CcNode, h_OldLst,
++                                                   &p_NextEngineParams);
++
++    /* This node must be found as next engine of one of its previous nodes or trees*/
++    if (p_NextEngineParams)
++    {
++        /* Building a new action descriptor that points to the modified node */
++        h_NewAd = GetNewAd(p_CcNode, FALSE);
++        if (!h_NewAd)
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++        MemSet8(h_NewAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++        h_OrigAd = p_CcNode->h_Ad;
++        BuildNewAd(h_NewAd, p_FmPcdModifyCcKeyAdditionalParams, p_CcNode,
++                   p_NextEngineParams);
++
++        ccNodeInfo.h_CcNode = h_NewAd;
++        EnqueueNodeInfoToRelevantLst(h_NewLst, &ccNodeInfo, NULL);
++
++        if (p_NextEngineParams->h_Manip && !h_OrigAd)
++            FmPcdManipUpdateOwner(p_NextEngineParams->h_Manip, FALSE);
++    }
++    return E_OK;
++}
++
++static void UpdateCcRootOwner(t_FmPcdCcTree *p_FmPcdCcTree, bool add)
++{
++    ASSERT_COND(p_FmPcdCcTree);
++
++    /* this routine must be protected by the calling routine! */
++
++    if (add)
++        p_FmPcdCcTree->owners++;
++    else
++    {
++        ASSERT_COND(p_FmPcdCcTree->owners);
++        p_FmPcdCcTree->owners--;
++    }
++}
++
++static t_Error CheckAndSetManipParamsWithCcNodeParams(t_FmPcdCcNode *p_CcNode)
++{
++    t_Error err = E_OK;
++    int i = 0;
++
++    for (i = 0; i < p_CcNode->numOfKeys; i++)
++    {
++        if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip)
++        {
++            err =
++                    FmPcdManipCheckParamsWithCcNodeParams(
++                            p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip,
++                            (t_Handle)p_CcNode);
++            if (err)
++                return err;
++        }
++    }
++
++    return err;
++}
++static t_Error ValidateAndCalcStatsParams(t_FmPcdCcNode *p_CcNode,
++                                          t_FmPcdCcNodeParams *p_CcNodeParam,
++                                          uint32_t *p_NumOfRanges,
++                                          uint32_t *p_CountersArraySize)
++{
++    e_FmPcdCcStatsMode statisticsMode = p_CcNode->statisticsMode;
++    uint32_t i;
++
++    UNUSED(p_CcNodeParam);
++
++    switch (statisticsMode)
++    {
++        case e_FM_PCD_CC_STATS_MODE_NONE:
++            for (i = 0; i < p_CcNode->numOfKeys; i++)
++                if (p_CcNodeParam->keysParams.keyParams[i].ccNextEngineParams.statisticsEn)
++                    RETURN_ERROR(
++                            MAJOR,
++                            E_INVALID_VALUE,
++                            ("Statistics cannot be enabled for key %d when statistics mode was set to 'NONE'", i));
++            return E_OK;
++
++        case e_FM_PCD_CC_STATS_MODE_FRAME:
++        case e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME:
++            *p_NumOfRanges = 1;
++            *p_CountersArraySize = 2 * FM_PCD_CC_STATS_COUNTER_SIZE;
++            return E_OK;
++
++#if (DPAA_VERSION >= 11)
++        case e_FM_PCD_CC_STATS_MODE_RMON:
++        {
++            uint16_t *p_FrameLengthRanges =
++                    p_CcNodeParam->keysParams.frameLengthRanges;
++            uint32_t i;
++
++            if (p_FrameLengthRanges[0] <= 0)
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Statistics mode"));
++
++            if (p_FrameLengthRanges[0] == 0xFFFF)
++            {
++                *p_NumOfRanges = 1;
++                *p_CountersArraySize = 2 * FM_PCD_CC_STATS_COUNTER_SIZE;
++                return E_OK;
++            }
++
++            for (i = 1; i < FM_PCD_CC_STATS_MAX_NUM_OF_FLR; i++)
++            {
++                if (p_FrameLengthRanges[i - 1] >= p_FrameLengthRanges[i])
++                    RETURN_ERROR(
++                            MAJOR,
++                            E_INVALID_VALUE,
++                            ("Frame length range must be larger at least by 1 from preceding range"));
++
++                /* Stop when last range is reached */
++                if (p_FrameLengthRanges[i] == 0xFFFF)
++                    break;
++            }
++
++            if ((i >= FM_PCD_CC_STATS_MAX_NUM_OF_FLR)
++                    || (p_FrameLengthRanges[i] != 0xFFFF))
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                             ("Last Frame length range must be 0xFFFF"));
++
++            *p_NumOfRanges = i + 1;
++
++            /* Allocate an extra counter for byte count, as counters
++             array always begins with byte count */
++            *p_CountersArraySize = (*p_NumOfRanges + 1)
++                    * FM_PCD_CC_STATS_COUNTER_SIZE;
++
++        }
++            return E_OK;
++#endif /* (DPAA_VERSION >= 11) */
++
++        default:
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Statistics mode"));
++    }
++}
++
++static t_Error CheckParams(t_Handle h_FmPcd, t_FmPcdCcNodeParams *p_CcNodeParam,
++                           t_FmPcdCcNode *p_CcNode, bool *isKeyTblAlloc)
++{
++    int tmp = 0;
++    t_FmPcdCcKeyParams *p_KeyParams;
++    t_Error err;
++    uint32_t requiredAction = 0;
++
++    /* Validate statistics parameters */
++    err = ValidateAndCalcStatsParams(p_CcNode, p_CcNodeParam,
++                                     &(p_CcNode->numOfStatsFLRs),
++                                     &(p_CcNode->countersArraySize));
++    if (err)
++        RETURN_ERROR(MAJOR, err, ("Invalid statistics parameters"));
++
++    /* Validate next engine parameters on Miss */
++    err = ValidateNextEngineParams(
++            h_FmPcd, &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
++            p_CcNode->statisticsMode);
++    if (err)
++        RETURN_ERROR(MAJOR, err,
++                     ("For this node MissNextEngineParams are not valid"));
++
++    if (p_CcNodeParam->keysParams.ccNextEngineParamsForMiss.h_Manip)
++    {
++        err = FmPcdManipCheckParamsForCcNextEngine(
++                &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
++                &requiredAction);
++        if (err)
++            RETURN_ERROR(MAJOR, err, (NO_MSG));
++    }
++
++    memcpy(&p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams,
++           &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
++           sizeof(t_FmPcdCcNextEngineParams));
++
++    p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].requiredAction =
++            requiredAction;
++
++    if ((p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine
++            == e_FM_PCD_CC)
++            && p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.h_Manip)
++    {
++        err =
++                AllocAndFillAdForContLookupManip(
++                        p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.params.ccParams.h_CcNode);
++        if (err)
++            RETURN_ERROR(MAJOR, err, (NO_MSG));
++    }
++
++    for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++)
++    {
++        p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp];
++
++        if (!p_KeyParams->p_Key)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_Key is not initialized"));
++
++        err = ValidateNextEngineParams(h_FmPcd,
++                                       &p_KeyParams->ccNextEngineParams,
++                                       p_CcNode->statisticsMode);
++        if (err)
++            RETURN_ERROR(MAJOR, err, (NO_MSG));
++
++        err = UpdateGblMask(p_CcNode, p_CcNodeParam->keysParams.keySize,
++                            p_KeyParams->p_Mask);
++        if (err)
++            RETURN_ERROR(MAJOR, err, (NO_MSG));
++
++        if (p_KeyParams->ccNextEngineParams.h_Manip)
++        {
++            err = FmPcdManipCheckParamsForCcNextEngine(
++                    &p_KeyParams->ccNextEngineParams, &requiredAction);
++            if (err)
++                RETURN_ERROR(MAJOR, err, (NO_MSG));
++        }
++
++        /* Store 'key' parameters - key, mask (if passed by the user) */
++        memcpy(p_CcNode->keyAndNextEngineParams[tmp].key, p_KeyParams->p_Key,
++               p_CcNodeParam->keysParams.keySize);
++
++        if (p_KeyParams->p_Mask)
++            memcpy(p_CcNode->keyAndNextEngineParams[tmp].mask,
++                   p_KeyParams->p_Mask, p_CcNodeParam->keysParams.keySize);
++        else
++            memset((void *)(p_CcNode->keyAndNextEngineParams[tmp].mask), 0xFF,
++                   p_CcNodeParam->keysParams.keySize);
++
++        /* Store next engine parameters */
++        memcpy(&p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams,
++               &p_KeyParams->ccNextEngineParams,
++               sizeof(t_FmPcdCcNextEngineParams));
++
++        p_CcNode->keyAndNextEngineParams[tmp].requiredAction = requiredAction;
++
++        if ((p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine
++                == e_FM_PCD_CC)
++                && p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip)
++        {
++            err =
++                    AllocAndFillAdForContLookupManip(
++                            p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode);
++            if (err)
++                RETURN_ERROR(MAJOR, err, (NO_MSG));
++        }
++    }
++
++    if (p_CcNode->maxNumOfKeys)
++    {
++        if (p_CcNode->maxNumOfKeys < p_CcNode->numOfKeys)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("Number of keys exceed the provided maximal number of keys"));
++    }
++
++    *isKeyTblAlloc = TRUE;
++
++    return E_OK;
++}
++
++static t_Error Ipv4TtlOrIpv6HopLimitCheckParams(
++        t_Handle h_FmPcd, t_FmPcdCcNodeParams *p_CcNodeParam,
++        t_FmPcdCcNode *p_CcNode, bool *isKeyTblAlloc)
++{
++    int tmp = 0;
++    t_FmPcdCcKeyParams *p_KeyParams;
++    t_Error err;
++    uint8_t key = 0x01;
++    uint32_t requiredAction = 0;
++
++    if (p_CcNode->numOfKeys != 1)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT the maximal supported 'numOfKeys' is 1"));
++
++    if ((p_CcNodeParam->keysParams.maxNumOfKeys)
++            && (p_CcNodeParam->keysParams.maxNumOfKeys != 1))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT the maximal supported 'maxNumOfKeys' is 1"));
++
++    /* Validate statistics parameters */
++    err = ValidateAndCalcStatsParams(p_CcNode, p_CcNodeParam,
++                                     &(p_CcNode->numOfStatsFLRs),
++                                     &(p_CcNode->countersArraySize));
++    if (err)
++        RETURN_ERROR(MAJOR, err, ("Invalid statistics parameters"));
++
++    err = ValidateNextEngineParams(
++            h_FmPcd, &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
++            p_CcNodeParam->keysParams.statisticsMode);
++    if (err)
++        RETURN_ERROR(MAJOR, err,
++                     ("For this node MissNextEngineParams are not valid"));
++
++    if (p_CcNodeParam->keysParams.ccNextEngineParamsForMiss.h_Manip)
++    {
++        err = FmPcdManipCheckParamsForCcNextEngine(
++                &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
++                &requiredAction);
++        if (err)
++            RETURN_ERROR(MAJOR, err, (NO_MSG));
++    }
++
++    memcpy(&p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams,
++           &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
++           sizeof(t_FmPcdCcNextEngineParams));
++
++    p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].requiredAction =
++            requiredAction;
++
++    if ((p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine
++            == e_FM_PCD_CC)
++            && p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.h_Manip)
++    {
++        err =
++                AllocAndFillAdForContLookupManip(
++                        p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.params.ccParams.h_CcNode);
++        if (err)
++            RETURN_ERROR(MAJOR, err, (NO_MSG));
++    }
++
++    for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++)
++    {
++        p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp];
++
++        if (p_KeyParams->p_Mask)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT p_Mask can not be initialized"));
++
++        if (memcmp(p_KeyParams->p_Key, &key, 1) != 0)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT p_Key has to be 1"));
++
++        err = ValidateNextEngineParams(h_FmPcd,
++                                       &p_KeyParams->ccNextEngineParams,
++                                       p_CcNode->statisticsMode);
++        if (err)
++            RETURN_ERROR(MAJOR, err, (NO_MSG));
++
++        if (p_KeyParams->ccNextEngineParams.h_Manip)
++        {
++            err = FmPcdManipCheckParamsForCcNextEngine(
++                    &p_KeyParams->ccNextEngineParams, &requiredAction);
++            if (err)
++                RETURN_ERROR(MAJOR, err, (NO_MSG));
++        }
++
++        /* Store 'key' parameters - key (fixed to 0x01), key size of 1 byte and full mask */
++        p_CcNode->keyAndNextEngineParams[tmp].key[0] = key;
++        p_CcNode->keyAndNextEngineParams[tmp].mask[0] = 0xFF;
++
++        /* Store NextEngine parameters */
++        memcpy(&p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams,
++               &p_KeyParams->ccNextEngineParams,
++               sizeof(t_FmPcdCcNextEngineParams));
++
++        if ((p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine
++                == e_FM_PCD_CC)
++                && p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip)
++        {
++            err =
++                    AllocAndFillAdForContLookupManip(
++                            p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode);
++            if (err)
++                RETURN_ERROR(MAJOR, err, (NO_MSG));
++        }
++        p_CcNode->keyAndNextEngineParams[tmp].requiredAction = requiredAction;
++    }
++
++    *isKeyTblAlloc = FALSE;
++
++    return E_OK;
++}
++
++static t_Error IcHashIndexedCheckParams(t_Handle h_FmPcd,
++                                        t_FmPcdCcNodeParams *p_CcNodeParam,
++                                        t_FmPcdCcNode *p_CcNode,
++                                        bool *isKeyTblAlloc)
++{
++    int tmp = 0, countOnes = 0;
++    t_FmPcdCcKeyParams *p_KeyParams;
++    t_Error err;
++    uint16_t glblMask = p_CcNodeParam->extractCcParams.extractNonHdr.icIndxMask;
++    uint16_t countMask = (uint16_t)(glblMask >> 4);
++    uint32_t requiredAction = 0;
++
++    if (glblMask & 0x000f)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("icIndxMask has to be with last nibble 0"));
++
++    while (countMask)
++    {
++        countOnes++;
++        countMask = (uint16_t)(countMask >> 1);
++    }
++
++    if (!POWER_OF_2(p_CcNode->numOfKeys))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("For Node of the type INDEXED numOfKeys has to be powerOfTwo"));
++
++    if (p_CcNode->numOfKeys != ((uint32_t)1 << countOnes))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("For Node of the type IC_HASH_INDEXED numOfKeys has to be powerOfTwo"));
++
++    if (p_CcNodeParam->keysParams.maxNumOfKeys
++            && (p_CcNodeParam->keysParams.maxNumOfKeys != p_CcNode->numOfKeys))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("For Node of the type INDEXED 'maxNumOfKeys' should be 0 or equal 'numOfKeys'"));
++
++    /* Validate statistics parameters */
++    err = ValidateAndCalcStatsParams(p_CcNode, p_CcNodeParam,
++                                     &(p_CcNode->numOfStatsFLRs),
++                                     &(p_CcNode->countersArraySize));
++    if (err)
++        RETURN_ERROR(MAJOR, err, ("Invalid statistics parameters"));
++
++    err = ValidateNextEngineParams(
++            h_FmPcd, &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
++            p_CcNode->statisticsMode);
++    if (GET_ERROR_TYPE(err) != E_NOT_SUPPORTED)
++        RETURN_ERROR(
++                MAJOR,
++                err,
++                ("MissNextEngineParams for the node of the type IC_INDEX_HASH has to be UnInitialized"));
++
++    for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++)
++    {
++        p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp];
++
++        if (p_KeyParams->p_Mask || p_KeyParams->p_Key)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("For Node of the type IC_HASH_INDEXED p_Key or p_Mask has to be NULL"));
++
++        if ((glblMask & (tmp * 16)) == (tmp * 16))
++        {
++            err = ValidateNextEngineParams(h_FmPcd,
++                                           &p_KeyParams->ccNextEngineParams,
++                                           p_CcNode->statisticsMode);
++            if (err)
++                RETURN_ERROR(
++                        MAJOR,
++                        err,
++                        ("This index has to be initialized for the node of the type IC_INDEX_HASH according to settings of GlobalMask "));
++
++            if (p_KeyParams->ccNextEngineParams.h_Manip)
++            {
++                err = FmPcdManipCheckParamsForCcNextEngine(
++                        &p_KeyParams->ccNextEngineParams, &requiredAction);
++                if (err)
++                    RETURN_ERROR(MAJOR, err, (NO_MSG));
++                p_CcNode->keyAndNextEngineParams[tmp].requiredAction =
++                        requiredAction;
++            }
++
++            memcpy(&p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams,
++                   &p_KeyParams->ccNextEngineParams,
++                   sizeof(t_FmPcdCcNextEngineParams));
++
++            if ((p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine
++                    == e_FM_PCD_CC)
++                    && p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip)
++            {
++                err =
++                        AllocAndFillAdForContLookupManip(
++                                p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode);
++                if (err)
++                    RETURN_ERROR(MAJOR, err, (NO_MSG));
++            }
++        }
++        else
++        {
++            err = ValidateNextEngineParams(h_FmPcd,
++                                           &p_KeyParams->ccNextEngineParams,
++                                           p_CcNode->statisticsMode);
++            if (GET_ERROR_TYPE(err) != E_NOT_SUPPORTED)
++                RETURN_ERROR(
++                        MAJOR,
++                        err,
++                        ("This index has to be UnInitialized for the node of the type IC_INDEX_HASH according to settings of GlobalMask"));
++        }
++    }
++
++    *isKeyTblAlloc = FALSE;
++    cpu_to_be16s(&glblMask);
++    memcpy(PTR_MOVE(p_CcNode->p_GlblMask, 2), &glblMask, 2);
++
++    return E_OK;
++}
++
++static t_Error ModifyNextEngineParamNode(
++        t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint16_t keyIndex,
++        t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode;
++    t_FmPcd *p_FmPcd;
++    t_List h_OldPointersLst, h_NewPointersLst;
++    t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_VALUE);
++    SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
++
++    if (keyIndex >= p_CcNode->numOfKeys)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                     ("keyIndex > previously cleared last index + 1"));
++
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++
++    INIT_LIST(&h_OldPointersLst);
++    INIT_LIST(&h_NewPointersLst);
++
++    p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex,
++                                             e_MODIFY_STATE_CHANGE, FALSE,
++                                             FALSE, FALSE);
++    if (!p_ModifyKeyParams)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++
++    if (p_CcNode->maxNumOfKeys
++            && !TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
++    {
++        XX_Free(p_ModifyKeyParams);
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = BuildNewNodeModifyNextEngine(h_FmPcd, p_CcNode, keyIndex,
++                                       p_FmPcdCcNextEngineParams,
++                                       &h_OldPointersLst, &h_NewPointersLst,
++                                       p_ModifyKeyParams);
++    if (err)
++    {
++        XX_Free(p_ModifyKeyParams);
++        if (p_CcNode->maxNumOfKeys)
++            RELEASE_LOCK(p_FmPcd->shadowLock);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst,
++                          p_ModifyKeyParams, FALSE);
++
++    if (p_CcNode->maxNumOfKeys)
++        RELEASE_LOCK(p_FmPcd->shadowLock);
++
++      ReleaseLst(&h_OldPointersLst);
++      ReleaseLst(&h_NewPointersLst);
++
++    return err;
++}
++
++static t_Error FindKeyIndex(t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key,
++                            uint8_t *p_Mask, uint16_t *p_KeyIndex)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    uint8_t tmpMask[FM_PCD_MAX_SIZE_OF_KEY];
++    uint16_t i;
++
++    ASSERT_COND(p_Key);
++    ASSERT_COND(p_KeyIndex);
++    ASSERT_COND(keySize < FM_PCD_MAX_SIZE_OF_KEY);
++
++    if (keySize != p_CcNode->userSizeOfExtraction)
++        RETURN_ERROR(
++                MINOR, E_INVALID_VALUE,
++                ("Key size doesn't match the extraction size of the node"));
++
++    /* If user didn't pass a mask for this key, we'll look for full extraction mask */
++    if (!p_Mask)
++        memset(tmpMask, 0xFF, keySize);
++
++    for (i = 0; i < p_CcNode->numOfKeys; i++)
++    {
++        /* Comparing received key */
++        if (memcmp(p_Key, p_CcNode->keyAndNextEngineParams[i].key, keySize)
++                == 0)
++        {
++            if (p_Mask)
++            {
++                /* If a user passed a mask for this key, it must match to the existing key's mask for a correct match */
++                if (memcmp(p_Mask, p_CcNode->keyAndNextEngineParams[i].mask,
++                           keySize) == 0)
++                {
++                    *p_KeyIndex = i;
++                    return E_OK;
++                }
++            }
++            else
++            {
++                /* If user didn't pass a mask for this key, check if the existing key mask is full extraction */
++                if (memcmp(tmpMask, p_CcNode->keyAndNextEngineParams[i].mask,
++                           keySize) == 0)
++                {
++                    *p_KeyIndex = i;
++                    return E_OK;
++                }
++            }
++        }
++    }
++
++    return ERROR_CODE(E_NOT_FOUND);
++}
++
++static t_Error CalcAndUpdateCcShadow(t_FmPcdCcNode *p_CcNode,
++                                     bool isKeyTblAlloc,
++                                     uint32_t *p_MatchTableSize,
++                                     uint32_t *p_AdTableSize)
++{
++    uint32_t shadowSize;
++    t_Error err;
++
++    /* Calculate keys table maximal size - each entry consists of a key and a mask,
++     (if local mask support is requested) */
++    *p_MatchTableSize = p_CcNode->ccKeySizeAccExtraction * sizeof(uint8_t)
++            * p_CcNode->maxNumOfKeys;
++
++    if (p_CcNode->maskSupport)
++        *p_MatchTableSize *= 2;
++
++    /* Calculate next action descriptors table, including one more entry for miss */
++    *p_AdTableSize = (uint32_t)((p_CcNode->maxNumOfKeys + 1)
++            * FM_PCD_CC_AD_ENTRY_SIZE);
++
++    /* Calculate maximal shadow size of this node.
++     All shadow structures will be used for runtime modifications host command. If
++     keys table was allocated for this node, the keys table and next engines table may
++     be modified in run time (entries added or removed), so shadow tables are requires.
++     Otherwise, the only supported runtime modification is a specific next engine update
++     and this requires shadow memory of a single AD */
++
++    /* Shadow size should be enough to hold the following 3 structures:
++     * 1 - an action descriptor */
++    shadowSize = FM_PCD_CC_AD_ENTRY_SIZE;
++
++    /* 2 - keys match table, if was allocated for the current node */
++    if (isKeyTblAlloc)
++        shadowSize += *p_MatchTableSize;
++
++    /* 3 - next action descriptors table */
++    shadowSize += *p_AdTableSize;
++
++    /* Update shadow to the calculated size */
++    err = FmPcdUpdateCcShadow(p_CcNode->h_FmPcd, (uint32_t)shadowSize,
++                              FM_PCD_CC_AD_TABLE_ALIGN);
++    if (err != E_OK)
++    {
++        DeleteNode(p_CcNode);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC node shadow"));
++    }
++
++    return E_OK;
++}
++
++static t_Error AllocStatsObjs(t_FmPcdCcNode *p_CcNode)
++{
++    t_FmPcdStatsObj *p_StatsObj;
++    t_Handle h_FmMuram, h_StatsAd, h_StatsCounters;
++    uint32_t i;
++
++    h_FmMuram = FmPcdGetMuramHandle(p_CcNode->h_FmPcd);
++    if (!h_FmMuram)
++        RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM MURAM"));
++
++    /* Allocate statistics ADs and statistics counter. An extra pair (AD + counters)
++     will be allocated to support runtime modifications */
++    for (i = 0; i < p_CcNode->maxNumOfKeys + 2; i++)
++    {
++        /* Allocate list object structure */
++        p_StatsObj = XX_Malloc(sizeof(t_FmPcdStatsObj));
++        if (!p_StatsObj)
++        {
++            FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram);
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Statistics object"));
++        }
++        memset(p_StatsObj, 0, sizeof(t_FmPcdStatsObj));
++
++        /* Allocate statistics AD from MURAM */
++        h_StatsAd = (t_Handle)FM_MURAM_AllocMem(h_FmMuram,
++                                                FM_PCD_CC_AD_ENTRY_SIZE,
++                                                FM_PCD_CC_AD_TABLE_ALIGN);
++        if (!h_StatsAd)
++        {
++            FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram);
++            XX_Free(p_StatsObj);
++            RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                         ("MURAM allocation for statistics ADs"));
++        }
++        MemSet8(h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++        /* Allocate statistics counters from MURAM */
++        h_StatsCounters = (t_Handle)FM_MURAM_AllocMem(
++                h_FmMuram, p_CcNode->countersArraySize,
++                FM_PCD_CC_AD_TABLE_ALIGN);
++        if (!h_StatsCounters)
++        {
++            FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram);
++            FM_MURAM_FreeMem(h_FmMuram, h_StatsAd);
++            XX_Free(p_StatsObj);
++            RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                         ("MURAM allocation for statistics counters"));
++        }
++        MemSet8(h_StatsCounters, 0, p_CcNode->countersArraySize);
++
++        p_StatsObj->h_StatsAd = h_StatsAd;
++        p_StatsObj->h_StatsCounters = h_StatsCounters;
++
++        EnqueueStatsObj(&p_CcNode->availableStatsLst, p_StatsObj);
++    }
++
++    return E_OK;
++}
++
++static t_Error MatchTableGetKeyStatistics(
++        t_FmPcdCcNode *p_CcNode, uint16_t keyIndex,
++        t_FmPcdCcKeyStatistics *p_KeyStatistics)
++{
++    uint32_t *p_StatsCounters, i;
++
++    if (p_CcNode->statisticsMode == e_FM_PCD_CC_STATS_MODE_NONE)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                     ("Statistics were not enabled for this match table"));
++
++    if (!p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                     ("Statistics were not enabled for this key"));
++
++    memset(p_KeyStatistics, 0, sizeof(t_FmPcdCcKeyStatistics));
++
++    p_StatsCounters =
++            p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsCounters;
++    ASSERT_COND(p_StatsCounters);
++
++    p_KeyStatistics->byteCount = GET_UINT32(*p_StatsCounters);
++
++    for (i = 1; i <= p_CcNode->numOfStatsFLRs; i++)
++    {
++        p_StatsCounters =
++                PTR_MOVE(p_StatsCounters, FM_PCD_CC_STATS_COUNTER_SIZE);
++
++        p_KeyStatistics->frameCount += GET_UINT32(*p_StatsCounters);
++
++#if (DPAA_VERSION >= 11)
++        p_KeyStatistics->frameLengthRangeCount[i - 1] =
++                GET_UINT32(*p_StatsCounters);
++#endif /* (DPAA_VERSION >= 11) */
++    }
++
++    return E_OK;
++}
++
++static t_Error MatchTableSet(t_Handle h_FmPcd, t_FmPcdCcNode *p_CcNode,
++                             t_FmPcdCcNodeParams *p_CcNodeParam)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    t_FmPcdCcNode *p_FmPcdCcNextNode;
++    t_Error err = E_OK;
++    uint32_t tmp, keySize;
++    bool glblMask = FALSE;
++    t_FmPcdCcKeyParams *p_KeyParams;
++    t_Handle h_FmMuram, p_KeysMatchTblTmp, p_AdTableTmp;
++#if (DPAA_VERSION >= 11)
++    t_Handle h_StatsFLRs;
++#endif /* (DPAA_VERSION >= 11) */
++    bool fullField = FALSE;
++    ccPrivateInfo_t icCode = CC_PRIVATE_INFO_NONE;
++    bool isKeyTblAlloc, fromIc = FALSE;
++    uint32_t matchTableSize, adTableSize;
++    t_CcNodeInformation ccNodeInfo, *p_CcInformation;
++    t_FmPcdStatsObj *p_StatsObj;
++    t_FmPcdCcStatsParams statsParams = { 0 };
++    t_Handle h_Manip;
++
++    ASSERT_COND(h_FmPcd);
++    ASSERT_COND(p_CcNode);
++    ASSERT_COND(p_CcNodeParam);
++
++    p_CcNode->p_GlblMask = (t_Handle)XX_Malloc(
++            CC_GLBL_MASK_SIZE * sizeof(uint8_t));
++    memset(p_CcNode->p_GlblMask, 0, CC_GLBL_MASK_SIZE * sizeof(uint8_t));
++
++    p_CcNode->h_FmPcd = h_FmPcd;
++    p_CcNode->numOfKeys = p_CcNodeParam->keysParams.numOfKeys;
++    p_CcNode->maxNumOfKeys = p_CcNodeParam->keysParams.maxNumOfKeys;
++    p_CcNode->maskSupport = p_CcNodeParam->keysParams.maskSupport;
++    p_CcNode->statisticsMode = p_CcNodeParam->keysParams.statisticsMode;
++
++    /* For backward compatibility - even if statistics mode is nullified,
++     we'll fix it to frame mode so we can support per-key request for
++     statistics using 'statisticsEn' in next engine parameters */
++    if (!p_CcNode->maxNumOfKeys
++            && (p_CcNode->statisticsMode == e_FM_PCD_CC_STATS_MODE_NONE))
++        p_CcNode->statisticsMode = e_FM_PCD_CC_STATS_MODE_FRAME;
++
++    h_FmMuram = FmPcdGetMuramHandle(h_FmPcd);
++    if (!h_FmMuram)
++        RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM MURAM"));
++
++    INIT_LIST(&p_CcNode->ccPrevNodesLst);
++    INIT_LIST(&p_CcNode->ccTreeIdLst);
++    INIT_LIST(&p_CcNode->ccTreesLst);
++    INIT_LIST(&p_CcNode->availableStatsLst);
++
++    p_CcNode->h_Spinlock = XX_InitSpinlock();
++    if (!p_CcNode->h_Spinlock)
++    {
++        DeleteNode(p_CcNode);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("CC node spinlock"));
++    }
++
++    if ((p_CcNodeParam->extractCcParams.type == e_FM_PCD_EXTRACT_BY_HDR)
++            && ((p_CcNodeParam->extractCcParams.extractByHdr.hdr
++                    == HEADER_TYPE_IPv4)
++                    || (p_CcNodeParam->extractCcParams.extractByHdr.hdr
++                            == HEADER_TYPE_IPv6))
++            && (p_CcNodeParam->extractCcParams.extractByHdr.type
++                    == e_FM_PCD_EXTRACT_FULL_FIELD)
++            && ((p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField.ipv6
++                    == NET_HEADER_FIELD_IPv6_HOP_LIMIT)
++                    || (p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField.ipv4
++                            == NET_HEADER_FIELD_IPv4_TTL)))
++    {
++        err = Ipv4TtlOrIpv6HopLimitCheckParams(h_FmPcd, p_CcNodeParam, p_CcNode,
++                                               &isKeyTblAlloc);
++        glblMask = FALSE;
++    }
++    else
++        if ((p_CcNodeParam->extractCcParams.type == e_FM_PCD_EXTRACT_NON_HDR)
++                && ((p_CcNodeParam->extractCcParams.extractNonHdr.src
++                        == e_FM_PCD_EXTRACT_FROM_KEY)
++                        || (p_CcNodeParam->extractCcParams.extractNonHdr.src
++                                == e_FM_PCD_EXTRACT_FROM_HASH)
++                        || (p_CcNodeParam->extractCcParams.extractNonHdr.src
++                                == e_FM_PCD_EXTRACT_FROM_FLOW_ID)))
++        {
++            if ((p_CcNodeParam->extractCcParams.extractNonHdr.src
++                    == e_FM_PCD_EXTRACT_FROM_FLOW_ID)
++                    && (p_CcNodeParam->extractCcParams.extractNonHdr.offset != 0))
++            {
++                DeleteNode(p_CcNode);
++                RETURN_ERROR(
++                        MAJOR,
++                        E_INVALID_VALUE,
++                        ("In the case of the extraction from e_FM_PCD_EXTRACT_FROM_FLOW_ID offset has to be 0"));
++            }
++
++            icCode = IcDefineCode(p_CcNodeParam);
++            fromIc = TRUE;
++            if (icCode == CC_PRIVATE_INFO_NONE)
++            {
++                DeleteNode(p_CcNode);
++                RETURN_ERROR(
++                        MAJOR,
++                        E_INVALID_STATE,
++                        ("user asked extraction from IC and field in internal context or action wasn't initialized in the right way"));
++            }
++
++            if ((icCode == CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP)
++                    || (icCode == CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP))
++            {
++                err = IcHashIndexedCheckParams(h_FmPcd, p_CcNodeParam, p_CcNode,
++                                               &isKeyTblAlloc);
++                glblMask = TRUE;
++            }
++            else
++            {
++                err = CheckParams(h_FmPcd, p_CcNodeParam, p_CcNode,
++                                  &isKeyTblAlloc);
++                if (p_CcNode->glblMaskSize)
++                    glblMask = TRUE;
++            }
++        }
++        else
++        {
++            err = CheckParams(h_FmPcd, p_CcNodeParam, p_CcNode, &isKeyTblAlloc);
++            if (p_CcNode->glblMaskSize)
++                glblMask = TRUE;
++        }
++
++    if (err)
++    {
++        DeleteNode(p_CcNode);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    switch (p_CcNodeParam->extractCcParams.type)
++    {
++        case (e_FM_PCD_EXTRACT_BY_HDR):
++            switch (p_CcNodeParam->extractCcParams.extractByHdr.type)
++            {
++                case (e_FM_PCD_EXTRACT_FULL_FIELD):
++                    p_CcNode->parseCode =
++                            GetFullFieldParseCode(
++                                    p_CcNodeParam->extractCcParams.extractByHdr.hdr,
++                                    p_CcNodeParam->extractCcParams.extractByHdr.hdrIndex,
++                                    p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField);
++                    GetSizeHeaderField(
++                            p_CcNodeParam->extractCcParams.extractByHdr.hdr,
++                            p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField,
++                            &p_CcNode->sizeOfExtraction);
++                    fullField = TRUE;
++                    if ((p_CcNode->parseCode != CC_PC_FF_TCI1)
++                            && (p_CcNode->parseCode != CC_PC_FF_TCI2)
++                            && (p_CcNode->parseCode != CC_PC_FF_MPLS1)
++                            && (p_CcNode->parseCode != CC_PC_FF_MPLS_LAST)
++                            && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC1)
++                            && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC2)
++                            && (p_CcNode->parseCode
++                                    != CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1)
++                            && (p_CcNode->parseCode != CC_PC_FF_IPDSCP)
++                            && (p_CcNode->parseCode
++                                    != CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2)
++                            && glblMask)
++                    {
++                        glblMask = FALSE;
++                        p_CcNode->glblMaskSize = 4;
++                        p_CcNode->lclMask = TRUE;
++                    }
++                    break;
++
++                case (e_FM_PCD_EXTRACT_FROM_HDR):
++                    p_CcNode->sizeOfExtraction =
++                            p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromHdr.size;
++                    p_CcNode->offset =
++                            p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromHdr.offset;
++                    p_CcNode->userOffset =
++                            p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromHdr.offset;
++                    p_CcNode->parseCode =
++                            GetPrParseCode(
++                                    p_CcNodeParam->extractCcParams.extractByHdr.hdr,
++                                    p_CcNodeParam->extractCcParams.extractByHdr.hdrIndex,
++                                    p_CcNode->offset, glblMask,
++                                    &p_CcNode->prsArrayOffset);
++                    break;
++
++                case (e_FM_PCD_EXTRACT_FROM_FIELD):
++                    p_CcNode->offset =
++                            p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.offset;
++                    p_CcNode->userOffset =
++                            p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.offset;
++                    p_CcNode->sizeOfExtraction =
++                            p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.size;
++                    p_CcNode->parseCode =
++                            GetFieldParseCode(
++                                    p_CcNodeParam->extractCcParams.extractByHdr.hdr,
++                                    p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.field,
++                                    p_CcNode->offset,
++                                    &p_CcNode->prsArrayOffset,
++                                    p_CcNodeParam->extractCcParams.extractByHdr.hdrIndex);
++                    break;
++
++                default:
++                    DeleteNode(p_CcNode);
++                    RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++            }
++            break;
++
++        case (e_FM_PCD_EXTRACT_NON_HDR):
++            /* get the field code for the generic extract */
++            p_CcNode->sizeOfExtraction =
++                    p_CcNodeParam->extractCcParams.extractNonHdr.size;
++            p_CcNode->offset =
++                    p_CcNodeParam->extractCcParams.extractNonHdr.offset;
++            p_CcNode->userOffset =
++                    p_CcNodeParam->extractCcParams.extractNonHdr.offset;
++            p_CcNode->parseCode = GetGenParseCode(
++                    p_CcNodeParam->extractCcParams.extractNonHdr.src,
++                    p_CcNode->offset, glblMask, &p_CcNode->prsArrayOffset,
++                    fromIc, icCode);
++
++            if (p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED)
++            {
++                if ((p_CcNode->offset + p_CcNode->sizeOfExtraction) > 8)
++                {
++                    DeleteNode(p_CcNode);
++                    RETURN_ERROR(
++                            MAJOR,
++                            E_INVALID_SELECTION,
++                            ("when node of the type CC_PC_GENERIC_IC_HASH_INDEXED offset + size can not be bigger then size of HASH 64 bits (8 bytes)"));
++                }
++            }
++            if ((p_CcNode->parseCode == CC_PC_GENERIC_IC_GMASK)
++                    || (p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED))
++            {
++                p_CcNode->offset += p_CcNode->prsArrayOffset;
++                p_CcNode->prsArrayOffset = 0;
++            }
++            break;
++
++        default:
++            DeleteNode(p_CcNode);
++            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++    }
++
++    if (p_CcNode->parseCode == CC_PC_ILLEGAL)
++    {
++        DeleteNode(p_CcNode);
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("illegal extraction type"));
++    }
++
++    if ((p_CcNode->sizeOfExtraction > FM_PCD_MAX_SIZE_OF_KEY)
++            || !p_CcNode->sizeOfExtraction)
++    {
++        DeleteNode(p_CcNode);
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("sizeOfExatrction can not be greater than 56 and not 0"));
++    }
++
++    if (p_CcNodeParam->keysParams.keySize != p_CcNode->sizeOfExtraction)
++    {
++        DeleteNode(p_CcNode);
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("keySize has to be equal to sizeOfExtraction"));
++    }
++
++    p_CcNode->userSizeOfExtraction = p_CcNode->sizeOfExtraction;
++
++    if (!glblMask)
++        memset(p_CcNode->p_GlblMask, 0xff, CC_GLBL_MASK_SIZE * sizeof(uint8_t));
++
++    err = CheckAndSetManipParamsWithCcNodeParams(p_CcNode);
++    if (err != E_OK)
++    {
++        DeleteNode(p_CcNode);
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("keySize has to be equal to sizeOfExtraction"));
++    }
++
++    /* Calculating matching table entry size by rounding up the user-defined size of extraction to valid entry size */
++    GetCcExtractKeySize(p_CcNode->sizeOfExtraction,
++                        &p_CcNode->ccKeySizeAccExtraction);
++
++    /* If local mask is used, it is stored next to each key in the keys match table */
++    if (p_CcNode->lclMask)
++        keySize = (uint32_t)(2 * p_CcNode->ccKeySizeAccExtraction);
++    else
++        keySize = p_CcNode->ccKeySizeAccExtraction;
++
++    /* Update CC shadow with maximal size required by this node */
++    if (p_CcNode->maxNumOfKeys)
++    {
++        err = CalcAndUpdateCcShadow(p_CcNode, isKeyTblAlloc, &matchTableSize,
++                                    &adTableSize);
++        if (err != E_OK)
++        {
++            DeleteNode(p_CcNode);
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        }
++
++        p_CcNode->keysMatchTableMaxSize = matchTableSize;
++
++        if (p_CcNode->statisticsMode != e_FM_PCD_CC_STATS_MODE_NONE)
++        {
++            err = AllocStatsObjs(p_CcNode);
++            if (err != E_OK)
++            {
++                DeleteNode(p_CcNode);
++                RETURN_ERROR(MAJOR, err, NO_MSG);
++            }
++        }
++
++        /* If manipulation will be initialized before this node, it will use the table
++         descriptor in the AD table of previous node and this node will need an extra
++         AD as his table descriptor. */
++        p_CcNode->h_TmpAd = (t_Handle)FM_MURAM_AllocMem(
++                h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE, FM_PCD_CC_AD_TABLE_ALIGN);
++        if (!p_CcNode->h_TmpAd)
++        {
++            DeleteNode(p_CcNode);
++            RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                         ("MURAM allocation for CC action descriptor"));
++        }
++    }
++    else
++    {
++        matchTableSize = (uint32_t)(keySize * sizeof(uint8_t)
++                * (p_CcNode->numOfKeys + 1));
++        adTableSize = (uint32_t)(FM_PCD_CC_AD_ENTRY_SIZE
++                * (p_CcNode->numOfKeys + 1));
++    }
++
++#if (DPAA_VERSION >= 11)
++    switch (p_CcNode->statisticsMode)
++    {
++
++        case e_FM_PCD_CC_STATS_MODE_RMON:
++            /* If RMON statistics or RMON conditional statistics modes are requested,
++             allocate frame length ranges array */
++            p_CcNode->h_StatsFLRs = FM_MURAM_AllocMem(
++                    h_FmMuram,
++                    (uint32_t)(p_CcNode->numOfStatsFLRs)
++                            * FM_PCD_CC_STATS_FLR_SIZE,
++                    FM_PCD_CC_AD_TABLE_ALIGN);
++
++            if (!p_CcNode->h_StatsFLRs)
++            {
++                DeleteNode(p_CcNode);
++                RETURN_ERROR(
++                        MAJOR, E_NO_MEMORY,
++                        ("MURAM allocation for CC frame length ranges array"));
++            }
++
++            /* Initialize using value received from the user */
++            for (tmp = 0; tmp < p_CcNode->numOfStatsFLRs; tmp++)
++            {
++                uint16_t flr =
++                         cpu_to_be16(p_CcNodeParam->keysParams.frameLengthRanges[tmp]);
++
++                h_StatsFLRs =
++                        PTR_MOVE(p_CcNode->h_StatsFLRs, tmp * FM_PCD_CC_STATS_FLR_SIZE);
++
++                MemCpy8(h_StatsFLRs,
++                            &flr,
++                            FM_PCD_CC_STATS_FLR_SIZE);
++            }
++            break;
++
++        default:
++            break;
++    }
++#endif /* (DPAA_VERSION >= 11) */
++
++    /* Allocate keys match table. Not required for some CC nodes, for example for IPv4 TTL
++     identification, IPv6 hop count identification, etc. */
++    if (isKeyTblAlloc)
++    {
++        p_CcNode->h_KeysMatchTable = (t_Handle)FM_MURAM_AllocMem(
++                h_FmMuram, matchTableSize, FM_PCD_CC_KEYS_MATCH_TABLE_ALIGN);
++        if (!p_CcNode->h_KeysMatchTable)
++        {
++            DeleteNode(p_CcNode);
++            RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                         ("MURAM allocation for CC node key match table"));
++        }
++        MemSet8((uint8_t *)p_CcNode->h_KeysMatchTable, 0, matchTableSize);
++    }
++
++    /* Allocate action descriptors table */
++    p_CcNode->h_AdTable = (t_Handle)FM_MURAM_AllocMem(h_FmMuram, adTableSize,
++                                                      FM_PCD_CC_AD_TABLE_ALIGN);
++    if (!p_CcNode->h_AdTable)
++    {
++        DeleteNode(p_CcNode);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                     ("MURAM allocation for CC node action descriptors table"));
++    }
++    MemSet8((uint8_t *)p_CcNode->h_AdTable, 0, adTableSize);
++
++    p_KeysMatchTblTmp = p_CcNode->h_KeysMatchTable;
++    p_AdTableTmp = p_CcNode->h_AdTable;
++
++    /* For each key, create the key and the next step AD */
++    for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++)
++    {
++        p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp];
++
++        if (p_KeysMatchTblTmp)
++        {
++            /* Copy the key */
++            MemCpy8((void*)p_KeysMatchTblTmp, p_KeyParams->p_Key,
++                        p_CcNode->sizeOfExtraction);
++
++            /* Copy the key mask or initialize it to 0xFF..F */
++            if (p_CcNode->lclMask && p_KeyParams->p_Mask)
++            {
++                MemCpy8(PTR_MOVE(p_KeysMatchTblTmp,
++                        p_CcNode->ccKeySizeAccExtraction), /* User's size of extraction rounded up to a valid matching table entry size */
++                            p_KeyParams->p_Mask, p_CcNode->sizeOfExtraction); /* Exact size of extraction as received from the user */
++            }
++            else
++                if (p_CcNode->lclMask)
++                {
++                    MemSet8(PTR_MOVE(p_KeysMatchTblTmp,
++                            p_CcNode->ccKeySizeAccExtraction), /* User's size of extraction rounded up to a valid matching table entry size */
++                               0xff, p_CcNode->sizeOfExtraction); /* Exact size of extraction as received from the user */
++                }
++
++            p_KeysMatchTblTmp =
++                    PTR_MOVE(p_KeysMatchTblTmp, keySize * sizeof(uint8_t));
++        }
++
++        /* Create the next action descriptor in the match table */
++        if (p_KeyParams->ccNextEngineParams.statisticsEn)
++        {
++            p_StatsObj = GetStatsObj(p_CcNode);
++            ASSERT_COND(p_StatsObj);
++
++            statsParams.h_StatsAd = p_StatsObj->h_StatsAd;
++            statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters;
++#if (DPAA_VERSION >= 11)
++            statsParams.h_StatsFLRs = p_CcNode->h_StatsFLRs;
++
++#endif /* (DPAA_VERSION >= 11) */
++            NextStepAd(p_AdTableTmp, &statsParams,
++                       &p_KeyParams->ccNextEngineParams, p_FmPcd);
++
++            p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = p_StatsObj;
++        }
++        else
++        {
++            NextStepAd(p_AdTableTmp, NULL, &p_KeyParams->ccNextEngineParams,
++                       p_FmPcd);
++
++            p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = NULL;
++        }
++
++        p_AdTableTmp = PTR_MOVE(p_AdTableTmp, FM_PCD_CC_AD_ENTRY_SIZE);
++    }
++
++    /* Update next engine for the 'miss' entry */
++    if (p_CcNodeParam->keysParams.ccNextEngineParamsForMiss.statisticsEn)
++    {
++        p_StatsObj = GetStatsObj(p_CcNode);
++        ASSERT_COND(p_StatsObj);
++
++        /* All 'bucket' nodes of a hash table should share the same statistics counters,
++         allocated by the hash table. So, if this node is a bucket of a hash table,
++         we'll replace the locally allocated counters with the shared counters. */
++        if (p_CcNode->isHashBucket)
++        {
++            ASSERT_COND(p_CcNode->h_MissStatsCounters);
++
++            /* Store original counters pointer and replace it with mutual preallocated pointer */
++            p_CcNode->h_PrivMissStatsCounters = p_StatsObj->h_StatsCounters;
++            p_StatsObj->h_StatsCounters = p_CcNode->h_MissStatsCounters;
++        }
++
++        statsParams.h_StatsAd = p_StatsObj->h_StatsAd;
++        statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters;
++#if (DPAA_VERSION >= 11)
++        statsParams.h_StatsFLRs = p_CcNode->h_StatsFLRs;
++
++#endif /* (DPAA_VERSION >= 11) */
++
++        NextStepAd(p_AdTableTmp, &statsParams,
++                   &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
++                   p_FmPcd);
++
++        p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = p_StatsObj;
++    }
++    else
++    {
++        NextStepAd(p_AdTableTmp, NULL,
++                   &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
++                   p_FmPcd);
++
++        p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = NULL;
++    }
++
++    /* This parameter will be used to initialize the "key length" field in the action descriptor
++     that points to this node and it should be 0 for full field extraction */
++    if (fullField == TRUE)
++        p_CcNode->sizeOfExtraction = 0;
++
++    for (tmp = 0; tmp < MIN(p_CcNode->numOfKeys + 1, CC_MAX_NUM_OF_KEYS); tmp++)
++    {
++        if (p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine
++                == e_FM_PCD_CC)
++        {
++            p_FmPcdCcNextNode =
++                    (t_FmPcdCcNode*)p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode;
++            p_CcInformation = FindNodeInfoInReleventLst(
++                    &p_FmPcdCcNextNode->ccPrevNodesLst, (t_Handle)p_CcNode,
++                    p_FmPcdCcNextNode->h_Spinlock);
++            if (!p_CcInformation)
++            {
++                memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
++                ccNodeInfo.h_CcNode = (t_Handle)p_CcNode;
++                ccNodeInfo.index = 1;
++                EnqueueNodeInfoToRelevantLst(&p_FmPcdCcNextNode->ccPrevNodesLst,
++                                             &ccNodeInfo,
++                                             p_FmPcdCcNextNode->h_Spinlock);
++            }
++            else
++                p_CcInformation->index++;
++
++            if (p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip)
++            {
++                h_Manip =
++                        p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip;
++                p_CcInformation = FindNodeInfoInReleventLst(
++                        FmPcdManipGetNodeLstPointedOnThisManip(h_Manip),
++                        (t_Handle)p_CcNode, FmPcdManipGetSpinlock(h_Manip));
++                if (!p_CcInformation)
++                {
++                    memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
++                    ccNodeInfo.h_CcNode = (t_Handle)p_CcNode;
++                    ccNodeInfo.index = 1;
++                    EnqueueNodeInfoToRelevantLst(
++                            FmPcdManipGetNodeLstPointedOnThisManip(h_Manip),
++                            &ccNodeInfo, FmPcdManipGetSpinlock(h_Manip));
++                }
++                else
++                    p_CcInformation->index++;
++            }
++        }
++    }
++
++    p_AdTableTmp = p_CcNode->h_AdTable;
++
++    if (!FmPcdLockTryLockAll(h_FmPcd))
++    {
++        FM_PCD_MatchTableDelete((t_Handle)p_CcNode);
++        DBG(TRACE, ("FmPcdLockTryLockAll failed"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    /* Required action for each next engine */
++    for (tmp = 0; tmp < MIN(p_CcNode->numOfKeys + 1, CC_MAX_NUM_OF_KEYS); tmp++)
++    {
++        if (p_CcNode->keyAndNextEngineParams[tmp].requiredAction)
++        {
++            err = SetRequiredAction(
++                    h_FmPcd,
++                    p_CcNode->keyAndNextEngineParams[tmp].requiredAction,
++                    &p_CcNode->keyAndNextEngineParams[tmp], p_AdTableTmp, 1,
++                    NULL);
++            if (err)
++            {
++                FmPcdLockUnlockAll(h_FmPcd);
++                FM_PCD_MatchTableDelete((t_Handle)p_CcNode);
++                RETURN_ERROR(MAJOR, err, NO_MSG);
++            }
++            p_AdTableTmp = PTR_MOVE(p_AdTableTmp, FM_PCD_CC_AD_ENTRY_SIZE);
++        }
++    }
++
++    FmPcdLockUnlockAll(h_FmPcd);
++
++    return E_OK;
++}
++/************************** End of static functions **************************/
++
++/*****************************************************************************/
++/*              Inter-module API routines                                    */
++/*****************************************************************************/
++
++t_CcNodeInformation* FindNodeInfoInReleventLst(t_List *p_List, t_Handle h_Info,
++                                               t_Handle h_Spinlock)
++{
++    t_CcNodeInformation *p_CcInformation;
++    t_List *p_Pos;
++    uint32_t intFlags;
++
++    intFlags = XX_LockIntrSpinlock(h_Spinlock);
++
++    for (p_Pos = LIST_FIRST(p_List); p_Pos != (p_List);
++            p_Pos = LIST_NEXT(p_Pos))
++    {
++        p_CcInformation = CC_NODE_F_OBJECT(p_Pos);
++
++        ASSERT_COND(p_CcInformation->h_CcNode);
++
++        if (p_CcInformation->h_CcNode == h_Info)
++        {
++            XX_UnlockIntrSpinlock(h_Spinlock, intFlags);
++            return p_CcInformation;
++        }
++    }
++
++    XX_UnlockIntrSpinlock(h_Spinlock, intFlags);
++
++    return NULL;
++}
++
++void EnqueueNodeInfoToRelevantLst(t_List *p_List, t_CcNodeInformation *p_CcInfo,
++                                  t_Handle h_Spinlock)
++{
++    t_CcNodeInformation *p_CcInformation;
++    uint32_t intFlags = 0;
++
++    p_CcInformation = (t_CcNodeInformation *)XX_Malloc(
++            sizeof(t_CcNodeInformation));
++
++    if (p_CcInformation)
++    {
++        memset(p_CcInformation, 0, sizeof(t_CcNodeInformation));
++        memcpy(p_CcInformation, p_CcInfo, sizeof(t_CcNodeInformation));
++        INIT_LIST(&p_CcInformation->node);
++
++        if (h_Spinlock)
++            intFlags = XX_LockIntrSpinlock(h_Spinlock);
++
++        LIST_AddToTail(&p_CcInformation->node, p_List);
++
++        if (h_Spinlock)
++            XX_UnlockIntrSpinlock(h_Spinlock, intFlags);
++    }
++    else
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("CC Node Information"));
++}
++
++void DequeueNodeInfoFromRelevantLst(t_List *p_List, t_Handle h_Info,
++                                    t_Handle h_Spinlock)
++{
++    t_CcNodeInformation *p_CcInformation = NULL;
++    uint32_t intFlags = 0;
++    t_List *p_Pos;
++
++    if (h_Spinlock)
++        intFlags = XX_LockIntrSpinlock(h_Spinlock);
++
++    if (LIST_IsEmpty(p_List))
++    {
++        XX_RestoreAllIntr(intFlags);
++        return;
++    }
++
++    for (p_Pos = LIST_FIRST(p_List); p_Pos != (p_List);
++            p_Pos = LIST_NEXT(p_Pos))
++    {
++        p_CcInformation = CC_NODE_F_OBJECT(p_Pos);
++        ASSERT_COND(p_CcInformation);
++        ASSERT_COND(p_CcInformation->h_CcNode);
++        if (p_CcInformation->h_CcNode == h_Info)
++            break;
++    }
++
++    if (p_CcInformation)
++    {
++        LIST_DelAndInit(&p_CcInformation->node);
++        XX_Free(p_CcInformation);
++    }
++
++    if (h_Spinlock)
++        XX_UnlockIntrSpinlock(h_Spinlock, intFlags);
++}
++
++void NextStepAd(t_Handle h_Ad, t_FmPcdCcStatsParams *p_FmPcdCcStatsParams,
++                t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams,
++                t_FmPcd *p_FmPcd)
++{
++    switch (p_FmPcdCcNextEngineParams->nextEngine)
++    {
++        case (e_FM_PCD_KG):
++        case (e_FM_PCD_PLCR):
++        case (e_FM_PCD_DONE):
++            /* if NIA is not CC, create a "result" type AD */
++            FillAdOfTypeResult(h_Ad, p_FmPcdCcStatsParams, p_FmPcd,
++                               p_FmPcdCcNextEngineParams);
++            break;
++#if (DPAA_VERSION >= 11)
++        case (e_FM_PCD_FR):
++            if (p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic)
++            {
++                FillAdOfTypeContLookup(
++                        h_Ad, p_FmPcdCcStatsParams, p_FmPcd,
++                        p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode,
++                        p_FmPcdCcNextEngineParams->h_Manip,
++                        p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic);
++                FrmReplicGroupUpdateOwner(
++                        p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic,
++                        TRUE/* add */);
++            }
++            break;
++#endif /* (DPAA_VERSION >= 11) */
++
++        case (e_FM_PCD_CC):
++            /* if NIA is not CC, create a TD to continue the CC lookup */
++            FillAdOfTypeContLookup(
++                    h_Ad, p_FmPcdCcStatsParams, p_FmPcd,
++                    p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode,
++                    p_FmPcdCcNextEngineParams->h_Manip, NULL);
++
++            UpdateNodeOwner(p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode,
++                            TRUE);
++            break;
++
++        default:
++            return;
++    }
++}
++
++t_Error FmPcdCcTreeAddIPR(t_Handle h_FmPcd, t_Handle h_FmTree,
++                          t_Handle h_NetEnv, t_Handle h_IpReassemblyManip,
++                          bool createSchemes)
++{
++    t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree;
++    t_FmPcdCcNextEngineParams nextEngineParams;
++    t_NetEnvParams netEnvParams;
++    t_Handle h_Ad;
++    bool isIpv6Present;
++    uint8_t ipv4GroupId, ipv6GroupId;
++    t_Error err;
++
++    ASSERT_COND(p_FmPcdCcTree);
++
++    /* this routine must be protected by the calling routine! */
++
++    memset(&nextEngineParams, 0, sizeof(t_FmPcdCcNextEngineParams));
++    memset(&netEnvParams, 0, sizeof(t_NetEnvParams));
++
++    h_Ad = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr);
++
++    isIpv6Present = FmPcdManipIpReassmIsIpv6Hdr(h_IpReassemblyManip);
++
++    if (isIpv6Present
++            && (p_FmPcdCcTree->numOfEntries > (FM_PCD_MAX_NUM_OF_CC_GROUPS - 2)))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("need two free entries for IPR"));
++
++    if (p_FmPcdCcTree->numOfEntries > (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("need two free entries for IPR"));
++
++    nextEngineParams.nextEngine = e_FM_PCD_DONE;
++    nextEngineParams.h_Manip = h_IpReassemblyManip;
++
++    /* Lock tree */
++    err = CcRootTryLock(p_FmPcdCcTree);
++    if (err)
++        return ERROR_CODE(E_BUSY);
++
++    if (p_FmPcdCcTree->h_IpReassemblyManip == h_IpReassemblyManip)
++    {
++        CcRootReleaseLock(p_FmPcdCcTree);
++        return E_OK;
++    }
++
++    if ((p_FmPcdCcTree->h_IpReassemblyManip)
++            && (p_FmPcdCcTree->h_IpReassemblyManip != h_IpReassemblyManip))
++    {
++        CcRootReleaseLock(p_FmPcdCcTree);
++        RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                     ("This tree was previously updated with different IPR"));
++    }
++
++    /* Initialize IPR for the first time for this tree */
++    if (isIpv6Present)
++    {
++        ipv6GroupId = p_FmPcdCcTree->numOfGrps++;
++        p_FmPcdCcTree->fmPcdGroupParam[ipv6GroupId].baseGroupEntry =
++                (FM_PCD_MAX_NUM_OF_CC_GROUPS - 2);
++
++        if (createSchemes)
++        {
++            err = FmPcdManipBuildIpReassmScheme(h_FmPcd, h_NetEnv,
++                                                p_FmPcdCcTree,
++                                                h_IpReassemblyManip, FALSE,
++                                                ipv6GroupId);
++            if (err)
++            {
++                p_FmPcdCcTree->numOfGrps--;
++                CcRootReleaseLock(p_FmPcdCcTree);
++                RETURN_ERROR(MAJOR, err, NO_MSG);
++            }
++        }
++
++        NextStepAd(
++                PTR_MOVE(h_Ad, (FM_PCD_MAX_NUM_OF_CC_GROUPS-2) * FM_PCD_CC_AD_ENTRY_SIZE),
++                NULL, &nextEngineParams, h_FmPcd);
++    }
++
++    ipv4GroupId = p_FmPcdCcTree->numOfGrps++;
++    p_FmPcdCcTree->fmPcdGroupParam[ipv4GroupId].totalBitsMask = 0;
++    p_FmPcdCcTree->fmPcdGroupParam[ipv4GroupId].baseGroupEntry =
++            (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1);
++
++    if (createSchemes)
++    {
++        err = FmPcdManipBuildIpReassmScheme(h_FmPcd, h_NetEnv, p_FmPcdCcTree,
++                                            h_IpReassemblyManip, TRUE,
++                                            ipv4GroupId);
++        if (err)
++        {
++            p_FmPcdCcTree->numOfGrps--;
++            if (isIpv6Present)
++            {
++                p_FmPcdCcTree->numOfGrps--;
++                FmPcdManipDeleteIpReassmSchemes(h_IpReassemblyManip);
++            }
++            CcRootReleaseLock(p_FmPcdCcTree);
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        }
++    }
++
++    NextStepAd(
++            PTR_MOVE(h_Ad, (FM_PCD_MAX_NUM_OF_CC_GROUPS-1) * FM_PCD_CC_AD_ENTRY_SIZE),
++            NULL, &nextEngineParams, h_FmPcd);
++
++    p_FmPcdCcTree->h_IpReassemblyManip = h_IpReassemblyManip;
++
++    CcRootReleaseLock(p_FmPcdCcTree);
++
++    return E_OK;
++}
++
++t_Error FmPcdCcTreeAddCPR(t_Handle h_FmPcd, t_Handle h_FmTree,
++                          t_Handle h_NetEnv, t_Handle h_ReassemblyManip,
++                          bool createSchemes)
++{
++    t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree;
++    t_FmPcdCcNextEngineParams nextEngineParams;
++    t_NetEnvParams netEnvParams;
++    t_Handle h_Ad;
++    uint8_t groupId;
++    t_Error err;
++
++    ASSERT_COND(p_FmPcdCcTree);
++
++    /* this routine must be protected by the calling routine! */
++    memset(&nextEngineParams, 0, sizeof(t_FmPcdCcNextEngineParams));
++    memset(&netEnvParams, 0, sizeof(t_NetEnvParams));
++
++    h_Ad = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr);
++
++    if (p_FmPcdCcTree->numOfEntries > (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("need one free entries for CPR"));
++
++    nextEngineParams.nextEngine = e_FM_PCD_DONE;
++    nextEngineParams.h_Manip = h_ReassemblyManip;
++
++    /* Lock tree */
++    err = CcRootTryLock(p_FmPcdCcTree);
++    if (err)
++        return ERROR_CODE(E_BUSY);
++
++    if (p_FmPcdCcTree->h_CapwapReassemblyManip == h_ReassemblyManip)
++    {
++        CcRootReleaseLock(p_FmPcdCcTree);
++        return E_OK;
++    }
++
++    if ((p_FmPcdCcTree->h_CapwapReassemblyManip)
++            && (p_FmPcdCcTree->h_CapwapReassemblyManip != h_ReassemblyManip))
++    {
++        CcRootReleaseLock(p_FmPcdCcTree);
++        RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                     ("This tree was previously updated with different CPR"));
++    }
++
++    groupId = p_FmPcdCcTree->numOfGrps++;
++    p_FmPcdCcTree->fmPcdGroupParam[groupId].baseGroupEntry =
++            (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1);
++
++    if (createSchemes)
++    {
++        err = FmPcdManipBuildCapwapReassmScheme(h_FmPcd, h_NetEnv,
++                                                p_FmPcdCcTree,
++                                                h_ReassemblyManip, groupId);
++        if (err)
++        {
++            p_FmPcdCcTree->numOfGrps--;
++            CcRootReleaseLock(p_FmPcdCcTree);
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        }
++    }
++
++    NextStepAd(
++            PTR_MOVE(h_Ad, (FM_PCD_MAX_NUM_OF_CC_GROUPS-1) * FM_PCD_CC_AD_ENTRY_SIZE),
++            NULL, &nextEngineParams, h_FmPcd);
++
++    p_FmPcdCcTree->h_CapwapReassemblyManip = h_ReassemblyManip;
++
++    CcRootReleaseLock(p_FmPcdCcTree);
++
++    return E_OK;
++}
++
++t_Handle FmPcdCcTreeGetSavedManipParams(t_Handle h_FmTree)
++{
++    t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree;
++
++    ASSERT_COND(p_FmPcdCcTree);
++
++    return p_FmPcdCcTree->h_FmPcdCcSavedManipParams;
++}
++
++void FmPcdCcTreeSetSavedManipParams(t_Handle h_FmTree,
++                                    t_Handle h_SavedManipParams)
++{
++    t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree;
++
++    ASSERT_COND(p_FmPcdCcTree);
++
++    p_FmPcdCcTree->h_FmPcdCcSavedManipParams = h_SavedManipParams;
++}
++
++uint8_t FmPcdCcGetParseCode(t_Handle h_CcNode)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++
++    ASSERT_COND(p_CcNode);
++
++    return p_CcNode->parseCode;
++}
++
++uint8_t FmPcdCcGetOffset(t_Handle h_CcNode)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++
++    ASSERT_COND(p_CcNode);
++
++    return p_CcNode->offset;
++}
++
++uint16_t FmPcdCcGetNumOfKeys(t_Handle h_CcNode)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++
++    ASSERT_COND(p_CcNode);
++
++    return p_CcNode->numOfKeys;
++}
++
++t_Error FmPcdCcModifyNextEngineParamTree(
++        t_Handle h_FmPcd, t_Handle h_FmPcdCcTree, uint8_t grpId, uint8_t index,
++        t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
++{
++    t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree;
++    t_FmPcd *p_FmPcd;
++    t_List h_OldPointersLst, h_NewPointersLst;
++    uint16_t keyIndex;
++    t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((grpId <= 7), E_INVALID_VALUE);
++
++    if (grpId >= p_FmPcdCcTree->numOfGrps)
++        RETURN_ERROR(MAJOR, E_INVALID_HANDLE,
++                     ("grpId you asked > numOfGroup of relevant tree"));
++
++    if (index >= p_FmPcdCcTree->fmPcdGroupParam[grpId].numOfEntriesInGroup)
++        RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("index > numOfEntriesInGroup"));
++
++    p_FmPcd = (t_FmPcd *)h_FmPcd;
++
++    INIT_LIST(&h_OldPointersLst);
++    INIT_LIST(&h_NewPointersLst);
++
++    keyIndex = (uint16_t)(p_FmPcdCcTree->fmPcdGroupParam[grpId].baseGroupEntry
++            + index);
++
++    p_ModifyKeyParams = ModifyNodeCommonPart(p_FmPcdCcTree, keyIndex,
++                                             e_MODIFY_STATE_CHANGE, FALSE,
++                                             FALSE, TRUE);
++    if (!p_ModifyKeyParams)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++
++    p_ModifyKeyParams->tree = TRUE;
++
++    if (p_FmPcd->p_CcShadow
++            && !TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
++    {
++        XX_Free(p_ModifyKeyParams);
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = BuildNewNodeModifyNextEngine(p_FmPcd, p_FmPcdCcTree, keyIndex,
++                                       p_FmPcdCcNextEngineParams,
++                                       &h_OldPointersLst, &h_NewPointersLst,
++                                       p_ModifyKeyParams);
++    if (err)
++    {
++        XX_Free(p_ModifyKeyParams);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst,
++                          p_ModifyKeyParams, FALSE);
++
++    if (p_FmPcd->p_CcShadow)
++        RELEASE_LOCK(p_FmPcd->shadowLock);
++
++      ReleaseLst(&h_OldPointersLst);
++      ReleaseLst(&h_NewPointersLst);
++
++    return err;
++
++}
++
++t_Error FmPcdCcRemoveKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode,
++                         uint16_t keyIndex)
++{
++
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode;
++    t_FmPcd *p_FmPcd;
++    t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams;
++    t_List h_OldPointersLst, h_NewPointersLst;
++    bool useShadowStructs = FALSE;
++    t_Error err = E_OK;
++
++    if (keyIndex >= p_CcNode->numOfKeys)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("impossible to remove key when numOfKeys <= keyIndex"));
++
++    if (p_CcNode->h_FmPcd != h_FmPcd)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("handler to FmPcd is different from the handle provided at node initialization time"));
++
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++
++    INIT_LIST(&h_OldPointersLst);
++    INIT_LIST(&h_NewPointersLst);
++
++    p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex,
++                                             e_MODIFY_STATE_REMOVE, TRUE, TRUE,
++                                             FALSE);
++    if (!p_ModifyKeyParams)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++
++    if (p_CcNode->maxNumOfKeys)
++    {
++        if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
++        {
++            XX_Free(p_ModifyKeyParams);
++            return ERROR_CODE(E_BUSY);
++        }
++
++        useShadowStructs = TRUE;
++    }
++
++    err = BuildNewNodeRemoveKey(p_CcNode, keyIndex, p_ModifyKeyParams);
++    if (err)
++    {
++        XX_Free(p_ModifyKeyParams);
++        if (p_CcNode->maxNumOfKeys)
++            RELEASE_LOCK(p_FmPcd->shadowLock);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams,
++                                           &h_OldPointersLst,
++                                           &h_NewPointersLst);
++    if (err)
++    {
++        ReleaseNewNodeCommonPart(p_ModifyKeyParams);
++        XX_Free(p_ModifyKeyParams);
++        if (p_CcNode->maxNumOfKeys)
++            RELEASE_LOCK(p_FmPcd->shadowLock);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst,
++                          p_ModifyKeyParams, useShadowStructs);
++
++    if (p_CcNode->maxNumOfKeys)
++        RELEASE_LOCK(p_FmPcd->shadowLock);
++
++      ReleaseLst(&h_OldPointersLst);
++      ReleaseLst(&h_NewPointersLst);
++
++    return err;
++}
++
++t_Error FmPcdCcModifyKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode,
++                         uint16_t keyIndex, uint8_t keySize, uint8_t *p_Key,
++                         uint8_t *p_Mask)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode;
++    t_FmPcd *p_FmPcd;
++    t_List h_OldPointersLst, h_NewPointersLst;
++    t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams;
++    uint16_t tmpKeyIndex;
++    bool useShadowStructs = FALSE;
++    t_Error err = E_OK;
++
++    if (keyIndex >= p_CcNode->numOfKeys)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                     ("keyIndex > previously cleared last index + 1"));
++
++    if (keySize != p_CcNode->userSizeOfExtraction)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("size for ModifyKey has to be the same as defined in SetNode"));
++
++    if (p_CcNode->h_FmPcd != h_FmPcd)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("handler to FmPcd is different from the handle provided at node initialization time"));
++
++    err = FindKeyIndex(h_FmPcdCcNode, keySize, p_Key, p_Mask, &tmpKeyIndex);
++    if (GET_ERROR_TYPE(err) != E_NOT_FOUND)
++        RETURN_ERROR(
++                MINOR,
++                E_ALREADY_EXISTS,
++                ("The received key and mask pair was already found in the match table of the provided node"));
++
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++
++    INIT_LIST(&h_OldPointersLst);
++    INIT_LIST(&h_NewPointersLst);
++
++    p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex,
++                                             e_MODIFY_STATE_CHANGE, TRUE, TRUE,
++                                             FALSE);
++    if (!p_ModifyKeyParams)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++
++    if (p_CcNode->maxNumOfKeys)
++    {
++        if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
++        {
++            XX_Free(p_ModifyKeyParams);
++            return ERROR_CODE(E_BUSY);
++        }
++
++        useShadowStructs = TRUE;
++    }
++
++    err = BuildNewNodeModifyKey(p_CcNode, keyIndex, p_Key, p_Mask,
++                                p_ModifyKeyParams);
++    if (err)
++    {
++        XX_Free(p_ModifyKeyParams);
++        if (p_CcNode->maxNumOfKeys)
++            RELEASE_LOCK(p_FmPcd->shadowLock);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams,
++                                           &h_OldPointersLst,
++                                           &h_NewPointersLst);
++    if (err)
++    {
++        ReleaseNewNodeCommonPart(p_ModifyKeyParams);
++        XX_Free(p_ModifyKeyParams);
++        if (p_CcNode->maxNumOfKeys)
++            RELEASE_LOCK(p_FmPcd->shadowLock);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst,
++                          p_ModifyKeyParams, useShadowStructs);
++
++    if (p_CcNode->maxNumOfKeys)
++        RELEASE_LOCK(p_FmPcd->shadowLock);
++
++      ReleaseLst(&h_OldPointersLst);
++      ReleaseLst(&h_NewPointersLst);
++
++    return err;
++}
++
++t_Error FmPcdCcModifyMissNextEngineParamNode(
++        t_Handle h_FmPcd, t_Handle h_FmPcdCcNode,
++        t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode;
++    t_FmPcd *p_FmPcd;
++    t_List h_OldPointersLst, h_NewPointersLst;
++    uint16_t keyIndex;
++    t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_VALUE);
++
++    keyIndex = p_CcNode->numOfKeys;
++
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++
++    INIT_LIST(&h_OldPointersLst);
++    INIT_LIST(&h_NewPointersLst);
++
++    p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex,
++                                             e_MODIFY_STATE_CHANGE, FALSE, TRUE,
++                                             FALSE);
++    if (!p_ModifyKeyParams)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++
++    if (p_CcNode->maxNumOfKeys
++            && !TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
++    {
++        XX_Free(p_ModifyKeyParams);
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = BuildNewNodeModifyNextEngine(h_FmPcd, p_CcNode, keyIndex,
++                                       p_FmPcdCcNextEngineParams,
++                                       &h_OldPointersLst, &h_NewPointersLst,
++                                       p_ModifyKeyParams);
++    if (err)
++    {
++        XX_Free(p_ModifyKeyParams);
++        if (p_CcNode->maxNumOfKeys)
++            RELEASE_LOCK(p_FmPcd->shadowLock);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst,
++                          p_ModifyKeyParams, FALSE);
++
++    if (p_CcNode->maxNumOfKeys)
++        RELEASE_LOCK(p_FmPcd->shadowLock);
++
++      ReleaseLst(&h_OldPointersLst);
++      ReleaseLst(&h_NewPointersLst);
++
++    return err;
++}
++
++t_Error FmPcdCcAddKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode,
++                      uint16_t keyIndex, uint8_t keySize,
++                      t_FmPcdCcKeyParams *p_FmPcdCcKeyParams)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode;
++    t_FmPcd *p_FmPcd;
++    t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams;
++    t_List h_OldPointersLst, h_NewPointersLst;
++    bool useShadowStructs = FALSE;
++    uint16_t tmpKeyIndex;
++    t_Error err = E_OK;
++
++    if (keyIndex > p_CcNode->numOfKeys)
++        RETURN_ERROR(MAJOR, E_NOT_IN_RANGE,
++                     ("keyIndex > previously cleared last index + 1"));
++
++    if (keySize != p_CcNode->userSizeOfExtraction)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("keySize has to be defined as it was defined in initialization step"));
++
++    if (p_CcNode->h_FmPcd != h_FmPcd)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("handler to FmPcd is different from the handle provided at node initialization time"));
++
++    if (p_CcNode->maxNumOfKeys)
++    {
++        if (p_CcNode->numOfKeys == p_CcNode->maxNumOfKeys)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_FULL,
++                    ("number of keys exceeds the maximal number of keys provided at node initialization time"));
++    }
++    else
++        if (p_CcNode->numOfKeys == FM_PCD_MAX_NUM_OF_KEYS)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("number of keys can not be larger than %d", FM_PCD_MAX_NUM_OF_KEYS));
++
++    err = FindKeyIndex(h_FmPcdCcNode, keySize, p_FmPcdCcKeyParams->p_Key,
++                       p_FmPcdCcKeyParams->p_Mask, &tmpKeyIndex);
++    if (GET_ERROR_TYPE(err) != E_NOT_FOUND)
++        RETURN_ERROR(
++                MAJOR,
++                E_ALREADY_EXISTS,
++                ("The received key and mask pair was already found in the match table of the provided node"));
++
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++
++    INIT_LIST(&h_OldPointersLst);
++    INIT_LIST(&h_NewPointersLst);
++
++    p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex,
++                                             e_MODIFY_STATE_ADD, TRUE, TRUE,
++                                             FALSE);
++    if (!p_ModifyKeyParams)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++
++    if (p_CcNode->maxNumOfKeys)
++    {
++        if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
++        {
++            XX_Free(p_ModifyKeyParams);
++            return ERROR_CODE(E_BUSY);
++        }
++
++        useShadowStructs = TRUE;
++    }
++
++    err = BuildNewNodeAddOrMdfyKeyAndNextEngine(h_FmPcd, p_CcNode, keyIndex,
++                                                p_FmPcdCcKeyParams,
++                                                p_ModifyKeyParams, TRUE);
++    if (err)
++    {
++        ReleaseNewNodeCommonPart(p_ModifyKeyParams);
++        XX_Free(p_ModifyKeyParams);
++        if (p_CcNode->maxNumOfKeys)
++            RELEASE_LOCK(p_FmPcd->shadowLock);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams,
++                                           &h_OldPointersLst,
++                                           &h_NewPointersLst);
++    if (err)
++    {
++        ReleaseNewNodeCommonPart(p_ModifyKeyParams);
++        XX_Free(p_ModifyKeyParams);
++        if (p_CcNode->maxNumOfKeys)
++            RELEASE_LOCK(p_FmPcd->shadowLock);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst,
++                          p_ModifyKeyParams, useShadowStructs);
++    if (p_CcNode->maxNumOfKeys)
++        RELEASE_LOCK(p_FmPcd->shadowLock);
++
++      ReleaseLst(&h_OldPointersLst);
++      ReleaseLst(&h_NewPointersLst);
++
++    return err;
++}
++
++t_Error FmPcdCcModifyKeyAndNextEngine(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode,
++                                      uint16_t keyIndex, uint8_t keySize,
++                                      t_FmPcdCcKeyParams *p_FmPcdCcKeyParams)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode;
++    t_FmPcd *p_FmPcd;
++    t_List h_OldPointersLst, h_NewPointersLst;
++    t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams;
++    uint16_t tmpKeyIndex;
++    bool useShadowStructs = FALSE;
++    t_Error err = E_OK;
++
++    if (keyIndex > p_CcNode->numOfKeys)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                     ("keyIndex > previously cleared last index + 1"));
++
++    if (keySize != p_CcNode->userSizeOfExtraction)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("keySize has to be defined as it was defined in initialization step"));
++
++    if (p_CcNode->h_FmPcd != h_FmPcd)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("handler to FmPcd is different from the handle provided at node initialization time"));
++
++    err = FindKeyIndex(h_FmPcdCcNode, keySize, p_FmPcdCcKeyParams->p_Key,
++                       p_FmPcdCcKeyParams->p_Mask, &tmpKeyIndex);
++    if (GET_ERROR_TYPE(err) != E_NOT_FOUND)
++        RETURN_ERROR(
++                MINOR,
++                E_ALREADY_EXISTS,
++                ("The received key and mask pair was already found in the match table of the provided node"));
++
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++
++    INIT_LIST(&h_OldPointersLst);
++    INIT_LIST(&h_NewPointersLst);
++
++    p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex,
++                                             e_MODIFY_STATE_CHANGE, TRUE, TRUE,
++                                             FALSE);
++    if (!p_ModifyKeyParams)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++
++    if (p_CcNode->maxNumOfKeys)
++    {
++        if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
++        {
++            XX_Free(p_ModifyKeyParams);
++            return ERROR_CODE(E_BUSY);
++        }
++
++        useShadowStructs = TRUE;
++    }
++
++    err = BuildNewNodeAddOrMdfyKeyAndNextEngine(h_FmPcd, p_CcNode, keyIndex,
++                                                p_FmPcdCcKeyParams,
++                                                p_ModifyKeyParams, FALSE);
++    if (err)
++    {
++        ReleaseNewNodeCommonPart(p_ModifyKeyParams);
++        XX_Free(p_ModifyKeyParams);
++        if (p_CcNode->maxNumOfKeys)
++            RELEASE_LOCK(p_FmPcd->shadowLock);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams,
++                                           &h_OldPointersLst,
++                                           &h_NewPointersLst);
++    if (err)
++    {
++        ReleaseNewNodeCommonPart(p_ModifyKeyParams);
++        XX_Free(p_ModifyKeyParams);
++        if (p_CcNode->maxNumOfKeys)
++            RELEASE_LOCK(p_FmPcd->shadowLock);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst,
++                          p_ModifyKeyParams, useShadowStructs);
++
++    if (p_CcNode->maxNumOfKeys)
++        RELEASE_LOCK(p_FmPcd->shadowLock);
++
++      ReleaseLst(&h_OldPointersLst);
++      ReleaseLst(&h_NewPointersLst);
++
++    return err;
++}
++
++uint32_t FmPcdCcGetNodeAddrOffsetFromNodeInfo(t_Handle h_FmPcd,
++                                              t_Handle h_Pointer)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    t_CcNodeInformation *p_CcNodeInfo;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE,
++                              (uint32_t)ILLEGAL_BASE);
++
++    p_CcNodeInfo = CC_NODE_F_OBJECT(h_Pointer);
++
++    return (uint32_t)(XX_VirtToPhys(p_CcNodeInfo->h_CcNode)
++            - p_FmPcd->physicalMuramBase);
++}
++
++t_Error FmPcdCcGetGrpParams(t_Handle h_FmPcdCcTree, uint8_t grpId,
++                            uint32_t *p_GrpBits, uint8_t *p_GrpBase)
++{
++    t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE);
++
++    if (grpId >= p_FmPcdCcTree->numOfGrps)
++        RETURN_ERROR(MAJOR, E_INVALID_HANDLE,
++                     ("grpId you asked > numOfGroup of relevant tree"));
++
++    *p_GrpBits = p_FmPcdCcTree->fmPcdGroupParam[grpId].totalBitsMask;
++    *p_GrpBase = p_FmPcdCcTree->fmPcdGroupParam[grpId].baseGroupEntry;
++
++    return E_OK;
++}
++
++t_Error FmPcdCcBindTree(t_Handle h_FmPcd, t_Handle h_PcdParams,
++                        t_Handle h_FmPcdCcTree, uint32_t *p_Offset,
++                        t_Handle h_FmPort)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE);
++
++    /* this routine must be protected by the calling routine by locking all PCD modules! */
++
++    err = CcUpdateParams(h_FmPcd, h_PcdParams, h_FmPort, h_FmPcdCcTree, TRUE);
++
++    if (err == E_OK)
++        UpdateCcRootOwner(p_FmPcdCcTree, TRUE);
++
++    *p_Offset = (uint32_t)(XX_VirtToPhys(
++            UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr))
++            - p_FmPcd->physicalMuramBase);
++
++    return err;
++}
++
++t_Error FmPcdCcUnbindTree(t_Handle h_FmPcd, t_Handle h_FmPcdCcTree)
++{
++    t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree;
++
++    /* this routine must be protected by the calling routine by locking all PCD modules! */
++
++    UNUSED(h_FmPcd);
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE);
++
++    UpdateCcRootOwner(p_FmPcdCcTree, FALSE);
++
++    return E_OK;
++}
++
++t_Error FmPcdCcNodeTreeTryLock(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode,
++                               t_List *p_List)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode;
++    t_List *p_Pos, *p_Tmp;
++    t_CcNodeInformation *p_CcNodeInfo, nodeInfo;
++    uint32_t intFlags;
++    t_Error err = E_OK;
++
++    intFlags = FmPcdLock(h_FmPcd);
++
++    LIST_FOR_EACH(p_Pos, &p_CcNode->ccTreesLst)
++    {
++        p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos);
++        ASSERT_COND(p_CcNodeInfo->h_CcNode);
++
++        err = CcRootTryLock(p_CcNodeInfo->h_CcNode);
++
++        if (err)
++        {
++            LIST_FOR_EACH(p_Tmp, &p_CcNode->ccTreesLst)
++            {
++                if (p_Tmp == p_Pos)
++                    break;
++
++                CcRootReleaseLock(p_CcNodeInfo->h_CcNode);
++            }
++            break;
++        }
++
++        memset(&nodeInfo, 0, sizeof(t_CcNodeInformation));
++        nodeInfo.h_CcNode = p_CcNodeInfo->h_CcNode;
++        EnqueueNodeInfoToRelevantLst(p_List, &nodeInfo, NULL);
++    }
++
++    FmPcdUnlock(h_FmPcd, intFlags);
++    CORE_MemoryBarrier();
++
++    return err;
++}
++
++void FmPcdCcNodeTreeReleaseLock(t_Handle h_FmPcd, t_List *p_List)
++{
++    t_List *p_Pos;
++    t_CcNodeInformation *p_CcNodeInfo;
++    t_Handle h_FmPcdCcTree;
++    uint32_t intFlags;
++
++    intFlags = FmPcdLock(h_FmPcd);
++
++    LIST_FOR_EACH(p_Pos, p_List)
++    {
++        p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos);
++        h_FmPcdCcTree = p_CcNodeInfo->h_CcNode;
++        CcRootReleaseLock(h_FmPcdCcTree);
++    }
++
++    ReleaseLst(p_List);
++
++    FmPcdUnlock(h_FmPcd, intFlags);
++    CORE_MemoryBarrier();
++}
++
++t_Error FmPcdUpdateCcShadow(t_FmPcd *p_FmPcd, uint32_t size, uint32_t align)
++{
++    uint32_t intFlags;
++    uint32_t newSize = 0, newAlign = 0;
++    bool allocFail = FALSE;
++
++    ASSERT_COND(p_FmPcd);
++
++    if (!size)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("size must be larger then 0"));
++
++    if (!POWER_OF_2(align))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("alignment must be power of 2"));
++
++    newSize = p_FmPcd->ccShadowSize;
++    newAlign = p_FmPcd->ccShadowAlign;
++
++    /* Check if current shadow is large enough to hold the requested size */
++    if (size > p_FmPcd->ccShadowSize)
++        newSize = size;
++
++    /* Check if current shadow matches the requested alignment */
++    if (align > p_FmPcd->ccShadowAlign)
++        newAlign = align;
++
++    /* If a bigger shadow size or bigger shadow alignment are required,
++     a new shadow will be allocated */
++    if ((newSize != p_FmPcd->ccShadowSize)
++            || (newAlign != p_FmPcd->ccShadowAlign))
++    {
++        intFlags = FmPcdLock(p_FmPcd);
++
++        if (p_FmPcd->p_CcShadow)
++        {
++            FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_FmPcd), p_FmPcd->p_CcShadow);
++            p_FmPcd->ccShadowSize = 0;
++            p_FmPcd->ccShadowAlign = 0;
++        }
++
++        p_FmPcd->p_CcShadow = FM_MURAM_AllocMem(FmPcdGetMuramHandle(p_FmPcd),
++                                                newSize, newAlign);
++        if (!p_FmPcd->p_CcShadow)
++        {
++            allocFail = TRUE;
++
++            /* If new shadow size allocation failed,
++             re-allocate with previous parameters */
++            p_FmPcd->p_CcShadow = FM_MURAM_AllocMem(
++                    FmPcdGetMuramHandle(p_FmPcd), p_FmPcd->ccShadowSize,
++                    p_FmPcd->ccShadowAlign);
++        }
++
++        FmPcdUnlock(p_FmPcd, intFlags);
++
++        if (allocFail)
++            RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                         ("MURAM allocation for CC Shadow memory"));
++
++        p_FmPcd->ccShadowSize = newSize;
++        p_FmPcd->ccShadowAlign = newAlign;
++    }
++
++    return E_OK;
++}
++
++#if (DPAA_VERSION >= 11)
++void FmPcdCcGetAdTablesThatPointOnReplicGroup(t_Handle h_Node,
++                                              t_Handle h_ReplicGroup,
++                                              t_List *p_AdTables,
++                                              uint32_t *p_NumOfAdTables)
++{
++    t_FmPcdCcNode *p_CurrentNode = (t_FmPcdCcNode *)h_Node;
++    int i = 0;
++    void * p_AdTable;
++    t_CcNodeInformation ccNodeInfo;
++
++    ASSERT_COND(h_Node);
++    *p_NumOfAdTables = 0;
++
++    /* search in the current node which exact index points on this current replicator group for getting AD */
++    for (i = 0; i < p_CurrentNode->numOfKeys + 1; i++)
++    {
++        if ((p_CurrentNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine
++                == e_FM_PCD_FR)
++                && ((p_CurrentNode->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic
++                        == (t_Handle)h_ReplicGroup)))
++        {
++            /* save the current ad table in the list */
++            /* this entry uses the input replicator group */
++            p_AdTable =
++                    PTR_MOVE(p_CurrentNode->h_AdTable, i*FM_PCD_CC_AD_ENTRY_SIZE);
++            memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
++            ccNodeInfo.h_CcNode = p_AdTable;
++            EnqueueNodeInfoToRelevantLst(p_AdTables, &ccNodeInfo, NULL);
++            (*p_NumOfAdTables)++;
++        }
++    }
++
++    ASSERT_COND(i != p_CurrentNode->numOfKeys);
++}
++#endif /* (DPAA_VERSION >= 11) */
++/*********************** End of inter-module routines ************************/
++
++/****************************************/
++/*       API Init unit functions        */
++/****************************************/
++
++t_Handle FM_PCD_CcRootBuild(t_Handle h_FmPcd,
++                            t_FmPcdCcTreeParams *p_PcdGroupsParam)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    t_Error err = E_OK;
++    int i = 0, j = 0, k = 0;
++    t_FmPcdCcTree *p_FmPcdCcTree;
++    uint8_t numOfEntries;
++    t_Handle p_CcTreeTmp;
++    t_FmPcdCcGrpParams *p_FmPcdCcGroupParams;
++    t_FmPcdCcKeyAndNextEngineParams *p_Params, *p_KeyAndNextEngineParams;
++    t_NetEnvParams netEnvParams;
++    uint8_t lastOne = 0;
++    uint32_t requiredAction = 0;
++    t_FmPcdCcNode *p_FmPcdCcNextNode;
++    t_CcNodeInformation ccNodeInfo, *p_CcInformation;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(p_PcdGroupsParam, E_INVALID_HANDLE, NULL);
++
++    if (p_PcdGroupsParam->numOfGrps > FM_PCD_MAX_NUM_OF_CC_GROUPS)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("numOfGrps should not exceed %d", FM_PCD_MAX_NUM_OF_CC_GROUPS));
++        return NULL;
++    }
++
++    p_FmPcdCcTree = (t_FmPcdCcTree*)XX_Malloc(sizeof(t_FmPcdCcTree));
++    if (!p_FmPcdCcTree)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("PCD tree structure"));
++        return NULL;
++    }
++    memset(p_FmPcdCcTree, 0, sizeof(t_FmPcdCcTree));
++    p_FmPcdCcTree->h_FmPcd = h_FmPcd;
++
++    p_Params = (t_FmPcdCcKeyAndNextEngineParams*)XX_Malloc(
++            FM_PCD_MAX_NUM_OF_CC_GROUPS
++                    * sizeof(t_FmPcdCcKeyAndNextEngineParams));
++    memset(p_Params,
++           0,
++           FM_PCD_MAX_NUM_OF_CC_GROUPS
++                   * sizeof(t_FmPcdCcKeyAndNextEngineParams));
++
++    INIT_LIST(&p_FmPcdCcTree->fmPortsLst);
++
++#ifdef FM_CAPWAP_SUPPORT
++    if ((p_PcdGroupsParam->numOfGrps == 1) &&
++            (p_PcdGroupsParam->ccGrpParams[0].numOfDistinctionUnits == 0) &&
++            (p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].nextEngine == e_FM_PCD_CC) &&
++            p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].params.ccParams.h_CcNode &&
++            IsCapwapApplSpecific(p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].params.ccParams.h_CcNode))
++    {
++        p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].h_Manip = FmPcdManipApplSpecificBuild();
++        if (!p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].h_Manip)
++        {
++            DeleteTree(p_FmPcdCcTree,p_FmPcd);
++            XX_Free(p_Params);
++            REPORT_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++            return NULL;
++        }
++    }
++#endif /* FM_CAPWAP_SUPPORT */
++
++    numOfEntries = 0;
++    p_FmPcdCcTree->netEnvId = FmPcdGetNetEnvId(p_PcdGroupsParam->h_NetEnv);
++
++    for (i = 0; i < p_PcdGroupsParam->numOfGrps; i++)
++    {
++        p_FmPcdCcGroupParams = &p_PcdGroupsParam->ccGrpParams[i];
++
++        if (p_FmPcdCcGroupParams->numOfDistinctionUnits
++                > FM_PCD_MAX_NUM_OF_CC_UNITS)
++        {
++            DeleteTree(p_FmPcdCcTree, p_FmPcd);
++            XX_Free(p_Params);
++            REPORT_ERROR(MAJOR, E_INVALID_VALUE,
++                    ("numOfDistinctionUnits (group %d) should not exceed %d", i, FM_PCD_MAX_NUM_OF_CC_UNITS));
++            return NULL;
++        }
++
++        p_FmPcdCcTree->fmPcdGroupParam[i].baseGroupEntry = numOfEntries;
++        p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup = (uint8_t)(0x01
++                << p_FmPcdCcGroupParams->numOfDistinctionUnits);
++        numOfEntries += p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup;
++        if (numOfEntries > FM_PCD_MAX_NUM_OF_CC_GROUPS)
++        {
++            DeleteTree(p_FmPcdCcTree, p_FmPcd);
++            XX_Free(p_Params);
++            REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("numOfEntries can not be larger than %d", FM_PCD_MAX_NUM_OF_CC_GROUPS));
++            return NULL;
++        }
++
++        if (lastOne)
++        {
++            if (p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup > lastOne)
++            {
++                DeleteTree(p_FmPcdCcTree, p_FmPcd);
++                XX_Free(p_Params);
++                REPORT_ERROR(MAJOR, E_CONFLICT, ("numOfEntries per group must be set in descending order"));
++                return NULL;
++            }
++        }
++
++        lastOne = p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup;
++
++        netEnvParams.netEnvId = p_FmPcdCcTree->netEnvId;
++        netEnvParams.numOfDistinctionUnits =
++                p_FmPcdCcGroupParams->numOfDistinctionUnits;
++
++        memcpy(netEnvParams.unitIds, &p_FmPcdCcGroupParams->unitIds,
++               (sizeof(uint8_t)) * p_FmPcdCcGroupParams->numOfDistinctionUnits);
++
++        err = PcdGetUnitsVector(p_FmPcd, &netEnvParams);
++        if (err)
++        {
++            DeleteTree(p_FmPcdCcTree, p_FmPcd);
++            XX_Free(p_Params);
++            REPORT_ERROR(MAJOR, err, NO_MSG);
++            return NULL;
++        }
++
++        p_FmPcdCcTree->fmPcdGroupParam[i].totalBitsMask = netEnvParams.vector;
++        for (j = 0; j < p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup;
++                j++)
++        {
++            err = ValidateNextEngineParams(
++                    h_FmPcd,
++                    &p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j],
++                    e_FM_PCD_CC_STATS_MODE_NONE);
++            if (err)
++            {
++                DeleteTree(p_FmPcdCcTree, p_FmPcd);
++                XX_Free(p_Params);
++                REPORT_ERROR(MAJOR, err, (NO_MSG));
++                return NULL;
++            }
++
++            if (p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j].h_Manip)
++            {
++                err = FmPcdManipCheckParamsForCcNextEngine(
++                        &p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j],
++                        &requiredAction);
++                if (err)
++                {
++                    DeleteTree(p_FmPcdCcTree, p_FmPcd);
++                    XX_Free(p_Params);
++                    REPORT_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++                    return NULL;
++                }
++            }
++            p_KeyAndNextEngineParams = p_Params + k;
++
++            memcpy(&p_KeyAndNextEngineParams->nextEngineParams,
++                   &p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j],
++                   sizeof(t_FmPcdCcNextEngineParams));
++
++            if ((p_KeyAndNextEngineParams->nextEngineParams.nextEngine
++                    == e_FM_PCD_CC)
++                    && p_KeyAndNextEngineParams->nextEngineParams.h_Manip)
++            {
++                err =
++                        AllocAndFillAdForContLookupManip(
++                                p_KeyAndNextEngineParams->nextEngineParams.params.ccParams.h_CcNode);
++                if (err)
++                {
++                    DeleteTree(p_FmPcdCcTree, p_FmPcd);
++                    XX_Free(p_Params);
++                    REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC Tree"));
++                    return NULL;
++                }
++            }
++
++            requiredAction |= UPDATE_CC_WITH_TREE;
++            p_KeyAndNextEngineParams->requiredAction = requiredAction;
++
++            k++;
++        }
++    }
++
++    p_FmPcdCcTree->numOfEntries = (uint8_t)k;
++    p_FmPcdCcTree->numOfGrps = p_PcdGroupsParam->numOfGrps;
++
++    p_FmPcdCcTree->ccTreeBaseAddr =
++            PTR_TO_UINT(FM_MURAM_AllocMem(FmPcdGetMuramHandle(h_FmPcd),
++                            (uint32_t)( FM_PCD_MAX_NUM_OF_CC_GROUPS * FM_PCD_CC_AD_ENTRY_SIZE),
++                            FM_PCD_CC_TREE_ADDR_ALIGN));
++    if (!p_FmPcdCcTree->ccTreeBaseAddr)
++    {
++        DeleteTree(p_FmPcdCcTree, p_FmPcd);
++        XX_Free(p_Params);
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC Tree"));
++        return NULL;
++    }
++    MemSet8(
++            UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr), 0,
++            (uint32_t)(FM_PCD_MAX_NUM_OF_CC_GROUPS * FM_PCD_CC_AD_ENTRY_SIZE));
++
++    p_CcTreeTmp = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr);
++
++    for (i = 0; i < numOfEntries; i++)
++    {
++        p_KeyAndNextEngineParams = p_Params + i;
++
++        NextStepAd(p_CcTreeTmp, NULL,
++                   &p_KeyAndNextEngineParams->nextEngineParams, p_FmPcd);
++
++        p_CcTreeTmp = PTR_MOVE(p_CcTreeTmp, FM_PCD_CC_AD_ENTRY_SIZE);
++
++        memcpy(&p_FmPcdCcTree->keyAndNextEngineParams[i],
++               p_KeyAndNextEngineParams,
++               sizeof(t_FmPcdCcKeyAndNextEngineParams));
++
++        if (p_FmPcdCcTree->keyAndNextEngineParams[i].nextEngineParams.nextEngine
++                == e_FM_PCD_CC)
++        {
++            p_FmPcdCcNextNode =
++                    (t_FmPcdCcNode*)p_FmPcdCcTree->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode;
++            p_CcInformation = FindNodeInfoInReleventLst(
++                    &p_FmPcdCcNextNode->ccTreeIdLst, (t_Handle)p_FmPcdCcTree,
++                    p_FmPcdCcNextNode->h_Spinlock);
++
++            if (!p_CcInformation)
++            {
++                memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
++                ccNodeInfo.h_CcNode = (t_Handle)p_FmPcdCcTree;
++                ccNodeInfo.index = 1;
++                EnqueueNodeInfoToRelevantLst(&p_FmPcdCcNextNode->ccTreeIdLst,
++                                             &ccNodeInfo,
++                                             p_FmPcdCcNextNode->h_Spinlock);
++            }
++            else
++                p_CcInformation->index++;
++        }
++    }
++
++    FmPcdIncNetEnvOwners(h_FmPcd, p_FmPcdCcTree->netEnvId);
++    p_CcTreeTmp = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr);
++
++    if (!FmPcdLockTryLockAll(p_FmPcd))
++    {
++        FM_PCD_CcRootDelete(p_FmPcdCcTree);
++        XX_Free(p_Params);
++        DBG(TRACE, ("FmPcdLockTryLockAll failed"));
++        return NULL;
++    }
++
++    for (i = 0; i < numOfEntries; i++)
++    {
++        if (p_FmPcdCcTree->keyAndNextEngineParams[i].requiredAction)
++        {
++            err = SetRequiredAction(
++                    h_FmPcd,
++                    p_FmPcdCcTree->keyAndNextEngineParams[i].requiredAction,
++                    &p_FmPcdCcTree->keyAndNextEngineParams[i], p_CcTreeTmp, 1,
++                    p_FmPcdCcTree);
++            if (err)
++            {
++                FmPcdLockUnlockAll(p_FmPcd);
++                FM_PCD_CcRootDelete(p_FmPcdCcTree);
++                XX_Free(p_Params);
++                REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory"));
++                return NULL;
++            }
++            p_CcTreeTmp = PTR_MOVE(p_CcTreeTmp, FM_PCD_CC_AD_ENTRY_SIZE);
++        }
++    }
++
++    FmPcdLockUnlockAll(p_FmPcd);
++    p_FmPcdCcTree->p_Lock = FmPcdAcquireLock(p_FmPcd);
++    if (!p_FmPcdCcTree->p_Lock)
++    {
++        FM_PCD_CcRootDelete(p_FmPcdCcTree);
++        XX_Free(p_Params);
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM CC lock"));
++        return NULL;
++    }
++
++    XX_Free(p_Params);
++
++    return p_FmPcdCcTree;
++}
++
++t_Error FM_PCD_CcRootDelete(t_Handle h_CcTree)
++{
++    t_FmPcd *p_FmPcd;
++    t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_CcTree;
++    int i = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_CcTree, E_INVALID_STATE);
++    p_FmPcd = (t_FmPcd *)p_CcTree->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++
++    FmPcdDecNetEnvOwners(p_FmPcd, p_CcTree->netEnvId);
++
++    if (p_CcTree->owners)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_SELECTION,
++                ("the tree with this ID can not be removed because this tree is occupied, first - unbind this tree"));
++
++    /* Delete ip-reassembly schemes if exist */
++    if (p_CcTree->h_IpReassemblyManip)
++    {
++        FmPcdManipDeleteIpReassmSchemes(p_CcTree->h_IpReassemblyManip);
++        FmPcdManipUpdateOwner(p_CcTree->h_IpReassemblyManip, FALSE);
++    }
++
++    /* Delete capwap-reassembly schemes if exist */
++    if (p_CcTree->h_CapwapReassemblyManip)
++    {
++        FmPcdManipDeleteCapwapReassmSchemes(p_CcTree->h_CapwapReassemblyManip);
++        FmPcdManipUpdateOwner(p_CcTree->h_CapwapReassemblyManip, FALSE);
++    }
++
++    for (i = 0; i < p_CcTree->numOfEntries; i++)
++    {
++        if (p_CcTree->keyAndNextEngineParams[i].nextEngineParams.nextEngine
++                == e_FM_PCD_CC)
++            UpdateNodeOwner(
++                    p_CcTree->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode,
++                    FALSE);
++
++        if (p_CcTree->keyAndNextEngineParams[i].nextEngineParams.h_Manip)
++            FmPcdManipUpdateOwner(
++                    p_CcTree->keyAndNextEngineParams[i].nextEngineParams.h_Manip,
++                    FALSE);
++
++#ifdef FM_CAPWAP_SUPPORT
++        if ((p_CcTree->numOfGrps == 1) &&
++                (p_CcTree->fmPcdGroupParam[0].numOfEntriesInGroup == 1) &&
++                (p_CcTree->keyAndNextEngineParams[0].nextEngineParams.nextEngine == e_FM_PCD_CC) &&
++                p_CcTree->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode &&
++                IsCapwapApplSpecific(p_CcTree->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode))
++        {
++            if (FM_PCD_ManipNodeDelete(p_CcTree->keyAndNextEngineParams[0].nextEngineParams.h_Manip) != E_OK)
++            return E_INVALID_STATE;
++        }
++#endif /* FM_CAPWAP_SUPPORT */
++
++#if (DPAA_VERSION >= 11)
++        if ((p_CcTree->keyAndNextEngineParams[i].nextEngineParams.nextEngine
++                == e_FM_PCD_FR)
++                && (p_CcTree->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic))
++            FrmReplicGroupUpdateOwner(
++                    p_CcTree->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic,
++                    FALSE);
++#endif /* (DPAA_VERSION >= 11) */
++    }
++
++    if (p_CcTree->p_Lock)
++        FmPcdReleaseLock(p_CcTree->h_FmPcd, p_CcTree->p_Lock);
++
++    DeleteTree(p_CcTree, p_FmPcd);
++
++    return E_OK;
++}
++
++t_Error FM_PCD_CcRootModifyNextEngine(
++        t_Handle h_CcTree, uint8_t grpId, uint8_t index,
++        t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
++{
++    t_FmPcd *p_FmPcd;
++    t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_CcTree;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_CcTree, E_INVALID_STATE);
++    p_FmPcd = (t_FmPcd *)p_CcTree->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++
++    if (!FmPcdLockTryLockAll(p_FmPcd))
++    {
++        DBG(TRACE, ("FmPcdLockTryLockAll failed"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = FmPcdCcModifyNextEngineParamTree(p_FmPcd, p_CcTree, grpId, index,
++                                           p_FmPcdCcNextEngineParams);
++    FmPcdLockUnlockAll(p_FmPcd);
++
++    if (err)
++    {
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    return E_OK;
++}
++
++t_Handle FM_PCD_MatchTableSet(t_Handle h_FmPcd,
++                              t_FmPcdCcNodeParams *p_CcNodeParam)
++{
++    t_FmPcdCcNode *p_CcNode;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(p_CcNodeParam, E_NULL_POINTER, NULL);
++
++    p_CcNode = (t_FmPcdCcNode*)XX_Malloc(sizeof(t_FmPcdCcNode));
++    if (!p_CcNode)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory"));
++        return NULL;
++    }
++    memset(p_CcNode, 0, sizeof(t_FmPcdCcNode));
++
++    err = MatchTableSet(h_FmPcd, p_CcNode, p_CcNodeParam);
++
++    switch(GET_ERROR_TYPE(err)
++)    {
++        case E_OK:
++        break;
++
++        case E_BUSY:
++        DBG(TRACE, ("E_BUSY error"));
++        return NULL;
++
++        default:
++        REPORT_ERROR(MAJOR, err, NO_MSG);
++        return NULL;
++    }
++
++    return p_CcNode;
++}
++
++t_Error FM_PCD_MatchTableDelete(t_Handle h_CcNode)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    int i = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_CcNode->h_FmPcd, E_INVALID_HANDLE);
++
++    if (p_CcNode->owners)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_STATE,
++                ("This node cannot be removed because it is occupied; first unbind this node"));
++
++    for (i = 0; i < p_CcNode->numOfKeys; i++)
++        if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine
++                == e_FM_PCD_CC)
++            UpdateNodeOwner(
++                    p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode,
++                    FALSE);
++
++    if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine
++            == e_FM_PCD_CC)
++        UpdateNodeOwner(
++                p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode,
++                FALSE);
++
++    /* Handle also Miss entry */
++    for (i = 0; i < p_CcNode->numOfKeys + 1; i++)
++    {
++        if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip)
++            FmPcdManipUpdateOwner(
++                    p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip,
++                    FALSE);
++
++#if (DPAA_VERSION >= 11)
++        if ((p_CcNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine
++                == e_FM_PCD_FR)
++                && (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic))
++        {
++            FrmReplicGroupUpdateOwner(
++                    p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic,
++                    FALSE);
++        }
++#endif /* (DPAA_VERSION >= 11) */
++    }
++
++    DeleteNode(p_CcNode);
++
++    return E_OK;
++}
++
++t_Error FM_PCD_MatchTableAddKey(t_Handle h_CcNode, uint16_t keyIndex,
++                                uint8_t keySize,
++                                t_FmPcdCcKeyParams *p_KeyParams)
++{
++    t_FmPcd *p_FmPcd;
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
++
++    if (keyIndex == FM_PCD_LAST_KEY_INDEX)
++        keyIndex = p_CcNode->numOfKeys;
++
++    if (!FmPcdLockTryLockAll(p_FmPcd))
++    {
++        DBG(TRACE, ("FmPcdLockTryLockAll failed"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = FmPcdCcAddKey(p_FmPcd, p_CcNode, keyIndex, keySize, p_KeyParams);
++
++    FmPcdLockUnlockAll(p_FmPcd);
++
++    switch(GET_ERROR_TYPE(err)
++)    {
++        case E_OK:
++        return E_OK;
++
++        case E_BUSY:
++        DBG(TRACE, ("E_BUSY error"));
++        return ERROR_CODE(E_BUSY);
++
++        default:
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++}
++
++t_Error FM_PCD_MatchTableRemoveKey(t_Handle h_CcNode, uint16_t keyIndex)
++{
++    t_FmPcd *p_FmPcd;
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
++
++    if (!FmPcdLockTryLockAll(p_FmPcd))
++    {
++        DBG(TRACE, ("FmPcdLockTryLockAll failed"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = FmPcdCcRemoveKey(p_FmPcd, p_CcNode, keyIndex);
++
++    FmPcdLockUnlockAll(p_FmPcd);
++
++    switch(GET_ERROR_TYPE(err)
++)    {
++        case E_OK:
++        return E_OK;
++
++        case E_BUSY:
++        DBG(TRACE, ("E_BUSY error"));
++        return ERROR_CODE(E_BUSY);
++
++        default:
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    return E_OK;
++}
++
++t_Error FM_PCD_MatchTableModifyKey(t_Handle h_CcNode, uint16_t keyIndex,
++                                   uint8_t keySize, uint8_t *p_Key,
++                                   uint8_t *p_Mask)
++{
++    t_FmPcd *p_FmPcd;
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
++
++
++    if (!FmPcdLockTryLockAll(p_FmPcd))
++    {
++        DBG(TRACE, ("FmPcdLockTryLockAll failed"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = FmPcdCcModifyKey(p_FmPcd, p_CcNode, keyIndex, keySize, p_Key, p_Mask);
++
++    FmPcdLockUnlockAll(p_FmPcd);
++
++    switch(GET_ERROR_TYPE(err)
++)    {
++        case E_OK:
++        return E_OK;
++
++        case E_BUSY:
++        DBG(TRACE, ("E_BUSY error"));
++        return ERROR_CODE(E_BUSY);
++
++        default:
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++}
++
++t_Error FM_PCD_MatchTableModifyNextEngine(
++        t_Handle h_CcNode, uint16_t keyIndex,
++        t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
++{
++    t_FmPcd *p_FmPcd;
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
++
++    if (!FmPcdLockTryLockAll(p_FmPcd))
++    {
++        DBG(TRACE, ("FmPcdLockTryLockAll failed"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = ModifyNextEngineParamNode(p_FmPcd, p_CcNode, keyIndex,
++                                    p_FmPcdCcNextEngineParams);
++
++    FmPcdLockUnlockAll(p_FmPcd);
++
++    switch(GET_ERROR_TYPE(err)
++)    {
++        case E_OK:
++        return E_OK;
++
++        case E_BUSY:
++        DBG(TRACE, ("E_BUSY error"));
++        return ERROR_CODE(E_BUSY);
++
++        default:
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++}
++
++t_Error FM_PCD_MatchTableModifyMissNextEngine(
++        t_Handle h_CcNode, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
++{
++    t_FmPcd *p_FmPcd;
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
++
++    if (!FmPcdLockTryLockAll(p_FmPcd))
++    {
++        DBG(TRACE, ("FmPcdLockTryLockAll failed"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = FmPcdCcModifyMissNextEngineParamNode(p_FmPcd, p_CcNode,
++                                               p_FmPcdCcNextEngineParams);
++
++    FmPcdLockUnlockAll(p_FmPcd);
++
++    switch(GET_ERROR_TYPE(err)
++)    {
++        case E_OK:
++        return E_OK;
++
++        case E_BUSY:
++        DBG(TRACE, ("E_BUSY error"));
++        return ERROR_CODE(E_BUSY);
++
++        default:
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++}
++
++t_Error FM_PCD_MatchTableModifyKeyAndNextEngine(t_Handle h_CcNode,
++                                                uint16_t keyIndex,
++                                                uint8_t keySize,
++                                                t_FmPcdCcKeyParams *p_KeyParams)
++{
++    t_FmPcd *p_FmPcd;
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
++
++    if (!FmPcdLockTryLockAll(p_FmPcd))
++    {
++        DBG(TRACE, ("FmPcdLockTryLockAll failed"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = FmPcdCcModifyKeyAndNextEngine(p_FmPcd, p_CcNode, keyIndex, keySize,
++                                        p_KeyParams);
++
++    FmPcdLockUnlockAll(p_FmPcd);
++
++    switch(GET_ERROR_TYPE(err)
++)    {
++        case E_OK:
++        return E_OK;
++
++        case E_BUSY:
++        DBG(TRACE, ("E_BUSY error"));
++        return ERROR_CODE(E_BUSY);
++
++        default:
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++}
++
++t_Error FM_PCD_MatchTableFindNRemoveKey(t_Handle h_CcNode, uint8_t keySize,
++                                        uint8_t *p_Key, uint8_t *p_Mask)
++{
++    t_FmPcd *p_FmPcd;
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    uint16_t keyIndex;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
++
++    if (!FmPcdLockTryLockAll(p_FmPcd))
++    {
++        DBG(TRACE, ("FmPcdLockTryLockAll failed"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex);
++    if (GET_ERROR_TYPE(err) != E_OK)
++    {
++        FmPcdLockUnlockAll(p_FmPcd);
++        RETURN_ERROR(
++                MAJOR,
++                err,
++                ("The received key and mask pair was not found in the match table of the provided node"));
++    }
++
++    err = FmPcdCcRemoveKey(p_FmPcd, p_CcNode, keyIndex);
++
++    FmPcdLockUnlockAll(p_FmPcd);
++
++    switch(GET_ERROR_TYPE(err)
++)    {
++        case E_OK:
++        return E_OK;
++
++        case E_BUSY:
++        DBG(TRACE, ("E_BUSY error"));
++        return ERROR_CODE(E_BUSY);
++
++        default:
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++}
++
++t_Error FM_PCD_MatchTableFindNModifyNextEngine(
++        t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask,
++        t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
++{
++    t_FmPcd *p_FmPcd;
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    uint16_t keyIndex;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
++
++    if (!FmPcdLockTryLockAll(p_FmPcd))
++    {
++        DBG(TRACE, ("FmPcdLockTryLockAll failed"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex);
++    if (GET_ERROR_TYPE(err) != E_OK)
++    {
++        FmPcdLockUnlockAll(p_FmPcd);
++        RETURN_ERROR(
++                MAJOR,
++                err,
++                ("The received key and mask pair was not found in the match table of the provided node"));
++    }
++
++    err = ModifyNextEngineParamNode(p_FmPcd, p_CcNode, keyIndex,
++                                    p_FmPcdCcNextEngineParams);
++
++    FmPcdLockUnlockAll(p_FmPcd);
++
++    switch(GET_ERROR_TYPE(err)
++)    {
++        case E_OK:
++        return E_OK;
++
++        case E_BUSY:
++        DBG(TRACE, ("E_BUSY error"));
++        return ERROR_CODE(E_BUSY);
++
++        default:
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++}
++
++t_Error FM_PCD_MatchTableFindNModifyKeyAndNextEngine(
++        t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask,
++        t_FmPcdCcKeyParams *p_KeyParams)
++{
++    t_FmPcd *p_FmPcd;
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    uint16_t keyIndex;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
++
++    if (!FmPcdLockTryLockAll(p_FmPcd))
++    {
++        DBG(TRACE, ("FmPcdLockTryLockAll failed"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex);
++    if (GET_ERROR_TYPE(err) != E_OK)
++    {
++        FmPcdLockUnlockAll(p_FmPcd);
++        RETURN_ERROR(
++                MAJOR,
++                err,
++                ("The received key and mask pair was not found in the match table of the provided node"));
++    }
++
++    err = FmPcdCcModifyKeyAndNextEngine(p_FmPcd, h_CcNode, keyIndex, keySize,
++                                        p_KeyParams);
++
++    FmPcdLockUnlockAll(p_FmPcd);
++
++    switch(GET_ERROR_TYPE(err)
++)    {
++        case E_OK:
++        return E_OK;
++
++        case E_BUSY:
++        DBG(TRACE, ("E_BUSY error"));
++        return ERROR_CODE(E_BUSY);
++
++        default:
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++}
++
++t_Error FM_PCD_MatchTableFindNModifyKey(t_Handle h_CcNode, uint8_t keySize,
++                                        uint8_t *p_Key, uint8_t *p_Mask,
++                                        uint8_t *p_NewKey, uint8_t *p_NewMask)
++{
++    t_FmPcd *p_FmPcd;
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    t_List h_List;
++    uint16_t keyIndex;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_NewKey, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
++    p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
++
++    INIT_LIST(&h_List);
++
++    err = FmPcdCcNodeTreeTryLock(p_FmPcd, p_CcNode, &h_List);
++    if (err)
++    {
++        DBG(TRACE, ("Node's trees lock failed"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex);
++    if (GET_ERROR_TYPE(err) != E_OK)
++    {
++        FmPcdCcNodeTreeReleaseLock(p_FmPcd, &h_List);
++        RETURN_ERROR(MAJOR, err,
++                     ("The received key and mask pair was not found in the "
++                     "match table of the provided node"));
++    }
++
++    err = FmPcdCcModifyKey(p_FmPcd, p_CcNode, keyIndex, keySize, p_NewKey,
++                           p_NewMask);
++
++    FmPcdCcNodeTreeReleaseLock(p_FmPcd, &h_List);
++
++    switch(GET_ERROR_TYPE(err)
++)    {
++        case E_OK:
++        return E_OK;
++
++        case E_BUSY:
++        DBG(TRACE, ("E_BUSY error"));
++        return ERROR_CODE(E_BUSY);
++
++        default:
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++}
++
++t_Error FM_PCD_MatchTableGetNextEngine(
++        t_Handle h_CcNode, uint16_t keyIndex,
++        t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++
++    SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
++
++    if (keyIndex >= p_CcNode->numOfKeys)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                     ("keyIndex exceeds current number of keys"));
++
++    if (keyIndex > (FM_PCD_MAX_NUM_OF_KEYS - 1))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("keyIndex can not be larger than %d", (FM_PCD_MAX_NUM_OF_KEYS - 1)));
++
++    memcpy(p_FmPcdCcNextEngineParams,
++           &p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams,
++           sizeof(t_FmPcdCcNextEngineParams));
++
++    return E_OK;
++}
++
++
++uint32_t FM_PCD_MatchTableGetKeyCounter(t_Handle h_CcNode, uint16_t keyIndex)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    uint32_t *p_StatsCounters, frameCount;
++    uint32_t intFlags;
++
++    SANITY_CHECK_RETURN_VALUE(p_CcNode, E_INVALID_HANDLE, 0);
++
++    if (p_CcNode->statisticsMode == e_FM_PCD_CC_STATS_MODE_NONE)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Statistics were not enabled for this match table"));
++        return 0;
++    }
++
++    if ((p_CcNode->statisticsMode != e_FM_PCD_CC_STATS_MODE_FRAME)
++            && (p_CcNode->statisticsMode
++                    != e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME))
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Frame count is not supported in the statistics mode of this match table"));
++        return 0;
++    }
++
++    intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock);
++
++    if (keyIndex >= p_CcNode->numOfKeys)
++    {
++        XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("The provided keyIndex exceeds the number of keys in this match table"));
++        return 0;
++    }
++
++    if (!p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj)
++    {
++        XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Statistics were not enabled for this key"));
++        return 0;
++    }
++
++    p_StatsCounters =
++            p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsCounters;
++    ASSERT_COND(p_StatsCounters);
++
++    /* The first counter is byte counter, so we need to advance to the next counter */
++    frameCount = GET_UINT32(*(uint32_t *)(PTR_MOVE(p_StatsCounters,
++                            FM_PCD_CC_STATS_COUNTER_SIZE)));
++
++    XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
++
++    return frameCount;
++}
++
++t_Error FM_PCD_MatchTableGetKeyStatistics(
++        t_Handle h_CcNode, uint16_t keyIndex,
++        t_FmPcdCcKeyStatistics *p_KeyStatistics)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    uint32_t intFlags;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(h_CcNode, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_KeyStatistics, E_NULL_POINTER);
++
++    intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock);
++
++    if (keyIndex >= p_CcNode->numOfKeys)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_STATE,
++                ("The provided keyIndex exceeds the number of keys in this match table"));
++
++    err = MatchTableGetKeyStatistics(p_CcNode, keyIndex, p_KeyStatistics);
++
++    XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
++
++    if (err != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++t_Error FM_PCD_MatchTableGetMissStatistics(
++        t_Handle h_CcNode, t_FmPcdCcKeyStatistics *p_MissStatistics)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    uint32_t intFlags;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(h_CcNode, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_MissStatistics, E_NULL_POINTER);
++
++    intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock);
++
++    err = MatchTableGetKeyStatistics(p_CcNode, p_CcNode->numOfKeys,
++                                     p_MissStatistics);
++
++    XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
++
++    if (err != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++t_Error FM_PCD_MatchTableFindNGetKeyStatistics(
++        t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask,
++        t_FmPcdCcKeyStatistics *p_KeyStatistics)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    uint16_t keyIndex;
++    uint32_t intFlags;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_KeyStatistics, E_NULL_POINTER);
++
++    intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock);
++
++    err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex);
++    if (GET_ERROR_TYPE(err) != E_OK)
++    {
++        XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
++        RETURN_ERROR(MAJOR, err,
++                     ("The received key and mask pair was not found in the "
++                     "match table of the provided node"));
++    }
++
++    ASSERT_COND(keyIndex < p_CcNode->numOfKeys);
++
++    err = MatchTableGetKeyStatistics(p_CcNode, keyIndex, p_KeyStatistics);
++
++    XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
++
++    if (err != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++t_Error FM_PCD_MatchTableGetIndexedHashBucket(t_Handle h_CcNode,
++                                              uint8_t keySize, uint8_t *p_Key,
++                                              uint8_t hashShift,
++                                              t_Handle *p_CcNodeBucketHandle,
++                                              uint8_t *p_BucketIndex,
++                                              uint16_t *p_LastIndex)
++{
++    t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
++    uint16_t glblMask;
++    uint64_t crc64 = 0;
++
++    SANITY_CHECK_RETURN_ERROR(h_CcNode, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(
++            p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED,
++            E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_CcNodeBucketHandle, E_NULL_POINTER);
++
++    memcpy(&glblMask, PTR_MOVE(p_CcNode->p_GlblMask, 2), 2);
++    be16_to_cpus(&glblMask);
++
++    crc64 = crc64_init();
++    crc64 = crc64_compute(p_Key, keySize, crc64);
++    crc64 >>= hashShift;
++
++    *p_BucketIndex = (uint8_t)(((crc64 >> (8 * (6 - p_CcNode->userOffset)))
++            & glblMask) >> 4);
++    if (*p_BucketIndex >= p_CcNode->numOfKeys)
++        RETURN_ERROR(MINOR, E_NOT_IN_RANGE, ("bucket index!"));
++
++    *p_CcNodeBucketHandle =
++            p_CcNode->keyAndNextEngineParams[*p_BucketIndex].nextEngineParams.params.ccParams.h_CcNode;
++    if (!*p_CcNodeBucketHandle)
++        RETURN_ERROR(MINOR, E_NOT_FOUND, ("bucket!"));
++
++    *p_LastIndex = ((t_FmPcdCcNode *)*p_CcNodeBucketHandle)->numOfKeys;
++
++    return E_OK;
++}
++
++t_Handle FM_PCD_HashTableSet(t_Handle h_FmPcd, t_FmPcdHashTableParams *p_Param)
++{
++    t_FmPcdCcNode *p_CcNodeHashTbl;
++    t_FmPcdCcNodeParams *p_IndxHashCcNodeParam, *p_ExactMatchCcNodeParam;
++    t_FmPcdCcNode *p_CcNode;
++    t_Handle h_MissStatsCounters = NULL;
++    t_FmPcdCcKeyParams *p_HashKeyParams;
++    int i;
++    uint16_t numOfSets, numOfWays, countMask, onesCount = 0;
++    bool statsEnForMiss = FALSE;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(p_Param, E_NULL_POINTER, NULL);
++
++    if (p_Param->maxNumOfKeys == 0)
++    {
++        REPORT_ERROR(MINOR, E_INVALID_VALUE, ("Max number of keys must be higher then 0"));
++        return NULL;
++    }
++
++    if (p_Param->hashResMask == 0)
++    {
++        REPORT_ERROR(MINOR, E_INVALID_VALUE, ("Hash result mask must differ from 0"));
++        return NULL;
++    }
++
++    /*Fix: QorIQ SDK / QSDK-2131*/
++    if (p_Param->ccNextEngineParamsForMiss.nextEngine == e_FM_PCD_INVALID)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Next PCD Engine for on-miss entry is invalid. On-miss entry is always required. You can use e_FM_PCD_DONE."));
++        return NULL;
++    }
++
++#if (DPAA_VERSION >= 11)
++    if (p_Param->statisticsMode == e_FM_PCD_CC_STATS_MODE_RMON)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE,
++                ("RMON statistics mode is not supported for hash table"));
++        return NULL;
++    }
++#endif /* (DPAA_VERSION >= 11) */
++
++    p_ExactMatchCcNodeParam = (t_FmPcdCcNodeParams*)XX_Malloc(
++            sizeof(t_FmPcdCcNodeParams));
++    if (!p_ExactMatchCcNodeParam)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_ExactMatchCcNodeParam"));
++        return NULL;
++    }
++    memset(p_ExactMatchCcNodeParam, 0, sizeof(t_FmPcdCcNodeParams));
++
++    p_IndxHashCcNodeParam = (t_FmPcdCcNodeParams*)XX_Malloc(
++            sizeof(t_FmPcdCcNodeParams));
++    if (!p_IndxHashCcNodeParam)
++    {
++        XX_Free(p_ExactMatchCcNodeParam);
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_IndxHashCcNodeParam"));
++        return NULL;
++    }
++    memset(p_IndxHashCcNodeParam, 0, sizeof(t_FmPcdCcNodeParams));
++
++    /* Calculate number of sets and number of ways of the hash table */
++    countMask = (uint16_t)(p_Param->hashResMask >> 4);
++    while (countMask)
++    {
++        onesCount++;
++        countMask = (uint16_t)(countMask >> 1);
++    }
++
++    numOfSets = (uint16_t)(1 << onesCount);
++    numOfWays = (uint16_t)DIV_CEIL(p_Param->maxNumOfKeys, numOfSets);
++
++    if (p_Param->maxNumOfKeys % numOfSets)
++        DBG(INFO, ("'maxNumOfKeys' is not a multiple of hash number of ways, so number of ways will be rounded up"));
++
++    if ((p_Param->statisticsMode == e_FM_PCD_CC_STATS_MODE_FRAME)
++            || (p_Param->statisticsMode == e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME))
++    {
++        /* Allocating a statistics counters table that will be used by all
++         'miss' entries of the hash table */
++        h_MissStatsCounters = (t_Handle)FM_MURAM_AllocMem(
++                FmPcdGetMuramHandle(h_FmPcd), 2 * FM_PCD_CC_STATS_COUNTER_SIZE,
++                FM_PCD_CC_AD_TABLE_ALIGN);
++        if (!h_MissStatsCounters)
++        {
++            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for statistics table for hash miss"));
++            XX_Free(p_IndxHashCcNodeParam);
++            XX_Free(p_ExactMatchCcNodeParam);
++            return NULL;
++        }
++        memset(h_MissStatsCounters, 0, (2 * FM_PCD_CC_STATS_COUNTER_SIZE));
++
++        /* Always enable statistics for 'miss', so that a statistics AD will be
++         initialized from the start. We'll store the requested 'statistics enable'
++         value and it will be used when statistics are read by the user. */
++        statsEnForMiss = p_Param->ccNextEngineParamsForMiss.statisticsEn;
++        p_Param->ccNextEngineParamsForMiss.statisticsEn = TRUE;
++    }
++
++    /* Building exact-match node params, will be used to create the hash buckets */
++    p_ExactMatchCcNodeParam->extractCcParams.type = e_FM_PCD_EXTRACT_NON_HDR;
++
++    p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.src =
++            e_FM_PCD_EXTRACT_FROM_KEY;
++    p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.action =
++            e_FM_PCD_ACTION_EXACT_MATCH;
++    p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.offset = 0;
++    p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.size =
++            p_Param->matchKeySize;
++
++    p_ExactMatchCcNodeParam->keysParams.maxNumOfKeys = numOfWays;
++    p_ExactMatchCcNodeParam->keysParams.maskSupport = FALSE;
++    p_ExactMatchCcNodeParam->keysParams.statisticsMode =
++            p_Param->statisticsMode;
++    p_ExactMatchCcNodeParam->keysParams.numOfKeys = 0;
++    p_ExactMatchCcNodeParam->keysParams.keySize = p_Param->matchKeySize;
++    p_ExactMatchCcNodeParam->keysParams.ccNextEngineParamsForMiss =
++            p_Param->ccNextEngineParamsForMiss;
++
++    p_HashKeyParams = p_IndxHashCcNodeParam->keysParams.keyParams;
++
++    for (i = 0; i < numOfSets; i++)
++    {
++        /* Each exact-match node will be marked as a 'bucket' and provided with
++           a pointer to statistics counters, to be used for 'miss' entry
++           statistics */
++        p_CcNode = (t_FmPcdCcNode *)XX_Malloc(sizeof(t_FmPcdCcNode));
++        if (!p_CcNode)
++            break;
++        memset(p_CcNode, 0, sizeof(t_FmPcdCcNode));
++
++        p_CcNode->isHashBucket = TRUE;
++        p_CcNode->h_MissStatsCounters = h_MissStatsCounters;
++
++        err = MatchTableSet(h_FmPcd, p_CcNode, p_ExactMatchCcNodeParam);
++        if (err)
++            break;
++
++        p_HashKeyParams[i].ccNextEngineParams.nextEngine = e_FM_PCD_CC;
++        p_HashKeyParams[i].ccNextEngineParams.statisticsEn = FALSE;
++        p_HashKeyParams[i].ccNextEngineParams.params.ccParams.h_CcNode =
++                p_CcNode;
++    }
++
++    if (i < numOfSets)
++    {
++        for (i = i - 1; i >= 0; i--)
++            FM_PCD_MatchTableDelete(
++                    p_HashKeyParams[i].ccNextEngineParams.params.ccParams.h_CcNode);
++
++        FM_MURAM_FreeMem(FmPcdGetMuramHandle(h_FmPcd), h_MissStatsCounters);
++
++        REPORT_ERROR(MAJOR, E_NULL_POINTER, NO_MSG);
++        XX_Free(p_IndxHashCcNodeParam);
++        XX_Free(p_ExactMatchCcNodeParam);
++        return NULL;
++    }
++
++    /* Creating indexed-hash CC node */
++    p_IndxHashCcNodeParam->extractCcParams.type = e_FM_PCD_EXTRACT_NON_HDR;
++    p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.src =
++            e_FM_PCD_EXTRACT_FROM_HASH;
++    p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.action =
++            e_FM_PCD_ACTION_INDEXED_LOOKUP;
++    p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.icIndxMask =
++            p_Param->hashResMask;
++    p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.offset =
++            p_Param->hashShift;
++    p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.size = 2;
++
++    p_IndxHashCcNodeParam->keysParams.maxNumOfKeys = numOfSets;
++    p_IndxHashCcNodeParam->keysParams.maskSupport = FALSE;
++    p_IndxHashCcNodeParam->keysParams.statisticsMode =
++            e_FM_PCD_CC_STATS_MODE_NONE;
++    /* Number of keys of this node is number of sets of the hash */
++    p_IndxHashCcNodeParam->keysParams.numOfKeys = numOfSets;
++    p_IndxHashCcNodeParam->keysParams.keySize = 2;
++
++    p_CcNodeHashTbl = FM_PCD_MatchTableSet(h_FmPcd, p_IndxHashCcNodeParam);
++
++    if (p_CcNodeHashTbl)
++    {
++        p_CcNodeHashTbl->kgHashShift = p_Param->kgHashShift;
++
++        /* Storing the allocated counters for buckets 'miss' in the hash table
++         and if statistics for miss were enabled. */
++        p_CcNodeHashTbl->h_MissStatsCounters = h_MissStatsCounters;
++        p_CcNodeHashTbl->statsEnForMiss = statsEnForMiss;
++    }
++
++    XX_Free(p_IndxHashCcNodeParam);
++    XX_Free(p_ExactMatchCcNodeParam);
++
++    return p_CcNodeHashTbl;
++}
++
++t_Error FM_PCD_HashTableDelete(t_Handle h_HashTbl)
++{
++    t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
++    t_Handle h_FmPcd;
++    t_Handle *p_HashBuckets, h_MissStatsCounters;
++    uint16_t i, numOfBuckets;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE);
++
++    /* Store all hash buckets before the hash is freed */
++    numOfBuckets = p_HashTbl->numOfKeys;
++
++    p_HashBuckets = (t_Handle *)XX_Malloc(numOfBuckets * sizeof(t_Handle));
++    if (!p_HashBuckets)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++
++    for (i = 0; i < numOfBuckets; i++)
++        p_HashBuckets[i] =
++                p_HashTbl->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode;
++
++    h_FmPcd = p_HashTbl->h_FmPcd;
++    h_MissStatsCounters = p_HashTbl->h_MissStatsCounters;
++
++    /* Free the hash */
++    err = FM_PCD_MatchTableDelete(p_HashTbl);
++
++    /* Free each hash bucket */
++    for (i = 0; i < numOfBuckets; i++)
++        err |= FM_PCD_MatchTableDelete(p_HashBuckets[i]);
++
++    XX_Free(p_HashBuckets);
++
++    /* Free statistics counters for 'miss', if these were allocated */
++    if (h_MissStatsCounters)
++        FM_MURAM_FreeMem(FmPcdGetMuramHandle(h_FmPcd), h_MissStatsCounters);
++
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++t_Error FM_PCD_HashTableAddKey(t_Handle h_HashTbl, uint8_t keySize,
++                               t_FmPcdCcKeyParams *p_KeyParams)
++{
++    t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
++    t_Handle h_HashBucket;
++    uint8_t bucketIndex;
++    uint16_t lastIndex;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_KeyParams->p_Key, E_NULL_POINTER);
++
++    if (p_KeyParams->p_Mask)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("Keys masks not supported for hash table"));
++
++    err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize,
++                                                p_KeyParams->p_Key,
++                                                p_HashTbl->kgHashShift,
++                                                &h_HashBucket, &bucketIndex,
++                                                &lastIndex);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    return FM_PCD_MatchTableAddKey(h_HashBucket, FM_PCD_LAST_KEY_INDEX, keySize,
++                                   p_KeyParams);
++}
++
++t_Error FM_PCD_HashTableRemoveKey(t_Handle h_HashTbl, uint8_t keySize,
++                                  uint8_t *p_Key)
++{
++    t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
++    t_Handle h_HashBucket;
++    uint8_t bucketIndex;
++    uint16_t lastIndex;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
++
++    err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize, p_Key,
++                                                p_HashTbl->kgHashShift,
++                                                &h_HashBucket, &bucketIndex,
++                                                &lastIndex);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    return FM_PCD_MatchTableFindNRemoveKey(h_HashBucket, keySize, p_Key, NULL);
++}
++
++t_Error FM_PCD_HashTableModifyNextEngine(
++        t_Handle h_HashTbl, uint8_t keySize, uint8_t *p_Key,
++        t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
++{
++    t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
++    t_Handle h_HashBucket;
++    uint8_t bucketIndex;
++    uint16_t lastIndex;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
++
++    err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize, p_Key,
++                                                p_HashTbl->kgHashShift,
++                                                &h_HashBucket, &bucketIndex,
++                                                &lastIndex);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    return FM_PCD_MatchTableFindNModifyNextEngine(h_HashBucket, keySize, p_Key,
++                                                  NULL,
++                                                  p_FmPcdCcNextEngineParams);
++}
++
++t_Error FM_PCD_HashTableModifyMissNextEngine(
++        t_Handle h_HashTbl,
++        t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
++{
++    t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
++    t_Handle h_HashBucket;
++    uint8_t i;
++    bool nullifyMissStats = FALSE;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(h_HashTbl, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
++
++    if ((!p_HashTbl->h_MissStatsCounters)
++            && (p_FmPcdCcNextEngineParams->statisticsEn))
++        RETURN_ERROR(
++                MAJOR,
++                E_CONFLICT,
++                ("Statistics are requested for a key, but statistics mode was set"
++                "to 'NONE' upon initialization"));
++
++    if (p_HashTbl->h_MissStatsCounters)
++    {
++        if ((!p_HashTbl->statsEnForMiss)
++                && (p_FmPcdCcNextEngineParams->statisticsEn))
++            nullifyMissStats = TRUE;
++
++        if ((p_HashTbl->statsEnForMiss)
++                && (!p_FmPcdCcNextEngineParams->statisticsEn))
++        {
++            p_HashTbl->statsEnForMiss = FALSE;
++            p_FmPcdCcNextEngineParams->statisticsEn = TRUE;
++        }
++    }
++
++    for (i = 0; i < p_HashTbl->numOfKeys; i++)
++    {
++        h_HashBucket =
++                p_HashTbl->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode;
++
++        err = FM_PCD_MatchTableModifyMissNextEngine(h_HashBucket,
++                                                    p_FmPcdCcNextEngineParams);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    if (nullifyMissStats)
++    {
++        memset(p_HashTbl->h_MissStatsCounters, 0,
++               (2 * FM_PCD_CC_STATS_COUNTER_SIZE));
++        memset(p_HashTbl->h_MissStatsCounters, 0,
++               (2 * FM_PCD_CC_STATS_COUNTER_SIZE));
++        p_HashTbl->statsEnForMiss = TRUE;
++    }
++
++    return E_OK;
++}
++
++
++t_Error FM_PCD_HashTableGetMissNextEngine(
++        t_Handle h_HashTbl,
++        t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
++{
++    t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
++    t_FmPcdCcNode *p_HashBucket;
++
++    SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE);
++
++    /* Miss next engine of each bucket was initialized with the next engine of the hash table */
++    p_HashBucket =
++            p_HashTbl->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode;
++
++    memcpy(p_FmPcdCcNextEngineParams,
++           &p_HashBucket->keyAndNextEngineParams[p_HashBucket->numOfKeys].nextEngineParams,
++           sizeof(t_FmPcdCcNextEngineParams));
++
++    return E_OK;
++}
++
++t_Error FM_PCD_HashTableFindNGetKeyStatistics(
++        t_Handle h_HashTbl, uint8_t keySize, uint8_t *p_Key,
++        t_FmPcdCcKeyStatistics *p_KeyStatistics)
++{
++    t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
++    t_Handle h_HashBucket;
++    uint8_t bucketIndex;
++    uint16_t lastIndex;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_KeyStatistics, E_NULL_POINTER);
++
++    err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize, p_Key,
++                                                p_HashTbl->kgHashShift,
++                                                &h_HashBucket, &bucketIndex,
++                                                &lastIndex);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    return FM_PCD_MatchTableFindNGetKeyStatistics(h_HashBucket, keySize, p_Key,
++                                                  NULL, p_KeyStatistics);
++}
++
++t_Error FM_PCD_HashTableGetMissStatistics(
++        t_Handle h_HashTbl, t_FmPcdCcKeyStatistics *p_MissStatistics)
++{
++    t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
++    t_Handle h_HashBucket;
++
++    SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_MissStatistics, E_NULL_POINTER);
++
++    if (!p_HashTbl->statsEnForMiss)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                     ("Statistics were not enabled for miss"));
++
++    h_HashBucket =
++            p_HashTbl->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode;
++
++    return FM_PCD_MatchTableGetMissStatistics(h_HashBucket, p_MissStatistics);
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.h
+@@ -0,0 +1,399 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_cc.h
++
++ @Description   FM PCD CC ...
++*//***************************************************************************/
++#ifndef __FM_CC_H
++#define __FM_CC_H
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "list_ext.h"
++
++#include "fm_pcd.h"
++
++
++/***********************************************************************/
++/*          Coarse classification defines                              */
++/***********************************************************************/
++
++#define CC_MAX_NUM_OF_KEYS                  (FM_PCD_MAX_NUM_OF_KEYS + 1)
++
++#define CC_PC_FF_MACDST                     0x00
++#define CC_PC_FF_MACSRC                     0x01
++#define CC_PC_FF_ETYPE                      0x02
++
++#define CC_PC_FF_TCI1                       0x03
++#define CC_PC_FF_TCI2                       0x04
++
++#define CC_PC_FF_MPLS1                      0x06
++#define CC_PC_FF_MPLS_LAST                  0x07
++
++#define CC_PC_FF_IPV4DST1                   0x08
++#define CC_PC_FF_IPV4DST2                   0x16
++#define CC_PC_FF_IPV4IPTOS_TC1              0x09
++#define CC_PC_FF_IPV4IPTOS_TC2              0x17
++#define CC_PC_FF_IPV4PTYPE1                 0x0A
++#define CC_PC_FF_IPV4PTYPE2                 0x18
++#define CC_PC_FF_IPV4SRC1                   0x0b
++#define CC_PC_FF_IPV4SRC2                   0x19
++#define CC_PC_FF_IPV4SRC1_IPV4DST1          0x0c
++#define CC_PC_FF_IPV4SRC2_IPV4DST2          0x1a
++#define CC_PC_FF_IPV4TTL                    0x29
++
++
++#define CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1    0x0d /*TODO - CLASS - what is it? TOS*/
++#define CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2    0x1b
++#define CC_PC_FF_IPV6PTYPE1                 0x0e
++#define CC_PC_FF_IPV6PTYPE2                 0x1c
++#define CC_PC_FF_IPV6DST1                   0x0f
++#define CC_PC_FF_IPV6DST2                   0x1d
++#define CC_PC_FF_IPV6SRC1                   0x10
++#define CC_PC_FF_IPV6SRC2                   0x1e
++#define CC_PC_FF_IPV6HOP_LIMIT              0x2a
++#define CC_PC_FF_IPPID                      0x24
++#define CC_PC_FF_IPDSCP                     0x76
++
++#define CC_PC_FF_GREPTYPE                   0x11
++
++#define CC_PC_FF_MINENCAP_PTYPE             0x12
++#define CC_PC_FF_MINENCAP_IPDST             0x13
++#define CC_PC_FF_MINENCAP_IPSRC             0x14
++#define CC_PC_FF_MINENCAP_IPSRC_IPDST       0x15
++
++#define CC_PC_FF_L4PSRC                     0x1f
++#define CC_PC_FF_L4PDST                     0x20
++#define CC_PC_FF_L4PSRC_L4PDST              0x21
++
++#define CC_PC_FF_PPPPID                     0x05
++
++#define CC_PC_PR_SHIM1                      0x22
++#define CC_PC_PR_SHIM2                      0x23
++
++#define CC_PC_GENERIC_WITHOUT_MASK          0x27
++#define CC_PC_GENERIC_WITH_MASK             0x28
++#define CC_PC_GENERIC_IC_GMASK              0x2B
++#define CC_PC_GENERIC_IC_HASH_INDEXED       0x2C
++#define CC_PC_GENERIC_IC_AGING_MASK         0x2D
++
++#define CC_PR_OFFSET                        0x25
++#define CC_PR_WITHOUT_OFFSET                0x26
++
++#define CC_PC_PR_ETH_OFFSET                 19
++#define CC_PC_PR_USER_DEFINED_SHIM1_OFFSET  16
++#define CC_PC_PR_USER_DEFINED_SHIM2_OFFSET  17
++#define CC_PC_PR_USER_LLC_SNAP_OFFSET       20
++#define CC_PC_PR_VLAN1_OFFSET               21
++#define CC_PC_PR_VLAN2_OFFSET               22
++#define CC_PC_PR_PPPOE_OFFSET               24
++#define CC_PC_PR_MPLS1_OFFSET               25
++#define CC_PC_PR_MPLS_LAST_OFFSET           26
++#define CC_PC_PR_IP1_OFFSET                 27
++#define CC_PC_PR_IP_LAST_OFFSET             28
++#define CC_PC_PR_MINENC_OFFSET              28
++#define CC_PC_PR_L4_OFFSET                  30
++#define CC_PC_PR_GRE_OFFSET                 29
++#define CC_PC_PR_ETYPE_LAST_OFFSET          23
++#define CC_PC_PR_NEXT_HEADER_OFFSET         31
++
++#define CC_PC_ILLEGAL                       0xff
++#define CC_SIZE_ILLEGAL                     0
++
++#define FM_PCD_CC_KEYS_MATCH_TABLE_ALIGN    16
++#define FM_PCD_CC_AD_TABLE_ALIGN            16
++#define FM_PCD_CC_AD_ENTRY_SIZE             16
++#define FM_PCD_CC_NUM_OF_KEYS               255
++#define FM_PCD_CC_TREE_ADDR_ALIGN           256
++
++#define FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE   0x00000000
++#define FM_PCD_AD_RESULT_DATA_FLOW_TYPE     0x80000000
++#define FM_PCD_AD_RESULT_PLCR_DIS           0x20000000
++#define FM_PCD_AD_RESULT_EXTENDED_MODE      0x80000000
++#define FM_PCD_AD_RESULT_NADEN              0x20000000
++#define FM_PCD_AD_RESULT_STATISTICS_EN      0x40000000
++
++#define FM_PCD_AD_CONT_LOOKUP_TYPE          0x40000000
++#define FM_PCD_AD_CONT_LOOKUP_LCL_MASK      0x00800000
++
++#define FM_PCD_AD_STATS_TYPE                0x40000000
++#define FM_PCD_AD_STATS_FLR_ADDR_MASK       0x00FFFFFF
++#define FM_PCD_AD_STATS_COUNTERS_ADDR_MASK  0x00FFFFFF
++#define FM_PCD_AD_STATS_NEXT_ACTION_MASK    0xFFFF0000
++#define FM_PCD_AD_STATS_NEXT_ACTION_SHIFT   12
++#define FM_PCD_AD_STATS_NAD_EN              0x00008000
++#define FM_PCD_AD_STATS_OP_CODE             0x00000036
++#define FM_PCD_AD_STATS_FLR_EN              0x00004000
++#define FM_PCD_AD_STATS_COND_EN             0x00002000
++
++
++
++#define FM_PCD_AD_BYPASS_TYPE               0xc0000000
++
++#define FM_PCD_AD_TYPE_MASK                 0xc0000000
++#define FM_PCD_AD_OPCODE_MASK               0x0000000f
++
++#define FM_PCD_AD_PROFILEID_FOR_CNTRL_SHIFT 16
++#if (DPAA_VERSION >= 11)
++#define FM_PCD_AD_RESULT_VSP_SHIFT           24
++#define FM_PCD_AD_RESULT_NO_OM_VSPE          0x02000000
++#define FM_PCD_AD_RESULT_VSP_MASK            0x3f
++#define FM_PCD_AD_NCSPFQIDM_MASK             0x80000000
++#endif /* (DPAA_VERSION >= 11) */
++
++#define GLBL_MASK_FOR_HASH_INDEXED          0xfff00000
++#define CC_GLBL_MASK_SIZE                   4
++#define CC_AGING_MASK_SIZE                  4
++
++typedef uint32_t ccPrivateInfo_t; /**< private info of CC: */
++
++#define CC_PRIVATE_INFO_NONE                       0
++#define CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP       0x80000000
++#define CC_PRIVATE_INFO_IC_HASH_EXACT_MATCH        0x40000000
++#define CC_PRIVATE_INFO_IC_KEY_EXACT_MATCH         0x20000000
++#define CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP   0x10000000
++
++#define CC_BUILD_AGING_MASK(numOfKeys)      ((((1LL << ((numOfKeys) + 1)) - 1)) << (31 - (numOfKeys)))
++/***********************************************************************/
++/*          Memory map                                                 */
++/***********************************************************************/
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(push,1)
++#endif /* defined(__MWERKS__) && ... */
++
++typedef struct
++{
++    volatile uint32_t fqid;
++    volatile uint32_t plcrProfile;
++    volatile uint32_t nia;
++    volatile uint32_t res;
++} t_AdOfTypeResult;
++
++typedef struct
++{
++    volatile uint32_t ccAdBase;
++    volatile uint32_t matchTblPtr;
++    volatile uint32_t pcAndOffsets;
++    volatile uint32_t gmask;
++} t_AdOfTypeContLookup;
++
++typedef struct
++{
++    volatile uint32_t profileTableAddr;
++    volatile uint32_t reserved;
++    volatile uint32_t nextActionIndx;
++    volatile uint32_t statsTableAddr;
++} t_AdOfTypeStats;
++
++typedef union
++{
++    volatile t_AdOfTypeResult        adResult;
++    volatile t_AdOfTypeContLookup    adContLookup;
++} t_Ad;
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(pop)
++#endif /* defined(__MWERKS__) && ... */
++
++
++/***********************************************************************/
++/*  Driver's internal structures                                       */
++/***********************************************************************/
++
++typedef struct t_FmPcdStatsObj
++{
++    t_Handle        h_StatsAd;
++    t_Handle        h_StatsCounters;
++    t_List          node;
++} t_FmPcdStatsObj;
++
++typedef struct
++{
++    uint8_t                     key[FM_PCD_MAX_SIZE_OF_KEY];
++    uint8_t                     mask[FM_PCD_MAX_SIZE_OF_KEY];
++
++    t_FmPcdCcNextEngineParams   nextEngineParams;
++    uint32_t                    requiredAction;
++    uint32_t                    shadowAction;
++
++    t_FmPcdStatsObj             *p_StatsObj;
++
++} t_FmPcdCcKeyAndNextEngineParams;
++
++typedef struct
++{
++    t_Handle        p_Ad;
++    e_FmPcdEngine   fmPcdEngine;
++    bool            adAllocated;
++    bool            isTree;
++
++    uint32_t        myInfo;
++    t_List          *h_CcNextNodesLst;
++    t_Handle        h_AdditionalInfo;
++    t_Handle        h_Node;
++} t_FmPcdModifyCcAdditionalParams;
++
++typedef struct
++{
++    t_Handle            p_AdTableNew;
++    t_Handle            p_KeysMatchTableNew;
++    t_Handle            p_AdTableOld;
++    t_Handle            p_KeysMatchTableOld;
++    uint16_t            numOfKeys;
++    t_Handle            h_CurrentNode;
++    uint16_t            savedKeyIndex;
++    t_Handle            h_NodeForAdd;
++    t_Handle            h_NodeForRmv;
++    t_Handle            h_ManipForRmv;
++    t_Handle            h_ManipForAdd;
++    t_FmPcdStatsObj     *p_StatsObjForRmv;
++#if (DPAA_VERSION >= 11)
++    t_Handle            h_FrmReplicForAdd;
++    t_Handle            h_FrmReplicForRmv;
++#endif /* (DPAA_VERSION >= 11) */
++    bool                tree;
++
++    t_FmPcdCcKeyAndNextEngineParams  keyAndNextEngineParams[CC_MAX_NUM_OF_KEYS];
++} t_FmPcdModifyCcKeyAdditionalParams;
++
++typedef struct
++{
++    t_Handle    h_Manip;
++    t_Handle    h_CcNode;
++} t_CcNextEngineInfo;
++
++typedef struct
++{
++    uint16_t            numOfKeys;
++    uint16_t            maxNumOfKeys;
++
++    bool                maskSupport;
++    uint32_t            keysMatchTableMaxSize;
++
++    e_FmPcdCcStatsMode  statisticsMode;
++    uint32_t            numOfStatsFLRs;
++    uint32_t            countersArraySize;
++
++    bool                isHashBucket;               /**< Valid for match table node that is a bucket of a hash table only */
++    t_Handle            h_MissStatsCounters;        /**< Valid for hash table node and match table that is a bucket;
++                                                         Holds the statistics counters allocated by the hash table and
++                                                         are shared by all hash table buckets; */
++    t_Handle            h_PrivMissStatsCounters;    /**< Valid for match table node that is a bucket of a hash table only;
++                                                         Holds the statistics counters that were allocated for this node
++                                                         and replaced by the shared counters (allocated by the hash table); */
++    bool                statsEnForMiss;             /**< Valid for hash table node only; TRUE is statistics are currently
++                                                         enabled for hash 'miss', FALSE otherwise; This parameter effects the
++                                                         returned statistics count to user, statistics AD always present for 'miss'
++                                                         for all hash buckets; */
++    bool                glblMaskUpdated;
++    t_Handle            p_GlblMask;
++    bool                lclMask;
++    uint8_t             parseCode;
++    uint8_t             offset;
++    uint8_t             prsArrayOffset;
++    bool                ctrlFlow;
++    uint16_t            owners;
++
++    uint8_t             ccKeySizeAccExtraction;
++    uint8_t             sizeOfExtraction;
++    uint8_t             glblMaskSize;
++
++    t_Handle            h_KeysMatchTable;
++    t_Handle            h_AdTable;
++    t_Handle            h_StatsAds;
++    t_Handle            h_TmpAd;
++    t_Handle            h_Ad;
++    t_Handle            h_StatsFLRs;
++
++    t_List              availableStatsLst;
++
++    t_List              ccPrevNodesLst;
++
++    t_List              ccTreeIdLst;
++    t_List              ccTreesLst;
++
++    t_Handle            h_FmPcd;
++    uint32_t            shadowAction;
++    uint8_t             userSizeOfExtraction;
++    uint8_t             userOffset;
++    uint8_t             kgHashShift;            /* used in hash-table */
++
++    t_Handle            h_Spinlock;
++
++    t_FmPcdCcKeyAndNextEngineParams keyAndNextEngineParams[CC_MAX_NUM_OF_KEYS];
++} t_FmPcdCcNode;
++
++typedef struct
++{
++    t_FmPcdCcNode       *p_FmPcdCcNode;
++    bool                occupied;
++    uint16_t            owners;
++    volatile bool       lock;
++} t_FmPcdCcNodeArray;
++
++typedef struct
++{
++    uint8_t             numOfEntriesInGroup;
++    uint32_t            totalBitsMask;
++    uint8_t             baseGroupEntry;
++} t_FmPcdCcGroupParam;
++
++typedef struct
++{
++    t_Handle            h_FmPcd;
++    uint8_t             netEnvId;
++    uintptr_t           ccTreeBaseAddr;
++    uint8_t             numOfGrps;
++    t_FmPcdCcGroupParam fmPcdGroupParam[FM_PCD_MAX_NUM_OF_CC_GROUPS];
++    t_List              fmPortsLst;
++    t_FmPcdLock         *p_Lock;
++    uint8_t             numOfEntries;
++    uint16_t            owners;
++    t_Handle            h_FmPcdCcSavedManipParams;
++    bool                modifiedState;
++    uint32_t            requiredAction;
++    t_Handle            h_IpReassemblyManip;
++    t_Handle            h_CapwapReassemblyManip;
++
++    t_FmPcdCcKeyAndNextEngineParams keyAndNextEngineParams[FM_PCD_MAX_NUM_OF_CC_GROUPS];
++} t_FmPcdCcTree;
++
++
++t_Error     FmPcdCcNodeTreeTryLock(t_Handle h_FmPcd,t_Handle h_FmPcdCcNode, t_List *p_List);
++void        FmPcdCcNodeTreeReleaseLock(t_Handle h_FmPcd, t_List *p_List);
++t_Error     FmPcdUpdateCcShadow (t_FmPcd *p_FmPcd, uint32_t size, uint32_t align);
++
++
++#endif /* __FM_CC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c
+@@ -0,0 +1,3242 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_kg.c
++
++ @Description   FM PCD ...
++*//***************************************************************************/
++#include "std_ext.h"
++#include "error_ext.h"
++#include "string_ext.h"
++#include "debug_ext.h"
++#include "net_ext.h"
++#include "fm_port_ext.h"
++
++#include "fm_common.h"
++#include "fm_pcd.h"
++#include "fm_hc.h"
++#include "fm_pcd_ipc.h"
++#include "fm_kg.h"
++#include "fsl_fman_kg.h"
++
++
++/****************************************/
++/*       static functions               */
++/****************************************/
++
++static uint32_t KgHwLock(t_Handle h_FmPcdKg)
++{
++    ASSERT_COND(h_FmPcdKg);
++    return XX_LockIntrSpinlock(((t_FmPcdKg *)h_FmPcdKg)->h_HwSpinlock);
++}
++
++static void KgHwUnlock(t_Handle h_FmPcdKg, uint32_t intFlags)
++{
++    ASSERT_COND(h_FmPcdKg);
++    XX_UnlockIntrSpinlock(((t_FmPcdKg *)h_FmPcdKg)->h_HwSpinlock, intFlags);
++}
++
++static uint32_t KgSchemeLock(t_Handle h_Scheme)
++{
++    ASSERT_COND(h_Scheme);
++    return FmPcdLockSpinlock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock);
++}
++
++static void KgSchemeUnlock(t_Handle h_Scheme, uint32_t intFlags)
++{
++    ASSERT_COND(h_Scheme);
++    FmPcdUnlockSpinlock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock, intFlags);
++}
++
++static bool KgSchemeFlagTryLock(t_Handle h_Scheme)
++{
++    ASSERT_COND(h_Scheme);
++    return FmPcdLockTryLock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock);
++}
++
++static void KgSchemeFlagUnlock(t_Handle h_Scheme)
++{
++    ASSERT_COND(h_Scheme);
++    FmPcdLockUnlock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock);
++}
++
++static t_Error WriteKgarWait(t_FmPcd *p_FmPcd, uint32_t fmkg_ar)
++{
++
++    struct fman_kg_regs *regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
++
++    if (fman_kg_write_ar_wait(regs, fmkg_ar))
++        RETURN_ERROR(MINOR, E_INVALID_STATE, ("Keygen scheme access violation"));
++
++    return E_OK;
++}
++
++static e_FmPcdKgExtractDfltSelect GetGenericSwDefault(t_FmPcdKgExtractDflt swDefaults[], uint8_t numOfSwDefaults, uint8_t code)
++{
++    int i;
++
++    switch (code)
++    {
++        case (KG_SCH_GEN_PARSE_RESULT_N_FQID):
++        case (KG_SCH_GEN_DEFAULT):
++        case (KG_SCH_GEN_NEXTHDR):
++            for (i=0 ; i<numOfSwDefaults ; i++)
++                if (swDefaults[i].type == e_FM_PCD_KG_GENERIC_NOT_FROM_DATA)
++                    return swDefaults[i].dfltSelect;
++            break;
++        case (KG_SCH_GEN_SHIM1):
++        case (KG_SCH_GEN_SHIM2):
++        case (KG_SCH_GEN_IP_PID_NO_V):
++        case (KG_SCH_GEN_ETH_NO_V):
++        case (KG_SCH_GEN_SNAP_NO_V):
++        case (KG_SCH_GEN_VLAN1_NO_V):
++        case (KG_SCH_GEN_VLAN2_NO_V):
++        case (KG_SCH_GEN_ETH_TYPE_NO_V):
++        case (KG_SCH_GEN_PPP_NO_V):
++        case (KG_SCH_GEN_MPLS1_NO_V):
++        case (KG_SCH_GEN_MPLS_LAST_NO_V):
++        case (KG_SCH_GEN_L3_NO_V):
++        case (KG_SCH_GEN_IP2_NO_V):
++        case (KG_SCH_GEN_GRE_NO_V):
++        case (KG_SCH_GEN_L4_NO_V):
++            for (i=0 ; i<numOfSwDefaults ; i++)
++                if (swDefaults[i].type == e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V)
++                    return swDefaults[i].dfltSelect;
++            break;
++        case (KG_SCH_GEN_START_OF_FRM):
++        case (KG_SCH_GEN_ETH):
++        case (KG_SCH_GEN_SNAP):
++        case (KG_SCH_GEN_VLAN1):
++        case (KG_SCH_GEN_VLAN2):
++        case (KG_SCH_GEN_ETH_TYPE):
++        case (KG_SCH_GEN_PPP):
++        case (KG_SCH_GEN_MPLS1):
++        case (KG_SCH_GEN_MPLS2):
++        case (KG_SCH_GEN_MPLS3):
++        case (KG_SCH_GEN_MPLS_LAST):
++        case (KG_SCH_GEN_IPV4):
++        case (KG_SCH_GEN_IPV6):
++        case (KG_SCH_GEN_IPV4_TUNNELED):
++        case (KG_SCH_GEN_IPV6_TUNNELED):
++        case (KG_SCH_GEN_MIN_ENCAP):
++        case (KG_SCH_GEN_GRE):
++        case (KG_SCH_GEN_TCP):
++        case (KG_SCH_GEN_UDP):
++        case (KG_SCH_GEN_IPSEC_AH):
++        case (KG_SCH_GEN_SCTP):
++        case (KG_SCH_GEN_DCCP):
++        case (KG_SCH_GEN_IPSEC_ESP):
++            for (i=0 ; i<numOfSwDefaults ; i++)
++                if (swDefaults[i].type == e_FM_PCD_KG_GENERIC_FROM_DATA)
++                    return swDefaults[i].dfltSelect;
++            break;
++        default:
++            break;
++    }
++
++    return e_FM_PCD_KG_DFLT_ILLEGAL;
++}
++
++static uint8_t GetGenCode(e_FmPcdExtractFrom src, uint8_t *p_Offset)
++{
++    *p_Offset = 0;
++
++    switch (src)
++    {
++        case (e_FM_PCD_EXTRACT_FROM_FRAME_START):
++            return KG_SCH_GEN_START_OF_FRM;
++        case (e_FM_PCD_EXTRACT_FROM_DFLT_VALUE):
++            return KG_SCH_GEN_DEFAULT;
++        case (e_FM_PCD_EXTRACT_FROM_PARSE_RESULT):
++            return KG_SCH_GEN_PARSE_RESULT_N_FQID;
++        case (e_FM_PCD_EXTRACT_FROM_ENQ_FQID):
++            *p_Offset = 32;
++            return KG_SCH_GEN_PARSE_RESULT_N_FQID;
++        case (e_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE):
++            return KG_SCH_GEN_NEXTHDR;
++        default:
++            REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 'extract from' src"));
++            return 0;
++    }
++}
++
++static uint8_t GetGenHdrCode(e_NetHeaderType hdr, e_FmPcdHdrIndex hdrIndex, bool ignoreProtocolValidation)
++{
++    if (!ignoreProtocolValidation)
++        switch (hdr)
++        {
++            case (HEADER_TYPE_NONE):
++                ASSERT_COND(FALSE);
++            case (HEADER_TYPE_ETH):
++                return KG_SCH_GEN_ETH;
++            case (HEADER_TYPE_LLC_SNAP):
++                return KG_SCH_GEN_SNAP;
++            case (HEADER_TYPE_PPPoE):
++                return KG_SCH_GEN_PPP;
++            case (HEADER_TYPE_MPLS):
++                if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
++                    return KG_SCH_GEN_MPLS1;
++                if (hdrIndex == e_FM_PCD_HDR_INDEX_2)
++                    return KG_SCH_GEN_MPLS2;
++                if (hdrIndex == e_FM_PCD_HDR_INDEX_3)
++                    return KG_SCH_GEN_MPLS3;
++                if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
++                    return KG_SCH_GEN_MPLS_LAST;
++                REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS header index"));
++                return 0;
++            case (HEADER_TYPE_IPv4):
++                if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
++                    return KG_SCH_GEN_IPV4;
++                if ((hdrIndex == e_FM_PCD_HDR_INDEX_2) || (hdrIndex == e_FM_PCD_HDR_INDEX_LAST))
++                    return KG_SCH_GEN_IPV4_TUNNELED;
++                REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 header index"));
++                return 0;
++            case (HEADER_TYPE_IPv6):
++                if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
++                    return KG_SCH_GEN_IPV6;
++                if ((hdrIndex == e_FM_PCD_HDR_INDEX_2) || (hdrIndex == e_FM_PCD_HDR_INDEX_LAST))
++                    return KG_SCH_GEN_IPV6_TUNNELED;
++                REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 header index"));
++                return 0;
++            case (HEADER_TYPE_GRE):
++                return KG_SCH_GEN_GRE;
++            case (HEADER_TYPE_TCP):
++                return KG_SCH_GEN_TCP;
++            case (HEADER_TYPE_UDP):
++                return KG_SCH_GEN_UDP;
++            case (HEADER_TYPE_IPSEC_AH):
++                return KG_SCH_GEN_IPSEC_AH;
++            case (HEADER_TYPE_IPSEC_ESP):
++                return KG_SCH_GEN_IPSEC_ESP;
++            case (HEADER_TYPE_SCTP):
++                return KG_SCH_GEN_SCTP;
++            case (HEADER_TYPE_DCCP):
++                return KG_SCH_GEN_DCCP;
++            default:
++                REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                return 0;
++        }
++    else
++        switch (hdr)
++        {
++            case (HEADER_TYPE_NONE):
++                ASSERT_COND(FALSE);
++            case (HEADER_TYPE_ETH):
++                return KG_SCH_GEN_ETH_NO_V;
++            case (HEADER_TYPE_LLC_SNAP):
++                return KG_SCH_GEN_SNAP_NO_V;
++            case (HEADER_TYPE_PPPoE):
++                return KG_SCH_GEN_PPP_NO_V;
++            case (HEADER_TYPE_MPLS):
++                 if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
++                    return KG_SCH_GEN_MPLS1_NO_V;
++                if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
++                    return KG_SCH_GEN_MPLS_LAST_NO_V;
++                if ((hdrIndex == e_FM_PCD_HDR_INDEX_2) || (hdrIndex == e_FM_PCD_HDR_INDEX_3) )
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Indexed MPLS Extraction not supported"));
++                else
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS header index"));
++                return 0;
++            case (HEADER_TYPE_IPv4):
++            case (HEADER_TYPE_IPv6):
++                if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
++                    return KG_SCH_GEN_L3_NO_V;
++                if ((hdrIndex == e_FM_PCD_HDR_INDEX_2) || (hdrIndex == e_FM_PCD_HDR_INDEX_LAST))
++                    return KG_SCH_GEN_IP2_NO_V;
++                REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP header index"));
++            case (HEADER_TYPE_MINENCAP):
++                return KG_SCH_GEN_IP2_NO_V;
++            case (HEADER_TYPE_USER_DEFINED_L3):
++                return KG_SCH_GEN_L3_NO_V;
++            case (HEADER_TYPE_GRE):
++                return KG_SCH_GEN_GRE_NO_V;
++            case (HEADER_TYPE_TCP):
++            case (HEADER_TYPE_UDP):
++            case (HEADER_TYPE_IPSEC_AH):
++            case (HEADER_TYPE_IPSEC_ESP):
++            case (HEADER_TYPE_SCTP):
++            case (HEADER_TYPE_DCCP):
++                return KG_SCH_GEN_L4_NO_V;
++            case (HEADER_TYPE_USER_DEFINED_SHIM1):
++                return KG_SCH_GEN_SHIM1;
++            case (HEADER_TYPE_USER_DEFINED_SHIM2):
++                return KG_SCH_GEN_SHIM2;
++            default:
++                REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                return 0;
++        }
++}
++static t_GenericCodes GetGenFieldCode(e_NetHeaderType hdr, t_FmPcdFields field, bool ignoreProtocolValidation, e_FmPcdHdrIndex hdrIndex)
++{
++    if (!ignoreProtocolValidation)
++        switch (hdr)
++        {
++            case (HEADER_TYPE_NONE):
++                ASSERT_COND(FALSE);
++                break;
++            case (HEADER_TYPE_ETH):
++                switch (field.eth)
++                {
++                    case (NET_HEADER_FIELD_ETH_TYPE):
++                        return KG_SCH_GEN_ETH_TYPE;
++                    default:
++                        REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                        return 0;
++                }
++                break;
++            case (HEADER_TYPE_VLAN):
++                switch (field.vlan)
++                {
++                    case (NET_HEADER_FIELD_VLAN_TCI):
++                        if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
++                            return KG_SCH_GEN_VLAN1;
++                        if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
++                            return KG_SCH_GEN_VLAN2;
++                        REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal VLAN header index"));
++                        return 0;
++                }
++                break;
++            case (HEADER_TYPE_MPLS):
++            case (HEADER_TYPE_IPSEC_AH):
++            case (HEADER_TYPE_IPSEC_ESP):
++            case (HEADER_TYPE_LLC_SNAP):
++            case (HEADER_TYPE_PPPoE):
++            case (HEADER_TYPE_IPv4):
++            case (HEADER_TYPE_IPv6):
++            case (HEADER_TYPE_GRE):
++            case (HEADER_TYPE_MINENCAP):
++            case (HEADER_TYPE_USER_DEFINED_L3):
++            case (HEADER_TYPE_TCP):
++            case (HEADER_TYPE_UDP):
++            case (HEADER_TYPE_SCTP):
++            case (HEADER_TYPE_DCCP):
++            case (HEADER_TYPE_USER_DEFINED_L4):
++                REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                return 0;
++            default:
++                break;
++
++        }
++        else
++            switch (hdr)
++            {
++                case (HEADER_TYPE_NONE):
++                    ASSERT_COND(FALSE);
++                    break;
++                case (HEADER_TYPE_ETH):
++                    switch (field.eth)
++                    {
++                        case (NET_HEADER_FIELD_ETH_TYPE):
++                            return KG_SCH_GEN_ETH_TYPE_NO_V;
++                        default:
++                            REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                            return 0;
++                    }
++                    break;
++                case (HEADER_TYPE_VLAN):
++                    switch (field.vlan)
++                    {
++                        case (NET_HEADER_FIELD_VLAN_TCI) :
++                            if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
++                                return KG_SCH_GEN_VLAN1_NO_V;
++                            if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
++                                return KG_SCH_GEN_VLAN2_NO_V;
++                            REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal VLAN header index"));
++                            return 0;
++                    }
++                    break;
++                case (HEADER_TYPE_IPv4):
++                    switch (field.ipv4)
++                    {
++                        case (NET_HEADER_FIELD_IPv4_PROTO):
++                            return KG_SCH_GEN_IP_PID_NO_V;
++                        default:
++                            REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                            return 0;
++                    }
++                    break;
++                case (HEADER_TYPE_IPv6):
++                   switch (field.ipv6)
++                    {
++                        case (NET_HEADER_FIELD_IPv6_NEXT_HDR):
++                            return KG_SCH_GEN_IP_PID_NO_V;
++                        default:
++                            REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                            return 0;
++                    }
++                    break;
++                case (HEADER_TYPE_MPLS):
++                case (HEADER_TYPE_LLC_SNAP):
++                case (HEADER_TYPE_PPPoE):
++                case (HEADER_TYPE_GRE):
++                case (HEADER_TYPE_MINENCAP):
++                case (HEADER_TYPE_USER_DEFINED_L3):
++                case (HEADER_TYPE_TCP):
++                case (HEADER_TYPE_UDP):
++                case (HEADER_TYPE_IPSEC_AH):
++                case (HEADER_TYPE_IPSEC_ESP):
++                case (HEADER_TYPE_SCTP):
++                case (HEADER_TYPE_DCCP):
++                case (HEADER_TYPE_USER_DEFINED_L4):
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++                default:
++                    break;
++            }
++    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Header not supported"));
++    return 0;
++}
++
++static t_KnownFieldsMasks GetKnownProtMask(t_FmPcd *p_FmPcd, e_NetHeaderType hdr, e_FmPcdHdrIndex index, t_FmPcdFields field)
++{
++    UNUSED(p_FmPcd);
++
++    switch (hdr)
++    {
++        case (HEADER_TYPE_NONE):
++            ASSERT_COND(FALSE);
++            break;
++        case (HEADER_TYPE_ETH):
++            switch (field.eth)
++            {
++                case (NET_HEADER_FIELD_ETH_DA):
++                    return KG_SCH_KN_MACDST;
++                case (NET_HEADER_FIELD_ETH_SA):
++                    return KG_SCH_KN_MACSRC;
++                case (NET_HEADER_FIELD_ETH_TYPE):
++                    return KG_SCH_KN_ETYPE;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++            }
++        case (HEADER_TYPE_LLC_SNAP):
++            switch (field.llcSnap)
++            {
++                case (NET_HEADER_FIELD_LLC_SNAP_TYPE):
++                    return KG_SCH_KN_ETYPE;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++            }
++        case (HEADER_TYPE_VLAN):
++            switch (field.vlan)
++            {
++                case (NET_HEADER_FIELD_VLAN_TCI):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
++                        return KG_SCH_KN_TCI1;
++                    if (index == e_FM_PCD_HDR_INDEX_LAST)
++                        return KG_SCH_KN_TCI2;
++                    else
++                    {
++                        REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                        return 0;
++                    }
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++            }
++        case (HEADER_TYPE_MPLS):
++            switch (field.mpls)
++            {
++                case (NET_HEADER_FIELD_MPLS_LABEL_STACK):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
++                        return KG_SCH_KN_MPLS1;
++                    if (index == e_FM_PCD_HDR_INDEX_2)
++                        return KG_SCH_KN_MPLS2;
++                    if (index == e_FM_PCD_HDR_INDEX_LAST)
++                        return KG_SCH_KN_MPLS_LAST;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS index"));
++                    return 0;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++            }
++        case (HEADER_TYPE_IPv4):
++            switch (field.ipv4)
++            {
++                case (NET_HEADER_FIELD_IPv4_SRC_IP):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
++                        return KG_SCH_KN_IPSRC1;
++                    if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
++                        return KG_SCH_KN_IPSRC2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
++                    return 0;
++                case (NET_HEADER_FIELD_IPv4_DST_IP):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
++                        return KG_SCH_KN_IPDST1;
++                    if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
++                        return KG_SCH_KN_IPDST2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
++                    return 0;
++                case (NET_HEADER_FIELD_IPv4_PROTO):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
++                        return KG_SCH_KN_PTYPE1;
++                    if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
++                        return KG_SCH_KN_PTYPE2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
++                    return 0;
++                case (NET_HEADER_FIELD_IPv4_TOS):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
++                        return KG_SCH_KN_IPTOS_TC1;
++                    if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
++                        return KG_SCH_KN_IPTOS_TC2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
++                    return 0;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++            }
++        case (HEADER_TYPE_IPv6):
++             switch (field.ipv6)
++            {
++                case (NET_HEADER_FIELD_IPv6_SRC_IP):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
++                        return KG_SCH_KN_IPSRC1;
++                    if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
++                        return KG_SCH_KN_IPSRC2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
++                    return 0;
++                case (NET_HEADER_FIELD_IPv6_DST_IP):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
++                        return KG_SCH_KN_IPDST1;
++                    if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
++                        return KG_SCH_KN_IPDST2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
++                    return 0;
++                case (NET_HEADER_FIELD_IPv6_NEXT_HDR):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
++                        return KG_SCH_KN_PTYPE1;
++                    if (index == e_FM_PCD_HDR_INDEX_2)
++                        return KG_SCH_KN_PTYPE2;
++                    if (index == e_FM_PCD_HDR_INDEX_LAST)
++#ifdef FM_KG_NO_IPPID_SUPPORT
++                    if (p_FmPcd->fmRevInfo.majorRev < 6)
++                        return KG_SCH_KN_PTYPE2;
++#endif /* FM_KG_NO_IPPID_SUPPORT */
++                        return KG_SCH_KN_IPPID;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
++                    return 0;
++                case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL | NET_HEADER_FIELD_IPv6_TC):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
++                        return (KG_SCH_KN_IPV6FL1 | KG_SCH_KN_IPTOS_TC1);
++                    if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
++                        return (KG_SCH_KN_IPV6FL2 | KG_SCH_KN_IPTOS_TC2);
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
++                    return 0;
++                case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_TC):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
++                        return KG_SCH_KN_IPTOS_TC1;
++                    if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
++                        return KG_SCH_KN_IPTOS_TC2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
++                    return 0;
++                case (NET_HEADER_FIELD_IPv6_FL):
++                    if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
++                        return KG_SCH_KN_IPV6FL1;
++                    if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
++                        return KG_SCH_KN_IPV6FL2;
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
++                    return 0;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++            }
++        case (HEADER_TYPE_GRE):
++            switch (field.gre)
++            {
++                case (NET_HEADER_FIELD_GRE_TYPE):
++                    return KG_SCH_KN_GREPTYPE;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++            }
++        case (HEADER_TYPE_MINENCAP):
++            switch (field.minencap)
++            {
++                case (NET_HEADER_FIELD_MINENCAP_SRC_IP):
++                    return KG_SCH_KN_IPSRC2;
++                case (NET_HEADER_FIELD_MINENCAP_DST_IP):
++                    return KG_SCH_KN_IPDST2;
++                case (NET_HEADER_FIELD_MINENCAP_TYPE):
++                    return KG_SCH_KN_PTYPE2;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++            }
++        case (HEADER_TYPE_TCP):
++            switch (field.tcp)
++            {
++                case (NET_HEADER_FIELD_TCP_PORT_SRC):
++                    return KG_SCH_KN_L4PSRC;
++                case (NET_HEADER_FIELD_TCP_PORT_DST):
++                    return KG_SCH_KN_L4PDST;
++                case (NET_HEADER_FIELD_TCP_FLAGS):
++                    return KG_SCH_KN_TFLG;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++            }
++        case (HEADER_TYPE_UDP):
++            switch (field.udp)
++            {
++                case (NET_HEADER_FIELD_UDP_PORT_SRC):
++                    return KG_SCH_KN_L4PSRC;
++                case (NET_HEADER_FIELD_UDP_PORT_DST):
++                    return KG_SCH_KN_L4PDST;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++            }
++        case (HEADER_TYPE_IPSEC_AH):
++            switch (field.ipsecAh)
++            {
++                case (NET_HEADER_FIELD_IPSEC_AH_SPI):
++                    return KG_SCH_KN_IPSEC_SPI;
++                case (NET_HEADER_FIELD_IPSEC_AH_NH):
++                    return KG_SCH_KN_IPSEC_NH;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++            }
++        case (HEADER_TYPE_IPSEC_ESP):
++            switch (field.ipsecEsp)
++            {
++                case (NET_HEADER_FIELD_IPSEC_ESP_SPI):
++                    return KG_SCH_KN_IPSEC_SPI;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++            }
++        case (HEADER_TYPE_SCTP):
++            switch (field.sctp)
++            {
++                case (NET_HEADER_FIELD_SCTP_PORT_SRC):
++                    return KG_SCH_KN_L4PSRC;
++                case (NET_HEADER_FIELD_SCTP_PORT_DST):
++                    return KG_SCH_KN_L4PDST;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++            }
++        case (HEADER_TYPE_DCCP):
++            switch (field.dccp)
++            {
++                case (NET_HEADER_FIELD_DCCP_PORT_SRC):
++                    return KG_SCH_KN_L4PSRC;
++                case (NET_HEADER_FIELD_DCCP_PORT_DST):
++                    return KG_SCH_KN_L4PDST;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++            }
++        case (HEADER_TYPE_PPPoE):
++            switch (field.pppoe)
++            {
++                case (NET_HEADER_FIELD_PPPoE_PID):
++                    return KG_SCH_KN_PPPID;
++                case (NET_HEADER_FIELD_PPPoE_SID):
++                    return KG_SCH_KN_PPPSID;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++                    return 0;
++            }
++        default:
++            break;
++
++    }
++
++    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
++    return 0;
++}
++
++
++static uint8_t GetKnownFieldId(uint32_t bitMask)
++{
++    uint8_t cnt = 0;
++
++    while (bitMask)
++        if (bitMask & 0x80000000)
++            break;
++        else
++        {
++            cnt++;
++            bitMask <<= 1;
++        }
++    return cnt;
++
++}
++
++static uint8_t GetExtractedOrMask(uint8_t bitOffset, bool fqid)
++{
++    uint8_t i, mask, numOfOnesToClear, walking1Mask = 1;
++
++    /* bitOffset 1-7 --> mask 0x1-0x7F */
++    if (bitOffset<8)
++    {
++        mask = 0;
++        for (i = 0 ; i < bitOffset ; i++, walking1Mask <<= 1)
++            mask |= walking1Mask;
++    }
++    else
++    {
++       mask = 0xFF;
++       numOfOnesToClear = 0;
++       if (fqid && bitOffset>24)
++           /* bitOffset 25-31 --> mask 0xFE-0x80 */
++           numOfOnesToClear = (uint8_t)(bitOffset-24);
++       else
++          /* bitOffset 9-15 --> mask 0xFE-0x80 */
++          if (!fqid && bitOffset>8)
++               numOfOnesToClear = (uint8_t)(bitOffset-8);
++       for (i = 0 ; i < numOfOnesToClear ; i++, walking1Mask <<= 1)
++           mask &= ~walking1Mask;
++       /* bitOffset 8-24 for FQID, 8 for PP --> no mask (0xFF)*/
++    }
++    return mask;
++}
++
++static void IncSchemeOwners(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort)
++{
++    t_FmPcdKg           *p_FmPcdKg;
++    t_FmPcdKgScheme     *p_Scheme;
++    uint32_t            intFlags;
++    uint8_t             relativeSchemeId;
++    int                 i;
++
++    p_FmPcdKg = p_FmPcd->p_FmPcdKg;
++
++    /* for each scheme - update owners counters */
++    for (i = 0; i < p_BindPort->numOfSchemes; i++)
++    {
++        relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, p_BindPort->schemesIds[i]);
++        ASSERT_COND(relativeSchemeId < FM_PCD_KG_NUM_OF_SCHEMES);
++
++        p_Scheme = &p_FmPcdKg->schemes[relativeSchemeId];
++
++        /* increment owners number */
++        intFlags = KgSchemeLock(p_Scheme);
++        p_Scheme->owners++;
++        KgSchemeUnlock(p_Scheme, intFlags);
++    }
++}
++
++static void DecSchemeOwners(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort)
++{
++    t_FmPcdKg           *p_FmPcdKg;
++    t_FmPcdKgScheme     *p_Scheme;
++    uint32_t            intFlags;
++    uint8_t             relativeSchemeId;
++    int                 i;
++
++    p_FmPcdKg = p_FmPcd->p_FmPcdKg;
++
++    /* for each scheme - update owners counters */
++    for (i = 0; i < p_BindPort->numOfSchemes; i++)
++    {
++        relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, p_BindPort->schemesIds[i]);
++        ASSERT_COND(relativeSchemeId < FM_PCD_KG_NUM_OF_SCHEMES);
++
++        p_Scheme = &p_FmPcdKg->schemes[relativeSchemeId];
++
++        /* increment owners number */
++        ASSERT_COND(p_Scheme->owners);
++        intFlags = KgSchemeLock(p_Scheme);
++        p_Scheme->owners--;
++        KgSchemeUnlock(p_Scheme, intFlags);
++    }
++}
++
++static void UpdateRequiredActionFlag(t_FmPcdKgScheme *p_Scheme, bool set)
++{
++    /* this routine is locked by the calling routine */
++    ASSERT_COND(p_Scheme);
++    ASSERT_COND(p_Scheme->valid);
++
++    if (set)
++        p_Scheme->requiredActionFlag = TRUE;
++    else
++    {
++        p_Scheme->requiredAction = 0;
++        p_Scheme->requiredActionFlag = FALSE;
++    }
++}
++
++static t_Error KgWriteSp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint32_t spReg, bool add)
++{
++    struct fman_kg_regs *p_KgRegs;
++
++    uint32_t                tmpKgarReg = 0, intFlags;
++    t_Error                 err = E_OK;
++
++    /* The calling routine had locked the port, so for each port only one core can access
++     * (so we don't need a lock here) */
++
++    if (p_FmPcd->h_Hc)
++        return FmHcKgWriteSp(p_FmPcd->h_Hc, hardwarePortId, spReg, add);
++
++    p_KgRegs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
++
++    tmpKgarReg = FmPcdKgBuildReadPortSchemeBindActionReg(hardwarePortId);
++    /* lock a common KG reg */
++    intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
++    err = WriteKgarWait(p_FmPcd, tmpKgarReg);
++    if (err)
++    {
++        KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
++        RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++
++    fman_kg_write_sp(p_KgRegs, spReg, add);
++
++    tmpKgarReg = FmPcdKgBuildWritePortSchemeBindActionReg(hardwarePortId);
++
++    err = WriteKgarWait(p_FmPcd, tmpKgarReg);
++    KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
++    return err;
++}
++
++static t_Error KgWriteCpp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint32_t cppReg)
++{
++    struct fman_kg_regs    *p_KgRegs;
++    uint32_t                tmpKgarReg, intFlags;
++    t_Error                 err;
++
++    p_KgRegs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
++
++    if (p_FmPcd->h_Hc)
++    {
++        err = FmHcKgWriteCpp(p_FmPcd->h_Hc, hardwarePortId, cppReg);
++        return err;
++    }
++
++    intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
++    fman_kg_write_cpp(p_KgRegs, cppReg);
++    tmpKgarReg = FmPcdKgBuildWritePortClsPlanBindActionReg(hardwarePortId);
++    err = WriteKgarWait(p_FmPcd, tmpKgarReg);
++    KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
++
++    return err;
++}
++
++static uint32_t BuildCppReg(t_FmPcd *p_FmPcd, uint8_t clsPlanGrpId)
++{
++    uint32_t    tmpKgpeCpp;
++
++    tmpKgpeCpp = (uint32_t)(p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].baseEntry / 8);
++    tmpKgpeCpp |= (uint32_t)(((p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].sizeOfGrp / 8) - 1) << FM_KG_PE_CPP_MASK_SHIFT);
++
++    return tmpKgpeCpp;
++}
++
++static t_Error BindPortToClsPlanGrp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId)
++{
++    uint32_t                tmpKgpeCpp = 0;
++
++    tmpKgpeCpp = BuildCppReg(p_FmPcd, clsPlanGrpId);
++    return KgWriteCpp(p_FmPcd, hardwarePortId, tmpKgpeCpp);
++}
++
++static void UnbindPortToClsPlanGrp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId)
++{
++    KgWriteCpp(p_FmPcd, hardwarePortId, 0);
++}
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++static uint32_t __attribute__((unused)) ReadClsPlanBlockActionReg(uint8_t grpId)
++{
++    return (uint32_t)(FM_KG_KGAR_GO |
++                      FM_KG_KGAR_READ |
++                      FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY |
++                      DUMMY_PORT_ID |
++                      ((uint32_t)grpId << FM_PCD_KG_KGAR_NUM_SHIFT) |
++                      FM_PCD_KG_KGAR_WSEL_MASK);
++
++    /* if we ever want to write 1 by 1, use:
++       sel = (uint8_t)(0x01 << (7- (entryId % CLS_PLAN_NUM_PER_GRP)));
++     */
++}
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++static void PcdKgErrorException(t_Handle h_FmPcd)
++{
++    t_FmPcd                 *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    uint32_t                event,schemeIndexes = 0, index = 0;
++    struct fman_kg_regs    *p_KgRegs;
++
++    ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
++    p_KgRegs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
++    fman_kg_get_event(p_KgRegs, &event, &schemeIndexes);
++
++    if (event & FM_EX_KG_DOUBLE_ECC)
++        p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC);
++    if (event & FM_EX_KG_KEYSIZE_OVERFLOW)
++    {
++        if (schemeIndexes)
++        {
++            while (schemeIndexes)
++            {
++                if (schemeIndexes & 0x1)
++                    p_FmPcd->f_FmPcdIndexedException(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW, (uint16_t)(31 - index));
++                schemeIndexes >>= 1;
++                index+=1;
++            }
++        }
++        else /* this should happen only when interrupt is forced. */
++            p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW);
++    }
++}
++
++static t_Error KgInitGuest(t_FmPcd *p_FmPcd)
++{
++    t_Error                     err = E_OK;
++    t_FmPcdIpcKgSchemesParams   kgAlloc;
++    uint32_t                    replyLength;
++    t_FmPcdIpcReply             reply;
++    t_FmPcdIpcMsg               msg;
++
++    ASSERT_COND(p_FmPcd->guestId != NCSW_MASTER_ID);
++
++    /* in GUEST_PARTITION, we use the IPC  */
++    memset(&reply, 0, sizeof(reply));
++    memset(&msg, 0, sizeof(msg));
++    memset(&kgAlloc, 0, sizeof(t_FmPcdIpcKgSchemesParams));
++    kgAlloc.numOfSchemes = p_FmPcd->p_FmPcdKg->numOfSchemes;
++    kgAlloc.guestId = p_FmPcd->guestId;
++    msg.msgId = FM_PCD_ALLOC_KG_SCHEMES;
++    memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc));
++    replyLength = sizeof(uint32_t) + p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t);
++    if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
++                                 (uint8_t*)&msg,
++                                 sizeof(msg.msgId) + sizeof(kgAlloc),
++                                 (uint8_t*)&reply,
++                                 &replyLength,
++                                 NULL,
++                                 NULL)) != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    if (replyLength != (sizeof(uint32_t) + p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t)))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++    memcpy(p_FmPcd->p_FmPcdKg->schemesIds, (uint8_t*)(reply.replyBody),p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t));
++
++    return (t_Error)reply.error;
++}
++
++static t_Error KgInitMaster(t_FmPcd *p_FmPcd)
++{
++    t_Error                     err = E_OK;
++    struct fman_kg_regs         *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
++
++    ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID);
++
++    if (p_FmPcd->exceptions & FM_EX_KG_DOUBLE_ECC)
++        FmEnableRamsEcc(p_FmPcd->h_Fm);
++
++    fman_kg_init(p_Regs, p_FmPcd->exceptions, GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd));
++
++    /* register even if no interrupts enabled, to allow future enablement */
++    FmRegisterIntr(p_FmPcd->h_Fm,
++                   e_FM_MOD_KG,
++                   0,
++                   e_FM_INTR_TYPE_ERR,
++                   PcdKgErrorException,
++                   p_FmPcd);
++
++    fman_kg_enable_scheme_interrupts(p_Regs);
++
++    if (p_FmPcd->p_FmPcdKg->numOfSchemes)
++    {
++        err = FmPcdKgAllocSchemes(p_FmPcd,
++                                  p_FmPcd->p_FmPcdKg->numOfSchemes,
++                                  p_FmPcd->guestId,
++                                  p_FmPcd->p_FmPcdKg->schemesIds);
++        if (err)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++
++    return E_OK;
++}
++
++static void  ValidateSchemeSw(t_FmPcdKgScheme *p_Scheme)
++{
++    ASSERT_COND(!p_Scheme->valid);
++    if (p_Scheme->netEnvId != ILLEGAL_NETENV)
++        FmPcdIncNetEnvOwners(p_Scheme->h_FmPcd, p_Scheme->netEnvId);
++    p_Scheme->valid = TRUE;
++}
++
++static t_Error InvalidateSchemeSw(t_FmPcdKgScheme *p_Scheme)
++{
++    if (p_Scheme->owners)
++       RETURN_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete a scheme that has ports bound to"));
++
++    if (p_Scheme->netEnvId != ILLEGAL_NETENV)
++        FmPcdDecNetEnvOwners(p_Scheme->h_FmPcd, p_Scheme->netEnvId);
++    p_Scheme->valid = FALSE;
++
++    return E_OK;
++}
++
++static t_Error BuildSchemeRegs(t_FmPcdKgScheme            *p_Scheme,
++                               t_FmPcdKgSchemeParams      *p_SchemeParams,
++                               struct fman_kg_scheme_regs *p_SchemeRegs)
++{
++    t_FmPcd                             *p_FmPcd = (t_FmPcd *)(p_Scheme->h_FmPcd);
++    uint32_t                            grpBits = 0;
++    uint8_t                             grpBase;
++    bool                                direct=TRUE, absolute=FALSE;
++    uint16_t                            profileId=0, numOfProfiles=0, relativeProfileId;
++    t_Error                             err = E_OK;
++    int                                 i = 0;
++    t_NetEnvParams                      netEnvParams;
++    uint32_t                            tmpReg, fqbTmp = 0, ppcTmp = 0, selectTmp, maskTmp, knownTmp, genTmp;
++    t_FmPcdKgKeyExtractAndHashParams    *p_KeyAndHash = NULL;
++    uint8_t                             j, curr, idx;
++    uint8_t                             id, shift=0, code=0, offset=0, size=0;
++    t_FmPcdExtractEntry                 *p_Extract = NULL;
++    t_FmPcdKgExtractedOrParams          *p_ExtractOr;
++    bool                                generic = FALSE;
++    t_KnownFieldsMasks                  bitMask;
++    e_FmPcdKgExtractDfltSelect          swDefault = (e_FmPcdKgExtractDfltSelect)0;
++    t_FmPcdKgSchemesExtracts            *p_LocalExtractsArray;
++    uint8_t                             numOfSwDefaults = 0;
++    t_FmPcdKgExtractDflt                swDefaults[NUM_OF_SW_DEFAULTS];
++    uint8_t                             currGenId = 0;
++
++    memset(swDefaults, 0, NUM_OF_SW_DEFAULTS*sizeof(t_FmPcdKgExtractDflt));
++    memset(p_SchemeRegs, 0, sizeof(struct fman_kg_scheme_regs));
++
++    if (p_SchemeParams->netEnvParams.numOfDistinctionUnits > FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("numOfDistinctionUnits should not exceed %d", FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS));
++
++    /* by netEnv parameters, get match vector */
++    if (!p_SchemeParams->alwaysDirect)
++    {
++        p_Scheme->netEnvId = FmPcdGetNetEnvId(p_SchemeParams->netEnvParams.h_NetEnv);
++        netEnvParams.netEnvId = p_Scheme->netEnvId;
++        netEnvParams.numOfDistinctionUnits = p_SchemeParams->netEnvParams.numOfDistinctionUnits;
++        memcpy(netEnvParams.unitIds, p_SchemeParams->netEnvParams.unitIds, (sizeof(uint8_t))*p_SchemeParams->netEnvParams.numOfDistinctionUnits);
++        err = PcdGetUnitsVector(p_FmPcd, &netEnvParams);
++        if (err)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++        p_Scheme->matchVector = netEnvParams.vector;
++    }
++    else
++    {
++        p_Scheme->matchVector = SCHEME_ALWAYS_DIRECT;
++        p_Scheme->netEnvId = ILLEGAL_NETENV;
++    }
++
++    if (p_SchemeParams->nextEngine == e_FM_PCD_INVALID)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next Engine of the scheme is not Valid"));
++
++    if (p_SchemeParams->bypassFqidGeneration)
++    {
++#ifdef FM_KG_NO_BYPASS_FQID_GEN
++        if ((p_FmPcd->fmRevInfo.majorRev != 4) && (p_FmPcd->fmRevInfo.majorRev < 6))
++            RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("bypassFqidGeneration."));
++#endif /* FM_KG_NO_BYPASS_FQID_GEN */
++        if (p_SchemeParams->baseFqid)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("baseFqid set for a scheme that does not generate an FQID"));
++    }
++    else
++        if (!p_SchemeParams->baseFqid)
++            DBG(WARNING, ("baseFqid is 0."));
++
++    if (p_SchemeParams->nextEngine == e_FM_PCD_PLCR)
++    {
++        direct = p_SchemeParams->kgNextEngineParams.plcrProfile.direct;
++        p_Scheme->directPlcr = direct;
++        absolute = (bool)(p_SchemeParams->kgNextEngineParams.plcrProfile.sharedProfile ? TRUE : FALSE);
++        if (!direct && absolute)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Indirect policing is not available when profile is shared."));
++
++        if (direct)
++        {
++            profileId = p_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.directRelativeProfileId;
++            numOfProfiles = 1;
++        }
++        else
++        {
++            profileId = p_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase;
++            shift = p_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.fqidOffsetShift;
++            numOfProfiles = p_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.numOfProfiles;
++        }
++    }
++
++    if (p_SchemeParams->nextEngine == e_FM_PCD_CC)
++    {
++#ifdef FM_KG_NO_BYPASS_PLCR_PROFILE_GEN
++        if ((p_SchemeParams->kgNextEngineParams.cc.plcrNext) && (p_SchemeParams->kgNextEngineParams.cc.bypassPlcrProfileGeneration))
++        {
++            if ((p_FmPcd->fmRevInfo.majorRev != 4) && (p_FmPcd->fmRevInfo.majorRev < 6))
++                RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("bypassPlcrProfileGeneration."));
++        }
++#endif /* FM_KG_NO_BYPASS_PLCR_PROFILE_GEN */
++
++        err = FmPcdCcGetGrpParams(p_SchemeParams->kgNextEngineParams.cc.h_CcTree,
++                             p_SchemeParams->kgNextEngineParams.cc.grpId,
++                             &grpBits,
++                             &grpBase);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        p_Scheme->ccUnits = grpBits;
++
++        if ((p_SchemeParams->kgNextEngineParams.cc.plcrNext) &&
++           (!p_SchemeParams->kgNextEngineParams.cc.bypassPlcrProfileGeneration))
++        {
++                if (p_SchemeParams->kgNextEngineParams.cc.plcrProfile.sharedProfile)
++                    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Shared profile may not be used after Coarse classification."));
++                absolute = FALSE;
++                direct = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.direct;
++                if (direct)
++                {
++                    profileId = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.directRelativeProfileId;
++                    numOfProfiles = 1;
++                }
++                else
++                {
++                    profileId = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase;
++                    shift = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.fqidOffsetShift;
++                    numOfProfiles = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.numOfProfiles;
++                }
++        }
++    }
++
++    /* if policer is used directly after KG, or after CC */
++    if ((p_SchemeParams->nextEngine == e_FM_PCD_PLCR)  ||
++       ((p_SchemeParams->nextEngine == e_FM_PCD_CC) &&
++        (p_SchemeParams->kgNextEngineParams.cc.plcrNext) &&
++        (!p_SchemeParams->kgNextEngineParams.cc.bypassPlcrProfileGeneration)))
++    {
++        /* if private policer profile, it may be uninitialized yet, therefore no checks are done at this stage */
++        if (absolute)
++        {
++            /* for absolute direct policy only, */
++            relativeProfileId = profileId;
++            err = FmPcdPlcrGetAbsoluteIdByProfileParams((t_Handle)p_FmPcd,e_FM_PCD_PLCR_SHARED,NULL, relativeProfileId, &profileId);
++            if (err)
++                RETURN_ERROR(MAJOR, err, ("Shared profile not valid offset"));
++            if (!FmPcdPlcrIsProfileValid(p_FmPcd, profileId))
++                RETURN_ERROR(MINOR, E_INVALID_STATE, ("Shared profile not valid."));
++            p_Scheme->relativeProfileId = profileId;
++        }
++        else
++        {
++            /* save relative profile id's for later check */
++            p_Scheme->nextRelativePlcrProfile = TRUE;
++            p_Scheme->relativeProfileId = profileId;
++            p_Scheme->numOfProfiles = numOfProfiles;
++        }
++    }
++    else
++    {
++        /* if policer is NOT going to be used after KG at all than if bypassFqidGeneration
++        is set, we do not need numOfUsedExtractedOrs and hashDistributionNumOfFqids */
++        if (p_SchemeParams->bypassFqidGeneration && p_SchemeParams->numOfUsedExtractedOrs)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                    ("numOfUsedExtractedOrs is set in a scheme that does not generate FQID or policer profile ID"));
++        if (p_SchemeParams->bypassFqidGeneration &&
++                p_SchemeParams->useHash &&
++                p_SchemeParams->keyExtractAndHashParams.hashDistributionNumOfFqids)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                    ("hashDistributionNumOfFqids is set in a scheme that does not generate FQID or policer profile ID"));
++    }
++
++    /* configure all 21 scheme registers */
++    tmpReg =  KG_SCH_MODE_EN;
++    switch (p_SchemeParams->nextEngine)
++    {
++        case (e_FM_PCD_PLCR):
++            /* add to mode register - NIA */
++            tmpReg |= KG_SCH_MODE_NIA_PLCR;
++            tmpReg |= NIA_ENG_PLCR;
++            tmpReg |= (uint32_t)(p_SchemeParams->kgNextEngineParams.plcrProfile.sharedProfile ? NIA_PLCR_ABSOLUTE:0);
++            /* initialize policer profile command - */
++            /*  configure kgse_ppc  */
++            if (direct)
++            /* use profileId as base, other fields are 0 */
++                p_SchemeRegs->kgse_ppc = (uint32_t)profileId;
++            else
++            {
++                if (shift > MAX_PP_SHIFT)
++                    RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_PP_SHIFT));
++
++                if (!numOfProfiles || !POWER_OF_2(numOfProfiles))
++                    RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfProfiles must not be 0 and must be a power of 2"));
++
++                ppcTmp = ((uint32_t)shift << KG_SCH_PP_SHIFT_HIGH_SHIFT) & KG_SCH_PP_SHIFT_HIGH;
++                ppcTmp |= ((uint32_t)shift << KG_SCH_PP_SHIFT_LOW_SHIFT) & KG_SCH_PP_SHIFT_LOW;
++                ppcTmp |= ((uint32_t)(numOfProfiles-1) << KG_SCH_PP_MASK_SHIFT);
++                ppcTmp |= (uint32_t)profileId;
++
++                p_SchemeRegs->kgse_ppc = ppcTmp;
++            }
++            break;
++        case (e_FM_PCD_CC):
++            /* mode reg - define NIA */
++            tmpReg |= (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC);
++
++            p_SchemeRegs->kgse_ccbs = grpBits;
++            tmpReg |= (uint32_t)(grpBase << KG_SCH_MODE_CCOBASE_SHIFT);
++
++            if (p_SchemeParams->kgNextEngineParams.cc.plcrNext)
++            {
++                if (!p_SchemeParams->kgNextEngineParams.cc.bypassPlcrProfileGeneration)
++                {
++                    /* find out if absolute or relative */
++                    if (absolute)
++                         RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("It is illegal to request a shared profile in a scheme that is in a KG->CC->PLCR flow"));
++                    if (direct)
++                    {
++                        /* mask = 0, base = directProfileId */
++                        p_SchemeRegs->kgse_ppc = (uint32_t)profileId;
++                    }
++                    else
++                    {
++                        if (shift > MAX_PP_SHIFT)
++                            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_PP_SHIFT));
++                        if (!numOfProfiles || !POWER_OF_2(numOfProfiles))
++                            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfProfiles must not be 0 and must be a power of 2"));
++
++                        ppcTmp = ((uint32_t)shift << KG_SCH_PP_SHIFT_HIGH_SHIFT) & KG_SCH_PP_SHIFT_HIGH;
++                        ppcTmp |= ((uint32_t)shift << KG_SCH_PP_SHIFT_LOW_SHIFT) & KG_SCH_PP_SHIFT_LOW;
++                        ppcTmp |= ((uint32_t)(numOfProfiles-1) << KG_SCH_PP_MASK_SHIFT);
++                        ppcTmp |= (uint32_t)profileId;
++
++                        p_SchemeRegs->kgse_ppc = ppcTmp;
++                    }
++                }
++            }
++            break;
++        case (e_FM_PCD_DONE):
++            if (p_SchemeParams->kgNextEngineParams.doneAction == e_FM_PCD_DROP_FRAME)
++                tmpReg |= GET_NIA_BMI_AC_DISCARD_FRAME(p_FmPcd);
++            else
++                tmpReg |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd);
++            break;
++        default:
++             RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Next engine not supported"));
++    }
++    p_SchemeRegs->kgse_mode = tmpReg;
++
++    p_SchemeRegs->kgse_mv = p_Scheme->matchVector;
++
++#if (DPAA_VERSION >= 11)
++    if (p_SchemeParams->overrideStorageProfile)
++    {
++        p_SchemeRegs->kgse_om |= KG_SCH_OM_VSPE;
++
++        if (p_SchemeParams->storageProfile.direct)
++        {
++            profileId = p_SchemeParams->storageProfile.profileSelect.directRelativeProfileId;
++            shift = 0;
++            numOfProfiles = 1;
++        }
++        else
++        {
++            profileId = p_SchemeParams->storageProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase;
++            shift = p_SchemeParams->storageProfile.profileSelect.indirectProfile.fqidOffsetShift;
++            numOfProfiles = p_SchemeParams->storageProfile.profileSelect.indirectProfile.numOfProfiles;
++        }
++        if (shift > MAX_SP_SHIFT)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_SP_SHIFT));
++
++        if (!numOfProfiles || !POWER_OF_2(numOfProfiles))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfProfiles must not be 0 and must be a power of 2"));
++
++        tmpReg = (uint32_t)shift << KG_SCH_VSP_SHIFT;
++        tmpReg |= ((uint32_t)(numOfProfiles-1) << KG_SCH_VSP_MASK_SHIFT);
++        tmpReg |= (uint32_t)profileId;
++
++
++        p_SchemeRegs->kgse_vsp = tmpReg;
++
++        p_Scheme->vspe = TRUE;
++
++    }
++    else
++        p_SchemeRegs->kgse_vsp = KG_SCH_VSP_NO_KSP_EN;
++#endif /* (DPAA_VERSION >= 11) */
++
++    if (p_SchemeParams->useHash)
++    {
++        p_KeyAndHash = &p_SchemeParams->keyExtractAndHashParams;
++
++        if (p_KeyAndHash->numOfUsedExtracts >= FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY)
++             RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfUsedExtracts out of range"));
++
++        /*  configure kgse_dv0  */
++        p_SchemeRegs->kgse_dv0 = p_KeyAndHash->privateDflt0;
++
++        /*  configure kgse_dv1  */
++        p_SchemeRegs->kgse_dv1 = p_KeyAndHash->privateDflt1;
++
++        if (!p_SchemeParams->bypassFqidGeneration)
++        {
++            if (!p_KeyAndHash->hashDistributionNumOfFqids || !POWER_OF_2(p_KeyAndHash->hashDistributionNumOfFqids))
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashDistributionNumOfFqids must not be 0 and must be a power of 2"));
++            if ((p_KeyAndHash->hashDistributionNumOfFqids-1) & p_SchemeParams->baseFqid)
++                DBG(WARNING, ("baseFqid unaligned. Distribution may result in less than hashDistributionNumOfFqids queues."));
++        }
++
++        /*  configure kgse_ekdv  */
++        tmpReg = 0;
++        for ( i=0 ;i<p_KeyAndHash->numOfUsedDflts ; i++)
++        {
++            switch (p_KeyAndHash->dflts[i].type)
++            {
++                case (e_FM_PCD_KG_MAC_ADDR):
++                    tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_MAC_ADDR_SHIFT);
++                    break;
++                case (e_FM_PCD_KG_TCI):
++                    tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_TCI_SHIFT);
++                    break;
++                case (e_FM_PCD_KG_ENET_TYPE):
++                    tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_ENET_TYPE_SHIFT);
++                    break;
++                case (e_FM_PCD_KG_PPP_SESSION_ID):
++                    tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PPP_SESSION_ID_SHIFT);
++                    break;
++                case (e_FM_PCD_KG_PPP_PROTOCOL_ID):
++                    tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PPP_PROTOCOL_ID_SHIFT);
++                    break;
++                case (e_FM_PCD_KG_MPLS_LABEL):
++                    tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_MPLS_LABEL_SHIFT);
++                    break;
++                case (e_FM_PCD_KG_IP_ADDR):
++                    tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IP_ADDR_SHIFT);
++                    break;
++                case (e_FM_PCD_KG_PROTOCOL_TYPE):
++                    tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PROTOCOL_TYPE_SHIFT);
++                    break;
++                case (e_FM_PCD_KG_IP_TOS_TC):
++                    tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IP_TOS_TC_SHIFT);
++                    break;
++                case (e_FM_PCD_KG_IPV6_FLOW_LABEL):
++                    tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_L4_PORT_SHIFT);
++                    break;
++                case (e_FM_PCD_KG_IPSEC_SPI):
++                    tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IPSEC_SPI_SHIFT);
++                    break;
++                case (e_FM_PCD_KG_L4_PORT):
++                    tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_L4_PORT_SHIFT);
++                    break;
++                case (e_FM_PCD_KG_TCP_FLAG):
++                    tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_TCP_FLAG_SHIFT);
++                    break;
++                case (e_FM_PCD_KG_GENERIC_FROM_DATA):
++                    swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_FROM_DATA;
++                    swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect;
++                    numOfSwDefaults ++;
++                    break;
++                case (e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V):
++                    swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V;
++                    swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect;
++                    numOfSwDefaults ++;
++                    break;
++                case (e_FM_PCD_KG_GENERIC_NOT_FROM_DATA):
++                    swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_NOT_FROM_DATA;
++                    swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect;
++                    numOfSwDefaults ++;
++                   break;
++                default:
++                    RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++            }
++        }
++        p_SchemeRegs->kgse_ekdv = tmpReg;
++
++        p_LocalExtractsArray = (t_FmPcdKgSchemesExtracts *)XX_Malloc(sizeof(t_FmPcdKgSchemesExtracts));
++        if (!p_LocalExtractsArray)
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("No memory"));
++
++        /*  configure kgse_ekfc and  kgse_gec */
++        knownTmp = 0;
++        for ( i=0 ;i<p_KeyAndHash->numOfUsedExtracts ; i++)
++        {
++            p_Extract = &p_KeyAndHash->extractArray[i];
++            switch (p_Extract->type)
++            {
++                case (e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO):
++                    knownTmp |= KG_SCH_KN_PORT_ID;
++                    /* save in driver structure */
++                    p_LocalExtractsArray->extractsArray[i].id = GetKnownFieldId(KG_SCH_KN_PORT_ID);
++                    p_LocalExtractsArray->extractsArray[i].known = TRUE;
++                    break;
++                case (e_FM_PCD_EXTRACT_BY_HDR):
++                    switch (p_Extract->extractByHdr.hdr)
++                    {
++#if (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++                        case (HEADER_TYPE_UDP_LITE):
++                            p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP;
++                            break;
++#endif /* (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
++                        case (HEADER_TYPE_UDP_ENCAP_ESP):
++                            switch (p_Extract->extractByHdr.type)
++                            {
++                                case (e_FM_PCD_EXTRACT_FROM_HDR):
++                                    /* case where extraction from ESP only */
++                                    if (p_Extract->extractByHdr.extractByHdrType.fromHdr.offset >= UDP_HEADER_SIZE)
++                                    {
++                                        p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP);
++                                        p_Extract->extractByHdr.extractByHdrType.fromHdr.offset -= UDP_HEADER_SIZE;
++                                        p_Extract->extractByHdr.ignoreProtocolValidation = TRUE;
++                                    }
++                                    else
++                                    {
++                                        p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP;
++                                        p_Extract->extractByHdr.ignoreProtocolValidation = FALSE;
++                                    }
++                                    break;
++                                case (e_FM_PCD_EXTRACT_FROM_FIELD):
++                                    switch (p_Extract->extractByHdr.extractByHdrType.fromField.field.udpEncapEsp)
++                                    {
++                                        case (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC):
++                                        case (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST):
++                                        case (NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN):
++                                        case (NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM):
++                                            p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP;
++                                            break;
++                                        case (NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI):
++                                            p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR;
++                                            p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP);
++                                            /*p_Extract->extractByHdr.extractByHdrType.fromField.offset += ESP_SPI_OFFSET;*/
++                                            p_Extract->extractByHdr.ignoreProtocolValidation = TRUE;
++                                            break;
++                                        case (NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM):
++                                            p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR;
++                                            p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP);
++                                            p_Extract->extractByHdr.extractByHdrType.fromField.offset += ESP_SEQ_NUM_OFFSET;
++                                            p_Extract->extractByHdr.ignoreProtocolValidation = TRUE;
++                                            break;
++                                    }
++                                    break;
++                                case (e_FM_PCD_EXTRACT_FULL_FIELD):
++                                    switch (p_Extract->extractByHdr.extractByHdrType.fullField.udpEncapEsp)
++                                    {
++                                        case (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC):
++                                        case (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST):
++                                        case (NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN):
++                                        case (NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM):
++                                            p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP;
++                                            break;
++                                        case (NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI):
++                                            p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR;
++                                            p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP);
++                                            p_Extract->extractByHdr.extractByHdrType.fromHdr.size = ESP_SPI_SIZE;
++                                            p_Extract->extractByHdr.extractByHdrType.fromHdr.offset = ESP_SPI_OFFSET;
++                                            p_Extract->extractByHdr.ignoreProtocolValidation = TRUE;
++                                            break;
++                                        case (NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM):
++                                            p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR;
++                                            p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP);
++                                            p_Extract->extractByHdr.extractByHdrType.fromHdr.size = ESP_SEQ_NUM_SIZE;
++                                            p_Extract->extractByHdr.extractByHdrType.fromHdr.offset = ESP_SEQ_NUM_OFFSET;
++                                            p_Extract->extractByHdr.ignoreProtocolValidation = TRUE;
++                                            break;
++                                    }
++                                    break;
++                            }
++                            break;
++                        default:
++                            break;
++                    }
++                    switch (p_Extract->extractByHdr.type)
++                    {
++                        case (e_FM_PCD_EXTRACT_FROM_HDR):
++                            generic = TRUE;
++                            /* get the header code for the generic extract */
++                            code = GetGenHdrCode(p_Extract->extractByHdr.hdr, p_Extract->extractByHdr.hdrIndex, p_Extract->extractByHdr.ignoreProtocolValidation);
++                            /* set generic register fields */
++                            offset = p_Extract->extractByHdr.extractByHdrType.fromHdr.offset;
++                            size = p_Extract->extractByHdr.extractByHdrType.fromHdr.size;
++                            break;
++                        case (e_FM_PCD_EXTRACT_FROM_FIELD):
++                            generic = TRUE;
++                            /* get the field code for the generic extract */
++                            code = GetGenFieldCode(p_Extract->extractByHdr.hdr,
++                                        p_Extract->extractByHdr.extractByHdrType.fromField.field, p_Extract->extractByHdr.ignoreProtocolValidation,p_Extract->extractByHdr.hdrIndex);
++                            offset = p_Extract->extractByHdr.extractByHdrType.fromField.offset;
++                            size = p_Extract->extractByHdr.extractByHdrType.fromField.size;
++                            break;
++                        case (e_FM_PCD_EXTRACT_FULL_FIELD):
++                            if (!p_Extract->extractByHdr.ignoreProtocolValidation)
++                            {
++                                /* if we have a known field for it - use it, otherwise use generic */
++                                bitMask = GetKnownProtMask(p_FmPcd, p_Extract->extractByHdr.hdr, p_Extract->extractByHdr.hdrIndex,
++                                            p_Extract->extractByHdr.extractByHdrType.fullField);
++                                if (bitMask)
++                                {
++                                    knownTmp |= bitMask;
++                                    /* save in driver structure */
++                                    p_LocalExtractsArray->extractsArray[i].id = GetKnownFieldId(bitMask);
++                                    p_LocalExtractsArray->extractsArray[i].known = TRUE;
++                                }
++                                else
++                                    generic = TRUE;
++                            }
++                            else
++                                generic = TRUE;
++                            if (generic)
++                            {
++                                /* tmp - till we cover more headers under generic */
++                                XX_Free(p_LocalExtractsArray);
++                                RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Full header selection not supported"));
++                            }
++                            break;
++                        default:
++                            XX_Free(p_LocalExtractsArray);
++                            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++                    }
++                    break;
++                case (e_FM_PCD_EXTRACT_NON_HDR):
++                    /* use generic */
++                    generic = TRUE;
++                    offset = 0;
++                    /* get the field code for the generic extract */
++                    code = GetGenCode(p_Extract->extractNonHdr.src, &offset);
++                    offset += p_Extract->extractNonHdr.offset;
++                    size = p_Extract->extractNonHdr.size;
++                    break;
++                default:
++                    RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++            }
++
++            if (generic)
++            {
++                /* set generic register fields */
++                if (currGenId >= FM_KG_NUM_OF_GENERIC_REGS)
++                {
++                    XX_Free(p_LocalExtractsArray);
++                    RETURN_ERROR(MAJOR, E_FULL, ("Generic registers are fully used"));
++                }
++                if (!code)
++                {
++                    XX_Free(p_LocalExtractsArray);
++                    RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG);
++                }
++
++                genTmp = KG_SCH_GEN_VALID;
++                genTmp |= (uint32_t)(code << KG_SCH_GEN_HT_SHIFT);
++                genTmp |= offset;
++                if ((size > MAX_KG_SCH_SIZE) || (size < 1))
++                {
++                    XX_Free(p_LocalExtractsArray);
++                    RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal extraction (size out of range)"));
++                }
++                genTmp |= (uint32_t)((size - 1) << KG_SCH_GEN_SIZE_SHIFT);
++                swDefault = GetGenericSwDefault(swDefaults, numOfSwDefaults, code);
++                if (swDefault == e_FM_PCD_KG_DFLT_ILLEGAL)
++                    DBG(WARNING, ("No sw default configured"));
++                else
++                    genTmp |= swDefault << KG_SCH_GEN_DEF_SHIFT;
++
++                genTmp |= KG_SCH_GEN_MASK;
++                p_SchemeRegs->kgse_gec[currGenId] = genTmp;
++                /* save in driver structure */
++                p_LocalExtractsArray->extractsArray[i].id = currGenId++;
++                p_LocalExtractsArray->extractsArray[i].known = FALSE;
++                generic = FALSE;
++            }
++        }
++        p_SchemeRegs->kgse_ekfc = knownTmp;
++
++        selectTmp = 0;
++        maskTmp = 0xFFFFFFFF;
++        /*  configure kgse_bmch, kgse_bmcl and kgse_fqb */
++
++        if (p_KeyAndHash->numOfUsedMasks > FM_PCD_KG_NUM_OF_EXTRACT_MASKS)
++        {
++            XX_Free(p_LocalExtractsArray);
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Only %d masks supported", FM_PCD_KG_NUM_OF_EXTRACT_MASKS));
++        }
++        for ( i=0 ;i<p_KeyAndHash->numOfUsedMasks ; i++)
++        {
++            /* Get the relative id of the extract (for known 0-0x1f, for generic 0-7) */
++            id = p_LocalExtractsArray->extractsArray[p_KeyAndHash->masks[i].extractArrayIndex].id;
++            /* Get the shift of the select field (depending on i) */
++            GET_MASK_SEL_SHIFT(shift,i);
++            if (p_LocalExtractsArray->extractsArray[p_KeyAndHash->masks[i].extractArrayIndex].known)
++                selectTmp |= id << shift;
++            else
++                selectTmp |= (id + MASK_FOR_GENERIC_BASE_ID) << shift;
++
++            /* Get the shift of the offset field (depending on i) - may
++               be in  kgse_bmch or in kgse_fqb (depending on i) */
++            GET_MASK_OFFSET_SHIFT(shift,i);
++            if (i<=1)
++                selectTmp |= p_KeyAndHash->masks[i].offset << shift;
++            else
++                fqbTmp |= p_KeyAndHash->masks[i].offset << shift;
++
++            /* Get the shift of the mask field (depending on i) */
++            GET_MASK_SHIFT(shift,i);
++            /* pass all bits */
++            maskTmp |= KG_SCH_BITMASK_MASK << shift;
++            /* clear bits that need masking */
++            maskTmp &= ~(0xFF << shift) ;
++            /* set mask bits */
++            maskTmp |= (p_KeyAndHash->masks[i].mask << shift) ;
++        }
++        p_SchemeRegs->kgse_bmch = selectTmp;
++        p_SchemeRegs->kgse_bmcl = maskTmp;
++        /* kgse_fqb will be written t the end of the routine */
++
++        /*  configure kgse_hc  */
++        if (p_KeyAndHash->hashShift > MAX_HASH_SHIFT)
++        {
++            XX_Free(p_LocalExtractsArray);
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashShift must not be larger than %d", MAX_HASH_SHIFT));
++        }
++        if (p_KeyAndHash->hashDistributionFqidsShift > MAX_DIST_FQID_SHIFT)
++        {
++            XX_Free(p_LocalExtractsArray);
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashDistributionFqidsShift must not be larger than %d", MAX_DIST_FQID_SHIFT));
++        }
++
++        tmpReg = 0;
++
++        tmpReg |= ((p_KeyAndHash->hashDistributionNumOfFqids - 1) << p_KeyAndHash->hashDistributionFqidsShift);
++        tmpReg |= p_KeyAndHash->hashShift << KG_SCH_HASH_CONFIG_SHIFT_SHIFT;
++
++        if (p_KeyAndHash->symmetricHash)
++        {
++            if ((!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_MACSRC) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_MACDST)) ||
++                    (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPSRC1) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPDST1)) ||
++                    (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPSRC2) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPDST2)) ||
++                    (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_L4PSRC) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_L4PDST)))
++            {
++                XX_Free(p_LocalExtractsArray);
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("symmetricHash set but src/dest extractions missing"));
++            }
++            tmpReg |= KG_SCH_HASH_CONFIG_SYM;
++        }
++        p_SchemeRegs->kgse_hc = tmpReg;
++
++        /* build the return array describing the order of the extractions */
++
++        /* the last currGenId places of the array
++           are for generic extracts that are always last.
++           We now sort for the calculation of the order of the known
++           extractions we sort the known extracts between orderedArray[0] and
++           orderedArray[p_KeyAndHash->numOfUsedExtracts - currGenId - 1].
++           for the calculation of the order of the generic extractions we use:
++           num_of_generic - currGenId
++           num_of_known - p_KeyAndHash->numOfUsedExtracts - currGenId
++           first_generic_index = num_of_known */
++        curr = 0;
++        for (i=0;i<p_KeyAndHash->numOfUsedExtracts ; i++)
++        {
++            if (p_LocalExtractsArray->extractsArray[i].known)
++            {
++                ASSERT_COND(curr<(p_KeyAndHash->numOfUsedExtracts - currGenId));
++                j = curr;
++                /* id is the extract id (port id = 0, mac src = 1 etc.). the value in the array is the original
++                index in the user's extractions array */
++                /* we compare the id of the current extract with the id of the extract in the orderedArray[j-1]
++                location */
++                while ((j > 0) && (p_LocalExtractsArray->extractsArray[i].id <
++                      p_LocalExtractsArray->extractsArray[p_Scheme->orderedArray[j-1]].id))
++                {
++                    p_Scheme->orderedArray[j] =
++                        p_Scheme->orderedArray[j-1];
++                    j--;
++                }
++                p_Scheme->orderedArray[j] = (uint8_t)i;
++                curr++;
++            }
++            else
++            {
++                /* index is first_generic_index + generic index (id) */
++                idx = (uint8_t)(p_KeyAndHash->numOfUsedExtracts - currGenId + p_LocalExtractsArray->extractsArray[i].id);
++                ASSERT_COND(idx < FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY);
++                p_Scheme->orderedArray[idx]= (uint8_t)i;
++            }
++        }
++        XX_Free(p_LocalExtractsArray);
++    }
++    else
++    {
++        /* clear all unused registers: */
++        p_SchemeRegs->kgse_ekfc = 0;
++        p_SchemeRegs->kgse_ekdv = 0;
++        p_SchemeRegs->kgse_bmch = 0;
++        p_SchemeRegs->kgse_bmcl = 0;
++        p_SchemeRegs->kgse_hc = 0;
++        p_SchemeRegs->kgse_dv0 = 0;
++        p_SchemeRegs->kgse_dv1 = 0;
++    }
++
++    if (p_SchemeParams->bypassFqidGeneration)
++        p_SchemeRegs->kgse_hc |= KG_SCH_HASH_CONFIG_NO_FQID;
++
++    /*  configure kgse_spc  */
++    if ( p_SchemeParams->schemeCounter.update)
++        p_SchemeRegs->kgse_spc = p_SchemeParams->schemeCounter.value;
++
++
++    /* check that are enough generic registers */
++    if (p_SchemeParams->numOfUsedExtractedOrs + currGenId > FM_KG_NUM_OF_GENERIC_REGS)
++        RETURN_ERROR(MAJOR, E_FULL, ("Generic registers are fully used"));
++
++    /* extracted OR mask on Qid */
++    for ( i=0 ;i<p_SchemeParams->numOfUsedExtractedOrs ; i++)
++    {
++
++        p_Scheme->extractedOrs = TRUE;
++        /*  configure kgse_gec[i]  */
++        p_ExtractOr = &p_SchemeParams->extractedOrs[i];
++        switch (p_ExtractOr->type)
++        {
++            case (e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO):
++                code = KG_SCH_GEN_PARSE_RESULT_N_FQID;
++                offset = 0;
++                break;
++            case (e_FM_PCD_EXTRACT_BY_HDR):
++                /* get the header code for the generic extract */
++                code = GetGenHdrCode(p_ExtractOr->extractByHdr.hdr, p_ExtractOr->extractByHdr.hdrIndex, p_ExtractOr->extractByHdr.ignoreProtocolValidation);
++                /* set generic register fields */
++                offset = p_ExtractOr->extractionOffset;
++                break;
++            case (e_FM_PCD_EXTRACT_NON_HDR):
++                /* get the field code for the generic extract */
++                offset = 0;
++                code = GetGenCode(p_ExtractOr->src, &offset);
++                offset += p_ExtractOr->extractionOffset;
++                break;
++            default:
++                RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++        }
++
++        /* set generic register fields */
++        if (!code)
++            RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG);
++        genTmp = KG_SCH_GEN_EXTRACT_TYPE | KG_SCH_GEN_VALID;
++        genTmp |= (uint32_t)(code << KG_SCH_GEN_HT_SHIFT);
++        genTmp |= offset;
++        if (!!p_ExtractOr->bitOffsetInFqid == !!p_ExtractOr->bitOffsetInPlcrProfile)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, (" extracted byte must effect either FQID or Policer profile"));
++
++        /************************************************************************************
++            bitOffsetInFqid and bitOffsetInPolicerProfile are translated to rotate parameter
++            in the following way:
++
++            Driver API and implementation:
++            ==============================
++            FQID: extracted OR byte may be shifted right 1-31 bits to effect parts of the FQID.
++            if shifted less than 8 bits, or more than 24 bits a mask is set on the bits that
++            are not overlapping FQID.
++                     ------------------------
++                    |      FQID (24)         |
++                     ------------------------
++            --------
++           |        |  extracted OR byte
++            --------
++
++            Policer Profile: extracted OR byte may be shifted right 1-15 bits to effect parts of the
++            PP id. Unless shifted exactly 8 bits to overlap the PP id, a mask is set on the bits that
++            are not overlapping PP id.
++
++                     --------
++                    | PP (8) |
++                     --------
++            --------
++           |        |  extracted OR byte
++            --------
++
++            HW implementation
++            =================
++            FQID and PP construct a 32 bit word in the way describe below. Extracted byte is located
++            as the highest byte of that word and may be rotated to effect any part os the FQID or
++            the PP.
++             ------------------------  --------
++            |      FQID (24)         || PP (8) |
++             ------------------------  --------
++             --------
++            |        |  extracted OR byte
++             --------
++
++        ************************************************************************************/
++
++        if (p_ExtractOr->bitOffsetInFqid)
++        {
++            if (p_ExtractOr->bitOffsetInFqid > MAX_KG_SCH_FQID_BIT_OFFSET )
++              RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal extraction (bitOffsetInFqid out of range)"));
++            if (p_ExtractOr->bitOffsetInFqid<8)
++                genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInFqid+24) << KG_SCH_GEN_SIZE_SHIFT);
++            else
++                genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInFqid-8) << KG_SCH_GEN_SIZE_SHIFT);
++            p_ExtractOr->mask &= GetExtractedOrMask(p_ExtractOr->bitOffsetInFqid, TRUE);
++        }
++        else /* effect policer profile */
++        {
++            if (p_ExtractOr->bitOffsetInPlcrProfile > MAX_KG_SCH_PP_BIT_OFFSET )
++              RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal extraction (bitOffsetInPlcrProfile out of range)"));
++            p_Scheme->bitOffsetInPlcrProfile = p_ExtractOr->bitOffsetInPlcrProfile;
++            genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInPlcrProfile+16) << KG_SCH_GEN_SIZE_SHIFT);
++            p_ExtractOr->mask &= GetExtractedOrMask(p_ExtractOr->bitOffsetInPlcrProfile, FALSE);
++        }
++
++        genTmp |= (uint32_t)(p_ExtractOr->extractionOffset << KG_SCH_GEN_DEF_SHIFT);
++        /* clear bits that need masking */
++        genTmp &= ~KG_SCH_GEN_MASK ;
++        /* set mask bits */
++        genTmp |= (uint32_t)(p_ExtractOr->mask << KG_SCH_GEN_MASK_SHIFT);
++        p_SchemeRegs->kgse_gec[currGenId++] = genTmp;
++
++    }
++    /* clear all unused GEC registers */
++    for ( i=currGenId ;i<FM_KG_NUM_OF_GENERIC_REGS ; i++)
++        p_SchemeRegs->kgse_gec[i] = 0;
++
++    /* add base Qid for this scheme */
++    /* add configuration for kgse_fqb */
++    if (p_SchemeParams->baseFqid & ~0x00FFFFFF)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("baseFqid must be between 1 and 2^24-1"));
++
++    fqbTmp |= p_SchemeParams->baseFqid;
++    p_SchemeRegs->kgse_fqb = fqbTmp;
++
++    p_Scheme->nextEngine = p_SchemeParams->nextEngine;
++    p_Scheme->doneAction = p_SchemeParams->kgNextEngineParams.doneAction;
++
++    return E_OK;
++}
++
++
++/*****************************************************************************/
++/*              Inter-module API routines                                    */
++/*****************************************************************************/
++
++t_Error FmPcdKgBuildClsPlanGrp(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_Grp, t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet)
++{
++    t_FmPcd                         *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    t_FmPcdKgClsPlanGrp             *p_ClsPlanGrp;
++    t_FmPcdIpcKgClsPlanParams       kgAlloc;
++    t_Error                         err = E_OK;
++    uint32_t                        oredVectors = 0;
++    int                             i, j;
++
++    /* this routine is protected by the calling routine ! */
++    if (p_Grp->numOfOptions >= FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Too many classification plan basic options selected."));
++
++    /* find a new clsPlan group */
++    for (i = 0; i < FM_MAX_NUM_OF_PORTS; i++)
++        if (!p_FmPcd->p_FmPcdKg->clsPlanGrps[i].used)
++            break;
++    if (i == FM_MAX_NUM_OF_PORTS)
++        RETURN_ERROR(MAJOR, E_FULL,("No classification plan groups available."));
++
++    p_FmPcd->p_FmPcdKg->clsPlanGrps[i].used = TRUE;
++
++    p_Grp->clsPlanGrpId = (uint8_t)i;
++
++    if (p_Grp->numOfOptions == 0)
++        p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId = (uint8_t)i;
++
++    p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[i];
++    p_ClsPlanGrp->netEnvId = p_Grp->netEnvId;
++    p_ClsPlanGrp->owners = 0;
++    FmPcdSetClsPlanGrpId(p_FmPcd, p_Grp->netEnvId, p_Grp->clsPlanGrpId);
++    if (p_Grp->numOfOptions != 0)
++        FmPcdIncNetEnvOwners(p_FmPcd, p_Grp->netEnvId);
++
++    p_ClsPlanGrp->sizeOfGrp = (uint16_t)(1 << p_Grp->numOfOptions);
++    /* a minimal group of 8 is required */
++    if (p_ClsPlanGrp->sizeOfGrp < CLS_PLAN_NUM_PER_GRP)
++        p_ClsPlanGrp->sizeOfGrp = CLS_PLAN_NUM_PER_GRP;
++    if (p_FmPcd->guestId == NCSW_MASTER_ID)
++    {
++        err = KgAllocClsPlanEntries(h_FmPcd, p_ClsPlanGrp->sizeOfGrp, p_FmPcd->guestId, &p_ClsPlanGrp->baseEntry);
++
++        if (err)
++            RETURN_ERROR(MINOR, E_INVALID_STATE, NO_MSG);
++    }
++    else
++    {
++        t_FmPcdIpcMsg   msg;
++        uint32_t        replyLength;
++        t_FmPcdIpcReply reply;
++
++        /* in GUEST_PARTITION, we use the IPC, to also set a private driver group if required */
++        memset(&reply, 0, sizeof(reply));
++        memset(&msg, 0, sizeof(msg));
++        memset(&kgAlloc, 0, sizeof(kgAlloc));
++        kgAlloc.guestId = p_FmPcd->guestId;
++        kgAlloc.numOfClsPlanEntries = p_ClsPlanGrp->sizeOfGrp;
++        msg.msgId = FM_PCD_ALLOC_KG_CLSPLAN;
++        memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc));
++        replyLength = (sizeof(uint32_t) + sizeof(p_ClsPlanGrp->baseEntry));
++        if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
++                                     (uint8_t*)&msg,
++                                     sizeof(msg.msgId) + sizeof(kgAlloc),
++                                     (uint8_t*)&reply,
++                                     &replyLength,
++                                     NULL,
++                                     NULL)) != E_OK)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++
++        if (replyLength != (sizeof(uint32_t) + sizeof(p_ClsPlanGrp->baseEntry)))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++        if ((t_Error)reply.error != E_OK)
++            RETURN_ERROR(MINOR, (t_Error)reply.error, NO_MSG);
++
++        p_ClsPlanGrp->baseEntry = *(uint8_t*)(reply.replyBody);
++    }
++
++    /* build classification plan entries parameters */
++    p_ClsPlanSet->baseEntry = p_ClsPlanGrp->baseEntry;
++    p_ClsPlanSet->numOfClsPlanEntries = p_ClsPlanGrp->sizeOfGrp;
++
++    oredVectors = 0;
++    for (i = 0; i<p_Grp->numOfOptions; i++)
++    {
++        oredVectors |= p_Grp->optVectors[i];
++        /* save an array of used options - the indexes represent the power of 2 index */
++        p_ClsPlanGrp->optArray[i] = p_Grp->options[i];
++    }
++    /* set the classification plan relevant entries so that all bits
++     * relevant to the list of options is cleared
++     */
++    for (j = 0; j<p_ClsPlanGrp->sizeOfGrp; j++)
++        p_ClsPlanSet->vectors[j] = ~oredVectors;
++
++    for (i = 0; i<p_Grp->numOfOptions; i++)
++    {
++       /* option i got the place 2^i in the clsPlan array. all entries that
++         * have bit i set, should have the vector bit cleared. So each option
++         * has one location that it is exclusive (1,2,4,8...) and represent the
++         * presence of that option only, and other locations that represent a
++         * combination of options.
++         * e.g:
++         * If ethernet-BC is option 1 it gets entry 2 in the table. Entry 2
++         * now represents a frame with ethernet-BC header - so the bit
++         * representing ethernet-BC should be set and all other option bits
++         * should be cleared.
++         * Entries 2,3,6,7,10... also have ethernet-BC and therefore have bit
++         * vector[1] set, but they also have other bits set:
++         * 3=1+2, options 0 and 1
++         * 6=2+4, options 1 and 2
++         * 7=1+2+4, options 0,1,and 2
++         * 10=2+8, options 1 and 3
++         * etc.
++         * */
++
++        /* now for each option (i), we set their bits in all entries (j)
++         * that contain bit 2^i.
++         */
++        for (j = 0; j<p_ClsPlanGrp->sizeOfGrp; j++)
++        {
++            if (j & (1<<i))
++                p_ClsPlanSet->vectors[j] |= p_Grp->optVectors[i];
++        }
++    }
++
++    return E_OK;
++}
++
++void FmPcdKgDestroyClsPlanGrp(t_Handle h_FmPcd, uint8_t grpId)
++{
++    t_FmPcd                         *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    t_FmPcdIpcKgClsPlanParams       kgAlloc;
++    t_Error                         err;
++    t_FmPcdIpcMsg                   msg;
++    uint32_t                        replyLength;
++    t_FmPcdIpcReply                 reply;
++
++    /* check that no port is bound to this clsPlan */
++    if (p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].owners)
++    {
++        REPORT_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete a clsPlan grp that has ports bound to"));
++        return;
++    }
++
++    FmPcdSetClsPlanGrpId(p_FmPcd, p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].netEnvId, ILLEGAL_CLS_PLAN);
++
++    if (grpId == p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId)
++        p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId = ILLEGAL_CLS_PLAN;
++    else
++        FmPcdDecNetEnvOwners(p_FmPcd, p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].netEnvId);
++
++    /* free blocks */
++    if (p_FmPcd->guestId == NCSW_MASTER_ID)
++        KgFreeClsPlanEntries(h_FmPcd,
++                             p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].sizeOfGrp,
++                             p_FmPcd->guestId,
++                             p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].baseEntry);
++    else    /* in GUEST_PARTITION, we use the IPC, to also set a private driver group if required */
++    {
++        memset(&reply, 0, sizeof(reply));
++        memset(&msg, 0, sizeof(msg));
++        kgAlloc.guestId = p_FmPcd->guestId;
++        kgAlloc.numOfClsPlanEntries = p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].sizeOfGrp;
++        kgAlloc.clsPlanBase = p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].baseEntry;
++        msg.msgId = FM_PCD_FREE_KG_CLSPLAN;
++        memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc));
++        replyLength = sizeof(uint32_t);
++        err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId) + sizeof(kgAlloc),
++                                (uint8_t*)&reply,
++                                &replyLength,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++        {
++            REPORT_ERROR(MINOR, err, NO_MSG);
++            return;
++        }
++        if (replyLength != sizeof(uint32_t))
++        {
++            REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++            return;
++        }
++        if ((t_Error)reply.error != E_OK)
++        {
++            REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Free KG clsPlan failed"));
++            return;
++        }
++    }
++
++    /* clear clsPlan driver structure */
++    memset(&p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId], 0, sizeof(t_FmPcdKgClsPlanGrp));
++}
++
++t_Error FmPcdKgBuildBindPortToSchemes(t_Handle h_FmPcd, t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort, uint32_t *p_SpReg, bool add)
++{
++    t_FmPcd                 *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint32_t                j, schemesPerPortVector = 0;
++    t_FmPcdKgScheme         *p_Scheme;
++    uint8_t                 i, relativeSchemeId;
++    uint32_t                tmp, walking1Mask;
++    uint8_t                 swPortIndex = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
++
++    /* for each scheme */
++    for (i = 0; i<p_BindPort->numOfSchemes; i++)
++    {
++        relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, p_BindPort->schemesIds[i]);
++        if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES)
++            RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
++
++        if (add)
++        {
++            p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId];
++            if (!FmPcdKgIsSchemeValidSw(p_Scheme))
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Requested scheme is invalid."));
++            /* check netEnvId  of the port against the scheme netEnvId */
++            if ((p_Scheme->netEnvId != p_BindPort->netEnvId) && (p_Scheme->netEnvId != ILLEGAL_NETENV))
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port may not be bound to requested scheme - differ in netEnvId"));
++
++            /* if next engine is private port policer profile, we need to check that it is valid */
++            HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, p_BindPort->hardwarePortId);
++            if (p_Scheme->nextRelativePlcrProfile)
++            {
++                for (j = 0;j<p_Scheme->numOfProfiles;j++)
++                {
++                    ASSERT_COND(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].h_FmPort);
++                    if (p_Scheme->relativeProfileId+j >= p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles)
++                        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Relative profile not in range"));
++                     if (!FmPcdPlcrIsProfileValid(p_FmPcd, (uint16_t)(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase + p_Scheme->relativeProfileId + j)))
++                        RETURN_ERROR(MINOR, E_INVALID_STATE, ("Relative profile not valid."));
++                }
++            }
++            if (!p_BindPort->useClsPlan)
++            {
++                /* This check may be redundant as port is a assigned to the whole NetEnv */
++
++                /* if this port does not use clsPlan, it may not be bound to schemes with units that contain
++                cls plan options. Schemes that are used only directly, should not be checked.
++                it also may not be bound to schemes that go to CC with units that are options  - so we OR
++                the match vector and the grpBits (= ccUnits) */
++                if ((p_Scheme->matchVector != SCHEME_ALWAYS_DIRECT) || p_Scheme->ccUnits)
++                {
++                    uint8_t netEnvId;
++                    walking1Mask = 0x80000000;
++                    netEnvId = (p_Scheme->netEnvId == ILLEGAL_NETENV)? p_BindPort->netEnvId:p_Scheme->netEnvId;
++                    tmp = (p_Scheme->matchVector == SCHEME_ALWAYS_DIRECT)? 0:p_Scheme->matchVector;
++                    tmp |= p_Scheme->ccUnits;
++                    while (tmp)
++                    {
++                        if (tmp & walking1Mask)
++                        {
++                            tmp &= ~walking1Mask;
++                            if (!PcdNetEnvIsUnitWithoutOpts(p_FmPcd, netEnvId, walking1Mask))
++                                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port (without clsPlan) may not be bound to requested scheme - uses clsPlan options"));
++                        }
++                        walking1Mask >>= 1;
++                    }
++                }
++            }
++        }
++        /* build vector */
++        schemesPerPortVector |= 1 << (31 - p_BindPort->schemesIds[i]);
++    }
++
++    *p_SpReg = schemesPerPortVector;
++
++    return E_OK;
++}
++
++t_Error FmPcdKgBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes  *p_SchemeBind)
++{
++    t_FmPcd                 *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint32_t                spReg;
++    t_Error                 err = E_OK;
++
++    err = FmPcdKgBuildBindPortToSchemes(h_FmPcd, p_SchemeBind, &spReg, TRUE);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    err = KgWriteSp(p_FmPcd, p_SchemeBind->hardwarePortId, spReg, TRUE);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    IncSchemeOwners(p_FmPcd, p_SchemeBind);
++
++    return E_OK;
++}
++
++t_Error FmPcdKgUnbindPortToSchemes(t_Handle h_FmPcd, t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind)
++{
++    t_FmPcd                 *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint32_t                spReg;
++    t_Error                 err = E_OK;
++
++    err = FmPcdKgBuildBindPortToSchemes(p_FmPcd, p_SchemeBind, &spReg, FALSE);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    err = KgWriteSp(p_FmPcd, p_SchemeBind->hardwarePortId, spReg, FALSE);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    DecSchemeOwners(p_FmPcd, p_SchemeBind);
++
++    return E_OK;
++}
++
++bool FmPcdKgIsSchemeValidSw(t_Handle h_Scheme)
++{
++    t_FmPcdKgScheme     *p_Scheme = (t_FmPcdKgScheme*)h_Scheme;
++
++    return p_Scheme->valid;
++}
++
++bool KgIsSchemeAlwaysDirect(t_Handle h_FmPcd, uint8_t schemeId)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    if (p_FmPcd->p_FmPcdKg->schemes[schemeId].matchVector == SCHEME_ALWAYS_DIRECT)
++        return TRUE;
++    else
++        return FALSE;
++}
++
++t_Error  FmPcdKgAllocSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds)
++{
++    t_FmPcd             *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    uint8_t             i, j;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE);
++
++    /* This routine is issued only on master core of master partition -
++       either directly or through IPC, so no need for lock */
++
++    for (j = 0, i = 0; i < FM_PCD_KG_NUM_OF_SCHEMES && j < numOfSchemes; i++)
++    {
++        if (!p_FmPcd->p_FmPcdKg->schemesMng[i].allocated)
++        {
++            p_FmPcd->p_FmPcdKg->schemesMng[i].allocated = TRUE;
++            p_FmPcd->p_FmPcdKg->schemesMng[i].ownerId = guestId;
++            p_SchemesIds[j] = i;
++            j++;
++        }
++    }
++
++    if (j != numOfSchemes)
++    {
++        /* roll back */
++        for (j--; j; j--)
++        {
++            p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[j]].allocated = FALSE;
++            p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[j]].ownerId = 0;
++            p_SchemesIds[j] = 0;
++        }
++
++        RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("No schemes found"));
++    }
++
++    return E_OK;
++}
++
++t_Error  FmPcdKgFreeSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds)
++{
++    t_FmPcd             *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    uint8_t             i;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE);
++
++    /* This routine is issued only on master core of master partition -
++       either directly or through IPC */
++
++    for (i = 0; i < numOfSchemes; i++)
++    {
++        if (!p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].allocated)
++        {
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Scheme was not previously allocated"));
++        }
++        if (p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].ownerId != guestId)
++        {
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Scheme is not owned by caller. "));
++        }
++        p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].allocated = FALSE;
++        p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].ownerId = 0;
++    }
++
++    return E_OK;
++}
++
++t_Error  KgAllocClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t *p_First)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    uint8_t     numOfBlocks, blocksFound=0, first=0;
++    uint8_t     i, j;
++
++    /* This routine is issued only on master core of master partition -
++       either directly or through IPC, so no need for lock */
++
++    if (!numOfClsPlanEntries)
++        return E_OK;
++
++    if ((numOfClsPlanEntries % CLS_PLAN_NUM_PER_GRP) || (!POWER_OF_2(numOfClsPlanEntries)))
++         RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfClsPlanEntries must be a power of 2 and divisible by 8"));
++
++    numOfBlocks =  (uint8_t)(numOfClsPlanEntries/CLS_PLAN_NUM_PER_GRP);
++
++    /* try to find consequent blocks */
++    first = 0;
++    for (i = 0; i < FM_PCD_MAX_NUM_OF_CLS_PLANS/CLS_PLAN_NUM_PER_GRP;)
++    {
++        if (!p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].allocated)
++        {
++            blocksFound++;
++            i++;
++            if (blocksFound == numOfBlocks)
++                break;
++        }
++        else
++        {
++            blocksFound = 0;
++            /* advance i to the next aligned address */
++            first = i = (uint8_t)(first + numOfBlocks);
++        }
++    }
++
++    if (blocksFound == numOfBlocks)
++    {
++        *p_First = (uint8_t)(first * CLS_PLAN_NUM_PER_GRP);
++        for (j = first; j < (first + numOfBlocks); j++)
++        {
++            p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[j].allocated = TRUE;
++            p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[j].ownerId = guestId;
++        }
++        return E_OK;
++    }
++    else
++        RETURN_ERROR(MINOR, E_FULL, ("No resources for clsPlan"));
++}
++
++void KgFreeClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t base)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint8_t     numOfBlocks;
++    uint8_t     i, baseBlock;
++
++#ifdef DISABLE_ASSERTIONS
++UNUSED(guestId);
++#endif /* DISABLE_ASSERTIONS */
++
++    /* This routine is issued only on master core of master partition -
++       either directly or through IPC, so no need for lock */
++
++    numOfBlocks =  (uint8_t)(numOfClsPlanEntries/CLS_PLAN_NUM_PER_GRP);
++    ASSERT_COND(!(base%CLS_PLAN_NUM_PER_GRP));
++
++    baseBlock = (uint8_t)(base/CLS_PLAN_NUM_PER_GRP);
++    for (i=baseBlock;i<baseBlock+numOfBlocks;i++)
++    {
++        ASSERT_COND(p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].allocated);
++        ASSERT_COND(guestId == p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].ownerId);
++        p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].allocated = FALSE;
++        p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].ownerId = 0;
++    }
++}
++
++void KgEnable(t_FmPcd *p_FmPcd)
++{
++    struct fman_kg_regs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
++
++    ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
++    fman_kg_enable(p_Regs);
++}
++
++void KgDisable(t_FmPcd *p_FmPcd)
++{
++    struct fman_kg_regs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
++
++    ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
++    fman_kg_disable(p_Regs);
++}
++
++void KgSetClsPlan(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanSet *p_Set)
++{
++    t_FmPcd                 *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    struct fman_kg_cp_regs  *p_FmPcdKgPortRegs;
++    uint32_t                tmpKgarReg = 0, intFlags;
++    uint16_t                i, j;
++
++    /* This routine is protected by the calling routine ! */
++    ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
++    p_FmPcdKgPortRegs = &p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->clsPlanRegs;
++
++    intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
++    for (i=p_Set->baseEntry;i<p_Set->baseEntry+p_Set->numOfClsPlanEntries;i+=8)
++    {
++        tmpKgarReg = FmPcdKgBuildWriteClsPlanBlockActionReg((uint8_t)(i / CLS_PLAN_NUM_PER_GRP));
++
++        for (j = i; j < i+8; j++)
++        {
++            ASSERT_COND(IN_RANGE(0, (j - p_Set->baseEntry), FM_PCD_MAX_NUM_OF_CLS_PLANS-1));
++            WRITE_UINT32(p_FmPcdKgPortRegs->kgcpe[j % CLS_PLAN_NUM_PER_GRP],p_Set->vectors[j - p_Set->baseEntry]);
++        }
++
++        if (WriteKgarWait(p_FmPcd, tmpKgarReg) != E_OK)
++        {
++            REPORT_ERROR(MAJOR, E_INVALID_STATE, ("WriteKgarWait FAILED"));
++            KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
++            return;
++        }
++    }
++    KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
++}
++
++t_Handle KgConfig( t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams)
++{
++    t_FmPcdKg   *p_FmPcdKg;
++
++    UNUSED(p_FmPcd);
++
++    if (p_FmPcdParams->numOfSchemes > FM_PCD_KG_NUM_OF_SCHEMES)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("numOfSchemes should not exceed %d", FM_PCD_KG_NUM_OF_SCHEMES));
++        return NULL;
++    }
++
++    p_FmPcdKg = (t_FmPcdKg *)XX_Malloc(sizeof(t_FmPcdKg));
++    if (!p_FmPcdKg)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Keygen allocation FAILED"));
++        return NULL;
++    }
++    memset(p_FmPcdKg, 0, sizeof(t_FmPcdKg));
++
++
++    if (FmIsMaster(p_FmPcd->h_Fm))
++    {
++        p_FmPcdKg->p_FmPcdKgRegs  = (struct fman_kg_regs *)UINT_TO_PTR(FmGetPcdKgBaseAddr(p_FmPcdParams->h_Fm));
++        p_FmPcd->exceptions |= DEFAULT_fmPcdKgErrorExceptions;
++        p_FmPcdKg->p_IndirectAccessRegs = (u_FmPcdKgIndirectAccessRegs *)&p_FmPcdKg->p_FmPcdKgRegs->fmkg_indirect[0];
++    }
++
++    p_FmPcdKg->numOfSchemes = p_FmPcdParams->numOfSchemes;
++    if ((p_FmPcd->guestId == NCSW_MASTER_ID) && !p_FmPcdKg->numOfSchemes)
++    {
++        p_FmPcdKg->numOfSchemes = FM_PCD_KG_NUM_OF_SCHEMES;
++        DBG(WARNING, ("numOfSchemes was defined 0 by user, re-defined by driver to FM_PCD_KG_NUM_OF_SCHEMES"));
++    }
++
++    p_FmPcdKg->emptyClsPlanGrpId = ILLEGAL_CLS_PLAN;
++
++    return p_FmPcdKg;
++}
++
++t_Error KgInit(t_FmPcd *p_FmPcd)
++{
++    t_Error err = E_OK;
++
++    p_FmPcd->p_FmPcdKg->h_HwSpinlock = XX_InitSpinlock();
++    if (!p_FmPcd->p_FmPcdKg->h_HwSpinlock)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM KG HW spinlock"));
++
++    if (p_FmPcd->guestId == NCSW_MASTER_ID)
++        err =  KgInitMaster(p_FmPcd);
++    else
++        err =  KgInitGuest(p_FmPcd);
++
++    if (err != E_OK)
++    {
++        if (p_FmPcd->p_FmPcdKg->h_HwSpinlock)
++            XX_FreeSpinlock(p_FmPcd->p_FmPcdKg->h_HwSpinlock);
++    }
++
++    return err;
++}
++
++t_Error KgFree(t_FmPcd *p_FmPcd)
++{
++    t_FmPcdIpcKgSchemesParams       kgAlloc;
++    t_Error                         err = E_OK;
++    t_FmPcdIpcMsg                   msg;
++    uint32_t                        replyLength;
++    t_FmPcdIpcReply                 reply;
++
++    FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_KG, 0, e_FM_INTR_TYPE_ERR);
++
++    if (p_FmPcd->guestId == NCSW_MASTER_ID)
++    {
++        err = FmPcdKgFreeSchemes(p_FmPcd,
++                                    p_FmPcd->p_FmPcdKg->numOfSchemes,
++                                    p_FmPcd->guestId,
++                                    p_FmPcd->p_FmPcdKg->schemesIds);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++
++        if (p_FmPcd->p_FmPcdKg->h_HwSpinlock)
++            XX_FreeSpinlock(p_FmPcd->p_FmPcdKg->h_HwSpinlock);
++
++        return E_OK;
++    }
++
++    /* guest */
++    memset(&reply, 0, sizeof(reply));
++    memset(&msg, 0, sizeof(msg));
++    kgAlloc.numOfSchemes = p_FmPcd->p_FmPcdKg->numOfSchemes;
++    kgAlloc.guestId = p_FmPcd->guestId;
++    ASSERT_COND(kgAlloc.numOfSchemes < FM_PCD_KG_NUM_OF_SCHEMES);
++    memcpy(kgAlloc.schemesIds, p_FmPcd->p_FmPcdKg->schemesIds, (sizeof(uint8_t))*kgAlloc.numOfSchemes);
++    msg.msgId = FM_PCD_FREE_KG_SCHEMES;
++    memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc));
++    replyLength = sizeof(uint32_t);
++    if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
++                                 (uint8_t*)&msg,
++                                 sizeof(msg.msgId) + sizeof(kgAlloc),
++                                 (uint8_t*)&reply,
++                                 &replyLength,
++                                 NULL,
++                                 NULL)) != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    if (replyLength != sizeof(uint32_t))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++
++    if (p_FmPcd->p_FmPcdKg->h_HwSpinlock)
++        XX_FreeSpinlock(p_FmPcd->p_FmPcdKg->h_HwSpinlock);
++
++    return (t_Error)reply.error;
++}
++
++t_Error FmPcdKgSetOrBindToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t netEnvId, protocolOpt_t *p_OptArray, uint8_t *p_ClsPlanGrpId, bool *p_IsEmptyClsPlanGrp)
++{
++    t_FmPcd                                 *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    t_FmPcdKgInterModuleClsPlanGrpParams    grpParams, *p_GrpParams;
++    t_FmPcdKgClsPlanGrp                     *p_ClsPlanGrp;
++    t_FmPcdKgInterModuleClsPlanSet          *p_ClsPlanSet;
++    t_Error                                 err;
++
++    /* This function is issued only from FM_PORT_SetPcd which locked all PCD modules,
++       so no need for lock here */
++
++    memset(&grpParams, 0, sizeof(grpParams));
++    grpParams.clsPlanGrpId = ILLEGAL_CLS_PLAN;
++    p_GrpParams = &grpParams;
++
++    p_GrpParams->netEnvId = netEnvId;
++
++    /* Get from the NetEnv the information of the clsPlan (can be already created,
++     * or needs to build) */
++    err = PcdGetClsPlanGrpParams(h_FmPcd, p_GrpParams);
++    if (err)
++        RETURN_ERROR(MINOR,err,NO_MSG);
++
++    if (p_GrpParams->grpExists)
++    {
++        /* this group was already updated (at least) in SW */
++        *p_ClsPlanGrpId = p_GrpParams->clsPlanGrpId;
++    }
++    else
++    {
++        p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet));
++        if (!p_ClsPlanSet)
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Classification plan set"));
++        memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet));
++        /* Build (in SW) the clsPlan parameters, including the vectors to be written to HW */
++        err = FmPcdKgBuildClsPlanGrp(h_FmPcd, p_GrpParams, p_ClsPlanSet);
++        if (err)
++        {
++            XX_Free(p_ClsPlanSet);
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        }
++        *p_ClsPlanGrpId = p_GrpParams->clsPlanGrpId;
++
++        if (p_FmPcd->h_Hc)
++        {
++            /* write clsPlan entries to memory */
++            err = FmHcPcdKgSetClsPlan(p_FmPcd->h_Hc, p_ClsPlanSet);
++            if (err)
++            {
++                XX_Free(p_ClsPlanSet);
++                RETURN_ERROR(MAJOR, err, NO_MSG);
++            }
++        }
++        else
++            /* write clsPlan entries to memory */
++            KgSetClsPlan(p_FmPcd, p_ClsPlanSet);
++
++        XX_Free(p_ClsPlanSet);
++    }
++
++    /* Set caller parameters     */
++
++    /* mark if this is an empty classification group */
++    if (*p_ClsPlanGrpId == p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId)
++        *p_IsEmptyClsPlanGrp = TRUE;
++    else
++        *p_IsEmptyClsPlanGrp = FALSE;
++
++    p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[*p_ClsPlanGrpId];
++
++   /* increment owners number */
++    p_ClsPlanGrp->owners++;
++
++    /* copy options array for port */
++    memcpy(p_OptArray, &p_FmPcd->p_FmPcdKg->clsPlanGrps[*p_ClsPlanGrpId].optArray, FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)*sizeof(protocolOpt_t));
++
++    /* bind port to the new or existing group */
++    err = BindPortToClsPlanGrp(p_FmPcd, hardwarePortId, p_GrpParams->clsPlanGrpId);
++    if (err)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++t_Error FmPcdKgDeleteOrUnbindPortToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId)
++{
++    t_FmPcd                         *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    t_FmPcdKgClsPlanGrp             *p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId];
++    t_FmPcdKgInterModuleClsPlanSet  *p_ClsPlanSet;
++    t_Error                         err;
++
++    /* This function is issued only from FM_PORT_DeletePcd which locked all PCD modules,
++       so no need for lock here */
++
++    UnbindPortToClsPlanGrp(p_FmPcd, hardwarePortId);
++
++    /* decrement owners number */
++    ASSERT_COND(p_ClsPlanGrp->owners);
++    p_ClsPlanGrp->owners--;
++
++    if (!p_ClsPlanGrp->owners)
++    {
++        if (p_FmPcd->h_Hc)
++        {
++            err = FmHcPcdKgDeleteClsPlan(p_FmPcd->h_Hc, clsPlanGrpId);
++            return err;
++        }
++        else
++        {
++            /* clear clsPlan entries in memory */
++            p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet));
++            if (!p_ClsPlanSet)
++            {
++                RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Classification plan set"));
++            }
++            memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet));
++
++            p_ClsPlanSet->baseEntry = p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].baseEntry;
++            p_ClsPlanSet->numOfClsPlanEntries = p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].sizeOfGrp;
++            KgSetClsPlan(p_FmPcd, p_ClsPlanSet);
++            XX_Free(p_ClsPlanSet);
++
++            FmPcdKgDestroyClsPlanGrp(h_FmPcd, clsPlanGrpId);
++       }
++    }
++    return E_OK;
++}
++
++uint32_t FmPcdKgGetRequiredAction(t_Handle h_FmPcd, uint8_t schemeId)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
++
++    return p_FmPcd->p_FmPcdKg->schemes[schemeId].requiredAction;
++}
++
++uint32_t FmPcdKgGetRequiredActionFlag(t_Handle h_FmPcd, uint8_t schemeId)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++   ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
++
++    return p_FmPcd->p_FmPcdKg->schemes[schemeId].requiredActionFlag;
++}
++
++bool FmPcdKgIsDirectPlcr(t_Handle h_FmPcd, uint8_t schemeId)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++   ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
++
++    return p_FmPcd->p_FmPcdKg->schemes[schemeId].directPlcr;
++}
++
++
++uint16_t FmPcdKgGetRelativeProfileId(t_Handle h_FmPcd, uint8_t schemeId)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++   ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
++
++    return p_FmPcd->p_FmPcdKg->schemes[schemeId].relativeProfileId;
++}
++
++bool FmPcdKgIsDistrOnPlcrProfile(t_Handle h_FmPcd, uint8_t schemeId)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++   ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
++
++    if ((p_FmPcd->p_FmPcdKg->schemes[schemeId].extractedOrs &&
++        p_FmPcd->p_FmPcdKg->schemes[schemeId].bitOffsetInPlcrProfile) ||
++        p_FmPcd->p_FmPcdKg->schemes[schemeId].nextRelativePlcrProfile)
++        return TRUE;
++    else
++        return FALSE;
++
++}
++
++e_FmPcdEngine FmPcdKgGetNextEngine(t_Handle h_FmPcd, uint8_t relativeSchemeId)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].valid);
++
++    return p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine;
++}
++
++e_FmPcdDoneAction FmPcdKgGetDoneAction(t_Handle h_FmPcd, uint8_t schemeId)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
++
++    return p_FmPcd->p_FmPcdKg->schemes[schemeId].doneAction;
++}
++
++void FmPcdKgUpdateRequiredAction(t_Handle h_Scheme, uint32_t requiredAction)
++{
++    t_FmPcdKgScheme *p_Scheme = (t_FmPcdKgScheme *)h_Scheme;
++
++    /* this routine is protected by calling routine */
++
++    ASSERT_COND(p_Scheme->valid);
++
++    p_Scheme->requiredAction |= requiredAction;
++}
++
++bool FmPcdKgHwSchemeIsValid(uint32_t schemeModeReg)
++{
++    return (bool)!!(schemeModeReg & KG_SCH_MODE_EN);
++}
++
++uint32_t FmPcdKgBuildWriteSchemeActionReg(uint8_t schemeId, bool updateCounter)
++{
++    return (uint32_t)(((uint32_t)schemeId << FM_PCD_KG_KGAR_NUM_SHIFT) |
++                      FM_KG_KGAR_GO |
++                      FM_KG_KGAR_WRITE |
++                      FM_KG_KGAR_SEL_SCHEME_ENTRY |
++                      DUMMY_PORT_ID |
++                      (updateCounter ? FM_KG_KGAR_SCM_WSEL_UPDATE_CNT:0));
++}
++
++uint32_t FmPcdKgBuildReadSchemeActionReg(uint8_t schemeId)
++{
++    return (uint32_t)(((uint32_t)schemeId << FM_PCD_KG_KGAR_NUM_SHIFT) |
++                      FM_KG_KGAR_GO |
++                      FM_KG_KGAR_READ |
++                      FM_KG_KGAR_SEL_SCHEME_ENTRY |
++                      DUMMY_PORT_ID |
++                      FM_KG_KGAR_SCM_WSEL_UPDATE_CNT);
++
++}
++
++uint32_t FmPcdKgBuildWriteClsPlanBlockActionReg(uint8_t grpId)
++{
++    return (uint32_t)(FM_KG_KGAR_GO |
++                      FM_KG_KGAR_WRITE |
++                      FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY |
++                      DUMMY_PORT_ID |
++                      ((uint32_t)grpId << FM_PCD_KG_KGAR_NUM_SHIFT) |
++                      FM_PCD_KG_KGAR_WSEL_MASK);
++
++    /* if we ever want to write 1 by 1, use:
++       sel = (uint8_t)(0x01 << (7- (entryId % CLS_PLAN_NUM_PER_GRP)));
++     */
++}
++
++uint32_t FmPcdKgBuildWritePortSchemeBindActionReg(uint8_t hardwarePortId)
++{
++
++    return (uint32_t)(FM_KG_KGAR_GO |
++                      FM_KG_KGAR_WRITE |
++                      FM_PCD_KG_KGAR_SEL_PORT_ENTRY |
++                      hardwarePortId |
++                      FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP);
++}
++
++uint32_t FmPcdKgBuildReadPortSchemeBindActionReg(uint8_t hardwarePortId)
++{
++
++    return (uint32_t)(FM_KG_KGAR_GO |
++                      FM_KG_KGAR_READ |
++                      FM_PCD_KG_KGAR_SEL_PORT_ENTRY |
++                      hardwarePortId |
++                      FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP);
++}
++
++uint32_t FmPcdKgBuildWritePortClsPlanBindActionReg(uint8_t hardwarePortId)
++{
++
++    return (uint32_t)(FM_KG_KGAR_GO |
++                      FM_KG_KGAR_WRITE |
++                      FM_PCD_KG_KGAR_SEL_PORT_ENTRY |
++                      hardwarePortId |
++                      FM_PCD_KG_KGAR_SEL_PORT_WSEL_CPP);
++}
++
++uint8_t FmPcdKgGetClsPlanGrpBase(t_Handle h_FmPcd, uint8_t clsPlanGrp)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    return p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrp].baseEntry;
++}
++
++uint16_t FmPcdKgGetClsPlanGrpSize(t_Handle h_FmPcd, uint8_t clsPlanGrp)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    return p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrp].sizeOfGrp;
++}
++
++
++uint8_t FmPcdKgGetSchemeId(t_Handle h_Scheme)
++{
++    return ((t_FmPcdKgScheme*)h_Scheme)->schemeId;
++
++}
++
++#if (DPAA_VERSION >= 11)
++bool FmPcdKgGetVspe(t_Handle h_Scheme)
++{
++    return ((t_FmPcdKgScheme*)h_Scheme)->vspe;
++
++}
++#endif /* (DPAA_VERSION >= 11) */
++
++uint8_t FmPcdKgGetRelativeSchemeId(t_Handle h_FmPcd, uint8_t schemeId)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint8_t     i;
++
++    for (i = 0;i<p_FmPcd->p_FmPcdKg->numOfSchemes;i++)
++        if (p_FmPcd->p_FmPcdKg->schemesIds[i] == schemeId)
++            return i;
++
++    if (i == p_FmPcd->p_FmPcdKg->numOfSchemes)
++        REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("Scheme is out of partition range"));
++
++    return FM_PCD_KG_NUM_OF_SCHEMES;
++}
++
++t_Handle FmPcdKgGetSchemeHandle(t_Handle h_FmPcd, uint8_t relativeSchemeId)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    ASSERT_COND(p_FmPcd);
++
++    /* check that schemeId is in range */
++    if (relativeSchemeId >= p_FmPcd->p_FmPcdKg->numOfSchemes)
++    {
++        REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("relative-scheme-id %d!", relativeSchemeId));
++        return NULL;
++    }
++
++    if (!FmPcdKgIsSchemeValidSw(&p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId]))
++        return NULL;
++
++    return &p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId];
++}
++
++bool FmPcdKgIsSchemeHasOwners(t_Handle h_Scheme)
++{
++    return (((t_FmPcdKgScheme*)h_Scheme)->owners == 0)?FALSE:TRUE;
++}
++
++t_Error FmPcdKgCcGetSetParams(t_Handle h_FmPcd, t_Handle h_Scheme, uint32_t requiredAction, uint32_t value)
++{
++    t_FmPcd             *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint8_t             relativeSchemeId, physicalSchemeId;
++    uint32_t            tmpKgarReg, tmpReg32 = 0, intFlags;
++    t_Error             err;
++    t_FmPcdKgScheme     *p_Scheme = (t_FmPcdKgScheme*)h_Scheme;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0);
++    SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, 0);
++    SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0);
++
++    /* Calling function locked all PCD modules, so no need to lock here */
++
++    if (!FmPcdKgIsSchemeValidSw(h_Scheme))
++        RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid"));
++
++    if (p_FmPcd->h_Hc)
++    {
++        err = FmHcPcdKgCcGetSetParams(p_FmPcd->h_Hc, h_Scheme, requiredAction, value);
++
++        UpdateRequiredActionFlag(h_Scheme,TRUE);
++        FmPcdKgUpdateRequiredAction(h_Scheme,requiredAction);
++        return err;
++    }
++
++    physicalSchemeId = p_Scheme->schemeId;
++
++    relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId);
++    if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES)
++        RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
++
++    if (!p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].requiredActionFlag ||
++        !(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].requiredAction & requiredAction))
++    {
++        if (requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA)
++        {
++            switch (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine)
++            {
++                case (e_FM_PCD_DONE):
++                    if (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].doneAction == e_FM_PCD_ENQ_FRAME)
++                    {
++                        tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
++                        intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
++                        WriteKgarWait(p_FmPcd, tmpKgarReg);
++                        tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode);
++                        ASSERT_COND(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME));
++                        WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode, tmpReg32 | NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA);
++                        /* call indirect command for scheme write */
++                        tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE);
++                        WriteKgarWait(p_FmPcd, tmpKgarReg);
++                        KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
++                    }
++                break;
++                case (e_FM_PCD_PLCR):
++                    if (!p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].directPlcr ||
++                       (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].extractedOrs &&
++                        p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].bitOffsetInPlcrProfile) ||
++                        p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextRelativePlcrProfile)
++                        {
++                            RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("In this situation PP can not be with distribution and has to be shared"));
++                        }
++                        err = FmPcdPlcrCcGetSetParams(h_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].relativeProfileId, requiredAction);
++                        if (err)
++                        {
++                            RETURN_ERROR(MAJOR, err, NO_MSG);
++                        }
++               break;
++               default:
++                    RETURN_ERROR(MAJOR, E_INVALID_VALUE,("in this situation the next engine after scheme can be or PLCR or ENQ_FRAME"));
++            }
++        }
++        if (requiredAction & UPDATE_KG_NIA_CC_WA)
++        {
++            if (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine == e_FM_PCD_CC)
++            {
++                tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
++                intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
++                WriteKgarWait(p_FmPcd, tmpKgarReg);
++                tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode);
++                ASSERT_COND(tmpReg32 & (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC));
++                tmpReg32 &= ~NIA_FM_CTL_AC_CC;
++                WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode, tmpReg32 | NIA_FM_CTL_AC_PRE_CC);
++                /* call indirect command for scheme write */
++                tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE);
++                WriteKgarWait(p_FmPcd, tmpKgarReg);
++                KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
++           }
++        }
++        if (requiredAction & UPDATE_KG_OPT_MODE)
++        {
++            tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
++            intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
++            WriteKgarWait(p_FmPcd, tmpKgarReg);
++            WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_om, value);
++            /* call indirect command for scheme write */
++            tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE);
++            WriteKgarWait(p_FmPcd, tmpKgarReg);
++            KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
++        }
++        if (requiredAction & UPDATE_KG_NIA)
++        {
++            tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
++            intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
++            WriteKgarWait(p_FmPcd, tmpKgarReg);
++            tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode);
++            tmpReg32 &= ~(NIA_ENG_MASK | NIA_AC_MASK);
++            tmpReg32 |= value;
++            WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode, tmpReg32);
++            /* call indirect command for scheme write */
++            tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE);
++            WriteKgarWait(p_FmPcd, tmpKgarReg);
++            KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
++        }
++    }
++
++    UpdateRequiredActionFlag(h_Scheme, TRUE);
++    FmPcdKgUpdateRequiredAction(h_Scheme, requiredAction);
++
++    return E_OK;
++}
++/*********************** End of inter-module routines ************************/
++
++
++/****************************************/
++/*  API routines                        */
++/****************************************/
++
++t_Handle FM_PCD_KgSchemeSet(t_Handle h_FmPcd,  t_FmPcdKgSchemeParams *p_SchemeParams)
++{
++    t_FmPcd                             *p_FmPcd;
++    struct fman_kg_scheme_regs          schemeRegs;
++    struct fman_kg_scheme_regs          *p_MemRegs;
++    uint8_t                             i;
++    t_Error                             err = E_OK;
++    uint32_t                            tmpKgarReg;
++    uint32_t                            intFlags;
++    uint8_t                             physicalSchemeId, relativeSchemeId = 0;
++    t_FmPcdKgScheme                     *p_Scheme;
++
++    if (p_SchemeParams->modify)
++    {
++        p_Scheme = (t_FmPcdKgScheme *)p_SchemeParams->id.h_Scheme;
++        p_FmPcd = p_Scheme->h_FmPcd;
++
++        SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, NULL);
++        SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, NULL);
++
++        if (!FmPcdKgIsSchemeValidSw(p_Scheme))
++        {
++            REPORT_ERROR(MAJOR, E_ALREADY_EXISTS,
++                         ("Scheme is invalid"));
++            return NULL;
++        }
++
++        if (!KgSchemeFlagTryLock(p_Scheme))
++        {
++            DBG(TRACE, ("Scheme Try Lock - BUSY"));
++            /* Signal to caller BUSY condition */
++            p_SchemeParams->id.h_Scheme = NULL;
++            return NULL;
++        }
++    }
++    else
++    {
++        p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++        SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, NULL);
++        SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, NULL);
++
++        relativeSchemeId = p_SchemeParams->id.relativeSchemeId;
++        /* check that schemeId is in range */
++        if (relativeSchemeId >= p_FmPcd->p_FmPcdKg->numOfSchemes)
++        {
++            REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("relative-scheme-id %d!", relativeSchemeId));
++            return NULL;
++        }
++
++        p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId];
++        if (FmPcdKgIsSchemeValidSw(p_Scheme))
++        {
++            REPORT_ERROR(MAJOR, E_ALREADY_EXISTS,
++                         ("Scheme id (%d)!", relativeSchemeId));
++            return NULL;
++        }
++        /* Clear all fields, scheme may have beed previously used */
++        memset(p_Scheme, 0, sizeof(t_FmPcdKgScheme));
++
++        p_Scheme->schemeId = p_FmPcd->p_FmPcdKg->schemesIds[relativeSchemeId];
++        p_Scheme->h_FmPcd = p_FmPcd;
++
++        p_Scheme->p_Lock = FmPcdAcquireLock(p_FmPcd);
++        if (!p_Scheme->p_Lock)
++            REPORT_ERROR(MAJOR, E_NOT_AVAILABLE, ("FM KG Scheme lock obj!"));
++    }
++
++    err = BuildSchemeRegs((t_Handle)p_Scheme, p_SchemeParams, &schemeRegs);
++    if (err)
++    {
++        REPORT_ERROR(MAJOR, err, NO_MSG);
++        if (p_SchemeParams->modify)
++            KgSchemeFlagUnlock(p_Scheme);
++        if (!p_SchemeParams->modify &&
++            p_Scheme->p_Lock)
++            FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock);
++        return NULL;
++    }
++
++    if (p_FmPcd->h_Hc)
++    {
++        err = FmHcPcdKgSetScheme(p_FmPcd->h_Hc,
++                                 (t_Handle)p_Scheme,
++                                 &schemeRegs,
++                                 p_SchemeParams->schemeCounter.update);
++        if (p_SchemeParams->modify)
++            KgSchemeFlagUnlock(p_Scheme);
++        if (err)
++        {
++            if (!p_SchemeParams->modify &&
++                p_Scheme->p_Lock)
++                FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock);
++            return NULL;
++        }
++        if (!p_SchemeParams->modify)
++            ValidateSchemeSw(p_Scheme);
++        return (t_Handle)p_Scheme;
++    }
++
++    physicalSchemeId = p_Scheme->schemeId;
++
++    /* configure all 21 scheme registers */
++    p_MemRegs = &p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs;
++    intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
++    WRITE_UINT32(p_MemRegs->kgse_ppc,   schemeRegs.kgse_ppc);
++    WRITE_UINT32(p_MemRegs->kgse_ccbs,  schemeRegs.kgse_ccbs);
++    WRITE_UINT32(p_MemRegs->kgse_mode,  schemeRegs.kgse_mode);
++    WRITE_UINT32(p_MemRegs->kgse_mv,    schemeRegs.kgse_mv);
++    WRITE_UINT32(p_MemRegs->kgse_dv0,   schemeRegs.kgse_dv0);
++    WRITE_UINT32(p_MemRegs->kgse_dv1,   schemeRegs.kgse_dv1);
++    WRITE_UINT32(p_MemRegs->kgse_ekdv,  schemeRegs.kgse_ekdv);
++    WRITE_UINT32(p_MemRegs->kgse_ekfc,  schemeRegs.kgse_ekfc);
++    WRITE_UINT32(p_MemRegs->kgse_bmch,  schemeRegs.kgse_bmch);
++    WRITE_UINT32(p_MemRegs->kgse_bmcl,  schemeRegs.kgse_bmcl);
++    WRITE_UINT32(p_MemRegs->kgse_hc,    schemeRegs.kgse_hc);
++    WRITE_UINT32(p_MemRegs->kgse_spc,   schemeRegs.kgse_spc);
++    WRITE_UINT32(p_MemRegs->kgse_fqb,   schemeRegs.kgse_fqb);
++    WRITE_UINT32(p_MemRegs->kgse_om,    schemeRegs.kgse_om);
++    WRITE_UINT32(p_MemRegs->kgse_vsp,   schemeRegs.kgse_vsp);
++    for (i=0 ; i<FM_KG_NUM_OF_GENERIC_REGS ; i++)
++        WRITE_UINT32(p_MemRegs->kgse_gec[i], schemeRegs.kgse_gec[i]);
++
++    /* call indirect command for scheme write */
++    tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, p_SchemeParams->schemeCounter.update);
++
++    WriteKgarWait(p_FmPcd, tmpKgarReg);
++    KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
++
++    if (!p_SchemeParams->modify)
++        ValidateSchemeSw(p_Scheme);
++    else
++        KgSchemeFlagUnlock(p_Scheme);
++
++    return (t_Handle)p_Scheme;
++}
++
++t_Error  FM_PCD_KgSchemeDelete(t_Handle h_Scheme)
++{
++    t_FmPcd             *p_FmPcd;
++    uint8_t             physicalSchemeId;
++    uint32_t            tmpKgarReg, intFlags;
++    t_Error             err = E_OK;
++    t_FmPcdKgScheme     *p_Scheme = (t_FmPcdKgScheme *)h_Scheme;
++
++    SANITY_CHECK_RETURN_ERROR(h_Scheme, E_INVALID_HANDLE);
++
++    p_FmPcd = (t_FmPcd*)(p_Scheme->h_FmPcd);
++
++    UpdateRequiredActionFlag(h_Scheme, FALSE);
++
++    /* check that no port is bound to this scheme */
++    err = InvalidateSchemeSw(h_Scheme);
++    if (err)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    if (p_FmPcd->h_Hc)
++    {
++        err = FmHcPcdKgDeleteScheme(p_FmPcd->h_Hc, h_Scheme);
++        if (p_Scheme->p_Lock)
++            FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock);
++        return err;
++    }
++
++    physicalSchemeId = ((t_FmPcdKgScheme *)h_Scheme)->schemeId;
++
++    intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
++    /* clear mode register, including enable bit */
++    WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode, 0);
++
++    /* call indirect command for scheme write */
++    tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE);
++
++    WriteKgarWait(p_FmPcd, tmpKgarReg);
++    KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
++
++    if (p_Scheme->p_Lock)
++        FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock);
++
++    return E_OK;
++}
++
++uint32_t  FM_PCD_KgSchemeGetCounter(t_Handle h_Scheme)
++{
++    t_FmPcd             *p_FmPcd;
++    uint32_t            tmpKgarReg, spc, intFlags;
++    uint8_t             physicalSchemeId;
++
++    SANITY_CHECK_RETURN_VALUE(h_Scheme, E_INVALID_HANDLE, 0);
++
++    p_FmPcd = (t_FmPcd*)(((t_FmPcdKgScheme *)h_Scheme)->h_FmPcd);
++    if (p_FmPcd->h_Hc)
++        return FmHcPcdKgGetSchemeCounter(p_FmPcd->h_Hc, h_Scheme);
++
++    physicalSchemeId = ((t_FmPcdKgScheme *)h_Scheme)->schemeId;
++
++    if (FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId) == FM_PCD_KG_NUM_OF_SCHEMES)
++        REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
++
++    tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
++    intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
++    WriteKgarWait(p_FmPcd, tmpKgarReg);
++    if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode) & KG_SCH_MODE_EN))
++       REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid"));
++    spc = GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_spc);
++    KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
++
++    return spc;
++}
++
++t_Error  FM_PCD_KgSchemeSetCounter(t_Handle h_Scheme, uint32_t value)
++{
++    t_FmPcd             *p_FmPcd;
++    uint32_t            tmpKgarReg, intFlags;
++    uint8_t             physicalSchemeId;
++
++    SANITY_CHECK_RETURN_VALUE(h_Scheme, E_INVALID_HANDLE, 0);
++
++    p_FmPcd = (t_FmPcd*)(((t_FmPcdKgScheme *)h_Scheme)->h_FmPcd);
++
++    if (!FmPcdKgIsSchemeValidSw(h_Scheme))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Requested scheme is invalid."));
++
++    if (p_FmPcd->h_Hc)
++        return FmHcPcdKgSetSchemeCounter(p_FmPcd->h_Hc, h_Scheme, value);
++
++    physicalSchemeId = ((t_FmPcdKgScheme *)h_Scheme)->schemeId;
++    /* check that schemeId is in range */
++    if (FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId) == FM_PCD_KG_NUM_OF_SCHEMES)
++        REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
++
++    /* read specified scheme into scheme registers */
++    tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
++    intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
++    WriteKgarWait(p_FmPcd, tmpKgarReg);
++    if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode) & KG_SCH_MODE_EN))
++    {
++       KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
++       RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid"));
++    }
++
++    /* change counter value */
++    WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_spc, value);
++
++    /* call indirect command for scheme write */
++    tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE);
++
++    WriteKgarWait(p_FmPcd, tmpKgarReg);
++    KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
++
++    return E_OK;
++}
++
++t_Error FM_PCD_KgSetAdditionalDataAfterParsing(t_Handle h_FmPcd, uint8_t payloadOffset)
++{
++   t_FmPcd              *p_FmPcd = (t_FmPcd*)h_FmPcd;
++   struct fman_kg_regs  *p_Regs;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs, E_NULL_POINTER);
++
++    p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
++    if (!FmIsMaster(p_FmPcd->h_Fm))
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_KgSetAdditionalDataAfterParsing - guest mode!"));
++
++    WRITE_UINT32(p_Regs->fmkg_fdor,payloadOffset);
++
++    return E_OK;
++}
++
++t_Error FM_PCD_KgSetDfltValue(t_Handle h_FmPcd, uint8_t valueId, uint32_t value)
++{
++   t_FmPcd              *p_FmPcd = (t_FmPcd*)h_FmPcd;
++   struct fman_kg_regs  *p_Regs;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(((valueId == 0) || (valueId == 1)), E_INVALID_VALUE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs, E_NULL_POINTER);
++
++    p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
++
++    if (!FmIsMaster(p_FmPcd->h_Fm))
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_KgSetDfltValue - guest mode!"));
++
++    if (valueId == 0)
++        WRITE_UINT32(p_Regs->fmkg_gdv0r,value);
++    else
++        WRITE_UINT32(p_Regs->fmkg_gdv1r,value);
++    return E_OK;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.h
+@@ -0,0 +1,206 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_kg.h
++
++ @Description   FM KG private header
++*//***************************************************************************/
++#ifndef __FM_KG_H
++#define __FM_KG_H
++
++#include "std_ext.h"
++
++/***********************************************************************/
++/*          Keygen defines                                             */
++/***********************************************************************/
++/* maskes */
++#if (DPAA_VERSION >= 11)
++#define KG_SCH_VSP_SHIFT_MASK                   0x0003f000
++#define KG_SCH_OM_VSPE                          0x00000001
++#define KG_SCH_VSP_NO_KSP_EN                    0x80000000
++
++#define MAX_SP_SHIFT                            23
++#define KG_SCH_VSP_MASK_SHIFT                   12
++#define KG_SCH_VSP_SHIFT                        24
++#endif /* (DPAA_VERSION >= 11) */
++
++typedef uint32_t t_KnownFieldsMasks;
++#define KG_SCH_KN_PORT_ID                   0x80000000
++#define KG_SCH_KN_MACDST                    0x40000000
++#define KG_SCH_KN_MACSRC                    0x20000000
++#define KG_SCH_KN_TCI1                      0x10000000
++#define KG_SCH_KN_TCI2                      0x08000000
++#define KG_SCH_KN_ETYPE                     0x04000000
++#define KG_SCH_KN_PPPSID                    0x02000000
++#define KG_SCH_KN_PPPID                     0x01000000
++#define KG_SCH_KN_MPLS1                     0x00800000
++#define KG_SCH_KN_MPLS2                     0x00400000
++#define KG_SCH_KN_MPLS_LAST                 0x00200000
++#define KG_SCH_KN_IPSRC1                    0x00100000
++#define KG_SCH_KN_IPDST1                    0x00080000
++#define KG_SCH_KN_PTYPE1                    0x00040000
++#define KG_SCH_KN_IPTOS_TC1                 0x00020000
++#define KG_SCH_KN_IPV6FL1                   0x00010000
++#define KG_SCH_KN_IPSRC2                    0x00008000
++#define KG_SCH_KN_IPDST2                    0x00004000
++#define KG_SCH_KN_PTYPE2                    0x00002000
++#define KG_SCH_KN_IPTOS_TC2                 0x00001000
++#define KG_SCH_KN_IPV6FL2                   0x00000800
++#define KG_SCH_KN_GREPTYPE                  0x00000400
++#define KG_SCH_KN_IPSEC_SPI                 0x00000200
++#define KG_SCH_KN_IPSEC_NH                  0x00000100
++#define KG_SCH_KN_IPPID                     0x00000080
++#define KG_SCH_KN_L4PSRC                    0x00000004
++#define KG_SCH_KN_L4PDST                    0x00000002
++#define KG_SCH_KN_TFLG                      0x00000001
++
++typedef uint8_t t_GenericCodes;
++#define KG_SCH_GEN_SHIM1                       0x70
++#define KG_SCH_GEN_DEFAULT                     0x10
++#define KG_SCH_GEN_PARSE_RESULT_N_FQID         0x20
++#define KG_SCH_GEN_START_OF_FRM                0x40
++#define KG_SCH_GEN_SHIM2                       0x71
++#define KG_SCH_GEN_IP_PID_NO_V                 0x72
++#define KG_SCH_GEN_ETH                         0x03
++#define KG_SCH_GEN_ETH_NO_V                    0x73
++#define KG_SCH_GEN_SNAP                        0x04
++#define KG_SCH_GEN_SNAP_NO_V                   0x74
++#define KG_SCH_GEN_VLAN1                       0x05
++#define KG_SCH_GEN_VLAN1_NO_V                  0x75
++#define KG_SCH_GEN_VLAN2                       0x06
++#define KG_SCH_GEN_VLAN2_NO_V                  0x76
++#define KG_SCH_GEN_ETH_TYPE                    0x07
++#define KG_SCH_GEN_ETH_TYPE_NO_V               0x77
++#define KG_SCH_GEN_PPP                         0x08
++#define KG_SCH_GEN_PPP_NO_V                    0x78
++#define KG_SCH_GEN_MPLS1                       0x09
++#define KG_SCH_GEN_MPLS2                       0x19
++#define KG_SCH_GEN_MPLS3                       0x29
++#define KG_SCH_GEN_MPLS1_NO_V                  0x79
++#define KG_SCH_GEN_MPLS_LAST                   0x0a
++#define KG_SCH_GEN_MPLS_LAST_NO_V              0x7a
++#define KG_SCH_GEN_IPV4                        0x0b
++#define KG_SCH_GEN_IPV6                        0x1b
++#define KG_SCH_GEN_L3_NO_V                     0x7b
++#define KG_SCH_GEN_IPV4_TUNNELED               0x0c
++#define KG_SCH_GEN_IPV6_TUNNELED               0x1c
++#define KG_SCH_GEN_MIN_ENCAP                   0x2c
++#define KG_SCH_GEN_IP2_NO_V                    0x7c
++#define KG_SCH_GEN_GRE                         0x0d
++#define KG_SCH_GEN_GRE_NO_V                    0x7d
++#define KG_SCH_GEN_TCP                         0x0e
++#define KG_SCH_GEN_UDP                         0x1e
++#define KG_SCH_GEN_IPSEC_AH                    0x2e
++#define KG_SCH_GEN_SCTP                        0x3e
++#define KG_SCH_GEN_DCCP                        0x4e
++#define KG_SCH_GEN_IPSEC_ESP                   0x6e
++#define KG_SCH_GEN_L4_NO_V                     0x7e
++#define KG_SCH_GEN_NEXTHDR                     0x7f
++/* shifts */
++#define KG_SCH_PP_SHIFT_HIGH_SHIFT          27
++#define KG_SCH_PP_SHIFT_LOW_SHIFT           12
++#define KG_SCH_PP_MASK_SHIFT                16
++#define KG_SCH_MODE_CCOBASE_SHIFT           24
++#define KG_SCH_DEF_MAC_ADDR_SHIFT           30
++#define KG_SCH_DEF_TCI_SHIFT                28
++#define KG_SCH_DEF_ENET_TYPE_SHIFT          26
++#define KG_SCH_DEF_PPP_SESSION_ID_SHIFT     24
++#define KG_SCH_DEF_PPP_PROTOCOL_ID_SHIFT    22
++#define KG_SCH_DEF_MPLS_LABEL_SHIFT         20
++#define KG_SCH_DEF_IP_ADDR_SHIFT            18
++#define KG_SCH_DEF_PROTOCOL_TYPE_SHIFT      16
++#define KG_SCH_DEF_IP_TOS_TC_SHIFT          14
++#define KG_SCH_DEF_IPV6_FLOW_LABEL_SHIFT    12
++#define KG_SCH_DEF_IPSEC_SPI_SHIFT          10
++#define KG_SCH_DEF_L4_PORT_SHIFT            8
++#define KG_SCH_DEF_TCP_FLAG_SHIFT           6
++#define KG_SCH_HASH_CONFIG_SHIFT_SHIFT      24
++#define KG_SCH_GEN_MASK_SHIFT               16
++#define KG_SCH_GEN_HT_SHIFT                 8
++#define KG_SCH_GEN_SIZE_SHIFT               24
++#define KG_SCH_GEN_DEF_SHIFT                29
++#define FM_PCD_KG_KGAR_NUM_SHIFT            16
++
++/* others */
++#define NUM_OF_SW_DEFAULTS                  3
++#define MAX_PP_SHIFT                        23
++#define MAX_KG_SCH_SIZE                     16
++#define MASK_FOR_GENERIC_BASE_ID            0x20
++#define MAX_HASH_SHIFT                      40
++#define MAX_KG_SCH_FQID_BIT_OFFSET          31
++#define MAX_KG_SCH_PP_BIT_OFFSET            15
++#define MAX_DIST_FQID_SHIFT                 23
++
++#define GET_MASK_SEL_SHIFT(shift,i)                 \
++switch (i) {                                        \
++    case (0):shift = 26;break;                      \
++    case (1):shift = 20;break;                      \
++    case (2):shift = 10;break;                      \
++    case (3):shift = 4;break;                       \
++    default:                                        \
++    RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);   \
++}
++
++#define GET_MASK_OFFSET_SHIFT(shift,i)              \
++switch (i) {                                        \
++    case (0):shift = 16;break;                      \
++    case (1):shift = 0;break;                       \
++    case (2):shift = 28;break;                      \
++    case (3):shift = 24;break;                      \
++    default:                                        \
++    RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);   \
++}
++
++#define GET_MASK_SHIFT(shift,i)                     \
++switch (i) {                                        \
++    case (0):shift = 24;break;                      \
++    case (1):shift = 16;break;                      \
++    case (2):shift = 8;break;                       \
++    case (3):shift = 0;break;                       \
++    default:                                        \
++    RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);   \
++}
++
++/***********************************************************************/
++/*          Keygen defines                                             */
++/***********************************************************************/
++
++#define KG_DOUBLE_MEANING_REGS_OFFSET           0x100
++#define NO_VALIDATION                           0x70
++#define KG_ACTION_REG_TO                        1024
++#define KG_MAX_PROFILE                          255
++#define SCHEME_ALWAYS_DIRECT                    0xFFFFFFFF
++
++
++#endif /* __FM_KG_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c
+@@ -0,0 +1,5571 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_manip.c
++
++ @Description   FM PCD manip ...
++ *//***************************************************************************/
++#include "std_ext.h"
++#include "error_ext.h"
++#include "string_ext.h"
++#include "debug_ext.h"
++#include "fm_pcd_ext.h"
++#include "fm_port_ext.h"
++#include "fm_muram_ext.h"
++#include "memcpy_ext.h"
++
++#include "fm_common.h"
++#include "fm_hc.h"
++#include "fm_manip.h"
++
++/****************************************/
++/*       static functions               */
++/****************************************/
++static t_Handle GetManipInfo(t_FmPcdManip *p_Manip, e_ManipInfo manipInfo)
++{
++    t_FmPcdManip *p_CurManip = p_Manip;
++
++    if (!MANIP_IS_UNIFIED(p_Manip))
++        p_CurManip = p_Manip;
++    else
++    {
++        /* go to first unified */
++        while (MANIP_IS_UNIFIED_NON_FIRST(p_CurManip))
++            p_CurManip = p_CurManip->h_PrevManip;
++    }
++
++    switch (manipInfo)
++    {
++        case (e_MANIP_HMCT):
++            return p_CurManip->p_Hmct;
++        case (e_MANIP_HMTD):
++            return p_CurManip->h_Ad;
++        case (e_MANIP_HANDLER_TABLE_OWNER):
++            return (t_Handle)p_CurManip;
++        default:
++            return NULL;
++    }
++}
++
++static uint16_t GetHmctSize(t_FmPcdManip *p_Manip)
++{
++    uint16_t size = 0;
++    t_FmPcdManip *p_CurManip = p_Manip;
++
++    if (!MANIP_IS_UNIFIED(p_Manip))
++        return p_Manip->tableSize;
++
++    /* accumulate sizes, starting with the first node */
++    while (MANIP_IS_UNIFIED_NON_FIRST(p_CurManip))
++        p_CurManip = p_CurManip->h_PrevManip;
++
++    while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip))
++    {
++        size += p_CurManip->tableSize;
++        p_CurManip = (t_FmPcdManip *)p_CurManip->h_NextManip;
++    }
++    size += p_CurManip->tableSize; /* add last size */
++
++    return (size);
++}
++
++static uint16_t GetDataSize(t_FmPcdManip *p_Manip)
++{
++    uint16_t size = 0;
++    t_FmPcdManip *p_CurManip = p_Manip;
++
++    if (!MANIP_IS_UNIFIED(p_Manip))
++        return p_Manip->dataSize;
++
++    /* accumulate sizes, starting with the first node */
++    while (MANIP_IS_UNIFIED_NON_FIRST(p_CurManip))
++        p_CurManip = p_CurManip->h_PrevManip;
++
++    while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip))
++    {
++        size += p_CurManip->dataSize;
++        p_CurManip = (t_FmPcdManip *)p_CurManip->h_NextManip;
++    }
++    size += p_CurManip->dataSize; /* add last size */
++
++    return (size);
++}
++
++static t_Error CalculateTableSize(t_FmPcdManipParams *p_FmPcdManipParams,
++                                  uint16_t *p_TableSize, uint8_t *p_DataSize)
++{
++    uint8_t localDataSize, remain, tableSize = 0, dataSize = 0;
++
++    if (p_FmPcdManipParams->u.hdr.rmv)
++    {
++        switch (p_FmPcdManipParams->u.hdr.rmvParams.type)
++        {
++            case (e_FM_PCD_MANIP_RMV_GENERIC):
++                tableSize += HMCD_BASIC_SIZE;
++                break;
++            case (e_FM_PCD_MANIP_RMV_BY_HDR):
++                switch (p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.type)
++                {
++                    case (e_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2):
++#if (DPAA_VERSION >= 11)
++                    case (e_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP):
++                    case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START):
++#endif /* (DPAA_VERSION >= 11) */
++                        tableSize += HMCD_BASIC_SIZE;
++                        break;
++                    default:
++                        RETURN_ERROR(MINOR, E_INVALID_SELECTION,
++                                     ("Unknown byHdr.type"));
++                }
++                break;
++            default:
++                RETURN_ERROR(MINOR, E_INVALID_SELECTION,
++                             ("Unknown rmvParams.type"));
++        }
++    }
++
++    if (p_FmPcdManipParams->u.hdr.insrt)
++    {
++        switch (p_FmPcdManipParams->u.hdr.insrtParams.type)
++        {
++            case (e_FM_PCD_MANIP_INSRT_GENERIC):
++                remain =
++                        (uint8_t)(p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size
++                                % 4);
++                if (remain)
++                    localDataSize =
++                            (uint8_t)(p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size
++                                    + 4 - remain);
++                else
++                    localDataSize =
++                            p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size;
++                tableSize += (uint8_t)(HMCD_BASIC_SIZE + localDataSize);
++                break;
++            case (e_FM_PCD_MANIP_INSRT_BY_HDR):
++            {
++                switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.type)
++                {
++
++                    case (e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2):
++                        tableSize += HMCD_BASIC_SIZE + HMCD_PTR_SIZE;
++                        switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.specificL2)
++                        {
++                            case (e_FM_PCD_MANIP_HDR_INSRT_MPLS):
++                            case (e_FM_PCD_MANIP_HDR_INSRT_PPPOE):
++                                dataSize +=
++                                        p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.size;
++                                break;
++                            default:
++                                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++                        }
++                        break;
++#if (DPAA_VERSION >= 11)
++                    case (e_FM_PCD_MANIP_INSRT_BY_HDR_IP):
++                        tableSize +=
++                                (HMCD_BASIC_SIZE + HMCD_PTR_SIZE
++                                        + HMCD_PARAM_SIZE
++                                        + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size);
++                        dataSize += 2;
++                        break;
++
++                    case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP):
++                    case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE):
++                        tableSize += (HMCD_BASIC_SIZE + HMCD_L4_HDR_SIZE);
++
++                        break;
++
++                    case (e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP):
++                        tableSize +=
++                                (HMCD_BASIC_SIZE
++                                        + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size);
++                        break;
++#endif /* (DPAA_VERSION >= 11) */
++                    default:
++                        RETURN_ERROR(MINOR, E_INVALID_SELECTION,
++                                     ("Unknown byHdr.type"));
++                }
++            }
++                break;
++            default:
++                RETURN_ERROR(MINOR, E_INVALID_SELECTION,
++                             ("Unknown insrtParams.type"));
++        }
++    }
++
++    if (p_FmPcdManipParams->u.hdr.fieldUpdate)
++    {
++        switch (p_FmPcdManipParams->u.hdr.fieldUpdateParams.type)
++        {
++            case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN):
++                tableSize += HMCD_BASIC_SIZE;
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType
++                        == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN)
++                {
++                    tableSize += HMCD_PTR_SIZE;
++                    dataSize += DSCP_TO_VLAN_TABLE_SIZE;
++                }
++                break;
++            case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4):
++                tableSize += HMCD_BASIC_SIZE;
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
++                        & HDR_MANIP_IPV4_ID)
++                {
++                    tableSize += HMCD_PARAM_SIZE;
++                    dataSize += 2;
++                }
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
++                        & HDR_MANIP_IPV4_SRC)
++                    tableSize += HMCD_IPV4_ADDR_SIZE;
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
++                        & HDR_MANIP_IPV4_DST)
++                    tableSize += HMCD_IPV4_ADDR_SIZE;
++                break;
++            case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6):
++                tableSize += HMCD_BASIC_SIZE;
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
++                        & HDR_MANIP_IPV6_SRC)
++                    tableSize += HMCD_IPV6_ADDR_SIZE;
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
++                        & HDR_MANIP_IPV6_DST)
++                    tableSize += HMCD_IPV6_ADDR_SIZE;
++                break;
++            case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP):
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates
++                        == HDR_MANIP_TCP_UDP_CHECKSUM)
++                    /* we implement this case with the update-checksum descriptor */
++                    tableSize += HMCD_BASIC_SIZE;
++                else
++                    /* we implement this case with the TCP/UDP-update descriptor */
++                    tableSize += HMCD_BASIC_SIZE + HMCD_PARAM_SIZE;
++                break;
++            default:
++                RETURN_ERROR(MINOR, E_INVALID_SELECTION,
++                             ("Unknown fieldUpdateParams.type"));
++        }
++    }
++
++    if (p_FmPcdManipParams->u.hdr.custom)
++    {
++        switch (p_FmPcdManipParams->u.hdr.customParams.type)
++        {
++            case (e_FM_PCD_MANIP_HDR_CUSTOM_IP_REPLACE):
++            {
++                tableSize += HMCD_BASIC_SIZE + HMCD_PARAM_SIZE + HMCD_PARAM_SIZE;
++                dataSize +=
++                        p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.hdrSize;
++                if ((p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType
++                        == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4)
++                        && (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.updateIpv4Id))
++                    dataSize += 2;
++            }
++                break;
++            case (e_FM_PCD_MANIP_HDR_CUSTOM_GEN_FIELD_REPLACE):
++                tableSize += HMCD_BASIC_SIZE + HMCD_PARAM_SIZE;
++            break;
++            default:
++                RETURN_ERROR(MINOR, E_INVALID_SELECTION,
++                             ("Unknown customParams.type"));
++        }
++    }
++
++    *p_TableSize = tableSize;
++    *p_DataSize = dataSize;
++
++    return E_OK;
++}
++
++static t_Error GetPrOffsetByHeaderOrField(t_FmManipHdrInfo *p_HdrInfo,
++                                          uint8_t *parseArrayOffset)
++{
++    e_NetHeaderType hdr = p_HdrInfo->hdr;
++    e_FmPcdHdrIndex hdrIndex = p_HdrInfo->hdrIndex;
++    bool byField = p_HdrInfo->byField;
++    t_FmPcdFields field;
++
++    if (byField)
++        field = p_HdrInfo->fullField;
++
++    if (byField)
++    {
++        switch (hdr)
++        {
++            case (HEADER_TYPE_ETH):
++                switch (field.eth)
++                {
++                    case (NET_HEADER_FIELD_ETH_TYPE):
++                        *parseArrayOffset = CC_PC_PR_ETYPE_LAST_OFFSET;
++                        break;
++                    default:
++                        RETURN_ERROR(
++                                MAJOR,
++                                E_NOT_SUPPORTED,
++                                ("Header manipulation of the type Ethernet with this field not supported"));
++                }
++                break;
++            case (HEADER_TYPE_VLAN):
++                switch (field.vlan)
++                {
++                    case (NET_HEADER_FIELD_VLAN_TCI):
++                        if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE)
++                                || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
++                            *parseArrayOffset = CC_PC_PR_VLAN1_OFFSET;
++                        else
++                            if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
++                                *parseArrayOffset = CC_PC_PR_VLAN2_OFFSET;
++                        break;
++                    default:
++                        RETURN_ERROR(
++                                MAJOR,
++                                E_NOT_SUPPORTED,
++                                ("Header manipulation of the type VLAN with this field not supported"));
++                }
++                break;
++            default:
++                RETURN_ERROR(
++                        MAJOR,
++                        E_NOT_SUPPORTED,
++                        ("Header manipulation of this header by field not supported"));
++        }
++    }
++    else
++    {
++        switch (hdr)
++        {
++            case (HEADER_TYPE_ETH):
++                *parseArrayOffset = (uint8_t)CC_PC_PR_ETH_OFFSET;
++                break;
++            case (HEADER_TYPE_USER_DEFINED_SHIM1):
++                *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM1_OFFSET;
++                break;
++            case (HEADER_TYPE_USER_DEFINED_SHIM2):
++                *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM2_OFFSET;
++                break;
++            case (HEADER_TYPE_LLC_SNAP):
++                *parseArrayOffset = CC_PC_PR_USER_LLC_SNAP_OFFSET;
++                break;
++            case (HEADER_TYPE_PPPoE):
++                *parseArrayOffset = CC_PC_PR_PPPOE_OFFSET;
++                break;
++            case (HEADER_TYPE_MPLS):
++                if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE)
++                        || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
++                    *parseArrayOffset = CC_PC_PR_MPLS1_OFFSET;
++                else
++                    if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
++                        *parseArrayOffset = CC_PC_PR_MPLS_LAST_OFFSET;
++                break;
++            case (HEADER_TYPE_IPv4):
++            case (HEADER_TYPE_IPv6):
++                if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE)
++                        || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
++                    *parseArrayOffset = CC_PC_PR_IP1_OFFSET;
++                else
++                    if (hdrIndex == e_FM_PCD_HDR_INDEX_2)
++                        *parseArrayOffset = CC_PC_PR_IP_LAST_OFFSET;
++                break;
++            case (HEADER_TYPE_MINENCAP):
++                *parseArrayOffset = CC_PC_PR_MINENC_OFFSET;
++                break;
++            case (HEADER_TYPE_GRE):
++                *parseArrayOffset = CC_PC_PR_GRE_OFFSET;
++                break;
++            case (HEADER_TYPE_TCP):
++            case (HEADER_TYPE_UDP):
++            case (HEADER_TYPE_IPSEC_AH):
++            case (HEADER_TYPE_IPSEC_ESP):
++            case (HEADER_TYPE_DCCP):
++            case (HEADER_TYPE_SCTP):
++                *parseArrayOffset = CC_PC_PR_L4_OFFSET;
++                break;
++            case (HEADER_TYPE_CAPWAP):
++            case (HEADER_TYPE_CAPWAP_DTLS):
++                *parseArrayOffset = CC_PC_PR_NEXT_HEADER_OFFSET;
++                break;
++            default:
++                RETURN_ERROR(
++                        MAJOR,
++                        E_NOT_SUPPORTED,
++                        ("Header manipulation of this header is not supported"));
++        }
++    }
++    return E_OK;
++}
++
++static t_Error BuildHmct(t_FmPcdManip *p_Manip,
++                         t_FmPcdManipParams *p_FmPcdManipParams,
++                         uint8_t *p_DestHmct, uint8_t *p_DestData, bool new)
++{
++    uint32_t *p_TmpHmct = (uint32_t*)p_DestHmct, *p_LocalData;
++    uint32_t tmpReg = 0, *p_Last = NULL, tmp_ipv6_addr;
++    uint8_t remain, i, size = 0, origSize, *p_UsrData = NULL, *p_TmpData =
++            p_DestData;
++    t_Handle h_FmPcd = p_Manip->h_FmPcd;
++    uint8_t j = 0;
++
++    if (p_FmPcdManipParams->u.hdr.rmv)
++    {
++        if (p_FmPcdManipParams->u.hdr.rmvParams.type
++                == e_FM_PCD_MANIP_RMV_GENERIC)
++        {
++            /* initialize HMCD */
++            tmpReg = (uint32_t)(HMCD_OPCODE_GENERIC_RMV) << HMCD_OC_SHIFT;
++            /* tmp, should be conditional */
++            tmpReg |= p_FmPcdManipParams->u.hdr.rmvParams.u.generic.offset
++                    << HMCD_RMV_OFFSET_SHIFT;
++            tmpReg |= p_FmPcdManipParams->u.hdr.rmvParams.u.generic.size
++                    << HMCD_RMV_SIZE_SHIFT;
++        }
++        else
++            if (p_FmPcdManipParams->u.hdr.rmvParams.type
++                    == e_FM_PCD_MANIP_RMV_BY_HDR)
++            {
++                switch (p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.type)
++                {
++                    case (e_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2):
++                    {
++                        uint8_t hmcdOpt;
++
++                        /* initialize HMCD */
++                        tmpReg = (uint32_t)(HMCD_OPCODE_L2_RMV) << HMCD_OC_SHIFT;
++
++                        switch (p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.u.specificL2)
++                        {
++                            case (e_FM_PCD_MANIP_HDR_RMV_ETHERNET):
++                                hmcdOpt = HMCD_RMV_L2_ETHERNET;
++                                break;
++                            case (e_FM_PCD_MANIP_HDR_RMV_STACKED_QTAGS):
++                                hmcdOpt = HMCD_RMV_L2_STACKED_QTAGS;
++                                break;
++                            case (e_FM_PCD_MANIP_HDR_RMV_ETHERNET_AND_MPLS):
++                                hmcdOpt = HMCD_RMV_L2_ETHERNET_AND_MPLS;
++                                break;
++                            case (e_FM_PCD_MANIP_HDR_RMV_MPLS):
++                                hmcdOpt = HMCD_RMV_L2_MPLS;
++                                break;
++                            case (e_FM_PCD_MANIP_HDR_RMV_PPPOE):
++                                hmcdOpt = HMCD_RMV_L2_PPPOE;
++                                break;
++                            default:
++                                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++                        }
++                        tmpReg |= hmcdOpt << HMCD_L2_MODE_SHIFT;
++                        break;
++                    }
++#if (DPAA_VERSION >= 11)
++                    case (e_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP):
++                        tmpReg = (uint32_t)(HMCD_OPCODE_CAPWAP_RMV)
++                                << HMCD_OC_SHIFT;
++                        break;
++                    case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START):
++                    {
++                        uint8_t prsArrayOffset;
++                        t_Error err = E_OK;
++
++                        tmpReg = (uint32_t)(HMCD_OPCODE_RMV_TILL)
++                                << HMCD_OC_SHIFT;
++
++                        err =
++                                GetPrOffsetByHeaderOrField(
++                                        &p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.u.hdrInfo,
++                                        &prsArrayOffset);
++                        ASSERT_COND(!err);
++                        /* was previously checked */
++
++                        tmpReg |= ((uint32_t)prsArrayOffset << 16);
++                    }
++                        break;
++#endif /* (DPAA_VERSION >= 11) */
++                    default:
++                        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                                     ("manip header remove by hdr type!"));
++                }
++            }
++
++        WRITE_UINT32(*p_TmpHmct, tmpReg);
++        /* save a pointer to the "last" indication word */
++        p_Last = p_TmpHmct;
++        /* advance to next command */
++        p_TmpHmct += HMCD_BASIC_SIZE / 4;
++    }
++
++    if (p_FmPcdManipParams->u.hdr.insrt)
++    {
++        if (p_FmPcdManipParams->u.hdr.insrtParams.type
++                == e_FM_PCD_MANIP_INSRT_GENERIC)
++        {
++            /* initialize HMCD */
++            if (p_FmPcdManipParams->u.hdr.insrtParams.u.generic.replace)
++                tmpReg = (uint32_t)(HMCD_OPCODE_GENERIC_REPLACE)
++                        << HMCD_OC_SHIFT;
++            else
++                tmpReg = (uint32_t)(HMCD_OPCODE_GENERIC_INSRT) << HMCD_OC_SHIFT;
++
++            tmpReg |= p_FmPcdManipParams->u.hdr.insrtParams.u.generic.offset
++                    << HMCD_INSRT_OFFSET_SHIFT;
++            tmpReg |= p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size
++                    << HMCD_INSRT_SIZE_SHIFT;
++
++            size = p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size;
++            p_UsrData = p_FmPcdManipParams->u.hdr.insrtParams.u.generic.p_Data;
++
++            WRITE_UINT32(*p_TmpHmct, tmpReg);
++            /* save a pointer to the "last" indication word */
++            p_Last = p_TmpHmct;
++
++            p_TmpHmct += HMCD_BASIC_SIZE / 4;
++
++            /* initialize data to be inserted */
++            /* if size is not a multiple of 4, padd with 0's */
++            origSize = size;
++            remain = (uint8_t)(size % 4);
++            if (remain)
++            {
++                size += (uint8_t)(4 - remain);
++                p_LocalData = (uint32_t *)XX_Malloc(size);
++                memset((uint8_t *)p_LocalData, 0, size);
++                memcpy((uint8_t *)p_LocalData, p_UsrData, origSize);
++            }
++            else
++                p_LocalData = (uint32_t*)p_UsrData;
++
++            /* initialize data and advance pointer to next command */
++            MemCpy8(p_TmpHmct, p_LocalData, size);
++            p_TmpHmct += size / sizeof(uint32_t);
++
++            if (remain)
++                XX_Free(p_LocalData);
++        }
++
++        else
++            if (p_FmPcdManipParams->u.hdr.insrtParams.type
++                    == e_FM_PCD_MANIP_INSRT_BY_HDR)
++            {
++                switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.type)
++                {
++                    case (e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2):
++                    {
++                        uint8_t hmcdOpt;
++
++                        /* initialize HMCD */
++                        tmpReg = (uint32_t)(HMCD_OPCODE_L2_INSRT)
++                                << HMCD_OC_SHIFT;
++
++                        switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.specificL2)
++                        {
++                            case (e_FM_PCD_MANIP_HDR_INSRT_MPLS):
++                                if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.update)
++                                    hmcdOpt = HMCD_INSRT_N_UPDATE_L2_MPLS;
++                                else
++                                    hmcdOpt = HMCD_INSRT_L2_MPLS;
++                                break;
++                            case (e_FM_PCD_MANIP_HDR_INSRT_PPPOE):
++                                hmcdOpt = HMCD_INSRT_L2_PPPOE;
++                                break;
++                            default:
++                                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++                        }
++                        tmpReg |= hmcdOpt << HMCD_L2_MODE_SHIFT;
++
++                        WRITE_UINT32(*p_TmpHmct, tmpReg);
++                        /* save a pointer to the "last" indication word */
++                        p_Last = p_TmpHmct;
++
++                        p_TmpHmct += HMCD_BASIC_SIZE / 4;
++
++                        /* set size and pointer of user's data */
++                        size =
++                                (uint8_t)p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.size;
++
++                        ASSERT_COND(p_TmpData);
++                        MemCpy8(
++                                p_TmpData,
++                                p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.p_Data,
++                                size);
++                        tmpReg =
++                                (size << HMCD_INSRT_L2_SIZE_SHIFT)
++                                        | (uint32_t)(XX_VirtToPhys(p_TmpData)
++                                                - (((t_FmPcd*)h_FmPcd)->physicalMuramBase));
++                        WRITE_UINT32(*p_TmpHmct, tmpReg);
++                        p_TmpHmct += HMCD_PTR_SIZE / 4;
++                        p_TmpData += size;
++                    }
++                        break;
++#if (DPAA_VERSION >= 11)
++                    case (e_FM_PCD_MANIP_INSRT_BY_HDR_IP):
++                        tmpReg = (uint32_t)(HMCD_OPCODE_IP_INSRT)
++                                << HMCD_OC_SHIFT;
++                        if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.calcL4Checksum)
++                            tmpReg |= HMCD_IP_L4_CS_CALC;
++                        if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.mappingMode
++                                == e_FM_PCD_MANIP_HDR_QOS_MAPPING_AS_IS)
++                            tmpReg |= HMCD_IP_OR_QOS;
++                        tmpReg |=
++                                p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.lastPidOffset
++                                        & HMCD_IP_LAST_PID_MASK;
++                        tmpReg |=
++                                ((p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size
++                                        << HMCD_IP_SIZE_SHIFT)
++                                        & HMCD_IP_SIZE_MASK);
++                        if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.dontFragOverwrite)
++                            tmpReg |= HMCD_IP_DF_MODE;
++
++                        WRITE_UINT32(*p_TmpHmct, tmpReg);
++
++                        /* save a pointer to the "last" indication word */
++                        p_Last = p_TmpHmct;
++
++                        p_TmpHmct += HMCD_BASIC_SIZE / 4;
++
++                        /* set IP id */
++                        ASSERT_COND(p_TmpData);
++                        WRITE_UINT16(
++                                *(uint16_t*)p_TmpData,
++                                p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.id);
++                        WRITE_UINT32(
++                                *p_TmpHmct,
++                                (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase)));
++                        p_TmpData += 2;
++                        p_TmpHmct += HMCD_PTR_SIZE / 4;
++
++                        WRITE_UINT8(*p_TmpHmct, p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.lastDstOffset);
++                        p_TmpHmct += HMCD_PARAM_SIZE / 4;
++
++                        MemCpy8(
++                                p_TmpHmct,
++                                p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.p_Data,
++                                p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size);
++                        p_TmpHmct +=
++                                p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size
++                                        / 4;
++                        break;
++                    case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE):
++                        tmpReg = HMCD_INSRT_UDP_LITE;
++                    case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP):
++                        tmpReg |= (uint32_t)(HMCD_OPCODE_UDP_INSRT)
++                                << HMCD_OC_SHIFT;
++
++                        WRITE_UINT32(*p_TmpHmct, tmpReg);
++
++                        /* save a pointer to the "last" indication word */
++                        p_Last = p_TmpHmct;
++
++                        p_TmpHmct += HMCD_BASIC_SIZE / 4;
++
++                        MemCpy8(
++                                p_TmpHmct,
++                                p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.p_Data,
++                                p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size);
++                        p_TmpHmct +=
++                                p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size
++                                        / 4;
++                        break;
++                    case (e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP):
++                        tmpReg = (uint32_t)(HMCD_OPCODE_CAPWAP_INSRT)
++                                << HMCD_OC_SHIFT;
++                        tmpReg |= HMCD_CAPWAP_INSRT;
++
++                        WRITE_UINT32(*p_TmpHmct, tmpReg);
++
++                        /* save a pointer to the "last" indication word */
++                        p_Last = p_TmpHmct;
++
++                        p_TmpHmct += HMCD_BASIC_SIZE / 4;
++
++                        MemCpy8(
++                                p_TmpHmct,
++                                p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.p_Data,
++                                p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size);
++                        p_TmpHmct +=
++                                p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size
++                                        / 4;
++                        break;
++#endif /* (DPAA_VERSION >= 11) */
++                    default:
++                        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                                     ("manip header insert by header type!"));
++
++                }
++            }
++    }
++
++    if (p_FmPcdManipParams->u.hdr.fieldUpdate)
++    {
++        switch (p_FmPcdManipParams->u.hdr.fieldUpdateParams.type)
++        {
++            case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN):
++                /* set opcode */
++                tmpReg = (uint32_t)(HMCD_OPCODE_VLAN_PRI_UPDATE)
++                        << HMCD_OC_SHIFT;
++
++                /* set mode & table pointer */
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType
++                        == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN)
++                {
++                    /* set Mode */
++                    tmpReg |= (uint32_t)(HMCD_VLAN_PRI_UPDATE_DSCP_TO_VPRI)
++                            << HMCD_VLAN_PRI_REP_MODE_SHIFT;
++                    /* set VPRI default */
++                    tmpReg |=
++                            p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.vpriDefVal;
++                    WRITE_UINT32(*p_TmpHmct, tmpReg);
++                    /* save a pointer to the "last" indication word */
++                    p_Last = p_TmpHmct;
++                    /* write the table pointer into the Manip descriptor */
++                    p_TmpHmct += HMCD_BASIC_SIZE / 4;
++
++                    tmpReg = 0;
++                    ASSERT_COND(p_TmpData);
++                    for (i = 0; i < HMCD_DSCP_VALUES; i++)
++                    {
++                        /* first we build from each 8 values a 32bit register */
++                        tmpReg |=
++                                (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.dscpToVpriTable[i])
++                                        << (32 - 4 * (j + 1));
++                        j++;
++                        /* Than we write this register to the next table word
++                         * (i=7-->word 0, i=15-->word 1,... i=63-->word 7) */
++                        if ((i % 8) == 7)
++                        {
++                            WRITE_UINT32(*((uint32_t*)p_TmpData + (i+1)/8-1),
++                                         tmpReg);
++                            tmpReg = 0;
++                            j = 0;
++                        }
++                    }
++
++                    WRITE_UINT32(
++                            *p_TmpHmct,
++                            (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)h_FmPcd)->physicalMuramBase)));
++                    p_TmpHmct += HMCD_PTR_SIZE / 4;
++
++                    p_TmpData += DSCP_TO_VLAN_TABLE_SIZE;
++                }
++                else
++                    if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType
++                            == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_VPRI)
++                    {
++                        /* set Mode */
++                        /* line commented out as it has no-side-effect ('0' value). */
++                        /*tmpReg |= HMCD_VLAN_PRI_UPDATE << HMCD_VLAN_PRI_REP_MODE_SHIFT*/;
++                        /* set VPRI parameter */
++                        tmpReg |=
++                                p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.u.vpri;
++                        WRITE_UINT32(*p_TmpHmct, tmpReg);
++                        /* save a pointer to the "last" indication word */
++                        p_Last = p_TmpHmct;
++                        p_TmpHmct += HMCD_BASIC_SIZE / 4;
++                    }
++                break;
++
++            case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4):
++                /* set opcode */
++                tmpReg = (uint32_t)(HMCD_OPCODE_IPV4_UPDATE) << HMCD_OC_SHIFT;
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
++                        & HDR_MANIP_IPV4_TTL)
++                    tmpReg |= HMCD_IPV4_UPDATE_TTL;
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
++                        & HDR_MANIP_IPV4_TOS)
++                {
++                    tmpReg |= HMCD_IPV4_UPDATE_TOS;
++                    tmpReg |=
++                            p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.tos
++                                    << HMCD_IPV4_UPDATE_TOS_SHIFT;
++                }
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
++                        & HDR_MANIP_IPV4_ID)
++                    tmpReg |= HMCD_IPV4_UPDATE_ID;
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
++                        & HDR_MANIP_IPV4_SRC)
++                    tmpReg |= HMCD_IPV4_UPDATE_SRC;
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
++                        & HDR_MANIP_IPV4_DST)
++                    tmpReg |= HMCD_IPV4_UPDATE_DST;
++                /* write the first 4 bytes of the descriptor */
++                WRITE_UINT32(*p_TmpHmct, tmpReg);
++                /* save a pointer to the "last" indication word */
++                p_Last = p_TmpHmct;
++
++                p_TmpHmct += HMCD_BASIC_SIZE / 4;
++
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
++                        & HDR_MANIP_IPV4_ID)
++                {
++                    ASSERT_COND(p_TmpData);
++                    WRITE_UINT16(
++                            *(uint16_t*)p_TmpData,
++                            p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.id);
++                    WRITE_UINT32(
++                            *p_TmpHmct,
++                            (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase)));
++                    p_TmpData += 2;
++                    p_TmpHmct += HMCD_PTR_SIZE / 4;
++                }
++
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
++                        & HDR_MANIP_IPV4_SRC)
++                {
++                    WRITE_UINT32(
++                            *p_TmpHmct,
++                            p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.src);
++                    p_TmpHmct += HMCD_IPV4_ADDR_SIZE / 4;
++                }
++
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
++                        & HDR_MANIP_IPV4_DST)
++                {
++                    WRITE_UINT32(
++                            *p_TmpHmct,
++                            p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.dst);
++                    p_TmpHmct += HMCD_IPV4_ADDR_SIZE / 4;
++                }
++                break;
++
++            case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6):
++                /* set opcode */
++                tmpReg = (uint32_t)(HMCD_OPCODE_IPV6_UPDATE) << HMCD_OC_SHIFT;
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates
++                        & HDR_MANIP_IPV6_HL)
++                    tmpReg |= HMCD_IPV6_UPDATE_HL;
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates
++                        & HDR_MANIP_IPV6_TC)
++                {
++                    tmpReg |= HMCD_IPV6_UPDATE_TC;
++                    tmpReg |=
++                            p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.trafficClass
++                                    << HMCD_IPV6_UPDATE_TC_SHIFT;
++                }
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates
++                        & HDR_MANIP_IPV6_SRC)
++                    tmpReg |= HMCD_IPV6_UPDATE_SRC;
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates
++                        & HDR_MANIP_IPV6_DST)
++                    tmpReg |= HMCD_IPV6_UPDATE_DST;
++                /* write the first 4 bytes of the descriptor */
++                WRITE_UINT32(*p_TmpHmct, tmpReg);
++                /* save a pointer to the "last" indication word */
++                p_Last = p_TmpHmct;
++
++                p_TmpHmct += HMCD_BASIC_SIZE / 4;
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates
++                        & HDR_MANIP_IPV6_SRC)
++                {
++                    for (i = 0; i < NET_HEADER_FIELD_IPv6_ADDR_SIZE; i += 4)
++                    {
++                        memcpy(&tmp_ipv6_addr,
++                               &p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.src[i],
++                               sizeof(uint32_t));
++                        WRITE_UINT32(*p_TmpHmct, tmp_ipv6_addr);
++                        p_TmpHmct += HMCD_PTR_SIZE / 4;
++                    }
++                }
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates
++                        & HDR_MANIP_IPV6_DST)
++                {
++                    for (i = 0; i < NET_HEADER_FIELD_IPv6_ADDR_SIZE; i += 4)
++                    {
++                        memcpy(&tmp_ipv6_addr,
++                               &p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.dst[i],
++                               sizeof(uint32_t));
++                        WRITE_UINT32(*p_TmpHmct, tmp_ipv6_addr);
++                        p_TmpHmct += HMCD_PTR_SIZE / 4;
++                    }
++                }
++                break;
++
++            case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP):
++                if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates
++                        == HDR_MANIP_TCP_UDP_CHECKSUM)
++                {
++                    /* we implement this case with the update-checksum descriptor */
++                    /* set opcode */
++                    tmpReg = (uint32_t)(HMCD_OPCODE_TCP_UDP_CHECKSUM)
++                            << HMCD_OC_SHIFT;
++                    /* write the first 4 bytes of the descriptor */
++                    WRITE_UINT32(*p_TmpHmct, tmpReg);
++                    /* save a pointer to the "last" indication word */
++                    p_Last = p_TmpHmct;
++
++                    p_TmpHmct += HMCD_BASIC_SIZE / 4;
++                }
++                else
++                {
++                    /* we implement this case with the TCP/UDP update descriptor */
++                    /* set opcode */
++                    tmpReg = (uint32_t)(HMCD_OPCODE_TCP_UDP_UPDATE)
++                            << HMCD_OC_SHIFT;
++                    if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates
++                            & HDR_MANIP_TCP_UDP_DST)
++                        tmpReg |= HMCD_TCP_UDP_UPDATE_DST;
++                    if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates
++                            & HDR_MANIP_TCP_UDP_SRC)
++                        tmpReg |= HMCD_TCP_UDP_UPDATE_SRC;
++                    /* write the first 4 bytes of the descriptor */
++                    WRITE_UINT32(*p_TmpHmct, tmpReg);
++                    /* save a pointer to the "last" indication word */
++                    p_Last = p_TmpHmct;
++
++                    p_TmpHmct += HMCD_BASIC_SIZE / 4;
++
++                    tmpReg = 0;
++                    if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates
++                            & HDR_MANIP_TCP_UDP_SRC)
++                        tmpReg |=
++                                ((uint32_t)p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.src)
++                                        << HMCD_TCP_UDP_UPDATE_SRC_SHIFT;
++                    if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates
++                            & HDR_MANIP_TCP_UDP_DST)
++                        tmpReg |=
++                                ((uint32_t)p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.dst);
++                    WRITE_UINT32(*p_TmpHmct, tmpReg);
++                    p_TmpHmct += HMCD_PTR_SIZE / 4;
++                }
++                break;
++
++            default:
++                RETURN_ERROR(MINOR, E_INVALID_SELECTION,
++                             ("Unknown fieldUpdateParams.type"));
++        }
++    }
++
++    if (p_FmPcdManipParams->u.hdr.custom)
++    {
++        switch (p_FmPcdManipParams->u.hdr.customParams.type)
++        {
++            case (e_FM_PCD_MANIP_HDR_CUSTOM_IP_REPLACE):
++                /* set opcode */
++                tmpReg = (uint32_t)(HMCD_OPCODE_REPLACE_IP) << HMCD_OC_SHIFT;
++
++                if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.decTtlHl)
++                    tmpReg |= HMCD_IP_REPLACE_TTL_HL;
++                if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType
++                        == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV4_BY_IPV6)
++                    /* line commented out as it has no-side-effect ('0' value). */
++                    /*tmpReg |= HMCD_IP_REPLACE_REPLACE_IPV4*/;
++                else
++                    if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType
++                            == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4)
++                    {
++                        tmpReg |= HMCD_IP_REPLACE_REPLACE_IPV6;
++                        if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.updateIpv4Id)
++                            tmpReg |= HMCD_IP_REPLACE_ID;
++                    }
++                    else
++                        RETURN_ERROR(
++                                MINOR,
++                                E_NOT_SUPPORTED,
++                                ("One flag out of HDR_MANIP_IP_REPLACE_IPV4, HDR_MANIP_IP_REPLACE_IPV6 - must be set."));
++
++                /* write the first 4 bytes of the descriptor */
++                WRITE_UINT32(*p_TmpHmct, tmpReg);
++                /* save a pointer to the "last" indication word */
++                p_Last = p_TmpHmct;
++
++                p_TmpHmct += HMCD_BASIC_SIZE / 4;
++
++                size =
++                        p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.hdrSize;
++                ASSERT_COND(p_TmpData);
++                MemCpy8(
++                        p_TmpData,
++                        p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.hdr,
++                        size);
++                tmpReg = (uint32_t)(size << HMCD_IP_REPLACE_L3HDRSIZE_SHIFT);
++                tmpReg |= (uint32_t)(XX_VirtToPhys(p_TmpData)
++                        - (((t_FmPcd*)h_FmPcd)->physicalMuramBase));
++                WRITE_UINT32(*p_TmpHmct, tmpReg);
++                p_TmpHmct += HMCD_PTR_SIZE / 4;
++                p_TmpData += size;
++
++                if ((p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType
++                        == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4)
++                        && (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.updateIpv4Id))
++                {
++                    WRITE_UINT16(
++                            *(uint16_t*)p_TmpData,
++                            p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.id);
++                    WRITE_UINT32(
++                            *p_TmpHmct,
++                            (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)h_FmPcd)->physicalMuramBase)));
++                    p_TmpData += 2;
++                }
++                p_TmpHmct += HMCD_PTR_SIZE / 4;
++                break;
++            case (e_FM_PCD_MANIP_HDR_CUSTOM_GEN_FIELD_REPLACE):
++                /* set opcode */
++                tmpReg = (uint32_t)(HMCD_OPCODE_GEN_FIELD_REPLACE) << HMCD_OC_SHIFT;
++                tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.size << HMCD_GEN_FIELD_SIZE_SHIFT;
++                tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.srcOffset << HMCD_GEN_FIELD_SRC_OFF_SHIFT;
++                tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.dstOffset << HMCD_GEN_FIELD_DST_OFF_SHIFT;
++                if (p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.mask)
++                    tmpReg |= HMCD_GEN_FIELD_MASK_EN;
++
++                /* write the first 4 bytes of the descriptor */
++                WRITE_UINT32(*p_TmpHmct, tmpReg);
++                /* save a pointer to the "last" indication word */
++                p_Last = p_TmpHmct;
++
++                p_TmpHmct += HMCD_BASIC_SIZE/4;
++
++                if (p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.mask)
++                {
++                    tmpReg = p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.mask << HMCD_GEN_FIELD_MASK_SHIFT;
++                    tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.maskOffset << HMCD_GEN_FIELD_MASK_OFF_SHIFT;
++                    /* write the next 4 bytes of the descriptor */
++                    WRITE_UINT32(*p_TmpHmct, tmpReg);
++                }
++                p_TmpHmct += HMCD_PARAM_SIZE/4;
++                break;
++            default:
++                RETURN_ERROR(MINOR, E_INVALID_SELECTION,
++                             ("Unknown customParams.type"));
++        }
++    }
++
++    /* If this node has a nextManip, and no parsing is required, the old table must be copied to the new table
++     the old table and should be freed */
++    if (p_FmPcdManipParams->h_NextManip
++            && (p_Manip->nextManipType == e_FM_PCD_MANIP_HDR)
++            && (MANIP_DONT_REPARSE(p_Manip)))
++    {
++        if (new)
++        {
++            /* If this is the first time this manip is created we need to free unused memory. If it
++             * is a dynamic changes case, the memory used is either the CC shadow or the existing
++             * table - no allocation, no free */
++            MANIP_UPDATE_UNIFIED_POSITION(p_FmPcdManipParams->h_NextManip);
++
++            p_Manip->unifiedPosition = e_MANIP_UNIFIED_FIRST;
++        }
++    }
++    else
++    {
++        ASSERT_COND(p_Last);
++        /* set the "last" indication on the last command of the current table */
++        WRITE_UINT32(*p_Last, GET_UINT32(*p_Last) | HMCD_LAST);
++    }
++
++    return E_OK;
++}
++
++static t_Error CreateManipActionNew(t_FmPcdManip *p_Manip,
++                                    t_FmPcdManipParams *p_FmPcdManipParams)
++{
++    t_FmPcdManip *p_CurManip;
++    t_Error err;
++    uint32_t nextSize = 0, totalSize;
++    uint16_t tmpReg;
++    uint8_t *p_OldHmct, *p_TmpHmctPtr, *p_TmpDataPtr;
++
++    /* set Manip structure */
++
++    p_Manip->dontParseAfterManip =
++            p_FmPcdManipParams->u.hdr.dontParseAfterManip;
++
++    if (p_FmPcdManipParams->h_NextManip)
++    {   /* Next Header manipulation exists */
++        p_Manip->nextManipType = MANIP_GET_TYPE(p_FmPcdManipParams->h_NextManip);
++
++        if ((p_Manip->nextManipType == e_FM_PCD_MANIP_HDR) && p_Manip->dontParseAfterManip)
++            nextSize = (uint32_t)(GetHmctSize(p_FmPcdManipParams->h_NextManip)
++                    + GetDataSize(p_FmPcdManipParams->h_NextManip));
++        else /* either parsing is required or next manip is Frag; no table merging. */
++            p_Manip->cascaded = TRUE;
++        /* pass up the "cascaded" attribute. The whole chain is cascaded
++         * if something is cascaded along the way. */
++        if (MANIP_IS_CASCADED(p_FmPcdManipParams->h_NextManip))
++            p_Manip->cascaded = TRUE;
++    }
++
++    /* Allocate new table */
++    /* calculate table size according to manip parameters */
++    err = CalculateTableSize(p_FmPcdManipParams, &p_Manip->tableSize,
++                             &p_Manip->dataSize);
++    if (err)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    totalSize = (uint16_t)(p_Manip->tableSize + p_Manip->dataSize + nextSize);
++
++    p_Manip->p_Hmct = (uint8_t*)FM_MURAM_AllocMem(
++            ((t_FmPcd *)p_Manip->h_FmPcd)->h_FmMuram, totalSize, 4);
++    if (!p_Manip->p_Hmct)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc failed"));
++
++    if (p_Manip->dataSize)
++        p_Manip->p_Data =
++                (uint8_t*)PTR_MOVE(p_Manip->p_Hmct, (p_Manip->tableSize + nextSize));
++
++    /* update shadow size to allow runtime replacement of Header manipulation */
++    /* The allocated shadow is divided as follows:
++     0 . . .       16 . . .
++     --------------------------------
++     |   Shadow   |   Shadow HMTD   |
++     |   HMTD     |   Match Table   |
++     | (16 bytes) | (maximal size)  |
++     --------------------------------
++     */
++
++    err = FmPcdUpdateCcShadow(p_Manip->h_FmPcd, (uint32_t)(totalSize + 16),
++                              (uint16_t)FM_PCD_CC_AD_TABLE_ALIGN);
++    if (err != E_OK)
++    {
++        FM_MURAM_FreeMem(p_Manip->h_FmPcd, p_Manip->p_Hmct);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                     ("MURAM allocation for HdrManip node shadow"));
++    }
++
++    if (p_FmPcdManipParams->h_NextManip
++            && (p_Manip->nextManipType == e_FM_PCD_MANIP_HDR)
++            && (MANIP_DONT_REPARSE(p_Manip)))
++    {
++        p_OldHmct = (uint8_t *)GetManipInfo(p_FmPcdManipParams->h_NextManip,
++                                            e_MANIP_HMCT);
++        p_CurManip = p_FmPcdManipParams->h_NextManip;
++        /* Run till the last Manip (which is the first to configure) */
++        while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip))
++            p_CurManip = p_CurManip->h_NextManip;
++
++        while (p_CurManip)
++        {
++            /* If this is a unified table, point to the part of the table
++             * which is the relative offset in HMCT.
++             */
++            p_TmpHmctPtr = (uint8_t*)PTR_MOVE(p_Manip->p_Hmct,
++                    (p_Manip->tableSize +
++                            (PTR_TO_UINT(p_CurManip->p_Hmct) -
++                                    PTR_TO_UINT(p_OldHmct))));
++            if (p_CurManip->p_Data)
++                p_TmpDataPtr = (uint8_t*)PTR_MOVE(p_Manip->p_Hmct,
++                        (p_Manip->tableSize +
++                                (PTR_TO_UINT(p_CurManip->p_Data) -
++                                        PTR_TO_UINT(p_OldHmct))));
++            else
++                p_TmpDataPtr = NULL;
++
++            BuildHmct(p_CurManip, &p_CurManip->manipParams, p_TmpHmctPtr,
++                      p_TmpDataPtr, FALSE);
++            /* update old manip table pointer */
++            MANIP_SET_HMCT_PTR(p_CurManip, p_TmpHmctPtr);
++            MANIP_SET_DATA_PTR(p_CurManip, p_TmpDataPtr);
++
++            p_CurManip = p_CurManip->h_PrevManip;
++        }
++        /* We copied the HMCT to create a new large HMCT so we can free the old one */
++        FM_MURAM_FreeMem(MANIP_GET_MURAM(p_FmPcdManipParams->h_NextManip),
++                         p_OldHmct);
++    }
++
++    /* Fill table */
++    err = BuildHmct(p_Manip, p_FmPcdManipParams, p_Manip->p_Hmct,
++                    p_Manip->p_Data, TRUE);
++    if (err)
++    {
++        FM_MURAM_FreeMem(p_Manip->h_FmPcd, p_Manip->p_Hmct);
++        RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++
++    /* Build HMTD (table descriptor) */
++     tmpReg = HMTD_CFG_TYPE; /* NADEN = 0 */
++
++     /* add parseAfterManip */
++      if (!p_Manip->dontParseAfterManip)
++          tmpReg |= HMTD_CFG_PRS_AFTER_HM;
++
++    /* create cascade */
++    /*if (p_FmPcdManipParams->h_NextManip
++            && (!MANIP_DONT_REPARSE(p_Manip) || (p_Manip->nextManipType != e_FM_PCD_MANIP_HDR)))*/
++    if (p_Manip->cascaded)
++    {
++        uint16_t nextAd;
++        /* indicate that there's another HM table descriptor */
++        tmpReg |= HMTD_CFG_NEXT_AD_EN;
++        /* get address of next HMTD (table descriptor; h_Ad).
++         * If the next HMTD was removed due to table unifing, get the address
++         * of the "next next" as written in the h_Ad of the next h_Manip node.
++         */
++        if (p_Manip->unifiedPosition != e_MANIP_UNIFIED_FIRST)
++            nextAd = (uint16_t)((uint32_t)(XX_VirtToPhys(MANIP_GET_HMTD_PTR(p_FmPcdManipParams->h_NextManip)) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase)) >> 4);
++        else
++            nextAd = ((t_Hmtd *)((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad)->nextAdIdx;
++
++        WRITE_UINT16(((t_Hmtd *)p_Manip->h_Ad)->nextAdIdx, nextAd);
++    }
++
++    WRITE_UINT16(((t_Hmtd *)p_Manip->h_Ad)->cfg, tmpReg);
++    WRITE_UINT32(
++            ((t_Hmtd *)p_Manip->h_Ad)->hmcdBasePtr,
++            (uint32_t)(XX_VirtToPhys(p_Manip->p_Hmct) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase)));
++
++    WRITE_UINT8(((t_Hmtd *)p_Manip->h_Ad)->opCode, HMAN_OC);
++
++    if (p_Manip->unifiedPosition == e_MANIP_UNIFIED_FIRST)
++    {
++        /* The HMTD of the next Manip is never going to be used */
++        if (((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->muramAllocate)
++            FM_MURAM_FreeMem(
++                    ((t_FmPcd *)((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_FmPcd)->h_FmMuram,
++                    ((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad);
++        else
++            XX_Free(((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad);
++        ((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad = NULL;
++    }
++
++    return E_OK;
++}
++
++static t_Error CreateManipActionShadow(t_FmPcdManip *p_Manip,
++                                       t_FmPcdManipParams *p_FmPcdManipParams)
++{
++    uint8_t *p_WholeHmct, *p_TmpHmctPtr, newDataSize, *p_TmpDataPtr = NULL;
++    uint16_t newSize;
++    t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd;
++    t_Error err;
++    t_FmPcdManip *p_CurManip = p_Manip;
++
++    err = CalculateTableSize(p_FmPcdManipParams, &newSize, &newDataSize);
++    if (err)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    /* check coherency of new table parameters */
++    if (newSize > p_Manip->tableSize)
++        RETURN_ERROR(
++                MINOR,
++                E_INVALID_VALUE,
++                ("New Hdr Manip configuration requires larger size than current one (command table)."));
++    if (newDataSize > p_Manip->dataSize)
++        RETURN_ERROR(
++                MINOR,
++                E_INVALID_VALUE,
++                ("New Hdr Manip configuration requires larger size than current one (data)."));
++    if (p_FmPcdManipParams->h_NextManip)
++        RETURN_ERROR(
++                MINOR, E_INVALID_VALUE,
++                ("New Hdr Manip configuration can not contain h_NextManip."));
++    if (MANIP_IS_UNIFIED(p_Manip) && (newSize != p_Manip->tableSize))
++        RETURN_ERROR(
++                MINOR,
++                E_INVALID_VALUE,
++                ("New Hdr Manip configuration in a chained manipulation requires different size than current one."));
++    if (p_Manip->dontParseAfterManip
++            != p_FmPcdManipParams->u.hdr.dontParseAfterManip)
++        RETURN_ERROR(
++                MINOR,
++                E_INVALID_VALUE,
++                ("New Hdr Manip configuration differs in dontParseAfterManip value."));
++
++    p_Manip->tableSize = newSize;
++    p_Manip->dataSize = newDataSize;
++
++    /* Build the new table in the shadow */
++    if (!MANIP_IS_UNIFIED(p_Manip))
++    {
++        p_TmpHmctPtr = (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow, 16);
++        if (p_Manip->p_Data)
++            p_TmpDataPtr =
++                    (uint8_t*)PTR_MOVE(p_TmpHmctPtr,
++                            (PTR_TO_UINT(p_Manip->p_Data) - PTR_TO_UINT(p_Manip->p_Hmct)));
++
++        BuildHmct(p_Manip, p_FmPcdManipParams, p_TmpHmctPtr, p_Manip->p_Data,
++                  FALSE);
++    }
++    else
++    {
++        p_WholeHmct = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMCT);
++        ASSERT_COND(p_WholeHmct);
++
++        /* Run till the last Manip (which is the first to configure) */
++        while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip))
++            p_CurManip = p_CurManip->h_NextManip;
++
++        while (p_CurManip)
++        {
++            /* If this is a non-head node in a unified table, point to the part of the shadow
++             * which is the relative offset in HMCT.
++             * else, point to the beginning of the
++             * shadow table (we save 16 for the HMTD.
++             */
++            p_TmpHmctPtr =
++                    (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow,
++                            (16 + PTR_TO_UINT(p_CurManip->p_Hmct) - PTR_TO_UINT(p_WholeHmct)));
++            if (p_CurManip->p_Data)
++                p_TmpDataPtr =
++                        (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow,
++                                (16 + PTR_TO_UINT(p_CurManip->p_Data) - PTR_TO_UINT(p_WholeHmct)));
++
++            BuildHmct(p_CurManip, &p_CurManip->manipParams, p_TmpHmctPtr,
++                      p_TmpDataPtr, FALSE);
++            p_CurManip = p_CurManip->h_PrevManip;
++        }
++    }
++
++    return E_OK;
++}
++
++static t_Error CreateManipActionBackToOrig(
++        t_FmPcdManip *p_Manip, t_FmPcdManipParams *p_FmPcdManipParams)
++{
++    uint8_t *p_WholeHmct = NULL, *p_TmpHmctPtr, *p_TmpDataPtr;
++    t_FmPcdManip *p_CurManip = p_Manip;
++
++    /* Build the new table in the shadow */
++    if (!MANIP_IS_UNIFIED(p_Manip))
++        BuildHmct(p_Manip, p_FmPcdManipParams, p_Manip->p_Hmct, p_Manip->p_Data,
++                  FALSE);
++    else
++    {
++        p_WholeHmct = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMCT);
++        ASSERT_COND(p_WholeHmct);
++
++        /* Run till the last Manip (which is the first to configure) */
++        while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip))
++            p_CurManip = p_CurManip->h_NextManip;
++
++        while (p_CurManip)
++        {
++            /* If this is a unified table, point to the part of the table
++             * which is the relative offset in HMCT.
++             */
++            p_TmpHmctPtr = p_CurManip->p_Hmct; /*- (uint32_t)p_WholeHmct*/
++            p_TmpDataPtr = p_CurManip->p_Data; /*- (uint32_t)p_WholeHmct*/
++
++            BuildHmct(p_CurManip, &p_CurManip->manipParams, p_TmpHmctPtr,
++                      p_TmpDataPtr, FALSE);
++
++            p_CurManip = p_CurManip->h_PrevManip;
++        }
++    }
++
++    return E_OK;
++}
++
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++static t_Error UpdateManipIc(t_Handle h_Manip, uint8_t icOffset)
++{
++    t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
++    t_Handle p_Ad;
++    uint32_t tmpReg32 = 0;
++    SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE);
++
++    switch (p_Manip->opcode)
++    {
++        case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX):
++        p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
++        if (p_Manip->updateParams & INTERNAL_CONTEXT_OFFSET)
++        {
++            tmpReg32 =
++            *(uint32_t *)&((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets;
++            tmpReg32 |= (uint32_t)((uint32_t)icOffset << 16);
++            *(uint32_t *)&((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets =
++            tmpReg32;
++            p_Manip->updateParams &= ~INTERNAL_CONTEXT_OFFSET;
++            p_Manip->icOffset = icOffset;
++        }
++        else
++        {
++            if (p_Manip->icOffset != icOffset)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("this manipulation was updated previously by different value"););
++        }
++        break;
++        case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST):
++        if (p_Manip->h_Frag)
++        {
++            if (p_Manip->updateParams & INTERNAL_CONTEXT_OFFSET)
++            {
++                p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
++                tmpReg32 |= GET_UINT32(((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets);
++                tmpReg32 |= (uint32_t)((uint32_t)icOffset << 16);
++                WRITE_UINT32(((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets, tmpReg32);
++                p_Manip->updateParams &= ~INTERNAL_CONTEXT_OFFSET;
++                p_Manip->icOffset = icOffset;
++            }
++            else
++            {
++                if (p_Manip->icOffset != icOffset)
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("this manipulation was updated previousely by different value"););
++            }
++        }
++        break;
++    }
++
++    return E_OK;
++}
++
++static t_Error UpdateInitMvIntFrameHeaderFromFrameToBufferPrefix(
++        t_Handle h_FmPort, t_FmPcdManip *p_Manip, t_Handle h_Ad, bool validate)
++{
++
++    t_AdOfTypeContLookup *p_Ad = (t_AdOfTypeContLookup *)h_Ad;
++    t_FmPortGetSetCcParams fmPortGetSetCcParams;
++    t_Error err;
++    uint32_t tmpReg32;
++
++    memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams));
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(
++            (p_Manip->opcode & HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX),
++            E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(!p_Manip->muramAllocate, E_INVALID_STATE);
++
++    if (p_Manip->updateParams)
++    {
++        if ((!(p_Manip->updateParams & OFFSET_OF_PR))
++                || (p_Manip->shadowUpdateParams & OFFSET_OF_PR))
++        RETURN_ERROR(
++                MAJOR, E_INVALID_STATE,
++                ("in this stage parameters from Port has not be updated"));
++
++        fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams;
++        fmPortGetSetCcParams.setCcParams.type = UPDATE_PSO;
++        fmPortGetSetCcParams.setCcParams.psoSize = 16;
++
++        err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
++        if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++        if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR)
++        RETURN_ERROR(
++                MAJOR, E_INVALID_STATE,
++                ("Parser result offset wasn't configured previousely"));
++#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004
++        ASSERT_COND(!(fmPortGetSetCcParams.getCcParams.prOffset % 16));
++#endif
++    }
++    else
++    if (validate)
++    {
++        if ((!(p_Manip->shadowUpdateParams & OFFSET_OF_PR))
++                || (p_Manip->updateParams & OFFSET_OF_PR))
++        RETURN_ERROR(
++                MAJOR, E_INVALID_STATE,
++                ("in this stage parameters from Port has be updated"));
++        fmPortGetSetCcParams.getCcParams.type = p_Manip->shadowUpdateParams;
++        fmPortGetSetCcParams.setCcParams.type = UPDATE_PSO;
++        fmPortGetSetCcParams.setCcParams.psoSize = 16;
++
++        err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
++        if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++        if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR)
++        RETURN_ERROR(
++                MAJOR, E_INVALID_STATE,
++                ("Parser result offset wasn't configured previousely"));
++
++    }
++
++    ASSERT_COND(p_Ad);
++
++    if (p_Manip->updateParams & OFFSET_OF_PR)
++    {
++        tmpReg32 = 0;
++        tmpReg32 |= fmPortGetSetCcParams.getCcParams.prOffset;
++        WRITE_UINT32(p_Ad->matchTblPtr,
++                (GET_UINT32(p_Ad->matchTblPtr) | tmpReg32));
++        p_Manip->updateParams &= ~OFFSET_OF_PR;
++        p_Manip->shadowUpdateParams |= OFFSET_OF_PR;
++    }
++    else
++    if (validate)
++    {
++        tmpReg32 = GET_UINT32(p_Ad->matchTblPtr);
++        if ((uint8_t)tmpReg32 != fmPortGetSetCcParams.getCcParams.prOffset)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_STATE,
++                ("this manipulation was updated previousely by different value"););
++    }
++
++    return E_OK;
++}
++
++static t_Error UpdateModifyCapwapFragmenation(t_FmPcdManip *p_Manip, t_Handle h_Ad, bool validate,t_Handle h_FmTree)
++{
++    t_AdOfTypeContLookup *p_Ad = (t_AdOfTypeContLookup *)h_Ad;
++    t_FmPcdCcSavedManipParams *p_SavedManipParams = NULL;
++    uint32_t tmpReg32 = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Manip->h_Frag,E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Manip->frag,E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(((p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION) || (p_Manip->opcode == HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER)), E_INVALID_STATE);
++
++    p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Frag;
++
++    if (p_Manip->updateParams)
++    {
++
++        if ((!(p_Manip->updateParams & OFFSET_OF_DATA)) ||
++                ((p_Manip->shadowUpdateParams & OFFSET_OF_DATA)))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has not be updated"));
++        p_SavedManipParams = FmPcdCcTreeGetSavedManipParams(h_FmTree);
++        if (!p_SavedManipParams)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("for this manipulation tree has to be configured previosely with this type"));
++        p_Manip->capwapFragParams.dataOffset = p_SavedManipParams->capwapParams.dataOffset;
++
++        tmpReg32 = GET_UINT32(p_Ad->pcAndOffsets);
++        tmpReg32 |= ((uint32_t)p_Manip->capwapFragParams.dataOffset<< 16);
++        WRITE_UINT32(p_Ad->pcAndOffsets,tmpReg32);
++
++        p_Manip->updateParams &= ~OFFSET_OF_DATA;
++        p_Manip->shadowUpdateParams |= OFFSET_OF_DATA;
++    }
++    else if (validate)
++    {
++
++        p_SavedManipParams = FmPcdCcTreeGetSavedManipParams(h_FmTree);
++        if (!p_SavedManipParams)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("for this manipulation tree has to be configured previosely with this type"));
++        if (p_Manip->capwapFragParams.dataOffset != p_SavedManipParams->capwapParams.dataOffset)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("this manipulation was updated previousely by different value"));
++    }
++
++    return E_OK;
++}
++
++static t_Error UpdateInitCapwapFragmentation(t_Handle h_FmPort,
++        t_FmPcdManip *p_Manip,
++        t_Handle h_Ad,
++        bool validate,
++        t_Handle h_FmTree)
++{
++    t_AdOfTypeContLookup *p_Ad;
++    t_FmPortGetSetCcParams fmPortGetSetCcParams;
++    t_Error err;
++    uint32_t tmpReg32 = 0;
++    t_FmPcdCcSavedManipParams *p_SavedManipParams;
++
++    UNUSED(h_Ad);
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Manip->h_Frag,E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Manip->frag,E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(((p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION) ||
++                    (p_Manip->opcode == HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER)), E_INVALID_STATE);
++
++    p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Frag;
++
++    if (p_Manip->updateParams)
++    {
++        if ((!(p_Manip->updateParams & OFFSET_OF_DATA)) ||
++                ((p_Manip->shadowUpdateParams & OFFSET_OF_DATA)))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has not be updated"));
++        fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams;
++        fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN | UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY;
++        fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL;
++        /* For CAPWAP Rassembly used FMAN_CTRL2 hardcoded - so for fragmentation its better to use FMAN_CTRL1 */
++        fmPortGetSetCcParams.setCcParams.orFmanCtrl = FPM_PORT_FM_CTL1;
++
++        err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
++        if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++        if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Data offset wasn't configured previousely"));
++
++        p_SavedManipParams = (t_FmPcdCcSavedManipParams *)XX_Malloc(sizeof(t_FmPcdCcSavedManipParams));
++        p_SavedManipParams->capwapParams.dataOffset = fmPortGetSetCcParams.getCcParams.dataOffset;
++
++#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004
++        ASSERT_COND(!(p_SavedManipParams->capwapParams.dataOffset % 16));
++#endif /* FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 */
++
++        FmPcdCcTreeSetSavedManipParams(h_FmTree, (t_Handle)p_SavedManipParams);
++    }
++    else if (validate)
++    {
++        if ((!(p_Manip->shadowUpdateParams & OFFSET_OF_DATA)) ||
++                ((p_Manip->updateParams & OFFSET_OF_DATA)))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has be updated"));
++        fmPortGetSetCcParams.getCcParams.type = p_Manip->shadowUpdateParams;
++        fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN | UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY;
++        fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL;
++        err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
++        if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++        if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Data offset wasn't configured previousely"));
++    }
++
++    if (p_Manip->updateParams)
++    {
++        tmpReg32 = GET_UINT32(p_Ad->pcAndOffsets);
++        tmpReg32 |= ((uint32_t)fmPortGetSetCcParams.getCcParams.dataOffset<< 16);
++        WRITE_UINT32(p_Ad->pcAndOffsets,tmpReg32);
++
++        p_Manip->updateParams &= ~OFFSET_OF_DATA;
++        p_Manip->shadowUpdateParams |= OFFSET_OF_DATA;
++        p_Manip->capwapFragParams.dataOffset = fmPortGetSetCcParams.getCcParams.dataOffset;
++    }
++    else if (validate)
++    {
++        if (p_Manip->capwapFragParams.dataOffset != fmPortGetSetCcParams.getCcParams.dataOffset)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("this manipulation was updated previousely by different value"));
++    }
++
++    return E_OK;
++}
++
++static t_Error UpdateInitCapwapReasm(t_Handle h_FmPcd,
++        t_Handle h_FmPort,
++        t_FmPcdManip *p_Manip,
++        t_Handle h_Ad,
++        bool validate)
++{
++    t_CapwapReasmPram *p_ReassmTbl;
++    t_Error err;
++    t_FmPortGetSetCcParams fmPortGetSetCcParams;
++    uint8_t i = 0;
++    uint16_t size;
++    uint32_t tmpReg32;
++    t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    t_FmPcdCcCapwapReassmTimeoutParams ccCapwapReassmTimeoutParams;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Manip->h_Frag,E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Manip->frag,E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Manip->opcode == HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST), E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(h_FmPcd,E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc,E_INVALID_HANDLE);
++
++    if (p_Manip->h_FmPcd != h_FmPcd)
++    RETURN_ERROR(MAJOR, E_INVALID_STATE,
++            ("handler of PCD previously was initiated by different value"));
++
++    UNUSED(h_Ad);
++
++    memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams));
++    p_ReassmTbl = (t_CapwapReasmPram *)p_Manip->h_Frag;
++
++    if (p_Manip->updateParams)
++    {
++        if ((!(p_Manip->updateParams & NUM_OF_TASKS) &&
++                        !(p_Manip->updateParams & OFFSET_OF_DATA) &&
++                        !(p_Manip->updateParams & OFFSET_OF_PR) &&
++                        !(p_Manip->updateParams & HW_PORT_ID)) ||
++                ((p_Manip->shadowUpdateParams & NUM_OF_TASKS) ||
++                        (p_Manip->shadowUpdateParams & OFFSET_OF_DATA) || (p_Manip->shadowUpdateParams & OFFSET_OF_PR) ||
++                        (p_Manip->shadowUpdateParams & HW_PORT_ID)))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has not be updated"));
++
++        fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams;
++        fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN;
++        fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL;
++
++        err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
++        if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++        if (fmPortGetSetCcParams.getCcParams.type & NUM_OF_TASKS)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Num of tasks wasn't configured previousely"));
++        if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("offset of the data  wasn't configured previousely"));
++        if (fmPortGetSetCcParams.getCcParams.type & HW_PORT_ID)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("hwPortId wasn't updated"));
++#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004
++        ASSERT_COND((fmPortGetSetCcParams.getCcParams.dataOffset % 16) == 0);
++#endif /* FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 */
++    }
++    else if (validate)
++    {
++        if ((!(p_Manip->shadowUpdateParams & NUM_OF_TASKS) &&
++                        !(p_Manip->shadowUpdateParams & OFFSET_OF_DATA) &&
++                        !(p_Manip->shadowUpdateParams & OFFSET_OF_PR) &&
++                        !(p_Manip->shadowUpdateParams & HW_PORT_ID)) &&
++                ((p_Manip->updateParams & NUM_OF_TASKS) ||
++                        (p_Manip->updateParams & OFFSET_OF_DATA) || (p_Manip->updateParams & OFFSET_OF_PR) ||
++                        (p_Manip->updateParams & HW_PORT_ID)))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has be updated"));
++
++        fmPortGetSetCcParams.getCcParams.type = p_Manip->shadowUpdateParams;
++        fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN;
++        fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL;
++
++        err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
++        if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++        if (fmPortGetSetCcParams.getCcParams.type & NUM_OF_TASKS)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("NumOfTasks wasn't configured previously"));
++        if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("offset of the data  wasn't configured previously"));
++        if (fmPortGetSetCcParams.getCcParams.type & HW_PORT_ID)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("hwPortId wasn't updated"));
++    }
++
++    if (p_Manip->updateParams)
++    {
++        if (p_Manip->updateParams & NUM_OF_TASKS)
++        {
++            /*recommendation of Microcode team - (maxNumFramesInProcess * 2) */
++            size = (uint16_t)(p_Manip->capwapFragParams.maxNumFramesInProcess*2 + fmPortGetSetCcParams.getCcParams.numOfTasks);
++            if (size > 255)
++            RETURN_ERROR(MAJOR,E_INVALID_VALUE, ("numOfOpenReassmEntries + numOfTasks per port can not be greater than 256"));
++
++            p_Manip->capwapFragParams.numOfTasks = fmPortGetSetCcParams.getCcParams.numOfTasks;
++
++            /*p_ReassmFrmDescrIndxPoolTbl*/
++            p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl =
++            (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
++                    (uint32_t)(size + 1),
++                    4);
++            if (!p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl)
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP Reassembly frame buffer index pool table"));
++
++            MemSet8(p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl, 0, (uint32_t)(size + 1));
++
++            for ( i = 0; i < size; i++)
++            WRITE_UINT8(*(uint8_t *)PTR_MOVE(p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl, i), (uint8_t)(i+1));
++
++            tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl) - p_FmPcd->physicalMuramBase);
++
++            WRITE_UINT32(p_ReassmTbl->reasmFrmDescIndexPoolTblPtr, tmpReg32);
++
++            /*p_ReassmFrmDescrPoolTbl*/
++            p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl =
++            (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
++                    (uint32_t)((size + 1) * FM_PCD_MANIP_CAPWAP_REASM_RFD_SIZE),
++                    4);
++
++            if (!p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl)
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP Reassembly frame buffer pool table"));
++
++            MemSet8(p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl, 0, (uint32_t)((size +1)* FM_PCD_MANIP_CAPWAP_REASM_RFD_SIZE));
++
++            tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl) - p_FmPcd->physicalMuramBase);
++
++            WRITE_UINT32(p_ReassmTbl->reasmFrmDescPoolTblPtr, tmpReg32);
++
++            /*p_TimeOutTbl*/
++
++            p_Manip->capwapFragParams.p_TimeOutTbl =
++            (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
++                    (uint32_t)((size + 1)* FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_ENTRY_SIZE),
++                    4);
++
++            if (!p_Manip->capwapFragParams.p_TimeOutTbl)
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP Reassembly timeout table"));
++
++            MemSet8(p_Manip->capwapFragParams.p_TimeOutTbl, 0, (uint16_t)((size + 1)*FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_ENTRY_SIZE));
++
++            tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_TimeOutTbl) - p_FmPcd->physicalMuramBase);
++            WRITE_UINT32(p_ReassmTbl->timeOutTblPtr, tmpReg32);
++
++            p_Manip->updateParams &= ~NUM_OF_TASKS;
++            p_Manip->shadowUpdateParams |= NUM_OF_TASKS;
++        }
++
++        if (p_Manip->updateParams & OFFSET_OF_DATA)
++        {
++            p_Manip->capwapFragParams.dataOffset = fmPortGetSetCcParams.getCcParams.dataOffset;
++            tmpReg32 = GET_UINT32(p_ReassmTbl->mode);
++            tmpReg32|= p_Manip->capwapFragParams.dataOffset;
++            WRITE_UINT32(p_ReassmTbl->mode, tmpReg32);
++            p_Manip->updateParams &= ~OFFSET_OF_DATA;
++            p_Manip->shadowUpdateParams |= OFFSET_OF_DATA;
++        }
++
++        if (!(fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR))
++        {
++            p_Manip->capwapFragParams.prOffset = fmPortGetSetCcParams.getCcParams.prOffset;
++
++            tmpReg32 = GET_UINT32(p_ReassmTbl->mode);
++            tmpReg32|= FM_PCD_MANIP_CAPWAP_REASM_PR_COPY;
++            WRITE_UINT32(p_ReassmTbl->mode, tmpReg32);
++
++            tmpReg32 = GET_UINT32(p_ReassmTbl->intStatsTblPtr);
++            tmpReg32 |= (uint32_t)p_Manip->capwapFragParams.prOffset << 24;
++            WRITE_UINT32(p_ReassmTbl->intStatsTblPtr, tmpReg32);
++            p_Manip->updateParams &= ~OFFSET_OF_PR;
++            p_Manip->shadowUpdateParams |= OFFSET_OF_PR;
++        }
++        else
++        {
++            p_Manip->capwapFragParams.prOffset = 0xff;
++            p_Manip->updateParams &= ~OFFSET_OF_PR;
++            p_Manip->shadowUpdateParams |= OFFSET_OF_PR;
++        }
++
++        p_Manip->capwapFragParams.hwPortId = fmPortGetSetCcParams.getCcParams.hardwarePortId;
++        p_Manip->updateParams &= ~HW_PORT_ID;
++        p_Manip->shadowUpdateParams |= HW_PORT_ID;
++
++        /*timeout hc */
++        ccCapwapReassmTimeoutParams.fqidForTimeOutFrames = p_Manip->capwapFragParams.fqidForTimeOutFrames;
++        ccCapwapReassmTimeoutParams.portIdAndCapwapReassmTbl = (uint32_t)p_Manip->capwapFragParams.hwPortId << 24;
++        ccCapwapReassmTimeoutParams.portIdAndCapwapReassmTbl |= (uint32_t)((XX_VirtToPhys(p_ReassmTbl) - p_FmPcd->physicalMuramBase));
++        ccCapwapReassmTimeoutParams.timeoutRequestTime = (((uint32_t)1<<p_Manip->capwapFragParams.bitFor1Micro) * p_Manip->capwapFragParams.timeoutRoutineRequestTime)/2;
++        return FmHcPcdCcCapwapTimeoutReassm(p_FmPcd->h_Hc,&ccCapwapReassmTimeoutParams);
++    }
++
++    else if (validate)
++    {
++        if (fmPortGetSetCcParams.getCcParams.hardwarePortId != p_Manip->capwapFragParams.hwPortId)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Reassembly manipulation previously was assigned to another port"));
++        if (fmPortGetSetCcParams.getCcParams.numOfTasks != p_Manip->capwapFragParams.numOfTasks)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfTasks for this manipulation previously was defined by another value "));
++
++        if (!(fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR))
++        {
++            if (p_Manip->capwapFragParams.prOffset != fmPortGetSetCcParams.getCcParams.prOffset)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Parse result offset previously was defined by another value "));
++        }
++        else
++        {
++            if (p_Manip->capwapFragParams.prOffset != 0xff)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Parse result offset previously was defined by another value "));
++        }
++        if (fmPortGetSetCcParams.getCcParams.dataOffset != p_Manip->capwapFragParams.dataOffset)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Data offset previously was defined by another value "));
++    }
++
++    return E_OK;
++}
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++
++t_Error FmPcdRegisterReassmPort(t_Handle h_FmPcd, t_Handle h_ReasmCommonPramTbl)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    t_FmPcdCcReassmTimeoutParams ccReassmTimeoutParams = { 0 };
++    t_Error err = E_OK;
++    uint8_t result;
++    uint32_t bitFor1Micro, tsbs, log2num;
++
++    ASSERT_COND(p_FmPcd);
++    ASSERT_COND(h_ReasmCommonPramTbl);
++
++    bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm);
++    if (bitFor1Micro == 0)
++        RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale"));
++
++    bitFor1Micro = 32 - bitFor1Micro;
++    LOG2(FM_PCD_MANIP_REASM_TIMEOUT_THREAD_THRESH, log2num);
++    tsbs = bitFor1Micro - log2num;
++
++    ccReassmTimeoutParams.iprcpt = (uint32_t)(XX_VirtToPhys(
++            h_ReasmCommonPramTbl) - p_FmPcd->physicalMuramBase);
++    ccReassmTimeoutParams.tsbs = (uint8_t)tsbs;
++    ccReassmTimeoutParams.activate = TRUE;
++    if ((err = FmHcPcdCcTimeoutReassm(p_FmPcd->h_Hc, &ccReassmTimeoutParams,
++                                      &result)) != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    switch (result)
++    {
++        case (0):
++            return E_OK;
++        case (1):
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("failed to allocate TNUM"));
++        case (2):
++            RETURN_ERROR(
++                    MAJOR, E_NO_MEMORY,
++                    ("failed to allocate internal buffer from the HC-Port"));
++        case (3):
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                         ("'Disable Timeout Task' with invalid IPRCPT"));
++        case (4):
++            RETURN_ERROR(MAJOR, E_FULL, ("too many timeout tasks"));
++        case (5):
++            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("invalid sub command"));
++        default:
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
++    }
++    return E_OK;
++}
++
++static t_Error CreateReassCommonTable(t_FmPcdManip *p_Manip)
++{
++    uint32_t tmpReg32 = 0, i, bitFor1Micro;
++    uint64_t tmpReg64, size;
++    t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd;
++    t_Error err = E_OK;
++
++    bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm);
++    if (bitFor1Micro == 0)
++        RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale"));
++
++    /* Allocation of the Reassembly Common Parameters table. This table is located in the
++     MURAM. Its size is 64 bytes and its base address should be 8-byte aligned. */
++    p_Manip->reassmParams.p_ReassCommonTbl =
++            (t_ReassCommonTbl *)FM_MURAM_AllocMem(
++                    p_FmPcd->h_FmMuram,
++                    FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_SIZE,
++                    FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_ALIGN);
++
++    if (!p_Manip->reassmParams.p_ReassCommonTbl)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                     ("MURAM alloc for Reassembly common parameters table"));
++
++    MemSet8(p_Manip->reassmParams.p_ReassCommonTbl, 0,
++               FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_SIZE);
++
++    /* Setting the TimeOut Mode.*/
++    tmpReg32 = 0;
++    if (p_Manip->reassmParams.timeOutMode
++            == e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAMES)
++        tmpReg32 |= FM_PCD_MANIP_REASM_TIME_OUT_BETWEEN_FRAMES;
++
++    /* Setting TimeOut FQID - Frames that time out are enqueued to this FQID.
++     In order to cause TimeOut frames to be discarded, this queue should be configured accordingly*/
++    tmpReg32 |= p_Manip->reassmParams.fqidForTimeOutFrames;
++    WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->timeoutModeAndFqid,
++                 tmpReg32);
++
++    /* Calculation the size of IP Reassembly Frame Descriptor - number of frames that are allowed to be reassembled simultaneously + 129.*/
++    size = p_Manip->reassmParams.maxNumFramesInProcess + 129;
++
++    /*Allocation of IP Reassembly Frame Descriptor Indexes Pool - This pool resides in the MURAM */
++    p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr =
++            PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
++                            (uint32_t)(size * 2),
++                            256));
++    if (!p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr)
++        RETURN_ERROR(
++                MAJOR, E_NO_MEMORY,
++                ("MURAM alloc for Reassembly frame descriptor indexes pool"));
++
++    MemSet8(UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr),
++               0, (uint32_t)(size * 2));
++
++    /* The entries in IP Reassembly Frame Descriptor Indexes Pool contains indexes starting with 1 up to
++     the maximum number of frames that are allowed to be reassembled simultaneously + 128.
++     The last entry in this pool must contain the index zero*/
++    for (i = 0; i < (size - 1); i++)
++        WRITE_UINT16(
++                *(uint16_t *)PTR_MOVE(UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr), (i<<1)),
++                (uint16_t)(i+1));
++
++    /* Sets the IP Reassembly Frame Descriptor Indexes Pool offset from MURAM */
++    tmpReg32 = (uint32_t)(XX_VirtToPhys(
++            UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr))
++            - p_FmPcd->physicalMuramBase);
++    WRITE_UINT32(
++            p_Manip->reassmParams.p_ReassCommonTbl->reassFrmDescIndexPoolTblPtr,
++            tmpReg32);
++
++    /* Allocation of the Reassembly Frame Descriptors Pool - This pool resides in external memory.
++     The number of entries in this pool should be equal to the number of entries in IP Reassembly Frame Descriptor Indexes Pool.*/
++    p_Manip->reassmParams.reassFrmDescrPoolTblAddr =
++            PTR_TO_UINT(XX_MallocSmart((uint32_t)(size * 64), p_Manip->reassmParams.dataMemId, 64));
++
++    if (!p_Manip->reassmParams.reassFrmDescrPoolTblAddr)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation FAILED"));
++
++    MemSet8(UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrPoolTblAddr), 0,
++               (uint32_t)(size * 64));
++
++    /* Sets the Reassembly Frame Descriptors Pool and liodn offset*/
++    tmpReg64 = (uint64_t)(XX_VirtToPhys(
++            UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrPoolTblAddr)));
++    tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset
++            & FM_PCD_MANIP_REASM_LIODN_MASK)
++            << (uint64_t)FM_PCD_MANIP_REASM_LIODN_SHIFT);
++    tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset
++            & FM_PCD_MANIP_REASM_ELIODN_MASK)
++            << (uint64_t)FM_PCD_MANIP_REASM_ELIODN_SHIFT);
++    WRITE_UINT32(
++            p_Manip->reassmParams.p_ReassCommonTbl->liodnAndReassFrmDescPoolPtrHi,
++            (uint32_t)(tmpReg64 >> 32));
++    WRITE_UINT32(
++            p_Manip->reassmParams.p_ReassCommonTbl->reassFrmDescPoolPtrLow,
++            (uint32_t)tmpReg64);
++
++    /*Allocation of the TimeOut table - This table resides in the MURAM.
++     The number of entries in this table is identical to the number of entries in the Reassembly Frame Descriptors Pool*/
++    p_Manip->reassmParams.timeOutTblAddr =
++            PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, (uint32_t)(size * 8),8));
++
++    if (!p_Manip->reassmParams.timeOutTblAddr)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                     ("MURAM alloc for Reassembly timeout table"));
++
++    MemSet8(UINT_TO_PTR(p_Manip->reassmParams.timeOutTblAddr), 0,
++               (uint16_t)(size * 8));
++
++    /* Sets the TimeOut table offset from MURAM */
++    tmpReg32 = (uint32_t)(XX_VirtToPhys(
++            UINT_TO_PTR(p_Manip->reassmParams.timeOutTblAddr))
++            - p_FmPcd->physicalMuramBase);
++    WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->timeOutTblPtr,
++                 tmpReg32);
++
++    /* Sets the Expiration Delay */
++    tmpReg32 = 0;
++    tmpReg32 |= (((uint32_t)(1 << bitFor1Micro))
++            * p_Manip->reassmParams.timeoutThresholdForReassmProcess);
++    WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->expirationDelay,
++                 tmpReg32);
++
++    err = FmPcdRegisterReassmPort(p_FmPcd,
++                                  p_Manip->reassmParams.p_ReassCommonTbl);
++    if (err != E_OK)
++    {
++        FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
++                         p_Manip->reassmParams.p_ReassCommonTbl);
++        RETURN_ERROR(MAJOR, err, ("port registration"));
++    }
++
++    return err;
++}
++
++static t_Error CreateReassTable(t_FmPcdManip *p_Manip, e_NetHeaderType hdr)
++{
++    t_FmPcd *p_FmPcd = p_Manip->h_FmPcd;
++    uint32_t tmpReg32, autoLearnHashTblSize;
++    uint32_t numOfWays, setSize, setSizeCode, keySize;
++    uint32_t waySize, numOfSets, numOfEntries;
++    uint64_t tmpReg64;
++    uint16_t minFragSize;
++    uint16_t maxReassemSize;
++    uintptr_t *p_AutoLearnHashTblAddr, *p_AutoLearnSetLockTblAddr;
++    t_ReassTbl **p_ReassTbl;
++
++    switch (hdr)
++    {
++        case HEADER_TYPE_IPv4:
++            p_ReassTbl = &p_Manip->reassmParams.ip.p_Ipv4ReassTbl;
++            p_AutoLearnHashTblAddr =
++                    &p_Manip->reassmParams.ip.ipv4AutoLearnHashTblAddr;
++            p_AutoLearnSetLockTblAddr =
++                    &p_Manip->reassmParams.ip.ipv4AutoLearnSetLockTblAddr;
++            minFragSize = p_Manip->reassmParams.ip.minFragSize[0];
++            maxReassemSize = 0;
++            numOfWays = p_Manip->reassmParams.ip.numOfFramesPerHashEntry[0];
++            keySize = 4 + 4 + 1 + 2; /* 3-tuple + IP-Id */
++            break;
++        case HEADER_TYPE_IPv6:
++            p_ReassTbl = &p_Manip->reassmParams.ip.p_Ipv6ReassTbl;
++            p_AutoLearnHashTblAddr =
++                    &p_Manip->reassmParams.ip.ipv6AutoLearnHashTblAddr;
++            p_AutoLearnSetLockTblAddr =
++                    &p_Manip->reassmParams.ip.ipv6AutoLearnSetLockTblAddr;
++            minFragSize = p_Manip->reassmParams.ip.minFragSize[1];
++            maxReassemSize = 0;
++            numOfWays = p_Manip->reassmParams.ip.numOfFramesPerHashEntry[1];
++            keySize = 16 + 16 + 4; /* 2-tuple + IP-Id */
++            if (numOfWays > e_FM_PCD_MANIP_SIX_WAYS_HASH)
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("num of ways"));
++            break;
++        case HEADER_TYPE_CAPWAP:
++            p_ReassTbl = &p_Manip->reassmParams.capwap.p_ReassTbl;
++            p_AutoLearnHashTblAddr =
++                    &p_Manip->reassmParams.capwap.autoLearnHashTblAddr;
++            p_AutoLearnSetLockTblAddr =
++                    &p_Manip->reassmParams.capwap.autoLearnSetLockTblAddr;
++            minFragSize = 0;
++            maxReassemSize = p_Manip->reassmParams.capwap.maxRessembledsSize;
++            numOfWays = p_Manip->reassmParams.capwap.numOfFramesPerHashEntry;
++            keySize = 4;
++            break;
++        default:
++            RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("header type"));
++    }
++    keySize += 2; /* 2 bytes reserved for RFDIndex */
++#if (DPAA_VERSION >= 11)
++    keySize += 2; /* 2 bytes reserved */
++#endif /* (DPAA_VERSION >= 11) */
++    waySize = ROUND_UP(keySize, 8);
++
++    /* Allocates the Reassembly Parameters Table - This table is located in the MURAM.*/
++    *p_ReassTbl = (t_ReassTbl *)FM_MURAM_AllocMem(
++            p_FmPcd->h_FmMuram, FM_PCD_MANIP_REASM_TABLE_SIZE,
++            FM_PCD_MANIP_REASM_TABLE_ALIGN);
++    if (!*p_ReassTbl)
++        RETURN_ERROR( MAJOR, E_NO_MEMORY,
++                     ("MURAM alloc for Reassembly specific parameters table"));
++    memset(*p_ReassTbl, 0, sizeof(t_ReassTbl));
++
++    /* Sets the Reassembly common Parameters table offset from MURAM in the Reassembly Table descriptor*/
++    tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->reassmParams.p_ReassCommonTbl)
++            - p_FmPcd->physicalMuramBase);
++    WRITE_UINT32((*p_ReassTbl)->reassCommonPrmTblPtr, tmpReg32);
++
++    /* Calculate set size (set size is rounded-up to next power of 2) */
++    NEXT_POWER_OF_2(numOfWays * waySize, setSize);
++
++    /* Get set size code */
++    LOG2(setSize, setSizeCode);
++
++    /* Sets ways number and set size code */
++    WRITE_UINT16((*p_ReassTbl)->waysNumAndSetSize,
++                 (uint16_t)((numOfWays << 8) | setSizeCode));
++
++    /* It is recommended that the total number of entries in this table
++     (number of sets * number of ways) will be twice the number of frames that
++     are expected to be reassembled simultaneously.*/
++    numOfEntries = (uint32_t)(p_Manip->reassmParams.maxNumFramesInProcess * 2);
++
++    /* sets number calculation - number of entries = number of sets * number of ways */
++    numOfSets = numOfEntries / numOfWays;
++
++    /* Sets AutoLearnHashKeyMask*/
++    NEXT_POWER_OF_2(numOfSets, numOfSets);
++
++    WRITE_UINT16((*p_ReassTbl)->autoLearnHashKeyMask,
++                 (uint16_t)(numOfSets - 1));
++
++    /* Allocation of Reassembly Automatic Learning Hash Table - This table resides in external memory.
++     The size of this table is determined by the number of sets and the set size.
++     Table size = set size * number of sets
++     This table base address should be aligned to SetSize.*/
++    autoLearnHashTblSize = numOfSets * setSize;
++
++    *p_AutoLearnHashTblAddr =
++            PTR_TO_UINT(XX_MallocSmart(autoLearnHashTblSize, p_Manip->reassmParams.dataMemId, setSize));
++    if (!*p_AutoLearnHashTblAddr)
++    {
++        FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, *p_ReassTbl);
++        *p_ReassTbl = NULL;
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation FAILED"));
++    }
++    MemSet8(UINT_TO_PTR(*p_AutoLearnHashTblAddr), 0, autoLearnHashTblSize);
++
++    /* Sets the Reassembly Automatic Learning Hash Table and liodn offset */
++    tmpReg64 = ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset
++            & FM_PCD_MANIP_REASM_LIODN_MASK)
++            << (uint64_t)FM_PCD_MANIP_REASM_LIODN_SHIFT);
++    tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset
++            & FM_PCD_MANIP_REASM_ELIODN_MASK)
++            << (uint64_t)FM_PCD_MANIP_REASM_ELIODN_SHIFT);
++    tmpReg64 |= XX_VirtToPhys(UINT_TO_PTR(*p_AutoLearnHashTblAddr));
++    WRITE_UINT32( (*p_ReassTbl)->liodnAlAndAutoLearnHashTblPtrHi,
++                 (uint32_t)(tmpReg64 >> 32));
++    WRITE_UINT32((*p_ReassTbl)->autoLearnHashTblPtrLow, (uint32_t)tmpReg64);
++
++    /* Allocation of the Set Lock table - This table resides in external memory
++     The size of this table is (number of sets in the Reassembly Automatic Learning Hash table)*4 bytes.
++     This table resides in external memory and its base address should be 4-byte aligned */
++    *p_AutoLearnSetLockTblAddr =
++            PTR_TO_UINT(XX_MallocSmart((uint32_t)(numOfSets * 4), p_Manip->reassmParams.dataMemId, 4));
++    if (!*p_AutoLearnSetLockTblAddr)
++    {
++        FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, *p_ReassTbl);
++        *p_ReassTbl = NULL;
++        XX_FreeSmart(UINT_TO_PTR(*p_AutoLearnHashTblAddr));
++        *p_AutoLearnHashTblAddr = 0;
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation FAILED"));
++    }
++    MemSet8(UINT_TO_PTR(*p_AutoLearnSetLockTblAddr), 0, (numOfSets * 4));
++
++    /* sets Set Lock table pointer and liodn offset*/
++    tmpReg64 = ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset
++            & FM_PCD_MANIP_REASM_LIODN_MASK)
++            << (uint64_t)FM_PCD_MANIP_REASM_LIODN_SHIFT);
++    tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset
++            & FM_PCD_MANIP_REASM_ELIODN_MASK)
++            << (uint64_t)FM_PCD_MANIP_REASM_ELIODN_SHIFT);
++    tmpReg64 |= XX_VirtToPhys(UINT_TO_PTR(*p_AutoLearnSetLockTblAddr));
++    WRITE_UINT32( (*p_ReassTbl)->liodnSlAndAutoLearnSetLockTblPtrHi,
++                 (uint32_t)(tmpReg64 >> 32));
++    WRITE_UINT32((*p_ReassTbl)->autoLearnSetLockTblPtrLow, (uint32_t)tmpReg64);
++
++    /* Sets user's requested minimum fragment size (in Bytes) for First/Middle fragment */
++    WRITE_UINT16((*p_ReassTbl)->minFragSize, minFragSize);
++
++    WRITE_UINT16((*p_ReassTbl)->maxReassemblySize, maxReassemSize);
++
++    return E_OK;
++}
++
++static t_Error UpdateInitReasm(t_Handle h_FmPcd, t_Handle h_PcdParams,
++                               t_Handle h_FmPort, t_FmPcdManip *p_Manip,
++                               t_Handle h_Ad, bool validate)
++{
++    t_FmPortGetSetCcParams fmPortGetSetCcParams;
++    uint32_t tmpReg32;
++    t_Error err;
++    t_FmPortPcdParams *p_PcdParams = (t_FmPortPcdParams *)h_PcdParams;
++#if (DPAA_VERSION >= 11)
++    t_FmPcdCtrlParamsPage *p_ParamsPage;
++#endif /* (DPAA_VERSION >= 11) */
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Manip->frag, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(
++            (p_Manip->opcode == HMAN_OC_IP_REASSEMBLY) || (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY),
++            E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Manip->updateParams || h_PcdParams,
++                              E_INVALID_HANDLE);
++
++    UNUSED(h_Ad);
++
++    if (!p_Manip->updateParams)
++        return E_OK;
++
++    if (p_Manip->h_FmPcd != h_FmPcd)
++        RETURN_ERROR(
++                MAJOR, E_INVALID_STATE,
++                ("handler of PCD previously was initiated by different value"));
++
++    if (p_Manip->updateParams)
++    {
++        if ((!(p_Manip->updateParams
++                & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK)))
++                || ((p_Manip->shadowUpdateParams
++                        & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK))))
++            RETURN_ERROR(
++                    MAJOR, E_INVALID_STATE,
++                    ("in this stage parameters from Port has not be updated"));
++
++        fmPortGetSetCcParams.setCcParams.type = 0;
++        if (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY)
++        {
++            fmPortGetSetCcParams.setCcParams.type |= UPDATE_OFP_DPTE;
++            fmPortGetSetCcParams.setCcParams.ofpDpde = 0xF;
++        }
++        fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams | FM_REV;
++        if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams))
++                != E_OK)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        if (fmPortGetSetCcParams.getCcParams.type
++                & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK | FM_REV))
++            RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                         ("offset of the data wasn't configured previously"));
++        if (p_Manip->updateParams
++                & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK))
++        {
++            t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
++            uint8_t *p_Ptr, i, totalNumOfTnums;
++
++            totalNumOfTnums =
++                    (uint8_t)(fmPortGetSetCcParams.getCcParams.numOfTasks
++                            + fmPortGetSetCcParams.getCcParams.numOfExtraTasks);
++
++            p_Manip->reassmParams.internalBufferPoolAddr =
++                    PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
++                                    (uint32_t)(totalNumOfTnums * BMI_FIFO_UNITS),
++                                    BMI_FIFO_UNITS));
++            if (!p_Manip->reassmParams.internalBufferPoolAddr)
++                RETURN_ERROR(
++                        MAJOR, E_NO_MEMORY,
++                        ("MURAM alloc for Reassembly internal buffers pool"));
++            MemSet8(
++                    UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolAddr),
++                    0, (uint32_t)(totalNumOfTnums * BMI_FIFO_UNITS));
++
++            p_Manip->reassmParams.internalBufferPoolManagementIndexAddr =
++                    PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
++                                    (uint32_t)(5 + totalNumOfTnums),
++                                    4));
++            if (!p_Manip->reassmParams.internalBufferPoolManagementIndexAddr)
++                RETURN_ERROR(
++                        MAJOR,
++                        E_NO_MEMORY,
++                        ("MURAM alloc for Reassembly internal buffers management"));
++
++            p_Ptr =
++                    (uint8_t*)UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolManagementIndexAddr);
++            WRITE_UINT32(
++                    *(uint32_t*)p_Ptr,
++                    (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolAddr)) - p_FmPcd->physicalMuramBase));
++            for (i = 0, p_Ptr += 4; i < totalNumOfTnums; i++, p_Ptr++)
++                WRITE_UINT8(*p_Ptr, i);
++            WRITE_UINT8(*p_Ptr, 0xFF);
++
++            tmpReg32 =
++                    (4 << FM_PCD_MANIP_REASM_COMMON_INT_BUFFER_IDX_SHIFT)
++                            | ((uint32_t)(XX_VirtToPhys(
++                                    UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolManagementIndexAddr))
++                                    - p_FmPcd->physicalMuramBase));
++            WRITE_UINT32(
++                    p_Manip->reassmParams.p_ReassCommonTbl->internalBufferManagement,
++                    tmpReg32);
++
++            p_Manip->updateParams &= ~(NUM_OF_TASKS | NUM_OF_EXTRA_TASKS
++                    | DISCARD_MASK);
++            p_Manip->shadowUpdateParams |= (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS
++                    | DISCARD_MASK);
++        }
++    }
++
++    if (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY)
++    {
++        if (p_Manip->reassmParams.capwap.h_Scheme)
++        {
++            p_PcdParams->p_KgParams->h_Schemes[p_PcdParams->p_KgParams->numOfSchemes] =
++                    p_Manip->reassmParams.capwap.h_Scheme;
++            p_PcdParams->p_KgParams->numOfSchemes++;
++        }
++
++    }
++    else
++    {
++        if (p_Manip->reassmParams.ip.h_Ipv4Scheme)
++        {
++            p_PcdParams->p_KgParams->h_Schemes[p_PcdParams->p_KgParams->numOfSchemes] =
++                    p_Manip->reassmParams.ip.h_Ipv4Scheme;
++            p_PcdParams->p_KgParams->numOfSchemes++;
++        }
++        if (p_Manip->reassmParams.ip.h_Ipv6Scheme)
++        {
++            p_PcdParams->p_KgParams->h_Schemes[p_PcdParams->p_KgParams->numOfSchemes] =
++                    p_Manip->reassmParams.ip.h_Ipv6Scheme;
++            p_PcdParams->p_KgParams->numOfSchemes++;
++        }
++#if (DPAA_VERSION >= 11)
++        if (fmPortGetSetCcParams.getCcParams.revInfo.majorRev >= 6)
++        {
++            if ((err = FmPortSetGprFunc(h_FmPort, e_FM_PORT_GPR_MURAM_PAGE,
++                                        (void**)&p_ParamsPage)) != E_OK)
++                RETURN_ERROR(MAJOR, err, NO_MSG);
++
++            tmpReg32 = NIA_ENG_KG;
++            if (p_Manip->reassmParams.ip.h_Ipv4Scheme)
++            {
++                tmpReg32 |= NIA_KG_DIRECT;
++                tmpReg32 |= NIA_KG_CC_EN;
++                tmpReg32 |= FmPcdKgGetSchemeId(
++                        p_Manip->reassmParams.ip.h_Ipv4Scheme);
++                WRITE_UINT32(p_ParamsPage->iprIpv4Nia, tmpReg32);
++            }
++            if (p_Manip->reassmParams.ip.h_Ipv6Scheme)
++            {
++                tmpReg32 &= ~NIA_AC_MASK;
++                tmpReg32 |= NIA_KG_DIRECT;
++                tmpReg32 |= NIA_KG_CC_EN;
++                tmpReg32 |= FmPcdKgGetSchemeId(
++                        p_Manip->reassmParams.ip.h_Ipv6Scheme);
++                WRITE_UINT32(p_ParamsPage->iprIpv6Nia, tmpReg32);
++            }
++        }
++#else
++        if (fmPortGetSetCcParams.getCcParams.revInfo.majorRev < 6)
++        {
++            WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->discardMask,
++                    fmPortGetSetCcParams.getCcParams.discardMask);
++        }
++#endif /* (DPAA_VERSION >= 11) */
++    }
++    return E_OK;
++}
++
++#if (DPAA_VERSION == 10)
++static t_Error FmPcdFragHcScratchPoolFill(t_Handle h_FmPcd, uint8_t scratchBpid)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    t_FmPcdCcFragScratchPoolCmdParams fmPcdCcFragScratchPoolCmdParams;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++
++    memset(&fmPcdCcFragScratchPoolCmdParams, 0, sizeof(t_FmPcdCcFragScratchPoolCmdParams));
++
++    fmPcdCcFragScratchPoolCmdParams.numOfBuffers = NUM_OF_SCRATCH_POOL_BUFFERS;
++    fmPcdCcFragScratchPoolCmdParams.bufferPoolId = scratchBpid;
++    if ((err = FmHcPcdCcIpFragScratchPollCmd(p_FmPcd->h_Hc, TRUE, &fmPcdCcFragScratchPoolCmdParams)) != E_OK)
++    RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    if (fmPcdCcFragScratchPoolCmdParams.numOfBuffers != 0)
++    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Fill scratch pool failed,"
++                    "Failed to release %d buffers to the BM (missing FBPRs)",
++                    fmPcdCcFragScratchPoolCmdParams.numOfBuffers));
++
++    return E_OK;
++}
++
++static t_Error FmPcdFragHcScratchPoolEmpty(t_Handle h_FmPcd, uint8_t scratchBpid)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    t_FmPcdCcFragScratchPoolCmdParams fmPcdCcFragScratchPoolCmdParams;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++
++    memset(&fmPcdCcFragScratchPoolCmdParams, 0, sizeof(t_FmPcdCcFragScratchPoolCmdParams));
++
++    fmPcdCcFragScratchPoolCmdParams.bufferPoolId = scratchBpid;
++    if ((err = FmHcPcdCcIpFragScratchPollCmd(p_FmPcd->h_Hc, FALSE, &fmPcdCcFragScratchPoolCmdParams)) != E_OK)
++    RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    return E_OK;
++}
++#endif /* (DPAA_VERSION == 10) */
++
++static void ReleaseManipHandler(t_FmPcdManip *p_Manip, t_FmPcd *p_FmPcd)
++{
++    if (p_Manip->h_Ad)
++    {
++        if (p_Manip->muramAllocate)
++            FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->h_Ad);
++        else
++            XX_Free(p_Manip->h_Ad);
++        p_Manip->h_Ad = NULL;
++    }
++    if (p_Manip->p_Template)
++    {
++        FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->p_Template);
++        p_Manip->p_Template = NULL;
++    }
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++    if (p_Manip->h_Frag)
++    {
++        if (p_Manip->capwapFragParams.p_AutoLearnHashTbl)
++        FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
++                p_Manip->capwapFragParams.p_AutoLearnHashTbl);
++        if (p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl)
++        FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
++                p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl);
++        if (p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl)
++        FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
++                p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl);
++        if (p_Manip->capwapFragParams.p_TimeOutTbl)
++        FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
++                p_Manip->capwapFragParams.p_TimeOutTbl);
++        FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->h_Frag);
++
++    }
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++    if (p_Manip->frag)
++    {
++        if (p_Manip->fragParams.p_Frag)
++        {
++#if (DPAA_VERSION == 10)
++            FmPcdFragHcScratchPoolEmpty((t_Handle)p_FmPcd, p_Manip->fragParams.scratchBpid);
++#endif /* (DPAA_VERSION == 10) */
++
++            FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->fragParams.p_Frag);
++        }
++    }
++    else
++        if (p_Manip->reassm)
++        {
++            FmPcdUnregisterReassmPort(p_FmPcd,
++                                      p_Manip->reassmParams.p_ReassCommonTbl);
++
++            if (p_Manip->reassmParams.timeOutTblAddr)
++                FM_MURAM_FreeMem(
++                        p_FmPcd->h_FmMuram,
++                        UINT_TO_PTR(p_Manip->reassmParams.timeOutTblAddr));
++            if (p_Manip->reassmParams.reassFrmDescrPoolTblAddr)
++                XX_FreeSmart(
++                        UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrPoolTblAddr));
++            if (p_Manip->reassmParams.p_ReassCommonTbl)
++                FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
++                                 p_Manip->reassmParams.p_ReassCommonTbl);
++            if (p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr)
++                FM_MURAM_FreeMem(
++                        p_FmPcd->h_FmMuram,
++                        UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr));
++            if (p_Manip->reassmParams.internalBufferPoolManagementIndexAddr)
++                FM_MURAM_FreeMem(
++                        p_FmPcd->h_FmMuram,
++                        UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolManagementIndexAddr));
++            if (p_Manip->reassmParams.internalBufferPoolAddr)
++                FM_MURAM_FreeMem(
++                        p_FmPcd->h_FmMuram,
++                        UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolAddr));
++            if (p_Manip->reassmParams.hdr == HEADER_TYPE_CAPWAP)
++            {
++
++            }
++            else
++            {
++                if (p_Manip->reassmParams.ip.ipv4AutoLearnHashTblAddr)
++                    XX_FreeSmart(
++                            UINT_TO_PTR(p_Manip->reassmParams.ip.ipv4AutoLearnHashTblAddr));
++                if (p_Manip->reassmParams.ip.ipv6AutoLearnHashTblAddr)
++                    XX_FreeSmart(
++                            UINT_TO_PTR(p_Manip->reassmParams.ip.ipv6AutoLearnHashTblAddr));
++                if (p_Manip->reassmParams.ip.ipv4AutoLearnSetLockTblAddr)
++                    XX_FreeSmart(
++                            UINT_TO_PTR(p_Manip->reassmParams.ip.ipv4AutoLearnSetLockTblAddr));
++                if (p_Manip->reassmParams.ip.ipv6AutoLearnSetLockTblAddr)
++                    XX_FreeSmart(
++                            UINT_TO_PTR(p_Manip->reassmParams.ip.ipv6AutoLearnSetLockTblAddr));
++                if (p_Manip->reassmParams.ip.p_Ipv4ReassTbl)
++                    FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
++                                     p_Manip->reassmParams.ip.p_Ipv4ReassTbl);
++                if (p_Manip->reassmParams.ip.p_Ipv6ReassTbl)
++                    FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
++                                     p_Manip->reassmParams.ip.p_Ipv6ReassTbl);
++                if (p_Manip->reassmParams.ip.h_Ipv6Ad)
++                    XX_FreeSmart(p_Manip->reassmParams.ip.h_Ipv6Ad);
++                if (p_Manip->reassmParams.ip.h_Ipv4Ad)
++                    XX_FreeSmart(p_Manip->reassmParams.ip.h_Ipv4Ad);
++            }
++        }
++
++    if (p_Manip->p_StatsTbl)
++        FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->p_StatsTbl);
++}
++
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++static t_Error CheckManipParamsAndSetType(t_FmPcdManip *p_Manip, t_FmPcdManipParams *p_ManipParams)
++{
++    if (p_ManipParams->u.hdr.rmv)
++    {
++        switch (p_ManipParams->u.hdr.rmvParams.type)
++        {
++            case (e_FM_PCD_MANIP_RMV_BY_HDR):
++            switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.type)
++            {
++                case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START) :
++                if (p_ManipParams->u.hdr.rmvParams.u.byHdr.u.fromStartByHdr.include)
++                {
++                    switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.u.fromStartByHdr.hdrInfo.hdr)
++                    {
++                        case (HEADER_TYPE_CAPWAP_DTLS) :
++                        p_Manip->opcode = HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST;
++                        p_Manip->muramAllocate = TRUE;
++                        if (p_ManipParams->u.hdr.insrt)
++                        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for  CAPWAP_DTLS_HDR remove can not be insrt manipualtion after"));
++                        if (p_ManipParams->fragOrReasm)
++                        {
++                            if (!p_ManipParams->fragOrReasmParams.frag)
++                            {
++                                switch (p_ManipParams->fragOrReasmParams.hdr)
++                                {
++                                    case (HEADER_TYPE_CAPWAP):
++                                    p_Manip->opcode = HMAN_OC_CAPWAP_REASSEMBLY;
++                                    break;
++                                    default:
++                                    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("unsupported header for Reassembly"));
++                                }
++                            }
++                            else
++                            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for this type of manipulation frag can not be TRUE"));
++                        }
++                        break;
++                        default:
++                        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("non valid net header of remove location"));
++                    }
++                }
++                else
++                {
++                    switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.u.fromStartByHdr.hdrInfo.hdr)
++                    {
++                        case (HEADER_TYPE_CAPWAP_DTLS) :
++                        case (HEADER_TYPE_CAPWAP) :
++                        if (p_ManipParams->fragOrReasm || p_ManipParams->u.hdr.insrt)
++                        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for the type of remove e_FM_PCD_MANIP_RMV_FROM_START_OF_FRAME_TILL_CAPWAP can not be insert or fragOrReasm TRUE"));
++                        p_Manip->opcode = HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR;
++                        p_Manip->muramAllocate = TRUE;
++                        p_ManipParams->u.hdr.insrt = TRUE; //internal frame header
++                        break;
++                        default :
++                        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid type of remove manipulation"));
++                    }
++                }
++                break;
++                default :
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid type of remove manipulation"));
++            }
++            break;
++            default:
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid type of remove manipulation"));
++        }
++    }
++    else if (p_ManipParams->u.hdr.insrt)
++    {
++        switch (p_ManipParams->u.hdr.insrtParams.type)
++        {
++            case (e_FM_PCD_MANIP_INSRT_BY_TEMPLATE) :
++
++            p_Manip->opcode = HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER;
++            p_Manip->muramAllocate = FALSE;
++            if (p_ManipParams->fragOrReasm)
++            {
++                if (p_ManipParams->fragOrReasmParams.frag)
++                {
++                    switch (p_ManipParams->fragOrReasmParams.hdr)
++                    {
++                        case (HEADER_TYPE_CAPWAP):
++                        p_Manip->opcode = HMAN_OC_CAPWAP_FRAGMENTATION;
++                        break;
++                        default:
++                        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid header for fragmentation"));
++                    }
++                }
++                else
++                RETURN_ERROR(MAJOR, E_INVALID_STATE,("can not reach this point"));
++            }
++            break;
++
++            default:
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for only isert manipulation unsupported type"));
++        }
++    }
++    else if (p_ManipParams->fragOrReasm)
++    {
++        if (p_ManipParams->fragOrReasmParams.frag)
++        {
++            switch (p_ManipParams->fragOrReasmParams.hdr)
++            {
++                case (HEADER_TYPE_CAPWAP):
++                p_Manip->opcode = HMAN_OC_CAPWAP_FRAGMENTATION;
++                p_Manip->muramAllocate = FALSE;
++                break;
++                default:
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported header for fragmentation"));
++            }
++        }
++        else
++        {
++            switch (p_ManipParams->fragOrReasmParams.hdr)
++            {
++                case (HEADER_TYPE_CAPWAP):
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Reassembly has to be with additional operation - rmv = TRUE, type of remove - e_FM_PCD_MANIP_RMV_FROM_START_OF_FRAME_INCLUDE_SPECIFIC_LOCATION,type = e_FM_PCD_MANIP_LOC_BY_HDR, hdr = HEADER_TYPE_CAPWAP_DTLS"));
++                default:
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported header for reassembly"));
++            }
++        }
++
++    }
++    else
++    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("User didn't ask for any manipulation"));
++
++    p_Manip->insrt = p_ManipParams->u.hdr.insrt;
++    p_Manip->rmv = p_ManipParams->u.hdr.rmv;
++
++    return E_OK;
++}
++
++#else /* not (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++static t_Error CheckManipParamsAndSetType(t_FmPcdManip *p_Manip,
++                                          t_FmPcdManipParams *p_ManipParams)
++{
++    switch (p_ManipParams->type)
++    {
++        case e_FM_PCD_MANIP_HDR:
++            /* Check that next-manip is not already used */
++            if (p_ManipParams->h_NextManip)
++            {
++                if (!MANIP_IS_FIRST(p_ManipParams->h_NextManip))
++                    RETURN_ERROR(
++                            MAJOR, E_INVALID_STATE,
++                            ("h_NextManip is already a part of another chain"));
++                if ((MANIP_GET_TYPE(p_ManipParams->h_NextManip)
++                        != e_FM_PCD_MANIP_HDR) &&
++                        (MANIP_GET_TYPE(p_ManipParams->h_NextManip)
++                        != e_FM_PCD_MANIP_FRAG))
++                    RETURN_ERROR(
++                            MAJOR,
++                            E_NOT_SUPPORTED,
++                            ("For a Header Manipulation node - no support of h_NextManip of type other than Header Manipulation or Fragmentation."));
++            }
++
++            if (p_ManipParams->u.hdr.rmv)
++            {
++                switch (p_ManipParams->u.hdr.rmvParams.type)
++                {
++                    case (e_FM_PCD_MANIP_RMV_BY_HDR):
++                        switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.type)
++                        {
++                            case (e_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2):
++                                break;
++#if (DPAA_VERSION >= 11)
++                            case (e_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP):
++                                break;
++                            case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START):
++                            {
++                                t_Error err;
++                                uint8_t prsArrayOffset;
++
++                                err =
++                                        GetPrOffsetByHeaderOrField(
++                                                &p_ManipParams->u.hdr.rmvParams.u.byHdr.u.hdrInfo,
++                                                &prsArrayOffset);
++                                if (err)
++                                    RETURN_ERROR(MAJOR, err, NO_MSG);
++                                break;
++                            }
++#endif /* (DPAA_VERSION >= 11) */
++                            default:
++                                RETURN_ERROR(
++                                        MAJOR,
++                                        E_INVALID_STATE,
++                                        ("invalid type of remove manipulation"));
++                        }
++                        break;
++                    case (e_FM_PCD_MANIP_RMV_GENERIC):
++                        break;
++                    default:
++                        RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                                     ("invalid type of remove manipulation"));
++                }
++                p_Manip->opcode = HMAN_OC;
++                p_Manip->muramAllocate = TRUE;
++                p_Manip->rmv = TRUE;
++            }
++            else
++                if (p_ManipParams->u.hdr.insrt)
++                {
++                    switch (p_ManipParams->u.hdr.insrtParams.type)
++                    {
++                        case (e_FM_PCD_MANIP_INSRT_BY_HDR):
++                        {
++                            switch (p_ManipParams->u.hdr.insrtParams.u.byHdr.type)
++                            {
++                                case (e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2):
++                                    /* nothing to check */
++                                    break;
++#if (DPAA_VERSION >= 11)
++                                case (e_FM_PCD_MANIP_INSRT_BY_HDR_IP):
++                                    if (p_ManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size
++                                            % 4)
++                                        RETURN_ERROR(
++                                                MAJOR,
++                                                E_INVALID_VALUE,
++                                                ("IP inserted header must be of size which is a multiple of four bytes"));
++                                    break;
++                                case (e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP):
++                                    if (p_ManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size
++                                            % 4)
++                                        RETURN_ERROR(
++                                                MAJOR,
++                                                E_INVALID_VALUE,
++                                                ("CAPWAP inserted header must be of size which is a multiple of four bytes"));
++                                    break;
++                                case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP):
++                                case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE):
++                                    if (p_ManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size
++                                            != 8)
++                                        RETURN_ERROR(
++                                                MAJOR,
++                                                E_INVALID_VALUE,
++                                                ("Inserted header must be of size 8"));
++                                    break;
++#endif /* (DPAA_VERSION >= 11) */
++                                default:
++                                    RETURN_ERROR(
++                                            MAJOR,
++                                            E_INVALID_STATE,
++                                            ("unsupported insert by header type"));
++                            }
++                        }
++                        case (e_FM_PCD_MANIP_INSRT_GENERIC):
++                            break;
++                        default:
++                            RETURN_ERROR(
++                                    MAJOR,
++                                    E_INVALID_STATE,
++                                    ("for only insert manipulation unsupported type"));
++                    }
++                    p_Manip->opcode = HMAN_OC;
++                    p_Manip->muramAllocate = TRUE;
++                    p_Manip->insrt = TRUE;
++                }
++                else
++                    if (p_ManipParams->u.hdr.fieldUpdate)
++                    {
++                        /* Check parameters */
++                        if (p_ManipParams->u.hdr.fieldUpdateParams.type
++                                == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN)
++                        {
++                            if ((p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType
++                                    == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_VPRI)
++                                    && (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.u.vpri
++                                            > 7))
++                                RETURN_ERROR(
++                                        MAJOR, E_INVALID_VALUE,
++                                        ("vpri should get values of 0-7 "));
++                            if (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType
++                                    == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN)
++                            {
++                                int i;
++
++                                if (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.vpriDefVal
++                                        > 7)
++                                    RETURN_ERROR(
++                                            MAJOR,
++                                            E_INVALID_VALUE,
++                                            ("vpriDefVal should get values of 0-7 "));
++                                for (i = 0; i < FM_PCD_MANIP_DSCP_TO_VLAN_TRANS;
++                                        i++)
++                                    if (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.dscpToVpriTable[i]
++                                            & 0xf0)
++                                        RETURN_ERROR(
++                                                MAJOR,
++                                                E_INVALID_VALUE,
++                                                ("dscpToVpriTabl value out of range (0-15)"));
++                            }
++
++                        }
++
++                        p_Manip->opcode = HMAN_OC;
++                        p_Manip->muramAllocate = TRUE;
++                        p_Manip->fieldUpdate = TRUE;
++                    }
++                    else
++                        if (p_ManipParams->u.hdr.custom)
++                        {
++                            if (p_ManipParams->u.hdr.customParams.type == e_FM_PCD_MANIP_HDR_CUSTOM_GEN_FIELD_REPLACE)
++                            {
++
++                            if ((p_ManipParams->u.hdr.customParams.u.genFieldReplace.size == 0) ||
++                                    (p_ManipParams->u.hdr.customParams.u.genFieldReplace.size > 8))
++                                RETURN_ERROR(
++                                        MAJOR, E_INVALID_VALUE,
++                                        ("size should get values of 1-8 "));
++
++                            if (p_ManipParams->u.hdr.customParams.u.genFieldReplace.srcOffset > 7)
++                                RETURN_ERROR(
++                                        MAJOR, E_INVALID_VALUE,
++                                        ("srcOffset should be <= 7"));
++
++                            if ((p_ManipParams->u.hdr.customParams.u.genFieldReplace.srcOffset +
++                                    p_ManipParams->u.hdr.customParams.u.genFieldReplace.size) > 8)
++                                RETURN_ERROR(
++                                        MAJOR, E_INVALID_VALUE,
++                                        ("(srcOffset + size) should be <= 8"));
++
++                            if ((p_ManipParams->u.hdr.customParams.u.genFieldReplace.dstOffset +
++                                    p_ManipParams->u.hdr.customParams.u.genFieldReplace.size) > 256)
++                                RETURN_ERROR(
++                                        MAJOR, E_INVALID_VALUE,
++                                        ("(dstOffset + size) should be <= 256"));
++
++                            }
++
++                            p_Manip->opcode = HMAN_OC;
++                            p_Manip->muramAllocate = TRUE;
++                            p_Manip->custom = TRUE;
++                        }
++            break;
++        case e_FM_PCD_MANIP_REASSEM:
++            if (p_ManipParams->h_NextManip)
++                RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
++                             ("next manip with reassembly"));
++            switch (p_ManipParams->u.reassem.hdr)
++            {
++                case (HEADER_TYPE_IPv4):
++                    p_Manip->reassmParams.hdr = HEADER_TYPE_IPv4;
++                    p_Manip->opcode = HMAN_OC_IP_REASSEMBLY;
++                    break;
++                case (HEADER_TYPE_IPv6):
++                    p_Manip->reassmParams.hdr = HEADER_TYPE_IPv6;
++                    p_Manip->opcode = HMAN_OC_IP_REASSEMBLY;
++                    break;
++#if (DPAA_VERSION >= 11)
++                case (HEADER_TYPE_CAPWAP):
++                    p_Manip->reassmParams.hdr = HEADER_TYPE_CAPWAP;
++                    p_Manip->opcode = HMAN_OC_CAPWAP_REASSEMBLY;
++                    break;
++#endif /* (DPAA_VERSION >= 11) */
++                default:
++                    RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
++                                 ("header for reassembly"));
++            }
++            break;
++        case e_FM_PCD_MANIP_FRAG:
++            if (p_ManipParams->h_NextManip)
++                RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
++                             ("next manip with fragmentation"));
++            switch (p_ManipParams->u.frag.hdr)
++            {
++                case (HEADER_TYPE_IPv4):
++                case (HEADER_TYPE_IPv6):
++                    p_Manip->opcode = HMAN_OC_IP_FRAGMENTATION;
++                    break;
++#if (DPAA_VERSION >= 11)
++                case (HEADER_TYPE_CAPWAP):
++                    p_Manip->opcode = HMAN_OC_CAPWAP_FRAGMENTATION;
++                    break;
++#endif /* (DPAA_VERSION >= 11) */
++                default:
++                    RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
++                                 ("header for fragmentation"));
++            }
++            p_Manip->muramAllocate = TRUE;
++            break;
++        case e_FM_PCD_MANIP_SPECIAL_OFFLOAD:
++            switch (p_ManipParams->u.specialOffload.type)
++            {
++                case (e_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC):
++                    p_Manip->opcode = HMAN_OC_IPSEC_MANIP;
++                    p_Manip->muramAllocate = TRUE;
++                    break;
++#if (DPAA_VERSION >= 11)
++                case (e_FM_PCD_MANIP_SPECIAL_OFFLOAD_CAPWAP):
++                    p_Manip->opcode = HMAN_OC_CAPWAP_MANIP;
++                    p_Manip->muramAllocate = TRUE;
++                    break;
++#endif /* (DPAA_VERSION >= 11) */
++                default:
++                    RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
++                                 ("special offload type"));
++            }
++            break;
++        default:
++            RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("manip type"));
++    }
++
++    return E_OK;
++}
++#endif /* not (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++
++static t_Error UpdateIndxStats(t_Handle h_FmPcd,
++        t_Handle h_FmPort,
++        t_FmPcdManip *p_Manip)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    uint32_t tmpReg32 = 0;
++    t_AdOfTypeContLookup *p_Ad;
++    t_FmPortGetSetCcParams fmPortGetSetCcParams;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE);
++
++    p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
++    if (p_Manip->h_FmPcd != h_FmPcd)
++    RETURN_ERROR(MAJOR, E_INVALID_STATE,
++            ("handler of PCD previously was initiated by different value"));
++
++    memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams));
++
++    if (!p_Manip->p_StatsTbl)
++    {
++
++        fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNDN;
++        fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_CC;
++        err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
++        if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++        tmpReg32 = GET_UINT32(p_Ad->ccAdBase);
++
++        p_Manip->p_StatsTbl =
++        (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
++                (uint32_t)p_Manip->owner * FM_PCD_MANIP_INDEXED_STATS_ENTRY_SIZE,
++                4);
++        if (!p_Manip->p_StatsTbl)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for Manipulation indexed statistics table"));
++
++        MemSet8(p_Manip->p_StatsTbl, 0, (uint32_t)(p_Manip->owner * 4));
++
++        tmpReg32 |= (uint32_t)(XX_VirtToPhys(p_Manip->p_StatsTbl) - p_FmPcd->physicalMuramBase);
++
++        if (p_Manip->cnia)
++        tmpReg32 |= FM_PCD_MANIP_INDEXED_STATS_CNIA;
++
++        tmpReg32 |= FM_PCD_MANIP_INDEXED_STATS_DPD;
++        WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
++    }
++    else
++    {
++        fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNDN;
++        fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_CC;
++        err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
++        if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    return E_OK;
++}
++
++static t_Error RmvHdrTillSpecLocNOrInsrtIntFrmHdr(t_FmPcdManipHdrRmvParams *p_ManipParams, t_FmPcdManip *p_Manip)
++{
++    t_AdOfTypeContLookup *p_Ad;
++    uint32_t tmpReg32 = 0;
++    uint8_t prsArrayOffset = 0;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip,E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_ManipParams,E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE);
++
++    p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
++    if (p_Manip->rmv)
++    {
++        err = GetPrOffsetByHeaderOrField(&p_ManipParams->u.byHdr.u.fromStartByHdr.hdrInfo, &prsArrayOffset);
++        if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++        tmpReg32 |= (uint32_t)prsArrayOffset << 24;
++        tmpReg32 |= HMAN_RMV_HDR;
++    }
++
++    if (p_Manip->insrt)
++    tmpReg32 |= HMAN_INSRT_INT_FRM_HDR;
++
++    tmpReg32 |= (uint32_t)HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR;
++
++    WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
++
++    tmpReg32 = 0;
++    tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
++    WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
++
++    return E_OK;
++}
++
++static t_Error MvIntFrameHeaderFromFrameToBufferPrefix(t_FmPcdManip *p_Manip,
++        bool caamUsed)
++{
++    t_AdOfTypeContLookup *p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
++    uint32_t tmpReg32 = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_Ad, E_INVALID_HANDLE);
++
++    p_Manip->updateParams |= OFFSET_OF_PR | INTERNAL_CONTEXT_OFFSET;
++
++    tmpReg32 = 0;
++    tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
++    *(uint32_t *)&p_Ad->ccAdBase = tmpReg32;
++
++    tmpReg32 = 0;
++    tmpReg32 |= HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX;
++    tmpReg32 |= (uint32_t)0x16 << 16;
++    *(uint32_t *)&p_Ad->pcAndOffsets = tmpReg32;
++
++    if (caamUsed)
++    *(uint32_t *)&p_Ad->gmask = 0xf0000000;
++
++    return E_OK;
++}
++
++static t_Error CapwapRmvDtlsHdr(t_FmPcd *p_FmPcd, t_FmPcdManip *p_Manip)
++{
++    t_AdOfTypeContLookup *p_Ad;
++    uint32_t tmpReg32 = 0;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE);
++
++    p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
++
++    tmpReg32 = 0;
++    tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST;
++    WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
++
++    tmpReg32 = 0;
++    tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
++
++
++    if (p_Manip->h_Frag)
++    {
++        p_Manip->updateParams |= INTERNAL_CONTEXT_OFFSET;
++        tmpReg32 |= (uint32_t)(XX_VirtToPhys(p_Manip->h_Frag) - (p_FmPcd->physicalMuramBase));
++    }
++
++    WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
++
++    return err;
++}
++
++static t_Error CapwapReassembly(t_CapwapReassemblyParams *p_ManipParams,
++        t_FmPcdManip *p_Manip,
++        t_FmPcd *p_FmPcd,
++        uint8_t poolId)
++{
++    t_Handle p_Table;
++    uint32_t tmpReg32 = 0;
++    int i = 0;
++    uint8_t log2Num;
++    uint8_t numOfSets;
++    uint32_t j = 0;
++    uint32_t bitFor1Micro;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
++
++    if (!p_FmPcd->h_Hc)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,("hc port has to be initialized in this mode"));
++    if (!POWER_OF_2(p_ManipParams->timeoutRoutineRequestTime))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("timeoutRoutineRequestTime has to be power of 2"));
++    if (!POWER_OF_2(p_ManipParams->maxNumFramesInProcess))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,("maxNumFramesInProcess has to be power of 2"));
++    if (!p_ManipParams->timeoutRoutineRequestTime && p_ManipParams->timeoutThresholdForReassmProcess)
++        DBG(WARNING, ("if timeoutRoutineRequestTime 0,  timeoutThresholdForReassmProcess is uselessly"));
++    if (p_ManipParams->numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH)
++    {
++        if ((p_ManipParams->maxNumFramesInProcess < 4) ||
++                (p_ManipParams->maxNumFramesInProcess > 512))
++        RETURN_ERROR(MAJOR,E_INVALID_VALUE, ("In the case of numOfFramesPerHashEntry = e_FM_PCD_MANIP_EIGHT_WAYS_HASH maxNumFramesInProcess has to be in the range 4-512"));
++    }
++    else
++    {
++        if ((p_ManipParams->maxNumFramesInProcess < 8) ||
++                (p_ManipParams->maxNumFramesInProcess > 2048))
++        RETURN_ERROR(MAJOR,E_INVALID_VALUE, ("In the case of numOfFramesPerHashEntry = e_FM_PCD_MANIP_FOUR_WAYS_HASH maxNumFramesInProcess has to be in the range 8-2048"));
++    }
++
++    bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm);
++    if (bitFor1Micro == 0)
++        RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale"));
++
++    p_Manip->updateParams |= (NUM_OF_TASKS | OFFSET_OF_PR | OFFSET_OF_DATA | HW_PORT_ID);
++
++    p_Manip->h_Frag = (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
++            FM_PCD_MANIP_CAPWAP_REASM_TABLE_SIZE,
++            FM_PCD_MANIP_CAPWAP_REASM_TABLE_ALIGN);
++    if (!p_Manip->h_Frag)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc CAPWAP reassembly parameters table"));
++
++    MemSet8(p_Manip->h_Frag, 0, FM_PCD_MANIP_CAPWAP_REASM_TABLE_SIZE);
++
++    p_Table = (t_CapwapReasmPram *)p_Manip->h_Frag;
++
++    p_Manip->capwapFragParams.p_AutoLearnHashTbl =
++    (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
++            (uint32_t)(p_ManipParams->maxNumFramesInProcess * 2 * FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE),
++            FM_PCD_MANIP_CAPWAP_REASM_TABLE_ALIGN);
++
++    if (!p_Manip->capwapFragParams.p_AutoLearnHashTbl)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY,("MURAM alloc for CAPWAP automatic learning hash table"));
++
++    MemSet8(p_Manip->capwapFragParams.p_AutoLearnHashTbl, 0, (uint32_t)(p_ManipParams->maxNumFramesInProcess * 2 * FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE));
++
++    tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_AutoLearnHashTbl) - p_FmPcd->physicalMuramBase);
++
++    WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->autoLearnHashTblPtr, tmpReg32);
++
++    tmpReg32 = 0;
++    if (p_ManipParams->timeOutMode == e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAMES)
++        tmpReg32 |= FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_BETWEEN_FRAMES;
++    if (p_ManipParams->haltOnDuplicationFrag)
++        tmpReg32 |= FM_PCD_MANIP_CAPWAP_REASM_HALT_ON_DUPLICATE_FRAG;
++    if (p_ManipParams->numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH)
++    {
++        i = 8;
++        tmpReg32 |= FM_PCD_MANIP_CAPWAP_REASM_AUTOMATIC_LEARNIN_HASH_8_WAYS;
++    }
++    else
++    i = 4;
++
++    numOfSets = (uint8_t)((p_ManipParams->maxNumFramesInProcess * 2) / i);
++    LOG2(numOfSets, log2Num);
++    tmpReg32 |= (uint32_t)(log2Num - 1) << 24;
++
++    WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->mode, tmpReg32);
++
++    for (j=0; j<p_ManipParams->maxNumFramesInProcess*2; j++)
++        if (((j / i) % 2)== 0)
++            WRITE_UINT32(*(uint32_t *)PTR_MOVE(p_Manip->capwapFragParams.p_AutoLearnHashTbl, j * FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE), 0x80000000);
++
++    tmpReg32 = 0x00008000;
++    tmpReg32 |= (uint32_t)poolId << 16;
++    WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->bufferPoolIdAndRisc1SetIndexes, tmpReg32);
++    WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->risc23SetIndexes, 0x80008000);
++    WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->risc4SetIndexesAndExtendedStatsTblPtr, 0x80000000);
++
++    p_Manip->capwapFragParams.maxNumFramesInProcess = p_ManipParams->maxNumFramesInProcess;
++
++    p_Manip->capwapFragParams.sgBpid = poolId;
++
++    p_Manip->capwapFragParams.fqidForTimeOutFrames = p_ManipParams->fqidForTimeOutFrames;
++    p_Manip->capwapFragParams.timeoutRoutineRequestTime = p_ManipParams->timeoutRoutineRequestTime;
++    p_Manip->capwapFragParams.bitFor1Micro = bitFor1Micro;
++
++    tmpReg32 = 0;
++    tmpReg32 |= (((uint32_t)1<<p_Manip->capwapFragParams.bitFor1Micro) * p_ManipParams->timeoutThresholdForReassmProcess);
++    WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->expirationDelay, tmpReg32);
++
++    return E_OK;
++}
++
++static t_Error CapwapFragmentation(t_CapwapFragmentationParams *p_ManipParams,
++        t_FmPcdManip *p_Manip,
++        t_FmPcd *p_FmPcd,
++        uint8_t poolId)
++{
++    t_AdOfTypeContLookup *p_Ad;
++    uint32_t tmpReg32 = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE);
++
++    p_Manip->updateParams |= OFFSET_OF_DATA;
++
++    p_Manip->frag = TRUE;
++
++    p_Manip->h_Frag = (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
++            FM_PCD_CC_AD_ENTRY_SIZE,
++            FM_PCD_CC_AD_TABLE_ALIGN);
++    if (!p_Manip->h_Frag)
++    RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP fragmentation table descriptor"));
++
++    MemSet8(p_Manip->h_Frag, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++    p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Frag;
++
++    tmpReg32 = 0;
++    tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_FRAGMENTATION;
++
++    if (p_ManipParams->headerOptionsCompr)
++    tmpReg32 |= FM_PCD_MANIP_CAPWAP_FRAG_COMPR_OPTION_FIELD_EN;
++    tmpReg32 |= ((uint32_t)poolId << 8);
++    WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
++
++    tmpReg32 = 0;
++    tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
++    WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
++
++    p_Manip->sizeForFragmentation = p_ManipParams->sizeForFragmentation;
++    p_Manip->capwapFragParams.sgBpid = poolId;
++
++    return E_OK;
++}
++
++static t_Error IndxStats(t_FmPcdStatsParams *p_StatsParams,t_FmPcdManip *p_Manip,t_FmPcd *p_FmPcd)
++{
++    t_AdOfTypeContLookup *p_Ad;
++    uint32_t tmpReg32 = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE);
++
++    UNUSED(p_FmPcd);
++
++    p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
++
++    tmpReg32 = 0;
++    tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_INDEXED_STATS;
++    if (p_StatsParams->type == e_FM_PCD_STATS_PER_FLOWID)
++    tmpReg32 |= (uint32_t)0x16 << 16;
++    WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
++
++    tmpReg32 = 0;
++    tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
++    WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
++
++    return E_OK;
++}
++
++static t_Error InsrtHdrByTempl(t_FmPcdManipHdrInsrtParams *p_ManipParams, t_FmPcdManip *p_Manip, t_FmPcd *p_FmPcd)
++{
++    t_FmPcdManipHdrInsrtByTemplateParams *p_InsrtByTemplate = &p_ManipParams->u.byTemplate;
++    uint8_t tmpReg8 = 0xff;
++    t_AdOfTypeContLookup *p_Ad;
++    bool ipModify = FALSE;
++    uint32_t tmpReg32 = 0, tmpRegNia = 0;
++    uint16_t tmpReg16 = 0;
++    t_Error err = E_OK;
++    uint8_t extraAddedBytes = 0, blockSize = 0, extraAddedBytesAlignedToBlockSize = 0, log2Num = 0;
++    uint8_t *p_Template = NULL;
++
++    SANITY_CHECK_RETURN_ERROR(p_ManipParams,E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_Manip,E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd,E_NULL_POINTER);
++
++    p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
++    if (p_Manip->insrt)
++    {
++        if ((!p_InsrtByTemplate->size && p_InsrtByTemplate->modifyOuterIp) ||
++                (!p_InsrtByTemplate->size && p_InsrtByTemplate->modifyOuterVlan))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : asking for header template modifications with no template for insertion (template size)"));
++
++        if (p_InsrtByTemplate->size && p_InsrtByTemplate->modifyOuterIp && (p_InsrtByTemplate->size <= p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : size of template < ipOuterOffset"));
++
++        if (p_InsrtByTemplate->size > 128)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Size of header template for insertion can not be more than 128"));
++
++        if (p_InsrtByTemplate->size)
++        {
++            p_Manip->p_Template = (uint8_t *)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
++                    p_InsrtByTemplate->size,
++                    FM_PCD_CC_AD_TABLE_ALIGN);
++            if(!p_Manip->p_Template)
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation in MURAM FAILED"));
++
++            tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->p_Template) - (p_FmPcd->physicalMuramBase));
++            tmpReg32 |= (uint32_t)p_InsrtByTemplate->size << 24;
++            *(uint32_t *)&p_Ad->matchTblPtr = tmpReg32;
++        }
++
++        tmpReg32 = 0;
++
++        p_Template = (uint8_t *)XX_Malloc(p_InsrtByTemplate->size * sizeof(uint8_t));
++
++        if (!p_Template)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("XX_Malloc allocation FAILED"));
++
++        memcpy(p_Template, p_InsrtByTemplate->hdrTemplate, p_InsrtByTemplate->size * sizeof(uint8_t));
++
++        if (p_InsrtByTemplate->modifyOuterIp)
++        {
++            ipModify = TRUE;
++
++            tmpReg8 = (uint8_t)p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset];
++
++            if((tmpReg8 & 0xf0) == 0x40)
++            tmpReg8 = 4;
++            else if((tmpReg8 & 0xf0) == 0x60)
++            tmpReg8 = 6;
++            else
++            tmpReg8 = 0xff;
++
++            if (tmpReg8 != 0xff)
++            {
++                if(p_InsrtByTemplate->modifyOuterIpParams.dscpEcn & 0xff00)
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : IPV4 present in header template, dscpEcn has to be only 1 byte"));
++                if(p_InsrtByTemplate->modifyOuterIpParams.recalculateLength)
++                {
++
++                    if((p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedAlignedToBlockSize + p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedNotAlignedToBlockSize) > 255)
++                    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("extra Byte added can not be more than 256 bytes"));
++                    extraAddedBytes = (uint8_t) (p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedAlignedToBlockSize + p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedNotAlignedToBlockSize);
++                    blockSize = p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.blockSize;
++                    extraAddedBytesAlignedToBlockSize = p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedAlignedToBlockSize;
++                    /*IP header template - IP totalLength -
++                     (1 byte) extraByteForIp = headerTemplateSize - ipOffset + insertedBytesAfterThisStage ,
++                     in the case of SEC insertedBytesAfterThisStage - SEC trailer (21/31) + header(13)
++                     second byte - extraByteForIp = headerTemplate - ipOffset + insertedBytesAfterThisStage*/
++                }
++                if (blockSize)
++                {
++                    if (!POWER_OF_2(blockSize))
++                    RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("inputFrmPaddingUpToBlockSize has to be power of 2"));
++                }
++
++            }
++            if (tmpReg8 == 4)
++            {
++                if ((IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP + p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset) > p_InsrtByTemplate->size)
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : IP present in header template, user asked for IP modifications but ipOffset + ipTotalLengthFieldOffset in header template bigger than template size"));
++
++                p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_DSCECN_FIELD_OFFSET_FROM_IP] = (uint8_t)p_InsrtByTemplate->modifyOuterIpParams.dscpEcn;
++
++                if (blockSize)
++                blockSize -= 1;
++
++                if ((p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes) > 255)
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes has to be less than 255"));
++
++                p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_TOTALLENGTH_FIELD_OFFSET_FROM_IP + 1] = blockSize; // IPV6 - in AD instead of SEQ IND
++                p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_TOTALLENGTH_FIELD_OFFSET_FROM_IP] = (uint8_t)(p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes);// for IPV6 decrement additional 40 bytes of IPV6 heade size
++
++                p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_ID_FIELD_OFFSET_FROM_IP] = 0x00;
++                p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_ID_FIELD_OFFSET_FROM_IP + 1] = extraAddedBytesAlignedToBlockSize;
++
++                /*IP header template - relevant only for ipv4 CheckSum = 0*/
++                p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP] = 0x00;
++                p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP + 1] = 0x00;
++
++                /*UDP checksum has to be 0*/
++                if (p_InsrtByTemplate->modifyOuterIpParams.udpPresent)
++                {
++                    if ((p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + UDP_CHECKSUM_FIELD_SIZE) > p_InsrtByTemplate->size)
++                    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : UDP present according to user but (UDP offset + UDP header size) < size of header template"));
++
++                    p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP ] = 0x00;
++                    p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + 1] = 0x00;
++
++                }
++
++                if (p_InsrtByTemplate->modifyOuterIpParams.ipIdentGenId > 7)
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("ipIdentGenId has to be one out of 8 sequence number generators (0 - 7) for IP identification field"));
++
++                tmpRegNia |= (uint32_t)p_InsrtByTemplate->modifyOuterIpParams.ipIdentGenId<<24;
++            }
++            else if (tmpReg8 == 6)
++            {
++                /*TODO - add check for maximum value of blockSize;*/
++                if (blockSize)
++                LOG2(blockSize, log2Num);
++                tmpRegNia |= (uint32_t)log2Num << 24;
++
++                // for IPV6 decrement additional 40 bytes of IPV6 heade size - because IPV6 header size is not included in payloadLength
++                p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv6_PAYLOAD_LENGTH_OFFSET_FROM_IP] = (uint8_t)(p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes - 40);
++                p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv6_PAYLOAD_LENGTH_OFFSET_FROM_IP + 1] = extraAddedBytesAlignedToBlockSize;
++                if (p_InsrtByTemplate->modifyOuterIpParams.udpPresent)
++                {
++                    if ((p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + UDP_CHECKSUM_FIELD_SIZE) > p_InsrtByTemplate->size)
++                    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : UDP present according to user but (UDP offset + UDP header size) < size of header template"));
++                    if (p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv6_NEXT_HEADER_OFFSET_FROM_IP] != 0x88)
++                    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("OUr suppport is only IPv6/UDPLite"));
++                    p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_LENGTH_FIELD_OFFSET_FROM_UDP] = 0x00;
++                    p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_LENGTH_FIELD_OFFSET_FROM_UDP + 1] = 0x08;
++                    p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP] = 0x00;
++                    p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + 1] = 0x00;
++                }
++            }
++            else
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("IP version supported only IPV4"));
++        }
++
++        tmpReg32 = tmpReg16 = tmpReg8 = 0;
++        /*TODO - check it*/
++        if (p_InsrtByTemplate->modifyOuterVlan)
++        {
++            if (p_InsrtByTemplate->modifyOuterVlanParams.vpri & ~0x07)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE,("Inconsistent parameters : user asked for VLAN modifications but VPRI more than 3 bits"));
++
++            memcpy(&tmpReg16, &p_Template[VLAN_TAG_FIELD_OFFSET_FROM_ETH], 2*(sizeof(uint8_t)));
++            if ((tmpReg16 != 0x9100) && (tmpReg16!= 0x9200) && (tmpReg16 != 0x8100))
++            RETURN_ERROR(MAJOR, E_INVALID_STATE,("Inconsistent parameters : user asked for VLAN modifications but Tag Protocol identifier is not VLAN "));
++
++            memcpy(&tmpReg8, &p_Template[14],1*(sizeof(uint8_t)));
++            tmpReg8 &= 0x1f;
++            tmpReg8 |= (uint8_t)(p_InsrtByTemplate->modifyOuterVlanParams.vpri << 5);
++
++            p_Template[14] = tmpReg8;
++        }
++
++        MemCpy8(p_Manip->p_Template, p_Template, p_InsrtByTemplate->size);
++
++        XX_Free(p_Template);
++    }
++
++    tmpReg32 = 0;
++    if (p_Manip->h_Frag)
++    {
++        tmpRegNia |= (uint32_t)(XX_VirtToPhys(p_Manip->h_Frag) - (p_FmPcd->physicalMuramBase));
++        tmpReg32 |= (uint32_t)p_Manip->sizeForFragmentation << 16;
++    }
++    else
++    tmpReg32 = 0xffff0000;
++
++    if (ipModify)
++    tmpReg32 |= (uint32_t)p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset << 8;
++    else
++    tmpReg32 |= (uint32_t)0x0000ff00;
++
++    tmpReg32 |= (uint32_t)HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER;
++    *(uint32_t *)&p_Ad->pcAndOffsets = tmpReg32;
++
++    tmpRegNia |= FM_PCD_AD_CONT_LOOKUP_TYPE;
++    *(uint32_t *)&p_Ad->ccAdBase = tmpRegNia;
++
++    return err;
++}
++
++static t_Error CheckStatsParamsAndSetType(t_FmPcdManip *p_Manip, t_FmPcdStatsParams *p_StatsParams)
++{
++
++    switch (p_StatsParams->type)
++    {
++        case (e_FM_PCD_STATS_PER_FLOWID):
++        p_Manip->opcode = HMAN_OC_CAPWAP_INDEXED_STATS;
++        p_Manip->muramAllocate = TRUE;
++        break;
++        default:
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported statistics type"));
++    }
++
++    return E_OK;
++}
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++
++static t_Error FillReassmManipParams(t_FmPcdManip *p_Manip, e_NetHeaderType hdr)
++{
++    t_AdOfTypeContLookup *p_Ad;
++    t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd;
++    uint32_t tmpReg32;
++    t_Error err = E_OK;
++
++    /* Creates the Reassembly Parameters table. It contains parameters that are specific to either the IPv4 reassembly
++     function or to the IPv6 reassembly function. If both IPv4 reassembly and IPv6 reassembly are required, then
++     two separate IP Reassembly Parameter tables are required.*/
++    if ((err = CreateReassTable(p_Manip, hdr)) != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    /* Sets the first Ad register (ccAdBase) - Action Descriptor Type and Pointer to the Reassembly Parameters Table offset from MURAM*/
++    tmpReg32 = 0;
++    tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
++
++    /* Gets the required Action descriptor table pointer */
++    switch (hdr)
++    {
++        case HEADER_TYPE_IPv4:
++            p_Ad = (t_AdOfTypeContLookup *)p_Manip->reassmParams.ip.h_Ipv4Ad;
++            tmpReg32 |= (uint32_t)(XX_VirtToPhys(
++                    p_Manip->reassmParams.ip.p_Ipv4ReassTbl)
++                    - (p_FmPcd->physicalMuramBase));
++            break;
++        case HEADER_TYPE_IPv6:
++            p_Ad = (t_AdOfTypeContLookup *)p_Manip->reassmParams.ip.h_Ipv6Ad;
++            tmpReg32 |= (uint32_t)(XX_VirtToPhys(
++                    p_Manip->reassmParams.ip.p_Ipv6ReassTbl)
++                    - (p_FmPcd->physicalMuramBase));
++            break;
++        case HEADER_TYPE_CAPWAP:
++            p_Ad = (t_AdOfTypeContLookup *)p_Manip->reassmParams.capwap.h_Ad;
++            tmpReg32 |= (uint32_t)(XX_VirtToPhys(
++                    p_Manip->reassmParams.capwap.p_ReassTbl)
++                    - (p_FmPcd->physicalMuramBase));
++            break;
++        default:
++            RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("header type"));
++    }
++
++    WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
++
++    /* Sets the second Ad register (matchTblPtr) - Buffer pool ID (BPID for V2) and Scatter/Gather table offset*/
++    /* mark the Scatter/Gather table offset to be set later on when the port will be known */
++    p_Manip->updateParams = (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK);
++
++    if ((hdr == HEADER_TYPE_IPv6) || (hdr == HEADER_TYPE_IPv4))
++    {
++#if (DPAA_VERSION == 10)
++        tmpReg32 = (uint32_t)(p_Manip->reassmParams.sgBpid << 8);
++        WRITE_UINT32(p_Ad->matchTblPtr, tmpReg32);
++#endif /* (DPAA_VERSION == 10) */
++#if (DPAA_VERSION >= 11)
++        if (p_Manip->reassmParams.ip.nonConsistentSpFqid != 0)
++        {
++            tmpReg32 = FM_PCD_AD_NCSPFQIDM_MASK
++                    | (uint32_t)(p_Manip->reassmParams.ip.nonConsistentSpFqid);
++            WRITE_UINT32(p_Ad->gmask, tmpReg32);
++        }
++#endif /* (DPAA_VERSION >= 11) */
++        /* Sets the third Ad register (pcAndOffsets)- IP Reassemble Operation Code*/
++        tmpReg32 = 0;
++        tmpReg32 |= (uint32_t)HMAN_OC_IP_REASSEMBLY;
++    }
++#if (DPAA_VERSION >= 11)
++    else
++        if (hdr == HEADER_TYPE_CAPWAP)
++        {
++            tmpReg32 = 0;
++            tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_REASSEMBLY;
++        }
++#endif /* (DPAA_VERSION >= 11) */
++
++    WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
++
++    p_Manip->reassm = TRUE;
++
++    return E_OK;
++}
++
++static t_Error SetIpv4ReassmManip(t_FmPcdManip *p_Manip)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd;
++
++    /* Allocation if IPv4 Action descriptor */
++    p_Manip->reassmParams.ip.h_Ipv4Ad = (t_Handle)XX_MallocSmart(
++            FM_PCD_CC_AD_ENTRY_SIZE, p_Manip->reassmParams.dataMemId,
++            FM_PCD_CC_AD_TABLE_ALIGN);
++    if (!p_Manip->reassmParams.ip.h_Ipv4Ad)
++    {
++        ReleaseManipHandler(p_Manip, p_FmPcd);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                     ("Allocation of IPv4 table descriptor"));
++    }
++
++    memset(p_Manip->reassmParams.ip.h_Ipv4Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++    /* Fill reassembly manipulation parameter in the IP Reassembly Action Descriptor */
++    return FillReassmManipParams(p_Manip, HEADER_TYPE_IPv4);
++}
++
++static t_Error SetIpv6ReassmManip(t_FmPcdManip *p_Manip)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd;
++
++    /* Allocation if IPv6 Action descriptor */
++    p_Manip->reassmParams.ip.h_Ipv6Ad = (t_Handle)XX_MallocSmart(
++            FM_PCD_CC_AD_ENTRY_SIZE, p_Manip->reassmParams.dataMemId,
++            FM_PCD_CC_AD_TABLE_ALIGN);
++    if (!p_Manip->reassmParams.ip.h_Ipv6Ad)
++    {
++        ReleaseManipHandler(p_Manip, p_FmPcd);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                     ("Allocation of IPv6 table descriptor"));
++    }
++
++    memset(p_Manip->reassmParams.ip.h_Ipv6Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++    /* Fill reassembly manipulation parameter in the IP Reassembly Action Descriptor */
++    return FillReassmManipParams(p_Manip, HEADER_TYPE_IPv6);
++}
++
++static t_Error IpReassembly(t_FmPcdManipReassemParams *p_ManipReassmParams,
++                            t_FmPcdManip *p_Manip)
++{
++    uint32_t maxSetNumber = 10000;
++    t_FmPcdManipReassemIpParams reassmManipParams =
++            p_ManipReassmParams->u.ipReassem;
++    t_Error res;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip->h_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(((t_FmPcd *)p_Manip->h_FmPcd)->h_Hc,
++                              E_INVALID_HANDLE);
++
++    /* Check validation of user's parameter.*/
++    if ((reassmManipParams.timeoutThresholdForReassmProcess < 1000)
++            || (reassmManipParams.timeoutThresholdForReassmProcess > 8000000))
++        RETURN_ERROR(
++                MAJOR, E_INVALID_VALUE,
++                ("timeoutThresholdForReassmProcess should be 1msec - 8sec"));
++    /* It is recommended that the total number of entries in this table (number of sets * number of ways)
++     will be twice the number of frames that are expected to be reassembled simultaneously.*/
++    if (reassmManipParams.maxNumFramesInProcess
++            > (reassmManipParams.maxNumFramesInProcess * maxSetNumber / 2))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("maxNumFramesInProcess has to be less than (maximun set number * number of ways / 2)"));
++
++    if ((p_ManipReassmParams->hdr == HEADER_TYPE_IPv6)
++            && (reassmManipParams.minFragSize[1] < 256))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("minFragSize[1] must be >= 256"));
++
++    /* Saves user's reassembly manipulation parameters */
++    p_Manip->reassmParams.ip.relativeSchemeId[0] =
++            reassmManipParams.relativeSchemeId[0];
++    p_Manip->reassmParams.ip.relativeSchemeId[1] =
++            reassmManipParams.relativeSchemeId[1];
++    p_Manip->reassmParams.ip.numOfFramesPerHashEntry[0] =
++            reassmManipParams.numOfFramesPerHashEntry[0];
++    p_Manip->reassmParams.ip.numOfFramesPerHashEntry[1] =
++            reassmManipParams.numOfFramesPerHashEntry[1];
++    p_Manip->reassmParams.ip.minFragSize[0] = reassmManipParams.minFragSize[0];
++    p_Manip->reassmParams.ip.minFragSize[1] = reassmManipParams.minFragSize[1];
++    p_Manip->reassmParams.maxNumFramesInProcess =
++            reassmManipParams.maxNumFramesInProcess;
++    p_Manip->reassmParams.timeOutMode = reassmManipParams.timeOutMode;
++    p_Manip->reassmParams.fqidForTimeOutFrames =
++            reassmManipParams.fqidForTimeOutFrames;
++    p_Manip->reassmParams.timeoutThresholdForReassmProcess =
++            reassmManipParams.timeoutThresholdForReassmProcess;
++    p_Manip->reassmParams.dataMemId = reassmManipParams.dataMemId;
++    p_Manip->reassmParams.dataLiodnOffset = reassmManipParams.dataLiodnOffset;
++#if (DPAA_VERSION == 10)
++    p_Manip->reassmParams.sgBpid = reassmManipParams.sgBpid;
++#endif /* (DPAA_VERSION == 10) */
++#if (DPAA_VERSION >= 11)
++    if (reassmManipParams.nonConsistentSpFqid != 0)
++    {
++        p_Manip->reassmParams.ip.nonConsistentSpFqid =
++                reassmManipParams.nonConsistentSpFqid;
++    }
++#endif /* (DPAA_VERSION >= 11) */
++
++    /* Creates and initializes the IP Reassembly common parameter table */
++    CreateReassCommonTable(p_Manip);
++
++    /* Creation of IPv4 reassembly manipulation */
++    if ((p_Manip->reassmParams.hdr == HEADER_TYPE_IPv6)
++            || (p_Manip->reassmParams.hdr == HEADER_TYPE_IPv4))
++    {
++        res = SetIpv4ReassmManip(p_Manip);
++        if (res != E_OK)
++            return res;
++    }
++
++    /* Creation of IPv6 reassembly manipulation */
++    if (p_Manip->reassmParams.hdr == HEADER_TYPE_IPv6)
++    {
++        res = SetIpv6ReassmManip(p_Manip);
++        if (res != E_OK)
++            return res;
++    }
++
++    return E_OK;
++}
++
++static void setIpReassmSchemeParams(t_FmPcd* p_FmPcd,
++                                    t_FmPcdKgSchemeParams *p_Scheme,
++                                    t_Handle h_CcTree, bool ipv4,
++                                    uint8_t groupId)
++{
++    uint32_t j;
++    uint8_t res;
++
++    /* Configures scheme's network environment parameters */
++    p_Scheme->netEnvParams.numOfDistinctionUnits = 2;
++    if (ipv4)
++        res = FmPcdNetEnvGetUnitId(
++                p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv),
++                HEADER_TYPE_IPv4, FALSE, 0);
++    else
++        res = FmPcdNetEnvGetUnitId(
++                p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv),
++                HEADER_TYPE_IPv6, FALSE, 0);
++    ASSERT_COND(res != FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
++    p_Scheme->netEnvParams.unitIds[0] = res;
++
++    res = FmPcdNetEnvGetUnitId(
++            p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv),
++            HEADER_TYPE_USER_DEFINED_SHIM2, FALSE, 0);
++    ASSERT_COND(res != FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
++    p_Scheme->netEnvParams.unitIds[1] = res;
++
++    /* Configures scheme's next engine parameters*/
++    p_Scheme->nextEngine = e_FM_PCD_CC;
++    p_Scheme->kgNextEngineParams.cc.h_CcTree = h_CcTree;
++    p_Scheme->kgNextEngineParams.cc.grpId = groupId;
++    p_Scheme->useHash = TRUE;
++
++    /* Configures scheme's key*/
++    if (ipv4 == TRUE)
++    {
++        p_Scheme->keyExtractAndHashParams.numOfUsedExtracts = 4;
++        p_Scheme->keyExtractAndHashParams.extractArray[0].type =
++                e_FM_PCD_EXTRACT_BY_HDR;
++        p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.type =
++                e_FM_PCD_EXTRACT_FULL_FIELD;
++        p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.hdr =
++                HEADER_TYPE_IPv4;
++        p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.extractByHdrType.fullField.ipv4 =
++                NET_HEADER_FIELD_IPv4_DST_IP;
++        p_Scheme->keyExtractAndHashParams.extractArray[1].type =
++                e_FM_PCD_EXTRACT_BY_HDR;
++        p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.type =
++                e_FM_PCD_EXTRACT_FULL_FIELD;
++        p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.hdr =
++                HEADER_TYPE_IPv4;
++        p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.extractByHdrType.fullField.ipv4 =
++                NET_HEADER_FIELD_IPv4_SRC_IP;
++        p_Scheme->keyExtractAndHashParams.extractArray[2].type =
++                e_FM_PCD_EXTRACT_BY_HDR;
++        p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.type =
++                e_FM_PCD_EXTRACT_FULL_FIELD;
++        p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.hdr =
++                HEADER_TYPE_IPv4;
++        p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.extractByHdrType.fullField.ipv4 =
++                NET_HEADER_FIELD_IPv4_PROTO;
++        p_Scheme->keyExtractAndHashParams.extractArray[3].type =
++                e_FM_PCD_EXTRACT_BY_HDR;
++        p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.hdr =
++                HEADER_TYPE_IPv4;
++        p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.type =
++                e_FM_PCD_EXTRACT_FROM_HDR;
++        p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.ignoreProtocolValidation =
++                FALSE;
++        p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.extractByHdrType.fromHdr.size =
++                2;
++        p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.extractByHdrType.fromHdr.offset =
++                4;
++    }
++    else /* IPv6 */
++    {
++        p_Scheme->keyExtractAndHashParams.numOfUsedExtracts = 3;
++        p_Scheme->keyExtractAndHashParams.extractArray[0].type =
++                e_FM_PCD_EXTRACT_BY_HDR;
++        p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.type =
++                e_FM_PCD_EXTRACT_FULL_FIELD;
++        p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.hdr =
++                HEADER_TYPE_IPv6;
++        p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.extractByHdrType.fullField.ipv6 =
++                NET_HEADER_FIELD_IPv6_DST_IP;
++        p_Scheme->keyExtractAndHashParams.extractArray[1].type =
++                e_FM_PCD_EXTRACT_BY_HDR;
++        p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.type =
++                e_FM_PCD_EXTRACT_FULL_FIELD;
++        p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.hdr =
++                HEADER_TYPE_IPv6;
++        p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.extractByHdrType.fullField.ipv6 =
++                NET_HEADER_FIELD_IPv6_SRC_IP;
++        p_Scheme->keyExtractAndHashParams.extractArray[2].type =
++                e_FM_PCD_EXTRACT_BY_HDR;
++        p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.hdr =
++                HEADER_TYPE_USER_DEFINED_SHIM2;
++        p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.type =
++                e_FM_PCD_EXTRACT_FROM_HDR;
++        p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.extractByHdrType.fromHdr.size =
++                4;
++        p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.extractByHdrType.fromHdr.offset =
++                4;
++        p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.ignoreProtocolValidation =
++                TRUE;
++    }
++
++    p_Scheme->keyExtractAndHashParams.privateDflt0 = 0x01020304;
++    p_Scheme->keyExtractAndHashParams.privateDflt1 = 0x11121314;
++    p_Scheme->keyExtractAndHashParams.numOfUsedDflts =
++            FM_PCD_KG_NUM_OF_DEFAULT_GROUPS;
++    for (j = 0; j < FM_PCD_KG_NUM_OF_DEFAULT_GROUPS; j++)
++    {
++        p_Scheme->keyExtractAndHashParams.dflts[j].type =
++                (e_FmPcdKgKnownFieldsDfltTypes)j; /* all types */
++        p_Scheme->keyExtractAndHashParams.dflts[j].dfltSelect =
++                e_FM_PCD_KG_DFLT_GBL_0;
++    }
++}
++
++static t_Error IpReassemblyStats(t_FmPcdManip *p_Manip,
++                                 t_FmPcdManipReassemIpStats *p_Stats)
++{
++    ASSERT_COND(p_Manip);
++    ASSERT_COND(p_Stats);
++    ASSERT_COND(p_Manip->reassmParams.p_ReassCommonTbl);
++
++    p_Stats->timeout =
++            GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalTimeOutCounter);
++    p_Stats->rfdPoolBusy =
++            GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalRfdPoolBusyCounter);
++    p_Stats->internalBufferBusy =
++            GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalInternalBufferBusy);
++    p_Stats->externalBufferBusy =
++            GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalExternalBufferBusy);
++    p_Stats->sgFragments =
++            GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalSgFragmentCounter);
++    p_Stats->dmaSemaphoreDepletion =
++            GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalDmaSemaphoreDepletionCounter);
++#if (DPAA_VERSION >= 11)
++    p_Stats->nonConsistentSp =
++            GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalNCSPCounter);
++#endif /* (DPAA_VERSION >= 11) */
++
++    if (p_Manip->reassmParams.ip.p_Ipv4ReassTbl)
++    {
++        p_Stats->specificHdrStatistics[0].successfullyReassembled =
++                GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalSuccessfullyReasmFramesCounter);
++        p_Stats->specificHdrStatistics[0].validFragments =
++                GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalValidFragmentCounter);
++        p_Stats->specificHdrStatistics[0].processedFragments =
++                GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalProcessedFragCounter);
++        p_Stats->specificHdrStatistics[0].malformedFragments =
++                GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalMalformdFragCounter);
++        p_Stats->specificHdrStatistics[0].autoLearnBusy =
++                GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalSetBusyCounter);
++        p_Stats->specificHdrStatistics[0].discardedFragments =
++                GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalDiscardedFragsCounter);
++        p_Stats->specificHdrStatistics[0].moreThan16Fragments =
++                GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalMoreThan16FramesCounter);
++    }
++    if (p_Manip->reassmParams.ip.p_Ipv6ReassTbl)
++    {
++        p_Stats->specificHdrStatistics[1].successfullyReassembled =
++                GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalSuccessfullyReasmFramesCounter);
++        p_Stats->specificHdrStatistics[1].validFragments =
++                GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalValidFragmentCounter);
++        p_Stats->specificHdrStatistics[1].processedFragments =
++                GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalProcessedFragCounter);
++        p_Stats->specificHdrStatistics[1].malformedFragments =
++                GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalMalformdFragCounter);
++        p_Stats->specificHdrStatistics[1].autoLearnBusy =
++                GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalSetBusyCounter);
++        p_Stats->specificHdrStatistics[1].discardedFragments =
++                GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalDiscardedFragsCounter);
++        p_Stats->specificHdrStatistics[1].moreThan16Fragments =
++                GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalMoreThan16FramesCounter);
++    }
++    return E_OK;
++}
++
++static t_Error IpFragmentationStats(t_FmPcdManip *p_Manip,
++                                    t_FmPcdManipFragIpStats *p_Stats)
++{
++    t_AdOfTypeContLookup *p_Ad;
++
++    ASSERT_COND(p_Manip);
++    ASSERT_COND(p_Stats);
++    ASSERT_COND(p_Manip->h_Ad);
++    ASSERT_COND(p_Manip->fragParams.p_Frag);
++
++    p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
++
++    p_Stats->totalFrames = GET_UINT32(p_Ad->gmask);
++    p_Stats->fragmentedFrames = GET_UINT32(p_Manip->fragParams.p_Frag->ccAdBase)
++            & 0x00ffffff;
++    p_Stats->generatedFragments =
++            GET_UINT32(p_Manip->fragParams.p_Frag->matchTblPtr);
++
++    return E_OK;
++}
++
++static t_Error IpFragmentation(t_FmPcdManipFragIpParams *p_ManipParams,
++                               t_FmPcdManip *p_Manip)
++{
++    uint32_t pcAndOffsetsReg = 0, ccAdBaseReg = 0, gmaskReg = 0;
++    t_FmPcd *p_FmPcd;
++#if (DPAA_VERSION == 10)
++    t_Error err = E_OK;
++#endif /* (DPAA_VERSION == 10) */
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_ManipParams->sizeForFragmentation != 0xFFFF,
++                              E_INVALID_VALUE);
++
++    p_FmPcd = p_Manip->h_FmPcd;
++    /* Allocation of fragmentation Action Descriptor */
++    p_Manip->fragParams.p_Frag = (t_AdOfTypeContLookup *)FM_MURAM_AllocMem(
++            p_FmPcd->h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE,
++            FM_PCD_CC_AD_TABLE_ALIGN);
++    if (!p_Manip->fragParams.p_Frag)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                     ("MURAM alloc for Fragmentation table descriptor"));
++    MemSet8(p_Manip->fragParams.p_Frag, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++    /* Prepare the third Ad register (pcAndOffsets)- OperationCode */
++    pcAndOffsetsReg = (uint32_t)HMAN_OC_IP_FRAGMENTATION;
++
++    /* Prepare the first Ad register (ccAdBase) - Don't frag action and Action descriptor type*/
++    ccAdBaseReg = FM_PCD_AD_CONT_LOOKUP_TYPE;
++    ccAdBaseReg |= (p_ManipParams->dontFragAction
++            << FM_PCD_MANIP_IP_FRAG_DF_SHIFT);
++
++
++    /* Set Scatter/Gather BPid */
++    if (p_ManipParams->sgBpidEn)
++    {
++        ccAdBaseReg |= FM_PCD_MANIP_IP_FRAG_SG_BDID_EN;
++        pcAndOffsetsReg |= ((p_ManipParams->sgBpid
++                << FM_PCD_MANIP_IP_FRAG_SG_BDID_SHIFT)
++                & FM_PCD_MANIP_IP_FRAG_SG_BDID_MASK);
++    }
++
++    /* Prepare the first Ad register (gmask) - scratch buffer pool id and Pointer to fragment ID */
++    gmaskReg = (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_FmPcd->ipv6FrameIdAddr))
++            - p_FmPcd->physicalMuramBase);
++#if (DPAA_VERSION == 10)
++    gmaskReg |= p_ManipParams->scratchBpid << FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID;
++#else
++    gmaskReg |= (0xFF) << FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID;
++#endif /* (DPAA_VERSION == 10) */
++
++    /* Set all Ad registers */
++    WRITE_UINT32(p_Manip->fragParams.p_Frag->pcAndOffsets, pcAndOffsetsReg);
++    WRITE_UINT32(p_Manip->fragParams.p_Frag->ccAdBase, ccAdBaseReg);
++    WRITE_UINT32(p_Manip->fragParams.p_Frag->gmask, gmaskReg);
++
++    /* Saves user's fragmentation manipulation parameters */
++    p_Manip->frag = TRUE;
++    p_Manip->sizeForFragmentation = p_ManipParams->sizeForFragmentation;
++
++#if (DPAA_VERSION == 10)
++    p_Manip->fragParams.scratchBpid = p_ManipParams->scratchBpid;
++
++    /* scratch buffer pool initialization */
++    if ((err = FmPcdFragHcScratchPoolFill((t_Handle)p_FmPcd, p_ManipParams->scratchBpid)) != E_OK)
++    {
++        FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->fragParams.p_Frag);
++        p_Manip->fragParams.p_Frag = NULL;
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++#endif /* (DPAA_VERSION == 10) */
++
++    return E_OK;
++}
++
++static t_Error IPManip(t_FmPcdManip *p_Manip)
++{
++    t_Error err = E_OK;
++    t_FmPcd *p_FmPcd;
++    t_AdOfTypeContLookup *p_Ad;
++    uint32_t tmpReg32 = 0, tmpRegNia = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
++    p_FmPcd = p_Manip->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++
++    p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
++
++    tmpReg32 = FM_PCD_MANIP_IP_NO_FRAGMENTATION;
++    if (p_Manip->frag == TRUE)
++    {
++        tmpRegNia = (uint32_t)(XX_VirtToPhys(p_Manip->fragParams.p_Frag)
++                - (p_FmPcd->physicalMuramBase));
++        tmpReg32 = (uint32_t)p_Manip->sizeForFragmentation
++                << FM_PCD_MANIP_IP_MTU_SHIFT;
++    }
++
++    tmpRegNia |= FM_PCD_AD_CONT_LOOKUP_TYPE;
++    tmpReg32 |= HMAN_OC_IP_MANIP;
++
++#if (DPAA_VERSION >= 11)
++    tmpRegNia |= FM_PCD_MANIP_IP_CNIA;
++#endif /* (DPAA_VERSION >= 11) */
++
++    WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
++    WRITE_UINT32(p_Ad->ccAdBase, tmpRegNia);
++    WRITE_UINT32(p_Ad->gmask, 0);
++    /* Total frame counter - MUST be initialized to zero.*/
++
++    return err;
++}
++
++static t_Error UpdateInitIpFrag(t_Handle h_FmPcd, t_Handle h_PcdParams,
++                                t_Handle h_FmPort, t_FmPcdManip *p_Manip,
++                                t_Handle h_Ad, bool validate)
++{
++    t_FmPortGetSetCcParams fmPortGetSetCcParams;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Manip->opcode == HMAN_OC_IP_FRAGMENTATION),
++                              E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
++
++    UNUSED(h_FmPcd);
++    UNUSED(h_Ad);
++    UNUSED(h_PcdParams);
++    UNUSED(validate);
++    UNUSED(p_Manip);
++
++    fmPortGetSetCcParams.setCcParams.type = 0;
++    fmPortGetSetCcParams.getCcParams.type = MANIP_EXTRA_SPACE;
++    if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    if (!fmPortGetSetCcParams.getCcParams.internalBufferOffset)
++        DBG(WARNING, ("manipExtraSpace must be larger than '0'"));
++
++    return E_OK;
++}
++
++static t_Error IPSecManip(t_FmPcdManipParams *p_ManipParams,
++                          t_FmPcdManip *p_Manip)
++{
++    t_AdOfTypeContLookup *p_Ad;
++    t_FmPcdManipSpecialOffloadIPSecParams *p_IPSecParams;
++    t_Error err = E_OK;
++    uint32_t tmpReg32 = 0;
++    uint32_t power;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_ManipParams, E_INVALID_HANDLE);
++
++    p_IPSecParams = &p_ManipParams->u.specialOffload.u.ipsec;
++
++    SANITY_CHECK_RETURN_ERROR(
++            !p_IPSecParams->variableIpHdrLen || p_IPSecParams->decryption,
++            E_INVALID_VALUE);
++    SANITY_CHECK_RETURN_ERROR(
++            !p_IPSecParams->variableIpVersion || !p_IPSecParams->decryption,
++            E_INVALID_VALUE);
++    SANITY_CHECK_RETURN_ERROR(
++            !p_IPSecParams->variableIpVersion || p_IPSecParams->outerIPHdrLen,
++            E_INVALID_VALUE);
++    SANITY_CHECK_RETURN_ERROR(
++            !p_IPSecParams->arwSize || p_IPSecParams->arwAddr,
++            E_INVALID_VALUE);
++    SANITY_CHECK_RETURN_ERROR(
++            !p_IPSecParams->arwSize || p_IPSecParams->decryption,
++            E_INVALID_VALUE);
++    SANITY_CHECK_RETURN_ERROR((p_IPSecParams->arwSize % 16) == 0, E_INVALID_VALUE);
++
++    p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
++
++    tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
++    tmpReg32 |= (p_IPSecParams->decryption) ? FM_PCD_MANIP_IPSEC_DEC : 0;
++    tmpReg32 |= (p_IPSecParams->ecnCopy) ? FM_PCD_MANIP_IPSEC_ECN_EN : 0;
++    tmpReg32 |= (p_IPSecParams->dscpCopy) ? FM_PCD_MANIP_IPSEC_DSCP_EN : 0;
++    tmpReg32 |=
++            (p_IPSecParams->variableIpHdrLen) ? FM_PCD_MANIP_IPSEC_VIPL_EN : 0;
++    tmpReg32 |=
++            (p_IPSecParams->variableIpVersion) ? FM_PCD_MANIP_IPSEC_VIPV_EN : 0;
++    if (p_IPSecParams->arwSize)
++        tmpReg32 |= (uint32_t)((XX_VirtToPhys(UINT_TO_PTR(p_IPSecParams->arwAddr))-FM_MM_MURAM)
++                & (FM_MURAM_SIZE-1));
++    WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
++
++    tmpReg32 = 0;
++    if (p_IPSecParams->arwSize) {
++        NEXT_POWER_OF_2((p_IPSecParams->arwSize + 32), power);
++        LOG2(power, power);
++        tmpReg32 = (p_IPSecParams->arwSize | (power - 5)) << FM_PCD_MANIP_IPSEC_ARW_SIZE_SHIFT;
++    }
++
++    if (p_ManipParams->h_NextManip)
++        tmpReg32 |=
++                (uint32_t)(XX_VirtToPhys(((t_FmPcdManip *)p_ManipParams->h_NextManip)->h_Ad)-
++                        (((t_FmPcd *)p_Manip->h_FmPcd)->physicalMuramBase)) >> 4;
++    WRITE_UINT32(p_Ad->matchTblPtr, tmpReg32);
++
++    tmpReg32 = HMAN_OC_IPSEC_MANIP;
++    tmpReg32 |= p_IPSecParams->outerIPHdrLen
++            << FM_PCD_MANIP_IPSEC_IP_HDR_LEN_SHIFT;
++    if (p_ManipParams->h_NextManip)
++        tmpReg32 |= FM_PCD_MANIP_IPSEC_NADEN;
++    WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
++
++    return err;
++}
++
++static t_Error SetCapwapReassmManip(t_FmPcdManip *p_Manip)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd;
++
++    /* Allocation if CAPWAP Action descriptor */
++    p_Manip->reassmParams.capwap.h_Ad = (t_Handle)XX_MallocSmart(
++            FM_PCD_CC_AD_ENTRY_SIZE, p_Manip->reassmParams.dataMemId,
++            FM_PCD_CC_AD_TABLE_ALIGN);
++    if (!p_Manip->reassmParams.capwap.h_Ad)
++    {
++        ReleaseManipHandler(p_Manip, p_FmPcd);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                     ("Allocation of CAPWAP table descriptor"));
++    }
++
++    memset(p_Manip->reassmParams.capwap.h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++    /* Fill reassembly manipulation parameter in the Reassembly Action Descriptor */
++    return FillReassmManipParams(p_Manip, HEADER_TYPE_CAPWAP);
++}
++
++static void setCapwapReassmSchemeParams(t_FmPcd* p_FmPcd,
++                                        t_FmPcdKgSchemeParams *p_Scheme,
++                                        t_Handle h_CcTree, uint8_t groupId)
++{
++    uint8_t res;
++
++    /* Configures scheme's network environment parameters */
++    p_Scheme->netEnvParams.numOfDistinctionUnits = 1;
++    res = FmPcdNetEnvGetUnitId(
++            p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv),
++            HEADER_TYPE_USER_DEFINED_SHIM2, FALSE, 0);
++    ASSERT_COND(res != FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
++    p_Scheme->netEnvParams.unitIds[0] = res;
++
++    /* Configures scheme's next engine parameters*/
++    p_Scheme->nextEngine = e_FM_PCD_CC;
++    p_Scheme->kgNextEngineParams.cc.h_CcTree = h_CcTree;
++    p_Scheme->kgNextEngineParams.cc.grpId = groupId;
++    p_Scheme->useHash = TRUE;
++
++    /* Configures scheme's key*/
++    p_Scheme->keyExtractAndHashParams.numOfUsedExtracts = 2;
++    p_Scheme->keyExtractAndHashParams.extractArray[0].type =
++            e_FM_PCD_EXTRACT_NON_HDR;
++    p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.src =
++            e_FM_PCD_EXTRACT_FROM_PARSE_RESULT;
++    p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.action =
++            e_FM_PCD_ACTION_NONE;
++    p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.offset = 20;
++    p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.size = 4;
++    p_Scheme->keyExtractAndHashParams.extractArray[1].type =
++            e_FM_PCD_EXTRACT_NON_HDR;
++    p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.src =
++            e_FM_PCD_EXTRACT_FROM_DFLT_VALUE;
++    p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.action =
++            e_FM_PCD_ACTION_NONE;
++    p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.offset = 0;
++    p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.size = 1;
++
++    p_Scheme->keyExtractAndHashParams.privateDflt0 = 0x0;
++    p_Scheme->keyExtractAndHashParams.privateDflt1 = 0x0;
++    p_Scheme->keyExtractAndHashParams.numOfUsedDflts = 1;
++    p_Scheme->keyExtractAndHashParams.dflts[0].type = e_FM_PCD_KG_GENERIC_NOT_FROM_DATA;
++    p_Scheme->keyExtractAndHashParams.dflts[0].dfltSelect = e_FM_PCD_KG_DFLT_PRIVATE_0;
++}
++
++#if (DPAA_VERSION >= 11)
++static t_Error CapwapReassemblyStats(t_FmPcdManip *p_Manip,
++                                     t_FmPcdManipReassemCapwapStats *p_Stats)
++{
++    ASSERT_COND(p_Manip);
++    ASSERT_COND(p_Stats);
++    ASSERT_COND(p_Manip->reassmParams.p_ReassCommonTbl);
++
++    p_Stats->timeout =
++            GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalTimeOutCounter);
++    p_Stats->rfdPoolBusy =
++            GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalRfdPoolBusyCounter);
++    p_Stats->internalBufferBusy =
++            GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalInternalBufferBusy);
++    p_Stats->externalBufferBusy =
++            GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalExternalBufferBusy);
++    p_Stats->sgFragments =
++            GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalSgFragmentCounter);
++    p_Stats->dmaSemaphoreDepletion =
++            GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalDmaSemaphoreDepletionCounter);
++    p_Stats->exceedMaxReassemblyFrameLen =
++            GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalNCSPCounter);
++
++    p_Stats->successfullyReassembled =
++            GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalSuccessfullyReasmFramesCounter);
++    p_Stats->validFragments =
++            GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalValidFragmentCounter);
++    p_Stats->processedFragments =
++            GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalProcessedFragCounter);
++    p_Stats->malformedFragments =
++            GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalMalformdFragCounter);
++    p_Stats->autoLearnBusy =
++            GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalSetBusyCounter);
++    p_Stats->discardedFragments =
++            GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalDiscardedFragsCounter);
++    p_Stats->moreThan16Fragments =
++            GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalMoreThan16FramesCounter);
++
++    return E_OK;
++}
++
++static t_Error CapwapFragmentationStats(t_FmPcdManip *p_Manip,
++              t_FmPcdManipFragCapwapStats *p_Stats)
++{
++      t_AdOfTypeContLookup *p_Ad;
++
++      ASSERT_COND(p_Manip);
++      ASSERT_COND(p_Stats);
++      ASSERT_COND(p_Manip->h_Ad);
++      ASSERT_COND(p_Manip->fragParams.p_Frag);
++
++      p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
++
++      p_Stats->totalFrames = GET_UINT32(p_Ad->gmask);
++
++      return E_OK;
++}
++
++static t_Error CapwapReassembly(t_FmPcdManipReassemParams *p_ManipReassmParams,
++                                t_FmPcdManip *p_Manip)
++{
++    uint32_t maxSetNumber = 10000;
++    t_FmPcdManipReassemCapwapParams reassmManipParams =
++            p_ManipReassmParams->u.capwapReassem;
++    t_Error res;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip->h_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(((t_FmPcd *)p_Manip->h_FmPcd)->h_Hc,
++                              E_INVALID_HANDLE);
++
++    /* Check validation of user's parameter.*/
++    if ((reassmManipParams.timeoutThresholdForReassmProcess < 1000)
++            || (reassmManipParams.timeoutThresholdForReassmProcess > 8000000))
++        RETURN_ERROR(
++                MAJOR, E_INVALID_VALUE,
++                ("timeoutThresholdForReassmProcess should be 1msec - 8sec"));
++    /* It is recommended that the total number of entries in this table (number of sets * number of ways)
++     will be twice the number of frames that are expected to be reassembled simultaneously.*/
++    if (reassmManipParams.maxNumFramesInProcess
++            > (reassmManipParams.maxNumFramesInProcess * maxSetNumber / 2))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("maxNumFramesInProcess has to be less than (maximun set number * number of ways / 2)"));
++
++    /* Saves user's reassembly manipulation parameters */
++    p_Manip->reassmParams.capwap.relativeSchemeId =
++            reassmManipParams.relativeSchemeId;
++    p_Manip->reassmParams.capwap.numOfFramesPerHashEntry =
++            reassmManipParams.numOfFramesPerHashEntry;
++    p_Manip->reassmParams.capwap.maxRessembledsSize =
++            reassmManipParams.maxReassembledFrameLength;
++    p_Manip->reassmParams.maxNumFramesInProcess =
++            reassmManipParams.maxNumFramesInProcess;
++    p_Manip->reassmParams.timeOutMode = reassmManipParams.timeOutMode;
++    p_Manip->reassmParams.fqidForTimeOutFrames =
++            reassmManipParams.fqidForTimeOutFrames;
++    p_Manip->reassmParams.timeoutThresholdForReassmProcess =
++            reassmManipParams.timeoutThresholdForReassmProcess;
++    p_Manip->reassmParams.dataMemId = reassmManipParams.dataMemId;
++    p_Manip->reassmParams.dataLiodnOffset = reassmManipParams.dataLiodnOffset;
++
++    /* Creates and initializes the Reassembly common parameter table */
++    CreateReassCommonTable(p_Manip);
++
++    res = SetCapwapReassmManip(p_Manip);
++    if (res != E_OK)
++        return res;
++
++    return E_OK;
++}
++
++static t_Error CapwapFragmentation(t_FmPcdManipFragCapwapParams *p_ManipParams,
++                                   t_FmPcdManip *p_Manip)
++{
++    t_FmPcd *p_FmPcd;
++    t_AdOfTypeContLookup *p_Ad;
++    uint32_t pcAndOffsetsReg = 0, ccAdBaseReg = 0, gmaskReg = 0;
++    uint32_t tmpReg32 = 0, tmpRegNia = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_ManipParams->sizeForFragmentation != 0xFFFF,
++                              E_INVALID_VALUE);
++    p_FmPcd = p_Manip->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++
++    /* Allocation of fragmentation Action Descriptor */
++    p_Manip->fragParams.p_Frag = (t_AdOfTypeContLookup *)FM_MURAM_AllocMem(
++            p_FmPcd->h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE,
++            FM_PCD_CC_AD_TABLE_ALIGN);
++    if (!p_Manip->fragParams.p_Frag)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                     ("MURAM alloc for Fragmentation table descriptor"));
++    MemSet8(p_Manip->fragParams.p_Frag, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++    /* Prepare the third Ad register (pcAndOffsets)- OperationCode */
++    pcAndOffsetsReg = (uint32_t)HMAN_OC_CAPWAP_FRAGMENTATION;
++
++    /* Prepare the first Ad register (ccAdBase) - Don't frag action and Action descriptor type*/
++    ccAdBaseReg = FM_PCD_AD_CONT_LOOKUP_TYPE;
++    ccAdBaseReg |=
++            (p_ManipParams->compressModeEn) ? FM_PCD_MANIP_CAPWAP_FRAG_COMPRESS_EN :
++                    0;
++
++    /* Set Scatter/Gather BPid */
++    if (p_ManipParams->sgBpidEn)
++    {
++        ccAdBaseReg |= FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_EN;
++        pcAndOffsetsReg |= ((p_ManipParams->sgBpid
++                << FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_SHIFT)
++                & FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_MASK);
++    }
++
++    /* Prepare the first Ad register (gmask) - scratch buffer pool id and Pointer to fragment ID */
++    gmaskReg = (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_FmPcd->capwapFrameIdAddr))
++            - p_FmPcd->physicalMuramBase);
++    gmaskReg |= (0xFF) << FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID;
++
++    /* Set all Ad registers */
++    WRITE_UINT32(p_Manip->fragParams.p_Frag->pcAndOffsets, pcAndOffsetsReg);
++    WRITE_UINT32(p_Manip->fragParams.p_Frag->ccAdBase, ccAdBaseReg);
++    WRITE_UINT32(p_Manip->fragParams.p_Frag->gmask, gmaskReg);
++
++    /* Saves user's fragmentation manipulation parameters */
++    p_Manip->frag = TRUE;
++    p_Manip->sizeForFragmentation = p_ManipParams->sizeForFragmentation;
++
++    p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
++
++    tmpRegNia = (uint32_t)(XX_VirtToPhys(p_Manip->fragParams.p_Frag)
++            - (p_FmPcd->physicalMuramBase));
++    tmpReg32 = (uint32_t)p_Manip->sizeForFragmentation
++            << FM_PCD_MANIP_CAPWAP_FRAG_CHECK_MTU_SHIFT;
++
++    tmpRegNia |= FM_PCD_AD_CONT_LOOKUP_TYPE;
++    tmpReg32 |= HMAN_OC_CAPWAP_FRAG_CHECK;
++
++    tmpRegNia |= FM_PCD_MANIP_CAPWAP_FRAG_CHECK_CNIA;
++
++    WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
++    WRITE_UINT32(p_Ad->ccAdBase, tmpRegNia);
++    WRITE_UINT32(p_Ad->gmask, 0);
++    /* Total frame counter - MUST be initialized to zero.*/
++
++    return E_OK;
++}
++
++static t_Error UpdateInitCapwapFrag(t_Handle h_FmPcd, t_Handle h_PcdParams,
++                                    t_Handle h_FmPort, t_FmPcdManip *p_Manip,
++                                    t_Handle h_Ad, bool validate)
++{
++    t_FmPortGetSetCcParams fmPortGetSetCcParams;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION),
++                              E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
++
++    UNUSED(h_FmPcd);
++    UNUSED(h_Ad);
++    UNUSED(h_PcdParams);
++    UNUSED(validate);
++    UNUSED(p_Manip);
++
++    fmPortGetSetCcParams.setCcParams.type = 0;
++    fmPortGetSetCcParams.getCcParams.type = MANIP_EXTRA_SPACE;
++    if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    if (!fmPortGetSetCcParams.getCcParams.internalBufferOffset)
++        DBG(WARNING, ("manipExtraSpace must be larger than '0'"));
++
++    return E_OK;
++}
++
++static t_Error CapwapManip(t_FmPcdManipParams *p_ManipParams,
++                           t_FmPcdManip *p_Manip)
++{
++    t_AdOfTypeContLookup *p_Ad;
++    t_FmPcdManipSpecialOffloadCapwapParams *p_Params;
++    t_Error err = E_OK;
++    uint32_t tmpReg32 = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_ManipParams, E_INVALID_HANDLE);
++
++    p_Params = &p_ManipParams->u.specialOffload.u.capwap;
++
++    p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
++    tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
++    tmpReg32 |= (p_Params->dtls) ? FM_PCD_MANIP_CAPWAP_DTLS : 0;
++    /* TODO - add 'qosSrc' */
++    WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
++
++    tmpReg32 = HMAN_OC_CAPWAP_MANIP;
++    if (p_ManipParams->h_NextManip)
++    {
++        WRITE_UINT32(
++                p_Ad->matchTblPtr,
++                (uint32_t)(XX_VirtToPhys(((t_FmPcdManip *)p_ManipParams->h_NextManip)->h_Ad)- (((t_FmPcd *)p_Manip->h_FmPcd)->physicalMuramBase)) >> 4);
++
++        tmpReg32 |= FM_PCD_MANIP_CAPWAP_NADEN;
++    }
++
++    WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
++
++    return err;
++}
++#endif /* (DPAA_VERSION >= 11) */
++
++static t_Handle ManipOrStatsSetNode(t_Handle h_FmPcd, t_Handle *p_Params,
++                                    bool stats)
++{
++    t_FmPcdManip *p_Manip;
++    t_Error err;
++    t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
++
++    p_Manip = (t_FmPcdManip*)XX_Malloc(sizeof(t_FmPcdManip));
++    if (!p_Manip)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory"));
++        return NULL;
++    }
++    memset(p_Manip, 0, sizeof(t_FmPcdManip));
++
++    p_Manip->type = ((t_FmPcdManipParams *)p_Params)->type;
++    memcpy((uint8_t*)&p_Manip->manipParams, p_Params,
++           sizeof(p_Manip->manipParams));
++
++    if (!stats)
++        err = CheckManipParamsAndSetType(p_Manip,
++                                         (t_FmPcdManipParams *)p_Params);
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++    else
++        err = CheckStatsParamsAndSetType(p_Manip, (t_FmPcdStatsParams *)p_Params);
++#else /* not (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++    else
++    {
++        REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Statistics node!"));
++        XX_Free(p_Manip);
++        return NULL;
++    }
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++    if (err)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Invalid header manipulation type"));
++        XX_Free(p_Manip);
++        return NULL;
++    }
++
++    if ((p_Manip->opcode != HMAN_OC_IP_REASSEMBLY) && (p_Manip->opcode != HMAN_OC_CAPWAP_REASSEMBLY))
++    {
++        /* In Case of reassembly manipulation the reassembly action descriptor will
++         be defines later on */
++        if (p_Manip->muramAllocate)
++        {
++            p_Manip->h_Ad = (t_Handle)FM_MURAM_AllocMem(
++                    p_FmPcd->h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE,
++                    FM_PCD_CC_AD_TABLE_ALIGN);
++            if (!p_Manip->h_Ad)
++            {
++                REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for Manipulation action descriptor"));
++                ReleaseManipHandler(p_Manip, p_FmPcd);
++                XX_Free(p_Manip);
++                return NULL;
++            }
++
++            MemSet8(p_Manip->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++        }
++        else
++        {
++            p_Manip->h_Ad = (t_Handle)XX_Malloc(
++                    FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t));
++            if (!p_Manip->h_Ad)
++            {
++                REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Allocation of Manipulation action descriptor"));
++                ReleaseManipHandler(p_Manip, p_FmPcd);
++                XX_Free(p_Manip);
++                return NULL;
++            }
++
++            memset(p_Manip->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t));
++        }
++    }
++
++    p_Manip->h_FmPcd = h_FmPcd;
++
++    return p_Manip;
++}
++
++static void UpdateAdPtrOfNodesWhichPointsOnCrntMdfManip(
++        t_FmPcdManip *p_CrntMdfManip, t_List *h_NodesLst)
++{
++    t_CcNodeInformation *p_CcNodeInformation;
++    t_FmPcdCcNode *p_NodePtrOnCurrentMdfManip = NULL;
++    t_List *p_Pos;
++    int i = 0;
++    t_Handle p_AdTablePtOnCrntCurrentMdfNode/*, p_AdTableNewModified*/;
++    t_CcNodeInformation ccNodeInfo;
++
++    LIST_FOR_EACH(p_Pos, &p_CrntMdfManip->nodesLst)
++    {
++        p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos);
++        p_NodePtrOnCurrentMdfManip =
++                (t_FmPcdCcNode *)p_CcNodeInformation->h_CcNode;
++
++        ASSERT_COND(p_NodePtrOnCurrentMdfManip);
++
++        /* Search in the previous node which exact index points on this current modified node for getting AD */
++        for (i = 0; i < p_NodePtrOnCurrentMdfManip->numOfKeys + 1; i++)
++        {
++            if (p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].nextEngineParams.nextEngine
++                    == e_FM_PCD_CC)
++            {
++                if (p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].nextEngineParams.h_Manip
++                        == (t_Handle)p_CrntMdfManip)
++                {
++                    if (p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].p_StatsObj)
++                        p_AdTablePtOnCrntCurrentMdfNode =
++                                p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].p_StatsObj->h_StatsAd;
++                    else
++                        p_AdTablePtOnCrntCurrentMdfNode =
++                                PTR_MOVE(p_NodePtrOnCurrentMdfManip->h_AdTable, i*FM_PCD_CC_AD_ENTRY_SIZE);
++
++                    memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
++                    ccNodeInfo.h_CcNode = p_AdTablePtOnCrntCurrentMdfNode;
++                    EnqueueNodeInfoToRelevantLst(h_NodesLst, &ccNodeInfo, NULL);
++                }
++            }
++        }
++
++        ASSERT_COND(i != p_NodePtrOnCurrentMdfManip->numOfKeys);
++    }
++}
++
++static void BuildHmtd(uint8_t *p_Dest, uint8_t *p_Src, uint8_t *p_Hmcd,
++                      t_FmPcd *p_FmPcd)
++{
++    t_Error err;
++
++    /* Copy the HMTD */
++    MemCpy8(p_Dest, (uint8_t*)p_Src, 16);
++    /* Replace the HMCT table pointer  */
++    WRITE_UINT32(
++            ((t_Hmtd *)p_Dest)->hmcdBasePtr,
++            (uint32_t)(XX_VirtToPhys(p_Hmcd) - ((t_FmPcd*)p_FmPcd)->physicalMuramBase));
++    /* Call Host Command to replace HMTD by a new HMTD */
++    err = FmHcPcdCcDoDynamicChange(
++            p_FmPcd->h_Hc,
++            (uint32_t)(XX_VirtToPhys(p_Src) - p_FmPcd->physicalMuramBase),
++            (uint32_t)(XX_VirtToPhys(p_Dest) - p_FmPcd->physicalMuramBase));
++    if (err)
++        REPORT_ERROR(MINOR, err, ("Failed in dynamic manip change, continued to the rest of the owners."));
++}
++
++static t_Error FmPcdManipInitUpdate(t_Handle h_FmPcd, t_Handle h_PcdParams,
++                                    t_Handle h_FmPort, t_Handle h_Manip,
++                                    t_Handle h_Ad, bool validate, int level,
++                                    t_Handle h_FmTree)
++{
++    t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE);
++
++    UNUSED(level);
++    UNUSED(h_FmTree);
++
++    switch (p_Manip->opcode)
++    {
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++        case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX):
++        err = UpdateInitMvIntFrameHeaderFromFrameToBufferPrefix(h_FmPort,
++                p_Manip,
++                h_Ad,
++                validate);
++        break;
++        case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER):
++        if (!p_Manip->h_Frag)
++        break;
++        case (HMAN_OC_CAPWAP_FRAGMENTATION):
++        err = UpdateInitCapwapFragmentation(h_FmPort, p_Manip, h_Ad, validate, h_FmTree);
++        break;
++        case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST):
++        if (p_Manip->h_Frag)
++        err = UpdateInitCapwapReasm(h_FmPcd, h_FmPort, p_Manip, h_Ad, validate);
++        break;
++        case (HMAN_OC_CAPWAP_INDEXED_STATS):
++        err = UpdateIndxStats(h_FmPcd, h_FmPort, p_Manip);
++        break;
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++        case (HMAN_OC_IP_REASSEMBLY):
++            err = UpdateInitReasm(h_FmPcd, h_PcdParams, h_FmPort, p_Manip, h_Ad,
++                                  validate);
++            break;
++        case (HMAN_OC_IP_FRAGMENTATION):
++            err = UpdateInitIpFrag(h_FmPcd, h_PcdParams, h_FmPort, p_Manip,
++                                   h_Ad, validate);
++            break;
++#if (DPAA_VERSION >= 11)
++        case (HMAN_OC_CAPWAP_FRAGMENTATION):
++            err = UpdateInitCapwapFrag(h_FmPcd, h_PcdParams, h_FmPort, p_Manip,
++                                       h_Ad, validate);
++            break;
++        case (HMAN_OC_CAPWAP_REASSEMBLY):
++            err = UpdateInitReasm(h_FmPcd, h_PcdParams, h_FmPort, p_Manip, h_Ad,
++                                  validate);
++            break;
++#endif /* (DPAA_VERSION >= 11) */
++        default:
++            return E_OK;
++    }
++
++    return err;
++}
++
++static t_Error FmPcdManipModifyUpdate(t_Handle h_Manip, t_Handle h_Ad,
++                                      bool validate, int level,
++                                      t_Handle h_FmTree)
++{
++
++    t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
++    t_Error err = E_OK;
++
++    UNUSED(level);
++
++    switch (p_Manip->opcode)
++    {
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++        case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX):
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_STATE,
++                ("modify node with this type of manipulation  is not suppported"));
++        case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST):
++
++        if (p_Manip->h_Frag)
++        {
++            if (!(p_Manip->shadowUpdateParams & NUM_OF_TASKS)
++                    && !(p_Manip->shadowUpdateParams & OFFSET_OF_DATA)
++                    && !(p_Manip->shadowUpdateParams & OFFSET_OF_PR))
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_STATE,
++                    ("modify node with this type of manipulation requires manipulation be updated previously in SetPcd function"));
++        }
++        break;
++        case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER):
++        if (p_Manip->h_Frag)
++        err = UpdateModifyCapwapFragmenation(p_Manip, h_Ad, validate, h_FmTree);
++        break;
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++        default:
++            return E_OK;
++    }
++
++    return err;
++}
++
++/*****************************************************************************/
++/*              Inter-module API routines                                    */
++/*****************************************************************************/
++
++t_Error FmPcdManipUpdate(t_Handle h_FmPcd, t_Handle h_PcdParams,
++                         t_Handle h_FmPort, t_Handle h_Manip, t_Handle h_Ad,
++                         bool validate, int level, t_Handle h_FmTree,
++                         bool modify)
++{
++    t_Error err;
++
++    if (!modify)
++        err = FmPcdManipInitUpdate(h_FmPcd, h_PcdParams, h_FmPort, h_Manip,
++                                   h_Ad, validate, level, h_FmTree);
++    else
++        err = FmPcdManipModifyUpdate(h_Manip, h_Ad, validate, level, h_FmTree);
++
++    return err;
++}
++
++void FmPcdManipUpdateOwner(t_Handle h_Manip, bool add)
++{
++
++    uint32_t intFlags;
++
++    intFlags = XX_LockIntrSpinlock(((t_FmPcdManip *)h_Manip)->h_Spinlock);
++    if (add)
++        ((t_FmPcdManip *)h_Manip)->owner++;
++    else
++    {
++        ASSERT_COND(((t_FmPcdManip *)h_Manip)->owner);
++        ((t_FmPcdManip *)h_Manip)->owner--;
++    }
++    XX_UnlockIntrSpinlock(((t_FmPcdManip *)h_Manip)->h_Spinlock, intFlags);
++}
++
++t_List *FmPcdManipGetNodeLstPointedOnThisManip(t_Handle h_Manip)
++{
++    ASSERT_COND(h_Manip);
++    return &((t_FmPcdManip *)h_Manip)->nodesLst;
++}
++
++t_List *FmPcdManipGetSpinlock(t_Handle h_Manip)
++{
++    ASSERT_COND(h_Manip);
++    return ((t_FmPcdManip *)h_Manip)->h_Spinlock;
++}
++
++t_Error FmPcdManipCheckParamsForCcNextEngine(
++        t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams,
++        uint32_t *requiredAction)
++{
++    t_FmPcdManip *p_Manip;
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++    t_Error err = E_OK;
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))*/
++    bool pointFromCc = TRUE;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams->h_Manip,
++                              E_NULL_POINTER);
++
++    p_Manip = (t_FmPcdManip *)(p_FmPcdCcNextEngineParams->h_Manip);
++    *requiredAction = 0;
++
++    while (p_Manip)
++    {
++        switch (p_Manip->opcode)
++        {
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++            case (HMAN_OC_CAPWAP_INDEXED_STATS):
++                if (p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_DONE)
++                    RETURN_ERROR(MAJOR,       E_INVALID_STATE, ("For this type of header manipulation has to be nextEngine e_FM_PCD_DONE"));
++                if (p_FmPcdCcNextEngineParams->params.enqueueParams.overrideFqid)
++                    p_Manip->cnia = TRUE;
++            case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST):
++                *requiredAction = UPDATE_NIA_ENQ_WITHOUT_DMA;
++            case (HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR):
++                p_Manip->ownerTmp++;
++                break;
++            case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER):
++                if ((p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_DONE)
++                    && !p_FmPcdCcNextEngineParams->params.enqueueParams.overrideFqid)
++                    RETURN_ERROR(
++                        MAJOR,
++                        E_INVALID_STATE,
++                        ("For this type of header manipulation has to be nextEngine e_FM_PCD_DONE with fqidForCtrlFlow FALSE"));
++                p_Manip->ownerTmp++;
++                break;
++            case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX):
++                if ((p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_CC)
++                    && (FmPcdCcGetParseCode(p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode)
++                        != CC_PC_GENERIC_IC_HASH_INDEXED))
++                    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("For this type of header manipulation next engine has to be CC and action = e_FM_PCD_ACTION_INDEXED_LOOKUP"));
++                err = UpdateManipIc(p_FmPcdCcNextEngineParams->h_Manip,
++                                    FmPcdCcGetOffset(p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode));
++                if (err)
++                    RETURN_ERROR(MAJOR, err, NO_MSG);
++                *requiredAction = UPDATE_NIA_ENQ_WITHOUT_DMA;
++                break;
++ #endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++            case (HMAN_OC_IP_FRAGMENTATION):
++            case (HMAN_OC_IP_REASSEMBLY):
++#if (DPAA_VERSION >= 11)
++            case (HMAN_OC_CAPWAP_REASSEMBLY):
++            case (HMAN_OC_CAPWAP_FRAGMENTATION):
++#endif /* (DPAA_VERSION >= 11) */
++                if (p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_DONE)
++                    RETURN_ERROR(
++                            MAJOR,
++                            E_INVALID_STATE,
++                            ("For this type of header manipulation has to be nextEngine e_FM_PCD_DONE"));
++                p_Manip->ownerTmp++;
++                break;
++            case (HMAN_OC_IPSEC_MANIP):
++#if (DPAA_VERSION >= 11)
++            case (HMAN_OC_CAPWAP_MANIP):
++#endif /* (DPAA_VERSION >= 11) */
++                p_Manip->ownerTmp++;
++                break;
++            case (HMAN_OC):
++                if ((p_FmPcdCcNextEngineParams->nextEngine == e_FM_PCD_CC)
++                        && MANIP_IS_CASCADED(p_Manip))
++                    RETURN_ERROR(
++                            MINOR,
++                            E_INVALID_STATE,
++                            ("Can't have a cascaded manipulation when and Next Engine is CC"));
++                if (!MANIP_IS_FIRST(p_Manip) && pointFromCc)
++                    RETURN_ERROR(
++                            MAJOR,
++                            E_INVALID_STATE,
++                            ("h_Manip is already used and may not be shared (no sharing of non-head manip nodes)"));
++                break;
++            default:
++                RETURN_ERROR(
++                        MAJOR, E_INVALID_STATE,
++                        ("invalid type of header manipulation for this state"));
++        }
++        p_Manip = p_Manip->h_NextManip;
++        pointFromCc = FALSE;
++    }
++    return E_OK;
++}
++
++
++t_Error FmPcdManipCheckParamsWithCcNodeParams(t_Handle h_Manip,
++                                              t_Handle h_FmPcdCcNode)
++{
++    t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(h_FmPcdCcNode, E_INVALID_HANDLE);
++
++    switch (p_Manip->opcode)
++    {
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++        case (HMAN_OC_CAPWAP_INDEXED_STATS):
++        if (p_Manip->ownerTmp != FmPcdCcGetNumOfKeys(h_FmPcdCcNode))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("The manipulation of the type statistics flowId if exist has to be pointed by all numOfKeys"));
++        break;
++        case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST):
++        if (p_Manip->h_Frag)
++        {
++            if (p_Manip->ownerTmp != FmPcdCcGetNumOfKeys(h_FmPcdCcNode))
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("The manipulation of the type remove DTLS if exist has to be pointed by all numOfKeys"));
++            err = UpdateManipIc(h_Manip, FmPcdCcGetOffset(h_FmPcdCcNode));
++            if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        }
++        break;
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++        default:
++            break;
++    }
++
++    return err;
++}
++
++void FmPcdManipUpdateAdResultForCc(
++        t_Handle h_Manip, t_FmPcdCcNextEngineParams *p_CcNextEngineParams,
++        t_Handle p_Ad, t_Handle *p_AdNewPtr)
++{
++    t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
++
++    /* This routine creates a Manip AD and can return in "p_AdNewPtr"
++     * either the new descriptor or NULL if it writes the Manip AD into p_AD (into the match table) */
++
++    ASSERT_COND(p_Manip);
++    ASSERT_COND(p_CcNextEngineParams);
++    ASSERT_COND(p_Ad);
++    ASSERT_COND(p_AdNewPtr);
++
++    FmPcdManipUpdateOwner(h_Manip, TRUE);
++
++    /* According to "type", either build & initialize a new AD (p_AdNew) or initialize
++     * p_Ad ( the AD in the match table) and set p_AdNew = NULL. */
++    switch (p_Manip->opcode)
++    {
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++        case (HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR):
++        case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST):
++        case (HMAN_OC_CAPWAP_INDEXED_STATS):
++        *p_AdNewPtr = p_Manip->h_Ad;
++        break;
++        case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER):
++        case (HMAN_OC_CAPWAP_FRAGMENTATION):
++        WRITE_UINT32(((t_AdOfTypeResult *)p_Ad)->fqid,
++                ((t_AdOfTypeResult *)(p_Manip->h_Ad))->fqid);
++        WRITE_UINT32(((t_AdOfTypeResult *)p_Ad)->plcrProfile,
++                ((t_AdOfTypeResult *)(p_Manip->h_Ad))->plcrProfile);
++        WRITE_UINT32(((t_AdOfTypeResult *)p_Ad)->nia,
++                ((t_AdOfTypeResult *)(p_Manip->h_Ad))->nia);
++        *p_AdNewPtr = NULL;
++        break;
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++        case (HMAN_OC_IPSEC_MANIP):
++#if (DPAA_VERSION >= 11)
++        case (HMAN_OC_CAPWAP_MANIP):
++#endif /* (DPAA_VERSION >= 11) */
++            *p_AdNewPtr = p_Manip->h_Ad;
++            break;
++        case (HMAN_OC_IP_FRAGMENTATION):
++#if (DPAA_VERSION >= 11)
++        case (HMAN_OC_CAPWAP_FRAGMENTATION):
++#endif /* (DPAA_VERSION >= 11) */
++            if ((p_CcNextEngineParams->nextEngine == e_FM_PCD_DONE)
++                    && (!p_CcNextEngineParams->params.enqueueParams.overrideFqid))
++            {
++                memcpy((uint8_t *)p_Ad, (uint8_t *)p_Manip->h_Ad,
++                       sizeof(t_AdOfTypeContLookup));
++#if (DPAA_VERSION >= 11)
++                WRITE_UINT32(
++                        ((t_AdOfTypeContLookup *)p_Ad)->ccAdBase,
++                        GET_UINT32(((t_AdOfTypeContLookup *)p_Ad)->ccAdBase) & ~FM_PCD_MANIP_IP_CNIA);
++#endif /* (DPAA_VERSION >= 11) */
++                *p_AdNewPtr = NULL;
++            }
++            else
++                *p_AdNewPtr = p_Manip->h_Ad;
++            break;
++        case (HMAN_OC_IP_REASSEMBLY):
++            if (FmPcdManipIpReassmIsIpv6Hdr(p_Manip))
++            {
++                if (!p_Manip->reassmParams.ip.ipv6Assigned)
++                {
++                    *p_AdNewPtr = p_Manip->reassmParams.ip.h_Ipv6Ad;
++                    p_Manip->reassmParams.ip.ipv6Assigned = TRUE;
++                    FmPcdManipUpdateOwner(h_Manip, FALSE);
++                }
++                else
++                {
++                    *p_AdNewPtr = p_Manip->reassmParams.ip.h_Ipv4Ad;
++                    p_Manip->reassmParams.ip.ipv6Assigned = FALSE;
++                }
++            }
++            else
++                *p_AdNewPtr = p_Manip->reassmParams.ip.h_Ipv4Ad;
++            memcpy((uint8_t *)p_Ad, (uint8_t *)*p_AdNewPtr,
++                   sizeof(t_AdOfTypeContLookup));
++            *p_AdNewPtr = NULL;
++            break;
++#if (DPAA_VERSION >= 11)
++        case (HMAN_OC_CAPWAP_REASSEMBLY):
++            *p_AdNewPtr = p_Manip->reassmParams.capwap.h_Ad;
++            memcpy((uint8_t *)p_Ad, (uint8_t *)*p_AdNewPtr,
++                   sizeof(t_AdOfTypeContLookup));
++            *p_AdNewPtr = NULL;
++            break;
++#endif /* (DPAA_VERSION >= 11) */
++        case (HMAN_OC):
++            /* Allocate and initialize HMTD */
++            *p_AdNewPtr = p_Manip->h_Ad;
++            break;
++        default:
++            break;
++    }
++}
++
++void FmPcdManipUpdateAdContLookupForCc(t_Handle h_Manip, t_Handle p_Ad,
++                                       t_Handle *p_AdNewPtr,
++                                       uint32_t adTableOffset)
++{
++    t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
++
++    /* This routine creates a Manip AD and can return in "p_AdNewPtr"
++     * either the new descriptor or NULL if it writes the Manip AD into p_AD (into the match table) */
++    ASSERT_COND(p_Manip);
++
++    FmPcdManipUpdateOwner(h_Manip, TRUE);
++
++    switch (p_Manip->opcode)
++    {
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++        case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX):
++        WRITE_UINT32(((t_AdOfTypeContLookup *)p_Ad)->ccAdBase,
++                ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->ccAdBase);
++        WRITE_UINT32(
++                ((t_AdOfTypeContLookup *)p_Ad)->matchTblPtr,
++                ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->matchTblPtr);
++        WRITE_UINT32(
++                ((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets,
++                ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->pcAndOffsets);
++        WRITE_UINT32(((t_AdOfTypeContLookup *)p_Ad)->gmask,
++                ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->gmask);
++        WRITE_UINT32(
++                ((t_AdOfTypeContLookup *)p_Ad)->ccAdBase,
++                (GET_UINT32(((t_AdOfTypeContLookup *)p_Ad)->ccAdBase) | adTableOffset));
++        *p_AdNewPtr = NULL;
++        break;
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++        case (HMAN_OC):
++            /* Initialize HMTD within the match table*/
++            MemSet8(p_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++            /* copy the existing HMTD *//* ask Alla - memcpy??? */
++            memcpy((uint8_t*)p_Ad, p_Manip->h_Ad, sizeof(t_Hmtd));
++            /* update NADEN to be "1"*/
++            WRITE_UINT16(
++                    ((t_Hmtd *)p_Ad)->cfg,
++                    (uint16_t)(GET_UINT16(((t_Hmtd *)p_Ad)->cfg) | HMTD_CFG_NEXT_AD_EN));
++            /* update next action descriptor */
++            WRITE_UINT16(((t_Hmtd *)p_Ad)->nextAdIdx,
++                         (uint16_t)(adTableOffset >> 4));
++            /* mark that Manip's HMTD is not used */
++            *p_AdNewPtr = NULL;
++            break;
++
++        default:
++            break;
++    }
++}
++
++t_Error FmPcdManipBuildIpReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv,
++                                      t_Handle h_CcTree, t_Handle h_Manip,
++                                      bool isIpv4, uint8_t groupId)
++{
++    t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
++    t_FmPcdKgSchemeParams *p_SchemeParams = NULL;
++    t_Handle h_Scheme;
++
++    ASSERT_COND(p_FmPcd);
++    ASSERT_COND(h_NetEnv);
++    ASSERT_COND(p_Manip);
++
++    /* scheme was already build, no need to check for IPv6 */
++    if (p_Manip->reassmParams.ip.h_Ipv4Scheme)
++        return E_OK;
++
++    if (isIpv4) {
++        h_Scheme = FmPcdKgGetSchemeHandle(p_FmPcd, p_Manip->reassmParams.ip.relativeSchemeId[0]);
++        if (h_Scheme) {
++            /* scheme was found */
++            p_Manip->reassmParams.ip.h_Ipv4Scheme = h_Scheme;
++            return E_OK;
++        }
++    } else {
++        h_Scheme = FmPcdKgGetSchemeHandle(p_FmPcd, p_Manip->reassmParams.ip.relativeSchemeId[1]);
++        if (h_Scheme) {
++            /* scheme was found */
++            p_Manip->reassmParams.ip.h_Ipv6Scheme = h_Scheme;
++            return E_OK;
++        }
++    }
++
++     p_SchemeParams = XX_Malloc(sizeof(t_FmPcdKgSchemeParams));
++    if (!p_SchemeParams)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                     ("Memory allocation failed for scheme"));
++
++    /* Configures the IPv4 or IPv6 scheme*/
++    memset(p_SchemeParams, 0, sizeof(t_FmPcdKgSchemeParams));
++    p_SchemeParams->netEnvParams.h_NetEnv = h_NetEnv;
++    p_SchemeParams->id.relativeSchemeId = (uint8_t)(
++            (isIpv4 == TRUE) ? p_Manip->reassmParams.ip.relativeSchemeId[0] :
++                    p_Manip->reassmParams.ip.relativeSchemeId[1]);
++    p_SchemeParams->schemeCounter.update = TRUE;
++#if (DPAA_VERSION >= 11)
++    p_SchemeParams->alwaysDirect = TRUE;
++    p_SchemeParams->bypassFqidGeneration = TRUE;
++#else
++    p_SchemeParams->keyExtractAndHashParams.hashDistributionNumOfFqids = 1;
++    p_SchemeParams->baseFqid = 0xFFFFFF; /*TODO- baseFqid*/
++#endif /* (DPAA_VERSION >= 11) */
++
++    setIpReassmSchemeParams(p_FmPcd, p_SchemeParams, h_CcTree, isIpv4, groupId);
++
++    /* Sets the new scheme */
++    if (isIpv4)
++        p_Manip->reassmParams.ip.h_Ipv4Scheme = FM_PCD_KgSchemeSet(
++                p_FmPcd, p_SchemeParams);
++    else
++        p_Manip->reassmParams.ip.h_Ipv6Scheme = FM_PCD_KgSchemeSet(
++                p_FmPcd, p_SchemeParams);
++
++    XX_Free(p_SchemeParams);
++
++    return E_OK;
++}
++
++t_Error FmPcdManipDeleteIpReassmSchemes(t_Handle h_Manip)
++{
++    t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
++
++    ASSERT_COND(p_Manip);
++
++    if ((p_Manip->reassmParams.ip.h_Ipv4Scheme) &&
++        !FmPcdKgIsSchemeHasOwners(p_Manip->reassmParams.ip.h_Ipv4Scheme))
++        FM_PCD_KgSchemeDelete(p_Manip->reassmParams.ip.h_Ipv4Scheme);
++
++    if ((p_Manip->reassmParams.ip.h_Ipv6Scheme) &&
++        !FmPcdKgIsSchemeHasOwners(p_Manip->reassmParams.ip.h_Ipv6Scheme))
++        FM_PCD_KgSchemeDelete(p_Manip->reassmParams.ip.h_Ipv6Scheme);
++
++    return E_OK;
++}
++
++bool FmPcdManipIpReassmIsIpv6Hdr(t_Handle h_Manip)
++{
++    t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
++
++    ASSERT_COND(p_Manip);
++
++    return (p_Manip->reassmParams.hdr == HEADER_TYPE_IPv6);
++}
++
++t_Error FmPcdManipBuildCapwapReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv,
++                                          t_Handle h_CcTree, t_Handle h_Manip,
++                                          uint8_t groupId)
++{
++    t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
++    t_FmPcdKgSchemeParams *p_SchemeParams = NULL;
++
++    ASSERT_COND(p_FmPcd);
++    ASSERT_COND(h_NetEnv);
++    ASSERT_COND(p_Manip);
++
++    /* scheme was already build, no need to check for IPv6 */
++    if (p_Manip->reassmParams.capwap.h_Scheme)
++        return E_OK;
++
++    p_SchemeParams = XX_Malloc(sizeof(t_FmPcdKgSchemeParams));
++    if (!p_SchemeParams)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY,
++                     ("Memory allocation failed for scheme"));
++
++    memset(p_SchemeParams, 0, sizeof(t_FmPcdKgSchemeParams));
++    p_SchemeParams->netEnvParams.h_NetEnv = h_NetEnv;
++    p_SchemeParams->id.relativeSchemeId =
++            (uint8_t)p_Manip->reassmParams.capwap.relativeSchemeId;
++    p_SchemeParams->schemeCounter.update = TRUE;
++    p_SchemeParams->bypassFqidGeneration = TRUE;
++
++    setCapwapReassmSchemeParams(p_FmPcd, p_SchemeParams, h_CcTree, groupId);
++
++    p_Manip->reassmParams.capwap.h_Scheme = FM_PCD_KgSchemeSet(p_FmPcd,
++                                                               p_SchemeParams);
++
++    XX_Free(p_SchemeParams);
++
++    return E_OK;
++}
++
++t_Error FmPcdManipDeleteCapwapReassmSchemes(t_Handle h_Manip)
++{
++    t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
++
++    ASSERT_COND(p_Manip);
++
++    if (p_Manip->reassmParams.capwap.h_Scheme)
++        FM_PCD_KgSchemeDelete(p_Manip->reassmParams.capwap.h_Scheme);
++
++    return E_OK;
++}
++
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++t_Handle FmPcdManipApplSpecificBuild(void)
++{
++    t_FmPcdManip *p_Manip;
++
++    p_Manip = (t_FmPcdManip*)XX_Malloc(sizeof(t_FmPcdManip));
++    if (!p_Manip)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory"));
++        return NULL;
++    }
++    memset(p_Manip, 0, sizeof(t_FmPcdManip));
++
++    p_Manip->opcode = HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX;
++    p_Manip->muramAllocate = FALSE;
++
++    p_Manip->h_Ad = (t_Handle)XX_Malloc(FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t));
++    if (!p_Manip->h_Ad)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Allocation of Manipulation action descriptor"));
++        XX_Free(p_Manip);
++        return NULL;
++    }
++
++    memset(p_Manip->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t));
++
++    /*treatFdStatusFieldsAsErrors = TRUE hardcoded - assumption its always come after CAAM*/
++    /*Application specific = type of flowId index, move internal frame header from data to IC,
++     SEC errors check*/
++    if (MvIntFrameHeaderFromFrameToBufferPrefix(p_Manip, TRUE)!= E_OK)
++    {
++        XX_Free(p_Manip->h_Ad);
++        XX_Free(p_Manip);
++        return NULL;
++    }
++    return p_Manip;
++}
++
++bool FmPcdManipIsCapwapApplSpecific(t_Handle h_Manip)
++{
++    t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
++    ASSERT_COND(h_Manip);
++
++    return (bool)((p_Manip->opcode == HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST) ? TRUE : FALSE);
++}
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++/*********************** End of inter-module routines ************************/
++
++/****************************************/
++/*       API Init unit functions        */
++/****************************************/
++
++t_Handle FM_PCD_ManipNodeSet(t_Handle h_FmPcd,
++                             t_FmPcdManipParams *p_ManipParams)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    t_FmPcdManip *p_Manip;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(p_ManipParams, E_INVALID_HANDLE, NULL);
++
++    p_Manip = ManipOrStatsSetNode(h_FmPcd, (t_Handle)p_ManipParams, FALSE);
++    if (!p_Manip)
++        return NULL;
++
++    if (((p_Manip->opcode == HMAN_OC_IP_REASSEMBLY)
++            || (p_Manip->opcode == HMAN_OC_IP_FRAGMENTATION)
++            || (p_Manip->opcode == HMAN_OC)
++            || (p_Manip->opcode == HMAN_OC_IPSEC_MANIP)
++#if (DPAA_VERSION >= 11)
++            || (p_Manip->opcode == HMAN_OC_CAPWAP_MANIP)
++            || (p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION)
++            || (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY)
++#endif /* (DPAA_VERSION >= 11) */
++            ) && (!FmPcdIsAdvancedOffloadSupported(p_FmPcd)))
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Advanced-offload must be enabled"));
++        XX_Free(p_Manip);
++        return NULL;
++    }
++    p_Manip->h_Spinlock = XX_InitSpinlock();
++    if (!p_Manip->h_Spinlock)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE"));
++        ReleaseManipHandler(p_Manip, p_FmPcd);
++        XX_Free(p_Manip);
++        return NULL;
++    }INIT_LIST(&p_Manip->nodesLst);
++
++    switch (p_Manip->opcode)
++    {
++        case (HMAN_OC_IP_REASSEMBLY):
++            /* IpReassembly */
++            err = IpReassembly(&p_ManipParams->u.reassem, p_Manip);
++            break;
++        case (HMAN_OC_IP_FRAGMENTATION):
++            /* IpFragmentation */
++            err = IpFragmentation(&p_ManipParams->u.frag.u.ipFrag, p_Manip);
++            if (err)
++                break;
++            err = IPManip(p_Manip);
++            break;
++        case (HMAN_OC_IPSEC_MANIP):
++            err = IPSecManip(p_ManipParams, p_Manip);
++            break;
++#if (DPAA_VERSION >= 11)
++        case (HMAN_OC_CAPWAP_REASSEMBLY):
++            /* CapwapReassembly */
++            err = CapwapReassembly(&p_ManipParams->u.reassem, p_Manip);
++            break;
++        case (HMAN_OC_CAPWAP_FRAGMENTATION):
++            /* CapwapFragmentation */
++            err = CapwapFragmentation(&p_ManipParams->u.frag.u.capwapFrag,
++                                      p_Manip);
++            break;
++        case (HMAN_OC_CAPWAP_MANIP):
++            err = CapwapManip(p_ManipParams, p_Manip);
++            break;
++#endif /* (DPAA_VERSION >= 11) */
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++            case (HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR):
++            /* HmanType1 */
++            err = RmvHdrTillSpecLocNOrInsrtIntFrmHdr(&p_ManipParams->u.hdr.rmvParams, p_Manip);
++            break;
++            case (HMAN_OC_CAPWAP_FRAGMENTATION):
++            err = CapwapFragmentation(&p_ManipParams->fragOrReasmParams.u.capwapFragParams,
++                    p_Manip,
++                    p_FmPcd,
++                    p_ManipParams->fragOrReasmParams.sgBpid);
++            if (err)
++            {
++                REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE"));
++                ReleaseManipHandler(p_Manip, p_FmPcd);
++                XX_Free(p_Manip);
++                return NULL;
++            }
++            if (p_Manip->insrt)
++            p_Manip->opcode = HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER;
++            case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER):
++            /* HmanType2 + if user asked only for fragmentation still need to allocate HmanType2 */
++            err = InsrtHdrByTempl(&p_ManipParams->u.hdr.insrtParams, p_Manip, p_FmPcd);
++            break;
++            case (HMAN_OC_CAPWAP_REASSEMBLY):
++            err = CapwapReassembly(&p_ManipParams->fragOrReasmParams.u.capwapReasmParams,
++                    p_Manip,
++                    p_FmPcd,
++                    p_ManipParams->fragOrReasmParams.sgBpid);
++            if (err)
++            {
++                REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE"));
++                ReleaseManipHandler(p_Manip, p_FmPcd);
++                XX_Free(p_Manip);
++                return NULL;
++            }
++            if (p_Manip->rmv)
++            p_Manip->opcode = HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST;
++            case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST):
++            /*CAPWAP decapsulation + if user asked only for reassembly still need to allocate CAPWAP decapsulation*/
++            err = CapwapRmvDtlsHdr(p_FmPcd, p_Manip);
++            break;
++            case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX):
++            /*Application Specific type 1*/
++            err = MvIntFrameHeaderFromFrameToBufferPrefix(p_Manip, TRUE);
++            break;
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++        case (HMAN_OC):
++            /* New Manip */
++            err = CreateManipActionNew(p_Manip, p_ManipParams);
++            break;
++        default:
++            REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE"));
++            ReleaseManipHandler(p_Manip, p_FmPcd);
++            XX_Free(p_Manip);
++            return NULL;
++    }
++
++    if (err)
++    {
++        REPORT_ERROR(MAJOR, err, NO_MSG);
++        ReleaseManipHandler(p_Manip, p_FmPcd);
++        XX_Free(p_Manip);
++        return NULL;
++    }
++
++    if (p_ManipParams->h_NextManip)
++    {
++        /* in the check routine we've verified that h_NextManip has no owners
++         * and that only supported types are allowed. */
++        p_Manip->h_NextManip = p_ManipParams->h_NextManip;
++        /* save a "prev" pointer in h_NextManip */
++        MANIP_SET_PREV(p_Manip->h_NextManip, p_Manip);
++        FmPcdManipUpdateOwner(p_Manip->h_NextManip, TRUE);
++    }
++
++    return p_Manip;
++}
++
++t_Error FM_PCD_ManipNodeReplace(t_Handle h_Manip,
++                                t_FmPcdManipParams *p_ManipParams)
++{
++    t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip, *p_FirstManip;
++    t_FmPcd *p_FmPcd = (t_FmPcd *)(p_Manip->h_FmPcd);
++    t_Error err;
++    uint8_t *p_WholeHmct = NULL, *p_ShadowHmct = NULL, *p_Hmtd = NULL;
++    t_List lstOfNodeshichPointsOnCrntMdfManip, *p_Pos;
++    t_CcNodeInformation *p_CcNodeInfo;
++    SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_ManipParams, E_INVALID_HANDLE);
++
++    INIT_LIST(&lstOfNodeshichPointsOnCrntMdfManip);
++
++    if ((p_ManipParams->type != e_FM_PCD_MANIP_HDR)
++            || (p_Manip->type != e_FM_PCD_MANIP_HDR))
++        RETURN_ERROR(
++                MINOR,
++                E_NOT_SUPPORTED,
++                ("FM_PCD_ManipNodeReplace Functionality supported only for Header Manipulation."));
++
++    ASSERT_COND(p_Manip->opcode == HMAN_OC);
++    ASSERT_COND(p_Manip->manipParams.h_NextManip == p_Manip->h_NextManip);
++    memcpy((uint8_t*)&p_Manip->manipParams, p_ManipParams,
++           sizeof(p_Manip->manipParams));
++    p_Manip->manipParams.h_NextManip = p_Manip->h_NextManip;
++
++    /* The replacement of the HdrManip depends on the node type.*/
++    /*
++     * (1) If this is an independent node, all its owners should be updated.
++     *
++     * (2) If it is the head of a cascaded chain (it does not have a "prev" but
++     * it has a "next" and it has a "cascaded" indication), the next
++     * node remains unchanged, and the behavior is as in (1).
++     *
++     * (3) If it is not the head, but a part of a cascaded chain, in can be
++     * also replaced as a regular node with just one owner.
++     *
++     * (4) If it is a part of a chain implemented as a unified table, the
++     * whole table is replaced and the owners of the head node must be updated.
++     *
++     */
++    /* lock shadow */
++    if (!p_FmPcd->p_CcShadow)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("CC Shadow not allocated"));
++
++    if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
++        return ERROR_CODE(E_BUSY);
++
++    /* this routine creates a new manip action in the CC Shadow. */
++    err = CreateManipActionShadow(p_Manip, p_ManipParams);
++    if (err)
++        RETURN_ERROR(MINOR, err, NO_MSG);
++
++    /* If the owners list is empty (these are NOT the "owners" counter, but pointers from CC)
++     * replace only HMTD and no lcok is required. Otherwise
++     * lock the whole PCD
++     * In case 4 MANIP_IS_UNIFIED_NON_FIRST(p_Manip) - Use the head node instead. */
++    if (!FmPcdLockTryLockAll(p_FmPcd))
++    {
++        DBG(TRACE, ("FmPcdLockTryLockAll failed"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    p_ShadowHmct = (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow, 16);
++
++    p_FirstManip = (t_FmPcdManip*)GetManipInfo(p_Manip,
++                                               e_MANIP_HANDLER_TABLE_OWNER);
++    ASSERT_COND(p_FirstManip);
++
++    if (!LIST_IsEmpty(&p_FirstManip->nodesLst))
++        UpdateAdPtrOfNodesWhichPointsOnCrntMdfManip(
++                p_FirstManip, &lstOfNodeshichPointsOnCrntMdfManip);
++
++    p_Hmtd = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMTD);
++    ASSERT_COND(p_Hmtd);
++    BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_Hmtd, p_ShadowHmct,
++              ((t_FmPcd*)(p_Manip->h_FmPcd)));
++
++    LIST_FOR_EACH(p_Pos, &lstOfNodeshichPointsOnCrntMdfManip)
++    {
++        p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos);
++        BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_CcNodeInfo->h_CcNode,
++                  p_ShadowHmct, ((t_FmPcd*)(p_Manip->h_FmPcd)));
++    }
++
++    p_WholeHmct = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMCT);
++    ASSERT_COND(p_WholeHmct);
++
++    /* re-build the HMCT n the original location */
++    err = CreateManipActionBackToOrig(p_Manip, p_ManipParams);
++    if (err)
++    {
++        RELEASE_LOCK(p_FmPcd->shadowLock);
++        RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++
++    p_Hmtd = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMTD);
++    ASSERT_COND(p_Hmtd);
++    BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_Hmtd, p_WholeHmct,
++              ((t_FmPcd*)p_Manip->h_FmPcd));
++
++    /* If LIST > 0, create a list of p_Ad's that point to the HMCT. Join also t_HMTD to this list.
++     * For each p_Hmct (from list+fixed):
++     * call Host Command to replace HMTD by a new one */LIST_FOR_EACH(p_Pos, &lstOfNodeshichPointsOnCrntMdfManip)
++    {
++        p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos);
++        BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_CcNodeInfo->h_CcNode,
++                  p_WholeHmct, ((t_FmPcd*)(p_Manip->h_FmPcd)));
++    }
++
++
++    ReleaseLst(&lstOfNodeshichPointsOnCrntMdfManip);
++
++    FmPcdLockUnlockAll(p_FmPcd);
++
++    /* unlock shadow */
++    RELEASE_LOCK(p_FmPcd->shadowLock);
++
++    return E_OK;
++}
++
++t_Error FM_PCD_ManipNodeDelete(t_Handle h_ManipNode)
++{
++    t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_ManipNode;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
++
++    if (p_Manip->owner)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_STATE,
++                ("This manipulation node not be removed because this node is occupied, first - unbind this node "));
++
++    if (p_Manip->h_NextManip)
++    {
++        MANIP_SET_PREV(p_Manip->h_NextManip, NULL);
++        FmPcdManipUpdateOwner(p_Manip->h_NextManip, FALSE);
++    }
++
++    if (p_Manip->p_Hmct
++            && (MANIP_IS_UNIFIED_FIRST(p_Manip) || !MANIP_IS_UNIFIED(p_Manip)))
++        FM_MURAM_FreeMem(((t_FmPcd *)p_Manip->h_FmPcd)->h_FmMuram,
++                         p_Manip->p_Hmct);
++
++    if (p_Manip->h_Spinlock)
++    {
++        XX_FreeSpinlock(p_Manip->h_Spinlock);
++        p_Manip->h_Spinlock = NULL;
++    }
++
++    ReleaseManipHandler(p_Manip, p_Manip->h_FmPcd);
++
++    XX_Free(h_ManipNode);
++
++    return E_OK;
++}
++
++t_Error FM_PCD_ManipGetStatistics(t_Handle h_ManipNode,
++                                  t_FmPcdManipStats *p_FmPcdManipStats)
++{
++    t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_ManipNode;
++
++    SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcdManipStats, E_NULL_POINTER);
++
++    switch (p_Manip->opcode)
++    {
++        case (HMAN_OC_IP_REASSEMBLY):
++            return IpReassemblyStats(p_Manip,
++                                     &p_FmPcdManipStats->u.reassem.u.ipReassem);
++        case (HMAN_OC_IP_FRAGMENTATION):
++            return IpFragmentationStats(p_Manip,
++                                        &p_FmPcdManipStats->u.frag.u.ipFrag);
++#if (DPAA_VERSION >= 11)
++        case (HMAN_OC_CAPWAP_REASSEMBLY):
++            return CapwapReassemblyStats(
++                    p_Manip, &p_FmPcdManipStats->u.reassem.u.capwapReassem);
++      case (HMAN_OC_CAPWAP_FRAGMENTATION):
++              return CapwapFragmentationStats(
++                      p_Manip, &p_FmPcdManipStats->u.frag.u.capwapFrag);
++#endif /* (DPAA_VERSION >= 11) */
++        default:
++            RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
++                         ("no statistics to this type of manip"));
++    }
++
++    return E_OK;
++}
++
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++t_Handle FM_PCD_StatisticsSetNode(t_Handle h_FmPcd, t_FmPcdStatsParams *p_StatsParams)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    t_FmPcdManip *p_Manip;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmPcd,E_INVALID_HANDLE,NULL);
++    SANITY_CHECK_RETURN_VALUE(p_StatsParams,E_INVALID_HANDLE,NULL);
++
++    p_Manip = ManipOrStatsSetNode(h_FmPcd, (t_Handle)p_StatsParams, TRUE);
++    if (!p_Manip)
++    return NULL;
++
++    switch (p_Manip->opcode)
++    {
++        case (HMAN_OC_CAPWAP_INDEXED_STATS):
++        /* Indexed statistics */
++        err = IndxStats(p_StatsParams, p_Manip, p_FmPcd);
++        break;
++        default:
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED Statistics type"));
++        ReleaseManipHandler(p_Manip, p_FmPcd);
++        XX_Free(p_Manip);
++        return NULL;
++    }
++
++    if (err)
++    {
++        REPORT_ERROR(MAJOR, err, NO_MSG);
++        ReleaseManipHandler(p_Manip, p_FmPcd);
++        XX_Free(p_Manip);
++        return NULL;
++    }
++
++    return p_Manip;
++}
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.h
+@@ -0,0 +1,555 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_manip.h
++
++ @Description   FM PCD manip...
++*//***************************************************************************/
++#ifndef __FM_MANIP_H
++#define __FM_MANIP_H
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "list_ext.h"
++
++#include "fm_cc.h"
++
++
++/***********************************************************************/
++/*          Header manipulations defines                              */
++/***********************************************************************/
++
++#define NUM_OF_SCRATCH_POOL_BUFFERS             1000 /*TODO - Change it!!*/
++
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++#define HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR                      0x2e
++#define HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER              0x31
++#define HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX     0x2f
++#define HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST                        0x30
++#define HMAN_OC_CAPWAP_REASSEMBLY                               0x11 /* dummy */
++#define HMAN_OC_CAPWAP_INDEXED_STATS                            0x32 /* dummy */
++#define HMAN_OC_CAPWAP_FRAGMENTATION                            0x33
++#else
++#define HMAN_OC_CAPWAP_MANIP                                    0x2F
++#define HMAN_OC_CAPWAP_FRAG_CHECK                               0x2E
++#define HMAN_OC_CAPWAP_FRAGMENTATION                            0x33
++#define HMAN_OC_CAPWAP_REASSEMBLY                               0x30
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++#define HMAN_OC_IP_MANIP                                        0x34
++#define HMAN_OC_IP_FRAGMENTATION                                0x74
++#define HMAN_OC_IP_REASSEMBLY                                   0xB4
++#define HMAN_OC_IPSEC_MANIP                                     0xF4
++#define HMAN_OC                                                 0x35
++
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++#define HMAN_RMV_HDR                               0x80000000
++#define HMAN_INSRT_INT_FRM_HDR                     0x40000000
++
++#define UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP          6
++#define UDP_CHECKSUM_FIELD_SIZE                     2
++#define UDP_LENGTH_FIELD_OFFSET_FROM_UDP            4
++
++#define IPv4_DSCECN_FIELD_OFFSET_FROM_IP            1
++#define IPv4_TOTALLENGTH_FIELD_OFFSET_FROM_IP       2
++#define IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP       10
++#define VLAN_TAG_FIELD_OFFSET_FROM_ETH              12
++#define IPv4_ID_FIELD_OFFSET_FROM_IP                4
++
++#define IPv6_PAYLOAD_LENGTH_OFFSET_FROM_IP          4
++#define IPv6_NEXT_HEADER_OFFSET_FROM_IP             6
++
++#define FM_PCD_MANIP_CAPWAP_REASM_TABLE_SIZE               0x80
++#define FM_PCD_MANIP_CAPWAP_REASM_TABLE_ALIGN              8
++#define FM_PCD_MANIP_CAPWAP_REASM_RFD_SIZE                 32
++#define FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE 4
++#define FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_ENTRY_SIZE      8
++
++
++#define FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_BETWEEN_FRAMES          0x40000000
++#define FM_PCD_MANIP_CAPWAP_REASM_HALT_ON_DUPLICATE_FRAG           0x10000000
++#define FM_PCD_MANIP_CAPWAP_REASM_AUTOMATIC_LEARNIN_HASH_8_WAYS    0x08000000
++#define FM_PCD_MANIP_CAPWAP_REASM_PR_COPY                          0x00800000
++
++#define FM_PCD_MANIP_CAPWAP_FRAG_COMPR_OPTION_FIELD_EN             0x80000000
++
++#define FM_PCD_MANIP_INDEXED_STATS_ENTRY_SIZE               4
++#define FM_PCD_MANIP_INDEXED_STATS_CNIA                     0x20000000
++#define FM_PCD_MANIP_INDEXED_STATS_DPD                      0x10000000
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++
++#if (DPAA_VERSION >= 11)
++#define FM_PCD_MANIP_CAPWAP_DTLS                            0x00040000
++#define FM_PCD_MANIP_CAPWAP_NADEN                           0x20000000
++
++#define FM_PCD_MANIP_CAPWAP_FRAG_CHECK_MTU_SHIFT            16
++#define FM_PCD_MANIP_CAPWAP_FRAG_CHECK_NO_FRAGMENTATION     0xFFFF0000
++#define FM_PCD_MANIP_CAPWAP_FRAG_CHECK_CNIA                 0x20000000
++
++#define FM_PCD_MANIP_CAPWAP_FRAG_COMPRESS_EN                0x04000000
++#define FM_PCD_MANIP_CAPWAP_FRAG_SCRATCH_BPID               24
++#define FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_EN                 0x08000000
++#define FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_MASK               0xFF000000
++#define FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_SHIFT              24
++#endif /* (DPAA_VERSION >= 11) */
++
++#define FM_PCD_MANIP_REASM_TABLE_SIZE                    0x40
++#define FM_PCD_MANIP_REASM_TABLE_ALIGN                   8
++
++#define FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_SIZE       64
++#define FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_ALIGN      8
++#define FM_PCD_MANIP_REASM_TIME_OUT_BETWEEN_FRAMES       0x80000000
++#define FM_PCD_MANIP_REASM_COUPLING_ENABLE               0x40000000
++#define FM_PCD_MANIP_REASM_COUPLING_MASK                 0xFF000000
++#define FM_PCD_MANIP_REASM_COUPLING_SHIFT                24
++#define FM_PCD_MANIP_REASM_LIODN_MASK                    0x0000003F
++#define FM_PCD_MANIP_REASM_LIODN_SHIFT                   56
++#define FM_PCD_MANIP_REASM_ELIODN_MASK                   0x000003c0
++#define FM_PCD_MANIP_REASM_ELIODN_SHIFT                  38
++#define FM_PCD_MANIP_REASM_COMMON_INT_BUFFER_IDX_MASK    0x000000FF
++#define FM_PCD_MANIP_REASM_COMMON_INT_BUFFER_IDX_SHIFT   24
++#define FM_PCD_MANIP_REASM_TIMEOUT_THREAD_THRESH        1024
++
++#define FM_PCD_MANIP_IP_MTU_SHIFT                           16
++#define FM_PCD_MANIP_IP_NO_FRAGMENTATION                    0xFFFF0000
++#define FM_PCD_MANIP_IP_CNIA                                0x20000000
++
++#define FM_PCD_MANIP_IP_FRAG_DF_SHIFT                       28
++#define FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID                   24
++#define FM_PCD_MANIP_IP_FRAG_SG_BDID_EN                     0x08000000
++#define FM_PCD_MANIP_IP_FRAG_SG_BDID_MASK                   0xFF000000
++#define FM_PCD_MANIP_IP_FRAG_SG_BDID_SHIFT                  24
++
++#define FM_PCD_MANIP_IPSEC_DEC                              0x10000000
++#define FM_PCD_MANIP_IPSEC_VIPV_EN                          0x08000000
++#define FM_PCD_MANIP_IPSEC_ECN_EN                           0x04000000
++#define FM_PCD_MANIP_IPSEC_DSCP_EN                          0x02000000
++#define FM_PCD_MANIP_IPSEC_VIPL_EN                          0x01000000
++#define FM_PCD_MANIP_IPSEC_NADEN                            0x20000000
++
++#define FM_PCD_MANIP_IPSEC_IP_HDR_LEN_MASK                  0x00FF0000
++#define FM_PCD_MANIP_IPSEC_IP_HDR_LEN_SHIFT                 16
++
++#define FM_PCD_MANIP_IPSEC_ARW_SIZE_MASK                    0xFFFF0000
++#define FM_PCD_MANIP_IPSEC_ARW_SIZE_SHIFT                   16
++
++#define e_FM_MANIP_IP_INDX                                  1
++
++#define HMCD_OPCODE_GENERIC_RMV                 0x01
++#define HMCD_OPCODE_GENERIC_INSRT               0x02
++#define HMCD_OPCODE_GENERIC_REPLACE             0x05
++#define HMCD_OPCODE_L2_RMV                      0x08
++#define HMCD_OPCODE_L2_INSRT                    0x09
++#define HMCD_OPCODE_VLAN_PRI_UPDATE             0x0B
++#define HMCD_OPCODE_IPV4_UPDATE                 0x0C
++#define HMCD_OPCODE_IPV6_UPDATE                 0x10
++#define HMCD_OPCODE_TCP_UDP_UPDATE              0x0E
++#define HMCD_OPCODE_TCP_UDP_CHECKSUM            0x14
++#define HMCD_OPCODE_REPLACE_IP                  0x12
++#define HMCD_OPCODE_RMV_TILL                    0x15
++#define HMCD_OPCODE_UDP_INSRT                   0x16
++#define HMCD_OPCODE_IP_INSRT                    0x17
++#define HMCD_OPCODE_CAPWAP_RMV                  0x18
++#define HMCD_OPCODE_CAPWAP_INSRT                0x18
++#define HMCD_OPCODE_GEN_FIELD_REPLACE           0x19
++
++#define HMCD_LAST                               0x00800000
++
++#define HMCD_DSCP_VALUES                        64
++
++#define HMCD_BASIC_SIZE                         4
++#define HMCD_PTR_SIZE                           4
++#define HMCD_PARAM_SIZE                         4
++#define HMCD_IPV4_ADDR_SIZE                     4
++#define HMCD_IPV6_ADDR_SIZE                     0x10
++#define HMCD_L4_HDR_SIZE                        8
++
++#define HMCD_CAPWAP_INSRT                       0x00010000
++#define HMCD_INSRT_UDP_LITE                     0x00010000
++#define HMCD_IP_ID_MASK                         0x0000FFFF
++#define HMCD_IP_SIZE_MASK                       0x0000FF00
++#define HMCD_IP_SIZE_SHIFT                      8
++#define HMCD_IP_LAST_PID_MASK                   0x000000FF
++#define HMCD_IP_OR_QOS                          0x00010000
++#define HMCD_IP_L4_CS_CALC                      0x00040000
++#define HMCD_IP_DF_MODE                         0x00400000
++
++
++#define HMCD_OC_SHIFT                           24
++
++#define HMCD_RMV_OFFSET_SHIFT                   0
++#define HMCD_RMV_SIZE_SHIFT                     8
++
++#define HMCD_INSRT_OFFSET_SHIFT                 0
++#define HMCD_INSRT_SIZE_SHIFT                   8
++
++#define HMTD_CFG_TYPE                           0x4000
++#define HMTD_CFG_EXT_HMCT                       0x0080
++#define HMTD_CFG_PRS_AFTER_HM                   0x0040
++#define HMTD_CFG_NEXT_AD_EN                     0x0020
++
++#define HMCD_RMV_L2_ETHERNET                    0
++#define HMCD_RMV_L2_STACKED_QTAGS               1
++#define HMCD_RMV_L2_ETHERNET_AND_MPLS           2
++#define HMCD_RMV_L2_MPLS                        3
++#define HMCD_RMV_L2_PPPOE                        4
++
++#define HMCD_INSRT_L2_MPLS                      0
++#define HMCD_INSRT_N_UPDATE_L2_MPLS             1
++#define HMCD_INSRT_L2_PPPOE                     2
++#define HMCD_INSRT_L2_SIZE_SHIFT                24
++
++#define HMCD_L2_MODE_SHIFT                      16
++
++#define HMCD_VLAN_PRI_REP_MODE_SHIFT            16
++#define HMCD_VLAN_PRI_UPDATE                    0
++#define HMCD_VLAN_PRI_UPDATE_DSCP_TO_VPRI       1
++
++#define HMCD_IPV4_UPDATE_TTL                    0x00000001
++#define HMCD_IPV4_UPDATE_TOS                    0x00000002
++#define HMCD_IPV4_UPDATE_DST                    0x00000020
++#define HMCD_IPV4_UPDATE_SRC                    0x00000040
++#define HMCD_IPV4_UPDATE_ID                     0x00000080
++#define HMCD_IPV4_UPDATE_TOS_SHIFT              8
++
++#define HMCD_IPV6_UPDATE_HL                     0x00000001
++#define HMCD_IPV6_UPDATE_TC                     0x00000002
++#define HMCD_IPV6_UPDATE_DST                    0x00000040
++#define HMCD_IPV6_UPDATE_SRC                    0x00000080
++#define HMCD_IPV6_UPDATE_TC_SHIFT               8
++
++#define HMCD_TCP_UDP_UPDATE_DST                 0x00004000
++#define HMCD_TCP_UDP_UPDATE_SRC                 0x00008000
++#define HMCD_TCP_UDP_UPDATE_SRC_SHIFT           16
++
++#define HMCD_IP_REPLACE_REPLACE_IPV4            0x00000000
++#define HMCD_IP_REPLACE_REPLACE_IPV6            0x00010000
++#define HMCD_IP_REPLACE_TTL_HL                  0x00200000
++#define HMCD_IP_REPLACE_ID                      0x00400000
++
++#define HMCD_IP_REPLACE_L3HDRSIZE_SHIFT         24
++
++#define HMCD_GEN_FIELD_SIZE_SHIFT               16
++#define HMCD_GEN_FIELD_SRC_OFF_SHIFT            8
++#define HMCD_GEN_FIELD_DST_OFF_SHIFT            0
++#define HMCD_GEN_FIELD_MASK_EN                  0x00400000
++
++#define HMCD_GEN_FIELD_MASK_OFF_SHIFT           16
++#define HMCD_GEN_FIELD_MASK_SHIFT               24
++
++#define DSCP_TO_VLAN_TABLE_SIZE                    32
++
++#define MANIP_GET_HMCT_SIZE(h_Manip)                    (((t_FmPcdManip *)h_Manip)->tableSize)
++#define MANIP_GET_DATA_SIZE(h_Manip)                    (((t_FmPcdManip *)h_Manip)->dataSize)
++
++#define MANIP_GET_HMCT_PTR(h_Manip)                     (((t_FmPcdManip *)h_Manip)->p_Hmct)
++#define MANIP_GET_DATA_PTR(h_Manip)                     (((t_FmPcdManip *)h_Manip)->p_Data)
++
++#define MANIP_SET_HMCT_PTR(h_Manip, h_NewPtr)           (((t_FmPcdManip *)h_Manip)->p_Hmct = h_NewPtr)
++#define MANIP_SET_DATA_PTR(h_Manip, h_NewPtr)           (((t_FmPcdManip *)h_Manip)->p_Data = h_NewPtr)
++
++#define MANIP_GET_HMTD_PTR(h_Manip)                     (((t_FmPcdManip *)h_Manip)->h_Ad)
++#define MANIP_DONT_REPARSE(h_Manip)                     (((t_FmPcdManip *)h_Manip)->dontParseAfterManip)
++#define MANIP_SET_PREV(h_Manip, h_Prev)                 (((t_FmPcdManip *)h_Manip)->h_PrevManip = h_Prev)
++#define MANIP_GET_OWNERS(h_Manip)                       (((t_FmPcdManip *)h_Manip)->owner)
++#define MANIP_GET_TYPE(h_Manip)                         (((t_FmPcdManip *)h_Manip)->type)
++#define MANIP_SET_UNIFIED_TBL_PTR_INDICATION(h_Manip)   (((t_FmPcdManip *)h_Manip)->unifiedTablePtr = TRUE)
++#define MANIP_GET_MURAM(h_Manip)                        (((t_FmPcd *)((t_FmPcdManip *)h_Manip)->h_FmPcd)->h_FmMuram)
++#define MANIP_FREE_HMTD(h_Manip)                        \
++        {if (((t_FmPcdManip *)h_Manip)->muramAllocate)    \
++            FM_MURAM_FreeMem(((t_FmPcd *)((t_FmPcdManip *)h_Manip)->h_FmPcd)->h_FmMuram, ((t_FmPcdManip *)h_Manip)->h_Ad);\
++        else                                            \
++            XX_Free(((t_FmPcdManip *)h_Manip)->h_Ad);    \
++        ((t_FmPcdManip *)h_Manip)->h_Ad = NULL;            \
++        }
++/* position regarding Manip SW structure */
++#define MANIP_IS_FIRST(h_Manip)                         (!(((t_FmPcdManip *)h_Manip)->h_PrevManip))
++#define MANIP_IS_CASCADED(h_Manip)                       (((t_FmPcdManip *)h_Manip)->cascaded)
++#define MANIP_IS_UNIFIED(h_Manip)                       (!(((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_NONE))
++#define MANIP_IS_UNIFIED_NON_FIRST(h_Manip)             ((((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_MID) || \
++                                                         (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_LAST))
++#define MANIP_IS_UNIFIED_NON_LAST(h_Manip)              ((((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_FIRST) ||\
++                                                         (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_MID))
++#define MANIP_IS_UNIFIED_FIRST(h_Manip)                    (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_FIRST)
++#define MANIP_IS_UNIFIED_LAST(h_Manip)                   (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_LAST)
++
++#define MANIP_UPDATE_UNIFIED_POSITION(h_Manip)          (((t_FmPcdManip *)h_Manip)->unifiedPosition = \
++                                                         (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_NONE)? \
++                                                            e_MANIP_UNIFIED_LAST : e_MANIP_UNIFIED_MID)
++
++typedef enum e_ManipUnifiedPosition {
++    e_MANIP_UNIFIED_NONE = 0,
++    e_MANIP_UNIFIED_FIRST,
++    e_MANIP_UNIFIED_MID,
++    e_MANIP_UNIFIED_LAST
++} e_ManipUnifiedPosition;
++
++typedef enum e_ManipInfo {
++    e_MANIP_HMTD,
++    e_MANIP_HMCT,
++    e_MANIP_HANDLER_TABLE_OWNER
++}e_ManipInfo;
++/***********************************************************************/
++/*          Memory map                                                 */
++/***********************************************************************/
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(push,1)
++#endif /* defined(__MWERKS__) && ... */
++
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++typedef struct t_CapwapReasmPram {
++    volatile uint32_t mode;
++    volatile uint32_t autoLearnHashTblPtr;
++    volatile uint32_t intStatsTblPtr;
++    volatile uint32_t reasmFrmDescPoolTblPtr;
++    volatile uint32_t reasmFrmDescIndexPoolTblPtr;
++    volatile uint32_t timeOutTblPtr;
++    volatile uint32_t bufferPoolIdAndRisc1SetIndexes;
++    volatile uint32_t risc23SetIndexes;
++    volatile uint32_t risc4SetIndexesAndExtendedStatsTblPtr;
++    volatile uint32_t extendedStatsTblPtr;
++    volatile uint32_t expirationDelay;
++    volatile uint32_t totalProcessedFragCounter;
++    volatile uint32_t totalUnsuccessfulReasmFramesCounter;
++    volatile uint32_t totalDuplicatedFragCounter;
++    volatile uint32_t totalMalformdFragCounter;
++    volatile uint32_t totalTimeOutCounter;
++    volatile uint32_t totalSetBusyCounter;
++    volatile uint32_t totalRfdPoolBusyCounter;
++    volatile uint32_t totalDiscardedFragsCounter;
++    volatile uint32_t totalMoreThan16FramesCounter;
++    volatile uint32_t internalBufferBusy;
++    volatile uint32_t externalBufferBusy;
++    volatile uint32_t reserved1[4];
++} t_CapwapReasmPram;
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++
++typedef _Packed struct t_ReassTbl {
++    volatile uint16_t waysNumAndSetSize;
++    volatile uint16_t autoLearnHashKeyMask;
++    volatile uint32_t reassCommonPrmTblPtr;
++    volatile uint32_t liodnAlAndAutoLearnHashTblPtrHi;
++    volatile uint32_t autoLearnHashTblPtrLow;
++    volatile uint32_t liodnSlAndAutoLearnSetLockTblPtrHi;
++    volatile uint32_t autoLearnSetLockTblPtrLow;
++    volatile uint16_t minFragSize; /* Not relevant for CAPWAP*/
++    volatile uint16_t maxReassemblySize; /* Only relevant for CAPWAP*/
++    volatile uint32_t totalSuccessfullyReasmFramesCounter;
++    volatile uint32_t totalValidFragmentCounter;
++    volatile uint32_t totalProcessedFragCounter;
++    volatile uint32_t totalMalformdFragCounter;
++    volatile uint32_t totalSetBusyCounter;
++    volatile uint32_t totalDiscardedFragsCounter;
++    volatile uint32_t totalMoreThan16FramesCounter;
++    volatile uint32_t reserved2[2];
++} _PackedType t_ReassTbl;
++
++typedef struct t_ReassCommonTbl {
++    volatile uint32_t timeoutModeAndFqid;
++    volatile uint32_t reassFrmDescIndexPoolTblPtr;
++    volatile uint32_t liodnAndReassFrmDescPoolPtrHi;
++    volatile uint32_t reassFrmDescPoolPtrLow;
++    volatile uint32_t timeOutTblPtr;
++    volatile uint32_t expirationDelay;
++    volatile uint32_t internalBufferManagement;
++    volatile uint32_t reserved2;
++    volatile uint32_t totalTimeOutCounter;
++    volatile uint32_t totalRfdPoolBusyCounter;
++    volatile uint32_t totalInternalBufferBusy;
++    volatile uint32_t totalExternalBufferBusy;
++    volatile uint32_t totalSgFragmentCounter;
++    volatile uint32_t totalDmaSemaphoreDepletionCounter;
++    volatile uint32_t totalNCSPCounter;
++    volatile uint32_t discardMask;
++} t_ReassCommonTbl;
++
++typedef _Packed struct t_Hmtd {
++    volatile uint16_t   cfg;
++    volatile uint8_t    eliodnOffset;
++    volatile uint8_t    extHmcdBasePtrHi;
++    volatile uint32_t   hmcdBasePtr;
++    volatile uint16_t   nextAdIdx;
++    volatile uint8_t    res1;
++    volatile uint8_t    opCode;
++    volatile uint32_t   res2;
++} _PackedType t_Hmtd;
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(pop)
++#endif /* defined(__MWERKS__) && ... */
++
++
++/***********************************************************************/
++/*  Driver's internal structures                                       */
++/***********************************************************************/
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++typedef struct
++{
++    t_Handle p_AutoLearnHashTbl;
++    t_Handle p_ReassmFrmDescrPoolTbl;
++    t_Handle p_ReassmFrmDescrIndxPoolTbl;
++    t_Handle p_TimeOutTbl;
++    uint16_t maxNumFramesInProcess;
++    uint8_t  numOfTasks;
++    //uint8_t  poolId;
++    uint8_t  prOffset;
++    uint16_t dataOffset;
++    uint8_t  sgBpid;
++    uint8_t  hwPortId;
++    uint32_t fqidForTimeOutFrames;
++    uint32_t timeoutRoutineRequestTime;
++    uint32_t bitFor1Micro;
++} t_CapwapFragParams;
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++
++typedef struct
++{
++    t_AdOfTypeContLookup    *p_Frag;
++#if (DPAA_VERSION == 10)
++    uint8_t                 scratchBpid;
++#endif /* (DPAA_VERSION == 10) */
++} t_FragParams;
++
++typedef struct t_ReassmParams
++{
++    e_NetHeaderType                 hdr; /* Header selection */
++    t_ReassCommonTbl                  *p_ReassCommonTbl;
++    uintptr_t                       reassFrmDescrIndxPoolTblAddr;
++    uintptr_t                       reassFrmDescrPoolTblAddr;
++    uintptr_t                       timeOutTblAddr;
++    uintptr_t                       internalBufferPoolManagementIndexAddr;
++    uintptr_t                       internalBufferPoolAddr;
++    uint32_t                        maxNumFramesInProcess;
++    uint8_t                         sgBpid;
++    uint8_t                         dataMemId;
++    uint16_t                        dataLiodnOffset;
++    uint32_t                        fqidForTimeOutFrames;
++    e_FmPcdManipReassemTimeOutMode  timeOutMode;
++    uint32_t                        timeoutThresholdForReassmProcess;
++    union {
++      struct {
++              t_Handle                h_Ipv4Ad;
++          t_Handle                h_Ipv6Ad;
++          bool                    ipv6Assigned;
++          t_ReassTbl                          *p_Ipv4ReassTbl;
++          t_ReassTbl              *p_Ipv6ReassTbl;
++          uintptr_t               ipv4AutoLearnHashTblAddr;
++          uintptr_t               ipv6AutoLearnHashTblAddr;
++          uintptr_t               ipv4AutoLearnSetLockTblAddr;
++          uintptr_t               ipv6AutoLearnSetLockTblAddr;
++          uint16_t                        minFragSize[2];
++          e_FmPcdManipReassemWaysNumber   numOfFramesPerHashEntry[2];
++          uint8_t                         relativeSchemeId[2];
++          t_Handle                        h_Ipv4Scheme;
++          t_Handle                        h_Ipv6Scheme;
++          uint32_t                        nonConsistentSpFqid;
++      } ip;
++      struct {
++              t_Handle                h_Ad;
++          t_ReassTbl                          *p_ReassTbl;
++          uintptr_t               autoLearnHashTblAddr;
++          uintptr_t               autoLearnSetLockTblAddr;
++          uint16_t                maxRessembledsSize;
++          e_FmPcdManipReassemWaysNumber   numOfFramesPerHashEntry;
++          uint8_t                 relativeSchemeId;
++          t_Handle                h_Scheme;
++      } capwap;
++    };
++} t_ReassmParams;
++
++typedef struct{
++    e_FmPcdManipType        type;
++    t_FmPcdManipParams      manipParams;
++    bool                    muramAllocate;
++    t_Handle                h_Ad;
++    uint32_t                opcode;
++    bool                    rmv;
++    bool                    insrt;
++    t_Handle                h_NextManip;
++    t_Handle                h_PrevManip;
++    e_FmPcdManipType        nextManipType;
++    /* HdrManip parameters*/
++    uint8_t                 *p_Hmct;
++    uint8_t                 *p_Data;
++    bool                    dontParseAfterManip;
++    bool                    fieldUpdate;
++    bool                    custom;
++    uint16_t                tableSize;
++    uint8_t                 dataSize;
++    bool                    cascaded;
++    e_ManipUnifiedPosition  unifiedPosition;
++    /* end HdrManip */
++    uint8_t                 *p_Template;
++    uint16_t                owner;
++    uint32_t                updateParams;
++    uint32_t                shadowUpdateParams;
++    bool                    frag;
++    bool                    reassm;
++    uint16_t                sizeForFragmentation;
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++    t_Handle                h_Frag;
++    t_CapwapFragParams      capwapFragParams;
++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
++    union {
++        t_ReassmParams        reassmParams;
++        t_FragParams          fragParams;
++    };
++    uint8_t                 icOffset;
++    uint16_t                ownerTmp;
++    bool                    cnia;
++    t_Handle                p_StatsTbl;
++    t_Handle                h_FmPcd;
++    t_List                  nodesLst;
++    t_Handle                h_Spinlock;
++} t_FmPcdManip;
++
++typedef struct t_FmPcdCcSavedManipParams
++{
++    union
++    {
++        struct
++        {
++            uint16_t    dataOffset;
++            //uint8_t     poolId;
++        }capwapParams;
++        struct
++        {
++            uint16_t    dataOffset;
++            uint8_t     poolId;
++        }ipParams;
++    };
++
++} t_FmPcdCcSavedManipParams;
++
++
++#endif /* __FM_MANIP_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.c
+@@ -0,0 +1,2095 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_pcd.c
++
++ @Description   FM PCD ...
++*//***************************************************************************/
++#include "std_ext.h"
++#include "error_ext.h"
++#include "string_ext.h"
++#include "xx_ext.h"
++#include "sprint_ext.h"
++#include "debug_ext.h"
++#include "net_ext.h"
++#include "fm_ext.h"
++#include "fm_pcd_ext.h"
++
++#include "fm_common.h"
++#include "fm_pcd.h"
++#include "fm_pcd_ipc.h"
++#include "fm_hc.h"
++#include "fm_muram_ext.h"
++
++
++/****************************************/
++/*       static functions               */
++/****************************************/
++
++static t_Error CheckFmPcdParameters(t_FmPcd *p_FmPcd)
++{
++    if (!p_FmPcd->h_Fm)
++         RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("h_Fm has to be initialized"));
++
++    if (p_FmPcd->guestId == NCSW_MASTER_ID)
++    {
++        if (p_FmPcd->p_FmPcdKg && !p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Something WRONG"));
++
++        if (p_FmPcd->p_FmPcdPlcr && !p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Something WRONG"));
++
++        if (!p_FmPcd->f_Exception)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("f_FmPcdExceptions has to be initialized"));
++
++        if ((!p_FmPcd->f_FmPcdIndexedException) && (p_FmPcd->p_FmPcdPlcr || p_FmPcd->p_FmPcdKg))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("f_FmPcdIndexedException has to be initialized"));
++
++        if (p_FmPcd->p_FmPcdDriverParam->prsMaxParseCycleLimit > PRS_MAX_CYCLE_LIMIT)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("prsMaxParseCycleLimit has to be less than 8191"));
++    }
++
++    return E_OK;
++}
++
++static volatile bool blockingFlag = FALSE;
++static void IpcMsgCompletionCB(t_Handle   h_FmPcd,
++                               uint8_t    *p_Msg,
++                               uint8_t    *p_Reply,
++                               uint32_t   replyLength,
++                               t_Error    status)
++{
++    UNUSED(h_FmPcd);UNUSED(p_Msg);UNUSED(p_Reply);UNUSED(replyLength);UNUSED(status);
++    blockingFlag = FALSE;
++}
++
++static t_Error IpcMsgHandlerCB(t_Handle  h_FmPcd,
++                               uint8_t   *p_Msg,
++                               uint32_t  msgLength,
++                               uint8_t   *p_Reply,
++                               uint32_t  *p_ReplyLength)
++{
++    t_FmPcd             *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    t_Error             err = E_OK;
++    t_FmPcdIpcMsg       *p_IpcMsg   = (t_FmPcdIpcMsg*)p_Msg;
++    t_FmPcdIpcReply     *p_IpcReply = (t_FmPcdIpcReply*)p_Reply;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((msgLength >= sizeof(uint32_t)), E_INVALID_VALUE);
++
++#ifdef DISABLE_SANITY_CHECKS
++    UNUSED(msgLength);
++#endif /* DISABLE_SANITY_CHECKS */
++
++    ASSERT_COND(p_Msg);
++
++    memset(p_IpcReply, 0, (sizeof(uint8_t) * FM_PCD_MAX_REPLY_SIZE));
++    *p_ReplyLength = 0;
++
++    switch (p_IpcMsg->msgId)
++    {
++        case (FM_PCD_MASTER_IS_ALIVE):
++            *(uint8_t*)(p_IpcReply->replyBody) = 1;
++            p_IpcReply->error = E_OK;
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t);
++            break;
++        case (FM_PCD_MASTER_IS_ENABLED):
++            /* count partitions registrations */
++            if (p_FmPcd->enabled)
++                p_FmPcd->numOfEnabledGuestPartitionsPcds++;
++            *(uint8_t*)(p_IpcReply->replyBody)  = (uint8_t)p_FmPcd->enabled;
++            p_IpcReply->error = E_OK;
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t);
++            break;
++        case (FM_PCD_GUEST_DISABLE):
++            if (p_FmPcd->numOfEnabledGuestPartitionsPcds)
++            {
++                p_FmPcd->numOfEnabledGuestPartitionsPcds--;
++                p_IpcReply->error = E_OK;
++            }
++            else
++            {
++                REPORT_ERROR(MINOR, E_INVALID_STATE,("Trying to disable an unregistered partition"));
++                p_IpcReply->error = E_INVALID_STATE;
++            }
++            *p_ReplyLength = sizeof(uint32_t);
++            break;
++        case (FM_PCD_GET_COUNTER):
++        {
++            e_FmPcdCounters inCounter;
++            uint32_t        outCounter;
++
++            memcpy((uint8_t*)&inCounter, p_IpcMsg->msgBody, sizeof(uint32_t));
++            outCounter = FM_PCD_GetCounter(h_FmPcd, inCounter);
++            memcpy(p_IpcReply->replyBody, (uint8_t*)&outCounter, sizeof(uint32_t));
++            p_IpcReply->error = E_OK;
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t);
++            break;
++        }
++        case (FM_PCD_ALLOC_KG_SCHEMES):
++        {
++            t_FmPcdIpcKgSchemesParams   ipcSchemesParams;
++
++            memcpy((uint8_t*)&ipcSchemesParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgSchemesParams));
++            err = FmPcdKgAllocSchemes(h_FmPcd,
++                                      ipcSchemesParams.numOfSchemes,
++                                      ipcSchemesParams.guestId,
++                                      p_IpcReply->replyBody);
++            p_IpcReply->error = err;
++            *p_ReplyLength = sizeof(uint32_t) + ipcSchemesParams.numOfSchemes*sizeof(uint8_t);
++            break;
++        }
++        case (FM_PCD_FREE_KG_SCHEMES):
++        {
++            t_FmPcdIpcKgSchemesParams   ipcSchemesParams;
++
++            memcpy((uint8_t*)&ipcSchemesParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgSchemesParams));
++            err = FmPcdKgFreeSchemes(h_FmPcd,
++                                     ipcSchemesParams.numOfSchemes,
++                                     ipcSchemesParams.guestId,
++                                     ipcSchemesParams.schemesIds);
++            p_IpcReply->error = err;
++            *p_ReplyLength = sizeof(uint32_t);
++            break;
++        }
++        case (FM_PCD_ALLOC_KG_CLSPLAN):
++        {
++            t_FmPcdIpcKgClsPlanParams   ipcKgClsPlanParams;
++
++            memcpy((uint8_t*)&ipcKgClsPlanParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgClsPlanParams));
++            err = KgAllocClsPlanEntries(h_FmPcd,
++                                        ipcKgClsPlanParams.numOfClsPlanEntries,
++                                        ipcKgClsPlanParams.guestId,
++                                        p_IpcReply->replyBody);
++            p_IpcReply->error = err;
++            *p_ReplyLength =  sizeof(uint32_t) + sizeof(uint8_t);
++            break;
++        }
++        case (FM_PCD_FREE_KG_CLSPLAN):
++        {
++            t_FmPcdIpcKgClsPlanParams   ipcKgClsPlanParams;
++
++            memcpy((uint8_t*)&ipcKgClsPlanParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgClsPlanParams));
++            KgFreeClsPlanEntries(h_FmPcd,
++                                 ipcKgClsPlanParams.numOfClsPlanEntries,
++                                 ipcKgClsPlanParams.guestId,
++                                 ipcKgClsPlanParams.clsPlanBase);
++            *p_ReplyLength = sizeof(uint32_t);
++            break;
++        }
++        case (FM_PCD_ALLOC_PROFILES):
++        {
++            t_FmIpcResourceAllocParams      ipcAllocParams;
++            uint16_t                        base;
++            memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams));
++            base =  PlcrAllocProfilesForPartition(h_FmPcd,
++                                                  ipcAllocParams.base,
++                                                  ipcAllocParams.num,
++                                                  ipcAllocParams.guestId);
++            memcpy(p_IpcReply->replyBody, (uint16_t*)&base, sizeof(uint16_t));
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(uint16_t);
++            break;
++        }
++        case (FM_PCD_FREE_PROFILES):
++        {
++            t_FmIpcResourceAllocParams   ipcAllocParams;
++            memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams));
++            PlcrFreeProfilesForPartition(h_FmPcd,
++                                         ipcAllocParams.base,
++                                         ipcAllocParams.num,
++                                         ipcAllocParams.guestId);
++            break;
++        }
++        case (FM_PCD_SET_PORT_PROFILES):
++        {
++            t_FmIpcResourceAllocParams   ipcAllocParams;
++            memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams));
++            PlcrSetPortProfiles(h_FmPcd,
++                                ipcAllocParams.guestId,
++                                ipcAllocParams.num,
++                                ipcAllocParams.base);
++            break;
++        }
++        case (FM_PCD_CLEAR_PORT_PROFILES):
++        {
++            t_FmIpcResourceAllocParams   ipcAllocParams;
++            memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams));
++            PlcrClearPortProfiles(h_FmPcd,
++                                  ipcAllocParams.guestId);
++            break;
++        }
++        case (FM_PCD_GET_SW_PRS_OFFSET):
++        {
++            t_FmPcdIpcSwPrsLable   ipcSwPrsLable;
++            uint32_t               swPrsOffset;
++
++            memcpy((uint8_t*)&ipcSwPrsLable, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcSwPrsLable));
++            swPrsOffset =
++                FmPcdGetSwPrsOffset(h_FmPcd,
++                                    (e_NetHeaderType)ipcSwPrsLable.enumHdr,
++                                    ipcSwPrsLable.indexPerHdr);
++            memcpy(p_IpcReply->replyBody, (uint8_t*)&swPrsOffset, sizeof(uint32_t));
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t);
++            break;
++        }
++        case (FM_PCD_PRS_INC_PORT_STATS):
++        {
++            t_FmPcdIpcPrsIncludePort   ipcPrsIncludePort;
++
++            memcpy((uint8_t*)&ipcPrsIncludePort, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcPrsIncludePort));
++            PrsIncludePortInStatistics(h_FmPcd,
++                                       ipcPrsIncludePort.hardwarePortId,
++                                       ipcPrsIncludePort.include);
++           break;
++        }
++        default:
++            *p_ReplyLength = 0;
++            RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!"));
++    }
++    return E_OK;
++}
++
++static uint32_t NetEnvLock(t_Handle h_NetEnv)
++{
++    ASSERT_COND(h_NetEnv);
++    return XX_LockIntrSpinlock(((t_FmPcdNetEnv*)h_NetEnv)->h_Spinlock);
++}
++
++static void NetEnvUnlock(t_Handle h_NetEnv, uint32_t intFlags)
++{
++    ASSERT_COND(h_NetEnv);
++    XX_UnlockIntrSpinlock(((t_FmPcdNetEnv*)h_NetEnv)->h_Spinlock, intFlags);
++}
++
++static void EnqueueLockToFreeLst(t_FmPcd *p_FmPcd, t_FmPcdLock *p_Lock)
++{
++    uint32_t   intFlags;
++
++    intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock);
++    LIST_AddToTail(&p_Lock->node, &p_FmPcd->freeLocksLst);
++    XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags);
++}
++
++static t_FmPcdLock * DequeueLockFromFreeLst(t_FmPcd *p_FmPcd)
++{
++    t_FmPcdLock *p_Lock = NULL;
++    uint32_t    intFlags;
++
++    intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock);
++    if (!LIST_IsEmpty(&p_FmPcd->freeLocksLst))
++    {
++        p_Lock = FM_PCD_LOCK_OBJ(p_FmPcd->freeLocksLst.p_Next);
++        LIST_DelAndInit(&p_Lock->node);
++    }
++    if (p_FmPcd->h_Spinlock)
++      XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags);
++
++    return p_Lock;
++}
++
++static void EnqueueLockToAcquiredLst(t_FmPcd *p_FmPcd, t_FmPcdLock *p_Lock)
++{
++    uint32_t   intFlags;
++
++    intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock);
++    LIST_AddToTail(&p_Lock->node, &p_FmPcd->acquiredLocksLst);
++    XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags);
++}
++
++static t_Error FillFreeLocksLst(t_FmPcd *p_FmPcd)
++{
++    t_FmPcdLock *p_Lock;
++    int         i;
++
++    for (i=0; i<10; i++)
++    {
++        p_Lock = (t_FmPcdLock *)XX_Malloc(sizeof(t_FmPcdLock));
++        if (!p_Lock)
++            RETURN_ERROR(MINOR, E_NO_MEMORY, ("FM-PCD lock obj!"));
++        memset(p_Lock, 0, sizeof(t_FmPcdLock));
++        INIT_LIST(&p_Lock->node);
++        p_Lock->h_Spinlock = XX_InitSpinlock();
++        if (!p_Lock->h_Spinlock)
++        {
++            XX_Free(p_Lock);
++            RETURN_ERROR(MINOR, E_INVALID_STATE, ("FM-PCD spinlock obj!"));
++        }
++        EnqueueLockToFreeLst(p_FmPcd, p_Lock);
++    }
++
++    return E_OK;
++}
++
++static void ReleaseFreeLocksLst(t_FmPcd *p_FmPcd)
++{
++    t_FmPcdLock *p_Lock;
++
++    p_Lock = DequeueLockFromFreeLst(p_FmPcd);
++    while (p_Lock)
++    {
++        XX_FreeSpinlock(p_Lock->h_Spinlock);
++        XX_Free(p_Lock);
++        p_Lock = DequeueLockFromFreeLst(p_FmPcd);
++    }
++}
++
++
++
++/*****************************************************************************/
++/*              Inter-module API routines                                    */
++/*****************************************************************************/
++
++void FmPcdSetClsPlanGrpId(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint8_t clsPlanGrpId)
++{
++    ASSERT_COND(p_FmPcd);
++    p_FmPcd->netEnvs[netEnvId].clsPlanGrpId = clsPlanGrpId;
++}
++
++t_Error PcdGetClsPlanGrpParams(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_GrpParams)
++{
++    uint8_t netEnvId = p_GrpParams->netEnvId;
++    int     i, k, j;
++
++    ASSERT_COND(p_FmPcd);
++    if (p_FmPcd->netEnvs[netEnvId].clsPlanGrpId != ILLEGAL_CLS_PLAN)
++    {
++        p_GrpParams->grpExists = TRUE;
++        p_GrpParams->clsPlanGrpId = p_FmPcd->netEnvs[netEnvId].clsPlanGrpId;
++        return E_OK;
++    }
++
++    for (i=0; ((i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) &&
++              (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE)); i++)
++    {
++        for (k=0; ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) &&
++                   (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE)); k++)
++        {
++            /* if an option exists, add it to the opts list */
++            if (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt)
++            {
++                /* check if this option already exists, add if it doesn't */
++                for (j = 0;j<p_GrpParams->numOfOptions;j++)
++                {
++                    if (p_GrpParams->options[j] == p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt)
++                        break;
++                }
++                p_GrpParams->optVectors[j] |= p_FmPcd->netEnvs[netEnvId].unitsVectors[i];
++                if (j == p_GrpParams->numOfOptions)
++                {
++                    p_GrpParams->options[p_GrpParams->numOfOptions] = p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt;
++                    p_GrpParams->numOfOptions++;
++                }
++            }
++        }
++    }
++
++    if (p_GrpParams->numOfOptions == 0)
++    {
++        if (p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId != ILLEGAL_CLS_PLAN)
++        {
++            p_GrpParams->grpExists = TRUE;
++            p_GrpParams->clsPlanGrpId = p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId;
++        }
++    }
++
++    return E_OK;
++
++}
++
++t_Error PcdGetVectorForOpt(t_FmPcd *p_FmPcd, uint8_t netEnvId, protocolOpt_t opt, uint32_t *p_Vector)
++{
++    uint8_t     j,k;
++
++    *p_Vector = 0;
++
++    ASSERT_COND(p_FmPcd);
++    for (j=0; ((j < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) &&
++              (p_FmPcd->netEnvs[netEnvId].units[j].hdrs[0].hdr != HEADER_TYPE_NONE)); j++)
++    {
++        for (k=0; ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) &&
++                  (p_FmPcd->netEnvs[netEnvId].units[j].hdrs[k].hdr != HEADER_TYPE_NONE)); k++)
++        {
++            if (p_FmPcd->netEnvs[netEnvId].units[j].hdrs[k].opt == opt)
++                *p_Vector |= p_FmPcd->netEnvs[netEnvId].unitsVectors[j];
++        }
++    }
++
++    if (!*p_Vector)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Requested option was not defined for this Network Environment Characteristics module"));
++    else
++        return E_OK;
++}
++
++t_Error PcdGetUnitsVector(t_FmPcd *p_FmPcd, t_NetEnvParams *p_Params)
++{
++    int                     i;
++
++    ASSERT_COND(p_FmPcd);
++    ASSERT_COND(p_Params->netEnvId < FM_MAX_NUM_OF_PORTS);
++
++    p_Params->vector = 0;
++    for (i=0; i<p_Params->numOfDistinctionUnits ;i++)
++    {
++        if (p_FmPcd->netEnvs[p_Params->netEnvId].units[p_Params->unitIds[i]].hdrs[0].hdr == HEADER_TYPE_NONE)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Requested unit was not defined for this Network Environment Characteristics module"));
++        ASSERT_COND(p_FmPcd->netEnvs[p_Params->netEnvId].unitsVectors[p_Params->unitIds[i]]);
++        p_Params->vector |= p_FmPcd->netEnvs[p_Params->netEnvId].unitsVectors[p_Params->unitIds[i]];
++    }
++
++    return E_OK;
++}
++
++bool PcdNetEnvIsUnitWithoutOpts(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint32_t unitVector)
++{
++    int     i=0, k;
++
++    ASSERT_COND(p_FmPcd);
++    /* check whether a given unit may be used by non-clsPlan users. */
++    /* first, recognize the unit by its vector */
++    while (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE)
++    {
++        if (p_FmPcd->netEnvs[netEnvId].unitsVectors[i] == unitVector)
++        {
++            for (k=0;
++                 ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) &&
++                  (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE));
++                 k++)
++                /* check that no option exists */
++                if ((protocolOpt_t)p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt)
++                    return FALSE;
++            break;
++        }
++        i++;
++    }
++    /* assert that a unit was found to mach the vector */
++    ASSERT_COND(p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE);
++
++    return TRUE;
++}
++bool  FmPcdNetEnvIsHdrExist(t_Handle h_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    int         i, k;
++
++    ASSERT_COND(p_FmPcd);
++
++    for (i=0; ((i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) &&
++              (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE)); i++)
++    {
++        for (k=0; ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) &&
++                  (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE)); k++)
++            if (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr == hdr)
++                return TRUE;
++    }
++    for (i=0; ((i < FM_PCD_MAX_NUM_OF_ALIAS_HDRS) &&
++              (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr != HEADER_TYPE_NONE)); i++)
++    {
++        if (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr == hdr)
++            return TRUE;
++    }
++
++    return FALSE;
++}
++
++uint8_t FmPcdNetEnvGetUnitId(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr, bool interchangeable, protocolOpt_t opt)
++{
++    uint8_t     i, k;
++
++    ASSERT_COND(p_FmPcd);
++
++    if (interchangeable)
++    {
++        for (i=0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) &&
++                 (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++)
++        {
++            for (k=0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) &&
++                     (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++)
++            {
++                if ((p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr == hdr) &&
++                    (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt == opt))
++
++                return i;
++            }
++        }
++    }
++    else
++    {
++        for (i=0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) &&
++                 (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++)
++            if ((p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr == hdr) &&
++                (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].opt == opt) &&
++                (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[1].hdr == HEADER_TYPE_NONE))
++                    return i;
++
++        for (i=0; (i < FM_PCD_MAX_NUM_OF_ALIAS_HDRS) &&
++                 (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr != HEADER_TYPE_NONE); i++)
++            if ((p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr == hdr) &&
++                (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].opt == opt))
++                return p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].aliasHdr;
++    }
++
++    return FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS;
++}
++
++t_Error FmPcdUnregisterReassmPort(t_Handle h_FmPcd, t_Handle h_ReasmCommonPramTbl)
++{
++    t_FmPcd                         *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    t_FmPcdCcReassmTimeoutParams    ccReassmTimeoutParams = {0};
++    uint8_t                         result;
++    t_Error                         err = E_OK;
++
++    ASSERT_COND(p_FmPcd);
++    ASSERT_COND(h_ReasmCommonPramTbl);
++
++    ccReassmTimeoutParams.iprcpt   = (uint32_t)(XX_VirtToPhys(h_ReasmCommonPramTbl) - p_FmPcd->physicalMuramBase);
++    ccReassmTimeoutParams.activate = FALSE; /*Disable Timeout Task*/
++
++    if ((err = FmHcPcdCcTimeoutReassm(p_FmPcd->h_Hc, &ccReassmTimeoutParams, &result)) != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    switch (result)
++    {
++        case (0):
++            return E_OK;
++        case (1):
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, (""));
++        case (2):
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, (""));
++        case (3):
++            RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("Disable Timeout Task with invalid IPRCPT"));
++        default:
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
++    }
++
++    return E_OK;
++}
++
++e_NetHeaderType FmPcdGetAliasHdr(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr)
++{
++    int         i;
++
++    ASSERT_COND(p_FmPcd);
++    ASSERT_COND(netEnvId < FM_MAX_NUM_OF_PORTS);
++
++    for (i=0; (i < FM_PCD_MAX_NUM_OF_ALIAS_HDRS)
++        && (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr != HEADER_TYPE_NONE); i++)
++    {
++        if (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr == hdr)
++            return p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].aliasHdr;
++    }
++
++    return HEADER_TYPE_NONE;
++}
++
++void   FmPcdPortRegister(t_Handle h_FmPcd, t_Handle h_FmPort, uint8_t hardwarePortId)
++{
++    t_FmPcd         *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint16_t        swPortIndex = 0;
++
++    ASSERT_COND(h_FmPcd);
++    HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
++    p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].h_FmPort = h_FmPort;
++}
++
++uint32_t FmPcdGetLcv(t_Handle h_FmPcd, uint32_t netEnvId, uint8_t hdrNum)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    ASSERT_COND(h_FmPcd);
++    return p_FmPcd->netEnvs[netEnvId].lcvs[hdrNum];
++}
++
++uint32_t FmPcdGetMacsecLcv(t_Handle h_FmPcd, uint32_t netEnvId)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    ASSERT_COND(h_FmPcd);
++    return p_FmPcd->netEnvs[netEnvId].macsecVector;
++}
++
++uint8_t FmPcdGetNetEnvId(t_Handle h_NetEnv)
++{
++    return ((t_FmPcdNetEnv*)h_NetEnv)->netEnvId;
++}
++
++void FmPcdIncNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId)
++{
++    uint32_t    intFlags;
++
++    ASSERT_COND(h_FmPcd);
++
++    intFlags = NetEnvLock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId]);
++    ((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId].owners++;
++    NetEnvUnlock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId], intFlags);
++}
++
++void FmPcdDecNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId)
++{
++    uint32_t    intFlags;
++
++    ASSERT_COND(h_FmPcd);
++    ASSERT_COND(((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId].owners);
++
++    intFlags = NetEnvLock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId]);
++    ((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId].owners--;
++    NetEnvUnlock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId], intFlags);
++}
++
++uint32_t FmPcdLock(t_Handle h_FmPcd)
++{
++    ASSERT_COND(h_FmPcd);
++    return XX_LockIntrSpinlock(((t_FmPcd*)h_FmPcd)->h_Spinlock);
++}
++
++void FmPcdUnlock(t_Handle h_FmPcd, uint32_t intFlags)
++{
++    ASSERT_COND(h_FmPcd);
++    XX_UnlockIntrSpinlock(((t_FmPcd*)h_FmPcd)->h_Spinlock, intFlags);
++}
++
++t_FmPcdLock * FmPcdAcquireLock(t_Handle h_FmPcd)
++{
++    t_FmPcdLock *p_Lock;
++    ASSERT_COND(h_FmPcd);
++    p_Lock = DequeueLockFromFreeLst((t_FmPcd*)h_FmPcd);
++    if (!p_Lock)
++    {
++        FillFreeLocksLst(h_FmPcd);
++        p_Lock = DequeueLockFromFreeLst((t_FmPcd*)h_FmPcd);
++    }
++
++    if (p_Lock)
++        EnqueueLockToAcquiredLst((t_FmPcd*)h_FmPcd, p_Lock);
++    return p_Lock;
++}
++
++void FmPcdReleaseLock(t_Handle h_FmPcd, t_FmPcdLock *p_Lock)
++{
++    uint32_t intFlags;
++    ASSERT_COND(h_FmPcd);
++    intFlags = FmPcdLock(h_FmPcd);
++    LIST_DelAndInit(&p_Lock->node);
++    FmPcdUnlock(h_FmPcd, intFlags);
++    EnqueueLockToFreeLst((t_FmPcd*)h_FmPcd, p_Lock);
++}
++
++bool FmPcdLockTryLockAll(t_Handle h_FmPcd)
++{
++    uint32_t    intFlags;
++    t_List      *p_Pos, *p_SavedPos=NULL;
++
++    ASSERT_COND(h_FmPcd);
++    intFlags = FmPcdLock(h_FmPcd);
++    LIST_FOR_EACH(p_Pos, &((t_FmPcd*)h_FmPcd)->acquiredLocksLst)
++    {
++        t_FmPcdLock *p_Lock = FM_PCD_LOCK_OBJ(p_Pos);
++        if (!FmPcdLockTryLock(p_Lock))
++        {
++            p_SavedPos = p_Pos;
++            break;
++        }
++    }
++    if (p_SavedPos)
++    {
++        LIST_FOR_EACH(p_Pos, &((t_FmPcd*)h_FmPcd)->acquiredLocksLst)
++        {
++            t_FmPcdLock *p_Lock = FM_PCD_LOCK_OBJ(p_Pos);
++            if (p_Pos == p_SavedPos)
++                break;
++            FmPcdLockUnlock(p_Lock);
++        }
++    }
++    FmPcdUnlock(h_FmPcd, intFlags);
++
++    CORE_MemoryBarrier();
++
++    if (p_SavedPos)
++        return FALSE;
++
++    return TRUE;
++}
++
++void FmPcdLockUnlockAll(t_Handle h_FmPcd)
++{
++    uint32_t    intFlags;
++    t_List      *p_Pos;
++
++    ASSERT_COND(h_FmPcd);
++    intFlags = FmPcdLock(h_FmPcd);
++    LIST_FOR_EACH(p_Pos, &((t_FmPcd*)h_FmPcd)->acquiredLocksLst)
++    {
++        t_FmPcdLock *p_Lock = FM_PCD_LOCK_OBJ(p_Pos);
++        p_Lock->flag = FALSE;
++    }
++    FmPcdUnlock(h_FmPcd, intFlags);
++
++    CORE_MemoryBarrier();
++}
++
++t_Error FmPcdHcSync(t_Handle h_FmPcd)
++{
++    ASSERT_COND(h_FmPcd);
++    ASSERT_COND(((t_FmPcd*)h_FmPcd)->h_Hc);
++
++    return FmHcPcdSync(((t_FmPcd*)h_FmPcd)->h_Hc);
++}
++
++t_Handle FmPcdGetHcHandle(t_Handle h_FmPcd)
++{
++    ASSERT_COND(h_FmPcd);
++    return ((t_FmPcd*)h_FmPcd)->h_Hc;
++}
++
++bool FmPcdIsAdvancedOffloadSupported(t_Handle h_FmPcd)
++{
++    ASSERT_COND(h_FmPcd);
++    return ((t_FmPcd*)h_FmPcd)->advancedOffloadSupport;
++}
++/*********************** End of inter-module routines ************************/
++
++
++/****************************************/
++/*       API Init unit functions        */
++/****************************************/
++
++t_Handle FM_PCD_Config(t_FmPcdParams *p_FmPcdParams)
++{
++    t_FmPcd             *p_FmPcd = NULL;
++    t_FmPhysAddr        physicalMuramBase;
++    uint8_t             i;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmPcdParams, E_INVALID_HANDLE,NULL);
++
++    p_FmPcd = (t_FmPcd *) XX_Malloc(sizeof(t_FmPcd));
++    if (!p_FmPcd)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD"));
++        return NULL;
++    }
++    memset(p_FmPcd, 0, sizeof(t_FmPcd));
++
++    p_FmPcd->p_FmPcdDriverParam = (t_FmPcdDriverParam *) XX_Malloc(sizeof(t_FmPcdDriverParam));
++    if (!p_FmPcd->p_FmPcdDriverParam)
++    {
++        XX_Free(p_FmPcd);
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Driver Param"));
++        return NULL;
++    }
++    memset(p_FmPcd->p_FmPcdDriverParam, 0, sizeof(t_FmPcdDriverParam));
++
++    p_FmPcd->h_Fm = p_FmPcdParams->h_Fm;
++    p_FmPcd->guestId = FmGetGuestId(p_FmPcd->h_Fm);
++    p_FmPcd->h_FmMuram = FmGetMuramHandle(p_FmPcd->h_Fm);
++    if (p_FmPcd->h_FmMuram)
++    {
++        FmGetPhysicalMuramBase(p_FmPcdParams->h_Fm, &physicalMuramBase);
++        p_FmPcd->physicalMuramBase = (uint64_t)((uint64_t)(&physicalMuramBase)->low | ((uint64_t)(&physicalMuramBase)->high << 32));
++    }
++
++    for (i = 0; i<FM_MAX_NUM_OF_PORTS; i++)
++        p_FmPcd->netEnvs[i].clsPlanGrpId = ILLEGAL_CLS_PLAN;
++
++    if (p_FmPcdParams->useHostCommand)
++    {
++        t_FmHcParams    hcParams;
++
++        memset(&hcParams, 0, sizeof(hcParams));
++        hcParams.h_Fm = p_FmPcd->h_Fm;
++        hcParams.h_FmPcd = (t_Handle)p_FmPcd;
++        memcpy((uint8_t*)&hcParams.params, (uint8_t*)&p_FmPcdParams->hc, sizeof(t_FmPcdHcParams));
++        p_FmPcd->h_Hc = FmHcConfigAndInit(&hcParams);
++        if (!p_FmPcd->h_Hc)
++        {
++            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD HC"));
++            FM_PCD_Free(p_FmPcd);
++            return NULL;
++        }
++    }
++    else if (p_FmPcd->guestId != NCSW_MASTER_ID)
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("No Host Command defined for a guest partition."));
++
++    if (p_FmPcdParams->kgSupport)
++    {
++        p_FmPcd->p_FmPcdKg = (t_FmPcdKg *)KgConfig(p_FmPcd, p_FmPcdParams);
++        if (!p_FmPcd->p_FmPcdKg)
++        {
++            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Keygen"));
++            FM_PCD_Free(p_FmPcd);
++            return NULL;
++        }
++    }
++
++    if (p_FmPcdParams->plcrSupport)
++    {
++        p_FmPcd->p_FmPcdPlcr = (t_FmPcdPlcr *)PlcrConfig(p_FmPcd, p_FmPcdParams);
++        if (!p_FmPcd->p_FmPcdPlcr)
++        {
++            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Policer"));
++            FM_PCD_Free(p_FmPcd);
++            return NULL;
++        }
++    }
++
++    if (p_FmPcdParams->prsSupport)
++    {
++        p_FmPcd->p_FmPcdPrs = (t_FmPcdPrs *)PrsConfig(p_FmPcd, p_FmPcdParams);
++        if (!p_FmPcd->p_FmPcdPrs)
++        {
++            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Parser"));
++            FM_PCD_Free(p_FmPcd);
++            return NULL;
++        }
++    }
++
++    p_FmPcd->h_Spinlock = XX_InitSpinlock();
++    if (!p_FmPcd->h_Spinlock)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD spinlock"));
++        FM_PCD_Free(p_FmPcd);
++        return NULL;
++    }
++    INIT_LIST(&p_FmPcd->freeLocksLst);
++    INIT_LIST(&p_FmPcd->acquiredLocksLst);
++
++    p_FmPcd->numOfEnabledGuestPartitionsPcds = 0;
++
++    p_FmPcd->f_Exception                = p_FmPcdParams->f_Exception;
++    p_FmPcd->f_FmPcdIndexedException    = p_FmPcdParams->f_ExceptionId;
++    p_FmPcd->h_App                      = p_FmPcdParams->h_App;
++
++    p_FmPcd->p_CcShadow                 = NULL;
++    p_FmPcd->ccShadowSize               = 0;
++    p_FmPcd->ccShadowAlign              = 0;
++
++    p_FmPcd->h_ShadowSpinlock = XX_InitSpinlock();
++    if (!p_FmPcd->h_ShadowSpinlock)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD shadow spinlock"));
++        FM_PCD_Free(p_FmPcd);
++        return NULL;
++    }
++
++    return p_FmPcd;
++}
++
++t_Error FM_PCD_Init(t_Handle h_FmPcd)
++{
++    t_FmPcd         *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    t_Error         err = E_OK;
++    t_FmPcdIpcMsg   msg;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
++
++    FM_GetRevision(p_FmPcd->h_Fm, &p_FmPcd->fmRevInfo);
++
++    if (p_FmPcd->guestId != NCSW_MASTER_ID)
++    {
++        memset(p_FmPcd->fmPcdIpcHandlerModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE);
++        if (Sprint (p_FmPcd->fmPcdIpcHandlerModuleName, "FM_PCD_%d_%d", FmGetId(p_FmPcd->h_Fm), NCSW_MASTER_ID) != 10)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
++        memset(p_FmPcd->fmPcdModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE);
++        if (Sprint (p_FmPcd->fmPcdModuleName, "FM_PCD_%d_%d",FmGetId(p_FmPcd->h_Fm), p_FmPcd->guestId) != (p_FmPcd->guestId<10 ? 10:11))
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
++
++        p_FmPcd->h_IpcSession = XX_IpcInitSession(p_FmPcd->fmPcdIpcHandlerModuleName, p_FmPcd->fmPcdModuleName);
++        if (p_FmPcd->h_IpcSession)
++        {
++            t_FmPcdIpcReply         reply;
++            uint32_t                replyLength;
++            uint8_t                 isMasterAlive = 0;
++
++            memset(&msg, 0, sizeof(msg));
++            memset(&reply, 0, sizeof(reply));
++            msg.msgId = FM_PCD_MASTER_IS_ALIVE;
++            msg.msgBody[0] = p_FmPcd->guestId;
++            blockingFlag = TRUE;
++
++            do
++            {
++                replyLength = sizeof(uint32_t) + sizeof(isMasterAlive);
++                if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
++                                             (uint8_t*)&msg,
++                                             sizeof(msg.msgId)+sizeof(p_FmPcd->guestId),
++                                             (uint8_t*)&reply,
++                                             &replyLength,
++                                             IpcMsgCompletionCB,
++                                             h_FmPcd)) != E_OK)
++                    REPORT_ERROR(MAJOR, err, NO_MSG);
++                while (blockingFlag) ;
++                if (replyLength != (sizeof(uint32_t) + sizeof(isMasterAlive)))
++                    REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++                isMasterAlive = *(uint8_t*)(reply.replyBody);
++            } while (!isMasterAlive);
++        }
++    }
++
++    CHECK_INIT_PARAMETERS(p_FmPcd, CheckFmPcdParameters);
++
++    if (p_FmPcd->p_FmPcdKg)
++    {
++        err = KgInit(p_FmPcd);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    if (p_FmPcd->p_FmPcdPlcr)
++    {
++        err = PlcrInit(p_FmPcd);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    if (p_FmPcd->p_FmPcdPrs)
++    {
++        err = PrsInit(p_FmPcd);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    if (p_FmPcd->guestId == NCSW_MASTER_ID)
++    {
++         /* register to inter-core messaging mechanism */
++        memset(p_FmPcd->fmPcdModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE);
++        if (Sprint (p_FmPcd->fmPcdModuleName, "FM_PCD_%d_%d",FmGetId(p_FmPcd->h_Fm),NCSW_MASTER_ID) != 10)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
++        err = XX_IpcRegisterMsgHandler(p_FmPcd->fmPcdModuleName, IpcMsgHandlerCB, p_FmPcd, FM_PCD_MAX_REPLY_SIZE);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    /* IPv6 Frame-Id used for fragmentation */
++    p_FmPcd->ipv6FrameIdAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, 4, 4));
++    if (!p_FmPcd->ipv6FrameIdAddr)
++    {
++        FM_PCD_Free(p_FmPcd);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for IPv6 Frame-Id"));
++    }
++    IOMemSet32(UINT_TO_PTR(p_FmPcd->ipv6FrameIdAddr), 0,  4);
++
++    /* CAPWAP Frame-Id used for fragmentation */
++    p_FmPcd->capwapFrameIdAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, 2, 4));
++    if (!p_FmPcd->capwapFrameIdAddr)
++    {
++        FM_PCD_Free(p_FmPcd);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CAPWAP Frame-Id"));
++    }
++    IOMemSet32(UINT_TO_PTR(p_FmPcd->capwapFrameIdAddr), 0,  2);
++
++    XX_Free(p_FmPcd->p_FmPcdDriverParam);
++    p_FmPcd->p_FmPcdDriverParam = NULL;
++
++    FmRegisterPcd(p_FmPcd->h_Fm, p_FmPcd);
++
++    return E_OK;
++}
++
++t_Error FM_PCD_Free(t_Handle h_FmPcd)
++{
++    t_FmPcd                             *p_FmPcd =(t_FmPcd *)h_FmPcd;
++    t_Error                             err = E_OK;
++
++    if (p_FmPcd->ipv6FrameIdAddr)
++        FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, UINT_TO_PTR(p_FmPcd->ipv6FrameIdAddr));
++
++    if (p_FmPcd->capwapFrameIdAddr)
++        FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, UINT_TO_PTR(p_FmPcd->capwapFrameIdAddr));
++
++    if (p_FmPcd->enabled)
++        FM_PCD_Disable(p_FmPcd);
++
++    if (p_FmPcd->p_FmPcdDriverParam)
++    {
++        XX_Free(p_FmPcd->p_FmPcdDriverParam);
++        p_FmPcd->p_FmPcdDriverParam = NULL;
++    }
++
++    if (p_FmPcd->p_FmPcdKg)
++    {
++        if ((err = KgFree(p_FmPcd)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        XX_Free(p_FmPcd->p_FmPcdKg);
++        p_FmPcd->p_FmPcdKg = NULL;
++    }
++
++    if (p_FmPcd->p_FmPcdPlcr)
++    {
++        PlcrFree(p_FmPcd);
++        XX_Free(p_FmPcd->p_FmPcdPlcr);
++        p_FmPcd->p_FmPcdPlcr = NULL;
++    }
++
++    if (p_FmPcd->p_FmPcdPrs)
++    {
++        if (p_FmPcd->guestId == NCSW_MASTER_ID)
++            PrsFree(p_FmPcd);
++        XX_Free(p_FmPcd->p_FmPcdPrs);
++        p_FmPcd->p_FmPcdPrs = NULL;
++    }
++
++    if (p_FmPcd->h_Hc)
++    {
++        FmHcFree(p_FmPcd->h_Hc);
++        p_FmPcd->h_Hc = NULL;
++    }
++
++    XX_IpcUnregisterMsgHandler(p_FmPcd->fmPcdModuleName);
++
++    FmUnregisterPcd(p_FmPcd->h_Fm);
++
++    ReleaseFreeLocksLst(p_FmPcd);
++
++    if (p_FmPcd->h_Spinlock)
++        XX_FreeSpinlock(p_FmPcd->h_Spinlock);
++
++    if (p_FmPcd->h_ShadowSpinlock)
++        XX_FreeSpinlock(p_FmPcd->h_ShadowSpinlock);
++
++    XX_Free(p_FmPcd);
++
++    return E_OK;
++}
++
++t_Error FM_PCD_ConfigException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable)
++{
++    t_FmPcd         *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint32_t        bitMask = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++
++    if (p_FmPcd->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigException - guest mode!"));
++
++    GET_FM_PCD_EXCEPTION_FLAG(bitMask, exception);
++    if (bitMask)
++    {
++        if (enable)
++            p_FmPcd->exceptions |= bitMask;
++        else
++            p_FmPcd->exceptions &= ~bitMask;
++   }
++    else
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
++
++    return E_OK;
++}
++
++t_Error FM_PCD_ConfigHcFramesDataMemory(t_Handle h_FmPcd, uint8_t memId)
++{
++    t_FmPcd         *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
++
++    return FmHcSetFramesDataMemory(p_FmPcd->h_Hc, memId);
++}
++
++t_Error FM_PCD_Enable(t_Handle h_FmPcd)
++{
++    t_FmPcd             *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    t_Error             err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
++
++    if (p_FmPcd->enabled)
++        return E_OK;
++
++    if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
++        p_FmPcd->h_IpcSession)
++    {
++        uint8_t         enabled;
++        t_FmPcdIpcMsg   msg;
++        t_FmPcdIpcReply reply;
++        uint32_t        replyLength;
++
++        memset(&reply, 0, sizeof(reply));
++        memset(&msg, 0, sizeof(msg));
++        msg.msgId = FM_PCD_MASTER_IS_ENABLED;
++        replyLength = sizeof(uint32_t) + sizeof(enabled);
++        if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
++                                     (uint8_t*)&msg,
++                                     sizeof(msg.msgId),
++                                     (uint8_t*)&reply,
++                                     &replyLength,
++                                     NULL,
++                                     NULL)) != E_OK)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        if (replyLength != sizeof(uint32_t) + sizeof(enabled))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++        p_FmPcd->enabled = (bool)!!(*(uint8_t*)(reply.replyBody));
++        if (!p_FmPcd->enabled)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-PCD master should be enabled first!"));
++
++        return E_OK;
++    }
++    else if (p_FmPcd->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("running in guest-mode without IPC!"));
++
++    if (p_FmPcd->p_FmPcdKg)
++        KgEnable(p_FmPcd);
++
++    if (p_FmPcd->p_FmPcdPlcr)
++        PlcrEnable(p_FmPcd);
++
++    if (p_FmPcd->p_FmPcdPrs)
++        PrsEnable(p_FmPcd);
++
++    p_FmPcd->enabled = TRUE;
++
++    return E_OK;
++}
++
++t_Error FM_PCD_Disable(t_Handle h_FmPcd)
++{
++    t_FmPcd             *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    t_Error             err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
++
++    if (!p_FmPcd->enabled)
++        return E_OK;
++
++    if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
++        p_FmPcd->h_IpcSession)
++    {
++        t_FmPcdIpcMsg       msg;
++        t_FmPcdIpcReply     reply;
++        uint32_t            replyLength;
++
++        memset(&reply, 0, sizeof(reply));
++        memset(&msg, 0, sizeof(msg));
++        msg.msgId = FM_PCD_GUEST_DISABLE;
++        replyLength = sizeof(uint32_t);
++        if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
++                                     (uint8_t*)&msg,
++                                     sizeof(msg.msgId),
++                                     (uint8_t*)&reply,
++                                     &replyLength,
++                                     NULL,
++                                     NULL)) != E_OK)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        if (replyLength != sizeof(uint32_t))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++        if (reply.error == E_OK)
++            p_FmPcd->enabled = FALSE;
++
++        return (t_Error)(reply.error);
++    }
++    else if (p_FmPcd->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("running in guest-mode without IPC!"));
++
++    if (p_FmPcd->numOfEnabledGuestPartitionsPcds != 0)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                     ("Trying to disable a master partition PCD while"
++                      "guest partitions are still enabled!"));
++
++    if (p_FmPcd->p_FmPcdKg)
++         KgDisable(p_FmPcd);
++
++    if (p_FmPcd->p_FmPcdPlcr)
++        PlcrDisable(p_FmPcd);
++
++    if (p_FmPcd->p_FmPcdPrs)
++        PrsDisable(p_FmPcd);
++
++    p_FmPcd->enabled = FALSE;
++
++    return E_OK;
++}
++
++t_Handle FM_PCD_NetEnvCharacteristicsSet(t_Handle h_FmPcd, t_FmPcdNetEnvParams  *p_NetEnvParams)
++{
++    t_FmPcd                 *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint32_t                intFlags, specialUnits = 0;
++    uint8_t                 bitId = 0;
++    uint8_t                 i, j, k;
++    uint8_t                 netEnvCurrId;
++    uint8_t                 ipsecAhUnit = 0,ipsecEspUnit = 0;
++    bool                    ipsecAhExists = FALSE, ipsecEspExists = FALSE, shim1Selected = FALSE;
++    uint8_t                 hdrNum;
++    t_FmPcdNetEnvParams     *p_ModifiedNetEnvParams;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_STATE, NULL);
++    SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, NULL);
++    SANITY_CHECK_RETURN_VALUE(p_NetEnvParams, E_NULL_POINTER, NULL);
++
++    intFlags = FmPcdLock(p_FmPcd);
++
++    /* find a new netEnv */
++    for (i = 0; i < FM_MAX_NUM_OF_PORTS; i++)
++        if (!p_FmPcd->netEnvs[i].used)
++            break;
++
++    if (i== FM_MAX_NUM_OF_PORTS)
++    {
++        REPORT_ERROR(MAJOR, E_FULL,("No more than %d netEnv's allowed.", FM_MAX_NUM_OF_PORTS));
++        FmPcdUnlock(p_FmPcd, intFlags);
++        return NULL;
++    }
++
++    p_FmPcd->netEnvs[i].used = TRUE;
++    FmPcdUnlock(p_FmPcd, intFlags);
++
++    /* As anyone doesn't have handle of this netEnv yet, no need
++       to protect it with spinlocks */
++
++    p_ModifiedNetEnvParams = (t_FmPcdNetEnvParams *)XX_Malloc(sizeof(t_FmPcdNetEnvParams));
++    if (!p_ModifiedNetEnvParams)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FmPcdNetEnvParams"));
++        return NULL;
++    }
++
++    memcpy(p_ModifiedNetEnvParams, p_NetEnvParams, sizeof(t_FmPcdNetEnvParams));
++    p_NetEnvParams = p_ModifiedNetEnvParams;
++
++    netEnvCurrId = (uint8_t)i;
++
++    /* clear from previous use */
++    memset(&p_FmPcd->netEnvs[netEnvCurrId].units, 0, FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS * sizeof(t_FmPcdIntDistinctionUnit));
++    memset(&p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs, 0, FM_PCD_MAX_NUM_OF_ALIAS_HDRS * sizeof(t_FmPcdNetEnvAliases));
++    memcpy(&p_FmPcd->netEnvs[netEnvCurrId].units, p_NetEnvParams->units, p_NetEnvParams->numOfDistinctionUnits*sizeof(t_FmPcdIntDistinctionUnit));
++
++    p_FmPcd->netEnvs[netEnvCurrId].netEnvId = netEnvCurrId;
++    p_FmPcd->netEnvs[netEnvCurrId].h_FmPcd = p_FmPcd;
++
++    p_FmPcd->netEnvs[netEnvCurrId].clsPlanGrpId = ILLEGAL_CLS_PLAN;
++
++    /* check that header with opt is not interchanged with the same header */
++    for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
++            && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++)
++    {
++        for (k = 0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS)
++            && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++)
++        {
++            /* if an option exists, check that other headers are not the same header
++            without option */
++            if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt)
++            {
++                for (j = 0; (j < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS)
++                        && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[j].hdr != HEADER_TYPE_NONE); j++)
++                {
++                    if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[j].hdr == p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr) &&
++                        !p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[j].opt)
++                    {
++                        REPORT_ERROR(MINOR, E_FULL,
++                                ("Illegal unit - header with opt may not be interchangeable with the same header without opt"));
++                        XX_Free(p_ModifiedNetEnvParams);
++                        return NULL;
++                    }
++                }
++            }
++        }
++    }
++
++    /* Specific headers checking  */
++    for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
++        && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++)
++    {
++        for (k = 0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS)
++            && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++)
++        {
++            /* Some headers pairs may not be defined on different units as the parser
++            doesn't distinguish */
++            /* IPSEC_AH and IPSEC_SPI can't be 2 units,  */
++            /* check that header with opt is not interchanged with the same header */
++            if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPSEC_AH)
++            {
++                if (ipsecEspExists && (ipsecEspUnit != i))
++                {
++                    REPORT_ERROR(MINOR, E_INVALID_STATE, ("HEADER_TYPE_IPSEC_AH and HEADER_TYPE_IPSEC_ESP may not be defined in separate units"));
++                    XX_Free(p_ModifiedNetEnvParams);
++                    return NULL;
++                }
++                else
++                {
++                    ipsecAhUnit = i;
++                    ipsecAhExists = TRUE;
++                }
++            }
++            if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPSEC_ESP)
++            {
++                if (ipsecAhExists && (ipsecAhUnit != i))
++                {
++                    REPORT_ERROR(MINOR, E_INVALID_STATE, ("HEADER_TYPE_IPSEC_AH and HEADER_TYPE_IPSEC_ESP may not be defined in separate units"));
++                    XX_Free(p_ModifiedNetEnvParams);
++                    return NULL;
++                }
++                else
++                {
++                    ipsecEspUnit = i;
++                    ipsecEspExists = TRUE;
++                }
++            }
++            /* ENCAP_ESP  */
++            if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_UDP_ENCAP_ESP)
++            {
++                /* IPSec UDP encapsulation is currently set to use SHIM1 */
++                p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_UDP_ENCAP_ESP;
++                p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM1;
++                p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM1;
++                p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0;
++            }
++#if (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++            /* UDP_LITE  */
++            if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_UDP_LITE)
++            {
++                p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_UDP_LITE;
++                p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_UDP;
++                p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_UDP;
++                p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0;
++            }
++#endif /* (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
++
++            /* IP FRAG  */
++            if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPv4) &&
++                (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt == IPV4_FRAG_1))
++            {
++                /* If IPv4+Frag, we need to set 2 units - SHIM 2 and IPv4. We first set SHIM2, and than check if
++                 * IPv4 exists. If so we don't need to set an extra unit
++                 * We consider as "having IPv4" any IPv4 without interchangable headers
++                 * but including any options.  */
++                p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_IPv4;
++                p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].opt = IPV4_FRAG_1;
++                p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM2;
++                p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM2;
++                p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0;
++
++                /* check if IPv4 header exists by itself */
++                if (FmPcdNetEnvGetUnitId(p_FmPcd, netEnvCurrId, HEADER_TYPE_IPv4, FALSE, 0) == FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
++                {
++                    p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits].hdrs[0].hdr = HEADER_TYPE_IPv4;
++                    p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits++].hdrs[0].opt = 0;
++                }
++            }
++            if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPv6) &&
++                (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt == IPV6_FRAG_1))
++            {
++                /* If IPv6+Frag, we need to set 2 units - SHIM 2 and IPv6. We first set SHIM2, and than check if
++                 * IPv4 exists. If so we don't need to set an extra unit
++                 * We consider as "having IPv6" any IPv6 without interchangable headers
++                 * but including any options.  */
++                p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_IPv6;
++                p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].opt = IPV6_FRAG_1;
++                p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM2;
++                p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM2;
++                p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0;
++
++                /* check if IPv6 header exists by itself */
++                if (FmPcdNetEnvGetUnitId(p_FmPcd, netEnvCurrId, HEADER_TYPE_IPv6, FALSE, 0) == FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
++                {
++                    p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits].hdrs[0].hdr = HEADER_TYPE_IPv6;
++                    p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits++].hdrs[0].opt = 0;
++                }
++            }
++#if (DPAA_VERSION >= 11)
++            /* CAPWAP FRAG  */
++            if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_CAPWAP) &&
++                (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt == CAPWAP_FRAG_1))
++            {
++                p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_CAPWAP;
++                p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].opt = CAPWAP_FRAG_1;
++                p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM2;
++                p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM2;
++                p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0;
++            }
++#endif /* (DPAA_VERSION >= 11) */
++        }
++    }
++
++    /* if private header (shim), check that no other headers specified */
++    for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
++        && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++)
++    {
++        if (IS_PRIVATE_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr))
++            if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[1].hdr != HEADER_TYPE_NONE)
++            {
++                REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("SHIM header may not be interchanged with other headers"));
++                XX_Free(p_ModifiedNetEnvParams);
++                return NULL;
++            }
++    }
++
++    for (i = 0; i < p_NetEnvParams->numOfDistinctionUnits; i++)
++    {
++        if (IS_PRIVATE_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr))
++            switch (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr)
++            {
++                case (HEADER_TYPE_USER_DEFINED_SHIM1):
++                    if (shim1Selected)
++                    {
++                        REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("SHIM header cannot be selected with UDP_IPSEC_ESP"));
++                        XX_Free(p_ModifiedNetEnvParams);
++                        return NULL;
++                    }
++                    shim1Selected = TRUE;
++                    p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i] = 0x00000001;
++                    break;
++                case (HEADER_TYPE_USER_DEFINED_SHIM2):
++                    p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i] = 0x00000002;
++                    break;
++                default:
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Requested SHIM not supported"));
++            }
++        else
++        {
++            p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i] = (uint32_t)(0x80000000 >> bitId++);
++
++            if (IS_SPECIAL_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr))
++                p_FmPcd->netEnvs[netEnvCurrId].macsecVector = p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i];
++        }
++    }
++
++    /* define a set of hardware parser LCV's according to the defined netenv */
++
++    /* set an array of LCV's for each header in the netEnv */
++    for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
++        && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++)
++    {
++        /* private headers have no LCV in the hard parser */
++        if (!IS_PRIVATE_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr))
++        {
++            for (k = 0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS)
++                    && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++)
++            {
++                hdrNum = GetPrsHdrNum(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr);
++                if ((hdrNum == ILLEGAL_HDR_NUM) || (hdrNum == NO_HDR_NUM))
++                {
++                    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG);
++                    XX_Free(p_ModifiedNetEnvParams);
++                    return NULL;
++                }
++                p_FmPcd->netEnvs[netEnvCurrId].lcvs[hdrNum] |= p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i];
++            }
++        }
++    }
++    XX_Free(p_ModifiedNetEnvParams);
++
++    p_FmPcd->netEnvs[netEnvCurrId].h_Spinlock = XX_InitSpinlock();
++    if (!p_FmPcd->netEnvs[netEnvCurrId].h_Spinlock)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Pcd NetEnv spinlock"));
++        return NULL;
++    }
++    return &p_FmPcd->netEnvs[netEnvCurrId];
++}
++
++t_Error FM_PCD_NetEnvCharacteristicsDelete(t_Handle h_NetEnv)
++{
++    t_FmPcdNetEnv   *p_NetEnv = (t_FmPcdNetEnv*)h_NetEnv;
++    t_FmPcd         *p_FmPcd = p_NetEnv->h_FmPcd;
++    uint32_t        intFlags;
++    uint8_t         netEnvId = p_NetEnv->netEnvId;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
++
++    /* check that no port is bound to this netEnv */
++    if (p_FmPcd->netEnvs[netEnvId].owners)
++    {
++        RETURN_ERROR(MINOR, E_INVALID_STATE,
++                ("Trying to delete a netEnv that has ports/schemes/trees/clsPlanGrps bound to"));
++    }
++
++    intFlags = FmPcdLock(p_FmPcd);
++
++    p_FmPcd->netEnvs[netEnvId].used = FALSE;
++    p_FmPcd->netEnvs[netEnvId].clsPlanGrpId = ILLEGAL_CLS_PLAN;
++
++    memset(p_FmPcd->netEnvs[netEnvId].units, 0, sizeof(t_FmPcdIntDistinctionUnit)*FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
++    memset(p_FmPcd->netEnvs[netEnvId].unitsVectors, 0, sizeof(uint32_t)*FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
++    memset(p_FmPcd->netEnvs[netEnvId].lcvs, 0, sizeof(uint32_t)*FM_PCD_PRS_NUM_OF_HDRS);
++
++    if (p_FmPcd->netEnvs[netEnvId].h_Spinlock)
++        XX_FreeSpinlock(p_FmPcd->netEnvs[netEnvId].h_Spinlock);
++
++    FmPcdUnlock(p_FmPcd, intFlags);
++    return E_OK;
++}
++
++void FM_PCD_HcTxConf(t_Handle h_FmPcd, t_DpaaFD *p_Fd)
++{
++    t_FmPcd                 *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    SANITY_CHECK_RETURN(h_FmPcd, E_INVALID_STATE);
++
++    FmHcTxConf(p_FmPcd->h_Hc, p_Fd);
++}
++
++t_Error FM_PCD_SetAdvancedOffloadSupport(t_Handle h_FmPcd)
++{
++    t_FmPcd                     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    t_FmCtrlCodeRevisionInfo    revInfo;
++    t_Error                     err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->enabled, E_INVALID_STATE);
++
++    if ((err = FM_GetFmanCtrlCodeRevision(p_FmPcd->h_Fm, &revInfo)) != E_OK)
++    {
++        DBG(WARNING, ("FM in guest-mode without IPC, can't validate firmware revision."));
++        revInfo.packageRev = IP_OFFLOAD_PACKAGE_NUMBER;
++    }
++    if (!IS_OFFLOAD_PACKAGE(revInfo.packageRev))
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Fman ctrl code package"));
++
++    if (!p_FmPcd->h_Hc)
++        RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("HC must be initialized in this mode"));
++
++    p_FmPcd->advancedOffloadSupport = TRUE;
++
++    return E_OK;
++}
++
++uint32_t FM_PCD_GetCounter(t_Handle h_FmPcd, e_FmPcdCounters counter)
++{
++    t_FmPcd                 *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint32_t                outCounter = 0;
++    t_Error                 err;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0);
++    SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0);
++
++    switch (counter)
++    {
++        case (e_FM_PCD_KG_COUNTERS_TOTAL):
++            if (!p_FmPcd->p_FmPcdKg)
++            {
++                REPORT_ERROR(MAJOR, E_INVALID_STATE, ("KeyGen is not activated"));
++                return 0;
++            }
++            if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
++                !p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs &&
++                !p_FmPcd->h_IpcSession)
++            {
++                REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
++                             ("running in guest-mode without neither IPC nor mapped register!"));
++                return 0;
++            }
++            break;
++
++        case (e_FM_PCD_PLCR_COUNTERS_YELLOW):
++        case (e_FM_PCD_PLCR_COUNTERS_RED):
++        case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED):
++        case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW):
++        case (e_FM_PCD_PLCR_COUNTERS_TOTAL):
++        case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH):
++            if (!p_FmPcd->p_FmPcdPlcr)
++            {
++                REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Policer is not activated"));
++                return 0;
++            }
++            if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
++                !p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs &&
++                !p_FmPcd->h_IpcSession)
++            {
++                REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
++                             ("running in \"guest-mode\" without neither IPC nor mapped register!"));
++                return 0;
++            }
++
++            /* check that counters are enabled */
++            if (p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs &&
++                !(GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr) & FM_PCD_PLCR_GCR_STEN))
++            {
++                REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled"));
++                return 0;
++            }
++            ASSERT_COND(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs ||
++                        ((p_FmPcd->guestId != NCSW_MASTER_ID) && p_FmPcd->h_IpcSession));
++            break;
++
++        case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH):
++        case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED):
++        case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED):
++        case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED):
++        case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED):
++        case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR):
++        case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR):
++        case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR):
++        case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR):
++        case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES):
++        case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES):
++        case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES):
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES):
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES):
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES):
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES):
++        case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES):
++            if (!p_FmPcd->p_FmPcdPrs)
++            {
++                REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Parser is not activated"));
++                return 0;
++            }
++            if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
++                !p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs &&
++                !p_FmPcd->h_IpcSession)
++            {
++                REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
++                             ("running in guest-mode without neither IPC nor mapped register!"));
++                return 0;
++            }
++            break;
++        default:
++            REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported type of counter"));
++            return 0;
++    }
++
++    if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
++        p_FmPcd->h_IpcSession)
++    {
++        t_FmPcdIpcMsg           msg;
++        t_FmPcdIpcReply         reply;
++        uint32_t                replyLength;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_PCD_GET_COUNTER;
++        memcpy(msg.msgBody, (uint8_t *)&counter, sizeof(uint32_t));
++        replyLength = sizeof(uint32_t) + sizeof(uint32_t);
++        if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
++                                     (uint8_t*)&msg,
++                                     sizeof(msg.msgId) +sizeof(uint32_t),
++                                     (uint8_t*)&reply,
++                                     &replyLength,
++                                     NULL,
++                                     NULL)) != E_OK)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        if (replyLength != sizeof(uint32_t) + sizeof(uint32_t))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++
++        memcpy((uint8_t*)&outCounter, reply.replyBody, sizeof(uint32_t));
++        return outCounter;
++    }
++
++    switch (counter)
++    {
++        /* Parser statistics */
++        case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pds);
++        case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rrs);
++        case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rrs);
++        case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rrs);
++        case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srrs);
++        case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rres);
++        case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rres);
++        case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rres);
++        case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srres);
++        case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spcs);
++        case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spscs);
++        case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_hxscs);
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrcs);
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrscs);
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwcs);
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwscs);
++        case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES):
++               return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_fcscs);
++        case (e_FM_PCD_KG_COUNTERS_TOTAL):
++               return GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_tpc);
++
++        /* Policer statistics */
++        case (e_FM_PCD_PLCR_COUNTERS_YELLOW):
++                return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ypcnt);
++        case (e_FM_PCD_PLCR_COUNTERS_RED):
++                return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rpcnt);
++        case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED):
++                return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rrpcnt);
++        case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW):
++                return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rypcnt);
++        case (e_FM_PCD_PLCR_COUNTERS_TOTAL):
++                return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_tpcnt);
++        case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH):
++                return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_flmcnt);
++    }
++    return 0;
++}
++
++t_Error FM_PCD_SetException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable)
++{
++    t_FmPcd         *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint32_t        bitMask = 0, tmpReg;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
++
++    if (p_FmPcd->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetException - guest mode!"));
++
++    GET_FM_PCD_EXCEPTION_FLAG(bitMask, exception);
++
++    if (bitMask)
++    {
++        if (enable)
++            p_FmPcd->exceptions |= bitMask;
++        else
++            p_FmPcd->exceptions &= ~bitMask;
++
++        switch (exception)
++        {
++            case (e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC):
++            case (e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW):
++                if (!p_FmPcd->p_FmPcdKg)
++                    RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - keygen is not working"));
++                break;
++            case (e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC):
++            case (e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR):
++            case (e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE):
++            case (e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE):
++                if (!p_FmPcd->p_FmPcdPlcr)
++                    RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - policer is not working"));
++                break;
++            case (e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC):
++            case (e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC):
++                if (!p_FmPcd->p_FmPcdPrs)
++                    RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - parser is not working"));
++                break;
++        }
++
++        switch (exception)
++        {
++            case (e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC):
++                tmpReg = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer);
++                if (enable)
++                    tmpReg |= FM_EX_KG_DOUBLE_ECC;
++                else
++                    tmpReg &= ~FM_EX_KG_DOUBLE_ECC;
++                WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer, tmpReg);
++                break;
++            case (e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW):
++                tmpReg = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer);
++                if (enable)
++                    tmpReg |= FM_EX_KG_KEYSIZE_OVERFLOW;
++                else
++                    tmpReg &= ~FM_EX_KG_KEYSIZE_OVERFLOW;
++                WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer, tmpReg);
++                break;
++            case (e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC):
++                tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_perer);
++                if (enable)
++                    tmpReg |= FM_PCD_PRS_DOUBLE_ECC;
++                else
++                    tmpReg &= ~FM_PCD_PRS_DOUBLE_ECC;
++                WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_perer, tmpReg);
++                break;
++            case (e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC):
++                tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pever);
++                if (enable)
++                    tmpReg |= FM_PCD_PRS_SINGLE_ECC;
++                else
++                    tmpReg &= ~FM_PCD_PRS_SINGLE_ECC;
++                WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pever, tmpReg);
++                break;
++            case (e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC):
++                tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier);
++                if (enable)
++                    tmpReg |= FM_PCD_PLCR_DOUBLE_ECC;
++                else
++                    tmpReg &= ~FM_PCD_PLCR_DOUBLE_ECC;
++                WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier, tmpReg);
++                break;
++            case (e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR):
++                tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier);
++                if (enable)
++                    tmpReg |= FM_PCD_PLCR_INIT_ENTRY_ERROR;
++                else
++                    tmpReg &= ~FM_PCD_PLCR_INIT_ENTRY_ERROR;
++                WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier, tmpReg);
++                break;
++            case (e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE):
++                tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier);
++                if (enable)
++                    tmpReg |= FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE;
++                else
++                    tmpReg &= ~FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE;
++                WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier, tmpReg);
++                break;
++            case (e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE):
++                tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier);
++                if (enable)
++                    tmpReg |= FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE;
++                else
++                    tmpReg &= ~FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE;
++                WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier, tmpReg);
++                break;
++        }
++        /* for ECC exceptions driver automatically enables ECC mechanism, if disabled.
++           Driver may disable them automatically, depending on driver's status */
++        if (enable && ((exception == e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC) |
++                       (exception == e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC) |
++                       (exception == e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC) |
++                       (exception == e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC)))
++            FmEnableRamsEcc(p_FmPcd->h_Fm);
++        if (!enable && ((exception == e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC) |
++                       (exception == e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC) |
++                       (exception == e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC) |
++                       (exception == e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC)))
++            FmDisableRamsEcc(p_FmPcd->h_Fm);
++    }
++
++    return E_OK;
++}
++
++t_Error FM_PCD_ForceIntr (t_Handle h_FmPcd, e_FmPcdExceptions exception)
++{
++    t_FmPcd            *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
++
++    if (p_FmPcd->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ForceIntr - guest mode!"));
++
++    switch (exception)
++    {
++        case (e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC):
++        case (e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW):
++            if (!p_FmPcd->p_FmPcdKg)
++                RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - keygen is not working"));
++            break;
++        case (e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC):
++        case (e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR):
++        case (e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE):
++        case (e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE):
++            if (!p_FmPcd->p_FmPcdPlcr)
++                RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - policer is not working"));
++            break;
++        case (e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC):
++        case (e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC):
++           if (!p_FmPcd->p_FmPcdPrs)
++                RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt -parsrer is not working"));
++            break;
++        default:
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid interrupt requested"));
++    }
++    switch (exception)
++    {
++        case e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC:
++            if (!(p_FmPcd->exceptions & FM_PCD_EX_PRS_DOUBLE_ECC))
++                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
++            break;
++        case e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC:
++            if (!(p_FmPcd->exceptions & FM_PCD_EX_PRS_SINGLE_ECC))
++                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
++            break;
++        case e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC:
++            if (!(p_FmPcd->exceptions & FM_EX_KG_DOUBLE_ECC))
++                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
++            WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_feer, FM_EX_KG_DOUBLE_ECC);
++            break;
++        case e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW:
++            if (!(p_FmPcd->exceptions & FM_EX_KG_KEYSIZE_OVERFLOW))
++                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
++            WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_feer, FM_EX_KG_KEYSIZE_OVERFLOW);
++            break;
++        case e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC:
++            if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_DOUBLE_ECC))
++                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
++            WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, FM_PCD_PLCR_DOUBLE_ECC);
++            break;
++        case e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR:
++            if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_INIT_ENTRY_ERROR))
++                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
++            WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, FM_PCD_PLCR_INIT_ENTRY_ERROR);
++            break;
++        case e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE:
++            if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE))
++                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
++            WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE);
++            break;
++        case e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE:
++            if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE))
++                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
++            WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE);
++            break;
++    }
++
++    return E_OK;
++}
++
++
++t_Error FM_PCD_ModifyCounter(t_Handle h_FmPcd, e_FmPcdCounters counter, uint32_t value)
++{
++    t_FmPcd            *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
++
++    if (p_FmPcd->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ModifyCounter - guest mode!"));
++
++    switch (counter)
++    {
++        case (e_FM_PCD_KG_COUNTERS_TOTAL):
++            if (!p_FmPcd->p_FmPcdKg)
++                RETURN_ERROR(MINOR, E_INVALID_STATE, ("Invalid counters - KeyGen is not working"));
++            break;
++        case (e_FM_PCD_PLCR_COUNTERS_YELLOW):
++        case (e_FM_PCD_PLCR_COUNTERS_RED):
++        case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED):
++        case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW):
++        case (e_FM_PCD_PLCR_COUNTERS_TOTAL):
++        case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH):
++            if (!p_FmPcd->p_FmPcdPlcr)
++                RETURN_ERROR(MINOR, E_INVALID_STATE, ("Invalid counters - Policer is not working"));
++            if (!(GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr) & FM_PCD_PLCR_GCR_STEN))
++                RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled"));
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH):
++        case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED):
++        case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED):
++        case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED):
++        case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED):
++        case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR):
++        case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR):
++        case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR):
++        case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR):
++        case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES):
++        case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES):
++        case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES):
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES):
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES):
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES):
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES):
++        case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES):
++            if (!p_FmPcd->p_FmPcdPrs)
++                RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported type of counter"));
++            break;
++        default:
++            RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported type of counter"));
++    }
++    switch (counter)
++    {
++        case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pds, value);
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rrs, value);
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rrs, value);
++             break;
++       case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rrs, value);
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srrs, value);
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rres, value);
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rres, value);
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rres, value);
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srres, value);
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spcs, value);
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spscs, value);
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_hxscs, value);
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrcs, value);
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrscs, value);
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwcs, value);
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwscs, value);
++            break;
++        case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES):
++               WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_fcscs, value);
++             break;
++        case (e_FM_PCD_KG_COUNTERS_TOTAL):
++            WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_tpc,value);
++            break;
++
++        /*Policer counters*/
++        case (e_FM_PCD_PLCR_COUNTERS_YELLOW):
++            WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ypcnt, value);
++            break;
++        case (e_FM_PCD_PLCR_COUNTERS_RED):
++            WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rpcnt, value);
++            break;
++        case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED):
++             WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rrpcnt, value);
++            break;
++        case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW):
++              WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rypcnt, value);
++            break;
++        case (e_FM_PCD_PLCR_COUNTERS_TOTAL):
++              WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_tpcnt, value);
++            break;
++        case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH):
++              WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_flmcnt, value);
++            break;
++    }
++
++    return E_OK;
++}
++
++t_Handle FM_PCD_GetHcPort(t_Handle h_FmPcd)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    return FmHcGetPort(p_FmPcd->h_Hc);
++}
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.h
+@@ -0,0 +1,543 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_pcd.h
++
++ @Description   FM PCD ...
++*//***************************************************************************/
++#ifndef __FM_PCD_H
++#define __FM_PCD_H
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "list_ext.h"
++#include "fm_pcd_ext.h"
++#include "fm_common.h"
++#include "fsl_fman_prs.h"
++#include "fsl_fman_kg.h"
++
++#define __ERR_MODULE__  MODULE_FM_PCD
++
++
++/****************************/
++/* Defaults                 */
++/****************************/
++#define DEFAULT_plcrAutoRefresh                 FALSE
++#define DEFAULT_fmPcdKgErrorExceptions          (FM_EX_KG_DOUBLE_ECC | FM_EX_KG_KEYSIZE_OVERFLOW)
++#define DEFAULT_fmPcdPlcrErrorExceptions        (FM_PCD_EX_PLCR_DOUBLE_ECC | FM_PCD_EX_PLCR_INIT_ENTRY_ERROR)
++#define DEFAULT_fmPcdPlcrExceptions             0
++#define DEFAULT_fmPcdPrsErrorExceptions         (FM_PCD_EX_PRS_DOUBLE_ECC)
++
++#define DEFAULT_fmPcdPrsExceptions              FM_PCD_EX_PRS_SINGLE_ECC
++#define DEFAULT_numOfUsedProfilesPerWindow      16
++#define DEFAULT_numOfSharedPlcrProfiles         4
++
++/****************************/
++/* Network defines          */
++/****************************/
++#define UDP_HEADER_SIZE     8
++
++#define ESP_SPI_OFFSET      0
++#define ESP_SPI_SIZE        4
++#define ESP_SEQ_NUM_OFFSET  ESP_SPI_SIZE
++#define ESP_SEQ_NUM_SIZE    4
++
++/****************************/
++/* General defines          */
++/****************************/
++#define ILLEGAL_CLS_PLAN    0xff
++#define ILLEGAL_NETENV      0xff
++
++#define FM_PCD_MAX_NUM_OF_ALIAS_HDRS    3
++
++/****************************/
++/* Error defines           */
++/****************************/
++
++#define FM_PCD_EX_PLCR_DOUBLE_ECC                   0x20000000
++#define FM_PCD_EX_PLCR_INIT_ENTRY_ERROR             0x10000000
++#define FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE      0x08000000
++#define FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE       0x04000000
++
++#define GET_FM_PCD_EXCEPTION_FLAG(bitMask, exception)               \
++switch (exception){                                                 \
++    case e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC:                          \
++        bitMask = FM_EX_KG_DOUBLE_ECC; break;                   \
++    case e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC:                        \
++        bitMask = FM_PCD_EX_PLCR_DOUBLE_ECC; break;                 \
++    case e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW:                    \
++        bitMask = FM_EX_KG_KEYSIZE_OVERFLOW; break;             \
++    case e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR:                  \
++        bitMask = FM_PCD_EX_PLCR_INIT_ENTRY_ERROR; break;           \
++    case e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE:           \
++        bitMask = FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE; break;    \
++    case e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE:            \
++        bitMask = FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE; break;     \
++    case e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC:                         \
++        bitMask = FM_PCD_EX_PRS_DOUBLE_ECC; break;                  \
++    case e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC:                         \
++        bitMask = FM_PCD_EX_PRS_SINGLE_ECC; break;                  \
++    default: bitMask = 0;break;}
++
++/***********************************************************************/
++/*          Policer defines                                            */
++/***********************************************************************/
++#define FM_PCD_PLCR_GCR_STEN                  0x40000000
++#define FM_PCD_PLCR_DOUBLE_ECC                0x80000000
++#define FM_PCD_PLCR_INIT_ENTRY_ERROR          0x40000000
++#define FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE   0x80000000
++#define FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE    0x40000000
++
++/***********************************************************************/
++/*          Memory map                                                 */
++/***********************************************************************/
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(push,1)
++#endif /* defined(__MWERKS__) && ... */
++
++
++typedef struct {
++/* General Configuration and Status Registers */
++    volatile uint32_t fmpl_gcr;         /* 0x000 FMPL_GCR  - FM Policer General Configuration */
++    volatile uint32_t fmpl_gsr;         /* 0x004 FMPL_GSR  - FM Policer Global Status Register */
++    volatile uint32_t fmpl_evr;         /* 0x008 FMPL_EVR  - FM Policer Event Register */
++    volatile uint32_t fmpl_ier;         /* 0x00C FMPL_IER  - FM Policer Interrupt Enable Register */
++    volatile uint32_t fmpl_ifr;         /* 0x010 FMPL_IFR  - FM Policer Interrupt Force Register */
++    volatile uint32_t fmpl_eevr;        /* 0x014 FMPL_EEVR - FM Policer Error Event Register */
++    volatile uint32_t fmpl_eier;        /* 0x018 FMPL_EIER - FM Policer Error Interrupt Enable Register */
++    volatile uint32_t fmpl_eifr;        /* 0x01C FMPL_EIFR - FM Policer Error Interrupt Force Register */
++/* Global Statistic Counters */
++    volatile uint32_t fmpl_rpcnt;       /* 0x020 FMPL_RPC  - FM Policer RED Packets Counter */
++    volatile uint32_t fmpl_ypcnt;       /* 0x024 FMPL_YPC  - FM Policer YELLOW Packets Counter */
++    volatile uint32_t fmpl_rrpcnt;      /* 0x028 FMPL_RRPC - FM Policer Recolored RED Packet Counter */
++    volatile uint32_t fmpl_rypcnt;      /* 0x02C FMPL_RYPC - FM Policer Recolored YELLOW Packet Counter */
++    volatile uint32_t fmpl_tpcnt;       /* 0x030 FMPL_TPC  - FM Policer Total Packet Counter */
++    volatile uint32_t fmpl_flmcnt;      /* 0x034 FMPL_FLMC - FM Policer Frame Length Mismatch Counter */
++    volatile uint32_t fmpl_res0[21];    /* 0x038 - 0x08B Reserved */
++/* Profile RAM Access Registers */
++    volatile uint32_t fmpl_par;         /* 0x08C FMPL_PAR    - FM Policer Profile Action Register*/
++    t_FmPcdPlcrProfileRegs profileRegs;
++/* Error Capture Registers */
++    volatile uint32_t fmpl_serc;        /* 0x100 FMPL_SERC - FM Policer Soft Error Capture */
++    volatile uint32_t fmpl_upcr;        /* 0x104 FMPL_UPCR - FM Policer Uninitialized Profile Capture Register */
++    volatile uint32_t fmpl_res2;        /* 0x108 Reserved */
++/* Debug Registers */
++    volatile uint32_t fmpl_res3[61];    /* 0x10C-0x200 Reserved Debug*/
++/* Profile Selection Mapping Registers Per Port-ID (n=1-11, 16) */
++    volatile uint32_t fmpl_dpmr;        /* 0x200 FMPL_DPMR - FM Policer Default Mapping Register */
++    volatile uint32_t fmpl_pmr[63];     /*+default 0x204-0x2FF FMPL_PMR1 - FMPL_PMR63, - FM Policer Profile Mapping Registers.
++                                           (for port-ID 1-11, only for supported Port-ID registers) */
++} t_FmPcdPlcrRegs;
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(pop)
++#endif /* defined(__MWERKS__) && ... */
++
++
++/***********************************************************************/
++/*  Driver's internal structures                                       */
++/***********************************************************************/
++
++typedef struct {
++    bool        known;
++    uint8_t     id;
++} t_FmPcdKgSchemesExtractsEntry;
++
++typedef struct {
++    t_FmPcdKgSchemesExtractsEntry extractsArray[FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY];
++} t_FmPcdKgSchemesExtracts;
++
++typedef struct {
++    t_Handle        h_Manip;
++    bool            keepRes;
++    e_FmPcdEngine   nextEngine;
++    uint8_t         parseCode;
++} t_FmPcdInfoForManip;
++
++/**************************************************************************//**
++ @Description   A structure of parameters to communicate
++                between the port and PCD regarding the KG scheme.
++*//***************************************************************************/
++typedef struct {
++    uint8_t             netEnvId;    /* in */
++    uint8_t             numOfDistinctionUnits; /* in */
++    uint8_t             unitIds[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; /* in */
++    uint32_t            vector; /* out */
++} t_NetEnvParams;
++
++typedef struct {
++    bool            allocated;
++    uint8_t         ownerId; /* guestId for KG in multi-partition only.
++                                portId for PLCR in any environment */
++} t_FmPcdAllocMng;
++
++typedef struct {
++    volatile bool       lock;
++    bool                used;
++    uint8_t             owners;
++    uint8_t             netEnvId;
++    uint8_t             guestId;
++    uint8_t             baseEntry;
++    uint16_t            sizeOfGrp;
++    protocolOpt_t       optArray[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)];
++} t_FmPcdKgClsPlanGrp;
++
++typedef struct {
++    t_Handle            h_FmPcd;
++    uint8_t             schemeId;
++    t_FmPcdLock         *p_Lock;
++    bool                valid;
++    uint8_t             netEnvId;
++    uint8_t             owners;
++    uint32_t            matchVector;
++    uint32_t            ccUnits;
++    bool                nextRelativePlcrProfile;
++    uint16_t            relativeProfileId;
++    uint16_t            numOfProfiles;
++    t_FmPcdKgKeyOrder   orderedArray;
++    e_FmPcdEngine       nextEngine;
++    e_FmPcdDoneAction   doneAction;
++    bool                requiredActionFlag;
++    uint32_t            requiredAction;
++    bool                extractedOrs;
++    uint8_t             bitOffsetInPlcrProfile;
++    bool                directPlcr;
++#if (DPAA_VERSION >= 11)
++    bool                vspe;
++#endif
++} t_FmPcdKgScheme;
++
++typedef union {
++    struct fman_kg_scheme_regs schemeRegs;
++    struct fman_kg_pe_regs portRegs;
++    struct fman_kg_cp_regs clsPlanRegs;
++} u_FmPcdKgIndirectAccessRegs;
++
++typedef struct {
++    struct fman_kg_regs *p_FmPcdKgRegs;
++    uint32_t            schemeExceptionsBitMask;
++    uint8_t             numOfSchemes;
++    t_Handle            h_HwSpinlock;
++    uint8_t             schemesIds[FM_PCD_KG_NUM_OF_SCHEMES];
++    t_FmPcdKgScheme     schemes[FM_PCD_KG_NUM_OF_SCHEMES];
++    t_FmPcdKgClsPlanGrp clsPlanGrps[FM_MAX_NUM_OF_PORTS];
++    uint8_t             emptyClsPlanGrpId;
++    t_FmPcdAllocMng     schemesMng[FM_PCD_KG_NUM_OF_SCHEMES]; /* only for MASTER ! */
++    t_FmPcdAllocMng     clsPlanBlocksMng[FM_PCD_MAX_NUM_OF_CLS_PLANS/CLS_PLAN_NUM_PER_GRP];
++    u_FmPcdKgIndirectAccessRegs *p_IndirectAccessRegs;
++} t_FmPcdKg;
++
++typedef struct {
++    uint16_t            profilesBase;
++    uint16_t            numOfProfiles;
++    t_Handle            h_FmPort;
++} t_FmPcdPlcrMapParam;
++
++typedef struct {
++    uint16_t                            absoluteProfileId;
++    t_Handle                            h_FmPcd;
++    bool                                valid;
++    t_FmPcdLock                         *p_Lock;
++    t_FmPcdAllocMng                     profilesMng;
++    bool                                requiredActionFlag;
++    uint32_t                            requiredAction;
++    e_FmPcdEngine                       nextEngineOnGreen;          /**< Green next engine type */
++    u_FmPcdPlcrNextEngineParams         paramsOnGreen;              /**< Green next engine params */
++
++    e_FmPcdEngine                       nextEngineOnYellow;         /**< Yellow next engine type */
++    u_FmPcdPlcrNextEngineParams         paramsOnYellow;             /**< Yellow next engine params */
++
++    e_FmPcdEngine                       nextEngineOnRed;            /**< Red next engine type */
++    u_FmPcdPlcrNextEngineParams         paramsOnRed;                /**< Red next engine params */
++} t_FmPcdPlcrProfile;
++
++typedef struct {
++    t_FmPcdPlcrRegs                 *p_FmPcdPlcrRegs;
++    uint16_t                        partPlcrProfilesBase;
++    uint16_t                        partNumOfPlcrProfiles;
++    t_FmPcdPlcrProfile              profiles[FM_PCD_PLCR_NUM_ENTRIES];
++    uint16_t                        numOfSharedProfiles;
++    uint16_t                        sharedProfilesIds[FM_PCD_PLCR_NUM_ENTRIES];
++    t_FmPcdPlcrMapParam             portsMapping[FM_MAX_NUM_OF_PORTS];
++    t_Handle                        h_HwSpinlock;
++    t_Handle                        h_SwSpinlock;
++} t_FmPcdPlcr;
++
++typedef struct {
++    uint32_t                        *p_SwPrsCode;
++    uint32_t                        *p_CurrSwPrs;
++    uint8_t                         currLabel;
++    struct fman_prs_regs            *p_FmPcdPrsRegs;
++    t_FmPcdPrsLabelParams           labelsTable[FM_PCD_PRS_NUM_OF_LABELS];
++    uint32_t                        fmPcdPrsPortIdStatistics;
++} t_FmPcdPrs;
++
++typedef struct {
++    struct {
++        e_NetHeaderType             hdr;
++        protocolOpt_t               opt; /* only one option !! */
++    } hdrs[FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS];
++} t_FmPcdIntDistinctionUnit;
++
++typedef struct {
++    e_NetHeaderType             hdr;
++    protocolOpt_t               opt; /* only one option !! */
++    e_NetHeaderType             aliasHdr;
++} t_FmPcdNetEnvAliases;
++
++typedef struct {
++    uint8_t                     netEnvId;
++    t_Handle                    h_FmPcd;
++    t_Handle                    h_Spinlock;
++    bool                        used;
++    uint8_t                     owners;
++    uint8_t                     clsPlanGrpId;
++    t_FmPcdIntDistinctionUnit   units[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS];
++    uint32_t                    unitsVectors[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS];
++    uint32_t                    lcvs[FM_PCD_PRS_NUM_OF_HDRS];
++    uint32_t                    macsecVector;
++    t_FmPcdNetEnvAliases        aliasHdrs[FM_PCD_MAX_NUM_OF_ALIAS_HDRS];
++} t_FmPcdNetEnv;
++
++typedef struct {
++    struct fman_prs_cfg          dfltCfg;
++    bool                        plcrAutoRefresh;
++    uint16_t                    prsMaxParseCycleLimit;
++} t_FmPcdDriverParam;
++
++typedef struct {
++    t_Handle                    h_Fm;
++    t_Handle                    h_FmMuram;
++    t_FmRevisionInfo            fmRevInfo;
++
++    uint64_t                    physicalMuramBase;
++
++    t_Handle                    h_Spinlock;
++    t_List                      freeLocksLst;
++    t_List                      acquiredLocksLst;
++
++    t_Handle                    h_IpcSession; /* relevant for guest only */
++    bool                        enabled;
++    uint8_t                     guestId;            /**< Guest Partition Id */
++    uint8_t                     numOfEnabledGuestPartitionsPcds;
++    char                        fmPcdModuleName[MODULE_NAME_SIZE];
++    char                        fmPcdIpcHandlerModuleName[MODULE_NAME_SIZE]; /* relevant for guest only - this is the master's name */
++    t_FmPcdNetEnv               netEnvs[FM_MAX_NUM_OF_PORTS];
++    t_FmPcdKg                   *p_FmPcdKg;
++    t_FmPcdPlcr                 *p_FmPcdPlcr;
++    t_FmPcdPrs                  *p_FmPcdPrs;
++
++    void                        *p_CcShadow;     /**< CC MURAM shadow */
++    uint32_t                    ccShadowSize;
++    uint32_t                    ccShadowAlign;
++    volatile bool               shadowLock;
++    t_Handle                    h_ShadowSpinlock;
++
++    t_Handle                    h_Hc;
++
++    uint32_t                    exceptions;
++    t_FmPcdExceptionCallback    *f_Exception;
++    t_FmPcdIdExceptionCallback  *f_FmPcdIndexedException;
++    t_Handle                    h_App;
++    uintptr_t                   ipv6FrameIdAddr;
++    uintptr_t                   capwapFrameIdAddr;
++    bool                        advancedOffloadSupport;
++
++    t_FmPcdDriverParam          *p_FmPcdDriverParam;
++} t_FmPcd;
++
++#if (DPAA_VERSION >= 11)
++typedef uint8_t t_FmPcdFrmReplicUpdateType;
++#define FRM_REPLIC_UPDATE_COUNTER             0x01
++#define FRM_REPLIC_UPDATE_INFO                0x02
++#endif /* (DPAA_VERSION >= 11) */
++/***********************************************************************/
++/*  PCD internal routines                                              */
++/***********************************************************************/
++
++t_Error     PcdGetVectorForOpt(t_FmPcd *p_FmPcd, uint8_t netEnvId, protocolOpt_t opt, uint32_t *p_Vector);
++t_Error     PcdGetUnitsVector(t_FmPcd *p_FmPcd, t_NetEnvParams *p_Params);
++bool        PcdNetEnvIsUnitWithoutOpts(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint32_t unitVector);
++t_Error     PcdGetClsPlanGrpParams(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_GrpParams);
++void        FmPcdSetClsPlanGrpId(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint8_t clsPlanGrpId);
++e_NetHeaderType FmPcdGetAliasHdr(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr);
++uint8_t     FmPcdNetEnvGetUnitIdForSingleHdr(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr);
++uint8_t     FmPcdNetEnvGetUnitId(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr, bool interchangeable, protocolOpt_t opt);
++
++t_Error     FmPcdManipBuildIpReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv, t_Handle h_CcTree, t_Handle h_Manip, bool isIpv4, uint8_t groupId);
++t_Error     FmPcdManipDeleteIpReassmSchemes(t_Handle h_Manip);
++t_Error     FmPcdManipBuildCapwapReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv, t_Handle h_CcTree, t_Handle h_Manip, uint8_t groupId);
++t_Error     FmPcdManipDeleteCapwapReassmSchemes(t_Handle h_Manip);
++bool        FmPcdManipIpReassmIsIpv6Hdr(t_Handle h_Manip);
++
++t_Handle    KgConfig( t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams);
++t_Error     KgInit(t_FmPcd *p_FmPcd);
++t_Error     KgFree(t_FmPcd *p_FmPcd);
++void        KgSetClsPlan(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanSet *p_Set);
++bool        KgIsSchemeAlwaysDirect(t_Handle h_FmPcd, uint8_t schemeId);
++void        KgEnable(t_FmPcd *p_FmPcd);
++void        KgDisable(t_FmPcd *p_FmPcd);
++t_Error     KgAllocClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t *p_First);
++void        KgFreeClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t base);
++
++/* only for MULTI partittion */
++t_Error     FmPcdKgAllocSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds);
++t_Error     FmPcdKgFreeSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds);
++/* only for SINGLE partittion */
++t_Error     KgBindPortToSchemes(t_Handle h_FmPcd , uint8_t hardwarePortId, uint32_t spReg);
++
++t_FmPcdLock *FmPcdAcquireLock(t_Handle h_FmPcd);
++void        FmPcdReleaseLock(t_Handle h_FmPcd, t_FmPcdLock *p_Lock);
++
++t_Handle    PlcrConfig(t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams);
++t_Error     PlcrInit(t_FmPcd *p_FmPcd);
++t_Error     PlcrFree(t_FmPcd *p_FmPcd);
++void        PlcrEnable(t_FmPcd *p_FmPcd);
++void        PlcrDisable(t_FmPcd *p_FmPcd);
++uint16_t    PlcrAllocProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId);
++void        PlcrFreeProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId);
++t_Error     PlcrSetPortProfiles(t_FmPcd    *p_FmPcd,
++                                uint8_t    hardwarePortId,
++                                uint16_t   numOfProfiles,
++                                uint16_t   base);
++t_Error     PlcrClearPortProfiles(t_FmPcd *p_FmPcd, uint8_t hardwarePortId);
++
++t_Handle    PrsConfig(t_FmPcd *p_FmPcd,t_FmPcdParams *p_FmPcdParams);
++t_Error     PrsInit(t_FmPcd *p_FmPcd);
++void        PrsEnable(t_FmPcd *p_FmPcd);
++void        PrsDisable(t_FmPcd *p_FmPcd);
++void        PrsFree(t_FmPcd *p_FmPcd );
++t_Error     PrsIncludePortInStatistics(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, bool include);
++
++t_Error     FmPcdCcGetGrpParams(t_Handle treeId, uint8_t grpId, uint32_t *p_GrpBits, uint8_t *p_GrpBase);
++uint8_t     FmPcdCcGetOffset(t_Handle h_CcNode);
++uint8_t     FmPcdCcGetParseCode(t_Handle h_CcNode);
++uint16_t    FmPcdCcGetNumOfKeys(t_Handle h_CcNode);
++t_Error     ValidateNextEngineParams(t_Handle h_FmPcd, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams, e_FmPcdCcStatsMode supportedStatsMode);
++
++void        FmPcdManipUpdateOwner(t_Handle h_Manip, bool add);
++t_Error     FmPcdManipCheckParamsForCcNextEngine(t_FmPcdCcNextEngineParams *p_InfoForManip, uint32_t *requiredAction);
++void        FmPcdManipUpdateAdResultForCc(t_Handle                     h_Manip,
++                                          t_FmPcdCcNextEngineParams    *p_CcNextEngineParams,
++                                          t_Handle                     p_Ad,
++                                          t_Handle                     *p_AdNewPtr);
++void        FmPcdManipUpdateAdContLookupForCc(t_Handle h_Manip, t_Handle p_Ad, t_Handle *p_AdNew, uint32_t adTableOffset);
++void        FmPcdManipUpdateOwner(t_Handle h_Manip, bool add);
++t_Error     FmPcdManipCheckParamsWithCcNodeParams(t_Handle h_Manip, t_Handle h_FmPcdCcNode);
++#ifdef FM_CAPWAP_SUPPORT
++t_Handle    FmPcdManipApplSpecificBuild(void);
++bool        FmPcdManipIsCapwapApplSpecific(t_Handle h_Manip);
++#endif /* FM_CAPWAP_SUPPORT */
++#if (DPAA_VERSION >= 11)
++void *      FrmReplicGroupGetSourceTableDescriptor(t_Handle h_ReplicGroup);
++void        FrmReplicGroupUpdateOwner(t_Handle h_ReplicGroup, bool add);
++void        FrmReplicGroupUpdateAd(t_Handle h_ReplicGroup, void *p_Ad, t_Handle *h_AdNew);
++
++void        FmPcdCcGetAdTablesThatPointOnReplicGroup(t_Handle   h_Node,
++                                                     t_Handle   h_ReplicGroup,
++                                                     t_List     *p_AdTables,
++                                                     uint32_t   *p_NumOfAdTables);
++#endif /* (DPAA_VERSION >= 11) */
++
++void EnqueueNodeInfoToRelevantLst(t_List *p_List, t_CcNodeInformation *p_CcInfo, t_Handle h_Spinlock);
++void DequeueNodeInfoFromRelevantLst(t_List *p_List, t_Handle h_Info, t_Handle h_Spinlock);
++t_CcNodeInformation* FindNodeInfoInReleventLst(t_List *p_List, t_Handle h_Info, t_Handle h_Spinlock);
++t_List *FmPcdManipGetSpinlock(t_Handle h_Manip);
++t_List *FmPcdManipGetNodeLstPointedOnThisManip(t_Handle h_Manip);
++
++typedef struct
++{
++    t_Handle    h_StatsAd;
++    t_Handle    h_StatsCounters;
++#if (DPAA_VERSION >= 11)
++    t_Handle    h_StatsFLRs;
++#endif /* (DPAA_VERSION >= 11) */
++} t_FmPcdCcStatsParams;
++
++void NextStepAd(t_Handle                     h_Ad,
++                t_FmPcdCcStatsParams         *p_FmPcdCcStatsParams,
++                t_FmPcdCcNextEngineParams    *p_FmPcdCcNextEngineParams,
++                t_FmPcd                      *p_FmPcd);
++void ReleaseLst(t_List *p_List);
++
++static __inline__ t_Handle FmPcdGetMuramHandle(t_Handle h_FmPcd)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    ASSERT_COND(p_FmPcd);
++    return p_FmPcd->h_FmMuram;
++}
++
++static __inline__ uint64_t FmPcdGetMuramPhysBase(t_Handle h_FmPcd)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    ASSERT_COND(p_FmPcd);
++    return p_FmPcd->physicalMuramBase;
++}
++
++static __inline__ uint32_t FmPcdLockSpinlock(t_FmPcdLock *p_Lock)
++{
++    ASSERT_COND(p_Lock);
++    return XX_LockIntrSpinlock(p_Lock->h_Spinlock);
++}
++
++static __inline__ void FmPcdUnlockSpinlock(t_FmPcdLock *p_Lock, uint32_t flags)
++{
++    ASSERT_COND(p_Lock);
++    XX_UnlockIntrSpinlock(p_Lock->h_Spinlock, flags);
++}
++
++static __inline__ bool FmPcdLockTryLock(t_FmPcdLock *p_Lock)
++{
++    uint32_t intFlags;
++
++    ASSERT_COND(p_Lock);
++    intFlags = XX_LockIntrSpinlock(p_Lock->h_Spinlock);
++    if (p_Lock->flag)
++    {
++        XX_UnlockIntrSpinlock(p_Lock->h_Spinlock, intFlags);
++        return FALSE;
++    }
++    p_Lock->flag = TRUE;
++    XX_UnlockIntrSpinlock(p_Lock->h_Spinlock, intFlags);
++    return TRUE;
++}
++
++static __inline__ void FmPcdLockUnlock(t_FmPcdLock *p_Lock)
++{
++    ASSERT_COND(p_Lock);
++    p_Lock->flag = FALSE;
++}
++
++
++#endif /* __FM_PCD_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd_ipc.h
+@@ -0,0 +1,280 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          fm_pcd_ipc.h
++
++ @Description   FM PCD Inter-Partition prototypes, structures and definitions.
++*//***************************************************************************/
++#ifndef __FM_PCD_IPC_H
++#define __FM_PCD_IPC_H
++
++#include "std_ext.h"
++
++
++/**************************************************************************//**
++ @Group         FM_grp Frame Manager API
++
++ @Description   FM API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(push,1)
++#endif /* defined(__MWERKS__) && ... */
++
++/**************************************************************************//**
++ @Description   Structure for getting a sw parser address according to a label
++                Fields commented 'IN' are passed by the port module to be used
++                by the FM module.
++                Fields commented 'OUT' will be filled by FM before returning to port.
++*//***************************************************************************/
++typedef _Packed struct t_FmPcdIpcSwPrsLable
++{
++    uint32_t    enumHdr;                        /**< IN. The existence of this header will invoke
++                                                     the sw parser code. */
++    uint8_t     indexPerHdr;                    /**< IN. Normally 0, if more than one sw parser
++                                                     attachments for the same header, use this
++
++                                                   index to distinguish between them. */
++} _PackedType t_FmPcdIpcSwPrsLable;
++
++/**************************************************************************//**
++ @Description   Structure for port-PCD communication.
++                Fields commented 'IN' are passed by the port module to be used
++                by the FM module.
++                Fields commented 'OUT' will be filled by FM before returning to port.
++                Some fields are optional (depending on configuration) and
++                will be analized by the port and FM modules accordingly.
++*//***************************************************************************/
++
++typedef  struct t_FmPcdIpcKgSchemesParams
++{
++    uint8_t     guestId;
++    uint8_t     numOfSchemes;
++    uint8_t     schemesIds[FM_PCD_KG_NUM_OF_SCHEMES];
++} _PackedType t_FmPcdIpcKgSchemesParams;
++
++typedef  struct t_FmPcdIpcKgClsPlanParams
++{
++    uint8_t     guestId;
++    uint16_t    numOfClsPlanEntries;
++    uint8_t     clsPlanBase;
++} _PackedType t_FmPcdIpcKgClsPlanParams;
++
++typedef _Packed struct t_FmPcdIpcPrsIncludePort
++{
++    uint8_t     hardwarePortId;
++    bool        include;
++} _PackedType t_FmPcdIpcPrsIncludePort;
++
++
++#define FM_PCD_MAX_REPLY_SIZE           16
++#define FM_PCD_MAX_MSG_SIZE             36
++#define FM_PCD_MAX_REPLY_BODY_SIZE      36
++
++typedef _Packed struct {
++    uint32_t    msgId;
++    uint8_t     msgBody[FM_PCD_MAX_MSG_SIZE];
++} _PackedType t_FmPcdIpcMsg;
++
++typedef _Packed struct t_FmPcdIpcReply {
++    uint32_t    error;
++    uint8_t     replyBody[FM_PCD_MAX_REPLY_BODY_SIZE];
++} _PackedType t_FmPcdIpcReply;
++
++typedef _Packed struct t_FmIpcResourceAllocParams {
++    uint8_t     guestId;
++    uint16_t    base;
++    uint16_t    num;
++}_PackedType t_FmIpcResourceAllocParams;
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(pop)
++#endif /* defined(__MWERKS__) && ... */
++
++
++
++/**************************************************************************//**
++ @Function      FM_PCD_ALLOC_KG_SCHEMES
++
++ @Description   Used by FM PCD front-end in order to allocate KG resources
++
++ @Param[in/out] t_FmPcdIpcKgAllocParams Pointer
++*//***************************************************************************/
++#define FM_PCD_ALLOC_KG_SCHEMES                 3
++
++/**************************************************************************//**
++ @Function      FM_PCD_FREE_KG_SCHEMES
++
++ @Description   Used by FM PCD front-end in order to Free KG resources
++
++ @Param[in/out] t_FmPcdIpcKgSchemesParams Pointer
++*//***************************************************************************/
++#define FM_PCD_FREE_KG_SCHEMES                  4
++
++/**************************************************************************//**
++ @Function      FM_PCD_ALLOC_PROFILES
++
++ @Description   Used by FM PCD front-end in order to allocate Policer profiles
++
++ @Param[in/out] t_FmIpcResourceAllocParams Pointer
++*//***************************************************************************/
++#define FM_PCD_ALLOC_PROFILES                   5
++
++/**************************************************************************//**
++ @Function      FM_PCD_FREE_PROFILES
++
++ @Description   Used by FM PCD front-end in order to Free Policer profiles
++
++ @Param[in/out] t_FmIpcResourceAllocParams Pointer
++*//***************************************************************************/
++#define FM_PCD_FREE_PROFILES                    6
++
++/**************************************************************************//**
++ @Function      FM_PCD_SET_PORT_PROFILES
++
++ @Description   Used by FM PCD front-end in order to allocate Policer profiles
++                for specific port
++
++ @Param[in/out] t_FmIpcResourceAllocParams Pointer
++*//***************************************************************************/
++#define FM_PCD_SET_PORT_PROFILES                7
++
++/**************************************************************************//**
++ @Function      FM_PCD_CLEAR_PORT_PROFILES
++
++ @Description   Used by FM PCD front-end in order to allocate Policer profiles
++                for specific port
++
++ @Param[in/out] t_FmIpcResourceAllocParams Pointer
++*//***************************************************************************/
++#define FM_PCD_CLEAR_PORT_PROFILES              8
++
++/**************************************************************************//**
++ @Function      FM_PCD_GET_PHYS_MURAM_BASE
++
++ @Description   Used by FM PCD front-end in order to get MURAM base address
++
++ @Param[in/out] t_FmPcdIcPhysAddr Pointer
++*//***************************************************************************/
++#define FM_PCD_GET_PHYS_MURAM_BASE              9
++
++/**************************************************************************//**
++ @Function      FM_PCD_GET_SW_PRS_OFFSET
++
++ @Description   Used by FM front-end to get the SW parser offset of the start of
++                code relevant to a given label.
++
++ @Param[in/out] t_FmPcdIpcSwPrsLable Pointer
++*//***************************************************************************/
++#define FM_PCD_GET_SW_PRS_OFFSET                10
++
++/**************************************************************************//**
++ @Function      FM_PCD_MASTER_IS_ENABLED
++
++ @Description   Used by FM front-end in order to verify
++                PCD enablement.
++
++ @Param[in]     bool Pointer
++*//***************************************************************************/
++#define FM_PCD_MASTER_IS_ENABLED                15
++
++/**************************************************************************//**
++ @Function      FM_PCD_GUEST_DISABLE
++
++ @Description   Used by FM front-end to inform back-end when
++                front-end PCD is disabled
++
++ @Param[in]     None
++*//***************************************************************************/
++#define FM_PCD_GUEST_DISABLE                    16
++
++/**************************************************************************//**
++ @Function      FM_PCD_FREE_KG_CLSPLAN
++
++ @Description   Used by FM PCD front-end in order to Free KG classification plan entries
++
++ @Param[in/out] t_FmPcdIpcKgClsPlanParams Pointer
++*//***************************************************************************/
++#define FM_PCD_FREE_KG_CLSPLAN                  22
++
++/**************************************************************************//**
++ @Function      FM_PCD_ALLOC_KG_CLSPLAN
++
++ @Description   Used by FM PCD front-end in order to allocate KG classification plan entries
++
++ @Param[in/out] t_FmPcdIpcKgClsPlanParams Pointer
++*//***************************************************************************/
++#define FM_PCD_ALLOC_KG_CLSPLAN                 23
++
++/**************************************************************************//**
++ @Function      FM_PCD_MASTER_IS_ALIVE
++
++ @Description   Used by FM front-end to check that back-end exists
++
++ @Param[in]     None
++*//***************************************************************************/
++#define FM_PCD_MASTER_IS_ALIVE                  24
++
++/**************************************************************************//**
++ @Function      FM_PCD_GET_COUNTER
++
++ @Description   Used by FM front-end to read PCD counters
++
++ @Param[in/out] t_FmPcdIpcGetCounter Pointer
++*//***************************************************************************/
++#define FM_PCD_GET_COUNTER                      25
++
++/**************************************************************************//**
++ @Function      FM_PCD_PRS_INC_PORT_STATS
++
++ @Description   Used by FM front-end to set/clear statistics for port
++
++ @Param[in/out] t_FmPcdIpcPrsIncludePort Pointer
++*//***************************************************************************/
++#define FM_PCD_PRS_INC_PORT_STATS               26
++
++#if (DPAA_VERSION >= 11)
++/* TODO - doc */
++#define FM_PCD_ALLOC_SP                         27
++#endif /* (DPAA_VERSION >= 11) */
++
++
++/** @} */ /* end of FM_PCD_IPC_grp group */
++/** @} */ /* end of FM_grp group */
++
++
++#endif /* __FM_PCD_IPC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.c
+@@ -0,0 +1,1847 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_plcr.c
++
++ @Description   FM PCD POLICER...
++*//***************************************************************************/
++#include <linux/math64.h>
++#include "std_ext.h"
++#include "error_ext.h"
++#include "string_ext.h"
++#include "debug_ext.h"
++#include "net_ext.h"
++#include "fm_ext.h"
++
++#include "fm_common.h"
++#include "fm_pcd.h"
++#include "fm_hc.h"
++#include "fm_pcd_ipc.h"
++#include "fm_plcr.h"
++
++
++/****************************************/
++/*       static functions               */
++/****************************************/
++
++static uint32_t PlcrProfileLock(t_Handle h_Profile)
++{
++    ASSERT_COND(h_Profile);
++    return FmPcdLockSpinlock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock);
++}
++
++static void PlcrProfileUnlock(t_Handle h_Profile, uint32_t intFlags)
++{
++    ASSERT_COND(h_Profile);
++    FmPcdUnlockSpinlock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock, intFlags);
++}
++
++static bool PlcrProfileFlagTryLock(t_Handle h_Profile)
++{
++    ASSERT_COND(h_Profile);
++    return FmPcdLockTryLock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock);
++}
++
++static void PlcrProfileFlagUnlock(t_Handle h_Profile)
++{
++    ASSERT_COND(h_Profile);
++    FmPcdLockUnlock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock);
++}
++
++static uint32_t PlcrHwLock(t_Handle h_FmPcdPlcr)
++{
++    ASSERT_COND(h_FmPcdPlcr);
++    return XX_LockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_HwSpinlock);
++}
++
++static void PlcrHwUnlock(t_Handle h_FmPcdPlcr, uint32_t intFlags)
++{
++    ASSERT_COND(h_FmPcdPlcr);
++    XX_UnlockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_HwSpinlock, intFlags);
++}
++
++static uint32_t PlcrSwLock(t_Handle h_FmPcdPlcr)
++{
++    ASSERT_COND(h_FmPcdPlcr);
++    return XX_LockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_SwSpinlock);
++}
++
++static void PlcrSwUnlock(t_Handle h_FmPcdPlcr, uint32_t intFlags)
++{
++    ASSERT_COND(h_FmPcdPlcr);
++    XX_UnlockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_SwSpinlock, intFlags);
++}
++
++static bool IsProfileShared(t_Handle h_FmPcd, uint16_t absoluteProfileId)
++{
++    t_FmPcd         *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint16_t        i;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, FALSE);
++
++    for (i=0;i<p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles;i++)
++        if (p_FmPcd->p_FmPcdPlcr->sharedProfilesIds[i] == absoluteProfileId)
++            return TRUE;
++    return FALSE;
++}
++
++static t_Error SetProfileNia(t_FmPcd *p_FmPcd, e_FmPcdEngine nextEngine, u_FmPcdPlcrNextEngineParams *p_NextEngineParams, uint32_t *nextAction)
++{
++    uint32_t    nia;
++    uint16_t    absoluteProfileId;
++    uint8_t     relativeSchemeId, physicalSchemeId;
++
++    nia = FM_PCD_PLCR_NIA_VALID;
++
++    switch (nextEngine)
++    {
++        case e_FM_PCD_DONE :
++            switch (p_NextEngineParams->action)
++            {
++                case e_FM_PCD_DROP_FRAME :
++                    nia |= GET_NIA_BMI_AC_DISCARD_FRAME(p_FmPcd);
++                    break;
++                case e_FM_PCD_ENQ_FRAME:
++                    nia |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd);
++                    break;
++                default:
++                    RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++            }
++            break;
++        case e_FM_PCD_KG:
++            physicalSchemeId = FmPcdKgGetSchemeId(p_NextEngineParams->h_DirectScheme);
++            relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId);
++            if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES)
++                RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
++            if (!FmPcdKgIsSchemeValidSw(p_NextEngineParams->h_DirectScheme))
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid direct scheme."));
++            if (!KgIsSchemeAlwaysDirect(p_FmPcd, relativeSchemeId))
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Policer Profile may point only to a scheme that is always direct."));
++            nia |= NIA_ENG_KG | NIA_KG_DIRECT | physicalSchemeId;
++            break;
++        case e_FM_PCD_PLCR:
++            absoluteProfileId = ((t_FmPcdPlcrProfile *)p_NextEngineParams->h_Profile)->absoluteProfileId;
++            if (!IsProfileShared(p_FmPcd, absoluteProfileId))
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next profile must be a shared profile"));
++            if (!FmPcdPlcrIsProfileValid(p_FmPcd, absoluteProfileId))
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid profile "));
++            nia |= NIA_ENG_PLCR | NIA_PLCR_ABSOLUTE | absoluteProfileId;
++            break;
++        default:
++            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++    }
++
++    *nextAction =  nia;
++
++    return E_OK;
++}
++
++static uint32_t CalcFPP(uint32_t fpp)
++{
++    if (fpp > 15)
++        return 15 - (0x1f - fpp);
++    else
++        return 16 + fpp;
++}
++
++static void GetInfoRateReg(e_FmPcdPlcrRateMode  rateMode,
++                           uint32_t             rate,
++                           uint64_t             tsuInTenthNano,
++                           uint32_t             fppShift,
++                           uint64_t             *p_Integer,
++                           uint64_t             *p_Fraction)
++{
++    uint64_t tmp, div;
++
++    if (rateMode == e_FM_PCD_PLCR_BYTE_MODE)
++    {
++        /* now we calculate the initial integer for the bigger rate */
++        /* from Kbps to Bytes/TSU */
++        tmp = (uint64_t)rate;
++        tmp *= 1000; /* kb --> b */
++        tmp *= tsuInTenthNano; /* bps --> bpTsu(in 10nano) */
++
++        div = 1000000000;   /* nano */
++        div *= 10;          /* 10 nano */
++        div *= 8;           /* bit to byte */
++    }
++    else
++    {
++        /* now we calculate the initial integer for the bigger rate */
++        /* from Kbps to Bytes/TSU */
++        tmp = (uint64_t)rate;
++        tmp *= tsuInTenthNano; /* bps --> bpTsu(in 10nano) */
++
++        div = 1000000000;   /* nano */
++        div *= 10;          /* 10 nano */
++    }
++    *p_Integer = div64_u64(tmp<<fppShift, div);
++
++    /* for calculating the fraction, we will recalculate cir and deduct the integer.
++     * For precision, we will multiply by 2^16. we do not divid back, since we write
++     * this value as fraction - see spec.
++     */
++    *p_Fraction = div64_u64(((tmp<<fppShift)<<16) - ((*p_Integer<<16)*div), div);
++}
++
++/* .......... */
++
++static void CalcRates(uint32_t                              bitFor1Micro,
++                      t_FmPcdPlcrNonPassthroughAlgParams    *p_NonPassthroughAlgParam,
++                      uint32_t                              *cir,
++                      uint32_t                              *cbs,
++                      uint32_t                              *pir_eir,
++                      uint32_t                              *pbs_ebs,
++                      uint32_t                              *fpp)
++{
++    uint64_t    integer, fraction;
++    uint32_t    temp, tsuInTenthNanos;
++    uint8_t     fppShift=0;
++
++    /* we want the tsu to count 10 nano for better precision normally tsu is 3.9 nano, now we will get 39 */
++    tsuInTenthNanos = (uint32_t)(1000*10/(1 << bitFor1Micro));
++
++    /* we choose the faster rate to calibrate fpp */
++    /* The meaning of this step:
++     * when fppShift is 0 it means all TS bits are treated as integer and TSU is the TS LSB count.
++     * In this configuration we calculate the integer and fraction that represent the higher infoRate
++     * When this is done, we can tell where we have "spare" unused bits and optimize the division of TS
++     * into "integer" and "fraction" where the logic is - as many bits as possible for integer at
++     * high rate, as many bits as possible for fraction at low rate.
++     */
++    if (p_NonPassthroughAlgParam->committedInfoRate > p_NonPassthroughAlgParam->peakOrExcessInfoRate)
++        GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->committedInfoRate, tsuInTenthNanos, 0, &integer, &fraction);
++    else
++        GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->peakOrExcessInfoRate, tsuInTenthNanos, 0, &integer, &fraction);
++
++    /* we shift integer, as in cir/pir it is represented by the MSB 16 bits, and
++     * the LSB bits are for the fraction */
++    temp = (uint32_t)((integer<<16) & 0x00000000FFFFFFFF);
++    /* temp is effected by the rate. For low rates it may be as low as 0, and then we'll
++     * take max FP = 31.
++     * For high rates it will never exceed the 32 bit reg (after the 16 shift), as it is
++     * limited by the 10G physical port.
++     */
++    if (temp != 0)
++    {
++        /* In this case, the largest rate integer is non 0, if it does not occupy all (high) 16
++         * bits of the PIR_EIR we can use this fact and enlarge it to occupy all 16 bits.
++         * The logic is to have as many bits for integer in the higher rates, but if we have "0"s
++         * in the integer part of the cir/pir register, than these bits are wasted. So we want
++         * to use these bits for the fraction. in this way we will have for fraction - the number
++         * of "0" bits and the rest - for integer.
++         * In other words: For each bit we shift it in PIR_EIR, we move the FP in the TS
++         * one bit to the left - preserving the relationship and achieving more bits
++         * for integer in the TS.
++         */
++
++        /* count zeroes left of the higher used bit (in order to shift the value such that
++         * unused bits may be used for fraction).
++         */
++        while ((temp & 0x80000000) == 0)
++        {
++            temp = temp << 1;
++            fppShift++;
++        }
++        if (fppShift > 15)
++        {
++            REPORT_ERROR(MAJOR, E_INVALID_SELECTION, ("timeStampPeriod to Information rate ratio is too small"));
++            return;
++        }
++    }
++    else
++    {
++        temp = (uint32_t)fraction; /* fraction will alyas be smaller than 2^16 */
++        if (!temp)
++            /* integer and fraction are 0, we set FP to its max val */
++            fppShift = 31;
++        else
++        {
++            /* integer was 0 but fraction is not. FP is 16 for the fraction,
++             * + all left zeroes of the fraction. */
++            fppShift=16;
++            /* count zeroes left of the higher used bit (in order to shift the value such that
++             * unused bits may be used for fraction).
++             */
++            while ((temp & 0x8000) == 0)
++            {
++                temp = temp << 1;
++                fppShift++;
++            }
++        }
++    }
++
++    /*
++     * This means that the FM TS register will now be used so that 'fppShift' bits are for
++     * fraction and the rest for integer */
++    /* now we re-calculate cir and pir_eir with the calculated FP */
++    GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->committedInfoRate, tsuInTenthNanos, fppShift, &integer, &fraction);
++    *cir = (uint32_t)(integer << 16 | (fraction & 0xFFFF));
++    GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->peakOrExcessInfoRate, tsuInTenthNanos, fppShift, &integer, &fraction);
++    *pir_eir = (uint32_t)(integer << 16 | (fraction & 0xFFFF));
++
++    *cbs     =  p_NonPassthroughAlgParam->committedBurstSize;
++    *pbs_ebs =  p_NonPassthroughAlgParam->peakOrExcessBurstSize;
++
++    /* convert FP as it should be written to reg.
++     * 0-15 --> 16-31
++     * 16-31 --> 0-15
++     */
++    *fpp = CalcFPP(fppShift);
++}
++
++static void WritePar(t_FmPcd *p_FmPcd, uint32_t par)
++{
++    t_FmPcdPlcrRegs *p_FmPcdPlcrRegs    = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
++
++    ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
++    WRITE_UINT32(p_FmPcdPlcrRegs->fmpl_par, par);
++
++    while (GET_UINT32(p_FmPcdPlcrRegs->fmpl_par) & FM_PCD_PLCR_PAR_GO) ;
++}
++
++static t_Error BuildProfileRegs(t_FmPcd                     *p_FmPcd,
++                                t_FmPcdPlcrProfileParams    *p_ProfileParams,
++                                t_FmPcdPlcrProfileRegs      *p_PlcrRegs)
++{
++    t_Error                 err = E_OK;
++    uint32_t                pemode, gnia, ynia, rnia, bitFor1Micro;
++
++    ASSERT_COND(p_FmPcd);
++
++    bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm);
++    if (bitFor1Micro == 0)
++    RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale"));
++
++/* Set G, Y, R Nia */
++    err = SetProfileNia(p_FmPcd, p_ProfileParams->nextEngineOnGreen,  &(p_ProfileParams->paramsOnGreen), &gnia);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    err = SetProfileNia(p_FmPcd, p_ProfileParams->nextEngineOnYellow, &(p_ProfileParams->paramsOnYellow), &ynia);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    err = SetProfileNia(p_FmPcd, p_ProfileParams->nextEngineOnRed,    &(p_ProfileParams->paramsOnRed), &rnia);
++   if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++/* Mode fmpl_pemode */
++    pemode = FM_PCD_PLCR_PEMODE_PI;
++
++    switch (p_ProfileParams->algSelection)
++    {
++        case    e_FM_PCD_PLCR_PASS_THROUGH:
++            p_PlcrRegs->fmpl_pecir         = 0;
++            p_PlcrRegs->fmpl_pecbs         = 0;
++            p_PlcrRegs->fmpl_pepepir_eir   = 0;
++            p_PlcrRegs->fmpl_pepbs_ebs     = 0;
++            p_PlcrRegs->fmpl_pelts         = 0;
++            p_PlcrRegs->fmpl_pects         = 0;
++            p_PlcrRegs->fmpl_pepts_ets     = 0;
++            pemode &= ~FM_PCD_PLCR_PEMODE_ALG_MASK;
++            switch (p_ProfileParams->colorMode)
++            {
++                case    e_FM_PCD_PLCR_COLOR_BLIND:
++                    pemode |= FM_PCD_PLCR_PEMODE_CBLND;
++                    switch (p_ProfileParams->color.dfltColor)
++                    {
++                        case e_FM_PCD_PLCR_GREEN:
++                            pemode &= ~FM_PCD_PLCR_PEMODE_DEFC_MASK;
++                            break;
++                        case e_FM_PCD_PLCR_YELLOW:
++                            pemode |= FM_PCD_PLCR_PEMODE_DEFC_Y;
++                            break;
++                        case e_FM_PCD_PLCR_RED:
++                            pemode |= FM_PCD_PLCR_PEMODE_DEFC_R;
++                            break;
++                        case e_FM_PCD_PLCR_OVERRIDE:
++                            pemode |= FM_PCD_PLCR_PEMODE_DEFC_OVERRIDE;
++                            break;
++                        default:
++                            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++                    }
++
++                    break;
++                case    e_FM_PCD_PLCR_COLOR_AWARE:
++                    pemode &= ~FM_PCD_PLCR_PEMODE_CBLND;
++                    break;
++                default:
++                    RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++            }
++            break;
++
++        case    e_FM_PCD_PLCR_RFC_2698:
++            /* Select algorithm MODE[ALG] = "01" */
++            pemode |= FM_PCD_PLCR_PEMODE_ALG_RFC2698;
++            if (p_ProfileParams->nonPassthroughAlgParams.committedInfoRate > p_ProfileParams->nonPassthroughAlgParams.peakOrExcessInfoRate)
++                RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("in RFC2698 Peak rate must be equal or larger than committedInfoRate."));
++            goto cont_rfc;
++        case    e_FM_PCD_PLCR_RFC_4115:
++            /* Select algorithm MODE[ALG] = "10" */
++            pemode |= FM_PCD_PLCR_PEMODE_ALG_RFC4115;
++cont_rfc:
++            /* Select Color-Blind / Color-Aware operation (MODE[CBLND]) */
++            switch (p_ProfileParams->colorMode)
++            {
++                case    e_FM_PCD_PLCR_COLOR_BLIND:
++                    pemode |= FM_PCD_PLCR_PEMODE_CBLND;
++                    break;
++                case    e_FM_PCD_PLCR_COLOR_AWARE:
++                    pemode &= ~FM_PCD_PLCR_PEMODE_CBLND;
++                    /*In color aware more select override color interpretation (MODE[OVCLR]) */
++                    switch (p_ProfileParams->color.override)
++                    {
++                        case e_FM_PCD_PLCR_GREEN:
++                            pemode &= ~FM_PCD_PLCR_PEMODE_OVCLR_MASK;
++                            break;
++                        case e_FM_PCD_PLCR_YELLOW:
++                            pemode |= FM_PCD_PLCR_PEMODE_OVCLR_Y;
++                            break;
++                        case e_FM_PCD_PLCR_RED:
++                            pemode |= FM_PCD_PLCR_PEMODE_OVCLR_R;
++                            break;
++                        case e_FM_PCD_PLCR_OVERRIDE:
++                            pemode |= FM_PCD_PLCR_PEMODE_OVCLR_G_NC;
++                            break;
++                        default:
++                            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++                    }
++                    break;
++                default:
++                    RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++            }
++            /* Select Measurement Unit Mode to BYTE or PACKET (MODE[PKT]) */
++            switch (p_ProfileParams->nonPassthroughAlgParams.rateMode)
++            {
++                case e_FM_PCD_PLCR_BYTE_MODE :
++                    pemode &= ~FM_PCD_PLCR_PEMODE_PKT;
++                        switch (p_ProfileParams->nonPassthroughAlgParams.byteModeParams.frameLengthSelection)
++                        {
++                            case e_FM_PCD_PLCR_L2_FRM_LEN:
++                                pemode |= FM_PCD_PLCR_PEMODE_FLS_L2;
++                                break;
++                            case e_FM_PCD_PLCR_L3_FRM_LEN:
++                                pemode |= FM_PCD_PLCR_PEMODE_FLS_L3;
++                                break;
++                            case e_FM_PCD_PLCR_L4_FRM_LEN:
++                                pemode |= FM_PCD_PLCR_PEMODE_FLS_L4;
++                                break;
++                            case e_FM_PCD_PLCR_FULL_FRM_LEN:
++                                pemode |= FM_PCD_PLCR_PEMODE_FLS_FULL;
++                                break;
++                            default:
++                                RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++                        }
++                        switch (p_ProfileParams->nonPassthroughAlgParams.byteModeParams.rollBackFrameSelection)
++                        {
++                            case e_FM_PCD_PLCR_ROLLBACK_L2_FRM_LEN:
++                                pemode &= ~FM_PCD_PLCR_PEMODE_RBFLS;
++                                break;
++                            case e_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN:
++                                pemode |= FM_PCD_PLCR_PEMODE_RBFLS;
++                                break;
++                            default:
++                                RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++                        }
++                    break;
++                case e_FM_PCD_PLCR_PACKET_MODE :
++                    pemode |= FM_PCD_PLCR_PEMODE_PKT;
++                    break;
++                default:
++                    RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++            }
++            /* Select timeStamp floating point position (MODE[FPP]) to fit the actual traffic rates. For PACKET
++               mode with low traffic rates move the fixed point to the left to increase fraction accuracy. For BYTE
++               mode with high traffic rates move the fixed point to the right to increase integer accuracy. */
++
++            /* Configure Traffic Parameters*/
++            {
++                uint32_t cir=0, cbs=0, pir_eir=0, pbs_ebs=0, fpp=0;
++
++                CalcRates(bitFor1Micro, &p_ProfileParams->nonPassthroughAlgParams, &cir, &cbs, &pir_eir, &pbs_ebs, &fpp);
++
++                /*  Set Committed Information Rate (CIR) */
++                p_PlcrRegs->fmpl_pecir = cir;
++                /*  Set Committed Burst Size (CBS). */
++                p_PlcrRegs->fmpl_pecbs =  cbs;
++                /*  Set Peak Information Rate (PIR_EIR used as PIR) */
++                p_PlcrRegs->fmpl_pepepir_eir = pir_eir;
++                /*   Set Peak Burst Size (PBS_EBS used as PBS) */
++                p_PlcrRegs->fmpl_pepbs_ebs = pbs_ebs;
++
++                /* Initialize the Metering Buckets to be full (write them with 0xFFFFFFFF. */
++                /* Peak Rate Token Bucket Size (PTS_ETS used as PTS) */
++                p_PlcrRegs->fmpl_pepts_ets = 0xFFFFFFFF;
++                /* Committed Rate Token Bucket Size (CTS) */
++                p_PlcrRegs->fmpl_pects = 0xFFFFFFFF;
++
++                /* Set the FPP based on calculation */
++                pemode |= (fpp << FM_PCD_PLCR_PEMODE_FPP_SHIFT);
++            }
++            break;  /* FM_PCD_PLCR_PEMODE_ALG_RFC2698 , FM_PCD_PLCR_PEMODE_ALG_RFC4115 */
++        default:
++            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++    }
++
++    p_PlcrRegs->fmpl_pemode = pemode;
++
++    p_PlcrRegs->fmpl_pegnia = gnia;
++    p_PlcrRegs->fmpl_peynia = ynia;
++    p_PlcrRegs->fmpl_pernia = rnia;
++
++    /* Zero Counters */
++    p_PlcrRegs->fmpl_pegpc     = 0;
++    p_PlcrRegs->fmpl_peypc     = 0;
++    p_PlcrRegs->fmpl_perpc     = 0;
++    p_PlcrRegs->fmpl_perypc    = 0;
++    p_PlcrRegs->fmpl_perrpc    = 0;
++
++    return E_OK;
++}
++
++static t_Error AllocSharedProfiles(t_FmPcd *p_FmPcd, uint16_t numOfProfiles, uint16_t *profilesIds)
++{
++    uint32_t        profilesFound;
++    uint16_t        i, k=0;
++    uint32_t        intFlags;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++
++    if (!numOfProfiles)
++        return E_OK;
++
++    if (numOfProfiles>FM_PCD_PLCR_NUM_ENTRIES)
++        RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles is too big."));
++
++    intFlags = PlcrSwLock(p_FmPcd->p_FmPcdPlcr);
++    /* Find numOfProfiles free profiles (may be spread) */
++    profilesFound = 0;
++    for (i=0;i<FM_PCD_PLCR_NUM_ENTRIES; i++)
++        if (!p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated)
++        {
++            profilesFound++;
++            profilesIds[k] = i;
++            k++;
++            if (profilesFound == numOfProfiles)
++                break;
++        }
++
++    if (profilesFound != numOfProfiles)
++    {
++        PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
++        RETURN_ERROR(MAJOR, E_INVALID_STATE,NO_MSG);
++    }
++
++    for (i = 0;i<k;i++)
++    {
++        p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated = TRUE;
++        p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.ownerId = 0;
++    }
++    PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
++
++    return E_OK;
++}
++
++static void FreeSharedProfiles(t_FmPcd *p_FmPcd, uint16_t numOfProfiles, uint16_t *profilesIds)
++{
++    uint16_t        i;
++
++    SANITY_CHECK_RETURN(p_FmPcd, E_INVALID_HANDLE);
++
++    ASSERT_COND(numOfProfiles);
++
++    for (i=0; i < numOfProfiles; i++)
++    {
++        ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated);
++        p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated = FALSE;
++        p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.ownerId = p_FmPcd->guestId;
++    }
++}
++
++static void UpdateRequiredActionFlag(t_Handle h_FmPcd, uint16_t absoluteProfileId, bool set)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    /* this routine is protected by calling routine */
++
++    ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
++
++    if (set)
++        p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredActionFlag = TRUE;
++    else
++    {
++        p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction = 0;
++        p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredActionFlag = FALSE;
++    }
++}
++
++/*********************************************/
++/*............Policer Exception..............*/
++/*********************************************/
++static void EventsCB(t_Handle h_FmPcd)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    uint32_t event, mask, force;
++
++    ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
++    event = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_evr);
++    mask = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier);
++
++    event &= mask;
++
++    /* clear the forced events */
++    force = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr);
++    if (force & event)
++        WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, force & ~event);
++
++
++    WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_evr, event);
++
++    if (event & FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE)
++        p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE);
++    if (event & FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE)
++        p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE);
++}
++
++/* ..... */
++
++static void ErrorExceptionsCB(t_Handle h_FmPcd)
++{
++    t_FmPcd             *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    uint32_t            event, force, captureReg, mask;
++
++    ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
++    event = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eevr);
++    mask = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier);
++
++    event &= mask;
++
++    /* clear the forced events */
++    force = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr);
++    if (force & event)
++        WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, force & ~event);
++
++    WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eevr, event);
++
++    if (event & FM_PCD_PLCR_DOUBLE_ECC)
++        p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC);
++    if (event & FM_PCD_PLCR_INIT_ENTRY_ERROR)
++    {
++        captureReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_upcr);
++        /*ASSERT_COND(captureReg & PLCR_ERR_UNINIT_CAP);
++        p_UnInitCapt->profileNum = (uint8_t)(captureReg & PLCR_ERR_UNINIT_NUM_MASK);
++        p_UnInitCapt->portId = (uint8_t)((captureReg & PLCR_ERR_UNINIT_PID_MASK) >>PLCR_ERR_UNINIT_PID_SHIFT) ;
++        p_UnInitCapt->absolute = (bool)(captureReg & PLCR_ERR_UNINIT_ABSOLUTE_MASK);*/
++        p_FmPcd->f_FmPcdIndexedException(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR,(uint16_t)(captureReg & PLCR_ERR_UNINIT_NUM_MASK));
++        WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_upcr, PLCR_ERR_UNINIT_CAP);
++    }
++}
++
++
++/*****************************************************************************/
++/*              Inter-module API routines                                    */
++/*****************************************************************************/
++
++t_Handle PlcrConfig(t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams)
++{
++    t_FmPcdPlcr *p_FmPcdPlcr;
++    uint16_t    i=0;
++
++    UNUSED(p_FmPcd);
++    UNUSED(p_FmPcdParams);
++
++    p_FmPcdPlcr = (t_FmPcdPlcr *) XX_Malloc(sizeof(t_FmPcdPlcr));
++    if (!p_FmPcdPlcr)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Policer structure allocation FAILED"));
++        return NULL;
++    }
++    memset(p_FmPcdPlcr, 0, sizeof(t_FmPcdPlcr));
++    if (p_FmPcd->guestId == NCSW_MASTER_ID)
++    {
++        p_FmPcdPlcr->p_FmPcdPlcrRegs  = (t_FmPcdPlcrRegs *)UINT_TO_PTR(FmGetPcdPlcrBaseAddr(p_FmPcdParams->h_Fm));
++        p_FmPcd->p_FmPcdDriverParam->plcrAutoRefresh    = DEFAULT_plcrAutoRefresh;
++        p_FmPcd->exceptions |= (DEFAULT_fmPcdPlcrExceptions | DEFAULT_fmPcdPlcrErrorExceptions);
++    }
++
++    p_FmPcdPlcr->numOfSharedProfiles    = DEFAULT_numOfSharedPlcrProfiles;
++
++    p_FmPcdPlcr->partPlcrProfilesBase   = p_FmPcdParams->partPlcrProfilesBase;
++    p_FmPcdPlcr->partNumOfPlcrProfiles  = p_FmPcdParams->partNumOfPlcrProfiles;
++    /* for backward compatabilty. if no policer profile, will set automatically to the max */
++    if ((p_FmPcd->guestId == NCSW_MASTER_ID) &&
++        (p_FmPcdPlcr->partNumOfPlcrProfiles == 0))
++        p_FmPcdPlcr->partNumOfPlcrProfiles = FM_PCD_PLCR_NUM_ENTRIES;
++
++    for (i=0; i<FM_PCD_PLCR_NUM_ENTRIES; i++)
++        p_FmPcdPlcr->profiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE;
++
++    return p_FmPcdPlcr;
++}
++
++t_Error PlcrInit(t_FmPcd *p_FmPcd)
++{
++    t_FmPcdDriverParam              *p_Param = p_FmPcd->p_FmPcdDriverParam;
++    t_FmPcdPlcr                     *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr;
++    t_FmPcdPlcrRegs                 *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
++    t_Error                         err = E_OK;
++    uint32_t                        tmpReg32 = 0;
++    uint16_t                        base;
++
++    if ((p_FmPcdPlcr->partPlcrProfilesBase + p_FmPcdPlcr->partNumOfPlcrProfiles) > FM_PCD_PLCR_NUM_ENTRIES)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("partPlcrProfilesBase+partNumOfPlcrProfiles out of range!!!"));
++
++    p_FmPcdPlcr->h_HwSpinlock = XX_InitSpinlock();
++    if (!p_FmPcdPlcr->h_HwSpinlock)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM Policer HW spinlock"));
++
++    p_FmPcdPlcr->h_SwSpinlock = XX_InitSpinlock();
++    if (!p_FmPcdPlcr->h_SwSpinlock)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM Policer SW spinlock"));
++
++    base = PlcrAllocProfilesForPartition(p_FmPcd,
++                                         p_FmPcdPlcr->partPlcrProfilesBase,
++                                         p_FmPcdPlcr->partNumOfPlcrProfiles,
++                                         p_FmPcd->guestId);
++    if (base == (uint16_t)ILLEGAL_BASE)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
++
++    if (p_FmPcdPlcr->numOfSharedProfiles)
++    {
++        err = AllocSharedProfiles(p_FmPcd,
++                                  p_FmPcdPlcr->numOfSharedProfiles,
++                                  p_FmPcdPlcr->sharedProfilesIds);
++        if (err)
++            RETURN_ERROR(MAJOR, err,NO_MSG);
++    }
++
++    if (p_FmPcd->guestId != NCSW_MASTER_ID)
++        return E_OK;
++
++    /**********************FMPL_GCR******************/
++    tmpReg32 = 0;
++    tmpReg32 |= FM_PCD_PLCR_GCR_STEN;
++    if (p_Param->plcrAutoRefresh)
++        tmpReg32 |= FM_PCD_PLCR_GCR_DAR;
++    tmpReg32 |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd);
++
++    WRITE_UINT32(p_Regs->fmpl_gcr, tmpReg32);
++    /**********************FMPL_GCR******************/
++
++    /**********************FMPL_EEVR******************/
++    WRITE_UINT32(p_Regs->fmpl_eevr, (FM_PCD_PLCR_DOUBLE_ECC | FM_PCD_PLCR_INIT_ENTRY_ERROR));
++    /**********************FMPL_EEVR******************/
++    /**********************FMPL_EIER******************/
++    tmpReg32 = 0;
++    if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_DOUBLE_ECC)
++    {
++        FmEnableRamsEcc(p_FmPcd->h_Fm);
++        tmpReg32 |= FM_PCD_PLCR_DOUBLE_ECC;
++    }
++    if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_INIT_ENTRY_ERROR)
++        tmpReg32 |= FM_PCD_PLCR_INIT_ENTRY_ERROR;
++    WRITE_UINT32(p_Regs->fmpl_eier, tmpReg32);
++    /**********************FMPL_EIER******************/
++
++    /**********************FMPL_EVR******************/
++    WRITE_UINT32(p_Regs->fmpl_evr, (FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE | FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE));
++    /**********************FMPL_EVR******************/
++    /**********************FMPL_IER******************/
++    tmpReg32 = 0;
++    if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE)
++        tmpReg32 |= FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE;
++    if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE)
++        tmpReg32 |= FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE;
++    WRITE_UINT32(p_Regs->fmpl_ier, tmpReg32);
++    /**********************FMPL_IER******************/
++
++    /* register even if no interrupts enabled, to allow future enablement */
++    FmRegisterIntr(p_FmPcd->h_Fm,
++                   e_FM_MOD_PLCR,
++                   0,
++                   e_FM_INTR_TYPE_ERR,
++                   ErrorExceptionsCB,
++                   p_FmPcd);
++    FmRegisterIntr(p_FmPcd->h_Fm,
++                   e_FM_MOD_PLCR,
++                   0,
++                   e_FM_INTR_TYPE_NORMAL,
++                   EventsCB,
++                   p_FmPcd);
++
++    /* driver initializes one DFLT profile at the last entry*/
++    /**********************FMPL_DPMR******************/
++    tmpReg32 = 0;
++    WRITE_UINT32(p_Regs->fmpl_dpmr, tmpReg32);
++    p_FmPcd->p_FmPcdPlcr->profiles[0].profilesMng.allocated = TRUE;
++
++    return E_OK;
++}
++
++t_Error PlcrFree(t_FmPcd *p_FmPcd)
++{
++    FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_ERR);
++    FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_NORMAL);
++
++    if (p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles)
++        FreeSharedProfiles(p_FmPcd,
++                           p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles,
++                           p_FmPcd->p_FmPcdPlcr->sharedProfilesIds);
++
++    if (p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles)
++        PlcrFreeProfilesForPartition(p_FmPcd,
++                                     p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase,
++                                     p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles,
++                                     p_FmPcd->guestId);
++
++    if (p_FmPcd->p_FmPcdPlcr->h_SwSpinlock)
++        XX_FreeSpinlock(p_FmPcd->p_FmPcdPlcr->h_SwSpinlock);
++
++    if (p_FmPcd->p_FmPcdPlcr->h_HwSpinlock)
++        XX_FreeSpinlock(p_FmPcd->p_FmPcdPlcr->h_HwSpinlock);
++
++    return E_OK;
++}
++
++void PlcrEnable(t_FmPcd *p_FmPcd)
++{
++    t_FmPcdPlcrRegs             *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
++
++    WRITE_UINT32(p_Regs->fmpl_gcr, GET_UINT32(p_Regs->fmpl_gcr) | FM_PCD_PLCR_GCR_EN);
++}
++
++void PlcrDisable(t_FmPcd *p_FmPcd)
++{
++    t_FmPcdPlcrRegs             *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
++
++    WRITE_UINT32(p_Regs->fmpl_gcr, GET_UINT32(p_Regs->fmpl_gcr) & ~FM_PCD_PLCR_GCR_EN);
++}
++
++uint16_t PlcrAllocProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId)
++{
++    uint32_t    intFlags;
++    uint16_t    profilesFound = 0;
++    int         i = 0;
++
++    ASSERT_COND(p_FmPcd);
++    ASSERT_COND(p_FmPcd->p_FmPcdPlcr);
++
++    if (!numOfProfiles)
++        return 0;
++
++    if ((numOfProfiles > FM_PCD_PLCR_NUM_ENTRIES) ||
++        (base + numOfProfiles > FM_PCD_PLCR_NUM_ENTRIES))
++        return (uint16_t)ILLEGAL_BASE;
++
++    if (p_FmPcd->h_IpcSession)
++    {
++        t_FmIpcResourceAllocParams      ipcAllocParams;
++        t_FmPcdIpcMsg                   msg;
++        t_FmPcdIpcReply                 reply;
++        t_Error                         err;
++        uint32_t                        replyLength;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams));
++        ipcAllocParams.guestId         = p_FmPcd->guestId;
++        ipcAllocParams.num             = p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles;
++        ipcAllocParams.base            = p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase;
++        msg.msgId                      = FM_PCD_ALLOC_PROFILES;
++        memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams));
++        replyLength = sizeof(uint32_t) + sizeof(uint16_t);
++        err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams),
++                                (uint8_t*)&reply,
++                                &replyLength,
++                                NULL,
++                                NULL);
++        if ((err != E_OK) ||
++            (replyLength != (sizeof(uint32_t) + sizeof(uint16_t))))
++        {
++            REPORT_ERROR(MAJOR, err, NO_MSG);
++            return (uint16_t)ILLEGAL_BASE;
++        }
++        else
++            memcpy((uint8_t*)&p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase, reply.replyBody, sizeof(uint16_t));
++        if (p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase == (uint16_t)ILLEGAL_BASE)
++        {
++            REPORT_ERROR(MAJOR, err, NO_MSG);
++            return (uint16_t)ILLEGAL_BASE;
++        }
++    }
++    else if (p_FmPcd->guestId != NCSW_MASTER_ID)
++    {
++        DBG(WARNING, ("FM Guest mode, without IPC - can't validate Policer-profiles range!"));
++        return (uint16_t)ILLEGAL_BASE;
++    }
++
++    intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock);
++    for (i=base; i<(base+numOfProfiles); i++)
++        if (p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId == (uint8_t)ILLEGAL_BASE)
++            profilesFound++;
++        else
++            break;
++
++    if (profilesFound == numOfProfiles)
++        for (i=base; i<(base+numOfProfiles); i++)
++            p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = guestId;
++    else
++    {
++        XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags);
++        return (uint16_t)ILLEGAL_BASE;
++    }
++    XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags);
++
++    return base;
++}
++
++void PlcrFreeProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId)
++{
++    int     i = 0;
++
++    ASSERT_COND(p_FmPcd);
++    ASSERT_COND(p_FmPcd->p_FmPcdPlcr);
++
++    if (p_FmPcd->h_IpcSession)
++    {
++        t_FmIpcResourceAllocParams      ipcAllocParams;
++        t_FmPcdIpcMsg                   msg;
++        t_Error                         err;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams));
++        ipcAllocParams.guestId         = p_FmPcd->guestId;
++        ipcAllocParams.num             = p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles;
++        ipcAllocParams.base            = p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase;
++        msg.msgId                      = FM_PCD_FREE_PROFILES;
++        memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams));
++        err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams),
++                                NULL,
++                                NULL,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            REPORT_ERROR(MAJOR, err, NO_MSG);
++        return;
++    }
++    else if (p_FmPcd->guestId != NCSW_MASTER_ID)
++    {
++        DBG(WARNING, ("FM Guest mode, without IPC - can't validate Policer-profiles range!"));
++        return;
++    }
++
++    for (i=base; i<(base+numOfProfiles); i++)
++    {
++        if (p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId == guestId)
++           p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE;
++        else
++            DBG(WARNING, ("Request for freeing storage profile window which wasn't allocated to this partition"));
++    }
++}
++
++t_Error PlcrSetPortProfiles(t_FmPcd    *p_FmPcd,
++                            uint8_t    hardwarePortId,
++                            uint16_t   numOfProfiles,
++                            uint16_t   base)
++{
++    t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
++    uint32_t        log2Num, tmpReg32;
++
++    if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
++        !p_Regs &&
++        p_FmPcd->h_IpcSession)
++    {
++        t_FmIpcResourceAllocParams      ipcAllocParams;
++        t_FmPcdIpcMsg                   msg;
++        t_Error                         err;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams));
++        ipcAllocParams.guestId         = hardwarePortId;
++        ipcAllocParams.num             = numOfProfiles;
++        ipcAllocParams.base            = base;
++        msg.msgId                              = FM_PCD_SET_PORT_PROFILES;
++        memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams));
++        err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams),
++                                NULL,
++                                NULL,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        return E_OK;
++    }
++    else if (!p_Regs)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("Either IPC or 'baseAddress' is required!"));
++
++    ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
++
++    if (GET_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1]) & FM_PCD_PLCR_PMR_V)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("The requesting port has already an allocated profiles window."));
++
++    /**********************FMPL_PMRx******************/
++    LOG2((uint64_t)numOfProfiles, log2Num);
++    tmpReg32 = base;
++    tmpReg32 |= log2Num << 16;
++    tmpReg32 |= FM_PCD_PLCR_PMR_V;
++    WRITE_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1], tmpReg32);
++
++    return E_OK;
++}
++
++t_Error PlcrClearPortProfiles(t_FmPcd *p_FmPcd, uint8_t hardwarePortId)
++{
++    t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
++
++    if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
++        !p_Regs &&
++        p_FmPcd->h_IpcSession)
++    {
++        t_FmIpcResourceAllocParams      ipcAllocParams;
++        t_FmPcdIpcMsg                   msg;
++        t_Error                         err;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams));
++        ipcAllocParams.guestId         = hardwarePortId;
++        msg.msgId                              = FM_PCD_CLEAR_PORT_PROFILES;
++        memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams));
++        err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams),
++                                NULL,
++                                NULL,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        return E_OK;
++    }
++    else if (!p_Regs)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("Either IPC or 'baseAddress' is required!"));
++
++    ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
++    WRITE_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1], 0);
++
++    return E_OK;
++}
++
++t_Error FmPcdPlcrAllocProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles)
++{
++    t_FmPcd                     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    t_Error                     err = E_OK;
++    uint32_t                    profilesFound;
++    uint32_t                    intFlags;
++    uint16_t                    i, first, swPortIndex = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++
++    if (!numOfProfiles)
++        return E_OK;
++
++    ASSERT_COND(hardwarePortId);
++
++    if (numOfProfiles>FM_PCD_PLCR_NUM_ENTRIES)
++        RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles is too big."));
++
++    if (!POWER_OF_2(numOfProfiles))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numProfiles must be a power of 2."));
++
++    first = 0;
++    profilesFound = 0;
++    intFlags = PlcrSwLock(p_FmPcd->p_FmPcdPlcr);
++
++    for (i=0; i<FM_PCD_PLCR_NUM_ENTRIES; )
++    {
++        if (!p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated)
++        {
++            profilesFound++;
++            i++;
++            if (profilesFound == numOfProfiles)
++                break;
++        }
++        else
++        {
++            profilesFound = 0;
++            /* advance i to the next aligned address */
++            i = first = (uint16_t)(first + numOfProfiles);
++        }
++    }
++
++    if (profilesFound == numOfProfiles)
++    {
++        for (i=first; i<first + numOfProfiles; i++)
++        {
++            p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated = TRUE;
++            p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = hardwarePortId;
++        }
++    }
++    else
++    {
++        PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
++        RETURN_ERROR(MINOR, E_FULL, ("No profiles."));
++    }
++    PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
++
++    err = PlcrSetPortProfiles(p_FmPcd, hardwarePortId, numOfProfiles, first);
++    if (err)
++    {
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
++
++    p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles = numOfProfiles;
++    p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase = first;
++
++    return E_OK;
++}
++
++t_Error FmPcdPlcrFreeProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId)
++{
++    t_FmPcd                     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    t_Error                     err = E_OK;
++    uint32_t                    intFlags;
++    uint16_t                    i, swPortIndex = 0;
++
++    ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
++
++    HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
++
++    err = PlcrClearPortProfiles(p_FmPcd, hardwarePortId);
++    if (err)
++        RETURN_ERROR(MAJOR, err,NO_MSG);
++
++    intFlags = PlcrSwLock(p_FmPcd->p_FmPcdPlcr);
++    for (i=p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase;
++         i<(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase +
++            p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles);
++         i++)
++    {
++        ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId == hardwarePortId);
++        ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated);
++
++        p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated = FALSE;
++        p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = p_FmPcd->guestId;
++    }
++    PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
++
++    p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles = 0;
++    p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase = 0;
++
++    return E_OK;
++}
++
++t_Error FmPcdPlcrCcGetSetParams(t_Handle h_FmPcd, uint16_t profileIndx ,uint32_t requiredAction)
++{
++    t_FmPcd         *p_FmPcd           = (t_FmPcd *)h_FmPcd;
++    t_FmPcdPlcr     *p_FmPcdPlcr        = p_FmPcd->p_FmPcdPlcr;
++    t_FmPcdPlcrRegs *p_FmPcdPlcrRegs    = p_FmPcdPlcr->p_FmPcdPlcrRegs;
++    uint32_t        tmpReg32, intFlags;
++    t_Error         err;
++
++    /* Calling function locked all PCD modules, so no need to lock here */
++
++    if (profileIndx >= FM_PCD_PLCR_NUM_ENTRIES)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Policer profile out of range"));
++
++    if (!FmPcdPlcrIsProfileValid(p_FmPcd, profileIndx))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Policer profile is not valid"));
++
++    /*intFlags = PlcrProfileLock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx]);*/
++
++    if (p_FmPcd->h_Hc)
++    {
++        err = FmHcPcdPlcrCcGetSetParams(p_FmPcd->h_Hc, profileIndx, requiredAction);
++
++        UpdateRequiredActionFlag(p_FmPcd, profileIndx, TRUE);
++        FmPcdPlcrUpdateRequiredAction(p_FmPcd, profileIndx, requiredAction);
++
++        /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/
++        return err;
++    }
++
++    /* lock the HW because once we read the registers we don't want them to be changed
++     * by another access. (We can copy to a tmp location and release the lock!) */
++
++    intFlags = PlcrHwLock(p_FmPcdPlcr);
++    WritePar(p_FmPcd, FmPcdPlcrBuildReadPlcrActionReg(profileIndx));
++
++    if (!p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].requiredActionFlag ||
++       !(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].requiredAction & requiredAction))
++    {
++        if (requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA)
++        {
++            if ((p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnGreen!= e_FM_PCD_DONE) ||
++               (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnYellow!= e_FM_PCD_DONE) ||
++               (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnRed!= e_FM_PCD_DONE))
++            {
++                PlcrHwUnlock(p_FmPcdPlcr, intFlags);
++                /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/
++                RETURN_ERROR (MAJOR, E_OK, ("In this case the next engine can be e_FM_PCD_DONE"));
++            }
++
++            if (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnGreen.action == e_FM_PCD_ENQ_FRAME)
++            {
++                tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia);
++                if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
++                {
++                    PlcrHwUnlock(p_FmPcdPlcr, intFlags);
++                    /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/
++                    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE"));
++                }
++                tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
++                WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia, tmpReg32);
++                tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx);
++                tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEGNIA;
++                WritePar(p_FmPcd, tmpReg32);
++            }
++
++            if (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnYellow.action == e_FM_PCD_ENQ_FRAME)
++            {
++                tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia);
++                if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
++                {
++                    PlcrHwUnlock(p_FmPcdPlcr, intFlags);
++                    /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/
++                    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE"));
++                }
++                tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
++                WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia, tmpReg32);
++                tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx);
++                tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEYNIA;
++                WritePar(p_FmPcd, tmpReg32);
++                PlcrHwUnlock(p_FmPcdPlcr, intFlags);
++            }
++
++            if (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnRed.action == e_FM_PCD_ENQ_FRAME)
++            {
++                tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia);
++                if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
++                {
++                    PlcrHwUnlock(p_FmPcdPlcr, intFlags);
++                    /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/
++                    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE"));
++                }
++                tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
++                WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia, tmpReg32);
++                tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx);
++                tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PERNIA;
++                WritePar(p_FmPcd, tmpReg32);
++
++            }
++        }
++    }
++    PlcrHwUnlock(p_FmPcdPlcr, intFlags);
++
++    UpdateRequiredActionFlag(p_FmPcd, profileIndx, TRUE);
++    FmPcdPlcrUpdateRequiredAction(p_FmPcd, profileIndx, requiredAction);
++
++    /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/
++
++    return E_OK;
++}
++
++uint32_t FmPcdPlcrGetRequiredActionFlag(t_Handle h_FmPcd, uint16_t absoluteProfileId)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++   ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
++
++    return p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredActionFlag;
++}
++
++uint32_t FmPcdPlcrGetRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++   ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
++
++    return p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction;
++}
++
++bool FmPcdPlcrIsProfileValid(t_Handle h_FmPcd, uint16_t absoluteProfileId)
++{
++    t_FmPcd         *p_FmPcd            = (t_FmPcd*)h_FmPcd;
++    t_FmPcdPlcr     *p_FmPcdPlcr        = p_FmPcd->p_FmPcdPlcr;
++
++    ASSERT_COND(absoluteProfileId < FM_PCD_PLCR_NUM_ENTRIES);
++
++    return p_FmPcdPlcr->profiles[absoluteProfileId].valid;
++}
++
++void  FmPcdPlcrValidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint32_t    intFlags;
++
++    ASSERT_COND(!p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
++
++    intFlags = PlcrProfileLock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId]);
++    p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid = TRUE;
++    PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId], intFlags);
++}
++
++void  FmPcdPlcrInvalidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint32_t    intFlags;
++
++    ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
++
++    intFlags = PlcrProfileLock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId]);
++    p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid = FALSE;
++    PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId], intFlags);
++}
++
++uint16_t     FmPcdPlcrProfileGetAbsoluteId(t_Handle h_Profile)
++{
++        return ((t_FmPcdPlcrProfile*)h_Profile)->absoluteProfileId;
++}
++
++t_Error FmPcdPlcrGetAbsoluteIdByProfileParams(t_Handle                      h_FmPcd,
++                                              e_FmPcdProfileTypeSelection   profileType,
++                                              t_Handle                      h_FmPort,
++                                              uint16_t                      relativeProfile,
++                                              uint16_t                      *p_AbsoluteId)
++{
++    t_FmPcd         *p_FmPcd            = (t_FmPcd*)h_FmPcd;
++    t_FmPcdPlcr     *p_FmPcdPlcr        = p_FmPcd->p_FmPcdPlcr;
++    uint8_t         i;
++
++    switch (profileType)
++    {
++        case e_FM_PCD_PLCR_PORT_PRIVATE:
++            /* get port PCD id from port handle */
++            for (i=0;i<FM_MAX_NUM_OF_PORTS;i++)
++                if (p_FmPcd->p_FmPcdPlcr->portsMapping[i].h_FmPort == h_FmPort)
++                    break;
++            if (i ==  FM_MAX_NUM_OF_PORTS)
++                RETURN_ERROR(MAJOR, E_INVALID_STATE , ("Invalid port handle."));
++
++            if (!p_FmPcd->p_FmPcdPlcr->portsMapping[i].numOfProfiles)
++                RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Port has no allocated profiles"));
++            if (relativeProfile >= p_FmPcd->p_FmPcdPlcr->portsMapping[i].numOfProfiles)
++                RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Profile id is out of range"));
++            *p_AbsoluteId = (uint16_t)(p_FmPcd->p_FmPcdPlcr->portsMapping[i].profilesBase + relativeProfile);
++            break;
++        case e_FM_PCD_PLCR_SHARED:
++            if (relativeProfile >= p_FmPcdPlcr->numOfSharedProfiles)
++                RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Profile id is out of range"));
++            *p_AbsoluteId = (uint16_t)(p_FmPcdPlcr->sharedProfilesIds[relativeProfile]);
++            break;
++        default:
++            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Invalid policer profile type"));
++    }
++
++    return E_OK;
++}
++
++uint16_t FmPcdPlcrGetPortProfilesBase(t_Handle h_FmPcd, uint8_t hardwarePortId)
++{
++    t_FmPcd         *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    uint16_t        swPortIndex = 0;
++
++    HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
++
++    return p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase;
++}
++
++uint16_t FmPcdPlcrGetPortNumOfProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId)
++{
++    t_FmPcd         *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    uint16_t        swPortIndex = 0;
++
++    HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
++
++    return p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles;
++
++}
++uint32_t FmPcdPlcrBuildWritePlcrActionReg(uint16_t absoluteProfileId)
++{
++    return (uint32_t)(FM_PCD_PLCR_PAR_GO |
++                      ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT));
++}
++
++uint32_t FmPcdPlcrBuildWritePlcrActionRegs(uint16_t absoluteProfileId)
++{
++    return (uint32_t)(FM_PCD_PLCR_PAR_GO |
++                      ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT) |
++                      FM_PCD_PLCR_PAR_PWSEL_MASK);
++}
++
++bool    FmPcdPlcrHwProfileIsValid(uint32_t profileModeReg)
++{
++
++    if (profileModeReg & FM_PCD_PLCR_PEMODE_PI)
++        return TRUE;
++    else
++        return FALSE;
++}
++
++uint32_t FmPcdPlcrBuildReadPlcrActionReg(uint16_t absoluteProfileId)
++{
++    return (uint32_t)(FM_PCD_PLCR_PAR_GO |
++                      FM_PCD_PLCR_PAR_R |
++                      ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT) |
++                      FM_PCD_PLCR_PAR_PWSEL_MASK);
++}
++
++uint32_t FmPcdPlcrBuildCounterProfileReg(e_FmPcdPlcrProfileCounters counter)
++{
++    switch (counter)
++    {
++        case (e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER):
++            return FM_PCD_PLCR_PAR_PWSEL_PEGPC;
++        case (e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER):
++            return FM_PCD_PLCR_PAR_PWSEL_PEYPC;
++        case (e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER) :
++            return FM_PCD_PLCR_PAR_PWSEL_PERPC;
++        case (e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER) :
++            return FM_PCD_PLCR_PAR_PWSEL_PERYPC;
++        case (e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER) :
++            return FM_PCD_PLCR_PAR_PWSEL_PERRPC;
++       default:
++            REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++            return 0;
++    }
++}
++
++uint32_t FmPcdPlcrBuildNiaProfileReg(bool green, bool yellow, bool red)
++{
++
++    uint32_t tmpReg32 = 0;
++
++    if (green)
++        tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEGNIA;
++    if (yellow)
++        tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEYNIA;
++    if (red)
++        tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PERNIA;
++
++    return tmpReg32;
++}
++
++void FmPcdPlcrUpdateRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId, uint32_t requiredAction)
++{
++    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    /* this routine is protected by calling routine */
++
++    ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
++
++    p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction |= requiredAction;
++}
++
++/*********************** End of inter-module routines ************************/
++
++
++/**************************************************/
++/*............Policer API.........................*/
++/**************************************************/
++
++t_Error FM_PCD_ConfigPlcrAutoRefreshMode(t_Handle h_FmPcd, bool enable)
++{
++   t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE);
++
++    if (!FmIsMaster(p_FmPcd->h_Fm))
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigPlcrAutoRefreshMode - guest mode!"));
++
++    p_FmPcd->p_FmPcdDriverParam->plcrAutoRefresh = enable;
++
++    return E_OK;
++}
++
++t_Error FM_PCD_ConfigPlcrNumOfSharedProfiles(t_Handle h_FmPcd, uint16_t numOfSharedPlcrProfiles)
++{
++   t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE);
++
++    p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles = numOfSharedPlcrProfiles;
++
++    return E_OK;
++}
++
++t_Error FM_PCD_SetPlcrStatistics(t_Handle h_FmPcd, bool enable)
++{
++   t_FmPcd  *p_FmPcd = (t_FmPcd*)h_FmPcd;
++   uint32_t tmpReg32;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE);
++
++    if (!FmIsMaster(p_FmPcd->h_Fm))
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetPlcrStatistics - guest mode!"));
++
++    tmpReg32 =  GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr);
++    if (enable)
++        tmpReg32 |= FM_PCD_PLCR_GCR_STEN;
++    else
++        tmpReg32 &= ~FM_PCD_PLCR_GCR_STEN;
++
++    WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr, tmpReg32);
++    return E_OK;
++}
++
++t_Handle FM_PCD_PlcrProfileSet(t_Handle     h_FmPcd,
++                               t_FmPcdPlcrProfileParams *p_ProfileParams)
++{
++    t_FmPcd                             *p_FmPcd;
++    t_FmPcdPlcrRegs                     *p_FmPcdPlcrRegs;
++    t_FmPcdPlcrProfileRegs              plcrProfileReg;
++    uint32_t                            intFlags;
++    uint16_t                            absoluteProfileId;
++    t_Error                             err = E_OK;
++    uint32_t                            tmpReg32;
++    t_FmPcdPlcrProfile                  *p_Profile;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL);
++
++    if (p_ProfileParams->modify)
++    {
++        p_Profile = (t_FmPcdPlcrProfile *)p_ProfileParams->id.h_Profile;
++        p_FmPcd = p_Profile->h_FmPcd;
++        absoluteProfileId = p_Profile->absoluteProfileId;
++        if (absoluteProfileId >= FM_PCD_PLCR_NUM_ENTRIES)
++        {
++            REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big "));
++            return NULL;
++        }
++
++        SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE, NULL);
++
++        /* Try lock profile using flag */
++         if (!PlcrProfileFlagTryLock(p_Profile))
++         {
++             DBG(TRACE, ("Profile Try Lock - BUSY"));
++             /* Signal to caller BUSY condition */
++             p_ProfileParams->id.h_Profile = NULL;
++             return NULL;
++         }
++   }
++    else
++    {
++        p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++        SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE, NULL);
++
++        /* SMP: needs to be protected only if another core now changes the windows */
++        err = FmPcdPlcrGetAbsoluteIdByProfileParams(h_FmPcd,
++                                                    p_ProfileParams->id.newParams.profileType,
++                                                    p_ProfileParams->id.newParams.h_FmPort,
++                                                    p_ProfileParams->id.newParams.relativeProfileId,
++                                                    &absoluteProfileId);
++        if (err)
++        {
++             REPORT_ERROR(MAJOR, err, NO_MSG);
++             return NULL;
++        }
++
++         if (absoluteProfileId >= FM_PCD_PLCR_NUM_ENTRIES)
++         {
++             REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big "));
++             return NULL;
++         }
++
++         if (FmPcdPlcrIsProfileValid(p_FmPcd, absoluteProfileId))
++         {
++             REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Policer Profile is already used"));
++             return NULL;
++         }
++
++         /* initialize profile struct */
++         p_Profile = &p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId];
++
++         p_Profile->h_FmPcd = p_FmPcd;
++         p_Profile->absoluteProfileId = absoluteProfileId;
++
++         p_Profile->p_Lock = FmPcdAcquireLock(p_FmPcd);
++         if (!p_Profile->p_Lock)
++             REPORT_ERROR(MAJOR, E_NOT_AVAILABLE, ("FM Policer Profile lock obj!"));
++    }
++
++    SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, NULL);
++
++    p_Profile->nextEngineOnGreen = p_ProfileParams->nextEngineOnGreen;
++    memcpy(&p_Profile->paramsOnGreen, &(p_ProfileParams->paramsOnGreen), sizeof(u_FmPcdPlcrNextEngineParams));
++
++    p_Profile->nextEngineOnYellow = p_ProfileParams->nextEngineOnYellow;
++    memcpy(&p_Profile->paramsOnYellow, &(p_ProfileParams->paramsOnYellow), sizeof(u_FmPcdPlcrNextEngineParams));
++
++    p_Profile->nextEngineOnRed = p_ProfileParams->nextEngineOnRed;
++    memcpy(&p_Profile->paramsOnRed, &(p_ProfileParams->paramsOnRed), sizeof(u_FmPcdPlcrNextEngineParams));
++
++    memset(&plcrProfileReg, 0, sizeof(t_FmPcdPlcrProfileRegs));
++
++    /* build the policer profile registers */
++    err =  BuildProfileRegs(h_FmPcd, p_ProfileParams, &plcrProfileReg);
++    if (err)
++    {
++        REPORT_ERROR(MAJOR, err, NO_MSG);
++        if (p_ProfileParams->modify)
++            /* unlock */
++            PlcrProfileFlagUnlock(p_Profile);
++        if (!p_ProfileParams->modify &&
++                p_Profile->p_Lock)
++            /* release allocated Profile lock */
++            FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock);
++        return NULL;
++    }
++
++    if (p_FmPcd->h_Hc)
++    {
++         err = FmHcPcdPlcrSetProfile(p_FmPcd->h_Hc, (t_Handle)p_Profile, &plcrProfileReg);
++         if (p_ProfileParams->modify)
++             PlcrProfileFlagUnlock(p_Profile);
++         if (err)
++         {
++             /* release the allocated scheme lock */
++             if (!p_ProfileParams->modify &&
++                     p_Profile->p_Lock)
++                 FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock);
++
++             return NULL;
++         }
++         if (!p_ProfileParams->modify)
++             FmPcdPlcrValidateProfileSw(p_FmPcd,absoluteProfileId);
++         return (t_Handle)p_Profile;
++    }
++
++    p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
++    SANITY_CHECK_RETURN_VALUE(p_FmPcdPlcrRegs, E_INVALID_HANDLE, NULL);
++
++    intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pemode , plcrProfileReg.fmpl_pemode);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia , plcrProfileReg.fmpl_pegnia);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia , plcrProfileReg.fmpl_peynia);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia , plcrProfileReg.fmpl_pernia);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pecir  , plcrProfileReg.fmpl_pecir);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pecbs  , plcrProfileReg.fmpl_pecbs);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepepir_eir,plcrProfileReg.fmpl_pepepir_eir);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepbs_ebs,plcrProfileReg.fmpl_pepbs_ebs);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pelts  , plcrProfileReg.fmpl_pelts);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pects  , plcrProfileReg.fmpl_pects);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepts_ets,plcrProfileReg.fmpl_pepts_ets);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc  , plcrProfileReg.fmpl_pegpc);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc  , plcrProfileReg.fmpl_peypc);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc  , plcrProfileReg.fmpl_perpc);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc , plcrProfileReg.fmpl_perypc);
++    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc , plcrProfileReg.fmpl_perrpc);
++
++    tmpReg32 = FmPcdPlcrBuildWritePlcrActionRegs(absoluteProfileId);
++    WritePar(p_FmPcd, tmpReg32);
++
++    PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
++
++    if (!p_ProfileParams->modify)
++        FmPcdPlcrValidateProfileSw(p_FmPcd,absoluteProfileId);
++    else
++        PlcrProfileFlagUnlock(p_Profile);
++
++    return (t_Handle)p_Profile;
++}
++
++t_Error FM_PCD_PlcrProfileDelete(t_Handle h_Profile)
++{
++    t_FmPcdPlcrProfile  *p_Profile = (t_FmPcdPlcrProfile*)h_Profile;
++    t_FmPcd             *p_FmPcd;
++    uint16_t            profileIndx;
++    uint32_t            tmpReg32, intFlags;
++    t_Error             err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Profile, E_INVALID_HANDLE);
++    p_FmPcd = p_Profile->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++
++    profileIndx = p_Profile->absoluteProfileId;
++
++    UpdateRequiredActionFlag(p_FmPcd, profileIndx, FALSE);
++
++    FmPcdPlcrInvalidateProfileSw(p_FmPcd,profileIndx);
++
++    if (p_FmPcd->h_Hc)
++    {
++        err = FmHcPcdPlcrDeleteProfile(p_FmPcd->h_Hc, h_Profile);
++        if (p_Profile->p_Lock)
++            /* release allocated Profile lock */
++            FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock);
++
++        return err;
++    }
++
++    intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr);
++    WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->profileRegs.fmpl_pemode, ~FM_PCD_PLCR_PEMODE_PI);
++
++    tmpReg32 = FmPcdPlcrBuildWritePlcrActionRegs(profileIndx);
++    WritePar(p_FmPcd, tmpReg32);
++    PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
++
++
++    if (p_Profile->p_Lock)
++        /* release allocated Profile lock */
++        FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock);
++
++    /* we do not memset profile as all its fields are being re-initialized at "set",
++     * plus its allocation information is still valid. */
++    return E_OK;
++}
++
++/***************************************************/
++/*............Policer Profile Counter..............*/
++/***************************************************/
++uint32_t FM_PCD_PlcrProfileGetCounter(t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter)
++{
++    t_FmPcdPlcrProfile  *p_Profile = (t_FmPcdPlcrProfile*)h_Profile;
++    t_FmPcd             *p_FmPcd;
++    uint16_t            profileIndx;
++    uint32_t            intFlags, counterVal = 0;
++    t_FmPcdPlcrRegs     *p_FmPcdPlcrRegs;
++
++    SANITY_CHECK_RETURN_ERROR(p_Profile, E_INVALID_HANDLE);
++    p_FmPcd = p_Profile->h_FmPcd;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++
++    if (p_FmPcd->h_Hc)
++        return FmHcPcdPlcrGetProfileCounter(p_FmPcd->h_Hc, h_Profile, counter);
++
++    p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
++    SANITY_CHECK_RETURN_VALUE(p_FmPcdPlcrRegs, E_INVALID_HANDLE, 0);
++
++    profileIndx = p_Profile->absoluteProfileId;
++
++    if (profileIndx >= FM_PCD_PLCR_NUM_ENTRIES)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big "));
++        return 0;
++    }
++    intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr);
++    WritePar(p_FmPcd, FmPcdPlcrBuildReadPlcrActionReg(profileIndx));
++
++    switch (counter)
++    {
++        case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER:
++            counterVal = (GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc));
++            break;
++        case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER:
++            counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc);
++            break;
++        case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER:
++            counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc);
++            break;
++        case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER:
++            counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc);
++            break;
++        case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER:
++            counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc);
++            break;
++        default:
++            REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++            break;
++    }
++    PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
++
++    return counterVal;
++}
++
++t_Error FM_PCD_PlcrProfileSetCounter(t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value)
++{
++    t_FmPcdPlcrProfile  *p_Profile = (t_FmPcdPlcrProfile*)h_Profile;
++    t_FmPcd             *p_FmPcd;
++    uint16_t            profileIndx;
++    uint32_t            tmpReg32, intFlags;
++    t_FmPcdPlcrRegs     *p_FmPcdPlcrRegs;
++
++    SANITY_CHECK_RETURN_ERROR(p_Profile, E_INVALID_HANDLE);
++
++    p_FmPcd = p_Profile->h_FmPcd;
++    profileIndx = p_Profile->absoluteProfileId;
++
++    if (p_FmPcd->h_Hc)
++        return FmHcPcdPlcrSetProfileCounter(p_FmPcd->h_Hc, h_Profile, counter, value);
++
++    p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
++    SANITY_CHECK_RETURN_ERROR(p_FmPcdPlcrRegs, E_INVALID_HANDLE);
++
++    intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr);
++    switch (counter)
++    {
++        case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER:
++             WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc, value);
++             break;
++        case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER:
++             WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc, value);
++             break;
++        case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER:
++             WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc, value);
++             break;
++        case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER:
++             WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc ,value);
++             break;
++        case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER:
++             WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc ,value);
++             break;
++        default:
++            PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
++            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++    }
++
++    /*  Activate the atomic write action by writing FMPL_PAR with: GO=1, RW=1, PSI=0, PNUM =
++     *  Profile Number, PWSEL=0xFFFF (select all words).
++     */
++    tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx);
++    tmpReg32 |= FmPcdPlcrBuildCounterProfileReg(counter);
++    WritePar(p_FmPcd, tmpReg32);
++    PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
++
++    return E_OK;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.h
+@@ -0,0 +1,165 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_plcr.h
++
++ @Description   FM Policer private header
++*//***************************************************************************/
++#ifndef __FM_PLCR_H
++#define __FM_PLCR_H
++
++#include "std_ext.h"
++
++
++/***********************************************************************/
++/*          Policer defines                                            */
++/***********************************************************************/
++
++#define FM_PCD_PLCR_PAR_GO                    0x80000000
++#define FM_PCD_PLCR_PAR_PWSEL_MASK            0x0000FFFF
++#define FM_PCD_PLCR_PAR_R                     0x40000000
++
++/* shifts */
++#define FM_PCD_PLCR_PAR_PNUM_SHIFT            16
++
++/* masks */
++#define FM_PCD_PLCR_PEMODE_PI                 0x80000000
++#define FM_PCD_PLCR_PEMODE_CBLND              0x40000000
++#define FM_PCD_PLCR_PEMODE_ALG_MASK           0x30000000
++#define FM_PCD_PLCR_PEMODE_ALG_RFC2698        0x10000000
++#define FM_PCD_PLCR_PEMODE_ALG_RFC4115        0x20000000
++#define FM_PCD_PLCR_PEMODE_DEFC_MASK          0x0C000000
++#define FM_PCD_PLCR_PEMODE_DEFC_Y             0x04000000
++#define FM_PCD_PLCR_PEMODE_DEFC_R             0x08000000
++#define FM_PCD_PLCR_PEMODE_DEFC_OVERRIDE      0x0C000000
++#define FM_PCD_PLCR_PEMODE_OVCLR_MASK         0x03000000
++#define FM_PCD_PLCR_PEMODE_OVCLR_Y            0x01000000
++#define FM_PCD_PLCR_PEMODE_OVCLR_R            0x02000000
++#define FM_PCD_PLCR_PEMODE_OVCLR_G_NC         0x03000000
++#define FM_PCD_PLCR_PEMODE_PKT                0x00800000
++#define FM_PCD_PLCR_PEMODE_FPP_MASK           0x001F0000
++#define FM_PCD_PLCR_PEMODE_FPP_SHIFT          16
++#define FM_PCD_PLCR_PEMODE_FLS_MASK           0x0000F000
++#define FM_PCD_PLCR_PEMODE_FLS_L2             0x00003000
++#define FM_PCD_PLCR_PEMODE_FLS_L3             0x0000B000
++#define FM_PCD_PLCR_PEMODE_FLS_L4             0x0000E000
++#define FM_PCD_PLCR_PEMODE_FLS_FULL           0x0000F000
++#define FM_PCD_PLCR_PEMODE_RBFLS              0x00000800
++#define FM_PCD_PLCR_PEMODE_TRA                0x00000004
++#define FM_PCD_PLCR_PEMODE_TRB                0x00000002
++#define FM_PCD_PLCR_PEMODE_TRC                0x00000001
++#define FM_PCD_PLCR_DOUBLE_ECC                0x80000000
++#define FM_PCD_PLCR_INIT_ENTRY_ERROR          0x40000000
++#define FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE   0x80000000
++#define FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE    0x40000000
++
++#define FM_PCD_PLCR_NIA_VALID                 0x80000000
++
++#define FM_PCD_PLCR_GCR_EN                    0x80000000
++#define FM_PCD_PLCR_GCR_STEN                  0x40000000
++#define FM_PCD_PLCR_GCR_DAR                   0x20000000
++#define FM_PCD_PLCR_GCR_DEFNIA                0x00FFFFFF
++#define FM_PCD_PLCR_NIA_ABS                   0x00000100
++
++#define FM_PCD_PLCR_GSR_BSY                   0x80000000
++#define FM_PCD_PLCR_GSR_DQS                   0x60000000
++#define FM_PCD_PLCR_GSR_RPB                   0x20000000
++#define FM_PCD_PLCR_GSR_FQS                   0x0C000000
++#define FM_PCD_PLCR_GSR_LPALG                 0x0000C000
++#define FM_PCD_PLCR_GSR_LPCA                  0x00003000
++#define FM_PCD_PLCR_GSR_LPNUM                 0x000000FF
++
++#define FM_PCD_PLCR_EVR_PSIC                  0x80000000
++#define FM_PCD_PLCR_EVR_AAC                   0x40000000
++
++#define FM_PCD_PLCR_PAR_PSI                   0x20000000
++#define FM_PCD_PLCR_PAR_PNUM                  0x00FF0000
++/* PWSEL Selctive select options */
++#define FM_PCD_PLCR_PAR_PWSEL_PEMODE          0x00008000    /* 0 */
++#define FM_PCD_PLCR_PAR_PWSEL_PEGNIA          0x00004000    /* 1 */
++#define FM_PCD_PLCR_PAR_PWSEL_PEYNIA          0x00002000    /* 2 */
++#define FM_PCD_PLCR_PAR_PWSEL_PERNIA          0x00001000    /* 3 */
++#define FM_PCD_PLCR_PAR_PWSEL_PECIR           0x00000800    /* 4 */
++#define FM_PCD_PLCR_PAR_PWSEL_PECBS           0x00000400    /* 5 */
++#define FM_PCD_PLCR_PAR_PWSEL_PEPIR_EIR       0x00000200    /* 6 */
++#define FM_PCD_PLCR_PAR_PWSEL_PEPBS_EBS       0x00000100    /* 7 */
++#define FM_PCD_PLCR_PAR_PWSEL_PELTS           0x00000080    /* 8 */
++#define FM_PCD_PLCR_PAR_PWSEL_PECTS           0x00000040    /* 9 */
++#define FM_PCD_PLCR_PAR_PWSEL_PEPTS_ETS       0x00000020    /* 10 */
++#define FM_PCD_PLCR_PAR_PWSEL_PEGPC           0x00000010    /* 11 */
++#define FM_PCD_PLCR_PAR_PWSEL_PEYPC           0x00000008    /* 12 */
++#define FM_PCD_PLCR_PAR_PWSEL_PERPC           0x00000004    /* 13 */
++#define FM_PCD_PLCR_PAR_PWSEL_PERYPC          0x00000002    /* 14 */
++#define FM_PCD_PLCR_PAR_PWSEL_PERRPC          0x00000001    /* 15 */
++
++#define FM_PCD_PLCR_PAR_PMR_BRN_1TO1          0x0000   /* - Full bit replacement. {PBNUM[0:N-1]
++                                                           1-> 2^N specific locations. */
++#define FM_PCD_PLCR_PAR_PMR_BRN_2TO2          0x1      /* - {PBNUM[0:N-2],PNUM[N-1]}.
++                                                           2-> 2^(N-1) base locations. */
++#define FM_PCD_PLCR_PAR_PMR_BRN_4TO4          0x2      /* - {PBNUM[0:N-3],PNUM[N-2:N-1]}.
++                                                           4-> 2^(N-2) base locations. */
++#define FM_PCD_PLCR_PAR_PMR_BRN_8TO8          0x3      /* - {PBNUM[0:N-4],PNUM[N-3:N-1]}.
++                                                           8->2^(N-3) base locations. */
++#define FM_PCD_PLCR_PAR_PMR_BRN_16TO16        0x4      /* - {PBNUM[0:N-5],PNUM[N-4:N-1]}.
++                                                           16-> 2^(N-4) base locations. */
++#define FM_PCD_PLCR_PAR_PMR_BRN_32TO32        0x5      /* {PBNUM[0:N-6],PNUM[N-5:N-1]}.
++                                                           32-> 2^(N-5) base locations. */
++#define FM_PCD_PLCR_PAR_PMR_BRN_64TO64        0x6      /* {PBNUM[0:N-7],PNUM[N-6:N-1]}.
++                                                           64-> 2^(N-6) base locations. */
++#define FM_PCD_PLCR_PAR_PMR_BRN_128TO128      0x7      /* {PBNUM[0:N-8],PNUM[N-7:N-1]}.
++                                                            128-> 2^(N-7) base locations. */
++#define FM_PCD_PLCR_PAR_PMR_BRN_256TO256      0x8      /* - No bit replacement for N=8. {PNUM[N-8:N-1]}.
++                                                            When N=8 this option maps all 256 profiles by the DISPATCH bus into one group. */
++
++#define FM_PCD_PLCR_PMR_V                     0x80000000
++#define PLCR_ERR_ECC_CAP                      0x80000000
++#define PLCR_ERR_ECC_TYPE_DOUBLE              0x40000000
++#define PLCR_ERR_ECC_PNUM_MASK                0x00000FF0
++#define PLCR_ERR_ECC_OFFSET_MASK              0x0000000F
++
++#define PLCR_ERR_UNINIT_CAP                   0x80000000
++#define PLCR_ERR_UNINIT_NUM_MASK              0x000000FF
++#define PLCR_ERR_UNINIT_PID_MASK              0x003f0000
++#define PLCR_ERR_UNINIT_ABSOLUTE_MASK         0x00008000
++
++/* shifts */
++#define PLCR_ERR_ECC_PNUM_SHIFT               4
++#define PLCR_ERR_UNINIT_PID_SHIFT             16
++
++#define FM_PCD_PLCR_PMR_BRN_SHIFT             16
++
++#define PLCR_PORT_WINDOW_SIZE(hardwarePortId)
++
++
++#endif /* __FM_PLCR_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.c
+@@ -0,0 +1,423 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_pcd.c
++
++ @Description   FM PCD ...
++*//***************************************************************************/
++#include <linux/math64.h>
++#include "std_ext.h"
++#include "error_ext.h"
++#include "string_ext.h"
++#include "debug_ext.h"
++#include "net_ext.h"
++
++#include "fm_common.h"
++#include "fm_pcd.h"
++#include "fm_pcd_ipc.h"
++#include "fm_prs.h"
++#include "fsl_fman_prs.h"
++
++
++static void PcdPrsErrorException(t_Handle h_FmPcd)
++{
++    t_FmPcd                 *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    uint32_t                event, ev_mask;
++    struct fman_prs_regs     *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
++
++    ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID);
++    ev_mask = fman_prs_get_err_ev_mask(PrsRegs);
++
++    event = fman_prs_get_err_event(PrsRegs, ev_mask);
++
++    fman_prs_ack_err_event(PrsRegs, event);
++
++    DBG(TRACE, ("parser error - 0x%08x\n",event));
++
++    if(event & FM_PCD_PRS_DOUBLE_ECC)
++        p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC);
++}
++
++static void PcdPrsException(t_Handle h_FmPcd)
++{
++    t_FmPcd             *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    uint32_t            event, ev_mask;
++    struct fman_prs_regs     *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
++
++    ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID);
++    ev_mask = fman_prs_get_expt_ev_mask(PrsRegs);
++    event = fman_prs_get_expt_event(PrsRegs, ev_mask);
++
++    ASSERT_COND(event & FM_PCD_PRS_SINGLE_ECC);
++
++    DBG(TRACE, ("parser event - 0x%08x\n",event));
++
++    fman_prs_ack_expt_event(PrsRegs, event);
++
++    p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC);
++}
++
++t_Handle PrsConfig(t_FmPcd *p_FmPcd,t_FmPcdParams *p_FmPcdParams)
++{
++    t_FmPcdPrs  *p_FmPcdPrs;
++    uintptr_t   baseAddr;
++
++    UNUSED(p_FmPcd);
++    UNUSED(p_FmPcdParams);
++
++    p_FmPcdPrs = (t_FmPcdPrs *) XX_Malloc(sizeof(t_FmPcdPrs));
++    if (!p_FmPcdPrs)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Parser structure allocation FAILED"));
++        return NULL;
++    }
++    memset(p_FmPcdPrs, 0, sizeof(t_FmPcdPrs));
++    fman_prs_defconfig(&p_FmPcd->p_FmPcdDriverParam->dfltCfg);
++
++    if (p_FmPcd->guestId == NCSW_MASTER_ID)
++    {
++        baseAddr = FmGetPcdPrsBaseAddr(p_FmPcdParams->h_Fm);
++        p_FmPcdPrs->p_SwPrsCode  = (uint32_t *)UINT_TO_PTR(baseAddr);
++        p_FmPcdPrs->p_FmPcdPrsRegs  = (struct fman_prs_regs *)UINT_TO_PTR(baseAddr + PRS_REGS_OFFSET);
++    }
++
++    p_FmPcdPrs->fmPcdPrsPortIdStatistics = p_FmPcd->p_FmPcdDriverParam->dfltCfg.port_id_stat;
++    p_FmPcd->p_FmPcdDriverParam->prsMaxParseCycleLimit = p_FmPcd->p_FmPcdDriverParam->dfltCfg.max_prs_cyc_lim;
++    p_FmPcd->exceptions |= p_FmPcd->p_FmPcdDriverParam->dfltCfg.prs_exceptions;
++
++    return p_FmPcdPrs;
++}
++
++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++    static uint8_t             swPrsPatch[] = SW_PRS_UDP_LITE_PATCH;
++#else
++    static uint8_t             swPrsPatch[] = SW_PRS_OFFLOAD_PATCH;
++#endif /* FM_CAPWAP_SUPPORT */
++
++t_Error PrsInit(t_FmPcd *p_FmPcd)
++{
++    t_FmPcdDriverParam  *p_Param = p_FmPcd->p_FmPcdDriverParam;
++    uint32_t            *p_TmpCode;
++    uint32_t            *p_LoadTarget = (uint32_t *)PTR_MOVE(p_FmPcd->p_FmPcdPrs->p_SwPrsCode,
++                                                             FM_PCD_SW_PRS_SIZE-FM_PCD_PRS_SW_PATCHES_SIZE);
++    struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
++    uint32_t            i;
++
++    ASSERT_COND(sizeof(swPrsPatch) <= (FM_PCD_PRS_SW_PATCHES_SIZE-FM_PCD_PRS_SW_TAIL_SIZE));
++
++    /* nothing to do in guest-partition */
++    if (p_FmPcd->guestId != NCSW_MASTER_ID)
++        return E_OK;
++
++    p_TmpCode = (uint32_t *)XX_MallocSmart(ROUND_UP(sizeof(swPrsPatch),4), 0, sizeof(uint32_t));
++    if (!p_TmpCode)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Tmp Sw-Parser code allocation FAILED"));
++    memset((uint8_t *)p_TmpCode, 0, ROUND_UP(sizeof(swPrsPatch),4));
++    memcpy((uint8_t *)p_TmpCode, (uint8_t *)swPrsPatch, sizeof(swPrsPatch));
++
++    fman_prs_init(PrsRegs, &p_Param->dfltCfg);
++
++    /* register even if no interrupts enabled, to allow future enablement */
++    FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_ERR, PcdPrsErrorException, p_FmPcd);
++
++    /* register even if no interrupts enabled, to allow future enablement */
++    FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_NORMAL, PcdPrsException, p_FmPcd);
++
++    if(p_FmPcd->exceptions & FM_PCD_EX_PRS_SINGLE_ECC)
++        FmEnableRamsEcc(p_FmPcd->h_Fm);
++
++    if(p_FmPcd->exceptions & FM_PCD_EX_PRS_DOUBLE_ECC)
++        FmEnableRamsEcc(p_FmPcd->h_Fm);
++
++    /* load sw parser Ip-Frag patch */
++    for (i=0; i<DIV_CEIL(sizeof(swPrsPatch), 4); i++)
++        WRITE_UINT32(p_LoadTarget[i], GET_UINT32(p_TmpCode[i]));
++
++    XX_FreeSmart(p_TmpCode);
++
++    return E_OK;
++}
++
++void PrsFree(t_FmPcd *p_FmPcd)
++{
++    ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID);
++    FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_ERR);
++    /* register even if no interrupts enabled, to allow future enablement */
++    FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_NORMAL);
++}
++
++void PrsEnable(t_FmPcd *p_FmPcd)
++{
++    struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
++
++    ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID);
++    fman_prs_enable(PrsRegs);
++}
++
++void PrsDisable(t_FmPcd *p_FmPcd)
++{
++    struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
++
++    ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID);
++    fman_prs_disable(PrsRegs);
++}
++
++int PrsIsEnabled(t_FmPcd *p_FmPcd)
++{
++    struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
++
++    ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID);
++    return fman_prs_is_enabled(PrsRegs);
++}
++
++t_Error PrsIncludePortInStatistics(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, bool include)
++{
++    struct fman_prs_regs *PrsRegs;
++    uint32_t    bitMask = 0;
++    uint8_t     prsPortId;
++
++    SANITY_CHECK_RETURN_ERROR((hardwarePortId >=1 && hardwarePortId <= 16), E_INVALID_VALUE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE);
++
++    PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
++
++    GET_FM_PCD_PRS_PORT_ID(prsPortId, hardwarePortId);
++    GET_FM_PCD_INDEX_FLAG(bitMask, prsPortId);
++
++    if (include)
++        p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics |= bitMask;
++    else
++        p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics &= ~bitMask;
++
++    fman_prs_set_stst_port_msk(PrsRegs,
++            p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics);
++
++    return E_OK;
++}
++
++t_Error FmPcdPrsIncludePortInStatistics(t_Handle h_FmPcd, uint8_t hardwarePortId, bool include)
++{
++    t_FmPcd                     *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    t_Error                     err;
++
++    SANITY_CHECK_RETURN_ERROR((hardwarePortId >=1 && hardwarePortId <= 16), E_INVALID_VALUE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE);
++
++    if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
++        p_FmPcd->h_IpcSession)
++    {
++        t_FmPcdIpcPrsIncludePort    prsIncludePortParams;
++        t_FmPcdIpcMsg               msg;
++
++        prsIncludePortParams.hardwarePortId = hardwarePortId;
++        prsIncludePortParams.include = include;
++        memset(&msg, 0, sizeof(msg));
++        msg.msgId = FM_PCD_PRS_INC_PORT_STATS;
++        memcpy(msg.msgBody, &prsIncludePortParams, sizeof(prsIncludePortParams));
++        err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId) +sizeof(prsIncludePortParams),
++                                NULL,
++                                NULL,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        return E_OK;
++    }
++    else if (p_FmPcd->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("running in guest-mode without IPC!"));
++
++    return PrsIncludePortInStatistics(p_FmPcd, hardwarePortId, include);
++}
++
++uint32_t FmPcdGetSwPrsOffset(t_Handle h_FmPcd, e_NetHeaderType hdr, uint8_t indexPerHdr)
++{
++    t_FmPcd                 *p_FmPcd = (t_FmPcd *)h_FmPcd;
++    t_FmPcdPrsLabelParams   *p_Label;
++    int                     i;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, 0);
++    SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE, 0);
++
++    if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
++        p_FmPcd->h_IpcSession)
++    {
++        t_Error                 err = E_OK;
++        t_FmPcdIpcSwPrsLable    labelParams;
++        t_FmPcdIpcMsg           msg;
++        uint32_t                prsOffset = 0;
++        t_FmPcdIpcReply         reply;
++        uint32_t                replyLength;
++
++        memset(&reply, 0, sizeof(reply));
++        memset(&msg, 0, sizeof(msg));
++        labelParams.enumHdr = (uint32_t)hdr;
++        labelParams.indexPerHdr = indexPerHdr;
++        msg.msgId = FM_PCD_GET_SW_PRS_OFFSET;
++        memcpy(msg.msgBody, &labelParams, sizeof(labelParams));
++        replyLength = sizeof(uint32_t) + sizeof(uint32_t);
++        err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId) +sizeof(labelParams),
++                                (uint8_t*)&reply,
++                                &replyLength,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        if (replyLength != sizeof(uint32_t) + sizeof(uint32_t))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++
++        memcpy((uint8_t*)&prsOffset, reply.replyBody, sizeof(uint32_t));
++        return prsOffset;
++    }
++    else if (p_FmPcd->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("running in guest-mode without IPC!"));
++
++    ASSERT_COND(p_FmPcd->p_FmPcdPrs->currLabel < FM_PCD_PRS_NUM_OF_LABELS);
++
++    for (i=0; i<p_FmPcd->p_FmPcdPrs->currLabel; i++)
++    {
++        p_Label = &p_FmPcd->p_FmPcdPrs->labelsTable[i];
++
++        if ((hdr == p_Label->hdr) && (indexPerHdr == p_Label->indexPerHdr))
++            return p_Label->instructionOffset;
++    }
++
++    REPORT_ERROR(MAJOR, E_NOT_FOUND, ("Sw Parser attachment Not found"));
++    return (uint32_t)ILLEGAL_BASE;
++}
++
++void FM_PCD_SetPrsStatistics(t_Handle h_FmPcd, bool enable)
++{
++    t_FmPcd             *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    struct fman_prs_regs *PrsRegs;
++
++    SANITY_CHECK_RETURN(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE);
++
++    PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
++
++
++    if(p_FmPcd->guestId != NCSW_MASTER_ID)
++    {
++        REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetPrsStatistics - guest mode!"));
++        return;
++    }
++
++    fman_prs_set_stst(PrsRegs, enable);
++}
++
++t_Error FM_PCD_PrsLoadSw(t_Handle h_FmPcd, t_FmPcdPrsSwParams *p_SwPrs)
++{
++    t_FmPcd                 *p_FmPcd = (t_FmPcd*)h_FmPcd;
++    uint32_t                *p_LoadTarget;
++    uint32_t                *p_TmpCode;
++    int                     i;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_SwPrs, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->enabled, E_INVALID_HANDLE);
++
++    if (p_FmPcd->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM in guest-mode!"));
++
++    if (!p_SwPrs->override)
++    {
++        if(p_FmPcd->p_FmPcdPrs->p_CurrSwPrs > p_FmPcd->p_FmPcdPrs->p_SwPrsCode + p_SwPrs->base*2/4)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("SW parser base must be larger than current loaded code"));
++    }
++    else
++        p_FmPcd->p_FmPcdPrs->currLabel = 0;
++
++    if (p_SwPrs->size > FM_PCD_SW_PRS_SIZE - FM_PCD_PRS_SW_TAIL_SIZE - p_SwPrs->base*2)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_SwPrs->size may not be larger than MAX_SW_PRS_CODE_SIZE"));
++
++    if (p_FmPcd->p_FmPcdPrs->currLabel + p_SwPrs->numOfLabels > FM_PCD_PRS_NUM_OF_LABELS)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceeded number of labels allowed "));
++
++    p_TmpCode = (uint32_t *)XX_MallocSmart(ROUND_UP(p_SwPrs->size,4), 0, sizeof(uint32_t));
++    if (!p_TmpCode)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Tmp Sw-Parser code allocation FAILED"));
++    memset((uint8_t *)p_TmpCode, 0, ROUND_UP(p_SwPrs->size,4));
++    memcpy((uint8_t *)p_TmpCode, p_SwPrs->p_Code, p_SwPrs->size);
++
++    /* save sw parser labels */
++    memcpy(&p_FmPcd->p_FmPcdPrs->labelsTable[p_FmPcd->p_FmPcdPrs->currLabel],
++           p_SwPrs->labelsTable,
++           p_SwPrs->numOfLabels*sizeof(t_FmPcdPrsLabelParams));
++    p_FmPcd->p_FmPcdPrs->currLabel += p_SwPrs->numOfLabels;
++
++    /* load sw parser code */
++    p_LoadTarget = p_FmPcd->p_FmPcdPrs->p_SwPrsCode + p_SwPrs->base*2/4;
++
++    for(i=0; i<DIV_CEIL(p_SwPrs->size, 4); i++)
++        WRITE_UINT32(p_LoadTarget[i], GET_UINT32(p_TmpCode[i]));
++
++    p_FmPcd->p_FmPcdPrs->p_CurrSwPrs =
++        p_FmPcd->p_FmPcdPrs->p_SwPrsCode + p_SwPrs->base*2/4 + ROUND_UP(p_SwPrs->size,4);
++
++    /* copy data parameters */
++    for (i=0;i<FM_PCD_PRS_NUM_OF_HDRS;i++)
++        WRITE_UINT32(*(p_FmPcd->p_FmPcdPrs->p_SwPrsCode+PRS_SW_DATA/4+i), p_SwPrs->swPrsDataParams[i]);
++
++    /* Clear last 4 bytes */
++    WRITE_UINT32(*(p_FmPcd->p_FmPcdPrs->p_SwPrsCode+(PRS_SW_DATA-FM_PCD_PRS_SW_TAIL_SIZE)/4), 0);
++
++    XX_FreeSmart(p_TmpCode);
++
++    return E_OK;
++}
++
++t_Error FM_PCD_ConfigPrsMaxCycleLimit(t_Handle h_FmPcd,uint16_t value)
++{
++    t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
++
++    if(p_FmPcd->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigPrsMaxCycleLimit - guest mode!"));
++
++    p_FmPcd->p_FmPcdDriverParam->prsMaxParseCycleLimit = value;
++
++    return E_OK;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.h
+@@ -0,0 +1,316 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_prs.h
++
++ @Description   FM Parser private header
++ *//***************************************************************************/
++#ifndef __FM_PRS_H
++#define __FM_PRS_H
++
++#include "std_ext.h"
++
++/***********************************************************************/
++/*          SW parser IP_FRAG patch                                    */
++/***********************************************************************/
++
++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++#define SW_PRS_UDP_LITE_PATCH   \
++{\
++        0x31,0x52,0x00,0xDA,0xFC,0x00,0x00,0x00,0x00,0x00, \
++        0x00,0x00,0x50,0x2C,0x40,0x00,0x31,0x92,0x50,0x2C, \
++        0x00,0x88,0x18,0x2F,0x00,0x01,0x1B,0xFE,0x18,0x71, \
++        0x02,0x1F,0x00,0x08,0x00,0x83,0x02,0x1F,0x00,0x20, \
++        0x28,0x1B,0x00,0x05,0x29,0x1F,0x30,0xD0,0x60,0x4F, \
++        0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F,0x00,0x52, \
++        0x00,0x01,0x07,0x01,0x60,0x3B,0x00,0x00,0x30,0xD0, \
++        0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \
++        0x40,0x4C,0x00,0x00,0x02,0x8F,0x00,0x00,0x30,0xF2, \
++        0x00,0x06,0x18,0x5D,0x00,0x00,0x9F,0xFF,0x30,0xF2, \
++        0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0,0x00,0x52, \
++        0x00,0x08,0x28,0x1A,0x60,0x37,0x00,0x00,0x30,0xF2, \
++        0x18,0x5D,0x06,0x00,0x29,0x1E,0x30,0xF2,0x2F,0x0E, \
++        0x30,0x72,0x00,0x00,0x9B,0x8F,0x00,0x06,0x2F,0x0E, \
++        0x32,0xF1,0x32,0xB0,0x00,0x4F,0x00,0x57,0x00,0x28, \
++        0x00,0x00,0x97,0x9E,0x00,0x4E,0x30,0x72,0x00,0x06, \
++        0x2F,0x0E,0x32,0xC1,0x32,0xF0,0x00,0x4A,0x00,0x80, \
++        0x00,0x02,0x00,0x00,0x97,0x9E,0x40,0x7E,0x00,0x08, \
++        0x08,0x16,0x00,0x54,0x00,0x01,0x1B,0xFE,0x00,0x00, \
++        0x9F,0x9E,0x40,0xB3,0x00,0x00,0x02,0x1F,0x00,0x08, \
++        0x28,0x1B,0x30,0x73,0x29,0x1F,0x30,0xD0,0x60,0x9F, \
++        0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F,0x00,0x52, \
++        0x00,0x01,0x07,0x01,0x60,0x8B,0x00,0x00,0x30,0xD0, \
++        0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \
++        0x40,0x9C,0x00,0x00,0x02,0x8F,0x00,0x00,0x30,0xF2, \
++        0x00,0x06,0x18,0xAD,0x00,0x00,0x9F,0xFF,0x30,0xF2, \
++        0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0,0x00,0x52, \
++        0x00,0x08,0x28,0x1A,0x60,0x87,0x00,0x00,0x30,0xF2, \
++        0x18,0xAD,0x06,0x00,0x29,0x1E,0x30,0xF2,0x50,0xB3, \
++        0xFF,0xFF,0x18,0xB8,0x08,0x16,0x00,0x54,0x00,0x01, \
++        0x1B,0xFE,0x18,0xC5,0x32,0xF1,0x28,0x5D,0x32,0xF1, \
++        0x00,0x55,0x00,0x08,0x28,0x5F,0x00,0x00,0x8F,0x9F, \
++        0x29,0x33,0x08,0x16,0x00,0x49,0x00,0x01,0x1B,0xFF, \
++        0x00,0x01,0x1B,0xFF    \
++}
++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
++
++#if (DPAA_VERSION == 10)
++/* Version: 106.1.9 */
++#define SW_PRS_OFFLOAD_PATCH                           \
++{                                                      \
++    0x31,0x52,0x00,0xDA,0x0A,0x00,0x00,0x00,0x00,0x00, \
++    0x00,0x00,0x43,0x0A,0x00,0x00,0x00,0x01,0x1B,0xFE, \
++    0x00,0x00,0x99,0x00,0x53,0x13,0x00,0x00,0x00,0x00, \
++    0x9F,0x98,0x53,0x13,0x00,0x00,0x1B,0x23,0x33,0xF1, \
++    0x00,0xF9,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \
++    0x28,0x7F,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0x01, \
++    0x32,0xC1,0x32,0xF0,0x00,0x4A,0x00,0x80,0x1F,0xFF, \
++    0x00,0x01,0x1B,0xFE,0x31,0x52,0x00,0xDA,0x06,0x00, \
++    0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x2F,0x00,0x00, \
++    0x00,0x01,0x1B,0xFE,0x31,0x52,0x00,0xDA,0x00,0x40, \
++    0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x95,0x00,0x00, \
++    0x00,0x00,0x9B,0x8F,0x2F,0x0F,0x32,0xC1,0x00,0x55, \
++    0x00,0x28,0x28,0x43,0x30,0x7E,0x43,0x45,0x00,0x00, \
++    0x30,0x7E,0x43,0x45,0x00,0x3C,0x1B,0x5D,0x32,0x11, \
++    0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00,0x83,0x8F, \
++    0x2F,0x0F,0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F, \
++    0x00,0x55,0x00,0x01,0x00,0x81,0x32,0x11,0x00,0x00, \
++    0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04,0x00,0x4D, \
++    0x28,0x43,0x06,0x00,0x1B,0x3E,0x30,0x7E,0x53,0x79, \
++    0x00,0x2B,0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x81, \
++    0x00,0x00,0x87,0x8F,0x28,0x23,0x06,0x00,0x32,0x11, \
++    0x32,0xC0,0x00,0x4F,0x00,0x55,0x00,0x01,0x00,0x81, \
++    0x32,0x11,0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01, \
++    0x01,0x04,0x00,0x4D,0x28,0x43,0x06,0x00,0x00,0x01, \
++    0x1B,0xFE,0x00,0x00,0x9B,0x8E,0x53,0x90,0x00,0x00, \
++    0x06,0x29,0x00,0x00,0x83,0x8F,0x28,0x23,0x06,0x00, \
++    0x06,0x29,0x32,0xC1,0x00,0x55,0x00,0x28,0x00,0x00, \
++    0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04,0x00,0x4D, \
++    0x28,0x43,0x06,0x00,0x00,0x01,0x1B,0xFE,0x32,0xC1, \
++    0x00,0x55,0x00,0x28,0x28,0x43,0x1B,0xCF,0x00,0x00, \
++    0x9B,0x8F,0x2F,0x0F,0x32,0xC1,0x00,0x55,0x00,0x28, \
++    0x28,0x43,0x30,0x7E,0x43,0xBF,0x00,0x2C,0x32,0x11, \
++    0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00,0x87,0x8F, \
++    0x28,0x23,0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F, \
++    0x00,0x81,0x00,0x00,0x83,0x8F,0x2F,0x0F,0x06,0x00, \
++    0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x55,0x00,0x01, \
++    0x00,0x81,0x32,0x11,0x00,0x00,0x83,0x8E,0x00,0x50, \
++    0x00,0x01,0x01,0x04,0x00,0x4D,0x28,0x43,0x06,0x00, \
++    0x1B,0x9C,0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00, \
++    0x00,0x00,0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02, \
++    0x00,0x00,0x00,0x01,0x32,0xC1,0x32,0xF0,0x00,0x4A, \
++    0x00,0x80,0x1F,0xFF,0x00,0x01,0x1B,0xFE,           \
++}
++
++#else
++#define SW_PRS_OFFLOAD_PATCH                           \
++{                                                      \
++    0x31,0x52,0x00,0xDA,0x0E,0x4F,0x00,0x00,0x00,0x00, \
++    0x00,0x00,0x51,0x16,0x08,0x4B,0x31,0x53,0x00,0xFB, \
++    0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0x2B, \
++    0x33,0xF1,0x00,0xFB,0x00,0xDF,0x00,0x00,0x00,0x00, \
++    0x00,0x00,0x28,0x7F,0x31,0x52,0x00,0xDA,0x0A,0x00, \
++    0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x20,0x00,0x00, \
++    0x00,0x01,0x1B,0xFE,0x00,0x00,0x99,0x00,0x51,0x29, \
++    0x00,0x00,0x00,0x00,0x9F,0x98,0x51,0x29,0x00,0x00, \
++    0x19,0x44,0x09,0x5F,0x00,0x20,0x00,0x00,0x09,0x4F, \
++    0x00,0x20,0x00,0x00,0x34,0xB7,0x00,0xF9,0x00,0x00, \
++    0x01,0x00,0x00,0x00,0x00,0x00,0x2B,0x97,0x31,0xB3, \
++    0x29,0x8F,0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00, \
++    0x00,0x00,0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02, \
++    0x00,0x00,0x00,0x01,0x1B,0xFE,0x00,0x01,0x1B,0xFE, \
++    0x31,0x52,0x00,0xDA,0xFC,0x00,0x00,0x00,0x00,0x00, \
++    0x00,0x00,0x51,0x52,0x40,0x00,0x31,0x92,0x51,0x52, \
++    0x00,0x88,0x19,0x55,0x08,0x05,0x00,0x00,0x19,0x99, \
++    0x02,0x1F,0x00,0x08,0x00,0x83,0x02,0x1F,0x00,0x20, \
++    0x28,0x1B,0x00,0x05,0x29,0x1F,0x30,0xD0,0x61,0x75, \
++    0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F,0x00,0x52, \
++    0x00,0x01,0x07,0x01,0x61,0x61,0x00,0x00,0x30,0xD0, \
++    0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \
++    0x41,0x72,0x00,0x00,0x02,0x8F,0x00,0x00,0x30,0xF2, \
++    0x00,0x06,0x19,0x83,0x00,0x00,0x9F,0xFF,0x30,0xF2, \
++    0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0,0x00,0x52, \
++    0x00,0x08,0x28,0x1A,0x61,0x5D,0x00,0x00,0x30,0xF2, \
++    0x19,0x83,0x06,0x00,0x29,0x1E,0x30,0xF2,0x29,0x0E, \
++    0x30,0x72,0x00,0x00,0x9B,0x8F,0x00,0x06,0x29,0x0E, \
++    0x32,0xF1,0x32,0xB0,0x00,0x4F,0x00,0x57,0x00,0x28, \
++    0x00,0x00,0x97,0x9E,0x00,0x4E,0x30,0x72,0x00,0x06, \
++    0x29,0x0E,0x08,0x05,0x00,0x01,0x31,0x52,0x00,0xDA, \
++    0x0E,0x4F,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0xAF, \
++    0x04,0x4B,0x31,0x53,0x00,0xFB,0xFF,0xF0,0x00,0x00, \
++    0x00,0x00,0x00,0x00,0x29,0x2B,0x33,0xF1,0x00,0xFB, \
++    0x00,0xDF,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7F, \
++    0x31,0x52,0x00,0xDA,0x06,0x00,0x00,0x00,0x00,0x00, \
++    0x00,0x00,0x41,0xB9,0x00,0x00,0x00,0x01,0x1B,0xFE, \
++    0x31,0x52,0x00,0xDA,0x00,0x40,0x00,0x00,0x00,0x00, \
++    0x00,0x00,0x42,0x06,0x00,0x00,0x00,0x00,0x9B,0x8F, \
++    0x28,0x01,0x32,0xC1,0x00,0x55,0x00,0x28,0x28,0x43, \
++    0x30,0x00,0x41,0xEB,0x00,0x2C,0x32,0x11,0x32,0xC0, \
++    0x00,0x4F,0x00,0x81,0x00,0x00,0x87,0x8F,0x28,0x23, \
++    0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x81, \
++    0x00,0x00,0x83,0x8F,0x28,0x01,0x06,0x00,0x32,0x11, \
++    0x32,0xC0,0x00,0x4F,0x00,0x55,0x00,0x01,0x00,0x81, \
++    0x32,0x11,0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01, \
++    0x01,0x04,0x00,0x4D,0x28,0x43,0x06,0x00,0x19,0xC8, \
++    0x09,0x5F,0x00,0x20,0x00,0x00,0x09,0x4F,0x00,0x20, \
++    0x00,0x00,0x34,0xB7,0x00,0xF9,0x00,0x00,0x01,0x00, \
++    0x00,0x00,0x00,0x00,0x2B,0x97,0x31,0xB3,0x29,0x8F, \
++    0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00,0x00,0x00, \
++    0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02,0x00,0x00, \
++    0x00,0x01,0x1B,0xFE,0x30,0x50,0x52,0x0B,0x00,0x00, \
++    0x00,0x01,0x1B,0xFE,0x32,0xF1,0x32,0xC0,0x00,0x4F, \
++    0x00,0x81,0x00,0x02,0x00,0x00,0x97,0x9E,0x42,0x18, \
++    0x00,0x08,0x08,0x16,0x00,0x54,0x00,0x01,0x1B,0xFE, \
++    0x00,0x00,0x9F,0x9E,0x42,0x4D,0x00,0x00,0x02,0x1F, \
++    0x00,0x08,0x28,0x1B,0x30,0x73,0x29,0x1F,0x30,0xD0, \
++    0x62,0x39,0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F, \
++    0x00,0x52,0x00,0x01,0x07,0x01,0x62,0x25,0x00,0x00, \
++    0x30,0xD0,0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00, \
++    0x00,0x00,0x42,0x36,0x00,0x00,0x02,0x8F,0x00,0x00, \
++    0x30,0xF2,0x00,0x06,0x1A,0x47,0x00,0x00,0x9F,0xFF, \
++    0x30,0xF2,0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0, \
++    0x00,0x52,0x00,0x08,0x28,0x1A,0x62,0x21,0x00,0x00, \
++    0x30,0xF2,0x1A,0x47,0x06,0x00,0x29,0x1E,0x30,0xF2, \
++    0x52,0x4D,0xFF,0xFF,0x1A,0x52,0x08,0x16,0x00,0x54, \
++    0x00,0x01,0x1B,0xFE,0x1A,0x5F,0x32,0xF1,0x28,0x5D, \
++    0x32,0xF1,0x00,0x55,0x00,0x08,0x28,0x5F,0x00,0x00, \
++    0x8F,0x9F,0x29,0x33,0x08,0x16,0x00,0x49,0x00,0x01, \
++    0x1B,0xFF,0x00,0x01,0x1B,0xFF,0x31,0x52,0x00,0xDA, \
++    0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x6D, \
++    0x40,0x00,0x31,0x92,0x52,0x6D,0x00,0x88,0x1A,0x70, \
++    0x08,0x05,0x00,0x00,0x1A,0xB4,0x02,0x1F,0x00,0x08, \
++    0x00,0x83,0x02,0x1F,0x00,0x20,0x28,0x1B,0x00,0x05, \
++    0x29,0x1F,0x30,0xD0,0x62,0x90,0x00,0x07,0x00,0x05, \
++    0x00,0x00,0xC3,0x8F,0x00,0x52,0x00,0x01,0x07,0x01, \
++    0x62,0x7C,0x00,0x00,0x30,0xD0,0x00,0xDA,0x00,0x01, \
++    0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x8D,0x00,0x00, \
++    0x02,0x8F,0x00,0x00,0x30,0xF2,0x00,0x06,0x1A,0x9E, \
++    0x00,0x00,0x9F,0xFF,0x30,0xF2,0x00,0x06,0x29,0x1E, \
++    0x07,0x08,0x30,0xD0,0x00,0x52,0x00,0x08,0x28,0x1A, \
++    0x62,0x78,0x00,0x00,0x30,0xF2,0x1A,0x9E,0x06,0x00, \
++    0x29,0x1E,0x30,0xF2,0x29,0x0E,0x30,0x72,0x00,0x00, \
++    0x9B,0x8F,0x00,0x06,0x29,0x0E,0x32,0xF1,0x32,0xB0, \
++    0x00,0x4F,0x00,0x57,0x00,0x28,0x00,0x00,0x97,0x9E, \
++    0x00,0x4E,0x30,0x72,0x00,0x06,0x29,0x0E,0x08,0x05, \
++    0x00,0x01,0x31,0x52,0x00,0xDA,0x0E,0x4F,0x00,0x00, \
++    0x00,0x00,0x00,0x00,0x52,0xCA,0x04,0x4B,0x31,0x53, \
++    0x00,0xFB,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00, \
++    0x29,0x2B,0x33,0xF1,0x00,0xFB,0x00,0xDF,0x00,0x00, \
++    0x00,0x00,0x00,0x00,0x28,0x7F,0x31,0x52,0x00,0xDA, \
++    0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0xD4, \
++    0x00,0x00,0x00,0x01,0x1B,0xFE,0x31,0x52,0x00,0xDA, \
++    0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x37, \
++    0x00,0x00,0x00,0x00,0x9B,0x8F,0x28,0x01,0x32,0xC1, \
++    0x00,0x55,0x00,0x28,0x28,0x43,0x30,0x00,0x42,0xEA, \
++    0x00,0x00,0x30,0x00,0x42,0xEA,0x00,0x3C,0x1B,0x02, \
++    0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00, \
++    0x83,0x8F,0x28,0x01,0x06,0x00,0x32,0x11,0x32,0xC0, \
++    0x00,0x4F,0x00,0x55,0x00,0x01,0x00,0x81,0x32,0x11, \
++    0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04, \
++    0x00,0x4D,0x28,0x43,0x06,0x00,0x1A,0xE3,0x30,0x00, \
++    0x43,0x20,0x00,0x2B,0x00,0x00,0x9B,0x8E,0x43,0x0E, \
++    0x00,0x00,0x32,0xC1,0x00,0x55,0x00,0x28,0x28,0x43, \
++    0x1B,0x1F,0x06,0x29,0x00,0x00,0x83,0x8F,0x28,0x23, \
++    0x06,0x00,0x06,0x29,0x32,0xC1,0x00,0x55,0x00,0x28, \
++    0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04, \
++    0x00,0x4D,0x28,0x43,0x06,0x00,0x1B,0x37,0x32,0x11, \
++    0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00,0x87,0x8F, \
++    0x28,0x23,0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F, \
++    0x00,0x55,0x00,0x01,0x00,0x81,0x32,0x11,0x00,0x00, \
++    0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04,0x00,0x4D, \
++    0x28,0x43,0x06,0x00,0x30,0x50,0x53,0x3C,0x00,0x00, \
++    0x00,0x01,0x1B,0xFE,0x32,0xF1,0x32,0xC0,0x00,0x4F, \
++    0x00,0x81,0x00,0x02,0x00,0x00,0x97,0x9E,0x43,0x49, \
++    0x00,0x08,0x08,0x16,0x00,0x54,0x00,0x01,0x1B,0xFE, \
++    0x00,0x00,0x9F,0x9E,0x43,0x7E,0x00,0x00,0x02,0x1F, \
++    0x00,0x08,0x28,0x1B,0x30,0x73,0x29,0x1F,0x30,0xD0, \
++    0x63,0x6A,0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F, \
++    0x00,0x52,0x00,0x01,0x07,0x01,0x63,0x56,0x00,0x00, \
++    0x30,0xD0,0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00, \
++    0x00,0x00,0x43,0x67,0x00,0x00,0x02,0x8F,0x00,0x00, \
++    0x30,0xF2,0x00,0x06,0x1B,0x78,0x00,0x00,0x9F,0xFF, \
++    0x30,0xF2,0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0, \
++    0x00,0x52,0x00,0x08,0x28,0x1A,0x63,0x52,0x00,0x00, \
++    0x30,0xF2,0x1B,0x78,0x06,0x00,0x29,0x1E,0x30,0xF2, \
++    0x53,0x7E,0xFF,0xFF,0x1B,0x83,0x08,0x16,0x00,0x54, \
++    0x00,0x01,0x1B,0xFE,0x1B,0x90,0x32,0xF1,0x28,0x5D, \
++    0x32,0xF1,0x00,0x55,0x00,0x08,0x28,0x5F,0x00,0x00, \
++    0x8F,0x9F,0x29,0x33,0x08,0x16,0x00,0x49,0x00,0x01, \
++    0x1B,0xFF,0x00,0x01,0x1B,0xFF,0x08,0x07,0x00,0x02, \
++    0x00,0x00,0x8D,0x80,0x53,0x9C,0x00,0x01,0x30,0x71, \
++    0x00,0x55,0x00,0x01,0x28,0x0F,0x00,0x00,0x8D,0x00, \
++    0x53,0xA4,0x00,0x01,0x30,0x71,0x00,0x55,0x00,0x01, \
++    0x28,0x0F,0x00,0x00,0x83,0x8E,0x53,0xB9,0x00,0x00, \
++    0x00,0x00,0x86,0x08,0x30,0x71,0x00,0x7B,0x03,0xB9, \
++    0x33,0xB4,0x00,0xDA,0xFF,0xFF,0x00,0x0F,0x00,0x00, \
++    0x00,0x00,0x00,0x00,0x86,0x09,0x01,0x03,0x00,0x7D, \
++    0x03,0xB9,0x1B,0xC8,0x33,0xD1,0x00,0xF9,0x00,0x10, \
++    0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7B,0x09,0x5F, \
++    0x00,0x1A,0x00,0x00,0x09,0x4F,0x00,0x1A,0x00,0x00, \
++    0x00,0x01,0x1B,0xFF,0x00,0x00,0x8C,0x00,0x53,0xF0, \
++    0x00,0x01,0x34,0xF5,0x00,0xFB,0xFF,0xFF,0x00,0x7F, \
++    0x00,0x00,0x00,0x00,0x2A,0x9F,0x00,0x00,0x93,0x8F, \
++    0x28,0x49,0x00,0x00,0x97,0x8F,0x28,0x4B,0x34,0x61, \
++    0x28,0x4D,0x34,0x71,0x28,0x4F,0x34,0xB7,0x00,0xF9, \
++    0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x2B,0x97, \
++    0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00,0x00,0x00, \
++    0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02,0x00,0x00, \
++    0x00,0x01,0x1B,0xFF,0x00,0x01,0x1B,0xFF, \
++}
++#endif /* (DPAA_VERSION == 10) */
++
++/****************************/
++/* Parser defines           */
++/****************************/
++#define FM_PCD_PRS_SW_TAIL_SIZE             4                   /**< Number of bytes that must be cleared at
++                                                                             the end of the SW parser area */
++
++/* masks */
++#define PRS_ERR_CAP                         0x80000000
++#define PRS_ERR_TYPE_DOUBLE                 0x40000000
++#define PRS_ERR_SINGLE_ECC_CNT_MASK         0x00FF0000
++#define PRS_ERR_ADDR_MASK                   0x000001FF
++
++/* others */
++#define PRS_MAX_CYCLE_LIMIT                 8191
++#define PRS_SW_DATA                         0x00000800
++#define PRS_REGS_OFFSET                     0x00000840
++
++#define GET_FM_PCD_PRS_PORT_ID(prsPortId,hardwarePortId) \
++    prsPortId = (uint8_t)(hardwarePortId & 0x0f)
++
++#define GET_FM_PCD_INDEX_FLAG(bitMask, prsPortId)    \
++    bitMask = 0x80000000>>prsPortId
++
++#endif /* __FM_PRS_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.c
+@@ -0,0 +1,984 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_replic.c
++
++ @Description   FM frame replicator
++*//***************************************************************************/
++#include "std_ext.h"
++#include "error_ext.h"
++#include "string_ext.h"
++#include "debug_ext.h"
++#include "fm_pcd_ext.h"
++#include "fm_muram_ext.h"
++#include "fm_common.h"
++#include "fm_hc.h"
++#include "fm_replic.h"
++#include "fm_cc.h"
++#include "list_ext.h"
++
++
++/****************************************/
++/*       static functions               */
++/****************************************/
++static uint8_t  GetMemberPosition(t_FmPcdFrmReplicGroup *p_ReplicGroup,
++                                  uint32_t              memberIndex,
++                                  bool                  isAddOperation)
++{
++    uint8_t     memberPosition;
++    uint32_t    lastMemberIndex;
++
++    ASSERT_COND(p_ReplicGroup);
++
++    /* the last member index is different between add and remove operation -
++    in case of remove - this is exactly the last member index
++    in case of add - this is the last member index + 1 - e.g.
++    if we have 4 members, the index of the actual last member is 3(because the
++    index starts from 0) therefore in order to add a new member as the last
++    member we shall use memberIndex = 4 and not 3
++    */
++    if (isAddOperation)
++        lastMemberIndex = p_ReplicGroup->numOfEntries;
++    else
++        lastMemberIndex = p_ReplicGroup->numOfEntries-1;
++
++    /* last */
++    if (memberIndex == lastMemberIndex)
++        memberPosition = FRM_REPLIC_LAST_MEMBER_INDEX;
++    else
++    {
++        /* first */
++        if (memberIndex == 0)
++            memberPosition = FRM_REPLIC_FIRST_MEMBER_INDEX;
++        else
++        {
++            /* middle */
++            ASSERT_COND(memberIndex < lastMemberIndex);
++            memberPosition = FRM_REPLIC_MIDDLE_MEMBER_INDEX;
++        }
++    }
++    return memberPosition;
++}
++
++static t_Error MemberCheckParams(t_Handle                  h_FmPcd,
++                                 t_FmPcdCcNextEngineParams *p_MemberParams)
++{
++    t_Error         err;
++
++
++    if ((p_MemberParams->nextEngine != e_FM_PCD_DONE) &&
++        (p_MemberParams->nextEngine != e_FM_PCD_KG)   &&
++        (p_MemberParams->nextEngine != e_FM_PCD_PLCR))
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Next engine of a member should be MatchTable(cc) or Done or Policer"));
++
++    /* check the regular parameters of the next engine */
++    err = ValidateNextEngineParams(h_FmPcd, p_MemberParams, e_FM_PCD_CC_STATS_MODE_NONE);
++    if (err)
++        RETURN_ERROR(MAJOR, err, ("member next engine parameters"));
++
++    return E_OK;
++}
++
++static t_Error CheckParams(t_Handle                     h_FmPcd,
++                           t_FmPcdFrmReplicGroupParams *p_ReplicGroupParam)
++{
++    int             i;
++    t_Error         err;
++
++    /* check that max num of entries is at least 2 */
++    if (!IN_RANGE(2, p_ReplicGroupParam->maxNumOfEntries, FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES))
++        RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ("maxNumOfEntries in the frame replicator parameters should be 2-%d",FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES));
++
++    /* check that number of entries is greater than zero */
++    if (!p_ReplicGroupParam->numOfEntries)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOFEntries in the frame replicator group should be greater than zero"));
++
++    /* check that max num of entries is equal or greater than number of entries */
++    if (p_ReplicGroupParam->maxNumOfEntries < p_ReplicGroupParam->numOfEntries)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("maxNumOfEntries should be equal or greater than numOfEntries"));
++
++    for (i=0; i<p_ReplicGroupParam->numOfEntries; i++)
++    {
++        err = MemberCheckParams(h_FmPcd, &p_ReplicGroupParam->nextEngineParams[i]);
++        if (err)
++            RETURN_ERROR(MAJOR, err, ("member check parameters"));
++    }
++    return E_OK;
++}
++
++static t_FmPcdFrmReplicMember *GetAvailableMember(t_FmPcdFrmReplicGroup *p_ReplicGroup)
++{
++    t_FmPcdFrmReplicMember  *p_ReplicMember = NULL;
++    t_List                  *p_Next;
++
++    if (!LIST_IsEmpty(&p_ReplicGroup->availableMembersList))
++    {
++        p_Next = LIST_FIRST(&p_ReplicGroup->availableMembersList);
++        p_ReplicMember = LIST_OBJECT(p_Next, t_FmPcdFrmReplicMember, node);
++        ASSERT_COND(p_ReplicMember);
++        LIST_DelAndInit(p_Next);
++    }
++    return p_ReplicMember;
++}
++
++static void PutAvailableMember(t_FmPcdFrmReplicGroup    *p_ReplicGroup,
++                               t_FmPcdFrmReplicMember   *p_ReplicMember)
++{
++    LIST_AddToTail(&p_ReplicMember->node, &p_ReplicGroup->availableMembersList);
++}
++
++static void AddMemberToList(t_FmPcdFrmReplicGroup   *p_ReplicGroup,
++                            t_FmPcdFrmReplicMember  *p_CurrentMember,
++                            t_List                  *p_ListHead)
++{
++    LIST_Add(&p_CurrentMember->node, p_ListHead);
++
++    p_ReplicGroup->numOfEntries++;
++}
++
++static void RemoveMemberFromList(t_FmPcdFrmReplicGroup  *p_ReplicGroup,
++                                 t_FmPcdFrmReplicMember *p_CurrentMember)
++{
++    ASSERT_COND(p_ReplicGroup->numOfEntries);
++    LIST_DelAndInit(&p_CurrentMember->node);
++    p_ReplicGroup->numOfEntries--;
++}
++
++static void LinkSourceToMember(t_FmPcdFrmReplicGroup    *p_ReplicGroup,
++                               t_AdOfTypeContLookup     *p_SourceTd,
++                               t_FmPcdFrmReplicMember   *p_ReplicMember)
++{
++    t_FmPcd             *p_FmPcd;
++
++    ASSERT_COND(p_SourceTd);
++    ASSERT_COND(p_ReplicMember);
++    ASSERT_COND(p_ReplicGroup);
++    ASSERT_COND(p_ReplicGroup->h_FmPcd);
++
++    /* Link the first member in the group to the source TD */
++    p_FmPcd = p_ReplicGroup->h_FmPcd;
++
++    WRITE_UINT32(p_SourceTd->matchTblPtr,
++        (uint32_t)(XX_VirtToPhys(p_ReplicMember->p_MemberAd) -
++                        p_FmPcd->physicalMuramBase));
++}
++
++static void LinkMemberToMember(t_FmPcdFrmReplicGroup    *p_ReplicGroup,
++                               t_FmPcdFrmReplicMember   *p_CurrentMember,
++                               t_FmPcdFrmReplicMember   *p_NextMember)
++{
++    t_AdOfTypeResult    *p_CurrReplicAd = (t_AdOfTypeResult*)p_CurrentMember->p_MemberAd;
++    t_AdOfTypeResult    *p_NextReplicAd = NULL;
++    t_FmPcd             *p_FmPcd;
++    uint32_t            offset = 0;
++
++    /* Check if the next member exists or it's NULL (- means that this is the last member) */
++    if (p_NextMember)
++    {
++        p_NextReplicAd = (t_AdOfTypeResult*)p_NextMember->p_MemberAd;
++        p_FmPcd = p_ReplicGroup->h_FmPcd;
++        offset = (XX_VirtToPhys(p_NextReplicAd) - (p_FmPcd->physicalMuramBase));
++        offset = ((offset>>NEXT_FRM_REPLIC_ADDR_SHIFT)<< NEXT_FRM_REPLIC_MEMBER_INDEX_SHIFT);
++    }
++
++    /* link the current AD to point to the AD of the next member */
++    WRITE_UINT32(p_CurrReplicAd->res, offset);
++}
++
++static t_Error ModifyDescriptor(t_FmPcdFrmReplicGroup   *p_ReplicGroup,
++                                void                    *p_OldDescriptor,
++                                void                    *p_NewDescriptor)
++{
++    t_Handle            h_Hc;
++    t_Error             err;
++    t_FmPcd             *p_FmPcd;
++
++    ASSERT_COND(p_ReplicGroup);
++    ASSERT_COND(p_ReplicGroup->h_FmPcd);
++    ASSERT_COND(p_OldDescriptor);
++    ASSERT_COND(p_NewDescriptor);
++
++    p_FmPcd = p_ReplicGroup->h_FmPcd;
++    h_Hc = FmPcdGetHcHandle(p_FmPcd);
++    if (!h_Hc)
++        RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("Host command"));
++
++    err = FmHcPcdCcDoDynamicChange(h_Hc,
++                                   (uint32_t)(XX_VirtToPhys(p_OldDescriptor) - p_FmPcd->physicalMuramBase),
++                                   (uint32_t)(XX_VirtToPhys(p_NewDescriptor) - p_FmPcd->physicalMuramBase));
++    if (err)
++        RETURN_ERROR(MAJOR, err, ("Dynamic change host command"));
++
++    return E_OK;
++}
++
++static void FillReplicAdOfTypeResult(void *p_ReplicAd, bool last)
++{
++    t_AdOfTypeResult    *p_CurrReplicAd = (t_AdOfTypeResult*)p_ReplicAd;
++    uint32_t            tmp;
++
++    tmp = GET_UINT32(p_CurrReplicAd->plcrProfile);
++    if (last)
++        /* clear the NL bit in case it's the last member in the group*/
++        WRITE_UINT32(p_CurrReplicAd->plcrProfile,(tmp & ~FRM_REPLIC_NL_BIT));
++    else
++        /* set the NL bit in case it's not the last member in the group */
++        WRITE_UINT32(p_CurrReplicAd->plcrProfile, (tmp |FRM_REPLIC_NL_BIT));
++
++    /* set FR bit in the action descriptor */
++    tmp = GET_UINT32(p_CurrReplicAd->nia);
++    WRITE_UINT32(p_CurrReplicAd->nia,
++        (tmp | FRM_REPLIC_FR_BIT | FM_PCD_AD_RESULT_EXTENDED_MODE ));
++}
++
++static void BuildSourceTd(void *p_Ad)
++{
++    t_AdOfTypeContLookup    *p_SourceTd;
++
++    ASSERT_COND(p_Ad);
++
++    p_SourceTd = (t_AdOfTypeContLookup *)p_Ad;
++
++    IOMemSet32((uint8_t*)p_SourceTd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++    /* initialize the source table descriptor */
++    WRITE_UINT32(p_SourceTd->ccAdBase,     FM_PCD_AD_CONT_LOOKUP_TYPE);
++    WRITE_UINT32(p_SourceTd->pcAndOffsets, FRM_REPLIC_SOURCE_TD_OPCODE);
++}
++
++static t_Error BuildShadowAndModifyDescriptor(t_FmPcdFrmReplicGroup   *p_ReplicGroup,
++                                              t_FmPcdFrmReplicMember  *p_NextMember,
++                                              t_FmPcdFrmReplicMember  *p_CurrentMember,
++                                              bool                    sourceDescriptor,
++                                              bool                    last)
++{
++    t_FmPcd                 *p_FmPcd;
++    t_FmPcdFrmReplicMember  shadowMember;
++    t_Error                 err;
++
++    ASSERT_COND(p_ReplicGroup);
++    ASSERT_COND(p_ReplicGroup->h_FmPcd);
++
++    p_FmPcd = p_ReplicGroup->h_FmPcd;
++    ASSERT_COND(p_FmPcd->p_CcShadow);
++
++    if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
++        return ERROR_CODE(E_BUSY);
++
++    if (sourceDescriptor)
++    {
++        BuildSourceTd(p_FmPcd->p_CcShadow);
++        LinkSourceToMember(p_ReplicGroup, p_FmPcd->p_CcShadow, p_NextMember);
++
++        /* Modify the source table descriptor according to the prepared shadow descriptor */
++        err = ModifyDescriptor(p_ReplicGroup,
++                               p_ReplicGroup->p_SourceTd,
++                               p_FmPcd->p_CcShadow/* new prepared source td */);
++
++        RELEASE_LOCK(p_FmPcd->shadowLock);
++        if (err)
++            RETURN_ERROR(MAJOR, err, ("Modify source Descriptor in BuildShadowAndModifyDescriptor"));
++
++    }
++    else
++    {
++        IO2IOCpy32(p_FmPcd->p_CcShadow,
++                   p_CurrentMember->p_MemberAd,
++                   FM_PCD_CC_AD_ENTRY_SIZE);
++
++        /* update the last bit in the shadow ad */
++        FillReplicAdOfTypeResult(p_FmPcd->p_CcShadow, last);
++
++        shadowMember.p_MemberAd = p_FmPcd->p_CcShadow;
++
++        /* update the next FR member index */
++        LinkMemberToMember(p_ReplicGroup, &shadowMember, p_NextMember);
++
++        /* Modify the next member according to the prepared shadow descriptor */
++        err = ModifyDescriptor(p_ReplicGroup,
++                               p_CurrentMember->p_MemberAd,
++                               p_FmPcd->p_CcShadow);
++
++        RELEASE_LOCK(p_FmPcd->shadowLock);
++        if (err)
++            RETURN_ERROR(MAJOR, err, ("Modify Descriptor in BuildShadowAndModifyDescriptor"));
++    }
++
++
++    return E_OK;
++}
++
++static t_FmPcdFrmReplicMember* GetMemberByIndex(t_FmPcdFrmReplicGroup   *p_ReplicGroup,
++                                                uint16_t                memberIndex)
++{
++    int                     i=0;
++    t_List                  *p_Pos;
++    t_FmPcdFrmReplicMember  *p_Member = NULL;
++
++    LIST_FOR_EACH(p_Pos, &p_ReplicGroup->membersList)
++    {
++        if (i == memberIndex)
++        {
++            p_Member = LIST_OBJECT(p_Pos, t_FmPcdFrmReplicMember, node);
++            return p_Member;
++        }
++        i++;
++    }
++    return p_Member;
++}
++
++static t_Error AllocMember(t_FmPcdFrmReplicGroup *p_ReplicGroup)
++{
++    t_FmPcdFrmReplicMember  *p_CurrentMember;
++    t_Handle                h_Muram;
++
++    ASSERT_COND(p_ReplicGroup);
++
++    h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd);
++    ASSERT_COND(h_Muram);
++
++    /* Initialize an internal structure of a member to add to the available members list */
++    p_CurrentMember = (t_FmPcdFrmReplicMember *)XX_Malloc(sizeof(t_FmPcdFrmReplicMember));
++    if (!p_CurrentMember)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Frame replicator member"));
++
++    memset(p_CurrentMember, 0 ,sizeof(t_FmPcdFrmReplicMember));
++
++    /* Allocate the member AD */
++    p_CurrentMember->p_MemberAd =
++        (t_AdOfTypeResult*)FM_MURAM_AllocMem(h_Muram,
++                                             FM_PCD_CC_AD_ENTRY_SIZE,
++                                             FM_PCD_CC_AD_TABLE_ALIGN);
++    if (!p_CurrentMember->p_MemberAd)
++    {
++        XX_Free(p_CurrentMember);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("member AD table"));
++    }
++    IOMemSet32((uint8_t*)p_CurrentMember->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++    /* Add the new member to the available members list */
++    LIST_AddToTail(&p_CurrentMember->node, &(p_ReplicGroup->availableMembersList));
++
++    return E_OK;
++}
++
++static t_FmPcdFrmReplicMember* InitMember(t_FmPcdFrmReplicGroup     *p_ReplicGroup,
++                                          t_FmPcdCcNextEngineParams *p_MemberParams,
++                                          bool                      last)
++{
++    t_FmPcdFrmReplicMember  *p_CurrentMember = NULL;
++
++    ASSERT_COND(p_ReplicGroup);
++
++    /* Get an available member from the internal members list */
++    p_CurrentMember = GetAvailableMember(p_ReplicGroup);
++    if (!p_CurrentMember)
++    {
++        REPORT_ERROR(MAJOR, E_NOT_FOUND, ("Available member"));
++        return NULL;
++    }
++    p_CurrentMember->h_Manip = NULL;
++
++    /* clear the Ad of the new member */
++    IOMemSet32((uint8_t*)p_CurrentMember->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++    INIT_LIST(&p_CurrentMember->node);
++
++    /* Initialize the Ad of the member */
++    NextStepAd(p_CurrentMember->p_MemberAd,
++               NULL,
++               p_MemberParams,
++               p_ReplicGroup->h_FmPcd);
++
++    /* save Manip handle (for free needs) */
++    if (p_MemberParams->h_Manip)
++        p_CurrentMember->h_Manip = p_MemberParams->h_Manip;
++
++    /* Initialize the relevant frame replicator fields in the AD */
++    FillReplicAdOfTypeResult(p_CurrentMember->p_MemberAd, last);
++
++    return p_CurrentMember;
++}
++
++static void FreeMember(t_FmPcdFrmReplicGroup    *p_ReplicGroup,
++                       t_FmPcdFrmReplicMember   *p_Member)
++{
++    /* Note: Can't free the member AD just returns the member to the available
++       member list - therefore only memset the AD */
++
++    /* zero the AD */
++    IOMemSet32(p_Member->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
++
++
++    /* return the member to the available members list */
++    PutAvailableMember(p_ReplicGroup, p_Member);
++}
++
++static t_Error RemoveMember(t_FmPcdFrmReplicGroup   *p_ReplicGroup,
++                            uint16_t                memberIndex)
++{
++    t_FmPcd                 *p_FmPcd = NULL;
++    t_FmPcdFrmReplicMember  *p_CurrentMember = NULL, *p_PreviousMember = NULL, *p_NextMember = NULL;
++    t_Error                 err;
++    uint8_t                 memberPosition;
++
++    p_FmPcd         = p_ReplicGroup->h_FmPcd;
++    ASSERT_COND(p_FmPcd);
++    UNUSED(p_FmPcd);
++
++    p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex);
++    ASSERT_COND(p_CurrentMember);
++
++    /* determine the member position in the group */
++    memberPosition = GetMemberPosition(p_ReplicGroup,
++                                       memberIndex,
++                                       FALSE/*remove operation*/);
++
++    switch (memberPosition)
++    {
++        case FRM_REPLIC_FIRST_MEMBER_INDEX:
++            p_NextMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex+1));
++            ASSERT_COND(p_NextMember);
++
++            /* update the source td itself by using a host command */
++            err = BuildShadowAndModifyDescriptor(p_ReplicGroup,
++                                                 p_NextMember,
++                                                 NULL,
++                                                 TRUE/*sourceDescriptor*/,
++                                                 FALSE/*last*/);
++            break;
++
++        case FRM_REPLIC_MIDDLE_MEMBER_INDEX:
++            p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));
++            ASSERT_COND(p_PreviousMember);
++
++            p_NextMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex+1));
++            ASSERT_COND(p_NextMember);
++
++            err = BuildShadowAndModifyDescriptor(p_ReplicGroup,
++                                                 p_NextMember,
++                                                 p_PreviousMember,
++                                                 FALSE/*sourceDescriptor*/,
++                                                 FALSE/*last*/);
++
++            break;
++
++        case FRM_REPLIC_LAST_MEMBER_INDEX:
++            p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));
++            ASSERT_COND(p_PreviousMember);
++
++            err = BuildShadowAndModifyDescriptor(p_ReplicGroup,
++                                                 NULL,
++                                                 p_PreviousMember,
++                                                 FALSE/*sourceDescriptor*/,
++                                                 TRUE/*last*/);
++            break;
++
++        default:
++            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member position in remove member"));
++    }
++
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    if (p_CurrentMember->h_Manip)
++    {
++        FmPcdManipUpdateOwner(p_CurrentMember->h_Manip, FALSE);
++        p_CurrentMember->h_Manip = NULL;
++    }
++
++    /* remove the member from the driver internal members list */
++    RemoveMemberFromList(p_ReplicGroup, p_CurrentMember);
++
++    /* return the member to the available members list */
++    FreeMember(p_ReplicGroup, p_CurrentMember);
++
++    return E_OK;
++}
++
++static void DeleteGroup(t_FmPcdFrmReplicGroup *p_ReplicGroup)
++{
++    int                     i, j;
++    t_Handle                h_Muram;
++    t_FmPcdFrmReplicMember  *p_Member, *p_CurrentMember;
++
++    if (p_ReplicGroup)
++    {
++        ASSERT_COND(p_ReplicGroup->h_FmPcd);
++        h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd);
++        ASSERT_COND(h_Muram);
++
++        /* free the source table descriptor */
++        if (p_ReplicGroup->p_SourceTd)
++        {
++            FM_MURAM_FreeMem(h_Muram, p_ReplicGroup->p_SourceTd);
++            p_ReplicGroup->p_SourceTd = NULL;
++        }
++
++        /* Remove all members from the members linked list (hw and sw) and
++           return the members to the available members list */
++        if (p_ReplicGroup->numOfEntries)
++        {
++            j = p_ReplicGroup->numOfEntries-1;
++
++            /* manually removal of the member because there are no owners of
++               this group */
++            for (i=j; i>=0; i--)
++            {
++                p_CurrentMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)i/*memberIndex*/);
++                ASSERT_COND(p_CurrentMember);
++
++                if (p_CurrentMember->h_Manip)
++                {
++                    FmPcdManipUpdateOwner(p_CurrentMember->h_Manip, FALSE);
++                    p_CurrentMember->h_Manip = NULL;
++                }
++
++                /* remove the member from the internal driver members list */
++                RemoveMemberFromList(p_ReplicGroup, p_CurrentMember);
++
++                /* return the member to the available members list */
++                FreeMember(p_ReplicGroup, p_CurrentMember);
++            }
++        }
++
++        /* Free members AD */
++        for (i=0; i<p_ReplicGroup->maxNumOfEntries; i++)
++        {
++            p_Member = GetAvailableMember(p_ReplicGroup);
++            ASSERT_COND(p_Member);
++            if (p_Member->p_MemberAd)
++            {
++                FM_MURAM_FreeMem(h_Muram, p_Member->p_MemberAd);
++                p_Member->p_MemberAd = NULL;
++            }
++            XX_Free(p_Member);
++        }
++
++        /* release the group lock */
++        if (p_ReplicGroup->p_Lock)
++            FmPcdReleaseLock(p_ReplicGroup->h_FmPcd, p_ReplicGroup->p_Lock);
++
++        /* free the replicator group */
++        XX_Free(p_ReplicGroup);
++    }
++}
++
++
++/*****************************************************************************/
++/*              Inter-module API routines                                    */
++/*****************************************************************************/
++
++/* NOTE: the inter-module routines are locked by cc in case of using them */
++void * FrmReplicGroupGetSourceTableDescriptor(t_Handle h_ReplicGroup)
++{
++    t_FmPcdFrmReplicGroup   *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
++    ASSERT_COND(p_ReplicGroup);
++
++    return (p_ReplicGroup->p_SourceTd);
++}
++
++void FrmReplicGroupUpdateAd(t_Handle  h_ReplicGroup,
++                            void      *p_Ad,
++                            t_Handle  *h_AdNew)
++{
++    t_FmPcdFrmReplicGroup   *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
++    t_AdOfTypeResult    *p_AdResult = (t_AdOfTypeResult*)p_Ad;
++    t_FmPcd             *p_FmPcd;
++
++    ASSERT_COND(p_ReplicGroup);
++    p_FmPcd = p_ReplicGroup->h_FmPcd;
++
++    /* build a bypass ad */
++    WRITE_UINT32(p_AdResult->fqid, FM_PCD_AD_BYPASS_TYPE |
++        (uint32_t)((XX_VirtToPhys(p_ReplicGroup->p_SourceTd)) - p_FmPcd->physicalMuramBase));
++
++    *h_AdNew = NULL;
++}
++
++void  FrmReplicGroupUpdateOwner(t_Handle                   h_ReplicGroup,
++                                bool                       add)
++{
++    t_FmPcdFrmReplicGroup   *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
++    ASSERT_COND(p_ReplicGroup);
++
++    /* update the group owner counter */
++    if (add)
++        p_ReplicGroup->owners++;
++    else
++    {
++        ASSERT_COND(p_ReplicGroup->owners);
++        p_ReplicGroup->owners--;
++    }
++}
++
++t_Error FrmReplicGroupTryLock(t_Handle h_ReplicGroup)
++{
++    t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
++
++    ASSERT_COND(h_ReplicGroup);
++
++    if (FmPcdLockTryLock(p_ReplicGroup->p_Lock))
++        return E_OK;
++
++    return ERROR_CODE(E_BUSY);
++}
++
++void FrmReplicGroupUnlock(t_Handle h_ReplicGroup)
++{
++    t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
++
++    ASSERT_COND(h_ReplicGroup);
++
++    FmPcdLockUnlock(p_ReplicGroup->p_Lock);
++}
++/*********************** End of inter-module routines ************************/
++
++
++/****************************************/
++/*       API Init unit functions        */
++/****************************************/
++t_Handle FM_PCD_FrmReplicSetGroup(t_Handle                    h_FmPcd,
++                                  t_FmPcdFrmReplicGroupParams *p_ReplicGroupParam)
++{
++    t_FmPcdFrmReplicGroup       *p_ReplicGroup;
++    t_FmPcdFrmReplicMember      *p_CurrentMember, *p_NextMember = NULL;
++    int                         i;
++    t_Error                     err;
++    bool                        last = FALSE;
++    t_Handle                    h_Muram;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(p_ReplicGroupParam, E_INVALID_HANDLE, NULL);
++
++    if (!FmPcdIsAdvancedOffloadSupported(h_FmPcd))
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Advanced-offload must be enabled"));
++        return NULL;
++    }
++
++    err = CheckParams(h_FmPcd, p_ReplicGroupParam);
++    if (err)
++    {
++        REPORT_ERROR(MAJOR, err, (NO_MSG));
++        return NULL;
++    }
++
++    p_ReplicGroup = (t_FmPcdFrmReplicGroup*)XX_Malloc(sizeof(t_FmPcdFrmReplicGroup));
++    if (!p_ReplicGroup)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory"));
++        return NULL;
++    }
++    memset(p_ReplicGroup, 0, sizeof(t_FmPcdFrmReplicGroup));
++
++    /* initialize lists for internal driver use */
++    INIT_LIST(&p_ReplicGroup->availableMembersList);
++    INIT_LIST(&p_ReplicGroup->membersList);
++
++    p_ReplicGroup->h_FmPcd = h_FmPcd;
++
++    h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd);
++    ASSERT_COND(h_Muram);
++
++    /* initialize the group lock */
++    p_ReplicGroup->p_Lock = FmPcdAcquireLock(p_ReplicGroup->h_FmPcd);
++    if (!p_ReplicGroup->p_Lock)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Replic group lock"));
++        DeleteGroup(p_ReplicGroup);
++        return NULL;
++    }
++
++    /* Allocate the frame replicator source table descriptor */
++    p_ReplicGroup->p_SourceTd =
++        (t_Handle)FM_MURAM_AllocMem(h_Muram,
++                                    FM_PCD_CC_AD_ENTRY_SIZE,
++                                    FM_PCD_CC_AD_TABLE_ALIGN);
++    if (!p_ReplicGroup->p_SourceTd)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("frame replicator source table descriptor"));
++        DeleteGroup(p_ReplicGroup);
++        return NULL;
++    }
++
++    /* update the shadow size - required for the host commands */
++    err = FmPcdUpdateCcShadow(p_ReplicGroup->h_FmPcd,
++                              FM_PCD_CC_AD_ENTRY_SIZE,
++                              FM_PCD_CC_AD_TABLE_ALIGN);
++    if (err)
++    {
++        REPORT_ERROR(MAJOR, err, ("Update CC shadow"));
++        DeleteGroup(p_ReplicGroup);
++        return NULL;
++    }
++
++    p_ReplicGroup->maxNumOfEntries  = p_ReplicGroupParam->maxNumOfEntries;
++
++    /* Allocate the maximal number of members ADs and Statistics AD for the group
++       It prevents allocation of Muram in run-time */
++    for (i=0; i<p_ReplicGroup->maxNumOfEntries; i++)
++    {
++        err = AllocMember(p_ReplicGroup);
++        if (err)
++        {
++            REPORT_ERROR(MAJOR, err, ("allocate a new member"));
++            DeleteGroup(p_ReplicGroup);
++            return NULL;
++        }
++    }
++
++    /* Initialize the members linked lists:
++      (hw - the one that is used by the FMan controller and
++       sw - the one that is managed by the driver internally) */
++    for (i=(p_ReplicGroupParam->numOfEntries-1); i>=0; i--)
++    {
++        /* check if this is the last member in the group */
++        if (i == (p_ReplicGroupParam->numOfEntries-1))
++            last = TRUE;
++        else
++            last = FALSE;
++
++        /* Initialize a new member */
++        p_CurrentMember = InitMember(p_ReplicGroup,
++                                     &(p_ReplicGroupParam->nextEngineParams[i]),
++                                     last);
++        if (!p_CurrentMember)
++        {
++            REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("No available member"));
++            DeleteGroup(p_ReplicGroup);
++            return NULL;
++        }
++
++        /* Build the members group - link two consecutive members in the hw linked list */
++        LinkMemberToMember(p_ReplicGroup, p_CurrentMember, p_NextMember);
++
++        /* update the driver internal members list to be compatible to the hw members linked list */
++        AddMemberToList(p_ReplicGroup, p_CurrentMember, &p_ReplicGroup->membersList);
++
++        p_NextMember = p_CurrentMember;
++    }
++
++    /* initialize the source table descriptor */
++    BuildSourceTd(p_ReplicGroup->p_SourceTd);
++
++    /* link the source table descriptor to point to the first member in the group */
++    LinkSourceToMember(p_ReplicGroup, p_ReplicGroup->p_SourceTd, p_NextMember);
++
++    return p_ReplicGroup;
++}
++
++t_Error FM_PCD_FrmReplicDeleteGroup(t_Handle h_ReplicGroup)
++{
++    t_FmPcdFrmReplicGroup   *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
++
++    SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE);
++
++    if (p_ReplicGroup->owners)
++        RETURN_ERROR(MAJOR,
++                     E_INVALID_STATE,
++                     ("the group has owners and can't be deleted"));
++
++    DeleteGroup(p_ReplicGroup);
++
++    return E_OK;
++}
++
++
++/*****************************************************************************/
++/*       API Run-time Frame replicator Control unit functions                */
++/*****************************************************************************/
++t_Error FM_PCD_FrmReplicAddMember(t_Handle                  h_ReplicGroup,
++                                  uint16_t                  memberIndex,
++                                  t_FmPcdCcNextEngineParams *p_MemberParams)
++{
++    t_FmPcdFrmReplicGroup       *p_ReplicGroup = (t_FmPcdFrmReplicGroup*) h_ReplicGroup;
++    t_FmPcdFrmReplicMember      *p_NewMember, *p_CurrentMember = NULL, *p_PreviousMember = NULL;
++    t_Error                     err;
++    uint8_t                     memberPosition;
++
++    SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_MemberParams, E_INVALID_HANDLE);
++
++    /* group lock */
++    err = FrmReplicGroupTryLock(p_ReplicGroup);
++    if (GET_ERROR_TYPE(err) == E_BUSY)
++        return ERROR_CODE(E_BUSY);
++
++    if (memberIndex > p_ReplicGroup->numOfEntries)
++    {
++        /* unlock */
++        FrmReplicGroupUnlock(p_ReplicGroup);
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
++                     ("memberIndex is greater than the members in the list"));
++    }
++
++    if (memberIndex >= p_ReplicGroup->maxNumOfEntries)
++    {
++        /* unlock */
++        FrmReplicGroupUnlock(p_ReplicGroup);
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("memberIndex is greater than the allowed number of members in the group"));
++    }
++
++    if ((p_ReplicGroup->numOfEntries + 1) > FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES)
++    {
++        /* unlock */
++        FrmReplicGroupUnlock(p_ReplicGroup);
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("numOfEntries with new entry can not be larger than %d\n",
++                      FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES));
++    }
++
++    err = MemberCheckParams(p_ReplicGroup->h_FmPcd, p_MemberParams);
++    if (err)
++    {
++        /* unlock */
++        FrmReplicGroupUnlock(p_ReplicGroup);
++        RETURN_ERROR(MAJOR, err, ("member check parameters in add operation"));
++    }
++    /* determine the member position in the group */
++    memberPosition = GetMemberPosition(p_ReplicGroup,
++                                       memberIndex,
++                                       TRUE/* add operation */);
++
++    /* Initialize a new member */
++    p_NewMember = InitMember(p_ReplicGroup,
++                             p_MemberParams,
++                             (memberPosition == FRM_REPLIC_LAST_MEMBER_INDEX ? TRUE : FALSE));
++    if (!p_NewMember)
++    {
++        /* unlock */
++        FrmReplicGroupUnlock(p_ReplicGroup);
++        RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("No available member"));
++    }
++
++    switch (memberPosition)
++    {
++        case FRM_REPLIC_FIRST_MEMBER_INDEX:
++            p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex);
++            ASSERT_COND(p_CurrentMember);
++
++            LinkMemberToMember(p_ReplicGroup, p_NewMember, p_CurrentMember);
++
++            /* update the internal group source TD */
++            LinkSourceToMember(p_ReplicGroup,
++                               p_ReplicGroup->p_SourceTd,
++                               p_NewMember);
++
++            /* add member to the internal sw member list */
++            AddMemberToList(p_ReplicGroup,
++                            p_NewMember,
++                            &p_ReplicGroup->membersList);
++            break;
++
++        case FRM_REPLIC_MIDDLE_MEMBER_INDEX:
++            p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex);
++            ASSERT_COND(p_CurrentMember);
++
++            p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));
++            ASSERT_COND(p_PreviousMember);
++
++            LinkMemberToMember(p_ReplicGroup, p_NewMember, p_CurrentMember);
++            LinkMemberToMember(p_ReplicGroup, p_PreviousMember, p_NewMember);
++
++            AddMemberToList(p_ReplicGroup, p_NewMember, &p_PreviousMember->node);
++            break;
++
++        case FRM_REPLIC_LAST_MEMBER_INDEX:
++            p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));
++            ASSERT_COND(p_PreviousMember);
++
++            LinkMemberToMember(p_ReplicGroup, p_PreviousMember, p_NewMember);
++            FillReplicAdOfTypeResult(p_PreviousMember->p_MemberAd, FALSE/*last*/);
++
++            /* add the new member to the internal sw member list */
++            AddMemberToList(p_ReplicGroup, p_NewMember, &p_PreviousMember->node);
++           break;
++
++        default:
++            /* unlock */
++            FrmReplicGroupUnlock(p_ReplicGroup);
++            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member position in add member"));
++
++    }
++
++    /* unlock */
++    FrmReplicGroupUnlock(p_ReplicGroup);
++
++    return E_OK;
++}
++
++t_Error FM_PCD_FrmReplicRemoveMember(t_Handle   h_ReplicGroup,
++                                     uint16_t   memberIndex)
++{
++    t_FmPcdFrmReplicGroup   *p_ReplicGroup = (t_FmPcdFrmReplicGroup*) h_ReplicGroup;
++    t_Error                 err;
++
++    SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE);
++
++    /* lock */
++    err = FrmReplicGroupTryLock(p_ReplicGroup);
++    if (GET_ERROR_TYPE(err) == E_BUSY)
++        return ERROR_CODE(E_BUSY);
++
++    if (memberIndex >= p_ReplicGroup->numOfEntries)
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member index to remove"));
++
++    /* Design decision: group must contain at least one member
++       No possibility to remove the last member from the group */
++    if (p_ReplicGroup->numOfEntries == 1)
++        RETURN_ERROR(MAJOR, E_CONFLICT, ("Can't remove the last member. At least one member should be related to a group."));
++
++    err = RemoveMember(p_ReplicGroup, memberIndex);
++
++    /* unlock */
++    FrmReplicGroupUnlock(p_ReplicGroup);
++
++    switch (GET_ERROR_TYPE(err))
++    {
++        case E_OK:
++            return E_OK;
++
++        case E_BUSY:
++            DBG(TRACE, ("E_BUSY error"));
++            return ERROR_CODE(E_BUSY);
++
++        default:
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++}
++
++/*********************** End of API routines ************************/
++
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.h
+@@ -0,0 +1,101 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_replic.h
++
++ @Description   FM frame replicator
++*//***************************************************************************/
++#ifndef __FM_REPLIC_H
++#define __FM_REPLIC_H
++
++#include "std_ext.h"
++#include "error_ext.h"
++
++
++#define FRM_REPLIC_SOURCE_TD_OPCODE           0x75
++#define NEXT_FRM_REPLIC_ADDR_SHIFT            4
++#define NEXT_FRM_REPLIC_MEMBER_INDEX_SHIFT    16
++#define FRM_REPLIC_FR_BIT                     0x08000000
++#define FRM_REPLIC_NL_BIT                     0x10000000
++#define FRM_REPLIC_INVALID_MEMBER_INDEX       0xffff
++#define FRM_REPLIC_FIRST_MEMBER_INDEX         0
++
++#define FRM_REPLIC_MIDDLE_MEMBER_INDEX        1
++#define FRM_REPLIC_LAST_MEMBER_INDEX          2
++
++#define SOURCE_TD_ITSELF_OPTION               0x01
++#define SOURCE_TD_COPY_OPTION                 0x02
++#define SOURCE_TD_ITSELF_AND_COPY_OPTION      SOURCE_TD_ITSELF_OPTION | SOURCE_TD_COPY_OPTION
++#define SOURCE_TD_NONE                        0x04
++
++/*typedef enum e_SourceTdOption
++{
++    e_SOURCE_TD_NONE = 0,
++    e_SOURCE_TD_ITSELF_OPTION = 1,
++    e_SOURCE_TD_COPY_OPTION = 2,
++    e_SOURCE_TD_ITSELF_AND_COPY_OPTION = e_SOURCE_TD_ITSELF_OPTION | e_SOURCE_TD_COPY_OPTION
++} e_SourceTdOption;
++*/
++
++typedef struct
++{
++    volatile uint32_t type;
++    volatile uint32_t frGroupPointer;
++    volatile uint32_t operationCode;
++    volatile uint32_t reserved;
++} t_FrmReplicGroupSourceAd;
++
++typedef struct t_FmPcdFrmReplicMember
++{
++    void                        *p_MemberAd;    /**< pointer to the member AD */
++    void                        *p_StatisticsAd;/**< pointer to the statistics AD of the member */
++    t_Handle                    h_Manip;        /**< manip handle - need for free routines */
++    t_List                      node;
++} t_FmPcdFrmReplicMember;
++
++typedef struct t_FmPcdFrmReplicGroup
++{
++    t_Handle                    h_FmPcd;
++
++    uint8_t                     maxNumOfEntries;/**< maximal number of members in the group */
++    uint8_t                     numOfEntries;   /**< actual number of members in the group */
++    uint16_t                    owners;         /**< how many keys share this frame replicator group */
++    void                        *p_SourceTd;     /**< pointer to the frame replicator source table descriptor */
++    t_List                      membersList;    /**< the members list - should reflect the order of the members as in the hw linked list*/
++    t_List                      availableMembersList;/**< list of all the available members in the group */
++    t_FmPcdLock                 *p_Lock;
++} t_FmPcdFrmReplicGroup;
++
++
++#endif /* __FM_REPLIC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c
+@@ -0,0 +1,888 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "fsl_fman_kg.h"
++
++/****************************************/
++/*       static functions               */
++/****************************************/
++
++
++static uint32_t build_ar_bind_scheme(uint8_t hwport_id, bool write)
++{
++      uint32_t rw;
++
++      rw = write ? (uint32_t)FM_KG_KGAR_WRITE : (uint32_t)FM_KG_KGAR_READ;
++
++      return (uint32_t)(FM_KG_KGAR_GO |
++                      rw |
++                      FM_PCD_KG_KGAR_SEL_PORT_ENTRY |
++                      hwport_id |
++                      FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP);
++}
++
++static void clear_pe_all_scheme(struct fman_kg_regs *regs, uint8_t hwport_id)
++{
++      uint32_t ar;
++
++      fman_kg_write_sp(regs, 0xffffffff, 0);
++
++      ar = build_ar_bind_scheme(hwport_id, TRUE);
++      fman_kg_write_ar_wait(regs, ar);
++}
++
++static uint32_t build_ar_bind_cls_plan(uint8_t hwport_id, bool write)
++{
++      uint32_t rw;
++
++      rw = write ? (uint32_t)FM_KG_KGAR_WRITE : (uint32_t)FM_KG_KGAR_READ;
++
++      return (uint32_t)(FM_KG_KGAR_GO |
++                      rw |
++                      FM_PCD_KG_KGAR_SEL_PORT_ENTRY |
++                      hwport_id |
++                      FM_PCD_KG_KGAR_SEL_PORT_WSEL_CPP);
++}
++
++static void clear_pe_all_cls_plan(struct fman_kg_regs *regs, uint8_t hwport_id)
++{
++      uint32_t ar;
++
++      fman_kg_write_cpp(regs, 0);
++
++      ar = build_ar_bind_cls_plan(hwport_id, TRUE);
++      fman_kg_write_ar_wait(regs, ar);
++}
++
++static uint8_t get_gen_ht_code(enum fman_kg_gen_extract_src src,
++                              bool no_validation,
++                              uint8_t *offset)
++{
++      int     code;
++
++      switch (src) {
++      case E_FMAN_KG_GEN_EXTRACT_ETH:
++              code = no_validation ? 0x73 : 0x3;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_ETYPE:
++              code = no_validation ? 0x77 : 0x7;
++              break;
++ 
++      case E_FMAN_KG_GEN_EXTRACT_SNAP:
++              code = no_validation ? 0x74 : 0x4;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_1:
++              code = no_validation ? 0x75 : 0x5;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_N:
++              code = no_validation ? 0x76 : 0x6;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_PPPoE:
++              code = no_validation ? 0x78 : 0x8;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_MPLS_1:
++              code = no_validation ? 0x79 : 0x9;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_MPLS_2:
++              code = no_validation ? FM_KG_SCH_GEN_HT_INVALID : 0x19;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_MPLS_3:
++              code = no_validation ? FM_KG_SCH_GEN_HT_INVALID : 0x29;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_MPLS_N:
++              code = no_validation ? 0x7a : 0xa;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_IPv4_1:
++              code = no_validation ? 0x7b : 0xb;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_IPv6_1:
++              code = no_validation ? 0x7b : 0x1b;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_IPv4_2:
++              code = no_validation ? 0x7c : 0xc;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_IPv6_2:
++              code = no_validation ? 0x7c : 0x1c;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_MINENCAP:
++              code = no_validation ? 0x7c : 0x2c;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_IP_PID:
++              code = no_validation ? 0x72 : 0x2;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_GRE:
++              code = no_validation ? 0x7d : 0xd;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_TCP:
++              code = no_validation ? 0x7e : 0xe;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_UDP:
++              code = no_validation ? 0x7e : 0x1e;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_SCTP:
++              code = no_validation ? 0x7e : 0x3e;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_DCCP:
++              code = no_validation ? 0x7e : 0x4e;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_IPSEC_AH:
++              code = no_validation ? 0x7e : 0x2e;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_IPSEC_ESP:
++              code = no_validation ? 0x7e : 0x6e;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_SHIM_1:
++              code = 0x70;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_SHIM_2:
++              code = 0x71;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_FROM_DFLT:
++              code = 0x10;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_FROM_FRAME_START:
++              code = 0x40;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_FROM_PARSE_RESULT:
++              code = 0x20;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_FROM_END_OF_PARSE:
++              code = 0x7f;
++              break;
++
++      case E_FMAN_KG_GEN_EXTRACT_FROM_FQID:
++              code = 0x20;
++              *offset += 0x20;
++              break;
++
++      default:
++              code = FM_KG_SCH_GEN_HT_INVALID;
++      }
++
++      return (uint8_t)code;
++}
++
++static uint32_t build_ar_scheme(uint8_t scheme,
++                              uint8_t hwport_id,
++                              bool update_counter,
++                              bool write)
++{
++      uint32_t rw;
++
++      rw = (uint32_t)(write ? FM_KG_KGAR_WRITE : FM_KG_KGAR_READ);
++
++      return (uint32_t)(FM_KG_KGAR_GO |
++                      rw |
++                      FM_KG_KGAR_SEL_SCHEME_ENTRY |
++                      hwport_id |
++                      ((uint32_t)scheme << FM_KG_KGAR_NUM_SHIFT) |
++                      (update_counter ? FM_KG_KGAR_SCM_WSEL_UPDATE_CNT : 0));
++}
++
++static uint32_t build_ar_cls_plan(uint8_t grp,
++                                      uint8_t entries_mask,
++                                      uint8_t hwport_id,
++                                      bool write)
++{
++      uint32_t rw;
++
++      rw = (uint32_t)(write ? FM_KG_KGAR_WRITE : FM_KG_KGAR_READ);
++
++      return (uint32_t)(FM_KG_KGAR_GO |
++                      rw |
++                      FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY |
++                      hwport_id |
++                      ((uint32_t)grp << FM_KG_KGAR_NUM_SHIFT) |
++                      ((uint32_t)entries_mask << FM_KG_KGAR_WSEL_SHIFT));
++}
++
++int fman_kg_write_ar_wait(struct fman_kg_regs *regs, uint32_t fmkg_ar)
++{
++      iowrite32be(fmkg_ar, &regs->fmkg_ar);
++      /* Wait for GO to be idle and read error */
++      while ((fmkg_ar = ioread32be(&regs->fmkg_ar)) & FM_KG_KGAR_GO) ;
++      if (fmkg_ar & FM_PCD_KG_KGAR_ERR)
++              return -EINVAL;
++      return 0;
++}
++
++void fman_kg_write_sp(struct fman_kg_regs *regs, uint32_t sp, bool add)
++{
++
++      struct fman_kg_pe_regs *kgpe_regs;
++      uint32_t tmp;
++
++      kgpe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]);
++      tmp = ioread32be(&kgpe_regs->fmkg_pe_sp);
++
++      if (add)
++              tmp |= sp;
++      else /* clear */
++              tmp &= ~sp;
++
++      iowrite32be(tmp, &kgpe_regs->fmkg_pe_sp);
++
++}
++
++void fman_kg_write_cpp(struct fman_kg_regs *regs, uint32_t cpp)
++{
++      struct fman_kg_pe_regs *kgpe_regs;
++
++      kgpe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]);
++
++      iowrite32be(cpp, &kgpe_regs->fmkg_pe_cpp);
++}
++
++void fman_kg_get_event(struct fman_kg_regs *regs,
++                      uint32_t *event,
++                      uint32_t *scheme_idx)
++{
++      uint32_t mask, force;
++
++      *event = ioread32be(&regs->fmkg_eer);
++      mask = ioread32be(&regs->fmkg_eeer);
++      *scheme_idx = ioread32be(&regs->fmkg_seer);
++      *scheme_idx &= ioread32be(&regs->fmkg_seeer);
++
++      *event &= mask;
++
++      /* clear the forced events */
++      force = ioread32be(&regs->fmkg_feer);
++      if (force & *event)
++              iowrite32be(force & ~*event ,&regs->fmkg_feer);
++
++      iowrite32be(*event, &regs->fmkg_eer);
++      iowrite32be(*scheme_idx, &regs->fmkg_seer);
++}
++
++
++void fman_kg_init(struct fman_kg_regs *regs,
++                      uint32_t exceptions,
++                      uint32_t dflt_nia)
++{
++      uint32_t tmp;
++      int i;
++
++      iowrite32be(FM_EX_KG_DOUBLE_ECC | FM_EX_KG_KEYSIZE_OVERFLOW,
++                      &regs->fmkg_eer);
++
++      tmp = 0;
++      if (exceptions & FM_EX_KG_DOUBLE_ECC)
++              tmp |= FM_EX_KG_DOUBLE_ECC;
++
++      if (exceptions & FM_EX_KG_KEYSIZE_OVERFLOW)
++              tmp |= FM_EX_KG_KEYSIZE_OVERFLOW;
++
++      iowrite32be(tmp, &regs->fmkg_eeer);
++      iowrite32be(0, &regs->fmkg_fdor);
++      iowrite32be(0, &regs->fmkg_gdv0r);
++      iowrite32be(0, &regs->fmkg_gdv1r);
++      iowrite32be(dflt_nia, &regs->fmkg_gcr);
++
++      /* Clear binding between ports to schemes and classification plans
++       * so that all ports are not bound to any scheme/classification plan */
++      for (i = 0; i < FMAN_MAX_NUM_OF_HW_PORTS; i++) {
++              clear_pe_all_scheme(regs, (uint8_t)i);
++              clear_pe_all_cls_plan(regs, (uint8_t)i);
++      }
++}
++
++void fman_kg_enable_scheme_interrupts(struct fman_kg_regs *regs)
++{
++      /* enable and enable all scheme interrupts */
++      iowrite32be(0xFFFFFFFF, &regs->fmkg_seer);
++      iowrite32be(0xFFFFFFFF, &regs->fmkg_seeer);
++}
++
++void fman_kg_enable(struct fman_kg_regs *regs)
++{
++      iowrite32be(ioread32be(&regs->fmkg_gcr) | FM_KG_KGGCR_EN,
++                      &regs->fmkg_gcr);
++}
++
++void fman_kg_disable(struct fman_kg_regs *regs)
++{
++      iowrite32be(ioread32be(&regs->fmkg_gcr) & ~FM_KG_KGGCR_EN,
++                      &regs->fmkg_gcr);
++}
++
++void fman_kg_set_data_after_prs(struct fman_kg_regs *regs, uint8_t offset)
++{
++      iowrite32be(offset, &regs->fmkg_fdor);
++}
++
++void fman_kg_set_dflt_val(struct fman_kg_regs *regs,
++                              uint8_t def_id,
++                              uint32_t val)
++{
++      if(def_id == 0)
++              iowrite32be(val, &regs->fmkg_gdv0r);
++      else
++              iowrite32be(val, &regs->fmkg_gdv1r);
++}
++
++
++void fman_kg_set_exception(struct fman_kg_regs *regs,
++                              uint32_t exception,
++                              bool enable)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&regs->fmkg_eeer);
++
++      if (enable) {
++              tmp |= exception;
++      } else {
++              tmp &= ~exception;
++      }
++
++      iowrite32be(tmp, &regs->fmkg_eeer);
++}
++
++void fman_kg_get_exception(struct fman_kg_regs *regs,
++                              uint32_t *events,
++                              uint32_t *scheme_ids,
++                              bool clear)
++{
++      uint32_t mask;
++
++      *events = ioread32be(&regs->fmkg_eer);
++      mask = ioread32be(&regs->fmkg_eeer);
++      *events &= mask;
++ 
++      *scheme_ids = 0;
++
++      if (*events & FM_EX_KG_KEYSIZE_OVERFLOW) {
++              *scheme_ids = ioread32be(&regs->fmkg_seer);
++              mask = ioread32be(&regs->fmkg_seeer);
++              *scheme_ids &= mask;
++      }
++
++      if (clear) {
++              iowrite32be(*scheme_ids, &regs->fmkg_seer);
++              iowrite32be(*events, &regs->fmkg_eer);
++      }
++}
++
++void fman_kg_get_capture(struct fman_kg_regs *regs,
++                              struct fman_kg_ex_ecc_attr *ecc_attr,
++                              bool clear)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&regs->fmkg_serc);
++
++      if (tmp & KG_FMKG_SERC_CAP) {
++              /* Captured data is valid */
++              ecc_attr->valid = TRUE;
++              ecc_attr->double_ecc =
++                      (bool)((tmp & KG_FMKG_SERC_CET) ? TRUE : FALSE);
++              ecc_attr->single_ecc_count =
++                      (uint8_t)((tmp & KG_FMKG_SERC_CNT_MSK) >>
++                                      KG_FMKG_SERC_CNT_SHIFT);
++              ecc_attr->addr = (uint16_t)(tmp & KG_FMKG_SERC_ADDR_MSK);
++
++              if (clear)
++                      iowrite32be(KG_FMKG_SERC_CAP, &regs->fmkg_serc);
++      } else {
++              /* No ECC error is captured */
++              ecc_attr->valid = FALSE;
++      }
++}
++
++int fman_kg_build_scheme(struct fman_kg_scheme_params *params,
++                              struct fman_kg_scheme_regs *scheme_regs)
++{
++      struct fman_kg_extract_params *extract_params;
++      struct fman_kg_gen_extract_params *gen_params;
++      uint32_t tmp_reg, i, select, mask, fqb;
++      uint8_t offset, shift, ht;
++
++      /* Zero out all registers so no need to care about unused ones */
++      memset(scheme_regs, 0, sizeof(struct fman_kg_scheme_regs));
++
++      /* Mode register */
++      tmp_reg = fm_kg_build_nia(params->next_engine,
++                      params->next_engine_action);
++      if (tmp_reg == KG_NIA_INVALID) {
++              return -EINVAL;
++      }
++
++      if (params->next_engine == E_FMAN_PCD_PLCR) {
++              tmp_reg |= FMAN_KG_SCH_MODE_NIA_PLCR;
++      }
++      else if (params->next_engine == E_FMAN_PCD_CC) {
++              tmp_reg |= (uint32_t)params->cc_params.base_offset <<
++                              FMAN_KG_SCH_MODE_CCOBASE_SHIFT;
++      }
++
++      tmp_reg |= FMAN_KG_SCH_MODE_EN;
++      scheme_regs->kgse_mode = tmp_reg;
++
++      /* Match vector */
++      scheme_regs->kgse_mv = params->match_vector;
++
++      extract_params = &params->extract_params;
++
++      /* Scheme default values registers */
++      scheme_regs->kgse_dv0 = extract_params->def_scheme_0;
++      scheme_regs->kgse_dv1 = extract_params->def_scheme_1;
++
++      /* Extract Known Fields Command register */
++      scheme_regs->kgse_ekfc = extract_params->known_fields;
++
++      /* Entry Extract Known Default Value register */
++      tmp_reg = 0;
++      tmp_reg |= extract_params->known_fields_def.mac_addr <<
++                      FMAN_KG_SCH_DEF_MAC_ADDR_SHIFT;
++      tmp_reg |= extract_params->known_fields_def.vlan_tci <<
++                      FMAN_KG_SCH_DEF_VLAN_TCI_SHIFT;
++      tmp_reg |= extract_params->known_fields_def.etype <<
++                      FMAN_KG_SCH_DEF_ETYPE_SHIFT;
++      tmp_reg |= extract_params->known_fields_def.ppp_sid <<
++                      FMAN_KG_SCH_DEF_PPP_SID_SHIFT;
++      tmp_reg |= extract_params->known_fields_def.ppp_pid <<
++                      FMAN_KG_SCH_DEF_PPP_PID_SHIFT;
++      tmp_reg |= extract_params->known_fields_def.mpls <<
++                      FMAN_KG_SCH_DEF_MPLS_SHIFT;
++      tmp_reg |= extract_params->known_fields_def.ip_addr <<
++                      FMAN_KG_SCH_DEF_IP_ADDR_SHIFT;
++      tmp_reg |= extract_params->known_fields_def.ptype <<
++                      FMAN_KG_SCH_DEF_PTYPE_SHIFT;
++      tmp_reg |= extract_params->known_fields_def.ip_tos_tc <<
++                      FMAN_KG_SCH_DEF_IP_TOS_TC_SHIFT;
++      tmp_reg |= extract_params->known_fields_def.ipv6_fl <<
++                      FMAN_KG_SCH_DEF_IPv6_FL_SHIFT;
++      tmp_reg |= extract_params->known_fields_def.ipsec_spi <<
++                      FMAN_KG_SCH_DEF_IPSEC_SPI_SHIFT;
++      tmp_reg |= extract_params->known_fields_def.l4_port <<
++                      FMAN_KG_SCH_DEF_L4_PORT_SHIFT;
++      tmp_reg |= extract_params->known_fields_def.tcp_flg <<
++                      FMAN_KG_SCH_DEF_TCP_FLG_SHIFT;
++
++      scheme_regs->kgse_ekdv = tmp_reg;
++
++      /* Generic extract registers */
++      if (extract_params->gen_extract_num > FM_KG_NUM_OF_GENERIC_REGS) {
++              return -EINVAL;
++      }
++
++      for (i = 0; i < extract_params->gen_extract_num; i++) {
++              gen_params = extract_params->gen_extract + i;
++
++              tmp_reg = FMAN_KG_SCH_GEN_VALID;
++              tmp_reg |= (uint32_t)gen_params->def_val <<
++                              FMAN_KG_SCH_GEN_DEF_SHIFT;
++
++              if (gen_params->type == E_FMAN_KG_HASH_EXTRACT) {
++                      if ((gen_params->extract > FMAN_KG_SCH_GEN_SIZE_MAX) ||
++                                      (gen_params->extract == 0)) {
++                              return -EINVAL;
++                      }
++              } else {
++                      tmp_reg |= FMAN_KG_SCH_GEN_OR;
++              }
++
++              tmp_reg |= (uint32_t)gen_params->extract <<
++                              FMAN_KG_SCH_GEN_SIZE_SHIFT;
++              tmp_reg |= (uint32_t)gen_params->mask <<
++                              FMAN_KG_SCH_GEN_MASK_SHIFT;
++
++              offset = gen_params->offset;
++              ht = get_gen_ht_code(gen_params->src,
++                              gen_params->no_validation,
++                              &offset);
++              tmp_reg |= (uint32_t)ht << FMAN_KG_SCH_GEN_HT_SHIFT;
++              tmp_reg |= offset;
++
++              scheme_regs->kgse_gec[i] = tmp_reg;
++      }
++
++      /* Masks registers */
++      if (extract_params->masks_num > FM_KG_EXTRACT_MASKS_NUM) {
++              return -EINVAL;
++      }
++
++      select = 0;
++      mask = 0;
++      fqb = 0;
++      for (i = 0; i < extract_params->masks_num; i++) {
++              /* MCSx fields */
++              KG_GET_MASK_SEL_SHIFT(shift, i);
++              if (extract_params->masks[i].is_known) {
++                      /* Mask known field */
++                      select |= extract_params->masks[i].field_or_gen_idx <<
++                                      shift;
++              } else {
++                      /* Mask generic extract */
++                      select |= (extract_params->masks[i].field_or_gen_idx +
++                                      FM_KG_MASK_SEL_GEN_BASE) << shift;
++              }
++
++              /* MOx fields - spread between se_bmch and se_fqb registers */
++              KG_GET_MASK_OFFSET_SHIFT(shift, i);
++              if (i < 2) {
++                      select |= (uint32_t)extract_params->masks[i].offset <<
++                                      shift;
++              } else {
++                      fqb |= (uint32_t)extract_params->masks[i].offset <<
++                                      shift;
++              }
++
++              /* BMx fields */
++              KG_GET_MASK_SHIFT(shift, i);
++              mask |= (uint32_t)extract_params->masks[i].mask << shift;
++      }
++
++      /* Finish with rest of BMx fileds -
++       * don't mask bits for unused masks by setting
++       * corresponding BMx field = 0xFF */
++      for (i = extract_params->masks_num; i < FM_KG_EXTRACT_MASKS_NUM; i++) {
++              KG_GET_MASK_SHIFT(shift, i);
++              mask |= 0xFF << shift;
++      }
++
++      scheme_regs->kgse_bmch = select;
++      scheme_regs->kgse_bmcl = mask;
++
++      /* Finish with FQB register initialization.
++       * Check fqid is 24-bit value. */
++      if (params->base_fqid & ~0x00FFFFFF) {
++              return -EINVAL;
++      }
++
++      fqb |= params->base_fqid;
++      scheme_regs->kgse_fqb = fqb;
++
++      /* Hash Configuration register */
++      tmp_reg = 0;
++      if (params->hash_params.use_hash) {
++              /* Check hash mask is 24-bit value */
++              if (params->hash_params.mask & ~0x00FFFFFF) {
++                      return -EINVAL;
++              }
++
++              /* Hash function produces 64-bit value, 24 bits of that
++               * are used to generate fq_id and policer profile.
++               * Thus, maximal shift is 40 bits to allow 24 bits out of 64.
++               */
++              if (params->hash_params.shift_r > FMAN_KG_SCH_HASH_HSHIFT_MAX) {
++                      return -EINVAL;
++              }
++
++              tmp_reg |= params->hash_params.mask;
++              tmp_reg |= (uint32_t)params->hash_params.shift_r <<
++                              FMAN_KG_SCH_HASH_HSHIFT_SHIFT;
++
++              if (params->hash_params.sym) {
++                      tmp_reg |= FMAN_KG_SCH_HASH_SYM;
++              }
++
++      }
++
++      if (params->bypass_fqid_gen) {
++              tmp_reg |= FMAN_KG_SCH_HASH_NO_FQID_GEN;
++      }
++
++      scheme_regs->kgse_hc = tmp_reg;
++
++      /* Policer Profile register */
++      if (params->policer_params.bypass_pp_gen) {
++              tmp_reg = 0;
++      } else {
++              /* Lower 8 bits of 24-bits extracted from hash result
++               * are used for policer profile generation.
++               * That leaves maximum shift value = 23. */
++              if (params->policer_params.shift > FMAN_KG_SCH_PP_SHIFT_MAX) {
++                      return -EINVAL;
++              }
++
++              tmp_reg = params->policer_params.base;
++              tmp_reg |= ((uint32_t)params->policer_params.shift <<
++                              FMAN_KG_SCH_PP_SH_SHIFT) &
++                              FMAN_KG_SCH_PP_SH_MASK;
++              tmp_reg |= ((uint32_t)params->policer_params.shift <<
++                              FMAN_KG_SCH_PP_SL_SHIFT) &
++                              FMAN_KG_SCH_PP_SL_MASK;
++              tmp_reg |= (uint32_t)params->policer_params.mask <<
++                              FMAN_KG_SCH_PP_MASK_SHIFT;
++      }
++
++      scheme_regs->kgse_ppc = tmp_reg;
++
++      /* Coarse Classification Bit Select register */
++      if (params->next_engine == E_FMAN_PCD_CC) {
++              scheme_regs->kgse_ccbs = params->cc_params.qlcv_bits_sel;
++      }
++
++      /* Packets Counter register */
++      if (params->update_counter) {
++              scheme_regs->kgse_spc = params->counter_value;
++      }
++
++      return 0;
++}
++
++int fman_kg_write_scheme(struct fman_kg_regs *regs,
++                              uint8_t scheme_id,
++                              uint8_t hwport_id,
++                              struct fman_kg_scheme_regs *scheme_regs,
++                              bool update_counter)
++{
++      struct fman_kg_scheme_regs *kgse_regs;
++      uint32_t tmp_reg;
++      int err, i;
++
++      /* Write indirect scheme registers */
++      kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]);
++
++      iowrite32be(scheme_regs->kgse_mode, &kgse_regs->kgse_mode);
++      iowrite32be(scheme_regs->kgse_ekfc, &kgse_regs->kgse_ekfc);
++      iowrite32be(scheme_regs->kgse_ekdv, &kgse_regs->kgse_ekdv);
++      iowrite32be(scheme_regs->kgse_bmch, &kgse_regs->kgse_bmch);
++      iowrite32be(scheme_regs->kgse_bmcl, &kgse_regs->kgse_bmcl);
++      iowrite32be(scheme_regs->kgse_fqb, &kgse_regs->kgse_fqb);
++      iowrite32be(scheme_regs->kgse_hc, &kgse_regs->kgse_hc);
++      iowrite32be(scheme_regs->kgse_ppc, &kgse_regs->kgse_ppc);
++      iowrite32be(scheme_regs->kgse_spc, &kgse_regs->kgse_spc);
++      iowrite32be(scheme_regs->kgse_dv0, &kgse_regs->kgse_dv0);
++      iowrite32be(scheme_regs->kgse_dv1, &kgse_regs->kgse_dv1);
++      iowrite32be(scheme_regs->kgse_ccbs, &kgse_regs->kgse_ccbs);
++      iowrite32be(scheme_regs->kgse_mv, &kgse_regs->kgse_mv);
++
++      for (i = 0 ; i < FM_KG_NUM_OF_GENERIC_REGS ; i++)
++              iowrite32be(scheme_regs->kgse_gec[i], &kgse_regs->kgse_gec[i]);
++
++      /* Write AR (Action register) */
++      tmp_reg = build_ar_scheme(scheme_id, hwport_id, update_counter, TRUE);
++      err = fman_kg_write_ar_wait(regs, tmp_reg);
++      return err;
++}
++
++int fman_kg_delete_scheme(struct fman_kg_regs *regs,
++                              uint8_t scheme_id,
++                              uint8_t hwport_id)
++{
++      struct fman_kg_scheme_regs *kgse_regs;
++      uint32_t tmp_reg;
++      int err, i;
++
++      kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]);
++
++      /* Clear all registers including enable bit in mode register */
++      for (i = 0; i < (sizeof(struct fman_kg_scheme_regs)) / 4; ++i) {
++              iowrite32be(0, ((uint32_t *)kgse_regs + i));
++      }
++
++      /* Write AR (Action register) */
++      tmp_reg = build_ar_scheme(scheme_id, hwport_id, FALSE, TRUE);
++      err = fman_kg_write_ar_wait(regs, tmp_reg);
++      return err;
++}
++
++int fman_kg_get_scheme_counter(struct fman_kg_regs *regs,
++                              uint8_t scheme_id,
++                              uint8_t hwport_id,
++                              uint32_t *counter)
++{
++      struct fman_kg_scheme_regs  *kgse_regs;
++      uint32_t                    tmp_reg;
++      int                         err;
++
++      kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]);
++ 
++      tmp_reg = build_ar_scheme(scheme_id, hwport_id, TRUE, FALSE);
++      err = fman_kg_write_ar_wait(regs, tmp_reg);
++
++      if (err != 0)
++              return err;
++
++      *counter = ioread32be(&kgse_regs->kgse_spc);
++
++      return 0;
++}
++
++int fman_kg_set_scheme_counter(struct fman_kg_regs *regs,
++                              uint8_t scheme_id,
++                              uint8_t hwport_id,
++                              uint32_t counter)
++{
++      struct fman_kg_scheme_regs *kgse_regs;
++      uint32_t tmp_reg;
++      int err;
++
++      kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]);
++
++      tmp_reg = build_ar_scheme(scheme_id, hwport_id, TRUE, FALSE);
++
++      err = fman_kg_write_ar_wait(regs, tmp_reg);
++      if (err != 0)
++              return err;
++ 
++      /* Keygen indirect access memory contains all scheme_id registers
++       * by now. Change only counter value. */
++      iowrite32be(counter, &kgse_regs->kgse_spc);
++
++      /* Write back scheme registers */
++      tmp_reg = build_ar_scheme(scheme_id, hwport_id, TRUE, TRUE);
++      err = fman_kg_write_ar_wait(regs, tmp_reg);
++
++      return err;
++}
++
++uint32_t fman_kg_get_schemes_total_counter(struct fman_kg_regs *regs)
++{
++    return ioread32be(&regs->fmkg_tpc);
++}
++
++int fman_kg_build_cls_plan(struct fman_kg_cls_plan_params *params,
++                              struct fman_kg_cp_regs *cls_plan_regs)
++{
++      uint8_t entries_set, entry_bit;
++      int i;
++
++      /* Zero out all group's register */
++      memset(cls_plan_regs, 0, sizeof(struct fman_kg_cp_regs));
++
++      /* Go over all classification entries in params->entries_mask and
++       * configure the corresponding cpe register */
++      entries_set = params->entries_mask;
++      for (i = 0; entries_set; i++) {
++              entry_bit = (uint8_t)(0x80 >> i);
++              if ((entry_bit & entries_set) == 0)
++                      continue;
++              entries_set ^= entry_bit;
++              cls_plan_regs->kgcpe[i] = params->mask_vector[i];
++      }
++
++      return 0;
++}
++
++int fman_kg_write_cls_plan(struct fman_kg_regs *regs,
++                              uint8_t grp_id,
++                              uint8_t entries_mask,
++                              uint8_t hwport_id,
++                              struct fman_kg_cp_regs *cls_plan_regs)
++{
++      struct fman_kg_cp_regs *kgcpe_regs;
++      uint32_t tmp_reg;
++      int i, err;
++
++      /* Check group index is valid and the group isn't empty */
++      if (grp_id >= FM_KG_CLS_PLAN_GRPS_NUM)
++              return -EINVAL;
++
++      /* Write indirect classification plan registers */
++      kgcpe_regs = (struct fman_kg_cp_regs *)&(regs->fmkg_indirect[0]);
++
++      for (i = 0; i < FM_KG_NUM_CLS_PLAN_ENTR; i++) {
++              iowrite32be(cls_plan_regs->kgcpe[i], &kgcpe_regs->kgcpe[i]);
++      }
++
++      tmp_reg = build_ar_cls_plan(grp_id, entries_mask, hwport_id, TRUE);
++      err = fman_kg_write_ar_wait(regs, tmp_reg);
++      return err;
++}
++
++int fman_kg_write_bind_schemes(struct fman_kg_regs *regs,
++                              uint8_t hwport_id,
++                              uint32_t schemes)
++{
++      struct fman_kg_pe_regs *kg_pe_regs;
++      uint32_t tmp_reg;
++      int err;
++
++      kg_pe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]);
++
++      iowrite32be(schemes, &kg_pe_regs->fmkg_pe_sp);
++
++      tmp_reg = build_ar_bind_scheme(hwport_id, TRUE);
++      err = fman_kg_write_ar_wait(regs, tmp_reg);
++      return err;
++}
++
++int fman_kg_build_bind_cls_plans(uint8_t grp_base,
++                                      uint8_t grp_mask,
++                                      uint32_t *bind_cls_plans)
++{
++      /* Check grp_base and grp_mask are 5-bits values */
++      if ((grp_base & ~0x0000001F) || (grp_mask & ~0x0000001F))
++              return -EINVAL;
++
++      *bind_cls_plans = (uint32_t) ((grp_mask << FMAN_KG_PE_CPP_MASK_SHIFT) | grp_base);
++      return 0;
++}
++
++
++int fman_kg_write_bind_cls_plans(struct fman_kg_regs *regs,
++                                      uint8_t hwport_id,
++                                      uint32_t bind_cls_plans)
++{
++      struct fman_kg_pe_regs *kg_pe_regs;
++      uint32_t tmp_reg;
++      int err;
++
++      kg_pe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]);
++
++      iowrite32be(bind_cls_plans, &kg_pe_regs->fmkg_pe_cpp);
++
++      tmp_reg = build_ar_bind_cls_plan(hwport_id, TRUE);
++      err = fman_kg_write_ar_wait(regs, tmp_reg);
++      return err;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_prs.c
+@@ -0,0 +1,129 @@
++/*
++ * Copyright 2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "fsl_fman_prs.h"
++
++uint32_t fman_prs_get_err_event(struct fman_prs_regs *regs, uint32_t ev_mask)
++{
++      return ioread32be(&regs->fmpr_perr) & ev_mask;
++}
++
++uint32_t fman_prs_get_err_ev_mask(struct fman_prs_regs *regs)
++{
++      return ioread32be(&regs->fmpr_perer);
++}
++
++void fman_prs_ack_err_event(struct fman_prs_regs *regs, uint32_t event)
++{
++      iowrite32be(event, &regs->fmpr_perr);
++}
++
++uint32_t fman_prs_get_expt_event(struct fman_prs_regs *regs, uint32_t ev_mask)
++{
++      return ioread32be(&regs->fmpr_pevr) & ev_mask;
++}
++
++uint32_t fman_prs_get_expt_ev_mask(struct fman_prs_regs *regs)
++{
++      return ioread32be(&regs->fmpr_pever);
++}
++
++void fman_prs_ack_expt_event(struct fman_prs_regs *regs, uint32_t event)
++{
++      iowrite32be(event, &regs->fmpr_pevr);
++}
++
++void fman_prs_defconfig(struct fman_prs_cfg *cfg)
++{
++      cfg->port_id_stat = 0;
++      cfg->max_prs_cyc_lim = DEFAULT_MAX_PRS_CYC_LIM;
++      cfg->prs_exceptions = 0x03000000;
++}
++
++int fman_prs_init(struct fman_prs_regs *regs, struct fman_prs_cfg *cfg)
++{
++      uint32_t tmp;
++
++      iowrite32be(cfg->max_prs_cyc_lim, &regs->fmpr_rpclim);
++      iowrite32be((FM_PCD_PRS_SINGLE_ECC | FM_PCD_PRS_PORT_IDLE_STS),
++                      &regs->fmpr_pevr);
++
++      if (cfg->prs_exceptions & FM_PCD_EX_PRS_SINGLE_ECC)
++              iowrite32be(FM_PCD_PRS_SINGLE_ECC, &regs->fmpr_pever);
++      else
++              iowrite32be(0, &regs->fmpr_pever);
++
++      iowrite32be(FM_PCD_PRS_DOUBLE_ECC, &regs->fmpr_perr);
++
++      tmp = 0;
++      if (cfg->prs_exceptions & FM_PCD_EX_PRS_DOUBLE_ECC)
++              tmp |= FM_PCD_PRS_DOUBLE_ECC;
++      iowrite32be(tmp, &regs->fmpr_perer);
++
++      iowrite32be(cfg->port_id_stat, &regs->fmpr_ppsc);
++
++      return 0;
++}
++
++void fman_prs_enable(struct fman_prs_regs *regs)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&regs->fmpr_rpimac) | FM_PCD_PRS_RPIMAC_EN;
++      iowrite32be(tmp, &regs->fmpr_rpimac);
++}
++
++void fman_prs_disable(struct fman_prs_regs *regs)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&regs->fmpr_rpimac) & ~FM_PCD_PRS_RPIMAC_EN;
++      iowrite32be(tmp, &regs->fmpr_rpimac);
++}
++
++int fman_prs_is_enabled(struct fman_prs_regs *regs)
++{
++      return ioread32be(&regs->fmpr_rpimac) & FM_PCD_PRS_RPIMAC_EN;
++}
++
++void fman_prs_set_stst_port_msk(struct fman_prs_regs *regs, uint32_t pid_msk)
++{
++      iowrite32be(pid_msk, &regs->fmpr_ppsc);
++}
++
++void fman_prs_set_stst(struct fman_prs_regs *regs, bool enable)
++{
++      if (enable)
++              iowrite32be(FM_PCD_PRS_PPSC_ALL_PORTS, &regs->fmpr_ppsc);
++      else
++              iowrite32be(0, &regs->fmpr_ppsc);
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile
+@@ -0,0 +1,15 @@
++#
++# Makefile for the Freescale Ethernet controllers
++#
++ccflags-y           += -DVERSION=\"\"
++#
++#Include netcomm SW specific definitions
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++
++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
++
++ccflags-y += -I$(NCSW_FM_INC)
++
++obj-y         += fsl-ncsw-Pcd.o
++
++fsl-ncsw-Pcd-objs     :=   fm_port.o fm_port_im.o fman_port.o
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c
+@@ -0,0 +1,6436 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_port.c
++
++ @Description   FM driver routines implementation.
++ *//***************************************************************************/
++#include "error_ext.h"
++#include "std_ext.h"
++#include "string_ext.h"
++#include "sprint_ext.h"
++#include "debug_ext.h"
++#include "fm_muram_ext.h"
++
++#include "fman_common.h"
++#include "fm_port.h"
++#include "fm_port_dsar.h"
++#include "common/general.h"
++
++/****************************************/
++/*       static functions               */
++/****************************************/
++static t_Error FmPortConfigAutoResForDeepSleepSupport1(t_FmPort *p_FmPort);
++
++static t_Error CheckInitParameters(t_FmPort *p_FmPort)
++{
++    t_FmPortDriverParam *p_Params = p_FmPort->p_FmPortDriverParam;
++    struct fman_port_cfg *p_DfltConfig = &p_Params->dfltCfg;
++    t_Error ans = E_OK;
++    uint32_t unusedMask;
++
++    if (p_FmPort->imEn)
++    {
++        if (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
++            if (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth
++                    > 2)
++                RETURN_ERROR(
++                        MAJOR,
++                        E_INVALID_VALUE,
++                        ("fifoDeqPipelineDepth for IM 10G can't be larger than 2"));
++
++        if ((ans = FmPortImCheckInitParameters(p_FmPort)) != E_OK)
++            return ERROR_CODE(ans);
++    }
++    else
++    {
++        /****************************************/
++        /*   Rx only                            */
++        /****************************************/
++        if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
++                || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
++        {
++            /* external buffer pools */
++            if (!p_Params->extBufPools.numOfPoolsUsed)
++                RETURN_ERROR(
++                        MAJOR,
++                        E_INVALID_VALUE,
++                        ("extBufPools.numOfPoolsUsed=0. At least one buffer pool must be defined"));
++
++            if (FmSpCheckBufPoolsParams(&p_Params->extBufPools,
++                                        p_Params->p_BackupBmPools,
++                                        &p_Params->bufPoolDepletion) != E_OK)
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
++
++            /* Check that part of IC that needs copying is small enough to enter start margin */
++            if (p_Params->intContext.size
++                    && (p_Params->intContext.size
++                            + p_Params->intContext.extBufOffset
++                            > p_Params->bufMargins.startMargins))
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                             ("intContext.size is larger than start margins"));
++
++            if ((p_Params->liodnOffset != (uint16_t)DPAA_LIODN_DONT_OVERRIDE)
++                    && (p_Params->liodnOffset & ~FM_LIODN_OFFSET_MASK))
++                RETURN_ERROR(
++                        MAJOR,
++                        E_INVALID_VALUE,
++                        ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1));
++
++#ifdef FM_NO_BACKUP_POOLS
++            if ((p_FmPort->fmRevInfo.majorRev != 4) && (p_FmPort->fmRevInfo.majorRev < 6))
++            if (p_FmPort->p_FmPortDriverParam->p_BackupBmPools)
++            RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("BackupBmPools"));
++#endif /* FM_NO_BACKUP_POOLS */
++        }
++
++        /****************************************/
++        /*   Non Rx ports                       */
++        /****************************************/
++        else
++        {
++            if (p_Params->deqSubPortal >= FM_MAX_NUM_OF_SUB_PORTALS)
++                RETURN_ERROR(
++                        MAJOR,
++                        E_INVALID_VALUE,
++                        (" deqSubPortal has to be in the range of 0 - %d", FM_MAX_NUM_OF_SUB_PORTALS));
++
++            /* to protect HW internal-context from overwrite */
++            if ((p_Params->intContext.size)
++                    && (p_Params->intContext.intContextOffset
++                            < MIN_TX_INT_OFFSET))
++                RETURN_ERROR(
++                        MAJOR,
++                        E_INVALID_VALUE,
++                        ("non-Rx intContext.intContextOffset can't be smaller than %d", MIN_TX_INT_OFFSET));
++
++            if ((p_FmPort->portType == e_FM_PORT_TYPE_TX)
++                    || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)
++                    /* in O/H DEFAULT_notSupported indicates that it is not supported and should not be checked */
++                    || (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth
++                            != DEFAULT_notSupported))
++            {
++                /* Check that not larger than 8 */
++                if ((!p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth)
++                        || (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth
++                                > MAX_FIFO_PIPELINE_DEPTH))
++                    RETURN_ERROR(
++                            MAJOR,
++                            E_INVALID_VALUE,
++                            ("fifoDeqPipelineDepth can't be larger than %d", MAX_FIFO_PIPELINE_DEPTH));
++            }
++        }
++
++        /****************************************/
++        /*   Rx Or Offline Parsing              */
++        /****************************************/
++        if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
++                || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
++                || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
++        {
++            if (!p_Params->dfltFqid)
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                             ("dfltFqid must be between 1 and 2^24-1"));
++#if defined(FM_CAPWAP_SUPPORT) && defined(FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004)
++            if (p_FmPort->p_FmPortDriverParam->bufferPrefixContent.manipExtraSpace % 16)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufferPrefixContent.manipExtraSpace has to be devidable by 16"));
++#endif /* defined(FM_CAPWAP_SUPPORT) && ... */
++        }
++
++        /****************************************/
++        /*   All ports                          */
++        /****************************************/
++        /* common BMI registers values */
++        /* Check that Queue Id is not larger than 2^24, and is not 0 */
++        if ((p_Params->errFqid & ~0x00FFFFFF) || !p_Params->errFqid)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                         ("errFqid must be between 1 and 2^24-1"));
++        if (p_Params->dfltFqid & ~0x00FFFFFF)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                         ("dfltFqid must be between 1 and 2^24-1"));
++    }
++
++    /****************************************/
++    /*   Rx only                            */
++    /****************************************/
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
++    {
++        if (p_DfltConfig->rx_pri_elevation % BMI_FIFO_UNITS)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("rxFifoPriElevationLevel has to be divisible by %d", BMI_FIFO_UNITS));
++        if ((p_DfltConfig->rx_pri_elevation < BMI_FIFO_UNITS)
++                || (p_DfltConfig->rx_pri_elevation > MAX_PORT_FIFO_SIZE))
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("rxFifoPriElevationLevel has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE));
++        if (p_DfltConfig->rx_fifo_thr % BMI_FIFO_UNITS)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("rxFifoThreshold has to be divisible by %d", BMI_FIFO_UNITS));
++        if ((p_DfltConfig->rx_fifo_thr < BMI_FIFO_UNITS)
++                || (p_DfltConfig->rx_fifo_thr > MAX_PORT_FIFO_SIZE))
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("rxFifoThreshold has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE));
++
++        /* Check that not larger than 16 */
++        if (p_DfltConfig->rx_cut_end_bytes > FRAME_END_DATA_SIZE)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("cutBytesFromEnd can't be larger than %d", FRAME_END_DATA_SIZE));
++
++        if (FmSpCheckBufMargins(&p_Params->bufMargins) != E_OK)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
++
++        /* extra FIFO size (allowed only to Rx ports) */
++        if (p_Params->setSizeOfFifo
++                && (p_FmPort->fifoBufs.extra % BMI_FIFO_UNITS))
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("fifoBufs.extra has to be divisible by %d", BMI_FIFO_UNITS));
++
++        if (p_Params->bufPoolDepletion.poolsGrpModeEnable
++                && !p_Params->bufPoolDepletion.numOfPools)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("bufPoolDepletion.numOfPools can not be 0 when poolsGrpModeEnable=TRUE"));
++#ifdef FM_CSI_CFED_LIMIT
++        if (p_FmPort->fmRevInfo.majorRev == 4)
++        {
++            /* Check that not larger than 16 */
++            if (p_DfltConfig->rx_cut_end_bytes + p_DfltConfig->checksum_bytes_ignore > FRAME_END_DATA_SIZE)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("cheksumLastBytesIgnore + cutBytesFromEnd can't be larger than %d", FRAME_END_DATA_SIZE));
++        }
++#endif /* FM_CSI_CFED_LIMIT */
++    }
++
++    /****************************************/
++    /*   Non Rx ports                       */
++    /****************************************/
++    /* extra FIFO size (allowed only to Rx ports) */
++    else
++        if (p_FmPort->fifoBufs.extra)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                         (" No fifoBufs.extra for non Rx ports"));
++
++    /****************************************/
++    /*   Tx only                            */
++    /****************************************/
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_TX)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G))
++    {
++        if (p_DfltConfig->tx_fifo_min_level % BMI_FIFO_UNITS)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("txFifoMinFillLevel has to be divisible by %d", BMI_FIFO_UNITS));
++        if (p_DfltConfig->tx_fifo_min_level > (MAX_PORT_FIFO_SIZE - 256))
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("txFifoMinFillLevel has to be in the range of 0 - %d", (MAX_PORT_FIFO_SIZE - 256)));
++        if (p_DfltConfig->tx_fifo_low_comf_level % BMI_FIFO_UNITS)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("txFifoLowComfLevel has to be divisible by %d", BMI_FIFO_UNITS));
++        if ((p_DfltConfig->tx_fifo_low_comf_level < BMI_FIFO_UNITS)
++                || (p_DfltConfig->tx_fifo_low_comf_level > MAX_PORT_FIFO_SIZE))
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("txFifoLowComfLevel has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE));
++
++        if (p_FmPort->portType == e_FM_PORT_TYPE_TX)
++            if (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth
++                    > 2)
++                RETURN_ERROR(
++                        MAJOR, E_INVALID_VALUE,
++                        ("fifoDeqPipelineDepth for 1G can't be larger than 2"));
++    }
++
++    /****************************************/
++    /*   Non Tx Ports                       */
++    /****************************************/
++    /* If discard override was selected , no frames may be discarded. */
++    else
++        if (p_DfltConfig->discard_override && p_Params->errorsToDiscard)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_CONFLICT,
++                    ("errorsToDiscard is not empty, but frmDiscardOverride selected (all discarded frames to be enqueued to error queue)."));
++
++    /****************************************/
++    /*   Rx and Offline parsing             */
++    /****************************************/
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
++    {
++        if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++            unusedMask = BMI_STATUS_OP_MASK_UNUSED;
++        else
++            unusedMask = BMI_STATUS_RX_MASK_UNUSED;
++
++        /* Check that no common bits with BMI_STATUS_MASK_UNUSED */
++        if (p_Params->errorsToDiscard & unusedMask)
++            RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
++                         ("errorsToDiscard contains undefined bits"));
++    }
++
++    /****************************************/
++    /*   Offline Ports                      */
++    /****************************************/
++#ifdef FM_OP_OPEN_DMA_MIN_LIMIT
++    if ((p_FmPort->fmRevInfo.majorRev >= 6)
++            && (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++            && p_Params->setNumOfOpenDmas
++            && (p_FmPort->openDmas.num < MIN_NUM_OF_OP_DMAS))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("For Offline port, openDmas.num can't be smaller than %d", MIN_NUM_OF_OP_DMAS));
++#endif /* FM_OP_OPEN_DMA_MIN_LIMIT */
++
++    /****************************************/
++    /*   Offline & HC Ports                 */
++    /****************************************/
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND))
++    {
++#ifndef FM_FRAME_END_PARAMS_FOR_OP
++        if ((p_FmPort->fmRevInfo.majorRev < 6) &&
++                (p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore != DEFAULT_notSupported))
++        /* this is an indication that user called config for this mode which is not supported in this integration */
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("cheksumLastBytesIgnore is available for Rx & Tx ports only"));
++#endif /* !FM_FRAME_END_PARAMS_FOR_OP */
++
++#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP
++        if ((!((p_FmPort->fmRevInfo.majorRev == 4) ||
++                                (p_FmPort->fmRevInfo.majorRev >= 6))) &&
++                (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth != DEFAULT_notSupported))
++        /* this is an indication that user called config for this mode which is not supported in this integration */
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("fifoDeqPipelineDepth is available for Tx ports only"));
++#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */
++    }
++
++    /****************************************/
++    /*   All ports                          */
++    /****************************************/
++    /* Check that not larger than 16 */
++    if ((p_Params->cheksumLastBytesIgnore > FRAME_END_DATA_SIZE)
++            && ((p_Params->cheksumLastBytesIgnore != DEFAULT_notSupported)))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("cheksumLastBytesIgnore can't be larger than %d", FRAME_END_DATA_SIZE));
++
++    if (FmSpCheckIntContextParams(&p_Params->intContext) != E_OK)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
++
++    /* common BMI registers values */
++    if (p_Params->setNumOfTasks
++            && ((!p_FmPort->tasks.num)
++                    || (p_FmPort->tasks.num > MAX_NUM_OF_TASKS)))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("tasks.num can't be larger than %d", MAX_NUM_OF_TASKS));
++    if (p_Params->setNumOfTasks
++            && (p_FmPort->tasks.extra > MAX_NUM_OF_EXTRA_TASKS))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("tasks.extra can't be larger than %d", MAX_NUM_OF_EXTRA_TASKS));
++    if (p_Params->setNumOfOpenDmas
++            && ((!p_FmPort->openDmas.num)
++                    || (p_FmPort->openDmas.num > MAX_NUM_OF_DMAS)))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("openDmas.num can't be larger than %d", MAX_NUM_OF_DMAS));
++    if (p_Params->setNumOfOpenDmas
++            && (p_FmPort->openDmas.extra > MAX_NUM_OF_EXTRA_DMAS))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("openDmas.extra can't be larger than %d", MAX_NUM_OF_EXTRA_DMAS));
++    if (p_Params->setSizeOfFifo
++            && (!p_FmPort->fifoBufs.num
++                    || (p_FmPort->fifoBufs.num > MAX_PORT_FIFO_SIZE)))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("fifoBufs.num has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE));
++    if (p_Params->setSizeOfFifo && (p_FmPort->fifoBufs.num % BMI_FIFO_UNITS))
++        RETURN_ERROR(
++                MAJOR, E_INVALID_VALUE,
++                ("fifoBufs.num has to be divisible by %d", BMI_FIFO_UNITS));
++
++#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
++    if (p_FmPort->fmRevInfo.majorRev == 4)
++    if (p_FmPort->p_FmPortDriverParam->deqPrefetchOption != DEFAULT_notSupported)
++    /* this is an indication that user called config for this mode which is not supported in this integration */
++    RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("deqPrefetchOption"));
++#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
++
++    return E_OK;
++}
++
++static t_Error VerifySizeOfFifo(t_FmPort *p_FmPort)
++{
++    uint32_t minFifoSizeRequired = 0, optFifoSizeForB2B = 0;
++
++    /*************************/
++    /*    TX PORTS           */
++    /*************************/
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_TX)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G))
++    {
++        minFifoSizeRequired =
++                (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS)
++                        + (3 * BMI_FIFO_UNITS));
++        if (!p_FmPort->imEn)
++            minFifoSizeRequired +=
++                    p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth
++                            * BMI_FIFO_UNITS;
++
++        optFifoSizeForB2B = minFifoSizeRequired;
++
++        /* Add some margin for back-to-back capability to improve performance,
++         allows the hardware to pipeline new frame dma while the previous
++         frame not yet transmitted. */
++        if (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)
++            optFifoSizeForB2B += 3 * BMI_FIFO_UNITS;
++        else
++            optFifoSizeForB2B += 2 * BMI_FIFO_UNITS;
++    }
++
++    /*************************/
++    /*    RX IM PORTS        */
++    /*************************/
++    else
++        if (((p_FmPort->portType == e_FM_PORT_TYPE_RX)
++                || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
++                && p_FmPort->imEn)
++        {
++            optFifoSizeForB2B =
++                    minFifoSizeRequired =
++                            (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS)
++                                    + (4 * BMI_FIFO_UNITS));
++        }
++
++        /*************************/
++        /*    RX non-IM PORTS    */
++        /*************************/
++        else
++            if (((p_FmPort->portType == e_FM_PORT_TYPE_RX)
++                    || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
++                    && !p_FmPort->imEn)
++            {
++                if (p_FmPort->fmRevInfo.majorRev == 4)
++                {
++                    if (p_FmPort->rxPoolsParams.numOfPools == 1)
++                        minFifoSizeRequired = 8 * BMI_FIFO_UNITS;
++                    else
++                        minFifoSizeRequired =
++                                (uint32_t)(ROUND_UP(p_FmPort->rxPoolsParams.secondLargestBufSize, BMI_FIFO_UNITS)
++                                        + (7 * BMI_FIFO_UNITS));
++                }
++                else
++                {
++#if (DPAA_VERSION >= 11)
++                    minFifoSizeRequired =
++                            (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS)
++                                    + (5 * BMI_FIFO_UNITS));
++                    /* 4 according to spec + 1 for FOF>0 */
++#else
++                    minFifoSizeRequired = (uint32_t)
++                    (ROUND_UP(MIN(p_FmPort->maxFrameLength, p_FmPort->rxPoolsParams.largestBufSize), BMI_FIFO_UNITS)
++                            + (7*BMI_FIFO_UNITS));
++#endif /* (DPAA_VERSION >= 11) */
++                }
++
++                optFifoSizeForB2B = minFifoSizeRequired;
++
++                /* Add some margin for back-to-back capability to improve performance,
++                 allows the hardware to pipeline new frame dma while the previous
++                 frame not yet transmitted. */
++                if (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
++                    optFifoSizeForB2B += 8 * BMI_FIFO_UNITS;
++                else
++                    optFifoSizeForB2B += 3 * BMI_FIFO_UNITS;
++            }
++
++            /* For O/H ports, check fifo size and update if necessary */
++            else
++                if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++                        || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND))
++                {
++#if (DPAA_VERSION >= 11)
++                    optFifoSizeForB2B =
++                            minFifoSizeRequired =
++                                    (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS)
++                                            + ((p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth
++                                                    + 5) * BMI_FIFO_UNITS));
++                    /* 4 according to spec + 1 for FOF>0 */
++#else
++                    optFifoSizeForB2B = minFifoSizeRequired = (uint32_t)((p_FmPort->tasks.num + 2) * BMI_FIFO_UNITS);
++#endif /* (DPAA_VERSION >= 11) */
++                }
++
++    ASSERT_COND(minFifoSizeRequired > 0);
++    ASSERT_COND(optFifoSizeForB2B >= minFifoSizeRequired);
++
++    /* Verify the size  */
++    if (p_FmPort->fifoBufs.num < minFifoSizeRequired)
++        DBG(INFO,
++           ("FIFO size is %d and should be enlarged to %d bytes",p_FmPort->fifoBufs.num, minFifoSizeRequired));
++    else if (p_FmPort->fifoBufs.num < optFifoSizeForB2B)
++        DBG(INFO,
++          ("For back-to-back frames processing, FIFO size is %d and needs to enlarge to %d bytes", p_FmPort->fifoBufs.num, optFifoSizeForB2B));
++
++    return E_OK;
++}
++
++static void FmPortDriverParamFree(t_FmPort *p_FmPort)
++{
++    if (p_FmPort->p_FmPortDriverParam)
++    {
++        XX_Free(p_FmPort->p_FmPortDriverParam);
++        p_FmPort->p_FmPortDriverParam = NULL;
++    }
++}
++
++static t_Error SetExtBufferPools(t_FmPort *p_FmPort)
++{
++    t_FmExtPools *p_ExtBufPools = &p_FmPort->p_FmPortDriverParam->extBufPools;
++    t_FmBufPoolDepletion *p_BufPoolDepletion =
++            &p_FmPort->p_FmPortDriverParam->bufPoolDepletion;
++    uint8_t orderedArray[FM_PORT_MAX_NUM_OF_EXT_POOLS];
++    uint16_t sizesArray[BM_MAX_NUM_OF_POOLS];
++    int i = 0, j = 0, err;
++    struct fman_port_bpools bpools;
++
++    memset(&orderedArray, 0, sizeof(uint8_t) * FM_PORT_MAX_NUM_OF_EXT_POOLS);
++    memset(&sizesArray, 0, sizeof(uint16_t) * BM_MAX_NUM_OF_POOLS);
++    memcpy(&p_FmPort->extBufPools, p_ExtBufPools, sizeof(t_FmExtPools));
++
++    FmSpSetBufPoolsInAscOrderOfBufSizes(p_ExtBufPools, orderedArray,
++                                        sizesArray);
++
++    /* Prepare flibs bpools structure */
++    memset(&bpools, 0, sizeof(struct fman_port_bpools));
++    bpools.count = p_ExtBufPools->numOfPoolsUsed;
++    bpools.counters_enable = TRUE;
++    for (i = 0; i < p_ExtBufPools->numOfPoolsUsed; i++)
++    {
++        bpools.bpool[i].bpid = orderedArray[i];
++        bpools.bpool[i].size = sizesArray[orderedArray[i]];
++        /* functionality available only for some derivatives (limited by config) */
++        if (p_FmPort->p_FmPortDriverParam->p_BackupBmPools)
++            for (j = 0;
++                    j
++                            < p_FmPort->p_FmPortDriverParam->p_BackupBmPools->numOfBackupPools;
++                    j++)
++                if (orderedArray[i]
++                        == p_FmPort->p_FmPortDriverParam->p_BackupBmPools->poolIds[j])
++                {
++                    bpools.bpool[i].is_backup = TRUE;
++                    break;
++                }
++    }
++
++    /* save pools parameters for later use */
++    p_FmPort->rxPoolsParams.numOfPools = p_ExtBufPools->numOfPoolsUsed;
++    p_FmPort->rxPoolsParams.largestBufSize =
++            sizesArray[orderedArray[p_ExtBufPools->numOfPoolsUsed - 1]];
++    p_FmPort->rxPoolsParams.secondLargestBufSize =
++            sizesArray[orderedArray[p_ExtBufPools->numOfPoolsUsed - 2]];
++
++    /* FMBM_RMPD reg. - pool depletion */
++    if (p_BufPoolDepletion->poolsGrpModeEnable)
++    {
++        bpools.grp_bp_depleted_num = p_BufPoolDepletion->numOfPools;
++        for (i = 0; i < BM_MAX_NUM_OF_POOLS; i++)
++        {
++            if (p_BufPoolDepletion->poolsToConsider[i])
++            {
++                for (j = 0; j < p_ExtBufPools->numOfPoolsUsed; j++)
++                {
++                    if (i == orderedArray[j])
++                    {
++                        bpools.bpool[j].grp_bp_depleted = TRUE;
++                        break;
++                    }
++                }
++            }
++        }
++    }
++
++    if (p_BufPoolDepletion->singlePoolModeEnable)
++    {
++        for (i = 0; i < BM_MAX_NUM_OF_POOLS; i++)
++        {
++            if (p_BufPoolDepletion->poolsToConsiderForSingleMode[i])
++            {
++                for (j = 0; j < p_ExtBufPools->numOfPoolsUsed; j++)
++                {
++                    if (i == orderedArray[j])
++                    {
++                        bpools.bpool[j].single_bp_depleted = TRUE;
++                        break;
++                    }
++                }
++            }
++        }
++    }
++
++#if (DPAA_VERSION >= 11)
++    /* fill QbbPEV */
++    if (p_BufPoolDepletion->poolsGrpModeEnable
++            || p_BufPoolDepletion->singlePoolModeEnable)
++    {
++        for (i = 0; i < FM_MAX_NUM_OF_PFC_PRIORITIES; i++)
++        {
++            if (p_BufPoolDepletion->pfcPrioritiesEn[i] == TRUE)
++            {
++                bpools.bpool[i].pfc_priorities_en = TRUE;
++            }
++        }
++    }
++#endif /* (DPAA_VERSION >= 11) */
++
++    /* Issue flibs function */
++    err = fman_port_set_bpools(&p_FmPort->port, &bpools);
++    if (err != 0)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_bpools"));
++
++    if (p_FmPort->p_FmPortDriverParam->p_BackupBmPools)
++        XX_Free(p_FmPort->p_FmPortDriverParam->p_BackupBmPools);
++
++    return E_OK;
++}
++
++static t_Error ClearPerfCnts(t_FmPort *p_FmPort)
++{
++    if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++        FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL, 0);
++    FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL, 0);
++    FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL, 0);
++    FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL, 0);
++    return E_OK;
++}
++
++static t_Error InitLowLevelDriver(t_FmPort *p_FmPort)
++{
++    t_FmPortDriverParam *p_DriverParams = p_FmPort->p_FmPortDriverParam;
++    struct fman_port_params portParams;
++    uint32_t tmpVal;
++    t_Error err;
++
++    /* Set up flibs parameters and issue init function */
++
++    memset(&portParams, 0, sizeof(struct fman_port_params));
++    portParams.discard_mask = p_DriverParams->errorsToDiscard;
++    portParams.dflt_fqid = p_DriverParams->dfltFqid;
++    portParams.err_fqid = p_DriverParams->errFqid;
++    portParams.deq_sp = p_DriverParams->deqSubPortal;
++    portParams.dont_release_buf = p_DriverParams->dontReleaseBuf;
++    switch (p_FmPort->portType)
++    {
++        case (e_FM_PORT_TYPE_RX_10G):
++        case (e_FM_PORT_TYPE_RX):
++            portParams.err_mask = (RX_ERRS_TO_ENQ & ~portParams.discard_mask);
++            if (!p_FmPort->imEn)
++            {
++                if (p_DriverParams->forwardReuseIntContext)
++                    p_DriverParams->dfltCfg.rx_fd_bits =
++                            (uint8_t)(BMI_PORT_RFNE_FRWD_RPD >> 24);
++            }
++            break;
++
++        case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++            portParams.err_mask = (OP_ERRS_TO_ENQ & ~portParams.discard_mask);
++            break;
++            break;
++
++        default:
++            break;
++    }
++
++    tmpVal =
++            (uint32_t)(
++                    (p_FmPort->internalBufferOffset % OFFSET_UNITS) ? (p_FmPort->internalBufferOffset
++                            / OFFSET_UNITS + 1) :
++                            (p_FmPort->internalBufferOffset / OFFSET_UNITS));
++    p_FmPort->internalBufferOffset = (uint8_t)(tmpVal * OFFSET_UNITS);
++    p_DriverParams->dfltCfg.int_buf_start_margin =
++            p_FmPort->internalBufferOffset;
++
++    p_DriverParams->dfltCfg.ext_buf_start_margin =
++            p_DriverParams->bufMargins.startMargins;
++    p_DriverParams->dfltCfg.ext_buf_end_margin =
++            p_DriverParams->bufMargins.endMargins;
++
++    p_DriverParams->dfltCfg.ic_ext_offset =
++            p_DriverParams->intContext.extBufOffset;
++    p_DriverParams->dfltCfg.ic_int_offset =
++            p_DriverParams->intContext.intContextOffset;
++    p_DriverParams->dfltCfg.ic_size = p_DriverParams->intContext.size;
++
++    p_DriverParams->dfltCfg.stats_counters_enable = TRUE;
++    p_DriverParams->dfltCfg.perf_counters_enable = TRUE;
++    p_DriverParams->dfltCfg.queue_counters_enable = TRUE;
++
++    p_DriverParams->dfltCfg.perf_cnt_params.task_val =
++            (uint8_t)p_FmPort->tasks.num;
++    if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING ||
++    p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)p_DriverParams->dfltCfg.perf_cnt_params.queue_val = 0;
++    else
++    p_DriverParams->dfltCfg.perf_cnt_params.queue_val = 1;
++    p_DriverParams->dfltCfg.perf_cnt_params.dma_val =
++            (uint8_t)p_FmPort->openDmas.num;
++    p_DriverParams->dfltCfg.perf_cnt_params.fifo_val = p_FmPort->fifoBufs.num;
++
++    if (0
++            != fman_port_init(&p_FmPort->port, &p_DriverParams->dfltCfg,
++                              &portParams))
++        RETURN_ERROR(MAJOR, E_NO_DEVICE, ("fman_port_init"));
++
++    if (p_FmPort->imEn && ((err = FmPortImInit(p_FmPort)) != E_OK))
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    else
++    {
++        //  from QMIInit
++        if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++                && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
++        {
++            if (p_DriverParams->deqPrefetchOption == e_FM_PORT_DEQ_NO_PREFETCH)
++                FmSetPortPreFetchConfiguration(p_FmPort->h_Fm, p_FmPort->portId,
++                                               FALSE);
++            else
++                FmSetPortPreFetchConfiguration(p_FmPort->h_Fm, p_FmPort->portId,
++                                               TRUE);
++        }
++    }
++    /* The code bellow is a trick so the FM will not release the buffer
++     to BM nor will try to enqueue the frame to QM */
++    if (((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_TX)) && (!p_FmPort->imEn))
++    {
++        if (!p_DriverParams->dfltFqid && p_DriverParams->dontReleaseBuf)
++        {
++            /* override fmbm_tcfqid 0 with a false non-0 value. This will force FM to
++             * act according to tfene. Otherwise, if fmbm_tcfqid is 0 the FM will release
++             * buffers to BM regardless of fmbm_tfene
++             */
++            WRITE_UINT32(p_FmPort->port.bmi_regs->tx.fmbm_tcfqid, 0xFFFFFF);
++            WRITE_UINT32(p_FmPort->port.bmi_regs->tx.fmbm_tfene,
++                         NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE);
++        }
++    }
++
++    return E_OK;
++}
++
++static bool CheckRxBmiCounter(t_FmPort *p_FmPort, e_FmPortCounters counter)
++{
++    UNUSED(p_FmPort);
++
++    switch (counter)
++    {
++        case (e_FM_PORT_COUNTERS_CYCLE):
++        case (e_FM_PORT_COUNTERS_TASK_UTIL):
++        case (e_FM_PORT_COUNTERS_QUEUE_UTIL):
++        case (e_FM_PORT_COUNTERS_DMA_UTIL):
++        case (e_FM_PORT_COUNTERS_FIFO_UTIL):
++        case (e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION):
++        case (e_FM_PORT_COUNTERS_FRAME):
++        case (e_FM_PORT_COUNTERS_DISCARD_FRAME):
++        case (e_FM_PORT_COUNTERS_RX_BAD_FRAME):
++        case (e_FM_PORT_COUNTERS_RX_LARGE_FRAME):
++        case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME):
++        case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR):
++        case (e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD):
++        case (e_FM_PORT_COUNTERS_DEALLOC_BUF):
++        case (e_FM_PORT_COUNTERS_PREPARE_TO_ENQUEUE_COUNTER):
++            return TRUE;
++        default:
++            return FALSE;
++    }
++}
++
++static bool CheckTxBmiCounter(t_FmPort *p_FmPort, e_FmPortCounters counter)
++{
++    UNUSED(p_FmPort);
++
++    switch (counter)
++    {
++        case (e_FM_PORT_COUNTERS_CYCLE):
++        case (e_FM_PORT_COUNTERS_TASK_UTIL):
++        case (e_FM_PORT_COUNTERS_QUEUE_UTIL):
++        case (e_FM_PORT_COUNTERS_DMA_UTIL):
++        case (e_FM_PORT_COUNTERS_FIFO_UTIL):
++        case (e_FM_PORT_COUNTERS_FRAME):
++        case (e_FM_PORT_COUNTERS_DISCARD_FRAME):
++        case (e_FM_PORT_COUNTERS_LENGTH_ERR):
++        case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT):
++        case (e_FM_PORT_COUNTERS_DEALLOC_BUF):
++            return TRUE;
++        default:
++            return FALSE;
++    }
++}
++
++static bool CheckOhBmiCounter(t_FmPort *p_FmPort, e_FmPortCounters counter)
++{
++    switch (counter)
++    {
++        case (e_FM_PORT_COUNTERS_CYCLE):
++        case (e_FM_PORT_COUNTERS_TASK_UTIL):
++        case (e_FM_PORT_COUNTERS_DMA_UTIL):
++        case (e_FM_PORT_COUNTERS_FIFO_UTIL):
++        case (e_FM_PORT_COUNTERS_FRAME):
++        case (e_FM_PORT_COUNTERS_DISCARD_FRAME):
++        case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR):
++        case (e_FM_PORT_COUNTERS_WRED_DISCARD):
++        case (e_FM_PORT_COUNTERS_LENGTH_ERR):
++        case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT):
++        case (e_FM_PORT_COUNTERS_DEALLOC_BUF):
++            return TRUE;
++        case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME):
++            if (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)
++                return FALSE;
++            else
++                return TRUE;
++        default:
++            return FALSE;
++    }
++}
++
++static t_Error BmiPortCheckAndGetCounterType(
++        t_FmPort *p_FmPort, e_FmPortCounters counter,
++        enum fman_port_stats_counters *p_StatsType,
++        enum fman_port_perf_counters *p_PerfType, bool *p_IsStats)
++{
++    volatile uint32_t *p_Reg;
++    bool isValid;
++
++    switch (p_FmPort->portType)
++    {
++        case (e_FM_PORT_TYPE_RX_10G):
++        case (e_FM_PORT_TYPE_RX):
++            p_Reg = &p_FmPort->port.bmi_regs->rx.fmbm_rstc;
++            isValid = CheckRxBmiCounter(p_FmPort, counter);
++            break;
++        case (e_FM_PORT_TYPE_TX_10G):
++        case (e_FM_PORT_TYPE_TX):
++            p_Reg = &p_FmPort->port.bmi_regs->tx.fmbm_tstc;
++            isValid = CheckTxBmiCounter(p_FmPort, counter);
++            break;
++        case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++        case (e_FM_PORT_TYPE_OH_HOST_COMMAND):
++            p_Reg = &p_FmPort->port.bmi_regs->oh.fmbm_ostc;
++            isValid = CheckOhBmiCounter(p_FmPort, counter);
++            break;
++        default:
++            RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported port type"));
++    }
++
++    if (!isValid)
++        RETURN_ERROR(MINOR, E_INVALID_STATE,
++                     ("Requested counter is not available for this port type"));
++
++    /* check that counters are enabled */
++    switch (counter)
++    {
++        case (e_FM_PORT_COUNTERS_CYCLE):
++        case (e_FM_PORT_COUNTERS_TASK_UTIL):
++        case (e_FM_PORT_COUNTERS_QUEUE_UTIL):
++        case (e_FM_PORT_COUNTERS_DMA_UTIL):
++        case (e_FM_PORT_COUNTERS_FIFO_UTIL):
++        case (e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION):
++            /* performance counters - may be read when disabled */
++            *p_IsStats = FALSE;
++            break;
++        case (e_FM_PORT_COUNTERS_FRAME):
++        case (e_FM_PORT_COUNTERS_DISCARD_FRAME):
++        case (e_FM_PORT_COUNTERS_DEALLOC_BUF):
++        case (e_FM_PORT_COUNTERS_RX_BAD_FRAME):
++        case (e_FM_PORT_COUNTERS_RX_LARGE_FRAME):
++        case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME):
++        case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR):
++        case (e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD):
++        case (e_FM_PORT_COUNTERS_LENGTH_ERR):
++        case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT):
++        case (e_FM_PORT_COUNTERS_WRED_DISCARD):
++            *p_IsStats = TRUE;
++            if (!(GET_UINT32(*p_Reg) & BMI_COUNTERS_EN))
++                RETURN_ERROR(MINOR, E_INVALID_STATE,
++                             ("Requested counter was not enabled"));
++            break;
++        default:
++            break;
++    }
++
++    /* Set counter */
++    switch (counter)
++    {
++        case (e_FM_PORT_COUNTERS_CYCLE):
++            *p_PerfType = E_FMAN_PORT_PERF_CNT_CYCLE;
++            break;
++        case (e_FM_PORT_COUNTERS_TASK_UTIL):
++            *p_PerfType = E_FMAN_PORT_PERF_CNT_TASK_UTIL;
++            break;
++        case (e_FM_PORT_COUNTERS_QUEUE_UTIL):
++            *p_PerfType = E_FMAN_PORT_PERF_CNT_QUEUE_UTIL;
++            break;
++        case (e_FM_PORT_COUNTERS_DMA_UTIL):
++            *p_PerfType = E_FMAN_PORT_PERF_CNT_DMA_UTIL;
++            break;
++        case (e_FM_PORT_COUNTERS_FIFO_UTIL):
++            *p_PerfType = E_FMAN_PORT_PERF_CNT_FIFO_UTIL;
++            break;
++        case (e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION):
++            *p_PerfType = E_FMAN_PORT_PERF_CNT_RX_PAUSE;
++            break;
++        case (e_FM_PORT_COUNTERS_FRAME):
++            *p_StatsType = E_FMAN_PORT_STATS_CNT_FRAME;
++            break;
++        case (e_FM_PORT_COUNTERS_DISCARD_FRAME):
++            *p_StatsType = E_FMAN_PORT_STATS_CNT_DISCARD;
++            break;
++        case (e_FM_PORT_COUNTERS_DEALLOC_BUF):
++            *p_StatsType = E_FMAN_PORT_STATS_CNT_DEALLOC_BUF;
++            break;
++        case (e_FM_PORT_COUNTERS_RX_BAD_FRAME):
++            *p_StatsType = E_FMAN_PORT_STATS_CNT_RX_BAD_FRAME;
++            break;
++        case (e_FM_PORT_COUNTERS_RX_LARGE_FRAME):
++            *p_StatsType = E_FMAN_PORT_STATS_CNT_RX_LARGE_FRAME;
++            break;
++        case (e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD):
++            *p_StatsType = E_FMAN_PORT_STATS_CNT_RX_OUT_OF_BUF;
++            break;
++        case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME):
++            *p_StatsType = E_FMAN_PORT_STATS_CNT_FILTERED_FRAME;
++            break;
++        case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR):
++            *p_StatsType = E_FMAN_PORT_STATS_CNT_DMA_ERR;
++            break;
++        case (e_FM_PORT_COUNTERS_WRED_DISCARD):
++            *p_StatsType = E_FMAN_PORT_STATS_CNT_WRED_DISCARD;
++            break;
++        case (e_FM_PORT_COUNTERS_LENGTH_ERR):
++            *p_StatsType = E_FMAN_PORT_STATS_CNT_LEN_ERR;
++            break;
++        case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT):
++            *p_StatsType = E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT;
++            break;
++        default:
++            break;
++    }
++
++    return E_OK;
++}
++
++static t_Error AdditionalPrsParams(t_FmPort *p_FmPort,
++                                   t_FmPcdPrsAdditionalHdrParams *p_HdrParams,
++                                   uint32_t *p_SoftSeqAttachReg)
++{
++    uint8_t hdrNum, Ipv4HdrNum;
++    u_FmPcdHdrPrsOpts *p_prsOpts;
++    uint32_t tmpReg = *p_SoftSeqAttachReg, tmpPrsOffset;
++
++    if (IS_PRIVATE_HEADER(p_HdrParams->hdr)
++            || IS_SPECIAL_HEADER(p_HdrParams->hdr))
++        RETURN_ERROR(
++                MAJOR, E_NOT_SUPPORTED,
++                ("No additional parameters for private or special headers."));
++
++    if (p_HdrParams->errDisable)
++        tmpReg |= PRS_HDR_ERROR_DIS;
++
++    /* Set parser options */
++    if (p_HdrParams->usePrsOpts)
++    {
++        p_prsOpts = &p_HdrParams->prsOpts;
++        switch (p_HdrParams->hdr)
++        {
++            case (HEADER_TYPE_MPLS):
++                if (p_prsOpts->mplsPrsOptions.labelInterpretationEnable)
++                    tmpReg |= PRS_HDR_MPLS_LBL_INTER_EN;
++                hdrNum = GetPrsHdrNum(p_prsOpts->mplsPrsOptions.nextParse);
++                if (hdrNum == ILLEGAL_HDR_NUM)
++                    RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
++                Ipv4HdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4);
++                if (hdrNum < Ipv4HdrNum)
++                    RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                                 ("Header must be equal or higher than IPv4"));
++                tmpReg |= ((uint32_t)hdrNum * PRS_HDR_ENTRY_SIZE)
++                        << PRS_HDR_MPLS_NEXT_HDR_SHIFT;
++                break;
++            case (HEADER_TYPE_PPPoE):
++                if (p_prsOpts->pppoePrsOptions.enableMTUCheck)
++                    tmpReg |= PRS_HDR_PPPOE_MTU_CHECK_EN;
++                break;
++            case (HEADER_TYPE_IPv6):
++                if (p_prsOpts->ipv6PrsOptions.routingHdrEnable)
++                    tmpReg |= PRS_HDR_IPV6_ROUTE_HDR_EN;
++                break;
++            case (HEADER_TYPE_TCP):
++                if (p_prsOpts->tcpPrsOptions.padIgnoreChecksum)
++                    tmpReg |= PRS_HDR_TCP_PAD_REMOVAL;
++                else
++                    tmpReg &= ~PRS_HDR_TCP_PAD_REMOVAL;
++                break;
++            case (HEADER_TYPE_UDP):
++                if (p_prsOpts->udpPrsOptions.padIgnoreChecksum)
++                    tmpReg |= PRS_HDR_UDP_PAD_REMOVAL;
++                else
++                    tmpReg &= ~PRS_HDR_UDP_PAD_REMOVAL;
++                break;
++            default:
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid header"));
++        }
++    }
++
++    /* set software parsing (address is divided in 2 since parser uses 2 byte access. */
++    if (p_HdrParams->swPrsEnable)
++    {
++        tmpPrsOffset = FmPcdGetSwPrsOffset(p_FmPort->h_FmPcd, p_HdrParams->hdr,
++                                           p_HdrParams->indexPerHdr);
++        if (tmpPrsOffset == ILLEGAL_BASE)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
++        tmpReg |= (PRS_HDR_SW_PRS_EN | tmpPrsOffset);
++    }
++    *p_SoftSeqAttachReg = tmpReg;
++
++    return E_OK;
++}
++
++static uint32_t GetPortSchemeBindParams(
++        t_Handle h_FmPort, t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    uint32_t walking1Mask = 0x80000000, tmp;
++    uint8_t idx = 0;
++
++    p_SchemeBind->netEnvId = p_FmPort->netEnvId;
++    p_SchemeBind->hardwarePortId = p_FmPort->hardwarePortId;
++    p_SchemeBind->useClsPlan = p_FmPort->useClsPlan;
++    p_SchemeBind->numOfSchemes = 0;
++    tmp = p_FmPort->schemesPerPortVector;
++    if (tmp)
++    {
++        while (tmp)
++        {
++            if (tmp & walking1Mask)
++            {
++                p_SchemeBind->schemesIds[p_SchemeBind->numOfSchemes] = idx;
++                p_SchemeBind->numOfSchemes++;
++                tmp &= ~walking1Mask;
++            }
++            walking1Mask >>= 1;
++            idx++;
++        }
++    }
++
++    return tmp;
++}
++
++static void FmPortCheckNApplyMacsec(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    volatile uint32_t *p_BmiCfgReg = NULL;
++    uint32_t macsecEn = BMI_PORT_CFG_EN_MACSEC;
++    uint32_t lcv, walking1Mask = 0x80000000;
++    uint8_t cnt = 0;
++
++    ASSERT_COND(p_FmPort);
++    ASSERT_COND(p_FmPort->h_FmPcd);
++    ASSERT_COND(!p_FmPort->p_FmPortDriverParam);
++
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
++        return;
++
++    p_BmiCfgReg = &p_FmPort->port.bmi_regs->rx.fmbm_rcfg;
++    /* get LCV for MACSEC */
++    if ((lcv = FmPcdGetMacsecLcv(p_FmPort->h_FmPcd, p_FmPort->netEnvId))
++                    != 0)
++    {
++        while (!(lcv & walking1Mask))
++        {
++            cnt++;
++            walking1Mask >>= 1;
++        }
++
++        macsecEn |= (uint32_t)cnt << BMI_PORT_CFG_MS_SEL_SHIFT;
++        WRITE_UINT32(*p_BmiCfgReg, GET_UINT32(*p_BmiCfgReg) | macsecEn);
++    }
++}
++
++static t_Error SetPcd(t_FmPort *p_FmPort, t_FmPortPcdParams *p_PcdParams)
++{
++    t_Error err = E_OK;
++    uint32_t tmpReg;
++    volatile uint32_t *p_BmiNia = NULL;
++    volatile uint32_t *p_BmiPrsNia = NULL;
++    volatile uint32_t *p_BmiPrsStartOffset = NULL;
++    volatile uint32_t *p_BmiInitPrsResult = NULL;
++    volatile uint32_t *p_BmiCcBase = NULL;
++    uint16_t hdrNum, L3HdrNum, greHdrNum;
++    int i;
++    bool isEmptyClsPlanGrp;
++    uint32_t tmpHxs[FM_PCD_PRS_NUM_OF_HDRS];
++    uint16_t absoluteProfileId;
++    uint8_t physicalSchemeId;
++    uint32_t ccTreePhysOffset;
++    t_FmPcdKgInterModuleBindPortToSchemes schemeBind;
++    uint32_t initialSwPrs = 0;
++
++    ASSERT_COND(p_FmPort);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    if (p_FmPort->imEn)
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for non-independant mode ports only"));
++
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for Rx and offline parsing ports only"));
++
++    p_FmPort->netEnvId = FmPcdGetNetEnvId(p_PcdParams->h_NetEnv);
++
++    p_FmPort->pcdEngines = 0;
++
++    /* initialize p_FmPort->pcdEngines field in port's structure */
++    switch (p_PcdParams->pcdSupport)
++    {
++        case (e_FM_PORT_PCD_SUPPORT_NONE):
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_STATE,
++                    ("No PCD configuration required if e_FM_PORT_PCD_SUPPORT_NONE selected"));
++        case (e_FM_PORT_PCD_SUPPORT_PRS_ONLY):
++            p_FmPort->pcdEngines |= FM_PCD_PRS;
++            break;
++        case (e_FM_PORT_PCD_SUPPORT_PLCR_ONLY):
++            p_FmPort->pcdEngines |= FM_PCD_PLCR;
++            break;
++        case (e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR):
++            p_FmPort->pcdEngines |= FM_PCD_PRS;
++            p_FmPort->pcdEngines |= FM_PCD_PLCR;
++            break;
++        case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG):
++            p_FmPort->pcdEngines |= FM_PCD_PRS;
++            p_FmPort->pcdEngines |= FM_PCD_KG;
++            break;
++        case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC):
++            p_FmPort->pcdEngines |= FM_PCD_PRS;
++            p_FmPort->pcdEngines |= FM_PCD_CC;
++            p_FmPort->pcdEngines |= FM_PCD_KG;
++            break;
++        case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR):
++            p_FmPort->pcdEngines |= FM_PCD_PRS;
++            p_FmPort->pcdEngines |= FM_PCD_KG;
++            p_FmPort->pcdEngines |= FM_PCD_CC;
++            p_FmPort->pcdEngines |= FM_PCD_PLCR;
++            break;
++        case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC):
++            p_FmPort->pcdEngines |= FM_PCD_PRS;
++            p_FmPort->pcdEngines |= FM_PCD_CC;
++            break;
++        case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC_AND_PLCR):
++            p_FmPort->pcdEngines |= FM_PCD_PRS;
++            p_FmPort->pcdEngines |= FM_PCD_CC;
++            p_FmPort->pcdEngines |= FM_PCD_PLCR;
++            break;
++        case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR):
++            p_FmPort->pcdEngines |= FM_PCD_PRS;
++            p_FmPort->pcdEngines |= FM_PCD_KG;
++            p_FmPort->pcdEngines |= FM_PCD_PLCR;
++            break;
++        case (e_FM_PORT_PCD_SUPPORT_CC_ONLY):
++            p_FmPort->pcdEngines |= FM_PCD_CC;
++            break;
++#ifdef FM_CAPWAP_SUPPORT
++            case (e_FM_PORT_PCD_SUPPORT_CC_AND_KG):
++            p_FmPort->pcdEngines |= FM_PCD_CC;
++            p_FmPort->pcdEngines |= FM_PCD_KG;
++            break;
++            case (e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR):
++            p_FmPort->pcdEngines |= FM_PCD_CC;
++            p_FmPort->pcdEngines |= FM_PCD_KG;
++            p_FmPort->pcdEngines |= FM_PCD_PLCR;
++            break;
++#endif /* FM_CAPWAP_SUPPORT */
++
++        default:
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid pcdSupport"));
++    }
++
++    if ((p_FmPort->pcdEngines & FM_PCD_PRS)
++            && (p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams
++                    > FM_PCD_PRS_NUM_OF_HDRS))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("Port parser numOfHdrsWithAdditionalParams may not exceed %d", FM_PCD_PRS_NUM_OF_HDRS));
++
++    /* check that parameters exist for each and only each defined engine */
++    if ((!!(p_FmPort->pcdEngines & FM_PCD_PRS) != !!p_PcdParams->p_PrsParams)
++            || (!!(p_FmPort->pcdEngines & FM_PCD_KG)
++                    != !!p_PcdParams->p_KgParams)
++            || (!!(p_FmPort->pcdEngines & FM_PCD_CC)
++                    != !!p_PcdParams->p_CcParams))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_STATE,
++                ("PCD initialization structure is not consistent with pcdSupport"));
++
++    /* get PCD registers pointers */
++    switch (p_FmPort->portType)
++    {
++        case (e_FM_PORT_TYPE_RX_10G):
++        case (e_FM_PORT_TYPE_RX):
++            p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne;
++            p_BmiPrsNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfpne;
++            p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->rx.fmbm_rpso;
++            p_BmiInitPrsResult = &p_FmPort->port.bmi_regs->rx.fmbm_rprai[0];
++            p_BmiCcBase = &p_FmPort->port.bmi_regs->rx.fmbm_rccb;
++            break;
++        case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++            p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne;
++            p_BmiPrsNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofpne;
++            p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->oh.fmbm_opso;
++            p_BmiInitPrsResult = &p_FmPort->port.bmi_regs->oh.fmbm_oprai[0];
++            p_BmiCcBase = &p_FmPort->port.bmi_regs->oh.fmbm_occb;
++            break;
++        default:
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
++    }
++
++    /* set PCD port parameter */
++    if (p_FmPort->pcdEngines & FM_PCD_CC)
++    {
++        err = FmPcdCcBindTree(p_FmPort->h_FmPcd, p_PcdParams,
++                              p_PcdParams->p_CcParams->h_CcTree,
++                              &ccTreePhysOffset, p_FmPort);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++
++        WRITE_UINT32(*p_BmiCcBase, ccTreePhysOffset);
++        p_FmPort->ccTreeId = p_PcdParams->p_CcParams->h_CcTree;
++    }
++
++    if (p_FmPort->pcdEngines & FM_PCD_KG)
++    {
++        if (p_PcdParams->p_KgParams->numOfSchemes == 0)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("For ports using Keygen, at least one scheme must be bound. "));
++
++        err = FmPcdKgSetOrBindToClsPlanGrp(p_FmPort->h_FmPcd,
++                                           p_FmPort->hardwarePortId,
++                                           p_FmPort->netEnvId,
++                                           p_FmPort->optArray,
++                                           &p_FmPort->clsPlanGrpId,
++                                           &isEmptyClsPlanGrp);
++        if (err)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                         ("FmPcdKgSetOrBindToClsPlanGrp failed. "));
++
++        p_FmPort->useClsPlan = !isEmptyClsPlanGrp;
++
++        schemeBind.netEnvId = p_FmPort->netEnvId;
++        schemeBind.hardwarePortId = p_FmPort->hardwarePortId;
++        schemeBind.numOfSchemes = p_PcdParams->p_KgParams->numOfSchemes;
++        schemeBind.useClsPlan = p_FmPort->useClsPlan;
++
++        /* for each scheme */
++        for (i = 0; i < p_PcdParams->p_KgParams->numOfSchemes; i++)
++        {
++            ASSERT_COND(p_PcdParams->p_KgParams->h_Schemes[i]);
++            physicalSchemeId = FmPcdKgGetSchemeId(
++                    p_PcdParams->p_KgParams->h_Schemes[i]);
++            schemeBind.schemesIds[i] = physicalSchemeId;
++            /* build vector */
++            p_FmPort->schemesPerPortVector |= 1
++                    << (31 - (uint32_t)physicalSchemeId);
++#if (DPAA_VERSION >= 11)
++            /*because of the state that VSPE is defined per port - all PCD path should be according to this requirement
++             if !VSPE - in port, for relevant scheme VSPE can not be set*/
++            if (!p_FmPort->vspe
++                    && FmPcdKgGetVspe((p_PcdParams->p_KgParams->h_Schemes[i])))
++                RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                             ("VSPE is not at port level"));
++#endif /* (DPAA_VERSION >= 11) */
++        }
++
++        err = FmPcdKgBindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    /***************************/
++    /* configure NIA after BMI */
++    /***************************/
++    /* rfne may contain FDCS bits, so first we read them. */
++    p_FmPort->savedBmiNia = GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK;
++
++    /* If policer is used directly after BMI or PRS */
++    if ((p_FmPort->pcdEngines & FM_PCD_PLCR)
++            && ((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PLCR_ONLY)
++                    || (p_PcdParams->pcdSupport
++                            == e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR)))
++    {
++        if (!p_PcdParams->p_PlcrParams->h_Profile)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                         ("Profile should be initialized"));
++
++        absoluteProfileId = (uint16_t)FmPcdPlcrProfileGetAbsoluteId(
++                p_PcdParams->p_PlcrParams->h_Profile);
++
++        if (!FmPcdPlcrIsProfileValid(p_FmPort->h_FmPcd, absoluteProfileId))
++            RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                         ("Private port profile not valid."));
++
++        tmpReg = (uint32_t)(absoluteProfileId | NIA_PLCR_ABSOLUTE);
++
++        if (p_FmPort->pcdEngines & FM_PCD_PRS) /* e_FM_PCD_SUPPORT_PRS_AND_PLCR */
++            /* update BMI HPNIA */
++            WRITE_UINT32(*p_BmiPrsNia, (uint32_t)(NIA_ENG_PLCR | tmpReg));
++        else
++            /* e_FM_PCD_SUPPORT_PLCR_ONLY */
++            /* update BMI NIA */
++            p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_PLCR);
++    }
++
++    /* if CC is used directly after BMI */
++    if ((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_ONLY)
++#ifdef FM_CAPWAP_SUPPORT
++    || (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_AND_KG)
++    || (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR)
++#endif /* FM_CAPWAP_SUPPORT */
++    )
++    {
++        if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_OPERATION,
++                    ("e_FM_PORT_PCD_SUPPORT_CC_xx available for offline parsing ports only"));
++        p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC);
++        /* check that prs start offset == RIM[FOF] */
++    }
++
++    if (p_FmPort->pcdEngines & FM_PCD_PRS)
++    {
++        ASSERT_COND(p_PcdParams->p_PrsParams);
++#if (DPAA_VERSION >= 11)
++        if (p_PcdParams->p_PrsParams->firstPrsHdr == HEADER_TYPE_CAPWAP)
++            hdrNum = OFFLOAD_SW_PATCH_CAPWAP_LABEL;
++        else
++        {
++#endif /* (DPAA_VERSION >= 11) */
++            /* if PRS is used it is always first */
++                hdrNum = GetPrsHdrNum(p_PcdParams->p_PrsParams->firstPrsHdr);
++            if (hdrNum == ILLEGAL_HDR_NUM)
++                RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unsupported header."));
++#if (DPAA_VERSION >= 11)
++        }
++#endif /* (DPAA_VERSION >= 11) */
++        p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_PRS | (uint32_t)(hdrNum));
++        /* set after parser NIA */
++        tmpReg = 0;
++        switch (p_PcdParams->pcdSupport)
++        {
++            case (e_FM_PORT_PCD_SUPPORT_PRS_ONLY):
++                WRITE_UINT32(*p_BmiPrsNia,
++                             GET_NIA_BMI_AC_ENQ_FRAME(p_FmPort->h_FmPcd));
++                break;
++            case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC):
++            case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR):
++                tmpReg = NIA_KG_CC_EN;
++            case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG):
++            case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR):
++                if (p_PcdParams->p_KgParams->directScheme)
++                {
++                    physicalSchemeId = FmPcdKgGetSchemeId(
++                            p_PcdParams->p_KgParams->h_DirectScheme);
++                    /* check that this scheme was bound to this port */
++                    for (i = 0; i < p_PcdParams->p_KgParams->numOfSchemes; i++)
++                        if (p_PcdParams->p_KgParams->h_DirectScheme
++                                == p_PcdParams->p_KgParams->h_Schemes[i])
++                            break;
++                    if (i == p_PcdParams->p_KgParams->numOfSchemes)
++                        RETURN_ERROR(
++                                MAJOR,
++                                E_INVALID_VALUE,
++                                ("Direct scheme is not one of the port selected schemes."));
++                    tmpReg |= (uint32_t)(NIA_KG_DIRECT | physicalSchemeId);
++                }
++                WRITE_UINT32(*p_BmiPrsNia, NIA_ENG_KG | tmpReg);
++                break;
++            case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC):
++            case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC_AND_PLCR):
++                WRITE_UINT32(*p_BmiPrsNia,
++                             (uint32_t)(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC));
++                break;
++            case (e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR):
++                break;
++            default:
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid PCD support"));
++        }
++
++        /* set start parsing offset */
++        WRITE_UINT32(*p_BmiPrsStartOffset,
++                     p_PcdParams->p_PrsParams->parsingOffset);
++
++        /************************************/
++        /* Parser port parameters           */
++        /************************************/
++        /* stop before configuring */
++        WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, PRS_CAC_STOP);
++        /* wait for parser to be in idle state */
++        while (GET_UINT32(p_FmPort->p_FmPortPrsRegs->pcac) & PRS_CAC_ACTIVE)
++            ;
++
++        /* set soft seq attachment register */
++        memset(tmpHxs, 0, FM_PCD_PRS_NUM_OF_HDRS * sizeof(uint32_t));
++
++        /* set protocol options */
++        for (i = 0; p_FmPort->optArray[i]; i++)
++            switch (p_FmPort->optArray[i])
++            {
++                case (ETH_BROADCAST):
++                    hdrNum = GetPrsHdrNum(HEADER_TYPE_ETH);
++                    tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_ETH_BC_SHIFT;
++                    break;
++                case (ETH_MULTICAST):
++                    hdrNum = GetPrsHdrNum(HEADER_TYPE_ETH);
++                    tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_ETH_MC_SHIFT;
++                    break;
++                case (VLAN_STACKED):
++                    hdrNum = GetPrsHdrNum(HEADER_TYPE_VLAN);
++                    tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_VLAN_STACKED_SHIFT;
++                    break;
++                case (MPLS_STACKED):
++                    hdrNum = GetPrsHdrNum(HEADER_TYPE_MPLS);
++                    tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_MPLS_STACKED_SHIFT;
++                    break;
++                case (IPV4_BROADCAST_1):
++                    hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4);
++                    tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_1_BC_SHIFT;
++                    break;
++                case (IPV4_MULTICAST_1):
++                    hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4);
++                    tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_1_MC_SHIFT;
++                    break;
++                case (IPV4_UNICAST_2):
++                                      hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4);
++                    tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_2_UC_SHIFT;
++                    break;
++                case (IPV4_MULTICAST_BROADCAST_2):
++                                      hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4);
++                    tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_2_MC_BC_SHIFT;
++                    break;
++                case (IPV6_MULTICAST_1):
++                    hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
++                    tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV6_1_MC_SHIFT;
++                    break;
++                case (IPV6_UNICAST_2):
++                    hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
++                    tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV6_2_UC_SHIFT;
++                    break;
++                case (IPV6_MULTICAST_2):
++                    hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
++                    tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV6_2_MC_SHIFT;
++                    break;
++            }
++
++        if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId,
++                                  HEADER_TYPE_UDP_ENCAP_ESP))
++        {
++            if (p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams == FM_PCD_PRS_NUM_OF_HDRS)
++                RETURN_ERROR(
++                         MINOR, E_INVALID_VALUE,
++                         ("If HEADER_TYPE_UDP_ENCAP_ESP is used, numOfHdrsWithAdditionalParams may be up to FM_PCD_PRS_NUM_OF_HDRS - 1"));
++
++            p_PcdParams->p_PrsParams->additionalParams[p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams].hdr =
++                    HEADER_TYPE_UDP;
++            p_PcdParams->p_PrsParams->additionalParams[p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams].swPrsEnable =
++                    TRUE;
++            p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams++;
++        }
++
++        /* set MPLS default next header - HW reset workaround  */
++        hdrNum = GetPrsHdrNum(HEADER_TYPE_MPLS);
++        tmpHxs[hdrNum] |= PRS_HDR_MPLS_LBL_INTER_EN;
++        L3HdrNum = GetPrsHdrNum(HEADER_TYPE_USER_DEFINED_L3);
++        tmpHxs[hdrNum] |= (uint32_t)L3HdrNum << PRS_HDR_MPLS_NEXT_HDR_SHIFT;
++
++        /* for GRE, disable errors */
++        greHdrNum = GetPrsHdrNum(HEADER_TYPE_GRE);
++        tmpHxs[greHdrNum] |= PRS_HDR_ERROR_DIS;
++
++        /* For UDP remove PAD from L4 checksum calculation */
++        hdrNum = GetPrsHdrNum(HEADER_TYPE_UDP);
++        tmpHxs[hdrNum] |= PRS_HDR_UDP_PAD_REMOVAL;
++        /* For TCP remove PAD from L4 checksum calculation */
++        hdrNum = GetPrsHdrNum(HEADER_TYPE_TCP);
++        tmpHxs[hdrNum] |= PRS_HDR_TCP_PAD_REMOVAL;
++
++        /* config additional params for specific headers */
++        for (i = 0; i < p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams;
++                i++)
++        {
++            /* case for using sw parser as the initial NIA address, before
++               * HW parsing
++               */
++            if ((p_PcdParams->p_PrsParams->additionalParams[i].hdr == HEADER_TYPE_NONE) && 
++                    p_PcdParams->p_PrsParams->additionalParams[i].swPrsEnable)
++            {
++                initialSwPrs = FmPcdGetSwPrsOffset(p_FmPort->h_FmPcd, HEADER_TYPE_NONE,
++                               p_PcdParams->p_PrsParams->additionalParams[i].indexPerHdr);
++                if (initialSwPrs == ILLEGAL_BASE)
++                    RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
++
++                /* clear parser first HXS */
++                p_FmPort->savedBmiNia &= ~BMI_RFNE_HXS_MASK; /* 0x000000FF */
++                /* rewrite with soft parser start */
++                p_FmPort->savedBmiNia |= initialSwPrs;
++                continue;
++            }
++
++            hdrNum =
++                GetPrsHdrNum(p_PcdParams->p_PrsParams->additionalParams[i].hdr);
++            if (hdrNum == ILLEGAL_HDR_NUM)
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
++            if (hdrNum == NO_HDR_NUM)
++                RETURN_ERROR(
++                        MAJOR, E_INVALID_VALUE,
++                        ("Private headers may not use additional parameters"));
++
++            err = AdditionalPrsParams(
++                    p_FmPort, &p_PcdParams->p_PrsParams->additionalParams[i],
++                    &tmpHxs[hdrNum]);
++            if (err)
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
++        }
++
++        /* Check if ip-reassembly port - need to link sw-parser code */
++        if (p_FmPort->h_IpReassemblyManip)
++        {
++           /* link to sw parser code for IP Frag - only if no other code is applied. */
++            hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4);
++            if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN))
++                tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv4_IPR_LABEL);
++            hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
++            if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN))
++                tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPR_LABEL);
++        } else {
++            if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId, HEADER_TYPE_UDP_LITE))
++            {
++                hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
++                if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN))
++                    tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPF_LABEL);
++            } else if ((FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)
++                       && (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)))
++                {
++                    hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
++                    if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN))
++                        tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPF_LABEL);
++                }
++            }
++
++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++        if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId,
++                        HEADER_TYPE_UDP_LITE))
++        {
++            /* link to sw parser code for udp lite - only if no other code is applied. */
++            hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
++            if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN))
++            tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | UDP_LITE_SW_PATCH_LABEL);
++        }
++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
++        for (i = 0; i < FM_PCD_PRS_NUM_OF_HDRS; i++)
++        {
++            /* For all header set LCV as taken from netEnv*/
++            WRITE_UINT32(
++                    p_FmPort->p_FmPortPrsRegs->hdrs[i].lcv,
++                    FmPcdGetLcv(p_FmPort->h_FmPcd, p_FmPort->netEnvId, (uint8_t)i));
++            /* set HXS register according to default+Additional params+protocol options */
++            WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->hdrs[i].softSeqAttach,
++                         tmpHxs[i]);
++        }
++
++        /* set tpid. */
++        tmpReg = PRS_TPID_DFLT;
++        if (p_PcdParams->p_PrsParams->setVlanTpid1)
++        {
++            tmpReg &= PRS_TPID2_MASK;
++            tmpReg |= (uint32_t)p_PcdParams->p_PrsParams->vlanTpid1
++                    << PRS_PCTPID_SHIFT;
++        }
++        if (p_PcdParams->p_PrsParams->setVlanTpid2)
++        {
++            tmpReg &= PRS_TPID1_MASK;
++            tmpReg |= (uint32_t)p_PcdParams->p_PrsParams->vlanTpid2;
++        }WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pctpid, tmpReg);
++
++        /* enable parser */
++        WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, 0);
++
++        if (p_PcdParams->p_PrsParams->prsResultPrivateInfo)
++            p_FmPort->privateInfo =
++                    p_PcdParams->p_PrsParams->prsResultPrivateInfo;
++
++    } /* end parser */
++    else {
++        if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)
++            && (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
++        {
++            hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
++            WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->hdrs[hdrNum].softSeqAttach,
++                         (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPF_LABEL));
++        }
++
++        WRITE_UINT32(*p_BmiPrsStartOffset, 0);
++
++        p_FmPort->privateInfo = 0;
++    }
++
++    FmPortCheckNApplyMacsec(p_FmPort);
++
++    WRITE_UINT32(
++            *p_BmiPrsStartOffset,
++            GET_UINT32(*p_BmiPrsStartOffset) + p_FmPort->internalBufferOffset);
++
++    /* set initial parser result - used for all engines */
++    for (i = 0; i < FM_PORT_PRS_RESULT_NUM_OF_WORDS; i++)
++    {
++        if (!i)
++            WRITE_UINT32(
++                    *(p_BmiInitPrsResult),
++                    (uint32_t)(((uint32_t)p_FmPort->privateInfo << BMI_PR_PORTID_SHIFT) | BMI_PRS_RESULT_HIGH));
++        else
++        {
++            if (i < FM_PORT_PRS_RESULT_NUM_OF_WORDS / 2)
++                WRITE_UINT32(*(p_BmiInitPrsResult+i), BMI_PRS_RESULT_HIGH);
++            else
++                WRITE_UINT32(*(p_BmiInitPrsResult+i), BMI_PRS_RESULT_LOW);
++        }
++    }
++
++    return E_OK;
++}
++
++static t_Error DeletePcd(t_FmPort *p_FmPort)
++{
++    t_Error err = E_OK;
++    volatile uint32_t *p_BmiNia = NULL;
++    volatile uint32_t *p_BmiPrsStartOffset = NULL;
++
++    ASSERT_COND(p_FmPort);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    if (p_FmPort->imEn)
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for non-independant mode ports only"));
++
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
++        RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
++                     ("available for Rx and offline parsing ports only"));
++
++    if (!p_FmPort->pcdEngines)
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("called for non PCD port"));
++
++    /* get PCD registers pointers */
++    switch (p_FmPort->portType)
++    {
++        case (e_FM_PORT_TYPE_RX_10G):
++        case (e_FM_PORT_TYPE_RX):
++            p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne;
++            p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->rx.fmbm_rpso;
++            break;
++        case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++            p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne;
++            p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->oh.fmbm_opso;
++            break;
++        default:
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
++    }
++
++    if ((GET_UINT32(*p_BmiNia) & GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME())
++            != GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME())
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("port has to be detached previousely"));
++
++    WRITE_UINT32(*p_BmiPrsStartOffset, 0);
++
++    /* "cut" PCD out of the port's flow - go to BMI */
++    /* WRITE_UINT32(*p_BmiNia, (p_FmPort->savedBmiNia & BMI_RFNE_FDCS_MASK) | (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)); */
++
++    if (p_FmPort->pcdEngines & FM_PCD_PRS)
++    {
++        /* stop parser */
++        WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, PRS_CAC_STOP);
++        /* wait for parser to be in idle state */
++        while (GET_UINT32(p_FmPort->p_FmPortPrsRegs->pcac) & PRS_CAC_ACTIVE)
++            ;
++    }
++
++    if (p_FmPort->pcdEngines & FM_PCD_KG)
++    {
++        t_FmPcdKgInterModuleBindPortToSchemes schemeBind;
++
++        /* unbind all schemes */
++        p_FmPort->schemesPerPortVector = GetPortSchemeBindParams(p_FmPort,
++                                                                 &schemeBind);
++
++        err = FmPcdKgUnbindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++
++        err = FmPcdKgDeleteOrUnbindPortToClsPlanGrp(p_FmPort->h_FmPcd,
++                                                    p_FmPort->hardwarePortId,
++                                                    p_FmPort->clsPlanGrpId);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        p_FmPort->useClsPlan = FALSE;
++    }
++
++    if (p_FmPort->pcdEngines & FM_PCD_CC)
++    {
++        /* unbind - we need to get the treeId too */
++        err = FmPcdCcUnbindTree(p_FmPort->h_FmPcd, p_FmPort->ccTreeId);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    p_FmPort->pcdEngines = 0;
++
++    return E_OK;
++}
++
++static t_Error AttachPCD(t_FmPort *p_FmPort)
++{
++    volatile uint32_t *p_BmiNia = NULL;
++
++    ASSERT_COND(p_FmPort);
++
++    /* get PCD registers pointers */
++    if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++        p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne;
++    else
++        p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne;
++
++    /* check that current NIA is BMI to BMI */
++    if ((GET_UINT32(*p_BmiNia) & ~BMI_RFNE_FDCS_MASK)
++            != GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME())
++        RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
++                     ("may be called only for ports in BMI-to-BMI state."));
++
++    if (p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY)
++        if (FmSetNumOfRiscsPerPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId, 1,
++                                   p_FmPort->orFmanCtrl) != E_OK)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++
++    if (p_FmPort->requiredAction & UPDATE_NIA_CMNE)
++    {
++        if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++            WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ocmne,
++                         p_FmPort->savedBmiCmne);
++        else
++            WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rcmne,
++                         p_FmPort->savedBmiCmne);
++    }
++
++    if (p_FmPort->requiredAction & UPDATE_NIA_PNEN)
++        WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnen,
++                     p_FmPort->savedQmiPnen);
++
++    if (p_FmPort->requiredAction & UPDATE_NIA_FENE)
++    {
++        if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++            WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofene,
++                         p_FmPort->savedBmiFene);
++        else
++            WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfene,
++                         p_FmPort->savedBmiFene);
++    }
++
++    if (p_FmPort->requiredAction & UPDATE_NIA_FPNE)
++    {
++        if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++            WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofpne,
++                         p_FmPort->savedBmiFpne);
++        else
++            WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfpne,
++                         p_FmPort->savedBmiFpne);
++    }
++
++    if (p_FmPort->requiredAction & UPDATE_OFP_DPTE)
++    {
++        ASSERT_COND(p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING);
++
++        WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofp,
++                     p_FmPort->savedBmiOfp);
++    }
++
++    WRITE_UINT32(*p_BmiNia, p_FmPort->savedBmiNia);
++
++    if (p_FmPort->requiredAction & UPDATE_NIA_PNDN)
++    {
++        p_FmPort->origNonRxQmiRegsPndn =
++                GET_UINT32(p_FmPort->port.qmi_regs->fmqm_pndn);
++        WRITE_UINT32(p_FmPort->port.qmi_regs->fmqm_pndn,
++                     p_FmPort->savedNonRxQmiRegsPndn);
++    }
++
++    return E_OK;
++}
++
++static t_Error DetachPCD(t_FmPort *p_FmPort)
++{
++    volatile uint32_t *p_BmiNia = NULL;
++
++    ASSERT_COND(p_FmPort);
++
++    /* get PCD registers pointers */
++    if (p_FmPort->requiredAction & UPDATE_NIA_PNDN)
++        WRITE_UINT32(p_FmPort->port.qmi_regs->fmqm_pndn,
++                     p_FmPort->origNonRxQmiRegsPndn);
++
++    if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++        p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne;
++    else
++        p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne;
++
++    WRITE_UINT32(
++            *p_BmiNia,
++            (p_FmPort->savedBmiNia & BMI_RFNE_FDCS_MASK) | GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME());
++
++    if (FmPcdGetHcHandle(p_FmPort->h_FmPcd))
++        FmPcdHcSync(p_FmPort->h_FmPcd);
++
++    if (p_FmPort->requiredAction & UPDATE_NIA_FENE)
++    {
++        if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++            WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofene,
++                         NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR);
++        else
++            WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfene,
++                         NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR);
++    }
++
++    if (p_FmPort->requiredAction & UPDATE_NIA_PNEN)
++        WRITE_UINT32(p_FmPort->port.qmi_regs->fmqm_pnen,
++                     NIA_ENG_BMI | NIA_BMI_AC_RELEASE);
++
++    if (p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY)
++        if (FmSetNumOfRiscsPerPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId, 2,
++                                   p_FmPort->orFmanCtrl) != E_OK)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++
++    p_FmPort->requiredAction = 0;
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++/*              Inter-module API routines                                    */
++/*****************************************************************************/
++void FmPortSetMacsecCmd(t_Handle h_FmPort, uint8_t dfltSci)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    volatile uint32_t *p_BmiCfgReg = NULL;
++    uint32_t tmpReg;
++
++    SANITY_CHECK_RETURN(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN(p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_TX))
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_OPERATION, ("The routine is relevant for Tx ports only"));
++        return;
++    }
++
++    p_BmiCfgReg = &p_FmPort->port.bmi_regs->tx.fmbm_tfca;
++    tmpReg = GET_UINT32(*p_BmiCfgReg) & ~BMI_CMD_ATTR_MACCMD_MASK;
++    tmpReg |= BMI_CMD_ATTR_MACCMD_SECURED;
++    tmpReg |= (((uint32_t)dfltSci << BMI_CMD_ATTR_MACCMD_SC_SHIFT)
++            & BMI_CMD_ATTR_MACCMD_SC_MASK);
++
++    WRITE_UINT32(*p_BmiCfgReg, tmpReg);
++}
++
++uint8_t FmPortGetNetEnvId(t_Handle h_FmPort)
++{
++    return ((t_FmPort*)h_FmPort)->netEnvId;
++}
++
++uint8_t FmPortGetHardwarePortId(t_Handle h_FmPort)
++{
++    return ((t_FmPort*)h_FmPort)->hardwarePortId;
++}
++
++uint32_t FmPortGetPcdEngines(t_Handle h_FmPort)
++{
++    return ((t_FmPort*)h_FmPort)->pcdEngines;
++}
++
++#if (DPAA_VERSION >= 11)
++t_Error FmPortSetGprFunc(t_Handle h_FmPort, e_FmPortGprFuncType gprFunc,
++                         void **p_Value)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    uint32_t muramPageOffset;
++
++    ASSERT_COND(p_FmPort);
++    ASSERT_COND(p_Value);
++
++    if (p_FmPort->gprFunc != e_FM_PORT_GPR_EMPTY)
++    {
++        if (p_FmPort->gprFunc != gprFunc)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                         ("gpr was assigned with different func"));
++    }
++    else
++    {
++        switch (gprFunc)
++        {
++            case (e_FM_PORT_GPR_MURAM_PAGE):
++                p_FmPort->p_ParamsPage = FM_MURAM_AllocMem(p_FmPort->h_FmMuram,
++                                                           256, 8);
++                if (!p_FmPort->p_ParamsPage)
++                    RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for page"));
++
++                IOMemSet32(p_FmPort->p_ParamsPage, 0, 256);
++                muramPageOffset =
++                        (uint32_t)(XX_VirtToPhys(p_FmPort->p_ParamsPage)
++                                - p_FmPort->fmMuramPhysBaseAddr);
++                switch (p_FmPort->portType)
++                {
++                    case (e_FM_PORT_TYPE_RX_10G):
++                    case (e_FM_PORT_TYPE_RX):
++                        WRITE_UINT32(
++                                p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr,
++                                muramPageOffset);
++                        break;
++                    case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++                        WRITE_UINT32(
++                                p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ogpr,
++                                muramPageOffset);
++                        break;
++                    default:
++                        RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                                     ("Invalid port type"));
++                }
++                break;
++            default:
++                RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++        }
++        p_FmPort->gprFunc = gprFunc;
++    }
++
++    switch (p_FmPort->gprFunc)
++    {
++        case (e_FM_PORT_GPR_MURAM_PAGE):
++            *p_Value = p_FmPort->p_ParamsPage;
++            break;
++        default:
++            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
++    }
++
++    return E_OK;
++}
++#endif /* (DPAA_VERSION >= 11) */
++
++t_Error FmPortGetSetCcParams(t_Handle h_FmPort,
++                             t_FmPortGetSetCcParams *p_CcParams)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    int tmpInt;
++    volatile uint32_t *p_BmiPrsStartOffset = NULL;
++
++    /* this function called from Cc for pass and receive parameters port params between CC and PORT*/
++
++    if ((p_CcParams->getCcParams.type & OFFSET_OF_PR)
++            && (p_FmPort->bufferOffsets.prsResultOffset != ILLEGAL_BASE))
++    {
++        p_CcParams->getCcParams.prOffset =
++                (uint8_t)p_FmPort->bufferOffsets.prsResultOffset;
++        p_CcParams->getCcParams.type &= ~OFFSET_OF_PR;
++    }
++    if (p_CcParams->getCcParams.type & HW_PORT_ID)
++    {
++        p_CcParams->getCcParams.hardwarePortId =
++                (uint8_t)p_FmPort->hardwarePortId;
++        p_CcParams->getCcParams.type &= ~HW_PORT_ID;
++    }
++    if ((p_CcParams->getCcParams.type & OFFSET_OF_DATA)
++            && (p_FmPort->bufferOffsets.dataOffset != ILLEGAL_BASE))
++    {
++        p_CcParams->getCcParams.dataOffset =
++                (uint16_t)p_FmPort->bufferOffsets.dataOffset;
++        p_CcParams->getCcParams.type &= ~OFFSET_OF_DATA;
++    }
++    if (p_CcParams->getCcParams.type & NUM_OF_TASKS)
++    {
++        p_CcParams->getCcParams.numOfTasks = (uint8_t)p_FmPort->tasks.num;
++        p_CcParams->getCcParams.type &= ~NUM_OF_TASKS;
++    }
++    if (p_CcParams->getCcParams.type & NUM_OF_EXTRA_TASKS)
++    {
++        p_CcParams->getCcParams.numOfExtraTasks =
++                (uint8_t)p_FmPort->tasks.extra;
++        p_CcParams->getCcParams.type &= ~NUM_OF_EXTRA_TASKS;
++    }
++    if (p_CcParams->getCcParams.type & FM_REV)
++    {
++        p_CcParams->getCcParams.revInfo.majorRev = p_FmPort->fmRevInfo.majorRev;
++        p_CcParams->getCcParams.revInfo.minorRev = p_FmPort->fmRevInfo.minorRev;
++        p_CcParams->getCcParams.type &= ~FM_REV;
++    }
++    if (p_CcParams->getCcParams.type & DISCARD_MASK)
++    {
++        if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++            p_CcParams->getCcParams.discardMask =
++                    GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm);
++        else
++            p_CcParams->getCcParams.discardMask =
++                    GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm);
++        p_CcParams->getCcParams.type &= ~DISCARD_MASK;
++    }
++    if (p_CcParams->getCcParams.type & MANIP_EXTRA_SPACE)
++    {
++        p_CcParams->getCcParams.internalBufferOffset =
++                p_FmPort->internalBufferOffset;
++        p_CcParams->getCcParams.type &= ~MANIP_EXTRA_SPACE;
++    }
++    if (p_CcParams->getCcParams.type & GET_NIA_FPNE)
++    {
++        if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++            p_CcParams->getCcParams.nia =
++                    GET_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofpne);
++        else
++            p_CcParams->getCcParams.nia =
++                    GET_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfpne);
++        p_CcParams->getCcParams.type &= ~GET_NIA_FPNE;
++    }
++    if (p_CcParams->getCcParams.type & GET_NIA_PNDN)
++    {
++        if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
++        p_CcParams->getCcParams.nia =
++                GET_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndn);
++        p_CcParams->getCcParams.type &= ~GET_NIA_PNDN;
++    }
++
++    if ((p_CcParams->setCcParams.type & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY)
++            && !(p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY))
++    {
++        p_FmPort->requiredAction |= UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY;
++        p_FmPort->orFmanCtrl = p_CcParams->setCcParams.orFmanCtrl;
++    }
++
++    if ((p_CcParams->setCcParams.type & UPDATE_NIA_PNEN)
++            && !(p_FmPort->requiredAction & UPDATE_NIA_PNEN))
++    {
++        p_FmPort->savedQmiPnen = p_CcParams->setCcParams.nia;
++        p_FmPort->requiredAction |= UPDATE_NIA_PNEN;
++    }
++    else
++        if (p_CcParams->setCcParams.type & UPDATE_NIA_PNEN)
++        {
++            if (p_FmPort->savedQmiPnen != p_CcParams->setCcParams.nia)
++                RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                             ("PNEN was defined previously different"));
++        }
++
++    if ((p_CcParams->setCcParams.type & UPDATE_NIA_PNDN)
++            && !(p_FmPort->requiredAction & UPDATE_NIA_PNDN))
++    {
++        p_FmPort->savedNonRxQmiRegsPndn = p_CcParams->setCcParams.nia;
++        p_FmPort->requiredAction |= UPDATE_NIA_PNDN;
++    }
++    else
++        if (p_CcParams->setCcParams.type & UPDATE_NIA_PNDN)
++        {
++            if (p_FmPort->savedNonRxQmiRegsPndn != p_CcParams->setCcParams.nia)
++                RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                             ("PNDN was defined previously different"));
++        }
++
++    if ((p_CcParams->setCcParams.type & UPDATE_NIA_FENE)
++            && (p_CcParams->setCcParams.overwrite
++                    || !(p_FmPort->requiredAction & UPDATE_NIA_FENE)))
++    {
++        p_FmPort->savedBmiFene = p_CcParams->setCcParams.nia;
++        p_FmPort->requiredAction |= UPDATE_NIA_FENE;
++    }
++    else
++        if (p_CcParams->setCcParams.type & UPDATE_NIA_FENE)
++        {
++            if (p_FmPort->savedBmiFene != p_CcParams->setCcParams.nia)
++                RETURN_ERROR( MAJOR, E_INVALID_STATE,
++                             ("xFENE was defined previously different"));
++        }
++
++    if ((p_CcParams->setCcParams.type & UPDATE_NIA_FPNE)
++            && !(p_FmPort->requiredAction & UPDATE_NIA_FPNE))
++    {
++        p_FmPort->savedBmiFpne = p_CcParams->setCcParams.nia;
++        p_FmPort->requiredAction |= UPDATE_NIA_FPNE;
++    }
++    else
++        if (p_CcParams->setCcParams.type & UPDATE_NIA_FPNE)
++        {
++            if (p_FmPort->savedBmiFpne != p_CcParams->setCcParams.nia)
++                RETURN_ERROR( MAJOR, E_INVALID_STATE,
++                             ("xFPNE was defined previously different"));
++        }
++
++    if ((p_CcParams->setCcParams.type & UPDATE_NIA_CMNE)
++            && !(p_FmPort->requiredAction & UPDATE_NIA_CMNE))
++    {
++        p_FmPort->savedBmiCmne = p_CcParams->setCcParams.nia;
++        p_FmPort->requiredAction |= UPDATE_NIA_CMNE;
++    }
++    else
++        if (p_CcParams->setCcParams.type & UPDATE_NIA_CMNE)
++        {
++            if (p_FmPort->savedBmiCmne != p_CcParams->setCcParams.nia)
++                RETURN_ERROR( MAJOR, E_INVALID_STATE,
++                             ("xCMNE was defined previously different"));
++        }
++
++    if ((p_CcParams->setCcParams.type & UPDATE_PSO)
++            && !(p_FmPort->requiredAction & UPDATE_PSO))
++    {
++        /* get PCD registers pointers */
++        switch (p_FmPort->portType)
++        {
++            case (e_FM_PORT_TYPE_RX_10G):
++            case (e_FM_PORT_TYPE_RX):
++                p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->rx.fmbm_rpso;
++                break;
++            case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++                p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->oh.fmbm_opso;
++                break;
++            default:
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
++        }
++
++        /* set start parsing offset */
++        tmpInt = (int)GET_UINT32(*p_BmiPrsStartOffset)
++                + p_CcParams->setCcParams.psoSize;
++        if (tmpInt > 0)
++            WRITE_UINT32(*p_BmiPrsStartOffset, (uint32_t)tmpInt);
++
++        p_FmPort->requiredAction |= UPDATE_PSO;
++        p_FmPort->savedPrsStartOffset = p_CcParams->setCcParams.psoSize;
++    }
++    else
++        if (p_CcParams->setCcParams.type & UPDATE_PSO)
++        {
++            if (p_FmPort->savedPrsStartOffset
++                    != p_CcParams->setCcParams.psoSize)
++                RETURN_ERROR(
++                        MAJOR,
++                        E_INVALID_STATE,
++                        ("parser start offset was defoned previousley different"));
++        }
++
++    if ((p_CcParams->setCcParams.type & UPDATE_OFP_DPTE)
++            && !(p_FmPort->requiredAction & UPDATE_OFP_DPTE))
++    {
++        if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
++        p_FmPort->savedBmiOfp = GET_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofp);
++        p_FmPort->savedBmiOfp &= ~BMI_FIFO_PIPELINE_DEPTH_MASK;
++        p_FmPort->savedBmiOfp |= p_CcParams->setCcParams.ofpDpde
++                << BMI_FIFO_PIPELINE_DEPTH_SHIFT;
++        p_FmPort->requiredAction |= UPDATE_OFP_DPTE;
++    }
++
++    return E_OK;
++}
++/*********************** End of inter-module routines ************************/
++
++/****************************************/
++/*       API Init unit functions        */
++/****************************************/
++
++t_Handle FM_PORT_Config(t_FmPortParams *p_FmPortParams)
++{
++    t_FmPort *p_FmPort;
++    uintptr_t baseAddr = p_FmPortParams->baseAddr;
++    uint32_t tmpReg;
++
++    /* Allocate FM structure */
++    p_FmPort = (t_FmPort *)XX_Malloc(sizeof(t_FmPort));
++    if (!p_FmPort)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Port driver structure"));
++        return NULL;
++    }
++    memset(p_FmPort, 0, sizeof(t_FmPort));
++
++    /* Allocate the FM driver's parameters structure */
++    p_FmPort->p_FmPortDriverParam = (t_FmPortDriverParam *)XX_Malloc(
++            sizeof(t_FmPortDriverParam));
++    if (!p_FmPort->p_FmPortDriverParam)
++    {
++        XX_Free(p_FmPort);
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Port driver parameters"));
++        return NULL;
++    }
++    memset(p_FmPort->p_FmPortDriverParam, 0, sizeof(t_FmPortDriverParam));
++
++    /* Initialize FM port parameters which will be kept by the driver */
++    p_FmPort->portType = p_FmPortParams->portType;
++    p_FmPort->portId = p_FmPortParams->portId;
++    p_FmPort->pcdEngines = FM_PCD_NONE;
++    p_FmPort->f_Exception = p_FmPortParams->f_Exception;
++    p_FmPort->h_App = p_FmPortParams->h_App;
++    p_FmPort->h_Fm = p_FmPortParams->h_Fm;
++
++    /* get FM revision */
++    FM_GetRevision(p_FmPort->h_Fm, &p_FmPort->fmRevInfo);
++
++    /* calculate global portId number */
++    p_FmPort->hardwarePortId = SwPortIdToHwPortId(p_FmPort->portType,
++                                    p_FmPortParams->portId,
++                                    p_FmPort->fmRevInfo.majorRev,
++                                    p_FmPort->fmRevInfo.minorRev);
++
++    if (p_FmPort->fmRevInfo.majorRev >= 6)
++    {
++        if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)
++                && (p_FmPortParams->portId != FM_OH_PORT_ID))
++            DBG(WARNING,
++                    ("Port ID %d is recommended for HC port. Overwriting HW defaults to be suitable for HC.",
++                            FM_OH_PORT_ID));
++
++        if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++                && (p_FmPortParams->portId == FM_OH_PORT_ID))
++            DBG(WARNING, ("Use non-zero portId for OP port due to insufficient resources on portId 0."));
++    }
++
++    /* Set up FM port parameters for initialization phase only */
++
++    /* First, fill in flibs struct */
++    fman_port_defconfig(&p_FmPort->p_FmPortDriverParam->dfltCfg,
++                        (enum fman_port_type)p_FmPort->portType);
++    /* Overwrite some integration specific parameters */
++    p_FmPort->p_FmPortDriverParam->dfltCfg.rx_pri_elevation =
++            DEFAULT_PORT_rxFifoPriElevationLevel;
++    p_FmPort->p_FmPortDriverParam->dfltCfg.rx_fifo_thr =
++            DEFAULT_PORT_rxFifoThreshold;
++
++#if defined(FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675) || defined(FM_ERROR_VSP_NO_MATCH_SW006)
++    p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006675 = TRUE;
++#else
++    p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006675 = FALSE;
++#endif
++    if ((p_FmPort->fmRevInfo.majorRev == 6)
++            && (p_FmPort->fmRevInfo.minorRev == 0))
++        p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006320 = TRUE;
++    else
++        p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006320 = FALSE;
++
++    /* Excessive Threshold register - exists for pre-FMv3 chips only */
++    if (p_FmPort->fmRevInfo.majorRev < 6)
++    {
++#ifdef FM_NO_RESTRICT_ON_ACCESS_RSRC
++        p_FmPort->p_FmPortDriverParam->dfltCfg.excessive_threshold_register =
++                TRUE;
++#endif
++        p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_rebm_has_sgd = FALSE;
++        p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_tfne_has_features = FALSE;
++    }
++    else
++    {
++        p_FmPort->p_FmPortDriverParam->dfltCfg.excessive_threshold_register =
++                FALSE;
++        p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_rebm_has_sgd = TRUE;
++        p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_tfne_has_features = TRUE;
++    }
++    if (p_FmPort->fmRevInfo.majorRev == 4)
++        p_FmPort->p_FmPortDriverParam->dfltCfg.qmi_deq_options_support = FALSE;
++    else
++        p_FmPort->p_FmPortDriverParam->dfltCfg.qmi_deq_options_support = TRUE;
++
++    /* Continue with other parameters */
++    p_FmPort->p_FmPortDriverParam->baseAddr = baseAddr;
++    /* set memory map pointers */
++    p_FmPort->p_FmPortQmiRegs =
++            (t_FmPortQmiRegs *)UINT_TO_PTR(baseAddr + QMI_PORT_REGS_OFFSET);
++    p_FmPort->p_FmPortBmiRegs =
++            (u_FmPortBmiRegs *)UINT_TO_PTR(baseAddr + BMI_PORT_REGS_OFFSET);
++    p_FmPort->p_FmPortPrsRegs =
++            (t_FmPortPrsRegs *)UINT_TO_PTR(baseAddr + PRS_PORT_REGS_OFFSET);
++
++    p_FmPort->p_FmPortDriverParam->bufferPrefixContent.privDataSize =
++            DEFAULT_PORT_bufferPrefixContent_privDataSize;
++    p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passPrsResult =
++            DEFAULT_PORT_bufferPrefixContent_passPrsResult;
++    p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passTimeStamp =
++            DEFAULT_PORT_bufferPrefixContent_passTimeStamp;
++    p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passAllOtherPCDInfo =
++            DEFAULT_PORT_bufferPrefixContent_passTimeStamp;
++    p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign =
++            DEFAULT_PORT_bufferPrefixContent_dataAlign;
++    /*    p_FmPort->p_FmPortDriverParam->dmaSwapData                      = (e_FmDmaSwapOption)DEFAULT_PORT_dmaSwapData;
++     p_FmPort->p_FmPortDriverParam->dmaIntContextCacheAttr           = (e_FmDmaCacheOption)DEFAULT_PORT_dmaIntContextCacheAttr;
++     p_FmPort->p_FmPortDriverParam->dmaHeaderCacheAttr               = (e_FmDmaCacheOption)DEFAULT_PORT_dmaHeaderCacheAttr;
++     p_FmPort->p_FmPortDriverParam->dmaScatterGatherCacheAttr        = (e_FmDmaCacheOption)DEFAULT_PORT_dmaScatterGatherCacheAttr;
++     p_FmPort->p_FmPortDriverParam->dmaWriteOptimize                 = DEFAULT_PORT_dmaWriteOptimize;
++     */
++    p_FmPort->p_FmPortDriverParam->liodnBase = p_FmPortParams->liodnBase;
++    p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore =
++            DEFAULT_PORT_cheksumLastBytesIgnore;
++
++    p_FmPort->maxFrameLength = DEFAULT_PORT_maxFrameLength;
++    /* resource distribution. */
++      p_FmPort->fifoBufs.num = DEFAULT_PORT_numOfFifoBufs(p_FmPort->portType)
++                      * BMI_FIFO_UNITS;
++      p_FmPort->fifoBufs.extra = DEFAULT_PORT_extraNumOfFifoBufs
++                      * BMI_FIFO_UNITS;
++      p_FmPort->openDmas.num = DEFAULT_PORT_numOfOpenDmas(p_FmPort->portType);
++      p_FmPort->openDmas.extra =
++                      DEFAULT_PORT_extraNumOfOpenDmas(p_FmPort->portType);
++      p_FmPort->tasks.num = DEFAULT_PORT_numOfTasks(p_FmPort->portType);
++      p_FmPort->tasks.extra = DEFAULT_PORT_extraNumOfTasks(p_FmPort->portType);
++
++
++#ifdef FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981
++    if ((p_FmPort->fmRevInfo.majorRev == 6)
++            && (p_FmPort->fmRevInfo.minorRev == 0)
++            && ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++                    || (p_FmPort->portType == e_FM_PORT_TYPE_TX)))
++    {
++        p_FmPort->openDmas.num = 16;
++        p_FmPort->openDmas.extra = 0;
++    }
++#endif /* FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 */
++
++    /* Port type specific initialization: */
++    switch (p_FmPort->portType)
++    {
++        case (e_FM_PORT_TYPE_RX):
++        case (e_FM_PORT_TYPE_RX_10G):
++            /* Initialize FM port parameters for initialization phase only */
++            p_FmPort->p_FmPortDriverParam->cutBytesFromEnd =
++                    DEFAULT_PORT_cutBytesFromEnd;
++            p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = FALSE;
++            p_FmPort->p_FmPortDriverParam->frmDiscardOverride =
++                    DEFAULT_PORT_frmDiscardOverride;
++
++                tmpReg =
++                        GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfp);
++                      p_FmPort->p_FmPortDriverParam->rxFifoPriElevationLevel =
++                        (((tmpReg & BMI_RX_FIFO_PRI_ELEVATION_MASK)
++                                >> BMI_RX_FIFO_PRI_ELEVATION_SHIFT) + 1)
++                                * BMI_FIFO_UNITS;
++                p_FmPort->p_FmPortDriverParam->rxFifoThreshold = (((tmpReg
++                        & BMI_RX_FIFO_THRESHOLD_MASK)
++                        >> BMI_RX_FIFO_THRESHOLD_SHIFT) + 1) * BMI_FIFO_UNITS;
++
++            p_FmPort->p_FmPortDriverParam->bufMargins.endMargins =
++                    DEFAULT_PORT_BufMargins_endMargins;
++            p_FmPort->p_FmPortDriverParam->errorsToDiscard =
++                    DEFAULT_PORT_errorsToDiscard;
++            p_FmPort->p_FmPortDriverParam->forwardReuseIntContext =
++                    DEFAULT_PORT_forwardIntContextReuse;
++#if (DPAA_VERSION >= 11)
++            p_FmPort->p_FmPortDriverParam->noScatherGather =
++                    DEFAULT_PORT_noScatherGather;
++#endif /* (DPAA_VERSION >= 11) */
++            break;
++
++        case (e_FM_PORT_TYPE_TX):
++            p_FmPort->p_FmPortDriverParam->dontReleaseBuf = FALSE;
++#ifdef FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127
++            tmpReg = 0x00001013;
++            WRITE_UINT32( p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfp,
++                         tmpReg);
++#endif /* FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 */
++        case (e_FM_PORT_TYPE_TX_10G):
++                tmpReg =
++                        GET_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfp);
++                p_FmPort->p_FmPortDriverParam->txFifoMinFillLevel = ((tmpReg
++                        & BMI_TX_FIFO_MIN_FILL_MASK)
++                        >> BMI_TX_FIFO_MIN_FILL_SHIFT) * BMI_FIFO_UNITS;
++                      p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth =
++                        (uint8_t)(((tmpReg & BMI_FIFO_PIPELINE_DEPTH_MASK)
++                                >> BMI_FIFO_PIPELINE_DEPTH_SHIFT) + 1);
++                p_FmPort->p_FmPortDriverParam->txFifoLowComfLevel = (((tmpReg
++                        & BMI_TX_LOW_COMF_MASK) >> BMI_TX_LOW_COMF_SHIFT) + 1)
++                        * BMI_FIFO_UNITS;
++
++            p_FmPort->p_FmPortDriverParam->deqType = DEFAULT_PORT_deqType;
++            p_FmPort->p_FmPortDriverParam->deqPrefetchOption =
++                    DEFAULT_PORT_deqPrefetchOption;
++            p_FmPort->p_FmPortDriverParam->deqHighPriority =
++                    (bool)((p_FmPort->portType == e_FM_PORT_TYPE_TX) ? DEFAULT_PORT_deqHighPriority_1G :
++                            DEFAULT_PORT_deqHighPriority_10G);
++            p_FmPort->p_FmPortDriverParam->deqByteCnt =
++                    (uint16_t)(
++                            (p_FmPort->portType == e_FM_PORT_TYPE_TX) ? DEFAULT_PORT_deqByteCnt_1G :
++                                    DEFAULT_PORT_deqByteCnt_10G);
++            break;
++        case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++            p_FmPort->p_FmPortDriverParam->errorsToDiscard =
++                    DEFAULT_PORT_errorsToDiscard;
++#if (DPAA_VERSION >= 11)
++            p_FmPort->p_FmPortDriverParam->noScatherGather =
++                    DEFAULT_PORT_noScatherGather;
++#endif /* (DPAA_VERSION >= 11) */
++        case (e_FM_PORT_TYPE_OH_HOST_COMMAND):
++            p_FmPort->p_FmPortDriverParam->deqPrefetchOption =
++                    DEFAULT_PORT_deqPrefetchOption_HC;
++            p_FmPort->p_FmPortDriverParam->deqHighPriority =
++                    DEFAULT_PORT_deqHighPriority_1G;
++            p_FmPort->p_FmPortDriverParam->deqType = DEFAULT_PORT_deqType;
++            p_FmPort->p_FmPortDriverParam->deqByteCnt =
++                    DEFAULT_PORT_deqByteCnt_1G;
++
++                tmpReg =
++                        GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofp);
++                p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth =
++                        (uint8_t)(((tmpReg & BMI_FIFO_PIPELINE_DEPTH_MASK)
++                                >> BMI_FIFO_PIPELINE_DEPTH_SHIFT) + 1);
++                if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)
++                        && (p_FmPortParams->portId != FM_OH_PORT_ID))
++                {
++                    /* Overwrite HC defaults */
++                      p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth =
++                                      DEFAULT_PORT_fifoDeqPipelineDepth_OH;
++                }
++
++#ifndef FM_FRAME_END_PARAMS_FOR_OP
++            if (p_FmPort->fmRevInfo.majorRev < 6)
++            p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore = DEFAULT_notSupported;
++#endif /* !FM_FRAME_END_PARAMS_FOR_OP */
++
++#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP
++            if (!((p_FmPort->fmRevInfo.majorRev == 4) ||
++                            (p_FmPort->fmRevInfo.majorRev >= 6)))
++            p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = DEFAULT_notSupported;
++#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */
++            break;
++
++        default:
++            XX_Free(p_FmPort->p_FmPortDriverParam);
++            XX_Free(p_FmPort);
++            REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
++            return NULL;
++    }
++#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
++    if (p_FmPort->fmRevInfo.majorRev == 4)
++    p_FmPort->p_FmPortDriverParam->deqPrefetchOption = (e_FmPortDeqPrefetchOption)DEFAULT_notSupported;
++#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
++
++    p_FmPort->imEn = p_FmPortParams->independentModeEnable;
++
++    if (p_FmPort->imEn)
++    {
++        if ((p_FmPort->portType == e_FM_PORT_TYPE_TX)
++                || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G))
++            p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth =
++                    DEFAULT_PORT_fifoDeqPipelineDepth_IM;
++        FmPortConfigIM(p_FmPort, p_FmPortParams);
++    }
++    else
++    {
++        switch (p_FmPort->portType)
++        {
++            case (e_FM_PORT_TYPE_RX):
++            case (e_FM_PORT_TYPE_RX_10G):
++                /* Initialize FM port parameters for initialization phase only */
++                memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools,
++                       &p_FmPortParams->specificParams.rxParams.extBufPools,
++                       sizeof(t_FmExtPools));
++                p_FmPort->p_FmPortDriverParam->errFqid =
++                        p_FmPortParams->specificParams.rxParams.errFqid;
++                p_FmPort->p_FmPortDriverParam->dfltFqid =
++                        p_FmPortParams->specificParams.rxParams.dfltFqid;
++                p_FmPort->p_FmPortDriverParam->liodnOffset =
++                        p_FmPortParams->specificParams.rxParams.liodnOffset;
++                break;
++            case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++            case (e_FM_PORT_TYPE_TX):
++            case (e_FM_PORT_TYPE_TX_10G):
++            case (e_FM_PORT_TYPE_OH_HOST_COMMAND):
++                p_FmPort->p_FmPortDriverParam->errFqid =
++                        p_FmPortParams->specificParams.nonRxParams.errFqid;
++                p_FmPort->p_FmPortDriverParam->deqSubPortal =
++                        (uint8_t)(p_FmPortParams->specificParams.nonRxParams.qmChannel
++                                & QMI_DEQ_CFG_SUBPORTAL_MASK);
++                p_FmPort->p_FmPortDriverParam->dfltFqid =
++                        p_FmPortParams->specificParams.nonRxParams.dfltFqid;
++                break;
++            default:
++                XX_Free(p_FmPort->p_FmPortDriverParam);
++                XX_Free(p_FmPort);
++                REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
++                return NULL;
++        }
++    }
++
++    memset(p_FmPort->name, 0, (sizeof(char)) * MODULE_NAME_SIZE);
++    if (Sprint(
++            p_FmPort->name,
++            "FM-%d-port-%s-%d",
++            FmGetId(p_FmPort->h_Fm),
++            ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING
++                    || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) ? "OH" :
++                    (p_FmPort->portType == e_FM_PORT_TYPE_RX ? "1g-RX" :
++                            (p_FmPort->portType == e_FM_PORT_TYPE_TX ? "1g-TX" :
++                                    (p_FmPort->portType
++                                            == e_FM_PORT_TYPE_RX_10G ? "10g-RX" :
++                                            "10g-TX")))),
++            p_FmPort->portId) == 0)
++    {
++        XX_Free(p_FmPort->p_FmPortDriverParam);
++        XX_Free(p_FmPort);
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
++        return NULL;
++    }
++
++    p_FmPort->h_Spinlock = XX_InitSpinlock();
++    if (!p_FmPort->h_Spinlock)
++    {
++        XX_Free(p_FmPort->p_FmPortDriverParam);
++        XX_Free(p_FmPort);
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
++        return NULL;
++    }
++
++    return p_FmPort;
++}
++
++t_FmPort *rx_port = 0;
++t_FmPort *tx_port = 0;
++
++/**************************************************************************//**
++ @Function      FM_PORT_Init
++
++ @Description   Initializes the FM module
++
++ @Param[in]     h_FmPort - FM module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++ *//***************************************************************************/
++t_Error FM_PORT_Init(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_FmPortDriverParam *p_DriverParams;
++    t_Error errCode;
++    t_FmInterModulePortInitParams fmParams;
++    t_FmRevisionInfo revInfo;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    errCode = FmSpBuildBufferStructure(
++            &p_FmPort->p_FmPortDriverParam->intContext,
++            &p_FmPort->p_FmPortDriverParam->bufferPrefixContent,
++            &p_FmPort->p_FmPortDriverParam->bufMargins,
++            &p_FmPort->bufferOffsets, &p_FmPort->internalBufferOffset);
++    if (errCode != E_OK)
++        RETURN_ERROR(MAJOR, errCode, NO_MSG);
++#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
++    if ((p_FmPort->p_FmPortDriverParam->bcbWorkaround) &&
++            (p_FmPort->portType == e_FM_PORT_TYPE_RX))
++    {
++        p_FmPort->p_FmPortDriverParam->errorsToDiscard |= FM_PORT_FRM_ERR_PHYSICAL;
++        if (!p_FmPort->fifoBufs.num)
++        p_FmPort->fifoBufs.num = DEFAULT_PORT_numOfFifoBufs(p_FmPort->portType)*BMI_FIFO_UNITS;
++        p_FmPort->fifoBufs.num += 4*KILOBYTE;
++    }
++#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */
++
++    CHECK_INIT_PARAMETERS(p_FmPort, CheckInitParameters);
++
++    p_DriverParams = p_FmPort->p_FmPortDriverParam;
++
++    /* Set up flibs port structure */
++    memset(&p_FmPort->port, 0, sizeof(struct fman_port));
++    p_FmPort->port.type = (enum fman_port_type)p_FmPort->portType;
++    FM_GetRevision(p_FmPort->h_Fm, &revInfo);
++    p_FmPort->port.fm_rev_maj = revInfo.majorRev;
++    p_FmPort->port.fm_rev_min = revInfo.minorRev;
++    p_FmPort->port.bmi_regs =
++            (union fman_port_bmi_regs *)UINT_TO_PTR(p_DriverParams->baseAddr + BMI_PORT_REGS_OFFSET);
++    p_FmPort->port.qmi_regs =
++            (struct fman_port_qmi_regs *)UINT_TO_PTR(p_DriverParams->baseAddr + QMI_PORT_REGS_OFFSET);
++    p_FmPort->port.ext_pools_num = (uint8_t)((revInfo.majorRev == 4) ? 4 : 8);
++    p_FmPort->port.im_en = p_FmPort->imEn;
++    p_FmPort->p_FmPortPrsRegs =
++            (t_FmPortPrsRegs *)UINT_TO_PTR(p_DriverParams->baseAddr + PRS_PORT_REGS_OFFSET);
++
++    if (((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) && !p_FmPort->imEn)
++    {
++        /* Call the external Buffer routine which also checks fifo
++         size and updates it if necessary */
++        /* define external buffer pools and pool depletion*/
++        errCode = SetExtBufferPools(p_FmPort);
++        if (errCode)
++            RETURN_ERROR(MAJOR, errCode, NO_MSG);
++        /* check if the largest external buffer pool is large enough */
++        if (p_DriverParams->bufMargins.startMargins + MIN_EXT_BUF_SIZE
++                + p_DriverParams->bufMargins.endMargins
++                > p_FmPort->rxPoolsParams.largestBufSize)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("bufMargins.startMargins (%d) + minimum buf size (64) + bufMargins.endMargins (%d) is larger than maximum external buffer size (%d)", p_DriverParams->bufMargins.startMargins, p_DriverParams->bufMargins.endMargins, p_FmPort->rxPoolsParams.largestBufSize));
++    }
++    if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++    {
++        {
++#ifdef FM_NO_OP_OBSERVED_POOLS
++            t_FmRevisionInfo revInfo;
++
++            FM_GetRevision(p_FmPort->h_Fm, &revInfo);
++            if ((revInfo.majorRev == 4) && (p_DriverParams->enBufPoolDepletion))
++#endif /* FM_NO_OP_OBSERVED_POOLS */
++            {
++                /* define external buffer pools */
++                errCode = SetExtBufferPools(p_FmPort);
++                if (errCode)
++                    RETURN_ERROR(MAJOR, errCode, NO_MSG);
++            }
++        }
++    }
++
++    /************************************************************/
++    /* Call FM module routine for communicating parameters      */
++    /************************************************************/
++    memset(&fmParams, 0, sizeof(fmParams));
++    fmParams.hardwarePortId = p_FmPort->hardwarePortId;
++    fmParams.portType = (e_FmPortType)p_FmPort->portType;
++    fmParams.numOfTasks = (uint8_t)p_FmPort->tasks.num;
++    fmParams.numOfExtraTasks = (uint8_t)p_FmPort->tasks.extra;
++    fmParams.numOfOpenDmas = (uint8_t)p_FmPort->openDmas.num;
++    fmParams.numOfExtraOpenDmas = (uint8_t)p_FmPort->openDmas.extra;
++
++    if (p_FmPort->fifoBufs.num)
++    {
++        errCode = VerifySizeOfFifo(p_FmPort);
++        if (errCode != E_OK)
++            RETURN_ERROR(MAJOR, errCode, NO_MSG);
++    }
++    fmParams.sizeOfFifo = p_FmPort->fifoBufs.num;
++    fmParams.extraSizeOfFifo = p_FmPort->fifoBufs.extra;
++    fmParams.independentMode = p_FmPort->imEn;
++    fmParams.liodnOffset = p_DriverParams->liodnOffset;
++    fmParams.liodnBase = p_DriverParams->liodnBase;
++    fmParams.deqPipelineDepth =
++            p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth;
++    fmParams.maxFrameLength = p_FmPort->maxFrameLength;
++#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ||
++            (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND))
++    {
++        if (!((p_FmPort->fmRevInfo.majorRev == 4) ||
++                        (p_FmPort->fmRevInfo.majorRev >= 6)))
++        /* HC ports do not have fifoDeqPipelineDepth, but it is needed only
++         * for deq threshold calculation.
++         */
++        fmParams.deqPipelineDepth = 2;
++    }
++#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */
++
++    errCode = FmGetSetPortParams(p_FmPort->h_Fm, &fmParams);
++    if (errCode)
++        RETURN_ERROR(MAJOR, errCode, NO_MSG);
++
++    /* get params for use in init */
++    p_FmPort->fmMuramPhysBaseAddr =
++            (uint64_t)((uint64_t)(fmParams.fmMuramPhysBaseAddr.low)
++                    | ((uint64_t)(fmParams.fmMuramPhysBaseAddr.high) << 32));
++    p_FmPort->h_FmMuram = FmGetMuramHandle(p_FmPort->h_Fm);
++
++    errCode = InitLowLevelDriver(p_FmPort);
++    if (errCode != E_OK)
++        RETURN_ERROR(MAJOR, errCode, NO_MSG);
++
++    FmPortDriverParamFree(p_FmPort);
++
++#if (DPAA_VERSION >= 11)
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_RX)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
++    {
++        t_FmPcdCtrlParamsPage *p_ParamsPage;
++
++        FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE,
++                         (void**)&p_ParamsPage);
++        ASSERT_COND(p_ParamsPage);
++
++        WRITE_UINT32(p_ParamsPage->misc, FM_CTL_PARAMS_PAGE_ALWAYS_ON);
++#ifdef FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675
++        if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++        {
++            WRITE_UINT32(
++                    p_ParamsPage->misc,
++                    (GET_UINT32(p_ParamsPage->misc) | FM_CTL_PARAMS_PAGE_OP_FIX_EN));
++            WRITE_UINT32(
++                    p_ParamsPage->discardMask,
++                    GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm));
++        }
++#endif /* FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675 */
++#ifdef FM_ERROR_VSP_NO_MATCH_SW006
++        if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++            WRITE_UINT32(
++                    p_ParamsPage->errorsDiscardMask,
++                    (GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm) | GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsem)));
++        else
++            WRITE_UINT32(
++                    p_ParamsPage->errorsDiscardMask,
++                    (GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm) | GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsem)));
++#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */
++    }
++#endif /* (DPAA_VERSION >= 11) */
++
++    if (p_FmPort->deepSleepVars.autoResMaxSizes)
++        FmPortConfigAutoResForDeepSleepSupport1(p_FmPort);
++    return E_OK;
++}
++
++/**************************************************************************//**
++ @Function      FM_PORT_Free
++
++ @Description   Frees all resources that were assigned to FM module.
++
++ Calling this routine invalidates the descriptor.
++
++ @Param[in]     h_FmPort - FM module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++ *//***************************************************************************/
++t_Error FM_PORT_Free(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_FmInterModulePortFreeParams fmParams;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++
++    if (p_FmPort->pcdEngines)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_STATE,
++                ("Trying to free a port with PCD. FM_PORT_DeletePCD must be called first."));
++
++    if (p_FmPort->enabled)
++    {
++        if (FM_PORT_Disable(p_FmPort) != E_OK)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM_PORT_Disable FAILED"));
++    }
++
++    if (p_FmPort->imEn)
++        FmPortImFree(p_FmPort);
++
++    FmPortDriverParamFree(p_FmPort);
++
++    memset(&fmParams, 0, sizeof(fmParams));
++    fmParams.hardwarePortId = p_FmPort->hardwarePortId;
++    fmParams.portType = (e_FmPortType)p_FmPort->portType;
++    fmParams.deqPipelineDepth =
++            p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth;
++
++    FmFreePortParams(p_FmPort->h_Fm, &fmParams);
++
++#if (DPAA_VERSION >= 11)
++    if (FmVSPFreeForPort(p_FmPort->h_Fm, p_FmPort->portType, p_FmPort->portId)
++            != E_OK)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("VSP free of port FAILED"));
++
++    if (p_FmPort->p_ParamsPage)
++        FM_MURAM_FreeMem(p_FmPort->h_FmMuram, p_FmPort->p_ParamsPage);
++#endif /* (DPAA_VERSION >= 11) */
++
++    if (p_FmPort->h_Spinlock)
++        XX_FreeSpinlock(p_FmPort->h_Spinlock);
++
++    XX_Free(p_FmPort);
++
++    return E_OK;
++}
++
++/*************************************************/
++/*       API Advanced Init unit functions        */
++/*************************************************/
++
++t_Error FM_PORT_ConfigNumOfOpenDmas(t_Handle h_FmPort, t_FmPortRsrc *p_OpenDmas)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    p_FmPort->p_FmPortDriverParam->setNumOfOpenDmas = TRUE;
++    memcpy(&p_FmPort->openDmas, p_OpenDmas, sizeof(t_FmPortRsrc));
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    memcpy(&p_FmPort->tasks, p_NumOfTasks, sizeof(t_FmPortRsrc));
++    p_FmPort->p_FmPortDriverParam->setNumOfTasks = TRUE;
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    p_FmPort->p_FmPortDriverParam->setSizeOfFifo = TRUE;
++    memcpy(&p_FmPort->fifoBufs, p_SizeOfFifo, sizeof(t_FmPortRsrc));
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigDeqHighPriority(t_Handle h_FmPort, bool highPri)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_RX))
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("not available for Rx ports"));
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.deq_high_pri = highPri;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigDeqType(t_Handle h_FmPort, e_FmPortDeqType deqType)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_RX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("not available for Rx ports"));
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.deq_type =
++            (enum fman_port_deq_type)deqType;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigDeqPrefetchOption(
++        t_Handle h_FmPort, e_FmPortDeqPrefetchOption deqPrefetchOption)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_RX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("not available for Rx ports"));
++    p_FmPort->p_FmPortDriverParam->dfltCfg.deq_prefetch_opt =
++            (enum fman_port_deq_prefetch)deqPrefetchOption;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigBackupPools(t_Handle h_FmPort,
++                                  t_FmBackupBmPools *p_BackupBmPools)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for Rx ports only"));
++
++    p_FmPort->p_FmPortDriverParam->p_BackupBmPools =
++            (t_FmBackupBmPools *)XX_Malloc(sizeof(t_FmBackupBmPools));
++    if (!p_FmPort->p_FmPortDriverParam->p_BackupBmPools)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_BackupBmPools allocation failed"));
++    memcpy(p_FmPort->p_FmPortDriverParam->p_BackupBmPools, p_BackupBmPools,
++           sizeof(t_FmBackupBmPools));
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigDeqByteCnt(t_Handle h_FmPort, uint16_t deqByteCnt)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_RX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("not available for Rx ports"));
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.deq_byte_cnt = deqByteCnt;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigBufferPrefixContent(
++        t_Handle h_FmPort, t_FmBufferPrefixContent *p_FmBufferPrefixContent)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    memcpy(&p_FmPort->p_FmPortDriverParam->bufferPrefixContent,
++           p_FmBufferPrefixContent, sizeof(t_FmBufferPrefixContent));
++    /* if dataAlign was not initialized by user, we return to driver's default */
++    if (!p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign)
++        p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign =
++                DEFAULT_PORT_bufferPrefixContent_dataAlign;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigCheksumLastBytesIgnore(t_Handle h_FmPort,
++                                             uint8_t checksumLastBytesIgnore)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.checksum_bytes_ignore =
++            checksumLastBytesIgnore;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigCutBytesFromEnd(t_Handle h_FmPort,
++                                      uint8_t cutBytesFromEnd)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for Rx ports only"));
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.rx_cut_end_bytes = cutBytesFromEnd;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigPoolDepletion(t_Handle h_FmPort,
++                                    t_FmBufPoolDepletion *p_BufPoolDepletion)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for Rx ports only"));
++
++    p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = TRUE;
++    memcpy(&p_FmPort->p_FmPortDriverParam->bufPoolDepletion, p_BufPoolDepletion,
++           sizeof(t_FmBufPoolDepletion));
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigObservedPoolDepletion(
++        t_Handle h_FmPort,
++        t_FmPortObservedBufPoolDepletion *p_FmPortObservedBufPoolDepletion)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for OP ports only"));
++
++    p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = TRUE;
++    memcpy(&p_FmPort->p_FmPortDriverParam->bufPoolDepletion,
++           &p_FmPortObservedBufPoolDepletion->poolDepletionParams,
++           sizeof(t_FmBufPoolDepletion));
++    memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools,
++           &p_FmPortObservedBufPoolDepletion->poolsParams,
++           sizeof(t_FmExtPools));
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigExtBufPools(t_Handle h_FmPort, t_FmExtPools *p_FmExtPools)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for OP ports only"));
++
++    memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools, p_FmExtPools,
++           sizeof(t_FmExtPools));
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigDontReleaseTxBufToBM(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_TX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for Tx ports only"));
++
++    p_FmPort->p_FmPortDriverParam->dontReleaseBuf = TRUE;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigDfltColor(t_Handle h_FmPort, e_FmPortColor color)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    p_FmPort->p_FmPortDriverParam->dfltCfg.color = (enum fman_port_color)color;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigSyncReq(t_Handle h_FmPort, bool syncReq)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_TX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("Not available for Tx ports"));
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.sync_req = syncReq;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigFrmDiscardOverride(t_Handle h_FmPort, bool override)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_TX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("Not available for Tx ports"));
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.discard_override = override;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigErrorsToDiscard(t_Handle h_FmPort,
++                                      fmPortFrameErrSelect_t errs)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
++        RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
++                     ("available for Rx and offline parsing ports only"));
++
++    p_FmPort->p_FmPortDriverParam->errorsToDiscard = errs;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigDmaSwapData(t_Handle h_FmPort, e_FmDmaSwapOption swapData)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.dma_swap_data =
++            (enum fman_port_dma_swap)swapData;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigDmaIcCacheAttr(t_Handle h_FmPort,
++                                     e_FmDmaCacheOption intContextCacheAttr)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.dma_ic_stash_on =
++            (bool)(intContextCacheAttr == e_FM_DMA_STASH);
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigDmaHdrAttr(t_Handle h_FmPort,
++                                 e_FmDmaCacheOption headerCacheAttr)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.dma_header_stash_on =
++            (bool)(headerCacheAttr == e_FM_DMA_STASH);
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigDmaScatterGatherAttr(
++        t_Handle h_FmPort, e_FmDmaCacheOption scatterGatherCacheAttr)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.dma_sg_stash_on =
++            (bool)(scatterGatherCacheAttr == e_FM_DMA_STASH);
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigDmaWriteOptimize(t_Handle h_FmPort, bool optimize)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_TX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("Not available for Tx ports"));
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.dma_write_optimize = optimize;
++
++    return E_OK;
++}
++
++#if (DPAA_VERSION >= 11)
++t_Error FM_PORT_ConfigNoScatherGather(t_Handle h_FmPort, bool noScatherGather)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    UNUSED(noScatherGather);
++    UNUSED(p_FmPort);
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    p_FmPort->p_FmPortDriverParam->noScatherGather = noScatherGather;
++
++    return E_OK;
++}
++#endif /* (DPAA_VERSION >= 11) */
++
++t_Error FM_PORT_ConfigForwardReuseIntContext(t_Handle h_FmPort,
++                                             bool forwardReuse)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for Rx ports only"));
++
++    p_FmPort->p_FmPortDriverParam->forwardReuseIntContext = forwardReuse;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigMaxFrameLength(t_Handle h_FmPort, uint16_t length)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    p_FmPort->maxFrameLength = length;
++
++    return E_OK;
++}
++
++#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
++t_Error FM_PORT_ConfigBCBWorkaround(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    p_FmPort->p_FmPortDriverParam->bcbWorkaround = TRUE;
++
++    return E_OK;
++}
++#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */
++
++/****************************************************/
++/*       Hidden-DEBUG Only API                      */
++/****************************************************/
++
++t_Error FM_PORT_ConfigTxFifoMinFillLevel(t_Handle h_FmPort,
++                                         uint32_t minFillLevel)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_TX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for Tx ports only"));
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_min_level = minFillLevel;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigFifoDeqPipelineDepth(t_Handle h_FmPort,
++                                           uint8_t deqPipelineDepth)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_RX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("Not available for Rx ports"));
++
++    if (p_FmPort->imEn)
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("Not available for IM ports!"));
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth =
++            deqPipelineDepth;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigTxFifoLowComfLevel(t_Handle h_FmPort,
++                                         uint32_t fifoLowComfLevel)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_TX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for Tx ports only"));
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_low_comf_level =
++            fifoLowComfLevel;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigRxFifoThreshold(t_Handle h_FmPort, uint32_t fifoThreshold)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for Rx ports only"));
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.rx_fifo_thr = fifoThreshold;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigRxFifoPriElevationLevel(t_Handle h_FmPort,
++                                              uint32_t priElevationLevel)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for Rx ports only"));
++
++    p_FmPort->p_FmPortDriverParam->dfltCfg.rx_pri_elevation = priElevationLevel;
++
++    return E_OK;
++}
++/****************************************************/
++/*       API Run-time Control unit functions        */
++/****************************************************/
++
++t_Error FM_PORT_SetNumOfOpenDmas(t_Handle h_FmPort,
++                                 t_FmPortRsrc *p_NumOfOpenDmas)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    if ((!p_NumOfOpenDmas->num) || (p_NumOfOpenDmas->num > MAX_NUM_OF_DMAS))
++        RETURN_ERROR( MAJOR, E_INVALID_VALUE,
++                     ("openDmas-num can't be larger than %d", MAX_NUM_OF_DMAS));
++    if (p_NumOfOpenDmas->extra > MAX_NUM_OF_EXTRA_DMAS)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("openDmas-extra can't be larger than %d", MAX_NUM_OF_EXTRA_DMAS));
++    err = FmSetNumOfOpenDmas(p_FmPort->h_Fm, p_FmPort->hardwarePortId,
++                             (uint8_t*)&p_NumOfOpenDmas->num,
++                             (uint8_t*)&p_NumOfOpenDmas->extra, FALSE);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    memcpy(&p_FmPort->openDmas, p_NumOfOpenDmas, sizeof(t_FmPortRsrc));
++
++    return E_OK;
++}
++
++t_Error FM_PORT_SetNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    /* only driver uses host command port, so ASSERT rather than  RETURN_ERROR */
++    ASSERT_COND(p_FmPort->portType != e_FM_PORT_TYPE_OH_HOST_COMMAND);
++
++    if ((!p_NumOfTasks->num) || (p_NumOfTasks->num > MAX_NUM_OF_TASKS))
++        RETURN_ERROR(
++                MAJOR, E_INVALID_VALUE,
++                ("NumOfTasks-num can't be larger than %d", MAX_NUM_OF_TASKS));
++    if (p_NumOfTasks->extra > MAX_NUM_OF_EXTRA_TASKS)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("NumOfTasks-extra can't be larger than %d", MAX_NUM_OF_EXTRA_TASKS));
++
++    err = FmSetNumOfTasks(p_FmPort->h_Fm, p_FmPort->hardwarePortId,
++                          (uint8_t*)&p_NumOfTasks->num,
++                          (uint8_t*)&p_NumOfTasks->extra, FALSE);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    /* update driver's struct */
++    memcpy(&p_FmPort->tasks, p_NumOfTasks, sizeof(t_FmPortRsrc));
++    return E_OK;
++}
++
++t_Error FM_PORT_SetSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_Error err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    if (!p_SizeOfFifo->num || (p_SizeOfFifo->num > MAX_PORT_FIFO_SIZE))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("SizeOfFifo-num has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE));
++    if (p_SizeOfFifo->num % BMI_FIFO_UNITS)
++        RETURN_ERROR(
++                MAJOR, E_INVALID_VALUE,
++                ("SizeOfFifo-num has to be divisible by %d", BMI_FIFO_UNITS));
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
++    {
++        /* extra FIFO size (allowed only to Rx ports) */
++        if (p_SizeOfFifo->extra % BMI_FIFO_UNITS)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("SizeOfFifo-extra has to be divisible by %d", BMI_FIFO_UNITS));
++    }
++    else
++        if (p_SizeOfFifo->extra)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                         (" No SizeOfFifo-extra for non Rx ports"));
++
++    memcpy(&p_FmPort->fifoBufs, p_SizeOfFifo, sizeof(t_FmPortRsrc));
++
++    /* we do not change user's parameter */
++    err = VerifySizeOfFifo(p_FmPort);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    err = FmSetSizeOfFifo(p_FmPort->h_Fm, p_FmPort->hardwarePortId,
++                          &p_SizeOfFifo->num, &p_SizeOfFifo->extra, FALSE);
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++uint32_t FM_PORT_GetBufferDataOffset(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0);
++    SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE,
++                              0);
++
++    return p_FmPort->bufferOffsets.dataOffset;
++}
++
++uint8_t * FM_PORT_GetBufferICInfo(t_Handle h_FmPort, char *p_Data)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE,
++                              NULL);
++
++    if (p_FmPort->bufferOffsets.pcdInfoOffset == ILLEGAL_BASE)
++        return NULL;
++
++    return (uint8_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.pcdInfoOffset);
++}
++
++t_FmPrsResult * FM_PORT_GetBufferPrsResult(t_Handle h_FmPort, char *p_Data)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE,
++                              NULL);
++
++    if (p_FmPort->bufferOffsets.prsResultOffset == ILLEGAL_BASE)
++        return NULL;
++
++    return (t_FmPrsResult *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.prsResultOffset);
++}
++
++uint64_t * FM_PORT_GetBufferTimeStamp(t_Handle h_FmPort, char *p_Data)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE,
++                              NULL);
++
++    if (p_FmPort->bufferOffsets.timeStampOffset == ILLEGAL_BASE)
++        return NULL;
++
++    return (uint64_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.timeStampOffset);
++}
++
++uint8_t * FM_PORT_GetBufferHashResult(t_Handle h_FmPort, char *p_Data)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE,
++                              NULL);
++
++    if (p_FmPort->bufferOffsets.hashResultOffset == ILLEGAL_BASE)
++        return NULL;
++
++    return (uint8_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.hashResultOffset);
++}
++
++t_Error FM_PORT_Disable(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    int err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    if (p_FmPort->imEn)
++        FmPortImDisable(p_FmPort);
++
++    err = fman_port_disable(&p_FmPort->port);
++    if (err == -EBUSY)
++    {
++        DBG(WARNING, ("%s: BMI or QMI is Busy. Port forced down",
++               p_FmPort->name));
++    }
++    else
++        if (err != 0)
++        {
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_disable"));
++        }
++
++    p_FmPort->enabled = FALSE;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_Enable(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    int err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    /* Used by FM_PORT_Free routine as indication
++     if to disable port. Thus set it to TRUE prior
++     to enabling itself. This way if part of enable
++     process fails there will be still things
++     to disable during Free. For example, if BMI
++     enable succeeded but QMI failed, still  BMI
++     needs to be disabled by Free. */
++    p_FmPort->enabled = TRUE;
++
++    if (p_FmPort->imEn)
++        FmPortImEnable(p_FmPort);
++
++    err = fman_port_enable(&p_FmPort->port);
++    if (err != 0)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_enable"));
++
++    return E_OK;
++}
++
++t_Error FM_PORT_SetRateLimit(t_Handle h_FmPort, t_FmPortRateLimit *p_RateLimit)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    uint8_t factor, countUnitBit;
++    uint16_t baseGran;
++    struct fman_port_rate_limiter params;
++    int err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    switch (p_FmPort->portType)
++    {
++        case (e_FM_PORT_TYPE_TX_10G):
++        case (e_FM_PORT_TYPE_TX):
++            baseGran = BMI_RATE_LIMIT_GRAN_TX;
++            break;
++        case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++            baseGran = BMI_RATE_LIMIT_GRAN_OP;
++            break;
++        default:
++            RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
++                         ("available for Tx and Offline parsing ports only"));
++    }
++
++    countUnitBit = (uint8_t)FmGetTimeStampScale(p_FmPort->h_Fm); /* TimeStamp per nano seconds units */
++    /* normally, we use 1 usec as the reference count */
++    factor = 1;
++    /* if ratelimit is too small for a 1usec factor, multiply the factor */
++    while (p_RateLimit->rateLimit < baseGran / factor)
++    {
++        if (countUnitBit == 31)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Rate limit is too small"));
++
++        countUnitBit++;
++        factor <<= 1;
++    }
++    /* if ratelimit is too large for a 1usec factor, it is also larger than max rate*/
++    if (p_RateLimit->rateLimit
++            > ((uint32_t)baseGran * (1 << 10) * (uint32_t)factor))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Rate limit is too large"));
++
++    if (!p_RateLimit->maxBurstSize
++            || (p_RateLimit->maxBurstSize > BMI_RATE_LIMIT_MAX_BURST_SIZE))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("maxBurstSize must be between 1K and %dk", BMI_RATE_LIMIT_MAX_BURST_SIZE));
++
++    params.count_1micro_bit = (uint8_t)FmGetTimeStampScale(p_FmPort->h_Fm);
++    params.high_burst_size_gran = FALSE;
++    params.burst_size = p_RateLimit->maxBurstSize;
++    params.rate = p_RateLimit->rateLimit;
++    params.rate_factor = E_FMAN_PORT_RATE_DOWN_NONE;
++
++    if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++    {
++#ifndef FM_NO_ADVANCED_RATE_LIMITER
++
++        if ((p_FmPort->fmRevInfo.majorRev == 4)
++                || (p_FmPort->fmRevInfo.majorRev >= 6))
++        {
++            params.high_burst_size_gran = TRUE;
++        }
++        else
++#endif /* ! FM_NO_ADVANCED_RATE_LIMITER */
++        {
++            if (p_RateLimit->rateLimitDivider
++                    != e_FM_PORT_DUAL_RATE_LIMITER_NONE)
++                RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
++                             ("FM_PORT_ConfigDualRateLimitScaleDown"));
++
++            if (p_RateLimit->maxBurstSize % 1000)
++            {
++                p_RateLimit->maxBurstSize =
++                        (uint16_t)((p_RateLimit->maxBurstSize / 1000) + 1);
++                DBG(WARNING, ("rateLimit.maxBurstSize rounded up to %d", (p_RateLimit->maxBurstSize/1000+1)*1000));
++            }
++            else
++                p_RateLimit->maxBurstSize = (uint16_t)(p_RateLimit->maxBurstSize
++                        / 1000);
++        }
++        params.rate_factor =
++                (enum fman_port_rate_limiter_scale_down)p_RateLimit->rateLimitDivider;
++        params.burst_size = p_RateLimit->maxBurstSize;
++    }
++
++    err = fman_port_set_rate_limiter(&p_FmPort->port, &params);
++    if (err != 0)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_rate_limiter"));
++
++    return E_OK;
++}
++
++t_Error FM_PORT_DeleteRateLimit(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    int err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_RX)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND))
++        RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
++                     ("available for Tx and Offline parsing ports only"));
++
++    err = fman_port_delete_rate_limiter(&p_FmPort->port);
++    if (err != 0)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_rate_limiter"));
++    return E_OK;
++}
++
++t_Error FM_PORT_SetPfcPrioritiesMappingToQmanWQ(t_Handle h_FmPort, uint8_t prio,
++                                                uint8_t wq)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    uint32_t tmpReg;
++    uint32_t wqTmpReg;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_TX)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_TX_10G))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("PFC mapping is available for Tx ports only"));
++
++    if (prio > 7)
++        RETURN_ERROR(MAJOR, E_NOT_IN_RANGE,
++                     ("PFC priority (%d) is out of range (0-7)", prio));
++    if (wq > 7)
++        RETURN_ERROR(MAJOR, E_NOT_IN_RANGE,
++                     ("WQ (%d) is out of range (0-7)", wq));
++
++    tmpReg = GET_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tpfcm[0]);
++    tmpReg &= ~(0xf << ((7 - prio) * 4));
++    wqTmpReg = ((uint32_t)wq << ((7 - prio) * 4));
++    tmpReg |= wqTmpReg;
++
++    WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tpfcm[0],
++                 tmpReg);
++
++    return E_OK;
++}
++
++t_Error FM_PORT_SetFrameQueueCounters(t_Handle h_FmPort, bool enable)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    fman_port_set_queue_cnt_mode(&p_FmPort->port, enable);
++
++    return E_OK;
++}
++
++t_Error FM_PORT_SetPerformanceCounters(t_Handle h_FmPort, bool enable)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    int err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    err = fman_port_set_perf_cnt_mode(&p_FmPort->port, enable);
++    if (err != 0)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_perf_cnt_mode"));
++    return E_OK;
++}
++
++t_Error FM_PORT_SetPerformanceCountersParams(
++        t_Handle h_FmPort, t_FmPortPerformanceCnt *p_FmPortPerformanceCnt)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    struct fman_port_perf_cnt_params params;
++    int err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++
++    /* check parameters */
++    if (!p_FmPortPerformanceCnt->taskCompVal
++            || (p_FmPortPerformanceCnt->taskCompVal > p_FmPort->tasks.num))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("taskCompVal (%d) has to be in the range of 1 - %d (current value)!", p_FmPortPerformanceCnt->taskCompVal, p_FmPort->tasks.num));
++    if (!p_FmPortPerformanceCnt->dmaCompVal
++            || (p_FmPortPerformanceCnt->dmaCompVal > p_FmPort->openDmas.num))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("dmaCompVal (%d) has to be in the range of 1 - %d (current value)!", p_FmPortPerformanceCnt->dmaCompVal, p_FmPort->openDmas.num));
++    if (!p_FmPortPerformanceCnt->fifoCompVal
++            || (p_FmPortPerformanceCnt->fifoCompVal > p_FmPort->fifoBufs.num))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("fifoCompVal (%d) has to be in the range of 256 - %d (current value)!", p_FmPortPerformanceCnt->fifoCompVal, p_FmPort->fifoBufs.num));
++    if (p_FmPortPerformanceCnt->fifoCompVal % BMI_FIFO_UNITS)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("fifoCompVal (%d) has to be divisible by %d", p_FmPortPerformanceCnt->fifoCompVal, BMI_FIFO_UNITS));
++
++    switch (p_FmPort->portType)
++    {
++        case (e_FM_PORT_TYPE_RX_10G):
++        case (e_FM_PORT_TYPE_RX):
++            if (!p_FmPortPerformanceCnt->queueCompVal
++                    || (p_FmPortPerformanceCnt->queueCompVal
++                            > MAX_PERFORMANCE_RX_QUEUE_COMP))
++                RETURN_ERROR(
++                        MAJOR,
++                        E_INVALID_VALUE,
++                        ("performanceCnt.queueCompVal for Rx has to be in the range of 1 - %d", MAX_PERFORMANCE_RX_QUEUE_COMP));
++            break;
++        case (e_FM_PORT_TYPE_TX_10G):
++        case (e_FM_PORT_TYPE_TX):
++            if (!p_FmPortPerformanceCnt->queueCompVal
++                    || (p_FmPortPerformanceCnt->queueCompVal
++                            > MAX_PERFORMANCE_TX_QUEUE_COMP))
++                RETURN_ERROR(
++                        MAJOR,
++                        E_INVALID_VALUE,
++                        ("performanceCnt.queueCompVal for Tx has to be in the range of 1 - %d", MAX_PERFORMANCE_TX_QUEUE_COMP));
++            break;
++        case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++        case (e_FM_PORT_TYPE_OH_HOST_COMMAND):
++            if (p_FmPortPerformanceCnt->queueCompVal)
++                RETURN_ERROR(
++                        MAJOR,
++                        E_INVALID_VALUE,
++                        ("performanceCnt.queueCompVal is not relevant for H/O ports."));
++            break;
++        default:
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
++    }
++
++    params.task_val = p_FmPortPerformanceCnt->taskCompVal;
++    params.queue_val = p_FmPortPerformanceCnt->queueCompVal;
++    params.dma_val = p_FmPortPerformanceCnt->dmaCompVal;
++    params.fifo_val = p_FmPortPerformanceCnt->fifoCompVal;
++
++    err = fman_port_set_perf_cnt_params(&p_FmPort->port, &params);
++    if (err != 0)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_perf_cnt_params"));
++
++    return E_OK;
++}
++
++t_Error FM_PORT_AnalyzePerformanceParams(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_FmPortPerformanceCnt currParams, savedParams;
++    t_Error err;
++    bool underTest, failed = FALSE;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++
++    XX_Print("Analyzing Performance parameters for port (type %d, id%d)\n",
++             p_FmPort->portType, p_FmPort->portId);
++
++    currParams.taskCompVal = (uint8_t)p_FmPort->tasks.num;
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND))
++        currParams.queueCompVal = 0;
++    else
++        currParams.queueCompVal = 1;
++    currParams.dmaCompVal = (uint8_t)p_FmPort->openDmas.num;
++    currParams.fifoCompVal = p_FmPort->fifoBufs.num;
++
++    FM_PORT_SetPerformanceCounters(p_FmPort, FALSE);
++    ClearPerfCnts(p_FmPort);
++    if ((err = FM_PORT_SetPerformanceCountersParams(p_FmPort, &currParams))
++            != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    FM_PORT_SetPerformanceCounters(p_FmPort, TRUE);
++    XX_UDelay(1000000);
++    FM_PORT_SetPerformanceCounters(p_FmPort, FALSE);
++    if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL))
++    {
++        XX_Print(
++                "Max num of defined port tasks (%d) utilized - Please enlarge\n",
++                p_FmPort->tasks.num);
++        failed = TRUE;
++    }
++    if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL))
++    {
++        XX_Print(
++                "Max num of defined port openDmas (%d) utilized - Please enlarge\n",
++                p_FmPort->openDmas.num);
++        failed = TRUE;
++    }
++    if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL))
++    {
++        XX_Print(
++                "Max size of defined port fifo (%d) utilized - Please enlarge\n",
++                p_FmPort->fifoBufs.num);
++        failed = TRUE;
++    }
++    if (failed)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++
++    memset(&savedParams, 0, sizeof(savedParams));
++    while (TRUE)
++    {
++        underTest = FALSE;
++        if ((currParams.taskCompVal != 1) && !savedParams.taskCompVal)
++        {
++            currParams.taskCompVal--;
++            underTest = TRUE;
++        }
++        if ((currParams.dmaCompVal != 1) && !savedParams.dmaCompVal)
++        {
++            currParams.dmaCompVal--;
++            underTest = TRUE;
++        }
++        if ((currParams.fifoCompVal != BMI_FIFO_UNITS)
++                && !savedParams.fifoCompVal)
++        {
++            currParams.fifoCompVal -= BMI_FIFO_UNITS;
++            underTest = TRUE;
++        }
++        if (!underTest)
++            break;
++
++        ClearPerfCnts(p_FmPort);
++        if ((err = FM_PORT_SetPerformanceCountersParams(p_FmPort, &currParams))
++                != E_OK)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        FM_PORT_SetPerformanceCounters(p_FmPort, TRUE);
++        XX_UDelay(1000000);
++        FM_PORT_SetPerformanceCounters(p_FmPort, FALSE);
++
++        if (!savedParams.taskCompVal
++                && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL))
++            savedParams.taskCompVal = (uint8_t)(currParams.taskCompVal + 2);
++        if (!savedParams.dmaCompVal
++                && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL))
++            savedParams.dmaCompVal = (uint8_t)(currParams.dmaCompVal + 2);
++        if (!savedParams.fifoCompVal
++                && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL))
++            savedParams.fifoCompVal = currParams.fifoCompVal
++                    + (2 * BMI_FIFO_UNITS);
++    }
++
++    XX_Print("best vals: tasks %d, dmas %d, fifos %d\n",
++             savedParams.taskCompVal, savedParams.dmaCompVal,
++             savedParams.fifoCompVal);
++    return E_OK;
++}
++
++t_Error FM_PORT_SetStatisticsCounters(t_Handle h_FmPort, bool enable)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    int err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    err = fman_port_set_stats_cnt_mode(&p_FmPort->port, enable);
++    if (err != 0)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_stats_cnt_mode"));
++    return E_OK;
++}
++
++t_Error FM_PORT_SetErrorsRoute(t_Handle h_FmPort, fmPortFrameErrSelect_t errs)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    volatile uint32_t *p_ErrDiscard = NULL;
++    int err;
++
++    UNUSED(p_ErrDiscard);
++    err = fman_port_set_err_mask(&p_FmPort->port, (uint32_t)errs);
++    if (err != 0)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_err_mask"));
++
++#ifdef FM_ERROR_VSP_NO_MATCH_SW006
++    if (p_FmPort->fmRevInfo.majorRev >= 6)
++    {
++        t_FmPcdCtrlParamsPage *p_ParamsPage;
++
++        FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE,
++                         (void**)&p_ParamsPage);
++        ASSERT_COND(p_ParamsPage);
++        switch (p_FmPort->portType)
++        {
++            case (e_FM_PORT_TYPE_RX_10G):
++            case (e_FM_PORT_TYPE_RX):
++                p_ErrDiscard =
++                        &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm;
++                break;
++            case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++                p_ErrDiscard =
++                        &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm;
++                break;
++            default:
++                RETURN_ERROR(
++                        MAJOR, E_INVALID_OPERATION,
++                        ("available for Rx and offline parsing ports only"));
++        }
++        WRITE_UINT32(p_ParamsPage->errorsDiscardMask,
++                     GET_UINT32(*p_ErrDiscard) | errs);
++    }
++#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */
++
++    return E_OK;
++}
++
++t_Error FM_PORT_SetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId,
++                                   bool enable)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    int err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(poolId<BM_MAX_NUM_OF_POOLS, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for Rx ports only"));
++
++    err = fman_port_set_bpool_cnt_mode(&p_FmPort->port, poolId, enable);
++    if (err != 0)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_bpool_cnt_mode"));
++    return E_OK;
++}
++
++t_Error FM_PORT_GetBmiCounters(t_Handle h_FmPort, t_FmPortBmiStats *p_BmiStats)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
++            || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)){
++        p_BmiStats->cntCycle =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_CYCLE);
++            /* fmbm_rccn */
++        p_BmiStats->cntTaskUtil =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL);
++            /* fmbm_rtuc */
++        p_BmiStats->cntQueueUtil =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL);
++            /* fmbm_rrquc */
++        p_BmiStats->cntDmaUtil =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL);
++            /* fmbm_rduc */
++        p_BmiStats->cntFifoUtil =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL);
++            /* fmbm_rfuc */
++        p_BmiStats->cntRxPauseActivation =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION);
++            /* fmbm_rpac */
++        p_BmiStats->cntFrame =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FRAME);
++            /* fmbm_rfrc */
++        p_BmiStats->cntDiscardFrame =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DISCARD_FRAME);
++            /* fmbm_rfdc */
++        p_BmiStats->cntDeallocBuf =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DEALLOC_BUF);
++            /* fmbm_rbdc */
++        p_BmiStats->cntRxBadFrame =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_BAD_FRAME);
++            /* fmbm_rfbc */
++        p_BmiStats->cntRxLargeFrame =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_LARGE_FRAME);
++            /* fmbm_rlfc */
++        p_BmiStats->cntRxFilterFrame =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_FILTER_FRAME);
++            /* fmbm_rffc */
++        p_BmiStats->cntRxListDmaErr =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR);
++            /* fmbm_rfldec */
++        p_BmiStats->cntRxOutOfBuffersDiscard =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD);
++            /* fmbm_rodc */
++        p_BmiStats->cntWredDiscard = 0;
++        p_BmiStats->cntLengthErr = 0;
++        p_BmiStats->cntUnsupportedFormat = 0;
++    }
++    else if ((p_FmPort->portType == e_FM_PORT_TYPE_TX)
++                || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)){
++        p_BmiStats->cntCycle =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_CYCLE);
++            /* fmbm_tccn */
++        p_BmiStats->cntTaskUtil =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL);
++            /* fmbm_ttuc */
++        p_BmiStats->cntQueueUtil =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL);
++            /* fmbm_ttcquc */
++        p_BmiStats->cntDmaUtil =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL);
++            /* fmbm_tduc */
++        p_BmiStats->cntFifoUtil =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL);
++            /* fmbm_tfuc */
++        p_BmiStats->cntRxPauseActivation = 0;
++        p_BmiStats->cntFrame =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FRAME);
++            /* fmbm_tfrc */
++        p_BmiStats->cntDiscardFrame =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DISCARD_FRAME);
++            /* fmbm_tfdc */
++        p_BmiStats->cntDeallocBuf =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DEALLOC_BUF);
++            /* fmbm_tbdc */
++        p_BmiStats->cntRxBadFrame = 0;
++        p_BmiStats->cntRxLargeFrame = 0;
++        p_BmiStats->cntRxFilterFrame = 0;
++        p_BmiStats->cntRxListDmaErr = 0;
++        p_BmiStats->cntRxOutOfBuffersDiscard = 0;
++        p_BmiStats->cntWredDiscard = 0;
++        p_BmiStats->cntLengthErr =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_LENGTH_ERR);
++            /* fmbm_tfledc */
++        p_BmiStats->cntUnsupportedFormat =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT);
++            /* fmbm_tfufdc */
++    }
++    else if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) {
++        p_BmiStats->cntCycle =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_CYCLE);
++            /* fmbm_occn */
++        p_BmiStats->cntTaskUtil =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL);
++            /* fmbm_otuc */
++        p_BmiStats->cntQueueUtil = 0;
++        p_BmiStats->cntDmaUtil =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL);
++            /* fmbm_oduc */
++        p_BmiStats->cntFifoUtil =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL);
++            /* fmbm_ofuc*/
++        p_BmiStats->cntRxPauseActivation = 0;
++        p_BmiStats->cntFrame =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FRAME);
++            /* fmbm_ofrc */
++        p_BmiStats->cntDiscardFrame =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DISCARD_FRAME);
++            /* fmbm_ofdc */
++        p_BmiStats->cntDeallocBuf =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DEALLOC_BUF);
++            /* fmbm_obdc*/
++        p_BmiStats->cntRxBadFrame = 0;
++        p_BmiStats->cntRxLargeFrame = 0;
++        p_BmiStats->cntRxFilterFrame =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_FILTER_FRAME);
++            /* fmbm_offc */
++        p_BmiStats->cntRxListDmaErr =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR);
++            /* fmbm_ofldec */
++        p_BmiStats->cntRxOutOfBuffersDiscard =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD);
++            /* fmbm_rodc */
++        p_BmiStats->cntWredDiscard =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_WRED_DISCARD);
++            /* fmbm_ofwdc */
++        p_BmiStats->cntLengthErr =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_LENGTH_ERR);
++            /* fmbm_ofledc */
++        p_BmiStats->cntUnsupportedFormat =
++            FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT);
++            /* fmbm_ofufdc */
++    }
++    return E_OK;
++}
++
++uint32_t FM_PORT_GetCounter(t_Handle h_FmPort, e_FmPortCounters counter)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    bool bmiCounter = FALSE;
++    enum fman_port_stats_counters statsType;
++    enum fman_port_perf_counters perfType;
++    enum fman_port_qmi_counters queueType;
++    bool isStats;
++    t_Error errCode;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    switch (counter)
++    {
++        case (e_FM_PORT_COUNTERS_DEQ_TOTAL):
++        case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT):
++        case (e_FM_PORT_COUNTERS_DEQ_CONFIRM):
++            /* check that counter is available for the port type */
++            if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
++                    || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
++            {
++                REPORT_ERROR(MINOR, E_INVALID_STATE,
++                        ("Requested counter is not available for Rx ports"));
++                return 0;
++            }
++            bmiCounter = FALSE;
++            break;
++        case (e_FM_PORT_COUNTERS_ENQ_TOTAL):
++            bmiCounter = FALSE;
++            break;
++        default: /* BMI counters (or error - will be checked in BMI routine )*/
++            bmiCounter = TRUE;
++            break;
++    }
++
++    if (bmiCounter)
++    {
++        errCode = BmiPortCheckAndGetCounterType(p_FmPort, counter, &statsType,
++                                                &perfType, &isStats);
++        if (errCode != E_OK)
++        {
++            REPORT_ERROR(MINOR, errCode, NO_MSG);
++            return 0;
++        }
++        if (isStats)
++            return fman_port_get_stats_counter(&p_FmPort->port, statsType);
++        else
++            return fman_port_get_perf_counter(&p_FmPort->port, perfType);
++    }
++    else /* QMI counter */
++    {
++        /* check that counters are enabled */
++        if (!(GET_UINT32(p_FmPort->port.qmi_regs->fmqm_pnc)
++                & QMI_PORT_CFG_EN_COUNTERS))
++
++        {
++            REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled"));
++            return 0;
++        }
++
++        /* Set counter */
++        switch (counter)
++        {
++            case (e_FM_PORT_COUNTERS_ENQ_TOTAL):
++                queueType = E_FMAN_PORT_ENQ_TOTAL;
++                break;
++            case (e_FM_PORT_COUNTERS_DEQ_TOTAL):
++                queueType = E_FMAN_PORT_DEQ_TOTAL;
++                break;
++            case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT):
++                queueType = E_FMAN_PORT_DEQ_FROM_DFLT;
++                break;
++            case (e_FM_PORT_COUNTERS_DEQ_CONFIRM):
++                queueType = E_FMAN_PORT_DEQ_CONFIRM;
++                break;
++            default:
++                REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available"));
++                return 0;
++        }
++
++        return fman_port_get_qmi_counter(&p_FmPort->port, queueType);
++    }
++
++    return 0;
++}
++
++t_Error FM_PORT_ModifyCounter(t_Handle h_FmPort, e_FmPortCounters counter,
++                              uint32_t value)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    bool bmiCounter = FALSE;
++    enum fman_port_stats_counters statsType;
++    enum fman_port_perf_counters perfType;
++    enum fman_port_qmi_counters queueType;
++    bool isStats;
++    t_Error errCode;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    switch (counter)
++    {
++        case (e_FM_PORT_COUNTERS_DEQ_TOTAL):
++        case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT):
++        case (e_FM_PORT_COUNTERS_DEQ_CONFIRM):
++            /* check that counter is available for the port type */
++            if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
++                    || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
++                RETURN_ERROR(
++                        MINOR, E_INVALID_STATE,
++                        ("Requested counter is not available for Rx ports"));
++        case (e_FM_PORT_COUNTERS_ENQ_TOTAL):
++            bmiCounter = FALSE;
++            break;
++        default: /* BMI counters (or error - will be checked in BMI routine )*/
++            bmiCounter = TRUE;
++            break;
++    }
++
++    if (bmiCounter)
++    {
++        errCode = BmiPortCheckAndGetCounterType(p_FmPort, counter, &statsType,
++                                                &perfType, &isStats);
++        if (errCode != E_OK)
++        {
++            RETURN_ERROR(MINOR, errCode, NO_MSG);
++        }
++        if (isStats)
++            fman_port_set_stats_counter(&p_FmPort->port, statsType, value);
++        else
++            fman_port_set_perf_counter(&p_FmPort->port, perfType, value);
++    }
++    else /* QMI counter */
++    {
++        /* check that counters are enabled */
++        if (!(GET_UINT32(p_FmPort->port.qmi_regs->fmqm_pnc)
++                & QMI_PORT_CFG_EN_COUNTERS))
++        {
++            RETURN_ERROR(MINOR, E_INVALID_STATE,
++                         ("Requested counter was not enabled"));
++        }
++
++        /* Set counter */
++        switch (counter)
++        {
++            case (e_FM_PORT_COUNTERS_ENQ_TOTAL):
++                queueType = E_FMAN_PORT_ENQ_TOTAL;
++                break;
++            case (e_FM_PORT_COUNTERS_DEQ_TOTAL):
++                queueType = E_FMAN_PORT_DEQ_TOTAL;
++                break;
++            case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT):
++                queueType = E_FMAN_PORT_DEQ_FROM_DFLT;
++                break;
++            case (e_FM_PORT_COUNTERS_DEQ_CONFIRM):
++                queueType = E_FMAN_PORT_DEQ_CONFIRM;
++                break;
++            default:
++                RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                             ("Requested counter is not available"));
++        }
++
++        fman_port_set_qmi_counter(&p_FmPort->port, queueType, value);
++    }
++
++    return E_OK;
++}
++
++uint32_t FM_PORT_GetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX)
++            && (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
++    {
++        REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for non-Rx ports"));
++        return 0;
++    }
++    return fman_port_get_bpool_counter(&p_FmPort->port, poolId);
++}
++
++t_Error FM_PORT_ModifyAllocBufCounter(t_Handle h_FmPort, uint8_t poolId,
++                                      uint32_t value)
++{
++    t_FmPort *p_FmPort = (t_FmPort *)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX)
++            && (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
++        RETURN_ERROR( MINOR, E_INVALID_STATE,
++                     ("Requested counter is not available for non-Rx ports"));
++
++    fman_port_set_bpool_counter(&p_FmPort->port, poolId, value);
++    return E_OK;
++}
++bool FM_PORT_IsStalled(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_Error err;
++    bool isStalled;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, FALSE);
++    SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE,
++                              FALSE);
++
++    err = FmIsPortStalled(p_FmPort->h_Fm, p_FmPort->hardwarePortId, &isStalled);
++    if (err != E_OK)
++    {
++        REPORT_ERROR(MAJOR, err, NO_MSG);
++        return TRUE;
++    }
++    return isStalled;
++}
++
++t_Error FM_PORT_ReleaseStalled(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    return FmResumeStalledPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId);
++}
++
++t_Error FM_PORT_SetRxL4ChecksumVerify(t_Handle h_FmPort, bool l4Checksum)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    int err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for Rx ports only"));
++
++    if (l4Checksum)
++        err = fman_port_modify_rx_fd_bits(
++                &p_FmPort->port, (uint8_t)(BMI_PORT_RFNE_FRWD_DCL4C >> 24),
++                TRUE);
++    else
++        err = fman_port_modify_rx_fd_bits(
++                &p_FmPort->port, (uint8_t)(BMI_PORT_RFNE_FRWD_DCL4C >> 24),
++                FALSE);
++    if (err != 0)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_modify_rx_fd_bits"));
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++/*       API Run-time PCD Control unit functions                             */
++/*****************************************************************************/
++
++#if (DPAA_VERSION >= 11)
++t_Error FM_PORT_VSPAlloc(t_Handle h_FmPort, t_FmPortVSPAllocParams *p_VSPParams)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_Error err = E_OK;
++    volatile uint32_t *p_BmiStorageProfileId = NULL, *p_BmiVspe = NULL;
++    uint32_t tmpReg = 0, tmp = 0;
++    uint16_t hwStoragePrflId;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->h_Fm, E_INVALID_HANDLE);
++    /*for numOfProfiles = 0 don't call this function*/
++    SANITY_CHECK_RETURN_ERROR(p_VSPParams->numOfProfiles, E_INVALID_VALUE);
++    /*dfltRelativeId should be in the range of numOfProfiles*/
++    SANITY_CHECK_RETURN_ERROR(
++            p_VSPParams->dfltRelativeId < p_VSPParams->numOfProfiles,
++            E_INVALID_VALUE);
++    /*p_FmPort should be from Rx type or OP*/
++    SANITY_CHECK_RETURN_ERROR(
++            ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) || (p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)),
++            E_INVALID_VALUE);
++    /*port should be disabled*/
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->enabled, E_INVALID_STATE);
++    /*if its called for Rx port relevant Tx Port should be passed (initialized) too and it should be disabled*/
++    SANITY_CHECK_RETURN_ERROR(
++            ((p_VSPParams->h_FmTxPort && !((t_FmPort *)(p_VSPParams->h_FmTxPort))->enabled) || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)),
++            E_INVALID_VALUE);
++    /*should be called before SetPCD - this port should be without PCD*/
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->pcdEngines, E_INVALID_STATE);
++
++    /*alloc window of VSPs for this port*/
++    err = FmVSPAllocForPort(p_FmPort->h_Fm, p_FmPort->portType,
++                            p_FmPort->portId, p_VSPParams->numOfProfiles);
++    if (err != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    /*get absolute VSP ID for dfltRelative*/
++    err = FmVSPGetAbsoluteProfileId(p_FmPort->h_Fm, p_FmPort->portType,
++                                    p_FmPort->portId,
++                                    p_VSPParams->dfltRelativeId,
++                                    &hwStoragePrflId);
++    if (err != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    /*fill relevant registers for p_FmPort and relative TxPort in the case p_FmPort from Rx type*/
++    switch (p_FmPort->portType)
++    {
++        case (e_FM_PORT_TYPE_RX_10G):
++        case (e_FM_PORT_TYPE_RX):
++            p_BmiStorageProfileId =
++                    &(((t_FmPort *)(p_VSPParams->h_FmTxPort))->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfqid);
++            p_BmiVspe =
++                    &(((t_FmPort *)(p_VSPParams->h_FmTxPort))->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfne);
++
++            tmpReg = GET_UINT32(*p_BmiStorageProfileId) & ~BMI_SP_ID_MASK;
++            tmpReg |= (uint32_t)hwStoragePrflId << BMI_SP_ID_SHIFT;
++            WRITE_UINT32(*p_BmiStorageProfileId, tmpReg);
++
++            tmpReg = GET_UINT32(*p_BmiVspe);
++            WRITE_UINT32(*p_BmiVspe, tmpReg | BMI_SP_EN);
++
++            p_BmiStorageProfileId =
++                    &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfqid;
++            p_BmiVspe = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rpp;
++            hwStoragePrflId = p_VSPParams->dfltRelativeId;
++            break;
++
++        case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++            tmpReg = NIA_ENG_BMI | NIA_BMI_AC_FETCH_ALL_FRAME;
++            WRITE_UINT32( p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndn,
++                         tmpReg);
++
++            p_BmiStorageProfileId =
++                    &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofqid;
++            p_BmiVspe = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_opp;
++            tmp |= BMI_EBD_EN;
++            break;
++
++        default:
++            RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
++                         ("available for Rx and offline parsing ports only"));
++    }
++
++    p_FmPort->vspe = TRUE;
++    p_FmPort->dfltRelativeId = p_VSPParams->dfltRelativeId;
++
++    tmpReg = GET_UINT32(*p_BmiStorageProfileId) & ~BMI_SP_ID_MASK;
++    tmpReg |= (uint32_t)hwStoragePrflId << BMI_SP_ID_SHIFT;
++    WRITE_UINT32(*p_BmiStorageProfileId, tmpReg);
++
++    tmpReg = GET_UINT32(*p_BmiVspe);
++    WRITE_UINT32(*p_BmiVspe, tmpReg | BMI_SP_EN | tmp);
++    return E_OK;
++}
++#endif /* (DPAA_VERSION >= 11) */
++
++t_Error FM_PORT_PcdPlcrAllocProfiles(t_Handle h_FmPort, uint16_t numOfProfiles)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_Error err = E_OK;
++
++    p_FmPort->h_FmPcd = FmGetPcdHandle(p_FmPort->h_Fm);
++    ASSERT_COND(p_FmPort->h_FmPcd);
++
++    if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
++    {
++        DBG(TRACE, ("FM Port Try Lock - BUSY"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    if (numOfProfiles)
++    {
++        err = FmPcdPlcrAllocProfiles(p_FmPort->h_FmPcd,
++                                     p_FmPort->hardwarePortId, numOfProfiles);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++    /* set the port handle within the PCD policer, even if no profiles defined */
++    FmPcdPortRegister(p_FmPort->h_FmPcd, h_FmPort, p_FmPort->hardwarePortId);
++
++    RELEASE_LOCK(p_FmPort->lock);
++
++    return E_OK;
++}
++
++t_Error FM_PORT_PcdPlcrFreeProfiles(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_Error err = E_OK;
++
++    if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
++    {
++        DBG(TRACE, ("FM Port Try Lock - BUSY"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = FmPcdPlcrFreeProfiles(p_FmPort->h_FmPcd, p_FmPort->hardwarePortId);
++
++    RELEASE_LOCK(p_FmPort->lock);
++
++    if (err)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    return E_OK;
++}
++
++t_Error FM_PORT_PcdKgModifyInitialScheme(t_Handle h_FmPort,
++                                         t_FmPcdKgSchemeSelect *p_FmPcdKgScheme)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    volatile uint32_t *p_BmiHpnia = NULL;
++    uint32_t tmpReg;
++    uint8_t relativeSchemeId;
++    uint8_t physicalSchemeId;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG,
++                              E_INVALID_STATE);
++
++    tmpReg = (uint32_t)((p_FmPort->pcdEngines & FM_PCD_CC) ? NIA_KG_CC_EN : 0);
++    switch (p_FmPort->portType)
++    {
++        case (e_FM_PORT_TYPE_RX_10G):
++        case (e_FM_PORT_TYPE_RX):
++            p_BmiHpnia = &p_FmPort->port.bmi_regs->rx.fmbm_rfpne;
++            break;
++        case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++            p_BmiHpnia = &p_FmPort->port.bmi_regs->oh.fmbm_ofpne;
++            break;
++        default:
++            RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
++                         ("available for Rx and offline parsing ports only"));
++    }
++
++    if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
++    {
++        DBG(TRACE, ("FM Port Try Lock - BUSY"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    /* if we want to change to direct scheme, we need to check that this scheme is valid */
++    if (p_FmPcdKgScheme->direct)
++    {
++        physicalSchemeId = FmPcdKgGetSchemeId(p_FmPcdKgScheme->h_DirectScheme);
++        /* check that this scheme is bound to this port */
++        if (!(p_FmPort->schemesPerPortVector
++                & (uint32_t)(1 << (31 - (uint32_t)physicalSchemeId))))
++        {
++            RELEASE_LOCK(p_FmPort->lock);
++            RETURN_ERROR(
++                    MAJOR, E_INVALID_STATE,
++                    ("called with a scheme that is not bound to this port"));
++        }
++
++        relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPort->h_FmPcd,
++                                                      physicalSchemeId);
++        if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES)
++        {
++            RELEASE_LOCK(p_FmPort->lock);
++            RETURN_ERROR(MAJOR, E_NOT_IN_RANGE,
++                         ("called with invalid Scheme "));
++        }
++
++        if (!FmPcdKgIsSchemeValidSw(p_FmPcdKgScheme->h_DirectScheme))
++        {
++            RELEASE_LOCK(p_FmPort->lock);
++            RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                         ("called with uninitialized Scheme "));
++        }
++
++        WRITE_UINT32(
++                *p_BmiHpnia,
++                NIA_ENG_KG | tmpReg | NIA_KG_DIRECT | (uint32_t)physicalSchemeId);
++    }
++    else
++        /* change to indirect scheme */
++        WRITE_UINT32(*p_BmiHpnia, NIA_ENG_KG | tmpReg);
++    RELEASE_LOCK(p_FmPort->lock);
++
++    return E_OK;
++}
++
++t_Error FM_PORT_PcdPlcrModifyInitialProfile(t_Handle h_FmPort,
++                                            t_Handle h_Profile)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    volatile uint32_t *p_BmiNia;
++    volatile uint32_t *p_BmiHpnia;
++    uint32_t tmpReg;
++    uint16_t absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile);
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_PLCR,
++                              E_INVALID_STATE);
++
++    /* check relevance of this routine  - only when policer is used
++     directly after BMI or Parser */
++    if ((p_FmPort->pcdEngines & FM_PCD_KG)
++            || (p_FmPort->pcdEngines & FM_PCD_CC))
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_STATE,
++                ("relevant only when PCD support mode is e_FM_PCD_SUPPORT_PLCR_ONLY or e_FM_PCD_SUPPORT_PRS_AND_PLCR"));
++
++    switch (p_FmPort->portType)
++    {
++        case (e_FM_PORT_TYPE_RX_10G):
++        case (e_FM_PORT_TYPE_RX):
++            p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne;
++            p_BmiHpnia = &p_FmPort->port.bmi_regs->rx.fmbm_rfpne;
++            tmpReg = GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK;
++            break;
++        case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++            p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne;
++            p_BmiHpnia = &p_FmPort->port.bmi_regs->oh.fmbm_ofpne;
++            tmpReg = 0;
++            break;
++        default:
++            RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
++                         ("available for Rx and offline parsing ports only"));
++    }
++
++    if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
++    {
++        DBG(TRACE, ("FM Port Try Lock - BUSY"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    if (!FmPcdPlcrIsProfileValid(p_FmPort->h_FmPcd, absoluteProfileId))
++    {
++        RELEASE_LOCK(p_FmPort->lock);
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Invalid profile"));
++    }
++
++    tmpReg |= (uint32_t)(NIA_ENG_PLCR | NIA_PLCR_ABSOLUTE | absoluteProfileId);
++
++    if (p_FmPort->pcdEngines & FM_PCD_PRS) /* e_FM_PCD_SUPPORT_PRS_AND_PLCR */
++    {
++        /* update BMI HPNIA */
++        WRITE_UINT32(*p_BmiHpnia, tmpReg);
++    }
++    else /* e_FM_PCD_SUPPORT_PLCR_ONLY */
++    {
++        /* rfne may contain FDCS bits, so first we read them. */
++        tmpReg |= (GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK);
++        /* update BMI NIA */
++        WRITE_UINT32(*p_BmiNia, tmpReg);
++    }RELEASE_LOCK(p_FmPort->lock);
++
++    return E_OK;
++}
++
++t_Error FM_PORT_PcdCcModifyTree(t_Handle h_FmPort, t_Handle h_CcTree)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_Error err = E_OK;
++    volatile uint32_t *p_BmiCcBase = NULL;
++    volatile uint32_t *p_BmiNia = NULL;
++    uint32_t ccTreePhysOffset;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(h_CcTree, E_INVALID_HANDLE);
++
++    if (p_FmPort->imEn)
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for non-independent mode ports only"));
++
++    /* get PCD registers pointers */
++    switch (p_FmPort->portType)
++    {
++        case (e_FM_PORT_TYPE_RX_10G):
++        case (e_FM_PORT_TYPE_RX):
++            p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne;
++            break;
++        case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++            p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne;
++            break;
++        default:
++            RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
++                         ("available for Rx and offline parsing ports only"));
++    }
++
++    /* check that current NIA is BMI to BMI */
++    if ((GET_UINT32(*p_BmiNia) & ~BMI_RFNE_FDCS_MASK)
++            != GET_NIA_BMI_AC_ENQ_FRAME(p_FmPort->h_FmPcd))
++        RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
++                     ("may be called only for ports in BMI-to-BMI state."));
++
++    if (p_FmPort->pcdEngines & FM_PCD_CC)
++    {
++        if (p_FmPort->h_IpReassemblyManip)
++        {
++            err = FmPcdCcTreeAddIPR(p_FmPort->h_FmPcd, h_CcTree, NULL,
++                                    p_FmPort->h_IpReassemblyManip, FALSE);
++            if (err != E_OK)
++            {
++                RETURN_ERROR(MAJOR, err, NO_MSG);
++            }
++        }
++        else
++            if (p_FmPort->h_CapwapReassemblyManip)
++            {
++                err = FmPcdCcTreeAddCPR(p_FmPort->h_FmPcd, h_CcTree, NULL,
++                                        p_FmPort->h_CapwapReassemblyManip,
++                                        FALSE);
++                if (err != E_OK)
++                {
++                    RETURN_ERROR(MAJOR, err, NO_MSG);
++                }
++            }
++        switch (p_FmPort->portType)
++        {
++            case (e_FM_PORT_TYPE_RX_10G):
++            case (e_FM_PORT_TYPE_RX):
++                p_BmiCcBase = &p_FmPort->port.bmi_regs->rx.fmbm_rccb;
++                break;
++            case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++                p_BmiCcBase = &p_FmPort->port.bmi_regs->oh.fmbm_occb;
++                break;
++            default:
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
++        }
++
++        if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
++        {
++            DBG(TRACE, ("FM Port Try Lock - BUSY"));
++            return ERROR_CODE(E_BUSY);
++        }
++        err = FmPcdCcBindTree(p_FmPort->h_FmPcd, NULL, h_CcTree,
++                              &ccTreePhysOffset, h_FmPort);
++        if (err)
++        {
++            RELEASE_LOCK(p_FmPort->lock);
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        }WRITE_UINT32(*p_BmiCcBase, ccTreePhysOffset);
++
++        p_FmPort->ccTreeId = h_CcTree;
++        RELEASE_LOCK(p_FmPort->lock);
++    }
++    else
++        RETURN_ERROR( MAJOR, E_INVALID_STATE,
++                     ("Coarse Classification not defined for this port."));
++
++    return E_OK;
++}
++
++t_Error FM_PORT_AttachPCD(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    if (p_FmPort->imEn)
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for non-independent mode ports only"));
++
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
++        RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
++                     ("available for Rx and offline parsing ports only"));
++
++    if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
++    {
++        DBG(TRACE, ("FM Port Try Lock - BUSY"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    if (p_FmPort->h_ReassemblyTree)
++        p_FmPort->pcdEngines |= FM_PCD_CC;
++
++    err = AttachPCD(h_FmPort);
++    RELEASE_LOCK(p_FmPort->lock);
++
++    return err;
++}
++
++t_Error FM_PORT_DetachPCD(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    if (p_FmPort->imEn)
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for non-independent mode ports only"));
++
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
++        RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
++                     ("available for Rx and offline parsing ports only"));
++
++    if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
++    {
++        DBG(TRACE, ("FM Port Try Lock - BUSY"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = DetachPCD(h_FmPort);
++    if (err != E_OK)
++    {
++        RELEASE_LOCK(p_FmPort->lock);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    if (p_FmPort->h_ReassemblyTree)
++        p_FmPort->pcdEngines &= ~FM_PCD_CC;
++    RELEASE_LOCK(p_FmPort->lock);
++
++    return E_OK;
++}
++
++t_Error FM_PORT_SetPCD(t_Handle h_FmPort, t_FmPortPcdParams *p_PcdParam)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_Error err = E_OK;
++    t_FmPortPcdParams modifiedPcdParams, *p_PcdParams;
++    t_FmPcdCcTreeParams *p_FmPcdCcTreeParams;
++    t_FmPortPcdCcParams fmPortPcdCcParams;
++    t_FmPortGetSetCcParams fmPortGetSetCcParams;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_PcdParam, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    if (p_FmPort->imEn)
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for non-independent mode ports only"));
++
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
++        RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
++                     ("available for Rx and offline parsing ports only"));
++
++    if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
++    {
++        DBG(TRACE, ("FM Port Try Lock - BUSY"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    p_FmPort->h_FmPcd = FmGetPcdHandle(p_FmPort->h_Fm);
++    ASSERT_COND(p_FmPort->h_FmPcd);
++
++    if (p_PcdParam->p_CcParams && !p_PcdParam->p_CcParams->h_CcTree)
++        RETURN_ERROR(MAJOR, E_INVALID_HANDLE,
++                     ("Tree handle must be given if CC is required"));
++
++    memcpy(&modifiedPcdParams, p_PcdParam, sizeof(t_FmPortPcdParams));
++    p_PcdParams = &modifiedPcdParams;
++    if ((p_PcdParams->h_IpReassemblyManip)
++#if (DPAA_VERSION >= 11)
++            || (p_PcdParams->h_CapwapReassemblyManip)
++#endif /* (DPAA_VERSION >= 11) */
++            )
++    {
++        if ((p_PcdParams->pcdSupport != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG)
++                && (p_PcdParams->pcdSupport
++                        != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC)
++                && (p_PcdParams->pcdSupport
++                        != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR)
++                && (p_PcdParams->pcdSupport
++                        != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR))
++        {
++            RELEASE_LOCK(p_FmPort->lock);
++            RETURN_ERROR( MAJOR, E_INVALID_STATE,
++                         ("pcdSupport must have KG for supporting Reassembly"));
++        }
++        p_FmPort->h_IpReassemblyManip = p_PcdParams->h_IpReassemblyManip;
++#if (DPAA_VERSION >= 11)
++        if ((p_PcdParams->h_IpReassemblyManip)
++                && (p_PcdParams->h_CapwapReassemblyManip))
++            RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                         ("Either IP-R or CAPWAP-R is allowed"));
++        if ((p_PcdParams->h_CapwapReassemblyManip)
++                && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
++            RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                         ("CAPWAP-R is allowed only on offline-port"));
++        if (p_PcdParams->h_CapwapReassemblyManip)
++            p_FmPort->h_CapwapReassemblyManip =
++                    p_PcdParams->h_CapwapReassemblyManip;
++#endif /* (DPAA_VERSION >= 11) */
++
++        if (!p_PcdParams->p_CcParams)
++        {
++            if (!((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PRS_AND_KG)
++                    || (p_PcdParams->pcdSupport
++                            == e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR)))
++            {
++                RELEASE_LOCK(p_FmPort->lock);
++                RETURN_ERROR(
++                        MAJOR,
++                        E_INVALID_STATE,
++                        ("PCD initialization structure is not consistent with pcdSupport"));
++            }
++
++            /* No user-tree, need to build internal tree */
++            p_FmPcdCcTreeParams = (t_FmPcdCcTreeParams*)XX_Malloc(
++                    sizeof(t_FmPcdCcTreeParams));
++            if (!p_FmPcdCcTreeParams)
++                RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_FmPcdCcTreeParams"));
++            memset(p_FmPcdCcTreeParams, 0, sizeof(t_FmPcdCcTreeParams));
++            p_FmPcdCcTreeParams->h_NetEnv = p_PcdParams->h_NetEnv;
++            p_FmPort->h_ReassemblyTree = FM_PCD_CcRootBuild(
++                    p_FmPort->h_FmPcd, p_FmPcdCcTreeParams);
++
++            if (!p_FmPort->h_ReassemblyTree)
++            {
++                RELEASE_LOCK(p_FmPort->lock);
++                XX_Free(p_FmPcdCcTreeParams);
++                RETURN_ERROR( MAJOR, E_INVALID_HANDLE,
++                             ("FM_PCD_CcBuildTree for Reassembly failed"));
++            }
++            if (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PRS_AND_KG)
++                p_PcdParams->pcdSupport =
++                        e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC;
++            else
++                p_PcdParams->pcdSupport =
++                        e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR;
++
++            memset(&fmPortPcdCcParams, 0, sizeof(t_FmPortPcdCcParams));
++            fmPortPcdCcParams.h_CcTree = p_FmPort->h_ReassemblyTree;
++            p_PcdParams->p_CcParams = &fmPortPcdCcParams;
++            XX_Free(p_FmPcdCcTreeParams);
++        }
++
++        if (p_FmPort->h_IpReassemblyManip)
++            err = FmPcdCcTreeAddIPR(p_FmPort->h_FmPcd,
++                                    p_PcdParams->p_CcParams->h_CcTree,
++                                    p_PcdParams->h_NetEnv,
++                                    p_FmPort->h_IpReassemblyManip, TRUE);
++#if (DPAA_VERSION >= 11)
++        else
++            if (p_FmPort->h_CapwapReassemblyManip)
++                err = FmPcdCcTreeAddCPR(p_FmPort->h_FmPcd,
++                                        p_PcdParams->p_CcParams->h_CcTree,
++                                        p_PcdParams->h_NetEnv,
++                                        p_FmPort->h_CapwapReassemblyManip,
++                                        TRUE);
++#endif /* (DPAA_VERSION >= 11) */
++
++        if (err != E_OK)
++        {
++            if (p_FmPort->h_ReassemblyTree)
++            {
++                FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
++                p_FmPort->h_ReassemblyTree = NULL;
++            }RELEASE_LOCK(p_FmPort->lock);
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        }
++    }
++
++    if (!FmPcdLockTryLockAll(p_FmPort->h_FmPcd))
++    {
++        if (p_FmPort->h_ReassemblyTree)
++        {
++            FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
++            p_FmPort->h_ReassemblyTree = NULL;
++        }RELEASE_LOCK(p_FmPort->lock);
++        DBG(TRACE, ("Try LockAll - BUSY"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = SetPcd(h_FmPort, p_PcdParams);
++    if (err)
++    {
++        if (p_FmPort->h_ReassemblyTree)
++        {
++            FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
++            p_FmPort->h_ReassemblyTree = NULL;
++        }
++        FmPcdLockUnlockAll(p_FmPort->h_FmPcd);
++        RELEASE_LOCK(p_FmPort->lock);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    if ((p_FmPort->pcdEngines & FM_PCD_PRS)
++            && (p_PcdParams->p_PrsParams->includeInPrsStatistics))
++    {
++        err = FmPcdPrsIncludePortInStatistics(p_FmPort->h_FmPcd,
++                                              p_FmPort->hardwarePortId, TRUE);
++        if (err)
++        {
++            DeletePcd(p_FmPort);
++            if (p_FmPort->h_ReassemblyTree)
++            {
++                FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
++                p_FmPort->h_ReassemblyTree = NULL;
++            }
++            FmPcdLockUnlockAll(p_FmPort->h_FmPcd);
++            RELEASE_LOCK(p_FmPort->lock);
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        }
++        p_FmPort->includeInPrsStatistics = TRUE;
++    }
++
++    FmPcdIncNetEnvOwners(p_FmPort->h_FmPcd, p_FmPort->netEnvId);
++
++    if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd))
++    {
++        memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams));
++
++        if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++        {
++#ifdef FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004
++            if ((p_FmPort->fmRevInfo.majorRev < 6) &&
++                    (p_FmPort->pcdEngines & FM_PCD_KG))
++            {
++                int i;
++                for (i = 0; i<p_PcdParams->p_KgParams->numOfSchemes; i++)
++                /* The following function must be locked */
++                FmPcdKgCcGetSetParams(p_FmPort->h_FmPcd,
++                        p_PcdParams->p_KgParams->h_Schemes[i],
++                        UPDATE_KG_NIA_CC_WA,
++                        0);
++            }
++#endif /* FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 */
++
++#if (DPAA_VERSION >= 11)
++            {
++                t_FmPcdCtrlParamsPage *p_ParamsPage;
++
++                FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE,
++                                 (void**)&p_ParamsPage);
++                ASSERT_COND(p_ParamsPage);
++                WRITE_UINT32(p_ParamsPage->postBmiFetchNia,
++                             p_FmPort->savedBmiNia);
++            }
++#endif /* (DPAA_VERSION >= 11) */
++
++            /* Set post-bmi-fetch nia */
++            p_FmPort->savedBmiNia &= BMI_RFNE_FDCS_MASK;
++            p_FmPort->savedBmiNia |= (NIA_FM_CTL_AC_POST_BMI_FETCH
++                    | NIA_ENG_FM_CTL);
++
++            /* Set pre-bmi-fetch nia */
++            fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNDN;
++#if (DPAA_VERSION >= 11)
++            fmPortGetSetCcParams.setCcParams.nia =
++                    (NIA_FM_CTL_AC_PRE_BMI_FETCH_FULL_FRAME | NIA_ENG_FM_CTL);
++#else
++            fmPortGetSetCcParams.setCcParams.nia = (NIA_FM_CTL_AC_PRE_BMI_FETCH_HEADER | NIA_ENG_FM_CTL);
++#endif /* (DPAA_VERSION >= 11) */
++            if ((err = FmPortGetSetCcParams(p_FmPort, &fmPortGetSetCcParams))
++                    != E_OK)
++            {
++                DeletePcd(p_FmPort);
++                if (p_FmPort->h_ReassemblyTree)
++                {
++                    FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
++                    p_FmPort->h_ReassemblyTree = NULL;
++                }
++                FmPcdLockUnlockAll(p_FmPort->h_FmPcd);
++                RELEASE_LOCK(p_FmPort->lock);
++                RETURN_ERROR(MAJOR, err, NO_MSG);
++            }
++        }
++
++        FmPcdLockUnlockAll(p_FmPort->h_FmPcd);
++
++        /* Set pop-to-next-step nia */
++#if (DPAA_VERSION == 10)
++        if (p_FmPort->fmRevInfo.majorRev < 6)
++        {
++            fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN;
++            fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL;
++        }
++        else
++        {
++#endif /* (DPAA_VERSION == 10) */
++        fmPortGetSetCcParams.getCcParams.type = GET_NIA_FPNE;
++#if (DPAA_VERSION == 10)
++    }
++#endif /* (DPAA_VERSION == 10) */
++        if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams))
++                != E_OK)
++        {
++            DeletePcd(p_FmPort);
++            if (p_FmPort->h_ReassemblyTree)
++            {
++                FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
++                p_FmPort->h_ReassemblyTree = NULL;
++            }RELEASE_LOCK(p_FmPort->lock);
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        }
++
++        /* Set post-bmi-prepare-to-enq nia */
++        fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_FENE;
++        fmPortGetSetCcParams.setCcParams.nia = (NIA_FM_CTL_AC_POST_BMI_ENQ
++                | NIA_ENG_FM_CTL);
++        if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams))
++                != E_OK)
++        {
++            DeletePcd(p_FmPort);
++            if (p_FmPort->h_ReassemblyTree)
++            {
++                FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
++                p_FmPort->h_ReassemblyTree = NULL;
++            }RELEASE_LOCK(p_FmPort->lock);
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        }
++
++        if ((p_FmPort->h_IpReassemblyManip)
++                || (p_FmPort->h_CapwapReassemblyManip))
++        {
++#if (DPAA_VERSION == 10)
++            if (p_FmPort->fmRevInfo.majorRev < 6)
++            {
++                /* Overwrite post-bmi-prepare-to-enq nia */
++                fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_FENE;
++                fmPortGetSetCcParams.setCcParams.nia = (NIA_FM_CTL_AC_POST_BMI_ENQ_ORR | NIA_ENG_FM_CTL | NIA_ORDER_RESTOR);
++                fmPortGetSetCcParams.setCcParams.overwrite = TRUE;
++            }
++            else
++            {
++#endif /* (DPAA_VERSION == 10) */
++            /* Set the ORR bit (for order-restoration) */
++            fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_FPNE;
++            fmPortGetSetCcParams.setCcParams.nia =
++                    fmPortGetSetCcParams.getCcParams.nia | NIA_ORDER_RESTOR;
++#if (DPAA_VERSION == 10)
++        }
++#endif /* (DPAA_VERSION == 10) */
++            if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams))
++                    != E_OK)
++            {
++                DeletePcd(p_FmPort);
++                if (p_FmPort->h_ReassemblyTree)
++                {
++                    FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
++                    p_FmPort->h_ReassemblyTree = NULL;
++                }RELEASE_LOCK(p_FmPort->lock);
++                RETURN_ERROR(MAJOR, err, NO_MSG);
++            }
++        }
++    }
++    else
++        FmPcdLockUnlockAll(p_FmPort->h_FmPcd);
++
++#if (DPAA_VERSION >= 11)
++    {
++        t_FmPcdCtrlParamsPage *p_ParamsPage;
++
++        memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams));
++
++        fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_CMNE;
++        if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd))
++            fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP
++                    | NIA_ENG_FM_CTL;
++        else
++            fmPortGetSetCcParams.setCcParams.nia =
++                    NIA_FM_CTL_AC_NO_IPACC_POP_TO_N_STEP | NIA_ENG_FM_CTL;
++        if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams))
++                != E_OK)
++        {
++            DeletePcd(p_FmPort);
++            if (p_FmPort->h_ReassemblyTree)
++            {
++                FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
++                p_FmPort->h_ReassemblyTree = NULL;
++            }RELEASE_LOCK(p_FmPort->lock);
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        }
++
++        FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE,
++                         (void**)&p_ParamsPage);
++        ASSERT_COND(p_ParamsPage);
++
++        if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd))
++            WRITE_UINT32(
++                    p_ParamsPage->misc,
++                    GET_UINT32(p_ParamsPage->misc) | FM_CTL_PARAMS_PAGE_OFFLOAD_SUPPORT_EN);
++
++        if ((p_FmPort->h_IpReassemblyManip)
++                || (p_FmPort->h_CapwapReassemblyManip))
++        {
++            if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++                WRITE_UINT32(
++                        p_ParamsPage->discardMask,
++                        GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm));
++            else
++                WRITE_UINT32(
++                        p_ParamsPage->discardMask,
++                        GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm));
++        }
++#ifdef FM_ERROR_VSP_NO_MATCH_SW006
++        if (p_FmPort->vspe)
++            WRITE_UINT32(
++                    p_ParamsPage->misc,
++                    GET_UINT32(p_ParamsPage->misc) | (p_FmPort->dfltRelativeId & FM_CTL_PARAMS_PAGE_ERROR_VSP_MASK));
++#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */
++    }
++#endif /* (DPAA_VERSION >= 11) */
++
++    err = AttachPCD(h_FmPort);
++    if (err)
++    {
++        DeletePcd(p_FmPort);
++        if (p_FmPort->h_ReassemblyTree)
++        {
++            FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
++            p_FmPort->h_ReassemblyTree = NULL;
++        }RELEASE_LOCK(p_FmPort->lock);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    RELEASE_LOCK(p_FmPort->lock);
++
++    return err;
++}
++
++t_Error FM_PORT_DeletePCD(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++
++    if (p_FmPort->imEn)
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
++                     ("available for non-independant mode ports only"));
++
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
++        RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
++                     ("available for Rx and offline parsing ports only"));
++
++    if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
++    {
++        DBG(TRACE, ("FM Port Try Lock - BUSY"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = DetachPCD(h_FmPort);
++    if (err)
++    {
++        RELEASE_LOCK(p_FmPort->lock);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    FmPcdDecNetEnvOwners(p_FmPort->h_FmPcd, p_FmPort->netEnvId);
++
++    /* we do it anyway, instead of checking if included */
++    if ((p_FmPort->pcdEngines & FM_PCD_PRS) && p_FmPort->includeInPrsStatistics)
++    {
++        FmPcdPrsIncludePortInStatistics(p_FmPort->h_FmPcd,
++                                        p_FmPort->hardwarePortId, FALSE);
++        p_FmPort->includeInPrsStatistics = FALSE;
++    }
++
++    if (!FmPcdLockTryLockAll(p_FmPort->h_FmPcd))
++    {
++        RELEASE_LOCK(p_FmPort->lock);
++        DBG(TRACE, ("Try LockAll - BUSY"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = DeletePcd(h_FmPort);
++    FmPcdLockUnlockAll(p_FmPort->h_FmPcd);
++    if (err)
++    {
++        RELEASE_LOCK(p_FmPort->lock);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    if (p_FmPort->h_ReassemblyTree)
++    {
++        err = FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
++        if (err)
++        {
++            RELEASE_LOCK(p_FmPort->lock);
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        }
++        p_FmPort->h_ReassemblyTree = NULL;
++    }RELEASE_LOCK(p_FmPort->lock);
++
++    return err;
++}
++
++t_Error FM_PORT_PcdKgBindSchemes(t_Handle h_FmPort,
++                                 t_FmPcdPortSchemesParams *p_PortScheme)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_FmPcdKgInterModuleBindPortToSchemes schemeBind;
++    t_Error err = E_OK;
++    uint32_t tmpScmVec = 0;
++    int i;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG,
++                              E_INVALID_STATE);
++
++    schemeBind.netEnvId = p_FmPort->netEnvId;
++    schemeBind.hardwarePortId = p_FmPort->hardwarePortId;
++    schemeBind.numOfSchemes = p_PortScheme->numOfSchemes;
++    schemeBind.useClsPlan = p_FmPort->useClsPlan;
++    for (i = 0; i < schemeBind.numOfSchemes; i++)
++    {
++        schemeBind.schemesIds[i] = FmPcdKgGetSchemeId(
++                p_PortScheme->h_Schemes[i]);
++        /* build vector */
++        tmpScmVec |= 1 << (31 - (uint32_t)schemeBind.schemesIds[i]);
++    }
++
++    if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
++    {
++        DBG(TRACE, ("FM Port Try Lock - BUSY"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = FmPcdKgBindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind);
++    if (err == E_OK)
++        p_FmPort->schemesPerPortVector |= tmpScmVec;
++
++#ifdef FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004
++    if ((FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)) &&
++            (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) &&
++            (p_FmPort->fmRevInfo.majorRev < 6))
++    {
++        for (i=0; i<p_PortScheme->numOfSchemes; i++)
++        FmPcdKgCcGetSetParams(p_FmPort->h_FmPcd, p_PortScheme->h_Schemes[i], UPDATE_KG_NIA_CC_WA, 0);
++    }
++#endif /* FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 */
++
++    RELEASE_LOCK(p_FmPort->lock);
++
++    return err;
++}
++
++t_Error FM_PORT_PcdKgUnbindSchemes(t_Handle h_FmPort,
++                                   t_FmPcdPortSchemesParams *p_PortScheme)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    t_FmPcdKgInterModuleBindPortToSchemes schemeBind;
++    t_Error err = E_OK;
++    uint32_t tmpScmVec = 0;
++    int i;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG,
++                              E_INVALID_STATE);
++
++    schemeBind.netEnvId = p_FmPort->netEnvId;
++    schemeBind.hardwarePortId = p_FmPort->hardwarePortId;
++    schemeBind.numOfSchemes = p_PortScheme->numOfSchemes;
++    for (i = 0; i < schemeBind.numOfSchemes; i++)
++    {
++        schemeBind.schemesIds[i] = FmPcdKgGetSchemeId(
++                p_PortScheme->h_Schemes[i]);
++        /* build vector */
++        tmpScmVec |= 1 << (31 - (uint32_t)schemeBind.schemesIds[i]);
++    }
++
++    if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
++    {
++        DBG(TRACE, ("FM Port Try Lock - BUSY"));
++        return ERROR_CODE(E_BUSY);
++    }
++
++    err = FmPcdKgUnbindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind);
++    if (err == E_OK)
++        p_FmPort->schemesPerPortVector &= ~tmpScmVec;
++    RELEASE_LOCK(p_FmPort->lock);
++
++    return err;
++}
++
++t_Error FM_PORT_AddCongestionGrps(t_Handle h_FmPort,
++                                  t_FmPortCongestionGrps *p_CongestionGrps)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    uint8_t priorityTmpArray[FM_PORT_NUM_OF_CONGESTION_GRPS];
++    uint8_t mod, index;
++    uint32_t i, grpsMap[FMAN_PORT_CG_MAP_NUM];
++    int err;
++#if (DPAA_VERSION >= 11)
++    int j;
++#endif /* (DPAA_VERSION >= 11) */
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++
++    /* un-necessary check of the indexes; probably will be needed in the future when there
++     will be more CGs available ....
++     for (i=0; i<p_CongestionGrps->numOfCongestionGrpsToConsider; i++)
++     if (p_CongestionGrps->congestionGrpsToConsider[i] >= FM_PORT_NUM_OF_CONGESTION_GRPS)
++     RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("CG id!"));
++     */
++
++#ifdef FM_NO_OP_OBSERVED_CGS
++    if ((p_FmPort->fmRevInfo.majorRev != 4) &&
++            (p_FmPort->fmRevInfo.majorRev < 6))
++    {
++        if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) &&
++                (p_FmPort->portType != e_FM_PORT_TYPE_RX))
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Available for Rx ports only"));
++    }
++    else
++#endif /* FM_NO_OP_OBSERVED_CGS */
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
++            && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
++                     ("Available for Rx & OP ports only"));
++
++    /* Prepare groups map array */
++    memset(grpsMap, 0, FMAN_PORT_CG_MAP_NUM * sizeof(uint32_t));
++    for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++)
++    {
++        index = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] / 32);
++        mod = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] % 32);
++        if (p_FmPort->fmRevInfo.majorRev != 4)
++            grpsMap[7 - index] |= (uint32_t)(1 << mod);
++        else
++            grpsMap[0] |= (uint32_t)(1 << mod);
++    }
++
++    memset(&priorityTmpArray, 0,
++           FM_PORT_NUM_OF_CONGESTION_GRPS * sizeof(uint8_t));
++
++    for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++)
++    {
++#if (DPAA_VERSION >= 11)
++        for (j = 0; j < FM_MAX_NUM_OF_PFC_PRIORITIES; j++)
++            if (p_CongestionGrps->pfcPrioritiesEn[i][j])
++                priorityTmpArray[p_CongestionGrps->congestionGrpsToConsider[i]] |=
++                        (0x01 << (FM_MAX_NUM_OF_PFC_PRIORITIES - j - 1));
++#endif /* (DPAA_VERSION >= 11) */
++    }
++
++#if (DPAA_VERSION >= 11)
++    for (i = 0; i < FM_PORT_NUM_OF_CONGESTION_GRPS; i++)
++    {
++        err = FmSetCongestionGroupPFCpriority(p_FmPort->h_Fm, i,
++                                              priorityTmpArray[i]);
++        if (err)
++            return err;
++    }
++#endif /* (DPAA_VERSION >= 11) */
++
++    err = fman_port_add_congestion_grps(&p_FmPort->port, grpsMap);
++    if (err != 0)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_add_congestion_grps"));
++
++    return E_OK;
++}
++
++t_Error FM_PORT_RemoveCongestionGrps(t_Handle h_FmPort,
++                                     t_FmPortCongestionGrps *p_CongestionGrps)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++    uint8_t mod, index;
++    uint32_t i, grpsMap[FMAN_PORT_CG_MAP_NUM];
++    int err;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++
++    {
++#ifdef FM_NO_OP_OBSERVED_CGS
++        t_FmRevisionInfo revInfo;
++
++        FM_GetRevision(p_FmPort->h_Fm, &revInfo);
++        if (revInfo.majorRev != 4)
++        {
++            if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) &&
++                    (p_FmPort->portType != e_FM_PORT_TYPE_RX))
++            RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Available for Rx ports only"));
++        }
++        else
++#endif /* FM_NO_OP_OBSERVED_CGS */
++        if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
++                && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
++                && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
++            RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
++                         ("Available for Rx & OP ports only"));
++    }
++
++    /* Prepare groups map array */
++    memset(grpsMap, 0, FMAN_PORT_CG_MAP_NUM * sizeof(uint32_t));
++    for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++)
++    {
++        index = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] / 32);
++        mod = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] % 32);
++        if (p_FmPort->fmRevInfo.majorRev != 4)
++            grpsMap[7 - index] |= (uint32_t)(1 << mod);
++        else
++            grpsMap[0] |= (uint32_t)(1 << mod);
++    }
++
++#if (DPAA_VERSION >= 11)
++    for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++)
++    {
++        t_Error err = FmSetCongestionGroupPFCpriority(
++                p_FmPort->h_Fm, p_CongestionGrps->congestionGrpsToConsider[i],
++                0);
++        if (err)
++            return err;
++    }
++#endif /* (DPAA_VERSION >= 11) */
++
++    err = fman_port_remove_congestion_grps(&p_FmPort->port, grpsMap);
++    if (err != 0)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("fman_port_remove_congestion_grps"));
++    return E_OK;
++}
++
++#if (DPAA_VERSION >= 11)
++t_Error FM_PORT_GetIPv4OptionsCount(t_Handle h_FmPort,
++                                    uint32_t *p_Ipv4OptionsCount)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(
++            (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING),
++            E_INVALID_VALUE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_ParamsPage, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_Ipv4OptionsCount, E_NULL_POINTER);
++
++    *p_Ipv4OptionsCount = GET_UINT32(p_FmPort->p_ParamsPage->ipfOptionsCounter);
++
++    return E_OK;
++}
++#endif /* (DPAA_VERSION >= 11) */
++
++t_Error FM_PORT_ConfigDsarSupport(t_Handle h_FmPortRx,
++                                  t_FmPortDsarTablesSizes *params)
++{
++    t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx;
++    p_FmPort->deepSleepVars.autoResMaxSizes = XX_Malloc(
++            sizeof(struct t_FmPortDsarTablesSizes));
++    memcpy(p_FmPort->deepSleepVars.autoResMaxSizes, params,
++           sizeof(struct t_FmPortDsarTablesSizes));
++    return E_OK;
++}
++
++static t_Error FmPortConfigAutoResForDeepSleepSupport1(t_FmPort *p_FmPort)
++{
++    uint32_t *param_page;
++    t_FmPortDsarTablesSizes *params = p_FmPort->deepSleepVars.autoResMaxSizes;
++    t_ArCommonDesc *ArCommonDescPtr;
++    uint32_t size = sizeof(t_ArCommonDesc);
++    // ARP
++    // should put here if (params->max_num_of_arp_entries)?
++    size = ROUND_UP(size,4);
++    size += sizeof(t_DsarArpDescriptor);
++    size += sizeof(t_DsarArpBindingEntry) * params->maxNumOfArpEntries;
++    size += sizeof(t_DsarArpStatistics);
++    //ICMPV4
++    size = ROUND_UP(size,4);
++    size += sizeof(t_DsarIcmpV4Descriptor);
++    size += sizeof(t_DsarIcmpV4BindingEntry) * params->maxNumOfEchoIpv4Entries;
++    size += sizeof(t_DsarIcmpV4Statistics);
++    //ICMPV6
++    size = ROUND_UP(size,4);
++    size += sizeof(t_DsarIcmpV6Descriptor);
++    size += sizeof(t_DsarIcmpV6BindingEntry) * params->maxNumOfEchoIpv6Entries;
++    size += sizeof(t_DsarIcmpV6Statistics);
++    //ND
++    size = ROUND_UP(size,4);
++    size += sizeof(t_DsarNdDescriptor);
++    size += sizeof(t_DsarIcmpV6BindingEntry) * params->maxNumOfNdpEntries;
++    size += sizeof(t_DsarIcmpV6Statistics);
++    //SNMP
++    size = ROUND_UP(size,4);
++    size += sizeof(t_DsarSnmpDescriptor);
++    size += sizeof(t_DsarSnmpIpv4AddrTblEntry)
++            * params->maxNumOfSnmpIPV4Entries;
++    size += sizeof(t_DsarSnmpIpv6AddrTblEntry)
++            * params->maxNumOfSnmpIPV6Entries;
++    size += sizeof(t_OidsTblEntry) * params->maxNumOfSnmpOidEntries;
++    size += params->maxNumOfSnmpOidChar;
++    size += sizeof(t_DsarIcmpV6Statistics);
++    //filters
++    size = ROUND_UP(size,4);
++    size += params->maxNumOfIpProtFiltering;
++    size = ROUND_UP(size,4);
++    size += params->maxNumOfUdpPortFiltering * sizeof(t_PortTblEntry);
++    size = ROUND_UP(size,4);
++    size += params->maxNumOfTcpPortFiltering * sizeof(t_PortTblEntry);
++
++    // add here for more protocols
++
++    // statistics
++    size = ROUND_UP(size,4);
++    size += sizeof(t_ArStatistics);
++
++    ArCommonDescPtr = FM_MURAM_AllocMem(p_FmPort->h_FmMuram, size, 0x10);
++
++    param_page =
++            XX_PhysToVirt(
++                    p_FmPort->fmMuramPhysBaseAddr
++                            + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr));
++    WRITE_UINT32(
++            *param_page,
++            (uint32_t)(XX_VirtToPhys(ArCommonDescPtr) - p_FmPort->fmMuramPhysBaseAddr));
++    return E_OK;
++}
++
++t_FmPortDsarTablesSizes* FM_PORT_GetDsarTablesMaxSizes(t_Handle h_FmPortRx)
++{
++    t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx;
++    return p_FmPort->deepSleepVars.autoResMaxSizes;
++}
++
++struct arOffsets
++{
++    uint32_t arp;
++    uint32_t nd;
++    uint32_t icmpv4;
++    uint32_t icmpv6;
++    uint32_t snmp;
++    uint32_t stats;
++    uint32_t filtIp;
++    uint32_t filtUdp;
++    uint32_t filtTcp;
++};
++
++static uint32_t AR_ComputeOffsets(struct arOffsets* of,
++                                  struct t_FmPortDsarParams *params,
++                                  t_FmPort *p_FmPort)
++{
++    uint32_t size = sizeof(t_ArCommonDesc);
++    // ARP
++    if (params->p_AutoResArpInfo)
++    {
++        size = ROUND_UP(size,4);
++        of->arp = size;
++        size += sizeof(t_DsarArpDescriptor);
++        size += sizeof(t_DsarArpBindingEntry)
++                * params->p_AutoResArpInfo->tableSize;
++        size += sizeof(t_DsarArpStatistics);
++    }
++    // ICMPV4
++    if (params->p_AutoResEchoIpv4Info)
++    {
++        size = ROUND_UP(size,4);
++        of->icmpv4 = size;
++        size += sizeof(t_DsarIcmpV4Descriptor);
++        size += sizeof(t_DsarIcmpV4BindingEntry)
++                * params->p_AutoResEchoIpv4Info->tableSize;
++        size += sizeof(t_DsarIcmpV4Statistics);
++    }
++    // ICMPV6
++    if (params->p_AutoResEchoIpv6Info)
++    {
++        size = ROUND_UP(size,4);
++        of->icmpv6 = size;
++        size += sizeof(t_DsarIcmpV6Descriptor);
++        size += sizeof(t_DsarIcmpV6BindingEntry)
++                * params->p_AutoResEchoIpv6Info->tableSize;
++        size += sizeof(t_DsarIcmpV6Statistics);
++    }
++    // ND
++    if (params->p_AutoResNdpInfo)
++    {
++        size = ROUND_UP(size,4);
++        of->nd = size;
++        size += sizeof(t_DsarNdDescriptor);
++        size += sizeof(t_DsarIcmpV6BindingEntry)
++                * (params->p_AutoResNdpInfo->tableSizeAssigned
++                        + params->p_AutoResNdpInfo->tableSizeTmp);
++        size += sizeof(t_DsarIcmpV6Statistics);
++    }
++    // SNMP
++    if (params->p_AutoResSnmpInfo)
++    {
++        size = ROUND_UP(size,4);
++        of->snmp = size;
++        size += sizeof(t_DsarSnmpDescriptor);
++        size += sizeof(t_DsarSnmpIpv4AddrTblEntry)
++                * params->p_AutoResSnmpInfo->numOfIpv4Addresses;
++        size += sizeof(t_DsarSnmpIpv6AddrTblEntry)
++                * params->p_AutoResSnmpInfo->numOfIpv6Addresses;
++        size += sizeof(t_OidsTblEntry) * params->p_AutoResSnmpInfo->oidsTblSize;
++        size += p_FmPort->deepSleepVars.autoResMaxSizes->maxNumOfSnmpOidChar;
++        size += sizeof(t_DsarIcmpV6Statistics);
++    }
++    //filters
++    size = ROUND_UP(size,4);
++    if (params->p_AutoResFilteringInfo)
++    {
++        of->filtIp = size;
++        size += params->p_AutoResFilteringInfo->ipProtTableSize;
++        size = ROUND_UP(size,4);
++        of->filtUdp = size;
++        size += params->p_AutoResFilteringInfo->udpPortsTableSize
++                * sizeof(t_PortTblEntry);
++        size = ROUND_UP(size,4);
++        of->filtTcp = size;
++        size += params->p_AutoResFilteringInfo->tcpPortsTableSize
++                * sizeof(t_PortTblEntry);
++    }
++    // add here for more protocols
++    // statistics
++    size = ROUND_UP(size,4);
++    of->stats = size;
++    size += sizeof(t_ArStatistics);
++    return size;
++}
++
++uint32_t* ARDesc;
++void PrsEnable(t_Handle p_FmPcd);
++void PrsDisable(t_Handle p_FmPcd);
++int PrsIsEnabled(t_Handle p_FmPcd);
++t_Handle FM_PCD_GetHcPort(t_Handle h_FmPcd);
++
++static t_Error DsarCheckParams(t_FmPortDsarParams *params,
++                               t_FmPortDsarTablesSizes *sizes)
++{
++    bool macInit = FALSE;
++    uint8_t mac[6];
++    int i = 0;
++
++    // check table sizes
++    if (params->p_AutoResArpInfo
++            && sizes->maxNumOfArpEntries < params->p_AutoResArpInfo->tableSize)
++        RETURN_ERROR(
++                MAJOR, E_INVALID_VALUE,
++                ("DSAR: Arp table size exceeds the configured maximum size."));
++    if (params->p_AutoResEchoIpv4Info
++            && sizes->maxNumOfEchoIpv4Entries
++                    < params->p_AutoResEchoIpv4Info->tableSize)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("DSAR: EchoIpv4 table size exceeds the configured maximum size."));
++    if (params->p_AutoResNdpInfo
++            && sizes->maxNumOfNdpEntries
++                    < params->p_AutoResNdpInfo->tableSizeAssigned
++                            + params->p_AutoResNdpInfo->tableSizeTmp)
++        RETURN_ERROR(
++                MAJOR, E_INVALID_VALUE,
++                ("DSAR: NDP table size exceeds the configured maximum size."));
++    if (params->p_AutoResEchoIpv6Info
++            && sizes->maxNumOfEchoIpv6Entries
++                    < params->p_AutoResEchoIpv6Info->tableSize)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("DSAR: EchoIpv6 table size exceeds the configured maximum size."));
++    if (params->p_AutoResSnmpInfo
++            && sizes->maxNumOfSnmpOidEntries
++                    < params->p_AutoResSnmpInfo->oidsTblSize)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("DSAR: Snmp Oid table size exceeds the configured maximum size."));
++    if (params->p_AutoResSnmpInfo
++            && sizes->maxNumOfSnmpIPV4Entries
++                    < params->p_AutoResSnmpInfo->numOfIpv4Addresses)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("DSAR: Snmp ipv4 table size exceeds the configured maximum size."));
++    if (params->p_AutoResSnmpInfo
++            && sizes->maxNumOfSnmpIPV6Entries
++                    < params->p_AutoResSnmpInfo->numOfIpv6Addresses)
++        RETURN_ERROR(
++                MAJOR,
++                E_INVALID_VALUE,
++                ("DSAR: Snmp ipv6 table size exceeds the configured maximum size."));
++    if (params->p_AutoResFilteringInfo)
++    {
++        if (sizes->maxNumOfIpProtFiltering
++                < params->p_AutoResFilteringInfo->ipProtTableSize)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("DSAR: ip filter table size exceeds the configured maximum size."));
++        if (sizes->maxNumOfTcpPortFiltering
++                < params->p_AutoResFilteringInfo->udpPortsTableSize)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("DSAR: udp filter table size exceeds the configured maximum size."));
++        if (sizes->maxNumOfUdpPortFiltering
++                < params->p_AutoResFilteringInfo->tcpPortsTableSize)
++            RETURN_ERROR(
++                    MAJOR,
++                    E_INVALID_VALUE,
++                    ("DSAR: tcp filter table size exceeds the configured maximum size."));
++    }
++    /* check only 1 MAC address is configured (this is what ucode currently supports) */
++    if (params->p_AutoResArpInfo && params->p_AutoResArpInfo->tableSize)
++    {
++        memcpy(mac, params->p_AutoResArpInfo->p_AutoResTable[0].mac, 6);
++        i = 1;
++        macInit = TRUE;
++
++        for (; i < params->p_AutoResArpInfo->tableSize; i++)
++            if (memcmp(mac, params->p_AutoResArpInfo->p_AutoResTable[i].mac, 6))
++                RETURN_ERROR(
++                        MAJOR, E_INVALID_VALUE,
++                        ("DSAR: Only 1 mac address is currently supported."));
++    }
++    if (params->p_AutoResEchoIpv4Info
++            && params->p_AutoResEchoIpv4Info->tableSize)
++    {
++        i = 0;
++        if (!macInit)
++        {
++            memcpy(mac, params->p_AutoResEchoIpv4Info->p_AutoResTable[0].mac,
++                   6);
++            i = 1;
++            macInit = TRUE;
++        }
++        for (; i < params->p_AutoResEchoIpv4Info->tableSize; i++)
++            if (memcmp(mac,
++                       params->p_AutoResEchoIpv4Info->p_AutoResTable[i].mac, 6))
++                RETURN_ERROR(
++                        MAJOR, E_INVALID_VALUE,
++                        ("DSAR: Only 1 mac address is currently supported."));
++    }
++    if (params->p_AutoResEchoIpv6Info
++            && params->p_AutoResEchoIpv6Info->tableSize)
++    {
++        i = 0;
++        if (!macInit)
++        {
++            memcpy(mac, params->p_AutoResEchoIpv6Info->p_AutoResTable[0].mac,
++                   6);
++            i = 1;
++            macInit = TRUE;
++        }
++        for (; i < params->p_AutoResEchoIpv6Info->tableSize; i++)
++            if (memcmp(mac,
++                       params->p_AutoResEchoIpv6Info->p_AutoResTable[i].mac, 6))
++                RETURN_ERROR(
++                        MAJOR, E_INVALID_VALUE,
++                        ("DSAR: Only 1 mac address is currently supported."));
++    }
++    if (params->p_AutoResNdpInfo && params->p_AutoResNdpInfo->tableSizeAssigned)
++    {
++        i = 0;
++        if (!macInit)
++        {
++            memcpy(mac, params->p_AutoResNdpInfo->p_AutoResTableAssigned[0].mac,
++                   6);
++            i = 1;
++            macInit = TRUE;
++        }
++        for (; i < params->p_AutoResNdpInfo->tableSizeAssigned; i++)
++            if (memcmp(mac,
++                       params->p_AutoResNdpInfo->p_AutoResTableAssigned[i].mac,
++                       6))
++                RETURN_ERROR(
++                        MAJOR, E_INVALID_VALUE,
++                        ("DSAR: Only 1 mac address is currently supported."));
++    }
++    if (params->p_AutoResNdpInfo && params->p_AutoResNdpInfo->tableSizeTmp)
++    {
++        i = 0;
++        if (!macInit)
++        {
++            memcpy(mac, params->p_AutoResNdpInfo->p_AutoResTableTmp[0].mac, 6);
++            i = 1;
++        }
++        for (; i < params->p_AutoResNdpInfo->tableSizeTmp; i++)
++            if (memcmp(mac, params->p_AutoResNdpInfo->p_AutoResTableTmp[i].mac,
++                       6))
++                RETURN_ERROR(
++                        MAJOR, E_INVALID_VALUE,
++                        ("DSAR: Only 1 mac address is currently supported."));
++    }
++    return E_OK;
++}
++
++static int GetBERLen(uint8_t* buf)
++{
++    if (*buf & 0x80)
++    {
++        if ((*buf & 0x7F) == 1)
++            return buf[1];
++        else
++            return *(uint16_t*)&buf[1]; // assuming max len is 2
++    }
++    else
++        return buf[0];
++}
++#define TOTAL_BER_LEN(len) (len < 128) ? len + 2 : len + 3
++
++#define SCFG_FMCLKDPSLPCR_ADDR 0xFFE0FC00C
++#define SCFG_FMCLKDPSLPCR_DS_VAL 0x08402000
++#define SCFG_FMCLKDPSLPCR_NORMAL_VAL 0x00402000
++static int fm_soc_suspend(void)
++{
++      uint32_t *fmclk, tmp32;
++      fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4);
++      tmp32 = GET_UINT32(*fmclk);
++      WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_DS_VAL);
++      tmp32 = GET_UINT32(*fmclk);
++      iounmap(fmclk);
++      return 0;
++}
++
++void fm_clk_down(void)
++{
++      uint32_t *fmclk, tmp32;
++      fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4);
++      tmp32 = GET_UINT32(*fmclk);
++      WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_DS_VAL | 0x40000000);
++      tmp32 = GET_UINT32(*fmclk);
++      iounmap(fmclk);
++}
++
++t_Error FM_PORT_EnterDsar(t_Handle h_FmPortRx, t_FmPortDsarParams *params)
++{
++    int i, j;
++    t_Error err;
++    uint32_t nia;
++    t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx;
++    t_FmPort *p_FmPortTx = (t_FmPort *)params->h_FmPortTx;
++    t_DsarArpDescriptor *ArpDescriptor;
++    t_DsarIcmpV4Descriptor* ICMPV4Descriptor;
++    t_DsarIcmpV6Descriptor* ICMPV6Descriptor;
++    t_DsarNdDescriptor* NDDescriptor;
++
++    uint64_t fmMuramVirtBaseAddr = (uint64_t)PTR_TO_UINT(XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr));
++    uint32_t *param_page = XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr));
++    t_ArCommonDesc *ArCommonDescPtr = (t_ArCommonDesc*)(XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(*param_page)));
++    struct arOffsets* of;
++    uint8_t tmp = 0;
++    t_FmGetSetParams fmGetSetParams;
++    memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
++    fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP;
++    fmGetSetParams.setParams.sleep = 1;    
++
++    err = DsarCheckParams(params, p_FmPort->deepSleepVars.autoResMaxSizes);
++    if (err != E_OK)
++        return err;
++
++    p_FmPort->deepSleepVars.autoResOffsets = XX_Malloc(sizeof(struct arOffsets));
++    of = (struct arOffsets *)p_FmPort->deepSleepVars.autoResOffsets;
++    IOMemSet32(ArCommonDescPtr, 0, AR_ComputeOffsets(of, params, p_FmPort));
++
++    // common
++    WRITE_UINT8(ArCommonDescPtr->arTxPort, p_FmPortTx->hardwarePortId);
++    nia = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne); // bmi nia
++    if ((nia & 0x007C0000) == 0x00440000) // bmi nia is parser
++        WRITE_UINT32(ArCommonDescPtr->activeHPNIA, GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne));
++    else
++        WRITE_UINT32(ArCommonDescPtr->activeHPNIA, nia);
++    WRITE_UINT16(ArCommonDescPtr->snmpPort, 161);
++
++    // ARP
++    if (params->p_AutoResArpInfo)
++    {
++        t_DsarArpBindingEntry* arp_bindings;
++        ArpDescriptor = (t_DsarArpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->arp);
++        WRITE_UINT32(ArCommonDescPtr->p_ArpDescriptor, PTR_TO_UINT(ArpDescriptor) - fmMuramVirtBaseAddr);
++        arp_bindings = (t_DsarArpBindingEntry*)(PTR_TO_UINT(ArpDescriptor) + sizeof(t_DsarArpDescriptor));
++      if (params->p_AutoResArpInfo->enableConflictDetection)
++              WRITE_UINT16(ArpDescriptor->control, 1);
++      else
++        WRITE_UINT16(ArpDescriptor->control, 0);
++        if (params->p_AutoResArpInfo->tableSize)
++        {
++            t_FmPortDsarArpEntry* arp_entry = params->p_AutoResArpInfo->p_AutoResTable;
++            WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&arp_entry[0].mac[0]);
++            WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&arp_entry[0].mac[2]);
++            WRITE_UINT16(ArpDescriptor->numOfBindings, params->p_AutoResArpInfo->tableSize);
++
++            for (i = 0; i < params->p_AutoResArpInfo->tableSize; i++)
++            {
++                WRITE_UINT32(arp_bindings[i].ipv4Addr, arp_entry[i].ipAddress);
++                if (arp_entry[i].isVlan)
++                    WRITE_UINT16(arp_bindings[i].vlanId, arp_entry[i].vid & 0xFFF);
++            }
++            WRITE_UINT32(ArpDescriptor->p_Bindings, PTR_TO_UINT(arp_bindings) - fmMuramVirtBaseAddr);
++        }
++        WRITE_UINT32(ArpDescriptor->p_Statistics, PTR_TO_UINT(arp_bindings) +
++            sizeof(t_DsarArpBindingEntry) * params->p_AutoResArpInfo->tableSize - fmMuramVirtBaseAddr);
++    }
++
++    // ICMPV4
++    if (params->p_AutoResEchoIpv4Info)
++    {
++        t_DsarIcmpV4BindingEntry* icmpv4_bindings;
++        ICMPV4Descriptor = (t_DsarIcmpV4Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv4);
++        WRITE_UINT32(ArCommonDescPtr->p_IcmpV4Descriptor, PTR_TO_UINT(ICMPV4Descriptor) - fmMuramVirtBaseAddr);
++        icmpv4_bindings = (t_DsarIcmpV4BindingEntry*)(PTR_TO_UINT(ICMPV4Descriptor) + sizeof(t_DsarIcmpV4Descriptor));
++        WRITE_UINT16(ICMPV4Descriptor->control, 0);
++        if (params->p_AutoResEchoIpv4Info->tableSize)
++        {
++            t_FmPortDsarArpEntry* arp_entry = params->p_AutoResEchoIpv4Info->p_AutoResTable;
++            WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&arp_entry[0].mac[0]);
++            WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&arp_entry[0].mac[2]);
++            WRITE_UINT16(ICMPV4Descriptor->numOfBindings, params->p_AutoResEchoIpv4Info->tableSize);
++
++            for (i = 0; i < params->p_AutoResEchoIpv4Info->tableSize; i++)
++            {
++                WRITE_UINT32(icmpv4_bindings[i].ipv4Addr, arp_entry[i].ipAddress);
++                if (arp_entry[i].isVlan)
++                    WRITE_UINT16(icmpv4_bindings[i].vlanId, arp_entry[i].vid & 0xFFF);
++            }
++            WRITE_UINT32(ICMPV4Descriptor->p_Bindings, PTR_TO_UINT(icmpv4_bindings) - fmMuramVirtBaseAddr);
++        }
++        WRITE_UINT32(ICMPV4Descriptor->p_Statistics, PTR_TO_UINT(icmpv4_bindings) +
++            sizeof(t_DsarIcmpV4BindingEntry) * params->p_AutoResEchoIpv4Info->tableSize - fmMuramVirtBaseAddr);
++    }
++
++    // ICMPV6
++    if (params->p_AutoResEchoIpv6Info)
++    {
++        t_DsarIcmpV6BindingEntry* icmpv6_bindings;
++        ICMPV6Descriptor = (t_DsarIcmpV6Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv6);
++        WRITE_UINT32(ArCommonDescPtr->p_IcmpV6Descriptor, PTR_TO_UINT(ICMPV6Descriptor) - fmMuramVirtBaseAddr);
++        icmpv6_bindings = (t_DsarIcmpV6BindingEntry*)(PTR_TO_UINT(ICMPV6Descriptor) + sizeof(t_DsarIcmpV6Descriptor));
++        WRITE_UINT16(ICMPV6Descriptor->control, 0);
++        if (params->p_AutoResEchoIpv6Info->tableSize)
++        {
++            t_FmPortDsarNdpEntry* ndp_entry = params->p_AutoResEchoIpv6Info->p_AutoResTable;
++            WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&ndp_entry[0].mac[0]);
++            WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&ndp_entry[0].mac[2]);
++            WRITE_UINT16(ICMPV6Descriptor->numOfBindings, params->p_AutoResEchoIpv6Info->tableSize);
++
++            for (i = 0; i < params->p_AutoResEchoIpv6Info->tableSize; i++)
++            {
++                for (j = 0; j < 4; j++)
++                    WRITE_UINT32(icmpv6_bindings[i].ipv6Addr[j], ndp_entry[i].ipAddress[j]);
++                if (ndp_entry[i].isVlan)
++                    WRITE_UINT16(*(uint16_t*)&icmpv6_bindings[i].ipv6Addr[4], ndp_entry[i].vid & 0xFFF); // writing vlan
++            }
++            WRITE_UINT32(ICMPV6Descriptor->p_Bindings, PTR_TO_UINT(icmpv6_bindings) - fmMuramVirtBaseAddr);
++        }
++        WRITE_UINT32(ICMPV6Descriptor->p_Statistics, PTR_TO_UINT(icmpv6_bindings) +
++            sizeof(t_DsarIcmpV6BindingEntry) * params->p_AutoResEchoIpv6Info->tableSize - fmMuramVirtBaseAddr);
++    }
++
++    // ND
++    if (params->p_AutoResNdpInfo)
++    {
++        t_DsarIcmpV6BindingEntry* icmpv6_bindings;
++        NDDescriptor = (t_DsarNdDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->nd);
++        WRITE_UINT32(ArCommonDescPtr->p_NdDescriptor, PTR_TO_UINT(NDDescriptor) - fmMuramVirtBaseAddr);
++        icmpv6_bindings = (t_DsarIcmpV6BindingEntry*)(PTR_TO_UINT(NDDescriptor) + sizeof(t_DsarNdDescriptor));
++      if (params->p_AutoResNdpInfo->enableConflictDetection)
++              WRITE_UINT16(NDDescriptor->control, 1);
++      else
++        WRITE_UINT16(NDDescriptor->control, 0);
++        if (params->p_AutoResNdpInfo->tableSizeAssigned + params->p_AutoResNdpInfo->tableSizeTmp)
++        {
++            t_FmPortDsarNdpEntry* ndp_entry = params->p_AutoResNdpInfo->p_AutoResTableAssigned;
++            WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&ndp_entry[0].mac[0]);
++            WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&ndp_entry[0].mac[2]);
++            WRITE_UINT16(NDDescriptor->numOfBindings, params->p_AutoResNdpInfo->tableSizeAssigned
++                + params->p_AutoResNdpInfo->tableSizeTmp);
++
++            for (i = 0; i < params->p_AutoResNdpInfo->tableSizeAssigned; i++)
++            {
++                for (j = 0; j < 4; j++)
++                    WRITE_UINT32(icmpv6_bindings[i].ipv6Addr[j], ndp_entry[i].ipAddress[j]);
++                if (ndp_entry[i].isVlan)
++                    WRITE_UINT16(*(uint16_t*)&icmpv6_bindings[i].ipv6Addr[4], ndp_entry[i].vid & 0xFFF); // writing vlan
++            }
++            ndp_entry = params->p_AutoResNdpInfo->p_AutoResTableTmp;
++            for (i = 0; i < params->p_AutoResNdpInfo->tableSizeTmp; i++)
++            {
++                for (j = 0; j < 4; j++)
++                    WRITE_UINT32(icmpv6_bindings[i + params->p_AutoResNdpInfo->tableSizeAssigned].ipv6Addr[j], ndp_entry[i].ipAddress[j]);
++                if (ndp_entry[i].isVlan)
++                    WRITE_UINT16(*(uint16_t*)&icmpv6_bindings[i + params->p_AutoResNdpInfo->tableSizeAssigned].ipv6Addr[4], ndp_entry[i].vid & 0xFFF); // writing vlan
++            }
++            WRITE_UINT32(NDDescriptor->p_Bindings, PTR_TO_UINT(icmpv6_bindings) - fmMuramVirtBaseAddr);
++        }
++        WRITE_UINT32(NDDescriptor->p_Statistics, PTR_TO_UINT(icmpv6_bindings) + sizeof(t_DsarIcmpV6BindingEntry)
++            * (params->p_AutoResNdpInfo->tableSizeAssigned + params->p_AutoResNdpInfo->tableSizeTmp)
++            - fmMuramVirtBaseAddr);
++        WRITE_UINT32(NDDescriptor->solicitedAddr, 0xFFFFFFFF);
++    }
++
++    // SNMP
++    if (params->p_AutoResSnmpInfo)
++    {
++        t_FmPortDsarSnmpInfo *snmpSrc = params->p_AutoResSnmpInfo;
++        t_DsarSnmpIpv4AddrTblEntry* snmpIpv4Addr;
++        t_DsarSnmpIpv6AddrTblEntry* snmpIpv6Addr;
++        t_OidsTblEntry* snmpOid;
++        uint8_t *charPointer;
++        int len;
++        t_DsarSnmpDescriptor* SnmpDescriptor = (t_DsarSnmpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->snmp);
++        WRITE_UINT32(ArCommonDescPtr->p_SnmpDescriptor, PTR_TO_UINT(SnmpDescriptor) - fmMuramVirtBaseAddr);
++        WRITE_UINT16(SnmpDescriptor->control, snmpSrc->control);
++        WRITE_UINT16(SnmpDescriptor->maxSnmpMsgLength, snmpSrc->maxSnmpMsgLength);
++        snmpIpv4Addr = (t_DsarSnmpIpv4AddrTblEntry*)(PTR_TO_UINT(SnmpDescriptor) + sizeof(t_DsarSnmpDescriptor));
++        if (snmpSrc->numOfIpv4Addresses)
++        {
++            t_FmPortDsarSnmpIpv4AddrTblEntry* snmpIpv4AddrSrc = snmpSrc->p_Ipv4AddrTbl;
++            WRITE_UINT16(SnmpDescriptor->numOfIpv4Addresses, snmpSrc->numOfIpv4Addresses);
++            for (i = 0; i < snmpSrc->numOfIpv4Addresses; i++)
++            {
++                WRITE_UINT32(snmpIpv4Addr[i].ipv4Addr, snmpIpv4AddrSrc[i].ipv4Addr);
++                if (snmpIpv4AddrSrc[i].isVlan)
++                    WRITE_UINT16(snmpIpv4Addr[i].vlanId, snmpIpv4AddrSrc[i].vid & 0xFFF);
++            }
++            WRITE_UINT32(SnmpDescriptor->p_Ipv4AddrTbl, PTR_TO_UINT(snmpIpv4Addr) - fmMuramVirtBaseAddr);
++        }
++        snmpIpv6Addr = (t_DsarSnmpIpv6AddrTblEntry*)(PTR_TO_UINT(snmpIpv4Addr)
++                + sizeof(t_DsarSnmpIpv4AddrTblEntry) * snmpSrc->numOfIpv4Addresses);
++        if (snmpSrc->numOfIpv6Addresses)
++        {
++            t_FmPortDsarSnmpIpv6AddrTblEntry* snmpIpv6AddrSrc = snmpSrc->p_Ipv6AddrTbl;
++            WRITE_UINT16(SnmpDescriptor->numOfIpv6Addresses, snmpSrc->numOfIpv6Addresses);
++            for (i = 0; i < snmpSrc->numOfIpv6Addresses; i++)
++            {
++                for (j = 0; j < 4; j++)
++                    WRITE_UINT32(snmpIpv6Addr[i].ipv6Addr[j], snmpIpv6AddrSrc[i].ipv6Addr[j]);
++                if (snmpIpv6AddrSrc[i].isVlan)
++                    WRITE_UINT16(snmpIpv6Addr[i].vlanId, snmpIpv6AddrSrc[i].vid & 0xFFF);
++            }
++            WRITE_UINT32(SnmpDescriptor->p_Ipv6AddrTbl, PTR_TO_UINT(snmpIpv6Addr) - fmMuramVirtBaseAddr);
++        }
++        snmpOid = (t_OidsTblEntry*)(PTR_TO_UINT(snmpIpv6Addr)
++                + sizeof(t_DsarSnmpIpv6AddrTblEntry) * snmpSrc->numOfIpv6Addresses);
++        charPointer = (uint8_t*)(PTR_TO_UINT(snmpOid)
++                + sizeof(t_OidsTblEntry) * snmpSrc->oidsTblSize);
++        len = TOTAL_BER_LEN(GetBERLen(&snmpSrc->p_RdOnlyCommunityStr[1]));
++        Mem2IOCpy32(charPointer, snmpSrc->p_RdOnlyCommunityStr, len);
++        WRITE_UINT32(SnmpDescriptor->p_RdOnlyCommunityStr, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr);
++        charPointer += len;
++        len = TOTAL_BER_LEN(GetBERLen(&snmpSrc->p_RdWrCommunityStr[1]));
++        Mem2IOCpy32(charPointer, snmpSrc->p_RdWrCommunityStr, len);
++        WRITE_UINT32(SnmpDescriptor->p_RdWrCommunityStr, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr);
++        charPointer += len;
++        WRITE_UINT32(SnmpDescriptor->oidsTblSize, snmpSrc->oidsTblSize);
++        WRITE_UINT32(SnmpDescriptor->p_OidsTbl, PTR_TO_UINT(snmpOid) - fmMuramVirtBaseAddr);
++        for (i = 0; i < snmpSrc->oidsTblSize; i++)
++        {
++            WRITE_UINT16(snmpOid->oidSize, snmpSrc->p_OidsTbl[i].oidSize);
++            WRITE_UINT16(snmpOid->resSize, snmpSrc->p_OidsTbl[i].resSize);
++            Mem2IOCpy32(charPointer, snmpSrc->p_OidsTbl[i].oidVal, snmpSrc->p_OidsTbl[i].oidSize);
++            WRITE_UINT32(snmpOid->p_Oid, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr);
++            charPointer += snmpSrc->p_OidsTbl[i].oidSize;
++            if (snmpSrc->p_OidsTbl[i].resSize <= 4)
++                WRITE_UINT32(snmpOid->resValOrPtr, *snmpSrc->p_OidsTbl[i].resVal);
++            else
++            {
++                Mem2IOCpy32(charPointer, snmpSrc->p_OidsTbl[i].resVal, snmpSrc->p_OidsTbl[i].resSize);
++                WRITE_UINT32(snmpOid->resValOrPtr, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr);
++                charPointer += snmpSrc->p_OidsTbl[i].resSize;
++            }
++            snmpOid++;
++        }
++        charPointer = UINT_TO_PTR(ROUND_UP(PTR_TO_UINT(charPointer),4));
++        WRITE_UINT32(SnmpDescriptor->p_Statistics, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr);
++    }
++
++    // filtering
++    if (params->p_AutoResFilteringInfo)
++    {
++        if (params->p_AutoResFilteringInfo->ipProtPassOnHit)
++            tmp |= IP_PROT_TBL_PASS_MASK;
++        if (params->p_AutoResFilteringInfo->udpPortPassOnHit)
++            tmp |= UDP_PORT_TBL_PASS_MASK;
++        if (params->p_AutoResFilteringInfo->tcpPortPassOnHit)
++            tmp |= TCP_PORT_TBL_PASS_MASK;
++        WRITE_UINT8(ArCommonDescPtr->filterControl, tmp);
++        WRITE_UINT16(ArCommonDescPtr->tcpControlPass, params->p_AutoResFilteringInfo->tcpFlagsMask);
++
++        // ip filtering
++        if (params->p_AutoResFilteringInfo->ipProtTableSize)
++        {
++            uint8_t* ip_tbl = (uint8_t*)(PTR_TO_UINT(ArCommonDescPtr) + of->filtIp);
++            WRITE_UINT8(ArCommonDescPtr->ipProtocolTblSize, params->p_AutoResFilteringInfo->ipProtTableSize);
++            for (i = 0; i < params->p_AutoResFilteringInfo->ipProtTableSize; i++)
++                WRITE_UINT8(ip_tbl[i], params->p_AutoResFilteringInfo->p_IpProtTablePtr[i]);
++            WRITE_UINT32(ArCommonDescPtr->p_IpProtocolFiltTbl, PTR_TO_UINT(ip_tbl) - fmMuramVirtBaseAddr);
++        }
++
++        // udp filtering
++        if (params->p_AutoResFilteringInfo->udpPortsTableSize)
++        {
++            t_PortTblEntry* udp_tbl = (t_PortTblEntry*)(PTR_TO_UINT(ArCommonDescPtr) + of->filtUdp);
++            WRITE_UINT8(ArCommonDescPtr->udpPortTblSize, params->p_AutoResFilteringInfo->udpPortsTableSize);
++            for (i = 0; i < params->p_AutoResFilteringInfo->udpPortsTableSize; i++)
++            {
++                WRITE_UINT32(udp_tbl[i].Ports,
++                    (params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].srcPort << 16) +
++                    params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].dstPort);
++                WRITE_UINT32(udp_tbl[i].PortsMask,
++                    (params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].srcPortMask << 16) +
++                    params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].dstPortMask);
++            }
++            WRITE_UINT32(ArCommonDescPtr->p_UdpPortFiltTbl, PTR_TO_UINT(udp_tbl) - fmMuramVirtBaseAddr);
++        }
++
++        // tcp filtering
++        if (params->p_AutoResFilteringInfo->tcpPortsTableSize)
++        {
++            t_PortTblEntry* tcp_tbl = (t_PortTblEntry*)(PTR_TO_UINT(ArCommonDescPtr) + of->filtTcp);
++            WRITE_UINT8(ArCommonDescPtr->tcpPortTblSize, params->p_AutoResFilteringInfo->tcpPortsTableSize);
++            for (i = 0; i < params->p_AutoResFilteringInfo->tcpPortsTableSize; i++)
++            {
++                WRITE_UINT32(tcp_tbl[i].Ports,
++                    (params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].srcPort << 16) +
++                    params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].dstPort);
++                WRITE_UINT32(tcp_tbl[i].PortsMask,
++                    (params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].srcPortMask << 16) +
++                    params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].dstPortMask);
++            }
++            WRITE_UINT32(ArCommonDescPtr->p_TcpPortFiltTbl, PTR_TO_UINT(tcp_tbl) - fmMuramVirtBaseAddr);
++        }
++    }
++    // common stats
++    WRITE_UINT32(ArCommonDescPtr->p_ArStats, PTR_TO_UINT(ArCommonDescPtr) + of->stats - fmMuramVirtBaseAddr);
++
++    // get into Deep Sleep sequence:
++
++      // Ensures that FMan do not enter the idle state. This is done by programing
++      // FMDPSLPCR[FM_STOP] to one.
++      fm_soc_suspend();
++
++    ARDesc = UINT_TO_PTR(XX_VirtToPhys(ArCommonDescPtr));
++    return E_OK;
++
++}
++
++void FM_ChangeClock(t_Handle h_Fm, int hardwarePortId);
++t_Error FM_PORT_EnterDsarFinal(t_Handle h_DsarRxPort, t_Handle h_DsarTxPort)
++{
++      t_FmGetSetParams fmGetSetParams;
++      t_FmPort *p_FmPort = (t_FmPort *)h_DsarRxPort;
++      t_FmPort *p_FmPortTx = (t_FmPort *)h_DsarTxPort;
++      t_Handle *h_FmPcd = FmGetPcd(p_FmPort->h_Fm);
++      t_FmPort *p_FmPortHc = FM_PCD_GetHcPort(h_FmPcd);
++      memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
++        fmGetSetParams.setParams.type = UPDATE_FM_CLD;
++        FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
++
++      /* Issue graceful stop to HC port */
++      FM_PORT_Disable(p_FmPortHc);
++
++      // config tx port
++    p_FmPort->deepSleepVars.fmbm_tcfg = GET_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg);
++    WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg, GET_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg) | BMI_PORT_CFG_IM | BMI_PORT_CFG_EN);
++    // ????
++    p_FmPort->deepSleepVars.fmbm_tcmne = GET_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcmne);
++    WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcmne, 0xE);
++    // Stage 7:echo
++    p_FmPort->deepSleepVars.fmbm_rfpne = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne);
++    WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne, 0x2E);
++    if (!PrsIsEnabled(h_FmPcd))
++    {
++        p_FmPort->deepSleepVars.dsarEnabledParser = TRUE;
++        PrsEnable(h_FmPcd);
++    }
++    else
++        p_FmPort->deepSleepVars.dsarEnabledParser = FALSE;
++
++    p_FmPort->deepSleepVars.fmbm_rfne = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne);
++    WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne, 0x440000);
++
++    // save rcfg for restoring: accumulate mode is changed by ucode
++    p_FmPort->deepSleepVars.fmbm_rcfg = GET_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rcfg);
++    WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rcfg, p_FmPort->deepSleepVars.fmbm_rcfg | BMI_PORT_CFG_AM);
++        memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
++        fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP;
++        fmGetSetParams.setParams.sleep = 1;
++        FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
++
++// ***** issue external request sync command
++        memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
++        fmGetSetParams.setParams.type = UPDATE_FPM_EXTC;
++        FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
++      // get
++      memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
++      fmGetSetParams.getParams.type = GET_FMFP_EXTC;
++      FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
++      if (fmGetSetParams.getParams.fmfp_extc != 0)
++      {
++              // clear
++              memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
++              fmGetSetParams.setParams.type = UPDATE_FPM_EXTC_CLEAR;
++              FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
++}
++
++      memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
++      fmGetSetParams.getParams.type = GET_FMFP_EXTC | GET_FM_NPI;
++      do
++      {
++              FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
++      } while (fmGetSetParams.getParams.fmfp_extc != 0 && fmGetSetParams.getParams.fm_npi == 0);
++      if (fmGetSetParams.getParams.fm_npi != 0)
++              XX_Print("FM: Sync did not finish\n");
++
++        // check that all stoped
++      memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
++        fmGetSetParams.getParams.type = GET_FMQM_GS | GET_FM_NPI;
++        FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
++      while (fmGetSetParams.getParams.fmqm_gs & 0xF0000000)
++              FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
++      if (fmGetSetParams.getParams.fmqm_gs == 0 && fmGetSetParams.getParams.fm_npi == 0)
++              XX_Print("FM: Sleeping\n");
++//    FM_ChangeClock(p_FmPort->h_Fm, p_FmPort->hardwarePortId);
++
++    return E_OK;
++}
++
++EXPORT_SYMBOL(FM_PORT_EnterDsarFinal);
++
++void FM_PORT_Dsar_DumpRegs()
++{
++    uint32_t* hh = XX_PhysToVirt(PTR_TO_UINT(ARDesc));
++    DUMP_MEMORY(hh, 0x220);
++}
++
++void FM_PORT_ExitDsar(t_Handle h_FmPortRx, t_Handle h_FmPortTx)
++{
++    t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx;
++    t_FmPort *p_FmPortTx = (t_FmPort *)h_FmPortTx;
++    t_Handle *h_FmPcd = FmGetPcd(p_FmPort->h_Fm);
++    t_FmPort *p_FmPortHc = FM_PCD_GetHcPort(h_FmPcd);
++    t_FmGetSetParams fmGetSetParams;
++    memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
++    fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP;
++    fmGetSetParams.setParams.sleep = 0;
++    if (p_FmPort->deepSleepVars.autoResOffsets)
++    {
++        XX_Free(p_FmPort->deepSleepVars.autoResOffsets);
++        p_FmPort->deepSleepVars.autoResOffsets = 0;
++    }
++
++    if (p_FmPort->deepSleepVars.dsarEnabledParser)
++        PrsDisable(FmGetPcd(p_FmPort->h_Fm));
++    WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne, p_FmPort->deepSleepVars.fmbm_rfpne);
++    WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne, p_FmPort->deepSleepVars.fmbm_rfne);
++    WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rcfg, p_FmPort->deepSleepVars.fmbm_rcfg);
++    FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
++    WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcmne, p_FmPort->deepSleepVars.fmbm_tcmne);
++    WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg, p_FmPort->deepSleepVars.fmbm_tcfg);
++    FM_PORT_Enable(p_FmPortHc);
++}
++
++bool FM_PORT_IsInDsar(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort *)h_FmPort;
++    return PTR_TO_UINT(p_FmPort->deepSleepVars.autoResOffsets);
++}
++
++t_Error FM_PORT_GetDsarStats(t_Handle h_FmPortRx, t_FmPortDsarStats *stats)
++{
++    t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx;
++    struct arOffsets *of = (struct arOffsets*)p_FmPort->deepSleepVars.autoResOffsets;
++    uint8_t* fmMuramVirtBaseAddr = XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr);
++    uint32_t *param_page = XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr));
++    t_ArCommonDesc *ArCommonDescPtr = (t_ArCommonDesc*)(XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(*param_page)));
++    t_DsarArpDescriptor *ArpDescriptor = (t_DsarArpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->arp);
++    t_DsarArpStatistics* arp_stats = (t_DsarArpStatistics*)(PTR_TO_UINT(ArpDescriptor->p_Statistics) + fmMuramVirtBaseAddr);
++    t_DsarIcmpV4Descriptor* ICMPV4Descriptor = (t_DsarIcmpV4Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv4);
++    t_DsarIcmpV4Statistics* icmpv4_stats = (t_DsarIcmpV4Statistics*)(PTR_TO_UINT(ICMPV4Descriptor->p_Statistics) + fmMuramVirtBaseAddr);
++    t_DsarNdDescriptor* NDDescriptor = (t_DsarNdDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->nd);
++    t_NdStatistics* nd_stats = (t_NdStatistics*)(PTR_TO_UINT(NDDescriptor->p_Statistics) + fmMuramVirtBaseAddr);
++    t_DsarIcmpV6Descriptor* ICMPV6Descriptor = (t_DsarIcmpV6Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv6);
++    t_DsarIcmpV6Statistics* icmpv6_stats = (t_DsarIcmpV6Statistics*)(PTR_TO_UINT(ICMPV6Descriptor->p_Statistics) + fmMuramVirtBaseAddr);
++    t_DsarSnmpDescriptor* SnmpDescriptor = (t_DsarSnmpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->snmp);
++    t_DsarSnmpStatistics* snmp_stats = (t_DsarSnmpStatistics*)(PTR_TO_UINT(SnmpDescriptor->p_Statistics) + fmMuramVirtBaseAddr);
++    stats->arpArCnt = arp_stats->arCnt;
++    stats->echoIcmpv4ArCnt = icmpv4_stats->arCnt;
++    stats->ndpArCnt = nd_stats->arCnt;
++    stats->echoIcmpv6ArCnt = icmpv6_stats->arCnt;
++    stats->snmpGetCnt = snmp_stats->snmpGetReqCnt;
++    stats->snmpGetNextCnt = snmp_stats->snmpGetNextReqCnt;
++    return E_OK;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h
+@@ -0,0 +1,999 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_port.h
++
++ @Description   FM Port internal structures and definitions.
++*//***************************************************************************/
++#ifndef __FM_PORT_H
++#define __FM_PORT_H
++
++#include "error_ext.h"
++#include "std_ext.h"
++#include "fm_port_ext.h"
++
++#include "fm_common.h"
++#include "fm_sp_common.h"
++#include "fsl_fman_sp.h"
++#include "fm_port_ext.h"
++#include "fsl_fman_port.h"
++
++#define __ERR_MODULE__  MODULE_FM_PORT
++
++
++#define MIN_EXT_BUF_SIZE                                64
++#define DATA_ALIGNMENT                                  64
++#define MAX_LIODN_OFFSET                                64
++#define MAX_PORT_FIFO_SIZE                              MIN(BMI_MAX_FIFO_SIZE, 1024*BMI_FIFO_UNITS)
++
++/**************************************************************************//**
++ @Description       Memory Map defines
++*//***************************************************************************/
++#define BMI_PORT_REGS_OFFSET                            0
++#define QMI_PORT_REGS_OFFSET                            0x400
++#define PRS_PORT_REGS_OFFSET                            0x800
++
++/**************************************************************************//**
++ @Description       defaults
++*//***************************************************************************/
++#define DEFAULT_PORT_deqHighPriority_1G                 FALSE
++#define DEFAULT_PORT_deqHighPriority_10G                TRUE
++#define DEFAULT_PORT_deqType                            e_FM_PORT_DEQ_TYPE1
++#define DEFAULT_PORT_deqPrefetchOption                  e_FM_PORT_DEQ_FULL_PREFETCH
++#define DEFAULT_PORT_deqPrefetchOption_HC               e_FM_PORT_DEQ_NO_PREFETCH
++#define DEFAULT_PORT_deqByteCnt_10G                     0x1400
++#define DEFAULT_PORT_deqByteCnt_1G                      0x400
++#define DEFAULT_PORT_bufferPrefixContent_privDataSize   DEFAULT_FM_SP_bufferPrefixContent_privDataSize
++#define DEFAULT_PORT_bufferPrefixContent_passPrsResult  DEFAULT_FM_SP_bufferPrefixContent_passPrsResult
++#define DEFAULT_PORT_bufferPrefixContent_passTimeStamp  DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp
++#define DEFAULT_PORT_bufferPrefixContent_allOtherPCDInfo DEFAULT_FM_SP_bufferPrefixContent_allOtherPCDInfo
++#define DEFAULT_PORT_bufferPrefixContent_dataAlign      DEFAULT_FM_SP_bufferPrefixContent_dataAlign
++#define DEFAULT_PORT_cheksumLastBytesIgnore             0
++#define DEFAULT_PORT_cutBytesFromEnd                    4
++#define DEFAULT_PORT_fifoDeqPipelineDepth_IM            2
++
++#define DEFAULT_PORT_frmDiscardOverride                 FALSE
++
++#define DEFAULT_PORT_dmaSwapData                        (e_FmDmaSwapOption)DEFAULT_FMAN_SP_DMA_SWAP_DATA
++#define DEFAULT_PORT_dmaIntContextCacheAttr             (e_FmDmaCacheOption)DEFAULT_FMAN_SP_DMA_INT_CONTEXT_CACHE_ATTR
++#define DEFAULT_PORT_dmaHeaderCacheAttr                 (e_FmDmaCacheOption)DEFAULT_FMAN_SP_DMA_HEADER_CACHE_ATTR
++#define DEFAULT_PORT_dmaScatterGatherCacheAttr          (e_FmDmaCacheOption)DEFAULT_FMAN_SP_DMA_SCATTER_GATHER_CACHE_ATTR
++#define DEFAULT_PORT_dmaWriteOptimize                   DEFAULT_FMAN_SP_DMA_WRITE_OPTIMIZE
++
++#define DEFAULT_PORT_noScatherGather                    DEFAULT_FMAN_SP_NO_SCATTER_GATHER
++#define DEFAULT_PORT_forwardIntContextReuse             FALSE
++#define DEFAULT_PORT_BufMargins_startMargins            32
++#define DEFAULT_PORT_BufMargins_endMargins              0
++#define DEFAULT_PORT_syncReq                            TRUE
++#define DEFAULT_PORT_syncReqForHc                       FALSE
++#define DEFAULT_PORT_color                              e_FM_PORT_COLOR_GREEN
++#define DEFAULT_PORT_errorsToDiscard                    FM_PORT_FRM_ERR_CLS_DISCARD
++/* #define DEFAULT_PORT_dualRateLimitScaleDown             e_FM_PORT_DUAL_RATE_LIMITER_NONE */
++/* #define DEFAULT_PORT_rateLimitBurstSizeHighGranularity  FALSE */
++#define DEFAULT_PORT_exception                          IM_EV_BSY
++#define DEFAULT_PORT_maxFrameLength                     9600
++
++#define DEFAULT_notSupported                            0xff
++
++#if (DPAA_VERSION < 11)
++#define DEFAULT_PORT_rxFifoPriElevationLevel            MAX_PORT_FIFO_SIZE
++#define DEFAULT_PORT_rxFifoThreshold                    (MAX_PORT_FIFO_SIZE*3/4)
++
++#define DEFAULT_PORT_txFifoMinFillLevel                 0
++#define DEFAULT_PORT_txFifoLowComfLevel                 (5*KILOBYTE)
++#define DEFAULT_PORT_fifoDeqPipelineDepth_1G            1
++#define DEFAULT_PORT_fifoDeqPipelineDepth_10G           4
++
++#define DEFAULT_PORT_fifoDeqPipelineDepth_OH            2
++
++/* Host command port MUST NOT be changed to more than 1 !!! */
++#define DEFAULT_PORT_numOfTasks(type)                       \
++    (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) ||        \
++                ((type) == e_FM_PORT_TYPE_TX_10G)) ? 16 :   \
++               ((((type) == e_FM_PORT_TYPE_RX) ||           \
++                 ((type) == e_FM_PORT_TYPE_TX) ||           \
++                 ((type) == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ? 3 : 1))
++
++#define DEFAULT_PORT_extraNumOfTasks(type)                  \
++    (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G)  ? 8 :    \
++               (((type) == e_FM_PORT_TYPE_RX) ? 2 : 0))
++
++#define DEFAULT_PORT_numOfOpenDmas(type)                    \
++    (uint32_t)((((type) == e_FM_PORT_TYPE_TX_10G) ||        \
++                ((type) == e_FM_PORT_TYPE_RX_10G)) ? 8 : 1 )
++
++#define DEFAULT_PORT_extraNumOfOpenDmas(type)               \
++    (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G) ? 8 :    \
++               (((type) == e_FM_PORT_TYPE_RX) ? 1 : 0))
++
++#define DEFAULT_PORT_numOfFifoBufs(type)                    \
++    (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) ||        \
++                ((type) == e_FM_PORT_TYPE_TX_10G)) ? 48 :   \
++                ((type) == e_FM_PORT_TYPE_RX) ? 45 :        \
++                ((type) == e_FM_PORT_TYPE_TX) ? 44 : 8)
++
++#define DEFAULT_PORT_extraNumOfFifoBufs             0
++
++#else  /* (DPAA_VERSION < 11) */
++/* Defaults are registers' reset values */
++#define DEFAULT_PORT_rxFifoPriElevationLevel            MAX_PORT_FIFO_SIZE
++#define DEFAULT_PORT_rxFifoThreshold                    MAX_PORT_FIFO_SIZE
++
++#define DEFAULT_PORT_txFifoMinFillLevel                 0
++#define DEFAULT_PORT_txFifoLowComfLevel                 (5 * KILOBYTE)
++#define DEFAULT_PORT_fifoDeqPipelineDepth_1G            2
++#define DEFAULT_PORT_fifoDeqPipelineDepth_10G           4
++
++#define DEFAULT_PORT_fifoDeqPipelineDepth_OH            2
++
++#define DEFAULT_PORT_numOfTasks(type)                       \
++    (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) ||        \
++                ((type) == e_FM_PORT_TYPE_TX_10G)) ? 14 :   \
++               (((type) == e_FM_PORT_TYPE_RX) ||            \
++                 ((type) == e_FM_PORT_TYPE_TX)) ? 4 :       \
++                 ((type) == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ? 6 : 1)
++
++#define DEFAULT_PORT_extraNumOfTasks(type)          0
++
++#define DEFAULT_PORT_numOfOpenDmas(type)                    \
++    (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G) ? 8 :      \
++               ((type) == e_FM_PORT_TYPE_TX_10G) ? 12 :     \
++               ((type) == e_FM_PORT_TYPE_RX)     ? 2 :      \
++               ((type) == e_FM_PORT_TYPE_TX)     ? 3 :      \
++               ((type) == e_FM_PORT_TYPE_OH_HOST_COMMAND) ? 2 : 4)
++
++#define DEFAULT_PORT_extraNumOfOpenDmas(type)       0
++
++#define DEFAULT_PORT_numOfFifoBufs(type)                   \
++    (uint32_t) (((type) == e_FM_PORT_TYPE_RX_10G) ? 96 : \
++                ((type) == e_FM_PORT_TYPE_TX_10G) ? 64 : \
++                ((type) == e_FM_PORT_TYPE_OH_HOST_COMMAND) ? 10 : 50)
++
++#define DEFAULT_PORT_extraNumOfFifoBufs             0
++
++#endif /* (DPAA_VERSION < 11) */
++
++#define DEFAULT_PORT_txBdRingLength                 16
++#define DEFAULT_PORT_rxBdRingLength                 128
++#define DEFAULT_PORT_ImfwExtStructsMemId            0
++#define DEFAULT_PORT_ImfwExtStructsMemAttr          MEMORY_ATTR_CACHEABLE
++
++#define FM_PORT_CG_REG_NUM(_cgId) (((FM_PORT_NUM_OF_CONGESTION_GRPS/32)-1)-_cgId/32)
++
++/**************************************************************************//**
++ @Collection    PCD Engines
++*//***************************************************************************/
++typedef uint32_t fmPcdEngines_t; /**< options as defined below: */
++
++#define FM_PCD_NONE                                 0                   /**< No PCD Engine indicated */
++#define FM_PCD_PRS                                  0x80000000          /**< Parser indicated */
++#define FM_PCD_KG                                   0x40000000          /**< Keygen indicated */
++#define FM_PCD_CC                                   0x20000000          /**< Coarse classification indicated */
++#define FM_PCD_PLCR                                 0x10000000          /**< Policer indicated */
++#define FM_PCD_MANIP                                0x08000000          /**< Manipulation indicated */
++/* @} */
++
++#define FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS       8
++#define FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS 256
++#define FM_PORT_CG_REG_NUM(_cgId) (((FM_PORT_NUM_OF_CONGESTION_GRPS/32)-1)-_cgId/32)
++
++#define FM_OH_PORT_ID                               0
++
++/***********************************************************************/
++/*          SW parser OFFLOAD labels (offsets)                         */
++/***********************************************************************/
++#if (DPAA_VERSION == 10)
++#define OFFLOAD_SW_PATCH_IPv4_IPR_LABEL         0x300
++#define OFFLOAD_SW_PATCH_IPv6_IPR_LABEL         0x325
++#define OFFLOAD_SW_PATCH_IPv6_IPF_LABEL         0x325
++#else
++#define OFFLOAD_SW_PATCH_IPv4_IPR_LABEL         0x100
++/* Will be used for:
++ * 1. identify fragments
++ * 2. udp-lite
++ */
++#define OFFLOAD_SW_PATCH_IPv6_IPR_LABEL         0x146
++/* Will be used for:
++ * 1. will identify the fragmentable area
++ * 2. udp-lite
++ */
++#define OFFLOAD_SW_PATCH_IPv6_IPF_LABEL         0x261
++#define OFFLOAD_SW_PATCH_CAPWAP_LABEL           0x38d
++#endif /* (DPAA_VERSION == 10) */
++
++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++#define UDP_LITE_SW_PATCH_LABEL                 0x2E0
++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
++
++
++/**************************************************************************//**
++ @Description       Memory Mapped Registers
++*//***************************************************************************/
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(push,1)
++#endif /* defined(__MWERKS__) && ... */
++
++typedef struct
++{
++    volatile uint32_t   fmbm_rcfg;      /**< Rx Configuration */
++    volatile uint32_t   fmbm_rst;       /**< Rx Status */
++    volatile uint32_t   fmbm_rda;       /**< Rx DMA attributes*/
++    volatile uint32_t   fmbm_rfp;       /**< Rx FIFO Parameters*/
++    volatile uint32_t   fmbm_rfed;      /**< Rx Frame End Data*/
++    volatile uint32_t   fmbm_ricp;      /**< Rx Internal Context Parameters*/
++    volatile uint32_t   fmbm_rim;       /**< Rx Internal Buffer Margins*/
++    volatile uint32_t   fmbm_rebm;      /**< Rx External Buffer Margins*/
++    volatile uint32_t   fmbm_rfne;      /**< Rx Frame Next Engine*/
++    volatile uint32_t   fmbm_rfca;      /**< Rx Frame Command Attributes.*/
++    volatile uint32_t   fmbm_rfpne;     /**< Rx Frame Parser Next Engine*/
++    volatile uint32_t   fmbm_rpso;      /**< Rx Parse Start Offset*/
++    volatile uint32_t   fmbm_rpp;       /**< Rx Policer Profile  */
++    volatile uint32_t   fmbm_rccb;      /**< Rx Coarse Classification Base */
++    volatile uint32_t   fmbm_reth;      /**< Rx Excessive Threshold */
++    volatile uint32_t   reserved1[0x01];/**< (0x03C) */
++    volatile uint32_t   fmbm_rprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS];
++                                        /**< Rx Parse Results Array Initialization*/
++    volatile uint32_t   fmbm_rfqid;     /**< Rx Frame Queue ID*/
++    volatile uint32_t   fmbm_refqid;    /**< Rx Error Frame Queue ID*/
++    volatile uint32_t   fmbm_rfsdm;     /**< Rx Frame Status Discard Mask*/
++    volatile uint32_t   fmbm_rfsem;     /**< Rx Frame Status Error Mask*/
++    volatile uint32_t   fmbm_rfene;     /**< Rx Frame Enqueue Next Engine */
++    volatile uint32_t   reserved2[0x02];/**< (0x074-0x078) */
++    volatile uint32_t   fmbm_rcmne;     /**< Rx Frame Continuous Mode Next Engine */
++    volatile uint32_t   reserved3[0x20];/**< (0x080 0x0FF)  */
++    volatile uint32_t   fmbm_ebmpi[FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS];
++                                        /**< Buffer Manager pool Information-*/
++    volatile uint32_t   fmbm_acnt[FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS];
++                                        /**< Allocate Counter-*/
++    volatile uint32_t   reserved4[0x08];
++                                        /**< 0x130/0x140 - 0x15F reserved -*/
++    volatile uint32_t   fmbm_rcgm[FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS/32];
++                                        /**< Congestion Group Map*/
++    volatile uint32_t   fmbm_rmpd;      /**< BM Pool Depletion  */
++    volatile uint32_t   reserved5[0x1F];/**< (0x184 0x1FF) */
++    volatile uint32_t   fmbm_rstc;      /**< Rx Statistics Counters*/
++    volatile uint32_t   fmbm_rfrc;      /**< Rx Frame Counter*/
++    volatile uint32_t   fmbm_rfbc;      /**< Rx Bad Frames Counter*/
++    volatile uint32_t   fmbm_rlfc;      /**< Rx Large Frames Counter*/
++    volatile uint32_t   fmbm_rffc;      /**< Rx Filter Frames Counter*/
++    volatile uint32_t   fmbm_rfcd;      /**< Rx Frame Discard Counter*/
++    volatile uint32_t   fmbm_rfldec;    /**< Rx Frames List DMA Error Counter*/
++    volatile uint32_t   fmbm_rodc;      /**< Rx Out of Buffers Discard Counter-*/
++    volatile uint32_t   fmbm_rbdc;      /**< Rx Buffers Deallocate Counter-*/
++    volatile uint32_t   fmbm_rpec;      /**< Rx RX Prepare to enqueue Counter-*/
++    volatile uint32_t   reserved6[0x16];/**< (0x228 0x27F) */
++    volatile uint32_t   fmbm_rpc;       /**< Rx Performance Counters*/
++    volatile uint32_t   fmbm_rpcp;      /**< Rx Performance Count Parameters*/
++    volatile uint32_t   fmbm_rccn;      /**< Rx Cycle Counter*/
++    volatile uint32_t   fmbm_rtuc;      /**< Rx Tasks Utilization Counter*/
++    volatile uint32_t   fmbm_rrquc;     /**< Rx Receive Queue Utilization Counter*/
++    volatile uint32_t   fmbm_rduc;      /**< Rx DMA Utilization Counter*/
++    volatile uint32_t   fmbm_rfuc;      /**< Rx FIFO Utilization Counter*/
++    volatile uint32_t   fmbm_rpac;      /**< Rx Pause Activation Counter*/
++    volatile uint32_t   reserved7[0x18];/**< (0x2A0-0x2FF) */
++    volatile uint32_t   fmbm_rdcfg[0x3];/**< Rx Debug-*/
++    volatile uint32_t   fmbm_rgpr;      /**< Rx General Purpose Register. */
++    volatile uint32_t   reserved8[0x3a];/**< (0x310-0x3FF) */
++} t_FmPortRxBmiRegs;
++
++typedef struct
++{
++    volatile uint32_t   fmbm_tcfg;      /**< Tx Configuration */
++    volatile uint32_t   fmbm_tst;       /**< Tx Status */
++    volatile uint32_t   fmbm_tda;       /**< Tx DMA attributes */
++    volatile uint32_t   fmbm_tfp;       /**< Tx FIFO Parameters */
++    volatile uint32_t   fmbm_tfed;      /**< Tx Frame End Data */
++    volatile uint32_t   fmbm_ticp;      /**< Tx Internal Context Parameters */
++    volatile uint32_t   fmbm_tfdne;     /**< Tx Frame Dequeue Next Engine. */
++    volatile uint32_t   fmbm_tfca;      /**< Tx Frame Command attribute. */
++    volatile uint32_t   fmbm_tcfqid;    /**< Tx Confirmation Frame Queue ID. */
++    volatile uint32_t   fmbm_tfeqid;    /**< Tx Frame Error Queue ID */
++    volatile uint32_t   fmbm_tfene;     /**< Tx Frame Enqueue Next Engine */
++    volatile uint32_t   fmbm_trlmts;    /**< Tx Rate Limiter Scale */
++    volatile uint32_t   fmbm_trlmt;     /**< Tx Rate Limiter */
++    volatile uint32_t   fmbm_tccb;      /**< Tx Coarse Classification Base */
++    volatile uint32_t   reserved0[0x0e];/**< (0x038-0x070) */
++    volatile uint32_t   fmbm_tfne;      /**< Tx Frame Next Engine */
++    volatile uint32_t   fmbm_tpfcm[0x02];/**< Tx Priority based Flow Control (PFC) Mapping */
++    volatile uint32_t   fmbm_tcmne;     /**< Tx Frame Continuous Mode Next Engine */
++    volatile uint32_t   reserved2[0x60];/**< (0x080-0x200) */
++    volatile uint32_t   fmbm_tstc;      /**< Tx Statistics Counters */
++    volatile uint32_t   fmbm_tfrc;      /**< Tx Frame Counter */
++    volatile uint32_t   fmbm_tfdc;      /**< Tx Frames Discard Counter */
++    volatile uint32_t   fmbm_tfledc;    /**< Tx Frame Length error discard counter */
++    volatile uint32_t   fmbm_tfufdc;    /**< Tx Frame unsupported format discard Counter */
++    volatile uint32_t   fmbm_tbdc;      /**< Tx Buffers Deallocate Counter */
++    volatile uint32_t   reserved3[0x1A];/**< (0x218-0x280) */
++    volatile uint32_t   fmbm_tpc;       /**< Tx Performance Counters*/
++    volatile uint32_t   fmbm_tpcp;      /**< Tx Performance Count Parameters*/
++    volatile uint32_t   fmbm_tccn;      /**< Tx Cycle Counter*/
++    volatile uint32_t   fmbm_ttuc;      /**< Tx Tasks Utilization Counter*/
++    volatile uint32_t   fmbm_ttcquc;    /**< Tx Transmit Confirm Queue Utilization Counter*/
++    volatile uint32_t   fmbm_tduc;      /**< Tx DMA Utilization Counter*/
++    volatile uint32_t   fmbm_tfuc;      /**< Tx FIFO Utilization Counter*/
++    volatile uint32_t   reserved4[16];  /**< (0x29C-0x2FF) */
++    volatile uint32_t   fmbm_tdcfg[0x3];/**< Tx Debug-*/
++    volatile uint32_t   fmbm_tgpr;      /**< O/H General Purpose Register */
++    volatile uint32_t   reserved5[0x3a];/**< (0x310-0x3FF) */
++} t_FmPortTxBmiRegs;
++
++typedef struct
++{
++    volatile uint32_t   fmbm_ocfg;      /**< O/H Configuration  */
++    volatile uint32_t   fmbm_ost;       /**< O/H Status */
++    volatile uint32_t   fmbm_oda;       /**< O/H DMA attributes  */
++    volatile uint32_t   fmbm_oicp;      /**< O/H Internal Context Parameters  */
++    volatile uint32_t   fmbm_ofdne;     /**< O/H Frame Dequeue Next Engine  */
++    volatile uint32_t   fmbm_ofne;      /**< O/H Frame Next Engine  */
++    volatile uint32_t   fmbm_ofca;      /**< O/H Frame Command Attributes.  */
++    volatile uint32_t   fmbm_ofpne;     /**< O/H Frame Parser Next Engine  */
++    volatile uint32_t   fmbm_opso;      /**< O/H Parse Start Offset  */
++    volatile uint32_t   fmbm_opp;       /**< O/H Policer Profile */
++    volatile uint32_t   fmbm_occb;      /**< O/H Coarse Classification base */
++    volatile uint32_t   fmbm_oim;       /**< O/H Internal margins*/
++    volatile uint32_t   fmbm_ofp;       /**< O/H Fifo Parameters*/
++    volatile uint32_t   fmbm_ofed;      /**< O/H Frame End Data*/
++    volatile uint32_t   reserved0[2];   /**< (0x038 - 0x03F) */
++    volatile uint32_t   fmbm_oprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS];
++                                        /**< O/H Parse Results Array Initialization  */
++    volatile uint32_t   fmbm_ofqid;     /**< O/H Frame Queue ID  */
++    volatile uint32_t   fmbm_oefqid;    /**< O/H Error Frame Queue ID  */
++    volatile uint32_t   fmbm_ofsdm;     /**< O/H Frame Status Discard Mask  */
++    volatile uint32_t   fmbm_ofsem;     /**< O/H Frame Status Error Mask  */
++    volatile uint32_t   fmbm_ofene;     /**< O/H Frame Enqueue Next Engine  */
++    volatile uint32_t   fmbm_orlmts;    /**< O/H Rate Limiter Scale  */
++    volatile uint32_t   fmbm_orlmt;     /**< O/H Rate Limiter  */
++    volatile uint32_t   fmbm_ocmne;     /**< O/H Continuous Mode Next Engine  */
++    volatile uint32_t   reserved1[0x20];/**< (0x080 - 0x0FF) */
++    volatile uint32_t   fmbm_oebmpi[2]; /**< Buffer Manager Observed Pool Information */
++    volatile uint32_t   reserved2[0x16];/**< (0x108 - 0x15F) */
++    volatile uint32_t   fmbm_ocgm;      /**< Observed Congestion Group Map */
++    volatile uint32_t   reserved3[0x7]; /**< (0x164 - 0x17F) */
++    volatile uint32_t   fmbm_ompd;      /**< Observed BMan Pool Depletion */
++    volatile uint32_t   reserved4[0x1F];/**< (0x184 - 0x1FF) */
++    volatile uint32_t   fmbm_ostc;      /**< O/H Statistics Counters  */
++    volatile uint32_t   fmbm_ofrc;      /**< O/H Frame Counter  */
++    volatile uint32_t   fmbm_ofdc;      /**< O/H Frames Discard Counter  */
++    volatile uint32_t   fmbm_ofledc;    /**< O/H Frames Length Error Discard Counter  */
++    volatile uint32_t   fmbm_ofufdc;    /**< O/H Frames Unsupported Format Discard Counter  */
++    volatile uint32_t   fmbm_offc;      /**< O/H Filter Frames Counter  */
++    volatile uint32_t   fmbm_ofwdc;     /**< - Rx Frames WRED Discard Counter  */
++    volatile uint32_t   fmbm_ofldec;    /**< O/H Frames List DMA Error Counter */
++    volatile uint32_t   fmbm_obdc;      /**< O/H Buffers Deallocate Counter */
++    volatile uint32_t   fmbm_oodc;      /**< O/H Out of Buffers Discard Counter */
++    volatile uint32_t   fmbm_opec;      /**< O/H Prepare to enqueue Counter */
++    volatile uint32_t   reserved5[0x15];/**< ( - 0x27F) */
++    volatile uint32_t   fmbm_opc;       /**< O/H Performance Counters  */
++    volatile uint32_t   fmbm_opcp;      /**< O/H Performance Count Parameters  */
++    volatile uint32_t   fmbm_occn;      /**< O/H Cycle Counter  */
++    volatile uint32_t   fmbm_otuc;      /**< O/H Tasks Utilization Counter  */
++    volatile uint32_t   fmbm_oduc;      /**< O/H DMA Utilization Counter */
++    volatile uint32_t   fmbm_ofuc;      /**< O/H FIFO Utilization Counter */
++    volatile uint32_t   reserved6[26];  /**< (0x298-0x2FF) */
++    volatile uint32_t   fmbm_odcfg[0x3];/**< O/H Debug (only 1 in P1023) */
++    volatile uint32_t   fmbm_ogpr;      /**< O/H General Purpose Register. */
++    volatile uint32_t   reserved7[0x3a];/**< (0x310 0x3FF) */
++} t_FmPortOhBmiRegs;
++
++typedef union
++{
++    t_FmPortRxBmiRegs rxPortBmiRegs;
++    t_FmPortTxBmiRegs txPortBmiRegs;
++    t_FmPortOhBmiRegs ohPortBmiRegs;
++} u_FmPortBmiRegs;
++
++typedef struct
++{
++    volatile uint32_t   reserved1[2];   /**<   0xn024 - 0x02B */
++    volatile uint32_t   fmqm_pndn;      /**<   PortID n Dequeue NIA Register */
++    volatile uint32_t   fmqm_pndc;      /**<   PortID n Dequeue Config Register */
++    volatile uint32_t   fmqm_pndtfc;    /**<   PortID n Dequeue Total Frame Counter */
++    volatile uint32_t   fmqm_pndfdc;    /**<   PortID n Dequeue FQID from Default Counter */
++    volatile uint32_t   fmqm_pndcc;     /**<   PortID n Dequeue Confirm Counter */
++} t_FmPortNonRxQmiRegs;
++
++typedef struct
++{
++    volatile uint32_t   fmqm_pnc;       /**<   PortID n Configuration Register */
++    volatile uint32_t   fmqm_pns;       /**<   PortID n Status Register */
++    volatile uint32_t   fmqm_pnts;      /**<   PortID n Task Status Register */
++    volatile uint32_t   reserved0[4];   /**<   0xn00C - 0xn01B */
++    volatile uint32_t   fmqm_pnen;      /**<   PortID n Enqueue NIA Register */
++    volatile uint32_t   fmqm_pnetfc;    /**<   PortID n Enqueue Total Frame Counter */
++    t_FmPortNonRxQmiRegs nonRxQmiRegs;  /**<   Registers for Tx Hc & Op ports */
++} t_FmPortQmiRegs;
++
++typedef struct
++{
++     struct
++    {
++        volatile uint32_t   softSeqAttach;  /**<   Soft Sequence Attachment */
++        volatile uint32_t   lcv;            /**<   Line-up Enable Confirmation Mask */
++    } hdrs[FM_PCD_PRS_NUM_OF_HDRS];
++    volatile uint32_t   reserved0[0xde];
++    volatile uint32_t   pcac;               /**<   Parse Internal Memory Configuration Access Control Register */
++    volatile uint32_t   pctpid;             /**<   Parse Internal Memory Configured TPID Register */
++} t_FmPortPrsRegs;
++
++/**************************************************************************//*
++ @Description   Basic buffer descriptor (BD) structure
++*//***************************************************************************/
++typedef _Packed struct
++{
++    volatile uint16_t       status;
++    volatile uint16_t       length;
++    volatile uint8_t        reserved0[0x6];
++    volatile uint8_t        reserved1[0x1];
++    volatile t_FmPhysAddr   buff;
++} _PackedType t_FmImBd;
++
++typedef _Packed struct
++{
++    volatile uint16_t       gen;                /**< tbd */
++    volatile uint8_t        reserved0[0x1];
++    volatile t_FmPhysAddr   bdRingBase;         /**< tbd */
++    volatile uint16_t       bdRingSize;         /**< tbd */
++    volatile uint16_t       offsetIn;           /**< tbd */
++    volatile uint16_t       offsetOut;          /**< tbd */
++    volatile uint8_t        reserved1[0x12];    /**< 0x0e - 0x1f */
++} _PackedType t_FmPortImQd;
++
++typedef _Packed struct
++{
++    volatile uint32_t   mode;               /**< Mode register */
++    volatile uint32_t   rxQdPtr;            /**< tbd */
++    volatile uint32_t   txQdPtr;            /**< tbd */
++    volatile uint16_t   mrblr;              /**< tbd */
++    volatile uint16_t   rxQdBsyCnt;         /**< tbd */
++    volatile uint8_t    reserved0[0x10];    /**< 0x10 - 0x1f */
++    t_FmPortImQd        rxQd;
++    t_FmPortImQd        txQd;
++    volatile uint8_t    reserved1[0xa0];    /**< 0x60 - 0xff */
++} _PackedType t_FmPortImPram;
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(pop)
++#endif /* defined(__MWERKS__) && ... */
++
++
++/**************************************************************************//**
++ @Description       Registers bit fields
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description       BMI defines
++*//***************************************************************************/
++#if (DPAA_VERSION >= 11)
++#define BMI_SP_ID_MASK                          0xff000000
++#define BMI_SP_ID_SHIFT                         24
++#define BMI_SP_EN                               0x01000000
++#endif /* (DPAA_VERSION >= 11) */
++
++#define BMI_PORT_CFG_EN                         0x80000000
++#define BMI_PORT_CFG_EN_MACSEC                  0x00800000
++#define BMI_PORT_CFG_FDOVR                      0x02000000
++#define BMI_PORT_CFG_IM                         0x01000000
++#define BMI_PORT_CFG_AM                         0x00000040
++#define BMI_PORT_STATUS_BSY                     0x80000000
++#define BMI_COUNTERS_EN                         0x80000000
++
++#define BMI_PORT_RFNE_FRWD_DCL4C                0x10000000
++#define BMI_PORT_RFNE_FRWD_RPD                  0x40000000
++#define BMI_RFNE_FDCS_MASK                      0xFF000000
++#define BMI_RFNE_HXS_MASK                       0x000000FF
++
++#define BMI_CMD_MR_LEAC                         0x00200000
++#define BMI_CMD_MR_SLEAC                        0x00100000
++#define BMI_CMD_MR_MA                           0x00080000
++#define BMI_CMD_MR_DEAS                         0x00040000
++#define BMI_CMD_RX_MR_DEF                       (BMI_CMD_MR_LEAC | \
++                                                 BMI_CMD_MR_SLEAC | \
++                                                 BMI_CMD_MR_MA | \
++                                                 BMI_CMD_MR_DEAS)
++#define BMI_CMD_ATTR_ORDER                      0x80000000
++#define BMI_CMD_ATTR_SYNC                       0x02000000
++#define BMI_CMD_ATTR_MODE_MISS_ALLIGN_ADDR_EN   0x00080000
++#define BMI_CMD_ATTR_MACCMD_MASK                0x0000ff00
++#define BMI_CMD_ATTR_MACCMD_OVERRIDE            0x00008000
++#define BMI_CMD_ATTR_MACCMD_SECURED             0x00001000
++#define BMI_CMD_ATTR_MACCMD_SC_MASK             0x00000f00
++
++#define BMI_EXT_BUF_POOL_ID_MASK                0x003F0000
++#define BMI_STATUS_RX_MASK_UNUSED               (uint32_t)(~(FM_PORT_FRM_ERR_DMA                    | \
++                                                             FM_PORT_FRM_ERR_PHYSICAL               | \
++                                                             FM_PORT_FRM_ERR_SIZE                   | \
++                                                             FM_PORT_FRM_ERR_CLS_DISCARD            | \
++                                                             FM_PORT_FRM_ERR_EXTRACTION             | \
++                                                             FM_PORT_FRM_ERR_NO_SCHEME              | \
++                                                             FM_PORT_FRM_ERR_COLOR_RED              | \
++                                                             FM_PORT_FRM_ERR_COLOR_YELLOW           | \
++                                                             FM_PORT_FRM_ERR_ILL_PLCR               | \
++                                                             FM_PORT_FRM_ERR_PLCR_FRAME_LEN         | \
++                                                             FM_PORT_FRM_ERR_PRS_TIMEOUT            | \
++                                                             FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT       | \
++                                                             FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED   | \
++                                                             FM_PORT_FRM_ERR_PRS_HDR_ERR            | \
++                                                             FM_PORT_FRM_ERR_IPRE                   | \
++                                                             FM_PORT_FRM_ERR_IPR_NCSP               | \
++                                                             FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW))
++
++#define BMI_STATUS_OP_MASK_UNUSED               (uint32_t)(BMI_STATUS_RX_MASK_UNUSED &                \
++                                                           ~(FM_PORT_FRM_ERR_LENGTH                 | \
++                                                             FM_PORT_FRM_ERR_NON_FM                 | \
++                                                             FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT))
++
++#define BMI_RATE_LIMIT_EN                       0x80000000
++#define BMI_RATE_LIMIT_BURST_SIZE_GRAN          0x80000000
++#define BMI_RATE_LIMIT_SCALE_BY_2               0x00000001
++#define BMI_RATE_LIMIT_SCALE_BY_4               0x00000002
++#define BMI_RATE_LIMIT_SCALE_BY_8               0x00000003
++
++#define BMI_RX_FIFO_THRESHOLD_BC                0x80000000
++
++#define BMI_PRS_RESULT_HIGH                     0x00000000
++#define BMI_PRS_RESULT_LOW                      0xFFFFFFFF
++
++
++#define RX_ERRS_TO_ENQ                          (FM_PORT_FRM_ERR_DMA                    | \
++                                                 FM_PORT_FRM_ERR_PHYSICAL               | \
++                                                 FM_PORT_FRM_ERR_SIZE                   | \
++                                                 FM_PORT_FRM_ERR_EXTRACTION             | \
++                                                 FM_PORT_FRM_ERR_NO_SCHEME              | \
++                                                 FM_PORT_FRM_ERR_ILL_PLCR               | \
++                                                 FM_PORT_FRM_ERR_PLCR_FRAME_LEN         | \
++                                                 FM_PORT_FRM_ERR_PRS_TIMEOUT            | \
++                                                 FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT       | \
++                                                 FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED   | \
++                                                 FM_PORT_FRM_ERR_PRS_HDR_ERR            | \
++                                                 FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW       | \
++                                                 FM_PORT_FRM_ERR_IPRE)
++
++#define OP_ERRS_TO_ENQ                          (RX_ERRS_TO_ENQ                         | \
++                                                 FM_PORT_FRM_ERR_LENGTH                 | \
++                                                 FM_PORT_FRM_ERR_NON_FM                 | \
++                                                 FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT)
++
++
++#define BMI_RX_FIFO_PRI_ELEVATION_MASK          0x03FF0000
++#define BMI_RX_FIFO_THRESHOLD_MASK              0x000003FF
++#define BMI_TX_FIFO_MIN_FILL_MASK               0x03FF0000
++#define BMI_FIFO_PIPELINE_DEPTH_MASK            0x0000F000
++#define BMI_TX_LOW_COMF_MASK                    0x000003FF
++
++/* shifts */
++#define BMI_PORT_CFG_MS_SEL_SHIFT               16
++#define BMI_DMA_ATTR_IC_CACHE_SHIFT             FMAN_SP_DMA_ATTR_IC_CACHE_SHIFT
++#define BMI_DMA_ATTR_HDR_CACHE_SHIFT            FMAN_SP_DMA_ATTR_HDR_CACHE_SHIFT
++#define BMI_DMA_ATTR_SG_CACHE_SHIFT             FMAN_SP_DMA_ATTR_SG_CACHE_SHIFT
++
++#define BMI_IM_FOF_SHIFT                        28
++#define BMI_PR_PORTID_SHIFT                     24
++
++#define BMI_RX_FIFO_PRI_ELEVATION_SHIFT         16
++#define BMI_RX_FIFO_THRESHOLD_SHIFT             0
++
++#define BMI_RX_FRAME_END_CS_IGNORE_SHIFT        24
++#define BMI_RX_FRAME_END_CUT_SHIFT              16
++
++#define BMI_IC_SIZE_SHIFT                       FMAN_SP_IC_SIZE_SHIFT
++
++#define BMI_INT_BUF_MARG_SHIFT                  28
++
++#define BMI_EXT_BUF_MARG_END_SHIFT              FMAN_SP_EXT_BUF_MARG_END_SHIFT
++
++#define BMI_CMD_ATTR_COLOR_SHIFT                26
++#define BMI_CMD_ATTR_COM_MODE_SHIFT             16
++#define BMI_CMD_ATTR_MACCMD_SHIFT               8
++#define BMI_CMD_ATTR_MACCMD_OVERRIDE_SHIFT      15
++#define BMI_CMD_ATTR_MACCMD_SECURED_SHIFT       12
++#define BMI_CMD_ATTR_MACCMD_SC_SHIFT            8
++
++#define BMI_POOL_DEP_NUM_OF_POOLS_VECTOR_SHIFT  24
++
++#define BMI_TX_FIFO_MIN_FILL_SHIFT              16
++#define BMI_TX_LOW_COMF_SHIFT                   0
++
++#define BMI_PERFORMANCE_TASK_COMP_SHIFT         24
++#define BMI_PERFORMANCE_PORT_COMP_SHIFT         16
++#define BMI_PERFORMANCE_DMA_COMP_SHIFT          12
++#define BMI_PERFORMANCE_FIFO_COMP_SHIFT         0
++
++#define BMI_MAX_BURST_SHIFT                     16
++#define BMI_COUNT_RATE_UNIT_SHIFT               16
++
++/* sizes */
++#define FRAME_END_DATA_SIZE                     16
++#define FRAME_OFFSET_UNITS                      16
++#define MIN_TX_INT_OFFSET                       16
++#define MAX_FRAME_OFFSET                        64
++#define MAX_FIFO_PIPELINE_DEPTH                 8
++#define MAX_PERFORMANCE_TASK_COMP               64
++#define MAX_PERFORMANCE_TX_QUEUE_COMP           8
++#define MAX_PERFORMANCE_RX_QUEUE_COMP           64
++#define MAX_PERFORMANCE_DMA_COMP                16
++#define MAX_NUM_OF_TASKS                        64
++#define MAX_NUM_OF_EXTRA_TASKS                  8
++#define MAX_NUM_OF_DMAS                         16
++#define MAX_NUM_OF_EXTRA_DMAS                   8
++#define MAX_BURST_SIZE                          1024
++#define MIN_NUM_OF_OP_DMAS                      2
++
++
++/**************************************************************************//**
++ @Description       QMI defines
++*//***************************************************************************/
++/* masks */
++#define QMI_PORT_CFG_EN                         0x80000000
++#define QMI_PORT_CFG_EN_COUNTERS                0x10000000
++#define QMI_PORT_STATUS_DEQ_TNUM_BSY            0x80000000
++#define QMI_PORT_STATUS_DEQ_FD_BSY              0x20000000
++
++#define QMI_DEQ_CFG_PREFETCH_NO_TNUM            0x02000000
++#define QMI_DEQ_CFG_PREFETCH_WAITING_TNUM       0
++#define QMI_DEQ_CFG_PREFETCH_1_FRAME            0
++#define QMI_DEQ_CFG_PREFETCH_3_FRAMES           0x01000000
++
++#define QMI_DEQ_CFG_PRI                         0x80000000
++#define QMI_DEQ_CFG_TYPE1                       0x10000000
++#define QMI_DEQ_CFG_TYPE2                       0x20000000
++#define QMI_DEQ_CFG_TYPE3                       0x30000000
++
++#define QMI_DEQ_CFG_SUBPORTAL_MASK              0x1f
++#define QMI_DEQ_CFG_SUBPORTAL_SHIFT             20
++
++/**************************************************************************//**
++ @Description       PARSER defines
++*//***************************************************************************/
++/* masks */
++#define PRS_HDR_ERROR_DIS                       0x00000800
++#define PRS_HDR_SW_PRS_EN                       0x00000400
++#define PRS_CP_OFFSET_MASK                      0x0000000F
++#define PRS_TPID1_MASK                          0xFFFF0000
++#define PRS_TPID2_MASK                          0x0000FFFF
++#define PRS_TPID_DFLT                           0x91009100
++
++#define PRS_HDR_MPLS_LBL_INTER_EN               0x00200000
++#define PRS_HDR_IPV6_ROUTE_HDR_EN               0x00008000
++#define PRS_HDR_PPPOE_MTU_CHECK_EN              0x80000000
++#define PRS_HDR_UDP_PAD_REMOVAL                 0x80000000
++#define PRS_HDR_TCP_PAD_REMOVAL                 0x80000000
++#define PRS_CAC_STOP                            0x00000001
++#define PRS_CAC_ACTIVE                          0x00000100
++
++/* shifts */
++#define PRS_PCTPID_SHIFT                        16
++#define PRS_HDR_MPLS_NEXT_HDR_SHIFT             22
++#define PRS_HDR_ETH_BC_SHIFT                    28
++#define PRS_HDR_ETH_MC_SHIFT                    24
++#define PRS_HDR_VLAN_STACKED_SHIFT              16
++#define PRS_HDR_MPLS_STACKED_SHIFT              16
++#define PRS_HDR_IPV4_1_BC_SHIFT                 28
++#define PRS_HDR_IPV4_1_MC_SHIFT                 24
++#define PRS_HDR_IPV4_2_UC_SHIFT                 20
++#define PRS_HDR_IPV4_2_MC_BC_SHIFT              16
++#define PRS_HDR_IPV6_1_MC_SHIFT                 24
++#define PRS_HDR_IPV6_2_UC_SHIFT                 20
++#define PRS_HDR_IPV6_2_MC_SHIFT                 16
++
++#define PRS_HDR_ETH_BC_MASK                     0x0fffffff
++#define PRS_HDR_ETH_MC_MASK                     0xf0ffffff
++#define PRS_HDR_VLAN_STACKED_MASK               0xfff0ffff
++#define PRS_HDR_MPLS_STACKED_MASK               0xfff0ffff
++#define PRS_HDR_IPV4_1_BC_MASK                  0x0fffffff
++#define PRS_HDR_IPV4_1_MC_MASK                  0xf0ffffff
++#define PRS_HDR_IPV4_2_UC_MASK                  0xff0fffff
++#define PRS_HDR_IPV4_2_MC_BC_MASK               0xfff0ffff
++#define PRS_HDR_IPV6_1_MC_MASK                  0xf0ffffff
++#define PRS_HDR_IPV6_2_UC_MASK                  0xff0fffff
++#define PRS_HDR_IPV6_2_MC_MASK                  0xfff0ffff
++
++/* others */
++#define PRS_HDR_ENTRY_SIZE                      8
++#define DEFAULT_CLS_PLAN_VECTOR                 0xFFFFFFFF
++
++#define IPSEC_SW_PATCH_START                    0x20
++#define SCTP_SW_PATCH_START                     0x4D
++#define DCCP_SW_PATCH_START                     0x41
++
++/**************************************************************************//**
++ @Description       IM defines
++*//***************************************************************************/
++#define BD_R_E                                  0x80000000
++#define BD_L                                    0x08000000
++
++#define BD_RX_CRE                               0x00080000
++#define BD_RX_FTL                               0x00040000
++#define BD_RX_FTS                               0x00020000
++#define BD_RX_OV                                0x00010000
++
++#define BD_RX_ERRORS                            (BD_RX_CRE | BD_RX_FTL | BD_RX_FTS | BD_RX_OV)
++
++#define FM_IM_SIZEOF_BD                         sizeof(t_FmImBd)
++
++#define BD_STATUS_MASK                          0xffff0000
++#define BD_LENGTH_MASK                          0x0000ffff
++
++#define BD_STATUS_AND_LENGTH_SET(bd, val)       WRITE_UINT32(*(volatile uint32_t*)(bd), (val))
++
++#define BD_STATUS_AND_LENGTH(bd)                GET_UINT32(*(volatile uint32_t*)(bd))
++
++#define BD_GET(id)                              &p_FmPort->im.p_BdRing[id]
++
++#define IM_ILEGAL_BD_ID                         0xffff
++
++/* others */
++#define IM_PRAM_ALIGN                           0x100
++
++/* masks */
++#define IM_MODE_GBL                             0x20000000
++#define IM_MODE_BO_MASK                         0x18000000
++#define IM_MODE_BO_SHIFT                        3
++#define IM_MODE_GRC_STP                         0x00800000
++
++#define IM_MODE_SET_BO(val)                     (uint32_t)((val << (31-IM_MODE_BO_SHIFT)) & IM_MODE_BO_MASK)
++
++#define IM_RXQD_BSYINTM                         0x0008
++#define IM_RXQD_RXFINTM                         0x0010
++#define IM_RXQD_FPMEVT_SEL_MASK                 0x0003
++
++#define IM_EV_BSY                               0x40000000
++#define IM_EV_RX                                0x80000000
++
++
++/**************************************************************************//**
++ @Description       Additional defines
++*//***************************************************************************/
++
++typedef struct {
++    t_Handle                    h_FmMuram;
++    t_FmPortImPram              *p_FmPortImPram;
++    uint8_t                     fwExtStructsMemId;
++    uint32_t                    fwExtStructsMemAttr;
++    uint16_t                    bdRingSize;
++    t_FmImBd                    *p_BdRing;
++    t_Handle                    *p_BdShadow;
++    uint16_t                    currBdId;
++    uint16_t                    firstBdOfFrameId;
++
++    /* Rx port parameters */
++    uint8_t                     dataMemId;          /**< Memory partition ID for data buffers */
++    uint32_t                    dataMemAttributes;  /**< Memory attributes for data buffers */
++    t_BufferPoolInfo            rxPool;
++    uint16_t                    mrblr;
++    uint16_t                    rxFrameAccumLength;
++    t_FmPortImRxStoreCallback   *f_RxStore;
++
++    /* Tx port parameters */
++    uint32_t                    txFirstBdStatus;
++    t_FmPortImTxConfCallback    *f_TxConf;
++} t_FmMacIm;
++
++
++typedef struct {
++    struct fman_port_cfg                dfltCfg;
++    uint32_t                            dfltFqid;
++    uint32_t                            confFqid;
++    uint32_t                            errFqid;
++    uintptr_t                           baseAddr;
++    uint8_t                             deqSubPortal;
++    bool                                deqHighPriority;
++    e_FmPortDeqType                     deqType;
++    e_FmPortDeqPrefetchOption           deqPrefetchOption;
++    uint16_t                            deqByteCnt;
++    uint8_t                             cheksumLastBytesIgnore;
++    uint8_t                             cutBytesFromEnd;
++    t_FmBufPoolDepletion                bufPoolDepletion;
++    uint8_t                             pipelineDepth;
++    uint16_t                            fifoLowComfLevel;
++    bool                                frmDiscardOverride;
++    bool                                enRateLimit;
++    t_FmPortRateLimit                   rateLimit;
++    e_FmPortDualRateLimiterScaleDown    rateLimitDivider;
++    bool                                enBufPoolDepletion;
++    uint16_t                            liodnOffset;
++    uint16_t                            liodnBase;
++    t_FmExtPools                        extBufPools;
++    e_FmDmaSwapOption                   dmaSwapData;
++    e_FmDmaCacheOption                  dmaIntContextCacheAttr;
++    e_FmDmaCacheOption                  dmaHeaderCacheAttr;
++    e_FmDmaCacheOption                  dmaScatterGatherCacheAttr;
++    bool                                dmaReadOptimize;
++    bool                                dmaWriteOptimize;
++    uint32_t                            txFifoMinFillLevel;
++    uint32_t                            txFifoLowComfLevel;
++    uint32_t                            rxFifoPriElevationLevel;
++    uint32_t                            rxFifoThreshold;
++    t_FmSpBufMargins                    bufMargins;
++    t_FmSpIntContextDataCopy            intContext;
++    bool                                syncReq;
++    e_FmPortColor                       color;
++    fmPortFrameErrSelect_t              errorsToDiscard;
++    fmPortFrameErrSelect_t              errorsToEnq;
++    bool                                forwardReuseIntContext;
++    t_FmBufferPrefixContent             bufferPrefixContent;
++     t_FmBackupBmPools                   *p_BackupBmPools;
++    bool                                dontReleaseBuf;
++    bool                                setNumOfTasks;
++    bool                                setNumOfOpenDmas;
++    bool                                setSizeOfFifo;
++#if (DPAA_VERSION >= 11)
++    bool                                noScatherGather;
++#endif /* (DPAA_VERSION >= 11) */
++
++#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
++    bool                                bcbWorkaround;
++#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */
++} t_FmPortDriverParam;
++
++
++typedef struct t_FmPortRxPoolsParams
++{
++    uint8_t     numOfPools;
++    uint16_t    secondLargestBufSize;
++    uint16_t    largestBufSize;
++} t_FmPortRxPoolsParams;
++
++typedef struct t_FmPortDsarVars {
++    t_Handle                    *autoResOffsets;
++    t_FmPortDsarTablesSizes     *autoResMaxSizes;
++    uint32_t                    fmbm_tcfg;
++    uint32_t                    fmbm_tcmne;
++    uint32_t                    fmbm_rfne;
++    uint32_t                    fmbm_rfpne;
++    uint32_t                    fmbm_rcfg;
++    bool                        dsarEnabledParser;
++} t_FmPortDsarVars;
++typedef struct {
++    struct fman_port            port;
++    t_Handle                    h_Fm;
++    t_Handle                    h_FmPcd;
++    t_Handle                    h_FmMuram;
++    t_FmRevisionInfo            fmRevInfo;
++    uint8_t                     portId;
++    e_FmPortType                portType;
++    int                         enabled;
++    char                        name[MODULE_NAME_SIZE];
++    uint8_t                     hardwarePortId;
++    uint16_t                    fmClkFreq;
++    t_FmPortQmiRegs             *p_FmPortQmiRegs;
++    u_FmPortBmiRegs             *p_FmPortBmiRegs;
++    t_FmPortPrsRegs             *p_FmPortPrsRegs;
++    fmPcdEngines_t              pcdEngines;
++    uint32_t                    savedBmiNia;
++    uint8_t                     netEnvId;
++    uint32_t                    optArray[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)];
++    uint32_t                    lcvs[FM_PCD_PRS_NUM_OF_HDRS];
++    uint8_t                     privateInfo;
++    uint32_t                    schemesPerPortVector;
++    bool                        useClsPlan;
++    uint8_t                     clsPlanGrpId;
++    t_Handle                    ccTreeId;
++    t_Handle                    completeArg;
++    void                        (*f_Complete)(t_Handle arg);
++    t_FmSpBufferOffsets         bufferOffsets;
++    /* Independent-Mode parameters support */
++    bool                        imEn;
++    t_FmMacIm                   im;
++    volatile bool               lock;
++    t_Handle                    h_Spinlock;
++    t_FmPortExceptionCallback   *f_Exception;
++    t_Handle                    h_App;
++    uint8_t                     internalBufferOffset;
++    uint8_t                     fmanCtrlEventId;
++    uint32_t                    exceptions;
++    bool                        polling;
++    t_FmExtPools                extBufPools;
++    uint32_t                    requiredAction;
++    uint32_t                    savedQmiPnen;
++    uint32_t                    savedBmiFene;
++    uint32_t                    savedBmiFpne;
++    uint32_t                    savedBmiCmne;
++    uint32_t                    savedBmiOfp;
++    uint32_t                    savedNonRxQmiRegsPndn;
++    uint32_t                    origNonRxQmiRegsPndn;
++    int                         savedPrsStartOffset;
++    bool                        includeInPrsStatistics;
++    uint16_t                    maxFrameLength;
++    t_FmFmanCtrl                orFmanCtrl;
++    t_FmPortRsrc                openDmas;
++    t_FmPortRsrc                tasks;
++    t_FmPortRsrc                fifoBufs;
++    t_FmPortRxPoolsParams       rxPoolsParams;
++//    bool                        explicitUserSizeOfFifo;
++    t_Handle                    h_IpReassemblyManip;
++    t_Handle                    h_CapwapReassemblyManip;
++    t_Handle                    h_ReassemblyTree;
++    uint64_t                    fmMuramPhysBaseAddr;
++#if (DPAA_VERSION >= 11)
++    bool                        vspe;
++    uint8_t                     dfltRelativeId;
++    e_FmPortGprFuncType         gprFunc;
++    t_FmPcdCtrlParamsPage       *p_ParamsPage;
++#endif /* (DPAA_VERSION >= 11) */
++    t_FmPortDsarVars            deepSleepVars;
++    t_FmPortDriverParam         *p_FmPortDriverParam;
++} t_FmPort;
++
++
++void FmPortConfigIM (t_FmPort *p_FmPort, t_FmPortParams *p_FmPortParams);
++t_Error FmPortImCheckInitParameters(t_FmPort *p_FmPort);
++
++t_Error FmPortImInit(t_FmPort *p_FmPort);
++void    FmPortImFree(t_FmPort *p_FmPort);
++
++t_Error FmPortImEnable  (t_FmPort *p_FmPort);
++t_Error FmPortImDisable (t_FmPort *p_FmPort);
++t_Error FmPortImRx      (t_FmPort *p_FmPort);
++
++void    FmPortSetMacsecLcv(t_Handle h_FmPort);
++void    FmPortSetMacsecCmd(t_Handle h_FmPort, uint8_t dfltSci);
++
++
++t_Error FM_PORT_SetNumOfOpenDmas(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfOpenDmas);
++t_Error FM_PORT_SetNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks);
++t_Error FM_PORT_SetSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo);
++
++static __inline__ uint8_t * BdBufferGet (t_PhysToVirt *f_PhysToVirt, t_FmImBd *p_Bd)
++{
++    uint64_t    physAddr = (uint64_t)((uint64_t)GET_UINT8(p_Bd->buff.high) << 32);
++    physAddr |= GET_UINT32(p_Bd->buff.low);
++
++    return (uint8_t *)f_PhysToVirt((physAddress_t)(physAddr));
++}
++
++static __inline__ void SET_ADDR(volatile t_FmPhysAddr *fmPhysAddr, uint64_t value)
++{
++    WRITE_UINT8(fmPhysAddr->high,(uint8_t)((value & 0x000000ff00000000LL) >> 32));
++    WRITE_UINT32(fmPhysAddr->low,(uint32_t)value);
++}
++
++static __inline__ void BdBufferSet(t_VirtToPhys *f_VirtToPhys, t_FmImBd *p_Bd, uint8_t *p_Buffer)
++{
++    uint64_t    physAddr = (uint64_t)(f_VirtToPhys(p_Buffer));
++    SET_ADDR(&p_Bd->buff, physAddr);
++}
++
++static __inline__ uint16_t GetNextBdId(t_FmPort *p_FmPort, uint16_t id)
++{
++    if (id < p_FmPort->im.bdRingSize-1)
++        return (uint16_t)(id+1);
++    else
++        return 0;
++}
++
++void FM_PORT_Dsar_DumpRegs(void);
++
++
++#endif /* __FM_PORT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h
+@@ -0,0 +1,494 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**************************************************************************//**
++ @File          fm_port_dsar.h
++
++ @Description   Deep Sleep Auto Response project - common module header file.               
++
++                Author - Eyal Harari
++                
++ @Cautions      See the FMan Controller spec and design document for more information.
++*//***************************************************************************/
++
++#ifndef __FM_PORT_DSAR_H_
++#define __FM_PORT_DSAR_H_
++
++#define DSAR_GETSER_MASK 0xFF0000FF
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(push,1)
++#endif /* defined(__MWERKS__) && ... */ 
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response VLAN-IPv4 Binding Table (for ARP/ICMPv4)
++                Refer to the FMan Controller spec for more details.
++*//***************************************************************************/
++typedef _Packed struct
++{
++        uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */
++        uint16_t vlanId;   /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared                      */
++                                         /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
++        uint16_t reserved;
++} _PackedType t_DsarArpBindingEntry;
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response Address Resolution Protocol Statistics Descriptor
++                Refer to the FMan Controller spec for more details.
++                  0x00 INVAL_CNT Invalid ARP IPv4-Ethernet counter
++                  0x04 ECHO_CNT Echo counter
++                  0x08 CD_CNT Conflict Detection counter
++                  0x0C AR_CNT Auto-Response counter
++                  0x10 RATM_CNT Replies Addressed To Me counter
++                  0x14 UKOP_CNT Unknown Operation counter
++                  0x18 NMTP_CNT Not my TPA counter
++                  0x1C NMVLAN_CNT Not My VLAN counter
++*//***************************************************************************/
++typedef _Packed struct
++{
++    uint32_t invalCnt;        /**< Invalid ARP IPv4-Ethernet counter. */
++    uint32_t echoCnt; /**< Echo counter.                                              */
++    uint32_t cdCnt;           /**< Conflict Detection counter.                */
++    uint32_t arCnt;           /**< Auto-Response counter.                             */
++    uint32_t ratmCnt; /**< Replies Addressed To Me counter.   */
++    uint32_t ukopCnt; /**< Unknown Operation counter.                 */
++    uint32_t nmtpCnt; /**< Not my TPA counter.                                */
++    uint32_t nmVlanCnt; /**< Not My VLAN counter                              */
++} _PackedType t_DsarArpStatistics;
++
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response Address Resolution Protocol Descriptor
++                0x0 0-15 Control bits [0-15]. Bit 15  = CDEN.
++                0x2 0-15 NumOfBindings Number of entries in the binding list.
++                0x4 0-15 BindingsPointer Bindings Pointer. This points to an IPv4-MAC Addresses Bindings list.
++                0x6 0-15
++                0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ARP Descriptors statistics data structure.
++                0xA 0-15
++                0xC 0-15 Reserved Reserved. Must be cleared.
++                0xE 015
++
++*//***************************************************************************/
++typedef _Packed struct
++{
++    uint16_t control;                       /** Control bits [0-15]. Bit 15  = CDEN */
++    uint16_t numOfBindings;                 /**< Number of VLAN-IPv4 */
++    uint32_t p_Bindings;      /**< VLAN-IPv4 Bindings table pointer. */
++    uint32_t p_Statistics;   /**< Statistics Data Structure pointer. */
++    uint32_t reserved1;                     /**< Reserved. */
++} _PackedType t_DsarArpDescriptor;
++
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response VLAN-IPv4 Binding Table (for ARP/ICMPv4)
++                Refer to the FMan Controller spec for more details.
++*//***************************************************************************/
++typedef _Packed struct 
++{
++    uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */
++      uint16_t vlanId;   /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared                      */
++                                         /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
++      uint16_t reserved;
++} _PackedType t_DsarIcmpV4BindingEntry;
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response ICMPv4 Statistics Descriptor
++                Refer to the FMan Controller spec for more details.
++                0x00 INVAL_CNT Invalid ICMPv4 header counter
++                0x04 NMVLAN_CNT Not My VLAN counter
++                0x08 NMIP_CNT Not My IP counter
++                0x0C AR_CNT Auto-Response counter
++                0x10 CSERR_CNT Checksum Error counter
++                0x14 Reserved Reserved
++                0x18 Reserved Reserved
++                0x1C Reserved Reserved
++
++*//***************************************************************************/
++typedef _Packed struct
++{
++    uint32_t invalCnt;        /**< Invalid ICMPv4 Echo counter. */
++    uint32_t nmVlanCnt;       /**< Not My VLAN counter          */
++    uint32_t nmIpCnt; /**< Not My IP counter                */
++    uint32_t arCnt;           /**< Auto-Response counter        */
++    uint32_t cserrCnt;        /**< Checksum Error counter       */
++    uint32_t reserved0;       /**< Reserved                     */
++    uint32_t reserved1;       /**< Reserved                     */
++    uint32_t reserved2; /**< Reserved                     */
++} _PackedType t_DsarIcmpV4Statistics;
++
++
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response ICMPv4 Descriptor
++                0x0 0-15 Control bits [0-15]
++                0x2 0-15 NumOfBindings Number of entries in the binding list.
++                0x4 0-15 BindingsPointer Bindings Pointer. This points to an VLAN-IPv4 Addresses Bindings list.
++                0x6 0-15
++                0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ICMPv4 statistics data structure.
++                0xA 0-15
++                0xC 0-15 Reserved Reserved. Must be cleared.
++                0xE 015
++
++*//***************************************************************************/
++typedef _Packed struct
++{
++    uint16_t control;                       /** Control bits [0-15].                */
++    uint16_t numOfBindings;                 /**< Number of VLAN-IPv4                */
++    uint32_t p_Bindings;      /**< VLAN-IPv4 Bindings table pointer.  */
++    uint32_t p_Statistics;   /**< Statistics Data Structure pointer. */
++    uint32_t reserved1;                     /**< Reserved.                          */
++} _PackedType t_DsarIcmpV4Descriptor;
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response VLAN-IPv4 Binding Table (for ARP/ICMPv4)
++                The 4 left-most bits (15:12) of the VlanId parameter are control flags.
++                Flags[3:1] (VlanId[15:13]): Reserved, should be cleared.
++                Flags[0] (VlanId[12]): Temporary address.
++                \95 0 - Assigned IP address.
++                \95 1- Temporary (tentative) IP address.
++                Refer to the FMan Controller spec for more details.
++*//***************************************************************************/
++typedef _Packed struct 
++{
++    uint32_t ipv6Addr[4];  /*!< 3 * 32 bit IPv4 Address.                                                    */
++      uint16_t resFlags:4;   /*!< reserved flags. should be cleared                                           */
++      uint16_t vlanId:12;    /*!< 12 bits VLAN ID.                                                            */
++                                             /*!< This field should be 0x000 for an entry with no VLAN tag or a null VLAN ID. */
++      uint16_t reserved;
++} _PackedType t_DsarIcmpV6BindingEntry;
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response ICMPv4 Statistics Descriptor
++                Refer to the FMan Controller spec for more details.
++                0x00 INVAL_CNT Invalid ICMPv4 header counter
++                0x04 NMVLAN_CNT Not My VLAN counter
++                0x08 NMIP_CNT Not My IP counter
++                0x0C AR_CNT Auto-Response counter
++                0x10 CSERR_CNT Checksum Error counter
++                0x14 MCAST_CNT Multicast counter
++                0x18 Reserved Reserved
++                0x1C Reserved Reserved
++
++*//***************************************************************************/
++typedef _Packed struct
++{
++    uint32_t invalCnt;        /**< Invalid ICMPv4 Echo counter. */
++    uint32_t nmVlanCnt;       /**< Not My VLAN counter          */
++    uint32_t nmIpCnt; /**< Not My IP counter                */
++    uint32_t arCnt;           /**< Auto-Response counter        */
++    uint32_t reserved1;       /**< Reserved                     */
++    uint32_t reserved2; /**< Reserved                     */
++    uint32_t reserved3;       /**< Reserved                     */
++    uint32_t reserved4; /**< Reserved                     */
++} _PackedType t_DsarIcmpV6Statistics;
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response Neighbor Discovery Statistics Descriptor
++                0x00 INVAL_CNT Invalid Neighbor Discovery message counter
++                0x04 NMVLAN_CNT Not My VLAN counter
++                0x08 NMIP_CNT Not My IP counter
++                0x0C AR_CNT Auto-Response counter
++                0x10 CSERR_CNT Checksum Error counter
++                0x14 USADVERT_CNT Unsolicited Neighbor Advertisements counter
++                0x18 NMMCAST_CNT Not My Multicast group counter
++                0x1C NSLLA_CNT No Source Link-Layer Address counter. Indicates that there was a match on a Target
++                     Address of a packet that its source IP address is a unicast address, but the ICMPv6
++                     Source Link-layer Address option is omitted
++*//***************************************************************************/
++typedef _Packed struct
++{
++    uint32_t invalCnt;          /**< Invalid ICMPv4 Echo counter.                */
++    uint32_t nmVlanCnt;         /**< Not My VLAN counter                         */
++    uint32_t nmIpCnt;   /**< Not My IP counter                                   */
++    uint32_t arCnt;             /**< Auto-Response counter                       */
++    uint32_t reserved1;         /**< Reserved                                    */
++    uint32_t usadvertCnt; /**< Unsolicited Neighbor Advertisements counter */
++    uint32_t nmmcastCnt;  /**< Not My Multicast group counter              */
++    uint32_t nsllaCnt;    /**< No Source Link-Layer Address counter        */
++} _PackedType t_NdStatistics;
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response ICMPv6 Descriptor
++                0x0 0-15 Control bits [0-15]
++                0x2 0-15 NumOfBindings Number of entries in the binding list.
++                0x4 0-15 BindingsPointer Bindings Pointer. This points to an VLAN-IPv4 Addresses Bindings list.
++                0x6 0-15
++                0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ICMPv4 statistics data structure.
++                0xA 0-15
++                0xC 0-15 Reserved Reserved. Must be cleared.
++                0xE 015
++
++*//***************************************************************************/
++typedef _Packed struct
++{
++    uint16_t control;                       /** Control bits [0-15].                */
++    uint16_t numOfBindings;                 /**< Number of VLAN-IPv6                */
++    uint32_t p_Bindings;      /**< VLAN-IPv4 Bindings table pointer.  */
++    uint32_t p_Statistics;   /**< Statistics Data Structure pointer. */
++      uint32_t reserved1;                     /**< Reserved.                          */
++} _PackedType t_DsarIcmpV6Descriptor;
++
++
++/**************************************************************************//**
++ @Description   Internet Control Message Protocol (ICMPv6) Echo message header
++                The fields names are taken from RFC 4443.
++*//***************************************************************************/
++/* 0                   1                   2                   3     */
++/* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1   */
++/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
++/* |     Type      |     Code      |          Checksum             | */
++/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
++/* |           Identifier          |        Sequence Number        | */
++/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
++/* |     Data ...                                                    */
++/* +-+-+-+-+-                                                        */
++typedef _Packed struct
++{
++      uint8_t  type;
++      uint8_t  code;
++      uint16_t checksum;
++      uint16_t identifier;
++      uint16_t sequenceNumber;
++} _PackedType t_IcmpV6EchoHdr;
++
++/**************************************************************************//**
++ @Description   Internet Control Message Protocol (ICMPv6) 
++                Neighbor Solicitation/Advertisement header
++                The fields names are taken from RFC 4861.
++                The R/S/O fields are valid for Neighbor Advertisement only
++*//***************************************************************************/
++/* 0                   1                   2                   3
++ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ * |     Type      |     Code      |          Checksum             |
++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ * |R|S|O|                     Reserved                            |
++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ * |                                                               |
++ * +                                                               +
++ * |                                                               |
++ * +                       Target Address                          +
++ * |                                                               |
++ * +                                                               +
++ * |                                                               |
++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ * |   Options ...
++ * +-+-+-+-+-+-+-+-+-+-+-+-
++ *
++ * Options Format:
++ * 0                   1                   2                   3
++ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ * |     Type      |    Length     |   Link-Layer Address ...      |
++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ * |                  Link-Layer Address                           |
++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++*/
++typedef _Packed struct
++{
++      uint8_t  type;
++      uint8_t  code;
++      uint16_t checksum;
++      uint32_t router:1;
++      uint32_t solicited:1;
++      uint32_t override:1;
++      uint32_t reserved:29;
++      uint32_t targetAddr[4];
++      uint8_t  optionType;
++      uint8_t  optionLength;
++      uint8_t  linkLayerAddr[6];
++} _PackedType t_IcmpV6NdHdr;
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response ICMPv6 Descriptor
++                0x0 0-15 Control bits [0-15]
++                0x2 0-15 NumOfBindings Number of entries in the binding list.
++                0x4 0-15 BindingsPointer Bindings Pointer. This points to an VLAN-IPv4 Addresses Bindings list.
++                0x6 0-15
++                0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ICMPv4 statistics data structure.
++                0xA 0-15
++                0xC 0-15 Reserved Reserved. Must be cleared.
++                0xE 015
++
++*//***************************************************************************/
++typedef _Packed struct
++{
++    uint16_t control;                       /** Control bits [0-15].                    */
++    uint16_t numOfBindings;                 /**< Number of VLAN-IPv6                    */
++    uint32_t p_Bindings;      /**< VLAN-IPv4 Bindings table pointer.      */
++    uint32_t p_Statistics;   /**< Statistics Data Structure pointer.     */
++      uint32_t solicitedAddr;                 /**< Solicited Node Multicast Group Address */
++} _PackedType t_DsarNdDescriptor;
++
++/**************************************************************************//**
++@Description    Deep Sleep Auto Response SNMP OIDs table entry
++                 
++*//***************************************************************************/
++typedef struct {
++    uint16_t oidSize;     /**< Size in octets of the OID. */
++    uint16_t resSize;     /**< Size in octets of the value that is attached to the OID. */
++    uint32_t p_Oid;       /**< Pointer to the OID. OID is encoded in BER but type and length are excluded. */
++    uint32_t resValOrPtr; /**< Value (for up to 4 octets) or pointer to the Value. Encoded in BER. */
++    uint32_t reserved;
++} t_OidsTblEntry;
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response SNMP IPv4 Addresses Table Entry
++                Refer to the FMan Controller spec for more details.
++*//***************************************************************************/
++typedef struct
++{
++    uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */
++    uint16_t vlanId;   /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared                      */
++                       /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
++    uint16_t reserved;
++} t_DsarSnmpIpv4AddrTblEntry;
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response SNMP IPv6 Addresses Table Entry
++                Refer to the FMan Controller spec for more details.
++*//***************************************************************************/
++#pragma pack(push,1)
++typedef struct
++{
++    uint32_t ipv6Addr[4];  /*!< 4 * 32 bit IPv6 Address.                                                     */
++    uint16_t vlanId;       /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared                      */
++                           /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
++    uint16_t reserved;
++} t_DsarSnmpIpv6AddrTblEntry;
++#pragma pack(pop)
++
++/**************************************************************************//**
++@Description    Deep Sleep Auto Response SNMP statistics table
++                 
++*//***************************************************************************/
++typedef struct {
++    uint32_t snmpErrCnt;  /**< Counts SNMP errors (wrong version, BER encoding, format). */
++    uint32_t snmpCommunityErrCnt; /**< Counts messages that were dropped due to insufficient permission. */
++    uint32_t snmpTotalDiscardCnt; /**< Counts any message that was dropped. */
++    uint32_t snmpGetReqCnt; /**< Counts the number of get-request messages */
++    uint32_t snmpGetNextReqCnt; /**< Counts the number of get-next-request messages */
++} t_DsarSnmpStatistics;
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response SNMP Descriptor
++
++*//***************************************************************************/
++typedef struct
++{
++    uint16_t control;                          /**< Control bits [0-15]. */
++    uint16_t maxSnmpMsgLength;                 /**< Maximal allowed SNMP message length. */
++    uint16_t numOfIpv4Addresses;               /**< Number of entries in IPv4 addresses table. */
++    uint16_t numOfIpv6Addresses;               /**< Number of entries in IPv6 addresses table. */
++    uint32_t p_Ipv4AddrTbl; /**< Pointer to IPv4 addresses table. */
++    uint32_t p_Ipv6AddrTbl; /**< Pointer to IPv6 addresses table. */
++    uint32_t p_RdOnlyCommunityStr;             /**< Pointer to the Read Only Community String. */
++    uint32_t p_RdWrCommunityStr;               /**< Pointer to the Read Write Community String. */
++    uint32_t p_OidsTbl;                 /**< Pointer to OIDs table. */
++    uint32_t oidsTblSize;                      /**< Number of entries in OIDs table. */
++    uint32_t p_Statistics;                 /**< Pointer to SNMP statistics table. */
++} t_DsarSnmpDescriptor;
++
++/**************************************************************************//**
++@Description    Deep Sleep Auto Response (Common) Statistics
++                 
++*//***************************************************************************/
++typedef _Packed struct {
++      uint32_t dsarDiscarded;
++      uint32_t dsarErrDiscarded;
++      uint32_t dsarFragDiscarded;
++      uint32_t dsarTunnelDiscarded;
++      uint32_t dsarArpDiscarded;
++      uint32_t dsarIpDiscarded;
++      uint32_t dsarTcpDiscarded;
++      uint32_t dsarUdpDiscarded;
++      uint32_t dsarIcmpV6ChecksumErr; /* ICMPv6 Checksum Error counter */
++      uint32_t dsarIcmpV6OtherType;   /* ICMPv6 'Other' type (not Echo or Neighbor Solicitaion/Advertisement counter */
++      uint32_t dsarIcmpV4OtherType;   /* ICMPv4 'Other' type (not Echo) counter */
++} _PackedType t_ArStatistics;
++
++
++/**************************************************************************//**
++@Description    Deep Sleep Auto Response TCP/UDP port filter table entry
++                 
++*//***************************************************************************/
++typedef _Packed struct {
++      uint32_t        Ports;
++      uint32_t        PortsMask;
++} _PackedType t_PortTblEntry;
++
++
++                                      
++/**************************************************************************//**
++@Description    Deep Sleep Auto Response Common Parameters Descriptor
++                 
++*//***************************************************************************/
++typedef _Packed struct {
++      uint8_t   arTxPort;            /* 0x00 0-7 Auto Response Transmit Port number            */
++      uint8_t   controlBits;         /* 0x00 8-15 Auto Response control bits                   */
++      uint16_t  res1;                /* 0x00 16-31 Reserved                                    */
++      uint32_t  activeHPNIA;         /* 0x04 0-31 Active mode Hardware Parser NIA              */
++      uint16_t  snmpPort;            /* 0x08 0-15 SNMP Port.                                   */
++      uint8_t   macStationAddr[6];   /* 0x08 16-31 and 0x0C 0-31 MAC Station Address           */
++      uint8_t   res2;                            /* 0x10 0-7 Reserved                                                                  */
++      uint8_t   filterControl;       /* 0x10 8-15 Filtering Control Bits.                      */
++      uint16_t   tcpControlPass;         /* 0x10 16-31 TCP control pass flags                                      */
++      uint8_t   ipProtocolTblSize;   /* 0x14 0-7 IP Protocol Table Size.                       */
++      uint8_t   udpPortTblSize;      /* 0x14 8-15 UDP Port Table Size.                         */
++      uint8_t   tcpPortTblSize;      /* 0x14 16-23 TCP Port Table Size.                        */
++      uint8_t   res3;                /* 0x14 24-31 Reserved                                    */
++      uint32_t  p_IpProtocolFiltTbl; /* 0x18 0-31 Pointer to IP Protocol Filter Table          */
++      uint32_t p_UdpPortFiltTbl; /* 0x1C 0-31 Pointer to UDP Port Filter Table          */
++      uint32_t p_TcpPortFiltTbl; /* 0x20 0-31 Pointer to TCP Port Filter Table          */
++      uint32_t res4;                 /* 0x24 Reserved                                          */
++      uint32_t p_ArpDescriptor;     /* 0x28 0-31 ARP Descriptor Pointer.                      */
++      uint32_t p_NdDescriptor;      /* 0x2C 0-31 Neighbor Discovery Descriptor.               */
++      uint32_t p_IcmpV4Descriptor;  /* 0x30 0-31 ICMPv4 Descriptor pointer.                   */
++      uint32_t p_IcmpV6Descriptor;  /* 0x34 0-31 ICMPv6 Descriptor pointer.                   */
++      uint32_t p_SnmpDescriptor;    /* 0x38 0-31 SNMP Descriptor pointer.                     */
++      uint32_t p_ArStats;     /* 0x3C 0-31 Pointer to Auto Response Statistics          */
++} _PackedType t_ArCommonDesc;
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(pop)
++#endif /* defined(__MWERKS__) && ... */ 
++
++/* t_ArCommonDesc.filterControl bits */
++#define       IP_PROT_TBL_PASS_MASK   0x08
++#define UDP_PORT_TBL_PASS_MASK        0x04
++#define TCP_PORT_TBL_PASS_MASK        0x02
++
++/* Offset of TCF flags within TCP packet */
++#define TCP_FLAGS_OFFSET 12
++
++
++#endif /* __FM_PORT_DSAR_H_ */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c
+@@ -0,0 +1,753 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_port_im.c
++
++ @Description   FM Port Independent-Mode ...
++*//***************************************************************************/
++#include "std_ext.h"
++#include "string_ext.h"
++#include "error_ext.h"
++#include "memcpy_ext.h"
++#include "fm_muram_ext.h"
++
++#include "fm_port.h"
++
++
++#define TX_CONF_STATUS_UNSENT 0x1
++
++
++typedef enum e_TxConfType
++{
++     e_TX_CONF_TYPE_CHECK      = 0  /**< check if all the buffers were touched by the muxator, no confirmation callback */
++    ,e_TX_CONF_TYPE_CALLBACK   = 1  /**< confirm to user all the available sent buffers */
++    ,e_TX_CONF_TYPE_FLUSH      = 3  /**< confirm all buffers plus the unsent one with an appropriate status */
++} e_TxConfType;
++
++
++static void ImException(t_Handle h_FmPort, uint32_t event)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    ASSERT_COND(((event & (IM_EV_RX | IM_EV_BSY)) && FmIsMaster(p_FmPort->h_Fm)) ||
++                !FmIsMaster(p_FmPort->h_Fm));
++
++    if (event & IM_EV_RX)
++        FmPortImRx(p_FmPort);
++    if ((event & IM_EV_BSY) && p_FmPort->f_Exception)
++        p_FmPort->f_Exception(p_FmPort->h_App, e_FM_PORT_EXCEPTION_IM_BUSY);
++}
++
++
++static t_Error TxConf(t_FmPort *p_FmPort, e_TxConfType confType)
++{
++    t_Error             retVal = E_BUSY;
++    uint32_t            bdStatus;
++    uint16_t            savedStartBdId, confBdId;
++
++    ASSERT_COND(p_FmPort);
++
++    /*
++    if (confType==e_TX_CONF_TYPE_CHECK)
++        return (WfqEntryIsQueueEmpty(p_FmPort->im.h_WfqEntry) ? E_OK : E_BUSY);
++    */
++
++    confBdId = savedStartBdId = p_FmPort->im.currBdId;
++    bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId));
++
++    /* If R bit is set, we don't enter, or we break.
++       we run till we get to R, or complete the loop */
++    while ((!(bdStatus & BD_R_E) || (confType == e_TX_CONF_TYPE_FLUSH)) && (retVal != E_OK))
++    {
++        if (confType & e_TX_CONF_TYPE_CALLBACK) /* if it is confirmation with user callbacks */
++            BD_STATUS_AND_LENGTH_SET(BD_GET(confBdId), 0);
++
++        /* case 1: R bit is 0 and Length is set -> confirm! */
++        if ((confType & e_TX_CONF_TYPE_CALLBACK) && (bdStatus & BD_LENGTH_MASK))
++        {
++            if (p_FmPort->im.f_TxConf)
++            {
++                if ((confType == e_TX_CONF_TYPE_FLUSH) && (bdStatus & BD_R_E))
++                    p_FmPort->im.f_TxConf(p_FmPort->h_App,
++                                          BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)),
++                                          TX_CONF_STATUS_UNSENT,
++                                          p_FmPort->im.p_BdShadow[confBdId]);
++                else
++                    p_FmPort->im.f_TxConf(p_FmPort->h_App,
++                                          BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)),
++                                          0,
++                                          p_FmPort->im.p_BdShadow[confBdId]);
++            }
++        }
++        /* case 2: R bit is 0 and Length is 0 -> not used yet, nop! */
++
++        confBdId = GetNextBdId(p_FmPort, confBdId);
++        if (confBdId == savedStartBdId)
++            retVal = E_OK;
++        bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId));
++    }
++
++    return retVal;
++}
++
++t_Error FmPortImEnable(t_FmPort *p_FmPort)
++{
++    uint32_t    tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode);
++    WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg & ~IM_MODE_GRC_STP));
++    return E_OK;
++}
++
++t_Error FmPortImDisable(t_FmPort *p_FmPort)
++{
++    uint32_t    tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode);
++    WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg | IM_MODE_GRC_STP));
++    return E_OK;
++}
++
++t_Error FmPortImRx(t_FmPort *p_FmPort)
++{
++    t_Handle                h_CurrUserPriv, h_NewUserPriv;
++    uint32_t                bdStatus;
++    volatile uint8_t        buffPos;
++    uint16_t                length;
++    uint16_t                errors;
++    uint8_t                 *p_CurData, *p_Data;
++    uint32_t                flags;
++
++    ASSERT_COND(p_FmPort);
++
++    flags = XX_LockIntrSpinlock(p_FmPort->h_Spinlock);
++    if (p_FmPort->lock)
++    {
++        XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags);
++        return E_OK;
++    }
++    p_FmPort->lock = TRUE;
++    XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags);
++
++    bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId));
++
++    while (!(bdStatus & BD_R_E)) /* while there is data in the Rx BD */
++    {
++        if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_NewUserPriv)) == NULL)
++        {
++            p_FmPort->lock = FALSE;
++            RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer"));
++        }
++
++        if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID)
++            p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId;
++
++        p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId));
++        h_CurrUserPriv = p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId];
++        length = (uint16_t)((bdStatus & BD_L) ?
++                            ((bdStatus & BD_LENGTH_MASK) - p_FmPort->im.rxFrameAccumLength):
++                            (bdStatus & BD_LENGTH_MASK));
++        p_FmPort->im.rxFrameAccumLength += length;
++
++        /* determine whether buffer is first, last, first and last (single  */
++        /* buffer frame) or middle (not first and not last)                 */
++        buffPos = (uint8_t)((p_FmPort->im.currBdId == p_FmPort->im.firstBdOfFrameId) ?
++                            ((bdStatus & BD_L) ? SINGLE_BUF : FIRST_BUF) :
++                            ((bdStatus & BD_L) ? LAST_BUF : MIDDLE_BUF));
++
++        if (bdStatus & BD_L)
++        {
++            p_FmPort->im.rxFrameAccumLength = 0;
++            p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID;
++        }
++
++        BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data);
++
++        BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), BD_R_E);
++
++        errors = (uint16_t)((bdStatus & BD_RX_ERRORS) >> 16);
++        p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_NewUserPriv;
++
++        p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId);
++        WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.offsetOut, (uint16_t)(p_FmPort->im.currBdId<<4));
++        /* Pass the buffer if one of the conditions is true:
++        - There are no errors
++        - This is a part of a larger frame ( the application has already received some buffers ) */
++        if ((buffPos != SINGLE_BUF) || !errors)
++        {
++            if (p_FmPort->im.f_RxStore(p_FmPort->h_App,
++                                       p_CurData,
++                                       length,
++                                       errors,
++                                       buffPos,
++                                       h_CurrUserPriv) == e_RX_STORE_RESPONSE_PAUSE)
++                break;
++        }
++        else if (p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool,
++                                              p_CurData,
++                                              h_CurrUserPriv))
++        {
++            p_FmPort->lock = FALSE;
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Failed freeing data buffer"));
++        }
++
++        bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId));
++    }
++    p_FmPort->lock = FALSE;
++    return E_OK;
++}
++
++void FmPortConfigIM (t_FmPort *p_FmPort, t_FmPortParams *p_FmPortParams)
++{
++    ASSERT_COND(p_FmPort);
++
++    SANITY_CHECK_RETURN(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    p_FmPort->im.h_FmMuram                      = p_FmPortParams->specificParams.imRxTxParams.h_FmMuram;
++    p_FmPort->p_FmPortDriverParam->liodnOffset  = p_FmPortParams->specificParams.imRxTxParams.liodnOffset;
++    p_FmPort->im.dataMemId                      = p_FmPortParams->specificParams.imRxTxParams.dataMemId;
++    p_FmPort->im.dataMemAttributes              = p_FmPortParams->specificParams.imRxTxParams.dataMemAttributes;
++
++    p_FmPort->im.fwExtStructsMemId              = DEFAULT_PORT_ImfwExtStructsMemId;
++    p_FmPort->im.fwExtStructsMemAttr            = DEFAULT_PORT_ImfwExtStructsMemAttr;
++
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ||
++        (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
++    {
++        p_FmPort->im.rxPool.h_BufferPool    = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.h_BufferPool;
++        p_FmPort->im.rxPool.f_GetBuf        = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_GetBuf;
++        p_FmPort->im.rxPool.f_PutBuf        = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PutBuf;
++        p_FmPort->im.rxPool.bufferSize      = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.bufferSize;
++        p_FmPort->im.rxPool.f_PhysToVirt    = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PhysToVirt;
++        if (!p_FmPort->im.rxPool.f_PhysToVirt)
++            p_FmPort->im.rxPool.f_PhysToVirt = XX_PhysToVirt;
++        p_FmPort->im.rxPool.f_VirtToPhys    = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_VirtToPhys;
++        if (!p_FmPort->im.rxPool.f_VirtToPhys)
++            p_FmPort->im.rxPool.f_VirtToPhys = XX_VirtToPhys;
++        p_FmPort->im.f_RxStore              = p_FmPortParams->specificParams.imRxTxParams.f_RxStore;
++
++        p_FmPort->im.mrblr                  = 0x8000;
++        while (p_FmPort->im.mrblr)
++        {
++            if (p_FmPort->im.rxPool.bufferSize & p_FmPort->im.mrblr)
++                break;
++            p_FmPort->im.mrblr >>= 1;
++        }
++        if (p_FmPort->im.mrblr != p_FmPort->im.rxPool.bufferSize)
++            DBG(WARNING, ("Max-Rx-Buffer-Length set to %d", p_FmPort->im.mrblr));
++        p_FmPort->im.bdRingSize             = DEFAULT_PORT_rxBdRingLength;
++        p_FmPort->exceptions                = DEFAULT_PORT_exception;
++        if (FmIsMaster(p_FmPort->h_Fm))
++            p_FmPort->polling               = FALSE;
++        else
++            p_FmPort->polling               = TRUE;
++        p_FmPort->fmanCtrlEventId           = (uint8_t)NO_IRQ;
++    }
++    else
++    {
++        p_FmPort->im.f_TxConf               = p_FmPortParams->specificParams.imRxTxParams.f_TxConf;
++
++        p_FmPort->im.bdRingSize             = DEFAULT_PORT_txBdRingLength;
++    }
++}
++
++t_Error FmPortImCheckInitParameters(t_FmPort *p_FmPort)
++{
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX) &&
++        (p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) &&
++        (p_FmPort->portType != e_FM_PORT_TYPE_TX) &&
++        (p_FmPort->portType != e_FM_PORT_TYPE_TX_10G))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
++
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ||
++        (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
++    {
++        if (!POWER_OF_2(p_FmPort->im.mrblr))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must be power of 2!!!"));
++        if (p_FmPort->im.mrblr < 256)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must at least 256!!!"));
++        if (p_FmPort->p_FmPortDriverParam->liodnOffset & ~FM_LIODN_OFFSET_MASK)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1));
++    }
++
++    return E_OK;
++}
++
++t_Error FmPortImInit(t_FmPort *p_FmPort)
++{
++    t_FmImBd    *p_Bd=NULL;
++    t_Handle    h_BufContext;
++    uint64_t    tmpPhysBase;
++    uint16_t    log2Num;
++    uint8_t     *p_Data/*, *p_Tmp*/;
++    int         i;
++    t_Error     err;
++    uint16_t    tmpReg16;
++    uint32_t    tmpReg32;
++
++    ASSERT_COND(p_FmPort);
++
++    p_FmPort->im.p_FmPortImPram =
++        (t_FmPortImPram *)FM_MURAM_AllocMem(p_FmPort->im.h_FmMuram, sizeof(t_FmPortImPram), IM_PRAM_ALIGN);
++    if (!p_FmPort->im.p_FmPortImPram)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Parameter-RAM!!!"));
++    WRITE_BLOCK(p_FmPort->im.p_FmPortImPram, 0, sizeof(t_FmPortImPram));
++
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ||
++        (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
++    {
++        p_FmPort->im.p_BdRing =
++            (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize),
++                                       p_FmPort->im.fwExtStructsMemId,
++                                       4);
++        if (!p_FmPort->im.p_BdRing)
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD ring!!!"));
++        IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize));
++
++        p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize));
++        if (!p_FmPort->im.p_BdShadow)
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!"));
++        memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize));
++
++        /* Initialize the Rx-BD ring */
++        for (i=0; i<p_FmPort->im.bdRingSize; i++)
++        {
++            p_Bd = BD_GET(i);
++            BD_STATUS_AND_LENGTH_SET (p_Bd, BD_R_E);
++
++            if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_BufContext)) == NULL)
++                RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer"));
++            BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, p_Bd, p_Data);
++            p_FmPort->im.p_BdShadow[i] = h_BufContext;
++        }
++
++        if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) ||
++            (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE))
++            WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2));
++        else
++            WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2));
++
++        WRITE_UINT32(p_FmPort->im.p_FmPortImPram->rxQdPtr,
++                     (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) -
++                                p_FmPort->fmMuramPhysBaseAddr + 0x20));
++
++        LOG2((uint64_t)p_FmPort->im.mrblr, log2Num);
++        WRITE_UINT16(p_FmPort->im.p_FmPortImPram->mrblr, log2Num);
++
++        /* Initialize Rx QD */
++        tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing));
++        SET_ADDR(&p_FmPort->im.p_FmPortImPram->rxQd.bdRingBase, tmpPhysBase);
++        WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize));
++
++        /* Update the IM PRAM address in the BMI */
++        WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfqid,
++                     (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) -
++                                p_FmPort->fmMuramPhysBaseAddr));
++        if (!p_FmPort->polling || p_FmPort->exceptions)
++        {
++            /* Allocate, configure and register interrupts */
++            err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId);
++            if (err)
++                RETURN_ERROR(MAJOR, err, NO_MSG);
++
++            ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK));
++            tmpReg16 = (uint16_t)(p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK);
++            tmpReg32 = 0;
++
++            if (p_FmPort->exceptions & IM_EV_BSY)
++            {
++                tmpReg16 |= IM_RXQD_BSYINTM;
++                tmpReg32 |= IM_EV_BSY;
++            }
++            if (!p_FmPort->polling)
++            {
++                tmpReg16 |= IM_RXQD_RXFINTM;
++                tmpReg32 |= IM_EV_RX;
++            }
++            WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16);
++
++            FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException , (t_Handle)p_FmPort);
++
++            FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32);
++        }
++        else
++            p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ;
++    }
++    else
++    {
++        p_FmPort->im.p_BdRing = (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize), p_FmPort->im.fwExtStructsMemId, 4);
++        if (!p_FmPort->im.p_BdRing)
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Tx BD ring!!!"));
++        IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize));
++
++        p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize));
++        if (!p_FmPort->im.p_BdShadow)
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!"));
++        memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize));
++        p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID;
++
++        if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) ||
++            (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE))
++            WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2));
++        else
++            WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2));
++
++        WRITE_UINT32(p_FmPort->im.p_FmPortImPram->txQdPtr,
++                     (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) -
++                                p_FmPort->fmMuramPhysBaseAddr + 0x40));
++
++        /* Initialize Tx QD */
++        tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing));
++        SET_ADDR(&p_FmPort->im.p_FmPortImPram->txQd.bdRingBase, tmpPhysBase);
++        WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize));
++
++        /* Update the IM PRAM address in the BMI */
++        WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfqid,
++                     (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) -
++                                p_FmPort->fmMuramPhysBaseAddr));
++    }
++
++
++    return E_OK;
++}
++
++void FmPortImFree(t_FmPort *p_FmPort)
++{
++    uint32_t    bdStatus;
++    uint8_t     *p_CurData;
++
++    ASSERT_COND(p_FmPort);
++    ASSERT_COND(p_FmPort->im.p_FmPortImPram);
++
++    if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ||
++        (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
++    {
++        if (!p_FmPort->polling || p_FmPort->exceptions)
++        {
++            /* Deallocate and unregister interrupts */
++            FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0);
++
++            FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId);
++
++            WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0);
++
++            FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId);
++        }
++        /* Try first clean what has received */
++        FmPortImRx(p_FmPort);
++
++        /* Now, get rid of the the empty buffer! */
++        bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId));
++
++        while (bdStatus & BD_R_E) /* while there is data in the Rx BD */
++        {
++            p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId));
++
++            BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), NULL);
++            BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), 0);
++
++            p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool,
++                                         p_CurData,
++                                         p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]);
++
++            p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId);
++            bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId));
++        }
++    }
++    else
++        TxConf(p_FmPort, e_TX_CONF_TYPE_FLUSH);
++
++    FM_MURAM_FreeMem(p_FmPort->im.h_FmMuram, p_FmPort->im.p_FmPortImPram);
++
++    if (p_FmPort->im.p_BdShadow)
++        XX_Free(p_FmPort->im.p_BdShadow);
++
++    if (p_FmPort->im.p_BdRing)
++        XX_FreeSmart(p_FmPort->im.p_BdRing);
++}
++
++
++t_Error FM_PORT_ConfigIMMaxRxBufLength(t_Handle h_FmPort, uint16_t newVal)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    p_FmPort->im.mrblr = newVal;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigIMRxBdRingLength(t_Handle h_FmPort, uint16_t newVal)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    p_FmPort->im.bdRingSize = newVal;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigIMTxBdRingLength(t_Handle h_FmPort, uint16_t newVal)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    p_FmPort->im.bdRingSize = newVal;
++
++    return E_OK;
++}
++
++t_Error  FM_PORT_ConfigIMFmanCtrlExternalStructsMemory(t_Handle h_FmPort,
++                                                       uint8_t  memId,
++                                                       uint32_t memAttributes)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    p_FmPort->im.fwExtStructsMemId              = memId;
++    p_FmPort->im.fwExtStructsMemAttr            = memAttributes;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_ConfigIMPolling(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available for Rx ports only"));
++
++    if (!FmIsMaster(p_FmPort->h_Fm))
++        RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available on master-partition only;"
++                                                  "in guest-partitions, IM is always in polling!"));
++
++    p_FmPort->polling = TRUE;
++
++    return E_OK;
++}
++
++t_Error FM_PORT_SetIMExceptions(t_Handle h_FmPort, e_FmPortExceptions exception, bool enable)
++{
++    t_FmPort    *p_FmPort = (t_FmPort*)h_FmPort;
++    t_Error     err;
++    uint16_t    tmpReg16;
++    uint32_t    tmpReg32;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    if (exception == e_FM_PORT_EXCEPTION_IM_BUSY)
++    {
++        if (enable)
++        {
++            p_FmPort->exceptions |= IM_EV_BSY;
++            if (p_FmPort->fmanCtrlEventId == (uint8_t)NO_IRQ)
++            {
++                /* Allocate, configure and register interrupts */
++                err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId);
++                if (err)
++                    RETURN_ERROR(MAJOR, err, NO_MSG);
++                ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK));
++
++                FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException, (t_Handle)p_FmPort);
++                tmpReg16 = (uint16_t)((p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK) | IM_RXQD_BSYINTM);
++                tmpReg32 = IM_EV_BSY;
++            }
++            else
++            {
++                tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) | IM_RXQD_BSYINTM);
++                tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) | IM_EV_BSY;
++            }
++
++            WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16);
++            FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32);
++        }
++        else
++        {
++            p_FmPort->exceptions &= ~IM_EV_BSY;
++            if (!p_FmPort->exceptions && p_FmPort->polling)
++            {
++                FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId);
++                FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId);
++                FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0);
++                WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0);
++                p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ;
++            }
++            else
++            {
++                tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) & ~IM_RXQD_BSYINTM);
++                WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16);
++                tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) & ~IM_EV_BSY;
++                FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32);
++            }
++        }
++    }
++    else
++        RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("Invalid exception."));
++
++    return E_OK;
++}
++
++t_Error  FM_PORT_ImTx( t_Handle               h_FmPort,
++                       uint8_t                *p_Data,
++                       uint16_t               length,
++                       bool                   lastBuffer,
++                       t_Handle               h_BufContext)
++{
++    t_FmPort            *p_FmPort = (t_FmPort*)h_FmPort;
++    uint16_t            nextBdId;
++    uint32_t            bdStatus, nextBdStatus;
++    bool                firstBuffer;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId));
++    nextBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId);
++    nextBdStatus = BD_STATUS_AND_LENGTH(BD_GET(nextBdId));
++
++    if (!(bdStatus & BD_R_E) && !(nextBdStatus & BD_R_E))
++    {
++        /* Confirm the current BD - BD is available */
++        if ((bdStatus & BD_LENGTH_MASK) && (p_FmPort->im.f_TxConf))
++            p_FmPort->im.f_TxConf (p_FmPort->h_App,
++                                   BdBufferGet(XX_PhysToVirt, BD_GET(p_FmPort->im.currBdId)),
++                                   0,
++                                   p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]);
++
++        bdStatus = length;
++
++        /* if this is the first BD of a frame */
++        if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID)
++        {
++            firstBuffer = TRUE;
++            p_FmPort->im.txFirstBdStatus = (bdStatus | BD_R_E);
++
++            if (!lastBuffer)
++                p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId;
++        }
++        else
++            firstBuffer = FALSE;
++
++        BdBufferSet(XX_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data);
++        p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_BufContext;
++
++        /* deal with last */
++        if (lastBuffer)
++        {
++            /* if single buffer frame */
++            if (firstBuffer)
++                BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), p_FmPort->im.txFirstBdStatus | BD_L);
++            else
++            {
++                /* Set the last BD of the frame */
++                BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), (bdStatus | BD_R_E | BD_L));
++                /* Set the first BD of the frame */
++                BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.firstBdOfFrameId), p_FmPort->im.txFirstBdStatus);
++                p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID;
++            }
++            WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.offsetIn, (uint16_t)(GetNextBdId(p_FmPort, p_FmPort->im.currBdId)<<4));
++        }
++        else if (!firstBuffer) /* mid frame buffer */
++            BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), bdStatus | BD_R_E);
++
++        p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId);
++    }
++    else
++    {
++        /* Discard current frame. Return error.   */
++        if (p_FmPort->im.firstBdOfFrameId != IM_ILEGAL_BD_ID)
++        {
++            /* Error:    No free BD */
++            /* Response: Discard current frame. Return error.   */
++            uint16_t   cleanBdId = p_FmPort->im.firstBdOfFrameId;
++
++            ASSERT_COND(p_FmPort->im.firstBdOfFrameId != p_FmPort->im.currBdId);
++
++            /* Since firstInFrame is not NULL, one buffer at least has already been
++               inserted into the BD ring. Using do-while covers the situation of a
++               frame spanned throughout the whole Tx BD ring (p_CleanBd is incremented
++               prior to testing whether or not it's equal to TxBd). */
++            do
++            {
++                BD_STATUS_AND_LENGTH_SET(BD_GET(cleanBdId), 0);
++                /* Advance BD pointer */
++                cleanBdId = GetNextBdId(p_FmPort, cleanBdId);
++            } while (cleanBdId != p_FmPort->im.currBdId);
++
++            p_FmPort->im.currBdId = cleanBdId;
++            p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID;
++        }
++
++        return ERROR_CODE(E_FULL);
++    }
++
++    return E_OK;
++}
++
++void FM_PORT_ImTxConf(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN(p_FmPort->imEn, E_INVALID_STATE);
++    SANITY_CHECK_RETURN(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    TxConf(p_FmPort, e_TX_CONF_TYPE_CALLBACK);
++}
++
++t_Error  FM_PORT_ImRx(t_Handle h_FmPort)
++{
++    t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
++
++    return FmPortImRx(p_FmPort);
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c
+@@ -0,0 +1,1568 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#include "common/general.h"
++
++#include "fman_common.h"
++#include "fsl_fman_port.h"
++
++
++/* problem Eyal: the following should not be here*/
++#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME        0x00000028
++
++static uint32_t get_no_pcd_nia_bmi_ac_enc_frame(struct fman_port_cfg *cfg)
++{
++    if (cfg->errata_A006675)
++        return NIA_ENG_FM_CTL |
++            NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME;
++    else
++        return NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME;
++}
++
++static int init_bmi_rx(struct fman_port *port,
++        struct fman_port_cfg *cfg,
++        struct fman_port_params *params)
++{
++    struct fman_port_rx_bmi_regs *regs = &port->bmi_regs->rx;
++    uint32_t tmp;
++
++    /* Rx Configuration register */
++    tmp = 0;
++    if (port->im_en)
++        tmp |= BMI_PORT_CFG_IM;
++    else if (cfg->discard_override)
++        tmp |= BMI_PORT_CFG_FDOVR;
++    iowrite32be(tmp, &regs->fmbm_rcfg);
++
++    /* DMA attributes */
++    tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT;
++    if (cfg->dma_ic_stash_on)
++        tmp |= BMI_DMA_ATTR_IC_STASH_ON;
++    if (cfg->dma_header_stash_on)
++        tmp |= BMI_DMA_ATTR_HDR_STASH_ON;
++    if (cfg->dma_sg_stash_on)
++        tmp |= BMI_DMA_ATTR_SG_STASH_ON;
++    if (cfg->dma_write_optimize)
++        tmp |= BMI_DMA_ATTR_WRITE_OPTIMIZE;
++    iowrite32be(tmp, &regs->fmbm_rda);
++
++    /* Rx FIFO parameters */
++    tmp = (cfg->rx_pri_elevation / FMAN_PORT_BMI_FIFO_UNITS - 1) <<
++            BMI_RX_FIFO_PRI_ELEVATION_SHIFT;
++    tmp |= cfg->rx_fifo_thr / FMAN_PORT_BMI_FIFO_UNITS - 1;
++    iowrite32be(tmp, &regs->fmbm_rfp);
++
++    if (cfg->excessive_threshold_register)
++        /* always allow access to the extra resources */
++        iowrite32be(BMI_RX_FIFO_THRESHOLD_ETHE, &regs->fmbm_reth);
++
++    /* Frame end data */
++    tmp = (uint32_t)cfg->checksum_bytes_ignore <<
++            BMI_RX_FRAME_END_CS_IGNORE_SHIFT;
++    tmp |= (uint32_t)cfg->rx_cut_end_bytes <<
++            BMI_RX_FRAME_END_CUT_SHIFT;
++    if (cfg->errata_A006320)
++        tmp &= 0xffe0ffff;
++    iowrite32be(tmp, &regs->fmbm_rfed);
++
++    /* Internal context parameters */
++    tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
++            BMI_IC_TO_EXT_SHIFT;
++    tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
++            BMI_IC_FROM_INT_SHIFT;
++    tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS;
++    iowrite32be(tmp, &regs->fmbm_ricp);
++
++    /* Internal buffer offset */
++    tmp = ((uint32_t)cfg->int_buf_start_margin / FMAN_PORT_IC_OFFSET_UNITS)
++            << BMI_INT_BUF_MARG_SHIFT;
++    iowrite32be(tmp, &regs->fmbm_rim);
++
++    /* External buffer margins */
++    if (!port->im_en)
++    {
++        tmp = (uint32_t)cfg->ext_buf_start_margin <<
++                BMI_EXT_BUF_MARG_START_SHIFT;
++        tmp |= (uint32_t)cfg->ext_buf_end_margin;
++        if (cfg->fmbm_rebm_has_sgd && cfg->no_scatter_gather)
++            tmp |= BMI_SG_DISABLE;
++        iowrite32be(tmp, &regs->fmbm_rebm);
++    }
++
++    /* Frame attributes */
++    tmp = BMI_CMD_RX_MR_DEF;
++    if (!port->im_en)
++    {
++        tmp |= BMI_CMD_ATTR_ORDER;
++        tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT;
++        if (cfg->sync_req)
++            tmp |= BMI_CMD_ATTR_SYNC;
++    }
++    iowrite32be(tmp, &regs->fmbm_rfca);
++
++    /* NIA */
++    if (port->im_en)
++        tmp = NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_RX;
++    else
++    {
++        tmp = (uint32_t)cfg->rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT;
++        tmp |= get_no_pcd_nia_bmi_ac_enc_frame(cfg);
++    }
++    iowrite32be(tmp, &regs->fmbm_rfne);
++
++    /* Enqueue NIA */
++    iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, &regs->fmbm_rfene);
++
++    /* Default/error queues */
++    if (!port->im_en)
++    {
++        iowrite32be((params->dflt_fqid & 0x00FFFFFF), &regs->fmbm_rfqid);
++        iowrite32be((params->err_fqid & 0x00FFFFFF), &regs->fmbm_refqid);
++    }
++
++    /* Discard/error masks */
++    iowrite32be(params->discard_mask, &regs->fmbm_rfsdm);
++    iowrite32be(params->err_mask, &regs->fmbm_rfsem);
++
++    /* Statistics counters */
++    tmp = 0;
++    if (cfg->stats_counters_enable)
++        tmp = BMI_COUNTERS_EN;
++    iowrite32be(tmp, &regs->fmbm_rstc);
++
++    /* Performance counters */
++    fman_port_set_perf_cnt_params(port, &cfg->perf_cnt_params);
++    tmp = 0;
++    if (cfg->perf_counters_enable)
++        tmp = BMI_COUNTERS_EN;
++    iowrite32be(tmp, &regs->fmbm_rpc);
++
++    return 0;
++}
++
++static int init_bmi_tx(struct fman_port *port,
++        struct fman_port_cfg *cfg,
++        struct fman_port_params *params)
++{
++    struct fman_port_tx_bmi_regs *regs = &port->bmi_regs->tx;
++    uint32_t tmp;
++
++    /* Tx Configuration register */
++    tmp = 0;
++    if (port->im_en)
++        tmp |= BMI_PORT_CFG_IM;
++    iowrite32be(tmp, &regs->fmbm_tcfg);
++
++    /* DMA attributes */
++    tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT;
++    if (cfg->dma_ic_stash_on)
++        tmp |= BMI_DMA_ATTR_IC_STASH_ON;
++    if (cfg->dma_header_stash_on)
++        tmp |= BMI_DMA_ATTR_HDR_STASH_ON;
++    if (cfg->dma_sg_stash_on)
++        tmp |= BMI_DMA_ATTR_SG_STASH_ON;
++    iowrite32be(tmp, &regs->fmbm_tda);
++
++    /* Tx FIFO parameters */
++    tmp = (cfg->tx_fifo_min_level / FMAN_PORT_BMI_FIFO_UNITS) <<
++            BMI_TX_FIFO_MIN_FILL_SHIFT;
++    tmp |= ((uint32_t)cfg->tx_fifo_deq_pipeline_depth - 1) <<
++            BMI_FIFO_PIPELINE_DEPTH_SHIFT;
++    tmp |= (uint32_t)(cfg->tx_fifo_low_comf_level /
++            FMAN_PORT_BMI_FIFO_UNITS - 1);
++    iowrite32be(tmp, &regs->fmbm_tfp);
++
++    /* Frame end data */
++    tmp = (uint32_t)cfg->checksum_bytes_ignore <<
++            BMI_FRAME_END_CS_IGNORE_SHIFT;
++    iowrite32be(tmp, &regs->fmbm_tfed);
++
++    /* Internal context parameters */
++    if (!port->im_en)
++    {
++        tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
++                BMI_IC_TO_EXT_SHIFT;
++        tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
++                BMI_IC_FROM_INT_SHIFT;
++        tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS;
++        iowrite32be(tmp, &regs->fmbm_ticp);
++    }
++    /* Frame attributes */
++    tmp = BMI_CMD_TX_MR_DEF;
++    if (port->im_en)
++        tmp |= BMI_CMD_MR_DEAS;
++    else
++    {
++        tmp |= BMI_CMD_ATTR_ORDER;
++        tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT;
++    }
++    iowrite32be(tmp, &regs->fmbm_tfca);
++
++    /* Dequeue NIA + enqueue NIA */
++    if (port->im_en)
++    {
++        iowrite32be(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_TX, &regs->fmbm_tfdne);
++        iowrite32be(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_TX, &regs->fmbm_tfene);
++    }
++    else
++    {
++        iowrite32be(NIA_ENG_QMI_DEQ, &regs->fmbm_tfdne);
++        iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, &regs->fmbm_tfene);
++        if (cfg->fmbm_tfne_has_features)
++            iowrite32be(!params->dflt_fqid ?
++                BMI_EBD_EN | NIA_BMI_AC_FETCH_ALL_FRAME :
++                NIA_BMI_AC_FETCH_ALL_FRAME, &regs->fmbm_tfne);
++        if (!params->dflt_fqid && params->dont_release_buf)
++        {
++            iowrite32be(0x00FFFFFF, &regs->fmbm_tcfqid);
++            iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE, &regs->fmbm_tfene);
++            if (cfg->fmbm_tfne_has_features)
++                iowrite32be(ioread32be(&regs->fmbm_tfne) & ~BMI_EBD_EN, &regs->fmbm_tfne);
++        }
++    }
++
++    /* Confirmation/error queues */
++    if (!port->im_en)
++    {
++        if (params->dflt_fqid || !params->dont_release_buf)
++            iowrite32be(params->dflt_fqid & 0x00FFFFFF, &regs->fmbm_tcfqid);
++        iowrite32be((params->err_fqid & 0x00FFFFFF), &regs->fmbm_tefqid);
++    }
++    /* Statistics counters */
++    tmp = 0;
++    if (cfg->stats_counters_enable)
++        tmp = BMI_COUNTERS_EN;
++    iowrite32be(tmp, &regs->fmbm_tstc);
++
++    /* Performance counters */
++    fman_port_set_perf_cnt_params(port, &cfg->perf_cnt_params);
++    tmp = 0;
++    if (cfg->perf_counters_enable)
++        tmp = BMI_COUNTERS_EN;
++    iowrite32be(tmp, &regs->fmbm_tpc);
++
++    return 0;
++}
++
++static int init_bmi_oh(struct fman_port *port,
++        struct fman_port_cfg *cfg,
++        struct fman_port_params *params)
++{
++    struct fman_port_oh_bmi_regs *regs = &port->bmi_regs->oh;
++    uint32_t tmp;
++
++    /* OP Configuration register */
++    tmp = 0;
++    if (cfg->discard_override)
++        tmp |= BMI_PORT_CFG_FDOVR;
++    iowrite32be(tmp, &regs->fmbm_ocfg);
++
++    /* DMA attributes */
++    tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT;
++    if (cfg->dma_ic_stash_on)
++        tmp |= BMI_DMA_ATTR_IC_STASH_ON;
++    if (cfg->dma_header_stash_on)
++        tmp |= BMI_DMA_ATTR_HDR_STASH_ON;
++    if (cfg->dma_sg_stash_on)
++        tmp |= BMI_DMA_ATTR_SG_STASH_ON;
++    if (cfg->dma_write_optimize)
++        tmp |= BMI_DMA_ATTR_WRITE_OPTIMIZE;
++    iowrite32be(tmp, &regs->fmbm_oda);
++
++    /* Tx FIFO parameters */
++    tmp = ((uint32_t)cfg->tx_fifo_deq_pipeline_depth - 1) <<
++            BMI_FIFO_PIPELINE_DEPTH_SHIFT;
++    iowrite32be(tmp, &regs->fmbm_ofp);
++
++    /* Internal context parameters */
++    tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
++            BMI_IC_TO_EXT_SHIFT;
++    tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
++            BMI_IC_FROM_INT_SHIFT;
++    tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS;
++    iowrite32be(tmp, &regs->fmbm_oicp);
++
++    /* Frame attributes */
++    tmp = BMI_CMD_OP_MR_DEF;
++    tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT;
++    if (cfg->sync_req)
++        tmp |= BMI_CMD_ATTR_SYNC;
++    if (port->type == E_FMAN_PORT_TYPE_OP)
++        tmp |= BMI_CMD_ATTR_ORDER;
++    iowrite32be(tmp, &regs->fmbm_ofca);
++
++    /* Internal buffer offset */
++    tmp = ((uint32_t)cfg->int_buf_start_margin / FMAN_PORT_IC_OFFSET_UNITS)
++            << BMI_INT_BUF_MARG_SHIFT;
++    iowrite32be(tmp, &regs->fmbm_oim);
++
++    /* Dequeue NIA */
++    iowrite32be(NIA_ENG_QMI_DEQ, &regs->fmbm_ofdne);
++
++    /* NIA and Enqueue NIA */
++    if (port->type == E_FMAN_PORT_TYPE_HC) {
++        iowrite32be(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_HC,
++                &regs->fmbm_ofne);
++        iowrite32be(NIA_ENG_QMI_ENQ, &regs->fmbm_ofene);
++    } else {
++        iowrite32be(get_no_pcd_nia_bmi_ac_enc_frame(cfg),
++                &regs->fmbm_ofne);
++        iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR,
++                &regs->fmbm_ofene);
++    }
++
++    /* Default/error queues */
++    iowrite32be((params->dflt_fqid & 0x00FFFFFF), &regs->fmbm_ofqid);
++    iowrite32be((params->err_fqid & 0x00FFFFFF), &regs->fmbm_oefqid);
++
++    /* Discard/error masks */
++    if (port->type == E_FMAN_PORT_TYPE_OP) {
++        iowrite32be(params->discard_mask, &regs->fmbm_ofsdm);
++        iowrite32be(params->err_mask, &regs->fmbm_ofsem);
++    }
++
++    /* Statistics counters */
++    tmp = 0;
++    if (cfg->stats_counters_enable)
++        tmp = BMI_COUNTERS_EN;
++    iowrite32be(tmp, &regs->fmbm_ostc);
++
++    /* Performance counters */
++    fman_port_set_perf_cnt_params(port, &cfg->perf_cnt_params);
++    tmp = 0;
++    if (cfg->perf_counters_enable)
++        tmp = BMI_COUNTERS_EN;
++    iowrite32be(tmp, &regs->fmbm_opc);
++
++    return 0;
++}
++
++static int init_qmi(struct fman_port *port,
++        struct fman_port_cfg *cfg,
++        struct fman_port_params *params)
++{
++    struct fman_port_qmi_regs *regs = port->qmi_regs;
++    uint32_t tmp;
++
++    tmp = 0;
++    if (cfg->queue_counters_enable)
++        tmp |= QMI_PORT_CFG_EN_COUNTERS;
++    iowrite32be(tmp, &regs->fmqm_pnc);
++
++    /* Rx port configuration */
++    if ((port->type == E_FMAN_PORT_TYPE_RX) ||
++            (port->type == E_FMAN_PORT_TYPE_RX_10G)) {
++        /* Enqueue NIA */
++        iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_RELEASE, &regs->fmqm_pnen);
++        return 0;
++    }
++
++    /* Continue with Tx and O/H port configuration */
++    if ((port->type == E_FMAN_PORT_TYPE_TX) ||
++            (port->type == E_FMAN_PORT_TYPE_TX_10G)) {
++        /* Enqueue NIA */
++        iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE,
++                &regs->fmqm_pnen);
++        /* Dequeue NIA */
++        iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX, &regs->fmqm_pndn);
++    } else {
++        /* Enqueue NIA */
++        iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_RELEASE, &regs->fmqm_pnen);
++        /* Dequeue NIA */
++        iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_FETCH, &regs->fmqm_pndn);
++    }
++
++    /* Dequeue Configuration register */
++    tmp = 0;
++    if (cfg->deq_high_pri)
++        tmp |= QMI_DEQ_CFG_PRI;
++
++    switch (cfg->deq_type) {
++    case E_FMAN_PORT_DEQ_BY_PRI:
++        tmp |= QMI_DEQ_CFG_TYPE1;
++        break;
++    case E_FMAN_PORT_DEQ_ACTIVE_FQ:
++        tmp |= QMI_DEQ_CFG_TYPE2;
++        break;
++    case E_FMAN_PORT_DEQ_ACTIVE_FQ_NO_ICS:
++        tmp |= QMI_DEQ_CFG_TYPE3;
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    if (cfg->qmi_deq_options_support) {
++        if ((port->type == E_FMAN_PORT_TYPE_HC) &&
++            (cfg->deq_prefetch_opt != E_FMAN_PORT_DEQ_NO_PREFETCH))
++            return -EINVAL;
++
++        switch (cfg->deq_prefetch_opt) {
++        case E_FMAN_PORT_DEQ_NO_PREFETCH:
++            break;
++        case E_FMAN_PORT_DEQ_PART_PREFETCH:
++            tmp |= QMI_DEQ_CFG_PREFETCH_PARTIAL;
++            break;
++        case E_FMAN_PORT_DEQ_FULL_PREFETCH:
++            tmp |= QMI_DEQ_CFG_PREFETCH_FULL;
++            break;
++        default:
++            return -EINVAL;
++        }
++    }
++    tmp |= (uint32_t)(params->deq_sp & QMI_DEQ_CFG_SP_MASK) <<
++            QMI_DEQ_CFG_SP_SHIFT;
++    tmp |= cfg->deq_byte_cnt;
++    iowrite32be(tmp, &regs->fmqm_pndc);
++
++    return 0;
++}
++
++static void get_rx_stats_reg(struct fman_port *port,
++        enum fman_port_stats_counters counter,
++        uint32_t **stats_reg)
++{
++    struct fman_port_rx_bmi_regs *regs = &port->bmi_regs->rx;
++
++    switch (counter) {
++    case E_FMAN_PORT_STATS_CNT_FRAME:
++        *stats_reg = &regs->fmbm_rfrc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_DISCARD:
++        *stats_reg = &regs->fmbm_rfdc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_DEALLOC_BUF:
++        *stats_reg = &regs->fmbm_rbdc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_RX_BAD_FRAME:
++        *stats_reg = &regs->fmbm_rfbc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_RX_LARGE_FRAME:
++        *stats_reg = &regs->fmbm_rlfc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_RX_OUT_OF_BUF:
++        *stats_reg = &regs->fmbm_rodc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_FILTERED_FRAME:
++        *stats_reg = &regs->fmbm_rffc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_DMA_ERR:
++        *stats_reg = &regs->fmbm_rfldec;
++        break;
++    default:
++        *stats_reg = NULL;
++    }
++}
++
++static void get_tx_stats_reg(struct fman_port *port,
++        enum fman_port_stats_counters counter,
++        uint32_t **stats_reg)
++{
++    struct fman_port_tx_bmi_regs *regs = &port->bmi_regs->tx;
++
++    switch (counter) {
++    case E_FMAN_PORT_STATS_CNT_FRAME:
++        *stats_reg = &regs->fmbm_tfrc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_DISCARD:
++        *stats_reg = &regs->fmbm_tfdc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_DEALLOC_BUF:
++        *stats_reg = &regs->fmbm_tbdc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_LEN_ERR:
++        *stats_reg = &regs->fmbm_tfledc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT:
++        *stats_reg = &regs->fmbm_tfufdc;
++        break;
++    default:
++        *stats_reg = NULL;
++    }
++}
++
++static void get_oh_stats_reg(struct fman_port *port,
++        enum fman_port_stats_counters counter,
++        uint32_t **stats_reg)
++{
++    struct fman_port_oh_bmi_regs *regs = &port->bmi_regs->oh;
++
++    switch (counter) {
++    case E_FMAN_PORT_STATS_CNT_FRAME:
++        *stats_reg = &regs->fmbm_ofrc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_DISCARD:
++        *stats_reg = &regs->fmbm_ofdc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_DEALLOC_BUF:
++        *stats_reg = &regs->fmbm_obdc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_FILTERED_FRAME:
++        *stats_reg = &regs->fmbm_offc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_DMA_ERR:
++        *stats_reg = &regs->fmbm_ofldec;
++        break;
++    case E_FMAN_PORT_STATS_CNT_LEN_ERR:
++        *stats_reg = &regs->fmbm_ofledc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT:
++        *stats_reg = &regs->fmbm_ofufdc;
++        break;
++    case E_FMAN_PORT_STATS_CNT_WRED_DISCARD:
++        *stats_reg = &regs->fmbm_ofwdc;
++        break;
++    default:
++        *stats_reg = NULL;
++    }
++}
++
++static void get_rx_perf_reg(struct fman_port *port,
++        enum fman_port_perf_counters counter,
++        uint32_t **perf_reg)
++{
++    struct fman_port_rx_bmi_regs *regs = &port->bmi_regs->rx;
++
++    switch (counter) {
++    case E_FMAN_PORT_PERF_CNT_CYCLE:
++        *perf_reg = &regs->fmbm_rccn;
++        break;
++    case E_FMAN_PORT_PERF_CNT_TASK_UTIL:
++        *perf_reg = &regs->fmbm_rtuc;
++        break;
++    case E_FMAN_PORT_PERF_CNT_QUEUE_UTIL:
++        *perf_reg = &regs->fmbm_rrquc;
++        break;
++    case E_FMAN_PORT_PERF_CNT_DMA_UTIL:
++        *perf_reg = &regs->fmbm_rduc;
++        break;
++    case E_FMAN_PORT_PERF_CNT_FIFO_UTIL:
++        *perf_reg = &regs->fmbm_rfuc;
++        break;
++    case E_FMAN_PORT_PERF_CNT_RX_PAUSE:
++        *perf_reg = &regs->fmbm_rpac;
++        break;
++    default:
++        *perf_reg = NULL;
++    }
++}
++
++static void get_tx_perf_reg(struct fman_port *port,
++        enum fman_port_perf_counters counter,
++        uint32_t **perf_reg)
++{
++    struct fman_port_tx_bmi_regs *regs = &port->bmi_regs->tx;
++
++    switch (counter) {
++    case E_FMAN_PORT_PERF_CNT_CYCLE:
++        *perf_reg = &regs->fmbm_tccn;
++        break;
++    case E_FMAN_PORT_PERF_CNT_TASK_UTIL:
++        *perf_reg = &regs->fmbm_ttuc;
++        break;
++    case E_FMAN_PORT_PERF_CNT_QUEUE_UTIL:
++        *perf_reg = &regs->fmbm_ttcquc;
++        break;
++    case E_FMAN_PORT_PERF_CNT_DMA_UTIL:
++        *perf_reg = &regs->fmbm_tduc;
++        break;
++    case E_FMAN_PORT_PERF_CNT_FIFO_UTIL:
++        *perf_reg = &regs->fmbm_tfuc;
++        break;
++    default:
++        *perf_reg = NULL;
++    }
++}
++
++static void get_oh_perf_reg(struct fman_port *port,
++        enum fman_port_perf_counters counter,
++        uint32_t **perf_reg)
++{
++    struct fman_port_oh_bmi_regs *regs = &port->bmi_regs->oh;
++
++    switch (counter) {
++    case E_FMAN_PORT_PERF_CNT_CYCLE:
++        *perf_reg = &regs->fmbm_occn;
++        break;
++    case E_FMAN_PORT_PERF_CNT_TASK_UTIL:
++        *perf_reg = &regs->fmbm_otuc;
++        break;
++    case E_FMAN_PORT_PERF_CNT_DMA_UTIL:
++        *perf_reg = &regs->fmbm_oduc;
++        break;
++    case E_FMAN_PORT_PERF_CNT_FIFO_UTIL:
++        *perf_reg = &regs->fmbm_ofuc;
++        break;
++    default:
++        *perf_reg = NULL;
++    }
++}
++
++static void get_qmi_counter_reg(struct fman_port *port,
++        enum fman_port_qmi_counters  counter,
++        uint32_t **queue_reg)
++{
++    struct fman_port_qmi_regs *regs = port->qmi_regs;
++
++    switch (counter) {
++    case E_FMAN_PORT_ENQ_TOTAL:
++        *queue_reg = &regs->fmqm_pnetfc;
++        break;
++    case E_FMAN_PORT_DEQ_TOTAL:
++        if ((port->type == E_FMAN_PORT_TYPE_RX) ||
++                (port->type == E_FMAN_PORT_TYPE_RX_10G))
++            /* Counter not available for Rx ports */
++            *queue_reg = NULL;
++        else
++            *queue_reg = &regs->fmqm_pndtfc;
++        break;
++    case E_FMAN_PORT_DEQ_FROM_DFLT:
++        if ((port->type == E_FMAN_PORT_TYPE_RX) ||
++                (port->type == E_FMAN_PORT_TYPE_RX_10G))
++            /* Counter not available for Rx ports */
++            *queue_reg = NULL;
++        else
++            *queue_reg = &regs->fmqm_pndfdc;
++        break;
++    case E_FMAN_PORT_DEQ_CONFIRM:
++        if ((port->type == E_FMAN_PORT_TYPE_RX) ||
++                (port->type == E_FMAN_PORT_TYPE_RX_10G))
++            /* Counter not available for Rx ports */
++            *queue_reg = NULL;
++        else
++            *queue_reg = &regs->fmqm_pndcc;
++        break;
++    default:
++        *queue_reg = NULL;
++    }
++}
++
++void fman_port_defconfig(struct fman_port_cfg *cfg, enum fman_port_type type)
++{
++    cfg->dma_swap_data = E_FMAN_PORT_DMA_NO_SWAP;
++    cfg->dma_ic_stash_on = FALSE;
++    cfg->dma_header_stash_on = FALSE;
++    cfg->dma_sg_stash_on = FALSE;
++    cfg->dma_write_optimize = TRUE;
++    cfg->color = E_FMAN_PORT_COLOR_GREEN;
++    cfg->discard_override = FALSE;
++    cfg->checksum_bytes_ignore = 0;
++    cfg->rx_cut_end_bytes = 4;
++    cfg->rx_pri_elevation = ((0x3FF + 1) * FMAN_PORT_BMI_FIFO_UNITS);
++    cfg->rx_fifo_thr = ((0x3FF + 1) * FMAN_PORT_BMI_FIFO_UNITS);
++    cfg->rx_fd_bits = 0;
++    cfg->ic_ext_offset = 0;
++    cfg->ic_int_offset = 0;
++    cfg->ic_size = 0;
++    cfg->int_buf_start_margin = 0;
++    cfg->ext_buf_start_margin = 0;
++    cfg->ext_buf_end_margin = 0;
++    cfg->tx_fifo_min_level  = 0;
++    cfg->tx_fifo_low_comf_level = (5 * KILOBYTE);
++    cfg->stats_counters_enable = TRUE;
++    cfg->perf_counters_enable = TRUE;
++    cfg->deq_type = E_FMAN_PORT_DEQ_BY_PRI;
++
++    if (type == E_FMAN_PORT_TYPE_HC) {
++        cfg->sync_req = FALSE;
++        cfg->deq_prefetch_opt = E_FMAN_PORT_DEQ_NO_PREFETCH;
++    } else {
++        cfg->sync_req = TRUE;
++        cfg->deq_prefetch_opt = E_FMAN_PORT_DEQ_FULL_PREFETCH;
++    }
++
++    if (type == E_FMAN_PORT_TYPE_TX_10G) {
++        cfg->tx_fifo_deq_pipeline_depth = 4;
++        cfg->deq_high_pri = TRUE;
++        cfg->deq_byte_cnt = 0x1400;
++    } else {
++        if ((type == E_FMAN_PORT_TYPE_HC) ||
++                (type == E_FMAN_PORT_TYPE_OP))
++            cfg->tx_fifo_deq_pipeline_depth = 2;
++        else
++            cfg->tx_fifo_deq_pipeline_depth = 1;
++
++        cfg->deq_high_pri = FALSE;
++        cfg->deq_byte_cnt = 0x400;
++    }
++    cfg->no_scatter_gather = DEFAULT_FMAN_SP_NO_SCATTER_GATHER;
++}
++
++static uint8_t fman_port_find_bpool(struct fman_port *port, uint8_t bpid)
++{
++    uint32_t *bp_reg, tmp;
++    uint8_t i, id;
++
++    /* Find the pool */
++    bp_reg = port->bmi_regs->rx.fmbm_ebmpi;
++    for (i = 0;
++         (i < port->ext_pools_num && (i < FMAN_PORT_MAX_EXT_POOLS_NUM));
++         i++) {
++        tmp = ioread32be(&bp_reg[i]);
++        id = (uint8_t)((tmp & BMI_EXT_BUF_POOL_ID_MASK) >>
++                BMI_EXT_BUF_POOL_ID_SHIFT);
++
++        if (id == bpid)
++            break;
++    }
++
++    return i;
++}
++
++int fman_port_init(struct fman_port *port,
++        struct fman_port_cfg *cfg,
++        struct fman_port_params *params)
++{
++    int err;
++
++    /* Init BMI registers */
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        err = init_bmi_rx(port, cfg, params);
++        break;
++    case E_FMAN_PORT_TYPE_TX:
++    case E_FMAN_PORT_TYPE_TX_10G:
++        err = init_bmi_tx(port, cfg, params);
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++    case E_FMAN_PORT_TYPE_HC:
++        err = init_bmi_oh(port, cfg, params);
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    if (err)
++        return err;
++
++    /* Init QMI registers */
++    if (!port->im_en)
++    {
++        err = init_qmi(port, cfg, params);
++        return err;
++    }
++    return 0;
++}
++
++int fman_port_enable(struct fman_port *port)
++{
++    uint32_t *bmi_cfg_reg, tmp;
++    bool rx_port;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        bmi_cfg_reg = &port->bmi_regs->rx.fmbm_rcfg;
++        rx_port = TRUE;
++        break;
++    case E_FMAN_PORT_TYPE_TX:
++    case E_FMAN_PORT_TYPE_TX_10G:
++        bmi_cfg_reg = &port->bmi_regs->tx.fmbm_tcfg;
++        rx_port = FALSE;
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++    case E_FMAN_PORT_TYPE_HC:
++        bmi_cfg_reg = &port->bmi_regs->oh.fmbm_ocfg;
++        rx_port = FALSE;
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    /* Enable QMI */
++    if (!rx_port) {
++        tmp = ioread32be(&port->qmi_regs->fmqm_pnc) | QMI_PORT_CFG_EN;
++        iowrite32be(tmp, &port->qmi_regs->fmqm_pnc);
++    }
++
++    /* Enable BMI */
++    tmp = ioread32be(bmi_cfg_reg) | BMI_PORT_CFG_EN;
++    iowrite32be(tmp, bmi_cfg_reg);
++
++    return 0;
++}
++
++int fman_port_disable(const struct fman_port *port)
++{
++    uint32_t *bmi_cfg_reg, *bmi_status_reg, tmp;
++    bool rx_port, failure = FALSE;
++    int count;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        bmi_cfg_reg = &port->bmi_regs->rx.fmbm_rcfg;
++        bmi_status_reg = &port->bmi_regs->rx.fmbm_rst;
++        rx_port = TRUE;
++        break;
++    case E_FMAN_PORT_TYPE_TX:
++    case E_FMAN_PORT_TYPE_TX_10G:
++        bmi_cfg_reg = &port->bmi_regs->tx.fmbm_tcfg;
++        bmi_status_reg = &port->bmi_regs->tx.fmbm_tst;
++        rx_port = FALSE;
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++    case E_FMAN_PORT_TYPE_HC:
++        bmi_cfg_reg = &port->bmi_regs->oh.fmbm_ocfg;
++        bmi_status_reg = &port->bmi_regs->oh.fmbm_ost;
++        rx_port = FALSE;
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    /* Disable QMI */
++    if (!rx_port) {
++        tmp = ioread32be(&port->qmi_regs->fmqm_pnc) & ~QMI_PORT_CFG_EN;
++        iowrite32be(tmp, &port->qmi_regs->fmqm_pnc);
++
++        /* Wait for QMI to finish FD handling */
++        count = 100;
++        do {
++            udelay(10);
++            tmp = ioread32be(&port->qmi_regs->fmqm_pns);
++        } while ((tmp & QMI_PORT_STATUS_DEQ_FD_BSY) && --count);
++
++        if (count == 0)
++        {
++            /* Timeout */
++            failure = TRUE;
++        }
++    }
++
++    /* Disable BMI */
++    tmp = ioread32be(bmi_cfg_reg) & ~BMI_PORT_CFG_EN;
++    iowrite32be(tmp, bmi_cfg_reg);
++
++    /* Wait for graceful stop end */
++    count = 500;
++    do {
++        udelay(10);
++        tmp = ioread32be(bmi_status_reg);
++    } while ((tmp & BMI_PORT_STATUS_BSY) && --count);
++
++    if (count == 0)
++    {
++        /* Timeout */
++        failure = TRUE;
++    }
++
++    if (failure)
++        return -EBUSY;
++
++    return 0;
++}
++
++int fman_port_set_bpools(const struct fman_port *port,
++        const struct fman_port_bpools *bp)
++{
++    uint32_t tmp, *bp_reg, *bp_depl_reg;
++    uint8_t i, max_bp_num;
++    bool grp_depl_used = FALSE, rx_port;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        max_bp_num = port->ext_pools_num;
++        rx_port = TRUE;
++        bp_reg = port->bmi_regs->rx.fmbm_ebmpi;
++        bp_depl_reg = &port->bmi_regs->rx.fmbm_mpd;
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++        if (port->fm_rev_maj != 4)
++            return -EINVAL;
++        max_bp_num = FMAN_PORT_OBS_EXT_POOLS_NUM;
++        rx_port = FALSE;
++        bp_reg = port->bmi_regs->oh.fmbm_oebmpi;
++        bp_depl_reg = &port->bmi_regs->oh.fmbm_ompd;
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    if (rx_port) {
++        /* Check buffers are provided in ascending order */
++        for (i = 0;
++             (i < (bp->count-1) && (i < FMAN_PORT_MAX_EXT_POOLS_NUM - 1));
++             i++) {
++            if (bp->bpool[i].size > bp->bpool[i+1].size)
++                return -EINVAL;
++        }
++    }
++
++    /* Set up external buffers pools */
++    for (i = 0; i < bp->count; i++) {
++        tmp = BMI_EXT_BUF_POOL_VALID;
++        tmp |= ((uint32_t)bp->bpool[i].bpid <<
++            BMI_EXT_BUF_POOL_ID_SHIFT) & BMI_EXT_BUF_POOL_ID_MASK;
++
++        if (rx_port) {
++            if (bp->counters_enable)
++                tmp |= BMI_EXT_BUF_POOL_EN_COUNTER;
++
++            if (bp->bpool[i].is_backup)
++                tmp |= BMI_EXT_BUF_POOL_BACKUP;
++
++            tmp |= (uint32_t)bp->bpool[i].size;
++        }
++
++        iowrite32be(tmp, &bp_reg[i]);
++    }
++
++    /* Clear unused pools */
++    for (i = bp->count; i < max_bp_num; i++)
++        iowrite32be(0, &bp_reg[i]);
++
++    /* Pools depletion */
++    tmp = 0;
++    for (i = 0; i < FMAN_PORT_MAX_EXT_POOLS_NUM; i++) {
++        if (bp->bpool[i].grp_bp_depleted) {
++            grp_depl_used = TRUE;
++            tmp |= 0x80000000 >> i;
++        }
++
++        if (bp->bpool[i].single_bp_depleted)
++            tmp |= 0x80 >> i;
++
++        if (bp->bpool[i].pfc_priorities_en)
++            tmp |= 0x0100 << i;
++    }
++
++    if (grp_depl_used)
++        tmp |= ((uint32_t)bp->grp_bp_depleted_num - 1) <<
++            BMI_POOL_DEP_NUM_OF_POOLS_SHIFT;
++
++    iowrite32be(tmp, bp_depl_reg);
++    return 0;
++}
++
++int fman_port_set_rate_limiter(struct fman_port *port,
++        struct fman_port_rate_limiter *rate_limiter)
++{
++    uint32_t *rate_limit_reg, *rate_limit_scale_reg;
++    uint32_t granularity, tmp;
++    uint8_t usec_bit, factor;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_TX:
++    case E_FMAN_PORT_TYPE_TX_10G:
++        rate_limit_reg = &port->bmi_regs->tx.fmbm_trlmt;
++        rate_limit_scale_reg = &port->bmi_regs->tx.fmbm_trlmts;
++        granularity = BMI_RATE_LIMIT_GRAN_TX;
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++        rate_limit_reg = &port->bmi_regs->oh.fmbm_orlmt;
++        rate_limit_scale_reg = &port->bmi_regs->oh.fmbm_orlmts;
++        granularity = BMI_RATE_LIMIT_GRAN_OP;
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    /* Factor is per 1 usec count */
++    factor = 1;
++    usec_bit = rate_limiter->count_1micro_bit;
++
++    /* If rate limit is too small for an 1usec factor, adjust timestamp
++     * scale and multiply the factor */
++    while (rate_limiter->rate < (granularity / factor)) {
++        if (usec_bit == 31)
++            /* Can't configure rate limiter - rate is too small */
++            return -EINVAL;
++
++        usec_bit++;
++        factor <<= 1;
++    }
++
++    /* Figure out register value. The "while" above quarantees that
++     * (rate_limiter->rate * factor / granularity) >= 1 */
++    tmp = (uint32_t)(rate_limiter->rate * factor / granularity - 1);
++
++    /* Check rate limit isn't too large */
++    if (tmp >= BMI_RATE_LIMIT_MAX_RATE_IN_GRAN_UNITS)
++        return -EINVAL;
++
++    /* Check burst size is in allowed range */
++    if ((rate_limiter->burst_size == 0) ||
++            (rate_limiter->burst_size >
++                BMI_RATE_LIMIT_MAX_BURST_SIZE))
++        return -EINVAL;
++
++    tmp |= (uint32_t)(rate_limiter->burst_size - 1) <<
++            BMI_RATE_LIMIT_MAX_BURST_SHIFT;
++
++    if ((port->type == E_FMAN_PORT_TYPE_OP) &&
++            (port->fm_rev_maj == 4)) {
++        if (rate_limiter->high_burst_size_gran)
++            tmp |= BMI_RATE_LIMIT_HIGH_BURST_SIZE_GRAN;
++    }
++
++    iowrite32be(tmp, rate_limit_reg);
++
++    /* Set up rate limiter scale register */
++    tmp = BMI_RATE_LIMIT_SCALE_EN;
++    tmp |= (31 - (uint32_t)usec_bit) << BMI_RATE_LIMIT_SCALE_TSBS_SHIFT;
++
++    if ((port->type == E_FMAN_PORT_TYPE_OP) &&
++            (port->fm_rev_maj == 4))
++        tmp |= rate_limiter->rate_factor;
++
++    iowrite32be(tmp, rate_limit_scale_reg);
++
++    return 0;
++}
++
++int fman_port_delete_rate_limiter(struct fman_port *port)
++{
++    uint32_t *rate_limit_scale_reg;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_TX:
++    case E_FMAN_PORT_TYPE_TX_10G:
++        rate_limit_scale_reg = &port->bmi_regs->tx.fmbm_trlmts;
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++        rate_limit_scale_reg = &port->bmi_regs->oh.fmbm_orlmts;
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    iowrite32be(0, rate_limit_scale_reg);
++    return 0;
++}
++
++int fman_port_set_err_mask(struct fman_port *port, uint32_t err_mask)
++{
++    uint32_t *err_mask_reg;
++
++    /* Obtain register address */
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        err_mask_reg = &port->bmi_regs->rx.fmbm_rfsem;
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++        err_mask_reg = &port->bmi_regs->oh.fmbm_ofsem;
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    iowrite32be(err_mask, err_mask_reg);
++    return 0;
++}
++
++int fman_port_set_discard_mask(struct fman_port *port, uint32_t discard_mask)
++{
++    uint32_t *discard_mask_reg;
++
++    /* Obtain register address */
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        discard_mask_reg = &port->bmi_regs->rx.fmbm_rfsdm;
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++        discard_mask_reg = &port->bmi_regs->oh.fmbm_ofsdm;
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    iowrite32be(discard_mask, discard_mask_reg);
++    return 0;
++}
++
++int fman_port_modify_rx_fd_bits(struct fman_port *port,
++        uint8_t rx_fd_bits,
++        bool add)
++{
++    uint32_t    tmp;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    tmp = ioread32be(&port->bmi_regs->rx.fmbm_rfne);
++
++    if (add)
++        tmp |= (uint32_t)rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT;
++    else
++        tmp &= ~((uint32_t)rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT);
++
++    iowrite32be(tmp, &port->bmi_regs->rx.fmbm_rfne);
++    return 0;
++}
++
++int fman_port_set_perf_cnt_params(struct fman_port *port,
++        struct fman_port_perf_cnt_params *params)
++{
++    uint32_t *pcp_reg, tmp;
++
++    /* Obtain register address and check parameters are in range */
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        pcp_reg = &port->bmi_regs->rx.fmbm_rpcp;
++        if ((params->queue_val == 0) ||
++            (params->queue_val > MAX_PERFORMANCE_RX_QUEUE_COMP))
++            return -EINVAL;
++        break;
++    case E_FMAN_PORT_TYPE_TX:
++    case E_FMAN_PORT_TYPE_TX_10G:
++        pcp_reg = &port->bmi_regs->tx.fmbm_tpcp;
++        if ((params->queue_val == 0) ||
++            (params->queue_val > MAX_PERFORMANCE_TX_QUEUE_COMP))
++            return -EINVAL;
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++    case E_FMAN_PORT_TYPE_HC:
++        pcp_reg = &port->bmi_regs->oh.fmbm_opcp;
++        if (params->queue_val != 0)
++            return -EINVAL;
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    if ((params->task_val == 0) ||
++            (params->task_val > MAX_PERFORMANCE_TASK_COMP))
++        return -EINVAL;
++    if ((params->dma_val == 0) ||
++            (params->dma_val > MAX_PERFORMANCE_DMA_COMP))
++        return -EINVAL;
++    if ((params->fifo_val == 0) ||
++            ((params->fifo_val / FMAN_PORT_BMI_FIFO_UNITS) >
++                MAX_PERFORMANCE_FIFO_COMP))
++        return -EINVAL;
++    tmp = (uint32_t)(params->task_val - 1) <<
++            BMI_PERFORMANCE_TASK_COMP_SHIFT;
++    tmp |= (uint32_t)(params->dma_val - 1) <<
++            BMI_PERFORMANCE_DMA_COMP_SHIFT;
++    tmp |= (uint32_t)(params->fifo_val / FMAN_PORT_BMI_FIFO_UNITS - 1);
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++    case E_FMAN_PORT_TYPE_TX:
++    case E_FMAN_PORT_TYPE_TX_10G:
++        tmp |= (uint32_t)(params->queue_val - 1) <<
++            BMI_PERFORMANCE_QUEUE_COMP_SHIFT;
++        break;
++    default:
++        break;
++    }
++
++
++    iowrite32be(tmp, pcp_reg);
++    return 0;
++}
++
++int fman_port_set_stats_cnt_mode(struct fman_port *port, bool enable)
++{
++    uint32_t *stats_reg, tmp;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        stats_reg = &port->bmi_regs->rx.fmbm_rstc;
++        break;
++    case E_FMAN_PORT_TYPE_TX:
++    case E_FMAN_PORT_TYPE_TX_10G:
++        stats_reg = &port->bmi_regs->tx.fmbm_tstc;
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++    case E_FMAN_PORT_TYPE_HC:
++        stats_reg = &port->bmi_regs->oh.fmbm_ostc;
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    tmp = ioread32be(stats_reg);
++
++    if (enable)
++        tmp |= BMI_COUNTERS_EN;
++    else
++        tmp &= ~BMI_COUNTERS_EN;
++
++    iowrite32be(tmp, stats_reg);
++    return 0;
++}
++
++int fman_port_set_perf_cnt_mode(struct fman_port *port, bool enable)
++{
++    uint32_t *stats_reg, tmp;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        stats_reg = &port->bmi_regs->rx.fmbm_rpc;
++        break;
++    case E_FMAN_PORT_TYPE_TX:
++    case E_FMAN_PORT_TYPE_TX_10G:
++        stats_reg = &port->bmi_regs->tx.fmbm_tpc;
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++    case E_FMAN_PORT_TYPE_HC:
++        stats_reg = &port->bmi_regs->oh.fmbm_opc;
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    tmp = ioread32be(stats_reg);
++
++    if (enable)
++        tmp |= BMI_COUNTERS_EN;
++    else
++        tmp &= ~BMI_COUNTERS_EN;
++
++    iowrite32be(tmp, stats_reg);
++    return 0;
++}
++
++int fman_port_set_queue_cnt_mode(struct fman_port *port, bool enable)
++{
++    uint32_t tmp;
++
++    tmp = ioread32be(&port->qmi_regs->fmqm_pnc);
++
++    if (enable)
++        tmp |= QMI_PORT_CFG_EN_COUNTERS;
++    else
++        tmp &= ~QMI_PORT_CFG_EN_COUNTERS;
++
++    iowrite32be(tmp, &port->qmi_regs->fmqm_pnc);
++    return 0;
++}
++
++int fman_port_set_bpool_cnt_mode(struct fman_port *port,
++        uint8_t bpid,
++        bool enable)
++{
++    uint8_t index;
++    uint32_t tmp;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    /* Find the pool */
++    index = fman_port_find_bpool(port, bpid);
++    if (index == port->ext_pools_num || index == FMAN_PORT_MAX_EXT_POOLS_NUM)
++        /* Not found */
++        return -EINVAL;
++
++    tmp = ioread32be(&port->bmi_regs->rx.fmbm_ebmpi[index]);
++
++    if (enable)
++        tmp |= BMI_EXT_BUF_POOL_EN_COUNTER;
++    else
++        tmp &= ~BMI_EXT_BUF_POOL_EN_COUNTER;
++
++    iowrite32be(tmp, &port->bmi_regs->rx.fmbm_ebmpi[index]);
++    return 0;
++}
++
++uint32_t fman_port_get_stats_counter(struct fman_port *port,
++        enum fman_port_stats_counters  counter)
++{
++    uint32_t *stats_reg, ret_val;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        get_rx_stats_reg(port, counter, &stats_reg);
++        break;
++    case E_FMAN_PORT_TYPE_TX:
++    case E_FMAN_PORT_TYPE_TX_10G:
++        get_tx_stats_reg(port, counter, &stats_reg);
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++    case E_FMAN_PORT_TYPE_HC:
++        get_oh_stats_reg(port, counter, &stats_reg);
++        break;
++    default:
++        stats_reg = NULL;
++    }
++
++    if (stats_reg == NULL)
++        return 0;
++
++    ret_val = ioread32be(stats_reg);
++    return ret_val;
++}
++
++void fman_port_set_stats_counter(struct fman_port *port,
++        enum fman_port_stats_counters counter,
++        uint32_t value)
++{
++    uint32_t *stats_reg;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        get_rx_stats_reg(port, counter, &stats_reg);
++        break;
++    case E_FMAN_PORT_TYPE_TX:
++    case E_FMAN_PORT_TYPE_TX_10G:
++        get_tx_stats_reg(port, counter, &stats_reg);
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++    case E_FMAN_PORT_TYPE_HC:
++        get_oh_stats_reg(port, counter, &stats_reg);
++        break;
++    default:
++        stats_reg = NULL;
++    }
++
++    if (stats_reg == NULL)
++        return;
++
++    iowrite32be(value, stats_reg);
++}
++
++uint32_t fman_port_get_perf_counter(struct fman_port *port,
++        enum fman_port_perf_counters counter)
++{
++    uint32_t *perf_reg, ret_val;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        get_rx_perf_reg(port, counter, &perf_reg);
++        break;
++    case E_FMAN_PORT_TYPE_TX:
++    case E_FMAN_PORT_TYPE_TX_10G:
++        get_tx_perf_reg(port, counter, &perf_reg);
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++    case E_FMAN_PORT_TYPE_HC:
++        get_oh_perf_reg(port, counter, &perf_reg);
++        break;
++    default:
++        perf_reg = NULL;
++    }
++
++    if (perf_reg == NULL)
++        return 0;
++
++    ret_val = ioread32be(perf_reg);
++    return ret_val;
++}
++
++void fman_port_set_perf_counter(struct fman_port *port,
++        enum fman_port_perf_counters counter,
++        uint32_t value)
++{
++    uint32_t *perf_reg;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        get_rx_perf_reg(port, counter, &perf_reg);
++        break;
++    case E_FMAN_PORT_TYPE_TX:
++    case E_FMAN_PORT_TYPE_TX_10G:
++        get_tx_perf_reg(port, counter, &perf_reg);
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++    case E_FMAN_PORT_TYPE_HC:
++        get_oh_perf_reg(port, counter, &perf_reg);
++        break;
++    default:
++        perf_reg = NULL;
++    }
++
++    if (perf_reg == NULL)
++        return;
++
++    iowrite32be(value, perf_reg);
++}
++
++uint32_t fman_port_get_qmi_counter(struct fman_port *port,
++        enum fman_port_qmi_counters  counter)
++{
++    uint32_t *queue_reg, ret_val;
++
++    get_qmi_counter_reg(port, counter, &queue_reg);
++
++    if (queue_reg == NULL)
++        return 0;
++
++    ret_val = ioread32be(queue_reg);
++    return ret_val;
++}
++
++void fman_port_set_qmi_counter(struct fman_port *port,
++        enum fman_port_qmi_counters counter,
++        uint32_t value)
++{
++    uint32_t *queue_reg;
++
++    get_qmi_counter_reg(port, counter, &queue_reg);
++
++    if (queue_reg == NULL)
++        return;
++
++    iowrite32be(value, queue_reg);
++}
++
++uint32_t fman_port_get_bpool_counter(struct fman_port *port, uint8_t bpid)
++{
++    uint8_t index;
++    uint32_t ret_val;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        break;
++    default:
++        return 0;
++    }
++
++    /* Find the pool */
++    index = fman_port_find_bpool(port, bpid);
++    if (index == port->ext_pools_num || index == FMAN_PORT_MAX_EXT_POOLS_NUM)
++        /* Not found */
++        return 0;
++
++    ret_val = ioread32be(&port->bmi_regs->rx.fmbm_acnt[index]);
++    return ret_val;
++}
++
++void fman_port_set_bpool_counter(struct fman_port *port,
++        uint8_t bpid,
++        uint32_t value)
++{
++    uint8_t index;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        break;
++    default:
++        return;
++    }
++
++    /* Find the pool */
++    index = fman_port_find_bpool(port, bpid);
++    if (index == port->ext_pools_num || index == FMAN_PORT_MAX_EXT_POOLS_NUM)
++        /* Not found */
++        return;
++
++    iowrite32be(value, &port->bmi_regs->rx.fmbm_acnt[index]);
++}
++
++int fman_port_add_congestion_grps(struct fman_port *port,
++        uint32_t grps_map[FMAN_PORT_CG_MAP_NUM])
++{
++    int i;
++    uint32_t tmp, *grp_map_reg;
++    uint8_t max_grp_map_num;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        if (port->fm_rev_maj == 4)
++            max_grp_map_num = 1;
++        else
++            max_grp_map_num = FMAN_PORT_CG_MAP_NUM;
++        grp_map_reg = port->bmi_regs->rx.fmbm_rcgm;
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++        max_grp_map_num = 1;
++        if (port->fm_rev_maj != 4)
++            return -EINVAL;
++        grp_map_reg = port->bmi_regs->oh.fmbm_ocgm;
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    for (i = (max_grp_map_num - 1); i >= 0; i--) {
++        if (grps_map[i] == 0)
++            continue;
++        tmp = ioread32be(&grp_map_reg[i]);
++        tmp |= grps_map[i];
++        iowrite32be(tmp, &grp_map_reg[i]);
++    }
++
++    return 0;
++}
++
++int fman_port_remove_congestion_grps(struct fman_port *port,
++        uint32_t grps_map[FMAN_PORT_CG_MAP_NUM])
++{
++    int i;
++    uint32_t tmp, *grp_map_reg;
++    uint8_t max_grp_map_num;
++
++    switch (port->type) {
++    case E_FMAN_PORT_TYPE_RX:
++    case E_FMAN_PORT_TYPE_RX_10G:
++        if (port->fm_rev_maj == 4)
++            max_grp_map_num = 1;
++        else
++            max_grp_map_num = FMAN_PORT_CG_MAP_NUM;
++        grp_map_reg = port->bmi_regs->rx.fmbm_rcgm;
++        break;
++    case E_FMAN_PORT_TYPE_OP:
++        max_grp_map_num = 1;
++        if (port->fm_rev_maj != 4)
++            return -EINVAL;
++        grp_map_reg = port->bmi_regs->oh.fmbm_ocgm;
++        break;
++    default:
++        return -EINVAL;
++    }
++
++    for (i = (max_grp_map_num - 1); i >= 0; i--) {
++        if (grps_map[i] == 0)
++            continue;
++        tmp = ioread32be(&grp_map_reg[i]);
++        tmp &= ~grps_map[i];
++        iowrite32be(tmp, &grp_map_reg[i]);
++    }
++    return 0;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/Makefile
+@@ -0,0 +1,15 @@
++#
++# Makefile for the Freescale Ethernet controllers
++#
++ccflags-y           += -DVERSION=\"\"
++#
++#Include netcomm SW specific definitions
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++
++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
++
++ccflags-y += -I$(NCSW_FM_INC)
++
++obj-y         += fsl-ncsw-RTC.o
++
++fsl-ncsw-RTC-objs     :=   fm_rtc.o fman_rtc.o
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.c
+@@ -0,0 +1,692 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_rtc.c
++
++ @Description   FM RTC driver implementation.
++
++ @Cautions      None
++*//***************************************************************************/
++#include <linux/math64.h>
++#include "error_ext.h"
++#include "debug_ext.h"
++#include "string_ext.h"
++#include "part_ext.h"
++#include "xx_ext.h"
++#include "ncsw_ext.h"
++
++#include "fm_rtc.h"
++#include "fm_common.h"
++
++
++
++/*****************************************************************************/
++static t_Error CheckInitParameters(t_FmRtc *p_Rtc)
++{
++    struct rtc_cfg  *p_RtcDriverParam = p_Rtc->p_RtcDriverParam;
++    int                 i;
++
++    if ((p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_EXTERNAL) &&
++        (p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_SYSTEM) &&
++        (p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR))
++        RETURN_ERROR(MAJOR, E_INVALID_CLOCK, ("Source clock undefined"));
++
++    if (p_Rtc->outputClockDivisor == 0)
++    {
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("Divisor for output clock (should be positive)"));
++    }
++
++    for (i=0; i < FM_RTC_NUM_OF_ALARMS; i++)
++    {
++        if ((p_RtcDriverParam->alarm_polarity[i] != E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW) &&
++            (p_RtcDriverParam->alarm_polarity[i] != E_FMAN_RTC_ALARM_POLARITY_ACTIVE_HIGH))
++        {
++            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm %d signal polarity", i));
++        }
++    }
++    for (i=0; i < FM_RTC_NUM_OF_EXT_TRIGGERS; i++)
++    {
++        if ((p_RtcDriverParam->trigger_polarity[i] != E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE) &&
++            (p_RtcDriverParam->trigger_polarity[i] != E_FMAN_RTC_TRIGGER_ON_RISING_EDGE))
++        {
++            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Trigger %d signal polarity", i));
++        }
++    }
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++static void RtcExceptions(t_Handle h_FmRtc)
++{
++    t_FmRtc             *p_Rtc = (t_FmRtc *)h_FmRtc;
++    struct rtc_regs     *p_MemMap;
++    register uint32_t   events;
++
++    ASSERT_COND(p_Rtc);
++    p_MemMap = p_Rtc->p_MemMap;
++
++    events = fman_rtc_check_and_clear_event(p_MemMap);
++    if (events & FMAN_RTC_TMR_TEVENT_ALM1)
++    {
++        if (p_Rtc->alarmParams[0].clearOnExpiration)
++        {
++            fman_rtc_set_timer_alarm_l(p_MemMap, 0, 0);
++            fman_rtc_disable_interupt(p_MemMap, FMAN_RTC_TMR_TEVENT_ALM1);
++        }
++        ASSERT_COND(p_Rtc->alarmParams[0].f_AlarmCallback);
++        p_Rtc->alarmParams[0].f_AlarmCallback(p_Rtc->h_App, 0);
++    }
++    if (events & FMAN_RTC_TMR_TEVENT_ALM2)
++    {
++        if (p_Rtc->alarmParams[1].clearOnExpiration)
++        {
++            fman_rtc_set_timer_alarm_l(p_MemMap, 1, 0);
++            fman_rtc_disable_interupt(p_MemMap, FMAN_RTC_TMR_TEVENT_ALM2);
++        }
++        ASSERT_COND(p_Rtc->alarmParams[1].f_AlarmCallback);
++        p_Rtc->alarmParams[1].f_AlarmCallback(p_Rtc->h_App, 1);
++    }
++    if (events & FMAN_RTC_TMR_TEVENT_PP1)
++    {
++        ASSERT_COND(p_Rtc->periodicPulseParams[0].f_PeriodicPulseCallback);
++        p_Rtc->periodicPulseParams[0].f_PeriodicPulseCallback(p_Rtc->h_App, 0);
++    }
++    if (events & FMAN_RTC_TMR_TEVENT_PP2)
++    {
++        ASSERT_COND(p_Rtc->periodicPulseParams[1].f_PeriodicPulseCallback);
++        p_Rtc->periodicPulseParams[1].f_PeriodicPulseCallback(p_Rtc->h_App, 1);
++    }
++    if (events & FMAN_RTC_TMR_TEVENT_ETS1)
++    {
++        ASSERT_COND(p_Rtc->externalTriggerParams[0].f_ExternalTriggerCallback);
++        p_Rtc->externalTriggerParams[0].f_ExternalTriggerCallback(p_Rtc->h_App, 0);
++    }
++    if (events & FMAN_RTC_TMR_TEVENT_ETS2)
++    {
++        ASSERT_COND(p_Rtc->externalTriggerParams[1].f_ExternalTriggerCallback);
++        p_Rtc->externalTriggerParams[1].f_ExternalTriggerCallback(p_Rtc->h_App, 1);
++    }
++}
++
++
++/*****************************************************************************/
++t_Handle FM_RTC_Config(t_FmRtcParams *p_FmRtcParam)
++{
++    t_FmRtc *p_Rtc;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmRtcParam, E_NULL_POINTER, NULL);
++
++    /* Allocate memory for the FM RTC driver parameters */
++    p_Rtc = (t_FmRtc *)XX_Malloc(sizeof(t_FmRtc));
++    if (!p_Rtc)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM RTC driver structure"));
++        return NULL;
++    }
++
++    memset(p_Rtc, 0, sizeof(t_FmRtc));
++
++    /* Allocate memory for the FM RTC driver parameters */
++    p_Rtc->p_RtcDriverParam = (struct rtc_cfg *)XX_Malloc(sizeof(struct rtc_cfg));
++    if (!p_Rtc->p_RtcDriverParam)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM RTC driver parameters"));
++        XX_Free(p_Rtc);
++        return NULL;
++    }
++
++    memset(p_Rtc->p_RtcDriverParam, 0, sizeof(struct rtc_cfg));
++
++    /* Store RTC configuration parameters */
++    p_Rtc->h_Fm = p_FmRtcParam->h_Fm;
++
++    /* Set default RTC configuration parameters */
++    fman_rtc_defconfig(p_Rtc->p_RtcDriverParam);
++
++    p_Rtc->outputClockDivisor = DEFAULT_OUTPUT_CLOCK_DIVISOR;
++    p_Rtc->p_RtcDriverParam->bypass = DEFAULT_BYPASS;
++    p_Rtc->clockPeriodNanoSec = DEFAULT_CLOCK_PERIOD; /* 1 usec */
++
++
++    /* Store RTC parameters in the RTC control structure */
++    p_Rtc->p_MemMap = (struct rtc_regs *)UINT_TO_PTR(p_FmRtcParam->baseAddress);
++    p_Rtc->h_App    = p_FmRtcParam->h_App;
++
++    return p_Rtc;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_Init(t_Handle h_FmRtc)
++{
++    t_FmRtc             *p_Rtc = (t_FmRtc *)h_FmRtc;
++    struct rtc_cfg      *p_RtcDriverParam;
++    struct rtc_regs     *p_MemMap;
++    uint32_t            freqCompensation = 0;
++    uint64_t            tmpDouble;
++    bool                init_freq_comp = FALSE;
++
++    p_RtcDriverParam = p_Rtc->p_RtcDriverParam;
++    p_MemMap = p_Rtc->p_MemMap;
++
++    if (CheckInitParameters(p_Rtc)!=E_OK)
++        RETURN_ERROR(MAJOR, E_CONFLICT,
++                     ("Init Parameters are not Valid"));
++
++    /* TODO check that no timestamping MACs are working in this stage. */
++
++    /* find source clock frequency in Mhz */
++    if (p_Rtc->p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_SYSTEM)
++        p_Rtc->srcClkFreqMhz = p_Rtc->p_RtcDriverParam->ext_src_clk_freq;
++    else
++        p_Rtc->srcClkFreqMhz = (uint32_t)(FmGetMacClockFreq(p_Rtc->h_Fm));
++
++    /* if timer in Master mode Initialize TMR_CTRL */
++    /* We want the counter (TMR_CNT) to count in nano-seconds */
++    if (!p_RtcDriverParam->timer_slave_mode && p_Rtc->p_RtcDriverParam->bypass)
++        p_Rtc->clockPeriodNanoSec = (1000 / p_Rtc->srcClkFreqMhz);
++    else
++    {
++        /* Initialize TMR_ADD with the initial frequency compensation value:
++           freqCompensation = (2^32 / frequency ratio) */
++        /* frequency ratio = sorce clock/rtc clock =
++         * (p_Rtc->srcClkFreqMhz*1000000))/ 1/(p_Rtc->clockPeriodNanoSec * 1000000000) */
++        init_freq_comp = TRUE;
++        freqCompensation = (uint32_t)DIV_CEIL(ACCUMULATOR_OVERFLOW * 1000,
++                                              p_Rtc->clockPeriodNanoSec * p_Rtc->srcClkFreqMhz);
++    }
++
++    /* check the legality of the relation between source and destination clocks */
++    /* should be larger than 1.0001 */
++    tmpDouble = 10000 * (uint64_t)p_Rtc->clockPeriodNanoSec * (uint64_t)p_Rtc->srcClkFreqMhz;
++    if ((tmpDouble) <= 10001)
++        RETURN_ERROR(MAJOR, E_CONFLICT,
++              ("Invalid relation between source and destination clocks. Should be larger than 1.0001"));
++
++    fman_rtc_init(p_RtcDriverParam,
++             p_MemMap,
++             FM_RTC_NUM_OF_ALARMS,
++             FM_RTC_NUM_OF_PERIODIC_PULSES,
++             FM_RTC_NUM_OF_EXT_TRIGGERS,
++             init_freq_comp,
++             freqCompensation,
++             p_Rtc->outputClockDivisor);
++
++    /* Register the FM RTC interrupt */
++    FmRegisterIntr(p_Rtc->h_Fm, e_FM_MOD_TMR, 0, e_FM_INTR_TYPE_NORMAL, RtcExceptions , p_Rtc);
++
++    /* Free parameters structures */
++    XX_Free(p_Rtc->p_RtcDriverParam);
++    p_Rtc->p_RtcDriverParam = NULL;
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_Free(t_Handle h_FmRtc)
++{
++    t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++
++    if (p_Rtc->p_RtcDriverParam)
++    {
++        XX_Free(p_Rtc->p_RtcDriverParam);
++    }
++    else
++    {
++        FM_RTC_Disable(h_FmRtc);
++    }
++
++    /* Unregister FM RTC interrupt */
++    FmUnregisterIntr(p_Rtc->h_Fm, e_FM_MOD_TMR, 0, e_FM_INTR_TYPE_NORMAL);
++    XX_Free(p_Rtc);
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_ConfigSourceClock(t_Handle         h_FmRtc,
++                                    e_FmSrcClk    srcClk,
++                                    uint32_t      freqInMhz)
++{
++    t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    p_Rtc->p_RtcDriverParam->src_clk = (enum fman_src_clock)srcClk;
++    if (srcClk != e_FM_RTC_SOURCE_CLOCK_SYSTEM)
++        p_Rtc->p_RtcDriverParam->ext_src_clk_freq = freqInMhz;
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_ConfigPeriod(t_Handle h_FmRtc, uint32_t period)
++{
++    t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    p_Rtc->clockPeriodNanoSec = period;
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_ConfigFrequencyBypass(t_Handle h_FmRtc, bool enabled)
++{
++    t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    p_Rtc->p_RtcDriverParam->bypass = enabled;
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_ConfigInvertedInputClockPhase(t_Handle h_FmRtc, bool inverted)
++{
++    t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    p_Rtc->p_RtcDriverParam->invert_input_clk_phase = inverted;
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_ConfigInvertedOutputClockPhase(t_Handle h_FmRtc, bool inverted)
++{
++    t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    p_Rtc->p_RtcDriverParam->invert_output_clk_phase = inverted;
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_ConfigOutputClockDivisor(t_Handle h_FmRtc, uint16_t divisor)
++{
++    t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    p_Rtc->outputClockDivisor = divisor;
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_ConfigPulseRealignment(t_Handle h_FmRtc, bool enable)
++{
++    t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    p_Rtc->p_RtcDriverParam->pulse_realign = enable;
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_ConfigAlarmPolarity(t_Handle             h_FmRtc,
++                                   uint8_t              alarmId,
++                                   e_FmRtcAlarmPolarity alarmPolarity)
++{
++    t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    if (alarmId >= FM_RTC_NUM_OF_ALARMS)
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm ID"));
++
++    p_Rtc->p_RtcDriverParam->alarm_polarity[alarmId] =
++        (enum fman_rtc_alarm_polarity)alarmPolarity;
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_ConfigExternalTriggerPolarity(t_Handle               h_FmRtc,
++                                             uint8_t                triggerId,
++                                             e_FmRtcTriggerPolarity triggerPolarity)
++{
++    t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    if (triggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
++    {
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External trigger ID"));
++    }
++
++    p_Rtc->p_RtcDriverParam->trigger_polarity[triggerId] =
++        (enum fman_rtc_trigger_polarity)triggerPolarity;
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_Enable(t_Handle h_FmRtc, bool resetClock)
++{
++    t_FmRtc         *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    fman_rtc_enable(p_Rtc->p_MemMap, resetClock);
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_Disable(t_Handle h_FmRtc)
++{
++    t_FmRtc         *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    /* TODO A check must be added here, that no timestamping MAC's
++     * are working in this stage. */
++    fman_rtc_disable(p_Rtc->p_MemMap);
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_SetClockOffset(t_Handle h_FmRtc, int64_t offset)
++{
++    t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    fman_rtc_set_timer_offset(p_Rtc->p_MemMap, offset);
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_SetAlarm(t_Handle h_FmRtc, t_FmRtcAlarmParams *p_FmRtcAlarmParams)
++{
++    t_FmRtc         *p_Rtc = (t_FmRtc *)h_FmRtc;
++    uint64_t        tmpAlarm;
++    bool            enable = FALSE;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    if (p_FmRtcAlarmParams->alarmId >= FM_RTC_NUM_OF_ALARMS)
++    {
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm ID"));
++    }
++
++    if (p_FmRtcAlarmParams->alarmTime < p_Rtc->clockPeriodNanoSec)
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
++                     ("Alarm time must be equal or larger than RTC period - %d nanoseconds",
++                      p_Rtc->clockPeriodNanoSec));
++    tmpAlarm = p_FmRtcAlarmParams->alarmTime;
++    if (do_div(tmpAlarm, p_Rtc->clockPeriodNanoSec))
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
++                     ("Alarm time must be a multiple of RTC period - %d nanoseconds",
++                      p_Rtc->clockPeriodNanoSec));
++
++    if (p_FmRtcAlarmParams->f_AlarmCallback)
++    {
++        p_Rtc->alarmParams[p_FmRtcAlarmParams->alarmId].f_AlarmCallback = p_FmRtcAlarmParams->f_AlarmCallback;
++        p_Rtc->alarmParams[p_FmRtcAlarmParams->alarmId].clearOnExpiration = p_FmRtcAlarmParams->clearOnExpiration;
++        enable = TRUE;
++    }
++
++    fman_rtc_set_alarm(p_Rtc->p_MemMap, p_FmRtcAlarmParams->alarmId, (unsigned long)tmpAlarm, enable);
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_SetPeriodicPulse(t_Handle h_FmRtc, t_FmRtcPeriodicPulseParams *p_FmRtcPeriodicPulseParams)
++{
++    t_FmRtc         *p_Rtc = (t_FmRtc *)h_FmRtc;
++    bool            enable = FALSE;
++    uint64_t        tmpFiper;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    if (p_FmRtcPeriodicPulseParams->periodicPulseId >= FM_RTC_NUM_OF_PERIODIC_PULSES)
++    {
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse ID"));
++    }
++    if (fman_rtc_is_enabled(p_Rtc->p_MemMap))
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Can't set Periodic pulse when RTC is enabled."));
++    if (p_FmRtcPeriodicPulseParams->periodicPulsePeriod < p_Rtc->clockPeriodNanoSec)
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
++                     ("Periodic pulse must be equal or larger than RTC period - %d nanoseconds",
++                      p_Rtc->clockPeriodNanoSec));
++    tmpFiper = p_FmRtcPeriodicPulseParams->periodicPulsePeriod;
++    if (do_div(tmpFiper, p_Rtc->clockPeriodNanoSec))
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
++                     ("Periodic pulse must be a multiple of RTC period - %d nanoseconds",
++                      p_Rtc->clockPeriodNanoSec));
++    if (tmpFiper & 0xffffffff00000000LL)
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
++                     ("Periodic pulse/RTC Period must be smaller than 4294967296",
++                      p_Rtc->clockPeriodNanoSec));
++
++    if (p_FmRtcPeriodicPulseParams->f_PeriodicPulseCallback)
++    {
++        p_Rtc->periodicPulseParams[p_FmRtcPeriodicPulseParams->periodicPulseId].f_PeriodicPulseCallback =
++                                                                p_FmRtcPeriodicPulseParams->f_PeriodicPulseCallback;
++        enable = TRUE;
++    }
++    fman_rtc_set_periodic_pulse(p_Rtc->p_MemMap, p_FmRtcPeriodicPulseParams->periodicPulseId, (uint32_t)tmpFiper, enable);
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_ClearPeriodicPulse(t_Handle h_FmRtc, uint8_t periodicPulseId)
++{
++    t_FmRtc     *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    if (periodicPulseId >= FM_RTC_NUM_OF_PERIODIC_PULSES)
++    {
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse ID"));
++    }
++
++    p_Rtc->periodicPulseParams[periodicPulseId].f_PeriodicPulseCallback = NULL;
++    fman_rtc_clear_periodic_pulse(p_Rtc->p_MemMap, periodicPulseId);
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_SetExternalTrigger(t_Handle h_FmRtc, t_FmRtcExternalTriggerParams *p_FmRtcExternalTriggerParams)
++{
++    t_FmRtc     *p_Rtc = (t_FmRtc *)h_FmRtc;
++    bool        enable = FALSE;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    if (p_FmRtcExternalTriggerParams->externalTriggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
++    {
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External Trigger ID"));
++    }
++
++    if (p_FmRtcExternalTriggerParams->f_ExternalTriggerCallback)
++    {
++        p_Rtc->externalTriggerParams[p_FmRtcExternalTriggerParams->externalTriggerId].f_ExternalTriggerCallback = p_FmRtcExternalTriggerParams->f_ExternalTriggerCallback;
++        enable = TRUE;
++    }
++
++    fman_rtc_set_ext_trigger(p_Rtc->p_MemMap, p_FmRtcExternalTriggerParams->externalTriggerId, enable, p_FmRtcExternalTriggerParams->usePulseAsInput);
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_ClearExternalTrigger(t_Handle h_FmRtc, uint8_t externalTriggerId)
++{
++    t_FmRtc     *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    if (externalTriggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External Trigger ID"));
++
++    p_Rtc->externalTriggerParams[externalTriggerId].f_ExternalTriggerCallback = NULL;
++
++    fman_rtc_clear_external_trigger(p_Rtc->p_MemMap, externalTriggerId);
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_GetExternalTriggerTimeStamp(t_Handle             h_FmRtc,
++                                              uint8_t           triggerId,
++                                              uint64_t          *p_TimeStamp)
++{
++    t_FmRtc     *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    if (triggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
++        RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External trigger ID"));
++
++    *p_TimeStamp = fman_rtc_get_trigger_stamp(p_Rtc->p_MemMap, triggerId)*p_Rtc->clockPeriodNanoSec;
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_GetCurrentTime(t_Handle h_FmRtc, uint64_t *p_Ts)
++{
++    t_FmRtc     *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    *p_Ts = fman_rtc_get_timer(p_Rtc->p_MemMap)*p_Rtc->clockPeriodNanoSec;
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_SetCurrentTime(t_Handle h_FmRtc, uint64_t ts)
++{
++    t_FmRtc     *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    do_div(ts, p_Rtc->clockPeriodNanoSec);
++    fman_rtc_set_timer(p_Rtc->p_MemMap, (int64_t)ts);
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_GetFreqCompensation(t_Handle h_FmRtc, uint32_t *p_Compensation)
++{
++    t_FmRtc     *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    *p_Compensation = fman_rtc_get_frequency_compensation(p_Rtc->p_MemMap);
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_SetFreqCompensation(t_Handle h_FmRtc, uint32_t freqCompensation)
++{
++    t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++    SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++    /* set the new freqCompensation */
++    fman_rtc_set_frequency_compensation(p_Rtc->p_MemMap, freqCompensation);
++
++    return E_OK;
++}
++
++#ifdef CONFIG_PTP_1588_CLOCK_DPAA
++/*****************************************************************************/
++t_Error FM_RTC_EnableInterrupt(t_Handle h_FmRtc, uint32_t events)
++{
++      t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++      SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++      SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++      /* enable interrupt */
++      fman_rtc_enable_interupt(p_Rtc->p_MemMap, events);
++
++      return E_OK;
++}
++
++/*****************************************************************************/
++t_Error FM_RTC_DisableInterrupt(t_Handle h_FmRtc, uint32_t events)
++{
++      t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
++
++      SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
++      SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
++
++      /* disable interrupt */
++      fman_rtc_disable_interupt(p_Rtc->p_MemMap, events);
++
++      return E_OK;
++}
++#endif
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.h
+@@ -0,0 +1,96 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_rtc.h
++
++ @Description   Memory map and internal definitions for FM RTC IEEE1588 Timer driver.
++
++ @Cautions      None
++*//***************************************************************************/
++
++#ifndef __FM_RTC_H__
++#define __FM_RTC_H__
++
++#include "std_ext.h"
++#include "fm_rtc_ext.h"
++
++
++#define __ERR_MODULE__  MODULE_FM_RTC
++
++/* General definitions */
++
++#define ACCUMULATOR_OVERFLOW            ((uint64_t)(1LL << 32))
++#define DEFAULT_OUTPUT_CLOCK_DIVISOR     0x00000002
++#define DEFAULT_BYPASS                         FALSE
++#define DEFAULT_CLOCK_PERIOD             1000
++
++
++
++typedef struct t_FmRtcAlarm
++{
++    t_FmRtcExceptionsCallback   *f_AlarmCallback;
++    bool                        clearOnExpiration;
++} t_FmRtcAlarm;
++
++typedef struct t_FmRtcPeriodicPulse
++{
++    t_FmRtcExceptionsCallback   *f_PeriodicPulseCallback;
++} t_FmRtcPeriodicPulse;
++
++typedef struct t_FmRtcExternalTrigger
++{
++    t_FmRtcExceptionsCallback   *f_ExternalTriggerCallback;
++} t_FmRtcExternalTrigger;
++
++
++/**************************************************************************//**
++ @Description RTC FM driver control structure.
++*//***************************************************************************/
++typedef struct t_FmRtc
++{
++    t_Part                  *p_Part;            /**< Pointer to the integration device              */
++    t_Handle                h_Fm;
++    t_Handle                h_App;              /**< Application handle */
++    struct rtc_regs                   *p_MemMap;
++    uint32_t                clockPeriodNanoSec; /**< RTC clock period in nano-seconds (for FS mode) */
++    uint32_t                srcClkFreqMhz;
++    uint16_t                outputClockDivisor; /**< Output clock divisor (for FS mode) */
++    t_FmRtcAlarm            alarmParams[FM_RTC_NUM_OF_ALARMS];
++    t_FmRtcPeriodicPulse    periodicPulseParams[FM_RTC_NUM_OF_PERIODIC_PULSES];
++    t_FmRtcExternalTrigger  externalTriggerParams[FM_RTC_NUM_OF_EXT_TRIGGERS];
++    struct rtc_cfg                    *p_RtcDriverParam;  /**< RTC Driver parameters (for Init phase) */
++} t_FmRtc;
++
++
++#endif /* __FM_RTC_H__ */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fman_rtc.c
+@@ -0,0 +1,334 @@
++/*
++ * Copyright 2008-2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "fsl_fman_rtc.h"
++
++void fman_rtc_defconfig(struct rtc_cfg *cfg)
++{
++      int i;
++      cfg->src_clk = DEFAULT_SRC_CLOCK;
++      cfg->invert_input_clk_phase = DEFAULT_INVERT_INPUT_CLK_PHASE;
++      cfg->invert_output_clk_phase = DEFAULT_INVERT_OUTPUT_CLK_PHASE;
++      cfg->pulse_realign = DEFAULT_PULSE_REALIGN;
++      for (i = 0; i < FMAN_RTC_MAX_NUM_OF_ALARMS; i++)
++              cfg->alarm_polarity[i] = DEFAULT_ALARM_POLARITY;
++      for (i = 0; i < FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS; i++)
++              cfg->trigger_polarity[i] = DEFAULT_TRIGGER_POLARITY;
++}
++
++uint32_t fman_rtc_get_events(struct rtc_regs *regs)
++{
++      return ioread32be(&regs->tmr_tevent);
++}
++
++uint32_t fman_rtc_get_event(struct rtc_regs *regs, uint32_t ev_mask)
++{
++      return ioread32be(&regs->tmr_tevent) & ev_mask;
++}
++
++uint32_t fman_rtc_get_interrupt_mask(struct rtc_regs *regs)
++{
++      return ioread32be(&regs->tmr_temask);
++}
++
++void fman_rtc_set_interrupt_mask(struct rtc_regs *regs, uint32_t mask)
++{
++      iowrite32be(mask, &regs->tmr_temask);
++}
++
++void fman_rtc_ack_event(struct rtc_regs *regs, uint32_t events)
++{
++      iowrite32be(events, &regs->tmr_tevent);
++}
++
++uint32_t fman_rtc_check_and_clear_event(struct rtc_regs *regs)
++{
++      uint32_t event;
++
++      event = ioread32be(&regs->tmr_tevent);
++      event &= ioread32be(&regs->tmr_temask);
++
++      if (event)
++              iowrite32be(event, &regs->tmr_tevent);
++      return event;
++}
++
++uint32_t fman_rtc_get_frequency_compensation(struct rtc_regs *regs)
++{
++      return ioread32be(&regs->tmr_add);
++}
++
++void fman_rtc_set_frequency_compensation(struct rtc_regs *regs, uint32_t val)
++{
++      iowrite32be(val, &regs->tmr_add);
++}
++
++void fman_rtc_enable_interupt(struct rtc_regs *regs, uint32_t events)
++{
++      fman_rtc_set_interrupt_mask(regs, fman_rtc_get_interrupt_mask(regs) | events);
++}
++
++void fman_rtc_disable_interupt(struct rtc_regs *regs, uint32_t events)
++{
++      fman_rtc_set_interrupt_mask(regs, fman_rtc_get_interrupt_mask(regs) & ~events);
++}
++
++void fman_rtc_set_timer_alarm_l(struct rtc_regs *regs, int index, uint32_t val)
++{
++      iowrite32be(val, &regs->tmr_alarm[index].tmr_alarm_l);
++}
++
++void fman_rtc_set_timer_fiper(struct rtc_regs *regs, int index, uint32_t val)
++{
++      iowrite32be(val, &regs->tmr_fiper[index]);
++}
++
++void fman_rtc_set_timer_alarm(struct rtc_regs *regs, int index, int64_t val)
++{
++      iowrite32be((uint32_t)val, &regs->tmr_alarm[index].tmr_alarm_l);
++      iowrite32be((uint32_t)(val >> 32), &regs->tmr_alarm[index].tmr_alarm_h);
++}
++
++void fman_rtc_set_timer_offset(struct rtc_regs *regs, int64_t val)
++{
++      iowrite32be((uint32_t)val, &regs->tmr_off_l);
++      iowrite32be((uint32_t)(val >> 32), &regs->tmr_off_h);
++}
++
++uint64_t fman_rtc_get_trigger_stamp(struct rtc_regs *regs, int id)
++{
++      uint64_t time;
++      /* TMR_CNT_L must be read first to get an accurate value */
++      time = (uint64_t)ioread32be(&regs->tmr_etts[id].tmr_etts_l);
++      time |= ((uint64_t)ioread32be(&regs->tmr_etts[id].tmr_etts_h)
++              << 32);
++
++      return time;
++}
++
++uint32_t fman_rtc_get_timer_ctrl(struct rtc_regs *regs)
++{
++      return ioread32be(&regs->tmr_ctrl);
++}
++
++void fman_rtc_set_timer_ctrl(struct rtc_regs *regs, uint32_t val)
++{
++      iowrite32be(val, &regs->tmr_ctrl);
++}
++
++void fman_rtc_timers_soft_reset(struct rtc_regs *regs)
++{
++      fman_rtc_set_timer_ctrl(regs, FMAN_RTC_TMR_CTRL_TMSR);
++      udelay(10);
++      fman_rtc_set_timer_ctrl(regs, 0);
++}
++
++void fman_rtc_init(struct rtc_cfg *cfg, struct rtc_regs *regs, int num_alarms,
++              int num_fipers, int num_ext_triggers, bool init_freq_comp,
++              uint32_t freq_compensation, uint32_t output_clock_divisor)
++{
++      uint32_t            tmr_ctrl;
++      int                     i;
++
++      fman_rtc_timers_soft_reset(regs);
++
++      /* Set the source clock */
++      switch (cfg->src_clk) {
++      case E_FMAN_RTC_SOURCE_CLOCK_SYSTEM:
++              tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_MAC_CLK;
++              break;
++      case E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR:
++              tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_OSC_CLK;
++              break;
++      default:
++              /* Use a clock from the External TMR reference clock.*/
++              tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_EXT_CLK;
++              break;
++      }
++
++      /* whatever period the user picked, the timestamp will advance in '1'
++      * every time the period passed. */
++      tmr_ctrl |= ((1 << FMAN_RTC_TMR_CTRL_TCLK_PERIOD_SHIFT) &
++                              FMAN_RTC_TMR_CTRL_TCLK_PERIOD_MASK);
++
++      if (cfg->invert_input_clk_phase)
++              tmr_ctrl |= FMAN_RTC_TMR_CTRL_CIPH;
++      if (cfg->invert_output_clk_phase)
++              tmr_ctrl |= FMAN_RTC_TMR_CTRL_COPH;
++
++      for (i = 0; i < num_alarms; i++) {
++              if (cfg->alarm_polarity[i] ==
++                      E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW)
++                      tmr_ctrl |= (FMAN_RTC_TMR_CTRL_ALMP1 >> i);
++      }
++
++      for (i = 0; i < num_ext_triggers; i++)
++              if (cfg->trigger_polarity[i] ==
++                      E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE)
++                      tmr_ctrl |= (FMAN_RTC_TMR_CTRL_ETEP1 << i);
++
++      if (!cfg->timer_slave_mode && cfg->bypass)
++              tmr_ctrl |= FMAN_RTC_TMR_CTRL_BYP;
++
++      fman_rtc_set_timer_ctrl(regs, tmr_ctrl);
++      if (init_freq_comp)
++              fman_rtc_set_frequency_compensation(regs, freq_compensation);
++
++      /* Clear TMR_ALARM registers */
++      for (i = 0; i < num_alarms; i++)
++              fman_rtc_set_timer_alarm(regs, i, 0xFFFFFFFFFFFFFFFFLL);
++
++      /* Clear TMR_TEVENT */
++      fman_rtc_ack_event(regs, FMAN_RTC_TMR_TEVENT_ALL);
++
++      /* Initialize TMR_TEMASK */
++      fman_rtc_set_interrupt_mask(regs, 0);
++
++      /* Clear TMR_FIPER registers */
++      for (i = 0; i < num_fipers; i++)
++              fman_rtc_set_timer_fiper(regs, i, 0xFFFFFFFF);
++
++      /* Initialize TMR_PRSC */
++      iowrite32be(output_clock_divisor, &regs->tmr_prsc);
++
++      /* Clear TMR_OFF */
++      fman_rtc_set_timer_offset(regs, 0);
++}
++
++bool fman_rtc_is_enabled(struct rtc_regs *regs)
++{
++      return (bool)(fman_rtc_get_timer_ctrl(regs) & FMAN_RTC_TMR_CTRL_TE);
++}
++
++void fman_rtc_enable(struct rtc_regs *regs, bool reset_clock)
++{
++      uint32_t tmr_ctrl = fman_rtc_get_timer_ctrl(regs);
++
++      /* TODO check that no timestamping MACs are working in this stage. */
++      if (reset_clock) {
++              fman_rtc_set_timer_ctrl(regs, (tmr_ctrl | FMAN_RTC_TMR_CTRL_TMSR));
++
++              udelay(10);
++              /* Clear TMR_OFF */
++              fman_rtc_set_timer_offset(regs, 0);
++      }
++
++      fman_rtc_set_timer_ctrl(regs, (tmr_ctrl | FMAN_RTC_TMR_CTRL_TE));
++}
++
++void fman_rtc_disable(struct rtc_regs *regs)
++{
++      fman_rtc_set_timer_ctrl(regs, (fman_rtc_get_timer_ctrl(regs)
++                                      & ~(FMAN_RTC_TMR_CTRL_TE)));
++}
++
++void fman_rtc_clear_periodic_pulse(struct rtc_regs *regs, int id)
++{
++      uint32_t tmp_reg;
++      if (id == 0)
++              tmp_reg = FMAN_RTC_TMR_TEVENT_PP1;
++      else
++              tmp_reg = FMAN_RTC_TMR_TEVENT_PP2;
++      fman_rtc_disable_interupt(regs, tmp_reg);
++
++      tmp_reg = fman_rtc_get_timer_ctrl(regs);
++      if (tmp_reg & FMAN_RTC_TMR_CTRL_FS)
++              fman_rtc_set_timer_ctrl(regs, tmp_reg & ~FMAN_RTC_TMR_CTRL_FS);
++
++      fman_rtc_set_timer_fiper(regs, id, 0xFFFFFFFF);
++}
++
++void fman_rtc_clear_external_trigger(struct rtc_regs *regs, int id)
++{
++      uint32_t    tmpReg, tmp_ctrl;
++
++      if (id == 0)
++              tmpReg = FMAN_RTC_TMR_TEVENT_ETS1;
++      else
++              tmpReg = FMAN_RTC_TMR_TEVENT_ETS2;
++      fman_rtc_disable_interupt(regs, tmpReg);
++
++      if (id == 0)
++              tmpReg = FMAN_RTC_TMR_CTRL_PP1L;
++      else
++              tmpReg = FMAN_RTC_TMR_CTRL_PP2L;
++      tmp_ctrl = fman_rtc_get_timer_ctrl(regs);
++      if (tmp_ctrl & tmpReg)
++              fman_rtc_set_timer_ctrl(regs, tmp_ctrl & ~tmpReg);
++}
++
++void fman_rtc_set_alarm(struct rtc_regs *regs, int id, uint32_t val, bool enable)
++{
++      uint32_t    tmpReg;
++      fman_rtc_set_timer_alarm(regs, id, val);
++      if (enable) {
++              if (id == 0)
++                      tmpReg = FMAN_RTC_TMR_TEVENT_ALM1;
++              else
++                      tmpReg = FMAN_RTC_TMR_TEVENT_ALM2;
++              fman_rtc_enable_interupt(regs, tmpReg);
++      }
++}
++
++void fman_rtc_set_periodic_pulse(struct rtc_regs *regs, int id, uint32_t val,
++                                              bool enable)
++{
++      uint32_t    tmpReg;
++      fman_rtc_set_timer_fiper(regs, id, val);
++      if (enable) {
++              if (id == 0)
++                      tmpReg = FMAN_RTC_TMR_TEVENT_PP1;
++              else
++                      tmpReg = FMAN_RTC_TMR_TEVENT_PP2;
++              fman_rtc_enable_interupt(regs, tmpReg);
++      }
++}
++
++void fman_rtc_set_ext_trigger(struct rtc_regs *regs, int id, bool enable,
++                                              bool use_pulse_as_input)
++{
++      uint32_t    tmpReg;
++      if (enable) {
++              if (id == 0)
++                      tmpReg = FMAN_RTC_TMR_TEVENT_ETS1;
++              else
++                      tmpReg = FMAN_RTC_TMR_TEVENT_ETS2;
++              fman_rtc_enable_interupt(regs, tmpReg);
++      }
++      if (use_pulse_as_input) {
++              if (id == 0)
++                      tmpReg = FMAN_RTC_TMR_CTRL_PP1L;
++              else
++                      tmpReg = FMAN_RTC_TMR_CTRL_PP2L;
++              fman_rtc_set_timer_ctrl(regs, fman_rtc_get_timer_ctrl(regs) | tmpReg);
++      }
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/Makefile
+@@ -0,0 +1,15 @@
++#
++# Makefile for the Freescale Ethernet controllers
++#
++ccflags-y           += -DVERSION=\"\"
++#
++#Include netcomm SW specific definitions
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++
++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
++
++ccflags-y += -I$(NCSW_FM_INC)
++
++obj-y         += fsl-ncsw-sp.o
++
++fsl-ncsw-sp-objs      := fm_sp.o fman_sp.o
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.c
+@@ -0,0 +1,757 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_sp.c
++
++ @Description   FM PCD Storage profile  ...
++*//***************************************************************************/
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "string_ext.h"
++#include "debug_ext.h"
++#include "net_ext.h"
++
++#include "fm_vsp_ext.h"
++#include "fm_sp.h"
++#include "fm_common.h"
++#include "fsl_fman_sp.h"
++
++
++#if (DPAA_VERSION >= 11)
++static t_Error CheckParamsGeneratedInternally(t_FmVspEntry *p_FmVspEntry)
++{
++    t_Error err = E_OK;
++
++    if ((err = FmSpCheckIntContextParams(&p_FmVspEntry->intContext))!= E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    if ((err =  FmSpCheckBufMargins(&p_FmVspEntry->bufMargins)) != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    return err;
++
++}
++
++static t_Error CheckParams(t_FmVspEntry *p_FmVspEntry)
++{
++    t_Error err = E_OK;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->h_Fm, E_INVALID_HANDLE);
++
++    if ((err = FmSpCheckBufPoolsParams(&p_FmVspEntry->p_FmVspEntryDriverParams->extBufPools,
++                                        p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools,
++                                        p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion)) != E_OK)
++
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++    if (p_FmVspEntry->p_FmVspEntryDriverParams->liodnOffset & ~FM_LIODN_OFFSET_MASK)
++         RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1));
++
++    err = FmVSPCheckRelativeProfile(p_FmVspEntry->h_Fm,
++                                    p_FmVspEntry->portType,
++                                    p_FmVspEntry->portId,
++                                    p_FmVspEntry->relativeProfileId);
++
++    return err;
++}
++#endif /* (DPAA_VERSION >= 11) */
++
++
++/*****************************************************************************/
++/*              Inter-module API routines                                    */
++/*****************************************************************************/
++void FmSpSetBufPoolsInAscOrderOfBufSizes(t_FmExtPools   *p_FmExtPools,
++                                         uint8_t        *orderedArray,
++                                         uint16_t       *sizesArray)
++{
++    uint16_t                    bufSize = 0;
++    int                         i=0, j=0, k=0;
++
++    /* First we copy the external buffers pools information to an ordered local array */
++    for (i=0;i<p_FmExtPools->numOfPoolsUsed;i++)
++    {
++        /* get pool size */
++        bufSize = p_FmExtPools->extBufPool[i].size;
++
++        /* keep sizes in an array according to poolId for direct access */
++        sizesArray[p_FmExtPools->extBufPool[i].id] =  bufSize;
++
++        /* save poolId in an ordered array according to size */
++        for (j=0;j<=i;j++)
++        {
++            /* this is the next free place in the array */
++            if (j==i)
++                orderedArray[i] = p_FmExtPools->extBufPool[i].id;
++            else
++            {
++                /* find the right place for this poolId */
++                if (bufSize < sizesArray[orderedArray[j]])
++                {
++                    /* move the poolIds one place ahead to make room for this poolId */
++                    for (k=i;k>j;k--)
++                       orderedArray[k] = orderedArray[k-1];
++
++                    /* now k==j, this is the place for the new size */
++                    orderedArray[k] = p_FmExtPools->extBufPool[i].id;
++                    break;
++                }
++            }
++        }
++    }
++}
++
++t_Error FmSpCheckBufPoolsParams(t_FmExtPools            *p_FmExtPools,
++                                t_FmBackupBmPools       *p_FmBackupBmPools,
++                                t_FmBufPoolDepletion    *p_FmBufPoolDepletion)
++{
++
++    int         i = 0, j = 0;
++    bool        found;
++    uint8_t     count = 0;
++
++    if (p_FmExtPools)
++    {
++        if (p_FmExtPools->numOfPoolsUsed > FM_PORT_MAX_NUM_OF_EXT_POOLS)
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfPoolsUsed can't be larger than %d", FM_PORT_MAX_NUM_OF_EXT_POOLS));
++
++        for (i=0;i<p_FmExtPools->numOfPoolsUsed;i++)
++        {
++            if (p_FmExtPools->extBufPool[i].id >= BM_MAX_NUM_OF_POOLS)
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("extBufPools.extBufPool[%d].id can't be larger than %d", i, BM_MAX_NUM_OF_POOLS));
++            if (!p_FmExtPools->extBufPool[i].size)
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("extBufPools.extBufPool[%d].size is 0", i));
++        }
++    }
++    if (!p_FmExtPools && (p_FmBackupBmPools || p_FmBufPoolDepletion))
++          RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("backupBmPools ot bufPoolDepletion can not be defined without external pools"));
++
++    /* backup BM pools indication is valid only for some chip derivatives
++       (limited by the config routine) */
++    if (p_FmBackupBmPools)
++    {
++        if (p_FmBackupBmPools->numOfBackupPools >= p_FmExtPools->numOfPoolsUsed)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_BackupBmPools must be smaller than extBufPools.numOfPoolsUsed"));
++        found = FALSE;
++        for (i = 0;i<p_FmBackupBmPools->numOfBackupPools;i++)
++        {
++
++            for (j=0;j<p_FmExtPools->numOfPoolsUsed;j++)
++            {
++                if (p_FmBackupBmPools->poolIds[i] == p_FmExtPools->extBufPool[j].id)
++                {
++                    found = TRUE;
++                    break;
++                }
++            }
++            if (!found)
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("All p_BackupBmPools.poolIds must be included in extBufPools.extBufPool[n].id"));
++            else
++                found = FALSE;
++        }
++    }
++
++    /* up to extBufPools.numOfPoolsUsed pools may be defined */
++    if (p_FmBufPoolDepletion && p_FmBufPoolDepletion->poolsGrpModeEnable)
++    {
++        if ((p_FmBufPoolDepletion->numOfPools > p_FmExtPools->numOfPoolsUsed))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPools can't be larger than %d and can't be larger than numOfPoolsUsed", FM_PORT_MAX_NUM_OF_EXT_POOLS));
++
++        if (!p_FmBufPoolDepletion->numOfPools)
++          RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPoolsToConsider can not be 0 when poolsGrpModeEnable=TRUE"));
++
++        found = FALSE;
++        count = 0;
++        /* for each pool that is in poolsToConsider, check if it is defined
++           in extBufPool */
++        for (i=0;i<BM_MAX_NUM_OF_POOLS;i++)
++        {
++            if (p_FmBufPoolDepletion->poolsToConsider[i])
++            {
++                for (j=0;j<p_FmExtPools->numOfPoolsUsed;j++)
++                 {
++                    if (i == p_FmExtPools->extBufPool[j].id)
++                    {
++                        found = TRUE;
++                        count++;
++                        break;
++                    }
++                 }
++                if (!found)
++                    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Pools selected for depletion are not used."));
++                else
++                    found = FALSE;
++            }
++        }
++        /* check that the number of pools that we have checked is equal to the number announced by the user */
++        if (count != p_FmBufPoolDepletion->numOfPools)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPools is larger than the number of pools defined."));
++    }
++
++    if (p_FmBufPoolDepletion && p_FmBufPoolDepletion->singlePoolModeEnable)
++    {
++        /* calculate vector for number of pools depletion */
++        found = FALSE;
++        count = 0;
++        for (i=0;i<BM_MAX_NUM_OF_POOLS;i++)
++        {
++            if (p_FmBufPoolDepletion->poolsToConsiderForSingleMode[i])
++            {
++                for (j=0;j<p_FmExtPools->numOfPoolsUsed;j++)
++                {
++                    if (i == p_FmExtPools->extBufPool[j].id)
++                    {
++                        found = TRUE;
++                        count++;
++                        break;
++                    }
++                }
++                if (!found)
++                    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Pools selected for depletion are not used."));
++                else
++                    found = FALSE;
++            }
++        }
++        if (!count)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("No pools defined for single buffer mode pool depletion."));
++    }
++
++    return E_OK;
++}
++
++t_Error FmSpCheckIntContextParams(t_FmSpIntContextDataCopy *p_FmSpIntContextDataCopy)
++{
++    /* Check that divisible by 16 and not larger than 240 */
++    if (p_FmSpIntContextDataCopy->intContextOffset >MAX_INT_OFFSET)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.intContextOffset can't be larger than %d", MAX_INT_OFFSET));
++    if (p_FmSpIntContextDataCopy->intContextOffset % OFFSET_UNITS)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.intContextOffset has to be divisible by %d", OFFSET_UNITS));
++
++    /* check that ic size+ic internal offset, does not exceed ic block size */
++    if (p_FmSpIntContextDataCopy->size + p_FmSpIntContextDataCopy->intContextOffset > MAX_IC_SIZE)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.size + intContext.intContextOffset has to be smaller than %d", MAX_IC_SIZE));
++    /* Check that divisible by 16 and not larger than 256 */
++    if (p_FmSpIntContextDataCopy->size % OFFSET_UNITS)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.size  has to be divisible by %d", OFFSET_UNITS));
++
++    /* Check that divisible by 16 and not larger than 4K */
++    if (p_FmSpIntContextDataCopy->extBufOffset > MAX_EXT_OFFSET)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.extBufOffset can't be larger than %d", MAX_EXT_OFFSET));
++    if (p_FmSpIntContextDataCopy->extBufOffset % OFFSET_UNITS)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.extBufOffset  has to be divisible by %d", OFFSET_UNITS));
++
++    return E_OK;
++}
++
++t_Error FmSpCheckBufMargins(t_FmSpBufMargins *p_FmSpBufMargins)
++{
++    /* Check the margin definition */
++    if (p_FmSpBufMargins->startMargins > MAX_EXT_BUFFER_OFFSET)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufMargins.startMargins can't be larger than %d", MAX_EXT_BUFFER_OFFSET));
++    if (p_FmSpBufMargins->endMargins > MAX_EXT_BUFFER_OFFSET)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufMargins.endMargins can't be larger than %d", MAX_EXT_BUFFER_OFFSET));
++
++    return E_OK;
++}
++
++t_Error FmSpBuildBufferStructure(t_FmSpIntContextDataCopy   *p_FmSpIntContextDataCopy,
++                                 t_FmBufferPrefixContent     *p_BufferPrefixContent,
++                                 t_FmSpBufMargins            *p_FmSpBufMargins,
++                                 t_FmSpBufferOffsets         *p_FmSpBufferOffsets,
++                                 uint8_t                     *internalBufferOffset)
++{
++    uint32_t                        tmp;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmSpIntContextDataCopy,  E_INVALID_VALUE);
++    ASSERT_COND(p_FmSpIntContextDataCopy);
++    ASSERT_COND(p_BufferPrefixContent);
++    ASSERT_COND(p_FmSpBufMargins);
++    ASSERT_COND(p_FmSpBufferOffsets);
++
++    /* Align start of internal context data to 16 byte */
++    p_FmSpIntContextDataCopy->extBufOffset =
++        (uint16_t)((p_BufferPrefixContent->privDataSize & (OFFSET_UNITS-1)) ?
++            ((p_BufferPrefixContent->privDataSize + OFFSET_UNITS) & ~(uint16_t)(OFFSET_UNITS-1)) :
++             p_BufferPrefixContent->privDataSize);
++
++    /* Translate margin and intContext params to FM parameters */
++    /* Initialize with illegal value. Later we'll set legal values. */
++    p_FmSpBufferOffsets->prsResultOffset = (uint32_t)ILLEGAL_BASE;
++    p_FmSpBufferOffsets->timeStampOffset = (uint32_t)ILLEGAL_BASE;
++    p_FmSpBufferOffsets->hashResultOffset= (uint32_t)ILLEGAL_BASE;
++    p_FmSpBufferOffsets->pcdInfoOffset   = (uint32_t)ILLEGAL_BASE;
++
++    /* Internally the driver supports 4 options
++       1. prsResult/timestamp/hashResult selection (in fact 8 options, but for simplicity we'll
++          relate to it as 1).
++       2. All IC context (from AD) not including debug.*/
++
++    /* This 'if' covers option 2. We copy from beginning of context. */
++    if (p_BufferPrefixContent->passAllOtherPCDInfo)
++    {
++        p_FmSpIntContextDataCopy->size = 128; /* must be aligned to 16 */
++        /* Start copying data after 16 bytes (FD) from the beginning of the internal context */
++        p_FmSpIntContextDataCopy->intContextOffset = 16;
++
++        if (p_BufferPrefixContent->passAllOtherPCDInfo)
++            p_FmSpBufferOffsets->pcdInfoOffset = p_FmSpIntContextDataCopy->extBufOffset;
++        if (p_BufferPrefixContent->passPrsResult)
++            p_FmSpBufferOffsets->prsResultOffset =
++                (uint32_t)(p_FmSpIntContextDataCopy->extBufOffset + 16);
++        if (p_BufferPrefixContent->passTimeStamp)
++            p_FmSpBufferOffsets->timeStampOffset =
++                (uint32_t)(p_FmSpIntContextDataCopy->extBufOffset + 48);
++        if (p_BufferPrefixContent->passHashResult)
++            p_FmSpBufferOffsets->hashResultOffset =
++                (uint32_t)(p_FmSpIntContextDataCopy->extBufOffset + 56);
++    }
++    else
++    {
++        /* This case covers the options under 1 */
++        /* Copy size must be in 16-byte granularity. */
++        p_FmSpIntContextDataCopy->size =
++            (uint16_t)((p_BufferPrefixContent->passPrsResult ? 32 : 0) +
++                      ((p_BufferPrefixContent->passTimeStamp ||
++                      p_BufferPrefixContent->passHashResult) ? 16 : 0));
++
++        /* Align start of internal context data to 16 byte */
++        p_FmSpIntContextDataCopy->intContextOffset =
++            (uint8_t)(p_BufferPrefixContent->passPrsResult ? 32 :
++                      ((p_BufferPrefixContent->passTimeStamp  ||
++                       p_BufferPrefixContent->passHashResult) ? 64 : 0));
++
++        if (p_BufferPrefixContent->passPrsResult)
++            p_FmSpBufferOffsets->prsResultOffset = p_FmSpIntContextDataCopy->extBufOffset;
++        if (p_BufferPrefixContent->passTimeStamp)
++            p_FmSpBufferOffsets->timeStampOffset =  p_BufferPrefixContent->passPrsResult ?
++                                        (p_FmSpIntContextDataCopy->extBufOffset + sizeof(t_FmPrsResult)) :
++                                        p_FmSpIntContextDataCopy->extBufOffset;
++        if (p_BufferPrefixContent->passHashResult)
++            /* If PR is not requested, whether TS is requested or not, IC will be copied from TS */
++            p_FmSpBufferOffsets->hashResultOffset = p_BufferPrefixContent->passPrsResult ?
++                                          (p_FmSpIntContextDataCopy->extBufOffset + sizeof(t_FmPrsResult) + 8) :
++                                          p_FmSpIntContextDataCopy->extBufOffset + 8;
++    }
++
++    if (p_FmSpIntContextDataCopy->size)
++        p_FmSpBufMargins->startMargins =
++            (uint16_t)(p_FmSpIntContextDataCopy->extBufOffset +
++                       p_FmSpIntContextDataCopy->size);
++    else
++        /* No Internal Context passing, STartMargin is immediately after privateInfo */
++        p_FmSpBufMargins->startMargins = p_BufferPrefixContent->privDataSize;
++
++    /* save extra space for manip in both external and internal buffers */
++    if (p_BufferPrefixContent->manipExtraSpace)
++    {
++        uint8_t extraSpace;
++#ifdef FM_CAPWAP_SUPPORT
++        if ((p_BufferPrefixContent->manipExtraSpace + CAPWAP_FRAG_EXTRA_SPACE) >= 256)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                         ("p_BufferPrefixContent->manipExtraSpace should be less than %d",
++                          256-CAPWAP_FRAG_EXTRA_SPACE));
++        extraSpace = (uint8_t)(p_BufferPrefixContent->manipExtraSpace + CAPWAP_FRAG_EXTRA_SPACE);
++#else
++        extraSpace = p_BufferPrefixContent->manipExtraSpace;
++#endif /* FM_CAPWAP_SUPPORT */
++        p_FmSpBufferOffsets->manipOffset = p_FmSpBufMargins->startMargins;
++        p_FmSpBufMargins->startMargins += extraSpace;
++        *internalBufferOffset = extraSpace;
++    }
++
++    /* align data start */
++    tmp = (uint32_t)(p_FmSpBufMargins->startMargins % p_BufferPrefixContent->dataAlign);
++    if (tmp)
++        p_FmSpBufMargins->startMargins += (p_BufferPrefixContent->dataAlign-tmp);
++    p_FmSpBufferOffsets->dataOffset = p_FmSpBufMargins->startMargins;
++
++    return E_OK;
++}
++/*********************** End of inter-module routines ************************/
++
++
++#if (DPAA_VERSION >= 11)
++/*****************************************************************************/
++/*              API routines                                                 */
++/*****************************************************************************/
++t_Handle FM_VSP_Config(t_FmVspParams *p_FmVspParams)
++{
++    t_FmVspEntry          *p_FmVspEntry = NULL;
++    struct fm_storage_profile_params   fm_vsp_params;
++
++    p_FmVspEntry = (t_FmVspEntry *)XX_Malloc(sizeof(t_FmVspEntry));
++    if (!p_FmVspEntry)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_StorageProfile allocation failed"));
++        return NULL;
++    }
++    memset(p_FmVspEntry, 0, sizeof(t_FmVspEntry));
++
++    p_FmVspEntry->p_FmVspEntryDriverParams = (t_FmVspEntryDriverParams *)XX_Malloc(sizeof(t_FmVspEntryDriverParams));
++    if (!p_FmVspEntry->p_FmVspEntryDriverParams)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_StorageProfile allocation failed"));
++        XX_Free(p_FmVspEntry);
++        return NULL;
++    }
++    memset(p_FmVspEntry->p_FmVspEntryDriverParams, 0, sizeof(t_FmVspEntryDriverParams));
++    fman_vsp_defconfig(&fm_vsp_params);
++    p_FmVspEntry->p_FmVspEntryDriverParams->dmaHeaderCacheAttr = fm_vsp_params.header_cache_attr;
++    p_FmVspEntry->p_FmVspEntryDriverParams->dmaIntContextCacheAttr = fm_vsp_params.int_context_cache_attr;
++    p_FmVspEntry->p_FmVspEntryDriverParams->dmaScatterGatherCacheAttr = fm_vsp_params.scatter_gather_cache_attr;
++    p_FmVspEntry->p_FmVspEntryDriverParams->dmaSwapData = fm_vsp_params.dma_swap_data;
++    p_FmVspEntry->p_FmVspEntryDriverParams->dmaWriteOptimize = fm_vsp_params.dma_write_optimize;
++    p_FmVspEntry->p_FmVspEntryDriverParams->noScatherGather = fm_vsp_params.no_scather_gather;
++    p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.privDataSize = DEFAULT_FM_SP_bufferPrefixContent_privDataSize;
++    p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.passPrsResult= DEFAULT_FM_SP_bufferPrefixContent_passPrsResult;
++    p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.passTimeStamp= DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp;
++    p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.passAllOtherPCDInfo
++                                                                    = DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp;
++    p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.dataAlign    = DEFAULT_FM_SP_bufferPrefixContent_dataAlign;
++    p_FmVspEntry->p_FmVspEntryDriverParams->liodnOffset                      = p_FmVspParams->liodnOffset;
++
++    memcpy(&p_FmVspEntry->p_FmVspEntryDriverParams->extBufPools, &p_FmVspParams->extBufPools, sizeof(t_FmExtPools));
++    p_FmVspEntry->h_Fm                                                       = p_FmVspParams->h_Fm;
++    p_FmVspEntry->portType                                                   = p_FmVspParams->portParams.portType;
++    p_FmVspEntry->portId                                                     = p_FmVspParams->portParams.portId;
++
++    p_FmVspEntry->relativeProfileId                                          = p_FmVspParams->relativeProfileId;
++
++   return p_FmVspEntry;
++}
++
++t_Error FM_VSP_Init(t_Handle h_FmVsp)
++{
++
++    t_FmVspEntry                *p_FmVspEntry = (t_FmVspEntry *)h_FmVsp;
++    struct fm_storage_profile_params   fm_vsp_params;
++    uint8_t                     orderedArray[FM_PORT_MAX_NUM_OF_EXT_POOLS];
++    uint16_t                    sizesArray[BM_MAX_NUM_OF_POOLS];
++    t_Error                     err;
++    uint16_t                    absoluteProfileId = 0;
++    int                         i = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams,E_INVALID_HANDLE);
++
++    CHECK_INIT_PARAMETERS(p_FmVspEntry, CheckParams);
++
++    memset(&orderedArray, 0, sizeof(uint8_t) * FM_PORT_MAX_NUM_OF_EXT_POOLS);
++    memset(&sizesArray, 0, sizeof(uint16_t) * BM_MAX_NUM_OF_POOLS);
++
++    err = FmSpBuildBufferStructure(&p_FmVspEntry->intContext,
++                                   &p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent,
++                                   &p_FmVspEntry->bufMargins,
++                                   &p_FmVspEntry->bufferOffsets,
++                                   &p_FmVspEntry->internalBufferOffset);
++    if (err != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++
++    err = CheckParamsGeneratedInternally(p_FmVspEntry);
++    if (err != E_OK)
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++
++
++     p_FmVspEntry->p_FmSpRegsBase =
++        (struct fm_pcd_storage_profile_regs *)FmGetVSPBaseAddr(p_FmVspEntry->h_Fm);
++    if (!p_FmVspEntry->p_FmSpRegsBase)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("impossible to initialize SpRegsBase"));
++
++    /* order external buffer pools in ascending order of buffer pools sizes */
++    FmSpSetBufPoolsInAscOrderOfBufSizes(&(p_FmVspEntry->p_FmVspEntryDriverParams)->extBufPools,
++                                        orderedArray,
++                                        sizesArray);
++
++    p_FmVspEntry->extBufPools.numOfPoolsUsed =
++        p_FmVspEntry->p_FmVspEntryDriverParams->extBufPools.numOfPoolsUsed;
++    for (i = 0; i < p_FmVspEntry->extBufPools.numOfPoolsUsed; i++)
++    {
++       p_FmVspEntry->extBufPools.extBufPool[i].id = orderedArray[i];
++       p_FmVspEntry->extBufPools.extBufPool[i].size = sizesArray[orderedArray[i]];
++    }
++
++    /* on user responsibility to fill it according requirement */
++    memset(&fm_vsp_params, 0, sizeof(struct fm_storage_profile_params));
++    fm_vsp_params.dma_swap_data              = p_FmVspEntry->p_FmVspEntryDriverParams->dmaSwapData;
++    fm_vsp_params.int_context_cache_attr     = p_FmVspEntry->p_FmVspEntryDriverParams->dmaIntContextCacheAttr;
++    fm_vsp_params.header_cache_attr          = p_FmVspEntry->p_FmVspEntryDriverParams->dmaHeaderCacheAttr;
++    fm_vsp_params.scatter_gather_cache_attr  = p_FmVspEntry->p_FmVspEntryDriverParams->dmaScatterGatherCacheAttr;
++    fm_vsp_params.dma_write_optimize         = p_FmVspEntry->p_FmVspEntryDriverParams->dmaWriteOptimize;
++    fm_vsp_params.liodn_offset               = p_FmVspEntry->p_FmVspEntryDriverParams->liodnOffset;
++    fm_vsp_params.no_scather_gather          = p_FmVspEntry->p_FmVspEntryDriverParams->noScatherGather;
++
++    if (p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion)
++    {
++        fm_vsp_params.buf_pool_depletion.buf_pool_depletion_enabled = TRUE;
++        fm_vsp_params.buf_pool_depletion.pools_grp_mode_enable = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->poolsGrpModeEnable;
++        fm_vsp_params.buf_pool_depletion.num_pools = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->numOfPools;
++        fm_vsp_params.buf_pool_depletion.pools_to_consider = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->poolsToConsider;
++        fm_vsp_params.buf_pool_depletion.single_pool_mode_enable = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->singlePoolModeEnable;
++        fm_vsp_params.buf_pool_depletion.pools_to_consider_for_single_mode = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->poolsToConsiderForSingleMode;
++        fm_vsp_params.buf_pool_depletion.has_pfc_priorities = TRUE;
++        fm_vsp_params.buf_pool_depletion.pfc_priorities_en = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->pfcPrioritiesEn;
++    }
++    else
++        fm_vsp_params.buf_pool_depletion.buf_pool_depletion_enabled = FALSE;
++ 
++    if (p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools)
++    {
++        fm_vsp_params.backup_pools.num_backup_pools = p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools->numOfBackupPools;
++        fm_vsp_params.backup_pools.pool_ids = p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools->poolIds;
++    }
++    else
++        fm_vsp_params.backup_pools.num_backup_pools = 0;
++
++    fm_vsp_params.fm_ext_pools.num_pools_used = p_FmVspEntry->extBufPools.numOfPoolsUsed;
++    fm_vsp_params.fm_ext_pools.ext_buf_pool = (struct fman_ext_pool_params*)&p_FmVspEntry->extBufPools.extBufPool;
++    fm_vsp_params.buf_margins = (struct fman_sp_buf_margins*)&p_FmVspEntry->bufMargins;
++    fm_vsp_params.int_context = (struct fman_sp_int_context_data_copy*)&p_FmVspEntry->intContext;
++
++    /* no check on err - it was checked earlier */
++    FmVSPGetAbsoluteProfileId(p_FmVspEntry->h_Fm,
++                              p_FmVspEntry->portType,
++                              p_FmVspEntry->portId,
++                              p_FmVspEntry->relativeProfileId,
++                              &absoluteProfileId);
++
++    ASSERT_COND(p_FmVspEntry->p_FmSpRegsBase);
++    ASSERT_COND(fm_vsp_params.int_context);
++    ASSERT_COND(fm_vsp_params.buf_margins);
++    ASSERT_COND((absoluteProfileId <= FM_VSP_MAX_NUM_OF_ENTRIES));
++
++    /* Set all registers related to VSP */
++    fman_vsp_init(p_FmVspEntry->p_FmSpRegsBase, absoluteProfileId, &fm_vsp_params,FM_PORT_MAX_NUM_OF_EXT_POOLS, BM_MAX_NUM_OF_POOLS, FM_MAX_NUM_OF_PFC_PRIORITIES);
++
++    p_FmVspEntry->absoluteSpId = absoluteProfileId;
++
++    if (p_FmVspEntry->p_FmVspEntryDriverParams)
++        XX_Free(p_FmVspEntry->p_FmVspEntryDriverParams);
++    p_FmVspEntry->p_FmVspEntryDriverParams = NULL;
++
++    return E_OK;
++}
++
++t_Error FM_VSP_Free(t_Handle h_FmVsp)
++{
++    t_FmVspEntry   *p_FmVspEntry = (t_FmVspEntry *)h_FmVsp;
++    SANITY_CHECK_RETURN_ERROR(h_FmVsp, E_INVALID_HANDLE);
++    XX_Free(p_FmVspEntry);
++    return E_OK;
++}
++
++t_Error FM_VSP_ConfigBufferPrefixContent(t_Handle h_FmVsp, t_FmBufferPrefixContent *p_FmBufferPrefixContent)
++{
++    t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
++
++    memcpy(&p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent, p_FmBufferPrefixContent, sizeof(t_FmBufferPrefixContent));
++    /* if dataAlign was not initialized by user, we return to driver's default */
++    if (!p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.dataAlign)
++        p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.dataAlign = DEFAULT_FM_SP_bufferPrefixContent_dataAlign;
++
++    return E_OK;
++}
++
++t_Error FM_VSP_ConfigDmaSwapData(t_Handle h_FmVsp, e_FmDmaSwapOption swapData)
++{
++    t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
++
++    p_FmVspEntry->p_FmVspEntryDriverParams->dmaSwapData = swapData;
++
++    return E_OK;
++}
++
++t_Error FM_VSP_ConfigDmaIcCacheAttr(t_Handle h_FmVsp, e_FmDmaCacheOption intContextCacheAttr)
++{
++    t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
++
++    p_FmVspEntry->p_FmVspEntryDriverParams->dmaIntContextCacheAttr = intContextCacheAttr;
++
++    return E_OK;
++}
++
++t_Error FM_VSP_ConfigDmaHdrAttr(t_Handle h_FmVsp, e_FmDmaCacheOption headerCacheAttr)
++{
++    t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
++
++    p_FmVspEntry->p_FmVspEntryDriverParams->dmaHeaderCacheAttr = headerCacheAttr;
++
++    return E_OK;
++}
++
++t_Error FM_VSP_ConfigDmaScatterGatherAttr(t_Handle h_FmVsp, e_FmDmaCacheOption scatterGatherCacheAttr)
++{
++    t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
++
++     p_FmVspEntry->p_FmVspEntryDriverParams->dmaScatterGatherCacheAttr = scatterGatherCacheAttr;
++
++    return E_OK;
++}
++
++t_Error FM_VSP_ConfigDmaWriteOptimize(t_Handle h_FmVsp, bool optimize)
++{
++    t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
++
++
++    p_FmVspEntry->p_FmVspEntryDriverParams->dmaWriteOptimize = optimize;
++
++    return E_OK;
++}
++
++t_Error FM_VSP_ConfigNoScatherGather(t_Handle h_FmVsp, bool noScatherGather)
++{
++    t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
++
++
++    p_FmVspEntry->p_FmVspEntryDriverParams->noScatherGather = noScatherGather;
++
++    return E_OK;
++}
++
++t_Error FM_VSP_ConfigPoolDepletion(t_Handle h_FmVsp, t_FmBufPoolDepletion *p_BufPoolDepletion)
++{
++    t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmVsp, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_BufPoolDepletion, E_INVALID_HANDLE);
++
++    p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion = (t_FmBufPoolDepletion *)XX_Malloc(sizeof(t_FmBufPoolDepletion));
++    if (!p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_BufPoolDepletion allocation failed"));
++    memcpy(p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion, p_BufPoolDepletion, sizeof(t_FmBufPoolDepletion));
++
++    return E_OK;
++}
++
++t_Error FM_VSP_ConfigBackupPools(t_Handle h_FmVsp, t_FmBackupBmPools *p_BackupBmPools)
++{
++    t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmVsp, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_BackupBmPools, E_INVALID_HANDLE);
++
++    p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools = (t_FmBackupBmPools *)XX_Malloc(sizeof(t_FmBackupBmPools));
++    if (!p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_BackupBmPools allocation failed"));
++    memcpy(p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools, p_BackupBmPools, sizeof(t_FmBackupBmPools));
++
++    return E_OK;
++}
++
++uint32_t FM_VSP_GetBufferDataOffset(t_Handle h_FmVsp)
++{
++    t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, 0);
++    SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, 0);
++
++    return p_FmVspEntry->bufferOffsets.dataOffset;
++}
++
++uint8_t * FM_VSP_GetBufferICInfo(t_Handle h_FmVsp, char *p_Data)
++{
++    t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL);
++
++    if (p_FmVspEntry->bufferOffsets.pcdInfoOffset == ILLEGAL_BASE)
++        return NULL;
++
++    return (uint8_t *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.pcdInfoOffset);
++}
++
++t_FmPrsResult * FM_VSP_GetBufferPrsResult(t_Handle h_FmVsp, char *p_Data)
++{
++    t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL);
++
++    if (p_FmVspEntry->bufferOffsets.prsResultOffset == ILLEGAL_BASE)
++        return NULL;
++
++    return (t_FmPrsResult *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.prsResultOffset);
++}
++
++uint64_t * FM_VSP_GetBufferTimeStamp(t_Handle h_FmVsp, char *p_Data)
++{
++    t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL);
++
++    if (p_FmVspEntry->bufferOffsets.timeStampOffset == ILLEGAL_BASE)
++        return NULL;
++
++    return (uint64_t *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.timeStampOffset);
++}
++
++uint8_t * FM_VSP_GetBufferHashResult(t_Handle h_FmVsp, char *p_Data)
++{
++    t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL);
++
++    if (p_FmVspEntry->bufferOffsets.hashResultOffset == ILLEGAL_BASE)
++        return NULL;
++
++    return (uint8_t *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.hashResultOffset);
++}
++
++#endif /* (DPAA_VERSION >= 11) */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.h
+@@ -0,0 +1,85 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_sp.h
++
++ @Description   FM SP  ...
++*//***************************************************************************/
++#ifndef __FM_SP_H
++#define __FM_SP_H
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "list_ext.h"
++
++#include "fm_sp_common.h"
++#include "fm_common.h"
++
++
++#define __ERR_MODULE__  MODULE_FM_SP
++
++typedef struct {
++    t_FmBufferPrefixContent             bufferPrefixContent;
++    e_FmDmaSwapOption                   dmaSwapData;
++    e_FmDmaCacheOption                  dmaIntContextCacheAttr;
++    e_FmDmaCacheOption                  dmaHeaderCacheAttr;
++    e_FmDmaCacheOption                  dmaScatterGatherCacheAttr;
++    bool                                dmaWriteOptimize;
++    uint16_t                            liodnOffset;
++    bool                                noScatherGather;
++    t_FmBufPoolDepletion                *p_BufPoolDepletion;
++    t_FmBackupBmPools                   *p_BackupBmPools;
++    t_FmExtPools                        extBufPools;
++} t_FmVspEntryDriverParams;
++
++typedef struct {
++    bool                        valid;
++    volatile bool               lock;
++    uint8_t                     pointedOwners;
++    uint16_t                    absoluteSpId;
++    uint8_t                     internalBufferOffset;
++    t_FmSpBufMargins            bufMargins;
++    t_FmSpIntContextDataCopy    intContext;
++    t_FmSpBufferOffsets         bufferOffsets;
++    t_Handle                    h_Fm;
++    e_FmPortType                portType;           /**< Port type */
++    uint8_t                     portId;             /**< Port Id - relative to type */
++    uint8_t                     relativeProfileId;
++    struct fm_pcd_storage_profile_regs *p_FmSpRegsBase;
++    t_FmExtPools                extBufPools;
++    t_FmVspEntryDriverParams    *p_FmVspEntryDriverParams;
++} t_FmVspEntry;
++
++
++#endif /* __FM_SP_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fman_sp.c
+@@ -0,0 +1,197 @@
++/*
++ * Copyright 2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "fsl_fman_sp.h"
++
++
++uint32_t fman_vsp_get_statistics(struct fm_pcd_storage_profile_regs   *regs,
++                    uint16_t                      index)
++{
++    struct fm_pcd_storage_profile_regs *sp_regs;
++    sp_regs = &regs[index];
++    return ioread32be(&sp_regs->fm_sp_acnt);
++}
++
++void fman_vsp_set_statistics(struct fm_pcd_storage_profile_regs *regs,
++            uint16_t index,   uint32_t value)
++{
++    struct fm_pcd_storage_profile_regs *sp_regs;
++    sp_regs = &regs[index];
++    iowrite32be(value, &sp_regs->fm_sp_acnt);
++}
++
++void fman_vsp_defconfig(struct fm_storage_profile_params *cfg)
++{
++    cfg->dma_swap_data =
++            DEFAULT_FMAN_SP_DMA_SWAP_DATA;
++    cfg->int_context_cache_attr =
++            DEFAULT_FMAN_SP_DMA_INT_CONTEXT_CACHE_ATTR;
++    cfg->header_cache_attr =
++            DEFAULT_FMAN_SP_DMA_HEADER_CACHE_ATTR;
++    cfg->scatter_gather_cache_attr =
++            DEFAULT_FMAN_SP_DMA_SCATTER_GATHER_CACHE_ATTR;
++    cfg->dma_write_optimize =
++            DEFAULT_FMAN_SP_DMA_WRITE_OPTIMIZE;
++    cfg->no_scather_gather =
++            DEFAULT_FMAN_SP_NO_SCATTER_GATHER;
++}
++
++static inline uint32_t calc_vec_dep(int max_pools, bool *pools,
++        struct fman_ext_pools *ext_buf_pools, uint32_t mask)
++{
++    int i, j;
++    uint32_t vector = 0;
++    for (i = 0; i < max_pools; i++)
++        if (pools[i])
++            for (j = 0; j < ext_buf_pools->num_pools_used; j++)
++                if (i == ext_buf_pools->ext_buf_pool[j].id) {
++                    vector |= mask >> j;
++                    break;
++                }
++    return vector;
++}
++
++void fman_vsp_init(struct fm_pcd_storage_profile_regs   *regs,
++    uint16_t index, struct fm_storage_profile_params *fm_vsp_params,
++    int port_max_num_of_ext_pools, int bm_max_num_of_pools,
++    int max_num_of_pfc_priorities)
++{
++    int i = 0, j = 0;
++    struct fm_pcd_storage_profile_regs *sp_regs;
++    uint32_t tmp_reg, vector;
++    struct fman_ext_pools *ext_buf_pools = &fm_vsp_params->fm_ext_pools;
++    struct fman_buf_pool_depletion *buf_pool_depletion =
++                    &fm_vsp_params->buf_pool_depletion;
++    struct fman_backup_bm_pools *backup_pools =
++                    &fm_vsp_params->backup_pools;
++    struct fman_sp_int_context_data_copy *int_context_data_copy =
++                        fm_vsp_params->int_context;
++    struct fman_sp_buf_margins *external_buffer_margins =
++                        fm_vsp_params->buf_margins;
++    bool no_scather_gather = fm_vsp_params->no_scather_gather;
++    uint16_t liodn_offset = fm_vsp_params->liodn_offset;
++
++    sp_regs = &regs[index];
++
++    /* fill external buffers manager pool information register*/
++    for (i = 0; i < ext_buf_pools->num_pools_used; i++) {
++        tmp_reg = FMAN_SP_EXT_BUF_POOL_VALID |
++            FMAN_SP_EXT_BUF_POOL_EN_COUNTER;
++        tmp_reg |= ((uint32_t)ext_buf_pools->ext_buf_pool[i].id <<
++            FMAN_SP_EXT_BUF_POOL_ID_SHIFT);
++        tmp_reg |= ext_buf_pools->ext_buf_pool[i].size;
++        /* functionality available only for some deriviatives
++             (limited by config) */
++        for (j = 0; j < backup_pools->num_backup_pools; j++)
++            if (ext_buf_pools->ext_buf_pool[i].id ==
++                backup_pools->pool_ids[j]) {
++                tmp_reg |= FMAN_SP_EXT_BUF_POOL_BACKUP;
++                break;
++            }
++        iowrite32be(tmp_reg, &sp_regs->fm_sp_ebmpi[i]);
++    }
++
++    /* clear unused pools */
++    for (i = ext_buf_pools->num_pools_used;
++        i < port_max_num_of_ext_pools; i++)
++        iowrite32be(0, &sp_regs->fm_sp_ebmpi[i]);
++
++    /* fill pool depletion register*/
++    tmp_reg = 0;
++    if (buf_pool_depletion->buf_pool_depletion_enabled && buf_pool_depletion->pools_grp_mode_enable) {
++        /* calculate vector for number of pools depletion */
++        vector = calc_vec_dep(bm_max_num_of_pools, buf_pool_depletion->
++                pools_to_consider, ext_buf_pools, 0x80000000);
++
++        /* configure num of pools and vector for number of pools mode */
++        tmp_reg |= (((uint32_t)buf_pool_depletion->num_pools - 1) <<
++            FMAN_SP_POOL_DEP_NUM_OF_POOLS_SHIFT);
++        tmp_reg |= vector;
++    }
++
++    if (buf_pool_depletion->buf_pool_depletion_enabled && buf_pool_depletion->single_pool_mode_enable) {
++        /* calculate vector for number of pools depletion */
++        vector = calc_vec_dep(bm_max_num_of_pools, buf_pool_depletion->
++                pools_to_consider_for_single_mode,
++                ext_buf_pools, 0x00000080);
++
++        /* configure num of pools and vector for number of pools mode */
++        tmp_reg |= vector;
++    }
++
++    /* fill QbbPEV */
++    if (buf_pool_depletion->buf_pool_depletion_enabled) {
++        vector = 0;
++        for (i = 0; i < max_num_of_pfc_priorities; i++)
++            if (buf_pool_depletion->pfc_priorities_en[i] == TRUE)
++                vector |= 0x00000100 << i;
++        tmp_reg |= vector;
++    }
++    iowrite32be(tmp_reg, &sp_regs->fm_sp_mpd);
++
++    /* fill dma attributes register */
++    tmp_reg = 0;
++    tmp_reg |= (uint32_t)fm_vsp_params->dma_swap_data <<
++        FMAN_SP_DMA_ATTR_SWP_SHIFT;
++    tmp_reg |= (uint32_t)fm_vsp_params->int_context_cache_attr <<
++        FMAN_SP_DMA_ATTR_IC_CACHE_SHIFT;
++    tmp_reg |= (uint32_t)fm_vsp_params->header_cache_attr <<
++        FMAN_SP_DMA_ATTR_HDR_CACHE_SHIFT;
++    tmp_reg |= (uint32_t)fm_vsp_params->scatter_gather_cache_attr <<
++        FMAN_SP_DMA_ATTR_SG_CACHE_SHIFT;
++    if (fm_vsp_params->dma_write_optimize)
++        tmp_reg |= FMAN_SP_DMA_ATTR_WRITE_OPTIMIZE;
++    iowrite32be(tmp_reg, &sp_regs->fm_sp_da);
++
++    /* IC parameters - fill internal context parameters register */
++    tmp_reg = 0;
++    tmp_reg |= (((uint32_t)int_context_data_copy->ext_buf_offset/
++        OFFSET_UNITS) << FMAN_SP_IC_TO_EXT_SHIFT);
++    tmp_reg |= (((uint32_t)int_context_data_copy->int_context_offset/
++        OFFSET_UNITS) << FMAN_SP_IC_FROM_INT_SHIFT);
++    tmp_reg |= (((uint32_t)int_context_data_copy->size/OFFSET_UNITS) <<
++        FMAN_SP_IC_SIZE_SHIFT);
++    iowrite32be(tmp_reg, &sp_regs->fm_sp_icp);
++
++    /* buffer margins - fill external buffer margins register */
++    tmp_reg = 0;
++    tmp_reg |= (((uint32_t)external_buffer_margins->start_margins) <<
++        FMAN_SP_EXT_BUF_MARG_START_SHIFT);
++    tmp_reg |= (((uint32_t)external_buffer_margins->end_margins) <<
++        FMAN_SP_EXT_BUF_MARG_END_SHIFT);
++    if (no_scather_gather)
++        tmp_reg |= FMAN_SP_SG_DISABLE;
++    iowrite32be(tmp_reg, &sp_regs->fm_sp_ebm);
++
++    /* buffer margins - fill spliodn register */
++    iowrite32be(liodn_offset, &sp_regs->fm_sp_spliodn);
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c
+@@ -0,0 +1,5216 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm.c
++
++ @Description   FM driver routines implementation.
++*//***************************************************************************/
++#include "std_ext.h"
++#include "error_ext.h"
++#include "xx_ext.h"
++#include "string_ext.h"
++#include "sprint_ext.h"
++#include "debug_ext.h"
++#include "fm_muram_ext.h"
++#include <linux/math64.h>
++
++#include "fm_common.h"
++#include "fm_ipc.h"
++#include "fm.h"
++#ifndef CONFIG_FMAN_ARM
++#include <linux/fsl/svr.h>
++#endif
++#include "fsl_fman.h"
++
++
++/****************************************/
++/*       static functions               */
++/****************************************/
++
++static volatile bool blockingFlag = FALSE;
++static void IpcMsgCompletionCB(t_Handle   h_Fm,
++                               uint8_t    *p_Msg,
++                               uint8_t    *p_Reply,
++                               uint32_t   replyLength,
++                               t_Error    status)
++{
++    UNUSED(h_Fm);UNUSED(p_Msg);UNUSED(p_Reply);UNUSED(replyLength);UNUSED(status);
++    blockingFlag = FALSE;
++}
++
++static void FreeInitResources(t_Fm *p_Fm)
++{
++    if (p_Fm->camBaseAddr)
++       FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->camBaseAddr));
++    if (p_Fm->fifoBaseAddr)
++       FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->fifoBaseAddr));
++    if (p_Fm->resAddr)
++       FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->resAddr));
++}
++
++static bool IsFmanCtrlCodeLoaded(t_Fm *p_Fm)
++{
++    t_FMIramRegs    *p_Iram;
++
++    ASSERT_COND(p_Fm);
++    p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM);
++
++    return (bool)!!(GET_UINT32(p_Iram->iready) & IRAM_READY);
++}
++
++static t_Error CheckFmParameters(t_Fm *p_Fm)
++{
++    if (IsFmanCtrlCodeLoaded(p_Fm) && !p_Fm->resetOnInit)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Old FMan CTRL code is loaded; FM must be reset!"));
++#if (DPAA_VERSION < 11)
++    if (!p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats ||
++        (p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats > DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("axiDbgNumOfBeats has to be in the range 1 - %d", DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS));
++#endif /* (DPAA_VERSION < 11) */
++    if (p_Fm->p_FmDriverParam->dma_cam_num_of_entries % DMA_CAM_UNITS)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_cam_num_of_entries has to be divisble by %d", DMA_CAM_UNITS));
++//    if (!p_Fm->p_FmDriverParam->dma_cam_num_of_entries || (p_Fm->p_FmDriverParam->dma_cam_num_of_entries > DMA_MODE_MAX_CAM_NUM_OF_ENTRIES))
++//        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_cam_num_of_entries has to be in the range 1 - %d", DMA_MODE_MAX_CAM_NUM_OF_ENTRIES));
++    if (p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer > DMA_THRESH_MAX_COMMQ)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_comm_qtsh_asrt_emer can not be larger than %d", DMA_THRESH_MAX_COMMQ));
++    if (p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer > DMA_THRESH_MAX_COMMQ)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_comm_qtsh_clr_emer can not be larger than %d", DMA_THRESH_MAX_COMMQ));
++    if (p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer >= p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_comm_qtsh_clr_emer must be smaller than dma_comm_qtsh_asrt_emer"));
++#if (DPAA_VERSION < 11)
++    if (p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer > DMA_THRESH_MAX_BUF)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_read_buf_tsh_asrt_emer can not be larger than %d", DMA_THRESH_MAX_BUF));
++    if (p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer > DMA_THRESH_MAX_BUF)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_read_buf_tsh_clr_emer can not be larger than %d", DMA_THRESH_MAX_BUF));
++    if (p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer >= p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_read_buf_tsh_clr_emer must be smaller than dma_read_buf_tsh_asrt_emer"));
++    if (p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer > DMA_THRESH_MAX_BUF)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_write_buf_tsh_asrt_emer can not be larger than %d", DMA_THRESH_MAX_BUF));
++    if (p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer > DMA_THRESH_MAX_BUF)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_write_buf_tsh_clr_emer can not be larger than %d", DMA_THRESH_MAX_BUF));
++    if (p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer >= p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_write_buf_tsh_clr_emer must be smaller than dma_write_buf_tsh_asrt_emer"));
++#else /* (DPAA_VERSION >= 11) */
++    if ((p_Fm->p_FmDriverParam->dma_dbg_cnt_mode == E_FMAN_DMA_DBG_CNT_INT_READ_EM)||
++            (p_Fm->p_FmDriverParam->dma_dbg_cnt_mode == E_FMAN_DMA_DBG_CNT_INT_WRITE_EM) ||
++            (p_Fm->p_FmDriverParam->dma_dbg_cnt_mode == E_FMAN_DMA_DBG_CNT_RAW_WAR_PROT))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_dbg_cnt_mode value not supported by this integration."));
++    if ((p_Fm->p_FmDriverParam->dma_emergency_bus_select == FM_DMA_MURAM_READ_EMERGENCY)||
++            (p_Fm->p_FmDriverParam->dma_emergency_bus_select == FM_DMA_MURAM_WRITE_EMERGENCY))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("emergencyBusSelect value not supported by this integration."));
++    if (p_Fm->p_FmDriverParam->dma_stop_on_bus_error)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_stop_on_bus_error not supported by this integration."));
++#ifdef FM_AID_MODE_NO_TNUM_SW005
++    if (p_Fm->p_FmDriverParam->dma_aid_mode != E_FMAN_DMA_AID_OUT_PORT_ID)
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_aid_mode not supported by this integration."));
++#endif /* FM_AID_MODE_NO_TNUM_SW005 */
++    if (p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_axi_dbg_num_of_beats not supported by this integration."));
++#endif /* (DPAA_VERSION < 11) */
++
++    if (!p_Fm->p_FmStateStruct->fmClkFreq)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fmClkFreq must be set."));
++    if (USEC_TO_CLK(p_Fm->p_FmDriverParam->dma_watchdog, p_Fm->p_FmStateStruct->fmClkFreq) > DMA_MAX_WATCHDOG)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("dma_watchdog depends on FM clock. dma_watchdog(in microseconds) * clk (in Mhz), may not exceed 0x08x", DMA_MAX_WATCHDOG));
++
++#if (DPAA_VERSION >= 11)
++    if ((p_Fm->partVSPBase + p_Fm->partNumOfVSPs) > FM_VSP_MAX_NUM_OF_ENTRIES)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("partVSPBase+partNumOfVSPs out of range!!!"));
++#endif /* (DPAA_VERSION >= 11) */
++
++    if (p_Fm->p_FmStateStruct->totalFifoSize % BMI_FIFO_UNITS)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("totalFifoSize number has to be divisible by %d", BMI_FIFO_UNITS));
++    if (!p_Fm->p_FmStateStruct->totalFifoSize ||
++        (p_Fm->p_FmStateStruct->totalFifoSize > BMI_MAX_FIFO_SIZE))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("totalFifoSize (currently defined as %d) has to be in the range of 256 to %d",
++                      p_Fm->p_FmStateStruct->totalFifoSize,
++                      BMI_MAX_FIFO_SIZE));
++    if (!p_Fm->p_FmStateStruct->totalNumOfTasks ||
++        (p_Fm->p_FmStateStruct->totalNumOfTasks > BMI_MAX_NUM_OF_TASKS))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("totalNumOfTasks number has to be in the range 1 - %d", BMI_MAX_NUM_OF_TASKS));
++
++#ifdef FM_HAS_TOTAL_DMAS
++    if (!p_Fm->p_FmStateStruct->maxNumOfOpenDmas ||
++        (p_Fm->p_FmStateStruct->maxNumOfOpenDmas > BMI_MAX_NUM_OF_DMAS))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("maxNumOfOpenDmas number has to be in the range 1 - %d", BMI_MAX_NUM_OF_DMAS));
++#endif /* FM_HAS_TOTAL_DMAS */
++
++    if (p_Fm->p_FmDriverParam->disp_limit_tsh > FPM_MAX_DISP_LIMIT)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("disp_limit_tsh can't be greater than %d", FPM_MAX_DISP_LIMIT));
++
++    if (!p_Fm->f_Exception)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided"));
++    if (!p_Fm->f_BusError)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided"));
++
++#ifdef FM_NO_WATCHDOG
++    if ((p_Fm->p_FmStateStruct->revInfo.majorRev == 2) &&
++        (p_Fm->p_FmDriverParam->dma_watchdog))
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("watchdog!"));
++#endif /* FM_NO_WATCHDOG */
++
++#ifdef FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008
++    if ((p_Fm->p_FmStateStruct->revInfo.majorRev < 6) &&
++        (p_Fm->p_FmDriverParam->halt_on_unrecov_ecc_err))
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("HaltOnEccError!"));
++#endif /* FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008 */
++
++#ifdef FM_NO_TNUM_AGING
++    if ((p_Fm->p_FmStateStruct->revInfo.majorRev != 4) &&
++        (p_Fm->p_FmStateStruct->revInfo.majorRev < 6))
++        if (p_Fm->p_FmDriverParam->tnum_aging_period)
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Tnum aging!"));
++#endif /* FM_NO_TNUM_AGING */
++
++    /* check that user did not set revision-dependent exceptions */
++#ifdef FM_NO_DISPATCH_RAM_ECC
++    if ((p_Fm->p_FmStateStruct->revInfo.majorRev != 4) &&
++        (p_Fm->p_FmStateStruct->revInfo.majorRev < 6))
++        if (p_Fm->userSetExceptions & FM_EX_BMI_DISPATCH_RAM_ECC)
++            RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("exception e_FM_EX_BMI_DISPATCH_RAM_ECC!"));
++#endif /* FM_NO_DISPATCH_RAM_ECC */
++
++#ifdef FM_QMI_NO_ECC_EXCEPTIONS
++    if (p_Fm->p_FmStateStruct->revInfo.majorRev == 4)
++        if (p_Fm->userSetExceptions & (FM_EX_QMI_SINGLE_ECC | FM_EX_QMI_DOUBLE_ECC))
++            RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("exception e_FM_EX_QMI_SINGLE_ECC/e_FM_EX_QMI_DOUBLE_ECC!"));
++#endif /* FM_QMI_NO_ECC_EXCEPTIONS */
++
++#ifdef FM_QMI_NO_SINGLE_ECC_EXCEPTION
++    if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
++        if (p_Fm->userSetExceptions & FM_EX_QMI_SINGLE_ECC)
++            RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("exception e_FM_EX_QMI_SINGLE_ECC!"));
++#endif /* FM_QMI_NO_SINGLE_ECC_EXCEPTION */
++
++    return E_OK;
++}
++
++
++static void SendIpcIsr(t_Fm *p_Fm, uint32_t macEvent, uint32_t pendingReg)
++{
++    ASSERT_COND(p_Fm->guestId == NCSW_MASTER_ID);
++
++    if (p_Fm->intrMng[macEvent].guestId == NCSW_MASTER_ID)
++        p_Fm->intrMng[macEvent].f_Isr(p_Fm->intrMng[macEvent].h_SrcHandle);
++
++    /* If the MAC is running on guest-partition and we have IPC session with it,
++       we inform him about the event through IPC; otherwise, we ignore the event. */
++    else if (p_Fm->h_IpcSessions[p_Fm->intrMng[macEvent].guestId])
++    {
++        t_Error     err;
++        t_FmIpcIsr  fmIpcIsr;
++        t_FmIpcMsg  msg;
++
++        memset(&msg, 0, sizeof(msg));
++        msg.msgId = FM_GUEST_ISR;
++        fmIpcIsr.pendingReg = pendingReg;
++        fmIpcIsr.boolErr = FALSE;
++        memcpy(msg.msgBody, &fmIpcIsr, sizeof(fmIpcIsr));
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[p_Fm->intrMng[macEvent].guestId],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId) + sizeof(fmIpcIsr),
++                                NULL,
++                                NULL,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            REPORT_ERROR(MINOR, err, NO_MSG);
++    }
++    else
++        DBG(TRACE, ("FM Guest mode, without IPC - can't call ISR!"));
++}
++
++static void BmiErrEvent(t_Fm *p_Fm)
++{
++    uint32_t    event;
++    struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs;
++
++
++    event = fman_get_bmi_err_event(bmi_rg);
++
++    if (event & BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC)
++        p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_STORAGE_PROFILE_ECC);
++    if (event & BMI_ERR_INTR_EN_LIST_RAM_ECC)
++        p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_LIST_RAM_ECC);
++    if (event & BMI_ERR_INTR_EN_STATISTICS_RAM_ECC)
++        p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_STATISTICS_RAM_ECC);
++    if (event & BMI_ERR_INTR_EN_DISPATCH_RAM_ECC)
++        p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_DISPATCH_RAM_ECC);
++}
++
++static void    QmiErrEvent(t_Fm *p_Fm)
++{
++    uint32_t    event;
++    struct fman_qmi_regs *qmi_rg = p_Fm->p_FmQmiRegs;
++
++    event = fman_get_qmi_err_event(qmi_rg);
++
++    if (event & QMI_ERR_INTR_EN_DOUBLE_ECC)
++        p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_QMI_DOUBLE_ECC);
++    if (event & QMI_ERR_INTR_EN_DEQ_FROM_DEF)
++        p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID);
++}
++
++static void    DmaErrEvent(t_Fm *p_Fm)
++{
++    uint32_t            status, com_id;
++    uint8_t             tnum;
++    uint8_t             hardwarePortId;
++    uint8_t             relativePortId;
++    uint16_t            liodn;
++    struct fman_dma_regs *dma_rg = p_Fm->p_FmDmaRegs;
++
++    status = fman_get_dma_err_event(dma_rg);
++
++    if (status & DMA_STATUS_BUS_ERR)
++    {
++        com_id = fman_get_dma_com_id(dma_rg);
++        hardwarePortId = (uint8_t)(((com_id & DMA_TRANSFER_PORTID_MASK) >> DMA_TRANSFER_PORTID_SHIFT));
++        ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
++        HW_PORT_ID_TO_SW_PORT_ID(relativePortId, hardwarePortId);
++        tnum = (uint8_t)((com_id & DMA_TRANSFER_TNUM_MASK) >> DMA_TRANSFER_TNUM_SHIFT);
++        liodn = (uint16_t)(com_id & DMA_TRANSFER_LIODN_MASK);
++        ASSERT_COND(p_Fm->p_FmStateStruct->portsTypes[hardwarePortId] != e_FM_PORT_TYPE_DUMMY);
++        p_Fm->f_BusError(p_Fm->h_App,
++                         p_Fm->p_FmStateStruct->portsTypes[hardwarePortId],
++                         relativePortId,
++                         fman_get_dma_addr(dma_rg),
++                         tnum,
++                         liodn);
++    }
++        if (status & DMA_STATUS_FM_SPDAT_ECC)
++            p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_SINGLE_PORT_ECC);
++        if (status & DMA_STATUS_READ_ECC)
++            p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_READ_ECC);
++        if (status & DMA_STATUS_SYSTEM_WRITE_ECC)
++            p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_SYSTEM_WRITE_ECC);
++        if (status & DMA_STATUS_FM_WRITE_ECC)
++            p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_FM_WRITE_ECC);
++    }
++
++static void    FpmErrEvent(t_Fm *p_Fm)
++{
++    uint32_t    event;
++    struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
++
++    event = fman_get_fpm_err_event(fpm_rg);
++
++    if ((event  & FPM_EV_MASK_DOUBLE_ECC) && (event & FPM_EV_MASK_DOUBLE_ECC_EN))
++        p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_FPM_DOUBLE_ECC);
++    if ((event  & FPM_EV_MASK_STALL) && (event & FPM_EV_MASK_STALL_EN))
++        p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_FPM_STALL_ON_TASKS);
++    if ((event  & FPM_EV_MASK_SINGLE_ECC) && (event & FPM_EV_MASK_SINGLE_ECC_EN))
++        p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_FPM_SINGLE_ECC);
++}
++
++static void    MuramErrIntr(t_Fm *p_Fm)
++{
++    uint32_t    event;
++    struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
++
++    event = fman_get_muram_err_event(fpm_rg);
++
++    if (event & FPM_RAM_MURAM_ECC)
++        p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_MURAM_ECC);
++}
++
++static void IramErrIntr(t_Fm *p_Fm)
++{
++    uint32_t    event;
++    struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
++
++    event = fman_get_iram_err_event(fpm_rg);
++
++    if (event & FPM_RAM_IRAM_ECC)
++        p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_IRAM_ECC);
++}
++
++static void QmiEvent(t_Fm *p_Fm)
++{
++    uint32_t    event;
++    struct fman_qmi_regs *qmi_rg = p_Fm->p_FmQmiRegs;
++
++    event = fman_get_qmi_event(qmi_rg);
++
++    if (event & QMI_INTR_EN_SINGLE_ECC)
++        p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_QMI_SINGLE_ECC);
++}
++
++static void UnimplementedIsr(t_Handle h_Arg)
++{
++    UNUSED(h_Arg);
++
++    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unimplemented ISR!"));
++}
++
++static void UnimplementedFmanCtrlIsr(t_Handle h_Arg, uint32_t event)
++{
++    UNUSED(h_Arg); UNUSED(event);
++
++    REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unimplemented FmCtl ISR!"));
++}
++
++static void EnableTimeStamp(t_Fm *p_Fm)
++{
++    struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
++
++    ASSERT_COND(p_Fm->p_FmStateStruct);
++    ASSERT_COND(p_Fm->p_FmStateStruct->count1MicroBit);
++
++    fman_enable_time_stamp(fpm_rg, p_Fm->p_FmStateStruct->count1MicroBit, p_Fm->p_FmStateStruct->fmClkFreq);
++
++    p_Fm->p_FmStateStruct->enabledTimeStamp = TRUE;
++}
++
++static t_Error ClearIRam(t_Fm *p_Fm)
++{
++    t_FMIramRegs    *p_Iram;
++    int             i;
++    int             iram_size;
++
++    ASSERT_COND(p_Fm);
++    p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM);
++    iram_size = FM_IRAM_SIZE(p_Fm->p_FmStateStruct->revInfo.majorRev,p_Fm->p_FmStateStruct->revInfo.minorRev);
++
++    /* Enable the auto-increment */
++    WRITE_UINT32(p_Iram->iadd, IRAM_IADD_AIE);
++    while (GET_UINT32(p_Iram->iadd) != IRAM_IADD_AIE) ;
++
++    for (i=0; i < (iram_size/4); i++)
++        WRITE_UINT32(p_Iram->idata, 0xffffffff);
++
++    WRITE_UINT32(p_Iram->iadd, iram_size - 4);
++    CORE_MemoryBarrier();
++    while (GET_UINT32(p_Iram->idata) != 0xffffffff) ;
++
++    return E_OK;
++}
++
++static t_Error LoadFmanCtrlCode(t_Fm *p_Fm)
++{
++    t_FMIramRegs    *p_Iram;
++    int             i;
++    uint32_t        tmp;
++    uint8_t         compTo16;
++
++    ASSERT_COND(p_Fm);
++    p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM);
++
++    /* Enable the auto-increment */
++    WRITE_UINT32(p_Iram->iadd, IRAM_IADD_AIE);
++    while (GET_UINT32(p_Iram->iadd) != IRAM_IADD_AIE) ;
++
++    for (i=0; i < (p_Fm->firmware.size / 4); i++)
++        WRITE_UINT32(p_Iram->idata, p_Fm->firmware.p_Code[i]);
++
++    compTo16 = (uint8_t)(p_Fm->firmware.size % 16);
++    if (compTo16)
++        for (i=0; i < ((16-compTo16) / 4); i++)
++            WRITE_UINT32(p_Iram->idata, 0xffffffff);
++
++    WRITE_UINT32(p_Iram->iadd,p_Fm->firmware.size-4);
++    while (GET_UINT32(p_Iram->iadd) != (p_Fm->firmware.size-4)) ;
++
++    /* verify that writing has completed */
++    while (GET_UINT32(p_Iram->idata) != p_Fm->firmware.p_Code[(p_Fm->firmware.size / 4)-1]) ;
++
++    if (p_Fm->fwVerify)
++    {
++        WRITE_UINT32(p_Iram->iadd, IRAM_IADD_AIE);
++        while (GET_UINT32(p_Iram->iadd) != IRAM_IADD_AIE) ;
++        for (i=0; i < (p_Fm->firmware.size / 4); i++)
++        {
++            tmp = GET_UINT32(p_Iram->idata);
++            if (tmp != p_Fm->firmware.p_Code[i])
++                RETURN_ERROR(MAJOR, E_WRITE_FAILED,
++                             ("UCode write error : write 0x%x, read 0x%x",
++                              p_Fm->firmware.p_Code[i],tmp));
++        }
++        WRITE_UINT32(p_Iram->iadd, 0x0);
++    }
++
++    /* Enable patch from IRAM */
++    WRITE_UINT32(p_Iram->iready, IRAM_READY);
++    XX_UDelay(1000);
++
++    DBG(INFO, ("FMan-Controller code (ver %d.%d.%d) loaded to IRAM.",
++               ((uint16_t *)p_Fm->firmware.p_Code)[2],
++               ((uint8_t *)p_Fm->firmware.p_Code)[6],
++               ((uint8_t *)p_Fm->firmware.p_Code)[7]));
++
++    return E_OK;
++}
++
++#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173
++static t_Error FwNotResetErratumBugzilla6173WA(t_Fm *p_Fm)
++{
++    t_FMIramRegs    *p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM);
++    uint32_t        tmpReg;
++    uint32_t        savedSpliodn[63];
++
++    /* write to IRAM first location the debug instruction */
++    WRITE_UINT32(p_Iram->iadd, 0);
++    while (GET_UINT32(p_Iram->iadd) != 0) ;
++    WRITE_UINT32(p_Iram->idata, FM_FW_DEBUG_INSTRUCTION);
++
++    WRITE_UINT32(p_Iram->iadd, 0);
++    while (GET_UINT32(p_Iram->iadd) != 0) ;
++    while (GET_UINT32(p_Iram->idata) != FM_FW_DEBUG_INSTRUCTION) ;
++
++    /* Enable patch from IRAM */
++    WRITE_UINT32(p_Iram->iready, IRAM_READY);
++    CORE_MemoryBarrier();
++    XX_UDelay(100);
++    IO2MemCpy32((uint8_t *)savedSpliodn,
++                (uint8_t *)p_Fm->p_FmBmiRegs->fmbm_spliodn,
++                63*sizeof(uint32_t));
++
++    /* reset FMAN */
++    WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rstc, FPM_RSTC_FM_RESET);
++    CORE_MemoryBarrier();
++    XX_UDelay(100);
++
++    /* verify breakpoint debug status register */
++    tmpReg = GET_UINT32(*(uint32_t *)UINT_TO_PTR(p_Fm->baseAddr + FM_DEBUG_STATUS_REGISTER_OFFSET));
++    if (!tmpReg)
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid debug status register value is '0'"));
++
++    /*************************************/
++    /* Load FMan-Controller code to IRAM */
++    /*************************************/
++    ClearIRam(p_Fm);
++    if (p_Fm->firmware.p_Code &&
++        (LoadFmanCtrlCode(p_Fm) != E_OK))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++    XX_UDelay(100);
++
++    /* reset FMAN again to start the microcode */
++    WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rstc, FPM_RSTC_FM_RESET);
++    CORE_MemoryBarrier();
++    XX_UDelay(100);
++    Mem2IOCpy32((uint8_t *)p_Fm->p_FmBmiRegs->fmbm_spliodn,
++                (uint8_t *)savedSpliodn,
++                63*sizeof(uint32_t));
++
++    if (fman_is_qmi_halt_not_busy_state(p_Fm->p_FmQmiRegs))
++    {
++        fman_resume(p_Fm->p_FmFpmRegs);
++        CORE_MemoryBarrier();
++        XX_UDelay(100);
++    }
++
++    return E_OK;
++}
++#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
++
++static void GuestErrorIsr(t_Fm *p_Fm, uint32_t pending)
++{
++#define FM_G_CALL_1G_MAC_ERR_ISR(_id)   \
++do {                                    \
++    p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].h_SrcHandle);\
++} while (0)
++#define FM_G_CALL_10G_MAC_ERR_ISR(_id)  \
++do {                                    \
++    p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].h_SrcHandle);\
++} while (0)
++
++    /* error interrupts */
++    if (pending & ERR_INTR_EN_1G_MAC0)
++        FM_G_CALL_1G_MAC_ERR_ISR(0);
++    if (pending & ERR_INTR_EN_1G_MAC1)
++        FM_G_CALL_1G_MAC_ERR_ISR(1);
++    if (pending & ERR_INTR_EN_1G_MAC2)
++        FM_G_CALL_1G_MAC_ERR_ISR(2);
++    if (pending & ERR_INTR_EN_1G_MAC3)
++        FM_G_CALL_1G_MAC_ERR_ISR(3);
++    if (pending & ERR_INTR_EN_1G_MAC4)
++        FM_G_CALL_1G_MAC_ERR_ISR(4);
++    if (pending & ERR_INTR_EN_1G_MAC5)
++        FM_G_CALL_1G_MAC_ERR_ISR(5);
++    if (pending & ERR_INTR_EN_1G_MAC6)
++        FM_G_CALL_1G_MAC_ERR_ISR(6);
++    if (pending & ERR_INTR_EN_1G_MAC7)
++        FM_G_CALL_1G_MAC_ERR_ISR(7);
++    if (pending & ERR_INTR_EN_10G_MAC0)
++        FM_G_CALL_10G_MAC_ERR_ISR(0);
++    if (pending & ERR_INTR_EN_10G_MAC1)
++        FM_G_CALL_10G_MAC_ERR_ISR(1);
++}
++
++static void GuestEventIsr(t_Fm *p_Fm, uint32_t pending)
++{
++#define FM_G_CALL_1G_MAC_ISR(_id)   \
++do {                                    \
++    p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].h_SrcHandle);\
++} while (0)
++#define FM_G_CALL_10G_MAC_ISR(_id)   \
++do {                                    \
++    p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].h_SrcHandle);\
++} while (0)
++
++    if (pending & INTR_EN_1G_MAC0)
++        FM_G_CALL_1G_MAC_ISR(0);
++    if (pending & INTR_EN_1G_MAC1)
++        FM_G_CALL_1G_MAC_ISR(1);
++    if (pending & INTR_EN_1G_MAC2)
++        FM_G_CALL_1G_MAC_ISR(2);
++    if (pending & INTR_EN_1G_MAC3)
++        FM_G_CALL_1G_MAC_ISR(3);
++    if (pending & INTR_EN_1G_MAC4)
++        FM_G_CALL_1G_MAC_ISR(4);
++    if (pending & INTR_EN_1G_MAC5)
++        FM_G_CALL_1G_MAC_ISR(5);
++    if (pending & INTR_EN_1G_MAC6)
++        FM_G_CALL_1G_MAC_ISR(6);
++    if (pending & INTR_EN_1G_MAC7)
++        FM_G_CALL_1G_MAC_ISR(7);
++    if (pending & INTR_EN_10G_MAC0)
++        FM_G_CALL_10G_MAC_ISR(0);
++    if (pending & INTR_EN_10G_MAC1)
++        FM_G_CALL_10G_MAC_ISR(1);
++    if (pending & INTR_EN_TMR)
++        p_Fm->intrMng[e_FM_EV_TMR].f_Isr(p_Fm->intrMng[e_FM_EV_TMR].h_SrcHandle);
++}
++
++#if (DPAA_VERSION >= 11)
++static t_Error SetVSPWindow(t_Handle  h_Fm,
++                            uint8_t   hardwarePortId,
++                            uint8_t   baseStorageProfile,
++                            uint8_t   log2NumOfProfiles)
++{
++    t_Fm                    *p_Fm = (t_Fm *)h_Fm;
++
++    ASSERT_COND(h_Fm);
++    ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        !p_Fm->p_FmBmiRegs &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_FmIpcVspSetPortWindow fmIpcVspSetPortWindow;
++        t_FmIpcMsg              msg;
++        t_Error                 err = E_OK;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&fmIpcVspSetPortWindow, 0, sizeof(t_FmIpcVspSetPortWindow));
++        fmIpcVspSetPortWindow.hardwarePortId      = hardwarePortId;
++        fmIpcVspSetPortWindow.baseStorageProfile  = baseStorageProfile;
++        fmIpcVspSetPortWindow.log2NumOfProfiles   = log2NumOfProfiles;
++        msg.msgId                                 = FM_VSP_SET_PORT_WINDOW;
++        memcpy(msg.msgBody, &fmIpcVspSetPortWindow, sizeof(t_FmIpcVspSetPortWindow));
++
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId),
++                                NULL,
++                                NULL,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        return E_OK;
++    }
++    else if (!p_Fm->p_FmBmiRegs)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("Either IPC or 'baseAddress' is required!"));
++
++    fman_set_vsp_window(p_Fm->p_FmBmiRegs,
++                        hardwarePortId,
++                        baseStorageProfile,
++                        log2NumOfProfiles);
++
++    return E_OK;
++}
++
++static uint8_t AllocVSPsForPartition(t_Handle  h_Fm, uint8_t base, uint8_t numOfProfiles, uint8_t guestId)
++{
++    t_Fm        *p_Fm = (t_Fm *)h_Fm;
++    uint8_t     profilesFound = 0;
++    int         i = 0;
++    uint32_t    intFlags;
++
++    if (!numOfProfiles)
++        return E_OK;
++
++    if ((numOfProfiles > FM_VSP_MAX_NUM_OF_ENTRIES) ||
++        (base + numOfProfiles > FM_VSP_MAX_NUM_OF_ENTRIES))
++        return (uint8_t)ILLEGAL_BASE;
++
++    if (p_Fm->h_IpcSessions[0])
++    {
++        t_FmIpcResourceAllocParams  ipcAllocParams;
++        t_FmIpcMsg                  msg;
++        t_FmIpcReply                reply;
++        t_Error                     err;
++        uint32_t                    replyLength;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams));
++        ipcAllocParams.guestId         = p_Fm->guestId;
++        ipcAllocParams.num             = p_Fm->partNumOfVSPs;
++        ipcAllocParams.base            = p_Fm->partVSPBase;
++        msg.msgId                              = FM_VSP_ALLOC;
++        memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams));
++        replyLength = sizeof(uint32_t) + sizeof(uint8_t);
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams),
++                                (uint8_t*)&reply,
++                                &replyLength,
++                                NULL,
++                                NULL);
++        if ((err != E_OK) ||
++            (replyLength != (sizeof(uint32_t) + sizeof(uint8_t))))
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        else
++            memcpy((uint8_t*)&p_Fm->partVSPBase, reply.replyBody, sizeof(uint8_t));
++        if (p_Fm->partVSPBase == (uint8_t)(ILLEGAL_BASE))
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++    if (p_Fm->guestId != NCSW_MASTER_ID)
++    {
++        DBG(WARNING, ("FM Guest mode, without IPC - can't validate VSP range!"));
++        return (uint8_t)ILLEGAL_BASE;
++    }
++
++    intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock);
++    for (i = base; i < base + numOfProfiles; i++)
++        if (p_Fm->p_FmSp->profiles[i].profilesMng.ownerId == (uint8_t)ILLEGAL_BASE)
++            profilesFound++;
++        else
++            break;
++
++    if (profilesFound == numOfProfiles)
++        for (i = base; i<base + numOfProfiles; i++)
++            p_Fm->p_FmSp->profiles[i].profilesMng.ownerId = guestId;
++    else
++    {
++        XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
++        return (uint8_t)ILLEGAL_BASE;
++    }
++    XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
++
++    return base;
++}
++
++static void FreeVSPsForPartition(t_Handle  h_Fm, uint8_t base, uint8_t numOfProfiles, uint8_t guestId)
++{
++    t_Fm    *p_Fm = (t_Fm *)h_Fm;
++    int     i = 0;
++
++    ASSERT_COND(p_Fm);
++
++    if (p_Fm->h_IpcSessions[0])
++    {
++        t_FmIpcResourceAllocParams  ipcAllocParams;
++        t_FmIpcMsg                  msg;
++        t_FmIpcReply                reply;
++        uint32_t                    replyLength;
++        t_Error                     err;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams));
++        ipcAllocParams.guestId         = p_Fm->guestId;
++        ipcAllocParams.num             = p_Fm->partNumOfVSPs;
++        ipcAllocParams.base            = p_Fm->partVSPBase;
++        msg.msgId                              = FM_VSP_FREE;
++        memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams));
++        replyLength = sizeof(uint32_t) + sizeof(uint8_t);
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams),
++                                (uint8_t*)&reply,
++                                &replyLength,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            REPORT_ERROR(MAJOR, err, NO_MSG);
++        return;
++    }
++    if (p_Fm->guestId != NCSW_MASTER_ID)
++    {
++        DBG(WARNING, ("FM Guest mode, without IPC - can't validate VSP range!"));
++        return;
++    }
++
++    ASSERT_COND(p_Fm->p_FmSp);
++
++    for (i=base; i<numOfProfiles; i++)
++    {
++        if (p_Fm->p_FmSp->profiles[i].profilesMng.ownerId == guestId)
++           p_Fm->p_FmSp->profiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE;
++        else
++            DBG(WARNING, ("Request for freeing storage profile window which wasn't allocated to this partition"));
++    }
++}
++#endif /* (DPAA_VERSION >= 11) */
++
++static t_Error FmGuestHandleIpcMsgCB(t_Handle  h_Fm,
++                                     uint8_t   *p_Msg,
++                                     uint32_t  msgLength,
++                                     uint8_t   *p_Reply,
++                                     uint32_t  *p_ReplyLength)
++{
++    t_Fm            *p_Fm       = (t_Fm*)h_Fm;
++    t_FmIpcMsg      *p_IpcMsg   = (t_FmIpcMsg*)p_Msg;
++
++    UNUSED(p_Reply);
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((msgLength > sizeof(uint32_t)), E_INVALID_VALUE);
++
++#ifdef DISABLE_SANITY_CHECKS
++    UNUSED(msgLength);
++#endif /* DISABLE_SANITY_CHECKS */
++
++    ASSERT_COND(p_Msg);
++
++    *p_ReplyLength = 0;
++
++    switch (p_IpcMsg->msgId)
++    {
++        case (FM_GUEST_ISR):
++        {
++            t_FmIpcIsr ipcIsr;
++
++            memcpy((uint8_t*)&ipcIsr, p_IpcMsg->msgBody, sizeof(t_FmIpcIsr));
++            if (ipcIsr.boolErr)
++                GuestErrorIsr(p_Fm, ipcIsr.pendingReg);
++            else
++                GuestEventIsr(p_Fm, ipcIsr.pendingReg);
++            break;
++        }
++        default:
++            *p_ReplyLength = 0;
++            RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!"));
++    }
++    return E_OK;
++}
++
++static t_Error FmHandleIpcMsgCB(t_Handle  h_Fm,
++                                uint8_t   *p_Msg,
++                                uint32_t  msgLength,
++                                uint8_t   *p_Reply,
++                                uint32_t  *p_ReplyLength)
++{
++    t_Error         err;
++    t_Fm            *p_Fm       = (t_Fm*)h_Fm;
++    t_FmIpcMsg      *p_IpcMsg   = (t_FmIpcMsg*)p_Msg;
++    t_FmIpcReply    *p_IpcReply = (t_FmIpcReply*)p_Reply;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((msgLength >= sizeof(uint32_t)), E_INVALID_VALUE);
++
++#ifdef DISABLE_SANITY_CHECKS
++    UNUSED(msgLength);
++#endif /* DISABLE_SANITY_CHECKS */
++
++    ASSERT_COND(p_IpcMsg);
++
++    memset(p_IpcReply, 0, (sizeof(uint8_t) * FM_IPC_MAX_REPLY_SIZE));
++    *p_ReplyLength = 0;
++
++    switch (p_IpcMsg->msgId)
++    {
++        case (FM_GET_SET_PORT_PARAMS):
++        {
++            t_FmIpcPortInInitParams         ipcInitParams;
++            t_FmInterModulePortInitParams   initParams;
++            t_FmIpcPortOutInitParams        ipcOutInitParams;
++
++            memcpy((uint8_t*)&ipcInitParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortInInitParams));
++            initParams.hardwarePortId = ipcInitParams.hardwarePortId;
++            initParams.portType = (e_FmPortType)ipcInitParams.enumPortType;
++            initParams.independentMode = (bool)(ipcInitParams.boolIndependentMode);
++            initParams.liodnOffset = ipcInitParams.liodnOffset;
++            initParams.numOfTasks = ipcInitParams.numOfTasks;
++            initParams.numOfExtraTasks = ipcInitParams.numOfExtraTasks;
++            initParams.numOfOpenDmas = ipcInitParams.numOfOpenDmas;
++            initParams.numOfExtraOpenDmas = ipcInitParams.numOfExtraOpenDmas;
++            initParams.sizeOfFifo = ipcInitParams.sizeOfFifo;
++            initParams.extraSizeOfFifo = ipcInitParams.extraSizeOfFifo;
++            initParams.deqPipelineDepth = ipcInitParams.deqPipelineDepth;
++            initParams.maxFrameLength = ipcInitParams.maxFrameLength;
++            initParams.liodnBase = ipcInitParams.liodnBase;
++
++            p_IpcReply->error = (uint32_t)FmGetSetPortParams(h_Fm, &initParams);
++
++            ipcOutInitParams.ipcPhysAddr.high = initParams.fmMuramPhysBaseAddr.high;
++            ipcOutInitParams.ipcPhysAddr.low = initParams.fmMuramPhysBaseAddr.low;
++            ipcOutInitParams.sizeOfFifo = initParams.sizeOfFifo;
++            ipcOutInitParams.extraSizeOfFifo = initParams.extraSizeOfFifo;
++            ipcOutInitParams.numOfTasks = initParams.numOfTasks;
++            ipcOutInitParams.numOfExtraTasks = initParams.numOfExtraTasks;
++            ipcOutInitParams.numOfOpenDmas = initParams.numOfOpenDmas;
++            ipcOutInitParams.numOfExtraOpenDmas = initParams.numOfExtraOpenDmas;
++            memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcOutInitParams, sizeof(ipcOutInitParams));
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcPortOutInitParams);
++            break;
++        }
++        case (FM_SET_SIZE_OF_FIFO):
++        {
++            t_FmIpcPortRsrcParams   ipcPortRsrcParams;
++
++            memcpy((uint8_t*)&ipcPortRsrcParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortRsrcParams));
++            p_IpcReply->error = (uint32_t)FmSetSizeOfFifo(h_Fm,
++                                                          ipcPortRsrcParams.hardwarePortId,
++                                                          &ipcPortRsrcParams.val,
++                                                          &ipcPortRsrcParams.extra,
++                                                          (bool)ipcPortRsrcParams.boolInitialConfig);
++            *p_ReplyLength = sizeof(uint32_t);
++            break;
++        }
++        case (FM_SET_NUM_OF_TASKS):
++        {
++            t_FmIpcPortRsrcParams   ipcPortRsrcParams;
++
++            memcpy((uint8_t*)&ipcPortRsrcParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortRsrcParams));
++            p_IpcReply->error = (uint32_t)FmSetNumOfTasks(h_Fm, ipcPortRsrcParams.hardwarePortId,
++                                                          (uint8_t*)&ipcPortRsrcParams.val,
++                                                          (uint8_t*)&ipcPortRsrcParams.extra,
++                                                          (bool)ipcPortRsrcParams.boolInitialConfig);
++            *p_ReplyLength = sizeof(uint32_t);
++            break;
++        }
++        case (FM_SET_NUM_OF_OPEN_DMAS):
++        {
++            t_FmIpcPortRsrcParams   ipcPortRsrcParams;
++
++            memcpy((uint8_t*)&ipcPortRsrcParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortRsrcParams));
++            p_IpcReply->error = (uint32_t)FmSetNumOfOpenDmas(h_Fm, ipcPortRsrcParams.hardwarePortId,
++                                                               (uint8_t*)&ipcPortRsrcParams.val,
++                                                               (uint8_t*)&ipcPortRsrcParams.extra,
++                                                               (bool)ipcPortRsrcParams.boolInitialConfig);
++            *p_ReplyLength = sizeof(uint32_t);
++            break;
++        }
++        case (FM_RESUME_STALLED_PORT):
++            *p_ReplyLength = sizeof(uint32_t);
++            p_IpcReply->error = (uint32_t)FmResumeStalledPort(h_Fm, p_IpcMsg->msgBody[0]);
++            break;
++        case (FM_MASTER_IS_ALIVE):
++        {
++            uint8_t guestId = p_IpcMsg->msgBody[0];
++            /* build the FM master partition IPC address */
++            memset(p_Fm->fmIpcHandlerModuleName[guestId], 0, (sizeof(char)) * MODULE_NAME_SIZE);
++            if (Sprint (p_Fm->fmIpcHandlerModuleName[guestId], "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, guestId) != (guestId<10 ? 6:7))
++                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
++            p_Fm->h_IpcSessions[guestId] = XX_IpcInitSession(p_Fm->fmIpcHandlerModuleName[guestId], p_Fm->fmModuleName);
++            if (p_Fm->h_IpcSessions[guestId] == NULL)
++                RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("FM Master IPC session for guest %d", guestId));
++            *(uint8_t*)(p_IpcReply->replyBody) = 1;
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t);
++            break;
++        }
++        case (FM_IS_PORT_STALLED):
++        {
++            bool tmp;
++
++            p_IpcReply->error = (uint32_t)FmIsPortStalled(h_Fm, p_IpcMsg->msgBody[0], &tmp);
++            *(uint8_t*)(p_IpcReply->replyBody) = (uint8_t)tmp;
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t);
++            break;
++        }
++        case (FM_RESET_MAC):
++        {
++            t_FmIpcMacParams    ipcMacParams;
++
++            memcpy((uint8_t*)&ipcMacParams, p_IpcMsg->msgBody, sizeof(t_FmIpcMacParams));
++            p_IpcReply->error = (uint32_t)FmResetMac(p_Fm,
++                                                     (e_FmMacType)(ipcMacParams.enumType),
++                                                     ipcMacParams.id);
++            *p_ReplyLength = sizeof(uint32_t);
++            break;
++        }
++        case (FM_SET_MAC_MAX_FRAME):
++        {
++            t_FmIpcMacMaxFrameParams    ipcMacMaxFrameParams;
++
++            memcpy((uint8_t*)&ipcMacMaxFrameParams, p_IpcMsg->msgBody, sizeof(t_FmIpcMacMaxFrameParams));
++            err = FmSetMacMaxFrame(p_Fm,
++                                  (e_FmMacType)(ipcMacMaxFrameParams.macParams.enumType),
++                                  ipcMacMaxFrameParams.macParams.id,
++                                  ipcMacMaxFrameParams.maxFrameLength);
++            if (err != E_OK)
++                REPORT_ERROR(MINOR, err, NO_MSG);
++            break;
++        }
++#if (DPAA_VERSION >= 11)
++        case (FM_VSP_ALLOC) :
++        {
++            t_FmIpcResourceAllocParams  ipcAllocParams;
++            uint8_t                     vspBase;
++            memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams));
++            vspBase =  AllocVSPsForPartition(h_Fm, (uint8_t)ipcAllocParams.base, (uint8_t)ipcAllocParams.num, ipcAllocParams.guestId);
++            memcpy(p_IpcReply->replyBody, (uint8_t*)&vspBase, sizeof(uint8_t));
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t);
++            break;
++        }
++        case (FM_VSP_FREE) :
++        {
++            t_FmIpcResourceAllocParams   ipcAllocParams;
++            memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams));
++            FreeVSPsForPartition(h_Fm, (uint8_t)ipcAllocParams.base, (uint8_t)ipcAllocParams.num, ipcAllocParams.guestId);
++            break;
++        }
++        case (FM_VSP_SET_PORT_WINDOW) :
++        {
++            t_FmIpcVspSetPortWindow   ipcVspSetPortWindow;
++            memcpy(&ipcVspSetPortWindow, p_IpcMsg->msgBody, sizeof(t_FmIpcVspSetPortWindow));
++            err = SetVSPWindow(h_Fm,
++                                            ipcVspSetPortWindow.hardwarePortId,
++                                            ipcVspSetPortWindow.baseStorageProfile,
++                                            ipcVspSetPortWindow.log2NumOfProfiles);
++            return err;
++        }
++        case (FM_SET_CONG_GRP_PFC_PRIO) :
++        {
++            t_FmIpcSetCongestionGroupPfcPriority    fmIpcSetCongestionGroupPfcPriority;
++            memcpy(&fmIpcSetCongestionGroupPfcPriority, p_IpcMsg->msgBody, sizeof(t_FmIpcSetCongestionGroupPfcPriority));
++            err = FmSetCongestionGroupPFCpriority(h_Fm,
++                                                  fmIpcSetCongestionGroupPfcPriority.congestionGroupId,
++                                                  fmIpcSetCongestionGroupPfcPriority.priorityBitMap);
++            return err;
++        }
++#endif /* (DPAA_VERSION >= 11) */
++
++        case (FM_FREE_PORT):
++        {
++            t_FmInterModulePortFreeParams   portParams;
++            t_FmIpcPortFreeParams           ipcPortParams;
++
++            memcpy((uint8_t*)&ipcPortParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortFreeParams));
++            portParams.hardwarePortId = ipcPortParams.hardwarePortId;
++            portParams.portType = (e_FmPortType)(ipcPortParams.enumPortType);
++            portParams.deqPipelineDepth = ipcPortParams.deqPipelineDepth;
++            FmFreePortParams(h_Fm, &portParams);
++            break;
++        }
++        case (FM_REGISTER_INTR):
++        {
++            t_FmIpcRegisterIntr ipcRegIntr;
++
++            memcpy((uint8_t*)&ipcRegIntr, p_IpcMsg->msgBody, sizeof(ipcRegIntr));
++            p_Fm->intrMng[ipcRegIntr.event].guestId = ipcRegIntr.guestId;
++            break;
++        }
++        case (FM_GET_PARAMS):
++        {
++             t_FmIpcParams  ipcParams;
++
++            /* Get clock frequency */
++            ipcParams.fmClkFreq = p_Fm->p_FmStateStruct->fmClkFreq;
++            ipcParams.fmMacClkFreq = p_Fm->p_FmStateStruct->fmMacClkFreq;
++
++            fman_get_revision(p_Fm->p_FmFpmRegs,&ipcParams.majorRev,&ipcParams.minorRev);
++
++            memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcParams, sizeof(t_FmIpcParams));
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcParams);
++             break;
++        }
++        case (FM_GET_FMAN_CTRL_CODE_REV):
++        {
++            t_FmCtrlCodeRevisionInfo        fmanCtrlRevInfo;
++            t_FmIpcFmanCtrlCodeRevisionInfo ipcRevInfo;
++
++            p_IpcReply->error = (uint32_t)FM_GetFmanCtrlCodeRevision(h_Fm, &fmanCtrlRevInfo);
++            ipcRevInfo.packageRev = fmanCtrlRevInfo.packageRev;
++            ipcRevInfo.majorRev = fmanCtrlRevInfo.majorRev;
++            ipcRevInfo.minorRev = fmanCtrlRevInfo.minorRev;
++            memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcRevInfo, sizeof(t_FmIpcFmanCtrlCodeRevisionInfo));
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcFmanCtrlCodeRevisionInfo);
++            break;
++        }
++
++        case (FM_DMA_STAT):
++        {
++            t_FmDmaStatus       dmaStatus;
++            t_FmIpcDmaStatus    ipcDmaStatus;
++
++            FM_GetDmaStatus(h_Fm, &dmaStatus);
++            ipcDmaStatus.boolCmqNotEmpty = (uint8_t)dmaStatus.cmqNotEmpty;
++            ipcDmaStatus.boolBusError = (uint8_t)dmaStatus.busError;
++            ipcDmaStatus.boolReadBufEccError = (uint8_t)dmaStatus.readBufEccError;
++            ipcDmaStatus.boolWriteBufEccSysError = (uint8_t)dmaStatus.writeBufEccSysError;
++            ipcDmaStatus.boolWriteBufEccFmError = (uint8_t)dmaStatus.writeBufEccFmError;
++            ipcDmaStatus.boolSinglePortEccError = (uint8_t)dmaStatus.singlePortEccError;
++            memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcDmaStatus, sizeof(t_FmIpcDmaStatus));
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcDmaStatus);
++            break;
++        }
++        case (FM_ALLOC_FMAN_CTRL_EVENT_REG):
++            p_IpcReply->error = (uint32_t)FmAllocFmanCtrlEventReg(h_Fm, (uint8_t*)p_IpcReply->replyBody);
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t);
++            break;
++        case (FM_FREE_FMAN_CTRL_EVENT_REG):
++            FmFreeFmanCtrlEventReg(h_Fm, p_IpcMsg->msgBody[0]);
++            break;
++        case (FM_GET_TIMESTAMP_SCALE):
++        {
++            uint32_t    timeStamp = FmGetTimeStampScale(h_Fm);
++
++            memcpy(p_IpcReply->replyBody, (uint8_t*)&timeStamp, sizeof(uint32_t));
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t);
++            break;
++        }
++        case (FM_GET_COUNTER):
++        {
++            e_FmCounters    inCounter;
++            uint32_t        outCounter;
++
++            memcpy((uint8_t*)&inCounter, p_IpcMsg->msgBody, sizeof(uint32_t));
++            outCounter = FM_GetCounter(h_Fm, inCounter);
++            memcpy(p_IpcReply->replyBody, (uint8_t*)&outCounter, sizeof(uint32_t));
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t);
++            break;
++        }
++        case (FM_SET_FMAN_CTRL_EVENTS_ENABLE):
++        {
++            t_FmIpcFmanEvents ipcFmanEvents;
++
++            memcpy((uint8_t*)&ipcFmanEvents, p_IpcMsg->msgBody, sizeof(t_FmIpcFmanEvents));
++            FmSetFmanCtrlIntr(h_Fm,
++                              ipcFmanEvents.eventRegId,
++                              ipcFmanEvents.enableEvents);
++            break;
++        }
++        case (FM_GET_FMAN_CTRL_EVENTS_ENABLE):
++        {
++            uint32_t    tmp = FmGetFmanCtrlIntr(h_Fm, p_IpcMsg->msgBody[0]);
++
++            memcpy(p_IpcReply->replyBody, (uint8_t*)&tmp, sizeof(uint32_t));
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t);
++            break;
++        }
++        case (FM_GET_PHYS_MURAM_BASE):
++        {
++            t_FmPhysAddr        physAddr;
++            t_FmIpcPhysAddr     ipcPhysAddr;
++
++            FmGetPhysicalMuramBase(h_Fm, &physAddr);
++            ipcPhysAddr.high    = physAddr.high;
++            ipcPhysAddr.low     = physAddr.low;
++            memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcPhysAddr, sizeof(t_FmIpcPhysAddr));
++            *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcPhysAddr);
++            break;
++        }
++        case (FM_ENABLE_RAM_ECC):
++        {
++            if (((err = FM_EnableRamsEcc(h_Fm)) != E_OK) ||
++                ((err = FM_SetException(h_Fm, e_FM_EX_IRAM_ECC, TRUE)) != E_OK) ||
++                ((err = FM_SetException(h_Fm, e_FM_EX_MURAM_ECC, TRUE)) != E_OK))
++#if (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0))
++                UNUSED(err);
++#else
++                REPORT_ERROR(MINOR, err, NO_MSG);
++#endif /* (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0)) */
++            break;
++        }
++        case (FM_DISABLE_RAM_ECC):
++        {
++
++            if (((err = FM_SetException(h_Fm, e_FM_EX_IRAM_ECC, FALSE)) != E_OK) ||
++                ((err = FM_SetException(h_Fm, e_FM_EX_MURAM_ECC, FALSE)) != E_OK) ||
++                ((err = FM_DisableRamsEcc(h_Fm)) != E_OK))
++#if (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0))
++                UNUSED(err);
++#else
++                REPORT_ERROR(MINOR, err, NO_MSG);
++#endif /* (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0)) */
++            break;
++        }
++        case (FM_SET_NUM_OF_FMAN_CTRL):
++        {
++            t_FmIpcPortNumOfFmanCtrls   ipcPortNumOfFmanCtrls;
++
++            memcpy((uint8_t*)&ipcPortNumOfFmanCtrls, p_IpcMsg->msgBody, sizeof(t_FmIpcPortNumOfFmanCtrls));
++            err = FmSetNumOfRiscsPerPort(h_Fm,
++                                         ipcPortNumOfFmanCtrls.hardwarePortId,
++                                         ipcPortNumOfFmanCtrls.numOfFmanCtrls,
++                                         ipcPortNumOfFmanCtrls.orFmanCtrl);
++            if (err != E_OK)
++                REPORT_ERROR(MINOR, err, NO_MSG);
++            break;
++        }
++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
++        case (FM_10G_TX_ECC_WA):
++            p_IpcReply->error = (uint32_t)Fm10GTxEccWorkaround(h_Fm, p_IpcMsg->msgBody[0]);
++            *p_ReplyLength = sizeof(uint32_t);
++            break;
++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
++        default:
++            *p_ReplyLength = 0;
++            RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!"));
++    }
++    return E_OK;
++}
++
++
++/****************************************/
++/*       Inter-Module functions         */
++/****************************************/
++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
++t_Error Fm10GTxEccWorkaround(t_Handle h_Fm, uint8_t macId)
++{
++    t_Fm            *p_Fm = (t_Fm*)h_Fm;
++    t_Error         err = E_OK;
++    t_FmIpcMsg      msg;
++    t_FmIpcReply    reply;
++    uint32_t        replyLength;
++    uint8_t         rxHardwarePortId, txHardwarePortId;
++    struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
++
++    if (p_Fm->guestId != NCSW_MASTER_ID)
++    {
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_10G_TX_ECC_WA;
++        msg.msgBody[0] = macId;
++        replyLength = sizeof(uint32_t);
++        if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                     (uint8_t*)&msg,
++                                     sizeof(msg.msgId)+sizeof(macId),
++                                     (uint8_t*)&reply,
++                                     &replyLength,
++                                     NULL,
++                                     NULL)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        if (replyLength != sizeof(uint32_t))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++        return (t_Error)(reply.error);
++    }
++
++    SANITY_CHECK_RETURN_ERROR((macId == 0), E_NOT_SUPPORTED);
++    SANITY_CHECK_RETURN_ERROR(IsFmanCtrlCodeLoaded(p_Fm), E_INVALID_STATE);
++
++    rxHardwarePortId = SwPortIdToHwPortId(e_FM_PORT_TYPE_RX_10G,
++                                    macId,
++                                    p_Fm->p_FmStateStruct->revInfo.majorRev,
++                                    p_Fm->p_FmStateStruct->revInfo.minorRev);
++    txHardwarePortId = SwPortIdToHwPortId(e_FM_PORT_TYPE_TX_10G,
++                                    macId,
++                                    p_Fm->p_FmStateStruct->revInfo.majorRev,
++                                    p_Fm->p_FmStateStruct->revInfo.minorRev);
++    if ((p_Fm->p_FmStateStruct->portsTypes[rxHardwarePortId] != e_FM_PORT_TYPE_DUMMY) ||
++        (p_Fm->p_FmStateStruct->portsTypes[txHardwarePortId] != e_FM_PORT_TYPE_DUMMY))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                     ("MAC should be initialized prior to Rx and Tx ports!"));
++
++    return fman_set_erratum_10gmac_a004_wa(fpm_rg);
++}
++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
++
++uint16_t FmGetTnumAgingPeriod(t_Handle h_Fm)
++{
++    t_Fm *p_Fm = (t_Fm *)h_Fm;
++
++    SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0);
++    SANITY_CHECK_RETURN_VALUE(!p_Fm->p_FmDriverParam, E_INVALID_STATE, 0);
++
++    return p_Fm->tnumAgingPeriod;
++}
++
++t_Error FmSetPortPreFetchConfiguration(t_Handle h_Fm,
++                                       uint8_t  portNum,
++                                       bool     preFetchConfigured)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
++
++    p_Fm->portsPreFetchConfigured[portNum] = TRUE;
++    p_Fm->portsPreFetchValue[portNum] = preFetchConfigured;
++
++    return E_OK;
++}
++
++t_Error FmGetPortPreFetchConfiguration(t_Handle h_Fm,
++                                       uint8_t  portNum,
++                                       bool     *p_PortConfigured,
++                                       bool     *p_PreFetchConfigured)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
++
++    /* If the prefetch wasn't configured yet (not enable or disabled)
++       we return the value TRUE as it was already configured */
++    if (!p_Fm->portsPreFetchConfigured[portNum])
++    {
++        *p_PortConfigured = FALSE;
++        *p_PreFetchConfigured = FALSE;
++    }
++    else
++    {
++        *p_PortConfigured = TRUE;
++        *p_PreFetchConfigured = (p_Fm->portsPreFetchConfigured[portNum]);
++    }
++
++    return E_OK;
++}
++
++t_Error FmSetCongestionGroupPFCpriority(t_Handle    h_Fm,
++                                        uint32_t    congestionGroupId,
++                                        uint8_t     priorityBitMap)
++{
++    t_Fm    *p_Fm  = (t_Fm *)h_Fm;
++    uint32_t regNum;
++
++    ASSERT_COND(h_Fm);
++
++    if (congestionGroupId > FM_PORT_NUM_OF_CONGESTION_GRPS)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++                     ("Congestion group ID bigger than %d",
++                      FM_PORT_NUM_OF_CONGESTION_GRPS));
++
++    if (p_Fm->guestId == NCSW_MASTER_ID)
++    {
++        ASSERT_COND(p_Fm->baseAddr);
++        regNum = (FM_PORT_NUM_OF_CONGESTION_GRPS - 1 - congestionGroupId) / 4;
++        fman_set_congestion_group_pfc_priority((uint32_t *)((p_Fm->baseAddr+FM_MM_CGP)),
++                                               congestionGroupId,
++                                               priorityBitMap,
++                                               regNum);
++    }
++    else if (p_Fm->h_IpcSessions[0])
++    {
++        t_Error                              err;
++        t_FmIpcMsg                           msg;
++        t_FmIpcSetCongestionGroupPfcPriority fmIpcSetCongestionGroupPfcPriority;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&fmIpcSetCongestionGroupPfcPriority, 0, sizeof(t_FmIpcSetCongestionGroupPfcPriority));
++        fmIpcSetCongestionGroupPfcPriority.congestionGroupId = congestionGroupId;
++        fmIpcSetCongestionGroupPfcPriority.priorityBitMap    = priorityBitMap;
++
++        msg.msgId = FM_SET_CONG_GRP_PFC_PRIO;
++        memcpy(msg.msgBody, &fmIpcSetCongestionGroupPfcPriority, sizeof(t_FmIpcSetCongestionGroupPfcPriority));
++
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId),
++                                NULL,
++                                NULL,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++    else
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("guest without IPC!"));
++
++    return E_OK;
++}
++
++uintptr_t FmGetPcdPrsBaseAddr(t_Handle h_Fm)
++{
++    t_Fm        *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0);
++
++    if (!p_Fm->baseAddr)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_STATE,
++                     ("No base-addr; probably Guest with IPC!"));
++        return 0;
++    }
++
++    return (p_Fm->baseAddr + FM_MM_PRS);
++}
++
++uintptr_t FmGetPcdKgBaseAddr(t_Handle h_Fm)
++{
++    t_Fm        *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0);
++
++    if (!p_Fm->baseAddr)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_STATE,
++                     ("No base-addr; probably Guest with IPC!"));
++        return 0;
++    }
++
++    return (p_Fm->baseAddr + FM_MM_KG);
++}
++
++uintptr_t FmGetPcdPlcrBaseAddr(t_Handle h_Fm)
++{
++    t_Fm        *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0);
++
++    if (!p_Fm->baseAddr)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_STATE,
++                     ("No base-addr; probably Guest with IPC!"));
++        return 0;
++    }
++
++    return (p_Fm->baseAddr + FM_MM_PLCR);
++}
++
++#if (DPAA_VERSION >= 11)
++uintptr_t FmGetVSPBaseAddr(t_Handle h_Fm)
++{
++    t_Fm        *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0);
++
++    return p_Fm->vspBaseAddr;
++}
++#endif /* (DPAA_VERSION >= 11) */
++
++t_Handle FmGetMuramHandle(t_Handle h_Fm)
++{
++    t_Fm        *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, NULL);
++
++    return (p_Fm->h_FmMuram);
++}
++
++void FmGetPhysicalMuramBase(t_Handle h_Fm, t_FmPhysAddr *p_FmPhysAddr)
++{
++    t_Fm            *p_Fm = (t_Fm*)h_Fm;
++
++    if (p_Fm->fmMuramPhysBaseAddr)
++    {
++        /* General FM driver initialization */
++        p_FmPhysAddr->low = (uint32_t)p_Fm->fmMuramPhysBaseAddr;
++        p_FmPhysAddr->high = (uint8_t)((p_Fm->fmMuramPhysBaseAddr & 0x000000ff00000000LL) >> 32);
++        return;
++    }
++
++    ASSERT_COND(p_Fm->guestId != NCSW_MASTER_ID);
++
++    if (p_Fm->h_IpcSessions[0])
++    {
++        t_Error         err;
++        t_FmIpcMsg      msg;
++        t_FmIpcReply    reply;
++        uint32_t        replyLength;
++        t_FmIpcPhysAddr ipcPhysAddr;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_GET_PHYS_MURAM_BASE;
++        replyLength = sizeof(uint32_t) + sizeof(t_FmPhysAddr);
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId),
++                                (uint8_t*)&reply,
++                                &replyLength,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++        {
++            REPORT_ERROR(MINOR, err, NO_MSG);
++            return;
++        }
++        if (replyLength != (sizeof(uint32_t) + sizeof(t_FmPhysAddr)))
++        {
++            REPORT_ERROR(MINOR, E_INVALID_VALUE,("IPC reply length mismatch"));
++            return;
++        }
++        memcpy((uint8_t*)&ipcPhysAddr, reply.replyBody, sizeof(t_FmIpcPhysAddr));
++        p_FmPhysAddr->high = ipcPhysAddr.high;
++        p_FmPhysAddr->low  = ipcPhysAddr.low;
++    }
++    else
++        REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("running in guest-mode without neither IPC nor mapped register!"));
++}
++
++#if (DPAA_VERSION >= 11)
++t_Error FmVSPAllocForPort (t_Handle        h_Fm,
++                           e_FmPortType    portType,
++                           uint8_t         portId,
++                           uint8_t         numOfVSPs)
++{
++    t_Fm           *p_Fm = (t_Fm *)h_Fm;
++    t_Error        err = E_OK;
++    uint32_t       profilesFound, intFlags;
++    uint8_t        first, i;
++    uint8_t        log2Num;
++    uint8_t        swPortIndex=0, hardwarePortId;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++
++     if (!numOfVSPs)
++        return E_OK;
++
++    if (numOfVSPs > FM_VSP_MAX_NUM_OF_ENTRIES)
++        RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles can not be bigger than %d.",FM_VSP_MAX_NUM_OF_ENTRIES));
++
++    if (!POWER_OF_2(numOfVSPs))
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numProfiles must be a power of 2."));
++
++    LOG2((uint64_t)numOfVSPs, log2Num);
++
++    if ((log2Num == 0) || (p_Fm->partVSPBase == 0))
++        first = 0;
++    else
++        first = 1<<log2Num;
++
++    if (first > (p_Fm->partVSPBase + p_Fm->partNumOfVSPs))
++         RETURN_ERROR(MINOR, E_INVALID_VALUE, ("can not allocate storage profile port window"));
++
++    if (first < p_Fm->partVSPBase)
++        while (first < p_Fm->partVSPBase)
++            first = first + numOfVSPs;
++
++    if ((first + numOfVSPs) > (p_Fm->partVSPBase + p_Fm->partNumOfVSPs))
++        RETURN_ERROR(MINOR, E_INVALID_VALUE, ("can not allocate storage profile port window"));
++
++    intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock);
++    profilesFound = 0;
++    for (i=first; i < p_Fm->partVSPBase + p_Fm->partNumOfVSPs; )
++    {
++        if (!p_Fm->p_FmSp->profiles[i].profilesMng.allocated)
++        {
++            profilesFound++;
++            i++;
++            if (profilesFound == numOfVSPs)
++                break;
++        }
++        else
++        {
++            profilesFound = 0;
++            /* advance i to the next aligned address */
++            first = i = (uint8_t)(first + numOfVSPs);
++        }
++    }
++    if (profilesFound == numOfVSPs)
++        for (i = first; i<first + numOfVSPs; i++)
++            p_Fm->p_FmSp->profiles[i].profilesMng.allocated = TRUE;
++    else
++    {
++        XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
++        RETURN_ERROR(MINOR, E_FULL, ("No profiles."));
++    }
++
++    hardwarePortId = SwPortIdToHwPortId(portType,
++                                    portId,
++                                    p_Fm->p_FmStateStruct->revInfo.majorRev,
++                                    p_Fm->p_FmStateStruct->revInfo.minorRev);
++    HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
++
++    p_Fm->p_FmSp->portsMapping[swPortIndex].numOfProfiles = numOfVSPs;
++    p_Fm->p_FmSp->portsMapping[swPortIndex].profilesBase = first;
++
++    if ((err = SetVSPWindow(h_Fm,hardwarePortId, first,log2Num)) != E_OK)
++        for (i = first; i < first + numOfVSPs; i++)
++            p_Fm->p_FmSp->profiles[i].profilesMng.allocated = FALSE;
++
++    XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
++
++    return err;
++}
++
++t_Error FmVSPFreeForPort(t_Handle        h_Fm,
++                         e_FmPortType    portType,
++                         uint8_t         portId)
++{
++    t_Fm            *p_Fm = (t_Fm *)h_Fm;
++    uint8_t         swPortIndex=0, hardwarePortId, first, numOfVSPs, i;
++    uint32_t        intFlags;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++
++    hardwarePortId = SwPortIdToHwPortId(portType,
++                                    portId,
++                                    p_Fm->p_FmStateStruct->revInfo.majorRev,
++                                    p_Fm->p_FmStateStruct->revInfo.minorRev);
++    HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
++
++    numOfVSPs = (uint8_t)p_Fm->p_FmSp->portsMapping[swPortIndex].numOfProfiles;
++    first = (uint8_t)p_Fm->p_FmSp->portsMapping[swPortIndex].profilesBase;
++
++    intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock);
++    for (i = first; i < first + numOfVSPs; i++)
++           p_Fm->p_FmSp->profiles[i].profilesMng.allocated = FALSE;
++    XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
++
++    p_Fm->p_FmSp->portsMapping[swPortIndex].numOfProfiles = 0;
++    p_Fm->p_FmSp->portsMapping[swPortIndex].profilesBase = 0;
++
++    return E_OK;
++}
++#endif /* (DPAA_VERSION >= 11) */
++
++t_Error FmAllocFmanCtrlEventReg(t_Handle h_Fm, uint8_t *p_EventId)
++{
++    t_Fm            *p_Fm = (t_Fm*)h_Fm;
++    uint8_t         i;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_Error         err;
++        t_FmIpcMsg      msg;
++        t_FmIpcReply    reply;
++        uint32_t        replyLength;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_ALLOC_FMAN_CTRL_EVENT_REG;
++        replyLength = sizeof(uint32_t) + sizeof(uint8_t);
++        if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                     (uint8_t*)&msg,
++                                     sizeof(msg.msgId),
++                                     (uint8_t*)&reply,
++                                     &replyLength,
++                                     NULL,
++                                     NULL)) != E_OK)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++
++        if (replyLength != (sizeof(uint32_t) + sizeof(uint8_t)))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++
++        *p_EventId = *(uint8_t*)(reply.replyBody);
++
++        return (t_Error)(reply.error);
++    }
++    else if (p_Fm->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("running in guest-mode without IPC!"));
++
++    for (i=0;i<FM_NUM_OF_FMAN_CTRL_EVENT_REGS;i++)
++        if (!p_Fm->usedEventRegs[i])
++        {
++            p_Fm->usedEventRegs[i] = TRUE;
++            *p_EventId = i;
++            break;
++        }
++
++    if (i==FM_NUM_OF_FMAN_CTRL_EVENT_REGS)
++        RETURN_ERROR(MAJOR, E_BUSY, ("No resource - FMan controller event register."));
++
++    return E_OK;
++}
++
++void FmFreeFmanCtrlEventReg(t_Handle h_Fm, uint8_t eventId)
++{
++    t_Fm        *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE);
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_Error     err;
++        t_FmIpcMsg  msg;
++
++        memset(&msg, 0, sizeof(msg));
++        msg.msgId = FM_FREE_FMAN_CTRL_EVENT_REG;
++        msg.msgBody[0] = eventId;
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId)+sizeof(eventId),
++                                NULL,
++                                NULL,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            REPORT_ERROR(MINOR, err, NO_MSG);
++        return;
++    }
++    else if (p_Fm->guestId != NCSW_MASTER_ID)
++    {
++        REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("running in guest-mode without IPC!"));
++        return;
++    }
++
++    ((t_Fm*)h_Fm)->usedEventRegs[eventId] = FALSE;
++}
++
++void FmSetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, uint32_t enableEvents)
++{
++    t_Fm                *p_Fm = (t_Fm*)h_Fm;
++    struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        !p_Fm->p_FmFpmRegs &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_FmIpcFmanEvents   fmanCtrl;
++        t_Error             err;
++        t_FmIpcMsg          msg;
++
++        fmanCtrl.eventRegId = eventRegId;
++        fmanCtrl.enableEvents = enableEvents;
++        memset(&msg, 0, sizeof(msg));
++        msg.msgId = FM_SET_FMAN_CTRL_EVENTS_ENABLE;
++        memcpy(msg.msgBody, &fmanCtrl, sizeof(fmanCtrl));
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId)+sizeof(fmanCtrl),
++                                NULL,
++                                NULL,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            REPORT_ERROR(MINOR, err, NO_MSG);
++        return;
++    }
++    else if (!p_Fm->p_FmFpmRegs)
++    {
++        REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("Either IPC or 'baseAddress' is required!"));
++        return;
++    }
++
++    ASSERT_COND(eventRegId < FM_NUM_OF_FMAN_CTRL_EVENT_REGS);
++    fman_set_ctrl_intr(fpm_rg, eventRegId, enableEvents);
++}
++
++uint32_t FmGetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId)
++{
++    t_Fm            *p_Fm = (t_Fm*)h_Fm;
++    struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        !p_Fm->p_FmFpmRegs &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_Error         err;
++        t_FmIpcMsg      msg;
++        t_FmIpcReply    reply;
++        uint32_t        replyLength, ctrlIntr;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_GET_FMAN_CTRL_EVENTS_ENABLE;
++        msg.msgBody[0] = eventRegId;
++        replyLength = sizeof(uint32_t) + sizeof(uint32_t);
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId)+sizeof(eventRegId),
++                                (uint8_t*)&reply,
++                                &replyLength,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++        {
++            REPORT_ERROR(MINOR, err, NO_MSG);
++            return 0;
++        }
++        if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t)))
++        {
++            REPORT_ERROR(MINOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++            return 0;
++        }
++        memcpy((uint8_t*)&ctrlIntr, reply.replyBody, sizeof(uint32_t));
++        return ctrlIntr;
++    }
++    else if (!p_Fm->p_FmFpmRegs)
++    {
++        REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("Either IPC or 'baseAddress' is required!"));
++        return 0;
++    }
++
++    return fman_get_ctrl_intr(fpm_rg, eventRegId);
++}
++
++void FmRegisterIntr(t_Handle                h_Fm,
++                    e_FmEventModules        module,
++                    uint8_t                 modId,
++                    e_FmIntrType            intrType,
++                    void                    (*f_Isr) (t_Handle h_Arg),
++                    t_Handle                h_Arg)
++{
++    t_Fm                *p_Fm = (t_Fm*)h_Fm;
++    int                 event = 0;
++
++    ASSERT_COND(h_Fm);
++
++    GET_FM_MODULE_EVENT(module, modId, intrType, event);
++    ASSERT_COND(event < e_FM_EV_DUMMY_LAST);
++
++    /* register in local FM structure */
++    p_Fm->intrMng[event].f_Isr = f_Isr;
++    p_Fm->intrMng[event].h_SrcHandle = h_Arg;
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_FmIpcRegisterIntr fmIpcRegisterIntr;
++        t_Error             err;
++        t_FmIpcMsg          msg;
++
++        /* register in Master FM structure */
++        fmIpcRegisterIntr.event = (uint32_t)event;
++        fmIpcRegisterIntr.guestId = p_Fm->guestId;
++        memset(&msg, 0, sizeof(msg));
++        msg.msgId = FM_REGISTER_INTR;
++        memcpy(msg.msgBody, &fmIpcRegisterIntr, sizeof(fmIpcRegisterIntr));
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId) + sizeof(fmIpcRegisterIntr),
++                                NULL,
++                                NULL,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            REPORT_ERROR(MINOR, err, NO_MSG);
++    }
++    else if (p_Fm->guestId != NCSW_MASTER_ID)
++        REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("running in guest-mode without IPC!"));
++}
++
++void FmUnregisterIntr(t_Handle                  h_Fm,
++                        e_FmEventModules        module,
++                        uint8_t                 modId,
++                        e_FmIntrType            intrType)
++{
++    t_Fm        *p_Fm = (t_Fm*)h_Fm;
++    int         event = 0;
++
++    ASSERT_COND(h_Fm);
++
++    GET_FM_MODULE_EVENT(module, modId,intrType, event);
++    ASSERT_COND(event < e_FM_EV_DUMMY_LAST);
++
++    p_Fm->intrMng[event].f_Isr = UnimplementedIsr;
++    p_Fm->intrMng[event].h_SrcHandle = NULL;
++}
++
++void  FmRegisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, void (*f_Isr) (t_Handle h_Arg, uint32_t event), t_Handle    h_Arg)
++{
++    t_Fm       *p_Fm = (t_Fm*)h_Fm;
++
++    ASSERT_COND(eventRegId<FM_NUM_OF_FMAN_CTRL_EVENT_REGS);
++
++    if (p_Fm->guestId != NCSW_MASTER_ID)
++    {
++        REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM in guest-mode"));
++        return;
++    }
++
++    p_Fm->fmanCtrlIntr[eventRegId].f_Isr = f_Isr;
++    p_Fm->fmanCtrlIntr[eventRegId].h_SrcHandle = h_Arg;
++}
++
++void  FmUnregisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId)
++{
++    t_Fm       *p_Fm = (t_Fm*)h_Fm;
++
++    ASSERT_COND(eventRegId<FM_NUM_OF_FMAN_CTRL_EVENT_REGS);
++
++    if (p_Fm->guestId != NCSW_MASTER_ID)
++    {
++        REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM in guest-mode"));
++        return;
++    }
++
++    p_Fm->fmanCtrlIntr[eventRegId].f_Isr = UnimplementedFmanCtrlIsr;
++    p_Fm->fmanCtrlIntr[eventRegId].h_SrcHandle = NULL;
++}
++
++void  FmRegisterPcd(t_Handle h_Fm, t_Handle h_FmPcd)
++{
++    t_Fm       *p_Fm = (t_Fm*)h_Fm;
++
++    if (p_Fm->h_Pcd)
++        REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("PCD already set"));
++
++    p_Fm->h_Pcd = h_FmPcd;
++}
++
++void  FmUnregisterPcd(t_Handle h_Fm)
++{
++    t_Fm       *p_Fm = (t_Fm*)h_Fm;
++
++    if (!p_Fm->h_Pcd)
++        REPORT_ERROR(MAJOR, E_NOT_FOUND, ("PCD handle!"));
++
++    p_Fm->h_Pcd = NULL;
++}
++
++t_Handle FmGetPcdHandle(t_Handle h_Fm)
++{
++    t_Fm       *p_Fm = (t_Fm*)h_Fm;
++
++    return p_Fm->h_Pcd;
++}
++
++uint8_t FmGetId(t_Handle h_Fm)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0xff);
++
++    return p_Fm->p_FmStateStruct->fmId;
++}
++
++t_Error FmReset(t_Handle h_Fm)
++{
++      t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++
++    WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rstc, FPM_RSTC_FM_RESET);
++    CORE_MemoryBarrier();
++    XX_UDelay(100);
++
++    return E_OK;
++}
++
++t_Error FmSetNumOfRiscsPerPort(t_Handle     h_Fm,
++                               uint8_t      hardwarePortId,
++                               uint8_t      numOfFmanCtrls,
++                               t_FmFmanCtrl orFmanCtrl)
++{
++
++    t_Fm                        *p_Fm = (t_Fm*)h_Fm;
++    struct fman_fpm_regs *fpm_rg;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(((numOfFmanCtrls > 0) && (numOfFmanCtrls < 3)) , E_INVALID_HANDLE);
++
++    fpm_rg = p_Fm->p_FmFpmRegs;
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        !p_Fm->p_FmFpmRegs &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_Error                     err;
++        t_FmIpcPortNumOfFmanCtrls   params;
++        t_FmIpcMsg                  msg;
++
++        memset(&msg, 0, sizeof(msg));
++        params.hardwarePortId = hardwarePortId;
++        params.numOfFmanCtrls = numOfFmanCtrls;
++        params.orFmanCtrl = orFmanCtrl;
++        msg.msgId = FM_SET_NUM_OF_FMAN_CTRL;
++        memcpy(msg.msgBody, &params, sizeof(params));
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId) +sizeof(params),
++                                NULL,
++                                NULL,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        return E_OK;
++    }
++    else if (!p_Fm->p_FmFpmRegs)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("Either IPC or 'baseAddress' is required!"));
++
++    fman_set_num_of_riscs_per_port(fpm_rg, hardwarePortId, numOfFmanCtrls, orFmanCtrl);
++
++    return E_OK;
++}
++
++t_Error FmGetSetPortParams(t_Handle h_Fm, t_FmInterModulePortInitParams *p_PortParams)
++{
++    t_Fm                    *p_Fm = (t_Fm*)h_Fm;
++    t_Error                 err;
++    uint32_t                intFlags;
++    uint8_t                 hardwarePortId = p_PortParams->hardwarePortId, macId;
++    struct fman_rg          fman_rg;
++
++    fman_rg.bmi_rg = p_Fm->p_FmBmiRegs;
++    fman_rg.qmi_rg = p_Fm->p_FmQmiRegs;
++    fman_rg.fpm_rg = p_Fm->p_FmFpmRegs;
++    fman_rg.dma_rg = p_Fm->p_FmDmaRegs;
++
++    if (p_Fm->guestId != NCSW_MASTER_ID)
++    {
++        t_FmIpcPortInInitParams     portInParams;
++        t_FmIpcPortOutInitParams    portOutParams;
++        t_FmIpcMsg                  msg;
++        t_FmIpcReply                reply;
++        uint32_t                    replyLength;
++
++        portInParams.hardwarePortId     = p_PortParams->hardwarePortId;
++        portInParams.enumPortType       = (uint32_t)p_PortParams->portType;
++        portInParams.boolIndependentMode= (uint8_t)p_PortParams->independentMode;
++        portInParams.liodnOffset        = p_PortParams->liodnOffset;
++        portInParams.numOfTasks         = p_PortParams->numOfTasks;
++        portInParams.numOfExtraTasks    = p_PortParams->numOfExtraTasks;
++        portInParams.numOfOpenDmas      = p_PortParams->numOfOpenDmas;
++        portInParams.numOfExtraOpenDmas = p_PortParams->numOfExtraOpenDmas;
++        portInParams.sizeOfFifo         = p_PortParams->sizeOfFifo;
++        portInParams.extraSizeOfFifo    = p_PortParams->extraSizeOfFifo;
++        portInParams.deqPipelineDepth   = p_PortParams->deqPipelineDepth;
++        portInParams.maxFrameLength     = p_PortParams->maxFrameLength;
++        portInParams.liodnBase          = p_PortParams->liodnBase;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_GET_SET_PORT_PARAMS;
++        memcpy(msg.msgBody, &portInParams, sizeof(portInParams));
++        replyLength = (sizeof(uint32_t) + sizeof(t_FmIpcPortOutInitParams));
++        if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                     (uint8_t*)&msg,
++                                     sizeof(msg.msgId) +sizeof(portInParams),
++                                     (uint8_t*)&reply,
++                                     &replyLength,
++                                     NULL,
++                                     NULL)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        if (replyLength != (sizeof(uint32_t) + sizeof(t_FmIpcPortOutInitParams)))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++        memcpy((uint8_t*)&portOutParams, reply.replyBody, sizeof(t_FmIpcPortOutInitParams));
++
++        p_PortParams->fmMuramPhysBaseAddr.high = portOutParams.ipcPhysAddr.high;
++        p_PortParams->fmMuramPhysBaseAddr.low  = portOutParams.ipcPhysAddr.low;
++        p_PortParams->numOfTasks = portOutParams.numOfTasks;
++        p_PortParams->numOfExtraTasks = portOutParams.numOfExtraTasks;
++        p_PortParams->numOfOpenDmas = portOutParams.numOfOpenDmas;
++        p_PortParams->numOfExtraOpenDmas = portOutParams.numOfExtraOpenDmas;
++        p_PortParams->sizeOfFifo = portOutParams.sizeOfFifo;
++        p_PortParams->extraSizeOfFifo = portOutParams.extraSizeOfFifo;
++
++        return (t_Error)(reply.error);
++    }
++
++    ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
++
++    intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock);
++    if (p_PortParams->independentMode)
++    {
++        /* set port parameters */
++        p_Fm->independentMode = p_PortParams->independentMode;
++        /* disable dispatch limit */
++        fman_qmi_disable_dispatch_limit(fman_rg.fpm_rg);
++    }
++
++    if (p_PortParams->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)
++    {
++        if (p_Fm->hcPortInitialized)
++        {
++            XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Only one host command port is allowed."));
++        }
++        else
++            p_Fm->hcPortInitialized = TRUE;
++    }
++    p_Fm->p_FmStateStruct->portsTypes[hardwarePortId] = p_PortParams->portType;
++
++    err = FmSetNumOfTasks(p_Fm, hardwarePortId, &p_PortParams->numOfTasks, &p_PortParams->numOfExtraTasks, TRUE);
++    if (err)
++    {
++        XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
++    if (p_Fm->p_FmStateStruct->revInfo.majorRev != 4)
++#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
++    if ((p_PortParams->portType != e_FM_PORT_TYPE_RX) &&
++       (p_PortParams->portType != e_FM_PORT_TYPE_RX_10G))
++    /* for transmit & O/H ports */
++    {
++        uint8_t     enqTh;
++        uint8_t     deqTh;
++
++        /* update qmi ENQ/DEQ threshold */
++        p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums += p_PortParams->deqPipelineDepth;
++        enqTh = fman_get_qmi_enq_th(fman_rg.qmi_rg);
++        /* if enqTh is too big, we reduce it to the max value that is still OK */
++        if (enqTh >= (QMI_MAX_NUM_OF_TNUMS - p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums))
++        {
++            enqTh = (uint8_t)(QMI_MAX_NUM_OF_TNUMS - p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums - 1);
++            fman_set_qmi_enq_th(fman_rg.qmi_rg, enqTh);
++        }
++
++        deqTh = fman_get_qmi_deq_th(fman_rg.qmi_rg);
++        /* if deqTh is too small, we enlarge it to the min value that is still OK.
++         deqTh may not be larger than 63 (QMI_MAX_NUM_OF_TNUMS-1). */
++        if ((deqTh <= p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums)  && (deqTh < QMI_MAX_NUM_OF_TNUMS-1))
++        {
++            deqTh = (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums + 1);
++            fman_set_qmi_deq_th(fman_rg.qmi_rg, deqTh);
++        }
++    }
++
++#ifdef FM_LOW_END_RESTRICTION
++    if ((hardwarePortId==0x1) || (hardwarePortId==0x29))
++    {
++        if (p_Fm->p_FmStateStruct->lowEndRestriction)
++        {
++            XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
++            RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("OP #0 cannot work with Tx Port #1."));
++        }
++        else
++            p_Fm->p_FmStateStruct->lowEndRestriction = TRUE;
++    }
++#endif /* FM_LOW_END_RESTRICTION */
++
++    err = FmSetSizeOfFifo(p_Fm,
++                          hardwarePortId,
++                          &p_PortParams->sizeOfFifo,
++                          &p_PortParams->extraSizeOfFifo,
++                          TRUE);
++    if (err)
++    {
++        XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    err = FmSetNumOfOpenDmas(p_Fm,
++                             hardwarePortId,
++                             &p_PortParams->numOfOpenDmas,
++                             &p_PortParams->numOfExtraOpenDmas,
++                             TRUE);
++    if (err)
++    {
++        XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    fman_set_liodn_per_port(&fman_rg,
++                            hardwarePortId,
++                            p_PortParams->liodnBase,
++                            p_PortParams->liodnOffset);
++
++    if (p_Fm->p_FmStateStruct->revInfo.majorRev < 6)
++        fman_set_order_restoration_per_port(fman_rg.fpm_rg,
++                                            hardwarePortId,
++                                            p_PortParams->independentMode,
++                                            !!((p_PortParams->portType==e_FM_PORT_TYPE_RX) || (p_PortParams->portType==e_FM_PORT_TYPE_RX_10G)));
++
++    HW_PORT_ID_TO_SW_PORT_ID(macId, hardwarePortId);
++
++#if defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS)
++    if ((p_PortParams->portType == e_FM_PORT_TYPE_TX_10G) ||
++        (p_PortParams->portType == e_FM_PORT_TYPE_RX_10G))
++    {
++        ASSERT_COND(macId < FM_MAX_NUM_OF_10G_MACS);
++        if (p_PortParams->maxFrameLength >= p_Fm->p_FmStateStruct->macMaxFrameLengths10G[macId])
++            p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId] = p_PortParams->maxFrameLength;
++        else
++            RETURN_ERROR(MINOR, E_INVALID_VALUE, ("Port maxFrameLength is smaller than MAC current MTU"));
++    }
++    else
++#endif /* defined(FM_MAX_NUM_OF_10G_MACS) && ... */
++    if ((p_PortParams->portType == e_FM_PORT_TYPE_TX) ||
++        (p_PortParams->portType == e_FM_PORT_TYPE_RX))
++    {
++        ASSERT_COND(macId < FM_MAX_NUM_OF_1G_MACS);
++        if (p_PortParams->maxFrameLength >= p_Fm->p_FmStateStruct->macMaxFrameLengths1G[macId])
++            p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId] = p_PortParams->maxFrameLength;
++        else
++            RETURN_ERROR(MINOR, E_INVALID_VALUE, ("Port maxFrameLength is smaller than MAC current MTU"));
++    }
++
++    FmGetPhysicalMuramBase(p_Fm, &p_PortParams->fmMuramPhysBaseAddr);
++    XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
++
++    return E_OK;
++}
++
++void FmFreePortParams(t_Handle h_Fm,t_FmInterModulePortFreeParams *p_PortParams)
++{
++    t_Fm                    *p_Fm = (t_Fm*)h_Fm;
++    uint32_t                intFlags;
++    uint8_t                 hardwarePortId = p_PortParams->hardwarePortId;
++    uint8_t                 numOfTasks, numOfDmas, macId;
++    uint16_t                sizeOfFifo;
++    t_Error                 err;
++    t_FmIpcPortFreeParams   portParams;
++    t_FmIpcMsg              msg;
++    struct fman_qmi_regs *qmi_rg = p_Fm->p_FmQmiRegs;
++    struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs;
++
++    if (p_Fm->guestId != NCSW_MASTER_ID)
++    {
++        portParams.hardwarePortId = p_PortParams->hardwarePortId;
++        portParams.enumPortType = (uint32_t)p_PortParams->portType;
++        portParams.deqPipelineDepth = p_PortParams->deqPipelineDepth;
++        memset(&msg, 0, sizeof(msg));
++        msg.msgId = FM_FREE_PORT;
++        memcpy(msg.msgBody, &portParams, sizeof(portParams));
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId)+sizeof(portParams),
++                                NULL,
++                                NULL,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            REPORT_ERROR(MINOR, err, NO_MSG);
++        return;
++    }
++
++    ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
++
++    intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock);
++
++    if (p_PortParams->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)
++    {
++        ASSERT_COND(p_Fm->hcPortInitialized);
++        p_Fm->hcPortInitialized = FALSE;
++    }
++
++    p_Fm->p_FmStateStruct->portsTypes[hardwarePortId] = e_FM_PORT_TYPE_DUMMY;
++
++    /* free numOfTasks */
++    numOfTasks = fman_get_num_of_tasks(bmi_rg, hardwarePortId);
++    ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfTasks >= numOfTasks);
++    p_Fm->p_FmStateStruct->accumulatedNumOfTasks -= numOfTasks;
++
++    /* free numOfOpenDmas */
++    numOfDmas = fman_get_num_of_dmas(bmi_rg, hardwarePortId);
++    ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas >= numOfDmas);
++    p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas -= numOfDmas;
++
++#ifdef FM_HAS_TOTAL_DMAS
++    if (p_Fm->p_FmStateStruct->revInfo.majorRev < 6)
++    {
++        /* update total num of DMA's with committed number of open DMAS, and max uncommitted pool. */
++        fman_set_num_of_open_dmas(bmi_rg,
++                                  hardwarePortId,
++                                  1,
++                                  0,
++                         (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize));
++    }
++#endif /* FM_HAS_TOTAL_DMAS */
++
++    /* free sizeOfFifo */
++    sizeOfFifo = fman_get_size_of_fifo(bmi_rg, hardwarePortId);
++    ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedFifoSize >= (sizeOfFifo * BMI_FIFO_UNITS));
++    p_Fm->p_FmStateStruct->accumulatedFifoSize -= (sizeOfFifo * BMI_FIFO_UNITS);
++
++#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
++    if (p_Fm->p_FmStateStruct->revInfo.majorRev != 4)
++#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
++    if ((p_PortParams->portType != e_FM_PORT_TYPE_RX) &&
++        (p_PortParams->portType != e_FM_PORT_TYPE_RX_10G))
++    /* for transmit & O/H ports */
++    {
++        uint8_t     enqTh;
++        uint8_t     deqTh;
++
++        /* update qmi ENQ/DEQ threshold */
++        p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums -= p_PortParams->deqPipelineDepth;
++
++        /* p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums is now smaller,
++           so we can enlarge enqTh */
++        enqTh = (uint8_t)(QMI_MAX_NUM_OF_TNUMS - p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums - 1);
++
++         /* p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums is now smaller,
++            so we can reduce deqTh */
++        deqTh = (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums + 1);
++
++        fman_set_qmi_enq_th(qmi_rg, enqTh);
++        fman_set_qmi_deq_th(qmi_rg, deqTh);
++    }
++
++    HW_PORT_ID_TO_SW_PORT_ID(macId, hardwarePortId);
++
++#if defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS)
++    if ((p_PortParams->portType == e_FM_PORT_TYPE_TX_10G) ||
++        (p_PortParams->portType == e_FM_PORT_TYPE_RX_10G))
++    {
++        ASSERT_COND(macId < FM_MAX_NUM_OF_10G_MACS);
++        p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId] = 0;
++    }
++    else
++#endif /* defined(FM_MAX_NUM_OF_10G_MACS) && ... */
++    if ((p_PortParams->portType == e_FM_PORT_TYPE_TX) ||
++        (p_PortParams->portType == e_FM_PORT_TYPE_RX))
++    {
++        ASSERT_COND(macId < FM_MAX_NUM_OF_1G_MACS);
++        p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId] = 0;
++    }
++
++#ifdef FM_LOW_END_RESTRICTION
++    if ((hardwarePortId==0x1) || (hardwarePortId==0x29))
++        p_Fm->p_FmStateStruct->lowEndRestriction = FALSE;
++#endif /* FM_LOW_END_RESTRICTION */
++    XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
++}
++
++t_Error FmIsPortStalled(t_Handle h_Fm, uint8_t hardwarePortId, bool *p_IsStalled)
++{
++    t_Fm            *p_Fm = (t_Fm*)h_Fm;
++    t_Error         err;
++    t_FmIpcMsg      msg;
++    t_FmIpcReply    reply;
++    uint32_t        replyLength;
++    struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        !p_Fm->baseAddr &&
++        p_Fm->h_IpcSessions[0])
++    {
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_IS_PORT_STALLED;
++        msg.msgBody[0] = hardwarePortId;
++        replyLength = sizeof(uint32_t) + sizeof(uint8_t);
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId)+sizeof(hardwarePortId),
++                                (uint8_t*)&reply,
++                                &replyLength,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        if (replyLength != (sizeof(uint32_t) + sizeof(uint8_t)))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++
++        *p_IsStalled = (bool)!!(*(uint8_t*)(reply.replyBody));
++
++        return (t_Error)(reply.error);
++    }
++    else if (!p_Fm->baseAddr)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("Either IPC or 'baseAddress' is required!"));
++
++    *p_IsStalled = fman_is_port_stalled(fpm_rg, hardwarePortId);
++
++    return E_OK;
++}
++
++t_Error FmResumeStalledPort(t_Handle h_Fm, uint8_t hardwarePortId)
++{
++    t_Fm            *p_Fm = (t_Fm*)h_Fm;
++    t_Error         err;
++    bool            isStalled;
++    struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        !p_Fm->baseAddr &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_FmIpcMsg      msg;
++        t_FmIpcReply    reply;
++        uint32_t        replyLength;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_RESUME_STALLED_PORT;
++        msg.msgBody[0] = hardwarePortId;
++        replyLength = sizeof(uint32_t);
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId) + sizeof(hardwarePortId),
++                                (uint8_t*)&reply,
++                                &replyLength,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        if (replyLength != sizeof(uint32_t))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++        return (t_Error)(reply.error);
++    }
++    else if (!p_Fm->baseAddr)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("Either IPC or 'baseAddress' is required!"));
++
++    if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
++        RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Not available for this FM revision!"));
++
++    /* Get port status */
++    err = FmIsPortStalled(h_Fm, hardwarePortId, &isStalled);
++    if (err)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't get port status"));
++    if (!isStalled)
++        return E_OK;
++
++    fman_resume_stalled_port(fpm_rg, hardwarePortId);
++
++    return E_OK;
++}
++
++t_Error FmResetMac(t_Handle h_Fm, e_FmMacType type, uint8_t macId)
++{
++    t_Fm                *p_Fm = (t_Fm*)h_Fm;
++    t_Error             err;
++    struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
++
++#if (DPAA_VERSION >= 11)
++    if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("FMan MAC reset!"));
++#endif /*(DPAA_VERSION >= 11)*/
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        !p_Fm->baseAddr &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_FmIpcMacParams    macParams;
++        t_FmIpcMsg          msg;
++        t_FmIpcReply        reply;
++        uint32_t            replyLength;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        macParams.id = macId;
++        macParams.enumType = (uint32_t)type;
++        msg.msgId = FM_RESET_MAC;
++        memcpy(msg.msgBody,  &macParams, sizeof(macParams));
++        replyLength = sizeof(uint32_t);
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId)+sizeof(macParams),
++                                (uint8_t*)&reply,
++                                &replyLength,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        if (replyLength != sizeof(uint32_t))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++        return (t_Error)(reply.error);
++    }
++    else if (!p_Fm->baseAddr)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("Either IPC or 'baseAddress' is required!"));
++
++    err = (t_Error)fman_reset_mac(fpm_rg, macId, !!(type == e_FM_MAC_10G));
++
++    if (err == -EBUSY)
++        return ERROR_CODE(E_TIMEOUT);
++    else if (err)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal MAC ID"));
++
++    return E_OK;
++}
++
++t_Error FmSetMacMaxFrame(t_Handle h_Fm, e_FmMacType type, uint8_t macId, uint16_t mtu)
++{
++    t_Fm                        *p_Fm = (t_Fm*)h_Fm;
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_FmIpcMacMaxFrameParams    macMaxFrameLengthParams;
++        t_Error                     err;
++        t_FmIpcMsg                  msg;
++
++        memset(&msg, 0, sizeof(msg));
++        macMaxFrameLengthParams.macParams.id = macId;
++        macMaxFrameLengthParams.macParams.enumType = (uint32_t)type;
++        macMaxFrameLengthParams.maxFrameLength = (uint16_t)mtu;
++        msg.msgId = FM_SET_MAC_MAX_FRAME;
++        memcpy(msg.msgBody,  &macMaxFrameLengthParams, sizeof(macMaxFrameLengthParams));
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId)+sizeof(macMaxFrameLengthParams),
++                                NULL,
++                                NULL,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        return E_OK;
++    }
++    else if (p_Fm->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("running in guest-mode without IPC!"));
++
++    /* if port is already initialized, check that MaxFrameLength is smaller
++     * or equal to the port's max */
++#if (defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS))
++    if (type == e_FM_MAC_10G)
++    {
++        if ((!p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId])
++           || (p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId] &&
++              (mtu <= p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId])))
++               p_Fm->p_FmStateStruct->macMaxFrameLengths10G[macId] = mtu;
++        else
++            RETURN_ERROR(MINOR, E_INVALID_VALUE, ("MAC maxFrameLength is larger than Port maxFrameLength"));
++
++    }
++    else
++#else
++    UNUSED(type);
++#endif /* (defined(FM_MAX_NUM_OF_10G_MACS) && ... */
++    if ((!p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId])
++       || (p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId] &&
++          (mtu <= p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId])))
++        p_Fm->p_FmStateStruct->macMaxFrameLengths1G[macId] = mtu;
++    else
++        RETURN_ERROR(MINOR, E_INVALID_VALUE, ("MAC maxFrameLength is larger than Port maxFrameLength"));
++
++    return E_OK;
++}
++
++uint16_t FmGetClockFreq(t_Handle h_Fm)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    /* for multicore environment: this depends on the
++     * fact that fmClkFreq was properly initialized at "init". */
++    return p_Fm->p_FmStateStruct->fmClkFreq;
++}
++
++uint16_t FmGetMacClockFreq(t_Handle h_Fm)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    return p_Fm->p_FmStateStruct->fmMacClkFreq;
++}
++
++uint32_t FmGetTimeStampScale(t_Handle h_Fm)
++{
++    t_Fm                *p_Fm = (t_Fm*)h_Fm;
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        !p_Fm->baseAddr &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_Error             err;
++        t_FmIpcMsg          msg;
++        t_FmIpcReply        reply;
++        uint32_t            replyLength, timeStamp;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_GET_TIMESTAMP_SCALE;
++        replyLength = sizeof(uint32_t) + sizeof(uint32_t);
++        if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                     (uint8_t*)&msg,
++                                     sizeof(msg.msgId),
++                                     (uint8_t*)&reply,
++                                     &replyLength,
++                                     NULL,
++                                     NULL)) != E_OK)
++        {
++            REPORT_ERROR(MAJOR, err, NO_MSG);
++            return 0;
++        }
++        if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t)))
++        {
++            REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++            return 0;
++        }
++
++        memcpy((uint8_t*)&timeStamp, reply.replyBody, sizeof(uint32_t));
++        return timeStamp;
++    }
++    else if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++             p_Fm->baseAddr)
++    {
++        if (!(GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_tsc1) & FPM_TS_CTL_EN))
++        {
++            REPORT_ERROR(MAJOR, E_INVALID_STATE, ("timestamp is not enabled!"));
++            return 0;
++        }
++    }
++    else if (p_Fm->guestId != NCSW_MASTER_ID)
++        DBG(WARNING, ("No IPC - can't validate FM if timestamp enabled."));
++
++    return p_Fm->p_FmStateStruct->count1MicroBit;
++}
++
++t_Error FmEnableRamsEcc(t_Handle h_Fm)
++{
++    t_Fm        *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++
++    p_Fm->p_FmStateStruct->ramsEccOwners++;
++    p_Fm->p_FmStateStruct->internalCall = TRUE;
++
++    return FM_EnableRamsEcc(p_Fm);
++}
++
++t_Error FmDisableRamsEcc(t_Handle h_Fm)
++{
++    t_Fm        *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++
++    ASSERT_COND(p_Fm->p_FmStateStruct->ramsEccOwners);
++    p_Fm->p_FmStateStruct->ramsEccOwners--;
++
++    if (p_Fm->p_FmStateStruct->ramsEccOwners==0)
++    {
++        p_Fm->p_FmStateStruct->internalCall = TRUE;
++        return FM_DisableRamsEcc(p_Fm);
++    }
++
++    return E_OK;
++}
++
++uint8_t FmGetGuestId(t_Handle h_Fm)
++{
++    t_Fm     *p_Fm = (t_Fm*)h_Fm;
++
++    return p_Fm->guestId;
++}
++
++bool FmIsMaster(t_Handle h_Fm)
++{
++    t_Fm     *p_Fm = (t_Fm*)h_Fm;
++
++    return (p_Fm->guestId == NCSW_MASTER_ID);
++}
++
++t_Error FmSetSizeOfFifo(t_Handle    h_Fm,
++                        uint8_t     hardwarePortId,
++                        uint32_t    *p_SizeOfFifo,
++                        uint32_t    *p_ExtraSizeOfFifo,
++                        bool        initialConfig)
++{
++    t_Fm                    *p_Fm = (t_Fm*)h_Fm;
++    t_FmIpcPortRsrcParams   rsrcParams;
++    t_Error                 err;
++    struct fman_bmi_regs    *bmi_rg = p_Fm->p_FmBmiRegs;
++    uint32_t                sizeOfFifo = *p_SizeOfFifo, extraSizeOfFifo = *p_ExtraSizeOfFifo;
++    uint16_t                currentVal = 0, currentExtraVal = 0;
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        !p_Fm->baseAddr &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_FmIpcMsg          msg;
++        t_FmIpcReply        reply;
++        uint32_t            replyLength;
++
++        rsrcParams.hardwarePortId = hardwarePortId;
++        rsrcParams.val = sizeOfFifo;
++        rsrcParams.extra = extraSizeOfFifo;
++        rsrcParams.boolInitialConfig = (uint8_t)initialConfig;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_SET_SIZE_OF_FIFO;
++        memcpy(msg.msgBody, &rsrcParams, sizeof(rsrcParams));
++        replyLength = sizeof(uint32_t);
++        if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                     (uint8_t*)&msg,
++                                     sizeof(msg.msgId) + sizeof(rsrcParams),
++                                     (uint8_t*)&reply,
++                                     &replyLength,
++                                     NULL,
++                                     NULL)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        if (replyLength != sizeof(uint32_t))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++        return (t_Error)(reply.error);
++    }
++    else if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++             p_Fm->baseAddr)
++    {
++        DBG(WARNING, ("No IPC - can't validate FM total-fifo size."));
++        fman_set_size_of_fifo(bmi_rg, hardwarePortId, sizeOfFifo, extraSizeOfFifo);
++    }
++    else if (p_Fm->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
++                     ("running in guest-mode without neither IPC nor mapped register!"));
++
++    if (!initialConfig)
++    {
++        /* !initialConfig - runtime change of existing value.
++         * - read the current FIFO and extra FIFO size */
++        currentExtraVal = fman_get_size_of_extra_fifo(bmi_rg, hardwarePortId);
++        currentVal = fman_get_size_of_fifo(bmi_rg, hardwarePortId);
++    }
++
++    if (extraSizeOfFifo > currentExtraVal)
++    {
++        if (extraSizeOfFifo && !p_Fm->p_FmStateStruct->extraFifoPoolSize)
++            /* if this is the first time a port requires extraFifoPoolSize, the total extraFifoPoolSize
++             * must be initialized to 1 buffer per port
++             */
++            p_Fm->p_FmStateStruct->extraFifoPoolSize = FM_MAX_NUM_OF_RX_PORTS*BMI_FIFO_UNITS;
++
++        p_Fm->p_FmStateStruct->extraFifoPoolSize = MAX(p_Fm->p_FmStateStruct->extraFifoPoolSize, extraSizeOfFifo);
++    }
++
++    /* check that there are enough uncommitted fifo size */
++    if ((p_Fm->p_FmStateStruct->accumulatedFifoSize - currentVal + sizeOfFifo) >
++        (p_Fm->p_FmStateStruct->totalFifoSize - p_Fm->p_FmStateStruct->extraFifoPoolSize)){
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE,
++            ("Port request fifo size + accumulated size > total FIFO size:"));
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
++            ("port 0x%x requested %d bytes, extra size = %d, accumulated size = %d total size = %d",
++                hardwarePortId, sizeOfFifo, p_Fm->p_FmStateStruct->extraFifoPoolSize,
++                p_Fm->p_FmStateStruct->accumulatedFifoSize,
++                p_Fm->p_FmStateStruct->totalFifoSize));
++    }
++    else
++    {
++        /* update accumulated */
++        ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedFifoSize >= currentVal);
++        p_Fm->p_FmStateStruct->accumulatedFifoSize -= currentVal;
++        p_Fm->p_FmStateStruct->accumulatedFifoSize += sizeOfFifo;
++        fman_set_size_of_fifo(bmi_rg, hardwarePortId, sizeOfFifo, extraSizeOfFifo);
++    }
++
++    return E_OK;
++}
++
++t_Error FmSetNumOfTasks(t_Handle    h_Fm,
++                        uint8_t     hardwarePortId,
++                        uint8_t     *p_NumOfTasks,
++                        uint8_t     *p_NumOfExtraTasks,
++                        bool        initialConfig)
++{
++    t_Fm                    *p_Fm = (t_Fm *)h_Fm;
++    t_Error                 err;
++    struct fman_bmi_regs    *bmi_rg = p_Fm->p_FmBmiRegs;
++    uint8_t                 currentVal = 0, currentExtraVal = 0, numOfTasks = *p_NumOfTasks, numOfExtraTasks = *p_NumOfExtraTasks;
++
++    ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        !p_Fm->baseAddr &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_FmIpcPortRsrcParams   rsrcParams;
++        t_FmIpcMsg              msg;
++        t_FmIpcReply            reply;
++        uint32_t                replyLength;
++
++        rsrcParams.hardwarePortId = hardwarePortId;
++        rsrcParams.val = numOfTasks;
++        rsrcParams.extra = numOfExtraTasks;
++        rsrcParams.boolInitialConfig = (uint8_t)initialConfig;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_SET_NUM_OF_TASKS;
++        memcpy(msg.msgBody, &rsrcParams, sizeof(rsrcParams));
++        replyLength = sizeof(uint32_t);
++        if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                     (uint8_t*)&msg,
++                                     sizeof(msg.msgId) + sizeof(rsrcParams),
++                                     (uint8_t*)&reply,
++                                     &replyLength,
++                                     NULL,
++                                     NULL)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        if (replyLength != sizeof(uint32_t))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++        return (t_Error)(reply.error);
++    }
++    else if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++             p_Fm->baseAddr)
++    {
++        DBG(WARNING, ("No IPC - can't validate FM total-num-of-tasks."));
++        fman_set_num_of_tasks(bmi_rg, hardwarePortId, numOfTasks, numOfExtraTasks);
++    }
++    else if (p_Fm->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
++                     ("running in guest-mode without neither IPC nor mapped register!"));
++
++    if (!initialConfig)
++    {
++        /* !initialConfig - runtime change of existing value.
++         * - read the current number of tasks */
++        currentVal = fman_get_num_of_tasks(bmi_rg, hardwarePortId);
++        currentExtraVal = fman_get_num_extra_tasks(bmi_rg, hardwarePortId);
++    }
++
++    if (numOfExtraTasks > currentExtraVal)
++         p_Fm->p_FmStateStruct->extraTasksPoolSize =
++             (uint8_t)MAX(p_Fm->p_FmStateStruct->extraTasksPoolSize, numOfExtraTasks);
++
++    /* check that there are enough uncommitted tasks */
++    if ((p_Fm->p_FmStateStruct->accumulatedNumOfTasks - currentVal + numOfTasks) >
++       (p_Fm->p_FmStateStruct->totalNumOfTasks - p_Fm->p_FmStateStruct->extraTasksPoolSize))
++        RETURN_ERROR(MAJOR, E_NOT_AVAILABLE,
++                     ("Requested numOfTasks and extra tasks pool for fm%d exceed total numOfTasks.",
++                      p_Fm->p_FmStateStruct->fmId));
++    else
++    {
++        ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfTasks >= currentVal);
++        /* update accumulated */
++        p_Fm->p_FmStateStruct->accumulatedNumOfTasks -= currentVal;
++        p_Fm->p_FmStateStruct->accumulatedNumOfTasks += numOfTasks;
++        fman_set_num_of_tasks(bmi_rg, hardwarePortId, numOfTasks, numOfExtraTasks);
++    }
++
++    return E_OK;
++}
++
++t_Error FmSetNumOfOpenDmas(t_Handle h_Fm,
++                           uint8_t hardwarePortId,
++                           uint8_t *p_NumOfOpenDmas,
++                           uint8_t *p_NumOfExtraOpenDmas,
++                           bool    initialConfig)
++
++{
++    t_Fm                    *p_Fm = (t_Fm *)h_Fm;
++    t_Error                 err;
++    struct fman_bmi_regs    *bmi_rg = p_Fm->p_FmBmiRegs;
++    uint8_t                 numOfOpenDmas = *p_NumOfOpenDmas, numOfExtraOpenDmas = *p_NumOfExtraOpenDmas;
++    uint8_t                 totalNumDmas = 0, currentVal = 0, currentExtraVal = 0;
++
++    ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        !p_Fm->baseAddr &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_FmIpcPortRsrcParams   rsrcParams;
++        t_FmIpcMsg              msg;
++        t_FmIpcReply            reply;
++        uint32_t                replyLength;
++
++        rsrcParams.hardwarePortId = hardwarePortId;
++        rsrcParams.val = numOfOpenDmas;
++        rsrcParams.extra = numOfExtraOpenDmas;
++        rsrcParams.boolInitialConfig = (uint8_t)initialConfig;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_SET_NUM_OF_OPEN_DMAS;
++        memcpy(msg.msgBody, &rsrcParams, sizeof(rsrcParams));
++        replyLength = sizeof(uint32_t);
++        if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                     (uint8_t*)&msg,
++                                     sizeof(msg.msgId) + sizeof(rsrcParams),
++                                     (uint8_t*)&reply,
++                                     &replyLength,
++                                     NULL,
++                                     NULL)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        if (replyLength != sizeof(uint32_t))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++        return (t_Error)(reply.error);
++    }
++#ifdef FM_HAS_TOTAL_DMAS
++    else if (p_Fm->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("running in guest-mode without IPC!"));
++#else
++    else if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++             p_Fm->baseAddr &&
++             (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6))
++    {
++        /*DBG(WARNING, ("No IPC - can't validate FM total-num-of-dmas."));*/
++
++        if (!numOfOpenDmas)
++        {
++             /* first config without explic it value: Do Nothing - reset value shouldn't be
++                changed, read register for port save */
++                *p_NumOfOpenDmas = fman_get_num_of_dmas(bmi_rg, hardwarePortId);
++                *p_NumOfExtraOpenDmas = fman_get_num_extra_dmas(bmi_rg, hardwarePortId);
++        }
++        else
++            /* whether it is the first time with explicit value, or runtime "set" - write register */
++            fman_set_num_of_open_dmas(bmi_rg,
++                                   hardwarePortId,
++                                   numOfOpenDmas,
++                                   numOfExtraOpenDmas,
++                                   p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize);
++    }
++    else if (p_Fm->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
++                     ("running in guest-mode without neither IPC nor mapped register!"));
++#endif /* FM_HAS_TOTAL_DMAS */
++
++    if (!initialConfig)
++    {
++        /* !initialConfig - runtime change of existing value.
++         * - read the current number of open Dma's */
++        currentExtraVal = fman_get_num_extra_dmas(bmi_rg, hardwarePortId);
++        currentVal = fman_get_num_of_dmas(bmi_rg, hardwarePortId);
++    }
++
++#ifdef FM_NO_GUARANTEED_RESET_VALUES
++    /* it's illegal to be in a state where this is not the first set and no value is specified */
++    ASSERT_COND(initialConfig || numOfOpenDmas);
++    if (!numOfOpenDmas)
++    {
++        /* !numOfOpenDmas - first configuration according to values in regs.
++         * - read the current number of open Dma's */
++        currentExtraVal = fman_get_num_extra_dmas(bmi_rg, hardwarePortId);
++        currentVal = fman_get_num_of_dmas(bmi_rg, hardwarePortId);
++        /* This is the first configuration and user did not specify value (!numOfOpenDmas),
++         * reset values will be used and we just save these values for resource management */
++        p_Fm->p_FmStateStruct->extraOpenDmasPoolSize =
++                    (uint8_t)MAX(p_Fm->p_FmStateStruct->extraOpenDmasPoolSize, currentExtraVal);
++        p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas += currentVal;
++        *p_NumOfOpenDmas = currentVal;
++        *p_NumOfExtraOpenDmas = currentExtraVal;
++        return E_OK;
++    }
++#endif /* FM_NO_GUARANTEED_RESET_VALUES */
++
++        if (numOfExtraOpenDmas > currentExtraVal)
++             p_Fm->p_FmStateStruct->extraOpenDmasPoolSize =
++                 (uint8_t)MAX(p_Fm->p_FmStateStruct->extraOpenDmasPoolSize, numOfExtraOpenDmas);
++
++#ifdef FM_HAS_TOTAL_DMAS
++        if ((p_Fm->p_FmStateStruct->revInfo.majorRev < 6) &&
++            (p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas - currentVal + numOfOpenDmas >
++                p_Fm->p_FmStateStruct->maxNumOfOpenDmas))
++                RETURN_ERROR(MAJOR, E_NOT_AVAILABLE,
++                             ("Requested numOfOpenDmas for fm%d exceeds total numOfOpenDmas.",
++                             p_Fm->p_FmStateStruct->fmId));
++#else
++        if ((p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) &&
++#ifdef FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981
++            !((p_Fm->p_FmStateStruct->revInfo.majorRev == 6) &&
++              (p_Fm->p_FmStateStruct->revInfo.minorRev == 0)) &&
++#endif /* FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 */
++            (p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas - currentVal + numOfOpenDmas > DMA_THRESH_MAX_COMMQ + 1))
++            RETURN_ERROR(MAJOR, E_NOT_AVAILABLE,
++                         ("Requested numOfOpenDmas for fm%d exceeds DMA Command queue (%d)",
++                          p_Fm->p_FmStateStruct->fmId, DMA_THRESH_MAX_COMMQ+1));
++#endif /* FM_HAS_TOTAL_DMAS */
++        else
++        {
++            ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas >= currentVal);
++            /* update acummulated */
++            p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas -= currentVal;
++            p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas += numOfOpenDmas;
++
++#ifdef FM_HAS_TOTAL_DMAS
++            if (p_Fm->p_FmStateStruct->revInfo.majorRev < 6)
++            totalNumDmas = (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize);
++#endif /* FM_HAS_TOTAL_DMAS */
++            fman_set_num_of_open_dmas(bmi_rg,
++                               hardwarePortId,
++                               numOfOpenDmas,
++                               numOfExtraOpenDmas,
++                               totalNumDmas);
++        }
++
++    return E_OK;
++}
++
++#if (DPAA_VERSION >= 11)
++t_Error FmVSPCheckRelativeProfile(t_Handle        h_Fm,
++                                  e_FmPortType    portType,
++                                  uint8_t         portId,
++                                  uint16_t        relativeProfile)
++{
++    t_Fm         *p_Fm;
++    t_FmSp      *p_FmPcdSp;
++    uint8_t     swPortIndex=0, hardwarePortId;
++
++    ASSERT_COND(h_Fm);
++    p_Fm = (t_Fm*)h_Fm;
++
++    hardwarePortId = SwPortIdToHwPortId(portType,
++                                    portId,
++                                    p_Fm->p_FmStateStruct->revInfo.majorRev,
++                                    p_Fm->p_FmStateStruct->revInfo.minorRev);
++    ASSERT_COND(hardwarePortId);
++    HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
++
++    p_FmPcdSp = p_Fm->p_FmSp;
++    ASSERT_COND(p_FmPcdSp);
++
++    if (!p_FmPcdSp->portsMapping[swPortIndex].numOfProfiles)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE , ("Port has no allocated profiles"));
++    if (relativeProfile >= p_FmPcdSp->portsMapping[swPortIndex].numOfProfiles)
++        RETURN_ERROR(MAJOR, E_NOT_IN_RANGE , ("Profile id is out of range"));
++
++    return E_OK;
++}
++
++t_Error FmVSPGetAbsoluteProfileId(t_Handle        h_Fm,
++                                  e_FmPortType    portType,
++                                  uint8_t         portId,
++                                  uint16_t        relativeProfile,
++                                  uint16_t        *p_AbsoluteId)
++{
++    t_Fm         *p_Fm;
++    t_FmSp      *p_FmPcdSp;
++    uint8_t     swPortIndex=0, hardwarePortId;
++    t_Error     err;
++
++    ASSERT_COND(h_Fm);
++    p_Fm = (t_Fm*)h_Fm;
++
++    err = FmVSPCheckRelativeProfile(h_Fm, portType, portId, relativeProfile);
++    if (err != E_OK)
++        return err;
++
++    hardwarePortId = SwPortIdToHwPortId(portType,
++                                    portId,
++                                    p_Fm->p_FmStateStruct->revInfo.majorRev,
++                                    p_Fm->p_FmStateStruct->revInfo.minorRev);
++    ASSERT_COND(hardwarePortId);
++    HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
++
++    p_FmPcdSp = p_Fm->p_FmSp;
++    ASSERT_COND(p_FmPcdSp);
++
++    *p_AbsoluteId = (uint16_t)(p_FmPcdSp->portsMapping[swPortIndex].profilesBase + relativeProfile);
++
++    return E_OK;
++}
++#endif /* (DPAA_VERSION >= 11) */
++
++static t_Error InitFmDma(t_Fm *p_Fm)
++{
++    t_Error err;
++
++    err = (t_Error)fman_dma_init(p_Fm->p_FmDmaRegs, p_Fm->p_FmDriverParam);
++    if (err != E_OK)
++        return err;
++
++    /* Allocate MURAM for CAM */
++    p_Fm->camBaseAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram,
++                                                      (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*DMA_CAM_SIZEOF_ENTRY),
++                                                      DMA_CAM_ALIGN));
++    if (!p_Fm->camBaseAddr)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for DMA CAM failed"));
++
++    WRITE_BLOCK(UINT_TO_PTR(p_Fm->camBaseAddr),
++                0,
++                (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*DMA_CAM_SIZEOF_ENTRY));
++
++    if (p_Fm->p_FmStateStruct->revInfo.majorRev == 2)
++    {
++        FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->camBaseAddr));
++
++        p_Fm->camBaseAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram,
++                                                          (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*72 + 128),
++                                                          64));
++        if (!p_Fm->camBaseAddr)
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for DMA CAM failed"));
++
++        WRITE_BLOCK(UINT_TO_PTR(p_Fm->camBaseAddr),
++                   0,
++               (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*72 + 128));
++
++        switch(p_Fm->p_FmDriverParam->dma_cam_num_of_entries)
++        {
++            case (8):
++                WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xff000000);
++                break;
++            case (16):
++                WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xffff0000);
++                break;
++            case (24):
++                WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xffffff00);
++                break;
++            case (32):
++                WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xffffffff);
++                break;
++            default:
++                RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("wrong dma_cam_num_of_entries"));
++        }
++    }
++
++    p_Fm->p_FmDriverParam->cam_base_addr =
++                 (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->camBaseAddr)) - p_Fm->fmMuramPhysBaseAddr);
++
++    return E_OK;
++}
++
++static t_Error InitFmFpm(t_Fm *p_Fm)
++{
++    return (t_Error)fman_fpm_init(p_Fm->p_FmFpmRegs, p_Fm->p_FmDriverParam);
++}
++
++static t_Error InitFmBmi(t_Fm *p_Fm)
++{
++    return (t_Error)fman_bmi_init(p_Fm->p_FmBmiRegs, p_Fm->p_FmDriverParam);
++}
++
++static t_Error InitFmQmi(t_Fm *p_Fm)
++{
++    return (t_Error)fman_qmi_init(p_Fm->p_FmQmiRegs, p_Fm->p_FmDriverParam);
++}
++
++static t_Error InitGuestMode(t_Fm *p_Fm)
++{
++    t_Error                 err = E_OK;
++    int                     i;
++    t_FmIpcMsg              msg;
++    t_FmIpcReply            reply;
++    uint32_t                replyLength;
++
++    ASSERT_COND(p_Fm);
++    ASSERT_COND(p_Fm->guestId != NCSW_MASTER_ID);
++
++    /* build the FM guest partition IPC address */
++    if (Sprint (p_Fm->fmModuleName, "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, p_Fm->guestId) != (p_Fm->guestId<10 ? 6:7))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
++
++    /* build the FM master partition IPC address */
++    memset(p_Fm->fmIpcHandlerModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE);
++    if (Sprint (p_Fm->fmIpcHandlerModuleName[0], "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, NCSW_MASTER_ID) != 6)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
++
++    for (i=0;i<e_FM_EV_DUMMY_LAST;i++)
++        p_Fm->intrMng[i].f_Isr = UnimplementedIsr;
++
++    p_Fm->h_IpcSessions[0] = XX_IpcInitSession(p_Fm->fmIpcHandlerModuleName[0], p_Fm->fmModuleName);
++    if (p_Fm->h_IpcSessions[0])
++    {
++        uint8_t                 isMasterAlive;
++        t_FmIpcParams           ipcParams;
++
++        err = XX_IpcRegisterMsgHandler(p_Fm->fmModuleName, FmGuestHandleIpcMsgCB, p_Fm, FM_IPC_MAX_REPLY_SIZE);
++        if (err)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_MASTER_IS_ALIVE;
++        msg.msgBody[0] = p_Fm->guestId;
++        replyLength = sizeof(uint32_t) + sizeof(uint8_t);
++        do
++        {
++            blockingFlag = TRUE;
++            if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                         (uint8_t*)&msg,
++                                         sizeof(msg.msgId)+sizeof(p_Fm->guestId),
++                                         (uint8_t*)&reply,
++                                         &replyLength,
++                                         IpcMsgCompletionCB,
++                                         p_Fm)) != E_OK)
++                REPORT_ERROR(MINOR, err, NO_MSG);
++            while (blockingFlag) ;
++            if (replyLength != (sizeof(uint32_t) + sizeof(uint8_t)))
++                REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++            isMasterAlive = *(uint8_t*)(reply.replyBody);
++        } while (!isMasterAlive);
++
++        /* read FM parameters and save */
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_GET_PARAMS;
++        replyLength = sizeof(uint32_t) + sizeof(t_FmIpcParams);
++        if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                     (uint8_t*)&msg,
++                                     sizeof(msg.msgId),
++                                     (uint8_t*)&reply,
++                                     &replyLength,
++                                     NULL,
++                                     NULL)) != E_OK)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++        if (replyLength != (sizeof(uint32_t) + sizeof(t_FmIpcParams)))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++        memcpy((uint8_t*)&ipcParams, reply.replyBody, sizeof(t_FmIpcParams));
++
++        p_Fm->p_FmStateStruct->fmClkFreq = ipcParams.fmClkFreq;
++        p_Fm->p_FmStateStruct->fmMacClkFreq = ipcParams.fmMacClkFreq;
++        p_Fm->p_FmStateStruct->revInfo.majorRev = ipcParams.majorRev;
++        p_Fm->p_FmStateStruct->revInfo.minorRev = ipcParams.minorRev;
++    }
++    else
++    {
++        DBG(WARNING, ("FM Guest mode - without IPC"));
++        if (!p_Fm->p_FmStateStruct->fmClkFreq)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("No fmClkFreq configured for guest without IPC"));
++        if (p_Fm->baseAddr)
++        {
++            fman_get_revision(p_Fm->p_FmFpmRegs,
++                              &p_Fm->p_FmStateStruct->revInfo.majorRev,
++                              &p_Fm->p_FmStateStruct->revInfo.minorRev);
++
++        }
++    }
++
++#if (DPAA_VERSION >= 11)
++    p_Fm->partVSPBase = AllocVSPsForPartition(p_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId);
++    if (p_Fm->partVSPBase == (uint8_t)(ILLEGAL_BASE))
++        DBG(WARNING, ("partition VSPs allocation is FAILED"));
++#endif /* (DPAA_VERSION >= 11) */
++
++    /* General FM driver initialization */
++    if (p_Fm->baseAddr)
++        p_Fm->fmMuramPhysBaseAddr =
++            (uint64_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->baseAddr + FM_MM_MURAM)));
++
++    XX_Free(p_Fm->p_FmDriverParam);
++    p_Fm->p_FmDriverParam = NULL;
++
++    if ((p_Fm->guestId == NCSW_MASTER_ID) ||
++        (p_Fm->h_IpcSessions[0]))
++    {
++        FM_DisableRamsEcc(p_Fm);
++        FmMuramClear(p_Fm->h_FmMuram);
++        FM_EnableRamsEcc(p_Fm);
++    }
++
++    return E_OK;
++}
++
++static __inline__ enum fman_exceptions FmanExceptionTrans(e_FmExceptions exception)
++{
++    switch (exception) {
++            case  e_FM_EX_DMA_BUS_ERROR:
++                return E_FMAN_EX_DMA_BUS_ERROR;
++            case  e_FM_EX_DMA_READ_ECC:
++                return E_FMAN_EX_DMA_READ_ECC;
++            case  e_FM_EX_DMA_SYSTEM_WRITE_ECC:
++                return E_FMAN_EX_DMA_SYSTEM_WRITE_ECC;
++            case  e_FM_EX_DMA_FM_WRITE_ECC:
++                return E_FMAN_EX_DMA_FM_WRITE_ECC;
++            case  e_FM_EX_FPM_STALL_ON_TASKS:
++                return E_FMAN_EX_FPM_STALL_ON_TASKS;
++            case  e_FM_EX_FPM_SINGLE_ECC:
++                return E_FMAN_EX_FPM_SINGLE_ECC;
++            case  e_FM_EX_FPM_DOUBLE_ECC:
++                return E_FMAN_EX_FPM_DOUBLE_ECC;
++            case  e_FM_EX_QMI_SINGLE_ECC:
++                return E_FMAN_EX_QMI_SINGLE_ECC;
++            case  e_FM_EX_QMI_DOUBLE_ECC:
++                return E_FMAN_EX_QMI_DOUBLE_ECC;
++            case  e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID:
++                return E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID;
++            case  e_FM_EX_BMI_LIST_RAM_ECC:
++                return E_FMAN_EX_BMI_LIST_RAM_ECC;
++            case  e_FM_EX_BMI_STORAGE_PROFILE_ECC:
++                return E_FMAN_EX_BMI_STORAGE_PROFILE_ECC;
++            case  e_FM_EX_BMI_STATISTICS_RAM_ECC:
++                return E_FMAN_EX_BMI_STATISTICS_RAM_ECC;
++            case  e_FM_EX_BMI_DISPATCH_RAM_ECC:
++                return E_FMAN_EX_BMI_DISPATCH_RAM_ECC;
++            case  e_FM_EX_IRAM_ECC:
++                return E_FMAN_EX_IRAM_ECC;
++            case  e_FM_EX_MURAM_ECC:
++                return E_FMAN_EX_MURAM_ECC;
++            default:
++                return E_FMAN_EX_DMA_BUS_ERROR;
++        }
++}
++
++uint8_t SwPortIdToHwPortId(e_FmPortType type, uint8_t relativePortId, uint8_t majorRev, uint8_t minorRev)
++{
++      switch (type)
++      {
++              case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++              case (e_FM_PORT_TYPE_OH_HOST_COMMAND):
++                      CHECK_PORT_ID_OH_PORTS(relativePortId);
++                      return (uint8_t)(BASE_OH_PORTID + (relativePortId));
++              case (e_FM_PORT_TYPE_RX):
++                      CHECK_PORT_ID_1G_RX_PORTS(relativePortId);
++                      return (uint8_t)(BASE_1G_RX_PORTID + (relativePortId));
++              case (e_FM_PORT_TYPE_RX_10G):
++                       /* The 10G port in T1024 (FMan Version 6.4) is the first port.
++                        * This is the reason why the 1G port offset is used.
++                        */
++                       if (majorRev == 6 && minorRev == 4)
++                       {
++                               CHECK_PORT_ID_1G_RX_PORTS(relativePortId);
++                               return (uint8_t)(BASE_1G_RX_PORTID + (relativePortId));
++                       }
++                       else
++                       {
++                               CHECK_PORT_ID_10G_RX_PORTS(relativePortId);
++                               return (uint8_t)(BASE_10G_RX_PORTID + (relativePortId));
++                       }
++              case (e_FM_PORT_TYPE_TX):
++                      CHECK_PORT_ID_1G_TX_PORTS(relativePortId);
++                      return (uint8_t)(BASE_1G_TX_PORTID + (relativePortId));
++              case (e_FM_PORT_TYPE_TX_10G):
++                       /* The 10G port in T1024 (FMan Version 6.4) is the first port.
++                        * This is the reason why the 1G port offset is used.
++                        */
++                       if (majorRev == 6 && minorRev == 4)
++                       {
++                               CHECK_PORT_ID_1G_TX_PORTS(relativePortId);
++                               return (uint8_t)(BASE_1G_TX_PORTID + (relativePortId));
++                       }
++                       else
++                       {
++                               CHECK_PORT_ID_10G_TX_PORTS(relativePortId);
++                               return (uint8_t)(BASE_10G_TX_PORTID + (relativePortId));
++                       }
++              default:
++                      REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal port type"));
++                      return 0;
++      }
++}
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++t_Error FmDumpPortRegs (t_Handle h_Fm, uint8_t hardwarePortId)
++{
++    t_Fm            *p_Fm = (t_Fm *)h_Fm;
++
++    DECLARE_DUMP;
++
++    ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(((p_Fm->guestId == NCSW_MASTER_ID) ||
++                               p_Fm->baseAddr), E_INVALID_OPERATION);
++
++    DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1], ("fmbm_pp for port %u", (hardwarePortId)));
++    DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1], sizeof(uint32_t));
++
++    DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId-1], ("fmbm_pfs for port %u", (hardwarePortId )));
++    DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId-1], sizeof(uint32_t));
++
++    DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_spliodn[hardwarePortId-1], ("fmbm_spliodn for port %u", (hardwarePortId)));
++    DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_spliodn[hardwarePortId-1], sizeof(uint32_t));
++
++    DUMP_TITLE(&p_Fm->p_FmFpmRegs->fmfp_ps[hardwarePortId], ("fmfp_ps for port %u", (hardwarePortId)));
++    DUMP_MEMORY(&p_Fm->p_FmFpmRegs->fmfp_ps[hardwarePortId], sizeof(uint32_t));
++
++    DUMP_TITLE(&p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId/2], ("fmdmplr for port %u", (hardwarePortId)));
++    DUMP_MEMORY(&p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId/2], sizeof(uint32_t));
++
++    return E_OK;
++}
++#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */
++
++
++/*****************************************************************************/
++/*                      API Init unit functions                              */
++/*****************************************************************************/
++t_Handle FM_Config(t_FmParams *p_FmParam)
++{
++    t_Fm                *p_Fm;
++    uint8_t             i;
++    uintptr_t           baseAddr;
++
++    SANITY_CHECK_RETURN_VALUE(p_FmParam, E_NULL_POINTER, NULL);
++    SANITY_CHECK_RETURN_VALUE(((p_FmParam->firmware.p_Code && p_FmParam->firmware.size) ||
++                               (!p_FmParam->firmware.p_Code && !p_FmParam->firmware.size)),
++                              E_INVALID_VALUE, NULL);
++
++    baseAddr = p_FmParam->baseAddr;
++
++    /* Allocate FM structure */
++    p_Fm = (t_Fm *) XX_Malloc(sizeof(t_Fm));
++    if (!p_Fm)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM driver structure"));
++        return NULL;
++    }
++    memset(p_Fm, 0, sizeof(t_Fm));
++
++    p_Fm->p_FmStateStruct = (t_FmStateStruct *) XX_Malloc(sizeof(t_FmStateStruct));
++    if (!p_Fm->p_FmStateStruct)
++    {
++        XX_Free(p_Fm);
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Status structure"));
++        return NULL;
++    }
++    memset(p_Fm->p_FmStateStruct, 0, sizeof(t_FmStateStruct));
++
++    /* Initialize FM parameters which will be kept by the driver */
++    p_Fm->p_FmStateStruct->fmId = p_FmParam->fmId;
++    p_Fm->guestId               = p_FmParam->guestId;
++
++    for (i=0; i<FM_MAX_NUM_OF_HW_PORT_IDS; i++)
++        p_Fm->p_FmStateStruct->portsTypes[i] = e_FM_PORT_TYPE_DUMMY;
++
++    /* Allocate the FM driver's parameters structure */
++    p_Fm->p_FmDriverParam = (struct fman_cfg *)XX_Malloc(sizeof(struct fman_cfg));
++    if (!p_Fm->p_FmDriverParam)
++    {
++        XX_Free(p_Fm->p_FmStateStruct);
++        XX_Free(p_Fm);
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM driver parameters"));
++        return NULL;
++    }
++    memset(p_Fm->p_FmDriverParam, 0, sizeof(struct fman_cfg));
++
++#if (DPAA_VERSION >= 11)
++    p_Fm->p_FmSp = (t_FmSp *)XX_Malloc(sizeof(t_FmSp));
++    if (!p_Fm->p_FmSp)
++    {
++        XX_Free(p_Fm->p_FmDriverParam);
++        XX_Free(p_Fm->p_FmStateStruct);
++        XX_Free(p_Fm);
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("allocation for internal data structure failed"));
++        return NULL;
++    }
++    memset(p_Fm->p_FmSp, 0, sizeof(t_FmSp));
++
++    for (i=0; i<FM_VSP_MAX_NUM_OF_ENTRIES; i++)
++        p_Fm->p_FmSp->profiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE;
++#endif /* (DPAA_VERSION >= 11) */
++
++    /* Initialize FM parameters which will be kept by the driver */
++    p_Fm->p_FmStateStruct->fmId                 = p_FmParam->fmId;
++    p_Fm->h_FmMuram                             = p_FmParam->h_FmMuram;
++    p_Fm->h_App                                 = p_FmParam->h_App;
++    p_Fm->p_FmStateStruct->fmClkFreq            = p_FmParam->fmClkFreq;
++    p_Fm->p_FmStateStruct->fmMacClkFreq         = p_FmParam->fmClkFreq / ((!p_FmParam->fmMacClkRatio)? 2: p_FmParam->fmMacClkRatio);
++    p_Fm->f_Exception                           = p_FmParam->f_Exception;
++    p_Fm->f_BusError                            = p_FmParam->f_BusError;
++    p_Fm->p_FmFpmRegs = (struct fman_fpm_regs *)UINT_TO_PTR(baseAddr + FM_MM_FPM);
++    p_Fm->p_FmBmiRegs = (struct fman_bmi_regs *)UINT_TO_PTR(baseAddr + FM_MM_BMI);
++    p_Fm->p_FmQmiRegs = (struct fman_qmi_regs *)UINT_TO_PTR(baseAddr + FM_MM_QMI);
++    p_Fm->p_FmDmaRegs = (struct fman_dma_regs *)UINT_TO_PTR(baseAddr + FM_MM_DMA);
++    p_Fm->p_FmRegs       = (struct fman_regs *)UINT_TO_PTR(baseAddr + FM_MM_BMI);
++    p_Fm->baseAddr                              = baseAddr;
++    p_Fm->p_FmStateStruct->irq                  = p_FmParam->irq;
++    p_Fm->p_FmStateStruct->errIrq               = p_FmParam->errIrq;
++    p_Fm->hcPortInitialized                     = FALSE;
++    p_Fm->independentMode                       = FALSE;
++
++    p_Fm->h_Spinlock = XX_InitSpinlock();
++    if (!p_Fm->h_Spinlock)
++    {
++        XX_Free(p_Fm->p_FmDriverParam);
++        XX_Free(p_Fm->p_FmStateStruct);
++        XX_Free(p_Fm);
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("can't allocate spinlock!"));
++        return NULL;
++    }
++
++#if (DPAA_VERSION >= 11)
++    p_Fm->partVSPBase   = p_FmParam->partVSPBase;
++    p_Fm->partNumOfVSPs = p_FmParam->partNumOfVSPs;
++    p_Fm->vspBaseAddr = p_FmParam->vspBaseAddr;
++#endif /* (DPAA_VERSION >= 11) */
++
++    fman_defconfig(p_Fm->p_FmDriverParam,
++                  !!(p_Fm->guestId == NCSW_MASTER_ID));
++/* overide macros dependent parameters */
++#ifdef FM_PEDANTIC_DMA
++    p_Fm->p_FmDriverParam->pedantic_dma = TRUE;
++    p_Fm->p_FmDriverParam->dma_aid_override = TRUE;
++#endif /* FM_PEDANTIC_DMA */
++#ifndef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
++    p_Fm->p_FmDriverParam->qmi_deq_option_support = TRUE;
++#endif /* !FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
++
++    p_Fm->p_FmStateStruct->ramsEccEnable        = FALSE;
++    p_Fm->p_FmStateStruct->extraFifoPoolSize    = 0;
++    p_Fm->p_FmStateStruct->exceptions           = DEFAULT_exceptions;
++    p_Fm->resetOnInit                          = DEFAULT_resetOnInit;
++    p_Fm->f_ResetOnInitOverride                = DEFAULT_resetOnInitOverrideCallback;
++    p_Fm->fwVerify                             = DEFAULT_VerifyUcode;
++    p_Fm->firmware.size                        = p_FmParam->firmware.size;
++    if (p_Fm->firmware.size)
++    {
++        p_Fm->firmware.p_Code = (uint32_t *)XX_Malloc(p_Fm->firmware.size);
++        if (!p_Fm->firmware.p_Code)
++        {
++            XX_FreeSpinlock(p_Fm->h_Spinlock);
++            XX_Free(p_Fm->p_FmStateStruct);
++            XX_Free(p_Fm->p_FmDriverParam);
++            XX_Free(p_Fm);
++            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM firmware code"));
++            return NULL;
++        }
++        memcpy(p_Fm->firmware.p_Code, p_FmParam->firmware.p_Code ,p_Fm->firmware.size);
++    }
++
++    if (p_Fm->guestId != NCSW_MASTER_ID)
++        return p_Fm;
++
++    /* read revision */
++    /* Chip dependent, will be configured in Init */
++    fman_get_revision(p_Fm->p_FmFpmRegs,
++                      &p_Fm->p_FmStateStruct->revInfo.majorRev,
++                      &p_Fm->p_FmStateStruct->revInfo.minorRev);
++
++#ifdef FM_AID_MODE_NO_TNUM_SW005
++    if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
++        p_Fm->p_FmDriverParam->dma_aid_mode = e_FM_DMA_AID_OUT_PORT_ID;
++#endif /* FM_AID_MODE_NO_TNUM_SW005 */
++#ifndef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
++   if (p_Fm->p_FmStateStruct->revInfo.majorRev != 4)
++        p_Fm->p_FmDriverParam->qmi_def_tnums_thresh = QMI_DEF_TNUMS_THRESH;
++#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
++
++        p_Fm->p_FmStateStruct->totalFifoSize        = 0;
++        p_Fm->p_FmStateStruct->totalNumOfTasks      = 
++            DEFAULT_totalNumOfTasks(p_Fm->p_FmStateStruct->revInfo.majorRev,
++                                    p_Fm->p_FmStateStruct->revInfo.minorRev);
++
++#ifdef FM_HAS_TOTAL_DMAS
++        p_Fm->p_FmStateStruct->maxNumOfOpenDmas     = BMI_MAX_NUM_OF_DMAS;
++#endif /* FM_HAS_TOTAL_DMAS */
++#if (DPAA_VERSION < 11)
++        p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer        = DEFAULT_dmaCommQLow;
++        p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer       = DEFAULT_dmaCommQHigh;
++        p_Fm->p_FmDriverParam->dma_cam_num_of_entries        = DEFAULT_dmaCamNumOfEntries;
++        p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer      = DEFAULT_dmaReadIntBufLow;
++        p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer     = DEFAULT_dmaReadIntBufHigh;
++        p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer     = DEFAULT_dmaWriteIntBufLow;
++        p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer    = DEFAULT_dmaWriteIntBufHigh;
++        p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats       = DEFAULT_axiDbgNumOfBeats;
++#endif /* (DPAA_VERSION < 11) */
++#ifdef FM_NO_TNUM_AGING
++    p_Fm->p_FmDriverParam->tnum_aging_period = 0;
++#endif
++    p_Fm->tnumAgingPeriod = p_Fm->p_FmDriverParam->tnum_aging_period;
++
++   return p_Fm;
++}
++
++/**************************************************************************//**
++ @Function      FM_Init
++
++ @Description   Initializes the FM module
++
++ @Param[in]     h_Fm - FM module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_Init(t_Handle h_Fm)
++{
++    t_Fm                    *p_Fm = (t_Fm*)h_Fm;
++    struct fman_cfg         *p_FmDriverParam = NULL;
++    t_Error                 err = E_OK;
++    int                     i;
++    t_FmRevisionInfo        revInfo;
++    struct fman_rg          fman_rg;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++
++    fman_rg.bmi_rg = p_Fm->p_FmBmiRegs;
++    fman_rg.qmi_rg = p_Fm->p_FmQmiRegs;
++    fman_rg.fpm_rg = p_Fm->p_FmFpmRegs;
++    fman_rg.dma_rg = p_Fm->p_FmDmaRegs;
++
++    p_Fm->p_FmStateStruct->count1MicroBit = FM_TIMESTAMP_1_USEC_BIT;
++    p_Fm->p_FmDriverParam->num_of_fman_ctrl_evnt_regs = FM_NUM_OF_FMAN_CTRL_EVENT_REGS;
++
++    if (p_Fm->guestId != NCSW_MASTER_ID)
++        return InitGuestMode(p_Fm);
++
++    /* if user didn't configured totalFifoSize - (totalFifoSize=0) we configure default
++    * according to chip. otherwise, we use user's configuration.
++    */
++    if (p_Fm->p_FmStateStruct->totalFifoSize == 0)
++        p_Fm->p_FmStateStruct->totalFifoSize = DEFAULT_totalFifoSize(p_Fm->p_FmStateStruct->revInfo.majorRev,
++                                                                     p_Fm->p_FmStateStruct->revInfo.minorRev);
++
++    CHECK_INIT_PARAMETERS(p_Fm, CheckFmParameters);
++
++    p_FmDriverParam = p_Fm->p_FmDriverParam;
++
++    FM_GetRevision(p_Fm, &revInfo);
++
++    /* clear revision-dependent non existing exception */
++#ifdef FM_NO_DISPATCH_RAM_ECC
++    if ((revInfo.majorRev != 4) &&
++        (revInfo.majorRev < 6))
++        p_Fm->p_FmStateStruct->exceptions &= ~FM_EX_BMI_DISPATCH_RAM_ECC;
++#endif /* FM_NO_DISPATCH_RAM_ECC */
++
++#ifdef FM_QMI_NO_ECC_EXCEPTIONS
++    if (revInfo.majorRev == 4)
++        p_Fm->p_FmStateStruct->exceptions &= ~(FM_EX_QMI_SINGLE_ECC | FM_EX_QMI_DOUBLE_ECC);
++#endif /* FM_QMI_NO_ECC_EXCEPTIONS */
++
++#ifdef FM_QMI_NO_SINGLE_ECC_EXCEPTION
++    if (revInfo.majorRev >= 6)
++       p_Fm->p_FmStateStruct->exceptions &= ~FM_EX_QMI_SINGLE_ECC;
++#endif /* FM_QMI_NO_SINGLE_ECC_EXCEPTION */
++
++    FmMuramClear(p_Fm->h_FmMuram);
++
++    /* clear CPG */
++    IOMemSet32(UINT_TO_PTR(p_Fm->baseAddr + FM_MM_CGP), 0, FM_PORT_NUM_OF_CONGESTION_GRPS);
++
++    /* add to the default exceptions the user's definitions */
++    p_Fm->p_FmStateStruct->exceptions |= p_Fm->userSetExceptions;
++
++    /* Reset the FM if required */
++    if (p_Fm->resetOnInit)
++    {
++#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173
++        if ((err = FwNotResetErratumBugzilla6173WA(p_Fm)) != E_OK)
++            RETURN_ERROR(MAJOR, err, NO_MSG);
++#else  /* not FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
++
++        if (p_Fm->f_ResetOnInitOverride)
++        {
++              /* Perform user specific FMan reset */
++              p_Fm->f_ResetOnInitOverride(h_Fm);
++        }
++        else
++        {
++              /* Perform FMan reset */
++              FmReset(h_Fm);
++        }
++
++        if (fman_is_qmi_halt_not_busy_state(p_Fm->p_FmQmiRegs))
++        {
++            fman_resume(p_Fm->p_FmFpmRegs);
++            XX_UDelay(100);
++        }
++#endif /* not FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
++    }
++
++#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173
++    if (!p_Fm->resetOnInit) /* Skip operations done in errata workaround */
++    {
++#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
++    /* Load FMan-Controller code to IRAM */
++
++    ClearIRam(p_Fm);
++
++    if (p_Fm->firmware.p_Code && (LoadFmanCtrlCode(p_Fm) != E_OK))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173
++    }
++#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
++
++#ifdef FM_CAPWAP_SUPPORT
++    /* save first 256 byte in MURAM */
++    p_Fm->resAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram, 256, 0));
++    if (!p_Fm->resAddr)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for reserved Area failed"));
++
++    WRITE_BLOCK(UINT_TO_PTR(p_Fm->resAddr), 0, 256);
++#endif /* FM_CAPWAP_SUPPORT */
++
++#if (DPAA_VERSION >= 11)
++    p_Fm->partVSPBase = AllocVSPsForPartition(h_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId);
++    if (p_Fm->partVSPBase == (uint8_t)(ILLEGAL_BASE))
++        DBG(WARNING, ("partition VSPs allocation is FAILED"));
++#endif /* (DPAA_VERSION >= 11) */
++
++    /* General FM driver initialization */
++    p_Fm->fmMuramPhysBaseAddr =
++        (uint64_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->baseAddr + FM_MM_MURAM)));
++
++    for (i=0;i<e_FM_EV_DUMMY_LAST;i++)
++        p_Fm->intrMng[i].f_Isr = UnimplementedIsr;
++    for (i=0;i<FM_NUM_OF_FMAN_CTRL_EVENT_REGS;i++)
++        p_Fm->fmanCtrlIntr[i].f_Isr = UnimplementedFmanCtrlIsr;
++
++    p_FmDriverParam->exceptions = p_Fm->p_FmStateStruct->exceptions;
++
++    /**********************/
++    /* Init DMA Registers */
++    /**********************/
++    err = InitFmDma(p_Fm);
++    if (err != E_OK)
++    {
++        FreeInitResources(p_Fm);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    /**********************/
++    /* Init FPM Registers */
++    /**********************/
++    err = InitFmFpm(p_Fm);
++    if (err != E_OK)
++    {
++        FreeInitResources(p_Fm);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    /* define common resources */
++    /* allocate MURAM for FIFO according to total size */
++    p_Fm->fifoBaseAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram,
++                                                       p_Fm->p_FmStateStruct->totalFifoSize,
++                                                       BMI_FIFO_ALIGN));
++    if (!p_Fm->fifoBaseAddr)
++    {
++        FreeInitResources(p_Fm);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for BMI FIFO failed"));
++    }
++
++    p_FmDriverParam->fifo_base_addr = (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->fifoBaseAddr)) - p_Fm->fmMuramPhysBaseAddr);
++    p_FmDriverParam->total_fifo_size = p_Fm->p_FmStateStruct->totalFifoSize;
++    p_FmDriverParam->total_num_of_tasks = p_Fm->p_FmStateStruct->totalNumOfTasks;
++    p_FmDriverParam->clk_freq = p_Fm->p_FmStateStruct->fmClkFreq;
++
++    /**********************/
++    /* Init BMI Registers */
++    /**********************/
++    err = InitFmBmi(p_Fm);
++    if (err != E_OK)
++    {
++        FreeInitResources(p_Fm);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    /**********************/
++    /* Init QMI Registers */
++    /**********************/
++    err = InitFmQmi(p_Fm);
++    if (err != E_OK)
++    {
++        FreeInitResources(p_Fm);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    /* build the FM master partition IPC address */
++    if (Sprint (p_Fm->fmModuleName, "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, NCSW_MASTER_ID) != 6)
++    {
++        FreeInitResources(p_Fm);
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
++    }
++
++    err = XX_IpcRegisterMsgHandler(p_Fm->fmModuleName, FmHandleIpcMsgCB, p_Fm, FM_IPC_MAX_REPLY_SIZE);
++    if (err)
++    {
++        FreeInitResources(p_Fm);
++        RETURN_ERROR(MAJOR, err, NO_MSG);
++    }
++
++    /* Register the FM interrupts handlers */
++    if (p_Fm->p_FmStateStruct->irq != NO_IRQ)
++    {
++        XX_SetIntr(p_Fm->p_FmStateStruct->irq, FM_EventIsr, p_Fm);
++        XX_EnableIntr(p_Fm->p_FmStateStruct->irq);
++    }
++
++    if (p_Fm->p_FmStateStruct->errIrq != NO_IRQ)
++    {
++        XX_SetIntr(p_Fm->p_FmStateStruct->errIrq, (void (*) (t_Handle))FM_ErrorIsr, p_Fm);
++        XX_EnableIntr(p_Fm->p_FmStateStruct->errIrq);
++    }
++
++    err = (t_Error)fman_enable(&fman_rg , p_FmDriverParam);
++    if (err != E_OK)
++        return err; /* FIXME */
++
++    EnableTimeStamp(p_Fm);
++
++    if (p_Fm->firmware.p_Code)
++    {
++        XX_Free(p_Fm->firmware.p_Code);
++        p_Fm->firmware.p_Code = NULL;
++    }
++
++    XX_Free(p_Fm->p_FmDriverParam);
++    p_Fm->p_FmDriverParam = NULL;
++
++    return E_OK;
++}
++
++/**************************************************************************//**
++ @Function      FM_Free
++
++ @Description   Frees all resources that were assigned to FM module.
++
++                Calling this routine invalidates the descriptor.
++
++ @Param[in]     h_Fm - FM module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_Free(t_Handle h_Fm)
++{
++    t_Fm    *p_Fm = (t_Fm*)h_Fm;
++    struct fman_rg          fman_rg;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++
++    fman_rg.bmi_rg = p_Fm->p_FmBmiRegs;
++    fman_rg.qmi_rg = p_Fm->p_FmQmiRegs;
++    fman_rg.fpm_rg = p_Fm->p_FmFpmRegs;
++    fman_rg.dma_rg = p_Fm->p_FmDmaRegs;
++
++    if (p_Fm->guestId != NCSW_MASTER_ID)
++    {
++#if (DPAA_VERSION >= 11)
++        FreeVSPsForPartition(h_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId);
++
++        if (p_Fm->p_FmSp)
++        {
++            XX_Free(p_Fm->p_FmSp);
++            p_Fm->p_FmSp = NULL;
++        }
++#endif /* (DPAA_VERSION >= 11) */
++
++        if (p_Fm->fmModuleName[0] != 0)
++            XX_IpcUnregisterMsgHandler(p_Fm->fmModuleName);
++
++        if (!p_Fm->recoveryMode)
++            XX_Free(p_Fm->p_FmStateStruct);
++
++        XX_Free(p_Fm);
++
++        return E_OK;
++    }
++
++    fman_free_resources(&fman_rg);
++
++    if ((p_Fm->guestId == NCSW_MASTER_ID) && (p_Fm->fmModuleName[0] != 0))
++        XX_IpcUnregisterMsgHandler(p_Fm->fmModuleName);
++
++    if (p_Fm->p_FmStateStruct)
++    {
++        if (p_Fm->p_FmStateStruct->irq != NO_IRQ)
++        {
++            XX_DisableIntr(p_Fm->p_FmStateStruct->irq);
++            XX_FreeIntr(p_Fm->p_FmStateStruct->irq);
++        }
++        if (p_Fm->p_FmStateStruct->errIrq != NO_IRQ)
++        {
++            XX_DisableIntr(p_Fm->p_FmStateStruct->errIrq);
++            XX_FreeIntr(p_Fm->p_FmStateStruct->errIrq);
++        }
++    }
++
++#if (DPAA_VERSION >= 11)
++    FreeVSPsForPartition(h_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId);
++
++    if (p_Fm->p_FmSp)
++    {
++        XX_Free(p_Fm->p_FmSp);
++        p_Fm->p_FmSp = NULL;
++    }
++#endif /* (DPAA_VERSION >= 11) */
++
++    if (p_Fm->h_Spinlock)
++        XX_FreeSpinlock(p_Fm->h_Spinlock);
++
++    if (p_Fm->p_FmDriverParam)
++    {
++        if (p_Fm->firmware.p_Code)
++            XX_Free(p_Fm->firmware.p_Code);
++        XX_Free(p_Fm->p_FmDriverParam);
++        p_Fm->p_FmDriverParam = NULL;
++    }
++
++    FreeInitResources(p_Fm);
++
++    if (!p_Fm->recoveryMode && p_Fm->p_FmStateStruct)
++        XX_Free(p_Fm->p_FmStateStruct);
++
++    XX_Free(p_Fm);
++
++    return E_OK;
++}
++
++/*************************************************/
++/*       API Advanced Init unit functions        */
++/*************************************************/
++
++t_Error FM_ConfigResetOnInit(t_Handle h_Fm, bool enable)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    p_Fm->resetOnInit = enable;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigResetOnInitOverrideCallback(t_Handle h_Fm, t_FmResetOnInitOverrideCallback *f_ResetOnInitOverride)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    p_Fm->f_ResetOnInitOverride = f_ResetOnInitOverride;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigTotalFifoSize(t_Handle h_Fm, uint32_t totalFifoSize)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    p_Fm->p_FmStateStruct->totalFifoSize = totalFifoSize;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigDmaCacheOverride(t_Handle h_Fm, e_FmDmaCacheOverride cacheOverride)
++{
++    t_Fm                            *p_Fm = (t_Fm*)h_Fm;
++    enum fman_dma_cache_override    fsl_cache_override;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    FMAN_CACHE_OVERRIDE_TRANS(fsl_cache_override, cacheOverride)
++    p_Fm->p_FmDriverParam->dma_cache_override = fsl_cache_override;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigDmaAidOverride(t_Handle h_Fm, bool aidOverride)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    p_Fm->p_FmDriverParam->dma_aid_override = aidOverride;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigDmaAidMode(t_Handle h_Fm, e_FmDmaAidMode aidMode)
++{
++    t_Fm                    *p_Fm = (t_Fm*)h_Fm;
++    enum fman_dma_aid_mode  fsl_aid_mode;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    FMAN_AID_MODE_TRANS(fsl_aid_mode, aidMode);
++    p_Fm->p_FmDriverParam->dma_aid_mode = fsl_aid_mode;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigDmaAxiDbgNumOfBeats(t_Handle h_Fm, uint8_t axiDbgNumOfBeats)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++#if (DPAA_VERSION >= 11)
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!"));
++#else
++    p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats = axiDbgNumOfBeats;
++
++    return E_OK;
++#endif /* (DPAA_VERSION >= 11) */
++}
++
++t_Error FM_ConfigDmaCamNumOfEntries(t_Handle h_Fm, uint8_t numOfEntries)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    p_Fm->p_FmDriverParam->dma_cam_num_of_entries = numOfEntries;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigDmaDbgCounter(t_Handle h_Fm, e_FmDmaDbgCntMode fmDmaDbgCntMode)
++{
++    t_Fm                        *p_Fm = (t_Fm*)h_Fm;
++    enum fman_dma_dbg_cnt_mode  fsl_dma_dbg_cnt;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    FMAN_DMA_DBG_CNT_TRANS(fsl_dma_dbg_cnt, fmDmaDbgCntMode);
++    p_Fm->p_FmDriverParam->dma_dbg_cnt_mode = fsl_dma_dbg_cnt;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigDmaStopOnBusErr(t_Handle h_Fm, bool stop)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    p_Fm->p_FmDriverParam->dma_stop_on_bus_error = stop;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigDmaEmergency(t_Handle h_Fm, t_FmDmaEmergency *p_Emergency)
++{
++    t_Fm                            *p_Fm = (t_Fm*)h_Fm;
++    enum fman_dma_emergency_level   fsl_dma_emer;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    FMAN_DMA_EMER_TRANS(fsl_dma_emer, p_Emergency->emergencyLevel);
++    p_Fm->p_FmDriverParam->dma_en_emergency = TRUE;
++    p_Fm->p_FmDriverParam->dma_emergency_bus_select = (uint32_t)p_Emergency->emergencyBusSelect;
++    p_Fm->p_FmDriverParam->dma_emergency_level = fsl_dma_emer;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigDmaEmergencySmoother(t_Handle h_Fm, uint32_t emergencyCnt)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    p_Fm->p_FmDriverParam->dma_en_emergency_smoother = TRUE;
++    p_Fm->p_FmDriverParam->dma_emergency_switch_counter = emergencyCnt;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigDmaErr(t_Handle h_Fm, e_FmDmaErr dmaErr)
++{
++    t_Fm                *p_Fm = (t_Fm*)h_Fm;
++    enum fman_dma_err   fsl_dma_err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    FMAN_DMA_ERR_TRANS(fsl_dma_err, dmaErr);
++    p_Fm->p_FmDriverParam->dma_err = fsl_dma_err;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigCatastrophicErr(t_Handle h_Fm, e_FmCatastrophicErr catastrophicErr)
++{
++    t_Fm                        *p_Fm = (t_Fm*)h_Fm;
++    enum fman_catastrophic_err  fsl_catastrophic_err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    FMAN_CATASTROPHIC_ERR_TRANS(fsl_catastrophic_err, catastrophicErr);
++    p_Fm->p_FmDriverParam->catastrophic_err = fsl_catastrophic_err;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigEnableMuramTestMode(t_Handle h_Fm)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!"));
++
++    p_Fm->p_FmDriverParam->en_muram_test_mode = TRUE;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigEnableIramTestMode(t_Handle h_Fm)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE );
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!"));
++
++    p_Fm->p_FmDriverParam->en_iram_test_mode = TRUE;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigHaltOnExternalActivation(t_Handle h_Fm, bool enable)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    p_Fm->p_FmDriverParam->halt_on_external_activ = enable;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigHaltOnUnrecoverableEccError(t_Handle h_Fm, bool enable)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!"));
++
++    p_Fm->p_FmDriverParam->halt_on_unrecov_ecc_err = enable;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigException(t_Handle h_Fm, e_FmExceptions exception, bool enable)
++{
++    t_Fm                *p_Fm = (t_Fm*)h_Fm;
++    uint32_t            bitMask = 0;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    GET_EXCEPTION_FLAG(bitMask, exception);
++    if (bitMask)
++    {
++        if (enable)
++            p_Fm->userSetExceptions |= bitMask;
++        else
++            p_Fm->p_FmStateStruct->exceptions &= ~bitMask;
++    }
++    else
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
++
++    return E_OK;
++}
++
++t_Error FM_ConfigExternalEccRamsEnable(t_Handle h_Fm, bool enable)
++{
++    t_Fm        *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    p_Fm->p_FmDriverParam->external_ecc_rams_enable = enable;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigTnumAgingPeriod(t_Handle h_Fm, uint16_t tnumAgingPeriod)
++{
++    t_Fm             *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    p_Fm->p_FmDriverParam->tnum_aging_period = tnumAgingPeriod;
++    p_Fm->tnumAgingPeriod = p_Fm->p_FmDriverParam->tnum_aging_period;
++
++    return E_OK;
++}
++
++/****************************************************/
++/*       Hidden-DEBUG Only API                      */
++/****************************************************/
++
++t_Error FM_ConfigThresholds(t_Handle h_Fm, t_FmThresholds *p_FmThresholds)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    p_Fm->p_FmDriverParam->disp_limit_tsh  = p_FmThresholds->dispLimit;
++    p_Fm->p_FmDriverParam->prs_disp_tsh    = p_FmThresholds->prsDispTh;
++    p_Fm->p_FmDriverParam->plcr_disp_tsh   = p_FmThresholds->plcrDispTh;
++    p_Fm->p_FmDriverParam->kg_disp_tsh     = p_FmThresholds->kgDispTh;
++    p_Fm->p_FmDriverParam->bmi_disp_tsh    = p_FmThresholds->bmiDispTh;
++    p_Fm->p_FmDriverParam->qmi_enq_disp_tsh = p_FmThresholds->qmiEnqDispTh;
++    p_Fm->p_FmDriverParam->qmi_deq_disp_tsh = p_FmThresholds->qmiDeqDispTh;
++    p_Fm->p_FmDriverParam->fm_ctl1_disp_tsh = p_FmThresholds->fmCtl1DispTh;
++    p_Fm->p_FmDriverParam->fm_ctl2_disp_tsh = p_FmThresholds->fmCtl2DispTh;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigDmaSosEmergencyThreshold(t_Handle h_Fm, uint32_t dmaSosEmergency)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    p_Fm->p_FmDriverParam->dma_sos_emergency = dmaSosEmergency;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigDmaWriteBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds)
++
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++#if (DPAA_VERSION >= 11)
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!"));
++#else
++    p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer = p_FmDmaThresholds->assertEmergency;
++    p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer  = p_FmDmaThresholds->clearEmergency;
++
++    return E_OK;
++#endif
++}
++
++t_Error FM_ConfigDmaCommQThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer    = p_FmDmaThresholds->assertEmergency;
++    p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer     = p_FmDmaThresholds->clearEmergency;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigDmaReadBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++#if (DPAA_VERSION >= 11)
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!"));
++#else
++    p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer   = p_FmDmaThresholds->clearEmergency;
++    p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer  = p_FmDmaThresholds->assertEmergency;
++
++    return E_OK;
++#endif
++}
++
++t_Error FM_ConfigDmaWatchdog(t_Handle h_Fm, uint32_t watchdogValue)
++{
++    t_Fm                *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    p_Fm->p_FmDriverParam->dma_watchdog = watchdogValue;
++
++    return E_OK;
++}
++
++t_Error FM_ConfigEnableCounters(t_Handle h_Fm)
++{
++    t_Fm                *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++UNUSED(p_Fm);
++
++    return E_OK;
++}
++
++t_Error FmGetSetParams(t_Handle h_Fm, t_FmGetSetParams *p_Params)
++{
++      t_Fm* p_Fm = (t_Fm*)h_Fm;
++      if (p_Params->setParams.type & UPDATE_FM_CLD)
++      {
++              WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_cld, GET_UINT32(
++                              p_Fm->p_FmFpmRegs->fm_cld) | 0x00000800);
++      }
++      if (p_Params->setParams.type & CLEAR_IRAM_READY)
++      {
++          t_FMIramRegs *p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM);
++              WRITE_UINT32(p_Iram->iready,GET_UINT32(p_Iram->iready) & ~IRAM_READY);
++      }
++      if (p_Params->setParams.type & UPDATE_FPM_EXTC)
++              WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_extc,0x80000000);
++      if (p_Params->setParams.type & UPDATE_FPM_EXTC_CLEAR)
++              WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_extc,0x00800000);
++      if (p_Params->setParams.type & UPDATE_FPM_BRKC_SLP)
++      {       
++              if (p_Params->setParams.sleep)
++                      WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc, GET_UINT32(
++                              p_Fm->p_FmFpmRegs->fmfp_brkc) | FPM_BRKC_SLP);
++              else
++                      WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc, GET_UINT32(
++                              p_Fm->p_FmFpmRegs->fmfp_brkc) & ~FPM_BRKC_SLP);
++      }
++      if (p_Params->getParams.type & GET_FM_CLD)
++              p_Params->getParams.fm_cld = GET_UINT32(p_Fm->p_FmFpmRegs->fm_cld);
++      if (p_Params->getParams.type & GET_FMQM_GS)
++              p_Params->getParams.fmqm_gs = GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_gs);
++      if (p_Params->getParams.type & GET_FM_NPI)
++              p_Params->getParams.fm_npi = GET_UINT32(p_Fm->p_FmFpmRegs->fm_npi);
++      if (p_Params->getParams.type & GET_FMFP_EXTC)
++              p_Params->getParams.fmfp_extc = GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_extc);
++      return E_OK;
++}
++
++
++/****************************************************/
++/*       API Run-time Control uint functions        */
++/****************************************************/
++void FM_EventIsr(t_Handle h_Fm)
++{
++#define FM_M_CALL_1G_MAC_ISR(_id)    \
++    {                                \
++        if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].guestId)    \
++            SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id), pending);                 \
++        else                                                                                        \
++            p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].h_SrcHandle);\
++    }
++#define FM_M_CALL_10G_MAC_ISR(_id)   \
++    {                                \
++        if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].guestId)    \
++            SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id), pending);                 \
++        else                                                                                         \
++            p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].h_SrcHandle);\
++    }
++    t_Fm                    *p_Fm = (t_Fm*)h_Fm;
++    uint32_t                pending, event;
++    struct fman_fpm_regs *fpm_rg;
++
++    SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    fpm_rg = p_Fm->p_FmFpmRegs;
++
++    /* normal interrupts */
++    pending = fman_get_normal_pending(fpm_rg);
++    if (!pending)
++        return;
++    if (pending & INTR_EN_WAKEUP) // this is a wake up from sleep interrupt
++    {
++        t_FmGetSetParams fmGetSetParams;
++        memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
++        fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP;
++        fmGetSetParams.setParams.sleep = 0;
++        FmGetSetParams(h_Fm, &fmGetSetParams);
++    }
++    if (pending & INTR_EN_QMI)
++        QmiEvent(p_Fm);
++    if (pending & INTR_EN_PRS)
++        p_Fm->intrMng[e_FM_EV_PRS].f_Isr(p_Fm->intrMng[e_FM_EV_PRS].h_SrcHandle);
++    if (pending & INTR_EN_PLCR)
++        p_Fm->intrMng[e_FM_EV_PLCR].f_Isr(p_Fm->intrMng[e_FM_EV_PLCR].h_SrcHandle);
++    if (pending & INTR_EN_TMR)
++            p_Fm->intrMng[e_FM_EV_TMR].f_Isr(p_Fm->intrMng[e_FM_EV_TMR].h_SrcHandle);
++
++    /* MAC events may belong to different partitions */
++    if (pending & INTR_EN_1G_MAC0)
++        FM_M_CALL_1G_MAC_ISR(0);
++    if (pending & INTR_EN_1G_MAC1)
++        FM_M_CALL_1G_MAC_ISR(1);
++    if (pending & INTR_EN_1G_MAC2)
++        FM_M_CALL_1G_MAC_ISR(2);
++    if (pending & INTR_EN_1G_MAC3)
++        FM_M_CALL_1G_MAC_ISR(3);
++    if (pending & INTR_EN_1G_MAC4)
++        FM_M_CALL_1G_MAC_ISR(4);
++    if (pending & INTR_EN_1G_MAC5)
++        FM_M_CALL_1G_MAC_ISR(5);
++    if (pending & INTR_EN_1G_MAC6)
++        FM_M_CALL_1G_MAC_ISR(6);
++    if (pending & INTR_EN_1G_MAC7)
++        FM_M_CALL_1G_MAC_ISR(7);
++    if (pending & INTR_EN_10G_MAC0)
++        FM_M_CALL_10G_MAC_ISR(0);
++    if (pending & INTR_EN_10G_MAC1)
++        FM_M_CALL_10G_MAC_ISR(1);
++
++    /* IM port events may belong to different partitions */
++    if (pending & INTR_EN_REV0)
++    {
++        event = fman_get_controller_event(fpm_rg, 0);
++        if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_0].guestId)
++            /*TODO IPC ISR For Fman Ctrl */
++            ASSERT_COND(0);
++            /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_0, pending); */
++        else
++            p_Fm->fmanCtrlIntr[0].f_Isr(p_Fm->fmanCtrlIntr[0].h_SrcHandle, event);
++
++    }
++    if (pending & INTR_EN_REV1)
++    {
++        event = fman_get_controller_event(fpm_rg, 1);
++        if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_1].guestId)
++            /*TODO IPC ISR For Fman Ctrl */
++            ASSERT_COND(0);
++            /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_1, pending); */
++        else
++            p_Fm->fmanCtrlIntr[1].f_Isr(p_Fm->fmanCtrlIntr[1].h_SrcHandle, event);
++    }
++    if (pending & INTR_EN_REV2)
++    {
++        event = fman_get_controller_event(fpm_rg, 2);
++        if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_2].guestId)
++            /*TODO IPC ISR For Fman Ctrl */
++            ASSERT_COND(0);
++            /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_2, pending); */
++        else
++           p_Fm->fmanCtrlIntr[2].f_Isr(p_Fm->fmanCtrlIntr[2].h_SrcHandle, event);
++    }
++    if (pending & INTR_EN_REV3)
++    {
++        event = fman_get_controller_event(fpm_rg, 3);
++        if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_3].guestId)
++            /*TODO IPC ISR For Fman Ctrl */
++            ASSERT_COND(0);
++            /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_2, pendin3); */
++        else
++            p_Fm->fmanCtrlIntr[3].f_Isr(p_Fm->fmanCtrlIntr[3].h_SrcHandle, event);
++    }
++#ifdef FM_MACSEC_SUPPORT
++    if (pending & INTR_EN_MACSEC_MAC0)
++    {
++       if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_MACSEC_MAC0].guestId)
++            SendIpcIsr(p_Fm, e_FM_EV_MACSEC_MAC0, pending);
++        else
++            p_Fm->intrMng[e_FM_EV_MACSEC_MAC0].f_Isr(p_Fm->intrMng[e_FM_EV_MACSEC_MAC0].h_SrcHandle);
++    }
++#endif /* FM_MACSEC_SUPPORT */
++}
++
++t_Error FM_ErrorIsr(t_Handle h_Fm)
++{
++#define FM_M_CALL_1G_MAC_ERR_ISR(_id)   \
++    {                                   \
++       if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].guestId) \
++            SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id), pending);             \
++       else                                                                                         \
++            p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].h_SrcHandle);\
++    }
++#define FM_M_CALL_10G_MAC_ERR_ISR(_id)   \
++    {                                    \
++       if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].guestId) \
++            SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id), pending);             \
++       else                                                                                          \
++            p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].h_SrcHandle);\
++    }
++    t_Fm                    *p_Fm = (t_Fm*)h_Fm;
++    uint32_t                pending;
++    struct fman_fpm_regs *fpm_rg;
++
++    SANITY_CHECK_RETURN_ERROR(h_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    fpm_rg = p_Fm->p_FmFpmRegs;
++
++    /* error interrupts */
++    pending = fman_get_fpm_error_interrupts(fpm_rg);
++    if (!pending)
++        return ERROR_CODE(E_EMPTY);
++
++    if (pending & ERR_INTR_EN_BMI)
++        BmiErrEvent(p_Fm);
++    if (pending & ERR_INTR_EN_QMI)
++        QmiErrEvent(p_Fm);
++    if (pending & ERR_INTR_EN_FPM)
++        FpmErrEvent(p_Fm);
++    if (pending & ERR_INTR_EN_DMA)
++        DmaErrEvent(p_Fm);
++    if (pending & ERR_INTR_EN_IRAM)
++        IramErrIntr(p_Fm);
++    if (pending & ERR_INTR_EN_MURAM)
++        MuramErrIntr(p_Fm);
++    if (pending & ERR_INTR_EN_PRS)
++        p_Fm->intrMng[e_FM_EV_ERR_PRS].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_PRS].h_SrcHandle);
++    if (pending & ERR_INTR_EN_PLCR)
++        p_Fm->intrMng[e_FM_EV_ERR_PLCR].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_PLCR].h_SrcHandle);
++    if (pending & ERR_INTR_EN_KG)
++        p_Fm->intrMng[e_FM_EV_ERR_KG].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_KG].h_SrcHandle);
++
++    /* MAC events may belong to different partitions */
++    if (pending & ERR_INTR_EN_1G_MAC0)
++        FM_M_CALL_1G_MAC_ERR_ISR(0);
++    if (pending & ERR_INTR_EN_1G_MAC1)
++        FM_M_CALL_1G_MAC_ERR_ISR(1);
++    if (pending & ERR_INTR_EN_1G_MAC2)
++        FM_M_CALL_1G_MAC_ERR_ISR(2);
++    if (pending & ERR_INTR_EN_1G_MAC3)
++        FM_M_CALL_1G_MAC_ERR_ISR(3);
++    if (pending & ERR_INTR_EN_1G_MAC4)
++        FM_M_CALL_1G_MAC_ERR_ISR(4);
++    if (pending & ERR_INTR_EN_1G_MAC5)
++        FM_M_CALL_1G_MAC_ERR_ISR(5);
++    if (pending & ERR_INTR_EN_1G_MAC6)
++        FM_M_CALL_1G_MAC_ERR_ISR(6);
++    if (pending & ERR_INTR_EN_1G_MAC7)
++        FM_M_CALL_1G_MAC_ERR_ISR(7);
++    if (pending & ERR_INTR_EN_10G_MAC0)
++        FM_M_CALL_10G_MAC_ERR_ISR(0);
++    if (pending & ERR_INTR_EN_10G_MAC1)
++        FM_M_CALL_10G_MAC_ERR_ISR(1);
++
++#ifdef FM_MACSEC_SUPPORT
++    if (pending & ERR_INTR_EN_MACSEC_MAC0)
++    {
++       if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_ERR_MACSEC_MAC0].guestId)
++            SendIpcIsr(p_Fm, e_FM_EV_ERR_MACSEC_MAC0, pending);
++        else
++            p_Fm->intrMng[e_FM_EV_ERR_MACSEC_MAC0].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_MACSEC_MAC0].h_SrcHandle);
++    }
++#endif /* FM_MACSEC_SUPPORT */
++
++    return E_OK;
++}
++
++t_Error FM_SetPortsBandwidth(t_Handle h_Fm, t_FmPortsBandwidthParams *p_PortsBandwidth)
++{
++    t_Fm        *p_Fm = (t_Fm*)h_Fm;
++    int         i;
++    uint8_t     sum;
++    uint8_t     hardwarePortId;
++    uint8_t     weights[64];
++    uint8_t     weight, maxPercent = 0;
++    struct fman_bmi_regs *bmi_rg;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    bmi_rg = p_Fm->p_FmBmiRegs;
++
++    memset(weights, 0, (sizeof(uint8_t) * 64));
++
++    /* check that all ports add up to 100% */
++    sum = 0;
++    for (i=0; i < p_PortsBandwidth->numOfPorts; i++)
++        sum +=p_PortsBandwidth->portsBandwidths[i].bandwidth;
++    if (sum != 100)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Sum of ports bandwidth differ from 100%"));
++
++    /* find highest percent */
++    for (i=0; i < p_PortsBandwidth->numOfPorts; i++)
++    {
++        if (p_PortsBandwidth->portsBandwidths[i].bandwidth > maxPercent)
++            maxPercent = p_PortsBandwidth->portsBandwidths[i].bandwidth;
++    }
++
++    ASSERT_COND(maxPercent > 0); /* guaranteed by sum = 100 */
++
++    /* calculate weight for each port */
++    for (i=0; i < p_PortsBandwidth->numOfPorts; i++)
++    {
++        weight = (uint8_t)((p_PortsBandwidth->portsBandwidths[i].bandwidth * PORT_MAX_WEIGHT ) / maxPercent);
++        /* we want even division between 1-to-PORT_MAX_WEIGHT. so if exact division
++           is not reached, we round up so that:
++           0 until maxPercent/PORT_MAX_WEIGHT get "1"
++           maxPercent/PORT_MAX_WEIGHT+1 until (maxPercent/PORT_MAX_WEIGHT)*2 get "2"
++           ...
++           maxPercent - maxPercent/PORT_MAX_WEIGHT until maxPercent get "PORT_MAX_WEIGHT: */
++        if ((uint8_t)((p_PortsBandwidth->portsBandwidths[i].bandwidth * PORT_MAX_WEIGHT ) % maxPercent))
++            weight++;
++
++        /* find the location of this port within the register */
++        hardwarePortId =
++            SwPortIdToHwPortId(p_PortsBandwidth->portsBandwidths[i].type,
++                               p_PortsBandwidth->portsBandwidths[i].relativePortId,
++                               p_Fm->p_FmStateStruct->revInfo.majorRev,
++                               p_Fm->p_FmStateStruct->revInfo.minorRev);
++
++        ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
++        weights[hardwarePortId] = weight;
++    }
++
++    fman_set_ports_bandwidth(bmi_rg, weights);
++
++    return E_OK;
++}
++
++t_Error FM_EnableRamsEcc(t_Handle h_Fm)
++{
++    t_Fm        *p_Fm = (t_Fm*)h_Fm;
++    struct fman_fpm_regs *fpm_rg;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++
++    fpm_rg = p_Fm->p_FmFpmRegs;
++
++    if (p_Fm->guestId != NCSW_MASTER_ID)
++    {
++        t_FmIpcMsg      msg;
++        t_Error         err;
++
++        memset(&msg, 0, sizeof(msg));
++        msg.msgId = FM_ENABLE_RAM_ECC;
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId),
++                                NULL,
++                                NULL,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        return E_OK;
++    }
++
++    if (!p_Fm->p_FmStateStruct->internalCall)
++        p_Fm->p_FmStateStruct->explicitEnable = TRUE;
++    p_Fm->p_FmStateStruct->internalCall = FALSE;
++
++    if (p_Fm->p_FmStateStruct->ramsEccEnable)
++        return E_OK;
++    else
++    {
++        fman_enable_rams_ecc(fpm_rg);
++        p_Fm->p_FmStateStruct->ramsEccEnable = TRUE;
++    }
++
++    return E_OK;
++}
++
++t_Error FM_DisableRamsEcc(t_Handle h_Fm)
++{
++    t_Fm        *p_Fm = (t_Fm*)h_Fm;
++    bool        explicitDisable = FALSE;
++    struct fman_fpm_regs *fpm_rg;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
++
++    fpm_rg = p_Fm->p_FmFpmRegs;
++
++    if (p_Fm->guestId != NCSW_MASTER_ID)
++    {
++        t_Error             err;
++        t_FmIpcMsg          msg;
++
++        memset(&msg, 0, sizeof(msg));
++        msg.msgId = FM_DISABLE_RAM_ECC;
++        if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                     (uint8_t*)&msg,
++                                     sizeof(msg.msgId),
++                                     NULL,
++                                     NULL,
++                                     NULL,
++                                     NULL)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        return E_OK;
++    }
++
++    if (!p_Fm->p_FmStateStruct->internalCall)
++        explicitDisable = TRUE;
++    p_Fm->p_FmStateStruct->internalCall = FALSE;
++
++    /* if rams are already disabled, or if rams were explicitly enabled and are
++       currently called indirectly (not explicitly), ignore this call. */
++    if (!p_Fm->p_FmStateStruct->ramsEccEnable ||
++        (p_Fm->p_FmStateStruct->explicitEnable && !explicitDisable))
++        return E_OK;
++    else
++    {
++        if (p_Fm->p_FmStateStruct->explicitEnable)
++            /* This is the case were both explicit are TRUE.
++               Turn off this flag for cases were following ramsEnable
++               routines are called */
++            p_Fm->p_FmStateStruct->explicitEnable = FALSE;
++
++        fman_enable_rams_ecc(fpm_rg);
++        p_Fm->p_FmStateStruct->ramsEccEnable = FALSE;
++    }
++
++    return E_OK;
++}
++
++t_Error FM_SetException(t_Handle h_Fm, e_FmExceptions exception, bool enable)
++{
++    t_Fm                *p_Fm = (t_Fm*)h_Fm;
++    uint32_t            bitMask = 0;
++    enum fman_exceptions fslException;
++    struct fman_rg       fman_rg;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
++
++    fman_rg.bmi_rg = p_Fm->p_FmBmiRegs;
++    fman_rg.qmi_rg = p_Fm->p_FmQmiRegs;
++    fman_rg.fpm_rg = p_Fm->p_FmFpmRegs;
++    fman_rg.dma_rg = p_Fm->p_FmDmaRegs;
++
++    GET_EXCEPTION_FLAG(bitMask, exception);
++    if (bitMask)
++    {
++        if (enable)
++            p_Fm->p_FmStateStruct->exceptions |= bitMask;
++        else
++            p_Fm->p_FmStateStruct->exceptions &= ~bitMask;
++
++        fslException = FmanExceptionTrans(exception);
++
++        return (t_Error)fman_set_exception(&fman_rg,
++                                  fslException,
++                                  enable);
++    }
++    else
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
++
++    return E_OK;
++}
++
++t_Error FM_GetRevision(t_Handle h_Fm, t_FmRevisionInfo *p_FmRevisionInfo)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++
++    p_FmRevisionInfo->majorRev = p_Fm->p_FmStateStruct->revInfo.majorRev;
++    p_FmRevisionInfo->minorRev = p_Fm->p_FmStateStruct->revInfo.minorRev;
++
++    return E_OK;
++}
++
++t_Error FM_GetFmanCtrlCodeRevision(t_Handle h_Fm, t_FmCtrlCodeRevisionInfo *p_RevisionInfo)
++{
++    t_Fm                            *p_Fm = (t_Fm*)h_Fm;
++    t_FMIramRegs                    *p_Iram;
++    uint32_t                        revInfo;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_RevisionInfo, E_NULL_POINTER);
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_Error                         err;
++        t_FmIpcMsg                      msg;
++        t_FmIpcReply                    reply;
++        uint32_t                        replyLength;
++        t_FmIpcFmanCtrlCodeRevisionInfo ipcRevInfo;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_GET_FMAN_CTRL_CODE_REV;
++        replyLength = sizeof(uint32_t) + sizeof(t_FmCtrlCodeRevisionInfo);
++        if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                     (uint8_t*)&msg,
++                                     sizeof(msg.msgId),
++                                     (uint8_t*)&reply,
++                                     &replyLength,
++                                     NULL,
++                                     NULL)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++        if (replyLength != (sizeof(uint32_t) + sizeof(t_FmCtrlCodeRevisionInfo)))
++            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++        memcpy((uint8_t*)&ipcRevInfo, reply.replyBody, sizeof(t_FmCtrlCodeRevisionInfo));
++        p_RevisionInfo->packageRev = ipcRevInfo.packageRev;
++        p_RevisionInfo->majorRev = ipcRevInfo.majorRev;
++        p_RevisionInfo->minorRev = ipcRevInfo.minorRev;
++        return (t_Error)(reply.error);
++    }
++    else if (p_Fm->guestId != NCSW_MASTER_ID)
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("running in guest-mode without IPC!"));
++
++    p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM);
++    WRITE_UINT32(p_Iram->iadd, 0x4);
++    while (GET_UINT32(p_Iram->iadd) != 0x4) ;
++    revInfo = GET_UINT32(p_Iram->idata);
++    p_RevisionInfo->packageRev = (uint16_t)((revInfo & 0xFFFF0000) >> 16);
++    p_RevisionInfo->majorRev = (uint8_t)((revInfo & 0x0000FF00) >> 8);
++    p_RevisionInfo->minorRev = (uint8_t)(revInfo & 0x000000FF);
++
++    return E_OK;
++}
++
++uint32_t FM_GetCounter(t_Handle h_Fm, e_FmCounters counter)
++{
++    t_Fm        *p_Fm = (t_Fm*)h_Fm;
++    t_Error     err;
++    uint32_t    counterValue;
++    struct fman_rg       fman_rg;
++    enum fman_counters fsl_counter;
++
++    SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0);
++    SANITY_CHECK_RETURN_VALUE(!p_Fm->p_FmDriverParam, E_INVALID_STATE, 0);
++
++    fman_rg.bmi_rg = p_Fm->p_FmBmiRegs;
++    fman_rg.qmi_rg = p_Fm->p_FmQmiRegs;
++    fman_rg.fpm_rg = p_Fm->p_FmFpmRegs;
++    fman_rg.dma_rg = p_Fm->p_FmDmaRegs;
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        !p_Fm->baseAddr &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_FmIpcMsg          msg;
++        t_FmIpcReply        reply;
++        uint32_t            replyLength, outCounter;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_GET_COUNTER;
++        memcpy(msg.msgBody, (uint8_t *)&counter, sizeof(uint32_t));
++        replyLength = sizeof(uint32_t) + sizeof(uint32_t);
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                     (uint8_t*)&msg,
++                                     sizeof(msg.msgId) +sizeof(counterValue),
++                                     (uint8_t*)&reply,
++                                     &replyLength,
++                                     NULL,
++                                     NULL);
++        if (err != E_OK)
++        {
++            REPORT_ERROR(MAJOR, err, NO_MSG);
++            return 0;
++        }
++        if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t)))
++        {
++            REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++            return 0;
++        }
++
++        memcpy((uint8_t*)&outCounter, reply.replyBody, sizeof(uint32_t));
++        return outCounter;
++    }
++    else if (!p_Fm->baseAddr)
++    {
++        REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Either IPC or 'baseAddress' is required!"));
++        return 0;
++    }
++
++    /* When applicable (when there is an 'enable counters' bit,
++    check that counters are enabled */
++    switch (counter)
++    {
++        case (e_FM_COUNTERS_DEQ_1):
++        case (e_FM_COUNTERS_DEQ_2):
++        case (e_FM_COUNTERS_DEQ_3):
++            if ((p_Fm->p_FmStateStruct->revInfo.majorRev == 4) ||
++                (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6))
++            {
++                REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Requested counter not supported"));
++                return 0;
++            }
++        case (e_FM_COUNTERS_ENQ_TOTAL_FRAME):
++        case (e_FM_COUNTERS_DEQ_TOTAL_FRAME):
++        case (e_FM_COUNTERS_DEQ_0):
++        case (e_FM_COUNTERS_DEQ_FROM_DEFAULT):
++        case (e_FM_COUNTERS_DEQ_FROM_CONTEXT):
++        case (e_FM_COUNTERS_DEQ_FROM_FD):
++        case (e_FM_COUNTERS_DEQ_CONFIRM):
++            if (!(GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_gc) & QMI_CFG_EN_COUNTERS))
++            {
++                REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Requested counter was not enabled"));
++                return 0;
++            }
++            break;
++        default:
++            break;
++    }
++
++    FMAN_COUNTERS_TRANS(fsl_counter, counter);
++    return fman_get_counter(&fman_rg, fsl_counter);
++}
++
++t_Error FM_ModifyCounter(t_Handle h_Fm, e_FmCounters counter, uint32_t val)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++    struct fman_rg          fman_rg;
++    enum fman_counters fsl_counter;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
++
++   fman_rg.bmi_rg = p_Fm->p_FmBmiRegs;
++   fman_rg.qmi_rg = p_Fm->p_FmQmiRegs;
++   fman_rg.fpm_rg = p_Fm->p_FmFpmRegs;
++   fman_rg.dma_rg = p_Fm->p_FmDmaRegs;
++
++   FMAN_COUNTERS_TRANS(fsl_counter, counter);
++   return  (t_Error)fman_modify_counter(&fman_rg, fsl_counter, val);
++}
++
++void FM_SetDmaEmergency(t_Handle h_Fm, e_FmDmaMuramPort muramPort, bool enable)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++    struct fman_dma_regs *dma_rg;
++
++    SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
++
++    dma_rg = p_Fm->p_FmDmaRegs;
++
++    fman_set_dma_emergency(dma_rg, !!(muramPort==e_FM_DMA_MURAM_PORT_WRITE), enable);
++}
++
++void FM_SetDmaExtBusPri(t_Handle h_Fm, e_FmDmaExtBusPri pri)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++    struct fman_dma_regs *dma_rg;
++
++    SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
++
++    dma_rg = p_Fm->p_FmDmaRegs;
++
++    fman_set_dma_ext_bus_pri(dma_rg, pri);
++}
++
++void FM_GetDmaStatus(t_Handle h_Fm, t_FmDmaStatus *p_FmDmaStatus)
++{
++    t_Fm                *p_Fm = (t_Fm*)h_Fm;
++    uint32_t             dmaStatus;
++    struct fman_dma_regs *dma_rg;
++
++    SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
++
++    dma_rg = p_Fm->p_FmDmaRegs;
++
++    if ((p_Fm->guestId != NCSW_MASTER_ID) &&
++        !p_Fm->baseAddr &&
++        p_Fm->h_IpcSessions[0])
++    {
++        t_FmIpcDmaStatus    ipcDmaStatus;
++        t_FmIpcMsg          msg;
++        t_FmIpcReply        reply;
++        t_Error             err;
++        uint32_t            replyLength;
++
++        memset(&msg, 0, sizeof(msg));
++        memset(&reply, 0, sizeof(reply));
++        msg.msgId = FM_DMA_STAT;
++        replyLength = sizeof(uint32_t) + sizeof(t_FmIpcDmaStatus);
++        err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
++                                (uint8_t*)&msg,
++                                sizeof(msg.msgId),
++                                (uint8_t*)&reply,
++                                &replyLength,
++                                NULL,
++                                NULL);
++        if (err != E_OK)
++        {
++            REPORT_ERROR(MINOR, err, NO_MSG);
++            return;
++        }
++        if (replyLength != (sizeof(uint32_t) + sizeof(t_FmIpcDmaStatus)))
++        {
++            REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
++            return;
++        }
++        memcpy((uint8_t*)&ipcDmaStatus, reply.replyBody, sizeof(t_FmIpcDmaStatus));
++
++        p_FmDmaStatus->cmqNotEmpty = (bool)ipcDmaStatus.boolCmqNotEmpty;            /**< Command queue is not empty */
++        p_FmDmaStatus->busError = (bool)ipcDmaStatus.boolBusError;                  /**< Bus error occurred */
++        p_FmDmaStatus->readBufEccError = (bool)ipcDmaStatus.boolReadBufEccError;        /**< Double ECC error on buffer Read */
++        p_FmDmaStatus->writeBufEccSysError =(bool)ipcDmaStatus.boolWriteBufEccSysError;    /**< Double ECC error on buffer write from system side */
++        p_FmDmaStatus->writeBufEccFmError = (bool)ipcDmaStatus.boolWriteBufEccFmError;     /**< Double ECC error on buffer write from FM side */
++        p_FmDmaStatus->singlePortEccError = (bool)ipcDmaStatus.boolSinglePortEccError;     /**< Double ECC error on buffer write from FM side */
++        return;
++    }
++    else if (!p_Fm->baseAddr)
++    {
++        REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
++                     ("Either IPC or 'baseAddress' is required!"));
++        return;
++    }
++
++    dmaStatus = fman_get_dma_status(dma_rg);
++
++    p_FmDmaStatus->cmqNotEmpty = (bool)(dmaStatus & DMA_STATUS_CMD_QUEUE_NOT_EMPTY);
++    p_FmDmaStatus->busError = (bool)(dmaStatus & DMA_STATUS_BUS_ERR);
++    if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
++        p_FmDmaStatus->singlePortEccError = (bool)(dmaStatus & DMA_STATUS_FM_SPDAT_ECC);
++    else
++    {
++        p_FmDmaStatus->readBufEccError = (bool)(dmaStatus & DMA_STATUS_READ_ECC);
++        p_FmDmaStatus->writeBufEccSysError = (bool)(dmaStatus & DMA_STATUS_SYSTEM_WRITE_ECC);
++        p_FmDmaStatus->writeBufEccFmError = (bool)(dmaStatus & DMA_STATUS_FM_WRITE_ECC);
++    }
++}
++
++void FM_Resume(t_Handle h_Fm)
++{
++    t_Fm            *p_Fm = (t_Fm*)h_Fm;
++    struct fman_fpm_regs *fpm_rg;
++
++    SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    fpm_rg = p_Fm->p_FmFpmRegs;
++
++    fman_resume(fpm_rg);
++}
++
++t_Error FM_GetSpecialOperationCoding(t_Handle               h_Fm,
++                                     fmSpecialOperations_t  spOper,
++                                     uint8_t                *p_SpOperCoding)
++{
++    t_Fm                        *p_Fm = (t_Fm*)h_Fm;
++    t_FmCtrlCodeRevisionInfo    revInfo;
++    t_Error                     err;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_SpOperCoding, E_NULL_POINTER);
++
++    if (!spOper)
++    {
++        *p_SpOperCoding = 0;
++        return E_OK;
++    }
++
++    if ((err = FM_GetFmanCtrlCodeRevision(p_Fm, &revInfo)) != E_OK)
++    {
++        DBG(WARNING, ("FM in guest-mode without IPC, can't validate firmware revision."));
++        revInfo.packageRev = IP_OFFLOAD_PACKAGE_NUMBER;
++    }
++    else if (!IS_OFFLOAD_PACKAGE(revInfo.packageRev))
++        RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Fman ctrl code package"));
++
++    switch (spOper)
++    {
++        case (FM_SP_OP_CAPWAP_DTLS_DEC):
++                *p_SpOperCoding = 9;
++                break;
++        case (FM_SP_OP_CAPWAP_DTLS_ENC):
++                *p_SpOperCoding = 10;
++                break;
++        case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_IPSEC_MANIP):
++        case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_IPSEC_MANIP|FM_SP_OP_RPD):
++                *p_SpOperCoding = 5;
++                break;
++        case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_MANIP):
++        case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_MANIP|FM_SP_OP_RPD):
++                *p_SpOperCoding = 6;
++                break;
++        case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_RPD):
++                *p_SpOperCoding = 3;
++                break;
++        case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN):
++                *p_SpOperCoding = 1;
++                break;
++        case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_IPSEC_NO_ETH_HDR):
++                *p_SpOperCoding = 12;
++                break;
++        case (FM_SP_OP_IPSEC|FM_SP_OP_RPD):
++                *p_SpOperCoding = 4;
++                break;
++        case (FM_SP_OP_IPSEC):
++                *p_SpOperCoding = 2;
++                break;
++        case (FM_SP_OP_DCL4C):
++                *p_SpOperCoding = 7;
++                break;
++        case (FM_SP_OP_CLEAR_RPD):
++                *p_SpOperCoding = 8;
++                break;
++        default:
++            RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
++    }
++
++    return E_OK;
++}
++
++t_Error FM_CtrlMonStart(t_Handle h_Fm)
++{
++    t_Fm            *p_Fm = (t_Fm *)h_Fm;
++    t_FmTrbRegs     *p_MonRegs;
++    uint8_t         i;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc,
++                 GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc) | FPM_BRKC_RDBG);
++
++    for (i = 0; i < FM_NUM_OF_CTRL; i++)
++    {
++        p_MonRegs = (t_FmTrbRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_TRB(i));
++
++        /* Reset control registers */
++        WRITE_UINT32(p_MonRegs->tcrh, TRB_TCRH_RESET);
++        WRITE_UINT32(p_MonRegs->tcrl, TRB_TCRL_RESET);
++
++        /* Configure: counter #1 counts all stalls in risc - ldsched stall
++                      counter #2 counts all stalls in risc - other stall*/
++        WRITE_UINT32(p_MonRegs->tcrl, TRB_TCRL_RESET | TRB_TCRL_UTIL);
++
++        /* Enable monitoring */
++        WRITE_UINT32(p_MonRegs->tcrh, TRB_TCRH_ENABLE_COUNTERS);
++    }
++
++    return E_OK;
++}
++
++t_Error FM_CtrlMonStop(t_Handle h_Fm)
++{
++    t_Fm            *p_Fm = (t_Fm *)h_Fm;
++    t_FmTrbRegs     *p_MonRegs;
++    uint8_t         i;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++
++    for (i = 0; i < FM_NUM_OF_CTRL; i++)
++    {
++        p_MonRegs = (t_FmTrbRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_TRB(i));
++        WRITE_UINT32(p_MonRegs->tcrh, TRB_TCRH_DISABLE_COUNTERS);
++    }
++
++    WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc,
++                 GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc) & ~FPM_BRKC_RDBG);
++
++    return E_OK;
++}
++
++t_Error FM_CtrlMonGetCounters(t_Handle h_Fm, uint8_t fmCtrlIndex, t_FmCtrlMon *p_Mon)
++{
++    t_Fm            *p_Fm = (t_Fm *)h_Fm;
++    t_FmTrbRegs     *p_MonRegs;
++    uint64_t        clkCnt, utilValue, effValue;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
++    SANITY_CHECK_RETURN_ERROR(p_Mon, E_NULL_POINTER);
++
++    if (fmCtrlIndex >= FM_NUM_OF_CTRL)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("FM Controller index"));
++
++    p_MonRegs = (t_FmTrbRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_TRB(fmCtrlIndex));
++
++    clkCnt = (uint64_t)
++            ((uint64_t)GET_UINT32(p_MonRegs->tpcch) << 32 | GET_UINT32(p_MonRegs->tpccl));
++
++    utilValue = (uint64_t)
++            ((uint64_t)GET_UINT32(p_MonRegs->tpc1h) << 32 | GET_UINT32(p_MonRegs->tpc1l));
++
++    effValue = (uint64_t)
++            ((uint64_t)GET_UINT32(p_MonRegs->tpc2h) << 32 | GET_UINT32(p_MonRegs->tpc2l));
++
++    p_Mon->percentCnt[0] = (uint8_t)div64_u64((clkCnt - utilValue) * 100, clkCnt);
++    if (clkCnt != utilValue)
++        p_Mon->percentCnt[1] = (uint8_t)div64_u64(((clkCnt - utilValue) - effValue) * 100, clkCnt - utilValue);
++    else
++        p_Mon->percentCnt[1] = 0;
++
++    return E_OK;
++}
++
++t_Handle FM_GetMuramHandle(t_Handle h_Fm)
++{
++    t_Fm        *p_Fm = (t_Fm*)h_Fm;
++
++    SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, NULL);
++
++    return (p_Fm->h_FmMuram);
++}
++
++/****************************************************/
++/*       Hidden-DEBUG Only API                      */
++/****************************************************/
++t_Error FM_ForceIntr (t_Handle h_Fm, e_FmExceptions exception)
++{
++    t_Fm *p_Fm = (t_Fm*)h_Fm;
++    enum fman_exceptions fslException;
++    struct fman_rg fman_rg;
++
++    SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
++
++    fman_rg.bmi_rg = p_Fm->p_FmBmiRegs;
++    fman_rg.qmi_rg = p_Fm->p_FmQmiRegs;
++    fman_rg.fpm_rg = p_Fm->p_FmFpmRegs;
++    fman_rg.dma_rg = p_Fm->p_FmDmaRegs;
++
++    switch (exception)
++    {
++        case e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID:
++            if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID))
++                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
++            break;
++        case e_FM_EX_QMI_SINGLE_ECC:
++            if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
++                 RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("e_FM_EX_QMI_SINGLE_ECC not supported on this integration."));
++
++            if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_SINGLE_ECC))
++                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
++            break;
++        case e_FM_EX_QMI_DOUBLE_ECC:
++            if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_DOUBLE_ECC))
++                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
++            break;
++        case e_FM_EX_BMI_LIST_RAM_ECC:
++            if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_LIST_RAM_ECC))
++                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
++            break;
++        case e_FM_EX_BMI_STORAGE_PROFILE_ECC:
++            if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_STORAGE_PROFILE_ECC))
++                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
++            break;
++        case e_FM_EX_BMI_STATISTICS_RAM_ECC:
++            if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_STATISTICS_RAM_ECC))
++                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
++            break;
++        case e_FM_EX_BMI_DISPATCH_RAM_ECC:
++            if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_DISPATCH_RAM_ECC))
++                RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
++            break;
++        default:
++            RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception may not be forced"));
++    }
++
++    fslException = FmanExceptionTrans(exception);
++    fman_force_intr (&fman_rg, fslException);
++
++    return E_OK;
++}
++
++t_Handle FmGetPcd(t_Handle h_Fm)
++{
++      return ((t_Fm*)h_Fm)->h_Pcd;
++}
++#if (DPAA_VERSION >= 11)
++extern void *g_MemacRegs;
++void fm_clk_down(void);
++uint32_t fman_memac_get_event(void *regs, uint32_t ev_mask);
++void FM_ChangeClock(t_Handle h_Fm, int hardwarePortId)
++{
++      int macId;
++      uint32_t    event, rcr;
++      t_Fm *p_Fm = (t_Fm*)h_Fm;
++      rcr = GET_UINT32(p_Fm->p_FmFpmRegs->fm_rcr);
++      rcr |= 0x04000000;
++      WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rcr, rcr);
++
++      HW_PORT_ID_TO_SW_PORT_ID(macId, hardwarePortId);
++      do
++      {
++              event = fman_memac_get_event(g_MemacRegs, 0xFFFFFFFF);
++      } while ((event & 0x00000020) == 0);
++      fm_clk_down();
++      rcr = GET_UINT32(p_Fm->p_FmFpmRegs->fm_rcr);
++      rcr &= ~0x04000000;
++      WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rcr, rcr);
++}
++#endif
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.h
+@@ -0,0 +1,648 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm.h
++
++ @Description   FM internal structures and definitions.
++*//***************************************************************************/
++#ifndef __FM_H
++#define __FM_H
++
++#include "error_ext.h"
++#include "std_ext.h"
++#include "fm_ext.h"
++#include "fm_ipc.h"
++
++#include "fsl_fman.h"
++
++#define __ERR_MODULE__  MODULE_FM
++
++#define FM_MAX_NUM_OF_HW_PORT_IDS           64
++#define FM_MAX_NUM_OF_GUESTS                100
++
++/**************************************************************************//**
++ @Description       Exceptions
++*//***************************************************************************/
++#define FM_EX_DMA_BUS_ERROR                 0x80000000      /**< DMA bus error. */
++#define FM_EX_DMA_READ_ECC                  0x40000000
++#define FM_EX_DMA_SYSTEM_WRITE_ECC          0x20000000
++#define FM_EX_DMA_FM_WRITE_ECC              0x10000000
++#define FM_EX_FPM_STALL_ON_TASKS            0x08000000      /**< Stall of tasks on FPM */
++#define FM_EX_FPM_SINGLE_ECC                0x04000000      /**< Single ECC on FPM */
++#define FM_EX_FPM_DOUBLE_ECC                0x02000000
++#define FM_EX_QMI_SINGLE_ECC                0x01000000      /**< Single ECC on FPM */
++#define FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID   0x00800000      /**< Dequeu from default queue id */
++#define FM_EX_QMI_DOUBLE_ECC                0x00400000
++#define FM_EX_BMI_LIST_RAM_ECC              0x00200000
++#define FM_EX_BMI_STORAGE_PROFILE_ECC       0x00100000
++#define FM_EX_BMI_STATISTICS_RAM_ECC        0x00080000
++#define FM_EX_IRAM_ECC                      0x00040000
++#define FM_EX_MURAM_ECC                     0x00020000
++#define FM_EX_BMI_DISPATCH_RAM_ECC          0x00010000
++#define FM_EX_DMA_SINGLE_PORT_ECC           0x00008000
++
++#define DMA_EMSR_EMSTR_MASK                 0x0000FFFF
++
++#define DMA_THRESH_COMMQ_MASK               0xFF000000
++#define DMA_THRESH_READ_INT_BUF_MASK        0x007F0000
++#define DMA_THRESH_WRITE_INT_BUF_MASK       0x0000007F
++
++#define GET_EXCEPTION_FLAG(bitMask, exception)              \
++switch (exception){                                         \
++    case e_FM_EX_DMA_BUS_ERROR:                             \
++        bitMask = FM_EX_DMA_BUS_ERROR; break;               \
++    case e_FM_EX_DMA_SINGLE_PORT_ECC:                       \
++        bitMask = FM_EX_DMA_SINGLE_PORT_ECC; break;         \
++    case e_FM_EX_DMA_READ_ECC:                              \
++        bitMask = FM_EX_DMA_READ_ECC; break;                \
++    case e_FM_EX_DMA_SYSTEM_WRITE_ECC:                      \
++        bitMask = FM_EX_DMA_SYSTEM_WRITE_ECC; break;        \
++    case e_FM_EX_DMA_FM_WRITE_ECC:                          \
++        bitMask = FM_EX_DMA_FM_WRITE_ECC; break;            \
++    case e_FM_EX_FPM_STALL_ON_TASKS:                        \
++        bitMask = FM_EX_FPM_STALL_ON_TASKS; break;          \
++    case e_FM_EX_FPM_SINGLE_ECC:                            \
++        bitMask = FM_EX_FPM_SINGLE_ECC; break;              \
++    case e_FM_EX_FPM_DOUBLE_ECC:                            \
++        bitMask = FM_EX_FPM_DOUBLE_ECC; break;              \
++    case e_FM_EX_QMI_SINGLE_ECC:                            \
++        bitMask = FM_EX_QMI_SINGLE_ECC; break;              \
++    case e_FM_EX_QMI_DOUBLE_ECC:                            \
++        bitMask = FM_EX_QMI_DOUBLE_ECC; break;              \
++    case e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID:               \
++        bitMask = FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID; break; \
++    case e_FM_EX_BMI_LIST_RAM_ECC:                          \
++        bitMask = FM_EX_BMI_LIST_RAM_ECC; break;            \
++    case e_FM_EX_BMI_STORAGE_PROFILE_ECC:                   \
++        bitMask = FM_EX_BMI_STORAGE_PROFILE_ECC; break;     \
++    case e_FM_EX_BMI_STATISTICS_RAM_ECC:                    \
++        bitMask = FM_EX_BMI_STATISTICS_RAM_ECC; break;      \
++    case e_FM_EX_BMI_DISPATCH_RAM_ECC:                      \
++        bitMask = FM_EX_BMI_DISPATCH_RAM_ECC; break;        \
++    case e_FM_EX_IRAM_ECC:                                  \
++        bitMask = FM_EX_IRAM_ECC; break;                    \
++    case e_FM_EX_MURAM_ECC:                                 \
++        bitMask = FM_EX_MURAM_ECC; break;                   \
++    default: bitMask = 0;break;                             \
++}
++
++#define GET_FM_MODULE_EVENT(_mod, _id, _intrType, _event)                                           \
++    switch (_mod) {                                                                                 \
++        case e_FM_MOD_PRS:                                                                          \
++            if (_id) _event = e_FM_EV_DUMMY_LAST;                                                   \
++            else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_PRS : e_FM_EV_PRS;        \
++            break;                                                                                  \
++        case e_FM_MOD_KG:                                                                           \
++            if (_id) _event = e_FM_EV_DUMMY_LAST;                                                   \
++            else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_KG : e_FM_EV_DUMMY_LAST;  \
++            break;                                                                                  \
++        case e_FM_MOD_PLCR:                                                                         \
++            if (_id) _event = e_FM_EV_DUMMY_LAST;                                                   \
++            else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_PLCR : e_FM_EV_PLCR;      \
++            break;                                                                                  \
++        case e_FM_MOD_TMR:                                                                          \
++            if (_id) _event = e_FM_EV_DUMMY_LAST;                                                   \
++            else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_DUMMY_LAST : e_FM_EV_TMR;     \
++            break;                                                                                  \
++        case e_FM_MOD_10G_MAC:                                                                      \
++            if (_id >= FM_MAX_NUM_OF_10G_MACS) _event = e_FM_EV_DUMMY_LAST;                         \
++            else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? (e_FM_EV_ERR_10G_MAC0 + _id) : (e_FM_EV_10G_MAC0 + _id); \
++            break;                                                                                  \
++        case e_FM_MOD_1G_MAC:                                                                       \
++            if (_id >= FM_MAX_NUM_OF_1G_MACS) _event = e_FM_EV_DUMMY_LAST;                          \
++            else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? (e_FM_EV_ERR_1G_MAC0 + _id) : (e_FM_EV_1G_MAC0 + _id); \
++            break;                                                                                  \
++        case e_FM_MOD_MACSEC:                                                                       \
++            switch (_id){                                                                           \
++                 case (0): _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_MACSEC_MAC0:e_FM_EV_MACSEC_MAC0; \
++                 break;                                                                             \
++                 }                                                                                  \
++            break;                                                                                  \
++        case e_FM_MOD_FMAN_CTRL:                                                                    \
++            if (_intrType == e_FM_INTR_TYPE_ERR) _event = e_FM_EV_DUMMY_LAST;                       \
++            else _event = (e_FM_EV_FMAN_CTRL_0 + _id);                                              \
++            break;                                                                                  \
++        default: _event = e_FM_EV_DUMMY_LAST;                                                       \
++        break;                                                                                      \
++    }
++
++#define FMAN_CACHE_OVERRIDE_TRANS(fsl_cache_override, _cache_override) \
++    switch (_cache_override){ \
++        case  e_FM_DMA_NO_CACHE_OR:                    \
++            fsl_cache_override =  E_FMAN_DMA_NO_CACHE_OR; break;    \
++        case  e_FM_DMA_NO_STASH_DATA:                    \
++            fsl_cache_override =  E_FMAN_DMA_NO_STASH_DATA; break;        \
++        case  e_FM_DMA_MAY_STASH_DATA:                    \
++            fsl_cache_override =  E_FMAN_DMA_MAY_STASH_DATA; break;    \
++        case  e_FM_DMA_STASH_DATA:                        \
++            fsl_cache_override =  E_FMAN_DMA_STASH_DATA; break;        \
++        default: \
++            fsl_cache_override =  E_FMAN_DMA_NO_CACHE_OR; break;    \
++    }
++
++#define FMAN_AID_MODE_TRANS(fsl_aid_mode, _aid_mode) \
++    switch (_aid_mode){ \
++        case  e_FM_DMA_AID_OUT_PORT_ID:                    \
++            fsl_aid_mode =  E_FMAN_DMA_AID_OUT_PORT_ID; break;    \
++        case  e_FM_DMA_AID_OUT_TNUM:                    \
++            fsl_aid_mode =  E_FMAN_DMA_AID_OUT_TNUM; break;        \
++        default: \
++            fsl_aid_mode =  E_FMAN_DMA_AID_OUT_PORT_ID; break;    \
++    }
++
++#define FMAN_DMA_DBG_CNT_TRANS(fsl_dma_dbg_cnt, _dma_dbg_cnt) \
++    switch (_dma_dbg_cnt){ \
++        case  e_FM_DMA_DBG_NO_CNT:                    \
++            fsl_dma_dbg_cnt =  E_FMAN_DMA_DBG_NO_CNT; break;    \
++        case  e_FM_DMA_DBG_CNT_DONE:                    \
++            fsl_dma_dbg_cnt =  E_FMAN_DMA_DBG_CNT_DONE; break;        \
++        case  e_FM_DMA_DBG_CNT_COMM_Q_EM:                    \
++            fsl_dma_dbg_cnt =  E_FMAN_DMA_DBG_CNT_COMM_Q_EM; break;    \
++        case  e_FM_DMA_DBG_CNT_INT_READ_EM:                        \
++            fsl_dma_dbg_cnt =  E_FMAN_DMA_DBG_CNT_INT_READ_EM; break;        \
++        case  e_FM_DMA_DBG_CNT_INT_WRITE_EM:                        \
++            fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_INT_WRITE_EM ; break;        \
++        case  e_FM_DMA_DBG_CNT_FPM_WAIT:                        \
++            fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_FPM_WAIT ; break;        \
++        case  e_FM_DMA_DBG_CNT_SIGLE_BIT_ECC:                        \
++            fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_SIGLE_BIT_ECC ; break;        \
++        case  e_FM_DMA_DBG_CNT_RAW_WAR_PROT:                        \
++            fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_RAW_WAR_PROT ; break;        \
++        default: \
++            fsl_dma_dbg_cnt =  E_FMAN_DMA_DBG_NO_CNT; break;    \
++    }
++
++#define FMAN_DMA_EMER_TRANS(fsl_dma_emer, _dma_emer) \
++    switch (_dma_emer){ \
++        case  e_FM_DMA_EM_EBS:                    \
++            fsl_dma_emer =  E_FMAN_DMA_EM_EBS; break;    \
++        case  e_FM_DMA_EM_SOS:                    \
++            fsl_dma_emer =  E_FMAN_DMA_EM_SOS; break;        \
++        default: \
++            fsl_dma_emer =  E_FMAN_DMA_EM_EBS; break;    \
++    }
++
++#define FMAN_DMA_ERR_TRANS(fsl_dma_err, _dma_err) \
++    switch (_dma_err){ \
++        case  e_FM_DMA_ERR_CATASTROPHIC:                    \
++            fsl_dma_err =  E_FMAN_DMA_ERR_CATASTROPHIC; break;    \
++        case  e_FM_DMA_ERR_REPORT:                    \
++            fsl_dma_err =  E_FMAN_DMA_ERR_REPORT; break;        \
++        default: \
++            fsl_dma_err =  E_FMAN_DMA_ERR_CATASTROPHIC; break;    \
++    }
++
++#define FMAN_CATASTROPHIC_ERR_TRANS(fsl_catastrophic_err, _catastrophic_err) \
++    switch (_catastrophic_err){ \
++        case  e_FM_CATASTROPHIC_ERR_STALL_PORT:                    \
++            fsl_catastrophic_err =  E_FMAN_CATAST_ERR_STALL_PORT; break;    \
++        case  e_FM_CATASTROPHIC_ERR_STALL_TASK:                    \
++            fsl_catastrophic_err =  E_FMAN_CATAST_ERR_STALL_TASK; break;        \
++        default: \
++            fsl_catastrophic_err =  E_FMAN_CATAST_ERR_STALL_PORT; break;    \
++    }
++
++#define FMAN_COUNTERS_TRANS(fsl_counters, _counters) \
++    switch (_counters){ \
++        case  e_FM_COUNTERS_ENQ_TOTAL_FRAME:                    \
++            fsl_counters =  E_FMAN_COUNTERS_ENQ_TOTAL_FRAME; break;    \
++        case  e_FM_COUNTERS_DEQ_TOTAL_FRAME:                    \
++            fsl_counters =  E_FMAN_COUNTERS_DEQ_TOTAL_FRAME; break;        \
++        case  e_FM_COUNTERS_DEQ_0:                    \
++            fsl_counters =  E_FMAN_COUNTERS_DEQ_0; break;    \
++        case  e_FM_COUNTERS_DEQ_1:                    \
++            fsl_counters =  E_FMAN_COUNTERS_DEQ_1; break;        \
++        case  e_FM_COUNTERS_DEQ_2:                    \
++            fsl_counters =  E_FMAN_COUNTERS_DEQ_2; break;    \
++        case  e_FM_COUNTERS_DEQ_3:                    \
++            fsl_counters =  E_FMAN_COUNTERS_DEQ_3; break;        \
++        case  e_FM_COUNTERS_DEQ_FROM_DEFAULT:                    \
++            fsl_counters =  E_FMAN_COUNTERS_DEQ_FROM_DEFAULT; break;    \
++        case  e_FM_COUNTERS_DEQ_FROM_CONTEXT:                    \
++            fsl_counters =  E_FMAN_COUNTERS_DEQ_FROM_CONTEXT; break;        \
++        case  e_FM_COUNTERS_DEQ_FROM_FD:                    \
++            fsl_counters =  E_FMAN_COUNTERS_DEQ_FROM_FD; break;    \
++        case  e_FM_COUNTERS_DEQ_CONFIRM:                    \
++            fsl_counters =  E_FMAN_COUNTERS_DEQ_CONFIRM; break;        \
++        default: \
++            fsl_counters =  E_FMAN_COUNTERS_ENQ_TOTAL_FRAME; break;    \
++    }
++
++/**************************************************************************//**
++ @Description       defaults
++*//***************************************************************************/
++#define DEFAULT_exceptions                 (FM_EX_DMA_BUS_ERROR            |\
++                                            FM_EX_DMA_READ_ECC              |\
++                                            FM_EX_DMA_SYSTEM_WRITE_ECC      |\
++                                            FM_EX_DMA_FM_WRITE_ECC          |\
++                                            FM_EX_FPM_STALL_ON_TASKS        |\
++                                            FM_EX_FPM_SINGLE_ECC            |\
++                                            FM_EX_FPM_DOUBLE_ECC            |\
++                                            FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID|\
++                                            FM_EX_BMI_LIST_RAM_ECC          |\
++                                            FM_EX_BMI_STORAGE_PROFILE_ECC   |\
++                                            FM_EX_BMI_STATISTICS_RAM_ECC    |\
++                                            FM_EX_IRAM_ECC                  |\
++                                            FM_EX_MURAM_ECC                 |\
++                                            FM_EX_BMI_DISPATCH_RAM_ECC      |\
++                                            FM_EX_QMI_DOUBLE_ECC            |\
++                                            FM_EX_QMI_SINGLE_ECC)
++
++#define DEFAULT_eccEnable                   FALSE
++#ifdef FM_PEDANTIC_DMA
++#define DEFAULT_aidOverride                 TRUE
++#else
++#define DEFAULT_aidOverride                 FALSE
++#endif /* FM_PEDANTIC_DMA */
++#define DEFAULT_aidMode                     e_FM_DMA_AID_OUT_TNUM
++#define DEFAULT_dmaStopOnBusError           FALSE
++#define DEFAULT_stopAtBusError              FALSE
++#define DEFAULT_axiDbgNumOfBeats            1
++#define DEFAULT_dmaReadIntBufLow            ((DMA_THRESH_MAX_BUF+1)/2)
++#define DEFAULT_dmaReadIntBufHigh           ((DMA_THRESH_MAX_BUF+1)*3/4)
++#define DEFAULT_dmaWriteIntBufLow           ((DMA_THRESH_MAX_BUF+1)/2)
++#define DEFAULT_dmaWriteIntBufHigh          ((DMA_THRESH_MAX_BUF+1)*3/4)
++#define DEFAULT_catastrophicErr             e_FM_CATASTROPHIC_ERR_STALL_PORT
++#define DEFAULT_dmaErr                      e_FM_DMA_ERR_CATASTROPHIC
++#define DEFAULT_resetOnInit                 FALSE
++#define DEFAULT_resetOnInitOverrideCallback NULL
++#define DEFAULT_haltOnExternalActivation    FALSE   /* do not change! if changed, must be disabled for rev1 ! */
++#define DEFAULT_haltOnUnrecoverableEccError FALSE   /* do not change! if changed, must be disabled for rev1 ! */
++#define DEFAULT_externalEccRamsEnable       FALSE
++#define DEFAULT_VerifyUcode                 FALSE
++
++#if (DPAA_VERSION < 11)
++#define DEFAULT_totalFifoSize(major, minor)     \
++    (((major == 2) || (major == 5)) ?           \
++     (100*KILOBYTE) : ((major == 4) ?           \
++     (49*KILOBYTE) : (122*KILOBYTE)))
++#define DEFAULT_totalNumOfTasks(major, minor)   \
++            BMI_MAX_NUM_OF_TASKS
++
++#define DEFAULT_dmaCommQLow                 ((DMA_THRESH_MAX_COMMQ+1)/2)
++#define DEFAULT_dmaCommQHigh                ((DMA_THRESH_MAX_COMMQ+1)*3/4)
++#define DEFAULT_cacheOverride               e_FM_DMA_NO_CACHE_OR
++#define DEFAULT_dmaCamNumOfEntries          32
++#define DEFAULT_dmaDbgCntMode               e_FM_DMA_DBG_NO_CNT
++#define DEFAULT_dmaEnEmergency              FALSE
++#define DEFAULT_dmaSosEmergency             0
++#define DEFAULT_dmaWatchdog                 0 /* disabled */
++#define DEFAULT_dmaEnEmergencySmoother      FALSE
++#define DEFAULT_dmaEmergencySwitchCounter   0
++
++#define DEFAULT_dispLimit                   0
++#define DEFAULT_prsDispTh                   16
++#define DEFAULT_plcrDispTh                  16
++#define DEFAULT_kgDispTh                    16
++#define DEFAULT_bmiDispTh                   16
++#define DEFAULT_qmiEnqDispTh                16
++#define DEFAULT_qmiDeqDispTh                16
++#define DEFAULT_fmCtl1DispTh                16
++#define DEFAULT_fmCtl2DispTh                16
++
++#else  /* (DPAA_VERSION < 11) */
++/* Defaults are registers' reset values */
++#define DEFAULT_totalFifoSize(major, minor)                   \
++      (((major == 6) && ((minor == 1) || (minor == 4))) ?     \
++      (156*KILOBYTE) : (295*KILOBYTE))
++
++/* According to the default value of FMBM_CFG2[TNTSKS] */
++#define DEFAULT_totalNumOfTasks(major, minor)   \
++      (((major == 6) && ((minor == 1) || (minor == 4))) ? 59 : 124)
++
++#define DEFAULT_dmaCommQLow                 0x2A
++#define DEFAULT_dmaCommQHigh                0x3F
++#define DEFAULT_cacheOverride               e_FM_DMA_NO_CACHE_OR
++#define DEFAULT_dmaCamNumOfEntries          64
++#define DEFAULT_dmaDbgCntMode               e_FM_DMA_DBG_NO_CNT
++#define DEFAULT_dmaEnEmergency              FALSE
++#define DEFAULT_dmaSosEmergency             0
++#define DEFAULT_dmaWatchdog                 0 /* disabled */
++#define DEFAULT_dmaEnEmergencySmoother      FALSE
++#define DEFAULT_dmaEmergencySwitchCounter   0
++
++#define DEFAULT_dispLimit                   0
++#define DEFAULT_prsDispTh                   16
++#define DEFAULT_plcrDispTh                  16
++#define DEFAULT_kgDispTh                    16
++#define DEFAULT_bmiDispTh                   16
++#define DEFAULT_qmiEnqDispTh                16
++#define DEFAULT_qmiDeqDispTh                16
++#define DEFAULT_fmCtl1DispTh                16
++#define DEFAULT_fmCtl2DispTh                16
++#endif /* (DPAA_VERSION < 11) */
++
++#define FM_TIMESTAMP_1_USEC_BIT             8
++
++/**************************************************************************//**
++ @Collection   Defines used for enabling/disabling FM interrupts
++ @{
++*//***************************************************************************/
++#define ERR_INTR_EN_DMA         0x00010000
++#define ERR_INTR_EN_FPM         0x80000000
++#define ERR_INTR_EN_BMI         0x00800000
++#define ERR_INTR_EN_QMI         0x00400000
++#define ERR_INTR_EN_PRS         0x00200000
++#define ERR_INTR_EN_KG          0x00100000
++#define ERR_INTR_EN_PLCR        0x00080000
++#define ERR_INTR_EN_MURAM       0x00040000
++#define ERR_INTR_EN_IRAM        0x00020000
++#define ERR_INTR_EN_10G_MAC0    0x00008000
++#define ERR_INTR_EN_10G_MAC1    0x00000040
++#define ERR_INTR_EN_1G_MAC0     0x00004000
++#define ERR_INTR_EN_1G_MAC1     0x00002000
++#define ERR_INTR_EN_1G_MAC2     0x00001000
++#define ERR_INTR_EN_1G_MAC3     0x00000800
++#define ERR_INTR_EN_1G_MAC4     0x00000400
++#define ERR_INTR_EN_1G_MAC5     0x00000200
++#define ERR_INTR_EN_1G_MAC6     0x00000100
++#define ERR_INTR_EN_1G_MAC7     0x00000080
++#define ERR_INTR_EN_MACSEC_MAC0 0x00000001
++
++#define INTR_EN_QMI             0x40000000
++#define INTR_EN_PRS             0x20000000
++#define INTR_EN_WAKEUP          0x10000000
++#define INTR_EN_PLCR            0x08000000
++#define INTR_EN_1G_MAC0         0x00080000
++#define INTR_EN_1G_MAC1         0x00040000
++#define INTR_EN_1G_MAC2         0x00020000
++#define INTR_EN_1G_MAC3         0x00010000
++#define INTR_EN_1G_MAC4         0x00000040
++#define INTR_EN_1G_MAC5         0x00000020
++#define INTR_EN_1G_MAC6         0x00000008
++#define INTR_EN_1G_MAC7         0x00000002
++#define INTR_EN_10G_MAC0        0x00200000
++#define INTR_EN_10G_MAC1        0x00100000
++#define INTR_EN_REV0            0x00008000
++#define INTR_EN_REV1            0x00004000
++#define INTR_EN_REV2            0x00002000
++#define INTR_EN_REV3            0x00001000
++#define INTR_EN_BRK             0x00000080
++#define INTR_EN_TMR             0x01000000
++#define INTR_EN_MACSEC_MAC0     0x00000001
++/* @} */
++
++/**************************************************************************//**
++ @Description       Memory Mapped Registers
++*//***************************************************************************/
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(push,1)
++#endif /* defined(__MWERKS__) && ... */
++
++typedef struct
++{
++    volatile uint32_t   iadd;           /**< FM IRAM instruction address register */
++    volatile uint32_t   idata;          /**< FM IRAM instruction data register */
++    volatile uint32_t   itcfg;          /**< FM IRAM timing config register */
++    volatile uint32_t   iready;         /**< FM IRAM ready register */
++    volatile uint32_t   res[0x1FFFC];
++} t_FMIramRegs;
++
++/* Trace buffer registers -
++   each FM Controller has its own trace buffer residing at FM_MM_TRB(fmCtrlIndex) offset */
++typedef struct t_FmTrbRegs
++{
++    volatile uint32_t   tcrh;
++    volatile uint32_t   tcrl;
++    volatile uint32_t   tesr;
++    volatile uint32_t   tecr0h;
++    volatile uint32_t   tecr0l;
++    volatile uint32_t   terf0h;
++    volatile uint32_t   terf0l;
++    volatile uint32_t   tecr1h;
++    volatile uint32_t   tecr1l;
++    volatile uint32_t   terf1h;
++    volatile uint32_t   terf1l;
++    volatile uint32_t   tpcch;
++    volatile uint32_t   tpccl;
++    volatile uint32_t   tpc1h;
++    volatile uint32_t   tpc1l;
++    volatile uint32_t   tpc2h;
++    volatile uint32_t   tpc2l;
++    volatile uint32_t   twdimr;
++    volatile uint32_t   twicvr;
++    volatile uint32_t   tar;
++    volatile uint32_t   tdr;
++    volatile uint32_t   tsnum1;
++    volatile uint32_t   tsnum2;
++    volatile uint32_t   tsnum3;
++    volatile uint32_t   tsnum4;
++} t_FmTrbRegs;
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(pop)
++#endif /* defined(__MWERKS__) && ... */
++
++/**************************************************************************//**
++ @Description       General defines
++*//***************************************************************************/
++#define FM_DEBUG_STATUS_REGISTER_OFFSET     0x000d1084UL
++#define FM_FW_DEBUG_INSTRUCTION             0x6ffff805UL
++
++/**************************************************************************//**
++ @Description       FPM defines
++*//***************************************************************************/
++/* masks */
++#define FPM_BRKC_RDBG                   0x00000200
++#define FPM_BRKC_SLP                    0x00000800
++/**************************************************************************//**
++ @Description       BMI defines
++*//***************************************************************************/
++/* masks */
++#define BMI_INIT_START                      0x80000000
++#define BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC 0x80000000
++#define BMI_ERR_INTR_EN_LIST_RAM_ECC        0x40000000
++#define BMI_ERR_INTR_EN_STATISTICS_RAM_ECC  0x20000000
++#define BMI_ERR_INTR_EN_DISPATCH_RAM_ECC    0x10000000
++/**************************************************************************//**
++ @Description       QMI defines
++*//***************************************************************************/
++/* masks */
++#define QMI_ERR_INTR_EN_DOUBLE_ECC      0x80000000
++#define QMI_ERR_INTR_EN_DEQ_FROM_DEF    0x40000000
++#define QMI_INTR_EN_SINGLE_ECC          0x80000000
++
++/**************************************************************************//**
++ @Description       IRAM defines
++*//***************************************************************************/
++/* masks */
++#define IRAM_IADD_AIE                   0x80000000
++#define IRAM_READY                      0x80000000
++
++/**************************************************************************//**
++ @Description       TRB defines
++*//***************************************************************************/
++/* masks */
++#define TRB_TCRH_RESET              0x04000000
++#define TRB_TCRH_ENABLE_COUNTERS    0x84008000
++#define TRB_TCRH_DISABLE_COUNTERS   0x8400C000
++#define TRB_TCRL_RESET              0x20000000
++#define TRB_TCRL_UTIL               0x00000460
++typedef struct {
++    void        (*f_Isr) (t_Handle h_Arg, uint32_t event);
++    t_Handle    h_SrcHandle;
++} t_FmanCtrlIntrSrc;
++
++
++typedef void (t_FmanCtrlIsr)( t_Handle h_Fm, uint32_t event);
++
++typedef struct
++{
++/***************************/
++/* Master/Guest parameters */
++/***************************/
++    uint8_t                     fmId;
++    e_FmPortType                portsTypes[FM_MAX_NUM_OF_HW_PORT_IDS];
++    uint16_t                    fmClkFreq;
++    uint16_t                    fmMacClkFreq;
++    t_FmRevisionInfo            revInfo;
++/**************************/
++/* Master Only parameters */
++/**************************/
++    bool                        enabledTimeStamp;
++    uint8_t                     count1MicroBit;
++    uint8_t                     totalNumOfTasks;
++    uint32_t                    totalFifoSize;
++    uint8_t                     maxNumOfOpenDmas;
++    uint8_t                     accumulatedNumOfTasks;
++    uint32_t                    accumulatedFifoSize;
++    uint8_t                     accumulatedNumOfOpenDmas;
++    uint8_t                     accumulatedNumOfDeqTnums;
++#ifdef FM_LOW_END_RESTRICTION
++    bool                        lowEndRestriction;
++#endif /* FM_LOW_END_RESTRICTION */
++    uint32_t                    exceptions;
++    int                         irq;
++    int                         errIrq;
++    bool                        ramsEccEnable;
++    bool                        explicitEnable;
++    bool                        internalCall;
++    uint8_t                     ramsEccOwners;
++    uint32_t                    extraFifoPoolSize;
++    uint8_t                     extraTasksPoolSize;
++    uint8_t                     extraOpenDmasPoolSize;
++#if defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS)
++    uint16_t                    portMaxFrameLengths10G[FM_MAX_NUM_OF_10G_MACS];
++    uint16_t                    macMaxFrameLengths10G[FM_MAX_NUM_OF_10G_MACS];
++#endif /* defined(FM_MAX_NUM_OF_10G_MACS) && ... */
++    uint16_t                    portMaxFrameLengths1G[FM_MAX_NUM_OF_1G_MACS];
++    uint16_t                    macMaxFrameLengths1G[FM_MAX_NUM_OF_1G_MACS];
++} t_FmStateStruct;
++
++#if (DPAA_VERSION >= 11)
++typedef struct t_FmMapParam {
++    uint16_t        profilesBase;
++    uint16_t        numOfProfiles;
++    t_Handle        h_FmPort;
++} t_FmMapParam;
++
++typedef struct t_FmAllocMng {
++    bool            allocated;
++    uint8_t         ownerId; /* guestId for KG in multi-partition only,
++                                portId for PLCR in any environment */
++} t_FmAllocMng;
++
++typedef struct t_FmPcdSpEntry {
++    bool            valid;
++    t_FmAllocMng    profilesMng;
++} t_FmPcdSpEntry;
++
++typedef struct t_FmSp {
++    void            *p_FmPcdStoragePrflRegs;
++    t_FmPcdSpEntry  profiles[FM_VSP_MAX_NUM_OF_ENTRIES];
++    t_FmMapParam    portsMapping[FM_MAX_NUM_OF_PORTS];
++} t_FmSp;
++#endif /* (DPAA_VERSION >= 11) */
++
++typedef struct t_Fm
++{
++/***************************/
++/* Master/Guest parameters */
++/***************************/
++/* locals for recovery */
++    uintptr_t                   baseAddr;
++
++/* un-needed for recovery */
++    t_Handle                    h_Pcd;
++    char                        fmModuleName[MODULE_NAME_SIZE];
++    char                        fmIpcHandlerModuleName[FM_MAX_NUM_OF_GUESTS][MODULE_NAME_SIZE];
++    t_Handle                    h_IpcSessions[FM_MAX_NUM_OF_GUESTS];
++    t_FmIntrSrc                 intrMng[e_FM_EV_DUMMY_LAST];    /* FM exceptions user callback */
++    uint8_t                     guestId;
++/**************************/
++/* Master Only parameters */
++/**************************/
++/* locals for recovery */
++    struct fman_fpm_regs *p_FmFpmRegs;
++    struct fman_bmi_regs *p_FmBmiRegs;
++    struct fman_qmi_regs *p_FmQmiRegs;
++    struct fman_dma_regs *p_FmDmaRegs;
++    struct fman_regs            *p_FmRegs;
++    t_FmExceptionsCallback      *f_Exception;
++    t_FmBusErrorCallback        *f_BusError;
++    t_Handle                    h_App;                          /* Application handle */
++    t_Handle                    h_Spinlock;
++    bool                        recoveryMode;
++    t_FmStateStruct             *p_FmStateStruct;
++    uint16_t                    tnumAgingPeriod;
++#if (DPAA_VERSION >= 11)
++    t_FmSp                      *p_FmSp;
++    uint8_t                     partNumOfVSPs;
++    uint8_t                     partVSPBase;
++    uintptr_t                   vspBaseAddr;
++#endif /* (DPAA_VERSION >= 11) */
++    bool                        portsPreFetchConfigured[FM_MAX_NUM_OF_HW_PORT_IDS]; /* Prefetch configration per Tx-port */
++    bool                        portsPreFetchValue[FM_MAX_NUM_OF_HW_PORT_IDS];      /* Prefetch configration per Tx-port */
++
++/* un-needed for recovery */
++    struct fman_cfg             *p_FmDriverParam;
++    t_Handle                    h_FmMuram;
++    uint64_t                    fmMuramPhysBaseAddr;
++    bool                        independentMode;
++    bool                        hcPortInitialized;
++    uintptr_t                   camBaseAddr;                    /* save for freeing */
++    uintptr_t                   resAddr;
++    uintptr_t                   fifoBaseAddr;                   /* save for freeing */
++    t_FmanCtrlIntrSrc           fmanCtrlIntr[FM_NUM_OF_FMAN_CTRL_EVENT_REGS];    /* FM exceptions user callback */
++    bool                        usedEventRegs[FM_NUM_OF_FMAN_CTRL_EVENT_REGS];
++    t_FmFirmwareParams          firmware;
++    bool                        fwVerify;
++    bool                        resetOnInit;
++    t_FmResetOnInitOverrideCallback     *f_ResetOnInitOverride;
++    uint32_t                    userSetExceptions;
++} t_Fm;
++
++
++#endif /* __FM_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_ipc.h
+@@ -0,0 +1,465 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          fm_ipc.h
++
++ @Description   FM Inter-Partition prototypes, structures and definitions.
++*//***************************************************************************/
++#ifndef __FM_IPC_H
++#define __FM_IPC_H
++
++#include "error_ext.h"
++#include "std_ext.h"
++
++
++/**************************************************************************//**
++ @Group         FM_grp Frame Manager API
++
++ @Description   FM API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         FM_IPC_grp FM Inter-Partition messaging Unit
++
++ @Description   FM Inter-Partition messaging unit API definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(push,1)
++#endif /* defined(__MWERKS__) && ... */
++
++/**************************************************************************//**
++ @Description   enum for defining MAC types
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   A structure of parameters for specifying a MAC.
++*//***************************************************************************/
++typedef _Packed struct
++{
++    uint8_t         id;
++    uint32_t        enumType;
++} _PackedType t_FmIpcMacParams;
++
++/**************************************************************************//**
++ @Description   A structure of parameters for specifying a MAC.
++*//***************************************************************************/
++typedef _Packed struct
++{
++    t_FmIpcMacParams    macParams;
++    uint16_t            maxFrameLength;
++} _PackedType t_FmIpcMacMaxFrameParams;
++
++/**************************************************************************//**
++ @Description   FM physical Address
++*//***************************************************************************/
++typedef _Packed struct t_FmIpcPhysAddr
++{
++    volatile uint8_t    high;
++    volatile uint32_t   low;
++} _PackedType t_FmIpcPhysAddr;
++
++
++typedef _Packed struct t_FmIpcPortOutInitParams {
++    uint8_t             numOfTasks;         /**< OUT */
++    uint8_t             numOfExtraTasks;    /**< OUT */
++    uint8_t             numOfOpenDmas;      /**< OUT */
++    uint8_t             numOfExtraOpenDmas; /**< OUT */
++    uint32_t            sizeOfFifo;         /**< OUT */
++    uint32_t            extraSizeOfFifo;    /**< OUT */
++    t_FmIpcPhysAddr     ipcPhysAddr;        /**< OUT */
++} _PackedType t_FmIpcPortOutInitParams;
++
++/**************************************************************************//**
++ @Description   Structure for IPC communication during FM_PORT_Init.
++*//***************************************************************************/
++typedef _Packed struct t_FmIpcPortInInitParams {
++    uint8_t             hardwarePortId;     /**< IN. port Id */
++    uint32_t            enumPortType;       /**< IN. Port type */
++    uint8_t             boolIndependentMode;/**< IN. TRUE if FM Port operates in independent mode */
++    uint16_t            liodnOffset;        /**< IN. Port's requested resource */
++    uint8_t             numOfTasks;         /**< IN. Port's requested resource */
++    uint8_t             numOfExtraTasks;    /**< IN. Port's requested resource */
++    uint8_t             numOfOpenDmas;      /**< IN. Port's requested resource */
++    uint8_t             numOfExtraOpenDmas; /**< IN. Port's requested resource */
++    uint32_t            sizeOfFifo;         /**< IN. Port's requested resource */
++    uint32_t            extraSizeOfFifo;    /**< IN. Port's requested resource */
++    uint8_t             deqPipelineDepth;   /**< IN. Port's requested resource */
++    uint16_t            maxFrameLength;     /**< IN. Port's max frame length. */
++    uint16_t            liodnBase;          /**< IN. Irrelevant for P4080 rev 1.
++                                                 LIODN base for this port, to be
++                                                 used together with LIODN offset. */
++} _PackedType t_FmIpcPortInInitParams;
++
++
++/**************************************************************************//**
++ @Description   Structure for IPC communication between port and FM
++                regarding tasks and open DMA resources management.
++*//***************************************************************************/
++typedef _Packed struct t_FmIpcPortRsrcParams {
++    uint8_t             hardwarePortId;     /**< IN. port Id */
++    uint32_t            val;                /**< IN. Port's requested resource */
++    uint32_t            extra;              /**< IN. Port's requested resource */
++    uint8_t             boolInitialConfig;
++} _PackedType t_FmIpcPortRsrcParams;
++
++
++/**************************************************************************//**
++ @Description   Structure for IPC communication between port and FM
++                regarding tasks and open DMA resources management.
++*//***************************************************************************/
++typedef _Packed struct t_FmIpcPortFifoParams {
++    t_FmIpcPortRsrcParams   rsrcParams;
++    uint32_t                enumPortType;
++    uint8_t                 boolIndependentMode;
++    uint8_t                 deqPipelineDepth;
++    uint8_t                 numOfPools;
++    uint16_t                secondLargestBufSize;
++    uint16_t                largestBufSize;
++    uint8_t                 boolInitialConfig;
++} _PackedType t_FmIpcPortFifoParams;
++
++/**************************************************************************//**
++ @Description   Structure for port-FM communication during FM_PORT_Free.
++*//***************************************************************************/
++typedef _Packed struct t_FmIpcPortFreeParams {
++    uint8_t             hardwarePortId;         /**< IN. port Id */
++    uint32_t            enumPortType;           /**< IN. Port type */
++    uint8_t             deqPipelineDepth;       /**< IN. Port's requested resource */
++} _PackedType t_FmIpcPortFreeParams;
++
++/**************************************************************************//**
++ @Description   Structure for defining DMA status
++*//***************************************************************************/
++typedef _Packed struct t_FmIpcDmaStatus {
++    uint8_t    boolCmqNotEmpty;            /**< Command queue is not empty */
++    uint8_t    boolBusError;               /**< Bus error occurred */
++    uint8_t    boolReadBufEccError;        /**< Double ECC error on buffer Read */
++    uint8_t    boolWriteBufEccSysError;    /**< Double ECC error on buffer write from system side */
++    uint8_t    boolWriteBufEccFmError;     /**< Double ECC error on buffer write from FM side */
++    uint8_t    boolSinglePortEccError;     /**< Single port ECC error from FM side */
++} _PackedType t_FmIpcDmaStatus;
++
++typedef _Packed struct t_FmIpcRegisterIntr
++{
++    uint8_t         guestId;        /* IN */
++    uint32_t        event;          /* IN */
++} _PackedType t_FmIpcRegisterIntr;
++
++typedef _Packed struct t_FmIpcIsr
++{
++    uint8_t         boolErr;        /* IN */
++    uint32_t        pendingReg;     /* IN */
++} _PackedType t_FmIpcIsr;
++
++/**************************************************************************//**
++ @Description   structure for returning FM parameters
++*//***************************************************************************/
++typedef _Packed struct t_FmIpcParams {
++    uint16_t        fmClkFreq;              /**< OUT: FM Clock frequency */
++    uint16_t        fmMacClkFreq;           /**< OUT: FM MAC clock frequence */
++    uint8_t         majorRev;               /**< OUT: FM Major revision */
++    uint8_t         minorRev;               /**< OUT: FM Minor revision */
++} _PackedType t_FmIpcParams;
++
++
++/**************************************************************************//**
++ @Description   structure for returning Fman Ctrl Code revision information
++*//***************************************************************************/
++typedef _Packed struct t_FmIpcFmanCtrlCodeRevisionInfo {
++    uint16_t        packageRev;             /**< OUT: Package revision */
++    uint8_t         majorRev;               /**< OUT: Major revision */
++    uint8_t         minorRev;               /**< OUT: Minor revision */
++} _PackedType t_FmIpcFmanCtrlCodeRevisionInfo;
++
++/**************************************************************************//**
++ @Description   Structure for defining Fm number of Fman controlers
++*//***************************************************************************/
++typedef _Packed struct t_FmIpcPortNumOfFmanCtrls {
++    uint8_t             hardwarePortId;         /**< IN. port Id */
++    uint8_t             numOfFmanCtrls;         /**< IN. Port type */
++    t_FmFmanCtrl        orFmanCtrl;             /**< IN. fman controller for order restoration*/
++} t_FmIpcPortNumOfFmanCtrls;
++
++/**************************************************************************//**
++ @Description   structure for setting Fman contriller events
++*//***************************************************************************/
++typedef _Packed struct t_FmIpcFmanEvents {
++    uint8_t     eventRegId;               /**< IN: Fman controller event register id */
++    uint32_t    enableEvents;             /**< IN/OUT: required enabled events mask */
++} _PackedType t_FmIpcFmanEvents;
++
++typedef _Packed struct t_FmIpcResourceAllocParams {
++    uint8_t     guestId;
++    uint16_t    base;
++    uint16_t    num;
++}_PackedType t_FmIpcResourceAllocParams;
++
++typedef _Packed struct t_FmIpcVspSetPortWindow {
++    uint8_t     hardwarePortId;
++    uint8_t     baseStorageProfile;
++    uint8_t     log2NumOfProfiles;
++}_PackedType t_FmIpcVspSetPortWindow;
++
++typedef _Packed struct t_FmIpcSetCongestionGroupPfcPriority {
++    uint32_t     congestionGroupId;
++    uint8_t      priorityBitMap;
++}_PackedType t_FmIpcSetCongestionGroupPfcPriority;
++
++#define FM_IPC_MAX_REPLY_BODY_SIZE  20
++#define FM_IPC_MAX_REPLY_SIZE       (FM_IPC_MAX_REPLY_BODY_SIZE + sizeof(uint32_t))
++#define FM_IPC_MAX_MSG_SIZE         30
++
++typedef _Packed struct t_FmIpcMsg
++{
++    uint32_t    msgId;
++    uint8_t     msgBody[FM_IPC_MAX_MSG_SIZE];
++} _PackedType t_FmIpcMsg;
++
++typedef _Packed struct t_FmIpcReply
++{
++    uint32_t    error;
++    uint8_t     replyBody[FM_IPC_MAX_REPLY_BODY_SIZE];
++} _PackedType t_FmIpcReply;
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(pop)
++#endif /* defined(__MWERKS__) && ... */
++
++
++/***************************************************************************/
++/************************ FRONT-END-TO-BACK-END*****************************/
++/***************************************************************************/
++
++/**************************************************************************//**
++ @Function      FM_GET_TIMESTAMP_SCALE
++
++ @Description   Used by FM front-end.
++
++ @Param[out]    uint32_t Pointer
++*//***************************************************************************/
++#define FM_GET_TIMESTAMP_SCALE      1
++
++/**************************************************************************//**
++ @Function      FM_GET_COUNTER
++
++ @Description   Used by FM front-end.
++
++ @Param[in/out] t_FmIpcGetCounter Pointer
++*//***************************************************************************/
++#define FM_GET_COUNTER              2
++
++/**************************************************************************//**
++ @Function      FM_GET_SET_PORT_PARAMS
++
++ @Description   Used by FM front-end for the PORT module in order to set and get
++                parameters in/from master FM module on FM PORT initialization time.
++
++ @Param[in/out] t_FmIcPortInitParams Pointer
++*//***************************************************************************/
++#define FM_GET_SET_PORT_PARAMS      4
++
++/**************************************************************************//**
++ @Function      FM_FREE_PORT
++
++ @Description   Used by FM front-end for the PORT module when a port is freed
++                to free all FM PORT resources.
++
++ @Param[in]     uint8_t Pointer
++*//***************************************************************************/
++#define FM_FREE_PORT                5
++
++/**************************************************************************//**
++ @Function      FM_RESET_MAC
++
++ @Description   Used by front-end for the MAC module to reset the MAC registers
++
++ @Param[in]     t_FmIpcMacParams Pointer .
++*//***************************************************************************/
++#define FM_RESET_MAC                6
++
++/**************************************************************************//**
++ @Function      FM_RESUME_STALLED_PORT
++
++ @Description   Used by FM front-end for the PORT module in order to
++                release a stalled FM Port.
++
++ @Param[in]     uint8_t Pointer
++*//***************************************************************************/
++#define FM_RESUME_STALLED_PORT      7
++
++/**************************************************************************//**
++ @Function      FM_IS_PORT_STALLED
++
++ @Description   Used by FM front-end for the PORT module in order to check whether
++                an FM port is stalled.
++
++ @Param[in/out] t_FmIcPortIsStalled Pointer
++*//***************************************************************************/
++#define FM_IS_PORT_STALLED          8
++
++/**************************************************************************//**
++ @Function      FM_GET_PARAMS
++
++ @Description   Used by FM front-end for the PORT module in order to dump
++                return FM parameters.
++
++ @Param[in]     uint8_t Pointer
++*//***************************************************************************/
++#define FM_GET_PARAMS                  10
++
++/**************************************************************************//**
++ @Function      FM_REGISTER_INTR
++
++ @Description   Used by FM front-end to register an interrupt handler to
++                be called upon interrupt for guest.
++
++ @Param[out]    t_FmIpcRegisterIntr Pointer
++*//***************************************************************************/
++#define FM_REGISTER_INTR            11
++
++/**************************************************************************//**
++ @Function      FM_DMA_STAT
++
++ @Description   Used by FM front-end to read the FM DMA status.
++
++ @Param[out]    t_FmIpcDmaStatus Pointer
++*//***************************************************************************/
++#define FM_DMA_STAT                 13
++
++/**************************************************************************//**
++ @Function      FM_ALLOC_FMAN_CTRL_EVENT_REG
++
++ @Description   Used by FM front-end to allocate event register.
++
++ @Param[out]    Event register id Pointer
++*//***************************************************************************/
++#define FM_ALLOC_FMAN_CTRL_EVENT_REG 14
++
++/**************************************************************************//**
++ @Function      FM_FREE_FMAN_CTRL_EVENT_REG
++
++ @Description   Used by FM front-end to free locate event register.
++
++ @Param[in]    uint8_t Pointer - Event register id
++*//***************************************************************************/
++#define FM_FREE_FMAN_CTRL_EVENT_REG 15
++
++/**************************************************************************//**
++ @Function      FM_SET_FMAN_CTRL_EVENTS_ENABLE
++
++ @Description   Used by FM front-end to enable events in the FPM
++                Fman controller event register.
++
++ @Param[in]    t_FmIpcFmanEvents Pointer
++*//***************************************************************************/
++#define FM_SET_FMAN_CTRL_EVENTS_ENABLE 16
++
++/**************************************************************************//**
++ @Function      FM_SET_FMAN_CTRL_EVENTS_ENABLE
++
++ @Description   Used by FM front-end to enable events in the FPM
++                Fman controller event register.
++
++ @Param[in/out] t_FmIpcFmanEvents Pointer
++*//***************************************************************************/
++#define FM_GET_FMAN_CTRL_EVENTS_ENABLE 17
++
++/**************************************************************************//**
++ @Function      FM_SET_MAC_MAX_FRAME
++
++ @Description   Used by FM front-end to set MAC's MTU/RTU's in
++                back-end.
++
++ @Param[in/out] t_FmIpcMacMaxFrameParams Pointer
++*//***************************************************************************/
++#define FM_SET_MAC_MAX_FRAME 18
++
++/**************************************************************************//**
++ @Function      FM_GET_PHYS_MURAM_BASE
++
++ @Description   Used by FM front-end in order to get MURAM base address
++
++ @Param[in/out] t_FmIpcPhysAddr Pointer
++*//***************************************************************************/
++#define FM_GET_PHYS_MURAM_BASE  19
++
++/**************************************************************************//**
++ @Function      FM_MASTER_IS_ALIVE
++
++ @Description   Used by FM front-end in order to verify Master is up
++
++ @Param[in/out] bool
++*//***************************************************************************/
++#define FM_MASTER_IS_ALIVE          20
++
++#define FM_ENABLE_RAM_ECC           21
++#define FM_DISABLE_RAM_ECC          22
++#define FM_SET_NUM_OF_FMAN_CTRL     23
++#define FM_SET_SIZE_OF_FIFO         24
++#define FM_SET_NUM_OF_TASKS         25
++#define FM_SET_NUM_OF_OPEN_DMAS     26
++#define FM_VSP_ALLOC                27
++#define FM_VSP_FREE                 28
++#define FM_VSP_SET_PORT_WINDOW      29
++#define FM_GET_FMAN_CTRL_CODE_REV   30
++#define FM_SET_CONG_GRP_PFC_PRIO    31
++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
++#define FM_10G_TX_ECC_WA            100
++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
++
++/***************************************************************************/
++/************************ BACK-END-TO-FRONT-END*****************************/
++/***************************************************************************/
++
++/**************************************************************************//**
++ @Function      FM_GUEST_ISR
++
++ @Description   Used by FM back-end to report an interrupt to the front-end.
++
++ @Param[out]    t_FmIpcIsr Pointer
++*//***************************************************************************/
++#define FM_GUEST_ISR                1
++
++
++
++/** @} */ /* end of FM_IPC_grp group */
++/** @} */ /* end of FM_grp group */
++
++
++#endif /* __FM_IPC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_muram.c
+@@ -0,0 +1,174 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          FM_muram.c
++
++ @Description   FM MURAM ...
++*//***************************************************************************/
++#include "error_ext.h"
++#include "std_ext.h"
++#include "mm_ext.h"
++#include "string_ext.h"
++#include "sprint_ext.h"
++#include "fm_muram_ext.h"
++#include "fm_common.h"
++
++#define __ERR_MODULE__  MODULE_FM_MURAM
++
++
++typedef struct
++{
++    t_Handle    h_Mem;
++    uintptr_t   baseAddr;
++    uint32_t    size;
++} t_FmMuram;
++
++
++void FmMuramClear(t_Handle h_FmMuram)
++{
++    t_FmMuram   *p_FmMuram = ( t_FmMuram *)h_FmMuram;
++
++    SANITY_CHECK_RETURN(h_FmMuram, E_INVALID_HANDLE);
++    IOMemSet32(UINT_TO_PTR(p_FmMuram->baseAddr), 0, p_FmMuram->size);
++}
++
++
++t_Handle FM_MURAM_ConfigAndInit(uintptr_t baseAddress, uint32_t size)
++{
++    t_Handle    h_Mem;
++    t_FmMuram   *p_FmMuram;
++
++    if (!baseAddress)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("baseAddress 0 is not supported"));
++        return NULL;
++    }
++
++    if (baseAddress%4)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("baseAddress not 4 bytes aligned!"));
++        return NULL;
++    }
++
++    /* Allocate FM MURAM structure */
++    p_FmMuram = (t_FmMuram *) XX_Malloc(sizeof(t_FmMuram));
++    if (!p_FmMuram)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MURAM driver structure"));
++        return NULL;
++    }
++    memset(p_FmMuram, 0, sizeof(t_FmMuram));
++
++
++    if ((MM_Init(&h_Mem, baseAddress, size) != E_OK) || (!h_Mem))
++    {
++        XX_Free(p_FmMuram);
++        REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-MURAM partition!!!"));
++        return NULL;
++    }
++
++    /* Initialize FM MURAM parameters which will be kept by the driver */
++    p_FmMuram->baseAddr = baseAddress;
++    p_FmMuram->size = size;
++    p_FmMuram->h_Mem = h_Mem;
++
++    return p_FmMuram;
++}
++
++t_Error FM_MURAM_Free(t_Handle h_FmMuram)
++{
++    t_FmMuram   *p_FmMuram = ( t_FmMuram *)h_FmMuram;
++
++    if (p_FmMuram->h_Mem)
++        MM_Free(p_FmMuram->h_Mem);
++
++    XX_Free(h_FmMuram);
++
++    return E_OK;
++}
++
++void  * FM_MURAM_AllocMem(t_Handle h_FmMuram, uint32_t size, uint32_t align)
++{
++    t_FmMuram   *p_FmMuram = ( t_FmMuram *)h_FmMuram;
++    uintptr_t   addr;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmMuram, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(p_FmMuram->h_Mem, E_INVALID_HANDLE, NULL);
++
++    addr = (uintptr_t)MM_Get(p_FmMuram->h_Mem, size, align ,"FM MURAM");
++
++    if (addr == ILLEGAL_BASE)
++        return NULL;
++
++    return UINT_TO_PTR(addr);
++}
++
++void  * FM_MURAM_AllocMemForce(t_Handle h_FmMuram, uint64_t base, uint32_t size)
++{
++    t_FmMuram   *p_FmMuram = ( t_FmMuram *)h_FmMuram;
++    uintptr_t   addr;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmMuram, E_INVALID_HANDLE, NULL);
++    SANITY_CHECK_RETURN_VALUE(p_FmMuram->h_Mem, E_INVALID_HANDLE, NULL);
++
++    addr = (uintptr_t)MM_GetForce(p_FmMuram->h_Mem, base, size, "FM MURAM");
++
++    if (addr == ILLEGAL_BASE)
++        return NULL;
++
++    return UINT_TO_PTR(addr);
++}
++
++t_Error FM_MURAM_FreeMem(t_Handle h_FmMuram, void *ptr)
++{
++    t_FmMuram   *p_FmMuram = ( t_FmMuram *)h_FmMuram;
++
++    SANITY_CHECK_RETURN_ERROR(h_FmMuram, E_INVALID_HANDLE);
++    SANITY_CHECK_RETURN_ERROR(p_FmMuram->h_Mem, E_INVALID_HANDLE);
++
++    if (MM_Put(p_FmMuram->h_Mem, PTR_TO_UINT(ptr)) == 0)
++        RETURN_ERROR(MINOR, E_INVALID_ADDRESS, ("memory pointer!!!"));
++
++    return E_OK;
++}
++
++uint64_t FM_MURAM_GetFreeMemSize(t_Handle h_FmMuram)
++{
++    t_FmMuram   *p_FmMuram = ( t_FmMuram *)h_FmMuram;
++
++    SANITY_CHECK_RETURN_VALUE(h_FmMuram, E_INVALID_HANDLE, 0);
++    SANITY_CHECK_RETURN_VALUE(p_FmMuram->h_Mem, E_INVALID_HANDLE, 0);
++
++    return MM_GetFreeMemSize(p_FmMuram->h_Mem);
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c
+@@ -0,0 +1,1398 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#include <linux/math64.h>
++#include "fsl_fman.h"
++#include "dpaa_integration_ext.h"
++
++uint32_t fman_get_bmi_err_event(struct fman_bmi_regs *bmi_rg)
++{
++      uint32_t        event, mask, force;
++
++      event = ioread32be(&bmi_rg->fmbm_ievr);
++      mask = ioread32be(&bmi_rg->fmbm_ier);
++      event &= mask;
++      /* clear the forced events */
++      force = ioread32be(&bmi_rg->fmbm_ifr);
++      if (force & event)
++              iowrite32be(force & ~event, &bmi_rg->fmbm_ifr);
++      /* clear the acknowledged events */
++      iowrite32be(event, &bmi_rg->fmbm_ievr);
++      return event;
++}
++
++uint32_t fman_get_qmi_err_event(struct fman_qmi_regs *qmi_rg)
++{
++      uint32_t        event, mask, force;
++
++      event = ioread32be(&qmi_rg->fmqm_eie);
++      mask = ioread32be(&qmi_rg->fmqm_eien);
++      event &= mask;
++
++      /* clear the forced events */
++      force = ioread32be(&qmi_rg->fmqm_eif);
++      if (force & event)
++              iowrite32be(force & ~event, &qmi_rg->fmqm_eif);
++      /* clear the acknowledged events */
++      iowrite32be(event, &qmi_rg->fmqm_eie);
++      return event;
++}
++
++uint32_t fman_get_dma_com_id(struct fman_dma_regs *dma_rg)
++{
++      return ioread32be(&dma_rg->fmdmtcid);
++}
++
++uint64_t fman_get_dma_addr(struct fman_dma_regs *dma_rg)
++{
++      uint64_t addr;
++
++      addr = (uint64_t)ioread32be(&dma_rg->fmdmtal);
++      addr |= ((uint64_t)(ioread32be(&dma_rg->fmdmtah)) << 32);
++
++      return addr;
++}
++
++uint32_t fman_get_dma_err_event(struct fman_dma_regs *dma_rg)
++{
++      uint32_t status, mask;
++
++      status = ioread32be(&dma_rg->fmdmsr);
++      mask = ioread32be(&dma_rg->fmdmmr);
++
++      /* clear DMA_STATUS_BUS_ERR if mask has no DMA_MODE_BER */
++      if ((mask & DMA_MODE_BER) != DMA_MODE_BER)
++              status &= ~DMA_STATUS_BUS_ERR;
++
++      /* clear relevant bits if mask has no DMA_MODE_ECC */
++      if ((mask & DMA_MODE_ECC) != DMA_MODE_ECC)
++              status &= ~(DMA_STATUS_FM_SPDAT_ECC |
++                      DMA_STATUS_READ_ECC |
++                              DMA_STATUS_SYSTEM_WRITE_ECC |
++                              DMA_STATUS_FM_WRITE_ECC);
++
++      /* clear set events */
++      iowrite32be(status, &dma_rg->fmdmsr);
++
++      return status;
++}
++
++uint32_t fman_get_fpm_err_event(struct fman_fpm_regs *fpm_rg)
++{
++      uint32_t        event;
++
++      event = ioread32be(&fpm_rg->fmfp_ee);
++      /* clear the all occurred events */
++      iowrite32be(event, &fpm_rg->fmfp_ee);
++      return event;
++}
++
++uint32_t fman_get_muram_err_event(struct fman_fpm_regs *fpm_rg)
++{
++      uint32_t        event, mask;
++
++      event = ioread32be(&fpm_rg->fm_rcr);
++      mask = ioread32be(&fpm_rg->fm_rie);
++
++      /* clear MURAM event bit (do not clear IRAM event) */
++      iowrite32be(event & ~FPM_RAM_IRAM_ECC, &fpm_rg->fm_rcr);
++
++      if ((mask & FPM_MURAM_ECC_ERR_EX_EN))
++              return event;
++      else
++              return 0;
++}
++
++uint32_t fman_get_iram_err_event(struct fman_fpm_regs *fpm_rg)
++{
++      uint32_t    event, mask;
++
++      event = ioread32be(&fpm_rg->fm_rcr) ;
++      mask = ioread32be(&fpm_rg->fm_rie);
++      /* clear IRAM event bit (do not clear MURAM event) */
++      iowrite32be(event & ~FPM_RAM_MURAM_ECC,
++                      &fpm_rg->fm_rcr);
++
++      if ((mask & FPM_IRAM_ECC_ERR_EX_EN))
++              return event;
++      else
++              return 0;
++}
++
++uint32_t fman_get_qmi_event(struct fman_qmi_regs *qmi_rg)
++{
++      uint32_t        event, mask, force;
++
++      event = ioread32be(&qmi_rg->fmqm_ie);
++      mask = ioread32be(&qmi_rg->fmqm_ien);
++      event &= mask;
++      /* clear the forced events */
++      force = ioread32be(&qmi_rg->fmqm_if);
++      if (force & event)
++              iowrite32be(force & ~event, &qmi_rg->fmqm_if);
++      /* clear the acknowledged events */
++      iowrite32be(event, &qmi_rg->fmqm_ie);
++      return event;
++}
++
++void fman_enable_time_stamp(struct fman_fpm_regs *fpm_rg,
++                              uint8_t count1ubit,
++                              uint16_t fm_clk_freq)
++{
++      uint32_t tmp;
++      uint64_t frac;
++      uint32_t intgr;
++      uint32_t ts_freq = (uint32_t)(1 << count1ubit); /* in Mhz */
++
++      /* configure timestamp so that bit 8 will count 1 microsecond
++       * Find effective count rate at TIMESTAMP least significant bits:
++       * Effective_Count_Rate = 1MHz x 2^8 = 256MHz
++       * Find frequency ratio between effective count rate and the clock:
++       * Effective_Count_Rate / CLK e.g. for 600 MHz clock:
++       * 256/600 = 0.4266666... */
++
++      intgr = ts_freq / fm_clk_freq;
++      /* we multiply by 2^16 to keep the fraction of the division
++       * we do not div back, since we write this value as a fraction
++       * see spec */
++
++      frac = ((uint64_t)ts_freq << 16) - ((uint64_t)intgr << 16) * fm_clk_freq;
++      /* we check remainder of the division in order to round up if not int */
++      if (do_div(frac, fm_clk_freq))
++              frac++;
++
++      tmp = (intgr << FPM_TS_INT_SHIFT) | (uint16_t)frac;
++      iowrite32be(tmp, &fpm_rg->fmfp_tsc2);
++
++      /* enable timestamp with original clock */
++      iowrite32be(FPM_TS_CTL_EN, &fpm_rg->fmfp_tsc1);
++}
++
++uint32_t fman_get_fpm_error_interrupts(struct fman_fpm_regs *fpm_rg)
++{
++      return ioread32be(&fpm_rg->fm_epi);
++}
++
++
++int fman_set_erratum_10gmac_a004_wa(struct fman_fpm_regs *fpm_rg)
++{
++      int timeout = 100;
++
++      iowrite32be(0x40000000, &fpm_rg->fmfp_extc);
++
++      while ((ioread32be(&fpm_rg->fmfp_extc) & 0x40000000) && --timeout)
++              udelay(10);
++
++      if (!timeout)
++              return -EBUSY;
++      return 0;
++}
++
++void fman_set_ctrl_intr(struct fman_fpm_regs *fpm_rg,
++                      uint8_t event_reg_id,
++                      uint32_t enable_events)
++{
++      iowrite32be(enable_events, &fpm_rg->fmfp_cee[event_reg_id]);
++}
++
++uint32_t fman_get_ctrl_intr(struct fman_fpm_regs *fpm_rg, uint8_t event_reg_id)
++{
++      return ioread32be(&fpm_rg->fmfp_cee[event_reg_id]);
++}
++
++void fman_set_num_of_riscs_per_port(struct fman_fpm_regs *fpm_rg,
++                                      uint8_t port_id,
++                                      uint8_t num_fman_ctrls,
++                                      uint32_t or_fman_ctrl)
++{
++      uint32_t tmp = 0;
++
++      tmp = (uint32_t)(port_id << FPM_PORT_FM_CTL_PORTID_SHIFT);
++      /*TODO - maybe to put CTL# according to another criteria*/
++      if (num_fman_ctrls == 2)
++              tmp = FPM_PRT_FM_CTL2 | FPM_PRT_FM_CTL1;
++      /* order restoration */
++      tmp |= (or_fman_ctrl << FPM_PRC_ORA_FM_CTL_SEL_SHIFT) | or_fman_ctrl;
++
++      iowrite32be(tmp, &fpm_rg->fmfp_prc);
++}
++
++void fman_set_order_restoration_per_port(struct fman_fpm_regs *fpm_rg,
++                                      uint8_t port_id,
++                                      bool independent_mode,
++                                      bool is_rx_port)
++{
++      uint32_t tmp = 0;
++
++      tmp = (uint32_t)(port_id << FPM_PORT_FM_CTL_PORTID_SHIFT);
++      if (independent_mode) {
++              if (is_rx_port)
++                      tmp |= (FPM_PRT_FM_CTL1 <<
++                              FPM_PRC_ORA_FM_CTL_SEL_SHIFT) | FPM_PRT_FM_CTL1;
++              else
++                      tmp |= (FPM_PRT_FM_CTL2 <<
++                              FPM_PRC_ORA_FM_CTL_SEL_SHIFT) | FPM_PRT_FM_CTL2;
++      } else {
++              tmp |= (FPM_PRT_FM_CTL2|FPM_PRT_FM_CTL1);
++
++              /* order restoration */
++              if (port_id % 2)
++                      tmp |= (FPM_PRT_FM_CTL1 <<
++                                      FPM_PRC_ORA_FM_CTL_SEL_SHIFT);
++              else
++                      tmp |= (FPM_PRT_FM_CTL2 <<
++                                      FPM_PRC_ORA_FM_CTL_SEL_SHIFT);
++      }
++      iowrite32be(tmp, &fpm_rg->fmfp_prc);
++}
++
++uint8_t fman_get_qmi_deq_th(struct fman_qmi_regs *qmi_rg)
++{
++      return (uint8_t)ioread32be(&qmi_rg->fmqm_gc);
++}
++
++uint8_t fman_get_qmi_enq_th(struct fman_qmi_regs *qmi_rg)
++{
++      return (uint8_t)(ioread32be(&qmi_rg->fmqm_gc) >> 8);
++}
++
++void fman_set_qmi_enq_th(struct fman_qmi_regs *qmi_rg, uint8_t val)
++{
++      uint32_t tmp_reg;
++
++      tmp_reg = ioread32be(&qmi_rg->fmqm_gc);
++      tmp_reg &= ~QMI_CFG_ENQ_MASK;
++      tmp_reg |= ((uint32_t)val << 8);
++      iowrite32be(tmp_reg, &qmi_rg->fmqm_gc);
++}
++
++void fman_set_qmi_deq_th(struct fman_qmi_regs *qmi_rg, uint8_t val)
++{
++      uint32_t tmp_reg;
++
++      tmp_reg = ioread32be(&qmi_rg->fmqm_gc);
++      tmp_reg &= ~QMI_CFG_DEQ_MASK;
++      tmp_reg |= (uint32_t)val;
++      iowrite32be(tmp_reg, &qmi_rg->fmqm_gc);
++}
++
++void fman_qmi_disable_dispatch_limit(struct fman_fpm_regs *fpm_rg)
++{
++      iowrite32be(0, &fpm_rg->fmfp_mxd);
++}
++
++void fman_set_liodn_per_port(struct fman_rg *fman_rg, uint8_t port_id,
++                              uint16_t liodn_base,
++                              uint16_t liodn_ofst)
++{
++      uint32_t tmp;
++
++      if ((port_id > 63) || (port_id < 1))
++              return;
++
++      /* set LIODN base for this port */
++      tmp = ioread32be(&fman_rg->dma_rg->fmdmplr[port_id / 2]);
++      if (port_id % 2) {
++              tmp &= ~FM_LIODN_BASE_MASK;
++              tmp |= (uint32_t)liodn_base;
++      } else {
++              tmp &= ~(FM_LIODN_BASE_MASK << DMA_LIODN_SHIFT);
++              tmp |= (uint32_t)liodn_base << DMA_LIODN_SHIFT;
++      }
++      iowrite32be(tmp, &fman_rg->dma_rg->fmdmplr[port_id / 2]);
++      iowrite32be((uint32_t)liodn_ofst,
++                      &fman_rg->bmi_rg->fmbm_spliodn[port_id - 1]);
++}
++
++bool fman_is_port_stalled(struct fman_fpm_regs *fpm_rg, uint8_t port_id)
++{
++      return (bool)!!(ioread32be(&fpm_rg->fmfp_ps[port_id]) & FPM_PS_STALLED);
++}
++
++void fman_resume_stalled_port(struct fman_fpm_regs *fpm_rg, uint8_t port_id)
++{
++      uint32_t        tmp;
++
++      tmp = (uint32_t)((port_id << FPM_PORT_FM_CTL_PORTID_SHIFT) |
++                              FPM_PRC_REALSE_STALLED);
++      iowrite32be(tmp, &fpm_rg->fmfp_prc);
++}
++
++int fman_reset_mac(struct fman_fpm_regs *fpm_rg, uint8_t mac_id, bool is_10g)
++{
++      uint32_t msk, timeout = 100;
++
++      /* Get the relevant bit mask */
++      if (is_10g) {
++              switch (mac_id) {
++              case(0):
++                      msk = FPM_RSTC_10G0_RESET;
++                      break;
++        case(1):
++            msk = FPM_RSTC_10G1_RESET;
++            break;
++              default:
++                      return -EINVAL;
++              }
++      } else {
++              switch (mac_id) {
++              case(0):
++                      msk = FPM_RSTC_1G0_RESET;
++                      break;
++              case(1):
++                      msk = FPM_RSTC_1G1_RESET;
++                      break;
++              case(2):
++                      msk = FPM_RSTC_1G2_RESET;
++                      break;
++              case(3):
++                      msk = FPM_RSTC_1G3_RESET;
++                      break;
++              case(4):
++                      msk = FPM_RSTC_1G4_RESET;
++                      break;
++        case (5):
++            msk = FPM_RSTC_1G5_RESET;
++            break;
++        case (6):
++            msk = FPM_RSTC_1G6_RESET;
++            break;
++        case (7):
++            msk = FPM_RSTC_1G7_RESET;
++            break;
++              default:
++                      return -EINVAL;
++              }
++      }
++      /* reset */
++      iowrite32be(msk, &fpm_rg->fm_rstc);
++      while ((ioread32be(&fpm_rg->fm_rstc) & msk) && --timeout)
++              udelay(10);
++
++      if (!timeout)
++              return -EBUSY;
++      return 0;
++}
++
++uint16_t fman_get_size_of_fifo(struct fman_bmi_regs *bmi_rg, uint8_t port_id)
++{
++      uint32_t tmp_reg;
++
++    if ((port_id > 63) || (port_id < 1))
++            return 0;
++
++      tmp_reg = ioread32be(&bmi_rg->fmbm_pfs[port_id - 1]);
++      return (uint16_t)((tmp_reg & BMI_FIFO_SIZE_MASK) + 1);
++}
++
++uint32_t fman_get_total_fifo_size(struct fman_bmi_regs *bmi_rg)
++{
++      uint32_t reg, res;
++
++      reg = ioread32be(&bmi_rg->fmbm_cfg1);
++      res = (reg >> BMI_CFG1_FIFO_SIZE_SHIFT) & 0x3ff;
++      return res * FMAN_BMI_FIFO_UNITS;
++}
++
++uint16_t fman_get_size_of_extra_fifo(struct fman_bmi_regs *bmi_rg,
++                                      uint8_t port_id)
++{
++      uint32_t tmp_reg;
++
++    if ((port_id > 63) || (port_id < 1))
++            return 0;
++
++      tmp_reg = ioread32be(&bmi_rg->fmbm_pfs[port_id-1]);
++      return (uint16_t)((tmp_reg & BMI_EXTRA_FIFO_SIZE_MASK) >>
++                              BMI_EXTRA_FIFO_SIZE_SHIFT);
++}
++
++void fman_set_size_of_fifo(struct fman_bmi_regs *bmi_rg,
++                              uint8_t port_id,
++                              uint32_t sz_fifo,
++                              uint32_t extra_sz_fifo)
++{
++      uint32_t tmp;
++
++      if ((port_id > 63) || (port_id < 1))
++              return;
++
++      /* calculate reg */
++      tmp = (uint32_t)((sz_fifo / FMAN_BMI_FIFO_UNITS - 1) |
++              ((extra_sz_fifo / FMAN_BMI_FIFO_UNITS) <<
++                              BMI_EXTRA_FIFO_SIZE_SHIFT));
++      iowrite32be(tmp, &bmi_rg->fmbm_pfs[port_id - 1]);
++}
++
++uint8_t fman_get_num_of_tasks(struct fman_bmi_regs *bmi_rg, uint8_t port_id)
++{
++      uint32_t tmp;
++
++    if ((port_id > 63) || (port_id < 1))
++        return 0;
++
++      tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
++      return (uint8_t)(((tmp & BMI_NUM_OF_TASKS_MASK) >>
++                              BMI_NUM_OF_TASKS_SHIFT) + 1);
++}
++
++uint8_t fman_get_num_extra_tasks(struct fman_bmi_regs *bmi_rg, uint8_t port_id)
++{
++      uint32_t tmp;
++
++    if ((port_id > 63) || (port_id < 1))
++        return 0;
++
++      tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
++      return (uint8_t)((tmp & BMI_NUM_OF_EXTRA_TASKS_MASK) >>
++                              BMI_EXTRA_NUM_OF_TASKS_SHIFT);
++}
++
++void fman_set_num_of_tasks(struct fman_bmi_regs *bmi_rg,
++                              uint8_t port_id,
++                              uint8_t num_tasks,
++                              uint8_t num_extra_tasks)
++{
++      uint32_t tmp;
++
++      if ((port_id > 63) || (port_id < 1))
++          return;
++
++      /* calculate reg */
++      tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]) &
++                      ~(BMI_NUM_OF_TASKS_MASK | BMI_NUM_OF_EXTRA_TASKS_MASK);
++      tmp |= (uint32_t)(((num_tasks - 1) << BMI_NUM_OF_TASKS_SHIFT) |
++                      (num_extra_tasks << BMI_EXTRA_NUM_OF_TASKS_SHIFT));
++      iowrite32be(tmp, &bmi_rg->fmbm_pp[port_id - 1]);
++}
++
++uint8_t fman_get_num_of_dmas(struct fman_bmi_regs *bmi_rg, uint8_t port_id)
++{
++      uint32_t tmp;
++
++    if ((port_id > 63) || (port_id < 1))
++            return 0;
++
++      tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
++      return (uint8_t)(((tmp & BMI_NUM_OF_DMAS_MASK) >>
++                      BMI_NUM_OF_DMAS_SHIFT) + 1);
++}
++
++uint8_t fman_get_num_extra_dmas(struct fman_bmi_regs *bmi_rg, uint8_t port_id)
++{
++      uint32_t tmp;
++
++      if ((port_id > 63) || (port_id < 1))
++              return 0;
++
++      tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
++      return (uint8_t)((tmp & BMI_NUM_OF_EXTRA_DMAS_MASK) >>
++                      BMI_EXTRA_NUM_OF_DMAS_SHIFT);
++}
++
++void fman_set_num_of_open_dmas(struct fman_bmi_regs *bmi_rg,
++                              uint8_t port_id,
++                              uint8_t num_open_dmas,
++                              uint8_t num_extra_open_dmas,
++                              uint8_t total_num_dmas)
++{
++      uint32_t tmp = 0;
++
++      if ((port_id > 63) || (port_id < 1))
++          return;
++
++      /* calculate reg */
++      tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]) &
++                      ~(BMI_NUM_OF_DMAS_MASK | BMI_NUM_OF_EXTRA_DMAS_MASK);
++      tmp |= (uint32_t)(((num_open_dmas-1) << BMI_NUM_OF_DMAS_SHIFT) |
++                      (num_extra_open_dmas << BMI_EXTRA_NUM_OF_DMAS_SHIFT));
++      iowrite32be(tmp, &bmi_rg->fmbm_pp[port_id - 1]);
++
++      /* update total num of DMA's with committed number of open DMAS,
++       * and max uncommitted pool. */
++    if (total_num_dmas)
++    {
++        tmp = ioread32be(&bmi_rg->fmbm_cfg2) & ~BMI_CFG2_DMAS_MASK;
++        tmp |= (uint32_t)(total_num_dmas - 1) << BMI_CFG2_DMAS_SHIFT;
++        iowrite32be(tmp, &bmi_rg->fmbm_cfg2);
++    }
++}
++
++void fman_set_vsp_window(struct fman_bmi_regs *bmi_rg,
++                                   uint8_t port_id,
++                                       uint8_t base_storage_profile,
++                                       uint8_t log2_num_of_profiles)
++{
++      uint32_t tmp = 0;
++      if ((port_id > 63) || (port_id < 1))
++          return;
++
++    tmp = ioread32be(&bmi_rg->fmbm_spliodn[port_id-1]);
++    tmp |= (uint32_t)((uint32_t)base_storage_profile & 0x3f) << 16;
++    tmp |= (uint32_t)log2_num_of_profiles << 28;
++    iowrite32be(tmp, &bmi_rg->fmbm_spliodn[port_id-1]);
++}
++
++void fman_set_congestion_group_pfc_priority(uint32_t *cpg_rg,
++                                            uint32_t congestion_group_id,
++                                            uint8_t priority_bit_map,
++                                            uint32_t reg_num)
++{
++      uint32_t offset, tmp = 0;
++
++    offset  = (congestion_group_id%4)*8;
++
++    tmp = ioread32be(&cpg_rg[reg_num]);
++    tmp &= ~(0xFF<<offset);
++    tmp |= (uint32_t)priority_bit_map << offset;
++
++    iowrite32be(tmp,&cpg_rg[reg_num]);
++}
++
++/*****************************************************************************/
++/*                      API Init unit functions                              */
++/*****************************************************************************/
++void fman_defconfig(struct fman_cfg *cfg, bool is_master)
++{
++    memset(cfg, 0, sizeof(struct fman_cfg));
++
++    cfg->catastrophic_err               = DEFAULT_CATASTROPHIC_ERR;
++    cfg->dma_err                        = DEFAULT_DMA_ERR;
++    cfg->halt_on_external_activ         = DEFAULT_HALT_ON_EXTERNAL_ACTIVATION;
++    cfg->halt_on_unrecov_ecc_err        = DEFAULT_HALT_ON_UNRECOVERABLE_ECC_ERROR;
++    cfg->en_iram_test_mode              = FALSE;
++    cfg->en_muram_test_mode             = FALSE;
++    cfg->external_ecc_rams_enable       = DEFAULT_EXTERNAL_ECC_RAMS_ENABLE;
++
++      if (!is_master)
++          return;
++
++    cfg->dma_aid_override               = DEFAULT_AID_OVERRIDE;
++    cfg->dma_aid_mode                   = DEFAULT_AID_MODE;
++    cfg->dma_comm_qtsh_clr_emer         = DEFAULT_DMA_COMM_Q_LOW;
++    cfg->dma_comm_qtsh_asrt_emer        = DEFAULT_DMA_COMM_Q_HIGH;
++    cfg->dma_cache_override             = DEFAULT_CACHE_OVERRIDE;
++    cfg->dma_cam_num_of_entries         = DEFAULT_DMA_CAM_NUM_OF_ENTRIES;
++    cfg->dma_dbg_cnt_mode               = DEFAULT_DMA_DBG_CNT_MODE;
++    cfg->dma_en_emergency               = DEFAULT_DMA_EN_EMERGENCY;
++    cfg->dma_sos_emergency              = DEFAULT_DMA_SOS_EMERGENCY;
++    cfg->dma_watchdog                   = DEFAULT_DMA_WATCHDOG;
++    cfg->dma_en_emergency_smoother      = DEFAULT_DMA_EN_EMERGENCY_SMOOTHER;
++    cfg->dma_emergency_switch_counter   = DEFAULT_DMA_EMERGENCY_SWITCH_COUNTER;
++    cfg->disp_limit_tsh                 = DEFAULT_DISP_LIMIT;
++    cfg->prs_disp_tsh                   = DEFAULT_PRS_DISP_TH;
++    cfg->plcr_disp_tsh                  = DEFAULT_PLCR_DISP_TH;
++    cfg->kg_disp_tsh                    = DEFAULT_KG_DISP_TH;
++    cfg->bmi_disp_tsh                   = DEFAULT_BMI_DISP_TH;
++    cfg->qmi_enq_disp_tsh               = DEFAULT_QMI_ENQ_DISP_TH;
++    cfg->qmi_deq_disp_tsh               = DEFAULT_QMI_DEQ_DISP_TH;
++    cfg->fm_ctl1_disp_tsh               = DEFAULT_FM_CTL1_DISP_TH;
++    cfg->fm_ctl2_disp_tsh               = DEFAULT_FM_CTL2_DISP_TH;
++ 
++      cfg->pedantic_dma                   = FALSE;
++      cfg->tnum_aging_period              = DEFAULT_TNUM_AGING_PERIOD;
++      cfg->dma_stop_on_bus_error          = FALSE;
++      cfg->qmi_deq_option_support         = FALSE;
++}
++
++void fman_regconfig(struct fman_rg *fman_rg, struct fman_cfg *cfg)
++{
++      uint32_t tmp_reg;
++
++    /* read the values from the registers as they are initialized by the HW with
++     * the required values.
++     */
++    tmp_reg = ioread32be(&fman_rg->bmi_rg->fmbm_cfg1);
++    cfg->total_fifo_size =
++        (((tmp_reg & BMI_TOTAL_FIFO_SIZE_MASK) >> BMI_CFG1_FIFO_SIZE_SHIFT) + 1) * FMAN_BMI_FIFO_UNITS;
++
++    tmp_reg = ioread32be(&fman_rg->bmi_rg->fmbm_cfg2);
++    cfg->total_num_of_tasks =
++        (uint8_t)(((tmp_reg & BMI_TOTAL_NUM_OF_TASKS_MASK) >> BMI_CFG2_TASKS_SHIFT) + 1);
++
++    tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmtr);
++    cfg->dma_comm_qtsh_asrt_emer = (uint8_t)(tmp_reg >> DMA_THRESH_COMMQ_SHIFT);
++
++    tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmhy);
++    cfg->dma_comm_qtsh_clr_emer  = (uint8_t)(tmp_reg >> DMA_THRESH_COMMQ_SHIFT);
++
++    tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmmr);
++    cfg->dma_cache_override      = (enum fman_dma_cache_override)((tmp_reg & DMA_MODE_CACHE_OR_MASK) >> DMA_MODE_CACHE_OR_SHIFT);
++    cfg->dma_cam_num_of_entries  = (uint8_t)((((tmp_reg & DMA_MODE_CEN_MASK) >> DMA_MODE_CEN_SHIFT) +1)*DMA_CAM_UNITS);
++    cfg->dma_aid_override        = (bool)((tmp_reg & DMA_MODE_AID_OR)? TRUE:FALSE);
++    cfg->dma_dbg_cnt_mode        = (enum fman_dma_dbg_cnt_mode)((tmp_reg & DMA_MODE_DBG_MASK) >> DMA_MODE_DBG_SHIFT);
++    cfg->dma_en_emergency        = (bool)((tmp_reg & DMA_MODE_EB)? TRUE : FALSE);
++
++    tmp_reg = ioread32be(&fman_rg->fpm_rg->fmfp_mxd);
++    cfg->disp_limit_tsh          = (uint8_t)((tmp_reg & FPM_DISP_LIMIT_MASK) >> FPM_DISP_LIMIT_SHIFT);
++
++    tmp_reg = ioread32be(&fman_rg->fpm_rg->fmfp_dist1);
++    cfg->prs_disp_tsh            = (uint8_t)((tmp_reg & FPM_THR1_PRS_MASK ) >> FPM_THR1_PRS_SHIFT);
++    cfg->plcr_disp_tsh           = (uint8_t)((tmp_reg & FPM_THR1_KG_MASK ) >> FPM_THR1_KG_SHIFT);
++    cfg->kg_disp_tsh             = (uint8_t)((tmp_reg & FPM_THR1_PLCR_MASK ) >> FPM_THR1_PLCR_SHIFT);
++    cfg->bmi_disp_tsh            = (uint8_t)((tmp_reg & FPM_THR1_BMI_MASK ) >> FPM_THR1_BMI_SHIFT);
++
++    tmp_reg = ioread32be(&fman_rg->fpm_rg->fmfp_dist2);
++    cfg->qmi_enq_disp_tsh        = (uint8_t)((tmp_reg & FPM_THR2_QMI_ENQ_MASK ) >> FPM_THR2_QMI_ENQ_SHIFT);
++    cfg->qmi_deq_disp_tsh        = (uint8_t)((tmp_reg & FPM_THR2_QMI_DEQ_MASK ) >> FPM_THR2_QMI_DEQ_SHIFT);
++    cfg->fm_ctl1_disp_tsh        = (uint8_t)((tmp_reg & FPM_THR2_FM_CTL1_MASK ) >> FPM_THR2_FM_CTL1_SHIFT);
++    cfg->fm_ctl2_disp_tsh        = (uint8_t)((tmp_reg & FPM_THR2_FM_CTL2_MASK ) >> FPM_THR2_FM_CTL2_SHIFT);
++
++    tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmsetr);
++    cfg->dma_sos_emergency       = tmp_reg;
++
++    tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmwcr);
++    cfg->dma_watchdog            = tmp_reg/cfg->clk_freq;
++
++    tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmemsr);
++    cfg->dma_en_emergency_smoother = (bool)((tmp_reg & DMA_EMSR_EMSTR_MASK)? TRUE : FALSE);
++    cfg->dma_emergency_switch_counter = (tmp_reg & DMA_EMSR_EMSTR_MASK);
++}
++
++void fman_reset(struct fman_fpm_regs *fpm_rg)
++{
++      iowrite32be(FPM_RSTC_FM_RESET, &fpm_rg->fm_rstc);
++}
++
++/**************************************************************************//**
++ @Function      FM_Init
++
++ @Description   Initializes the FM module
++
++ @Param[in]     h_Fm - FM module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++int fman_dma_init(struct fman_dma_regs *dma_rg, struct fman_cfg *cfg)
++{
++      uint32_t    tmp_reg;
++
++      /**********************/
++      /* Init DMA Registers */
++      /**********************/
++      /* clear status reg events */
++      /* oren - check!!!  */
++      tmp_reg = (DMA_STATUS_BUS_ERR | DMA_STATUS_READ_ECC |
++                      DMA_STATUS_SYSTEM_WRITE_ECC | DMA_STATUS_FM_WRITE_ECC);
++      iowrite32be(ioread32be(&dma_rg->fmdmsr) | tmp_reg,
++                      &dma_rg->fmdmsr);
++
++      /* configure mode register */
++      tmp_reg = 0;
++      tmp_reg |= cfg->dma_cache_override << DMA_MODE_CACHE_OR_SHIFT;
++      if (cfg->dma_aid_override)
++              tmp_reg |= DMA_MODE_AID_OR;
++      if (cfg->exceptions & FMAN_EX_DMA_BUS_ERROR)
++              tmp_reg |= DMA_MODE_BER;
++      if ((cfg->exceptions & FMAN_EX_DMA_SYSTEM_WRITE_ECC) |
++              (cfg->exceptions & FMAN_EX_DMA_READ_ECC) |
++              (cfg->exceptions & FMAN_EX_DMA_FM_WRITE_ECC))
++              tmp_reg |= DMA_MODE_ECC;
++      if (cfg->dma_stop_on_bus_error)
++              tmp_reg |= DMA_MODE_SBER;
++      if(cfg->dma_axi_dbg_num_of_beats)
++          tmp_reg |= (uint32_t)(DMA_MODE_AXI_DBG_MASK &
++                         ((cfg->dma_axi_dbg_num_of_beats - 1) << DMA_MODE_AXI_DBG_SHIFT));
++
++      if (cfg->dma_en_emergency) {
++              tmp_reg |= cfg->dma_emergency_bus_select;
++              tmp_reg |= cfg->dma_emergency_level << DMA_MODE_EMER_LVL_SHIFT;
++      if (cfg->dma_en_emergency_smoother)
++              iowrite32be(cfg->dma_emergency_switch_counter,
++                              &dma_rg->fmdmemsr);
++      }
++      tmp_reg |= ((cfg->dma_cam_num_of_entries / DMA_CAM_UNITS) - 1) <<
++                      DMA_MODE_CEN_SHIFT;
++      tmp_reg |= DMA_MODE_SECURE_PROT;
++      tmp_reg |= cfg->dma_dbg_cnt_mode << DMA_MODE_DBG_SHIFT;
++      tmp_reg |= cfg->dma_aid_mode << DMA_MODE_AID_MODE_SHIFT;
++
++      if (cfg->pedantic_dma)
++              tmp_reg |= DMA_MODE_EMER_READ;
++
++      iowrite32be(tmp_reg, &dma_rg->fmdmmr);
++
++      /* configure thresholds register */
++      tmp_reg = ((uint32_t)cfg->dma_comm_qtsh_asrt_emer <<
++                      DMA_THRESH_COMMQ_SHIFT) |
++                      ((uint32_t)cfg->dma_read_buf_tsh_asrt_emer <<
++                      DMA_THRESH_READ_INT_BUF_SHIFT) |
++                      ((uint32_t)cfg->dma_write_buf_tsh_asrt_emer);
++
++      iowrite32be(tmp_reg, &dma_rg->fmdmtr);
++
++      /* configure hysteresis register */
++      tmp_reg = ((uint32_t)cfg->dma_comm_qtsh_clr_emer <<
++              DMA_THRESH_COMMQ_SHIFT) |
++              ((uint32_t)cfg->dma_read_buf_tsh_clr_emer <<
++              DMA_THRESH_READ_INT_BUF_SHIFT) |
++              ((uint32_t)cfg->dma_write_buf_tsh_clr_emer);
++
++      iowrite32be(tmp_reg, &dma_rg->fmdmhy);
++
++      /* configure emergency threshold */
++      iowrite32be(cfg->dma_sos_emergency, &dma_rg->fmdmsetr);
++
++      /* configure Watchdog */
++      iowrite32be((cfg->dma_watchdog * cfg->clk_freq),
++                      &dma_rg->fmdmwcr);
++
++      iowrite32be(cfg->cam_base_addr, &dma_rg->fmdmebcr);
++
++      return 0;
++}
++
++int fman_fpm_init(struct fman_fpm_regs *fpm_rg, struct fman_cfg *cfg)
++{
++      uint32_t tmp_reg;
++      int i;
++
++      /**********************/
++      /* Init FPM Registers */
++      /**********************/
++      tmp_reg = (uint32_t)(cfg->disp_limit_tsh << FPM_DISP_LIMIT_SHIFT);
++      iowrite32be(tmp_reg, &fpm_rg->fmfp_mxd);
++
++      tmp_reg = (((uint32_t)cfg->prs_disp_tsh << FPM_THR1_PRS_SHIFT) |
++              ((uint32_t)cfg->kg_disp_tsh << FPM_THR1_KG_SHIFT) |
++              ((uint32_t)cfg->plcr_disp_tsh << FPM_THR1_PLCR_SHIFT) |
++              ((uint32_t)cfg->bmi_disp_tsh << FPM_THR1_BMI_SHIFT));
++      iowrite32be(tmp_reg, &fpm_rg->fmfp_dist1);
++
++      tmp_reg = (((uint32_t)cfg->qmi_enq_disp_tsh << FPM_THR2_QMI_ENQ_SHIFT) |
++              ((uint32_t)cfg->qmi_deq_disp_tsh << FPM_THR2_QMI_DEQ_SHIFT) |
++              ((uint32_t)cfg->fm_ctl1_disp_tsh << FPM_THR2_FM_CTL1_SHIFT) |
++              ((uint32_t)cfg->fm_ctl2_disp_tsh << FPM_THR2_FM_CTL2_SHIFT));
++      iowrite32be(tmp_reg, &fpm_rg->fmfp_dist2);
++
++      /* define exceptions and error behavior */
++      tmp_reg = 0;
++      /* Clear events */
++      tmp_reg |= (FPM_EV_MASK_STALL | FPM_EV_MASK_DOUBLE_ECC |
++              FPM_EV_MASK_SINGLE_ECC);
++      /* enable interrupts */
++      if (cfg->exceptions & FMAN_EX_FPM_STALL_ON_TASKS)
++              tmp_reg |= FPM_EV_MASK_STALL_EN;
++      if (cfg->exceptions & FMAN_EX_FPM_SINGLE_ECC)
++              tmp_reg |= FPM_EV_MASK_SINGLE_ECC_EN;
++      if (cfg->exceptions & FMAN_EX_FPM_DOUBLE_ECC)
++              tmp_reg |= FPM_EV_MASK_DOUBLE_ECC_EN;
++      tmp_reg |= (cfg->catastrophic_err  << FPM_EV_MASK_CAT_ERR_SHIFT);
++      tmp_reg |= (cfg->dma_err << FPM_EV_MASK_DMA_ERR_SHIFT);
++      if (!cfg->halt_on_external_activ)
++              tmp_reg |= FPM_EV_MASK_EXTERNAL_HALT;
++      if (!cfg->halt_on_unrecov_ecc_err)
++              tmp_reg |= FPM_EV_MASK_ECC_ERR_HALT;
++      iowrite32be(tmp_reg, &fpm_rg->fmfp_ee);
++
++      /* clear all fmCtls event registers */
++      for (i = 0; i < cfg->num_of_fman_ctrl_evnt_regs; i++)
++              iowrite32be(0xFFFFFFFF, &fpm_rg->fmfp_cev[i]);
++
++      /* RAM ECC -  enable and clear events*/
++      /* first we need to clear all parser memory,
++       * as it is uninitialized and may cause ECC errors */
++      /* event bits */
++      tmp_reg = (FPM_RAM_MURAM_ECC | FPM_RAM_IRAM_ECC);
++      /* Rams enable not effected by RCR bit, but by a COP configuration */
++      if (cfg->external_ecc_rams_enable)
++              tmp_reg |= FPM_RAM_RAMS_ECC_EN_SRC_SEL;
++
++      /* enable test mode */
++      if (cfg->en_muram_test_mode)
++              tmp_reg |= FPM_RAM_MURAM_TEST_ECC;
++      if (cfg->en_iram_test_mode)
++              tmp_reg |= FPM_RAM_IRAM_TEST_ECC;
++      iowrite32be(tmp_reg, &fpm_rg->fm_rcr);
++
++      tmp_reg = 0;
++      if (cfg->exceptions & FMAN_EX_IRAM_ECC) {
++              tmp_reg |= FPM_IRAM_ECC_ERR_EX_EN;
++              fman_enable_rams_ecc(fpm_rg);
++      }
++      if (cfg->exceptions & FMAN_EX_NURAM_ECC) {
++              tmp_reg |= FPM_MURAM_ECC_ERR_EX_EN;
++              fman_enable_rams_ecc(fpm_rg);
++      }
++      iowrite32be(tmp_reg, &fpm_rg->fm_rie);
++
++      return 0;
++}
++
++int fman_bmi_init(struct fman_bmi_regs *bmi_rg, struct fman_cfg *cfg)
++{
++      uint32_t tmp_reg;
++
++      /**********************/
++      /* Init BMI Registers */
++      /**********************/
++
++      /* define common resources */
++      tmp_reg = cfg->fifo_base_addr;
++      tmp_reg = tmp_reg / BMI_FIFO_ALIGN;
++
++      tmp_reg |= ((cfg->total_fifo_size / FMAN_BMI_FIFO_UNITS - 1) <<
++                      BMI_CFG1_FIFO_SIZE_SHIFT);
++      iowrite32be(tmp_reg, &bmi_rg->fmbm_cfg1);
++
++      tmp_reg = ((uint32_t)(cfg->total_num_of_tasks - 1) <<
++                      BMI_CFG2_TASKS_SHIFT);
++      /* num of DMA's will be dynamically updated when each port is set */
++      iowrite32be(tmp_reg, &bmi_rg->fmbm_cfg2);
++
++      /* define unmaskable exceptions, enable and clear events */
++      tmp_reg = 0;
++      iowrite32be(BMI_ERR_INTR_EN_LIST_RAM_ECC |
++                      BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC |
++                      BMI_ERR_INTR_EN_STATISTICS_RAM_ECC |
++                      BMI_ERR_INTR_EN_DISPATCH_RAM_ECC,
++                      &bmi_rg->fmbm_ievr);
++
++      if (cfg->exceptions & FMAN_EX_BMI_LIST_RAM_ECC)
++              tmp_reg |= BMI_ERR_INTR_EN_LIST_RAM_ECC;
++      if (cfg->exceptions & FMAN_EX_BMI_PIPELINE_ECC)
++              tmp_reg |= BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC;
++      if (cfg->exceptions & FMAN_EX_BMI_STATISTICS_RAM_ECC)
++              tmp_reg |= BMI_ERR_INTR_EN_STATISTICS_RAM_ECC;
++      if (cfg->exceptions & FMAN_EX_BMI_DISPATCH_RAM_ECC)
++              tmp_reg |= BMI_ERR_INTR_EN_DISPATCH_RAM_ECC;
++      iowrite32be(tmp_reg, &bmi_rg->fmbm_ier);
++
++      return 0;
++}
++
++int fman_qmi_init(struct fman_qmi_regs *qmi_rg, struct fman_cfg *cfg)
++{
++      uint32_t tmp_reg;
++      uint16_t period_in_fm_clocks;
++      uint8_t remainder;
++      /**********************/
++      /* Init QMI Registers */
++      /**********************/
++      /* Clear error interrupt events */
++
++      iowrite32be(QMI_ERR_INTR_EN_DOUBLE_ECC | QMI_ERR_INTR_EN_DEQ_FROM_DEF,
++                      &qmi_rg->fmqm_eie);
++      tmp_reg = 0;
++      if (cfg->exceptions & FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID)
++              tmp_reg |= QMI_ERR_INTR_EN_DEQ_FROM_DEF;
++      if (cfg->exceptions & FMAN_EX_QMI_DOUBLE_ECC)
++              tmp_reg |= QMI_ERR_INTR_EN_DOUBLE_ECC;
++      /* enable events */
++      iowrite32be(tmp_reg, &qmi_rg->fmqm_eien);
++
++      if (cfg->tnum_aging_period) {
++              /* tnum_aging_period is in units of usec, p_FmClockFreq in Mhz */
++              period_in_fm_clocks = (uint16_t)
++                              (cfg->tnum_aging_period * cfg->clk_freq);
++              /* period_in_fm_clocks must be a 64 multiply */
++              remainder = (uint8_t)(period_in_fm_clocks % 64);
++              if (remainder)
++                      tmp_reg = (uint32_t)((period_in_fm_clocks / 64) + 1);
++              else{
++                      tmp_reg = (uint32_t)(period_in_fm_clocks / 64);
++                      if (!tmp_reg)
++                              tmp_reg = 1;
++              }
++              tmp_reg <<= QMI_TAPC_TAP;
++              iowrite32be(tmp_reg, &qmi_rg->fmqm_tapc);
++      }
++      tmp_reg = 0;
++      /* Clear interrupt events */
++      iowrite32be(QMI_INTR_EN_SINGLE_ECC, &qmi_rg->fmqm_ie);
++      if (cfg->exceptions & FMAN_EX_QMI_SINGLE_ECC)
++              tmp_reg |= QMI_INTR_EN_SINGLE_ECC;
++      /* enable events */
++      iowrite32be(tmp_reg, &qmi_rg->fmqm_ien);
++
++      return 0;
++}
++
++int fman_enable(struct fman_rg *fman_rg, struct fman_cfg *cfg)
++{
++      uint32_t cfg_reg = 0;
++
++      /**********************/
++      /* Enable all modules */
++      /**********************/
++      /* clear & enable global counters  - calculate reg and save for later,
++      because it's the same reg for QMI enable */
++      cfg_reg = QMI_CFG_EN_COUNTERS;
++      if (cfg->qmi_deq_option_support)
++              cfg_reg |= (uint32_t)(((cfg->qmi_def_tnums_thresh) << 8) |
++                              (uint32_t)cfg->qmi_def_tnums_thresh);
++
++      iowrite32be(BMI_INIT_START, &fman_rg->bmi_rg->fmbm_init);
++      iowrite32be(cfg_reg | QMI_CFG_ENQ_EN | QMI_CFG_DEQ_EN,
++                      &fman_rg->qmi_rg->fmqm_gc);
++
++      return 0;
++}
++
++void fman_free_resources(struct fman_rg *fman_rg)
++{
++      /* disable BMI and QMI */
++      iowrite32be(0, &fman_rg->bmi_rg->fmbm_init);
++      iowrite32be(0, &fman_rg->qmi_rg->fmqm_gc);
++
++      /* release BMI resources */
++      iowrite32be(0, &fman_rg->bmi_rg->fmbm_cfg2);
++      iowrite32be(0, &fman_rg->bmi_rg->fmbm_cfg1);
++
++      /* disable ECC */
++      iowrite32be(0, &fman_rg->fpm_rg->fm_rcr);
++}
++
++/****************************************************/
++/*       API Run-time Control uint functions        */
++/****************************************************/
++uint32_t fman_get_normal_pending(struct fman_fpm_regs *fpm_rg)
++{
++      return ioread32be(&fpm_rg->fm_npi);
++}
++
++uint32_t fman_get_controller_event(struct fman_fpm_regs *fpm_rg, uint8_t reg_id)
++{
++      uint32_t event;
++
++      event = ioread32be(&fpm_rg->fmfp_fcev[reg_id]) &
++                      ioread32be(&fpm_rg->fmfp_cee[reg_id]);
++      iowrite32be(event, &fpm_rg->fmfp_cev[reg_id]);
++
++      return event;
++}
++
++uint32_t fman_get_error_pending(struct fman_fpm_regs *fpm_rg)
++{
++      return ioread32be(&fpm_rg->fm_epi);
++}
++
++void fman_set_ports_bandwidth(struct fman_bmi_regs *bmi_rg, uint8_t *weights)
++{
++      int i;
++      uint8_t shift;
++      uint32_t tmp = 0;
++
++      for (i = 0; i < 64; i++) {
++              if (weights[i] > 1) { /* no need to write 1 since it is 0 */
++                      /* Add this port to tmp_reg */
++                      /* (each 8 ports result in one register)*/
++                      shift = (uint8_t)(32 - 4 * ((i % 8) + 1));
++                      tmp |= ((weights[i] - 1) << shift);
++              }
++              if (i % 8 == 7) { /* last in this set */
++                      iowrite32be(tmp, &bmi_rg->fmbm_arb[i / 8]);
++                      tmp = 0;
++              }
++      }
++}
++
++void fman_enable_rams_ecc(struct fman_fpm_regs *fpm_rg)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&fpm_rg->fm_rcr);
++      if (tmp & FPM_RAM_RAMS_ECC_EN_SRC_SEL)
++              iowrite32be(tmp | FPM_RAM_IRAM_ECC_EN,
++                              &fpm_rg->fm_rcr);
++      else
++              iowrite32be(tmp | FPM_RAM_RAMS_ECC_EN |
++                              FPM_RAM_IRAM_ECC_EN,
++                              &fpm_rg->fm_rcr);
++}
++
++void fman_disable_rams_ecc(struct fman_fpm_regs *fpm_rg)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&fpm_rg->fm_rcr);
++      if (tmp & FPM_RAM_RAMS_ECC_EN_SRC_SEL)
++              iowrite32be(tmp & ~FPM_RAM_IRAM_ECC_EN,
++                              &fpm_rg->fm_rcr);
++      else
++              iowrite32be(tmp & ~(FPM_RAM_RAMS_ECC_EN | FPM_RAM_IRAM_ECC_EN),
++                              &fpm_rg->fm_rcr);
++}
++
++int fman_set_exception(struct fman_rg *fman_rg,
++                      enum fman_exceptions exception,
++                      bool enable)
++{
++      uint32_t tmp;
++
++      switch (exception) {
++      case(E_FMAN_EX_DMA_BUS_ERROR):
++              tmp = ioread32be(&fman_rg->dma_rg->fmdmmr);
++              if (enable)
++                      tmp |= DMA_MODE_BER;
++              else
++                      tmp &= ~DMA_MODE_BER;
++              /* disable bus error */
++              iowrite32be(tmp, &fman_rg->dma_rg->fmdmmr);
++              break;
++      case(E_FMAN_EX_DMA_READ_ECC):
++      case(E_FMAN_EX_DMA_SYSTEM_WRITE_ECC):
++      case(E_FMAN_EX_DMA_FM_WRITE_ECC):
++              tmp = ioread32be(&fman_rg->dma_rg->fmdmmr);
++              if (enable)
++                      tmp |= DMA_MODE_ECC;
++              else
++                      tmp &= ~DMA_MODE_ECC;
++              iowrite32be(tmp, &fman_rg->dma_rg->fmdmmr);
++              break;
++      case(E_FMAN_EX_FPM_STALL_ON_TASKS):
++              tmp = ioread32be(&fman_rg->fpm_rg->fmfp_ee);
++              if (enable)
++                      tmp |= FPM_EV_MASK_STALL_EN;
++              else
++                      tmp &= ~FPM_EV_MASK_STALL_EN;
++              iowrite32be(tmp, &fman_rg->fpm_rg->fmfp_ee);
++              break;
++      case(E_FMAN_EX_FPM_SINGLE_ECC):
++              tmp = ioread32be(&fman_rg->fpm_rg->fmfp_ee);
++              if (enable)
++                      tmp |= FPM_EV_MASK_SINGLE_ECC_EN;
++              else
++                      tmp &= ~FPM_EV_MASK_SINGLE_ECC_EN;
++              iowrite32be(tmp, &fman_rg->fpm_rg->fmfp_ee);
++              break;
++      case(E_FMAN_EX_FPM_DOUBLE_ECC):
++              tmp = ioread32be(&fman_rg->fpm_rg->fmfp_ee);
++              if (enable)
++                      tmp |= FPM_EV_MASK_DOUBLE_ECC_EN;
++              else
++                      tmp &= ~FPM_EV_MASK_DOUBLE_ECC_EN;
++              iowrite32be(tmp, &fman_rg->fpm_rg->fmfp_ee);
++              break;
++      case(E_FMAN_EX_QMI_SINGLE_ECC):
++              tmp = ioread32be(&fman_rg->qmi_rg->fmqm_ien);
++              if (enable)
++                      tmp |= QMI_INTR_EN_SINGLE_ECC;
++              else
++                      tmp &= ~QMI_INTR_EN_SINGLE_ECC;
++              iowrite32be(tmp, &fman_rg->qmi_rg->fmqm_ien);
++              break;
++      case(E_FMAN_EX_QMI_DOUBLE_ECC):
++              tmp = ioread32be(&fman_rg->qmi_rg->fmqm_eien);
++              if (enable)
++                      tmp |= QMI_ERR_INTR_EN_DOUBLE_ECC;
++              else
++                      tmp &= ~QMI_ERR_INTR_EN_DOUBLE_ECC;
++              iowrite32be(tmp, &fman_rg->qmi_rg->fmqm_eien);
++              break;
++      case(E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID):
++              tmp = ioread32be(&fman_rg->qmi_rg->fmqm_eien);
++              if (enable)
++                      tmp |= QMI_ERR_INTR_EN_DEQ_FROM_DEF;
++              else
++                      tmp &= ~QMI_ERR_INTR_EN_DEQ_FROM_DEF;
++              iowrite32be(tmp, &fman_rg->qmi_rg->fmqm_eien);
++              break;
++      case(E_FMAN_EX_BMI_LIST_RAM_ECC):
++              tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier);
++              if (enable)
++                      tmp |= BMI_ERR_INTR_EN_LIST_RAM_ECC;
++              else
++                      tmp &= ~BMI_ERR_INTR_EN_LIST_RAM_ECC;
++              iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier);
++              break;
++      case(E_FMAN_EX_BMI_STORAGE_PROFILE_ECC):
++              tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier);
++              if (enable)
++                      tmp |= BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC;
++              else
++                      tmp &= ~BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC;
++              iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier);
++              break;
++      case(E_FMAN_EX_BMI_STATISTICS_RAM_ECC):
++              tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier);
++              if (enable)
++                      tmp |= BMI_ERR_INTR_EN_STATISTICS_RAM_ECC;
++              else
++                      tmp &= ~BMI_ERR_INTR_EN_STATISTICS_RAM_ECC;
++              iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier);
++              break;
++      case(E_FMAN_EX_BMI_DISPATCH_RAM_ECC):
++              tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier);
++              if (enable)
++                      tmp |= BMI_ERR_INTR_EN_DISPATCH_RAM_ECC;
++              else
++                      tmp &= ~BMI_ERR_INTR_EN_DISPATCH_RAM_ECC;
++              iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier);
++              break;
++      case(E_FMAN_EX_IRAM_ECC):
++              tmp = ioread32be(&fman_rg->fpm_rg->fm_rie);
++              if (enable) {
++                      /* enable ECC if not enabled */
++                      fman_enable_rams_ecc(fman_rg->fpm_rg);
++                      /* enable ECC interrupts */
++                      tmp |= FPM_IRAM_ECC_ERR_EX_EN;
++              } else {
++                      /* ECC mechanism may be disabled,
++                       * depending on driver status  */
++                      fman_disable_rams_ecc(fman_rg->fpm_rg);
++                      tmp &= ~FPM_IRAM_ECC_ERR_EX_EN;
++              }
++              iowrite32be(tmp, &fman_rg->fpm_rg->fm_rie);
++              break;
++      case(E_FMAN_EX_MURAM_ECC):
++              tmp = ioread32be(&fman_rg->fpm_rg->fm_rie);
++              if (enable) {
++                      /* enable ECC if not enabled */
++                      fman_enable_rams_ecc(fman_rg->fpm_rg);
++                      /* enable ECC interrupts */
++                      tmp |= FPM_MURAM_ECC_ERR_EX_EN;
++              } else {
++                      /* ECC mechanism may be disabled,
++                       * depending on driver status  */
++                      fman_disable_rams_ecc(fman_rg->fpm_rg);
++                      tmp &= ~FPM_MURAM_ECC_ERR_EX_EN;
++              }
++              iowrite32be(tmp, &fman_rg->fpm_rg->fm_rie);
++              break;
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++
++void fman_get_revision(struct fman_fpm_regs *fpm_rg,
++                      uint8_t *major,
++                      uint8_t *minor)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&fpm_rg->fm_ip_rev_1);
++      *major = (uint8_t)((tmp & FPM_REV1_MAJOR_MASK) >> FPM_REV1_MAJOR_SHIFT);
++      *minor = (uint8_t)((tmp & FPM_REV1_MINOR_MASK) >> FPM_REV1_MINOR_SHIFT);
++
++}
++
++uint32_t fman_get_counter(struct fman_rg *fman_rg,
++                              enum fman_counters reg_name)
++{
++      uint32_t ret_val;
++
++      switch (reg_name) {
++      case(E_FMAN_COUNTERS_ENQ_TOTAL_FRAME):
++              ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_etfc);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_TOTAL_FRAME):
++              ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dtfc);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_0):
++              ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc0);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_1):
++              ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc1);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_2):
++              ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc2);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_3):
++              ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc3);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_FROM_DEFAULT):
++              ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dfdc);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_FROM_CONTEXT):
++              ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dfcc);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_FROM_FD):
++              ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dffc);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_CONFIRM):
++              ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dcc);
++              break;
++      default:
++              ret_val = 0;
++      }
++      return ret_val;
++}
++
++int fman_modify_counter(struct fman_rg *fman_rg,
++                      enum fman_counters reg_name,
++                      uint32_t val)
++{
++      /* When applicable (when there is an 'enable counters' bit,
++       * check that counters are enabled */
++      switch (reg_name) {
++      case(E_FMAN_COUNTERS_ENQ_TOTAL_FRAME):
++      case(E_FMAN_COUNTERS_DEQ_TOTAL_FRAME):
++      case(E_FMAN_COUNTERS_DEQ_0):
++      case(E_FMAN_COUNTERS_DEQ_1):
++      case(E_FMAN_COUNTERS_DEQ_2):
++      case(E_FMAN_COUNTERS_DEQ_3):
++      case(E_FMAN_COUNTERS_DEQ_FROM_DEFAULT):
++      case(E_FMAN_COUNTERS_DEQ_FROM_CONTEXT):
++      case(E_FMAN_COUNTERS_DEQ_FROM_FD):
++      case(E_FMAN_COUNTERS_DEQ_CONFIRM):
++              if (!(ioread32be(&fman_rg->qmi_rg->fmqm_gc) &
++                              QMI_CFG_EN_COUNTERS))
++                      return -EINVAL;
++              break;
++      default:
++              break;
++      }
++      /* Set counter */
++      switch (reg_name) {
++      case(E_FMAN_COUNTERS_ENQ_TOTAL_FRAME):
++              iowrite32be(val, &fman_rg->qmi_rg->fmqm_etfc);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_TOTAL_FRAME):
++              iowrite32be(val, &fman_rg->qmi_rg->fmqm_dtfc);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_0):
++              iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc0);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_1):
++              iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc1);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_2):
++              iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc2);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_3):
++              iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc3);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_FROM_DEFAULT):
++              iowrite32be(val, &fman_rg->qmi_rg->fmqm_dfdc);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_FROM_CONTEXT):
++              iowrite32be(val, &fman_rg->qmi_rg->fmqm_dfcc);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_FROM_FD):
++              iowrite32be(val, &fman_rg->qmi_rg->fmqm_dffc);
++              break;
++      case(E_FMAN_COUNTERS_DEQ_CONFIRM):
++              iowrite32be(val, &fman_rg->qmi_rg->fmqm_dcc);
++              break;
++      case(E_FMAN_COUNTERS_SEMAPHOR_ENTRY_FULL_REJECT):
++              iowrite32be(val, &fman_rg->dma_rg->fmdmsefrc);
++              break;
++      case(E_FMAN_COUNTERS_SEMAPHOR_QUEUE_FULL_REJECT):
++              iowrite32be(val, &fman_rg->dma_rg->fmdmsqfrc);
++              break;
++      case(E_FMAN_COUNTERS_SEMAPHOR_SYNC_REJECT):
++              iowrite32be(val, &fman_rg->dma_rg->fmdmssrc);
++              break;
++      default:
++              break;
++      }
++      return 0;
++}
++
++void fman_set_dma_emergency(struct fman_dma_regs *dma_rg,
++                              bool is_write,
++                              bool enable)
++{
++      uint32_t msk;
++
++      msk = (uint32_t)(is_write ? DMA_MODE_EMER_WRITE : DMA_MODE_EMER_READ);
++
++      if (enable)
++              iowrite32be(ioread32be(&dma_rg->fmdmmr) | msk,
++                              &dma_rg->fmdmmr);
++      else /* disable */
++              iowrite32be(ioread32be(&dma_rg->fmdmmr) & ~msk,
++                              &dma_rg->fmdmmr);
++}
++
++void fman_set_dma_ext_bus_pri(struct fman_dma_regs *dma_rg, uint32_t pri)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&dma_rg->fmdmmr) |
++                      (pri << DMA_MODE_BUS_PRI_SHIFT);
++
++      iowrite32be(tmp, &dma_rg->fmdmmr);
++}
++
++uint32_t fman_get_dma_status(struct fman_dma_regs *dma_rg)
++{
++      return ioread32be(&dma_rg->fmdmsr);
++}
++
++void fman_force_intr(struct fman_rg *fman_rg,
++              enum fman_exceptions exception)
++{
++      switch (exception) {
++      case E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID:
++              iowrite32be(QMI_ERR_INTR_EN_DEQ_FROM_DEF,
++                              &fman_rg->qmi_rg->fmqm_eif);
++              break;
++      case E_FMAN_EX_QMI_SINGLE_ECC:
++              iowrite32be(QMI_INTR_EN_SINGLE_ECC,
++                              &fman_rg->qmi_rg->fmqm_if);
++              break;
++      case E_FMAN_EX_QMI_DOUBLE_ECC:
++              iowrite32be(QMI_ERR_INTR_EN_DOUBLE_ECC,
++                              &fman_rg->qmi_rg->fmqm_eif);
++              break;
++      case E_FMAN_EX_BMI_LIST_RAM_ECC:
++              iowrite32be(BMI_ERR_INTR_EN_LIST_RAM_ECC,
++                              &fman_rg->bmi_rg->fmbm_ifr);
++              break;
++      case E_FMAN_EX_BMI_STORAGE_PROFILE_ECC:
++              iowrite32be(BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC,
++                              &fman_rg->bmi_rg->fmbm_ifr);
++              break;
++      case E_FMAN_EX_BMI_STATISTICS_RAM_ECC:
++              iowrite32be(BMI_ERR_INTR_EN_STATISTICS_RAM_ECC,
++                              &fman_rg->bmi_rg->fmbm_ifr);
++              break;
++      case E_FMAN_EX_BMI_DISPATCH_RAM_ECC:
++              iowrite32be(BMI_ERR_INTR_EN_DISPATCH_RAM_ECC,
++                              &fman_rg->bmi_rg->fmbm_ifr);
++              break;
++      default:
++              break;
++      }
++}
++
++bool fman_is_qmi_halt_not_busy_state(struct fman_qmi_regs *qmi_rg)
++{
++      return (bool)!!(ioread32be(&qmi_rg->fmqm_gs) & QMI_GS_HALT_NOT_BUSY);
++}
++void fman_resume(struct fman_fpm_regs *fpm_rg)
++{
++      uint32_t tmp;
++
++      tmp = ioread32be(&fpm_rg->fmfp_ee);
++      /* clear tmp_reg event bits in order not to clear standing events */
++      tmp &= ~(FPM_EV_MASK_DOUBLE_ECC |
++                      FPM_EV_MASK_STALL |
++                      FPM_EV_MASK_SINGLE_ECC);
++      tmp |= FPM_EV_MASK_RELEASE_FM;
++
++      iowrite32be(tmp, &fpm_rg->fmfp_ee);
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_common.h
+@@ -0,0 +1,1214 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_common.h
++
++ @Description   FM internal structures and definitions.
++*//***************************************************************************/
++#ifndef __FM_COMMON_H
++#define __FM_COMMON_H
++
++#include "error_ext.h"
++#include "std_ext.h"
++#include "fm_pcd_ext.h"
++#include "fm_ext.h"
++#include "fm_port_ext.h"
++
++
++#define e_FM_PORT_TYPE_OH_HOST_COMMAND      e_FM_PORT_TYPE_DUMMY
++
++#define CLS_PLAN_NUM_PER_GRP                        8
++
++#define IP_OFFLOAD_PACKAGE_NUMBER                   106
++#define CAPWAP_OFFLOAD_PACKAGE_NUMBER               108
++#define IS_OFFLOAD_PACKAGE(num) ((num == IP_OFFLOAD_PACKAGE_NUMBER) || (num == CAPWAP_OFFLOAD_PACKAGE_NUMBER))
++
++
++
++/**************************************************************************//**
++ @Description       Modules registers offsets
++*//***************************************************************************/
++#define FM_MM_MURAM             0x00000000
++#define FM_MM_BMI               0x00080000
++#define FM_MM_QMI               0x00080400
++#define FM_MM_PRS               0x000c7000
++#define FM_MM_KG                0x000C1000
++#define FM_MM_DMA               0x000C2000
++#define FM_MM_FPM               0x000C3000
++#define FM_MM_PLCR              0x000C0000
++#define FM_MM_IMEM              0x000C4000
++#define FM_MM_CGP               0x000DB000
++#define FM_MM_TRB(i)            (0x000D0200 + 0x400 * (i))
++#if (DPAA_VERSION >= 11)
++#define FM_MM_SP                0x000dc000
++#endif /* (DPAA_VERSION >= 11) */
++
++
++/**************************************************************************//**
++ @Description   Enum for inter-module interrupts registration
++*//***************************************************************************/
++typedef enum e_FmEventModules{
++    e_FM_MOD_PRS,                   /**< Parser event */
++    e_FM_MOD_KG,                    /**< Keygen event */
++    e_FM_MOD_PLCR,                  /**< Policer event */
++    e_FM_MOD_10G_MAC,               /**< 10G MAC event */
++    e_FM_MOD_1G_MAC,                /**< 1G MAC event */
++    e_FM_MOD_TMR,                   /**< Timer event */
++    e_FM_MOD_FMAN_CTRL,             /**< FMAN Controller  Timer event */
++    e_FM_MOD_MACSEC,
++    e_FM_MOD_DUMMY_LAST
++} e_FmEventModules;
++
++/**************************************************************************//**
++ @Description   Enum for interrupts types
++*//***************************************************************************/
++typedef enum e_FmIntrType {
++    e_FM_INTR_TYPE_ERR,
++    e_FM_INTR_TYPE_NORMAL
++} e_FmIntrType;
++
++/**************************************************************************//**
++ @Description   Enum for inter-module interrupts registration
++*//***************************************************************************/
++typedef enum e_FmInterModuleEvent
++{
++    e_FM_EV_PRS = 0,                /**< Parser event */
++    e_FM_EV_ERR_PRS,                /**< Parser error event */
++    e_FM_EV_KG,                     /**< Keygen event */
++    e_FM_EV_ERR_KG,                 /**< Keygen error event */
++    e_FM_EV_PLCR,                   /**< Policer event */
++    e_FM_EV_ERR_PLCR,               /**< Policer error event */
++    e_FM_EV_ERR_10G_MAC0,           /**< 10G MAC 0 error event */
++    e_FM_EV_ERR_10G_MAC1,           /**< 10G MAC 1 error event */
++    e_FM_EV_ERR_1G_MAC0,            /**< 1G MAC 0 error event */
++    e_FM_EV_ERR_1G_MAC1,            /**< 1G MAC 1 error event */
++    e_FM_EV_ERR_1G_MAC2,            /**< 1G MAC 2 error event */
++    e_FM_EV_ERR_1G_MAC3,            /**< 1G MAC 3 error event */
++    e_FM_EV_ERR_1G_MAC4,            /**< 1G MAC 4 error event */
++    e_FM_EV_ERR_1G_MAC5,            /**< 1G MAC 5 error event */
++    e_FM_EV_ERR_1G_MAC6,            /**< 1G MAC 6 error event */
++    e_FM_EV_ERR_1G_MAC7,            /**< 1G MAC 7 error event */
++    e_FM_EV_ERR_MACSEC_MAC0,
++    e_FM_EV_TMR,                    /**< Timer event */
++    e_FM_EV_10G_MAC0,               /**< 10G MAC 0 event (Magic packet detection)*/
++    e_FM_EV_10G_MAC1,               /**< 10G MAC 1 event (Magic packet detection)*/
++    e_FM_EV_1G_MAC0,                /**< 1G MAC 0 event (Magic packet detection)*/
++    e_FM_EV_1G_MAC1,                /**< 1G MAC 1 event (Magic packet detection)*/
++    e_FM_EV_1G_MAC2,                /**< 1G MAC 2 (Magic packet detection)*/
++    e_FM_EV_1G_MAC3,                /**< 1G MAC 3 (Magic packet detection)*/
++    e_FM_EV_1G_MAC4,                /**< 1G MAC 4 (Magic packet detection)*/
++    e_FM_EV_1G_MAC5,                /**< 1G MAC 5 (Magic packet detection)*/
++    e_FM_EV_1G_MAC6,                /**< 1G MAC 6 (Magic packet detection)*/
++    e_FM_EV_1G_MAC7,                /**< 1G MAC 7 (Magic packet detection)*/
++    e_FM_EV_MACSEC_MAC0,            /**< MACSEC MAC 0 event */
++    e_FM_EV_FMAN_CTRL_0,            /**< Fman controller event 0 */
++    e_FM_EV_FMAN_CTRL_1,            /**< Fman controller event 1 */
++    e_FM_EV_FMAN_CTRL_2,            /**< Fman controller event 2 */
++    e_FM_EV_FMAN_CTRL_3,            /**< Fman controller event 3 */
++    e_FM_EV_DUMMY_LAST
++} e_FmInterModuleEvent;
++
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(push,1)
++#endif /* defined(__MWERKS__) && ... */
++
++/**************************************************************************//**
++ @Description   PCD KG scheme registers
++*//***************************************************************************/
++typedef _Packed struct t_FmPcdPlcrProfileRegs {
++    volatile uint32_t fmpl_pemode;      /* 0x090 FMPL_PEMODE - FM Policer Profile Entry Mode*/
++    volatile uint32_t fmpl_pegnia;      /* 0x094 FMPL_PEGNIA - FM Policer Profile Entry GREEN Next Invoked Action*/
++    volatile uint32_t fmpl_peynia;      /* 0x098 FMPL_PEYNIA - FM Policer Profile Entry YELLOW Next Invoked Action*/
++    volatile uint32_t fmpl_pernia;      /* 0x09C FMPL_PERNIA - FM Policer Profile Entry RED Next Invoked Action*/
++    volatile uint32_t fmpl_pecir;       /* 0x0A0 FMPL_PECIR  - FM Policer Profile Entry Committed Information Rate*/
++    volatile uint32_t fmpl_pecbs;       /* 0x0A4 FMPL_PECBS  - FM Policer Profile Entry Committed Burst Size*/
++    volatile uint32_t fmpl_pepepir_eir; /* 0x0A8 FMPL_PEPIR_EIR - FM Policer Profile Entry Peak/Excess Information Rate*/
++    volatile uint32_t fmpl_pepbs_ebs;   /* 0x0AC FMPL_PEPBS_EBS - FM Policer Profile Entry Peak/Excess Information Rate*/
++    volatile uint32_t fmpl_pelts;       /* 0x0B0 FMPL_PELTS  - FM Policer Profile Entry Last TimeStamp*/
++    volatile uint32_t fmpl_pects;       /* 0x0B4 FMPL_PECTS  - FM Policer Profile Entry Committed Token Status*/
++    volatile uint32_t fmpl_pepts_ets;   /* 0x0B8 FMPL_PEPTS_ETS - FM Policer Profile Entry Peak/Excess Token Status*/
++    volatile uint32_t fmpl_pegpc;       /* 0x0BC FMPL_PEGPC  - FM Policer Profile Entry GREEN Packet Counter*/
++    volatile uint32_t fmpl_peypc;       /* 0x0C0 FMPL_PEYPC  - FM Policer Profile Entry YELLOW Packet Counter*/
++    volatile uint32_t fmpl_perpc;       /* 0x0C4 FMPL_PERPC  - FM Policer Profile Entry RED Packet Counter */
++    volatile uint32_t fmpl_perypc;      /* 0x0C8 FMPL_PERYPC - FM Policer Profile Entry Recolored YELLOW Packet Counter*/
++    volatile uint32_t fmpl_perrpc;      /* 0x0CC FMPL_PERRPC - FM Policer Profile Entry Recolored RED Packet Counter*/
++    volatile uint32_t fmpl_res1[12];    /* 0x0D0-0x0FF Reserved */
++} _PackedType t_FmPcdPlcrProfileRegs;
++
++
++typedef _Packed struct t_FmPcdCcCapwapReassmTimeoutParams {
++    volatile uint32_t                       portIdAndCapwapReassmTbl;
++    volatile uint32_t                       fqidForTimeOutFrames;
++    volatile uint32_t                       timeoutRequestTime;
++}_PackedType t_FmPcdCcCapwapReassmTimeoutParams;
++
++/**************************************************************************//**
++ @Description   PCD CTRL Parameters Page
++*//***************************************************************************/
++typedef _Packed struct t_FmPcdCtrlParamsPage {
++    volatile uint8_t  reserved0[16];
++    volatile uint32_t iprIpv4Nia;
++    volatile uint32_t iprIpv6Nia;
++    volatile uint8_t  reserved1[24];
++    volatile uint32_t ipfOptionsCounter;
++    volatile uint8_t  reserved2[12];
++    volatile uint32_t misc;
++    volatile uint32_t errorsDiscardMask;
++    volatile uint32_t discardMask;
++    volatile uint8_t  reserved3[4];
++    volatile uint32_t postBmiFetchNia;
++    volatile uint8_t  reserved4[172];
++} _PackedType t_FmPcdCtrlParamsPage;
++
++
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(pop)
++#endif /* defined(__MWERKS__) && ... */
++
++
++/*for UNDER_CONSTRUCTION_FM_RMU_USE_SEC its defined in fm_ext.h*/
++typedef uint32_t t_FmFmanCtrl;
++
++#define FPM_PORT_FM_CTL1                0x00000001
++#define FPM_PORT_FM_CTL2                0x00000002
++
++
++
++typedef struct t_FmPcdCcFragScratchPoolCmdParams {
++    uint32_t    numOfBuffers;
++    uint8_t     bufferPoolId;
++} t_FmPcdCcFragScratchPoolCmdParams;
++
++typedef struct t_FmPcdCcReassmTimeoutParams {
++    bool        activate;
++    uint8_t     tsbs;
++    uint32_t    iprcpt;
++} t_FmPcdCcReassmTimeoutParams;
++
++typedef struct {
++    uint8_t             baseEntry;
++    uint16_t            numOfClsPlanEntries;
++    uint32_t            vectors[FM_PCD_MAX_NUM_OF_CLS_PLANS];
++} t_FmPcdKgInterModuleClsPlanSet;
++
++/**************************************************************************//**
++ @Description   Structure for binding a port to keygen schemes.
++*//***************************************************************************/
++typedef struct t_FmPcdKgInterModuleBindPortToSchemes {
++    uint8_t     hardwarePortId;
++    uint8_t     netEnvId;
++    bool        useClsPlan;                 /**< TRUE if this port uses the clsPlan mechanism */
++    uint8_t     numOfSchemes;
++    uint8_t     schemesIds[FM_PCD_KG_NUM_OF_SCHEMES];
++} t_FmPcdKgInterModuleBindPortToSchemes;
++
++typedef struct {
++    uint32_t nextCcNodeInfo;
++    t_List   node;
++} t_CcNodeInfo;
++
++typedef struct
++{
++    t_Handle    h_CcNode;
++    uint16_t    index;
++    t_List      node;
++}t_CcNodeInformation;
++#define CC_NODE_F_OBJECT(ptr)  LIST_OBJECT(ptr, t_CcNodeInformation, node)
++
++typedef enum e_ModifyState
++{
++    e_MODIFY_STATE_ADD = 0,
++    e_MODIFY_STATE_REMOVE,
++    e_MODIFY_STATE_CHANGE
++} e_ModifyState;
++
++typedef struct
++{
++    t_Handle h_Manip;
++    t_List   node;
++}t_ManipInfo;
++#define CC_NEXT_NODE_F_OBJECT(ptr)  LIST_OBJECT(ptr, t_CcNodeInfo, node)
++
++typedef struct {
++    uint32_t            type;
++    uint8_t             prOffset;
++    uint16_t            dataOffset;
++    uint8_t             internalBufferOffset;
++    uint8_t             numOfTasks;
++    uint8_t             numOfExtraTasks;
++    uint8_t             hardwarePortId;
++    t_FmRevisionInfo    revInfo;
++    uint32_t            nia;
++    uint32_t            discardMask;
++} t_GetCcParams;
++
++typedef struct {
++    uint32_t        type;
++    int             psoSize;
++    uint32_t        nia;
++    t_FmFmanCtrl    orFmanCtrl;
++    bool            overwrite;
++    uint8_t         ofpDpde;
++} t_SetCcParams;
++
++typedef struct {
++    t_GetCcParams getCcParams;
++    t_SetCcParams setCcParams;
++} t_FmPortGetSetCcParams;
++
++typedef struct {
++    uint32_t    type;
++    bool        sleep;
++} t_FmSetParams;
++
++typedef struct {
++    uint32_t    type;
++    uint32_t    fmqm_gs;
++    uint32_t    fm_npi;
++    uint32_t    fm_cld;
++    uint32_t    fmfp_extc;
++} t_FmGetParams;
++
++typedef struct {
++    t_FmSetParams setParams;
++    t_FmGetParams getParams;
++} t_FmGetSetParams;
++
++t_Error FmGetSetParams(t_Handle h_Fm, t_FmGetSetParams *p_Params);
++
++static __inline__ bool TRY_LOCK(t_Handle h_Spinlock, volatile bool *p_Flag)
++{
++    uint32_t intFlags;
++    if (h_Spinlock)
++        intFlags = XX_LockIntrSpinlock(h_Spinlock);
++    else
++        intFlags = XX_DisableAllIntr();
++
++    if (*p_Flag)
++    {
++        if (h_Spinlock)
++            XX_UnlockIntrSpinlock(h_Spinlock, intFlags);
++        else
++            XX_RestoreAllIntr(intFlags);
++        return FALSE;
++    }
++    *p_Flag = TRUE;
++
++    if (h_Spinlock)
++        XX_UnlockIntrSpinlock(h_Spinlock, intFlags);
++    else
++        XX_RestoreAllIntr(intFlags);
++
++    return TRUE;
++}
++
++#define RELEASE_LOCK(_flag) _flag = FALSE;
++
++/**************************************************************************//**
++ @Collection   Defines used for manipulation CC and BMI
++ @{
++*//***************************************************************************/
++#define INTERNAL_CONTEXT_OFFSET                 0x80000000
++#define OFFSET_OF_PR                            0x40000000
++#define MANIP_EXTRA_SPACE                       0x20000000
++#define NUM_OF_TASKS                            0x10000000
++#define OFFSET_OF_DATA                          0x08000000
++#define HW_PORT_ID                              0x04000000
++#define FM_REV                                  0x02000000
++#define GET_NIA_FPNE                            0x01000000
++#define GET_NIA_PNDN                            0x00800000
++#define NUM_OF_EXTRA_TASKS                      0x00400000
++#define DISCARD_MASK                            0x00200000
++
++#define UPDATE_NIA_PNEN                         0x80000000
++#define UPDATE_PSO                              0x40000000
++#define UPDATE_NIA_PNDN                         0x20000000
++#define UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY      0x10000000
++#define UPDATE_OFP_DPTE                         0x08000000
++#define UPDATE_NIA_FENE                         0x04000000
++#define UPDATE_NIA_CMNE                         0x02000000
++#define UPDATE_NIA_FPNE                         0x01000000
++/* @} */
++
++/**************************************************************************//**
++ @Collection   Defines used for manipulation CC and CC
++ @{
++*//***************************************************************************/
++#define UPDATE_NIA_ENQ_WITHOUT_DMA              0x80000000
++#define UPDATE_CC_WITH_TREE                     0x40000000
++#define UPDATE_CC_WITH_DELETE_TREE              0x20000000
++#define UPDATE_KG_NIA_CC_WA                     0x10000000
++#define UPDATE_KG_OPT_MODE                      0x08000000
++#define UPDATE_KG_NIA                           0x04000000
++#define UPDATE_CC_SHADOW_CLEAR                    0x02000000
++/* @} */
++
++#define UPDATE_FPM_BRKC_SLP                     0x80000000
++#define UPDATE_FPM_EXTC                               0x40000000
++#define UPDATE_FPM_EXTC_CLEAR                 0x20000000
++#define GET_FMQM_GS                           0x10000000
++#define GET_FM_NPI                            0x08000000
++#define GET_FMFP_EXTC                         0x04000000
++#define CLEAR_IRAM_READY                      0x02000000
++#define UPDATE_FM_CLD                         0x01000000
++#define GET_FM_CLD                            0x00800000
++#define FM_MAX_NUM_OF_PORTS     (FM_MAX_NUM_OF_OH_PORTS +     \
++                                 FM_MAX_NUM_OF_1G_RX_PORTS +  \
++                                 FM_MAX_NUM_OF_10G_RX_PORTS + \
++                                 FM_MAX_NUM_OF_1G_TX_PORTS +  \
++                                 FM_MAX_NUM_OF_10G_TX_PORTS)
++
++#define MODULE_NAME_SIZE        30
++#define DUMMY_PORT_ID           0
++
++#define FM_LIODN_OFFSET_MASK    0x3FF
++
++/**************************************************************************//**
++  @Description       NIA Description
++*//***************************************************************************/
++#define NIA_ENG_MASK                0x007C0000
++#define NIA_AC_MASK                 0x0003ffff
++
++#define NIA_ORDER_RESTOR            0x00800000
++#define NIA_ENG_FM_CTL              0x00000000
++#define NIA_ENG_PRS                 0x00440000
++#define NIA_ENG_KG                  0x00480000
++#define NIA_ENG_PLCR                0x004C0000
++#define NIA_ENG_BMI                 0x00500000
++#define NIA_ENG_QMI_ENQ             0x00540000
++#define NIA_ENG_QMI_DEQ             0x00580000
++
++#define NIA_FM_CTL_AC_CC                        0x00000006
++#define NIA_FM_CTL_AC_HC                        0x0000000C
++#define NIA_FM_CTL_AC_IND_MODE_TX               0x00000008
++#define NIA_FM_CTL_AC_IND_MODE_RX               0x0000000A
++#define NIA_FM_CTL_AC_POP_TO_N_STEP             0x0000000e
++#define NIA_FM_CTL_AC_PRE_BMI_FETCH_HEADER      0x00000010
++#define NIA_FM_CTL_AC_PRE_BMI_FETCH_FULL_FRAME  0x00000018
++#define NIA_FM_CTL_AC_POST_BMI_FETCH            0x00000012
++#define NIA_FM_CTL_AC_PRE_BMI_ENQ_FRAME         0x0000001A
++#define NIA_FM_CTL_AC_PRE_BMI_DISCARD_FRAME     0x0000001E
++#define NIA_FM_CTL_AC_POST_BMI_ENQ_ORR          0x00000014
++#define NIA_FM_CTL_AC_POST_BMI_ENQ              0x00000022
++#define NIA_FM_CTL_AC_PRE_CC                    0x00000020
++#define NIA_FM_CTL_AC_POST_TX                   0x00000024
++/* V3 only */
++#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME        0x00000028
++#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_DISCARD_FRAME    0x0000002A
++#define NIA_FM_CTL_AC_NO_IPACC_POP_TO_N_STEP            0x0000002C
++
++#define NIA_BMI_AC_ENQ_FRAME        0x00000002
++#define NIA_BMI_AC_TX_RELEASE       0x000002C0
++#define NIA_BMI_AC_RELEASE          0x000000C0
++#define NIA_BMI_AC_DISCARD          0x000000C1
++#define NIA_BMI_AC_TX               0x00000274
++#define NIA_BMI_AC_FETCH            0x00000208
++#define NIA_BMI_AC_MASK             0x000003FF
++
++#define NIA_KG_DIRECT               0x00000100
++#define NIA_KG_CC_EN                0x00000200
++#define NIA_PLCR_ABSOLUTE           0x00008000
++
++#define NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA    0x00000202
++
++#if defined(FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675) || defined(FM_ERROR_VSP_NO_MATCH_SW006)
++#define GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd)   \
++    (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \
++                (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_ENQ_FRAME) : \
++                (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME))
++#define GET_NIA_BMI_AC_DISCARD_FRAME(h_FmPcd)   \
++    (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \
++                (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_DISCARD_FRAME) : \
++                (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_DISCARD_FRAME))
++#define GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME()   \
++        (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME)
++#else
++#define GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd)   \
++    (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \
++                (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_ENQ_FRAME) : \
++                (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))
++#define GET_NIA_BMI_AC_DISCARD_FRAME(h_FmPcd)   \
++    (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \
++                (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_DISCARD_FRAME) : \
++                (NIA_ENG_BMI | NIA_BMI_AC_DISCARD))
++#define GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME()   \
++            (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)
++#endif /* defined(FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675) || ... */
++
++/**************************************************************************//**
++  @Description        CTRL Parameters Page defines
++*//***************************************************************************/
++#define FM_CTL_PARAMS_PAGE_OP_FIX_EN            0x80000000
++#define FM_CTL_PARAMS_PAGE_OFFLOAD_SUPPORT_EN   0x40000000
++#define FM_CTL_PARAMS_PAGE_ALWAYS_ON            0x00000100
++
++#define FM_CTL_PARAMS_PAGE_ERROR_VSP_MASK       0x0000003f
++
++/**************************************************************************//**
++ @Description       Port Id defines
++*//***************************************************************************/
++#if (DPAA_VERSION == 10)
++#define BASE_OH_PORTID              1
++#else
++#define BASE_OH_PORTID              2
++#endif /* (DPAA_VERSION == 10) */
++#define BASE_1G_RX_PORTID           8
++#define BASE_10G_RX_PORTID          0x10
++#define BASE_1G_TX_PORTID           0x28
++#define BASE_10G_TX_PORTID          0x30
++
++#define FM_PCD_PORT_OH_BASE_INDX        0
++#define FM_PCD_PORT_1G_RX_BASE_INDX     (FM_PCD_PORT_OH_BASE_INDX+FM_MAX_NUM_OF_OH_PORTS)
++#define FM_PCD_PORT_10G_RX_BASE_INDX    (FM_PCD_PORT_1G_RX_BASE_INDX+FM_MAX_NUM_OF_1G_RX_PORTS)
++#define FM_PCD_PORT_1G_TX_BASE_INDX     (FM_PCD_PORT_10G_RX_BASE_INDX+FM_MAX_NUM_OF_10G_RX_PORTS)
++#define FM_PCD_PORT_10G_TX_BASE_INDX    (FM_PCD_PORT_1G_TX_BASE_INDX+FM_MAX_NUM_OF_1G_TX_PORTS)
++
++#if (FM_MAX_NUM_OF_OH_PORTS > 0)
++#define CHECK_PORT_ID_OH_PORTS(_relativePortId)                     \
++    if ((_relativePortId) >= FM_MAX_NUM_OF_OH_PORTS)                \
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal OH_PORT port id"))
++#else
++#define CHECK_PORT_ID_OH_PORTS(_relativePortId)                     \
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal OH_PORT port id"))
++#endif
++#if (FM_MAX_NUM_OF_1G_RX_PORTS > 0)
++#define CHECK_PORT_ID_1G_RX_PORTS(_relativePortId)                  \
++    if ((_relativePortId) >= FM_MAX_NUM_OF_1G_RX_PORTS)             \
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_RX_PORT port id"))
++#else
++#define CHECK_PORT_ID_1G_RX_PORTS(_relativePortId)                  \
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_RX_PORT port id"))
++#endif
++#if (FM_MAX_NUM_OF_10G_RX_PORTS > 0)
++#define CHECK_PORT_ID_10G_RX_PORTS(_relativePortId)                 \
++    if ((_relativePortId) >= FM_MAX_NUM_OF_10G_RX_PORTS)            \
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_RX_PORT port id"))
++#else
++#define CHECK_PORT_ID_10G_RX_PORTS(_relativePortId)                 \
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_RX_PORT port id"))
++#endif
++#if (FM_MAX_NUM_OF_1G_TX_PORTS > 0)
++#define CHECK_PORT_ID_1G_TX_PORTS(_relativePortId)                  \
++    if ((_relativePortId) >= FM_MAX_NUM_OF_1G_TX_PORTS)             \
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_TX_PORT port id"))
++#else
++#define CHECK_PORT_ID_1G_TX_PORTS(_relativePortId)                  \
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_TX_PORT port id"))
++#endif
++#if (FM_MAX_NUM_OF_10G_TX_PORTS > 0)
++#define CHECK_PORT_ID_10G_TX_PORTS(_relativePortId)                 \
++    if ((_relativePortId) >= FM_MAX_NUM_OF_10G_TX_PORTS)            \
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_TX_PORT port id"))
++#else
++#define CHECK_PORT_ID_10G_TX_PORTS(_relativePortId)                 \
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_TX_PORT port id"))
++#endif
++
++uint8_t SwPortIdToHwPortId(e_FmPortType type, uint8_t relativePortId, uint8_t majorRev, uint8_t minorRev);
++
++#define HW_PORT_ID_TO_SW_PORT_ID(_relativePortId, hardwarePortId)                   \
++{   if (((hardwarePortId) >= BASE_OH_PORTID) &&                                     \
++        ((hardwarePortId) < BASE_OH_PORTID+FM_MAX_NUM_OF_OH_PORTS))                 \
++        _relativePortId = (uint8_t)((hardwarePortId)-BASE_OH_PORTID);               \
++    else if (((hardwarePortId) >= BASE_10G_TX_PORTID) &&                            \
++             ((hardwarePortId) < BASE_10G_TX_PORTID+FM_MAX_NUM_OF_10G_TX_PORTS))    \
++        _relativePortId = (uint8_t)((hardwarePortId)-BASE_10G_TX_PORTID);           \
++    else if (((hardwarePortId) >= BASE_1G_TX_PORTID) &&                             \
++             ((hardwarePortId) < BASE_1G_TX_PORTID+FM_MAX_NUM_OF_1G_TX_PORTS))      \
++        _relativePortId = (uint8_t)((hardwarePortId)-BASE_1G_TX_PORTID);            \
++    else if (((hardwarePortId) >= BASE_10G_RX_PORTID) &&                            \
++             ((hardwarePortId) < BASE_10G_RX_PORTID+FM_MAX_NUM_OF_10G_RX_PORTS))    \
++        _relativePortId = (uint8_t)((hardwarePortId)-BASE_10G_RX_PORTID);           \
++    else if (((hardwarePortId) >= BASE_1G_RX_PORTID) &&                             \
++             ((hardwarePortId) < BASE_1G_RX_PORTID+FM_MAX_NUM_OF_1G_RX_PORTS))      \
++        _relativePortId = (uint8_t)((hardwarePortId)-BASE_1G_RX_PORTID);            \
++    else {                                                                          \
++        _relativePortId = (uint8_t)DUMMY_PORT_ID;                                   \
++        ASSERT_COND(TRUE);                                                          \
++    }                                                                               \
++}
++
++#define HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId)                                             \
++do {                                                                                                        \
++    if (((hardwarePortId) >= BASE_OH_PORTID) && ((hardwarePortId) < BASE_OH_PORTID+FM_MAX_NUM_OF_OH_PORTS)) \
++        swPortIndex = (uint8_t)((hardwarePortId)-BASE_OH_PORTID+FM_PCD_PORT_OH_BASE_INDX);                  \
++    else if (((hardwarePortId) >= BASE_1G_RX_PORTID) &&                                                     \
++             ((hardwarePortId) < BASE_1G_RX_PORTID+FM_MAX_NUM_OF_1G_RX_PORTS))                              \
++        swPortIndex = (uint8_t)((hardwarePortId)-BASE_1G_RX_PORTID+FM_PCD_PORT_1G_RX_BASE_INDX);            \
++    else if (((hardwarePortId) >= BASE_10G_RX_PORTID) &&                                                    \
++             ((hardwarePortId) < BASE_10G_RX_PORTID+FM_MAX_NUM_OF_10G_RX_PORTS))                            \
++        swPortIndex = (uint8_t)((hardwarePortId)-BASE_10G_RX_PORTID+FM_PCD_PORT_10G_RX_BASE_INDX);          \
++    else if (((hardwarePortId) >= BASE_1G_TX_PORTID) &&                                                     \
++             ((hardwarePortId) < BASE_1G_TX_PORTID+FM_MAX_NUM_OF_1G_TX_PORTS))                              \
++        swPortIndex = (uint8_t)((hardwarePortId)-BASE_1G_TX_PORTID+FM_PCD_PORT_1G_TX_BASE_INDX);            \
++    else if (((hardwarePortId) >= BASE_10G_TX_PORTID) &&                                                    \
++             ((hardwarePortId) < BASE_10G_TX_PORTID+FM_MAX_NUM_OF_10G_TX_PORTS))                            \
++        swPortIndex = (uint8_t)((hardwarePortId)-BASE_10G_TX_PORTID+FM_PCD_PORT_10G_TX_BASE_INDX);          \
++    else ASSERT_COND(FALSE);                                                                                \
++} while (0)
++
++#define SW_PORT_INDX_TO_HW_PORT_ID(hardwarePortId, swPortIndex)                                                 \
++do {                                                                                                            \
++    if (((swPortIndex) >= FM_PCD_PORT_OH_BASE_INDX) && ((swPortIndex) < FM_PCD_PORT_1G_RX_BASE_INDX))           \
++        hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_OH_BASE_INDX+BASE_OH_PORTID);                      \
++    else if (((swPortIndex) >= FM_PCD_PORT_1G_RX_BASE_INDX) && ((swPortIndex) < FM_PCD_PORT_10G_RX_BASE_INDX))  \
++        hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_1G_RX_BASE_INDX+BASE_1G_RX_PORTID);                \
++    else if (((swPortIndex) >= FM_PCD_PORT_10G_RX_BASE_INDX) && ((swPortIndex) < FM_MAX_NUM_OF_PORTS))          \
++        hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_10G_RX_BASE_INDX+BASE_10G_RX_PORTID);              \
++    else if (((swPortIndex) >= FM_PCD_PORT_1G_TX_BASE_INDX) && ((swPortIndex) < FM_PCD_PORT_10G_TX_BASE_INDX))  \
++        hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_1G_TX_BASE_INDX+BASE_1G_TX_PORTID);                \
++    else if (((swPortIndex) >= FM_PCD_PORT_10G_TX_BASE_INDX) && ((swPortIndex) < FM_MAX_NUM_OF_PORTS))          \
++        hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_10G_TX_BASE_INDX+BASE_10G_TX_PORTID);              \
++    else ASSERT_COND(FALSE);                                                                                    \
++} while (0)
++
++#define BMI_MAX_FIFO_SIZE                   (FM_MURAM_SIZE)
++#define BMI_FIFO_UNITS                      0x100
++
++typedef struct {
++    void        (*f_Isr) (t_Handle h_Arg);
++    t_Handle    h_SrcHandle;
++    uint8_t     guestId;
++} t_FmIntrSrc;
++
++#define ILLEGAL_HDR_NUM                     0xFF
++#define NO_HDR_NUM                          FM_PCD_PRS_NUM_OF_HDRS
++
++#define IS_PRIVATE_HEADER(hdr)              (((hdr) == HEADER_TYPE_USER_DEFINED_SHIM1) ||   \
++                                             ((hdr) == HEADER_TYPE_USER_DEFINED_SHIM2))
++#define IS_SPECIAL_HEADER(hdr)              ((hdr) == HEADER_TYPE_MACSEC)
++
++static __inline__ uint8_t GetPrsHdrNum(e_NetHeaderType hdr)
++{
++       switch (hdr)
++       {   case (HEADER_TYPE_ETH):              return 0;
++           case (HEADER_TYPE_LLC_SNAP):         return 1;
++           case (HEADER_TYPE_VLAN):             return 2;
++           case (HEADER_TYPE_PPPoE):            return 3;
++           case (HEADER_TYPE_PPP):              return 3;
++           case (HEADER_TYPE_MPLS):             return 4;
++           case (HEADER_TYPE_IPv4):             return 5;
++           case (HEADER_TYPE_IPv6):             return 6;
++           case (HEADER_TYPE_GRE):              return 7;
++           case (HEADER_TYPE_MINENCAP):         return 8;
++           case (HEADER_TYPE_USER_DEFINED_L3):  return 9;
++           case (HEADER_TYPE_TCP):              return 10;
++           case (HEADER_TYPE_UDP):              return 11;
++           case (HEADER_TYPE_IPSEC_AH):
++           case (HEADER_TYPE_IPSEC_ESP):        return 12;
++           case (HEADER_TYPE_SCTP):             return 13;
++           case (HEADER_TYPE_DCCP):             return 14;
++           case (HEADER_TYPE_USER_DEFINED_L4):  return 15;
++           case (HEADER_TYPE_USER_DEFINED_SHIM1):
++           case (HEADER_TYPE_USER_DEFINED_SHIM2):
++           case (HEADER_TYPE_MACSEC):           return NO_HDR_NUM;
++           default:
++               return ILLEGAL_HDR_NUM;
++       }
++}
++
++#define FM_PCD_MAX_NUM_OF_OPTIONS(clsPlanEntries)   ((clsPlanEntries==256)? 8:((clsPlanEntries==128)? 7: ((clsPlanEntries==64)? 6: ((clsPlanEntries==32)? 5:0))))
++
++
++/**************************************************************************//**
++ @Description   A structure for initializing a keygen classification plan group
++*//***************************************************************************/
++typedef struct t_FmPcdKgInterModuleClsPlanGrpParams {
++    uint8_t         netEnvId;   /* IN */
++    bool            grpExists;  /* OUT (unused in FmPcdKgBuildClsPlanGrp)*/
++    uint8_t         clsPlanGrpId;  /* OUT */
++    bool            emptyClsPlanGrp; /* OUT */
++    uint8_t         numOfOptions;   /* OUT in FmPcdGetSetClsPlanGrpParams IN in FmPcdKgBuildClsPlanGrp*/
++    protocolOpt_t   options[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)];
++                                    /* OUT in FmPcdGetSetClsPlanGrpParams IN in FmPcdKgBuildClsPlanGrp*/
++    uint32_t        optVectors[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)];
++                               /* OUT in FmPcdGetSetClsPlanGrpParams IN in FmPcdKgBuildClsPlanGrp*/
++} t_FmPcdKgInterModuleClsPlanGrpParams;
++
++typedef struct t_FmPcdLock {
++    t_Handle        h_Spinlock;
++    volatile bool   flag;
++    t_List          node;
++} t_FmPcdLock;
++#define FM_PCD_LOCK_OBJ(ptr)  LIST_OBJECT(ptr, t_FmPcdLock, node)
++
++
++typedef t_Error (t_FmPortGetSetCcParamsCallback) (t_Handle                  h_FmPort,
++                                                  t_FmPortGetSetCcParams    *p_FmPortGetSetCcParams);
++
++
++/***********************************************************************/
++/*          Common API for FM-PCD module                               */
++/***********************************************************************/
++t_Handle    FmPcdGetHcHandle(t_Handle h_FmPcd);
++uint32_t    FmPcdGetSwPrsOffset(t_Handle h_FmPcd, e_NetHeaderType hdr, uint8_t  indexPerHdr);
++uint32_t    FmPcdGetLcv(t_Handle h_FmPcd, uint32_t netEnvId, uint8_t hdrNum);
++uint32_t    FmPcdGetMacsecLcv(t_Handle h_FmPcd, uint32_t netEnvId);
++void        FmPcdIncNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId);
++void        FmPcdDecNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId);
++uint8_t     FmPcdGetNetEnvId(t_Handle h_NetEnv);
++void        FmPcdPortRegister(t_Handle h_FmPcd, t_Handle h_FmPort, uint8_t hardwarePortId);
++uint32_t    FmPcdLock(t_Handle h_FmPcd);
++void        FmPcdUnlock(t_Handle h_FmPcd, uint32_t  intFlags);
++bool        FmPcdNetEnvIsHdrExist(t_Handle h_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr);
++t_Error     FmPcdFragHcScratchPoolInit(t_Handle h_FmPcd, uint8_t scratchBpid);
++t_Error     FmPcdRegisterReassmPort(t_Handle h_FmPcd, t_Handle h_IpReasmCommonPramTbl);
++t_Error     FmPcdUnregisterReassmPort(t_Handle h_FmPcd, t_Handle h_IpReasmCommonPramTbl);
++bool        FmPcdIsAdvancedOffloadSupported(t_Handle h_FmPcd);
++bool        FmPcdLockTryLockAll(t_Handle h_FmPcd);
++void        FmPcdLockUnlockAll(t_Handle h_FmPcd);
++t_Error     FmPcdHcSync(t_Handle h_FmPcd);
++t_Handle    FmGetPcd(t_Handle h_Fm);
++/***********************************************************************/
++/*          Common API for FM-PCD KG module                            */
++/***********************************************************************/
++uint8_t     FmPcdKgGetClsPlanGrpBase(t_Handle h_FmPcd, uint8_t clsPlanGrp);
++uint16_t    FmPcdKgGetClsPlanGrpSize(t_Handle h_FmPcd, uint8_t clsPlanGrp);
++t_Error     FmPcdKgBuildClsPlanGrp(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_Grp, t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet);
++
++uint8_t     FmPcdKgGetSchemeId(t_Handle h_Scheme);
++#if (DPAA_VERSION >= 11)
++bool        FmPcdKgGetVspe(t_Handle h_Scheme);
++#endif /* (DPAA_VERSION >= 11) */
++uint8_t     FmPcdKgGetRelativeSchemeId(t_Handle h_FmPcd, uint8_t schemeId);
++void        FmPcdKgDestroyClsPlanGrp(t_Handle h_FmPcd, uint8_t grpId);
++t_Error     FmPcdKgCheckInvalidateSchemeSw(t_Handle h_Scheme);
++t_Error     FmPcdKgBuildBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPortToSchemes, uint32_t *p_SpReg, bool add);
++bool        FmPcdKgHwSchemeIsValid(uint32_t schemeModeReg);
++uint32_t    FmPcdKgBuildWriteSchemeActionReg(uint8_t schemeId, bool updateCounter);
++uint32_t    FmPcdKgBuildReadSchemeActionReg(uint8_t schemeId);
++uint32_t    FmPcdKgBuildWriteClsPlanBlockActionReg(uint8_t grpId);
++uint32_t    FmPcdKgBuildWritePortSchemeBindActionReg(uint8_t hardwarePortId);
++uint32_t    FmPcdKgBuildReadPortSchemeBindActionReg(uint8_t hardwarePortId);
++uint32_t    FmPcdKgBuildWritePortClsPlanBindActionReg(uint8_t hardwarePortId);
++bool        FmPcdKgIsSchemeValidSw(t_Handle h_Scheme);
++
++t_Error     FmPcdKgBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes  *p_SchemeBind);
++t_Error     FmPcdKgUnbindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind);
++uint32_t    FmPcdKgGetRequiredAction(t_Handle h_FmPcd, uint8_t schemeId);
++uint32_t    FmPcdKgGetRequiredActionFlag(t_Handle h_FmPcd, uint8_t schemeId);
++e_FmPcdDoneAction FmPcdKgGetDoneAction(t_Handle h_FmPcd, uint8_t schemeId);
++e_FmPcdEngine FmPcdKgGetNextEngine(t_Handle h_FmPcd, uint8_t schemeId);
++void        FmPcdKgUpdateRequiredAction(t_Handle h_Scheme, uint32_t requiredAction);
++bool        FmPcdKgIsDirectPlcr(t_Handle h_FmPcd, uint8_t schemeId);
++bool        FmPcdKgIsDistrOnPlcrProfile(t_Handle h_FmPcd, uint8_t schemeId);
++uint16_t    FmPcdKgGetRelativeProfileId(t_Handle h_FmPcd, uint8_t schemeId);
++t_Handle    FmPcdKgGetSchemeHandle(t_Handle h_FmPcd, uint8_t relativeSchemeId);
++bool        FmPcdKgIsSchemeHasOwners(t_Handle h_Scheme);
++t_Error     FmPcdKgCcGetSetParams(t_Handle h_FmPcd, t_Handle  h_Scheme, uint32_t requiredAction, uint32_t value);
++t_Error     FmPcdKgSetOrBindToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t netEnvId, protocolOpt_t *p_OptArray, uint8_t *p_ClsPlanGrpId, bool *p_IsEmptyClsPlanGrp);
++t_Error     FmPcdKgDeleteOrUnbindPortToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId);
++
++/***********************************************************************/
++/*          Common API for FM-PCD parser module                        */
++/***********************************************************************/
++t_Error     FmPcdPrsIncludePortInStatistics(t_Handle p_FmPcd, uint8_t hardwarePortId,  bool include);
++
++/***********************************************************************/
++/*          Common API for FM-PCD policer module                       */
++/***********************************************************************/
++t_Error     FmPcdPlcrAllocProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles);
++t_Error     FmPcdPlcrFreeProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId);
++bool        FmPcdPlcrIsProfileValid(t_Handle h_FmPcd, uint16_t absoluteProfileId);
++uint16_t    FmPcdPlcrGetPortProfilesBase(t_Handle h_FmPcd, uint8_t hardwarePortId);
++uint16_t    FmPcdPlcrGetPortNumOfProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId);
++uint32_t    FmPcdPlcrBuildWritePlcrActionRegs(uint16_t absoluteProfileId);
++uint32_t    FmPcdPlcrBuildCounterProfileReg(e_FmPcdPlcrProfileCounters counter);
++uint32_t    FmPcdPlcrBuildWritePlcrActionReg(uint16_t absoluteProfileId);
++uint32_t    FmPcdPlcrBuildReadPlcrActionReg(uint16_t absoluteProfileId);
++uint16_t    FmPcdPlcrProfileGetAbsoluteId(t_Handle h_Profile);
++t_Error     FmPcdPlcrGetAbsoluteIdByProfileParams(t_Handle                      h_FmPcd,
++                                          e_FmPcdProfileTypeSelection   profileType,
++                                          t_Handle                      h_FmPort,
++                                          uint16_t                      relativeProfile,
++                                          uint16_t                      *p_AbsoluteId);
++void        FmPcdPlcrInvalidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId);
++void        FmPcdPlcrValidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId);
++bool        FmPcdPlcrHwProfileIsValid(uint32_t profileModeReg);
++uint32_t    FmPcdPlcrGetRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId);
++uint32_t    FmPcdPlcrGetRequiredActionFlag(t_Handle h_FmPcd, uint16_t absoluteProfileId);
++uint32_t    FmPcdPlcrBuildNiaProfileReg(bool green, bool yellow, bool red);
++void        FmPcdPlcrUpdateRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId, uint32_t requiredAction);
++t_Error     FmPcdPlcrCcGetSetParams(t_Handle h_FmPcd, uint16_t profileIndx,uint32_t requiredAction);
++
++/***********************************************************************/
++/*          Common API for FM-PCD CC module                            */
++/***********************************************************************/
++uint8_t     FmPcdCcGetParseCode(t_Handle h_CcNode);
++uint8_t     FmPcdCcGetOffset(t_Handle h_CcNode);
++t_Error     FmPcdCcRemoveKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint16_t keyIndex);
++t_Error     FmPcdCcAddKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint16_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_FmPCdCcKeyParams);
++t_Error     FmPcdCcModifyKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint16_t keyIndex, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask);
++t_Error     FmPcdCcModifyKeyAndNextEngine(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint16_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_FmPcdCcKeyParams);
++t_Error     FmPcdCcModifyMissNextEngineParamNode(t_Handle h_FmPcd,t_Handle h_FmPcdCcNode, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
++t_Error     FmPcdCcModifyNextEngineParamTree(t_Handle h_FmPcd, t_Handle h_FmPcdCcTree, uint8_t grpId, uint8_t index, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
++uint32_t    FmPcdCcGetNodeAddrOffsetFromNodeInfo(t_Handle h_FmPcd, t_Handle h_Pointer);
++t_Handle    FmPcdCcTreeGetSavedManipParams(t_Handle h_FmTree);
++void        FmPcdCcTreeSetSavedManipParams(t_Handle h_FmTree, t_Handle h_SavedManipParams);
++t_Error     FmPcdCcTreeAddIPR(t_Handle h_FmPcd, t_Handle h_FmTree, t_Handle h_NetEnv, t_Handle h_ReassemblyManip, bool schemes);
++t_Error     FmPcdCcTreeAddCPR(t_Handle h_FmPcd, t_Handle h_FmTree, t_Handle h_NetEnv, t_Handle h_ReassemblyManip, bool schemes);
++t_Error     FmPcdCcBindTree(t_Handle h_FmPcd, t_Handle h_PcdParams, t_Handle h_CcTree,  uint32_t  *p_Offset,t_Handle h_FmPort);
++t_Error     FmPcdCcUnbindTree(t_Handle h_FmPcd, t_Handle h_CcTree);
++
++/***********************************************************************/
++/*          Common API for FM-PCD Manip module                            */
++/***********************************************************************/
++t_Error     FmPcdManipUpdate(t_Handle h_FmPcd, t_Handle h_PcdParams, t_Handle h_FmPort, t_Handle h_Manip, t_Handle h_Ad, bool validate, int level, t_Handle h_FmTree, bool modify);
++
++/***********************************************************************/
++/*          Common API for FM-Port module                            */
++/***********************************************************************/
++#if (DPAA_VERSION >= 11)
++typedef enum e_FmPortGprFuncType
++{
++    e_FM_PORT_GPR_EMPTY = 0,
++    e_FM_PORT_GPR_MURAM_PAGE
++} e_FmPortGprFuncType;
++
++t_Error     FmPortSetGprFunc(t_Handle h_FmPort, e_FmPortGprFuncType gprFunc, void **p_Value);
++#endif /* DPAA_VERSION >= 11) */
++t_Error     FmGetSetParams(t_Handle h_Fm, t_FmGetSetParams *p_FmGetSetParams);
++t_Error     FmPortGetSetCcParams(t_Handle h_FmPort, t_FmPortGetSetCcParams *p_FmPortGetSetCcParams);
++uint8_t     FmPortGetNetEnvId(t_Handle h_FmPort);
++uint8_t     FmPortGetHardwarePortId(t_Handle h_FmPort);
++uint32_t    FmPortGetPcdEngines(t_Handle h_FmPort);
++void        FmPortPcdKgSwUnbindClsPlanGrp (t_Handle h_FmPort);
++
++
++#if (DPAA_VERSION >= 11)
++t_Error     FmPcdFrmReplicUpdate(t_Handle h_FmPcd, t_Handle h_FmPort, t_Handle h_FrmReplic);
++#endif /* (DPAA_VERSION >= 11) */
++
++/**************************************************************************//**
++ @Function      FmRegisterIntr
++
++ @Description   Used to register an inter-module event handler to be processed by FM
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     mod             The module that causes the event
++ @Param[in]     modId           Module id - if more than 1 instansiation of this
++                                mode exists,0 otherwise.
++ @Param[in]     intrType        Interrupt type (error/normal) selection.
++ @Param[in]     f_Isr           The interrupt service routine.
++ @Param[in]     h_Arg           Argument to be passed to f_Isr.
++
++ @Return        None.
++*//***************************************************************************/
++void FmRegisterIntr(t_Handle               h_Fm,
++                    e_FmEventModules       mod,
++                    uint8_t                modId,
++                    e_FmIntrType           intrType,
++                    void                   (*f_Isr) (t_Handle h_Arg),
++                    t_Handle               h_Arg);
++
++/**************************************************************************//**
++ @Function      FmUnregisterIntr
++
++ @Description   Used to un-register an inter-module event handler that was processed by FM
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     mod             The module that causes the event
++ @Param[in]     modId           Module id - if more than 1 instansiation of this
++                                mode exists,0 otherwise.
++ @Param[in]     intrType        Interrupt type (error/normal) selection.
++
++ @Return        None.
++*//***************************************************************************/
++void FmUnregisterIntr(t_Handle          h_Fm,
++                      e_FmEventModules  mod,
++                      uint8_t           modId,
++                      e_FmIntrType      intrType);
++
++/**************************************************************************//**
++ @Function      FmRegisterFmCtlIntr
++
++ @Description   Used to register to one of the fmCtl events in the FM module
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     eventRegId      FmCtl event id (0-7).
++ @Param[in]     f_Isr           The interrupt service routine.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++void  FmRegisterFmCtlIntr(t_Handle h_Fm, uint8_t eventRegId, void (*f_Isr) (t_Handle h_Fm, uint32_t event));
++
++
++/**************************************************************************//**
++ @Description   enum for defining MAC types
++*//***************************************************************************/
++typedef enum e_FmMacType {
++    e_FM_MAC_10G = 0,               /**< 10G MAC */
++    e_FM_MAC_1G                     /**< 1G MAC */
++} e_FmMacType;
++
++/**************************************************************************//**
++ @Description   Structure for port-FM communication during FM_PORT_Init.
++                Fields commented 'IN' are passed by the port module to be used
++                by the FM module.
++                Fields commented 'OUT' will be filled by FM before returning to port.
++                Some fields are optional (depending on configuration) and
++                will be analized by the port and FM modules accordingly.
++*//***************************************************************************/
++typedef struct t_FmInterModulePortInitParams {
++    uint8_t             hardwarePortId;     /**< IN. port Id */
++    e_FmPortType        portType;           /**< IN. Port type */
++    bool                independentMode;    /**< IN. TRUE if FM Port operates in independent mode */
++    uint16_t            liodnOffset;        /**< IN. Port's requested resource */
++    uint8_t             numOfTasks;         /**< IN. Port's requested resource */
++    uint8_t             numOfExtraTasks;    /**< IN. Port's requested resource */
++    uint8_t             numOfOpenDmas;      /**< IN. Port's requested resource */
++    uint8_t             numOfExtraOpenDmas; /**< IN. Port's requested resource */
++    uint32_t            sizeOfFifo;         /**< IN. Port's requested resource */
++    uint32_t            extraSizeOfFifo;    /**< IN. Port's requested resource */
++    uint8_t             deqPipelineDepth;   /**< IN. Port's requested resource */
++    uint16_t            maxFrameLength;     /**< IN. Port's max frame length. */
++    uint16_t            liodnBase;          /**< IN. Irrelevant for P4080 rev 1.
++                                                 LIODN base for this port, to be
++                                                 used together with LIODN offset. */
++    t_FmPhysAddr        fmMuramPhysBaseAddr;/**< OUT. FM-MURAM physical address*/
++} t_FmInterModulePortInitParams;
++
++/**************************************************************************//**
++ @Description   Structure for port-FM communication during FM_PORT_Free.
++*//***************************************************************************/
++typedef struct t_FmInterModulePortFreeParams {
++    uint8_t             hardwarePortId;     /**< IN. port Id */
++    e_FmPortType        portType;           /**< IN. Port type */
++    uint8_t             deqPipelineDepth;   /**< IN. Port's requested resource */
++} t_FmInterModulePortFreeParams;
++
++/**************************************************************************//**
++ @Function      FmGetPcdPrsBaseAddr
++
++ @Description   Get the base address of the Parser from the FM module
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++
++ @Return        Base address.
++*//***************************************************************************/
++uintptr_t FmGetPcdPrsBaseAddr(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FmGetPcdKgBaseAddr
++
++ @Description   Get the base address of the Keygen from the FM module
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++
++ @Return        Base address.
++*//***************************************************************************/
++uintptr_t FmGetPcdKgBaseAddr(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FmGetPcdPlcrBaseAddr
++
++ @Description   Get the base address of the Policer from the FM module
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++
++ @Return        Base address.
++*//***************************************************************************/
++uintptr_t FmGetPcdPlcrBaseAddr(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FmGetMuramHandle
++
++ @Description   Get the handle of the MURAM from the FM module
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++
++ @Return        MURAM module handle.
++*//***************************************************************************/
++t_Handle FmGetMuramHandle(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FmGetPhysicalMuramBase
++
++ @Description   Get the physical base address of the MURAM from the FM module
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     fmPhysAddr      Physical MURAM base
++
++ @Return        Physical base address.
++*//***************************************************************************/
++void FmGetPhysicalMuramBase(t_Handle h_Fm, t_FmPhysAddr *fmPhysAddr);
++
++/**************************************************************************//**
++ @Function      FmGetTimeStampScale
++
++ @Description   Used internally by other modules in order to get the timeStamp
++                period as requested by the application.
++
++                This function returns bit number that is incremented every 1 usec.
++                To calculate timestamp period in nsec, use
++                1000 / (1 << FmGetTimeStampScale()).
++
++ @Param[in]     h_Fm                    A handle to an FM Module.
++
++ @Return        Bit that counts 1 usec.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++uint32_t FmGetTimeStampScale(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FmResumeStalledPort
++
++ @Description   Used internally by FM port to release a stalled port.
++
++ @Param[in]     h_Fm                            A handle to an FM Module.
++ @Param[in]     hardwarePortId                    HW port id.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++t_Error FmResumeStalledPort(t_Handle h_Fm, uint8_t hardwarePortId);
++
++/**************************************************************************//**
++ @Function      FmIsPortStalled
++
++ @Description   Used internally by FM port to read the port's status.
++
++ @Param[in]     h_Fm                            A handle to an FM Module.
++ @Param[in]     hardwarePortId                  HW port id.
++ @Param[in]     p_IsStalled                     A pointer to the boolean port stalled state
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++t_Error FmIsPortStalled(t_Handle h_Fm, uint8_t hardwarePortId, bool *p_IsStalled);
++
++/**************************************************************************//**
++ @Function      FmResetMac
++
++ @Description   Used by MAC driver to reset the MAC registers
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     type            MAC type.
++ @Param[in]     macId           MAC id - according to type.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++t_Error FmResetMac(t_Handle h_Fm, e_FmMacType type, uint8_t macId);
++
++/**************************************************************************//**
++ @Function      FmGetClockFreq
++
++ @Description   Used by MAC driver to get the FM clock frequency
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++
++ @Return        clock-freq on success; 0 otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++uint16_t FmGetClockFreq(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FmGetMacClockFreq
++
++ @Description   Used by MAC driver to get the MAC clock frequency
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++
++ @Return        clock-freq on success; 0 otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++uint16_t FmGetMacClockFreq(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FmGetId
++
++ @Description   Used by PCD driver to read rhe FM id
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++uint8_t FmGetId(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FmReset
++
++ @Description   Used to reset the FM
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FmReset(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FmGetSetPortParams
++
++ @Description   Used by FM-PORT driver to pass and receive parameters between
++                PORT and FM modules.
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in,out] p_PortParams    A structure of FM Port parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++t_Error FmGetSetPortParams(t_Handle h_Fm,t_FmInterModulePortInitParams *p_PortParams);
++
++/**************************************************************************//**
++ @Function      FmFreePortParams
++
++ @Description   Used by FM-PORT driver to free port's resources within the FM.
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in,out] p_PortParams    A structure of FM Port parameters.
++
++ @Return        None.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++void FmFreePortParams(t_Handle h_Fm,t_FmInterModulePortFreeParams *p_PortParams);
++
++/**************************************************************************//**
++ @Function      FmSetNumOfRiscsPerPort
++
++ @Description   Used by FM-PORT driver to pass parameter between
++                PORT and FM modules for working with number of RISC..
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     hardwarePortId    hardware port Id.
++ @Param[in]     numOfFmanCtrls    number of Fman Controllers.
++ @Param[in]     orFmanCtrl        Fman Controller for order restoration.
++
++ @Return        None.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++t_Error FmSetNumOfRiscsPerPort(t_Handle h_Fm, uint8_t hardwarePortId, uint8_t numOfFmanCtrls, t_FmFmanCtrl orFmanCtrl);
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++/**************************************************************************//*
++ @Function      FmDumpPortRegs
++
++ @Description   Dumps FM port registers which are part of FM common registers
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     hardwarePortId    HW port id.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only FM_Init().
++*//***************************************************************************/
++t_Error FmDumpPortRegs(t_Handle h_Fm,uint8_t hardwarePortId);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++void        FmRegisterPcd(t_Handle h_Fm, t_Handle h_FmPcd);
++void        FmUnregisterPcd(t_Handle h_Fm);
++t_Handle    FmGetPcdHandle(t_Handle h_Fm);
++t_Error     FmEnableRamsEcc(t_Handle h_Fm);
++t_Error     FmDisableRamsEcc(t_Handle h_Fm);
++void        FmGetRevision(t_Handle h_Fm, t_FmRevisionInfo *p_FmRevisionInfo);
++t_Error     FmAllocFmanCtrlEventReg(t_Handle h_Fm, uint8_t *p_EventId);
++void        FmFreeFmanCtrlEventReg(t_Handle h_Fm, uint8_t eventId);
++void        FmSetFmanCtrlIntr(t_Handle h_Fm, uint8_t   eventRegId, uint32_t enableEvents);
++uint32_t    FmGetFmanCtrlIntr(t_Handle h_Fm, uint8_t   eventRegId);
++void        FmRegisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, void (*f_Isr) (t_Handle h_Fm, uint32_t event), t_Handle    h_Arg);
++void        FmUnregisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId);
++t_Error     FmSetMacMaxFrame(t_Handle h_Fm, e_FmMacType type, uint8_t macId, uint16_t mtu);
++bool        FmIsMaster(t_Handle h_Fm);
++uint8_t     FmGetGuestId(t_Handle h_Fm);
++uint16_t    FmGetTnumAgingPeriod(t_Handle h_Fm);
++t_Error     FmSetPortPreFetchConfiguration(t_Handle h_Fm, uint8_t portNum, bool preFetchConfigured);
++t_Error     FmGetPortPreFetchConfiguration(t_Handle h_Fm, uint8_t portNum, bool *p_PortConfigured, bool *p_PreFetchConfigured);
++
++
++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
++t_Error     Fm10GTxEccWorkaround(t_Handle h_Fm, uint8_t macId);
++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
++
++void        FmMuramClear(t_Handle h_FmMuram);
++t_Error     FmSetNumOfOpenDmas(t_Handle h_Fm,
++                               uint8_t  hardwarePortId,
++                               uint8_t  *p_NumOfOpenDmas,
++                               uint8_t  *p_NumOfExtraOpenDmas,
++                               bool     initialConfig);
++t_Error     FmSetNumOfTasks(t_Handle    h_Fm,
++                            uint8_t     hardwarePortId,
++                            uint8_t     *p_NumOfTasks,
++                            uint8_t     *p_NumOfExtraTasks,
++                            bool        initialConfig);
++t_Error     FmSetSizeOfFifo(t_Handle    h_Fm,
++                            uint8_t     hardwarePortId,
++                            uint32_t    *p_SizeOfFifo,
++                            uint32_t    *p_ExtraSizeOfFifo,
++                            bool        initialConfig);
++
++t_Error     FmSetCongestionGroupPFCpriority(t_Handle    h_Fm,
++                                            uint32_t    congestionGroupId,
++                                            uint8_t     priorityBitMap);
++
++#if (DPAA_VERSION >= 11)
++t_Error     FmVSPAllocForPort(t_Handle         h_Fm,
++                              e_FmPortType     portType,
++                              uint8_t          portId,
++                              uint8_t          numOfStorageProfiles);
++
++t_Error     FmVSPFreeForPort(t_Handle        h_Fm,
++                             e_FmPortType    portType,
++                             uint8_t         portId);
++
++t_Error     FmVSPGetAbsoluteProfileId(t_Handle      h_Fm,
++                                      e_FmPortType  portType,
++                                      uint8_t       portId,
++                                      uint16_t      relativeProfile,
++                                      uint16_t      *p_AbsoluteId);
++t_Error FmVSPCheckRelativeProfile(t_Handle        h_Fm,
++                                  e_FmPortType    portType,
++                                  uint8_t         portId,
++                                  uint16_t        relativeProfile);
++
++uintptr_t   FmGetVSPBaseAddr(t_Handle h_Fm);
++#endif /* (DPAA_VERSION >= 11) */
++
++
++#endif /* __FM_COMMON_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_hc.h
+@@ -0,0 +1,93 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#ifndef __FM_HC_H
++#define __FM_HC_H
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "fsl_fman_kg.h"
++
++#define __ERR_MODULE__  MODULE_FM_PCD
++
++
++typedef struct t_FmHcParams {
++    t_Handle        h_Fm;
++    t_Handle        h_FmPcd;
++    t_FmPcdHcParams params;
++} t_FmHcParams;
++
++
++t_Handle    FmHcConfigAndInit(t_FmHcParams *p_FmHcParams);
++void        FmHcFree(t_Handle h_FmHc);
++t_Error     FmHcSetFramesDataMemory(t_Handle h_FmHc,
++                                    uint8_t  memId);
++t_Error     FmHcDumpRegs(t_Handle h_FmHc);
++
++void        FmHcTxConf(t_Handle h_FmHc, t_DpaaFD *p_Fd);
++
++t_Error     FmHcPcdKgSetScheme(t_Handle                   h_FmHc,
++                               t_Handle                   h_Scheme,
++                               struct fman_kg_scheme_regs *p_SchemeRegs,
++                               bool                       updateCounter);
++t_Error     FmHcPcdKgDeleteScheme(t_Handle h_FmHc, t_Handle h_Scheme);
++t_Error     FmHcPcdCcCapwapTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcCapwapReassmTimeoutParams *p_CcCapwapReassmTimeoutParams );
++t_Error     FmHcPcdCcIpFragScratchPollCmd(t_Handle h_FmHc, bool fill, t_FmPcdCcFragScratchPoolCmdParams *p_FmPcdCcFragScratchPoolCmdParams);
++t_Error     FmHcPcdCcTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcReassmTimeoutParams *p_CcReassmTimeoutParams, uint8_t *p_Result);
++t_Error     FmHcPcdKgSetClsPlan(t_Handle h_FmHc, t_FmPcdKgInterModuleClsPlanSet *p_Set);
++t_Error     FmHcPcdKgDeleteClsPlan(t_Handle h_FmHc, uint8_t clsPlanGrpId);
++
++t_Error     FmHcPcdKgSetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t value);
++uint32_t    FmHcPcdKgGetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme);
++
++t_Error     FmHcPcdCcDoDynamicChange(t_Handle h_FmHc, uint32_t oldAdAddrOffset, uint32_t newAdAddrOffset);
++
++t_Error     FmHcPcdPlcrSetProfile(t_Handle h_FmHc, t_Handle h_Profile, t_FmPcdPlcrProfileRegs *p_PlcrRegs);
++t_Error     FmHcPcdPlcrDeleteProfile(t_Handle h_FmHc, t_Handle h_Profile);
++
++t_Error     FmHcPcdPlcrSetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value);
++uint32_t    FmHcPcdPlcrGetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter);
++
++t_Error     FmHcKgWriteSp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t spReg, bool add);
++t_Error     FmHcKgWriteCpp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t cppReg);
++
++t_Error     FmHcPcdKgCcGetSetParams(t_Handle h_FmHc, t_Handle  h_Scheme, uint32_t requiredAction, uint32_t value);
++t_Error     FmHcPcdPlcrCcGetSetParams(t_Handle h_FmHc,uint16_t absoluteProfileId, uint32_t requiredAction);
++
++t_Error     FmHcPcdSync(t_Handle h_FmHc);
++t_Handle    FmHcGetPort(t_Handle h_FmHc);
++
++
++
++
++#endif /* __FM_HC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_sp_common.h
+@@ -0,0 +1,117 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_sp_common.h
++
++ @Description   FM SP  ...
++*//***************************************************************************/
++#ifndef __FM_SP_COMMON_H
++#define __FM_SP_COMMON_H
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "list_ext.h"
++
++#include "fm_ext.h"
++#include "fm_pcd_ext.h"
++#include "fsl_fman.h"
++
++/**************************************************************************//**
++ @Description       defaults
++*//***************************************************************************/
++#define DEFAULT_FM_SP_bufferPrefixContent_privDataSize      0
++#define DEFAULT_FM_SP_bufferPrefixContent_passPrsResult     FALSE
++#define DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp     FALSE
++#define DEFAULT_FM_SP_bufferPrefixContent_allOtherPCDInfo   FALSE
++#define DEFAULT_FM_SP_bufferPrefixContent_dataAlign         64
++
++/**************************************************************************//**
++ @Description   structure for defining internal context copying
++*//***************************************************************************/
++typedef struct
++{
++    uint16_t    extBufOffset;       /**< Offset in External buffer to which internal
++                                         context is copied to (Rx) or taken from (Tx, Op). */
++    uint8_t     intContextOffset;   /**< Offset within internal context to copy from
++                                         (Rx) or to copy to (Tx, Op). */
++    uint16_t    size;               /**< Internal offset size to be copied */
++} t_FmSpIntContextDataCopy;
++
++/**************************************************************************//**
++ @Description   struct for defining external buffer margins
++*//***************************************************************************/
++typedef struct {
++    uint16_t    startMargins;           /**< Number of bytes to be left at the beginning
++                                             of the external buffer (must be divisible by 16) */
++    uint16_t    endMargins;             /**< number of bytes to be left at the end
++                                             of the external buffer(must be divisible by 16) */
++} t_FmSpBufMargins;
++
++typedef struct {
++    uint32_t      dataOffset;
++    uint32_t      prsResultOffset;
++    uint32_t      timeStampOffset;
++    uint32_t      hashResultOffset;
++    uint32_t      pcdInfoOffset;
++    uint32_t      manipOffset;
++} t_FmSpBufferOffsets;
++
++
++t_Error        FmSpBuildBufferStructure(t_FmSpIntContextDataCopy      *p_FmPortIntContextDataCopy,
++                                        t_FmBufferPrefixContent       *p_BufferPrefixContent,
++                                        t_FmSpBufMargins              *p_FmPortBufMargins,
++                                        t_FmSpBufferOffsets           *p_FmPortBufferOffsets,
++                                        uint8_t                       *internalBufferOffset);
++
++t_Error     FmSpCheckIntContextParams(t_FmSpIntContextDataCopy *p_FmSpIntContextDataCopy);
++t_Error     FmSpCheckBufPoolsParams(t_FmExtPools *p_FmExtPools,
++                                    t_FmBackupBmPools *p_FmBackupBmPools,
++                                    t_FmBufPoolDepletion *p_FmBufPoolDepletion);
++t_Error     FmSpCheckBufMargins(t_FmSpBufMargins *p_FmSpBufMargins);
++void        FmSpSetBufPoolsInAscOrderOfBufSizes(t_FmExtPools *p_FmExtPools, uint8_t *orderedArray, uint16_t *sizesArray);
++
++t_Error     FmPcdSpAllocProfiles(t_Handle h_FmPcd,
++                                 uint8_t  hardwarePortId,
++                                 uint16_t numOfStorageProfiles,
++                                 uint16_t *base,
++                                 uint8_t  *log2Num);
++t_Error     FmPcdSpGetAbsoluteProfileId(t_Handle                        h_FmPcd,
++                                        t_Handle                        h_FmPort,
++                                        uint16_t                        relativeProfile,
++                                        uint16_t                        *p_AbsoluteId);
++void SpInvalidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId);
++void SpValidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId);
++
++
++#endif /* __FM_SP_COMMON_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/etc/Makefile
+@@ -0,0 +1,12 @@
++#
++# Makefile for the Freescale Ethernet controllers
++#
++ccflags-y           += -DVERSION=\"\"
++#
++#Include netcomm SW specific definitions
++
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++
++obj-y         += fsl-ncsw-etc.o
++
++fsl-ncsw-etc-objs     := mm.o memcpy.o sprint.o list.o error.o
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/etc/error.c
+@@ -0,0 +1,95 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/*
++
++ @File          error.c
++
++ @Description   General errors and events reporting utilities.
++*//***************************************************************************/
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++#include "error_ext.h"
++
++
++const char *dbgLevelStrings[] =
++{
++     "CRITICAL"
++    ,"MAJOR"
++    ,"MINOR"
++    ,"WARNING"
++    ,"INFO"
++    ,"TRACE"
++};
++
++
++char * ErrTypeStrings (e_ErrorType err)
++{
++    switch (err)
++    {
++        case (E_OK):                    return "OK";
++        case (E_WRITE_FAILED):          return "Write Access Failed";
++        case (E_NO_DEVICE):             return "No Device";
++        case (E_NOT_AVAILABLE):         return "Resource Is Unavailable";
++        case (E_NO_MEMORY):             return "Memory Allocation Failed";
++        case (E_INVALID_ADDRESS):       return "Invalid Address";
++        case (E_BUSY):                  return "Resource Is Busy";
++        case (E_ALREADY_EXISTS):        return "Resource Already Exists";
++        case (E_INVALID_OPERATION):     return "Invalid Operation";
++        case (E_INVALID_VALUE):         return "Invalid Value";
++        case (E_NOT_IN_RANGE):          return "Value Out Of Range";
++        case (E_NOT_SUPPORTED):         return "Unsupported Operation";
++        case (E_INVALID_STATE):         return "Invalid State";
++        case (E_INVALID_HANDLE):        return "Invalid Handle";
++        case (E_INVALID_ID):            return "Invalid ID";
++        case (E_NULL_POINTER):          return "Unexpected NULL Pointer";
++        case (E_INVALID_SELECTION):     return "Invalid Selection";
++        case (E_INVALID_COMM_MODE):     return "Invalid Communication Mode";
++        case (E_INVALID_MEMORY_TYPE):   return "Invalid Memory Type";
++        case (E_INVALID_CLOCK):         return "Invalid Clock";
++        case (E_CONFLICT):              return "Conflict In Settings";
++        case (E_NOT_ALIGNED):           return "Incorrect Alignment";
++        case (E_NOT_FOUND):             return "Resource Not Found";
++        case (E_FULL):                  return "Resource Is Full";
++        case (E_EMPTY):                 return "Resource Is Empty";
++        case (E_ALREADY_FREE):          return "Resource Already Free";
++        case (E_READ_FAILED):           return "Read Access Failed";
++        case (E_INVALID_FRAME):         return "Invalid Frame";
++        case (E_SEND_FAILED):           return "Send Operation Failed";
++        case (E_RECEIVE_FAILED):        return "Receive Operation Failed";
++        case (E_TIMEOUT):               return "Operation Timed Out";
++        default:
++            break;
++    }
++    return NULL;
++}
++#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/etc/list.c
+@@ -0,0 +1,71 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++
++ @File          list.c
++
++ @Description   Implementation of list.
++*//***************************************************************************/
++#include "std_ext.h"
++#include "list_ext.h"
++
++
++void LIST_Append(t_List *p_NewList, t_List *p_Head)
++{
++    t_List *p_First = LIST_FIRST(p_NewList);
++
++    if (p_First != p_NewList)
++    {
++        t_List *p_Last  = LIST_LAST(p_NewList);
++        t_List *p_Cur   = LIST_NEXT(p_Head);
++
++        LIST_PREV(p_First) = p_Head;
++        LIST_FIRST(p_Head) = p_First;
++        LIST_NEXT(p_Last)  = p_Cur;
++        LIST_LAST(p_Cur)   = p_Last;
++    }
++}
++
++
++int LIST_NumOfObjs(t_List *p_List)
++{
++    t_List *p_Tmp;
++    int    numOfObjs = 0;
++
++    if (!LIST_IsEmpty(p_List))
++        LIST_FOR_EACH(p_Tmp, p_List)
++            numOfObjs++;
++
++    return numOfObjs;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/etc/memcpy.c
+@@ -0,0 +1,620 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++
++#include "std_ext.h"
++#include "xx_ext.h"
++#include "memcpy_ext.h"
++
++void * MemCpy8(void* pDst, void* pSrc, uint32_t size)
++{
++    int i;
++
++    for(i = 0; i < size; ++i)
++        *(((uint8_t*)(pDst)) + i) = *(((uint8_t*)(pSrc)) + i);
++
++    return pDst;
++}
++
++void * MemSet8(void* pDst, int c, uint32_t size)
++{
++    int i;
++
++    for(i = 0; i < size; ++i)
++        *(((uint8_t*)(pDst)) + i) = (uint8_t)(c);
++
++    return pDst;
++}
++
++void * MemCpy32(void* pDst,void* pSrc, uint32_t size)
++{
++    uint32_t leftAlign;
++    uint32_t rightAlign;
++    uint32_t lastWord;
++    uint32_t currWord;
++    uint32_t *p_Src32;
++    uint32_t *p_Dst32;
++    uint8_t  *p_Src8;
++    uint8_t  *p_Dst8;
++
++    p_Src8 = (uint8_t*)(pSrc);
++    p_Dst8 = (uint8_t*)(pDst);
++    /* first copy byte by byte till the source first alignment
++     * this step is necessary to ensure we do not even try to access
++     * data which is before the source buffer, hence it is not ours.
++     */
++    while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */
++    {
++        *p_Dst8++ = *p_Src8++;
++        size--;
++    }
++
++    /* align destination (possibly disaligning source)*/
++    while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */
++    {
++        *p_Dst8++ = *p_Src8++;
++        size--;
++    }
++
++    /* dest is aligned and source is not necessarily aligned */
++    leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */
++    rightAlign = 32 - leftAlign;
++
++
++    if (leftAlign == 0)
++    {
++        /* source is also aligned */
++        p_Src32 = (uint32_t*)(p_Src8);
++        p_Dst32 = (uint32_t*)(p_Dst8);
++        while (size >> 2) /* size >= 4 */
++        {
++            *p_Dst32++ = *p_Src32++;
++            size -= 4;
++        }
++        p_Src8 = (uint8_t*)(p_Src32);
++        p_Dst8 = (uint8_t*)(p_Dst32);
++    }
++    else
++    {
++        /* source is not aligned (destination is aligned)*/
++        p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3));
++        p_Dst32 = (uint32_t*)(p_Dst8);
++        lastWord = *p_Src32++;
++        while(size >> 3) /* size >= 8 */
++        {
++            currWord = *p_Src32;
++            *p_Dst32 = (lastWord << leftAlign) | (currWord >> rightAlign);
++            lastWord = currWord;
++            p_Src32++;
++            p_Dst32++;
++            size -= 4;
++        }
++        p_Dst8 = (uint8_t*)(p_Dst32);
++        p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3);
++    }
++
++    /* complete the left overs */
++    while (size--)
++        *p_Dst8++ = *p_Src8++;
++
++    return pDst;
++}
++
++void * IO2IOCpy32(void* pDst,void* pSrc, uint32_t size)
++{
++    uint32_t leftAlign;
++    uint32_t rightAlign;
++    uint32_t lastWord;
++    uint32_t currWord;
++    uint32_t *p_Src32;
++    uint32_t *p_Dst32;
++    uint8_t  *p_Src8;
++    uint8_t  *p_Dst8;
++
++    p_Src8 = (uint8_t*)(pSrc);
++    p_Dst8 = (uint8_t*)(pDst);
++    /* first copy byte by byte till the source first alignment
++     * this step is necessary to ensure we do not even try to access
++     * data which is before the source buffer, hence it is not ours.
++     */
++    while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */
++    {
++        WRITE_UINT8(*p_Dst8, GET_UINT8(*p_Src8));
++        p_Dst8++;p_Src8++;
++        size--;
++    }
++
++    /* align destination (possibly disaligning source)*/
++    while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */
++    {
++        WRITE_UINT8(*p_Dst8, GET_UINT8(*p_Src8));
++        p_Dst8++;p_Src8++;
++        size--;
++    }
++
++    /* dest is aligned and source is not necessarily aligned */
++    leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */
++    rightAlign = 32 - leftAlign;
++
++    if (leftAlign == 0)
++    {
++        /* source is also aligned */
++        p_Src32 = (uint32_t*)(p_Src8);
++        p_Dst32 = (uint32_t*)(p_Dst8);
++        while (size >> 2) /* size >= 4 */
++        {
++            WRITE_UINT32(*p_Dst32, GET_UINT32(*p_Src32));
++            p_Dst32++;p_Src32++;
++            size -= 4;
++        }
++        p_Src8 = (uint8_t*)(p_Src32);
++        p_Dst8 = (uint8_t*)(p_Dst32);
++    }
++    else
++    {
++        /* source is not aligned (destination is aligned)*/
++        p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3));
++        p_Dst32 = (uint32_t*)(p_Dst8);
++        lastWord = GET_UINT32(*p_Src32);
++        p_Src32++;
++        while(size >> 3) /* size >= 8 */
++        {
++            currWord = GET_UINT32(*p_Src32);
++            WRITE_UINT32(*p_Dst32, (lastWord << leftAlign) | (currWord >> rightAlign));
++            lastWord = currWord;
++            p_Src32++;p_Dst32++;
++            size -= 4;
++        }
++        p_Dst8 = (uint8_t*)(p_Dst32);
++        p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3);
++    }
++
++    /* complete the left overs */
++    while (size--)
++    {
++        WRITE_UINT8(*p_Dst8, GET_UINT8(*p_Src8));
++        p_Dst8++;p_Src8++;
++    }
++
++    return pDst;
++}
++
++void * Mem2IOCpy32(void* pDst,void* pSrc, uint32_t size)
++{
++    uint32_t leftAlign;
++    uint32_t rightAlign;
++    uint32_t lastWord;
++    uint32_t currWord;
++    uint32_t *p_Src32;
++    uint32_t *p_Dst32;
++    uint8_t  *p_Src8;
++    uint8_t  *p_Dst8;
++
++    p_Src8 = (uint8_t*)(pSrc);
++    p_Dst8 = (uint8_t*)(pDst);
++    /* first copy byte by byte till the source first alignment
++     * this step is necessary to ensure we do not even try to access
++     * data which is before the source buffer, hence it is not ours.
++     */
++    while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */
++    {
++        WRITE_UINT8(*p_Dst8, *p_Src8);
++        p_Dst8++;p_Src8++;
++        size--;
++    }
++
++    /* align destination (possibly disaligning source)*/
++    while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */
++    {
++        WRITE_UINT8(*p_Dst8, *p_Src8);
++        p_Dst8++;p_Src8++;
++        size--;
++    }
++
++    /* dest is aligned and source is not necessarily aligned */
++    leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */
++    rightAlign = 32 - leftAlign;
++
++    if (leftAlign == 0)
++    {
++        /* source is also aligned */
++        p_Src32 = (uint32_t*)(p_Src8);
++        p_Dst32 = (uint32_t*)(p_Dst8);
++        while (size >> 2) /* size >= 4 */
++        {
++            WRITE_UINT32(*p_Dst32, *p_Src32);
++            p_Dst32++;p_Src32++;
++            size -= 4;
++        }
++        p_Src8 = (uint8_t*)(p_Src32);
++        p_Dst8 = (uint8_t*)(p_Dst32);
++    }
++    else
++    {
++        /* source is not aligned (destination is aligned)*/
++        p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3));
++        p_Dst32 = (uint32_t*)(p_Dst8);
++        lastWord = *p_Src32++;
++        while(size >> 3) /* size >= 8 */
++        {
++            currWord = *p_Src32;
++            WRITE_UINT32(*p_Dst32, (lastWord << leftAlign) | (currWord >> rightAlign));
++            lastWord = currWord;
++            p_Src32++;p_Dst32++;
++            size -= 4;
++        }
++        p_Dst8 = (uint8_t*)(p_Dst32);
++        p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3);
++    }
++
++    /* complete the left overs */
++    while (size--)
++    {
++        WRITE_UINT8(*p_Dst8, *p_Src8);
++        p_Dst8++;p_Src8++;
++    }
++
++    return pDst;
++}
++
++void * IO2MemCpy32(void* pDst,void* pSrc, uint32_t size)
++{
++    uint32_t leftAlign;
++    uint32_t rightAlign;
++    uint32_t lastWord;
++    uint32_t currWord;
++    uint32_t *p_Src32;
++    uint32_t *p_Dst32;
++    uint8_t  *p_Src8;
++    uint8_t  *p_Dst8;
++
++    p_Src8 = (uint8_t*)(pSrc);
++    p_Dst8 = (uint8_t*)(pDst);
++    /* first copy byte by byte till the source first alignment
++     * this step is necessary to ensure we do not even try to access
++     * data which is before the source buffer, hence it is not ours.
++     */
++    while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */
++    {
++        *p_Dst8 = GET_UINT8(*p_Src8);
++        p_Dst8++;p_Src8++;
++        size--;
++    }
++
++    /* align destination (possibly disaligning source)*/
++    while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */
++    {
++        *p_Dst8 = GET_UINT8(*p_Src8);
++        p_Dst8++;p_Src8++;
++        size--;
++    }
++
++    /* dest is aligned and source is not necessarily aligned */
++    leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */
++    rightAlign = 32 - leftAlign;
++
++    if (leftAlign == 0)
++    {
++        /* source is also aligned */
++        p_Src32 = (uint32_t*)(p_Src8);
++        p_Dst32 = (uint32_t*)(p_Dst8);
++        while (size >> 2) /* size >= 4 */
++        {
++            *p_Dst32 = GET_UINT32(*p_Src32);
++            p_Dst32++;p_Src32++;
++            size -= 4;
++        }
++        p_Src8 = (uint8_t*)(p_Src32);
++        p_Dst8 = (uint8_t*)(p_Dst32);
++    }
++    else
++    {
++        /* source is not aligned (destination is aligned)*/
++        p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3));
++        p_Dst32 = (uint32_t*)(p_Dst8);
++        lastWord = GET_UINT32(*p_Src32);
++        p_Src32++;
++        while(size >> 3) /* size >= 8 */
++        {
++            currWord = GET_UINT32(*p_Src32);
++            *p_Dst32 = (lastWord << leftAlign) | (currWord >> rightAlign);
++            lastWord = currWord;
++            p_Src32++;p_Dst32++;
++            size -= 4;
++        }
++        p_Dst8 = (uint8_t*)(p_Dst32);
++        p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3);
++    }
++
++    /* complete the left overs */
++    while (size--)
++    {
++        *p_Dst8 = GET_UINT8(*p_Src8);
++        p_Dst8++;p_Src8++;
++    }
++
++    return pDst;
++}
++
++void * MemCpy64(void* pDst,void* pSrc, uint32_t size)
++{
++    uint32_t leftAlign;
++    uint32_t rightAlign;
++    uint64_t lastWord;
++    uint64_t currWord;
++    uint64_t *pSrc64;
++    uint64_t *pDst64;
++    uint8_t  *p_Src8;
++    uint8_t  *p_Dst8;
++
++    p_Src8 = (uint8_t*)(pSrc);
++    p_Dst8 = (uint8_t*)(pDst);
++    /* first copy byte by byte till the source first alignment
++     * this step is necessarily to ensure we do not even try to access
++     * data which is before the source buffer, hence it is not ours.
++     */
++    while((PTR_TO_UINT(p_Src8) & 7) && size) /* (pSrc mod 8) > 0 and size > 0 */
++    {
++        *p_Dst8++ = *p_Src8++;
++        size--;
++    }
++
++    /* align destination (possibly disaligning source)*/
++    while((PTR_TO_UINT(p_Dst8) & 7) && size) /* (pDst mod 8) > 0 and size > 0 */
++    {
++        *p_Dst8++ = *p_Src8++;
++        size--;
++    }
++
++    /* dest is aligned and source is not necessarily aligned */
++    leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 7) << 3); /* leftAlign = (pSrc mod 8)*8 */
++    rightAlign = 64 - leftAlign;
++
++
++    if (leftAlign == 0)
++    {
++        /* source is also aligned */
++        pSrc64 = (uint64_t*)(p_Src8);
++        pDst64 = (uint64_t*)(p_Dst8);
++        while (size >> 3) /* size >= 8 */
++        {
++            *pDst64++ = *pSrc64++;
++            size -= 8;
++        }
++        p_Src8 = (uint8_t*)(pSrc64);
++        p_Dst8 = (uint8_t*)(pDst64);
++    }
++    else
++    {
++        /* source is not aligned (destination is aligned)*/
++        pSrc64 = (uint64_t*)(p_Src8 - (leftAlign >> 3));
++        pDst64 = (uint64_t*)(p_Dst8);
++        lastWord = *pSrc64++;
++        while(size >> 4) /* size >= 16 */
++        {
++            currWord = *pSrc64;
++            *pDst64 = (lastWord << leftAlign) | (currWord >> rightAlign);
++            lastWord = currWord;
++            pSrc64++;
++            pDst64++;
++            size -= 8;
++        }
++        p_Dst8 = (uint8_t*)(pDst64);
++        p_Src8 = (uint8_t*)(pSrc64) - 8 + (leftAlign >> 3);
++    }
++
++    /* complete the left overs */
++    while (size--)
++        *p_Dst8++ = *p_Src8++;
++
++    return pDst;
++}
++
++void * MemSet32(void* pDst, uint8_t val, uint32_t size)
++{
++    uint32_t val32;
++    uint32_t *p_Dst32;
++    uint8_t  *p_Dst8;
++
++    p_Dst8 = (uint8_t*)(pDst);
++
++    /* generate four 8-bit val's in 32-bit container */
++    val32  = (uint32_t) val;
++    val32 |= (val32 <<  8);
++    val32 |= (val32 << 16);
++
++    /* align destination to 32 */
++    while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */
++    {
++        *p_Dst8++ = val;
++        size--;
++    }
++
++    /* 32-bit chunks */
++    p_Dst32 = (uint32_t*)(p_Dst8);
++    while (size >> 2) /* size >= 4 */
++    {
++        *p_Dst32++ = val32;
++        size -= 4;
++    }
++
++    /* complete the leftovers */
++    p_Dst8 = (uint8_t*)(p_Dst32);
++    while (size--)
++        *p_Dst8++ = val;
++
++    return pDst;
++}
++
++void * IOMemSet32(void* pDst, uint8_t val, uint32_t size)
++{
++    uint32_t val32;
++    uint32_t *p_Dst32;
++    uint8_t  *p_Dst8;
++
++    p_Dst8 = (uint8_t*)(pDst);
++
++    /* generate four 8-bit val's in 32-bit container */
++    val32  = (uint32_t) val;
++    val32 |= (val32 <<  8);
++    val32 |= (val32 << 16);
++
++    /* align destination to 32 */
++    while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */
++    {
++        WRITE_UINT8(*p_Dst8, val);
++        p_Dst8++;
++        size--;
++    }
++
++    /* 32-bit chunks */
++    p_Dst32 = (uint32_t*)(p_Dst8);
++    while (size >> 2) /* size >= 4 */
++    {
++        WRITE_UINT32(*p_Dst32, val32);
++        p_Dst32++;
++        size -= 4;
++    }
++
++    /* complete the leftovers */
++    p_Dst8 = (uint8_t*)(p_Dst32);
++    while (size--)
++    {
++        WRITE_UINT8(*p_Dst8, val);
++        p_Dst8++;
++    }
++
++    return pDst;
++}
++
++void * MemSet64(void* pDst, uint8_t val, uint32_t size)
++{
++    uint64_t val64;
++    uint64_t *pDst64;
++    uint8_t  *p_Dst8;
++
++    p_Dst8 = (uint8_t*)(pDst);
++
++    /* generate four 8-bit val's in 32-bit container */
++    val64  = (uint64_t) val;
++    val64 |= (val64 <<  8);
++    val64 |= (val64 << 16);
++    val64 |= (val64 << 24);
++    val64 |= (val64 << 32);
++
++    /* align destination to 64 */
++    while((PTR_TO_UINT(p_Dst8) & 7) && size) /* (pDst mod 8) > 0 and size > 0 */
++    {
++        *p_Dst8++ = val;
++        size--;
++    }
++
++    /* 64-bit chunks */
++    pDst64 = (uint64_t*)(p_Dst8);
++    while (size >> 4) /* size >= 8 */
++    {
++        *pDst64++ = val64;
++        size -= 8;
++    }
++
++    /* complete the leftovers */
++    p_Dst8 = (uint8_t*)(pDst64);
++    while (size--)
++        *p_Dst8++ = val;
++
++    return pDst;
++}
++
++void MemDisp(uint8_t *p, int size)
++{
++    uint32_t    space = (uint32_t)(PTR_TO_UINT(p) & 0x3);
++    uint8_t     *p_Limit;
++
++    if (space)
++    {
++        p_Limit = (p - space + 4);
++
++        XX_Print("0x%08X: ", (p - space));
++
++        while (space--)
++        {
++            XX_Print("--");
++        }
++        while (size  && (p < p_Limit))
++        {
++            XX_Print("%02x", *(uint8_t*)p);
++            size--;
++            p++;
++        }
++
++        XX_Print(" ");
++        p_Limit += 12;
++
++        while ((size > 3) && (p < p_Limit))
++        {
++            XX_Print("%08x ", *(uint32_t*)p);
++            size -= 4;
++            p += 4;
++        }
++        XX_Print("\r\n");
++    }
++
++    while (size > 15)
++    {
++        XX_Print("0x%08X: %08x %08x %08x %08x\r\n",
++                 p, *(uint32_t *)p, *(uint32_t *)(p + 4),
++                 *(uint32_t *)(p + 8), *(uint32_t *)(p + 12));
++        size -= 16;
++        p += 16;
++    }
++
++    if (size)
++    {
++        XX_Print("0x%08X: ", p);
++
++        while (size > 3)
++        {
++            XX_Print("%08x ", *(uint32_t *)p);
++            size -= 4;
++            p += 4;
++        }
++        while (size)
++        {
++            XX_Print("%02x", *(uint8_t *)p);
++            size--;
++            p++;
++        }
++
++        XX_Print("\r\n");
++    }
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/etc/mm.c
+@@ -0,0 +1,1155 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#include "string_ext.h"
++#include "error_ext.h"
++#include "std_ext.h"
++#include "part_ext.h"
++#include "xx_ext.h"
++
++#include "mm.h"
++
++
++
++
++/**********************************************************************
++ *                     MM internal routines set                       *
++ **********************************************************************/
++
++/****************************************************************
++ *  Routine:   CreateBusyBlock
++ *
++ *  Description:
++ *      Initializes a new busy block of "size" bytes and started
++ *      rom "base" address. Each busy block has a name that
++ *      specified the purpose of the memory allocation.
++ *
++ *  Arguments:
++ *      base      - base address of the busy block
++ *      size      - size of the busy block
++ *      name      - name that specified the busy block
++ *
++ *  Return value:
++ *      A pointer to new created structure returned on success;
++ *      Otherwise, NULL.
++ ****************************************************************/
++static t_BusyBlock * CreateBusyBlock(uint64_t base, uint64_t size, char *name)
++{
++    t_BusyBlock *p_BusyBlock;
++    uint32_t    n;
++
++    p_BusyBlock = (t_BusyBlock *)XX_Malloc(sizeof(t_BusyBlock));
++    if ( !p_BusyBlock )
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++        return NULL;
++    }
++
++    p_BusyBlock->base = base;
++    p_BusyBlock->end = base + size;
++
++    n = strlen(name);
++    if (n >= MM_MAX_NAME_LEN)
++        n = MM_MAX_NAME_LEN - 1;
++    strncpy(p_BusyBlock->name, name, MM_MAX_NAME_LEN-1);
++    p_BusyBlock->name[n] = '\0';
++    p_BusyBlock->p_Next = 0;
++
++    return p_BusyBlock;
++}
++
++/****************************************************************
++ *  Routine:   CreateNewBlock
++ *
++ *  Description:
++ *      Initializes a new memory block of "size" bytes and started
++ *      from "base" address.
++ *
++ *  Arguments:
++ *      base    - base address of the memory block
++ *      size    - size of the memory block
++ *
++ *  Return value:
++ *      A pointer to new created structure returned on success;
++ *      Otherwise, NULL.
++ ****************************************************************/
++static t_MemBlock * CreateNewBlock(uint64_t base, uint64_t size)
++{
++    t_MemBlock *p_MemBlock;
++
++    p_MemBlock = (t_MemBlock *)XX_Malloc(sizeof(t_MemBlock));
++    if ( !p_MemBlock )
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++        return NULL;
++    }
++
++    p_MemBlock->base = base;
++    p_MemBlock->end = base+size;
++    p_MemBlock->p_Next = 0;
++
++    return p_MemBlock;
++}
++
++/****************************************************************
++ *  Routine:   CreateFreeBlock
++ *
++ *  Description:
++ *      Initializes a new free block of of "size" bytes and
++ *      started from "base" address.
++ *
++ *  Arguments:
++ *      base      - base address of the free block
++ *      size      - size of the free block
++ *
++ *  Return value:
++ *      A pointer to new created structure returned on success;
++ *      Otherwise, NULL.
++ ****************************************************************/
++static t_FreeBlock * CreateFreeBlock(uint64_t base, uint64_t size)
++{
++    t_FreeBlock *p_FreeBlock;
++
++    p_FreeBlock = (t_FreeBlock *)XX_Malloc(sizeof(t_FreeBlock));
++    if ( !p_FreeBlock )
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++        return NULL;
++    }
++
++    p_FreeBlock->base = base;
++    p_FreeBlock->end = base + size;
++    p_FreeBlock->p_Next = 0;
++
++    return p_FreeBlock;
++}
++
++/****************************************************************
++ *  Routine:    AddFree
++ *
++ *  Description:
++ *      Adds a new free block to the free lists. It updates each
++ *      free list to include a new free block.
++ *      Note, that all free block in each free list are ordered
++ *      by their base address.
++ *
++ *  Arguments:
++ *      p_MM  - pointer to the MM object
++ *      base  - base address of a given free block
++ *      end   - end address of a given free block
++ *
++ *  Return value:
++ *
++ *
++ ****************************************************************/
++static t_Error AddFree(t_MM *p_MM, uint64_t base, uint64_t end)
++{
++    t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB;
++    uint64_t    alignment;
++    uint64_t    alignBase;
++    int         i;
++
++    /* Updates free lists to include  a just released block */
++    for (i=0; i <= MM_MAX_ALIGNMENT; i++)
++    {
++        p_PrevB = p_NewB = 0;
++        p_CurrB = p_MM->freeBlocks[i];
++
++        alignment = (uint64_t)(0x1 << i);
++        alignBase = MAKE_ALIGNED(base, alignment);
++
++        /* Goes to the next free list if there is no block to free */
++        if (alignBase >= end)
++            continue;
++
++        /* Looks for a free block that should be updated */
++        while ( p_CurrB )
++        {
++            if ( alignBase <= p_CurrB->end )
++            {
++                if ( end > p_CurrB->end )
++                {
++                    t_FreeBlock *p_NextB;
++                    while ( p_CurrB->p_Next && end > p_CurrB->p_Next->end )
++                    {
++                        p_NextB = p_CurrB->p_Next;
++                        p_CurrB->p_Next = p_CurrB->p_Next->p_Next;
++                        XX_Free(p_NextB);
++                    }
++
++                    p_NextB = p_CurrB->p_Next;
++                    if ( !p_NextB || (p_NextB && end < p_NextB->base) )
++                    {
++                        p_CurrB->end = end;
++                    }
++                    else
++                    {
++                        p_CurrB->end = p_NextB->end;
++                        p_CurrB->p_Next = p_NextB->p_Next;
++                        XX_Free(p_NextB);
++                    }
++                }
++                else if ( (end < p_CurrB->base) && ((end-alignBase) >= alignment) )
++                {
++                    if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL)
++                        RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++
++                    p_NewB->p_Next = p_CurrB;
++                    if (p_PrevB)
++                        p_PrevB->p_Next = p_NewB;
++                    else
++                        p_MM->freeBlocks[i] = p_NewB;
++                    break;
++                }
++
++                if ((alignBase < p_CurrB->base) && (end >= p_CurrB->base))
++                {
++                    p_CurrB->base = alignBase;
++                }
++
++                /* if size of the free block is less then alignment
++                 * deletes that free block from the free list. */
++                if ( (p_CurrB->end - p_CurrB->base) < alignment)
++                {
++                    if ( p_PrevB )
++                        p_PrevB->p_Next = p_CurrB->p_Next;
++                    else
++                        p_MM->freeBlocks[i] = p_CurrB->p_Next;
++                    XX_Free(p_CurrB);
++                    p_CurrB = NULL;
++                }
++                break;
++            }
++            else
++            {
++                p_PrevB = p_CurrB;
++                p_CurrB = p_CurrB->p_Next;
++            }
++        }
++
++        /* If no free block found to be updated, insert a new free block
++         * to the end of the free list.
++         */
++        if ( !p_CurrB && ((((uint64_t)(end-base)) & ((uint64_t)(alignment-1))) == 0) )
++        {
++            if ((p_NewB = CreateFreeBlock(alignBase, end-base)) == NULL)
++                RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++
++            if (p_PrevB)
++                p_PrevB->p_Next = p_NewB;
++            else
++                p_MM->freeBlocks[i] = p_NewB;
++        }
++
++        /* Update boundaries of the new free block */
++        if ((alignment == 1) && !p_NewB)
++        {
++            if ( p_CurrB && base > p_CurrB->base )
++                base = p_CurrB->base;
++            if ( p_CurrB && end < p_CurrB->end )
++                end = p_CurrB->end;
++        }
++    }
++
++    return (E_OK);
++}
++
++/****************************************************************
++ *  Routine:      CutFree
++ *
++ *  Description:
++ *      Cuts a free block from holdBase to holdEnd from the free lists.
++ *      That is, it updates all free lists of the MM object do
++ *      not include a block of memory from holdBase to holdEnd.
++ *      For each free lists it seek for a free block that holds
++ *      either holdBase or holdEnd. If such block is found it updates it.
++ *
++ *  Arguments:
++ *      p_MM            - pointer to the MM object
++ *      holdBase        - base address of the allocated block
++ *      holdEnd         - end address of the allocated block
++ *
++ *  Return value:
++ *      E_OK is returned on success,
++ *      otherwise returns an error code.
++ *
++ ****************************************************************/
++static t_Error CutFree(t_MM *p_MM, uint64_t holdBase, uint64_t holdEnd)
++{
++    t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB;
++    uint64_t    alignBase, base, end;
++    uint64_t    alignment;
++    int         i;
++
++    for (i=0; i <= MM_MAX_ALIGNMENT; i++)
++    {
++        p_PrevB = p_NewB = 0;
++        p_CurrB = p_MM->freeBlocks[i];
++
++        alignment = (uint64_t)(0x1 << i);
++        alignBase = MAKE_ALIGNED(holdEnd, alignment);
++
++        while ( p_CurrB )
++        {
++            base = p_CurrB->base;
++            end = p_CurrB->end;
++
++            if ( (holdBase <= base) && (holdEnd <= end) && (holdEnd > base) )
++            {
++                if ( alignBase >= end ||
++                     (alignBase < end && ((end-alignBase) < alignment)) )
++                {
++                    if (p_PrevB)
++                        p_PrevB->p_Next = p_CurrB->p_Next;
++                    else
++                        p_MM->freeBlocks[i] = p_CurrB->p_Next;
++                    XX_Free(p_CurrB);
++                }
++                else
++                {
++                    p_CurrB->base = alignBase;
++                }
++                break;
++            }
++            else if ( (holdBase > base) && (holdEnd <= end) )
++            {
++                if ( (holdBase-base) >= alignment )
++                {
++                    if ( (alignBase < end) && ((end-alignBase) >= alignment) )
++                    {
++                        if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL)
++                            RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++                        p_NewB->p_Next = p_CurrB->p_Next;
++                        p_CurrB->p_Next = p_NewB;
++                    }
++                    p_CurrB->end = holdBase;
++                }
++                else if ( (alignBase < end) && ((end-alignBase) >= alignment) )
++                {
++                    p_CurrB->base = alignBase;
++                }
++                else
++                {
++                    if (p_PrevB)
++                        p_PrevB->p_Next = p_CurrB->p_Next;
++                    else
++                        p_MM->freeBlocks[i] = p_CurrB->p_Next;
++                    XX_Free(p_CurrB);
++                }
++                break;
++            }
++            else
++            {
++                p_PrevB = p_CurrB;
++                p_CurrB = p_CurrB->p_Next;
++            }
++        }
++    }
++
++    return (E_OK);
++}
++
++/****************************************************************
++ *  Routine:     AddBusy
++ *
++ *  Description:
++ *      Adds a new busy block to the list of busy blocks. Note,
++ *      that all busy blocks are ordered by their base address in
++ *      the busy list.
++ *
++ *  Arguments:
++ *      MM              - handler to the MM object
++ *      p_NewBusyB      - pointer to the a busy block
++ *
++ *  Return value:
++ *      None.
++ *
++ ****************************************************************/
++static void AddBusy(t_MM *p_MM, t_BusyBlock *p_NewBusyB)
++{
++    t_BusyBlock *p_CurrBusyB, *p_PrevBusyB;
++
++    /* finds a place of a new busy block in the list of busy blocks */
++    p_PrevBusyB = 0;
++    p_CurrBusyB = p_MM->busyBlocks;
++
++    while ( p_CurrBusyB && p_NewBusyB->base > p_CurrBusyB->base )
++    {
++        p_PrevBusyB = p_CurrBusyB;
++        p_CurrBusyB = p_CurrBusyB->p_Next;
++    }
++
++    /* insert the new busy block into the list of busy blocks */
++    if ( p_CurrBusyB )
++        p_NewBusyB->p_Next = p_CurrBusyB;
++    if ( p_PrevBusyB )
++        p_PrevBusyB->p_Next = p_NewBusyB;
++    else
++        p_MM->busyBlocks = p_NewBusyB;
++}
++
++/****************************************************************
++ *  Routine:    CutBusy
++ *
++ *  Description:
++ *      Cuts a block from base to end from the list of busy blocks.
++ *      This is done by updating the list of busy blocks do not
++ *      include a given block, that block is going to be free. If a
++ *      given block is a part of some other busy block, so that
++ *      busy block is updated. If there are number of busy blocks
++ *      included in the given block, so all that blocks are removed
++ *      from the busy list and the end blocks are updated.
++ *      If the given block devides some block into two parts, a new
++ *      busy block is added to the busy list.
++ *
++ *  Arguments:
++ *      p_MM  - pointer to the MM object
++ *      base  - base address of a given busy block
++ *      end   - end address of a given busy block
++ *
++ *  Return value:
++ *      E_OK on success, E_NOMEMORY otherwise.
++ *
++ ****************************************************************/
++static t_Error CutBusy(t_MM *p_MM, uint64_t base, uint64_t end)
++{
++    t_BusyBlock  *p_CurrB, *p_PrevB, *p_NewB;
++
++    p_CurrB = p_MM->busyBlocks;
++    p_PrevB = p_NewB = 0;
++
++    while ( p_CurrB )
++    {
++        if ( base < p_CurrB->end )
++        {
++            if ( end > p_CurrB->end )
++            {
++                t_BusyBlock *p_NextB;
++                while ( p_CurrB->p_Next && end >= p_CurrB->p_Next->end )
++                {
++                    p_NextB = p_CurrB->p_Next;
++                    p_CurrB->p_Next = p_CurrB->p_Next->p_Next;
++                    XX_Free(p_NextB);
++                }
++
++                p_NextB = p_CurrB->p_Next;
++                if ( p_NextB && end > p_NextB->base )
++                {
++                    p_NextB->base = end;
++                }
++            }
++
++            if ( base <= p_CurrB->base )
++            {
++                if ( end < p_CurrB->end && end > p_CurrB->base )
++                {
++                    p_CurrB->base = end;
++                }
++                else if ( end >= p_CurrB->end )
++                {
++                    if ( p_PrevB )
++                        p_PrevB->p_Next = p_CurrB->p_Next;
++                    else
++                        p_MM->busyBlocks = p_CurrB->p_Next;
++                    XX_Free(p_CurrB);
++                }
++            }
++            else
++            {
++                if ( end < p_CurrB->end && end > p_CurrB->base )
++                {
++                    if ((p_NewB = CreateBusyBlock(end,
++                                                  p_CurrB->end-end,
++                                                  p_CurrB->name)) == NULL)
++                        RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++                    p_NewB->p_Next = p_CurrB->p_Next;
++                    p_CurrB->p_Next = p_NewB;
++                }
++                p_CurrB->end = base;
++            }
++            break;
++        }
++        else
++        {
++            p_PrevB = p_CurrB;
++            p_CurrB = p_CurrB->p_Next;
++        }
++    }
++
++    return (E_OK);
++}
++
++/****************************************************************
++ *  Routine:     MmGetGreaterAlignment
++ *
++ *  Description:
++ *      Allocates a block of memory according to the given size
++ *      and the alignment. That routine is called from the MM_Get
++ *      routine if the required alignment is greater then MM_MAX_ALIGNMENT.
++ *      In that case, it goes over free blocks of 64 byte align list
++ *      and checks if it has the required size of bytes of the required
++ *      alignment. If no blocks found returns ILLEGAL_BASE.
++ *      After the block is found and data is allocated, it calls
++ *      the internal CutFree routine to update all free lists
++ *      do not include a just allocated block. Of course, each
++ *      free list contains a free blocks with the same alignment.
++ *      It is also creates a busy block that holds
++ *      information about an allocated block.
++ *
++ *  Arguments:
++ *      MM              - handle to the MM object
++ *      size            - size of the MM
++ *      alignment       - index as a power of two defines
++ *                        a required alignment that is greater then 64.
++ *      name            - the name that specifies an allocated block.
++ *
++ *  Return value:
++ *      base address of an allocated block.
++ *      ILLEGAL_BASE if can't allocate a block
++ *
++ ****************************************************************/
++static uint64_t MmGetGreaterAlignment(t_MM *p_MM, uint64_t size, uint64_t alignment, char* name)
++{
++    t_FreeBlock *p_FreeB;
++    t_BusyBlock *p_NewBusyB;
++    uint64_t    holdBase, holdEnd, alignBase = 0;
++
++    /* goes over free blocks of the 64 byte alignment list
++       and look for a block of the suitable size and
++       base address according to the alignment. */
++    p_FreeB = p_MM->freeBlocks[MM_MAX_ALIGNMENT];
++
++    while ( p_FreeB )
++    {
++        alignBase = MAKE_ALIGNED(p_FreeB->base, alignment);
++
++        /* the block is found if the aligned base inside the block
++         * and has the anough size. */
++        if ( alignBase >= p_FreeB->base &&
++             alignBase < p_FreeB->end &&
++             size <= (p_FreeB->end - alignBase) )
++            break;
++        else
++            p_FreeB = p_FreeB->p_Next;
++    }
++
++    /* If such block isn't found */
++    if ( !p_FreeB )
++        return (uint64_t)(ILLEGAL_BASE);
++
++    holdBase = alignBase;
++    holdEnd = alignBase + size;
++
++    /* init a new busy block */
++    if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)
++        return (uint64_t)(ILLEGAL_BASE);
++
++    /* calls Update routine to update a lists of free blocks */
++    if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK )
++    {
++        XX_Free(p_NewBusyB);
++        return (uint64_t)(ILLEGAL_BASE);
++    }
++
++    /* insert the new busy block into the list of busy blocks */
++    AddBusy ( p_MM, p_NewBusyB );
++
++    return (holdBase);
++}
++
++
++/**********************************************************************
++ *                     MM API routines set                            *
++ **********************************************************************/
++
++/*****************************************************************************/
++t_Error MM_Init(t_Handle *h_MM, uint64_t base, uint64_t size)
++{
++    t_MM        *p_MM;
++    uint64_t    newBase, newSize;
++    int         i;
++
++    if (!size)
++    {
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Size (should be positive)"));
++    }
++
++    /* Initializes a new MM object */
++    p_MM = (t_MM *)XX_Malloc(sizeof(t_MM));
++    if (!p_MM)
++    {
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++    }
++
++    p_MM->h_Spinlock = XX_InitSpinlock();
++    if (!p_MM->h_Spinlock)
++    {
++        XX_Free(p_MM);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MM spinlock!"));
++    }
++
++    /* Initializes counter of free memory to total size */
++    p_MM->freeMemSize = size;
++
++    /* A busy list is empty */
++    p_MM->busyBlocks = 0;
++
++    /* Initializes a new memory block */
++    if ((p_MM->memBlocks = CreateNewBlock(base, size)) == NULL)
++    {
++        MM_Free(p_MM);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++    }
++
++    /* Initializes a new free block for each free list*/
++    for (i=0; i <= MM_MAX_ALIGNMENT; i++)
++    {
++        newBase = MAKE_ALIGNED( base, (0x1 << i) );
++        newSize = size - (newBase - base);
++
++        if ((p_MM->freeBlocks[i] = CreateFreeBlock(newBase, newSize)) == NULL)
++        {
++            MM_Free(p_MM);
++            RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++        }
++    }
++
++    *h_MM = p_MM;
++
++    return (E_OK);
++}
++
++/*****************************************************************************/
++void MM_Free(t_Handle h_MM)
++{
++    t_MM        *p_MM = (t_MM *)h_MM;
++    t_MemBlock  *p_MemBlock;
++    t_BusyBlock *p_BusyBlock;
++    t_FreeBlock *p_FreeBlock;
++    void        *p_Block;
++    int         i;
++
++    ASSERT_COND(p_MM);
++
++    /* release memory allocated for busy blocks */
++    p_BusyBlock = p_MM->busyBlocks;
++    while ( p_BusyBlock )
++    {
++        p_Block = p_BusyBlock;
++        p_BusyBlock = p_BusyBlock->p_Next;
++        XX_Free(p_Block);
++    }
++
++    /* release memory allocated for free blocks */
++    for (i=0; i <= MM_MAX_ALIGNMENT; i++)
++    {
++        p_FreeBlock = p_MM->freeBlocks[i];
++        while ( p_FreeBlock )
++        {
++            p_Block = p_FreeBlock;
++            p_FreeBlock = p_FreeBlock->p_Next;
++            XX_Free(p_Block);
++        }
++    }
++
++    /* release memory allocated for memory blocks */
++    p_MemBlock = p_MM->memBlocks;
++    while ( p_MemBlock )
++    {
++        p_Block = p_MemBlock;
++        p_MemBlock = p_MemBlock->p_Next;
++        XX_Free(p_Block);
++    }
++
++    if (p_MM->h_Spinlock)
++        XX_FreeSpinlock(p_MM->h_Spinlock);
++
++    /* release memory allocated for MM object itself */
++    XX_Free(p_MM);
++}
++
++/*****************************************************************************/
++uint64_t MM_Get(t_Handle h_MM, uint64_t size, uint64_t alignment, char* name)
++{
++    t_MM        *p_MM = (t_MM *)h_MM;
++    t_FreeBlock *p_FreeB;
++    t_BusyBlock *p_NewBusyB;
++    uint64_t    holdBase, holdEnd, j, i = 0;
++    uint32_t    intFlags;
++
++    SANITY_CHECK_RETURN_VALUE(p_MM, E_INVALID_HANDLE, (uint64_t)ILLEGAL_BASE);
++
++    /* checks that alignment value is greater then zero */
++    if (alignment == 0)
++    {
++        alignment = 1;
++    }
++
++    j = alignment;
++
++    /* checks if alignment is a power of two, if it correct and if the
++       required size is multiple of the given alignment. */
++    while ((j & 0x1) == 0)
++    {
++        i++;
++        j = j >> 1;
++    }
++
++    /* if the given alignment isn't power of two, returns an error */
++    if (j != 1)
++    {
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("alignment (should be power of 2)"));
++        return (uint64_t)ILLEGAL_BASE;
++    }
++
++    if (i > MM_MAX_ALIGNMENT)
++    {
++        return (MmGetGreaterAlignment(p_MM, size, alignment, name));
++    }
++
++    intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
++    /* look for a block of the size greater or equal to the required size. */
++    p_FreeB = p_MM->freeBlocks[i];
++    while ( p_FreeB && (p_FreeB->end - p_FreeB->base) < size )
++        p_FreeB = p_FreeB->p_Next;
++
++    /* If such block is found */
++    if ( !p_FreeB )
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        return (uint64_t)(ILLEGAL_BASE);
++    }
++
++    holdBase = p_FreeB->base;
++    holdEnd = holdBase + size;
++
++    /* init a new busy block */
++    if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        return (uint64_t)(ILLEGAL_BASE);
++    }
++
++    /* calls Update routine to update a lists of free blocks */
++    if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK )
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        XX_Free(p_NewBusyB);
++        return (uint64_t)(ILLEGAL_BASE);
++    }
++
++    /* Decreasing the allocated memory size from free memory size */
++    p_MM->freeMemSize -= size;
++
++    /* insert the new busy block into the list of busy blocks */
++    AddBusy ( p_MM, p_NewBusyB );
++    XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++
++    return (holdBase);
++}
++
++/*****************************************************************************/
++uint64_t MM_GetForce(t_Handle h_MM, uint64_t base, uint64_t size, char* name)
++{
++    t_MM        *p_MM = (t_MM *)h_MM;
++    t_FreeBlock *p_FreeB;
++    t_BusyBlock *p_NewBusyB;
++    uint32_t    intFlags;
++    bool        blockIsFree = FALSE;
++
++    ASSERT_COND(p_MM);
++
++    intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
++    p_FreeB = p_MM->freeBlocks[0]; /* The biggest free blocks are in the
++                                      free list with alignment 1 */
++
++    while ( p_FreeB )
++    {
++        if ( base >= p_FreeB->base && (base+size) <= p_FreeB->end )
++        {
++            blockIsFree = TRUE;
++            break;
++        }
++        else
++            p_FreeB = p_FreeB->p_Next;
++    }
++
++    if ( !blockIsFree )
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        return (uint64_t)(ILLEGAL_BASE);
++    }
++
++    /* init a new busy block */
++    if ((p_NewBusyB = CreateBusyBlock(base, size, name)) == NULL)
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        return (uint64_t)(ILLEGAL_BASE);
++    }
++
++    /* calls Update routine to update a lists of free blocks */
++    if ( CutFree ( p_MM, base, base+size ) != E_OK )
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        XX_Free(p_NewBusyB);
++        return (uint64_t)(ILLEGAL_BASE);
++    }
++
++    /* Decreasing the allocated memory size from free memory size */
++    p_MM->freeMemSize -= size;
++
++    /* insert the new busy block into the list of busy blocks */
++    AddBusy ( p_MM, p_NewBusyB );
++    XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++
++    return (base);
++}
++
++/*****************************************************************************/
++uint64_t MM_GetForceMin(t_Handle h_MM, uint64_t size, uint64_t alignment, uint64_t min, char* name)
++{
++    t_MM        *p_MM = (t_MM *)h_MM;
++    t_FreeBlock *p_FreeB;
++    t_BusyBlock *p_NewBusyB;
++    uint64_t    holdBase, holdEnd, j = alignment, i=0;
++    uint32_t    intFlags;
++
++    ASSERT_COND(p_MM);
++
++    /* checks if alignment is a power of two, if it correct and if the
++       required size is multiple of the given alignment. */
++    while ((j & 0x1) == 0)
++    {
++        i++;
++        j = j >> 1;
++    }
++
++    if ( (j != 1) || (i > MM_MAX_ALIGNMENT) )
++    {
++        return (uint64_t)(ILLEGAL_BASE);
++    }
++
++    intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
++    p_FreeB = p_MM->freeBlocks[i];
++
++    /* look for the first block that contains the minimum
++       base address. If the whole required size may be fit
++       into it, use that block, otherwise look for the next
++       block of size greater or equal to the required size. */
++    while ( p_FreeB && (min >= p_FreeB->end))
++            p_FreeB = p_FreeB->p_Next;
++
++    /* If such block is found */
++    if ( !p_FreeB )
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        return (uint64_t)(ILLEGAL_BASE);
++    }
++
++    /* if this block is large enough, use this block */
++    holdBase = ( min <= p_FreeB->base ) ? p_FreeB->base : min;
++    if ((holdBase + size) <= p_FreeB->end )
++    {
++        holdEnd = holdBase + size;
++    }
++    else
++    {
++        p_FreeB = p_FreeB->p_Next;
++        while ( p_FreeB && ((p_FreeB->end - p_FreeB->base) < size) )
++            p_FreeB = p_FreeB->p_Next;
++
++        /* If such block is found */
++        if ( !p_FreeB )
++        {
++            XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++            return (uint64_t)(ILLEGAL_BASE);
++        }
++
++        holdBase = p_FreeB->base;
++        holdEnd = holdBase + size;
++    }
++
++    /* init a new busy block */
++    if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        return (uint64_t)(ILLEGAL_BASE);
++    }
++
++    /* calls Update routine to update a lists of free blocks */
++    if ( CutFree( p_MM, holdBase, holdEnd ) != E_OK )
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        XX_Free(p_NewBusyB);
++        return (uint64_t)(ILLEGAL_BASE);
++    }
++
++    /* Decreasing the allocated memory size from free memory size */
++    p_MM->freeMemSize -= size;
++
++    /* insert the new busy block into the list of busy blocks */
++    AddBusy( p_MM, p_NewBusyB );
++    XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++
++    return (holdBase);
++}
++
++/*****************************************************************************/
++uint64_t MM_Put(t_Handle h_MM, uint64_t base)
++{
++    t_MM        *p_MM = (t_MM *)h_MM;
++    t_BusyBlock *p_BusyB, *p_PrevBusyB;
++    uint64_t    size;
++    uint32_t    intFlags;
++
++    ASSERT_COND(p_MM);
++
++    /* Look for a busy block that have the given base value.
++     * That block will be returned back to the memory.
++     */
++    p_PrevBusyB = 0;
++
++    intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
++    p_BusyB = p_MM->busyBlocks;
++    while ( p_BusyB && base != p_BusyB->base )
++    {
++        p_PrevBusyB = p_BusyB;
++        p_BusyB = p_BusyB->p_Next;
++    }
++
++    if ( !p_BusyB )
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        return (uint64_t)(0);
++    }
++
++    if ( AddFree( p_MM, p_BusyB->base, p_BusyB->end ) != E_OK )
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        return (uint64_t)(0);
++    }
++
++    /* removes a busy block form the list of busy blocks */
++    if ( p_PrevBusyB )
++        p_PrevBusyB->p_Next = p_BusyB->p_Next;
++    else
++        p_MM->busyBlocks = p_BusyB->p_Next;
++
++    size = p_BusyB->end - p_BusyB->base;
++
++    /* Adding the deallocated memory size to free memory size */
++    p_MM->freeMemSize += size;
++
++    XX_Free(p_BusyB);
++    XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++
++    return (size);
++}
++
++/*****************************************************************************/
++uint64_t MM_PutForce(t_Handle h_MM, uint64_t base, uint64_t size)
++{
++    t_MM        *p_MM = (t_MM *)h_MM;
++    uint64_t    end = base + size;
++    uint32_t    intFlags;
++
++    ASSERT_COND(p_MM);
++
++    intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
++
++    if ( CutBusy( p_MM, base, end ) != E_OK )
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        return (uint64_t)(0);
++    }
++
++    if ( AddFree ( p_MM, base, end ) != E_OK )
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        return (uint64_t)(0);
++    }
++
++    /* Adding the deallocated memory size to free memory size */
++    p_MM->freeMemSize += size;
++
++    XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++
++    return (size);
++}
++
++/*****************************************************************************/
++t_Error MM_Add(t_Handle h_MM, uint64_t base, uint64_t size)
++{
++    t_MM        *p_MM = (t_MM *)h_MM;
++    t_MemBlock  *p_MemB, *p_NewMemB;
++    t_Error     errCode;
++    uint32_t    intFlags;
++
++    ASSERT_COND(p_MM);
++
++    /* find a last block in the list of memory blocks to insert a new
++     * memory block
++     */
++    intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
++
++    p_MemB = p_MM->memBlocks;
++    while ( p_MemB->p_Next )
++    {
++        if ( base >= p_MemB->base && base < p_MemB->end )
++        {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++            RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
++        }
++        p_MemB = p_MemB->p_Next;
++    }
++    /* check for a last memory block */
++    if ( base >= p_MemB->base && base < p_MemB->end )
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
++    }
++
++    /* create a new memory block */
++    if ((p_NewMemB = CreateNewBlock(base, size)) == NULL)
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++    }
++
++    /* append a new memory block to the end of the list of memory blocks */
++    p_MemB->p_Next = p_NewMemB;
++
++    /* add a new free block to the free lists */
++    errCode = AddFree(p_MM, base, base+size);
++    if (errCode)
++    {
++        XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++        p_MemB->p_Next = 0;
++        XX_Free(p_NewMemB);
++        return ((t_Error)errCode);
++    }
++
++    /* Adding the new block size to free memory size */
++    p_MM->freeMemSize += size;
++
++    XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
++
++    return (E_OK);
++}
++
++/*****************************************************************************/
++uint64_t MM_GetMemBlock(t_Handle h_MM, int index)
++{
++    t_MM       *p_MM = (t_MM*)h_MM;
++    t_MemBlock *p_MemBlock;
++    int         i;
++
++    ASSERT_COND(p_MM);
++
++    p_MemBlock = p_MM->memBlocks;
++    for (i=0; i < index; i++)
++        p_MemBlock = p_MemBlock->p_Next;
++
++    if ( p_MemBlock )
++        return (p_MemBlock->base);
++    else
++        return (uint64_t)ILLEGAL_BASE;
++}
++
++/*****************************************************************************/
++uint64_t MM_GetBase(t_Handle h_MM)
++{
++    t_MM       *p_MM = (t_MM*)h_MM;
++    t_MemBlock *p_MemBlock;
++
++    ASSERT_COND(p_MM);
++
++    p_MemBlock = p_MM->memBlocks;
++    return  p_MemBlock->base;
++}
++
++/*****************************************************************************/
++bool MM_InRange(t_Handle h_MM, uint64_t addr)
++{
++    t_MM       *p_MM = (t_MM*)h_MM;
++    t_MemBlock *p_MemBlock;
++
++    ASSERT_COND(p_MM);
++
++    p_MemBlock = p_MM->memBlocks;
++
++    if ((addr >= p_MemBlock->base) && (addr < p_MemBlock->end))
++        return TRUE;
++    else
++        return FALSE;
++}
++
++/*****************************************************************************/
++uint64_t MM_GetFreeMemSize(t_Handle h_MM)
++{
++    t_MM       *p_MM = (t_MM*)h_MM;
++
++    ASSERT_COND(p_MM);
++
++    return p_MM->freeMemSize;
++}
++
++/*****************************************************************************/
++void MM_Dump(t_Handle h_MM)
++{
++    t_MM        *p_MM = (t_MM *)h_MM;
++    t_FreeBlock *p_FreeB;
++    t_BusyBlock *p_BusyB;
++    int          i;
++
++    p_BusyB = p_MM->busyBlocks;
++    XX_Print("List of busy blocks:\n");
++    while (p_BusyB)
++    {
++        XX_Print("\t0x%p: (%s: b=0x%llx, e=0x%llx)\n", p_BusyB, p_BusyB->name, p_BusyB->base, p_BusyB->end );
++        p_BusyB = p_BusyB->p_Next;
++    }
++
++    XX_Print("\nLists of free blocks according to alignment:\n");
++    for (i=0; i <= MM_MAX_ALIGNMENT; i++)
++    {
++        XX_Print("%d alignment:\n", (0x1 << i));
++        p_FreeB = p_MM->freeBlocks[i];
++        while (p_FreeB)
++        {
++            XX_Print("\t0x%p: (b=0x%llx, e=0x%llx)\n", p_FreeB, p_FreeB->base, p_FreeB->end);
++            p_FreeB = p_FreeB->p_Next;
++        }
++        XX_Print("\n");
++    }
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/etc/mm.h
+@@ -0,0 +1,105 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/****************************************************************
++ *
++ * File:  mm.h
++ *
++ *
++ * Description:
++ *  MM (Memory Management) object definitions.
++ *  It also includes definitions of the Free Block, Busy Block
++ *  and Memory Block structures used by the MM object.
++ *
++ ****************************************************************/
++
++#ifndef __MM_H
++#define __MM_H
++
++
++#include "mm_ext.h"
++
++#define __ERR_MODULE__  MODULE_MM
++
++
++#define MAKE_ALIGNED(addr, align)    \
++    (((uint64_t)(addr) + ((align) - 1)) & (~(((uint64_t)align) - 1)))
++
++
++/* t_MemBlock data structure defines parameters of the Memory Block */
++typedef struct t_MemBlock
++{
++    struct t_MemBlock *p_Next;      /* Pointer to the next memory block */
++
++    uint64_t  base;                 /* Base address of the memory block */
++    uint64_t  end;                  /* End address of the memory block */
++} t_MemBlock;
++
++
++/* t_FreeBlock data structure defines parameters of the Free Block */
++typedef struct t_FreeBlock
++{
++    struct t_FreeBlock *p_Next;     /* Pointer to the next free block */
++
++    uint64_t  base;                 /* Base address of the block */
++    uint64_t  end;                  /* End address of the block */
++} t_FreeBlock;
++
++
++/* t_BusyBlock data structure defines parameters of the Busy Block  */
++typedef struct t_BusyBlock
++{
++    struct t_BusyBlock *p_Next;         /* Pointer to the next free block */
++
++    uint64_t    base;                   /* Base address of the block */
++    uint64_t    end;                    /* End address of the block */
++    char        name[MM_MAX_NAME_LEN];  /* That block of memory was allocated for
++                                           something specified by the Name */
++} t_BusyBlock;
++
++
++/* t_MM data structure defines parameters of the MM object */
++typedef struct t_MM
++{
++    t_Handle        h_Spinlock;
++
++    t_MemBlock      *memBlocks;     /* List of memory blocks (Memory list) */
++    t_BusyBlock     *busyBlocks;    /* List of busy blocks (Busy list) */
++    t_FreeBlock     *freeBlocks[MM_MAX_ALIGNMENT + 1];
++                                    /* Alignment lists of free blocks (Free lists) */
++
++    uint64_t        freeMemSize;    /* Total size of free memory (in bytes) */
++} t_MM;
++
++
++#endif /* __MM_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/etc/sprint.c
+@@ -0,0 +1,81 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/*------------------------------------------------------*/
++/* File: sprint.c                                       */
++/*                                                      */
++/* Description:                                         */
++/*    Debug routines (externals)                        */
++/*------------------------------------------------------*/
++#include "string_ext.h"
++#include "stdlib_ext.h"
++#include "stdarg_ext.h"
++#include "sprint_ext.h"
++#include "std_ext.h"
++#include "xx_ext.h"
++
++
++int Sprint(char * buf, const char *fmt, ...)
++{
++    va_list args;
++    int i;
++
++    va_start(args, fmt);
++    i=vsprintf(buf,fmt,args);
++    va_end(args);
++    return i;
++}
++
++int Snprint(char * buf, uint32_t size, const char *fmt, ...)
++{
++    va_list args;
++    int i;
++
++    va_start(args, fmt);
++    i=vsnprintf(buf,size,fmt,args);
++    va_end(args);
++    return i;
++}
++
++#ifndef NCSW_VXWORKS
++int Sscan(const char * buf, const char * fmt, ...)
++{
++    va_list args;
++    int i;
++
++    va_start(args,fmt);
++    i = vsscanf(buf,fmt,args);
++    va_end(args);
++    return i;
++}
++#endif /* NCSW_VXWORKS */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/fmanv3h_dflags.h
+@@ -0,0 +1,57 @@
++/*
++ * Copyright 2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __dflags_h
++#define __dflags_h
++
++
++#define NCSW_LINUX
++
++#define T4240
++#define NCSW_PPC_CORE
++
++#define DEBUG_ERRORS        1
++
++#if defined(DEBUG)
++#define DEBUG_GLOBAL_LEVEL  REPORT_LEVEL_INFO
++
++#define DEBUG_XX_MALLOC
++#define DEBUG_MEM_LEAKS
++
++#else
++#define DEBUG_GLOBAL_LEVEL  REPORT_LEVEL_WARNING
++#endif /* (DEBUG) */
++
++#define REPORT_EVENTS       1
++#define EVENT_GLOBAL_LEVEL  REPORT_LEVEL_MINOR
++
++#endif /* __dflags_h */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/fmanv3l_dflags.h
+@@ -0,0 +1,56 @@
++/*
++ * Copyright 2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __dflags_h
++#define __dflags_h
++
++
++#define NCSW_LINUX
++
++#define NCSW_PPC_CORE
++
++#define DEBUG_ERRORS        1
++
++#if defined(DEBUG)
++#define DEBUG_GLOBAL_LEVEL  REPORT_LEVEL_INFO
++
++#define DEBUG_XX_MALLOC
++#define DEBUG_MEM_LEAKS
++
++#else
++#define DEBUG_GLOBAL_LEVEL  REPORT_LEVEL_WARNING
++#endif /* (DEBUG) */
++
++#define REPORT_EVENTS       1
++#define EVENT_GLOBAL_LEVEL  REPORT_LEVEL_MINOR
++
++#endif /* __dflags_h */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/crc_mac_addr_ext.h
+@@ -0,0 +1,364 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/*------------------------------------------------------*/
++/*                                                      */
++/* File: crc_mac_addr_ext.h                             */
++/*                                                      */
++/* Description:                                         */
++/*    Define a macro that calculate the crc value of    */
++/*    an Ethernet MAC address (48 bitd address          */
++/*------------------------------------------------------*/
++
++#ifndef __crc_mac_addr_ext_h
++#define __crc_mac_addr_ext_h
++
++#include "std_ext.h"
++
++
++static uint32_t crc_table[256] =
++{
++    0x00000000,
++    0x77073096,
++    0xee0e612c,
++    0x990951ba,
++    0x076dc419,
++    0x706af48f,
++    0xe963a535,
++    0x9e6495a3,
++    0x0edb8832,
++    0x79dcb8a4,
++    0xe0d5e91e,
++    0x97d2d988,
++    0x09b64c2b,
++    0x7eb17cbd,
++    0xe7b82d07,
++    0x90bf1d91,
++    0x1db71064,
++    0x6ab020f2,
++    0xf3b97148,
++    0x84be41de,
++    0x1adad47d,
++    0x6ddde4eb,
++    0xf4d4b551,
++    0x83d385c7,
++    0x136c9856,
++    0x646ba8c0,
++    0xfd62f97a,
++    0x8a65c9ec,
++    0x14015c4f,
++    0x63066cd9,
++    0xfa0f3d63,
++    0x8d080df5,
++    0x3b6e20c8,
++    0x4c69105e,
++    0xd56041e4,
++    0xa2677172,
++    0x3c03e4d1,
++    0x4b04d447,
++    0xd20d85fd,
++    0xa50ab56b,
++    0x35b5a8fa,
++    0x42b2986c,
++    0xdbbbc9d6,
++    0xacbcf940,
++    0x32d86ce3,
++    0x45df5c75,
++    0xdcd60dcf,
++    0xabd13d59,
++    0x26d930ac,
++    0x51de003a,
++    0xc8d75180,
++    0xbfd06116,
++    0x21b4f4b5,
++    0x56b3c423,
++    0xcfba9599,
++    0xb8bda50f,
++    0x2802b89e,
++    0x5f058808,
++    0xc60cd9b2,
++    0xb10be924,
++    0x2f6f7c87,
++    0x58684c11,
++    0xc1611dab,
++    0xb6662d3d,
++    0x76dc4190,
++    0x01db7106,
++    0x98d220bc,
++    0xefd5102a,
++    0x71b18589,
++    0x06b6b51f,
++    0x9fbfe4a5,
++    0xe8b8d433,
++    0x7807c9a2,
++    0x0f00f934,
++    0x9609a88e,
++    0xe10e9818,
++    0x7f6a0dbb,
++    0x086d3d2d,
++    0x91646c97,
++    0xe6635c01,
++    0x6b6b51f4,
++    0x1c6c6162,
++    0x856530d8,
++    0xf262004e,
++    0x6c0695ed,
++    0x1b01a57b,
++    0x8208f4c1,
++    0xf50fc457,
++    0x65b0d9c6,
++    0x12b7e950,
++    0x8bbeb8ea,
++    0xfcb9887c,
++    0x62dd1ddf,
++    0x15da2d49,
++    0x8cd37cf3,
++    0xfbd44c65,
++    0x4db26158,
++    0x3ab551ce,
++    0xa3bc0074,
++    0xd4bb30e2,
++    0x4adfa541,
++    0x3dd895d7,
++    0xa4d1c46d,
++    0xd3d6f4fb,
++    0x4369e96a,
++    0x346ed9fc,
++    0xad678846,
++    0xda60b8d0,
++    0x44042d73,
++    0x33031de5,
++    0xaa0a4c5f,
++    0xdd0d7cc9,
++    0x5005713c,
++    0x270241aa,
++    0xbe0b1010,
++    0xc90c2086,
++    0x5768b525,
++    0x206f85b3,
++    0xb966d409,
++    0xce61e49f,
++    0x5edef90e,
++    0x29d9c998,
++    0xb0d09822,
++    0xc7d7a8b4,
++    0x59b33d17,
++    0x2eb40d81,
++    0xb7bd5c3b,
++    0xc0ba6cad,
++    0xedb88320,
++    0x9abfb3b6,
++    0x03b6e20c,
++    0x74b1d29a,
++    0xead54739,
++    0x9dd277af,
++    0x04db2615,
++    0x73dc1683,
++    0xe3630b12,
++    0x94643b84,
++    0x0d6d6a3e,
++    0x7a6a5aa8,
++    0xe40ecf0b,
++    0x9309ff9d,
++    0x0a00ae27,
++    0x7d079eb1,
++    0xf00f9344,
++    0x8708a3d2,
++    0x1e01f268,
++    0x6906c2fe,
++    0xf762575d,
++    0x806567cb,
++    0x196c3671,
++    0x6e6b06e7,
++    0xfed41b76,
++    0x89d32be0,
++    0x10da7a5a,
++    0x67dd4acc,
++    0xf9b9df6f,
++    0x8ebeeff9,
++    0x17b7be43,
++    0x60b08ed5,
++    0xd6d6a3e8,
++    0xa1d1937e,
++    0x38d8c2c4,
++    0x4fdff252,
++    0xd1bb67f1,
++    0xa6bc5767,
++    0x3fb506dd,
++    0x48b2364b,
++    0xd80d2bda,
++    0xaf0a1b4c,
++    0x36034af6,
++    0x41047a60,
++    0xdf60efc3,
++    0xa867df55,
++    0x316e8eef,
++    0x4669be79,
++    0xcb61b38c,
++    0xbc66831a,
++    0x256fd2a0,
++    0x5268e236,
++    0xcc0c7795,
++    0xbb0b4703,
++    0x220216b9,
++    0x5505262f,
++    0xc5ba3bbe,
++    0xb2bd0b28,
++    0x2bb45a92,
++    0x5cb36a04,
++    0xc2d7ffa7,
++    0xb5d0cf31,
++    0x2cd99e8b,
++    0x5bdeae1d,
++    0x9b64c2b0,
++    0xec63f226,
++    0x756aa39c,
++    0x026d930a,
++    0x9c0906a9,
++    0xeb0e363f,
++    0x72076785,
++    0x05005713,
++    0x95bf4a82,
++    0xe2b87a14,
++    0x7bb12bae,
++    0x0cb61b38,
++    0x92d28e9b,
++    0xe5d5be0d,
++    0x7cdcefb7,
++    0x0bdbdf21,
++    0x86d3d2d4,
++    0xf1d4e242,
++    0x68ddb3f8,
++    0x1fda836e,
++    0x81be16cd,
++    0xf6b9265b,
++    0x6fb077e1,
++    0x18b74777,
++    0x88085ae6,
++    0xff0f6a70,
++    0x66063bca,
++    0x11010b5c,
++    0x8f659eff,
++    0xf862ae69,
++    0x616bffd3,
++    0x166ccf45,
++    0xa00ae278,
++    0xd70dd2ee,
++    0x4e048354,
++    0x3903b3c2,
++    0xa7672661,
++    0xd06016f7,
++    0x4969474d,
++    0x3e6e77db,
++    0xaed16a4a,
++    0xd9d65adc,
++    0x40df0b66,
++    0x37d83bf0,
++    0xa9bcae53,
++    0xdebb9ec5,
++    0x47b2cf7f,
++    0x30b5ffe9,
++    0xbdbdf21c,
++    0xcabac28a,
++    0x53b39330,
++    0x24b4a3a6,
++    0xbad03605,
++    0xcdd70693,
++    0x54de5729,
++    0x23d967bf,
++    0xb3667a2e,
++    0xc4614ab8,
++    0x5d681b02,
++    0x2a6f2b94,
++    0xb40bbe37,
++    0xc30c8ea1,
++    0x5a05df1b,
++    0x2d02ef8d
++};
++
++
++#define GET_MAC_ADDR_CRC(addr, crc)             \
++{                                               \
++    uint32_t    i;                              \
++    uint8_t     data;                           \
++                                                \
++    /* CRC calculation */                       \
++    crc = 0xffffffff;                           \
++    for (i=0; i < 6; i++)                       \
++    {                                           \
++        data = (uint8_t)(addr >> ((5-i)*8));    \
++        crc = crc^data;                         \
++        crc = crc_table[crc&0xff] ^ (crc>>8);   \
++    }                                           \
++}                                               \
++
++/*    Define a macro for getting the mirrored value of      */
++/*    a byte size number. (0x11010011 --> 0x11001011)       */
++/*    Sometimes the mirrored value of the CRC is required   */
++static __inline__ uint8_t GetMirror(uint8_t n)
++{
++    uint8_t mirror[16] =
++        {
++            0x00,
++            0x08,
++            0x04,
++            0x0c,
++            0x02,
++            0x0a,
++            0x06,
++            0x0e,
++            0x01,
++            0x09,
++            0x05,
++            0x0d,
++            0x03,
++            0x0b,
++            0x07,
++            0x0f
++        };
++    return ((uint8_t)(((mirror[n & 0x0f] << 4) | (mirror[n >> 4]))));
++}
++
++static __inline__ uint32_t GetMirror32(uint32_t n)
++{
++    return (((uint32_t)GetMirror((uint8_t)(n))<<24) |
++            ((uint32_t)GetMirror((uint8_t)(n>>8))<<16) |
++            ((uint32_t)GetMirror((uint8_t)(n>>16))<<8) |
++            ((uint32_t)GetMirror((uint8_t)(n>>24))));
++}
++
++#define MIRROR      GetMirror
++#define MIRROR_32   GetMirror32
++
++
++#endif /* __crc_mac_addr_ext_h */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/dpaa_ext.h
+@@ -0,0 +1,210 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          dpaa_ext.h
++
++ @Description   DPAA Application Programming Interface.
++*//***************************************************************************/
++#ifndef __DPAA_EXT_H
++#define __DPAA_EXT_H
++
++#include "std_ext.h"
++#include "error_ext.h"
++
++
++/**************************************************************************//**
++ @Group         DPAA_grp Data Path Acceleration Architecture API
++
++ @Description   DPAA API functions, definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(push,1)
++#endif /* defined(__MWERKS__) && ... */
++
++/**************************************************************************//**
++ @Description   Frame descriptor
++*//***************************************************************************/
++typedef _Packed struct t_DpaaFD {
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++    volatile uint8_t liodn;
++    volatile uint8_t bpid;
++    volatile uint8_t elion;
++    volatile uint8_t addrh;
++    volatile uint32_t addrl;
++#else
++    volatile uint32_t addrl;
++    volatile uint8_t addrh;
++    volatile uint8_t elion;
++    volatile uint8_t bpid;
++    volatile uint8_t liodn;
++ #endif
++    volatile uint32_t    length;            /**< Frame length */
++    volatile uint32_t    status;            /**< FD status */
++} _PackedType t_DpaaFD;
++
++/**************************************************************************//**
++ @Description   enum for defining frame format
++*//***************************************************************************/
++typedef enum e_DpaaFDFormatType {
++    e_DPAA_FD_FORMAT_TYPE_SHORT_SBSF  = 0x0,   /**< Simple frame Single buffer; Offset and
++                                                    small length (9b OFFSET, 20b LENGTH) */
++    e_DPAA_FD_FORMAT_TYPE_LONG_SBSF   = 0x2,   /**< Simple frame, single buffer; big length
++                                                    (29b LENGTH ,No OFFSET) */
++    e_DPAA_FD_FORMAT_TYPE_SHORT_MBSF  = 0x4,   /**< Simple frame, Scatter Gather table; Offset
++                                                    and small length (9b OFFSET, 20b LENGTH) */
++    e_DPAA_FD_FORMAT_TYPE_LONG_MBSF   = 0x6,   /**< Simple frame, Scatter Gather table;
++                                                    big length (29b LENGTH ,No OFFSET) */
++    e_DPAA_FD_FORMAT_TYPE_COMPOUND    = 0x1,   /**< Compound Frame (29b CONGESTION-WEIGHT
++                                                    No LENGTH or OFFSET) */
++    e_DPAA_FD_FORMAT_TYPE_DUMMY
++} e_DpaaFDFormatType;
++
++/**************************************************************************//**
++ @Collection   Frame descriptor macros
++*//***************************************************************************/
++#define DPAA_FD_DD_MASK       0xc0000000           /**< FD DD field mask */
++#define DPAA_FD_PID_MASK      0x3f000000           /**< FD PID field mask */
++#define DPAA_FD_ELIODN_MASK   0x0000f000           /**< FD ELIODN field mask */
++#define DPAA_FD_BPID_MASK     0x00ff0000           /**< FD BPID field mask */
++#define DPAA_FD_ADDRH_MASK    0x000000ff           /**< FD ADDRH field mask */
++#define DPAA_FD_ADDRL_MASK    0xffffffff           /**< FD ADDRL field mask */
++#define DPAA_FD_FORMAT_MASK   0xe0000000           /**< FD FORMAT field mask */
++#define DPAA_FD_OFFSET_MASK   0x1ff00000           /**< FD OFFSET field mask */
++#define DPAA_FD_LENGTH_MASK   0x000fffff           /**< FD LENGTH field mask */
++
++#define DPAA_FD_GET_ADDRH(fd)         ((t_DpaaFD *)fd)->addrh                       /**< Macro to get FD ADDRH field */
++#define DPAA_FD_GET_ADDRL(fd)         ((t_DpaaFD *)fd)->addrl                                           /**< Macro to get FD ADDRL field */
++#define DPAA_FD_GET_PHYS_ADDR(fd)     ((physAddress_t)(((uint64_t)DPAA_FD_GET_ADDRH(fd) << 32) | (uint64_t)DPAA_FD_GET_ADDRL(fd))) /**< Macro to get FD ADDR field */
++#define DPAA_FD_GET_FORMAT(fd)        ((((t_DpaaFD *)fd)->length & DPAA_FD_FORMAT_MASK) >> (31-2))      /**< Macro to get FD FORMAT field */
++#define DPAA_FD_GET_OFFSET(fd)        ((((t_DpaaFD *)fd)->length & DPAA_FD_OFFSET_MASK) >> (31-11))     /**< Macro to get FD OFFSET field */
++#define DPAA_FD_GET_LENGTH(fd)        (((t_DpaaFD *)fd)->length & DPAA_FD_LENGTH_MASK)                  /**< Macro to get FD LENGTH field */
++#define DPAA_FD_GET_STATUS(fd)        ((t_DpaaFD *)fd)->status                                          /**< Macro to get FD STATUS field */
++#define DPAA_FD_GET_ADDR(fd)          XX_PhysToVirt(DPAA_FD_GET_PHYS_ADDR(fd))                          /**< Macro to get FD ADDR (virtual) */
++
++#define DPAA_FD_SET_ADDRH(fd,val)     ((t_DpaaFD *)fd)->addrh = (val)            /**< Macro to set FD ADDRH field */
++#define DPAA_FD_SET_ADDRL(fd,val)     ((t_DpaaFD *)fd)->addrl = (val)                                   /**< Macro to set FD ADDRL field */
++#define DPAA_FD_SET_ADDR(fd,val)                            \
++do {                                                        \
++    uint64_t physAddr = (uint64_t)(XX_VirtToPhys(val));     \
++    DPAA_FD_SET_ADDRH(fd, ((uint32_t)(physAddr >> 32)));    \
++    DPAA_FD_SET_ADDRL(fd, (uint32_t)physAddr);              \
++} while (0)                                                                                             /**< Macro to set FD ADDR field */
++#define DPAA_FD_SET_FORMAT(fd,val)    (((t_DpaaFD *)fd)->length = ((((t_DpaaFD *)fd)->length & ~DPAA_FD_FORMAT_MASK) | (((val)  << (31-2))& DPAA_FD_FORMAT_MASK)))  /**< Macro to set FD FORMAT field */
++#define DPAA_FD_SET_OFFSET(fd,val)    (((t_DpaaFD *)fd)->length = ((((t_DpaaFD *)fd)->length & ~DPAA_FD_OFFSET_MASK) | (((val) << (31-11))& DPAA_FD_OFFSET_MASK) )) /**< Macro to set FD OFFSET field */
++#define DPAA_FD_SET_LENGTH(fd,val)    (((t_DpaaFD *)fd)->length = (((t_DpaaFD *)fd)->length & ~DPAA_FD_LENGTH_MASK) | ((val) & DPAA_FD_LENGTH_MASK))                /**< Macro to set FD LENGTH field */
++#define DPAA_FD_SET_STATUS(fd,val)    ((t_DpaaFD *)fd)->status = (val)                                  /**< Macro to set FD STATUS field */
++/* @} */
++
++/**************************************************************************//**
++ @Description   Frame Scatter/Gather Table Entry
++*//***************************************************************************/
++typedef _Packed struct t_DpaaSGTE {
++    volatile uint32_t    addrh;        /**< Buffer Address high */
++    volatile uint32_t    addrl;        /**< Buffer Address low */
++    volatile uint32_t    length;       /**< Buffer length */
++    volatile uint32_t    offset;       /**< SGTE offset */
++} _PackedType t_DpaaSGTE;
++
++#define DPAA_NUM_OF_SG_TABLE_ENTRY 16
++
++/**************************************************************************//**
++ @Description   Frame Scatter/Gather Table
++*//***************************************************************************/
++typedef _Packed struct t_DpaaSGT {
++    t_DpaaSGTE    tableEntry[DPAA_NUM_OF_SG_TABLE_ENTRY];
++                                    /**< Structure that holds information about
++                                         a single S/G entry. */
++} _PackedType t_DpaaSGT;
++
++/**************************************************************************//**
++ @Description   Compound Frame Table
++*//***************************************************************************/
++typedef _Packed struct t_DpaaCompTbl {
++    t_DpaaSGTE    outputBuffInfo;   /**< Structure that holds information about
++                                         the compound-frame output buffer;
++                                         NOTE: this may point to a S/G table */
++    t_DpaaSGTE    inputBuffInfo;    /**< Structure that holds information about
++                                         the compound-frame input buffer;
++                                         NOTE: this may point to a S/G table */
++} _PackedType t_DpaaCompTbl;
++
++/**************************************************************************//**
++ @Collection   Frame Scatter/Gather Table Entry macros
++*//***************************************************************************/
++#define DPAA_SGTE_ADDRH_MASK    0x000000ff           /**< SGTE ADDRH field mask */
++#define DPAA_SGTE_ADDRL_MASK    0xffffffff           /**< SGTE ADDRL field mask */
++#define DPAA_SGTE_E_MASK        0x80000000           /**< SGTE Extension field mask */
++#define DPAA_SGTE_F_MASK        0x40000000           /**< SGTE Final field mask */
++#define DPAA_SGTE_LENGTH_MASK   0x3fffffff           /**< SGTE LENGTH field mask */
++#define DPAA_SGTE_BPID_MASK     0x00ff0000           /**< SGTE BPID field mask */
++#define DPAA_SGTE_OFFSET_MASK   0x00001fff           /**< SGTE OFFSET field mask */
++
++#define DPAA_SGTE_GET_ADDRH(sgte)         (((t_DpaaSGTE *)sgte)->addrh & DPAA_SGTE_ADDRH_MASK)              /**< Macro to get SGTE ADDRH field */
++#define DPAA_SGTE_GET_ADDRL(sgte)         ((t_DpaaSGTE *)sgte)->addrl                                       /**< Macro to get SGTE ADDRL field */
++#define DPAA_SGTE_GET_PHYS_ADDR(sgte)     ((physAddress_t)(((uint64_t)DPAA_SGTE_GET_ADDRH(sgte) << 32) | (uint64_t)DPAA_SGTE_GET_ADDRL(sgte))) /**< Macro to get FD ADDR field */
++#define DPAA_SGTE_GET_EXTENSION(sgte)     ((((t_DpaaSGTE *)sgte)->length & DPAA_SGTE_E_MASK) >> (31-0))     /**< Macro to get SGTE EXTENSION field */
++#define DPAA_SGTE_GET_FINAL(sgte)         ((((t_DpaaSGTE *)sgte)->length & DPAA_SGTE_F_MASK) >> (31-1))     /**< Macro to get SGTE FINAL field */
++#define DPAA_SGTE_GET_LENGTH(sgte)        (((t_DpaaSGTE *)sgte)->length & DPAA_SGTE_LENGTH_MASK)            /**< Macro to get SGTE LENGTH field */
++#define DPAA_SGTE_GET_BPID(sgte)          ((((t_DpaaSGTE *)sgte)->offset & DPAA_SGTE_BPID_MASK) >> (31-15)) /**< Macro to get SGTE BPID field */
++#define DPAA_SGTE_GET_OFFSET(sgte)        (((t_DpaaSGTE *)sgte)->offset & DPAA_SGTE_OFFSET_MASK)            /**< Macro to get SGTE OFFSET field */
++#define DPAA_SGTE_GET_ADDR(sgte)          XX_PhysToVirt(DPAA_SGTE_GET_PHYS_ADDR(sgte))
++
++#define DPAA_SGTE_SET_ADDRH(sgte,val)     (((t_DpaaSGTE *)sgte)->addrh = ((((t_DpaaSGTE *)sgte)->addrh & ~DPAA_SGTE_ADDRH_MASK) | ((val) & DPAA_SGTE_ADDRH_MASK))) /**< Macro to set SGTE ADDRH field */
++#define DPAA_SGTE_SET_ADDRL(sgte,val)     ((t_DpaaSGTE *)sgte)->addrl = (val)                                 /**< Macro to set SGTE ADDRL field */
++#define DPAA_SGTE_SET_ADDR(sgte,val)                            \
++do {                                                            \
++    uint64_t physAddr = (uint64_t)(XX_VirtToPhys(val));         \
++    DPAA_SGTE_SET_ADDRH(sgte, ((uint32_t)(physAddr >> 32)));    \
++    DPAA_SGTE_SET_ADDRL(sgte, (uint32_t)physAddr);              \
++} while (0)                                                                                                 /**< Macro to set SGTE ADDR field */
++#define DPAA_SGTE_SET_EXTENSION(sgte,val) (((t_DpaaSGTE *)sgte)->length = ((((t_DpaaSGTE *)sgte)->length & ~DPAA_SGTE_E_MASK) | (((val)  << (31-0))& DPAA_SGTE_E_MASK)))            /**< Macro to set SGTE EXTENSION field */
++#define DPAA_SGTE_SET_FINAL(sgte,val)     (((t_DpaaSGTE *)sgte)->length = ((((t_DpaaSGTE *)sgte)->length & ~DPAA_SGTE_F_MASK) | (((val)  << (31-1))& DPAA_SGTE_F_MASK)))            /**< Macro to set SGTE FINAL field */
++#define DPAA_SGTE_SET_LENGTH(sgte,val)    (((t_DpaaSGTE *)sgte)->length = (((t_DpaaSGTE *)sgte)->length & ~DPAA_SGTE_LENGTH_MASK) | ((val) & DPAA_SGTE_LENGTH_MASK))                /**< Macro to set SGTE LENGTH field */
++#define DPAA_SGTE_SET_BPID(sgte,val)      (((t_DpaaSGTE *)sgte)->offset = ((((t_DpaaSGTE *)sgte)->offset & ~DPAA_SGTE_BPID_MASK) | (((val)  << (31-15))& DPAA_SGTE_BPID_MASK)))     /**< Macro to set SGTE BPID field */
++#define DPAA_SGTE_SET_OFFSET(sgte,val)    (((t_DpaaSGTE *)sgte)->offset = ((((t_DpaaSGTE *)sgte)->offset & ~DPAA_SGTE_OFFSET_MASK) | (((val) << (31-31))& DPAA_SGTE_OFFSET_MASK) )) /**< Macro to set SGTE OFFSET field */
++/* @} */
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(pop)
++#endif /* defined(__MWERKS__) && ... */
++
++#define DPAA_LIODN_DONT_OVERRIDE    (-1)
++
++/** @} */ /* end of DPAA_grp group */
++
++
++#endif /* __DPAA_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_ext.h
+@@ -0,0 +1,1731 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          fm_ext.h
++
++ @Description   FM Application Programming Interface.
++*//***************************************************************************/
++#ifndef __FM_EXT
++#define __FM_EXT
++
++#include "error_ext.h"
++#include "std_ext.h"
++#include "dpaa_ext.h"
++#include "fsl_fman_sp.h"
++
++/**************************************************************************//**
++ @Group         FM_grp Frame Manager API
++
++ @Description   FM API functions, definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         FM_lib_grp FM library
++
++ @Description   FM API functions, definitions and enums.
++
++                The FM module is the main driver module and is a mandatory module
++                for FM driver users. This module must be initialized first prior
++                to any other drivers modules.
++                The FM is a "singleton" module. It is responsible of the common
++                HW modules: FPM, DMA, common QMI and common BMI initializations and
++                run-time control routines. This module must be initialized always
++                when working with any of the FM modules.
++                NOTE - We assume that the FM library will be initialized only by core No. 0!
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   Enum for defining port types
++*//***************************************************************************/
++typedef enum e_FmPortType {
++    e_FM_PORT_TYPE_OH_OFFLINE_PARSING = 0,  /**< Offline parsing port */
++    e_FM_PORT_TYPE_RX,                      /**< 1G Rx port */
++    e_FM_PORT_TYPE_RX_10G,                  /**< 10G Rx port */
++    e_FM_PORT_TYPE_TX,                      /**< 1G Tx port */
++    e_FM_PORT_TYPE_TX_10G,                  /**< 10G Tx port */
++    e_FM_PORT_TYPE_DUMMY
++} e_FmPortType;
++
++/**************************************************************************//**
++ @Collection    General FM defines
++*//***************************************************************************/
++#define FM_MAX_NUM_OF_PARTITIONS    64      /**< Maximum number of partitions */
++#define FM_PHYS_ADDRESS_SIZE        6       /**< FM Physical address size */
++/* @} */
++
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(push,1)
++#endif /* defined(__MWERKS__) && ... */
++
++/**************************************************************************//**
++ @Description   FM physical Address
++*//***************************************************************************/
++typedef _Packed struct t_FmPhysAddr {
++    volatile uint8_t    high;         /**< High part of the physical address */
++    volatile uint32_t   low;          /**< Low part of the physical address */
++} _PackedType t_FmPhysAddr;
++
++/**************************************************************************//**
++ @Description   Parse results memory layout
++*//***************************************************************************/
++typedef _Packed struct t_FmPrsResult {
++    volatile uint8_t     lpid;               /**< Logical port id */
++    volatile uint8_t     shimr;              /**< Shim header result  */
++    volatile uint16_t    l2r;                /**< Layer 2 result */
++    volatile uint16_t    l3r;                /**< Layer 3 result */
++    volatile uint8_t     l4r;                /**< Layer 4 result */
++    volatile uint8_t     cplan;              /**< Classification plan id */
++    volatile uint16_t    nxthdr;             /**< Next Header  */
++    volatile uint16_t    cksum;              /**< Running-sum */
++    volatile uint16_t    flags_frag_off;     /**< Flags & fragment-offset field of the last IP-header */
++    volatile uint8_t     route_type;         /**< Routing type field of a IPv6 routing extension header */
++    volatile uint8_t     rhp_ip_valid;       /**< Routing Extension Header Present; last bit is IP valid */
++    volatile uint8_t     shim_off[2];        /**< Shim offset */
++    volatile uint8_t     ip_pid_off;         /**< IP PID (last IP-proto) offset */
++    volatile uint8_t     eth_off;            /**< ETH offset */
++    volatile uint8_t     llc_snap_off;       /**< LLC_SNAP offset */
++    volatile uint8_t     vlan_off[2];        /**< VLAN offset */
++    volatile uint8_t     etype_off;          /**< ETYPE offset */
++    volatile uint8_t     pppoe_off;          /**< PPP offset */
++    volatile uint8_t     mpls_off[2];        /**< MPLS offset */
++    volatile uint8_t     ip_off[2];          /**< IP offset */
++    volatile uint8_t     gre_off;            /**< GRE offset */
++    volatile uint8_t     l4_off;             /**< Layer 4 offset */
++    volatile uint8_t     nxthdr_off;         /**< Parser end point */
++} _PackedType t_FmPrsResult;
++
++/**************************************************************************//**
++ @Collection   FM Parser results
++*//***************************************************************************/
++#define FM_PR_L2_VLAN_STACK         0x00000100  /**< Parse Result: VLAN stack */
++#define FM_PR_L2_ETHERNET           0x00008000  /**< Parse Result: Ethernet*/
++#define FM_PR_L2_VLAN               0x00004000  /**< Parse Result: VLAN */
++#define FM_PR_L2_LLC_SNAP           0x00002000  /**< Parse Result: LLC_SNAP */
++#define FM_PR_L2_MPLS               0x00001000  /**< Parse Result: MPLS */
++#define FM_PR_L2_PPPoE              0x00000800  /**< Parse Result: PPPoE */
++/* @} */
++
++/**************************************************************************//**
++ @Collection   FM Frame descriptor macros
++*//***************************************************************************/
++#define FM_FD_CMD_FCO                   0x80000000  /**< Frame queue Context Override */
++#define FM_FD_CMD_RPD                   0x40000000  /**< Read Prepended Data */
++#define FM_FD_CMD_UPD                   0x20000000  /**< Update Prepended Data */
++#define FM_FD_CMD_DTC                   0x10000000  /**< Do L4 Checksum */
++#define FM_FD_CMD_DCL4C                 0x10000000  /**< Didn't calculate L4 Checksum */
++#define FM_FD_CMD_CFQ                   0x00ffffff  /**< Confirmation Frame Queue */
++
++#define FM_FD_ERR_UNSUPPORTED_FORMAT    0x04000000  /**< Not for Rx-Port! Unsupported Format */
++#define FM_FD_ERR_LENGTH                0x02000000  /**< Not for Rx-Port! Length Error */
++#define FM_FD_ERR_DMA                   0x01000000  /**< DMA Data error */
++
++#define FM_FD_IPR                       0x00000001  /**< IPR frame (not error) */
++
++#define FM_FD_ERR_IPR_NCSP              (0x00100000 | FM_FD_IPR)    /**< IPR non-consistent-sp */
++#define FM_FD_ERR_IPR                   (0x00200000 | FM_FD_IPR)    /**< IPR error */
++#define FM_FD_ERR_IPR_TO                (0x00300000 | FM_FD_IPR)    /**< IPR timeout */
++
++#ifdef FM_CAPWAP_SUPPORT
++#define FM_FD_ERR_CRE                   0x00200000
++#define FM_FD_ERR_CHE                   0x00100000
++#endif /* FM_CAPWAP_SUPPORT */
++
++#define FM_FD_ERR_PHYSICAL              0x00080000  /**< Rx FIFO overflow, FCS error, code error, running disparity
++                                                         error (SGMII and TBI modes), FIFO parity error. PHY
++                                                         Sequence error, PHY error control character detected. */
++#define FM_FD_ERR_SIZE                  0x00040000  /**< Frame too long OR Frame size exceeds max_length_frame  */
++#define FM_FD_ERR_CLS_DISCARD           0x00020000  /**< classification discard */
++#define FM_FD_ERR_EXTRACTION            0x00008000  /**< Extract Out of Frame */
++#define FM_FD_ERR_NO_SCHEME             0x00004000  /**< No Scheme Selected */
++#define FM_FD_ERR_KEYSIZE_OVERFLOW      0x00002000  /**< Keysize Overflow */
++#define FM_FD_ERR_COLOR_RED             0x00000800  /**< Frame color is red */
++#define FM_FD_ERR_COLOR_YELLOW          0x00000400  /**< Frame color is yellow */
++#define FM_FD_ERR_ILL_PLCR              0x00000200  /**< Illegal Policer Profile selected */
++#define FM_FD_ERR_PLCR_FRAME_LEN        0x00000100  /**< Policer frame length error */
++#define FM_FD_ERR_PRS_TIMEOUT           0x00000080  /**< Parser Time out Exceed */
++#define FM_FD_ERR_PRS_ILL_INSTRUCT      0x00000040  /**< Invalid Soft Parser instruction */
++#define FM_FD_ERR_PRS_HDR_ERR           0x00000020  /**< Header error was identified during parsing */
++#define FM_FD_ERR_BLOCK_LIMIT_EXCEEDED  0x00000008  /**< Frame parsed beyind 256 first bytes */
++
++#define FM_FD_TX_STATUS_ERR_MASK        (FM_FD_ERR_UNSUPPORTED_FORMAT   | \
++                                         FM_FD_ERR_LENGTH               | \
++                                         FM_FD_ERR_DMA) /**< TX Error FD bits */
++
++#define FM_FD_RX_STATUS_ERR_MASK        (FM_FD_ERR_UNSUPPORTED_FORMAT   | \
++                                         FM_FD_ERR_LENGTH               | \
++                                         FM_FD_ERR_DMA                  | \
++                                         FM_FD_ERR_IPR                  | \
++                                         FM_FD_ERR_IPR_TO               | \
++                                         FM_FD_ERR_IPR_NCSP             | \
++                                         FM_FD_ERR_PHYSICAL             | \
++                                         FM_FD_ERR_SIZE                 | \
++                                         FM_FD_ERR_CLS_DISCARD          | \
++                                         FM_FD_ERR_COLOR_RED            | \
++                                         FM_FD_ERR_COLOR_YELLOW         | \
++                                         FM_FD_ERR_ILL_PLCR             | \
++                                         FM_FD_ERR_PLCR_FRAME_LEN       | \
++                                         FM_FD_ERR_EXTRACTION           | \
++                                         FM_FD_ERR_NO_SCHEME            | \
++                                         FM_FD_ERR_KEYSIZE_OVERFLOW     | \
++                                         FM_FD_ERR_PRS_TIMEOUT          | \
++                                         FM_FD_ERR_PRS_ILL_INSTRUCT     | \
++                                         FM_FD_ERR_PRS_HDR_ERR          | \
++                                         FM_FD_ERR_BLOCK_LIMIT_EXCEEDED) /**< RX Error FD bits */
++
++#define FM_FD_RX_STATUS_ERR_NON_FM      0x00400000  /**< non Frame-Manager error */
++/* @} */
++
++/**************************************************************************//**
++ @Description   Context A
++*//***************************************************************************/
++typedef _Packed struct t_FmContextA {
++    volatile uint32_t    command;   /**< ContextA Command */
++    volatile uint8_t     res0[4];   /**< ContextA Reserved bits */
++} _PackedType t_FmContextA;
++
++/**************************************************************************//**
++ @Description   Context B
++*//***************************************************************************/
++typedef uint32_t t_FmContextB;
++
++/**************************************************************************//**
++ @Collection   Special Operation options
++*//***************************************************************************/
++typedef uint32_t fmSpecialOperations_t;                 /**< typedef for defining Special Operation options */
++
++#define  FM_SP_OP_IPSEC                     0x80000000  /**< activate features that related to IPSec (e.g fix Eth-type) */
++#define  FM_SP_OP_IPSEC_UPDATE_UDP_LEN      0x40000000  /**< update the UDP-Len after Encryption */
++#define  FM_SP_OP_IPSEC_MANIP               0x20000000  /**< handle the IPSec-manip options */
++#define  FM_SP_OP_RPD                       0x10000000  /**< Set the RPD bit */
++#define  FM_SP_OP_DCL4C                     0x08000000  /**< Set the DCL4C bit */
++#define  FM_SP_OP_CHECK_SEC_ERRORS          0x04000000  /**< Check SEC errors */
++#define  FM_SP_OP_CLEAR_RPD                 0x02000000  /**< Clear the RPD bit */
++#define  FM_SP_OP_CAPWAP_DTLS_ENC           0x01000000  /**< activate features that related to CAPWAP-DTLS post Encryption */
++#define  FM_SP_OP_CAPWAP_DTLS_DEC           0x00800000  /**< activate features that related to CAPWAP-DTLS post Decryption */
++#define  FM_SP_OP_IPSEC_NO_ETH_HDR          0x00400000  /**< activate features that related to IPSec without Eth hdr */
++/* @} */
++
++/**************************************************************************//**
++ @Collection   Context A macros
++*//***************************************************************************/
++#define FM_CONTEXTA_OVERRIDE_MASK       0x80000000
++#define FM_CONTEXTA_ICMD_MASK           0x40000000
++#define FM_CONTEXTA_A1_VALID_MASK       0x20000000
++#define FM_CONTEXTA_MACCMD_MASK         0x00ff0000
++#define FM_CONTEXTA_MACCMD_VALID_MASK   0x00800000
++#define FM_CONTEXTA_MACCMD_SECURED_MASK 0x00100000
++#define FM_CONTEXTA_MACCMD_SC_MASK      0x000f0000
++#define FM_CONTEXTA_A1_MASK             0x0000ffff
++
++#define FM_CONTEXTA_GET_OVERRIDE(contextA)                 ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_OVERRIDE_MASK) >> (31-0))
++#define FM_CONTEXTA_GET_ICMD(contextA)                     ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_ICMD_MASK) >> (31-1))
++#define FM_CONTEXTA_GET_A1_VALID(contextA)                 ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_A1_VALID_MASK) >> (31-2))
++#define FM_CONTEXTA_GET_A1(contextA)                       ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_A1_MASK) >> (31-31))
++#define FM_CONTEXTA_GET_MACCMD(contextA)                   ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_MASK) >> (31-15))
++#define FM_CONTEXTA_GET_MACCMD_VALID(contextA)             ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_VALID_MASK) >> (31-8))
++#define FM_CONTEXTA_GET_MACCMD_SECURED(contextA)           ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_SECURED_MASK) >> (31-11))
++#define FM_CONTEXTA_GET_MACCMD_SECURE_CHANNEL(contextA)    ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_SC_MASK) >> (31-15))
++
++#define FM_CONTEXTA_SET_OVERRIDE(contextA,val)              (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_OVERRIDE_MASK) | (((uint32_t)(val) << (31-0)) & FM_CONTEXTA_OVERRIDE_MASK) ))
++#define FM_CONTEXTA_SET_ICMD(contextA,val)                  (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_ICMD_MASK) | (((val) << (31-1)) & FM_CONTEXTA_ICMD_MASK) ))
++#define FM_CONTEXTA_SET_A1_VALID(contextA,val)              (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_A1_VALID_MASK) | (((val) << (31-2)) & FM_CONTEXTA_A1_VALID_MASK) ))
++#define FM_CONTEXTA_SET_A1(contextA,val)                    (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_A1_MASK) | (((val) << (31-31)) & FM_CONTEXTA_A1_MASK) ))
++#define FM_CONTEXTA_SET_MACCMD(contextA,val)                (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_MASK) | (((val) << (31-15)) & FM_CONTEXTA_MACCMD_MASK) ))
++#define FM_CONTEXTA_SET_MACCMD_VALID(contextA,val)          (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_VALID_MASK) | (((val) << (31-8)) & FM_CONTEXTA_MACCMD_VALID_MASK) ))
++#define FM_CONTEXTA_SET_MACCMD_SECURED(contextA,val)        (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_SECURED_MASK) | (((val) << (31-11)) & FM_CONTEXTA_MACCMD_SECURED_MASK) ))
++#define FM_CONTEXTA_SET_MACCMD_SECURE_CHANNEL(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_SC_MASK) | (((val) << (31-15)) & FM_CONTEXTA_MACCMD_SC_MASK) ))
++/* @} */
++
++/**************************************************************************//**
++ @Collection   Context B macros
++*//***************************************************************************/
++#define FM_CONTEXTB_FQID_MASK               0x00ffffff
++
++#define FM_CONTEXTB_GET_FQID(contextB)      (*((t_FmContextB *)contextB) & FM_CONTEXTB_FQID_MASK)
++#define FM_CONTEXTB_SET_FQID(contextB,val)  (*((t_FmContextB *)contextB) = ((*((t_FmContextB *)contextB) & ~FM_CONTEXTB_FQID_MASK) | ((val) & FM_CONTEXTB_FQID_MASK)))
++/* @} */
++
++#if defined(__MWERKS__) && !defined(__GNUC__)
++#pragma pack(pop)
++#endif /* defined(__MWERKS__) && ... */
++
++
++/**************************************************************************//**
++ @Description   FM Exceptions
++*//***************************************************************************/
++typedef enum e_FmExceptions {
++    e_FM_EX_DMA_BUS_ERROR = 0,          /**< DMA bus error. */
++    e_FM_EX_DMA_READ_ECC,               /**< Read Buffer ECC error (Valid for FM rev < 6)*/
++    e_FM_EX_DMA_SYSTEM_WRITE_ECC,       /**< Write Buffer ECC error on system side (Valid for FM rev < 6)*/
++    e_FM_EX_DMA_FM_WRITE_ECC,           /**< Write Buffer ECC error on FM side (Valid for FM rev < 6)*/
++    e_FM_EX_DMA_SINGLE_PORT_ECC,        /**< Single Port ECC error on FM side (Valid for FM rev > 6)*/
++    e_FM_EX_FPM_STALL_ON_TASKS,         /**< Stall of tasks on FPM */
++    e_FM_EX_FPM_SINGLE_ECC,             /**< Single ECC on FPM. */
++    e_FM_EX_FPM_DOUBLE_ECC,             /**< Double ECC error on FPM ram access */
++    e_FM_EX_QMI_SINGLE_ECC,             /**< Single ECC on QMI. */
++    e_FM_EX_QMI_DOUBLE_ECC,             /**< Double bit ECC occurred on QMI */
++    e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,/**< Dequeue from unknown port id */
++    e_FM_EX_BMI_LIST_RAM_ECC,           /**< Linked List RAM ECC error */
++    e_FM_EX_BMI_STORAGE_PROFILE_ECC,    /**< Storage Profile ECC Error */
++    e_FM_EX_BMI_STATISTICS_RAM_ECC,     /**< Statistics Count RAM ECC Error Enable */
++    e_FM_EX_BMI_DISPATCH_RAM_ECC,       /**< Dispatch RAM ECC Error Enable */
++    e_FM_EX_IRAM_ECC,                   /**< Double bit ECC occurred on IRAM*/
++    e_FM_EX_MURAM_ECC                   /**< Double bit ECC occurred on MURAM*/
++} e_FmExceptions;
++
++/**************************************************************************//**
++ @Description   Enum for defining port DMA swap mode
++*//***************************************************************************/
++typedef enum e_FmDmaSwapOption {
++    e_FM_DMA_NO_SWP = FMAN_DMA_NO_SWP,          /**< No swap, transfer data as is.*/
++    e_FM_DMA_SWP_PPC_LE = FMAN_DMA_SWP_PPC_LE,  /**< The transferred data should be swapped
++                                                in PowerPc Little Endian mode. */
++    e_FM_DMA_SWP_BE = FMAN_DMA_SWP_BE           /**< The transferred data should be swapped
++                                                in Big Endian mode */
++} e_FmDmaSwapOption;
++
++/**************************************************************************//**
++ @Description   Enum for defining port DMA cache attributes
++*//***************************************************************************/
++typedef enum e_FmDmaCacheOption {
++    e_FM_DMA_NO_STASH = FMAN_DMA_NO_STASH,      /**< Cacheable, no Allocate (No Stashing) */
++    e_FM_DMA_STASH = FMAN_DMA_STASH             /**< Cacheable and Allocate (Stashing on) */
++} e_FmDmaCacheOption;
++
++
++/**************************************************************************//**
++ @Group         FM_init_grp FM Initialization Unit
++
++ @Description   FM Initialization Unit
++
++                Initialization Flow
++                Initialization of the FM Module will be carried out by the application
++                according to the following sequence:
++                -  Calling the configuration routine with basic parameters.
++                -  Calling the advance initialization routines to change driver's defaults.
++                -  Calling the initialization routine.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      t_FmExceptionsCallback
++
++ @Description   Exceptions user callback routine, will be called upon an
++                exception passing the exception identification.
++
++ @Param[in]     h_App      - User's application descriptor.
++ @Param[in]     exception  - The exception.
++*//***************************************************************************/
++typedef void (t_FmExceptionsCallback)(t_Handle          h_App,
++                                      e_FmExceptions    exception);
++
++
++/**************************************************************************//**
++ @Function      t_FmBusErrorCallback
++
++ @Description   Bus error user callback routine, will be called upon a
++                bus error, passing parameters describing the errors and the owner.
++
++ @Param[in]     h_App       - User's application descriptor.
++ @Param[in]     portType    - Port type (e_FmPortType)
++ @Param[in]     portId      - Port id - relative to type.
++ @Param[in]     addr        - Address that caused the error
++ @Param[in]     tnum        - Owner of error
++ @Param[in]     liodn       - Logical IO device number
++*//***************************************************************************/
++typedef void (t_FmBusErrorCallback) (t_Handle        h_App,
++                                     e_FmPortType    portType,
++                                     uint8_t         portId,
++                                     uint64_t        addr,
++                                     uint8_t         tnum,
++                                     uint16_t        liodn);
++
++/**************************************************************************//**
++ @Description   A structure for defining buffer prefix area content.
++*//***************************************************************************/
++typedef struct t_FmBufferPrefixContent {
++    uint16_t    privDataSize;       /**< Number of bytes to be left at the beginning
++                                         of the external buffer; Note that the private-area will
++                                         start from the base of the buffer address. */
++    bool        passPrsResult;      /**< TRUE to pass the parse result to/from the FM;
++                                         User may use FM_PORT_GetBufferPrsResult() in order to
++                                         get the parser-result from a buffer. */
++    bool        passTimeStamp;      /**< TRUE to pass the timeStamp to/from the FM
++                                         User may use FM_PORT_GetBufferTimeStamp() in order to
++                                         get the parser-result from a buffer. */
++    bool        passHashResult;     /**< TRUE to pass the KG hash result to/from the FM
++                                         User may use FM_PORT_GetBufferHashResult() in order to
++                                         get the parser-result from a buffer. */
++    bool        passAllOtherPCDInfo;/**< Add all other Internal-Context information:
++                                         AD, hash-result, key, etc. */
++    uint16_t    dataAlign;          /**< 0 to use driver's default alignment [DEFAULT_FM_SP_bufferPrefixContent_dataAlign],
++                                         other value for selecting a data alignment (must be a power of 2);
++                                         if write optimization is used, must be >= 16. */
++    uint8_t     manipExtraSpace;    /**< Maximum extra size needed (insertion-size minus removal-size);
++                                         Note that this field impacts the size of the buffer-prefix
++                                         (i.e. it pushes the data offset);
++                                         This field is irrelevant if DPAA_VERSION==10 */
++} t_FmBufferPrefixContent;
++
++/**************************************************************************//**
++ @Description   A structure of information about each of the external
++                buffer pools used by a port or storage-profile.
++*//***************************************************************************/
++typedef struct t_FmExtPoolParams {
++    uint8_t                 id;     /**< External buffer pool id */
++    uint16_t                size;   /**< External buffer pool buffer size */
++} t_FmExtPoolParams;
++
++/**************************************************************************//**
++ @Description   A structure for informing the driver about the external
++                buffer pools allocated in the BM and used by a port or a
++                storage-profile.
++*//***************************************************************************/
++typedef struct t_FmExtPools {
++    uint8_t                 numOfPoolsUsed;     /**< Number of pools use by this port */
++    t_FmExtPoolParams       extBufPool[FM_PORT_MAX_NUM_OF_EXT_POOLS];
++                                                /**< Parameters for each port */
++} t_FmExtPools;
++
++/**************************************************************************//**
++ @Description   A structure for defining backup BM Pools.
++*//***************************************************************************/
++typedef struct t_FmBackupBmPools {
++    uint8_t     numOfBackupPools;       /**< Number of BM backup pools -
++                                             must be smaller than the total number of
++                                             pools defined for the specified port.*/
++    uint8_t     poolIds[FM_PORT_MAX_NUM_OF_EXT_POOLS];
++                                        /**< numOfBackupPools pool id's, specifying which
++                                             pools should be used only as backup. Pool
++                                             id's specified here must be a subset of the
++                                             pools used by the specified port.*/
++} t_FmBackupBmPools;
++
++/**************************************************************************//**
++ @Description   A structure for defining BM pool depletion criteria
++*//***************************************************************************/
++typedef struct t_FmBufPoolDepletion {
++    bool        poolsGrpModeEnable;                 /**< select mode in which pause frames will be sent after
++                                                         a number of pools (all together!) are depleted */
++    uint8_t     numOfPools;                         /**< the number of depleted pools that will invoke
++                                                         pause frames transmission. */
++    bool        poolsToConsider[BM_MAX_NUM_OF_POOLS];
++                                                    /**< For each pool, TRUE if it should be considered for
++                                                         depletion (Note - this pool must be used by this port!). */
++    bool        singlePoolModeEnable;               /**< select mode in which pause frames will be sent after
++                                                         a single-pool is depleted; */
++    bool        poolsToConsiderForSingleMode[BM_MAX_NUM_OF_POOLS];
++                                                    /**< For each pool, TRUE if it should be considered for
++                                                         depletion (Note - this pool must be used by this port!) */
++#if (DPAA_VERSION >= 11)
++    bool        pfcPrioritiesEn[FM_MAX_NUM_OF_PFC_PRIORITIES];
++                                                    /**< This field is used by the MAC as the Priority Enable Vector in the PFC frame which is transmitted */
++#endif /* (DPAA_VERSION >= 11) */
++} t_FmBufPoolDepletion;
++
++/**************************************************************************//**
++ @Description   A Structure for defining Ucode patch for loading.
++*//***************************************************************************/
++typedef struct t_FmFirmwareParams {
++    uint32_t                size;                   /**< Size of uCode */
++    uint32_t                *p_Code;                /**< A pointer to the uCode */
++} t_FmFirmwareParams;
++
++/**************************************************************************//**
++ @Description   A Structure for defining FM initialization parameters
++*//***************************************************************************/
++typedef struct t_FmParams {
++    uint8_t                 fmId;                   /**< Index of the FM */
++    uint8_t                 guestId;                /**< FM Partition Id */
++    uintptr_t               baseAddr;               /**< A pointer to base of memory mapped FM registers (virtual);
++                                                         this field is optional when the FM runs in "guest-mode"
++                                                         (i.e. guestId != NCSW_MASTER_ID); in that case, the driver will
++                                                         use the memory-map instead of calling the IPC where possible;
++                                                         NOTE that this should include ALL common registers of the FM including
++                                                         the PCD registers area (i.e. until the VSP pages - 880KB). */
++    t_Handle                h_FmMuram;              /**< A handle of an initialized MURAM object,
++                                                         to be used by the FM. */
++    uint16_t                fmClkFreq;              /**< In Mhz;
++                                                         Relevant when FM not runs in "guest-mode". */
++    uint16_t                fmMacClkRatio;          /**< FM MAC Clock ratio, for backward comparability:
++                                                                     when fmMacClkRatio = 0, ratio is 2:1
++                                                                     when fmMacClkRatio = 1, ratio is 1:1  */
++    t_FmExceptionsCallback  *f_Exception;           /**< An application callback routine to handle exceptions;
++                                                         Relevant when FM not runs in "guest-mode". */
++    t_FmBusErrorCallback    *f_BusError;            /**< An application callback routine to handle exceptions;
++                                                         Relevant when FM not runs in "guest-mode". */
++    t_Handle                h_App;                  /**< A handle to an application layer object; This handle will
++                                                         be passed by the driver upon calling the above callbacks;
++                                                         Relevant when FM not runs in "guest-mode". */
++    int                     irq;                    /**< FM interrupt source for normal events;
++                                                         Relevant when FM not runs in "guest-mode". */
++    int                     errIrq;                 /**< FM interrupt source for errors;
++                                                         Relevant when FM not runs in "guest-mode". */
++    t_FmFirmwareParams      firmware;               /**< The firmware parameters structure;
++                                                         Relevant when FM not runs in "guest-mode". */
++
++#if (DPAA_VERSION >= 11)
++    uintptr_t               vspBaseAddr;            /**< A pointer to base of memory mapped FM VSP registers (virtual);
++                                                         i.e. up to 24KB, depending on the specific chip. */
++    uint8_t                 partVSPBase;            /**< The first Virtual-Storage-Profile-id dedicated to this partition.
++                                                         NOTE: this parameter relevant only when working with multiple partitions. */
++    uint8_t                 partNumOfVSPs;          /**< Number of VSPs dedicated to this partition.
++                                                         NOTE: this parameter relevant only when working with multiple partitions. */
++#endif /* (DPAA_VERSION >= 11) */
++} t_FmParams;
++
++
++/**************************************************************************//**
++ @Function      FM_Config
++
++ @Description   Creates the FM module and returns its handle (descriptor).
++                This descriptor must be passed as first parameter to all other
++                FM function calls.
++
++                No actual initialization or configuration of FM hardware is
++                done by this routine. All FM parameters get default values that
++                may be changed by calling one or more of the advance config routines.
++
++ @Param[in]     p_FmParams  - A pointer to a data structure of mandatory FM parameters
++
++ @Return        A handle to the FM object, or NULL for Failure.
++*//***************************************************************************/
++t_Handle FM_Config(t_FmParams *p_FmParams);
++
++/**************************************************************************//**
++ @Function      FM_Init
++
++ @Description   Initializes the FM module by defining the software structure
++                and configuring the hardware registers.
++
++ @Param[in]     h_Fm - FM module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_Init(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FM_Free
++
++ @Description   Frees all resources that were assigned to FM module.
++
++                Calling this routine invalidates the descriptor.
++
++ @Param[in]     h_Fm - FM module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_Free(t_Handle h_Fm);
++
++
++/**************************************************************************//**
++ @Group         FM_advanced_init_grp    FM Advanced Configuration Unit
++
++ @Description   Advanced configuration routines are optional routines that may
++                be called in order to change the default driver settings.
++
++                Note: Advanced configuration routines are not available for guest partition.
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   Enum for selecting DMA debug mode
++*//***************************************************************************/
++typedef enum e_FmDmaDbgCntMode {
++    e_FM_DMA_DBG_NO_CNT             = 0,    /**< No counting */
++    e_FM_DMA_DBG_CNT_DONE,                  /**< Count DONE commands */
++    e_FM_DMA_DBG_CNT_COMM_Q_EM,             /**< count command queue emergency signals */
++    e_FM_DMA_DBG_CNT_INT_READ_EM,           /**< Count Internal Read buffer emergency signal */
++    e_FM_DMA_DBG_CNT_INT_WRITE_EM,          /**< Count Internal Write buffer emergency signal */
++    e_FM_DMA_DBG_CNT_FPM_WAIT,              /**< Count FPM WAIT signal */
++    e_FM_DMA_DBG_CNT_SIGLE_BIT_ECC,         /**< Single bit ECC errors. */
++    e_FM_DMA_DBG_CNT_RAW_WAR_PROT           /**< Number of times there was a need for RAW & WAR protection. */
++} e_FmDmaDbgCntMode;
++
++/**************************************************************************//**
++ @Description   Enum for selecting DMA Cache Override
++*//***************************************************************************/
++typedef enum e_FmDmaCacheOverride {
++    e_FM_DMA_NO_CACHE_OR = 0,               /**< No override of the Cache field */
++    e_FM_DMA_NO_STASH_DATA,                 /**< Data should not be stashed in system level cache */
++    e_FM_DMA_MAY_STASH_DATA,                /**< Data may be stashed in system level cache */
++    e_FM_DMA_STASH_DATA                     /**< Data should be stashed in system level cache */
++} e_FmDmaCacheOverride;
++
++/**************************************************************************//**
++ @Description   Enum for selecting DMA External Bus Priority
++*//***************************************************************************/
++typedef enum e_FmDmaExtBusPri {
++    e_FM_DMA_EXT_BUS_NORMAL = 0,            /**< Normal priority */
++    e_FM_DMA_EXT_BUS_EBS,                   /**< AXI extended bus service priority */
++    e_FM_DMA_EXT_BUS_SOS,                   /**< AXI sos priority */
++    e_FM_DMA_EXT_BUS_EBS_AND_SOS            /**< AXI ebs + sos priority */
++} e_FmDmaExtBusPri;
++
++/**************************************************************************//**
++ @Description   Enum for choosing the field that will be output on AID
++*//***************************************************************************/
++typedef enum e_FmDmaAidMode {
++    e_FM_DMA_AID_OUT_PORT_ID = 0,           /**< 4 LSB of PORT_ID */
++    e_FM_DMA_AID_OUT_TNUM                   /**< 4 LSB of TNUM */
++} e_FmDmaAidMode;
++
++/**************************************************************************//**
++ @Description   Enum for selecting FPM Catastrophic error behavior
++*//***************************************************************************/
++typedef enum e_FmCatastrophicErr {
++    e_FM_CATASTROPHIC_ERR_STALL_PORT = 0,   /**< Port_ID is stalled (only reset can release it) */
++    e_FM_CATASTROPHIC_ERR_STALL_TASK        /**< Only erroneous task is stalled */
++} e_FmCatastrophicErr;
++
++/**************************************************************************//**
++ @Description   Enum for selecting FPM DMA Error behavior
++*//***************************************************************************/
++typedef enum e_FmDmaErr {
++    e_FM_DMA_ERR_CATASTROPHIC = 0,          /**< Dma error is treated as a catastrophic
++                                                 error (e_FmCatastrophicErr)*/
++    e_FM_DMA_ERR_REPORT                     /**< Dma error is just reported */
++} e_FmDmaErr;
++
++/**************************************************************************//**
++ @Description   Enum for selecting DMA Emergency level by BMI emergency signal
++*//***************************************************************************/
++typedef enum e_FmDmaEmergencyLevel {
++    e_FM_DMA_EM_EBS = 0,                    /**< EBS emergency */
++    e_FM_DMA_EM_SOS                         /**< SOS emergency */
++} e_FmDmaEmergencyLevel;
++
++/**************************************************************************//**
++ @Collection   Enum for selecting DMA Emergency options
++*//***************************************************************************/
++typedef uint32_t fmEmergencyBus_t;          /**< DMA emergency options */
++
++#define  FM_DMA_MURAM_READ_EMERGENCY        0x00800000    /**< Enable emergency for MURAM1 */
++#define  FM_DMA_MURAM_WRITE_EMERGENCY       0x00400000    /**< Enable emergency for MURAM2 */
++#define  FM_DMA_EXT_BUS_EMERGENCY           0x00100000    /**< Enable emergency for external bus */
++/* @} */
++
++/**************************************************************************//**
++ @Description   A structure for defining DMA emergency level
++*//***************************************************************************/
++typedef struct t_FmDmaEmergency {
++    fmEmergencyBus_t        emergencyBusSelect;             /**< An OR of the busses where emergency
++                                                                 should be enabled */
++    e_FmDmaEmergencyLevel   emergencyLevel;                 /**< EBS/SOS */
++} t_FmDmaEmergency;
++
++/**************************************************************************//*
++ @Description   structure for defining FM threshold
++*//***************************************************************************/
++typedef struct t_FmThresholds {
++    uint8_t                 dispLimit;                      /**< The number of times a frames may
++                                                                 be passed in the FM before assumed to
++                                                                 be looping. */
++    uint8_t                 prsDispTh;                      /**< This is the number pf packets that may be
++                                                                 queued in the parser dispatch queue*/
++    uint8_t                 plcrDispTh;                     /**< This is the number pf packets that may be
++                                                                 queued in the policer dispatch queue*/
++    uint8_t                 kgDispTh;                       /**< This is the number pf packets that may be
++                                                                 queued in the keygen dispatch queue*/
++    uint8_t                 bmiDispTh;                      /**< This is the number pf packets that may be
++                                                                 queued in the BMI dispatch queue*/
++    uint8_t                 qmiEnqDispTh;                   /**< This is the number pf packets that may be
++                                                                 queued in the QMI enqueue dispatch queue*/
++    uint8_t                 qmiDeqDispTh;                   /**< This is the number pf packets that may be
++                                                                 queued in the QMI dequeue dispatch queue*/
++    uint8_t                 fmCtl1DispTh;                   /**< This is the number pf packets that may be
++                                                                 queued in fmCtl1 dispatch queue*/
++    uint8_t                 fmCtl2DispTh;                   /**< This is the number pf packets that may be
++                                                                 queued in fmCtl2 dispatch queue*/
++} t_FmThresholds;
++
++/**************************************************************************//*
++ @Description   structure for defining DMA thresholds
++*//***************************************************************************/
++typedef struct t_FmDmaThresholds {
++    uint8_t                     assertEmergency;            /**< When this value is reached,
++                                                                 assert emergency (Threshold)*/
++    uint8_t                     clearEmergency;             /**< After emergency is asserted, it is held
++                                                                 until this value is reached (Hystheresis) */
++} t_FmDmaThresholds;
++
++/**************************************************************************//**
++ @Function      t_FmResetOnInitOverrideCallback
++
++ @Description   FMan specific reset on init user callback routine,
++                will be used to override the standard FMan reset on init procedure
++
++ @Param[in]     h_Fm  - FMan handler
++*//***************************************************************************/
++typedef void (t_FmResetOnInitOverrideCallback)(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FM_ConfigResetOnInit
++
++ @Description   Define whether to reset the FM before initialization.
++                Change the default configuration [DEFAULT_resetOnInit].
++
++ @Param[in]     h_Fm                A handle to an FM Module.
++ @Param[in]     enable              When TRUE, FM will be reset before any initialization.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigResetOnInit(t_Handle h_Fm, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_ConfigResetOnInitOverrideCallback
++
++ @Description   Define a special reset of FM before initialization.
++                Change the default configuration [DEFAULT_resetOnInitOverrideCallback].
++
++ @Param[in]     h_Fm                  A handle to an FM Module.
++ @Param[in]     f_ResetOnInitOverride   FM specific reset on init user callback routine.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigResetOnInitOverrideCallback(t_Handle h_Fm, t_FmResetOnInitOverrideCallback *f_ResetOnInitOverride);
++
++/**************************************************************************//**
++ @Function      FM_ConfigTotalFifoSize
++
++ @Description   Define Total FIFO size for the whole FM.
++                Calling this routine changes the total Fifo size in the internal driver
++                data base from its default configuration [DEFAULT_totalFifoSize]
++
++ @Param[in]     h_Fm                A handle to an FM Module.
++ @Param[in]     totalFifoSize       The selected new value.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigTotalFifoSize(t_Handle h_Fm, uint32_t totalFifoSize);
++
++ /**************************************************************************//**
++ @Function      FM_ConfigDmaCacheOverride
++
++ @Description   Define cache override mode.
++                Calling this routine changes the cache override mode
++                in the internal driver data base from its default configuration [DEFAULT_cacheOverride]
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     cacheOverride   The selected new value.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigDmaCacheOverride(t_Handle h_Fm, e_FmDmaCacheOverride cacheOverride);
++
++/**************************************************************************//**
++ @Function      FM_ConfigDmaAidOverride
++
++ @Description   Define DMA AID override mode.
++                Calling this routine changes the AID override mode
++                in the internal driver data base from its default configuration  [DEFAULT_aidOverride]
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     aidOverride     The selected new value.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigDmaAidOverride(t_Handle h_Fm, bool aidOverride);
++
++/**************************************************************************//**
++ @Function      FM_ConfigDmaAidMode
++
++ @Description   Define DMA AID  mode.
++                Calling this routine changes the AID  mode in the internal
++                driver data base from its default configuration [DEFAULT_aidMode]
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     aidMode         The selected new value.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigDmaAidMode(t_Handle h_Fm, e_FmDmaAidMode aidMode);
++
++/**************************************************************************//**
++ @Function      FM_ConfigDmaAxiDbgNumOfBeats
++
++ @Description   Define DMA AXI number of beats.
++                Calling this routine changes the AXI number of beats in the internal
++                driver data base from its default configuration [DEFAULT_axiDbgNumOfBeats]
++
++ @Param[in]     h_Fm                A handle to an FM Module.
++ @Param[in]     axiDbgNumOfBeats    The selected new value.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigDmaAxiDbgNumOfBeats(t_Handle h_Fm, uint8_t axiDbgNumOfBeats);
++
++/**************************************************************************//**
++ @Function      FM_ConfigDmaCamNumOfEntries
++
++ @Description   Define number of CAM entries.
++                Calling this routine changes the number of CAM entries in the internal
++                driver data base from its default configuration [DEFAULT_dmaCamNumOfEntries].
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     numOfEntries    The selected new value.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigDmaCamNumOfEntries(t_Handle h_Fm, uint8_t numOfEntries);
++
++/**************************************************************************//**
++ @Function      FM_ConfigEnableCounters
++
++ @Description   Obsolete, always return E_OK.
++
++ @Param[in]     h_Fm    A handle to an FM Module.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_ConfigEnableCounters(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FM_ConfigDmaDbgCounter
++
++ @Description   Define DMA debug counter.
++                Calling this routine changes the number of the DMA debug counter in the internal
++                driver data base from its default configuration [DEFAULT_dmaDbgCntMode].
++
++ @Param[in]     h_Fm                A handle to an FM Module.
++ @Param[in]     fmDmaDbgCntMode     An enum selecting the debug counter mode.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigDmaDbgCounter(t_Handle h_Fm, e_FmDmaDbgCntMode fmDmaDbgCntMode);
++
++/**************************************************************************//**
++ @Function      FM_ConfigDmaStopOnBusErr
++
++ @Description   Define bus error behavior.
++                Calling this routine changes the bus error behavior definition
++                in the internal driver data base from its default
++                configuration [DEFAULT_dmaStopOnBusError].
++
++ @Param[in]     h_Fm    A handle to an FM Module.
++ @Param[in]     stop    TRUE to stop on bus error, FALSE to continue.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                Only if bus error is enabled.
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigDmaStopOnBusErr(t_Handle h_Fm, bool stop);
++
++/**************************************************************************//**
++ @Function      FM_ConfigDmaEmergency
++
++ @Description   Define DMA emergency.
++                Calling this routine changes the DMA emergency definition
++                in the internal driver data base from its default
++                configuration where's it's disabled.
++
++ @Param[in]     h_Fm        A handle to an FM Module.
++ @Param[in]     p_Emergency An OR mask of all required options.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigDmaEmergency(t_Handle h_Fm, t_FmDmaEmergency *p_Emergency);
++
++/**************************************************************************//**
++ @Function      FM_ConfigDmaErr
++
++ @Description   DMA error treatment.
++                Calling this routine changes the DMA error treatment
++                in the internal driver data base from its default
++                configuration [DEFAULT_dmaErr].
++
++ @Param[in]     h_Fm    A handle to an FM Module.
++ @Param[in]     dmaErr  The selected new choice.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigDmaErr(t_Handle h_Fm, e_FmDmaErr dmaErr);
++
++/**************************************************************************//**
++ @Function      FM_ConfigCatastrophicErr
++
++ @Description   Define FM behavior on catastrophic error.
++                Calling this routine changes the FM behavior on catastrophic
++                error in the internal driver data base from its default
++                [DEFAULT_catastrophicErr].
++
++ @Param[in]     h_Fm                A handle to an FM Module.
++ @Param[in]     catastrophicErr     The selected new choice.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigCatastrophicErr(t_Handle h_Fm, e_FmCatastrophicErr catastrophicErr);
++
++/**************************************************************************//**
++ @Function      FM_ConfigEnableMuramTestMode
++
++ @Description   Enable MURAM test mode.
++                Calling this routine changes the internal driver data base
++                from its default selection of test mode where it's disabled.
++                This routine is only avaiable on old FM revisions (FMan v2).
++
++ @Param[in]     h_Fm    A handle to an FM Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigEnableMuramTestMode(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FM_ConfigEnableIramTestMode
++
++ @Description   Enable IRAM test mode.
++                Calling this routine changes the internal driver data base
++                from its default selection of test mode where it's disabled.
++                This routine is only avaiable on old FM revisions (FMan v2).
++
++ @Param[in]     h_Fm    A handle to an FM Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigEnableIramTestMode(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FM_ConfigHaltOnExternalActivation
++
++ @Description   Define FM behavior on external halt activation.
++                Calling this routine changes the FM behavior on external halt
++                activation in the internal driver data base from its default
++                [DEFAULT_haltOnExternalActivation].
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     enable          TRUE to enable halt on external halt
++                                activation.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigHaltOnExternalActivation(t_Handle h_Fm, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_ConfigHaltOnUnrecoverableEccError
++
++ @Description   Define FM behavior on external halt activation.
++                Calling this routine changes the FM behavior on unrecoverable
++                ECC error in the internal driver data base from its default
++                [DEFAULT_haltOnUnrecoverableEccError].
++                This routine is only avaiable on old FM revisions (FMan v2).
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     enable          TRUE to enable halt on unrecoverable Ecc error
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigHaltOnUnrecoverableEccError(t_Handle h_Fm, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_ConfigException
++
++ @Description   Define FM exceptions.
++                Calling this routine changes the exceptions defaults in the
++                internal driver data base where all exceptions are enabled.
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     exception       The exception to be selected.
++ @Param[in]     enable          TRUE to enable interrupt, FALSE to mask it.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigException(t_Handle h_Fm, e_FmExceptions exception, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_ConfigExternalEccRamsEnable
++
++ @Description   Select external ECC enabling.
++                Calling this routine changes the ECC enabling control in the internal
++                driver data base from its default [DEFAULT_externalEccRamsEnable].
++                When this option is enabled Rams ECC enabling is not effected
++                by FM_EnableRamsEcc/FM_DisableRamsEcc, but by a JTAG.
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     enable          TRUE to enable this option.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigExternalEccRamsEnable(t_Handle h_Fm, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_ConfigTnumAgingPeriod
++
++ @Description   Define Tnum aging period.
++                Calling this routine changes the Tnum aging of dequeue TNUMs
++                in the QMI in the internal driver data base from its default
++                [DEFAULT_tnumAgingPeriod].
++
++ @Param[in]     h_Fm                A handle to an FM Module.
++ @Param[in]     tnumAgingPeriod     Tnum Aging Period in microseconds.
++                                    Note that period is recalculated in units of
++                                    64 FM clocks. Driver will pick the closest
++                                    possible period.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++                NOTE that if some MAC is configured for PFC, '0' value is NOT
++                allowed.
++*//***************************************************************************/
++t_Error FM_ConfigTnumAgingPeriod(t_Handle h_Fm, uint16_t tnumAgingPeriod);
++
++/**************************************************************************//*
++ @Function      FM_ConfigDmaEmergencySmoother
++
++ @Description   Define DMA emergency smoother.
++                Calling this routine changes the definition of the minimum
++                amount of DATA beats transferred on the AXI READ and WRITE
++                ports before lowering the emergency level.
++                By default smoother is disabled.
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     emergencyCnt    emergency switching counter.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigDmaEmergencySmoother(t_Handle h_Fm, uint32_t emergencyCnt);
++
++/**************************************************************************//*
++ @Function      FM_ConfigThresholds
++
++ @Description   Calling this routine changes the internal driver data base
++                from its default FM threshold configuration:
++                    dispLimit:    [DEFAULT_dispLimit]
++                    prsDispTh:    [DEFAULT_prsDispTh]
++                    plcrDispTh:   [DEFAULT_plcrDispTh]
++                    kgDispTh:     [DEFAULT_kgDispTh]
++                    bmiDispTh:    [DEFAULT_bmiDispTh]
++                    qmiEnqDispTh: [DEFAULT_qmiEnqDispTh]
++                    qmiDeqDispTh: [DEFAULT_qmiDeqDispTh]
++                    fmCtl1DispTh: [DEFAULT_fmCtl1DispTh]
++                    fmCtl2DispTh: [DEFAULT_fmCtl2DispTh]
++
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     p_FmThresholds  A structure of threshold parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigThresholds(t_Handle h_Fm, t_FmThresholds *p_FmThresholds);
++
++/**************************************************************************//*
++ @Function      FM_ConfigDmaSosEmergencyThreshold
++
++ @Description   Calling this routine changes the internal driver data base
++                from its default dma SOS emergency configuration [DEFAULT_dmaSosEmergency]
++
++ @Param[in]     h_Fm                A handle to an FM Module.
++ @Param[in]     dmaSosEmergency     The selected new value.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigDmaSosEmergencyThreshold(t_Handle h_Fm, uint32_t dmaSosEmergency);
++
++/**************************************************************************//*
++ @Function      FM_ConfigDmaWriteBufThresholds
++
++ @Description   Calling this routine changes the internal driver data base
++                from its default configuration of DMA write buffer threshold
++                assertEmergency: [DEFAULT_dmaWriteIntBufLow]
++                clearEmergency:  [DEFAULT_dmaWriteIntBufHigh]
++                This routine is only avaiable on old FM revisions (FMan v2).
++
++ @Param[in]     h_Fm                A handle to an FM Module.
++ @Param[in]     p_FmDmaThresholds   A structure of thresholds to define emergency behavior -
++                                    When 'assertEmergency' value is reached, emergency is asserted,
++                                    then it is held until 'clearEmergency' value is reached.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigDmaWriteBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds);
++
++ /**************************************************************************//*
++ @Function      FM_ConfigDmaCommQThresholds
++
++ @Description   Calling this routine changes the internal driver data base
++                from its default configuration of DMA command queue threshold
++                assertEmergency: [DEFAULT_dmaCommQLow]
++                clearEmergency:  [DEFAULT_dmaCommQHigh]
++
++ @Param[in]     h_Fm                A handle to an FM Module.
++ @Param[in]     p_FmDmaThresholds   A structure of thresholds to define emergency behavior -
++                                    When 'assertEmergency' value is reached, emergency is asserted,
++                                    then it is held until 'clearEmergency' value is reached..
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigDmaCommQThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds);
++
++/**************************************************************************//*
++ @Function      FM_ConfigDmaReadBufThresholds
++
++ @Description   Calling this routine changes the internal driver data base
++                from its default configuration of DMA read buffer threshold
++                assertEmergency: [DEFAULT_dmaReadIntBufLow]
++                clearEmergency:  [DEFAULT_dmaReadIntBufHigh]
++                This routine is only avaiable on old FM revisions (FMan v2).
++
++ @Param[in]     h_Fm                A handle to an FM Module.
++ @Param[in]     p_FmDmaThresholds   A structure of thresholds to define emergency behavior -
++                                    When 'assertEmergency' value is reached, emergency is asserted,
++                                    then it is held until 'clearEmergency' value is reached..
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigDmaReadBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds);
++
++/**************************************************************************//*
++ @Function      FM_ConfigDmaWatchdog
++
++ @Description   Calling this routine changes the internal driver data base
++                from its default watchdog configuration, which is disabled
++                [DEFAULT_dmaWatchdog].
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     watchDogValue   The selected new value - in microseconds.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ConfigDmaWatchdog(t_Handle h_Fm, uint32_t watchDogValue);
++
++/** @} */ /* end of FM_advanced_init_grp group */
++/** @} */ /* end of FM_init_grp group */
++
++
++/**************************************************************************//**
++ @Group         FM_runtime_control_grp FM Runtime Control Unit
++
++ @Description   FM Runtime control unit API functions, definitions and enums.
++                The FM driver provides a set of control routines.
++                These routines may only be called after the module was fully
++                initialized (both configuration and initialization routines were
++                called). They are typically used to get information from hardware
++                (status, counters/statistics, revision etc.), to modify a current
++                state or to force/enable a required action. Run-time control may
++                be called whenever necessary and as many times as needed.
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Collection   General FM defines.
++*//***************************************************************************/
++#define FM_MAX_NUM_OF_VALID_PORTS   (FM_MAX_NUM_OF_OH_PORTS +       \
++                                     FM_MAX_NUM_OF_1G_RX_PORTS +    \
++                                     FM_MAX_NUM_OF_10G_RX_PORTS +   \
++                                     FM_MAX_NUM_OF_1G_TX_PORTS +    \
++                                     FM_MAX_NUM_OF_10G_TX_PORTS)      /**< Number of available FM ports */
++/* @} */
++
++/**************************************************************************//*
++ @Description   A Structure for Port bandwidth requirement. Port is identified
++                by type and relative id.
++*//***************************************************************************/
++typedef struct t_FmPortBandwidth {
++    e_FmPortType        type;           /**< FM port type */
++    uint8_t             relativePortId; /**< Type relative port id */
++    uint8_t             bandwidth;      /**< bandwidth - (in term of percents) */
++} t_FmPortBandwidth;
++
++/**************************************************************************//*
++ @Description   A Structure containing an array of Port bandwidth requirements.
++                The user should state the ports requiring bandwidth in terms of
++                percentage - i.e. all port's bandwidths in the array must add
++                up to 100.
++*//***************************************************************************/
++typedef struct t_FmPortsBandwidthParams {
++    uint8_t             numOfPorts;         /**< The number of relevant ports, which is the
++                                                 number of valid entries in the array below */
++    t_FmPortBandwidth   portsBandwidths[FM_MAX_NUM_OF_VALID_PORTS];
++                                            /**< for each port, it's bandwidth (all port's
++                                                 bandwidths must add up to 100.*/
++} t_FmPortsBandwidthParams;
++
++/**************************************************************************//**
++ @Description   DMA Emergency control on MURAM
++*//***************************************************************************/
++typedef enum e_FmDmaMuramPort {
++    e_FM_DMA_MURAM_PORT_WRITE,              /**< MURAM write port */
++    e_FM_DMA_MURAM_PORT_READ                /**< MURAM read port */
++} e_FmDmaMuramPort;
++
++/**************************************************************************//**
++ @Description   Enum for defining FM counters
++*//***************************************************************************/
++typedef enum e_FmCounters {
++    e_FM_COUNTERS_ENQ_TOTAL_FRAME = 0,              /**< QMI total enqueued frames counter */
++    e_FM_COUNTERS_DEQ_TOTAL_FRAME,                  /**< QMI total dequeued frames counter */
++    e_FM_COUNTERS_DEQ_0,                            /**< QMI 0 frames from QMan counter */
++    e_FM_COUNTERS_DEQ_1,                            /**< QMI 1 frames from QMan counter */
++    e_FM_COUNTERS_DEQ_2,                            /**< QMI 2 frames from QMan counter */
++    e_FM_COUNTERS_DEQ_3,                            /**< QMI 3 frames from QMan counter */
++    e_FM_COUNTERS_DEQ_FROM_DEFAULT,                 /**< QMI dequeue from default queue counter */
++    e_FM_COUNTERS_DEQ_FROM_CONTEXT,                 /**< QMI dequeue from FQ context counter */
++    e_FM_COUNTERS_DEQ_FROM_FD,                      /**< QMI dequeue from FD command field counter */
++    e_FM_COUNTERS_DEQ_CONFIRM                       /**< QMI dequeue confirm counter */
++} e_FmCounters;
++
++/**************************************************************************//**
++ @Description   A Structure for returning FM revision information
++*//***************************************************************************/
++typedef struct t_FmRevisionInfo {
++    uint8_t         majorRev;               /**< Major revision */
++    uint8_t         minorRev;               /**< Minor revision */
++} t_FmRevisionInfo;
++
++/**************************************************************************//**
++ @Description   A Structure for returning FM ctrl code revision information
++*//***************************************************************************/
++typedef struct t_FmCtrlCodeRevisionInfo {
++    uint16_t        packageRev;             /**< Package revision */
++    uint8_t         majorRev;               /**< Major revision */
++    uint8_t         minorRev;               /**< Minor revision */
++} t_FmCtrlCodeRevisionInfo;
++
++/**************************************************************************//**
++ @Description   A Structure for defining DMA status
++*//***************************************************************************/
++typedef struct t_FmDmaStatus {
++    bool    cmqNotEmpty;            /**< Command queue is not empty */
++    bool    busError;               /**< Bus error occurred */
++    bool    readBufEccError;        /**< Double ECC error on buffer Read (Valid for FM rev < 6)*/
++    bool    writeBufEccSysError;    /**< Double ECC error on buffer write from system side (Valid for FM rev < 6)*/
++    bool    writeBufEccFmError;     /**< Double ECC error on buffer write from FM side (Valid for FM rev < 6) */
++    bool    singlePortEccError;     /**< Single Port ECC error from FM side (Valid for FM rev >= 6)*/
++} t_FmDmaStatus;
++
++/**************************************************************************//**
++ @Description   A Structure for obtaining FM controller monitor values
++*//***************************************************************************/
++typedef struct t_FmCtrlMon {
++    uint8_t percentCnt[2];          /**< Percentage value */
++} t_FmCtrlMon;
++
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++/**************************************************************************//**
++ @Function      FM_DumpRegs
++
++ @Description   Dumps all FM registers
++
++ @Param[in]     h_Fm      A handle to an FM Module.
++
++ @Return        E_OK on success;
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++t_Error FM_DumpRegs(t_Handle h_Fm);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++/**************************************************************************//**
++ @Function      FM_SetException
++
++ @Description   Calling this routine enables/disables the specified exception.
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     exception       The exception to be selected.
++ @Param[in]     enable          TRUE to enable interrupt, FALSE to mask it.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_SetException(t_Handle h_Fm, e_FmExceptions exception, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_EnableRamsEcc
++
++ @Description   Enables ECC mechanism for all the different FM RAM's; E.g. IRAM,
++                MURAM, Parser, Keygen, Policer, etc.
++                Note:
++                If FM_ConfigExternalEccRamsEnable was called to enable external
++                setting of ECC, this routine effects IRAM ECC only.
++                This routine is also called by the driver if an ECC exception is
++                enabled.
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_EnableRamsEcc(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FM_DisableRamsEcc
++
++ @Description   Disables ECC mechanism for all the different FM RAM's; E.g. IRAM,
++                MURAM, Parser, Keygen, Policer, etc.
++                Note:
++                If FM_ConfigExternalEccRamsEnable was called to enable external
++                setting of ECC, this routine effects IRAM ECC only.
++                In opposed to FM_EnableRamsEcc, this routine must be called
++                explicitly to disable all Rams ECC.
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Config() and before FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_DisableRamsEcc(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FM_GetRevision
++
++ @Description   Returns the FM revision
++
++ @Param[in]     h_Fm                A handle to an FM Module.
++ @Param[out]    p_FmRevisionInfo    A structure of revision information parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++t_Error  FM_GetRevision(t_Handle h_Fm, t_FmRevisionInfo *p_FmRevisionInfo);
++
++/**************************************************************************//**
++ @Function      FM_GetFmanCtrlCodeRevision
++
++ @Description   Returns the Fman controller code revision
++
++ @Param[in]     h_Fm                A handle to an FM Module.
++ @Param[out]    p_RevisionInfo      A structure of revision information parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++t_Error FM_GetFmanCtrlCodeRevision(t_Handle h_Fm, t_FmCtrlCodeRevisionInfo *p_RevisionInfo);
++
++/**************************************************************************//**
++ @Function      FM_GetCounter
++
++ @Description   Reads one of the FM counters.
++
++ @Param[in]     h_Fm        A handle to an FM Module.
++ @Param[in]     counter     The requested counter.
++
++ @Return        Counter's current value.
++
++ @Cautions      Allowed only following FM_Init().
++                Note that it is user's responsibility to call this routine only
++                for enabled counters, and there will be no indication if a
++                disabled counter is accessed.
++*//***************************************************************************/
++uint32_t  FM_GetCounter(t_Handle h_Fm, e_FmCounters counter);
++
++/**************************************************************************//**
++ @Function      FM_ModifyCounter
++
++ @Description   Sets a value to an enabled counter. Use "0" to reset the counter.
++
++ @Param[in]     h_Fm        A handle to an FM Module.
++ @Param[in]     counter     The requested counter.
++ @Param[in]     val         The requested value to be written into the counter.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error  FM_ModifyCounter(t_Handle h_Fm, e_FmCounters counter, uint32_t val);
++
++/**************************************************************************//**
++ @Function      FM_Resume
++
++ @Description   Release FM after halt FM command or after unrecoverable ECC error.
++
++ @Param[in]     h_Fm        A handle to an FM Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++void FM_Resume(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FM_SetDmaEmergency
++
++ @Description   Manual emergency set
++
++ @Param[in]     h_Fm        A handle to an FM Module.
++ @Param[in]     muramPort   MURAM direction select.
++ @Param[in]     enable      TRUE to manually enable emergency, FALSE to disable.
++
++ @Return        None.
++
++ @Cautions      Allowed only following FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++void FM_SetDmaEmergency(t_Handle h_Fm, e_FmDmaMuramPort muramPort, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_SetDmaExtBusPri
++
++ @Description   Set the DMA external bus priority
++
++ @Param[in]     h_Fm    A handle to an FM Module.
++ @Param[in]     pri     External bus priority select
++
++ @Return        None.
++
++ @Cautions      Allowed only following FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++void FM_SetDmaExtBusPri(t_Handle h_Fm, e_FmDmaExtBusPri pri);
++
++/**************************************************************************//**
++ @Function      FM_GetDmaStatus
++
++ @Description   Reads the DMA current status
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[out]    p_FmDmaStatus   A structure of DMA status parameters.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++void FM_GetDmaStatus(t_Handle h_Fm, t_FmDmaStatus *p_FmDmaStatus);
++
++/**************************************************************************//**
++ @Function      FM_ErrorIsr
++
++ @Description   FM interrupt-service-routine for errors.
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++
++ @Return        E_OK on success; E_EMPTY if no errors found in register, other
++                error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ErrorIsr(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FM_EventIsr
++
++ @Description   FM interrupt-service-routine for normal events.
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++
++ @Cautions      Allowed only following FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++void FM_EventIsr(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FM_GetSpecialOperationCoding
++
++ @Description   Return a specific coding according to the input mask.
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     spOper          special operation mask.
++ @Param[out]    p_SpOperCoding  special operation code.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++t_Error FM_GetSpecialOperationCoding(t_Handle               h_Fm,
++                                     fmSpecialOperations_t  spOper,
++                                     uint8_t                *p_SpOperCoding);
++
++/**************************************************************************//**
++ @Function      FM_CtrlMonStart
++
++ @Description   Start monitoring utilization of all available FM controllers.
++
++                In order to obtain FM controllers utilization the following sequence
++                should be used:
++                -# FM_CtrlMonStart()
++                -# FM_CtrlMonStop()
++                -# FM_CtrlMonGetCounters() - issued for each FM controller
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID).
++*//***************************************************************************/
++t_Error FM_CtrlMonStart(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FM_CtrlMonStop
++
++ @Description   Stop monitoring utilization of all available FM controllers.
++
++                In order to obtain FM controllers utilization the following sequence
++                should be used:
++                -# FM_CtrlMonStart()
++                -# FM_CtrlMonStop()
++                -# FM_CtrlMonGetCounters() - issued for each FM controller
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID).
++*//***************************************************************************/
++t_Error FM_CtrlMonStop(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FM_CtrlMonGetCounters
++
++ @Description   Obtain FM controller utilization parameters.
++
++                In order to obtain FM controllers utilization the following sequence
++                should be used:
++                -# FM_CtrlMonStart()
++                -# FM_CtrlMonStop()
++                -# FM_CtrlMonGetCounters() - issued for each FM controller
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     fmCtrlIndex     FM Controller index for that utilization results
++                                are requested.
++ @Param[in]     p_Mon           Pointer to utilization results structure.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID).
++*//***************************************************************************/
++t_Error FM_CtrlMonGetCounters(t_Handle h_Fm, uint8_t fmCtrlIndex, t_FmCtrlMon *p_Mon);
++
++
++/**************************************************************************//*
++ @Function      FM_ForceIntr
++
++ @Description   Causes an interrupt event on the requested source.
++
++ @Param[in]     h_Fm            A handle to an FM Module.
++ @Param[in]     exception       An exception to be forced.
++
++ @Return        E_OK on success; Error code if the exception is not enabled,
++                or is not able to create interrupt.
++
++ @Cautions      Allowed only following FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_ForceIntr (t_Handle h_Fm, e_FmExceptions exception);
++
++/**************************************************************************//*
++ @Function      FM_SetPortsBandwidth
++
++ @Description   Sets relative weights between ports when accessing common resources.
++
++ @Param[in]     h_Fm                A handle to an FM Module.
++ @Param[in]     p_PortsBandwidth    A structure of ports bandwidths in percentage, i.e.
++                                    total must equal 100.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_SetPortsBandwidth(t_Handle h_Fm, t_FmPortsBandwidthParams *p_PortsBandwidth);
++
++/**************************************************************************//*
++ @Function      FM_GetMuramHandle
++
++ @Description   Gets the corresponding MURAM handle
++
++ @Param[in]     h_Fm                A handle to an FM Module.
++
++ @Return        MURAM handle; NULL otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Handle FM_GetMuramHandle(t_Handle h_Fm);
++
++/** @} */ /* end of FM_runtime_control_grp group */
++/** @} */ /* end of FM_lib_grp group */
++/** @} */ /* end of FM_grp group */
++
++
++#ifdef NCSW_BACKWARD_COMPATIBLE_API
++typedef t_FmFirmwareParams          t_FmPcdFirmwareParams;
++typedef t_FmBufferPrefixContent     t_FmPortBufferPrefixContent;
++typedef t_FmExtPoolParams           t_FmPortExtPoolParams;
++typedef t_FmExtPools                t_FmPortExtPools;
++typedef t_FmBackupBmPools           t_FmPortBackupBmPools;
++typedef t_FmBufPoolDepletion        t_FmPortBufPoolDepletion;
++typedef e_FmDmaSwapOption           e_FmPortDmaSwapOption;
++typedef e_FmDmaCacheOption          e_FmPortDmaCacheOption;
++
++#define FM_CONTEXTA_GET_OVVERIDE    FM_CONTEXTA_GET_OVERRIDE
++#define FM_CONTEXTA_SET_OVVERIDE    FM_CONTEXTA_SET_OVERRIDE
++
++#define e_FM_EX_BMI_PIPELINE_ECC    e_FM_EX_BMI_STORAGE_PROFILE_ECC
++#define e_FM_PORT_DMA_NO_SWP        e_FM_DMA_NO_SWP
++#define e_FM_PORT_DMA_SWP_PPC_LE    e_FM_DMA_SWP_PPC_LE
++#define e_FM_PORT_DMA_SWP_BE        e_FM_DMA_SWP_BE
++#define e_FM_PORT_DMA_NO_STASH      e_FM_DMA_NO_STASH
++#define e_FM_PORT_DMA_STASH         e_FM_DMA_STASH
++#endif /* NCSW_BACKWARD_COMPATIBLE_API */
++
++
++#endif /* __FM_EXT */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_mac_ext.h
+@@ -0,0 +1,859 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          fm_mac_ext.h
++
++ @Description   FM MAC ...
++*//***************************************************************************/
++#ifndef __FM_MAC_EXT_H
++#define __FM_MAC_EXT_H
++
++#include "std_ext.h"
++#include "enet_ext.h"
++
++
++/**************************************************************************//**
++
++ @Group         FM_grp Frame Manager API
++
++ @Description   FM API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         FM_mac_grp FM MAC
++
++ @Description   FM MAC API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++#define FM_MAC_NO_PFC   0xff
++
++
++/**************************************************************************//**
++ @Description   FM MAC Exceptions
++*//***************************************************************************/
++typedef enum e_FmMacExceptions {
++    e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO = 0                     /**< 10GEC MDIO scan event interrupt */
++   ,e_FM_MAC_EX_10G_MDIO_CMD_CMPL                               /**< 10GEC MDIO command completion interrupt */
++   ,e_FM_MAC_EX_10G_REM_FAULT                                   /**< 10GEC, mEMAC Remote fault interrupt */
++   ,e_FM_MAC_EX_10G_LOC_FAULT                                   /**< 10GEC, mEMAC Local fault interrupt */
++   ,e_FM_MAC_EX_10G_1TX_ECC_ER                                  /**< 10GEC, mEMAC Transmit frame ECC error interrupt */
++   ,e_FM_MAC_EX_10G_TX_FIFO_UNFL                                /**< 10GEC, mEMAC Transmit FIFO underflow interrupt */
++   ,e_FM_MAC_EX_10G_TX_FIFO_OVFL                                /**< 10GEC, mEMAC Transmit FIFO overflow interrupt */
++   ,e_FM_MAC_EX_10G_TX_ER                                       /**< 10GEC Transmit frame error interrupt */
++   ,e_FM_MAC_EX_10G_RX_FIFO_OVFL                                /**< 10GEC, mEMAC Receive FIFO overflow interrupt */
++   ,e_FM_MAC_EX_10G_RX_ECC_ER                                   /**< 10GEC, mEMAC Receive frame ECC error interrupt */
++   ,e_FM_MAC_EX_10G_RX_JAB_FRM                                  /**< 10GEC Receive jabber frame interrupt */
++   ,e_FM_MAC_EX_10G_RX_OVRSZ_FRM                                /**< 10GEC Receive oversized frame interrupt */
++   ,e_FM_MAC_EX_10G_RX_RUNT_FRM                                 /**< 10GEC Receive runt frame interrupt */
++   ,e_FM_MAC_EX_10G_RX_FRAG_FRM                                 /**< 10GEC Receive fragment frame interrupt */
++   ,e_FM_MAC_EX_10G_RX_LEN_ER                                   /**< 10GEC Receive payload length error interrupt */
++   ,e_FM_MAC_EX_10G_RX_CRC_ER                                   /**< 10GEC Receive CRC error interrupt */
++   ,e_FM_MAC_EX_10G_RX_ALIGN_ER                                 /**< 10GEC Receive alignment error interrupt */
++   ,e_FM_MAC_EX_1G_BAB_RX                                       /**< dTSEC Babbling receive error */
++   ,e_FM_MAC_EX_1G_RX_CTL                                       /**< dTSEC Receive control (pause frame) interrupt */
++   ,e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET                      /**< dTSEC Graceful transmit stop complete */
++   ,e_FM_MAC_EX_1G_BAB_TX                                       /**< dTSEC Babbling transmit error */
++   ,e_FM_MAC_EX_1G_TX_CTL                                       /**< dTSEC Transmit control (pause frame) interrupt */
++   ,e_FM_MAC_EX_1G_TX_ERR                                       /**< dTSEC Transmit error */
++   ,e_FM_MAC_EX_1G_LATE_COL                                     /**< dTSEC Late collision */
++   ,e_FM_MAC_EX_1G_COL_RET_LMT                                  /**< dTSEC Collision retry limit */
++   ,e_FM_MAC_EX_1G_TX_FIFO_UNDRN                                /**< dTSEC Transmit FIFO underrun */
++   ,e_FM_MAC_EX_1G_MAG_PCKT                                     /**< dTSEC Magic Packet detection */
++   ,e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET                           /**< dTSEC MII management read completion */
++   ,e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET                           /**< dTSEC MII management write completion */
++   ,e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET                      /**< dTSEC Graceful receive stop complete */
++   ,e_FM_MAC_EX_1G_TX_DATA_ERR                                  /**< dTSEC Internal data error on transmit */
++   ,e_FM_MAC_EX_1G_RX_DATA_ERR                                  /**< dTSEC Internal data error on receive */
++   ,e_FM_MAC_EX_1G_1588_TS_RX_ERR                               /**< dTSEC Time-Stamp Receive Error */
++   ,e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL                              /**< dTSEC MIB counter overflow */
++   ,e_FM_MAC_EX_TS_FIFO_ECC_ERR                                 /**< mEMAC Time-stamp FIFO ECC error interrupt;
++                                                                     not supported on T4240/B4860 rev1 chips */
++   ,e_FM_MAC_EX_MAGIC_PACKET_INDICATION = e_FM_MAC_EX_1G_MAG_PCKT
++                                                                /**< mEMAC Magic Packet Indication Interrupt */
++} e_FmMacExceptions;
++
++/**************************************************************************//**
++ @Description   TM MAC statistics level
++*//***************************************************************************/
++typedef enum e_FmMacStatisticsLevel {
++    e_FM_MAC_NONE_STATISTICS = 0,       /**< No statistics */
++    e_FM_MAC_PARTIAL_STATISTICS,        /**< Only error counters are available; Optimized for performance */
++    e_FM_MAC_FULL_STATISTICS            /**< All counters available; Not optimized for performance */
++} e_FmMacStatisticsLevel;
++
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Description   Priority Flow Control Parameters
++*//***************************************************************************/
++typedef struct t_FmMacPfcParams {
++    bool        pfcEnable;                                      /**< Enable/Disable PFC */
++
++    uint16_t    pauseQuanta[FM_MAX_NUM_OF_PFC_PRIORITIES];      /**< Pause Quanta per priority to be sent in a pause frame. Each quanta represents a 512 bit-times*/
++
++    uint16_t    pauseThresholdQuanta[FM_MAX_NUM_OF_PFC_PRIORITIES];/**< Pause threshold per priority, when timer passes this threshold time a PFC frames is sent again if the port is still congested or BM pool in depletion*/
++
++
++} t_FmMacPfcParams;
++#endif /* (DPAA_VERSION >= 11) */
++
++/**************************************************************************//**
++ @Function      t_FmMacExceptionCallback
++
++ @Description   Fm Mac Exception Callback from FM MAC to the user
++
++ @Param[in]     h_App             - Handle to the upper layer handler
++
++ @Param[in]     exceptions        - The exception that occurred
++
++ @Return        void.
++*//***************************************************************************/
++typedef void (t_FmMacExceptionCallback)(t_Handle h_App, e_FmMacExceptions exceptions);
++
++
++/**************************************************************************//**
++ @Description   TM MAC statistics rfc3635
++*//***************************************************************************/
++typedef struct t_FmMacStatistics {
++/* RMON */
++    uint64_t  eStatPkts64;             /**< r-10G tr-DT 64 byte frame counter */
++    uint64_t  eStatPkts65to127;        /**< r-10G 65 to 127 byte frame counter */
++    uint64_t  eStatPkts128to255;       /**< r-10G 128 to 255 byte frame counter */
++    uint64_t  eStatPkts256to511;       /**< r-10G 256 to 511 byte frame counter */
++    uint64_t  eStatPkts512to1023;      /**< r-10G 512 to 1023 byte frame counter */
++    uint64_t  eStatPkts1024to1518;     /**< r-10G 1024 to 1518 byte frame counter */
++    uint64_t  eStatPkts1519to1522;     /**< r-10G 1519 to 1522 byte good frame count */
++/* */
++    uint64_t  eStatFragments;          /**< Total number of packets that were less than 64 octets long with a wrong CRC.*/
++    uint64_t  eStatJabbers;            /**< Total number of packets longer than valid maximum length octets */
++    uint64_t  eStatsDropEvents;        /**< number of dropped packets due to internal errors of the MAC Client (during receive). */
++    uint64_t  eStatCRCAlignErrors;     /**< Incremented when frames of correct length but with CRC error are received.*/
++    uint64_t  eStatUndersizePkts;      /**< Incremented for frames under 64 bytes with a valid FCS and otherwise well formed;
++                                            This count does not include range length errors */
++    uint64_t  eStatOversizePkts;       /**< Incremented for frames which exceed 1518 (non VLAN) or 1522 (VLAN) and contains
++                                            a valid FCS and otherwise well formed */
++/* Pause */
++    uint64_t  teStatPause;             /**< Pause MAC Control received */
++    uint64_t  reStatPause;             /**< Pause MAC Control sent */
++/* MIB II */
++    uint64_t  ifInOctets;              /**< Total number of byte received. */
++    uint64_t  ifInPkts;                /**< Total number of packets received.*/
++    uint64_t  ifInUcastPkts;           /**< Total number of unicast frame received;
++                                            NOTE: this counter is not supported on dTSEC MAC */
++    uint64_t  ifInMcastPkts;           /**< Total number of multicast frame received*/
++    uint64_t  ifInBcastPkts;           /**< Total number of broadcast frame received */
++    uint64_t  ifInDiscards;            /**< Frames received, but discarded due to problems within the MAC RX. */
++    uint64_t  ifInErrors;              /**< Number of frames received with error:
++                                               - FIFO Overflow Error
++                                               - CRC Error
++                                               - Frame Too Long Error
++                                               - Alignment Error
++                                               - The dedicated Error Code (0xfe, not a code error) was received */
++    uint64_t  ifOutOctets;             /**< Total number of byte sent. */
++    uint64_t  ifOutPkts;               /**< Total number of packets sent .*/
++    uint64_t  ifOutUcastPkts;          /**< Total number of unicast frame sent;
++                                            NOTE: this counter is not supported on dTSEC MAC */
++    uint64_t  ifOutMcastPkts;          /**< Total number of multicast frame sent */
++    uint64_t  ifOutBcastPkts;          /**< Total number of multicast frame sent */
++    uint64_t  ifOutDiscards;           /**< Frames received, but discarded due to problems within the MAC TX N/A!.*/
++    uint64_t  ifOutErrors;             /**< Number of frames transmitted with error:
++                                               - FIFO Overflow Error
++                                               - FIFO Underflow Error
++                                               - Other */
++} t_FmMacStatistics;
++
++
++/**************************************************************************//**
++ @Group         FM_mac_init_grp FM MAC Initialization Unit
++
++ @Description   FM MAC Initialization Unit
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   FM MAC config input
++*//***************************************************************************/
++typedef struct t_FmMacParams {
++    uintptr_t                   baseAddr;           /**< Base of memory mapped FM MAC registers */
++    t_EnetAddr                  addr;               /**< MAC address of device; First octet is sent first */
++    uint8_t                     macId;              /**< MAC ID;
++                                                         numbering of dTSEC and 1G-mEMAC:
++                                                            0 - FM_MAX_NUM_OF_1G_MACS;
++                                                         numbering of 10G-MAC (TGEC) and 10G-mEMAC:
++                                                            0 - FM_MAX_NUM_OF_10G_MACS */
++    e_EnetMode                  enetMode;           /**< Ethernet operation mode (MAC-PHY interface and speed);
++                                                         Note that the speed should indicate the maximum rate that
++                                                         this MAC should support rather than the actual speed;
++                                                         i.e. user should use the FM_MAC_AdjustLink() routine to
++                                                         provide accurate speed;
++                                                         In case of mEMAC RGMII mode, the MAC is configured to RGMII
++                                                         automatic mode, where actual speed/duplex mode information
++                                                         is provided by PHY automatically in-band; FM_MAC_AdjustLink()
++                                                         function should be used to switch to manual RGMII speed/duplex mode
++                                                         configuration if RGMII PHY doesn't support in-band status signaling;
++                                                         In addition, in mEMAC, in case where user is using the higher MACs
++                                                         (i.e. the MACs that should support 10G), user should pass here
++                                                         speed=10000 even if the interface is not allowing that (e.g. SGMII). */
++    t_Handle                    h_Fm;               /**< A handle to the FM object this port related to */
++    int                         mdioIrq;            /**< MDIO exceptions interrupt source - not valid for all
++                                                         MACs; MUST be set to 'NO_IRQ' for MACs that don't have
++                                                         mdio-irq, or for polling */
++    t_FmMacExceptionCallback    *f_Event;           /**< MDIO Events Callback Routine         */
++    t_FmMacExceptionCallback    *f_Exception;       /**< Exception Callback Routine         */
++    t_Handle                    h_App;              /**< A handle to an application layer object; This handle will
++                                                         be passed by the driver upon calling the above callbacks */
++} t_FmMacParams;
++
++
++/**************************************************************************//**
++ @Function      FM_MAC_Config
++
++ @Description   Creates descriptor for the FM MAC module.
++
++                The routine returns a handle (descriptor) to the FM MAC object.
++                This descriptor must be passed as first parameter to all other
++                FM MAC function calls.
++
++                No actual initialization or configuration of FM MAC hardware is
++                done by this routine.
++
++ @Param[in]     p_FmMacParam   - Pointer to data structure of parameters
++
++ @Retval        Handle to FM MAC object, or NULL for Failure.
++*//***************************************************************************/
++t_Handle FM_MAC_Config(t_FmMacParams *p_FmMacParam);
++
++/**************************************************************************//**
++ @Function      FM_MAC_Init
++
++ @Description   Initializes the FM MAC module
++
++ @Param[in]     h_FmMac - FM module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error  FM_MAC_Init(t_Handle h_FmMac);
++
++/**************************************************************************//**
++ @Function      FM_Free
++
++ @Description   Frees all resources that were assigned to FM MAC module.
++
++                Calling this routine invalidates the descriptor.
++
++ @Param[in]     h_FmMac - FM module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error  FM_MAC_Free(t_Handle h_FmMac);
++
++
++/**************************************************************************//**
++ @Group         FM_mac_advanced_init_grp    FM MAC Advanced Configuration Unit
++
++ @Description   Configuration functions used to change default values.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      FM_MAC_ConfigResetOnInit
++
++ @Description   Tell the driver whether to reset the FM MAC before initialization or
++                not. It changes the default configuration [DEFAULT_resetOnInit].
++
++ @Param[in]     h_FmMac    A handle to a FM MAC Module.
++ @Param[in]     enable     When TRUE, FM will be reset before any initialization.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Config() and before FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_ConfigResetOnInit(t_Handle h_FmMac, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_MAC_ConfigLoopback
++
++ @Description   Enable/Disable internal loopback mode
++
++ @Param[in]     h_FmMac    A handle to a FM MAC Module.
++ @Param[in]     enable     TRUE to enable or FALSE to disable.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Config() and before FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_ConfigLoopback(t_Handle h_FmMac, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_MAC_ConfigMaxFrameLength
++
++ @Description   Setup maximum Rx Frame Length (in 1G MAC, effects also Tx)
++
++ @Param[in]     h_FmMac    A handle to a FM MAC Module.
++ @Param[in]     newVal     MAX Frame length
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Config() and before FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_ConfigMaxFrameLength(t_Handle h_FmMac, uint16_t newVal);
++
++/**************************************************************************//**
++ @Function      FM_MAC_ConfigWan
++
++ @Description   ENABLE WAN mode in 10G-MAC
++
++ @Param[in]     h_FmMac    A handle to a FM MAC Module.
++ @Param[in]     enable     TRUE to enable or FALSE to disable.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Config() and before FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_ConfigWan(t_Handle h_FmMac, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_MAC_ConfigPadAndCrc
++
++ @Description   Config PAD and CRC mode
++
++ @Param[in]     h_FmMac    A handle to a FM MAC Module.
++ @Param[in]     enable     TRUE to enable or FALSE to disable.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Config() and before FM_MAC_Init().
++                Not supported on 10G-MAC (i.e. CRC & PAD are added automatically
++                by HW); on mEMAC, this routine supports only PAD (i.e. CRC is
++                added automatically by HW).
++*//***************************************************************************/
++t_Error FM_MAC_ConfigPadAndCrc(t_Handle h_FmMac, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_MAC_ConfigHalfDuplex
++
++ @Description   Config Half Duplex Mode
++
++ @Param[in]     h_FmMac    A handle to a FM MAC Module.
++ @Param[in]     enable     TRUE to enable or FALSE to disable.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Config() and before FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_ConfigHalfDuplex(t_Handle h_FmMac, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_MAC_ConfigTbiPhyAddr
++
++ @Description   Configures the address of internal TBI PHY.
++
++ @Param[in]     h_FmMac    A handle to a FM MAC Module.
++ @Param[in]     newVal     TBI PHY address (1-31).
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Config() and before FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_ConfigTbiPhyAddr(t_Handle h_FmMac, uint8_t newVal);
++
++/**************************************************************************//**
++ @Function      FM_MAC_ConfigLengthCheck
++
++ @Description   Configure the frame length checking.
++
++ @Param[in]     h_FmMac    A handle to a FM MAC Module.
++ @Param[in]     enable     TRUE to enable or FALSE to disable.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Config() and before FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_ConfigLengthCheck(t_Handle h_FmMac, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_MAC_ConfigException
++
++ @Description   Change Exception selection from default
++
++ @Param[in]     h_FmMac         A handle to a FM MAC Module.
++ @Param[in]     ex              Type of the desired exceptions
++ @Param[in]     enable          TRUE to enable the specified exception, FALSE to disable it.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Config() and before FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_ConfigException(t_Handle h_FmMac, e_FmMacExceptions ex, bool enable);
++
++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
++t_Error FM_MAC_ConfigSkipFman11Workaround (t_Handle h_FmMac);
++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
++/** @} */ /* end of FM_mac_advanced_init_grp group */
++/** @} */ /* end of FM_mac_init_grp group */
++
++
++/**************************************************************************//**
++ @Group         FM_mac_runtime_control_grp FM MAC Runtime Control Unit
++
++ @Description   FM MAC Runtime control unit API functions, definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      FM_MAC_Enable
++
++ @Description   Enable the MAC
++
++ @Param[in]     h_FmMac    A handle to a FM MAC Module.
++ @Param[in]     mode       Mode of operation (RX, TX, Both)
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_Enable(t_Handle h_FmMac,  e_CommMode mode);
++
++/**************************************************************************//**
++ @Function      FM_MAC_Disable
++
++ @Description   DISABLE the MAC
++
++ @Param[in]     h_FmMac    A handle to a FM MAC Module.
++ @Param[in]     mode       Define what part to Disable (RX,  TX or BOTH)
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_Disable(t_Handle h_FmMac, e_CommMode mode);
++
++/**************************************************************************//**
++ @Function      FM_MAC_Resume
++
++ @Description   Re-init the MAC after suspend
++
++ @Param[in]     h_FmMac    A handle to a FM MAC Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_Resume(t_Handle h_FmMac);
++
++/**************************************************************************//**
++ @Function      FM_MAC_Enable1588TimeStamp
++
++ @Description   Enables the TSU operation.
++
++ @Param[in]     h_Fm   - Handle to the PTP as returned from the FM_MAC_PtpConfig.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_Enable1588TimeStamp(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FM_MAC_Disable1588TimeStamp
++
++ @Description   Disables the TSU operation.
++
++ @Param[in]     h_Fm   - Handle to the PTP as returned from the FM_MAC_PtpConfig.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_Disable1588TimeStamp(t_Handle h_Fm);
++
++/**************************************************************************//**
++ @Function      FM_MAC_SetTxAutoPauseFrames
++
++ @Description   Enable/Disable transmission of Pause-Frames.
++                The routine changes the default configuration [DEFAULT_TX_PAUSE_TIME].
++
++ @Param[in]     h_FmMac       -  A handle to a FM MAC Module.
++ @Param[in]     pauseTime     -  Pause quanta value used with transmitted pause frames.
++                                 Each quanta represents a 512 bit-times; Note that '0'
++                                 as an input here will be used as disabling the
++                                 transmission of the pause-frames.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_SetTxAutoPauseFrames(t_Handle h_FmMac,
++                                    uint16_t pauseTime);
++
++ /**************************************************************************//**
++ @Function      FM_MAC_SetTxPauseFrames
++
++ @Description   Enable/Disable transmission of Pause-Frames.
++                The routine changes the default configuration:
++                pause-time - [DEFAULT_TX_PAUSE_TIME]
++                threshold-time - [0]
++
++ @Param[in]     h_FmMac       -  A handle to a FM MAC Module.
++ @Param[in]     priority      -  the PFC class of service; use 'FM_MAC_NO_PFC'
++                                 to indicate legacy pause support (i.e. no PFC).
++ @Param[in]     pauseTime     -  Pause quanta value used with transmitted pause frames.
++                                 Each quanta represents a 512 bit-times;
++                                 Note that '0' as an input here will be used as disabling the
++                                 transmission of the pause-frames.
++ @Param[in]     threshTime    -  Pause Threshold equanta value used by the MAC to retransmit pause frame.
++                                 if the situation causing a pause frame to be sent didn't finish when the timer
++                                 reached the threshold quanta, the MAC will retransmit the pause frame.
++                                 Each quanta represents a 512 bit-times.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init().
++                In order for PFC to work properly the user must configure
++                TNUM-aging in the tx-port it is recommended that pre-fetch and
++                rate limit in the tx port should be disabled;
++                PFC is supported only on new mEMAC; i.e. in MACs that don't have
++                PFC support (10G-MAC and dTSEC), user should use 'FM_MAC_NO_PFC'
++                in the 'priority' field.
++*//***************************************************************************/
++t_Error FM_MAC_SetTxPauseFrames(t_Handle h_FmMac,
++                                uint8_t  priority,
++                                uint16_t pauseTime,
++                                uint16_t threshTime);
++
++/**************************************************************************//**
++ @Function      FM_MAC_SetRxIgnorePauseFrames
++
++ @Description   Enable/Disable ignoring of Pause-Frames.
++
++ @Param[in]     h_FmMac    - A handle to a FM MAC Module.
++ @Param[in]     en         - boolean indicates whether to ignore the incoming pause
++                             frames or not.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_SetRxIgnorePauseFrames(t_Handle h_FmMac, bool en);
++
++/**************************************************************************//**
++ @Function      FM_MAC_SetWakeOnLan
++
++ @Description   Enable/Disable Wake On Lan support
++
++ @Param[in]     h_FmMac    - A handle to a FM MAC Module.
++ @Param[in]     en         - boolean indicates whether to enable Wake On Lan
++                             support or not.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_SetWakeOnLan(t_Handle h_FmMac, bool en);
++
++/**************************************************************************//**
++ @Function      FM_MAC_ResetCounters
++
++ @Description   reset all statistics counters
++
++ @Param[in]     h_FmMac    - A handle to a FM MAC Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_ResetCounters(t_Handle h_FmMac);
++
++/**************************************************************************//**
++ @Function      FM_MAC_SetException
++
++ @Description   Enable/Disable a specific Exception
++
++ @Param[in]     h_FmMac        - A handle to a FM MAC Module.
++ @Param[in]     ex             - Type of the desired exceptions
++ @Param[in]     enable         - TRUE to enable the specified exception, FALSE to disable it.
++
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_SetException(t_Handle h_FmMac, e_FmMacExceptions ex, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_MAC_SetStatistics
++
++ @Description   Define Statistics level.
++                Where applicable, the routine also enables the MIB counters
++                overflow interrupt in order to keep counters accurate
++                and account for overflows.
++                This routine is relevant only for dTSEC.
++
++ @Param[in]     h_FmMac         - A handle to a FM MAC Module.
++ @Param[in]     statisticsLevel - Full statistics level provides all standard counters but may
++                                  reduce performance. Partial statistics provides only special
++                                  event counters (errors etc.). If selected, regular counters (such as
++                                  byte/packet) will be invalid and will return -1.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_SetStatistics(t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel);
++
++/**************************************************************************//**
++ @Function      FM_MAC_GetStatistics
++
++ @Description   get all statistics counters
++
++ @Param[in]     h_FmMac       -  A handle to a FM MAC Module.
++ @Param[in]     p_Statistics  -  Structure with statistics
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++t_Error FM_MAC_GetStatistics(t_Handle h_FmMac, t_FmMacStatistics *p_Statistics);
++
++/**************************************************************************//**
++ @Function      FM_MAC_ModifyMacAddr
++
++ @Description   Replace the main MAC Address
++
++ @Param[in]     h_FmMac     -   A handle to a FM Module.
++ @Param[in]     p_EnetAddr  -   Ethernet Mac address
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only after FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_ModifyMacAddr(t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
++
++/**************************************************************************//**
++ @Function      FM_MAC_AddHashMacAddr
++
++ @Description   Add an Address to the hash table. This is for filter purpose only.
++
++ @Param[in]     h_FmMac     -   A handle to a FM Module.
++ @Param[in]     p_EnetAddr  -   Ethernet Mac address
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init(). It is a filter only address.
++ @Cautions      Some address need to be filterd out in upper FM blocks.
++*//***************************************************************************/
++t_Error FM_MAC_AddHashMacAddr(t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
++
++/**************************************************************************//**
++ @Function      FM_MAC_RemoveHashMacAddr
++
++ @Description   Delete an Address to the hash table. This is for filter purpose only.
++
++ @Param[in]     h_FmMac     -   A handle to a FM Module.
++ @Param[in]     p_EnetAddr  -   Ethernet Mac address
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_RemoveHashMacAddr(t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
++
++/**************************************************************************//**
++ @Function      FM_MAC_AddExactMatchMacAddr
++
++ @Description   Add a unicast or multicast mac address for exact-match filtering
++                (8 on dTSEC, 2 for 10G-MAC)
++
++ @Param[in]     h_FmMac     -   A handle to a FM Module.
++ @Param[in]     p_EnetAddr  -   MAC Address to ADD
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only after FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_AddExactMatchMacAddr(t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
++
++/**************************************************************************//**
++ @Function      FM_MAC_RemovelExactMatchMacAddr
++
++ @Description   Remove a uni cast or multi cast mac address.
++
++ @Param[in]     h_FmMac     -   A handle to a FM Module.
++ @Param[in]     p_EnetAddr  -   MAC Address to remove
++
++ @Return        E_OK on success; Error code otherwise..
++
++ @Cautions      Allowed only after FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_RemovelExactMatchMacAddr(t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
++
++/**************************************************************************//**
++ @Function      FM_MAC_SetPromiscuous
++
++ @Description   Enable/Disable MAC Promiscuous mode for ALL mac addresses.
++
++ @Param[in]     h_FmMac    - A handle to a FM MAC Module.
++ @Param[in]     enable     - TRUE to enable or FALSE to disable.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only after FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_SetPromiscuous(t_Handle h_FmMac, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_MAC_AdjustLink
++
++ @Description   Adjusts the Ethernet link with new speed/duplex setup.
++                This routine is relevant for dTSEC and mEMAC.
++                In case of mEMAC, this routine is also used for manual
++                re-configuration of RGMII speed and duplex mode for
++                RGMII PHYs not supporting in-band status information
++                to MAC.
++
++ @Param[in]     h_FmMac     - A handle to a FM Module.
++ @Param[in]     speed       - Ethernet speed.
++ @Param[in]     fullDuplex  - TRUE for full-duplex mode;
++                              FALSE for half-duplex mode.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_MAC_AdjustLink(t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex);
++
++/**************************************************************************//**
++ @Function      FM_MAC_RestartAutoneg
++
++ @Description   Restarts the auto-negotiation process.
++                When auto-negotiation process is invoked under traffic the
++                auto-negotiation process between the internal SGMII PHY and the
++                external PHY does not always complete successfully. Calling this
++                function will restart the auto-negotiation process that will end
++                successfully. It is recommended to call this function after issuing
++                auto-negotiation restart command to the Eth Phy.
++                This routine is relevant only for dTSEC.
++
++ @Param[in]     h_FmMac     - A handle to a FM Module.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_MAC_RestartAutoneg(t_Handle h_FmMac);
++
++/**************************************************************************//**
++ @Function      FM_MAC_GetId
++
++ @Description   Return the MAC ID
++
++ @Param[in]     h_FmMac     -   A handle to a FM Module.
++ @Param[out]    p_MacId     -   MAC ID of device
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only after FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_GetId(t_Handle h_FmMac, uint32_t *p_MacId);
++
++/**************************************************************************//**
++ @Function      FM_MAC_GetVesrion
++
++ @Description   Return Mac HW chip version
++
++ @Param[in]     h_FmMac      -   A handle to a FM Module.
++ @Param[out]    p_MacVresion -   Mac version as defined by the chip
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only after FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_GetVesrion(t_Handle h_FmMac, uint32_t *p_MacVresion);
++
++/**************************************************************************//**
++ @Function      FM_MAC_MII_WritePhyReg
++
++ @Description   Write data into Phy Register
++
++ @Param[in]     h_FmMac     -   A handle to a FM Module.
++ @Param[in]     phyAddr     -   Phy Address on the MII bus
++ @Param[in]     reg         -   Register Number.
++ @Param[in]     data        -   Data to write.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only after FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_MII_WritePhyReg(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data);
++
++/**************************************************************************//**
++ @Function      FM_MAC_MII_ReadPhyReg
++
++ @Description   Read data from Phy Register
++
++ @Param[in]     h_FmMac     -   A handle to a FM Module.
++ @Param[in]     phyAddr     -   Phy Address on the MII bus
++ @Param[in]     reg         -   Register Number.
++ @Param[out]    p_Data      -   Data from PHY.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only after FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_MII_ReadPhyReg(t_Handle h_FmMac,  uint8_t phyAddr, uint8_t reg, uint16_t *p_Data);
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++/**************************************************************************//**
++ @Function      FM_MAC_DumpRegs
++
++ @Description   Dump internal registers
++
++ @Param[in]     h_FmMac     -   A handle to a FM Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only after FM_MAC_Init().
++*//***************************************************************************/
++t_Error FM_MAC_DumpRegs(t_Handle h_FmMac);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++/** @} */ /* end of FM_mac_runtime_control_grp group */
++/** @} */ /* end of FM_mac_grp group */
++/** @} */ /* end of FM_grp group */
++
++
++#endif /* __FM_MAC_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_macsec_ext.h
+@@ -0,0 +1,1271 @@
++/*
++ * Copyright 2008-2015 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**************************************************************************//**
++ @File          fm_macsec_ext.h
++
++ @Description   FM MACSEC ...
++*//***************************************************************************/
++#ifndef __FM_MACSEC_EXT_H
++#define __FM_MACSEC_EXT_H
++
++#include "std_ext.h"
++
++
++/**************************************************************************//**
++ @Group         FM_grp Frame Manager API
++
++ @Description   FM API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         FM_MACSEC_grp FM MACSEC
++
++ @Description   FM MACSEC API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   MACSEC Exceptions
++*//***************************************************************************/
++typedef enum e_FmMacsecExceptions {
++    e_FM_MACSEC_EX_SINGLE_BIT_ECC,          /**< Single bit ECC error */
++    e_FM_MACSEC_EX_MULTI_BIT_ECC            /**< Multi bit ECC error */
++} e_FmMacsecExceptions;
++
++
++/**************************************************************************//**
++ @Group         FM_MACSEC_init_grp FM-MACSEC Initialization Unit
++
++ @Description   FM MACSEC Initialization Unit
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      t_FmMacsecExceptionsCallback
++
++ @Description   Exceptions user callback routine, will be called upon an
++                exception passing the exception identification.
++
++ @Param[in]     h_App       A handle to an application layer object; This handle
++                            will be passed by the driver upon calling this callback.
++ @Param[in]     exception   The exception.
++*//***************************************************************************/
++typedef void (t_FmMacsecExceptionsCallback) ( t_Handle                  h_App,
++                                              e_FmMacsecExceptions      exception);
++
++
++/**************************************************************************//**
++ @Description   FM MACSEC config input
++*//***************************************************************************/
++typedef struct t_FmMacsecParams {
++    t_Handle                                h_Fm;               /**< A handle to the FM object related to */
++    bool                                    guestMode;          /**< Partition-id */
++    union {
++        struct {
++            uint8_t                         fmMacId;            /**< FM MAC id */
++        } guestParams;
++
++        struct {
++            uintptr_t                       baseAddr;           /**< Base of memory mapped FM MACSEC registers */
++            t_Handle                        h_FmMac;            /**< A handle to the FM MAC object  related to */
++            t_FmMacsecExceptionsCallback    *f_Exception;       /**< Exception Callback Routine         */
++            t_Handle                        h_App;              /**< A handle to an application layer object; This handle will
++                                                                     be passed by the driver upon calling the above callbacks */
++        } nonGuestParams;
++    };
++} t_FmMacsecParams;
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_Config
++
++ @Description   Creates descriptor for the FM MACSEC module;
++
++                The routine returns a handle (descriptor) to the FM MACSEC object;
++                This descriptor must be passed as first parameter to all other
++                FM MACSEC function calls;
++
++                No actual initialization or configuration of FM MACSEC hardware is
++                done by this routine.
++
++ @Param[in]     p_FmMacsecParam     Pointer to data structure of parameters.
++
++ @Retval        Handle to FM MACSEC object, or NULL for Failure.
++*//***************************************************************************/
++t_Handle FM_MACSEC_Config(t_FmMacsecParams *p_FmMacsecParam);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_Init
++
++ @Description   Initializes the FM MACSEC module.
++
++ @Param[in]     h_FmMacsec      FM MACSEC module descriptor.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_MACSEC_Init(t_Handle h_FmMacsec);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_Free
++
++ @Description   Frees all resources that were assigned to FM MACSEC module;
++
++                Calling this routine invalidates the descriptor.
++
++ @Param[in]     h_FmMacsec      FM MACSEC module descriptor.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_MACSEC_Free(t_Handle h_FmMacsec);
++
++
++/**************************************************************************//**
++ @Group         FM_MACSEC_advanced_init_grp    FM-MACSEC Advanced Configuration Unit
++
++ @Description   Configuration functions used to change default values.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   enum for unknown sci frame treatment
++*//***************************************************************************/
++typedef enum e_FmMacsecUnknownSciFrameTreatment {
++    e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_BOTH = 0,                                               /**< Controlled port - Strict mode */
++    e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_UNCONTROLLED_DELIVER_OR_DISCARD_CONTROLLED,             /**< If C bit clear deliver on controlled port, else discard
++                                                                                                                 Controlled port - Check or Disable mode */
++    e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED,                        /**< Controlled port - Strict mode */
++    e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DELIVER_OR_DISCARD_UNCONTROLLED_DELIVER_OR_DISCARD_CONTROLLED   /**< If C bit set deliver on uncontrolled port and discard on controlled port,
++                                                                                                                 else discard on uncontrolled port and deliver on controlled port
++                                                                                                                 Controlled port - Check or Disable mode */
++} e_FmMacsecUnknownSciFrameTreatment;
++
++/**************************************************************************//**
++ @Description   enum for untag frame treatment
++*//***************************************************************************/
++typedef enum e_FmMacsecUntagFrameTreatment {
++    e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED = 0,                    /**< Controlled port - Strict mode */
++    e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DISCARD_BOTH,                                                   /**< Controlled port - Strict mode */
++    e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DISCARD_UNCONTROLLED_DELIVER_CONTROLLED_UNMODIFIED              /**< Controlled port - Strict mode */
++} e_FmMacsecUntagFrameTreatment;
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_ConfigUnknownSciFrameTreatment
++
++ @Description   Change the treatment for received frames with unknown sci from its default
++                configuration [DEFAULT_unknownSciFrameTreatment].
++
++ @Param[in]     h_FmMacsec      FM MACSEC module descriptor.
++ @Param[in]     treatMode       The selected mode.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_ConfigUnknownSciFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUnknownSciFrameTreatment treatMode);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_ConfigInvalidTagsFrameTreatment
++
++ @Description   Change the treatment for received frames with invalid tags or
++                a zero value PN or an invalid ICV from its default configuration
++                [DEFAULT_invalidTagsFrameTreatment].
++
++ @Param[in]     h_FmMacsec              FM MACSEC module descriptor.
++ @Param[in]     deliverUncontrolled     If True deliver on the uncontrolled port, else discard;
++                                        In both cases discard on the controlled port;
++                                        this provide Strict, Check or Disable mode.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_ConfigInvalidTagsFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment
++
++ @Description   Change the treatment for received frames with the Encryption bit
++                set and the Changed Text bit clear from its default configuration
++                [DEFAULT_encryptWithNoChangedTextFrameTreatment].
++
++ @Param[in]     h_FmMacsec              FM MACSEC module descriptor.
++ @Param[in]     discardUncontrolled     If True discard on the uncontrolled port, else deliver;
++                                        In both cases discard on the controlled port;
++                                        this provide Strict, Check or Disable mode.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment(t_Handle h_FmMacsec, bool discardUncontrolled);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_ConfigChangedTextWithNoEncryptFrameTreatment
++
++ @Description   Change the treatment for received frames with the Encryption bit
++                clear and the Changed Text bit set from its default configuration
++                [DEFAULT_changedTextWithNoEncryptFrameTreatment].
++
++ @Param[in]     h_FmMacsec              FM MACSEC module descriptor.
++ @Param[in]     deliverUncontrolled     If True deliver on the uncontrolled port, else discard;
++                                        In both cases discard on the controlled port;
++                                        this provide Strict, Check or Disable mode.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_ConfigChangedTextWithNoEncryptFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_ConfigUntagFrameTreatment
++
++ @Description   Change the treatment for received frames without the MAC security tag (SecTAG)
++                from its default configuration [DEFAULT_untagFrameTreatment].
++
++ @Param[in]     h_FmMacsec     FM MACSEC module descriptor.
++ @Param[in]     treatMode      The selected mode.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_ConfigUntagFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUntagFrameTreatment treatMode);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_ConfigOnlyScbIsSetFrameTreatment
++
++ @Description   Change the treatment for received frames with only SCB bit set
++                from its default configuration [DEFAULT_onlyScbIsSetFrameTreatment].
++
++ @Param[in]     h_FmMacsec              FM MACSEC module descriptor.
++ @Param[in]     deliverUncontrolled     If True deliver on the uncontrolled port, else discard;
++                                        In both cases discard on the controlled port;
++                                        this provide Strict, Check or Disable mode.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_ConfigOnlyScbIsSetFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_ConfigPnExhaustionThreshold
++
++ @Description   It's provide the ability to configure a PN exhaustion threshold;
++                When the NextPn crosses this value an interrupt event
++                is asserted to warn that the active SA should re-key.
++
++ @Param[in]     h_FmMacsec     FM MACSEC module descriptor.
++ @Param[in]     pnExhThr       If the threshold is reached, an interrupt event
++                               is asserted to re-key.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_ConfigPnExhaustionThreshold(t_Handle h_FmMacsec, uint32_t pnExhThr);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_ConfigKeysUnreadable
++
++ @Description   Turn on privacy mode; All the keys and their hash values can't be read any more;
++                Can not be cleared unless hard reset.
++
++ @Param[in]     h_FmMacsec         FM MACSEC module descriptor.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_ConfigKeysUnreadable(t_Handle h_FmMacsec);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_ConfigSectagWithoutSCI
++
++ @Description   Promise that all generated Sectag will be without SCI included.
++
++ @Param[in]     h_FmMacsec         FM MACSEC module descriptor.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_ConfigSectagWithoutSCI(t_Handle h_FmMacsec);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_ConfigException
++
++ @Description   Calling this routine changes the internal driver data base
++                from its default selection of exceptions enablement;
++                By default all exceptions are enabled.
++
++ @Param[in]     h_FmMacsec      FM MACSEC module descriptor.
++ @Param[in]     exception       The exception to be selected.
++ @Param[in]     enable          TRUE to enable interrupt, FALSE to mask it.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_ConfigException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable);
++
++/** @} */ /* end of FM_MACSEC_advanced_init_grp group */
++/** @} */ /* end of FM_MACSEC_init_grp group */
++
++
++/**************************************************************************//**
++ @Group         FM_MACSEC_runtime_control_grp FM-MACSEC Runtime Control Data Unit
++
++ @Description   FM MACSEC runtime control data unit API functions, definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_GetRevision
++
++ @Description   Return MACSEC HW chip revision
++
++ @Param[in]     h_FmMacsec         FM MACSEC module descriptor.
++ @Param[out]    p_MacsecRevision   MACSEC revision as defined by the chip.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only after FM_MACSEC_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_GetRevision(t_Handle h_FmMacsec, uint32_t *p_MacsecRevision);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_Enable
++
++ @Description   This routine should be called after MACSEC is initialized for enabling all
++                MACSEC engines according to their existing configuration.
++
++ @Param[in]     h_FmMacsec         FM MACSEC module descriptor.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_Init() and when MACSEC is disabled.
++*//***************************************************************************/
++t_Error FM_MACSEC_Enable(t_Handle h_FmMacsec);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_Disable
++
++ @Description   This routine may be called when MACSEC is enabled in order to
++                disable all MACSEC engines; The MACSEC is working in bypass mode.
++
++ @Param[in]     h_FmMacsec         FM MACSEC module descriptor.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_Init() and when MACSEC is enabled.
++*//***************************************************************************/
++t_Error FM_MACSEC_Disable(t_Handle h_FmMacsec);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SetException
++
++ @Description   Calling this routine enables/disables the specified exception.
++
++ @Param[in]     h_FmMacsec      FM MACSEC module descriptor.
++ @Param[in]     exception       The exception to be selected.
++ @Param[in]     enable          TRUE to enable interrupt, FALSE to mask it.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SetException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable);
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++/**************************************************************************//**
++ @Function      FM_MACSEC_DumpRegs
++
++ @Description   Dump internal registers.
++
++ @Param[in]     h_FmMacsec  - FM MACSEC module descriptor.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only after FM_MACSEC_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_DumpRegs(t_Handle h_FmMacsec);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++#ifdef VERIFICATION_SUPPORT
++/********************* VERIFICATION ONLY ********************************/
++/**************************************************************************//**
++ @Function      FM_MACSEC_BackdoorSet
++
++ @Description   Set register of the MACSEC memory map
++
++ @Param[in]     h_FmMacsec          FM MACSEC module descriptor.
++ @Param[out]    offset              Register offset.
++ @Param[out]    value               Value to write.
++
++
++ @Return        None
++
++ @Cautions      Allowed only following FM_MACSEC_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_BackdoorSet(t_Handle h_FmMacsec, uint32_t offset, uint32_t value);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_BackdoorGet
++
++ @Description   Read from register of the MACSEC memory map.
++
++ @Param[in]     h_FmMacsec          FM MACSEC module descriptor.
++ @Param[out]    offset              Register offset.
++
++ @Return        Value read
++
++ @Cautions      Allowed only following FM_MACSEC_Init().
++*//***************************************************************************/
++uint32_t FM_MACSEC_BackdoorGet(t_Handle h_FmMacsec, uint32_t offset);
++#endif /* VERIFICATION_SUPPORT */
++
++/** @} */ /* end of FM_MACSEC_runtime_control_grp group */
++
++
++/**************************************************************************//**
++ @Group         FM_MACSEC_SECY_grp FM-MACSEC SecY
++
++ @Description   FM-MACSEC SecY API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++typedef uint8_t     macsecSAKey_t[32];
++typedef uint64_t    macsecSCI_t;
++typedef uint8_t     macsecAN_t;
++
++/**************************************************************************//**
++@Description   MACSEC SECY Cipher Suite
++*//***************************************************************************/
++typedef enum e_FmMacsecSecYCipherSuite {
++    e_FM_MACSEC_SECY_GCM_AES_128 = 0,       /**< GCM-AES-128 */
++#if (DPAA_VERSION >= 11)
++    e_FM_MACSEC_SECY_GCM_AES_256            /**< GCM-AES-256 */
++#endif /* (DPAA_VERSION >= 11) */
++} e_FmMacsecSecYCipherSuite;
++
++/**************************************************************************//**
++ @Description   MACSEC SECY Exceptions
++*//***************************************************************************/
++typedef enum e_FmMacsecSecYExceptions {
++    e_FM_MACSEC_SECY_EX_FRAME_DISCARDED     /**< Frame  Discarded */
++} e_FmMacsecSecYExceptions;
++
++/**************************************************************************//**
++ @Description   MACSEC SECY Events
++*//***************************************************************************/
++typedef enum e_FmMacsecSecYEvents {
++    e_FM_MACSEC_SECY_EV_NEXT_PN             /**< Next Packet Number exhaustion threshold reached */
++} e_FmMacsecSecYEvents;
++
++/**************************************************************************//**
++ @Collection   MACSEC SECY Frame Discarded Descriptor error
++*//***************************************************************************/
++typedef uint8_t    macsecTxScFrameDiscardedErrSelect_t; /**< typedef for defining Frame Discarded Descriptor errors */
++
++#define FM_MACSEC_SECY_TX_SC_FRM_DISCAR_ERR_NEXT_PN_ZERO              0x8000  /**< NextPn == 0 */
++#define FM_MACSEC_SECY_TX_SC_FRM_DISCAR_ERR_SC_DISBALE                0x4000  /**< SC is disable */
++/* @} */
++
++/**************************************************************************//**
++ @Function      t_FmMacsecSecYExceptionsCallback
++
++ @Description   Exceptions user callback routine, will be called upon an
++                exception passing the exception identification.
++
++ @Param[in]     h_App       A handle to an application layer object; This handle
++                            will be passed by the driver upon calling this callback.
++ @Param[in]     exception   The exception.
++*//***************************************************************************/
++typedef void (t_FmMacsecSecYExceptionsCallback) ( t_Handle                  h_App,
++                                                  e_FmMacsecSecYExceptions  exception);
++
++/**************************************************************************//**
++ @Function      t_FmMacsecSecYEventsCallback
++
++ @Description   Events user callback routine, will be called upon an
++                event passing the event identification.
++
++ @Param[in]     h_App       A handle to an application layer object; This handle
++                            will be passed by the driver upon calling this callback.
++ @Param[in]     event       The event.
++*//***************************************************************************/
++typedef void (t_FmMacsecSecYEventsCallback) ( t_Handle                  h_App,
++                                              e_FmMacsecSecYEvents      event);
++
++/**************************************************************************//**
++ @Description   RFC2863 MIB
++*//***************************************************************************/
++typedef struct t_MIBStatistics {
++    uint64_t  ifInOctets;              /**< Total number of byte received */
++    uint64_t  ifInPkts;                /**< Total number of packets received */
++    uint64_t  ifInMcastPkts;           /**< Total number of multicast frame received */
++    uint64_t  ifInBcastPkts;           /**< Total number of broadcast frame received */
++    uint64_t  ifInDiscards;            /**< Frames received, but discarded due to problems within the MAC RX :
++                                               - InPktsNoTag,
++                                               - InPktsLate,
++                                               - InPktsOverrun */
++    uint64_t  ifInErrors;              /**< Number of frames received with error:
++                                               - InPktsBadTag,
++                                               - InPktsNoSCI,
++                                               - InPktsNotUsingSA
++                                               - InPktsNotValid */
++    uint64_t  ifOutOctets;             /**< Total number of byte sent */
++    uint64_t  ifOutPkts;               /**< Total number of packets sent */
++    uint64_t  ifOutMcastPkts;          /**< Total number of multicast frame sent */
++    uint64_t  ifOutBcastPkts;          /**< Total number of multicast frame sent */
++    uint64_t  ifOutDiscards;           /**< Frames received, but discarded due to problems within the MAC TX N/A! */
++    uint64_t  ifOutErrors;             /**< Number of frames transmitted with error:
++                                               - FIFO Overflow Error
++                                               - FIFO Underflow Error
++                                               - Other */
++} t_MIBStatistics;
++
++/**************************************************************************//**
++ @Description   MACSEC SecY Rx SA Statistics
++*//***************************************************************************/
++typedef struct t_FmMacsecSecYRxSaStatistics {
++    uint32_t            inPktsOK;               /**< The number of frames with resolved SCI, have passed all
++                                                     frame validation frame validation with the validateFrame not set to disable */
++    uint32_t            inPktsInvalid;          /**< The number of frames with resolved SCI, that have failed frame
++                                                     validation with the validateFrame set to check */
++    uint32_t            inPktsNotValid;         /**< The number of frames with resolved SCI, discarded on the controlled port,
++                                                     that have failed frame validation with the validateFrame set to strict or the c bit is set */
++    uint32_t            inPktsNotUsingSA;       /**< The number of frames received with resolved SCI and discarded on disabled or
++                                                     not provisioned SA with validateFrame in the strict mode or the C bit is set */
++    uint32_t            inPktsUnusedSA;         /**< The number of frames received with resolved SCI on disabled or not provisioned SA
++                                                     with validateFrame not in the strict mode and the C bit is cleared */
++} t_FmMacsecSecYRxSaStatistics;
++
++/**************************************************************************//**
++ @Description   MACSEC SecY Tx SA Statistics
++*//***************************************************************************/
++typedef struct t_FmMacsecSecYTxSaStatistics {
++    uint64_t            outPktsProtected;       /**< The number of frames, that the user of the controlled port requested to
++                                                     be transmitted, which were integrity protected */
++    uint64_t            outPktsEncrypted;       /**< The number of frames, that the user of the controlled port requested to
++                                                     be transmitted, which were confidentiality protected */
++} t_FmMacsecSecYTxSaStatistics;
++
++/**************************************************************************//**
++ @Description   MACSEC SecY Rx SC Statistics
++*//***************************************************************************/
++typedef struct t_FmMacsecSecYRxScStatistics {
++    uint64_t            inPktsUnchecked;        /**< The number of frames with resolved SCI, delivered to the user of a controlled port,
++                                                     that are not validated with the validateFrame set to disable */
++    uint64_t            inPktsDelayed;          /**< The number of frames with resolved SCI, delivered to the user of a controlled port,
++                                                     that have their PN smaller than the lowest_PN with the validateFrame set to
++                                                     disable or replayProtect disabled */
++    uint64_t            inPktsLate;             /**< The number of frames with resolved SCI, discarded on the controlled port,
++                                                     that have their PN smaller than the lowest_PN with the validateFrame set to
++                                                     Check or Strict and replayProtect enabled */
++    uint64_t            inPktsOK;               /**< The number of frames with resolved SCI, have passed all
++                                                     frame validation frame validation with the validateFrame not set to disable */
++    uint64_t            inPktsInvalid;          /**< The number of frames with resolved SCI, that have failed frame
++                                                     validation with the validateFrame set to check */
++    uint64_t            inPktsNotValid;         /**< The number of frames with resolved SCI, discarded on the controlled port,
++                                                     that have failed frame validation with the validateFrame set to strict or the c bit is set */
++    uint64_t            inPktsNotUsingSA;       /**< The number of frames received with resolved SCI and discarded on disabled or
++                                                     not provisioned SA with validateFrame in the strict mode or the C bit is set */
++    uint64_t            inPktsUnusedSA;         /**< The number of frames received with resolved SCI on disabled or not provisioned SA
++                                                     with validateFrame not in the strict mode and the C bit is cleared */
++} t_FmMacsecSecYRxScStatistics;
++
++/**************************************************************************//**
++ @Description   MACSEC SecY Tx SC Statistics
++*//***************************************************************************/
++typedef struct t_FmMacsecSecYTxScStatistics {
++    uint64_t            outPktsProtected;       /**< The number of frames, that the user of the controlled port requested to
++                                                     be transmitted, which were integrity protected */
++    uint64_t            outPktsEncrypted;       /**< The number of frames, that the user of the controlled port requested to
++                                                     be transmitted, which were confidentiality protected */
++} t_FmMacsecSecYTxScStatistics;
++
++/**************************************************************************//**
++ @Description   MACSEC SecY Statistics
++*//***************************************************************************/
++typedef struct t_FmMacsecSecYStatistics {
++    t_MIBStatistics     mibCtrlStatistics;      /**< Controlled port MIB statistics */
++    t_MIBStatistics     mibNonCtrlStatistics;   /**< Uncontrolled port MIB statistics */
++/* Frame verification statistics */
++    uint64_t            inPktsUntagged;         /**< The number of received packets without the MAC security tag
++                                                     (SecTAG) with validateFrames which is not in the strict mode */
++    uint64_t            inPktsNoTag;            /**< The number of received packets discarded without the
++                                                     MAC security tag (SecTAG) with validateFrames which is in the strict mode */
++    uint64_t            inPktsBadTag;           /**< The number of received packets discarded with an invalid
++                                                     SecTAG or a zero value PN or an invalid ICV */
++    uint64_t            inPktsUnknownSCI;       /**< The number of received packets with unknown SCI with the
++                                                     condition : validateFrames is not in the strict mode and the
++                                                     C bit in the SecTAG is not set */
++    uint64_t            inPktsNoSCI;            /**< The number of received packets discarded with unknown SCI
++                                                     information with the condition : validateFrames is in the strict mode
++                                                     or the C bit in the SecTAG is set */
++    uint64_t            inPktsOverrun;          /**< The number of packets discarded because the number of
++                                                     received packets exceeded the cryptographic performance capabilities */
++/* Frame validation statistics */
++    uint64_t            inOctetsValidated;      /**< The number of octets of plaintext recovered from received frames with
++                                                     resolved SCI that were integrity protected but not encrypted */
++    uint64_t            inOctetsDecrypted;      /**< The number of octets of plaintext recovered from received frames with
++                                                     resolved SCI that were integrity protected and encrypted */
++/* Frame generation statistics */
++    uint64_t            outPktsUntagged;        /**< The number of frames, that the user of the controlled port requested to
++                                                     be transmitted, with protectFrame false */
++    uint64_t            outPktsTooLong;         /**< The number of frames, that the user of the controlled port requested to
++                                                     be transmitted, discarded due to length being larger than Maximum Frame Length (MACSEC_MFL) */
++/* Frame protection statistics */
++    uint64_t            outOctetsProtected;     /**< The number of octets of User Data in transmitted frames that were
++                                                     integrity protected but not encrypted */
++    uint64_t            outOctetsEncrypted;     /**< The number of octets of User Data in transmitted frames that were
++                                                     both integrity protected and encrypted */
++} t_FmMacsecSecYStatistics;
++
++
++/**************************************************************************//**
++ @Description   MACSEC SecY SC Params
++*//***************************************************************************/
++typedef struct t_FmMacsecSecYSCParams {
++    macsecSCI_t                 sci;            /**< The secure channel identification of the SC */
++    e_FmMacsecSecYCipherSuite   cipherSuite;    /**< Cipher suite to be used for the SC */
++} t_FmMacsecSecYSCParams;
++
++/**************************************************************************//**
++ @Group         FM_MACSEC_SECY_init_grp FM-MACSEC SecY Initialization Unit
++
++ @Description   FM-MACSEC SecY Initialization Unit
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   enum for validate frames
++*//***************************************************************************/
++typedef enum e_FmMacsecValidFrameBehavior {
++    e_FM_MACSEC_VALID_FRAME_BEHAVIOR_DISABLE = 0,   /**< disable the validation function */
++    e_FM_MACSEC_VALID_FRAME_BEHAVIOR_CHECK,         /**< enable the validation function but only for checking
++                                                         without filtering out invalid frames */
++    e_FM_MACSEC_VALID_FRAME_BEHAVIOR_STRICT         /**< enable the validation function and also strictly filter
++                                                         out those invalid frames */
++} e_FmMacsecValidFrameBehavior;
++
++/**************************************************************************//**
++ @Description   enum for sci insertion
++*//***************************************************************************/
++typedef enum e_FmMacsecSciInsertionMode {
++    e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_SECTAG = 0, /**< explicit sci in the sectag */
++    e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_MAC_SA,     /**< mac sa is overwritten with the sci*/
++    e_FM_MACSEC_SCI_INSERTION_MODE_IMPLICT_PTP          /**< implicit point-to-point sci (pre-shared) */
++} e_FmMacsecSciInsertionMode;
++
++/**************************************************************************//**
++ @Description   FM MACSEC SecY config input
++*//***************************************************************************/
++typedef struct t_FmMacsecSecYParams {
++    t_Handle                                    h_FmMacsec;             /**< A handle to the FM MACSEC object */
++    t_FmMacsecSecYSCParams                      txScParams;             /**< Tx SC Params */
++    uint32_t                                    numReceiveChannels;     /**< Number of receive channels dedicated to this SecY */
++    t_FmMacsecSecYExceptionsCallback            *f_Exception;           /**< Callback routine to be called by the driver upon SecY exception */
++    t_FmMacsecSecYEventsCallback                *f_Event;               /**< Callback routine to be called by the driver upon SecY event */
++    t_Handle                                    h_App;                  /**< A handle to an application layer object; This handle will
++                                                                             be passed by the driver upon calling the above callbacks */
++} t_FmMacsecSecYParams;
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_Config
++
++ @Description   Creates descriptor for the FM MACSEC SECY module;
++
++                The routine returns a handle (descriptor) to the FM MACSEC SECY object;
++                This descriptor must be passed as first parameter to all other
++                FM MACSEC SECY function calls;
++                No actual initialization or configuration of FM MACSEC SecY hardware is
++                done by this routine.
++
++ @Param[in]     p_FmMacsecSecYParam     Pointer to data structure of parameters.
++
++ @Return        Handle to FM MACSEC SECY object, or NULL for Failure.
++*//***************************************************************************/
++t_Handle FM_MACSEC_SECY_Config(t_FmMacsecSecYParams *p_FmMacsecSecYParam);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_Init
++
++ @Description   Initializes the FM MACSEC SECY module.
++
++ @Param[in]     h_FmMacsecSecY  FM MACSEC SECY module descriptor.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_Init(t_Handle h_FmMacsecSecY);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_Free
++
++ @Description   Frees all resources that were assigned to FM MACSEC SECY module.
++
++                Calling this routine invalidates the descriptor.
++
++ @Param[in]     h_FmMacsecSecY  FM MACSEC SECY module descriptor.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_Free(t_Handle h_FmMacsecSecY);
++
++/**************************************************************************//**
++ @Group         FM_MACSEC_SECY_advanced_init_grp  FM-MACSEC SecY Advanced Configuration Unit
++
++ @Description   Configuration functions used to change default values.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_ConfigSciInsertionMode
++
++ @Description   Calling this routine changes the SCI-insertion-mode in the
++                internal driver data base from its default configuration
++                [DEFAULT_sciInsertionMode]
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     sciInsertionMode    Sci insertion mode
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init();
++
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_ConfigSciInsertionMode(t_Handle h_FmMacsecSecY, e_FmMacsecSciInsertionMode sciInsertionMode);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_ConfigProtectFrames
++
++ @Description   Calling this routine changes the protect-frame mode in the
++                internal driver data base from its default configuration
++                [DEFAULT_protectFrames]
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     protectFrames       If FALSE, frames are transmitted without modification
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init();
++
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_ConfigProtectFrames(t_Handle h_FmMacsecSecY, bool protectFrames);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_ConfigReplayWindow
++
++ @Description   Calling this routine changes the replay-window settings in the
++                internal driver data base from its default configuration
++                [DEFAULT_replayEnable], [DEFAULT_replayWindow]
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     replayProtect;      Replay protection function mode
++ @Param[in]     replayWindow;       The size of the replay window
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init();
++
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_ConfigReplayWindow(t_Handle h_FmMacsecSecY, bool replayProtect, uint32_t replayWindow);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_ConfigValidationMode
++
++ @Description   Calling this routine changes the frame-validation-behavior mode
++                in the internal driver data base from its default configuration
++                [DEFAULT_validateFrames]
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     validateFrames      Validation function mode
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init();
++
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_ConfigValidationMode(t_Handle h_FmMacsecSecY, e_FmMacsecValidFrameBehavior validateFrames);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_ConfigConfidentiality
++
++ @Description   Calling this routine changes the confidentiality settings in the
++                internal driver data base from its default configuration
++                [DEFAULT_confidentialityEnable], [DEFAULT_confidentialityOffset]
++
++ @Param[in]     h_FmMacsecSecY          FM MACSEC SECY module descriptor.
++ @Param[in]     confidentialityEnable   TRUE  - confidentiality protection and integrity protection
++                                        FALSE - no confidentiality protection, only integrity protection
++ @Param[in]     confidentialityOffset   The number of initial octets of each MSDU without confidentiality protection
++                                        common values are 0, 30, and 50
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init();
++
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_ConfigConfidentiality(t_Handle h_FmMacsecSecY, bool confidentialityEnable, uint16_t confidentialityOffset);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_ConfigPointToPoint
++
++ @Description   configure this SecY to work in point-to-point mode, means that
++                it will have only one rx sc;
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init();
++                Can be called only once in a system; only the first secY that will call this
++                routine will be able to operate in Point-To-Point mode.
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_ConfigPointToPoint(t_Handle h_FmMacsecSecY);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_ConfigException
++
++ @Description   Calling this routine changes the internal driver data base
++                from its default selection of exceptions enablement;
++                By default all exceptions are enabled.
++
++ @Param[in]     h_FmMacsecSecY  FM MACSEC SECY module descriptor.
++ @Param[in]     exception       The exception to be selected.
++ @Param[in]     enable          TRUE to enable interrupt, FALSE to mask it.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_ConfigException(t_Handle h_FmMacsecSecY, e_FmMacsecSecYExceptions exception, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_ConfigEvent
++
++ @Description   Calling this routine changes the internal driver data base
++                from its default selection of events enablement;
++                By default all events are enabled.
++
++ @Param[in]     h_FmMacsecSecY  FM MACSEC SECY module descriptor.
++ @Param[in]     event           The event to be selected.
++ @Param[in]     enable          TRUE to enable interrupt, FALSE to mask it.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_ConfigEvent(t_Handle h_FmMacsecSecY, e_FmMacsecSecYEvents event, bool enable);
++
++/** @} */ /* end of FM_MACSEC_SECY_advanced_init_grp group */
++/** @} */ /* end of FM_MACSEC_SECY_init_grp group */
++
++
++/**************************************************************************//**
++ @Group         FM_MACSEC_SECY_runtime_control_grp FM-MACSEC SecY Runtime Control Unit
++
++ @Description   FM MACSEC SECY Runtime control unit API functions, definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_CreateRxSc
++
++ @Description   Create a receive secure channel.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     scParams            secure channel params.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Handle FM_MACSEC_SECY_CreateRxSc(t_Handle h_FmMacsecSecY, t_FmMacsecSecYSCParams *p_ScParams);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_DeleteRxSc
++
++ @Description   Deleting an initialized secure channel.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     h_Sc                SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_CreateRxSc().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_DeleteRxSc(t_Handle h_FmMacsecSecY, t_Handle h_Sc);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_CreateRxSa
++
++ @Description   Create a receive secure association for the secure channel;
++                the SA cannot be used to receive frames until FM_MACSEC_SECY_RxSaEnableReceive is called.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     h_Sc                SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
++ @Param[in]     an                  association number represent the SA.
++ @Param[in]     lowestPn            the lowest acceptable PN value for a received frame.
++ @Param[in]     key                 the desired key for this SA.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_CreateRxSc().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_CreateRxSa(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t lowestPn, macsecSAKey_t key);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_DeleteRxSa
++
++ @Description   Deleting an initialized secure association.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     h_Sc                SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
++ @Param[in]     an                  association number represent the SA.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_DeleteRxSa(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_RxSaEnableReceive
++
++ @Description   Enabling the SA to receive frames.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     h_Sc                SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
++ @Param[in]     an                  association number represent the SA.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_CreateRxSa().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_RxSaEnableReceive(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_RxSaDisableReceive
++
++ @Description   Disabling the SA from receive frames.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     h_Sc                SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
++ @Param[in]     an                  association number represent the SA.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_CreateRxSa().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_RxSaDisableReceive(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_RxSaUpdateNextPn
++
++ @Description   Update the next packet number expected on RX;
++                The value of nextPN shall be set to the greater of its existing value and the
++                supplied of updtNextPN (802.1AE-2006 10.7.15).
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     h_Sc                SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
++ @Param[in]     an                  association number represent the SA.
++ @Param[in]     updtNextPN          the next PN value for a received frame.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_CreateRxSa().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_RxSaUpdateNextPn(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t updtNextPN);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_RxSaUpdateLowestPn
++
++ @Description   Update the lowest packet number expected on RX;
++                The value of lowestPN shall be set to the greater of its existing value and the
++                supplied of updtLowestPN (802.1AE-2006 10.7.15).
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     h_Sc                SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
++ @Param[in]     an                  association number represent the SA.
++ @Param[in]     updtLowestPN        the lowest PN acceptable value for a received frame.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_CreateRxSa().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_RxSaUpdateLowestPn(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t updtLowestPN);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_RxSaModifyKey
++
++ @Description   Modify the current key of the SA with a new one.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     h_Sc                SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
++ @Param[in]     an                  association number represent the SA.
++ @Param[in]     key                 new key to replace the current key.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_CreateRxSa().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_RxSaModifyKey(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, macsecSAKey_t key);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_CreateTxSa
++
++ @Description   Create a transmit secure association for the secure channel;
++                the SA cannot be used to transmit frames until FM_MACSEC_SECY_TxSaSetActivate is called;
++                Only one SA can be active at a time.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     an                  association number represent the SA.
++ @Param[in]     key                 the desired key for this SA.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_CreateTxSa(t_Handle h_FmMacsecSecY, macsecAN_t an, macsecSAKey_t key);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_DeleteTxSa
++
++ @Description   Deleting an initialized secure association.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     an                  association number represent the SA.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_DeleteTxSa(t_Handle h_FmMacsecSecY, macsecAN_t an);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_TxSaModifyKey
++
++ @Description   Modify the key of the inactive SA with a new one.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     nextActiveAn        association number represent the next SA to be activated.
++ @Param[in]     key                 new key to replace the current key.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_TxSaModifyKey(t_Handle h_FmMacsecSecY, macsecAN_t nextActiveAn, macsecSAKey_t key);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_TxSaSetActive
++
++ @Description   Set this SA to the active SA to be used on TX for SC;
++                only one SA can be active at a time.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     an                  association number represent the SA.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_TxSaSetActive(t_Handle h_FmMacsecSecY, macsecAN_t an);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_TxSaGetActive
++
++ @Description   Get the active SA that being used for TX.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[out]    p_An                the active an.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_TxSaGetActive(t_Handle h_FmMacsecSecY, macsecAN_t *p_An);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_GetStatistics
++
++ @Description   get all statistics counters.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     p_Statistics        Structure with statistics.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_GetStatistics(t_Handle h_FmMacsecSecY, t_FmMacsecSecYStatistics *p_Statistics);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_RxScGetStatistics
++
++ @Description   get all statistics counters.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     h_Sc                Rx Sc handle.
++ @Param[in]     p_Statistics        Structure with statistics.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_RxScGetStatistics(t_Handle h_FmMacsecSecY, t_Handle h_Sc, t_FmMacsecSecYRxScStatistics *p_Statistics);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_RxSaGetStatistics
++
++ @Description   get all statistics counters
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     h_Sc                Rx Sc handle.
++ @Param[in]     an                  association number represent the SA.
++ @Param[in]     p_Statistics        Structure with statistics.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_RxSaGetStatistics(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, t_FmMacsecSecYRxSaStatistics *p_Statistics);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_TxScGetStatistics
++
++ @Description   get all statistics counters.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     p_Statistics        Structure with statistics.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_TxScGetStatistics(t_Handle h_FmMacsecSecY, t_FmMacsecSecYTxScStatistics *p_Statistics);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_TxSaGetStatistics
++
++ @Description   get all statistics counters.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     an                  association number represent the SA.
++ @Param[in]     p_Statistics        Structure with statistics.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_TxSaGetStatistics(t_Handle h_FmMacsecSecY, macsecAN_t an, t_FmMacsecSecYTxSaStatistics *p_Statistics);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_SetException
++
++ @Description   Calling this routine enables/disables the specified exception.
++
++ @Param[in]     h_FmMacsecSecY  FM MACSEC SECY module descriptor.
++ @Param[in]     exception       The exception to be selected.
++ @Param[in]     enable          TRUE to enable interrupt, FALSE to mask it.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_SetException(t_Handle h_FmMacsecSecY, e_FmMacsecExceptions exception, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_SetEvent
++
++ @Description   Calling this routine enables/disables the specified event.
++
++ @Param[in]     h_FmMacsecSecY  FM MACSEC SECY module descriptor.
++ @Param[in]     event           The event to be selected.
++ @Param[in]     enable          TRUE to enable interrupt, FALSE to mask it.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_SetEvent(t_Handle h_FmMacsecSecY, e_FmMacsecSecYEvents event, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_GetRxScPhysId
++
++ @Description   return the physical id of the Secure Channel.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[in]     h_Sc                SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
++ @Param[out]    p_ScPhysId          the SC physical id.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_CreateRxSc().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_GetRxScPhysId(t_Handle h_FmMacsecSecY, t_Handle h_Sc, uint32_t *p_ScPhysId);
++
++/**************************************************************************//**
++ @Function      FM_MACSEC_SECY_GetTxScPhysId
++
++ @Description   return the physical id of the Secure Channel.
++
++ @Param[in]     h_FmMacsecSecY      FM MACSEC SECY module descriptor.
++ @Param[out]    p_ScPhysId          the SC physical id.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MACSEC_SECY_Init().
++*//***************************************************************************/
++t_Error FM_MACSEC_SECY_GetTxScPhysId(t_Handle h_FmMacsecSecY, uint32_t *p_ScPhysId);
++
++/** @} */ /* end of FM_MACSEC_SECY_runtime_control_grp group */
++/** @} */ /* end of FM_MACSEC_SECY_grp group */
++/** @} */ /* end of FM_MACSEC_grp group */
++/** @} */ /* end of FM_grp group */
++
++
++#endif /* __FM_MACSEC_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_muram_ext.h
+@@ -0,0 +1,170 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          fm_muram_ext.h
++
++ @Description   FM MURAM Application Programming Interface.
++*//***************************************************************************/
++#ifndef __FM_MURAM_EXT
++#define __FM_MURAM_EXT
++
++#include "error_ext.h"
++#include "std_ext.h"
++
++
++/**************************************************************************//**
++
++ @Group         FM_grp Frame Manager API
++
++ @Description   FM API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         FM_muram_grp FM MURAM
++
++ @Description   FM MURAM API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         FM_muram_init_grp FM MURAM Initialization Unit
++
++ @Description   FM MURAM initialization API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      FM_MURAM_ConfigAndInit
++
++ @Description   Creates partition in the MURAM.
++
++                The routine returns a handle (descriptor) to the MURAM partition.
++                This descriptor must be passed as first parameter to all other
++                FM-MURAM function calls.
++
++                No actual initialization or configuration of FM_MURAM hardware is
++                done by this routine.
++
++ @Param[in]     baseAddress - Pointer to base of memory mapped FM-MURAM.
++ @Param[in]     size        - Size of the FM-MURAM partition.
++
++ @Return        Handle to FM-MURAM object, or NULL for Failure.
++*//***************************************************************************/
++t_Handle FM_MURAM_ConfigAndInit(uintptr_t baseAddress, uint32_t size);
++
++/**************************************************************************//**
++ @Function      FM_MURAM_Free
++
++ @Description   Frees all resources that were assigned to FM-MURAM module.
++
++                Calling this routine invalidates the descriptor.
++
++ @Param[in]     h_FmMuram - FM-MURAM module descriptor.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error  FM_MURAM_Free(t_Handle h_FmMuram);
++
++/** @} */ /* end of FM_muram_init_grp group */
++
++
++/**************************************************************************//**
++ @Group         FM_muram_ctrl_grp FM MURAM Control Unit
++
++ @Description   FM MURAM control API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      FM_MURAM_AllocMem
++
++ @Description   Allocate some memory from FM-MURAM partition.
++
++ @Param[in]     h_FmMuram - FM-MURAM module descriptor.
++ @Param[in]     size      - size of the memory to be allocated.
++ @Param[in]     align     - Alignment of the memory.
++
++ @Return        address of the allocated memory; NULL otherwise.
++*//***************************************************************************/
++void  * FM_MURAM_AllocMem(t_Handle h_FmMuram, uint32_t size, uint32_t align);
++
++/**************************************************************************//**
++ @Function      FM_MURAM_AllocMemForce
++
++ @Description   Allocate some specific memory from FM-MURAM partition (according
++                to base).
++
++ @Param[in]     h_FmMuram - FM-MURAM module descriptor.
++ @Param[in]     base      - the desired base-address to be allocated.
++ @Param[in]     size      - size of the memory to be allocated.
++
++ @Return        address of the allocated memory; NULL otherwise.
++*//***************************************************************************/
++void  * FM_MURAM_AllocMemForce(t_Handle h_FmMuram, uint64_t base, uint32_t size);
++
++/**************************************************************************//**
++ @Function      FM_MURAM_FreeMem
++
++ @Description   Free an allocated memory from FM-MURAM partition.
++
++ @Param[in]     h_FmMuram - FM-MURAM module descriptor.
++ @Param[in]     ptr       - A pointer to an allocated memory.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_MURAM_FreeMem(t_Handle h_FmMuram, void *ptr);
++
++/**************************************************************************//**
++ @Function      FM_MURAM_GetFreeMemSize
++
++ @Description   Returns the size (in bytes) of free MURAM memory.
++
++ @Param[in]     h_FmMuram - FM-MURAM module descriptor.
++
++ @Return        Free MURAM memory size in bytes.
++*//***************************************************************************/
++uint64_t FM_MURAM_GetFreeMemSize(t_Handle h_FmMuram);
++
++/** @} */ /* end of FM_muram_ctrl_grp group */
++/** @} */ /* end of FM_muram_grp group */
++/** @} */ /* end of FM_grp group */
++
++
++
++#endif /* __FM_MURAM_EXT */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_pcd_ext.h
+@@ -0,0 +1,3974 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          fm_pcd_ext.h
++
++ @Description   FM PCD API definitions
++*//***************************************************************************/
++#ifndef __FM_PCD_EXT
++#define __FM_PCD_EXT
++
++#include "std_ext.h"
++#include "net_ext.h"
++#include "list_ext.h"
++#include "fm_ext.h"
++#include "fsl_fman_kg.h"
++
++
++/**************************************************************************//**
++ @Group         FM_grp Frame Manager API
++
++ @Description   Frame Manager Application Programming Interface
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         FM_PCD_grp FM PCD
++
++ @Description   Frame Manager PCD (Parse-Classify-Distribute) API.
++
++                The FM PCD module is responsible for the initialization of all
++                global classifying FM modules. This includes the parser general and
++                common registers, the key generator global and common registers,
++                and the policer global and common registers.
++                In addition, the FM PCD SW module will initialize all required
++                key generator schemes, coarse classification flows, and policer
++                profiles. When FM module is configured to work with one of these
++                entities, it will register to it using the FM PORT API. The PCD
++                module will manage the PCD resources - i.e. resource management of
++                KeyGen schemes, etc.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Collection    General PCD defines
++*//***************************************************************************/
++#define FM_PCD_MAX_NUM_OF_PRIVATE_HDRS              2                   /**< Number of units/headers saved for user */
++
++#define FM_PCD_PRS_NUM_OF_HDRS                      16                  /**< Number of headers supported by HW parser */
++#define FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS         (32 - FM_PCD_MAX_NUM_OF_PRIVATE_HDRS)
++                                                                        /**< Number of distinction units is limited by
++                                                                             register size (32 bits) minus reserved bits
++                                                                             for private headers. */
++#define FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS      4                   /**< Maximum number of interchangeable headers
++                                                                             in a distinction unit */
++#define FM_PCD_KG_NUM_OF_GENERIC_REGS               FM_KG_NUM_OF_GENERIC_REGS /**< Total number of generic KeyGen registers */
++#define FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY       35                  /**< Max number allowed on any configuration;
++                                                                             For HW implementation reasons, in most
++                                                                             cases less than this will be allowed; The
++                                                                             driver will return an initialization error
++                                                                             if resource is unavailable. */
++#define FM_PCD_KG_NUM_OF_EXTRACT_MASKS              4                   /**< Total number of masks allowed on KeyGen extractions. */
++#define FM_PCD_KG_NUM_OF_DEFAULT_GROUPS             16                  /**< Number of default value logical groups */
++
++#define FM_PCD_PRS_NUM_OF_LABELS                    32                  /**< Maximum number of SW parser labels */
++#define FM_SW_PRS_MAX_IMAGE_SIZE                    (FM_PCD_SW_PRS_SIZE /*- FM_PCD_PRS_SW_OFFSET -FM_PCD_PRS_SW_TAIL_SIZE*/-FM_PCD_PRS_SW_PATCHES_SIZE)
++                                                                        /**< Maximum size of SW parser code */
++
++#define FM_PCD_MAX_MANIP_INSRT_TEMPLATE_SIZE        128                 /**< Maximum size of insertion template for
++                                                                             insert manipulation */
++
++#if (DPAA_VERSION >= 11)
++#define FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES        64                  /**< Maximum possible entries for frame replicator group */
++#endif /* (DPAA_VERSION >= 11) */
++/* @} */
++
++
++/**************************************************************************//**
++ @Group         FM_PCD_init_grp FM PCD Initialization Unit
++
++ @Description   Frame Manager PCD Initialization Unit API
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   PCD counters
++*//***************************************************************************/
++typedef enum e_FmPcdCounters {
++    e_FM_PCD_KG_COUNTERS_TOTAL,                                 /**< KeyGen counter */
++    e_FM_PCD_PLCR_COUNTERS_RED,                                 /**< Policer counter - counts the total number of RED packets that exit the Policer. */
++    e_FM_PCD_PLCR_COUNTERS_YELLOW,                              /**< Policer counter - counts the total number of YELLOW packets that exit the Policer. */
++    e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED,                    /**< Policer counter - counts the number of packets that changed color to RED by the Policer;
++                                                                     This is a subset of e_FM_PCD_PLCR_COUNTERS_RED packet count, indicating active color changes. */
++    e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW,                 /**< Policer counter - counts the number of packets that changed color to YELLOW by the Policer;
++                                                                     This is a subset of e_FM_PCD_PLCR_COUNTERS_YELLOW packet count, indicating active color changes. */
++    e_FM_PCD_PLCR_COUNTERS_TOTAL,                               /**< Policer counter - counts the total number of packets passed in the Policer. */
++    e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH,                     /**< Policer counter - counts the number of packets with length mismatch. */
++    e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH,                       /**< Parser counter - counts the number of times the parser block is dispatched. */
++    e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED,             /**< Parser counter - counts the number of times L2 parse result is returned (including errors). */
++    e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED,             /**< Parser counter - counts the number of times L3 parse result is returned (including errors). */
++    e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED,             /**< Parser counter - counts the number of times L4 parse result is returned (including errors). */
++    e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED,           /**< Parser counter - counts the number of times SHIM parse result is returned (including errors). */
++    e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR,    /**< Parser counter - counts the number of times L2 parse result is returned with errors. */
++    e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR,    /**< Parser counter - counts the number of times L3 parse result is returned with errors. */
++    e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR,    /**< Parser counter - counts the number of times L4 parse result is returned with errors. */
++    e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR,  /**< Parser counter - counts the number of times SHIM parse result is returned with errors. */
++    e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES,                      /**< Parser counter - counts the number of cycles spent executing soft parser instruction (including stall cycles). */
++    e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES,                /**< Parser counter - counts the number of cycles stalled waiting for parser internal memory reads while executing soft parser instruction. */
++    e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES,     /**< Parser counter - counts the number of cycles spent executing hard parser (including stall cycles). */
++    e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES,                    /**< MURAM counter - counts the number of cycles while performing FMan Memory read. */
++    e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES,              /**< MURAM counter - counts the number of cycles stalled while performing FMan Memory read. */
++    e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES,                   /**< MURAM counter - counts the number of cycles while performing FMan Memory write. */
++    e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES,             /**< MURAM counter - counts the number of cycles stalled while performing FMan Memory write. */
++    e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES              /**< FPM counter - counts the number of cycles stalled while performing a FPM Command. */
++} e_FmPcdCounters;
++
++/**************************************************************************//**
++ @Description   PCD interrupts
++*//***************************************************************************/
++typedef enum e_FmPcdExceptions {
++    e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC,                   /**< KeyGen double-bit ECC error is detected on internal memory read access. */
++    e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW,             /**< KeyGen scheme configuration error indicating a key size larger than 56 bytes. */
++    e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC,                 /**< Policer double-bit ECC error has been detected on PRAM read access. */
++    e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR,           /**< Policer access to a non-initialized profile has been detected. */
++    e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE,    /**< Policer RAM self-initialization complete */
++    e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE,     /**< Policer atomic action complete */
++    e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC,                  /**< Parser double-bit ECC error */
++    e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC                   /**< Parser single-bit ECC error */
++} e_FmPcdExceptions;
++
++
++/**************************************************************************//**
++ @Description   Exceptions user callback routine, will be called upon an
++                exception passing the exception identification.
++
++ @Param[in]     h_App      - User's application descriptor.
++ @Param[in]     exception  - The exception.
++  *//***************************************************************************/
++typedef void (t_FmPcdExceptionCallback) (t_Handle h_App, e_FmPcdExceptions exception);
++
++/**************************************************************************//**
++ @Description   Exceptions user callback routine, will be called upon an exception
++                passing the exception identification.
++
++ @Param[in]     h_App           - User's application descriptor.
++ @Param[in]     exception       - The exception.
++ @Param[in]     index           - id of the relevant source (may be scheme or profile id).
++ *//***************************************************************************/
++typedef void (t_FmPcdIdExceptionCallback) ( t_Handle           h_App,
++                                            e_FmPcdExceptions  exception,
++                                            uint16_t           index);
++
++/**************************************************************************//**
++ @Description   A callback for enqueuing frame onto a QM queue.
++
++ @Param[in]     h_QmArg         - Application's handle passed to QM module on enqueue.
++ @Param[in]     p_Fd            - Frame descriptor for the frame.
++
++ @Return        E_OK on success; Error code otherwise.
++ *//***************************************************************************/
++typedef t_Error (t_FmPcdQmEnqueueCallback) (t_Handle h_QmArg, void *p_Fd);
++
++/**************************************************************************//**
++ @Description   Host-Command parameters structure.
++
++                When using Host command for PCD functionalities, a dedicated port
++                must be used. If this routine is called for a PCD in a single partition
++                environment, or it is the Master partition in a Multi-partition
++                environment, The port will be initialized by the PCD driver
++                initialization routine.
++ *//***************************************************************************/
++typedef struct t_FmPcdHcParams {
++    uintptr_t                   portBaseAddr;       /**< Virtual Address of Host-Command Port memory mapped registers.*/
++    uint8_t                     portId;             /**< Port Id (0-6 relative to Host-Command/Offline-Parsing ports);
++                                                         NOTE: When configuring Host Command port for
++                                                         FMANv3 devices (DPAA_VERSION 11 and higher),
++                                                         portId=0 MUST be used. */
++    uint16_t                    liodnBase;          /**< LIODN base for this port, to be used together with LIODN offset
++                                                         (irrelevant for P4080 revision 1.0) */
++    uint32_t                    errFqid;            /**< Host-Command Port error queue Id. */
++    uint32_t                    confFqid;           /**< Host-Command Port confirmation queue Id. */
++    uint32_t                    qmChannel;          /**< QM channel dedicated to this Host-Command port;
++                                                         will be used by the FM for dequeue. */
++    t_FmPcdQmEnqueueCallback    *f_QmEnqueue;       /**< Callback routine for enqueuing a frame to the QM */
++    t_Handle                    h_QmArg;            /**< Application's handle passed to QM module on enqueue */
++} t_FmPcdHcParams;
++
++/**************************************************************************//**
++ @Description   The main structure for PCD initialization
++ *//***************************************************************************/
++typedef struct t_FmPcdParams {
++    bool                        prsSupport;             /**< TRUE if Parser will be used for any of the FM ports. */
++    bool                        ccSupport;              /**< TRUE if Coarse Classification will be used for any
++                                                             of the FM ports. */
++    bool                        kgSupport;              /**< TRUE if KeyGen will be used for any of the FM ports. */
++    bool                        plcrSupport;            /**< TRUE if Policer will be used for any of the FM ports. */
++    t_Handle                    h_Fm;                   /**< A handle to the FM module. */
++    uint8_t                     numOfSchemes;           /**< Number of schemes dedicated to this partition.
++                                                             this parameter is relevant if 'kgSupport'=TRUE. */
++    bool                        useHostCommand;         /**< Optional for single partition, Mandatory for Multi partition */
++    t_FmPcdHcParams             hc;                     /**< Host Command parameters, relevant only if 'useHostCommand'=TRUE;
++                                                             Relevant when FM not runs in "guest-mode". */
++
++    t_FmPcdExceptionCallback    *f_Exception;           /**< Callback routine for general PCD exceptions;
++                                                             Relevant when FM not runs in "guest-mode". */
++    t_FmPcdIdExceptionCallback  *f_ExceptionId;         /**< Callback routine for specific KeyGen scheme or
++                                                             Policer profile exceptions;
++                                                             Relevant when FM not runs in "guest-mode". */
++    t_Handle                    h_App;                  /**< A handle to an application layer object; This handle will
++                                                             be passed by the driver upon calling the above callbacks;
++                                                             Relevant when FM not runs in "guest-mode". */
++    uint8_t                     partPlcrProfilesBase;   /**< The first policer-profile-id dedicated to this partition.
++                                                             this parameter is relevant if 'plcrSupport'=TRUE.
++                                                             NOTE: this parameter relevant only when working with multiple partitions. */
++    uint16_t                    partNumOfPlcrProfiles;  /**< Number of policer-profiles dedicated to this partition.
++                                                             this parameter is relevant if 'plcrSupport'=TRUE.
++                                                             NOTE: this parameter relevant only when working with multiple partitions. */
++} t_FmPcdParams;
++
++
++/**************************************************************************//**
++ @Function      FM_PCD_Config
++
++ @Description   Basic configuration of the PCD module.
++                Creates descriptor for the FM PCD module.
++
++ @Param[in]     p_FmPcdParams    A structure of parameters for the initialization of PCD.
++
++ @Return        A handle to the initialized module.
++*//***************************************************************************/
++t_Handle FM_PCD_Config(t_FmPcdParams *p_FmPcdParams);
++
++/**************************************************************************//**
++ @Function      FM_PCD_Init
++
++ @Description   Initialization of the PCD module.
++
++ @Param[in]     h_FmPcd - FM PCD module descriptor.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_PCD_Init(t_Handle h_FmPcd);
++
++/**************************************************************************//**
++ @Function      FM_PCD_Free
++
++ @Description   Frees all resources that were assigned to FM module.
++
++                Calling this routine invalidates the descriptor.
++
++ @Param[in]     h_FmPcd - FM PCD module descriptor.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_PCD_Free(t_Handle h_FmPcd);
++
++/**************************************************************************//**
++ @Group         FM_PCD_advanced_cfg_grp    FM PCD Advanced Configuration Unit
++
++ @Description   Frame Manager PCD Advanced Configuration API.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      FM_PCD_ConfigException
++
++ @Description   Calling this routine changes the internal driver data base
++                from its default selection of exceptions enabling.
++                [DEFAULT_numOfSharedPlcrProfiles].
++
++ @Param[in]     h_FmPcd         FM PCD module descriptor.
++ @Param[in]     exception       The exception to be selected.
++ @Param[in]     enable          TRUE to enable interrupt, FALSE to mask it.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_PCD_ConfigException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_PCD_ConfigHcFramesDataMemory
++
++ @Description   Configures memory-partition-id for FMan-Controller Host-Command
++                frames. Calling this routine changes the internal driver data
++                base from its default configuration [0].
++
++ @Param[in]     h_FmPcd         FM PCD module descriptor.
++ @Param[in]     memId           Memory partition ID.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      This routine may be called only if 'useHostCommand' was TRUE
++                when FM_PCD_Config() routine was called.
++*//***************************************************************************/
++t_Error FM_PCD_ConfigHcFramesDataMemory(t_Handle h_FmPcd, uint8_t memId);
++
++/**************************************************************************//**
++ @Function      FM_PCD_ConfigPlcrNumOfSharedProfiles
++
++ @Description   Calling this routine changes the internal driver data base
++                from its default selection of exceptions enablement.
++                [DEFAULT_numOfSharedPlcrProfiles].
++
++ @Param[in]     h_FmPcd                     FM PCD module descriptor.
++ @Param[in]     numOfSharedPlcrProfiles     Number of profiles to
++                                            be shared between ports on this partition
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_PCD_ConfigPlcrNumOfSharedProfiles(t_Handle h_FmPcd, uint16_t numOfSharedPlcrProfiles);
++
++/**************************************************************************//**
++ @Function      FM_PCD_ConfigPlcrAutoRefreshMode
++
++ @Description   Calling this routine changes the internal driver data base
++                from its default selection of exceptions enablement.
++                By default auto-refresh is [DEFAULT_plcrAutoRefresh].
++
++ @Param[in]     h_FmPcd         FM PCD module descriptor.
++ @Param[in]     enable          TRUE to enable, FALSE to disable
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_PCD_ConfigPlcrAutoRefreshMode(t_Handle h_FmPcd, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_PCD_ConfigPrsMaxCycleLimit
++
++ @Description   Calling this routine changes the internal data structure for
++                the maximum parsing time from its default value
++                [DEFAULT_MAX_PRS_CYC_LIM].
++
++ @Param[in]     h_FmPcd         FM PCD module descriptor.
++ @Param[in]     value           0 to disable the mechanism, or new
++                                maximum parsing time.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_PCD_ConfigPrsMaxCycleLimit(t_Handle h_FmPcd,uint16_t value);
++
++/** @} */ /* end of FM_PCD_advanced_cfg_grp group */
++/** @} */ /* end of FM_PCD_init_grp group */
++
++
++/**************************************************************************//**
++ @Group         FM_PCD_Runtime_grp FM PCD Runtime Unit
++
++ @Description   Frame Manager PCD Runtime Unit API
++
++                The runtime control allows creation of PCD infrastructure modules
++                such as Network Environment Characteristics, Classification Plan
++                Groups and Coarse Classification Trees.
++                It also allows on-the-fly initialization, modification and removal
++                of PCD modules such as KeyGen schemes, coarse classification nodes
++                and Policer profiles.
++
++                In order to explain the programming model of the PCD driver interface
++                a few terms should be explained, and will be used below.
++                  - Distinction Header - One of the 16 protocols supported by the FM parser,
++                    or one of the SHIM headers (1 or 2). May be a header with a special
++                    option (see below).
++                  - Interchangeable Headers Group - This is a group of Headers recognized
++                    by either one of them. For example, if in a specific context the user
++                    chooses to treat IPv4 and IPV6 in the same way, they may create an
++                    interchangeable Headers Unit consisting of these 2 headers.
++                  - A Distinction Unit - a Distinction Header or an Interchangeable Headers
++                    Group.
++                  - Header with special option - applies to Ethernet, MPLS, VLAN, IPv4 and
++                    IPv6, includes multicast, broadcast and other protocol specific options.
++                    In terms of hardware it relates to the options available in the classification
++                    plan.
++                  - Network Environment Characteristics - a set of Distinction Units that define
++                    the total recognizable header selection for a certain environment. This is
++                    NOT the list of all headers that will ever appear in a flow, but rather
++                    everything that needs distinction in a flow, where distinction is made by KeyGen
++                    schemes and coarse classification action descriptors.
++
++                The PCD runtime modules initialization is done in stages. The first stage after
++                initializing the PCD module itself is to establish a Network Flows Environment
++                Definition. The application may choose to establish one or more such environments.
++                Later, when needed, the application will have to state, for some of its modules,
++                to which single environment it belongs.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   A structure for SW parser labels
++ *//***************************************************************************/
++typedef struct t_FmPcdPrsLabelParams {
++    uint32_t                instructionOffset;              /**< SW parser label instruction offset (2 bytes
++                                                                 resolution), relative to Parser RAM. */
++    e_NetHeaderType         hdr;                            /**< The existence of this header will invoke
++                                                                 the SW parser code; Use  HEADER_TYPE_NONE
++                                                                 to indicate that sw parser is to run
++                                                                 independent of the existence of any protocol
++                                                                 (run before HW parser). */
++    uint8_t                 indexPerHdr;                    /**< Normally 0, if more than one SW parser
++                                                                 attachments for the same header, use this
++                                                                 index to distinguish between them. */
++} t_FmPcdPrsLabelParams;
++
++/**************************************************************************//**
++ @Description   A structure for SW parser
++ *//***************************************************************************/
++typedef struct t_FmPcdPrsSwParams {
++    bool                    override;                   /**< FALSE to invoke a check that nothing else
++                                                             was loaded to this address, including
++                                                             internal patches.
++                                                             TRUE to override any existing code.*/
++    uint32_t                size;                       /**< SW parser code size */
++    uint16_t                base;                       /**< SW parser base (in instruction counts!
++                                                             must be larger than 0x20)*/
++    uint8_t                 *p_Code;                    /**< SW parser code */
++    uint32_t                swPrsDataParams[FM_PCD_PRS_NUM_OF_HDRS];
++                                                        /**< SW parser data (parameters) */
++    uint8_t                 numOfLabels;                /**< Number of labels for SW parser. */
++    t_FmPcdPrsLabelParams   labelsTable[FM_PCD_PRS_NUM_OF_LABELS];
++                                                        /**< SW parser labels table, containing
++                                                             numOfLabels entries */
++} t_FmPcdPrsSwParams;
++
++
++/**************************************************************************//**
++ @Function      FM_PCD_Enable
++
++ @Description   This routine should be called after PCD is initialized for enabling all
++                PCD engines according to their existing configuration.
++
++ @Param[in]     h_FmPcd         FM PCD module descriptor.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init() and when PCD is disabled.
++*//***************************************************************************/
++t_Error FM_PCD_Enable(t_Handle h_FmPcd);
++
++/**************************************************************************//**
++ @Function      FM_PCD_Disable
++
++ @Description   This routine may be called when PCD is enabled in order to
++                disable all PCD engines. It may be called
++                only when none of the ports in the system are using the PCD.
++
++ @Param[in]     h_FmPcd         FM PCD module descriptor.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init() and when PCD is enabled.
++*//***************************************************************************/
++t_Error FM_PCD_Disable(t_Handle h_FmPcd);
++
++/**************************************************************************//**
++ @Function      FM_PCD_GetCounter
++
++ @Description   Reads one of the FM PCD counters.
++
++ @Param[in]     h_FmPcd     FM PCD module descriptor.
++ @Param[in]     counter     The requested counter.
++
++ @Return        Counter's current value.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++                Note that it is user's responsibility to call this routine only
++                for enabled counters, and there will be no indication if a
++                disabled counter is accessed.
++*//***************************************************************************/
++uint32_t FM_PCD_GetCounter(t_Handle h_FmPcd, e_FmPcdCounters counter);
++
++/**************************************************************************//**
++@Function       FM_PCD_PrsLoadSw
++
++@Description    This routine may be called in order to load software parsing code.
++
++
++@Param[in]      h_FmPcd        FM PCD module descriptor.
++@Param[in]      p_SwPrs        A pointer to a structure of software
++                               parser parameters, including the software
++                               parser image.
++
++@Return         E_OK on success; Error code otherwise.
++
++@Cautions       Allowed only following FM_PCD_Init() and when PCD is disabled.
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_PCD_PrsLoadSw(t_Handle h_FmPcd, t_FmPcdPrsSwParams *p_SwPrs);
++
++/**************************************************************************//**
++@Function      FM_PCD_SetAdvancedOffloadSupport
++
++@Description   This routine must be called in order to support the following features:
++               IP-fragmentation, IP-reassembly, IPsec, Header-manipulation, frame-replicator.
++
++@Param[in]     h_FmPcd         FM PCD module descriptor.
++
++@Return        E_OK on success; Error code otherwise.
++
++@Cautions      Allowed only following FM_PCD_Init() and when PCD is disabled.
++               This routine should NOT be called from guest-partition
++               (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_PCD_SetAdvancedOffloadSupport(t_Handle h_FmPcd);
++
++/**************************************************************************//**
++ @Function      FM_PCD_KgSetDfltValue
++
++ @Description   Calling this routine sets a global default value to be used
++                by the KeyGen when parser does not recognize a required
++                field/header.
++                By default default values are 0.
++
++ @Param[in]     h_FmPcd         FM PCD module descriptor.
++ @Param[in]     valueId         0,1 - one of 2 global default values.
++ @Param[in]     value           The requested default value.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init() and when PCD is disabled.
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_PCD_KgSetDfltValue(t_Handle h_FmPcd, uint8_t valueId, uint32_t value);
++
++/**************************************************************************//**
++ @Function      FM_PCD_KgSetAdditionalDataAfterParsing
++
++ @Description   Calling this routine allows the KeyGen to access data past
++                the parser finishing point.
++
++ @Param[in]     h_FmPcd         FM PCD module descriptor.
++ @Param[in]     payloadOffset   the number of bytes beyond the parser location.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init() and when PCD is disabled.
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_PCD_KgSetAdditionalDataAfterParsing(t_Handle h_FmPcd, uint8_t payloadOffset);
++
++/**************************************************************************//**
++ @Function      FM_PCD_SetException
++
++ @Description   Calling this routine enables/disables PCD interrupts.
++
++ @Param[in]     h_FmPcd         FM PCD module descriptor.
++ @Param[in]     exception       The exception to be selected.
++ @Param[in]     enable          TRUE to enable interrupt, FALSE to mask it.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_PCD_SetException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_PCD_ModifyCounter
++
++ @Description   Sets a value to an enabled counter. Use "0" to reset the counter.
++
++ @Param[in]     h_FmPcd     FM PCD module descriptor.
++ @Param[in]     counter     The requested counter.
++ @Param[in]     value       The requested value to be written into the counter.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_PCD_ModifyCounter(t_Handle h_FmPcd, e_FmPcdCounters counter, uint32_t value);
++
++/**************************************************************************//**
++ @Function      FM_PCD_SetPlcrStatistics
++
++ @Description   This routine may be used to enable/disable policer statistics
++                counter. By default the statistics is enabled.
++
++ @Param[in]     h_FmPcd         FM PCD module descriptor
++ @Param[in]     enable          TRUE to enable, FALSE to disable.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_PCD_SetPlcrStatistics(t_Handle h_FmPcd, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_PCD_SetPrsStatistics
++
++ @Description   Defines whether to gather parser statistics including all ports.
++
++ @Param[in]     h_FmPcd     FM PCD module descriptor.
++ @Param[in]     enable      TRUE to enable, FALSE to disable.
++
++ @Return        None
++
++ @Cautions      Allowed only following FM_PCD_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++void FM_PCD_SetPrsStatistics(t_Handle h_FmPcd, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_PCD_HcTxConf
++
++ @Description   This routine should be called to confirm frames that were
++                 received on the HC confirmation queue.
++
++ @Param[in]     h_FmPcd         A handle to an FM PCD Module.
++ @Param[in]     p_Fd            Frame descriptor of the received frame.
++
++ @Cautions      Allowed only following FM_PCD_Init(). Allowed only if 'useHostCommand'
++                option was selected in the initialization.
++*//***************************************************************************/
++void FM_PCD_HcTxConf(t_Handle h_FmPcd, t_DpaaFD *p_Fd);
++
++/**************************************************************************//*
++ @Function      FM_PCD_ForceIntr
++
++ @Description   Causes an interrupt event on the requested source.
++
++ @Param[in]     h_FmPcd     FM PCD module descriptor.
++ @Param[in]     exception       An exception to be forced.
++
++ @Return        E_OK on success; Error code if the exception is not enabled,
++                or is not able to create interrupt.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_PCD_ForceIntr (t_Handle h_FmPcd, e_FmPcdExceptions exception);
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++/**************************************************************************//**
++ @Function      FM_PCD_DumpRegs
++
++ @Description   Dumps all PCD registers
++
++ @Param[in]     h_FmPcd         A handle to an FM PCD Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++                NOTE: this routine may be called only for FM in master mode
++                (i.e. 'guestId'=NCSW_MASTER_ID) or in a case that the registers
++                are mapped.
++*//***************************************************************************/
++t_Error FM_PCD_DumpRegs(t_Handle h_FmPcd);
++
++/**************************************************************************//**
++ @Function      FM_PCD_KgDumpRegs
++
++ @Description   Dumps all PCD KG registers
++
++ @Param[in]     h_FmPcd         A handle to an FM PCD Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++                NOTE: this routine may be called only for FM in master mode
++                (i.e. 'guestId'=NCSW_MASTER_ID) or in a case that the registers
++                are mapped.
++*//***************************************************************************/
++t_Error FM_PCD_KgDumpRegs(t_Handle h_FmPcd);
++
++/**************************************************************************//**
++ @Function      FM_PCD_PlcrDumpRegs
++
++ @Description   Dumps all PCD Policer registers
++
++ @Param[in]     h_FmPcd         A handle to an FM PCD Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++                NOTE: this routine may be called only for FM in master mode
++                (i.e. 'guestId'=NCSW_MASTER_ID) or in a case that the registers
++                are mapped.
++*//***************************************************************************/
++t_Error FM_PCD_PlcrDumpRegs(t_Handle h_FmPcd);
++
++/**************************************************************************//**
++ @Function      FM_PCD_PlcrProfileDumpRegs
++
++ @Description   Dumps all PCD Policer profile registers
++
++ @Param[in]     h_Profile       A handle to a Policer profile.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++                NOTE: this routine may be called only for FM in master mode
++                (i.e. 'guestId'=NCSW_MASTER_ID) or in a case that the registers
++                are mapped.
++*//***************************************************************************/
++t_Error FM_PCD_PlcrProfileDumpRegs(t_Handle h_Profile);
++
++/**************************************************************************//**
++ @Function      FM_PCD_PrsDumpRegs
++
++ @Description   Dumps all PCD Parser registers
++
++ @Param[in]     h_FmPcd         A handle to an FM PCD Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++                NOTE: this routine may be called only for FM in master mode
++                (i.e. 'guestId'=NCSW_MASTER_ID) or in a case that the registers
++                are mapped.
++*//***************************************************************************/
++t_Error FM_PCD_PrsDumpRegs(t_Handle h_FmPcd);
++
++/**************************************************************************//**
++ @Function      FM_PCD_HcDumpRegs
++
++ @Description   Dumps HC Port registers
++
++ @Param[in]     h_FmPcd         A handle to an FM PCD Module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++                NOTE: this routine may be called only for FM in master mode
++                (i.e. 'guestId'=NCSW_MASTER_ID).
++*//***************************************************************************/
++t_Error     FM_PCD_HcDumpRegs(t_Handle h_FmPcd);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++
++
++/**************************************************************************//**
++ KeyGen         FM_PCD_Runtime_build_grp FM PCD Runtime Building Unit
++
++ @Description   Frame Manager PCD Runtime Building API
++
++                This group contains routines for setting, deleting and modifying
++                PCD resources, for defining the total PCD tree.
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Collection    Definitions of coarse classification
++                parameters as required by KeyGen (when coarse classification
++                is the next engine after this scheme).
++*//***************************************************************************/
++#define FM_PCD_MAX_NUM_OF_CC_TREES              8
++#define FM_PCD_MAX_NUM_OF_CC_GROUPS             16
++#define FM_PCD_MAX_NUM_OF_CC_UNITS              4
++#define FM_PCD_MAX_NUM_OF_KEYS                  256
++#define FM_PCD_MAX_NUM_OF_FLOWS                 (4*KILOBYTE)
++#define FM_PCD_MAX_SIZE_OF_KEY                  56
++#define FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP     16
++#define FM_PCD_LAST_KEY_INDEX                   0xffff
++
++#define FM_PCD_MAX_NUM_OF_CC_NODES              255 /* Obsolete, not used - will be removed in the future */
++/* @} */
++
++/**************************************************************************//**
++ @Collection    A set of definitions to allow protocol
++                special option description.
++*//***************************************************************************/
++typedef uint32_t        protocolOpt_t;          /**< A general type to define a protocol option. */
++
++typedef protocolOpt_t   ethProtocolOpt_t;       /**< Ethernet protocol options. */
++#define ETH_BROADCAST               0x80000000  /**< Ethernet Broadcast. */
++#define ETH_MULTICAST               0x40000000  /**< Ethernet Multicast. */
++
++typedef protocolOpt_t   vlanProtocolOpt_t;      /**< VLAN protocol options. */
++#define VLAN_STACKED                0x20000000  /**< Stacked VLAN. */
++
++typedef protocolOpt_t   mplsProtocolOpt_t;      /**< MPLS protocol options. */
++#define MPLS_STACKED                0x10000000  /**< Stacked MPLS. */
++
++typedef protocolOpt_t   ipv4ProtocolOpt_t;      /**< IPv4 protocol options. */
++#define IPV4_BROADCAST_1            0x08000000  /**< IPv4 Broadcast. */
++#define IPV4_MULTICAST_1            0x04000000  /**< IPv4 Multicast. */
++#define IPV4_UNICAST_2              0x02000000  /**< Tunneled IPv4 - Unicast. */
++#define IPV4_MULTICAST_BROADCAST_2  0x01000000  /**< Tunneled IPv4 - Broadcast/Multicast. */
++
++#define IPV4_FRAG_1                 0x00000008  /**< IPV4 reassembly option.
++                                                     IPV4 Reassembly manipulation requires network
++                                                     environment with IPV4 header and IPV4_FRAG_1 option  */
++
++typedef protocolOpt_t   ipv6ProtocolOpt_t;      /**< IPv6 protocol options. */
++#define IPV6_MULTICAST_1            0x00800000  /**< IPv6 Multicast. */
++#define IPV6_UNICAST_2              0x00400000  /**< Tunneled IPv6 - Unicast. */
++#define IPV6_MULTICAST_2            0x00200000  /**< Tunneled IPv6 - Multicast. */
++
++#define IPV6_FRAG_1                 0x00000004  /**< IPV6 reassembly option.
++                                                     IPV6 Reassembly manipulation requires network
++                                                     environment with IPV6 header and IPV6_FRAG_1 option;
++                                                     in case where fragment found, the fragment-extension offset
++                                                     may be found at 'shim2' (in parser-result). */
++#if (DPAA_VERSION >= 11)
++typedef protocolOpt_t   capwapProtocolOpt_t;      /**< CAPWAP protocol options. */
++#define CAPWAP_FRAG_1               0x00000008  /**< CAPWAP reassembly option.
++                                                     CAPWAP Reassembly manipulation requires network
++                                                     environment with CAPWAP header and CAPWAP_FRAG_1 option;
++                                                     in case where fragment found, the fragment-extension offset
++                                                     may be found at 'shim2' (in parser-result). */
++#endif /* (DPAA_VERSION >= 11) */
++
++
++/* @} */
++
++#define FM_PCD_MANIP_MAX_HDR_SIZE               256
++#define FM_PCD_MANIP_DSCP_TO_VLAN_TRANS         64
++
++/**************************************************************************//**
++ @Collection    A set of definitions to support Header Manipulation selection.
++*//***************************************************************************/
++typedef uint32_t                hdrManipFlags_t;            /**< A general type to define a HMan update command flags. */
++
++typedef hdrManipFlags_t         ipv4HdrManipUpdateFlags_t;  /**< IPv4 protocol HMan update command flags. */
++
++#define HDR_MANIP_IPV4_TOS      0x80000000                  /**< update TOS with the given value ('tos' field
++                                                                 of t_FmPcdManipHdrFieldUpdateIpv4) */
++#define HDR_MANIP_IPV4_ID       0x40000000                  /**< update IP ID with the given value ('id' field
++                                                                 of t_FmPcdManipHdrFieldUpdateIpv4) */
++#define HDR_MANIP_IPV4_TTL      0x20000000                  /**< Decrement TTL by 1 */
++#define HDR_MANIP_IPV4_SRC      0x10000000                  /**< update IP source address with the given value
++                                                                 ('src' field of t_FmPcdManipHdrFieldUpdateIpv4) */
++#define HDR_MANIP_IPV4_DST      0x08000000                  /**< update IP destination address with the given value
++                                                                 ('dst' field of t_FmPcdManipHdrFieldUpdateIpv4) */
++
++typedef hdrManipFlags_t         ipv6HdrManipUpdateFlags_t;  /**< IPv6 protocol HMan update command flags. */
++
++#define HDR_MANIP_IPV6_TC       0x80000000                  /**< update Traffic Class address with the given value
++                                                                 ('trafficClass' field of t_FmPcdManipHdrFieldUpdateIpv6) */
++#define HDR_MANIP_IPV6_HL       0x40000000                  /**< Decrement Hop Limit by 1 */
++#define HDR_MANIP_IPV6_SRC      0x20000000                  /**< update IP source address with the given value
++                                                                 ('src' field of t_FmPcdManipHdrFieldUpdateIpv6) */
++#define HDR_MANIP_IPV6_DST      0x10000000                  /**< update IP destination address with the given value
++                                                                 ('dst' field of t_FmPcdManipHdrFieldUpdateIpv6) */
++
++typedef hdrManipFlags_t         tcpUdpHdrManipUpdateFlags_t;/**< TCP/UDP protocol HMan update command flags. */
++
++#define HDR_MANIP_TCP_UDP_SRC       0x80000000              /**< update TCP/UDP source address with the given value
++                                                                 ('src' field of t_FmPcdManipHdrFieldUpdateTcpUdp) */
++#define HDR_MANIP_TCP_UDP_DST       0x40000000              /**< update TCP/UDP destination address with the given value
++                                                                 ('dst' field of t_FmPcdManipHdrFieldUpdateTcpUdp) */
++#define HDR_MANIP_TCP_UDP_CHECKSUM  0x20000000             /**< update TCP/UDP checksum */
++
++/* @} */
++
++/**************************************************************************//**
++ @Description   A type used for returning the order of the key extraction.
++                each value in this array represents the index of the extraction
++                command as defined by the user in the initialization extraction array.
++                The valid size of this array is the user define number of extractions
++                required (also marked by the second '0' in this array).
++*//***************************************************************************/
++typedef    uint8_t    t_FmPcdKgKeyOrder [FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY];
++
++/**************************************************************************//**
++ @Description   All PCD engines
++*//***************************************************************************/
++typedef enum e_FmPcdEngine {
++    e_FM_PCD_INVALID = 0,   /**< Invalid PCD engine */
++    e_FM_PCD_DONE,          /**< No PCD Engine indicated */
++    e_FM_PCD_KG,            /**< KeyGen */
++    e_FM_PCD_CC,            /**< Coarse classifier */
++    e_FM_PCD_PLCR,          /**< Policer */
++    e_FM_PCD_PRS,           /**< Parser */
++#if (DPAA_VERSION >= 11)
++    e_FM_PCD_FR,            /**< Frame-Replicator */
++#endif /* (DPAA_VERSION >= 11) */
++    e_FM_PCD_HASH           /**< Hash table */
++} e_FmPcdEngine;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting extraction by header types
++*//***************************************************************************/
++typedef enum e_FmPcdExtractByHdrType {
++    e_FM_PCD_EXTRACT_FROM_HDR,      /**< Extract bytes from header */
++    e_FM_PCD_EXTRACT_FROM_FIELD,    /**< Extract bytes from header field */
++    e_FM_PCD_EXTRACT_FULL_FIELD     /**< Extract a full field */
++} e_FmPcdExtractByHdrType;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting extraction source
++                (when it is not the header)
++*//***************************************************************************/
++typedef enum e_FmPcdExtractFrom {
++    e_FM_PCD_EXTRACT_FROM_FRAME_START,          /**< KG & CC: Extract from beginning of frame */
++    e_FM_PCD_EXTRACT_FROM_DFLT_VALUE,           /**< KG only: Extract from a default value */
++    e_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE,    /**< KG & CC: Extract from the point where parsing had finished */
++    e_FM_PCD_EXTRACT_FROM_KEY,                  /**< CC only: Field where saved KEY */
++    e_FM_PCD_EXTRACT_FROM_HASH,                 /**< CC only: Field where saved HASH */
++    e_FM_PCD_EXTRACT_FROM_PARSE_RESULT,         /**< KG only: Extract from the parser result */
++    e_FM_PCD_EXTRACT_FROM_ENQ_FQID,             /**< KG & CC: Extract from enqueue FQID */
++    e_FM_PCD_EXTRACT_FROM_FLOW_ID               /**< CC only: Field where saved Dequeue FQID */
++} e_FmPcdExtractFrom;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting extraction type
++*//***************************************************************************/
++typedef enum e_FmPcdExtractType {
++    e_FM_PCD_EXTRACT_BY_HDR,                /**< Extract according to header */
++    e_FM_PCD_EXTRACT_NON_HDR,               /**< Extract from data that is not the header */
++    e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO   /**< Extract private info as specified by user */
++} e_FmPcdExtractType;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting default extraction value
++*//***************************************************************************/
++typedef enum e_FmPcdKgExtractDfltSelect {
++    e_FM_PCD_KG_DFLT_GBL_0,          /**< Default selection is KG register 0 */
++    e_FM_PCD_KG_DFLT_GBL_1,          /**< Default selection is KG register 1 */
++    e_FM_PCD_KG_DFLT_PRIVATE_0,      /**< Default selection is a per scheme register 0 */
++    e_FM_PCD_KG_DFLT_PRIVATE_1,      /**< Default selection is a per scheme register 1 */
++    e_FM_PCD_KG_DFLT_ILLEGAL         /**< Illegal selection */
++} e_FmPcdKgExtractDfltSelect;
++
++/**************************************************************************//**
++ @Description   Enumeration type defining all default groups - each group shares
++                a default value, one of four user-initialized values.
++*//***************************************************************************/
++typedef enum e_FmPcdKgKnownFieldsDfltTypes {
++    e_FM_PCD_KG_MAC_ADDR,               /**< MAC Address */
++    e_FM_PCD_KG_TCI,                    /**< TCI field */
++    e_FM_PCD_KG_ENET_TYPE,              /**< ENET Type */
++    e_FM_PCD_KG_PPP_SESSION_ID,         /**< PPP Session id */
++    e_FM_PCD_KG_PPP_PROTOCOL_ID,        /**< PPP Protocol id */
++    e_FM_PCD_KG_MPLS_LABEL,             /**< MPLS label */
++    e_FM_PCD_KG_IP_ADDR,                /**< IP address */
++    e_FM_PCD_KG_PROTOCOL_TYPE,          /**< Protocol type */
++    e_FM_PCD_KG_IP_TOS_TC,              /**< TOS or TC */
++    e_FM_PCD_KG_IPV6_FLOW_LABEL,        /**< IPV6 flow label */
++    e_FM_PCD_KG_IPSEC_SPI,              /**< IPSEC SPI */
++    e_FM_PCD_KG_L4_PORT,                /**< L4 Port */
++    e_FM_PCD_KG_TCP_FLAG,               /**< TCP Flag */
++    e_FM_PCD_KG_GENERIC_FROM_DATA,      /**< grouping implemented by SW,
++                                             any data extraction that is not the full
++                                             field described above  */
++    e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V, /**< grouping implemented by SW,
++                                             any data extraction without validation */
++    e_FM_PCD_KG_GENERIC_NOT_FROM_DATA   /**< grouping implemented by SW,
++                                             extraction from parser result or
++                                             direct use of default value  */
++} e_FmPcdKgKnownFieldsDfltTypes;
++
++/**************************************************************************//**
++ @Description   Enumeration type for defining header index for scenarios with
++                multiple (tunneled) headers
++*//***************************************************************************/
++typedef enum e_FmPcdHdrIndex {
++    e_FM_PCD_HDR_INDEX_NONE = 0,        /**< used when multiple headers not used, also
++                                             to specify regular IP (not tunneled). */
++    e_FM_PCD_HDR_INDEX_1,               /**< may be used for VLAN, MPLS, tunneled IP */
++    e_FM_PCD_HDR_INDEX_2,               /**< may be used for MPLS, tunneled IP */
++    e_FM_PCD_HDR_INDEX_3,               /**< may be used for MPLS */
++    e_FM_PCD_HDR_INDEX_LAST = 0xFF      /**< may be used for VLAN, MPLS */
++} e_FmPcdHdrIndex;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting the policer profile functional type
++*//***************************************************************************/
++typedef enum e_FmPcdProfileTypeSelection {
++    e_FM_PCD_PLCR_PORT_PRIVATE,         /**< Port dedicated profile */
++    e_FM_PCD_PLCR_SHARED                /**< Shared profile (shared within partition) */
++} e_FmPcdProfileTypeSelection;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting the policer profile algorithm
++*//***************************************************************************/
++typedef enum e_FmPcdPlcrAlgorithmSelection {
++    e_FM_PCD_PLCR_PASS_THROUGH,         /**< Policer pass through */
++    e_FM_PCD_PLCR_RFC_2698,             /**< Policer algorithm RFC 2698 */
++    e_FM_PCD_PLCR_RFC_4115              /**< Policer algorithm RFC 4115 */
++} e_FmPcdPlcrAlgorithmSelection;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting a policer profile color mode
++*//***************************************************************************/
++typedef enum e_FmPcdPlcrColorMode {
++    e_FM_PCD_PLCR_COLOR_BLIND,          /**< Color blind */
++    e_FM_PCD_PLCR_COLOR_AWARE           /**< Color aware */
++} e_FmPcdPlcrColorMode;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting a policer profile color
++*//***************************************************************************/
++typedef enum e_FmPcdPlcrColor {
++    e_FM_PCD_PLCR_GREEN,                /**< Green color code */
++    e_FM_PCD_PLCR_YELLOW,               /**< Yellow color code */
++    e_FM_PCD_PLCR_RED,                  /**< Red color code */
++    e_FM_PCD_PLCR_OVERRIDE              /**< Color override code */
++} e_FmPcdPlcrColor;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting the policer profile packet frame length selector
++*//***************************************************************************/
++typedef enum e_FmPcdPlcrFrameLengthSelect {
++  e_FM_PCD_PLCR_L2_FRM_LEN,             /**< L2 frame length */
++  e_FM_PCD_PLCR_L3_FRM_LEN,             /**< L3 frame length */
++  e_FM_PCD_PLCR_L4_FRM_LEN,             /**< L4 frame length */
++  e_FM_PCD_PLCR_FULL_FRM_LEN            /**< Full frame length */
++} e_FmPcdPlcrFrameLengthSelect;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting roll-back frame
++*//***************************************************************************/
++typedef enum e_FmPcdPlcrRollBackFrameSelect {
++  e_FM_PCD_PLCR_ROLLBACK_L2_FRM_LEN,    /**< Roll-back L2 frame length */
++  e_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN   /**< Roll-back Full frame length */
++} e_FmPcdPlcrRollBackFrameSelect;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting the policer profile packet or byte mode
++*//***************************************************************************/
++typedef enum e_FmPcdPlcrRateMode {
++    e_FM_PCD_PLCR_BYTE_MODE,            /**< Byte mode */
++    e_FM_PCD_PLCR_PACKET_MODE           /**< Packet mode */
++} e_FmPcdPlcrRateMode;
++
++/**************************************************************************//**
++ @Description   Enumeration type for defining action of frame
++*//***************************************************************************/
++typedef enum e_FmPcdDoneAction {
++    e_FM_PCD_ENQ_FRAME = 0,        /**< Enqueue frame */
++    e_FM_PCD_DROP_FRAME            /**< Mark this frame as error frame and continue
++                                        to error flow; 'FM_PORT_FRM_ERR_CLS_DISCARD'
++                                        flag will be set for this frame. */
++} e_FmPcdDoneAction;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting the policer counter
++*//***************************************************************************/
++typedef enum e_FmPcdPlcrProfileCounters {
++    e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER,               /**< Green packets counter */
++    e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER,              /**< Yellow packets counter */
++    e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER,                 /**< Red packets counter */
++    e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER,   /**< Recolored yellow packets counter */
++    e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER       /**< Recolored red packets counter */
++} e_FmPcdPlcrProfileCounters;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting the PCD action after extraction
++*//***************************************************************************/
++typedef enum e_FmPcdAction {
++    e_FM_PCD_ACTION_NONE,                           /**< NONE  */
++    e_FM_PCD_ACTION_EXACT_MATCH,                    /**< Exact match on the selected extraction */
++    e_FM_PCD_ACTION_INDEXED_LOOKUP                  /**< Indexed lookup on the selected extraction */
++} e_FmPcdAction;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of insert manipulation
++*//***************************************************************************/
++typedef enum e_FmPcdManipHdrInsrtType {
++    e_FM_PCD_MANIP_INSRT_GENERIC,                   /**< Insert according to offset & size */
++    e_FM_PCD_MANIP_INSRT_BY_HDR,                    /**< Insert according to protocol */
++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++    e_FM_PCD_MANIP_INSRT_BY_TEMPLATE                /**< Insert template to start of frame */
++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
++} e_FmPcdManipHdrInsrtType;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of remove manipulation
++*//***************************************************************************/
++typedef enum e_FmPcdManipHdrRmvType {
++    e_FM_PCD_MANIP_RMV_GENERIC,                     /**< Remove according to offset & size */
++    e_FM_PCD_MANIP_RMV_BY_HDR                       /**< Remove according to offset & size */
++} e_FmPcdManipHdrRmvType;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting specific L2 fields removal
++*//***************************************************************************/
++typedef enum e_FmPcdManipHdrRmvSpecificL2 {
++    e_FM_PCD_MANIP_HDR_RMV_ETHERNET,                /**< Ethernet/802.3 MAC */
++    e_FM_PCD_MANIP_HDR_RMV_STACKED_QTAGS,           /**< stacked QTags */
++    e_FM_PCD_MANIP_HDR_RMV_ETHERNET_AND_MPLS,       /**< MPLS and Ethernet/802.3 MAC header until
++                                                         the header which follows the MPLS header */
++    e_FM_PCD_MANIP_HDR_RMV_MPLS,                     /**< Remove MPLS header (Unlimited MPLS labels) */
++    e_FM_PCD_MANIP_HDR_RMV_PPPOE                     /**< Remove the PPPoE header and PPP protocol field. */
++} e_FmPcdManipHdrRmvSpecificL2;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting specific fields updates
++*//***************************************************************************/
++typedef enum e_FmPcdManipHdrFieldUpdateType {
++    e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN,               /**< VLAN updates */
++    e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4,               /**< IPV4 updates */
++    e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6,               /**< IPV6 updates */
++    e_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP,            /**< TCP_UDP updates */
++} e_FmPcdManipHdrFieldUpdateType;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting VLAN updates
++*//***************************************************************************/
++typedef enum e_FmPcdManipHdrFieldUpdateVlan {
++    e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_VPRI,      /**< Replace VPri of outer most VLAN tag. */
++    e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN    /**< DSCP to VLAN priority bits translation */
++} e_FmPcdManipHdrFieldUpdateVlan;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting specific L2 header insertion
++*//***************************************************************************/
++typedef enum e_FmPcdManipHdrInsrtSpecificL2 {
++    e_FM_PCD_MANIP_HDR_INSRT_MPLS,                   /**< Insert MPLS header (Unlimited MPLS labels) */
++    e_FM_PCD_MANIP_HDR_INSRT_PPPOE                   /**< Insert PPPOE */
++} e_FmPcdManipHdrInsrtSpecificL2;
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Description   Enumeration type for selecting QoS mapping mode
++
++                Note: In all cases except 'e_FM_PCD_MANIP_HDR_QOS_MAPPING_NONE'
++                User should instruct the port to read the hash-result
++*//***************************************************************************/
++typedef enum e_FmPcdManipHdrQosMappingMode {
++    e_FM_PCD_MANIP_HDR_QOS_MAPPING_NONE = 0,   /**< No mapping, QoS field will not be changed */
++    e_FM_PCD_MANIP_HDR_QOS_MAPPING_AS_IS, /**< QoS field will be overwritten by the last byte in the hash-result. */
++} e_FmPcdManipHdrQosMappingMode;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting QoS source
++
++                Note: In all cases except 'e_FM_PCD_MANIP_HDR_QOS_SRC_NONE'
++                User should left room for the hash-result on input/output buffer
++                and instruct the port to read/write the hash-result to the buffer (RPD should be set)
++*//***************************************************************************/
++typedef enum e_FmPcdManipHdrQosSrc {
++    e_FM_PCD_MANIP_HDR_QOS_SRC_NONE = 0,        /**< TODO */
++    e_FM_PCD_MANIP_HDR_QOS_SRC_USER_DEFINED,    /**< QoS will be taken from the last byte in the hash-result. */
++} e_FmPcdManipHdrQosSrc;
++#endif /* (DPAA_VERSION >= 11) */
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of header insertion
++*//***************************************************************************/
++typedef enum e_FmPcdManipHdrInsrtByHdrType {
++    e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2,        /**< Specific L2 fields insertion */
++#if (DPAA_VERSION >= 11)
++    e_FM_PCD_MANIP_INSRT_BY_HDR_IP,                 /**< IP insertion */
++    e_FM_PCD_MANIP_INSRT_BY_HDR_UDP,                /**< UDP insertion */
++    e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE,             /**< UDP lite insertion */
++    e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP                 /**< CAPWAP insertion */
++#endif /* (DPAA_VERSION >= 11) */
++} e_FmPcdManipHdrInsrtByHdrType;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting specific customCommand
++*//***************************************************************************/
++typedef enum e_FmPcdManipHdrCustomType {
++    e_FM_PCD_MANIP_HDR_CUSTOM_IP_REPLACE,           /**< Replace IPv4/IPv6 */
++    e_FM_PCD_MANIP_HDR_CUSTOM_GEN_FIELD_REPLACE,     /**< Replace IPv4/IPv6 */
++} e_FmPcdManipHdrCustomType;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting specific customCommand
++*//***************************************************************************/
++typedef enum e_FmPcdManipHdrCustomIpReplace {
++    e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV4_BY_IPV6,           /**< Replace IPv4 by IPv6 */
++    e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4            /**< Replace IPv6 by IPv4 */
++} e_FmPcdManipHdrCustomIpReplace;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of header removal
++*//***************************************************************************/
++typedef enum e_FmPcdManipHdrRmvByHdrType {
++    e_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2 = 0,      /**< Specific L2 fields removal */
++#if (DPAA_VERSION >= 11)
++    e_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP,                  /**< CAPWAP removal */
++#endif /* (DPAA_VERSION >= 11) */
++#if (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++    e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START,           /**< Locate from data that is not the header */
++#endif /* (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
++} e_FmPcdManipHdrRmvByHdrType;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of timeout mode
++*//***************************************************************************/
++typedef enum e_FmPcdManipReassemTimeOutMode {
++    e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAMES, /**< Limits the time of the reassembly process
++                                                 from the first fragment to the last */
++    e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAG    /**< Limits the time of receiving the fragment */
++} e_FmPcdManipReassemTimeOutMode;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of WaysNumber mode
++*//***************************************************************************/
++typedef enum e_FmPcdManipReassemWaysNumber {
++    e_FM_PCD_MANIP_ONE_WAY_HASH = 1,    /**< One way hash    */
++    e_FM_PCD_MANIP_TWO_WAYS_HASH,       /**< Two ways hash   */
++    e_FM_PCD_MANIP_THREE_WAYS_HASH,     /**< Three ways hash */
++    e_FM_PCD_MANIP_FOUR_WAYS_HASH,      /**< Four ways hash  */
++    e_FM_PCD_MANIP_FIVE_WAYS_HASH,      /**< Five ways hash  */
++    e_FM_PCD_MANIP_SIX_WAYS_HASH,       /**< Six ways hash   */
++    e_FM_PCD_MANIP_SEVEN_WAYS_HASH,     /**< Seven ways hash */
++    e_FM_PCD_MANIP_EIGHT_WAYS_HASH      /**< Eight ways hash */
++} e_FmPcdManipReassemWaysNumber;
++
++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of statistics mode
++*//***************************************************************************/
++typedef enum e_FmPcdStatsType {
++    e_FM_PCD_STATS_PER_FLOWID = 0       /**< Flow ID is used as index for getting statistics */
++} e_FmPcdStatsType;
++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting manipulation type
++*//***************************************************************************/
++typedef enum e_FmPcdManipType {
++    e_FM_PCD_MANIP_HDR = 0,             /**< Header manipulation */
++    e_FM_PCD_MANIP_REASSEM,             /**< Reassembly */
++    e_FM_PCD_MANIP_FRAG,                /**< Fragmentation */
++    e_FM_PCD_MANIP_SPECIAL_OFFLOAD      /**< Special Offloading */
++} e_FmPcdManipType;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of statistics mode
++*//***************************************************************************/
++typedef enum e_FmPcdCcStatsMode {
++    e_FM_PCD_CC_STATS_MODE_NONE = 0,        /**< No statistics support */
++    e_FM_PCD_CC_STATS_MODE_FRAME,           /**< Frame count statistics */
++    e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME,  /**< Byte and frame count statistics */
++#if (DPAA_VERSION >= 11)
++    e_FM_PCD_CC_STATS_MODE_RMON,            /**< Byte and frame length range count statistics;
++                                                 This mode is supported only on B4860 device */
++#endif /* (DPAA_VERSION >= 11) */
++} e_FmPcdCcStatsMode;
++
++/**************************************************************************//**
++ @Description   Enumeration type for determining the action in case an IP packet
++                is larger than MTU but its DF (Don't Fragment) bit is set.
++*//***************************************************************************/
++typedef enum e_FmPcdManipDontFragAction {
++    e_FM_PCD_MANIP_DISCARD_PACKET = 0,                  /**< Discard packet */
++    e_FM_PCD_MANIP_ENQ_TO_ERR_Q_OR_DISCARD_PACKET = e_FM_PCD_MANIP_DISCARD_PACKET,
++                                                        /**< Obsolete, cannot enqueue to error queue;
++                                                             In practice, selects to discard packets;
++                                                             Will be removed in the future */
++    e_FM_PCD_MANIP_FRAGMENT_PACKET,                     /**< Fragment packet and continue normal processing */
++    e_FM_PCD_MANIP_CONTINUE_WITHOUT_FRAG                /**< Continue normal processing without fragmenting the packet */
++} e_FmPcdManipDontFragAction;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of special offload manipulation
++*//***************************************************************************/
++typedef enum e_FmPcdManipSpecialOffloadType {
++    e_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC,    /**< IPSec offload manipulation */
++#if (DPAA_VERSION >= 11)
++    e_FM_PCD_MANIP_SPECIAL_OFFLOAD_CAPWAP    /**< CAPWAP offload manipulation */
++#endif /* (DPAA_VERSION >= 11) */
++} e_FmPcdManipSpecialOffloadType;
++
++
++/**************************************************************************//**
++ @Description   A Union of protocol dependent special options
++*//***************************************************************************/
++typedef union u_FmPcdHdrProtocolOpt {
++    ethProtocolOpt_t    ethOpt;     /**< Ethernet options */
++    vlanProtocolOpt_t   vlanOpt;    /**< VLAN options */
++    mplsProtocolOpt_t   mplsOpt;    /**< MPLS options */
++    ipv4ProtocolOpt_t   ipv4Opt;    /**< IPv4 options */
++    ipv6ProtocolOpt_t   ipv6Opt;    /**< IPv6 options */
++#if (DPAA_VERSION >= 11)
++    capwapProtocolOpt_t capwapOpt;  /**< CAPWAP options */
++#endif /* (DPAA_VERSION >= 11) */
++} u_FmPcdHdrProtocolOpt;
++
++/**************************************************************************//**
++ @Description   A union holding protocol fields
++
++
++                Fields supported as "full fields":
++                    HEADER_TYPE_ETH:
++                        NET_HEADER_FIELD_ETH_DA
++                        NET_HEADER_FIELD_ETH_SA
++                        NET_HEADER_FIELD_ETH_TYPE
++
++                    HEADER_TYPE_LLC_SNAP:
++                        NET_HEADER_FIELD_LLC_SNAP_TYPE
++
++                    HEADER_TYPE_VLAN:
++                        NET_HEADER_FIELD_VLAN_TCI
++                                (index may apply:
++                                 e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1,
++                                 e_FM_PCD_HDR_INDEX_LAST)
++
++                    HEADER_TYPE_MPLS:
++                        NET_HEADER_FIELD_MPLS_LABEL_STACK
++                                (index may apply:
++                                 e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1,
++                                 e_FM_PCD_HDR_INDEX_2,
++                                 e_FM_PCD_HDR_INDEX_LAST)
++
++                    HEADER_TYPE_IPv4:
++                        NET_HEADER_FIELD_IPv4_SRC_IP
++                        NET_HEADER_FIELD_IPv4_DST_IP
++                        NET_HEADER_FIELD_IPv4_PROTO
++                        NET_HEADER_FIELD_IPv4_TOS
++                                (index may apply:
++                                 e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1,
++                                 e_FM_PCD_HDR_INDEX_2/e_FM_PCD_HDR_INDEX_LAST)
++
++                    HEADER_TYPE_IPv6:
++                        NET_HEADER_FIELD_IPv6_SRC_IP
++                        NET_HEADER_FIELD_IPv6_DST_IP
++                        NET_HEADER_FIELD_IPv6_NEXT_HDR
++                        NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL | NET_HEADER_FIELD_IPv6_TC (must come together!)
++                                (index may apply:
++                                 e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1,
++                                 e_FM_PCD_HDR_INDEX_2/e_FM_PCD_HDR_INDEX_LAST)
++
++                                (Note that starting from DPAA 1-1, NET_HEADER_FIELD_IPv6_NEXT_HDR applies to
++                                 the last next header indication, meaning the next L4, which may be
++                                 present at the Ipv6 last extension. On earlier revisions this field
++                                 applies to the Next-Header field of the main IPv6 header)
++
++                    HEADER_TYPE_IP:
++                        NET_HEADER_FIELD_IP_PROTO
++                                (index may apply:
++                                 e_FM_PCD_HDR_INDEX_LAST)
++                        NET_HEADER_FIELD_IP_DSCP
++                                (index may apply:
++                                 e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1)
++                    HEADER_TYPE_GRE:
++                        NET_HEADER_FIELD_GRE_TYPE
++
++                    HEADER_TYPE_MINENCAP
++                        NET_HEADER_FIELD_MINENCAP_SRC_IP
++                        NET_HEADER_FIELD_MINENCAP_DST_IP
++                        NET_HEADER_FIELD_MINENCAP_TYPE
++
++                    HEADER_TYPE_TCP:
++                        NET_HEADER_FIELD_TCP_PORT_SRC
++                        NET_HEADER_FIELD_TCP_PORT_DST
++                        NET_HEADER_FIELD_TCP_FLAGS
++
++                    HEADER_TYPE_UDP:
++                        NET_HEADER_FIELD_UDP_PORT_SRC
++                        NET_HEADER_FIELD_UDP_PORT_DST
++
++                    HEADER_TYPE_UDP_LITE:
++                        NET_HEADER_FIELD_UDP_LITE_PORT_SRC
++                        NET_HEADER_FIELD_UDP_LITE_PORT_DST
++
++                    HEADER_TYPE_IPSEC_AH:
++                        NET_HEADER_FIELD_IPSEC_AH_SPI
++                        NET_HEADER_FIELD_IPSEC_AH_NH
++
++                    HEADER_TYPE_IPSEC_ESP:
++                        NET_HEADER_FIELD_IPSEC_ESP_SPI
++
++                    HEADER_TYPE_SCTP:
++                        NET_HEADER_FIELD_SCTP_PORT_SRC
++                        NET_HEADER_FIELD_SCTP_PORT_DST
++
++                    HEADER_TYPE_DCCP:
++                        NET_HEADER_FIELD_DCCP_PORT_SRC
++                        NET_HEADER_FIELD_DCCP_PORT_DST
++
++                    HEADER_TYPE_PPPoE:
++                        NET_HEADER_FIELD_PPPoE_PID
++                        NET_HEADER_FIELD_PPPoE_SID
++
++        *****************************************************************
++                Fields supported as "from fields":
++                    HEADER_TYPE_ETH (with or without validation):
++                        NET_HEADER_FIELD_ETH_TYPE
++
++                    HEADER_TYPE_VLAN (with or without validation):
++                        NET_HEADER_FIELD_VLAN_TCI
++                                (index may apply:
++                                 e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1,
++                                 e_FM_PCD_HDR_INDEX_LAST)
++
++                    HEADER_TYPE_IPv4 (without validation):
++                        NET_HEADER_FIELD_IPv4_PROTO
++                                (index may apply:
++                                 e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1,
++                                 e_FM_PCD_HDR_INDEX_2/e_FM_PCD_HDR_INDEX_LAST)
++
++                    HEADER_TYPE_IPv6 (without validation):
++                        NET_HEADER_FIELD_IPv6_NEXT_HDR
++                                (index may apply:
++                                 e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1,
++                                 e_FM_PCD_HDR_INDEX_2/e_FM_PCD_HDR_INDEX_LAST)
++
++*//***************************************************************************/
++typedef union t_FmPcdFields {
++    headerFieldEth_t            eth;            /**< Ethernet               */
++    headerFieldVlan_t           vlan;           /**< VLAN                   */
++    headerFieldLlcSnap_t        llcSnap;        /**< LLC SNAP               */
++    headerFieldPppoe_t          pppoe;          /**< PPPoE                  */
++    headerFieldMpls_t           mpls;           /**< MPLS                   */
++    headerFieldIp_t             ip;             /**< IP                     */
++    headerFieldIpv4_t           ipv4;           /**< IPv4                   */
++    headerFieldIpv6_t           ipv6;           /**< IPv6                   */
++    headerFieldUdp_t            udp;            /**< UDP                    */
++    headerFieldUdpLite_t        udpLite;        /**< UDP Lite               */
++    headerFieldTcp_t            tcp;            /**< TCP                    */
++    headerFieldSctp_t           sctp;           /**< SCTP                   */
++    headerFieldDccp_t           dccp;           /**< DCCP                   */
++    headerFieldGre_t            gre;            /**< GRE                    */
++    headerFieldMinencap_t       minencap;       /**< Minimal Encapsulation  */
++    headerFieldIpsecAh_t        ipsecAh;        /**< IPSec AH               */
++    headerFieldIpsecEsp_t       ipsecEsp;       /**< IPSec ESP              */
++    headerFieldUdpEncapEsp_t    udpEncapEsp;    /**< UDP Encapsulation ESP  */
++} t_FmPcdFields;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header extraction for key generation
++*//***************************************************************************/
++typedef struct t_FmPcdFromHdr {
++    uint8_t             size;           /**< Size in byte */
++    uint8_t             offset;         /**< Byte offset */
++} t_FmPcdFromHdr;
++
++/**************************************************************************//**
++ @Description   Parameters for defining field extraction for key generation
++*//***************************************************************************/
++typedef struct t_FmPcdFromField {
++    t_FmPcdFields       field;          /**< Field selection */
++    uint8_t             size;           /**< Size in byte */
++    uint8_t             offset;         /**< Byte offset */
++} t_FmPcdFromField;
++
++/**************************************************************************//**
++ @Description   Parameters for defining a single network environment unit
++
++                A distinction unit should be defined if it will later be used
++                by one or more PCD engines to distinguish between flows.
++*//***************************************************************************/
++typedef struct t_FmPcdDistinctionUnit {
++    struct {
++        e_NetHeaderType         hdr;        /**< One of the headers supported by the FM */
++        u_FmPcdHdrProtocolOpt   opt;        /**< Select only one option ! */
++    } hdrs[FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS];
++} t_FmPcdDistinctionUnit;
++
++/**************************************************************************//**
++ @Description   Parameters for defining all different distinction units supported
++                by a specific PCD Network Environment Characteristics module.
++
++                Each unit represent a protocol or a group of protocols that may
++                be used later by the different PCD engines to distinguish
++                between flows.
++*//***************************************************************************/
++typedef struct t_FmPcdNetEnvParams {
++    uint8_t                 numOfDistinctionUnits;                      /**< Number of different units to be identified */
++    t_FmPcdDistinctionUnit  units[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; /**< An array of numOfDistinctionUnits of the
++                                                                             different units to be identified */
++} t_FmPcdNetEnvParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining a single extraction action when
++                creating a key
++*//***************************************************************************/
++typedef struct t_FmPcdExtractEntry {
++    e_FmPcdExtractType                  type;           /**< Extraction type select */
++    union {
++        struct {
++            e_NetHeaderType             hdr;            /**< Header selection */
++            bool                        ignoreProtocolValidation;
++                                                        /**< Ignore protocol validation */
++            e_FmPcdHdrIndex             hdrIndex;       /**< Relevant only for MPLS, VLAN and tunneled
++                                                             IP. Otherwise should be cleared. */
++            e_FmPcdExtractByHdrType     type;           /**< Header extraction type select */
++            union {
++                t_FmPcdFromHdr          fromHdr;        /**< Extract bytes from header parameters */
++                t_FmPcdFromField        fromField;      /**< Extract bytes from field parameters */
++                t_FmPcdFields           fullField;      /**< Extract full filed parameters */
++            } extractByHdrType;
++        } extractByHdr;                                 /**< used when type = e_FM_PCD_KG_EXTRACT_BY_HDR */
++        struct {
++            e_FmPcdExtractFrom          src;            /**< Non-header extraction source */
++            e_FmPcdAction               action;         /**< Relevant for CC Only */
++            uint16_t                    icIndxMask;     /**< Relevant only for CC when
++                                                             action = e_FM_PCD_ACTION_INDEXED_LOOKUP;
++                                                             Note that the number of bits that are set within
++                                                             this mask must be log2 of the CC-node 'numOfKeys'.
++                                                             Note that the mask cannot be set on the lower bits. */
++            uint8_t                     offset;         /**< Byte offset */
++            uint8_t                     size;           /**< Size in byte */
++        } extractNonHdr;                                /**< used when type = e_FM_PCD_KG_EXTRACT_NON_HDR */
++    };
++} t_FmPcdExtractEntry;
++
++/**************************************************************************//**
++ @Description   Parameters for defining masks for each extracted field in the key.
++*//***************************************************************************/
++typedef struct t_FmPcdKgExtractMask {
++    uint8_t                             extractArrayIndex;  /**< Index in the extraction array, as initialized by user */
++    uint8_t                             offset;             /**< Byte offset */
++    uint8_t                             mask;               /**< A byte mask (selected bits will be used) */
++} t_FmPcdKgExtractMask;
++
++/**************************************************************************//**
++ @Description   Parameters for defining default selection per groups of fields
++*//***************************************************************************/
++typedef struct t_FmPcdKgExtractDflt {
++    e_FmPcdKgKnownFieldsDfltTypes       type;                /**< Default type select */
++    e_FmPcdKgExtractDfltSelect          dfltSelect;          /**< Default register select */
++} t_FmPcdKgExtractDflt;
++
++/**************************************************************************//**
++ @Description   Parameters for defining key extraction and hashing
++*//***************************************************************************/
++typedef struct t_FmPcdKgKeyExtractAndHashParams {
++    uint32_t                    privateDflt0;                /**< Scheme default register 0 */
++    uint32_t                    privateDflt1;                /**< Scheme default register 1 */
++    uint8_t                     numOfUsedExtracts;           /**< defines the valid size of the following array */
++    t_FmPcdExtractEntry         extractArray [FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY]; /**< An array of extractions definition. */
++    uint8_t                     numOfUsedDflts;              /**< defines the valid size of the following array */
++    t_FmPcdKgExtractDflt        dflts[FM_PCD_KG_NUM_OF_DEFAULT_GROUPS];
++                                                             /**< For each extraction used in this scheme, specify the required
++                                                                  default register to be used when header is not found.
++                                                                  types not specified in this array will get undefined value. */
++    uint8_t                     numOfUsedMasks;              /**< defines the valid size of the following array */
++    t_FmPcdKgExtractMask        masks[FM_PCD_KG_NUM_OF_EXTRACT_MASKS];
++    uint8_t                     hashShift;                   /**< hash result right shift. Select the 24 bits out of the 64 hash
++                                                                  result. 0 means using the 24 LSB's, otherwise use the
++                                                                  24 LSB's after shifting right.*/
++    uint32_t                    hashDistributionNumOfFqids;  /**< must be > 1 and a power of 2. Represents the range
++                                                                  of queues for the key and hash functionality */
++    uint8_t                     hashDistributionFqidsShift;  /**< selects the FQID bits that will be effected by the hash */
++    bool                        symmetricHash;               /**< TRUE to generate the same hash for frames with swapped source and
++                                                                  destination fields on all layers; If TRUE, driver will check that for
++                                                                  all layers, if SRC extraction is selected, DST extraction must also be
++                                                                  selected, and vice versa. */
++} t_FmPcdKgKeyExtractAndHashParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining a single FQID mask (extracted OR).
++*//***************************************************************************/
++typedef struct t_FmPcdKgExtractedOrParams {
++    e_FmPcdExtractType              type;               /**< Extraction type select */
++    union {
++        struct {                                        /**< used when type = e_FM_PCD_KG_EXTRACT_BY_HDR */
++            e_NetHeaderType         hdr;
++            e_FmPcdHdrIndex         hdrIndex;           /**< Relevant only for MPLS, VLAN and tunneled
++                                                             IP. Otherwise should be cleared.*/
++            bool                    ignoreProtocolValidation;
++                                                        /**< continue extraction even if protocol is not recognized */
++        } extractByHdr;                                 /**< Header to extract by */
++        e_FmPcdExtractFrom          src;                /**< used when type = e_FM_PCD_KG_EXTRACT_NON_HDR */
++    };
++    uint8_t                         extractionOffset;   /**< Offset for extraction (in bytes).  */
++    e_FmPcdKgExtractDfltSelect      dfltValue;          /**< Select register from which extraction is taken if
++                                                             field not found */
++    uint8_t                         mask;               /**< Extraction mask (specified bits are used) */
++    uint8_t                         bitOffsetInFqid;    /**< 0-31, Selects which bits of the 24 FQID bits to effect using
++                                                             the extracted byte; Assume byte is placed as the 8 MSB's in
++                                                             a 32 bit word where the lower bits
++                                                             are the FQID; i.e if bitOffsetInFqid=1 than its LSB
++                                                             will effect the FQID MSB, if bitOffsetInFqid=24 than the
++                                                             extracted byte will effect the 8 LSB's of the FQID,
++                                                             if bitOffsetInFqid=31 than the byte's MSB will effect
++                                                             the FQID's LSB; 0 means - no effect on FQID;
++                                                             Note that one, and only one of
++                                                             bitOffsetInFqid or bitOffsetInPlcrProfile must be set (i.e,
++                                                             extracted byte must effect either FQID or Policer profile).*/
++    uint8_t                         bitOffsetInPlcrProfile;
++                                                        /**< 0-15, Selects which bits of the 8 policer profile id bits to
++                                                             effect using the extracted byte; Assume byte is placed
++                                                             as the 8 MSB's in a 16 bit word where the lower bits
++                                                             are the policer profile id; i.e if bitOffsetInPlcrProfile=1
++                                                             than its LSB will effect the profile MSB, if bitOffsetInFqid=8
++                                                             than the extracted byte will effect the whole policer profile id,
++                                                             if bitOffsetInFqid=15 than the byte's MSB will effect
++                                                             the Policer Profile id's LSB;
++                                                             0 means - no effect on policer profile; Note that one, and only one of
++                                                             bitOffsetInFqid or bitOffsetInPlcrProfile must be set (i.e,
++                                                             extracted byte must effect either FQID or Policer profile).*/
++} t_FmPcdKgExtractedOrParams;
++
++/**************************************************************************//**
++ @Description   Parameters for configuring a scheme counter
++*//***************************************************************************/
++typedef struct t_FmPcdKgSchemeCounter {
++    bool        update;     /**< FALSE to keep the current counter state
++                                 and continue from that point, TRUE to update/reset
++                                 the counter when the scheme is written. */
++    uint32_t    value;      /**< If update=TRUE, this value will be written into the
++                                 counter. clear this field to reset the counter. */
++} t_FmPcdKgSchemeCounter;
++
++/**************************************************************************//**
++ @Description   Parameters for configuring a policer profile for a KeyGen scheme
++                (when policer is the next engine after this scheme).
++*//***************************************************************************/
++typedef struct t_FmPcdKgPlcrProfile {
++    bool                sharedProfile;              /**< TRUE if this profile is shared between ports
++                                                         (managed by master partition); Must not be TRUE
++                                                         if profile is after Coarse Classification*/
++    bool                direct;                     /**< if TRUE, directRelativeProfileId only selects the profile
++                                                         id, if FALSE fqidOffsetRelativeProfileIdBase is used
++                                                         together with fqidOffsetShift and numOfProfiles
++                                                         parameters, to define a range of profiles from
++                                                         which the KeyGen result will determine the
++                                                         destination policer profile.  */
++    union {
++        uint16_t        directRelativeProfileId;    /**< Used if 'direct' is TRUE, to select policer profile.
++                                                         should indicate the policer profile offset within the
++                                                         port's policer profiles or shared window. */
++        struct {
++            uint8_t     fqidOffsetShift;            /**< Shift on the KeyGen create FQID offset (i.e. not the
++                                                         final FQID - without the FQID base). */
++            uint8_t     fqidOffsetRelativeProfileIdBase;
++                                                    /**< The base of the FMan Port's relative Storage-Profile ID;
++                                                         this value will be "OR'ed" with the KeyGen create FQID
++                                                         offset (i.e. not the final FQID - without the FQID base);
++                                                         the final result should indicate the Storage-Profile offset
++                                                         within the FMan Port's relative Storage-Profiles window/
++                                                         (or the SHARED window depends on 'sharedProfile'). */
++            uint8_t     numOfProfiles;              /**< Range of profiles starting at base */
++        } indirectProfile;                          /**< Indirect profile parameters */
++    } profileSelect;                                /**< Direct/indirect profile selection and parameters */
++} t_FmPcdKgPlcrProfile;
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Description   Parameters for configuring a storage profile for a KeyGen scheme.
++*//***************************************************************************/
++typedef struct t_FmPcdKgStorageProfile {
++    bool                direct;                     /**< If TRUE, directRelativeProfileId only selects the
++                                                         profile id;
++                                                         If FALSE, fqidOffsetRelativeProfileIdBase is used
++                                                         together with fqidOffsetShift and numOfProfiles
++                                                         parameters to define a range of profiles from which
++                                                         the KeyGen result will determine the destination
++                                                         storage profile. */
++    union {
++        uint16_t        directRelativeProfileId;    /**< Used when 'direct' is TRUE, to select a storage profile;
++                                                         should indicate the storage profile offset within the
++                                                         port's storage profiles window. */
++        struct {
++            uint8_t     fqidOffsetShift;            /**< Shift on the KeyGen create FQID offset (i.e. not the
++                                                         final FQID - without the FQID base). */
++            uint8_t     fqidOffsetRelativeProfileIdBase;
++                                                    /**< The base of the FMan Port's relative Storage-Profile ID;
++                                                         this value will be "OR'ed" with the KeyGen create FQID
++                                                         offset (i.e. not the final FQID - without the FQID base);
++                                                         the final result should indicate the Storage-Profile offset
++                                                         within the FMan Port's relative Storage-Profiles window. */
++            uint8_t     numOfProfiles;              /**< Range of profiles starting at base. */
++        } indirectProfile;                          /**< Indirect profile parameters. */
++    } profileSelect;                                /**< Direct/indirect profile selection and parameters. */
++} t_FmPcdKgStorageProfile;
++#endif /* (DPAA_VERSION >= 11) */
++
++/**************************************************************************//**
++ @Description   Parameters for defining CC as the next engine after KeyGen
++*//***************************************************************************/
++typedef struct t_FmPcdKgCc {
++    t_Handle                h_CcTree;                       /**< A handle to a CC Tree */
++    uint8_t                 grpId;                          /**< CC group id within the CC tree */
++    bool                    plcrNext;                       /**< TRUE if after CC, in case of data frame,
++                                                                 policing is required. */
++    bool                    bypassPlcrProfileGeneration;    /**< TRUE to bypass KeyGen policer profile generation;
++                                                                 selected profile is the one set at port initialization. */
++    t_FmPcdKgPlcrProfile    plcrProfile;                    /**< Valid only if plcrNext = TRUE and
++                                                                 bypassPlcrProfileGeneration = FALSE */
++} t_FmPcdKgCc;
++
++/**************************************************************************//**
++ @Description   Parameters for defining initializing a KeyGen scheme
++*//***************************************************************************/
++typedef struct t_FmPcdKgSchemeParams {
++    bool                                modify;                 /**< TRUE to change an existing scheme */
++    union
++    {
++        uint8_t                         relativeSchemeId;       /**< if modify=FALSE:Partition relative scheme id */
++        t_Handle                        h_Scheme;               /**< if modify=TRUE: a handle of the existing scheme */
++    } id;
++    bool                                alwaysDirect;           /**< This scheme is reached only directly, i.e. no need
++                                                                     for match vector; KeyGen will ignore it when matching */
++    struct {                                                    /**< HL Relevant only if alwaysDirect = FALSE */
++        t_Handle                        h_NetEnv;               /**< A handle to the Network environment as returned
++                                                                     by FM_PCD_NetEnvCharacteristicsSet() */
++        uint8_t                         numOfDistinctionUnits;  /**< Number of NetEnv units listed in unitIds array */
++        uint8_t                         unitIds[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS];
++                                                                /**< Indexes as passed to SetNetEnvCharacteristics array*/
++    } netEnvParams;
++    bool                                useHash;                /**< use the KeyGen Hash functionality  */
++    t_FmPcdKgKeyExtractAndHashParams    keyExtractAndHashParams;
++                                                                /**< used only if useHash = TRUE */
++    bool                                bypassFqidGeneration;   /**< Normally - FALSE, TRUE to avoid FQID update in the IC;
++                                                                     In such a case FQID after KeyGen will be the default FQID
++                                                                     defined for the relevant port, or the FQID defined by CC
++                                                                     in cases where CC was the previous engine. */
++    uint32_t                            baseFqid;               /**< Base FQID; Relevant only if bypassFqidGeneration = FALSE;
++                                                                     If hash is used and an even distribution is expected
++                                                                     according to hashDistributionNumOfFqids, baseFqid must be aligned to
++                                                                     hashDistributionNumOfFqids. */
++    uint8_t                             numOfUsedExtractedOrs;  /**< Number of FQID masks listed in extractedOrs array */
++    t_FmPcdKgExtractedOrParams          extractedOrs[FM_PCD_KG_NUM_OF_GENERIC_REGS];
++                                                                /**< FM_PCD_KG_NUM_OF_GENERIC_REGS
++                                                                     registers are shared between qidMasks
++                                                                     functionality and some of the extraction
++                                                                     actions; Normally only some will be used
++                                                                     for qidMask. Driver will return error if
++                                                                     resource is full at initialization time. */
++
++#if (DPAA_VERSION >= 11)
++    bool                                overrideStorageProfile; /**< TRUE if KeyGen override previously decided storage profile */
++    t_FmPcdKgStorageProfile             storageProfile;         /**< Used when overrideStorageProfile TRUE */
++#endif /* (DPAA_VERSION >= 11) */
++
++    e_FmPcdEngine                       nextEngine;             /**< may be BMI, PLCR or CC */
++    union {                                                     /**< depends on nextEngine */
++        e_FmPcdDoneAction               doneAction;             /**< Used when next engine is BMI (done) */
++        t_FmPcdKgPlcrProfile            plcrProfile;            /**< Used when next engine is PLCR */
++        t_FmPcdKgCc                     cc;                     /**< Used when next engine is CC */
++    } kgNextEngineParams;
++    t_FmPcdKgSchemeCounter              schemeCounter;          /**< A structure of parameters for updating
++                                                                     the scheme counter */
++} t_FmPcdKgSchemeParams;
++
++/**************************************************************************//**
++ @Collection    Definitions for CC statistics
++*//***************************************************************************/
++#if (DPAA_VERSION >= 11)
++#define FM_PCD_CC_STATS_MAX_NUM_OF_FLR      10  /* Maximal supported number of frame length ranges */
++#define FM_PCD_CC_STATS_FLR_SIZE            2   /* Size in bytes of a frame length range limit */
++#endif /* (DPAA_VERSION >= 11) */
++#define FM_PCD_CC_STATS_COUNTER_SIZE        4   /* Size in bytes of a frame length range counter */
++/* @} */
++
++/**************************************************************************//**
++ @Description   Parameters for defining CC as the next engine after a CC node.
++*//***************************************************************************/
++typedef struct t_FmPcdCcNextCcParams {
++    t_Handle    h_CcNode;               /**< A handle of the next CC node */
++} t_FmPcdCcNextCcParams;
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Description   Parameters for defining Frame replicator as the next engine after a CC node.
++*//***************************************************************************/
++typedef struct t_FmPcdCcNextFrParams {
++    t_Handle    h_FrmReplic;               /**< A handle of the next frame replicator group */
++} t_FmPcdCcNextFrParams;
++#endif /* (DPAA_VERSION >= 11) */
++
++/**************************************************************************//**
++ @Description   Parameters for defining Policer as the next engine after a CC node.
++*//***************************************************************************/
++typedef struct t_FmPcdCcNextPlcrParams {
++    bool        overrideParams;         /**< TRUE if CC override previously decided parameters*/
++    bool        sharedProfile;          /**< Relevant only if overrideParams=TRUE:
++                                             TRUE if this profile is shared between ports */
++    uint16_t    newRelativeProfileId;   /**< Relevant only if overrideParams=TRUE:
++                                             (otherwise profile id is taken from KeyGen);
++                                             This parameter should indicate the policer
++                                             profile offset within the port's
++                                             policer profiles or from SHARED window.*/
++    uint32_t    newFqid;                /**< Relevant only if overrideParams=TRUE:
++                                             FQID for enqueuing the frame;
++                                             In earlier chips  if policer next engine is KEYGEN,
++                                             this parameter can be 0, because the KEYGEN
++                                             always decides the enqueue FQID.*/
++#if (DPAA_VERSION >= 11)
++    uint8_t     newRelativeStorageProfileId;
++                                        /**< Indicates the relative storage profile offset within
++                                             the port's storage profiles window;
++                                             Relevant only if the port was configured with VSP. */
++#endif /* (DPAA_VERSION >= 11) */
++} t_FmPcdCcNextPlcrParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining enqueue as the next action after a CC node.
++*//***************************************************************************/
++typedef struct t_FmPcdCcNextEnqueueParams {
++    e_FmPcdDoneAction    action;        /**< Action - when next engine is BMI (done) */
++    bool                 overrideFqid;  /**< TRUE if CC override previously decided fqid and vspid,
++                                             relevant if action = e_FM_PCD_ENQ_FRAME */
++    uint32_t             newFqid;       /**< Valid if overrideFqid=TRUE, FQID for enqueuing the frame
++                                             (otherwise FQID is taken from KeyGen),
++                                             relevant if action = e_FM_PCD_ENQ_FRAME */
++#if (DPAA_VERSION >= 11)
++    uint8_t              newRelativeStorageProfileId;
++                                        /**< Valid if overrideFqid=TRUE, Indicates the relative virtual
++                                             storage profile offset within the port's storage profiles
++                                             window; Relevant only if the port was configured with VSP. */
++#endif /* (DPAA_VERSION >= 11) */
++} t_FmPcdCcNextEnqueueParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining KeyGen as the next engine after a CC node.
++*//***************************************************************************/
++typedef struct t_FmPcdCcNextKgParams {
++    bool        overrideFqid;           /**< TRUE if CC override previously decided fqid and vspid,
++                                             Note - this parameters irrelevant for earlier chips */
++    uint32_t    newFqid;                /**< Valid if overrideFqid=TRUE, FQID for enqueuing the frame
++                                             (otherwise FQID is taken from KeyGen),
++                                             Note - this parameters irrelevant for earlier chips */
++#if (DPAA_VERSION >= 11)
++    uint8_t     newRelativeStorageProfileId;
++                                        /**< Valid if overrideFqid=TRUE, Indicates the relative virtual
++                                             storage profile offset within the port's storage profiles
++                                             window; Relevant only if the port was configured with VSP. */
++#endif /* (DPAA_VERSION >= 11) */
++
++    t_Handle    h_DirectScheme;         /**< Direct scheme handle to go to. */
++} t_FmPcdCcNextKgParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining the next engine after a CC node.
++*//***************************************************************************/
++typedef struct t_FmPcdCcNextEngineParams {
++    e_FmPcdEngine                       nextEngine;     /**< User has to initialize parameters
++                                                             according to nextEngine definition */
++    union {
++        t_FmPcdCcNextCcParams           ccParams;       /**< Parameters in case next engine is CC */
++        t_FmPcdCcNextPlcrParams         plcrParams;     /**< Parameters in case next engine is PLCR */
++        t_FmPcdCcNextEnqueueParams      enqueueParams;  /**< Parameters in case next engine is BMI */
++        t_FmPcdCcNextKgParams           kgParams;       /**< Parameters in case next engine is KG */
++#if (DPAA_VERSION >= 11)
++        t_FmPcdCcNextFrParams           frParams;       /**< Parameters in case next engine is FR */
++#endif /* (DPAA_VERSION >= 11) */
++    } params;                                           /**< union used for all the next-engine parameters options */
++
++    t_Handle                            h_Manip;        /**< Handle to Manipulation object.
++                                                             Relevant if next engine is of type result
++                                                             (e_FM_PCD_PLCR, e_FM_PCD_KG, e_FM_PCD_DONE) */
++
++    bool                                statisticsEn;   /**< If TRUE, statistics counters are incremented
++                                                             for each frame passing through this
++                                                             Coarse Classification entry. */
++} t_FmPcdCcNextEngineParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining a single CC key
++*//***************************************************************************/
++typedef struct t_FmPcdCcKeyParams {
++    uint8_t                     *p_Key;     /**< Relevant only if 'action' = e_FM_PCD_ACTION_EXACT_MATCH;
++                                                 pointer to the key of the size defined in keySize */
++    uint8_t                     *p_Mask;    /**< Relevant only if 'action' = e_FM_PCD_ACTION_EXACT_MATCH;
++                                                 pointer to the Mask per key  of the size defined
++                                                 in keySize. p_Key and p_Mask (if defined) has to be
++                                                 of the same size defined in the keySize;
++                                                 NOTE that if this value is equal for all entries whithin
++                                                 this table, the driver will automatically use global-mask
++                                                 (i.e. one common mask for all entries) instead of private
++                                                 one; that is done in order to spare some memory and for
++                                                 better performance. */
++    t_FmPcdCcNextEngineParams   ccNextEngineParams;
++                                            /**< parameters for the next for the defined Key in
++                                                 the p_Key */
++} t_FmPcdCcKeyParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining CC keys parameters
++                The driver supports two methods for CC node allocation: dynamic and static.
++                Static mode was created in order to prevent runtime alloc/free
++                of FMan memory (MURAM), which may cause fragmentation; in this mode,
++                the driver automatically allocates the memory according to
++                'maxNumOfKeys' parameter. The driver calculates the maximal memory
++                size that may be used for this CC-Node taking into consideration
++                'maskSupport' and 'statisticsMode' parameters.
++                When 'action' = e_FM_PCD_ACTION_INDEXED_LOOKUP in the extraction
++                parameters of this node, 'maxNumOfKeys' must be equal to 'numOfKeys'.
++                In dynamic mode, 'maxNumOfKeys' must be zero. At initialization,
++                all required structures are allocated according to 'numOfKeys'
++                parameter. During runtime modification, these structures are
++                re-allocated according to the updated number of keys.
++
++                Please note that 'action' and 'icIndxMask' mentioned in the
++                specific parameter explanations are passed in the extraction
++                parameters of the node (fields of extractCcParams.extractNonHdr).
++*//***************************************************************************/
++typedef struct t_KeysParams {
++    uint16_t                    maxNumOfKeys;   /**< Maximum number of keys that will (ever) be used in this CC-Node;
++                                                     A value of zero may be used for dynamic memory allocation. */
++    bool                        maskSupport;    /**< This parameter is relevant only if a node is initialized with
++                                                     'action' = e_FM_PCD_ACTION_EXACT_MATCH and maxNumOfKeys > 0;
++                                                     Should be TRUE to reserve table memory for key masks, even if
++                                                     initial keys do not contain masks, or if the node was initialized
++                                                     as 'empty' (without keys); this will allow user to add keys with
++                                                     masks at runtime.
++                                                     NOTE that if user want to use only global-masks (i.e. one common mask
++                                                     for all the entries within this table, this parameter should set to 'FALSE'. */
++    e_FmPcdCcStatsMode          statisticsMode; /**< Determines the supported statistics mode for all node's keys.
++                                                     To enable statistics gathering, statistics should be enabled per
++                                                     every key, using 'statisticsEn' in next engine parameters structure
++                                                     of that key;
++                                                     If 'maxNumOfKeys' is set, all required structures will be
++                                                     preallocated for all keys. */
++#if (DPAA_VERSION >= 11)
++    uint16_t                    frameLengthRanges[FM_PCD_CC_STATS_MAX_NUM_OF_FLR];
++                                                /**< Relevant only for 'RMON' statistics mode
++                                                     (this feature is supported only on B4860 device);
++                                                     Holds a list of programmable thresholds - for each received frame,
++                                                     its length in bytes is examined against these range thresholds and
++                                                     the appropriate counter is incremented by 1 - for example, to belong
++                                                     to range i, the following should hold:
++                                                     range i-1 threshold < frame length <= range i threshold
++                                                     Each range threshold must be larger then its preceding range
++                                                     threshold, and last range threshold must be 0xFFFF. */
++#endif /* (DPAA_VERSION >= 11) */
++    uint16_t                    numOfKeys;      /**< Number of initial keys;
++                                                     Note that in case of 'action' = e_FM_PCD_ACTION_INDEXED_LOOKUP,
++                                                     this field should be power-of-2 of the number of bits that are
++                                                     set in 'icIndxMask'. */
++    uint8_t                     keySize;        /**< Size of key - for extraction of type FULL_FIELD, 'keySize' has
++                                                     to be the standard size of the selected key; For other extraction
++                                                     types, 'keySize' has to be as size of extraction; When 'action' =
++                                                     e_FM_PCD_ACTION_INDEXED_LOOKUP, 'keySize' must be 2. */
++    t_FmPcdCcKeyParams          keyParams[FM_PCD_MAX_NUM_OF_KEYS];
++                                                /**< An array with 'numOfKeys' entries, each entry specifies the
++                                                     corresponding key parameters;
++                                                     When 'action' = e_FM_PCD_ACTION_EXACT_MATCH, this value must not
++                                                     exceed 255 (FM_PCD_MAX_NUM_OF_KEYS-1) as the last entry is saved
++                                                     for the 'miss' entry. */
++    t_FmPcdCcNextEngineParams   ccNextEngineParamsForMiss;
++                                                /**< Parameters for defining the next engine when a key is not matched;
++                                                     Not relevant if action = e_FM_PCD_ACTION_INDEXED_LOOKUP. */
++} t_KeysParams;
++
++
++/**************************************************************************//**
++ @Description   Parameters for defining a CC node
++*//***************************************************************************/
++typedef struct t_FmPcdCcNodeParams {
++    t_FmPcdExtractEntry         extractCcParams;    /**< Extraction parameters */
++    t_KeysParams                keysParams;         /**< Keys definition matching the selected extraction */
++} t_FmPcdCcNodeParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining a hash table
++*//***************************************************************************/
++typedef struct t_FmPcdHashTableParams {
++    uint16_t                    maxNumOfKeys;               /**< Maximum Number Of Keys that will (ever) be used in this Hash-table */
++    e_FmPcdCcStatsMode          statisticsMode;             /**< If not e_FM_PCD_CC_STATS_MODE_NONE, the required structures for the
++                                                                 requested statistics mode will be allocated according to maxNumOfKeys. */
++    uint8_t                     kgHashShift;                /**< KG-Hash-shift as it was configured in the KG-scheme
++                                                                 that leads to this hash-table. */
++    uint16_t                    hashResMask;                /**< Mask that will be used on the hash-result;
++                                                                 The number-of-sets for this hash will be calculated
++                                                                 as (2^(number of bits set in 'hashResMask'));
++                                                                 The 4 lower bits must be cleared. */
++    uint8_t                     hashShift;                  /**< Byte offset from the beginning of the KeyGen hash result to the
++                                                                 2-bytes to be used as hash index. */
++    uint8_t                     matchKeySize;               /**< Size of the exact match keys held by the hash buckets */
++
++    t_FmPcdCcNextEngineParams   ccNextEngineParamsForMiss;  /**< Parameters for defining the next engine when a key is not matched */
++
++} t_FmPcdHashTableParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining a CC tree group.
++
++                This structure defines a CC group in terms of NetEnv units
++                and the action to be taken in each case. The unitIds list must
++                be given in order from low to high indices.
++
++                t_FmPcdCcNextEngineParams is a list of 2^numOfDistinctionUnits
++                structures where each defines the next action to be taken for
++                each units combination. for example:
++                numOfDistinctionUnits = 2
++                unitIds = {1,3}
++                p_NextEnginePerEntriesInGrp[0] = t_FmPcdCcNextEngineParams for the case that
++                                                        unit 1 - not found; unit 3 - not found;
++                p_NextEnginePerEntriesInGrp[1] = t_FmPcdCcNextEngineParams for the case that
++                                                        unit 1 - not found; unit 3 - found;
++                p_NextEnginePerEntriesInGrp[2] = t_FmPcdCcNextEngineParams for the case that
++                                                        unit 1 - found; unit 3 - not found;
++                p_NextEnginePerEntriesInGrp[3] = t_FmPcdCcNextEngineParams for the case that
++                                                        unit 1 - found; unit 3 - found;
++*//***************************************************************************/
++typedef struct t_FmPcdCcGrpParams {
++    uint8_t                     numOfDistinctionUnits;          /**< Up to 4 */
++    uint8_t                     unitIds[FM_PCD_MAX_NUM_OF_CC_UNITS];
++                                                                /**< Indices of the units as defined in
++                                                                     FM_PCD_NetEnvCharacteristicsSet() */
++    t_FmPcdCcNextEngineParams   nextEnginePerEntriesInGrp[FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP];
++                                                                /**< Maximum entries per group is 16 */
++} t_FmPcdCcGrpParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining CC tree groups
++*//***************************************************************************/
++typedef struct t_FmPcdCcTreeParams {
++    t_Handle                h_NetEnv;                   /**< A handle to the Network environment as returned
++                                                             by FM_PCD_NetEnvCharacteristicsSet() */
++    uint8_t                 numOfGrps;                  /**< Number of CC groups within the CC tree */
++    t_FmPcdCcGrpParams      ccGrpParams[FM_PCD_MAX_NUM_OF_CC_GROUPS];
++                                                        /**< Parameters for each group. */
++} t_FmPcdCcTreeParams;
++
++
++/**************************************************************************//**
++ @Description   CC key statistics structure
++*//***************************************************************************/
++typedef struct t_FmPcdCcKeyStatistics {
++    uint32_t    byteCount;      /**< This counter reflects byte count of frames that
++                                     were matched by this key. */
++    uint32_t    frameCount;     /**< This counter reflects count of frames that
++                                     were matched by this key. */
++#if (DPAA_VERSION >= 11)
++    uint32_t    frameLengthRangeCount[FM_PCD_CC_STATS_MAX_NUM_OF_FLR];
++                                /**< These counters reflect how many frames matched
++                                     this key in 'RMON' statistics mode:
++                                     Each counter holds the number of frames of a
++                                     specific frames length range, according to the
++                                     ranges provided at initialization. */
++#endif /* (DPAA_VERSION >= 11) */
++} t_FmPcdCcKeyStatistics;
++
++/**************************************************************************//**
++ @Description   Parameters for defining policer byte rate
++*//***************************************************************************/
++typedef struct t_FmPcdPlcrByteRateModeParams {
++    e_FmPcdPlcrFrameLengthSelect    frameLengthSelection;   /**< Frame length selection */
++    e_FmPcdPlcrRollBackFrameSelect  rollBackFrameSelection; /**< relevant option only e_FM_PCD_PLCR_L2_FRM_LEN,
++                                                                 e_FM_PCD_PLCR_FULL_FRM_LEN */
++} t_FmPcdPlcrByteRateModeParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining the policer profile (based on
++                RFC-2698 or RFC-4115 attributes).
++*//***************************************************************************/
++typedef struct t_FmPcdPlcrNonPassthroughAlgParams {
++    e_FmPcdPlcrRateMode              rateMode;                       /**< Byte mode or Packet mode */
++    t_FmPcdPlcrByteRateModeParams    byteModeParams;                 /**< Valid for Byte NULL for Packet */
++    uint32_t                         committedInfoRate;              /**< KBits/Second or Packets/Second */
++    uint32_t                         committedBurstSize;             /**< Bytes/Packets */
++    uint32_t                         peakOrExcessInfoRate;           /**< KBits/Second or Packets/Second */
++    uint32_t                         peakOrExcessBurstSize;          /**< Bytes/Packets */
++} t_FmPcdPlcrNonPassthroughAlgParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining the next engine after policer
++*//***************************************************************************/
++typedef union u_FmPcdPlcrNextEngineParams {
++    e_FmPcdDoneAction               action;             /**< Action - when next engine is BMI (done) */
++    t_Handle                        h_Profile;          /**< Policer profile handle -  used when next engine
++                                                             is Policer, must be a SHARED profile */
++    t_Handle                        h_DirectScheme;     /**< Direct scheme select - when next engine is KeyGen */
++} u_FmPcdPlcrNextEngineParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining the policer profile entry
++*//***************************************************************************/
++typedef struct t_FmPcdPlcrProfileParams {
++    bool                                modify;                     /**< TRUE to change an existing profile */
++    union {
++        struct {
++            e_FmPcdProfileTypeSelection profileType;                /**< Type of policer profile */
++            t_Handle                    h_FmPort;                   /**< Relevant for per-port profiles only */
++            uint16_t                    relativeProfileId;          /**< Profile id - relative to shared group or to port */
++        } newParams;                                                /**< use it when modify = FALSE */
++        t_Handle                        h_Profile;                  /**< A handle to a profile - use it when modify=TRUE */
++    } id;
++    e_FmPcdPlcrAlgorithmSelection       algSelection;               /**< Profile Algorithm PASS_THROUGH, RFC_2698, RFC_4115 */
++    e_FmPcdPlcrColorMode                colorMode;                  /**< COLOR_BLIND, COLOR_AWARE */
++
++    union {
++        e_FmPcdPlcrColor                dfltColor;                  /**< For Color-Blind Pass-Through mode; the policer will re-color
++                                                                         any incoming packet with the default value. */
++        e_FmPcdPlcrColor                override;                   /**< For Color-Aware modes; the profile response to a
++                                                                         pre-color value of 2'b11. */
++    } color;
++
++    t_FmPcdPlcrNonPassthroughAlgParams  nonPassthroughAlgParams;    /**< RFC2698 or RFC4115 parameters */
++
++    e_FmPcdEngine                       nextEngineOnGreen;          /**< Next engine for green-colored frames */
++    u_FmPcdPlcrNextEngineParams         paramsOnGreen;              /**< Next engine parameters for green-colored frames  */
++
++    e_FmPcdEngine                       nextEngineOnYellow;         /**< Next engine for yellow-colored frames */
++    u_FmPcdPlcrNextEngineParams         paramsOnYellow;             /**< Next engine parameters for yellow-colored frames  */
++
++    e_FmPcdEngine                       nextEngineOnRed;            /**< Next engine for red-colored frames */
++    u_FmPcdPlcrNextEngineParams         paramsOnRed;                /**< Next engine parameters for red-colored frames  */
++
++    bool                                trapProfileOnFlowA;         /**< Obsolete - do not use */
++    bool                                trapProfileOnFlowB;         /**< Obsolete - do not use */
++    bool                                trapProfileOnFlowC;         /**< Obsolete - do not use */
++} t_FmPcdPlcrProfileParams;
++
++/**************************************************************************//**
++ @Description   Parameters for selecting a location for requested manipulation
++*//***************************************************************************/
++typedef struct t_FmManipHdrInfo {
++    e_NetHeaderType                     hdr;            /**< Header selection */
++    e_FmPcdHdrIndex                     hdrIndex;       /**< Relevant only for MPLS, VLAN and tunneled IP. Otherwise should be cleared. */
++    bool                                byField;        /**< TRUE if the location of manipulation is according to some field in the specific header*/
++    t_FmPcdFields                       fullField;      /**< Relevant only when byField = TRUE: Extract field */
++} t_FmManipHdrInfo;
++
++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++/**************************************************************************//**
++ @Description   Parameters for defining an insertion manipulation
++                of type e_FM_PCD_MANIP_INSRT_TO_START_OF_FRAME_TEMPLATE
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrInsrtByTemplateParams {
++    uint8_t         size;                               /**< Size of insert template to the start of the frame. */
++    uint8_t         hdrTemplate[FM_PCD_MAX_MANIP_INSRT_TEMPLATE_SIZE];
++                                                        /**< Array of the insertion template. */
++
++    bool            modifyOuterIp;                      /**< TRUE if user want to modify some fields in outer IP. */
++    struct {
++        uint16_t    ipOuterOffset;                      /**< Offset of outer IP in the insert template, relevant if modifyOuterIp = TRUE.*/
++        uint16_t    dscpEcn;                            /**< value of dscpEcn in IP outer, relevant if modifyOuterIp = TRUE.
++                                                             in IPV4 dscpEcn only byte - it has to be adjusted to the right*/
++        bool        udpPresent;                         /**< TRUE if UDP is present in the insert template, relevant if modifyOuterIp = TRUE.*/
++        uint8_t     udpOffset;                          /**< Offset in the insert template of UDP, relevant if modifyOuterIp = TRUE and udpPresent=TRUE.*/
++        uint8_t     ipIdentGenId;                       /**< Used by FMan-CTRL to calculate IP-identification field,relevant if modifyOuterIp = TRUE.*/
++        bool        recalculateLength;                  /**< TRUE if recalculate length has to be performed due to the engines in the path which can change the frame later, relevant if modifyOuterIp = TRUE.*/
++        struct {
++            uint8_t blockSize;                          /**< The CAAM block-size; Used by FMan-CTRL to calculate the IP Total Length field.*/
++            uint8_t extraBytesAddedAlignedToBlockSize;  /**< Used by FMan-CTRL to calculate the IP Total Length field and UDP length*/
++            uint8_t extraBytesAddedNotAlignedToBlockSize;/**< Used by FMan-CTRL to calculate the IP Total Length field and UDP length.*/
++        } recalculateLengthParams;                      /**< Recalculate length parameters - relevant if modifyOuterIp = TRUE and recalculateLength = TRUE */
++    } modifyOuterIpParams;                              /**< Outer IP modification parameters - ignored if modifyOuterIp is FALSE */
++
++    bool            modifyOuterVlan;                    /**< TRUE if user wants to modify VPri field in the outer VLAN header*/
++    struct {
++        uint8_t     vpri;                               /**< Value of VPri, relevant if modifyOuterVlan = TRUE
++                                                             VPri only 3 bits, it has to be adjusted to the right*/
++    } modifyOuterVlanParams;
++} t_FmPcdManipHdrInsrtByTemplateParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining CAPWAP fragmentation
++*//***************************************************************************/
++typedef struct t_CapwapFragmentationParams {
++    uint16_t         sizeForFragmentation;              /**< if length of the frame is greater than this value, CAPWAP fragmentation will be executed.*/
++    bool             headerOptionsCompr;                /**< TRUE - first fragment include the CAPWAP header options field,
++                                                             and all other fragments exclude the CAPWAP options field,
++                                                             FALSE - all fragments include CAPWAP header options field. */
++} t_CapwapFragmentationParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining CAPWAP reassembly
++*//***************************************************************************/
++typedef struct t_CapwapReassemblyParams {
++    uint16_t                        maxNumFramesInProcess;  /**< Number of frames which can be reassembled concurrently; must be power of 2.
++                                                                 In case numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH,
++                                                                 maxNumFramesInProcess has to be in the range of 4 - 512,
++                                                                 In case numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH,
++                                                                 maxNumFramesInProcess has to be in the range of 8 - 2048 */
++    bool                            haltOnDuplicationFrag;  /**< If TRUE, reassembly process will be halted due to duplicated fragment,
++                                                                 and all processed fragments will be enqueued with error indication;
++                                                                 If FALSE, only duplicated fragments will be enqueued with error indication. */
++
++    e_FmPcdManipReassemTimeOutMode  timeOutMode;            /**< Expiration delay initialized by the reassembly process */
++    uint32_t                        fqidForTimeOutFrames;   /**< FQID in which time out frames will enqueue during Time Out Process  */
++    uint32_t                        timeoutRoutineRequestTime;
++                                                            /**< Represents the time interval in microseconds between consecutive
++                                                                 timeout routine requests It has to be power of 2. */
++    uint32_t                        timeoutThresholdForReassmProcess;
++                                                            /**< Time interval (microseconds) for marking frames in process as too old;
++                                                                 Frames in process are those for which at least one fragment was received
++                                                                 but not all fragments. */
++
++    e_FmPcdManipReassemWaysNumber   numOfFramesPerHashEntry;/**< Number of frames per hash entry (needed for the reassembly process) */
++} t_CapwapReassemblyParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining fragmentation/reassembly manipulation
++*//***************************************************************************/
++typedef struct t_FmPcdManipFragOrReasmParams {
++    bool                                frag;               /**< TRUE if using the structure for fragmentation,
++                                                                 otherwise this structure is used for reassembly */
++    uint8_t                             sgBpid;             /**< Scatter/Gather buffer pool id;
++                                                                 Same LIODN number is used for these buffers as for
++                                                                 the received frames buffers, so buffers of this pool
++                                                                 need to be allocated in the same memory area as the
++                                                                 received buffers. If the received buffers arrive
++                                                                 from different sources, the Scatter/Gather BP id
++                                                                 should be mutual to all these sources. */
++    e_NetHeaderType                     hdr;                /**< Header selection */
++    union {
++        t_CapwapFragmentationParams     capwapFragParams;   /**< Structure for CAPWAP fragmentation,
++                                                                 relevant if 'frag' = TRUE, 'hdr' = HEADER_TYPE_CAPWAP */
++        t_CapwapReassemblyParams        capwapReasmParams;  /**< Structure for CAPWAP reassembly,
++                                                                 relevant if 'frag' = FALSE, 'hdr' = HEADER_TYPE_CAPWAP */
++    } u;
++} t_FmPcdManipFragOrReasmParams;
++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
++
++
++/**************************************************************************//**
++ @Description   Parameters for defining header removal by header type
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrRmvByHdrParams {
++    e_FmPcdManipHdrRmvByHdrType         type;           /**< Selection of header removal location */
++    union {
++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++        struct {
++            bool                        include;        /**< If FALSE, remove until the specified header (not including the header);
++                                                             If TRUE, remove also the specified header. */
++            t_FmManipHdrInfo            hdrInfo;
++        } fromStartByHdr;                               /**< Relevant when type = e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START */
++#endif /* (DPAA_VERSION >= 11) || ... */
++#if (DPAA_VERSION >= 11)
++        t_FmManipHdrInfo                hdrInfo;        /**< Relevant when type = e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START */
++#endif /* (DPAA_VERSION >= 11) */
++        e_FmPcdManipHdrRmvSpecificL2    specificL2;     /**< Relevant when type = e_FM_PCD_MANIP_BY_HDR_SPECIFIC_L2;
++                                                             Defines which L2 headers to remove. */
++    } u;
++} t_FmPcdManipHdrRmvByHdrParams;
++
++/**************************************************************************//**
++ @Description   Parameters for configuring IP fragmentation manipulation
++
++ Restrictions:
++     - IP Fragmentation output fragments must not be forwarded to application directly.
++     - Maximum number of fragments per frame is 16.
++     - Fragmentation of IP fragments is not supported.
++     - IPv4 packets containing header Option fields are fragmented by copying all option
++       fields to each fragment, regardless of the copy bit value.
++     - Transmit confirmation is not supported.
++     - Fragmentation after SEC can't handle S/G frames.
++     - Fragmentation nodes must be set as the last PCD action (i.e. the
++       corresponding CC node key must have next engine set to e_FM_PCD_DONE).
++     - Only BMan buffers shall be used for frames to be fragmented.
++     - IPF does not support VSP. Therefore, on the same port where we have IPF
++       we cannot support VSP.
++     - NOTE: The following comment is relevant only for FMAN v3 devices: IPF
++       does not support VSP. Therefore, on the same port where we have IPF we
++       cannot support VSP.
++*//***************************************************************************/
++typedef struct t_FmPcdManipFragIpParams {
++    uint16_t                    sizeForFragmentation;   /**< If length of the frame is greater than this value,
++                                                             IP fragmentation will be executed.*/
++#if (DPAA_VERSION == 10)
++    uint8_t                     scratchBpid;            /**< Absolute buffer pool id according to BM configuration.*/
++#endif /* (DPAA_VERSION == 10) */
++    bool                        sgBpidEn;               /**< Enable a dedicated buffer pool id for the Scatter/Gather buffer allocation;
++                                                             If disabled, the Scatter/Gather buffer will be allocated from the same pool as the
++                                                             received frame's buffer. */
++    uint8_t                     sgBpid;                 /**< Scatter/Gather buffer pool id;
++                                                             This parameters is relevant when 'sgBpidEn=TRUE';
++                                                             Same LIODN number is used for these buffers as for the received frames buffers, so buffers
++                                                             of this pool need to be allocated in the same memory area as the received buffers.
++                                                             If the received buffers arrive from different sources, the Scatter/Gather BP id should be
++                                                             mutual to all these sources. */
++    e_FmPcdManipDontFragAction  dontFragAction;         /**< Don't Fragment Action - If an IP packet is larger
++                                                             than MTU and its DF bit is set, then this field will
++                                                             determine the action to be taken.*/
++} t_FmPcdManipFragIpParams;
++
++/**************************************************************************//**
++ @Description   Parameters for configuring IP reassembly manipulation.
++
++                This is a common structure for both IPv4 and IPv6 reassembly
++                manipulation. For reassembly of both IPv4 and IPv6, make sure to
++                set the 'hdr' field in t_FmPcdManipReassemParams to HEADER_TYPE_IPv6.
++
++ Restrictions:
++    - Application must define at least one scheme to catch the reassembled frames.
++    - Maximum number of fragments per frame is 16.
++    - Reassembly of IPv4 fragments containing Option fields is supported.
++
++*//***************************************************************************/
++typedef struct t_FmPcdManipReassemIpParams {
++    uint8_t                         relativeSchemeId[2];    /**< Partition relative scheme id:
++                                                                 relativeSchemeId[0] -  Relative scheme ID for IPV4 Reassembly manipulation;
++                                                                 relativeSchemeId[1] -  Relative scheme ID for IPV6 Reassembly manipulation;
++                                                                 NOTE: The following comment is relevant only for FMAN v2 devices:
++                                                                 Relative scheme ID for IPv4/IPv6 Reassembly manipulation must be smaller than
++                                                                 the user schemes id to ensure that the reassembly schemes will be first match;
++                                                                 Rest schemes, if defined, should have higher relative scheme ID. */
++#if (DPAA_VERSION >= 11)
++    uint32_t                        nonConsistentSpFqid;    /**< In case that other fragments of the frame corresponds to different storage
++                                                                 profile than the opening fragment (Non-Consistent-SP state)
++                                                                 then one of two possible scenarios occurs:
++                                                                 if 'nonConsistentSpFqid != 0', the reassembled frame will be enqueued to
++                                                                 this fqid, otherwise a 'Non Consistent SP' bit will be set in the FD[status].*/
++#else
++    uint8_t                         sgBpid;                 /**< Buffer pool id for the S/G frame created by the reassembly process */
++#endif /* (DPAA_VERSION >= 11) */
++    uint8_t                         dataMemId;              /**< Memory partition ID for the IPR's external tables structure */
++    uint16_t                        dataLiodnOffset;        /**< LIODN offset for access the IPR's external tables structure. */
++    uint16_t                        minFragSize[2];         /**< Minimum fragment size:
++                                                                 minFragSize[0] - for ipv4, minFragSize[1] - for ipv6 */
++    e_FmPcdManipReassemWaysNumber   numOfFramesPerHashEntry[2];
++                                                            /**< Number of frames per hash entry needed for reassembly process:
++                                                                 numOfFramesPerHashEntry[0] - for ipv4 (max value is e_FM_PCD_MANIP_EIGHT_WAYS_HASH);
++                                                                 numOfFramesPerHashEntry[1] - for ipv6 (max value is e_FM_PCD_MANIP_SIX_WAYS_HASH). */
++    uint16_t                        maxNumFramesInProcess;  /**< Number of frames which can be processed by Reassembly in the same time;
++                                                                 Must be power of 2;
++                                                                 In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH,
++                                                                 maxNumFramesInProcess has to be in the range of 4 - 512;
++                                                                 In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH,
++                                                                 maxNumFramesInProcess has to be in the range of 8 - 2048. */
++    e_FmPcdManipReassemTimeOutMode  timeOutMode;            /**< Expiration delay initialized by Reassembly process */
++    uint32_t                        fqidForTimeOutFrames;   /**< FQID in which time out frames will enqueue during Time Out Process;
++                                                                 Recommended value for this field is 0; in this way timed-out frames will be discarded */
++    uint32_t                        timeoutThresholdForReassmProcess;
++                                                            /**< Represents the time interval in microseconds which defines
++                                                                 if opened frame (at least one fragment was processed but not all the fragments)is found as too old*/
++} t_FmPcdManipReassemIpParams;
++
++/**************************************************************************//**
++ @Description   structure for defining IPSEC manipulation
++*//***************************************************************************/
++typedef struct t_FmPcdManipSpecialOffloadIPSecParams {
++    bool        decryption;                     /**< TRUE if being used in decryption direction;
++                                                     FALSE if being used in encryption direction. */
++    bool        ecnCopy;                        /**< TRUE to copy the ECN bits from inner/outer to outer/inner
++                                                     (direction depends on the 'decryption' field). */
++    bool        dscpCopy;                       /**< TRUE to copy the DSCP bits from inner/outer to outer/inner
++                                                     (direction depends on the 'decryption' field). */
++    bool        variableIpHdrLen;               /**< TRUE for supporting variable IP header length in decryption. */
++    bool        variableIpVersion;              /**< TRUE for supporting both IP version on the same SA in encryption */
++    uint8_t     outerIPHdrLen;                  /**< if 'variableIpVersion == TRUE' then this field must be set to non-zero value;
++                                                     It is specifies the length of the outer IP header that was configured in the
++                                                     corresponding SA. */
++    uint16_t    arwSize;                        /**< if <> '0' then will perform ARW check for this SA;
++                                                     The value must be a multiplication of 16 */
++    uintptr_t   arwAddr;                        /**< if arwSize <> '0' then this field must be set to non-zero value;
++                                                     MUST be allocated from FMAN's MURAM that the post-sec op-port belongs to;
++                                                     Must be 4B aligned. Required MURAM size is 'NEXT_POWER_OF_2(arwSize+32))/8+4' Bytes */
++} t_FmPcdManipSpecialOffloadIPSecParams;
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Description   Parameters for configuring CAPWAP fragmentation manipulation
++
++ Restrictions:
++     - Maximum number of fragments per frame is 16.
++     - Transmit confirmation is not supported.
++     - Fragmentation nodes must be set as the last PCD action (i.e. the
++       corresponding CC node key must have next engine set to e_FM_PCD_DONE).
++     - Only BMan buffers shall be used for frames to be fragmented.
++     - NOTE: The following comment is relevant only for FMAN v3 devices: IPF
++       does not support VSP. Therefore, on the same port where we have IPF we
++       cannot support VSP.
++*//***************************************************************************/
++typedef struct t_FmPcdManipFragCapwapParams {
++    uint16_t                    sizeForFragmentation;   /**< If length of the frame is greater than this value,
++                                                             CAPWAP fragmentation will be executed.*/
++    bool                        sgBpidEn;               /**< Enable a dedicated buffer pool id for the Scatter/Gather buffer allocation;
++                                                             If disabled, the Scatter/Gather buffer will be allocated from the same pool as the
++                                                             received frame's buffer. */
++    uint8_t                     sgBpid;                 /**< Scatter/Gather buffer pool id;
++                                                             This parameters is relevant when 'sgBpidEn=TRUE';
++                                                             Same LIODN number is used for these buffers as for the received frames buffers, so buffers
++                                                             of this pool need to be allocated in the same memory area as the received buffers.
++                                                             If the received buffers arrive from different sources, the Scatter/Gather BP id should be
++                                                             mutual to all these sources. */
++    bool                        compressModeEn;         /**< CAPWAP Header Options Compress Enable mode;
++                                                             When this mode is enabled then only the first fragment include the CAPWAP header options
++                                                             field (if user provides it in the input frame) and all other fragments exclude the CAPWAP
++                                                             options field (CAPWAP header is updated accordingly).*/
++} t_FmPcdManipFragCapwapParams;
++
++/**************************************************************************//**
++ @Description   Parameters for configuring CAPWAP reassembly manipulation.
++
++ Restrictions:
++    - Application must define one scheme to catch the reassembled frames.
++    - Maximum number of fragments per frame is 16.
++
++*//***************************************************************************/
++typedef struct t_FmPcdManipReassemCapwapParams {
++    uint8_t                         relativeSchemeId;    /**< Partition relative scheme id;
++                                                                 NOTE: this id must be smaller than the user schemes id to ensure that the reassembly scheme will be first match;
++                                                                 Rest schemes, if defined, should have higher relative scheme ID. */
++    uint8_t                         dataMemId;              /**< Memory partition ID for the IPR's external tables structure */
++    uint16_t                        dataLiodnOffset;        /**< LIODN offset for access the IPR's external tables structure. */
++    uint16_t                        maxReassembledFrameLength;/**< The maximum CAPWAP reassembled frame length in bytes;
++                                                                   If maxReassembledFrameLength == 0, any successful reassembled frame length is
++                                                                   considered as a valid length;
++                                                                   if maxReassembledFrameLength > 0, a successful reassembled frame which its length
++                                                                   exceeds this value is considered as an error frame (FD status[CRE] bit is set). */
++    e_FmPcdManipReassemWaysNumber   numOfFramesPerHashEntry;
++                                                            /**< Number of frames per hash entry needed for reassembly process */
++    uint16_t                        maxNumFramesInProcess;  /**< Number of frames which can be processed by reassembly in the same time;
++                                                                 Must be power of 2;
++                                                                 In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH,
++                                                                 maxNumFramesInProcess has to be in the range of 4 - 512;
++                                                                 In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH,
++                                                                 maxNumFramesInProcess has to be in the range of 8 - 2048. */
++    e_FmPcdManipReassemTimeOutMode  timeOutMode;            /**< Expiration delay initialized by Reassembly process */
++    uint32_t                        fqidForTimeOutFrames;   /**< FQID in which time out frames will enqueue during Time Out Process;
++                                                                 Recommended value for this field is 0; in this way timed-out frames will be discarded */
++    uint32_t                        timeoutThresholdForReassmProcess;
++                                                            /**< Represents the time interval in microseconds which defines
++                                                                 if opened frame (at least one fragment was processed but not all the fragments)is found as too old*/
++} t_FmPcdManipReassemCapwapParams;
++
++/**************************************************************************//**
++ @Description   structure for defining CAPWAP manipulation
++*//***************************************************************************/
++typedef struct t_FmPcdManipSpecialOffloadCapwapParams {
++    bool                    dtls;   /**< TRUE if continue to SEC DTLS encryption */
++    e_FmPcdManipHdrQosSrc   qosSrc; /**< TODO */
++} t_FmPcdManipSpecialOffloadCapwapParams;
++
++#endif /* (DPAA_VERSION >= 11) */
++
++
++/**************************************************************************//**
++ @Description   Parameters for defining special offload manipulation
++*//***************************************************************************/
++typedef struct t_FmPcdManipSpecialOffloadParams {
++    e_FmPcdManipSpecialOffloadType              type;       /**< Type of special offload manipulation */
++    union
++    {
++        t_FmPcdManipSpecialOffloadIPSecParams   ipsec;      /**< Parameters for IPSec; Relevant when
++                                                                 type = e_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC */
++#if (DPAA_VERSION >= 11)
++        t_FmPcdManipSpecialOffloadCapwapParams  capwap;     /**< Parameters for CAPWAP; Relevant when
++                                                                 type = e_FM_PCD_MANIP_SPECIAL_OFFLOAD_CAPWAP */
++#endif /* (DPAA_VERSION >= 11) */
++    } u;
++} t_FmPcdManipSpecialOffloadParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining insertion manipulation
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrInsrt {
++    uint8_t size;           /**< size of inserted section */
++    uint8_t *p_Data;        /**< data to be inserted */
++} t_FmPcdManipHdrInsrt;
++
++
++/**************************************************************************//**
++ @Description   Parameters for defining generic removal manipulation
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrRmvGenericParams {
++    uint8_t                         offset;         /**< Offset from beginning of header to the start
++                                                         location of the removal */
++    uint8_t                         size;           /**< Size of removed section */
++} t_FmPcdManipHdrRmvGenericParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining generic insertion manipulation
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrInsrtGenericParams {
++    uint8_t                         offset;         /**< Offset from beginning of header to the start
++                                                         location of the insertion */
++    uint8_t                         size;           /**< Size of inserted section */
++    bool                            replace;        /**< TRUE to override (replace) existing data at
++                                                         'offset', FALSE to insert */
++    uint8_t                         *p_Data;        /**< Pointer to data to be inserted */
++} t_FmPcdManipHdrInsrtGenericParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header manipulation VLAN DSCP To Vpri translation
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrFieldUpdateVlanDscpToVpri {
++    uint8_t                         dscpToVpriTable[FM_PCD_MANIP_DSCP_TO_VLAN_TRANS];
++                                                        /**< A table of VPri values for each DSCP value;
++                                                             The index is the DSCP value (0-0x3F) and the
++                                                             value is the corresponding VPRI (0-15). */
++    uint8_t                         vpriDefVal;         /**< 0-7, Relevant only if if updateType =
++                                                             e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN,
++                                                             this field is the Q Tag default value if the
++                                                             IP header is not found. */
++} t_FmPcdManipHdrFieldUpdateVlanDscpToVpri;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header manipulation VLAN fields updates
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrFieldUpdateVlan {
++    e_FmPcdManipHdrFieldUpdateVlan                  updateType; /**< Selects VLAN update type */
++    union {
++        uint8_t                                     vpri;       /**< 0-7, Relevant only if If updateType =
++                                                                     e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_PRI, this
++                                                                     is the new VLAN pri. */
++        t_FmPcdManipHdrFieldUpdateVlanDscpToVpri    dscpToVpri; /**< Parameters structure, Relevant only if updateType
++                                                                     = e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN. */
++    } u;
++} t_FmPcdManipHdrFieldUpdateVlan;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header manipulation IPV4 fields updates
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrFieldUpdateIpv4 {
++    ipv4HdrManipUpdateFlags_t       validUpdates;       /**< ORed flag, selecting the required updates */
++    uint8_t                         tos;                /**< 8 bit New TOS; Relevant if validUpdates contains
++                                                             HDR_MANIP_IPV4_TOS */
++    uint16_t                        id;                 /**< 16 bit New IP ID; Relevant only if validUpdates
++                                                             contains HDR_MANIP_IPV4_ID */
++    uint32_t                        src;                /**< 32 bit New IP SRC; Relevant only if validUpdates
++                                                             contains HDR_MANIP_IPV4_SRC */
++    uint32_t                        dst;                /**< 32 bit New IP DST; Relevant only if validUpdates
++                                                             contains HDR_MANIP_IPV4_DST */
++} t_FmPcdManipHdrFieldUpdateIpv4;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header manipulation IPV6 fields updates
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrFieldUpdateIpv6 {
++    ipv6HdrManipUpdateFlags_t   validUpdates;           /**< ORed flag, selecting the required updates */
++    uint8_t                     trafficClass;           /**< 8 bit New Traffic Class; Relevant if validUpdates contains
++                                                             HDR_MANIP_IPV6_TC */
++    uint8_t                     src[NET_HEADER_FIELD_IPv6_ADDR_SIZE];
++                                                        /**< 16 byte new IP SRC; Relevant only if validUpdates
++                                                             contains HDR_MANIP_IPV6_SRC */
++    uint8_t                     dst[NET_HEADER_FIELD_IPv6_ADDR_SIZE];
++                                                        /**< 16 byte new IP DST; Relevant only if validUpdates
++                                                             contains HDR_MANIP_IPV6_DST */
++} t_FmPcdManipHdrFieldUpdateIpv6;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header manipulation TCP/UDP fields updates
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrFieldUpdateTcpUdp {
++    tcpUdpHdrManipUpdateFlags_t     validUpdates;       /**< ORed flag, selecting the required updates */
++    uint16_t                        src;                /**< 16 bit New TCP/UDP SRC; Relevant only if validUpdates
++                                                             contains HDR_MANIP_TCP_UDP_SRC */
++    uint16_t                        dst;                /**< 16 bit New TCP/UDP DST; Relevant only if validUpdates
++                                                             contains HDR_MANIP_TCP_UDP_DST */
++} t_FmPcdManipHdrFieldUpdateTcpUdp;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header manipulation fields updates
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrFieldUpdateParams {
++    e_FmPcdManipHdrFieldUpdateType                  type;           /**< Type of header field update manipulation */
++    union {
++        t_FmPcdManipHdrFieldUpdateVlan              vlan;           /**< Parameters for VLAN update. Relevant when
++                                                                         type = e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN */
++        t_FmPcdManipHdrFieldUpdateIpv4              ipv4;           /**< Parameters for IPv4 update. Relevant when
++                                                                         type = e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4 */
++        t_FmPcdManipHdrFieldUpdateIpv6              ipv6;           /**< Parameters for IPv6 update. Relevant when
++                                                                         type = e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6 */
++        t_FmPcdManipHdrFieldUpdateTcpUdp            tcpUdp;         /**< Parameters for TCP/UDP update. Relevant when
++                                                                         type = e_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP */
++    } u;
++} t_FmPcdManipHdrFieldUpdateParams;
++
++
++
++/**************************************************************************//**
++ @Description   Parameters for defining custom header manipulation for generic field replacement
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrCustomGenFieldReplace {
++    uint8_t                         srcOffset;          /**< Location of new data - Offset from
++                                                             Parse Result  (>= 16, srcOffset+size <= 32, ) */
++    uint8_t                         dstOffset;          /**< Location of data to be overwritten - Offset from
++                                                             start of frame (dstOffset + size <= 256). */
++    uint8_t                         size;               /**< The number of bytes (<=16) to be replaced */
++    uint8_t                         mask;               /**< Optional 1 byte mask. Set to select bits for
++                                                             replacement (1 - bit will be replaced);
++                                                             Clear to use field as is. */
++    uint8_t                         maskOffset;         /**< Relevant if mask != 0;
++                                                             Mask offset within the replaces "size" */
++} t_FmPcdManipHdrCustomGenFieldReplace;
++
++/**************************************************************************//**
++ @Description   Parameters for defining custom header manipulation for IP replacement
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrCustomIpHdrReplace {
++    e_FmPcdManipHdrCustomIpReplace  replaceType;        /**< Selects replace update type */
++    bool                            decTtlHl;           /**< Decrement TTL (IPV4) or Hop limit (IPV6) by 1  */
++    bool                            updateIpv4Id;       /**< Relevant when replaceType =
++                                                             e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4 */
++    uint16_t                        id;                 /**< 16 bit New IP ID; Relevant only if
++                                                             updateIpv4Id = TRUE */
++    uint8_t                         hdrSize;            /**< The size of the new IP header */
++    uint8_t                         hdr[FM_PCD_MANIP_MAX_HDR_SIZE];
++                                                        /**< The new IP header */
++} t_FmPcdManipHdrCustomIpHdrReplace;
++
++/**************************************************************************//**
++ @Description   Parameters for defining custom header manipulation
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrCustomParams {
++    e_FmPcdManipHdrCustomType                   type;           /**< Type of header field update manipulation */
++    union {
++        t_FmPcdManipHdrCustomIpHdrReplace       ipHdrReplace;   /**< Parameters IP header replacement */
++        t_FmPcdManipHdrCustomGenFieldReplace    genFieldReplace;   /**< Parameters IP header replacement */
++    } u;
++} t_FmPcdManipHdrCustomParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining specific L2 insertion manipulation
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrInsrtSpecificL2Params {
++    e_FmPcdManipHdrInsrtSpecificL2  specificL2;     /**< Selects which L2 headers to insert */
++    bool                            update;         /**< TRUE to update MPLS header */
++    uint8_t                         size;           /**< size of inserted section */
++    uint8_t                         *p_Data;        /**< data to be inserted */
++} t_FmPcdManipHdrInsrtSpecificL2Params;
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Description   Parameters for defining IP insertion manipulation
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrInsrtIpParams {
++    bool                            calcL4Checksum; /**< Calculate L4 checksum. */
++    e_FmPcdManipHdrQosMappingMode   mappingMode;    /**< TODO */
++    uint8_t                         lastPidOffset;  /**< the offset of the last Protocol within
++                                                         the inserted header */
++    uint16_t                        id;         /**< 16 bit New IP ID */
++    bool                            dontFragOverwrite;
++    /**< IPv4 only. DF is overwritten with the hash-result next-to-last byte.
++     * This byte is configured to be overwritten when RPD is set. */
++    uint8_t                         lastDstOffset;
++    /**< IPv6 only. if routing extension exist, user should set the offset of the destination address
++     * in order to calculate UDP checksum pseudo header;
++     * Otherwise set it to '0'. */
++    t_FmPcdManipHdrInsrt            insrt;      /**< size and data to be inserted. */
++} t_FmPcdManipHdrInsrtIpParams;
++#endif /* (DPAA_VERSION >= 11) */
++
++/**************************************************************************//**
++ @Description   Parameters for defining header insertion manipulation by header type
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrInsrtByHdrParams {
++    e_FmPcdManipHdrInsrtByHdrType               type;   /**< Selects manipulation type */
++    union {
++
++        t_FmPcdManipHdrInsrtSpecificL2Params    specificL2Params;
++                                                             /**< Used when type = e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2:
++                                                              Selects which L2 headers to insert */
++#if (DPAA_VERSION >= 11)
++        t_FmPcdManipHdrInsrtIpParams            ipParams;  /**< Used when type = e_FM_PCD_MANIP_INSRT_BY_HDR_IP */
++        t_FmPcdManipHdrInsrt                    insrt;     /**< Used when type is one of e_FM_PCD_MANIP_INSRT_BY_HDR_UDP,
++                                                                e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE, or
++                                                                e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP */
++#endif /* (DPAA_VERSION >= 11) */
++    } u;
++} t_FmPcdManipHdrInsrtByHdrParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header insertion manipulation
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrInsrtParams {
++    e_FmPcdManipHdrInsrtType                    type;       /**< Type of insertion manipulation */
++    union {
++        t_FmPcdManipHdrInsrtByHdrParams         byHdr;      /**< Parameters for defining header insertion manipulation by header type,
++                                                                 relevant if 'type' = e_FM_PCD_MANIP_INSRT_BY_HDR */
++        t_FmPcdManipHdrInsrtGenericParams       generic;    /**< Parameters for defining generic header insertion manipulation,
++                                                                 relevant if 'type' = e_FM_PCD_MANIP_INSRT_GENERIC */
++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++        t_FmPcdManipHdrInsrtByTemplateParams    byTemplate; /**< Parameters for defining header insertion manipulation by template,
++                                                                 relevant if 'type' = e_FM_PCD_MANIP_INSRT_BY_TEMPLATE */
++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
++    } u;
++} t_FmPcdManipHdrInsrtParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header removal manipulation
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrRmvParams {
++    e_FmPcdManipHdrRmvType                  type;       /**< Type of header removal manipulation */
++    union {
++        t_FmPcdManipHdrRmvByHdrParams       byHdr;      /**< Parameters for defining header removal manipulation by header type,
++                                                             relevant if type = e_FM_PCD_MANIP_RMV_BY_HDR */
++        t_FmPcdManipHdrRmvGenericParams     generic;    /**< Parameters for defining generic header removal manipulation,
++                                                             relevant if type = e_FM_PCD_MANIP_RMV_GENERIC */
++    } u;
++} t_FmPcdManipHdrRmvParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header manipulation node
++*//***************************************************************************/
++typedef struct t_FmPcdManipHdrParams {
++    bool                                        rmv;                /**< TRUE, to define removal manipulation */
++    t_FmPcdManipHdrRmvParams                    rmvParams;          /**< Parameters for removal manipulation, relevant if 'rmv' = TRUE */
++
++    bool                                        insrt;              /**< TRUE, to define insertion manipulation */
++    t_FmPcdManipHdrInsrtParams                  insrtParams;        /**< Parameters for insertion manipulation, relevant if 'insrt' = TRUE */
++
++    bool                                        fieldUpdate;        /**< TRUE, to define field update manipulation */
++    t_FmPcdManipHdrFieldUpdateParams            fieldUpdateParams;  /**< Parameters for field update manipulation, relevant if 'fieldUpdate' = TRUE */
++
++    bool                                        custom;             /**< TRUE, to define custom manipulation */
++    t_FmPcdManipHdrCustomParams                 customParams;       /**< Parameters for custom manipulation, relevant if 'custom' = TRUE */
++
++    bool                                        dontParseAfterManip;/**< TRUE to de-activate the parser after the manipulation defined in this node.
++                                                                                          Restrictions:
++                                                                                          1. MUST be set if the next engine after the CC is not another CC node
++                                                                                          (but rather Policer or Keygen), and this is the last (no h_NextManip) in a chain
++                                                                                          of manipulation nodes. This includes single nodes (i.e. no h_NextManip and
++                                                                                          also never pointed as h_NextManip of other manipulation nodes)
++                                                                                          2. MUST be set if the next engine after the CC is another CC node, and
++                                                                                          this is NOT the last manipulation node (i.e. it has h_NextManip).*/
++} t_FmPcdManipHdrParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining fragmentation manipulation
++*//***************************************************************************/
++typedef struct t_FmPcdManipFragParams {
++    e_NetHeaderType                     hdr;          /**< Header selection */
++    union {
++#if (DPAA_VERSION >= 11)
++        t_FmPcdManipFragCapwapParams    capwapFrag;   /**< Parameters for defining CAPWAP fragmentation,
++                                                           relevant if 'hdr' = HEADER_TYPE_CAPWAP */
++#endif /* (DPAA_VERSION >= 11) */
++        t_FmPcdManipFragIpParams        ipFrag;       /**< Parameters for defining IP fragmentation,
++                                                           relevant if 'hdr' = HEADER_TYPE_Ipv4 or HEADER_TYPE_Ipv6 */
++    } u;
++} t_FmPcdManipFragParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining reassembly manipulation
++*//***************************************************************************/
++typedef struct t_FmPcdManipReassemParams {
++    e_NetHeaderType                     hdr;          /**< Header selection */
++    union {
++#if (DPAA_VERSION >= 11)
++        t_FmPcdManipReassemCapwapParams capwapReassem;  /**< Parameters for defining CAPWAP reassembly,
++                                                           relevant if 'hdr' = HEADER_TYPE_CAPWAP */
++#endif /* (DPAA_VERSION >= 11) */
++
++        t_FmPcdManipReassemIpParams     ipReassem;    /**< Parameters for defining IP reassembly,
++                                                           relevant if 'hdr' = HEADER_TYPE_Ipv4 or HEADER_TYPE_Ipv6 */
++    } u;
++} t_FmPcdManipReassemParams;
++
++/**************************************************************************//**
++ @Description   Parameters for defining a manipulation node
++*//***************************************************************************/
++typedef struct t_FmPcdManipParams {
++    e_FmPcdManipType                        type;               /**< Selects type of manipulation node */
++    union{
++        t_FmPcdManipHdrParams               hdr;                /**< Parameters for defining header manipulation node */
++        t_FmPcdManipReassemParams           reassem;            /**< Parameters for defining reassembly manipulation node */
++        t_FmPcdManipFragParams              frag;               /**< Parameters for defining fragmentation manipulation node */
++        t_FmPcdManipSpecialOffloadParams    specialOffload;     /**< Parameters for defining special offload manipulation node */
++    } u;
++
++    t_Handle                                h_NextManip;        /**< Supported for Header Manipulation only;
++                                                                     Handle to another (previously defined) manipulation node;
++                                                                     Allows concatenation of manipulation actions;
++                                                                     This parameter is optional and may be NULL. */
++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++    bool                                    fragOrReasm;        /**< TRUE, if defined fragmentation/reassembly manipulation */
++    t_FmPcdManipFragOrReasmParams           fragOrReasmParams;  /**< Parameters for fragmentation/reassembly manipulation,
++                                                                     relevant if fragOrReasm = TRUE */
++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
++} t_FmPcdManipParams;
++
++/**************************************************************************//**
++ @Description   Structure for retrieving IP reassembly statistics
++*//***************************************************************************/
++typedef struct t_FmPcdManipReassemIpStats {
++    /* common counters for both IPv4 and IPv6 */
++    uint32_t        timeout;                    /**< Counts the number of timeout occurrences */
++    uint32_t        rfdPoolBusy;                /**< Counts the number of failed attempts to allocate
++                                                     a Reassembly Frame Descriptor */
++    uint32_t        internalBufferBusy;         /**< Counts the number of times an internal buffer busy occurred */
++    uint32_t        externalBufferBusy;         /**< Counts the number of times external buffer busy occurred */
++    uint32_t        sgFragments;                /**< Counts the number of Scatter/Gather fragments */
++    uint32_t        dmaSemaphoreDepletion;      /**< Counts the number of failed attempts to allocate a DMA semaphore */
++#if (DPAA_VERSION >= 11)
++    uint32_t        nonConsistentSp;            /**< Counts the number of Non Consistent Storage Profile events for
++                                                     successfully reassembled frames */
++#endif /* (DPAA_VERSION >= 11) */
++    struct {
++        uint32_t    successfullyReassembled;    /**< Counts the number of successfully reassembled frames */
++        uint32_t    validFragments;             /**< Counts the total number of valid fragments that
++                                                     have been processed for all frames */
++        uint32_t    processedFragments;         /**< Counts the number of processed fragments
++                                                     (valid and error fragments) for all frames */
++        uint32_t    malformedFragments;         /**< Counts the number of malformed fragments processed for all frames */
++        uint32_t    discardedFragments;         /**< Counts the number of fragments discarded by the reassembly process */
++        uint32_t    autoLearnBusy;              /**< Counts the number of times a busy condition occurs when attempting
++                                                     to access an IP-Reassembly Automatic Learning Hash set */
++        uint32_t    moreThan16Fragments;        /**< Counts the fragment occurrences in which the number of fragments-per-frame
++                                                     exceeds 16 */
++    } specificHdrStatistics[2];                 /**< slot '0' is for IPv4, slot '1' is for IPv6 */
++} t_FmPcdManipReassemIpStats;
++
++/**************************************************************************//**
++ @Description   Structure for retrieving IP fragmentation statistics
++*//***************************************************************************/
++typedef struct t_FmPcdManipFragIpStats {
++    uint32_t    totalFrames;            /**< Number of frames that passed through the manipulation node */
++    uint32_t    fragmentedFrames;       /**< Number of frames that were fragmented */
++    uint32_t    generatedFragments;     /**< Number of fragments that were generated */
++} t_FmPcdManipFragIpStats;
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Description   Structure for retrieving CAPWAP reassembly statistics
++*//***************************************************************************/
++typedef struct t_FmPcdManipReassemCapwapStats {
++    uint32_t    timeout;                    /**< Counts the number of timeout occurrences */
++    uint32_t    rfdPoolBusy;                /**< Counts the number of failed attempts to allocate
++                                                 a Reassembly Frame Descriptor */
++    uint32_t    internalBufferBusy;         /**< Counts the number of times an internal buffer busy occurred */
++    uint32_t    externalBufferBusy;         /**< Counts the number of times external buffer busy occurred */
++    uint32_t    sgFragments;                /**< Counts the number of Scatter/Gather fragments */
++    uint32_t    dmaSemaphoreDepletion;      /**< Counts the number of failed attempts to allocate a DMA semaphore */
++    uint32_t    successfullyReassembled;    /**< Counts the number of successfully reassembled frames */
++    uint32_t    validFragments;             /**< Counts the total number of valid fragments that
++                                                 have been processed for all frames */
++    uint32_t    processedFragments;         /**< Counts the number of processed fragments
++                                                 (valid and error fragments) for all frames */
++    uint32_t    malformedFragments;         /**< Counts the number of malformed fragments processed for all frames */
++    uint32_t    autoLearnBusy;              /**< Counts the number of times a busy condition occurs when attempting
++                                                 to access an Reassembly Automatic Learning Hash set */
++    uint32_t    discardedFragments;         /**< Counts the number of fragments discarded by the reassembly process */
++    uint32_t    moreThan16Fragments;        /**< Counts the fragment occurrences in which the number of fragments-per-frame
++                                                 exceeds 16 */
++    uint32_t    exceedMaxReassemblyFrameLen;/**< ounts the number of times that a successful reassembled frame
++                                                 length exceeds MaxReassembledFrameLength value */
++} t_FmPcdManipReassemCapwapStats;
++
++/**************************************************************************//**
++ @Description   Structure for retrieving CAPWAP fragmentation statistics
++*//***************************************************************************/
++typedef struct t_FmPcdManipFragCapwapStats {
++    uint32_t    totalFrames;            /**< Number of frames that passed through the manipulation node */
++    uint32_t    fragmentedFrames;       /**< Number of frames that were fragmented */
++    uint32_t    generatedFragments;     /**< Number of fragments that were generated */
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++    uint8_t     sgAllocationFailure;    /**< Number of allocation failure of s/g buffers */
++#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */
++} t_FmPcdManipFragCapwapStats;
++#endif /* (DPAA_VERSION >= 11) */
++
++/**************************************************************************//**
++ @Description   Structure for retrieving reassembly statistics
++*//***************************************************************************/
++typedef struct t_FmPcdManipReassemStats {
++    union {
++        t_FmPcdManipReassemIpStats  ipReassem;  /**< Structure for IP reassembly statistics */
++#if (DPAA_VERSION >= 11)
++        t_FmPcdManipReassemCapwapStats  capwapReassem;  /**< Structure for CAPWAP reassembly statistics */
++#endif /* (DPAA_VERSION >= 11) */
++    } u;
++} t_FmPcdManipReassemStats;
++
++/**************************************************************************//**
++ @Description   Structure for retrieving fragmentation statistics
++*//***************************************************************************/
++typedef struct t_FmPcdManipFragStats {
++    union {
++        t_FmPcdManipFragIpStats     ipFrag;     /**< Structure for IP fragmentation statistics */
++#if (DPAA_VERSION >= 11)
++        t_FmPcdManipFragCapwapStats capwapFrag; /**< Structure for CAPWAP fragmentation statistics */
++#endif /* (DPAA_VERSION >= 11) */
++    } u;
++} t_FmPcdManipFragStats;
++
++/**************************************************************************//**
++ @Description   Structure for selecting manipulation statistics
++*//***************************************************************************/
++typedef struct t_FmPcdManipStats {
++    union {
++        t_FmPcdManipReassemStats    reassem;    /**< Structure for reassembly statistics */
++        t_FmPcdManipFragStats       frag;       /**< Structure for fragmentation statistics */
++    } u;
++} t_FmPcdManipStats;
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Description   Parameters for defining frame replicator group and its members
++*//***************************************************************************/
++typedef struct t_FmPcdFrmReplicGroupParams {
++    uint8_t                     maxNumOfEntries;    /**< Maximal number of members in the group;
++                                                         Must be at least 2. */
++    uint8_t                     numOfEntries;       /**< Number of members in the group;
++                                                         Must be at least 1. */
++    t_FmPcdCcNextEngineParams   nextEngineParams[FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES];
++                                                    /**< Array of members' parameters */
++} t_FmPcdFrmReplicGroupParams;
++#endif /* (DPAA_VERSION >= 11) */
++
++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++/**************************************************************************//**
++ @Description   structure for defining statistics node
++*//***************************************************************************/
++typedef struct t_FmPcdStatsParams {
++    e_FmPcdStatsType    type;   /**< type of statistics node */
++} t_FmPcdStatsParams;
++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
++
++/**************************************************************************//**
++ @Function      FM_PCD_NetEnvCharacteristicsSet
++
++ @Description   Define a set of Network Environment Characteristics.
++
++                When setting an environment it is important to understand its
++                application. It is not meant to describe the flows that will run
++                on the ports using this environment, but what the user means TO DO
++                with the PCD mechanisms in order to parse-classify-distribute those
++                frames.
++                By specifying a distinction unit, the user means it would use that option
++                for distinction between frames at either a KeyGen scheme or a coarse
++                classification action descriptor. Using interchangeable headers to define a
++                unit means that the user is indifferent to which of the interchangeable
++                headers is present in the frame, and wants the distinction to be based
++                on the presence of either one of them.
++
++                Depending on context, there are limitations to the use of environments. A
++                port using the PCD functionality is bound to an environment. Some or even
++                all ports may share an environment but also an environment per port is
++                possible. When initializing a scheme, a classification plan group (see below),
++                or a coarse classification tree, one of the initialized environments must be
++                stated and related to. When a port is bound to a scheme, a classification
++                plan group, or a coarse classification tree, it MUST be bound to the same
++                environment.
++
++                The different PCD modules, may relate (for flows definition) ONLY on
++                distinction units as defined by their environment. When initializing a
++                scheme for example, it may not choose to select IPV4 as a match for
++                recognizing flows unless it was defined in the relating environment. In
++                fact, to guide the user through the configuration of the PCD, each module's
++                characterization in terms of flows is not done using protocol names, but using
++                environment indexes.
++
++                In terms of HW implementation, the list of distinction units sets the LCV vectors
++                and later used for match vector, classification plan vectors and coarse classification
++                indexing.
++
++ @Param[in]     h_FmPcd         FM PCD module descriptor.
++ @Param[in]     p_NetEnvParams  A structure of parameters for the initialization of
++                                the network environment.
++
++ @Return        A handle to the initialized object on success; NULL code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++t_Handle FM_PCD_NetEnvCharacteristicsSet(t_Handle h_FmPcd, t_FmPcdNetEnvParams *p_NetEnvParams);
++
++/**************************************************************************//**
++ @Function      FM_PCD_NetEnvCharacteristicsDelete
++
++ @Description   Deletes a set of Network Environment Characteristics.
++
++ @Param[in]     h_NetEnv        A handle to the Network environment.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_PCD_NetEnvCharacteristicsDelete(t_Handle h_NetEnv);
++
++/**************************************************************************//**
++ @Function      FM_PCD_KgSchemeSet
++
++ @Description   Initializing or modifying and enabling a scheme for the KeyGen.
++                This routine should be called for adding or modifying a scheme.
++                When a scheme needs modifying, the API requires that it will be
++                rewritten. In such a case 'modify' should be TRUE. If the
++                routine is called for a valid scheme and 'modify' is FALSE,
++                it will return error.
++
++ @Param[in]     h_FmPcd         If this is a new scheme - A handle to an FM PCD Module.
++                                Otherwise NULL (ignored by driver).
++ @Param[in,out] p_SchemeParams  A structure of parameters for defining the scheme
++
++ @Return        A handle to the initialized scheme on success; NULL code otherwise.
++                When used as "modify" (rather than for setting a new scheme),
++                p_SchemeParams->id.h_Scheme will return NULL if action fails due to scheme
++                BUSY state.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++t_Handle FM_PCD_KgSchemeSet(t_Handle                h_FmPcd,
++                            t_FmPcdKgSchemeParams   *p_SchemeParams);
++
++/**************************************************************************//**
++ @Function      FM_PCD_KgSchemeDelete
++
++ @Description   Deleting an initialized scheme.
++
++ @Param[in]     h_Scheme        scheme handle as returned by FM_PCD_KgSchemeSet()
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init() & FM_PCD_KgSchemeSet().
++*//***************************************************************************/
++t_Error     FM_PCD_KgSchemeDelete(t_Handle h_Scheme);
++
++/**************************************************************************//**
++ @Function      FM_PCD_KgSchemeGetCounter
++
++ @Description   Reads scheme packet counter.
++
++ @Param[in]     h_Scheme        scheme handle as returned by FM_PCD_KgSchemeSet().
++
++ @Return        Counter's current value.
++
++ @Cautions      Allowed only following FM_PCD_Init() & FM_PCD_KgSchemeSet().
++*//***************************************************************************/
++uint32_t  FM_PCD_KgSchemeGetCounter(t_Handle h_Scheme);
++
++/**************************************************************************//**
++ @Function      FM_PCD_KgSchemeSetCounter
++
++ @Description   Writes scheme packet counter.
++
++ @Param[in]     h_Scheme        scheme handle as returned by FM_PCD_KgSchemeSet().
++ @Param[in]     value           New scheme counter value - typically '0' for
++                                resetting the counter.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init() & FM_PCD_KgSchemeSet().
++*//***************************************************************************/
++t_Error  FM_PCD_KgSchemeSetCounter(t_Handle h_Scheme, uint32_t value);
++
++/**************************************************************************//**
++ @Function      FM_PCD_PlcrProfileSet
++
++ @Description   Sets a profile entry in the policer profile table.
++                The routine overrides any existing value.
++
++ @Param[in]     h_FmPcd           A handle to an FM PCD Module.
++ @Param[in]     p_Profile         A structure of parameters for defining a
++                                  policer profile entry.
++
++ @Return        A handle to the initialized object on success; NULL code otherwise.
++                When used as "modify" (rather than for setting a new profile),
++                p_Profile->id.h_Profile will return NULL if action fails due to profile
++                BUSY state.
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++t_Handle FM_PCD_PlcrProfileSet(t_Handle                  h_FmPcd,
++                               t_FmPcdPlcrProfileParams  *p_Profile);
++
++/**************************************************************************//**
++ @Function      FM_PCD_PlcrProfileDelete
++
++ @Description   Delete a profile entry in the policer profile table.
++                The routine set entry to invalid.
++
++ @Param[in]     h_Profile       A handle to the profile.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++t_Error FM_PCD_PlcrProfileDelete(t_Handle h_Profile);
++
++/**************************************************************************//**
++ @Function      FM_PCD_PlcrProfileGetCounter
++
++ @Description   Sets an entry in the classification plan.
++                The routine overrides any existing value.
++
++ @Param[in]     h_Profile       A handle to the profile.
++ @Param[in]     counter         Counter selector.
++
++ @Return        specific counter value.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++uint32_t FM_PCD_PlcrProfileGetCounter(t_Handle                      h_Profile,
++                                      e_FmPcdPlcrProfileCounters    counter);
++
++/**************************************************************************//**
++ @Function      FM_PCD_PlcrProfileSetCounter
++
++ @Description   Sets an entry in the classification plan.
++                The routine overrides any existing value.
++
++ @Param[in]     h_Profile       A handle to the profile.
++ @Param[in]     counter         Counter selector.
++ @Param[in]     value           value to set counter with.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++t_Error FM_PCD_PlcrProfileSetCounter(t_Handle                   h_Profile,
++                                     e_FmPcdPlcrProfileCounters counter,
++                                     uint32_t                   value);
++
++/**************************************************************************//**
++ @Function      FM_PCD_CcRootBuild
++
++ @Description   This routine must be called to define a complete coarse
++                classification tree. This is the way to define coarse
++                classification to a certain flow - the KeyGen schemes
++                may point only to trees defined in this way.
++
++ @Param[in]     h_FmPcd         FM PCD module descriptor.
++ @Param[in]     p_Params        A structure of parameters to define the tree.
++
++ @Return        A handle to the initialized object on success; NULL code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++t_Handle FM_PCD_CcRootBuild (t_Handle             h_FmPcd,
++                             t_FmPcdCcTreeParams  *p_Params);
++
++/**************************************************************************//**
++ @Function      FM_PCD_CcRootDelete
++
++ @Description   Deleting an built tree.
++
++ @Param[in]     h_CcTree        A handle to a CC tree.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++t_Error FM_PCD_CcRootDelete(t_Handle h_CcTree);
++
++/**************************************************************************//**
++ @Function      FM_PCD_CcRootModifyNextEngine
++
++ @Description   Modify the Next Engine Parameters in the entry of the tree.
++
++ @Param[in]     h_CcTree                    A handle to the tree
++ @Param[in]     grpId                       A Group index in the tree
++ @Param[in]     index                       Entry index in the group defined by grpId
++ @Param[in]     p_FmPcdCcNextEngineParams   Pointer to new next engine parameters
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_CcBuildTree().
++*//***************************************************************************/
++t_Error FM_PCD_CcRootModifyNextEngine(t_Handle                  h_CcTree,
++                                      uint8_t                   grpId,
++                                      uint8_t                   index,
++                                      t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableSet
++
++ @Description   This routine should be called for each CC (coarse classification)
++                node. The whole CC tree should be built bottom up so that each
++                node points to already defined nodes.
++
++ @Param[in]     h_FmPcd         FM PCD module descriptor.
++ @Param[in]     p_Param         A structure of parameters defining the CC node
++
++ @Return        A handle to the initialized object on success; NULL code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++t_Handle   FM_PCD_MatchTableSet(t_Handle h_FmPcd, t_FmPcdCcNodeParams *p_Param);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableDelete
++
++ @Description   Deleting an built node.
++
++ @Param[in]     h_CcNode        A handle to a CC node.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableDelete(t_Handle h_CcNode);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableModifyMissNextEngine
++
++ @Description   Modify the Next Engine Parameters of the Miss key case of the node.
++
++ @Param[in]     h_CcNode                    A handle to the node
++ @Param[in]     p_FmPcdCcNextEngineParams   Parameters for defining next engine
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet();
++                Not relevant in the case the node is of type 'INDEXED_LOOKUP'.
++                When configuring nextEngine = e_FM_PCD_CC, note that
++                p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different
++                from the currently changed table.
++
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableModifyMissNextEngine(t_Handle                  h_CcNode,
++                                              t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableRemoveKey
++
++ @Description   Remove the key (including next engine parameters of this key)
++                defined by the index of the relevant node.
++
++ @Param[in]     h_CcNode                    A handle to the node
++ @Param[in]     keyIndex                    Key index for removing
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet() was called for this
++                node and the nodes that lead to it.
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableRemoveKey(t_Handle h_CcNode, uint16_t keyIndex);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableAddKey
++
++ @Description   Add the key (including next engine parameters of this key in the
++                index defined by the keyIndex. Note that 'FM_PCD_LAST_KEY_INDEX'
++                may be used by user that don't care about the position of the
++                key in the table - in that case, the key will be automatically
++                added by the driver in the last available entry.
++
++ @Param[in]     h_CcNode     A handle to the node
++ @Param[in]     keyIndex     Key index for adding.
++ @Param[in]     keySize      Key size of added key
++ @Param[in]     p_KeyParams  A pointer to the parameters includes
++                             new key with Next Engine Parameters
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet() was called for this
++                node and the nodes that lead to it.
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableAddKey(t_Handle            h_CcNode,
++                                uint16_t            keyIndex,
++                                uint8_t             keySize,
++                                t_FmPcdCcKeyParams  *p_KeyParams);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableModifyNextEngine
++
++ @Description   Modify the Next Engine Parameters in the relevant key entry of the node.
++
++ @Param[in]     h_CcNode                    A handle to the node
++ @Param[in]     keyIndex                    Key index for Next Engine modifications
++ @Param[in]     p_FmPcdCcNextEngineParams   Parameters for defining next engine
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet().
++                When configuring nextEngine = e_FM_PCD_CC, note that
++                p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different
++                from the currently changed table.
++
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableModifyNextEngine(t_Handle                  h_CcNode,
++                                          uint16_t                  keyIndex,
++                                          t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableModifyKeyAndNextEngine
++
++ @Description   Modify the key and Next Engine Parameters of this key in the
++                index defined by the keyIndex.
++
++ @Param[in]     h_CcNode                    A handle to the node
++ @Param[in]     keyIndex                    Key index for adding
++ @Param[in]     keySize                     Key size of added key
++ @Param[in]     p_KeyParams                 A pointer to the parameters includes
++                                            modified key and modified Next Engine Parameters
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet() was called for this
++                node and the nodes that lead to it.
++                When configuring nextEngine = e_FM_PCD_CC, note that
++                p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different
++                from the currently changed table.
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableModifyKeyAndNextEngine(t_Handle            h_CcNode,
++                                                uint16_t            keyIndex,
++                                                uint8_t             keySize,
++                                                t_FmPcdCcKeyParams  *p_KeyParams);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableModifyKey
++
++ @Description   Modify the key in the index defined by the keyIndex.
++
++ @Param[in]     h_CcNode                    A handle to the node
++ @Param[in]     keyIndex                    Key index for adding
++ @Param[in]     keySize                     Key size of added key
++ @Param[in]     p_Key                       A pointer to the new key
++ @Param[in]     p_Mask                      A pointer to the new mask if relevant,
++                                            otherwise pointer to NULL
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet() was called for this
++                node and the nodes that lead to it.
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableModifyKey(t_Handle h_CcNode,
++                                   uint16_t keyIndex,
++                                   uint8_t  keySize,
++                                   uint8_t  *p_Key,
++                                   uint8_t  *p_Mask);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableFindNRemoveKey
++
++ @Description   Remove the key (including next engine parameters of this key)
++                defined by the key and mask. Note that this routine will search
++                the node to locate the index of the required key (& mask) to remove.
++
++ @Param[in]     h_CcNode                    A handle to the node
++ @Param[in]     keySize                     Key size of the one to remove.
++ @Param[in]     p_Key                       A pointer to the requested key to remove.
++ @Param[in]     p_Mask                      A pointer to the mask if relevant,
++                                            otherwise pointer to NULL
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet() was called for this
++                node and the nodes that lead to it.
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableFindNRemoveKey(t_Handle h_CcNode,
++                                        uint8_t  keySize,
++                                        uint8_t  *p_Key,
++                                        uint8_t  *p_Mask);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableFindNModifyNextEngine
++
++ @Description   Modify the Next Engine Parameters in the relevant key entry of
++                the node. Note that this routine will search the node to locate
++                the index of the required key (& mask) to modify.
++
++ @Param[in]     h_CcNode                    A handle to the node
++ @Param[in]     keySize                     Key size of the one to modify.
++ @Param[in]     p_Key                       A pointer to the requested key to modify.
++ @Param[in]     p_Mask                      A pointer to the mask if relevant,
++                                            otherwise pointer to NULL
++ @Param[in]     p_FmPcdCcNextEngineParams   Parameters for defining next engine
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet().
++                When configuring nextEngine = e_FM_PCD_CC, note that
++                p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different
++                from the currently changed table.
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableFindNModifyNextEngine(t_Handle                  h_CcNode,
++                                               uint8_t                   keySize,
++                                               uint8_t                   *p_Key,
++                                               uint8_t                   *p_Mask,
++                                               t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableFindNModifyKeyAndNextEngine
++
++ @Description   Modify the key and Next Engine Parameters of this key in the
++                index defined by the keyIndex. Note that this routine will search
++                the node to locate the index of the required key (& mask) to modify.
++
++ @Param[in]     h_CcNode                    A handle to the node
++ @Param[in]     keySize                     Key size of the one to modify.
++ @Param[in]     p_Key                       A pointer to the requested key to modify.
++ @Param[in]     p_Mask                      A pointer to the mask if relevant,
++                                            otherwise pointer to NULL
++ @Param[in]     p_KeyParams                 A pointer to the parameters includes
++                                            modified key and modified Next Engine Parameters
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet() was called for this
++                node and the nodes that lead to it.
++                When configuring nextEngine = e_FM_PCD_CC, note that
++                p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different
++                from the currently changed table.
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableFindNModifyKeyAndNextEngine(t_Handle            h_CcNode,
++                                                     uint8_t             keySize,
++                                                     uint8_t             *p_Key,
++                                                     uint8_t             *p_Mask,
++                                                     t_FmPcdCcKeyParams  *p_KeyParams);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableFindNModifyKey
++
++ @Description   Modify the key  in the index defined by the keyIndex. Note that
++                this routine will search the node to locate the index of the
++                required key (& mask) to modify.
++
++ @Param[in]     h_CcNode                    A handle to the node
++ @Param[in]     keySize                     Key size of the one to modify.
++ @Param[in]     p_Key                       A pointer to the requested key to modify.
++ @Param[in]     p_Mask                      A pointer to the mask if relevant,
++                                            otherwise pointer to NULL
++ @Param[in]     p_NewKey                    A pointer to the new key
++ @Param[in]     p_NewMask                   A pointer to the new mask if relevant,
++                                            otherwise pointer to NULL
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet() was called for this
++                node and the nodes that lead to it.
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableFindNModifyKey(t_Handle h_CcNode,
++                                        uint8_t  keySize,
++                                        uint8_t  *p_Key,
++                                        uint8_t  *p_Mask,
++                                        uint8_t  *p_NewKey,
++                                        uint8_t  *p_NewMask);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableGetKeyCounter
++
++ @Description   This routine may be used to get a counter of specific key in a CC
++                Node; This counter reflects how many frames passed that were matched
++                this key.
++
++ @Param[in]     h_CcNode        A handle to the node
++ @Param[in]     keyIndex        Key index for adding
++
++ @Return        The specific key counter.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet().
++*//***************************************************************************/
++uint32_t FM_PCD_MatchTableGetKeyCounter(t_Handle h_CcNode, uint16_t keyIndex);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableGetKeyStatistics
++
++ @Description   This routine may be used to get statistics counters of specific key
++                in a CC Node.
++
++                If 'e_FM_PCD_CC_STATS_MODE_FRAME' and
++                'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node,
++                these counters reflect how many frames passed that were matched
++                this key; The total frames count will be returned in the counter
++                of the first range (as only one frame length range was defined).
++                If 'e_FM_PCD_CC_STATS_MODE_RMON' was set for this node, the total
++                frame count will be separated to frame length counters, based on
++                provided frame length ranges.
++
++ @Param[in]     h_CcNode        A handle to the node
++ @Param[in]     keyIndex        Key index for adding
++ @Param[out]    p_KeyStatistics Key statistics counters
++
++ @Return        The specific key statistics.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet().
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableGetKeyStatistics(t_Handle                  h_CcNode,
++                                          uint16_t                  keyIndex,
++                                          t_FmPcdCcKeyStatistics    *p_KeyStatistics);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableGetMissStatistics
++
++ @Description   This routine may be used to get statistics counters of miss entry
++                in a CC Node.
++
++                If 'e_FM_PCD_CC_STATS_MODE_FRAME' and
++                'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node,
++                these counters reflect how many frames were not matched to any
++                existing key and therefore passed through the miss entry; The
++                total frames count will be returned in the counter of the
++                first range (as only one frame length range was defined).
++
++ @Param[in]     h_CcNode            A handle to the node
++ @Param[out]    p_MissStatistics    Statistics counters for 'miss'
++
++ @Return        The statistics for 'miss'.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet().
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableGetMissStatistics(t_Handle                  h_CcNode,
++                                           t_FmPcdCcKeyStatistics    *p_MissStatistics);
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableFindNGetKeyStatistics
++
++ @Description   This routine may be used to get statistics counters of specific key
++                in a CC Node.
++
++                If 'e_FM_PCD_CC_STATS_MODE_FRAME' and
++                'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node,
++                these counters reflect how many frames passed that were matched
++                this key; The total frames count will be returned in the counter
++                of the first range (as only one frame length range was defined).
++                If 'e_FM_PCD_CC_STATS_MODE_RMON' was set for this node, the total
++                frame count will be separated to frame length counters, based on
++                provided frame length ranges.
++                Note that this routine will search the node to locate the index
++                of the required key based on received key parameters.
++
++ @Param[in]     h_CcNode        A handle to the node
++ @Param[in]     keySize         Size of the requested key
++ @Param[in]     p_Key           A pointer to the requested key
++ @Param[in]     p_Mask          A pointer to the mask if relevant,
++                                otherwise pointer to NULL
++ @Param[out]    p_KeyStatistics Key statistics counters
++
++ @Return        The specific key statistics.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet().
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableFindNGetKeyStatistics(t_Handle                 h_CcNode,
++                                               uint8_t                  keySize,
++                                               uint8_t                  *p_Key,
++                                               uint8_t                  *p_Mask,
++                                               t_FmPcdCcKeyStatistics   *p_KeyStatistics);
++
++/**************************************************************************//*
++ @Function      FM_PCD_MatchTableGetNextEngine
++
++ @Description   Gets NextEngine of the relevant keyIndex.
++
++ @Param[in]     h_CcNode                    A handle to the node.
++ @Param[in]     keyIndex                    keyIndex in the relevant node.
++ @Param[out]    p_FmPcdCcNextEngineParams   here updated nextEngine parameters for
++                                            the relevant keyIndex of the CC Node
++                                            received as parameter to this function
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableGetNextEngine(t_Handle                     h_CcNode,
++                                       uint16_t                     keyIndex,
++                                       t_FmPcdCcNextEngineParams    *p_FmPcdCcNextEngineParams);
++
++/**************************************************************************//*
++ @Function      FM_PCD_MatchTableGetIndexedHashBucket
++
++ @Description   This routine simulates KeyGen operation on the provided key and
++                calculates to which hash bucket it will be mapped.
++
++ @Param[in]     h_CcNode                A handle to the node.
++ @Param[in]     kgKeySize               Key size as it was configured in the KG
++                                        scheme that leads to this hash.
++ @Param[in]     p_KgKey                 Pointer to the key; must be like the key
++                                        that the KG is generated, i.e. the same
++                                        extraction and with mask if exist.
++ @Param[in]     kgHashShift             Hash-shift as it was configured in the KG
++                                        scheme that leads to this hash.
++ @Param[out]    p_CcNodeBucketHandle    Pointer to the bucket of the provided key.
++ @Param[out]    p_BucketIndex           Index to the bucket of the provided key
++ @Param[out]    p_LastIndex             Pointer to last index in the bucket of the
++                                        provided key.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_HashTableSet()
++*//***************************************************************************/
++t_Error FM_PCD_MatchTableGetIndexedHashBucket(t_Handle    h_CcNode,
++                                              uint8_t     kgKeySize,
++                                              uint8_t     *p_KgKey,
++                                              uint8_t     kgHashShift,
++                                              t_Handle    *p_CcNodeBucketHandle,
++                                              uint8_t     *p_BucketIndex,
++                                              uint16_t    *p_LastIndex);
++
++/**************************************************************************//**
++ @Function      FM_PCD_HashTableSet
++
++ @Description   This routine initializes a hash table structure.
++                KeyGen hash result determines the hash bucket.
++                Next, KeyGen key is compared against all keys of this
++                bucket (exact match).
++                Number of sets (number of buckets) of the hash equals to the
++                number of 1-s in 'hashResMask' in the provided parameters.
++                Number of hash table ways is then calculated by dividing
++                'maxNumOfKeys' equally between the hash sets. This is the maximal
++                number of keys that a hash bucket may hold.
++                The hash table is initialized empty and keys may be
++                added to it following the initialization. Keys masks are not
++                supported in current hash table implementation.
++                The initialized hash table can be integrated as a node in a
++                CC tree.
++
++ @Param[in]     h_FmPcd     FM PCD module descriptor.
++ @Param[in]     p_Param     A structure of parameters defining the hash table
++
++ @Return        A handle to the initialized object on success; NULL code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++t_Handle FM_PCD_HashTableSet(t_Handle h_FmPcd, t_FmPcdHashTableParams *p_Param);
++
++/**************************************************************************//**
++ @Function      FM_PCD_HashTableDelete
++
++ @Description   This routine deletes the provided hash table and released all
++                its allocated resources.
++
++ @Param[in]     h_HashTbl       A handle to a hash table
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_HashTableSet().
++*//***************************************************************************/
++t_Error FM_PCD_HashTableDelete(t_Handle h_HashTbl);
++
++/**************************************************************************//**
++ @Function      FM_PCD_HashTableAddKey
++
++ @Description   This routine adds the provided key (including next engine
++                parameters of this key) to the hash table.
++                The key is added as the last key of the bucket that it is
++                mapped to.
++
++ @Param[in]     h_HashTbl    A handle to a hash table
++ @Param[in]     keySize      Key size of added key
++ @Param[in]     p_KeyParams  A pointer to the parameters includes
++                             new key with next engine parameters; The pointer
++                             to the key mask must be NULL, as masks are not
++                             supported in hash table implementation.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_HashTableSet().
++*//***************************************************************************/
++t_Error FM_PCD_HashTableAddKey(t_Handle            h_HashTbl,
++                               uint8_t             keySize,
++                               t_FmPcdCcKeyParams  *p_KeyParams);
++
++/**************************************************************************//**
++ @Function      FM_PCD_HashTableRemoveKey
++
++ @Description   This routine removes the requested key (including next engine
++                parameters of this key) from the hash table.
++
++ @Param[in]     h_HashTbl    A handle to a hash table
++ @Param[in]     keySize      Key size of the one to remove.
++ @Param[in]     p_Key        A pointer to the requested key to remove.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_HashTableSet().
++*//***************************************************************************/
++t_Error FM_PCD_HashTableRemoveKey(t_Handle h_HashTbl,
++                                  uint8_t  keySize,
++                                  uint8_t  *p_Key);
++
++/**************************************************************************//**
++ @Function      FM_PCD_HashTableModifyNextEngine
++
++ @Description   This routine modifies the next engine for the provided key. The
++                key should be previously added to the hash table.
++
++ @Param[in]     h_HashTbl                   A handle to a hash table
++ @Param[in]     keySize                     Key size of the key to modify.
++ @Param[in]     p_Key                       A pointer to the requested key to modify.
++ @Param[in]     p_FmPcdCcNextEngineParams   A structure for defining new next engine
++                                            parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_HashTableSet().
++                When configuring nextEngine = e_FM_PCD_CC, note that
++                p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different
++                from the currently changed table.
++*//***************************************************************************/
++t_Error FM_PCD_HashTableModifyNextEngine(t_Handle                  h_HashTbl,
++                                         uint8_t                   keySize,
++                                         uint8_t                   *p_Key,
++                                         t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
++
++/**************************************************************************//**
++ @Function      FM_PCD_HashTableModifyMissNextEngine
++
++ @Description   This routine modifies the next engine on key match miss.
++
++ @Param[in]     h_HashTbl                   A handle to a hash table
++ @Param[in]     p_FmPcdCcNextEngineParams   A structure for defining new next engine
++                                            parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_HashTableSet().
++                When configuring nextEngine = e_FM_PCD_CC, note that
++                p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different
++                from the currently changed table.
++*//***************************************************************************/
++t_Error FM_PCD_HashTableModifyMissNextEngine(t_Handle                  h_HashTbl,
++                                             t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
++
++/**************************************************************************//*
++ @Function      FM_PCD_HashTableGetMissNextEngine
++
++ @Description   Gets NextEngine in case of key match miss.
++
++ @Param[in]     h_HashTbl                   A handle to a hash table
++ @Param[out]    p_FmPcdCcNextEngineParams   Next engine parameters for the specified
++                                            hash table.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_HashTableSet().
++*//***************************************************************************/
++t_Error FM_PCD_HashTableGetMissNextEngine(t_Handle                     h_HashTbl,
++                                          t_FmPcdCcNextEngineParams    *p_FmPcdCcNextEngineParams);
++
++/**************************************************************************//**
++ @Function      FM_PCD_HashTableFindNGetKeyStatistics
++
++ @Description   This routine may be used to get statistics counters of specific key
++                in a hash table.
++
++                If 'e_FM_PCD_CC_STATS_MODE_FRAME' and
++                'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node,
++                these counters reflect how many frames passed that were matched
++                this key; The total frames count will be returned in the counter
++                of the first range (as only one frame length range was defined).
++                If 'e_FM_PCD_CC_STATS_MODE_RMON' was set for this node, the total
++                frame count will be separated to frame length counters, based on
++                provided frame length ranges.
++                Note that this routine will identify the bucket of this key in
++                the hash table and will search the bucket to locate the index
++                of the required key based on received key parameters.
++
++ @Param[in]     h_HashTbl       A handle to a hash table
++ @Param[in]     keySize         Size of the requested key
++ @Param[in]     p_Key           A pointer to the requested key
++ @Param[out]    p_KeyStatistics Key statistics counters
++
++ @Return        The specific key statistics.
++
++ @Cautions      Allowed only following FM_PCD_HashTableSet().
++*//***************************************************************************/
++t_Error FM_PCD_HashTableFindNGetKeyStatistics(t_Handle                 h_HashTbl,
++                                              uint8_t                  keySize,
++                                              uint8_t                  *p_Key,
++                                              t_FmPcdCcKeyStatistics   *p_KeyStatistics);
++
++/**************************************************************************//**
++ @Function      FM_PCD_HashTableGetMissStatistics
++
++ @Description   This routine may be used to get statistics counters of 'miss'
++                entry of the a hash table.
++
++                If 'e_FM_PCD_CC_STATS_MODE_FRAME' and
++                'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node,
++                these counters reflect how many frames were not matched to any
++                existing key and therefore passed through the miss entry;
++
++ @Param[in]     h_HashTbl           A handle to a hash table
++ @Param[out]    p_MissStatistics    Statistics counters for 'miss'
++
++ @Return        The statistics for 'miss'.
++
++ @Cautions      Allowed only following FM_PCD_HashTableSet().
++*//***************************************************************************/
++t_Error FM_PCD_HashTableGetMissStatistics(t_Handle                 h_HashTbl,
++                                          t_FmPcdCcKeyStatistics   *p_MissStatistics);
++
++/**************************************************************************//**
++ @Function      FM_PCD_ManipNodeSet
++
++ @Description   This routine should be called for defining a manipulation
++                node. A manipulation node must be defined before the CC node
++                that precedes it.
++
++ @Param[in]     h_FmPcd             FM PCD module descriptor.
++ @Param[in]     p_FmPcdManipParams  A structure of parameters defining the manipulation
++
++ @Return        A handle to the initialized object on success; NULL code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++t_Handle FM_PCD_ManipNodeSet(t_Handle h_FmPcd, t_FmPcdManipParams *p_FmPcdManipParams);
++
++/**************************************************************************//**
++ @Function      FM_PCD_ManipNodeDelete
++
++ @Description   Delete an existing manipulation node.
++
++ @Param[in]     h_ManipNode     A handle to a manipulation node.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_ManipNodeSet().
++*//***************************************************************************/
++t_Error  FM_PCD_ManipNodeDelete(t_Handle h_ManipNode);
++
++/**************************************************************************//**
++ @Function      FM_PCD_ManipGetStatistics
++
++ @Description   Retrieve the manipulation statistics.
++
++ @Param[in]     h_ManipNode         A handle to a manipulation node.
++ @Param[out]    p_FmPcdManipStats   A structure for retrieving the manipulation statistics
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_ManipNodeSet().
++*//***************************************************************************/
++t_Error FM_PCD_ManipGetStatistics(t_Handle h_ManipNode, t_FmPcdManipStats *p_FmPcdManipStats);
++
++/**************************************************************************//**
++ @Function      FM_PCD_ManipNodeReplace
++
++ @Description   Change existing manipulation node to be according to new requirement.
++
++ @Param[in]     h_ManipNode         A handle to a manipulation node.
++ @Param[out]    p_ManipParams       A structure of parameters defining the change requirement
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_ManipNodeSet().
++*//***************************************************************************/
++t_Error FM_PCD_ManipNodeReplace(t_Handle h_ManipNode, t_FmPcdManipParams *p_ManipParams);
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Function      FM_PCD_FrmReplicSetGroup
++
++ @Description   Initialize a Frame Replicator group.
++
++ @Param[in]     h_FmPcd                FM PCD module descriptor.
++ @Param[in]     p_FrmReplicGroupParam  A structure of parameters for the initialization of
++                                       the frame replicator group.
++
++ @Return        A handle to the initialized object on success; NULL code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++t_Handle FM_PCD_FrmReplicSetGroup(t_Handle h_FmPcd, t_FmPcdFrmReplicGroupParams *p_FrmReplicGroupParam);
++
++/**************************************************************************//**
++ @Function      FM_PCD_FrmReplicDeleteGroup
++
++ @Description   Delete a Frame Replicator group.
++
++ @Param[in]     h_FrmReplicGroup  A handle to the frame replicator group.
++
++ @Return        E_OK on success;  Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_FrmReplicSetGroup().
++*//***************************************************************************/
++t_Error FM_PCD_FrmReplicDeleteGroup(t_Handle h_FrmReplicGroup);
++
++/**************************************************************************//**
++ @Function      FM_PCD_FrmReplicAddMember
++
++ @Description   Add the member in the index defined by the memberIndex.
++
++ @Param[in]     h_FrmReplicGroup   A handle to the frame replicator group.
++ @Param[in]     memberIndex        member index for adding.
++ @Param[in]     p_MemberParams     A pointer to the new member parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_FrmReplicSetGroup() of this group.
++*//***************************************************************************/
++t_Error FM_PCD_FrmReplicAddMember(t_Handle                   h_FrmReplicGroup,
++                                  uint16_t                   memberIndex,
++                                  t_FmPcdCcNextEngineParams *p_MemberParams);
++
++/**************************************************************************//**
++ @Function      FM_PCD_FrmReplicRemoveMember
++
++ @Description   Remove the member defined by the index from the relevant group.
++
++ @Param[in]     h_FrmReplicGroup   A handle to the frame replicator group.
++ @Param[in]     memberIndex        member index for removing.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_FrmReplicSetGroup() of this group.
++*//***************************************************************************/
++t_Error FM_PCD_FrmReplicRemoveMember(t_Handle h_FrmReplicGroup,
++                                     uint16_t memberIndex);
++#endif /* (DPAA_VERSION >= 11) */
++
++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++/**************************************************************************//**
++ @Function      FM_PCD_StatisticsSetNode
++
++ @Description   This routine should be called for defining a statistics node.
++
++ @Param[in]     h_FmPcd             FM PCD module descriptor.
++ @Param[in]     p_FmPcdstatsParams  A structure of parameters defining the statistics
++
++ @Return        A handle to the initialized object on success; NULL code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++t_Handle FM_PCD_StatisticsSetNode(t_Handle h_FmPcd, t_FmPcdStatsParams *p_FmPcdstatsParams);
++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
++
++/** @} */ /* end of FM_PCD_Runtime_build_grp group */
++/** @} */ /* end of FM_PCD_Runtime_grp group */
++/** @} */ /* end of FM_PCD_grp group */
++/** @} */ /* end of FM_grp group */
++
++
++#ifdef NCSW_BACKWARD_COMPATIBLE_API
++#define FM_PCD_MAX_NUM_OF_INTERCHANGABLE_HDRS   FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS
++#define e_FM_PCD_MANIP_ONE_WAYS_HASH            e_FM_PCD_MANIP_ONE_WAY_HASH
++#define e_FM_PCD_MANIP_TOW_WAYS_HASH            e_FM_PCD_MANIP_TWO_WAYS_HASH
++
++#define e_FM_PCD_MANIP_FRAGMENT_PACKECT         e_FM_PCD_MANIP_FRAGMENT_PACKET /* Feb13 */
++
++#define FM_PCD_SetNetEnvCharacteristics(_pcd, _params)  \
++    FM_PCD_NetEnvCharacteristicsSet(_pcd, _params)
++#define FM_PCD_KgSetScheme(_pcd, _params)       FM_PCD_KgSchemeSet(_pcd, _params)
++#define FM_PCD_CcBuildTree(_pcd, _params)       FM_PCD_CcRootBuild(_pcd, _params)
++#define FM_PCD_CcSetNode(_pcd, _params)         FM_PCD_MatchTableSet(_pcd, _params)
++#define FM_PCD_PlcrSetProfile(_pcd, _params)    FM_PCD_PlcrProfileSet(_pcd, _params)
++#define FM_PCD_ManipSetNode(_pcd, _params)      FM_PCD_ManipNodeSet(_pcd, _params)
++
++#define FM_PCD_DeleteNetEnvCharacteristics(_pcd, ...)   \
++    FM_PCD_NetEnvCharacteristicsDelete(__VA_ARGS__)
++#define FM_PCD_KgDeleteScheme(_pcd, ...)   \
++    FM_PCD_KgSchemeDelete(__VA_ARGS__)
++#define FM_PCD_KgGetSchemeCounter(_pcd, ...)   \
++    FM_PCD_KgSchemeGetCounter(__VA_ARGS__)
++#define FM_PCD_KgSetSchemeCounter(_pcd, ...)   \
++    FM_PCD_KgSchemeSetCounter(__VA_ARGS__)
++#define FM_PCD_PlcrDeleteProfile(_pcd, ...)   \
++    FM_PCD_PlcrProfileDelete(__VA_ARGS__)
++#define FM_PCD_PlcrGetProfileCounter(_pcd, ...)   \
++    FM_PCD_PlcrProfileGetCounter(__VA_ARGS__)
++#define FM_PCD_PlcrSetProfileCounter(_pcd, ...)   \
++    FM_PCD_PlcrProfileSetCounter(__VA_ARGS__)
++#define FM_PCD_CcDeleteTree(_pcd, ...)   \
++    FM_PCD_CcRootDelete(__VA_ARGS__)
++#define FM_PCD_CcTreeModifyNextEngine(_pcd, ...)   \
++    FM_PCD_CcRootModifyNextEngine(__VA_ARGS__)
++#define FM_PCD_CcDeleteNode(_pcd, ...)   \
++    FM_PCD_MatchTableDelete(__VA_ARGS__)
++#define FM_PCD_CcNodeModifyMissNextEngine(_pcd, ...)   \
++    FM_PCD_MatchTableModifyMissNextEngine(__VA_ARGS__)
++#define FM_PCD_CcNodeRemoveKey(_pcd, ...)   \
++    FM_PCD_MatchTableRemoveKey(__VA_ARGS__)
++#define FM_PCD_CcNodeAddKey(_pcd, ...)   \
++    FM_PCD_MatchTableAddKey(__VA_ARGS__)
++#define FM_PCD_CcNodeModifyNextEngine(_pcd, ...)   \
++    FM_PCD_MatchTableModifyNextEngine(__VA_ARGS__)
++#define FM_PCD_CcNodeModifyKeyAndNextEngine(_pcd, ...)   \
++    FM_PCD_MatchTableModifyKeyAndNextEngine(__VA_ARGS__)
++#define FM_PCD_CcNodeModifyKey(_pcd, ...)   \
++    FM_PCD_MatchTableModifyKey(__VA_ARGS__)
++#define FM_PCD_CcNodeFindNRemoveKey(_pcd, ...)   \
++    FM_PCD_MatchTableFindNRemoveKey(__VA_ARGS__)
++#define FM_PCD_CcNodeFindNModifyNextEngine(_pcd, ...)   \
++    FM_PCD_MatchTableFindNModifyNextEngine(__VA_ARGS__)
++#define FM_PCD_CcNodeFindNModifyKeyAndNextEngine(_pcd, ...) \
++    FM_PCD_MatchTableFindNModifyKeyAndNextEngine(__VA_ARGS__)
++#define FM_PCD_CcNodeFindNModifyKey(_pcd, ...)   \
++    FM_PCD_MatchTableFindNModifyKey(__VA_ARGS__)
++#define FM_PCD_CcIndexedHashNodeGetBucket(_pcd, ...)   \
++    FM_PCD_MatchTableGetIndexedHashBucket(__VA_ARGS__)
++#define FM_PCD_CcNodeGetNextEngine(_pcd, ...)   \
++    FM_PCD_MatchTableGetNextEngine(__VA_ARGS__)
++#define FM_PCD_CcNodeGetKeyCounter(_pcd, ...)   \
++    FM_PCD_MatchTableGetKeyCounter(__VA_ARGS__)
++#define FM_PCD_ManipDeleteNode(_pcd, ...)   \
++    FM_PCD_ManipNodeDelete(__VA_ARGS__)
++#endif /* NCSW_BACKWARD_COMPATIBLE_API */
++
++
++#endif /* __FM_PCD_EXT */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_port_ext.h
+@@ -0,0 +1,2608 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          fm_port_ext.h
++
++ @Description   FM-Port Application Programming Interface.
++*//***************************************************************************/
++#ifndef __FM_PORT_EXT
++#define __FM_PORT_EXT
++
++#include "error_ext.h"
++#include "std_ext.h"
++#include "fm_pcd_ext.h"
++#include "fm_ext.h"
++#include "net_ext.h"
++
++
++/**************************************************************************//**
++
++ @Group         FM_grp Frame Manager API
++
++ @Description   FM API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         FM_PORT_grp FM Port
++
++ @Description   FM Port API
++
++                The FM uses a general module called "port" to represent a Tx port
++                (MAC), an Rx port (MAC) or Offline Parsing port.
++                The number of ports in an FM varies between SOCs.
++                The SW driver manages these ports as sub-modules of the FM, i.e.
++                after an FM is initialized, its ports may be initialized and
++                operated upon.
++
++                The port is initialized aware of its type, but other functions on
++                a port may be indifferent to its type. When necessary, the driver
++                verifies coherence and returns error if applicable.
++
++                On initialization, user specifies the port type and it's index
++                (relative to the port's type) - always starting at 0.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   An enum for defining port PCD modes.
++                This enum defines the superset of PCD engines support - i.e. not
++                all engines have to be used, but all have to be enabled. The real
++                flow of a specific frame depends on the PCD configuration and the
++                frame headers and payload.
++                Note: the first engine and the first engine after the parser (if
++                exists) should be in order, the order is important as it will
++                define the flow of the port. However, as for the rest engines
++                (the ones that follows), the order is not important anymore as
++                it is defined by the PCD graph itself.
++*//***************************************************************************/
++typedef enum e_FmPortPcdSupport {
++      e_FM_PORT_PCD_SUPPORT_NONE = 0                /**< BMI to BMI, PCD is not used */
++    , e_FM_PORT_PCD_SUPPORT_PRS_ONLY                /**< Use only Parser */
++    , e_FM_PORT_PCD_SUPPORT_PLCR_ONLY               /**< Use only Policer */
++    , e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR            /**< Use Parser and Policer */
++    , e_FM_PORT_PCD_SUPPORT_PRS_AND_KG              /**< Use Parser and Keygen */
++    , e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC       /**< Use Parser, Keygen and Coarse Classification */
++    , e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR
++                                                    /**< Use all PCD engines */
++    , e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR     /**< Use Parser, Keygen and Policer */
++    , e_FM_PORT_PCD_SUPPORT_PRS_AND_CC              /**< Use Parser and Coarse Classification */
++    , e_FM_PORT_PCD_SUPPORT_PRS_AND_CC_AND_PLCR     /**< Use Parser and Coarse Classification and Policer */
++    , e_FM_PORT_PCD_SUPPORT_CC_ONLY                 /**< Use only Coarse Classification */
++#ifdef FM_CAPWAP_SUPPORT
++    , e_FM_PORT_PCD_SUPPORT_CC_AND_KG               /**< Use Coarse Classification,and Keygen */
++    , e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR      /**< Use Coarse Classification, Keygen and Policer */
++#endif /* FM_CAPWAP_SUPPORT */
++} e_FmPortPcdSupport;
++
++/**************************************************************************//**
++ @Description   Port interrupts
++*//***************************************************************************/
++typedef enum e_FmPortExceptions {
++    e_FM_PORT_EXCEPTION_IM_BUSY                 /**< Independent-Mode Rx-BUSY */
++} e_FmPortExceptions;
++
++
++/**************************************************************************//**
++ @Collection    General FM Port defines
++*//***************************************************************************/
++#define FM_PORT_PRS_RESULT_NUM_OF_WORDS     8   /**< Number of 4 bytes words in parser result */
++/* @} */
++
++/**************************************************************************//**
++ @Collection   FM Frame error
++*//***************************************************************************/
++typedef uint32_t    fmPortFrameErrSelect_t;                         /**< typedef for defining Frame Descriptor errors */
++
++#define FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT      FM_FD_ERR_UNSUPPORTED_FORMAT    /**< Not for Rx-Port! Unsupported Format */
++#define FM_PORT_FRM_ERR_LENGTH                  FM_FD_ERR_LENGTH                /**< Not for Rx-Port! Length Error */
++#define FM_PORT_FRM_ERR_DMA                     FM_FD_ERR_DMA                   /**< DMA Data error */
++#define FM_PORT_FRM_ERR_NON_FM                  FM_FD_RX_STATUS_ERR_NON_FM      /**< non Frame-Manager error; probably come from SEC that
++                                                                                     was chained to FM */
++
++#define FM_PORT_FRM_ERR_IPRE                    (FM_FD_ERR_IPR & ~FM_FD_IPR)        /**< IPR error */
++#define FM_PORT_FRM_ERR_IPR_NCSP                (FM_FD_ERR_IPR_NCSP & ~FM_FD_IPR)   /**< IPR non-consistent-sp */
++
++#define FM_PORT_FRM_ERR_IPFE                    0                                   /**< Obsolete; will be removed in the future */
++
++#ifdef FM_CAPWAP_SUPPORT
++#define FM_PORT_FRM_ERR_CRE                     FM_FD_ERR_CRE
++#define FM_PORT_FRM_ERR_CHE                     FM_FD_ERR_CHE
++#endif /* FM_CAPWAP_SUPPORT */
++
++#define FM_PORT_FRM_ERR_PHYSICAL                FM_FD_ERR_PHYSICAL              /**< Rx FIFO overflow, FCS error, code error, running disparity
++                                                                                     error (SGMII and TBI modes), FIFO parity error. PHY
++                                                                                     Sequence error, PHY error control character detected. */
++#define FM_PORT_FRM_ERR_SIZE                    FM_FD_ERR_SIZE                  /**< Frame too long OR Frame size exceeds max_length_frame  */
++#define FM_PORT_FRM_ERR_CLS_DISCARD             FM_FD_ERR_CLS_DISCARD           /**< indicates a classifier "drop" operation */
++#define FM_PORT_FRM_ERR_EXTRACTION              FM_FD_ERR_EXTRACTION            /**< Extract Out of Frame */
++#define FM_PORT_FRM_ERR_NO_SCHEME               FM_FD_ERR_NO_SCHEME             /**< No Scheme Selected */
++#define FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW        FM_FD_ERR_KEYSIZE_OVERFLOW      /**< Keysize Overflow */
++#define FM_PORT_FRM_ERR_COLOR_RED               FM_FD_ERR_COLOR_RED             /**< Frame color is red */
++#define FM_PORT_FRM_ERR_COLOR_YELLOW            FM_FD_ERR_COLOR_YELLOW          /**< Frame color is yellow */
++#define FM_PORT_FRM_ERR_ILL_PLCR                FM_FD_ERR_ILL_PLCR              /**< Illegal Policer Profile selected */
++#define FM_PORT_FRM_ERR_PLCR_FRAME_LEN          FM_FD_ERR_PLCR_FRAME_LEN        /**< Policer frame length error */
++#define FM_PORT_FRM_ERR_PRS_TIMEOUT             FM_FD_ERR_PRS_TIMEOUT           /**< Parser Time out Exceed */
++#define FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT        FM_FD_ERR_PRS_ILL_INSTRUCT      /**< Invalid Soft Parser instruction */
++#define FM_PORT_FRM_ERR_PRS_HDR_ERR             FM_FD_ERR_PRS_HDR_ERR           /**< Header error was identified during parsing */
++#define FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED    FM_FD_ERR_BLOCK_LIMIT_EXCEEDED  /**< Frame parsed beyind 256 first bytes */
++#define FM_PORT_FRM_ERR_PROCESS_TIMEOUT         0x00000001                      /**< FPM Frame Processing Timeout Exceeded */
++/* @} */
++
++
++
++/**************************************************************************//**
++ @Group         FM_PORT_init_grp FM Port Initialization Unit
++
++ @Description   FM Port Initialization Unit
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   Exceptions user callback routine, will be called upon an
++                exception passing the exception identification.
++
++ @Param[in]     h_App      - User's application descriptor.
++ @Param[in]     exception  - The exception.
++  *//***************************************************************************/
++typedef void (t_FmPortExceptionCallback) (t_Handle h_App, e_FmPortExceptions exception);
++
++/**************************************************************************//**
++ @Description   User callback function called by driver with received data.
++
++                User provides this function. Driver invokes it.
++
++ @Param[in]     h_App           Application's handle originally specified to
++                                the API Config function
++ @Param[in]     p_Data          A pointer to data received
++ @Param[in]     length          length of received data
++ @Param[in]     status          receive status and errors
++ @Param[in]     position        position of buffer in frame
++ @Param[in]     h_BufContext    A handle of the user acossiated with this buffer
++
++ @Retval        e_RX_STORE_RESPONSE_CONTINUE - order the driver to continue Rx
++                                               operation for all ready data.
++ @Retval        e_RX_STORE_RESPONSE_PAUSE    - order the driver to stop Rx operation.
++*//***************************************************************************/
++typedef e_RxStoreResponse (t_FmPortImRxStoreCallback) (t_Handle h_App,
++                                                       uint8_t  *p_Data,
++                                                       uint16_t length,
++                                                       uint16_t status,
++                                                       uint8_t  position,
++                                                       t_Handle h_BufContext);
++
++/**************************************************************************//**
++ @Description   User callback function called by driver when transmit completed.
++
++                User provides this function. Driver invokes it.
++
++ @Param[in]     h_App           Application's handle originally specified to
++                                the API Config function
++ @Param[in]     p_Data          A pointer to data received
++ @Param[in]     status          transmit status and errors
++ @Param[in]     lastBuffer      is last buffer in frame
++ @Param[in]     h_BufContext    A handle of the user acossiated with this buffer
++ *//***************************************************************************/
++typedef void (t_FmPortImTxConfCallback) (t_Handle   h_App,
++                                         uint8_t    *p_Data,
++                                         uint16_t   status,
++                                         t_Handle   h_BufContext);
++
++/**************************************************************************//**
++ @Description   A structure for additional Rx port parameters
++*//***************************************************************************/
++typedef struct t_FmPortRxParams {
++    uint32_t                errFqid;            /**< Error Queue Id. */
++    uint32_t                dfltFqid;           /**< Default Queue Id.  */
++    uint16_t                liodnOffset;        /**< Port's LIODN offset. */
++    t_FmExtPools            extBufPools;        /**< Which external buffer pools are used
++                                                     (up to FM_PORT_MAX_NUM_OF_EXT_POOLS), and their sizes. */
++} t_FmPortRxParams;
++
++/**************************************************************************//**
++ @Description   A structure for additional non-Rx port parameters
++*//***************************************************************************/
++typedef struct t_FmPortNonRxParams {
++    uint32_t                errFqid;            /**< Error Queue Id. */
++    uint32_t                dfltFqid;           /**< For Tx - Default Confirmation queue,
++                                                     0 means no Tx confirmation for processed
++                                                     frames. For OP port - default Rx queue. */
++    uint32_t                qmChannel;          /**< QM-channel dedicated to this port; will be used
++                                                     by the FM for dequeue. */
++} t_FmPortNonRxParams;
++
++/**************************************************************************//**
++ @Description   A structure for additional Rx port parameters
++*//***************************************************************************/
++typedef struct t_FmPortImRxTxParams {
++    t_Handle                    h_FmMuram;          /**< A handle of the FM-MURAM partition */
++    uint16_t                    liodnOffset;        /**< For Rx ports only. Port's LIODN Offset. */
++    uint8_t                     dataMemId;          /**< Memory partition ID for data buffers */
++    uint32_t                    dataMemAttributes;  /**< Memory attributes for data buffers */
++    t_BufferPoolInfo            rxPoolParams;       /**< For Rx ports only. */
++    t_FmPortImRxStoreCallback   *f_RxStore;         /**< For Rx ports only. */
++    t_FmPortImTxConfCallback    *f_TxConf;          /**< For Tx ports only. */
++} t_FmPortImRxTxParams;
++
++/**************************************************************************//**
++ @Description   A union for additional parameters depending on port type
++*//***************************************************************************/
++typedef union u_FmPortSpecificParams {
++    t_FmPortImRxTxParams        imRxTxParams;       /**< Rx/Tx Independent-Mode port parameter structure */
++    t_FmPortRxParams            rxParams;           /**< Rx port parameters structure */
++    t_FmPortNonRxParams         nonRxParams;        /**< Non-Rx port parameters structure */
++} u_FmPortSpecificParams;
++
++/**************************************************************************//**
++ @Description   A structure representing FM initialization parameters
++*//***************************************************************************/
++typedef struct t_FmPortParams {
++    uintptr_t                   baseAddr;           /**< Virtual Address of memory mapped FM Port registers.*/
++    t_Handle                    h_Fm;               /**< A handle to the FM object this port related to */
++    e_FmPortType                portType;           /**< Port type */
++    uint8_t                     portId;             /**< Port Id - relative to type;
++                                                         NOTE: When configuring Offline Parsing port for
++                                                         FMANv3 devices (DPAA_VERSION 11 and higher),
++                                                         it is highly recommended NOT to use portId=0 due to lack
++                                                         of HW resources on portId=0. */
++    bool                        independentModeEnable;
++                                                    /**< This port is Independent-Mode - Used for Rx/Tx ports only! */
++    uint16_t                    liodnBase;          /**< Irrelevant for P4080 rev 1. LIODN base for this port, to be
++                                                         used together with LIODN offset. */
++    u_FmPortSpecificParams      specificParams;     /**< Additional parameters depending on port
++                                                         type. */
++
++    t_FmPortExceptionCallback   *f_Exception;       /**< Relevant for IM only Callback routine to be called on BUSY exception */
++    t_Handle                    h_App;              /**< A handle to an application layer object; This handle will
++                                                         be passed by the driver upon calling the above callbacks */
++} t_FmPortParams;
++
++
++/**************************************************************************//**
++ @Function      FM_PORT_Config
++
++ @Description   Creates a descriptor for the FM PORT module.
++
++                The routine returns a handle (descriptor) to the FM PORT object.
++                This descriptor must be passed as first parameter to all other
++                FM PORT function calls.
++
++                No actual initialization or configuration of FM hardware is
++                done by this routine.
++
++ @Param[in]     p_FmPortParams   - Pointer to data structure of parameters
++
++ @Retval        Handle to FM object, or NULL for Failure.
++*//***************************************************************************/
++t_Handle FM_PORT_Config(t_FmPortParams *p_FmPortParams);
++
++/**************************************************************************//**
++ @Function      FM_PORT_Init
++
++ @Description   Initializes the FM PORT module by defining the software structure
++                and configuring the hardware registers.
++
++ @Param[in]     h_FmPort - FM PORT module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_PORT_Init(t_Handle h_FmPort);
++
++/**************************************************************************//**
++ @Function      FM_PORT_Free
++
++ @Description   Frees all resources that were assigned to FM PORT module.
++
++                Calling this routine invalidates the descriptor.
++
++ @Param[in]     h_FmPort - FM PORT module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_PORT_Free(t_Handle h_FmPort);
++
++
++/**************************************************************************//**
++ @Group         FM_PORT_advanced_init_grp    FM Port Advanced Configuration Unit
++
++ @Description   Configuration functions used to change default values.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   enum for defining QM frame dequeue
++*//***************************************************************************/
++typedef enum e_FmPortDeqType {
++   e_FM_PORT_DEQ_TYPE1,             /**< Dequeue from the SP channel - with priority precedence,
++                                         and Intra-Class Scheduling respected. */
++   e_FM_PORT_DEQ_TYPE2,             /**< Dequeue from the SP channel - with active FQ precedence,
++                                         and Intra-Class Scheduling respected. */
++   e_FM_PORT_DEQ_TYPE3              /**< Dequeue from the SP channel - with active FQ precedence,
++                                         and override Intra-Class Scheduling */
++} e_FmPortDeqType;
++
++/**************************************************************************//**
++ @Description   enum for defining QM frame dequeue
++*//***************************************************************************/
++typedef enum e_FmPortDeqPrefetchOption {
++   e_FM_PORT_DEQ_NO_PREFETCH,       /**< QMI preforms a dequeue action for a single frame
++                                         only when a dedicated portID Tnum is waiting. */
++   e_FM_PORT_DEQ_PARTIAL_PREFETCH,  /**< QMI preforms a dequeue action for 3 frames when
++                                         one dedicated portId tnum is waiting. */
++   e_FM_PORT_DEQ_FULL_PREFETCH      /**< QMI preforms a dequeue action for 3 frames when
++                                         no dedicated portId tnums are waiting. */
++
++} e_FmPortDeqPrefetchOption;
++
++/**************************************************************************//**
++ @Description   enum for defining port default color
++*//***************************************************************************/
++typedef enum e_FmPortColor {
++    e_FM_PORT_COLOR_GREEN,          /**< Default port color is green */
++    e_FM_PORT_COLOR_YELLOW,         /**< Default port color is yellow */
++    e_FM_PORT_COLOR_RED,            /**< Default port color is red */
++    e_FM_PORT_COLOR_OVERRIDE        /**< Ignore color */
++} e_FmPortColor;
++
++/**************************************************************************//**
++ @Description   A structure for defining Dual Tx rate limiting scale
++*//***************************************************************************/
++typedef enum e_FmPortDualRateLimiterScaleDown {
++    e_FM_PORT_DUAL_RATE_LIMITER_NONE = 0,           /**< Use only single rate limiter  */
++    e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_2,    /**< Divide high rate limiter by 2 */
++    e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_4,    /**< Divide high rate limiter by 4 */
++    e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8     /**< Divide high rate limiter by 8 */
++} e_FmPortDualRateLimiterScaleDown;
++
++
++/**************************************************************************//**
++ @Description   A structure for defining FM port resources
++*//***************************************************************************/
++typedef struct t_FmPortRsrc {
++    uint32_t    num;                /**< Committed required resource */
++    uint32_t    extra;              /**< Extra (not committed) required resource */
++} t_FmPortRsrc;
++
++/**************************************************************************//**
++ @Description   A structure for defining observed pool depletion
++*//***************************************************************************/
++typedef struct t_FmPortObservedBufPoolDepletion {
++    t_FmBufPoolDepletion    poolDepletionParams;/**< parameters to define pool depletion */
++    t_FmExtPools            poolsParams;        /**< Which external buffer pools are observed
++                                                     (up to FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS),
++                                                     and their sizes. */
++} t_FmPortObservedBufPoolDepletion;
++
++/**************************************************************************//**
++ @Description   A structure for defining Tx rate limiting
++*//***************************************************************************/
++typedef struct t_FmPortRateLimit {
++    uint16_t                            maxBurstSize;           /**< in KBytes for Tx ports, in frames
++                                                                     for OP ports. (note that
++                                                                     for early chips burst size is
++                                                                     rounded up to a multiply of 1000 frames).*/
++    uint32_t                            rateLimit;              /**< in Kb/sec for Tx ports, in frame/sec for
++                                                                     OP ports. Rate limit refers to
++                                                                     data rate (rather than line rate). */
++    e_FmPortDualRateLimiterScaleDown    rateLimitDivider;       /**< For OP ports only. Not-valid
++                                                                     for some earlier chip revisions */
++} t_FmPortRateLimit;
++
++/**************************************************************************//**
++ @Description   A structure for defining the parameters of
++                the Rx port performance counters
++*//***************************************************************************/
++typedef struct t_FmPortPerformanceCnt {
++    uint8_t     taskCompVal;            /**< Task compare value */
++    uint8_t     queueCompVal;           /**< Rx queue/Tx confirm queue compare
++                                             value (unused for H/O) */
++    uint8_t     dmaCompVal;             /**< Dma compare value */
++    uint32_t    fifoCompVal;            /**< Fifo compare value (in bytes) */
++} t_FmPortPerformanceCnt;
++
++
++/**************************************************************************//**
++ @Description   A structure for defining the sizes of the Deep Sleep
++                the Auto Response tables
++*//***************************************************************************/
++typedef struct t_FmPortDsarTablesSizes
++{
++    uint16_t   maxNumOfArpEntries;
++    uint16_t   maxNumOfEchoIpv4Entries;
++    uint16_t   maxNumOfNdpEntries;
++    uint16_t   maxNumOfEchoIpv6Entries;
++    uint16_t   maxNumOfSnmpIPV4Entries;
++    uint16_t   maxNumOfSnmpIPV6Entries;
++    uint16_t   maxNumOfSnmpOidEntries;
++    uint16_t   maxNumOfSnmpOidChar; /* total amount of character needed for the snmp table */
++
++    uint16_t   maxNumOfIpProtFiltering;
++    uint16_t   maxNumOfTcpPortFiltering;
++    uint16_t   maxNumOfUdpPortFiltering;
++} t_FmPortDsarTablesSizes;
++
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigDsarSupport
++
++ @Description   This function will allocate the amount of MURAM needed for
++                this max number of entries for Deep Sleep Auto Response.
++                it will calculate all needed MURAM for autoresponse including
++                necesary common stuff.
++
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[in]     params      A pointer to a structure containing the maximum
++                            sizes of the auto response tables
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigDsarSupport(t_Handle h_FmPortRx, t_FmPortDsarTablesSizes *params);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigNumOfOpenDmas
++
++ @Description   Calling this routine changes the max number of open DMA's
++                available for this port. It changes this parameter in the
++                internal driver data base from its default configuration
++                [OP: 1]
++                [1G-RX, 1G-TX: 1 (+1)]
++                [10G-RX, 10G-TX: 8 (+8)]
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[in]     p_OpenDmas  A pointer to a structure of parameters defining
++                            the open DMA allocation.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigNumOfOpenDmas(t_Handle h_FmPort, t_FmPortRsrc *p_OpenDmas);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigNumOfTasks
++
++ @Description   Calling this routine changes the max number of tasks
++                available for this port. It changes this parameter in the
++                internal driver data base from its default configuration
++                [OP: 1]
++                [1G-RX, 1G-TX: 3 (+2)]
++                [10G-RX, 10G-TX: 16 (+8)]
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     p_NumOfTasks    A pointer to a structure of parameters defining
++                                the tasks allocation.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigSizeOfFifo
++
++ @Description   Calling this routine changes the max FIFO size configured for this port.
++
++                This function changes the internal driver data base from its
++                default configuration. Please refer to the driver's User Guide for
++                information on default FIFO sizes in the various devices.
++                [OP: 2KB]
++                [1G-RX, 1G-TX: 11KB]
++                [10G-RX, 10G-TX: 12KB]
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     p_SizeOfFifo    A pointer to a structure of parameters defining
++                                the FIFO allocation.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigDeqHighPriority
++
++ @Description   Calling this routine changes the dequeue priority in the
++                internal driver data base from its default configuration
++                1G: [DEFAULT_PORT_deqHighPriority_1G]
++                10G: [DEFAULT_PORT_deqHighPriority_10G]
++
++                May be used for Non-Rx ports only
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[in]     highPri     TRUE to select high priority, FALSE for normal operation.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigDeqHighPriority(t_Handle h_FmPort, bool highPri);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigDeqType
++
++ @Description   Calling this routine changes the dequeue type parameter in the
++                internal driver data base from its default configuration
++                [DEFAULT_PORT_deqType].
++
++                May be used for Non-Rx ports only
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[in]     deqType     According to QM definition.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigDeqType(t_Handle h_FmPort, e_FmPortDeqType deqType);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigDeqPrefetchOption
++
++ @Description   Calling this routine changes the dequeue prefetch option parameter in the
++                internal driver data base from its default configuration
++                [DEFAULT_PORT_deqPrefetchOption]
++                Note: Available for some chips only
++
++                May be used for Non-Rx ports only
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     deqPrefetchOption   New option
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigDeqPrefetchOption(t_Handle h_FmPort, e_FmPortDeqPrefetchOption deqPrefetchOption);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigDeqByteCnt
++
++ @Description   Calling this routine changes the dequeue byte count parameter in
++                the internal driver data base from its default configuration
++                1G:[DEFAULT_PORT_deqByteCnt_1G].
++                10G:[DEFAULT_PORT_deqByteCnt_10G].
++
++                May be used for Non-Rx ports only
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     deqByteCnt      New byte count
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigDeqByteCnt(t_Handle h_FmPort, uint16_t deqByteCnt);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigBufferPrefixContent
++
++ @Description   Defines the structure, size and content of the application buffer.
++                The prefix will
++                In Tx ports, if 'passPrsResult', the application
++                should set a value to their offsets in the prefix of
++                the FM will save the first 'privDataSize', than,
++                depending on 'passPrsResult' and 'passTimeStamp', copy parse result
++                and timeStamp, and the packet itself (in this order), to the
++                application buffer, and to offset.
++                Calling this routine changes the buffer margins definitions
++                in the internal driver data base from its default
++                configuration: Data size:  [DEFAULT_PORT_bufferPrefixContent_privDataSize]
++                               Pass Parser result: [DEFAULT_PORT_bufferPrefixContent_passPrsResult].
++                               Pass timestamp: [DEFAULT_PORT_bufferPrefixContent_passTimeStamp].
++
++                May be used for all ports
++
++ @Param[in]     h_FmPort                        A handle to a FM Port module.
++ @Param[in,out] p_FmBufferPrefixContent         A structure of parameters describing the
++                                                structure of the buffer.
++                                                Out parameter: Start margin - offset
++                                                of data from start of external buffer.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigBufferPrefixContent(t_Handle                      h_FmPort,
++                                          t_FmBufferPrefixContent       *p_FmBufferPrefixContent);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigCheksumLastBytesIgnore
++
++ @Description   Calling this routine changes the number of checksum bytes to ignore
++                parameter in the internal driver data base from its default configuration
++                [DEFAULT_PORT_cheksumLastBytesIgnore]
++
++                May be used by Tx & Rx ports only
++
++ @Param[in]     h_FmPort                A handle to a FM Port module.
++ @Param[in]     cheksumLastBytesIgnore  New value
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigCheksumLastBytesIgnore(t_Handle h_FmPort, uint8_t cheksumLastBytesIgnore);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigCutBytesFromEnd
++
++ @Description   Calling this routine changes the number of bytes to cut from a
++                frame's end parameter in the internal driver data base
++                from its default configuration [DEFAULT_PORT_cutBytesFromEnd]
++                Note that if the result of (frame length before chop - cutBytesFromEnd) is
++                less than 14 bytes, the chop operation is not executed.
++
++                May be used for Rx ports only
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     cutBytesFromEnd     New value
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigCutBytesFromEnd(t_Handle h_FmPort, uint8_t cutBytesFromEnd);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigPoolDepletion
++
++ @Description   Calling this routine enables pause frame generation depending on the
++                depletion status of BM pools. It also defines the conditions to activate
++                this functionality. By default, this functionality is disabled.
++
++                May be used for Rx ports only
++
++ @Param[in]     h_FmPort                A handle to a FM Port module.
++ @Param[in]     p_BufPoolDepletion      A structure of pool depletion parameters
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigPoolDepletion(t_Handle h_FmPort, t_FmBufPoolDepletion *p_BufPoolDepletion);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigObservedPoolDepletion
++
++ @Description   Calling this routine enables a mechanism to stop port enqueue
++                depending on the depletion status of selected BM pools.
++                It also defines the conditions to activate
++                this functionality. By default, this functionality is disabled.
++
++                Note: Available for some chips only
++
++                May be used for OP ports only
++
++ @Param[in]     h_FmPort                            A handle to a FM Port module.
++ @Param[in]     p_FmPortObservedBufPoolDepletion    A structure of parameters for pool depletion.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigObservedPoolDepletion(t_Handle                            h_FmPort,
++                                            t_FmPortObservedBufPoolDepletion    *p_FmPortObservedBufPoolDepletion);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigExtBufPools
++
++ @Description   This routine should be called for OP ports
++                that internally use BM buffer pools. In such cases, e.g. for fragmentation and
++                re-assembly, the FM needs new BM buffers. By calling this routine the user
++                specifies the BM buffer pools that should be used.
++
++                Note: Available for some chips only
++
++                May be used for OP ports only
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     p_FmExtPools        A structure of parameters for the external pools.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigExtBufPools(t_Handle h_FmPort, t_FmExtPools *p_FmExtPools);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigBackupPools
++
++ @Description   Calling this routine allows the configuration of some of the BM pools
++                defined for this port as backup pools.
++                A pool configured to be a backup pool will be used only if all other
++                enabled non-backup pools are depleted.
++
++                May be used for Rx ports only
++
++ @Param[in]     h_FmPort                A handle to a FM Port module.
++ @Param[in]     p_FmPortBackupBmPools   An array of pool id's. All pools specified here will
++                                        be defined as backup pools.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigBackupPools(t_Handle h_FmPort, t_FmBackupBmPools *p_FmPortBackupBmPools);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigFrmDiscardOverride
++
++ @Description   Calling this routine changes the error frames destination parameter
++                in the internal driver data base from its default configuration:
++                override = [DEFAULT_PORT_frmDiscardOverride]
++
++                May be used for Rx and OP ports only
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[in]     override    TRUE to override discarding of error frames and
++                            enqueueing them to error queue.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigFrmDiscardOverride(t_Handle h_FmPort, bool override);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigErrorsToDiscard
++
++ @Description   Calling this routine changes the behaviour on error parameter
++                in the internal driver data base from its default configuration:
++                [DEFAULT_PORT_errorsToDiscard].
++                If a requested error was previously defined as "ErrorsToEnqueue" it's
++                definition will change and the frame will be discarded.
++                Errors that were not defined either as "ErrorsToEnqueue" nor as
++                "ErrorsToDiscard", will be forwarded to CPU.
++
++                May be used for Rx and OP ports only
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[in]     errs        A list of errors to discard
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigErrorsToDiscard(t_Handle h_FmPort, fmPortFrameErrSelect_t errs);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigDmaSwapData
++
++ @Description   Calling this routine changes the DMA swap data aparameter
++                in the internal driver data base from its default
++                configuration  [DEFAULT_PORT_dmaSwapData]
++
++                May be used for all port types
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[in]     swapData    New selection
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigDmaSwapData(t_Handle h_FmPort, e_FmDmaSwapOption swapData);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigDmaIcCacheAttr
++
++ @Description   Calling this routine changes the internal context cache
++                attribute parameter in the internal driver data base
++                from its default configuration  [DEFAULT_PORT_dmaIntContextCacheAttr]
++
++                May be used for all port types
++
++ @Param[in]     h_FmPort               A handle to a FM Port module.
++ @Param[in]     intContextCacheAttr    New selection
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigDmaIcCacheAttr(t_Handle h_FmPort, e_FmDmaCacheOption intContextCacheAttr);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigDmaHdrAttr
++
++ @Description   Calling this routine changes the header cache
++                attribute parameter in the internal driver data base
++                from its default configuration  [DEFAULT_PORT_dmaHeaderCacheAttr]
++
++                May be used for all port types
++
++ @Param[in]     h_FmPort                    A handle to a FM Port module.
++ @Param[in]     headerCacheAttr             New selection
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigDmaHdrAttr(t_Handle h_FmPort, e_FmDmaCacheOption headerCacheAttr);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigDmaScatterGatherAttr
++
++ @Description   Calling this routine changes the scatter gather cache
++                attribute parameter in the internal driver data base
++                from its default configuration  [DEFAULT_PORT_dmaScatterGatherCacheAttr]
++
++                May be used for all port types
++
++ @Param[in]     h_FmPort                    A handle to a FM Port module.
++ @Param[in]     scatterGatherCacheAttr      New selection
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigDmaScatterGatherAttr(t_Handle h_FmPort, e_FmDmaCacheOption scatterGatherCacheAttr);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigDmaWriteOptimize
++
++ @Description   Calling this routine changes the write optimization
++                parameter in the internal driver data base
++                from its default configuration:  By default optimize = [DEFAULT_PORT_dmaWriteOptimize].
++                Note:
++
++                1. For head optimization, data alignment must be >= 16 (supported by default).
++
++                3. For tail optimization, note that the optimization is performed by extending the write transaction
++                of the frame payload at the tail as needed to achieve optimal bus transfers, so that the last write
++                is extended to be on 16/64 bytes aligned block (chip dependent).
++
++                Relevant for non-Tx port types
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[in]     optimize    TRUE to enable optimization, FALSE for normal operation
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigDmaWriteOptimize(t_Handle h_FmPort, bool optimize);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigNoScatherGather
++
++ @Description    Calling this routine changes the noScatherGather parameter in internal driver data base
++                 from its default configuration.
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     noScatherGather (TRUE - frame is discarded if can not be stored in single buffer,
++                                 FALSE - frame can be stored in scatter gather (S/G) format).
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigNoScatherGather(t_Handle h_FmPort, bool noScatherGather);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigDfltColor
++
++ @Description   Calling this routine changes the internal default color parameter
++                in the internal driver data base
++                from its default configuration  [DEFAULT_PORT_color]
++
++                May be used for all port types
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     color           New selection
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigDfltColor(t_Handle h_FmPort, e_FmPortColor color);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigSyncReq
++
++ @Description   Calling this routine changes the synchronization attribute parameter
++                in the internal driver data base from its default configuration:
++                syncReq = [DEFAULT_PORT_syncReq]
++
++                May be used for all port types
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     syncReq         TRUE to request synchronization, FALSE otherwize.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigSyncReq(t_Handle h_FmPort, bool syncReq);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigForwardReuseIntContext
++
++ @Description   This routine is relevant for Rx ports that are routed to OP port.
++                It changes the internal context reuse option in the internal
++                driver data base from its default configuration:
++                reuse = [DEFAULT_PORT_forwardIntContextReuse]
++
++                May be used for Rx ports only
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     reuse           TRUE to reuse internal context on frames
++                                forwarded to OP port.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigForwardReuseIntContext(t_Handle h_FmPort, bool reuse);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigDontReleaseTxBufToBM
++
++ @Description   This routine should be called if no Tx confirmation
++                is done, and yet buffers should not be released to the BM.
++                Normally, buffers are returned using the Tx confirmation
++                process. When Tx confirmation is not used (defFqid=0),
++                buffers are typically released to the BM. This routine
++                may be called to avoid this behavior and not release the
++                buffers.
++
++                May be used for Tx ports only
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigDontReleaseTxBufToBM(t_Handle h_FmPort);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigIMMaxRxBufLength
++
++ @Description   Changes the maximum receive buffer length from its default
++                configuration: Closest rounded down power of 2 value of the
++                data buffer size.
++
++                The maximum receive buffer length directly affects the structure
++                of received frames (single- or multi-buffered) and the performance
++                of both the FM and the driver.
++
++                The selection between single- or multi-buffered frames should be
++                done according to the characteristics of the specific application.
++                The recommended mode is to use a single data buffer per packet,
++                as this mode provides the best performance. However, the user can
++                select to use multiple data buffers per packet.
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     newVal          Maximum receive buffer length (in bytes).
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++                This routine is to be used only if Independent-Mode is enabled.
++*//***************************************************************************/
++t_Error FM_PORT_ConfigIMMaxRxBufLength(t_Handle h_FmPort, uint16_t newVal);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigIMRxBdRingLength
++
++ @Description   Changes the receive BD ring length from its default
++                configuration:[DEFAULT_PORT_rxBdRingLength]
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     newVal          The desired BD ring length.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++                This routine is to be used only if Independent-Mode is enabled.
++*//***************************************************************************/
++t_Error FM_PORT_ConfigIMRxBdRingLength(t_Handle h_FmPort, uint16_t newVal);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigIMTxBdRingLength
++
++ @Description   Changes the transmit BD ring length from its default
++                configuration:[DEFAULT_PORT_txBdRingLength]
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     newVal          The desired BD ring length.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++                This routine is to be used only if Independent-Mode is enabled.
++*//***************************************************************************/
++t_Error FM_PORT_ConfigIMTxBdRingLength(t_Handle h_FmPort, uint16_t newVal);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigIMFmanCtrlExternalStructsMemory
++
++ @Description   Configures memory partition and attributes for FMan-Controller
++                data structures (e.g. BD rings).
++                Calling this routine changes the internal driver data base
++                from its default configuration
++                [DEFAULT_PORT_ImfwExtStructsMemId, DEFAULT_PORT_ImfwExtStructsMemAttr].
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     memId           Memory partition ID.
++ @Param[in]     memAttributes   Memory attributes mask (a combination of MEMORY_ATTR_x flags).
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error  FM_PORT_ConfigIMFmanCtrlExternalStructsMemory(t_Handle h_FmPort,
++                                                       uint8_t  memId,
++                                                       uint32_t memAttributes);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigIMPolling
++
++ @Description   Changes the Rx flow from interrupt driven (default) to polling.
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++                This routine is to be used only if Independent-Mode is enabled.
++*//***************************************************************************/
++t_Error FM_PORT_ConfigIMPolling(t_Handle h_FmPort);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigMaxFrameLength
++
++ @Description   Changes the definition of the max size of frame that should be
++                transmitted/received on this port from its default value [DEFAULT_PORT_maxFrameLength].
++                This parameter is used for confirmation of the minimum Fifo
++                size calculations and only for Tx ports or ports working in
++                independent mode. This should be larger than the maximum possible
++                MTU that will be used for this port (i.e. its MAC).
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     length          Max size of frame
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++                This routine is to be used only if Independent-Mode is enabled.
++*//***************************************************************************/
++t_Error FM_PORT_ConfigMaxFrameLength(t_Handle h_FmPort, uint16_t length);
++
++/**************************************************************************//*
++ @Function      FM_PORT_ConfigTxFifoMinFillLevel
++
++ @Description   Calling this routine changes the fifo minimum
++                fill level parameter in the internal driver data base
++                from its default configuration  [DEFAULT_PORT_txFifoMinFillLevel]
++
++                May be used for Tx ports only
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     minFillLevel    New value
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigTxFifoMinFillLevel(t_Handle h_FmPort, uint32_t minFillLevel);
++
++/**************************************************************************//*
++ @Function      FM_PORT_ConfigFifoDeqPipelineDepth
++
++ @Description   Calling this routine changes the fifo dequeue
++                pipeline depth parameter in the internal driver data base
++
++                from its default configuration: 1G ports: [DEFAULT_PORT_fifoDeqPipelineDepth_1G],
++                10G port: [DEFAULT_PORT_fifoDeqPipelineDepth_10G],
++                OP port: [DEFAULT_PORT_fifoDeqPipelineDepth_OH]
++
++                May be used for Tx/OP ports only
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     deqPipelineDepth    New value
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigFifoDeqPipelineDepth(t_Handle h_FmPort, uint8_t deqPipelineDepth);
++
++/**************************************************************************//*
++ @Function      FM_PORT_ConfigTxFifoLowComfLevel
++
++ @Description   Calling this routine changes the fifo low comfort level
++                parameter in internal driver data base
++                from its default configuration [DEFAULT_PORT_txFifoLowComfLevel]
++
++                May be used for Tx ports only
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     fifoLowComfLevel    New value
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigTxFifoLowComfLevel(t_Handle h_FmPort, uint32_t fifoLowComfLevel);
++
++/**************************************************************************//*
++ @Function      FM_PORT_ConfigRxFifoThreshold
++
++ @Description   Calling this routine changes the threshold of the FIFO
++                fill level parameter in the internal driver data base
++                from its default configuration [DEFAULT_PORT_rxFifoThreshold]
++
++                If the total number of buffers which are
++                currently in use and associated with the
++                specific RX port exceed this threshold, the
++                BMI will signal the MAC to send a pause frame
++                over the link.
++
++                May be used for Rx ports only
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     fifoThreshold       New value
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigRxFifoThreshold(t_Handle h_FmPort, uint32_t fifoThreshold);
++
++/**************************************************************************//*
++ @Function      FM_PORT_ConfigRxFifoPriElevationLevel
++
++ @Description   Calling this routine changes the priority elevation level
++                parameter in the internal driver data base from its default
++                configuration  [DEFAULT_PORT_rxFifoPriElevationLevel]
++
++                If the total number of buffers which are currently in use and
++                associated with the specific RX port exceed the amount specified
++                in priElevationLevel, BMI will signal the main FM's DMA to
++                elevate the FM priority on the system bus.
++
++                May be used for Rx ports only
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     priElevationLevel   New value
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigRxFifoPriElevationLevel(t_Handle h_FmPort, uint32_t priElevationLevel);
++
++#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
++/**************************************************************************//*
++ @Function      FM_PORT_ConfigBCBWorkaround
++
++ @Description   Configures BCB errata workaround.
++
++                When BCB errata is applicable, the workaround is always
++                performed by FM Controller. Thus, this functions doesn't
++                actually enable errata workaround but rather allows driver
++                to perform adjustments required due to errata workaround
++                execution in FM controller.
++
++                Applying BCB workaround also configures FM_PORT_FRM_ERR_PHYSICAL
++                errors to be discarded. Thus FM_PORT_FRM_ERR_PHYSICAL can't be
++                set by FM_PORT_SetErrorsRoute() function.
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigBCBWorkaround(t_Handle h_FmPort);
++#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//*
++ @Function      FM_PORT_ConfigInternalBuffOffset
++
++ @Description   Configures internal buffer offset.
++
++                May be used for Rx and OP ports only
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     val                 New value
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ConfigInternalBuffOffset(t_Handle h_FmPort, uint8_t val);
++#endif /* (DPAA_VERSION >= 11) */
++
++/** @} */ /* end of FM_PORT_advanced_init_grp group */
++/** @} */ /* end of FM_PORT_init_grp group */
++
++
++/**************************************************************************//**
++ @Group         FM_PORT_runtime_control_grp FM Port Runtime Control Unit
++
++ @Description   FM Port Runtime control unit API functions, definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   enum for defining FM Port counters
++*//***************************************************************************/
++typedef enum e_FmPortCounters {
++    e_FM_PORT_COUNTERS_CYCLE,                       /**< BMI performance counter */
++    e_FM_PORT_COUNTERS_TASK_UTIL,                   /**< BMI performance counter */
++    e_FM_PORT_COUNTERS_QUEUE_UTIL,                  /**< BMI performance counter */
++    e_FM_PORT_COUNTERS_DMA_UTIL,                    /**< BMI performance counter */
++    e_FM_PORT_COUNTERS_FIFO_UTIL,                   /**< BMI performance counter */
++    e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION,         /**< BMI Rx only performance counter */
++    e_FM_PORT_COUNTERS_FRAME,                       /**< BMI statistics counter */
++    e_FM_PORT_COUNTERS_DISCARD_FRAME,               /**< BMI statistics counter */
++    e_FM_PORT_COUNTERS_DEALLOC_BUF,                 /**< BMI deallocate buffer statistics counter */
++    e_FM_PORT_COUNTERS_RX_BAD_FRAME,                /**< BMI Rx only statistics counter */
++    e_FM_PORT_COUNTERS_RX_LARGE_FRAME,              /**< BMI Rx only statistics counter */
++    e_FM_PORT_COUNTERS_RX_FILTER_FRAME,             /**< BMI Rx & OP only statistics counter */
++    e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR,             /**< BMI Rx, OP & HC only statistics counter */
++    e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD,   /**< BMI Rx, OP & HC statistics counter */
++    e_FM_PORT_COUNTERS_PREPARE_TO_ENQUEUE_COUNTER,  /**< BMI Rx, OP & HC only statistics counter */
++    e_FM_PORT_COUNTERS_WRED_DISCARD,                /**< BMI OP & HC only statistics counter */
++    e_FM_PORT_COUNTERS_LENGTH_ERR,                  /**< BMI non-Rx statistics counter */
++    e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT,           /**< BMI non-Rx statistics counter */
++    e_FM_PORT_COUNTERS_DEQ_TOTAL,                   /**< QMI total QM dequeues counter */
++    e_FM_PORT_COUNTERS_ENQ_TOTAL,                   /**< QMI total QM enqueues counter */
++    e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT,            /**< QMI counter */
++    e_FM_PORT_COUNTERS_DEQ_CONFIRM                  /**< QMI counter */
++} e_FmPortCounters;
++
++typedef struct t_FmPortBmiStats {
++    uint32_t cntCycle;
++    uint32_t cntTaskUtil;
++    uint32_t cntQueueUtil;
++    uint32_t cntDmaUtil;
++    uint32_t cntFifoUtil;
++    uint32_t cntRxPauseActivation;
++    uint32_t cntFrame;
++    uint32_t cntDiscardFrame;
++    uint32_t cntDeallocBuf;
++    uint32_t cntRxBadFrame;
++    uint32_t cntRxLargeFrame;
++    uint32_t cntRxFilterFrame;
++    uint32_t cntRxListDmaErr;
++    uint32_t cntRxOutOfBuffersDiscard;
++    uint32_t cntWredDiscard;
++    uint32_t cntLengthErr;
++    uint32_t cntUnsupportedFormat;
++} t_FmPortBmiStats;
++
++/**************************************************************************//**
++ @Description   Structure for Port id parameters.
++                Fields commented 'IN' are passed by the port module to be used
++                by the FM module.
++                Fields commented 'OUT' will be filled by FM before returning to port.
++*//***************************************************************************/
++typedef struct t_FmPortCongestionGrps {
++    uint16_t    numOfCongestionGrpsToConsider;          /**< The number of required CGs
++                                                             to define the size of the following array */
++    uint8_t     congestionGrpsToConsider[FM_PORT_NUM_OF_CONGESTION_GRPS];
++                                                        /**< An array of CG indexes;
++                                                             Note that the size of the array should be
++                                                             'numOfCongestionGrpsToConsider'. */
++#if (DPAA_VERSION >= 11)
++    bool        pfcPrioritiesEn[FM_PORT_NUM_OF_CONGESTION_GRPS][FM_MAX_NUM_OF_PFC_PRIORITIES];
++                                                        /**< a matrix that represents the map between the CG ids
++                                                             defined in 'congestionGrpsToConsider' to the priorties
++                                                             mapping array. */
++#endif /* (DPAA_VERSION >= 11) */
++} t_FmPortCongestionGrps;
++
++/**************************************************************************//**
++ @Description   Structure for Deep Sleep Auto Response ARP Entry
++*//***************************************************************************/
++typedef struct t_FmPortDsarArpEntry
++{
++    uint32_t  ipAddress;
++    uint8_t   mac[6];
++    bool      isVlan;
++    uint16_t  vid;
++} t_FmPortDsarArpEntry;
++
++/**************************************************************************//**
++ @Description   Structure for Deep Sleep Auto Response ARP info
++*//***************************************************************************/
++typedef struct t_FmPortDsarArpInfo
++{
++    uint8_t           tableSize;
++    t_FmPortDsarArpEntry *p_AutoResTable;
++    bool              enableConflictDetection; /* when TRUE Conflict Detection will be checked and wake the host if needed */
++} t_FmPortDsarArpInfo;
++
++/**************************************************************************//**
++ @Description   Structure for Deep Sleep Auto Response NDP Entry
++*//***************************************************************************/
++typedef struct t_FmPortDsarNdpEntry
++{
++    uint32_t  ipAddress[4];
++    uint8_t   mac[6];
++    bool      isVlan;
++    uint16_t  vid;
++} t_FmPortDsarNdpEntry;
++
++/**************************************************************************//**
++ @Description   Structure for Deep Sleep Auto Response NDP info
++*//***************************************************************************/
++typedef struct t_FmPortDsarNdpInfo
++{
++    uint32_t              multicastGroup;
++
++    uint8_t               tableSizeAssigned;
++    t_FmPortDsarNdpEntry  *p_AutoResTableAssigned; /* This list refer to solicitation IP addresses.
++                                                                 Note that all IP adresses must be from the same multicast group.
++                                                                 This will be checked and if not operation will fail. */
++    uint8_t               tableSizeTmp;
++    t_FmPortDsarNdpEntry  *p_AutoResTableTmp;      /* This list refer to temp IP addresses.
++                                                             Note that all temp IP adresses must be from the same multicast group.
++                                                             This will be checked and if not operation will fail. */
++
++    bool                  enableConflictDetection; /* when TRUE Conflict Detection will be checked and wake the host if needed */
++
++} t_FmPortDsarNdpInfo;
++
++/**************************************************************************//**
++ @Description   Structure for Deep Sleep Auto Response ICMPV4 info
++*//***************************************************************************/
++typedef struct t_FmPortDsarEchoIpv4Info
++{
++    uint8_t            tableSize;
++    t_FmPortDsarArpEntry  *p_AutoResTable;
++} t_FmPortDsarEchoIpv4Info;
++
++/**************************************************************************//**
++ @Description   Structure for Deep Sleep Auto Response ICMPV6 info
++*//***************************************************************************/
++typedef struct t_FmPortDsarEchoIpv6Info
++{
++    uint8_t            tableSize;
++    t_FmPortDsarNdpEntry  *p_AutoResTable;
++} t_FmPortDsarEchoIpv6Info;
++
++/**************************************************************************//**
++@Description    Deep Sleep Auto Response SNMP OIDs table entry
++
++*//***************************************************************************/
++typedef struct {
++      uint16_t     oidSize;
++      uint8_t      *oidVal; /* only the oid string */
++      uint16_t     resSize;
++      uint8_t      *resVal; /* resVal will be the entire reply,
++                              i.e. "Type|Length|Value" */
++} t_FmPortDsarOidsEntry;
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response SNMP IPv4 Addresses Table Entry
++                Refer to the FMan Controller spec for more details.
++*//***************************************************************************/
++typedef struct
++{
++    uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */
++    bool      isVlan;
++    uint16_t vid;   /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared                      */
++                       /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
++} t_FmPortDsarSnmpIpv4AddrTblEntry;
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response SNMP IPv6 Addresses Table Entry
++                Refer to the FMan Controller spec for more details.
++*//***************************************************************************/
++typedef struct
++{
++    uint32_t ipv6Addr[4];  /*!< 4 * 32 bit IPv6 Address.                                                     */
++    bool      isVlan;
++    uint16_t vid;       /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared                      */
++                           /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
++} t_FmPortDsarSnmpIpv6AddrTblEntry;
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response SNMP Descriptor
++
++*//***************************************************************************/
++typedef struct
++{
++    uint16_t control;                          /**< Control bits [0-15]. */
++    uint16_t maxSnmpMsgLength;                 /**< Maximal allowed SNMP message length. */
++    uint16_t numOfIpv4Addresses;               /**< Number of entries in IPv4 addresses table. */
++    uint16_t numOfIpv6Addresses;               /**< Number of entries in IPv6 addresses table. */
++    t_FmPortDsarSnmpIpv4AddrTblEntry *p_Ipv4AddrTbl; /**< Pointer to IPv4 addresses table. */
++    t_FmPortDsarSnmpIpv6AddrTblEntry *p_Ipv6AddrTbl; /**< Pointer to IPv6 addresses table. */
++    uint8_t *p_RdOnlyCommunityStr;             /**< Pointer to the Read Only Community String. */
++    uint8_t *p_RdWrCommunityStr;               /**< Pointer to the Read Write Community String. */
++    t_FmPortDsarOidsEntry *p_OidsTbl;                 /**< Pointer to OIDs table. */
++    uint32_t oidsTblSize;                      /**< Number of entries in OIDs table. */
++} t_FmPortDsarSnmpInfo;
++
++/**************************************************************************//**
++ @Description   Structure for Deep Sleep Auto Response filtering Entry
++*//***************************************************************************/
++typedef struct t_FmPortDsarFilteringEntry
++{
++    uint16_t    srcPort;
++    uint16_t    dstPort;
++    uint16_t    srcPortMask;
++    uint16_t    dstPortMask;
++} t_FmPortDsarFilteringEntry;
++
++/**************************************************************************//**
++ @Description   Structure for Deep Sleep Auto Response filtering info
++*//***************************************************************************/
++typedef struct t_FmPortDsarFilteringInfo
++{
++    /* IP protocol filtering parameters */
++    uint8_t     ipProtTableSize;
++    uint8_t     *p_IpProtTablePtr;
++    bool        ipProtPassOnHit;  /* when TRUE, miss in the table will cause the packet to be droped,
++                                         hit will pass the packet to UDP/TCP filters if needed and if not
++                                         to the classification tree. If the classification tree will pass
++                                         the packet to a queue it will cause a wake interupt.
++                                         When FALSE it the other way around. */
++    /* UDP port filtering parameters */
++    uint8_t     udpPortsTableSize;
++    t_FmPortDsarFilteringEntry *p_UdpPortsTablePtr;
++    bool        udpPortPassOnHit; /* when TRUE, miss in the table will cause the packet to be droped,
++                                         hit will pass the packet to classification tree.
++                                         If the classification tree will pass the packet to a queue it
++                                         will cause a wake interupt.
++                                         When FALSE it the other way around. */
++    /* TCP port filtering parameters */
++    uint16_t    tcpFlagsMask;
++    uint8_t     tcpPortsTableSize;
++    t_FmPortDsarFilteringEntry *p_TcpPortsTablePtr;
++    bool        tcpPortPassOnHit; /* when TRUE, miss in the table will cause the packet to be droped,
++                                         hit will pass the packet to classification tree.
++                                         If the classification tree will pass the packet to a queue it
++                                         will cause a wake interupt.
++                                         When FALSE it the other way around. */
++} t_FmPortDsarFilteringInfo;
++
++/**************************************************************************//**
++ @Description   Structure for Deep Sleep Auto Response parameters
++*//***************************************************************************/
++typedef struct t_FmPortDsarParams
++{
++    t_Handle                  h_FmPortTx;
++    t_FmPortDsarArpInfo       *p_AutoResArpInfo;
++    t_FmPortDsarEchoIpv4Info  *p_AutoResEchoIpv4Info;
++    t_FmPortDsarNdpInfo       *p_AutoResNdpInfo;
++    t_FmPortDsarEchoIpv6Info  *p_AutoResEchoIpv6Info;
++    t_FmPortDsarSnmpInfo      *p_AutoResSnmpInfo;
++    t_FmPortDsarFilteringInfo *p_AutoResFilteringInfo;
++} t_FmPortDsarParams;
++
++/**************************************************************************//**
++ @Function      FM_PORT_EnterDsar
++
++ @Description   Enter Deep Sleep Auto Response mode.
++                This function write the apropriate values to in the relevant
++                tables in the MURAM.
++
++ @Param[in]     h_FmPortRx - FM PORT module descriptor
++ @Param[in]     params - Auto Response parameters
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_EnterDsar(t_Handle h_FmPortRx, t_FmPortDsarParams *params);
++
++/**************************************************************************//**
++ @Function      FM_PORT_EnterDsarFinal
++
++ @Description   Enter Deep Sleep Auto Response mode.
++                This function sets the Tx port in independent mode as needed
++                and redirect the receive flow to go through the
++                Dsar Fman-ctrl code
++
++ @Param[in]     h_DsarRxPort - FM Rx PORT module descriptor
++ @Param[in]     h_DsarTxPort - FM Tx PORT module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_EnterDsarFinal(t_Handle h_DsarRxPort, t_Handle h_DsarTxPort);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ExitDsar
++
++ @Description   Exit Deep Sleep Auto Response mode.
++                This function reverse the AR mode and put the ports back into
++                their original wake mode
++
++ @Param[in]     h_FmPortRx - FM PORT Rx module descriptor
++ @Param[in]     h_FmPortTx - FM PORT Tx module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_EnterDsar().
++*//***************************************************************************/
++void FM_PORT_ExitDsar(t_Handle h_FmPortRx, t_Handle h_FmPortTx);
++
++/**************************************************************************//**
++ @Function      FM_PORT_IsInDsar
++
++ @Description   This function returns TRUE if the port was set as Auto Response
++                and FALSE if not. Once Exit AR mode it will return FALSE as well
++                until re-enabled once more.
++
++ @Param[in]     h_FmPort - FM PORT module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++bool FM_PORT_IsInDsar(t_Handle h_FmPort);
++
++typedef struct t_FmPortDsarStats
++{
++    uint32_t arpArCnt;
++    uint32_t echoIcmpv4ArCnt;
++    uint32_t ndpArCnt;
++    uint32_t echoIcmpv6ArCnt;
++    uint32_t snmpGetCnt;
++    uint32_t snmpGetNextCnt;
++} t_FmPortDsarStats;
++
++/**************************************************************************//**
++ @Function      FM_PORT_GetDsarStats
++
++ @Description   Return statistics for Deep Sleep Auto Response
++
++ @Param[in]     h_FmPortRx - FM PORT module descriptor
++ @Param[out]    stats - structure containing the statistics counters
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_PORT_GetDsarStats(t_Handle h_FmPortRx, t_FmPortDsarStats *stats);
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++/**************************************************************************//**
++ @Function      FM_PORT_DumpRegs
++
++ @Description   Dump all regs.
++
++                Calling this routine invalidates the descriptor.
++
++ @Param[in]     h_FmPort - FM PORT module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_DumpRegs(t_Handle h_FmPort);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++/**************************************************************************//**
++ @Function      FM_PORT_GetBufferDataOffset
++
++ @Description   Relevant for Rx ports.
++                Returns the data offset from the beginning of the data buffer
++
++ @Param[in]     h_FmPort - FM PORT module descriptor
++
++ @Return        data offset.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++uint32_t FM_PORT_GetBufferDataOffset(t_Handle h_FmPort);
++
++/**************************************************************************//**
++ @Function      FM_PORT_GetBufferICInfo
++
++ @Description   Returns the Internal Context offset from the beginning of the data buffer
++
++ @Param[in]     h_FmPort - FM PORT module descriptor
++ @Param[in]     p_Data   - A pointer to the data buffer.
++
++ @Return        Internal context info pointer on success, NULL if 'allOtherInfo' was not
++                configured for this port.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++uint8_t * FM_PORT_GetBufferICInfo(t_Handle h_FmPort, char *p_Data);
++
++/**************************************************************************//**
++ @Function      FM_PORT_GetBufferPrsResult
++
++ @Description   Returns the pointer to the parse result in the data buffer.
++                In Rx ports this is relevant after reception, if parse
++                result is configured to be part of the data passed to the
++                application. For non Rx ports it may be used to get the pointer
++                of the area in the buffer where parse result should be
++                initialized - if so configured.
++                See FM_PORT_ConfigBufferPrefixContent for data buffer prefix
++                configuration.
++
++ @Param[in]     h_FmPort    - FM PORT module descriptor
++ @Param[in]     p_Data      - A pointer to the data buffer.
++
++ @Return        Parse result pointer on success, NULL if parse result was not
++                configured for this port.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_FmPrsResult * FM_PORT_GetBufferPrsResult(t_Handle h_FmPort, char *p_Data);
++
++/**************************************************************************//**
++ @Function      FM_PORT_GetBufferTimeStamp
++
++ @Description   Returns the time stamp in the data buffer.
++                Relevant for Rx ports for getting the buffer time stamp.
++                See FM_PORT_ConfigBufferPrefixContent for data buffer prefix
++                configuration.
++
++ @Param[in]     h_FmPort    - FM PORT module descriptor
++ @Param[in]     p_Data      - A pointer to the data buffer.
++
++ @Return        A pointer to the hash result on success, NULL otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++uint64_t * FM_PORT_GetBufferTimeStamp(t_Handle h_FmPort, char *p_Data);
++
++/**************************************************************************//**
++ @Function      FM_PORT_GetBufferHashResult
++
++ @Description   Given a data buffer, on the condition that hash result was defined
++                as a part of the buffer content (see FM_PORT_ConfigBufferPrefixContent)
++                this routine will return the pointer to the hash result location in the
++                buffer prefix.
++
++ @Param[in]     h_FmPort    - FM PORT module descriptor
++ @Param[in]     p_Data      - A pointer to the data buffer.
++
++ @Return        A pointer to the hash result on success, NULL otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++uint8_t * FM_PORT_GetBufferHashResult(t_Handle h_FmPort, char *p_Data);
++
++/**************************************************************************//**
++ @Function      FM_PORT_Disable
++
++ @Description   Gracefully disable an FM port. The port will not start new tasks after all
++                tasks associated with the port are terminated.
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++                This is a blocking routine, it returns after port is
++                gracefully stopped, i.e. the port will not except new frames,
++                but it will finish all frames or tasks which were already began
++*//***************************************************************************/
++t_Error FM_PORT_Disable(t_Handle h_FmPort);
++
++/**************************************************************************//**
++ @Function      FM_PORT_Enable
++
++ @Description   A runtime routine provided to allow disable/enable of port.
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_Enable(t_Handle h_FmPort);
++
++/**************************************************************************//**
++ @Function      FM_PORT_SetRateLimit
++
++ @Description   Calling this routine enables rate limit algorithm.
++                By default, this functionality is disabled.
++                Note that rate-limit mechanism uses the FM time stamp.
++                The selected rate limit specified here would be
++                rounded DOWN to the nearest 16M.
++
++                May be used for Tx and OP ports only
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     p_RateLimit     A structure of rate limit parameters
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++                If rate limit is set on a port that need to send PFC frames,
++                it might violate the stop transmit timing.
++*//***************************************************************************/
++t_Error FM_PORT_SetRateLimit(t_Handle h_FmPort, t_FmPortRateLimit *p_RateLimit);
++
++/**************************************************************************//**
++ @Function      FM_PORT_DeleteRateLimit
++
++ @Description   Calling this routine disables and clears rate limit
++                initialization.
++
++                May be used for Tx and OP ports only
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_DeleteRateLimit(t_Handle h_FmPort);
++
++/**************************************************************************//**
++ @Function      FM_PORT_SetPfcPrioritiesMappingToQmanWQ
++
++ @Description   Calling this routine maps each PFC received priority to the transmit WQ.
++                This WQ will be blocked upon receiving a PFC frame with this priority.
++
++                May be used for Tx ports only.
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     prio            PFC priority (0-7).
++ @Param[in]     wq              Work Queue (0-7).
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_SetPfcPrioritiesMappingToQmanWQ(t_Handle h_FmPort, uint8_t prio, uint8_t wq);
++
++/**************************************************************************//**
++ @Function      FM_PORT_SetStatisticsCounters
++
++ @Description   Calling this routine enables/disables port's statistics counters.
++                By default, counters are enabled.
++
++                May be used for all port types
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[in]     enable      TRUE to enable, FALSE to disable.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_SetStatisticsCounters(t_Handle h_FmPort, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_PORT_SetFrameQueueCounters
++
++ @Description   Calling this routine enables/disables port's enqueue/dequeue counters.
++                By default, counters are enabled.
++
++                May be used for all ports
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[in]     enable      TRUE to enable, FALSE to disable.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_SetFrameQueueCounters(t_Handle h_FmPort, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_PORT_AnalyzePerformanceParams
++
++ @Description   User may call this routine to so the driver will analyze if the
++                basic performance parameters are correct and also the driver may
++                suggest of improvements; The basic parameters are FIFO sizes, number
++                of DMAs and number of TNUMs for the port.
++
++                May be used for all port types
++
++ @Param[in]     h_FmPort                A handle to a FM Port module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_AnalyzePerformanceParams(t_Handle h_FmPort);
++
++
++/**************************************************************************//**
++ @Function      FM_PORT_SetAllocBufCounter
++
++ @Description   Calling this routine enables/disables BM pool allocate
++                buffer counters.
++                By default, counters are enabled.
++
++                May be used for Rx ports only
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[in]     poolId      BM pool id.
++ @Param[in]     enable      TRUE to enable, FALSE to disable.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_SetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_PORT_GetBmiCounters
++
++ @Description   Read port's BMI stat counters and place them into
++                a designated structure of counters.
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[out]    p_BmiStats  counters structure
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_GetBmiCounters(t_Handle h_FmPort, t_FmPortBmiStats *p_BmiStats);
++
++/**************************************************************************//**
++ @Function      FM_PORT_GetCounter
++
++ @Description   Reads one of the FM PORT counters.
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     fmPortCounter       The requested counter.
++
++ @Return        Counter's current value.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++                Note that it is user's responsibility to call this routine only
++                for enabled counters, and there will be no indication if a
++                disabled counter is accessed.
++*//***************************************************************************/
++uint32_t FM_PORT_GetCounter(t_Handle h_FmPort, e_FmPortCounters fmPortCounter);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ModifyCounter
++
++ @Description   Sets a value to an enabled counter. Use "0" to reset the counter.
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     fmPortCounter       The requested counter.
++ @Param[in]     value               The requested value to be written into the counter.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ModifyCounter(t_Handle h_FmPort, e_FmPortCounters fmPortCounter, uint32_t value);
++
++/**************************************************************************//**
++ @Function      FM_PORT_GetAllocBufCounter
++
++ @Description   Reads one of the FM PORT buffer counters.
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     poolId              The requested pool.
++
++ @Return        Counter's current value.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++                Note that it is user's responsibility to call this routine only
++                for enabled counters, and there will be no indication if a
++                disabled counter is accessed.
++*//***************************************************************************/
++uint32_t FM_PORT_GetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ModifyAllocBufCounter
++
++ @Description   Sets a value to an enabled counter. Use "0" to reset the counter.
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     poolId              The requested pool.
++ @Param[in]     value               The requested value to be written into the counter.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ModifyAllocBufCounter(t_Handle h_FmPort,  uint8_t poolId, uint32_t value);
++
++/**************************************************************************//**
++ @Function      FM_PORT_AddCongestionGrps
++
++ @Description   This routine effects the corresponding Tx port.
++                It should be called in order to enable pause
++                frame transmission in case of congestion in one or more
++                of the congestion groups relevant to this port.
++                Each call to this routine may add one or more congestion
++                groups to be considered relevant to this port.
++
++                May be used for Rx, or RX+OP ports only (depending on chip)
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     p_CongestionGrps    A pointer to an array of congestion groups
++                                    id's to consider.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_AddCongestionGrps(t_Handle h_FmPort, t_FmPortCongestionGrps *p_CongestionGrps);
++
++/**************************************************************************//**
++ @Function      FM_PORT_RemoveCongestionGrps
++
++ @Description   This routine effects the corresponding Tx port. It should be
++                called when congestion groups were
++                defined for this port and are no longer relevant, or pause
++                frames transmitting is not required on their behalf.
++                Each call to this routine may remove one or more congestion
++                groups to be considered relevant to this port.
++
++                May be used for Rx, or RX+OP ports only (depending on chip)
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     p_CongestionGrps    A pointer to an array of congestion groups
++                                    id's to consider.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_RemoveCongestionGrps(t_Handle h_FmPort, t_FmPortCongestionGrps *p_CongestionGrps);
++
++/**************************************************************************//**
++ @Function      FM_PORT_IsStalled
++
++ @Description   A routine for checking whether the specified port is stalled.
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++
++ @Return        TRUE if port is stalled, FALSE otherwize
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++bool FM_PORT_IsStalled(t_Handle h_FmPort);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ReleaseStalled
++
++ @Description   This routine may be called in case the port was stalled and may
++                now be released.
++                Note that this routine is available only on older FMan revisions
++                (FMan v2, DPAA v1.0 only).
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_ReleaseStalled(t_Handle h_FmPort);
++
++/**************************************************************************//**
++ @Function      FM_PORT_SetRxL4ChecksumVerify
++
++ @Description   This routine is relevant for Rx ports (1G and 10G). The routine
++                set/clear the L3/L4 checksum verification (on RX side).
++                Note that this takes affect only if hw-parser is enabled!
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     l4Checksum      boolean indicates whether to do L3/L4 checksum
++                                on frames or not.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_SetRxL4ChecksumVerify(t_Handle h_FmPort, bool l4Checksum);
++
++/**************************************************************************//**
++ @Function      FM_PORT_SetErrorsRoute
++
++ @Description   Errors selected for this routine will cause a frame with that error
++                to be enqueued to error queue.
++                Errors not selected for this routine will cause a frame with that error
++                to be enqueued to the one of the other port queues.
++                By default all errors are defined to be enqueued to error queue.
++                Errors that were configured to be discarded (at initialization)
++                may not be selected here.
++
++                May be used for Rx and OP ports only
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[in]     errs        A list of errors to enqueue to error queue
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_SetErrorsRoute(t_Handle h_FmPort, fmPortFrameErrSelect_t errs);
++
++/**************************************************************************//**
++ @Function      FM_PORT_SetIMExceptions
++
++ @Description   Calling this routine enables/disables FM PORT interrupts.
++
++ @Param[in]     h_FmPort        FM PORT module descriptor.
++ @Param[in]     exception       The exception to be selected.
++ @Param[in]     enable          TRUE to enable interrupt, FALSE to mask it.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++                This routine should NOT be called from guest-partition
++                (i.e. guestId != NCSW_MASTER_ID)
++*//***************************************************************************/
++t_Error FM_PORT_SetIMExceptions(t_Handle h_FmPort, e_FmPortExceptions exception, bool enable);
++
++/**************************************************************************//*
++ @Function      FM_PORT_SetPerformanceCounters
++
++ @Description   Calling this routine enables/disables port's performance counters.
++                By default, counters are enabled.
++
++                May be used for all port types
++
++ @Param[in]     h_FmPort                A handle to a FM Port module.
++ @Param[in]     enable                  TRUE to enable, FALSE to disable.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_SetPerformanceCounters(t_Handle h_FmPort, bool enable);
++
++/**************************************************************************//*
++ @Function      FM_PORT_SetPerformanceCountersParams
++
++ @Description   Calling this routine defines port's performance
++                counters parameters.
++
++                May be used for all port types
++
++ @Param[in]     h_FmPort                A handle to a FM Port module.
++ @Param[in]     p_FmPortPerformanceCnt  A pointer to a structure of performance
++                                        counters parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_SetPerformanceCountersParams(t_Handle h_FmPort, t_FmPortPerformanceCnt *p_FmPortPerformanceCnt);
++
++/**************************************************************************//**
++ @Group         FM_PORT_pcd_runtime_control_grp FM Port PCD Runtime Control Unit
++
++ @Description   FM Port PCD Runtime control unit API functions, definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   A structure defining the KG scheme after the parser.
++                This is relevant only to change scheme selection mode - from
++                direct to indirect and vice versa, or when the scheme is selected directly,
++                to select the scheme id.
++
++*//***************************************************************************/
++typedef struct t_FmPcdKgSchemeSelect {
++    bool        direct;                 /**< TRUE to use 'h_Scheme' directly, FALSE to use LCV. */
++    t_Handle    h_DirectScheme;         /**< Scheme handle, selects the scheme after parser;
++                                             Relevant only when 'direct' is TRUE. */
++} t_FmPcdKgSchemeSelect;
++
++/**************************************************************************//**
++ @Description   A structure of scheme parameters
++*//***************************************************************************/
++typedef struct t_FmPcdPortSchemesParams {
++    uint8_t     numOfSchemes;                           /**< Number of schemes for port to be bound to. */
++    t_Handle    h_Schemes[FM_PCD_KG_NUM_OF_SCHEMES];    /**< Array of 'numOfSchemes' schemes for the
++                                                             port to be bound to */
++} t_FmPcdPortSchemesParams;
++
++/**************************************************************************//**
++ @Description   Union for defining port protocol parameters for parser
++*//***************************************************************************/
++typedef union u_FmPcdHdrPrsOpts {
++    /* MPLS */
++    struct {
++        bool            labelInterpretationEnable;  /**< When this bit is set, the last MPLS label will be
++                                                         interpreted as described in HW spec table. When the bit
++                                                         is cleared, the parser will advance to MPLS next parse */
++        e_NetHeaderType nextParse;                  /**< must be equal or higher than IPv4 */
++    } mplsPrsOptions;
++    /* VLAN */
++    struct {
++        uint16_t        tagProtocolId1;             /**< User defined Tag Protocol Identifier, to be recognized
++                                                         on VLAN TAG on top of 0x8100 and 0x88A8 */
++        uint16_t        tagProtocolId2;             /**< User defined Tag Protocol Identifier, to be recognized
++                                                         on VLAN TAG on top of 0x8100 and 0x88A8 */
++    } vlanPrsOptions;
++    /* PPP */
++    struct{
++        bool            enableMTUCheck;             /**< Check validity of MTU according to RFC2516 */
++    } pppoePrsOptions;
++
++    /* IPV6 */
++    struct{
++        bool            routingHdrEnable;          /**< TRUE to enable routing header, otherwise ignore */
++    } ipv6PrsOptions;
++
++    /* UDP */
++    struct{
++        bool            padIgnoreChecksum;          /**< TRUE to ignore pad in checksum */
++    } udpPrsOptions;
++
++    /* TCP */
++    struct {
++        bool            padIgnoreChecksum;          /**< TRUE to ignore pad in checksum */
++    } tcpPrsOptions;
++} u_FmPcdHdrPrsOpts;
++
++/**************************************************************************//**
++ @Description   A structure for defining each header for the parser
++*//***************************************************************************/
++typedef struct t_FmPcdPrsAdditionalHdrParams {
++    e_NetHeaderType         hdr;            /**< Selected header; use  HEADER_TYPE_NONE
++                                                 to indicate that sw parser is to run first
++                                                 (before HW parser, and independent of the
++                                                 existence of any protocol), in this case,
++                                                 swPrsEnable must be set, and all other
++                                                 parameters are irrelevant.  */
++    bool                    errDisable;     /**< TRUE to disable error indication */
++    bool                    swPrsEnable;    /**< Enable jump to SW parser when this
++                                                 header is recognized by the HW parser. */
++    uint8_t                 indexPerHdr;    /**< Normally 0, if more than one sw parser
++                                                 attachments exists for the same header,
++                                                 (in the main sw parser code) use this
++                                                 index to distinguish between them. */
++    bool                    usePrsOpts;     /**< TRUE to use parser options. */
++    u_FmPcdHdrPrsOpts       prsOpts;        /**< A union according to header type,
++                                                 defining the parser options selected.*/
++} t_FmPcdPrsAdditionalHdrParams;
++
++/**************************************************************************//**
++ @Description   struct for defining port PCD parameters
++*//***************************************************************************/
++typedef struct t_FmPortPcdPrsParams {
++    uint8_t                         prsResultPrivateInfo;           /**< The private info provides a method of inserting
++                                                                         port information into the parser result. This information
++                                                                         may be extracted by Keygen and be used for frames
++                                                                         distribution when a per-port distinction is required,
++                                                                         it may also be used as a port logical id for analyzing
++                                                                         incoming frames. */
++    uint8_t                         parsingOffset;                  /**< Number of bytes from beginning of packet to start parsing */
++    e_NetHeaderType                 firstPrsHdr;                    /**< The type of the first header expected at 'parsingOffset' */
++    bool                            includeInPrsStatistics;         /**< TRUE to include this port in the parser statistics;
++                                                                         NOTE: this field is not valid when the FM is in "guest" mode
++                                                                               and IPC is not available. */
++    uint8_t                         numOfHdrsWithAdditionalParams;  /**< Normally 0, some headers may get
++                                                                         special parameters */
++    t_FmPcdPrsAdditionalHdrParams   additionalParams[FM_PCD_PRS_NUM_OF_HDRS];
++                                                                    /**< 'numOfHdrsWithAdditionalParams'  structures
++                                                                         of additional parameters
++                                                                         for each header that requires them */
++    bool                            setVlanTpid1;                   /**< TRUE to configure user selection of Ethertype to
++                                                                         indicate a VLAN tag (in addition to the TPID values
++                                                                         0x8100 and 0x88A8). */
++    uint16_t                        vlanTpid1;                      /**< extra tag to use if setVlanTpid1=TRUE. */
++    bool                            setVlanTpid2;                   /**< TRUE to configure user selection of Ethertype to
++                                                                         indicate a VLAN tag (in addition to the TPID values
++                                                                         0x8100 and 0x88A8). */
++    uint16_t                        vlanTpid2;                      /**< extra tag to use if setVlanTpid1=TRUE. */
++} t_FmPortPcdPrsParams;
++
++/**************************************************************************//**
++ @Description   struct for defining coarse alassification parameters
++*//***************************************************************************/
++typedef struct t_FmPortPcdCcParams {
++    t_Handle            h_CcTree;                       /**< A handle to a CC tree */
++} t_FmPortPcdCcParams;
++
++/**************************************************************************//**
++ @Description   struct for defining keygen parameters
++*//***************************************************************************/
++typedef struct t_FmPortPcdKgParams {
++    uint8_t             numOfSchemes;                   /**< Number of schemes for port to be bound to. */
++    t_Handle            h_Schemes[FM_PCD_KG_NUM_OF_SCHEMES];
++                                                        /**< Array of 'numOfSchemes' schemes handles for the
++                                                             port to be bound to */
++    bool                directScheme;                   /**< TRUE for going from parser to a specific scheme,
++                                                             regardless of parser result */
++    t_Handle            h_DirectScheme;                 /**< relevant only if direct == TRUE, Scheme handle,
++                                                             as returned by FM_PCD_KgSetScheme */
++} t_FmPortPcdKgParams;
++
++/**************************************************************************//**
++ @Description   struct for defining policer parameters
++*//***************************************************************************/
++typedef struct t_FmPortPcdPlcrParams {
++    t_Handle                h_Profile;          /**< Selected profile handle */
++} t_FmPortPcdPlcrParams;
++
++/**************************************************************************//**
++ @Description   struct for defining port PCD parameters
++*//***************************************************************************/
++typedef struct t_FmPortPcdParams {
++    e_FmPortPcdSupport      pcdSupport;         /**< Relevant for Rx and offline ports only.
++                                                     Describes the active PCD engines for this port. */
++    t_Handle                h_NetEnv;           /**< HL Unused in PLCR only mode */
++    t_FmPortPcdPrsParams    *p_PrsParams;       /**< Parser parameters for this port */
++    t_FmPortPcdCcParams     *p_CcParams;        /**< Coarse classification parameters for this port */
++    t_FmPortPcdKgParams     *p_KgParams;        /**< Keygen parameters for this port */
++    t_FmPortPcdPlcrParams   *p_PlcrParams;      /**< Policer parameters for this port; Relevant for one of
++                                                     following cases:
++                                                     e_FM_PORT_PCD_SUPPORT_PLCR_ONLY or
++                                                     e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR were selected,
++                                                     or if any flow uses a KG scheme were policer
++                                                     profile is not generated
++                                                     ('bypassPlcrProfileGeneration selected'). */
++    t_Handle                h_IpReassemblyManip;    /**< IP Reassembly manipulation */
++#if (DPAA_VERSION >= 11)
++    t_Handle                h_CapwapReassemblyManip;/**< CAPWAP Reassembly manipulation */
++#endif /* (DPAA_VERSION >= 11) */
++} t_FmPortPcdParams;
++
++/**************************************************************************//**
++ @Description   A structure for defining the Parser starting point
++*//***************************************************************************/
++typedef struct t_FmPcdPrsStart {
++    uint8_t             parsingOffset;  /**< Number of bytes from beginning of packet to
++                                             start parsing */
++    e_NetHeaderType     firstPrsHdr;    /**< The type of the first header axpected at
++                                             'parsingOffset' */
++} t_FmPcdPrsStart;
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Description   struct for defining external buffer margins
++*//***************************************************************************/
++typedef struct t_FmPortVSPAllocParams {
++    uint8_t     numOfProfiles;          /**< Number of Virtual Storage Profiles; must be a power of 2 */
++    uint8_t     dfltRelativeId;         /**< The default Virtual-Storage-Profile-id dedicated to Rx/OP port
++                                             The same default Virtual-Storage-Profile-id will be for coupled Tx port
++                                             if relevant function called for Rx port */
++    t_Handle    h_FmTxPort;             /**< Handle to coupled Tx Port; not relevant for OP port. */
++} t_FmPortVSPAllocParams;
++#endif /* (DPAA_VERSION >= 11) */
++
++
++/**************************************************************************//**
++ @Function      FM_PORT_SetPCD
++
++ @Description   Calling this routine defines the port's PCD configuration.
++                It changes it from its default configuration which is PCD
++                disabled (BMI to BMI) and configures it according to the passed
++                parameters.
++
++                May be used for Rx and OP ports only
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     p_FmPortPcd     A Structure of parameters defining the port's PCD
++                                configuration.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_SetPCD(t_Handle h_FmPort, t_FmPortPcdParams *p_FmPortPcd);
++
++/**************************************************************************//**
++ @Function      FM_PORT_DeletePCD
++
++ @Description   Calling this routine releases the port's PCD configuration.
++                The port returns to its default configuration which is PCD
++                disabled (BMI to BMI) and all PCD configuration is removed.
++
++                May be used for Rx and OP ports which are
++                in PCD mode  only
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_DeletePCD(t_Handle h_FmPort);
++
++/**************************************************************************//**
++ @Function      FM_PORT_AttachPCD
++
++ @Description   This routine may be called after FM_PORT_DetachPCD was called,
++                to return to the originally configured PCD support flow.
++                The couple of routines are used to allow PCD configuration changes
++                that demand that PCD will not be used while changes take place.
++
++                May be used for Rx and OP ports which are
++                in PCD mode only
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++t_Error FM_PORT_AttachPCD(t_Handle h_FmPort);
++
++/**************************************************************************//**
++ @Function      FM_PORT_DetachPCD
++
++ @Description   Calling this routine detaches the port from its PCD functionality.
++                The port returns to its default flow which is BMI to BMI.
++
++                May be used for Rx and OP ports which are
++                in PCD mode only
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_AttachPCD().
++*//***************************************************************************/
++t_Error FM_PORT_DetachPCD(t_Handle h_FmPort);
++
++/**************************************************************************//**
++ @Function      FM_PORT_PcdPlcrAllocProfiles
++
++ @Description   This routine may be called only for ports that use the Policer in
++                order to allocate private policer profiles.
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     numOfProfiles       The number of required policer profiles
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init() and FM_PCD_Init(),
++                and before FM_PORT_SetPCD().
++*//***************************************************************************/
++t_Error FM_PORT_PcdPlcrAllocProfiles(t_Handle h_FmPort, uint16_t numOfProfiles);
++
++/**************************************************************************//**
++ @Function      FM_PORT_PcdPlcrFreeProfiles
++
++ @Description   This routine should be called for freeing private policer profiles.
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init() and FM_PCD_Init(),
++                and before FM_PORT_SetPCD().
++*//***************************************************************************/
++t_Error FM_PORT_PcdPlcrFreeProfiles(t_Handle h_FmPort);
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Function      FM_PORT_VSPAlloc
++
++ @Description   This routine allocated VSPs per port and forces the port to work
++                in VSP mode. Note that the port is initialized by default with the
++                physical-storage-profile only.
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[in]     p_Params    A structure of parameters for allocation VSP's per port
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init(), and before FM_PORT_SetPCD()
++                and also before FM_PORT_Enable(); i.e. the port should be disabled.
++*//***************************************************************************/
++t_Error FM_PORT_VSPAlloc(t_Handle h_FmPort, t_FmPortVSPAllocParams *p_Params);
++#endif /* (DPAA_VERSION >= 11) */
++
++/**************************************************************************//**
++ @Function      FM_PORT_PcdKgModifyInitialScheme
++
++ @Description   This routine may be called only for ports that use the keygen in
++                order to change the initial scheme frame should be routed to.
++                The change may be of a scheme id (in case of direct mode),
++                from direct to indirect, or from indirect to direct - specifying the scheme id.
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     p_FmPcdKgScheme     A structure of parameters for defining whether
++                                    a scheme is direct/indirect, and if direct - scheme id.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init() and FM_PORT_SetPCD().
++*//***************************************************************************/
++t_Error FM_PORT_PcdKgModifyInitialScheme (t_Handle h_FmPort, t_FmPcdKgSchemeSelect *p_FmPcdKgScheme);
++
++/**************************************************************************//**
++ @Function      FM_PORT_PcdPlcrModifyInitialProfile
++
++ @Description   This routine may be called for ports with flows
++                e_FM_PORT_PCD_SUPPORT_PLCR_ONLY or e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR
++                only, to change the initial Policer profile frame should be
++                routed to. The change may be of a profile and/or absolute/direct
++                mode selection.
++
++ @Param[in]     h_FmPort                A handle to a FM Port module.
++ @Param[in]     h_Profile               Policer profile handle
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init() and FM_PORT_SetPCD().
++*//***************************************************************************/
++t_Error FM_PORT_PcdPlcrModifyInitialProfile (t_Handle h_FmPort, t_Handle h_Profile);
++
++/**************************************************************************//**
++ @Function      FM_PORT_PcdCcModifyTree
++
++ @Description   This routine may be called for ports that use coarse classification tree
++                if the user wishes to replace the tree. The routine may not be called while port
++                receives packets using the PCD functionalities, therefor port must be first detached
++                from the PCD, only than the routine may be called, and than port be attached to PCD again.
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[in]     h_CcTree            A CC tree that was already built. The tree id as returned from
++                                    the BuildTree routine.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init(), FM_PORT_SetPCD() and FM_PORT_DetachPCD()
++*//***************************************************************************/
++t_Error FM_PORT_PcdCcModifyTree (t_Handle h_FmPort, t_Handle h_CcTree);
++
++/**************************************************************************//**
++ @Function      FM_PORT_PcdKgBindSchemes
++
++ @Description   These routines may be called for adding more schemes for the
++                port to be bound to. The selected schemes are not added,
++                just this specific port starts using them.
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     p_PortScheme    A structure defining the list of schemes to be added.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init() and FM_PORT_SetPCD().
++*//***************************************************************************/
++t_Error FM_PORT_PcdKgBindSchemes (t_Handle h_FmPort, t_FmPcdPortSchemesParams *p_PortScheme);
++
++/**************************************************************************//**
++ @Function      FM_PORT_PcdKgUnbindSchemes
++
++ @Description   These routines may be called for adding more schemes for the
++                port to be bound to. The selected schemes are not removed or invalidated,
++                just this specific port stops using them.
++
++ @Param[in]     h_FmPort        A handle to a FM Port module.
++ @Param[in]     p_PortScheme    A structure defining the list of schemes to be added.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init() and FM_PORT_SetPCD().
++*//***************************************************************************/
++t_Error FM_PORT_PcdKgUnbindSchemes (t_Handle h_FmPort, t_FmPcdPortSchemesParams *p_PortScheme);
++
++/**************************************************************************//**
++ @Function      FM_PORT_GetIPv4OptionsCount
++
++ @Description   TODO
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++ @Param[out]    p_Ipv4OptionsCount  will hold the counter value
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init()
++*//***************************************************************************/
++t_Error FM_PORT_GetIPv4OptionsCount(t_Handle h_FmPort, uint32_t *p_Ipv4OptionsCount);
++
++/** @} */ /* end of FM_PORT_pcd_runtime_control_grp group */
++/** @} */ /* end of FM_PORT_runtime_control_grp group */
++
++
++/**************************************************************************//**
++ @Group         FM_PORT_runtime_data_grp FM Port Runtime Data-path Unit
++
++ @Description   FM Port Runtime data unit API functions, definitions and enums.
++                This API is valid only if working in Independent-Mode.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      FM_PORT_ImTx
++
++ @Description   Tx function, called to transmit a data buffer on the port.
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[in]     p_Data      A pointer to an LCP data buffer.
++ @Param[in]     length      Size of data for transmission.
++ @Param[in]     lastBuffer  Buffer position - TRUE for the last buffer
++                            of a frame, including a single buffer frame
++ @Param[in]     h_BufContext  A handle of the user acossiated with this buffer
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++                NOTE - This routine can be used only when working in
++                Independent-Mode mode.
++*//***************************************************************************/
++t_Error  FM_PORT_ImTx( t_Handle               h_FmPort,
++                       uint8_t                *p_Data,
++                       uint16_t               length,
++                       bool                   lastBuffer,
++                       t_Handle               h_BufContext);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ImTxConf
++
++ @Description   Tx port confirmation routine, optional, may be called to verify
++                transmission of all frames. The procedure performed by this
++                routine will be performed automatically on next buffer transmission,
++                but if desired, calling this routine will invoke this action on
++                demand.
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++                NOTE - This routine can be used only when working in
++                Independent-Mode mode.
++*//***************************************************************************/
++void FM_PORT_ImTxConf(t_Handle h_FmPort);
++
++/**************************************************************************//**
++ @Function      FM_PORT_ImRx
++
++ @Description   Rx function, may be called to poll for received buffers.
++                Normally, Rx process is invoked by the driver on Rx interrupt.
++                Alternatively, this routine may be called on demand.
++
++ @Param[in]     h_FmPort            A handle to a FM Port module.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++                NOTE - This routine can be used only when working in
++                Independent-Mode mode.
++*//***************************************************************************/
++t_Error  FM_PORT_ImRx(t_Handle h_FmPort);
++
++/** @} */ /* end of FM_PORT_runtime_data_grp group */
++/** @} */ /* end of FM_PORT_grp group */
++/** @} */ /* end of FM_grp group */
++
++
++
++#ifdef NCSW_BACKWARD_COMPATIBLE_API
++#define FM_PORT_ConfigTxFifoDeqPipelineDepth FM_PORT_ConfigFifoDeqPipelineDepth
++#endif /* NCSW_BACKWARD_COMPATIBLE_API */
++
++
++#endif /* __FM_PORT_EXT */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_rtc_ext.h
+@@ -0,0 +1,619 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          fm_rtc_ext.h
++
++ @Description   External definitions and API for FM RTC IEEE1588 Timer Module.
++
++ @Cautions      None.
++*//***************************************************************************/
++
++#ifndef __FM_RTC_EXT_H__
++#define __FM_RTC_EXT_H__
++
++
++#include "error_ext.h"
++#include "std_ext.h"
++#include "fsl_fman_rtc.h"
++
++/**************************************************************************//**
++
++ @Group         FM_grp Frame Manager API
++
++ @Description   FM API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         fm_rtc_grp FM RTC
++
++ @Description   FM RTC functions, definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         fm_rtc_init_grp FM RTC Initialization Unit
++
++ @Description   FM RTC initialization API.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   FM RTC Alarm Polarity Options.
++*//***************************************************************************/
++typedef enum e_FmRtcAlarmPolarity
++{
++    e_FM_RTC_ALARM_POLARITY_ACTIVE_HIGH = E_FMAN_RTC_ALARM_POLARITY_ACTIVE_HIGH,    /**< Active-high output polarity */
++    e_FM_RTC_ALARM_POLARITY_ACTIVE_LOW = E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW     /**< Active-low output polarity */
++} e_FmRtcAlarmPolarity;
++
++/**************************************************************************//**
++ @Description   FM RTC Trigger Polarity Options.
++*//***************************************************************************/
++typedef enum e_FmRtcTriggerPolarity
++{
++    e_FM_RTC_TRIGGER_ON_RISING_EDGE = E_FMAN_RTC_TRIGGER_ON_RISING_EDGE,    /**< Trigger on rising edge */
++    e_FM_RTC_TRIGGER_ON_FALLING_EDGE = E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE   /**< Trigger on falling edge */
++} e_FmRtcTriggerPolarity;
++
++/**************************************************************************//**
++ @Description   IEEE1588 Timer Module FM RTC Optional Clock Sources.
++*//***************************************************************************/
++typedef enum e_FmSrcClock
++{
++    e_FM_RTC_SOURCE_CLOCK_EXTERNAL = E_FMAN_RTC_SOURCE_CLOCK_EXTERNAL,  /**< external high precision timer reference clock */
++    e_FM_RTC_SOURCE_CLOCK_SYSTEM = E_FMAN_RTC_SOURCE_CLOCK_SYSTEM,    /**< MAC system clock */
++    e_FM_RTC_SOURCE_CLOCK_OSCILATOR = E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR  /**< RTC clock oscilator */
++}e_FmSrcClk;
++
++/**************************************************************************//**
++ @Description   FM RTC configuration parameters structure.
++
++                This structure should be passed to FM_RTC_Config().
++*//***************************************************************************/
++typedef struct t_FmRtcParams
++{
++    t_Handle                 h_Fm;               /**< FM Handle*/
++    uintptr_t                baseAddress;        /**< Base address of FM RTC registers */
++    t_Handle                 h_App;              /**< A handle to an application layer object; This handle will
++                                                      be passed by the driver upon calling the above callbacks */
++} t_FmRtcParams;
++
++
++/**************************************************************************//**
++ @Function      FM_RTC_Config
++
++ @Description   Configures the FM RTC module according to user's parameters.
++
++                The driver assigns default values to some FM RTC parameters.
++                These parameters can be overwritten using the advanced
++                configuration routines.
++
++ @Param[in]     p_FmRtcParam    - FM RTC configuration parameters.
++
++ @Return        Handle to the new FM RTC object; NULL pointer on failure.
++
++ @Cautions      None
++*//***************************************************************************/
++t_Handle FM_RTC_Config(t_FmRtcParams *p_FmRtcParam);
++
++/**************************************************************************//**
++ @Function      FM_RTC_Init
++
++ @Description   Initializes the FM RTC driver and hardware.
++
++ @Param[in]     h_FmRtc - Handle to FM RTC object.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously created using FM_RTC_Config().
++*//***************************************************************************/
++t_Error FM_RTC_Init(t_Handle h_FmRtc);
++
++/**************************************************************************//**
++ @Function      FM_RTC_Free
++
++ @Description   Frees the FM RTC object and all allocated resources.
++
++ @Param[in]     h_FmRtc - Handle to FM RTC object.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously created using FM_RTC_Config().
++*//***************************************************************************/
++t_Error FM_RTC_Free(t_Handle h_FmRtc);
++
++
++/**************************************************************************//**
++ @Group         fm_rtc_adv_config_grp  FM RTC Advanced Configuration Unit
++
++ @Description   FM RTC advanced configuration functions.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      FM_RTC_ConfigPeriod
++
++ @Description   Configures the period of the timestamp if different than
++                default [DEFAULT_clockPeriod].
++
++ @Param[in]     h_FmRtc         - Handle to FM RTC object.
++ @Param[in]     period          - Period in nano-seconds.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously created using FM_RTC_Config().
++*//***************************************************************************/
++t_Error FM_RTC_ConfigPeriod(t_Handle h_FmRtc, uint32_t period);
++
++/**************************************************************************//**
++ @Function      FM_RTC_ConfigSourceClock
++
++ @Description   Configures the source clock of the RTC.
++
++ @Param[in]     h_FmRtc         - Handle to FM RTC object.
++ @Param[in]     srcClk          - Source clock selection.
++ @Param[in]     freqInMhz       - the source-clock frequency (in MHz).
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously created using FM_RTC_Config().
++*//***************************************************************************/
++t_Error FM_RTC_ConfigSourceClock(t_Handle      h_FmRtc,
++                                 e_FmSrcClk    srcClk,
++                                 uint32_t      freqInMhz);
++
++/**************************************************************************//**
++ @Function      FM_RTC_ConfigPulseRealignment
++
++ @Description   Configures the RTC to automatic FIPER pulse realignment in
++                response to timer adjustments [DEFAULT_pulseRealign]
++
++                In this mode, the RTC clock is identical to the source clock.
++                This feature can be useful when the system contains an external
++                RTC with inherent frequency compensation.
++
++ @Param[in]     h_FmRtc     - Handle to FM RTC object.
++ @Param[in]     enable      - TRUE to enable automatic realignment.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously created using FM_RTC_Config().
++*//***************************************************************************/
++t_Error FM_RTC_ConfigPulseRealignment(t_Handle h_FmRtc, bool enable);
++
++/**************************************************************************//**
++ @Function      FM_RTC_ConfigFrequencyBypass
++
++ @Description   Configures the RTC to bypass the frequency compensation
++                mechanism. [DEFAULT_bypass]
++
++                In this mode, the RTC clock is identical to the source clock.
++                This feature can be useful when the system contains an external
++                RTC with inherent frequency compensation.
++
++ @Param[in]     h_FmRtc     - Handle to FM RTC object.
++ @Param[in]     enabled     - TRUE to bypass frequency compensation;
++                              FALSE otherwise.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously created using FM_RTC_Config().
++*//***************************************************************************/
++t_Error FM_RTC_ConfigFrequencyBypass(t_Handle h_FmRtc, bool enabled);
++
++/**************************************************************************//**
++ @Function      FM_RTC_ConfigInvertedInputClockPhase
++
++ @Description   Configures the RTC to invert the source clock phase on input.
++                [DEFAULT_invertInputClkPhase]
++
++ @Param[in]     h_FmRtc  - Handle to FM RTC object.
++ @Param[in]     inverted    - TRUE to invert the source clock phase on input.
++                              FALSE otherwise.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously created using FM_RTC_Config().
++*//***************************************************************************/
++t_Error FM_RTC_ConfigInvertedInputClockPhase(t_Handle h_FmRtc, bool inverted);
++
++/**************************************************************************//**
++ @Function      FM_RTC_ConfigInvertedOutputClockPhase
++
++ @Description   Configures the RTC to invert the output clock phase.
++                [DEFAULT_invertOutputClkPhase]
++
++ @Param[in]     h_FmRtc  - Handle to FM RTC object.
++ @Param[in]     inverted    - TRUE to invert the output clock phase.
++                              FALSE otherwise.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously created using FM_RTC_Config().
++*//***************************************************************************/
++t_Error FM_RTC_ConfigInvertedOutputClockPhase(t_Handle h_FmRtc, bool inverted);
++
++/**************************************************************************//**
++ @Function      FM_RTC_ConfigOutputClockDivisor
++
++ @Description   Configures the divisor for generating the output clock from
++                the RTC clock. [DEFAULT_outputClockDivisor]
++
++ @Param[in]     h_FmRtc  - Handle to FM RTC object.
++ @Param[in]     divisor     - Divisor for generation of the output clock.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously created using FM_RTC_Config().
++*//***************************************************************************/
++t_Error FM_RTC_ConfigOutputClockDivisor(t_Handle h_FmRtc, uint16_t divisor);
++
++/**************************************************************************//**
++ @Function      FM_RTC_ConfigAlarmPolarity
++
++ @Description   Configures the polarity (active-high/active-low) of a specific
++                alarm signal. [DEFAULT_alarmPolarity]
++
++ @Param[in]     h_FmRtc      - Handle to FM RTC object.
++ @Param[in]     alarmId         - Alarm ID.
++ @Param[in]     alarmPolarity   - Alarm polarity.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously created using FM_RTC_Config().
++*//***************************************************************************/
++t_Error FM_RTC_ConfigAlarmPolarity(t_Handle             h_FmRtc,
++                                   uint8_t              alarmId,
++                                   e_FmRtcAlarmPolarity alarmPolarity);
++
++/**************************************************************************//**
++ @Function      FM_RTC_ConfigExternalTriggerPolarity
++
++ @Description   Configures the polarity (rising/falling edge) of a specific
++                external trigger signal. [DEFAULT_triggerPolarity]
++
++ @Param[in]     h_FmRtc      - Handle to FM RTC object.
++ @Param[in]     triggerId       - Trigger ID.
++ @Param[in]     triggerPolarity - Trigger polarity.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously created using FM_RTC_Config().
++*//***************************************************************************/
++t_Error FM_RTC_ConfigExternalTriggerPolarity(t_Handle               h_FmRtc,
++                                             uint8_t                triggerId,
++                                             e_FmRtcTriggerPolarity triggerPolarity);
++
++/** @} */ /* end of fm_rtc_adv_config_grp */
++/** @} */ /* end of fm_rtc_init_grp */
++
++
++/**************************************************************************//**
++ @Group         fm_rtc_control_grp FM RTC Control Unit
++
++ @Description   FM RTC runtime control API.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      t_FmRtcExceptionsCallback
++
++ @Description   Exceptions user callback routine, used for RTC different mechanisms.
++
++ @Param[in]     h_App       - User's application descriptor.
++ @Param[in]     id          - source id.
++*//***************************************************************************/
++typedef void (t_FmRtcExceptionsCallback) ( t_Handle  h_App, uint8_t id);
++
++/**************************************************************************//**
++ @Description   FM RTC alarm parameters.
++*//***************************************************************************/
++typedef struct t_FmRtcAlarmParams {
++    uint8_t                     alarmId;            /**< 0 or 1 */
++    uint64_t                    alarmTime;          /**< In nanoseconds, the time when the alarm
++                                                         should go off - must be a multiple of
++                                                         the RTC period */
++    t_FmRtcExceptionsCallback   *f_AlarmCallback;   /**< This routine will be called when RTC
++                                                         reaches alarmTime */
++    bool                        clearOnExpiration;  /**< TRUE to turn off the alarm once expired. */
++} t_FmRtcAlarmParams;
++
++/**************************************************************************//**
++ @Description   FM RTC Periodic Pulse parameters.
++*//***************************************************************************/
++typedef struct t_FmRtcPeriodicPulseParams {
++    uint8_t                     periodicPulseId;            /**< 0 or 1 */
++    uint64_t                    periodicPulsePeriod;        /**< In Nanoseconds. Must be
++                                                                 a multiple of the RTC period */
++    t_FmRtcExceptionsCallback   *f_PeriodicPulseCallback;   /**< This routine will be called every
++                                                                 periodicPulsePeriod. */
++} t_FmRtcPeriodicPulseParams;
++
++/**************************************************************************//**
++ @Description   FM RTC Periodic Pulse parameters.
++*//***************************************************************************/
++typedef struct t_FmRtcExternalTriggerParams {
++    uint8_t                     externalTriggerId;              /**< 0 or 1 */
++    bool                        usePulseAsInput;                /**< Use the pulse interrupt instead of
++                                                                     an external signal */
++    t_FmRtcExceptionsCallback   *f_ExternalTriggerCallback;     /**< This routine will be called every
++                                                                     periodicPulsePeriod. */
++} t_FmRtcExternalTriggerParams;
++
++
++/**************************************************************************//**
++ @Function      FM_RTC_Enable
++
++ @Description   Enable the RTC (time count is started).
++
++                The user can select to resume the time count from previous
++                point, or to restart the time count.
++
++ @Param[in]     h_FmRtc     - Handle to FM RTC object.
++ @Param[in]     resetClock  - Restart the time count from zero.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously initialized using FM_RTC_Init().
++*//***************************************************************************/
++t_Error FM_RTC_Enable(t_Handle h_FmRtc, bool resetClock);
++
++/**************************************************************************//**
++ @Function      FM_RTC_Disable
++
++ @Description   Disables the RTC (time count is stopped).
++
++ @Param[in]     h_FmRtc - Handle to FM RTC object.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously initialized using FM_RTC_Init().
++*//***************************************************************************/
++t_Error FM_RTC_Disable(t_Handle h_FmRtc);
++
++/**************************************************************************//**
++ @Function      FM_RTC_SetClockOffset
++
++ @Description   Sets the clock offset (usually relative to another clock).
++
++                The user can pass a negative offset value.
++
++ @Param[in]     h_FmRtc  - Handle to FM RTC object.
++ @Param[in]     offset   - New clock offset (in nanoseconds).
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously initialized using FM_RTC_Init().
++*//***************************************************************************/
++t_Error FM_RTC_SetClockOffset(t_Handle h_FmRtc, int64_t offset);
++
++/**************************************************************************//**
++ @Function      FM_RTC_SetAlarm
++
++ @Description   Schedules an alarm event to a given RTC time.
++
++ @Param[in]     h_FmRtc             - Handle to FM RTC object.
++ @Param[in]     p_FmRtcAlarmParams  - Alarm parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously initialized using FM_RTC_Init().
++                Must be called only prior to FM_RTC_Enable().
++*//***************************************************************************/
++t_Error FM_RTC_SetAlarm(t_Handle h_FmRtc, t_FmRtcAlarmParams *p_FmRtcAlarmParams);
++
++/**************************************************************************//**
++ @Function      FM_RTC_SetPeriodicPulse
++
++ @Description   Sets a periodic pulse.
++
++ @Param[in]     h_FmRtc                         - Handle to FM RTC object.
++ @Param[in]     p_FmRtcPeriodicPulseParams      - Periodic pulse parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously initialized using FM_RTC_Init().
++                Must be called only prior to FM_RTC_Enable().
++*//***************************************************************************/
++t_Error FM_RTC_SetPeriodicPulse(t_Handle h_FmRtc, t_FmRtcPeriodicPulseParams *p_FmRtcPeriodicPulseParams);
++
++/**************************************************************************//**
++ @Function      FM_RTC_ClearPeriodicPulse
++
++ @Description   Clears a periodic pulse.
++
++ @Param[in]     h_FmRtc                         - Handle to FM RTC object.
++ @Param[in]     periodicPulseId                 - Periodic pulse id.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously initialized using FM_RTC_Init().
++*//***************************************************************************/
++t_Error FM_RTC_ClearPeriodicPulse(t_Handle h_FmRtc, uint8_t periodicPulseId);
++
++/**************************************************************************//**
++ @Function      FM_RTC_SetExternalTrigger
++
++ @Description   Sets an external trigger indication and define a callback
++                routine to be called on such event.
++
++ @Param[in]     h_FmRtc                         - Handle to FM RTC object.
++ @Param[in]     p_FmRtcExternalTriggerParams    - External Trigger parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously initialized using FM_RTC_Init().
++*//***************************************************************************/
++t_Error FM_RTC_SetExternalTrigger(t_Handle h_FmRtc, t_FmRtcExternalTriggerParams *p_FmRtcExternalTriggerParams);
++
++/**************************************************************************//**
++ @Function      FM_RTC_ClearExternalTrigger
++
++ @Description   Clears external trigger indication.
++
++ @Param[in]     h_FmRtc                         - Handle to FM RTC object.
++ @Param[in]     id                              - External Trigger id.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously initialized using FM_RTC_Init().
++*//***************************************************************************/
++t_Error FM_RTC_ClearExternalTrigger(t_Handle h_FmRtc, uint8_t id);
++
++/**************************************************************************//**
++ @Function      FM_RTC_GetExternalTriggerTimeStamp
++
++ @Description   Reads the External Trigger TimeStamp.
++
++ @Param[in]     h_FmRtc                 - Handle to FM RTC object.
++ @Param[in]     triggerId               - External Trigger id.
++ @Param[out]    p_TimeStamp             - External Trigger timestamp (in nanoseconds).
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously initialized using FM_RTC_Init().
++*//***************************************************************************/
++t_Error FM_RTC_GetExternalTriggerTimeStamp(t_Handle             h_FmRtc,
++                                           uint8_t              triggerId,
++                                           uint64_t             *p_TimeStamp);
++
++/**************************************************************************//**
++ @Function      FM_RTC_GetCurrentTime
++
++ @Description   Returns the current RTC time.
++
++ @Param[in]     h_FmRtc - Handle to FM RTC object.
++ @Param[out]    p_Ts - returned time stamp (in nanoseconds).
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously initialized using FM_RTC_Init().
++*//***************************************************************************/
++t_Error FM_RTC_GetCurrentTime(t_Handle h_FmRtc, uint64_t *p_Ts);
++
++/**************************************************************************//**
++ @Function      FM_RTC_SetCurrentTime
++
++ @Description   Sets the current RTC time.
++
++ @Param[in]     h_FmRtc - Handle to FM RTC object.
++ @Param[in]     ts - The new time stamp (in nanoseconds).
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously initialized using FM_RTC_Init().
++*//***************************************************************************/
++t_Error FM_RTC_SetCurrentTime(t_Handle h_FmRtc, uint64_t ts);
++
++/**************************************************************************//**
++ @Function      FM_RTC_GetFreqCompensation
++
++ @Description   Retrieves the frequency compensation value
++
++ @Param[in]     h_FmRtc         - Handle to FM RTC object.
++ @Param[out]    p_Compensation  - A pointer to the returned value of compensation.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously initialized using FM_RTC_Init().
++*//***************************************************************************/
++t_Error FM_RTC_GetFreqCompensation(t_Handle h_FmRtc, uint32_t *p_Compensation);
++
++/**************************************************************************//**
++ @Function      FM_RTC_SetFreqCompensation
++
++ @Description   Sets a new frequency compensation value.
++
++ @Param[in]     h_FmRtc             - Handle to FM RTC object.
++ @Param[in]     freqCompensation    - The new frequency compensation value to set.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      h_FmRtc must have been previously initialized using FM_RTC_Init().
++*//***************************************************************************/
++t_Error FM_RTC_SetFreqCompensation(t_Handle h_FmRtc, uint32_t freqCompensation);
++
++#ifdef CONFIG_PTP_1588_CLOCK_DPAA
++/**************************************************************************//**
++*@Function      FM_RTC_EnableInterrupt
++*
++*@Description   Enable interrupt of FM RTC.
++*
++*@Param[in]     h_FmRtc             - Handle to FM RTC object.
++*@Param[in]     events              - Interrupt events.
++*
++*@Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_RTC_EnableInterrupt(t_Handle h_FmRtc, uint32_t events);
++
++/**************************************************************************//**
++*@Function      FM_RTC_DisableInterrupt
++*
++*@Description   Disable interrupt of FM RTC.
++*
++*@Param[in]     h_FmRtc             - Handle to FM RTC object.
++*@Param[in]     events              - Interrupt events.
++*
++*@Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_RTC_DisableInterrupt(t_Handle h_FmRtc, uint32_t events);
++#endif
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++/**************************************************************************//**
++ @Function      FM_RTC_DumpRegs
++
++ @Description   Dumps all FM registers
++
++ @Param[in]     h_FmRtc      A handle to an FM RTC Module.
++
++ @Return        E_OK on success;
++
++ @Cautions      Allowed only FM_Init().
++*//***************************************************************************/
++t_Error FM_RTC_DumpRegs(t_Handle h_FmRtc);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++/** @} */ /* end of fm_rtc_control_grp */
++/** @} */ /* end of fm_rtc_grp */
++/** @} */ /* end of FM_grp group */
++
++
++#endif /* __FM_RTC_EXT_H__ */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_vsp_ext.h
+@@ -0,0 +1,411 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          fm_vsp_ext.h
++
++ @Description   FM Virtual Storage-Profile ...
++*//***************************************************************************/
++#ifndef __FM_VSP_EXT_H
++#define __FM_VSP_EXT_H
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "string_ext.h"
++#include "debug_ext.h"
++
++#include "fm_ext.h"
++
++
++/**************************************************************************//**
++
++ @Group         FM_grp Frame Manager API
++
++ @Description   FM API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         FM_VSP_grp FM Virtual-Storage-Profile
++
++ @Description   FM Virtual-Storage-Profile API
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         FM_VSP_init_grp FM VSP Initialization Unit
++
++ @Description   FM VSP initialization API.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   Virtual Storage Profile
++*//***************************************************************************/
++typedef struct t_FmVspParams {
++    t_Handle            h_Fm;               /**< A handle to the FM object this VSP related to */
++    t_FmExtPools        extBufPools;        /**< Which external buffer pools are used
++                                                 (up to FM_PORT_MAX_NUM_OF_EXT_POOLS), and their sizes.
++                                                 parameter associated with Rx / OP port */
++    uint16_t            liodnOffset;        /**< VSP's LIODN offset */
++    struct {
++        e_FmPortType    portType;           /**< Port type */
++        uint8_t         portId;             /**< Port Id - relative to type */
++    } portParams;
++    uint8_t             relativeProfileId;  /**< VSP Id - relative to VSP's range
++                                                 defined in relevant FM object */
++} t_FmVspParams;
++
++
++/**************************************************************************//**
++ @Function      FM_VSP_Config
++
++ @Description   Creates descriptor for the FM VSP module.
++
++                The routine returns a handle (descriptor) to the FM VSP object.
++                This descriptor must be passed as first parameter to all other
++                FM VSP function calls.
++
++                No actual initialization or configuration of FM hardware is
++                done by this routine.
++
++@Param[in]      p_FmVspParams   Pointer to data structure of parameters
++
++ @Retval        Handle to FM VSP object, or NULL for Failure.
++*//***************************************************************************/
++t_Handle FM_VSP_Config(t_FmVspParams *p_FmVspParams);
++
++/**************************************************************************//**
++ @Function      FM_VSP_Init
++
++ @Description   Initializes the FM VSP module
++
++ @Param[in]     h_FmVsp - FM VSP module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_VSP_Init(t_Handle h_FmVsp);
++
++/**************************************************************************//**
++ @Function      FM_VSP_Free
++
++ @Description   Frees all resources that were assigned to FM VSP module.
++
++                Calling this routine invalidates the descriptor.
++
++ @Param[in]     h_FmVsp - FM VSP module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error FM_VSP_Free(t_Handle h_FmVsp);
++
++
++/**************************************************************************//**
++ @Group         FM_VSP_adv_config_grp  FM VSP Advanced Configuration Unit
++
++ @Description   FM VSP advanced configuration functions.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      FM_VSP_ConfigBufferPrefixContent
++
++ @Description   Defines the structure, size and content of the application buffer.
++
++                The prefix will
++                In VSPs defined for Tx ports, if 'passPrsResult', the application
++                should set a value to their offsets in the prefix of
++                the FM will save the first 'privDataSize', than,
++                depending on 'passPrsResult' and 'passTimeStamp', copy parse result
++                and timeStamp, and the packet itself (in this order), to the
++                application buffer, and to offset.
++
++                Calling this routine changes the buffer margins definitions
++                in the internal driver data base from its default
++                configuration: Data size:  [DEFAULT_FM_SP_bufferPrefixContent_privDataSize]
++                               Pass Parser result: [DEFAULT_FM_SP_bufferPrefixContent_passPrsResult].
++                               Pass timestamp: [DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp].
++
++ @Param[in]     h_FmVsp                         A handle to a FM VSP module.
++ @Param[in,out] p_FmBufferPrefixContent         A structure of parameters describing the
++                                                structure of the buffer.
++                                                Out parameter: Start margin - offset
++                                                of data from start of external buffer.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_VSP_Config() and before FM_VSP_Init().
++*//***************************************************************************/
++t_Error FM_VSP_ConfigBufferPrefixContent(t_Handle                   h_FmVsp,
++                                         t_FmBufferPrefixContent    *p_FmBufferPrefixContent);
++
++/**************************************************************************//**
++ @Function      FM_VSP_ConfigDmaSwapData
++
++ @Description   Calling this routine changes the DMA swap data parameter
++                in the internal driver data base from its default
++                configuration  [DEFAULT_FM_SP_dmaSwapData]
++
++ @Param[in]     h_FmVsp     A handle to a FM VSP module.
++ @Param[in]     swapData    New selection
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_VSP_Config() and before FM_VSP_Init().
++*//***************************************************************************/
++t_Error FM_VSP_ConfigDmaSwapData(t_Handle h_FmVsp, e_FmDmaSwapOption swapData);
++
++/**************************************************************************//**
++ @Function      FM_VSP_ConfigDmaIcCacheAttr
++
++ @Description   Calling this routine changes the internal context cache
++                attribute parameter in the internal driver data base
++                from its default configuration  [DEFAULT_FM_SP_dmaIntContextCacheAttr]
++
++ @Param[in]     h_FmVsp                 A handle to a FM VSP module.
++ @Param[in]     intContextCacheAttr     New selection
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_VSP_Config() and before FM_VSP_Init().
++*//***************************************************************************/
++t_Error FM_VSP_ConfigDmaIcCacheAttr(t_Handle            h_FmVsp,
++                                    e_FmDmaCacheOption  intContextCacheAttr);
++
++/**************************************************************************//**
++ @Function      FM_VSP_ConfigDmaHdrAttr
++
++ @Description   Calling this routine changes the header cache
++                attribute parameter in the internal driver data base
++                from its default configuration  [DEFAULT_FM_SP_dmaHeaderCacheAttr]
++
++ @Param[in]     h_FmVsp                     A handle to a FM VSP module.
++ @Param[in]     headerCacheAttr             New selection
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_VSP_Config() and before FM_VSP_Init().
++*//***************************************************************************/
++t_Error FM_VSP_ConfigDmaHdrAttr(t_Handle h_FmVsp, e_FmDmaCacheOption headerCacheAttr);
++
++/**************************************************************************//**
++ @Function      FM_VSP_ConfigDmaScatterGatherAttr
++
++ @Description   Calling this routine changes the scatter gather cache
++                attribute parameter in the internal driver data base
++                from its default configuration [DEFAULT_FM_SP_dmaScatterGatherCacheAttr]
++
++ @Param[in]     h_FmVsp                     A handle to a FM VSP module.
++ @Param[in]     scatterGatherCacheAttr      New selection
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_VSP_Config() and before FM_VSP_Init().
++*//***************************************************************************/
++t_Error FM_VSP_ConfigDmaScatterGatherAttr(t_Handle              h_FmVsp,
++                                          e_FmDmaCacheOption    scatterGatherCacheAttr);
++
++/**************************************************************************//**
++ @Function      FM_VSP_ConfigDmaWriteOptimize
++
++ @Description   Calling this routine changes the write optimization
++                parameter in the internal driver data base
++                from its default configuration: optimize = [DEFAULT_FM_SP_dmaWriteOptimize]
++
++ @Param[in]     h_FmVsp     A handle to a FM VSP module.
++ @Param[in]     optimize    TRUE to enable optimization, FALSE for normal operation
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_VSP_Config() and before FM_VSP_Init().
++*//***************************************************************************/
++t_Error FM_VSP_ConfigDmaWriteOptimize(t_Handle h_FmVsp, bool optimize);
++
++/**************************************************************************//**
++ @Function      FM_VSP_ConfigNoScatherGather
++
++ @Description   Calling this routine changes the possibility to receive S/G frame
++                in the internal driver data base
++                from its default configuration: optimize = [DEFAULT_FM_SP_noScatherGather]
++
++ @Param[in]     h_FmVsp             A handle to a FM VSP module.
++ @Param[in]     noScatherGather     TRUE to operate without scatter/gather capability.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_VSP_Config() and before FM_VSP_Init().
++*//***************************************************************************/
++t_Error FM_VSP_ConfigNoScatherGather(t_Handle h_FmVsp, bool noScatherGather);
++
++/**************************************************************************//**
++ @Function      FM_VSP_ConfigPoolDepletion
++
++ @Description   Calling this routine enables pause frame generation depending on the
++                depletion status of BM pools. It also defines the conditions to activate
++                this functionality. By default, this functionality is disabled.
++
++ @Param[in]     h_FmVsp                 A handle to a FM VSP module.
++ @Param[in]     p_BufPoolDepletion      A structure of pool depletion parameters
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_VSP_Config() and before FM_VSP_Init().
++*//***************************************************************************/
++t_Error FM_VSP_ConfigPoolDepletion(t_Handle h_FmVsp, t_FmBufPoolDepletion *p_BufPoolDepletion);
++
++/**************************************************************************//**
++ @Function      FM_VSP_ConfigBackupPools
++
++ @Description   Calling this routine allows the configuration of some of the BM pools
++                defined for this port as backup pools.
++                A pool configured to be a backup pool will be used only if all other
++                enabled non-backup pools are depleted.
++
++ @Param[in]     h_FmVsp                 A handle to a FM VSP module.
++ @Param[in]     p_BackupBmPools         An array of pool id's. All pools specified here will
++                                        be defined as backup pools.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_VSP_Config() and before FM_VSP_Init().
++*//***************************************************************************/
++t_Error FM_VSP_ConfigBackupPools(t_Handle h_FmVsp, t_FmBackupBmPools *p_BackupBmPools);
++
++/** @} */ /* end of FM_VSP_adv_config_grp group */
++/** @} */ /* end of FM_VSP_init_grp group */
++
++
++/**************************************************************************//**
++ @Group         FM_VSP_control_grp FM VSP Control Unit
++
++ @Description   FM VSP runtime control API.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      FM_VSP_GetBufferDataOffset
++
++ @Description   Relevant for Rx ports.
++                Returns the data offset from the beginning of the data buffer
++
++ @Param[in]     h_FmVsp - FM PORT module descriptor
++
++ @Return        data offset.
++
++ @Cautions      Allowed only following FM_VSP_Init().
++*//***************************************************************************/
++uint32_t FM_VSP_GetBufferDataOffset(t_Handle h_FmVsp);
++
++/**************************************************************************//**
++ @Function      FM_VSP_GetBufferICInfo
++
++ @Description   Returns the Internal Context offset from the beginning of the data buffer
++
++ @Param[in]     h_FmVsp - FM PORT module descriptor
++ @Param[in]     p_Data   - A pointer to the data buffer.
++
++ @Return        Internal context info pointer on success, NULL if 'allOtherInfo' was not
++                configured for this port.
++
++ @Cautions      Allowed only following FM_VSP_Init().
++*//***************************************************************************/
++uint8_t * FM_VSP_GetBufferICInfo(t_Handle h_FmVsp, char *p_Data);
++
++/**************************************************************************//**
++ @Function      FM_VSP_GetBufferPrsResult
++
++ @Description   Returns the pointer to the parse result in the data buffer.
++                In Rx ports this is relevant after reception, if parse
++                result is configured to be part of the data passed to the
++                application. For non Rx ports it may be used to get the pointer
++                of the area in the buffer where parse result should be
++                initialized - if so configured.
++                See FM_VSP_ConfigBufferPrefixContent for data buffer prefix
++                configuration.
++
++ @Param[in]     h_FmVsp    - FM PORT module descriptor
++ @Param[in]     p_Data      - A pointer to the data buffer.
++
++ @Return        Parse result pointer on success, NULL if parse result was not
++                configured for this port.
++
++ @Cautions      Allowed only following FM_VSP_Init().
++*//***************************************************************************/
++t_FmPrsResult * FM_VSP_GetBufferPrsResult(t_Handle h_FmVsp, char *p_Data);
++
++/**************************************************************************//**
++ @Function      FM_VSP_GetBufferTimeStamp
++
++ @Description   Returns the time stamp in the data buffer.
++                Relevant for Rx ports for getting the buffer time stamp.
++                See FM_VSP_ConfigBufferPrefixContent for data buffer prefix
++                configuration.
++
++ @Param[in]     h_FmVsp    - FM PORT module descriptor
++ @Param[in]     p_Data      - A pointer to the data buffer.
++
++ @Return        A pointer to the hash result on success, NULL otherwise.
++
++ @Cautions      Allowed only following FM_VSP_Init().
++*//***************************************************************************/
++uint64_t * FM_VSP_GetBufferTimeStamp(t_Handle h_FmVsp, char *p_Data);
++
++/**************************************************************************//**
++ @Function      FM_VSP_GetBufferHashResult
++
++ @Description   Given a data buffer, on the condition that hash result was defined
++                as a part of the buffer content (see FM_VSP_ConfigBufferPrefixContent)
++                this routine will return the pointer to the hash result location in the
++                buffer prefix.
++
++ @Param[in]     h_FmVsp    - FM PORT module descriptor
++ @Param[in]     p_Data      - A pointer to the data buffer.
++
++ @Return        A pointer to the hash result on success, NULL otherwise.
++
++ @Cautions      Allowed only following FM_VSP_Init().
++*//***************************************************************************/
++uint8_t * FM_VSP_GetBufferHashResult(t_Handle h_FmVsp, char *p_Data);
++
++
++/** @} */ /* end of FM_VSP_control_grp group */
++/** @} */ /* end of FM_VSP_grp group */
++/** @} */ /* end of FM_grp group */
++
++
++#endif /* __FM_VSP_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/mii_acc_ext.h
+@@ -0,0 +1,76 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++
++#ifndef __MII_ACC_EXT_H
++#define __MII_ACC_EXT_H
++
++
++/**************************************************************************//**
++ @Function      MII_ReadPhyReg
++
++ @Description   This routine is called to read a specified PHY
++                register value.
++
++ @Param[in]     h_MiiAccess - Handle to MII configuration access registers
++ @Param[in]     phyAddr     - PHY address (0-31).
++ @Param[in]     reg         - PHY register to read
++ @Param[out]    p_Data      - Gets the register value.
++
++ @Return        Always zero (success).
++*//***************************************************************************/
++int MII_ReadPhyReg(t_Handle h_MiiAccess,
++                   uint8_t  phyAddr,
++                   uint8_t  reg,
++                   uint16_t *p_Data);
++
++/**************************************************************************//**
++ @Function      MII_WritePhyReg
++
++ @Description   This routine is called to write data to a specified PHY
++                   register.
++
++ @Param[in]     h_MiiAccess - Handle to MII configuration access registers
++ @Param[in]     phyAddr     - PHY address (0-31).
++ @Param[in]     reg         - PHY register to write
++ @Param[in]     data        - Data to write in register.
++
++ @Return        Always zero (success).
++*//***************************************************************************/
++int MII_WritePhyReg(t_Handle    h_MiiAccess,
++                    uint8_t     phyAddr,
++                    uint8_t     reg,
++                    uint16_t    data);
++
++
++#endif /* __MII_ACC_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/core_ext.h
+@@ -0,0 +1,90 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          core_ext.h
++
++ @Description   Generic interface to basic core operations.
++
++                The system integrator must ensure that this interface is
++                mapped to a specific core implementation, by including the
++                appropriate header file.
++*//***************************************************************************/
++#ifndef __CORE_EXT_H
++#define __CORE_EXT_H
++
++#ifdef CONFIG_FMAN_ARM
++#include "arm_ext.h"
++#include <linux/smp.h>
++#else
++#ifdef NCSW_PPC_CORE
++#include "ppc_ext.h"
++#elif defined(NCSW_VXWORKS)
++#include "core_vxw_ext.h"
++#else
++#error "Core is not defined!"
++#endif /* NCSW_CORE */
++
++#if (!defined(CORE_IS_LITTLE_ENDIAN) && !defined(CORE_IS_BIG_ENDIAN))
++#error "Must define core as little-endian or big-endian!"
++#endif /* (!defined(CORE_IS_LITTLE_ENDIAN) && ... */
++
++#ifndef CORE_CACHELINE_SIZE
++#error "Must define the core cache-line size!"
++#endif /* !CORE_CACHELINE_SIZE */
++
++#endif /* CONFIG_FMAN_ARM */
++
++
++/**************************************************************************//**
++ @Function      CORE_GetId
++
++ @Description   Returns the core ID in the system.
++
++ @Return        Core ID.
++*//***************************************************************************/
++uint32_t CORE_GetId(void);
++
++/**************************************************************************//**
++ @Function      CORE_MemoryBarrier
++
++ @Description   This routine will cause the core to stop executing any commands
++                until all previous memory read/write commands are completely out
++                of the core's pipeline.
++
++ @Return        None.
++*//***************************************************************************/
++void CORE_MemoryBarrier(void);
++#define fsl_mem_core_barrier() CORE_MemoryBarrier()
++
++#endif /* __CORE_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/cores/arm_ext.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          arm_ext.h
++
++ @Description   Core API for ARM cores
++
++                These routines must be implemented by each specific PowerPC
++                core driver.
++*//***************************************************************************/
++#ifndef __ARM_EXT_H
++#define __ARM_EXT_H
++
++#include "part_ext.h"
++
++
++#define CORE_IS_LITTLE_ENDIAN
++
++static __inline__ void CORE_MemoryBarrier(void)
++{
++      mb();
++}
++
++#endif /* __PPC_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/cores/e500v2_ext.h
+@@ -0,0 +1,476 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          e500v2_ext.h
++
++ @Description   E500 external definitions prototypes
++                This file is not included by the E500
++                source file as it is an assembly file. It is used
++                only for prototypes exposure, for inclusion
++                by user and other modules.
++*//***************************************************************************/
++
++#ifndef __E500V2_EXT_H
++#define __E500V2_EXT_H
++
++#include "std_ext.h"
++
++
++/* Layer 1 Cache Manipulations
++ *==============================
++ * Should not be called directly by the user.
++ */
++void        L1DCache_Invalidate (void);
++void        L1ICache_Invalidate(void);
++void        L1DCache_Enable(void);
++void        L1ICache_Enable(void);
++void        L1DCache_Disable(void);
++void        L1ICache_Disable(void);
++void        L1DCache_Flush(void);
++void        L1ICache_Flush(void);
++uint32_t    L1ICache_IsEnabled(void);
++uint32_t    L1DCache_IsEnabled(void);
++/*
++ *
++ */
++uint32_t    L1DCache_LineLock(uint32_t addr);
++uint32_t    L1ICache_LineLock(uint32_t addr);
++void        L1Cache_BroadCastEnable(void);
++void        L1Cache_BroadCastDisable(void);
++
++
++#define CORE_DCacheEnable       E500_DCacheEnable
++#define CORE_ICacheEnable       E500_ICacheEnable
++#define CORE_DCacheDisable      E500_DCacheDisable
++#define CORE_ICacheDisable      E500_ICacheDisable
++#define CORE_GetId              E500_GetId
++#define CORE_TestAndSet         E500_TestAndSet
++#define CORE_MemoryBarrier      E500_MemoryBarrier
++#define CORE_InstructionSync    E500_InstructionSync
++
++#define CORE_SetDozeMode        E500_SetDozeMode
++#define CORE_SetNapMode         E500_SetNapMode
++#define CORE_SetSleepMode       E500_SetSleepMode
++#define CORE_SetJogMode         E500_SetJogMode
++#define CORE_SetDeepSleepMode   E500_SetDeepSleepMode
++
++#define CORE_RecoverDozeMode    E500_RecoverDozeMode
++#define CORE_RecoverNapMode     E500_RecoverNapMode
++#define CORE_RecoverSleepMode   E500_RecoverSleepMode
++#define CORE_RecoverJogMode     E500_RecoverJogMode
++
++void E500_SetDozeMode(void);
++void E500_SetNapMode(void);
++void E500_SetSleepMode(void);
++void E500_SetJogMode(void);
++t_Error E500_SetDeepSleepMode(uint32_t bptrAddress);
++
++void E500_RecoverDozeMode(void);
++void E500_RecoverNapMode(void);
++void E500_RecoverSleepMode(void);
++void E500_RecoverJogMode(void);
++
++
++/**************************************************************************//**
++ @Group         E500_id E500 Application Programming Interface
++
++ @Description   E500 API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         E500_init_grp E500 Initialization Unit
++
++ @Description   E500 initialization unit API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++
++/**************************************************************************//**
++ @Function      E500_DCacheEnable
++
++ @Description   Enables the data cache for memory pages that are
++                not cache inhibited.
++
++ @Return        None.
++*//***************************************************************************/
++void E500_DCacheEnable(void);
++
++/**************************************************************************//**
++ @Function      E500_ICacheEnable
++
++ @Description   Enables the instruction cache for memory pages that are
++                not cache inhibited.
++
++ @Return        None.
++*//***************************************************************************/
++void E500_ICacheEnable(void);
++
++/**************************************************************************//**
++ @Function      E500_DCacheDisable
++
++ @Description   Disables the data cache.
++
++ @Return        None.
++*//***************************************************************************/
++void E500_DCacheDisable(void);
++
++/**************************************************************************//**
++ @Function      E500_ICacheDisable
++
++ @Description   Disables the instruction cache.
++
++ @Return        None.
++*//***************************************************************************/
++void E500_ICacheDisable(void);
++
++/**************************************************************************//**
++ @Function      E500_DCacheFlush
++
++ @Description   Flushes the data cache
++
++ @Return        None.
++*//***************************************************************************/
++void E500_DCacheFlush(void);
++
++/**************************************************************************//**
++ @Function      E500_ICacheFlush
++
++ @Description   Flushes the instruction cache.
++
++ @Return        None.
++*//***************************************************************************/
++void E500_ICacheFlush(void);
++
++/**************************************************************************//**
++ @Function      E500_DCacheSetStashId
++
++ @Description   Set Stash Id for data cache
++
++ @Param[in]     stashId     the stash id to be set.
++
++ @Return        None.
++*//***************************************************************************/
++void E500_DCacheSetStashId(uint8_t stashId);
++
++/**************************************************************************//**
++ @Description   E500mc L2 Cache Operation Mode
++*//***************************************************************************/
++typedef enum e_E500mcL2CacheMode
++{
++    e_L2_CACHE_MODE_DATA_ONLY      = 0x00000001,   /**< Cache data only */
++    e_L2_CACHE_MODE_INST_ONLY      = 0x00000002,   /**< Cache instructions only */
++    e_L2_CACHE_MODE_DATA_AND_INST  = 0x00000003    /**< Cache data and instructions */
++} e_E500mcL2CacheMode;
++
++#if defined(CORE_E500MC) || defined(CORE_E5500)
++/**************************************************************************//**
++ @Function      E500_L2CacheEnable
++
++ @Description   Enables the cache for memory pages that are not cache inhibited.
++
++ @param[in]     mode - L2 cache mode: data only, instruction only or instruction and data.
++
++ @Return        None.
++
++ @Cautions      This routine must be call only ONCE for both caches. I.e. it is
++                not possible to call this routine for i-cache and than to call
++                again for d-cache; The second call will override the first one.
++*//***************************************************************************/
++void E500_L2CacheEnable(e_E500mcL2CacheMode mode);
++
++/**************************************************************************//**
++ @Function      E500_L2CacheDisable
++
++ @Description   Disables the cache (data instruction or both).
++
++ @Return        None.
++
++*//***************************************************************************/
++void E500_L2CacheDisable(void);
++
++/**************************************************************************//**
++ @Function      E500_L2CacheFlush
++
++ @Description   Flushes the cache.
++
++ @Return        None.
++*//***************************************************************************/
++void E500_L2CacheFlush(void);
++
++/**************************************************************************//**
++ @Function      E500_L2SetStashId
++
++ @Description   Set Stash Id
++
++ @Param[in]     stashId     the stash id to be set.
++
++ @Return        None.
++*//***************************************************************************/
++void E500_L2SetStashId(uint8_t stashId);
++#endif /* defined(CORE_E500MC) || defined(CORE_E5500) */
++
++#ifdef CORE_E6500
++/**************************************************************************//**
++ @Function      E6500_L2CacheEnable
++
++ @Description   Enables the cache for memory pages that are not cache inhibited.
++
++ @param[in]     mode - L2 cache mode: support data & instruction only.
++
++ @Return        None.
++
++ @Cautions      This routine must be call only ONCE for both caches. I.e. it is
++                not possible to call this routine for i-cache and than to call
++                again for d-cache; The second call will override the first one.
++*//***************************************************************************/
++void E6500_L2CacheEnable(uintptr_t clusterBase);
++
++/**************************************************************************//**
++ @Function      E6500_L2CacheDisable
++
++ @Description   Disables the cache (data instruction or both).
++
++ @Return        None.
++
++*//***************************************************************************/
++void E6500_L2CacheDisable(uintptr_t clusterBase);
++
++/**************************************************************************//**
++ @Function      E6500_L2CacheFlush
++
++ @Description   Flushes the cache.
++
++ @Return        None.
++*//***************************************************************************/
++void E6500_L2CacheFlush(uintptr_t clusterBase);
++
++/**************************************************************************//**
++ @Function      E6500_L2SetStashId
++
++ @Description   Set Stash Id
++
++ @Param[in]     stashId     the stash id to be set.
++
++ @Return        None.
++*//***************************************************************************/
++void E6500_L2SetStashId(uintptr_t clusterBase, uint8_t stashId);
++
++/**************************************************************************//**
++ @Function      E6500_GetCcsrBase
++
++ @Description   Obtain SoC CCSR base address
++
++ @Param[in]     None.
++
++ @Return        Physical CCSR base address.
++*//***************************************************************************/
++physAddress_t E6500_GetCcsrBase(void);
++#endif /* CORE_E6500 */
++
++/**************************************************************************//**
++ @Function      E500_AddressBusStreamingEnable
++
++ @Description   Enables address bus streaming on the CCB.
++
++                This setting, along with the ECM streaming configuration
++                parameters, enables address bus streaming on the CCB.
++
++ @Return        None.
++*//***************************************************************************/
++void E500_AddressBusStreamingEnable(void);
++
++/**************************************************************************//**
++ @Function      E500_AddressBusStreamingDisable
++
++ @Description   Disables address bus streaming on the CCB.
++
++ @Return        None.
++*//***************************************************************************/
++void E500_AddressBusStreamingDisable(void);
++
++/**************************************************************************//**
++ @Function      E500_AddressBroadcastEnable
++
++ @Description   Enables address broadcast.
++
++                The e500 broadcasts cache management instructions (dcbst, dcblc
++                (CT = 1), icblc (CT = 1), dcbf, dcbi, mbar, msync, tlbsync, icbi)
++                based on ABE. ABE must be set to allow management of external
++                L2 caches.
++
++ @Return        None.
++*//***************************************************************************/
++void E500_AddressBroadcastEnable(void);
++
++/**************************************************************************//**
++ @Function      E500_AddressBroadcastDisable
++
++ @Description   Disables address broadcast.
++
++                The e500 broadcasts cache management instructions (dcbst, dcblc
++                (CT = 1), icblc (CT = 1), dcbf, dcbi, mbar, msync, tlbsync, icbi)
++                based on ABE. ABE must be set to allow management of external
++                L2 caches.
++
++ @Return        None.
++*//***************************************************************************/
++void E500_AddressBroadcastDisable(void);
++
++/**************************************************************************//**
++ @Function      E500_IsTaskletSupported
++
++ @Description   Checks if tasklets are supported by the e500 interrupt handler.
++
++ @Retval        TRUE    - Tasklets are supported.
++ @Retval        FALSE   - Tasklets are not supported.
++*//***************************************************************************/
++bool E500_IsTaskletSupported(void);
++
++void E500_EnableTimeBase(void);
++void E500_DisableTimeBase(void);
++
++uint64_t E500_GetTimeBaseTime(void);
++
++void E500_GenericIntrInit(void);
++
++t_Error E500_SetIntr(int        ppcIntrSrc,
++                     void       (* Isr)(t_Handle handle),
++                     t_Handle   handle);
++
++t_Error E500_ClearIntr(int ppcIntrSrc);
++
++/**************************************************************************//**
++ @Function      E500_GenericIntrHandler
++
++ @Description   This is the general e500 interrupt handler.
++
++                It is called by the main assembly interrupt handler
++                when an exception occurs and no other function has been
++                assigned to this exception.
++
++ @Param         intrEntry   - (In) The exception interrupt vector entry.
++*//***************************************************************************/
++void E500_GenericIntrHandler(uint32_t intrEntry);
++
++/**************************************************************************//**
++ @Function      CriticalIntr
++
++ @Description   This is the specific critical e500 interrupt handler.
++
++                It is called by the main assembly interrupt handler
++                when an critical interrupt.
++
++ @Param         intrEntry   - (In) The exception interrupt vector entry.
++*//***************************************************************************/
++void CriticalIntr(uint32_t intrEntry);
++
++
++/**************************************************************************//**
++ @Function      E500_GetId
++
++ @Description   Returns the core ID in the system.
++
++ @Return        Core ID.
++*//***************************************************************************/
++uint32_t E500_GetId(void);
++
++/**************************************************************************//**
++ @Function      E500_TestAndSet
++
++ @Description   This routine tries to atomically test-and-set an integer
++                in memory to a non-zero value.
++
++                The memory will be set only if it is tested as zero, in which
++                case the routine returns the new non-zero value; otherwise the
++                routine returns zero.
++
++ @Param[in]     p - pointer to a volatile int in memory, on which test-and-set
++                    operation should be made.
++
++ @Retval        Zero        - Operation failed - memory was already set.
++ @Retval        Non-zero    - Operation succeeded - memory has been set.
++*//***************************************************************************/
++int E500_TestAndSet(volatile int *p);
++
++/**************************************************************************//**
++ @Function      E500_MemoryBarrier
++
++ @Description   This routine will cause the core to stop executing any commands
++                until all previous memory read/write commands are completely out
++                of the core's pipeline.
++
++ @Return        None.
++*//***************************************************************************/
++static __inline__ void E500_MemoryBarrier(void)
++{
++#ifndef CORE_E500V2
++    __asm__ ("mbar 1");
++#else  /* CORE_E500V2 */
++    /**** ERRATA WORK AROUND START ****/
++    /* ERRATA num:  CPU1 */
++    /* Description: "mbar MO = 1" instruction fails to order caching-inhibited
++                    guarded loads and stores. */
++
++    /* "msync" instruction is used instead */
++
++    __asm__ ("msync");
++
++    /**** ERRATA WORK AROUND END ****/
++#endif /* CORE_E500V2 */
++}
++
++/**************************************************************************//**
++ @Function      E500_InstructionSync
++
++ @Description   This routine will cause the core to wait for previous instructions
++                (including any interrupts they generate) to complete before the
++                synchronization command executes, which purges all instructions
++                from the processor's pipeline and refetches the next instruction.
++
++ @Return        None.
++*//***************************************************************************/
++static __inline__ void E500_InstructionSync(void)
++{
++    __asm__ ("isync");
++}
++
++
++/** @} */ /* end of E500_init_grp group */
++/** @} */ /* end of E500_grp group */
++
++
++#endif /* __E500V2_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/cores/ppc_ext.h
+@@ -0,0 +1,141 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          ppc_ext.h
++
++ @Description   Core API for PowerPC cores
++
++                These routines must be implemented by each specific PowerPC
++                core driver.
++*//***************************************************************************/
++#ifndef __PPC_EXT_H
++#define __PPC_EXT_H
++
++#include "part_ext.h"
++
++
++#define CORE_IS_BIG_ENDIAN
++
++#if defined(CORE_E300) || defined(CORE_E500V2)
++#define CORE_CACHELINE_SIZE     32
++#elif defined(CORE_E500MC) || defined(CORE_E5500) || defined(CORE_E6500)
++#define CORE_CACHELINE_SIZE     64
++#else
++#error "Core not defined!"
++#endif /* defined(CORE_E300) || ... */
++
++
++/**************************************************************************//**
++ @Function      CORE_TestAndSet
++
++ @Description   This routine tries to atomically test-and-set an integer
++                in memory to a non-zero value.
++
++                The memory will be set only if it is tested as zero, in which
++                case the routine returns the new non-zero value; otherwise the
++                routine returns zero.
++
++ @Param[in]     p - pointer to a volatile int in memory, on which test-and-set
++                    operation should be made.
++
++ @Retval        Zero        - Operation failed - memory was already set.
++ @Retval        Non-zero    - Operation succeeded - memory has been set.
++*//***************************************************************************/
++int CORE_TestAndSet(volatile int *p);
++
++/**************************************************************************//**
++ @Function      CORE_InstructionSync
++
++ @Description   This routine will cause the core to wait for previous instructions
++                (including any interrupts they generate) to complete before the
++                synchronization command executes, which purges all instructions
++                from the processor's pipeline and refetches the next instruction.
++
++ @Return        None.
++*//***************************************************************************/
++void CORE_InstructionSync(void);
++
++/**************************************************************************//**
++ @Function      CORE_DCacheEnable
++
++ @Description   Enables the data cache for memory pages that are
++                not cache inhibited.
++
++ @Return        None.
++*//***************************************************************************/
++void CORE_DCacheEnable(void);
++
++/**************************************************************************//**
++ @Function      CORE_ICacheEnable
++
++ @Description   Enables the instruction cache for memory pages that are
++                not cache inhibited.
++
++ @Return        None.
++*//***************************************************************************/
++void CORE_ICacheEnable(void);
++
++/**************************************************************************//**
++ @Function      CORE_DCacheDisable
++
++ @Description   Disables the data cache.
++
++ @Return        None.
++*//***************************************************************************/
++void CORE_DCacheDisable(void);
++
++/**************************************************************************//**
++ @Function      CORE_ICacheDisable
++
++ @Description   Disables the instruction cache.
++
++ @Return        None.
++*//***************************************************************************/
++void CORE_ICacheDisable(void);
++
++
++
++#if defined(CORE_E300)
++#include "e300_ext.h"
++#elif defined(CORE_E500V2) || defined(CORE_E500MC) || defined(CORE_E5500) || defined(CORE_E6500)
++#include "e500v2_ext.h"
++#if !defined(NCSW_LINUX)
++#include "e500v2_asm_ext.h"
++#endif
++#else
++#error "Core not defined!"
++#endif
++
++
++#endif /* __PPC_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/ddr_std_ext.h
+@@ -0,0 +1,77 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __DDR_SDT_EXT_H
++#define __DDR_SDT_EXT_H
++
++
++/**************************************************************************//**
++ @Group         ddr_Generic_Resources
++
++ @Description   ddr generic functions, definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++
++/**************************************************************************//**
++ @Description   SPD maximum size
++*//***************************************************************************/
++#define SPD_MAX_SIZE 256
++
++/**************************************************************************//**
++ @Description   DDR types select
++*//***************************************************************************/
++typedef enum e_DdrType
++{
++    e_DDR_DDR1,
++    e_DDR_DDR2,
++    e_DDR_DDR3,
++    e_DDR_DDR3L,
++    e_DDR_DDR4
++} e_DdrType;
++
++/**************************************************************************//**
++ @Description   DDR Mode.
++*//***************************************************************************/
++typedef enum e_DdrMode
++{
++    e_DDR_BUS_WIDTH_32BIT,
++    e_DDR_BUS_WIDTH_64BIT
++} e_DdrMode;
++
++/** @} */ /* end of ddr_Generic_Resources group */
++
++
++
++#endif /* __DDR_SDT_EXT_H */
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/debug_ext.h
+@@ -0,0 +1,233 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          debug_ext.h
++
++ @Description   Debug mode definitions.
++*//***************************************************************************/
++
++#ifndef __DEBUG_EXT_H
++#define __DEBUG_EXT_H
++
++#include "std_ext.h"
++#include "xx_ext.h"
++#include "memcpy_ext.h"
++#if (DEBUG_ERRORS > 0)
++#include "sprint_ext.h"
++#include "string_ext.h"
++#endif /* DEBUG_ERRORS > 0 */
++
++
++#if (DEBUG_ERRORS > 0)
++
++/* Internally used macros */
++
++#define DUMP_Print          XX_Print
++#define DUMP_MAX_LEVELS     6
++#define DUMP_IDX_LEN        6
++#define DUMP_MAX_STR        64
++
++
++#define _CREATE_DUMP_SUBSTR(phrase) \
++    dumpTmpLevel = 0; dumpSubStr[0] = '\0'; \
++    snprintf(dumpTmpStr, DUMP_MAX_STR, "%s", #phrase); \
++    p_DumpToken = strtok(dumpTmpStr, (dumpIsArr[0] ? "[" : ".")); \
++    while ((p_DumpToken != NULL) && (dumpTmpLevel < DUMP_MAX_LEVELS)) \
++    { \
++        strlcat(dumpSubStr, p_DumpToken, DUMP_MAX_STR); \
++        if (dumpIsArr[dumpTmpLevel]) \
++        { \
++            strlcat(dumpSubStr, dumpIdxStr[dumpTmpLevel], DUMP_MAX_STR); \
++            p_DumpToken = strtok(NULL, "."); \
++        } \
++        if ((p_DumpToken != NULL) && \
++            ((p_DumpToken = strtok(NULL, (dumpIsArr[++dumpTmpLevel] ? "[" : "."))) != NULL)) \
++            strlcat(dumpSubStr, ".", DUMP_MAX_STR); \
++    }
++
++
++/**************************************************************************//**
++ @Group         gen_id  General Drivers Utilities
++
++ @Description   External routines.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         dump_id  Memory and Registers Dump Mechanism
++
++ @Description   Macros for dumping memory mapped structures.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   Declaration of dump mechanism variables.
++
++                This macro must be declared at the beginning of each routine
++                which uses the dump mechanism macros, before the routine's code
++                starts.
++*//***************************************************************************/
++#define DECLARE_DUMP \
++    char    dumpIdxStr[DUMP_MAX_LEVELS + 1][DUMP_IDX_LEN] = { "", }; \
++    char    dumpSubStr[DUMP_MAX_STR] = ""; \
++    char    dumpTmpStr[DUMP_MAX_STR] = ""; \
++    char    *p_DumpToken = NULL; \
++    int     dumpArrIdx = 0, dumpArrSize = 0, dumpLevel = 0, dumpTmpLevel = 0; \
++    uint8_t dumpIsArr[DUMP_MAX_LEVELS + 1] = { 0 }; \
++    /* Prevent warnings if not all used */ \
++    UNUSED(dumpIdxStr[0][0]); \
++    UNUSED(dumpSubStr[0]); \
++    UNUSED(dumpTmpStr[0]); \
++    UNUSED(p_DumpToken); \
++    UNUSED(dumpArrIdx); \
++    UNUSED(dumpArrSize); \
++    UNUSED(dumpLevel); \
++    UNUSED(dumpTmpLevel); \
++    UNUSED(dumpIsArr[0]);
++
++
++/**************************************************************************//**
++ @Description   Prints a title for a subsequent dumped structure or memory.
++
++                The inputs for this macro are the structure/memory title and
++                its base addresses.
++*//***************************************************************************/
++#define DUMP_TITLE(addr, msg)           \
++    DUMP_Print("\r\n"); DUMP_Print msg; \
++    if (addr)                           \
++        DUMP_Print(" (%p)", (addr));    \
++    DUMP_Print("\r\n---------------------------------------------------------\r\n");
++
++/**************************************************************************//**
++ @Description   Prints a subtitle for a subsequent dumped sub-structure (optional).
++
++                The inputs for this macro are the sub-structure subtitle.
++                A separating line with this subtitle will be printed.
++*//***************************************************************************/
++#define DUMP_SUBTITLE(subtitle)  \
++    DUMP_Print("----------- "); DUMP_Print subtitle; DUMP_Print("\r\n")
++
++
++/**************************************************************************//**
++ @Description   Dumps a memory region in 4-bytes aligned format.
++
++                The inputs for this macro are the base addresses and size
++                (in bytes) of the memory region.
++*//***************************************************************************/
++#define DUMP_MEMORY(addr, size)  \
++    MemDisp((uint8_t *)(addr), (int)(size))
++
++
++/**************************************************************************//**
++ @Description   Declares a dump loop, for dumping a sub-structure array.
++
++                The inputs for this macro are:
++                - idx: an index variable, for indexing the sub-structure items
++                       inside the loop. This variable must be declared separately
++                       in the beginning of the routine.
++                - cnt: the number of times to repeat the loop. This number should
++                       equal the number of items in the sub-structures array.
++
++                Note, that the body of the loop must be written inside brackets.
++*//***************************************************************************/
++#define DUMP_SUBSTRUCT_ARRAY(idx, cnt) \
++    for (idx=0, dumpIsArr[dumpLevel++] = 1; \
++         (idx < cnt) && (dumpLevel > 0) && snprintf(dumpIdxStr[dumpLevel-1], DUMP_IDX_LEN, "[%d]", idx); \
++         idx++, ((idx < cnt) || (dumpIsArr[--dumpLevel] = 0)))
++
++
++/**************************************************************************//**
++ @Description   Dumps a structure's member variable.
++
++                The input for this macro is the full reference for the member
++                variable, where the structure is referenced using a pointer.
++
++                Note, that a members array must be dumped using DUMP_ARR macro,
++                rather than using this macro.
++
++                If the member variable is part of a sub-structure hierarchy,
++                the full hierarchy (including array indexing) must be specified.
++
++                Examples:   p_Struct->member
++                            p_Struct->sub.member
++                            p_Struct->sub[i].member
++*//***************************************************************************/
++#define DUMP_VAR(st, phrase) \
++    do { \
++        void            *addr = (void *)&((st)->phrase); \
++        physAddress_t   physAddr = XX_VirtToPhys(addr); \
++        _CREATE_DUMP_SUBSTR(phrase); \
++        DUMP_Print("0x%010llX: 0x%08x%8s\t%s\r\n", \
++                   physAddr, GET_UINT32(*(uint32_t*)addr), "", dumpSubStr); \
++    } while (0)
++
++
++/**************************************************************************//**
++ @Description   Dumps a structure's members array.
++
++                The input for this macro is the full reference for the members
++                array, where the structure is referenced using a pointer.
++
++                If the members array is part of a sub-structure hierarchy,
++                the full hierarchy (including array indexing) must be specified.
++
++                Examples:   p_Struct->array
++                            p_Struct->sub.array
++                            p_Struct->sub[i].array
++*//***************************************************************************/
++#define DUMP_ARR(st, phrase) \
++    do { \
++        physAddress_t physAddr; \
++        _CREATE_DUMP_SUBSTR(phrase); \
++        dumpArrSize = ARRAY_SIZE((st)->phrase); \
++        for (dumpArrIdx=0; dumpArrIdx < dumpArrSize; dumpArrIdx++) { \
++            physAddr = XX_VirtToPhys((void *)&((st)->phrase[dumpArrIdx])); \
++            DUMP_Print("0x%010llX: 0x%08x%8s\t%s[%d]\r\n", \
++                       physAddr, GET_UINT32((st)->phrase[dumpArrIdx]), "", dumpSubStr, dumpArrIdx); \
++        } \
++    } while (0)
++
++
++
++#endif /* DEBUG_ERRORS > 0 */
++
++
++/** @} */ /* end of dump_id group */
++/** @} */ /* end of gen_id group */
++
++
++#endif /* __DEBUG_EXT_H */
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/endian_ext.h
+@@ -0,0 +1,447 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++
++ @File          endian_ext.h
++
++ @Description   Big/little endian swapping routines.
++*//***************************************************************************/
++
++#ifndef __ENDIAN_EXT_H
++#define __ENDIAN_EXT_H
++
++#include "std_ext.h"
++
++
++/**************************************************************************//**
++ @Group         gen_id  General Drivers Utilities
++
++ @Description   General usage API. This API is intended for usage by both the
++                internal modules and the user's application.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         endian_id Big/Little-Endian Conversion
++
++ @Description   Routines and macros for Big/Little-Endian conversion and
++                general byte swapping.
++
++                All routines and macros are expecting unsigned values as
++                parameters, but will generate the correct result also for
++                signed values. Therefore, signed/unsigned casting is allowed.
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Collection    Byte-Swap Macros
++
++                Macros for swapping byte order.
++
++ @Cautions      The parameters of these macros are evaluated multiple times.
++                For calculated expressions or expressions that contain function
++                calls it is recommended to use the byte-swap routines.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   Swaps the byte order of a given 16-bit value.
++
++ @Param[in]     val - The 16-bit value to swap.
++
++ @Return        The byte-swapped value..
++
++ @Cautions      The given value is evaluated multiple times by this macro.
++                For calculated expressions or expressions that contain function
++                calls it is recommended to use the SwapUint16() routine.
++
++ @hideinitializer
++*//***************************************************************************/
++#define SWAP_UINT16(val) \
++    ((uint16_t)((((val) & 0x00FF) << 8) | (((val) & 0xFF00) >> 8)))
++
++/**************************************************************************//**
++ @Description   Swaps the byte order of a given 32-bit value.
++
++ @Param[in]     val - The 32-bit value to swap.
++
++ @Return        The byte-swapped value..
++
++ @Cautions      The given value is evaluated multiple times by this macro.
++                For calculated expressions or expressions that contain function
++                calls it is recommended to use the SwapUint32() routine.
++
++ @hideinitializer
++*//***************************************************************************/
++#define SWAP_UINT32(val) \
++    ((uint32_t)((((val) & 0x000000FF) << 24) | \
++                (((val) & 0x0000FF00) <<  8) | \
++                (((val) & 0x00FF0000) >>  8) | \
++                (((val) & 0xFF000000) >> 24)))
++
++/**************************************************************************//**
++ @Description   Swaps the byte order of a given 64-bit value.
++
++ @Param[in]     val - The 64-bit value to swap.
++
++ @Return        The byte-swapped value..
++
++ @Cautions      The given value is evaluated multiple times by this macro.
++                For calculated expressions or expressions that contain function
++                calls it is recommended to use the SwapUint64() routine.
++
++ @hideinitializer
++*//***************************************************************************/
++#define SWAP_UINT64(val) \
++    ((uint64_t)((((val) & 0x00000000000000FFULL) << 56) | \
++                (((val) & 0x000000000000FF00ULL) << 40) | \
++                (((val) & 0x0000000000FF0000ULL) << 24) | \
++                (((val) & 0x00000000FF000000ULL) <<  8) | \
++                (((val) & 0x000000FF00000000ULL) >>  8) | \
++                (((val) & 0x0000FF0000000000ULL) >> 24) | \
++                (((val) & 0x00FF000000000000ULL) >> 40) | \
++                (((val) & 0xFF00000000000000ULL) >> 56)))
++
++/* @} */
++
++/**************************************************************************//**
++ @Collection    Byte-Swap Routines
++
++                Routines for swapping the byte order of a given parameter and
++                returning the swapped value.
++
++                These inline routines are safer than the byte-swap macros,
++                because they evaluate the parameter expression only once.
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      SwapUint16
++
++ @Description   Returns the byte-swapped value of a given 16-bit value.
++
++ @Param[in]     val - The 16-bit value.
++
++ @Return        The byte-swapped value of the parameter.
++*//***************************************************************************/
++static __inline__ uint16_t SwapUint16(uint16_t val)
++{
++    return (uint16_t)(((val & 0x00FF) << 8) |
++                      ((val & 0xFF00) >> 8));
++}
++
++/**************************************************************************//**
++ @Function      SwapUint32
++
++ @Description   Returns the byte-swapped value of a given 32-bit value.
++
++ @Param[in]     val - The 32-bit value.
++
++ @Return        The byte-swapped value of the parameter.
++*//***************************************************************************/
++static __inline__ uint32_t SwapUint32(uint32_t val)
++{
++    return (uint32_t)(((val & 0x000000FF) << 24) |
++                      ((val & 0x0000FF00) <<  8) |
++                      ((val & 0x00FF0000) >>  8) |
++                      ((val & 0xFF000000) >> 24));
++}
++
++/**************************************************************************//**
++ @Function      SwapUint64
++
++ @Description   Returns the byte-swapped value of a given 64-bit value.
++
++ @Param[in]     val - The 64-bit value.
++
++ @Return        The byte-swapped value of the parameter.
++*//***************************************************************************/
++static __inline__ uint64_t SwapUint64(uint64_t val)
++{
++    return (uint64_t)(((val & 0x00000000000000FFULL) << 56) |
++                      ((val & 0x000000000000FF00ULL) << 40) |
++                      ((val & 0x0000000000FF0000ULL) << 24) |
++                      ((val & 0x00000000FF000000ULL) <<  8) |
++                      ((val & 0x000000FF00000000ULL) >>  8) |
++                      ((val & 0x0000FF0000000000ULL) >> 24) |
++                      ((val & 0x00FF000000000000ULL) >> 40) |
++                      ((val & 0xFF00000000000000ULL) >> 56));
++}
++
++/* @} */
++
++/**************************************************************************//**
++ @Collection    In-place Byte-Swap-And-Set Routines
++
++                Routines for swapping the byte order of a given variable and
++                setting the swapped value back to the same variable.
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      SwapUint16P
++
++ @Description   Swaps the byte order of a given 16-bit variable.
++
++ @Param[in]     p_Val - Pointer to the 16-bit variable.
++
++ @Return        None.
++*//***************************************************************************/
++static __inline__ void SwapUint16P(uint16_t *p_Val)
++{
++    *p_Val = SwapUint16(*p_Val);
++}
++
++/**************************************************************************//**
++ @Function      SwapUint32P
++
++ @Description   Swaps the byte order of a given 32-bit variable.
++
++ @Param[in]     p_Val - Pointer to the 32-bit variable.
++
++ @Return        None.
++*//***************************************************************************/
++static __inline__ void SwapUint32P(uint32_t *p_Val)
++{
++    *p_Val = SwapUint32(*p_Val);
++}
++
++/**************************************************************************//**
++ @Function      SwapUint64P
++
++ @Description   Swaps the byte order of a given 64-bit variable.
++
++ @Param[in]     p_Val - Pointer to the 64-bit variable.
++
++ @Return        None.
++*//***************************************************************************/
++static __inline__ void SwapUint64P(uint64_t *p_Val)
++{
++    *p_Val = SwapUint64(*p_Val);
++}
++
++/* @} */
++
++
++/**************************************************************************//**
++ @Collection    Little-Endian Conversion Macros
++
++                These macros convert given parameters to or from Little-Endian
++                format. Use these macros when you want to read or write a specific
++                Little-Endian value in memory, without a-priori knowing the CPU
++                byte order.
++
++                These macros use the byte-swap routines. For conversion of
++                constants in initialization structures, you may use the CONST
++                versions of these macros (see below), which are using the
++                byte-swap macros instead.
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   Converts a given 16-bit value from CPU byte order to
++                Little-Endian byte order.
++
++ @Param[in]     val - The 16-bit value to convert.
++
++ @Return        The converted value.
++
++ @hideinitializer
++*//***************************************************************************/
++#define CPU_TO_LE16(val)        SwapUint16(val)
++
++/**************************************************************************//**
++ @Description   Converts a given 32-bit value from CPU byte order to
++                Little-Endian byte order.
++
++ @Param[in]     val - The 32-bit value to convert.
++
++ @Return        The converted value.
++
++ @hideinitializer
++*//***************************************************************************/
++#define CPU_TO_LE32(val)        SwapUint32(val)
++
++/**************************************************************************//**
++ @Description   Converts a given 64-bit value from CPU byte order to
++                Little-Endian byte order.
++
++ @Param[in]     val - The 64-bit value to convert.
++
++ @Return        The converted value.
++
++ @hideinitializer
++*//***************************************************************************/
++#define CPU_TO_LE64(val)        SwapUint64(val)
++
++
++/**************************************************************************//**
++ @Description   Converts a given 16-bit value from Little-Endian byte order to
++                CPU byte order.
++
++ @Param[in]     val - The 16-bit value to convert.
++
++ @Return        The converted value.
++
++ @hideinitializer
++*//***************************************************************************/
++#define LE16_TO_CPU(val)        CPU_TO_LE16(val)
++
++/**************************************************************************//**
++ @Description   Converts a given 32-bit value from Little-Endian byte order to
++                CPU byte order.
++
++ @Param[in]     val - The 32-bit value to convert.
++
++ @Return        The converted value.
++
++ @hideinitializer
++*//***************************************************************************/
++#define LE32_TO_CPU(val)        CPU_TO_LE32(val)
++
++/**************************************************************************//**
++ @Description   Converts a given 64-bit value from Little-Endian byte order to
++                CPU byte order.
++
++ @Param[in]     val - The 64-bit value to convert.
++
++ @Return        The converted value.
++
++ @hideinitializer
++*//***************************************************************************/
++#define LE64_TO_CPU(val)        CPU_TO_LE64(val)
++
++/* @} */
++
++/**************************************************************************//**
++ @Collection    Little-Endian Constant Conversion Macros
++
++                These macros convert given constants to or from Little-Endian
++                format. Use these macros when you want to read or write a specific
++                Little-Endian constant in memory, without a-priori knowing the
++                CPU byte order.
++
++                These macros use the byte-swap macros, therefore can be used for
++                conversion of constants in initialization structures.
++
++ @Cautions      The parameters of these macros are evaluated multiple times.
++                For non-constant expressions, use the non-CONST macro versions.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   Converts a given 16-bit constant from CPU byte order to
++                Little-Endian byte order.
++
++ @Param[in]     val - The 16-bit value to convert.
++
++ @Return        The converted value.
++
++ @hideinitializer
++*//***************************************************************************/
++#define CONST_CPU_TO_LE16(val)  SWAP_UINT16(val)
++
++/**************************************************************************//**
++ @Description   Converts a given 32-bit constant from CPU byte order to
++                Little-Endian byte order.
++
++ @Param[in]     val - The 32-bit value to convert.
++
++ @Return        The converted value.
++
++ @hideinitializer
++*//***************************************************************************/
++#define CONST_CPU_TO_LE32(val)  SWAP_UINT32(val)
++
++/**************************************************************************//**
++ @Description   Converts a given 64-bit constant from CPU byte order to
++                Little-Endian byte order.
++
++ @Param[in]     val - The 64-bit value to convert.
++
++ @Return        The converted value.
++
++ @hideinitializer
++*//***************************************************************************/
++#define CONST_CPU_TO_LE64(val)  SWAP_UINT64(val)
++
++
++/**************************************************************************//**
++ @Description   Converts a given 16-bit constant from Little-Endian byte order
++                to CPU byte order.
++
++ @Param[in]     val - The 16-bit value to convert.
++
++ @Return        The converted value.
++
++ @hideinitializer
++*//***************************************************************************/
++#define CONST_LE16_TO_CPU(val)  CONST_CPU_TO_LE16(val)
++
++/**************************************************************************//**
++ @Description   Converts a given 32-bit constant from Little-Endian byte order
++                to CPU byte order.
++
++ @Param[in]     val - The 32-bit value to convert.
++
++ @Return        The converted value.
++
++ @hideinitializer
++*//***************************************************************************/
++#define CONST_LE32_TO_CPU(val)  CONST_CPU_TO_LE32(val)
++
++/**************************************************************************//**
++ @Description   Converts a given 64-bit constant from Little-Endian byte order
++                to CPU byte order.
++
++ @Param[in]     val - The 64-bit value to convert.
++
++ @Return        The converted value.
++
++ @hideinitializer
++*//***************************************************************************/
++#define CONST_LE64_TO_CPU(val)  CONST_CPU_TO_LE64(val)
++
++/* @} */
++
++
++/** @} */ /* end of endian_id group */
++/** @} */ /* end of gen_id group */
++
++
++#endif /* __ENDIAN_EXT_H */
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/enet_ext.h
+@@ -0,0 +1,205 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          enet_ext.h
++
++ @Description   Ethernet generic definitions and enums.
++*//***************************************************************************/
++
++#ifndef __ENET_EXT_H
++#define __ENET_EXT_H
++
++#include "fsl_enet.h"
++
++#define ENET_NUM_OCTETS_PER_ADDRESS 6     /**< Number of octets (8-bit bytes) in an ethernet address */
++#define ENET_GROUP_ADDR             0x01  /**< Group address mask for ethernet addresses */
++
++
++/**************************************************************************//**
++ @Description   Ethernet Address
++*//***************************************************************************/
++typedef uint8_t t_EnetAddr[ENET_NUM_OCTETS_PER_ADDRESS];
++
++/**************************************************************************//**
++ @Description   Ethernet Address Type.
++*//***************************************************************************/
++typedef enum e_EnetAddrType
++{
++    e_ENET_ADDR_TYPE_INDIVIDUAL,    /**< Individual (unicast) address */
++    e_ENET_ADDR_TYPE_GROUP,         /**< Group (multicast) address */
++    e_ENET_ADDR_TYPE_BROADCAST      /**< Broadcast address */
++} e_EnetAddrType;
++
++/**************************************************************************//**
++ @Description   Ethernet MAC-PHY Interface
++*//***************************************************************************/
++typedef enum e_EnetInterface
++{
++    e_ENET_IF_MII   = E_ENET_IF_MII,     /**< MII interface */
++    e_ENET_IF_RMII  = E_ENET_IF_RMII,    /**< RMII interface */
++    e_ENET_IF_SMII  = E_ENET_IF_SMII,    /**< SMII interface */
++    e_ENET_IF_GMII  = E_ENET_IF_GMII,    /**< GMII interface */
++    e_ENET_IF_RGMII = E_ENET_IF_RGMII,   /**< RGMII interface */
++    e_ENET_IF_TBI   = E_ENET_IF_TBI,     /**< TBI interface */
++    e_ENET_IF_RTBI  = E_ENET_IF_RTBI,    /**< RTBI interface */
++    e_ENET_IF_SGMII = E_ENET_IF_SGMII,   /**< SGMII interface */
++    e_ENET_IF_XGMII = E_ENET_IF_XGMII,   /**< XGMII interface */
++    e_ENET_IF_QSGMII= E_ENET_IF_QSGMII,  /**< QSGMII interface */
++    e_ENET_IF_XFI   = E_ENET_IF_XFI      /**< XFI interface */
++} e_EnetInterface;
++
++#define ENET_IF_SGMII_BASEX       0x80000000   /**< SGMII/QSGII interface with 1000BaseX
++                                                    auto-negotiation between MAC and phy
++                                                    or backplane;
++                                                    Note: 1000BaseX auto-negotiation relates
++                                                    only to interface between MAC and phy/backplane,
++                                                    SGMII phy can still synchronize with far-end phy
++                                                    at 10Mbps, 100Mbps or 1000Mbps */
++
++/**************************************************************************//**
++ @Description   Ethernet Duplex Mode
++*//***************************************************************************/
++typedef enum e_EnetDuplexMode
++{
++    e_ENET_HALF_DUPLEX,             /**< Half-Duplex mode */
++    e_ENET_FULL_DUPLEX              /**< Full-Duplex mode */
++} e_EnetDuplexMode;
++
++/**************************************************************************//**
++ @Description   Ethernet Speed (nominal data rate)
++*//***************************************************************************/
++typedef enum e_EnetSpeed
++{
++    e_ENET_SPEED_10     = E_ENET_SPEED_10,       /**< 10 Mbps */
++    e_ENET_SPEED_100    = E_ENET_SPEED_100,      /**< 100 Mbps */
++    e_ENET_SPEED_1000   = E_ENET_SPEED_1000,     /**< 1000 Mbps = 1 Gbps */
++    e_ENET_SPEED_2500   = E_ENET_SPEED_2500,     /**< 2500 Mbps = 2.5 Gbps */
++    e_ENET_SPEED_10000  = E_ENET_SPEED_10000     /**< 10000 Mbps = 10 Gbps */
++} e_EnetSpeed;
++
++/**************************************************************************//**
++ @Description   Ethernet mode (combination of MAC-PHY interface and speed)
++*//***************************************************************************/
++typedef enum e_EnetMode
++{
++    e_ENET_MODE_INVALID           = 0,                                        /**< Invalid Ethernet mode */
++    e_ENET_MODE_MII_10            = (e_ENET_IF_MII   | e_ENET_SPEED_10),      /**<    10 Mbps MII   */
++    e_ENET_MODE_MII_100           = (e_ENET_IF_MII   | e_ENET_SPEED_100),     /**<   100 Mbps MII   */
++    e_ENET_MODE_RMII_10           = (e_ENET_IF_RMII  | e_ENET_SPEED_10),      /**<    10 Mbps RMII  */
++    e_ENET_MODE_RMII_100          = (e_ENET_IF_RMII  | e_ENET_SPEED_100),     /**<   100 Mbps RMII  */
++    e_ENET_MODE_SMII_10           = (e_ENET_IF_SMII  | e_ENET_SPEED_10),      /**<    10 Mbps SMII  */
++    e_ENET_MODE_SMII_100          = (e_ENET_IF_SMII  | e_ENET_SPEED_100),     /**<   100 Mbps SMII  */
++    e_ENET_MODE_GMII_1000         = (e_ENET_IF_GMII  | e_ENET_SPEED_1000),    /**<  1000 Mbps GMII  */
++    e_ENET_MODE_RGMII_10          = (e_ENET_IF_RGMII | e_ENET_SPEED_10),      /**<    10 Mbps RGMII */
++    e_ENET_MODE_RGMII_100         = (e_ENET_IF_RGMII | e_ENET_SPEED_100),     /**<   100 Mbps RGMII */
++    e_ENET_MODE_RGMII_1000        = (e_ENET_IF_RGMII | e_ENET_SPEED_1000),    /**<  1000 Mbps RGMII */
++    e_ENET_MODE_TBI_1000          = (e_ENET_IF_TBI   | e_ENET_SPEED_1000),    /**<  1000 Mbps TBI   */
++    e_ENET_MODE_RTBI_1000         = (e_ENET_IF_RTBI  | e_ENET_SPEED_1000),    /**<  1000 Mbps RTBI  */
++    e_ENET_MODE_SGMII_10          = (e_ENET_IF_SGMII | e_ENET_SPEED_10),
++                                        /**< 10 Mbps SGMII with auto-negotiation between MAC and
++                                             SGMII phy according to Cisco SGMII specification */
++    e_ENET_MODE_SGMII_100         = (e_ENET_IF_SGMII | e_ENET_SPEED_100),
++                                        /**< 100 Mbps SGMII with auto-negotiation between MAC and
++                                             SGMII phy according to Cisco SGMII specification */
++    e_ENET_MODE_SGMII_1000        = (e_ENET_IF_SGMII | e_ENET_SPEED_1000),
++                                        /**< 1000 Mbps SGMII with auto-negotiation between MAC and
++                                             SGMII phy according to Cisco SGMII specification */
++    e_ENET_MODE_SGMII_2500        = (e_ENET_IF_SGMII | e_ENET_SPEED_2500),
++    e_ENET_MODE_SGMII_BASEX_10    = (ENET_IF_SGMII_BASEX | e_ENET_IF_SGMII | e_ENET_SPEED_10),
++                                        /**< 10 Mbps SGMII with 1000BaseX auto-negotiation between
++                                             MAC and SGMII phy or backplane */
++    e_ENET_MODE_SGMII_BASEX_100   = (ENET_IF_SGMII_BASEX | e_ENET_IF_SGMII | e_ENET_SPEED_100),
++                                        /**< 100 Mbps SGMII with 1000BaseX auto-negotiation between
++                                             MAC and SGMII phy or backplane */
++    e_ENET_MODE_SGMII_BASEX_1000  = (ENET_IF_SGMII_BASEX | e_ENET_IF_SGMII | e_ENET_SPEED_1000),
++                                        /**< 1000 Mbps SGMII with 1000BaseX auto-negotiation between
++                                             MAC and SGMII phy or backplane */
++    e_ENET_MODE_QSGMII_1000       = (e_ENET_IF_QSGMII| e_ENET_SPEED_1000),
++                                        /**< 1000 Mbps QSGMII with auto-negotiation between MAC and
++                                             QSGMII phy according to Cisco QSGMII specification */
++    e_ENET_MODE_QSGMII_BASEX_1000 = (ENET_IF_SGMII_BASEX | e_ENET_IF_QSGMII| e_ENET_SPEED_1000),
++                                        /**< 1000 Mbps QSGMII with 1000BaseX auto-negotiation between
++                                             MAC and QSGMII phy or backplane */
++    e_ENET_MODE_XGMII_10000       = (e_ENET_IF_XGMII | e_ENET_SPEED_10000),   /**< 10000 Mbps XGMII */
++    e_ENET_MODE_XFI_10000         = (e_ENET_IF_XFI   | e_ENET_SPEED_10000)    /**< 10000 Mbps XFI */
++} e_EnetMode;
++
++
++#define IS_ENET_MODE_VALID(mode) \
++        (((mode) == e_ENET_MODE_MII_10     ) || \
++         ((mode) == e_ENET_MODE_MII_100    ) || \
++         ((mode) == e_ENET_MODE_RMII_10    ) || \
++         ((mode) == e_ENET_MODE_RMII_100   ) || \
++         ((mode) == e_ENET_MODE_SMII_10    ) || \
++         ((mode) == e_ENET_MODE_SMII_100   ) || \
++         ((mode) == e_ENET_MODE_GMII_1000  ) || \
++         ((mode) == e_ENET_MODE_RGMII_10   ) || \
++         ((mode) == e_ENET_MODE_RGMII_100  ) || \
++         ((mode) == e_ENET_MODE_RGMII_1000 ) || \
++         ((mode) == e_ENET_MODE_TBI_1000   ) || \
++         ((mode) == e_ENET_MODE_RTBI_1000  ) || \
++         ((mode) == e_ENET_MODE_SGMII_10   ) || \
++         ((mode) == e_ENET_MODE_SGMII_100  ) || \
++         ((mode) == e_ENET_MODE_SGMII_1000 ) || \
++         ((mode) == e_ENET_MODE_SGMII_BASEX_10   ) || \
++         ((mode) == e_ENET_MODE_SGMII_BASEX_100  ) || \
++         ((mode) == e_ENET_MODE_SGMII_BASEX_1000 ) || \
++         ((mode) == e_ENET_MODE_XGMII_10000) || \
++         ((mode) == e_ENET_MODE_QSGMII_1000) || \
++         ((mode) == e_ENET_MODE_QSGMII_BASEX_1000) || \
++         ((mode) == e_ENET_MODE_XFI_10000))
++
++
++#define MAKE_ENET_MODE(_interface, _speed)     (e_EnetMode)((_interface) | (_speed))
++
++#define ENET_INTERFACE_FROM_MODE(mode)          (e_EnetInterface)((mode) & 0x0FFF0000)
++#define ENET_SPEED_FROM_MODE(mode)              (e_EnetSpeed)((mode) & 0x0000FFFF)
++
++#define ENET_ADDR_TO_UINT64(_enetAddr)                  \
++        (uint64_t)(((uint64_t)(_enetAddr)[0] << 40) |   \
++                   ((uint64_t)(_enetAddr)[1] << 32) |   \
++                   ((uint64_t)(_enetAddr)[2] << 24) |   \
++                   ((uint64_t)(_enetAddr)[3] << 16) |   \
++                   ((uint64_t)(_enetAddr)[4] << 8) |    \
++                   ((uint64_t)(_enetAddr)[5]))
++
++#define MAKE_ENET_ADDR_FROM_UINT64(_addr64, _enetAddr)              \
++        do {                                                        \
++            int i;                                                  \
++            for (i=0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++)         \
++                (_enetAddr)[i] = (uint8_t)((_addr64) >> ((5-i)*8)); \
++        } while (0)
++
++
++#endif /* __ENET_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/error_ext.h
+@@ -0,0 +1,529 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          error_ext.h
++
++ @Description   Error definitions.
++*//***************************************************************************/
++
++#ifndef __ERROR_EXT_H
++#define __ERROR_EXT_H
++
++#if !defined(NCSW_LINUX)
++#include <errno.h>
++#endif
++
++#include "std_ext.h"
++#include "xx_ext.h"
++#include "core_ext.h"
++
++
++
++
++/**************************************************************************//**
++ @Group         gen_id  General Drivers Utilities
++
++ @Description   External routines.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         gen_error_id  Errors, Events and Debug
++
++ @Description   External routines.
++
++ @{
++*//***************************************************************************/
++
++/******************************************************************************
++The scheme below provides the bits description for error codes:
++
++ 0    1    2    3    4    5    6    7    8    9    10   11   12   13   14   15
++|       Reserved (should be zero)      |              Module ID               |
++
++ 16   17   18   19   20   21   22   23   24   25   26   27   28   29   30   31
++|                               Error Type                                    |
++******************************************************************************/
++
++#define ERROR_CODE(_err)            ((((uint32_t)_err) & 0x0000FFFF) | __ERR_MODULE__)
++
++#define GET_ERROR_TYPE(_errcode)    ((_errcode) & 0x0000FFFF)
++                                /**< Extract module code from error code (#t_Error) */
++
++#define GET_ERROR_MODULE(_errcode)  ((_errcode) & 0x00FF0000)
++                                /**< Extract error type (#e_ErrorType) from
++                                     error code (#t_Error) */
++
++
++/**************************************************************************//**
++ @Description    Error Type Enumeration
++*//***************************************************************************/
++typedef enum e_ErrorType    /*   Comments / Associated Message Strings                      */
++{                           /* ------------------------------------------------------------ */
++    E_OK = 0                /*   Never use "RETURN_ERROR" with E_OK; Use "return E_OK;"     */
++    ,E_WRITE_FAILED = EIO   /**< Write access failed on memory/device.                      */
++                            /*   String: none, or device name.                              */
++    ,E_NO_DEVICE = ENXIO    /**< The associated device is not initialized.                  */
++                            /*   String: none.                                              */
++    ,E_NOT_AVAILABLE = EAGAIN
++                            /**< Resource is unavailable.                                   */
++                            /*   String: none, unless the operation is not the main goal
++                                 of the function (in this case add resource description).   */
++    ,E_NO_MEMORY = ENOMEM   /**< External memory allocation failed.                         */
++                            /*   String: description of item for which allocation failed.   */
++    ,E_INVALID_ADDRESS = EFAULT
++                            /**< Invalid address.                                           */
++                            /*   String: description of the specific violation.             */
++    ,E_BUSY = EBUSY         /**< Resource or module is busy.                                */
++                            /*   String: none, unless the operation is not the main goal
++                                 of the function (in this case add resource description).   */
++    ,E_ALREADY_EXISTS = EEXIST
++                            /**< Requested resource or item already exists.                 */
++                            /*   Use when resource duplication or sharing are not allowed.
++                                 String: none, unless the operation is not the main goal
++                                 of the function (in this case add item description).       */
++    ,E_INVALID_OPERATION = ENODEV
++                            /**< The operation/command is invalid (unrecognized).           */
++                            /*   String: none.                                              */
++    ,E_INVALID_VALUE = EDOM /**< Invalid value.                                             */
++                            /*   Use for non-enumeration parameters, and
++                                 only when other error types are not suitable.
++                                 String: parameter description + "(should be <attribute>)",
++                                 e.g: "Maximum Rx buffer length (should be divisible by 8)",
++                                      "Channel number (should be even)".                    */
++    ,E_NOT_IN_RANGE = ERANGE/**< Parameter value is out of range.                           */
++                            /*   Don't use this error for enumeration parameters.
++                                 String: parameter description + "(should be %d-%d)",
++                                 e.g: "Number of pad characters (should be 0-15)".          */
++    ,E_NOT_SUPPORTED = ENOSYS
++                            /**< The function is not supported or not implemented.          */
++                            /*   String: none.                                              */
++    ,E_INVALID_STATE        /**< The operation is not allowed in current module state.      */
++                            /*   String: none.                                              */
++    ,E_INVALID_HANDLE       /**< Invalid handle of module or object.                        */
++                            /*   String: none, unless the function takes in more than one
++                                 handle (in this case add the handle description)           */
++    ,E_INVALID_ID           /**< Invalid module ID (usually enumeration or index).          */
++                            /*   String: none, unless the function takes in more than one
++                                 ID (in this case add the ID description)                   */
++    ,E_NULL_POINTER         /**< Unexpected NULL pointer.                                   */
++                            /*   String: pointer description.                               */
++    ,E_INVALID_SELECTION    /**< Invalid selection or mode.                                 */
++                            /*   Use for enumeration values, only when other error types
++                                 are not suitable.
++                                 String: parameter description.                             */
++    ,E_INVALID_COMM_MODE    /**< Invalid communication mode.                                */
++                            /*   String: none, unless the function takes in more than one
++                                 communication mode indications (in this case add
++                                 parameter description).                                    */
++    ,E_INVALID_MEMORY_TYPE  /**< Invalid memory type.                                       */
++                            /*   String: none, unless the function takes in more than one
++                                 memory types (in this case add memory description,
++                                 e.g: "Data memory", "Buffer descriptors memory").          */
++    ,E_INVALID_CLOCK        /**< Invalid clock.                                             */
++                            /*   String: none, unless the function takes in more than one
++                                 clocks (in this case add clock description,
++                                 e.g: "Rx clock", "Tx clock").                              */
++    ,E_CONFLICT             /**< Some setting conflicts with another setting.               */
++                            /*   String: description of the conflicting settings.           */
++    ,E_NOT_ALIGNED          /**< Non-aligned address.                                       */
++                            /*   String: parameter description + "(should be %d-bytes aligned)",
++                                 e.g: "Rx data buffer (should be 32-bytes aligned)".        */
++    ,E_NOT_FOUND            /**< Requested resource or item was not found.                  */
++                            /*   Use only when the resource/item is uniquely identified.
++                                 String: none, unless the operation is not the main goal
++                                 of the function (in this case add item description).       */
++    ,E_FULL                 /**< Resource is full.                                          */
++                            /*   String: none, unless the operation is not the main goal
++                                 of the function (in this case add resource description).   */
++    ,E_EMPTY                /**< Resource is empty.                                         */
++                            /*   String: none, unless the operation is not the main goal
++                                 of the function (in this case add resource description).   */
++    ,E_ALREADY_FREE         /**< Specified resource or item is already free or deleted.     */
++                            /*   String: none, unless the operation is not the main goal
++                                 of the function (in this case add item description).       */
++    ,E_READ_FAILED          /**< Read access failed on memory/device.                       */
++                            /*   String: none, or device name.                              */
++    ,E_INVALID_FRAME        /**< Invalid frame object (NULL handle or missing buffers).     */
++                            /*   String: none.                                              */
++    ,E_SEND_FAILED          /**< Send operation failed on device.                           */
++                            /*   String: none, or device name.                              */
++    ,E_RECEIVE_FAILED       /**< Receive operation failed on device.                        */
++                            /*   String: none, or device name.                              */
++    ,E_TIMEOUT/* = ETIMEDOUT*/  /**< The operation timed out.                                   */
++                            /*   String: none.                                              */
++
++    ,E_DUMMY_LAST           /* NEVER USED */
++
++} e_ErrorType;
++
++/**************************************************************************//**
++ @Description    Event Type Enumeration
++*//***************************************************************************/
++typedef enum e_Event        /*   Comments / Associated Flags and Message Strings            */
++{                           /* ------------------------------------------------------------ */
++    EV_NO_EVENT = 0         /**< No event; Never used.                                      */
++
++    ,EV_RX_DISCARD          /**< Received packet discarded (by the driver, and only for
++                                 complete packets);
++                                 Flags: error flags in case of error, zero otherwise.       */
++                            /*   String: reason for discard, e.g: "Error in frame",
++                                 "Disordered frame", "Incomplete frame", "No frame object". */
++    ,EV_RX_ERROR            /**< Receive error (by hardware/firmware);
++                                 Flags: usually status flags from the buffer descriptor.    */
++                            /*   String: none.                                              */
++    ,EV_TX_ERROR            /**< Transmit error (by hardware/firmware);
++                                 Flags: usually status flags from the buffer descriptor.    */
++                            /*   String: none.                                              */
++    ,EV_NO_BUFFERS          /**< System ran out of buffer objects;
++                                 Flags: zero.                                               */
++                            /*   String: none.                                              */
++    ,EV_NO_MB_FRAMES        /**< System ran out of multi-buffer frame objects;
++                                 Flags: zero.                                               */
++                            /*   String: none.                                              */
++    ,EV_NO_SB_FRAMES        /**< System ran out of single-buffer frame objects;
++                                 Flags: zero.                                               */
++                            /*   String: none.                                              */
++    ,EV_TX_QUEUE_FULL       /**< Transmit queue is full;
++                                 Flags: zero.                                               */
++                            /*   String: none.                                              */
++    ,EV_RX_QUEUE_FULL       /**< Receive queue is full;
++                                 Flags: zero.                                               */
++                            /*   String: none.                                              */
++    ,EV_INTR_QUEUE_FULL     /**< Interrupt queue overflow;
++                                 Flags: zero.                                               */
++                            /*   String: none.                                              */
++    ,EV_NO_DATA_BUFFER      /**< Data buffer allocation (from higher layer) failed;
++                                 Flags: zero.                                               */
++                            /*   String: none.                                              */
++    ,EV_OBJ_POOL_EMPTY      /**< Objects pool is empty;
++                                 Flags: zero.                                               */
++                            /*   String: object description (name).                         */
++    ,EV_BUS_ERROR           /**< Illegal access on bus;
++                                 Flags: the address (if available) or bus identifier        */
++                            /*   String: bus/address/module description.                    */
++    ,EV_PTP_TXTS_QUEUE_FULL /**< PTP Tx timestamps queue is full;
++                                 Flags: zero.                                               */
++                            /*   String: none.                                              */
++    ,EV_PTP_RXTS_QUEUE_FULL /**< PTP Rx timestamps queue is full;
++                                 Flags: zero.                                               */
++                            /*   String: none.                                              */
++    ,EV_DUMMY_LAST
++
++} e_Event;
++
++
++/**************************************************************************//**
++ @Collection    Debug Levels for Errors and Events
++
++                The level description refers to errors only.
++                For events, classification is done by the user.
++
++                The TRACE, INFO and WARNING levels are allowed only when using
++                the DBG macro, and are not allowed when using the error macros
++                (RETURN_ERROR or REPORT_ERROR).
++ @{
++*//***************************************************************************/
++#define REPORT_LEVEL_CRITICAL   1       /**< Crasher: Incorrect flow, NULL pointers/handles. */
++#define REPORT_LEVEL_MAJOR      2       /**< Cannot proceed: Invalid operation, parameters or
++                                             configuration. */
++#define REPORT_LEVEL_MINOR      3       /**< Recoverable problem: a repeating call with the same
++                                             parameters may be successful. */
++#define REPORT_LEVEL_WARNING    4       /**< Something is not exactly right, yet it is not an error. */
++#define REPORT_LEVEL_INFO       5       /**< Messages which may be of interest to user/programmer. */
++#define REPORT_LEVEL_TRACE      6       /**< Program flow messages. */
++
++#define EVENT_DISABLED          0xFF    /**< Disabled event (not reported at all) */
++
++/* @} */
++
++
++
++#define NO_MSG      ("")
++
++#ifndef DEBUG_GLOBAL_LEVEL
++#define DEBUG_GLOBAL_LEVEL  REPORT_LEVEL_WARNING
++#endif /* DEBUG_GLOBAL_LEVEL */
++
++#ifndef ERROR_GLOBAL_LEVEL
++#define ERROR_GLOBAL_LEVEL  DEBUG_GLOBAL_LEVEL
++#endif /* ERROR_GLOBAL_LEVEL */
++
++#ifndef EVENT_GLOBAL_LEVEL
++#define EVENT_GLOBAL_LEVEL  REPORT_LEVEL_MINOR
++#endif /* EVENT_GLOBAL_LEVEL */
++
++#ifdef EVENT_LOCAL_LEVEL
++#define EVENT_DYNAMIC_LEVEL EVENT_LOCAL_LEVEL
++#else
++#define EVENT_DYNAMIC_LEVEL EVENT_GLOBAL_LEVEL
++#endif /* EVENT_LOCAL_LEVEL */
++
++
++#ifndef DEBUG_DYNAMIC_LEVEL
++#define DEBUG_USING_STATIC_LEVEL
++
++#ifdef DEBUG_STATIC_LEVEL
++#define DEBUG_DYNAMIC_LEVEL DEBUG_STATIC_LEVEL
++#else
++#define DEBUG_DYNAMIC_LEVEL DEBUG_GLOBAL_LEVEL
++#endif /* DEBUG_STATIC_LEVEL */
++
++#else /* DEBUG_DYNAMIC_LEVEL */
++#ifdef DEBUG_STATIC_LEVEL
++#error "Please use either DEBUG_STATIC_LEVEL or DEBUG_DYNAMIC_LEVEL (not both)"
++#else
++int DEBUG_DYNAMIC_LEVEL = DEBUG_GLOBAL_LEVEL;
++#endif /* DEBUG_STATIC_LEVEL */
++#endif /* !DEBUG_DYNAMIC_LEVEL */
++
++
++#ifndef ERROR_DYNAMIC_LEVEL
++
++#ifdef ERROR_STATIC_LEVEL
++#define ERROR_DYNAMIC_LEVEL ERROR_STATIC_LEVEL
++#else
++#define ERROR_DYNAMIC_LEVEL ERROR_GLOBAL_LEVEL
++#endif /* ERROR_STATIC_LEVEL */
++
++#else /* ERROR_DYNAMIC_LEVEL */
++#ifdef ERROR_STATIC_LEVEL
++#error "Please use either ERROR_STATIC_LEVEL or ERROR_DYNAMIC_LEVEL (not both)"
++#else
++int ERROR_DYNAMIC_LEVEL = ERROR_GLOBAL_LEVEL;
++#endif /* ERROR_STATIC_LEVEL */
++#endif /* !ERROR_DYNAMIC_LEVEL */
++
++#define PRINT_FORMAT        "[CPU%02d, %s:%d %s]"
++#define PRINT_FMT_PARAMS    raw_smp_processor_id(), __FILE__, __LINE__, __FUNCTION__
++
++#if (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0))
++/* No debug/error/event messages at all */
++#define DBG(_level, _vmsg)
++
++#define REPORT_ERROR(_level, _err, _vmsg)
++
++#define RETURN_ERROR(_level, _err, _vmsg) \
++        return ERROR_CODE(_err)
++
++#if (REPORT_EVENTS > 0)
++
++#define REPORT_EVENT(_ev, _appId, _flg, _vmsg) \
++    do { \
++        if (_ev##_LEVEL <= EVENT_DYNAMIC_LEVEL) { \
++            XX_EventById((uint32_t)(_ev), (t_Handle)(_appId), (uint16_t)(_flg), NO_MSG); \
++        } \
++    } while (0)
++
++#else
++
++#define REPORT_EVENT(_ev, _appId, _flg, _vmsg)
++
++#endif /* (REPORT_EVENTS > 0) */
++
++
++#else /* DEBUG_ERRORS > 0 */
++
++extern const char *dbgLevelStrings[];
++extern const char *moduleStrings[];
++#if (REPORT_EVENTS > 0)
++extern const char *eventStrings[];
++#endif /* (REPORT_EVENTS > 0) */
++
++char * ErrTypeStrings (e_ErrorType err);
++
++
++#if ((defined(DEBUG_USING_STATIC_LEVEL)) && (DEBUG_DYNAMIC_LEVEL < REPORT_LEVEL_WARNING))
++/* No need for DBG macro - debug level is higher anyway */
++#define DBG(_level, _vmsg)
++#else
++#define DBG(_level, _vmsg) \
++    do { \
++        if (REPORT_LEVEL_##_level <= DEBUG_DYNAMIC_LEVEL) { \
++            XX_Print("> %s (%s) " PRINT_FORMAT ": ", \
++                     dbgLevelStrings[REPORT_LEVEL_##_level - 1], \
++                     moduleStrings[__ERR_MODULE__ >> 16], \
++                     PRINT_FMT_PARAMS); \
++            XX_Print _vmsg; \
++            XX_Print("\r\n"); \
++        } \
++    } while (0)
++#endif /* (defined(DEBUG_USING_STATIC_LEVEL) && (DEBUG_DYNAMIC_LEVEL < WARNING)) */
++
++
++#define REPORT_ERROR(_level, _err, _vmsg) \
++    do { \
++        if (REPORT_LEVEL_##_level <= ERROR_DYNAMIC_LEVEL) { \
++            XX_Print("! %s %s Error " PRINT_FORMAT ": %s; ", \
++                     dbgLevelStrings[REPORT_LEVEL_##_level - 1], \
++                     moduleStrings[__ERR_MODULE__ >> 16], \
++                     PRINT_FMT_PARAMS, \
++                     ErrTypeStrings((e_ErrorType)GET_ERROR_TYPE(_err))); \
++            XX_Print _vmsg; \
++            XX_Print("\r\n"); \
++        } \
++    } while (0)
++
++
++#define RETURN_ERROR(_level, _err, _vmsg) \
++    do { \
++        REPORT_ERROR(_level, (_err), _vmsg); \
++        return ERROR_CODE(_err); \
++    } while (0)
++
++
++#if (REPORT_EVENTS > 0)
++
++#define REPORT_EVENT(_ev, _appId, _flg, _vmsg) \
++    do { \
++        if (_ev##_LEVEL <= EVENT_DYNAMIC_LEVEL) { \
++            XX_Print("~ %s %s Event " PRINT_FORMAT ": %s (flags: 0x%04x); ", \
++                     dbgLevelStrings[_ev##_LEVEL - 1], \
++                     moduleStrings[__ERR_MODULE__ >> 16], \
++                     PRINT_FMT_PARAMS, \
++                     eventStrings[((_ev) - EV_NO_EVENT - 1)], \
++                     (uint16_t)(_flg)); \
++            XX_Print _vmsg; \
++            XX_Print("\r\n"); \
++            XX_EventById((uint32_t)(_ev), (t_Handle)(_appId), (uint16_t)(_flg), NO_MSG); \
++        } \
++    } while (0)
++
++#else /* not REPORT_EVENTS */
++
++#define REPORT_EVENT(_ev, _appId, _flg, _vmsg)
++
++#endif /* (REPORT_EVENTS > 0) */
++
++#endif /* (DEBUG_ERRORS > 0) */
++
++
++/**************************************************************************//**
++ @Function      ASSERT_COND
++
++ @Description   Assertion macro.
++
++ @Param[in]     _cond - The condition being checked, in positive form;
++                        Failure of the condition triggers the assert.
++*//***************************************************************************/
++#ifdef DISABLE_ASSERTIONS
++#define ASSERT_COND(_cond)
++#else
++#define ASSERT_COND(_cond) \
++    do { \
++        if (!(_cond)) { \
++            XX_Print("*** ASSERT_COND failed " PRINT_FORMAT "\r\n", \
++                    PRINT_FMT_PARAMS); \
++            XX_Exit(1); \
++        } \
++    } while (0)
++#endif /* DISABLE_ASSERTIONS */
++
++
++#ifdef DISABLE_INIT_PARAMETERS_CHECK
++
++#define CHECK_INIT_PARAMETERS(handle, f_check)
++#define CHECK_INIT_PARAMETERS_RETURN_VALUE(handle, f_check, retval)
++
++#else
++
++#define CHECK_INIT_PARAMETERS(handle, f_check) \
++    do { \
++        t_Error err = f_check(handle); \
++        if (err != E_OK) { \
++            RETURN_ERROR(MAJOR, err, NO_MSG); \
++        } \
++    } while (0)
++
++#define CHECK_INIT_PARAMETERS_RETURN_VALUE(handle, f_check, retval) \
++    do { \
++        t_Error err = f_check(handle); \
++        if (err != E_OK) { \
++            REPORT_ERROR(MAJOR, err, NO_MSG); \
++            return (retval); \
++        } \
++    } while (0)
++
++#endif /* DISABLE_INIT_PARAMETERS_CHECK */
++
++#ifdef DISABLE_SANITY_CHECKS
++
++#define SANITY_CHECK_RETURN_ERROR(_cond, _err)
++#define SANITY_CHECK_RETURN_VALUE(_cond, _err, retval)
++#define SANITY_CHECK_RETURN(_cond, _err)
++#define SANITY_CHECK_EXIT(_cond, _err)
++
++#else /* DISABLE_SANITY_CHECKS */
++
++#define SANITY_CHECK_RETURN_ERROR(_cond, _err) \
++    do { \
++        if (!(_cond)) { \
++            RETURN_ERROR(CRITICAL, (_err), NO_MSG); \
++        } \
++    } while (0)
++
++#define SANITY_CHECK_RETURN_VALUE(_cond, _err, retval) \
++    do { \
++        if (!(_cond)) { \
++            REPORT_ERROR(CRITICAL, (_err), NO_MSG); \
++            return (retval); \
++        } \
++    } while (0)
++
++#define SANITY_CHECK_RETURN(_cond, _err) \
++    do { \
++        if (!(_cond)) { \
++            REPORT_ERROR(CRITICAL, (_err), NO_MSG); \
++            return; \
++        } \
++    } while (0)
++
++#define SANITY_CHECK_EXIT(_cond, _err) \
++    do { \
++        if (!(_cond)) { \
++            REPORT_ERROR(CRITICAL, (_err), NO_MSG); \
++            XX_Exit(1); \
++        } \
++    } while (0)
++
++#endif /* DISABLE_SANITY_CHECKS */
++
++/** @} */ /* end of Debug/error Utils group */
++
++/** @} */ /* end of General Utils group */
++
++#endif /* __ERROR_EXT_H */
++
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/list_ext.h
+@@ -0,0 +1,358 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++
++ @File          list_ext.h
++
++ @Description   External prototypes for list.c
++*//***************************************************************************/
++
++#ifndef __LIST_EXT_H
++#define __LIST_EXT_H
++
++
++#include "std_ext.h"
++
++
++/**************************************************************************//**
++ @Group         etc_id   Utility Library Application Programming Interface
++
++ @Description   External routines.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         list_id List
++
++ @Description   List module functions,definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   List structure.
++*//***************************************************************************/
++typedef struct List
++{
++    struct List *p_Next;  /**< A pointer to the next list object     */
++    struct List *p_Prev;  /**< A pointer to the previous list object */
++} t_List;
++
++
++/**************************************************************************//**
++ @Function      LIST_FIRST/LIST_LAST/LIST_NEXT/LIST_PREV
++
++ @Description   Macro to get first/last/next/previous entry in a list.
++
++ @Param[in]     p_List - A pointer to a list.
++*//***************************************************************************/
++#define LIST_FIRST(p_List) (p_List)->p_Next
++#define LIST_LAST(p_List)  (p_List)->p_Prev
++#define LIST_NEXT          LIST_FIRST
++#define LIST_PREV          LIST_LAST
++
++
++/**************************************************************************//**
++ @Function      LIST_INIT
++
++ @Description   Macro for initialization of a list struct.
++
++ @Param[in]     lst - The t_List object to initialize.
++*//***************************************************************************/
++#define LIST_INIT(lst) {&(lst), &(lst)}
++
++
++/**************************************************************************//**
++ @Function      LIST
++
++ @Description   Macro to declare of a list.
++
++ @Param[in]     listName - The list object name.
++*//***************************************************************************/
++#define LIST(listName) t_List listName = LIST_INIT(listName)
++
++
++/**************************************************************************//**
++ @Function      INIT_LIST
++
++ @Description   Macro to initialize a list pointer.
++
++ @Param[in]     p_List - The list pointer.
++*//***************************************************************************/
++#define INIT_LIST(p_List)   LIST_FIRST(p_List) = LIST_LAST(p_List) = (p_List)
++
++
++/**************************************************************************//**
++ @Function      LIST_OBJECT
++
++ @Description   Macro to get the struct (object) for this entry.
++
++ @Param[in]     type   - The type of the struct (object) this list is embedded in.
++ @Param[in]     member - The name of the t_List object within the struct.
++
++ @Return        The structure pointer for this entry.
++*//***************************************************************************/
++#define MEMBER_OFFSET(type, member) (PTR_TO_UINT(&((type *)0)->member))
++#define LIST_OBJECT(p_List, type, member) \
++    ((type *)((char *)(p_List)-MEMBER_OFFSET(type, member)))
++
++
++/**************************************************************************//**
++ @Function      LIST_FOR_EACH
++
++ @Description   Macro to iterate over a list.
++
++ @Param[in]     p_Pos  - A pointer to a list to use as a loop counter.
++ @Param[in]     p_Head - A pointer to the head for your list pointer.
++
++ @Cautions      You can't delete items with this routine.
++                For deletion use LIST_FOR_EACH_SAFE().
++*//***************************************************************************/
++#define LIST_FOR_EACH(p_Pos, p_Head) \
++    for (p_Pos = LIST_FIRST(p_Head); p_Pos != (p_Head); p_Pos = LIST_NEXT(p_Pos))
++
++
++/**************************************************************************//**
++ @Function      LIST_FOR_EACH_SAFE
++
++ @Description   Macro to iterate over a list safe against removal of list entry.
++
++ @Param[in]     p_Pos  - A pointer to a list to use as a loop counter.
++ @Param[in]     p_Tmp  - Another pointer to a list to use as temporary storage.
++ @Param[in]     p_Head - A pointer to the head for your list pointer.
++*//***************************************************************************/
++#define LIST_FOR_EACH_SAFE(p_Pos, p_Tmp, p_Head)                \
++    for (p_Pos = LIST_FIRST(p_Head), p_Tmp = LIST_FIRST(p_Pos); \
++         p_Pos != (p_Head);                                     \
++         p_Pos = p_Tmp, p_Tmp = LIST_NEXT(p_Pos))
++
++
++/**************************************************************************//**
++ @Function      LIST_FOR_EACH_OBJECT_SAFE
++
++ @Description   Macro to iterate over list of given type safely.
++
++ @Param[in]     p_Pos  - A pointer to a list to use as a loop counter.
++ @Param[in]     p_Tmp  - Another pointer to a list to use as temporary storage.
++ @Param[in]     type   - The type of the struct this is embedded in.
++ @Param[in]     p_Head - A pointer to the head for your list pointer.
++ @Param[in]     member - The name of the list_struct within the struct.
++
++ @Cautions      You can't delete items with this routine.
++                For deletion use LIST_FOR_EACH_SAFE().
++*//***************************************************************************/
++#define LIST_FOR_EACH_OBJECT_SAFE(p_Pos, p_Tmp, p_Head, type, member)      \
++    for (p_Pos = LIST_OBJECT(LIST_FIRST(p_Head), type, member),            \
++         p_Tmp = LIST_OBJECT(LIST_FIRST(&p_Pos->member), type, member);    \
++         &p_Pos->member != (p_Head);                                       \
++         p_Pos = p_Tmp,                                                    \
++         p_Tmp = LIST_OBJECT(LIST_FIRST(&p_Pos->member), type, member))
++
++/**************************************************************************//**
++ @Function      LIST_FOR_EACH_OBJECT
++
++ @Description   Macro to iterate over list of given type.
++
++ @Param[in]     p_Pos  - A pointer to a list to use as a loop counter.
++ @Param[in]     type   - The type of the struct this is embedded in.
++ @Param[in]     p_Head - A pointer to the head for your list pointer.
++ @Param[in]     member - The name of the list_struct within the struct.
++
++ @Cautions      You can't delete items with this routine.
++                For deletion use LIST_FOR_EACH_SAFE().
++*//***************************************************************************/
++#define LIST_FOR_EACH_OBJECT(p_Pos, type, p_Head, member)                  \
++    for (p_Pos = LIST_OBJECT(LIST_FIRST(p_Head), type, member);            \
++         &p_Pos->member != (p_Head);                                       \
++         p_Pos = LIST_OBJECT(LIST_FIRST(&(p_Pos->member)), type, member))
++
++
++/**************************************************************************//**
++ @Function      LIST_Add
++
++ @Description   Add a new entry to a list.
++
++                Insert a new entry after the specified head.
++                This is good for implementing stacks.
++
++ @Param[in]     p_New  - A pointer to a new list entry to be added.
++ @Param[in]     p_Head - A pointer to a list head to add it after.
++
++ @Return        none.
++*//***************************************************************************/
++static __inline__ void LIST_Add(t_List *p_New, t_List *p_Head)
++{
++    LIST_PREV(LIST_NEXT(p_Head)) = p_New;
++    LIST_NEXT(p_New)             = LIST_NEXT(p_Head);
++    LIST_PREV(p_New)             = p_Head;
++    LIST_NEXT(p_Head)            = p_New;
++}
++
++
++/**************************************************************************//**
++ @Function      LIST_AddToTail
++
++ @Description   Add a new entry to a list.
++
++                Insert a new entry before the specified head.
++                This is useful for implementing queues.
++
++ @Param[in]     p_New  - A pointer to a new list entry to be added.
++ @Param[in]     p_Head - A pointer to a list head to add it before.
++
++ @Return        none.
++*//***************************************************************************/
++static __inline__ void LIST_AddToTail(t_List *p_New, t_List *p_Head)
++{
++    LIST_NEXT(LIST_PREV(p_Head)) = p_New;
++    LIST_PREV(p_New)             = LIST_PREV(p_Head);
++    LIST_NEXT(p_New)             = p_Head;
++    LIST_PREV(p_Head)            = p_New;
++}
++
++
++/**************************************************************************//**
++ @Function      LIST_Del
++
++ @Description   Deletes entry from a list.
++
++ @Param[in]     p_Entry - A pointer to the element to delete from the list.
++
++ @Return        none.
++
++ @Cautions      LIST_IsEmpty() on entry does not return true after this,
++                the entry is in an undefined state.
++*//***************************************************************************/
++static __inline__ void LIST_Del(t_List *p_Entry)
++{
++    LIST_PREV(LIST_NEXT(p_Entry)) = LIST_PREV(p_Entry);
++    LIST_NEXT(LIST_PREV(p_Entry)) = LIST_NEXT(p_Entry);
++}
++
++
++/**************************************************************************//**
++ @Function      LIST_DelAndInit
++
++ @Description   Deletes entry from list and reinitialize it.
++
++ @Param[in]     p_Entry - A pointer to the element to delete from the list.
++
++ @Return        none.
++*//***************************************************************************/
++static __inline__ void LIST_DelAndInit(t_List *p_Entry)
++{
++    LIST_Del(p_Entry);
++    INIT_LIST(p_Entry);
++}
++
++
++/**************************************************************************//**
++ @Function      LIST_Move
++
++ @Description   Delete from one list and add as another's head.
++
++ @Param[in]     p_Entry - A pointer to the list entry to move.
++ @Param[in]     p_Head  - A pointer to the list head that will precede our entry.
++
++ @Return        none.
++*//***************************************************************************/
++static __inline__ void LIST_Move(t_List *p_Entry, t_List *p_Head)
++{
++    LIST_Del(p_Entry);
++    LIST_Add(p_Entry, p_Head);
++}
++
++
++/**************************************************************************//**
++ @Function      LIST_MoveToTail
++
++ @Description   Delete from one list and add as another's tail.
++
++ @Param[in]     p_Entry - A pointer to the entry to move.
++ @Param[in]     p_Head  - A pointer to the list head that will follow our entry.
++
++ @Return        none.
++*//***************************************************************************/
++static __inline__ void LIST_MoveToTail(t_List *p_Entry, t_List *p_Head)
++{
++    LIST_Del(p_Entry);
++    LIST_AddToTail(p_Entry, p_Head);
++}
++
++
++/**************************************************************************//**
++ @Function      LIST_IsEmpty
++
++ @Description   Tests whether a list is empty.
++
++ @Param[in]     p_List - A pointer to the list to test.
++
++ @Return        1 if the list is empty, 0 otherwise.
++*//***************************************************************************/
++static __inline__ int LIST_IsEmpty(t_List *p_List)
++{
++    return (LIST_FIRST(p_List) == p_List);
++}
++
++
++/**************************************************************************//**
++ @Function      LIST_Append
++
++ @Description   Join two lists.
++
++ @Param[in]     p_NewList - A pointer to the new list to add.
++ @Param[in]     p_Head    - A pointer to the place to add it in the first list.
++
++ @Return        none.
++*//***************************************************************************/
++void LIST_Append(t_List *p_NewList, t_List *p_Head);
++
++
++/**************************************************************************//**
++ @Function      LIST_NumOfObjs
++
++ @Description   Counts number of objects in the list
++
++ @Param[in]     p_List - A pointer to the list which objects are to be counted.
++
++ @Return        Number of objects in the list.
++*//***************************************************************************/
++int LIST_NumOfObjs(t_List *p_List);
++
++/** @} */ /* end of list_id group */
++/** @} */ /* end of etc_id group */
++
++
++#endif /* __LIST_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/mem_ext.h
+@@ -0,0 +1,318 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++
++ @File          mem_ext.h
++
++ @Description   External prototypes for the memory manager object
++*//***************************************************************************/
++
++#ifndef __MEM_EXT_H
++#define __MEM_EXT_H
++
++#include "std_ext.h"
++#include "part_ext.h"
++
++
++/**************************************************************************//**
++ @Group         etc_id   Utility Library Application Programming Interface
++
++ @Description   External routines.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         mem_id   Slab Memory Manager
++
++ @Description   Slab Memory Manager module functions, definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++/* Each block is of the following structure:
++ *
++ *
++ *  +-----------+----------+---------------------------+-----------+-----------+
++ *  | Alignment |  Prefix  | Data                      | Postfix   | Alignment |
++ *  |  field    |   field  |  field                    |   field   | Padding   |
++ *  |           |          |                           |           |           |
++ *  +-----------+----------+---------------------------+-----------+-----------+
++ *  and at the beginning of all bytes, an additional optional padding might reside
++ *  to ensure that the first blocks data field is aligned as requested.
++ */
++
++
++#define MEM_MAX_NAME_LENGTH     8
++
++/**************************************************************************//*
++ @Description   Memory Segment structure
++*//***************************************************************************/
++
++typedef struct
++{
++    char        name[MEM_MAX_NAME_LENGTH];
++                                    /* The segment's name */
++    uint8_t     **p_Bases;          /* Base addresses of the segments */
++    uint8_t     **p_BlocksStack;    /* Array of pointers to blocks */
++    t_Handle    h_Spinlock;
++    uint16_t    dataSize;           /* Size of each data block */
++    uint16_t    prefixSize;         /* How many bytes to reserve before the data */
++    uint16_t    postfixSize;        /* How many bytes to reserve after the data */
++    uint16_t    alignment;          /* Requested alignment for the data field */
++    int         allocOwner;         /* Memory allocation owner */
++    uint32_t    getFailures;        /* Number of times get failed */
++    uint32_t    num;                /* Number of blocks in segment */
++    uint32_t    current;            /* Current block */
++    bool        consecutiveMem;     /* Allocate consecutive data blocks memory */
++#ifdef DEBUG_MEM_LEAKS
++    void        *p_MemDbg;          /* MEM debug database (MEM leaks detection) */
++    uint32_t    blockOffset;
++    uint32_t    blockSize;
++#endif /* DEBUG_MEM_LEAKS */
++} t_MemorySegment;
++
++
++
++/**************************************************************************//**
++ @Function      MEM_Init
++
++ @Description   Create a new memory segment.
++
++ @Param[in]     name        - Name of memory partition.
++ @Param[in]     p_Handle    - Handle to new segment is returned through here.
++ @Param[in]     num         - Number of blocks in new segment.
++ @Param[in]     dataSize    - Size of blocks in segment.
++ @Param[in]     prefixSize  - How many bytes to allocate before the data.
++ @Param[in]     postfixSize - How many bytes to allocate after the data.
++ @Param[in]     alignment   - Requested alignment for data field (in bytes).
++
++ @Return        E_OK - success, E_NO_MEMORY - out of memory.
++*//***************************************************************************/
++t_Error MEM_Init(char     name[],
++                 t_Handle *p_Handle,
++                 uint32_t num,
++                 uint16_t dataSize,
++                 uint16_t prefixSize,
++                 uint16_t postfixSize,
++                 uint16_t alignment);
++
++/**************************************************************************//**
++ @Function      MEM_InitSmart
++
++ @Description   Create a new memory segment.
++
++ @Param[in]     name            - Name of memory partition.
++ @Param[in]     p_Handle        - Handle to new segment is returned through here.
++ @Param[in]     num             - Number of blocks in new segment.
++ @Param[in]     dataSize        - Size of blocks in segment.
++ @Param[in]     prefixSize      - How many bytes to allocate before the data.
++ @Param[in]     postfixSize     - How many bytes to allocate after the data.
++ @Param[in]     alignment       - Requested alignment for data field (in bytes).
++ @Param[in]     memPartitionId  - Memory partition ID for allocation.
++ @Param[in]     consecutiveMem  - Whether to allocate the memory blocks
++                                  continuously or not.
++
++ @Return        E_OK - success, E_NO_MEMORY - out of memory.
++*//***************************************************************************/
++t_Error MEM_InitSmart(char      name[],
++                      t_Handle  *p_Handle,
++                      uint32_t  num,
++                      uint16_t  dataSize,
++                      uint16_t  prefixSize,
++                      uint16_t  postfixSize,
++                      uint16_t  alignment,
++                      uint8_t   memPartitionId,
++                      bool      consecutiveMem);
++
++/**************************************************************************//**
++ @Function      MEM_InitByAddress
++
++ @Description   Create a new memory segment with a specified base address.
++
++ @Param[in]     name        - Name of memory partition.
++ @Param[in]     p_Handle    - Handle to new segment is returned through here.
++ @Param[in]     num         - Number of blocks in new segment.
++ @Param[in]     dataSize    - Size of blocks in segment.
++ @Param[in]     prefixSize  - How many bytes to allocate before the data.
++ @Param[in]     postfixSize - How many bytes to allocate after the data.
++ @Param[in]     alignment   - Requested alignment for data field (in bytes).
++ @Param[in]     address     - The required base address.
++
++ @Return        E_OK - success, E_NO_MEMORY - out of memory.
++ *//***************************************************************************/
++t_Error MEM_InitByAddress(char        name[],
++                          t_Handle    *p_Handle,
++                          uint32_t    num,
++                          uint16_t    dataSize,
++                          uint16_t    prefixSize,
++                          uint16_t    postfixSize,
++                          uint16_t    alignment,
++                          uint8_t     *address);
++
++/**************************************************************************//**
++ @Function      MEM_Free
++
++ @Description   Free a specific memory segment.
++
++ @Param[in]     h_Mem - Handle to memory segment.
++
++ @Return        None.
++*//***************************************************************************/
++void MEM_Free(t_Handle h_Mem);
++
++/**************************************************************************//**
++ @Function      MEM_Get
++
++ @Description   Get a block of memory from a segment.
++
++ @Param[in]     h_Mem - Handle to memory segment.
++
++ @Return        Pointer to new memory block on success,0 otherwise.
++*//***************************************************************************/
++void * MEM_Get(t_Handle h_Mem);
++
++/**************************************************************************//**
++ @Function      MEM_GetN
++
++ @Description   Get up to N blocks of memory from a segment.
++
++                The blocks are assumed to be of a fixed size (one size per segment).
++
++ @Param[in]     h_Mem   - Handle to memory segment.
++ @Param[in]     num     - Number of blocks to allocate.
++ @Param[out]    array   - Array of at least num pointers to which the addresses
++                          of the allocated blocks are written.
++
++ @Return        The number of blocks actually allocated.
++
++ @Cautions      Interrupts are disabled for all of the allocation loop.
++                Although this loop is very short for each block (several machine
++                instructions), you should not allocate a very large number
++                of blocks via this routine.
++*//***************************************************************************/
++uint16_t MEM_GetN(t_Handle h_Mem, uint32_t num, void *array[]);
++
++/**************************************************************************//**
++ @Function      MEM_Put
++
++ @Description   Put a block of memory back to a segment.
++
++ @Param[in]     h_Mem   - Handle to memory segment.
++ @Param[in]     p_Block - The block to return.
++
++ @Return        Pointer to new memory block on success,0 otherwise.
++*//***************************************************************************/
++t_Error MEM_Put(t_Handle h_Mem, void *p_Block);
++
++/**************************************************************************//**
++ @Function      MEM_ComputePartitionSize
++
++ @Description   calculate a tight upper boundary of the size of a partition with
++                given attributes.
++
++                The returned value is suitable if one wants to use MEM_InitByAddress().
++
++ @Param[in]     num         - The number of blocks in the segment.
++ @Param[in]     dataSize    - Size of block to get.
++ @Param[in]     prefixSize  - The prefix size
++ @Param         postfixSize - The postfix size
++ @Param[in]     alignment   - The requested alignment value (in bytes)
++
++ @Return        The memory block size a segment with the given attributes needs.
++*//***************************************************************************/
++uint32_t MEM_ComputePartitionSize(uint32_t num,
++                                  uint16_t dataSize,
++                                  uint16_t prefixSize,
++                                  uint16_t postfixSize,
++                                  uint16_t alignment);
++
++#ifdef DEBUG_MEM_LEAKS
++#if !((defined(__MWERKS__) || defined(__GNUC__)) && (__dest_os == __ppc_eabi))
++#error  "Memory-Leaks-Debug option is supported only for freescale CodeWarrior"
++#endif /* !(defined(__MWERKS__) && ... */
++
++/**************************************************************************//**
++ @Function      MEM_CheckLeaks
++
++ @Description   Report MEM object leaks.
++
++                This routine is automatically called by the MEM_Free() routine,
++                but it can also be invoked while the MEM object is alive.
++
++ @Param[in]     h_Mem - Handle to memory segment.
++
++ @Return        None.
++*//***************************************************************************/
++void MEM_CheckLeaks(t_Handle h_Mem);
++
++#else  /* not DEBUG_MEM_LEAKS */
++#define MEM_CheckLeaks(h_Mem)
++#endif /* not DEBUG_MEM_LEAKS */
++
++/**************************************************************************//**
++ @Description   Get base of MEM
++*//***************************************************************************/
++#define MEM_GetBase(h_Mem)             ((t_MemorySegment *)(h_Mem))->p_Bases[0]
++
++/**************************************************************************//**
++ @Description   Get size of MEM block
++*//***************************************************************************/
++#define MEM_GetSize(h_Mem)             ((t_MemorySegment *)(h_Mem))->dataSize
++
++/**************************************************************************//**
++ @Description   Get prefix size of MEM block
++*//***************************************************************************/
++#define MEM_GetPrefixSize(h_Mem)       ((t_MemorySegment *)(h_Mem))->prefixSize
++
++/**************************************************************************//**
++ @Description   Get postfix size of MEM block
++*//***************************************************************************/
++#define MEM_GetPostfixSize(h_Mem)      ((t_MemorySegment *)(h_Mem))->postfixSize
++
++/**************************************************************************//**
++ @Description   Get alignment of MEM block (in bytes)
++*//***************************************************************************/
++#define MEM_GetAlignment(h_Mem)        ((t_MemorySegment *)(h_Mem))->alignment
++
++/**************************************************************************//**
++ @Description   Get the number of blocks in the segment
++*//***************************************************************************/
++#define MEM_GetNumOfBlocks(h_Mem)             ((t_MemorySegment *)(h_Mem))->num
++
++/** @} */ /* end of MEM group */
++/** @} */ /* end of etc_id group */
++
++
++#endif /* __MEM_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/memcpy_ext.h
+@@ -0,0 +1,208 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++
++ @File          memcpy_ext.h
++
++ @Description   Efficient functions for copying and setting blocks of memory.
++*//***************************************************************************/
++
++#ifndef __MEMCPY_EXT_H
++#define __MEMCPY_EXT_H
++
++#include "std_ext.h"
++
++
++/**************************************************************************//**
++ @Group         etc_id   Utility Library Application Programming Interface
++
++ @Description   External routines.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         mem_cpy Memory Copy
++
++ @Description   Memory Copy module functions,definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      MemCpy32
++
++ @Description   Copies one memory buffer into another one in 4-byte chunks!
++                Which should be more efficient than byte by byte.
++
++                For large buffers (over 60 bytes) this function is about 4 times
++                more efficient than the trivial memory copy. For short buffers
++                it is reduced to the trivial copy and may be a bit worse.
++
++ @Param[in]     pDst    - The address of the destination buffer.
++ @Param[in]     pSrc    - The address of the source buffer.
++ @Param[in]     size    - The number of bytes that will be copied from pSrc to pDst.
++
++ @Return        pDst (the address of the destination buffer).
++
++ @Cautions      There is no parameter or boundary checking! It is up to the user
++                to supply non-null parameters as source & destination and size
++                that actually fits into the destination buffer.
++*//***************************************************************************/
++void * MemCpy32(void* pDst,void* pSrc, uint32_t size);
++void * IO2IOCpy32(void* pDst,void* pSrc, uint32_t size);
++void * IO2MemCpy32(void* pDst,void* pSrc, uint32_t size);
++void * Mem2IOCpy32(void* pDst,void* pSrc, uint32_t size);
++
++/**************************************************************************//**
++ @Function      MemCpy64
++
++ @Description   Copies one memory buffer into another one in 8-byte chunks!
++                Which should be more efficient than byte by byte.
++
++                For large buffers (over 60 bytes) this function is about 8 times
++                more efficient than the trivial memory copy. For short buffers
++                it is reduced to the trivial copy and may be a bit worse.
++
++                Some testing suggests that MemCpy32() preforms better than
++                MemCpy64() over small buffers. On average they break even at
++                100 byte buffers. For buffers larger than that MemCpy64 is
++                superior.
++
++ @Param[in]     pDst    - The address of the destination buffer.
++ @Param[in]     pSrc    - The address of the source buffer.
++ @Param[in]     size    - The number of bytes that will be copied from pSrc to pDst.
++
++ @Return        pDst (the address of the destination buffer).
++
++ @Cautions      There is no parameter or boundary checking! It is up to the user
++                to supply non null parameters as source & destination and size
++                that actually fits into their buffer.
++
++                Do not use under Linux.
++*//***************************************************************************/
++void * MemCpy64(void* pDst,void* pSrc, uint32_t size);
++
++/**************************************************************************//**
++ @Function      MemSet32
++
++ @Description   Sets all bytes of a memory buffer to a specific value, in
++                4-byte chunks.
++
++ @Param[in]     pDst    - The address of the destination buffer.
++ @Param[in]     val     - Value to set destination bytes to.
++ @Param[in]     size    - The number of bytes that will be set to val.
++
++ @Return        pDst (the address of the destination buffer).
++
++ @Cautions      There is no parameter or boundary checking! It is up to the user
++                to supply non null parameter as destination and size
++                that actually fits into the destination buffer.
++*//***************************************************************************/
++void * MemSet32(void* pDst, uint8_t val, uint32_t size);
++void * IOMemSet32(void* pDst, uint8_t val, uint32_t size);
++
++/**************************************************************************//**
++ @Function      MemSet64
++
++ @Description   Sets all bytes of a memory buffer to a specific value, in
++                8-byte chunks.
++
++ @Param[in]     pDst    - The address of the destination buffer.
++ @Param[in]     val     - Value to set destination bytes to.
++ @Param[in]     size    - The number of bytes that will be set to val.
++
++ @Return        pDst (the address of the destination buffer).
++
++ @Cautions      There is no parameter or boundary checking! It is up to the user
++                to supply non null parameter as destination and size
++                that actually fits into the destination buffer.
++*//***************************************************************************/
++void * MemSet64(void* pDst, uint8_t val, uint32_t size);
++
++/**************************************************************************//**
++ @Function      MemDisp
++
++ @Description   Displays a block of memory in chunks of 32 bits.
++
++ @Param[in]     addr    - The address of the memory to display.
++ @Param[in]     size    - The number of bytes that will be displayed.
++
++ @Return        None.
++
++ @Cautions      There is no parameter or boundary checking! It is up to the user
++                to supply non null parameter as destination and size
++                that actually fits into the destination buffer.
++*//***************************************************************************/
++void MemDisp(uint8_t *addr, int size);
++
++/**************************************************************************//**
++ @Function      MemCpy8
++
++ @Description   Trivial copy one memory buffer into another byte by byte
++
++ @Param[in]     pDst    - The address of the destination buffer.
++ @Param[in]     pSrc    - The address of the source buffer.
++ @Param[in]     size    - The number of bytes that will be copied from pSrc to pDst.
++
++ @Return        pDst (the address of the destination buffer).
++
++ @Cautions      There is no parameter or boundary checking! It is up to the user
++                to supply non-null parameters as source & destination and size
++                that actually fits into the destination buffer.
++*//***************************************************************************/
++void * MemCpy8(void* pDst,void* pSrc, uint32_t size);
++
++/**************************************************************************//**
++ @Function      MemSet8
++
++ @Description   Sets all bytes of a memory buffer to a specific value byte by byte.
++
++ @Param[in]     pDst    - The address of the destination buffer.
++ @Param[in]     c       - Value to set destination bytes to.
++ @Param[in]     size    - The number of bytes that will be set to val.
++
++ @Return        pDst (the address of the destination buffer).
++
++ @Cautions      There is no parameter or boundary checking! It is up to the user
++                to supply non null parameter as destination and size
++                that actually fits into the destination buffer.
++*//***************************************************************************/
++void * MemSet8(void* pDst, int c, uint32_t size);
++
++/** @} */ /* end of mem_cpy group */
++/** @} */ /* end of etc_id group */
++
++
++#endif /* __MEMCPY_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/mm_ext.h
+@@ -0,0 +1,310 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          mm_ext.h
++
++ @Description   Memory Manager Application Programming Interface
++*//***************************************************************************/
++#ifndef __MM_EXT
++#define __MM_EXT
++
++#include "std_ext.h"
++
++#define MM_MAX_ALIGNMENT    20  /* Alignments from 2 to 128 are available
++                                   where maximum alignment defined as
++                                   MM_MAX_ALIGNMENT power of 2 */
++
++#define MM_MAX_NAME_LEN     32
++
++/**************************************************************************//**
++ @Group         etc_id   Utility Library Application Programming Interface
++
++ @Description   External routines.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         mm_grp Flexible Memory Manager
++
++ @Description   Flexible Memory Manager module functions,definitions and enums.
++                (All of the following functions,definitions and enums can be found in mm_ext.h)
++
++ @{
++*//***************************************************************************/
++
++
++/**************************************************************************//**
++ @Function      MM_Init
++
++ @Description   Initializes a new MM object.
++
++                It initializes a new memory block consisting of base address
++                and size of the available memory by calling to MemBlock_Init
++                routine. It is also initializes a new free block for each
++                by calling FreeBlock_Init routine, which is pointed to
++                the almost all memory started from the required alignment
++                from the base address and to the end of the memory.
++                The handle to the new MM object is returned via "MM"
++                argument (passed by reference).
++
++ @Param[in]     h_MM    - Handle to the MM object.
++ @Param[in]     base    - Base address of the MM.
++ @Param[in]     size    - Size of the MM.
++
++ @Return        E_OK is returned on success. E_NOMEMORY is returned if the new MM object or a new free block can not be initialized.
++*//***************************************************************************/
++t_Error     MM_Init(t_Handle *h_MM, uint64_t base, uint64_t size);
++
++/**************************************************************************//**
++ @Function      MM_Get
++
++ @Description   Allocates a block of memory according to the given size and the alignment.
++
++                The Alignment argument tells from which
++                free list allocate a block of memory. 2^alignment indicates
++                the alignment that the base address of the allocated block
++                should have. So, the only values 1, 2, 4, 8, 16, 32 and 64
++                are available for the alignment argument.
++                The routine passes through the specific free list of free
++                blocks and seeks for a first block that have anough memory
++                that  is required (best fit).
++                After the block is found and data is allocated, it calls
++                the internal MM_CutFree routine to update all free lists
++                do not include a just allocated block. Of course, each
++                free list contains a free blocks with the same alignment.
++                It is also creates a busy block that holds
++                information about an allocated block.
++
++ @Param[in]     h_MM        - Handle to the MM object.
++ @Param[in]     size        - Size of the MM.
++ @Param[in]     alignment   - Index as a power of two defines a required
++                              alignment (in bytes); Should be 1, 2, 4, 8, 16, 32 or 64
++ @Param[in]     name        - The name that specifies an allocated block.
++
++ @Return        base address of an allocated block ILLEGAL_BASE if can't allocate a block
++*//***************************************************************************/
++uint64_t    MM_Get(t_Handle h_MM, uint64_t size, uint64_t alignment, char *name);
++
++/**************************************************************************//**
++ @Function      MM_GetBase
++
++ @Description   Gets the base address of the required MM objects.
++
++ @Param[in]     h_MM - Handle to the MM object.
++
++ @Return        base address of the block.
++*//***************************************************************************/
++uint64_t    MM_GetBase(t_Handle h_MM);
++
++/**************************************************************************//**
++ @Function      MM_GetForce
++
++ @Description   Force memory allocation.
++
++                It means to allocate a block of memory of the given
++                size from the given base address.
++                The routine checks if the required block can be allocated
++                (that is it is free) and then, calls the internal MM_CutFree
++                routine to update all free lists do not include that block.
++
++ @Param[in]     h_MM    - Handle to the MM object.
++ @Param[in]     base    - Base address of the MM.
++ @Param[in]     size    - Size of the MM.
++ @Param[in]     name    - Name that specifies an allocated block.
++
++ @Return        base address of an allocated block, ILLEGAL_BASE if can't allocate a block.
++*//***************************************************************************/
++uint64_t    MM_GetForce(t_Handle h_MM, uint64_t base, uint64_t size, char *name);
++
++/**************************************************************************//**
++ @Function      MM_GetForceMin
++
++ @Description   Allocates a block of memory according to the given size, the alignment and minimum base address.
++
++                The Alignment argument tells from which
++                free list allocate a block of memory. 2^alignment indicates
++                the alignment that the base address of the allocated block
++                should have. So, the only values 1, 2, 4, 8, 16, 32 and 64
++                are available for the alignment argument.
++                The minimum baser address forces the location of the block
++                to be from a given address onward.
++                The routine passes through the specific free list of free
++                blocks and seeks for the first base address equal or smaller
++                than the required minimum address and end address larger than
++                than the required base + its size - i.e. that may contain
++                the required block.
++                After the block is found and data is allocated, it calls
++                the internal MM_CutFree routine to update all free lists
++                do not include a just allocated block. Of course, each
++                free list contains a free blocks with the same alignment.
++                It is also creates a busy block that holds
++                information about an allocated block.
++
++ @Param[in]     h_MM        - Handle to the MM object.
++ @Param[in]     size        - Size of the MM.
++ @Param[in]     alignment   - Index as a power of two defines a required
++                              alignment (in bytes); Should be 1, 2, 4, 8, 16, 32 or 64
++ @Param[in]     min         - The minimum base address of the block.
++ @Param[in]     name        - Name that specifies an allocated block.
++
++ @Return        base address of an allocated block,ILLEGAL_BASE if can't allocate a block.
++*//***************************************************************************/
++uint64_t    MM_GetForceMin(t_Handle h_MM,
++                           uint64_t size,
++                           uint64_t alignment,
++                           uint64_t min,
++                           char     *name);
++
++/**************************************************************************//**
++ @Function      MM_Put
++
++ @Description   Puts a block of memory of the given base address back to the memory.
++
++                It checks if there is a busy block with the
++                given base address. If not, it returns 0, that
++                means can't free a block. Otherwise, it gets parameters of
++                the busy block and after it updates lists of free blocks,
++                removes that busy block from the list by calling to MM_CutBusy
++                routine.
++                After that it calls to MM_AddFree routine to add a new free
++                block to the free lists.
++
++ @Param[in]     h_MM    - Handle to the MM object.
++ @Param[in]     base    - Base address of the MM.
++
++ @Return         The size of bytes released, 0 if failed.
++*//***************************************************************************/
++uint64_t    MM_Put(t_Handle h_MM, uint64_t base);
++
++/**************************************************************************//**
++ @Function      MM_PutForce
++
++ @Description   Releases a block of memory of the required size from the required base address.
++
++                First, it calls to MM_CutBusy routine
++                to cut a free block from the busy list. And then, calls to
++                MM_AddFree routine to add the free block to the free lists.
++
++ @Param[in]     h_MM    - Handle to the MM object.
++ @Param[in]     base    - Base address of of a block to free.
++ @Param[in]     size    - Size of a block to free.
++
++ @Return        The number of bytes released, 0 on failure.
++*//***************************************************************************/
++uint64_t    MM_PutForce(t_Handle h_MM, uint64_t base, uint64_t size);
++
++/**************************************************************************//**
++ @Function      MM_Add
++
++ @Description   Adds a new memory block for memory allocation.
++
++                When a new memory block is initialized and added to the
++                memory list, it calls to MM_AddFree routine to add the
++                new free block to the free lists.
++
++ @Param[in]     h_MM    - Handle to the MM object.
++ @Param[in]     base    - Base address of the memory block.
++ @Param[in]     size    - Size of the memory block.
++
++ @Return        E_OK on success, otherwise returns an error code.
++*//***************************************************************************/
++t_Error     MM_Add(t_Handle h_MM, uint64_t base, uint64_t size);
++
++/**************************************************************************//**
++ @Function      MM_Dump
++
++ @Description   Prints results of free and busy lists.
++
++ @Param[in]     h_MM        - Handle to the MM object.
++*//***************************************************************************/
++void        MM_Dump(t_Handle h_MM);
++
++/**************************************************************************//**
++ @Function      MM_Free
++
++ @Description   Releases memory allocated for MM object.
++
++ @Param[in]     h_MM - Handle of the MM object.
++*//***************************************************************************/
++void        MM_Free(t_Handle h_MM);
++
++/**************************************************************************//**
++ @Function      MM_GetMemBlock
++
++ @Description   Returns base address of the memory block specified by the index.
++
++                If index is 0, returns base address
++                of the first memory block, 1 - returns base address
++                of the second memory block, etc.
++                Note, those memory blocks are allocated by the
++                application before MM_Init or MM_Add and have to
++                be released by the application before or after invoking
++                the MM_Free routine.
++
++ @Param[in]     h_MM    - Handle to the MM object.
++ @Param[in]     index   - Index of the memory block.
++
++ @Return        valid base address or ILLEGAL_BASE if no memory block specified by the index.
++*//***************************************************************************/
++uint64_t    MM_GetMemBlock(t_Handle h_MM, int index);
++
++/**************************************************************************//**
++ @Function      MM_InRange
++
++ @Description   Checks if a specific address is in the memory range of the passed MM object.
++
++ @Param[in]     h_MM    - Handle to the MM object.
++ @Param[in]     addr    - The address to be checked.
++
++ @Return        TRUE if the address is in the address range of the block, FALSE otherwise.
++*//***************************************************************************/
++bool        MM_InRange(t_Handle h_MM, uint64_t addr);
++
++/**************************************************************************//**
++ @Function      MM_GetFreeMemSize
++
++ @Description   Returns the size (in bytes) of free memory.
++
++ @Param[in]     h_MM    - Handle to the MM object.
++
++ @Return        Free memory size in bytes.
++*//***************************************************************************/
++uint64_t MM_GetFreeMemSize(t_Handle h_MM);
++
++
++/** @} */ /* end of mm_grp group */
++/** @} */ /* end of etc_id group */
++
++#endif /* __MM_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/sprint_ext.h
+@@ -0,0 +1,118 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          sprint_ext.h
++
++ @Description   Debug routines (externals).
++
++*//***************************************************************************/
++
++#ifndef __SPRINT_EXT_H
++#define __SPRINT_EXT_H
++
++
++#if defined(NCSW_LINUX) && defined(__KERNEL__)
++#include <linux/kernel.h>
++
++#elif defined(NCSW_VXWORKS)
++#include "private/stdioP.h"
++
++#else
++#include <stdio.h>
++#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */
++
++#include "std_ext.h"
++
++
++/**************************************************************************//**
++ @Group         etc_id   Utility Library Application Programming Interface
++
++ @Description   External routines.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         sprint_id Sprint
++
++ @Description   Sprint & Sscan module functions,definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Function      Sprint
++
++ @Description   Format a string and place it in a buffer.
++
++ @Param[in]     buff - The buffer to place the result into.
++ @Param[in]     str  - The format string to use.
++ @Param[in]     ...  - Arguments for the format string.
++
++ @Return        Number of bytes formatted.
++*//***************************************************************************/
++int Sprint(char *buff, const char *str, ...);
++
++/**************************************************************************//**
++ @Function      Snprint
++
++ @Description   Format a string and place it in a buffer.
++
++ @Param[in]     buf  - The buffer to place the result into.
++ @Param[in]     size - The size of the buffer, including the trailing null space.
++ @Param[in]     fmt  - The format string to use.
++ @Param[in]     ...  - Arguments for the format string.
++
++ @Return        Number of bytes formatted.
++*//***************************************************************************/
++int Snprint(char * buf, uint32_t size, const char *fmt, ...);
++
++/**************************************************************************//**
++ @Function      Sscan
++
++ @Description   Unformat a buffer into a list of arguments.
++
++ @Param[in]     buf  - input buffer.
++ @Param[in]     fmt  - formatting of buffer.
++ @Param[out]    ...  - resulting arguments.
++
++ @Return        Number of bytes unformatted.
++*//***************************************************************************/
++int Sscan(const char * buf, const char * fmt, ...);
++
++/** @} */ /* end of sprint_id group */
++/** @} */ /* end of etc_id group */
++
++
++#endif /* __SPRINT_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/arch/ppc_access.h
+@@ -0,0 +1,37 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef FL_E500_MACROS_H
++#define FL_E500_MACROS_H
++
++#endif /* FL_E500_MACROS_H */
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/general.h
+@@ -0,0 +1,52 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __GENERAL_H
++#define __GENERAL_H
++
++#include "std_ext.h"
++#if !defined(NCSW_LINUX)
++#include "errno.h"
++#endif
++
++
++extern uint32_t get_mac_addr_crc(uint64_t _addr);
++
++#ifndef CONFIG_FMAN_ARM
++#define iowrite32be(val, addr)  WRITE_UINT32(*addr, val)
++#define ioread32be(addr)        GET_UINT32(*addr)
++#endif
++
++#define ether_crc(len, addr)    get_mac_addr_crc(*(uint64_t *)(addr)>>16)
++
++
++#endif /* __GENERAL_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fman_common.h
+@@ -0,0 +1,78 @@
++/*
++ * Copyright 2008-2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#ifndef __FMAN_COMMON_H
++#define __FMAN_COMMON_H
++
++/**************************************************************************//**
++  @Description       NIA Description
++*//***************************************************************************/
++#define NIA_ORDER_RESTOR                        0x00800000
++#define NIA_ENG_FM_CTL                          0x00000000
++#define NIA_ENG_PRS                             0x00440000
++#define NIA_ENG_KG                              0x00480000
++#define NIA_ENG_PLCR                            0x004C0000
++#define NIA_ENG_BMI                             0x00500000
++#define NIA_ENG_QMI_ENQ                         0x00540000
++#define NIA_ENG_QMI_DEQ                         0x00580000
++#define NIA_ENG_MASK                            0x007C0000
++
++#define NIA_FM_CTL_AC_CC                        0x00000006
++#define NIA_FM_CTL_AC_HC                        0x0000000C
++#define NIA_FM_CTL_AC_IND_MODE_TX               0x00000008
++#define NIA_FM_CTL_AC_IND_MODE_RX               0x0000000A
++#define NIA_FM_CTL_AC_FRAG                      0x0000000e
++#define NIA_FM_CTL_AC_PRE_FETCH                 0x00000010
++#define NIA_FM_CTL_AC_POST_FETCH_PCD            0x00000012
++#define NIA_FM_CTL_AC_POST_FETCH_PCD_UDP_LEN    0x00000018
++#define NIA_FM_CTL_AC_POST_FETCH_NO_PCD         0x00000012
++#define NIA_FM_CTL_AC_FRAG_CHECK                0x00000014
++#define NIA_FM_CTL_AC_PRE_CC                    0x00000020
++
++
++#define NIA_BMI_AC_ENQ_FRAME                    0x00000002
++#define NIA_BMI_AC_TX_RELEASE                   0x000002C0
++#define NIA_BMI_AC_RELEASE                      0x000000C0
++#define NIA_BMI_AC_DISCARD                      0x000000C1
++#define NIA_BMI_AC_TX                           0x00000274
++#define NIA_BMI_AC_FETCH                        0x00000208
++#define NIA_BMI_AC_MASK                         0x000003FF
++
++#define NIA_KG_DIRECT                           0x00000100
++#define NIA_KG_CC_EN                            0x00000200
++#define NIA_PLCR_ABSOLUTE                       0x00008000
++
++#define NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA        0x00000202
++#define NIA_BMI_AC_FETCH_ALL_FRAME              0x0000020c
++
++#endif /* __FMAN_COMMON_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_enet.h
+@@ -0,0 +1,273 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __FSL_ENET_H
++#define __FSL_ENET_H
++
++/**
++ @Description  Ethernet MAC-PHY Interface
++*/
++
++enum enet_interface {
++      E_ENET_IF_MII           = 0x00010000, /**< MII interface */
++      E_ENET_IF_RMII          = 0x00020000, /**< RMII interface */
++      E_ENET_IF_SMII          = 0x00030000, /**< SMII interface */
++      E_ENET_IF_GMII          = 0x00040000, /**< GMII interface */
++      E_ENET_IF_RGMII         = 0x00050000, /**< RGMII interface */
++      E_ENET_IF_TBI           = 0x00060000, /**< TBI interface */
++      E_ENET_IF_RTBI          = 0x00070000, /**< RTBI interface */
++      E_ENET_IF_SGMII         = 0x00080000, /**< SGMII interface */
++      E_ENET_IF_XGMII         = 0x00090000, /**< XGMII interface */
++      E_ENET_IF_QSGMII        = 0x000a0000, /**< QSGMII interface */
++      E_ENET_IF_XFI           = 0x000b0000  /**< XFI interface */
++};
++
++/**
++ @Description  Ethernet Speed (nominal data rate)
++*/
++enum enet_speed {
++      E_ENET_SPEED_10         = 10,   /**< 10 Mbps */
++      E_ENET_SPEED_100        = 100,  /**< 100 Mbps */
++      E_ENET_SPEED_1000       = 1000, /**< 1000 Mbps = 1 Gbps */
++      E_ENET_SPEED_2500       = 2500, /**< 2500 Mbps = 2.5 Gbps */
++      E_ENET_SPEED_10000      = 10000 /**< 10000 Mbps = 10 Gbps */
++};
++
++enum mac_type {
++      E_MAC_DTSEC,
++      E_MAC_TGEC,
++      E_MAC_MEMAC
++};
++
++/**************************************************************************//**
++ @Description   Enum for inter-module interrupts registration
++*//***************************************************************************/
++enum fman_event_modules {
++      E_FMAN_MOD_PRS,                   /**< Parser event */
++      E_FMAN_MOD_KG,                    /**< Keygen event */
++      E_FMAN_MOD_PLCR,                  /**< Policer event */
++      E_FMAN_MOD_10G_MAC,               /**< 10G MAC event */
++      E_FMAN_MOD_1G_MAC,                /**< 1G MAC event */
++      E_FMAN_MOD_TMR,                   /**< Timer event */
++      E_FMAN_MOD_FMAN_CTRL,             /**< FMAN Controller  Timer event */
++      E_FMAN_MOD_MACSEC,
++      E_FMAN_MOD_DUMMY_LAST
++};
++
++/**************************************************************************//**
++ @Description   Enum for interrupts types
++*//***************************************************************************/
++enum fman_intr_type {
++      E_FMAN_INTR_TYPE_ERR,
++      E_FMAN_INTR_TYPE_NORMAL
++};
++
++/**************************************************************************//**
++ @Description   enum for defining MAC types
++*//***************************************************************************/
++enum fman_mac_type {
++      E_FMAN_MAC_10G = 0,               /**< 10G MAC */
++      E_FMAN_MAC_1G                     /**< 1G MAC */
++};
++
++enum fman_mac_exceptions {
++      E_FMAN_MAC_EX_10G_MDIO_SCAN_EVENTMDIO = 0,
++              /**< 10GEC MDIO scan event interrupt */
++      E_FMAN_MAC_EX_10G_MDIO_CMD_CMPL,
++              /**< 10GEC MDIO command completion interrupt */
++      E_FMAN_MAC_EX_10G_REM_FAULT,
++              /**< 10GEC, mEMAC Remote fault interrupt */
++      E_FMAN_MAC_EX_10G_LOC_FAULT,
++              /**< 10GEC, mEMAC Local fault interrupt */
++      E_FMAN_MAC_EX_10G_1TX_ECC_ER,
++              /**< 10GEC, mEMAC Transmit frame ECC error interrupt */
++      E_FMAN_MAC_EX_10G_TX_FIFO_UNFL,
++              /**< 10GEC, mEMAC Transmit FIFO underflow interrupt */
++      E_FMAN_MAC_EX_10G_TX_FIFO_OVFL,
++              /**< 10GEC, mEMAC Transmit FIFO overflow interrupt */
++      E_FMAN_MAC_EX_10G_TX_ER,
++              /**< 10GEC Transmit frame error interrupt */
++      E_FMAN_MAC_EX_10G_RX_FIFO_OVFL,
++              /**< 10GEC, mEMAC Receive FIFO overflow interrupt */
++      E_FMAN_MAC_EX_10G_RX_ECC_ER,
++              /**< 10GEC, mEMAC Receive frame ECC error interrupt */
++      E_FMAN_MAC_EX_10G_RX_JAB_FRM,
++              /**< 10GEC Receive jabber frame interrupt */
++      E_FMAN_MAC_EX_10G_RX_OVRSZ_FRM,
++              /**< 10GEC Receive oversized frame interrupt */
++      E_FMAN_MAC_EX_10G_RX_RUNT_FRM,
++              /**< 10GEC Receive runt frame interrupt */
++      E_FMAN_MAC_EX_10G_RX_FRAG_FRM,
++              /**< 10GEC Receive fragment frame interrupt */
++      E_FMAN_MAC_EX_10G_RX_LEN_ER,
++              /**< 10GEC Receive payload length error interrupt */
++      E_FMAN_MAC_EX_10G_RX_CRC_ER,
++              /**< 10GEC Receive CRC error interrupt */
++      E_FMAN_MAC_EX_10G_RX_ALIGN_ER,
++              /**< 10GEC Receive alignment error interrupt */
++      E_FMAN_MAC_EX_1G_BAB_RX,
++              /**< dTSEC Babbling receive error */
++      E_FMAN_MAC_EX_1G_RX_CTL,
++              /**< dTSEC Receive control (pause frame) interrupt */
++      E_FMAN_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET,
++              /**< dTSEC Graceful transmit stop complete */
++      E_FMAN_MAC_EX_1G_BAB_TX,
++              /**< dTSEC Babbling transmit error */
++      E_FMAN_MAC_EX_1G_TX_CTL,
++              /**< dTSEC Transmit control (pause frame) interrupt */
++      E_FMAN_MAC_EX_1G_TX_ERR,
++              /**< dTSEC Transmit error */
++      E_FMAN_MAC_EX_1G_LATE_COL,
++              /**< dTSEC Late collision */
++      E_FMAN_MAC_EX_1G_COL_RET_LMT,
++              /**< dTSEC Collision retry limit */
++      E_FMAN_MAC_EX_1G_TX_FIFO_UNDRN,
++              /**< dTSEC Transmit FIFO underrun */
++      E_FMAN_MAC_EX_1G_MAG_PCKT,
++              /**< dTSEC Magic Packet detection */
++      E_FMAN_MAC_EX_1G_MII_MNG_RD_COMPLET,
++              /**< dTSEC MII management read completion */
++      E_FMAN_MAC_EX_1G_MII_MNG_WR_COMPLET,
++              /**< dTSEC MII management write completion */
++      E_FMAN_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET,
++              /**< dTSEC Graceful receive stop complete */
++      E_FMAN_MAC_EX_1G_TX_DATA_ERR,
++              /**< dTSEC Internal data error on transmit */
++      E_FMAN_MAC_EX_1G_RX_DATA_ERR,
++              /**< dTSEC Internal data error on receive */
++      E_FMAN_MAC_EX_1G_1588_TS_RX_ERR,
++              /**< dTSEC Time-Stamp Receive Error */
++      E_FMAN_MAC_EX_1G_RX_MIB_CNT_OVFL,
++              /**< dTSEC MIB counter overflow */
++      E_FMAN_MAC_EX_TS_FIFO_ECC_ERR,
++              /**< mEMAC Time-stamp FIFO ECC error interrupt;
++              not supported on T4240/B4860 rev1 chips */
++};
++
++#define ENET_IF_SGMII_BASEX 0x80000000
++      /**< SGMII/QSGII interface with 1000BaseX auto-negotiation between MAC
++      and phy or backplane;
++      Note: 1000BaseX auto-negotiation relates only to interface between MAC
++      and phy/backplane, SGMII phy can still synchronize with far-end phy at
++      10Mbps, 100Mbps or 1000Mbps */
++
++enum enet_mode {
++      E_ENET_MODE_INVALID           = 0,
++              /**< Invalid Ethernet mode */
++      E_ENET_MODE_MII_10            = (E_ENET_IF_MII   | E_ENET_SPEED_10),
++              /**<    10 Mbps MII   */
++      E_ENET_MODE_MII_100           = (E_ENET_IF_MII   | E_ENET_SPEED_100),
++              /**<   100 Mbps MII   */
++      E_ENET_MODE_RMII_10           = (E_ENET_IF_RMII  | E_ENET_SPEED_10),
++              /**<    10 Mbps RMII  */
++      E_ENET_MODE_RMII_100          = (E_ENET_IF_RMII  | E_ENET_SPEED_100),
++              /**<   100 Mbps RMII  */
++      E_ENET_MODE_SMII_10           = (E_ENET_IF_SMII  | E_ENET_SPEED_10),
++              /**<    10 Mbps SMII  */
++      E_ENET_MODE_SMII_100          = (E_ENET_IF_SMII  | E_ENET_SPEED_100),
++              /**<   100 Mbps SMII  */
++      E_ENET_MODE_GMII_1000         = (E_ENET_IF_GMII  | E_ENET_SPEED_1000),
++              /**<  1000 Mbps GMII  */
++      E_ENET_MODE_RGMII_10          = (E_ENET_IF_RGMII | E_ENET_SPEED_10),
++              /**<    10 Mbps RGMII */
++      E_ENET_MODE_RGMII_100         = (E_ENET_IF_RGMII | E_ENET_SPEED_100),
++              /**<   100 Mbps RGMII */
++      E_ENET_MODE_RGMII_1000        = (E_ENET_IF_RGMII | E_ENET_SPEED_1000),
++              /**<  1000 Mbps RGMII */
++      E_ENET_MODE_TBI_1000          = (E_ENET_IF_TBI   | E_ENET_SPEED_1000),
++              /**<  1000 Mbps TBI   */
++      E_ENET_MODE_RTBI_1000         = (E_ENET_IF_RTBI  | E_ENET_SPEED_1000),
++              /**<  1000 Mbps RTBI  */
++      E_ENET_MODE_SGMII_10          = (E_ENET_IF_SGMII | E_ENET_SPEED_10),
++              /**< 10 Mbps SGMII with auto-negotiation between MAC and
++              SGMII phy according to Cisco SGMII specification */
++      E_ENET_MODE_SGMII_100         = (E_ENET_IF_SGMII | E_ENET_SPEED_100),
++              /**< 100 Mbps SGMII with auto-negotiation between MAC and
++              SGMII phy according to Cisco SGMII specification */
++      E_ENET_MODE_SGMII_1000        = (E_ENET_IF_SGMII | E_ENET_SPEED_1000),
++              /**< 1000 Mbps SGMII with auto-negotiation between MAC and
++              SGMII phy according to Cisco SGMII specification */
++      E_ENET_MODE_SGMII_BASEX_10    = (ENET_IF_SGMII_BASEX | E_ENET_IF_SGMII
++              | E_ENET_SPEED_10),
++              /**< 10 Mbps SGMII with 1000BaseX auto-negotiation between
++              MAC and SGMII phy or backplane */
++      E_ENET_MODE_SGMII_BASEX_100   = (ENET_IF_SGMII_BASEX | E_ENET_IF_SGMII
++              | E_ENET_SPEED_100),
++              /**< 100 Mbps SGMII with 1000BaseX auto-negotiation between
++              MAC and SGMII phy or backplane */
++      E_ENET_MODE_SGMII_BASEX_1000  = (ENET_IF_SGMII_BASEX | E_ENET_IF_SGMII
++              | E_ENET_SPEED_1000),
++              /**< 1000 Mbps SGMII with 1000BaseX auto-negotiation between
++              MAC and SGMII phy or backplane */
++      E_ENET_MODE_QSGMII_1000       = (E_ENET_IF_QSGMII | E_ENET_SPEED_1000),
++              /**< 1000 Mbps QSGMII with auto-negotiation between MAC and
++              QSGMII phy according to Cisco QSGMII specification */
++      E_ENET_MODE_QSGMII_BASEX_1000 = (ENET_IF_SGMII_BASEX | E_ENET_IF_QSGMII
++              | E_ENET_SPEED_1000),
++              /**< 1000 Mbps QSGMII with 1000BaseX auto-negotiation between
++              MAC and QSGMII phy or backplane */
++      E_ENET_MODE_XGMII_10000       = (E_ENET_IF_XGMII | E_ENET_SPEED_10000),
++              /**< 10000 Mbps XGMII */
++      E_ENET_MODE_XFI_10000         = (E_ENET_IF_XFI   | E_ENET_SPEED_10000)
++              /**< 10000 Mbps XFI */
++};
++
++enum fmam_mac_statistics_level {
++      E_FMAN_MAC_NONE_STATISTICS,     /**< No statistics */
++      E_FMAN_MAC_PARTIAL_STATISTICS,  /**< Only error counters are available;
++                                      Optimized for performance */
++      E_FMAN_MAC_FULL_STATISTICS      /**< All counters available; Not
++                                      optimized for performance */
++};
++
++#define _MAKE_ENET_MODE(_interface, _speed) (enum enet_mode)((_interface) \
++      | (_speed))
++
++#define _ENET_INTERFACE_FROM_MODE(mode) (enum enet_interface) \
++      ((mode) & 0x0FFF0000)
++#define _ENET_SPEED_FROM_MODE(mode) (enum enet_speed)((mode) & 0x0000FFFF)
++#define _ENET_ADDR_TO_UINT64(_enet_addr)              \
++      (uint64_t)(((uint64_t)(_enet_addr)[0] << 40) |  \
++              ((uint64_t)(_enet_addr)[1] << 32) |     \
++              ((uint64_t)(_enet_addr)[2] << 24) |     \
++              ((uint64_t)(_enet_addr)[3] << 16) |     \
++              ((uint64_t)(_enet_addr)[4] << 8) |      \
++              ((uint64_t)(_enet_addr)[5]))
++
++#define _MAKE_ENET_ADDR_FROM_UINT64(_addr64, _enet_addr)              \
++      do {                                                            \
++              int i;                                                  \
++              for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++)       \
++                      (_enet_addr)[i] = (uint8_t)((_addr64) >> ((5-i)*8));\
++      } while (0)
++
++#endif /* __FSL_ENET_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman.h
+@@ -0,0 +1,825 @@
++/*
++ * Copyright 2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __FSL_FMAN_H
++#define __FSL_FMAN_H
++
++#include "common/general.h"
++
++struct fman_ext_pool_params {
++      uint8_t                 id;    /**< External buffer pool id */
++      uint16_t                size;  /**< External buffer pool buffer size */
++};
++
++struct fman_ext_pools {
++      uint8_t num_pools_used;        /**< Number of pools use by this port */
++      struct fman_ext_pool_params *ext_buf_pool;
++                                      /**< Parameters for each port */
++};
++
++struct fman_backup_bm_pools {
++      uint8_t          num_backup_pools; /**< Number of BM backup pools -
++                                      must be smaller than the total number
++                                      of pools defined for the specified
++                                      port.*/
++      uint8_t         *pool_ids;      /**< numOfBackupPools pool id's,
++                                      specifying which pools should be used
++                                      only as backup. Pool id's specified
++                                      here must be a subset of the pools
++                                      used by the specified port.*/
++};
++
++/**************************************************************************//**
++ @Description   A structure for defining BM pool depletion criteria
++*//***************************************************************************/
++struct fman_buf_pool_depletion {
++      bool buf_pool_depletion_enabled;
++      bool pools_grp_mode_enable;    /**< select mode in which pause frames
++                                      will be sent after a number of pools
++                                      (all together!) are depleted */
++      uint8_t num_pools;             /**< the number of depleted pools that
++                                      will invoke pause frames transmission.
++                                      */
++      bool *pools_to_consider;       /**< For each pool, TRUE if it should be
++                                      considered for depletion (Note - this
++                                      pool must be used by this port!). */
++      bool single_pool_mode_enable;  /**< select mode in which pause frames
++                                      will be sent after a single-pool
++                                      is depleted; */
++      bool *pools_to_consider_for_single_mode;
++                                     /**< For each pool, TRUE if it should be
++                                      considered for depletion (Note - this
++                                      pool must be used by this port!) */
++      bool has_pfc_priorities;
++      bool *pfc_priorities_en;       /**< This field is used by the MAC as
++                                      the Priority Enable Vector in the PFC
++                                      frame which is transmitted */
++};
++
++/**************************************************************************//**
++ @Description   Enum for defining port DMA swap mode
++*//***************************************************************************/
++enum fman_dma_swap_option {
++      FMAN_DMA_NO_SWP,           /**< No swap, transfer data as is.*/
++      FMAN_DMA_SWP_PPC_LE,       /**< The transferred data should be swapped
++                                      in PowerPc Little Endian mode. */
++      FMAN_DMA_SWP_BE            /**< The transferred data should be swapped
++                                      in Big Endian mode */
++};
++
++/**************************************************************************//**
++ @Description   Enum for defining port DMA cache attributes
++*//***************************************************************************/
++enum fman_dma_cache_option {
++      FMAN_DMA_NO_STASH = 0,     /**< Cacheable, no Allocate (No Stashing) */
++      FMAN_DMA_STASH = 1         /**< Cacheable and Allocate (Stashing on) */
++};
++
++typedef struct t_FmPrsResult fm_prs_result_t;
++typedef enum e_EnetMode enet_mode_t;
++typedef t_Handle handle_t;
++
++struct fman_revision_info {
++      uint8_t         majorRev;               /**< Major revision */
++      uint8_t         minorRev;               /**< Minor revision */
++};
++
++/* sizes */
++#define CAPWAP_FRAG_EXTRA_SPACE                 32
++#define OFFSET_UNITS                            16
++#define MAX_INT_OFFSET                          240
++#define MAX_IC_SIZE                             256
++#define MAX_EXT_OFFSET                          496
++#define MAX_EXT_BUFFER_OFFSET                   511
++
++/**************************************************************************
++ @Description       Memory Mapped Registers
++***************************************************************************/
++#define FMAN_LIODN_TBL        64      /* size of LIODN table */
++
++struct fman_fpm_regs {
++      uint32_t fmfp_tnc;      /**< FPM TNUM Control 0x00 */
++      uint32_t fmfp_prc;      /**< FPM Port_ID FmCtl Association 0x04 */
++      uint32_t fmfp_brkc;             /**< FPM Breakpoint Control 0x08 */
++      uint32_t fmfp_mxd;      /**< FPM Flush Control 0x0c */
++      uint32_t fmfp_dist1;    /**< FPM Dispatch Thresholds1 0x10 */
++      uint32_t fmfp_dist2;    /**< FPM Dispatch Thresholds2 0x14 */
++      uint32_t fm_epi;        /**< FM Error Pending Interrupts 0x18 */
++      uint32_t fm_rie;        /**< FM Error Interrupt Enable 0x1c */
++      uint32_t fmfp_fcev[4];  /**< FPM FMan-Controller Event 1-4 0x20-0x2f */
++      uint32_t res0030[4];    /**< res 0x30 - 0x3f */
++      uint32_t fmfp_cee[4];   /**< PM FMan-Controller Event 1-4 0x40-0x4f */
++      uint32_t res0050[4];    /**< res 0x50-0x5f */
++      uint32_t fmfp_tsc1;     /**< FPM TimeStamp Control1 0x60 */
++      uint32_t fmfp_tsc2;     /**< FPM TimeStamp Control2 0x64 */
++      uint32_t fmfp_tsp;      /**< FPM Time Stamp 0x68 */
++      uint32_t fmfp_tsf;      /**< FPM Time Stamp Fraction 0x6c */
++      uint32_t fm_rcr;        /**< FM Rams Control 0x70 */
++      uint32_t fmfp_extc;     /**< FPM External Requests Control 0x74 */
++      uint32_t fmfp_ext1;     /**< FPM External Requests Config1 0x78 */
++      uint32_t fmfp_ext2;     /**< FPM External Requests Config2 0x7c */
++      uint32_t fmfp_drd[16];  /**< FPM Data_Ram Data 0-15 0x80 - 0xbf */
++      uint32_t fmfp_dra;      /**< FPM Data Ram Access 0xc0 */
++      uint32_t fm_ip_rev_1;   /**< FM IP Block Revision 1 0xc4 */
++      uint32_t fm_ip_rev_2;   /**< FM IP Block Revision 2 0xc8 */
++      uint32_t fm_rstc;       /**< FM Reset Command 0xcc */
++      uint32_t fm_cld;        /**< FM Classifier Debug 0xd0 */
++      uint32_t fm_npi;        /**< FM Normal Pending Interrupts 0xd4 */
++      uint32_t fmfp_exte;     /**< FPM External Requests Enable 0xd8 */
++      uint32_t fmfp_ee;       /**< FPM Event & Mask 0xdc */
++      uint32_t fmfp_cev[4];   /**< FPM CPU Event 1-4 0xe0-0xef */
++      uint32_t res00f0[4];    /**< res 0xf0-0xff */
++      uint32_t fmfp_ps[64];   /**< FPM Port Status 0x100-0x1ff */
++      uint32_t fmfp_clfabc;   /**< FPM CLFABC 0x200 */
++      uint32_t fmfp_clfcc;    /**< FPM CLFCC 0x204 */
++      uint32_t fmfp_clfaval;  /**< FPM CLFAVAL 0x208 */
++      uint32_t fmfp_clfbval;  /**< FPM CLFBVAL 0x20c */
++      uint32_t fmfp_clfcval;  /**< FPM CLFCVAL 0x210 */
++      uint32_t fmfp_clfamsk;  /**< FPM CLFAMSK 0x214 */
++      uint32_t fmfp_clfbmsk;  /**< FPM CLFBMSK 0x218 */
++      uint32_t fmfp_clfcmsk;  /**< FPM CLFCMSK 0x21c */
++      uint32_t fmfp_clfamc;   /**< FPM CLFAMC 0x220 */
++      uint32_t fmfp_clfbmc;   /**< FPM CLFBMC 0x224 */
++      uint32_t fmfp_clfcmc;   /**< FPM CLFCMC 0x228 */
++      uint32_t fmfp_decceh;   /**< FPM DECCEH 0x22c */
++      uint32_t res0230[116];  /**< res 0x230 - 0x3ff */
++      uint32_t fmfp_ts[128];  /**< 0x400: FPM Task Status 0x400 - 0x5ff */
++      uint32_t res0600[0x400 - 384];
++};
++
++struct fman_bmi_regs {
++      uint32_t fmbm_init; /**< BMI Initialization 0x00 */
++      uint32_t fmbm_cfg1; /**< BMI Configuration 1 0x04 */
++      uint32_t fmbm_cfg2; /**< BMI Configuration 2 0x08 */
++      uint32_t res000c[5]; /**< 0x0c - 0x1f */
++      uint32_t fmbm_ievr; /**< Interrupt Event Register 0x20 */
++      uint32_t fmbm_ier; /**< Interrupt Enable Register 0x24 */
++      uint32_t fmbm_ifr; /**< Interrupt Force Register 0x28 */
++      uint32_t res002c[5]; /**< 0x2c - 0x3f */
++      uint32_t fmbm_arb[8]; /**< BMI Arbitration 0x40 - 0x5f */
++      uint32_t res0060[12]; /**<0x60 - 0x8f */
++      uint32_t fmbm_dtc[3]; /**< Debug Trap Counter 0x90 - 0x9b */
++      uint32_t res009c; /**< 0x9c */
++      uint32_t fmbm_dcv[3][4]; /**< Debug Compare val 0xa0-0xcf */
++      uint32_t fmbm_dcm[3][4]; /**< Debug Compare Mask 0xd0-0xff */
++      uint32_t fmbm_gde; /**< BMI Global Debug Enable 0x100 */
++      uint32_t fmbm_pp[63]; /**< BMI Port Parameters 0x104 - 0x1ff */
++      uint32_t res0200; /**< 0x200 */
++      uint32_t fmbm_pfs[63]; /**< BMI Port FIFO Size 0x204 - 0x2ff */
++      uint32_t res0300; /**< 0x300 */
++      uint32_t fmbm_spliodn[63]; /**< Port Partition ID 0x304 - 0x3ff */
++};
++
++struct fman_qmi_regs {
++      uint32_t fmqm_gc; /**< General Configuration Register 0x00 */
++      uint32_t res0004; /**< 0x04 */
++      uint32_t fmqm_eie; /**< Error Interrupt Event Register 0x08 */
++      uint32_t fmqm_eien; /**< Error Interrupt Enable Register 0x0c */
++      uint32_t fmqm_eif; /**< Error Interrupt Force Register 0x10 */
++      uint32_t fmqm_ie; /**< Interrupt Event Register 0x14 */
++      uint32_t fmqm_ien; /**< Interrupt Enable Register 0x18 */
++      uint32_t fmqm_if; /**< Interrupt Force Register 0x1c */
++      uint32_t fmqm_gs; /**< Global Status Register 0x20 */
++      uint32_t fmqm_ts; /**< Task Status Register 0x24 */
++      uint32_t fmqm_etfc; /**< Enqueue Total Frame Counter 0x28 */
++      uint32_t fmqm_dtfc; /**< Dequeue Total Frame Counter 0x2c */
++      uint32_t fmqm_dc0; /**< Dequeue Counter 0 0x30 */
++      uint32_t fmqm_dc1; /**< Dequeue Counter 1 0x34 */
++      uint32_t fmqm_dc2; /**< Dequeue Counter 2 0x38 */
++      uint32_t fmqm_dc3; /**< Dequeue Counter 3 0x3c */
++      uint32_t fmqm_dfdc; /**< Dequeue FQID from Default Counter 0x40 */
++      uint32_t fmqm_dfcc; /**< Dequeue FQID from Context Counter 0x44 */
++      uint32_t fmqm_dffc; /**< Dequeue FQID from FD Counter 0x48 */
++      uint32_t fmqm_dcc; /**< Dequeue Confirm Counter 0x4c */
++      uint32_t res0050[7]; /**< 0x50 - 0x6b */
++      uint32_t fmqm_tapc; /**< Tnum Aging Period Control 0x6c */
++      uint32_t fmqm_dmcvc; /**< Dequeue MAC Command Valid Counter 0x70 */
++      uint32_t fmqm_difdcc; /**< Dequeue Invalid FD Command Counter 0x74 */
++      uint32_t fmqm_da1v; /**< Dequeue A1 Valid Counter 0x78 */
++      uint32_t res007c; /**< 0x7c */
++      uint32_t fmqm_dtc; /**< 0x80 Debug Trap Counter 0x80 */
++      uint32_t fmqm_efddd; /**< 0x84 Enqueue Frame desc Dynamic dbg 0x84 */
++      uint32_t res0088[2]; /**< 0x88 - 0x8f */
++      struct {
++              uint32_t fmqm_dtcfg1; /**< 0x90 dbg trap cfg 1 Register 0x00 */
++              uint32_t fmqm_dtval1; /**< Debug Trap Value 1 Register 0x04 */
++              uint32_t fmqm_dtm1; /**< Debug Trap Mask 1 Register 0x08 */
++              uint32_t fmqm_dtc1; /**< Debug Trap Counter 1 Register 0x0c */
++              uint32_t fmqm_dtcfg2; /**< dbg Trap cfg 2 Register 0x10 */
++              uint32_t fmqm_dtval2; /**< Debug Trap Value 2 Register 0x14 */
++              uint32_t fmqm_dtm2; /**< Debug Trap Mask 2 Register 0x18 */
++              uint32_t res001c; /**< 0x1c */
++      } dbg_traps[3]; /**< 0x90 - 0xef */
++      uint8_t res00f0[0x400 - 0xf0]; /**< 0xf0 - 0x3ff */
++};
++
++struct fman_dma_regs {
++      uint32_t fmdmsr; /**< FM DMA status register 0x00 */
++      uint32_t fmdmmr; /**< FM DMA mode register 0x04 */
++      uint32_t fmdmtr; /**< FM DMA bus threshold register 0x08 */
++      uint32_t fmdmhy; /**< FM DMA bus hysteresis register 0x0c */
++      uint32_t fmdmsetr; /**< FM DMA SOS emergency Threshold Register 0x10 */
++      uint32_t fmdmtah; /**< FM DMA transfer bus address high reg 0x14 */
++      uint32_t fmdmtal; /**< FM DMA transfer bus address low reg 0x18 */
++      uint32_t fmdmtcid; /**< FM DMA transfer bus communication ID reg 0x1c */
++      uint32_t fmdmra; /**< FM DMA bus internal ram address register 0x20 */
++      uint32_t fmdmrd; /**< FM DMA bus internal ram data register 0x24 */
++      uint32_t fmdmwcr; /**< FM DMA CAM watchdog counter value 0x28 */
++      uint32_t fmdmebcr; /**< FM DMA CAM base in MURAM register 0x2c */
++      uint32_t fmdmccqdr; /**< FM DMA CAM and CMD Queue Debug reg 0x30 */
++      uint32_t fmdmccqvr1; /**< FM DMA CAM and CMD Queue Value reg #1 0x34 */
++      uint32_t fmdmccqvr2; /**< FM DMA CAM and CMD Queue Value reg #2 0x38 */
++      uint32_t fmdmcqvr3; /**< FM DMA CMD Queue Value register #3 0x3c */
++      uint32_t fmdmcqvr4; /**< FM DMA CMD Queue Value register #4 0x40 */
++      uint32_t fmdmcqvr5; /**< FM DMA CMD Queue Value register #5 0x44 */
++      uint32_t fmdmsefrc; /**< FM DMA Semaphore Entry Full Reject Cntr 0x48 */
++      uint32_t fmdmsqfrc; /**< FM DMA Semaphore Queue Full Reject Cntr 0x4c */
++      uint32_t fmdmssrc; /**< FM DMA Semaphore SYNC Reject Counter 0x50 */
++      uint32_t fmdmdcr;  /**< FM DMA Debug Counter 0x54 */
++      uint32_t fmdmemsr; /**< FM DMA Emergency Smoother Register 0x58 */
++      uint32_t res005c; /**< 0x5c */
++      uint32_t fmdmplr[FMAN_LIODN_TBL / 2]; /**< DMA LIODN regs 0x60-0xdf */
++      uint32_t res00e0[0x400 - 56];
++};
++
++struct fman_rg {
++      struct fman_fpm_regs *fpm_rg;
++      struct fman_dma_regs *dma_rg;
++      struct fman_bmi_regs *bmi_rg;
++      struct fman_qmi_regs *qmi_rg;
++};
++
++enum fman_dma_cache_override {
++      E_FMAN_DMA_NO_CACHE_OR = 0, /**< No override of the Cache field */
++      E_FMAN_DMA_NO_STASH_DATA, /**< No data stashing in system level cache */
++      E_FMAN_DMA_MAY_STASH_DATA, /**< Stashing allowed in sys level cache */
++      E_FMAN_DMA_STASH_DATA /**< Stashing performed in system level cache */
++};
++
++enum fman_dma_aid_mode {
++      E_FMAN_DMA_AID_OUT_PORT_ID = 0,           /**< 4 LSB of PORT_ID */
++      E_FMAN_DMA_AID_OUT_TNUM                   /**< 4 LSB of TNUM */
++};
++
++enum fman_dma_dbg_cnt_mode {
++      E_FMAN_DMA_DBG_NO_CNT = 0, /**< No counting */
++      E_FMAN_DMA_DBG_CNT_DONE, /**< Count DONE commands */
++      E_FMAN_DMA_DBG_CNT_COMM_Q_EM, /**< command Q emergency signal */
++      E_FMAN_DMA_DBG_CNT_INT_READ_EM, /**< Read buf emergency signal */
++      E_FMAN_DMA_DBG_CNT_INT_WRITE_EM, /**< Write buf emergency signal */
++      E_FMAN_DMA_DBG_CNT_FPM_WAIT, /**< FPM WAIT signal */
++      E_FMAN_DMA_DBG_CNT_SIGLE_BIT_ECC, /**< Single bit ECC errors */
++      E_FMAN_DMA_DBG_CNT_RAW_WAR_PROT /**< RAW & WAR protection counter */
++};
++
++enum fman_dma_emergency_level {
++      E_FMAN_DMA_EM_EBS = 0, /**< EBS emergency */
++      E_FMAN_DMA_EM_SOS /**< SOS emergency */
++};
++
++enum fman_catastrophic_err {
++      E_FMAN_CATAST_ERR_STALL_PORT = 0, /**< Port_ID stalled reset required */
++      E_FMAN_CATAST_ERR_STALL_TASK /**< Only erroneous task is stalled */
++};
++
++enum fman_dma_err {
++      E_FMAN_DMA_ERR_CATASTROPHIC = 0, /**< Catastrophic DMA error */
++      E_FMAN_DMA_ERR_REPORT /**< Reported DMA error */
++};
++
++struct fman_cfg {
++      uint16_t        liodn_bs_pr_port[FMAN_LIODN_TBL];/* base per port */
++      bool            en_counters;
++      uint8_t         disp_limit_tsh;
++      uint8_t         prs_disp_tsh;
++      uint8_t         plcr_disp_tsh;
++      uint8_t         kg_disp_tsh;
++      uint8_t         bmi_disp_tsh;
++      uint8_t         qmi_enq_disp_tsh;
++      uint8_t         qmi_deq_disp_tsh;
++      uint8_t         fm_ctl1_disp_tsh;
++      uint8_t         fm_ctl2_disp_tsh;
++      enum fman_dma_cache_override    dma_cache_override;
++      enum fman_dma_aid_mode          dma_aid_mode;
++      bool            dma_aid_override;
++      uint8_t         dma_axi_dbg_num_of_beats;
++      uint8_t         dma_cam_num_of_entries;
++      uint32_t        dma_watchdog;
++      uint8_t         dma_comm_qtsh_asrt_emer;
++      uint8_t         dma_write_buf_tsh_asrt_emer;
++      uint8_t         dma_read_buf_tsh_asrt_emer;
++      uint8_t         dma_comm_qtsh_clr_emer;
++      uint8_t         dma_write_buf_tsh_clr_emer;
++      uint8_t         dma_read_buf_tsh_clr_emer;
++      uint32_t        dma_sos_emergency;
++      enum fman_dma_dbg_cnt_mode      dma_dbg_cnt_mode;
++      bool            dma_stop_on_bus_error;
++      bool            dma_en_emergency;
++      uint32_t        dma_emergency_bus_select;
++      enum fman_dma_emergency_level   dma_emergency_level;
++      bool            dma_en_emergency_smoother;
++      uint32_t        dma_emergency_switch_counter;
++      bool            halt_on_external_activ;
++      bool            halt_on_unrecov_ecc_err;
++      enum fman_catastrophic_err      catastrophic_err;
++      enum fman_dma_err               dma_err;
++      bool            en_muram_test_mode;
++      bool            en_iram_test_mode;
++      bool            external_ecc_rams_enable;
++      uint16_t        tnum_aging_period;
++      uint32_t        exceptions;
++      uint16_t        clk_freq;
++      bool            pedantic_dma;
++      uint32_t        cam_base_addr;
++      uint32_t        fifo_base_addr;
++      uint32_t        total_fifo_size;
++      uint8_t         total_num_of_tasks;
++      bool            qmi_deq_option_support;
++      uint32_t        qmi_def_tnums_thresh;
++      bool            fman_partition_array;
++      uint8_t         num_of_fman_ctrl_evnt_regs;
++};
++
++/**************************************************************************//**
++ @Description       Exceptions
++*//***************************************************************************/
++#define FMAN_EX_DMA_BUS_ERROR                 0x80000000
++#define FMAN_EX_DMA_READ_ECC                  0x40000000
++#define FMAN_EX_DMA_SYSTEM_WRITE_ECC          0x20000000
++#define FMAN_EX_DMA_FM_WRITE_ECC              0x10000000
++#define FMAN_EX_FPM_STALL_ON_TASKS            0x08000000
++#define FMAN_EX_FPM_SINGLE_ECC                        0x04000000
++#define FMAN_EX_FPM_DOUBLE_ECC                        0x02000000
++#define FMAN_EX_QMI_SINGLE_ECC                        0x01000000
++#define FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID   0x00800000
++#define FMAN_EX_QMI_DOUBLE_ECC                        0x00400000
++#define FMAN_EX_BMI_LIST_RAM_ECC              0x00200000
++#define FMAN_EX_BMI_PIPELINE_ECC              0x00100000
++#define FMAN_EX_BMI_STATISTICS_RAM_ECC                0x00080000
++#define FMAN_EX_IRAM_ECC                      0x00040000
++#define FMAN_EX_NURAM_ECC                     0x00020000
++#define FMAN_EX_BMI_DISPATCH_RAM_ECC          0x00010000
++
++enum fman_exceptions {
++      E_FMAN_EX_DMA_BUS_ERROR = 0, /**< DMA bus error. */
++      E_FMAN_EX_DMA_READ_ECC, /**< Read Buffer ECC error */
++      E_FMAN_EX_DMA_SYSTEM_WRITE_ECC, /**< Write Buffer ECC err on sys side */
++      E_FMAN_EX_DMA_FM_WRITE_ECC, /**< Write Buffer ECC error on FM side */
++      E_FMAN_EX_FPM_STALL_ON_TASKS, /**< Stall of tasks on FPM */
++      E_FMAN_EX_FPM_SINGLE_ECC, /**< Single ECC on FPM. */
++      E_FMAN_EX_FPM_DOUBLE_ECC, /**< Double ECC error on FPM ram access */
++      E_FMAN_EX_QMI_SINGLE_ECC, /**< Single ECC on QMI. */
++      E_FMAN_EX_QMI_DOUBLE_ECC, /**< Double bit ECC occurred on QMI */
++      E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,/**< DeQ from unknown port id */
++      E_FMAN_EX_BMI_LIST_RAM_ECC, /**< Linked List RAM ECC error */
++      E_FMAN_EX_BMI_STORAGE_PROFILE_ECC, /**< storage profile */
++      E_FMAN_EX_BMI_STATISTICS_RAM_ECC, /**< Statistics RAM ECC Err Enable */
++      E_FMAN_EX_BMI_DISPATCH_RAM_ECC, /**< Dispatch RAM ECC Error Enable */
++      E_FMAN_EX_IRAM_ECC, /**< Double bit ECC occurred on IRAM*/
++      E_FMAN_EX_MURAM_ECC /**< Double bit ECC occurred on MURAM*/
++};
++
++enum fman_counters {
++      E_FMAN_COUNTERS_ENQ_TOTAL_FRAME = 0, /**< QMI tot enQ frames counter */
++      E_FMAN_COUNTERS_DEQ_TOTAL_FRAME, /**< QMI tot deQ frames counter */
++      E_FMAN_COUNTERS_DEQ_0, /**< QMI 0 frames from QMan counter */
++      E_FMAN_COUNTERS_DEQ_1, /**< QMI 1 frames from QMan counter */
++      E_FMAN_COUNTERS_DEQ_2, /**< QMI 2 frames from QMan counter */
++      E_FMAN_COUNTERS_DEQ_3, /**< QMI 3 frames from QMan counter */
++      E_FMAN_COUNTERS_DEQ_FROM_DEFAULT, /**< QMI deQ from dflt queue cntr */
++      E_FMAN_COUNTERS_DEQ_FROM_CONTEXT, /**< QMI deQ from FQ context cntr */
++      E_FMAN_COUNTERS_DEQ_FROM_FD, /**< QMI deQ from FD command field cntr */
++      E_FMAN_COUNTERS_DEQ_CONFIRM, /**< QMI dequeue confirm counter */
++      E_FMAN_COUNTERS_SEMAPHOR_ENTRY_FULL_REJECT, /**< DMA full entry cntr */
++      E_FMAN_COUNTERS_SEMAPHOR_QUEUE_FULL_REJECT, /**< DMA full CAM Q cntr */
++      E_FMAN_COUNTERS_SEMAPHOR_SYNC_REJECT /**< DMA sync counter */
++};
++
++#define FPM_PRT_FM_CTL1       0x00000001
++#define FPM_PRT_FM_CTL2       0x00000002
++
++/**************************************************************************//**
++ @Description       DMA definitions
++*//***************************************************************************/
++
++/* masks */
++#define DMA_MODE_AID_OR                       0x20000000
++#define DMA_MODE_SBER                 0x10000000
++#define DMA_MODE_BER                  0x00200000
++#define DMA_MODE_EB             0x00100000
++#define DMA_MODE_ECC                  0x00000020
++#define DMA_MODE_PRIVILEGE_PROT       0x00001000
++#define DMA_MODE_SECURE_PROT  0x00000800
++#define DMA_MODE_EMER_READ            0x00080000
++#define DMA_MODE_EMER_WRITE           0x00040000
++#define DMA_MODE_CACHE_OR_MASK  0xC0000000
++#define DMA_MODE_CEN_MASK       0x0000E000
++#define DMA_MODE_DBG_MASK       0x00000380
++#define DMA_MODE_AXI_DBG_MASK   0x0F000000
++
++#define DMA_EMSR_EMSTR_MASK         0x0000FFFF
++
++#define DMA_TRANSFER_PORTID_MASK      0xFF000000
++#define DMA_TRANSFER_TNUM_MASK                0x00FF0000
++#define DMA_TRANSFER_LIODN_MASK               0x00000FFF
++
++#define DMA_HIGH_LIODN_MASK           0x0FFF0000
++#define DMA_LOW_LIODN_MASK            0x00000FFF
++
++#define DMA_STATUS_CMD_QUEUE_NOT_EMPTY        0x10000000
++#define DMA_STATUS_BUS_ERR            0x08000000
++#define DMA_STATUS_READ_ECC           0x04000000
++#define DMA_STATUS_SYSTEM_WRITE_ECC   0x02000000
++#define DMA_STATUS_FM_WRITE_ECC               0x01000000
++#define DMA_STATUS_SYSTEM_DPEXT_ECC   0x00800000
++#define DMA_STATUS_FM_DPEXT_ECC               0x00400000
++#define DMA_STATUS_SYSTEM_DPDAT_ECC   0x00200000
++#define DMA_STATUS_FM_DPDAT_ECC               0x00100000
++#define DMA_STATUS_FM_SPDAT_ECC               0x00080000
++
++#define FM_LIODN_BASE_MASK            0x00000FFF
++
++/* shifts */
++#define DMA_MODE_CACHE_OR_SHIFT                       30
++#define DMA_MODE_BUS_PRI_SHIFT                        16
++#define DMA_MODE_AXI_DBG_SHIFT                        24
++#define DMA_MODE_CEN_SHIFT                    13
++#define DMA_MODE_BUS_PROT_SHIFT                       10
++#define DMA_MODE_DBG_SHIFT                    7
++#define DMA_MODE_EMER_LVL_SHIFT                       6
++#define DMA_MODE_AID_MODE_SHIFT                       4
++#define DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS     16
++#define DMA_MODE_MAX_CAM_NUM_OF_ENTRIES               32
++
++#define DMA_THRESH_COMMQ_SHIFT                        24
++#define DMA_THRESH_READ_INT_BUF_SHIFT         16
++
++#define DMA_LIODN_SHIFT                               16
++
++#define DMA_TRANSFER_PORTID_SHIFT             24
++#define DMA_TRANSFER_TNUM_SHIFT                       16
++
++/* sizes */
++#define DMA_MAX_WATCHDOG                      0xffffffff
++
++/* others */
++#define DMA_CAM_SIZEOF_ENTRY                  0x40
++#define DMA_CAM_ALIGN                         0x1000
++#define DMA_CAM_UNITS                         8
++
++/**************************************************************************//**
++ @Description       General defines
++*//***************************************************************************/
++
++#define FM_DEBUG_STATUS_REGISTER_OFFSET       0x000d1084UL
++#define FM_UCODE_DEBUG_INSTRUCTION    0x6ffff805UL
++
++/**************************************************************************//**
++ @Description       FPM defines
++*//***************************************************************************/
++
++/* masks */
++#define FPM_EV_MASK_DOUBLE_ECC                0x80000000
++#define FPM_EV_MASK_STALL             0x40000000
++#define FPM_EV_MASK_SINGLE_ECC                0x20000000
++#define FPM_EV_MASK_RELEASE_FM                0x00010000
++#define FPM_EV_MASK_DOUBLE_ECC_EN     0x00008000
++#define FPM_EV_MASK_STALL_EN          0x00004000
++#define FPM_EV_MASK_SINGLE_ECC_EN     0x00002000
++#define FPM_EV_MASK_EXTERNAL_HALT     0x00000008
++#define FPM_EV_MASK_ECC_ERR_HALT      0x00000004
++
++#define FPM_RAM_RAMS_ECC_EN           0x80000000
++#define FPM_RAM_IRAM_ECC_EN           0x40000000
++#define FPM_RAM_MURAM_ECC             0x00008000
++#define FPM_RAM_IRAM_ECC              0x00004000
++#define FPM_RAM_MURAM_TEST_ECC                0x20000000
++#define FPM_RAM_IRAM_TEST_ECC         0x10000000
++#define FPM_RAM_RAMS_ECC_EN_SRC_SEL   0x08000000
++
++#define FPM_IRAM_ECC_ERR_EX_EN                0x00020000
++#define FPM_MURAM_ECC_ERR_EX_EN               0x00040000
++
++#define FPM_REV1_MAJOR_MASK           0x0000FF00
++#define FPM_REV1_MINOR_MASK           0x000000FF
++
++#define FPM_REV2_INTEG_MASK           0x00FF0000
++#define FPM_REV2_ERR_MASK             0x0000FF00
++#define FPM_REV2_CFG_MASK             0x000000FF
++
++#define FPM_TS_FRACTION_MASK          0x0000FFFF
++#define FPM_TS_CTL_EN                 0x80000000
++
++#define FPM_PRC_REALSE_STALLED                0x00800000
++
++#define FPM_PS_STALLED                        0x00800000
++#define FPM_PS_FM_CTL1_SEL            0x80000000
++#define FPM_PS_FM_CTL2_SEL            0x40000000
++#define FPM_PS_FM_CTL_SEL_MASK        (FPM_PS_FM_CTL1_SEL | FPM_PS_FM_CTL2_SEL)
++
++#define FPM_RSTC_FM_RESET             0x80000000
++#define FPM_RSTC_10G0_RESET           0x04000000
++#define FPM_RSTC_1G0_RESET            0x40000000
++#define FPM_RSTC_1G1_RESET            0x20000000
++#define FPM_RSTC_1G2_RESET            0x10000000
++#define FPM_RSTC_1G3_RESET            0x08000000
++#define FPM_RSTC_1G4_RESET            0x02000000
++
++
++#define FPM_DISP_LIMIT_MASK             0x1F000000
++#define FPM_THR1_PRS_MASK               0xFF000000
++#define FPM_THR1_KG_MASK                0x00FF0000
++#define FPM_THR1_PLCR_MASK              0x0000FF00
++#define FPM_THR1_BMI_MASK               0x000000FF
++
++#define FPM_THR2_QMI_ENQ_MASK           0xFF000000
++#define FPM_THR2_QMI_DEQ_MASK           0x000000FF
++#define FPM_THR2_FM_CTL1_MASK           0x00FF0000
++#define FPM_THR2_FM_CTL2_MASK           0x0000FF00
++
++/* shifts */
++#define FPM_DISP_LIMIT_SHIFT          24
++
++#define FPM_THR1_PRS_SHIFT            24
++#define FPM_THR1_KG_SHIFT             16
++#define FPM_THR1_PLCR_SHIFT           8
++#define FPM_THR1_BMI_SHIFT            0
++
++#define FPM_THR2_QMI_ENQ_SHIFT                24
++#define FPM_THR2_QMI_DEQ_SHIFT                0
++#define FPM_THR2_FM_CTL1_SHIFT                16
++#define FPM_THR2_FM_CTL2_SHIFT                8
++
++#define FPM_EV_MASK_CAT_ERR_SHIFT     1
++#define FPM_EV_MASK_DMA_ERR_SHIFT     0
++
++#define FPM_REV1_MAJOR_SHIFT          8
++#define FPM_REV1_MINOR_SHIFT          0
++
++#define FPM_REV2_INTEG_SHIFT          16
++#define FPM_REV2_ERR_SHIFT            8
++#define FPM_REV2_CFG_SHIFT            0
++
++#define FPM_TS_INT_SHIFT              16
++
++#define FPM_PORT_FM_CTL_PORTID_SHIFT  24
++
++#define FPM_PS_FM_CTL_SEL_SHIFT               30
++#define FPM_PRC_ORA_FM_CTL_SEL_SHIFT  16
++
++#define FPM_DISP_LIMIT_SHIFT            24
++
++/* Interrupts defines */
++#define FPM_EVENT_FM_CTL_0            0x00008000
++#define FPM_EVENT_FM_CTL              0x0000FF00
++#define FPM_EVENT_FM_CTL_BRK          0x00000080
++
++/* others */
++#define FPM_MAX_DISP_LIMIT            31
++#define FPM_RSTC_FM_RESET               0x80000000
++#define FPM_RSTC_1G0_RESET              0x40000000
++#define FPM_RSTC_1G1_RESET              0x20000000
++#define FPM_RSTC_1G2_RESET              0x10000000
++#define FPM_RSTC_1G3_RESET              0x08000000
++#define FPM_RSTC_10G0_RESET             0x04000000
++#define FPM_RSTC_1G4_RESET              0x02000000
++#define FPM_RSTC_1G5_RESET              0x01000000
++#define FPM_RSTC_1G6_RESET              0x00800000
++#define FPM_RSTC_1G7_RESET              0x00400000
++#define FPM_RSTC_10G1_RESET             0x00200000
++/**************************************************************************//**
++ @Description       BMI defines
++*//***************************************************************************/
++/* masks */
++#define BMI_INIT_START                                0x80000000
++#define BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC   0x80000000
++#define BMI_ERR_INTR_EN_LIST_RAM_ECC          0x40000000
++#define BMI_ERR_INTR_EN_STATISTICS_RAM_ECC    0x20000000
++#define BMI_ERR_INTR_EN_DISPATCH_RAM_ECC      0x10000000
++#define BMI_NUM_OF_TASKS_MASK                 0x3F000000
++#define BMI_NUM_OF_EXTRA_TASKS_MASK           0x000F0000
++#define BMI_NUM_OF_DMAS_MASK                  0x00000F00
++#define BMI_NUM_OF_EXTRA_DMAS_MASK            0x0000000F
++#define BMI_FIFO_SIZE_MASK                    0x000003FF
++#define BMI_EXTRA_FIFO_SIZE_MASK              0x03FF0000
++#define BMI_CFG2_DMAS_MASK                    0x0000003F
++#define BMI_TOTAL_FIFO_SIZE_MASK           0x07FF0000
++#define BMI_TOTAL_NUM_OF_TASKS_MASK        0x007F0000
++
++/* shifts */
++#define BMI_CFG2_TASKS_SHIFT          16
++#define BMI_CFG2_DMAS_SHIFT           0
++#define BMI_CFG1_FIFO_SIZE_SHIFT      16
++#define BMI_FIFO_SIZE_SHIFT           0
++#define BMI_EXTRA_FIFO_SIZE_SHIFT     16
++#define BMI_NUM_OF_TASKS_SHIFT                24
++#define BMI_EXTRA_NUM_OF_TASKS_SHIFT  16
++#define BMI_NUM_OF_DMAS_SHIFT         8
++#define BMI_EXTRA_NUM_OF_DMAS_SHIFT   0
++
++/* others */
++#define BMI_FIFO_ALIGN                        0x100
++#define FMAN_BMI_FIFO_UNITS           0x100
++
++
++/**************************************************************************//**
++ @Description       QMI defines
++*//***************************************************************************/
++/* masks */
++#define QMI_CFG_ENQ_EN                        0x80000000
++#define QMI_CFG_DEQ_EN                        0x40000000
++#define QMI_CFG_EN_COUNTERS           0x10000000
++#define QMI_CFG_SOFT_RESET            0x01000000
++#define QMI_CFG_DEQ_MASK              0x0000003F
++#define QMI_CFG_ENQ_MASK              0x00003F00
++
++#define QMI_ERR_INTR_EN_DOUBLE_ECC    0x80000000
++#define QMI_ERR_INTR_EN_DEQ_FROM_DEF  0x40000000
++#define QMI_INTR_EN_SINGLE_ECC                0x80000000
++
++/* shifts */
++#define QMI_CFG_ENQ_SHIFT             8
++#define QMI_TAPC_TAP                  22
++
++#define QMI_GS_HALT_NOT_BUSY            0x00000002
++
++/**************************************************************************//**
++ @Description       IRAM defines
++*//***************************************************************************/
++/* masks */
++#define IRAM_IADD_AIE                 0x80000000
++#define IRAM_READY                    0x80000000
++
++uint32_t fman_get_bmi_err_event(struct fman_bmi_regs *bmi_rg);
++uint32_t fman_get_qmi_err_event(struct fman_qmi_regs *qmi_rg);
++uint32_t fman_get_dma_com_id(struct fman_dma_regs *dma_rg);
++uint64_t fman_get_dma_addr(struct fman_dma_regs *dma_rg);
++uint32_t fman_get_dma_err_event(struct fman_dma_regs *dma_rg);
++uint32_t fman_get_fpm_err_event(struct fman_fpm_regs *fpm_rg);
++uint32_t fman_get_muram_err_event(struct fman_fpm_regs *fpm_rg);
++uint32_t fman_get_iram_err_event(struct fman_fpm_regs *fpm_rg);
++uint32_t fman_get_qmi_event(struct fman_qmi_regs *qmi_rg);
++uint32_t fman_get_fpm_error_interrupts(struct fman_fpm_regs *fpm_rg);
++uint32_t fman_get_ctrl_intr(struct fman_fpm_regs *fpm_rg,
++                              uint8_t event_reg_id);
++uint8_t fman_get_qmi_deq_th(struct fman_qmi_regs *qmi_rg);
++uint8_t fman_get_qmi_enq_th(struct fman_qmi_regs *qmi_rg);
++uint16_t fman_get_size_of_fifo(struct fman_bmi_regs *bmi_rg, uint8_t port_id);
++uint32_t fman_get_total_fifo_size(struct fman_bmi_regs *bmi_rg);
++uint16_t fman_get_size_of_extra_fifo(struct fman_bmi_regs *bmi_rg,
++                              uint8_t port_id);
++uint8_t fman_get_num_of_tasks(struct fman_bmi_regs *bmi_rg, uint8_t port_id);
++uint8_t fman_get_num_extra_tasks(struct fman_bmi_regs *bmi_rg,
++                              uint8_t port_id);
++uint8_t fman_get_num_of_dmas(struct fman_bmi_regs *bmi_rg, uint8_t port_id);
++uint8_t fman_get_num_extra_dmas(struct fman_bmi_regs *bmi_rg,
++                              uint8_t port_id);
++uint32_t fman_get_normal_pending(struct fman_fpm_regs *fpm_rg);
++uint32_t fman_get_controller_event(struct fman_fpm_regs *fpm_rg,
++                                      uint8_t reg_id);
++uint32_t fman_get_error_pending(struct fman_fpm_regs *fpm_rg);
++void fman_get_revision(struct fman_fpm_regs *fpm_rg, uint8_t *major,
++                              uint8_t *minor);
++uint32_t fman_get_counter(struct fman_rg *fman_rg,
++                              enum fman_counters reg_name);
++uint32_t fman_get_dma_status(struct fman_dma_regs *dma_rg);
++
++
++int fman_set_erratum_10gmac_a004_wa(struct fman_fpm_regs *fpm_rg);
++void fman_set_ctrl_intr(struct fman_fpm_regs *fpm_rg, uint8_t event_reg_id,
++                              uint32_t enable_events);
++void fman_set_num_of_riscs_per_port(struct fman_fpm_regs *fpm_rg,
++                              uint8_t port_id,
++                              uint8_t num_fman_ctrls,
++                              uint32_t or_fman_ctrl);
++void fman_set_order_restoration_per_port(struct fman_fpm_regs *fpm_rg,
++                              uint8_t port_id,
++                              bool independent_mode,
++                              bool is_rx_port);
++void fman_set_qmi_enq_th(struct fman_qmi_regs *qmi_rg, uint8_t val);
++void fman_set_qmi_deq_th(struct fman_qmi_regs *qmi_rg, uint8_t val);
++void fman_set_liodn_per_port(struct fman_rg *fman_rg,
++                              uint8_t port_id,
++                              uint16_t liodn_base,
++                              uint16_t liodn_offset);
++void fman_set_size_of_fifo(struct fman_bmi_regs *bmi_rg,
++                              uint8_t port_id,
++                              uint32_t size_of_fifo,
++                              uint32_t extra_size_of_fifo);
++void fman_set_num_of_tasks(struct fman_bmi_regs *bmi_rg,
++                              uint8_t port_id,
++                              uint8_t num_of_tasks,
++                              uint8_t num_of_extra_tasks);
++void fman_set_num_of_open_dmas(struct fman_bmi_regs *bmi_rg,
++                              uint8_t port_id,
++                              uint8_t num_of_open_dmas,
++                              uint8_t num_of_extra_open_dmas,
++                              uint8_t total_num_of_dmas);
++void fman_set_ports_bandwidth(struct fman_bmi_regs *bmi_rg, uint8_t *weights);
++int fman_set_exception(struct fman_rg *fman_rg,
++                              enum fman_exceptions exception,
++                              bool enable);
++void fman_set_dma_emergency(struct fman_dma_regs *dma_rg, bool is_write,
++                              bool enable);
++void fman_set_dma_ext_bus_pri(struct fman_dma_regs *dma_rg, uint32_t pri);
++void fman_set_congestion_group_pfc_priority(uint32_t *cpg_rg,
++                                            uint32_t congestion_group_id,
++                                            uint8_t piority_bit_map,
++                                            uint32_t reg_num);
++
++
++void fman_defconfig(struct fman_cfg *cfg, bool is_master);
++void fman_regconfig(struct fman_rg *fman_rg, struct fman_cfg *cfg);
++int fman_fpm_init(struct fman_fpm_regs *fpm_rg, struct fman_cfg *cfg);
++int fman_bmi_init(struct fman_bmi_regs *bmi_rg, struct fman_cfg *cfg);
++int fman_qmi_init(struct fman_qmi_regs *qmi_rg, struct fman_cfg *cfg);
++int fman_dma_init(struct fman_dma_regs *dma_rg, struct fman_cfg *cfg);
++void fman_free_resources(struct fman_rg *fman_rg);
++int fman_enable(struct fman_rg *fman_rg, struct fman_cfg *cfg);
++void fman_reset(struct fman_fpm_regs *fpm_rg);
++void fman_resume(struct fman_fpm_regs *fpm_rg);
++
++
++void fman_enable_time_stamp(struct fman_fpm_regs *fpm_rg,
++                              uint8_t count1ubit,
++                              uint16_t fm_clk_freq);
++void fman_enable_rams_ecc(struct fman_fpm_regs *fpm_rg);
++void fman_qmi_disable_dispatch_limit(struct fman_fpm_regs *fpm_rg);
++void fman_disable_rams_ecc(struct fman_fpm_regs *fpm_rg);
++void fman_resume_stalled_port(struct fman_fpm_regs *fpm_rg, uint8_t port_id);
++int fman_reset_mac(struct fman_fpm_regs *fpm_rg, uint8_t macId, bool is_10g);
++bool fman_is_port_stalled(struct fman_fpm_regs *fpm_rg, uint8_t port_id);
++bool fman_rams_ecc_is_external_ctl(struct fman_fpm_regs *fpm_rg);
++bool fman_is_qmi_halt_not_busy_state(struct fman_qmi_regs *qmi_rg);
++int fman_modify_counter(struct fman_rg *fman_rg,
++                              enum fman_counters reg_name,
++                              uint32_t val);
++void fman_force_intr(struct fman_rg *fman_rg,
++                              enum fman_exceptions exception);
++void fman_set_vsp_window(struct fman_bmi_regs *bmi_rg,
++                                   uint8_t port_id,
++                                       uint8_t base_storage_profile,
++                                       uint8_t log2_num_of_profiles);
++
++/**************************************************************************//**
++ @Description       default values
++*//***************************************************************************/
++#define DEFAULT_CATASTROPHIC_ERR                E_FMAN_CATAST_ERR_STALL_PORT
++#define DEFAULT_DMA_ERR                         E_FMAN_DMA_ERR_CATASTROPHIC
++#define DEFAULT_HALT_ON_EXTERNAL_ACTIVATION     FALSE   /* do not change! if changed, must be disabled for rev1 ! */
++#define DEFAULT_HALT_ON_UNRECOVERABLE_ECC_ERROR FALSE   /* do not change! if changed, must be disabled for rev1 ! */
++#define DEFAULT_EXTERNAL_ECC_RAMS_ENABLE        FALSE
++#define DEFAULT_AID_OVERRIDE                    FALSE
++#define DEFAULT_AID_MODE                        E_FMAN_DMA_AID_OUT_TNUM
++#define DEFAULT_DMA_COMM_Q_LOW                  0x2A
++#define DEFAULT_DMA_COMM_Q_HIGH                 0x3F
++#define DEFAULT_CACHE_OVERRIDE                  E_FMAN_DMA_NO_CACHE_OR
++#define DEFAULT_DMA_CAM_NUM_OF_ENTRIES          64
++#define DEFAULT_DMA_DBG_CNT_MODE                E_FMAN_DMA_DBG_NO_CNT
++#define DEFAULT_DMA_EN_EMERGENCY                FALSE
++#define DEFAULT_DMA_SOS_EMERGENCY               0
++#define DEFAULT_DMA_WATCHDOG                    0 /* disabled */
++#define DEFAULT_DMA_EN_EMERGENCY_SMOOTHER       FALSE
++#define DEFAULT_DMA_EMERGENCY_SWITCH_COUNTER    0
++#define DEFAULT_DISP_LIMIT                      0
++#define DEFAULT_PRS_DISP_TH                     16
++#define DEFAULT_PLCR_DISP_TH                    16
++#define DEFAULT_KG_DISP_TH                      16
++#define DEFAULT_BMI_DISP_TH                     16
++#define DEFAULT_QMI_ENQ_DISP_TH                 16
++#define DEFAULT_QMI_DEQ_DISP_TH                 16
++#define DEFAULT_FM_CTL1_DISP_TH                 16
++#define DEFAULT_FM_CTL2_DISP_TH                 16
++#define DEFAULT_TNUM_AGING_PERIOD               4
++
++
++#endif /* __FSL_FMAN_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec.h
+@@ -0,0 +1,1096 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __FSL_FMAN_DTSEC_H
++#define __FSL_FMAN_DTSEC_H
++
++#include "common/general.h"
++#include "fsl_enet.h"
++
++/**
++ * DOC: dTSEC Init sequence
++ *
++ * To prepare dTSEC block for transfer use the following call sequence:
++ *
++ * - fman_dtsec_defconfig() - This step is optional and yet recommended. Its
++ * use is to obtain the default dTSEC configuration parameters.
++ *
++ * - Change dtsec configuration in &dtsec_cfg. This structure will be used
++ * to customize the dTSEC behavior.
++ *
++ * - fman_dtsec_init() - Applies the configuration on dTSEC hardware.  Note that
++ * dTSEC is initialized while both Tx and Rx are disabled.
++ *
++ * - fman_dtsec_set_mac_address() - Set the station address (mac address).
++ * This is used by dTSEC to match against received packets.
++ *
++ * - fman_dtsec_adjust_link() - Set the link speed and duplex parameters
++ * after the PHY establishes the link.
++ *
++ * - dtsec_enable_tx() and dtsec_enable_rx() to enable transmission and
++ * reception.
++ */
++
++/**
++ * DOC: dTSEC Graceful stop
++ *
++ * To temporary stop dTSEC activity use fman_dtsec_stop_tx() and
++ * fman_dtsec_stop_rx(). Note that these functions request dTSEC graceful stop
++ * but return before this stop is complete.  To query for graceful stop
++ * completion use fman_dtsec_get_event() and check DTSEC_IEVENT_GTSC and
++ * DTSEC_IEVENT_GRSC bits. Alternatively the dTSEC interrupt mask can be set to
++ * enable graceful stop interrupts.
++ *
++ * To resume operation after graceful stop use fman_dtsec_start_tx() and
++ * fman_dtsec_start_rx().
++ */
++
++/**
++ * DOC: dTSEC interrupt handling
++ *
++ * This code does not provide an interrupt handler for dTSEC.  Instead this
++ * handler should be implemented and registered to the operating system by the
++ * caller.  Some primitives for accessing the event status and mask registers
++ * are provided.
++ *
++ * See "dTSEC Events" section for a list of events that dTSEC can generate.
++ */
++
++/**
++ * DOC: dTSEC Events
++ *
++ * Interrupt events cause dTSEC event bits to be set.  Software may poll the
++ * event register at any time to check for pending interrupts.  If an event
++ * occurs and its corresponding enable bit is set in the interrupt mask
++ * register, the event also causes a hardware interrupt at the PIC.
++ *
++ * To poll for event status use the fman_dtsec_get_event() function.
++ * To configure the interrupt mask use fman_dtsec_enable_interrupt() and
++ * fman_dtsec_disable_interrupt() functions.
++ * After servicing a dTSEC interrupt use fman_dtsec_ack_event to reset the
++ * serviced event bit.
++ *
++ * The following events may be signaled by dTSEC hardware:
++ *
++ * %DTSEC_IEVENT_BABR - Babbling receive error.  This bit indicates that
++ * a frame was received with length in excess of the MAC's maximum frame length
++ * register.
++ *
++ * %DTSEC_IEVENT_RXC - Receive control (pause frame) interrupt.  A pause
++ * control frame was received while Rx pause frame handling is enabled.
++ * Also see fman_dtsec_handle_rx_pause().
++ *
++ * %DTSEC_IEVENT_MSRO - MIB counter overflow.  The count for one of the MIB
++ * counters has exceeded the size of its register.
++ *
++ * %DTSEC_IEVENT_GTSC - Graceful transmit stop complete.  Graceful stop is now
++ * complete. The transmitter is in a stopped state, in which only pause frames
++ * can be transmitted.
++ * Also see fman_dtsec_stop_tx().
++ *
++ * %DTSEC_IEVENT_BABT - Babbling transmit error.  The transmitted frame length
++ * has exceeded the value in the MAC's Maximum Frame Length register.
++ *
++ * %DTSEC_IEVENT_TXC - Transmit control (pause frame) interrupt.  his bit
++ * indicates that a control frame was transmitted.
++ *
++ * %DTSEC_IEVENT_TXE - Transmit error.  This bit indicates that an error
++ * occurred on the transmitted channel.  This bit is set whenever any transmit
++ * error occurs which causes the dTSEC to discard all or part of a frame
++ * (LC, CRL, XFUN).
++ *
++ * %DTSEC_IEVENT_LC - Late collision.  This bit indicates that a collision
++ * occurred beyond the collision window (slot time) in half-duplex mode.
++ * The frame is truncated with a bad CRC and the remainder of the frame
++ * is discarded.
++ *
++ * %DTSEC_IEVENT_CRL - Collision retry limit.  is bit indicates that the number
++ * of successive transmission collisions has exceeded the MAC's half-duplex
++ * register's retransmission maximum count.  The frame is discarded without
++ * being transmitted and transmission of the next frame commences.  This only
++ * occurs while in half-duplex mode.
++ * The number of retransmit attempts can be set in
++ * &dtsec_halfdup_cfg.@retransmit before calling fman_dtsec_init().
++ *
++ * %DTSEC_IEVENT_XFUN - Transmit FIFO underrun.  This bit indicates that the
++ * transmit FIFO became empty before the complete frame was transmitted.
++ * The frame is truncated with a bad CRC and the remainder of the frame is
++ * discarded.
++ *
++ * %DTSEC_IEVENT_MAG - TBD
++ *
++ * %DTSEC_IEVENT_MMRD - MII management read completion.
++ *
++ * %DTSEC_IEVENT_MMWR - MII management write completion.
++ *
++ * %DTSEC_IEVENT_GRSC - Graceful receive stop complete.  It allows the user to
++ * know if the system has completed the stop and it is safe to write to receive
++ * registers (status, control or configuration registers) that are used by the
++ * system during normal operation.
++ *
++ * %DTSEC_IEVENT_TDPE - Internal data error on transmit.  This bit indicates
++ * that the dTSEC has detected a parity error on its stored transmit data, which
++ * is likely to compromise the validity of recently transferred frames.
++ *
++ * %DTSEC_IEVENT_RDPE - Internal data error on receive.  This bit indicates that
++ * the dTSEC has detected a parity error on its stored receive data, which is
++ * likely to compromise the validity of recently transferred frames.
++ */
++/* Interrupt Mask Register (IMASK) */
++#define DTSEC_IMASK_BREN      0x80000000
++#define DTSEC_IMASK_RXCEN     0x40000000
++#define DTSEC_IMASK_MSROEN    0x04000000
++#define DTSEC_IMASK_GTSCEN    0x02000000
++#define DTSEC_IMASK_BTEN      0x01000000
++#define DTSEC_IMASK_TXCEN     0x00800000
++#define DTSEC_IMASK_TXEEN     0x00400000
++#define DTSEC_IMASK_LCEN      0x00040000
++#define DTSEC_IMASK_CRLEN     0x00020000
++#define DTSEC_IMASK_XFUNEN    0x00010000
++#define DTSEC_IMASK_ABRTEN    0x00008000
++#define DTSEC_IMASK_IFERREN   0x00004000
++#define DTSEC_IMASK_MAGEN     0x00000800
++#define DTSEC_IMASK_MMRDEN    0x00000400
++#define DTSEC_IMASK_MMWREN    0x00000200
++#define DTSEC_IMASK_GRSCEN    0x00000100
++#define DTSEC_IMASK_TDPEEN    0x00000002
++#define DTSEC_IMASK_RDPEEN    0x00000001
++
++#define DTSEC_EVENTS_MASK                                     \
++      ((uint32_t)(DTSEC_IMASK_BREN    | \
++                              DTSEC_IMASK_RXCEN   | \
++                              DTSEC_IMASK_BTEN    | \
++                              DTSEC_IMASK_TXCEN   | \
++                              DTSEC_IMASK_TXEEN   | \
++                              DTSEC_IMASK_ABRTEN  | \
++                              DTSEC_IMASK_LCEN    | \
++                              DTSEC_IMASK_CRLEN   | \
++                              DTSEC_IMASK_XFUNEN  | \
++                              DTSEC_IMASK_IFERREN | \
++                              DTSEC_IMASK_MAGEN   | \
++                              DTSEC_IMASK_TDPEEN  | \
++                              DTSEC_IMASK_RDPEEN))
++
++/* dtsec timestamp event bits */
++#define TMR_PEMASK_TSREEN     0x00010000
++#define TMR_PEVENT_TSRE               0x00010000
++
++/* Group address bit indication */
++#define MAC_GROUP_ADDRESS     0x0000010000000000ULL
++/* size in bytes of L2 address */
++#define MAC_ADDRLEN           6
++
++#define DEFAULT_HALFDUP_ON            FALSE
++#define DEFAULT_HALFDUP_RETRANSMIT    0xf
++#define DEFAULT_HALFDUP_COLL_WINDOW   0x37
++#define DEFAULT_HALFDUP_EXCESS_DEFER  TRUE
++#define DEFAULT_HALFDUP_NO_BACKOFF    FALSE
++#define DEFAULT_HALFDUP_BP_NO_BACKOFF FALSE
++#define DEFAULT_HALFDUP_ALT_BACKOFF_VAL       0x0A
++#define DEFAULT_HALFDUP_ALT_BACKOFF_EN        FALSE
++#define DEFAULT_RX_DROP_BCAST         FALSE
++#define DEFAULT_RX_SHORT_FRM          TRUE
++#define DEFAULT_RX_LEN_CHECK          FALSE
++#define DEFAULT_TX_PAD_CRC            TRUE
++#define DEFAULT_TX_CRC                        FALSE
++#define DEFAULT_RX_CTRL_ACC           FALSE
++#define DEFAULT_TX_PAUSE_TIME         0xf000
++#define DEFAULT_TBIPA                 5
++#define DEFAULT_RX_PREPEND            0
++#define DEFAULT_PTP_TSU_EN            TRUE
++#define DEFAULT_PTP_EXCEPTION_EN      TRUE
++#define DEFAULT_PREAMBLE_LEN          7
++#define DEFAULT_RX_PREAMBLE           FALSE
++#define DEFAULT_TX_PREAMBLE           FALSE
++#define DEFAULT_LOOPBACK              FALSE
++#define DEFAULT_RX_TIME_STAMP_EN      FALSE
++#define DEFAULT_TX_TIME_STAMP_EN      FALSE
++#define DEFAULT_RX_FLOW                       TRUE
++#define DEFAULT_TX_FLOW                       TRUE
++#define DEFAULT_RX_GROUP_HASH_EXD     FALSE
++#define DEFAULT_TX_PAUSE_TIME_EXTD    0
++#define DEFAULT_RX_PROMISC            FALSE
++#define DEFAULT_NON_BACK_TO_BACK_IPG1 0x40
++#define DEFAULT_NON_BACK_TO_BACK_IPG2 0x60
++#define DEFAULT_MIN_IFG_ENFORCEMENT   0x50
++#define DEFAULT_BACK_TO_BACK_IPG      0x60
++#define DEFAULT_MAXIMUM_FRAME         0x600
++#define DEFAULT_TBI_PHY_ADDR          5
++#define DEFAULT_WAKE_ON_LAN                   FALSE
++
++/* register related defines (bits, field offsets..) */
++#define DTSEC_ID1_ID                  0xffff0000
++#define DTSEC_ID1_REV_MJ              0x0000FF00
++#define DTSEC_ID1_REV_MN              0x000000ff
++
++#define DTSEC_ID2_INT_REDUCED_OFF     0x00010000
++#define DTSEC_ID2_INT_NORMAL_OFF      0x00020000
++
++#define DTSEC_ECNTRL_CLRCNT           0x00004000
++#define DTSEC_ECNTRL_AUTOZ            0x00002000
++#define DTSEC_ECNTRL_STEN             0x00001000
++#define DTSEC_ECNTRL_CFG_RO           0x80000000
++#define DTSEC_ECNTRL_GMIIM            0x00000040
++#define DTSEC_ECNTRL_TBIM             0x00000020
++#define DTSEC_ECNTRL_SGMIIM           0x00000002
++#define DTSEC_ECNTRL_RPM              0x00000010
++#define DTSEC_ECNTRL_R100M            0x00000008
++#define DTSEC_ECNTRL_RMM              0x00000004
++#define DTSEC_ECNTRL_QSGMIIM          0x00000001
++
++#define DTSEC_TCTRL_THDF              0x00000800
++#define DTSEC_TCTRL_TTSE              0x00000040
++#define DTSEC_TCTRL_GTS                       0x00000020
++#define DTSEC_TCTRL_TFC_PAUSE         0x00000010
++
++/* PTV offsets */
++#define PTV_PTE_OFST          16
++
++#define RCTRL_CFA             0x00008000
++#define RCTRL_GHTX            0x00000400
++#define RCTRL_RTSE            0x00000040
++#define RCTRL_GRS             0x00000020
++#define RCTRL_BC_REJ          0x00000010
++#define RCTRL_MPROM           0x00000008
++#define RCTRL_RSF             0x00000004
++#define RCTRL_UPROM           0x00000001
++#define RCTRL_PROM            (RCTRL_UPROM | RCTRL_MPROM)
++
++#define TMR_CTL_ESFDP         0x00000800
++#define TMR_CTL_ESFDE         0x00000400
++
++#define MACCFG1_SOFT_RESET    0x80000000
++#define MACCFG1_LOOPBACK      0x00000100
++#define MACCFG1_RX_FLOW               0x00000020
++#define MACCFG1_TX_FLOW               0x00000010
++#define MACCFG1_TX_EN         0x00000001
++#define MACCFG1_RX_EN         0x00000004
++#define MACCFG1_RESET_RxMC    0x00080000
++#define MACCFG1_RESET_TxMC    0x00040000
++#define MACCFG1_RESET_RxFUN   0x00020000
++#define MACCFG1_RESET_TxFUN   0x00010000
++
++#define MACCFG2_NIBBLE_MODE   0x00000100
++#define MACCFG2_BYTE_MODE     0x00000200
++#define MACCFG2_PRE_AM_Rx_EN  0x00000080
++#define MACCFG2_PRE_AM_Tx_EN  0x00000040
++#define MACCFG2_LENGTH_CHECK  0x00000010
++#define MACCFG2_MAGIC_PACKET_EN       0x00000008
++#define MACCFG2_PAD_CRC_EN    0x00000004
++#define MACCFG2_CRC_EN                0x00000002
++#define MACCFG2_FULL_DUPLEX   0x00000001
++
++#define PREAMBLE_LENGTH_SHIFT 12
++
++#define IPGIFG_NON_BACK_TO_BACK_IPG_1_SHIFT   24
++#define IPGIFG_NON_BACK_TO_BACK_IPG_2_SHIFT   16
++#define IPGIFG_MIN_IFG_ENFORCEMENT_SHIFT      8
++
++#define IPGIFG_NON_BACK_TO_BACK_IPG_1 0x7F000000
++#define IPGIFG_NON_BACK_TO_BACK_IPG_2 0x007F0000
++#define IPGIFG_MIN_IFG_ENFORCEMENT    0x0000FF00
++#define IPGIFG_BACK_TO_BACK_IPG               0x0000007F
++
++#define HAFDUP_ALT_BEB                        0x00080000
++#define HAFDUP_BP_NO_BACKOFF          0x00040000
++#define HAFDUP_NO_BACKOFF             0x00020000
++#define HAFDUP_EXCESS_DEFER           0x00010000
++#define HAFDUP_COLLISION_WINDOW               0x000003ff
++
++#define HAFDUP_ALTERNATE_BEB_TRUNCATION_SHIFT 20
++#define HAFDUP_RETRANSMISSION_MAX_SHIFT               12
++#define HAFDUP_RETRANSMISSION_MAX             0x0000f000
++
++#define NUM_OF_HASH_REGS      8 /* Number of hash table registers */
++
++/* CAR1/2 bits */
++#define DTSEC_CAR1_TR64               0x80000000
++#define DTSEC_CAR1_TR127      0x40000000
++#define DTSEC_CAR1_TR255      0x20000000
++#define DTSEC_CAR1_TR511      0x10000000
++#define DTSEC_CAR1_TRK1               0x08000000
++#define DTSEC_CAR1_TRMAX      0x04000000
++#define DTSEC_CAR1_TRMGV      0x02000000
++
++#define DTSEC_CAR1_RBYT               0x00010000
++#define DTSEC_CAR1_RPKT               0x00008000
++#define DTSEC_CAR1_RFCS               0x00004000
++#define DTSEC_CAR1_RMCA               0x00002000
++#define DTSEC_CAR1_RBCA               0x00001000
++#define DTSEC_CAR1_RXCF               0x00000800
++#define DTSEC_CAR1_RXPF               0x00000400
++#define DTSEC_CAR1_RXUO               0x00000200
++#define DTSEC_CAR1_RALN               0x00000100
++#define DTSEC_CAR1_RFLR               0x00000080
++#define DTSEC_CAR1_RCDE               0x00000040
++#define DTSEC_CAR1_RCSE               0x00000020
++#define DTSEC_CAR1_RUND               0x00000010
++#define DTSEC_CAR1_ROVR               0x00000008
++#define DTSEC_CAR1_RFRG               0x00000004
++#define DTSEC_CAR1_RJBR               0x00000002
++#define DTSEC_CAR1_RDRP               0x00000001
++
++#define DTSEC_CAR2_TJBR               0x00080000
++#define DTSEC_CAR2_TFCS               0x00040000
++#define DTSEC_CAR2_TXCF               0x00020000
++#define DTSEC_CAR2_TOVR               0x00010000
++#define DTSEC_CAR2_TUND               0x00008000
++#define DTSEC_CAR2_TFRG               0x00004000
++#define DTSEC_CAR2_TBYT               0x00002000
++#define DTSEC_CAR2_TPKT               0x00001000
++#define DTSEC_CAR2_TMCA               0x00000800
++#define DTSEC_CAR2_TBCA               0x00000400
++#define DTSEC_CAR2_TXPF               0x00000200
++#define DTSEC_CAR2_TDFR               0x00000100
++#define DTSEC_CAR2_TEDF               0x00000080
++#define DTSEC_CAR2_TSCL               0x00000040
++#define DTSEC_CAR2_TMCL               0x00000020
++#define DTSEC_CAR2_TLCL               0x00000010
++#define DTSEC_CAR2_TXCL               0x00000008
++#define DTSEC_CAR2_TNCL               0x00000004
++#define DTSEC_CAR2_TDRP               0x00000001
++
++#define CAM1_ERRORS_ONLY \
++      (DTSEC_CAR1_RXPF | DTSEC_CAR1_RALN | DTSEC_CAR1_RFLR \
++      | DTSEC_CAR1_RCDE | DTSEC_CAR1_RCSE | DTSEC_CAR1_RUND \
++      | DTSEC_CAR1_ROVR | DTSEC_CAR1_RFRG | DTSEC_CAR1_RJBR \
++      | DTSEC_CAR1_RDRP)
++
++#define CAM2_ERRORS_ONLY (DTSEC_CAR2_TFCS | DTSEC_CAR2_TXPF | DTSEC_CAR2_TDRP)
++
++/*
++ * Group of dTSEC specific counters relating to the standard RMON MIB Group 1
++ * (or Ethernet) statistics.
++ */
++#define CAM1_MIB_GRP_1 \
++      (DTSEC_CAR1_RDRP | DTSEC_CAR1_RBYT | DTSEC_CAR1_RPKT | DTSEC_CAR1_RMCA\
++      | DTSEC_CAR1_RBCA | DTSEC_CAR1_RALN | DTSEC_CAR1_RUND | DTSEC_CAR1_ROVR\
++      | DTSEC_CAR1_RFRG | DTSEC_CAR1_RJBR \
++      | DTSEC_CAR1_TR64 | DTSEC_CAR1_TR127 | DTSEC_CAR1_TR255 \
++      | DTSEC_CAR1_TR511 | DTSEC_CAR1_TRMAX)
++
++#define CAM2_MIB_GRP_1 (DTSEC_CAR2_TNCL | DTSEC_CAR2_TDRP)
++
++/* memory map */
++
++struct dtsec_regs {
++      /* dTSEC General Control and Status Registers */
++      uint32_t tsec_id;       /* 0x000 ETSEC_ID register */
++      uint32_t tsec_id2;      /* 0x004 ETSEC_ID2 register */
++      uint32_t ievent;        /* 0x008 Interrupt event register */
++      uint32_t imask;         /* 0x00C Interrupt mask register */
++      uint32_t reserved0010[1];
++      uint32_t ecntrl;        /* 0x014 E control register */
++      uint32_t ptv;           /* 0x018 Pause time value register */
++      uint32_t tbipa;         /* 0x01C TBI PHY address register */
++      uint32_t tmr_ctrl;      /* 0x020 Time-stamp Control register */
++      uint32_t tmr_pevent;    /* 0x024 Time-stamp event register */
++      uint32_t tmr_pemask;    /* 0x028 Timer event mask register */
++      uint32_t reserved002c[5];
++      uint32_t tctrl;         /* 0x040 Transmit control register */
++      uint32_t reserved0044[3];
++      uint32_t rctrl;         /* 0x050 Receive control register */
++      uint32_t reserved0054[11];
++      uint32_t igaddr[8];     /* 0x080-0x09C Individual/group address */
++      uint32_t gaddr[8];      /* 0x0A0-0x0BC Group address registers 0-7 */
++      uint32_t reserved00c0[16];
++      uint32_t maccfg1;               /* 0x100 MAC configuration #1 */
++      uint32_t maccfg2;               /* 0x104 MAC configuration #2 */
++      uint32_t ipgifg;                /* 0x108 IPG/IFG */
++      uint32_t hafdup;                /* 0x10C Half-duplex */
++      uint32_t maxfrm;                /* 0x110 Maximum frame */
++      uint32_t reserved0114[10];
++      uint32_t ifstat;                /* 0x13C Interface status */
++      uint32_t macstnaddr1;           /* 0x140 Station Address,part 1 */
++      uint32_t macstnaddr2;           /* 0x144 Station Address,part 2  */
++      struct {
++          uint32_t exact_match1; /* octets 1-4 */
++          uint32_t exact_match2; /* octets 5-6 */
++      } macaddr[15];  /* 0x148-0x1BC mac exact match addresses 1-15 */
++      uint32_t reserved01c0[16];
++      uint32_t tr64;  /* 0x200 transmit and receive 64 byte frame counter */
++      uint32_t tr127; /* 0x204 transmit and receive 65 to 127 byte frame
++                       * counter */
++      uint32_t tr255; /* 0x208 transmit and receive 128 to 255 byte frame
++                       * counter */
++      uint32_t tr511; /* 0x20C transmit and receive 256 to 511 byte frame
++                       * counter */
++      uint32_t tr1k;  /* 0x210 transmit and receive 512 to 1023 byte frame
++                       * counter */
++      uint32_t trmax; /* 0x214 transmit and receive 1024 to 1518 byte frame
++                       * counter */
++      uint32_t trmgv; /* 0x218 transmit and receive 1519 to 1522 byte good
++                       * VLAN frame count */
++      uint32_t rbyt;  /* 0x21C receive byte counter */
++      uint32_t rpkt;  /* 0x220 receive packet counter */
++      uint32_t rfcs;  /* 0x224 receive FCS error counter */
++      uint32_t rmca;  /* 0x228 RMCA receive multicast packet counter */
++      uint32_t rbca;  /* 0x22C receive broadcast packet counter */
++      uint32_t rxcf;  /* 0x230 receive control frame packet counter */
++      uint32_t rxpf;  /* 0x234 receive pause frame packet counter */
++      uint32_t rxuo;  /* 0x238 receive unknown OP code counter */
++      uint32_t raln;  /* 0x23C receive alignment error counter */
++      uint32_t rflr;  /* 0x240 receive frame length error counter */
++      uint32_t rcde;  /* 0x244 receive code error counter */
++      uint32_t rcse;  /* 0x248 receive carrier sense error counter */
++      uint32_t rund;  /* 0x24C receive undersize packet counter */
++      uint32_t rovr;  /* 0x250 receive oversize packet counter */
++      uint32_t rfrg;  /* 0x254 receive fragments counter */
++      uint32_t rjbr;  /* 0x258 receive jabber counter */
++      uint32_t rdrp;  /* 0x25C receive drop */
++      uint32_t tbyt;  /* 0x260 transmit byte counter */
++      uint32_t tpkt;  /* 0x264 transmit packet counter */
++      uint32_t tmca;  /* 0x268 transmit multicast packet counter */
++      uint32_t tbca;  /* 0x26C transmit broadcast packet counter */
++      uint32_t txpf;  /* 0x270 transmit pause control frame counter */
++      uint32_t tdfr;  /* 0x274 transmit deferral packet counter */
++      uint32_t tedf;  /* 0x278 transmit excessive deferral packet counter */
++      uint32_t tscl;  /* 0x27C transmit single collision packet counter */
++      uint32_t tmcl;  /* 0x280 transmit multiple collision packet counter */
++      uint32_t tlcl;  /* 0x284 transmit late collision packet counter */
++      uint32_t txcl;  /* 0x288 transmit excessive collision packet counter */
++      uint32_t tncl;  /* 0x28C transmit total collision counter */
++      uint32_t reserved0290[1];
++      uint32_t tdrp;  /* 0x294 transmit drop frame counter */
++      uint32_t tjbr;  /* 0x298 transmit jabber frame counter */
++      uint32_t tfcs;  /* 0x29C transmit FCS error counter */
++      uint32_t txcf;  /* 0x2A0 transmit control frame counter */
++      uint32_t tovr;  /* 0x2A4 transmit oversize frame counter */
++      uint32_t tund;  /* 0x2A8 transmit undersize frame counter */
++      uint32_t tfrg;  /* 0x2AC transmit fragments frame counter */
++      uint32_t car1;  /* 0x2B0 carry register one register* */
++      uint32_t car2;  /* 0x2B4 carry register two register* */
++      uint32_t cam1;  /* 0x2B8 carry register one mask register */
++      uint32_t cam2;  /* 0x2BC carry register two mask register */
++      uint32_t reserved02c0[848];
++};
++
++/**
++ * struct dtsec_mib_grp_1_counters - MIB counter overflows
++ *
++ * @tr64:     Transmit and Receive 64 byte frame count.  Increment for each
++ *            good or bad frame, of any type, transmitted or received, which
++ *            is 64 bytes in length.
++ * @tr127:    Transmit and Receive 65 to 127 byte frame count.  Increments for
++ *            each good or bad frame of any type, transmitted or received,
++ *            which is 65-127 bytes in length.
++ * @tr255:    Transmit and Receive 128 to 255 byte frame count.  Increments
++ *            for each good or bad frame, of any type, transmitted or
++ *            received, which is 128-255 bytes in length.
++ * @tr511:    Transmit and Receive 256 to 511 byte frame count.  Increments
++ *            for each good or bad frame, of any type, transmitted or
++ *            received, which is 256-511 bytes in length.
++ * @tr1k:     Transmit and Receive 512 to 1023 byte frame count.  Increments
++ *            for each good or bad frame, of any type, transmitted or
++ *            received, which is 512-1023 bytes in length.
++ * @trmax:    Transmit and Receive 1024 to 1518 byte frame count.  Increments
++ *            for each good or bad frame, of any type, transmitted or
++ *            received, which is 1024-1518 bytes in length.
++ * @rfrg:     Receive fragments count.  Increments for each received frame
++ *            which is less than 64 bytes in length and contains an invalid
++ *            FCS.  This includes integral and non-integral lengths.
++ * @rjbr:     Receive jabber count.  Increments for received frames which
++ *            exceed 1518 (non VLAN) or 1522 (VLAN) bytes and contain an
++ *            invalid FCS.  This includes alignment errors.
++ * @rdrp:     Receive dropped packets count.  Increments for received frames
++ *            which are streamed to system but are later dropped due to lack
++ *            of system resources.  Does not increment for frames rejected due
++ *            to address filtering.
++ * @raln:     Receive alignment error count.  Increments for each received
++ *            frame from 64 to 1518 (non VLAN) or 1522 (VLAN) which contains
++ *            an invalid FCS and is not an integral number of bytes.
++ * @rund:     Receive undersize packet count.  Increments each time a frame is
++ *            received which is less than 64 bytes in length and contains a
++ *            valid FCS and is otherwise well formed.  This count does not
++ *            include range length errors.
++ * @rovr:     Receive oversize packet count.  Increments each time a frame is
++ *            received which exceeded 1518 (non VLAN) or 1522 (VLAN) and
++ *            contains a valid FCS and is otherwise well formed.
++ * @rbyt:     Receive byte count.  Increments by the byte count of frames
++ *            received, including those in bad packets, excluding preamble and
++ *            SFD but including FCS bytes.
++ * @rpkt:     Receive packet count.  Increments for each received frame
++ *            (including bad packets, all unicast, broadcast, and multicast
++ *            packets).
++ * @rmca:     Receive multicast packet count.  Increments for each multicast
++ *            frame with valid CRC and of lengths 64 to 1518 (non VLAN) or
++ *            1522 (VLAN), excluding broadcast frames. This count does not
++ *            include range/length errors.
++ * @rbca:     Receive broadcast packet count.  Increments for each broadcast
++ *            frame with valid CRC and of lengths 64 to 1518 (non VLAN) or
++ *            1522 (VLAN), excluding multicast frames. Does not include
++ *            range/length errors.
++ * @tdrp:     Transmit drop frame count.  Increments each time a memory error
++ *            or an underrun has occurred.
++ * @tncl:     Transmit total collision counter. Increments by the number of
++ *            collisions experienced during the transmission of a frame. Does
++ *            not increment for aborted frames.
++ *
++ * The structure contains a group of dTSEC HW specific counters relating to the
++ * standard RMON MIB Group 1 (or Ethernet statistics) counters.  This structure
++ * is counting only the carry events of the corresponding HW counters.
++ *
++ * tr64 to trmax notes: Frame sizes specified are considered excluding preamble
++ * and SFD but including FCS bytes.
++ */
++struct dtsec_mib_grp_1_counters {
++      uint64_t        rdrp;
++      uint64_t        tdrp;
++      uint64_t        rbyt;
++      uint64_t        rpkt;
++      uint64_t        rbca;
++      uint64_t        rmca;
++      uint64_t        raln;
++      uint64_t        rund;
++      uint64_t        rovr;
++      uint64_t        rfrg;
++      uint64_t        rjbr;
++      uint64_t        tncl;
++      uint64_t        tr64;
++      uint64_t        tr127;
++      uint64_t        tr255;
++      uint64_t        tr511;
++      uint64_t        tr1k;
++      uint64_t        trmax;
++};
++
++enum dtsec_stat_counters {
++      E_DTSEC_STAT_TR64,
++      E_DTSEC_STAT_TR127,
++      E_DTSEC_STAT_TR255,
++      E_DTSEC_STAT_TR511,
++      E_DTSEC_STAT_TR1K,
++      E_DTSEC_STAT_TRMAX,
++      E_DTSEC_STAT_TRMGV,
++      E_DTSEC_STAT_RBYT,
++      E_DTSEC_STAT_RPKT,
++      E_DTSEC_STAT_RMCA,
++      E_DTSEC_STAT_RBCA,
++      E_DTSEC_STAT_RXPF,
++      E_DTSEC_STAT_RALN,
++      E_DTSEC_STAT_RFLR,
++      E_DTSEC_STAT_RCDE,
++      E_DTSEC_STAT_RCSE,
++      E_DTSEC_STAT_RUND,
++      E_DTSEC_STAT_ROVR,
++      E_DTSEC_STAT_RFRG,
++      E_DTSEC_STAT_RJBR,
++      E_DTSEC_STAT_RDRP,
++      E_DTSEC_STAT_TFCS,
++      E_DTSEC_STAT_TBYT,
++      E_DTSEC_STAT_TPKT,
++      E_DTSEC_STAT_TMCA,
++      E_DTSEC_STAT_TBCA,
++      E_DTSEC_STAT_TXPF,
++      E_DTSEC_STAT_TNCL,
++      E_DTSEC_STAT_TDRP
++};
++
++enum dtsec_stat_level {
++      /* No statistics */
++      E_MAC_STAT_NONE = 0,
++      /* Only RMON MIB group 1 (ether stats). Optimized for performance */
++      E_MAC_STAT_MIB_GRP1,
++      /* Only error counters are available. Optimized for performance */
++      E_MAC_STAT_PARTIAL,
++      /* All counters available. Not optimized for performance */
++      E_MAC_STAT_FULL
++};
++
++
++/**
++ * struct dtsec_cfg - dTSEC configuration
++ *
++ * @halfdup_on:               Transmit half-duplex flow control, under software
++ *                    control for 10/100-Mbps half-duplex media. If set,
++ *                    back pressure is applied to media by raising carrier.
++ * @halfdup_retransmit:       Number of retransmission attempts following a collision.
++ *                    If this is exceeded dTSEC aborts transmission due to
++ *                    excessive collisions. The standard specifies the
++ *                    attempt limit to be 15.
++ * @halfdup_coll_window:The number of bytes of the frame during which
++ *                    collisions may occur. The default value of 55
++ *                    corresponds to the frame byte at the end of the
++ *                    standard 512-bit slot time window. If collisions are
++ *                    detected after this byte, the late collision event is
++ *                    asserted and transmission of current frame is aborted.
++ * @rx_drop_bcast:    Discard broadcast frames.  If set, all broadcast frames
++ *                    will be discarded by dTSEC.
++ * @rx_short_frm:     Accept short frames.  If set, dTSEC will accept frames
++ *                    of length 14..63 bytes.
++ * @rx_len_check:     Length check for received frames.  If set, the MAC
++ *                    checks the frame's length field on receive to ensure it
++ *                    matches the actual data field length. This only works
++ *                    for received frames with length field less than 1500.
++ *                    No check is performed for larger frames.
++ * @tx_pad_crc:               Pad and append CRC.  If set, the MAC pads all
++ *                    transmitted short frames and appends a CRC to every
++ *                    frame regardless of padding requirement.
++ * @tx_crc:           Transmission CRC enable.  If set, the MAC appends a CRC
++ *                    to all frames.  If frames presented to the MAC have a
++ *                    valid length and contain a valid CRC, @tx_crc should be
++ *                    reset.
++ *                    This field is ignored if @tx_pad_crc is set.
++ * @rx_ctrl_acc:      Control frame accept.  If set, this overrides 802.3
++ *                    standard control frame behavior, and all Ethernet frames
++ *                    that have an ethertype of 0x8808 are treated as normal
++ *                    Ethernet frames and passed up to the packet interface on
++ *                    a DA match.  Received pause control frames are passed to
++ *                    the packet interface only if Rx flow control is also
++ *                    disabled.  See fman_dtsec_handle_rx_pause() function.
++ * @tx_pause_time:    Transmit pause time value.  This pause value is used as
++ *                    part of the pause frame to be sent when a transmit pause
++ *                    frame is initiated.  If set to 0 this disables
++ *                    transmission of pause frames.
++ * @rx_preamble:      Receive preamble enable.  If set, the MAC recovers the
++ *                    received Ethernet 7-byte preamble and passes it to the
++ *                    packet interface at the start of each received frame.
++ *                    This field should be reset for internal MAC loop-back
++ *                    mode.
++ * @tx_preamble:      User defined preamble enable for transmitted frames.
++ *                    If set, a user-defined preamble must passed to the MAC
++ *                    and it is transmitted instead of the standard preamble.
++ * @preamble_len:     Length, in bytes, of the preamble field preceding each
++ *                    Ethernet start-of-frame delimiter byte.  The default
++ *                    value of 0x7 should be used in order to guarantee
++ *                    reliable operation with IEEE 802.3 compliant hardware.
++ * @rx_prepend:               Packet alignment padding length.  The specified number
++ *                    of bytes (1-31) of zero padding are inserted before the
++ *                    start of each received frame.  For Ethernet, where
++ *                    optional preamble extraction is enabled, the padding
++ *                    appears before the preamble, otherwise the padding
++ *                    precedes the layer 2 header.
++ *
++ * This structure contains basic dTSEC configuration and must be passed to
++ * fman_dtsec_init() function.  A default set of configuration values can be
++ * obtained by calling fman_dtsec_defconfig().
++ */
++struct dtsec_cfg {
++      bool            halfdup_on;
++      bool            halfdup_alt_backoff_en;
++      bool            halfdup_excess_defer;
++      bool            halfdup_no_backoff;
++      bool            halfdup_bp_no_backoff;
++      uint8_t         halfdup_alt_backoff_val;
++      uint16_t        halfdup_retransmit;
++      uint16_t        halfdup_coll_window;
++      bool            rx_drop_bcast;
++      bool            rx_short_frm;
++      bool            rx_len_check;
++      bool            tx_pad_crc;
++      bool            tx_crc;
++      bool            rx_ctrl_acc;
++      unsigned short  tx_pause_time;
++      unsigned short  tbipa;
++      bool            ptp_tsu_en;
++      bool            ptp_exception_en;
++      bool            rx_preamble;
++      bool            tx_preamble;
++      unsigned char   preamble_len;
++      unsigned char   rx_prepend;
++      bool            loopback;
++      bool            rx_time_stamp_en;
++      bool            tx_time_stamp_en;
++      bool            rx_flow;
++      bool            tx_flow;
++      bool            rx_group_hash_exd;
++      bool            rx_promisc;
++      uint8_t         tbi_phy_addr;
++      uint16_t        tx_pause_time_extd;
++      uint16_t        maximum_frame;
++      uint32_t        non_back_to_back_ipg1;
++      uint32_t        non_back_to_back_ipg2;
++      uint32_t        min_ifg_enforcement;
++      uint32_t        back_to_back_ipg;
++      bool            wake_on_lan;
++};
++
++
++/**
++ * fman_dtsec_defconfig() - Get default dTSEC configuration
++ * @cfg:      pointer to configuration structure.
++ *
++ * Call this function to obtain a default set of configuration values for
++ * initializing dTSEC.  The user can overwrite any of the values before calling
++ * fman_dtsec_init(), if specific configuration needs to be applied.
++ */
++void fman_dtsec_defconfig(struct dtsec_cfg *cfg);
++
++/**
++ * fman_dtsec_init() - Init dTSEC hardware block
++ * @regs:             Pointer to dTSEC register block
++ * @cfg:              dTSEC configuration data
++ * @iface_mode:               dTSEC interface mode, the type of MAC - PHY interface.
++ * @iface_speed:      1G or 10G
++ * @macaddr:          MAC station address to be assigned to the device
++ * @fm_rev_maj:               major rev number
++ * @fm_rev_min:               minor rev number
++ * @exceptions_mask:  initial exceptions mask
++ *
++ * This function initializes dTSEC and applies basic configuration.
++ *
++ * dTSEC initialization sequence:
++ * Before enabling Rx/Tx call dtsec_set_address() to set MAC address,
++ * fman_dtsec_adjust_link() to configure interface speed and duplex and finally
++ * dtsec_enable_tx()/dtsec_enable_rx() to start transmission and reception.
++ *
++ * Returns: 0 if successful, an error code otherwise.
++ */
++int fman_dtsec_init(struct dtsec_regs *regs, struct dtsec_cfg *cfg,
++      enum enet_interface iface_mode,
++      enum enet_speed iface_speed,
++      uint8_t *macaddr, uint8_t fm_rev_maj,
++      uint8_t fm_rev_min,
++      uint32_t exception_mask);
++
++/**
++ * fman_dtsec_enable() - Enable dTSEC Tx and Tx
++ * @regs:     Pointer to dTSEC register block
++ * @apply_rx: enable rx side
++ * @apply_tx: enable tx side
++ *
++ * This function resets Tx and Rx graceful stop bit and enables dTSEC Tx and Rx.
++ */
++void fman_dtsec_enable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx);
++
++/**
++ * fman_dtsec_disable() - Disable dTSEC Tx and Rx
++ * @regs:     Pointer to dTSEC register block
++ * @apply_rx: disable rx side
++ * @apply_tx: disable tx side
++ *
++ * This function disables Tx and Rx in dTSEC.
++ */
++void fman_dtsec_disable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx);
++
++/**
++ * fman_dtsec_get_revision() - Get dTSEC hardware revision
++ * @regs:   Pointer to dTSEC register block
++ *
++ * Returns dtsec_id content
++ *
++ * Call this function to obtain the dTSEC hardware version.
++ */
++uint32_t fman_dtsec_get_revision(struct dtsec_regs *regs);
++
++/**
++ * fman_dtsec_set_mac_address() - Set MAC station address
++ * @regs:   Pointer to dTSEC register block
++ * @macaddr:    MAC address array
++ *
++ * This function sets MAC station address.  To enable unicast reception call
++ * this after fman_dtsec_init().  While promiscuous mode is disabled dTSEC will
++ * match the destination address of received unicast frames against this
++ * address.
++ */
++void fman_dtsec_set_mac_address(struct dtsec_regs *regs, uint8_t *macaddr);
++
++/**
++ * fman_dtsec_get_mac_address() - Query MAC station address
++ * @regs:   Pointer to dTSEC register block
++ * @macaddr:    MAC address array
++ */
++void fman_dtsec_get_mac_address(struct dtsec_regs *regs, uint8_t *macaddr);
++
++/**
++ * fman_dtsec_set_uc_promisc() - Sets unicast promiscuous mode
++ * @regs:     Pointer to dTSEC register block
++ * @enable:   Enable unicast promiscuous mode
++ *
++ * Use this function to enable/disable dTSEC L2 address filtering.  If the
++ * address filtering is disabled all unicast packets are accepted.
++ * To set dTSEC in promiscuous mode call both fman_dtsec_set_uc_promisc() and
++ * fman_dtsec_set_mc_promisc() to disable filtering for both unicast and
++ * multicast addresses.
++ */
++void fman_dtsec_set_uc_promisc(struct dtsec_regs *regs, bool enable);
++
++/**
++ * fman_dtsec_set_wol() - Enable/Disable wake on lan
++ *                        (magic packet support)
++ * @regs:   Pointer to dTSEC register block
++ * @en:     Enable Wake On Lan support in dTSEC
++ *
++ */
++void fman_dtsec_set_wol(struct dtsec_regs *regs, bool en);
++
++/**
++ * fman_dtsec_adjust_link() - Adjust dTSEC speed/duplex settings
++ * @regs:     Pointer to dTSEC register block
++ * @iface_mode: dTSEC interface mode
++ * @speed:    Link speed
++ * @full_dx:  True for full-duplex, false for half-duplex.
++ *
++ * This function configures the MAC to function and the desired rates.  Use it
++ * to configure dTSEC after fman_dtsec_init() and whenever the link speed
++ * changes (for instance following PHY auto-negociation).
++ *
++ * Returns: 0 if successful, an error code otherwise.
++ */
++int fman_dtsec_adjust_link(struct dtsec_regs *regs,
++      enum enet_interface iface_mode,
++      enum enet_speed speed, bool full_dx);
++
++/**
++ * fman_dtsec_set_tbi_phy_addr() - Updates TBI address field
++ * @regs:     Pointer to dTSEC register block
++ * @address:  Valid PHY address in the range of 1 to 31. 0 is reserved.
++ *
++ * In SGMII mode, the dTSEC's TBIPA field must contain a valid TBI PHY address
++ * so that the associated TBI PHY (i.e. the link) may be initialized.
++ *
++ * Returns: 0 if successful, an error code otherwise.
++ */
++int fman_dtsec_set_tbi_phy_addr(struct dtsec_regs *regs,
++      uint8_t addr);
++
++/**
++ * fman_dtsec_set_max_frame_len() - Set max frame length
++ * @regs:     Pointer to dTSEC register block
++ * @length:   Max frame length.
++ *
++ * Sets maximum frame length for received and transmitted frames.  Frames that
++ * exceeds this length are truncated.
++ */
++void fman_dtsec_set_max_frame_len(struct dtsec_regs *regs, uint16_t length);
++
++/**
++ * fman_dtsec_get_max_frame_len() - Query max frame length
++ * @regs:     Pointer to dTSEC register block
++ *
++ * Returns: the current value of the maximum frame length.
++ */
++uint16_t fman_dtsec_get_max_frame_len(struct dtsec_regs *regs);
++
++/**
++ * fman_dtsec_handle_rx_pause() - Configure pause frame handling
++ * @regs:     Pointer to dTSEC register block
++ * @en:               Enable pause frame handling in dTSEC
++ *
++ * If enabled, dTSEC will handle pause frames internally.  This must be disabled
++ * if dTSEC is set in half-duplex mode.
++ * If pause frame handling is disabled and &dtsec_cfg.rx_ctrl_acc is set, pause
++ * frames will be transferred to the packet interface just like regular Ethernet
++ * frames.
++ */
++void fman_dtsec_handle_rx_pause(struct dtsec_regs *regs, bool en);
++
++/**
++ * fman_dtsec_set_tx_pause_frames() - Configure Tx pause time
++ * @regs:     Pointer to dTSEC register block
++ * @time:     Time value included in pause frames
++ *
++ * Call this function to set the time value used in transmitted pause frames.
++ * If time is 0, transmission of pause frames is disabled
++ */
++void fman_dtsec_set_tx_pause_frames(struct dtsec_regs *regs, uint16_t time);
++
++/**
++ * fman_dtsec_ack_event() - Acknowledge handled events
++ * @regs:     Pointer to dTSEC register block
++ * @ev_mask:  Events to acknowledge
++ *
++ * After handling events signaled by dTSEC in either polling or interrupt mode,
++ * call this function to reset the associated status bits in dTSEC event
++ * register.
++ */
++void fman_dtsec_ack_event(struct dtsec_regs *regs, uint32_t ev_mask);
++
++/**
++ * fman_dtsec_get_event() - Returns currently asserted events
++ * @regs:     Pointer to dTSEC register block
++ * @ev_mask:  Mask of relevant events
++ *
++ * Call this function to obtain a bit-mask of events that are currently asserted
++ * in dTSEC, taken from IEVENT register.
++ *
++ * Returns: a bit-mask of events asserted in dTSEC.
++ */
++uint32_t fman_dtsec_get_event(struct dtsec_regs *regs, uint32_t ev_mask);
++
++/**
++ * fman_dtsec_get_interrupt_mask() - Returns a bit-mask of enabled interrupts
++ * @regs:   Pointer to dTSEC register block
++ *
++ * Call this function to obtain a bit-mask of enabled interrupts
++ * in dTSEC, taken from IMASK register.
++ *
++ * Returns: a bit-mask of enabled interrupts in dTSEC.
++ */
++uint32_t fman_dtsec_get_interrupt_mask(struct dtsec_regs *regs);
++
++void fman_dtsec_clear_addr_in_paddr(struct dtsec_regs *regs,
++      uint8_t paddr_num);
++
++void fman_dtsec_add_addr_in_paddr(struct dtsec_regs *regs,
++      uint64_t addr,
++      uint8_t paddr_num);
++
++void fman_dtsec_enable_tmr_interrupt (struct dtsec_regs *regs);
++
++void fman_dtsec_disable_tmr_interrupt(struct dtsec_regs *regs);
++
++/**
++ * fman_dtsec_disable_interrupt() - Disables interrupts for the specified events
++ * @regs:     Pointer to dTSEC register block
++ * @ev_mask:  Mask of relevant events
++ *
++ * Call this function to disable interrupts in dTSEC for the specified events.
++ * To enable interrupts use fman_dtsec_enable_interrupt().
++ */
++void fman_dtsec_disable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask);
++
++/**
++ * fman_dtsec_enable_interrupt() - Enable interrupts for the specified events
++ * @regs:     Pointer to dTSEC register block
++ * @ev_mask:  Mask of relevant events
++ *
++ * Call this function to enable interrupts in dTSEC for the specified events.
++ * To disable interrupts use fman_dtsec_disable_interrupt().
++ */
++void fman_dtsec_enable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask);
++
++/**
++ * fman_dtsec_set_ts() - Enables dTSEC timestamps
++ * @regs:     Pointer to dTSEC register block
++ * @en:               true to enable timestamps, false to disable them
++ *
++ * Call this function to enable/disable dTSEC timestamps.  This affects both
++ * Tx and Rx.
++ */
++void fman_dtsec_set_ts(struct dtsec_regs *regs, bool en);
++
++/**
++ * fman_dtsec_set_bucket() - Enables/disables a filter bucket
++ * @regs:   Pointer to dTSEC register block
++ * @bucket: Bucket index
++ * @enable: true/false to enable/disable this bucket
++ *
++ * This function enables or disables the specified bucket.  Enabling a bucket
++ * associated with an address configures dTSEC to accept received packets
++ * with that destination address.
++ * Multiple addresses may be associated with the same bucket.  Disabling a
++ * bucket will affect all addresses associated with that bucket. A bucket that
++ * is enabled requires further filtering and verification in the upper layers
++ *
++ */
++void fman_dtsec_set_bucket(struct dtsec_regs *regs, int bucket, bool enable);
++
++/**
++ * dtsec_set_hash_table() - insert a crc code into thr filter table
++ * @regs:     Pointer to dTSEC register block
++ * @crc:      crc to insert
++ * @mcast:    true is this is a multicast address
++ * @ghtx:     true if we are in ghtx mode
++ *
++ * This function inserts a crc code into the filter table.
++ */
++void fman_dtsec_set_hash_table(struct dtsec_regs *regs, uint32_t crc,
++      bool mcast, bool ghtx);
++
++/**
++ * fman_dtsec_reset_filter_table() - Resets the address filtering table
++ * @regs:     Pointer to dTSEC register block
++ * @mcast:    Reset multicast entries
++ * @ucast:    Reset unicast entries
++ *
++ * Resets all entries in L2 address filter table.  After calling this function
++ * all buckets enabled using fman_dtsec_set_bucket() will be disabled.
++ * If dtsec_init_filter_table() was called with @unicast_hash set to false,
++ * @ucast argument is ignored.
++ * This does not affect the primary nor the 15 additional addresses configured
++ * using dtsec_set_address() or dtsec_set_match_address().
++ */
++void fman_dtsec_reset_filter_table(struct dtsec_regs *regs, bool mcast,
++      bool ucast);
++
++/**
++ * fman_dtsec_set_mc_promisc() - Set multicast promiscuous mode
++ * @regs:     Pointer to dTSEC register block
++ * @enable:   Enable multicast promiscuous mode
++ *
++ * Call this to enable/disable L2 address filtering for multicast packets.
++ */
++void fman_dtsec_set_mc_promisc(struct dtsec_regs *regs, bool enable);
++
++/* statistics APIs */
++
++/**
++ * fman_dtsec_set_stat_level() - Enable a group of MIB statistics counters
++ * @regs:     Pointer to dTSEC register block
++ * @level:    Specifies a certain group of dTSEC MIB HW counters or _all_,
++ *            to specify all the existing counters.
++ *            If set to _none_, it disables all the counters.
++ *
++ * Enables the MIB statistics hw counters and sets up the carry interrupt
++ * masks for the counters corresponding to the @level input parameter.
++ *
++ * Returns: error if invalid @level value given.
++ */
++int fman_dtsec_set_stat_level(struct dtsec_regs *regs,
++      enum dtsec_stat_level level);
++
++/**
++ * fman_dtsec_reset_stat() - Completely resets all dTSEC HW counters
++ * @regs:     Pointer to dTSEC register block
++ */
++void fman_dtsec_reset_stat(struct dtsec_regs *regs);
++
++/**
++ * fman_dtsec_get_clear_carry_regs() - Read and clear carry bits (CAR1-2 registers)
++ * @regs:     Pointer to dTSEC register block
++ * @car1:     car1 register value
++ * @car2:     car2 register value
++ *
++ * When set, the carry bits signal that an overflow occurred on the
++ * corresponding counters.
++ * Note that the carry bits (CAR1-2 registers) will assert the
++ * %DTSEC_IEVENT_MSRO interrupt if unmasked (via CAM1-2 regs).
++ *
++ * Returns: true if overflow occurred, otherwise - false
++ */
++bool fman_dtsec_get_clear_carry_regs(struct dtsec_regs *regs,
++      uint32_t *car1, uint32_t *car2);
++
++uint32_t fman_dtsec_check_and_clear_tmr_event(struct dtsec_regs *regs);
++
++uint32_t fman_dtsec_get_stat_counter(struct dtsec_regs *regs,
++      enum dtsec_stat_counters reg_name);
++
++void fman_dtsec_start_tx(struct dtsec_regs *regs);
++void fman_dtsec_start_rx(struct dtsec_regs *regs);
++void fman_dtsec_stop_tx(struct dtsec_regs *regs);
++void fman_dtsec_stop_rx(struct dtsec_regs *regs);
++uint32_t fman_dtsec_get_rctrl(struct dtsec_regs *regs);
++
++
++#endif /* __FSL_FMAN_DTSEC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec_mii_acc.h
+@@ -0,0 +1,107 @@
++/*
++ * Copyright 2008-2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __FSL_FMAN_DTSEC_MII_ACC_H
++#define __FSL_FMAN_DTSEC_MII_ACC_H
++
++#include "common/general.h"
++
++
++/* MII Management Configuration Register */
++#define MIIMCFG_RESET_MGMT            0x80000000
++#define MIIMCFG_MGNTCLK_MASK          0x00000007
++#define MIIMCFG_MGNTCLK_SHIFT         0
++
++/* MII  Management Command Register */
++#define MIIMCOM_SCAN_CYCLE            0x00000002
++#define MIIMCOM_READ_CYCLE            0x00000001
++
++/* MII  Management Address Register */
++#define MIIMADD_PHY_ADDR_SHIFT                8
++#define MIIMADD_PHY_ADDR_MASK         0x00001f00
++
++#define MIIMADD_REG_ADDR_SHIFT                0
++#define MIIMADD_REG_ADDR_MASK         0x0000001f
++
++/* MII Management Indicator Register */
++#define MIIMIND_BUSY                  0x00000001
++
++
++/* PHY Control Register */
++#define PHY_CR_PHY_RESET    0x8000
++#define PHY_CR_LOOPBACK     0x4000
++#define PHY_CR_SPEED0       0x2000
++#define PHY_CR_ANE          0x1000
++#define PHY_CR_RESET_AN     0x0200
++#define PHY_CR_FULLDUPLEX   0x0100
++#define PHY_CR_SPEED1       0x0040
++
++#define PHY_TBICON_SRESET   0x8000
++#define PHY_TBICON_SPEED2   0x0020
++#define PHY_TBICON_CLK_SEL  0x0020
++#define PHY_TBIANA_SGMII    0x4001
++#define PHY_TBIANA_1000X    0x01a0
++/* register map */
++
++/* MII Configuration Control Memory Map Registers */
++struct dtsec_mii_reg {
++      uint32_t reserved1[72];
++      uint32_t miimcfg;       /* MII Mgmt:configuration */
++      uint32_t miimcom;       /* MII Mgmt:command       */
++      uint32_t miimadd;       /* MII Mgmt:address       */
++      uint32_t miimcon;       /* MII Mgmt:control 3     */
++      uint32_t miimstat;      /* MII Mgmt:status        */
++      uint32_t miimind;       /* MII Mgmt:indicators    */
++};
++
++/* dTSEC MII API */
++
++/* functions to access the mii registers for phy configuration.
++ * this functionality may not be available for all dtsecs in the system.
++ * consult the reference manual for details */
++void fman_dtsec_mii_reset(struct dtsec_mii_reg *regs);
++/* frequency is in MHz.
++ * note that dtsec clock is 1/2 of fman clock */
++void fman_dtsec_mii_init(struct dtsec_mii_reg *regs, uint16_t dtsec_freq);
++int fman_dtsec_mii_write_reg(struct dtsec_mii_reg *regs,
++                      uint8_t addr,
++                      uint8_t reg,
++                      uint16_t data,
++                      uint16_t dtsec_freq);
++
++int fman_dtsec_mii_read_reg(struct dtsec_mii_reg *regs,
++                      uint8_t addr,
++                      uint8_t reg,
++                      uint16_t *data,
++                      uint16_t dtsec_freq);
++
++#endif /* __FSL_FMAN_DTSEC_MII_ACC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_kg.h
+@@ -0,0 +1,514 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __FSL_FMAN_KG_H
++#define __FSL_FMAN_KG_H
++
++#include "common/general.h"
++
++#define FM_KG_NUM_OF_GENERIC_REGS     8 /**< Num of generic KeyGen regs */
++#define FMAN_MAX_NUM_OF_HW_PORTS      64
++/**< Total num of masks allowed on KG extractions */
++#define FM_KG_EXTRACT_MASKS_NUM               4
++#define FM_KG_NUM_CLS_PLAN_ENTR               8 /**< Num of class. plan regs */
++#define FM_KG_CLS_PLAN_GRPS_NUM               32 /**< Max num of class. groups */
++
++struct fman_kg_regs {
++      uint32_t fmkg_gcr;
++      uint32_t res004;
++      uint32_t res008;
++      uint32_t fmkg_eer;
++      uint32_t fmkg_eeer;
++      uint32_t res014;
++      uint32_t res018;
++      uint32_t fmkg_seer;
++      uint32_t fmkg_seeer;
++      uint32_t fmkg_gsr;
++      uint32_t fmkg_tpc;
++      uint32_t fmkg_serc;
++      uint32_t res030[4];
++      uint32_t fmkg_fdor;
++      uint32_t fmkg_gdv0r;
++      uint32_t fmkg_gdv1r;
++      uint32_t res04c[6];
++      uint32_t fmkg_feer;
++      uint32_t res068[38];
++      uint32_t fmkg_indirect[63];
++      uint32_t fmkg_ar;
++};
++
++struct fman_kg_scheme_regs {
++      uint32_t kgse_mode; /**< MODE */
++      uint32_t kgse_ekfc; /**< Extract Known Fields Command */
++      uint32_t kgse_ekdv; /**< Extract Known Default Value */
++      uint32_t kgse_bmch; /**< Bit Mask Command High */
++      uint32_t kgse_bmcl; /**< Bit Mask Command Low */
++      uint32_t kgse_fqb; /**< Frame Queue Base */
++      uint32_t kgse_hc; /**< Hash Command */
++      uint32_t kgse_ppc; /**< Policer Profile Command */
++      uint32_t kgse_gec[FM_KG_NUM_OF_GENERIC_REGS];
++                              /**< Generic Extract Command */
++      uint32_t kgse_spc; /**< KeyGen Scheme Entry Statistic Packet Counter */
++      uint32_t kgse_dv0; /**< KeyGen Scheme Entry Default Value 0 */
++      uint32_t kgse_dv1; /**< KeyGen Scheme Entry Default Value 1 */
++      uint32_t kgse_ccbs; /**< KeyGen Scheme Entry Coarse Classification Bit*/
++      uint32_t kgse_mv; /**< KeyGen Scheme Entry Match vector */
++      uint32_t kgse_om; /**< KeyGen Scheme Entry Operation Mode bits */
++      uint32_t kgse_vsp; /**< KeyGen Scheme Entry Virtual Storage Profile */
++};
++
++struct fman_kg_pe_regs{
++      uint32_t fmkg_pe_sp;
++      uint32_t fmkg_pe_cpp;
++};
++
++struct fman_kg_cp_regs {
++      uint32_t kgcpe[FM_KG_NUM_CLS_PLAN_ENTR];
++};
++
++
++#define FM_KG_KGAR_GO                         0x80000000
++#define FM_KG_KGAR_READ                               0x40000000
++#define FM_KG_KGAR_WRITE                      0x00000000
++#define FM_KG_KGAR_SEL_SCHEME_ENTRY           0x00000000
++#define FM_KG_KGAR_SCM_WSEL_UPDATE_CNT                0x00008000
++
++#define KG_SCH_PP_SHIFT_HIGH                  0x80000000
++#define KG_SCH_PP_NO_GEN                      0x10000000
++#define KG_SCH_PP_SHIFT_LOW                   0x0000F000
++#define KG_SCH_MODE_NIA_PLCR                  0x40000000
++#define KG_SCH_GEN_EXTRACT_TYPE                       0x00008000
++#define KG_SCH_BITMASK_MASK                   0x000000FF
++#define KG_SCH_GEN_VALID                      0x80000000
++#define KG_SCH_GEN_MASK                               0x00FF0000
++#define FM_PCD_KG_KGAR_ERR                    0x20000000
++#define FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY     0x01000000
++#define FM_PCD_KG_KGAR_SEL_PORT_ENTRY         0x02000000
++#define FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP               0x00008000
++#define FM_PCD_KG_KGAR_SEL_PORT_WSEL_CPP      0x00004000
++#define FM_PCD_KG_KGAR_WSEL_MASK              0x0000FF00
++#define KG_SCH_HASH_CONFIG_NO_FQID            0x80000000
++#define KG_SCH_HASH_CONFIG_SYM                        0x40000000
++
++#define FM_EX_KG_DOUBLE_ECC                   0x80000000
++#define FM_EX_KG_KEYSIZE_OVERFLOW             0x40000000
++
++/* ECC capture register */
++#define KG_FMKG_SERC_CAP                      0x80000000
++#define KG_FMKG_SERC_CET                      0x40000000
++#define KG_FMKG_SERC_CNT_MSK                  0x00FF0000
++#define KG_FMKG_SERC_CNT_SHIFT                        16
++#define KG_FMKG_SERC_ADDR_MSK                 0x000003FF
++
++/* Masks */
++#define FM_KG_KGGCR_EN                                0x80000000
++#define KG_SCH_GEN_VALID                      0x80000000
++#define KG_SCH_GEN_EXTRACT_TYPE                       0x00008000
++#define KG_ERR_TYPE_DOUBLE                    0x40000000
++#define KG_ERR_ADDR_MASK                      0x00000FFF
++#define KG_SCH_MODE_EN                                0x80000000
++
++/* shifts */
++#define FM_KG_KGAR_NUM_SHIFT                  16
++#define FM_KG_PE_CPP_MASK_SHIFT                       16
++#define FM_KG_KGAR_WSEL_SHIFT                 8
++
++#define FM_KG_SCH_GEN_HT_INVALID              0
++
++#define FM_KG_MASK_SEL_GEN_BASE                       0x20
++
++#define KG_GET_MASK_SEL_SHIFT(shift, i)       \
++switch (i)                            \
++{                                     \
++      case 0: (shift) = 26; break;    \
++      case 1: (shift) = 20; break;    \
++      case 2: (shift) = 10; break;    \
++      case 3: (shift) = 4; break;     \
++      default: (shift) = 0;           \
++}
++
++#define KG_GET_MASK_OFFSET_SHIFT(shift, i)    \
++switch (i)                            \
++{                                     \
++      case 0: (shift) = 16; break;    \
++      case 1: (shift) = 0; break;     \
++      case 2: (shift) = 28; break;    \
++      case 3: (shift) = 24; break;    \
++      default: (shift) = 0;           \
++}
++
++#define KG_GET_MASK_SHIFT(shift, i)   \
++switch (i)                            \
++{                                     \
++      case 0: shift = 24; break;      \
++      case 1: shift = 16; break;      \
++      case 2: shift = 8;  break;      \
++      case 3: shift = 0;  break;      \
++      default: shift = 0;             \
++}
++
++/* Port entry CPP register */
++#define FMAN_KG_PE_CPP_MASK_SHIFT     16
++
++/* Scheme registers */
++#define FMAN_KG_SCH_MODE_EN           0x80000000
++#define FMAN_KG_SCH_MODE_NIA_PLCR     0x40000000
++#define FMAN_KG_SCH_MODE_CCOBASE_SHIFT        24
++
++#define FMAN_KG_SCH_DEF_MAC_ADDR_SHIFT        30
++#define FMAN_KG_SCH_DEF_VLAN_TCI_SHIFT        28
++#define FMAN_KG_SCH_DEF_ETYPE_SHIFT   26
++#define FMAN_KG_SCH_DEF_PPP_SID_SHIFT 24
++#define FMAN_KG_SCH_DEF_PPP_PID_SHIFT 22
++#define FMAN_KG_SCH_DEF_MPLS_SHIFT    20
++#define FMAN_KG_SCH_DEF_IP_ADDR_SHIFT 18
++#define FMAN_KG_SCH_DEF_PTYPE_SHIFT   16
++#define FMAN_KG_SCH_DEF_IP_TOS_TC_SHIFT       14
++#define FMAN_KG_SCH_DEF_IPv6_FL_SHIFT 12
++#define FMAN_KG_SCH_DEF_IPSEC_SPI_SHIFT       10
++#define FMAN_KG_SCH_DEF_L4_PORT_SHIFT 8
++#define FMAN_KG_SCH_DEF_TCP_FLG_SHIFT 6
++
++#define FMAN_KG_SCH_GEN_VALID         0x80000000
++#define FMAN_KG_SCH_GEN_SIZE_MAX      16
++#define FMAN_KG_SCH_GEN_OR            0x00008000
++
++#define FMAN_KG_SCH_GEN_DEF_SHIFT     29
++#define FMAN_KG_SCH_GEN_SIZE_SHIFT    24
++#define FMAN_KG_SCH_GEN_MASK_SHIFT    16
++#define FMAN_KG_SCH_GEN_HT_SHIFT      8
++
++#define FMAN_KG_SCH_HASH_HSHIFT_SHIFT 24
++#define FMAN_KG_SCH_HASH_HSHIFT_MAX   0x28
++#define FMAN_KG_SCH_HASH_SYM          0x40000000
++#define FMAN_KG_SCH_HASH_NO_FQID_GEN  0x80000000
++
++#define FMAN_KG_SCH_PP_SH_SHIFT               27
++#define FMAN_KG_SCH_PP_SL_SHIFT               12
++#define FMAN_KG_SCH_PP_SH_MASK                0x80000000
++#define FMAN_KG_SCH_PP_SL_MASK                0x0000F000
++#define FMAN_KG_SCH_PP_SHIFT_MAX      0x17
++#define FMAN_KG_SCH_PP_MASK_SHIFT     16
++#define FMAN_KG_SCH_PP_NO_GEN         0x10000000
++
++enum fman_kg_gen_extract_src {
++      E_FMAN_KG_GEN_EXTRACT_ETH,
++      E_FMAN_KG_GEN_EXTRACT_ETYPE,
++      E_FMAN_KG_GEN_EXTRACT_SNAP,
++      E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_1,
++      E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_N,
++      E_FMAN_KG_GEN_EXTRACT_PPPoE,
++      E_FMAN_KG_GEN_EXTRACT_MPLS_1,
++      E_FMAN_KG_GEN_EXTRACT_MPLS_2,
++      E_FMAN_KG_GEN_EXTRACT_MPLS_3,
++      E_FMAN_KG_GEN_EXTRACT_MPLS_N,
++      E_FMAN_KG_GEN_EXTRACT_IPv4_1,
++      E_FMAN_KG_GEN_EXTRACT_IPv6_1,
++      E_FMAN_KG_GEN_EXTRACT_IPv4_2,
++      E_FMAN_KG_GEN_EXTRACT_IPv6_2,
++      E_FMAN_KG_GEN_EXTRACT_MINENCAP,
++      E_FMAN_KG_GEN_EXTRACT_IP_PID,
++      E_FMAN_KG_GEN_EXTRACT_GRE,
++      E_FMAN_KG_GEN_EXTRACT_TCP,
++      E_FMAN_KG_GEN_EXTRACT_UDP,
++      E_FMAN_KG_GEN_EXTRACT_SCTP,
++      E_FMAN_KG_GEN_EXTRACT_DCCP,
++      E_FMAN_KG_GEN_EXTRACT_IPSEC_AH,
++      E_FMAN_KG_GEN_EXTRACT_IPSEC_ESP,
++      E_FMAN_KG_GEN_EXTRACT_SHIM_1,
++      E_FMAN_KG_GEN_EXTRACT_SHIM_2,
++      E_FMAN_KG_GEN_EXTRACT_FROM_DFLT,
++      E_FMAN_KG_GEN_EXTRACT_FROM_FRAME_START,
++      E_FMAN_KG_GEN_EXTRACT_FROM_PARSE_RESULT,
++      E_FMAN_KG_GEN_EXTRACT_FROM_END_OF_PARSE,
++      E_FMAN_KG_GEN_EXTRACT_FROM_FQID
++};
++
++struct fman_kg_ex_ecc_attr
++{
++      bool            valid;
++      bool            double_ecc;
++      uint16_t        addr;
++      uint8_t         single_ecc_count;
++};
++
++enum fman_kg_def_select
++{
++      E_FMAN_KG_DEF_GLOBAL_0,
++      E_FMAN_KG_DEF_GLOBAL_1,
++      E_FMAN_KG_DEF_SCHEME_0,
++      E_FMAN_KG_DEF_SCHEME_1
++};
++
++struct fman_kg_extract_def
++{
++      enum fman_kg_def_select mac_addr;
++      enum fman_kg_def_select vlan_tci;
++      enum fman_kg_def_select etype;
++      enum fman_kg_def_select ppp_sid;
++      enum fman_kg_def_select ppp_pid;
++      enum fman_kg_def_select mpls;
++      enum fman_kg_def_select ip_addr;
++      enum fman_kg_def_select ptype;
++      enum fman_kg_def_select ip_tos_tc;
++      enum fman_kg_def_select ipv6_fl;
++      enum fman_kg_def_select ipsec_spi;
++      enum fman_kg_def_select l4_port;
++      enum fman_kg_def_select tcp_flg;
++};
++
++enum fman_kg_gen_extract_type
++{
++      E_FMAN_KG_HASH_EXTRACT,
++      E_FMAN_KG_OR_EXTRACT
++};
++
++struct fman_kg_gen_extract_params
++{
++      /* Hash or Or-ed extract */
++      enum fman_kg_gen_extract_type   type;
++      enum fman_kg_gen_extract_src    src;
++      bool                            no_validation;
++      /* Extraction offset from the header location specified above */
++      uint8_t                         offset;
++      /* Size of extraction for FMAN_KG_HASH_EXTRACT,
++       * hash result shift for FMAN_KG_OR_EXTRACT */
++      uint8_t                         extract;
++      uint8_t                         mask;
++      /* Default value to use when header specified
++       * by fman_kg_gen_extract_src doesn't present */
++      enum fman_kg_def_select         def_val;
++};
++
++struct fman_kg_extract_mask
++{
++      /**< Indication if mask is on known field extraction or
++       * on general extraction; TRUE for known field */
++      bool            is_known;
++      /**< One of FMAN_KG_EXTRACT_xxx defines for known fields mask and
++       * generic register index for generic extracts mask */
++      uint32_t        field_or_gen_idx;
++      /**< Byte offset from start of the extracted data specified
++       * by field_or_gen_idx */
++      uint8_t         offset;
++      /**< Byte mask (selected bits will be used) */
++      uint8_t         mask;
++};
++
++struct fman_kg_extract_params
++{
++      /* Or-ed mask of FMAN_KG_EXTRACT_xxx defines */
++      uint32_t                                known_fields;
++      struct fman_kg_extract_def              known_fields_def;
++      /* Number of entries in gen_extract */
++      uint8_t                                 gen_extract_num;
++      struct fman_kg_gen_extract_params       gen_extract[FM_KG_NUM_OF_GENERIC_REGS];
++      /* Number of entries in masks */
++      uint8_t                                 masks_num;
++      struct fman_kg_extract_mask             masks[FM_KG_EXTRACT_MASKS_NUM];
++      uint32_t                                def_scheme_0;
++      uint32_t                                def_scheme_1;
++};
++
++struct fman_kg_hash_params
++{
++      bool            use_hash;
++      uint8_t         shift_r;
++      uint32_t        mask; /**< 24-bit mask */
++      bool            sym; /**< Symmetric hash for src and dest pairs */
++};
++
++struct fman_kg_pp_params
++{
++      uint8_t         base;
++      uint8_t         shift;
++      uint8_t         mask;
++      bool            bypass_pp_gen;
++};
++
++struct fman_kg_cc_params
++{
++      uint8_t         base_offset;
++      uint32_t        qlcv_bits_sel;
++};
++
++enum fman_pcd_engine
++{
++      E_FMAN_PCD_INVALID = 0, /**< Invalid PCD engine indicated*/
++      E_FMAN_PCD_DONE,        /**< No PCD Engine indicated */
++      E_FMAN_PCD_KG,          /**< Keygen indicated */
++      E_FMAN_PCD_CC,          /**< Coarse classification indicated */
++      E_FMAN_PCD_PLCR,        /**< Policer indicated */
++      E_FMAN_PCD_PRS          /**< Parser indicated */
++};
++
++struct fman_kg_cls_plan_params
++{
++      uint8_t entries_mask;
++      uint32_t mask_vector[FM_KG_NUM_CLS_PLAN_ENTR];
++};
++
++struct fman_kg_scheme_params
++{
++      uint32_t                        match_vector;
++      struct fman_kg_extract_params   extract_params;
++      struct fman_kg_hash_params      hash_params;
++      uint32_t                        base_fqid;
++      /* What we do w/features supported per FM version ?? */
++      bool                            bypass_fqid_gen;
++      struct fman_kg_pp_params        policer_params;
++      struct fman_kg_cc_params        cc_params;
++      bool                            update_counter;
++      /**< counter_value: Set scheme counter to the specified value;
++       * relevant only when update_counter = TRUE. */
++      uint32_t                        counter_value;
++      enum fman_pcd_engine            next_engine;
++      /**< Next engine action code */
++      uint32_t                        next_engine_action;
++};
++
++
++
++int fman_kg_write_ar_wait(struct fman_kg_regs *regs, uint32_t fmkg_ar);
++void fman_kg_write_sp(struct fman_kg_regs *regs, uint32_t sp, bool add);
++void fman_kg_write_cpp(struct fman_kg_regs *regs, uint32_t cpp);
++void fman_kg_get_event(struct fman_kg_regs *regs,
++                      uint32_t *event,
++                      uint32_t *scheme_idx);
++void fman_kg_init(struct fman_kg_regs *regs,
++                      uint32_t exceptions,
++                      uint32_t dflt_nia);
++void fman_kg_enable_scheme_interrupts(struct fman_kg_regs *regs);
++void fman_kg_enable(struct fman_kg_regs *regs);
++void fman_kg_disable(struct fman_kg_regs *regs);
++int fman_kg_write_bind_cls_plans(struct fman_kg_regs *regs,
++                                      uint8_t hwport_id,
++                                      uint32_t bind_cls_plans);
++int fman_kg_build_bind_cls_plans(uint8_t grp_base,
++                                      uint8_t grp_mask,
++                                      uint32_t *bind_cls_plans);
++int fman_kg_write_bind_schemes(struct fman_kg_regs *regs,
++                              uint8_t hwport_id,
++                              uint32_t schemes);
++int fman_kg_write_cls_plan(struct fman_kg_regs *regs,
++                              uint8_t grp_id,
++                              uint8_t entries_mask,
++                              uint8_t hwport_id,
++                              struct fman_kg_cp_regs *cls_plan_regs);
++int fman_kg_build_cls_plan(struct fman_kg_cls_plan_params *params,
++                              struct fman_kg_cp_regs *cls_plan_regs);
++uint32_t fman_kg_get_schemes_total_counter(struct fman_kg_regs *regs);
++int fman_kg_set_scheme_counter(struct fman_kg_regs *regs,
++                              uint8_t scheme_id,
++                              uint8_t hwport_id,
++                              uint32_t counter);
++int fman_kg_get_scheme_counter(struct fman_kg_regs *regs,
++                              uint8_t scheme_id,
++                              uint8_t hwport_id,
++                              uint32_t *counter);
++int fman_kg_delete_scheme(struct fman_kg_regs *regs,
++                              uint8_t scheme_id,
++                              uint8_t hwport_id);
++int fman_kg_write_scheme(struct fman_kg_regs *regs,
++                              uint8_t scheme_id,
++                              uint8_t hwport_id,
++                              struct fman_kg_scheme_regs *scheme_regs,
++                              bool update_counter);
++int fman_kg_build_scheme(struct fman_kg_scheme_params *params,
++                              struct fman_kg_scheme_regs *scheme_regs);
++void fman_kg_get_capture(struct fman_kg_regs *regs,
++                              struct fman_kg_ex_ecc_attr *ecc_attr,
++                              bool clear);
++void fman_kg_get_exception(struct fman_kg_regs *regs,
++                              uint32_t *events,
++                              uint32_t *scheme_ids,
++                              bool clear);
++void fman_kg_set_exception(struct fman_kg_regs *regs,
++                              uint32_t exception,
++                              bool enable);
++void fman_kg_set_dflt_val(struct fman_kg_regs *regs,
++                              uint8_t def_id,
++                              uint32_t val);
++void fman_kg_set_data_after_prs(struct fman_kg_regs *regs, uint8_t offset);
++
++
++      
++/**************************************************************************//**
++  @Description       NIA Description
++*//***************************************************************************/
++#define KG_NIA_ORDER_RESTOR   0x00800000
++#define KG_NIA_ENG_FM_CTL     0x00000000
++#define KG_NIA_ENG_PRS                0x00440000
++#define KG_NIA_ENG_KG         0x00480000
++#define KG_NIA_ENG_PLCR               0x004C0000
++#define KG_NIA_ENG_BMI                0x00500000
++#define KG_NIA_ENG_QMI_ENQ    0x00540000
++#define KG_NIA_ENG_QMI_DEQ    0x00580000
++#define KG_NIA_ENG_MASK               0x007C0000
++
++#define KG_NIA_AC_MASK                0x0003FFFF
++
++#define KG_NIA_INVALID                0xFFFFFFFF
++
++static __inline__ uint32_t fm_kg_build_nia(enum fman_pcd_engine next_engine,
++                                      uint32_t next_engine_action)
++{
++      uint32_t nia;
++
++      if (next_engine_action & ~KG_NIA_AC_MASK)
++              return KG_NIA_INVALID;
++
++      switch (next_engine) {
++      case E_FMAN_PCD_DONE:
++              nia = KG_NIA_ENG_BMI | next_engine_action;
++              break;
++
++      case E_FMAN_PCD_KG:
++              nia = KG_NIA_ENG_KG | next_engine_action;
++              break;
++
++      case E_FMAN_PCD_CC:
++              nia = KG_NIA_ENG_FM_CTL | next_engine_action;
++              break;
++
++      case E_FMAN_PCD_PLCR:
++              nia = KG_NIA_ENG_PLCR | next_engine_action;
++              break;
++
++      default:
++              nia = KG_NIA_INVALID;
++      }
++
++      return nia;
++}
++
++#endif /* __FSL_FMAN_KG_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac.h
+@@ -0,0 +1,427 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#ifndef __FSL_FMAN_MEMAC_H
++#define __FSL_FMAN_MEMAC_H
++
++#include "common/general.h"
++#include "fsl_enet.h"
++
++
++#define MEMAC_NUM_OF_PADDRS 7 /* Num of additional exact match MAC adr regs */
++
++/* Control and Configuration Register (COMMAND_CONFIG) */
++#define CMD_CFG_MG            0x80000000 /* 00 Magic Packet detection */
++#define CMD_CFG_REG_LOWP_RXETY        0x01000000 /* 07 Rx low power indication */
++#define CMD_CFG_TX_LOWP_ENA   0x00800000 /* 08 Tx Low Power Idle Enable */
++#define CMD_CFG_SFD_ANY               0x00200000 /* 10 Disable SFD check */
++#define CMD_CFG_PFC_MODE      0x00080000 /* 12 Enable PFC */
++#define CMD_CFG_NO_LEN_CHK    0x00020000 /* 14 Payload length check disable */
++#define CMD_CFG_SEND_IDLE     0x00010000 /* 15 Force idle generation */
++#define CMD_CFG_CNT_FRM_EN    0x00002000 /* 18 Control frame rx enable */
++#define CMD_CFG_SW_RESET      0x00001000 /* 19 S/W Reset, self clearing bit */
++#define CMD_CFG_TX_PAD_EN     0x00000800 /* 20 Enable Tx padding of frames */
++#define CMD_CFG_LOOPBACK_EN   0x00000400 /* 21 XGMII/GMII loopback enable */
++#define CMD_CFG_TX_ADDR_INS   0x00000200 /* 22 Tx source MAC addr insertion */
++#define CMD_CFG_PAUSE_IGNORE  0x00000100 /* 23 Ignore Pause frame quanta */
++#define CMD_CFG_PAUSE_FWD     0x00000080 /* 24 Terminate/frwd Pause frames */
++#define CMD_CFG_CRC_FWD               0x00000040 /* 25 Terminate/frwd CRC of frames */
++#define CMD_CFG_PAD_EN                0x00000020 /* 26 Frame padding removal */
++#define CMD_CFG_PROMIS_EN     0x00000010 /* 27 Promiscuous operation enable */
++#define CMD_CFG_WAN_MODE      0x00000008 /* 28 WAN mode enable */
++#define CMD_CFG_RX_EN         0x00000002 /* 30 MAC receive path enable */
++#define CMD_CFG_TX_EN         0x00000001 /* 31 MAC transmit path enable */
++
++/* Transmit FIFO Sections Register (TX_FIFO_SECTIONS) */
++#define TX_FIFO_SECTIONS_TX_EMPTY_MASK                        0xFFFF0000
++#define TX_FIFO_SECTIONS_TX_AVAIL_MASK                        0x0000FFFF
++#define TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G 0x00400000
++#define TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G  0x00100000
++#define TX_FIFO_SECTIONS_TX_EMPTY_PFC_10G             0x00360000
++#define TX_FIFO_SECTIONS_TX_EMPTY_PFC_1G              0x00040000
++#define TX_FIFO_SECTIONS_TX_AVAIL_10G                 0x00000019
++#define TX_FIFO_SECTIONS_TX_AVAIL_1G                  0x00000020
++#define TX_FIFO_SECTIONS_TX_AVAIL_SLOW_10G            0x00000060
++
++#define GET_TX_EMPTY_DEFAULT_VALUE(_val)                                      \
++_val &= ~TX_FIFO_SECTIONS_TX_EMPTY_MASK;                                      \
++((_val == TX_FIFO_SECTIONS_TX_AVAIL_10G) ?                                    \
++              (_val |= TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G) :       \
++              (_val |= TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G));
++
++#define GET_TX_EMPTY_PFC_VALUE(_val)                                          \
++_val &= ~TX_FIFO_SECTIONS_TX_EMPTY_MASK;                                      \
++((_val == TX_FIFO_SECTIONS_TX_AVAIL_10G) ?                                    \
++              (_val |= TX_FIFO_SECTIONS_TX_EMPTY_PFC_10G) :           \
++              (_val |= TX_FIFO_SECTIONS_TX_EMPTY_PFC_1G));
++
++/* Interface Mode Register (IF_MODE) */
++#define IF_MODE_MASK          0x00000003 /* 30-31 Mask on i/f mode bits */
++#define IF_MODE_XGMII         0x00000000 /* 30-31 XGMII (10G) interface */
++#define IF_MODE_GMII          0x00000002 /* 30-31 GMII (1G) interface */
++#define IF_MODE_RGMII         0x00000004
++#define IF_MODE_RGMII_AUTO    0x00008000
++#define IF_MODE_RGMII_1000  0x00004000 /* 10 - 1000Mbps RGMII */
++#define IF_MODE_RGMII_100   0x00000000 /* 00 - 100Mbps RGMII */
++#define IF_MODE_RGMII_10    0x00002000 /* 01 - 10Mbps RGMII */
++#define IF_MODE_RGMII_SP_MASK 0x00006000 /* Setsp mask bits */
++#define IF_MODE_RGMII_FD    0x00001000 /* Full duplex RGMII */
++#define IF_MODE_HD          0x00000040 /* Half duplex operation */
++
++/* Hash table Control Register (HASHTABLE_CTRL) */
++#define HASH_CTRL_MCAST_SHIFT 26
++#define HASH_CTRL_MCAST_EN    0x00000100 /* 23 Mcast frame rx for hash */
++#define HASH_CTRL_ADDR_MASK   0x0000003F /* 26-31 Hash table address code */
++
++#define GROUP_ADDRESS         0x0000010000000000LL /* MAC mcast indication */
++#define HASH_TABLE_SIZE               64 /* Hash tbl size */
++
++/* Transmit Inter-Packet Gap Length Register (TX_IPG_LENGTH) */
++#define MEMAC_TX_IPG_LENGTH_MASK      0x0000003F
++
++/* Statistics Configuration Register (STATN_CONFIG) */
++#define STATS_CFG_CLR         0x00000004 /* 29 Reset all counters */
++#define STATS_CFG_CLR_ON_RD   0x00000002 /* 30 Clear on read */
++#define STATS_CFG_SATURATE    0x00000001 /* 31 Saturate at the maximum val */
++
++/* Interrupt Mask Register (IMASK) */
++#define MEMAC_IMASK_MGI               0x40000000 /* 1 Magic pkt detect indication */
++#define MEMAC_IMASK_TSECC_ER 0x20000000 /* 2 Timestamp FIFO ECC error evnt */
++#define MEMAC_IMASK_TECC_ER   0x02000000 /* 6 Transmit frame ECC error evnt */
++#define MEMAC_IMASK_RECC_ER   0x01000000 /* 7 Receive frame ECC error evnt */
++
++#define MEMAC_ALL_ERRS_IMASK                  \
++              ((uint32_t)(MEMAC_IMASK_TSECC_ER        | \
++                      MEMAC_IMASK_TECC_ER     | \
++                      MEMAC_IMASK_RECC_ER     | \
++                      MEMAC_IMASK_MGI))
++
++#define MEMAC_IEVNT_PCS                       0x80000000 /* PCS (XG). Link sync (G) */
++#define MEMAC_IEVNT_AN                        0x40000000 /* Auto-negotiation */
++#define MEMAC_IEVNT_LT                        0x20000000 /* Link Training/New page */
++#define MEMAC_IEVNT_MGI                       0x00004000 /* Magic pkt detection */
++#define MEMAC_IEVNT_TS_ECC_ER   0x00002000 /* Timestamp FIFO ECC error */
++#define MEMAC_IEVNT_RX_FIFO_OVFL      0x00001000 /* Rx FIFO overflow */
++#define MEMAC_IEVNT_TX_FIFO_UNFL      0x00000800 /* Tx FIFO underflow */
++#define MEMAC_IEVNT_TX_FIFO_OVFL      0x00000400 /* Tx FIFO overflow */
++#define MEMAC_IEVNT_TX_ECC_ER         0x00000200 /* Tx frame ECC error */
++#define MEMAC_IEVNT_RX_ECC_ER         0x00000100 /* Rx frame ECC error */
++#define MEMAC_IEVNT_LI_FAULT          0x00000080 /* Link Interruption flt */
++#define MEMAC_IEVNT_RX_EMPTY          0x00000040 /* Rx FIFO empty */
++#define MEMAC_IEVNT_TX_EMPTY          0x00000020 /* Tx FIFO empty */
++#define MEMAC_IEVNT_RX_LOWP           0x00000010 /* Low Power Idle */
++#define MEMAC_IEVNT_PHY_LOS           0x00000004 /* Phy loss of signal */
++#define MEMAC_IEVNT_REM_FAULT         0x00000002 /* Remote fault (XGMII) */
++#define MEMAC_IEVNT_LOC_FAULT         0x00000001 /* Local fault (XGMII) */
++
++enum memac_counters {
++      E_MEMAC_COUNTER_R64,
++      E_MEMAC_COUNTER_R127,
++      E_MEMAC_COUNTER_R255,
++      E_MEMAC_COUNTER_R511,
++      E_MEMAC_COUNTER_R1023,
++      E_MEMAC_COUNTER_R1518,
++      E_MEMAC_COUNTER_R1519X,
++      E_MEMAC_COUNTER_RFRG,
++      E_MEMAC_COUNTER_RJBR,
++      E_MEMAC_COUNTER_RDRP,
++      E_MEMAC_COUNTER_RALN,
++      E_MEMAC_COUNTER_TUND,
++      E_MEMAC_COUNTER_ROVR,
++      E_MEMAC_COUNTER_RXPF,
++      E_MEMAC_COUNTER_TXPF,
++      E_MEMAC_COUNTER_ROCT,
++      E_MEMAC_COUNTER_RMCA,
++      E_MEMAC_COUNTER_RBCA,
++      E_MEMAC_COUNTER_RPKT,
++      E_MEMAC_COUNTER_RUCA,
++      E_MEMAC_COUNTER_RERR,
++      E_MEMAC_COUNTER_TOCT,
++      E_MEMAC_COUNTER_TMCA,
++      E_MEMAC_COUNTER_TBCA,
++      E_MEMAC_COUNTER_TUCA,
++      E_MEMAC_COUNTER_TERR
++};
++
++#define DEFAULT_PAUSE_QUANTA  0xf000
++#define DEFAULT_FRAME_LENGTH  0x600
++#define DEFAULT_TX_IPG_LENGTH 12
++
++/*
++ * memory map
++ */
++
++struct mac_addr {
++      uint32_t   mac_addr_l;  /* Lower 32 bits of 48-bit MAC address */
++      uint32_t   mac_addr_u;  /* Upper 16 bits of 48-bit MAC address */
++};
++
++struct memac_regs {
++      /* General Control and Status */
++      uint32_t res0000[2];
++      uint32_t command_config;        /* 0x008 Ctrl and cfg */
++      struct mac_addr mac_addr0;      /* 0x00C-0x010 MAC_ADDR_0...1 */
++      uint32_t maxfrm;                /* 0x014 Max frame length */
++      uint32_t res0018[1];
++      uint32_t rx_fifo_sections;      /* Receive FIFO configuration reg */
++      uint32_t tx_fifo_sections;      /* Transmit FIFO configuration reg */
++      uint32_t res0024[2];
++      uint32_t hashtable_ctrl;        /* 0x02C Hash table control */
++      uint32_t res0030[4];
++      uint32_t ievent;                /* 0x040 Interrupt event */
++      uint32_t tx_ipg_length;         /* 0x044 Transmitter inter-packet-gap */
++      uint32_t res0048;
++      uint32_t imask;                 /* 0x04C Interrupt mask */
++      uint32_t res0050;
++      uint32_t pause_quanta[4];       /* 0x054 Pause quanta */
++      uint32_t pause_thresh[4];       /* 0x064 Pause quanta threshold */
++      uint32_t rx_pause_status;       /* 0x074 Receive pause status */
++      uint32_t res0078[2];
++      struct mac_addr mac_addr[MEMAC_NUM_OF_PADDRS]; /* 0x80-0x0B4 mac padr */
++      uint32_t lpwake_timer;          /* 0x0B8 Low Power Wakeup Timer */
++      uint32_t sleep_timer;           /* 0x0BC Transmit EEE Low Power Timer */
++      uint32_t res00c0[8];
++      uint32_t statn_config;          /* 0x0E0 Statistics configuration */
++      uint32_t res00e4[7];
++      /* Rx Statistics Counter */
++      uint32_t reoct_l;
++      uint32_t reoct_u;
++      uint32_t roct_l;
++      uint32_t roct_u;
++      uint32_t raln_l;
++      uint32_t raln_u;
++      uint32_t rxpf_l;
++      uint32_t rxpf_u;
++      uint32_t rfrm_l;
++      uint32_t rfrm_u;
++      uint32_t rfcs_l;
++      uint32_t rfcs_u;
++      uint32_t rvlan_l;
++      uint32_t rvlan_u;
++      uint32_t rerr_l;
++      uint32_t rerr_u;
++      uint32_t ruca_l;
++      uint32_t ruca_u;
++      uint32_t rmca_l;
++      uint32_t rmca_u;
++      uint32_t rbca_l;
++      uint32_t rbca_u;
++      uint32_t rdrp_l;
++      uint32_t rdrp_u;
++      uint32_t rpkt_l;
++      uint32_t rpkt_u;
++      uint32_t rund_l;
++      uint32_t rund_u;
++      uint32_t r64_l;
++      uint32_t r64_u;
++      uint32_t r127_l;
++      uint32_t r127_u;
++      uint32_t r255_l;
++      uint32_t r255_u;
++      uint32_t r511_l;
++      uint32_t r511_u;
++      uint32_t r1023_l;
++      uint32_t r1023_u;
++      uint32_t r1518_l;
++      uint32_t r1518_u;
++      uint32_t r1519x_l;
++      uint32_t r1519x_u;
++      uint32_t rovr_l;
++      uint32_t rovr_u;
++      uint32_t rjbr_l;
++      uint32_t rjbr_u;
++      uint32_t rfrg_l;
++      uint32_t rfrg_u;
++      uint32_t rcnp_l;
++      uint32_t rcnp_u;
++      uint32_t rdrntp_l;
++      uint32_t rdrntp_u;
++      uint32_t res01d0[12];
++      /* Tx Statistics Counter */
++      uint32_t teoct_l;
++      uint32_t teoct_u;
++      uint32_t toct_l;
++      uint32_t toct_u;
++      uint32_t res0210[2];
++      uint32_t txpf_l;
++      uint32_t txpf_u;
++      uint32_t tfrm_l;
++      uint32_t tfrm_u;
++      uint32_t tfcs_l;
++      uint32_t tfcs_u;
++      uint32_t tvlan_l;
++      uint32_t tvlan_u;
++      uint32_t terr_l;
++      uint32_t terr_u;
++      uint32_t tuca_l;
++      uint32_t tuca_u;
++      uint32_t tmca_l;
++      uint32_t tmca_u;
++      uint32_t tbca_l;
++      uint32_t tbca_u;
++      uint32_t res0258[2];
++      uint32_t tpkt_l;
++      uint32_t tpkt_u;
++      uint32_t tund_l;
++      uint32_t tund_u;
++      uint32_t t64_l;
++      uint32_t t64_u;
++      uint32_t t127_l;
++      uint32_t t127_u;
++      uint32_t t255_l;
++      uint32_t t255_u;
++      uint32_t t511_l;
++      uint32_t t511_u;
++      uint32_t t1023_l;
++      uint32_t t1023_u;
++      uint32_t t1518_l;
++      uint32_t t1518_u;
++      uint32_t t1519x_l;
++      uint32_t t1519x_u;
++      uint32_t res02a8[6];
++      uint32_t tcnp_l;
++      uint32_t tcnp_u;
++      uint32_t res02c8[14];
++      /* Line Interface Control */
++      uint32_t if_mode;               /* 0x300 Interface Mode Control */
++      uint32_t if_status;             /* 0x304 Interface Status */
++      uint32_t res0308[14];
++      /* HiGig/2 */
++      uint32_t hg_config;             /* 0x340 Control and cfg */
++      uint32_t res0344[3];
++      uint32_t hg_pause_quanta;       /* 0x350 Pause quanta */
++      uint32_t res0354[3];
++      uint32_t hg_pause_thresh;       /* 0x360 Pause quanta threshold */
++      uint32_t res0364[3];
++      uint32_t hgrx_pause_status;     /* 0x370 Receive pause status */
++      uint32_t hg_fifos_status;       /* 0x374 fifos status */
++      uint32_t rhm;                   /* 0x378 rx messages counter */
++      uint32_t thm;                   /* 0x37C tx messages counter */
++};
++
++struct memac_cfg {
++      bool            reset_on_init;
++      bool            rx_error_discard;
++      bool            pause_ignore;
++      bool            pause_forward_enable;
++      bool            no_length_check_enable;
++      bool            cmd_frame_enable;
++      bool            send_idle_enable;
++      bool            wan_mode_enable;
++      bool            promiscuous_mode_enable;
++      bool            tx_addr_ins_enable;
++      bool            loopback_enable;
++      bool            lgth_check_nostdr;
++      bool            time_stamp_enable;
++      bool            pad_enable;
++      bool            phy_tx_ena_on;
++      bool            rx_sfd_any;
++      bool            rx_pbl_fwd;
++      bool            tx_pbl_fwd;
++      bool            debug_mode;
++      bool            wake_on_lan;
++      uint16_t        max_frame_length;
++      uint16_t        pause_quanta;
++      uint32_t        tx_ipg_length;
++};
++
++
++/**
++ * fman_memac_defconfig() - Get default MEMAC configuration
++ * @cfg:    pointer to configuration structure.
++ *
++ * Call this function to obtain a default set of configuration values for
++ * initializing MEMAC. The user can overwrite any of the values before calling
++ * fman_memac_init(), if specific configuration needs to be applied.
++ */
++void fman_memac_defconfig(struct memac_cfg *cfg);
++
++int fman_memac_init(struct memac_regs *regs,
++      struct memac_cfg *cfg,
++      enum enet_interface enet_interface,
++      enum enet_speed enet_speed,
++      bool slow_10g_if,
++      uint32_t exceptions);
++
++void fman_memac_enable(struct memac_regs *regs, bool apply_rx, bool apply_tx);
++
++void fman_memac_disable(struct memac_regs *regs, bool apply_rx, bool apply_tx);
++
++void fman_memac_set_promiscuous(struct memac_regs *regs, bool val);
++
++void fman_memac_add_addr_in_paddr(struct memac_regs *regs,
++      uint8_t *adr,
++      uint8_t paddr_num);
++
++void fman_memac_clear_addr_in_paddr(struct memac_regs *regs,
++      uint8_t paddr_num);
++
++uint64_t fman_memac_get_counter(struct memac_regs *regs,
++      enum memac_counters reg_name);
++
++void fman_memac_set_tx_pause_frames(struct memac_regs *regs,
++      uint8_t priority, uint16_t pauseTime, uint16_t threshTime);
++
++uint16_t fman_memac_get_max_frame_len(struct memac_regs *regs);
++
++void fman_memac_set_exception(struct memac_regs *regs, uint32_t val,
++      bool enable);
++
++void fman_memac_reset_stat(struct memac_regs *regs);
++
++void fman_memac_reset(struct memac_regs *regs);
++
++void fman_memac_reset_filter_table(struct memac_regs *regs);
++
++void fman_memac_set_hash_table_entry(struct memac_regs *regs, uint32_t crc);
++
++void fman_memac_set_hash_table(struct memac_regs *regs, uint32_t val);
++
++void fman_memac_set_rx_ignore_pause_frames(struct memac_regs *regs,
++      bool enable);
++
++void fman_memac_set_wol(struct memac_regs *regs, bool enable);
++
++uint32_t fman_memac_get_event(struct memac_regs *regs, uint32_t ev_mask);
++
++void fman_memac_ack_event(struct memac_regs *regs, uint32_t ev_mask);
++
++uint32_t fman_memac_get_interrupt_mask(struct memac_regs *regs);
++
++void fman_memac_adjust_link(struct memac_regs *regs,
++      enum enet_interface iface_mode,
++      enum enet_speed speed, bool full_dx);
++
++
++
++#endif /*__FSL_FMAN_MEMAC_H*/
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac_mii_acc.h
+@@ -0,0 +1,78 @@
++/*
++ * Copyright 2008-2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __FSL_FMAN_MEMAC_MII_ACC_H
++#define __FSL_FMAN_MEMAC_MII_ACC_H
++
++#include "common/general.h"
++#include "fsl_enet.h"
++/* MII Management Registers */
++#define MDIO_CFG_CLK_DIV_MASK       0x0080ff80
++#define MDIO_CFG_CLK_DIV_SHIFT      7
++#define MDIO_CFG_HOLD_MASK          0x0000001c
++#define MDIO_CFG_ENC45              0x00000040
++#define MDIO_CFG_READ_ERR           0x00000002
++#define MDIO_CFG_BSY                0x00000001
++
++#define MDIO_CTL_PHY_ADDR_SHIFT     5
++#define MDIO_CTL_READ               0x00008000
++
++#define MDIO_DATA_BSY               0x80000000
++
++/*MEMAC Internal PHY Registers - SGMII */
++#define PHY_SGMII_CR_PHY_RESET          0x8000
++#define PHY_SGMII_CR_RESET_AN           0x0200
++#define PHY_SGMII_CR_DEF_VAL            0x1140
++#define PHY_SGMII_DEV_ABILITY_SGMII     0x4001
++#define PHY_SGMII_DEV_ABILITY_1000X     0x01A0
++#define PHY_SGMII_IF_MODE_AN            0x0002
++#define PHY_SGMII_IF_MODE_SGMII         0x0001
++#define PHY_SGMII_IF_MODE_1000X         0x0000
++
++/*----------------------------------------------------*/
++/* MII Configuration Control Memory Map Registers     */
++/*----------------------------------------------------*/
++struct memac_mii_access_mem_map {
++      uint32_t   mdio_cfg;       /* 0x030  */
++      uint32_t   mdio_ctrl;      /* 0x034  */
++      uint32_t   mdio_data;      /* 0x038  */
++      uint32_t   mdio_addr;      /* 0x03c  */
++};
++
++int fman_memac_mii_read_phy_reg(struct memac_mii_access_mem_map *mii_regs,
++      uint8_t phy_addr, uint8_t reg, uint16_t *data,
++      enum enet_speed enet_speed);
++int fman_memac_mii_write_phy_reg(struct memac_mii_access_mem_map *mii_regs,
++      uint8_t phy_addr, uint8_t reg, uint16_t data,
++      enum enet_speed enet_speed);
++
++#endif /* __MAC_API_MEMAC_MII_ACC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_port.h
+@@ -0,0 +1,593 @@
++/*
++ * Copyright 2008-2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __FSL_FMAN_PORT_H
++#define __FSL_FMAN_PORT_H
++
++#include "fsl_fman_sp.h"
++
++/** @Collection  Registers bit fields */
++
++/** @Description  BMI defines */
++#define BMI_EBD_EN                              0x80000000
++
++#define BMI_PORT_CFG_EN                               0x80000000
++#define BMI_PORT_CFG_FDOVR                    0x02000000
++#define BMI_PORT_CFG_IM                               0x01000000
++
++#define BMI_PORT_STATUS_BSY                   0x80000000
++
++#define BMI_DMA_ATTR_SWP_SHIFT                        FMAN_SP_DMA_ATTR_SWP_SHIFT
++#define BMI_DMA_ATTR_IC_STASH_ON              0x10000000
++#define BMI_DMA_ATTR_HDR_STASH_ON             0x04000000
++#define BMI_DMA_ATTR_SG_STASH_ON              0x01000000
++#define BMI_DMA_ATTR_WRITE_OPTIMIZE           FMAN_SP_DMA_ATTR_WRITE_OPTIMIZE
++
++#define BMI_RX_FIFO_PRI_ELEVATION_SHIFT               16
++#define BMI_RX_FIFO_THRESHOLD_ETHE            0x80000000
++
++#define BMI_TX_FRAME_END_CS_IGNORE_SHIFT      24
++#define BMI_RX_FRAME_END_CS_IGNORE_SHIFT      24
++#define BMI_RX_FRAME_END_CUT_SHIFT            16
++
++#define BMI_IC_TO_EXT_SHIFT                   FMAN_SP_IC_TO_EXT_SHIFT
++#define BMI_IC_FROM_INT_SHIFT                 FMAN_SP_IC_FROM_INT_SHIFT
++
++#define BMI_INT_BUF_MARG_SHIFT                        28
++#define BMI_EXT_BUF_MARG_START_SHIFT          FMAN_SP_EXT_BUF_MARG_START_SHIFT
++
++#define BMI_CMD_MR_LEAC                               0x00200000
++#define BMI_CMD_MR_SLEAC                      0x00100000
++#define BMI_CMD_MR_MA                         0x00080000
++#define BMI_CMD_MR_DEAS                               0x00040000
++#define BMI_CMD_RX_MR_DEF                     (BMI_CMD_MR_LEAC | \
++                                              BMI_CMD_MR_SLEAC | \
++                                              BMI_CMD_MR_MA | \
++                                              BMI_CMD_MR_DEAS)
++#define BMI_CMD_TX_MR_DEF                     0
++#define BMI_CMD_OP_MR_DEF                     (BMI_CMD_MR_DEAS | \
++                                              BMI_CMD_MR_MA)
++
++#define BMI_CMD_ATTR_ORDER                    0x80000000
++#define BMI_CMD_ATTR_SYNC                     0x02000000
++#define BMI_CMD_ATTR_COLOR_SHIFT              26
++
++#define BMI_FIFO_PIPELINE_DEPTH_SHIFT           12
++#define BMI_NEXT_ENG_FD_BITS_SHIFT            24
++#define BMI_FRAME_END_CS_IGNORE_SHIFT           24
++
++#define BMI_COUNTERS_EN                               0x80000000
++
++#define BMI_EXT_BUF_POOL_VALID                        FMAN_SP_EXT_BUF_POOL_VALID
++#define BMI_EXT_BUF_POOL_EN_COUNTER           FMAN_SP_EXT_BUF_POOL_EN_COUNTER
++#define BMI_EXT_BUF_POOL_BACKUP                       FMAN_SP_EXT_BUF_POOL_BACKUP
++#define BMI_EXT_BUF_POOL_ID_SHIFT             16
++#define BMI_EXT_BUF_POOL_ID_MASK              0x003F0000
++#define BMI_POOL_DEP_NUM_OF_POOLS_SHIFT               16
++
++#define BMI_TX_FIFO_MIN_FILL_SHIFT            16
++#define BMI_TX_FIFO_PIPELINE_DEPTH_SHIFT      12
++
++#define MAX_PERFORMANCE_TASK_COMP             64
++#define MAX_PERFORMANCE_RX_QUEUE_COMP         64
++#define MAX_PERFORMANCE_TX_QUEUE_COMP         8
++#define MAX_PERFORMANCE_DMA_COMP              16
++#define MAX_PERFORMANCE_FIFO_COMP             1024
++
++#define BMI_PERFORMANCE_TASK_COMP_SHIFT               24
++#define BMI_PERFORMANCE_QUEUE_COMP_SHIFT      16
++#define BMI_PERFORMANCE_DMA_COMP_SHIFT                12
++
++#define BMI_RATE_LIMIT_GRAN_TX                        16000 /* In Kbps */
++#define BMI_RATE_LIMIT_GRAN_OP                        10000 /* In frames */
++#define BMI_RATE_LIMIT_MAX_RATE_IN_GRAN_UNITS 1024
++#define BMI_RATE_LIMIT_MAX_BURST_SIZE         1024 /* In KBytes */
++#define BMI_RATE_LIMIT_MAX_BURST_SHIFT                16
++#define BMI_RATE_LIMIT_HIGH_BURST_SIZE_GRAN   0x80000000
++#define BMI_RATE_LIMIT_SCALE_TSBS_SHIFT               16
++#define BMI_RATE_LIMIT_SCALE_EN                       0x80000000
++#define BMI_SG_DISABLE                          FMAN_SP_SG_DISABLE
++
++/** @Description  QMI defines */
++#define QMI_PORT_CFG_EN                               0x80000000
++#define QMI_PORT_CFG_EN_COUNTERS              0x10000000
++
++#define QMI_PORT_STATUS_DEQ_TNUM_BSY          0x80000000
++#define QMI_PORT_STATUS_DEQ_FD_BSY            0x20000000
++
++#define QMI_DEQ_CFG_PRI                               0x80000000
++#define QMI_DEQ_CFG_TYPE1                     0x10000000
++#define QMI_DEQ_CFG_TYPE2                     0x20000000
++#define QMI_DEQ_CFG_TYPE3                     0x30000000
++#define QMI_DEQ_CFG_PREFETCH_PARTIAL          0x01000000
++#define QMI_DEQ_CFG_PREFETCH_FULL             0x03000000
++#define QMI_DEQ_CFG_SP_MASK                   0xf
++#define QMI_DEQ_CFG_SP_SHIFT                  20
++
++
++/** @Description  General port defines */
++#define FMAN_PORT_EXT_POOLS_NUM(fm_rev_maj) \
++              (((fm_rev_maj) == 4) ? 4 : 8)
++#define FMAN_PORT_MAX_EXT_POOLS_NUM   8
++#define FMAN_PORT_OBS_EXT_POOLS_NUM   2
++#define FMAN_PORT_CG_MAP_NUM          8
++#define FMAN_PORT_PRS_RESULT_WORDS_NUM        8
++#define FMAN_PORT_BMI_FIFO_UNITS      0x100
++#define FMAN_PORT_IC_OFFSET_UNITS     0x10
++
++
++/** @Collection    FM Port Register Map */
++
++/** @Description   BMI Rx port register map */
++struct fman_port_rx_bmi_regs {
++      uint32_t fmbm_rcfg;             /**< Rx Configuration */
++      uint32_t fmbm_rst;              /**< Rx Status */
++      uint32_t fmbm_rda;              /**< Rx DMA attributes*/
++      uint32_t fmbm_rfp;              /**< Rx FIFO Parameters*/
++      uint32_t fmbm_rfed;             /**< Rx Frame End Data*/
++      uint32_t fmbm_ricp;             /**< Rx Internal Context Parameters*/
++      uint32_t fmbm_rim;              /**< Rx Internal Buffer Margins*/
++      uint32_t fmbm_rebm;             /**< Rx External Buffer Margins*/
++      uint32_t fmbm_rfne;             /**< Rx Frame Next Engine*/
++      uint32_t fmbm_rfca;             /**< Rx Frame Command Attributes.*/
++      uint32_t fmbm_rfpne;            /**< Rx Frame Parser Next Engine*/
++      uint32_t fmbm_rpso;             /**< Rx Parse Start Offset*/
++      uint32_t fmbm_rpp;              /**< Rx Policer Profile  */
++      uint32_t fmbm_rccb;             /**< Rx Coarse Classification Base */
++      uint32_t fmbm_reth;             /**< Rx Excessive Threshold */
++      uint32_t reserved003c[1];       /**< (0x03C 0x03F) */
++      uint32_t fmbm_rprai[FMAN_PORT_PRS_RESULT_WORDS_NUM];
++                                      /**< Rx Parse Results Array Init*/
++      uint32_t fmbm_rfqid;            /**< Rx Frame Queue ID*/
++      uint32_t fmbm_refqid;           /**< Rx Error Frame Queue ID*/
++      uint32_t fmbm_rfsdm;            /**< Rx Frame Status Discard Mask*/
++      uint32_t fmbm_rfsem;            /**< Rx Frame Status Error Mask*/
++      uint32_t fmbm_rfene;            /**< Rx Frame Enqueue Next Engine */
++      uint32_t reserved0074[0x2];     /**< (0x074-0x07C)  */
++      uint32_t fmbm_rcmne;            /**< Rx Frame Continuous Mode Next Engine */
++      uint32_t reserved0080[0x20];/**< (0x080 0x0FF)  */
++      uint32_t fmbm_ebmpi[FMAN_PORT_MAX_EXT_POOLS_NUM];
++                                      /**< Buffer Manager pool Information-*/
++      uint32_t fmbm_acnt[FMAN_PORT_MAX_EXT_POOLS_NUM];
++                                      /**< Allocate Counter-*/
++      uint32_t reserved0130[8];
++                                      /**< 0x130/0x140 - 0x15F reserved -*/
++      uint32_t fmbm_rcgm[FMAN_PORT_CG_MAP_NUM];
++                                      /**< Congestion Group Map*/
++      uint32_t fmbm_mpd;              /**< BM Pool Depletion  */
++      uint32_t reserved0184[0x1F];    /**< (0x184 0x1FF) */
++      uint32_t fmbm_rstc;             /**< Rx Statistics Counters*/
++      uint32_t fmbm_rfrc;             /**< Rx Frame Counter*/
++      uint32_t fmbm_rfbc;             /**< Rx Bad Frames Counter*/
++      uint32_t fmbm_rlfc;             /**< Rx Large Frames Counter*/
++      uint32_t fmbm_rffc;             /**< Rx Filter Frames Counter*/
++      uint32_t fmbm_rfdc;             /**< Rx Frame Discard Counter*/
++      uint32_t fmbm_rfldec;           /**< Rx Frames List DMA Error Counter*/
++      uint32_t fmbm_rodc;             /**< Rx Out of Buffers Discard nntr*/
++      uint32_t fmbm_rbdc;             /**< Rx Buffers Deallocate Counter*/
++      uint32_t reserved0224[0x17];    /**< (0x224 0x27F) */
++      uint32_t fmbm_rpc;              /**< Rx Performance Counters*/
++      uint32_t fmbm_rpcp;             /**< Rx Performance Count Parameters*/
++      uint32_t fmbm_rccn;             /**< Rx Cycle Counter*/
++      uint32_t fmbm_rtuc;             /**< Rx Tasks Utilization Counter*/
++      uint32_t fmbm_rrquc;            /**< Rx Receive Queue Utilization cntr*/
++      uint32_t fmbm_rduc;             /**< Rx DMA Utilization Counter*/
++      uint32_t fmbm_rfuc;             /**< Rx FIFO Utilization Counter*/
++      uint32_t fmbm_rpac;             /**< Rx Pause Activation Counter*/
++      uint32_t reserved02a0[0x18];    /**< (0x2A0 0x2FF) */
++      uint32_t fmbm_rdbg;             /**< Rx Debug-*/
++};
++
++/** @Description   BMI Tx port register map */
++struct fman_port_tx_bmi_regs {
++      uint32_t fmbm_tcfg;             /**< Tx Configuration */
++      uint32_t fmbm_tst;              /**< Tx Status */
++      uint32_t fmbm_tda;              /**< Tx DMA attributes */
++      uint32_t fmbm_tfp;              /**< Tx FIFO Parameters */
++      uint32_t fmbm_tfed;             /**< Tx Frame End Data */
++      uint32_t fmbm_ticp;             /**< Tx Internal Context Parameters */
++      uint32_t fmbm_tfdne;            /**< Tx Frame Dequeue Next Engine. */
++      uint32_t fmbm_tfca;             /**< Tx Frame Command attribute. */
++      uint32_t fmbm_tcfqid;           /**< Tx Confirmation Frame Queue ID. */
++      uint32_t fmbm_tefqid;           /**< Tx Frame Error Queue ID */
++      uint32_t fmbm_tfene;            /**< Tx Frame Enqueue Next Engine */
++      uint32_t fmbm_trlmts;           /**< Tx Rate Limiter Scale */
++      uint32_t fmbm_trlmt;            /**< Tx Rate Limiter */
++      uint32_t reserved0034[0x0e];    /**< (0x034-0x6c) */
++      uint32_t fmbm_tccb;             /**< Tx Coarse Classification base */
++      uint32_t fmbm_tfne;             /**< Tx Frame Next Engine */
++      uint32_t fmbm_tpfcm[0x02];      /**< Tx Priority based Flow Control (PFC) Mapping */
++      uint32_t fmbm_tcmne;            /**< Tx Frame Continuous Mode Next Engine */
++      uint32_t reserved0080[0x60];    /**< (0x080-0x200) */
++      uint32_t fmbm_tstc;             /**< Tx Statistics Counters */
++      uint32_t fmbm_tfrc;             /**< Tx Frame Counter */
++      uint32_t fmbm_tfdc;             /**< Tx Frames Discard Counter */
++      uint32_t fmbm_tfledc;           /**< Tx Frame len error discard cntr */
++      uint32_t fmbm_tfufdc;           /**< Tx Frame unsprt frmt discard cntr*/
++      uint32_t fmbm_tbdc;             /**< Tx Buffers Deallocate Counter */
++      uint32_t reserved0218[0x1A];    /**< (0x218-0x280) */
++      uint32_t fmbm_tpc;              /**< Tx Performance Counters*/
++      uint32_t fmbm_tpcp;             /**< Tx Performance Count Parameters*/
++      uint32_t fmbm_tccn;             /**< Tx Cycle Counter*/
++      uint32_t fmbm_ttuc;             /**< Tx Tasks Utilization Counter*/
++      uint32_t fmbm_ttcquc;           /**< Tx Transmit conf Q util Counter*/
++      uint32_t fmbm_tduc;             /**< Tx DMA Utilization Counter*/
++      uint32_t fmbm_tfuc;             /**< Tx FIFO Utilization Counter*/
++};
++
++/** @Description   BMI O/H port register map */
++struct fman_port_oh_bmi_regs {
++      uint32_t fmbm_ocfg;             /**< O/H Configuration  */
++      uint32_t fmbm_ost;              /**< O/H Status */
++      uint32_t fmbm_oda;              /**< O/H DMA attributes  */
++      uint32_t fmbm_oicp;             /**< O/H Internal Context Parameters */
++      uint32_t fmbm_ofdne;            /**< O/H Frame Dequeue Next Engine  */
++      uint32_t fmbm_ofne;             /**< O/H Frame Next Engine  */
++      uint32_t fmbm_ofca;             /**< O/H Frame Command Attributes.  */
++      uint32_t fmbm_ofpne;            /**< O/H Frame Parser Next Engine  */
++      uint32_t fmbm_opso;             /**< O/H Parse Start Offset  */
++      uint32_t fmbm_opp;              /**< O/H Policer Profile */
++      uint32_t fmbm_occb;             /**< O/H Coarse Classification base */
++      uint32_t fmbm_oim;              /**< O/H Internal margins*/
++      uint32_t fmbm_ofp;              /**< O/H Fifo Parameters*/
++      uint32_t fmbm_ofed;             /**< O/H Frame End Data*/
++      uint32_t reserved0030[2];       /**< (0x038 - 0x03F) */
++      uint32_t fmbm_oprai[FMAN_PORT_PRS_RESULT_WORDS_NUM];
++                              /**< O/H Parse Results Array Initialization  */
++      uint32_t fmbm_ofqid;            /**< O/H Frame Queue ID  */
++      uint32_t fmbm_oefqid;           /**< O/H Error Frame Queue ID  */
++      uint32_t fmbm_ofsdm;            /**< O/H Frame Status Discard Mask  */
++      uint32_t fmbm_ofsem;            /**< O/H Frame Status Error Mask  */
++      uint32_t fmbm_ofene;            /**< O/H Frame Enqueue Next Engine  */
++      uint32_t fmbm_orlmts;           /**< O/H Rate Limiter Scale  */
++      uint32_t fmbm_orlmt;            /**< O/H Rate Limiter  */
++      uint32_t fmbm_ocmne;            /**< O/H Continuous Mode Next Engine  */
++      uint32_t reserved0080[0x20];    /**< 0x080 - 0x0FF Reserved */
++      uint32_t fmbm_oebmpi[2];        /**< Buf Mngr Observed Pool Info */
++      uint32_t reserved0108[0x16];    /**< 0x108 - 0x15F Reserved */
++      uint32_t fmbm_ocgm[FMAN_PORT_CG_MAP_NUM]; /**< Observed Congestion Group Map */
++      uint32_t fmbm_ompd;             /**< Observed BMan Pool Depletion */
++      uint32_t reserved0184[0x1F];    /**< 0x184 - 0x1FF Reserved */
++      uint32_t fmbm_ostc;             /**< O/H Statistics Counters  */
++      uint32_t fmbm_ofrc;             /**< O/H Frame Counter  */
++      uint32_t fmbm_ofdc;             /**< O/H Frames Discard Counter  */
++      uint32_t fmbm_ofledc;           /**< O/H Frames Len Err Discard Cntr */
++      uint32_t fmbm_ofufdc;           /**< O/H Frames Unsprtd Discard Cutr  */
++      uint32_t fmbm_offc;             /**< O/H Filter Frames Counter  */
++      uint32_t fmbm_ofwdc;            /**< Rx Frames WRED Discard Counter  */
++      uint32_t fmbm_ofldec;           /**< O/H Frames List DMA Error Cntr */
++      uint32_t fmbm_obdc;             /**< O/H Buffers Deallocate Counter */
++      uint32_t reserved0218[0x17];    /**< (0x218 - 0x27F) */
++      uint32_t fmbm_opc;              /**< O/H Performance Counters  */
++      uint32_t fmbm_opcp;             /**< O/H Performance Count Parameters */
++      uint32_t fmbm_occn;             /**< O/H Cycle Counter  */
++      uint32_t fmbm_otuc;             /**< O/H Tasks Utilization Counter  */
++      uint32_t fmbm_oduc;             /**< O/H DMA Utilization Counter */
++      uint32_t fmbm_ofuc;             /**< O/H FIFO Utilization Counter */
++};
++
++/** @Description   BMI port register map */
++union fman_port_bmi_regs {
++      struct fman_port_rx_bmi_regs rx;
++      struct fman_port_tx_bmi_regs tx;
++      struct fman_port_oh_bmi_regs oh;
++};
++
++/** @Description   QMI port register map */
++struct fman_port_qmi_regs {
++      uint32_t fmqm_pnc;              /**< PortID n Configuration Register */
++      uint32_t fmqm_pns;              /**< PortID n Status Register */
++      uint32_t fmqm_pnts;             /**< PortID n Task Status Register */
++      uint32_t reserved00c[4];        /**< 0xn00C - 0xn01B */
++      uint32_t fmqm_pnen;             /**< PortID n Enqueue NIA Register */
++      uint32_t fmqm_pnetfc;           /**< PortID n Enq Total Frame Counter */
++      uint32_t reserved024[2];        /**< 0xn024 - 0x02B */
++      uint32_t fmqm_pndn;             /**< PortID n Dequeue NIA Register */
++      uint32_t fmqm_pndc;             /**< PortID n Dequeue Config Register */
++      uint32_t fmqm_pndtfc;           /**< PortID n Dequeue tot Frame cntr */
++      uint32_t fmqm_pndfdc;           /**< PortID n Dequeue FQID Dflt Cntr */
++      uint32_t fmqm_pndcc;            /**< PortID n Dequeue Confirm Counter */
++};
++
++
++enum fman_port_dma_swap {
++      E_FMAN_PORT_DMA_NO_SWAP,        /**< No swap, transfer data as is */
++      E_FMAN_PORT_DMA_SWAP_LE,
++      /**< The transferred data should be swapped in PPC Little Endian mode */
++      E_FMAN_PORT_DMA_SWAP_BE
++      /**< The transferred data should be swapped in Big Endian mode */
++};
++
++/* Default port color */
++enum fman_port_color {
++      E_FMAN_PORT_COLOR_GREEN,        /**< Default port color is green */
++      E_FMAN_PORT_COLOR_YELLOW,       /**< Default port color is yellow */
++      E_FMAN_PORT_COLOR_RED,          /**< Default port color is red */
++      E_FMAN_PORT_COLOR_OVERRIDE      /**< Ignore color */
++};
++
++/* QMI dequeue from the SP channel - types */
++enum fman_port_deq_type {
++      E_FMAN_PORT_DEQ_BY_PRI,
++      /**< Priority precedence and Intra-Class scheduling */
++      E_FMAN_PORT_DEQ_ACTIVE_FQ,
++      /**< Active FQ precedence and Intra-Class scheduling */
++      E_FMAN_PORT_DEQ_ACTIVE_FQ_NO_ICS
++      /**< Active FQ precedence and override Intra-Class scheduling */
++};
++
++/* QMI dequeue prefetch modes */
++enum fman_port_deq_prefetch {
++      E_FMAN_PORT_DEQ_NO_PREFETCH, /**< No prefetch mode */
++      E_FMAN_PORT_DEQ_PART_PREFETCH, /**< Partial prefetch mode */
++      E_FMAN_PORT_DEQ_FULL_PREFETCH /**< Full prefetch mode */
++};
++
++/* Parameters for defining performance counters behavior */
++struct fman_port_perf_cnt_params {
++      uint8_t task_val;       /**< Task compare value */
++      uint8_t queue_val;
++      /**< Rx or Tx conf queue compare value (unused for O/H ports) */
++      uint8_t dma_val;        /**< Dma compare value */
++      uint32_t fifo_val;      /**< Fifo compare value (in bytes) */
++};
++
++/** @Description   FM Port configuration structure, used at init */
++struct fman_port_cfg {
++      struct fman_port_perf_cnt_params perf_cnt_params;
++      /* BMI parameters */
++      enum fman_port_dma_swap         dma_swap_data;
++      bool                            dma_ic_stash_on;
++      bool                            dma_header_stash_on;
++      bool                            dma_sg_stash_on;
++      bool                            dma_write_optimize;
++      uint16_t                        ic_ext_offset;
++      uint8_t                         ic_int_offset;
++      uint16_t                        ic_size;
++      enum fman_port_color            color;
++      bool                            sync_req;
++      bool                            discard_override;
++      uint8_t                         checksum_bytes_ignore;
++      uint8_t                         rx_cut_end_bytes;
++      uint32_t                        rx_pri_elevation;
++      uint32_t                        rx_fifo_thr;
++      uint8_t                         rx_fd_bits;
++      uint8_t                         int_buf_start_margin;
++      uint16_t                        ext_buf_start_margin;
++      uint16_t                        ext_buf_end_margin;
++      uint32_t                        tx_fifo_min_level;
++      uint32_t                        tx_fifo_low_comf_level;
++      uint8_t                         tx_fifo_deq_pipeline_depth;
++      bool                            stats_counters_enable;
++      bool                            perf_counters_enable;
++      /* QMI parameters */
++      bool                            deq_high_pri;
++      enum fman_port_deq_type         deq_type;
++      enum fman_port_deq_prefetch     deq_prefetch_opt;
++      uint16_t                        deq_byte_cnt;
++      bool                            queue_counters_enable;
++      bool                            no_scatter_gather;
++      int                             errata_A006675;
++      int                             errata_A006320;
++      int                             excessive_threshold_register;
++      int                             fmbm_rebm_has_sgd;
++      int                             fmbm_tfne_has_features;
++      int                             qmi_deq_options_support;
++};
++
++enum fman_port_type {
++      E_FMAN_PORT_TYPE_OP = 0,
++      /**< Offline parsing port, shares id-s with
++       * host command, so must have exclusive id-s */
++      E_FMAN_PORT_TYPE_RX,        /**< 1G Rx port */
++      E_FMAN_PORT_TYPE_RX_10G,    /**< 10G Rx port */
++      E_FMAN_PORT_TYPE_TX,        /**< 1G Tx port */
++      E_FMAN_PORT_TYPE_TX_10G,     /**< 10G Tx port */
++      E_FMAN_PORT_TYPE_DUMMY,
++      E_FMAN_PORT_TYPE_HC = E_FMAN_PORT_TYPE_DUMMY
++      /**< Host command port, shares id-s with
++       * offline parsing ports, so must have exclusive id-s */
++};
++
++struct fman_port_params {
++      uint32_t discard_mask;
++      uint32_t err_mask;
++      uint32_t dflt_fqid;
++      uint32_t err_fqid;
++      uint8_t deq_sp;
++      bool dont_release_buf;
++};
++
++/* Port context - used by most API functions */
++struct fman_port {
++      enum fman_port_type type;
++      uint8_t fm_rev_maj;
++      uint8_t fm_rev_min;
++      union fman_port_bmi_regs *bmi_regs;
++      struct fman_port_qmi_regs *qmi_regs;
++      bool im_en;
++      uint8_t ext_pools_num;
++};
++
++/** @Description   External buffer pools configuration */
++struct fman_port_bpools {
++      uint8_t count;                  /**< Num of pools to set up */
++      bool    counters_enable;        /**< Enable allocate counters */
++      uint8_t grp_bp_depleted_num;
++      /**< Number of depleted pools - if reached the BMI indicates
++       * the MAC to send a pause frame */
++      struct {
++              uint8_t         bpid;   /**< BM pool ID */
++              uint16_t        size;
++              /**< Pool's size - must be in ascending order */
++              bool            is_backup;
++              /**< If this is a backup pool */
++              bool            grp_bp_depleted;
++              /**< Consider this buffer in multiple pools depletion criteria*/
++              bool            single_bp_depleted;
++              /**< Consider this buffer in single pool depletion criteria */
++              bool            pfc_priorities_en;
++      } bpool[FMAN_PORT_MAX_EXT_POOLS_NUM];
++};
++
++enum fman_port_rate_limiter_scale_down {
++      E_FMAN_PORT_RATE_DOWN_NONE,
++      E_FMAN_PORT_RATE_DOWN_BY_2,
++      E_FMAN_PORT_RATE_DOWN_BY_4,
++      E_FMAN_PORT_RATE_DOWN_BY_8
++};
++
++/* Rate limiter configuration */
++struct fman_port_rate_limiter {
++      uint8_t         count_1micro_bit;
++      bool            high_burst_size_gran;
++      /**< Defines burst_size granularity for OP ports; when TRUE,
++       * burst_size below counts in frames, otherwise in 10^3 frames */
++      uint16_t        burst_size;
++      /**< Max burst size, in KBytes for Tx port, according to
++       * high_burst_size_gran definition for OP port */
++      uint32_t        rate;
++      /**< In Kbps for Tx port, in frames/sec for OP port */
++      enum fman_port_rate_limiter_scale_down rate_factor;
++};
++
++/* BMI statistics counters */
++enum fman_port_stats_counters {
++      E_FMAN_PORT_STATS_CNT_FRAME,
++      /**< Number of processed frames; valid for all ports */
++      E_FMAN_PORT_STATS_CNT_DISCARD,
++      /**< For Rx ports - frames discarded by QMAN, for Tx or O/H ports -
++       * frames discarded due to DMA error; valid for all ports */
++      E_FMAN_PORT_STATS_CNT_DEALLOC_BUF,
++      /**< Number of buffer deallocate operations; valid for all ports */
++      E_FMAN_PORT_STATS_CNT_RX_BAD_FRAME,
++      /**< Number of bad Rx frames, like CRC error, Rx FIFO overflow etc;
++       * valid for Rx ports only */
++      E_FMAN_PORT_STATS_CNT_RX_LARGE_FRAME,
++      /**< Number of Rx oversized frames, that is frames exceeding max frame
++       * size configured for the corresponding ETH controller;
++       * valid for Rx ports only */
++      E_FMAN_PORT_STATS_CNT_RX_OUT_OF_BUF,
++      /**< Frames discarded due to lack of external buffers; valid for
++       * Rx ports only */
++      E_FMAN_PORT_STATS_CNT_LEN_ERR,
++      /**< Frames discarded due to frame length error; valid for Tx and
++       * O/H ports only */
++      E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT,
++      /**< Frames discarded due to unsupported FD format; valid for Tx
++       * and O/H ports only */
++      E_FMAN_PORT_STATS_CNT_FILTERED_FRAME,
++      /**< Number of frames filtered out by PCD module; valid for
++       * Rx and OP ports only */
++      E_FMAN_PORT_STATS_CNT_DMA_ERR,
++      /**< Frames rejected by QMAN that were not able to release their
++       * buffers due to DMA error; valid for Rx and O/H ports only */
++      E_FMAN_PORT_STATS_CNT_WRED_DISCARD
++      /**< Frames going through O/H port that were not able to to enter the
++       * return queue due to WRED algorithm; valid for O/H ports only */
++};
++
++/* BMI performance counters */
++enum fman_port_perf_counters {
++      E_FMAN_PORT_PERF_CNT_CYCLE,     /**< Cycle counter */
++      E_FMAN_PORT_PERF_CNT_TASK_UTIL, /**< Tasks utilization counter */
++      E_FMAN_PORT_PERF_CNT_QUEUE_UTIL,
++      /**< For Rx ports - Rx queue utilization, for Tx ports - Tx conf queue
++       * utilization; not valid for O/H ports */
++      E_FMAN_PORT_PERF_CNT_DMA_UTIL,  /**< DMA utilization counter */
++      E_FMAN_PORT_PERF_CNT_FIFO_UTIL, /**< FIFO utilization counter */
++      E_FMAN_PORT_PERF_CNT_RX_PAUSE
++      /**< Number of cycles in which Rx pause activation control is on;
++       * valid for Rx ports only */
++};
++
++/* QMI counters */
++enum fman_port_qmi_counters {
++      E_FMAN_PORT_ENQ_TOTAL,  /**< EnQ tot frame cntr */
++      E_FMAN_PORT_DEQ_TOTAL,  /**< DeQ tot frame cntr; invalid for Rx ports */
++      E_FMAN_PORT_DEQ_FROM_DFLT,
++      /**< Dequeue from default FQID counter not valid for Rx ports */
++      E_FMAN_PORT_DEQ_CONFIRM /**< DeQ confirm cntr invalid for Rx ports */
++};
++
++
++/** @Collection    FM Port API */
++void fman_port_defconfig(struct fman_port_cfg *cfg, enum fman_port_type type);
++int fman_port_init(struct fman_port *port,
++              struct fman_port_cfg *cfg,
++              struct fman_port_params *params);
++int fman_port_enable(struct fman_port *port);
++int fman_port_disable(const struct fman_port *port);
++int fman_port_set_bpools(const struct fman_port *port,
++              const struct fman_port_bpools *bp);
++int fman_port_set_rate_limiter(struct fman_port *port,
++              struct fman_port_rate_limiter *rate_limiter);
++int fman_port_delete_rate_limiter(struct fman_port *port);
++int fman_port_set_err_mask(struct fman_port *port, uint32_t err_mask);
++int fman_port_set_discard_mask(struct fman_port *port, uint32_t discard_mask);
++int fman_port_modify_rx_fd_bits(struct fman_port *port,
++              uint8_t rx_fd_bits,
++              bool add);
++int fman_port_set_perf_cnt_params(struct fman_port *port,
++              struct fman_port_perf_cnt_params *params);
++int fman_port_set_stats_cnt_mode(struct fman_port *port, bool enable);
++int fman_port_set_perf_cnt_mode(struct fman_port *port, bool enable);
++int fman_port_set_queue_cnt_mode(struct fman_port *port, bool enable);
++int fman_port_set_bpool_cnt_mode(struct fman_port *port,
++              uint8_t bpid,
++              bool enable);
++uint32_t fman_port_get_stats_counter(struct fman_port *port,
++              enum fman_port_stats_counters counter);
++void fman_port_set_stats_counter(struct fman_port *port,
++              enum fman_port_stats_counters counter,
++              uint32_t value);
++uint32_t fman_port_get_perf_counter(struct fman_port *port,
++              enum fman_port_perf_counters counter);
++void fman_port_set_perf_counter(struct fman_port *port,
++              enum fman_port_perf_counters counter,
++              uint32_t value);
++uint32_t fman_port_get_qmi_counter(struct fman_port *port,
++              enum fman_port_qmi_counters counter);
++void fman_port_set_qmi_counter(struct fman_port *port,
++              enum fman_port_qmi_counters counter,
++              uint32_t value);
++uint32_t fman_port_get_bpool_counter(struct fman_port *port, uint8_t bpid);
++void fman_port_set_bpool_counter(struct fman_port *port,
++              uint8_t bpid,
++              uint32_t value);
++int fman_port_add_congestion_grps(struct fman_port *port,
++              uint32_t grps_map[FMAN_PORT_CG_MAP_NUM]);
++int fman_port_remove_congestion_grps(struct fman_port  *port,
++              uint32_t grps_map[FMAN_PORT_CG_MAP_NUM]);
++
++
++#endif /* __FSL_FMAN_PORT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_prs.h
+@@ -0,0 +1,102 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __FSL_FMAN_PRS_H
++#define __FSL_FMAN_PRS_H
++
++#include "common/general.h"
++
++#define FM_PCD_EX_PRS_DOUBLE_ECC      0x02000000
++#define FM_PCD_EX_PRS_SINGLE_ECC      0x01000000
++
++#define FM_PCD_PRS_PPSC_ALL_PORTS     0xffff0000
++#define FM_PCD_PRS_RPIMAC_EN          0x00000001
++#define FM_PCD_PRS_PORT_IDLE_STS      0xffff0000
++#define FM_PCD_PRS_SINGLE_ECC         0x00004000
++#define FM_PCD_PRS_DOUBLE_ECC         0x00004000
++#define PRS_MAX_CYCLE_LIMIT           8191
++
++#define DEFAULT_MAX_PRS_CYC_LIM               0
++
++struct fman_prs_regs {
++      uint32_t fmpr_rpclim;
++      uint32_t fmpr_rpimac;
++      uint32_t pmeec;
++      uint32_t res00c[5];
++      uint32_t fmpr_pevr;
++      uint32_t fmpr_pever;
++      uint32_t res028;
++      uint32_t fmpr_perr;
++      uint32_t fmpr_perer;
++      uint32_t res034;
++      uint32_t res038[10];
++      uint32_t fmpr_ppsc;
++      uint32_t res064;
++      uint32_t fmpr_pds;
++      uint32_t fmpr_l2rrs;
++      uint32_t fmpr_l3rrs;
++      uint32_t fmpr_l4rrs;
++      uint32_t fmpr_srrs;
++      uint32_t fmpr_l2rres;
++      uint32_t fmpr_l3rres;
++      uint32_t fmpr_l4rres;
++      uint32_t fmpr_srres;
++      uint32_t fmpr_spcs;
++      uint32_t fmpr_spscs;
++      uint32_t fmpr_hxscs;
++      uint32_t fmpr_mrcs;
++      uint32_t fmpr_mwcs;
++      uint32_t fmpr_mrscs;
++      uint32_t fmpr_mwscs;
++      uint32_t fmpr_fcscs;
++};
++
++struct fman_prs_cfg {
++      uint32_t        port_id_stat;
++      uint16_t        max_prs_cyc_lim;
++      uint32_t        prs_exceptions;
++};
++
++uint32_t fman_prs_get_err_event(struct fman_prs_regs *regs, uint32_t ev_mask);
++uint32_t fman_prs_get_err_ev_mask(struct fman_prs_regs *regs);
++void fman_prs_ack_err_event(struct fman_prs_regs *regs, uint32_t event);
++uint32_t fman_prs_get_expt_event(struct fman_prs_regs *regs, uint32_t ev_mask);
++uint32_t fman_prs_get_expt_ev_mask(struct fman_prs_regs *regs);
++void fman_prs_ack_expt_event(struct fman_prs_regs *regs, uint32_t event);
++void fman_prs_defconfig(struct fman_prs_cfg *cfg);
++int fman_prs_init(struct fman_prs_regs *regs, struct fman_prs_cfg *cfg);
++void fman_prs_enable(struct fman_prs_regs *regs);
++void fman_prs_disable(struct fman_prs_regs *regs);
++int fman_prs_is_enabled(struct fman_prs_regs *regs);
++void fman_prs_set_stst_port_msk(struct fman_prs_regs *regs, uint32_t pid_msk);
++void fman_prs_set_stst(struct fman_prs_regs *regs, bool enable);
++#endif /* __FSL_FMAN_PRS_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_rtc.h
+@@ -0,0 +1,449 @@
++/*
++ * Copyright 2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __FSL_FMAN_RTC_H
++#define __FSL_FMAN_RTC_H
++
++#include "common/general.h"
++
++/* FM RTC Registers definitions */
++#define FMAN_RTC_TMR_CTRL_ALMP1                  0x80000000
++#define FMAN_RTC_TMR_CTRL_ALMP2                  0x40000000
++#define FMAN_RTC_TMR_CTRL_FS                     0x10000000
++#define FMAN_RTC_TMR_CTRL_PP1L                   0x08000000
++#define FMAN_RTC_TMR_CTRL_PP2L                   0x04000000
++#define FMAN_RTC_TMR_CTRL_TCLK_PERIOD_MASK       0x03FF0000
++#define FMAN_RTC_TMR_CTRL_FRD                    0x00004000
++#define FMAN_RTC_TMR_CTRL_SLV                    0x00002000
++#define FMAN_RTC_TMR_CTRL_ETEP1                  0x00000100
++#define FMAN_RTC_TMR_CTRL_COPH                   0x00000080
++#define FMAN_RTC_TMR_CTRL_CIPH                   0x00000040
++#define FMAN_RTC_TMR_CTRL_TMSR                   0x00000020
++#define FMAN_RTC_TMR_CTRL_DBG                    0x00000010
++#define FMAN_RTC_TMR_CTRL_BYP                    0x00000008
++#define FMAN_RTC_TMR_CTRL_TE                     0x00000004
++#define FMAN_RTC_TMR_CTRL_CKSEL_OSC_CLK          0x00000003
++#define FMAN_RTC_TMR_CTRL_CKSEL_MAC_CLK          0x00000001
++#define FMAN_RTC_TMR_CTRL_CKSEL_EXT_CLK          0x00000000
++#define FMAN_RTC_TMR_CTRL_TCLK_PERIOD_SHIFT      16
++
++#define FMAN_RTC_TMR_TEVENT_ETS2                 0x02000000
++#define FMAN_RTC_TMR_TEVENT_ETS1                 0x01000000
++#define FMAN_RTC_TMR_TEVENT_ALM2                 0x00020000
++#define FMAN_RTC_TMR_TEVENT_ALM1                 0x00010000
++#define FMAN_RTC_TMR_TEVENT_PP1                  0x00000080
++#define FMAN_RTC_TMR_TEVENT_PP2                  0x00000040
++#define FMAN_RTC_TMR_TEVENT_PP3                  0x00000020
++#define FMAN_RTC_TMR_TEVENT_ALL                  (FMAN_RTC_TMR_TEVENT_ETS2 |\
++                                              FMAN_RTC_TMR_TEVENT_ETS1 |\
++                                              FMAN_RTC_TMR_TEVENT_ALM2 |\
++                                              FMAN_RTC_TMR_TEVENT_ALM1 |\
++                                              FMAN_RTC_TMR_TEVENT_PP1 |\
++                                              FMAN_RTC_TMR_TEVENT_PP2 |\
++                                              FMAN_RTC_TMR_TEVENT_PP3)
++
++#define FMAN_RTC_TMR_PRSC_OCK_MASK               0x0000FFFF
++
++/**************************************************************************//**
++ @Description   FM RTC Alarm Polarity Options.
++*//***************************************************************************/
++enum fman_rtc_alarm_polarity {
++    E_FMAN_RTC_ALARM_POLARITY_ACTIVE_HIGH,  /**< Active-high output polarity */
++    E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW    /**< Active-low output polarity */
++};
++
++/**************************************************************************//**
++ @Description   FM RTC Trigger Polarity Options.
++*//***************************************************************************/
++enum fman_rtc_trigger_polarity {
++    E_FMAN_RTC_TRIGGER_ON_RISING_EDGE,    /**< Trigger on rising edge */
++    E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE    /**< Trigger on falling edge */
++};
++
++/**************************************************************************//**
++ @Description   IEEE1588 Timer Module FM RTC Optional Clock Sources.
++*//***************************************************************************/
++enum fman_src_clock {
++    E_FMAN_RTC_SOURCE_CLOCK_EXTERNAL,  /**< external high precision timer
++                                              reference clock */
++    E_FMAN_RTC_SOURCE_CLOCK_SYSTEM,    /**< MAC system clock */
++    E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR  /**< RTC clock oscilator */
++};
++
++/* RTC default values */
++#define DEFAULT_SRC_CLOCK                E_FMAN_RTC_SOURCE_CLOCK_SYSTEM
++#define DEFAULT_INVERT_INPUT_CLK_PHASE   FALSE
++#define DEFAULT_INVERT_OUTPUT_CLK_PHASE  FALSE
++#define DEFAULT_ALARM_POLARITY           E_FMAN_RTC_ALARM_POLARITY_ACTIVE_HIGH
++#define DEFAULT_TRIGGER_POLARITY         E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE
++#define DEFAULT_PULSE_REALIGN            FALSE
++
++#define FMAN_RTC_MAX_NUM_OF_ALARMS 3
++#define FMAN_RTC_MAX_NUM_OF_PERIODIC_PULSES 4
++#define FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS 3
++
++/**************************************************************************//**
++ @Description FM RTC timer alarm
++*//***************************************************************************/
++struct t_tmr_alarm{
++    uint32_t   tmr_alarm_h;    /**<  */
++    uint32_t   tmr_alarm_l;    /**<  */
++};
++
++/**************************************************************************//**
++ @Description FM RTC timer Ex trigger
++*//***************************************************************************/
++struct t_tmr_ext_trigger{
++    uint32_t   tmr_etts_h;     /**<  */
++    uint32_t   tmr_etts_l;     /**<  */
++};
++
++struct rtc_regs {
++    uint32_t tmr_id;      /* 0x000 Module ID register */
++    uint32_t tmr_id2;     /* 0x004 Controller ID register */
++    uint32_t reserved0008[30];
++    uint32_t tmr_ctrl;    /* 0x0080 timer control register */
++    uint32_t tmr_tevent;  /* 0x0084 timer event register */
++    uint32_t tmr_temask;  /* 0x0088 timer event mask register */
++    uint32_t reserved008c[3];
++    uint32_t tmr_cnt_h;   /* 0x0098 timer counter high register */
++    uint32_t tmr_cnt_l;   /* 0x009c timer counter low register */
++    uint32_t tmr_add;     /* 0x00a0 timer drift compensation addend register */
++    uint32_t tmr_acc;     /* 0x00a4 timer accumulator register */
++    uint32_t tmr_prsc;    /* 0x00a8 timer prescale */
++    uint32_t reserved00ac;
++    uint32_t tmr_off_h;    /* 0x00b0 timer offset high */
++    uint32_t tmr_off_l;    /* 0x00b4 timer offset low  */
++    struct t_tmr_alarm tmr_alarm[FMAN_RTC_MAX_NUM_OF_ALARMS]; /* 0x00b8 timer
++                                                              alarm */
++    uint32_t tmr_fiper[FMAN_RTC_MAX_NUM_OF_PERIODIC_PULSES]; /* 0x00d0 timer
++                                              fixed period interval */
++    struct t_tmr_ext_trigger tmr_etts[FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS];
++                      /* 0x00e0 time stamp general purpose external */
++    uint32_t reserved00f0[4];
++};
++
++struct rtc_cfg {
++    enum fman_src_clock            src_clk;
++    uint32_t                ext_src_clk_freq;
++    uint32_t                rtc_freq_hz;
++    bool                    timer_slave_mode;
++    bool                    invert_input_clk_phase;
++    bool                    invert_output_clk_phase;
++    uint32_t                events_mask;
++    bool                    bypass; /**< Indicates if frequency compensation
++                                      is bypassed */
++    bool                    pulse_realign;
++    enum fman_rtc_alarm_polarity    alarm_polarity[FMAN_RTC_MAX_NUM_OF_ALARMS];
++    enum fman_rtc_trigger_polarity  trigger_polarity
++                                      [FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS];
++};
++
++/**
++ * fman_rtc_defconfig() - Get default RTC configuration
++ * @cfg:      pointer to configuration structure.
++ *
++ * Call this function to obtain a default set of configuration values for
++ * initializing RTC.  The user can overwrite any of the values before calling
++ * fman_rtc_init(), if specific configuration needs to be applied.
++ */
++void fman_rtc_defconfig(struct rtc_cfg *cfg);
++
++/**
++ * fman_rtc_get_events() - Get the events
++ * @regs:             Pointer to RTC register block
++ *
++ * Returns: The events
++ */
++uint32_t fman_rtc_get_events(struct rtc_regs *regs);
++
++/**
++ * fman_rtc_get_interrupt_mask() - Get the events mask
++ * @regs:             Pointer to RTC register block
++ *
++ * Returns: The events mask
++ */
++uint32_t fman_rtc_get_interrupt_mask(struct rtc_regs *regs);
++
++
++/**
++ * fman_rtc_set_interrupt_mask() - Set the events mask
++ * @regs:             Pointer to RTC register block
++ * @mask:             The mask to set
++ */
++void fman_rtc_set_interrupt_mask(struct rtc_regs *regs, uint32_t mask);
++
++/**
++ * fman_rtc_get_event() - Check if specific events occurred
++ * @regs:             Pointer to RTC register block
++ * @ev_mask:  a mask of the events to check
++ *
++ * Returns: 0 if the events did not occur. Non zero if one of the events occurred
++ */
++uint32_t fman_rtc_get_event(struct rtc_regs *regs, uint32_t ev_mask);
++
++/**
++ * fman_rtc_check_and_clear_event() - Clear events which are on
++ * @regs:             Pointer to RTC register block
++ *
++ * Returns: A mask of the events which were cleared
++ */
++uint32_t fman_rtc_check_and_clear_event(struct rtc_regs *regs);
++
++/**
++ * fman_rtc_ack_event() - Clear events
++ * @regs:             Pointer to RTC register block
++ * @events:           The events to disable
++ */
++void fman_rtc_ack_event(struct rtc_regs *regs, uint32_t events);
++
++/**
++ * fman_rtc_enable_interupt() - Enable events interrupts
++ * @regs:             Pointer to RTC register block
++ * @mask:             The events to disable
++ */
++void fman_rtc_enable_interupt(struct rtc_regs *regs, uint32_t mask);
++
++/**
++ * fman_rtc_disable_interupt() - Disable events interrupts
++ * @regs:             Pointer to RTC register block
++ * @mask:             The events to disable
++ */
++void fman_rtc_disable_interupt(struct rtc_regs *regs, uint32_t mask);
++
++/**
++ * fman_rtc_get_timer_ctrl() - Get the control register
++ * @regs:             Pointer to RTC register block
++ *
++ * Returns: The control register value
++ */
++uint32_t fman_rtc_get_timer_ctrl(struct rtc_regs *regs);
++
++/**
++ * fman_rtc_set_timer_ctrl() - Set timer control register
++ * @regs:             Pointer to RTC register block
++ * @val:              The value to set
++ */
++void fman_rtc_set_timer_ctrl(struct rtc_regs *regs, uint32_t val);
++
++/**
++ * fman_rtc_get_frequency_compensation() - Get the frequency compensation
++ * @regs:             Pointer to RTC register block
++ *
++ * Returns: The timer counter
++ */
++uint32_t fman_rtc_get_frequency_compensation(struct rtc_regs *regs);
++
++/**
++ * fman_rtc_set_frequency_compensation() - Set frequency compensation
++ * @regs:             Pointer to RTC register block
++ * @val:              The value to set
++ */
++void fman_rtc_set_frequency_compensation(struct rtc_regs *regs, uint32_t val);
++
++/**
++ * fman_rtc_get_trigger_stamp() - Get a trigger stamp
++ * @regs:             Pointer to RTC register block
++ * @id:       The id of the trigger stamp
++ *
++ * Returns: The time stamp
++ */
++uint64_t fman_rtc_get_trigger_stamp(struct rtc_regs *regs,  int id);
++
++/**
++ * fman_rtc_set_timer_alarm_l() - Set timer alarm low register
++ * @regs:             Pointer to RTC register block
++ * @index:            The index of alarm to set
++ * @val:              The value to set
++ */
++void fman_rtc_set_timer_alarm_l(struct rtc_regs *regs, int index,
++              uint32_t val);
++
++/**
++ * fman_rtc_set_timer_alarm() - Set timer alarm
++ * @regs:             Pointer to RTC register block
++ * @index:            The index of alarm to set
++ * @val:              The value to set
++ */
++void fman_rtc_set_timer_alarm(struct rtc_regs *regs, int index, int64_t val);
++
++/**
++ * fman_rtc_set_timer_fiper() - Set timer fiper
++ * @regs:             Pointer to RTC register block
++ * @index:            The index of fiper to set
++ * @val:              The value to set
++ */
++void fman_rtc_set_timer_fiper(struct rtc_regs *regs, int index, uint32_t val);
++
++/**
++ * fman_rtc_set_timer_offset() - Set timer offset
++ * @regs:             Pointer to RTC register block
++ * @val:              The value to set
++ */
++void fman_rtc_set_timer_offset(struct rtc_regs *regs, int64_t val);
++
++/**
++ * fman_rtc_get_timer() - Get the timer counter
++ * @regs:             Pointer to RTC register block
++ *
++ * Returns: The timer counter
++ */
++static inline uint64_t fman_rtc_get_timer(struct rtc_regs *regs)
++{
++      uint64_t time;
++    /* TMR_CNT_L must be read first to get an accurate value */
++    time = (uint64_t)ioread32be(&regs->tmr_cnt_l);
++    time |= ((uint64_t)ioread32be(&regs->tmr_cnt_h) << 32);
++
++    return time;
++}
++
++/**
++ * fman_rtc_set_timer() - Set timer counter
++ * @regs:             Pointer to RTC register block
++ * @val:              The value to set
++ */
++static inline void fman_rtc_set_timer(struct rtc_regs *regs, int64_t val)
++{
++      iowrite32be((uint32_t)val, &regs->tmr_cnt_l);
++      iowrite32be((uint32_t)(val >> 32), &regs->tmr_cnt_h);
++}
++
++/**
++ * fman_rtc_timers_soft_reset() - Soft reset
++ * @regs:             Pointer to RTC register block
++ *
++ * Resets all the timer registers and state machines for the 1588 IP and
++ * the attached client 1588
++ */
++void fman_rtc_timers_soft_reset(struct rtc_regs *regs);
++
++/**
++ * fman_rtc_clear_external_trigger() - Clear an external trigger
++ * @regs:             Pointer to RTC register block
++ * @id: The id of the trigger to clear
++ */
++void fman_rtc_clear_external_trigger(struct rtc_regs *regs, int id);
++
++/**
++ * fman_rtc_clear_periodic_pulse() - Clear periodic pulse
++ * @regs:             Pointer to RTC register block
++ * @id: The id of the fiper to clear
++ */
++void fman_rtc_clear_periodic_pulse(struct rtc_regs *regs, int id);
++
++/**
++ * fman_rtc_enable() - Enable RTC hardware block
++ * @regs:             Pointer to RTC register block
++ */
++void fman_rtc_enable(struct rtc_regs *regs, bool reset_clock);
++
++/**
++ * fman_rtc_is_enabled() - Is RTC hardware block enabled
++ * @regs:             Pointer to RTC register block
++ *
++ * Return: TRUE if enabled
++ */
++bool fman_rtc_is_enabled(struct rtc_regs *regs);
++
++/**
++ * fman_rtc_disable() - Disable RTC hardware block
++ * @regs:             Pointer to RTC register block
++ */
++void fman_rtc_disable(struct rtc_regs *regs);
++
++/**
++ * fman_rtc_init() - Init RTC hardware block
++ * @cfg:              RTC configuration data
++ * @regs:             Pointer to RTC register block
++ * @num_alarms:               Number of alarms in RTC
++ * @num_fipers:               Number of fipers in RTC
++ * @num_ext_triggers: Number of external triggers in RTC
++ * @freq_compensation:                Frequency compensation
++ * @output_clock_divisor:             Output clock divisor
++ *
++ * This function initializes RTC and applies basic configuration.
++ */
++void fman_rtc_init(struct rtc_cfg *cfg, struct rtc_regs *regs, int num_alarms,
++              int num_fipers, int num_ext_triggers, bool init_freq_comp,
++              uint32_t freq_compensation, uint32_t output_clock_divisor);
++
++/**
++ * fman_rtc_set_alarm() - Set an alarm
++ * @regs:             Pointer to RTC register block
++ * @id:                       id of alarm
++ * @val:              value to write
++ * @enable:           should interrupt be enabled
++ */
++void fman_rtc_set_alarm(struct rtc_regs *regs, int id, uint32_t val, bool enable);
++
++/**
++ * fman_rtc_set_periodic_pulse() - Set an alarm
++ * @regs:             Pointer to RTC register block
++ * @id:                       id of fiper
++ * @val:              value to write
++ * @enable:           should interrupt be enabled
++ */
++void fman_rtc_set_periodic_pulse(struct rtc_regs *regs, int id, uint32_t val,
++      bool enable);
++
++/**
++ * fman_rtc_set_ext_trigger() - Set an external trigger
++ * @regs:             Pointer to RTC register block
++ * @id:                       id of trigger
++ * @enable:           should interrupt be enabled
++ * @use_pulse_as_input: use the pulse as input
++ */
++void fman_rtc_set_ext_trigger(struct rtc_regs *regs, int id, bool enable,
++      bool use_pulse_as_input);
++
++struct fm_rtc_alarm_params {
++      uint8_t alarm_id;               /**< 0 or 1 */
++      uint64_t alarm_time;            /**< In nanoseconds, the time when the
++                                      alarm should go off - must be a
++                                      multiple of the RTC period */
++      void (*f_alarm_callback)(void* app, uint8_t id); /**< This routine will
++                                      be called when RTC reaches alarmTime */
++      bool clear_on_expiration;       /**< TRUE to turn off the alarm once
++                                      expired.*/
++};
++
++struct fm_rtc_periodic_pulse_params {
++      uint8_t periodic_pulse_id;      /**< 0 or 1 */
++      uint64_t periodic_pulse_period; /**< In Nanoseconds. Must be a multiple
++                                      of the RTC period */
++      void (*f_periodic_pulse_callback)(void* app, uint8_t id); /**< This
++                                      routine will be called every
++                                      periodicPulsePeriod. */
++};
++
++#endif /* __FSL_FMAN_RTC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_sp.h
+@@ -0,0 +1,138 @@
++/*
++ * Copyright 2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __FSL_FMAN_SP_H
++#define __FSL_FMAN_SP_H
++
++#include "common/general.h"
++#include "fsl_fman.h"
++
++
++struct fm_pcd_storage_profile_regs{
++      uint32_t   fm_sp_ebmpi[8];
++                                      /*offset 0 - 0xc*/
++                                      /**< Buffer Manager pool Information */
++
++      uint32_t   fm_sp_acnt;      /*offset 0x20*/
++      uint32_t   fm_sp_ebm;       /*offset 0x24*/
++      uint32_t   fm_sp_da;        /*offset 0x28*/
++      uint32_t   fm_sp_icp;       /*offset 0x2c*/
++      uint32_t   fm_sp_mpd;       /*offset 0x30*/
++      uint32_t   res1[2];         /*offset 0x34 - 0x38*/
++      uint32_t   fm_sp_spliodn;   /*offset 0x3c*/
++};
++
++/**************************************************************************//**
++ @Description   structure for defining internal context copying
++*//***************************************************************************/
++struct fman_sp_int_context_data_copy{
++      uint16_t ext_buf_offset;     /**< Offset in External buffer to which
++                                      internal context is copied to (Rx)
++                                      or taken from (Tx, Op). */
++      uint8_t int_context_offset; /**< Offset within internal context to copy
++                                      from (Rx) or to copy to (Tx, Op).*/
++      uint16_t size;             /**< Internal offset size to be copied */
++};
++
++/**************************************************************************//**
++ @Description   struct for defining external buffer margins
++*//***************************************************************************/
++struct fman_sp_buf_margins{
++      uint16_t start_margins; /**< Number of bytes to be left at the
++                              beginning of the external buffer (must be
++                              divisible by 16) */
++      uint16_t end_margins;   /**< number of bytes to be left at the end of
++                               the external buffer(must be divisible by 16)*/
++};
++
++struct fm_storage_profile_params {
++      struct fman_ext_pools                   fm_ext_pools;
++      struct fman_backup_bm_pools             backup_pools;
++      struct fman_sp_int_context_data_copy    *int_context;
++      struct fman_sp_buf_margins              *buf_margins;
++      enum fman_dma_swap_option               dma_swap_data;
++      enum fman_dma_cache_option              int_context_cache_attr;
++      enum fman_dma_cache_option              header_cache_attr;
++      enum fman_dma_cache_option              scatter_gather_cache_attr;
++      bool                                    dma_write_optimize;
++      uint16_t                                liodn_offset;
++      bool                                    no_scather_gather;
++      struct fman_buf_pool_depletion        buf_pool_depletion;
++};
++
++/**************************************************************************//**
++ @Description       Registers bit fields
++*//***************************************************************************/
++#define FMAN_SP_EXT_BUF_POOL_EN_COUNTER             0x40000000
++#define FMAN_SP_EXT_BUF_POOL_VALID                  0x80000000
++#define FMAN_SP_EXT_BUF_POOL_BACKUP                 0x20000000
++#define FMAN_SP_DMA_ATTR_WRITE_OPTIMIZE             0x00100000
++#define FMAN_SP_SG_DISABLE                          0x80000000
++
++/* shifts */
++#define FMAN_SP_EXT_BUF_POOL_ID_SHIFT               16
++#define FMAN_SP_POOL_DEP_NUM_OF_POOLS_SHIFT         16
++#define FMAN_SP_EXT_BUF_MARG_START_SHIFT            16
++#define FMAN_SP_EXT_BUF_MARG_END_SHIFT              0
++#define FMAN_SP_DMA_ATTR_SWP_SHIFT                  30
++#define FMAN_SP_DMA_ATTR_IC_CACHE_SHIFT             28
++#define FMAN_SP_DMA_ATTR_HDR_CACHE_SHIFT            26
++#define FMAN_SP_DMA_ATTR_SG_CACHE_SHIFT             24
++#define FMAN_SP_IC_TO_EXT_SHIFT                     16
++#define FMAN_SP_IC_FROM_INT_SHIFT                   8
++#define FMAN_SP_IC_SIZE_SHIFT                       0
++
++/**************************************************************************//**
++ @Description       defaults
++*//***************************************************************************/
++#define DEFAULT_FMAN_SP_DMA_SWAP_DATA                         FMAN_DMA_NO_SWP
++#define DEFAULT_FMAN_SP_DMA_INT_CONTEXT_CACHE_ATTR            FMAN_DMA_NO_STASH
++#define DEFAULT_FMAN_SP_DMA_HEADER_CACHE_ATTR                 FMAN_DMA_NO_STASH
++#define DEFAULT_FMAN_SP_DMA_SCATTER_GATHER_CACHE_ATTR         FMAN_DMA_NO_STASH
++#define DEFAULT_FMAN_SP_DMA_WRITE_OPTIMIZE                    TRUE
++#define DEFAULT_FMAN_SP_NO_SCATTER_GATHER                     FALSE
++
++void fman_vsp_defconfig(struct fm_storage_profile_params *cfg);
++
++void fman_vsp_init(struct fm_pcd_storage_profile_regs   *regs,
++      uint16_t index, struct fm_storage_profile_params *fm_vsp_params,
++      int port_max_num_of_ext_pools, int bm_max_num_of_pools,
++      int max_num_of_pfc_priorities);
++
++uint32_t fman_vsp_get_statistics(struct fm_pcd_storage_profile_regs *regs,
++                                      uint16_t index);
++
++void fman_vsp_set_statistics(struct fm_pcd_storage_profile_regs *regs,
++                      uint16_t index, uint32_t value);
++
++
++#endif /* __FSL_FMAN_SP_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_tgec.h
+@@ -0,0 +1,479 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __FSL_FMAN_TGEC_H
++#define __FSL_FMAN_TGEC_H
++
++#include "common/general.h"
++#include "fsl_enet.h"
++
++
++/* Transmit Inter-Packet Gap Length Register (TX_IPG_LENGTH) */
++#define TGEC_TX_IPG_LENGTH_MASK       0x000003ff
++
++enum tgec_counters {
++      E_TGEC_COUNTER_R64,
++      E_TGEC_COUNTER_R127,
++      E_TGEC_COUNTER_R255,
++      E_TGEC_COUNTER_R511,
++      E_TGEC_COUNTER_R1023,
++      E_TGEC_COUNTER_R1518,
++      E_TGEC_COUNTER_R1519X,
++      E_TGEC_COUNTER_TRFRG,
++      E_TGEC_COUNTER_TRJBR,
++      E_TGEC_COUNTER_RDRP,
++      E_TGEC_COUNTER_RALN,
++      E_TGEC_COUNTER_TRUND,
++      E_TGEC_COUNTER_TROVR,
++      E_TGEC_COUNTER_RXPF,
++      E_TGEC_COUNTER_TXPF,
++      E_TGEC_COUNTER_ROCT,
++      E_TGEC_COUNTER_RMCA,
++      E_TGEC_COUNTER_RBCA,
++      E_TGEC_COUNTER_RPKT,
++      E_TGEC_COUNTER_RUCA,
++      E_TGEC_COUNTER_RERR,
++      E_TGEC_COUNTER_TOCT,
++      E_TGEC_COUNTER_TMCA,
++      E_TGEC_COUNTER_TBCA,
++      E_TGEC_COUNTER_TUCA,
++      E_TGEC_COUNTER_TERR
++};
++
++/* Command and Configuration Register (COMMAND_CONFIG) */
++#define CMD_CFG_EN_TIMESTAMP  0x00100000
++#define CMD_CFG_TX_ADDR_INS_SEL       0x00080000
++#define CMD_CFG_NO_LEN_CHK    0x00020000
++#define CMD_CFG_SEND_IDLE     0x00010000
++#define CMD_CFG_RX_ER_DISC    0x00004000
++#define CMD_CFG_CMD_FRM_EN    0x00002000
++#define CMD_CFG_STAT_CLR      0x00001000
++#define CMD_CFG_LOOPBACK_EN   0x00000400
++#define CMD_CFG_TX_ADDR_INS   0x00000200
++#define CMD_CFG_PAUSE_IGNORE  0x00000100
++#define CMD_CFG_PAUSE_FWD     0x00000080
++#define CMD_CFG_PROMIS_EN     0x00000010
++#define CMD_CFG_WAN_MODE      0x00000008
++#define CMD_CFG_RX_EN         0x00000002
++#define CMD_CFG_TX_EN         0x00000001
++
++/* Interrupt Mask Register (IMASK) */
++#define TGEC_IMASK_MDIO_SCAN_EVENT    0x00010000
++#define TGEC_IMASK_MDIO_CMD_CMPL      0x00008000
++#define TGEC_IMASK_REM_FAULT          0x00004000
++#define TGEC_IMASK_LOC_FAULT          0x00002000
++#define TGEC_IMASK_TX_ECC_ER          0x00001000
++#define TGEC_IMASK_TX_FIFO_UNFL               0x00000800
++#define TGEC_IMASK_TX_FIFO_OVFL               0x00000400
++#define TGEC_IMASK_TX_ER                      0x00000200
++#define TGEC_IMASK_RX_FIFO_OVFL               0x00000100
++#define TGEC_IMASK_RX_ECC_ER          0x00000080
++#define TGEC_IMASK_RX_JAB_FRM         0x00000040
++#define TGEC_IMASK_RX_OVRSZ_FRM               0x00000020
++#define TGEC_IMASK_RX_RUNT_FRM                0x00000010
++#define TGEC_IMASK_RX_FRAG_FRM                0x00000008
++#define TGEC_IMASK_RX_LEN_ER          0x00000004
++#define TGEC_IMASK_RX_CRC_ER          0x00000002
++#define TGEC_IMASK_RX_ALIGN_ER                0x00000001
++
++#define TGEC_EVENTS_MASK                                      \
++      ((uint32_t)(TGEC_IMASK_MDIO_SCAN_EVENT                  | \
++                              TGEC_IMASK_MDIO_CMD_CMPL        | \
++                              TGEC_IMASK_REM_FAULT            | \
++                              TGEC_IMASK_LOC_FAULT            | \
++                              TGEC_IMASK_TX_ECC_ER            | \
++                              TGEC_IMASK_TX_FIFO_UNFL         | \
++                              TGEC_IMASK_TX_FIFO_OVFL         | \
++                              TGEC_IMASK_TX_ER                | \
++                              TGEC_IMASK_RX_FIFO_OVFL         | \
++                              TGEC_IMASK_RX_ECC_ER            | \
++                              TGEC_IMASK_RX_JAB_FRM           | \
++                              TGEC_IMASK_RX_OVRSZ_FRM         | \
++                              TGEC_IMASK_RX_RUNT_FRM          | \
++                              TGEC_IMASK_RX_FRAG_FRM          | \
++                              TGEC_IMASK_RX_LEN_ER            | \
++                              TGEC_IMASK_RX_CRC_ER            | \
++                              TGEC_IMASK_RX_ALIGN_ER))
++
++/* Hashtable Control Register (HASHTABLE_CTRL) */
++#define TGEC_HASH_MCAST_SHIFT 23
++#define TGEC_HASH_MCAST_EN    0x00000200
++#define TGEC_HASH_ADR_MSK     0x000001ff
++
++#define DEFAULT_WAN_MODE_ENABLE               FALSE
++#define DEFAULT_PROMISCUOUS_MODE_ENABLE       FALSE
++#define DEFAULT_PAUSE_FORWARD_ENABLE  FALSE
++#define DEFAULT_PAUSE_IGNORE          FALSE
++#define DEFAULT_TX_ADDR_INS_ENABLE    FALSE
++#define DEFAULT_LOOPBACK_ENABLE               FALSE
++#define DEFAULT_CMD_FRAME_ENABLE      FALSE
++#define DEFAULT_RX_ERROR_DISCARD      FALSE
++#define DEFAULT_SEND_IDLE_ENABLE      FALSE
++#define DEFAULT_NO_LENGTH_CHECK_ENABLE        TRUE
++#define DEFAULT_LGTH_CHECK_NOSTDR     FALSE
++#define DEFAULT_TIME_STAMP_ENABLE     FALSE
++#define DEFAULT_TX_IPG_LENGTH         12
++#define DEFAULT_MAX_FRAME_LENGTH      0x600
++#define DEFAULT_PAUSE_QUANT           0xf000
++
++/*
++ * 10G memory map
++ */
++struct tgec_regs {
++      uint32_t tgec_id;               /* 0x000 Controller ID */
++      uint32_t reserved001[1];        /* 0x004 */
++      uint32_t command_config;        /* 0x008 Control and configuration */
++      uint32_t mac_addr_0;            /* 0x00c Lower 32 bits of the MAC adr */
++      uint32_t mac_addr_1;            /* 0x010 Upper 16 bits of the MAC adr */
++      uint32_t maxfrm;                /* 0x014 Maximum frame length */
++      uint32_t pause_quant;           /* 0x018 Pause quanta */
++      uint32_t rx_fifo_sections;      /* 0x01c  */
++      uint32_t tx_fifo_sections;      /* 0x020  */
++      uint32_t rx_fifo_almost_f_e;    /* 0x024  */
++      uint32_t tx_fifo_almost_f_e;    /* 0x028  */
++      uint32_t hashtable_ctrl;        /* 0x02c Hash table control*/
++      uint32_t mdio_cfg_status;       /* 0x030  */
++      uint32_t mdio_command;          /* 0x034  */
++      uint32_t mdio_data;             /* 0x038  */
++      uint32_t mdio_regaddr;          /* 0x03c  */
++      uint32_t status;                /* 0x040  */
++      uint32_t tx_ipg_len;            /* 0x044 Transmitter inter-packet-gap */
++      uint32_t mac_addr_2;            /* 0x048 Lower 32 bits of 2nd MAC adr */
++      uint32_t mac_addr_3;            /* 0x04c Upper 16 bits of 2nd MAC adr */
++      uint32_t rx_fifo_ptr_rd;        /* 0x050  */
++      uint32_t rx_fifo_ptr_wr;        /* 0x054  */
++      uint32_t tx_fifo_ptr_rd;        /* 0x058  */
++      uint32_t tx_fifo_ptr_wr;        /* 0x05c  */
++      uint32_t imask;                 /* 0x060 Interrupt mask */
++      uint32_t ievent;                /* 0x064 Interrupt event */
++      uint32_t udp_port;              /* 0x068 Defines a UDP Port number */
++      uint32_t type_1588v2;           /* 0x06c Type field for 1588v2 */
++      uint32_t reserved070[4];        /* 0x070 */
++      /*10Ge Statistics Counter */
++      uint32_t tfrm_u;                /* 80 aFramesTransmittedOK */
++      uint32_t tfrm_l;                /* 84 aFramesTransmittedOK */
++      uint32_t rfrm_u;                /* 88 aFramesReceivedOK */
++      uint32_t rfrm_l;                /* 8c aFramesReceivedOK */
++      uint32_t rfcs_u;                /* 90 aFrameCheckSequenceErrors */
++      uint32_t rfcs_l;                /* 94 aFrameCheckSequenceErrors */
++      uint32_t raln_u;                /* 98 aAlignmentErrors */
++      uint32_t raln_l;                /* 9c aAlignmentErrors */
++      uint32_t txpf_u;                /* A0 aPAUSEMACCtrlFramesTransmitted */
++      uint32_t txpf_l;                /* A4 aPAUSEMACCtrlFramesTransmitted */
++      uint32_t rxpf_u;                /* A8 aPAUSEMACCtrlFramesReceived */
++      uint32_t rxpf_l;                /* Ac aPAUSEMACCtrlFramesReceived */
++      uint32_t rlong_u;               /* B0 aFrameTooLongErrors */
++      uint32_t rlong_l;               /* B4 aFrameTooLongErrors */
++      uint32_t rflr_u;                /* B8 aInRangeLengthErrors */
++      uint32_t rflr_l;                /* Bc aInRangeLengthErrors */
++      uint32_t tvlan_u;               /* C0 VLANTransmittedOK */
++      uint32_t tvlan_l;               /* C4 VLANTransmittedOK */
++      uint32_t rvlan_u;               /* C8 VLANReceivedOK */
++      uint32_t rvlan_l;               /* Cc VLANReceivedOK */
++      uint32_t toct_u;                /* D0 ifOutOctets */
++      uint32_t toct_l;                /* D4 ifOutOctets */
++      uint32_t roct_u;                /* D8 ifInOctets */
++      uint32_t roct_l;                /* Dc ifInOctets */
++      uint32_t ruca_u;                /* E0 ifInUcastPkts */
++      uint32_t ruca_l;                /* E4 ifInUcastPkts */
++      uint32_t rmca_u;                /* E8 ifInMulticastPkts */
++      uint32_t rmca_l;                /* Ec ifInMulticastPkts */
++      uint32_t rbca_u;                /* F0 ifInBroadcastPkts */
++      uint32_t rbca_l;                /* F4 ifInBroadcastPkts */
++      uint32_t terr_u;                /* F8 ifOutErrors */
++      uint32_t terr_l;                /* Fc ifOutErrors */
++      uint32_t reserved100[2];        /* 100-108*/
++      uint32_t tuca_u;                /* 108 ifOutUcastPkts */
++      uint32_t tuca_l;                /* 10c ifOutUcastPkts */
++      uint32_t tmca_u;                /* 110 ifOutMulticastPkts */
++      uint32_t tmca_l;                /* 114 ifOutMulticastPkts */
++      uint32_t tbca_u;                /* 118 ifOutBroadcastPkts */
++      uint32_t tbca_l;                /* 11c ifOutBroadcastPkts */
++      uint32_t rdrp_u;                /* 120 etherStatsDropEvents */
++      uint32_t rdrp_l;                /* 124 etherStatsDropEvents */
++      uint32_t reoct_u;               /* 128 etherStatsOctets */
++      uint32_t reoct_l;               /* 12c etherStatsOctets */
++      uint32_t rpkt_u;                /* 130 etherStatsPkts */
++      uint32_t rpkt_l;                /* 134 etherStatsPkts */
++      uint32_t trund_u;               /* 138 etherStatsUndersizePkts */
++      uint32_t trund_l;               /* 13c etherStatsUndersizePkts */
++      uint32_t r64_u;                 /* 140 etherStatsPkts64Octets */
++      uint32_t r64_l;                 /* 144 etherStatsPkts64Octets */
++      uint32_t r127_u;                /* 148 etherStatsPkts65to127Octets */
++      uint32_t r127_l;                /* 14c etherStatsPkts65to127Octets */
++      uint32_t r255_u;                /* 150 etherStatsPkts128to255Octets */
++      uint32_t r255_l;                /* 154 etherStatsPkts128to255Octets */
++      uint32_t r511_u;                /* 158 etherStatsPkts256to511Octets */
++      uint32_t r511_l;                /* 15c etherStatsPkts256to511Octets */
++      uint32_t r1023_u;               /* 160 etherStatsPkts512to1023Octets */
++      uint32_t r1023_l;               /* 164 etherStatsPkts512to1023Octets */
++      uint32_t r1518_u;               /* 168 etherStatsPkts1024to1518Octets */
++      uint32_t r1518_l;               /* 16c etherStatsPkts1024to1518Octets */
++      uint32_t r1519x_u;              /* 170 etherStatsPkts1519toX */
++      uint32_t r1519x_l;              /* 174 etherStatsPkts1519toX */
++      uint32_t trovr_u;               /* 178 etherStatsOversizePkts */
++      uint32_t trovr_l;               /* 17c etherStatsOversizePkts */
++      uint32_t trjbr_u;               /* 180 etherStatsJabbers */
++      uint32_t trjbr_l;               /* 184 etherStatsJabbers */
++      uint32_t trfrg_u;               /* 188 etherStatsFragments */
++      uint32_t trfrg_l;               /* 18C etherStatsFragments */
++      uint32_t rerr_u;                /* 190 ifInErrors */
++      uint32_t rerr_l;                /* 194 ifInErrors */
++};
++
++/**
++ * struct tgec_cfg - TGEC configuration
++ *
++ * @rx_error_discard:    Receive Erroneous Frame Discard Enable. When set to 1
++ *            any frame received with an error is discarded in the
++ *            Core and not forwarded to the Client interface.
++ *            When set to 0 (Reset value), erroneous Frames are
++ *            forwarded to the Client interface with ff_rx_err
++ *            asserted.
++ * @pause_ignore:    Ignore Pause Frame Quanta. If set to 1 received pause
++ *            frames are ignored by the MAC. When set to 0
++ *            (Reset value) the transmit process is stopped for the
++ *            amount of time specified in the pause quanta received
++ *            within a pause frame.
++ * @pause_forward_enable:
++ *            Terminate / Forward Pause Frames. If set to 1 pause
++ *            frames are forwarded to the user application. When set
++ *            to 0 (Reset value) pause frames are terminated and
++ *            discarded within the MAC.
++ * @no_length_check_enable:
++ *            Payload Length Check Disable. When set to 0
++ *            (Reset value), the Core checks the frame's payload
++ *            length with the Frame Length/Type field, when set to 1
++ *            the payload length check is disabled.
++ * @cmd_frame_enable:    Enables reception of all command frames. When set to 1
++ *            all Command Frames are accepted, when set to 0
++ *            (Reset Value) only Pause Frames are accepted and all
++ *            other Command Frames are rejected.
++ * @send_idle_enable:    Force Idle Generation. When set to 1, the MAC
++ *            permanently sends XGMII Idle sequences even when faults
++ *            are received.
++ * @wan_mode_enable:    WAN Mode Enable. Sets WAN mode (1) or LAN mode
++ *            (0, default) of operation.
++ * @promiscuous_mode_enable:
++ *            Enables MAC promiscuous operation. When set to 1, all
++ *            frames are received without any MAC address filtering,
++ *            when set to 0 (Reset value) Unicast Frames with a
++ *            destination address not matching the Core MAC Address
++ *            (MAC Address programmed in Registers MAC_ADDR_0 and
++ *            MAC_ADDR_1 or the MAC address programmed in Registers
++ *            MAC_ADDR_2 and MAC_ADDR_3) are rejected.
++ * @tx_addr_ins_enable:    Set Source MAC Address on Transmit. If set to 1 the
++ *            MAC overwrites the source MAC address received from the
++ *            Client Interface with one of the MAC addresses. If set
++ *            to 0 (Reset value), the source MAC address from the
++ *            Client Interface is transmitted unmodified to the line.
++ * @loopback_enable:    PHY Interface Loopback. When set to 1, the signal
++ *            loop_ena is set to '1', when set to 0 (Reset value)
++ *            the signal loop_ena is set to 0.
++ * @lgth_check_nostdr:    The Core interprets the Length/Type field differently
++ *            depending on the value of this Bit
++ * @time_stamp_enable:    This bit selects between enabling and disabling the
++ *            IEEE 1588 functionality. 1: IEEE 1588 is enabled
++ *            0: IEEE 1588 is disabled
++ * @max_frame_length:    Maximum supported received frame length.
++ *            The 10GEC MAC supports reception of any frame size up
++ *            to 16,352 bytes (0x3FE0). Typical settings are
++ *            0x05EE (1,518 bytes) for standard frames.
++ *            Default setting is 0x0600 (1,536 bytes).
++ *            Received frames that exceed this stated maximum
++ *            are truncated.
++ * @pause_quant:    Pause quanta value used with transmitted pause frames.
++ *            Each quanta represents a 512 bit-times.
++ * @tx_ipg_length:    Transmit Inter-Packet-Gap (IPG) value. A 6-bit value:
++ *            Depending on LAN or WAN mode of operation the value has
++ *            the following meaning: - LAN Mode: Number of octets in
++ *            steps of 4. Valid values are 8, 12, 16, ... 100. DIC is
++ *            fully supported (see 10.6.1 page 49) for any setting. A
++ *            default of 12 (reset value) must be set to conform to
++ *            IEEE802.3ae. Warning: When set to 8, PCS layers may not
++ *            be able to perform clock rate compensation. - WAN Mode:
++ *            Stretch factor. Valid values are 4..15. The stretch
++ *            factor is calculated as (value+1)*8. A default of 12
++ *            (reset value) must be set to conform to IEEE 802.3ae
++ *            (i.e. 13*8=104). A larger value shrinks the IPG
++ *            (increasing bandwidth).
++ *
++ * This structure contains basic TGEC configuration and must be passed to
++ * fman_tgec_init() function.  A default set of configuration values can be
++ * obtained by calling fman_tgec_defconfig().
++ */
++struct tgec_cfg {
++      bool            rx_error_discard;
++      bool            pause_ignore;
++      bool            pause_forward_enable;
++      bool            no_length_check_enable;
++      bool            cmd_frame_enable;
++      bool            send_idle_enable;
++      bool            wan_mode_enable;
++      bool            promiscuous_mode_enable;
++      bool            tx_addr_ins_enable;
++      bool            loopback_enable;
++      bool            lgth_check_nostdr;
++      bool            time_stamp_enable;
++      uint16_t        max_frame_length;
++      uint16_t        pause_quant;
++      uint32_t        tx_ipg_length;
++      bool            skip_fman11_workaround;
++};
++
++
++void fman_tgec_defconfig(struct tgec_cfg *cfg);
++
++/**
++ * fman_tgec_init() - Init tgec hardware block
++ * @regs:        Pointer to tgec register block
++ * @cfg:        tgec configuration data
++ * @exceptions_mask:    initial exceptions mask
++ *
++ * This function initializes the tgec controller and applies its
++ * basic configuration.
++ *
++ * Returns: 0 if successful, an error code otherwise.
++ */
++
++int fman_tgec_init(struct tgec_regs *regs, struct tgec_cfg *cfg,
++      uint32_t exception_mask);
++
++void fman_tgec_enable(struct tgec_regs *regs, bool apply_rx, bool apply_tx);
++
++void fman_tgec_disable(struct tgec_regs *regs, bool apply_rx, bool apply_tx);
++
++uint32_t fman_tgec_get_revision(struct tgec_regs *regs);
++
++void fman_tgec_set_mac_address(struct tgec_regs *regs, uint8_t *macaddr);
++
++void fman_tgec_set_promiscuous(struct tgec_regs *regs, bool val);
++
++/**
++ * fman_tgec_reset_stat() - Completely resets all TGEC HW counters
++ * @regs:    Pointer to TGEC register block
++ */
++void fman_tgec_reset_stat(struct tgec_regs *regs);
++
++/**
++ * fman_tgec_get_counter() - Reads TGEC HW counters
++ * @regs:    Pointer to TGEC register block
++ * @reg_name:    Counter name according to the appropriate enum
++ *
++ * Returns:    Required counter value
++ */
++uint64_t fman_tgec_get_counter(struct tgec_regs *regs,
++      enum tgec_counters reg_name);
++
++/**
++ * fman_tgec_set_hash_table() - Sets the Hashtable Control Register
++ * @regs:    Pointer to TGEC register block
++ * @value:    Value to be written in Hashtable Control Register
++ */
++void fman_tgec_set_hash_table(struct tgec_regs *regs, uint32_t value);
++
++/**
++ * fman_tgec_set_tx_pause_frames() - Sets the Pause Quanta Register
++ * @regs:    Pointer to TGEC register block
++ * @pause_time:    Pause quanta value used with transmitted pause frames.
++ *        Each quanta represents a 512 bit-times
++ */
++void fman_tgec_set_tx_pause_frames(struct tgec_regs *regs, uint16_t pause_time);
++
++/**
++ * fman_tgec_set_rx_ignore_pause_frames() - Changes the policy WRT pause frames
++ * @regs:    Pointer to TGEC register block
++ * @en:        Ignore/Respond to pause frame quanta
++ *
++ * Sets the value of PAUSE_IGNORE field in the COMMAND_CONFIG Register
++ * 0 - MAC stops transmit process for the duration specified
++ * in the Pause frame quanta of a received Pause frame.
++ * 1 - MAC ignores received Pause frames.
++ */
++void fman_tgec_set_rx_ignore_pause_frames(struct tgec_regs *regs, bool en);
++
++/**
++ * fman_tgec_enable_1588_time_stamp() - change timestamp functionality
++ * @regs:    Pointer to TGEC register block
++ * @en:        enable/disable timestamp functionality
++ *
++ * Sets the value of EN_TIMESTAMP field in the COMMAND_CONFIG Register
++ * IEEE 1588 timestamp functionality control:
++ * 0 disabled, 1 enabled
++ */
++
++void fman_tgec_enable_1588_time_stamp(struct tgec_regs *regs, bool en);
++
++uint32_t fman_tgec_get_event(struct tgec_regs *regs, uint32_t ev_mask);
++
++void fman_tgec_ack_event(struct tgec_regs *regs, uint32_t ev_mask);
++
++uint32_t fman_tgec_get_interrupt_mask(struct tgec_regs *regs);
++
++/**
++ * fman_tgec_add_addr_in_paddr() - Sets additional exact match MAC address
++ * @regs:    Pointer to TGEC register block
++ * @addr_ptr:    Pointer to 6-byte array containing the MAC address
++ *
++ * Sets the additional station MAC address
++ */
++void fman_tgec_add_addr_in_paddr(struct tgec_regs *regs, uint8_t *addr_ptr);
++
++void fman_tgec_clear_addr_in_paddr(struct tgec_regs *regs);
++
++void fman_tgec_enable_interrupt(struct tgec_regs *regs, uint32_t ev_mask);
++
++void fman_tgec_disable_interrupt(struct tgec_regs *regs, uint32_t ev_mask);
++
++void fman_tgec_reset_filter_table(struct tgec_regs *regs);
++
++void fman_tgec_set_hash_table_entry(struct tgec_regs *regs, uint32_t crc);
++
++
++/**
++ * fman_tgec_get_max_frame_len() - Returns the maximum frame length value
++ * @regs:    Pointer to TGEC register block
++ */
++uint16_t fman_tgec_get_max_frame_len(struct tgec_regs *regs);
++
++/**
++ * fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007() - Initialize the
++ * main tgec configuration parameters
++ * @regs:    Pointer to TGEC register block
++ *
++ * TODO
++ */
++void fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(struct tgec_regs
++      *regs);
++
++
++#endif /* __FSL_FMAN_TGEC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/dpaa_integration_ext.h
+@@ -0,0 +1,291 @@
++/*
++ * Copyright 2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**
++
++ @File          dpaa_integration_ext.h
++
++ @Description   T4240 FM external definitions and structures.
++*//***************************************************************************/
++#ifndef __DPAA_INTEGRATION_EXT_H
++#define __DPAA_INTEGRATION_EXT_H
++
++#include "std_ext.h"
++
++
++#define DPAA_VERSION    11
++
++/**************************************************************************//**
++ @Description   DPAA SW Portals Enumeration.
++*//***************************************************************************/
++typedef enum
++{
++    e_DPAA_SWPORTAL0 = 0,
++    e_DPAA_SWPORTAL1,
++    e_DPAA_SWPORTAL2,
++    e_DPAA_SWPORTAL3,
++    e_DPAA_SWPORTAL4,
++    e_DPAA_SWPORTAL5,
++    e_DPAA_SWPORTAL6,
++    e_DPAA_SWPORTAL7,
++    e_DPAA_SWPORTAL8,
++    e_DPAA_SWPORTAL9,
++    e_DPAA_SWPORTAL10,
++    e_DPAA_SWPORTAL11,
++    e_DPAA_SWPORTAL12,
++    e_DPAA_SWPORTAL13,
++    e_DPAA_SWPORTAL14,
++    e_DPAA_SWPORTAL15,
++    e_DPAA_SWPORTAL16,
++    e_DPAA_SWPORTAL17,
++    e_DPAA_SWPORTAL18,
++    e_DPAA_SWPORTAL19,
++    e_DPAA_SWPORTAL20,
++    e_DPAA_SWPORTAL21,
++    e_DPAA_SWPORTAL22,
++    e_DPAA_SWPORTAL23,
++    e_DPAA_SWPORTAL24,
++    e_DPAA_SWPORTAL_DUMMY_LAST
++} e_DpaaSwPortal;
++
++/**************************************************************************//**
++ @Description   DPAA Direct Connect Portals Enumeration.
++*//***************************************************************************/
++typedef enum
++{
++    e_DPAA_DCPORTAL0 = 0,
++    e_DPAA_DCPORTAL1,
++    e_DPAA_DCPORTAL2,
++    e_DPAA_DCPORTAL_DUMMY_LAST
++} e_DpaaDcPortal;
++
++#define DPAA_MAX_NUM_OF_SW_PORTALS      e_DPAA_SWPORTAL_DUMMY_LAST
++#define DPAA_MAX_NUM_OF_DC_PORTALS      e_DPAA_DCPORTAL_DUMMY_LAST
++
++/*****************************************************************************
++ QMan INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define QM_MAX_NUM_OF_POOL_CHANNELS     15      /**< Total number of channels, dedicated and pool */
++#define QM_MAX_NUM_OF_WQ                8       /**< Number of work queues per channel */
++#define QM_MAX_NUM_OF_CGS               256     /**< Congestion groups number */
++#define QM_MAX_NUM_OF_FQIDS             (16 * MEGABYTE)
++                                                /**< FQIDs range - 24 bits */
++
++/**************************************************************************//**
++ @Description   Work Queue Channel assignments in QMan.
++*//***************************************************************************/
++typedef enum
++{
++    e_QM_FQ_CHANNEL_SWPORTAL0 = 0x0,              /**< Dedicated channels serviced by software portals 0 to 24 */
++    e_QM_FQ_CHANNEL_SWPORTAL1,
++    e_QM_FQ_CHANNEL_SWPORTAL2,
++    e_QM_FQ_CHANNEL_SWPORTAL3,
++    e_QM_FQ_CHANNEL_SWPORTAL4,
++    e_QM_FQ_CHANNEL_SWPORTAL5,
++    e_QM_FQ_CHANNEL_SWPORTAL6,
++    e_QM_FQ_CHANNEL_SWPORTAL7,
++    e_QM_FQ_CHANNEL_SWPORTAL8,
++    e_QM_FQ_CHANNEL_SWPORTAL9,
++    e_QM_FQ_CHANNEL_SWPORTAL10,
++    e_QM_FQ_CHANNEL_SWPORTAL11,
++    e_QM_FQ_CHANNEL_SWPORTAL12,
++    e_QM_FQ_CHANNEL_SWPORTAL13,
++    e_QM_FQ_CHANNEL_SWPORTAL14,
++    e_QM_FQ_CHANNEL_SWPORTAL15,
++    e_QM_FQ_CHANNEL_SWPORTAL16,
++    e_QM_FQ_CHANNEL_SWPORTAL17,
++    e_QM_FQ_CHANNEL_SWPORTAL18,
++    e_QM_FQ_CHANNEL_SWPORTAL19,
++    e_QM_FQ_CHANNEL_SWPORTAL20,
++    e_QM_FQ_CHANNEL_SWPORTAL21,
++    e_QM_FQ_CHANNEL_SWPORTAL22,
++    e_QM_FQ_CHANNEL_SWPORTAL23,
++    e_QM_FQ_CHANNEL_SWPORTAL24,
++
++    e_QM_FQ_CHANNEL_POOL1 = 0x401,               /**< Pool channels that can be serviced by any of the software portals */
++    e_QM_FQ_CHANNEL_POOL2,
++    e_QM_FQ_CHANNEL_POOL3,
++    e_QM_FQ_CHANNEL_POOL4,
++    e_QM_FQ_CHANNEL_POOL5,
++    e_QM_FQ_CHANNEL_POOL6,
++    e_QM_FQ_CHANNEL_POOL7,
++    e_QM_FQ_CHANNEL_POOL8,
++    e_QM_FQ_CHANNEL_POOL9,
++    e_QM_FQ_CHANNEL_POOL10,
++    e_QM_FQ_CHANNEL_POOL11,
++    e_QM_FQ_CHANNEL_POOL12,
++    e_QM_FQ_CHANNEL_POOL13,
++    e_QM_FQ_CHANNEL_POOL14,
++    e_QM_FQ_CHANNEL_POOL15,
++
++    e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x800,           /**< Dedicated channels serviced by Direct Connect Portal 0:
++                                                      connected to FMan 0; assigned in incrementing order to
++                                                      each sub-portal (SP) in the portal */
++    e_QM_FQ_CHANNEL_FMAN0_SP1,
++    e_QM_FQ_CHANNEL_FMAN0_SP2,
++    e_QM_FQ_CHANNEL_FMAN0_SP3,
++    e_QM_FQ_CHANNEL_FMAN0_SP4,
++    e_QM_FQ_CHANNEL_FMAN0_SP5,
++    e_QM_FQ_CHANNEL_FMAN0_SP6,
++    e_QM_FQ_CHANNEL_FMAN0_SP7,
++    e_QM_FQ_CHANNEL_FMAN0_SP8,
++    e_QM_FQ_CHANNEL_FMAN0_SP9,
++    e_QM_FQ_CHANNEL_FMAN0_SP10,
++    e_QM_FQ_CHANNEL_FMAN0_SP11,
++    e_QM_FQ_CHANNEL_FMAN0_SP12,
++    e_QM_FQ_CHANNEL_FMAN0_SP13,
++    e_QM_FQ_CHANNEL_FMAN0_SP14,
++    e_QM_FQ_CHANNEL_FMAN0_SP15,
++
++    e_QM_FQ_CHANNEL_RMAN_SP0 = 0x820,            /**< Dedicated channels serviced by Direct Connect Portal 1: connected to RMan */
++    e_QM_FQ_CHANNEL_RMAN_SP1,
++
++    e_QM_FQ_CHANNEL_CAAM = 0x840                 /**< Dedicated channel serviced by Direct Connect Portal 2:
++                                                      connected to SEC */
++} e_QmFQChannel;
++
++/*****************************************************************************
++ BMan INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define BM_MAX_NUM_OF_POOLS         64          /**< Number of buffers pools */
++
++/*****************************************************************************
++ SEC INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define SEC_NUM_OF_DECOS            3
++#define SEC_ALL_DECOS_MASK          0x00000003
++
++
++/*****************************************************************************
++ FM INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define INTG_MAX_NUM_OF_FM          2
++/* Ports defines */
++#define FM_MAX_NUM_OF_1G_MACS       6
++#define FM_MAX_NUM_OF_10G_MACS      2
++#define FM_MAX_NUM_OF_MACS          (FM_MAX_NUM_OF_1G_MACS + FM_MAX_NUM_OF_10G_MACS)
++#define FM_MAX_NUM_OF_OH_PORTS      6
++
++#define FM_MAX_NUM_OF_1G_RX_PORTS   FM_MAX_NUM_OF_1G_MACS
++#define FM_MAX_NUM_OF_10G_RX_PORTS  FM_MAX_NUM_OF_10G_MACS
++#define FM_MAX_NUM_OF_RX_PORTS      (FM_MAX_NUM_OF_10G_RX_PORTS + FM_MAX_NUM_OF_1G_RX_PORTS)
++
++#define FM_MAX_NUM_OF_1G_TX_PORTS   FM_MAX_NUM_OF_1G_MACS
++#define FM_MAX_NUM_OF_10G_TX_PORTS  FM_MAX_NUM_OF_10G_MACS
++#define FM_MAX_NUM_OF_TX_PORTS      (FM_MAX_NUM_OF_10G_TX_PORTS + FM_MAX_NUM_OF_1G_TX_PORTS)
++
++#define FM_PORT_MAX_NUM_OF_EXT_POOLS            4           /**< Number of external BM pools per Rx port */
++#define FM_PORT_NUM_OF_CONGESTION_GRPS          256         /**< Total number of congestion groups in QM */
++#define FM_MAX_NUM_OF_SUB_PORTALS               16
++#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS   0
++
++#define FM_VSP_MAX_NUM_OF_ENTRIES               64
++#define FM_MAX_NUM_OF_PFC_PRIORITIES            8
++
++/* RAMs defines */
++#define FM_MURAM_SIZE                   (384 * KILOBYTE)
++#define FM_IRAM_SIZE(major, minor)      (64 * KILOBYTE)
++#define FM_NUM_OF_CTRL                  4
++
++/* PCD defines */
++#define FM_PCD_PLCR_NUM_ENTRIES         256                 /**< Total number of policer profiles */
++#define FM_PCD_KG_NUM_OF_SCHEMES        32                  /**< Total number of KG schemes */
++#define FM_PCD_MAX_NUM_OF_CLS_PLANS     256                 /**< Number of classification plan entries. */
++#define FM_PCD_PRS_SW_PATCHES_SIZE      0x00000600          /**< Number of bytes saved for patches */
++#define FM_PCD_SW_PRS_SIZE              0x00000800          /**< Total size of SW parser area */
++
++/* RTC defines */
++#define FM_RTC_NUM_OF_ALARMS            2                   /**< RTC number of alarms */
++#define FM_RTC_NUM_OF_PERIODIC_PULSES   3                   /**< RTC number of periodic pulses */
++#define FM_RTC_NUM_OF_EXT_TRIGGERS      2                   /**< RTC number of external triggers */
++
++/* QMI defines */
++#define QMI_MAX_NUM_OF_TNUMS            64
++#define QMI_DEF_TNUMS_THRESH            32
++/* FPM defines */
++#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS  4
++
++/* DMA defines */
++#define DMA_THRESH_MAX_COMMQ            83
++#define DMA_THRESH_MAX_BUF              127
++
++/* BMI defines */
++#define BMI_MAX_NUM_OF_TASKS            128
++#define BMI_MAX_NUM_OF_DMAS             84
++
++#define BMI_MAX_FIFO_SIZE               (FM_MURAM_SIZE)
++#define PORT_MAX_WEIGHT                 16
++
++#define FM_CHECK_PORT_RESTRICTIONS(__validPorts, __newPortIndx)   TRUE
++
++/* Unique T4240 */
++#define FM_OP_OPEN_DMA_MIN_LIMIT
++#define FM_NO_RESTRICT_ON_ACCESS_RSRC
++#define FM_NO_OP_OBSERVED_POOLS
++#define FM_FRAME_END_PARAMS_FOR_OP
++#define FM_DEQ_PIPELINE_PARAMS_FOR_OP
++#define FM_QMI_NO_SINGLE_ECC_EXCEPTION
++
++#define FM_NO_GUARANTEED_RESET_VALUES
++
++/* FM errata */
++#define FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
++#define FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127
++#define FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320
++#define FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675
++#define FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981
++#define FM_HANG_AT_RESET_MAC_CLK_DISABLED_ERRATA_FMAN_A007273
++
++#define FM_BCB_ERRATA_BMI_SW001
++#define FM_LEN_CHECK_ERRATA_FMAN_SW002
++#define FM_AID_MODE_NO_TNUM_SW005 /* refer to pdm TKT068794 - only support of port_id on aid */
++#define FM_ERROR_VSP_NO_MATCH_SW006 /* refer to pdm TKT174304 - no match between errorQ and VSP */
++
++/*****************************************************************************
++ RMan INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define RM_MAX_NUM_OF_IB        4           /**< Number of inbound blocks */
++#define RM_NUM_OF_IBCU          8           /**< NUmber of classification units in an inbound block */
++
++/* RMan erratas */
++#define RM_ERRONEOUS_ACK_ERRATA_RMAN_A006756
++
++/*****************************************************************************
++ FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define NUM_OF_RX_SC                16
++#define NUM_OF_TX_SC                16
++
++#define NUM_OF_SA_PER_RX_SC         2
++#define NUM_OF_SA_PER_TX_SC         2
++
++#endif /* __DPAA_INTEGRATION_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_ext.h
+@@ -0,0 +1,71 @@
++/*
++ * Copyright 2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**************************************************************************//**
++
++ @File          part_ext.h
++
++ @Description   Definitions for the part (integration) module.
++*//***************************************************************************/
++
++#ifndef __PART_EXT_H
++#define __PART_EXT_H
++
++#include "std_ext.h"
++#include "part_integration_ext.h"
++
++#if !(defined(P1023) || \
++      defined(P2041) || \
++      defined(P3041) || \
++      defined(P4080) || \
++      defined(P5020) || \
++      defined(P5040) || \
++      defined(B4860) || \
++      defined(T4240))
++#error "unable to proceed without chip-definition"
++#endif
++
++
++/**************************************************************************//*
++ @Description   Part data structure - must be contained in any integration
++                data structure.
++*//***************************************************************************/
++typedef struct t_Part
++{
++    uintptr_t   (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId);
++                /**< Returns the address of the module's memory map base. */
++    e_ModuleId  (* f_GetModuleIdByBase)(t_Handle h_Part, uintptr_t baseAddress);
++                /**< Returns the module's ID according to its memory map base. */
++} t_Part;
++
++
++#endif /* __PART_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_integration_ext.h
+@@ -0,0 +1,304 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**
++
++ @File          part_integration_ext.h
++
++ @Description   T4240 external definitions and structures.
++*//***************************************************************************/
++#ifndef __PART_INTEGRATION_EXT_H
++#define __PART_INTEGRATION_EXT_H
++
++#include "std_ext.h"
++#include "ddr_std_ext.h"
++#include "enet_ext.h"
++#include "dpaa_integration_ext.h"
++
++
++/**************************************************************************//**
++ @Group         T4240_chip_id T4240 Application Programming Interface
++
++ @Description   T4240 Chip functions,definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++#define CORE_E6500
++
++#define INTG_MAX_NUM_OF_CORES   24
++
++
++/**************************************************************************//**
++ @Description   Module types.
++*//***************************************************************************/
++typedef enum e_ModuleId
++{
++    e_MODULE_ID_DUART_1 = 0,
++    e_MODULE_ID_DUART_2,
++    e_MODULE_ID_DUART_3,
++    e_MODULE_ID_DUART_4,
++    e_MODULE_ID_LAW,
++    e_MODULE_ID_IFC,
++    e_MODULE_ID_PAMU,
++    e_MODULE_ID_QM,                 /**< Queue manager module */
++    e_MODULE_ID_BM,                 /**< Buffer manager module */
++    e_MODULE_ID_QM_CE_PORTAL_0,
++    e_MODULE_ID_QM_CI_PORTAL_0,
++    e_MODULE_ID_QM_CE_PORTAL_1,
++    e_MODULE_ID_QM_CI_PORTAL_1,
++    e_MODULE_ID_QM_CE_PORTAL_2,
++    e_MODULE_ID_QM_CI_PORTAL_2,
++    e_MODULE_ID_QM_CE_PORTAL_3,
++    e_MODULE_ID_QM_CI_PORTAL_3,
++    e_MODULE_ID_QM_CE_PORTAL_4,
++    e_MODULE_ID_QM_CI_PORTAL_4,
++    e_MODULE_ID_QM_CE_PORTAL_5,
++    e_MODULE_ID_QM_CI_PORTAL_5,
++    e_MODULE_ID_QM_CE_PORTAL_6,
++    e_MODULE_ID_QM_CI_PORTAL_6,
++    e_MODULE_ID_QM_CE_PORTAL_7,
++    e_MODULE_ID_QM_CI_PORTAL_7,
++    e_MODULE_ID_QM_CE_PORTAL_8,
++    e_MODULE_ID_QM_CI_PORTAL_8,
++    e_MODULE_ID_QM_CE_PORTAL_9,
++    e_MODULE_ID_QM_CI_PORTAL_9,
++    e_MODULE_ID_BM_CE_PORTAL_0,
++    e_MODULE_ID_BM_CI_PORTAL_0,
++    e_MODULE_ID_BM_CE_PORTAL_1,
++    e_MODULE_ID_BM_CI_PORTAL_1,
++    e_MODULE_ID_BM_CE_PORTAL_2,
++    e_MODULE_ID_BM_CI_PORTAL_2,
++    e_MODULE_ID_BM_CE_PORTAL_3,
++    e_MODULE_ID_BM_CI_PORTAL_3,
++    e_MODULE_ID_BM_CE_PORTAL_4,
++    e_MODULE_ID_BM_CI_PORTAL_4,
++    e_MODULE_ID_BM_CE_PORTAL_5,
++    e_MODULE_ID_BM_CI_PORTAL_5,
++    e_MODULE_ID_BM_CE_PORTAL_6,
++    e_MODULE_ID_BM_CI_PORTAL_6,
++    e_MODULE_ID_BM_CE_PORTAL_7,
++    e_MODULE_ID_BM_CI_PORTAL_7,
++    e_MODULE_ID_BM_CE_PORTAL_8,
++    e_MODULE_ID_BM_CI_PORTAL_8,
++    e_MODULE_ID_BM_CE_PORTAL_9,
++    e_MODULE_ID_BM_CI_PORTAL_9,
++    e_MODULE_ID_FM,                 /**< Frame manager module */
++    e_MODULE_ID_FM_RTC,             /**< FM Real-Time-Clock */
++    e_MODULE_ID_FM_MURAM,           /**< FM Multi-User-RAM */
++    e_MODULE_ID_FM_BMI,             /**< FM BMI block */
++    e_MODULE_ID_FM_QMI,             /**< FM QMI block */
++    e_MODULE_ID_FM_PARSER,          /**< FM parser block */
++    e_MODULE_ID_FM_PORT_HO1,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO2,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO3,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO4,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO5,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO6,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO7,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_1GRx1,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx2,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx3,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx4,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx5,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx6,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_10GRx1,     /**< FM Rx 10G MAC port block */
++    e_MODULE_ID_FM_PORT_10GRx2,     /**< FM Rx 10G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx1,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx2,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx3,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx4,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx5,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx6,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_10GTx1,     /**< FM Tx 10G MAC port block */
++    e_MODULE_ID_FM_PORT_10GTx2,     /**< FM Tx 10G MAC port block */
++    e_MODULE_ID_FM_PLCR,            /**< FM Policer */
++    e_MODULE_ID_FM_KG,              /**< FM Keygen */
++    e_MODULE_ID_FM_DMA,             /**< FM DMA */
++    e_MODULE_ID_FM_FPM,             /**< FM FPM */
++    e_MODULE_ID_FM_IRAM,            /**< FM Instruction-RAM */
++    e_MODULE_ID_FM_1GMDIO,          /**< FM 1G MDIO MAC */
++    e_MODULE_ID_FM_10GMDIO,         /**< FM 10G MDIO */
++    e_MODULE_ID_FM_PRS_IRAM,        /**< FM SW-parser Instruction-RAM */
++    e_MODULE_ID_FM_1GMAC1,          /**< FM 1G MAC #1 */
++    e_MODULE_ID_FM_1GMAC2,          /**< FM 1G MAC #2 */
++    e_MODULE_ID_FM_1GMAC3,          /**< FM 1G MAC #3 */
++    e_MODULE_ID_FM_1GMAC4,          /**< FM 1G MAC #4 */
++    e_MODULE_ID_FM_1GMAC5,          /**< FM 1G MAC #5 */
++    e_MODULE_ID_FM_1GMAC6,          /**< FM 1G MAC #6 */
++    e_MODULE_ID_FM_10GMAC1,         /**< FM 10G MAC */
++    e_MODULE_ID_FM_10GMAC2,         /**< FM 10G MAC */
++
++    e_MODULE_ID_SEC_GEN,            /**< SEC 4.0 General registers      */
++    e_MODULE_ID_SEC_QI,             /**< SEC 4.0 QI registers           */
++    e_MODULE_ID_SEC_JQ0,            /**< SEC 4.0 JQ-0 registers         */
++    e_MODULE_ID_SEC_JQ1,            /**< SEC 4.0 JQ-1 registers         */
++    e_MODULE_ID_SEC_JQ2,            /**< SEC 4.0 JQ-2 registers         */
++    e_MODULE_ID_SEC_JQ3,            /**< SEC 4.0 JQ-3 registers         */
++    e_MODULE_ID_SEC_RTIC,           /**< SEC 4.0 RTIC registers         */
++    e_MODULE_ID_SEC_DECO0_CCB0,     /**< SEC 4.0 DECO-0/CCB-0 registers */
++    e_MODULE_ID_SEC_DECO1_CCB1,     /**< SEC 4.0 DECO-1/CCB-1 registers */
++    e_MODULE_ID_SEC_DECO2_CCB2,     /**< SEC 4.0 DECO-2/CCB-2 registers */
++    e_MODULE_ID_SEC_DECO3_CCB3,     /**< SEC 4.0 DECO-3/CCB-3 registers */
++    e_MODULE_ID_SEC_DECO4_CCB4,     /**< SEC 4.0 DECO-4/CCB-4 registers */
++
++    e_MODULE_ID_PIC,                /**< PIC */
++    e_MODULE_ID_GPIO,               /**< GPIO */
++    e_MODULE_ID_SERDES,             /**< SERDES */
++    e_MODULE_ID_CPC_1,              /**< CoreNet-Platform-Cache 1 */
++    e_MODULE_ID_CPC_2,              /**< CoreNet-Platform-Cache 2 */
++
++    e_MODULE_ID_SRIO_PORTS,         /**< RapidIO controller */
++
++    e_MODULE_ID_DUMMY_LAST
++} e_ModuleId;
++
++#define NUM_OF_MODULES  e_MODULE_ID_DUMMY_LAST
++
++#if 0 /* using unified values */
++/*****************************************************************************
++ INTEGRATION-SPECIFIC MODULE CODES
++******************************************************************************/
++#define MODULE_UNKNOWN          0x00000000
++#define MODULE_MEM              0x00010000
++#define MODULE_MM               0x00020000
++#define MODULE_CORE             0x00030000
++#define MODULE_T4240            0x00040000
++#define MODULE_T4240_PLATFORM   0x00050000
++#define MODULE_PM               0x00060000
++#define MODULE_MMU              0x00070000
++#define MODULE_PIC              0x00080000
++#define MODULE_CPC              0x00090000
++#define MODULE_DUART            0x000a0000
++#define MODULE_SERDES           0x000b0000
++#define MODULE_PIO              0x000c0000
++#define MODULE_QM               0x000d0000
++#define MODULE_BM               0x000e0000
++#define MODULE_SEC              0x000f0000
++#define MODULE_LAW              0x00100000
++#define MODULE_LBC              0x00110000
++#define MODULE_PAMU             0x00120000
++#define MODULE_FM               0x00130000
++#define MODULE_FM_MURAM         0x00140000
++#define MODULE_FM_PCD           0x00150000
++#define MODULE_FM_RTC           0x00160000
++#define MODULE_FM_MAC           0x00170000
++#define MODULE_FM_PORT          0x00180000
++#define MODULE_FM_SP            0x00190000
++#define MODULE_DPA_PORT         0x001a0000
++#define MODULE_MII              0x001b0000
++#define MODULE_I2C              0x001c0000
++#define MODULE_DMA              0x001d0000
++#define MODULE_DDR              0x001e0000
++#define MODULE_ESPI             0x001f0000
++#define MODULE_DPAA_IPSEC       0x00200000
++#endif /* using unified values */
++
++/*****************************************************************************
++ PAMU INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define PAMU_NUM_OF_PARTITIONS  4
++
++/*****************************************************************************
++ LAW INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define LAW_NUM_OF_WINDOWS      32
++#define LAW_MIN_WINDOW_SIZE     0x0000000000001000LL    /**< 4 Kbytes */
++#define LAW_MAX_WINDOW_SIZE     0x0000010000000000LL    /**< 1 Tbytes for 40-bit address space */
++
++
++/*****************************************************************************
++ LBC INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++/**************************************************************************//**
++ @Group         lbc_exception_grp LBC Exception Unit
++
++ @Description   LBC Exception unit API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Anchor        lbc_exbm
++
++ @Collection    LBC Errors Bit Mask
++
++                These errors are reported through the exceptions callback..
++                The values can be or'ed in any combination in the errors mask
++                parameter of the errors report structure.
++
++                These errors can also be passed as a bit-mask to
++                LBC_EnableErrorChecking() or LBC_DisableErrorChecking(),
++                for enabling or disabling error checking.
++ @{
++*//***************************************************************************/
++#define LBC_ERR_BUS_MONITOR     0x80000000  /**< Bus monitor error */
++#define LBC_ERR_PARITY_ECC      0x20000000  /**< Parity error for GPCM/UPM */
++#define LBC_ERR_WRITE_PROTECT   0x04000000  /**< Write protection error */
++#define LBC_ERR_CHIP_SELECT     0x00080000  /**< Unrecognized chip select */
++
++#define LBC_ERR_ALL             (LBC_ERR_BUS_MONITOR | LBC_ERR_PARITY_ECC | \
++                                 LBC_ERR_WRITE_PROTECT | LBC_ERR_CHIP_SELECT)
++                                            /**< All possible errors */
++/* @} */
++/** @} */ /* end of lbc_exception_grp group */
++
++#define LBC_INCORRECT_ERROR_REPORT_ERRATA
++
++#define LBC_NUM_OF_BANKS            8
++#define LBC_MAX_CS_SIZE             0x0000000100000000LL  /* Up to 4G memory block size */
++#define LBC_PARITY_SUPPORT
++#define LBC_ADDRESS_HOLD_TIME_CTRL
++#define LBC_HIGH_CLK_DIVIDERS
++#define LBC_FCM_AVAILABLE
++
++/*****************************************************************************
++ GPIO INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define GPIO_PORT_OFFSET_0x1000
++
++#define GPIO_NUM_OF_PORTS   3   /**< Number of ports in GPIO module;
++                                     Each port contains up to 32 I/O pins. */
++
++#define GPIO_VALID_PIN_MASKS   \
++    { /* Port A */ 0xFFFFFFFF, \
++      /* Port B */ 0xFFFFFFFF, \
++      /* Port C */ 0xFFFFFFFF }
++
++#define GPIO_VALID_INTR_MASKS  \
++    { /* Port A */ 0xFFFFFFFF, \
++      /* Port B */ 0xFFFFFFFF, \
++      /* Port C */ 0xFFFFFFFF }
++
++
++
++#endif /* __PART_INTEGRATION_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/dpaa_integration_ext.h
+@@ -0,0 +1,293 @@
++/*
++ * Copyright 2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**
++
++ @File          dpaa_integration_ext.h
++
++ @Description   T4240 FM external definitions and structures.
++*//***************************************************************************/
++#ifndef __DPAA_INTEGRATION_EXT_H
++#define __DPAA_INTEGRATION_EXT_H
++
++#include "std_ext.h"
++
++
++#define DPAA_VERSION    11
++
++/**************************************************************************//**
++ @Description   DPAA SW Portals Enumeration.
++*//***************************************************************************/
++typedef enum
++{
++    e_DPAA_SWPORTAL0 = 0,
++    e_DPAA_SWPORTAL1,
++    e_DPAA_SWPORTAL2,
++    e_DPAA_SWPORTAL3,
++    e_DPAA_SWPORTAL4,
++    e_DPAA_SWPORTAL5,
++    e_DPAA_SWPORTAL6,
++    e_DPAA_SWPORTAL7,
++    e_DPAA_SWPORTAL8,
++    e_DPAA_SWPORTAL9,
++    e_DPAA_SWPORTAL10,
++    e_DPAA_SWPORTAL11,
++    e_DPAA_SWPORTAL12,
++    e_DPAA_SWPORTAL13,
++    e_DPAA_SWPORTAL14,
++    e_DPAA_SWPORTAL15,
++    e_DPAA_SWPORTAL16,
++    e_DPAA_SWPORTAL17,
++    e_DPAA_SWPORTAL18,
++    e_DPAA_SWPORTAL19,
++    e_DPAA_SWPORTAL20,
++    e_DPAA_SWPORTAL21,
++    e_DPAA_SWPORTAL22,
++    e_DPAA_SWPORTAL23,
++    e_DPAA_SWPORTAL24,
++    e_DPAA_SWPORTAL_DUMMY_LAST
++} e_DpaaSwPortal;
++
++/**************************************************************************//**
++ @Description   DPAA Direct Connect Portals Enumeration.
++*//***************************************************************************/
++typedef enum
++{
++    e_DPAA_DCPORTAL0 = 0,
++    e_DPAA_DCPORTAL1,
++    e_DPAA_DCPORTAL2,
++    e_DPAA_DCPORTAL_DUMMY_LAST
++} e_DpaaDcPortal;
++
++#define DPAA_MAX_NUM_OF_SW_PORTALS      e_DPAA_SWPORTAL_DUMMY_LAST
++#define DPAA_MAX_NUM_OF_DC_PORTALS      e_DPAA_DCPORTAL_DUMMY_LAST
++
++/*****************************************************************************
++ QMan INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define QM_MAX_NUM_OF_POOL_CHANNELS     15      /**< Total number of channels, dedicated and pool */
++#define QM_MAX_NUM_OF_WQ                8       /**< Number of work queues per channel */
++#define QM_MAX_NUM_OF_CGS               256     /**< Congestion groups number */
++#define QM_MAX_NUM_OF_FQIDS             (16 * MEGABYTE)
++                                                /**< FQIDs range - 24 bits */
++
++/**************************************************************************//**
++ @Description   Work Queue Channel assignments in QMan.
++*//***************************************************************************/
++typedef enum
++{
++    e_QM_FQ_CHANNEL_SWPORTAL0 = 0x0,              /**< Dedicated channels serviced by software portals 0 to 24 */
++    e_QM_FQ_CHANNEL_SWPORTAL1,
++    e_QM_FQ_CHANNEL_SWPORTAL2,
++    e_QM_FQ_CHANNEL_SWPORTAL3,
++    e_QM_FQ_CHANNEL_SWPORTAL4,
++    e_QM_FQ_CHANNEL_SWPORTAL5,
++    e_QM_FQ_CHANNEL_SWPORTAL6,
++    e_QM_FQ_CHANNEL_SWPORTAL7,
++    e_QM_FQ_CHANNEL_SWPORTAL8,
++    e_QM_FQ_CHANNEL_SWPORTAL9,
++    e_QM_FQ_CHANNEL_SWPORTAL10,
++    e_QM_FQ_CHANNEL_SWPORTAL11,
++    e_QM_FQ_CHANNEL_SWPORTAL12,
++    e_QM_FQ_CHANNEL_SWPORTAL13,
++    e_QM_FQ_CHANNEL_SWPORTAL14,
++    e_QM_FQ_CHANNEL_SWPORTAL15,
++    e_QM_FQ_CHANNEL_SWPORTAL16,
++    e_QM_FQ_CHANNEL_SWPORTAL17,
++    e_QM_FQ_CHANNEL_SWPORTAL18,
++    e_QM_FQ_CHANNEL_SWPORTAL19,
++    e_QM_FQ_CHANNEL_SWPORTAL20,
++    e_QM_FQ_CHANNEL_SWPORTAL21,
++    e_QM_FQ_CHANNEL_SWPORTAL22,
++    e_QM_FQ_CHANNEL_SWPORTAL23,
++    e_QM_FQ_CHANNEL_SWPORTAL24,
++
++    e_QM_FQ_CHANNEL_POOL1 = 0x401,               /**< Pool channels that can be serviced by any of the software portals */
++    e_QM_FQ_CHANNEL_POOL2,
++    e_QM_FQ_CHANNEL_POOL3,
++    e_QM_FQ_CHANNEL_POOL4,
++    e_QM_FQ_CHANNEL_POOL5,
++    e_QM_FQ_CHANNEL_POOL6,
++    e_QM_FQ_CHANNEL_POOL7,
++    e_QM_FQ_CHANNEL_POOL8,
++    e_QM_FQ_CHANNEL_POOL9,
++    e_QM_FQ_CHANNEL_POOL10,
++    e_QM_FQ_CHANNEL_POOL11,
++    e_QM_FQ_CHANNEL_POOL12,
++    e_QM_FQ_CHANNEL_POOL13,
++    e_QM_FQ_CHANNEL_POOL14,
++    e_QM_FQ_CHANNEL_POOL15,
++
++    e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x800,           /**< Dedicated channels serviced by Direct Connect Portal 0:
++                                                      connected to FMan 0; assigned in incrementing order to
++                                                      each sub-portal (SP) in the portal */
++    e_QM_FQ_CHANNEL_FMAN0_SP1,
++    e_QM_FQ_CHANNEL_FMAN0_SP2,
++    e_QM_FQ_CHANNEL_FMAN0_SP3,
++    e_QM_FQ_CHANNEL_FMAN0_SP4,
++    e_QM_FQ_CHANNEL_FMAN0_SP5,
++    e_QM_FQ_CHANNEL_FMAN0_SP6,
++    e_QM_FQ_CHANNEL_FMAN0_SP7,
++    e_QM_FQ_CHANNEL_FMAN0_SP8,
++    e_QM_FQ_CHANNEL_FMAN0_SP9,
++    e_QM_FQ_CHANNEL_FMAN0_SP10,
++    e_QM_FQ_CHANNEL_FMAN0_SP11,
++    e_QM_FQ_CHANNEL_FMAN0_SP12,
++    e_QM_FQ_CHANNEL_FMAN0_SP13,
++    e_QM_FQ_CHANNEL_FMAN0_SP14,
++    e_QM_FQ_CHANNEL_FMAN0_SP15,
++
++    e_QM_FQ_CHANNEL_RMAN_SP0 = 0x820,            /**< Dedicated channels serviced by Direct Connect Portal 1: connected to RMan */
++    e_QM_FQ_CHANNEL_RMAN_SP1,
++
++    e_QM_FQ_CHANNEL_CAAM = 0x840                 /**< Dedicated channel serviced by Direct Connect Portal 2:
++                                                      connected to SEC */
++} e_QmFQChannel;
++
++/*****************************************************************************
++ BMan INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define BM_MAX_NUM_OF_POOLS         64          /**< Number of buffers pools */
++
++/*****************************************************************************
++ SEC INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define SEC_NUM_OF_DECOS            3
++#define SEC_ALL_DECOS_MASK          0x00000003
++
++
++/*****************************************************************************
++ FM INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define INTG_MAX_NUM_OF_FM        1
++/* Ports defines */
++#define FM_MAX_NUM_OF_1G_MACS     5
++#define FM_MAX_NUM_OF_10G_MACS            1
++#define FM_MAX_NUM_OF_MACS        (FM_MAX_NUM_OF_1G_MACS + FM_MAX_NUM_OF_10G_MACS)
++#define FM_MAX_NUM_OF_OH_PORTS            4
++
++#define FM_MAX_NUM_OF_1G_RX_PORTS   FM_MAX_NUM_OF_1G_MACS
++#define FM_MAX_NUM_OF_10G_RX_PORTS  FM_MAX_NUM_OF_10G_MACS
++#define FM_MAX_NUM_OF_RX_PORTS      (FM_MAX_NUM_OF_10G_RX_PORTS + FM_MAX_NUM_OF_1G_RX_PORTS)
++
++#define FM_MAX_NUM_OF_1G_TX_PORTS   FM_MAX_NUM_OF_1G_MACS
++#define FM_MAX_NUM_OF_10G_TX_PORTS  FM_MAX_NUM_OF_10G_MACS
++#define FM_MAX_NUM_OF_TX_PORTS      (FM_MAX_NUM_OF_10G_TX_PORTS + FM_MAX_NUM_OF_1G_TX_PORTS)
++
++#define FM_MAX_NUM_OF_MACSECS       1 /* Should be updated */
++
++#define FM_PORT_MAX_NUM_OF_EXT_POOLS            4           /**< Number of external BM pools per Rx port */
++#define FM_PORT_NUM_OF_CONGESTION_GRPS          256         /**< Total number of congestion groups in QM */
++#define FM_MAX_NUM_OF_SUB_PORTALS               16
++#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS   0
++
++#define FM_VSP_MAX_NUM_OF_ENTRIES               32
++#define FM_MAX_NUM_OF_PFC_PRIORITIES            8
++
++/* RAMs defines */
++#define FM_MURAM_SIZE                   (192 * KILOBYTE)
++#define FM_IRAM_SIZE(major, minor)      \
++    (((major == 6) && ((minor == 4) )) ? (64 * KILOBYTE) : (32 * KILOBYTE))
++#define FM_NUM_OF_CTRL                  2
++
++/* PCD defines */
++#define FM_PCD_PLCR_NUM_ENTRIES         256                 /**< Total number of policer profiles */
++#define FM_PCD_KG_NUM_OF_SCHEMES        32                  /**< Total number of KG schemes */
++#define FM_PCD_MAX_NUM_OF_CLS_PLANS     256                 /**< Number of classification plan entries. */
++#define FM_PCD_PRS_SW_PATCHES_SIZE      0x00000600          /**< Number of bytes saved for patches */
++#define FM_PCD_SW_PRS_SIZE              0x00000800          /**< Total size of SW parser area */
++
++/* RTC defines */
++#define FM_RTC_NUM_OF_ALARMS            2                   /**< RTC number of alarms */
++#define FM_RTC_NUM_OF_PERIODIC_PULSES   3                   /**< RTC number of periodic pulses */
++#define FM_RTC_NUM_OF_EXT_TRIGGERS      2                   /**< RTC number of external triggers */
++
++/* QMI defines */
++#define QMI_MAX_NUM_OF_TNUMS            64
++#define QMI_DEF_TNUMS_THRESH            32
++/* FPM defines */
++#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS  4
++
++/* DMA defines */
++#define DMA_THRESH_MAX_COMMQ            83
++#define DMA_THRESH_MAX_BUF              127
++
++/* BMI defines */
++#define BMI_MAX_NUM_OF_TASKS            64
++#define BMI_MAX_NUM_OF_DMAS             32
++
++#define BMI_MAX_FIFO_SIZE               (FM_MURAM_SIZE)
++#define PORT_MAX_WEIGHT                 16
++
++#define FM_CHECK_PORT_RESTRICTIONS(__validPorts, __newPortIndx)   TRUE
++
++/* Unique T4240 */
++#define FM_OP_OPEN_DMA_MIN_LIMIT
++#define FM_NO_RESTRICT_ON_ACCESS_RSRC
++#define FM_NO_OP_OBSERVED_POOLS
++#define FM_FRAME_END_PARAMS_FOR_OP
++#define FM_DEQ_PIPELINE_PARAMS_FOR_OP
++#define FM_QMI_NO_SINGLE_ECC_EXCEPTION
++
++#define FM_NO_GUARANTEED_RESET_VALUES
++
++/* FM errata */
++#define FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
++#define FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320
++#define FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675
++#define FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981
++#define FM_HANG_AT_RESET_MAC_CLK_DISABLED_ERRATA_FMAN_A007273
++
++#define FM_BCB_ERRATA_BMI_SW001
++#define FM_LEN_CHECK_ERRATA_FMAN_SW002
++#define FM_AID_MODE_NO_TNUM_SW005 /* refer to pdm TKT068794 - only support of port_id on aid */
++#define FM_ERROR_VSP_NO_MATCH_SW006 /* refer to pdm TKT174304 - no match between errorQ and VSP */
++
++/*****************************************************************************
++ RMan INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define RM_MAX_NUM_OF_IB        4           /**< Number of inbound blocks */
++#define RM_NUM_OF_IBCU          8           /**< NUmber of classification units in an inbound block */
++
++/* RMan erratas */
++#define RM_ERRONEOUS_ACK_ERRATA_RMAN_A006756
++
++/*****************************************************************************
++ FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define NUM_OF_RX_SC                16
++#define NUM_OF_TX_SC                16
++
++#define NUM_OF_SA_PER_RX_SC         2
++#define NUM_OF_SA_PER_TX_SC         2
++
++#endif /* __DPAA_INTEGRATION_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_ext.h
+@@ -0,0 +1,59 @@
++/*
++ * Copyright 2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**************************************************************************//**
++
++ @File          part_ext.h
++
++ @Description   Definitions for the part (integration) module.
++*//***************************************************************************/
++
++#ifndef __PART_EXT_H
++#define __PART_EXT_H
++
++#include "std_ext.h"
++#include "part_integration_ext.h"
++
++/**************************************************************************//*
++ @Description   Part data structure - must be contained in any integration
++                data structure.
++*//***************************************************************************/
++typedef struct t_Part
++{
++    uintptr_t   (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId);
++                /**< Returns the address of the module's memory map base. */
++    e_ModuleId  (* f_GetModuleIdByBase)(t_Handle h_Part, uintptr_t baseAddress);
++                /**< Returns the module's ID according to its memory map base. */
++} t_Part;
++
++
++#endif /* __PART_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_integration_ext.h
+@@ -0,0 +1,304 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**
++
++ @File          part_integration_ext.h
++
++ @Description   T4240 external definitions and structures.
++*//***************************************************************************/
++#ifndef __PART_INTEGRATION_EXT_H
++#define __PART_INTEGRATION_EXT_H
++
++#include "std_ext.h"
++#include "ddr_std_ext.h"
++#include "enet_ext.h"
++#include "dpaa_integration_ext.h"
++
++
++/**************************************************************************//**
++ @Group         T4240_chip_id T4240 Application Programming Interface
++
++ @Description   T4240 Chip functions,definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++#define CORE_E6500
++
++#define INTG_MAX_NUM_OF_CORES   24
++
++
++/**************************************************************************//**
++ @Description   Module types.
++*//***************************************************************************/
++typedef enum e_ModuleId
++{
++    e_MODULE_ID_DUART_1 = 0,
++    e_MODULE_ID_DUART_2,
++    e_MODULE_ID_DUART_3,
++    e_MODULE_ID_DUART_4,
++    e_MODULE_ID_LAW,
++    e_MODULE_ID_IFC,
++    e_MODULE_ID_PAMU,
++    e_MODULE_ID_QM,                 /**< Queue manager module */
++    e_MODULE_ID_BM,                 /**< Buffer manager module */
++    e_MODULE_ID_QM_CE_PORTAL_0,
++    e_MODULE_ID_QM_CI_PORTAL_0,
++    e_MODULE_ID_QM_CE_PORTAL_1,
++    e_MODULE_ID_QM_CI_PORTAL_1,
++    e_MODULE_ID_QM_CE_PORTAL_2,
++    e_MODULE_ID_QM_CI_PORTAL_2,
++    e_MODULE_ID_QM_CE_PORTAL_3,
++    e_MODULE_ID_QM_CI_PORTAL_3,
++    e_MODULE_ID_QM_CE_PORTAL_4,
++    e_MODULE_ID_QM_CI_PORTAL_4,
++    e_MODULE_ID_QM_CE_PORTAL_5,
++    e_MODULE_ID_QM_CI_PORTAL_5,
++    e_MODULE_ID_QM_CE_PORTAL_6,
++    e_MODULE_ID_QM_CI_PORTAL_6,
++    e_MODULE_ID_QM_CE_PORTAL_7,
++    e_MODULE_ID_QM_CI_PORTAL_7,
++    e_MODULE_ID_QM_CE_PORTAL_8,
++    e_MODULE_ID_QM_CI_PORTAL_8,
++    e_MODULE_ID_QM_CE_PORTAL_9,
++    e_MODULE_ID_QM_CI_PORTAL_9,
++    e_MODULE_ID_BM_CE_PORTAL_0,
++    e_MODULE_ID_BM_CI_PORTAL_0,
++    e_MODULE_ID_BM_CE_PORTAL_1,
++    e_MODULE_ID_BM_CI_PORTAL_1,
++    e_MODULE_ID_BM_CE_PORTAL_2,
++    e_MODULE_ID_BM_CI_PORTAL_2,
++    e_MODULE_ID_BM_CE_PORTAL_3,
++    e_MODULE_ID_BM_CI_PORTAL_3,
++    e_MODULE_ID_BM_CE_PORTAL_4,
++    e_MODULE_ID_BM_CI_PORTAL_4,
++    e_MODULE_ID_BM_CE_PORTAL_5,
++    e_MODULE_ID_BM_CI_PORTAL_5,
++    e_MODULE_ID_BM_CE_PORTAL_6,
++    e_MODULE_ID_BM_CI_PORTAL_6,
++    e_MODULE_ID_BM_CE_PORTAL_7,
++    e_MODULE_ID_BM_CI_PORTAL_7,
++    e_MODULE_ID_BM_CE_PORTAL_8,
++    e_MODULE_ID_BM_CI_PORTAL_8,
++    e_MODULE_ID_BM_CE_PORTAL_9,
++    e_MODULE_ID_BM_CI_PORTAL_9,
++    e_MODULE_ID_FM,                 /**< Frame manager module */
++    e_MODULE_ID_FM_RTC,             /**< FM Real-Time-Clock */
++    e_MODULE_ID_FM_MURAM,           /**< FM Multi-User-RAM */
++    e_MODULE_ID_FM_BMI,             /**< FM BMI block */
++    e_MODULE_ID_FM_QMI,             /**< FM QMI block */
++    e_MODULE_ID_FM_PARSER,          /**< FM parser block */
++    e_MODULE_ID_FM_PORT_HO1,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO2,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO3,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO4,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO5,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO6,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO7,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_1GRx1,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx2,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx3,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx4,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx5,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx6,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_10GRx1,     /**< FM Rx 10G MAC port block */
++    e_MODULE_ID_FM_PORT_10GRx2,     /**< FM Rx 10G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx1,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx2,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx3,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx4,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx5,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx6,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_10GTx1,     /**< FM Tx 10G MAC port block */
++    e_MODULE_ID_FM_PORT_10GTx2,     /**< FM Tx 10G MAC port block */
++    e_MODULE_ID_FM_PLCR,            /**< FM Policer */
++    e_MODULE_ID_FM_KG,              /**< FM Keygen */
++    e_MODULE_ID_FM_DMA,             /**< FM DMA */
++    e_MODULE_ID_FM_FPM,             /**< FM FPM */
++    e_MODULE_ID_FM_IRAM,            /**< FM Instruction-RAM */
++    e_MODULE_ID_FM_1GMDIO,          /**< FM 1G MDIO MAC */
++    e_MODULE_ID_FM_10GMDIO,         /**< FM 10G MDIO */
++    e_MODULE_ID_FM_PRS_IRAM,        /**< FM SW-parser Instruction-RAM */
++    e_MODULE_ID_FM_1GMAC1,          /**< FM 1G MAC #1 */
++    e_MODULE_ID_FM_1GMAC2,          /**< FM 1G MAC #2 */
++    e_MODULE_ID_FM_1GMAC3,          /**< FM 1G MAC #3 */
++    e_MODULE_ID_FM_1GMAC4,          /**< FM 1G MAC #4 */
++    e_MODULE_ID_FM_1GMAC5,          /**< FM 1G MAC #5 */
++    e_MODULE_ID_FM_1GMAC6,          /**< FM 1G MAC #6 */
++    e_MODULE_ID_FM_10GMAC1,         /**< FM 10G MAC */
++    e_MODULE_ID_FM_10GMAC2,         /**< FM 10G MAC */
++
++    e_MODULE_ID_SEC_GEN,            /**< SEC 4.0 General registers      */
++    e_MODULE_ID_SEC_QI,             /**< SEC 4.0 QI registers           */
++    e_MODULE_ID_SEC_JQ0,            /**< SEC 4.0 JQ-0 registers         */
++    e_MODULE_ID_SEC_JQ1,            /**< SEC 4.0 JQ-1 registers         */
++    e_MODULE_ID_SEC_JQ2,            /**< SEC 4.0 JQ-2 registers         */
++    e_MODULE_ID_SEC_JQ3,            /**< SEC 4.0 JQ-3 registers         */
++    e_MODULE_ID_SEC_RTIC,           /**< SEC 4.0 RTIC registers         */
++    e_MODULE_ID_SEC_DECO0_CCB0,     /**< SEC 4.0 DECO-0/CCB-0 registers */
++    e_MODULE_ID_SEC_DECO1_CCB1,     /**< SEC 4.0 DECO-1/CCB-1 registers */
++    e_MODULE_ID_SEC_DECO2_CCB2,     /**< SEC 4.0 DECO-2/CCB-2 registers */
++    e_MODULE_ID_SEC_DECO3_CCB3,     /**< SEC 4.0 DECO-3/CCB-3 registers */
++    e_MODULE_ID_SEC_DECO4_CCB4,     /**< SEC 4.0 DECO-4/CCB-4 registers */
++
++    e_MODULE_ID_PIC,                /**< PIC */
++    e_MODULE_ID_GPIO,               /**< GPIO */
++    e_MODULE_ID_SERDES,             /**< SERDES */
++    e_MODULE_ID_CPC_1,              /**< CoreNet-Platform-Cache 1 */
++    e_MODULE_ID_CPC_2,              /**< CoreNet-Platform-Cache 2 */
++
++    e_MODULE_ID_SRIO_PORTS,         /**< RapidIO controller */
++
++    e_MODULE_ID_DUMMY_LAST
++} e_ModuleId;
++
++#define NUM_OF_MODULES  e_MODULE_ID_DUMMY_LAST
++
++#if 0 /* using unified values */
++/*****************************************************************************
++ INTEGRATION-SPECIFIC MODULE CODES
++******************************************************************************/
++#define MODULE_UNKNOWN          0x00000000
++#define MODULE_MEM              0x00010000
++#define MODULE_MM               0x00020000
++#define MODULE_CORE             0x00030000
++#define MODULE_T4240            0x00040000
++#define MODULE_T4240_PLATFORM   0x00050000
++#define MODULE_PM               0x00060000
++#define MODULE_MMU              0x00070000
++#define MODULE_PIC              0x00080000
++#define MODULE_CPC              0x00090000
++#define MODULE_DUART            0x000a0000
++#define MODULE_SERDES           0x000b0000
++#define MODULE_PIO              0x000c0000
++#define MODULE_QM               0x000d0000
++#define MODULE_BM               0x000e0000
++#define MODULE_SEC              0x000f0000
++#define MODULE_LAW              0x00100000
++#define MODULE_LBC              0x00110000
++#define MODULE_PAMU             0x00120000
++#define MODULE_FM               0x00130000
++#define MODULE_FM_MURAM         0x00140000
++#define MODULE_FM_PCD           0x00150000
++#define MODULE_FM_RTC           0x00160000
++#define MODULE_FM_MAC           0x00170000
++#define MODULE_FM_PORT          0x00180000
++#define MODULE_FM_SP            0x00190000
++#define MODULE_DPA_PORT         0x001a0000
++#define MODULE_MII              0x001b0000
++#define MODULE_I2C              0x001c0000
++#define MODULE_DMA              0x001d0000
++#define MODULE_DDR              0x001e0000
++#define MODULE_ESPI             0x001f0000
++#define MODULE_DPAA_IPSEC       0x00200000
++#endif /* using unified values */
++
++/*****************************************************************************
++ PAMU INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define PAMU_NUM_OF_PARTITIONS  4
++
++/*****************************************************************************
++ LAW INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define LAW_NUM_OF_WINDOWS      32
++#define LAW_MIN_WINDOW_SIZE     0x0000000000001000LL    /**< 4 Kbytes */
++#define LAW_MAX_WINDOW_SIZE     0x0000010000000000LL    /**< 1 Tbytes for 40-bit address space */
++
++
++/*****************************************************************************
++ LBC INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++/**************************************************************************//**
++ @Group         lbc_exception_grp LBC Exception Unit
++
++ @Description   LBC Exception unit API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Anchor        lbc_exbm
++
++ @Collection    LBC Errors Bit Mask
++
++                These errors are reported through the exceptions callback..
++                The values can be or'ed in any combination in the errors mask
++                parameter of the errors report structure.
++
++                These errors can also be passed as a bit-mask to
++                LBC_EnableErrorChecking() or LBC_DisableErrorChecking(),
++                for enabling or disabling error checking.
++ @{
++*//***************************************************************************/
++#define LBC_ERR_BUS_MONITOR     0x80000000  /**< Bus monitor error */
++#define LBC_ERR_PARITY_ECC      0x20000000  /**< Parity error for GPCM/UPM */
++#define LBC_ERR_WRITE_PROTECT   0x04000000  /**< Write protection error */
++#define LBC_ERR_CHIP_SELECT     0x00080000  /**< Unrecognized chip select */
++
++#define LBC_ERR_ALL             (LBC_ERR_BUS_MONITOR | LBC_ERR_PARITY_ECC | \
++                                 LBC_ERR_WRITE_PROTECT | LBC_ERR_CHIP_SELECT)
++                                            /**< All possible errors */
++/* @} */
++/** @} */ /* end of lbc_exception_grp group */
++
++#define LBC_INCORRECT_ERROR_REPORT_ERRATA
++
++#define LBC_NUM_OF_BANKS            8
++#define LBC_MAX_CS_SIZE             0x0000000100000000LL  /* Up to 4G memory block size */
++#define LBC_PARITY_SUPPORT
++#define LBC_ADDRESS_HOLD_TIME_CTRL
++#define LBC_HIGH_CLK_DIVIDERS
++#define LBC_FCM_AVAILABLE
++
++/*****************************************************************************
++ GPIO INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define GPIO_PORT_OFFSET_0x1000
++
++#define GPIO_NUM_OF_PORTS   3   /**< Number of ports in GPIO module;
++                                     Each port contains up to 32 I/O pins. */
++
++#define GPIO_VALID_PIN_MASKS   \
++    { /* Port A */ 0xFFFFFFFF, \
++      /* Port B */ 0xFFFFFFFF, \
++      /* Port C */ 0xFFFFFFFF }
++
++#define GPIO_VALID_INTR_MASKS  \
++    { /* Port A */ 0xFFFFFFFF, \
++      /* Port B */ 0xFFFFFFFF, \
++      /* Port C */ 0xFFFFFFFF }
++
++
++
++#endif /* __PART_INTEGRATION_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/dpaa_integration_ext.h
+@@ -0,0 +1,291 @@
++/*
++ * Copyright 2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**
++
++ @File          dpaa_integration_ext.h
++
++ @Description   T4240 FM external definitions and structures.
++*//***************************************************************************/
++#ifndef __DPAA_INTEGRATION_EXT_H
++#define __DPAA_INTEGRATION_EXT_H
++
++#include "std_ext.h"
++
++
++#define DPAA_VERSION    11
++
++/**************************************************************************//**
++ @Description   DPAA SW Portals Enumeration.
++*//***************************************************************************/
++typedef enum
++{
++    e_DPAA_SWPORTAL0 = 0,
++    e_DPAA_SWPORTAL1,
++    e_DPAA_SWPORTAL2,
++    e_DPAA_SWPORTAL3,
++    e_DPAA_SWPORTAL4,
++    e_DPAA_SWPORTAL5,
++    e_DPAA_SWPORTAL6,
++    e_DPAA_SWPORTAL7,
++    e_DPAA_SWPORTAL8,
++    e_DPAA_SWPORTAL9,
++    e_DPAA_SWPORTAL10,
++    e_DPAA_SWPORTAL11,
++    e_DPAA_SWPORTAL12,
++    e_DPAA_SWPORTAL13,
++    e_DPAA_SWPORTAL14,
++    e_DPAA_SWPORTAL15,
++    e_DPAA_SWPORTAL16,
++    e_DPAA_SWPORTAL17,
++    e_DPAA_SWPORTAL18,
++    e_DPAA_SWPORTAL19,
++    e_DPAA_SWPORTAL20,
++    e_DPAA_SWPORTAL21,
++    e_DPAA_SWPORTAL22,
++    e_DPAA_SWPORTAL23,
++    e_DPAA_SWPORTAL24,
++    e_DPAA_SWPORTAL_DUMMY_LAST
++} e_DpaaSwPortal;
++
++/**************************************************************************//**
++ @Description   DPAA Direct Connect Portals Enumeration.
++*//***************************************************************************/
++typedef enum
++{
++    e_DPAA_DCPORTAL0 = 0,
++    e_DPAA_DCPORTAL1,
++    e_DPAA_DCPORTAL2,
++    e_DPAA_DCPORTAL_DUMMY_LAST
++} e_DpaaDcPortal;
++
++#define DPAA_MAX_NUM_OF_SW_PORTALS      e_DPAA_SWPORTAL_DUMMY_LAST
++#define DPAA_MAX_NUM_OF_DC_PORTALS      e_DPAA_DCPORTAL_DUMMY_LAST
++
++/*****************************************************************************
++ QMan INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define QM_MAX_NUM_OF_POOL_CHANNELS     15      /**< Total number of channels, dedicated and pool */
++#define QM_MAX_NUM_OF_WQ                8       /**< Number of work queues per channel */
++#define QM_MAX_NUM_OF_CGS               256     /**< Congestion groups number */
++#define QM_MAX_NUM_OF_FQIDS             (16 * MEGABYTE)
++                                                /**< FQIDs range - 24 bits */
++
++/**************************************************************************//**
++ @Description   Work Queue Channel assignments in QMan.
++*//***************************************************************************/
++typedef enum
++{
++    e_QM_FQ_CHANNEL_SWPORTAL0 = 0x0,              /**< Dedicated channels serviced by software portals 0 to 24 */
++    e_QM_FQ_CHANNEL_SWPORTAL1,
++    e_QM_FQ_CHANNEL_SWPORTAL2,
++    e_QM_FQ_CHANNEL_SWPORTAL3,
++    e_QM_FQ_CHANNEL_SWPORTAL4,
++    e_QM_FQ_CHANNEL_SWPORTAL5,
++    e_QM_FQ_CHANNEL_SWPORTAL6,
++    e_QM_FQ_CHANNEL_SWPORTAL7,
++    e_QM_FQ_CHANNEL_SWPORTAL8,
++    e_QM_FQ_CHANNEL_SWPORTAL9,
++    e_QM_FQ_CHANNEL_SWPORTAL10,
++    e_QM_FQ_CHANNEL_SWPORTAL11,
++    e_QM_FQ_CHANNEL_SWPORTAL12,
++    e_QM_FQ_CHANNEL_SWPORTAL13,
++    e_QM_FQ_CHANNEL_SWPORTAL14,
++    e_QM_FQ_CHANNEL_SWPORTAL15,
++    e_QM_FQ_CHANNEL_SWPORTAL16,
++    e_QM_FQ_CHANNEL_SWPORTAL17,
++    e_QM_FQ_CHANNEL_SWPORTAL18,
++    e_QM_FQ_CHANNEL_SWPORTAL19,
++    e_QM_FQ_CHANNEL_SWPORTAL20,
++    e_QM_FQ_CHANNEL_SWPORTAL21,
++    e_QM_FQ_CHANNEL_SWPORTAL22,
++    e_QM_FQ_CHANNEL_SWPORTAL23,
++    e_QM_FQ_CHANNEL_SWPORTAL24,
++
++    e_QM_FQ_CHANNEL_POOL1 = 0x401,               /**< Pool channels that can be serviced by any of the software portals */
++    e_QM_FQ_CHANNEL_POOL2,
++    e_QM_FQ_CHANNEL_POOL3,
++    e_QM_FQ_CHANNEL_POOL4,
++    e_QM_FQ_CHANNEL_POOL5,
++    e_QM_FQ_CHANNEL_POOL6,
++    e_QM_FQ_CHANNEL_POOL7,
++    e_QM_FQ_CHANNEL_POOL8,
++    e_QM_FQ_CHANNEL_POOL9,
++    e_QM_FQ_CHANNEL_POOL10,
++    e_QM_FQ_CHANNEL_POOL11,
++    e_QM_FQ_CHANNEL_POOL12,
++    e_QM_FQ_CHANNEL_POOL13,
++    e_QM_FQ_CHANNEL_POOL14,
++    e_QM_FQ_CHANNEL_POOL15,
++
++    e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x800,           /**< Dedicated channels serviced by Direct Connect Portal 0:
++                                                      connected to FMan 0; assigned in incrementing order to
++                                                      each sub-portal (SP) in the portal */
++    e_QM_FQ_CHANNEL_FMAN0_SP1,
++    e_QM_FQ_CHANNEL_FMAN0_SP2,
++    e_QM_FQ_CHANNEL_FMAN0_SP3,
++    e_QM_FQ_CHANNEL_FMAN0_SP4,
++    e_QM_FQ_CHANNEL_FMAN0_SP5,
++    e_QM_FQ_CHANNEL_FMAN0_SP6,
++    e_QM_FQ_CHANNEL_FMAN0_SP7,
++    e_QM_FQ_CHANNEL_FMAN0_SP8,
++    e_QM_FQ_CHANNEL_FMAN0_SP9,
++    e_QM_FQ_CHANNEL_FMAN0_SP10,
++    e_QM_FQ_CHANNEL_FMAN0_SP11,
++    e_QM_FQ_CHANNEL_FMAN0_SP12,
++    e_QM_FQ_CHANNEL_FMAN0_SP13,
++    e_QM_FQ_CHANNEL_FMAN0_SP14,
++    e_QM_FQ_CHANNEL_FMAN0_SP15,
++
++    e_QM_FQ_CHANNEL_RMAN_SP0 = 0x820,            /**< Dedicated channels serviced by Direct Connect Portal 1: connected to RMan */
++    e_QM_FQ_CHANNEL_RMAN_SP1,
++
++    e_QM_FQ_CHANNEL_CAAM = 0x840                 /**< Dedicated channel serviced by Direct Connect Portal 2:
++                                                      connected to SEC */
++} e_QmFQChannel;
++
++/*****************************************************************************
++ BMan INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define BM_MAX_NUM_OF_POOLS         64          /**< Number of buffers pools */
++
++/*****************************************************************************
++ SEC INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define SEC_NUM_OF_DECOS            3
++#define SEC_ALL_DECOS_MASK          0x00000003
++
++
++/*****************************************************************************
++ FM INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define INTG_MAX_NUM_OF_FM          2
++
++/* Ports defines */
++#define FM_MAX_NUM_OF_1G_MACS       6
++#define FM_MAX_NUM_OF_10G_MACS      2
++#define FM_MAX_NUM_OF_MACS          (FM_MAX_NUM_OF_1G_MACS + FM_MAX_NUM_OF_10G_MACS)
++#define FM_MAX_NUM_OF_OH_PORTS      6
++
++#define FM_MAX_NUM_OF_1G_RX_PORTS   FM_MAX_NUM_OF_1G_MACS
++#define FM_MAX_NUM_OF_10G_RX_PORTS  FM_MAX_NUM_OF_10G_MACS
++#define FM_MAX_NUM_OF_RX_PORTS      (FM_MAX_NUM_OF_10G_RX_PORTS + FM_MAX_NUM_OF_1G_RX_PORTS)
++
++#define FM_MAX_NUM_OF_1G_TX_PORTS   FM_MAX_NUM_OF_1G_MACS
++#define FM_MAX_NUM_OF_10G_TX_PORTS  FM_MAX_NUM_OF_10G_MACS
++#define FM_MAX_NUM_OF_TX_PORTS      (FM_MAX_NUM_OF_10G_TX_PORTS + FM_MAX_NUM_OF_1G_TX_PORTS)
++
++#define FM_PORT_MAX_NUM_OF_EXT_POOLS            4           /**< Number of external BM pools per Rx port */
++#define FM_PORT_NUM_OF_CONGESTION_GRPS          256         /**< Total number of congestion groups in QM */
++#define FM_MAX_NUM_OF_SUB_PORTALS               16
++#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS   0
++
++#define FM_VSP_MAX_NUM_OF_ENTRIES               64
++#define FM_MAX_NUM_OF_PFC_PRIORITIES            8
++
++/* RAMs defines */
++#define FM_MURAM_SIZE                   (384 * KILOBYTE)
++#define FM_IRAM_SIZE(major, minor)      (64 * KILOBYTE)
++#define FM_NUM_OF_CTRL                  4
++
++/* PCD defines */
++#define FM_PCD_PLCR_NUM_ENTRIES         256                 /**< Total number of policer profiles */
++#define FM_PCD_KG_NUM_OF_SCHEMES        32                  /**< Total number of KG schemes */
++#define FM_PCD_MAX_NUM_OF_CLS_PLANS     256                 /**< Number of classification plan entries. */
++#define FM_PCD_PRS_SW_PATCHES_SIZE      0x00000600          /**< Number of bytes saved for patches */
++#define FM_PCD_SW_PRS_SIZE              0x00000800          /**< Total size of SW parser area */
++
++/* RTC defines */
++#define FM_RTC_NUM_OF_ALARMS            2                   /**< RTC number of alarms */
++#define FM_RTC_NUM_OF_PERIODIC_PULSES   3                   /**< RTC number of periodic pulses */
++#define FM_RTC_NUM_OF_EXT_TRIGGERS      2                   /**< RTC number of external triggers */
++
++/* QMI defines */
++#define QMI_MAX_NUM_OF_TNUMS            64
++#define QMI_DEF_TNUMS_THRESH            32
++/* FPM defines */
++#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS  4
++
++/* DMA defines */
++#define DMA_THRESH_MAX_COMMQ            83
++#define DMA_THRESH_MAX_BUF              127
++
++/* BMI defines */
++#define BMI_MAX_NUM_OF_TASKS            128
++#define BMI_MAX_NUM_OF_DMAS             84
++
++#define BMI_MAX_FIFO_SIZE               (FM_MURAM_SIZE)
++#define PORT_MAX_WEIGHT                 16
++
++#define FM_CHECK_PORT_RESTRICTIONS(__validPorts, __newPortIndx)   TRUE
++
++/* Unique T4240 */
++#define FM_OP_OPEN_DMA_MIN_LIMIT
++#define FM_NO_RESTRICT_ON_ACCESS_RSRC
++#define FM_NO_OP_OBSERVED_POOLS
++#define FM_FRAME_END_PARAMS_FOR_OP
++#define FM_DEQ_PIPELINE_PARAMS_FOR_OP
++#define FM_QMI_NO_SINGLE_ECC_EXCEPTION
++
++#define FM_NO_GUARANTEED_RESET_VALUES
++
++/* FM errata */
++#define FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
++#define FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127
++#define FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320
++#define FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675
++#define FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981
++
++#define FM_BCB_ERRATA_BMI_SW001
++#define FM_LEN_CHECK_ERRATA_FMAN_SW002
++#define FM_AID_MODE_NO_TNUM_SW005 /* refer to pdm TKT068794 - only support of port_id on aid */
++#define FM_ERROR_VSP_NO_MATCH_SW006 /* refer to pdm TKT174304 - no match between errorQ and VSP */
++
++/*****************************************************************************
++ RMan INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define RM_MAX_NUM_OF_IB        4           /**< Number of inbound blocks */
++#define RM_NUM_OF_IBCU          8           /**< NUmber of classification units in an inbound block */
++
++/* RMan erratas */
++#define RM_ERRONEOUS_ACK_ERRATA_RMAN_A006756
++
++/*****************************************************************************
++ FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define NUM_OF_RX_SC                16
++#define NUM_OF_TX_SC                16
++
++#define NUM_OF_SA_PER_RX_SC         2
++#define NUM_OF_SA_PER_TX_SC         2
++
++#endif /* __DPAA_INTEGRATION_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_ext.h
+@@ -0,0 +1,64 @@
++/*
++ * Copyright 2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**************************************************************************//**
++
++ @File          part_ext.h
++
++ @Description   Definitions for the part (integration) module.
++*//***************************************************************************/
++
++#ifndef __PART_EXT_H
++#define __PART_EXT_H
++
++#include "std_ext.h"
++#include "part_integration_ext.h"
++
++#if !(defined(LS1043))
++#error "unable to proceed without chip-definition"
++#endif
++
++
++/**************************************************************************//*
++ @Description   Part data structure - must be contained in any integration
++                data structure.
++*//***************************************************************************/
++typedef struct t_Part
++{
++    uintptr_t   (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId);
++                /**< Returns the address of the module's memory map base. */
++    e_ModuleId  (* f_GetModuleIdByBase)(t_Handle h_Part, uintptr_t baseAddress);
++                /**< Returns the module's ID according to its memory map base. */
++} t_Part;
++
++
++#endif /* __PART_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_integration_ext.h
+@@ -0,0 +1,185 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**
++
++ @File          part_integration_ext.h
++
++ @Description   T4240 external definitions and structures.
++*//***************************************************************************/
++#ifndef __PART_INTEGRATION_EXT_H
++#define __PART_INTEGRATION_EXT_H
++
++#include "std_ext.h"
++#include "ddr_std_ext.h"
++#include "enet_ext.h"
++#include "dpaa_integration_ext.h"
++
++
++/**************************************************************************//**
++ @Group         T4240_chip_id T4240 Application Programming Interface
++
++ @Description   T4240 Chip functions,definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++#define INTG_MAX_NUM_OF_CORES   4
++
++/**************************************************************************//**
++ @Description   Module types.
++*//***************************************************************************/
++typedef enum e_ModuleId
++{
++    e_MODULE_ID_DUART_1 = 0,
++    e_MODULE_ID_DUART_2,
++    e_MODULE_ID_DUART_3,
++    e_MODULE_ID_DUART_4,
++    e_MODULE_ID_LAW,
++    e_MODULE_ID_IFC,
++    e_MODULE_ID_PAMU,
++    e_MODULE_ID_QM,                 /**< Queue manager module */
++    e_MODULE_ID_BM,                 /**< Buffer manager module */
++    e_MODULE_ID_QM_CE_PORTAL_0,
++    e_MODULE_ID_QM_CI_PORTAL_0,
++    e_MODULE_ID_QM_CE_PORTAL_1,
++    e_MODULE_ID_QM_CI_PORTAL_1,
++    e_MODULE_ID_QM_CE_PORTAL_2,
++    e_MODULE_ID_QM_CI_PORTAL_2,
++    e_MODULE_ID_QM_CE_PORTAL_3,
++    e_MODULE_ID_QM_CI_PORTAL_3,
++    e_MODULE_ID_QM_CE_PORTAL_4,
++    e_MODULE_ID_QM_CI_PORTAL_4,
++    e_MODULE_ID_QM_CE_PORTAL_5,
++    e_MODULE_ID_QM_CI_PORTAL_5,
++    e_MODULE_ID_QM_CE_PORTAL_6,
++    e_MODULE_ID_QM_CI_PORTAL_6,
++    e_MODULE_ID_QM_CE_PORTAL_7,
++    e_MODULE_ID_QM_CI_PORTAL_7,
++    e_MODULE_ID_QM_CE_PORTAL_8,
++    e_MODULE_ID_QM_CI_PORTAL_8,
++    e_MODULE_ID_QM_CE_PORTAL_9,
++    e_MODULE_ID_QM_CI_PORTAL_9,
++    e_MODULE_ID_BM_CE_PORTAL_0,
++    e_MODULE_ID_BM_CI_PORTAL_0,
++    e_MODULE_ID_BM_CE_PORTAL_1,
++    e_MODULE_ID_BM_CI_PORTAL_1,
++    e_MODULE_ID_BM_CE_PORTAL_2,
++    e_MODULE_ID_BM_CI_PORTAL_2,
++    e_MODULE_ID_BM_CE_PORTAL_3,
++    e_MODULE_ID_BM_CI_PORTAL_3,
++    e_MODULE_ID_BM_CE_PORTAL_4,
++    e_MODULE_ID_BM_CI_PORTAL_4,
++    e_MODULE_ID_BM_CE_PORTAL_5,
++    e_MODULE_ID_BM_CI_PORTAL_5,
++    e_MODULE_ID_BM_CE_PORTAL_6,
++    e_MODULE_ID_BM_CI_PORTAL_6,
++    e_MODULE_ID_BM_CE_PORTAL_7,
++    e_MODULE_ID_BM_CI_PORTAL_7,
++    e_MODULE_ID_BM_CE_PORTAL_8,
++    e_MODULE_ID_BM_CI_PORTAL_8,
++    e_MODULE_ID_BM_CE_PORTAL_9,
++    e_MODULE_ID_BM_CI_PORTAL_9,
++    e_MODULE_ID_FM,                 /**< Frame manager module */
++    e_MODULE_ID_FM_RTC,             /**< FM Real-Time-Clock */
++    e_MODULE_ID_FM_MURAM,           /**< FM Multi-User-RAM */
++    e_MODULE_ID_FM_BMI,             /**< FM BMI block */
++    e_MODULE_ID_FM_QMI,             /**< FM QMI block */
++    e_MODULE_ID_FM_PARSER,          /**< FM parser block */
++    e_MODULE_ID_FM_PORT_HO1,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO2,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO3,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO4,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO5,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO6,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO7,        /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_1GRx1,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx2,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx3,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx4,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx5,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx6,      /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_10GRx1,     /**< FM Rx 10G MAC port block */
++    e_MODULE_ID_FM_PORT_10GRx2,     /**< FM Rx 10G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx1,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx2,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx3,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx4,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx5,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx6,      /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_10GTx1,     /**< FM Tx 10G MAC port block */
++    e_MODULE_ID_FM_PORT_10GTx2,     /**< FM Tx 10G MAC port block */
++    e_MODULE_ID_FM_PLCR,            /**< FM Policer */
++    e_MODULE_ID_FM_KG,              /**< FM Keygen */
++    e_MODULE_ID_FM_DMA,             /**< FM DMA */
++    e_MODULE_ID_FM_FPM,             /**< FM FPM */
++    e_MODULE_ID_FM_IRAM,            /**< FM Instruction-RAM */
++    e_MODULE_ID_FM_1GMDIO,          /**< FM 1G MDIO MAC */
++    e_MODULE_ID_FM_10GMDIO,         /**< FM 10G MDIO */
++    e_MODULE_ID_FM_PRS_IRAM,        /**< FM SW-parser Instruction-RAM */
++    e_MODULE_ID_FM_1GMAC1,          /**< FM 1G MAC #1 */
++    e_MODULE_ID_FM_1GMAC2,          /**< FM 1G MAC #2 */
++    e_MODULE_ID_FM_1GMAC3,          /**< FM 1G MAC #3 */
++    e_MODULE_ID_FM_1GMAC4,          /**< FM 1G MAC #4 */
++    e_MODULE_ID_FM_1GMAC5,          /**< FM 1G MAC #5 */
++    e_MODULE_ID_FM_1GMAC6,          /**< FM 1G MAC #6 */
++    e_MODULE_ID_FM_10GMAC1,         /**< FM 10G MAC */
++    e_MODULE_ID_FM_10GMAC2,         /**< FM 10G MAC */
++
++    e_MODULE_ID_SEC_GEN,            /**< SEC 4.0 General registers      */
++    e_MODULE_ID_SEC_QI,             /**< SEC 4.0 QI registers           */
++    e_MODULE_ID_SEC_JQ0,            /**< SEC 4.0 JQ-0 registers         */
++    e_MODULE_ID_SEC_JQ1,            /**< SEC 4.0 JQ-1 registers         */
++    e_MODULE_ID_SEC_JQ2,            /**< SEC 4.0 JQ-2 registers         */
++    e_MODULE_ID_SEC_JQ3,            /**< SEC 4.0 JQ-3 registers         */
++    e_MODULE_ID_SEC_RTIC,           /**< SEC 4.0 RTIC registers         */
++    e_MODULE_ID_SEC_DECO0_CCB0,     /**< SEC 4.0 DECO-0/CCB-0 registers */
++    e_MODULE_ID_SEC_DECO1_CCB1,     /**< SEC 4.0 DECO-1/CCB-1 registers */
++    e_MODULE_ID_SEC_DECO2_CCB2,     /**< SEC 4.0 DECO-2/CCB-2 registers */
++    e_MODULE_ID_SEC_DECO3_CCB3,     /**< SEC 4.0 DECO-3/CCB-3 registers */
++    e_MODULE_ID_SEC_DECO4_CCB4,     /**< SEC 4.0 DECO-4/CCB-4 registers */
++
++    e_MODULE_ID_PIC,                /**< PIC */
++    e_MODULE_ID_GPIO,               /**< GPIO */
++    e_MODULE_ID_SERDES,             /**< SERDES */
++    e_MODULE_ID_CPC_1,              /**< CoreNet-Platform-Cache 1 */
++    e_MODULE_ID_CPC_2,              /**< CoreNet-Platform-Cache 2 */
++
++    e_MODULE_ID_SRIO_PORTS,         /**< RapidIO controller */
++
++    e_MODULE_ID_DUMMY_LAST
++} e_ModuleId;
++
++#define NUM_OF_MODULES  e_MODULE_ID_DUMMY_LAST
++
++
++#endif /* __PART_INTEGRATION_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/dpaa_integration_ext.h
+@@ -0,0 +1,213 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**
++
++ @File          dpaa_integration_ext.h
++
++ @Description   P1023 FM external definitions and structures.
++*//***************************************************************************/
++#ifndef __DPAA_INTEGRATION_EXT_H
++#define __DPAA_INTEGRATION_EXT_H
++
++#include "std_ext.h"
++
++
++#define DPAA_VERSION    10
++
++typedef enum e_DpaaSwPortal {
++    e_DPAA_SWPORTAL0 = 0,
++    e_DPAA_SWPORTAL1,
++    e_DPAA_SWPORTAL2,
++    e_DPAA_SWPORTAL_DUMMY_LAST
++} e_DpaaSwPortal;
++
++typedef enum {
++    e_DPAA_DCPORTAL0 = 0,
++    e_DPAA_DCPORTAL2,
++    e_DPAA_DCPORTAL_DUMMY_LAST
++} e_DpaaDcPortal;
++
++#define DPAA_MAX_NUM_OF_SW_PORTALS      e_DPAA_SWPORTAL_DUMMY_LAST
++#define DPAA_MAX_NUM_OF_DC_PORTALS      e_DPAA_DCPORTAL_DUMMY_LAST
++
++/*****************************************************************************
++ QMAN INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define QM_MAX_NUM_OF_POOL_CHANNELS 3
++#define QM_MAX_NUM_OF_WQ            8
++#define QM_MAX_NUM_OF_SWP_AS        2
++#define QM_MAX_NUM_OF_CGS           64
++#define QM_MAX_NUM_OF_FQIDS         (16*MEGABYTE)
++
++typedef enum {
++    e_QM_FQ_CHANNEL_SWPORTAL0 = 0,
++    e_QM_FQ_CHANNEL_SWPORTAL1,
++    e_QM_FQ_CHANNEL_SWPORTAL2,
++
++    e_QM_FQ_CHANNEL_POOL1 = 0x21,
++    e_QM_FQ_CHANNEL_POOL2,
++    e_QM_FQ_CHANNEL_POOL3,
++
++    e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x40,
++    e_QM_FQ_CHANNEL_FMAN0_SP1,
++    e_QM_FQ_CHANNEL_FMAN0_SP2,
++    e_QM_FQ_CHANNEL_FMAN0_SP3,
++    e_QM_FQ_CHANNEL_FMAN0_SP4,
++    e_QM_FQ_CHANNEL_FMAN0_SP5,
++    e_QM_FQ_CHANNEL_FMAN0_SP6,
++
++
++    e_QM_FQ_CHANNEL_CAAM = 0x80
++} e_QmFQChannel;
++
++/*****************************************************************************
++ BMAN INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define BM_MAX_NUM_OF_POOLS         8
++
++/*****************************************************************************
++ SEC INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define SEC_NUM_OF_DECOS    2
++#define SEC_ALL_DECOS_MASK  0x00000003
++#define SEC_RNGB
++#define SEC_NO_ESP_TRAILER_REMOVAL
++
++/*****************************************************************************
++ FM INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define INTG_MAX_NUM_OF_FM          1
++
++/* Ports defines */
++#define FM_MAX_NUM_OF_1G_MACS       2
++#define FM_MAX_NUM_OF_10G_MACS      0
++#define FM_MAX_NUM_OF_MACS          (FM_MAX_NUM_OF_1G_MACS + FM_MAX_NUM_OF_10G_MACS)
++#define FM_MAX_NUM_OF_OH_PORTS      5
++
++#define FM_MAX_NUM_OF_1G_RX_PORTS   FM_MAX_NUM_OF_1G_MACS
++#define FM_MAX_NUM_OF_10G_RX_PORTS  FM_MAX_NUM_OF_10G_MACS
++#define FM_MAX_NUM_OF_RX_PORTS      (FM_MAX_NUM_OF_10G_RX_PORTS + FM_MAX_NUM_OF_1G_RX_PORTS)
++
++#define FM_MAX_NUM_OF_1G_TX_PORTS   FM_MAX_NUM_OF_1G_MACS
++#define FM_MAX_NUM_OF_10G_TX_PORTS  FM_MAX_NUM_OF_10G_MACS
++#define FM_MAX_NUM_OF_TX_PORTS      (FM_MAX_NUM_OF_10G_TX_PORTS + FM_MAX_NUM_OF_1G_TX_PORTS)
++
++#define FM_MAX_NUM_OF_MACSECS       1
++
++#define FM_MACSEC_SUPPORT
++
++#define FM_LOW_END_RESTRICTION      /* prevents the use of TX port 1 with OP port 0 */
++
++#define FM_PORT_MAX_NUM_OF_EXT_POOLS            4           /**< Number of external BM pools per Rx port */
++#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS   2           /**< Number of Offline parsing port external BM pools per Rx port */
++#define FM_PORT_NUM_OF_CONGESTION_GRPS          32          /**< Total number of congestion groups in QM */
++#define FM_MAX_NUM_OF_SUB_PORTALS               7
++
++/* Rams defines */
++#define FM_MURAM_SIZE                   (64*KILOBYTE)
++#define FM_IRAM_SIZE(major, minor)      (32 * KILOBYTE)
++#define FM_NUM_OF_CTRL                  2
++
++/* PCD defines */
++#define FM_PCD_PLCR_NUM_ENTRIES         32                  /**< Total number of policer profiles */
++#define FM_PCD_KG_NUM_OF_SCHEMES        16                  /**< Total number of KG schemes */
++#define FM_PCD_MAX_NUM_OF_CLS_PLANS     128                 /**< Number of classification plan entries. */
++#define FM_PCD_PRS_SW_PATCHES_SIZE      0x00000240          /**< Number of bytes saved for patches */
++#define FM_PCD_SW_PRS_SIZE              0x00000800          /**< Total size of SW parser area */
++
++/* RTC defines */
++#define FM_RTC_NUM_OF_ALARMS            2
++#define FM_RTC_NUM_OF_PERIODIC_PULSES   2
++#define FM_RTC_NUM_OF_EXT_TRIGGERS      2
++
++/* QMI defines */
++#define QMI_MAX_NUM_OF_TNUMS            15
++
++/* FPM defines */
++#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS  4
++
++/* DMA defines */
++#define DMA_THRESH_MAX_COMMQ            15
++#define DMA_THRESH_MAX_BUF              7
++
++/* BMI defines */
++#define BMI_MAX_NUM_OF_TASKS            64
++#define BMI_MAX_NUM_OF_DMAS             16
++#define BMI_MAX_FIFO_SIZE              (FM_MURAM_SIZE)
++#define PORT_MAX_WEIGHT                 4
++
++/*****************************************************************************
++ FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define NUM_OF_RX_SC                16
++#define NUM_OF_TX_SC                16
++
++#define NUM_OF_SA_PER_RX_SC         2
++#define NUM_OF_SA_PER_TX_SC         2
++
++/**************************************************************************//**
++ @Description   Enum for inter-module interrupts registration
++*//***************************************************************************/
++
++/* 1023 unique features */
++#define FM_QMI_NO_ECC_EXCEPTIONS
++#define FM_CSI_CFED_LIMIT
++#define FM_PEDANTIC_DMA
++#define FM_QMI_NO_DEQ_OPTIONS_SUPPORT
++#define FM_FIFO_ALLOCATION_ALG
++#define FM_DEQ_PIPELINE_PARAMS_FOR_OP
++#define FM_HAS_TOTAL_DMAS
++#define FM_KG_NO_IPPID_SUPPORT
++#define FM_NO_GUARANTEED_RESET_VALUES
++#define FM_MAC_RESET
++
++/* FM erratas */
++#define FM_RX_PREAM_4_ERRATA_DTSEC_A001
++#define FM_MAGIC_PACKET_UNRECOGNIZED_ERRATA_DTSEC2      /* No implementation, Out of LLD scope */
++
++#define FM_DEBUG_TRACE_FMAN_A004                        /* No implementation, Out of LLD scope */
++#define FM_INT_BUF_LEAK_FMAN_A005                       /* No implementation, Out of LLD scope. App must avoid S/G */
++
++#define FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839
++
++/* #define FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
++
++/*
++TKT056919 - axi12axi0 can hang if read request follows the single byte write on the very next cycle
++TKT038900 - FM dma lockup occur due to AXI slave protocol violation
++*/
++#define FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004
++
++
++#endif /* __DPAA_INTEGRATION_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_ext.h
+@@ -0,0 +1,82 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++
++ @File          part_ext.h
++
++ @Description   Definitions for the part (integration) module.
++*//***************************************************************************/
++
++#ifndef __PART_EXT_H
++#define __PART_EXT_H
++
++#include "std_ext.h"
++#include "part_integration_ext.h"
++
++
++#if !(defined(MPC8306) || \
++      defined(MPC8309) || \
++      defined(MPC834x) || \
++      defined(MPC836x) || \
++      defined(MPC832x) || \
++      defined(MPC837x) || \
++      defined(MPC8568) || \
++      defined(MPC8569) || \
++      defined(P1020)   || \
++      defined(P1021)   || \
++      defined(P1022)   || \
++      defined(P1023)   || \
++      defined(P2020)   || \
++      defined(P3041)   || \
++      defined(P4080)   || \
++      defined(P5020)   || \
++      defined(MSC814x))
++#error "unable to proceed without chip-definition"
++#endif
++
++
++/**************************************************************************//*
++ @Description   Part data structure - must be contained in any integration
++                data structure.
++*//***************************************************************************/
++typedef struct t_Part
++{
++    uint64_t    (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId);
++                /**< Returns the address of the module's memory map base. */
++    e_ModuleId  (* f_GetModuleIdByBase)(t_Handle h_Part, uint64_t baseAddress);
++                /**< Returns the module's ID according to its memory map base. */
++} t_Part;
++
++
++#endif /* __PART_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_integration_ext.h
+@@ -0,0 +1,635 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**************************************************************************//**
++ @File          part_integration_ext.h
++
++ @Description   P1023 external definitions and structures.
++*//***************************************************************************/
++#ifndef __PART_INTEGRATION_EXT_H
++#define __PART_INTEGRATION_EXT_H
++
++#include "std_ext.h"
++#include "dpaa_integration_ext.h"
++
++
++/**************************************************************************//**
++ @Group         1023_chip_id P1023 Application Programming Interface
++
++ @Description   P1023 Chip functions,definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++#define INTG_MAX_NUM_OF_CORES   2
++
++
++/**************************************************************************//**
++ @Description   Module types.
++*//***************************************************************************/
++typedef enum e_ModuleId
++{
++    e_MODULE_ID_LAW,            /**< Local Access module                     */
++    e_MODULE_ID_ECM,            /**< e500 Coherency Module                   */
++    e_MODULE_ID_DDR,            /**< DDR memory controller                   */
++    e_MODULE_ID_I2C_1,          /**< I2C 1                                   */
++    e_MODULE_ID_I2C_2,          /**< I2C 1                                   */
++    e_MODULE_ID_DUART_1,        /**< DUART module 1                          */
++    e_MODULE_ID_DUART_2,        /**< DUART module 2                          */
++    e_MODULE_ID_LBC,            /**< Local bus memory controller module      */
++    e_MODULE_ID_PCIE_1,         /**< PCI Express 1 controller module         */
++    e_MODULE_ID_PCIE_ATMU_1,    /**< PCI 1 ATMU Window                       */
++    e_MODULE_ID_PCIE_2,         /**< PCI Express 2 controller module         */
++    e_MODULE_ID_PCIE_ATMU_2,    /**< PCI 2 ATMU Window                       */
++    e_MODULE_ID_PCIE_3,         /**< PCI Express 3 controller module         */
++    e_MODULE_ID_PCIE_ATMU_3,    /**< PCI 3 ATMU Window                       */
++    e_MODULE_ID_MSI,            /**< MSI registers                           */
++    e_MODULE_ID_L2_SRAM,        /**< L2/SRAM Memory-Mapped controller module */
++    e_MODULE_ID_DMA_1,          /**< DMA controller 1                        */
++    e_MODULE_ID_DMA_2,          /**< DMA controller 2                        */
++    e_MODULE_ID_EPIC,           /**< Programmable interrupt controller       */
++    e_MODULE_ID_ESPI,           /**< ESPI module                             */
++    e_MODULE_ID_GPIO,           /**< General Purpose I/O                     */
++    e_MODULE_ID_SEC_GEN,        /**< SEC 4.0 General registers               */
++    e_MODULE_ID_SEC_QI,         /**< SEC 4.0 QI registers                    */
++    e_MODULE_ID_SEC_JQ0,        /**< SEC 4.0 JQ-0 registers                  */
++    e_MODULE_ID_SEC_JQ1,        /**< SEC 4.0 JQ-1 registers                  */
++    e_MODULE_ID_SEC_JQ2,        /**< SEC 4.0 JQ-2 registers                  */
++    e_MODULE_ID_SEC_JQ3,        /**< SEC 4.0 JQ-3 registers                  */
++    e_MODULE_ID_SEC_RTIC,       /**< SEC 4.0 RTIC registers                  */
++    e_MODULE_ID_SEC_DECO0_CCB0, /**< SEC 4.0 DECO-0/CCB-0 registers          */
++    e_MODULE_ID_SEC_DECO1_CCB1, /**< SEC 4.0 DECO-1/CCB-1 registers          */
++    e_MODULE_ID_SEC_DECO2_CCB2, /**< SEC 4.0 DECO-2/CCB-2 registers          */
++    e_MODULE_ID_SEC_DECO3_CCB3, /**< SEC 4.0 DECO-3/CCB-3 registers          */
++    e_MODULE_ID_SEC_DECO4_CCB4, /**< SEC 4.0 DECO-4/CCB-4 registers          */
++    e_MODULE_ID_USB_DR_1,       /**< USB 2.0 module 1                        */
++    e_MODULE_ID_USB_DR_2,       /**< USB 2.0 module 2                        */
++    e_MODULE_ID_ETSEC_MII_MNG,  /**< MII MNG registers                       */
++    e_MODULE_ID_ETSEC_1,        /**< ETSEC module 1                             */
++    e_MODULE_ID_ETSEC_2,        /**< ETSEC module 2                             */
++    e_MODULE_ID_GUTS,           /**< Serial DMA                              */
++    e_MODULE_ID_PM,             /**< Performance Monitor module              */
++    e_MODULE_ID_QM,                 /**< Queue manager module */
++    e_MODULE_ID_BM,                 /**< Buffer manager module */
++    e_MODULE_ID_QM_CE_PORTAL,
++    e_MODULE_ID_QM_CI_PORTAL,
++    e_MODULE_ID_BM_CE_PORTAL,
++    e_MODULE_ID_BM_CI_PORTAL,
++    e_MODULE_ID_FM,                /**< Frame manager #1 module */
++    e_MODULE_ID_FM_RTC,            /**< FM Real-Time-Clock */
++    e_MODULE_ID_FM_MURAM,          /**< FM Multi-User-RAM */
++    e_MODULE_ID_FM_BMI,            /**< FM BMI block */
++    e_MODULE_ID_FM_QMI,            /**< FM QMI block */
++    e_MODULE_ID_FM_PRS,            /**< FM parser block */
++    e_MODULE_ID_FM_PORT_HO0,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO1,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO2,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO3,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_HO4,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM_PORT_1GRx0,     /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GRx1,     /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx0,     /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PORT_1GTx1,     /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM_PLCR,           /**< FM Policer */
++    e_MODULE_ID_FM_KG,             /**< FM Keygen */
++    e_MODULE_ID_FM_DMA,            /**< FM DMA */
++    e_MODULE_ID_FM_FPM,            /**< FM FPM */
++    e_MODULE_ID_FM_IRAM,           /**< FM Instruction-RAM */
++    e_MODULE_ID_FM_1GMDIO0,        /**< FM 1G MDIO MAC 0*/
++    e_MODULE_ID_FM_1GMDIO1,        /**< FM 1G MDIO MAC 1*/
++    e_MODULE_ID_FM_PRS_IRAM,       /**< FM SW-parser Instruction-RAM */
++    e_MODULE_ID_FM_RISC0,          /**< FM risc #0 */
++    e_MODULE_ID_FM_RISC1,          /**< FM risc #1 */
++    e_MODULE_ID_FM_1GMAC0,         /**< FM 1G MAC #0 */
++    e_MODULE_ID_FM_1GMAC1,         /**< FM 1G MAC #1 */
++    e_MODULE_ID_FM_MACSEC,         /**< FM MACSEC */
++
++    e_MODULE_ID_DUMMY_LAST
++} e_ModuleId;
++
++#define NUM_OF_MODULES  e_MODULE_ID_DUMMY_LAST
++
++
++#define P1023_OFFSET_LAW                    0x00000C08
++#define P1023_OFFSET_ECM                    0x00001000
++#define P1023_OFFSET_DDR                    0x00002000
++#define P1023_OFFSET_I2C1                   0x00003000
++#define P1023_OFFSET_I2C2                   0x00003100
++#define P1023_OFFSET_DUART1                 0x00004500
++#define P1023_OFFSET_DUART2                 0x00004600
++#define P1023_OFFSET_LBC                    0x00005000
++#define P1023_OFFSET_ESPI                   0x00007000
++#define P1023_OFFSET_PCIE2                  0x00009000
++#define P1023_OFFSET_PCIE2_ATMU             0x00009C00
++#define P1023_OFFSET_PCIE1                  0x0000A000
++#define P1023_OFFSET_PCIE1_ATMU             0x0000AC00
++#define P1023_OFFSET_PCIE3                  0x0000B000
++#define P1023_OFFSET_PCIE3_ATMU             0x0000BC00
++#define P1023_OFFSET_DMA2                   0x0000C100
++#define P1023_OFFSET_GPIO                   0x0000F000
++#define P1023_OFFSET_L2_SRAM                0x00020000
++#define P1023_OFFSET_DMA1                   0x00021100
++#define P1023_OFFSET_USB1                   0x00022000
++#define P1023_OFFSET_SEC_GEN                0x00030000
++#define P1023_OFFSET_SEC_JQ0                0x00031000
++#define P1023_OFFSET_SEC_JQ1                0x00032000
++#define P1023_OFFSET_SEC_JQ2                0x00033000
++#define P1023_OFFSET_SEC_JQ3                0x00034000
++#define P1023_OFFSET_SEC_RTIC               0x00036000
++#define P1023_OFFSET_SEC_QI                 0x00037000
++#define P1023_OFFSET_SEC_DECO0_CCB0         0x00038000
++#define P1023_OFFSET_SEC_DECO1_CCB1         0x00039000
++#define P1023_OFFSET_SEC_DECO2_CCB2         0x0003a000
++#define P1023_OFFSET_SEC_DECO3_CCB3         0x0003b000
++#define P1023_OFFSET_SEC_DECO4_CCB4         0x0003c000
++#define P1023_OFFSET_PIC                    0x00040000
++#define P1023_OFFSET_MSI                    0x00041600
++#define P1023_OFFSET_AXI                    0x00081000
++#define P1023_OFFSET_QM                     0x00088000
++#define P1023_OFFSET_BM                     0x0008A000
++#define P1022_OFFSET_PM                     0x000E1000
++
++#define P1023_OFFSET_GUTIL                  0x000E0000
++#define P1023_OFFSET_PM                     0x000E1000
++#define P1023_OFFSET_DEBUG                  0x000E2000
++#define P1023_OFFSET_SERDES                 0x000E3000
++#define P1023_OFFSET_ROM                    0x000F0000
++#define P1023_OFFSET_FM                     0x00100000
++
++#define P1023_OFFSET_FM_MURAM               (P1023_OFFSET_FM + 0x00000000)
++#define P1023_OFFSET_FM_BMI                 (P1023_OFFSET_FM + 0x00080000)
++#define P1023_OFFSET_FM_QMI                 (P1023_OFFSET_FM + 0x00080400)
++#define P1023_OFFSET_FM_PRS                 (P1023_OFFSET_FM + 0x00080800)
++#define P1023_OFFSET_FM_PORT_HO0            (P1023_OFFSET_FM + 0x00081000)
++#define P1023_OFFSET_FM_PORT_HO1            (P1023_OFFSET_FM + 0x00082000)
++#define P1023_OFFSET_FM_PORT_HO2            (P1023_OFFSET_FM + 0x00083000)
++#define P1023_OFFSET_FM_PORT_HO3            (P1023_OFFSET_FM + 0x00084000)
++#define P1023_OFFSET_FM_PORT_HO4            (P1023_OFFSET_FM + 0x00085000)
++#define P1023_OFFSET_FM_PORT_1GRX0          (P1023_OFFSET_FM + 0x00088000)
++#define P1023_OFFSET_FM_PORT_1GRX1          (P1023_OFFSET_FM + 0x00089000)
++#define P1023_OFFSET_FM_PORT_1GTX0          (P1023_OFFSET_FM + 0x000A8000)
++#define P1023_OFFSET_FM_PORT_1GTX1          (P1023_OFFSET_FM + 0x000A9000)
++#define P1023_OFFSET_FM_PLCR                (P1023_OFFSET_FM + 0x000C0000)
++#define P1023_OFFSET_FM_KG                  (P1023_OFFSET_FM + 0x000C1000)
++#define P1023_OFFSET_FM_DMA                 (P1023_OFFSET_FM + 0x000C2000)
++#define P1023_OFFSET_FM_FPM                 (P1023_OFFSET_FM + 0x000C3000)
++#define P1023_OFFSET_FM_IRAM                (P1023_OFFSET_FM + 0x000C4000)
++#define P1023_OFFSET_FM_PRS_IRAM            (P1023_OFFSET_FM + 0x000C7000)
++#define P1023_OFFSET_FM_RISC0               (P1023_OFFSET_FM + 0x000D0000)
++#define P1023_OFFSET_FM_RISC1               (P1023_OFFSET_FM + 0x000D0400)
++#define P1023_OFFSET_FM_MACSEC              (P1023_OFFSET_FM + 0x000D8000)
++#define P1023_OFFSET_FM_1GMAC0              (P1023_OFFSET_FM + 0x000E0000)
++#define P1023_OFFSET_FM_1GMDIO0             (P1023_OFFSET_FM + 0x000E1120)
++#define P1023_OFFSET_FM_1GMAC1              (P1023_OFFSET_FM + 0x000E2000)
++#define P1023_OFFSET_FM_1GMDIO1             (P1023_OFFSET_FM + 0x000E3000)
++#define P1023_OFFSET_FM_RTC                 (P1023_OFFSET_FM + 0x000FE000)
++
++/* Offsets relative to QM or BM portals base */
++#define P1023_OFFSET_PORTALS_CE_AREA        0x00000000        /* cache enabled area */
++#define P1023_OFFSET_PORTALS_CI_AREA        0x00100000        /* cache inhibited area */
++
++#define P1023_OFFSET_PORTALS_CE(portal)     (P1023_OFFSET_PORTALS_CE_AREA + 0x4000 * (portal))
++#define P1023_OFFSET_PORTALS_CI(portal)     (P1023_OFFSET_PORTALS_CI_AREA + 0x1000 * (portal))
++
++/**************************************************************************//**
++ @Description   Transaction source ID (for memory controllers error reporting).
++*//***************************************************************************/
++typedef enum e_TransSrc
++{
++    e_TRANS_SRC_PCIE_2          = 0x01, /**< PCIe port 2                    */
++    e_TRANS_SRC_PCIE_1          = 0x02, /**< PCIe port 1                    */
++    e_TRANS_SRC_PCIE_3          = 0x03, /**< PCIe port 3                    */
++    e_TRANS_SRC_LBC             = 0x04, /**< Enhanced local bus             */
++    e_TRANS_SRC_DPAA_SW_PORTALS = 0x0E, /**< DPAA software portals or SRAM  */
++    e_TRANS_SRC_DDR             = 0x0F, /**< DDR controller                 */
++    e_TRANS_SRC_CORE_INS_FETCH  = 0x10, /**< Processor (instruction)        */
++    e_TRANS_SRC_CORE_DATA       = 0x11, /**< Processor (data)               */
++    e_TRANS_SRC_DMA             = 0x15  /**< DMA                            */
++} e_TransSrc;
++
++/**************************************************************************//**
++ @Description   Local Access Window Target interface ID
++*//***************************************************************************/
++typedef enum e_P1023LawTargetId
++{
++    e_P1023_LAW_TARGET_PCIE_2       = 0x01, /**< PCI Express 2 target interface */
++    e_P1023_LAW_TARGET_PCIE_1       = 0x02, /**< PCI Express 1 target interface */
++    e_P1023_LAW_TARGET_PCIE_3       = 0x03, /**< PCI Express 3 target interface */
++    e_P1023_LAW_TARGET_LBC          = 0x04, /**< Local bus target interface */
++    e_P1023_LAW_TARGET_QM_PORTALS   = 0x0E, /**< Queue Manager Portals */
++    e_P1023_LAW_TARGET_BM_PORTALS   = 0x0E, /**< Buffer Manager Portals */
++    e_P1023_LAW_TARGET_SRAM         = 0x0E, /**< SRAM scratchpad */
++    e_P1023_LAW_TARGET_DDR          = 0x0F, /**< DDR target interface */
++    e_P1023_LAW_TARGET_NONE         = 0xFF  /**< Invalid target interface */
++} e_P1023LawTargetId;
++
++
++/**************************************************************************//**
++ @Group         1023_init_grp P1023 Initialization Unit
++
++ @Description   P1023 initialization unit API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   Part ID and revision number
++*//***************************************************************************/
++typedef enum e_P1023DeviceName
++{
++    e_P1023_REV_INVALID     = 0x00000000,       /**< Invalid revision */
++    e_SC1023_REV_1_0        = (int)0x80FC0010,  /**< SC1023 rev 1.0 */
++    e_SC1023_REV_1_1        = (int)0x80FC0011,  /**< SC1023 rev 1.1 */
++    e_P1023_REV_1_0         = (int)0x80FE0010,  /**< P1023 rev 1.0 with security */
++    e_P1023_REV_1_1         = (int)0x80FE0011,  /**< P1023 rev 1.1 with security */
++    e_P1017_REV_1_1         = (int)0x80FF0011,  /**< P1017 rev 1.1 with security */
++    e_P1023_REV_1_0_NO_SEC  = (int)0x80F60010,  /**< P1023 rev 1.0 without security */
++    e_P1023_REV_1_1_NO_SEC  = (int)0x80F60011,  /**< P1023 rev 1.1 without security */
++    e_P1017_REV_1_1_NO_SEC  = (int)0x80F70011   /**< P1017 rev 1.1 without security */
++} e_P1023DeviceName;
++
++/**************************************************************************//**
++ @Description   structure representing P1023 initialization parameters
++*//***************************************************************************/
++typedef struct t_P1023Params
++{
++    uintptr_t   ccsrBaseAddress;        /**< CCSR base address (virtual) */
++    uintptr_t   bmPortalsBaseAddress;   /**< Portals base address (virtual) */
++    uintptr_t   qmPortalsBaseAddress;   /**< Portals base address (virtual) */
++} t_P1023Params;
++
++/**************************************************************************//**
++ @Function      P1023_ConfigAndInit
++
++ @Description   General initiation of the chip registers.
++
++ @Param[in]     p_P1023Params  - A pointer to data structure of parameters
++
++ @Return        A handle to the P1023 data structure.
++*//***************************************************************************/
++t_Handle P1023_ConfigAndInit(t_P1023Params *p_P1023Params);
++
++/**************************************************************************//**
++ @Function      P1023_Free
++
++ @Description   Free all resources.
++
++ @Param         h_P1023 - (In) The handle of the initialized P1023 object.
++
++ @Return        E_OK on success; Other value otherwise.
++*//***************************************************************************/
++t_Error P1023_Free(t_Handle h_P1023);
++
++/**************************************************************************//**
++ @Function      P1023_GetRevInfo
++
++ @Description   This routine enables access to chip and revision information.
++
++ @Param[in]     gutilBase       - Base address of P1023 GUTIL registers.
++
++ @Return        Part ID and revision.
++*//***************************************************************************/
++e_P1023DeviceName P1023_GetRevInfo(uintptr_t gutilBase);
++
++/**************************************************************************//**
++ @Function      P1023_GetE500Factor
++
++ @Description   Returns E500 core clock multiplication factor.
++
++ @Param[in]     gutilBase       - Base address of P1023 GUTIL registers.
++ @Param[in]     coreId          - Id of the requested core.
++ @Param[out]    p_E500MulFactor - Returns E500 to CCB multification factor.
++ @Param[out]    p_E500DivFactor - Returns E500 to CCB division factor.
++
++ @Return        E_OK on success; Other value otherwise.
++*
++*//***************************************************************************/
++t_Error P1023_GetE500Factor(uintptr_t    gutilBase,
++                            uint32_t    coreId,
++                            uint32_t    *p_E500MulFactor,
++                            uint32_t    *p_E500DivFactor);
++
++/**************************************************************************//**
++ @Function      P1023_GetFmFactor
++
++ @Description   returns FM multiplication factors. (This value is returned using
++                two parameters to avoid using float parameter).
++
++ @Param[in]     gutilBase       - Base address of P1023 GUTIL registers.
++ @Param[out]    p_FmMulFactor   - returns E500 to CCB multification factor.
++ @Param[out]    p_FmDivFactor   - returns E500 to CCB division factor.
++
++ @Return        E_OK on success; Other value otherwise.
++*//***************************************************************************/
++t_Error  P1023_GetFmFactor(uintptr_t gutilBase, uint32_t *p_FmMulFactor, uint32_t *p_FmDivFactor);
++
++/**************************************************************************//**
++ @Function      P1023_GetCcbFactor
++
++ @Description   returns system multiplication factor.
++
++ @Param[in]     gutilBase       - Base address of P1023 GUTIL registers.
++
++ @Return        System multiplication factor.
++*//***************************************************************************/
++uint32_t P1023_GetCcbFactor(uintptr_t gutilBase);
++
++#if 0
++/**************************************************************************//**
++ @Function      P1023_GetDdrFactor
++
++ @Description   returns the multiplication factor of the clock in for the DDR clock .
++                Note: assumes the ddr_in_clk is identical to the sys_in_clk
++
++ @Param[in]     gutilBase       - Base address of P1023 GUTIL registers.
++ @Param         p_DdrMulFactor  - returns DDR in clk multification factor.
++ @Param         p_DdrDivFactor  - returns DDR division factor.
++
++ @Return        E_OK on success; Other value otherwise..
++*//***************************************************************************/
++t_Error P1023_GetDdrFactor( uintptr_t   gutilBase,
++                            uint32_t    *p_DdrMulFactor,
++                            uint32_t    *p_DdrDivFactor);
++
++/**************************************************************************//**
++ @Function      P1023_GetDdrType
++
++ @Description   returns the multiplication factor of the clock in for the DDR clock .
++
++ @Param[in]     gutilBase       - Base address of P1023 GUTIL registers.
++ @Param         p_DdrType   - (Out) returns DDR type DDR1/DDR2/DDR3.
++
++ @Return        E_OK on success; Other value otherwise.
++*//***************************************************************************/
++t_Error P1023_GetDdrType(uintptr_t gutilBase, e_DdrType *p_DdrType );
++#endif
++
++/** @} */ /* end of 1023_init_grp group */
++/** @} */ /* end of 1023_grp group */
++
++#define CORE_E500V2
++
++#if 0 /* using unified values */
++/*****************************************************************************
++ INTEGRATION-SPECIFIC MODULE CODES
++******************************************************************************/
++#define MODULE_UNKNOWN          0x00000000
++#define MODULE_MEM              0x00010000
++#define MODULE_MM               0x00020000
++#define MODULE_CORE             0x00030000
++#define MODULE_P1023            0x00040000
++#define MODULE_MII              0x00050000
++#define MODULE_PM               0x00060000
++#define MODULE_MMU              0x00070000
++#define MODULE_PIC              0x00080000
++#define MODULE_L2_CACHE         0x00090000
++#define MODULE_DUART            0x000a0000
++#define MODULE_SERDES           0x000b0000
++#define MODULE_PIO              0x000c0000
++#define MODULE_QM               0x000d0000
++#define MODULE_BM               0x000e0000
++#define MODULE_SEC              0x000f0000
++#define MODULE_FM               0x00100000
++#define MODULE_FM_MURAM         0x00110000
++#define MODULE_FM_PCD           0x00120000
++#define MODULE_FM_RTC           0x00130000
++#define MODULE_FM_MAC           0x00140000
++#define MODULE_FM_PORT          0x00150000
++#define MODULE_FM_MACSEC        0x00160000
++#define MODULE_FM_MACSEC_SECY   0x00170000
++#define MODULE_FM_SP            0x00280000
++#define MODULE_ECM              0x00190000
++#define MODULE_DMA              0x001a0000
++#define MODULE_DDR              0x001b0000
++#define MODULE_LAW              0x001c0000
++#define MODULE_LBC              0x001d0000
++#define MODULE_I2C              0x001e0000
++#define MODULE_ESPI             0x001f0000
++#define MODULE_PCI              0x00200000
++#define MODULE_DPA_PORT         0x00210000
++#define MODULE_USB              0x00220000
++#endif /* using unified values */
++
++/*****************************************************************************
++ LBC INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++/**************************************************************************//**
++ @Group         lbc_exception_grp LBC Exception Unit
++
++ @Description   LBC Exception unit API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Anchor        lbc_exbm
++
++ @Collection    LBC Errors Bit Mask
++
++                These errors are reported through the exceptions callback..
++                The values can be or'ed in any combination in the errors mask
++                parameter of the errors report structure.
++
++                These errors can also be passed as a bit-mask to
++                LBC_EnableErrorChecking() or LBC_DisableErrorChecking(),
++                for enabling or disabling error checking.
++ @{
++*//***************************************************************************/
++#define LBC_ERR_BUS_MONITOR     0x80000000  /**< Bus monitor error */
++#define LBC_ERR_PARITY_ECC      0x20000000  /**< Parity error for GPCM/UPM */
++#define LBC_ERR_WRITE_PROTECT   0x04000000  /**< Write protection error */
++#define LBC_ERR_CHIP_SELECT     0x00080000  /**< Unrecognized chip select */
++
++#define LBC_ERR_ALL             (LBC_ERR_BUS_MONITOR | LBC_ERR_PARITY_ECC | \
++                                 LBC_ERR_WRITE_PROTECT | LBC_ERR_CHIP_SELECT)
++                                            /**< All possible errors */
++/* @} */
++/** @} */ /* end of lbc_exception_grp group */
++
++#define LBC_NUM_OF_BANKS            2
++#define LBC_MAX_CS_SIZE             0x0000000100000000LL
++#define LBC_ATOMIC_OPERATION_SUPPORT
++#define LBC_PARITY_SUPPORT
++#define LBC_ADDRESS_SHIFT_SUPPORT
++#define LBC_ADDRESS_HOLD_TIME_CTRL
++#define LBC_HIGH_CLK_DIVIDERS
++#define LBC_FCM_AVAILABLE
++
++
++/*****************************************************************************
++ LAW INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define LAW_ARCH_CCB
++#define LAW_NUM_OF_WINDOWS      12
++#define LAW_MIN_WINDOW_SIZE     0x0000000000001000LL    /**< 4KB */
++#define LAW_MAX_WINDOW_SIZE     0x0000001000000000LL    /**< 32GB */
++
++
++/*****************************************************************************
++ SPI INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define SPI_NUM_OF_CONTROLLERS      1
++
++/*****************************************************************************
++ PCI/PCIe INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++
++#define PCI_MAX_INBOUND_WINDOWS_NUM     4
++#define PCI_MAX_OUTBOUND_WINDOWS_NUM    5
++
++/**************************************************************************//**
++ @Description   Target interface of an inbound window
++*//***************************************************************************/
++typedef enum e_PciTargetInterface
++{
++    e_PCI_TARGET_PCIE_2         = 0x1,  /**<  PCI Express target interface 2 */
++    e_PCI_TARGET_PCIE_1         = 0x2,  /**<  PCI Express target interface 1 */
++    e_PCI_TARGET_PCIE_3         = 0x3,  /**<  PCI Express target interface 3 */
++    e_PCI_TARGET_LOCAL_MEMORY   = 0xF   /**<  Local Memory (DDR SDRAM, Local Bus, SRAM) target interface */
++
++} e_PciTargetInterface;
++
++/*****************************************************************************
++ DDR INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define DDR_NUM_OF_VALID_CS         2
++
++/*****************************************************************************
++ SEC INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define SEC_ERRATA_STAT_REGS_UNUSABLE
++
++/*****************************************************************************
++ DMA INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define DMA_NUM_OF_CONTROLLERS      2
++
++
++
++
++/*****************************************************************************
++ 1588 INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define PTP_V2
++
++/**************************************************************************//**
++ @Function      P1023_GetMuxControlReg
++
++ @Description   Returns the value of PMUXCR (Alternate Function Signal Multiplex
++                Control Register)
++
++ @Param[in]     gutilBase   - Base address of P1023 GUTIL registers.
++
++ @Return        Value of PMUXCR
++*//***************************************************************************/
++uint32_t P1023_GetMuxControlReg(uintptr_t gutilBase);
++
++/**************************************************************************//**
++ @Function      P1023_SetMuxControlReg
++
++ @Description   Sets the value of PMUXCR (Alternate Function Signal Multiplex
++                Control Register)
++
++ @Param[in]     gutilBase   - Base address of P1023 GUTIL registers.
++ @Param[in]     val         - the new value for PMUXCR.
++
++ @Return        None
++*//***************************************************************************/
++void P1023_SetMuxControlReg(uintptr_t gutilBase, uint32_t val);
++
++/**************************************************************************//**
++ @Function      P1023_GetDeviceDisableStatusRegister
++
++ @Description   Returns the value of DEVDISR (Device Disable Register)
++
++ @Param[in]     gutilBase   - Base address of P1023 GUTIL registers.
++
++ @Return        Value of DEVDISR
++*//***************************************************************************/
++uint32_t P1023_GetDeviceDisableStatusRegister(uintptr_t gutilBase);
++
++/**************************************************************************//**
++ @Function      P1023_GetPorDeviceStatusRegister
++
++ @Description   Returns the value of POR Device Status Register
++
++ @Param[in]     gutilBase   - Base address of P1023 GUTIL registers.
++
++ @Return        POR Device Status Register
++*//***************************************************************************/
++uint32_t P1023_GetPorDeviceStatusRegister(uintptr_t gutilBase);
++
++/**************************************************************************//**
++ @Function      P1023_GetPorBootModeStatusRegister
++
++ @Description   Returns the value of POR Boot Mode Status Register
++
++ @Param[in]     gutilBase   - Base address of P1023 GUTIL registers.
++
++ @Return        POR Boot Mode Status Register value
++*//***************************************************************************/
++uint32_t P1023_GetPorBootModeStatusRegister(uintptr_t gutilBase);
++
++
++#define PORDEVSR_SGMII1_DIS     0x10000000
++#define PORDEVSR_SGMII2_DIS     0x08000000
++#define PORDEVSR_ECP1           0x02000000
++#define PORDEVSR_IO_SEL         0x00780000
++#define PORDEVSR_IO_SEL_SHIFT   19
++#define PORBMSR_HA              0x00070000
++#define PORBMSR_HA_SHIFT        16
++
++#define DEVDISR_QM_BM           0x80000000
++#define DEVDISR_FM              0x40000000
++#define DEVDISR_PCIE1           0x20000000
++#define DEVDISR_MAC_SEC         0x10000000
++#define DEVDISR_ELBC            0x08000000
++#define DEVDISR_PCIE2           0x04000000
++#define DEVDISR_PCIE3           0x02000000
++#define DEVDISR_CAAM            0x01000000
++#define DEVDISR_USB0            0x00800000
++#define DEVDISR_1588            0x00020000
++#define DEVDISR_CORE0           0x00008000
++#define DEVDISR_TB0             0x00004000
++#define DEVDISR_CORE1           0x00002000
++#define DEVDISR_TB1             0x00001000
++#define DEVDISR_DMA1            0x00000400
++#define DEVDISR_DMA2            0x00000200
++#define DEVDISR_DDR             0x00000010
++#define DEVDISR_TSEC1           0x00000080
++#define DEVDISR_TSEC2           0x00000040
++#define DEVDISR_SPI             0x00000008
++#define DEVDISR_I2C             0x00000004
++#define DEVDISR_DUART           0x00000002
++
++
++#endif /* __PART_INTEGRATION_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/dpaa_integration_ext.h
+@@ -0,0 +1,276 @@
++/* Copyright (c) 2009-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**************************************************************************//**
++ @File          dpaa_integration_ext.h
++
++ @Description   P3040/P4080/P5020 FM external definitions and structures.
++*//***************************************************************************/
++#ifndef __DPAA_INTEGRATION_EXT_H
++#define __DPAA_INTEGRATION_EXT_H
++
++#include "std_ext.h"
++
++
++#define DPAA_VERSION    10
++
++typedef enum {
++    e_DPAA_SWPORTAL0 = 0,
++    e_DPAA_SWPORTAL1,
++    e_DPAA_SWPORTAL2,
++    e_DPAA_SWPORTAL3,
++    e_DPAA_SWPORTAL4,
++    e_DPAA_SWPORTAL5,
++    e_DPAA_SWPORTAL6,
++    e_DPAA_SWPORTAL7,
++    e_DPAA_SWPORTAL8,
++    e_DPAA_SWPORTAL9,
++    e_DPAA_SWPORTAL_DUMMY_LAST
++} e_DpaaSwPortal;
++
++typedef enum {
++    e_DPAA_DCPORTAL0 = 0,
++    e_DPAA_DCPORTAL1,
++    e_DPAA_DCPORTAL2,
++    e_DPAA_DCPORTAL3,
++    e_DPAA_DCPORTAL4,
++    e_DPAA_DCPORTAL_DUMMY_LAST
++} e_DpaaDcPortal;
++
++#define DPAA_MAX_NUM_OF_SW_PORTALS      e_DPAA_SWPORTAL_DUMMY_LAST
++#define DPAA_MAX_NUM_OF_DC_PORTALS      e_DPAA_DCPORTAL_DUMMY_LAST
++
++/*****************************************************************************
++ QMan INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define QM_MAX_NUM_OF_POOL_CHANNELS 15              /**< Total number of channels, dedicated and pool */
++#define QM_MAX_NUM_OF_WQ            8               /**< Number of work queues per channel */
++#define QM_MAX_NUM_OF_SWP_AS        4
++#define QM_MAX_NUM_OF_CGS           256             /**< Number of congestion groups */
++#define QM_MAX_NUM_OF_FQIDS         (16 * MEGABYTE) /**< FQIDs range - 24 bits */
++
++/**************************************************************************//**
++ @Description   Work Queue Channel assignments in QMan.
++*//***************************************************************************/
++typedef enum
++{
++    e_QM_FQ_CHANNEL_SWPORTAL0 = 0,              /**< Dedicated channels serviced by software portals 0 to 9 */
++    e_QM_FQ_CHANNEL_SWPORTAL1,
++    e_QM_FQ_CHANNEL_SWPORTAL2,
++    e_QM_FQ_CHANNEL_SWPORTAL3,
++    e_QM_FQ_CHANNEL_SWPORTAL4,
++    e_QM_FQ_CHANNEL_SWPORTAL5,
++    e_QM_FQ_CHANNEL_SWPORTAL6,
++    e_QM_FQ_CHANNEL_SWPORTAL7,
++    e_QM_FQ_CHANNEL_SWPORTAL8,
++    e_QM_FQ_CHANNEL_SWPORTAL9,
++
++    e_QM_FQ_CHANNEL_POOL1 = 0x21,               /**< Pool channels that can be serviced by any of the software portals */
++    e_QM_FQ_CHANNEL_POOL2,
++    e_QM_FQ_CHANNEL_POOL3,
++    e_QM_FQ_CHANNEL_POOL4,
++    e_QM_FQ_CHANNEL_POOL5,
++    e_QM_FQ_CHANNEL_POOL6,
++    e_QM_FQ_CHANNEL_POOL7,
++    e_QM_FQ_CHANNEL_POOL8,
++    e_QM_FQ_CHANNEL_POOL9,
++    e_QM_FQ_CHANNEL_POOL10,
++    e_QM_FQ_CHANNEL_POOL11,
++    e_QM_FQ_CHANNEL_POOL12,
++    e_QM_FQ_CHANNEL_POOL13,
++    e_QM_FQ_CHANNEL_POOL14,
++    e_QM_FQ_CHANNEL_POOL15,
++
++    e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x40,           /**< Dedicated channels serviced by Direct Connect Portal 0:
++                                                     connected to FMan 0; assigned in incrementing order to
++                                                     each sub-portal (SP) in the portal */
++    e_QM_FQ_CHANNEL_FMAN0_SP1,
++    e_QM_FQ_CHANNEL_FMAN0_SP2,
++    e_QM_FQ_CHANNEL_FMAN0_SP3,
++    e_QM_FQ_CHANNEL_FMAN0_SP4,
++    e_QM_FQ_CHANNEL_FMAN0_SP5,
++    e_QM_FQ_CHANNEL_FMAN0_SP6,
++    e_QM_FQ_CHANNEL_FMAN0_SP7,
++    e_QM_FQ_CHANNEL_FMAN0_SP8,
++    e_QM_FQ_CHANNEL_FMAN0_SP9,
++    e_QM_FQ_CHANNEL_FMAN0_SP10,
++    e_QM_FQ_CHANNEL_FMAN0_SP11,
++/* difference between 5020 and 4080 :) */
++    e_QM_FQ_CHANNEL_FMAN1_SP0 = 0x60,
++    e_QM_FQ_CHANNEL_FMAN1_SP1,
++    e_QM_FQ_CHANNEL_FMAN1_SP2,
++    e_QM_FQ_CHANNEL_FMAN1_SP3,
++    e_QM_FQ_CHANNEL_FMAN1_SP4,
++    e_QM_FQ_CHANNEL_FMAN1_SP5,
++    e_QM_FQ_CHANNEL_FMAN1_SP6,
++    e_QM_FQ_CHANNEL_FMAN1_SP7,
++    e_QM_FQ_CHANNEL_FMAN1_SP8,
++    e_QM_FQ_CHANNEL_FMAN1_SP9,
++    e_QM_FQ_CHANNEL_FMAN1_SP10,
++    e_QM_FQ_CHANNEL_FMAN1_SP11,
++
++    e_QM_FQ_CHANNEL_CAAM = 0x80,                /**< Dedicated channel serviced by Direct Connect Portal 2:
++                                                     connected to SEC 4.x */
++
++    e_QM_FQ_CHANNEL_PME = 0xA0,                 /**< Dedicated channel serviced by Direct Connect Portal 3:
++                                                     connected to PME */
++    e_QM_FQ_CHANNEL_RAID = 0xC0                 /**< Dedicated channel serviced by Direct Connect Portal 4:
++                                                     connected to RAID */
++} e_QmFQChannel;
++
++/*****************************************************************************
++ BMan INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define BM_MAX_NUM_OF_POOLS         64          /**< Number of buffers pools */
++
++
++/*****************************************************************************
++ FM INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define INTG_MAX_NUM_OF_FM          2
++
++/* Ports defines */
++#define FM_MAX_NUM_OF_1G_MACS       5
++#define FM_MAX_NUM_OF_10G_MACS      1
++#define FM_MAX_NUM_OF_MACS          (FM_MAX_NUM_OF_1G_MACS + FM_MAX_NUM_OF_10G_MACS)
++#define FM_MAX_NUM_OF_OH_PORTS      7
++
++#define FM_MAX_NUM_OF_1G_RX_PORTS   FM_MAX_NUM_OF_1G_MACS
++#define FM_MAX_NUM_OF_10G_RX_PORTS  FM_MAX_NUM_OF_10G_MACS
++#define FM_MAX_NUM_OF_RX_PORTS      (FM_MAX_NUM_OF_10G_RX_PORTS + FM_MAX_NUM_OF_1G_RX_PORTS)
++
++#define FM_MAX_NUM_OF_1G_TX_PORTS   FM_MAX_NUM_OF_1G_MACS
++#define FM_MAX_NUM_OF_10G_TX_PORTS  FM_MAX_NUM_OF_10G_MACS
++#define FM_MAX_NUM_OF_TX_PORTS      (FM_MAX_NUM_OF_10G_TX_PORTS + FM_MAX_NUM_OF_1G_TX_PORTS)
++
++#define FM_PORT_MAX_NUM_OF_EXT_POOLS            8           /**< Number of external BM pools per Rx port */
++#define FM_PORT_NUM_OF_CONGESTION_GRPS          256         /**< Total number of congestion groups in QM */
++#define FM_MAX_NUM_OF_SUB_PORTALS               12
++#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS   0
++
++/* Rams defines */
++#define FM_MURAM_SIZE                   (160*KILOBYTE)
++#define FM_IRAM_SIZE(major, minor)      (64 * KILOBYTE)
++#define FM_NUM_OF_CTRL                  2
++
++/* PCD defines */
++#define FM_PCD_PLCR_NUM_ENTRIES         256             /**< Total number of policer profiles */
++#define FM_PCD_KG_NUM_OF_SCHEMES        32              /**< Total number of KG schemes */
++#define FM_PCD_MAX_NUM_OF_CLS_PLANS     256             /**< Number of classification plan entries. */
++#define FM_PCD_PRS_SW_PATCHES_SIZE      0x00000200      /**< Number of bytes saved for patches */
++#define FM_PCD_SW_PRS_SIZE              0x00000800      /**< Total size of SW parser area */
++
++/* RTC defines */
++#define FM_RTC_NUM_OF_ALARMS            2                   /**< RTC number of alarms */
++#define FM_RTC_NUM_OF_PERIODIC_PULSES   2                   /**< RTC number of periodic pulses */
++#define FM_RTC_NUM_OF_EXT_TRIGGERS      2                   /**< RTC number of external triggers */
++
++/* QMI defines */
++#define QMI_MAX_NUM_OF_TNUMS            64
++#define QMI_DEF_TNUMS_THRESH            48
++
++/* FPM defines */
++#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS  4
++
++/* DMA defines */
++#define DMA_THRESH_MAX_COMMQ            31
++#define DMA_THRESH_MAX_BUF              127
++
++/* BMI defines */
++#define BMI_MAX_NUM_OF_TASKS            128
++#define BMI_MAX_NUM_OF_DMAS             32
++#define BMI_MAX_FIFO_SIZE               (FM_MURAM_SIZE)
++#define PORT_MAX_WEIGHT                 16
++
++
++#define FM_CHECK_PORT_RESTRICTIONS(__validPorts, __newPortIndx)   TRUE
++
++/* p4080-rev1 unique features */
++#define QM_CGS_NO_FRAME_MODE
++
++/* p4080 unique features */
++#define FM_NO_DISPATCH_RAM_ECC
++#define FM_NO_WATCHDOG
++#define FM_NO_TNUM_AGING
++#define FM_KG_NO_BYPASS_FQID_GEN
++#define FM_KG_NO_BYPASS_PLCR_PROFILE_GEN
++#define FM_NO_BACKUP_POOLS
++#define FM_NO_OP_OBSERVED_POOLS
++#define FM_NO_ADVANCED_RATE_LIMITER
++#define FM_NO_OP_OBSERVED_CGS
++#define FM_HAS_TOTAL_DMAS
++#define FM_KG_NO_IPPID_SUPPORT
++#define FM_NO_GUARANTEED_RESET_VALUES
++#define FM_MAC_RESET
++
++/* FM erratas */
++#define FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
++#define FM_TX_SHORT_FRAME_BAD_TS_ERRATA_10GMAC_A006     /* No implementation, Out of LLD scope */
++#define FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007
++#define FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008
++#define FM_TX_INVALID_ECC_ERRATA_10GMAC_A009            /* Out of LLD scope, user may disable ECC exceptions using FM_DisableRamsEcc */
++#define FM_BAD_VLAN_DETECT_ERRATA_10GMAC_A010
++
++#define FM_RX_PREAM_4_ERRATA_DTSEC_A001
++#define FM_GRS_ERRATA_DTSEC_A002
++#define FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003
++#define FM_GTS_ERRATA_DTSEC_A004
++#define FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012
++#define FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014
++#define FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839
++
++#define FM_MAGIC_PACKET_UNRECOGNIZED_ERRATA_DTSEC2          /* No implementation, Out of LLD scope */
++#define FM_TX_LOCKUP_ERRATA_DTSEC6
++
++#define FM_HC_DEF_FQID_ONLY_ERRATA_FMAN_A003                /* Implemented by ucode */
++#define FM_DEBUG_TRACE_FMAN_A004                            /* No implementation, Out of LLD scope */
++
++#define FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173
++
++#define FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005
++
++#define FM_LEN_CHECK_ERRATA_FMAN_SW002
++
++#define FM_NO_CTXA_COPY_ERRATA_FMAN_SW001
++#define FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004
++
++/*****************************************************************************
++ FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define NUM_OF_RX_SC                16
++#define NUM_OF_TX_SC                16
++
++#define NUM_OF_SA_PER_RX_SC         2
++#define NUM_OF_SA_PER_TX_SC         2
++
++
++#endif /* __DPAA_INTEGRATION_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_ext.h
+@@ -0,0 +1,83 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**************************************************************************//**
++
++ @File          part_ext.h
++
++ @Description   Definitions for the part (integration) module.
++*//***************************************************************************/
++
++#ifndef __PART_EXT_H
++#define __PART_EXT_H
++
++#include "std_ext.h"
++#include "part_integration_ext.h"
++
++
++#if !(defined(MPC8306) || \
++      defined(MPC8309) || \
++      defined(MPC834x) || \
++      defined(MPC836x) || \
++      defined(MPC832x) || \
++      defined(MPC837x) || \
++      defined(MPC8568) || \
++      defined(MPC8569) || \
++      defined(P1020)   || \
++      defined(P1021)   || \
++      defined(P1022)   || \
++      defined(P1023)   || \
++      defined(P2020)   || \
++      defined(P2040)   || \
++      defined(P3041)   || \
++      defined(P4080)   || \
++      defined(SC4080)  || \
++      defined(P5020)   || \
++      defined(MSC814x))
++#error "unable to proceed without chip-definition"
++#endif /* !(defined(MPC834x) || ... */
++
++
++/**************************************************************************//*
++ @Description   Part data structure - must be contained in any integration
++                data structure.
++*//***************************************************************************/
++typedef struct t_Part
++{
++    uintptr_t   (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId);
++                /**< Returns the address of the module's memory map base. */
++    e_ModuleId  (* f_GetModuleIdByBase)(t_Handle h_Part, uintptr_t baseAddress);
++                /**< Returns the module's ID according to its memory map base. */
++} t_Part;
++
++
++#endif /* __PART_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_integration_ext.h
+@@ -0,0 +1,336 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**************************************************************************//**
++ @File          part_integration_ext.h
++
++ @Description   P3040/P4080/P5020 external definitions and structures.
++*//***************************************************************************/
++#ifndef __PART_INTEGRATION_EXT_H
++#define __PART_INTEGRATION_EXT_H
++
++#include "std_ext.h"
++#include "dpaa_integration_ext.h"
++
++
++/**************************************************************************//**
++ @Group         P3040/P4080/P5020_chip_id P5020 Application Programming Interface
++
++ @Description   P3040/P4080/P5020 Chip functions,definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++#define CORE_E500MC
++
++#define INTG_MAX_NUM_OF_CORES   1
++
++
++/**************************************************************************//**
++ @Description   Module types.
++*//***************************************************************************/
++typedef enum e_ModuleId
++{
++    e_MODULE_ID_DUART_1 = 0,
++    e_MODULE_ID_DUART_2,
++    e_MODULE_ID_DUART_3,
++    e_MODULE_ID_DUART_4,
++    e_MODULE_ID_LAW,
++    e_MODULE_ID_LBC,
++    e_MODULE_ID_PAMU,
++    e_MODULE_ID_QM,                 /**< Queue manager module */
++    e_MODULE_ID_BM,                 /**< Buffer manager module */
++    e_MODULE_ID_QM_CE_PORTAL_0,
++    e_MODULE_ID_QM_CI_PORTAL_0,
++    e_MODULE_ID_QM_CE_PORTAL_1,
++    e_MODULE_ID_QM_CI_PORTAL_1,
++    e_MODULE_ID_QM_CE_PORTAL_2,
++    e_MODULE_ID_QM_CI_PORTAL_2,
++    e_MODULE_ID_QM_CE_PORTAL_3,
++    e_MODULE_ID_QM_CI_PORTAL_3,
++    e_MODULE_ID_QM_CE_PORTAL_4,
++    e_MODULE_ID_QM_CI_PORTAL_4,
++    e_MODULE_ID_QM_CE_PORTAL_5,
++    e_MODULE_ID_QM_CI_PORTAL_5,
++    e_MODULE_ID_QM_CE_PORTAL_6,
++    e_MODULE_ID_QM_CI_PORTAL_6,
++    e_MODULE_ID_QM_CE_PORTAL_7,
++    e_MODULE_ID_QM_CI_PORTAL_7,
++    e_MODULE_ID_QM_CE_PORTAL_8,
++    e_MODULE_ID_QM_CI_PORTAL_8,
++    e_MODULE_ID_QM_CE_PORTAL_9,
++    e_MODULE_ID_QM_CI_PORTAL_9,
++    e_MODULE_ID_BM_CE_PORTAL_0,
++    e_MODULE_ID_BM_CI_PORTAL_0,
++    e_MODULE_ID_BM_CE_PORTAL_1,
++    e_MODULE_ID_BM_CI_PORTAL_1,
++    e_MODULE_ID_BM_CE_PORTAL_2,
++    e_MODULE_ID_BM_CI_PORTAL_2,
++    e_MODULE_ID_BM_CE_PORTAL_3,
++    e_MODULE_ID_BM_CI_PORTAL_3,
++    e_MODULE_ID_BM_CE_PORTAL_4,
++    e_MODULE_ID_BM_CI_PORTAL_4,
++    e_MODULE_ID_BM_CE_PORTAL_5,
++    e_MODULE_ID_BM_CI_PORTAL_5,
++    e_MODULE_ID_BM_CE_PORTAL_6,
++    e_MODULE_ID_BM_CI_PORTAL_6,
++    e_MODULE_ID_BM_CE_PORTAL_7,
++    e_MODULE_ID_BM_CI_PORTAL_7,
++    e_MODULE_ID_BM_CE_PORTAL_8,
++    e_MODULE_ID_BM_CI_PORTAL_8,
++    e_MODULE_ID_BM_CE_PORTAL_9,
++    e_MODULE_ID_BM_CI_PORTAL_9,
++    e_MODULE_ID_FM1,                /**< Frame manager #1 module */
++    e_MODULE_ID_FM1_RTC,            /**< FM Real-Time-Clock */
++    e_MODULE_ID_FM1_MURAM,          /**< FM Multi-User-RAM */
++    e_MODULE_ID_FM1_BMI,            /**< FM BMI block */
++    e_MODULE_ID_FM1_QMI,            /**< FM QMI block */
++    e_MODULE_ID_FM1_PRS,            /**< FM parser block */
++    e_MODULE_ID_FM1_PORT_HO0,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM1_PORT_HO1,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM1_PORT_HO2,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM1_PORT_HO3,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM1_PORT_HO4,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM1_PORT_HO5,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM1_PORT_HO6,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM1_PORT_1GRx0,     /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM1_PORT_1GRx1,     /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM1_PORT_1GRx2,     /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM1_PORT_1GRx3,     /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM1_PORT_1GRx4,     /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM1_PORT_10GRx0,    /**< FM Rx 10G MAC port block */
++    e_MODULE_ID_FM1_PORT_1GTx0,     /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM1_PORT_1GTx1,     /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM1_PORT_1GTx2,     /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM1_PORT_1GTx3,     /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM1_PORT_1GTx4,     /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM1_PORT_10GTx0,    /**< FM Tx 10G MAC port block */
++    e_MODULE_ID_FM1_PLCR,           /**< FM Policer */
++    e_MODULE_ID_FM1_KG,             /**< FM Keygen */
++    e_MODULE_ID_FM1_DMA,            /**< FM DMA */
++    e_MODULE_ID_FM1_FPM,            /**< FM FPM */
++    e_MODULE_ID_FM1_IRAM,           /**< FM Instruction-RAM */
++    e_MODULE_ID_FM1_1GMDIO0,        /**< FM 1G MDIO MAC 0*/
++    e_MODULE_ID_FM1_1GMDIO1,        /**< FM 1G MDIO MAC 1*/
++    e_MODULE_ID_FM1_1GMDIO2,        /**< FM 1G MDIO MAC 2*/
++    e_MODULE_ID_FM1_1GMDIO3,        /**< FM 1G MDIO MAC 3*/
++    e_MODULE_ID_FM1_10GMDIO,        /**< FM 10G MDIO */
++    e_MODULE_ID_FM1_PRS_IRAM,       /**< FM SW-parser Instruction-RAM */
++    e_MODULE_ID_FM1_1GMAC0,         /**< FM 1G MAC #0 */
++    e_MODULE_ID_FM1_1GMAC1,         /**< FM 1G MAC #1 */
++    e_MODULE_ID_FM1_1GMAC2,         /**< FM 1G MAC #2 */
++    e_MODULE_ID_FM1_1GMAC3,         /**< FM 1G MAC #3 */
++    e_MODULE_ID_FM1_10GMAC0,        /**< FM 10G MAC #0 */
++
++    e_MODULE_ID_FM2,                /**< Frame manager #2 module */
++    e_MODULE_ID_FM2_RTC,            /**< FM Real-Time-Clock */
++    e_MODULE_ID_FM2_MURAM,          /**< FM Multi-User-RAM */
++    e_MODULE_ID_FM2_BMI,            /**< FM BMI block */
++    e_MODULE_ID_FM2_QMI,            /**< FM QMI block */
++    e_MODULE_ID_FM2_PRS,            /**< FM parser block */
++    e_MODULE_ID_FM2_PORT_HO0,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM2_PORT_HO1,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM2_PORT_HO2,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM2_PORT_HO3,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM2_PORT_HO4,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM2_PORT_HO5,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM2_PORT_HO6,       /**< FM Host-command/offline-parsing port block */
++    e_MODULE_ID_FM2_PORT_1GRx0,     /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM2_PORT_1GRx1,     /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM2_PORT_1GRx2,     /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM2_PORT_1GRx3,     /**< FM Rx 1G MAC port block */
++    e_MODULE_ID_FM2_PORT_10GRx0,    /**< FM Rx 10G MAC port block */
++    e_MODULE_ID_FM2_PORT_1GTx0,     /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM2_PORT_1GTx1,     /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM2_PORT_1GTx2,     /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM2_PORT_1GTx3,     /**< FM Tx 1G MAC port block */
++    e_MODULE_ID_FM2_PORT_10GTx0,    /**< FM Tx 10G MAC port block */
++    e_MODULE_ID_FM2_PLCR,           /**< FM Policer */
++    e_MODULE_ID_FM2_KG,             /**< FM Keygen */
++    e_MODULE_ID_FM2_DMA,            /**< FM DMA */
++    e_MODULE_ID_FM2_FPM,            /**< FM FPM */
++    e_MODULE_ID_FM2_IRAM,           /**< FM Instruction-RAM */
++    e_MODULE_ID_FM2_1GMDIO0,        /**< FM 1G MDIO MAC 0*/
++    e_MODULE_ID_FM2_1GMDIO1,        /**< FM 1G MDIO MAC 1*/
++    e_MODULE_ID_FM2_1GMDIO2,        /**< FM 1G MDIO MAC 2*/
++    e_MODULE_ID_FM2_1GMDIO3,        /**< FM 1G MDIO MAC 3*/
++    e_MODULE_ID_FM2_10GMDIO,        /**< FM 10G MDIO */
++    e_MODULE_ID_FM2_PRS_IRAM,       /**< FM SW-parser Instruction-RAM */
++    e_MODULE_ID_FM2_1GMAC0,         /**< FM 1G MAC #0 */
++    e_MODULE_ID_FM2_1GMAC1,         /**< FM 1G MAC #1 */
++    e_MODULE_ID_FM2_1GMAC2,         /**< FM 1G MAC #2 */
++    e_MODULE_ID_FM2_1GMAC3,         /**< FM 1G MAC #3 */
++    e_MODULE_ID_FM2_10GMAC0,        /**< FM 10G MAC #0 */
++
++    e_MODULE_ID_SEC_GEN,            /**< SEC 4.0 General registers      */
++    e_MODULE_ID_SEC_QI,             /**< SEC 4.0 QI registers           */
++    e_MODULE_ID_SEC_JQ0,            /**< SEC 4.0 JQ-0 registers         */
++    e_MODULE_ID_SEC_JQ1,            /**< SEC 4.0 JQ-1 registers         */
++    e_MODULE_ID_SEC_JQ2,            /**< SEC 4.0 JQ-2 registers         */
++    e_MODULE_ID_SEC_JQ3,            /**< SEC 4.0 JQ-3 registers         */
++    e_MODULE_ID_SEC_RTIC,           /**< SEC 4.0 RTIC registers         */
++    e_MODULE_ID_SEC_DECO0_CCB0,     /**< SEC 4.0 DECO-0/CCB-0 registers */
++    e_MODULE_ID_SEC_DECO1_CCB1,     /**< SEC 4.0 DECO-1/CCB-1 registers */
++    e_MODULE_ID_SEC_DECO2_CCB2,     /**< SEC 4.0 DECO-2/CCB-2 registers */
++    e_MODULE_ID_SEC_DECO3_CCB3,     /**< SEC 4.0 DECO-3/CCB-3 registers */
++    e_MODULE_ID_SEC_DECO4_CCB4,     /**< SEC 4.0 DECO-4/CCB-4 registers */
++
++    e_MODULE_ID_MPIC,               /**< MPIC */
++    e_MODULE_ID_GPIO,               /**< GPIO */
++    e_MODULE_ID_SERDES,             /**< SERDES */
++    e_MODULE_ID_CPC_1,              /**< CoreNet-Platform-Cache 1 */
++    e_MODULE_ID_CPC_2,              /**< CoreNet-Platform-Cache 2 */
++
++    e_MODULE_ID_SRIO_PORTS,         /**< RapidIO controller */
++    e_MODULE_ID_SRIO_MU,            /**< RapidIO messaging unit module */
++
++    e_MODULE_ID_DUMMY_LAST
++} e_ModuleId;
++
++#define NUM_OF_MODULES  e_MODULE_ID_DUMMY_LAST
++
++#if 0 /* using unified values */
++/*****************************************************************************
++ INTEGRATION-SPECIFIC MODULE CODES
++******************************************************************************/
++#define MODULE_UNKNOWN          0x00000000
++#define MODULE_MEM              0x00010000
++#define MODULE_MM               0x00020000
++#define MODULE_CORE             0x00030000
++#define MODULE_CHIP             0x00040000
++#define MODULE_PLTFRM           0x00050000
++#define MODULE_PM               0x00060000
++#define MODULE_MMU              0x00070000
++#define MODULE_PIC              0x00080000
++#define MODULE_CPC              0x00090000
++#define MODULE_DUART            0x000a0000
++#define MODULE_SERDES           0x000b0000
++#define MODULE_PIO              0x000c0000
++#define MODULE_QM               0x000d0000
++#define MODULE_BM               0x000e0000
++#define MODULE_SEC              0x000f0000
++#define MODULE_LAW              0x00100000
++#define MODULE_LBC              0x00110000
++#define MODULE_PAMU             0x00120000
++#define MODULE_FM               0x00130000
++#define MODULE_FM_MURAM         0x00140000
++#define MODULE_FM_PCD           0x00150000
++#define MODULE_FM_RTC           0x00160000
++#define MODULE_FM_MAC           0x00170000
++#define MODULE_FM_PORT          0x00180000
++#define MODULE_FM_SP            0x00190000
++#define MODULE_DPA_PORT         0x001a0000
++#define MODULE_MII              0x001b0000
++#define MODULE_I2C              0x001c0000
++#define MODULE_DMA              0x001d0000
++#define MODULE_DDR              0x001e0000
++#define MODULE_ESPI             0x001f0000
++#define MODULE_DPAA_IPSEC       0x00200000
++#endif /* using unified values */
++
++/*****************************************************************************
++ PAMU INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define PAMU_NUM_OF_PARTITIONS  5
++
++#define PAMU_PICS_AVICS_ERRATA_PAMU3
++
++/*****************************************************************************
++ LAW INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define LAW_NUM_OF_WINDOWS      32
++#define LAW_MIN_WINDOW_SIZE     0x0000000000001000LL    /**< 4KB */
++#define LAW_MAX_WINDOW_SIZE     0x0000002000000000LL    /**< 64GB */
++
++
++/*****************************************************************************
++ LBC INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++/**************************************************************************//**
++ @Group         lbc_exception_grp LBC Exception Unit
++
++ @Description   LBC Exception unit API functions, definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Anchor        lbc_exbm
++
++ @Collection    LBC Errors Bit Mask
++
++                These errors are reported through the exceptions callback..
++                The values can be or'ed in any combination in the errors mask
++                parameter of the errors report structure.
++
++                These errors can also be passed as a bit-mask to
++                LBC_EnableErrorChecking() or LBC_DisableErrorChecking(),
++                for enabling or disabling error checking.
++ @{
++*//***************************************************************************/
++#define LBC_ERR_BUS_MONITOR     0x80000000  /**< Bus monitor error */
++#define LBC_ERR_PARITY_ECC      0x20000000  /**< Parity error for GPCM/UPM */
++#define LBC_ERR_WRITE_PROTECT   0x04000000  /**< Write protection error */
++#define LBC_ERR_ATOMIC_WRITE    0x00800000  /**< Atomic write error */
++#define LBC_ERR_ATOMIC_READ     0x00400000  /**< Atomic read error */
++#define LBC_ERR_CHIP_SELECT     0x00080000  /**< Unrecognized chip select */
++
++#define LBC_ERR_ALL             (LBC_ERR_BUS_MONITOR | LBC_ERR_PARITY_ECC | \
++                                 LBC_ERR_WRITE_PROTECT | LBC_ERR_ATOMIC_WRITE | \
++                                 LBC_ERR_ATOMIC_READ | LBC_ERR_CHIP_SELECT)
++                                            /**< All possible errors */
++/* @} */
++/** @} */ /* end of lbc_exception_grp group */
++
++#define LBC_INCORRECT_ERROR_REPORT_ERRATA
++
++#define LBC_NUM_OF_BANKS            8
++#define LBC_MAX_CS_SIZE             0x0000000100000000LL
++#define LBC_ATOMIC_OPERATION_SUPPORT
++#define LBC_PARITY_SUPPORT
++#define LBC_ADDRESS_HOLD_TIME_CTRL
++#define LBC_HIGH_CLK_DIVIDERS
++#define LBC_FCM_AVAILABLE
++
++/*****************************************************************************
++ GPIO INTEGRATION-SPECIFIC DEFINITIONS
++******************************************************************************/
++#define GPIO_NUM_OF_PORTS   1   /**< Number of ports in GPIO module;
++                                     Each port contains up to 32 i/O pins. */
++
++#define GPIO_VALID_PIN_MASKS  \
++    { /* Port A */ 0xFFFFFFFF }
++
++#define GPIO_VALID_INTR_MASKS \
++    { /* Port A */ 0xFFFFFFFF }
++
++#endif /* __PART_INTEGRATION_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/math_ext.h
+@@ -0,0 +1,100 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#ifndef __MATH_EXT_H
++#define __MATH_EXT_H
++
++
++#if defined(NCSW_LINUX) && defined(__KERNEL__)
++#include <linux/math.h>
++#include <linux/math64.h>
++
++#elif defined(__MWERKS__)
++#define LOW(x) ( sizeof(x)==8 ? *(1+(int32_t*)&x) : (*(int32_t*)&x))
++#define HIGH(x) (*(int32_t*)&x)
++#define ULOW(x) ( sizeof(x)==8 ? *(1+(uint32_t*)&x) : (*(uint32_t*)&x))
++#define UHIGH(x) (*(uint32_t*)&x)
++
++static const double big = 1.0e300;
++
++/* Macro for checking if a number is a power of 2 */
++static __inline__ double ceil(double x)
++{
++    int32_t i0,i1,j0; /*- cc 020130 -*/
++    uint32_t i,j; /*- cc 020130 -*/
++    i0 =  HIGH(x);
++    i1 =  LOW(x);
++    j0 = ((i0>>20)&0x7ff)-0x3ff;
++    if(j0<20) {
++        if(j0<0) {     /* raise inexact if x != 0 */
++        if(big+x>0.0) {/* return 0*sign(x) if |x|<1 */
++            if(i0<0) {i0=0x80000000;i1=0;}
++            else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;}
++        }
++        } else {
++        i = (uint32_t)(0x000fffff)>>j0;
++        if(((i0&i)|i1)==0) return x; /* x is integral */
++        if(big+x>0.0) {    /* raise inexact flag */
++            if(i0>0) i0 += (0x00100000)>>j0;
++            i0 &= (~i); i1=0;
++        }
++        }
++    } else if (j0>51) {
++        if(j0==0x400) return x+x;    /* inf or NaN */
++        else return x;        /* x is integral */
++    } else {
++        i = ((uint32_t)(0xffffffff))>>(j0-20); /*- cc 020130 -*/
++        if((i1&i)==0) return x;    /* x is integral */
++        if(big+x>0.0) {         /* raise inexact flag */
++        if(i0>0) {
++            if(j0==20) i0+=1;
++            else {
++            j = (uint32_t)(i1 + (1<<(52-j0)));
++            if(j<i1) i0+=1;    /* got a carry */
++            i1 = (int32_t)j;
++            }
++        }
++        i1 &= (~i);
++        }
++    }
++    HIGH(x) = i0;
++    LOW(x) = i1;
++    return x;
++}
++
++#else
++#include <math.h>
++#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */
++
++
++#endif /* __MATH_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/ncsw_ext.h
+@@ -0,0 +1,435 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          ncsw_ext.h
++
++ @Description   General NetCommSw Standard Definitions
++*//***************************************************************************/
++
++#ifndef __NCSW_EXT_H
++#define __NCSW_EXT_H
++
++
++#include "memcpy_ext.h"
++
++#define WRITE_BLOCK                 IOMemSet32   /* include memcpy_ext.h */
++#define COPY_BLOCK                  Mem2IOCpy32  /* include memcpy_ext.h */
++
++#define PTR_TO_UINT(_ptr)           ((uintptr_t)(_ptr))
++#define UINT_TO_PTR(_val)           ((void*)(uintptr_t)(_val))
++
++#define PTR_MOVE(_ptr, _offset)     (void*)((uint8_t*)(_ptr) + (_offset))
++
++
++#define WRITE_UINT8_UINT24(arg, data08, data24) \
++    WRITE_UINT32(arg,((uint32_t)(data08)<<24)|((uint32_t)(data24)&0x00FFFFFF))
++#define WRITE_UINT24_UINT8(arg, data24, data08) \
++    WRITE_UINT32(arg,((uint32_t)(data24)<< 8)|((uint32_t)(data08)&0x000000FF))
++
++/* Little-Endian access macros */
++
++#define WRITE_UINT16_LE(arg, data) \
++        WRITE_UINT16((arg), SwapUint16(data))
++
++#define WRITE_UINT32_LE(arg, data) \
++        WRITE_UINT32((arg), SwapUint32(data))
++
++#define WRITE_UINT64_LE(arg, data) \
++        WRITE_UINT64((arg), SwapUint64(data))
++
++#define GET_UINT16_LE(arg) \
++        SwapUint16(GET_UINT16(arg))
++
++#define GET_UINT32_LE(arg) \
++        SwapUint32(GET_UINT32(arg))
++
++#define GET_UINT64_LE(arg) \
++        SwapUint64(GET_UINT64(arg))
++
++/* Write and Read again macros */
++#define WRITE_UINT_SYNC(size, arg, data)    \
++    do {                                    \
++        WRITE_UINT##size((arg), (data));    \
++        CORE_MemoryBarrier();               \
++    } while (0)
++
++#define WRITE_UINT8_SYNC(arg, data)     WRITE_UINT_SYNC(8, (arg), (data))
++
++#define WRITE_UINT16_SYNC(arg, data)    WRITE_UINT_SYNC(16, (arg), (data))
++#define WRITE_UINT32_SYNC(arg, data)    WRITE_UINT_SYNC(32, (arg), (data))
++
++#define MAKE_UINT64(high32, low32)      (((uint64_t)high32 << 32) | (low32))
++
++
++/*----------------------*/
++/* Miscellaneous macros */
++/*----------------------*/
++
++#define UNUSED(_x)            ((void)(_x))
++
++#define KILOBYTE            0x400UL                 /* 1024 */
++#define MEGABYTE            (KILOBYTE * KILOBYTE)   /* 1024*1024 */
++#define GIGABYTE            ((uint64_t)(KILOBYTE * MEGABYTE))   /* 1024*1024*1024 */
++#define TERABYTE            ((uint64_t)(KILOBYTE * GIGABYTE))   /* 1024*1024*1024*1024 */
++
++#ifndef NO_IRQ
++#define NO_IRQ                (0)
++#endif
++#define NCSW_MASTER_ID      (0)
++
++/* Macro for checking if a number is a power of 2 */
++#define POWER_OF_2(n)   (!((n) & ((n)-1)))
++
++/* Macro for calculating log of base 2 */
++#define LOG2(num, log2Num)      \
++    do                          \
++    {                           \
++        uint64_t tmp = (num);   \
++        log2Num = 0;            \
++        while (tmp > 1)         \
++        {                       \
++            log2Num++;          \
++            tmp >>= 1;          \
++        }                       \
++    } while (0)
++
++#define NEXT_POWER_OF_2(_num, _nextPow) \
++do                                      \
++{                                       \
++    if (POWER_OF_2(_num))               \
++        _nextPow = (_num);              \
++    else                                \
++    {                                   \
++        uint64_t tmp = (_num);          \
++        _nextPow = 1;                   \
++        while (tmp)                     \
++        {                               \
++            _nextPow <<= 1;             \
++            tmp >>= 1;                  \
++        }                               \
++    }                                   \
++} while (0)
++
++/* Ceiling division - not the fastest way, but safer in terms of overflow */
++#define DIV_CEIL(x,y) (div64_u64((x),(y)) + (((div64_u64((x),(y))*(y)) == (x)) ? 0 : 1))
++
++/* Round up a number to be a multiple of a second number */
++#define ROUND_UP(x,y)   ((((x) + (y) - 1) / (y)) * (y))
++
++/* Timing macro for converting usec units to number of ticks.   */
++/* (number of usec *  clock_Hz) / 1,000,000) - since            */
++/* clk is in MHz units, no division needed.                     */
++#define USEC_TO_CLK(usec,clk)       ((usec) * (clk))
++#define CYCLES_TO_USEC(cycles,clk)  ((cycles) / (clk))
++
++/* Timing macros for converting between nsec units and number of clocks. */
++#define NSEC_TO_CLK(nsec,clk)       DIV_CEIL(((nsec) * (clk)), 1000)
++#define CYCLES_TO_NSEC(cycles,clk)  (((cycles) * 1000) / (clk))
++
++/* Timing macros for converting between psec units and number of clocks. */
++#define PSEC_TO_CLK(psec,clk)       DIV_CEIL(((psec) * (clk)), 1000000)
++#define CYCLES_TO_PSEC(cycles,clk)  (((cycles) * 1000000) / (clk))
++
++/* Min, Max macros */
++#define MIN(a,b)    ((a) < (b) ? (a) : (b))
++#define MAX(a,b)    ((a) > (b) ? (a) : (b))
++#define IN_RANGE(min,val,max) ((min)<=(val) && (val)<=(max))
++
++#define ABS(a)  ((a<0)?(a*-1):a)
++
++#if !(defined(ARRAY_SIZE))
++#define ARRAY_SIZE(arr)   (sizeof(arr) / sizeof((arr)[0]))
++#endif /* !defined(ARRAY_SIZE) */
++
++
++/* possible alignments */
++#define HALF_WORD_ALIGNMENT     2
++#define WORD_ALIGNMENT          4
++#define DOUBLE_WORD_ALIGNMENT   8
++#define BURST_ALIGNMENT         32
++
++#define HALF_WORD_ALIGNED       0x00000001
++#define WORD_ALIGNED            0x00000003
++#define DOUBLE_WORD_ALIGNED     0x00000007
++#define BURST_ALIGNED           0x0000001f
++#ifndef IS_ALIGNED
++#define IS_ALIGNED(n,align)     (!((uint32_t)(n) & (align - 1)))
++#endif /* IS_ALIGNED */
++
++
++#define LAST_BUF        1
++#define FIRST_BUF       2
++#define SINGLE_BUF      (LAST_BUF | FIRST_BUF)
++#define MIDDLE_BUF      4
++
++#define ARRAY_END       -1
++
++#define ILLEGAL_BASE    (~0)
++
++#define BUF_POSITION(first, last)   state[(!!(last))<<1 | !!(first)]
++#define DECLARE_POSITION static uint8_t state[4] = { (uint8_t)MIDDLE_BUF, (uint8_t)FIRST_BUF, (uint8_t)LAST_BUF, (uint8_t)SINGLE_BUF };
++
++
++/**************************************************************************//**
++ @Description   Timers operation mode
++*//***************************************************************************/
++typedef enum e_TimerMode
++{
++    e_TIMER_MODE_INVALID = 0,
++    e_TIMER_MODE_FREE_RUN,    /**< Free run - counter continues to increase
++                                   after reaching the reference value. */
++    e_TIMER_MODE_PERIODIC,    /**< Periodic - counter restarts counting from 0
++                                   after reaching the reference value. */
++    e_TIMER_MODE_SINGLE       /**< Single (one-shot) - counter stops counting
++                                   after reaching the reference value. */
++} e_TimerMode;
++
++
++/**************************************************************************//**
++ @Description   Enumeration (bit flags) of communication modes (Transmit,
++                receive or both).
++*//***************************************************************************/
++typedef enum e_CommMode
++{
++    e_COMM_MODE_NONE        = 0,    /**< No transmit/receive communication */
++    e_COMM_MODE_RX          = 1,    /**< Only receive communication */
++    e_COMM_MODE_TX          = 2,    /**< Only transmit communication */
++    e_COMM_MODE_RX_AND_TX   = 3     /**< Both transmit and receive communication */
++} e_CommMode;
++
++/**************************************************************************//**
++ @Description   General Diagnostic Mode
++*//***************************************************************************/
++typedef enum e_DiagMode
++{
++    e_DIAG_MODE_NONE = 0,       /**< Normal operation; no diagnostic mode */
++    e_DIAG_MODE_CTRL_LOOPBACK,  /**< Loopback in the controller */
++    e_DIAG_MODE_CHIP_LOOPBACK,  /**< Loopback in the chip but not in the
++                                     controller; e.g. IO-pins, SerDes, etc. */
++    e_DIAG_MODE_PHY_LOOPBACK,   /**< Loopback in the external PHY */
++    e_DIAG_MODE_EXT_LOOPBACK,   /**< Loopback in the external line (beyond the PHY) */
++    e_DIAG_MODE_CTRL_ECHO,      /**< Echo incoming data by the controller */
++    e_DIAG_MODE_PHY_ECHO        /**< Echo incoming data by the PHY */
++} e_DiagMode;
++
++/**************************************************************************//**
++ @Description   Possible RxStore callback responses.
++*//***************************************************************************/
++typedef enum e_RxStoreResponse
++{
++      e_RX_STORE_RESPONSE_PAUSE     /**< Pause invoking callback with received data;
++                                         in polling mode, start again invoking callback
++                                         only next time user invokes the receive routine;
++                                         in interrupt mode, start again invoking callback
++                                         only next time a receive event triggers an interrupt;
++                                         in all cases, received data that are pending are not
++                                         lost, rather, their processing is temporarily deferred;
++                                         in all cases, received data are processed in the order
++                                         in which they were received. */
++    , e_RX_STORE_RESPONSE_CONTINUE  /**< Continue invoking callback with received data. */
++} e_RxStoreResponse;
++
++
++/**************************************************************************//**
++ @Description   General Handle
++*//***************************************************************************/
++typedef void *      t_Handle;   /**< handle, used as object's descriptor */
++
++/**************************************************************************//**
++ @Description   MUTEX type
++*//***************************************************************************/
++typedef uint32_t    t_Mutex;
++
++/**************************************************************************//**
++ @Description   Error Code.
++
++                The high word of the error code is the code of the software
++                module (driver). The low word is the error type (e_ErrorType).
++                To get the values from the error code, use GET_ERROR_TYPE()
++                and GET_ERROR_MODULE().
++*//***************************************************************************/
++typedef uint32_t    t_Error;
++
++/**************************************************************************//**
++ @Description   General prototype of interrupt service routine (ISR).
++
++ @Param[in]     handle - Optional handle of the module handling the interrupt.
++
++ @Return        None
++ *//***************************************************************************/
++typedef void (t_Isr)(t_Handle handle);
++
++/**************************************************************************//**
++ @Anchor        mem_attr
++
++ @Collection    Memory Attributes
++
++                Various attributes of memory partitions. These values may be
++                or'ed together to create a mask of all memory attributes.
++ @{
++*//***************************************************************************/
++#define MEMORY_ATTR_CACHEABLE           0x00000001
++                                        /**< Memory is cacheable */
++#define MEMORY_ATTR_QE_2ND_BUS_ACCESS   0x00000002
++                                        /**< Memory can be accessed by QUICC Engine
++                                             through its secondary bus interface */
++
++/* @} */
++
++
++/**************************************************************************//**
++ @Function      t_GetBufFunction
++
++ @Description   User callback function called by driver to get data buffer.
++
++                User provides this function. Driver invokes it.
++
++ @Param[in]     h_BufferPool        - A handle to buffer pool manager
++ @Param[out]    p_BufContextHandle  - Returns the user's private context that
++                                      should be associated with the buffer
++
++ @Return        Pointer to data buffer, NULL if error
++ *//***************************************************************************/
++typedef uint8_t * (t_GetBufFunction)(t_Handle   h_BufferPool,
++                                     t_Handle   *p_BufContextHandle);
++
++/**************************************************************************//**
++ @Function      t_PutBufFunction
++
++ @Description   User callback function called by driver to return data buffer.
++
++                User provides this function. Driver invokes it.
++
++ @Param[in]     h_BufferPool    - A handle to buffer pool manager
++ @Param[in]     p_Buffer        - A pointer to buffer to return
++ @Param[in]     h_BufContext    - The user's private context associated with
++                                  the returned buffer
++
++ @Return        E_OK on success; Error code otherwise
++ *//***************************************************************************/
++typedef t_Error (t_PutBufFunction)(t_Handle h_BufferPool,
++                                   uint8_t  *p_Buffer,
++                                   t_Handle h_BufContext);
++
++/**************************************************************************//**
++ @Function      t_PhysToVirt
++
++ @Description   Translates a physical address to the matching virtual address.
++
++ @Param[in]     addr - The physical address to translate.
++
++ @Return        Virtual address.
++*//***************************************************************************/
++typedef void * t_PhysToVirt(physAddress_t addr);
++
++/**************************************************************************//**
++ @Function      t_VirtToPhys
++
++ @Description   Translates a virtual address to the matching physical address.
++
++ @Param[in]     addr - The virtual address to translate.
++
++ @Return        Physical address.
++*//***************************************************************************/
++typedef physAddress_t t_VirtToPhys(void *addr);
++
++/**************************************************************************//**
++ @Description   Buffer Pool Information Structure.
++*//***************************************************************************/
++typedef struct t_BufferPoolInfo
++{
++    t_Handle            h_BufferPool;   /**< A handle to the buffer pool manager */
++    t_GetBufFunction    *f_GetBuf;      /**< User callback to get a free buffer */
++    t_PutBufFunction    *f_PutBuf;      /**< User callback to return a buffer */
++    uint16_t            bufferSize;     /**< Buffer size (in bytes) */
++
++    t_PhysToVirt        *f_PhysToVirt;  /**< User callback to translate pool buffers
++                                             physical addresses to virtual addresses  */
++    t_VirtToPhys        *f_VirtToPhys;  /**< User callback to translate pool buffers
++                                             virtual addresses to physical addresses */
++} t_BufferPoolInfo;
++
++
++/**************************************************************************//**
++ @Description   User callback function called by driver when transmit completed.
++
++                User provides this function. Driver invokes it.
++
++ @Param[in]     h_App           - Application's handle, as was provided to the
++                                  driver by the user
++ @Param[in]     queueId         - Transmit queue ID
++ @Param[in]     p_Data          - Pointer to the data buffer
++ @Param[in]     h_BufContext    - The user's private context associated with
++                                  the given data buffer
++ @Param[in]     status          - Transmit status and errors
++ @Param[in]     flags           - Driver-dependent information
++ *//***************************************************************************/
++typedef void (t_TxConfFunction)(t_Handle    h_App,
++                                uint32_t    queueId,
++                                uint8_t     *p_Data,
++                                t_Handle    h_BufContext,
++                                uint16_t    status,
++                                uint32_t    flags);
++
++/**************************************************************************//**
++ @Description   User callback function called by driver with receive data.
++
++                User provides this function. Driver invokes it.
++
++ @Param[in]     h_App           - Application's handle, as was provided to the
++                                  driver by the user
++ @Param[in]     queueId         - Receive queue ID
++ @Param[in]     p_Data          - Pointer to the buffer with received data
++ @Param[in]     h_BufContext    - The user's private context associated with
++                                  the given data buffer
++ @Param[in]     length          - Length of received data
++ @Param[in]     status          - Receive status and errors
++ @Param[in]     position        - Position of buffer in frame
++ @Param[in]     flags           - Driver-dependent information
++
++ @Retval        e_RX_STORE_RESPONSE_CONTINUE - order the driver to continue Rx
++                                               operation for all ready data.
++ @Retval        e_RX_STORE_RESPONSE_PAUSE    - order the driver to stop Rx operation.
++ *//***************************************************************************/
++typedef e_RxStoreResponse (t_RxStoreFunction)(t_Handle  h_App,
++                                              uint32_t  queueId,
++                                              uint8_t   *p_Data,
++                                              t_Handle  h_BufContext,
++                                              uint32_t  length,
++                                              uint16_t  status,
++                                              uint8_t   position,
++                                              uint32_t  flags);
++
++
++#endif /* __NCSW_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/net_ext.h
+@@ -0,0 +1,430 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          net_ext.h
++
++ @Description   This file contains common and general netcomm headers definitions.
++*//***************************************************************************/
++#ifndef __NET_EXT_H
++#define __NET_EXT_H
++
++#include "std_ext.h"
++
++
++typedef uint8_t headerFieldPpp_t;
++
++#define NET_HEADER_FIELD_PPP_PID                        (1)
++#define NET_HEADER_FIELD_PPP_COMPRESSED                 (NET_HEADER_FIELD_PPP_PID << 1)
++#define NET_HEADER_FIELD_PPP_ALL_FIELDS                 ((NET_HEADER_FIELD_PPP_PID << 2) - 1)
++
++
++typedef uint8_t headerFieldPppoe_t;
++
++#define NET_HEADER_FIELD_PPPoE_VER                      (1)
++#define NET_HEADER_FIELD_PPPoE_TYPE                     (NET_HEADER_FIELD_PPPoE_VER << 1)
++#define NET_HEADER_FIELD_PPPoE_CODE                     (NET_HEADER_FIELD_PPPoE_VER << 2)
++#define NET_HEADER_FIELD_PPPoE_SID                      (NET_HEADER_FIELD_PPPoE_VER << 3)
++#define NET_HEADER_FIELD_PPPoE_LEN                      (NET_HEADER_FIELD_PPPoE_VER << 4)
++#define NET_HEADER_FIELD_PPPoE_SESSION                  (NET_HEADER_FIELD_PPPoE_VER << 5)
++#define NET_HEADER_FIELD_PPPoE_PID                      (NET_HEADER_FIELD_PPPoE_VER << 6)
++#define NET_HEADER_FIELD_PPPoE_ALL_FIELDS               ((NET_HEADER_FIELD_PPPoE_VER << 7) - 1)
++
++#define NET_HEADER_FIELD_PPPMUX_PID                     (1)
++#define NET_HEADER_FIELD_PPPMUX_CKSUM                   (NET_HEADER_FIELD_PPPMUX_PID << 1)
++#define NET_HEADER_FIELD_PPPMUX_COMPRESSED              (NET_HEADER_FIELD_PPPMUX_PID << 2)
++#define NET_HEADER_FIELD_PPPMUX_ALL_FIELDS              ((NET_HEADER_FIELD_PPPMUX_PID << 3) - 1)
++
++#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF            (1)
++#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_LXT            (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 1)
++#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_LEN            (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 2)
++#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_PID            (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 3)
++#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_USE_PID        (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 4)
++#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_ALL_FIELDS     ((NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 5) - 1)
++
++
++typedef uint8_t headerFieldEth_t;
++
++#define NET_HEADER_FIELD_ETH_DA                         (1)
++#define NET_HEADER_FIELD_ETH_SA                         (NET_HEADER_FIELD_ETH_DA << 1)
++#define NET_HEADER_FIELD_ETH_LENGTH                     (NET_HEADER_FIELD_ETH_DA << 2)
++#define NET_HEADER_FIELD_ETH_TYPE                       (NET_HEADER_FIELD_ETH_DA << 3)
++#define NET_HEADER_FIELD_ETH_FINAL_CKSUM                (NET_HEADER_FIELD_ETH_DA << 4)
++#define NET_HEADER_FIELD_ETH_PADDING                    (NET_HEADER_FIELD_ETH_DA << 5)
++#define NET_HEADER_FIELD_ETH_ALL_FIELDS                 ((NET_HEADER_FIELD_ETH_DA << 6) - 1)
++
++#define NET_HEADER_FIELD_ETH_ADDR_SIZE                 6
++
++typedef uint16_t headerFieldIp_t;
++
++#define NET_HEADER_FIELD_IP_VER                         (1)
++#define NET_HEADER_FIELD_IP_DSCP                        (NET_HEADER_FIELD_IP_VER << 2)
++#define NET_HEADER_FIELD_IP_ECN                         (NET_HEADER_FIELD_IP_VER << 3)
++#define NET_HEADER_FIELD_IP_PROTO                       (NET_HEADER_FIELD_IP_VER << 4)
++
++#define NET_HEADER_FIELD_IP_PROTO_SIZE                  1
++
++typedef uint16_t headerFieldIpv4_t;
++
++#define NET_HEADER_FIELD_IPv4_VER                       (1)
++#define NET_HEADER_FIELD_IPv4_HDR_LEN                   (NET_HEADER_FIELD_IPv4_VER << 1)
++#define NET_HEADER_FIELD_IPv4_TOS                       (NET_HEADER_FIELD_IPv4_VER << 2)
++#define NET_HEADER_FIELD_IPv4_TOTAL_LEN                 (NET_HEADER_FIELD_IPv4_VER << 3)
++#define NET_HEADER_FIELD_IPv4_ID                        (NET_HEADER_FIELD_IPv4_VER << 4)
++#define NET_HEADER_FIELD_IPv4_FLAG_D                    (NET_HEADER_FIELD_IPv4_VER << 5)
++#define NET_HEADER_FIELD_IPv4_FLAG_M                    (NET_HEADER_FIELD_IPv4_VER << 6)
++#define NET_HEADER_FIELD_IPv4_OFFSET                    (NET_HEADER_FIELD_IPv4_VER << 7)
++#define NET_HEADER_FIELD_IPv4_TTL                       (NET_HEADER_FIELD_IPv4_VER << 8)
++#define NET_HEADER_FIELD_IPv4_PROTO                     (NET_HEADER_FIELD_IPv4_VER << 9)
++#define NET_HEADER_FIELD_IPv4_CKSUM                     (NET_HEADER_FIELD_IPv4_VER << 10)
++#define NET_HEADER_FIELD_IPv4_SRC_IP                    (NET_HEADER_FIELD_IPv4_VER << 11)
++#define NET_HEADER_FIELD_IPv4_DST_IP                    (NET_HEADER_FIELD_IPv4_VER << 12)
++#define NET_HEADER_FIELD_IPv4_OPTS                      (NET_HEADER_FIELD_IPv4_VER << 13)
++#define NET_HEADER_FIELD_IPv4_OPTS_COUNT                (NET_HEADER_FIELD_IPv4_VER << 14)
++#define NET_HEADER_FIELD_IPv4_ALL_FIELDS                ((NET_HEADER_FIELD_IPv4_VER << 15) - 1)
++
++#define NET_HEADER_FIELD_IPv4_ADDR_SIZE                 4
++#define NET_HEADER_FIELD_IPv4_PROTO_SIZE                1
++
++
++typedef uint8_t headerFieldIpv6_t;
++
++#define NET_HEADER_FIELD_IPv6_VER                       (1)
++#define NET_HEADER_FIELD_IPv6_TC                        (NET_HEADER_FIELD_IPv6_VER << 1)
++#define NET_HEADER_FIELD_IPv6_SRC_IP                    (NET_HEADER_FIELD_IPv6_VER << 2)
++#define NET_HEADER_FIELD_IPv6_DST_IP                    (NET_HEADER_FIELD_IPv6_VER << 3)
++#define NET_HEADER_FIELD_IPv6_NEXT_HDR                  (NET_HEADER_FIELD_IPv6_VER << 4)
++#define NET_HEADER_FIELD_IPv6_FL                        (NET_HEADER_FIELD_IPv6_VER << 5)
++#define NET_HEADER_FIELD_IPv6_HOP_LIMIT                 (NET_HEADER_FIELD_IPv6_VER << 6)
++#define NET_HEADER_FIELD_IPv6_ALL_FIELDS                ((NET_HEADER_FIELD_IPv6_VER << 7) - 1)
++
++#define NET_HEADER_FIELD_IPv6_ADDR_SIZE                 16
++#define NET_HEADER_FIELD_IPv6_NEXT_HDR_SIZE             1
++
++#define NET_HEADER_FIELD_ICMP_TYPE                      (1)
++#define NET_HEADER_FIELD_ICMP_CODE                      (NET_HEADER_FIELD_ICMP_TYPE << 1)
++#define NET_HEADER_FIELD_ICMP_CKSUM                     (NET_HEADER_FIELD_ICMP_TYPE << 2)
++#define NET_HEADER_FIELD_ICMP_ID                        (NET_HEADER_FIELD_ICMP_TYPE << 3)
++#define NET_HEADER_FIELD_ICMP_SQ_NUM                    (NET_HEADER_FIELD_ICMP_TYPE << 4)
++#define NET_HEADER_FIELD_ICMP_ALL_FIELDS                ((NET_HEADER_FIELD_ICMP_TYPE << 5) - 1)
++
++#define NET_HEADER_FIELD_ICMP_CODE_SIZE                 1
++#define NET_HEADER_FIELD_ICMP_TYPE_SIZE                 1
++
++#define NET_HEADER_FIELD_IGMP_VERSION                   (1)
++#define NET_HEADER_FIELD_IGMP_TYPE                      (NET_HEADER_FIELD_IGMP_VERSION << 1)
++#define NET_HEADER_FIELD_IGMP_CKSUM                     (NET_HEADER_FIELD_IGMP_VERSION << 2)
++#define NET_HEADER_FIELD_IGMP_DATA                      (NET_HEADER_FIELD_IGMP_VERSION << 3)
++#define NET_HEADER_FIELD_IGMP_ALL_FIELDS                ((NET_HEADER_FIELD_IGMP_VERSION << 4) - 1)
++
++
++typedef uint16_t headerFieldTcp_t;
++
++#define NET_HEADER_FIELD_TCP_PORT_SRC                   (1)
++#define NET_HEADER_FIELD_TCP_PORT_DST                   (NET_HEADER_FIELD_TCP_PORT_SRC << 1)
++#define NET_HEADER_FIELD_TCP_SEQ                        (NET_HEADER_FIELD_TCP_PORT_SRC << 2)
++#define NET_HEADER_FIELD_TCP_ACK                        (NET_HEADER_FIELD_TCP_PORT_SRC << 3)
++#define NET_HEADER_FIELD_TCP_OFFSET                     (NET_HEADER_FIELD_TCP_PORT_SRC << 4)
++#define NET_HEADER_FIELD_TCP_FLAGS                      (NET_HEADER_FIELD_TCP_PORT_SRC << 5)
++#define NET_HEADER_FIELD_TCP_WINDOW                     (NET_HEADER_FIELD_TCP_PORT_SRC << 6)
++#define NET_HEADER_FIELD_TCP_CKSUM                      (NET_HEADER_FIELD_TCP_PORT_SRC << 7)
++#define NET_HEADER_FIELD_TCP_URGPTR                     (NET_HEADER_FIELD_TCP_PORT_SRC << 8)
++#define NET_HEADER_FIELD_TCP_OPTS                       (NET_HEADER_FIELD_TCP_PORT_SRC << 9)
++#define NET_HEADER_FIELD_TCP_OPTS_COUNT                 (NET_HEADER_FIELD_TCP_PORT_SRC << 10)
++#define NET_HEADER_FIELD_TCP_ALL_FIELDS                 ((NET_HEADER_FIELD_TCP_PORT_SRC << 11) - 1)
++
++#define NET_HEADER_FIELD_TCP_PORT_SIZE                  2
++
++
++typedef uint8_t headerFieldSctp_t;
++
++#define NET_HEADER_FIELD_SCTP_PORT_SRC                  (1)
++#define NET_HEADER_FIELD_SCTP_PORT_DST                  (NET_HEADER_FIELD_SCTP_PORT_SRC << 1)
++#define NET_HEADER_FIELD_SCTP_VER_TAG                   (NET_HEADER_FIELD_SCTP_PORT_SRC << 2)
++#define NET_HEADER_FIELD_SCTP_CKSUM                     (NET_HEADER_FIELD_SCTP_PORT_SRC << 3)
++#define NET_HEADER_FIELD_SCTP_ALL_FIELDS                ((NET_HEADER_FIELD_SCTP_PORT_SRC << 4) - 1)
++
++#define NET_HEADER_FIELD_SCTP_PORT_SIZE                 2
++
++typedef uint8_t headerFieldDccp_t;
++
++#define NET_HEADER_FIELD_DCCP_PORT_SRC                  (1)
++#define NET_HEADER_FIELD_DCCP_PORT_DST                  (NET_HEADER_FIELD_DCCP_PORT_SRC << 1)
++#define NET_HEADER_FIELD_DCCP_ALL_FIELDS                ((NET_HEADER_FIELD_DCCP_PORT_SRC << 2) - 1)
++
++#define NET_HEADER_FIELD_DCCP_PORT_SIZE                 2
++
++
++typedef uint8_t headerFieldUdp_t;
++
++#define NET_HEADER_FIELD_UDP_PORT_SRC                   (1)
++#define NET_HEADER_FIELD_UDP_PORT_DST                   (NET_HEADER_FIELD_UDP_PORT_SRC << 1)
++#define NET_HEADER_FIELD_UDP_LEN                        (NET_HEADER_FIELD_UDP_PORT_SRC << 2)
++#define NET_HEADER_FIELD_UDP_CKSUM                      (NET_HEADER_FIELD_UDP_PORT_SRC << 3)
++#define NET_HEADER_FIELD_UDP_ALL_FIELDS                 ((NET_HEADER_FIELD_UDP_PORT_SRC << 4) - 1)
++
++#define NET_HEADER_FIELD_UDP_PORT_SIZE                  2
++
++typedef uint8_t headerFieldUdpLite_t;
++
++#define NET_HEADER_FIELD_UDP_LITE_PORT_SRC              (1)
++#define NET_HEADER_FIELD_UDP_LITE_PORT_DST              (NET_HEADER_FIELD_UDP_LITE_PORT_SRC << 1)
++#define NET_HEADER_FIELD_UDP_LITE_ALL_FIELDS            ((NET_HEADER_FIELD_UDP_LITE_PORT_SRC << 2) - 1)
++
++#define NET_HEADER_FIELD_UDP_LITE_PORT_SIZE             2
++
++typedef uint8_t headerFieldUdpEncapEsp_t;
++
++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC         (1)
++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST         (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 1)
++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN              (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 2)
++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM            (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 3)
++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI              (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 4)
++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM     (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 5)
++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_ALL_FIELDS       ((NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 6) - 1)
++
++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SIZE        2
++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI_SIZE         4
++
++#define NET_HEADER_FIELD_IPHC_CID                       (1)
++#define NET_HEADER_FIELD_IPHC_CID_TYPE                  (NET_HEADER_FIELD_IPHC_CID << 1)
++#define NET_HEADER_FIELD_IPHC_HCINDEX                   (NET_HEADER_FIELD_IPHC_CID << 2)
++#define NET_HEADER_FIELD_IPHC_GEN                       (NET_HEADER_FIELD_IPHC_CID << 3)
++#define NET_HEADER_FIELD_IPHC_D_BIT                     (NET_HEADER_FIELD_IPHC_CID << 4)
++#define NET_HEADER_FIELD_IPHC_ALL_FIELDS                ((NET_HEADER_FIELD_IPHC_CID << 5) - 1)
++
++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE           (1)
++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_FLAGS          (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 1)
++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_LENGTH         (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 2)
++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_TSN            (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 3)
++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_ID      (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 4)
++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_SQN     (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 5)
++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_PAYLOAD_PID    (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 6)
++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_UNORDERED      (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 7)
++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_BEGGINING      (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 8)
++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_END            (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 9)
++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_ALL_FIELDS     ((NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 10) - 1)
++
++#define NET_HEADER_FIELD_L2TPv2_TYPE_BIT                (1)
++#define NET_HEADER_FIELD_L2TPv2_LENGTH_BIT              (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 1)
++#define NET_HEADER_FIELD_L2TPv2_SEQUENCE_BIT            (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 2)
++#define NET_HEADER_FIELD_L2TPv2_OFFSET_BIT              (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 3)
++#define NET_HEADER_FIELD_L2TPv2_PRIORITY_BIT            (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 4)
++#define NET_HEADER_FIELD_L2TPv2_VERSION                 (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 5)
++#define NET_HEADER_FIELD_L2TPv2_LEN                     (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 6)
++#define NET_HEADER_FIELD_L2TPv2_TUNNEL_ID               (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 7)
++#define NET_HEADER_FIELD_L2TPv2_SESSION_ID              (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 8)
++#define NET_HEADER_FIELD_L2TPv2_NS                      (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 9)
++#define NET_HEADER_FIELD_L2TPv2_NR                      (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 10)
++#define NET_HEADER_FIELD_L2TPv2_OFFSET_SIZE             (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 11)
++#define NET_HEADER_FIELD_L2TPv2_FIRST_BYTE              (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 12)
++#define NET_HEADER_FIELD_L2TPv2_ALL_FIELDS              ((NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 13) - 1)
++
++#define NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT           (1)
++#define NET_HEADER_FIELD_L2TPv3_CTRL_LENGTH_BIT         (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 1)
++#define NET_HEADER_FIELD_L2TPv3_CTRL_SEQUENCE_BIT       (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 2)
++#define NET_HEADER_FIELD_L2TPv3_CTRL_VERSION            (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 3)
++#define NET_HEADER_FIELD_L2TPv3_CTRL_LENGTH             (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 4)
++#define NET_HEADER_FIELD_L2TPv3_CTRL_CONTROL            (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 5)
++#define NET_HEADER_FIELD_L2TPv3_CTRL_SENT               (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 6)
++#define NET_HEADER_FIELD_L2TPv3_CTRL_RECV               (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 7)
++#define NET_HEADER_FIELD_L2TPv3_CTRL_FIRST_BYTE         (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 8)
++#define NET_HEADER_FIELD_L2TPv3_CTRL_ALL_FIELDS         ((NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 9) - 1)
++
++#define NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT           (1)
++#define NET_HEADER_FIELD_L2TPv3_SESS_VERSION            (NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 1)
++#define NET_HEADER_FIELD_L2TPv3_SESS_ID                 (NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 2)
++#define NET_HEADER_FIELD_L2TPv3_SESS_COOKIE             (NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 3)
++#define NET_HEADER_FIELD_L2TPv3_SESS_ALL_FIELDS         ((NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 4) - 1)
++
++
++typedef uint8_t headerFieldVlan_t;
++
++#define NET_HEADER_FIELD_VLAN_VPRI                      (1)
++#define NET_HEADER_FIELD_VLAN_CFI                       (NET_HEADER_FIELD_VLAN_VPRI << 1)
++#define NET_HEADER_FIELD_VLAN_VID                       (NET_HEADER_FIELD_VLAN_VPRI << 2)
++#define NET_HEADER_FIELD_VLAN_LENGTH                    (NET_HEADER_FIELD_VLAN_VPRI << 3)
++#define NET_HEADER_FIELD_VLAN_TYPE                      (NET_HEADER_FIELD_VLAN_VPRI << 4)
++#define NET_HEADER_FIELD_VLAN_ALL_FIELDS                ((NET_HEADER_FIELD_VLAN_VPRI << 5) - 1)
++
++#define NET_HEADER_FIELD_VLAN_TCI                       (NET_HEADER_FIELD_VLAN_VPRI | \
++                                                         NET_HEADER_FIELD_VLAN_CFI | \
++                                                         NET_HEADER_FIELD_VLAN_VID)
++
++
++typedef uint8_t headerFieldLlc_t;
++
++#define NET_HEADER_FIELD_LLC_DSAP                       (1)
++#define NET_HEADER_FIELD_LLC_SSAP                       (NET_HEADER_FIELD_LLC_DSAP << 1)
++#define NET_HEADER_FIELD_LLC_CTRL                       (NET_HEADER_FIELD_LLC_DSAP << 2)
++#define NET_HEADER_FIELD_LLC_ALL_FIELDS                 ((NET_HEADER_FIELD_LLC_DSAP << 3) - 1)
++
++#define NET_HEADER_FIELD_NLPID_NLPID                    (1)
++#define NET_HEADER_FIELD_NLPID_ALL_FIELDS               ((NET_HEADER_FIELD_NLPID_NLPID << 1) - 1)
++
++
++typedef uint8_t headerFieldSnap_t;
++
++#define NET_HEADER_FIELD_SNAP_OUI                       (1)
++#define NET_HEADER_FIELD_SNAP_PID                       (NET_HEADER_FIELD_SNAP_OUI << 1)
++#define NET_HEADER_FIELD_SNAP_ALL_FIELDS                ((NET_HEADER_FIELD_SNAP_OUI << 2) - 1)
++
++
++typedef uint8_t headerFieldLlcSnap_t;
++
++#define NET_HEADER_FIELD_LLC_SNAP_TYPE                  (1)
++#define NET_HEADER_FIELD_LLC_SNAP_ALL_FIELDS            ((NET_HEADER_FIELD_LLC_SNAP_TYPE << 1) - 1)
++
++#define NET_HEADER_FIELD_ARP_HTYPE                      (1)
++#define NET_HEADER_FIELD_ARP_PTYPE                      (NET_HEADER_FIELD_ARP_HTYPE << 1)
++#define NET_HEADER_FIELD_ARP_HLEN                       (NET_HEADER_FIELD_ARP_HTYPE << 2)
++#define NET_HEADER_FIELD_ARP_PLEN                       (NET_HEADER_FIELD_ARP_HTYPE << 3)
++#define NET_HEADER_FIELD_ARP_OPER                       (NET_HEADER_FIELD_ARP_HTYPE << 4)
++#define NET_HEADER_FIELD_ARP_SHA                        (NET_HEADER_FIELD_ARP_HTYPE << 5)
++#define NET_HEADER_FIELD_ARP_SPA                        (NET_HEADER_FIELD_ARP_HTYPE << 6)
++#define NET_HEADER_FIELD_ARP_THA                        (NET_HEADER_FIELD_ARP_HTYPE << 7)
++#define NET_HEADER_FIELD_ARP_TPA                        (NET_HEADER_FIELD_ARP_HTYPE << 8)
++#define NET_HEADER_FIELD_ARP_ALL_FIELDS                 ((NET_HEADER_FIELD_ARP_HTYPE << 9) - 1)
++
++#define NET_HEADER_FIELD_RFC2684_LLC                    (1)
++#define NET_HEADER_FIELD_RFC2684_NLPID                  (NET_HEADER_FIELD_RFC2684_LLC << 1)
++#define NET_HEADER_FIELD_RFC2684_OUI                    (NET_HEADER_FIELD_RFC2684_LLC << 2)
++#define NET_HEADER_FIELD_RFC2684_PID                    (NET_HEADER_FIELD_RFC2684_LLC << 3)
++#define NET_HEADER_FIELD_RFC2684_VPN_OUI                (NET_HEADER_FIELD_RFC2684_LLC << 4)
++#define NET_HEADER_FIELD_RFC2684_VPN_IDX                (NET_HEADER_FIELD_RFC2684_LLC << 5)
++#define NET_HEADER_FIELD_RFC2684_ALL_FIELDS             ((NET_HEADER_FIELD_RFC2684_LLC << 6) - 1)
++
++#define NET_HEADER_FIELD_USER_DEFINED_SRCPORT           (1)
++#define NET_HEADER_FIELD_USER_DEFINED_PCDID             (NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 1)
++#define NET_HEADER_FIELD_USER_DEFINED_ALL_FIELDS        ((NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 2) - 1)
++
++#define NET_HEADER_FIELD_PAYLOAD_BUFFER                 (1)
++#define NET_HEADER_FIELD_PAYLOAD_SIZE                   (NET_HEADER_FIELD_PAYLOAD_BUFFER << 1)
++#define NET_HEADER_FIELD_MAX_FRM_SIZE                   (NET_HEADER_FIELD_PAYLOAD_BUFFER << 2)
++#define NET_HEADER_FIELD_MIN_FRM_SIZE                   (NET_HEADER_FIELD_PAYLOAD_BUFFER << 3)
++#define NET_HEADER_FIELD_PAYLOAD_TYPE                   (NET_HEADER_FIELD_PAYLOAD_BUFFER << 4)
++#define NET_HEADER_FIELD_FRAME_SIZE                     (NET_HEADER_FIELD_PAYLOAD_BUFFER << 5)
++#define NET_HEADER_FIELD_PAYLOAD_ALL_FIELDS             ((NET_HEADER_FIELD_PAYLOAD_BUFFER << 6) - 1)
++
++
++typedef uint8_t headerFieldGre_t;
++
++#define NET_HEADER_FIELD_GRE_TYPE                       (1)
++#define NET_HEADER_FIELD_GRE_ALL_FIELDS                 ((NET_HEADER_FIELD_GRE_TYPE << 1) - 1)
++
++
++typedef uint8_t headerFieldMinencap_t;
++
++#define NET_HEADER_FIELD_MINENCAP_SRC_IP                (1)
++#define NET_HEADER_FIELD_MINENCAP_DST_IP                (NET_HEADER_FIELD_MINENCAP_SRC_IP << 1)
++#define NET_HEADER_FIELD_MINENCAP_TYPE                  (NET_HEADER_FIELD_MINENCAP_SRC_IP << 2)
++#define NET_HEADER_FIELD_MINENCAP_ALL_FIELDS            ((NET_HEADER_FIELD_MINENCAP_SRC_IP << 3) - 1)
++
++
++typedef uint8_t headerFieldIpsecAh_t;
++
++#define NET_HEADER_FIELD_IPSEC_AH_SPI                   (1)
++#define NET_HEADER_FIELD_IPSEC_AH_NH                    (NET_HEADER_FIELD_IPSEC_AH_SPI << 1)
++#define NET_HEADER_FIELD_IPSEC_AH_ALL_FIELDS            ((NET_HEADER_FIELD_IPSEC_AH_SPI << 2) - 1)
++
++
++typedef uint8_t headerFieldIpsecEsp_t;
++
++#define NET_HEADER_FIELD_IPSEC_ESP_SPI                  (1)
++#define NET_HEADER_FIELD_IPSEC_ESP_SEQUENCE_NUM         (NET_HEADER_FIELD_IPSEC_ESP_SPI << 1)
++#define NET_HEADER_FIELD_IPSEC_ESP_ALL_FIELDS           ((NET_HEADER_FIELD_IPSEC_ESP_SPI << 2) - 1)
++
++#define NET_HEADER_FIELD_IPSEC_ESP_SPI_SIZE             4
++
++
++typedef uint8_t headerFieldMpls_t;
++
++#define NET_HEADER_FIELD_MPLS_LABEL_STACK               (1)
++#define NET_HEADER_FIELD_MPLS_LABEL_STACK_ALL_FIELDS    ((NET_HEADER_FIELD_MPLS_LABEL_STACK << 1) - 1)
++
++
++typedef uint8_t headerFieldMacsec_t;
++
++#define NET_HEADER_FIELD_MACSEC_SECTAG                  (1)
++#define NET_HEADER_FIELD_MACSEC_ALL_FIELDS              ((NET_HEADER_FIELD_MACSEC_SECTAG << 1) - 1)
++
++
++typedef enum {
++    HEADER_TYPE_NONE = 0,
++    HEADER_TYPE_PAYLOAD,
++    HEADER_TYPE_ETH,
++    HEADER_TYPE_VLAN,
++    HEADER_TYPE_IPv4,
++    HEADER_TYPE_IPv6,
++    HEADER_TYPE_IP,
++    HEADER_TYPE_TCP,
++    HEADER_TYPE_UDP,
++    HEADER_TYPE_UDP_LITE,
++    HEADER_TYPE_IPHC,
++    HEADER_TYPE_SCTP,
++    HEADER_TYPE_SCTP_CHUNK_DATA,
++    HEADER_TYPE_PPPoE,
++    HEADER_TYPE_PPP,
++    HEADER_TYPE_PPPMUX,
++    HEADER_TYPE_PPPMUX_SUBFRAME,
++    HEADER_TYPE_L2TPv2,
++    HEADER_TYPE_L2TPv3_CTRL,
++    HEADER_TYPE_L2TPv3_SESS,
++    HEADER_TYPE_LLC,
++    HEADER_TYPE_LLC_SNAP,
++    HEADER_TYPE_NLPID,
++    HEADER_TYPE_SNAP,
++    HEADER_TYPE_MPLS,
++    HEADER_TYPE_IPSEC_AH,
++    HEADER_TYPE_IPSEC_ESP,
++    HEADER_TYPE_UDP_ENCAP_ESP, /* RFC 3948 */
++    HEADER_TYPE_MACSEC,
++    HEADER_TYPE_GRE,
++    HEADER_TYPE_MINENCAP,
++    HEADER_TYPE_DCCP,
++    HEADER_TYPE_ICMP,
++    HEADER_TYPE_IGMP,
++    HEADER_TYPE_ARP,
++    HEADER_TYPE_CAPWAP,
++    HEADER_TYPE_CAPWAP_DTLS,
++    HEADER_TYPE_RFC2684,
++    HEADER_TYPE_USER_DEFINED_L2,
++    HEADER_TYPE_USER_DEFINED_L3,
++    HEADER_TYPE_USER_DEFINED_L4,
++    HEADER_TYPE_USER_DEFINED_SHIM1,
++    HEADER_TYPE_USER_DEFINED_SHIM2,
++    MAX_HEADER_TYPE_COUNT
++} e_NetHeaderType;
++
++
++#endif /* __NET_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/std_ext.h
+@@ -0,0 +1,48 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          std_ext.h
++
++ @Description   General Standard Definitions
++*//***************************************************************************/
++
++#ifndef __STD_EXT_H
++#define __STD_EXT_H
++
++
++#include "types_ext.h"
++#include "ncsw_ext.h"
++
++
++#endif /* __STD_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/stdarg_ext.h
+@@ -0,0 +1,49 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#ifndef __STDARG_EXT_H
++#define __STDARG_EXT_H
++
++
++#if defined(NCSW_LINUX) && defined(__KERNEL__)
++#include <stdarg.h>
++
++#else
++#include <stdarg.h>
++
++#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */
++
++#include "std_ext.h"
++
++
++#endif /* __STDARG_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/stdlib_ext.h
+@@ -0,0 +1,162 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++
++#ifndef __STDLIB_EXT_H
++#define __STDLIB_EXT_H
++
++
++#if (defined(NCSW_LINUX)) && defined(__KERNEL__)
++#include "stdarg_ext.h"
++#include "std_ext.h"
++
++
++/**
++ * strtoul - convert a string to an uint32_t
++ * @cp: The start of the string
++ * @endp: A pointer to the end of the parsed string will be placed here
++ * @base: The number base to use
++ */
++uint32_t strtoul(const char *cp,char **endp,uint32_t base);
++
++/**
++ * strtol - convert a string to a int32_t
++ * @cp: The start of the string
++ * @endp: A pointer to the end of the parsed string will be placed here
++ * @base: The number base to use
++ */
++long strtol(const char *cp,char **endp,uint32_t base);
++
++/**
++ * strtoull - convert a string to an uint64_t
++ * @cp: The start of the string
++ * @endp: A pointer to the end of the parsed string will be placed here
++ * @base: The number base to use
++ */
++uint64_t strtoull(const char *cp,char **endp,uint32_t base);
++
++/**
++ * strtoll - convert a string to a int64 long
++ * @cp: The start of the string
++ * @endp: A pointer to the end of the parsed string will be placed here
++ * @base: The number base to use
++ */
++long long strtoll(const char *cp,char **endp,uint32_t base);
++
++/**
++ * atoi - convert a character to a int
++ * @s: The start of the string
++ */
++int atoi(const char *s);
++
++/**
++ * strnlen - Find the length of a length-limited string
++ * @s: The string to be sized
++ * @count: The maximum number of bytes to search
++ */
++size_t strnlen(const char * s, size_t count);
++
++/**
++ * strlen - Find the length of a string
++ * @s: The string to be sized
++ */
++size_t strlen(const char * s);
++
++/**
++ * strtok - Split a string into tokens
++ * @s: The string to be searched
++ * @ct: The characters to search for
++ *
++ * WARNING: strtok is deprecated, use strsep instead.
++ */
++char * strtok(char * s,const char * ct);
++
++/**
++ * strncpy - Copy a length-limited, %NUL-terminated string
++ * @dest: Where to copy the string to
++ * @src: Where to copy the string from
++ * @count: The maximum number of bytes to copy
++ *
++ * Note that unlike userspace strncpy, this does not %NUL-pad the buffer.
++ * However, the result is not %NUL-terminated if the source exceeds
++ * @count bytes.
++ */
++char * strncpy(char * dest,const char *src,size_t count);
++
++/**
++ * strcpy - Copy a %NUL terminated string
++ * @dest: Where to copy the string to
++ * @src: Where to copy the string from
++ */
++char * strcpy(char * dest,const char *src);
++
++/**
++ * vsscanf - Unformat a buffer into a list of arguments
++ * @buf:    input buffer
++ * @fmt:    format of buffer
++ * @args:    arguments
++ */
++int vsscanf(const char * buf, const char * fmt, va_list args);
++
++/**
++ * vsnprintf - Format a string and place it in a buffer
++ * @buf: The buffer to place the result into
++ * @size: The size of the buffer, including the trailing null space
++ * @fmt: The format string to use
++ * @args: Arguments for the format string
++ *
++ * Call this function if you are already dealing with a va_list.
++ * You probably want snprintf instead.
++ */
++int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
++
++/**
++ * vsprintf - Format a string and place it in a buffer
++ * @buf: The buffer to place the result into
++ * @fmt: The format string to use
++ * @args: Arguments for the format string
++ *
++ * Call this function if you are already dealing with a va_list.
++ * You probably want sprintf instead.
++ */
++int vsprintf(char *buf, const char *fmt, va_list args);
++
++#else
++#include <stdlib.h>
++#include <stdio.h>
++#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */
++
++#include "std_ext.h"
++
++
++#endif /* __STDLIB_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/string_ext.h
+@@ -0,0 +1,56 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#ifndef __STRING_EXT_H
++#define __STRING_EXT_H
++
++
++#if defined(NCSW_LINUX) && defined(__KERNEL__)
++#include <linux/kernel.h>
++#include <linux/string.h>
++extern char * strtok ( char * str, const char * delimiters );
++
++#elif defined(__KERNEL__)
++#include "linux/types.h"
++#include "linux/posix_types.h"
++#include "linux/string.h"
++
++#else
++#include <string.h>
++
++#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */
++
++#include "std_ext.h"
++
++
++#endif /* __STRING_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/types_ext.h
+@@ -0,0 +1,62 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          types_ext.h
++
++ @Description   General types Standard Definitions
++*//***************************************************************************/
++
++#ifndef __TYPES_EXT_H
++#define __TYPES_EXT_H
++
++#if defined(NCSW_LINUX)
++#include "types_linux.h"
++
++#elif defined(NCSW_VXWORKS)
++#include "types_vxworks.h"
++
++#elif defined(__GNUC__) && defined(__cplusplus)
++#include "types_bb_gpp.h"
++
++#elif defined(__GNUC__)
++#include "types_bb_gcc.h"
++
++#elif defined(__ghs__)
++#include "types_ghs.h"
++
++#else
++#include "types_dflt.h"
++#endif /* defined (__ROCOO__) */
++
++#endif /* __TYPES_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/xx_common.h
+@@ -0,0 +1,56 @@
++/*
++ * Copyright 2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          debug_ext.h
++
++ @Description   Debug mode definitions.
++*//***************************************************************************/
++
++#ifndef __XX_COMMON_H
++#define __XX_COMMON_H
++
++/*****************************************************************************
++ *  UNIFIED MODULE CODES
++ *****************************************************************************/
++#define MODULE_UNKNOWN          0x00000000
++#define MODULE_FM               0x00010000
++#define MODULE_FM_MURAM         0x00020000
++#define MODULE_FM_PCD           0x00030000
++#define MODULE_FM_RTC           0x00040000
++#define MODULE_FM_MAC           0x00050000
++#define MODULE_FM_PORT          0x00060000
++#define MODULE_MM               0x00070000
++#define MODULE_FM_SP            0x00080000
++#define MODULE_FM_MACSEC        0x00090000
++#endif /* __XX_COMMON_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/xx_ext.h
+@@ -0,0 +1,791 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          xx_ext.h
++
++ @Description   Prototypes, externals and typedefs for system-supplied
++                (external) routines
++*//***************************************************************************/
++
++#ifndef __XX_EXT_H
++#define __XX_EXT_H
++
++#include "std_ext.h"
++#include "xx_common.h"
++#include "part_ext.h"
++
++
++
++/**************************************************************************//**
++ @Group         xx_id  XX Interface (System call hooks)
++
++ @Description   Prototypes, externals and typedefs for system-supplied
++                (external) routines
++
++ @{
++*//***************************************************************************/
++
++#ifdef DEBUG_XX_MALLOC
++void * XX_MallocDebug(uint32_t size, char *fname, int line);
++
++void * XX_MallocSmartDebug(uint32_t size,
++                           int      memPartitionId,
++                           uint32_t alignment,
++                           char     *fname,
++                           int      line);
++
++#define XX_Malloc(sz) \
++    XX_MallocDebug((sz), __FILE__, __LINE__)
++
++#define XX_MallocSmart(sz, memt, al) \
++    XX_MallocSmartDebug((sz), (memt), (al), __FILE__, __LINE__)
++
++#else /* not DEBUG_XX_MALLOC */
++/**************************************************************************//**
++ @Function      XX_Malloc
++
++ @Description   allocates contiguous block of memory.
++
++ @Param[in]     size - Number of bytes to allocate.
++
++ @Return        The address of the newly allocated block on success, NULL on failure.
++*//***************************************************************************/
++void * XX_Malloc(uint32_t size);
++
++/**************************************************************************//**
++ @Function      XX_MallocSmart
++
++ @Description   Allocates contiguous block of memory in a specified
++                alignment and from the specified segment.
++
++ @Param[in]     size            - Number of bytes to allocate.
++ @Param[in]     memPartitionId  - Memory partition ID; The value zero must
++                                  be mapped to the default heap partition.
++ @Param[in]     alignment       - Required memory alignment (in bytes).
++
++ @Return        The address of the newly allocated block on success, NULL on failure.
++*//***************************************************************************/
++void * XX_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment);
++#endif /* not DEBUG_XX_MALLOC */
++
++/**************************************************************************//**
++ @Function      XX_FreeSmart
++
++ @Description   Frees the memory block pointed to by "p".
++                Only for memory allocated by XX_MallocSmart
++
++ @Param[in]     p_Memory - pointer to the memory block.
++
++ @Return        None.
++*//***************************************************************************/
++void XX_FreeSmart(void *p_Memory);
++
++/**************************************************************************//**
++ @Function      XX_Free
++
++ @Description   frees the memory block pointed to by "p".
++
++ @Param[in]     p_Memory - pointer to the memory block.
++
++ @Return        None.
++*//***************************************************************************/
++void XX_Free(void *p_Memory);
++
++/**************************************************************************//**
++ @Function      XX_Print
++
++ @Description   print a string.
++
++ @Param[in]     str - string to print.
++
++ @Return        None.
++*//***************************************************************************/
++void XX_Print(char *str, ...);
++
++/**************************************************************************//**
++ @Function      XX_SetIntr
++
++ @Description   Set an interrupt service routine for a specific interrupt source.
++
++ @Param[in]     irq     - Interrupt ID (system-specific number).
++ @Param[in]     f_Isr   - Callback routine that will be called when the interrupt occurs.
++ @Param[in]     handle  - The argument for the user callback routine.
++
++ @Return        E_OK on success; error code otherwise..
++*//***************************************************************************/
++t_Error XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle);
++
++/**************************************************************************//**
++ @Function      XX_FreeIntr
++
++ @Description   Free a specific interrupt and a specific callback routine.
++
++ @Param[in]     irq - Interrupt ID (system-specific number).
++
++ @Return        E_OK on success; error code otherwise..
++*//***************************************************************************/
++t_Error XX_FreeIntr(int irq);
++
++/**************************************************************************//**
++ @Function      XX_EnableIntr
++
++ @Description   Enable a specific interrupt.
++
++ @Param[in]     irq - Interrupt ID (system-specific number).
++
++ @Return        E_OK on success; error code otherwise..
++*//***************************************************************************/
++t_Error XX_EnableIntr(int irq);
++
++/**************************************************************************//**
++ @Function      XX_DisableIntr
++
++ @Description   Disable a specific interrupt.
++
++ @Param[in]     irq - Interrupt ID (system-specific number).
++
++ @Return        E_OK on success; error code otherwise..
++*//***************************************************************************/
++t_Error XX_DisableIntr(int irq);
++
++/**************************************************************************//**
++ @Function      XX_DisableAllIntr
++
++ @Description   Disable all interrupts by masking them at the CPU.
++
++ @Return        A value that represents the interrupts state before the
++                operation, and should be passed to the matching
++                XX_RestoreAllIntr() call.
++*//***************************************************************************/
++uint32_t XX_DisableAllIntr(void);
++
++/**************************************************************************//**
++ @Function      XX_RestoreAllIntr
++
++ @Description   Restore previous state of interrupts level at the CPU.
++
++ @Param[in]     flags - A value that represents the interrupts state to restore,
++                        as returned by the matching call for XX_DisableAllIntr().
++
++ @Return        None.
++*//***************************************************************************/
++void XX_RestoreAllIntr(uint32_t flags);
++
++
++/**************************************************************************//**
++ @Function      XX_Exit
++
++ @Description   Stop execution and report status (where it is applicable)
++
++ @Param[in]     status - exit status
++*//***************************************************************************/
++void    XX_Exit(int status);
++
++
++/*****************************************************************************/
++/*                        Tasklet Service Routines                           */
++/*****************************************************************************/
++typedef t_Handle t_TaskletHandle;
++
++/**************************************************************************//**
++ @Function      XX_InitTasklet
++
++ @Description   Create and initialize a tasklet object.
++
++ @Param[in]     routine - A routine to be ran as a tasklet.
++ @Param[in]     data    - An argument to pass to the tasklet.
++
++ @Return        Tasklet handle is returned on success. NULL is returned otherwise.
++*//***************************************************************************/
++t_TaskletHandle XX_InitTasklet (void (*routine)(void *), void *data);
++
++/**************************************************************************//**
++ @Function      XX_FreeTasklet
++
++ @Description   Free a tasklet object.
++
++ @Param[in]     h_Tasklet - A handle to a tasklet to be free.
++
++ @Return        None.
++*//***************************************************************************/
++void XX_FreeTasklet (t_TaskletHandle h_Tasklet);
++
++/**************************************************************************//**
++ @Function      XX_ScheduleTask
++
++ @Description   Schedule a tasklet object.
++
++ @Param[in]     h_Tasklet - A handle to a tasklet to be scheduled.
++ @Param[in]     immediate - Indicate whether to schedule this tasklet on
++                            the immediate queue or on the delayed one.
++
++ @Return        0 - on success. Error code - otherwise.
++*//***************************************************************************/
++int XX_ScheduleTask(t_TaskletHandle h_Tasklet, int immediate);
++
++/**************************************************************************//**
++ @Function      XX_FlushScheduledTasks
++
++ @Description   Flush all tasks there are in the scheduled tasks queue.
++
++ @Return        None.
++*//***************************************************************************/
++void XX_FlushScheduledTasks(void);
++
++/**************************************************************************//**
++ @Function      XX_TaskletIsQueued
++
++ @Description   Check if task is queued.
++
++ @Param[in]     h_Tasklet - A handle to a tasklet to be scheduled.
++
++ @Return        1 - task is queued. 0 - otherwise.
++*//***************************************************************************/
++int XX_TaskletIsQueued(t_TaskletHandle h_Tasklet);
++
++/**************************************************************************//**
++ @Function      XX_SetTaskletData
++
++ @Description   Set data to a scheduled task. Used to change data of already
++                scheduled task.
++
++ @Param[in]     h_Tasklet - A handle to a tasklet to be scheduled.
++ @Param[in]     data      - Data to be set.
++*//***************************************************************************/
++void XX_SetTaskletData(t_TaskletHandle h_Tasklet, t_Handle data);
++
++/**************************************************************************//**
++ @Function      XX_GetTaskletData
++
++ @Description   Get the data of scheduled task.
++
++ @Param[in]     h_Tasklet - A handle to a tasklet to be scheduled.
++
++ @Return        handle to the data of the task.
++*//***************************************************************************/
++t_Handle XX_GetTaskletData(t_TaskletHandle h_Tasklet);
++
++/**************************************************************************//**
++ @Function      XX_BottomHalf
++
++ @Description   Bottom half implementation, invoked by the interrupt handler.
++
++                This routine handles all bottom-half tasklets with interrupts
++                enabled.
++
++ @Return        None.
++*//***************************************************************************/
++void XX_BottomHalf(void);
++
++
++/*****************************************************************************/
++/*                        Spinlock Service Routines                          */
++/*****************************************************************************/
++
++/**************************************************************************//**
++ @Function      XX_InitSpinlock
++
++ @Description   Creates a spinlock.
++
++ @Return        Spinlock handle is returned on success; NULL otherwise.
++*//***************************************************************************/
++t_Handle XX_InitSpinlock(void);
++
++/**************************************************************************//**
++ @Function      XX_FreeSpinlock
++
++ @Description   Frees the memory allocated for the spinlock creation.
++
++ @Param[in]     h_Spinlock - A handle to a spinlock.
++
++ @Return        None.
++*//***************************************************************************/
++void XX_FreeSpinlock(t_Handle h_Spinlock);
++
++/**************************************************************************//**
++ @Function      XX_LockSpinlock
++
++ @Description   Locks a spinlock.
++
++ @Param[in]     h_Spinlock - A handle to a spinlock.
++
++ @Return        None.
++*//***************************************************************************/
++void XX_LockSpinlock(t_Handle h_Spinlock);
++
++/**************************************************************************//**
++ @Function      XX_UnlockSpinlock
++
++ @Description   Unlocks a spinlock.
++
++ @Param[in]     h_Spinlock - A handle to a spinlock.
++
++ @Return        None.
++*//***************************************************************************/
++void XX_UnlockSpinlock(t_Handle h_Spinlock);
++
++/**************************************************************************//**
++ @Function      XX_LockIntrSpinlock
++
++ @Description   Locks a spinlock (interrupt safe).
++
++ @Param[in]     h_Spinlock - A handle to a spinlock.
++
++ @Return        A value that represents the interrupts state before the
++                operation, and should be passed to the matching
++                XX_UnlockIntrSpinlock() call.
++*//***************************************************************************/
++uint32_t XX_LockIntrSpinlock(t_Handle h_Spinlock);
++
++/**************************************************************************//**
++ @Function      XX_UnlockIntrSpinlock
++
++ @Description   Unlocks a spinlock (interrupt safe).
++
++ @Param[in]     h_Spinlock  - A handle to a spinlock.
++ @Param[in]     intrFlags   - A value that represents the interrupts state to
++                              restore, as returned by the matching call for
++                              XX_LockIntrSpinlock().
++
++ @Return        None.
++*//***************************************************************************/
++void XX_UnlockIntrSpinlock(t_Handle h_Spinlock, uint32_t intrFlags);
++
++
++/*****************************************************************************/
++/*                        Timers Service Routines                            */
++/*****************************************************************************/
++
++/**************************************************************************//**
++ @Function      XX_CurrentTime
++
++ @Description   Returns current system time.
++
++ @Return        Current system time (in milliseconds).
++*//***************************************************************************/
++uint32_t XX_CurrentTime(void);
++
++/**************************************************************************//**
++ @Function      XX_CreateTimer
++
++ @Description   Creates a timer.
++
++ @Return        Timer handle is returned on success; NULL otherwise.
++*//***************************************************************************/
++t_Handle XX_CreateTimer(void);
++
++/**************************************************************************//**
++ @Function      XX_FreeTimer
++
++ @Description   Frees the memory allocated for the timer creation.
++
++ @Param[in]     h_Timer - A handle to a timer.
++
++ @Return        None.
++*//***************************************************************************/
++void XX_FreeTimer(t_Handle h_Timer);
++
++/**************************************************************************//**
++ @Function      XX_StartTimer
++
++ @Description   Starts a timer.
++
++                The user can select to start the timer as periodic timer or as
++                one-shot timer. The user should provide a callback routine that
++                will be called when the timer expires.
++
++ @Param[in]     h_Timer         - A handle to a timer.
++ @Param[in]     msecs           - Timer expiration period (in milliseconds).
++ @Param[in]     periodic        - TRUE for a periodic timer;
++                                  FALSE for a one-shot timer..
++ @Param[in]     f_TimerExpired  - A callback routine to be called when the
++                                  timer expires.
++ @Param[in]     h_Arg           - The argument to pass in the timer-expired
++                                  callback routine.
++
++ @Return        None.
++*//***************************************************************************/
++void XX_StartTimer(t_Handle h_Timer,
++                   uint32_t msecs,
++                   bool     periodic,
++                   void     (*f_TimerExpired)(t_Handle h_Arg),
++                   t_Handle h_Arg);
++
++/**************************************************************************//**
++ @Function      XX_StopTimer
++
++ @Description   Frees the memory allocated for the timer creation.
++
++ @Param[in]     h_Timer - A handle to a timer.
++
++ @Return        None.
++*//***************************************************************************/
++void XX_StopTimer(t_Handle h_Timer);
++
++/**************************************************************************//**
++ @Function      XX_ModTimer
++
++ @Description   Updates the expiration time of a timer.
++
++                This routine adds the given time to the current system time,
++                and sets this value as the new expiration time of the timer.
++
++ @Param[in]     h_Timer - A handle to a timer.
++ @Param[in]     msecs   - The new interval until timer expiration
++                          (in milliseconds).
++
++ @Return        None.
++*//***************************************************************************/
++void XX_ModTimer(t_Handle h_Timer, uint32_t msecs);
++
++/**************************************************************************//**
++ @Function      XX_Sleep
++
++ @Description   Non-busy wait until the desired time (in milliseconds) has passed.
++
++ @Param[in]     msecs - The requested sleep time (in milliseconds).
++
++ @Return        Zero if the requested time has elapsed; Otherwise, the value
++                returned will be the unslept amount) in milliseconds.
++
++ @Cautions      This routine enables interrupts during its wait time.
++*//***************************************************************************/
++uint32_t XX_Sleep(uint32_t msecs);
++
++/**************************************************************************//**
++ @Function      XX_UDelay
++
++ @Description   Busy-wait until the desired time (in microseconds) has passed.
++
++ @Param[in]     usecs - The requested delay time (in microseconds).
++
++ @Return        None.
++
++ @Cautions      It is highly unrecommended to call this routine during interrupt
++                time, because the system time may not be updated properly during
++                the delay loop. The behavior of this routine during interrupt
++                time is unexpected.
++*//***************************************************************************/
++void XX_UDelay(uint32_t usecs);
++
++
++/*****************************************************************************/
++/*                         Other Service Routines                            */
++/*****************************************************************************/
++
++/**************************************************************************//**
++ @Function      XX_PhysToVirt
++
++ @Description   Translates a physical address to the matching virtual address.
++
++ @Param[in]     addr - The physical address to translate.
++
++ @Return        Virtual address.
++*//***************************************************************************/
++void * XX_PhysToVirt(physAddress_t addr);
++
++/**************************************************************************//**
++ @Function      XX_VirtToPhys
++
++ @Description   Translates a virtual address to the matching physical address.
++
++ @Param[in]     addr - The virtual address to translate.
++
++ @Return        Physical address.
++*//***************************************************************************/
++physAddress_t XX_VirtToPhys(void *addr);
++
++
++/**************************************************************************//**
++ @Group         xx_ipc  XX Inter-Partition-Communication API
++
++ @Description   The following API is to be used when working with multiple
++                partitions configuration.
++
++ @{
++*//***************************************************************************/
++
++#define XX_IPC_MAX_ADDR_NAME_LENGTH 16         /**< Maximum length of an endpoint name string;
++                                                    The IPC service can use this constant to limit
++                                                    the storage space for IPC endpoint names. */
++
++
++/**************************************************************************//**
++ @Function      t_IpcMsgCompletion
++
++ @Description   Callback function used upon IPC non-blocking transaction completion
++                to return message buffer to the caller and to forward reply if available.
++
++                This callback function may be attached by the source endpoint to any outgoing
++                IPC message to indicate a non-blocking send (see also XX_IpcSendMessage() routine).
++                Upon completion of an IPC transaction (consisting of a message and an optional reply),
++                the IPC service invokes this callback routine to return the message buffer to the sender
++                and to provide the received reply, if requested.
++
++                User provides this function. Driver invokes it.
++
++ @Param[in]     h_Module        - Abstract handle to the sending module -  the same handle as was passed
++                                  in the XX_IpcSendMessage() function; This handle is typically used to point
++                                  to the internal data structure of the source endpoint.
++ @Param[in]     p_Msg           - Pointer to original (sent) message buffer;
++                                  The source endpoint can free (or reuse) this buffer when message
++                                  completion callback is called.
++ @Param[in]     p_Reply         - Pointer to (received) reply buffer;
++                                  This pointer is the same as was provided by the source endpoint in
++                                  XX_IpcSendMessage().
++ @Param[in]     replyLength     - Length (in bytes) of actual data in the reply buffer.
++ @Param[in]     status          - Completion status - E_OK or failure indication, e.g. IPC transaction completion
++                                  timeout.
++
++ @Return        None
++ *//***************************************************************************/
++typedef void    (t_IpcMsgCompletion)(t_Handle   h_Module,
++                                     uint8_t    *p_Msg,
++                                     uint8_t    *p_Reply,
++                                     uint32_t   replyLength,
++                                     t_Error    status);
++
++/**************************************************************************//**
++ @Function      t_IpcMsgHandler
++
++ @Description   Callback function used as IPC message handler.
++
++                The IPC service invokes message handlers for each IPC message received.
++                The actual function pointer should be registered by each destination endpoint
++                via the XX_IpcRegisterMsgHandler() routine.
++
++                User provides this function. Driver invokes it.
++
++ @Param[in]     h_Module        - Abstract handle to the message handling module -  the same handle as
++                                  was passed in the XX_IpcRegisterMsgHandler() function; this handle is
++                                  typically used to point to the internal data structure of the destination
++                                  endpoint.
++ @Param[in]     p_Msg           - Pointer to message buffer with data received from peer.
++ @Param[in]     msgLength       - Length (in bytes) of message data.
++ @Param[in]     p_Reply         - Pointer to reply buffer, to be filled by the message handler and then sent
++                                  by the IPC service;
++                                  The reply buffer is allocated by the IPC service with size equals to the
++                                  replyLength parameter provided in message handler registration (see
++                                  XX_IpcRegisterMsgHandler() function);
++                                  If replyLength was initially specified as zero during message handler registration,
++                                  the IPC service may set this pointer to NULL and assume that a reply is not needed;
++                                  The IPC service is also responsible for freeing the reply buffer after the
++                                  reply has been sent or dismissed.
++ @Param[in,out] p_ReplyLength   - Pointer to reply length, which has a dual role in this function:
++                                  [In] equals the replyLength parameter provided in message handler
++                                  registration (see XX_IpcRegisterMsgHandler() function), and
++                                  [Out] should be updated by message handler to the actual reply length; if
++                                  this value is set to zero, the IPC service must assume that a reply should
++                                  not be sent;
++                                  Note: If p_Reply is not NULL, p_ReplyLength must not be NULL as well.
++
++ @Return        E_OK on success; Error code otherwise.
++ *//***************************************************************************/
++typedef t_Error (t_IpcMsgHandler)(t_Handle  h_Module,
++                                  uint8_t   *p_Msg,
++                                  uint32_t  msgLength,
++                                  uint8_t   *p_Reply,
++                                  uint32_t  *p_ReplyLength);
++
++/**************************************************************************//**
++ @Function      XX_IpcRegisterMsgHandler
++
++ @Description   IPC mailbox registration.
++
++                This function is used for registering an IPC message handler in the IPC service.
++                This function is called by each destination endpoint to indicate that it is ready
++                to handle incoming messages. The IPC service invokes the message handler upon receiving
++                a message addressed to the specified destination endpoint.
++
++ @Param[in]     addr                - The address name string associated with the destination endpoint;
++                                      This address must be unique across the IPC service domain to ensure
++                                      correct message routing.
++ @Param[in]     f_MsgHandler        - Pointer to the message handler callback for processing incoming
++                                      message; invoked by the IPC service upon receiving a message
++                                      addressed to the destination endpoint specified by the addr
++                                      parameter.
++ @Param[in]     h_Module            - Abstract handle to the message handling module, passed unchanged
++                                      to f_MsgHandler callback function.
++ @Param[in]     replyLength         - The maximal data length (in bytes) of any reply that the specified message handler
++                                      may generate; the IPC service provides the message handler with buffer
++                                      for reply according to the length specified here (refer also to the description
++                                      of #t_IpcMsgHandler callback function type);
++                                      This size shall be zero if the message handler never generates replies.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error XX_IpcRegisterMsgHandler(char                   addr[XX_IPC_MAX_ADDR_NAME_LENGTH],
++                                 t_IpcMsgHandler        *f_MsgHandler,
++                                 t_Handle               h_Module,
++                                 uint32_t               replyLength);
++
++/**************************************************************************//**
++ @Function      XX_IpcUnregisterMsgHandler
++
++ @Description   Release IPC mailbox routine.
++
++                 This function is used for unregistering an IPC message handler from the IPC service.
++                 This function is called by each destination endpoint to indicate that it is no longer
++                 capable of handling incoming messages.
++
++ @Param[in]     addr          - The address name string associated with the destination endpoint;
++                                This address is the same as was used when the message handler was
++                                registered via XX_IpcRegisterMsgHandler().
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error XX_IpcUnregisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH]);
++
++/**************************************************************************//**
++ @Function      XX_IpcInitSession
++
++ @Description   This function is used for creating an IPC session between the source endpoint
++                and the destination endpoint.
++
++                The actual implementation and representation of a session is left for the IPC service.
++                The function returns an abstract handle to the created session. This handle shall be used
++                by the source endpoint in subsequent calls to XX_IpcSendMessage().
++                The IPC service assumes that before this function is called, no messages are sent from
++                the specified source endpoint to the specified destination endpoint.
++
++                The IPC service may use a connection-oriented approach or a connectionless approach (or both)
++                as described below.
++
++                @par Connection-Oriented Approach
++
++                The IPC service may implement a session in a connection-oriented approach -  when this function is called,
++                the IPC service should take the necessary steps to bring up a source-to-destination channel for messages
++                and a destination-to-source channel for replies. The returned handle should represent the internal
++                representation of these channels.
++
++                @par Connectionless Approach
++
++                The IPC service may implement a session in a connectionless approach -  when this function is called, the
++                IPC service should not perform any particular steps, but it must store the pair of source and destination
++                addresses in some session representation and return it as a handle. When XX_IpcSendMessage() shall be
++                called, the IPC service may use this handle to provide the necessary identifiers for routing the messages
++                through the connectionless medium.
++
++ @Param[in]     destAddr      - The address name string associated with the destination endpoint.
++ @Param[in]     srcAddr       - The address name string associated with the source endpoint.
++
++ @Return        Abstract handle to the initialized session, or NULL on error.
++*//***************************************************************************/
++t_Handle XX_IpcInitSession(char destAddr[XX_IPC_MAX_ADDR_NAME_LENGTH],
++                           char srcAddr[XX_IPC_MAX_ADDR_NAME_LENGTH]);
++
++/**************************************************************************//**
++ @Function      XX_IpcFreeSession
++
++ @Description   This function is used for terminating an existing IPC session between a source endpoint
++                and a destination endpoint.
++
++                The IPC service assumes that after this function is called, no messages shall be sent from
++                the associated source endpoint to the associated destination endpoint.
++
++ @Param[in]     h_Session      - Abstract handle to the IPC session -  the same handle as was originally
++                                 returned by the XX_IpcInitSession() function.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error XX_IpcFreeSession(t_Handle h_Session);
++
++/**************************************************************************//**
++ @Function      XX_IpcSendMessage
++
++ @Description   IPC message send routine.
++
++                This function may be used by a source endpoint to send an IPC message to a destination
++                endpoint. The source endpoint cannot send a message to the destination endpoint without
++                first initiating a session with that destination endpoint via XX_IpcInitSession() routine.
++
++                The source endpoint must provide the buffer pointer and length of the outgoing message.
++                Optionally, it may also provide a buffer for an expected reply. In the latter case, the
++                transaction is not considered complete by the IPC service until the reply has been received.
++                If the source endpoint does not provide a reply buffer, the transaction is considered
++                complete after the message has been sent. The source endpoint must keep the message (and
++                optional reply) buffers valid until the transaction is complete.
++
++                @par Non-blocking mode
++
++                The source endpoint may request a non-blocking send by providing a non-NULL pointer to a message
++                completion callback function (f_Completion). Upon completion of the IPC transaction (consisting of a
++                message and an optional reply), the IPC service invokes this callback routine to return the message
++                buffer to the sender and to provide the received reply, if requested.
++
++                @par Blocking mode
++
++                The source endpoint may request a blocking send by setting f_Completion to NULL. The function is
++                expected to block until the IPC transaction is complete -  either the reply has been received or (if no reply
++                was requested) the message has been sent.
++
++ @Param[in]     h_Session       - Abstract handle to the IPC session -  the same handle as was originally
++                                  returned by the XX_IpcInitSession() function.
++ @Param[in]     p_Msg           - Pointer to message buffer to send.
++ @Param[in]     msgLength       - Length (in bytes) of actual data in the message buffer.
++ @Param[in]     p_Reply         - Pointer to reply buffer -  if this buffer is not NULL, the IPC service
++                                  fills this buffer with the received reply data;
++                                  In blocking mode, the reply data must be valid when the function returns;
++                                  In non-blocking mode, the reply data is valid when f_Completion is called;
++                                  If this pointer is NULL, no reply is expected.
++ @Param[in,out] p_ReplyLength   - Pointer to reply length, which has a dual role in this function:
++                                  [In] specifies the maximal length (in bytes) of the reply buffer pointed by
++                                  p_Reply, and
++                                  [Out] in non-blocking mode this value is updated by the IPC service to the
++                                  actual reply length (in bytes).
++ @Param[in]     f_Completion    - Pointer to a completion callback to be used in non-blocking send mode;
++                                  The completion callback is invoked by the IPC service upon
++                                  completion of the IPC transaction (consisting of a message and an optional
++                                  reply);
++                                  If this pointer is NULL, the function is expected to block until the IPC
++                                  transaction is complete.
++ @Param[in]     h_Arg           - Abstract handle to the sending module; passed unchanged to the f_Completion
++                                  callback function as the first argument.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error XX_IpcSendMessage(t_Handle           h_Session,
++                          uint8_t            *p_Msg,
++                          uint32_t           msgLength,
++                          uint8_t            *p_Reply,
++                          uint32_t           *p_ReplyLength,
++                          t_IpcMsgCompletion *f_Completion,
++                          t_Handle           h_Arg);
++
++
++/** @} */ /* end of xx_ipc group */
++/** @} */ /* end of xx_id group */
++
++
++#endif /* __XX_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/ls1043_dflags.h
+@@ -0,0 +1,56 @@
++/*
++ * Copyright 2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __dflags_h
++#define __dflags_h
++
++
++#define NCSW_LINUX
++
++#define LS1043
++
++#define DEBUG_ERRORS        1
++
++#if defined(DEBUG)
++#define DEBUG_GLOBAL_LEVEL  REPORT_LEVEL_INFO
++
++#define DEBUG_XX_MALLOC
++#define DEBUG_MEM_LEAKS
++
++#else
++#define DEBUG_GLOBAL_LEVEL  REPORT_LEVEL_WARNING
++#endif /* (DEBUG) */
++
++#define REPORT_EVENTS       1
++#define EVENT_GLOBAL_LEVEL  REPORT_LEVEL_MINOR
++
++#endif /* __dflags_h */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+@@ -0,0 +1,53 @@
++#
++# Makefile config for the Freescale NetcommSW
++#
++NET_DPA     = $(srctree)/drivers/net
++DRV_DPA     = $(srctree)/drivers/net/ethernet/freescale/sdk_dpaa
++FMAN        = $(srctree)/drivers/net/ethernet/freescale/sdk_fman
++
++ifeq ("$(CONFIG_FMAN_P3040_P4080_P5020)", "y")
++ccflags-y +=-include $(FMAN)/p3040_4080_5020_dflags.h
++endif
++ifeq ("$(CONFIG_FMAN_P1023)", "y")
++ccflags-y +=-include $(FMAN)/p1023_dflags.h
++endif
++ifdef CONFIG_FMAN_V3H
++ccflags-y +=-include $(FMAN)/fmanv3h_dflags.h
++endif
++ifdef CONFIG_FMAN_V3L
++ccflags-y +=-include $(FMAN)/fmanv3l_dflags.h
++endif
++ifdef CONFIG_FMAN_ARM
++ccflags-y +=-include $(FMAN)/ls1043_dflags.h
++endif
++
++ccflags-y += -I$(DRV_DPA)/
++ccflags-y += -I$(FMAN)/inc
++ccflags-y += -I$(FMAN)/inc/cores
++ccflags-y += -I$(FMAN)/inc/etc
++ccflags-y += -I$(FMAN)/inc/Peripherals
++ccflags-y += -I$(FMAN)/inc/flib
++
++ifeq ("$(CONFIG_FMAN_P3040_P4080_P5020)", "y")
++ccflags-y += -I$(FMAN)/inc/integrations/P3040_P4080_P5020
++endif
++ifeq ("$(CONFIG_FMAN_P1023)", "y")
++ccflags-y += -I$(FMAN)/inc/integrations/P1023
++endif
++ifdef CONFIG_FMAN_V3H
++ccflags-y += -I$(FMAN)/inc/integrations/FMANV3H
++endif
++ifdef CONFIG_FMAN_V3L
++ccflags-y += -I$(FMAN)/inc/integrations/FMANV3L
++endif
++ifdef CONFIG_FMAN_ARM
++ccflags-y += -I$(FMAN)/inc/integrations/LS1043
++endif
++
++ccflags-y += -I$(FMAN)/src/inc
++ccflags-y += -I$(FMAN)/src/inc/system
++ccflags-y += -I$(FMAN)/src/inc/wrapper
++ccflags-y += -I$(FMAN)/src/inc/xx
++ccflags-y += -I$(srctree)/include/uapi/linux/fmd
++ccflags-y += -I$(srctree)/include/uapi/linux/fmd/Peripherals
++ccflags-y += -I$(srctree)/include/uapi/linux/fmd/integrations
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/p1023_dflags.h
+@@ -0,0 +1,65 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __dflags_h
++#define __dflags_h
++
++
++#define NCSW_LINUX
++#if 0
++#define DEBUG
++#endif
++
++#define P1023
++#define NCSW_PPC_CORE
++
++#define DEBUG_ERRORS        1
++
++#if defined(DEBUG)
++#define DEBUG_GLOBAL_LEVEL  REPORT_LEVEL_INFO
++
++#define DEBUG_XX_MALLOC
++#define DEBUG_MEM_LEAKS
++
++#else
++#define DEBUG_GLOBAL_LEVEL  REPORT_LEVEL_WARNING
++#endif /* (DEBUG) */
++
++#define REPORT_EVENTS       1
++#define EVENT_GLOBAL_LEVEL  REPORT_LEVEL_MINOR
++
++#ifdef CONFIG_P4080_SIM
++#error "Do not define CONFIG_P4080_SIM..."
++#endif
++
++
++#endif /* __dflags_h */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/p3040_4080_5020_dflags.h
+@@ -0,0 +1,62 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __dflags_h
++#define __dflags_h
++
++
++#define NCSW_LINUX
++
++#define P4080
++#define NCSW_PPC_CORE
++
++#define DEBUG_ERRORS        1
++
++#if defined(DEBUG)
++#define DEBUG_GLOBAL_LEVEL  REPORT_LEVEL_INFO
++
++#define DEBUG_XX_MALLOC
++#define DEBUG_MEM_LEAKS
++
++#else
++#define DEBUG_GLOBAL_LEVEL  REPORT_LEVEL_WARNING
++#endif /* (DEBUG) */
++
++#define REPORT_EVENTS       1
++#define EVENT_GLOBAL_LEVEL  REPORT_LEVEL_MINOR
++
++#ifdef CONFIG_P4080_SIM
++#define SIMULATOR
++#endif /* CONFIG_P4080_SIM */
++
++
++#endif /* __dflags_h */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/Makefile
+@@ -0,0 +1,11 @@
++#
++# Makefile for the Freescale Ethernet controllers
++#
++ccflags-y           += -DVERSION=\"\"
++#
++#Include netcomm SW specific definitions
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++#
++obj-y         += system/
++obj-y         += wrapper/
++obj-y         += xx/
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_ext.h
+@@ -0,0 +1,118 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __SYS_EXT_H
++#define __SYS_EXT_H
++
++#include "std_ext.h"
++
++
++/**************************************************************************//**
++ @Group         sys_grp     System Interfaces
++
++ @Description   Linux system programming interfaces.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         sys_gen_grp     System General Interface
++
++ @Description   General definitions, structures and routines of the linux
++                system programming interface.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Collection    Macros for Advanced Configuration Requests
++ @{
++*//***************************************************************************/
++#define SYS_MAX_ADV_CONFIG_ARGS     4
++                                    /**< Maximum number of arguments in
++                                         an advanced configuration entry */
++/* @} */
++
++/**************************************************************************//**
++ @Description   System Object Advanced Configuration Entry
++
++                This structure represents a single request for an advanced
++                configuration call on the initialized object. An array of such
++                requests may be contained in the settings structure of the
++                corresponding object.
++
++                The maximum number of arguments is limited to #SYS_MAX_ADV_CONFIG_ARGS.
++*//***************************************************************************/
++typedef struct t_SysObjectAdvConfigEntry
++{
++    void        *p_Function;    /**< Pointer to advanced configuration routine */
++
++    uintptr_t    args[SYS_MAX_ADV_CONFIG_ARGS];
++                                /**< Array of arguments for the specified routine;
++                                     All arguments should be casted to uint32_t. */
++} t_SysObjectAdvConfigEntry;
++
++
++/** @} */ /* end of sys_gen_grp */
++/** @} */ /* end of sys_grp */
++
++#define NCSW_PARAMS(_num, _params)   ADV_CONFIG_PARAMS_##_num _params
++
++#define ADV_CONFIG_PARAMS_1(_type) \
++    , (_type)p_Entry->args[0]
++
++#define SET_ADV_CONFIG_ARGS_1(_arg0)        \
++    p_Entry->args[0] = (uintptr_t )(_arg0);   \
++
++#define ARGS(_num, _params) SET_ADV_CONFIG_ARGS_##_num _params
++
++#define ADD_ADV_CONFIG_START(_p_Entries, _maxEntries)           \
++    {                                                           \
++        t_SysObjectAdvConfigEntry   *p_Entry;                   \
++        t_SysObjectAdvConfigEntry   *p_Entrys = (_p_Entries);   \
++        int                         i=0, max = (_maxEntries);   \
++
++#define ADD_ADV_CONFIG_END \
++    }
++
++#define ADV_CONFIG_CHECK_START(_p_Entry)                        \
++    {                                                           \
++        t_SysObjectAdvConfigEntry   *p_Entry = _p_Entry;        \
++        t_Error                     errCode;                    \
++
++#define ADV_CONFIG_CHECK(_handle, _func, _params)               \
++        if (p_Entry->p_Function == _func)                       \
++        {                                                       \
++            errCode = _func(_handle _params);                   \
++        } else
++
++#endif /* __SYS_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_io_ext.h
+@@ -0,0 +1,46 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __SYS_IO_EXT_H
++#define __SYS_IO_EXT_H
++
++#include "std_ext.h"
++#include "error_ext.h"
++
++
++t_Error  SYS_RegisterIoMap   (uint64_t virtAddr, uint64_t physAddr, uint32_t size);
++t_Error  SYS_UnregisterIoMap (uint64_t virtAddr);
++uint64_t SYS_PhysToVirt      (uint64_t addr);
++uint64_t SYS_VirtToPhys      (uint64_t addr);
++
++
++#endif /* __SYS_IO_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/types_linux.h
+@@ -0,0 +1,208 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __TYPES_LINUX_H__
++#define __TYPES_LINUX_H__
++
++#include <linux/version.h>
++
++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
++#define MODVERSIONS
++#endif
++#ifdef MODVERSIONS
++#include <config/modversions.h>
++#endif /* MODVERSIONS */
++
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <asm/io.h>
++#include <linux/delay.h>
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
++    #error "This kernel is probably not supported!!!"
++#elif   (!((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) || \
++           (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)) || \
++           (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,30))))
++    #warning "This kernel is probably not supported!!! You may need to add some fixes."
++#endif    /* LINUX_VERSION_CODE */
++
++
++typedef float               float_t;    /* Single precision floating point  */
++typedef double              double_t;   /* Double precision floating point  */
++
++
++#define _Packed
++#define _PackedType __attribute__ ((packed))
++
++typedef  phys_addr_t physAddress_t;
++
++#define UINT8_MAX   0xFF
++#define UINT8_MIN   0
++#define UINT16_MAX  0xFFFF
++#define UINT16_MIN  0
++#define UINT32_MAX  0xFFFFFFFF
++#define UINT32_MIN  0
++#define UINT64_MAX  0xFFFFFFFFFFFFFFFFLL
++#define UINT64_MIN  0
++#define INT8_MAX    0x7F
++#define INT8_MIN    0x80
++#define INT16_MAX   0x7FFF
++#define INT16_MIN   0x8000
++#define INT32_MAX   0x7FFFFFFF
++#define INT32_MIN   0x80000000
++#define INT64_MAX   0x7FFFFFFFFFFFFFFFLL
++#define INT64_MIN   0x8000000000000000LL
++
++#define ON          1
++#define OFF         0
++
++#define FALSE       false
++#define TRUE        true
++
++
++/************************/
++/* memory access macros */
++/************************/
++#ifdef CONFIG_FMAN_ARM
++#define in_be16(a)            __be16_to_cpu(__raw_readw(a))
++#define in_be32(a)            __be32_to_cpu(__raw_readl(a))
++#define out_be16(a, v)                __raw_writew(__cpu_to_be16(v), a)
++#define out_be32(a, v)                __raw_writel(__cpu_to_be32(v), a)
++#endif
++
++#define GET_UINT8(arg)              *(volatile uint8_t *)(&(arg))
++#define GET_UINT16(arg)             in_be16(&(arg))//*(volatile uint16_t*)(&(arg))
++#define GET_UINT32(arg)             in_be32(&(arg))//*(volatile uint32_t*)(&(arg))
++#define GET_UINT64(arg)             *(volatile uint64_t*)(&(arg))
++
++#ifdef VERBOSE_WRITE
++void    XX_Print(char *str, ...);
++#define WRITE_UINT8(arg, data)  \
++    do { XX_Print("ADDR: 0x%08x, VAL: 0x%02x\r\n",    (uint32_t)&(arg), (data)); *(volatile uint8_t *)(&(arg)) = (data); } while (0)
++#define WRITE_UINT16(arg, data) \
++    do { XX_Print("ADDR: 0x%08x, VAL: 0x%04x\r\n",    (uint32_t)&(arg), (data)); out_be16(&(arg), data); /* *(volatile uint16_t*)(&(arg)) = (data);*/ } while (0)
++#define WRITE_UINT32(arg, data) \
++    do { XX_Print("ADDR: 0x%08x, VAL: 0x%08x\r\n",    (uint32_t)&(arg), (data)); out_be32(&(arg), data); /* *(volatile uint32_t*)(&(arg)) = (data);*/ } while (0)
++#define WRITE_UINT64(arg, data) \
++    do { XX_Print("ADDR: 0x%08x, VAL: 0x%016llx\r\n", (uint32_t)&(arg), (data)); *(volatile uint64_t*)(&(arg)) = (data); } while (0)
++
++#else  /* not VERBOSE_WRITE */
++#define WRITE_UINT8(arg, data)      *(volatile uint8_t *)(&(arg)) = (data)
++#define WRITE_UINT16(arg, data)     out_be16(&(arg), data)//*(volatile uint16_t*)(&(arg)) = (data)
++#define WRITE_UINT32(arg, data)     out_be32(&(arg), data)//*(volatile unsigned int *)(&(arg)) = (data)
++#define WRITE_UINT64(arg, data)     *(volatile uint64_t*)(&(arg)) = (data)
++#endif /* not VERBOSE_WRITE */
++
++
++/*****************************************************************************/
++/*                      General stuff                                        */
++/*****************************************************************************/
++#ifdef ARRAY_SIZE
++#undef ARRAY_SIZE
++#endif /* ARRAY_SIZE */
++
++#ifdef MAJOR
++#undef MAJOR
++#endif /* MAJOR */
++
++#ifdef MINOR
++#undef MINOR
++#endif /* MINOR */
++
++#ifdef QE_SIZEOF_BD
++#undef QE_SIZEOF_BD
++#endif /* QE_SIZEOF_BD */
++
++#ifdef BD_BUFFER_CLEAR
++#undef BD_BUFFER_CLEAR
++#endif /* BD_BUFFER_CLEAR */
++
++#ifdef BD_BUFFER
++#undef BD_BUFFER
++#endif /* BD_BUFFER */
++
++#ifdef BD_STATUS_AND_LENGTH_SET
++#undef BD_STATUS_AND_LENGTH_SET
++#endif /* BD_STATUS_AND_LENGTH_SET */
++
++#ifdef BD_STATUS_AND_LENGTH
++#undef BD_STATUS_AND_LENGTH
++#endif /* BD_STATUS_AND_LENGTH */
++
++#ifdef BD_BUFFER_ARG
++#undef BD_BUFFER_ARG
++#endif /* BD_BUFFER_ARG */
++
++#ifdef BD_GET_NEXT
++#undef BD_GET_NEXT
++#endif /* BD_GET_NEXT */
++
++#ifdef QE_SDEBCR_BA_MASK
++#undef QE_SDEBCR_BA_MASK
++#endif /* QE_SDEBCR_BA_MASK */
++
++#ifdef BD_BUFFER_SET
++#undef BD_BUFFER_SET
++#endif /* BD_BUFFER_SET */
++
++#ifdef UPGCR_PROTOCOL
++#undef UPGCR_PROTOCOL
++#endif /* UPGCR_PROTOCOL */
++
++#ifdef UPGCR_TMS
++#undef UPGCR_TMS
++#endif /* UPGCR_TMS */
++
++#ifdef UPGCR_RMS
++#undef UPGCR_RMS
++#endif /* UPGCR_RMS */
++
++#ifdef UPGCR_ADDR
++#undef UPGCR_ADDR
++#endif /* UPGCR_ADDR */
++
++#ifdef UPGCR_DIAG
++#undef UPGCR_DIAG
++#endif /* UPGCR_DIAG */
++
++#ifdef NCSW_PARAMS
++#undef NCSW_PARAMS
++#endif /* NCSW_PARAMS */
++
++#ifdef NO_IRQ
++#undef NO_IRQ
++#endif /* NO_IRQ */
++
++#define PRINT_LINE   XX_Print("%s:\n %s [%d]\n",__FILE__,__FUNCTION__,__LINE__);
++
++
++#endif /* __TYPES_LINUX_H__ */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/fsl_fman_test.h
+@@ -0,0 +1,84 @@
++/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/******************************************************************************
++ @File          fsl_fman_test.h
++
++ @Description
++*//***************************************************************************/
++
++#ifndef __FSL_FMAN_TEST_H
++#define __FSL_FMAN_TEST_H
++
++#include <linux/types.h>
++#include <linux/smp.h>  /* raw_smp_processor_id() */
++
++//#define FMT_K_DBG
++//#define FMT_K_DBG_RUNTIME
++
++#define _fmt_prk(stage, format, arg...)       \
++      printk(stage "fmt (cpu:%u): " format, raw_smp_processor_id(), ##arg)
++
++#define _fmt_inf(format, arg...) _fmt_prk(KERN_INFO, format, ##arg)
++#define _fmt_wrn(format, arg...) _fmt_prk(KERN_WARNING, format, ##arg)
++#define _fmt_err(format, arg...) _fmt_prk(KERN_ERR, format, ##arg)
++
++/* there are two macros for debugging: for runtime and generic.
++ * Helps when the runtime functions are not targeted for debugging,
++ * thus all the unnecessary information will be skipped.
++ */
++/* used for generic debugging */
++#if defined(FMT_K_DBG)
++      #define _fmt_dbg(format, arg...) \
++              printk("fmt [%s:%u](cpu:%u) - " format, \
++                      __func__, __LINE__, raw_smp_processor_id(), ##arg)
++#else
++#     define _fmt_dbg(arg...)
++#endif
++
++/* used for debugging runtime functions */
++#if defined(FMT_K_DBG_RUNTIME)
++      #define _fmt_dbgr(format, arg...) \
++              printk("fmt [%s:%u](cpu:%u) - " format, \
++                      __func__, __LINE__, raw_smp_processor_id(), ##arg)
++#else
++#     define _fmt_dbgr(arg...)
++#endif
++
++#define FMT_RX_ERR_Q    0xffffffff
++#define FMT_RX_DFLT_Q   0xfffffffe
++#define FMT_TX_ERR_Q    0xfffffffd
++#define FMT_TX_CONF_Q   0xfffffffc
++
++#define FMAN_TEST_MAX_TX_FQS 8
++
++#endif /* __FSL_FMAN_TEST_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_exp_sym.h
+@@ -0,0 +1,128 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ @File          lnxwrp_exp_sym.h
++ @Description   FMan exported routines
++*/
++
++#ifndef __LNXWRP_EXP_SYM_H
++#define __LNXWRP_EXP_SYM_H
++
++#include "fm_port_ext.h"
++#include "fm_pcd_ext.h"
++#include "fm_mac_ext.h"
++
++
++/* FMAN Port exported routines */
++EXPORT_SYMBOL(FM_PORT_Disable);
++EXPORT_SYMBOL(FM_PORT_Enable);
++EXPORT_SYMBOL(FM_PORT_SetPCD);
++EXPORT_SYMBOL(FM_PORT_DeletePCD);
++
++/* Runtime PCD exported routines */
++EXPORT_SYMBOL(FM_PCD_Enable);
++EXPORT_SYMBOL(FM_PCD_Disable);
++EXPORT_SYMBOL(FM_PCD_GetCounter);
++EXPORT_SYMBOL(FM_PCD_PrsLoadSw);
++EXPORT_SYMBOL(FM_PCD_KgSetDfltValue);
++EXPORT_SYMBOL(FM_PCD_KgSetAdditionalDataAfterParsing);
++EXPORT_SYMBOL(FM_PCD_SetException);
++EXPORT_SYMBOL(FM_PCD_ModifyCounter);
++EXPORT_SYMBOL(FM_PCD_SetPlcrStatistics);
++EXPORT_SYMBOL(FM_PCD_SetPrsStatistics);
++EXPORT_SYMBOL(FM_PCD_ForceIntr);
++EXPORT_SYMBOL(FM_PCD_HcTxConf);
++
++EXPORT_SYMBOL(FM_PCD_NetEnvCharacteristicsSet);
++EXPORT_SYMBOL(FM_PCD_NetEnvCharacteristicsDelete);
++EXPORT_SYMBOL(FM_PCD_KgSchemeSet);
++EXPORT_SYMBOL(FM_PCD_KgSchemeDelete);
++EXPORT_SYMBOL(FM_PCD_KgSchemeGetCounter);
++EXPORT_SYMBOL(FM_PCD_KgSchemeSetCounter);
++EXPORT_SYMBOL(FM_PCD_CcRootBuild);
++EXPORT_SYMBOL(FM_PCD_CcRootDelete);
++EXPORT_SYMBOL(FM_PCD_MatchTableSet);
++EXPORT_SYMBOL(FM_PCD_MatchTableDelete);
++EXPORT_SYMBOL(FM_PCD_CcRootModifyNextEngine);
++EXPORT_SYMBOL(FM_PCD_MatchTableModifyNextEngine);
++EXPORT_SYMBOL(FM_PCD_MatchTableFindNModifyNextEngine);
++EXPORT_SYMBOL(FM_PCD_MatchTableModifyMissNextEngine);
++EXPORT_SYMBOL(FM_PCD_MatchTableRemoveKey);
++EXPORT_SYMBOL(FM_PCD_MatchTableFindNRemoveKey);
++EXPORT_SYMBOL(FM_PCD_MatchTableAddKey);
++EXPORT_SYMBOL(FM_PCD_MatchTableModifyKeyAndNextEngine);
++EXPORT_SYMBOL(FM_PCD_MatchTableFindNModifyKeyAndNextEngine);
++EXPORT_SYMBOL(FM_PCD_MatchTableModifyKey);
++EXPORT_SYMBOL(FM_PCD_MatchTableFindNModifyKey);
++EXPORT_SYMBOL(FM_PCD_MatchTableGetIndexedHashBucket);
++EXPORT_SYMBOL(FM_PCD_MatchTableGetNextEngine);
++EXPORT_SYMBOL(FM_PCD_MatchTableGetKeyCounter);
++EXPORT_SYMBOL(FM_PCD_MatchTableGetKeyStatistics);
++EXPORT_SYMBOL(FM_PCD_MatchTableFindNGetKeyStatistics);
++EXPORT_SYMBOL(FM_PCD_MatchTableGetMissStatistics);
++EXPORT_SYMBOL(FM_PCD_HashTableGetMissStatistics);
++EXPORT_SYMBOL(FM_PCD_HashTableSet);
++EXPORT_SYMBOL(FM_PCD_HashTableDelete);
++EXPORT_SYMBOL(FM_PCD_HashTableAddKey);
++EXPORT_SYMBOL(FM_PCD_HashTableRemoveKey);
++EXPORT_SYMBOL(FM_PCD_HashTableModifyNextEngine);
++EXPORT_SYMBOL(FM_PCD_HashTableModifyMissNextEngine);
++EXPORT_SYMBOL(FM_PCD_HashTableGetMissNextEngine);
++EXPORT_SYMBOL(FM_PCD_HashTableFindNGetKeyStatistics);
++EXPORT_SYMBOL(FM_PCD_PlcrProfileSet);
++EXPORT_SYMBOL(FM_PCD_PlcrProfileDelete);
++EXPORT_SYMBOL(FM_PCD_PlcrProfileGetCounter);
++EXPORT_SYMBOL(FM_PCD_PlcrProfileSetCounter);
++EXPORT_SYMBOL(FM_PCD_ManipNodeSet);
++EXPORT_SYMBOL(FM_PCD_ManipNodeDelete);
++EXPORT_SYMBOL(FM_PCD_ManipGetStatistics);
++EXPORT_SYMBOL(FM_PCD_ManipNodeReplace);
++#if (DPAA_VERSION >= 11)
++EXPORT_SYMBOL(FM_PCD_FrmReplicSetGroup);
++EXPORT_SYMBOL(FM_PCD_FrmReplicDeleteGroup);
++EXPORT_SYMBOL(FM_PCD_FrmReplicAddMember);
++EXPORT_SYMBOL(FM_PCD_FrmReplicRemoveMember);
++#endif /* DPAA_VERSION >= 11 */
++
++#ifdef FM_CAPWAP_SUPPORT
++EXPORT_SYMBOL(FM_PCD_StatisticsSetNode);
++#endif /* FM_CAPWAP_SUPPORT */
++
++EXPORT_SYMBOL(FM_PCD_SetAdvancedOffloadSupport);
++
++/* FMAN MAC exported routines */
++EXPORT_SYMBOL(FM_MAC_GetStatistics);
++
++EXPORT_SYMBOL(FM_GetSpecialOperationCoding);
++
++#endif /* __LNXWRP_EXP_SYM_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fm_ext.h
+@@ -0,0 +1,163 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/******************************************************************************
++ @File          lnxwrp_fm_ext.h
++
++ @Description   TODO
++*//***************************************************************************/
++
++#ifndef __LNXWRP_FM_EXT_H
++#define __LNXWRP_FM_EXT_H
++
++#include "std_ext.h"
++#include "sys_ext.h"
++#include "fm_ext.h"
++#include "fm_muram_ext.h"
++#include "fm_pcd_ext.h"
++#include "fm_port_ext.h"
++#include "fm_mac_ext.h"
++#include "fm_rtc_ext.h"
++
++
++/**************************************************************************//**
++ @Group         FM_LnxKern_grp Frame Manager Linux wrapper API
++
++ @Description   FM API functions, definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         FM_LnxKern_init_grp Initialization Unit
++
++ @Description   Initialization Unit
++
++                Initialization Flow:
++                Initialization of the FM Module will be carried out by the Linux
++                kernel according to the following sequence:
++                a. Calling the initialization routine with no parameters.
++                b. The driver will register to the Device-Tree.
++                c. The Linux Device-Tree will initiate a call to the driver for
++                   initialization.
++                d. The driver will read the appropriate information from the Device-Tree
++                e. [Optional] Calling the advance initialization routines to change
++                   driver's defaults.
++                f. Initialization of the device will be automatically upon using it.
++
++ @{
++*//***************************************************************************/
++
++typedef struct t_WrpFmDevSettings
++{
++    t_FmParams                  param;
++    t_SysObjectAdvConfigEntry   *advConfig;
++} t_WrpFmDevSettings;
++
++typedef struct t_WrpFmPcdDevSettings
++{
++    t_FmPcdParams               param;
++    t_SysObjectAdvConfigEntry   *advConfig;
++} t_WrpFmPcdDevSettings;
++
++typedef struct t_WrpFmPortDevSettings
++{
++    bool                        frag_enabled;
++    t_FmPortParams              param;
++    t_SysObjectAdvConfigEntry   *advConfig;
++} t_WrpFmPortDevSettings;
++
++typedef struct t_WrpFmMacDevSettings
++{
++    t_FmMacParams               param;
++    t_SysObjectAdvConfigEntry   *advConfig;
++} t_WrpFmMacDevSettings;
++
++
++/**************************************************************************//**
++ @Function      LNXWRP_FM_Init
++
++ @Description   Initialize the FM linux wrapper.
++
++ @Return        A handle (descriptor) of the newly created FM Linux wrapper
++                structure.
++*//***************************************************************************/
++t_Handle LNXWRP_FM_Init(void);
++
++/**************************************************************************//**
++ @Function      LNXWRP_FM_Free
++
++ @Description   Free the FM linux wrapper.
++
++ @Param[in]     h_LnxWrpFm   - A handle to the FM linux wrapper.
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++t_Error  LNXWRP_FM_Free(t_Handle h_LnxWrpFm);
++
++/**************************************************************************//**
++ @Function      LNXWRP_FM_GetMacHandle
++
++ @Description   Get the FM-MAC LLD handle from the FM linux wrapper.
++
++ @Param[in]     h_LnxWrpFm   - A handle to the FM linux wrapper.
++ @Param[in]     fmId         - Index of the FM device to get the MAC handle from.
++ @Param[in]     macId        - Index of the mac handle.
++
++ @Return        A handle of the LLD compressor.
++*//***************************************************************************/
++t_Handle LNXWRP_FM_GetMacHandle(t_Handle h_LnxWrpFm, uint8_t fmId, uint8_t macId);
++
++#ifdef CONFIG_FSL_SDK_FMAN_TEST
++t_Handle LNXWRP_FM_TEST_Init(void);
++t_Error  LNXWRP_FM_TEST_Free(t_Handle h_FmTestLnxWrp);
++#endif /* CONFIG_FSL_SDK_FMAN_TEST */
++
++/** @} */ /* end of FM_LnxKern_init_grp group */
++
++
++/**************************************************************************//**
++ @Group         FM_LnxKern_ctrl_grp Control Unit
++
++ @Description   Control Unit
++
++                TODO
++ @{
++*//***************************************************************************/
++
++#include "lnxwrp_fsl_fman.h"
++
++/** @} */ /* end of FM_LnxKern_ctrl_grp group */
++/** @} */ /* end of FM_LnxKern_grp group */
++
++
++#endif /* __LNXWRP_FM_EXT_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h
+@@ -0,0 +1,921 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/******************************************************************************
++ @File                lnxwrp_fsl_fman.h
++
++ @Description Linux internal kernel API
++*//***************************************************************************/
++
++#ifndef __LNXWRP_FSL_FMAN_H
++#define __LNXWRP_FSL_FMAN_H
++
++#include <linux/types.h>
++#include <linux/device.h>   /* struct device */
++#include <linux/fsl_qman.h> /* struct qman_fq */
++#include "dpaa_integration_ext.h"
++#include "fm_port_ext.h"
++#include "fm_mac_ext.h"
++#include "fm_macsec_ext.h"
++#include "fm_rtc_ext.h"
++
++/**************************************************************************//**
++ @Group               FM_LnxKern_grp Frame Manager Linux wrapper API
++
++ @Description FM API functions, definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group               FM_LnxKern_ctrl_grp Control Unit
++
++ @Description Control Unit
++
++              Internal Kernel Control Unit API
++ @{
++*//***************************************************************************/
++
++/*****************************************************************************/
++/*                  Internal Linux kernel routines                           */
++/*****************************************************************************/
++
++/**************************************************************************//**
++ @Description   MACSEC Exceptions wrapper
++*//***************************************************************************/
++typedef enum fm_macsec_exception {
++      SINGLE_BIT_ECC = e_FM_MACSEC_EX_SINGLE_BIT_ECC,
++      MULTI_BIT_ECC = e_FM_MACSEC_EX_MULTI_BIT_ECC
++} fm_macsec_exception;
++
++/**************************************************************************//**
++ @Description   Unknown sci frame treatment wrapper
++*//***************************************************************************/
++typedef enum fm_macsec_unknown_sci_frame_treatment {
++      SCI_DISCARD_BOTH = e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_BOTH,
++      SCI_DISCARD_UNCTRL_DELIVER_DISCARD_CTRL = \
++              e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_UNCONTROLLED_DELIVER_OR_DISCARD_CONTROLLED,
++      SCI_DELIVER_UNCTRL_DISCARD_CTRL = \
++              e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED,
++      SCI_DELIVER_DISCARD_UNCTRL_DELIVER_DISCARD_CTRL = \
++              e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DELIVER_OR_DISCARD_UNCONTROLLED_DELIVER_OR_DISCARD_CONTROLLED
++} fm_macsec_unknown_sci_frame_treatment;
++
++/**************************************************************************//**
++ @Description   Untag frame treatment wrapper
++*//***************************************************************************/
++typedef enum fm_macsec_untag_frame_treatment {
++      UNTAG_DELIVER_UNCTRL_DISCARD_CTRL = \
++              e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED,
++      UNTAG_DISCARD_BOTH = e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DISCARD_BOTH,
++      UNTAG_DISCARD_UNCTRL_DELIVER_CTRL_UNMODIFIED = \
++              e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DISCARD_UNCONTROLLED_DELIVER_CONTROLLED_UNMODIFIED
++} fm_macsec_untag_frame_treatment;
++
++/**************************************************************************//**
++@Description   MACSEC SECY Cipher Suite wrapper
++*//***************************************************************************/
++typedef enum fm_macsec_secy_cipher_suite {
++      SECY_GCM_AES_128 = e_FM_MACSEC_SECY_GCM_AES_128,    /**< GCM-AES-128 */
++#if (DPAA_VERSION >= 11)
++      SECY_GCM_AES_256 = e_FM_MACSEC_SECY_GCM_AES_256     /**< GCM-AES-256 */
++#endif /* (DPAA_VERSION >= 11) */
++} fm_macsec_secy_cipher_suite;
++
++/**************************************************************************//**
++ @Description   MACSEC SECY Exceptions wrapper
++*//***************************************************************************/
++typedef enum fm_macsec_secy_exception {
++      SECY_EX_FRAME_DISCARDED = e_FM_MACSEC_SECY_EX_FRAME_DISCARDED
++} fm_macsec_secy_exception;
++
++/**************************************************************************//**
++ @Description   MACSEC SECY Events wrapper
++*//***************************************************************************/
++typedef enum fm_macsec_secy_event {
++      SECY_EV_NEXT_PN = e_FM_MACSEC_SECY_EV_NEXT_PN
++} fm_macsec_secy_event;
++
++/**************************************************************************//**
++ @Description   Valid frame behaviors wrapper
++*//***************************************************************************/
++typedef enum fm_macsec_valid_frame_behavior {
++      VALID_FRAME_BEHAVIOR_DISABLE = e_FM_MACSEC_VALID_FRAME_BEHAVIOR_DISABLE,
++      VALID_FRAME_BEHAVIOR_CHECK = e_FM_MACSEC_VALID_FRAME_BEHAVIOR_CHECK,
++      VALID_FRAME_BEHAVIOR_STRICT = e_FM_MACSEC_VALID_FRAME_BEHAVIOR_STRICT
++} fm_macsec_valid_frame_behavior;
++
++/**************************************************************************//**
++ @Description   SCI insertion modes wrapper
++*//***************************************************************************/
++typedef enum fm_macsec_sci_insertion_mode {
++      SCI_INSERTION_MODE_EXPLICIT_SECTAG = \
++              e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_SECTAG,
++      SCI_INSERTION_MODE_EXPLICIT_MAC_SA = \
++              e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_MAC_SA,
++      SCI_INSERTION_MODE_IMPLICT_PTP = e_FM_MACSEC_SCI_INSERTION_MODE_IMPLICT_PTP
++} fm_macsec_sci_insertion_mode;
++
++typedef macsecSAKey_t macsec_sa_key_t;
++typedef macsecSCI_t macsec_sci_t;
++typedef macsecAN_t macsec_an_t;
++typedef t_Handle handle_t;
++
++/**************************************************************************//**
++ @Function      fm_macsec_secy_exception_callback wrapper
++ @Description   Exceptions user callback routine, will be called upon an
++                exception passing the exception identification.
++ @Param[in]     app_h       A handle to an application layer object; This handle
++                            will be passed by the driver upon calling this callback.
++ @Param[in]     exception   The exception.
++*//***************************************************************************/
++typedef void (fm_macsec_secy_exception_callback) (handle_t app_h,
++                              fm_macsec_secy_exception exception);
++
++/**************************************************************************//**
++ @Function      fm_macsec_secy_event_callback wrapper
++ @Description   Events user callback routine, will be called upon an
++                event passing the event identification.
++ @Param[in]     app_h       A handle to an application layer object; This handle
++                            will be passed by the driver upon calling this callback.
++ @Param[in]     event       The event.
++*//***************************************************************************/
++typedef void (fm_macsec_secy_event_callback) (handle_t app_h,
++                              fm_macsec_secy_event event);
++
++/**************************************************************************//**
++ @Function      fm_macsec_exception_callback wrapper
++ @Description   Exceptions user callback routine, will be called upon an
++                exception passing the exception identification.
++ @Param[in]     app_h       A handle to an application layer object; This handle
++                            will be passed by the driver upon calling this callback.
++ @Param[in]     exception   The exception.
++*//***************************************************************************/
++typedef void (fm_macsec_exception_callback) (handle_t app_h,
++                              fm_macsec_exception exception);
++
++/**************************************************************************//**
++ @Description   MACSEC SecY SC Params wrapper
++*//***************************************************************************/
++struct fm_macsec_secy_sc_params {
++      macsec_sci_t sci;
++      fm_macsec_secy_cipher_suite cipher_suite;
++};
++
++/**************************************************************************//**
++ @Description   FM MACSEC SecY config input wrapper
++*//***************************************************************************/
++struct fm_macsec_secy_params {
++      handle_t fm_macsec_h;
++      struct fm_macsec_secy_sc_params tx_sc_params;
++      uint32_t num_receive_channels;
++      fm_macsec_secy_exception_callback *exception_f;
++      fm_macsec_secy_event_callback *event_f;
++      handle_t app_h;
++};
++
++/**************************************************************************//**
++ @Description   FM MACSEC config input wrapper
++*//***************************************************************************/
++struct fm_macsec_params {
++      handle_t fm_h;
++      bool guest_mode;
++
++      union {
++              struct {
++                      uint8_t fm_mac_id;
++              } guest_params;
++
++              struct {
++                      uintptr_t base_addr;
++                      handle_t fm_mac_h;
++                      fm_macsec_exception_callback *exception_f;
++                      handle_t app_h;
++              } non_guest_params;
++      };
++
++};
++
++/**************************************************************************//**
++ @Description FM device opaque structure used for type checking
++*//***************************************************************************/
++struct fm;
++
++/**************************************************************************//**
++ @Description FM MAC device opaque structure used for type checking
++*//***************************************************************************/
++struct fm_mac_dev;
++
++/**************************************************************************//**
++ @Description FM MACSEC device opaque structure used for type checking
++*//***************************************************************************/
++struct fm_macsec_dev;
++struct fm_macsec_secy_dev;
++
++/**************************************************************************//**
++ @Description A structure ..,
++*//***************************************************************************/
++struct fm_port;
++
++typedef int (*alloc_pcd_fqids)(struct device *dev, uint32_t num,
++                             uint8_t alignment, uint32_t *base_fqid);
++
++typedef int (*free_pcd_fqids)(struct device *dev, uint32_t base_fqid);
++
++struct fm_port_pcd_param {
++      alloc_pcd_fqids  cba;
++      free_pcd_fqids   cbf;
++      struct device   *dev;
++};
++
++/**************************************************************************//**
++ @Description A structure of information about each of the external
++              buffer pools used by the port,
++*//***************************************************************************/
++struct fm_port_pool_param {
++      uint8_t         id;             /**< External buffer pool id */
++      uint16_t        size;           /**< External buffer pool buffer size */
++};
++
++/**************************************************************************//**
++ @Description   structure for additional port parameters
++*//***************************************************************************/
++struct fm_port_params {
++      uint32_t errq;      /**< Error Queue Id. */
++      uint32_t defq;      /**< For Tx and HC - Default Confirmation queue,
++                               0 means no Tx conf for processed frames.
++                               For Rx and OP - default Rx queue. */
++      uint8_t num_pools;  /**< Number of pools use by this port */
++      struct fm_port_pool_param pool_param[FM_PORT_MAX_NUM_OF_EXT_POOLS];
++                          /**< Parameters for each pool */
++      uint16_t priv_data_size;  /**< Area that user may save for his own
++                                     need (E.g. save the SKB) */
++      bool parse_results; /**< Put the parser-results in the Rx/Tx buffer */
++      bool hash_results;  /**< Put the hash-results in the Rx/Tx buffer */
++      bool time_stamp;    /**< Put the time-stamp in the Rx/Tx buffer */
++      bool frag_enable;   /**< Fragmentation support, for OP only */
++      uint16_t data_align;  /**< value for selecting a data alignment (must be a power of 2);
++                               if write optimization is used, must be >= 16. */
++      uint8_t manip_extra_space;  /**< Maximum extra size needed (insertion-size minus removal-size);
++                                     Note that this field impacts the size of the buffer-prefix
++                                     (i.e. it pushes the data offset); */
++};
++
++/**************************************************************************//**
++ @Function    fm_bind
++
++ @Description Bind to a specific FM device.
++
++ @Param[in]   fm_dev  - the OF handle of the FM device.
++
++ @Return      A handle of the FM device.
++
++ @Cautions    Allowed only after the port was created.
++*//***************************************************************************/
++struct fm *fm_bind(struct device *fm_dev);
++
++/**************************************************************************//**
++ @Function    fm_unbind
++
++ @Description Un-bind from a specific FM device.
++
++ @Param[in]   fm      - A handle of the FM device.
++
++ @Cautions    Allowed only after the port was created.
++*//***************************************************************************/
++void fm_unbind(struct fm *fm);
++
++void *fm_get_handle(struct fm *fm);
++void *fm_get_rtc_handle(struct fm *fm);
++struct resource *fm_get_mem_region(struct fm *fm);
++
++/**************************************************************************//**
++ @Function    fm_port_bind
++
++ @Description Bind to a specific FM-port device (may be Rx or Tx port).
++
++ @Param[in]   fm_port_dev - the OF handle of the FM port device.
++
++ @Return      A handle of the FM port device.
++
++ @Cautions    Allowed only after the port was created.
++*//***************************************************************************/
++struct fm_port *fm_port_bind(struct device *fm_port_dev);
++
++/**************************************************************************//**
++ @Function    fm_port_unbind
++
++ @Description Un-bind from a specific FM-port device (may be Rx or Tx port).
++
++ @Param[in]   port    - A handle of the FM port device.
++
++ @Cautions    Allowed only after the port was created.
++*//***************************************************************************/
++void fm_port_unbind(struct fm_port *port);
++
++/**************************************************************************//**
++ @Function    fm_set_rx_port_params
++
++ @Description Configure parameters for a specific Rx FM-port device.
++
++ @Param[in]   port    - A handle of the FM port device.
++ @Param[in]   params  - Rx port parameters
++
++ @Cautions    Allowed only after the port is binded.
++*//***************************************************************************/
++void fm_set_rx_port_params(struct fm_port *port,
++                         struct fm_port_params *params);
++
++/**************************************************************************//**
++ @Function    fm_port_pcd_bind
++
++ @Description Bind as a listener on a port PCD.
++
++ @Param[in]   port    - A handle of the FM port device.
++ @Param[in]   params  - PCD port parameters
++
++ @Cautions    Allowed only after the port is binded.
++*//***************************************************************************/
++void fm_port_pcd_bind (struct fm_port *port, struct fm_port_pcd_param *params);
++
++/**************************************************************************//**
++ @Function    fm_port_get_buff_layout_ext_params
++
++ @Description Get data_align and manip_extra_space from the device tree
++                chosen node if applied.
++                This function will only update these two parameters.
++                When this port has no such parameters in the device tree
++                values will be set to 0.
++
++ @Param[in]   port    - A handle of the FM port device.
++ @Param[in]   params  - PCD port parameters
++
++ @Cautions    Allowed only after the port is binded.
++*//***************************************************************************/
++void fm_port_get_buff_layout_ext_params(struct fm_port *port, struct fm_port_params *params);
++
++/**************************************************************************//**
++ @Function    fm_get_tx_port_channel
++
++ @Description Get qman-channel number for this Tx port.
++
++ @Param[in]   port    - A handle of the FM port device.
++
++ @Return      qman-channel number for this Tx port.
++
++ @Cautions    Allowed only after the port is binded.
++*//***************************************************************************/
++uint16_t fm_get_tx_port_channel(struct fm_port *port);
++
++/**************************************************************************//**
++ @Function    fm_set_tx_port_params
++
++ @Description Configure parameters for a specific Tx FM-port device
++
++ @Param[in]   port    - A handle of the FM port device.
++ @Param[in]   params  - Tx port parameters
++
++ @Cautions    Allowed only after the port is binded.
++*//***************************************************************************/
++void fm_set_tx_port_params(struct fm_port *port, struct fm_port_params *params);
++
++
++/**************************************************************************//**
++ @Function    fm_mac_set_handle
++
++ @Description Set mac handle
++
++ @Param[in]   h_lnx_wrp_fm_dev - A handle of the LnxWrp FM device.
++ @Param[in]   h_fm_mac         - A handle of the LnxWrp FM MAC device.
++ @Param[in]   mac_id           - MAC id.
++*//***************************************************************************/
++void fm_mac_set_handle(t_Handle h_lnx_wrp_fm_dev, t_Handle h_fm_mac,
++                     int mac_id);
++
++/**************************************************************************//**
++ @Function    fm_port_enable
++
++ @Description Enable specific FM-port device (may be Rx or Tx port).
++
++ @Param[in]   port    - A handle of the FM port device.
++
++ @Cautions    Allowed only after the port is initialized.
++*//***************************************************************************/
++int fm_port_enable(struct fm_port *port);
++
++/**************************************************************************//**
++ @Function    fm_port_disable
++
++ @Description Disable specific FM-port device (may be Rx or Tx port).
++
++ @Param[in]   port    - A handle of the FM port device.
++
++ @Cautions    Allowed only after the port is initialized.
++*//***************************************************************************/
++int fm_port_disable(struct fm_port *port);
++
++void *fm_port_get_handle(const struct fm_port *port);
++
++u64 *fm_port_get_buffer_time_stamp(const struct fm_port *port,
++              const void *data);
++
++/**************************************************************************//**
++ @Function    fm_port_get_base_address
++
++ @Description Get base address of this port. Useful for accessing
++              port-specific registers (i.e., not common ones).
++
++ @Param[in]   port            - A handle of the FM port device.
++
++ @Param[out]  base_addr       - The port's base addr (virtual address).
++*//***************************************************************************/
++void fm_port_get_base_addr(const struct fm_port *port, uint64_t *base_addr);
++
++/**************************************************************************//**
++ @Function    fm_mutex_lock
++
++ @Description   Lock function required before any FMD/LLD call.
++*//***************************************************************************/
++void fm_mutex_lock(void);
++
++/**************************************************************************//**
++ @Function    fm_mutex_unlock
++
++ @Description   Unlock function required after any FMD/LLD call.
++*//***************************************************************************/
++void fm_mutex_unlock(void);
++
++/**************************************************************************//**
++ @Function    fm_get_max_frm
++
++ @Description   Get the maximum frame size
++*//***************************************************************************/
++int fm_get_max_frm(void);
++
++/**************************************************************************//**
++ @Function    fm_get_rx_extra_headroom
++
++ @Description   Get the extra headroom size
++*//***************************************************************************/
++int fm_get_rx_extra_headroom(void);
++
++/**************************************************************************//**
++@Function     fm_port_set_rate_limit
++
++@Description  Configure Shaper parameter on FM-port device (Tx port).
++
++@Param[in]    port   - A handle of the FM port device.
++@Param[in]    max_burst_size - Value of maximum burst size allowed.
++@Param[in]    rate_limit     - The required rate value.
++
++@Cautions     Allowed only after the port is initialized.
++*//***************************************************************************/
++int fm_port_set_rate_limit(struct fm_port *port,
++                           uint16_t max_burst_size,
++                           uint32_t rate_limit);
++/**************************************************************************//**
++@Function     fm_port_set_rate_limit
++
++@Description  Delete Shaper configuration on FM-port device (Tx port).
++
++@Param[in]    port   - A handle of the FM port device.
++
++@Cautions     Allowed only after the port is initialized.
++*//***************************************************************************/
++int fm_port_del_rate_limit(struct fm_port *port);
++
++struct   auto_res_tables_sizes
++{
++      uint16_t   max_num_of_arp_entries;
++      uint16_t   max_num_of_echo_ipv4_entries;
++      uint16_t   max_num_of_ndp_entries;
++      uint16_t   max_num_of_echo_ipv6_entries;
++      uint16_t   max_num_of_snmp_ipv4_entries;
++      uint16_t   max_num_of_snmp_ipv6_entries;
++      uint16_t   max_num_of_snmp_oid_entries;
++      uint16_t   max_num_of_snmp_char; /* total amount of character needed
++              for the snmp table */
++      uint16_t   max_num_of_ip_prot_filtering;
++      uint16_t   max_num_of_tcp_port_filtering;
++      uint16_t   max_num_of_udp_port_filtering;
++};
++/* ARP */
++struct   auto_res_arp_entry
++{
++      uint32_t  ip_address;
++      uint8_t   mac[6];
++      bool      is_vlan;
++      uint16_t  vid;
++};
++struct   auto_res_arp_info
++{
++      uint8_t                     table_size;
++      struct auto_res_arp_entry   *auto_res_table;
++      bool                        enable_conflict_detection; /* when TRUE
++              Conflict Detection will be checked and wake the host if
++              needed */
++};
++
++/* NDP */
++struct   auto_res_ndp_entry
++{
++      uint32_t  ip_address[4];
++      uint8_t   mac[6];
++      bool      is_vlan;
++      uint16_t  vid;
++};
++struct   auto_res_ndp_info
++{
++      uint32_t                    multicast_group;
++      uint8_t                     table_size_assigned;
++      struct auto_res_ndp_entry   *auto_res_table_assigned; /* This list
++              refer to solicitation IP addresses. Note that all IP adresses
++              must be from the same multicast group. This will be checked and
++              if not operation will fail. */
++      uint8_t                     table_size_tmp;
++      struct auto_res_ndp_entry   *auto_res_table_tmp;      /* This list
++              refer to temp IP addresses. Note that all temp IP adresses must
++              be from the same multicast group. This will be checked and if
++              not operation will fail. */
++
++      bool                        enable_conflict_detection; /* when TRUE
++              Conflict Detection will be checked and wake the host if
++              needed */
++};
++
++/* ICMP ECHO */
++struct   auto_res_echo_ipv4_info
++{
++      uint8_t                     table_size;
++      struct auto_res_arp_entry  *auto_res_table;
++};
++
++struct   auto_res_echo_ipv6_info
++{
++      uint8_t                     table_size;
++      struct auto_res_ndp_entry  *auto_res_table;
++};
++
++/* SNMP */
++struct   auto_res_snmp_entry
++{
++      uint16_t     oidSize;
++      uint8_t      *oidVal; /* only the oid string */
++      uint16_t     resSize;
++      uint8_t      *resVal; /* resVal will be the entire reply,
++                              i.e. "Type|Length|Value" */
++};
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response SNMP IPv4 Addresses Table Entry
++                Refer to the FMan Controller spec for more details.
++*//***************************************************************************/
++struct auto_res_snmp_ipv4addr_tbl_entry
++{
++      uint32_t ipv4addr; /*!< 32 bit IPv4 Address. */
++      bool      is_vlan;
++      uint16_t vid;   /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared                      */
++                      /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
++};
++
++/**************************************************************************//**
++ @Description   Deep Sleep Auto Response SNMP IPv6 Addresses Table Entry
++                Refer to the FMan Controller spec for more details.
++*//***************************************************************************/
++struct auto_res_snmp_ipv6addr_tbl_entry
++{
++      uint32_t ipv6Addr[4];  /*!< 4 * 32 bit IPv6 Address.                                                     */
++      bool      isVlan;
++      uint16_t vid;       /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared                      */
++                      /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
++};
++
++struct   auto_res_snmp_info
++{
++      uint16_t control;                          /**< Control bits [0-15]. */
++      uint16_t max_snmp_msg_length;              /**< Maximal allowed SNMP message length. */
++      uint16_t num_ipv4_addresses;               /**< Number of entries in IPv4 addresses table. */
++      uint16_t num_ipv6_addresses;               /**< Number of entries in IPv6 addresses table. */
++      struct auto_res_snmp_ipv4addr_tbl_entry *ipv4addr_tbl; /**< Pointer to IPv4 addresses table. */
++      struct auto_res_snmp_ipv6addr_tbl_entry *ipv6addr_tbl; /**< Pointer to IPv6 addresses table. */
++      char                        *community_read_write_string;
++      char                        *community_read_only_string;
++      struct auto_res_snmp_entry  *oid_table;
++      uint32_t                     oid_table_size;
++      uint32_t                    *statistics;
++};
++
++/* Filtering */
++struct   auto_res_port_filtering_entry
++{
++      uint16_t    src_port;
++      uint16_t    dst_port;
++      uint16_t    src_port_mask;
++      uint16_t    dst_port_mask;
++};
++struct   auto_res_filtering_info
++{
++      /* IP protocol filtering parameters */
++      uint8_t     ip_prot_table_size;
++      uint8_t     *ip_prot_table_ptr;
++      bool        ip_prot_pass_on_hit;  /* when TRUE, miss in the table will
++              cause the packet to be droped, hit will pass the packet to
++              UDP/TCP filters if needed and if not to the classification
++              tree. If the classification tree will pass the packet to a
++              queue it will cause a wake interupt. When FALSE it the other
++              way around. */
++      /* UDP port filtering parameters */
++      uint8_t     udp_ports_table_size;
++      struct auto_res_port_filtering_entry *udp_ports_table_ptr;
++      bool        udp_port_pass_on_hit; /* when TRUE, miss in the table will
++              cause the packet to be droped, hit will pass the packet to
++              classification tree. If the classification tree will pass the
++              packet to a queue it will cause a wake interupt. When FALSE it
++              the other way around. */
++    /* TCP port filtering parameters */
++      uint16_t    tcp_flags_mask;
++      uint8_t     tcp_ports_table_size;
++      struct auto_res_port_filtering_entry *tcp_ports_table_ptr;
++      bool        tcp_port_pass_on_hit; /* when TRUE, miss in the table will
++              cause the packet to be droped, hit will pass the packet to
++              classification tree. If the classification tree will pass the
++              packet to a queue it will cause a wake interupt. When FALSE it
++              the other way around. */
++};
++
++struct auto_res_port_params
++{
++      t_Handle                            h_FmPortTx;
++      struct   auto_res_arp_info          *p_auto_res_arp_info;
++      struct   auto_res_echo_ipv4_info    *p_auto_res_echo_ipv4_info;
++      struct   auto_res_ndp_info          *p_auto_res_ndp_info;
++      struct   auto_res_echo_ipv6_info    *p_auto_res_echo_ipv6_info;
++      struct   auto_res_snmp_info         *p_auto_res_snmp_info;
++      struct   auto_res_filtering_info    *p_auto_res_filtering_info;
++};
++
++struct auto_res_port_stats
++{
++    uint32_t arp_ar_cnt;
++    uint32_t echo_icmpv4_ar_cnt;
++    uint32_t ndp_ar_cnt;
++    uint32_t echo_icmpv6_ar_cnt;
++};
++
++int fm_port_config_autores_for_deepsleep_support(struct fm_port *port,
++      struct auto_res_tables_sizes *params);
++
++int fm_port_enter_autores_for_deepsleep(struct fm_port *port,
++      struct auto_res_port_params *params);
++
++void fm_port_exit_auto_res_for_deep_sleep(struct fm_port *port_rx,
++      struct fm_port *port_tx);
++
++bool fm_port_is_in_auto_res_mode(struct fm_port *port);
++
++struct auto_res_tables_sizes *fm_port_get_autores_maxsize(
++      struct fm_port *port);
++
++int fm_port_get_autores_stats(struct fm_port *port, struct auto_res_port_stats
++      *stats);
++
++int fm_port_resume(struct fm_port *port);
++
++int fm_port_suspend(struct fm_port *port);
++
++#ifdef CONFIG_FMAN_PFC
++/**************************************************************************//**
++@Function     fm_port_set_pfc_priorities_mapping_to_qman_wq
++
++@Description  Associate a QMan Work Queue with a PFC priority on this
++              FM-port device (Tx port).
++
++@Param[in]    port   - A handle of the FM port device.
++
++@Param[in]    prio   - The PFC priority.
++
++@Param[in]    wq   - The Work Queue associated with the PFC priority.
++
++@Cautions     Allowed only after the port is initialized.
++*//***************************************************************************/
++int fm_port_set_pfc_priorities_mapping_to_qman_wq(struct fm_port *port,
++              uint8_t prio, uint8_t wq);
++#endif
++
++/**************************************************************************//**
++@Function     fm_mac_set_exception
++
++@Description  Set MAC exception state.
++
++@Param[in]    fm_mac_dev   - A handle of the FM MAC device.
++@Param[in]    exception    - FM MAC exception type.
++@Param[in]    enable       - new state.
++
++*//***************************************************************************/
++int fm_mac_set_exception(struct fm_mac_dev *fm_mac_dev,
++              e_FmMacExceptions exception, bool enable);
++
++int fm_mac_free(struct fm_mac_dev *fm_mac_dev);
++
++struct fm_mac_dev *fm_mac_config(t_FmMacParams *params);
++
++int fm_mac_config_max_frame_length(struct fm_mac_dev *fm_mac_dev,
++              int len);
++
++int fm_mac_config_pad_and_crc(struct fm_mac_dev *fm_mac_dev, bool enable);
++
++int fm_mac_config_half_duplex(struct fm_mac_dev *fm_mac_dev, bool enable);
++
++int fm_mac_config_reset_on_init(struct fm_mac_dev *fm_mac_dev, bool enable);
++
++int fm_mac_init(struct fm_mac_dev *fm_mac_dev);
++
++int fm_mac_get_version(struct fm_mac_dev *fm_mac_dev, uint32_t *version);
++
++int fm_mac_enable(struct fm_mac_dev *fm_mac_dev);
++
++int fm_mac_disable(struct fm_mac_dev *fm_mac_dev);
++
++int fm_mac_resume(struct fm_mac_dev *fm_mac_dev);
++
++int fm_mac_set_promiscuous(struct fm_mac_dev *fm_mac_dev,
++              bool enable);
++
++int fm_mac_remove_hash_mac_addr(struct fm_mac_dev *fm_mac_dev,
++              t_EnetAddr *mac_addr);
++
++int fm_mac_add_hash_mac_addr(struct fm_mac_dev *fm_mac_dev,
++              t_EnetAddr *mac_addr);
++
++int fm_mac_modify_mac_addr(struct fm_mac_dev *fm_mac_dev,
++                                       uint8_t *addr);
++
++int fm_mac_adjust_link(struct fm_mac_dev *fm_mac_dev,
++              bool link, int speed, bool duplex);
++
++int fm_mac_enable_1588_time_stamp(struct fm_mac_dev *fm_mac_dev);
++
++int fm_mac_disable_1588_time_stamp(struct fm_mac_dev *fm_mac_dev);
++
++int fm_mac_set_rx_pause_frames(
++              struct fm_mac_dev *fm_mac_dev, bool en);
++
++int fm_mac_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev,
++                                           bool en);
++
++int fm_rtc_enable(struct fm *fm_dev);
++
++int fm_rtc_disable(struct fm *fm_dev);
++
++int fm_rtc_get_cnt(struct fm *fm_dev, uint64_t *ts);
++
++int fm_rtc_set_cnt(struct fm *fm_dev, uint64_t ts);
++
++int fm_rtc_get_drift(struct fm *fm_dev, uint32_t *drift);
++
++int fm_rtc_set_drift(struct fm *fm_dev, uint32_t drift);
++
++int fm_rtc_set_alarm(struct fm *fm_dev, uint32_t id,
++              uint64_t time);
++
++int fm_rtc_set_fiper(struct fm *fm_dev, uint32_t id,
++              uint64_t fiper);
++
++int fm_mac_set_wol(struct fm_port *port, struct fm_mac_dev *fm_mac_dev,
++                      bool en);
++
++/**************************************************************************//**
++@Function     fm_macsec_set_exception
++
++@Description  Set MACSEC exception state.
++
++@Param[in]    fm_macsec_dev   - A handle of the FM MACSEC device.
++@Param[in]    exception    - FM MACSEC exception type.
++@Param[in]    enable       - new state.
++
++*//***************************************************************************/
++
++int fm_macsec_set_exception(struct fm_macsec_dev *fm_macsec_dev,
++                      fm_macsec_exception exception, bool enable);
++int fm_macsec_free(struct fm_macsec_dev *fm_macsec_dev);
++struct fm_macsec_dev *fm_macsec_config(struct fm_macsec_params *fm_params);
++int fm_macsec_init(struct fm_macsec_dev *fm_macsec_dev);
++int fm_macsec_config_unknown_sci_frame_treatment(struct fm_macsec_dev
++                              *fm_macsec_dev,
++                              fm_macsec_unknown_sci_frame_treatment treat_mode);
++int fm_macsec_config_invalid_tags_frame_treatment(struct fm_macsec_dev *fm_macsec_dev,
++                              bool deliver_uncontrolled);
++int fm_macsec_config_kay_frame_treatment(struct fm_macsec_dev *fm_macsec_dev,
++                              bool discard_uncontrolled);
++int fm_macsec_config_untag_frame_treatment(struct fm_macsec_dev *fm_macsec_dev,
++                                  fm_macsec_untag_frame_treatment treat_mode);
++int fm_macsec_config_pn_exhaustion_threshold(struct fm_macsec_dev *fm_macsec_dev,
++                                      uint32_t pnExhThr);
++int fm_macsec_config_keys_unreadable(struct fm_macsec_dev *fm_macsec_dev);
++int fm_macsec_config_sectag_without_sci(struct fm_macsec_dev *fm_macsec_dev);
++int fm_macsec_config_exception(struct fm_macsec_dev *fm_macsec_dev,
++                          fm_macsec_exception exception, bool enable);
++int fm_macsec_get_revision(struct fm_macsec_dev *fm_macsec_dev,
++                          int *macsec_revision);
++int fm_macsec_enable(struct fm_macsec_dev *fm_macsec_dev);
++int fm_macsec_disable(struct fm_macsec_dev *fm_macsec_dev);
++
++
++int fm_macsec_secy_config_exception(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                  fm_macsec_secy_exception exception,
++                                  bool enable);
++int fm_macsec_secy_free(struct fm_macsec_secy_dev *fm_macsec_secy_dev);
++struct fm_macsec_secy_dev *fm_macsec_secy_config(struct fm_macsec_secy_params *secy_params);
++int fm_macsec_secy_init(struct fm_macsec_secy_dev *fm_macsec_secy_dev);
++int fm_macsec_secy_config_sci_insertion_mode(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              fm_macsec_sci_insertion_mode sci_insertion_mode);
++int fm_macsec_secy_config_protect_frames(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              bool protect_frames);
++int fm_macsec_secy_config_replay_window(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              bool replay_protect, uint32_t replay_window);
++int fm_macsec_secy_config_validation_mode(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              fm_macsec_valid_frame_behavior validate_frames);
++int fm_macsec_secy_config_confidentiality(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              bool confidentiality_enable,
++                              uint32_t confidentiality_offset);
++int fm_macsec_secy_config_point_to_point(struct fm_macsec_secy_dev *fm_macsec_secy_dev);
++int fm_macsec_secy_config_event(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                  fm_macsec_secy_event event,
++                                  bool enable);
++struct rx_sc_dev *fm_macsec_secy_create_rxsc(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              struct fm_macsec_secy_sc_params *params);
++int fm_macsec_secy_delete_rxsc(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              struct rx_sc_dev *sc);
++int fm_macsec_secy_create_rx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              struct rx_sc_dev *sc, macsec_an_t an,
++                              uint32_t lowest_pn, macsec_sa_key_t key);
++int fm_macsec_secy_delete_rx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              struct rx_sc_dev *sc, macsec_an_t an);
++int fm_macsec_secy_rxsa_enable_receive(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      struct rx_sc_dev *sc,
++                                      macsec_an_t an);
++int fm_macsec_secy_rxsa_disable_receive(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      struct rx_sc_dev *sc,
++                                      macsec_an_t an);
++int fm_macsec_secy_rxsa_update_next_pn(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      struct rx_sc_dev *sc,
++                                      macsec_an_t an, uint32_t updt_next_pn);
++int fm_macsec_secy_rxsa_update_lowest_pn(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      struct rx_sc_dev *sc,
++                                      macsec_an_t an, uint32_t updt_lowest_pn);
++int fm_macsec_secy_rxsa_modify_key(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      struct rx_sc_dev *sc,
++                                      macsec_an_t an, macsec_sa_key_t key);
++int fm_macsec_secy_create_tx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              macsec_an_t an, macsec_sa_key_t key);
++int fm_macsec_secy_delete_tx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              macsec_an_t an);
++int fm_macsec_secy_txsa_modify_key(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      macsec_an_t next_active_an,
++                                      macsec_sa_key_t key);
++int fm_macsec_secy_txsa_set_active(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      macsec_an_t an);
++int fm_macsec_secy_txsa_get_active(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      macsec_an_t *p_an);
++int fm_macsec_secy_get_rxsc_phys_id(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              struct rx_sc_dev *sc, uint32_t *sc_phys_id);
++int fm_macsec_secy_get_txsc_phys_id(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                  uint32_t *sc_phys_id);
++
++/** @} */ /* end of FM_LnxKern_ctrl_grp group */
++/** @} */ /* end of FM_LnxKern_grp group */
++
++/* default values for initializing PTP 1588 timer clock */
++#define DPA_PTP_NOMINAL_FREQ_PERIOD_SHIFT 2 /* power of 2 for better performance */
++#define DPA_PTP_NOMINAL_FREQ_PERIOD_NS (1 << DPA_PTP_NOMINAL_FREQ_PERIOD_SHIFT) /* 4ns,250MHz */
++
++#endif /* __LNXWRP_FSL_FMAN_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/xx/xx.h
+@@ -0,0 +1,50 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __XX_H
++#define __XX_H
++
++#include "xx_ext.h"
++
++void * xx_Malloc(uint32_t n);
++void xx_Free(void *p);
++
++void *xx_MallocSmart(uint32_t size, int memPartitionId, uint32_t align);
++void xx_FreeSmart(void *p);
++
++/* never used: */
++#define GetDeviceName(irq) ((char *)NULL)
++
++int     GetDeviceIrqNum(int irq);
++
++
++#endif /* __XX_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/system/Makefile
+@@ -0,0 +1,10 @@
++#
++# Makefile for the Freescale Ethernet controllers
++#
++ccflags-y           += -DVERSION=\"\"
++#
++#Include netcomm SW specific definitions
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++#
++
++obj-y         += sys_io.o
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/system/sys_io.c
+@@ -0,0 +1,171 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/version.h>
++
++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
++#define MODVERSIONS
++#endif
++#ifdef MODVERSIONS
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++#include <linux/modversions.h>
++#else
++#include <config/modversions.h>
++#endif    /* LINUX_VERSION_CODE */
++#endif /* MODVERSIONS */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++
++#include <asm/io.h>
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "string_ext.h"
++#include "list_ext.h"
++#include "sys_io_ext.h"
++
++
++#define __ERR_MODULE__      MODULE_UNKNOWN
++
++
++typedef struct {
++    uint64_t    virtAddr;
++    uint64_t    physAddr;
++    uint32_t    size;
++    t_List      node;
++} t_IoMap;
++#define IOMAP_OBJECT(ptr)  LIST_OBJECT(ptr, t_IoMap, node)
++
++LIST(mapsList);
++
++
++static void EnqueueIoMap(t_IoMap *p_IoMap)
++{
++    uint32_t   intFlags;
++
++    intFlags = XX_DisableAllIntr();
++    LIST_AddToTail(&p_IoMap->node, &mapsList);
++    XX_RestoreAllIntr(intFlags);
++}
++
++static t_IoMap * FindIoMapByVirtAddr(uint64_t addr)
++{
++    t_IoMap     *p_IoMap;
++    t_List      *p_Pos;
++
++    LIST_FOR_EACH(p_Pos, &mapsList)
++    {
++        p_IoMap = IOMAP_OBJECT(p_Pos);
++        if ((addr >= p_IoMap->virtAddr) && (addr < p_IoMap->virtAddr+p_IoMap->size))
++            return p_IoMap;
++    }
++
++    return NULL;
++}
++
++static t_IoMap * FindIoMapByPhysAddr(uint64_t addr)
++{
++    t_IoMap     *p_IoMap;
++    t_List      *p_Pos;
++
++    LIST_FOR_EACH(p_Pos, &mapsList)
++    {
++        p_IoMap = IOMAP_OBJECT(p_Pos);
++        if ((addr >= p_IoMap->physAddr) && (addr < p_IoMap->physAddr+p_IoMap->size))
++            return p_IoMap;
++    }
++
++    return NULL;
++}
++
++t_Error SYS_RegisterIoMap (uint64_t virtAddr, uint64_t physAddr, uint32_t size)
++{
++    t_IoMap *p_IoMap;
++
++    p_IoMap = (t_IoMap*)XX_Malloc(sizeof(t_IoMap));
++    if (!p_IoMap)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("message handler object!!!"));
++    memset(p_IoMap, 0, sizeof(t_IoMap));
++
++    p_IoMap->virtAddr = virtAddr;
++    p_IoMap->physAddr = physAddr;
++    p_IoMap->size     = size;
++
++    INIT_LIST(&p_IoMap->node);
++    EnqueueIoMap(p_IoMap);
++
++    return E_OK;
++}
++
++t_Error SYS_UnregisterIoMap  (uint64_t virtAddr)
++{
++    t_IoMap *p_IoMap = FindIoMapByVirtAddr(virtAddr);
++    if (!p_IoMap)
++        RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!"));
++
++    LIST_Del(&p_IoMap->node);
++    XX_Free(p_IoMap);
++
++    return E_OK;
++}
++
++uint64_t SYS_PhysToVirt(uint64_t addr)
++{
++    t_IoMap *p_IoMap = FindIoMapByPhysAddr(addr);
++    if (p_IoMap)
++    {
++        /* This is optimization - put the latest in the list-head - like a cache */
++        if (mapsList.p_Next != &p_IoMap->node)
++        {
++            uint32_t intFlags = XX_DisableAllIntr();
++            LIST_DelAndInit(&p_IoMap->node);
++            LIST_Add(&p_IoMap->node, &mapsList);
++            XX_RestoreAllIntr(intFlags);
++        }
++        return (uint64_t)(addr - p_IoMap->physAddr + p_IoMap->virtAddr);
++    }
++    return PTR_TO_UINT(phys_to_virt((unsigned long)addr));
++}
++
++uint64_t SYS_VirtToPhys(uint64_t addr)
++{
++    t_IoMap *p_IoMap;
++
++    if (addr == 0)
++        return 0;
++
++    p_IoMap = FindIoMapByVirtAddr(addr);
++    if (p_IoMap)
++        return (uint64_t)(addr - p_IoMap->virtAddr + p_IoMap->physAddr);
++    return (uint64_t)virt_to_phys(UINT_TO_PTR(addr));
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/Makefile
+@@ -0,0 +1,19 @@
++#
++# Makefile for the Freescale Ethernet controllers
++#
++ccflags-y           += -DVERSION=\"\"
++#
++#Include netcomm SW specific definitions
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++
++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
++
++ccflags-y += -I$(NCSW_FM_INC)
++ccflags-y += -I$(NET_DPA)
++
++obj-y         += fsl-ncsw-PFM.o
++obj-$(CONFIG_FSL_SDK_FMAN_TEST)       += fman_test.o
++
++fsl-ncsw-PFM-objs     :=      lnxwrp_fm.o lnxwrp_fm_port.o lnxwrp_ioctls_fm.o \
++                              lnxwrp_sysfs.o lnxwrp_sysfs_fm.o lnxwrp_sysfs_fm_port.o 
++obj-$(CONFIG_COMPAT)     +=   lnxwrp_ioctls_fm_compat.o
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/fman_test.c
+@@ -0,0 +1,1665 @@
++/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ @File          fman_test.c
++ @Authors       Pistirica Sorin Andrei
++ @Description   FM Linux test environment
++*/
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/of_platform.h>
++#include <linux/ip.h>
++#include <linux/compat.h>
++#include <linux/uaccess.h>
++#include <linux/errno.h>
++#include <linux/netdevice.h>
++#include <linux/spinlock.h>
++#include <linux/types.h>
++#include <linux/fsl_qman.h>
++#include <linux/fsl_bman.h>
++
++/* private headers */
++#include "fm_ext.h"
++#include "lnxwrp_fsl_fman.h"
++#include "fm_port_ext.h"
++#if (DPAA_VERSION == 11)
++#include "../../Peripherals/FM/MAC/memac.h"
++#endif
++#include "fm_test_ioctls.h"
++#include "fsl_fman_test.h"
++
++#include "dpaa_eth.h"
++#include "dpaa_eth_common.h"
++
++#define FMT_FRM_WATERMARK   0xdeadbeefdeadbeeaLL
++
++struct fmt_frame_s {
++      ioc_fmt_buff_desc_t     buff;
++      struct list_head        list;
++};
++
++struct fmt_fqs_s {
++      struct qman_fq          fq_base;
++      bool                    init;
++      struct fmt_port_s       *fmt_port_priv;
++};
++
++struct fmt_port_pcd_s {
++      int              num_queues;
++      struct fmt_fqs_s *fmt_pcd_fqs;
++      uint32_t         fqid_base;
++};
++
++/* char dev structure: fm test port */
++struct fmt_port_s {
++      bool                valid;
++      uint8_t             id;
++      ioc_fmt_port_type   port_type;
++      ioc_diag_mode       diag;
++      bool                compat_test_type;
++
++      /* fm ports */
++      /* ! for oh ports p_tx_fm_port_dev == p_rx_fm_port_dev &&
++       * p_tx_port == p_rx_port */
++                              /* t_LnxWrpFmPortDev */
++      struct fm_port      *p_tx_port;
++                              /* t_LnxWrpFmPortDev->h_Dev: t_FmPort */
++      void                *p_tx_fm_port_dev;
++                              /* t_LnxWrpFmPortDev */
++      struct fm_port      *p_rx_port;
++                              /* t_LnxWrpFmPortDev->h_Dev: t_FmPort */
++      void                *p_rx_fm_port_dev;
++
++      void                *p_mac_dev;
++      uint64_t            fm_phys_base_addr;
++
++      /* read/write queue manipulation */
++      spinlock_t          rx_q_lock;
++      struct list_head    rx_q;
++
++      /* tx queuee for injecting traffic */
++      int                 num_of_tx_fqs;
++      struct fmt_fqs_s    p_tx_fqs[FMAN_TEST_MAX_TX_FQS];
++
++      /* pcd private queues manipulation */
++      struct fmt_port_pcd_s fmt_port_pcd;
++
++      /* debugging stuff */
++
++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
++      atomic_t enqueue_to_qman_frm;
++      atomic_t enqueue_to_rxq;
++      atomic_t dequeue_from_rxq;
++      atomic_t not_enqueue_to_rxq_wrong_frm;
++#endif
++
++};
++
++/* The devices. */
++struct fmt_s {
++      int major;
++      struct fmt_port_s ports[IOC_FMT_MAX_NUM_OF_PORTS];
++      struct class *fmt_class;
++};
++
++/* fm test structure */
++static struct fmt_s fm_test;
++
++#if (DPAA_VERSION == 11)
++struct mac_priv_s {
++        t_Handle        mac;
++};
++#endif
++
++#define DTSEC_BASE_ADDR         0x000e0000
++#define DTSEC_MEM_RANGE         0x00002000
++#define MAC_1G_MACCFG1          0x00000100
++#define MAC_1G_LOOP_MASK        0x00000100
++static int set_1gmac_loopback(
++              struct fmt_port_s *fmt_port,
++              bool en)
++{
++#if (DPAA_VERSION <= 10)
++      uint32_t dtsec_idx = fmt_port->id; /* dtsec for which port */
++      uint32_t dtsec_idx_off = dtsec_idx * DTSEC_MEM_RANGE;
++      phys_addr_t maccfg1_hw;
++      void *maccfg1_map;
++      uint32_t maccfg1_val;
++
++      /* compute the maccfg1 register address */
++      maccfg1_hw = fmt_port->fm_phys_base_addr +
++                      (phys_addr_t)(DTSEC_BASE_ADDR +
++                                      dtsec_idx_off +
++                                      MAC_1G_MACCFG1);
++
++      /* map register */
++      maccfg1_map = ioremap(maccfg1_hw, sizeof(u32));
++
++      /* set register */
++      maccfg1_val = in_be32(maccfg1_map);
++      if (en)
++              maccfg1_val |= MAC_1G_LOOP_MASK;
++      else
++              maccfg1_val &= ~MAC_1G_LOOP_MASK;
++      out_be32(maccfg1_map, maccfg1_val);
++
++      /* unmap register */
++      iounmap(maccfg1_map);
++#else
++      struct mac_device *mac_dev;
++      struct mac_priv_s *priv;
++      t_Memac *p_memac;
++
++      if (!fmt_port)
++              return -EINVAL;
++
++      mac_dev = (struct mac_device *)fmt_port->p_mac_dev;
++
++      if (!mac_dev)
++              return -EINVAL;
++
++      priv = macdev_priv(mac_dev);
++
++      if (!priv)
++              return -EINVAL;
++
++      p_memac = priv->mac;
++
++      if (!p_memac)
++              return -EINVAL;
++
++      memac_set_loopback(p_memac->p_MemMap, en);
++#endif
++      return 0;
++}
++
++/* TODO: re-write this function */
++static int set_10gmac_int_loopback(
++              struct fmt_port_s *fmt_port,
++              bool en)
++{
++#ifndef FM_10G_MAC_NO_CTRL_LOOPBACK
++#define FM_10GMAC0_OFFSET               0x000f0000
++#define FM_10GMAC_CMD_CONF_CTRL_OFFSET  0x8
++#define CMD_CFG_LOOPBACK_EN             0x00000400
++
++      uint64_t    base_addr, reg_addr;
++      uint32_t    tmp_val;
++
++      base_addr = fmt_port->fm_phys_base_addr + (FM_10GMAC0_OFFSET +
++                      ((fmt_port->id-FM_MAX_NUM_OF_1G_RX_PORTS)*0x2000));
++
++      base_addr = PTR_TO_UINT(ioremap(base_addr, 0x1000));
++
++      reg_addr = base_addr + FM_10GMAC_CMD_CONF_CTRL_OFFSET;
++      tmp_val = GET_UINT32(*((uint32_t  *)UINT_TO_PTR(reg_addr)));
++      if (en)
++              tmp_val |= CMD_CFG_LOOPBACK_EN;
++      else
++              tmp_val &= ~CMD_CFG_LOOPBACK_EN;
++      WRITE_UINT32(*((uint32_t  *)UINT_TO_PTR(reg_addr)), tmp_val);
++
++      iounmap(UINT_TO_PTR(base_addr));
++
++      return 0;
++#else
++      _fmt_err("TGEC don't have internal-loopback.\n");
++      return  -EPERM;
++#endif
++}
++
++static int set_mac_int_loopback(struct fmt_port_s *fmt_port, bool en)
++{
++      int _err = 0;
++
++      switch (fmt_port->port_type) {
++
++      case e_IOC_FMT_PORT_T_RXTX:
++      /* 1G port */
++      if (fmt_port->id < FM_MAX_NUM_OF_1G_RX_PORTS)
++              _err = set_1gmac_loopback(fmt_port, en);
++      /* 10g port */
++      else if ((fmt_port->id >= FM_MAX_NUM_OF_1G_RX_PORTS) &&
++                      (fmt_port->id < FM_MAX_NUM_OF_1G_RX_PORTS +
++                                      FM_MAX_NUM_OF_10G_RX_PORTS)) {
++
++              _err = set_10gmac_int_loopback(fmt_port, en);
++      } else
++              _err = -EINVAL;
++      break;
++      /* op port does not have MAC (loopback mode) */
++      case e_IOC_FMT_PORT_T_OP:
++
++      _err = 0;
++      break;
++      default:
++
++      _err = -EPERM;
++      break;
++      }
++
++      return _err;
++}
++
++static void enqueue_fmt_frame(
++              struct fmt_port_s *fmt_port,
++              struct fmt_frame_s *p_fmt_frame)
++{
++      spinlock_t *rx_q_lock = NULL;
++
++      rx_q_lock = &fmt_port->rx_q_lock;
++
++      spin_lock(rx_q_lock);
++      list_add_tail(&p_fmt_frame->list, &fmt_port->rx_q);
++      spin_unlock(rx_q_lock);
++
++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
++      atomic_inc(&fmt_port->enqueue_to_rxq);
++#endif
++}
++
++static struct fmt_frame_s *dequeue_fmt_frame(
++              struct fmt_port_s *fmt_port)
++{
++      struct fmt_frame_s *p_fmt_frame = NULL;
++      spinlock_t *rx_q_lock = NULL;
++
++      rx_q_lock = &fmt_port->rx_q_lock;
++
++      spin_lock(rx_q_lock);
++
++#define list_last_entry(ptr, type, member) list_entry((ptr)->prev, type, member)
++
++      if (!list_empty(&fmt_port->rx_q)) {
++              p_fmt_frame = list_last_entry(&fmt_port->rx_q,
++                                              struct fmt_frame_s,
++                                              list);
++              list_del(&p_fmt_frame->list);
++
++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
++              atomic_inc(&fmt_port->dequeue_from_rxq);
++#endif
++      }
++
++      spin_unlock(rx_q_lock);
++
++      return p_fmt_frame;
++}
++
++/* eth-dev -to- fmt port association */
++struct fmt_port_s *match_dpa_to_fmt_port(
++                              struct dpa_priv_s *dpa_priv) {
++      struct mac_device *mac_dev = dpa_priv->mac_dev;
++      struct fm_port *fm_port = (struct fm_port  *) mac_dev;
++      struct fmt_port_s *fmt_port = NULL;
++      int i;
++
++      _fmt_dbgr("calling...\n");
++
++      /* find the FM-test-port object */
++      for (i = 0; i < IOC_FMT_MAX_NUM_OF_PORTS; i++)
++              if ((fm_test.ports[i].p_mac_dev &&
++                   mac_dev == fm_test.ports[i].p_mac_dev) ||
++                   fm_port == fm_test.ports[i].p_tx_port) {
++
++                      fmt_port = &fm_test.ports[i];
++                      break;
++              }
++
++      _fmt_dbgr("called\n");
++      return fmt_port;
++}
++
++void dump_frame(
++      uint8_t  *buffer,
++      uint32_t size)
++{
++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
++      unsigned int i;
++
++      for (i = 0; i < size; i++) {
++              if (i%16 == 0)
++                      printk(KERN_DEBUG "\n");
++              printk(KERN_DEBUG "%2x ", *(buffer+i));
++      }
++#endif
++      return;
++}
++
++bool test_and_steal_frame(struct fmt_port_s *fmt_port,
++              uint32_t fqid,
++              uint8_t  *buffer,
++              uint32_t size)
++{
++      struct fmt_frame_s *p_fmt_frame = NULL;
++      bool test_and_steal_frame_frame;
++      uint32_t data_offset;
++      uint32_t i;
++
++      _fmt_dbgr("calling...\n");
++
++      if (!fmt_port || !fmt_port->p_rx_fm_port_dev)
++              return false;
++
++      /* check watermark */
++      test_and_steal_frame_frame = false;
++      for (i = 0; i < size; i++) {
++              uint64_t temp = *((uint64_t  *)(buffer + i));
++
++              if (temp == (uint64_t) FMT_FRM_WATERMARK) {
++                      _fmt_dbgr("watermark found!\n");
++                      test_and_steal_frame_frame = true;
++                      break;
++              }
++      }
++
++      if (!test_and_steal_frame_frame) {
++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
++              atomic_inc(&fmt_port->not_enqueue_to_rxq_wrong_frm);
++#endif
++              _fmt_dbgr("NOT watermark found!\n");
++              return false;
++      }
++
++      /* do not enqueue the tx conf/err frames */
++      if ((fqid == FMT_TX_CONF_Q) || (fqid == FMT_TX_ERR_Q))
++              goto _test_and_steal_frame_return_true;
++
++      _fmt_dbgr("on port %d got FMUC frame\n", fmt_port->id);
++      data_offset = FM_PORT_GetBufferDataOffset(
++                                      fmt_port->p_rx_fm_port_dev);
++
++      p_fmt_frame = kmalloc(sizeof(struct fmt_frame_s), GFP_KERNEL);
++
++      /* dump frame... no more space left on device */
++      if (p_fmt_frame == NULL) {
++              _fmt_err("no space left on device!\n");
++              goto _test_and_steal_frame_return_true;
++      }
++
++      memset(p_fmt_frame, 0, sizeof(struct fmt_frame_s));
++      p_fmt_frame->buff.p_data = kmalloc(size * sizeof(uint8_t), GFP_KERNEL);
++
++      /* No more space left on device*/
++      if (p_fmt_frame->buff.p_data == NULL) {
++              _fmt_err("no space left on device!\n");
++              kfree(p_fmt_frame);
++              goto _test_and_steal_frame_return_true;
++      }
++
++      p_fmt_frame->buff.size = size-data_offset;
++      p_fmt_frame->buff.qid = fqid;
++
++      memcpy(p_fmt_frame->buff.p_data,
++              (uint8_t  *)PTR_MOVE(buffer, data_offset),
++              p_fmt_frame->buff.size);
++
++      memcpy(p_fmt_frame->buff.buff_context.fm_prs_res,
++              FM_PORT_GetBufferPrsResult(fmt_port->p_rx_fm_port_dev,
++                                              (char *)buffer),
++              32);
++
++      /* enqueue frame - this frame will go to us */
++      enqueue_fmt_frame(fmt_port, p_fmt_frame);
++
++_test_and_steal_frame_return_true:
++      return true;
++}
++
++static int fmt_fq_release(const struct qm_fd *fd)
++{
++      struct dpa_bp *_dpa_bp;
++      struct bm_buffer _bmb;
++
++      if (fd->format == qm_fd_contig) {
++              _dpa_bp = dpa_bpid2pool(fd->bpid);
++              BUG_ON(IS_ERR(_dpa_bp));
++
++              _bmb.hi = fd->addr_hi;
++              _bmb.lo = fd->addr_lo;
++
++              while (bman_release(_dpa_bp->pool, &_bmb, 1, 0))
++                      cpu_relax();
++
++      } else {
++              _fmt_err("frame not supported !\n");
++              return -1;
++      }
++
++      return 0;
++}
++
++/* sync it w/ dpaa_eth.c: DPA_BP_HEAD */
++#define DPA_BP_HEADROOM (DPA_TX_PRIV_DATA_SIZE + \
++                      fm_get_rx_extra_headroom() + \
++                      DPA_PARSE_RESULTS_SIZE + \
++                      DPA_HASH_RESULTS_SIZE)
++#define MAC_HEADER_LENGTH 14
++#define L2_AND_HEADROOM_OFF ((DPA_BP_HEADROOM) + (MAC_HEADER_LENGTH))
++
++/* dpa ingress hooks definition */
++enum dpaa_eth_hook_result fmt_rx_default_hook(
++              struct sk_buff *skb,
++              struct net_device *net_dev,
++              u32 fqid)
++{
++      struct dpa_priv_s *dpa_priv = NULL;
++      struct fmt_port_s *fmt_port = NULL;
++      uint8_t *buffer;
++      uint32_t buffer_len;
++
++      _fmt_dbgr("calling...\n");
++
++      dpa_priv = netdev_priv(net_dev);
++      fmt_port = match_dpa_to_fmt_port(dpa_priv);
++
++      /* conversion from skb to fd:
++       *  skb cames processed for L3, so we need to go back for
++       *  layer 2 offset */
++      buffer = (uint8_t  *)(skb->data - ((int)L2_AND_HEADROOM_OFF));
++      buffer_len = skb->len + ((int)L2_AND_HEADROOM_OFF);
++
++      /* if is not out frame let dpa to handle it */
++      if (test_and_steal_frame(fmt_port,
++                      FMT_RX_DFLT_Q,
++                      buffer,
++                      buffer_len))
++              goto _fmt_rx_default_hook_stolen;
++
++      _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n");
++      return DPAA_ETH_CONTINUE;
++
++_fmt_rx_default_hook_stolen:
++      dev_kfree_skb(skb);
++
++      _fmt_dbgr("called:DPAA_ETH_STOLEN.\n");
++      return DPAA_ETH_STOLEN;
++}
++
++enum dpaa_eth_hook_result fmt_rx_error_hook(
++      struct net_device *net_dev,
++      const struct qm_fd *fd,
++      u32 fqid)
++{
++      struct dpa_priv_s *dpa_priv = NULL;
++      struct dpa_bp *dpa_bp = NULL;
++      struct fmt_port_s *fmt_port = NULL;
++      void *fd_virt_addr = NULL;
++      dma_addr_t addr = qm_fd_addr(fd);
++
++      _fmt_dbgr("calling...\n");
++
++      dpa_priv = netdev_priv(net_dev);
++      fmt_port = match_dpa_to_fmt_port(dpa_priv);
++
++      /* dpaa doesn't do this... we have to do it here */
++      dpa_bp = dpa_bpid2pool(fd->bpid);
++      dma_unmap_single(dpa_bp->dev, addr, dpa_bp->size, DMA_BIDIRECTIONAL);
++
++      fd_virt_addr = phys_to_virt(addr);
++      /* if is not out frame let dpa to handle it */
++      if (test_and_steal_frame(fmt_port,
++                      FMT_RX_ERR_Q,
++                      fd_virt_addr,
++                      fd->length20 + fd->offset)) {
++              goto _fmt_rx_error_hook_stolen;
++      }
++
++      _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n");
++      return DPAA_ETH_CONTINUE;
++
++_fmt_rx_error_hook_stolen:
++      /* the frame data  doesn't matter,
++       * so, no mapping is needed */
++      fmt_fq_release(fd);
++
++      _fmt_dbgr("called:DPAA_ETH_STOLEN.\n");
++      return DPAA_ETH_STOLEN;
++}
++
++enum dpaa_eth_hook_result fmt_tx_confirm_hook(
++      struct net_device *net_dev,
++      const struct qm_fd *fd,
++      u32 fqid)
++{
++      struct dpa_priv_s *dpa_priv = NULL;
++      struct fmt_port_s *fmt_port = NULL;
++      dma_addr_t addr = qm_fd_addr(fd);
++      void *fd_virt_addr = NULL;
++      uint32_t fd_len = 0;
++
++      _fmt_dbgr("calling...\n");
++
++      dpa_priv = netdev_priv(net_dev);
++      fmt_port = match_dpa_to_fmt_port(dpa_priv);
++
++      fd_virt_addr = phys_to_virt(addr);
++      fd_len = fd->length20 + fd->offset;
++
++      if (fd_len > fm_get_max_frm()) {
++              _fmt_err("tx confirm bad frame size: %u!\n", fd_len);
++              goto _fmt_tx_confirm_hook_continue;
++      }
++
++      if (test_and_steal_frame(fmt_port,
++                      FMT_TX_CONF_Q,
++                      fd_virt_addr,
++                      fd_len))
++              goto _fmt_tx_confirm_hook_stolen;
++
++_fmt_tx_confirm_hook_continue:
++      _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n");
++      return DPAA_ETH_CONTINUE;
++
++_fmt_tx_confirm_hook_stolen:
++      kfree(fd_virt_addr);
++
++      _fmt_dbgr("called:DPAA_ETH_STOLEN.\n");
++      return DPAA_ETH_STOLEN;
++}
++
++enum dpaa_eth_hook_result fmt_tx_confirm_error_hook(
++      struct net_device *net_dev,
++      const struct qm_fd *fd,
++      u32 fqid)
++{
++      struct dpa_priv_s *dpa_priv = NULL;
++      struct fmt_port_s *fmt_port = NULL;
++      dma_addr_t addr = qm_fd_addr(fd);
++      void *fd_virt_addr = NULL;
++      uint32_t fd_len = 0;
++
++      _fmt_dbgr("calling...\n");
++
++      dpa_priv = netdev_priv(net_dev);
++      fmt_port = match_dpa_to_fmt_port(dpa_priv);
++
++      fd_virt_addr = phys_to_virt(addr);
++      fd_len = fd->length20 + fd->offset;
++
++      if (fd_len > fm_get_max_frm()) {
++              _fmt_err("tx confirm err bad frame size: %u !\n", fd_len);
++              goto _priv_ingress_tx_err_continue;
++      }
++
++      if (test_and_steal_frame(fmt_port, FMT_TX_ERR_Q, fd_virt_addr, fd_len))
++              goto _priv_ingress_tx_err_stolen;
++
++_priv_ingress_tx_err_continue:
++      _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n");
++      return DPAA_ETH_CONTINUE;
++
++_priv_ingress_tx_err_stolen:
++      kfree(fd_virt_addr);
++
++      _fmt_dbgr("called:DPAA_ETH_STOLEN.\n");
++      return DPAA_ETH_STOLEN;
++}
++
++/* egress callbacks definition */
++enum qman_cb_dqrr_result fmt_egress_dqrr(
++              struct qman_portal         *portal,
++              struct qman_fq             *fq,
++              const struct qm_dqrr_entry *dqrr)
++{
++      /* this callback should never be called */
++      BUG();
++      return qman_cb_dqrr_consume;
++}
++
++static void  fmt_egress_error_dqrr(
++              struct qman_portal *p,
++              struct qman_fq *fq,
++              const struct qm_mr_entry *msg)
++{
++      uint8_t *fd_virt_addr = NULL;
++
++      /* tx failure, on the ern callback - release buffer */
++      fd_virt_addr = (uint8_t  *)phys_to_virt(qm_fd_addr(&msg->ern.fd));
++      kfree(fd_virt_addr);
++
++      return;
++}
++
++static const struct qman_fq fmt_egress_fq = {
++      .cb = { .dqrr = fmt_egress_dqrr,
++              .ern = fmt_egress_error_dqrr,
++              .fqs = NULL}
++};
++
++int fmt_fq_alloc(
++      struct fmt_fqs_s *fmt_fqs,
++      const struct qman_fq *qman_fq,
++      uint32_t fqid,  uint32_t flags,
++      uint16_t channel, uint8_t wq)
++{
++      int _errno = 0;
++
++      _fmt_dbg("calling...\n");
++
++      fmt_fqs->fq_base = *qman_fq;
++
++      if (fqid == 0) {
++              flags |= QMAN_FQ_FLAG_DYNAMIC_FQID;
++              flags &= ~QMAN_FQ_FLAG_NO_MODIFY;
++      } else
++              flags &= ~QMAN_FQ_FLAG_DYNAMIC_FQID;
++
++      fmt_fqs->init = !(flags & QMAN_FQ_FLAG_NO_MODIFY);
++
++      _errno = qman_create_fq(fqid, flags, &fmt_fqs->fq_base);
++      if (_errno < 0) {
++              _fmt_err("frame queues create failed.\n");
++              return -EINVAL;
++      }
++
++      if (fmt_fqs->init) {
++              struct qm_mcc_initfq initfq;
++
++              initfq.we_mask          = QM_INITFQ_WE_DESTWQ;
++              initfq.fqd.dest.channel = channel;
++              initfq.fqd.dest.wq      = wq;
++
++              _errno = qman_init_fq(&fmt_fqs->fq_base,
++                              QMAN_INITFQ_FLAG_SCHED,
++                              &initfq);
++              if (_errno < 0) {
++                      _fmt_err("frame queues init erorr.\n");
++                      qman_destroy_fq(&fmt_fqs->fq_base, 0);
++                      return -EINVAL;
++              }
++      }
++
++      _fmt_dbg("called.\n");
++      return 0;
++}
++
++static int fmt_fq_free(struct fmt_fqs_s *fmt_fq)
++{
++      int _err = 0;
++
++      _fmt_dbg("calling...\n");
++
++      if (fmt_fq->init) {
++              _err = qman_retire_fq(&fmt_fq->fq_base, NULL);
++              if (unlikely(_err < 0))
++                      _fmt_err("qman_retire_fq(%u) = %d\n",
++                              qman_fq_fqid(&fmt_fq->fq_base), _err);
++
++              _err = qman_oos_fq(&fmt_fq->fq_base);
++              if (unlikely(_err < 0))
++                      _fmt_err("qman_oos_fq(%u) = %d\n",
++                              qman_fq_fqid(&fmt_fq->fq_base), _err);
++      }
++
++      qman_destroy_fq(&fmt_fq->fq_base, 0);
++
++      _fmt_dbg("called.\n");
++      return _err;
++}
++
++/* private pcd dqrr calbacks */
++static enum qman_cb_dqrr_result fmt_pcd_dqrr(
++              struct qman_portal *portal,
++              struct qman_fq *fq,
++              const struct qm_dqrr_entry *dq)
++{
++      struct dpa_bp *dpa_bp = NULL;
++      dma_addr_t addr = qm_fd_addr(&dq->fd);
++      uint8_t *fd_virt_addr = NULL;
++      struct fmt_port_s *fmt_port;
++      struct fmt_port_pcd_s *fmt_port_pcd;
++      uint32_t relative_fqid = 0;
++      uint32_t fd_len = 0;
++
++      _fmt_dbgr("calling...\n");
++
++      /* upcast - from pcd_alloc_fq */
++      fmt_port = ((struct fmt_fqs_s  *)fq)->fmt_port_priv;
++      if (!fmt_port) {
++              _fmt_err(" wrong fmt port -to- fq match.\n");
++              goto _fmt_pcd_dqrr_return;
++      }
++      fmt_port_pcd = &fmt_port->fmt_port_pcd;
++
++      relative_fqid = dq->fqid - fmt_port_pcd->fqid_base;
++      _fmt_dbgr("pcd dqrr got frame on relative fq:%u@base:%u\n",
++                              relative_fqid, fmt_port_pcd->fqid_base);
++
++      fd_len = dq->fd.length20 + dq->fd.offset;
++
++      if (fd_len > fm_get_max_frm()) {
++              _fmt_err("pcd dqrr wrong frame size: %u (%u:%u)!\n",
++                      fd_len, dq->fd.length20, dq->fd.offset);
++              goto _fmt_pcd_dqrr_return;
++      }
++
++      dpa_bp = dpa_bpid2pool(dq->fd.bpid);
++      dma_unmap_single(dpa_bp->dev, addr, dpa_bp->size, DMA_BIDIRECTIONAL);
++
++      fd_virt_addr = phys_to_virt(addr);
++      if (!test_and_steal_frame(fmt_port, relative_fqid, fd_virt_addr,
++                                                                 fd_len)) {
++
++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
++              atomic_inc(&fmt_port->not_enqueue_to_rxq_wrong_frm);
++#endif
++              _fmt_wrn("pcd dqrr unrecognized frame@fqid: %u,"
++                       " frame len: %u (dropped).\n",
++                      dq->fqid, dq->fd.length20);
++              dump_frame(fd_virt_addr, fd_len);
++      }
++
++_fmt_pcd_dqrr_return:
++      /* no need to map again here */
++      fmt_fq_release(&dq->fd);
++
++      _fmt_dbgr("calle.\n");
++      return qman_cb_dqrr_consume;
++}
++
++static void fmt_pcd_err_dqrr(
++      struct qman_portal *qm,
++      struct qman_fq *fq,
++      const struct qm_mr_entry *msg)
++{
++      _fmt_err("this callback should never be called.\n");
++      BUG();
++      return;
++}
++
++static void fmt_pcd_fqs_dqrr(
++      struct qman_portal *qm,
++      struct qman_fq *fq,
++      const struct qm_mr_entry *msg)
++{
++      _fmt_dbg(" fq state(0x%x)@fqid(%u.\n", msg->fq.fqs, msg->fq.fqid);
++      return;
++}
++
++/* private pcd queue template */
++static const struct qman_fq pcd_fq = {
++      .cb = { .dqrr = fmt_pcd_dqrr,
++              .ern = fmt_pcd_err_dqrr,
++              .fqs = fmt_pcd_fqs_dqrr}
++};
++
++/* defined as weak in dpaa driver. */
++/* ! parameters come from IOCTL call - US */
++int dpa_alloc_pcd_fqids(
++              struct device *dev,
++              uint32_t num, uint8_t alignment,
++              uint32_t *base_fqid)
++{
++      int _err = 0, i;
++      struct net_device *net_dev = NULL;
++      struct dpa_priv_s *dpa_priv = NULL;
++      struct fmt_port_pcd_s *fmt_port_pcd = NULL;
++      struct fmt_fqs_s *fmt_fqs = NULL;
++      struct fmt_port_s *fmt_port = NULL;
++      int num_allocated = 0;
++
++      _fmt_dbg("calling...\n");
++
++      net_dev = (typeof(net_dev))dev_get_drvdata(dev);
++      dpa_priv = (typeof(dpa_priv))netdev_priv(net_dev);
++
++      if (!netif_msg_probe(dpa_priv)) {
++              _fmt_err("dpa not probe.\n");
++              _err = -ENODEV;
++              goto _pcd_alloc_fqs_err;
++      }
++
++      fmt_port = match_dpa_to_fmt_port(dpa_priv);
++      if (!fmt_port) {
++              _fmt_err("fmt port not found.");
++              _err = -EINVAL;
++              goto _pcd_alloc_fqs_err;
++      }
++
++      fmt_port_pcd = &fmt_port->fmt_port_pcd;
++
++      num_allocated = qman_alloc_fqid_range(base_fqid, num, alignment, 0);
++
++      if ((num_allocated <= 0) ||
++          (num_allocated < num) ||
++          (alignment && (*base_fqid) % alignment)) {
++              *base_fqid = 0;
++              _fmt_err("Failed to alloc pcd fqs rang.\n");
++              _err = -EINVAL;
++              goto _pcd_alloc_fqs_err;
++      }
++
++      _fmt_dbg("wanted %d fqs(align %d), got %d fqids@%u.\n",
++                              num, alignment, num_allocated, *base_fqid);
++
++      /* alloc pcd queues */
++      fmt_port_pcd->fmt_pcd_fqs = kmalloc(num_allocated *
++                                              sizeof(struct fmt_fqs_s),
++                                              GFP_KERNEL);
++      fmt_port_pcd->num_queues = num_allocated;
++      fmt_port_pcd->fqid_base = *base_fqid;
++      fmt_fqs = fmt_port_pcd->fmt_pcd_fqs;
++
++      /* alloc the pcd queues */
++      for (i = 0; i < num_allocated; i++, fmt_fqs++) {
++              _err = fmt_fq_alloc(
++                      fmt_fqs,
++                      &pcd_fq,
++                      (*base_fqid) + i, QMAN_FQ_FLAG_NO_ENQUEUE,
++                      dpa_priv->channel, 7);
++
++              if (_err < 0)
++                      goto _pcd_alloc_fqs_err;
++
++              /* upcast to identify from where the frames came from */
++              fmt_fqs->fmt_port_priv = fmt_port;
++      }
++
++      _fmt_dbg("called.\n");
++      return _err;
++_pcd_alloc_fqs_err:
++      if (num_allocated > 0)
++              qman_release_fqid_range(*base_fqid, num_allocated);
++      /*TODO: free fmt_pcd_fqs if are any */
++
++      _fmt_dbg("called(_err:%d).\n", _err);
++      return _err;
++}
++
++/* defined as weak in dpaa driver. */
++int dpa_free_pcd_fqids(
++      struct device *dev,
++      uint32_t base_fqid)
++{
++
++      int _err = 0, i;
++      struct net_device *net_dev = NULL;
++      struct dpa_priv_s *dpa_priv = NULL;
++      struct fmt_port_pcd_s *fmt_port_pcd = NULL;
++      struct fmt_fqs_s *fmt_fqs = NULL;
++      struct fmt_port_s *fmt_port = NULL;
++      int num_allocated = 0;
++
++      _fmt_dbg("calling...\n");
++
++      net_dev = (typeof(net_dev))dev_get_drvdata(dev);
++      dpa_priv = (typeof(dpa_priv))netdev_priv(net_dev);
++
++      if (!netif_msg_probe(dpa_priv)) {
++              _fmt_err("dpa not probe.\n");
++              _err = -ENODEV;
++              goto _pcd_free_fqs_err;
++      }
++
++      fmt_port = match_dpa_to_fmt_port(dpa_priv);
++      if (!fmt_port) {
++              _fmt_err("fmt port not found.");
++              _err = -EINVAL;
++              goto _pcd_free_fqs_err;
++      }
++
++      fmt_port_pcd = &fmt_port->fmt_port_pcd;
++      num_allocated = fmt_port_pcd->num_queues;
++      fmt_fqs = fmt_port_pcd->fmt_pcd_fqs;
++
++      for (i = 0; i < num_allocated; i++, fmt_fqs++)
++              fmt_fq_free(fmt_fqs);
++
++      qman_release_fqid_range(base_fqid,num_allocated);
++
++      kfree(fmt_port_pcd->fmt_pcd_fqs);
++      memset(fmt_port_pcd, 0, sizeof(*fmt_port_pcd));
++
++      /* debugging stuff */
++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
++      _fmt_dbg(" portid: %u.\n", fmt_port->id);
++      _fmt_dbg(" frames enqueue to qman: %u.\n",
++                      atomic_read(&fmt_port->enqueue_to_qman_frm));
++      _fmt_dbg(" frames enqueue to rxq: %u.\n",
++                      atomic_read(&fmt_port->enqueue_to_rxq));
++      _fmt_dbg(" frames dequeue from rxq: %u.\n",
++                      atomic_read(&fmt_port->dequeue_from_rxq));
++      _fmt_dbg(" frames not enqueue to rxq - wrong frm: %u.\n",
++                      atomic_read(&fmt_port->not_enqueue_to_rxq_wrong_frm));
++      atomic_set(&fmt_port->enqueue_to_qman_frm, 0);
++      atomic_set(&fmt_port->enqueue_to_rxq, 0);
++      atomic_set(&fmt_port->dequeue_from_rxq, 0);
++      atomic_set(&fmt_port->not_enqueue_to_rxq_wrong_frm, 0);
++#endif
++      return 0;
++
++_pcd_free_fqs_err:
++      return _err;
++}
++
++static int fmt_port_init(
++      struct fmt_port_s *fmt_port,
++      ioc_fmt_port_param_t *p_Params)
++{
++      struct device_node  *fm_node, *fm_port_node;
++      const uint32_t      *uint32_prop;
++      int                 _errno = 0, lenp = 0, i;
++      static struct of_device_id fm_node_of_match[] = {
++              { .compatible = "fsl,fman", },
++              { /* end of list */ },
++              };
++
++      _fmt_dbg("calling...\n");
++
++      /* init send/receive tu US list */
++      INIT_LIST_HEAD(&fmt_port->rx_q);
++
++      /* check parameters */
++      if (p_Params->num_tx_queues > FMAN_TEST_MAX_TX_FQS ||
++              p_Params->fm_port_id > IOC_FMT_MAX_NUM_OF_PORTS) {
++              _fmt_dbg("wrong test parameters.\n");
++              return -EINVAL;
++      }
++
++      /* set port parameters */
++      fmt_port->num_of_tx_fqs = p_Params->num_tx_queues;
++      fmt_port->id = p_Params->fm_port_id;
++      fmt_port->port_type = p_Params->fm_port_type;
++      fmt_port->diag = e_IOC_DIAG_MODE_NONE;
++
++      /* init debugging stuff */
++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
++      atomic_set(&fmt_port->enqueue_to_qman_frm, 0);
++      atomic_set(&fmt_port->enqueue_to_rxq, 0);
++      atomic_set(&fmt_port->dequeue_from_rxq, 0);
++      atomic_set(&fmt_port->not_enqueue_to_rxq_wrong_frm, 0);
++#endif
++
++      /* TODO: This should be done at probe time not at runtime
++       *      very ugly function */
++      /* fill fmt port properties from dts */
++      for_each_matching_node(fm_node, fm_node_of_match) {
++
++      uint32_prop = (uint32_t *)of_get_property(fm_node,
++                                              "cell-index", &lenp);
++      if (unlikely(uint32_prop == NULL)) {
++              _fmt_wrn("of_get_property(%s, cell-index) invalid",
++                                              fm_node->full_name);
++              return -EINVAL;
++      }
++      if (WARN_ON(lenp != sizeof(uint32_t))) {
++              _fmt_wrn("of_get_property(%s, cell-index) invalid",
++                                              fm_node->full_name);
++              return -EINVAL;
++      }
++
++      if (*uint32_prop == p_Params->fm_id) {
++              struct resource res;
++
++              /* Get the FM address */
++              _errno = of_address_to_resource(fm_node, 0, &res);
++              if (unlikely(_errno < 0)) {
++                      _fmt_wrn("of_address_to_resource() = %u.\n", _errno);
++                      return -EINVAL;
++              }
++
++              fmt_port->fm_phys_base_addr = res.start;
++
++              for_each_child_of_node(fm_node, fm_port_node) {
++              struct platform_device    *of_dev;
++
++              if (!of_device_is_available(fm_port_node))
++                      continue;
++
++              uint32_prop = (uint32_t *)of_get_property(
++                                              fm_port_node,
++                                              "cell-index",
++                                              &lenp);
++              if (uint32_prop == NULL)
++                      continue;
++
++              if (of_device_is_compatible(fm_port_node,
++                                              "fsl,fman-port-oh") &&
++                      (fmt_port->port_type  == e_IOC_FMT_PORT_T_OP)) {
++
++                      if (*uint32_prop == fmt_port->id) {
++                              of_dev = of_find_device_by_node(fm_port_node);
++                              if (unlikely(of_dev == NULL)) {
++                                      _fmt_wrn("fm id invalid\n");
++                                      return -EINVAL;
++                              }
++
++                              fmt_port->p_tx_port =
++                                              fm_port_bind(&of_dev->dev);
++                              fmt_port->p_tx_fm_port_dev =
++                                              (void  *)fm_port_get_handle(
++                                                      fmt_port->p_tx_port);
++                              fmt_port->p_rx_port =
++                                              fmt_port->p_tx_port;
++                              fmt_port->p_rx_fm_port_dev =
++                                              fmt_port->p_tx_fm_port_dev;
++                              fmt_port->p_mac_dev = NULL;
++                      break;
++                      }
++              } else if ((*uint32_prop == fmt_port->id) &&
++                      fmt_port->port_type == e_IOC_FMT_PORT_T_RXTX) {
++
++                      of_dev = of_find_device_by_node(fm_port_node);
++                      if (unlikely(of_dev == NULL)) {
++                              _fmt_wrn("dtb fm id invalid value");
++                              return -EINVAL;
++                      }
++
++                      if (of_device_is_compatible(fm_port_node,
++                                         "fsl,fman-port-1g-tx")) {
++                              fmt_port->p_tx_port =
++                                              fm_port_bind(&of_dev->dev);
++                              fmt_port->p_tx_fm_port_dev = (void  *)
++                                              fm_port_get_handle(
++                                                      fmt_port->p_tx_port);
++                      } else if (of_device_is_compatible(fm_port_node,
++                                                    "fsl,fman-port-1g-rx")) {
++                              fmt_port->p_rx_port =
++                                              fm_port_bind(&of_dev->dev);
++                              fmt_port->p_rx_fm_port_dev = (void  *)
++                                              fm_port_get_handle(
++                                                      fmt_port->p_rx_port);
++                      } else if (of_device_is_compatible(fm_port_node,
++                                                      "fsl,fman-1g-mac") ||
++                                 of_device_is_compatible(fm_port_node,
++                                                      "fsl,fman-memac"))
++                              fmt_port->p_mac_dev =
++                                              (typeof(fmt_port->p_mac_dev))
++                                              dev_get_drvdata(&of_dev->dev);
++                      else
++                              continue;
++
++                      if (fmt_port->p_tx_fm_port_dev &&
++                      fmt_port->p_rx_fm_port_dev && fmt_port->p_mac_dev)
++                              break;
++              } else if (((*uint32_prop + FM_MAX_NUM_OF_1G_RX_PORTS) ==
++                              fmt_port->id) &&
++                              fmt_port->port_type == e_IOC_FMT_PORT_T_RXTX) {
++
++                      of_dev = of_find_device_by_node(fm_port_node);
++                      if (unlikely(of_dev == NULL)) {
++                              _fmt_wrn("dtb fm id invalid value\n");
++                              return -EINVAL;
++                      }
++
++                      if (of_device_is_compatible(fm_port_node,
++                                           "fsl,fman-port-10g-tx")) {
++                              fmt_port->p_tx_port =
++                                              fm_port_bind(&of_dev->dev);
++                              fmt_port->p_tx_fm_port_dev = (void *)
++                                              fm_port_get_handle(
++                                                      fmt_port->p_tx_port);
++                      } else if (of_device_is_compatible(fm_port_node,
++                                                   "fsl,fman-port-10g-rx")) {
++                              fmt_port->p_rx_port =
++                                              fm_port_bind(&of_dev->dev);
++                              fmt_port->p_rx_fm_port_dev = (void *)
++                                              fm_port_get_handle(
++                                                      fmt_port->p_rx_port);
++                      } else if (of_device_is_compatible(fm_port_node,
++                                                      "fsl,fman-10g-mac") ||
++                                 of_device_is_compatible(fm_port_node,
++                                                      "fsl,fman-memac"))
++                              fmt_port->p_mac_dev =
++                                              (typeof(fmt_port->p_mac_dev))
++                                              dev_get_drvdata(&of_dev->dev);
++                      else
++                              continue;
++
++                      if (fmt_port->p_tx_fm_port_dev &&
++                      fmt_port->p_rx_fm_port_dev && fmt_port->p_mac_dev)
++                              break;
++                      }
++              } /* for_each_child */
++      }
++      } /* for each matching node */
++
++      if (fmt_port->p_tx_fm_port_dev == 0 ||
++              fmt_port->p_rx_fm_port_dev == 0) {
++
++              _fmt_err("bad fm port pointers.\n");
++              return -EINVAL;
++      }
++
++      _fmt_dbg("alloc %u tx queues.\n", fmt_port->num_of_tx_fqs);
++
++      /* init fman test egress dynamic frame queues */
++      for (i = 0; i < fmt_port->num_of_tx_fqs; i++) {
++              int _errno;
++              _errno = fmt_fq_alloc(
++                              &fmt_port->p_tx_fqs[i],
++                              &fmt_egress_fq,
++                              0,
++                              QMAN_FQ_FLAG_TO_DCPORTAL,
++                              fm_get_tx_port_channel(fmt_port->p_tx_port),
++                              i);
++
++              if (_errno < 0) {
++                      _fmt_err("tx queues allocation failed.\n");
++                      /* TODO: memory leak here if 1 queue is allocated and
++                      * next queues are failing ... */
++                      return -EINVAL;
++              }
++      }
++
++      /* port is valid and ready to use. */
++      fmt_port->valid  = TRUE;
++
++      _fmt_dbg("called.\n");
++      return 0;
++}
++
++/* fm test chardev functions */
++static int fmt_open(struct inode *inode, struct file *file)
++{
++      unsigned int minor = iminor(inode);
++
++      _fmt_dbg("calling...\n");
++
++      if (file->private_data != NULL)
++              return 0;
++
++      /* The minor represent the port number.
++       * Set the port structure accordingly, thus all the operations
++       * will be done on this port. */
++      if ((minor >= DEV_FM_TEST_PORTS_MINOR_BASE) &&
++          (minor < DEV_FM_TEST_MAX_MINORS))
++              file->private_data = &fm_test.ports[minor];
++      else
++              return -ENXIO;
++
++      _fmt_dbg("called.\n");
++      return 0;
++}
++
++static int fmt_close(struct inode *inode, struct file *file)
++{
++      struct fmt_port_s *fmt_port = NULL;
++      struct fmt_frame_s *fmt_frame = NULL;
++
++      int err = 0;
++
++      _fmt_dbg("calling...\n");
++
++      fmt_port = file->private_data;
++      if (!fmt_port)
++              return -ENODEV;
++
++      /* Close the current test port by invalidating it. */
++      fmt_port->valid = FALSE;
++
++      /* clean the fmt port queue */
++      while ((fmt_frame = dequeue_fmt_frame(fmt_port)) != NULL) {
++              if (fmt_frame && fmt_frame->buff.p_data){
++              kfree(fmt_frame->buff.p_data);
++              kfree(fmt_frame);
++      }
++      }
++
++      /* !!! the qman queues are cleaning from fm_ioctl...
++       * - very ugly */
++
++      _fmt_dbg("called.\n");
++      return err;
++}
++
++static int fmt_ioctls(unsigned int minor,
++                      struct file *file,
++                      unsigned int cmd,
++                      unsigned long arg,
++                      bool compat)
++{
++      struct fmt_port_s *fmt_port = NULL;
++
++      _fmt_dbg("IOCTL minor:%u "
++                " arg:0x%08lx ioctl cmd (0x%08x):(0x%02x:0x%02x.\n",
++                 minor, arg, cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
++
++      fmt_port = file->private_data;
++      if (!fmt_port) {
++              _fmt_err("invalid fmt port.\n");
++              return -ENODEV;
++      }
++
++      /* set test type properly */
++      if (compat)
++              fmt_port->compat_test_type = true;
++      else
++              fmt_port->compat_test_type = false;
++
++      switch (cmd) {
++      case FMT_PORT_IOC_INIT:
++      {
++              ioc_fmt_port_param_t param;
++
++              if (fmt_port->valid) {
++                      _fmt_wrn("port is already initialized.\n");
++                      return -EFAULT;
++              }
++#if defined(CONFIG_COMPAT)
++              if (compat) {
++                      if (copy_from_user(&param,
++                              (ioc_fmt_port_param_t  *)compat_ptr(arg),
++                              sizeof(ioc_fmt_port_param_t)))
++
++                              return -EFAULT;
++              } else
++#endif
++              {
++                      if (copy_from_user(&param,
++                              (ioc_fmt_port_param_t  *) arg,
++                              sizeof(ioc_fmt_port_param_t)))
++
++                              return -EFAULT;
++              }
++
++              return fmt_port_init(fmt_port, &param);
++      }
++
++      case FMT_PORT_IOC_SET_DIAG_MODE:
++              if (get_user(fmt_port->diag, (ioc_diag_mode  *)arg))
++                      return -EFAULT;
++
++              if (fmt_port->diag == e_IOC_DIAG_MODE_CTRL_LOOPBACK)
++                      return set_mac_int_loopback(fmt_port, TRUE);
++              else
++                      return set_mac_int_loopback(fmt_port, FALSE);
++      break;
++
++      case FMT_PORT_IOC_SET_DPAECHO_MODE:
++      case FMT_PORT_IOC_SET_IP_HEADER_MANIP:
++      default:
++              _fmt_wrn("ioctl unimplemented minor:%u@ioctl"
++                        " cmd:0x%08x(type:0x%02x, nr:0x%02x.\n",
++                        minor, cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
++      return -EFAULT;
++      }
++
++      return 0;
++}
++
++#ifdef CONFIG_COMPAT
++static long fmt_compat_ioctl(
++              struct file *file,
++              unsigned int cmd,
++              unsigned long arg)
++{
++      unsigned int minor = iminor(file->f_path.dentry->d_inode);
++
++      _fmt_dbg("calling...\n");
++      return fmt_ioctls(minor, file, cmd, arg, true);
++}
++#endif
++
++static long fmt_ioctl(
++              struct file *file,
++              unsigned int cmd,
++              unsigned long arg)
++{
++      unsigned int minor = iminor(file->f_path.dentry->d_inode);
++      unsigned int res;
++
++      _fmt_dbg("calling...\n");
++
++      fm_mutex_lock();
++      res = fmt_ioctls(minor, file, cmd, arg, false);
++      fm_mutex_unlock();
++
++      _fmt_dbg("called.\n");
++
++      return res;
++}
++
++#ifdef CONFIG_COMPAT
++void copy_compat_test_frame_buffer(
++              ioc_fmt_buff_desc_t *buff,
++              ioc_fmt_compat_buff_desc_t *compat_buff)
++{
++      compat_buff->qid = buff->qid;
++      compat_buff->p_data = ptr_to_compat(buff->p_data);
++      compat_buff->size = buff->size;
++      compat_buff->status = buff->status;
++
++      compat_buff->buff_context.p_user_priv =
++                      ptr_to_compat(buff->buff_context.p_user_priv);
++      memcpy(compat_buff->buff_context.fm_prs_res,
++                      buff->buff_context.fm_prs_res,
++                      FM_PRS_MAX * sizeof(uint8_t));
++      memcpy(compat_buff->buff_context.fm_time_stamp,
++                      buff->buff_context.fm_time_stamp,
++                      FM_TIME_STAMP_MAX * sizeof(uint8_t));
++}
++#endif
++
++ssize_t fmt_read(
++              struct file *file,
++              char __user *buf,
++              size_t size,
++              loff_t *ppos)
++{
++      struct fmt_port_s *fmt_port = NULL;
++      struct fmt_frame_s *p_fmt_frame = NULL;
++      ssize_t cnt = 0;
++
++      fmt_port = file->private_data;
++      if (!fmt_port || !fmt_port->valid) {
++              _fmt_err("fmt port not valid!\n");
++              return -ENODEV;
++      }
++
++      p_fmt_frame = dequeue_fmt_frame(fmt_port);
++      if (p_fmt_frame == NULL)
++              return 0;
++
++      _fmt_dbgr("calling...\n");
++
++#ifdef CONFIG_COMPAT
++      if (fmt_port->compat_test_type){
++              cnt = sizeof(ioc_fmt_compat_buff_desc_t);
++      }
++      else
++#endif
++      {
++              cnt = sizeof(ioc_fmt_buff_desc_t);
++      }
++
++      if (size < cnt) {
++              _fmt_err("illegal buffer-size!\n");
++              cnt = 0;
++              goto _fmt_read_return;
++      }
++
++        /* Copy structure */
++#ifdef CONFIG_COMPAT
++      if (fmt_port->compat_test_type) {
++              {
++                      ioc_fmt_compat_buff_desc_t compat_buff;
++                      copy_compat_test_frame_buffer(&p_fmt_frame->buff,
++                                                              &compat_buff);
++
++                      if (copy_to_user(buf, &compat_buff, cnt)) {
++                              _fmt_err("copy_to_user failed!\n");
++                              goto _fmt_read_return;
++                      }
++              }
++
++              ((ioc_fmt_compat_buff_desc_t  *)buf)->p_data =
++                      ptr_to_compat(buf+sizeof(ioc_fmt_compat_buff_desc_t));
++              cnt += MIN(p_fmt_frame->buff.size, size-cnt);
++      } else
++#endif
++      {
++              if (copy_to_user(buf, &p_fmt_frame->buff, cnt)) {
++                      _fmt_err("copy_to_user failed!\n");
++                      goto _fmt_read_return;
++              }
++
++              ((ioc_fmt_buff_desc_t  *)buf)->p_data =
++                              buf + sizeof(ioc_fmt_buff_desc_t);
++              cnt += MIN(p_fmt_frame->buff.size, size-cnt);
++      }
++
++      if (size < cnt) {
++              _fmt_err("illegal buffer-size!\n");
++              goto _fmt_read_return;
++      }
++
++      /* copy frame */
++#ifdef CONFIG_COMPAT
++      if (fmt_port->compat_test_type) {
++              if (copy_to_user(buf+sizeof(ioc_fmt_compat_buff_desc_t),
++                                      p_fmt_frame->buff.p_data, cnt)) {
++                      _fmt_err("copy_to_user failed!\n");
++                      goto _fmt_read_return;
++              }
++      } else
++#endif
++      {
++              if (copy_to_user(buf+sizeof(ioc_fmt_buff_desc_t),
++                                      p_fmt_frame->buff.p_data, cnt)) {
++                      _fmt_err("copy_to_user failed!\n");
++                      goto _fmt_read_return;
++              }
++      }
++
++_fmt_read_return:
++      kfree(p_fmt_frame->buff.p_data);
++      kfree(p_fmt_frame);
++
++      _fmt_dbgr("called.\n");
++      return cnt;
++}
++
++ssize_t fmt_write(
++              struct file *file,
++              const char __user *buf,
++              size_t size,
++              loff_t *ppos)
++{
++      struct fmt_port_s *fmt_port = NULL;
++      ioc_fmt_buff_desc_t buff_desc;
++#ifdef CONFIG_COMPAT
++      ioc_fmt_compat_buff_desc_t buff_desc_compat;
++#endif
++      uint8_t *p_data = NULL;
++      uint32_t data_offset;
++      int _errno;
++      t_DpaaFD fd;
++
++      _fmt_dbgr("calling...\n");
++
++      fmt_port = file->private_data;
++      if (!fmt_port || !fmt_port->valid) {
++              _fmt_err("fmt port not valid.\n");
++              return -EINVAL;
++      }
++
++    /* If Compat (32B UserSpace - 64B KernelSpace)  */
++#ifdef CONFIG_COMPAT
++      if (fmt_port->compat_test_type) {
++              if (size < sizeof(ioc_fmt_compat_buff_desc_t)) {
++                      _fmt_err("invalid buff_desc size.\n");
++                      return -EFAULT;
++              }
++
++              if (copy_from_user(&buff_desc_compat, buf,
++                                      sizeof(ioc_fmt_compat_buff_desc_t)))
++                      return -EFAULT;
++
++              buff_desc.qid = buff_desc_compat.qid;
++              buff_desc.p_data = compat_ptr(buff_desc_compat.p_data);
++              buff_desc.size = buff_desc_compat.size;
++              buff_desc.status = buff_desc_compat.status;
++
++              buff_desc.buff_context.p_user_priv =
++                      compat_ptr(buff_desc_compat.buff_context.p_user_priv);
++              memcpy(buff_desc.buff_context.fm_prs_res,
++                              buff_desc_compat.buff_context.fm_prs_res,
++                              FM_PRS_MAX * sizeof(uint8_t));
++              memcpy(buff_desc.buff_context.fm_time_stamp,
++                              buff_desc_compat.buff_context.fm_time_stamp,
++                              FM_TIME_STAMP_MAX * sizeof(uint8_t));
++      } else
++#endif
++      {
++              if (size < sizeof(ioc_fmt_buff_desc_t)) {
++                      _fmt_err("invalid buff_desc size.\n");
++                      return -EFAULT;
++              }
++
++              if (copy_from_user(&buff_desc, (ioc_fmt_buff_desc_t  *)buf,
++                                      sizeof(ioc_fmt_buff_desc_t)))
++                      return -EFAULT;
++      }
++
++      data_offset = FM_PORT_GetBufferDataOffset(fmt_port->p_tx_fm_port_dev);
++      p_data = kmalloc(buff_desc.size+data_offset, GFP_KERNEL);
++      if (!p_data)
++              return -ENOMEM;
++
++      /* If Compat (32UserSpace - 64KernelSpace) the buff_desc.p_data is ok */
++      if (copy_from_user((uint8_t *)PTR_MOVE(p_data, data_offset),
++                              buff_desc.p_data,
++                              buff_desc.size)) {
++              kfree(p_data);
++              return -EFAULT;
++      }
++
++      /* TODO: dma_map_single here (cannot access the bpool struct) */
++
++      /* prepare fd */
++      memset(&fd, 0, sizeof(fd));
++      DPAA_FD_SET_ADDR(&fd, p_data);
++      DPAA_FD_SET_OFFSET(&fd, data_offset);
++      DPAA_FD_SET_LENGTH(&fd, buff_desc.size);
++
++      _errno = qman_enqueue(&fmt_port->p_tx_fqs[buff_desc.qid].fq_base,
++                                                      (struct qm_fd *)&fd, 0);
++      if (_errno) {
++              buff_desc.status = (uint32_t)_errno;
++              if (copy_to_user((ioc_fmt_buff_desc_t *)buf, &buff_desc,
++                                              sizeof(ioc_fmt_buff_desc_t))) {
++                      kfree(p_data);
++                      return -EFAULT;
++              }
++      }
++
++      /* for debugging */
++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
++      atomic_inc(&fmt_port->enqueue_to_qman_frm);
++#endif
++      _fmt_dbgr("called.\n");
++      return buff_desc.size;
++}
++
++/* fm test character device definition */
++static const struct file_operations fmt_fops =
++{
++      .owner                  = THIS_MODULE,
++#ifdef CONFIG_COMPAT
++      .compat_ioctl           = fmt_compat_ioctl,
++#endif
++      .unlocked_ioctl         = fmt_ioctl,
++      .open                   = fmt_open,
++      .release                = fmt_close,
++      .read                   = fmt_read,
++      .write                  = fmt_write,
++};
++
++static int fmt_init(void)
++{
++      int id;
++
++      _fmt_dbg("calling...\n");
++
++      /* Register to the /dev for IOCTL API */
++      /* Register dynamically a new major number for the character device: */
++      fm_test.major = register_chrdev(0, DEV_FM_TEST_NAME, &fmt_fops);
++      if (fm_test.major  <= 0) {
++              _fmt_wrn("Failed to allocate major number for device %s.\n",
++                                                      DEV_FM_TEST_NAME);
++              return -ENODEV;
++      }
++
++      /* Creating class for FMan_test */
++      fm_test.fmt_class = class_create(THIS_MODULE, DEV_FM_TEST_NAME);
++      if (IS_ERR(fm_test.fmt_class)) {
++              unregister_chrdev(fm_test.major, DEV_FM_TEST_NAME);
++              _fmt_wrn("Error creating %s class.\n", DEV_FM_TEST_NAME);
++              return -ENODEV;
++      }
++
++      for (id = 0; id < IOC_FMT_MAX_NUM_OF_PORTS; id++)
++              if (NULL == device_create(fm_test.fmt_class, NULL,
++                              MKDEV(fm_test.major,
++                              DEV_FM_TEST_PORTS_MINOR_BASE + id), NULL,
++                              DEV_FM_TEST_NAME "%d", id)) {
++
++                      _fmt_err("Error creating %s device.\n",
++                                                      DEV_FM_TEST_NAME);
++                      return -ENODEV;
++              }
++
++      return 0;
++}
++
++static void  fmt_free(void)
++{
++      int id;
++
++      for (id = 0; id < IOC_FMT_MAX_NUM_OF_PORTS; id++)
++              device_destroy(fm_test.fmt_class, MKDEV(fm_test.major,
++                      DEV_FM_TEST_PORTS_MINOR_BASE + id));
++      class_destroy(fm_test.fmt_class);
++}
++
++static int __init __cold fmt_load(void)
++{
++      struct dpaa_eth_hooks_s priv_dpaa_eth_hooks;
++
++      /* set dpaa hooks for default queues */
++      memset(&priv_dpaa_eth_hooks, 0, sizeof(priv_dpaa_eth_hooks));
++      priv_dpaa_eth_hooks.rx_default = fmt_rx_default_hook;
++      priv_dpaa_eth_hooks.rx_error = fmt_rx_error_hook;
++      priv_dpaa_eth_hooks.tx_confirm = fmt_tx_confirm_hook;
++      priv_dpaa_eth_hooks.tx_error = fmt_tx_confirm_error_hook;
++
++      fsl_dpaa_eth_set_hooks(&priv_dpaa_eth_hooks);
++
++      /* initialize the fman test environment */
++      if (fmt_init() < 0) {
++              _fmt_err("Failed to init FM-test modul.\n");
++              fmt_free();
++              return -ENODEV;
++      }
++
++      _fmt_inf("FSL FM test module loaded.\n");
++
++      return 0;
++}
++
++static void __exit __cold fmt_unload(void)
++{
++      fmt_free();
++      _fmt_inf("FSL FM test module unloaded.\n");
++}
++
++module_init(fmt_load);
++module_exit(fmt_unload);
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
+@@ -0,0 +1,2908 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ @File          lnxwrp_fm.c
++ @Author        Shlomi Gridish
++ @Description   FM Linux wrapper functions.
++*/
++
++#include <linux/version.h>
++#include <linux/slab.h>
++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
++#define MODVERSIONS
++#endif
++#ifdef MODVERSIONS
++#include <config/modversions.h>
++#endif /* MODVERSIONS */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/device.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/of_platform.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/clk.h>
++#include <asm/uaccess.h>
++#include <asm/errno.h>
++#ifndef CONFIG_FMAN_ARM
++#include <sysdev/fsl_soc.h>
++#include <linux/fsl/guts.h>
++#include <linux/fsl/svr.h>
++#endif
++#include <linux/stat.h>          /* For file access mask */
++#include <linux/skbuff.h>
++#include <linux/proc_fs.h>
++
++/* NetCommSw Headers --------------- */
++#include "std_ext.h"
++#include "error_ext.h"
++#include "sprint_ext.h"
++#include "debug_ext.h"
++#include "sys_io_ext.h"
++
++#include "fm_ioctls.h"
++
++#include "lnxwrp_fm.h"
++#include "lnxwrp_resources.h"
++#include "lnxwrp_sysfs_fm.h"
++#include "lnxwrp_sysfs_fm_port.h"
++#include "lnxwrp_exp_sym.h"
++#include "fm_common.h"
++#include "../../sdk_fman/Peripherals/FM/fm.h"
++#define __ERR_MODULE__  MODULE_FM
++
++extern struct device_node *GetFmPortAdvArgsDevTreeNode (struct device_node *fm_node,
++                                                         e_FmPortType       portType,
++                                                         uint8_t            portId);
++
++#define PROC_PRINT(args...) offset += sprintf(buf+offset,args)
++
++#define ADD_ADV_CONFIG_NO_RET(_func, _param)    \
++    do {                                        \
++        if (i<max){                             \
++            p_Entry = &p_Entrys[i];             \
++            p_Entry->p_Function = _func;        \
++            _param                              \
++            i++;                                \
++        }                                       \
++        else                                    \
++            REPORT_ERROR(MAJOR, E_INVALID_VALUE,\
++                         ("Number of advanced-configuration entries exceeded"));\
++    } while (0)
++
++/* Bootarg used to override the Kconfig FSL_FM_MAX_FRAME_SIZE value */
++#define FSL_FM_MAX_FRM_BOOTARG     "fsl_fm_max_frm"
++
++/* Bootarg used to override FSL_FM_RX_EXTRA_HEADROOM Kconfig value */
++#define FSL_FM_RX_EXTRA_HEADROOM_BOOTARG  "fsl_fm_rx_extra_headroom"
++
++/* Minimum and maximum value for the fsl_fm_rx_extra_headroom bootarg */
++#define FSL_FM_RX_EXTRA_HEADROOM_MIN 16
++#define FSL_FM_RX_EXTRA_HEADROOM_MAX 384
++
++#define FSL_FM_PAUSE_TIME_ENABLE 0xf000
++#define FSL_FM_PAUSE_TIME_DISABLE 0
++#define FSL_FM_PAUSE_THRESH_DEFAULT 0
++
++/*
++ * Max frame size, across all interfaces.
++ * Configurable from Kconfig or bootargs, to avoid allocating
++ * oversized (socket) buffers when not using jumbo frames.
++ * Must be large enough to accommodate the network MTU, but small enough
++ * to avoid wasting skb memory.
++ *
++ * Could be overridden once, at boot-time, via the
++ * fm_set_max_frm() callback.
++ */
++int fsl_fm_max_frm = CONFIG_FSL_FM_MAX_FRAME_SIZE;
++
++/*
++ * Extra headroom for Rx buffers.
++ * FMan is instructed to allocate, on the Rx path, this amount of
++ * space at the beginning of a data buffer, beside the DPA private
++ * data area and the IC fields.
++ * Does not impact Tx buffer layout.
++ *
++ * Configurable from Kconfig or bootargs. Zero by default, it's needed
++ * on particular forwarding scenarios that add extra headers to the
++ * forwarded frame.
++ */
++int fsl_fm_rx_extra_headroom = CONFIG_FSL_FM_RX_EXTRA_HEADROOM;
++
++#ifdef CONFIG_FMAN_PFC
++static int fsl_fm_pfc_quanta[] = {
++              CONFIG_FMAN_PFC_QUANTA_0,
++              CONFIG_FMAN_PFC_QUANTA_1,
++              CONFIG_FMAN_PFC_QUANTA_2,
++              CONFIG_FMAN_PFC_QUANTA_3
++};
++#endif
++
++static t_LnxWrpFm   lnxWrpFm;
++
++int fm_get_max_frm()
++{
++      return fsl_fm_max_frm;
++}
++EXPORT_SYMBOL(fm_get_max_frm);
++
++int fm_get_rx_extra_headroom()
++{
++      return ALIGN(fsl_fm_rx_extra_headroom, 16);
++}
++EXPORT_SYMBOL(fm_get_rx_extra_headroom);
++
++static int __init fm_set_max_frm(char *str)
++{
++      int ret = 0;
++
++      ret = get_option(&str, &fsl_fm_max_frm);
++      if (ret != 1) {
++              /*
++               * This will only work if CONFIG_EARLY_PRINTK is compiled in,
++               * and something like "earlyprintk=serial,uart0,115200" is
++               * specified in the bootargs
++               */
++              printk(KERN_WARNING "No suitable %s=<int> prop in bootargs; "
++                      "will use the default FSL_FM_MAX_FRAME_SIZE (%d) "
++                      "from Kconfig.\n", FSL_FM_MAX_FRM_BOOTARG,
++                      CONFIG_FSL_FM_MAX_FRAME_SIZE);
++
++              fsl_fm_max_frm = CONFIG_FSL_FM_MAX_FRAME_SIZE;
++              return 1;
++      }
++
++      /* Don't allow invalid bootargs; fallback to the Kconfig value */
++      if (fsl_fm_max_frm < 64 || fsl_fm_max_frm > 9600) {
++              printk(KERN_WARNING "Invalid %s=%d in bootargs, valid range is "
++                      "64-9600. Falling back to the FSL_FM_MAX_FRAME_SIZE (%d) "
++                      "from Kconfig.\n",
++                      FSL_FM_MAX_FRM_BOOTARG, fsl_fm_max_frm,
++                      CONFIG_FSL_FM_MAX_FRAME_SIZE);
++
++              fsl_fm_max_frm = CONFIG_FSL_FM_MAX_FRAME_SIZE;
++              return 1;
++      }
++
++      printk(KERN_INFO "Using fsl_fm_max_frm=%d from bootargs\n",
++              fsl_fm_max_frm);
++      return 0;
++}
++early_param(FSL_FM_MAX_FRM_BOOTARG, fm_set_max_frm);
++
++static int __init fm_set_rx_extra_headroom(char *str)
++{
++      int ret;
++
++      ret = get_option(&str, &fsl_fm_rx_extra_headroom);
++
++      if (ret != 1) {
++              printk(KERN_WARNING "No suitable %s=<int> prop in bootargs; "
++                      "will use the default FSL_FM_RX_EXTRA_HEADROOM (%d) "
++                      "from Kconfig.\n", FSL_FM_RX_EXTRA_HEADROOM_BOOTARG,
++                      CONFIG_FSL_FM_RX_EXTRA_HEADROOM);
++              fsl_fm_rx_extra_headroom = CONFIG_FSL_FM_RX_EXTRA_HEADROOM;
++
++              return 1;
++      }
++
++      if (fsl_fm_rx_extra_headroom < FSL_FM_RX_EXTRA_HEADROOM_MIN ||
++              fsl_fm_rx_extra_headroom > FSL_FM_RX_EXTRA_HEADROOM_MAX) {
++              printk(KERN_WARNING "Invalid value for %s=%d prop in "
++                      "bootargs; will use the default "
++                      "FSL_FM_RX_EXTRA_HEADROOM (%d) from Kconfig.\n",
++                      FSL_FM_RX_EXTRA_HEADROOM_BOOTARG,
++                      fsl_fm_rx_extra_headroom,
++                      CONFIG_FSL_FM_RX_EXTRA_HEADROOM);
++              fsl_fm_rx_extra_headroom = CONFIG_FSL_FM_RX_EXTRA_HEADROOM;
++      }
++
++      printk(KERN_INFO "Using fsl_fm_rx_extra_headroom=%d from bootargs\n",
++              fsl_fm_rx_extra_headroom);
++
++      return 0;
++}
++early_param(FSL_FM_RX_EXTRA_HEADROOM_BOOTARG, fm_set_rx_extra_headroom);
++
++static irqreturn_t fm_irq(int irq, void *_dev)
++{
++    t_LnxWrpFmDev       *p_LnxWrpFmDev = (t_LnxWrpFmDev *)_dev;
++#ifdef CONFIG_PM_SLEEP
++    t_Fm               *p_Fm = (t_Fm*)p_LnxWrpFmDev->h_Dev;
++#endif
++    if (!p_LnxWrpFmDev || !p_LnxWrpFmDev->h_Dev)
++        return IRQ_NONE;
++
++#ifdef CONFIG_PM_SLEEP
++    if (fman_get_normal_pending(p_Fm->p_FmFpmRegs) & INTR_EN_WAKEUP)
++    {
++        pm_wakeup_event(p_LnxWrpFmDev->dev, 200);        
++    }
++#endif
++    FM_EventIsr(p_LnxWrpFmDev->h_Dev);
++    return IRQ_HANDLED;
++}
++
++static irqreturn_t fm_err_irq(int irq, void *_dev)
++{
++    t_LnxWrpFmDev       *p_LnxWrpFmDev = (t_LnxWrpFmDev *)_dev;
++
++    if (!p_LnxWrpFmDev || !p_LnxWrpFmDev->h_Dev)
++        return IRQ_NONE;
++
++    if (FM_ErrorIsr(p_LnxWrpFmDev->h_Dev) == E_OK)
++        return IRQ_HANDLED;
++
++    return IRQ_NONE;
++}
++
++/* used to protect FMD/LLD from concurrent calls in functions fm_mutex_lock / fm_mutex_unlock */
++static struct mutex   lnxwrp_mutex;
++
++static t_LnxWrpFmDev * CreateFmDev(uint8_t  id)
++{
++    t_LnxWrpFmDev   *p_LnxWrpFmDev;
++    int             j;
++
++    p_LnxWrpFmDev = (t_LnxWrpFmDev *)XX_Malloc(sizeof(t_LnxWrpFmDev));
++    if (!p_LnxWrpFmDev)
++    {
++        REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++        return NULL;
++    }
++
++    memset(p_LnxWrpFmDev, 0, sizeof(t_LnxWrpFmDev));
++    p_LnxWrpFmDev->fmDevSettings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry));
++    memset(p_LnxWrpFmDev->fmDevSettings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)));
++    p_LnxWrpFmDev->fmPcdDevSettings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry));
++    memset(p_LnxWrpFmDev->fmPcdDevSettings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)));
++    p_LnxWrpFmDev->hcPort.settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry));
++    memset(p_LnxWrpFmDev->hcPort.settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)));
++    for (j=0; j<FM_MAX_NUM_OF_RX_PORTS; j++)
++    {
++        p_LnxWrpFmDev->rxPorts[j].settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry));
++        memset(p_LnxWrpFmDev->rxPorts[j].settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)));
++    }
++    for (j=0; j<FM_MAX_NUM_OF_TX_PORTS; j++)
++    {
++        p_LnxWrpFmDev->txPorts[j].settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry));
++        memset(p_LnxWrpFmDev->txPorts[j].settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)));
++    }
++    for (j=0; j<FM_MAX_NUM_OF_OH_PORTS-1; j++)
++    {
++        p_LnxWrpFmDev->opPorts[j].settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry));
++        memset(p_LnxWrpFmDev->opPorts[j].settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)));
++    }
++
++    return p_LnxWrpFmDev;
++}
++
++static void DestroyFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev)
++{
++    int             j;
++
++    for (j=0; j<FM_MAX_NUM_OF_OH_PORTS-1; j++)
++        if (p_LnxWrpFmDev->opPorts[j].settings.advConfig)
++            XX_Free(p_LnxWrpFmDev->opPorts[j].settings.advConfig);
++    for (j=0; j<FM_MAX_NUM_OF_TX_PORTS; j++)
++        if (p_LnxWrpFmDev->txPorts[j].settings.advConfig)
++            XX_Free(p_LnxWrpFmDev->txPorts[j].settings.advConfig);
++    for (j=0; j<FM_MAX_NUM_OF_RX_PORTS; j++)
++        if (p_LnxWrpFmDev->rxPorts[j].settings.advConfig)
++            XX_Free(p_LnxWrpFmDev->rxPorts[j].settings.advConfig);
++    if (p_LnxWrpFmDev->hcPort.settings.advConfig)
++        XX_Free(p_LnxWrpFmDev->hcPort.settings.advConfig);
++    if (p_LnxWrpFmDev->fmPcdDevSettings.advConfig)
++        XX_Free(p_LnxWrpFmDev->fmPcdDevSettings.advConfig);
++    if (p_LnxWrpFmDev->fmDevSettings.advConfig)
++        XX_Free(p_LnxWrpFmDev->fmDevSettings.advConfig);
++
++    XX_Free(p_LnxWrpFmDev);
++}
++
++static t_Error FillRestFmInfo(t_LnxWrpFmDev *p_LnxWrpFmDev)
++{
++#define FM_BMI_PPIDS_OFFSET                 0x00080304
++#define FM_DMA_PLR_OFFSET                   0x000c2060
++#define FM_FPM_IP_REV_1_OFFSET              0x000c30c4
++#define DMA_HIGH_LIODN_MASK                 0x0FFF0000
++#define DMA_LOW_LIODN_MASK                  0x00000FFF
++#define DMA_LIODN_SHIFT                     16
++
++typedef _Packed struct {
++    uint32_t    plr[32];
++} _PackedType t_Plr;
++
++typedef _Packed struct {
++   volatile uint32_t   fmbm_ppid[63];
++} _PackedType t_Ppids;
++
++    t_Plr       *p_Plr;
++    t_Ppids     *p_Ppids;
++    int         i,j;
++    uint32_t    fmRev;
++
++    static const uint8_t     phys1GRxPortId[] = {0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf};
++    static const uint8_t     phys10GRxPortId[] = {0x10,0x11};
++#if (DPAA_VERSION >= 11)
++    static const uint8_t     physOhPortId[] = {/* 0x1, */0x2,0x3,0x4,0x5,0x6,0x7};
++#else
++    static const uint8_t     physOhPortId[] = {0x1,0x2,0x3,0x4,0x5,0x6,0x7};
++#endif
++    static const uint8_t     phys1GTxPortId[] = {0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f};
++    static const uint8_t     phys10GTxPortId[] = {0x30,0x31};
++
++    fmRev = (uint32_t)(*((volatile uint32_t *)UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr+FM_FPM_IP_REV_1_OFFSET)));
++    fmRev &= 0xffff;
++
++    p_Plr = (t_Plr *)UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr+FM_DMA_PLR_OFFSET);
++#ifdef MODULE
++    for (i=0;i<FM_MAX_NUM_OF_PARTITIONS/2;i++)
++        p_Plr->plr[i] = 0;
++#endif /* MODULE */
++
++    for (i=0; i<FM_MAX_NUM_OF_PARTITIONS; i++)
++    {
++        uint16_t liodnBase = (uint16_t)((i%2) ?
++                       (p_Plr->plr[i/2] & DMA_LOW_LIODN_MASK) :
++                       ((p_Plr->plr[i/2] & DMA_HIGH_LIODN_MASK) >> DMA_LIODN_SHIFT));
++#ifdef FM_PARTITION_ARRAY
++        /* TODO: this was .liodnPerPartition[i] = liodnBase; is the index meaning the same? */
++        p_LnxWrpFmDev->fmDevSettings.param.liodnBasePerPort[i] = liodnBase;
++#endif /* FM_PARTITION_ARRAY */
++
++        if ((i >= phys1GRxPortId[0]) &&
++             (i <= phys1GRxPortId[FM_MAX_NUM_OF_1G_RX_PORTS-1]))
++        {
++            for (j=0; j<ARRAY_SIZE(phys1GRxPortId); j++)
++                if (phys1GRxPortId[j] == i)
++                    break;
++            ASSERT_COND(j<ARRAY_SIZE(phys1GRxPortId));
++            p_LnxWrpFmDev->rxPorts[j].settings.param.liodnBase = liodnBase;
++        }
++        else if (FM_MAX_NUM_OF_10G_RX_PORTS &&
++                 (i >= phys10GRxPortId[0]) &&
++                 (i <= phys10GRxPortId[FM_MAX_NUM_OF_10G_RX_PORTS-1]))
++        {
++            for (j=0; j<ARRAY_SIZE(phys10GRxPortId); j++)
++                if (phys10GRxPortId[j] == i)
++                    break;
++            ASSERT_COND(j<ARRAY_SIZE(phys10GRxPortId));
++            p_LnxWrpFmDev->rxPorts[FM_MAX_NUM_OF_1G_RX_PORTS+j].settings.param.liodnBase = liodnBase;
++        }
++        else if ((i >= physOhPortId[0]) &&
++                 (i <= physOhPortId[FM_MAX_NUM_OF_OH_PORTS-1]))
++        {
++            for (j=0; j<ARRAY_SIZE(physOhPortId); j++)
++                if (physOhPortId[j] == i)
++                    break;
++            ASSERT_COND(j<ARRAY_SIZE(physOhPortId));
++            if (j == 0)
++                p_LnxWrpFmDev->hcPort.settings.param.liodnBase = liodnBase;
++            else
++                p_LnxWrpFmDev->opPorts[j - 1].settings.param.liodnBase = liodnBase;
++        }
++        else if ((i >= phys1GTxPortId[0]) &&
++                  (i <= phys1GTxPortId[FM_MAX_NUM_OF_1G_TX_PORTS-1]))
++        {
++            for (j=0; j<ARRAY_SIZE(phys1GTxPortId); j++)
++                if (phys1GTxPortId[j] == i)
++                    break;
++            ASSERT_COND(j<ARRAY_SIZE(phys1GTxPortId));
++            p_LnxWrpFmDev->txPorts[j].settings.param.liodnBase = liodnBase;
++        }
++        else if (FM_MAX_NUM_OF_10G_TX_PORTS &&
++                 (i >= phys10GTxPortId[0]) &&
++                 (i <= phys10GTxPortId[FM_MAX_NUM_OF_10G_TX_PORTS-1]))
++        {
++            for (j=0; j<ARRAY_SIZE(phys10GTxPortId); j++)
++                if (phys10GTxPortId[j] == i)
++                    break;
++            ASSERT_COND(j<ARRAY_SIZE(phys10GTxPortId));
++            p_LnxWrpFmDev->txPorts[FM_MAX_NUM_OF_1G_TX_PORTS+j].settings.param.liodnBase = liodnBase;
++        }
++    }
++
++    p_Ppids = (t_Ppids *)UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr+FM_BMI_PPIDS_OFFSET);
++
++    for (i=0; i<FM_MAX_NUM_OF_1G_RX_PORTS; i++)
++        p_LnxWrpFmDev->rxPorts[i].settings.param.specificParams.rxParams.liodnOffset =
++                p_Ppids->fmbm_ppid[phys1GRxPortId[i]-1];
++
++    for (i=0; i<FM_MAX_NUM_OF_10G_RX_PORTS; i++)
++            p_LnxWrpFmDev->rxPorts[FM_MAX_NUM_OF_1G_RX_PORTS+i].settings.param.specificParams.rxParams.liodnOffset =
++                p_Ppids->fmbm_ppid[phys10GRxPortId[i]-1];
++
++    return E_OK;
++}
++
++/* Structure that defines QE firmware binary files.
++ *
++ * See Documentation/powerpc/qe_firmware.txt for a description of these
++ * fields.
++ */
++struct qe_firmware {
++        struct qe_header {
++                __be32 length;  /* Length of the entire structure, in bytes */
++                u8 magic[3];    /* Set to { 'Q', 'E', 'F' } */
++                u8 version;     /* Version of this layout. First ver is '1' */
++        } header;
++        u8 id[62];      /* Null-terminated identifier string */
++        u8 split;       /* 0 = shared I-RAM, 1 = split I-RAM */
++        u8 count;       /* Number of microcode[] structures */
++        struct {
++                __be16 model;           /* The SOC model  */
++                u8 major;               /* The SOC revision major */
++                u8 minor;               /* The SOC revision minor */
++        } __attribute__ ((packed)) soc;
++        u8 padding[4];                  /* Reserved, for alignment */
++        __be64 extended_modes;          /* Extended modes */
++        __be32 vtraps[8];               /* Virtual trap addresses */
++        u8 reserved[4];                 /* Reserved, for future expansion */
++        struct qe_microcode {
++                u8 id[32];              /* Null-terminated identifier */
++                __be32 traps[16];       /* Trap addresses, 0 == ignore */
++                __be32 eccr;            /* The value for the ECCR register */
++                __be32 iram_offset;     /* Offset into I-RAM for the code */
++                __be32 count;           /* Number of 32-bit words of the code */
++                __be32 code_offset;     /* Offset of the actual microcode */
++                u8 major;               /* The microcode version major */
++                u8 minor;               /* The microcode version minor */
++                u8 revision;            /* The microcode version revision */
++                u8 padding;             /* Reserved, for alignment */
++                u8 reserved[4];         /* Reserved, for future expansion */
++        } __attribute__ ((packed)) microcode[1];
++        /* All microcode binaries should be located here */
++        /* CRC32 should be located here, after the microcode binaries */
++} __attribute__ ((packed));
++
++
++/**
++ * FindFmanMicrocode - find the Fman microcode
++ *
++ * This function returns a pointer to the QE Firmware blob that holds
++ * the Fman microcode.  We use the QE Firmware structure because Fman microcode
++ * is similar to QE microcode, so there's no point in defining a new layout.
++ *
++ * Current versions of U-Boot embed the Fman firmware into the device tree,
++ * so we check for that first.  Each Fman node in the device tree contains a
++ * node or a pointer to node that holds the firmware.  Technically, we should
++ * be fetching the firmware node for the current Fman, but we don't have that
++ * information any more, so we assume that there is only one firmware node in
++ * the device tree, and that all Fmen use the same firmware.
++ */
++static const struct qe_firmware *FindFmanMicrocode(void)
++{
++    static const struct qe_firmware *P4080_UCPatch;
++    struct device_node *np;
++
++    if (P4080_UCPatch)
++          return P4080_UCPatch;
++
++    /* The firmware should be inside the device tree. */
++    np = of_find_compatible_node(NULL, NULL, "fsl,fman-firmware");
++    if (np) {
++          P4080_UCPatch = of_get_property(np, "fsl,firmware", NULL);
++            of_node_put(np);
++          if (P4080_UCPatch)
++                  return P4080_UCPatch;
++          else
++                  REPORT_ERROR(WARNING, E_NOT_FOUND, ("firmware node is incomplete"));
++    }
++
++    /* Returning NULL here forces the reuse of the IRAM content */
++    return NULL;
++}
++#define SVR_SECURITY_MASK    0x00080000
++#define SVR_PERSONALITY_MASK 0x0000FF00
++#define SVR_VER_IGNORE_MASK (SVR_SECURITY_MASK | SVR_PERSONALITY_MASK)
++#define SVR_B4860_REV1_VALUE 0x86800010
++#define SVR_B4860_REV2_VALUE 0x86800020
++#define SVR_T4240_VALUE      0x82400000
++#define SVR_T4120_VALUE      0x82400100
++#define SVR_T4160_VALUE      0x82410000
++#define SVR_T4080_VALUE      0x82410200
++#define SVR_T4_DEVICE_ID     0x82400000
++#define SVR_DEVICE_ID_MASK   0xFFF00000
++
++#define OF_DEV_ID_NUM 2 /* one used, another one zeroed */
++
++/* searches for a subnode with the given name/compatible  */
++static bool HasFmPcdOfNode(struct device_node *fm_node,
++                           struct of_device_id *ids,
++                           const char *name,
++                           const char *compatible)
++{
++    struct device_node *dev_node;
++    bool ret = false;
++
++    memset(ids, 0, OF_DEV_ID_NUM*sizeof(struct of_device_id));
++    if (WARN_ON(strlen(name) >= sizeof(ids[0].name)))
++        return false;
++    strcpy(ids[0].name, name);
++    if (WARN_ON(strlen(compatible) >= sizeof(ids[0].compatible)))
++        return false;
++    strcpy(ids[0].compatible, compatible);
++    for_each_child_of_node(fm_node, dev_node)
++        if (of_match_node(ids, dev_node) != NULL)
++            ret = true;
++    return ret;
++}
++
++static t_LnxWrpFmDev * ReadFmDevTreeNode (struct platform_device *of_dev)
++{
++    t_LnxWrpFmDev       *p_LnxWrpFmDev;
++    struct device_node  *fm_node, *dev_node;
++    struct of_device_id ids[OF_DEV_ID_NUM];
++    struct resource     res;
++    struct clk *clk;
++    u32 clk_rate;
++    const uint32_t      *uint32_prop;
++    int                 _errno=0, lenp;
++    uint32_t            tmp_prop;
++
++    fm_node = of_node_get(of_dev->dev.of_node);
++
++    uint32_prop = (uint32_t *)of_get_property(fm_node, "cell-index", &lenp);
++    if (unlikely(uint32_prop == NULL)) {
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_get_property(%s, cell-index) failed", fm_node->full_name));
++        return NULL;
++    }
++    tmp_prop = be32_to_cpu(*uint32_prop);
++
++    if (WARN_ON(lenp != sizeof(uint32_t)))
++        return NULL;
++
++    if (tmp_prop > INTG_MAX_NUM_OF_FM) {
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!"));
++        return NULL;
++    }
++    p_LnxWrpFmDev = CreateFmDev(tmp_prop);
++    if (!p_LnxWrpFmDev) {
++        REPORT_ERROR(MAJOR, E_NULL_POINTER, NO_MSG);
++        return NULL;
++    }
++    p_LnxWrpFmDev->dev = &of_dev->dev;
++    p_LnxWrpFmDev->id = tmp_prop;
++
++    /* Get the FM interrupt */
++    p_LnxWrpFmDev->irq = of_irq_to_resource(fm_node, 0, NULL);
++    if (unlikely(p_LnxWrpFmDev->irq == /*NO_IRQ*/0)) {
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_irq_to_resource() = %d", NO_IRQ));
++        DestroyFmDev(p_LnxWrpFmDev);
++        return NULL;
++    }
++
++    /* Get the FM error interrupt */
++    p_LnxWrpFmDev->err_irq = of_irq_to_resource(fm_node, 1, NULL);
++
++    if (unlikely(p_LnxWrpFmDev->err_irq == /*NO_IRQ*/0)) {
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_irq_to_resource() = %d", NO_IRQ));
++        DestroyFmDev(p_LnxWrpFmDev);
++        return NULL;
++    }
++
++    /* Get the FM address */
++    _errno = of_address_to_resource(fm_node, 0, &res);
++    if (unlikely(_errno < 0)) {
++        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno));
++        DestroyFmDev(p_LnxWrpFmDev);
++        return NULL;
++    }
++
++
++    p_LnxWrpFmDev->fmBaseAddr = 0;
++    p_LnxWrpFmDev->fmPhysBaseAddr = res.start;
++    p_LnxWrpFmDev->fmMemSize = res.end + 1 - res.start;
++
++    clk = of_clk_get(fm_node, 0);
++    if (IS_ERR(clk)) {
++        dev_err(&of_dev->dev, "%s: Failed to get FM clock structure\n",
++                __func__);
++        of_node_put(fm_node);
++        DestroyFmDev(p_LnxWrpFmDev);
++        return NULL;
++    }
++
++    clk_rate = clk_get_rate(clk);
++    if (!clk_rate) {
++        dev_err(&of_dev->dev, "%s: Failed to determine FM clock rate\n",
++                __func__);
++        of_node_put(fm_node);
++        DestroyFmDev(p_LnxWrpFmDev);
++        return NULL;
++    }
++
++    p_LnxWrpFmDev->fmDevSettings.param.fmClkFreq = DIV_ROUND_UP(clk_rate, 1000000); /* In MHz, rounded */
++    /* Get the MURAM base address and size */
++    memset(ids, 0, sizeof(ids));
++    if (WARN_ON(strlen("muram") >= sizeof(ids[0].name)))
++        return NULL;
++    strcpy(ids[0].name, "muram");
++    if (WARN_ON(strlen("fsl,fman-muram") >= sizeof(ids[0].compatible)))
++        return NULL;
++    strcpy(ids[0].compatible, "fsl,fman-muram");
++    for_each_child_of_node(fm_node, dev_node) {
++        if (likely(of_match_node(ids, dev_node) != NULL)) {
++            _errno = of_address_to_resource(dev_node, 0, &res);
++            if (unlikely(_errno < 0)) {
++                REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno));
++                DestroyFmDev(p_LnxWrpFmDev);
++                return NULL;
++            }
++
++            p_LnxWrpFmDev->fmMuramBaseAddr = 0;
++            p_LnxWrpFmDev->fmMuramPhysBaseAddr = res.start;
++            p_LnxWrpFmDev->fmMuramMemSize = res.end + 1 - res.start;
++
++#ifndef CONFIG_FMAN_ARM
++            {
++               uint32_t svr;
++                svr = mfspr(SPRN_SVR);
++
++                if ((svr & ~SVR_VER_IGNORE_MASK) >= SVR_B4860_REV2_VALUE)
++                    p_LnxWrpFmDev->fmMuramMemSize = 0x80000;
++            }
++#endif
++        }
++    }
++
++    /* Get the RTC base address and size */
++    memset(ids, 0, sizeof(ids));
++    if (WARN_ON(strlen("rtc") >= sizeof(ids[0].name)))
++        return NULL;
++    strcpy(ids[0].name, "rtc");
++    if (WARN_ON(strlen("fsl,fman-rtc") >= sizeof(ids[0].compatible)))
++        return NULL;
++    strcpy(ids[0].compatible, "fsl,fman-rtc");
++    for_each_child_of_node(fm_node, dev_node) {
++        if (likely(of_match_node(ids, dev_node) != NULL)) {
++            _errno = of_address_to_resource(dev_node, 0, &res);
++            if (unlikely(_errno < 0)) {
++                REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno));
++                DestroyFmDev(p_LnxWrpFmDev);
++                return NULL;
++            }
++
++            p_LnxWrpFmDev->fmRtcBaseAddr = 0;
++            p_LnxWrpFmDev->fmRtcPhysBaseAddr = res.start;
++            p_LnxWrpFmDev->fmRtcMemSize = res.end + 1 - res.start;
++        }
++    }
++
++#if (DPAA_VERSION >= 11)
++    /* Get the VSP base address */
++    for_each_child_of_node(fm_node, dev_node) {
++        if (of_device_is_compatible(dev_node, "fsl,fman-vsps")) {
++            _errno = of_address_to_resource(dev_node, 0, &res);
++            if (unlikely(_errno < 0)) {
++                REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno));
++                DestroyFmDev(p_LnxWrpFmDev);
++                return NULL;
++            }
++            p_LnxWrpFmDev->fmVspBaseAddr = 0;
++            p_LnxWrpFmDev->fmVspPhysBaseAddr = res.start;
++            p_LnxWrpFmDev->fmVspMemSize = res.end + 1 - res.start;
++        }
++    }
++#endif
++
++    /* Get all PCD nodes */
++    p_LnxWrpFmDev->prsActive = HasFmPcdOfNode(fm_node, ids, "parser", "fsl,fman-parser");
++    p_LnxWrpFmDev->kgActive = HasFmPcdOfNode(fm_node, ids, "keygen", "fsl,fman-keygen");
++    p_LnxWrpFmDev->ccActive = HasFmPcdOfNode(fm_node, ids, "cc", "fsl,fman-cc");
++    p_LnxWrpFmDev->plcrActive = HasFmPcdOfNode(fm_node, ids, "policer", "fsl,fman-policer");
++
++    if (p_LnxWrpFmDev->prsActive || p_LnxWrpFmDev->kgActive ||
++        p_LnxWrpFmDev->ccActive || p_LnxWrpFmDev->plcrActive)
++        p_LnxWrpFmDev->pcdActive = TRUE;
++
++    if (p_LnxWrpFmDev->pcdActive)
++    {
++        const char *str_prop = (char *)of_get_property(fm_node, "fsl,default-pcd", &lenp);
++        if (str_prop) {
++            if (strncmp(str_prop, "3-tuple", strlen("3-tuple")) == 0)
++                p_LnxWrpFmDev->defPcd = e_FM_PCD_3_TUPLE;
++        }
++        else
++            p_LnxWrpFmDev->defPcd = e_NO_PCD;
++    }
++
++    of_node_put(fm_node);
++
++    p_LnxWrpFmDev->hcCh =
++        qman_affine_channel(cpumask_first(qman_affine_cpus()));
++
++    p_LnxWrpFmDev->active = TRUE;
++
++    return p_LnxWrpFmDev;
++}
++
++struct device_node *GetFmAdvArgsDevTreeNode (uint8_t fmIndx)
++{
++    struct device_node  *dev_node;
++    const uint32_t      *uint32_prop;
++    int                 lenp;
++    uint32_t            tmp_prop;
++
++    for_each_compatible_node(dev_node, NULL, "fsl,fman-extended-args") {
++        uint32_prop = (uint32_t *)of_get_property(dev_node, "cell-index", &lenp);
++        if (unlikely(uint32_prop == NULL)) {
++            REPORT_ERROR(MAJOR, E_INVALID_VALUE,
++                         ("of_get_property(%s, cell-index) failed",
++                          dev_node->full_name));
++            return NULL;
++        }
++        tmp_prop = be32_to_cpu(*uint32_prop);
++        if (WARN_ON(lenp != sizeof(uint32_t)))
++            return NULL;
++        if (tmp_prop > INTG_MAX_NUM_OF_FM) {
++            REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!"));
++            return NULL;
++        }
++        if (fmIndx == tmp_prop)
++            return dev_node;
++    }
++
++    return NULL;
++}
++
++static t_Error CheckNConfigFmAdvArgs (t_LnxWrpFmDev *p_LnxWrpFmDev)
++{
++    struct device_node  *dev_node;
++    t_Error             err = E_INVALID_VALUE;
++    const uint32_t      *uint32_prop;
++    const char          *str_prop;
++    int                 lenp;
++    uint32_t            tmp_prop;
++
++    dev_node = GetFmAdvArgsDevTreeNode(p_LnxWrpFmDev->id);
++    if (!dev_node) /* no advance parameters for FMan */
++        return E_OK;
++
++    str_prop = (char *)of_get_property(dev_node, "dma-aid-mode", &lenp);
++    if (str_prop) {
++        if (strcmp(str_prop, "port") == 0)
++            err = FM_ConfigDmaAidMode(p_LnxWrpFmDev->h_Dev, e_FM_DMA_AID_OUT_PORT_ID);
++        else if (strcmp(str_prop, "tnum") == 0)
++            err = FM_ConfigDmaAidMode(p_LnxWrpFmDev->h_Dev, e_FM_DMA_AID_OUT_TNUM);
++
++        if (err != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++
++      uint32_prop = (uint32_t *)of_get_property(dev_node,
++                                              "total-fifo-size", &lenp);
++      if (uint32_prop) {
++              tmp_prop = be32_to_cpu(*uint32_prop);
++              if (WARN_ON(lenp != sizeof(uint32_t)))
++                      RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
++
++              if (FM_ConfigTotalFifoSize(p_LnxWrpFmDev->h_Dev,
++                              tmp_prop) != E_OK)
++                      RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
++      }
++
++    uint32_prop = (uint32_t *)of_get_property(dev_node, "tnum-aging-period",
++      &lenp);
++      if (uint32_prop) {
++              tmp_prop = be32_to_cpu(*uint32_prop);
++              if (WARN_ON(lenp != sizeof(uint32_t)))
++                      RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
++
++        err = FM_ConfigTnumAgingPeriod(p_LnxWrpFmDev->h_Dev,
++            (uint16_t)tmp_prop/*tnumAgingPeriod*/);
++
++        if (err != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++
++    of_node_put(dev_node);
++
++    return E_OK;
++}
++
++static void LnxwrpFmDevExceptionsCb(t_Handle h_App, e_FmExceptions exception)
++{
++    t_LnxWrpFmDev       *p_LnxWrpFmDev = (t_LnxWrpFmDev *)h_App;
++
++    ASSERT_COND(p_LnxWrpFmDev);
++
++    DBG(INFO, ("got fm exception %d", exception));
++
++    /* do nothing */
++    UNUSED(exception);
++}
++
++static void LnxwrpFmDevBusErrorCb(t_Handle        h_App,
++                                  e_FmPortType    portType,
++                                  uint8_t         portId,
++                                  uint64_t        addr,
++                                  uint8_t         tnum,
++                                  uint16_t        liodn)
++{
++    t_LnxWrpFmDev       *p_LnxWrpFmDev = (t_LnxWrpFmDev *)h_App;
++
++    ASSERT_COND(p_LnxWrpFmDev);
++
++    /* do nothing */
++    UNUSED(portType);UNUSED(portId);UNUSED(addr);UNUSED(tnum);UNUSED(liodn);
++}
++
++static t_Error ConfigureFmDev(t_LnxWrpFmDev  *p_LnxWrpFmDev)
++{
++    struct resource     *dev_res;
++    int                 _errno;
++
++    if (!p_LnxWrpFmDev->active)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM not configured!!!"));
++
++#ifndef MODULE
++    _errno = can_request_irq(p_LnxWrpFmDev->irq, 0);
++    if (unlikely(_errno < 0))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("can_request_irq() = %d", _errno));
++#endif
++    _errno = devm_request_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->irq, fm_irq, 0, "fman", p_LnxWrpFmDev);
++    if (unlikely(_errno < 0))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_irq(%d) = %d", p_LnxWrpFmDev->irq, _errno));
++
++    enable_irq_wake(p_LnxWrpFmDev->irq);
++
++    if (p_LnxWrpFmDev->err_irq != 0) {
++#ifndef MODULE
++        _errno = can_request_irq(p_LnxWrpFmDev->err_irq, 0);
++        if (unlikely(_errno < 0))
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("can_request_irq() = %d", _errno));
++#endif
++        _errno = devm_request_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->err_irq, fm_err_irq, IRQF_SHARED, "fman-err", p_LnxWrpFmDev);
++        if (unlikely(_errno < 0))
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_irq(%d) = %d", p_LnxWrpFmDev->err_irq, _errno));
++
++      enable_irq_wake(p_LnxWrpFmDev->err_irq);
++    }
++
++    p_LnxWrpFmDev->res = devm_request_mem_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize, "fman");
++    if (unlikely(p_LnxWrpFmDev->res == NULL))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_mem_region() failed"));
++
++    p_LnxWrpFmDev->fmBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize));
++    if (unlikely(p_LnxWrpFmDev->fmBaseAddr == 0))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed"));
++
++    if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmBaseAddr, (uint64_t)p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize) != E_OK)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM memory map"));
++
++    dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize, "fman-muram");
++    if (unlikely(dev_res == NULL))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("__devm_request_region() failed"));
++
++    p_LnxWrpFmDev->fmMuramBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize));
++    if (unlikely(p_LnxWrpFmDev->fmMuramBaseAddr == 0))
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed"));
++
++    if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmMuramBaseAddr, (uint64_t)p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize) != E_OK)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM MURAM memory map"));
++
++    if (p_LnxWrpFmDev->fmRtcPhysBaseAddr)
++    {
++        dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize, "fman-rtc");
++        if (unlikely(dev_res == NULL))
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("__devm_request_region() failed"));
++
++        p_LnxWrpFmDev->fmRtcBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize));
++        if (unlikely(p_LnxWrpFmDev->fmRtcBaseAddr == 0))
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed"));
++
++        if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmRtcBaseAddr, (uint64_t)p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize) != E_OK)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC memory map"));
++    }
++
++#if (DPAA_VERSION >= 11)
++    if (p_LnxWrpFmDev->fmVspPhysBaseAddr) {
++        dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmVspPhysBaseAddr, p_LnxWrpFmDev->fmVspMemSize, "fman-vsp");
++        if (unlikely(dev_res == NULL))
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("__devm_request_region() failed"));
++
++        p_LnxWrpFmDev->fmVspBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmVspPhysBaseAddr, p_LnxWrpFmDev->fmVspMemSize));
++        if (unlikely(p_LnxWrpFmDev->fmVspBaseAddr == 0))
++          RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed"));
++    }
++#endif
++
++    p_LnxWrpFmDev->fmDevSettings.param.baseAddr     = p_LnxWrpFmDev->fmBaseAddr;
++    p_LnxWrpFmDev->fmDevSettings.param.fmId         = p_LnxWrpFmDev->id;
++    p_LnxWrpFmDev->fmDevSettings.param.irq          = NO_IRQ;
++    p_LnxWrpFmDev->fmDevSettings.param.errIrq       = NO_IRQ;
++    p_LnxWrpFmDev->fmDevSettings.param.f_Exception  = LnxwrpFmDevExceptionsCb;
++    p_LnxWrpFmDev->fmDevSettings.param.f_BusError   = LnxwrpFmDevBusErrorCb;
++    p_LnxWrpFmDev->fmDevSettings.param.h_App        = p_LnxWrpFmDev;
++
++    return FillRestFmInfo(p_LnxWrpFmDev);
++}
++
++#ifndef CONFIG_FMAN_ARM
++/*
++ * Table for matching compatible strings, for device tree
++ * guts node, for QorIQ SOCs.
++ * "fsl,qoriq-device-config-2.0" corresponds to T4 & B4
++ * SOCs. For the older SOCs "fsl,qoriq-device-config-1.0"
++ * string would be used.
++*/
++static const struct of_device_id guts_device_ids[] = {
++        { .compatible = "fsl,qoriq-device-config-1.0", },
++        { .compatible = "fsl,qoriq-device-config-2.0", },
++        {}
++};
++
++static unsigned int get_rcwsr(int regnum)
++{
++      struct ccsr_guts __iomem *guts_regs = NULL;
++      struct device_node *guts_node;
++
++      guts_node = of_find_matching_node(NULL, guts_device_ids);
++      if (!guts_node) {
++              pr_err("could not find GUTS node\n");
++              return 0;
++      }
++      guts_regs = of_iomap(guts_node, 0);
++      of_node_put(guts_node);
++      if (!guts_regs) {
++              pr_err("ioremap of GUTS node failed\n");
++              return 0;
++      }
++
++      return ioread32be(&guts_regs->rcwsr[regnum]);
++}
++
++#define FMAN1_ALL_MACS_MASK   0xFCC00000
++#define FMAN2_ALL_MACS_MASK   0x000FCC00
++
++/**
++ * @Function          ResetOnInitErrata_A007273
++ *
++ * @Description               Workaround for Errata A-007273
++ *                                    This workaround is required to avoid a FMan hang during reset on initialization.
++ *                                    Enable all MACs in guts.devdisr2 register,
++ *                                    then perform a regular FMan reset and then restore MACs to their original state.
++ *
++ * @Param[in]     h_Fm - FM module descriptor
++ *
++ * @Return        None.
++ */
++void ResetOnInitErrata_A007273(t_Handle h_Fm)
++{
++      struct ccsr_guts __iomem *guts_regs = NULL;
++      struct device_node *guts_node;
++      u32 devdisr2, enableMacs;
++
++      /* Get guts registers */
++      guts_node = of_find_matching_node(NULL, guts_device_ids);
++      if (!guts_node) {
++              pr_err("could not find GUTS node\n");
++              return;
++      }
++      guts_regs = of_iomap(guts_node, 0);
++      of_node_put(guts_node);
++      if (!guts_regs) {
++              pr_err("ioremap of GUTS node failed\n");
++              return;
++      }
++
++      /* Read current state */
++      devdisr2 = ioread32be(&guts_regs->devdisr2);
++
++      if (FmGetId(h_Fm) == 0)
++              enableMacs = devdisr2 & ~FMAN1_ALL_MACS_MASK;
++      else
++              enableMacs = devdisr2 & ~FMAN2_ALL_MACS_MASK;
++
++      /* Enable all MACs */
++      iowrite32be(enableMacs, &guts_regs->devdisr2);
++
++      /* Perform standard FMan reset */
++      FmReset(h_Fm);
++
++      /* Restore devdisr2 value */
++      iowrite32be(devdisr2, &guts_regs->devdisr2);
++
++      iounmap(guts_regs);
++}
++#endif
++
++static t_Error InitFmDev(t_LnxWrpFmDev  *p_LnxWrpFmDev)
++{
++    const struct qe_firmware *fw;
++
++    if (!p_LnxWrpFmDev->active)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM not configured!!!"));
++
++    if ((p_LnxWrpFmDev->h_MuramDev = FM_MURAM_ConfigAndInit(p_LnxWrpFmDev->fmMuramBaseAddr, p_LnxWrpFmDev->fmMuramMemSize)) == NULL)
++        RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-MURAM!"));
++
++    /* Loading the fman-controller code */
++    fw = FindFmanMicrocode();
++
++    if (!fw) {
++        /* this forces the reuse of the current IRAM content */
++        p_LnxWrpFmDev->fmDevSettings.param.firmware.size = 0;
++        p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code = NULL;
++    } else {
++        p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code =
++            (void *) fw + be32_to_cpu(fw->microcode[0].code_offset);
++        p_LnxWrpFmDev->fmDevSettings.param.firmware.size =
++            sizeof(u32) * be32_to_cpu(fw->microcode[0].count);
++        DBG(INFO, ("Loading fman-controller code version %d.%d.%d",
++                   fw->microcode[0].major,
++                   fw->microcode[0].minor,
++                   fw->microcode[0].revision));
++    }
++
++#ifdef CONFIG_FMAN_ARM
++      { /* endianness adjustments: byteswap the ucode retrieved from the f/w blob */
++              int i;
++              int usz = p_LnxWrpFmDev->fmDevSettings.param.firmware.size;
++              void * p_Code = p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code;
++              u32 *dest = kzalloc(usz, GFP_KERNEL);
++
++              if (p_Code && dest)
++              for(i=0; i < usz / 4; ++i)
++                      dest[i] = be32_to_cpu(((u32 *)p_Code)[i]);
++
++              p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code = dest;
++      }
++#endif
++
++    p_LnxWrpFmDev->fmDevSettings.param.h_FmMuram = p_LnxWrpFmDev->h_MuramDev;
++
++#if (DPAA_VERSION >= 11)
++    if (p_LnxWrpFmDev->fmVspBaseAddr) {
++        p_LnxWrpFmDev->fmDevSettings.param.vspBaseAddr = p_LnxWrpFmDev->fmVspBaseAddr;
++        p_LnxWrpFmDev->fmDevSettings.param.partVSPBase = 0;
++        p_LnxWrpFmDev->fmDevSettings.param.partNumOfVSPs = FM_VSP_MAX_NUM_OF_ENTRIES;
++    }
++#endif
++
++#ifdef CONFIG_FMAN_ARM
++    p_LnxWrpFmDev->fmDevSettings.param.fmMacClkRatio = 1;
++#else
++    if(p_LnxWrpFmDev->fmDevSettings.param.fmId == 0)
++        p_LnxWrpFmDev->fmDevSettings.param.fmMacClkRatio =
++            !!(get_rcwsr(4) & 0x2); /* RCW[FM_MAC_RAT0] */
++    else
++        p_LnxWrpFmDev->fmDevSettings.param.fmMacClkRatio =
++            !!(get_rcwsr(4) & 0x1); /* RCW[FM_MAC_RAT1] */
++
++    {   
++    /* T4 Devices ClkRatio is always 1 regardless of RCW[FM_MAC_RAT1] */
++        uint32_t svr;
++        svr = mfspr(SPRN_SVR);
++
++        if ((svr & SVR_DEVICE_ID_MASK) == SVR_T4_DEVICE_ID)
++            p_LnxWrpFmDev->fmDevSettings.param.fmMacClkRatio = 1;
++    }
++#endif /* CONFIG_FMAN_ARM */
++
++    if ((p_LnxWrpFmDev->h_Dev = FM_Config(&p_LnxWrpFmDev->fmDevSettings.param)) == NULL)
++        RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM"));
++
++
++    if (FM_ConfigResetOnInit(p_LnxWrpFmDev->h_Dev, TRUE) != E_OK)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM"));
++
++#ifndef CONFIG_FMAN_ARM
++#ifdef FM_HANG_AT_RESET_MAC_CLK_DISABLED_ERRATA_FMAN_A007273
++      if (FM_ConfigResetOnInitOverrideCallback(p_LnxWrpFmDev->h_Dev, ResetOnInitErrata_A007273) != E_OK)
++              RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM"));
++#endif /* FM_HANG_AT_RESET_MAC_CLK_DISABLED_ERRATA_FMAN_A007273 */
++#endif /* CONFIG_FMAN_ARM */
++
++#ifdef CONFIG_FMAN_P1023
++    if (FM_ConfigDmaAidOverride(p_LnxWrpFmDev->h_Dev, TRUE) != E_OK)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM"));
++#endif
++
++
++    CheckNConfigFmAdvArgs(p_LnxWrpFmDev);
++
++    if (FM_Init(p_LnxWrpFmDev->h_Dev) != E_OK)
++        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM"));
++
++    /* TODO: Why we mask these interrupts? */
++    if (p_LnxWrpFmDev->err_irq == 0) {
++        FM_SetException(p_LnxWrpFmDev->h_Dev, e_FM_EX_DMA_BUS_ERROR,FALSE);
++        FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_READ_ECC,FALSE);
++        FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_SYSTEM_WRITE_ECC,FALSE);
++        FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_FM_WRITE_ECC,FALSE);
++        FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_SINGLE_PORT_ECC, FALSE);
++        FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_FPM_STALL_ON_TASKS , FALSE);
++        FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_FPM_SINGLE_ECC, FALSE);
++        FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_FPM_DOUBLE_ECC,FALSE);
++        FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_QMI_SINGLE_ECC, FALSE);
++        FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_QMI_DOUBLE_ECC,FALSE);
++        FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,FALSE);
++        FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_LIST_RAM_ECC,FALSE);
++        FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_STORAGE_PROFILE_ECC, FALSE);
++        FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_STATISTICS_RAM_ECC, FALSE);
++        FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_DISPATCH_RAM_ECC, FALSE);
++        FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_IRAM_ECC,FALSE);
++        /* TODO: FmDisableRamsEcc assert for ramsEccOwners.
++         * FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_MURAM_ECC,FALSE);*/
++    }
++
++    if (p_LnxWrpFmDev->fmRtcBaseAddr)
++    {
++        t_FmRtcParams   fmRtcParam;
++
++        memset(&fmRtcParam, 0, sizeof(fmRtcParam));
++        fmRtcParam.h_App = p_LnxWrpFmDev;
++        fmRtcParam.h_Fm = p_LnxWrpFmDev->h_Dev;
++        fmRtcParam.baseAddress = p_LnxWrpFmDev->fmRtcBaseAddr;
++
++        if(!(p_LnxWrpFmDev->h_RtcDev = FM_RTC_Config(&fmRtcParam)))
++            RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-RTC"));
++
++      if (FM_RTC_ConfigPeriod(p_LnxWrpFmDev->h_RtcDev, DPA_PTP_NOMINAL_FREQ_PERIOD_NS) != E_OK)
++          RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC"));
++
++        if (FM_RTC_Init(p_LnxWrpFmDev->h_RtcDev) != E_OK)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC"));
++    }
++
++    return E_OK;
++}
++
++/* TODO: to be moved back here */
++extern void FreeFmPcdDev(t_LnxWrpFmDev  *p_LnxWrpFmDev);
++
++static void FreeFmDev(t_LnxWrpFmDev  *p_LnxWrpFmDev)
++{
++    if (!p_LnxWrpFmDev->active)
++        return;
++
++    FreeFmPcdDev(p_LnxWrpFmDev);
++
++    if (p_LnxWrpFmDev->h_RtcDev)
++      FM_RTC_Free(p_LnxWrpFmDev->h_RtcDev);
++
++    if (p_LnxWrpFmDev->h_Dev)
++        FM_Free(p_LnxWrpFmDev->h_Dev);
++
++    if (p_LnxWrpFmDev->h_MuramDev)
++        FM_MURAM_Free(p_LnxWrpFmDev->h_MuramDev);
++
++    if (p_LnxWrpFmDev->fmRtcBaseAddr)
++    {
++        SYS_UnregisterIoMap(p_LnxWrpFmDev->fmRtcBaseAddr);
++        devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmRtcBaseAddr));
++        __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize);
++    }
++    SYS_UnregisterIoMap(p_LnxWrpFmDev->fmMuramBaseAddr);
++    devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmMuramBaseAddr));
++    __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize);
++    SYS_UnregisterIoMap(p_LnxWrpFmDev->fmBaseAddr);
++    devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr));
++    devm_release_mem_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize);
++    if (p_LnxWrpFmDev->err_irq != 0) {
++        devm_free_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->err_irq, p_LnxWrpFmDev);
++    }
++
++    devm_free_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->irq, p_LnxWrpFmDev);
++}
++
++/* FMan character device file operations */
++extern struct file_operations fm_fops;
++
++static int /*__devinit*/ fm_probe(struct platform_device *of_dev)
++{
++    t_LnxWrpFmDev   *p_LnxWrpFmDev;
++
++    if ((p_LnxWrpFmDev = ReadFmDevTreeNode(of_dev)) == NULL)
++        return -EIO;
++    if (ConfigureFmDev(p_LnxWrpFmDev) != E_OK)
++        return -EIO;
++    if (InitFmDev(p_LnxWrpFmDev) != E_OK)
++        return -EIO;
++
++    /* IOCTL ABI checking */
++    LnxWrpPCDIOCTLEnumChecking();
++    LnxWrpPCDIOCTLTypeChecking();
++
++    Sprint (p_LnxWrpFmDev->name, "%s%d", DEV_FM_NAME, p_LnxWrpFmDev->id);
++
++    /* Register to the /dev for IOCTL API */
++    /* Register dynamically a new major number for the character device: */
++    if ((p_LnxWrpFmDev->major = register_chrdev(0, p_LnxWrpFmDev->name, &fm_fops)) <= 0) {
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Failed to allocate a major number for device \"%s\"", p_LnxWrpFmDev->name));
++        return -EIO;
++    }
++
++    /* Creating classes for FM */
++    DBG(TRACE ,("class_create fm_class"));
++    p_LnxWrpFmDev->fm_class = class_create(THIS_MODULE, p_LnxWrpFmDev->name);
++    if (IS_ERR(p_LnxWrpFmDev->fm_class)) {
++        unregister_chrdev(p_LnxWrpFmDev->major, p_LnxWrpFmDev->name);
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("class_create error fm_class"));
++        return -EIO;
++    }
++
++    device_create(p_LnxWrpFmDev->fm_class, NULL, MKDEV(p_LnxWrpFmDev->major, DEV_FM_MINOR_BASE), NULL,
++                  "fm%d", p_LnxWrpFmDev->id);
++    device_create(p_LnxWrpFmDev->fm_class, NULL, MKDEV(p_LnxWrpFmDev->major, DEV_FM_PCD_MINOR_BASE), NULL,
++                  "fm%d-pcd", p_LnxWrpFmDev->id);
++    dev_set_drvdata(p_LnxWrpFmDev->dev, p_LnxWrpFmDev);
++
++   /* create sysfs entries for stats and regs */
++    if ( fm_sysfs_create(p_LnxWrpFmDev->dev) !=0 )
++    {
++        FreeFmDev(p_LnxWrpFmDev);
++        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Unable to create sysfs entry - fm!!!"));
++        return -EIO;
++    }
++
++#ifdef CONFIG_PM
++    device_set_wakeup_capable(p_LnxWrpFmDev->dev, true);
++#endif
++
++    DBG(TRACE, ("FM%d probed", p_LnxWrpFmDev->id));
++
++    return 0;
++}
++
++static int fm_remove(struct platform_device *of_dev)
++{
++    t_LnxWrpFmDev   *p_LnxWrpFmDev;
++    struct device   *dev;
++
++    dev = &of_dev->dev;
++    p_LnxWrpFmDev = dev_get_drvdata(dev);
++
++    fm_sysfs_destroy(dev);
++
++    DBG(TRACE, ("destroy fm_class"));
++    device_destroy(p_LnxWrpFmDev->fm_class, MKDEV(p_LnxWrpFmDev->major, DEV_FM_MINOR_BASE));
++    device_destroy(p_LnxWrpFmDev->fm_class, MKDEV(p_LnxWrpFmDev->major, DEV_FM_PCD_MINOR_BASE));
++    class_destroy(p_LnxWrpFmDev->fm_class);
++
++    /* Destroy chardev */
++    unregister_chrdev(p_LnxWrpFmDev->major, p_LnxWrpFmDev->name);
++
++    FreeFmDev(p_LnxWrpFmDev);
++
++    DestroyFmDev(p_LnxWrpFmDev);
++
++    dev_set_drvdata(dev, NULL);
++
++    return 0;
++}
++
++static const struct of_device_id fm_match[] = {
++    {
++        .compatible    = "fsl,fman"
++    },
++    {}
++};
++#ifndef MODULE
++MODULE_DEVICE_TABLE(of, fm_match);
++#endif /* !MODULE */
++
++#ifdef CONFIG_PM
++
++#define SCFG_FMCLKDPSLPCR_ADDR 0xFFE0FC00C
++#define SCFG_FMCLKDPSLPCR_DS_VAL 0x48402000
++#define SCFG_FMCLKDPSLPCR_NORMAL_VAL 0x00402000
++
++struct device *g_fm_dev;
++
++static int fm_soc_suspend(struct device *dev)
++{
++      int err = 0;
++      uint32_t *fmclk;
++      t_LnxWrpFmDev *p_LnxWrpFmDev = dev_get_drvdata(get_device(dev));
++      g_fm_dev = dev;
++      fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4);
++      WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_DS_VAL);
++      if (p_LnxWrpFmDev->h_DsarRxPort)
++      {
++#ifdef CONFIG_FSL_QORIQ_PM
++              device_set_wakeup_enable(p_LnxWrpFmDev->dev, 1);
++#endif
++              err = FM_PORT_EnterDsarFinal(p_LnxWrpFmDev->h_DsarRxPort,
++                      p_LnxWrpFmDev->h_DsarTxPort);
++      }
++      return err;
++}
++
++static int fm_soc_resume(struct device *dev)
++{
++      t_LnxWrpFmDev *p_LnxWrpFmDev = dev_get_drvdata(get_device(dev));
++      uint32_t *fmclk;
++      fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4);
++      WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_NORMAL_VAL);
++      if (p_LnxWrpFmDev->h_DsarRxPort)
++      {
++#ifdef CONFIG_FSL_QORIQ_PM
++              device_set_wakeup_enable(p_LnxWrpFmDev->dev, 0);
++#endif
++              FM_PORT_ExitDsar(p_LnxWrpFmDev->h_DsarRxPort,
++                      p_LnxWrpFmDev->h_DsarTxPort);
++              p_LnxWrpFmDev->h_DsarRxPort = 0;
++              p_LnxWrpFmDev->h_DsarTxPort = 0;
++      }
++      return 0;
++}
++
++static const struct dev_pm_ops fm_pm_ops = {
++      .suspend = fm_soc_suspend,
++      .resume = fm_soc_resume,
++};
++
++#define FM_PM_OPS (&fm_pm_ops)
++
++#else /* CONFIG_PM */
++
++#define FM_PM_OPS NULL
++
++#endif /* CONFIG_PM */
++
++static struct platform_driver fm_driver = {
++    .driver = {
++        .name           = "fsl-fman",
++        .of_match_table    = fm_match,
++        .owner          = THIS_MODULE,
++      .pm             = FM_PM_OPS,
++    },
++    .probe          = fm_probe,
++    .remove         = fm_remove
++};
++
++t_Handle LNXWRP_FM_Init(void)
++{
++    memset(&lnxWrpFm, 0, sizeof(lnxWrpFm));
++    mutex_init(&lnxwrp_mutex);
++
++    /* Register to the DTB for basic FM API */
++    platform_driver_register(&fm_driver);
++
++    return &lnxWrpFm;
++}
++
++t_Error LNXWRP_FM_Free(t_Handle h_LnxWrpFm)
++{
++    platform_driver_unregister(&fm_driver);
++    mutex_destroy(&lnxwrp_mutex);
++
++    return E_OK;
++}
++
++
++struct fm * fm_bind(struct device *fm_dev)
++{
++    return (struct fm *)(dev_get_drvdata(get_device(fm_dev)));
++}
++EXPORT_SYMBOL(fm_bind);
++
++void fm_unbind(struct fm *fm)
++{
++    t_LnxWrpFmDev       *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm;
++
++    put_device(p_LnxWrpFmDev->dev);
++}
++EXPORT_SYMBOL(fm_unbind);
++
++struct resource * fm_get_mem_region(struct fm *fm)
++{
++    t_LnxWrpFmDev       *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm;
++
++    return p_LnxWrpFmDev->res;
++}
++EXPORT_SYMBOL(fm_get_mem_region);
++
++void * fm_get_handle(struct fm *fm)
++{
++    t_LnxWrpFmDev       *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm;
++
++    return (void *)p_LnxWrpFmDev->h_Dev;
++}
++EXPORT_SYMBOL(fm_get_handle);
++
++void * fm_get_rtc_handle(struct fm *fm)
++{
++    t_LnxWrpFmDev       *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm;
++
++    return (void *)p_LnxWrpFmDev->h_RtcDev;
++}
++EXPORT_SYMBOL(fm_get_rtc_handle);
++
++struct fm_port * fm_port_bind (struct device *fm_port_dev)
++{
++    return (struct fm_port *)(dev_get_drvdata(get_device(fm_port_dev)));
++}
++EXPORT_SYMBOL(fm_port_bind);
++
++void fm_port_unbind(struct fm_port *port)
++{
++    t_LnxWrpFmPortDev   *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port;
++
++    put_device(p_LnxWrpFmPortDev->dev);
++}
++EXPORT_SYMBOL(fm_port_unbind);
++
++void *fm_port_get_handle(const struct fm_port *port)
++{
++    t_LnxWrpFmPortDev   *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port;
++
++    return (void *)p_LnxWrpFmPortDev->h_Dev;
++}
++EXPORT_SYMBOL(fm_port_get_handle);
++
++u64 *fm_port_get_buffer_time_stamp(const struct fm_port *port,
++              const void *data)
++{
++      return FM_PORT_GetBufferTimeStamp(fm_port_get_handle(port),
++                                        (void *)data);
++}
++EXPORT_SYMBOL(fm_port_get_buffer_time_stamp);
++
++void fm_port_get_base_addr(const struct fm_port *port, uint64_t *base_addr)
++{
++    t_LnxWrpFmPortDev   *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
++
++    *base_addr = p_LnxWrpFmPortDev->settings.param.baseAddr;
++}
++EXPORT_SYMBOL(fm_port_get_base_addr);
++
++void fm_port_pcd_bind (struct fm_port *port, struct fm_port_pcd_param *params)
++{
++    t_LnxWrpFmPortDev   *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port;
++
++    p_LnxWrpFmPortDev->pcd_owner_params.cba = params->cba;
++    p_LnxWrpFmPortDev->pcd_owner_params.cbf = params->cbf;
++    p_LnxWrpFmPortDev->pcd_owner_params.dev = params->dev;
++}
++EXPORT_SYMBOL(fm_port_pcd_bind);
++
++void fm_port_get_buff_layout_ext_params(struct fm_port *port, struct fm_port_params *params)
++{
++    t_LnxWrpFmPortDev   *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
++    struct device_node  *fm_node, *port_node;
++    const uint32_t       *uint32_prop;
++    int                  lenp;
++
++    params->data_align = 0;
++    params->manip_extra_space = 0;
++
++    fm_node = GetFmAdvArgsDevTreeNode(((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev)->id);
++    if (!fm_node) /* no advance parameters for FMan */
++        return;
++
++    port_node = GetFmPortAdvArgsDevTreeNode(fm_node,
++                                            p_LnxWrpFmPortDev->settings.param.portType,
++                                            p_LnxWrpFmPortDev->settings.param.portId);
++    if (!port_node) /* no advance parameters for FMan-Port */
++        return;
++
++    uint32_prop = (uint32_t *)of_get_property(port_node, "buffer-layout", &lenp);
++    if (uint32_prop) {
++       if (WARN_ON(lenp != sizeof(uint32_t)*2))
++            return;
++
++        params->manip_extra_space = (uint8_t)be32_to_cpu(uint32_prop[0]);
++        params->data_align        = (uint16_t)be32_to_cpu(uint32_prop[1]);
++    }
++
++    of_node_put(port_node);
++    of_node_put(fm_node);
++}
++EXPORT_SYMBOL(fm_port_get_buff_layout_ext_params);
++
++uint16_t fm_get_tx_port_channel(struct fm_port *port)
++{
++    t_LnxWrpFmPortDev   *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port;
++
++    return p_LnxWrpFmPortDev->txCh;
++}
++EXPORT_SYMBOL(fm_get_tx_port_channel);
++
++int fm_port_enable (struct fm_port *port)
++{
++    t_LnxWrpFmPortDev   *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port;
++    t_Error err = FM_PORT_Enable(p_LnxWrpFmPortDev->h_Dev);
++
++    return GET_ERROR_TYPE(err);
++}
++EXPORT_SYMBOL(fm_port_enable);
++
++int fm_port_disable(struct fm_port *port)
++{
++    t_LnxWrpFmPortDev   *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port;
++    t_Error err = FM_PORT_Disable(p_LnxWrpFmPortDev->h_Dev);
++
++    return GET_ERROR_TYPE(err);
++}
++EXPORT_SYMBOL(fm_port_disable);
++
++int fm_port_set_rate_limit(struct fm_port *port,
++                      uint16_t        max_burst_size,
++                      uint32_t        rate_limit)
++{
++      t_FmPortRateLimit param;
++      t_LnxWrpFmPortDev   *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
++      int err = 0;
++
++      param.maxBurstSize = max_burst_size;
++      param.rateLimit = rate_limit;
++      param.rateLimitDivider = 0;
++
++      err = FM_PORT_SetRateLimit(p_LnxWrpFmPortDev->h_Dev, &param);
++      return err;
++}
++EXPORT_SYMBOL(fm_port_set_rate_limit);
++
++int fm_port_del_rate_limit(struct fm_port *port)
++{
++      t_LnxWrpFmPortDev   *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
++
++      FM_PORT_DeleteRateLimit(p_LnxWrpFmPortDev->h_Dev);
++      return 0;
++}
++EXPORT_SYMBOL(fm_port_del_rate_limit);
++
++void FM_PORT_Dsar_DumpRegs(void);
++int ar_showmem(struct file *file, const char __user *buffer,
++              unsigned long count, void *data)
++{
++      FM_PORT_Dsar_DumpRegs();
++      return 2;
++}
++
++struct auto_res_tables_sizes *fm_port_get_autores_maxsize(
++      struct fm_port *port)
++{
++      t_LnxWrpFmPortDev   *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
++      return &p_LnxWrpFmPortDev->dsar_table_sizes;
++}
++EXPORT_SYMBOL(fm_port_get_autores_maxsize);
++
++int fm_port_enter_autores_for_deepsleep(struct fm_port *port,
++      struct auto_res_port_params *params)
++{
++      t_LnxWrpFmPortDev   *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
++      t_LnxWrpFmDev* p_LnxWrpFmDev = (t_LnxWrpFmDev*)p_LnxWrpFmPortDev->h_LnxWrpFmDev;
++      p_LnxWrpFmDev->h_DsarRxPort = p_LnxWrpFmPortDev->h_Dev;
++      p_LnxWrpFmDev->h_DsarTxPort = params->h_FmPortTx;
++
++              /*Register other under /proc/autoresponse */
++      if (WARN_ON(sizeof(t_FmPortDsarParams) != sizeof(struct auto_res_port_params)))
++            return -EFAULT;
++
++      FM_PORT_EnterDsar(p_LnxWrpFmPortDev->h_Dev, (t_FmPortDsarParams*)params);
++      return 0;
++}
++EXPORT_SYMBOL(fm_port_enter_autores_for_deepsleep);
++
++void fm_port_exit_auto_res_for_deep_sleep(struct fm_port *port_rx,
++      struct fm_port *port_tx)
++{
++}
++EXPORT_SYMBOL(fm_port_exit_auto_res_for_deep_sleep);
++
++int fm_port_get_autores_stats(struct fm_port *port,
++      struct auto_res_port_stats *stats)
++{
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
++      if (WARN_ON(sizeof(t_FmPortDsarStats) != sizeof(struct auto_res_port_stats)))
++            return -EFAULT;
++      return FM_PORT_GetDsarStats(p_LnxWrpFmPortDev->h_Dev, (t_FmPortDsarStats*)stats);
++}
++EXPORT_SYMBOL(fm_port_get_autores_stats);
++
++int fm_port_suspend(struct fm_port *port)
++{
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
++      if (!FM_PORT_IsInDsar(p_LnxWrpFmPortDev->h_Dev))
++              return FM_PORT_Disable(p_LnxWrpFmPortDev->h_Dev);
++      else
++              return 0;
++}
++EXPORT_SYMBOL(fm_port_suspend);
++
++int fm_port_resume(struct fm_port *port)
++{
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
++      if (!FM_PORT_IsInDsar(p_LnxWrpFmPortDev->h_Dev))
++              return FM_PORT_Enable(p_LnxWrpFmPortDev->h_Dev);
++      else
++              return 0;
++}
++EXPORT_SYMBOL(fm_port_resume);
++
++bool fm_port_is_in_auto_res_mode(struct fm_port *port)
++{
++      return FM_PORT_IsInDsar(port);
++}
++EXPORT_SYMBOL(fm_port_is_in_auto_res_mode);
++
++#ifdef CONFIG_FMAN_PFC
++int fm_port_set_pfc_priorities_mapping_to_qman_wq(struct fm_port *port,
++              uint8_t prio, uint8_t wq)
++{
++      t_LnxWrpFmPortDev   *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
++      int err;
++      int _errno;
++
++      err = FM_PORT_SetPfcPrioritiesMappingToQmanWQ(p_LnxWrpFmPortDev->h_Dev,
++                      prio, wq);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_PORT_SetPfcPrioritiesMappingToQmanWQ() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_port_set_pfc_priorities_mapping_to_qman_wq);
++#endif
++
++int fm_mac_set_exception(struct fm_mac_dev *fm_mac_dev,
++              e_FmMacExceptions exception, bool enable)
++{
++      int err;
++      int _errno;
++
++      err = FM_MAC_SetException(fm_mac_dev, exception, enable);
++
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MAC_SetException() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_set_exception);
++
++int fm_mac_free(struct fm_mac_dev *fm_mac_dev)
++{
++      int err;
++      int _error;
++
++      err = FM_MAC_Free(fm_mac_dev);
++      _error = -GET_ERROR_TYPE(err);
++
++      if (unlikely(_error < 0))
++              pr_err("FM_MAC_Free() = 0x%08x\n", err);
++
++      return _error;
++}
++EXPORT_SYMBOL(fm_mac_free);
++
++struct fm_mac_dev *fm_mac_config(t_FmMacParams *params)
++{
++      struct fm_mac_dev *fm_mac_dev;
++
++      fm_mac_dev = FM_MAC_Config(params);
++      if (unlikely(fm_mac_dev == NULL))
++              pr_err("FM_MAC_Config() failed\n");
++
++      return fm_mac_dev;
++}
++EXPORT_SYMBOL(fm_mac_config);
++
++int fm_mac_config_max_frame_length(struct fm_mac_dev *fm_mac_dev,
++              int len)
++{
++      int err;
++      int _errno;
++
++      err = FM_MAC_ConfigMaxFrameLength(fm_mac_dev, len);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MAC_ConfigMaxFrameLength() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_config_max_frame_length);
++
++int fm_mac_config_pad_and_crc(struct fm_mac_dev *fm_mac_dev, bool enable)
++{
++      int err;
++      int _errno;
++
++      err = FM_MAC_ConfigPadAndCrc(fm_mac_dev, enable);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MAC_ConfigPadAndCrc() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_config_pad_and_crc);
++
++int fm_mac_config_half_duplex(struct fm_mac_dev *fm_mac_dev, bool enable)
++{
++      int err;
++      int _errno;
++
++      err = FM_MAC_ConfigHalfDuplex(fm_mac_dev, enable);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MAC_ConfigHalfDuplex() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_config_half_duplex);
++
++int fm_mac_config_reset_on_init(struct fm_mac_dev *fm_mac_dev, bool enable)
++{
++      int err;
++      int _errno;
++
++      err = FM_MAC_ConfigResetOnInit(fm_mac_dev, enable);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MAC_ConfigResetOnInit() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_config_reset_on_init);
++
++int fm_mac_init(struct fm_mac_dev *fm_mac_dev)
++{
++      int err;
++      int _errno;
++
++      err = FM_MAC_Init(fm_mac_dev);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MAC_Init() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_init);
++
++int fm_mac_get_version(struct fm_mac_dev *fm_mac_dev, uint32_t *version)
++{
++      int err;
++      int _errno;
++
++      err = FM_MAC_GetVesrion(fm_mac_dev, version);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MAC_GetVesrion() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_get_version);
++
++int fm_mac_enable(struct fm_mac_dev *fm_mac_dev)
++{
++      int      _errno;
++      t_Error  err;
++
++      err = FM_MAC_Enable(fm_mac_dev, e_COMM_MODE_RX_AND_TX);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MAC_Enable() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_enable);
++
++int fm_mac_disable(struct fm_mac_dev *fm_mac_dev)
++{
++      int      _errno;
++      t_Error  err;
++
++      err = FM_MAC_Disable(fm_mac_dev, e_COMM_MODE_RX_AND_TX);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MAC_Disable() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_disable);
++
++int fm_mac_resume(struct fm_mac_dev *fm_mac_dev)
++{
++        int      _errno;
++        t_Error  err;
++
++        err = FM_MAC_Resume(fm_mac_dev);
++        _errno = -GET_ERROR_TYPE(err);
++        if (unlikely(_errno < 0))
++                pr_err("FM_MAC_Resume() = 0x%08x\n", err);
++
++        return _errno;
++}
++EXPORT_SYMBOL(fm_mac_resume);
++
++int fm_mac_set_promiscuous(struct fm_mac_dev *fm_mac_dev,
++              bool enable)
++{
++      int     _errno;
++      t_Error err;
++
++      err = FM_MAC_SetPromiscuous(fm_mac_dev, enable);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MAC_SetPromiscuous() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_set_promiscuous);
++
++int fm_mac_remove_hash_mac_addr(struct fm_mac_dev *fm_mac_dev,
++              t_EnetAddr *mac_addr)
++{
++      int     _errno;
++      t_Error err;
++
++      err = FM_MAC_RemoveHashMacAddr(fm_mac_dev, mac_addr);
++      _errno = -GET_ERROR_TYPE(err);
++      if (_errno < 0) {
++              pr_err("FM_MAC_RemoveHashMacAddr() = 0x%08x\n", err);
++              return _errno;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(fm_mac_remove_hash_mac_addr);
++
++int fm_mac_add_hash_mac_addr(struct fm_mac_dev *fm_mac_dev,
++              t_EnetAddr *mac_addr)
++{
++      int     _errno;
++      t_Error err;
++
++      err = FM_MAC_AddHashMacAddr(fm_mac_dev, mac_addr);
++      _errno = -GET_ERROR_TYPE(err);
++      if (_errno < 0) {
++              pr_err("FM_MAC_AddHashMacAddr() = 0x%08x\n", err);
++              return _errno;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(fm_mac_add_hash_mac_addr);
++
++int fm_mac_modify_mac_addr(struct fm_mac_dev *fm_mac_dev,
++                                       uint8_t *addr)
++{
++      int     _errno;
++      t_Error err;
++
++      err = FM_MAC_ModifyMacAddr(fm_mac_dev, (t_EnetAddr *)addr);
++      _errno = -GET_ERROR_TYPE(err);
++      if (_errno < 0)
++              pr_err("FM_MAC_ModifyMacAddr() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_modify_mac_addr);
++
++int fm_mac_adjust_link(struct fm_mac_dev *fm_mac_dev,
++              bool link, int speed, bool duplex)
++{
++      int      _errno;
++      t_Error  err;
++
++      if (!link) {
++#if (DPAA_VERSION < 11)
++              FM_MAC_RestartAutoneg(fm_mac_dev);
++#endif
++              return 0;
++      }
++
++      err = FM_MAC_AdjustLink(fm_mac_dev, speed, duplex);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MAC_AdjustLink() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_adjust_link);
++
++int fm_mac_enable_1588_time_stamp(struct fm_mac_dev *fm_mac_dev)
++{
++      int                      _errno;
++      t_Error                  err;
++
++      err = FM_MAC_Enable1588TimeStamp(fm_mac_dev);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MAC_Enable1588TimeStamp() = 0x%08x\n", err);
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_enable_1588_time_stamp);
++
++int fm_mac_disable_1588_time_stamp(struct fm_mac_dev *fm_mac_dev)
++{
++      int                      _errno;
++      t_Error                  err;
++
++      err = FM_MAC_Disable1588TimeStamp(fm_mac_dev);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MAC_Disable1588TimeStamp() = 0x%08x\n", err);
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_disable_1588_time_stamp);
++
++int fm_mac_set_rx_pause_frames(
++              struct fm_mac_dev *fm_mac_dev, bool en)
++{
++      int     _errno;
++      t_Error err;
++
++      /* if rx pause is enabled, do NOT ignore pause frames */
++      err = FM_MAC_SetRxIgnorePauseFrames(fm_mac_dev, !en);
++
++      _errno = -GET_ERROR_TYPE(err);
++      if (_errno < 0)
++              pr_err("FM_MAC_SetRxIgnorePauseFrames() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_set_rx_pause_frames);
++
++#ifdef CONFIG_FMAN_PFC
++int fm_mac_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev,
++                                           bool en)
++{
++      int     _errno, i;
++      t_Error err;
++
++      if (en)
++              for (i = 0; i < CONFIG_FMAN_PFC_COS_COUNT; i++) {
++                      err = FM_MAC_SetTxPauseFrames(fm_mac_dev,
++                                      i, fsl_fm_pfc_quanta[i],
++                                      FSL_FM_PAUSE_THRESH_DEFAULT);
++                      _errno = -GET_ERROR_TYPE(err);
++                      if (_errno < 0) {
++                              pr_err("FM_MAC_SetTxPauseFrames() = 0x%08x\n", err);
++                              return _errno;
++                      }
++              }
++      else
++              for (i = 0; i < CONFIG_FMAN_PFC_COS_COUNT; i++) {
++                      err = FM_MAC_SetTxPauseFrames(fm_mac_dev,
++                                      i, FSL_FM_PAUSE_TIME_DISABLE,
++                                      FSL_FM_PAUSE_THRESH_DEFAULT);
++                      _errno = -GET_ERROR_TYPE(err);
++                      if (_errno < 0) {
++                              pr_err("FM_MAC_SetTxPauseFrames() = 0x%08x\n", err);
++                              return _errno;
++                      }
++              }
++
++      return _errno;
++}
++#else
++int fm_mac_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev,
++                                           bool en)
++{
++      int     _errno;
++      t_Error err;
++
++      if (en)
++              err = FM_MAC_SetTxAutoPauseFrames(fm_mac_dev,
++                              FSL_FM_PAUSE_TIME_ENABLE);
++      else
++              err = FM_MAC_SetTxAutoPauseFrames(fm_mac_dev,
++                              FSL_FM_PAUSE_TIME_DISABLE);
++
++      _errno = -GET_ERROR_TYPE(err);
++      if (_errno < 0)
++              pr_err("FM_MAC_SetTxAutoPauseFrames() = 0x%08x\n", err);
++
++      return _errno;
++}
++#endif
++EXPORT_SYMBOL(fm_mac_set_tx_pause_frames);
++
++int fm_rtc_enable(struct fm *fm_dev)
++{
++      int                      _errno;
++      t_Error                  err;
++
++      err = FM_RTC_Enable(fm_get_rtc_handle(fm_dev), 0);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_RTC_Enable = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_rtc_enable);
++
++int fm_rtc_disable(struct fm *fm_dev)
++{
++      int                      _errno;
++      t_Error                  err;
++
++      err = FM_RTC_Disable(fm_get_rtc_handle(fm_dev));
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_RTC_Disable = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_rtc_disable);
++
++int fm_rtc_get_cnt(struct fm *fm_dev, uint64_t *ts)
++{
++      int _errno;
++      t_Error err;
++
++      err = FM_RTC_GetCurrentTime(fm_get_rtc_handle(fm_dev), ts);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_RTC_GetCurrentTime = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_rtc_get_cnt);
++
++int fm_rtc_set_cnt(struct fm *fm_dev, uint64_t ts)
++{
++      int _errno;
++      t_Error err;
++
++      err = FM_RTC_SetCurrentTime(fm_get_rtc_handle(fm_dev), ts);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_RTC_SetCurrentTime = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_rtc_set_cnt);
++
++int fm_rtc_get_drift(struct fm *fm_dev, uint32_t *drift)
++{
++      int _errno;
++      t_Error err;
++
++      err = FM_RTC_GetFreqCompensation(fm_get_rtc_handle(fm_dev),
++                      drift);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_RTC_GetFreqCompensation = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_rtc_get_drift);
++
++int fm_rtc_set_drift(struct fm *fm_dev, uint32_t drift)
++{
++      int _errno;
++      t_Error err;
++
++      err = FM_RTC_SetFreqCompensation(fm_get_rtc_handle(fm_dev),
++                      drift);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_RTC_SetFreqCompensation = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_rtc_set_drift);
++
++int fm_rtc_set_alarm(struct fm *fm_dev, uint32_t id,
++              uint64_t time)
++{
++      t_FmRtcAlarmParams alarm;
++      int _errno;
++      t_Error err;
++
++      alarm.alarmId = id;
++      alarm.alarmTime = time;
++      alarm.f_AlarmCallback = NULL;
++      err = FM_RTC_SetAlarm(fm_get_rtc_handle(fm_dev),
++                      &alarm);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_RTC_SetAlarm = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_rtc_set_alarm);
++
++int fm_rtc_set_fiper(struct fm *fm_dev, uint32_t id,
++              uint64_t fiper)
++{
++      t_FmRtcPeriodicPulseParams pp;
++      int _errno;
++      t_Error err;
++
++      pp.periodicPulseId = id;
++      pp.periodicPulsePeriod = fiper;
++      pp.f_PeriodicPulseCallback = NULL;
++      err = FM_RTC_SetPeriodicPulse(fm_get_rtc_handle(fm_dev), &pp);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_RTC_SetPeriodicPulse = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_rtc_set_fiper);
++
++#ifdef CONFIG_PTP_1588_CLOCK_DPAA
++int fm_rtc_enable_interrupt(struct fm *fm_dev, uint32_t events)
++{
++      int _errno;
++      t_Error err;
++
++      err = FM_RTC_EnableInterrupt(fm_get_rtc_handle(fm_dev),
++                      events);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_RTC_EnableInterrupt = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_rtc_enable_interrupt);
++
++int fm_rtc_disable_interrupt(struct fm *fm_dev, uint32_t events)
++{
++      int _errno;
++      t_Error err;
++
++      err = FM_RTC_DisableInterrupt(fm_get_rtc_handle(fm_dev),
++                      events);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_RTC_DisableInterrupt = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_rtc_disable_interrupt);
++#endif
++
++int fm_mac_set_wol(struct fm_port *port, struct fm_mac_dev *fm_mac_dev, bool en)
++{
++      int _errno;
++      t_Error err;
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
++
++      /* Do not set WoL on AR ports */
++      if (FM_PORT_IsInDsar(p_LnxWrpFmPortDev->h_Dev)) {
++              printk(KERN_WARNING "Port is AutoResponse enabled! WoL will not be set on this port!\n");
++              return 0;
++      }
++
++      err = FM_MAC_SetWakeOnLan(fm_mac_dev, en);
++
++      _errno = -GET_ERROR_TYPE(err);
++      if (_errno < 0)
++              pr_err("FM_MAC_SetWakeOnLan() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_mac_set_wol);
++
++void fm_mutex_lock(void)
++{
++    mutex_lock(&lnxwrp_mutex);
++}
++EXPORT_SYMBOL(fm_mutex_lock);
++
++void fm_mutex_unlock(void)
++{
++    mutex_unlock(&lnxwrp_mutex);
++}
++EXPORT_SYMBOL(fm_mutex_unlock);
++
++/*Macsec wrapper functions*/
++struct fm_macsec_dev *fm_macsec_config(struct fm_macsec_params *fm_params)
++{
++      struct fm_macsec_dev *fm_macsec_dev;
++
++      fm_macsec_dev = FM_MACSEC_Config((t_FmMacsecParams *)fm_params);
++      if (unlikely(fm_macsec_dev == NULL))
++              pr_err("FM_MACSEC_Config() failed\n");
++
++      return fm_macsec_dev;
++}
++EXPORT_SYMBOL(fm_macsec_config);
++
++int fm_macsec_init(struct fm_macsec_dev *fm_macsec_dev)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_Init(fm_macsec_dev);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_Init() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_init);
++
++int fm_macsec_free(struct fm_macsec_dev *fm_macsec_dev)
++{
++      int err;
++      int _error;
++
++      err = FM_MACSEC_Free(fm_macsec_dev);
++      _error = -GET_ERROR_TYPE(err);
++
++      if (unlikely(_error < 0))
++              pr_err("FM_MACSEC_Free() = 0x%08x\n", err);
++
++      return _error;
++}
++EXPORT_SYMBOL(fm_macsec_free);
++
++int fm_macsec_config_unknown_sci_frame_treatment(struct fm_macsec_dev
++                              *fm_macsec_dev,
++                              fm_macsec_unknown_sci_frame_treatment treat_mode)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_ConfigUnknownSciFrameTreatment(fm_macsec_dev,
++              treat_mode);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_ConfigUnknownSciFrameTreatmen() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_config_unknown_sci_frame_treatment);
++
++int fm_macsec_config_invalid_tags_frame_treatment(struct fm_macsec_dev *fm_macsec_dev,
++                              bool deliver_uncontrolled)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_ConfigInvalidTagsFrameTreatment(fm_macsec_dev,
++                                              deliver_uncontrolled);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MAC_ConfigMaxFrameLength() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_config_invalid_tags_frame_treatment);
++
++int fm_macsec_config_kay_frame_treatment(struct fm_macsec_dev *fm_macsec_dev,
++                              bool discard_uncontrolled)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment(fm_macsec_dev,
++                                              discard_uncontrolled);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatmen() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_config_kay_frame_treatment);
++
++int fm_macsec_config_untag_frame_treatment(struct fm_macsec_dev *fm_macsec_dev,
++                                  fm_macsec_untag_frame_treatment treat_mode)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_ConfigUntagFrameTreatment(fm_macsec_dev, treat_mode);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_ConfigUntagFrameTreatment() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_config_untag_frame_treatment);
++
++int fm_macsec_config_pn_exhaustion_threshold(struct fm_macsec_dev *fm_macsec_dev,
++                                      uint32_t pn_exh_thr)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_ConfigPnExhaustionThreshold(fm_macsec_dev, pn_exh_thr);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_ConfigPnExhaustionThreshold() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_config_pn_exhaustion_threshold);
++
++int fm_macsec_config_keys_unreadable(struct fm_macsec_dev *fm_macsec_dev)
++{
++      int err;
++      int _errno;
++
++      err =  FM_MACSEC_ConfigKeysUnreadable(fm_macsec_dev);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_ConfigKeysUnreadable() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_config_keys_unreadable);
++
++int fm_macsec_config_sectag_without_sci(struct fm_macsec_dev *fm_macsec_dev)
++{
++      int err;
++      int _errno;
++
++      err =  FM_MACSEC_ConfigSectagWithoutSCI(fm_macsec_dev);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_ConfigSectagWithoutSCI() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_config_sectag_without_sci);
++
++int fm_macsec_config_exception(struct fm_macsec_dev *fm_macsec_dev,
++                          fm_macsec_exception exception, bool enable)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_ConfigException(fm_macsec_dev, exception, enable);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_ConfigException() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_config_exception);
++
++int fm_macsec_get_revision(struct fm_macsec_dev *fm_macsec_dev,
++                          int *macsec_revision)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_GetRevision(fm_macsec_dev, macsec_revision);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_GetRevision() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_get_revision);
++
++int fm_macsec_enable(struct fm_macsec_dev *fm_macsec_dev)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_Enable(fm_macsec_dev);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_Enable() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_enable);
++
++int fm_macsec_disable(struct fm_macsec_dev *fm_macsec_dev)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_Disable(fm_macsec_dev);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_Disable() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_disable);
++
++int fm_macsec_set_exception(struct fm_macsec_dev *fm_macsec_dev,
++                      fm_macsec_exception exception, bool enable)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SetException(fm_macsec_dev, exception, enable);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SetException() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_set_exception);
++
++/* Macsec SECY wrapper API */
++struct fm_macsec_secy_dev *fm_macsec_secy_config(struct fm_macsec_secy_params *secy_params)
++{
++      struct fm_macsec_secy_dev *fm_macsec_secy;
++
++      fm_macsec_secy = FM_MACSEC_SECY_Config((t_FmMacsecSecYParams *)secy_params);
++      if (unlikely(fm_macsec_secy < 0))
++              pr_err("FM_MACSEC_SECY_Config() failed\n");
++
++      return fm_macsec_secy;
++}
++EXPORT_SYMBOL(fm_macsec_secy_config);
++
++int fm_macsec_secy_init(struct fm_macsec_secy_dev *fm_macsec_secy_dev)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_Init(fm_macsec_secy_dev);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_Init() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_init);
++
++int fm_macsec_secy_free(struct fm_macsec_secy_dev *fm_macsec_secy_dev)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_Free(fm_macsec_secy_dev);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_Free() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_free);
++
++int fm_macsec_secy_config_sci_insertion_mode(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              fm_macsec_sci_insertion_mode sci_insertion_mode)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_ConfigSciInsertionMode(fm_macsec_secy_dev,
++                                      sci_insertion_mode);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_ConfigSciInsertionMode() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_config_sci_insertion_mode);
++
++int fm_macsec_secy_config_protect_frames(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              bool protect_frames)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_ConfigProtectFrames(fm_macsec_secy_dev,
++                                              protect_frames);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_ConfigProtectFrames() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_config_protect_frames);
++
++int fm_macsec_secy_config_replay_window(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              bool replay_protect, uint32_t replay_window)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_ConfigReplayWindow(fm_macsec_secy_dev,
++                                              replay_protect, replay_window);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_ConfigReplayWindow() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_config_replay_window);
++
++int fm_macsec_secy_config_validation_mode(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              fm_macsec_valid_frame_behavior validate_frames)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_ConfigValidationMode(fm_macsec_secy_dev,
++                                                  validate_frames);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_ConfigValidationMode() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_config_validation_mode);
++
++int fm_macsec_secy_config_confidentiality(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              bool confidentiality_enable,
++                              uint32_t confidentiality_offset)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_ConfigConfidentiality(fm_macsec_secy_dev,
++                                                  confidentiality_enable,
++                                                  confidentiality_offset);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_ConfigConfidentiality() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_config_confidentiality);
++
++int fm_macsec_secy_config_point_to_point(struct fm_macsec_secy_dev *fm_macsec_secy_dev)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_ConfigPointToPoint(fm_macsec_secy_dev);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_ConfigPointToPoint() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_config_point_to_point);
++
++int fm_macsec_secy_config_exception(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                  fm_macsec_secy_exception exception,
++                                  bool enable)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_ConfigException(fm_macsec_secy_dev, exception,
++                                          enable);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_ConfigException() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_config_exception);
++
++int fm_macsec_secy_config_event(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                  fm_macsec_secy_event event,
++                                  bool enable)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_ConfigEvent(fm_macsec_secy_dev, event, enable);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_ConfigEvent() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_config_event);
++
++struct rx_sc_dev *fm_macsec_secy_create_rxsc(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              struct fm_macsec_secy_sc_params  *params)
++{
++      struct rx_sc_dev *rx_sc_dev;
++
++      rx_sc_dev = FM_MACSEC_SECY_CreateRxSc(fm_macsec_secy_dev, (t_FmMacsecSecYSCParams *)params);
++      if (unlikely(rx_sc_dev == NULL))
++              pr_err("FM_MACSEC_SECY_CreateRxSc() failed\n");
++
++      return rx_sc_dev;
++}
++EXPORT_SYMBOL(fm_macsec_secy_create_rxsc);
++
++int fm_macsec_secy_delete_rxsc(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              struct rx_sc_dev *sc)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_DeleteRxSc(fm_macsec_secy_dev, sc);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_DeleteRxSc() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_delete_rxsc);
++
++int fm_macsec_secy_create_rx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              struct rx_sc_dev *sc, macsec_an_t an,
++                              uint32_t lowest_pn, macsec_sa_key_t key)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_CreateRxSa(fm_macsec_secy_dev, sc, an,
++                                      lowest_pn, key);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_CreateRxSa() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_create_rx_sa);
++
++int fm_macsec_secy_delete_rx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              struct rx_sc_dev *sc, macsec_an_t an)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_DeleteRxSa(fm_macsec_secy_dev, sc, an);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_DeleteRxSa() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_delete_rx_sa);
++
++int fm_macsec_secy_rxsa_enable_receive(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      struct rx_sc_dev *sc,
++                                      macsec_an_t an)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_RxSaEnableReceive(fm_macsec_secy_dev, sc, an);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_RxSaEnableReceive() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_rxsa_enable_receive);
++
++int fm_macsec_secy_rxsa_disable_receive(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      struct rx_sc_dev *sc,
++                                      macsec_an_t an)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_RxSaDisableReceive(fm_macsec_secy_dev, sc, an);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_RxSaDisableReceive() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_rxsa_disable_receive);
++
++int fm_macsec_secy_rxsa_update_next_pn(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      struct rx_sc_dev *sc,
++                                      macsec_an_t an, uint32_t updt_next_pn)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_RxSaUpdateNextPn(fm_macsec_secy_dev, sc, an,
++                                              updt_next_pn);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_RxSaUpdateNextPn() = 0x%08x\n", err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_rxsa_update_next_pn);
++
++int fm_macsec_secy_rxsa_update_lowest_pn(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      struct rx_sc_dev *sc,
++                                      macsec_an_t an, uint32_t updt_lowest_pn)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_RxSaUpdateLowestPn(fm_macsec_secy_dev, sc, an,
++                                              updt_lowest_pn);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_RxSaUpdateLowestPn() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_rxsa_update_lowest_pn);
++
++int fm_macsec_secy_rxsa_modify_key(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      struct rx_sc_dev *sc,
++                                      macsec_an_t an, macsec_sa_key_t key)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_RxSaModifyKey(fm_macsec_secy_dev, sc, an, key);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_RxSaModifyKey() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_rxsa_modify_key);
++
++int fm_macsec_secy_create_tx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              macsec_an_t an, macsec_sa_key_t key)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_CreateTxSa(fm_macsec_secy_dev, an, key);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_CreateTxSa() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_create_tx_sa);
++
++int fm_macsec_secy_delete_tx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              macsec_an_t an)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_DeleteTxSa(fm_macsec_secy_dev, an);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_DeleteTxSa() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_delete_tx_sa);
++
++int fm_macsec_secy_txsa_modify_key(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      macsec_an_t next_active_an,
++                                      macsec_sa_key_t key)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_TxSaModifyKey(fm_macsec_secy_dev, next_active_an,
++                                          key);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_TxSaModifyKey() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_txsa_modify_key);
++
++int fm_macsec_secy_txsa_set_active(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      macsec_an_t an)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_TxSaSetActive(fm_macsec_secy_dev, an);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_TxSaSetActive() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_txsa_set_active);
++
++int fm_macsec_secy_txsa_get_active(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                      macsec_an_t *p_an)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_TxSaGetActive(fm_macsec_secy_dev, p_an);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_TxSaGetActive() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_txsa_get_active);
++
++int fm_macsec_secy_get_rxsc_phys_id(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                              struct rx_sc_dev *sc, uint32_t *sc_phys_id)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_GetRxScPhysId(fm_macsec_secy_dev, sc, sc_phys_id);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_GetRxScPhysId() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_get_rxsc_phys_id);
++
++int fm_macsec_secy_get_txsc_phys_id(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
++                                  uint32_t *sc_phys_id)
++{
++      int err;
++      int _errno;
++
++      err = FM_MACSEC_SECY_GetTxScPhysId(fm_macsec_secy_dev, sc_phys_id);
++      _errno = -GET_ERROR_TYPE(err);
++      if (unlikely(_errno < 0))
++              pr_err("FM_MACSEC_SECY_GetTxScPhysId() = 0x%08x\n",
++                      err);
++
++      return _errno;
++}
++EXPORT_SYMBOL(fm_macsec_secy_get_txsc_phys_id);
++
++static t_Handle h_FmLnxWrp;
++
++static int __init __cold fm_load (void)
++{
++    if ((h_FmLnxWrp = LNXWRP_FM_Init()) == NULL)
++    {
++        printk("Failed to init FM wrapper!\n");
++        return -ENODEV;
++    }
++
++      printk(KERN_CRIT "Freescale FM module," \
++              " FMD API version %d.%d.%d\n",
++              FMD_API_VERSION_MAJOR,
++              FMD_API_VERSION_MINOR,
++              FMD_API_VERSION_RESPIN);
++    return 0;
++}
++
++static void __exit __cold fm_unload (void)
++{
++    if (h_FmLnxWrp)
++        LNXWRP_FM_Free(h_FmLnxWrp);
++}
++
++module_init (fm_load);
++module_exit (fm_unload);
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.h
+@@ -0,0 +1,294 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ @File          lnxwrp_fm.h
++
++ @Author        Shlomi Gridish
++
++ @Description   FM Linux wrapper functions.
++
++*/
++
++#ifndef __LNXWRP_FM_H__
++#define __LNXWRP_FM_H__
++
++#include <linux/fsl_qman.h> /* struct qman_fq */
++
++#include "std_ext.h"
++#include "error_ext.h"
++#include "list_ext.h"
++
++#include "lnxwrp_fm_ext.h"
++
++#define FM_MAX_NUM_OF_ADV_SETTINGS          10
++
++#define LNXWRP_FM_NUM_OF_SHARED_PROFILES    16
++
++#if defined(CONFIG_FMAN_DISABLE_OH_TO_REUSE_RESOURCES)
++#define FM_10G_OPENDMA_MIN_TRESHOLD 8 /* 10g minimum treshold if only HC is enabled and no OH port enabled */
++#define FM_OPENDMA_RX_TX_RAPORT 2 /* RX = 2*TX */
++#else
++#define FM_10G_OPENDMA_MIN_TRESHOLD 7 /* 10g minimum treshold if 7 OH ports are enabled */
++#define FM_OPENDMA_RX_TX_RAPORT 1 /* RX = TX */
++#endif
++#define FM_DEFAULT_TX10G_OPENDMA 8 /* default TX 10g open dmas */
++#define FM_DEFAULT_RX10G_OPENDMA 8 /* default RX 10g open dmas */
++
++#define FRAG_MANIP_SPACE 128
++#define FRAG_DATA_ALIGN 64
++
++#ifndef CONFIG_FSL_FM_MAX_FRAME_SIZE
++#define CONFIG_FSL_FM_MAX_FRAME_SIZE 0
++#endif
++
++#ifndef CONFIG_FSL_FM_RX_EXTRA_HEADROOM
++#define CONFIG_FSL_FM_RX_EXTRA_HEADROOM       16
++#endif
++
++typedef enum {
++    e_NO_PCD = 0,
++    e_FM_PCD_3_TUPLE
++} e_LnxWrpFmPortPcdDefUseCase;
++
++
++typedef struct t_FmTestFq {
++    struct qman_fq      fq_base;
++    t_Handle            h_Arg;
++} t_FmTestFq;
++
++typedef struct {
++    uint8_t                     id; /* sw port id, see SW_PORT_ID_TO_HW_PORT_ID() in fm_common.h */
++    int                         minor;
++    char                        name[20];
++    bool                        active;
++    uint64_t                    phys_baseAddr;
++    uint64_t                    baseAddr;               /* Port's *virtual* address */
++    uint32_t                    memSize;
++    t_WrpFmPortDevSettings      settings;
++    t_FmExtPools                opExtPools;
++    uint8_t                     totalNumOfSchemes;
++    uint8_t                     schemesBase;
++    uint8_t                     numOfSchemesUsed;
++    uint32_t                    pcdBaseQ;
++    uint16_t                    pcdNumOfQs;
++    struct fm_port_pcd_param    pcd_owner_params;
++    e_LnxWrpFmPortPcdDefUseCase defPcd;
++    t_Handle                    h_DefNetEnv;
++    t_Handle                    h_Schemes[FM_PCD_KG_NUM_OF_SCHEMES];
++    t_FmBufferPrefixContent     buffPrefixContent;
++    t_Handle                    h_Dev;
++    t_Handle                    h_DfltVsp;
++    t_Handle                    h_LnxWrpFmDev;
++    uint16_t                    txCh;
++    struct device               *dev;
++    struct device_attribute     *dev_attr_stats;
++    struct device_attribute     *dev_attr_regs;
++    struct device_attribute     *dev_attr_bmi_regs;
++    struct device_attribute     *dev_attr_qmi_regs;
++#if (DPAA_VERSION >= 11)
++    struct device_attribute     *dev_attr_ipv4_opt;
++#endif
++    struct device_attribute     *dev_attr_dsar_regs;
++    struct device_attribute     *dev_attr_dsar_mem;
++    struct auto_res_tables_sizes dsar_table_sizes;
++} t_LnxWrpFmPortDev;
++
++typedef struct {
++    uint8_t                     id;
++    bool                        active;
++    uint64_t                    baseAddr;
++    uint32_t                    memSize;
++    t_WrpFmMacDevSettings       settings;
++    t_Handle                    h_Dev;
++    t_Handle                    h_LnxWrpFmDev;
++} t_LnxWrpFmMacDev;
++
++/* information about all active ports for an FMan.
++ * !Some ports may be disabled by u-boot, thus will not be available */
++struct fm_active_ports {
++    uint32_t num_oh_ports;
++    uint32_t num_tx_ports;
++    uint32_t num_rx_ports;
++    uint32_t num_tx25_ports;
++    uint32_t num_rx25_ports;
++    uint32_t num_tx10_ports;
++    uint32_t num_rx10_ports;
++};
++
++/* FMan resources precalculated at fm probe based
++ * on available FMan port. */
++struct fm_resource_settings {
++    /* buffers - fifo sizes */
++    uint32_t tx1g_num_buffers;
++    uint32_t rx1g_num_buffers;
++    uint32_t tx2g5_num_buffers; /* Not supported yet by LLD */
++    uint32_t rx2g5_num_buffers; /* Not supported yet by LLD */
++    uint32_t tx10g_num_buffers;
++    uint32_t rx10g_num_buffers;
++    uint32_t oh_num_buffers;
++    uint32_t shared_ext_buffers;
++
++    /* open DMAs */
++    uint32_t tx_1g_dmas;
++    uint32_t rx_1g_dmas;
++    uint32_t tx_2g5_dmas; /* Not supported yet by LLD */
++    uint32_t rx_2g5_dmas; /* Not supported yet by LLD */
++    uint32_t tx_10g_dmas;
++    uint32_t rx_10g_dmas;
++    uint32_t oh_dmas;
++    uint32_t shared_ext_open_dma;
++
++    /* Tnums */
++    uint32_t tx_1g_tnums;
++    uint32_t rx_1g_tnums;
++    uint32_t tx_2g5_tnums; /* Not supported yet by LLD */
++    uint32_t rx_2g5_tnums; /* Not supported yet by LLD */
++    uint32_t tx_10g_tnums;
++    uint32_t rx_10g_tnums;
++    uint32_t oh_tnums;
++    uint32_t shared_ext_tnums;
++};
++
++typedef struct {
++    uint8_t                     id;
++    char                        name[10];
++    bool                        active;
++    bool                        pcdActive;
++    bool                        prsActive;
++    bool                        kgActive;
++    bool                        ccActive;
++    bool                        plcrActive;
++    e_LnxWrpFmPortPcdDefUseCase defPcd;
++    uint32_t                    usedSchemes;
++    uint8_t                     totalNumOfSharedSchemes;
++    uint8_t                     sharedSchemesBase;
++    uint8_t                     numOfSchemesUsed;
++    uint8_t                     defNetEnvId;
++    uint64_t                    fmPhysBaseAddr;
++    uint64_t                    fmBaseAddr;
++    uint32_t                    fmMemSize;
++    uint64_t                    fmMuramPhysBaseAddr;
++    uint64_t                    fmMuramBaseAddr;
++    uint32_t                    fmMuramMemSize;
++    uint64_t                    fmRtcPhysBaseAddr;
++    uint64_t                    fmRtcBaseAddr;
++    uint32_t                    fmRtcMemSize;
++    uint64_t                    fmVspPhysBaseAddr;
++    uint64_t                    fmVspBaseAddr;
++    uint32_t                    fmVspMemSize;
++    int                         irq;
++    int                         err_irq;
++    t_WrpFmDevSettings          fmDevSettings;
++    t_WrpFmPcdDevSettings       fmPcdDevSettings;
++    t_Handle                    h_Dev;
++    uint16_t                    hcCh;
++
++    t_Handle                    h_MuramDev;
++    t_Handle                    h_PcdDev;
++    t_Handle                    h_RtcDev;
++
++    t_Handle                  h_DsarRxPort;
++    t_Handle                  h_DsarTxPort;
++
++    t_LnxWrpFmPortDev           hcPort;
++    t_LnxWrpFmPortDev           opPorts[FM_MAX_NUM_OF_OH_PORTS-1];
++    t_LnxWrpFmPortDev           rxPorts[FM_MAX_NUM_OF_RX_PORTS];
++    t_LnxWrpFmPortDev           txPorts[FM_MAX_NUM_OF_TX_PORTS];
++    t_LnxWrpFmMacDev            macs[FM_MAX_NUM_OF_MACS];
++    struct fm_active_ports      fm_active_ports_info;
++    struct fm_resource_settings fm_resource_settings_info;
++
++    struct device               *dev;
++    struct resource             *res;
++    int                         major;
++    struct class                *fm_class;
++    struct device_attribute     *dev_attr_stats;
++    struct device_attribute     *dev_attr_regs;
++    struct device_attribute     *dev_attr_risc_load;
++
++    struct device_attribute     *dev_pcd_attr_stats;
++    struct device_attribute     *dev_plcr_attr_regs;
++    struct device_attribute     *dev_prs_attr_regs;
++    struct device_attribute     *dev_fm_fpm_attr_regs;
++    struct device_attribute     *dev_fm_kg_attr_regs;
++    struct device_attribute     *dev_fm_kg_pe_attr_regs;
++    struct device_attribute     *dev_attr_muram_free_size;
++    struct device_attribute     *dev_attr_fm_ctrl_code_ver;
++
++
++    struct qman_fq              *hc_tx_conf_fq, *hc_tx_err_fq, *hc_tx_fq;
++} t_LnxWrpFmDev;
++
++typedef struct {
++    t_LnxWrpFmDev   *p_FmDevs[INTG_MAX_NUM_OF_FM];
++} t_LnxWrpFm;
++#define LNXWRP_FM_OBJECT(ptr)   LIST_OBJECT(ptr, t_LnxWrpFm, fms[((t_LnxWrpFmDev *)ptr)->id])
++
++
++t_Error  LnxwrpFmIOCTL(t_LnxWrpFmDev *p_LnxWrpFmDev, unsigned int cmd, unsigned long arg, bool compat);
++t_Error  LnxwrpFmPortIOCTL(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev, unsigned int cmd, unsigned long arg, bool compat);
++
++
++#if 0
++static __inline__ t_Error AllocSchemesForPort(t_LnxWrpFmDev *p_LnxWrpFmDev, uint8_t numSchemes, uint8_t *p_BaseSchemeNum)
++{
++    uint32_t    schemeMask;
++    uint8_t     i;
++
++    if (!numSchemes)
++        RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
++
++    schemeMask = 0x80000000;
++    *p_BaseSchemeNum = 0xff;
++
++    for (i=0; schemeMask && numSchemes; schemeMask>>=1, i++)
++        if ((p_LnxWrpFmDev->usedSchemes & schemeMask) == 0)
++        {
++            p_LnxWrpFmDev->usedSchemes |= schemeMask;
++            numSchemes--;
++            if (*p_BaseSchemeNum==0xff)
++                *p_BaseSchemeNum = i;
++        }
++        else if (*p_BaseSchemeNum!=0xff)
++            RETURN_ERROR(MINOR, E_INVALID_STATE, ("Fragmentation on schemes array!!!"));
++
++    if (numSchemes)
++        RETURN_ERROR(MINOR, E_FULL, ("schemes!!!"));
++    return E_OK;
++}
++#endif
++
++void LnxWrpPCDIOCTLTypeChecking(void);
++void LnxWrpPCDIOCTLEnumChecking(void);
++
++#endif /* __LNXWRP_FM_H__ */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c
+@@ -0,0 +1,1480 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ @File          lnxwrp_fm_port.c
++
++ @Description   FMD wrapper - FMan port functions.
++
++*/
++
++#include <linux/version.h>
++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
++#define MODVERSIONS
++#endif
++#ifdef MODVERSIONS
++#include <config/modversions.h>
++#endif /* MODVERSIONS */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include <linux/of_address.h>
++#include <linux/cdev.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#ifndef CONFIG_FMAN_ARM
++#include <linux/fsl/svr.h>
++#endif
++#include <linux/io.h>
++
++#include "sprint_ext.h"
++#include "fm_common.h"
++#include "lnxwrp_fsl_fman.h"
++#include "fm_port_ext.h"
++#if (DPAA_VERSION >= 11)
++#include "fm_vsp_ext.h"
++#endif /* DPAA_VERSION >= 11 */
++#include "fm_ioctls.h"
++#include "lnxwrp_resources.h"
++#include "lnxwrp_sysfs_fm_port.h"
++
++#define __ERR_MODULE__  MODULE_FM
++
++extern struct device_node *GetFmAdvArgsDevTreeNode (uint8_t fmIndx);
++
++/* TODO: duplicated, see lnxwrp_fm.c */
++#define ADD_ADV_CONFIG_NO_RET(_func, _param)\
++do {\
++      if (i < max) {\
++              p_Entry = &p_Entrys[i];\
++              p_Entry->p_Function = _func;\
++              _param\
++              i++;\
++      } else {\
++              REPORT_ERROR(MAJOR, E_INVALID_VALUE,\
++              ("Number of advanced-configuration entries exceeded"));\
++      } \
++} while (0)
++
++#ifndef CONFIG_FMAN_ARM
++#define IS_T1023_T1024        (SVR_SOC_VER(mfspr(SPRN_SVR)) == SVR_T1024 || \
++                      SVR_SOC_VER(mfspr(SPRN_SVR)) == SVR_T1023)
++#endif
++
++static volatile int hcFrmRcv/* = 0 */;
++static spinlock_t lock;
++
++static enum qman_cb_dqrr_result qm_tx_conf_dqrr_cb(struct qman_portal *portal,
++                                                 struct qman_fq *fq,
++                                                 const struct qm_dqrr_entry
++                                                 *dq)
++{
++      t_LnxWrpFmDev *p_LnxWrpFmDev = ((t_FmTestFq *) fq)->h_Arg;
++      unsigned long flags;
++
++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
++{
++      /* extract the HC frame address */
++      uint32_t *hcf_va = XX_PhysToVirt(qm_fd_addr((struct qm_fd *)&dq->fd));
++      int hcf_l = ((struct qm_fd *)&dq->fd)->length20;
++      int i;
++
++      /* 32b byteswap of all data in the HC Frame */
++      for(i = 0; i < hcf_l / 4; ++i)
++              hcf_va[i] =
++                      ___constant_swab32(hcf_va[i]);
++}
++#endif
++      FM_PCD_HcTxConf(p_LnxWrpFmDev->h_PcdDev, (t_DpaaFD *)&dq->fd);
++      spin_lock_irqsave(&lock, flags);
++      hcFrmRcv--;
++      spin_unlock_irqrestore(&lock, flags);
++
++      return qman_cb_dqrr_consume;
++}
++
++static enum qman_cb_dqrr_result qm_tx_dqrr_cb(struct qman_portal *portal,
++                                            struct qman_fq *fq,
++                                            const struct qm_dqrr_entry *dq)
++{
++      WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__,
++           __func__);
++      return qman_cb_dqrr_consume;
++}
++
++static void qm_err_cb(struct qman_portal *portal,
++                    struct qman_fq *fq, const struct qm_mr_entry *msg)
++{
++      WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__,
++           __func__);
++}
++
++static struct qman_fq *FqAlloc(t_LnxWrpFmDev * p_LnxWrpFmDev,
++                             uint32_t fqid,
++                             uint32_t flags, uint16_t channel, uint8_t wq)
++{
++      int _errno;
++      struct qman_fq *fq = NULL;
++      t_FmTestFq *p_FmtFq;
++      struct qm_mcc_initfq initfq;
++
++      p_FmtFq = (t_FmTestFq *) XX_Malloc(sizeof(t_FmTestFq));
++      if (!p_FmtFq) {
++              REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj!!!"));
++              return NULL;
++      }
++
++      p_FmtFq->fq_base.cb.dqrr = ((flags & QMAN_FQ_FLAG_NO_ENQUEUE)
++                      ? qm_tx_conf_dqrr_cb
++                      : qm_tx_dqrr_cb);
++      p_FmtFq->fq_base.cb.ern = qm_err_cb;
++      /* p_FmtFq->fq_base.cb.fqs = qm_err_cb; */
++      /* qm_err_cb wrongly called when the FQ is parked */
++      p_FmtFq->fq_base.cb.fqs = NULL;
++      p_FmtFq->h_Arg = (t_Handle) p_LnxWrpFmDev;
++      if (fqid == 0) {
++              flags |= QMAN_FQ_FLAG_DYNAMIC_FQID;
++              flags &= ~QMAN_FQ_FLAG_NO_MODIFY;
++      } else {
++              flags &= ~QMAN_FQ_FLAG_DYNAMIC_FQID;
++      }
++
++      if (qman_create_fq(fqid, flags, &p_FmtFq->fq_base)) {
++              REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj - qman_new_fq!!!"));
++              XX_Free(p_FmtFq);
++              return NULL;
++      }
++      fq = &p_FmtFq->fq_base;
++
++      if (!(flags & QMAN_FQ_FLAG_NO_MODIFY)) {
++              initfq.we_mask = QM_INITFQ_WE_DESTWQ;
++              initfq.fqd.dest.channel = channel;
++              initfq.fqd.dest.wq = wq;
++
++              _errno = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &initfq);
++              if (unlikely(_errno < 0)) {
++                      REPORT_ERROR(MAJOR, E_NO_MEMORY,
++                                   ("FQ obj - qman_init_fq!!!"));
++                      qman_destroy_fq(fq, 0);
++                      XX_Free(p_FmtFq);
++                      return NULL;
++              }
++      }
++
++      DBG(TRACE,
++          ("fqid %d, flags 0x%08x, channel %d, wq %d", qman_fq_fqid(fq),
++           flags, channel, wq));
++
++      return fq;
++}
++
++static void FqFree(struct qman_fq *fq)
++{
++      int _errno;
++
++      _errno = qman_retire_fq(fq, NULL);
++      if (unlikely(_errno < 0))
++              printk(KERN_WARNING "qman_retire_fq(%u) = %d\n", qman_fq_fqid(fq), _errno);
++
++      _errno = qman_oos_fq(fq);
++      if (unlikely(_errno < 0))
++              printk(KERN_WARNING "qman_oos_fq(%u) = %d\n", qman_fq_fqid(fq), _errno);
++
++      qman_destroy_fq(fq, 0);
++      XX_Free((t_FmTestFq *) fq);
++}
++
++static t_Error QmEnqueueCB(t_Handle h_Arg, void *p_Fd)
++{
++      t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *) h_Arg;
++      int _errno, timeout = 1000000;
++      unsigned long flags;
++
++      ASSERT_COND(p_LnxWrpFmDev);
++
++      spin_lock_irqsave(&lock, flags);
++      hcFrmRcv++;
++      spin_unlock_irqrestore(&lock, flags);
++
++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
++{
++      /* extract the HC frame address */
++      uint32_t *hcf_va = XX_PhysToVirt(qm_fd_addr((struct qm_fd *) p_Fd));
++      int hcf_l = ((struct qm_fd *)p_Fd)->length20;
++      int i;
++
++      /* 32b byteswap of all data in the HC Frame */
++      for(i = 0; i < hcf_l / 4; ++i)
++              hcf_va[i] =
++                      ___constant_swab32(hcf_va[i]);
++}
++#endif
++
++      _errno = qman_enqueue(p_LnxWrpFmDev->hc_tx_fq, (struct qm_fd *) p_Fd,
++                            0);
++      if (_errno)
++              RETURN_ERROR(MINOR, E_INVALID_STATE,
++                           ("qman_enqueue() failed"));
++
++      while (hcFrmRcv && --timeout) {
++              udelay(1);
++              cpu_relax();
++      }
++      if (timeout == 0) {
++              dump_stack();
++              RETURN_ERROR(MINOR, E_WRITE_FAILED,
++                           ("timeout waiting for Tx confirmation"));
++              return E_WRITE_FAILED;
++      }
++
++      return E_OK;
++}
++
++static t_LnxWrpFmPortDev *ReadFmPortDevTreeNode(struct platform_device
++                                              *of_dev)
++{
++      t_LnxWrpFmDev *p_LnxWrpFmDev;
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
++      struct device_node *fm_node, *port_node;
++      struct resource res;
++      const uint32_t *uint32_prop;
++      int _errno = 0, lenp;
++      uint32_t tmp_prop;
++
++#ifdef CONFIG_FMAN_P1023
++      static unsigned char have_oh_port/* = 0 */;
++#endif
++
++      port_node = of_node_get(of_dev->dev.of_node);
++
++      /* Get the FM node */
++      fm_node = of_get_parent(port_node);
++      if (unlikely(fm_node == NULL)) {
++              REPORT_ERROR(MAJOR, E_NO_DEVICE,
++                           ("of_get_parent() = %d", _errno));
++              return NULL;
++      }
++
++      p_LnxWrpFmDev =
++              dev_get_drvdata(&of_find_device_by_node(fm_node)->dev);
++      of_node_put(fm_node);
++
++      /* if fm_probe() failed, no point in going further with port probing */
++      if (p_LnxWrpFmDev == NULL)
++              return NULL;
++
++      uint32_prop =
++              (uint32_t *) of_get_property(port_node, "cell-index", &lenp);
++      if (unlikely(uint32_prop == NULL)) {
++              REPORT_ERROR(MAJOR, E_INVALID_VALUE,
++                           ("of_get_property(%s, cell-index) failed",
++                            port_node->full_name));
++              return NULL;
++      }
++      tmp_prop = be32_to_cpu(*uint32_prop);
++      if (WARN_ON(lenp != sizeof(uint32_t)))
++              return NULL;
++      if (of_device_is_compatible(port_node, "fsl,fman-port-oh")) {
++              if (unlikely(tmp_prop >= FM_MAX_NUM_OF_OH_PORTS)) {
++                      REPORT_ERROR(MAJOR, E_INVALID_VALUE,
++                                   ("of_get_property(%s, cell-index) failed",
++                                    port_node->full_name));
++                      return NULL;
++              }
++
++#ifdef CONFIG_FMAN_P1023
++              /* Beware, this can be done when there is only
++                 one FMan to be initialized */
++              if (!have_oh_port) {
++                      have_oh_port = 1; /* first OP/HC port
++                                           is used for host command */
++#else
++              /* Here it is hardcoded the use of the OH port 1
++                 (with cell-index 0) */
++              if (tmp_prop == 0) {
++#endif
++                      p_LnxWrpFmPortDev = &p_LnxWrpFmDev->hcPort;
++                      p_LnxWrpFmPortDev->id = 0;
++                      /*
++                      p_LnxWrpFmPortDev->id = *uint32_prop-1;
++                      p_LnxWrpFmPortDev->id = *uint32_prop;
++                      */
++                      p_LnxWrpFmPortDev->settings.param.portType =
++                              e_FM_PORT_TYPE_OH_HOST_COMMAND;
++              } else {
++                      p_LnxWrpFmPortDev =
++                              &p_LnxWrpFmDev->opPorts[tmp_prop - 1];
++                      p_LnxWrpFmPortDev->id = tmp_prop- 1;
++                      p_LnxWrpFmPortDev->settings.param.portType =
++                              e_FM_PORT_TYPE_OH_OFFLINE_PARSING;
++              }
++              p_LnxWrpFmPortDev->settings.param.portId = tmp_prop;
++
++              uint32_prop =
++                      (uint32_t *) of_get_property(port_node,
++                                                   "fsl,qman-channel-id",
++                                                   &lenp);
++              if (uint32_prop == NULL) {
++                                              /*
++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("missing fsl,qman-channel-id"));
++ */
++                      XX_Print("FM warning: missing fsl,qman-channel-id"
++                                      " for OH port.\n");
++                      return NULL;
++              }
++              tmp_prop = be32_to_cpu(*uint32_prop);
++              if (WARN_ON(lenp != sizeof(uint32_t)))
++                      return NULL;
++              p_LnxWrpFmPortDev->txCh = tmp_prop;
++
++              p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams.
++                      qmChannel = p_LnxWrpFmPortDev->txCh;
++      } else if (of_device_is_compatible(port_node, "fsl,fman-port-1g-tx")) {
++              tmp_prop -= 0x28;
++              if (unlikely(tmp_prop >= FM_MAX_NUM_OF_1G_TX_PORTS)) {
++                      REPORT_ERROR(MAJOR, E_INVALID_VALUE,
++                                      ("of_get_property(%s, cell-index) failed",
++                                       port_node->full_name));
++                      return NULL;
++              }
++              p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[tmp_prop];
++
++              p_LnxWrpFmPortDev->id = tmp_prop;
++              p_LnxWrpFmPortDev->settings.param.portId =
++                      p_LnxWrpFmPortDev->id;
++              p_LnxWrpFmPortDev->settings.param.portType = e_FM_PORT_TYPE_TX;
++
++              uint32_prop = (uint32_t *) of_get_property(port_node,
++                              "fsl,qman-channel-id", &lenp);
++              if (uint32_prop == NULL) {
++                      REPORT_ERROR(MAJOR, E_INVALID_VALUE,
++                                      ("missing fsl,qman-channel-id"));
++                      return NULL;
++              }
++              tmp_prop = be32_to_cpu(*uint32_prop);
++              if (WARN_ON(lenp != sizeof(uint32_t)))
++                      return NULL;
++              p_LnxWrpFmPortDev->txCh = tmp_prop;
++              p_LnxWrpFmPortDev->
++                      settings.param.specificParams.nonRxParams.qmChannel =
++                      p_LnxWrpFmPortDev->txCh;
++      } else if (of_device_is_compatible(port_node, "fsl,fman-port-10g-tx")) {
++              tmp_prop -= 0x30;
++              if (unlikely(tmp_prop>= FM_MAX_NUM_OF_10G_TX_PORTS)) {
++                      REPORT_ERROR(MAJOR, E_INVALID_VALUE,
++                                      ("of_get_property(%s, cell-index) failed",
++                                       port_node->full_name));
++                      return NULL;
++              }
++              p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[tmp_prop +
++                      FM_MAX_NUM_OF_1G_TX_PORTS];
++#ifndef CONFIG_FMAN_ARM
++              if (IS_T1023_T1024)
++                      p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[*uint32_prop];
++#endif
++
++              p_LnxWrpFmPortDev->id = tmp_prop;
++              p_LnxWrpFmPortDev->settings.param.portId =
++                      p_LnxWrpFmPortDev->id;
++              p_LnxWrpFmPortDev->settings.param.portType =
++                      e_FM_PORT_TYPE_TX_10G;
++              uint32_prop = (uint32_t *) of_get_property(port_node,
++                              "fsl,qman-channel-id", &lenp);
++              if (uint32_prop == NULL) {
++                      REPORT_ERROR(MAJOR, E_INVALID_VALUE,
++                                      ("missing fsl,qman-channel-id"));
++                      return NULL;
++              }
++              tmp_prop = be32_to_cpu(*uint32_prop);
++              if (WARN_ON(lenp != sizeof(uint32_t)))
++                      return NULL;
++              p_LnxWrpFmPortDev->txCh = tmp_prop;
++              p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams.
++                      qmChannel = p_LnxWrpFmPortDev->txCh;
++      } else if (of_device_is_compatible(port_node, "fsl,fman-port-1g-rx")) {
++              tmp_prop -= 0x08;
++              if (unlikely(tmp_prop >= FM_MAX_NUM_OF_1G_RX_PORTS)) {
++                      REPORT_ERROR(MAJOR, E_INVALID_VALUE,
++                                      ("of_get_property(%s, cell-index) failed",
++                                       port_node->full_name));
++                      return NULL;
++              }
++              p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[tmp_prop];
++
++              p_LnxWrpFmPortDev->id = tmp_prop;
++              p_LnxWrpFmPortDev->settings.param.portId =
++                      p_LnxWrpFmPortDev->id;
++              p_LnxWrpFmPortDev->settings.param.portType = e_FM_PORT_TYPE_RX;
++              if (p_LnxWrpFmDev->pcdActive)
++                      p_LnxWrpFmPortDev->defPcd = p_LnxWrpFmDev->defPcd;
++      } else if (of_device_is_compatible(port_node, "fsl,fman-port-10g-rx")) {
++              tmp_prop -= 0x10;
++              if (unlikely(tmp_prop >= FM_MAX_NUM_OF_10G_RX_PORTS)) {
++                      REPORT_ERROR(MAJOR, E_INVALID_VALUE,
++                                      ("of_get_property(%s, cell-index) failed",
++                                       port_node->full_name));
++                      return NULL;
++              }
++              p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[tmp_prop +
++                      FM_MAX_NUM_OF_1G_RX_PORTS];
++
++#ifndef CONFIG_FMAN_ARM
++              if (IS_T1023_T1024)
++                      p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[*uint32_prop];
++#endif
++
++              p_LnxWrpFmPortDev->id = tmp_prop;
++              p_LnxWrpFmPortDev->settings.param.portId =
++                      p_LnxWrpFmPortDev->id;
++              p_LnxWrpFmPortDev->settings.param.portType =
++                      e_FM_PORT_TYPE_RX_10G;
++              if (p_LnxWrpFmDev->pcdActive)
++                      p_LnxWrpFmPortDev->defPcd = p_LnxWrpFmDev->defPcd;
++      } else {
++              REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal port type"));
++              return NULL;
++      }
++
++      _errno = of_address_to_resource(port_node, 0, &res);
++      if (unlikely(_errno < 0)) {
++              REPORT_ERROR(MAJOR, E_INVALID_VALUE,
++                           ("of_address_to_resource() = %d", _errno));
++              return NULL;
++      }
++
++      p_LnxWrpFmPortDev->dev = &of_dev->dev;
++      p_LnxWrpFmPortDev->baseAddr = 0;
++      p_LnxWrpFmPortDev->phys_baseAddr = res.start;
++      p_LnxWrpFmPortDev->memSize = res.end + 1 - res.start;
++      p_LnxWrpFmPortDev->settings.param.h_Fm = p_LnxWrpFmDev->h_Dev;
++      p_LnxWrpFmPortDev->h_LnxWrpFmDev = (t_Handle) p_LnxWrpFmDev;
++
++      of_node_put(port_node);
++
++      p_LnxWrpFmPortDev->active = TRUE;
++
++#if defined(CONFIG_FMAN_DISABLE_OH_TO_REUSE_RESOURCES)
++      /* for performance mode no OH port available. */
++      if (p_LnxWrpFmPortDev->settings.param.portType ==
++          e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++              p_LnxWrpFmPortDev->active = FALSE;
++#endif
++
++      return p_LnxWrpFmPortDev;
++}
++
++struct device_node * GetFmPortAdvArgsDevTreeNode (struct device_node *fm_node,
++                                                         e_FmPortType       portType,
++                                                         uint8_t            portId)
++{
++    struct device_node  *port_node;
++    const uint32_t      *uint32_prop;
++    int                 lenp;
++    char                *portTypeString;
++    uint32_t            tmp_prop;
++
++    switch(portType) {
++        case e_FM_PORT_TYPE_OH_OFFLINE_PARSING:
++            portTypeString = "fsl,fman-port-op-extended-args";
++            break;
++        case e_FM_PORT_TYPE_TX:
++            portTypeString = "fsl,fman-port-1g-tx-extended-args";
++            break;
++        case e_FM_PORT_TYPE_TX_10G:
++            portTypeString = "fsl,fman-port-10g-tx-extended-args";
++            break;
++        case e_FM_PORT_TYPE_RX:
++            portTypeString = "fsl,fman-port-1g-rx-extended-args";
++            break;
++        case e_FM_PORT_TYPE_RX_10G:
++            portTypeString = "fsl,fman-port-10g-rx-extended-args";
++            break;
++        default:
++            return NULL;
++    }
++
++    for_each_child_of_node(fm_node, port_node) {
++        uint32_prop = (uint32_t *)of_get_property(port_node, "cell-index", &lenp);
++        if (unlikely(uint32_prop == NULL)) {
++            REPORT_ERROR(MAJOR, E_INVALID_VALUE,
++                         ("of_get_property(%s, cell-index) failed",
++                          port_node->full_name));
++            return NULL;
++        }
++        tmp_prop = be32_to_cpu(*uint32_prop);
++        if (WARN_ON(lenp != sizeof(uint32_t)))
++            return NULL;
++      if ((portId == tmp_prop) &&
++          (of_device_is_compatible(port_node, portTypeString))) {
++            return port_node;
++      }
++    }
++
++    return NULL;
++}
++
++static t_Error CheckNConfigFmPortAdvArgs (t_LnxWrpFmPortDev *p_LnxWrpFmPortDev)
++{
++    struct device_node      *fm_node, *port_node;
++    t_Error                 err;
++    t_FmPortRsrc            portRsrc;
++    const uint32_t          *uint32_prop;
++    /*const char              *str_prop;*/
++    int                     lenp;
++#ifdef CONFIG_FMAN_PFC
++    uint8_t i, id, num_pools;
++    t_FmBufPoolDepletion poolDepletion;
++
++    if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX ||
++            p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX_10G) {
++        memset(&poolDepletion, 0, sizeof(t_FmBufPoolDepletion));
++        poolDepletion.singlePoolModeEnable = true;
++        num_pools = p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.
++                extBufPools.numOfPoolsUsed;
++        for (i = 0; i < num_pools; i++) {
++            id = p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.
++                    extBufPools.extBufPool[i].id;
++            poolDepletion.poolsToConsiderForSingleMode[id] = true;
++        }
++
++        for (i = 0; i < CONFIG_FMAN_PFC_COS_COUNT; i++)
++            poolDepletion.pfcPrioritiesEn[i] = true;
++
++        err = FM_PORT_ConfigPoolDepletion(p_LnxWrpFmPortDev->h_Dev,
++                &poolDepletion);
++        if (err != E_OK)
++            RETURN_ERROR(MAJOR, err, ("FM_PORT_ConfigPoolDepletion() failed"));
++    }
++#endif
++
++    fm_node = GetFmAdvArgsDevTreeNode(((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev)->id);
++    if (!fm_node) /* no advance parameters for FMan */
++        return E_OK;
++
++    port_node = GetFmPortAdvArgsDevTreeNode(fm_node,
++                                            p_LnxWrpFmPortDev->settings.param.portType,
++                                            p_LnxWrpFmPortDev->settings.param.portId);
++    if (!port_node) /* no advance parameters for FMan-Port */
++        return E_OK;
++
++    uint32_prop = (uint32_t *)of_get_property(port_node, "num-tnums", &lenp);
++    if (uint32_prop) {
++      if (WARN_ON(lenp != sizeof(uint32_t)*2))
++            RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
++
++        portRsrc.num   = be32_to_cpu(uint32_prop[0]);
++        portRsrc.extra = be32_to_cpu(uint32_prop[1]);
++
++        if ((err = FM_PORT_ConfigNumOfTasks(p_LnxWrpFmPortDev->h_Dev,
++                                            &portRsrc)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++
++    uint32_prop = (uint32_t *)of_get_property(port_node, "num-dmas", &lenp);
++    if (uint32_prop) {
++      if (WARN_ON(lenp != sizeof(uint32_t)*2))
++            RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
++
++        portRsrc.num   = be32_to_cpu(uint32_prop[0]);
++        portRsrc.extra = be32_to_cpu(uint32_prop[1]);
++
++        if ((err = FM_PORT_ConfigNumOfOpenDmas(p_LnxWrpFmPortDev->h_Dev,
++                                            &portRsrc)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++
++    uint32_prop = (uint32_t *)of_get_property(port_node, "fifo-size", &lenp);
++    if (uint32_prop) {
++      if (WARN_ON(lenp != sizeof(uint32_t)*2))
++            RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
++
++        portRsrc.num   = be32_to_cpu(uint32_prop[0]);
++        portRsrc.extra = be32_to_cpu(uint32_prop[1]);
++
++        if ((err = FM_PORT_ConfigSizeOfFifo(p_LnxWrpFmPortDev->h_Dev,
++                                            &portRsrc)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++
++    uint32_prop = (uint32_t *)of_get_property(port_node, "errors-to-discard", &lenp);
++    if (uint32_prop) {
++      if (WARN_ON(lenp != sizeof(uint32_t)))
++            RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
++        if ((err = FM_PORT_ConfigErrorsToDiscard(p_LnxWrpFmPortDev->h_Dev,
++                                                 be32_to_cpu(uint32_prop[0]))) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++
++    uint32_prop = (uint32_t *)of_get_property(port_node, "ar-tables-sizes",
++      &lenp);
++    if (uint32_prop) {
++    
++      if (WARN_ON(lenp != sizeof(uint32_t)*8))
++            RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
++      if (WARN_ON(p_LnxWrpFmPortDev->settings.param.portType !=
++              e_FM_PORT_TYPE_RX) &&
++              (p_LnxWrpFmPortDev->settings.param.portType !=
++              e_FM_PORT_TYPE_RX_10G))
++            RETURN_ERROR(MINOR, E_INVALID_VALUE,
++              ("Auto Response is an Rx port atribute."));
++
++        memset(&p_LnxWrpFmPortDev->dsar_table_sizes, 0, sizeof(struct auto_res_tables_sizes));
++
++        p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_arp_entries        =
++              (uint16_t)be32_to_cpu(uint32_prop[0]);
++        p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_echo_ipv4_entries  =
++              (uint16_t)be32_to_cpu(uint32_prop[1]);
++        p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_ndp_entries        =
++              (uint16_t)be32_to_cpu(uint32_prop[2]);
++        p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_echo_ipv6_entries  =
++              (uint16_t)be32_to_cpu(uint32_prop[3]);
++        p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_snmp_ipv4_entries   =
++              (uint16_t)be32_to_cpu(uint32_prop[4]);
++        p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_snmp_ipv6_entries   =
++              (uint16_t)be32_to_cpu(uint32_prop[5]);
++        p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_snmp_oid_entries   =
++              (uint16_t)be32_to_cpu(uint32_prop[6]);
++        p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_snmp_char          =
++              (uint16_t)be32_to_cpu(uint32_prop[7]);
++
++      uint32_prop = (uint32_t *)of_get_property(port_node,
++              "ar-filters-sizes", &lenp);
++        if (uint32_prop) {
++              if (WARN_ON(lenp != sizeof(uint32_t)*3))
++                RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
++         
++            p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_ip_prot_filtering  =
++              (uint16_t)be32_to_cpu(uint32_prop[0]);
++            p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_tcp_port_filtering =
++              (uint16_t)be32_to_cpu(uint32_prop[1]);
++            p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_udp_port_filtering =
++              (uint16_t)be32_to_cpu(uint32_prop[2]);
++        }
++        
++        if ((err = FM_PORT_ConfigDsarSupport(p_LnxWrpFmPortDev->h_Dev,
++              (t_FmPortDsarTablesSizes*)&p_LnxWrpFmPortDev->dsar_table_sizes)) != E_OK)
++              RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++
++    of_node_put(port_node);
++    of_node_put(fm_node);
++
++    return E_OK;
++}
++
++static t_Error CheckNSetFmPortAdvArgs (t_LnxWrpFmPortDev *p_LnxWrpFmPortDev)
++{
++    struct device_node      *fm_node, *port_node;
++    t_Error                 err;
++    const uint32_t          *uint32_prop;
++    /*const char              *str_prop;*/
++    int                     lenp;
++
++    fm_node = GetFmAdvArgsDevTreeNode(((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev)->id);
++    if (!fm_node) /* no advance parameters for FMan */
++        return E_OK;
++
++    port_node = GetFmPortAdvArgsDevTreeNode(fm_node,
++                                            p_LnxWrpFmPortDev->settings.param.portType,
++                                            p_LnxWrpFmPortDev->settings.param.portId);
++    if (!port_node) /* no advance parameters for FMan-Port */
++        return E_OK;
++
++#if (DPAA_VERSION >= 11)
++    uint32_prop = (uint32_t *)of_get_property(port_node, "vsp-window", &lenp);
++    if (uint32_prop) {
++        t_FmPortVSPAllocParams  portVSPAllocParams;
++        t_FmVspParams           fmVspParams;
++        t_LnxWrpFmDev           *p_LnxWrpFmDev;
++        uint8_t                 portId;
++
++        p_LnxWrpFmDev = ((t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev);
++
++      if (WARN_ON(lenp != sizeof(uint32_t)*2))
++            RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
++
++        if ((p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_TX) ||
++            (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_TX_10G) ||
++            ((p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) &&
++             p_LnxWrpFmPortDev->settings.frag_enabled))
++            return E_OK;
++
++        memset(&portVSPAllocParams, 0, sizeof(portVSPAllocParams));
++        memset(&fmVspParams, 0, sizeof(fmVspParams));
++
++        portVSPAllocParams.numOfProfiles = (uint8_t)be32_to_cpu(uint32_prop[0]);
++        portVSPAllocParams.dfltRelativeId = (uint8_t)be32_to_cpu(uint32_prop[1]);
++        fmVspParams.h_Fm = p_LnxWrpFmDev->h_Dev;
++
++        fmVspParams.portParams.portType = p_LnxWrpFmPortDev->settings.param.portType;
++        fmVspParams.portParams.portId   = p_LnxWrpFmPortDev->settings.param.portId;
++        fmVspParams.relativeProfileId   = portVSPAllocParams.dfltRelativeId;
++
++        if (p_LnxWrpFmPortDev->settings.param.portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
++        {
++            portId = fmVspParams.portParams.portId;
++            if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX_10G){
++#ifndef CONFIG_FMAN_ARM
++              if (!(IS_T1023_T1024))
++#endif
++                    portId += FM_MAX_NUM_OF_1G_RX_PORTS;
++          }
++          portVSPAllocParams.h_FmTxPort =
++                p_LnxWrpFmDev->txPorts[portId].h_Dev;
++            fmVspParams.liodnOffset =
++                p_LnxWrpFmDev->rxPorts[portId].settings.param.specificParams.rxParams.liodnOffset;
++            memcpy(&fmVspParams.extBufPools,
++                   &p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.extBufPools,
++                   sizeof(t_FmExtPools));
++        }
++        else
++        {
++            memcpy(&fmVspParams.extBufPools,
++                   &p_LnxWrpFmPortDev->opExtPools,
++                   sizeof(t_FmExtPools));
++        }
++
++        if ((err = FM_PORT_VSPAlloc(p_LnxWrpFmPortDev->h_Dev,
++                                    &portVSPAllocParams)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++
++        /* We're initializing only the default VSP that are being used by the Linux-Ethernet-driver */
++        if ((p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) &&
++            !p_LnxWrpFmPortDev->opExtPools.numOfPoolsUsed)
++            return E_OK;
++
++        p_LnxWrpFmPortDev->h_DfltVsp = FM_VSP_Config(&fmVspParams);
++        if (!p_LnxWrpFmPortDev->h_DfltVsp)
++            RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("default-VSP for port!"));
++
++        if ((err = FM_VSP_ConfigBufferPrefixContent(p_LnxWrpFmPortDev->h_DfltVsp,
++                                                    &p_LnxWrpFmPortDev->buffPrefixContent)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++
++        if ((err = FM_VSP_Init(p_LnxWrpFmPortDev->h_DfltVsp)) != E_OK)
++            RETURN_ERROR(MINOR, err, NO_MSG);
++    }
++#else
++UNUSED(err); UNUSED(uint32_prop); UNUSED(lenp);
++#endif /* (DPAA_VERSION >= 11) */
++
++    of_node_put(port_node);
++    of_node_put(fm_node);
++
++    return E_OK;
++}
++
++static t_Error ConfigureFmPortDev(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev)
++{
++      t_LnxWrpFmDev *p_LnxWrpFmDev =
++              (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev;
++      struct resource *dev_res;
++
++      if (!p_LnxWrpFmPortDev->active)
++              RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                           ("FM port not configured!!!"));
++
++      dev_res =
++              __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res,
++                                    p_LnxWrpFmPortDev->phys_baseAddr,
++                                    p_LnxWrpFmPortDev->memSize,
++                                    "fman-port-hc");
++      if (unlikely(dev_res == NULL))
++              RETURN_ERROR(MAJOR, E_INVALID_STATE,
++                           ("__devm_request_region() failed"));
++      p_LnxWrpFmPortDev->baseAddr =
++              PTR_TO_UINT(devm_ioremap
++                          (p_LnxWrpFmDev->dev,
++                           p_LnxWrpFmPortDev->phys_baseAddr,
++                           p_LnxWrpFmPortDev->memSize));
++      if (unlikely(p_LnxWrpFmPortDev->baseAddr == 0))
++              REPORT_ERROR(MAJOR, E_INVALID_STATE,
++                           ("devm_ioremap() failed"));
++
++      p_LnxWrpFmPortDev->settings.param.baseAddr =
++              p_LnxWrpFmPortDev->baseAddr;
++
++      return E_OK;
++}
++
++static t_Error InitFmPortDev(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev)
++{
++#define MY_ADV_CONFIG_CHECK_END \
++              RETURN_ERROR(MAJOR, E_INVALID_SELECTION,\
++                      ("Advanced configuration routine"));\
++              if (errCode != E_OK)\
++                      RETURN_ERROR(MAJOR, errCode, NO_MSG);\
++      }
++
++      int i = 0;
++
++      if (!p_LnxWrpFmPortDev->active || p_LnxWrpFmPortDev->h_Dev)
++              return E_INVALID_STATE;
++
++      p_LnxWrpFmPortDev->h_Dev =
++                   FM_PORT_Config(&p_LnxWrpFmPortDev->settings.param);
++      if (p_LnxWrpFmPortDev->h_Dev == NULL)
++              RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-port"));
++
++#ifndef  FM_QMI_NO_DEQ_OPTIONS_SUPPORT
++      if ((p_LnxWrpFmPortDev->settings.param.portType ==
++           e_FM_PORT_TYPE_TX_10G)
++          || (p_LnxWrpFmPortDev->settings.param.portType ==
++              e_FM_PORT_TYPE_TX)) {
++              t_Error errCode = E_OK;
++              errCode =
++                   FM_PORT_ConfigDeqHighPriority(p_LnxWrpFmPortDev->h_Dev,
++                                                                 TRUE);
++              if (errCode != E_OK)
++                      RETURN_ERROR(MAJOR, errCode, NO_MSG);
++              errCode =
++              FM_PORT_ConfigDeqPrefetchOption(p_LnxWrpFmPortDev->h_Dev,
++                                              e_FM_PORT_DEQ_FULL_PREFETCH);
++              if (errCode
++                  != E_OK)
++                      RETURN_ERROR(MAJOR, errCode, NO_MSG);
++      }
++#endif  /* !FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
++
++#ifndef CONFIG_FMAN_ARM
++#ifdef FM_BCB_ERRATA_BMI_SW001
++/* Configure BCB workaround on Rx ports, only for B4860 rev1 */
++#define SVR_SECURITY_MASK    0x00080000
++#define SVR_PERSONALITY_MASK 0x0000FF00
++#define SVR_VER_IGNORE_MASK (SVR_SECURITY_MASK | SVR_PERSONALITY_MASK)
++#define SVR_B4860_REV1_VALUE 0x86800010
++
++      if ((p_LnxWrpFmPortDev->settings.param.portType ==
++              e_FM_PORT_TYPE_RX_10G) ||
++              (p_LnxWrpFmPortDev->settings.param.portType ==
++              e_FM_PORT_TYPE_RX)) {
++              unsigned int svr;
++
++              svr = mfspr(SPRN_SVR);
++
++              if ((svr & ~SVR_VER_IGNORE_MASK) == SVR_B4860_REV1_VALUE)
++                      FM_PORT_ConfigBCBWorkaround(p_LnxWrpFmPortDev->h_Dev);
++      }
++#endif /* FM_BCB_ERRATA_BMI_SW001 */
++#endif /* CONFIG_FMAN_ARM */
++/* Call the driver's advanced configuration routines, if requested:
++   Compare the function pointer of each entry to the available routines,
++   and invoke the matching routine with proper casting of arguments. */
++      while (p_LnxWrpFmPortDev->settings.advConfig[i].p_Function
++             && (i < FM_MAX_NUM_OF_ADV_SETTINGS)) {
++
++/* TODO: Change this MACRO */
++                      ADV_CONFIG_CHECK_START(
++                              &(p_LnxWrpFmPortDev->settings.advConfig[i]))
++
++                      ADV_CONFIG_CHECK(p_LnxWrpFmPortDev->h_Dev,
++                                       FM_PORT_ConfigBufferPrefixContent,
++                                       NCSW_PARAMS(1,
++                                              (t_FmBufferPrefixContent *)))
++
++                      if ((p_LnxWrpFmPortDev->settings.param.portType ==
++                                  e_FM_PORT_TYPE_OH_OFFLINE_PARSING) &&
++                                 (p_LnxWrpFmPortDev->settings.frag_enabled == TRUE)) {
++
++                              ADV_CONFIG_CHECK(p_LnxWrpFmPortDev->h_Dev,
++                                      FM_PORT_ConfigExtBufPools,
++                                      NCSW_PARAMS(1, (t_FmExtPools *)))
++
++              /* this define contains an else */
++              MY_ADV_CONFIG_CHECK_END
++              }
++
++                      /* Advance to next advanced configuration entry */
++                      i++;
++      }
++
++
++    if ((p_LnxWrpFmPortDev->settings.param.portType != e_FM_PORT_TYPE_TX) &&
++        (p_LnxWrpFmPortDev->settings.param.portType != e_FM_PORT_TYPE_TX_10G)) {
++            if (FM_PORT_ConfigErrorsToDiscard(p_LnxWrpFmPortDev->h_Dev, (FM_PORT_FRM_ERR_IPRE |
++                                                                         FM_PORT_FRM_ERR_IPR_NCSP |
++                                                                         FM_PORT_FRM_ERR_CLS_DISCARD)) !=E_OK)
++            RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++    }
++
++    if (CheckNConfigFmPortAdvArgs(p_LnxWrpFmPortDev) != E_OK)
++              RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++
++    if (FM_PORT_Init(p_LnxWrpFmPortDev->h_Dev) != E_OK)
++              RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++
++    if (CheckNSetFmPortAdvArgs(p_LnxWrpFmPortDev) != E_OK)
++              RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++
++/* FMan Fifo sizes behind the scene":
++ * Using the following formulae (*), under a set of simplifying assumptions (.):
++ *  . all ports are configured in Normal Mode (rather than Independent Mode)
++ *  . the DPAA Eth driver allocates buffers of size:
++ *      . MAXFRM + NET_IP_ALIGN + DPA_PRIV_DATA_SIZE + DPA_PARSE_RESULTS_SIZE
++ *             + DPA_HASH_RESULTS_SIZE, i.e.:
++ *        MAXFRM + 2 + 16 + sizeof(t_FmPrsResult) + 16, i.e.:
++ *        MAXFRM + 66
++ *  . excessive buffer pools not accounted for
++ *
++ *  * for Rx ports on P4080:
++ *      . IFSZ = ceil(max(FMBM_EBMPI[PBS]) / 256) * 256 + 7 * 256
++ *      . no internal frame offset (FMBM_RIM[FOF] == 0) - otherwise,
++ *      add up to 256 to the above
++ *
++ *  * for Rx ports on P1023:
++ *      . IFSZ = ceil(second_largest(FMBM_EBMPI[PBS] / 256)) * 256 + 7 * 256,
++ *      if at least 2 bpools are configured
++ *      . IFSZ = 8 * 256, if only a single bpool is configured
++ *
++ *  * for Tx ports:
++ *      . IFSZ = ceil(frame_size / 256) * 256 + 3 * 256
++ *                    + FMBM_TFP[DPDE] * 256, i.e.:
++ *        IFSZ = ceil(MAXFRM / 256) * 256 + 3 x 256 + FMBM_TFP[DPDE] * 256
++ *
++ *  * for OH ports on P4080:
++ *      . IFSZ = ceil(frame_size / 256) * 256 + 1 * 256 + FMBM_PP[MXT] * 256
++ *  * for OH ports on P1023:
++ *      . IFSZ = ceil(frame_size / 256) * 256 + 3 * 256 + FMBM_TFP[DPDE] * 256
++ *  * for both P4080 and P1023:
++ *      . (conservative decisions, assuming that BMI must bring the entire
++ *      frame, not only the frame header)
++ *      . no internal frame offset (FMBM_OIM[FOF] == 0) - otherwise,
++ *      add up to 256 to the above
++ *
++ *  . for P4080/P5020/P3041/P2040, DPDE is:
++ *              > 0 or 1, for 1Gb ports, HW default: 0
++ *              > 2..7 (recommended: 3..7) for 10Gb ports, HW default: 3
++ *  . for P1023, DPDE should be 1
++ *
++ *  . for P1023, MXT is in range (0..31)
++ *  . for P4080, MXT is in range (0..63)
++ *
++ */
++#if 0
++      if ((p_LnxWrpFmPortDev->defPcd != e_NO_PCD) &&
++          (InitFmPort3TupleDefPcd(p_LnxWrpFmPortDev) != E_OK))
++              RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
++#endif
++      return E_OK;
++}
++
++void fm_set_rx_port_params(struct fm_port *port,
++                         struct fm_port_params *params)
++{
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) port;
++      int i;
++
++      p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.errFqid =
++              params->errq;
++      p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.dfltFqid =
++              params->defq;
++      p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.extBufPools.
++              numOfPoolsUsed = params->num_pools;
++      for (i = 0; i < params->num_pools; i++) {
++              p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.
++                      extBufPools.extBufPool[i].id =
++                      params->pool_param[i].id;
++              p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.
++                      extBufPools.extBufPool[i].size =
++                      params->pool_param[i].size;
++      }
++
++      p_LnxWrpFmPortDev->buffPrefixContent.privDataSize =
++              params->priv_data_size;
++      p_LnxWrpFmPortDev->buffPrefixContent.passPrsResult =
++              params->parse_results;
++      p_LnxWrpFmPortDev->buffPrefixContent.passHashResult =
++              params->hash_results;
++      p_LnxWrpFmPortDev->buffPrefixContent.passTimeStamp =
++              params->time_stamp;
++      p_LnxWrpFmPortDev->buffPrefixContent.dataAlign =
++              params->data_align;
++      p_LnxWrpFmPortDev->buffPrefixContent.manipExtraSpace =
++              params->manip_extra_space;
++
++      ADD_ADV_CONFIG_START(p_LnxWrpFmPortDev->settings.advConfig,
++                           FM_MAX_NUM_OF_ADV_SETTINGS)
++
++              ADD_ADV_CONFIG_NO_RET(FM_PORT_ConfigBufferPrefixContent,
++                                    ARGS(1,
++                                         (&p_LnxWrpFmPortDev->
++                                          buffPrefixContent)));
++
++      ADD_ADV_CONFIG_END InitFmPortDev(p_LnxWrpFmPortDev);
++}
++EXPORT_SYMBOL(fm_set_rx_port_params);
++
++/* this function is called from oh_probe as well, thus it contains oh port
++ * specific parameters (make sure everything is checked) */
++void fm_set_tx_port_params(struct fm_port *port,
++                         struct fm_port_params *params)
++{
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) port;
++
++      p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams.errFqid =
++              params->errq;
++      p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams.
++              dfltFqid = params->defq;
++
++      p_LnxWrpFmPortDev->buffPrefixContent.privDataSize =
++              params->priv_data_size;
++      p_LnxWrpFmPortDev->buffPrefixContent.passPrsResult =
++              params->parse_results;
++      p_LnxWrpFmPortDev->buffPrefixContent.passHashResult =
++              params->hash_results;
++      p_LnxWrpFmPortDev->buffPrefixContent.passTimeStamp =
++              params->time_stamp;
++      p_LnxWrpFmPortDev->settings.frag_enabled =
++              params->frag_enable;
++      p_LnxWrpFmPortDev->buffPrefixContent.dataAlign =
++              params->data_align;
++      p_LnxWrpFmPortDev->buffPrefixContent.manipExtraSpace =
++              params->manip_extra_space;
++
++      ADD_ADV_CONFIG_START(p_LnxWrpFmPortDev->settings.advConfig,
++                           FM_MAX_NUM_OF_ADV_SETTINGS)
++
++      ADD_ADV_CONFIG_NO_RET(FM_PORT_ConfigBufferPrefixContent,
++                            ARGS(1,
++                                 (&p_LnxWrpFmPortDev->
++                                  buffPrefixContent)));
++
++      /* oh port specific parameter (for fragmentation only) */
++      if ((p_LnxWrpFmPortDev->settings.param.portType ==
++           e_FM_PORT_TYPE_OH_OFFLINE_PARSING) &&
++           params->num_pools) {
++              int i;
++
++              p_LnxWrpFmPortDev->opExtPools.numOfPoolsUsed = params->num_pools;
++              for (i = 0; i < params->num_pools; i++) {
++                      p_LnxWrpFmPortDev->opExtPools.extBufPool[i].id = params->pool_param[i].id;
++                      p_LnxWrpFmPortDev->opExtPools.extBufPool[i].size = params->pool_param[i].size;
++              }
++
++              if (p_LnxWrpFmPortDev->settings.frag_enabled)
++              ADD_ADV_CONFIG_NO_RET(FM_PORT_ConfigExtBufPools,
++                                    ARGS(1, (&p_LnxWrpFmPortDev->opExtPools)));
++      }
++
++      ADD_ADV_CONFIG_END InitFmPortDev(p_LnxWrpFmPortDev);
++}
++EXPORT_SYMBOL(fm_set_tx_port_params);
++
++void fm_mac_set_handle(t_Handle h_lnx_wrp_fm_dev,
++        t_Handle h_fm_mac,
++        int mac_id)
++{
++    t_LnxWrpFmDev *p_lnx_wrp_fm_dev = (t_LnxWrpFmDev *)h_lnx_wrp_fm_dev;
++
++    p_lnx_wrp_fm_dev->macs[mac_id].h_Dev = h_fm_mac;
++    p_lnx_wrp_fm_dev->macs[mac_id].h_LnxWrpFmDev = h_lnx_wrp_fm_dev;
++}
++EXPORT_SYMBOL(fm_mac_set_handle);
++
++static void LnxwrpFmPcdDevExceptionsCb(t_Handle h_App,
++                                     e_FmPcdExceptions exception)
++{
++      t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *) h_App;
++
++      ASSERT_COND(p_LnxWrpFmDev);
++
++      DBG(INFO, ("got fm-pcd exception %d", exception));
++
++      /* do nothing */
++      UNUSED(exception);
++}
++
++static void LnxwrpFmPcdDevIndexedExceptionsCb(t_Handle h_App,
++                                            e_FmPcdExceptions exception,
++                                            uint16_t index)
++{
++      t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *) h_App;
++
++      ASSERT_COND(p_LnxWrpFmDev);
++
++      DBG(INFO,
++          ("got fm-pcd-indexed exception %d, indx %d", exception, index));
++
++      /* do nothing */
++      UNUSED(exception);
++      UNUSED(index);
++}
++
++static t_Error InitFmPcdDev(t_LnxWrpFmDev *p_LnxWrpFmDev)
++{
++      spin_lock_init(&lock);
++
++      if (p_LnxWrpFmDev->pcdActive) {
++              t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = &p_LnxWrpFmDev->hcPort;
++              t_FmPcdParams fmPcdParams;
++              t_Error err;
++
++              memset(&fmPcdParams, 0, sizeof(fmPcdParams));
++              fmPcdParams.h_Fm = p_LnxWrpFmDev->h_Dev;
++              fmPcdParams.prsSupport = p_LnxWrpFmDev->prsActive;
++              fmPcdParams.kgSupport = p_LnxWrpFmDev->kgActive;
++              fmPcdParams.plcrSupport = p_LnxWrpFmDev->plcrActive;
++              fmPcdParams.ccSupport = p_LnxWrpFmDev->ccActive;
++              fmPcdParams.numOfSchemes = FM_PCD_KG_NUM_OF_SCHEMES;
++
++#ifndef CONFIG_GUEST_PARTITION
++              fmPcdParams.f_Exception = LnxwrpFmPcdDevExceptionsCb;
++              if (fmPcdParams.kgSupport)
++                      fmPcdParams.f_ExceptionId =
++                              LnxwrpFmPcdDevIndexedExceptionsCb;
++              fmPcdParams.h_App = p_LnxWrpFmDev;
++#endif /* !CONFIG_GUEST_PARTITION */
++
++#ifdef CONFIG_MULTI_PARTITION_SUPPORT
++              fmPcdParams.numOfSchemes = 0;
++              fmPcdParams.numOfClsPlanEntries = 0;
++              fmPcdParams.partitionId = 0;
++#endif /* CONFIG_MULTI_PARTITION_SUPPORT */
++              fmPcdParams.useHostCommand = TRUE;
++
++              p_LnxWrpFmDev->hc_tx_fq =
++                      FqAlloc(p_LnxWrpFmDev,
++                              0,
++                              QMAN_FQ_FLAG_TO_DCPORTAL,
++                              p_LnxWrpFmPortDev->txCh, 0);
++              if (!p_LnxWrpFmDev->hc_tx_fq)
++                      RETURN_ERROR(MAJOR, E_NULL_POINTER,
++                                   ("Frame queue allocation failed..."));
++
++              p_LnxWrpFmDev->hc_tx_conf_fq =
++                      FqAlloc(p_LnxWrpFmDev,
++                              0,
++                              QMAN_FQ_FLAG_NO_ENQUEUE,
++                              p_LnxWrpFmDev->hcCh, 1);
++              if (!p_LnxWrpFmDev->hc_tx_conf_fq)
++                      RETURN_ERROR(MAJOR, E_NULL_POINTER,
++                                   ("Frame queue allocation failed..."));
++
++              p_LnxWrpFmDev->hc_tx_err_fq =
++                      FqAlloc(p_LnxWrpFmDev,
++                              0,
++                              QMAN_FQ_FLAG_NO_ENQUEUE,
++                              p_LnxWrpFmDev->hcCh, 2);
++              if (!p_LnxWrpFmDev->hc_tx_err_fq)
++                      RETURN_ERROR(MAJOR, E_NULL_POINTER,
++                                   ("Frame queue allocation failed..."));
++
++              fmPcdParams.hc.portBaseAddr = p_LnxWrpFmPortDev->baseAddr;
++              fmPcdParams.hc.portId =
++                      p_LnxWrpFmPortDev->settings.param.portId;
++              fmPcdParams.hc.liodnBase =
++                      p_LnxWrpFmPortDev->settings.param.liodnBase;
++              fmPcdParams.hc.errFqid =
++                      qman_fq_fqid(p_LnxWrpFmDev->hc_tx_err_fq);
++              fmPcdParams.hc.confFqid =
++                      qman_fq_fqid(p_LnxWrpFmDev->hc_tx_conf_fq);
++              fmPcdParams.hc.qmChannel = p_LnxWrpFmPortDev->txCh;
++              fmPcdParams.hc.f_QmEnqueue = QmEnqueueCB;
++              fmPcdParams.hc.h_QmArg = (t_Handle) p_LnxWrpFmDev;
++
++              p_LnxWrpFmDev->h_PcdDev = FM_PCD_Config(&fmPcdParams);
++              if (!p_LnxWrpFmDev->h_PcdDev)
++                      RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM PCD!"));
++
++              err =
++              FM_PCD_ConfigPlcrNumOfSharedProfiles(p_LnxWrpFmDev->h_PcdDev,
++                              LNXWRP_FM_NUM_OF_SHARED_PROFILES);
++              if (err != E_OK)
++                      RETURN_ERROR(MAJOR, err, NO_MSG);
++
++              err = FM_PCD_Init(p_LnxWrpFmDev->h_PcdDev);
++              if (err != E_OK)
++                      RETURN_ERROR(MAJOR, err, NO_MSG);
++
++              if (p_LnxWrpFmDev->err_irq == 0) {
++                      FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
++                              e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC,
++                              FALSE);
++                      FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
++                              e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW,
++                              FALSE);
++                      FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
++                              e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR,
++                              FALSE);
++                      FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
++                              e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC,
++                              FALSE);
++                      FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
++                              e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC,
++                              FALSE);
++                      FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
++                          e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE,
++                              FALSE);
++                      FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
++                              e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE,
++                              FALSE);
++                      FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
++                              e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC,
++                              FALSE);
++              }
++      }
++
++      return E_OK;
++}
++
++void FreeFmPcdDev(t_LnxWrpFmDev *p_LnxWrpFmDev)
++{
++
++      if (p_LnxWrpFmDev->h_PcdDev)
++              FM_PCD_Free(p_LnxWrpFmDev->h_PcdDev);
++
++      if (p_LnxWrpFmDev->hc_tx_err_fq)
++              FqFree(p_LnxWrpFmDev->hc_tx_err_fq);
++
++      if (p_LnxWrpFmDev->hc_tx_conf_fq)
++              FqFree(p_LnxWrpFmDev->hc_tx_conf_fq);
++
++      if (p_LnxWrpFmDev->hc_tx_fq)
++              FqFree(p_LnxWrpFmDev->hc_tx_fq);
++}
++
++static void FreeFmPortDev(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev)
++{
++      t_LnxWrpFmDev *p_LnxWrpFmDev =
++              (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev;
++
++      if (!p_LnxWrpFmPortDev->active)
++              return;
++
++      if (p_LnxWrpFmPortDev->h_Dev)
++              FM_PORT_Free(p_LnxWrpFmPortDev->h_Dev);
++
++      devm_iounmap(p_LnxWrpFmDev->dev,
++                   UINT_TO_PTR(p_LnxWrpFmPortDev->baseAddr));
++      __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res,
++                            p_LnxWrpFmPortDev->phys_baseAddr,
++                            p_LnxWrpFmPortDev->memSize);
++}
++
++static int /*__devinit*/ fm_port_probe(struct platform_device *of_dev)
++{
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
++      t_LnxWrpFmDev *p_LnxWrpFmDev;
++      struct device *dev;
++
++      dev = &of_dev->dev;
++
++      p_LnxWrpFmPortDev = ReadFmPortDevTreeNode(of_dev);
++      if (p_LnxWrpFmPortDev == NULL)
++              return -EIO;
++      /* Port can be inactive, thus will not be probed:
++         - in performance mode, OH ports are disabled
++         ...
++       */
++      if (!p_LnxWrpFmPortDev->active)
++              return 0;
++
++      if (ConfigureFmPortDev(p_LnxWrpFmPortDev) != E_OK)
++              return -EIO;
++
++      dev_set_drvdata(dev, p_LnxWrpFmPortDev);
++
++      if (p_LnxWrpFmPortDev->settings.param.portType ==
++              e_FM_PORT_TYPE_OH_HOST_COMMAND)
++              InitFmPcdDev((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev);
++
++      p_LnxWrpFmDev = (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev;
++
++      if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX) {
++              Sprint(p_LnxWrpFmPortDev->name, "%s-port-rx%d",
++                     p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id);
++              p_LnxWrpFmPortDev->minor =
++                      p_LnxWrpFmPortDev->id + DEV_FM_RX_PORTS_MINOR_BASE;
++      } else if (p_LnxWrpFmPortDev->settings.param.portType ==
++               e_FM_PORT_TYPE_RX_10G) {
++              Sprint(p_LnxWrpFmPortDev->name, "%s-port-rx%d",
++                     p_LnxWrpFmDev->name,
++                     p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_RX_PORTS);
++              p_LnxWrpFmPortDev->minor =
++                      p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_RX_PORTS +
++                      DEV_FM_RX_PORTS_MINOR_BASE;
++#ifndef CONFIG_FMAN_ARM
++              if (IS_T1023_T1024) {
++                      Sprint(p_LnxWrpFmPortDev->name, "%s-port-rx%d",
++                              p_LnxWrpFmDev->name,
++                              p_LnxWrpFmPortDev->id);
++                      p_LnxWrpFmPortDev->minor =
++                              p_LnxWrpFmPortDev->id +
++                              DEV_FM_RX_PORTS_MINOR_BASE;
++              }
++#endif
++      } else if (p_LnxWrpFmPortDev->settings.param.portType ==
++               e_FM_PORT_TYPE_TX) {
++              Sprint(p_LnxWrpFmPortDev->name, "%s-port-tx%d",
++                     p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id);
++              p_LnxWrpFmPortDev->minor =
++                      p_LnxWrpFmPortDev->id + DEV_FM_TX_PORTS_MINOR_BASE;
++      } else if (p_LnxWrpFmPortDev->settings.param.portType ==
++               e_FM_PORT_TYPE_TX_10G) {
++              Sprint(p_LnxWrpFmPortDev->name, "%s-port-tx%d",
++                     p_LnxWrpFmDev->name,
++                     p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_TX_PORTS);
++              p_LnxWrpFmPortDev->minor =
++                      p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_TX_PORTS +
++                      DEV_FM_TX_PORTS_MINOR_BASE;
++#ifndef CONFIG_FMAN_ARM
++              if (IS_T1023_T1024) {
++                      Sprint(p_LnxWrpFmPortDev->name, "%s-port-tx%d",
++                              p_LnxWrpFmDev->name,
++                              p_LnxWrpFmPortDev->id);
++                      p_LnxWrpFmPortDev->minor =
++                              p_LnxWrpFmPortDev->id +
++                              DEV_FM_TX_PORTS_MINOR_BASE;
++              }
++#endif
++      } else if (p_LnxWrpFmPortDev->settings.param.portType ==
++               e_FM_PORT_TYPE_OH_HOST_COMMAND) {
++              Sprint(p_LnxWrpFmPortDev->name, "%s-port-oh%d",
++                     p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id);
++              p_LnxWrpFmPortDev->minor =
++                      p_LnxWrpFmPortDev->id + DEV_FM_OH_PORTS_MINOR_BASE;
++      } else if (p_LnxWrpFmPortDev->settings.param.portType ==
++               e_FM_PORT_TYPE_OH_OFFLINE_PARSING) {
++              Sprint(p_LnxWrpFmPortDev->name, "%s-port-oh%d",
++                     p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id + 1);
++              p_LnxWrpFmPortDev->minor =
++                      p_LnxWrpFmPortDev->id + 1 +
++                      DEV_FM_OH_PORTS_MINOR_BASE;
++      }
++
++      device_create(p_LnxWrpFmDev->fm_class, NULL,
++                    MKDEV(p_LnxWrpFmDev->major, p_LnxWrpFmPortDev->minor),
++                    NULL, p_LnxWrpFmPortDev->name);
++
++      /* create sysfs entries for stats and regs */
++
++      if (fm_port_sysfs_create(dev) != 0) {
++              FreeFmPortDev(p_LnxWrpFmPortDev);
++              REPORT_ERROR(MAJOR, E_INVALID_STATE,
++                           ("Unable to create sys entry - fm port!!!"));
++              return -EIO;
++      }
++
++#ifdef FM_TX_INVALID_ECC_ERRATA_10GMAC_A009
++      FM_DisableRamsEcc(p_LnxWrpFmDev->h_Dev);
++#endif /* FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 */
++
++      DBG(TRACE, ("%s probed", p_LnxWrpFmPortDev->name));
++
++      return 0;
++}
++
++static int fm_port_remove(struct platform_device *of_dev)
++{
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
++      t_LnxWrpFmDev *p_LnxWrpFmDev;
++      struct device *dev;
++
++      dev = &of_dev->dev;
++      p_LnxWrpFmPortDev = dev_get_drvdata(dev);
++
++      fm_port_sysfs_destroy(dev);
++
++      p_LnxWrpFmDev = (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev;
++      device_destroy(p_LnxWrpFmDev->fm_class,
++                     MKDEV(p_LnxWrpFmDev->major, p_LnxWrpFmPortDev->minor));
++
++      FreeFmPortDev(p_LnxWrpFmPortDev);
++
++      dev_set_drvdata(dev, NULL);
++
++      return 0;
++}
++
++static const struct of_device_id fm_port_match[] = {
++      {
++       .compatible = "fsl,fman-port-oh"},
++      {
++       .compatible = "fsl,fman-port-1g-rx"},
++      {
++       .compatible = "fsl,fman-port-10g-rx"},
++      {
++       .compatible = "fsl,fman-port-1g-tx"},
++      {
++       .compatible = "fsl,fman-port-10g-tx"},
++      {}
++};
++
++#ifndef MODULE
++MODULE_DEVICE_TABLE(of, fm_port_match);
++#endif /* !MODULE */
++
++static struct platform_driver fm_port_driver = {
++
++      .driver = {
++                 .name = "fsl-fman-port",
++                 .of_match_table = fm_port_match,
++                 .owner = THIS_MODULE,
++                 },
++      .probe = fm_port_probe,
++      .remove = fm_port_remove
++};
++
++
++t_Error LNXWRP_FM_Port_Init(void)
++{
++      /* Register to the DTB for basic FM port API */
++      if (platform_driver_register(&fm_port_driver))
++              return E_NO_DEVICE;
++
++      return E_OK;
++}
++
++void LNXWRP_FM_Port_Free(void)
++{
++      platform_driver_unregister(&fm_port_driver);
++}
++
++static int __init __cold fm_port_load(void)
++{
++      if (LNXWRP_FM_Port_Init() != E_OK) {
++              printk(KERN_CRIT "Failed to init FM Ports wrapper!\n");
++              return -ENODEV;
++      }
++
++      printk(KERN_CRIT "Freescale FM Ports module\n");
++
++      return 0;
++}
++
++static void __exit __cold fm_port_unload(void)
++{
++      LNXWRP_FM_Port_Free();
++}
++
++module_init(fm_port_load);
++module_exit(fm_port_unload);
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm.c
+@@ -0,0 +1,4813 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ @File          lnxwrp_ioctls_fm.c
++ @Author        Shlomi Gridish
++ @Description   FM Linux wrapper functions.
++*/
++
++/* Linux Headers ------------------- */
++#include <linux/version.h>
++
++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
++#define MODVERSIONS
++#endif
++#ifdef MODVERSIONS
++#include <config/modversions.h>
++#endif /* MODVERSIONS */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/device.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/of_platform.h>
++#include <linux/uaccess.h>
++#include <asm/errno.h>
++#ifndef CONFIG_FMAN_ARM
++#include <sysdev/fsl_soc.h>
++#include <linux/fsl/svr.h>
++#endif
++
++#if defined(CONFIG_COMPAT)
++#include <linux/compat.h>
++#endif
++
++#include "part_ext.h"
++#include "fm_ioctls.h"
++#include "fm_pcd_ioctls.h"
++#include "fm_port_ioctls.h"
++#include "fm_vsp_ext.h"
++
++#ifndef CONFIG_FMAN_ARM
++#define IS_T1023_T1024        (SVR_SOC_VER(mfspr(SPRN_SVR)) == SVR_T1024 || \
++                      SVR_SOC_VER(mfspr(SPRN_SVR)) == SVR_T1023)
++#endif
++
++#define __ERR_MODULE__  MODULE_FM
++
++#if defined(CONFIG_COMPAT)
++#include "lnxwrp_ioctls_fm_compat.h"
++#endif
++
++#include "lnxwrp_fm.h"
++
++#define CMP_IOC_DEFINE(def) (IOC_##def != def)
++
++/* fm_pcd_ioctls.h === fm_pcd_ext.h assertions */
++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_PRIVATE_HDRS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_PRS_NUM_OF_HDRS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_GENERIC_REGS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_EXTRACT_MASKS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_DEFAULT_GROUPS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_PRS_NUM_OF_LABELS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_SW_PRS_SIZE)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_MAX_MANIP_INSRT_TEMPLATE_SIZE)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if DPAA_VERSION >= 11
++#if CMP_IOC_DEFINE(FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES)
++#error Error: please synchronize IOC_ defines!
++#endif
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_TREES)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_GROUPS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_UNITS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_KEYS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_MAX_SIZE_OF_KEY)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(FM_PCD_LAST_KEY_INDEX)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++/* net_ioctls.h === net_ext.h assertions */
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPP_PID)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPP_COMPRESSED)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPP_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPPoE_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPPMUX_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPPMUX_SUBFRAME_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_ETH_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPv4_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPv6_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_ICMP_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IGMP_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_TCP_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_SCTP_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_DCCP_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_UDP_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_UDP_ENCAP_ESP_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPHC_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_SCTP_CHUNK_DATA_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_L2TPv2_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_L2TPv3_CTRL_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_L2TPv3_SESS_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_VLAN_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_LLC_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_NLPID_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_SNAP_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_LLC_SNAP_ALL_FIELDS)
++#warning Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_ARP_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_RFC2684_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_USER_DEFINED_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PAYLOAD_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_GRE_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_MINENCAP_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPSEC_AH_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPSEC_ESP_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_MPLS_LABEL_STACK_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_MACSEC_ALL_FIELDS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++/* fm_ioctls.h === fm_ext.h assertions */
++#if CMP_IOC_DEFINE(FM_MAX_NUM_OF_VALID_PORTS)
++#error Error: please synchronize IOC_ defines!
++#endif
++
++void LnxWrpPCDIOCTLTypeChecking(void)
++{
++    /* fm_ext.h == fm_ioctls.h */
++    ASSERT_COND(sizeof(ioc_fm_port_bandwidth_params) == sizeof(t_FmPortsBandwidthParams));
++    ASSERT_COND(sizeof(ioc_fm_revision_info_t) == sizeof(t_FmRevisionInfo));
++
++    /* fm_pcd_ext.h == fm_pcd_ioctls.h */
++    /*ioc_fm_pcd_counters_params_t  : NOT USED */
++    /*ioc_fm_pcd_exception_params_t : private */
++#if (DPAA_VERSION >= 11)
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_capwap_params_t) == sizeof(t_FmPcdManipFragCapwapParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_capwap_params_t) == sizeof(t_FmPcdManipReassemCapwapParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_by_hdr_params_t) == sizeof(t_FmPcdManipHdrInsrtByHdrParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_ip_params_t) == sizeof(t_FmPcdManipHdrInsrtIpParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_t) == sizeof(t_FmPcdManipHdrInsrt));
++    ASSERT_COND(sizeof(ioc_fm_manip_hdr_info_t) == sizeof(t_FmManipHdrInfo));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_rmv_by_hdr_params_t) == sizeof(t_FmPcdManipHdrRmvByHdrParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_special_offload_capwap_params_t) == sizeof(t_FmPcdManipSpecialOffloadCapwapParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_capwap_stats_t) == sizeof(t_FmPcdManipFragCapwapStats));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_capwap_stats_t) == sizeof(t_FmPcdManipReassemCapwapStats));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_params_t) == sizeof(t_FmPcdManipFragParams));
++#endif /* (DPAA_VERSION >= 11) */
++
++    ASSERT_COND(sizeof(ioc_fm_pcd_prs_label_params_t) == sizeof(t_FmPcdPrsLabelParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_prs_sw_params_t) == sizeof(t_FmPcdPrsSwParams));
++    /*ioc_fm_pcd_kg_dflt_value_params_t : private */
++    ASSERT_COND(sizeof(ioc_fm_pcd_hdr_protocol_opt_u) == sizeof(u_FmPcdHdrProtocolOpt));
++    ASSERT_COND(sizeof(ioc_fm_pcd_fields_u) == sizeof(t_FmPcdFields));
++    ASSERT_COND(sizeof(ioc_fm_pcd_from_hdr_t) == sizeof(t_FmPcdFromHdr));
++    ASSERT_COND(sizeof(ioc_fm_pcd_from_field_t) == sizeof(t_FmPcdFromField));
++    ASSERT_COND(sizeof(ioc_fm_pcd_distinction_unit_t) == sizeof(t_FmPcdDistinctionUnit));
++
++#if defined(CONFIG_ARM64)
++    /* different alignment */
++    ASSERT_COND(sizeof(ioc_fm_pcd_net_env_params_t) == sizeof(t_FmPcdNetEnvParams) + sizeof(void *) + 4);
++#else
++#if !defined(CONFIG_COMPAT)
++    /* different alignment */
++    ASSERT_COND(sizeof(ioc_fm_pcd_net_env_params_t) == sizeof(t_FmPcdNetEnvParams) + sizeof(void *));
++#endif
++#endif
++    ASSERT_COND(sizeof(ioc_fm_pcd_extract_entry_t) == sizeof(t_FmPcdExtractEntry));
++    ASSERT_COND(sizeof(ioc_fm_pcd_kg_extract_mask_t) == sizeof(t_FmPcdKgExtractMask));
++    ASSERT_COND(sizeof(ioc_fm_pcd_kg_extract_dflt_t) == sizeof(t_FmPcdKgExtractDflt));
++    ASSERT_COND(sizeof(ioc_fm_pcd_kg_key_extract_and_hash_params_t) == sizeof(t_FmPcdKgKeyExtractAndHashParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_kg_extracted_or_params_t) == sizeof(t_FmPcdKgExtractedOrParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_kg_scheme_counter_t) == sizeof(t_FmPcdKgSchemeCounter));
++    ASSERT_COND(sizeof(ioc_fm_pcd_kg_plcr_profile_t) == sizeof(t_FmPcdKgPlcrProfile));
++#if (DPAA_VERSION >= 11)
++    ASSERT_COND(sizeof(ioc_fm_pcd_kg_storage_profile_t) == sizeof(t_FmPcdKgStorageProfile));
++#endif
++    ASSERT_COND(sizeof(ioc_fm_pcd_kg_cc_t) == sizeof(t_FmPcdKgCc));
++#if !defined(CONFIG_COMPAT)
++    /* different alignment */
++    ASSERT_COND(sizeof(ioc_fm_pcd_kg_scheme_params_t) == sizeof(t_FmPcdKgSchemeParams) + sizeof(void *));
++#endif
++    ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_cc_params_t) == sizeof(t_FmPcdCcNextCcParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_plcr_params_t) == sizeof(t_FmPcdCcNextPlcrParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_enqueue_params_t) == sizeof(t_FmPcdCcNextEnqueueParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_kg_params_t) == sizeof(t_FmPcdCcNextKgParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_engine_params_t) == sizeof(t_FmPcdCcNextEngineParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_cc_key_params_t) == sizeof(t_FmPcdCcKeyParams));
++    ASSERT_COND(sizeof(ioc_keys_params_t) == sizeof(t_KeysParams));
++#if !defined(CONFIG_COMPAT)
++    /* different alignment */
++    ASSERT_COND(sizeof(ioc_fm_pcd_cc_node_params_t) == sizeof(t_FmPcdCcNodeParams) + sizeof(void *));
++    ASSERT_COND(sizeof(ioc_fm_pcd_hash_table_params_t) == sizeof(t_FmPcdHashTableParams) + sizeof(void *));
++#endif
++    ASSERT_COND(sizeof(ioc_fm_pcd_cc_grp_params_t) == sizeof(t_FmPcdCcGrpParams));
++#if !defined(CONFIG_COMPAT)
++    /* different alignment */
++    ASSERT_COND(sizeof(ioc_fm_pcd_cc_tree_params_t) == sizeof(t_FmPcdCcTreeParams) + sizeof(void *));
++#endif
++    ASSERT_COND(sizeof(ioc_fm_pcd_plcr_byte_rate_mode_param_t) == sizeof(t_FmPcdPlcrByteRateModeParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_plcr_non_passthrough_alg_param_t) == sizeof(t_FmPcdPlcrNonPassthroughAlgParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_plcr_next_engine_params_u) == sizeof(u_FmPcdPlcrNextEngineParams));
++    /*ioc_fm_pcd_port_params_t : private */
++    ASSERT_COND(sizeof(ioc_fm_pcd_plcr_profile_params_t) == sizeof(t_FmPcdPlcrProfileParams) + sizeof(void *));
++    /*ioc_fm_pcd_cc_tree_modify_next_engine_params_t : private */
++
++#ifdef FM_CAPWAP_SUPPORT
++#error TODO: unsupported feature
++/*
++    ASSERT_COND(sizeof(TODO) == sizeof(t_FmPcdManipHdrInsrtByTemplateParams));
++    ASSERT_COND(sizeof(TODO) == sizeof(t_CapwapFragmentationParams));
++    ASSERT_COND(sizeof(TODO) == sizeof(t_CapwapReassemblyParams));
++*/
++#endif
++
++    /*ioc_fm_pcd_cc_node_modify_next_engine_params_t : private */
++    /*ioc_fm_pcd_cc_node_remove_key_params_t : private */
++    /*ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t : private */
++    /*ioc_fm_pcd_cc_node_modify_key_params_t : private */
++    /*ioc_fm_manip_hdr_info_t : private */
++    /*ioc_fm_pcd_hash_table_set_t : private */
++
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_ip_params_t) == sizeof(t_FmPcdManipFragIpParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_ip_params_t) == sizeof(t_FmPcdManipReassemIpParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_special_offload_ipsec_params_t) == sizeof(t_FmPcdManipSpecialOffloadIPSecParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_special_offload_params_t) == sizeof(t_FmPcdManipSpecialOffloadParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_rmv_generic_params_t) == sizeof(t_FmPcdManipHdrRmvGenericParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_generic_params_t) == sizeof(t_FmPcdManipHdrInsrtGenericParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_params_t) == sizeof(t_FmPcdManipHdrInsrtParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_rmv_params_t) == sizeof(t_FmPcdManipHdrRmvParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_params_t) == sizeof(t_FmPcdManipHdrParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_params_t) == sizeof(t_FmPcdManipFragParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_params_t) == sizeof(t_FmPcdManipReassemParams));
++#if !defined(CONFIG_COMPAT)
++    /* different alignment */
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_params_t) == sizeof(t_FmPcdManipParams) + sizeof(void *));
++#endif
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_ip_stats_t) == sizeof(t_FmPcdManipReassemIpStats));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_ip_stats_t) == sizeof(t_FmPcdManipFragIpStats));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_stats_t) == sizeof(t_FmPcdManipReassemStats));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_stats_t) == sizeof(t_FmPcdManipFragStats));
++    ASSERT_COND(sizeof(ioc_fm_pcd_manip_stats_t) == sizeof(t_FmPcdManipStats));
++#if DPAA_VERSION >= 11
++    ASSERT_COND(sizeof(ioc_fm_pcd_frm_replic_group_params_t) == sizeof(t_FmPcdFrmReplicGroupParams) + sizeof(void *));
++#endif
++
++    /* fm_port_ext.h == fm_port_ioctls.h */
++    ASSERT_COND(sizeof(ioc_fm_port_rate_limit_t) == sizeof(t_FmPortRateLimit));
++    ASSERT_COND(sizeof(ioc_fm_port_pcd_params_t) == sizeof(t_FmPortPcdParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_kg_scheme_select_t) == sizeof(t_FmPcdKgSchemeSelect));
++    ASSERT_COND(sizeof(ioc_fm_pcd_port_schemes_params_t) == sizeof(t_FmPcdPortSchemesParams));
++    ASSERT_COND(sizeof(ioc_fm_pcd_prs_start_t) == sizeof(t_FmPcdPrsStart));
++
++    return;
++}
++
++#define ASSERT_IOC_NET_ENUM(def) ASSERT_COND((unsigned long)e_IOC_NET_##def == (unsigned long)def)
++
++void LnxWrpPCDIOCTLEnumChecking(void)
++{
++    /* net_ext.h == net_ioctls.h : sampling checks */
++    ASSERT_IOC_NET_ENUM(HEADER_TYPE_MACSEC);
++    ASSERT_IOC_NET_ENUM(HEADER_TYPE_PPP);
++    ASSERT_IOC_NET_ENUM(MAX_HEADER_TYPE_COUNT);
++
++    /* fm_ext.h == fm_ioctls.h */
++    ASSERT_COND((unsigned long)e_IOC_FM_PORT_TYPE_DUMMY == (unsigned long)e_FM_PORT_TYPE_DUMMY);
++    ASSERT_COND((unsigned long)e_IOC_EX_MURAM_ECC == (unsigned long)e_FM_EX_MURAM_ECC);
++    ASSERT_COND((unsigned long)e_IOC_FM_COUNTERS_DEQ_CONFIRM == (unsigned long)e_FM_COUNTERS_DEQ_CONFIRM);
++
++    /* fm_pcd_ext.h == fm_pcd_ioctls.h */
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES == (unsigned long)e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_PRS_EXCEPTION_SINGLE_ECC == (unsigned long)e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_PRS == (unsigned long)e_FM_PCD_PRS);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_EXTRACT_FULL_FIELD == (unsigned long)e_FM_PCD_EXTRACT_FULL_FIELD);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_EXTRACT_FROM_FLOW_ID == (unsigned long)e_FM_PCD_EXTRACT_FROM_FLOW_ID);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO == (unsigned long)e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_KG_DFLT_ILLEGAL == (unsigned long)e_FM_PCD_KG_DFLT_ILLEGAL);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_KG_GENERIC_NOT_FROM_DATA == (unsigned long)e_FM_PCD_KG_GENERIC_NOT_FROM_DATA);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_HDR_INDEX_LAST == (unsigned long)e_FM_PCD_HDR_INDEX_LAST);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_SHARED == (unsigned long)e_FM_PCD_PLCR_SHARED);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_RFC_4115 == (unsigned long)e_FM_PCD_PLCR_RFC_4115);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_COLOR_AWARE == (unsigned long)e_FM_PCD_PLCR_COLOR_AWARE);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_OVERRIDE == (unsigned long)e_FM_PCD_PLCR_OVERRIDE);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_FULL_FRM_LEN == (unsigned long)e_FM_PCD_PLCR_FULL_FRM_LEN);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN == (unsigned long)e_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_PACKET_MODE == (unsigned long)e_FM_PCD_PLCR_PACKET_MODE);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_DROP_FRAME == (unsigned long)e_FM_PCD_DROP_FRAME);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER == (unsigned long)e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP == (unsigned long)e_FM_PCD_ACTION_INDEXED_LOOKUP);
++    ASSERT_COND((unsigned long)e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR == (unsigned long)e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR);
++#if !defined(FM_CAPWAP_SUPPORT)
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_INSRT_GENERIC == (unsigned long)e_FM_PCD_MANIP_INSRT_GENERIC);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_RMV_GENERIC == (unsigned long)e_FM_PCD_MANIP_RMV_GENERIC);
++#else
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_INSRT_BY_TEMPLATE == (unsigned long)e_FM_PCD_MANIP_INSRT_BY_TEMPLATE);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_RMV_BY_HDR == (unsigned long)e_FM_PCD_MANIP_RMV_BY_HDR);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_RMV_BY_HDR_FROM_START == (unsigned long)e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START);
++#endif
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAG == (unsigned long)e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAG);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_EIGHT_WAYS_HASH == (unsigned long)e_FM_PCD_MANIP_EIGHT_WAYS_HASH);
++
++#ifdef FM_CAPWAP_SUPPORT
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_STATS_PER_FLOWID == (unsigned long)e_FM_PCD_STATS_PER_FLOWID);
++#endif
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD == (unsigned long)e_FM_PCD_MANIP_SPECIAL_OFFLOAD);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_CC_STATS_MODE_FRAME == (unsigned long)e_FM_PCD_CC_STATS_MODE_FRAME);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_CONTINUE_WITHOUT_FRAG == (unsigned long)e_FM_PCD_MANIP_CONTINUE_WITHOUT_FRAG);
++    ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC == (unsigned long)e_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC);
++
++    /* fm_port_ext.h == fm_port_ioctls.h */
++#if !defined(FM_CAPWAP_SUPPORT)
++    ASSERT_COND((unsigned long)e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR == (unsigned long)e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR);
++#else
++    ASSERT_COND((unsigned long)e_IOC_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR == (unsigned long)e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR);
++#endif
++    ASSERT_COND((unsigned long)e_IOC_FM_PORT_COUNTERS_DEQ_CONFIRM == (unsigned long)e_FM_PORT_COUNTERS_DEQ_CONFIRM);
++    ASSERT_COND((unsigned long)e_IOC_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8 == (unsigned long)e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8);
++
++    return;
++}
++
++static t_Error LnxwrpFmPcdIOCTL(t_LnxWrpFmDev *p_LnxWrpFmDev, unsigned int cmd, unsigned long arg, bool compat)
++{
++    t_Error err = E_OK;
++
++/*
++Status: PCD API to fmlib (file: drivers/net/dpa/NetCommSw/inc/Peripherals/fm_pcd_ext.h):
++
++    FM_PCD_PrsLoadSw
++    FM_PCD_SetAdvancedOffloadSupport
++    FM_PCD_Enable
++    FM_PCD_Disable
++    FM_PCD_ForceIntr
++    FM_PCD_SetException
++    FM_PCD_KgSetAdditionalDataAfterParsing
++    FM_PCD_KgSetDfltValue
++    FM_PCD_NetEnvCharacteristicsSet
++    FM_PCD_NetEnvCharacteristicsDelete
++    FM_PCD_KgSchemeSet
++    FM_PCD_KgSchemeDelete
++    FM_PCD_MatchTableSet
++    FM_PCD_MatchTableDelete
++    FM_PCD_CcRootBuild
++    FM_PCD_CcRootDelete
++    FM_PCD_PlcrProfileSet
++    FM_PCD_PlcrProfileDelete
++    FM_PCD_CcRootModifyNextEngine
++    FM_PCD_MatchTableModifyNextEngine
++    FM_PCD_MatchTableModifyMissNextEngine
++    FM_PCD_MatchTableRemoveKey
++    FM_PCD_MatchTableAddKey
++    FM_PCD_MatchTableModifyKeyAndNextEngine
++    FM_PCD_HashTableSet
++    FM_PCD_HashTableDelete
++    FM_PCD_HashTableAddKey
++    FM_PCD_HashTableRemoveKey
++    FM_PCD_MatchTableModifyKey
++    FM_PCD_ManipNodeReplace
++    FM_PCD_ManipNodeSet
++    FM_PCD_ManipNodeDelete
++
++Status: not exported, should be thru sysfs
++    FM_PCD_KgSchemeGetCounter
++    FM_PCD_KgSchemeSetCounter
++    FM_PCD_PlcrProfileGetCounter
++    FM_PCD_PlcrProfileSetCounter
++
++Status: not exported
++    FM_PCD_MatchTableFindNRemoveKey
++    FM_PCD_MatchTableFindNModifyNextEngine
++    FM_PCD_MatchTableFindNModifyKeyAndNextEngine
++    FM_PCD_MatchTableFindNModifyKey
++    FM_PCD_MatchTableGetIndexedHashBucket
++    FM_PCD_MatchTableGetNextEngine
++    FM_PCD_MatchTableGetKeyCounter
++
++Status: not exported, would be nice to have
++    FM_PCD_HashTableModifyNextEngine
++    FM_PCD_HashTableModifyMissNextEngine
++    FM_PCD_HashTableGetMissNextEngine
++    FM_PCD_ManipGetStatistics
++
++Status: not exported
++#if DPAA_VERSION >= 11
++
++    FM_VSP_GetStatistics -- it's not available yet
++#endif
++
++Status: feature not supported
++#ifdef FM_CAPWAP_SUPPORT
++#error unsupported feature
++    FM_PCD_StatisticsSetNode
++#endif
++
++ */
++    _fm_ioctl_dbg("cmd:0x%08x(type:0x%02x, nr:%u).\n",
++            cmd, _IOC_TYPE(cmd), _IOC_NR(cmd) - 20);
++
++    switch (cmd)
++    {
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_PRS_LOAD_SW_COMPAT:
++#endif
++        case FM_PCD_IOC_PRS_LOAD_SW:
++        {
++            ioc_fm_pcd_prs_sw_params_t *param;
++            uint8_t                    *p_code;
++
++            param = (ioc_fm_pcd_prs_sw_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_prs_sw_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_prs_sw_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_prs_sw_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_prs_sw_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_prs_sw_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_prs_sw_params_t));
++                if (copy_from_user(compat_param,
++                            (ioc_compat_fm_pcd_prs_sw_params_t *) compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_prs_sw_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_fm_pcd_prs_sw(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_prs_sw_params_t *)arg,
++                            sizeof(ioc_fm_pcd_prs_sw_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            if (!param->p_code || !param->size)
++            {
++                XX_Free(param);
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            p_code = (uint8_t *) XX_Malloc(param->size);
++            if (!p_code)
++            {
++                XX_Free(param);
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++            }
++
++            memset(p_code, 0, param->size);
++            if (copy_from_user(p_code, param->p_code, param->size))
++            {
++                XX_Free(p_code);
++                XX_Free(param);
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            param->p_code = p_code;
++
++            err = FM_PCD_PrsLoadSw(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdPrsSwParams*)param);
++
++            XX_Free(p_code);
++            XX_Free(param);
++            break;
++        }
++
++        case FM_PCD_IOC_SET_ADVANCED_OFFLOAD_SUPPORT:
++            err = FM_PCD_SetAdvancedOffloadSupport(p_LnxWrpFmDev->h_PcdDev);
++            break;
++
++        case FM_PCD_IOC_ENABLE:
++            err = FM_PCD_Enable(p_LnxWrpFmDev->h_PcdDev);
++            break;
++
++        case FM_PCD_IOC_DISABLE:
++            err = FM_PCD_Disable(p_LnxWrpFmDev->h_PcdDev);
++            break;
++
++        case FM_PCD_IOC_FORCE_INTR:
++        {
++            int exception;
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (get_user(exception, (int *) compat_ptr(arg)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++            else
++#endif
++            {
++                if (get_user(exception, (int *)arg))
++                   RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            err = FM_PCD_ForceIntr(p_LnxWrpFmDev->h_PcdDev, (e_FmPcdExceptions)exception);
++            break;
++        }
++
++        case FM_PCD_IOC_SET_EXCEPTION:
++        {
++            ioc_fm_pcd_exception_params_t *param;
++
++            param = (ioc_fm_pcd_exception_params_t *) XX_Malloc(
++                    sizeof(ioc_fm_pcd_exception_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_exception_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_exception_params_t *)compat_ptr(arg),
++                                    sizeof(ioc_fm_pcd_exception_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_exception_params_t *)arg,
++                                    sizeof(ioc_fm_pcd_exception_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            err = FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, param->exception, param->enable);
++
++            XX_Free(param);
++            break;
++        }
++
++        case FM_PCD_IOC_KG_SET_ADDITIONAL_DATA_AFTER_PARSING:
++        {
++            uint8_t payloadOffset;
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (get_user(payloadOffset, (uint8_t*) compat_ptr(arg)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++            else
++#endif
++            {
++                if (get_user(payloadOffset, (uint8_t*) arg))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            err = FM_PCD_KgSetAdditionalDataAfterParsing(p_LnxWrpFmDev->h_PcdDev, payloadOffset);
++            break;
++        }
++
++        case FM_PCD_IOC_KG_SET_DFLT_VALUE:
++        {
++            ioc_fm_pcd_kg_dflt_value_params_t *param;
++
++            param = (ioc_fm_pcd_kg_dflt_value_params_t *) XX_Malloc(
++                    sizeof(ioc_fm_pcd_kg_dflt_value_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_kg_dflt_value_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_kg_dflt_value_params_t *)compat_ptr(arg),
++                                    sizeof(ioc_fm_pcd_kg_dflt_value_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_kg_dflt_value_params_t *)arg,
++                                    sizeof(ioc_fm_pcd_kg_dflt_value_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            err = FM_PCD_KgSetDfltValue(p_LnxWrpFmDev->h_PcdDev, param->valueId, param->value);
++
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET_COMPAT:
++#endif
++        case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET:
++        {
++            ioc_fm_pcd_net_env_params_t  *param;
++
++            param = (ioc_fm_pcd_net_env_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_net_env_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_net_env_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_net_env_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_net_env_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_net_env_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_net_env_params_t));
++                if (copy_from_user(compat_param, (ioc_compat_fm_pcd_net_env_params_t *) compat_ptr(arg),
++                                    sizeof(ioc_compat_fm_pcd_net_env_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_net_env(compat_param, param, COMPAT_US_TO_K);
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_net_env_params_t *) arg,
++                            sizeof(ioc_fm_pcd_net_env_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            param->id = FM_PCD_NetEnvCharacteristicsSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdNetEnvParams*)param);
++
++            if (!param->id)
++            {
++                XX_Free(param);
++                err = E_INVALID_VALUE;
++                /* Since the LLD has no errno-style error reporting,
++                   we're left here with no other option than to report
++                   a generic E_INVALID_VALUE */
++                break;
++            }
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_net_env_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_net_env_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_net_env_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_net_env_params_t));
++                compat_copy_fm_pcd_net_env(compat_param, param, COMPAT_K_TO_US);
++
++                if (copy_to_user((ioc_compat_fm_pcd_net_env_params_t *) compat_ptr(arg),
++                            compat_param,
++                            sizeof(ioc_compat_fm_pcd_net_env_params_t)))
++                    err = E_READ_FAILED;
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_to_user((ioc_fm_pcd_net_env_params_t *)arg,
++                            param,
++                            sizeof(ioc_fm_pcd_net_env_params_t)))
++                    err = E_READ_FAILED;
++            }
++
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE_COMPAT:
++#endif
++        case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE:
++        {
++            ioc_fm_obj_t id;
++
++            memset(&id, 0 , sizeof(ioc_fm_obj_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_obj_t compat_id;
++
++                if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++                compat_obj_delete(&compat_id, &id);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            err = FM_PCD_NetEnvCharacteristicsDelete(id.obj);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_KG_SCHEME_SET_COMPAT:
++#endif
++        case FM_PCD_IOC_KG_SCHEME_SET:
++        {
++            ioc_fm_pcd_kg_scheme_params_t *param;
++
++            param = (ioc_fm_pcd_kg_scheme_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_kg_scheme_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_kg_scheme_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_kg_scheme_params_t *compat_param = NULL;
++
++                compat_param = (ioc_compat_fm_pcd_kg_scheme_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_kg_scheme_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_params_t));
++
++                if (copy_from_user(compat_param, (ioc_compat_fm_pcd_kg_scheme_params_t *) compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_kg_scheme_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_kg_scheme(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_kg_scheme_params_t *)arg,
++                            sizeof(ioc_fm_pcd_kg_scheme_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            param->id = FM_PCD_KgSchemeSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdKgSchemeParams*)param);
++
++            if (!param->id)
++            {
++                XX_Free(param);
++                err = E_INVALID_VALUE;
++                /* Since the LLD has no errno-style error reporting,
++                   we're left here with no other option than to report
++                   a generic E_INVALID_VALUE */
++                break;
++            }
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_kg_scheme_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_kg_scheme_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_kg_scheme_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_params_t));
++                compat_copy_fm_pcd_kg_scheme(compat_param, param, COMPAT_K_TO_US);
++                if (copy_to_user((ioc_compat_fm_pcd_kg_scheme_params_t *)compat_ptr(arg),
++                            compat_param,
++                            sizeof(ioc_compat_fm_pcd_kg_scheme_params_t)))
++                    err = E_READ_FAILED;
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_to_user((ioc_fm_pcd_kg_scheme_params_t *)arg,
++                            param,
++                            sizeof(ioc_fm_pcd_kg_scheme_params_t)))
++                    err = E_READ_FAILED;
++            }
++
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_KG_SCHEME_GET_CNTR_COMPAT:
++#endif
++        case FM_PCD_IOC_KG_SCHEME_GET_CNTR:
++        {
++            ioc_fm_pcd_kg_scheme_spc_t *param;
++
++            param = (ioc_fm_pcd_kg_scheme_spc_t *) XX_Malloc(sizeof(ioc_fm_pcd_kg_scheme_spc_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_kg_scheme_spc_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_kg_scheme_spc_t *compat_param = NULL;
++
++                compat_param = (ioc_compat_fm_pcd_kg_scheme_spc_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t));
++
++                if (copy_from_user(compat_param, (ioc_compat_fm_pcd_kg_scheme_spc_t *) compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_kg_scheme_spc(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_kg_scheme_spc_t *)arg,
++                            sizeof(ioc_fm_pcd_kg_scheme_spc_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            param->val = FM_PCD_KgSchemeGetCounter((t_Handle)param->id);
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_kg_scheme_spc_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_kg_scheme_spc_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t));
++                compat_copy_fm_pcd_kg_scheme_spc(compat_param, param, COMPAT_K_TO_US);
++                if (copy_to_user((ioc_compat_fm_pcd_kg_scheme_spc_t *)compat_ptr(arg),
++                            compat_param,
++                            sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t)))
++                    err = E_READ_FAILED;
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_to_user((ioc_fm_pcd_kg_scheme_spc_t *)arg,
++                            param,
++                            sizeof(ioc_fm_pcd_kg_scheme_spc_t)))
++                    err = E_READ_FAILED;
++            }
++
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_KG_SCHEME_DELETE_COMPAT:
++#endif
++        case FM_PCD_IOC_KG_SCHEME_DELETE:
++        {
++            ioc_fm_obj_t id;
++
++            memset(&id, 0 , sizeof(ioc_fm_obj_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_obj_t compat_id;
++
++                if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++                compat_obj_delete(&compat_id, &id);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            err = FM_PCD_KgSchemeDelete(id.obj);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_MATCH_TABLE_SET_COMPAT:
++#endif
++        case FM_PCD_IOC_MATCH_TABLE_SET:
++        {
++            ioc_fm_pcd_cc_node_params_t *param;
++            uint8_t                     *keys;
++            uint8_t                     *masks;
++            int                         i,k;
++
++            param = (ioc_fm_pcd_cc_node_params_t *) XX_Malloc(
++                    sizeof(ioc_fm_pcd_cc_node_params_t) +
++                    2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY);
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_cc_node_params_t) +
++                    2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY);
++
++            keys = (uint8_t *) (param + 1);
++            masks = keys + IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY;
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_node_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_node_params_t *) XX_Malloc(
++                                    sizeof(ioc_compat_fm_pcd_cc_node_params_t) +
++                                    2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY);
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_params_t) +
++                        2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY);
++
++                if (copy_from_user(compat_param,
++                            (ioc_compat_fm_pcd_cc_node_params_t *)compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_cc_node_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_cc_node(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_cc_node_params_t *)arg, sizeof(ioc_fm_pcd_cc_node_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            ASSERT_COND(param->keys_params.num_of_keys <= IOC_FM_PCD_MAX_NUM_OF_KEYS);
++            ASSERT_COND(param->keys_params.key_size <= IOC_FM_PCD_MAX_SIZE_OF_KEY);
++
++            /* support for indexed lookup */
++            if( !(param->extract_cc_params.type == e_IOC_FM_PCD_EXTRACT_NON_HDR &&
++                  param->extract_cc_params.extract_params.extract_non_hdr.src == e_IOC_FM_PCD_EXTRACT_FROM_HASH &&
++                  param->extract_cc_params.extract_params.extract_non_hdr.action == e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP))
++            {
++                for (i=0, k=0;
++                     i < param->keys_params.num_of_keys;
++                     i++, k += IOC_FM_PCD_MAX_SIZE_OF_KEY)
++                {
++                    if (param->keys_params.key_params[i].p_key &&
++                            param->keys_params.key_size)
++                    {
++                        if (copy_from_user(&keys[k],
++                                    param->keys_params.key_params[i].p_key,
++                                    param->keys_params.key_size))
++                        {
++                            XX_Free(param);
++                            RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                        }
++
++                        param->keys_params.key_params[i].p_key = &keys[k];
++                    }
++
++                    if (param->keys_params.key_params[i].p_mask)
++                    {
++                        if (copy_from_user(&masks[k],
++                                    param->keys_params.key_params[i].p_mask,
++                                    param->keys_params.key_size))
++                        {
++                            XX_Free(param);
++                            RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                        }
++
++                        param->keys_params.key_params[i].p_mask = &masks[k];
++                    }
++                }
++            }
++
++            param->id = FM_PCD_MatchTableSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdCcNodeParams*)param);
++
++            if (!param->id) {
++                XX_Free(param);
++                err = E_INVALID_VALUE;
++                /* Since the LLD has no errno-style error reporting,
++                   we're left here with no other option than to report
++                   a generic E_INVALID_VALUE */
++                break;
++            }
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_node_params_t *compat_param;
++                compat_param = (ioc_compat_fm_pcd_cc_node_params_t *) XX_Malloc(
++                                            sizeof(ioc_compat_fm_pcd_cc_node_params_t) +
++                                            2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY);
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_params_t) +
++                        2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY);
++                compat_copy_fm_pcd_cc_node(compat_param, param, COMPAT_K_TO_US);
++
++                if (copy_to_user((ioc_compat_fm_pcd_cc_node_params_t *)compat_ptr(arg),
++                            compat_param,
++                            sizeof(ioc_compat_fm_pcd_cc_node_params_t)))
++                    err = E_READ_FAILED;
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_to_user((ioc_fm_pcd_cc_node_params_t *)arg,
++                            param,
++                            sizeof(ioc_fm_pcd_cc_node_params_t)))
++                    err = E_READ_FAILED;
++            }
++
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_MATCH_TABLE_DELETE_COMPAT:
++#endif
++        case FM_PCD_IOC_MATCH_TABLE_DELETE:
++        {
++            ioc_fm_obj_t id;
++
++            memset(&id, 0 , sizeof(ioc_fm_obj_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_obj_t compat_id;
++
++                if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++                compat_obj_delete(&compat_id, &id);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            err = FM_PCD_MatchTableDelete(id.obj);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_CC_ROOT_BUILD_COMPAT:
++#endif
++        case FM_PCD_IOC_CC_ROOT_BUILD:
++        {
++            ioc_fm_pcd_cc_tree_params_t *param;
++
++            param = (ioc_fm_pcd_cc_tree_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_cc_tree_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_cc_tree_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_tree_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_tree_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_cc_tree_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tree_params_t));
++                if (copy_from_user(compat_param,
++                            (ioc_compat_fm_pcd_cc_tree_params_t *)compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_cc_tree_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_cc_tree(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_cc_tree_params_t *)arg,
++                            sizeof(ioc_fm_pcd_cc_tree_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            param->id = FM_PCD_CcRootBuild(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdCcTreeParams*)param);
++
++            if (!param->id) {
++                XX_Free(param);
++                err = E_INVALID_VALUE;
++                /* Since the LLD has no errno-style error reporting,
++                   we're left here with no other option than to report
++                   a generic E_INVALID_VALUE */
++                break;
++            }
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_tree_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_tree_params_t *) XX_Malloc(sizeof(ioc_compat_fm_pcd_cc_tree_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tree_params_t));
++
++                compat_copy_fm_pcd_cc_tree(compat_param, param, COMPAT_K_TO_US);
++
++                if (copy_to_user((ioc_compat_fm_pcd_cc_tree_params_t *)compat_ptr(arg),
++                            compat_param,
++                            sizeof(ioc_compat_fm_pcd_cc_tree_params_t)))
++                    err = E_READ_FAILED;
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_to_user((ioc_fm_pcd_cc_tree_params_t *)arg,
++                            param,
++                            sizeof(ioc_fm_pcd_cc_tree_params_t)))
++                    err = E_READ_FAILED;
++            }
++
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_CC_ROOT_DELETE_COMPAT:
++#endif
++        case FM_PCD_IOC_CC_ROOT_DELETE:
++        {
++            ioc_fm_obj_t id;
++
++            memset(&id, 0 , sizeof(ioc_fm_obj_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_obj_t compat_id;
++
++                if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++                compat_obj_delete(&compat_id, &id);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            err = FM_PCD_CcRootDelete(id.obj);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_PLCR_PROFILE_SET_COMPAT:
++#endif
++        case FM_PCD_IOC_PLCR_PROFILE_SET:
++        {
++            ioc_fm_pcd_plcr_profile_params_t *param;
++
++            param = (ioc_fm_pcd_plcr_profile_params_t *) XX_Malloc(
++                    sizeof(ioc_fm_pcd_plcr_profile_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_plcr_profile_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_plcr_profile_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_plcr_profile_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_plcr_profile_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_plcr_profile_params_t));
++                if (copy_from_user(compat_param, (
++                            ioc_compat_fm_pcd_plcr_profile_params_t *)compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_plcr_profile_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_plcr_profile(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_plcr_profile_params_t *)arg,
++                                    sizeof(ioc_fm_pcd_plcr_profile_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            if (!param->modify &&
++                (((t_FmPcdPlcrProfileParams*)param)->id.newParams.profileType != e_FM_PCD_PLCR_SHARED))
++            {
++                t_Handle h_Port;
++                ioc_fm_pcd_port_params_t *port_params;
++
++                port_params = (ioc_fm_pcd_port_params_t*) XX_Malloc(sizeof(ioc_fm_pcd_port_params_t));
++                if (!port_params)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(port_params, 0, sizeof(ioc_fm_pcd_port_params_t));
++                if (copy_from_user(port_params, (ioc_fm_pcd_port_params_t*)((t_FmPcdPlcrProfileParams*)param)->id.newParams.h_FmPort,
++                            sizeof(ioc_fm_pcd_port_params_t)))
++                {
++                    XX_Free(port_params);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                switch(port_params->port_type)
++                {
++                    case (e_IOC_FM_PORT_TYPE_RX):
++                        if (port_params->port_id < FM_MAX_NUM_OF_1G_RX_PORTS) {
++                            h_Port = p_LnxWrpFmDev->rxPorts[port_params->port_id].h_Dev;
++                            break;
++                        }
++                        goto invalid_port_id;
++
++                    case (e_IOC_FM_PORT_TYPE_RX_10G):
++                        if (port_params->port_id < FM_MAX_NUM_OF_10G_RX_PORTS) {
++#ifndef CONFIG_FMAN_ARM
++                            if (IS_T1023_T1024) {
++                                h_Port = p_LnxWrpFmDev->rxPorts[port_params->port_id].h_Dev;
++                            } else {
++#else
++                            {
++#endif
++                                h_Port = p_LnxWrpFmDev->rxPorts[port_params->port_id + FM_MAX_NUM_OF_1G_RX_PORTS].h_Dev;
++                            }
++                            break;
++                        }
++                        goto invalid_port_id;
++
++                    case (e_IOC_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++                        if (port_params->port_id && port_params->port_id < FM_MAX_NUM_OF_OH_PORTS) {
++                            h_Port = p_LnxWrpFmDev->opPorts[port_params->port_id - 1].h_Dev;
++                            break;
++                        }
++                        goto invalid_port_id;
++
++                    default:
++invalid_port_id:
++                        XX_Free(port_params);
++                        XX_Free(param);
++                        RETURN_ERROR(MINOR, E_INVALID_SELECTION, NO_MSG);
++                }
++
++                ((t_FmPcdPlcrProfileParams*)param)->id.newParams.h_FmPort = h_Port;
++                XX_Free(port_params);
++            }
++
++            param->id = FM_PCD_PlcrProfileSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdPlcrProfileParams*)param);
++
++            if (!param->id) {
++                XX_Free(param);
++                err = E_INVALID_VALUE;
++                /* Since the LLD has no errno-style error reporting,
++                   we're left here with no other option than to report
++                   a generic E_INVALID_VALUE */
++                break;
++            }
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_plcr_profile_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_plcr_profile_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_plcr_profile_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_plcr_profile_params_t));
++                compat_copy_fm_pcd_plcr_profile(compat_param, param, COMPAT_K_TO_US);
++                if (copy_to_user((ioc_compat_fm_pcd_plcr_profile_params_t *) compat_ptr(arg),
++                            compat_param,
++                            sizeof(ioc_compat_fm_pcd_plcr_profile_params_t)))
++                    err = E_READ_FAILED;
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_to_user((ioc_fm_pcd_plcr_profile_params_t *)arg,
++                            param,
++                            sizeof(ioc_fm_pcd_plcr_profile_params_t)))
++                    err = E_READ_FAILED;
++            }
++
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_PLCR_PROFILE_DELETE_COMPAT:
++#endif
++        case FM_PCD_IOC_PLCR_PROFILE_DELETE:
++        {
++            ioc_fm_obj_t id;
++
++            memset(&id, 0 , sizeof(ioc_fm_obj_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_obj_t compat_id;
++
++                if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++                compat_obj_delete(&compat_id, &id);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            err = FM_PCD_PlcrProfileDelete(id.obj);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE_COMPAT:
++#endif
++        case FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE:
++        {
++            ioc_fm_pcd_cc_tree_modify_next_engine_params_t *param;
++
++            param = (ioc_fm_pcd_cc_tree_modify_next_engine_params_t *) XX_Malloc(
++                    sizeof(ioc_fm_pcd_cc_tree_modify_next_engine_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_cc_tree_modify_next_engine_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t));
++                if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *) compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_fm_pcd_cc_tree_modify_next_engine(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_cc_tree_modify_next_engine_params_t *)arg,
++                            sizeof(ioc_fm_pcd_cc_tree_modify_next_engine_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            err = FM_PCD_CcRootModifyNextEngine(param->id,
++                                                param->grp_indx,
++                                                param->indx,
++                                                (t_FmPcdCcNextEngineParams*)(&param->cc_next_engine_params));
++
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE_COMPAT:
++#endif
++        case FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE:
++        {
++            ioc_fm_pcd_cc_node_modify_next_engine_params_t *param;
++
++            param = (ioc_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc(
++                    sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t));
++                if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_cc_node_modify_next_engine(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_next_engine_params_t *)arg,
++                            sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            err = FM_PCD_MatchTableModifyNextEngine(param->id,
++                    param->key_indx,
++                    (t_FmPcdCcNextEngineParams*)(&param->cc_next_engine_params));
++
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE_COMPAT:
++#endif
++        case FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE:
++        {
++            ioc_fm_pcd_cc_node_modify_next_engine_params_t *param;
++
++            param = (ioc_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc(
++                    sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t));
++                if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) compat_ptr(arg),
++                                    sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_cc_node_modify_next_engine(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_next_engine_params_t *) arg,
++                                    sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            err = FM_PCD_MatchTableModifyMissNextEngine(param->id,
++                    (t_FmPcdCcNextEngineParams*)(&param->cc_next_engine_params));
++
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY_COMPAT:
++#endif
++        case FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY:
++        {
++            ioc_fm_pcd_cc_node_remove_key_params_t *param;
++
++            param = (ioc_fm_pcd_cc_node_remove_key_params_t *) XX_Malloc(
++                    sizeof(ioc_fm_pcd_cc_node_remove_key_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_cc_node_remove_key_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_node_remove_key_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_node_remove_key_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_cc_node_remove_key_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_remove_key_params_t));
++                if (copy_from_user(compat_param,
++                            (ioc_compat_fm_pcd_cc_node_remove_key_params_t *)compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_cc_node_remove_key_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                param->id = compat_ptr(compat_param->id);
++                param->key_indx = compat_param->key_indx;
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_cc_node_remove_key_params_t *) arg,
++                            sizeof(ioc_fm_pcd_cc_node_remove_key_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            err = FM_PCD_MatchTableRemoveKey(param->id, param->key_indx);
++
++            XX_Free(param);
++            break;
++        }
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_MATCH_TABLE_ADD_KEY_COMPAT:
++#endif
++        case FM_PCD_IOC_MATCH_TABLE_ADD_KEY:
++        {
++            ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param;
++
++            param = (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc(
++                    sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
++                if (copy_from_user(compat_param,
++                            (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_cc_node_modify_key_and_next_engine(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)arg,
++                                    sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            if (param->key_size)
++            {
++                int size = 0;
++
++                if (param->key_params.p_key)  size += param->key_size;
++                if (param->key_params.p_mask) size += param->key_size;
++
++                if (size)
++                {
++                    uint8_t *p_tmp;
++
++                    p_tmp = (uint8_t*) XX_Malloc(size);
++                    if (!p_tmp)
++                    {
++                        XX_Free(param);
++                        RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD key/mask"));
++                    }
++
++                    if (param->key_params.p_key)
++                    {
++                        if (copy_from_user(p_tmp, param->key_params.p_key, param->key_size))
++                        {
++                            XX_Free(p_tmp);
++                            XX_Free(param);
++                            RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                        }
++
++                        param->key_params.p_key = p_tmp;
++                    }
++
++                    if (param->key_params.p_mask)
++                    {
++                        p_tmp += param->key_size;
++                        if (copy_from_user(p_tmp, param->key_params.p_mask, param->key_size))
++                        {
++                            XX_Free(p_tmp - param->key_size);
++                            XX_Free(param);
++                            RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                        }
++
++                        param->key_params.p_mask = p_tmp;
++                    }
++                }
++            }
++
++            err = FM_PCD_MatchTableAddKey(
++                    param->id,
++                    param->key_indx,
++                    param->key_size,
++                    (t_FmPcdCcKeyParams*)&param->key_params);
++
++            if (param->key_params.p_key)
++                XX_Free(param->key_params.p_key);
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE_COMPAT:
++#endif
++        case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE:
++        {
++            ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param;
++
++            param = (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc(
++                    sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
++                if (copy_from_user(compat_param,
++                            (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_cc_node_modify_key_and_next_engine(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)arg,
++                            sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            err = FM_PCD_MatchTableModifyKeyAndNextEngine(param->id,
++                    param->key_indx,
++                    param->key_size,
++                    (t_FmPcdCcKeyParams*)(&param->key_params));
++
++            XX_Free(param);
++            break;
++        }
++        
++        
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_MATCH_TABLE_GET_KEY_STAT_COMPAT:
++#endif
++        case FM_PCD_IOC_MATCH_TABLE_GET_KEY_STAT:
++        {
++            ioc_fm_pcd_cc_tbl_get_stats_t param;
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
++                if (!compat_param)
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
++                if (copy_from_user(compat_param,
++                            (ioc_compat_fm_pcd_cc_tbl_get_stats_t *)compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)))
++                {
++                    XX_Free(compat_param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, &param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(&param, (ioc_fm_pcd_cc_tbl_get_stats_t *)arg,
++                            sizeof(ioc_fm_pcd_cc_tbl_get_stats_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++  
++            err = FM_PCD_MatchTableGetKeyStatistics((t_Handle) param.id,
++                                                     param.key_index,
++                                                     (t_FmPcdCcKeyStatistics *) &param.statistics);
++         
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t*) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
++                if (!compat_param)
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
++                compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, &param, COMPAT_K_TO_US);
++                if (copy_to_user((ioc_compat_fm_pcd_cc_tbl_get_stats_t*) compat_ptr(arg),
++                            compat_param,
++                            sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t))){
++                    XX_Free(compat_param);
++                    RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
++                }
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_to_user((ioc_fm_pcd_cc_tbl_get_stats_t *)arg,
++                                  &param,
++                                  sizeof(ioc_fm_pcd_cc_tbl_get_stats_t)))
++                    RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
++            }
++
++            break;
++        }
++
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_MATCH_TABLE_GET_MISS_STAT_COMPAT:
++#endif
++        case FM_PCD_IOC_MATCH_TABLE_GET_MISS_STAT:
++        {
++            ioc_fm_pcd_cc_tbl_get_stats_t param;
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
++                if (!compat_param)
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
++                if (copy_from_user(compat_param,
++                            (ioc_compat_fm_pcd_cc_tbl_get_stats_t *)compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)))
++                {
++                    XX_Free(compat_param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, &param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(&param, (ioc_fm_pcd_cc_tbl_get_stats_t *)arg,
++                            sizeof(ioc_fm_pcd_cc_tbl_get_stats_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++  
++            err = FM_PCD_MatchTableGetMissStatistics((t_Handle) param.id,
++                                                     (t_FmPcdCcKeyStatistics *) &param.statistics);
++         
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t*) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
++                if (!compat_param)
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
++                compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, &param, COMPAT_K_TO_US);
++                if (copy_to_user((ioc_compat_fm_pcd_cc_tbl_get_stats_t*) compat_ptr(arg),
++                            compat_param,
++                            sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t))){
++                    XX_Free(compat_param);
++                    RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
++                }
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_to_user((ioc_fm_pcd_cc_tbl_get_stats_t *)arg,
++                                  &param,
++                                  sizeof(ioc_fm_pcd_cc_tbl_get_stats_t)))
++                    RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
++            }
++
++            break;
++        }
++        
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_HASH_TABLE_GET_MISS_STAT_COMPAT:
++#endif
++        case FM_PCD_IOC_HASH_TABLE_GET_MISS_STAT:
++        {
++            ioc_fm_pcd_cc_tbl_get_stats_t param;
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
++                if (!compat_param)
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
++                if (copy_from_user(compat_param,
++                            (ioc_compat_fm_pcd_cc_tbl_get_stats_t *)compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)))
++                {
++                    XX_Free(compat_param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, &param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(&param, (ioc_fm_pcd_cc_tbl_get_stats_t *)arg,
++                            sizeof(ioc_fm_pcd_cc_tbl_get_stats_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++  
++            err = FM_PCD_HashTableGetMissStatistics((t_Handle) param.id,
++                                                     (t_FmPcdCcKeyStatistics *) &param.statistics);
++         
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t*) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
++                if (!compat_param)
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
++                compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, &param, COMPAT_K_TO_US);
++                if (copy_to_user((ioc_compat_fm_pcd_cc_tbl_get_stats_t*) compat_ptr(arg),
++                            compat_param,
++                            sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t))){
++                    XX_Free(compat_param);
++                    RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
++                }
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_to_user((ioc_fm_pcd_cc_tbl_get_stats_t *)arg,
++                                  &param,
++                                  sizeof(ioc_fm_pcd_cc_tbl_get_stats_t)))
++                    RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
++            }
++
++            break;
++        }
++      
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_HASH_TABLE_SET_COMPAT:
++#endif
++        case FM_PCD_IOC_HASH_TABLE_SET:
++        {
++            ioc_fm_pcd_hash_table_params_t *param;
++
++            param = (ioc_fm_pcd_hash_table_params_t*) XX_Malloc(
++                    sizeof(ioc_fm_pcd_hash_table_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_hash_table_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_hash_table_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_hash_table_params_t*) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_hash_table_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_params_t));
++                if (copy_from_user(compat_param,
++                            (ioc_compat_fm_pcd_hash_table_params_t*)compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_hash_table_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_hash_table(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_hash_table_params_t *)arg,
++                                    sizeof(ioc_fm_pcd_hash_table_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            param->id = FM_PCD_HashTableSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdHashTableParams *) param);
++
++            if (!param->id)
++            {
++                XX_Free(param);
++                err = E_INVALID_VALUE;
++                /* Since the LLD has no errno-style error reporting,
++                   we're left here with no other option than to report
++                   a generic E_INVALID_VALUE */
++                break;
++            }
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_hash_table_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_hash_table_params_t*) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_hash_table_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_params_t));
++                compat_copy_fm_pcd_hash_table(compat_param, param, COMPAT_K_TO_US);
++                if (copy_to_user((ioc_compat_fm_pcd_hash_table_params_t*) compat_ptr(arg),
++                            compat_param,
++                            sizeof(ioc_compat_fm_pcd_hash_table_params_t)))
++                    err = E_READ_FAILED;
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_to_user((ioc_fm_pcd_hash_table_params_t *)arg,
++                            param,
++                            sizeof(ioc_fm_pcd_hash_table_params_t)))
++                    err = E_READ_FAILED;
++            }
++
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_HASH_TABLE_DELETE_COMPAT:
++#endif
++        case FM_PCD_IOC_HASH_TABLE_DELETE:
++        {
++            ioc_fm_obj_t id;
++
++            memset(&id, 0, sizeof(ioc_fm_obj_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_obj_t compat_id;
++
++                if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++                id.obj = compat_pcd_id2ptr(compat_id.obj);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            err = FM_PCD_HashTableDelete(id.obj);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_HASH_TABLE_ADD_KEY_COMPAT:
++#endif
++        case FM_PCD_IOC_HASH_TABLE_ADD_KEY:
++        {
++            ioc_fm_pcd_hash_table_add_key_params_t *param = NULL;
++
++            param = (ioc_fm_pcd_hash_table_add_key_params_t*) XX_Malloc(
++                    sizeof(ioc_fm_pcd_hash_table_add_key_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_hash_table_add_key_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_hash_table_add_key_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_hash_table_add_key_params_t*) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_hash_table_add_key_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_add_key_params_t));
++                if (copy_from_user(compat_param,
++                            (ioc_compat_fm_pcd_hash_table_add_key_params_t*) compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_hash_table_add_key_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                if (compat_param->key_size)
++                {
++                    param->p_hash_tbl = compat_pcd_id2ptr(compat_param->p_hash_tbl);
++                    param->key_size   = compat_param->key_size;
++
++                    compat_copy_fm_pcd_cc_key(&compat_param->key_params, &param->key_params, COMPAT_US_TO_K);
++                }
++                else
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    err = E_INVALID_VALUE;
++                    break;
++                }
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_hash_table_add_key_params_t*) arg,
++                            sizeof(ioc_fm_pcd_hash_table_add_key_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            if (param->key_size)
++            {
++                int size = 0;
++
++                if (param->key_params.p_key)  size += param->key_size;
++                if (param->key_params.p_mask) size += param->key_size;
++
++                if (size)
++                {
++                    uint8_t *p_tmp;
++
++                    p_tmp = (uint8_t*) XX_Malloc(size);
++                    if (!p_tmp)
++                    {
++                        XX_Free(param);
++                        RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD key/mask"));
++                    }
++
++                    if (param->key_params.p_key)
++                    {
++                        if (copy_from_user(p_tmp, param->key_params.p_key, param->key_size))
++                        {
++                            XX_Free(p_tmp);
++                            XX_Free(param);
++                            RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                        }
++
++                        param->key_params.p_key = p_tmp;
++                    }
++
++                    if (param->key_params.p_mask)
++                    {
++                        p_tmp += param->key_size;
++                        if (copy_from_user(p_tmp, param->key_params.p_mask, param->key_size))
++                        {
++                            XX_Free(p_tmp - param->key_size);
++                            XX_Free(param);
++                            RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                        }
++
++                        param->key_params.p_mask = p_tmp;
++                    }
++                }
++            }
++
++            err = FM_PCD_HashTableAddKey(
++                    param->p_hash_tbl,
++                    param->key_size,
++                    (t_FmPcdCcKeyParams*)&param->key_params);
++
++            if (param->key_params.p_key)
++                XX_Free(param->key_params.p_key);
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_HASH_TABLE_REMOVE_KEY_COMPAT:
++#endif
++        case FM_PCD_IOC_HASH_TABLE_REMOVE_KEY:
++        {
++            ioc_fm_pcd_hash_table_remove_key_params_t *param = NULL;
++
++            param = (ioc_fm_pcd_hash_table_remove_key_params_t*) XX_Malloc(
++                    sizeof(ioc_fm_pcd_hash_table_remove_key_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_hash_table_remove_key_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_hash_table_remove_key_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_hash_table_remove_key_params_t*) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_hash_table_remove_key_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_remove_key_params_t));
++                if (copy_from_user(compat_param,
++                            (ioc_compat_fm_pcd_hash_table_remove_key_params_t*) compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_hash_table_remove_key_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                param->p_hash_tbl = compat_pcd_id2ptr(compat_param->p_hash_tbl);
++                param->key_size   = compat_param->key_size;
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_hash_table_remove_key_params_t*)arg,
++                            sizeof(ioc_fm_pcd_hash_table_remove_key_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            if (param->key_size)
++            {
++                uint8_t *p_key;
++
++                p_key = (uint8_t*) XX_Malloc(param->key_size);
++                if (!p_key)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                if (param->p_key && copy_from_user(p_key, param->p_key, param->key_size))
++                {
++                    XX_Free(p_key);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++                param->p_key = p_key;
++            }
++
++            err = FM_PCD_HashTableRemoveKey(
++                    param->p_hash_tbl,
++                    param->key_size,
++                    param->p_key);
++
++            if (param->p_key)
++                XX_Free(param->p_key);
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_COMPAT:
++#endif
++        case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY:
++        {
++            ioc_fm_pcd_cc_node_modify_key_params_t  *param;
++
++            param = (ioc_fm_pcd_cc_node_modify_key_params_t *) XX_Malloc(
++                    sizeof(ioc_fm_pcd_cc_node_modify_key_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_key_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_cc_node_modify_key_params_t  *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_cc_node_modify_key_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_cc_node_modify_key_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_key_params_t));
++                if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_node_modify_key_params_t *)compat_ptr(arg),
++                                    sizeof(ioc_compat_fm_pcd_cc_node_modify_key_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_cc_node_modify_key(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_key_params_t *)arg,
++                                    sizeof(ioc_fm_pcd_cc_node_modify_key_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            if (param->key_size)
++            {
++                int size = 0;
++
++                if (param->p_key)  size += param->key_size;
++                if (param->p_mask) size += param->key_size;
++
++                if (size)
++                {
++                    uint8_t *p_tmp;
++
++                    p_tmp = (uint8_t*) XX_Malloc(size);
++                    if (!p_tmp)
++                    {
++                        XX_Free(param);
++                        RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD key/mask"));
++                    }
++
++                    if (param->p_key)
++                    {
++                        if (copy_from_user(p_tmp, param->p_key, param->key_size))
++                        {
++                            XX_Free(p_tmp);
++                            XX_Free(param);
++                            RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                        }
++
++                        param->p_key = p_tmp;
++                    }
++
++                    if (param->p_mask)
++                    {
++                        p_tmp += param->key_size;
++                        if (copy_from_user(p_tmp, param->p_mask, param->key_size))
++                        {
++                            XX_Free(p_tmp - param->key_size);
++                            XX_Free(param);
++                            RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                        }
++
++                        param->p_mask = p_tmp;
++                    }
++                }
++            }
++
++            err = FM_PCD_MatchTableModifyKey(param->id,
++                    param->key_indx,
++                    param->key_size,
++                    param->p_key,
++                    param->p_mask);
++
++            if (param->p_key)
++                XX_Free(param->p_key);
++            else if (param->p_mask)
++                XX_Free(param->p_mask);
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_MANIP_NODE_SET_COMPAT:
++#endif
++        case FM_PCD_IOC_MANIP_NODE_SET:
++        {
++            ioc_fm_pcd_manip_params_t *param;
++            uint8_t *p_data = NULL;
++            uint8_t size;
++
++            param = (ioc_fm_pcd_manip_params_t *) XX_Malloc(
++                        sizeof(ioc_fm_pcd_manip_params_t));
++
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_manip_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_manip_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_manip_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_manip_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_manip_params_t));
++                if (copy_from_user(compat_param,
++                            (ioc_compat_fm_pcd_manip_params_t *) compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_manip_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_fm_pcd_manip_set_node(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_manip_params_t *)arg,
++                                            sizeof(ioc_fm_pcd_manip_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            if (param->type == e_IOC_FM_PCD_MANIP_HDR)
++            {
++                size = param->u.hdr.insrt_params.u.generic.size;
++                p_data = (uint8_t *) XX_Malloc(size);
++                if (!p_data )
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, NO_MSG);
++                }
++
++                if (param->u.hdr.insrt_params.u.generic.p_data &&
++                        copy_from_user(p_data,
++                            param->u.hdr.insrt_params.u.generic.p_data, size))
++                {
++                    XX_Free(p_data);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                param->u.hdr.insrt_params.u.generic.p_data = p_data;
++            }
++
++            if (param->id)
++            {
++                /* Security Hole: the user can pass any piece of garbage
++                   in 'param->id', and that will go straight through to the LLD,
++                   no checks being done by the wrapper! */
++                err = FM_PCD_ManipNodeReplace(
++                        (t_Handle) param->id,
++                        (t_FmPcdManipParams*) param);
++                if (err)
++                {
++                    if (p_data)
++                        XX_Free(p_data);
++                    XX_Free(param);
++                    break;
++                }
++            }
++            else
++            {
++                param->id = FM_PCD_ManipNodeSet(
++                        p_LnxWrpFmDev->h_PcdDev,
++                        (t_FmPcdManipParams*) param);
++                if (!param->id)
++                {
++                    if (p_data)
++                        XX_Free(p_data);
++                    XX_Free(param);
++                    err = E_INVALID_VALUE;
++                    /* Since the LLD has no errno-style error reporting,
++                       we're left here with no other option than to report
++                       a generic E_INVALID_VALUE */
++                    break;
++                }
++            }
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_manip_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_manip_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_manip_params_t));
++                if (!compat_param)
++                {
++                    if (p_data)
++                        XX_Free(p_data);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_manip_params_t));
++
++                compat_fm_pcd_manip_set_node(compat_param, param, COMPAT_K_TO_US);
++
++                if (copy_to_user((ioc_compat_fm_pcd_manip_params_t *) compat_ptr(arg),
++                            compat_param,
++                            sizeof(ioc_compat_fm_pcd_manip_params_t)))
++                    err = E_READ_FAILED;
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_to_user((ioc_fm_pcd_manip_params_t *)arg,
++                            param, sizeof(ioc_fm_pcd_manip_params_t)))
++                    err = E_READ_FAILED;
++            }
++
++            if (p_data)
++                XX_Free(p_data);
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_MANIP_NODE_DELETE_COMPAT:
++#endif
++        case FM_PCD_IOC_MANIP_NODE_DELETE:
++        {
++            ioc_fm_obj_t id;
++
++            memset(&id, 0, sizeof(ioc_fm_obj_t));
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_obj_t compat_id;
++
++                if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++                compat_obj_delete(&compat_id, &id);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            err = FM_PCD_ManipNodeDelete(id.obj);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++      case FM_PCD_IOC_MANIP_GET_STATS_COMPAT:
++#endif
++        case FM_PCD_IOC_MANIP_GET_STATS:
++      {
++            ioc_fm_pcd_manip_get_stats_t param;
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_manip_get_stats_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_manip_get_stats_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_manip_get_stats_t));
++                if (!compat_param)
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_manip_get_stats_t));
++                if (copy_from_user(compat_param,
++                            (ioc_compat_fm_pcd_manip_get_stats_t *)compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_manip_get_stats_t)))
++                {
++                    XX_Free(compat_param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_manip_get_stats(compat_param, &param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(&param, (ioc_fm_pcd_manip_get_stats_t *)arg,
++                            sizeof(ioc_fm_pcd_manip_get_stats_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            err = FM_PCD_ManipGetStatistics((t_Handle) param.id,
++                                              (t_FmPcdManipStats*) &param.stats);
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_manip_get_stats_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_manip_get_stats_t*) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_manip_get_stats_t));
++                if (!compat_param)
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_manip_get_stats_t));
++                compat_copy_fm_pcd_manip_get_stats(compat_param, &param, COMPAT_K_TO_US);
++                if (copy_to_user((ioc_compat_fm_pcd_manip_get_stats_t*) compat_ptr(arg),
++                            compat_param,
++                            sizeof(ioc_compat_fm_pcd_manip_get_stats_t))){
++                    XX_Free(compat_param);
++                    RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
++                }
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            if (copy_to_user((ioc_fm_pcd_manip_get_stats_t *)arg,
++                                  &param,
++                                  sizeof(ioc_fm_pcd_manip_get_stats_t)))
++                    RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
++
++            break;
++      }
++
++#if (DPAA_VERSION >= 11)
++#if defined(CONFIG_COMPAT)
++      case FM_PCD_IOC_FRM_REPLIC_GROUP_SET_COMPAT:
++#endif
++      case FM_PCD_IOC_FRM_REPLIC_GROUP_SET:
++      {
++              ioc_fm_pcd_frm_replic_group_params_t *param;
++
++              param = (ioc_fm_pcd_frm_replic_group_params_t *) XX_Malloc(
++                              sizeof(ioc_fm_pcd_frm_replic_group_params_t));
++              if (!param)
++                      RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++              memset(param, 0, sizeof(ioc_fm_pcd_frm_replic_group_params_t));
++
++#if defined(CONFIG_COMPAT)
++              if (compat)
++              {
++                      ioc_compat_fm_pcd_frm_replic_group_params_t
++                              *compat_param;
++
++                      compat_param =
++                              (ioc_compat_fm_pcd_frm_replic_group_params_t *)
++                                      XX_Malloc(sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t));
++                      if (!compat_param)
++                      {
++                              XX_Free(param);
++                              RETURN_ERROR(MINOR, E_NO_MEMORY,
++                                              ("IOCTL FM PCD"));
++                      }
++
++                      memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t));
++                      if (copy_from_user(compat_param,
++                              (ioc_compat_fm_pcd_frm_replic_group_params_t *)
++                                      compat_ptr(arg),
++                                      sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t))) {
++                              XX_Free(compat_param);
++                              XX_Free(param);
++                              RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
++                      }
++
++                      compat_copy_fm_pcd_frm_replic_group_params(compat_param,
++                                      param, COMPAT_US_TO_K);
++
++                      XX_Free(compat_param);
++              }
++              else
++#endif
++              {
++                      if (copy_from_user(param,
++                              (ioc_fm_pcd_frm_replic_group_params_t *)arg,
++                              sizeof(ioc_fm_pcd_frm_replic_group_params_t)))
++                      {
++                              XX_Free(param);
++                              RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
++                      }
++              }
++
++              param->id = FM_PCD_FrmReplicSetGroup(p_LnxWrpFmDev->h_PcdDev,
++                              (t_FmPcdFrmReplicGroupParams*)param);
++
++              if (!param->id) {
++                      XX_Free(param);
++                      err = E_INVALID_VALUE;
++                      /*
++                       * Since the LLD has no errno-style error reporting,
++                       * we're left here with no other option than to report
++                       * a generic E_INVALID_VALUE
++                       */
++                      break;
++              }
++
++#if defined(CONFIG_COMPAT)
++              if (compat)
++              {
++                      ioc_compat_fm_pcd_frm_replic_group_params_t
++                              *compat_param;
++
++                      compat_param =
++                              (ioc_compat_fm_pcd_frm_replic_group_params_t *)
++                                      XX_Malloc(sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t));
++                      if (!compat_param)
++                      {
++                              XX_Free(param);
++                              RETURN_ERROR(MINOR, E_NO_MEMORY,
++                                              ("IOCTL FM PCD"));
++                      }
++
++                      memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t));
++                      compat_copy_fm_pcd_frm_replic_group_params(compat_param,
++                                      param, COMPAT_K_TO_US);
++                      if (copy_to_user(
++                              (ioc_compat_fm_pcd_frm_replic_group_params_t *)
++                                      compat_ptr(arg),
++                                      compat_param,
++                                      sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t)))
++                              err = E_WRITE_FAILED;
++
++                      XX_Free(compat_param);
++              }
++              else
++#endif
++              {
++                      if (copy_to_user(
++                              (ioc_fm_pcd_frm_replic_group_params_t *)arg,
++                              param,
++                              sizeof(ioc_fm_pcd_frm_replic_group_params_t)))
++                              err = E_WRITE_FAILED;
++              }
++
++              XX_Free(param);
++              break;
++      }
++      break;
++
++#if defined(CONFIG_COMPAT)
++      case FM_PCD_IOC_FRM_REPLIC_GROUP_DELETE_COMPAT:
++#endif
++      case FM_PCD_IOC_FRM_REPLIC_GROUP_DELETE:
++      {
++              ioc_fm_obj_t id;
++
++              memset(&id, 0, sizeof(ioc_fm_obj_t));
++#if defined(CONFIG_COMPAT)
++              if (compat)
++              {
++                      ioc_compat_fm_obj_t compat_id;
++
++                      if (copy_from_user(&compat_id,
++                                      (ioc_compat_fm_obj_t *) compat_ptr(arg),
++                                      sizeof(ioc_compat_fm_obj_t)))
++                              break;
++                      compat_obj_delete(&compat_id, &id);
++              }
++              else
++#endif
++              {
++                      if (copy_from_user(&id, (ioc_fm_obj_t *) arg,
++                                      sizeof(ioc_fm_obj_t)))
++                              break;
++              }
++
++              return FM_PCD_FrmReplicDeleteGroup(id.obj);
++      }
++      break;
++
++#if defined(CONFIG_COMPAT)
++      case FM_PCD_IOC_FRM_REPLIC_MEMBER_ADD_COMPAT:
++#endif
++      case FM_PCD_IOC_FRM_REPLIC_MEMBER_ADD:
++      {
++              ioc_fm_pcd_frm_replic_member_params_t param;
++
++#if defined(CONFIG_COMPAT)
++              if (compat)
++              {
++                      ioc_compat_fm_pcd_frm_replic_member_params_t compat_param;
++
++                      if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param)))
++                              RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++                      compat_copy_fm_pcd_frm_replic_member_params(&compat_param, &param, COMPAT_US_TO_K);
++              }
++              else
++#endif
++                      if (copy_from_user(&param, (void *)arg, sizeof(param)))
++                              RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++              return FM_PCD_FrmReplicAddMember(param.member.h_replic_group,
++                      param.member.member_index,
++                      (t_FmPcdCcNextEngineParams*)&param.next_engine_params);
++      }
++      break;
++
++#if defined(CONFIG_COMPAT)
++      case FM_PCD_IOC_FRM_REPLIC_MEMBER_REMOVE_COMPAT:
++#endif
++      case FM_PCD_IOC_FRM_REPLIC_MEMBER_REMOVE:
++      {
++              ioc_fm_pcd_frm_replic_member_t param;
++
++#if defined(CONFIG_COMPAT)
++              if (compat)
++              {
++                      ioc_compat_fm_pcd_frm_replic_member_t compat_param;
++
++                      if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param)))
++                              RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++                      compat_copy_fm_pcd_frm_replic_member(&compat_param, &param, COMPAT_US_TO_K);
++              }
++              else
++#endif
++                      if (copy_from_user(&param, (void *)arg, sizeof(param)))
++                              RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++              return FM_PCD_FrmReplicRemoveMember(param.h_replic_group, param.member_index);
++      }
++      break;
++
++#if defined(CONFIG_COMPAT)
++    case FM_IOC_VSP_CONFIG_COMPAT:
++#endif
++    case FM_IOC_VSP_CONFIG:
++    {
++        ioc_fm_vsp_params_t param;
++
++#if defined(CONFIG_COMPAT)
++        if (compat)
++        {
++            ioc_compat_fm_vsp_params_t compat_param;
++
++            if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++            compat_copy_fm_vsp_params(&compat_param, &param, COMPAT_US_TO_K);
++        }
++        else
++#endif
++            if (copy_from_user(&param, (void *)arg, sizeof(param)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++        {
++            uint8_t portId = param.port_params.port_id;
++            param.liodn_offset =
++                p_LnxWrpFmDev->rxPorts[portId].settings.param.specificParams.rxParams.liodnOffset;
++        }
++        param.p_fm = p_LnxWrpFmDev->h_Dev;
++        param.id = FM_VSP_Config((t_FmVspParams *)&param);
++
++#if defined(CONFIG_COMPAT)
++        if (compat)
++        {
++            ioc_compat_fm_vsp_params_t compat_param;
++
++            memset(&compat_param, 0, sizeof(compat_param));
++            compat_copy_fm_vsp_params(&compat_param, &param, COMPAT_K_TO_US);
++
++            if (copy_to_user(compat_ptr(arg), &compat_param, sizeof(compat_param)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++        }
++        else
++#endif
++            if (copy_to_user((void *)arg, &param, sizeof(param)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++        break;
++    }
++
++#if defined(CONFIG_COMPAT)
++    case FM_IOC_VSP_INIT_COMPAT:
++#endif
++    case FM_IOC_VSP_INIT:
++    {
++        ioc_fm_obj_t id;
++
++        memset(&id, 0, sizeof(ioc_fm_obj_t));
++#if defined(CONFIG_COMPAT)
++        if (compat)
++        {
++            ioc_compat_fm_obj_t compat_id;
++
++            if (copy_from_user(&compat_id,
++                    (ioc_compat_fm_obj_t *) compat_ptr(arg),
++                    sizeof(ioc_compat_fm_obj_t)))
++                break;
++            id.obj = compat_pcd_id2ptr(compat_id.obj);
++        }
++        else
++#endif
++        {
++            if (copy_from_user(&id, (ioc_fm_obj_t *) arg,
++                    sizeof(ioc_fm_obj_t)))
++                break;
++        }
++
++        return FM_VSP_Init(id.obj);
++    }
++
++#if defined(CONFIG_COMPAT)
++    case FM_IOC_VSP_FREE_COMPAT:
++#endif
++    case FM_IOC_VSP_FREE:
++    {
++        ioc_fm_obj_t id;
++
++        memset(&id, 0, sizeof(ioc_fm_obj_t));
++#if defined(CONFIG_COMPAT)
++        if (compat)
++        {
++            ioc_compat_fm_obj_t compat_id;
++
++            if (copy_from_user(&compat_id,
++                    (ioc_compat_fm_obj_t *) compat_ptr(arg),
++                    sizeof(ioc_compat_fm_obj_t)))
++                break;
++            compat_obj_delete(&compat_id, &id);
++        }
++        else
++#endif
++        {
++            if (copy_from_user(&id, (ioc_fm_obj_t *) arg,
++                    sizeof(ioc_fm_obj_t)))
++                break;
++        }
++
++        return FM_VSP_Free(id.obj);
++    }
++
++#if defined(CONFIG_COMPAT)
++    case FM_IOC_VSP_CONFIG_POOL_DEPLETION_COMPAT:
++#endif
++    case FM_IOC_VSP_CONFIG_POOL_DEPLETION:
++    {
++        ioc_fm_buf_pool_depletion_params_t param;
++
++#if defined(CONFIG_COMPAT)
++        if (compat)
++        {
++            ioc_compat_fm_buf_pool_depletion_params_t compat_param;
++
++            if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++            compat_copy_fm_buf_pool_depletion_params(&compat_param, &param, COMPAT_US_TO_K);
++        }
++        else
++#endif
++            if (copy_from_user(&param, (void *)arg, sizeof(param)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++        if (FM_VSP_ConfigPoolDepletion(param.p_fm_vsp,
++                    (t_FmBufPoolDepletion *)&param.fm_buf_pool_depletion))
++            RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++        break;
++    }
++
++
++#if defined(CONFIG_COMPAT)
++    case FM_IOC_VSP_CONFIG_BUFFER_PREFIX_CONTENT_COMPAT:
++#endif
++    case FM_IOC_VSP_CONFIG_BUFFER_PREFIX_CONTENT:
++    {
++        ioc_fm_buffer_prefix_content_params_t param;
++
++#if defined(CONFIG_COMPAT)
++        if (compat)
++        {
++            ioc_compat_fm_buffer_prefix_content_params_t compat_param;
++
++            if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++            compat_copy_fm_buffer_prefix_content_params(&compat_param, &param, COMPAT_US_TO_K);
++        }
++        else
++#endif
++            if (copy_from_user(&param, (void *)arg, sizeof(param)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++        if (FM_VSP_ConfigBufferPrefixContent(param.p_fm_vsp,
++                (t_FmBufferPrefixContent *)&param.fm_buffer_prefix_content))
++            RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++        break;
++    }
++
++#if defined(CONFIG_COMPAT)
++    case FM_IOC_VSP_CONFIG_NO_SG_COMPAT:
++#endif
++    case FM_IOC_VSP_CONFIG_NO_SG:
++    {
++        ioc_fm_vsp_config_no_sg_params_t param;
++
++#if defined(CONFIG_COMPAT)
++        if (compat)
++        {
++            ioc_compat_fm_vsp_config_no_sg_params_t compat_param;
++
++            if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++            compat_copy_fm_vsp_config_no_sg_params(&compat_param, &param, COMPAT_US_TO_K);
++        }
++        else
++#endif
++            if (copy_from_user(&param, (void *)arg, sizeof(param)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++        if (FM_VSP_ConfigNoScatherGather(param.p_fm_vsp, param.no_sg))
++            RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++        break;
++    }
++
++#if defined(CONFIG_COMPAT)
++    case FM_IOC_VSP_GET_BUFFER_PRS_RESULT_COMPAT:
++#endif
++    case FM_IOC_VSP_GET_BUFFER_PRS_RESULT:
++    {
++        ioc_fm_vsp_prs_result_params_t param;
++
++#if defined(CONFIG_COMPAT)
++        if (compat)
++        {
++            ioc_compat_fm_vsp_prs_result_params_t compat_param;
++
++            if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++            compat_copy_fm_vsp_prs_result_params(&compat_param, &param, COMPAT_US_TO_K);
++        }
++        else
++#endif
++            if (copy_from_user(&param, (void *)arg, sizeof(param)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++        /* this call just adds the parse results offset to p_data */
++        param.p_data = FM_VSP_GetBufferPrsResult(param.p_fm_vsp, param.p_data);
++
++        if (!param.p_data)
++            RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++#if defined(CONFIG_COMPAT)
++        if (compat)
++        {
++            ioc_compat_fm_vsp_prs_result_params_t compat_param;
++
++            memset(&compat_param, 0, sizeof(compat_param));
++            compat_copy_fm_vsp_prs_result_params(&compat_param, &param, COMPAT_K_TO_US);
++
++            if (copy_to_user(compat_ptr(arg), &compat_param, sizeof(compat_param)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++        }
++        else
++#endif
++            if (copy_to_user((void *)arg, &param, sizeof(param)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++        break;
++    }
++#endif /* (DPAA_VERSION >= 11) */
++
++#ifdef FM_CAPWAP_SUPPORT
++#warning "feature not supported!"
++#if defined(CONFIG_COMPAT)
++        case FM_PCD_IOC_STATISTICS_SET_NODE_COMPAT:
++#endif
++        case FM_PCD_IOC_STATISTICS_SET_NODE:
++        {
++/*          ioc_fm_pcd_stats_params_t param;
++            ...
++            param->id = FM_PCD_StatisticsSetNode(p_LnxWrpFmDev->h_PcdDev,
++                                (t_FmPcdStatsParams *)&param);
++*/
++            err = E_NOT_SUPPORTED;
++            break;
++        }
++#endif /* FM_CAPWAP_SUPPORT */
++
++        default:
++            RETURN_ERROR(MINOR, E_INVALID_SELECTION,
++                ("invalid ioctl: cmd:0x%08x(type:0x%02x, nr: %d.\n",
++                cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)));
++    }
++
++    if (err)
++        RETURN_ERROR(MINOR, err, ("IOCTL FM PCD"));
++
++    return E_OK;
++}
++
++void FM_Get_Api_Version(ioc_fm_api_version_t *p_version)
++{
++      p_version->version.major = FMD_API_VERSION_MAJOR;
++      p_version->version.minor = FMD_API_VERSION_MINOR;
++      p_version->version.respin = FMD_API_VERSION_RESPIN;
++      p_version->version.reserved = 0;
++}
++
++t_Error LnxwrpFmIOCTL(t_LnxWrpFmDev *p_LnxWrpFmDev, unsigned int cmd, unsigned long arg, bool compat)
++{
++    t_Error err = E_OK;
++
++    switch (cmd)
++    {
++        case FM_IOC_SET_PORTS_BANDWIDTH:
++        {
++            ioc_fm_port_bandwidth_params *param;
++
++            param = (ioc_fm_port_bandwidth_params*) XX_Malloc(sizeof(ioc_fm_port_bandwidth_params));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_port_bandwidth_params));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (copy_from_user(param, (ioc_fm_port_bandwidth_params*)compat_ptr(arg), sizeof(ioc_fm_port_bandwidth_params)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_port_bandwidth_params*)arg, sizeof(ioc_fm_port_bandwidth_params)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            err =  FM_SetPortsBandwidth(p_LnxWrpFmDev->h_Dev, (t_FmPortsBandwidthParams*) param);
++
++            XX_Free(param);
++            break;
++        }
++
++        case FM_IOC_GET_REVISION:
++        {
++            ioc_fm_revision_info_t *param;
++
++            param = (ioc_fm_revision_info_t *) XX_Malloc(sizeof(ioc_fm_revision_info_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            FM_GetRevision(p_LnxWrpFmDev->h_Dev, (t_FmRevisionInfo*)param);
++            /* This one never returns anything other than E_OK */
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (copy_to_user((ioc_fm_revision_info_t *)compat_ptr(arg),
++                            param,
++                            sizeof(ioc_fm_revision_info_t))){
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
++                 }
++            }
++            else
++#endif
++            {
++                if (copy_to_user((ioc_fm_revision_info_t *)arg,
++                            param,
++                            sizeof(ioc_fm_revision_info_t))){
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
++                }
++            }
++            XX_Free(param);
++            break;
++        }
++
++        case FM_IOC_SET_COUNTER:
++        {
++            ioc_fm_counters_params_t *param;
++
++            param = (ioc_fm_counters_params_t *) XX_Malloc(sizeof(ioc_fm_counters_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_counters_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (copy_from_user(param, (ioc_fm_counters_params_t *)compat_ptr(arg), sizeof(ioc_fm_counters_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_counters_params_t *)arg, sizeof(ioc_fm_counters_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            err = FM_ModifyCounter(p_LnxWrpFmDev->h_Dev, param->cnt, param->val);
++
++            XX_Free(param);
++            break;
++        }
++
++        case FM_IOC_GET_COUNTER:
++        {
++            ioc_fm_counters_params_t *param;
++
++            param = (ioc_fm_counters_params_t *) XX_Malloc(sizeof(ioc_fm_counters_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
++
++            memset(param, 0, sizeof(ioc_fm_counters_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (copy_from_user(param, (ioc_fm_counters_params_t *)compat_ptr(arg), sizeof(ioc_fm_counters_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_counters_params_t *)arg, sizeof(ioc_fm_counters_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            param->val = FM_GetCounter(p_LnxWrpFmDev->h_Dev, param->cnt);
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (copy_to_user((ioc_fm_counters_params_t *)compat_ptr(arg), param, sizeof(ioc_fm_counters_params_t)))
++                    err = E_READ_FAILED;
++            }
++            else
++#endif
++            {
++                if (copy_to_user((ioc_fm_counters_params_t *)arg, param, sizeof(ioc_fm_counters_params_t)))
++                    err = E_READ_FAILED;
++            }
++
++            XX_Free(param);
++            break;
++        }
++
++        case FM_IOC_FORCE_INTR:
++        {
++            ioc_fm_exceptions param;
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (get_user(param, (ioc_fm_exceptions*) compat_ptr(arg)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++            else
++#endif
++            {
++                if (get_user(param, (ioc_fm_exceptions*)arg))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            err = FM_ForceIntr(p_LnxWrpFmDev->h_Dev, (e_FmExceptions)param);
++            break;
++        }
++
++      case FM_IOC_GET_API_VERSION:
++      {
++              ioc_fm_api_version_t version;
++
++              FM_Get_Api_Version(&version);
++
++#if defined(CONFIG_COMPAT)
++              if (compat)
++              {
++                      if (copy_to_user(
++                              (ioc_fm_api_version_t *)compat_ptr(arg),
++                              &version, sizeof(version)))
++                              err = E_READ_FAILED;
++              }
++              else
++#endif
++              {
++                      if (copy_to_user((ioc_fm_api_version_t *)arg,
++                              &version, sizeof(version)))
++                              err = E_READ_FAILED;
++              }
++      }
++      break;
++
++        case FM_IOC_CTRL_MON_START:
++        {
++            FM_CtrlMonStart(p_LnxWrpFmDev->h_Dev);
++        }
++        break;
++
++        case FM_IOC_CTRL_MON_STOP:
++        {
++            FM_CtrlMonStop(p_LnxWrpFmDev->h_Dev);
++        }
++        break;
++
++#if defined(CONFIG_COMPAT)
++        case FM_IOC_CTRL_MON_GET_COUNTERS_COMPAT:
++#endif
++        case FM_IOC_CTRL_MON_GET_COUNTERS:
++        {
++            ioc_fm_ctrl_mon_counters_params_t param;
++            t_FmCtrlMon mon;
++
++#if defined(CONFIG_COMPAT)
++            ioc_compat_fm_ctrl_mon_counters_params_t compat_param;
++
++            if (compat)
++            {
++                if (copy_from_user(&compat_param, (void *)compat_ptr(arg),
++                            sizeof(compat_param)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++                param.fm_ctrl_index = compat_param.fm_ctrl_index;
++                param.p_mon = (fm_ctrl_mon_t *)compat_ptr(compat_param.p_mon);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(&param, (void *)arg, sizeof(ioc_fm_ctrl_mon_counters_params_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            if (FM_CtrlMonGetCounters(p_LnxWrpFmDev->h_Dev, param.fm_ctrl_index, &mon))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++            if (copy_to_user(param.p_mon, &mon, sizeof(t_FmCtrlMon)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++        }
++        break;
++
++        default:
++            return LnxwrpFmPcdIOCTL(p_LnxWrpFmDev, cmd, arg, compat);
++    }
++
++    if (err)
++        RETURN_ERROR(MINOR, E_INVALID_OPERATION, ("IOCTL FM"));
++
++    return E_OK;
++}
++
++t_Error LnxwrpFmPortIOCTL(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev, unsigned int cmd, unsigned long arg, bool compat)
++{
++    t_Error err = E_OK;
++
++    _fm_ioctl_dbg("cmd:0x%08x(type:0x%02x, nr:%u).\n",
++        cmd, _IOC_TYPE(cmd), _IOC_NR(cmd) - 70);
++
++    switch (cmd)
++    {
++        case FM_PORT_IOC_DISABLE:
++            FM_PORT_Disable(p_LnxWrpFmPortDev->h_Dev);
++            /* deliberately ignoring error codes here */
++            return E_OK;
++
++        case FM_PORT_IOC_ENABLE:
++            FM_PORT_Enable(p_LnxWrpFmPortDev->h_Dev);
++            /* deliberately ignoring error codes here */
++            return E_OK;
++
++        case FM_PORT_IOC_SET_ERRORS_ROUTE:
++        {
++            ioc_fm_port_frame_err_select_t errs;
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (get_user(errs, (ioc_fm_port_frame_err_select_t*)compat_ptr(arg)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++            else
++#endif
++            {
++                if (get_user(errs, (ioc_fm_port_frame_err_select_t*)arg))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            err = FM_PORT_SetErrorsRoute(p_LnxWrpFmPortDev->h_Dev, (fmPortFrameErrSelect_t)errs);
++            break;
++        }
++
++        case FM_PORT_IOC_SET_RATE_LIMIT:
++        {
++            ioc_fm_port_rate_limit_t *param;
++
++            param = (ioc_fm_port_rate_limit_t *) XX_Malloc(sizeof(ioc_fm_port_rate_limit_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
++
++            memset(param, 0, sizeof(ioc_fm_port_rate_limit_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (copy_from_user(param, (ioc_fm_port_rate_limit_t *)compat_ptr(arg), sizeof(ioc_fm_port_rate_limit_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_port_rate_limit_t *)arg, sizeof(ioc_fm_port_rate_limit_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            err =  FM_PORT_SetRateLimit(p_LnxWrpFmPortDev->h_Dev, (t_FmPortRateLimit *)param);
++
++            XX_Free(param);
++            break;
++        }
++
++        case FM_PORT_IOC_REMOVE_RATE_LIMIT:
++            FM_PORT_DeleteRateLimit(p_LnxWrpFmPortDev->h_Dev);
++            /* deliberately ignoring error codes here */
++            return E_OK;
++
++        case FM_PORT_IOC_ALLOC_PCD_FQIDS:
++        {
++            ioc_fm_port_pcd_fqids_params_t *param;
++
++            if (!p_LnxWrpFmPortDev->pcd_owner_params.cba)
++                RETURN_ERROR(MINOR, E_INVALID_STATE, ("No one to listen on this PCD!!!"));
++
++            param = (ioc_fm_port_pcd_fqids_params_t *) XX_Malloc(sizeof(ioc_fm_port_pcd_fqids_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
++
++            memset(param, 0, sizeof(ioc_fm_port_pcd_fqids_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (copy_from_user(param, (ioc_fm_port_pcd_fqids_params_t *)compat_ptr(arg),
++                                    sizeof(ioc_fm_port_pcd_fqids_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_port_pcd_fqids_params_t *)arg,
++                                    sizeof(ioc_fm_port_pcd_fqids_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            if (p_LnxWrpFmPortDev->pcd_owner_params.cba(p_LnxWrpFmPortDev->pcd_owner_params.dev,
++                                                        param->num_fqids,
++                                                        param->alignment,
++                                                        &param->base_fqid))
++            {
++                XX_Free(param);
++                RETURN_ERROR(MINOR, E_INVALID_STATE, ("can't allocate fqids for PCD!!!"));
++            }
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (copy_to_user((ioc_fm_port_pcd_fqids_params_t *)compat_ptr(arg),
++                                  param, sizeof(ioc_fm_port_pcd_fqids_params_t)))
++                    err = E_READ_FAILED;
++            }
++            else
++#endif
++            {
++                if (copy_to_user((ioc_fm_port_pcd_fqids_params_t *)arg,
++                                  param, sizeof(ioc_fm_port_pcd_fqids_params_t)))
++                    err = E_READ_FAILED;
++            }
++
++            XX_Free(param);
++            break;
++        }
++
++        case FM_PORT_IOC_FREE_PCD_FQIDS:
++        {
++            uint32_t base_fqid;
++
++            if (!p_LnxWrpFmPortDev->pcd_owner_params.cbf)
++                RETURN_ERROR(MINOR, E_INVALID_STATE, ("No one to listen on this PCD!!!"));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (get_user(base_fqid, (uint32_t*) compat_ptr(arg)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++            else
++#endif
++            {
++                if (get_user(base_fqid, (uint32_t*)arg))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            if (p_LnxWrpFmPortDev->pcd_owner_params.cbf(p_LnxWrpFmPortDev->pcd_owner_params.dev, base_fqid))
++               err = E_WRITE_FAILED;
++
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PORT_IOC_SET_PCD_COMPAT:
++#endif
++        case FM_PORT_IOC_SET_PCD:
++        {
++            ioc_fm_port_pcd_params_t      *port_pcd_params;
++            ioc_fm_port_pcd_prs_params_t  *port_pcd_prs_params;
++            ioc_fm_port_pcd_cc_params_t   *port_pcd_cc_params;
++            ioc_fm_port_pcd_kg_params_t   *port_pcd_kg_params;
++            ioc_fm_port_pcd_plcr_params_t *port_pcd_plcr_params;
++
++            port_pcd_params = (ioc_fm_port_pcd_params_t *) XX_Malloc(
++                    sizeof(ioc_fm_port_pcd_params_t) +
++                    sizeof(ioc_fm_port_pcd_prs_params_t) +
++                    sizeof(ioc_fm_port_pcd_cc_params_t) +
++                    sizeof(ioc_fm_port_pcd_kg_params_t) +
++                    sizeof(ioc_fm_port_pcd_plcr_params_t));
++            if (!port_pcd_params)
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
++
++            memset(port_pcd_params, 0,
++                    sizeof(ioc_fm_port_pcd_params_t) +
++                    sizeof(ioc_fm_port_pcd_prs_params_t) +
++                    sizeof(ioc_fm_port_pcd_cc_params_t) +
++                    sizeof(ioc_fm_port_pcd_kg_params_t) +
++                    sizeof(ioc_fm_port_pcd_plcr_params_t));
++
++            port_pcd_prs_params  = (ioc_fm_port_pcd_prs_params_t *)  (port_pcd_params + 1);
++            port_pcd_cc_params   = (ioc_fm_port_pcd_cc_params_t *)   (port_pcd_prs_params + 1);
++            port_pcd_kg_params   = (ioc_fm_port_pcd_kg_params_t *)   (port_pcd_cc_params + 1);
++            port_pcd_plcr_params = (ioc_fm_port_pcd_plcr_params_t *) (port_pcd_kg_params + 1);
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_port_pcd_params_t      *compat_port_pcd_params;
++                ioc_fm_port_pcd_prs_params_t         *same_port_pcd_prs_params;
++                ioc_compat_fm_port_pcd_cc_params_t   *compat_port_pcd_cc_params;
++                ioc_compat_fm_port_pcd_kg_params_t   *compat_port_pcd_kg_params;
++                ioc_compat_fm_port_pcd_plcr_params_t *compat_port_pcd_plcr_params;
++
++                compat_port_pcd_params = (ioc_compat_fm_port_pcd_params_t *) XX_Malloc(
++                                sizeof(ioc_compat_fm_port_pcd_params_t) +
++                                sizeof(ioc_fm_port_pcd_prs_params_t) +
++                                sizeof(ioc_compat_fm_port_pcd_cc_params_t) +
++                                sizeof(ioc_compat_fm_port_pcd_kg_params_t) +
++                                sizeof(ioc_compat_fm_port_pcd_plcr_params_t));
++                if (!compat_port_pcd_params)
++                {
++                    XX_Free(port_pcd_params);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
++                }
++
++                memset(compat_port_pcd_params, 0,
++                        sizeof(ioc_compat_fm_port_pcd_params_t) +
++                        sizeof(ioc_fm_port_pcd_prs_params_t) +
++                        sizeof(ioc_compat_fm_port_pcd_cc_params_t) +
++                        sizeof(ioc_compat_fm_port_pcd_kg_params_t) +
++                        sizeof(ioc_compat_fm_port_pcd_plcr_params_t));
++                same_port_pcd_prs_params    = (ioc_fm_port_pcd_prs_params_t *) (compat_port_pcd_params + 1);
++                compat_port_pcd_cc_params   = (ioc_compat_fm_port_pcd_cc_params_t *) (same_port_pcd_prs_params + 1);
++                compat_port_pcd_kg_params   = (ioc_compat_fm_port_pcd_kg_params_t *) (compat_port_pcd_cc_params + 1);
++                compat_port_pcd_plcr_params = (ioc_compat_fm_port_pcd_plcr_params_t *) (compat_port_pcd_kg_params + 1);
++
++                if (copy_from_user(compat_port_pcd_params,
++                            (ioc_compat_fm_port_pcd_params_t*) compat_ptr(arg),
++                            sizeof(ioc_compat_fm_port_pcd_params_t)))
++                    err = E_WRITE_FAILED;
++
++                while (!err) /* pseudo-while */
++                {
++                    /* set pointers from where to copy from: */
++                    port_pcd_params->p_prs_params          = compat_ptr(compat_port_pcd_params->p_prs_params); /* same structure */
++                    port_pcd_params->p_cc_params           = compat_ptr(compat_port_pcd_params->p_cc_params);
++                    port_pcd_params->p_kg_params           = compat_ptr(compat_port_pcd_params->p_kg_params);
++                    port_pcd_params->p_plcr_params         = compat_ptr(compat_port_pcd_params->p_plcr_params);
++                    port_pcd_params->p_ip_reassembly_manip = compat_ptr(compat_port_pcd_params->p_ip_reassembly_manip);
++#if (DPAA_VERSION >= 11)
++                    port_pcd_params->p_capwap_reassembly_manip = compat_ptr(compat_port_pcd_params->p_capwap_reassembly_manip);
++#endif
++                    /* the prs member is the same, no compat structure...memcpy only */
++                    if (port_pcd_params->p_prs_params)
++                    {
++                        if (copy_from_user(same_port_pcd_prs_params,
++                                port_pcd_params->p_prs_params,
++                                sizeof(ioc_fm_port_pcd_prs_params_t)))
++                        {
++                            err = E_WRITE_FAILED;
++                            break; /* from pseudo-while */
++                        }
++
++                        memcpy(port_pcd_prs_params, same_port_pcd_prs_params, sizeof(ioc_fm_port_pcd_prs_params_t));
++                        port_pcd_params->p_prs_params = port_pcd_prs_params;
++                    }
++
++                    if (port_pcd_params->p_cc_params)
++                    {
++                        if (copy_from_user(compat_port_pcd_cc_params,
++                                port_pcd_params->p_cc_params,
++                                sizeof(ioc_compat_fm_port_pcd_cc_params_t)))
++                        {
++                            err = E_WRITE_FAILED;
++                            break; /* from pseudo-while */
++                        }
++
++                        port_pcd_params->p_cc_params = port_pcd_cc_params;
++                    }
++
++                    if (port_pcd_params->p_kg_params)
++                    {
++                        if (copy_from_user(compat_port_pcd_kg_params,
++                                port_pcd_params->p_kg_params,
++                                sizeof(ioc_compat_fm_port_pcd_kg_params_t)))
++                        {
++                            err = E_WRITE_FAILED;
++                            break; /* from pseudo-while */
++                        }
++
++                        port_pcd_params->p_kg_params = port_pcd_kg_params;
++                    }
++
++                    if (port_pcd_params->p_plcr_params)
++                    {
++                        if (copy_from_user(compat_port_pcd_plcr_params,
++                                    port_pcd_params->p_plcr_params,
++                                    sizeof(ioc_compat_fm_port_pcd_plcr_params_t)))
++                        {
++                            err = E_WRITE_FAILED;
++                            break; /* from pseudo-while */
++                        }
++
++                        port_pcd_params->p_plcr_params = port_pcd_plcr_params;
++                    }
++
++                    break; /* pseudo-while: always run once! */
++                }
++
++                if (!err)
++                    compat_copy_fm_port_pcd(compat_port_pcd_params, port_pcd_params, COMPAT_US_TO_K);
++
++                XX_Free(compat_port_pcd_params);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(port_pcd_params,
++                            (ioc_fm_port_pcd_params_t*) arg,
++                            sizeof(ioc_fm_port_pcd_params_t)))
++                    err = E_WRITE_FAILED;
++
++                while (!err) /* pseudo-while */
++                {
++                    if (port_pcd_params->p_prs_params)
++                    {
++                        if (copy_from_user(port_pcd_prs_params,
++                                port_pcd_params->p_prs_params,
++                                sizeof(ioc_fm_port_pcd_prs_params_t)))
++                        {
++                            err = E_WRITE_FAILED;
++                            break; /* from pseudo-while */
++                        }
++
++                        port_pcd_params->p_prs_params = port_pcd_prs_params;
++                    }
++
++                    if (port_pcd_params->p_cc_params)
++                    {
++                        if (copy_from_user(port_pcd_cc_params,
++                                port_pcd_params->p_cc_params,
++                                sizeof(ioc_fm_port_pcd_cc_params_t)))
++                        {
++                            err = E_WRITE_FAILED;
++                            break; /* from pseudo-while */
++                        }
++
++                        port_pcd_params->p_cc_params = port_pcd_cc_params;
++                    }
++
++                    if (port_pcd_params->p_kg_params)
++                    {
++                        if (copy_from_user(port_pcd_kg_params,
++                                port_pcd_params->p_kg_params,
++                                sizeof(ioc_fm_port_pcd_kg_params_t)))
++                        {
++                            err = E_WRITE_FAILED;
++                            break; /* from pseudo-while */
++                        }
++
++                        port_pcd_params->p_kg_params = port_pcd_kg_params;
++                    }
++
++                    if (port_pcd_params->p_plcr_params)
++                    {
++                        if (copy_from_user(port_pcd_plcr_params,
++                                port_pcd_params->p_plcr_params,
++                                sizeof(ioc_fm_port_pcd_plcr_params_t)))
++                        {
++                            err = E_WRITE_FAILED;
++                            break; /* from pseudo-while */
++                        }
++
++                        port_pcd_params->p_plcr_params = port_pcd_plcr_params;
++                    }
++
++                    break; /* pseudo-while: always run once! */
++                }
++            }
++
++            if (!err)
++                err = FM_PORT_SetPCD(p_LnxWrpFmPortDev->h_Dev, (t_FmPortPcdParams*) port_pcd_params);
++
++            XX_Free(port_pcd_params);
++            break;
++        }
++
++        case FM_PORT_IOC_DELETE_PCD:
++            err = FM_PORT_DeletePCD(p_LnxWrpFmPortDev->h_Dev);
++            break;
++
++#if defined(CONFIG_COMPAT)
++        case FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME_COMPAT:
++#endif
++        case FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME:
++        {
++            ioc_fm_pcd_kg_scheme_select_t *param;
++
++            param = (ioc_fm_pcd_kg_scheme_select_t *) XX_Malloc(
++                    sizeof(ioc_fm_pcd_kg_scheme_select_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
++
++            memset(param, 0, sizeof(ioc_fm_pcd_kg_scheme_select_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_kg_scheme_select_t *compat_param;
++
++                compat_param = (ioc_compat_fm_pcd_kg_scheme_select_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_pcd_kg_scheme_select_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_select_t));
++                if (copy_from_user(compat_param,
++                                   (ioc_compat_fm_pcd_kg_scheme_select_t *) compat_ptr(arg),
++                                   sizeof(ioc_compat_fm_pcd_kg_scheme_select_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_kg_scheme_select(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_kg_scheme_select_t *)arg,
++                                   sizeof(ioc_fm_pcd_kg_scheme_select_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            err =  FM_PORT_PcdKgModifyInitialScheme(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdKgSchemeSelect *)param);
++
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE_COMPAT:
++#endif
++        case FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE:
++        {
++            ioc_fm_obj_t id;
++
++            memset(&id, 0 , sizeof(ioc_fm_obj_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_obj_t compat_id;
++
++                if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++                id.obj = compat_ptr(compat_id.obj);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            err = FM_PORT_PcdPlcrModifyInitialProfile(p_LnxWrpFmPortDev->h_Dev, id.obj);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PORT_IOC_PCD_KG_BIND_SCHEMES_COMPAT:
++#endif
++        case FM_PORT_IOC_PCD_KG_BIND_SCHEMES:
++        {
++            ioc_fm_pcd_port_schemes_params_t *param;
++
++            param = (ioc_fm_pcd_port_schemes_params_t *) XX_Malloc(
++                    sizeof(ioc_fm_pcd_port_schemes_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
++
++            memset(param, 0 , sizeof(ioc_fm_pcd_port_schemes_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_port_schemes_params_t compat_param;
++
++                if (copy_from_user(&compat_param,
++                            (ioc_compat_fm_pcd_port_schemes_params_t *) compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_port_schemes_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_kg_schemes_params(&compat_param, param, COMPAT_US_TO_K);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_port_schemes_params_t *) arg,
++                            sizeof(ioc_fm_pcd_port_schemes_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            err = FM_PORT_PcdKgBindSchemes(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdPortSchemesParams *)param);
++
++            XX_Free(param);
++            break;
++        }
++
++#if defined(CONFIG_COMPAT)
++        case FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES_COMPAT:
++#endif
++        case FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES:
++        {
++            ioc_fm_pcd_port_schemes_params_t *param;
++
++            param = (ioc_fm_pcd_port_schemes_params_t *) XX_Malloc(
++                    sizeof(ioc_fm_pcd_port_schemes_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
++
++            memset(param, 0 , sizeof(ioc_fm_pcd_port_schemes_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_pcd_port_schemes_params_t compat_param;
++
++                if (copy_from_user(&compat_param,
++                            (ioc_compat_fm_pcd_port_schemes_params_t *) compat_ptr(arg),
++                            sizeof(ioc_compat_fm_pcd_port_schemes_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_pcd_kg_schemes_params(&compat_param, param, COMPAT_US_TO_K);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_pcd_port_schemes_params_t *) arg,
++                            sizeof(ioc_fm_pcd_port_schemes_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            err =  FM_PORT_PcdKgUnbindSchemes(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdPortSchemesParams *)param);
++
++            XX_Free(param);
++            break;
++        }
++
++        case FM_PORT_IOC_PCD_PLCR_ALLOC_PROFILES:
++        {
++            uint16_t num;
++            if (get_user(num, (uint16_t*) arg))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++            err = FM_PORT_PcdPlcrAllocProfiles(p_LnxWrpFmPortDev->h_Dev, num);
++            break;
++        }
++
++        case FM_PORT_IOC_PCD_PLCR_FREE_PROFILES:
++            err = FM_PORT_PcdPlcrFreeProfiles(p_LnxWrpFmPortDev->h_Dev);
++            break;
++
++        case FM_PORT_IOC_DETACH_PCD:
++            err = FM_PORT_DetachPCD(p_LnxWrpFmPortDev->h_Dev);
++            break;
++
++        case FM_PORT_IOC_ATTACH_PCD:
++            err = FM_PORT_AttachPCD(p_LnxWrpFmPortDev->h_Dev);
++            break;
++
++#if defined(CONFIG_COMPAT)
++        case FM_PORT_IOC_PCD_CC_MODIFY_TREE_COMPAT:
++#endif
++        case FM_PORT_IOC_PCD_CC_MODIFY_TREE:
++        {
++            ioc_fm_obj_t id;
++
++            memset(&id, 0 , sizeof(ioc_fm_obj_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_obj_t compat_id;
++
++                if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++                compat_copy_fm_port_pcd_modify_tree(&compat_id, &id, COMPAT_US_TO_K);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            err = FM_PORT_PcdCcModifyTree(p_LnxWrpFmPortDev->h_Dev, id.obj);
++            break;
++        }
++
++        case FM_PORT_IOC_ADD_CONGESTION_GRPS:
++        case FM_PORT_IOC_REMOVE_CONGESTION_GRPS:
++        {
++            ioc_fm_port_congestion_groups_t *param;
++
++            param = (ioc_fm_port_congestion_groups_t*) XX_Malloc(sizeof(ioc_fm_port_congestion_groups_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
++
++            memset(param, 0, sizeof(ioc_fm_port_congestion_groups_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (copy_from_user(param, (t_FmPortCongestionGrps*) compat_ptr(arg),
++                            sizeof(t_FmPortCongestionGrps)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++            else
++#endif /* CONFIG_COMPAT */
++            {
++                if (copy_from_user(param, (t_FmPortCongestionGrps*) arg,
++                            sizeof(t_FmPortCongestionGrps)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            err = (cmd == FM_PORT_IOC_ADD_CONGESTION_GRPS)
++                ? FM_PORT_AddCongestionGrps(p_LnxWrpFmPortDev->h_Dev, (t_FmPortCongestionGrps*) param)
++                : FM_PORT_RemoveCongestionGrps(p_LnxWrpFmPortDev->h_Dev, (t_FmPortCongestionGrps*) param)
++                ;
++
++            XX_Free(param);
++            break;
++        }
++
++        case FM_PORT_IOC_ADD_RX_HASH_MAC_ADDR:
++        case FM_PORT_IOC_REMOVE_RX_HASH_MAC_ADDR:
++        {
++            ioc_fm_port_mac_addr_params_t *param;
++
++            param = (ioc_fm_port_mac_addr_params_t*) XX_Malloc(
++                    sizeof(ioc_fm_port_mac_addr_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
++
++            memset(param, 0, sizeof(ioc_fm_port_mac_addr_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                if (copy_from_user(param, (ioc_fm_port_mac_addr_params_t*) compat_ptr(arg),
++                            sizeof(ioc_fm_port_mac_addr_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++            else
++#endif /* CONFIG_COMPAT */
++            {
++                if (copy_from_user(param, (ioc_fm_port_mac_addr_params_t*) arg,
++                            sizeof(ioc_fm_port_mac_addr_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            if (p_LnxWrpFmPortDev->pcd_owner_params.dev)
++            {
++                int id = -1;
++
++                switch(p_LnxWrpFmPortDev->settings.param.portType)
++                {
++                    case e_FM_PORT_TYPE_RX:
++                    case e_FM_PORT_TYPE_TX:
++                        id = p_LnxWrpFmPortDev->id;
++                    break;
++                    case e_FM_PORT_TYPE_RX_10G:
++                    case e_FM_PORT_TYPE_TX_10G:
++                        id = p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_MACS;
++                    break;
++                    default:
++                        err = E_NOT_AVAILABLE;
++                        REPORT_ERROR(MINOR, err, ("Attempt to add/remove hash MAC addr. to/from MAC-less port!"));
++                }
++                if (id >= 0)
++                {
++                    t_LnxWrpFmDev *fm = (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev;
++                    t_Handle mac_handle = fm->macs[id].h_Dev;
++
++                    err = (cmd == FM_PORT_IOC_ADD_RX_HASH_MAC_ADDR)
++                        ? FM_MAC_AddHashMacAddr(mac_handle, (t_EnetAddr*) param)
++                        : FM_MAC_RemoveHashMacAddr(mac_handle, (t_EnetAddr*) param);
++                }
++            }
++            else
++            {
++                err = E_NOT_AVAILABLE;
++                REPORT_ERROR(MINOR, err, ("Port not initialized or other error!?!?"));
++            }
++
++            XX_Free(param);
++            break;
++        }
++
++        case FM_PORT_IOC_SET_TX_PAUSE_FRAMES:
++        {
++            t_LnxWrpFmDev *p_LnxWrpFmDev =
++                    (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev;
++            ioc_fm_port_tx_pause_frames_params_t param;
++            int mac_id = p_LnxWrpFmPortDev->id;
++
++            if(&p_LnxWrpFmDev->txPorts[mac_id] != p_LnxWrpFmPortDev)
++                mac_id += FM_MAX_NUM_OF_1G_MACS; /* 10G port */
++
++            if (copy_from_user(&param, (ioc_fm_port_tx_pause_frames_params_t *)arg,
++                        sizeof(ioc_fm_port_tx_pause_frames_params_t)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++            if (p_LnxWrpFmDev && p_LnxWrpFmDev->macs[mac_id].h_Dev)
++            {
++                FM_MAC_SetTxPauseFrames(p_LnxWrpFmDev->macs[mac_id].h_Dev,
++                        param.priority,
++                        param.pause_time,
++                        param.thresh_time);
++            }
++            else
++            {
++                err = E_NOT_AVAILABLE;
++                REPORT_ERROR(MINOR, err, ("Port not initialized or other error!"));
++            }
++
++            break;
++        }
++
++        case FM_PORT_IOC_CONFIG_BUFFER_PREFIX_CONTENT:
++        {
++            ioc_fm_buffer_prefix_content_t *param;
++
++            param = (ioc_fm_buffer_prefix_content_t*) XX_Malloc(sizeof(ioc_fm_buffer_prefix_content_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
++
++            memset(param, 0, sizeof(ioc_fm_buffer_prefix_content_t));
++
++            if (copy_from_user(param, (ioc_fm_buffer_prefix_content_t*) arg,
++                        sizeof(ioc_fm_buffer_prefix_content_t)))
++            {
++                XX_Free(param);
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            if (FM_PORT_ConfigBufferPrefixContent(p_LnxWrpFmPortDev->h_Dev,
++                    (t_FmBufferPrefixContent *)param))
++            {
++                XX_Free(param);
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            XX_Free(param);
++            break;
++        }
++
++#if (DPAA_VERSION >= 11)
++#if defined(CONFIG_COMPAT)
++        case FM_PORT_IOC_VSP_ALLOC_COMPAT:
++#endif
++        case FM_PORT_IOC_VSP_ALLOC:
++        {
++            ioc_fm_port_vsp_alloc_params_t *param;
++            t_LnxWrpFmDev *p_LnxWrpFmDev;
++            t_LnxWrpFmPortDev *p_LnxWrpFmTxPortDev;
++
++            param = (ioc_fm_port_vsp_alloc_params_t *) XX_Malloc(
++                    sizeof(ioc_fm_port_vsp_alloc_params_t));
++            if (!param)
++                RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
++
++            memset(param, 0, sizeof(ioc_fm_port_vsp_alloc_params_t));
++
++#if defined(CONFIG_COMPAT)
++            if (compat)
++            {
++                ioc_compat_fm_port_vsp_alloc_params_t *compat_param;
++
++                compat_param = (ioc_compat_fm_port_vsp_alloc_params_t *) XX_Malloc(
++                        sizeof(ioc_compat_fm_port_vsp_alloc_params_t));
++                if (!compat_param)
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
++                }
++
++                memset(compat_param, 0, sizeof(ioc_compat_fm_port_vsp_alloc_params_t));
++                if (copy_from_user(compat_param,
++                                   (ioc_compat_fm_port_vsp_alloc_params_t *) compat_ptr(arg),
++                                   sizeof(ioc_compat_fm_port_vsp_alloc_params_t)))
++                {
++                    XX_Free(compat_param);
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++
++                compat_copy_fm_port_vsp_alloc_params(compat_param, param, COMPAT_US_TO_K);
++
++                XX_Free(compat_param);
++            }
++            else
++#endif
++            {
++                if (copy_from_user(param, (ioc_fm_port_vsp_alloc_params_t *)arg,
++                                   sizeof(ioc_fm_port_vsp_alloc_params_t)))
++                {
++                    XX_Free(param);
++                    RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++                }
++            }
++
++            /* Userspace may not have the Tx port t_handle when issuing the IOCTL */
++            if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX ||
++                    p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX_10G)
++            {
++                /* Determine the Tx port t_Handle from the Rx port id */
++                p_LnxWrpFmDev = p_LnxWrpFmPortDev->h_LnxWrpFmDev;
++                p_LnxWrpFmTxPortDev = &p_LnxWrpFmDev->txPorts[p_LnxWrpFmPortDev->id];
++                param->p_fm_tx_port = p_LnxWrpFmTxPortDev->h_Dev;
++            }
++
++            if (FM_PORT_VSPAlloc(p_LnxWrpFmPortDev->h_Dev, (t_FmPortVSPAllocParams *)param))
++            {
++                XX_Free(param);
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++            }
++
++            XX_Free(param);
++            break;
++        }
++#endif /* (DPAA_VERSION >= 11) */
++
++        case FM_PORT_IOC_GET_MAC_STATISTICS:
++        {
++            t_LnxWrpFmDev *p_LnxWrpFmDev =
++                    (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev;
++            ioc_fm_port_mac_statistics_t param;
++            int mac_id = p_LnxWrpFmPortDev->id;
++
++            if (!p_LnxWrpFmDev)
++                RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Port not initialized or other error!"));
++
++            if (&p_LnxWrpFmDev->txPorts[mac_id] != p_LnxWrpFmPortDev &&
++                &p_LnxWrpFmDev->rxPorts[mac_id] != p_LnxWrpFmPortDev)
++                mac_id += FM_MAX_NUM_OF_1G_MACS; /* 10G port */
++
++            if (!p_LnxWrpFmDev->macs[mac_id].h_Dev)
++                RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Port not initialized or other error!"));
++
++            if (FM_MAC_GetStatistics(p_LnxWrpFmDev->macs[mac_id].h_Dev,
++                        (t_FmMacStatistics *)&param))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++            if (copy_to_user((ioc_fm_port_mac_statistics_t *)arg, &param,
++                        sizeof(ioc_fm_port_mac_statistics_t)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++            break;
++        }
++
++        case FM_PORT_IOC_GET_BMI_COUNTERS:
++        {
++            t_LnxWrpFmDev *p_LnxWrpFmDev =
++                    (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev;
++            ioc_fm_port_bmi_stats_t param;
++
++            if (!p_LnxWrpFmDev)
++                RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Port not initialized or other error!"));
++
++            if (FM_PORT_GetBmiCounters(p_LnxWrpFmPortDev->h_Dev,
++                        (t_FmPortBmiStats *)&param))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++            if (copy_to_user((ioc_fm_port_bmi_stats_t *)arg, &param,
++                        sizeof(ioc_fm_port_bmi_stats_t)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++            break;
++        }
++
++        default:
++            RETURN_ERROR(MINOR, E_INVALID_SELECTION,
++                ("invalid ioctl: cmd:0x%08x(type:0x%02x, nr:0x%02x.\n",
++                cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)));
++    }
++
++    if (err)
++        RETURN_ERROR(MINOR, E_INVALID_OPERATION, ("IOCTL FM PORT"));
++
++    return E_OK;
++}
++
++/*****************************************************************************/
++/*               API routines for the FM Linux Device                        */
++/*****************************************************************************/
++
++static int fm_open(struct inode *inode, struct file *file)
++{
++    t_LnxWrpFmDev       *p_LnxWrpFmDev = NULL;
++    t_LnxWrpFmPortDev   *p_LnxWrpFmPortDev = NULL;
++    unsigned int        major = imajor(inode);
++    unsigned int        minor = iminor(inode);
++    struct device_node  *fm_node;
++    static struct of_device_id fm_node_of_match[] = {
++        { .compatible = "fsl,fman", },
++        { /* end of list */ },
++    };
++
++    DBG(TRACE, ("Opening minor - %d - ", minor));
++
++    if (file->private_data != NULL)
++        return 0;
++
++    /* Get all the FM nodes */
++    for_each_matching_node(fm_node, fm_node_of_match) {
++        struct platform_device    *of_dev;
++
++        of_dev = of_find_device_by_node(fm_node);
++        if (unlikely(of_dev == NULL)) {
++            REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!"));
++            return -ENXIO;
++        }
++
++        p_LnxWrpFmDev = (t_LnxWrpFmDev *)fm_bind(&of_dev->dev);
++        if (p_LnxWrpFmDev->major == major)
++            break;
++        fm_unbind((struct fm *)p_LnxWrpFmDev);
++        p_LnxWrpFmDev = NULL;
++    }
++
++    if (!p_LnxWrpFmDev)
++        return -ENODEV;
++
++    if (minor == DEV_FM_MINOR_BASE)
++        file->private_data = p_LnxWrpFmDev;
++    else if (minor == DEV_FM_PCD_MINOR_BASE)
++        file->private_data = p_LnxWrpFmDev;
++    else {
++        if (minor == DEV_FM_OH_PORTS_MINOR_BASE)
++            p_LnxWrpFmPortDev = &p_LnxWrpFmDev->hcPort;
++        else if ((minor > DEV_FM_OH_PORTS_MINOR_BASE) && (minor < DEV_FM_RX_PORTS_MINOR_BASE))
++            p_LnxWrpFmPortDev = &p_LnxWrpFmDev->opPorts[minor-DEV_FM_OH_PORTS_MINOR_BASE-1];
++        else if ((minor >= DEV_FM_RX_PORTS_MINOR_BASE) && (minor < DEV_FM_TX_PORTS_MINOR_BASE))
++            p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[minor-DEV_FM_RX_PORTS_MINOR_BASE];
++        else if ((minor >= DEV_FM_TX_PORTS_MINOR_BASE) && (minor < DEV_FM_MAX_MINORS))
++            p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[minor-DEV_FM_TX_PORTS_MINOR_BASE];
++        else
++            return -EINVAL;
++
++        /* if trying to open port, check if it initialized */
++        if (!p_LnxWrpFmPortDev->h_Dev)
++            return -ENODEV;
++
++        p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)fm_port_bind(p_LnxWrpFmPortDev->dev);
++        file->private_data = p_LnxWrpFmPortDev;
++        fm_unbind((struct fm *)p_LnxWrpFmDev);
++    }
++
++    if (file->private_data == NULL)
++         return -ENXIO;
++
++    return 0;
++}
++
++static int fm_close(struct inode *inode, struct file *file)
++{
++    t_LnxWrpFmDev       *p_LnxWrpFmDev;
++    t_LnxWrpFmPortDev   *p_LnxWrpFmPortDev;
++    unsigned int        minor = iminor(inode);
++    int                 err = 0;
++
++    DBG(TRACE, ("Closing minor - %d - ", minor));
++
++    if ((minor == DEV_FM_MINOR_BASE) ||
++        (minor == DEV_FM_PCD_MINOR_BASE))
++    {
++        p_LnxWrpFmDev = (t_LnxWrpFmDev*)file->private_data;
++        if (!p_LnxWrpFmDev)
++            return -ENODEV;
++        fm_unbind((struct fm *)p_LnxWrpFmDev);
++    }
++    else if (((minor >= DEV_FM_OH_PORTS_MINOR_BASE) && (minor < DEV_FM_RX_PORTS_MINOR_BASE)) ||
++             ((minor >= DEV_FM_RX_PORTS_MINOR_BASE) && (minor < DEV_FM_TX_PORTS_MINOR_BASE)) ||
++             ((minor >= DEV_FM_TX_PORTS_MINOR_BASE) && (minor < DEV_FM_MAX_MINORS)))
++    {
++        p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)file->private_data;
++        if (!p_LnxWrpFmPortDev)
++            return -ENODEV;
++        fm_port_unbind((struct fm_port *)p_LnxWrpFmPortDev);
++    }
++
++    return err;
++}
++
++static int fm_ioctls(unsigned int minor, struct file *file, unsigned int cmd, unsigned long arg, bool compat)
++{
++    DBG(TRACE, ("IOCTL minor - %u, cmd - 0x%08x, arg - 0x%08lx \n", minor, cmd, arg));
++
++    if ((minor == DEV_FM_MINOR_BASE) ||
++        (minor == DEV_FM_PCD_MINOR_BASE))
++    {
++        t_LnxWrpFmDev *p_LnxWrpFmDev = ((t_LnxWrpFmDev*)file->private_data);
++        if (!p_LnxWrpFmDev)
++            return -ENODEV;
++        if (LnxwrpFmIOCTL(p_LnxWrpFmDev, cmd, arg, compat))
++            return -EFAULT;
++    }
++    else if (((minor >= DEV_FM_OH_PORTS_MINOR_BASE) && (minor < DEV_FM_RX_PORTS_MINOR_BASE)) ||
++             ((minor >= DEV_FM_RX_PORTS_MINOR_BASE) && (minor < DEV_FM_TX_PORTS_MINOR_BASE)) ||
++             ((minor >= DEV_FM_TX_PORTS_MINOR_BASE) && (minor < DEV_FM_MAX_MINORS)))
++    {
++        t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = ((t_LnxWrpFmPortDev*)file->private_data);
++        if (!p_LnxWrpFmPortDev)
++            return -ENODEV;
++        if (LnxwrpFmPortIOCTL(p_LnxWrpFmPortDev, cmd, arg, compat))
++            return -EFAULT;
++    }
++    else
++    {
++        REPORT_ERROR(MINOR, E_INVALID_VALUE, ("minor"));
++        return -ENODEV;
++    }
++
++    return 0;
++}
++
++#ifdef CONFIG_COMPAT
++static long fm_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++    unsigned int minor = iminor(file->f_path.dentry->d_inode);
++    long res;
++
++    fm_mutex_lock();
++    res = fm_ioctls(minor, file, cmd, arg, true);
++    fm_mutex_unlock();
++
++    return res;
++}
++#endif
++
++static long fm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++    unsigned int minor = iminor(file->f_path.dentry->d_inode);
++    long res;
++
++    fm_mutex_lock();
++    res = fm_ioctls(minor, file, cmd, arg, false);
++    fm_mutex_unlock();
++
++    return res;
++}
++
++/* Globals for FM character device */
++struct file_operations fm_fops =
++{
++    .owner =            THIS_MODULE,
++    .unlocked_ioctl =   fm_ioctl,
++#ifdef CONFIG_COMPAT
++    .compat_ioctl =     fm_compat_ioctl,
++#endif
++    .open =             fm_open,
++    .release =          fm_close,
++};
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c
+@@ -0,0 +1,1297 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ @File          lnxwrp_fm_compat_ioctls.c
++
++ @Description   FM PCD compat functions
++
++*/
++
++#if !defined(CONFIG_COMPAT)
++#error "missing COMPAT layer..."
++#endif
++
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/device.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <asm/uaccess.h>
++#include <asm/errno.h>
++#ifndef CONFIG_FMAN_ARM
++#include <sysdev/fsl_soc.h>
++#endif
++
++#include "part_ext.h"
++#include "fm_ioctls.h"
++#include "fm_pcd_ioctls.h"
++#include "fm_port_ioctls.h"
++#include "lnxwrp_ioctls_fm_compat.h"
++
++#if defined(FM_COMPAT_DBG)
++static void hex_dump(void * p_addr, unsigned int size)
++{
++   int i;
++
++   for(i=0; i<size; i+=16)
++   {
++       printk("%p: 0x%08x 0x%08x 0x%08x 0x%08x\n", p_addr + i,
++           *(unsigned int *)(p_addr + i),
++           *(unsigned int *)(p_addr + i + 4),
++           *(unsigned int *)(p_addr + i + 8),
++           *(unsigned int *)(p_addr + i +12)
++           );
++   }
++}
++#endif
++
++/* maping kernel pointers w/ UserSpace id's { */
++struct map_node {
++    void *ptr;
++    u8 node_type;
++};
++
++static struct map_node compat_ptr2id_array[COMPAT_PTR2ID_ARRAY_MAX] = {{NULL},{FM_MAP_TYPE_UNSPEC}};
++
++void compat_del_ptr2id(void *p, enum fm_map_node_type node_type)
++{
++    compat_uptr_t k;
++
++    _fm_cpt_dbg(COMPAT_GENERIC, "delete (%p)\n", p);
++
++    for(k=1; k < COMPAT_PTR2ID_ARRAY_MAX; k++)
++        if(compat_ptr2id_array[k].ptr == p){
++            compat_ptr2id_array[k].ptr = NULL;
++            compat_ptr2id_array[k].node_type = FM_MAP_TYPE_UNSPEC;
++        }
++}
++EXPORT_SYMBOL(compat_del_ptr2id);
++
++compat_uptr_t compat_add_ptr2id(void *p, enum fm_map_node_type node_type)
++{
++    compat_uptr_t k;
++
++    _fm_cpt_dbg(COMPAT_GENERIC, " (%p) do ->\n", p);
++
++    if(!p)
++        return 0;
++
++    for(k=1; k < COMPAT_PTR2ID_ARRAY_MAX; k++)
++        if(compat_ptr2id_array[k].ptr == NULL)
++        {
++            compat_ptr2id_array[k].ptr = p;
++            compat_ptr2id_array[k].node_type = node_type;
++            _fm_cpt_dbg(COMPAT_GENERIC, "0x%08x \n", k | COMPAT_PTR2ID_WATERMARK);
++            return k | COMPAT_PTR2ID_WATERMARK;
++        }
++
++    printk(KERN_WARNING "FMan map list full! No more PCD space on kernel!\n");
++    return 0;
++}
++EXPORT_SYMBOL(compat_add_ptr2id);
++
++compat_uptr_t compat_get_ptr2id(void *p, enum fm_map_node_type node_type)
++{
++    compat_uptr_t k;
++
++    _fm_cpt_dbg(COMPAT_GENERIC, " (%p) get -> \n", p);
++
++    for(k=1; k < COMPAT_PTR2ID_ARRAY_MAX; k++)
++        if(compat_ptr2id_array[k].ptr == p &&
++           compat_ptr2id_array[k].node_type == node_type) {
++
++            _fm_cpt_dbg(COMPAT_GENERIC, "0x%08x\n", k | COMPAT_PTR2ID_WATERMARK);
++            return k | COMPAT_PTR2ID_WATERMARK;
++        }
++
++    return 0;
++}
++EXPORT_SYMBOL(compat_get_ptr2id);
++
++void *compat_get_id2ptr(compat_uptr_t comp, enum fm_map_node_type node_type)
++{
++
++    _fm_cpt_dbg(COMPAT_GENERIC, " (0x%08x) get -> \n", comp);
++
++    if((COMPAT_PTR2ID_WM_MASK & comp) != COMPAT_PTR2ID_WATERMARK) {
++        _fm_cpt_dbg(COMPAT_GENERIC, "Error, invalid watermark (0x%08x)!\n\n", comp);
++        dump_stack();
++        return compat_ptr(comp);
++    }
++
++    comp &= ~COMPAT_PTR2ID_WM_MASK;
++
++    if(((0 < comp) && (comp < COMPAT_PTR2ID_ARRAY_MAX) && (compat_ptr2id_array[comp].ptr != NULL)
++                && compat_ptr2id_array[comp].node_type == node_type)) {
++        _fm_cpt_dbg(COMPAT_GENERIC, "%p\n", compat_ptr2id_array[comp].ptr);
++        return compat_ptr2id_array[comp].ptr;
++    }
++    return NULL;
++}
++EXPORT_SYMBOL(compat_get_id2ptr);
++/* } maping kernel pointers w/ UserSpace id's  */
++
++void compat_obj_delete(
++      ioc_compat_fm_obj_t *compat_id,
++      ioc_fm_obj_t *id)
++{
++      id->obj = compat_pcd_id2ptr(compat_id->obj);
++      compat_del_ptr2id(id->obj, FM_MAP_TYPE_PCD_NODE);
++}
++
++static inline void compat_copy_fm_pcd_plcr_next_engine(
++        ioc_compat_fm_pcd_plcr_next_engine_params_u *compat_param,
++        ioc_fm_pcd_plcr_next_engine_params_u        *param,
++        ioc_fm_pcd_engine                           next_engine,
++        uint8_t                                     compat)
++{
++    _fm_cpt_dbg (compat, " {->...\n");
++
++    switch (next_engine)
++    {
++        case e_IOC_FM_PCD_PLCR:
++            if (compat == COMPAT_US_TO_K)
++                param->p_profile = compat_pcd_id2ptr(compat_param->p_profile);
++            else
++                compat_param->p_profile = compat_pcd_ptr2id(param->p_profile);
++        break;
++        case e_IOC_FM_PCD_KG:
++            if (compat == COMPAT_US_TO_K)
++                param->p_direct_scheme = compat_pcd_id2ptr(compat_param->p_direct_scheme);
++            else
++                compat_param->p_direct_scheme = compat_pcd_ptr2id(param->p_direct_scheme);
++        break;
++        default:
++            if (compat == COMPAT_US_TO_K)
++                param->action = compat_param->action;
++            else
++                compat_param->action = param->action;
++        break;
++    }
++
++    _fm_cpt_dbg (compat, " ...->}\n");
++}
++
++void compat_copy_fm_pcd_plcr_profile(
++        ioc_compat_fm_pcd_plcr_profile_params_t *compat_param,
++        ioc_fm_pcd_plcr_profile_params_t        *param,
++        uint8_t                                 compat)
++{
++    _fm_cpt_dbg (compat, " {->...\n");
++
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->modify = compat_param->modify;
++
++        /* profile_select */
++        if (!compat_param->modify)
++        {
++            param->profile_select.new_params.profile_type =
++                compat_param->profile_select.new_params.profile_type;
++            param->profile_select.new_params.p_fm_port =
++                compat_ptr(compat_param->profile_select.new_params.p_fm_port);
++            param->profile_select.new_params.relative_profile_id =
++                compat_param->profile_select.new_params.relative_profile_id;
++        }
++        else
++            param->profile_select.p_profile =
++                compat_pcd_id2ptr(compat_param->profile_select.p_profile);
++
++        param->alg_selection    = compat_param->alg_selection;
++        param->color_mode       = compat_param->color_mode;
++
++        /* both parameters in the union has the same size, so memcpy works */
++        memcpy(&param->color, &compat_param->color, sizeof(param->color));
++
++        memcpy(&param->non_passthrough_alg_param,
++               &compat_param->non_passthrough_alg_param,
++               sizeof(ioc_fm_pcd_plcr_non_passthrough_alg_param_t));
++
++        param->next_engine_on_green = compat_param->next_engine_on_green;
++        param->next_engine_on_yellow = compat_param->next_engine_on_yellow;
++        param->next_engine_on_red = compat_param->next_engine_on_red;
++
++        param->trap_profile_on_flow_A = compat_param->trap_profile_on_flow_A;
++        param->trap_profile_on_flow_B = compat_param->trap_profile_on_flow_B;
++        param->trap_profile_on_flow_C = compat_param->trap_profile_on_flow_C;
++    }
++    else
++    {
++        compat_param->modify = param->modify;
++
++        /* profile_select */
++        if (!param->modify)
++        {
++            compat_param->profile_select.new_params.profile_type =
++                param->profile_select.new_params.profile_type;
++            compat_param->profile_select.new_params.p_fm_port =
++                ptr_to_compat(param->profile_select.new_params.p_fm_port);
++            compat_param->profile_select.new_params.relative_profile_id =
++                param->profile_select.new_params.relative_profile_id;
++        }
++        else
++            compat_param->profile_select.p_profile =
++                compat_pcd_ptr2id(param->profile_select.p_profile);
++
++        compat_param->alg_selection = param->alg_selection;
++        compat_param->color_mode    = param->color_mode;
++
++        /* both parameters in the union has the same size, so memcpy works */
++        memcpy(&compat_param->color, &param->color, sizeof(compat_param->color));
++
++        memcpy(&compat_param->non_passthrough_alg_param,
++               &param->non_passthrough_alg_param,
++               sizeof(ioc_fm_pcd_plcr_non_passthrough_alg_param_t));
++
++        compat_param->next_engine_on_green = param->next_engine_on_green;
++        compat_param->next_engine_on_yellow = param->next_engine_on_yellow;
++        compat_param->next_engine_on_red = param->next_engine_on_red;
++
++        compat_param->trap_profile_on_flow_A = param->trap_profile_on_flow_A;
++        compat_param->trap_profile_on_flow_B = param->trap_profile_on_flow_B;
++        compat_param->trap_profile_on_flow_C = param->trap_profile_on_flow_C;
++
++        compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
++    }
++
++    compat_copy_fm_pcd_plcr_next_engine(&compat_param->params_on_green,
++            &param->params_on_green, param->next_engine_on_green, compat);
++
++    compat_copy_fm_pcd_plcr_next_engine(&compat_param->params_on_yellow,
++            &param->params_on_yellow, param->next_engine_on_yellow, compat);
++
++    compat_copy_fm_pcd_plcr_next_engine(&compat_param->params_on_red,
++            &param->params_on_red, param->next_engine_on_red, compat);
++
++    _fm_cpt_dbg (compat, " ...->}\n");
++}
++
++static inline void compat_copy_fm_pcd_cc_next_kg(
++        ioc_compat_fm_pcd_cc_next_kg_params_t   *compat_param,
++        ioc_fm_pcd_cc_next_kg_params_t          *param,
++        uint8_t                                 compat)
++{
++    _fm_cpt_dbg (compat, " {->...\n");
++
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->new_fqid         = compat_param->new_fqid;
++        param->override_fqid    = compat_param->override_fqid;
++#if DPAA_VERSION >= 11
++        param->new_relative_storage_profile_id = compat_param->new_relative_storage_profile_id;
++#endif
++        param->p_direct_scheme  = compat_pcd_id2ptr(compat_param->p_direct_scheme);
++    }
++    else
++    {
++        compat_param->new_fqid          = param->new_fqid;
++        compat_param->override_fqid     = param->override_fqid;
++#if DPAA_VERSION >= 11
++        compat_param->new_relative_storage_profile_id = param->new_relative_storage_profile_id;
++#endif
++        compat_param->p_direct_scheme   = compat_pcd_ptr2id(param->p_direct_scheme);
++    }
++
++    _fm_cpt_dbg (compat, " ...->}\n");
++}
++
++static inline void compat_copy_fm_pcd_cc_next_cc(
++        ioc_compat_fm_pcd_cc_next_cc_params_t   *compat_param,
++        ioc_fm_pcd_cc_next_cc_params_t          *param,
++        uint8_t                                 compat)
++{
++    _fm_cpt_dbg (compat, " {->...\n");
++
++    if (compat == COMPAT_US_TO_K)
++        param->cc_node_id = compat_pcd_id2ptr(compat_param->cc_node_id);
++    else
++        compat_param->cc_node_id = compat_pcd_ptr2id(param->cc_node_id);
++
++    _fm_cpt_dbg (compat, " ...->}\n");
++}
++
++static inline void compat_copy_fm_pcd_cc_next_engine(
++        ioc_compat_fm_pcd_cc_next_engine_params_t   *compat_param,
++        ioc_fm_pcd_cc_next_engine_params_t          *param,
++        uint8_t                                     compat)
++{
++    _fm_cpt_dbg (compat, " {->...\n");
++
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->next_engine = compat_param->next_engine;
++        if (param->next_engine != e_IOC_FM_PCD_INVALID )
++            _fm_cpt_dbg(compat, " param->next_engine = %i \n", param->next_engine);
++
++        switch (param->next_engine)
++        {
++#if DPAA_VERSION >= 11
++            case e_IOC_FM_PCD_FR:
++                param->params.fr_params.frm_replic_id = compat_pcd_id2ptr(compat_param->params.fr_params.frm_replic_id);
++                break;
++#endif /* DPAA_VERSION >= 11 */
++            case e_IOC_FM_PCD_CC:
++                param->manip_id = compat_pcd_id2ptr(compat_param->manip_id);
++                compat_copy_fm_pcd_cc_next_cc(&compat_param->params.cc_params, &param->params.cc_params, compat);
++                break;
++            case e_IOC_FM_PCD_KG:
++                param->manip_id = compat_pcd_id2ptr(compat_param->manip_id);
++                compat_copy_fm_pcd_cc_next_kg(&compat_param->params.kg_params, &param->params.kg_params, compat);
++                break;
++            case e_IOC_FM_PCD_DONE:
++            case e_IOC_FM_PCD_PLCR:
++                param->manip_id = compat_pcd_id2ptr(compat_param->manip_id);
++            default:
++                memcpy(&param->params, &compat_param->params, sizeof(param->params));
++        }
++        param->statistics_en = compat_param->statistics_en;
++    }
++    else
++    {
++        compat_param->next_engine = param->next_engine;
++
++        switch (compat_param->next_engine)
++        {
++#if DPAA_VERSION >= 11
++            case e_IOC_FM_PCD_FR:
++                compat_param->params.fr_params.frm_replic_id = compat_pcd_ptr2id(param->params.fr_params.frm_replic_id);
++                break;
++#endif /* DPAA_VERSION >= 11 */
++            case e_IOC_FM_PCD_CC:
++                compat_param->manip_id = compat_pcd_ptr2id(param->manip_id);
++                compat_copy_fm_pcd_cc_next_cc(&compat_param->params.cc_params, &param->params.cc_params, compat);
++                break;
++            case e_IOC_FM_PCD_KG:
++                compat_param->manip_id = compat_pcd_ptr2id(param->manip_id);
++                compat_copy_fm_pcd_cc_next_kg(&compat_param->params.kg_params, &param->params.kg_params, compat);
++                break;
++            case e_IOC_FM_PCD_DONE:
++            case e_IOC_FM_PCD_PLCR:
++                compat_param->manip_id = compat_pcd_ptr2id(param->manip_id);
++            default:
++                memcpy(&compat_param->params, &param->params, sizeof(compat_param->params));
++        }
++        compat_param->statistics_en = param->statistics_en;
++    }
++
++    _fm_cpt_dbg (compat, " ...->}\n");
++}
++
++void compat_copy_fm_pcd_cc_key(
++        ioc_compat_fm_pcd_cc_key_params_t   *compat_param,
++        ioc_fm_pcd_cc_key_params_t          *param,
++        uint8_t                             compat)
++{
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->p_key = compat_ptr(compat_param->p_key);
++        param->p_mask = compat_ptr(compat_param->p_mask);
++    }
++    else
++    {
++        compat_param->p_key = ptr_to_compat(param->p_key);
++        compat_param->p_mask = ptr_to_compat(param->p_mask);
++    }
++
++    compat_copy_fm_pcd_cc_next_engine(
++            &compat_param->cc_next_engine_params,
++            &param->cc_next_engine_params,
++            compat);
++}
++
++void compat_copy_fm_pcd_cc_node_modify_key_and_next_engine(
++        ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t   *compat_param,
++        ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t          *param,
++        uint8_t                                                         compat)
++{
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->id       = compat_pcd_id2ptr(compat_param->id);
++        param->key_indx = compat_param->key_indx;
++        param->key_size = compat_param->key_size;
++        compat_copy_fm_pcd_cc_key(
++            &compat_param->key_params,
++            &param->key_params,
++            compat);
++    }
++    else
++    {
++        compat_param->id       = compat_pcd_ptr2id(param->id);
++        compat_param->key_indx = param->key_indx;
++        compat_param->key_size = param->key_size;
++        compat_copy_fm_pcd_cc_key(
++            &compat_param->key_params,
++            &param->key_params,
++            compat);
++    }
++}
++
++void compat_copy_fm_pcd_cc_node_modify_next_engine(
++        ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t   *compat_param,
++        ioc_fm_pcd_cc_node_modify_next_engine_params_t          *param,
++        uint8_t                                                 compat)
++{
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->id       = compat_pcd_id2ptr(compat_param->id);
++        param->key_indx = compat_param->key_indx;
++        param->key_size = compat_param->key_size;
++    }
++    else
++    {
++        compat_param->id       = compat_pcd_ptr2id(param->id);
++        compat_param->key_indx = param->key_indx;
++        compat_param->key_size = param->key_size;
++    }
++
++    compat_copy_fm_pcd_cc_next_engine(
++            &compat_param->cc_next_engine_params,
++            &param->cc_next_engine_params,
++            compat);
++}
++
++void compat_fm_pcd_cc_tree_modify_next_engine(
++        ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t   *compat_param,
++        ioc_fm_pcd_cc_tree_modify_next_engine_params_t          *param,
++        uint8_t                                                 compat)
++{
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->id       = compat_pcd_id2ptr(compat_param->id);
++        param->grp_indx = compat_param->grp_indx;
++        param->indx     = compat_param->indx;
++    }
++    else
++    {
++        compat_param->id       = compat_pcd_ptr2id(param->id);
++        compat_param->grp_indx = param->grp_indx;
++        compat_param->indx     = param->indx;
++    }
++
++    compat_copy_fm_pcd_cc_next_engine(
++            &compat_param->cc_next_engine_params,
++            &param->cc_next_engine_params,
++            compat);
++}
++
++void compat_copy_fm_pcd_hash_table(
++        ioc_compat_fm_pcd_hash_table_params_t *compat_param,
++        ioc_fm_pcd_hash_table_params_t *param,
++        uint8_t compat)
++{
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->max_num_of_keys  = compat_param->max_num_of_keys;
++        param->statistics_mode  = compat_param->statistics_mode;
++        param->kg_hash_shift    = compat_param->kg_hash_shift;
++        param->hash_res_mask    = compat_param->hash_res_mask;
++        param->hash_shift       = compat_param->hash_shift;
++        param->match_key_size   = compat_param->match_key_size;
++        param->id               = compat_pcd_id2ptr(compat_param->id);
++    }
++    else
++    {
++        compat_param->max_num_of_keys  = param->max_num_of_keys;
++        compat_param->statistics_mode  = param->statistics_mode;
++        compat_param->kg_hash_shift    = param->kg_hash_shift;
++        compat_param->hash_res_mask    = param->hash_res_mask;
++        compat_param->hash_shift       = param->hash_shift;
++        compat_param->match_key_size   = param->match_key_size;
++
++        compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
++    }
++
++    compat_copy_fm_pcd_cc_next_engine(
++            &compat_param->cc_next_engine_params_for_miss,
++            &param->cc_next_engine_params_for_miss,
++            compat);
++}
++
++void compat_copy_fm_pcd_cc_grp(
++        ioc_compat_fm_pcd_cc_grp_params_t *compat_param,
++        ioc_fm_pcd_cc_grp_params_t *param,
++        uint8_t compat)
++{
++    int k;
++
++    _fm_cpt_dbg (compat, " {->...\n");
++
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->num_of_distinction_units = compat_param->num_of_distinction_units;
++        memcpy(param->unit_ids, compat_param->unit_ids, IOC_FM_PCD_MAX_NUM_OF_CC_UNITS);
++    }
++    else
++    {
++        compat_param->num_of_distinction_units = param->num_of_distinction_units;
++        memcpy(compat_param->unit_ids, param->unit_ids, IOC_FM_PCD_MAX_NUM_OF_CC_UNITS);
++    }
++
++    for (k=0; k < IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP; k++)
++        compat_copy_fm_pcd_cc_next_engine(
++                &compat_param->next_engine_per_entries_in_grp[k],
++                &param->next_engine_per_entries_in_grp[k],
++                compat);
++
++    _fm_cpt_dbg (compat, " ...->}\n");
++}
++
++void compat_copy_fm_pcd_cc_tree(
++        ioc_compat_fm_pcd_cc_tree_params_t *compat_param,
++        ioc_fm_pcd_cc_tree_params_t *param,
++        uint8_t compat)
++{
++    int k;
++    _fm_cpt_dbg (compat, " {->...\n");
++
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->net_env_id = compat_pcd_id2ptr(compat_param->net_env_id);
++        param->num_of_groups = compat_param->num_of_groups;
++    }
++    else
++    {
++        compat_param->net_env_id = compat_pcd_ptr2id(param->net_env_id);
++        compat_param->num_of_groups = param->num_of_groups;
++
++        compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
++    }
++
++    for (k=0; k < IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS; k++)
++        compat_copy_fm_pcd_cc_grp(
++                &compat_param->fm_pcd_cc_group_params[k],
++                &param->fm_pcd_cc_group_params[k],
++                compat);
++
++    _fm_cpt_dbg (compat, " ...->}\n");
++}
++
++void compat_fm_pcd_prs_sw(
++        ioc_compat_fm_pcd_prs_sw_params_t *compat_param,
++        ioc_fm_pcd_prs_sw_params_t *param,
++        uint8_t compat)
++{
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->override = compat_param->override;
++        param->size = compat_param->size;
++        param->base = compat_param->base;
++        param->p_code = compat_ptr(compat_param->p_code);
++        memcpy(param->sw_prs_data_params,compat_param->sw_prs_data_params,IOC_FM_PCD_PRS_NUM_OF_HDRS*sizeof(uint32_t));
++        param->num_of_labels = compat_param->num_of_labels;
++        memcpy(param->labels_table,compat_param->labels_table,IOC_FM_PCD_PRS_NUM_OF_LABELS*sizeof(ioc_fm_pcd_prs_label_params_t));
++    }
++}
++
++void compat_copy_fm_pcd_kg_scheme(
++        ioc_compat_fm_pcd_kg_scheme_params_t    *compat_param,
++        ioc_fm_pcd_kg_scheme_params_t           *param,
++        uint8_t                                 compat)
++{
++    _fm_cpt_dbg(compat," {->...\n");
++
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->modify = compat_param->modify;
++
++        /* scm_id */
++        if (compat_param->modify)
++        {
++            param->scm_id.scheme_id = compat_pcd_id2ptr(compat_param->scm_id.scheme_id);
++            _fm_cpt_dbg(compat," param->scm_id.scheme_id = %p \n", param->scm_id.scheme_id);
++        }
++        else
++            param->scm_id.relative_scheme_id = compat_param->scm_id.relative_scheme_id;
++
++        param->always_direct = compat_param->always_direct;
++        /* net_env_params */
++        param->net_env_params.net_env_id = compat_pcd_id2ptr(compat_param->net_env_params.net_env_id);
++        param->net_env_params.num_of_distinction_units = compat_param->net_env_params.num_of_distinction_units;
++        memcpy(param->net_env_params.unit_ids,
++                compat_param->net_env_params.unit_ids,
++                IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
++
++        param->use_hash = compat_param->use_hash;
++        memcpy(&param->key_extract_and_hash_params,
++               &compat_param->key_extract_and_hash_params,
++               sizeof(ioc_fm_pcd_kg_key_extract_and_hash_params_t));
++        param->bypass_fqid_generation = compat_param->bypass_fqid_generation;
++        param->base_fqid = compat_param->base_fqid;
++#if DPAA_VERSION >= 11
++        param->override_storage_profile =
++                                 compat_param->override_storage_profile;
++        param->storage_profile = compat_param->storage_profile;
++#endif
++        param->num_of_used_extracted_ors = compat_param->num_of_used_extracted_ors;
++        memcpy(param->extracted_ors,
++               compat_param->extracted_ors,
++               IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS * sizeof(ioc_fm_pcd_kg_extracted_or_params_t));
++        param->next_engine = compat_param->next_engine;
++
++        /* kg_next_engine_params */
++        if (param->next_engine == e_IOC_FM_PCD_CC)
++        {
++            param->kg_next_engine_params.cc.tree_id   = compat_pcd_id2ptr(compat_param->kg_next_engine_params.cc.tree_id);
++            param->kg_next_engine_params.cc.grp_id    = compat_param->kg_next_engine_params.cc.grp_id;
++            param->kg_next_engine_params.cc.plcr_next = compat_param->kg_next_engine_params.cc.plcr_next;
++            param->kg_next_engine_params.cc.bypass_plcr_profile_generation
++                                                      = compat_param->kg_next_engine_params.cc.bypass_plcr_profile_generation;
++            memcpy(&param->kg_next_engine_params.cc.plcr_profile,
++                   &compat_param->kg_next_engine_params.cc.plcr_profile,
++                   sizeof(ioc_fm_pcd_kg_plcr_profile_t));
++        }
++        else
++            memcpy(&param->kg_next_engine_params,
++                   &compat_param->kg_next_engine_params,
++                   sizeof(param->kg_next_engine_params));
++
++        memcpy(&param->scheme_counter,
++               &compat_param->scheme_counter,
++               sizeof(ioc_fm_pcd_kg_scheme_counter_t));
++    }
++    else
++    {
++        compat_param->modify = param->modify;
++
++        /* scm_id */
++        if (param->modify)
++            compat_param->scm_id.scheme_id = compat_pcd_ptr2id(param->scm_id.scheme_id);
++        else
++            compat_param->scm_id.relative_scheme_id = param->scm_id.relative_scheme_id;
++
++        compat_param->always_direct = param->always_direct;
++
++        /* net_env_params */
++        compat_param->net_env_params.net_env_id = compat_pcd_ptr2id(param->net_env_params.net_env_id);
++        compat_param->net_env_params.num_of_distinction_units = param->net_env_params.num_of_distinction_units;
++        memcpy(compat_param->net_env_params.unit_ids, param->net_env_params.unit_ids, IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
++
++        compat_param->use_hash = param->use_hash;
++        memcpy(&compat_param->key_extract_and_hash_params, &param->key_extract_and_hash_params, sizeof(ioc_fm_pcd_kg_key_extract_and_hash_params_t));
++        compat_param->bypass_fqid_generation = param->bypass_fqid_generation;
++        compat_param->base_fqid = param->base_fqid;
++#if DPAA_VERSION >= 11
++        compat_param->override_storage_profile =
++                                        param->override_storage_profile;
++        compat_param->storage_profile =  param->storage_profile;
++#endif
++        compat_param->num_of_used_extracted_ors = param->num_of_used_extracted_ors;
++        memcpy(compat_param->extracted_ors, param->extracted_ors, IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS * sizeof(ioc_fm_pcd_kg_extracted_or_params_t));
++        compat_param->next_engine = param->next_engine;
++
++        /* kg_next_engine_params */
++        if (compat_param->next_engine == e_IOC_FM_PCD_CC)
++        {
++            compat_param->kg_next_engine_params.cc.tree_id   = compat_pcd_ptr2id(param->kg_next_engine_params.cc.tree_id);
++            compat_param->kg_next_engine_params.cc.grp_id    = param->kg_next_engine_params.cc.grp_id;
++            compat_param->kg_next_engine_params.cc.plcr_next = param->kg_next_engine_params.cc.plcr_next;
++            compat_param->kg_next_engine_params.cc.bypass_plcr_profile_generation
++                                                             = param->kg_next_engine_params.cc.bypass_plcr_profile_generation;
++            memcpy(&compat_param->kg_next_engine_params.cc.plcr_profile,
++                   &param->kg_next_engine_params.cc.plcr_profile,
++                   sizeof(ioc_fm_pcd_kg_plcr_profile_t));
++        }
++        else
++            memcpy(&param->kg_next_engine_params, &compat_param->kg_next_engine_params, sizeof(compat_param->kg_next_engine_params));
++
++        memcpy(&compat_param->scheme_counter, &param->scheme_counter, sizeof(ioc_fm_pcd_kg_scheme_counter_t));
++
++        compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
++    }
++
++    _fm_cpt_dbg(compat," ...->}\n");
++}
++
++void compat_copy_fm_pcd_kg_scheme_spc(
++        ioc_compat_fm_pcd_kg_scheme_spc_t *compat_param,
++        ioc_fm_pcd_kg_scheme_spc_t *param,
++        uint8_t compat)
++{
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->id = compat_pcd_id2ptr(compat_param->id);
++        param->val = compat_param->val;
++    } else {
++        compat_param->id = compat_pcd_ptr2id(param->id);
++        compat_param->val = param->val;
++    }
++}
++
++
++void compat_copy_fm_pcd_kg_scheme_select(
++        ioc_compat_fm_pcd_kg_scheme_select_t *compat_param,
++        ioc_fm_pcd_kg_scheme_select_t *param,
++        uint8_t compat)
++{
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->direct = compat_param->direct;
++        if (param->direct)
++            param->scheme_id = compat_pcd_id2ptr(compat_param->scheme_id);
++    }
++}
++
++void compat_copy_fm_pcd_kg_schemes_params(
++        ioc_compat_fm_pcd_port_schemes_params_t *compat_param,
++        ioc_fm_pcd_port_schemes_params_t *param,
++        uint8_t compat)
++{
++    int k;
++
++    if (compat == COMPAT_US_TO_K) {
++        param->num_of_schemes = compat_param->num_of_schemes;
++        for(k=0; k < compat_param->num_of_schemes; k++)
++            param->scheme_ids[k] = compat_pcd_id2ptr(compat_param->scheme_ids[k]);
++    }
++}
++
++void compat_copy_fm_port_pcd_cc(
++    ioc_compat_fm_port_pcd_cc_params_t *compat_cc_params ,
++    ioc_fm_port_pcd_cc_params_t *p_cc_params,
++    uint8_t compat)
++{
++    if (compat == COMPAT_US_TO_K){
++        p_cc_params->cc_tree_id = compat_pcd_id2ptr(compat_cc_params->cc_tree_id);
++    }
++}
++
++void compat_copy_fm_port_pcd_kg(
++        ioc_compat_fm_port_pcd_kg_params_t *compat_param,
++        ioc_fm_port_pcd_kg_params_t *param,
++        uint8_t compat)
++{
++    if (compat == COMPAT_US_TO_K){
++        uint8_t k;
++
++        param->num_of_schemes = compat_param->num_of_schemes;
++        for(k=0; k<compat_param->num_of_schemes; k++)
++            param->scheme_ids[k] = compat_pcd_id2ptr(compat_param->scheme_ids[k]);
++
++        param->direct_scheme = compat_param->direct_scheme;
++        if (param->direct_scheme)
++            param->direct_scheme_id = compat_pcd_id2ptr(compat_param->direct_scheme_id);
++    }
++}
++
++void compat_copy_fm_port_pcd(
++        ioc_compat_fm_port_pcd_params_t *compat_param,
++        ioc_fm_port_pcd_params_t *param,
++        uint8_t compat)
++{
++    if (compat == COMPAT_US_TO_K)
++    {
++        ioc_fm_port_pcd_prs_params_t         *same_port_pcd_prs_params;
++        ioc_compat_fm_port_pcd_cc_params_t   *compat_port_pcd_cc_params;
++        ioc_compat_fm_port_pcd_kg_params_t   *compat_port_pcd_kg_params;
++        ioc_compat_fm_port_pcd_plcr_params_t *compat_port_pcd_plcr_params;
++
++        same_port_pcd_prs_params    = (ioc_fm_port_pcd_prs_params_t *) (compat_param + 1);
++        compat_port_pcd_cc_params   = (ioc_compat_fm_port_pcd_cc_params_t *) (same_port_pcd_prs_params + 1);
++        compat_port_pcd_kg_params   = (ioc_compat_fm_port_pcd_kg_params_t *) (compat_port_pcd_cc_params + 1);
++        compat_port_pcd_plcr_params = (ioc_compat_fm_port_pcd_plcr_params_t *) (compat_port_pcd_kg_params + 1);
++
++        _fm_cpt_dbg(compat,"\n param->p_prs_params=%p \n", param->p_prs_params);
++        _fm_cpt_dbg(compat," param->p_cc_params=%p  \n", param->p_cc_params);
++        _fm_cpt_dbg(compat," param->p_kg_params=%p  \n", param->p_kg_params);
++        _fm_cpt_dbg(compat," param->p_plcr_params=%p  \n", param->p_plcr_params);
++        _fm_cpt_dbg(compat," param->p_ip_reassembly_manip=%p  \n", param->p_ip_reassembly_manip);
++#if (DPAA_VERSION >= 11)
++        _fm_cpt_dbg(compat," param->p_capwap_reassembly_manip=%p  \n", param->p_capwap_reassembly_manip);
++#endif
++        param->pcd_support = compat_param->pcd_support;
++        param->net_env_id = compat_pcd_id2ptr(compat_param->net_env_id);
++
++        if (param->p_cc_params)
++            compat_copy_fm_port_pcd_cc(compat_port_pcd_cc_params, param->p_cc_params, COMPAT_US_TO_K);
++        if (param->p_kg_params)
++            compat_copy_fm_port_pcd_kg(compat_port_pcd_kg_params, param->p_kg_params, COMPAT_US_TO_K);
++        if (param->p_plcr_params)
++            param->p_plcr_params->plcr_profile_id = compat_pcd_id2ptr(compat_port_pcd_plcr_params->plcr_profile_id);
++        param->p_ip_reassembly_manip = compat_pcd_id2ptr(compat_param->p_ip_reassembly_manip);
++#if (DPAA_VERSION >= 11)
++        param->p_capwap_reassembly_manip = compat_pcd_id2ptr(compat_param->p_capwap_reassembly_manip);
++#endif
++    }
++}
++
++void compat_copy_fm_port_pcd_modify_tree(
++        ioc_compat_fm_obj_t *compat_id,
++        ioc_fm_obj_t *id,
++        uint8_t compat)
++{
++    if (compat == COMPAT_US_TO_K)
++        id->obj = compat_pcd_id2ptr(compat_id->obj);
++}
++
++#if (DPAA_VERSION >= 11)
++void compat_copy_fm_port_vsp_alloc_params(
++        ioc_compat_fm_port_vsp_alloc_params_t *compat_param,
++        ioc_fm_port_vsp_alloc_params_t *param,
++        uint8_t compat)
++{
++    if (compat == COMPAT_US_TO_K)
++    {
++        _fm_cpt_dbg(compat," param->p_fm_tx_port=%p  \n", param->p_fm_tx_port);
++
++        param->dflt_relative_id = compat_param->dflt_relative_id;
++        param->num_of_profiles = compat_param->num_of_profiles;
++        param->p_fm_tx_port = compat_pcd_id2ptr(compat_param->p_fm_tx_port);
++    }
++}
++#endif /* (DPAA_VERSION >= 11) */
++
++void compat_copy_fm_pcd_cc_tbl_get_stats(
++        ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param,
++        ioc_fm_pcd_cc_tbl_get_stats_t *param,
++        uint8_t compat)
++{
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->id = compat_pcd_id2ptr(compat_param->id);
++      param->key_index = compat_param->key_index;
++        memcpy(&param->statistics, &compat_param->statistics, sizeof(ioc_fm_pcd_cc_key_statistics_t));
++    } else {
++        compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
++      compat_param->key_index = param->key_index;
++        memcpy(&compat_param->statistics, &param->statistics, sizeof(ioc_fm_pcd_cc_key_statistics_t));
++    }
++}
++
++  
++void compat_copy_fm_pcd_net_env(
++        ioc_compat_fm_pcd_net_env_params_t *compat_param,
++        ioc_fm_pcd_net_env_params_t *param,
++        uint8_t compat)
++{
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->num_of_distinction_units = compat_param->num_of_distinction_units;
++        memcpy(param->units, compat_param->units, sizeof(ioc_fm_pcd_distinction_unit_t)*IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
++        param->id = NULL; /* to avoid passing garbage to the kernel */
++    }
++    else
++    {
++        compat_param->num_of_distinction_units = param->num_of_distinction_units;
++        memcpy(compat_param->units, param->units, sizeof(ioc_fm_pcd_distinction_unit_t)*IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
++
++        compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
++    }
++}
++
++void compat_copy_fm_pcd_cc_node_modify_key(
++        ioc_compat_fm_pcd_cc_node_modify_key_params_t   *compat_param,
++        ioc_fm_pcd_cc_node_modify_key_params_t          *param,
++        uint8_t                                         compat)
++{
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->key_indx = compat_param->key_indx;
++        param->key_size = compat_param->key_size;
++        param->p_key    = (uint8_t *)compat_ptr(compat_param->p_key);
++        _fm_cpt_dbg(compat," param->p_key = %p \n", param->p_key);
++        param->p_mask   = (uint8_t *)compat_ptr(compat_param->p_mask);
++        _fm_cpt_dbg(compat," param->p_mask = %p\n", param->p_mask);
++        param->id       = compat_pcd_id2ptr(compat_param->id);
++        _fm_cpt_dbg(compat," param->id = %p \n", param->id);
++    }
++    else
++    {
++        compat_param->key_indx  = param->key_indx;
++        compat_param->key_size  = param->key_size;
++        compat_param->p_key     = ptr_to_compat((void *)param->p_key);
++        compat_param->p_mask    = ptr_to_compat((void *)param->p_mask);
++
++        compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
++    }
++}
++
++void compat_copy_keys(
++        ioc_compat_keys_params_t *compat_param,
++        ioc_keys_params_t *param,
++        uint8_t compat)
++{
++    int k = 0;
++
++    _fm_cpt_dbg(compat," {->...\n");
++
++    if (compat == COMPAT_US_TO_K) {
++        param->max_num_of_keys = compat_param->max_num_of_keys;
++        param->mask_support    = compat_param->mask_support;
++        param->statistics_mode = compat_param->statistics_mode;
++        param->num_of_keys     = compat_param->num_of_keys;
++        param->key_size        = compat_param->key_size;
++#if (DPAA_VERSION >= 11)
++        memcpy(&param->frame_length_ranges,
++                &compat_param->frame_length_ranges,
++                sizeof(param->frame_length_ranges[0]) *
++                    IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR);
++#endif /* (DPAA_VERSION >= 11) */
++    }
++    else {
++        compat_param->max_num_of_keys = param->max_num_of_keys;
++        compat_param->mask_support    = param->mask_support;
++        compat_param->statistics_mode = param->statistics_mode;
++        compat_param->num_of_keys     = param->num_of_keys;
++        compat_param->key_size        = param->key_size;
++#if (DPAA_VERSION >= 11)
++        memcpy(&compat_param->frame_length_ranges,
++            &param->frame_length_ranges,
++            sizeof(compat_param->frame_length_ranges[0]) *
++                IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR);
++#endif /* (DPAA_VERSION >= 11) */
++    }
++
++    for (k=0; k < IOC_FM_PCD_MAX_NUM_OF_KEYS; k++)
++        compat_copy_fm_pcd_cc_key(
++            &compat_param->key_params[k],
++            &param->key_params[k],
++             compat);
++
++    compat_copy_fm_pcd_cc_next_engine(
++            &compat_param->cc_next_engine_params_for_miss,
++            &param->cc_next_engine_params_for_miss,
++            compat);
++
++    _fm_cpt_dbg(compat," ...->}\n");
++}
++
++void compat_copy_fm_pcd_cc_node(
++        ioc_compat_fm_pcd_cc_node_params_t  *compat_param,
++        ioc_fm_pcd_cc_node_params_t         *param,
++        uint8_t                             compat)
++{
++    _fm_cpt_dbg(compat," {->...\n");
++
++    if (compat == COMPAT_US_TO_K)
++        memcpy(&param->extract_cc_params, &compat_param->extract_cc_params, sizeof(ioc_fm_pcd_extract_entry_t));
++
++    else
++    {
++        compat_copy_keys(&compat_param->keys_params, &param->keys_params, compat);
++
++        compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
++        _fm_cpt_dbg(compat," param->id = %p \n", param->id);
++    }
++
++    compat_copy_keys(&compat_param->keys_params, &param->keys_params, compat);
++
++    _fm_cpt_dbg(compat," ...->}\n");
++}
++
++void compat_fm_pcd_manip_set_node(
++        ioc_compat_fm_pcd_manip_params_t *compat_param,
++        ioc_fm_pcd_manip_params_t *param,
++        uint8_t compat)
++{
++    if (compat == COMPAT_US_TO_K) {
++        param->type = compat_param->type;
++        switch (param->type) {
++            case e_IOC_FM_PCD_MANIP_HDR:
++                param->u.hdr.rmv = compat_param->u.hdr.rmv;
++                memcpy(&param->u.hdr.rmv_params,
++                        &compat_param->u.hdr.rmv_params,
++                        sizeof(param->u.hdr.rmv_params));
++
++                param->u.hdr.insrt = compat_param->u.hdr.insrt;
++                param->u.hdr.insrt_params.type =
++                    compat_param->u.hdr.insrt_params.type;
++                switch (compat_param->u.hdr.insrt_params.type)
++                {
++                    case e_IOC_FM_PCD_MANIP_INSRT_GENERIC:
++                        param->u.hdr.insrt_params.u.generic.offset =
++                            compat_param->u.hdr.insrt_params.u.generic.offset;
++                        param->u.hdr.insrt_params.u.generic.size =
++                            compat_param->u.hdr.insrt_params.u.generic.size;
++                        param->u.hdr.insrt_params.u.generic.replace =
++                            compat_param->u.hdr.insrt_params.u.generic.replace;
++                        param->u.hdr.insrt_params.u.generic.p_data =
++                            compat_ptr(compat_param->u.hdr.insrt_params.u.generic.p_data);
++                        break;
++                    case e_IOC_FM_PCD_MANIP_INSRT_BY_HDR:
++                        param->u.hdr.insrt_params.u.by_hdr.type =
++                            compat_param->u.hdr.insrt_params.u.by_hdr.type;
++                        param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.specific_l2 =
++                            compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.specific_l2;
++                        param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.update =
++                            compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.update;
++                        param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.size =
++                            compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.size;
++                        param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.p_data =
++                            compat_ptr(compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.p_data);
++                        break;
++                    default:
++                        _fm_cpt_err("Unsupported type: %d", compat_param->u.hdr.insrt_params.type);
++                }
++
++                param->u.hdr.field_update = compat_param->u.hdr.field_update;
++                memcpy(&param->u.hdr.field_update_params,
++                        &compat_param->u.hdr.field_update_params,
++                        sizeof(param->u.hdr.field_update_params));
++
++                param->u.hdr.custom = compat_param->u.hdr.custom;
++                memcpy(&param->u.hdr.custom_params,
++                        &compat_param->u.hdr.custom_params,
++                        sizeof(param->u.hdr.custom_params));
++
++                param->u.hdr.dont_parse_after_manip =
++                    compat_param->u.hdr.dont_parse_after_manip;
++                break;
++            case e_IOC_FM_PCD_MANIP_REASSEM:
++                memcpy(&param->u.reassem, &compat_param->u.reassem, sizeof(param->u.reassem));
++                break;
++            case e_IOC_FM_PCD_MANIP_FRAG:
++                memcpy(&param->u.frag, &compat_param->u.frag, sizeof(param->u.frag));
++                break;
++            case e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD:
++                memcpy(&param->u.special_offload,
++                       &compat_param->u.special_offload,
++                       sizeof(param->u.special_offload));
++            break;
++        }
++
++        param->p_next_manip = compat_pcd_id2ptr(compat_param->p_next_manip);
++        param->id = compat_pcd_id2ptr(compat_param->id);
++    }
++    else {
++        compat_param->type = param->type;
++        memcpy(&compat_param->u, &param->u, sizeof(compat_param->u));
++
++        if (param->type == e_IOC_FM_PCD_MANIP_HDR &&
++            param->u.hdr.insrt_params.type == e_IOC_FM_PCD_MANIP_INSRT_GENERIC)
++                compat_param->u.hdr.insrt_params.u.generic.p_data =
++                    ptr_to_compat(param->u.hdr.insrt_params.u.generic.p_data);
++
++        compat_param->p_next_manip = compat_pcd_ptr2id(param->id);
++        /* ... should be one that was added previously by the very call to
++           compat_add_ptr2id() below: */
++        compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
++    }
++}
++
++void compat_copy_fm_pcd_manip_get_stats(
++      ioc_compat_fm_pcd_manip_get_stats_t *compat_param,
++      ioc_fm_pcd_manip_get_stats_t *param,
++      uint8_t compat)
++{
++      _fm_cpt_dbg (compat, " {->...\n");
++
++      if (compat == COMPAT_US_TO_K)
++      {
++              param->id = compat_pcd_id2ptr(compat_param->id);
++              memcpy(&param->stats, &compat_param->stats,
++                                      sizeof(ioc_fm_pcd_manip_stats_t));
++      }
++      else
++      {
++              compat_param->id = compat_add_ptr2id(param->id,
++                                FM_MAP_TYPE_PCD_NODE);
++              memcpy(&compat_param->stats, &param->stats,
++                                      sizeof(ioc_fm_pcd_manip_stats_t));
++      }
++
++      _fm_cpt_dbg (compat, " ...->}\n");
++}
++
++#if (DPAA_VERSION >= 11)
++void compat_copy_fm_pcd_frm_replic_group_params(
++      ioc_compat_fm_pcd_frm_replic_group_params_t *compat_param,
++      ioc_fm_pcd_frm_replic_group_params_t *param,
++      uint8_t compat)
++{
++      int k;
++
++      _fm_cpt_dbg (compat, " {->...\n");
++
++      if (compat == COMPAT_US_TO_K)
++      {
++              param->max_num_of_entries = compat_param->max_num_of_entries;
++              param->num_of_entries = compat_param->num_of_entries;
++              param->id = compat_pcd_id2ptr(compat_param->id);
++      }
++      else
++      {
++              compat_param->max_num_of_entries = param->max_num_of_entries;
++              compat_param->num_of_entries = param->num_of_entries;
++              compat_param->id = compat_add_ptr2id(param->id,
++                              FM_MAP_TYPE_PCD_NODE);
++      }
++
++      for (k=0; k < IOC_FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES; k++)
++              compat_copy_fm_pcd_cc_next_engine(
++                              &compat_param->next_engine_params[k],
++                              &param->next_engine_params[k],
++                              compat);
++
++      _fm_cpt_dbg (compat, " ...->}\n");
++}
++
++void compat_copy_fm_pcd_frm_replic_member(
++      ioc_compat_fm_pcd_frm_replic_member_t *compat_param,
++      ioc_fm_pcd_frm_replic_member_t *param,
++      uint8_t compat)
++{
++      _fm_cpt_dbg (compat, " {->...\n");
++
++      if (compat == COMPAT_US_TO_K)
++      {
++              param->h_replic_group = compat_pcd_id2ptr(compat_param->h_replic_group);
++              param->member_index = compat_param->member_index;
++      }
++
++      _fm_cpt_dbg (compat, " ...->}\n");
++}
++
++void compat_copy_fm_pcd_frm_replic_member_params(
++      ioc_compat_fm_pcd_frm_replic_member_params_t *compat_param,
++      ioc_fm_pcd_frm_replic_member_params_t *param,
++      uint8_t compat)
++{
++      _fm_cpt_dbg (compat, " {->...\n");
++
++      compat_copy_fm_pcd_frm_replic_member(&compat_param->member,
++              &param->member, compat);
++
++      compat_copy_fm_pcd_cc_next_engine(&compat_param->next_engine_params,
++              &param->next_engine_params, compat);
++
++      _fm_cpt_dbg (compat, " ...->}\n");
++}
++
++void compat_copy_fm_vsp_params(
++    ioc_compat_fm_vsp_params_t *compat_param,
++    ioc_fm_vsp_params_t *param,
++    uint8_t compat)
++{
++    _fm_cpt_dbg (compat, " {->...\n");
++
++    if (compat == COMPAT_US_TO_K)
++    {
++        memcpy(&param->ext_buf_pools, &compat_param->ext_buf_pools, sizeof(ioc_fm_ext_pools));
++        param->liodn_offset = compat_param->liodn_offset;
++        param->port_params.port_id = compat_param->port_params.port_id;
++        param->port_params.port_type = compat_param->port_params.port_type;
++        param->relative_profile_id = compat_param->relative_profile_id;
++    }
++    else
++    {
++        memcpy(&compat_param->ext_buf_pools, &param->ext_buf_pools, sizeof(ioc_fm_ext_pools));
++        compat_param->liodn_offset = param->liodn_offset;
++        compat_param->port_params.port_id = param->port_params.port_id;
++        compat_param->port_params.port_type = param->port_params.port_type;
++        compat_param->relative_profile_id = param->relative_profile_id;
++        compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
++    }
++
++    _fm_cpt_dbg (compat, " ...->}\n");
++}
++
++void compat_copy_fm_buf_pool_depletion_params(
++    ioc_compat_fm_buf_pool_depletion_params_t *compat_param,
++    ioc_fm_buf_pool_depletion_params_t *param,
++    uint8_t compat)
++{
++    _fm_cpt_dbg (compat, " {->...\n");
++
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp);
++        memcpy(&param->fm_buf_pool_depletion,
++                &compat_param->fm_buf_pool_depletion,
++                sizeof(ioc_fm_buf_pool_depletion_t));
++    }
++
++    _fm_cpt_dbg (compat, " ...->}\n");
++}
++
++void compat_copy_fm_buffer_prefix_content_params(
++    ioc_compat_fm_buffer_prefix_content_params_t *compat_param,
++    ioc_fm_buffer_prefix_content_params_t *param,
++    uint8_t compat)
++{
++    _fm_cpt_dbg (compat, " {->...\n");
++
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp);
++        memcpy(&param->fm_buffer_prefix_content,
++                &compat_param->fm_buffer_prefix_content,
++                sizeof(ioc_fm_buffer_prefix_content_t));
++    }
++
++    _fm_cpt_dbg (compat, " ...->}\n");
++}
++
++void compat_copy_fm_vsp_config_no_sg_params(
++    ioc_compat_fm_vsp_config_no_sg_params_t *compat_param,
++    ioc_fm_vsp_config_no_sg_params_t *param,
++    uint8_t compat)
++{
++    _fm_cpt_dbg (compat, " {->...\n");
++
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp);
++        param->no_sg = compat_param->no_sg;
++    }
++
++    _fm_cpt_dbg (compat, " ...->}\n");
++}
++
++void compat_copy_fm_vsp_prs_result_params(
++    ioc_compat_fm_vsp_prs_result_params_t *compat_param,
++    ioc_fm_vsp_prs_result_params_t *param,
++    uint8_t compat)
++{
++    _fm_cpt_dbg (compat, " {->...\n");
++
++    if (compat == COMPAT_US_TO_K)
++    {
++        param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp);
++        /* p_data is an user-space pointer that needs to remain unmodified */
++        param->p_data = (void *)(unsigned long long)compat_param->p_data;
++    }
++    else
++    {
++        compat_param->p_fm_vsp = compat_pcd_ptr2id(param->p_fm_vsp);
++        /* p_data is an user-space pointer that needs to remain unmodified */
++        compat_param->p_data = (compat_uptr_t)((unsigned long long)param->p_data & 0xFFFFFFFF);
++    }
++
++    _fm_cpt_dbg (compat, " ...->}\n");
++}
++#endif /* (DPAA_VERSION >= 11) */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.h
+@@ -0,0 +1,755 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ @File          lnxwrp_ioctls_fm_compat.h
++
++ @Description   FM PCD compat structures definition.
++
++*/
++
++#ifndef __FM_COMPAT_IOCTLS_H
++#define __FM_COMPAT_IOCTLS_H
++
++#include <linux/compat.h>
++
++#define COMPAT_K_TO_US 0 /* copy from Kernel to User */
++#define COMPAT_US_TO_K 1 /* copy from User to Kernel */
++#define COMPAT_GENERIC 2
++
++#define COMPAT_COPY_K2US(dest, src, type)     compat_copy_##type(src, dest, 0)
++#define COMPAT_COPY_US2K(dest, src, type)     compat_copy_##type(dest, src, 1)
++
++/* mapping kernel pointers w/ UserSpace id's { */
++/* Because compat_ptr(ptr_to_compat(X)) != X, this way we cannot exchange pointers
++   back and forth (US - KS). compat_ptr is a cast and pointers are broken. */
++#define COMPAT_PTR2ID_ARRAY_MAX (512+1) /* first location is not used */
++#define COMPAT_PTR2ID_WATERMARK 0xface0000
++#define COMPAT_PTR2ID_WM_MASK   0xffff0000
++
++/* define it for debug trace */
++/*#define FM_COMPAT_DBG*/
++
++#define _fm_cpt_prk(stage, format, arg...)    \
++      printk(stage "fm_cpt (cpu:%u): " format, raw_smp_processor_id(), ##arg)
++
++#define _fm_cpt_inf(format, arg...) _fm_cpt_prk(KERN_INFO, format, ##arg)
++#define _fm_cpt_wrn(format, arg...) _fm_cpt_prk(KERN_WARNING, format, ##arg)
++#define _fm_cpt_err(format, arg...) _fm_cpt_prk(KERN_ERR, format, ##arg)
++
++/* used for compat IOCTL debugging */
++#if defined(FM_COMPAT_DBG)
++      #define _fm_cpt_dbg(from, format, arg...) \
++              do{ \
++                      if (from == COMPAT_US_TO_K) \
++                              printk("fm_cpt to KS [%s:%u](cpu:%u) - " format,        \
++                                      __func__, __LINE__, raw_smp_processor_id(), ##arg); \
++                      else if (from == COMPAT_K_TO_US) \
++                              printk("fm_cpt to US [%s:%u](cpu:%u) - " format,        \
++                                      __func__, __LINE__, raw_smp_processor_id(), ##arg); \
++            else \
++                printk("fm_cpt [%s:%u](cpu:%u) - " format,    \
++                    __func__, __LINE__, raw_smp_processor_id(), ##arg); \
++              }while(0)
++#else
++#     define _fm_cpt_dbg(arg...)
++#endif
++
++/*TODO: per FMan module:
++ *
++ *      Parser:  FM_MAP_TYPE_PARSER_NODE,
++ *      Kg:      FM_MAP_TYPE_KG_NODE,
++ *      Policer: FM_MAP_TYPE_POLICER_NODE
++ *      Manip:   FM_MAP_TYPE_MANIP_NODE
++ **/
++enum fm_map_node_type {
++    FM_MAP_TYPE_UNSPEC = 0,
++    FM_MAP_TYPE_PCD_NODE,
++
++    /* add types here, update the policy */
++
++    __FM_MAP_TYPE_AFTER_LAST,
++    FM_MAP_TYPE_MAX = __FM_MAP_TYPE_AFTER_LAST - 1
++};
++
++void compat_del_ptr2id(void *p, enum fm_map_node_type);
++compat_uptr_t compat_add_ptr2id(void *p, enum fm_map_node_type);
++compat_uptr_t compat_get_ptr2id(void *p, enum fm_map_node_type);
++void *compat_get_id2ptr(compat_uptr_t comp, enum fm_map_node_type);
++
++static inline compat_uptr_t compat_pcd_ptr2id(void *ptr) {
++    return (ptr)? compat_get_ptr2id(ptr, FM_MAP_TYPE_PCD_NODE)
++                : (compat_uptr_t) 0;
++}
++
++static inline void *compat_pcd_id2ptr(compat_uptr_t id) {
++    return (id) ? compat_get_id2ptr(id, FM_MAP_TYPE_PCD_NODE)
++                : NULL;
++}
++
++/* other similar inlines may be added as new nodes are added
++   to enum fm_map_node_type above... */
++/* } mapping kernel pointers w/ UserSpace id's  */
++
++/* pcd compat structures { */
++typedef struct ioc_compat_fm_pcd_cc_node_remove_key_params_t {
++    compat_uptr_t                       id;
++    uint16_t                            key_indx;
++} ioc_compat_fm_pcd_cc_node_remove_key_params_t;
++
++typedef union ioc_compat_fm_pcd_plcr_next_engine_params_u {
++        ioc_fm_pcd_done_action     action;
++        compat_uptr_t              p_profile;
++        compat_uptr_t              p_direct_scheme;
++} ioc_compat_fm_pcd_plcr_next_engine_params_u;
++
++typedef struct ioc_compat_fm_pcd_plcr_profile_params_t {
++    bool                                        modify;
++    union {
++        struct {
++            ioc_fm_pcd_profile_type_selection   profile_type;
++            compat_uptr_t                       p_fm_port;
++            uint16_t                            relative_profile_id;
++        } new_params;
++        compat_uptr_t                           p_profile;
++    } profile_select;
++    ioc_fm_pcd_plcr_algorithm_selection         alg_selection;
++    ioc_fm_pcd_plcr_color_mode                  color_mode;
++
++    union {
++        ioc_fm_pcd_plcr_color                   dflt_color;
++        ioc_fm_pcd_plcr_color                   override;
++    } color;
++
++    ioc_fm_pcd_plcr_non_passthrough_alg_param_t non_passthrough_alg_param;
++
++    ioc_fm_pcd_engine                           next_engine_on_green;
++    ioc_compat_fm_pcd_plcr_next_engine_params_u params_on_green;
++
++    ioc_fm_pcd_engine                           next_engine_on_yellow;
++    ioc_compat_fm_pcd_plcr_next_engine_params_u params_on_yellow;
++
++    ioc_fm_pcd_engine                           next_engine_on_red;
++    ioc_compat_fm_pcd_plcr_next_engine_params_u params_on_red;
++
++    bool                                        trap_profile_on_flow_A;
++    bool                                        trap_profile_on_flow_B;
++    bool                                        trap_profile_on_flow_C;
++    compat_uptr_t                               id;
++} ioc_compat_fm_pcd_plcr_profile_params_t;
++
++typedef struct ioc_compat_fm_obj_t {
++    compat_uptr_t obj;
++} ioc_compat_fm_obj_t;
++
++typedef struct ioc_compat_fm_pcd_kg_scheme_select_t {
++    bool          direct;
++    compat_uptr_t scheme_id;
++} ioc_compat_fm_pcd_kg_scheme_select_t;
++
++typedef struct ioc_compat_fm_pcd_port_schemes_params_t {
++    uint8_t        num_of_schemes;
++    compat_uptr_t  scheme_ids[FM_PCD_KG_NUM_OF_SCHEMES];
++} ioc_compat_fm_pcd_port_schemes_params_t;
++
++#if (DPAA_VERSION >= 11)
++typedef struct ioc_compat_fm_port_vsp_alloc_params_t {
++    uint8_t       num_of_profiles;          /**< Number of Virtual Storage Profiles */
++    uint8_t             dflt_relative_id;         /**< The default Virtual-Storage-Profile-id dedicated to Rx/OP port
++                                             The same default Virtual-Storage-Profile-id will be for coupled Tx port
++                                             if relevant function called for Rx port */
++    compat_uptr_t p_fm_tx_port;             /**< Handle to coupled Tx Port; not relevant for OP port. */
++}ioc_compat_fm_port_vsp_alloc_params_t;
++#endif /* (DPAA_VERSION >= 11) */
++
++typedef struct ioc_compat_fm_pcd_net_env_params_t {
++    uint8_t                         num_of_distinction_units;
++    ioc_fm_pcd_distinction_unit_t   units[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; /* same structure*/
++    compat_uptr_t                   id;
++} ioc_compat_fm_pcd_net_env_params_t;
++
++typedef struct ioc_compat_fm_pcd_prs_sw_params_t {
++    bool                            override;
++    uint32_t                        size;
++    uint16_t                        base;
++    compat_uptr_t                   p_code;
++    uint32_t                        sw_prs_data_params[IOC_FM_PCD_PRS_NUM_OF_HDRS];
++    uint8_t                         num_of_labels;
++    ioc_fm_pcd_prs_label_params_t   labels_table[IOC_FM_PCD_PRS_NUM_OF_LABELS];
++} ioc_compat_fm_pcd_prs_sw_params_t;
++
++typedef struct ioc_compat_fm_pcd_cc_next_kg_params_t {
++    bool          override_fqid;
++    uint32_t      new_fqid;
++#if DPAA_VERSION >= 11
++    uint8_t       new_relative_storage_profile_id;
++#endif
++    compat_uptr_t p_direct_scheme;
++} ioc_compat_fm_pcd_cc_next_kg_params_t;
++
++typedef struct ioc_compat_fm_pcd_cc_next_cc_params_t {
++    compat_uptr_t       cc_node_id;
++} ioc_compat_fm_pcd_cc_next_cc_params_t;
++
++#if DPAA_VERSION >= 11
++typedef struct ioc_compat_fm_pcd_cc_next_fr_params_t {
++    compat_uptr_t       frm_replic_id;
++} ioc_compat_fm_pcd_cc_next_fr_params_t;
++#endif /* DPAA_VERSION >= 11 */
++
++typedef struct ioc_compat_fm_pcd_cc_next_engine_params_t {
++    ioc_fm_pcd_engine                          next_engine;
++    union {
++        ioc_compat_fm_pcd_cc_next_cc_params_t  cc_params;      /**< compat structure*/
++        ioc_fm_pcd_cc_next_plcr_params_t       plcr_params;    /**< same structure*/
++        ioc_fm_pcd_cc_next_enqueue_params_t    enqueue_params; /**< same structure*/
++        ioc_compat_fm_pcd_cc_next_kg_params_t  kg_params;      /**< compat structure*/
++#if DPAA_VERSION >= 11
++        ioc_compat_fm_pcd_cc_next_fr_params_t  fr_params;      /**< compat structure*/
++#endif /* DPAA_VERSION >= 11 */
++    } params;
++    compat_uptr_t                               manip_id;
++    bool                                        statistics_en;
++} ioc_compat_fm_pcd_cc_next_engine_params_t;
++
++typedef struct ioc_compat_fm_pcd_cc_grp_params_t {
++    uint8_t                             num_of_distinction_units;
++    uint8_t                             unit_ids [IOC_FM_PCD_MAX_NUM_OF_CC_UNITS];
++    ioc_compat_fm_pcd_cc_next_engine_params_t  next_engine_per_entries_in_grp[IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP];
++} ioc_compat_fm_pcd_cc_grp_params_t;
++
++typedef struct ioc_compat_fm_pcd_cc_tree_params_t {
++    compat_uptr_t                   net_env_id;
++    uint8_t                         num_of_groups;
++    ioc_compat_fm_pcd_cc_grp_params_t      fm_pcd_cc_group_params [IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS];
++    compat_uptr_t                   id;
++} ioc_compat_fm_pcd_cc_tree_params_t;
++
++typedef struct ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t {
++    compat_uptr_t                       id;
++    uint8_t                             grp_indx;
++    uint8_t                             indx;
++    ioc_compat_fm_pcd_cc_next_engine_params_t  cc_next_engine_params;
++} ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t;
++
++typedef struct ioc_compat_fm_pcd_cc_key_params_t {
++    compat_uptr_t                              p_key;
++    compat_uptr_t                              p_mask;
++    ioc_compat_fm_pcd_cc_next_engine_params_t  cc_next_engine_params; /**< compat structure*/
++} ioc_compat_fm_pcd_cc_key_params_t;
++
++typedef struct ioc_compat_keys_params_t {
++    uint16_t                                   max_num_of_keys;
++    bool                                       mask_support;
++    ioc_fm_pcd_cc_stats_mode                   statistics_mode;
++#if (DPAA_VERSION >= 11)
++    uint16_t                                   frame_length_ranges[IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR];
++#endif /* (DPAA_VERSION >= 11) */
++    uint16_t                                   num_of_keys;
++    uint8_t                                    key_size;
++    ioc_compat_fm_pcd_cc_key_params_t          key_params[IOC_FM_PCD_MAX_NUM_OF_KEYS]; /**< compat structure*/
++    ioc_compat_fm_pcd_cc_next_engine_params_t  cc_next_engine_params_for_miss;         /**< compat structure*/
++} ioc_compat_keys_params_t;
++
++typedef struct ioc_compat_fm_pcd_cc_node_params_t {
++    ioc_fm_pcd_extract_entry_t                 extract_cc_params;  /**< same structure*/
++    ioc_compat_keys_params_t                   keys_params;        /**< compat structure*/
++    compat_uptr_t                              id;
++} ioc_compat_fm_pcd_cc_node_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining a hash table
++*//***************************************************************************/
++typedef struct ioc_compat_fm_pcd_hash_table_params_t {
++    uint16_t                    max_num_of_keys;
++    ioc_fm_pcd_cc_stats_mode    statistics_mode;
++    uint8_t                     kg_hash_shift;
++    uint16_t                    hash_res_mask;
++    uint8_t                     hash_shift;
++    uint8_t                     match_key_size;
++    ioc_compat_fm_pcd_cc_next_engine_params_t   cc_next_engine_params_for_miss;
++    compat_uptr_t               id;
++} ioc_compat_fm_pcd_hash_table_params_t;
++
++typedef struct ioc_compat_fm_pcd_hash_table_add_key_params_t {
++    compat_uptr_t                       p_hash_tbl;
++    uint8_t                             key_size;
++    ioc_compat_fm_pcd_cc_key_params_t   key_params;
++} ioc_compat_fm_pcd_hash_table_add_key_params_t;
++
++typedef struct ioc_compat_fm_pcd_cc_node_modify_key_params_t {
++    compat_uptr_t                       id;
++    uint16_t                            key_indx;
++    uint8_t                             key_size;
++    compat_uptr_t                       p_key;
++    compat_uptr_t                       p_mask;
++} ioc_compat_fm_pcd_cc_node_modify_key_params_t;
++
++typedef struct ioc_compat_fm_pcd_hash_table_remove_key_params_t {
++    compat_uptr_t   p_hash_tbl;
++    uint8_t         key_size;
++    compat_uptr_t   p_key;
++} ioc_compat_fm_pcd_hash_table_remove_key_params_t;
++
++typedef struct ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t {
++    compat_uptr_t                       id;
++    uint16_t                            key_indx;
++    uint8_t                             key_size;
++    ioc_compat_fm_pcd_cc_key_params_t   key_params;
++} ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t;
++
++typedef struct ioc_compat_fm_port_pcd_plcr_params_t {
++    compat_uptr_t                plcr_profile_id;
++} ioc_compat_fm_port_pcd_plcr_params_t;
++
++typedef struct ioc_compat_fm_port_pcd_cc_params_t {
++    compat_uptr_t                cc_tree_id;
++} ioc_compat_fm_port_pcd_cc_params_t;
++
++typedef struct ioc_compat_fm_port_pcd_kg_params_t {
++    uint8_t             num_of_schemes;
++    compat_uptr_t       scheme_ids[FM_PCD_KG_NUM_OF_SCHEMES];
++    bool                direct_scheme;
++    compat_uptr_t       direct_scheme_id;
++} ioc_compat_fm_port_pcd_kg_params_t;
++
++typedef struct ioc_compat_fm_port_pcd_params_t {
++    ioc_fm_port_pcd_support          pcd_support;
++    compat_uptr_t                    net_env_id;
++    compat_uptr_t                    p_prs_params;
++    compat_uptr_t                    p_cc_params;
++    compat_uptr_t                    p_kg_params;
++    compat_uptr_t                    p_plcr_params;
++    compat_uptr_t                    p_ip_reassembly_manip;
++#if DPAA_VERSION >= 11
++    compat_uptr_t                    p_capwap_reassembly_manip;
++#endif
++} ioc_compat_fm_port_pcd_params_t;
++
++typedef struct ioc_compat_fm_pcd_kg_cc_t {
++    compat_uptr_t                   tree_id;
++    uint8_t                         grp_id;
++    bool                            plcr_next;
++    bool                            bypass_plcr_profile_generation;
++    ioc_fm_pcd_kg_plcr_profile_t    plcr_profile;
++} ioc_compat_fm_pcd_kg_cc_t;
++
++typedef struct ioc_compat_fm_pcd_kg_scheme_params_t {
++    bool                                modify;
++    union {
++        uint8_t                         relative_scheme_id;
++        compat_uptr_t                   scheme_id;
++    } scm_id;
++    bool                                always_direct;
++    struct {
++        compat_uptr_t                   net_env_id;
++        uint8_t                         num_of_distinction_units;
++        uint8_t                         unit_ids[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS];
++    } net_env_params;
++    bool                                use_hash;
++    ioc_fm_pcd_kg_key_extract_and_hash_params_t key_extract_and_hash_params;
++    bool                                bypass_fqid_generation;
++    uint32_t                            base_fqid;
++    uint8_t                             num_of_used_extracted_ors;
++    ioc_fm_pcd_kg_extracted_or_params_t extracted_ors[IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS];
++#if DPAA_VERSION >= 11
++    bool                                override_storage_profile;
++    ioc_fm_pcd_kg_storage_profile_t     storage_profile;
++#endif /* DPAA_VERSION >= 11 */
++    ioc_fm_pcd_engine                   next_engine;
++    union{
++        ioc_fm_pcd_done_action          done_action;
++        ioc_fm_pcd_kg_plcr_profile_t    plcr_profile;
++        ioc_compat_fm_pcd_kg_cc_t       cc;
++    } kg_next_engine_params;
++    ioc_fm_pcd_kg_scheme_counter_t      scheme_counter;
++    compat_uptr_t                       id;
++} ioc_compat_fm_pcd_kg_scheme_params_t;
++
++typedef struct ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t {
++    compat_uptr_t                       id;
++    uint16_t                            key_indx;
++    uint8_t                             key_size;
++    ioc_compat_fm_pcd_cc_next_engine_params_t  cc_next_engine_params;
++} ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t;
++
++typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_generic_params_t {
++    uint8_t                         offset;
++    uint8_t                         size;
++    bool                            replace;
++    compat_uptr_t                   p_data;
++} ioc_compat_fm_pcd_manip_hdr_insrt_generic_params_t;
++
++typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_specific_l2_params_t {
++    ioc_fm_pcd_manip_hdr_insrt_specific_l2  specific_l2;
++    bool                                    update;
++    uint8_t                                 size;
++    compat_uptr_t                           p_data;
++} ioc_compat_fm_pcd_manip_hdr_insrt_specific_l2_params_t;
++
++typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_t {
++    uint8_t       size;          /**< size of inserted section */
++    compat_uptr_t p_data;        /**< data to be inserted */
++} ioc_compat_fm_pcd_manip_hdr_insrt_t;
++
++#if (DPAA_VERSION >= 11)
++typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_ip_params_t {
++    bool    calc_l4_checksum; /**< Calculate L4 checksum. */
++    ioc_fm_pcd_manip_hdr_qos_mapping_mode   mapping_mode; /**< TODO */
++    uint8_t last_pid_offset;     /**< the offset of the last Protocol within
++                                 the inserted header */
++    uint16_t  id;           /**< 16 bit New IP ID */
++    bool                            dont_frag_overwrite;
++    /**< IPv4 only. DF is overwritten with the hash-result next-to-last byte.
++     * This byte is configured to be overwritten when RPD is set. */
++    uint8_t                         last_dst_offset;
++    /**< IPv6 only. if routing extension exist, user should set the offset of the destination address
++     * in order to calculate UDP checksum pseudo header;
++     * Otherwise set it to '0'. */
++    ioc_compat_fm_pcd_manip_hdr_insrt_t insrt; /**< size and data to be inserted. */
++} ioc_compat_fm_pcd_manip_hdr_insrt_ip_params_t;
++#endif /* (DPAA_VERSION >= 11) */
++
++typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_by_hdr_params_t {
++    ioc_fm_pcd_manip_hdr_insrt_by_hdr_type                      type;
++    union {
++       ioc_compat_fm_pcd_manip_hdr_insrt_specific_l2_params_t   specific_l2_params;
++#if (DPAA_VERSION >= 11)
++        ioc_compat_fm_pcd_manip_hdr_insrt_ip_params_t          ip_params;
++        ioc_compat_fm_pcd_manip_hdr_insrt_t             insrt;
++#endif /* (DPAA_VERSION >= 11) */
++    } u;
++} ioc_compat_fm_pcd_manip_hdr_insrt_by_hdr_params_t;
++
++typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_params_t {
++    ioc_fm_pcd_manip_hdr_insrt_type                         type;
++    union {
++        ioc_compat_fm_pcd_manip_hdr_insrt_by_hdr_params_t   by_hdr;
++        ioc_compat_fm_pcd_manip_hdr_insrt_generic_params_t  generic;
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++#error "FM_CAPWAP_SUPPORT feature not supported!"
++        ioc_fm_pcd_manip_hdr_insrt_by_template_params_t     by_template;
++#endif /* FM_CAPWAP_SUPPORT */
++    } u;
++} ioc_compat_fm_pcd_manip_hdr_insrt_params_t;
++
++typedef struct ioc_compat_fm_pcd_manip_hdr_params_t {
++    bool                                        rmv;
++    ioc_fm_pcd_manip_hdr_rmv_params_t           rmv_params;
++    bool                                        insrt;
++    ioc_compat_fm_pcd_manip_hdr_insrt_params_t  insrt_params;
++    bool                                        field_update;
++    ioc_fm_pcd_manip_hdr_field_update_params_t  field_update_params;
++    bool                                        custom;
++    ioc_fm_pcd_manip_hdr_custom_params_t        custom_params;
++    bool                                        dont_parse_after_manip;
++} ioc_compat_fm_pcd_manip_hdr_params_t;
++
++typedef struct ioc_compat_fm_pcd_manip_special_offload_params_t {
++    bool    decryption;
++    bool    ecn_copy;
++    bool    dscp_copy;
++    bool    variable_ip_hdr_len;
++    bool    variable_ip_version;
++    uint8_t outer_ip_hdr_len;
++    uint16_t    arw_size;
++    compat_uptr_t   arw_addr;
++} ioc_compat_fm_pcd_manip_special_offload_params_t;
++
++typedef struct ioc_compat_fm_pcd_manip_params_t {
++    ioc_fm_pcd_manip_type                         type;
++    union {
++        ioc_compat_fm_pcd_manip_hdr_params_t      hdr;
++        ioc_fm_pcd_manip_reassem_params_t         reassem;
++        ioc_fm_pcd_manip_frag_params_t            frag;
++        ioc_compat_fm_pcd_manip_special_offload_params_t special_offload;
++    } u;
++    compat_uptr_t                                 p_next_manip;
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++#error "FM_CAPWAP_SUPPORT feature not supported!"
++    bool                                          frag_or_reasm;
++    ioc_fm_pcd_manip_frag_or_reasm_params_t       frag_or_reasm_params;
++#endif /* FM_CAPWAP_SUPPORT */
++    compat_uptr_t                                 id;
++} ioc_compat_fm_pcd_manip_params_t;
++
++typedef struct ioc_compat_fm_pcd_manip_get_stats_t {
++      compat_uptr_t                   id;
++      ioc_fm_pcd_manip_stats_t        stats;
++} ioc_compat_fm_pcd_manip_get_stats_t;
++
++#if (DPAA_VERSION >= 11)
++typedef struct ioc_compat_fm_pcd_frm_replic_group_params_t {
++      uint8_t                     max_num_of_entries;
++      uint8_t                     num_of_entries;
++      ioc_compat_fm_pcd_cc_next_engine_params_t
++              next_engine_params[IOC_FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES];
++      compat_uptr_t               id;
++} ioc_compat_fm_pcd_frm_replic_group_params_t;
++
++typedef struct ioc_compat_fm_pcd_frm_replic_member_t {
++    compat_uptr_t       h_replic_group;
++    uint16_t            member_index;
++} ioc_compat_fm_pcd_frm_replic_member_t;
++
++typedef struct ioc_compat_fm_pcd_frm_replic_member_params_t {
++    ioc_compat_fm_pcd_frm_replic_member_t       member;
++    ioc_compat_fm_pcd_cc_next_engine_params_t          next_engine_params;
++} ioc_compat_fm_pcd_frm_replic_member_params_t;
++
++typedef struct ioc_compat_fm_vsp_params_t {
++    compat_uptr_t       p_fm;                 /**< A handle to the FM object this VSP related to */
++    ioc_fm_ext_pools    ext_buf_pools;        /**< Which external buffer pools are used
++                                                   (up to FM_PORT_MAX_NUM_OF_EXT_POOLS), and their sizes.
++                                                   parameter associated with Rx / OP port */
++    uint16_t            liodn_offset;         /**< VSP's LIODN offset */
++    struct {
++        ioc_fm_port_type port_type;           /**< Port type */
++        uint8_t          port_id;             /**< Port Id - relative to type */
++    } port_params;
++    uint8_t             relative_profile_id;  /**< VSP Id - relative to VSP's range
++                                                   defined in relevant FM object */
++    compat_uptr_t       id;                 /**< return value */
++} ioc_compat_fm_vsp_params_t;
++
++typedef struct ioc_compat_fm_buf_pool_depletion_params_t {
++    compat_uptr_t p_fm_vsp;
++    ioc_fm_buf_pool_depletion_t fm_buf_pool_depletion;
++} ioc_compat_fm_buf_pool_depletion_params_t;
++
++typedef struct ioc_compat_fm_buffer_prefix_content_params_t {
++    compat_uptr_t p_fm_vsp;
++    ioc_fm_buffer_prefix_content_t fm_buffer_prefix_content;
++} ioc_compat_fm_buffer_prefix_content_params_t;
++
++typedef struct ioc_compat_fm_vsp_config_no_sg_params_t {
++    compat_uptr_t p_fm_vsp;
++    bool no_sg;
++} ioc_compat_fm_vsp_config_no_sg_params_t;
++
++typedef struct ioc_compat_fm_vsp_prs_result_params_t {
++    compat_uptr_t p_fm_vsp;
++    compat_uptr_t p_data;
++} ioc_compat_fm_vsp_prs_result_params_t;
++
++#endif /* (DPAA_VERSION >= 11) */
++typedef struct ioc_compat_fm_pcd_kg_scheme_spc_t {
++    uint32_t        val;
++    compat_uptr_t   id;
++} ioc_compat_fm_pcd_kg_scheme_spc_t;
++
++typedef struct ioc_compat_fm_ctrl_mon_counters_params_t {
++    uint8_t     fm_ctrl_index;
++    compat_uptr_t p_mon;
++} ioc_compat_fm_ctrl_mon_counters_params_t;
++
++typedef struct ioc_compat_fm_pcd_cc_tbl_get_stats_t {
++    compat_uptr_t                   id;
++    uint16_t                        key_index;
++    ioc_fm_pcd_cc_key_statistics_t  statistics;
++} ioc_compat_fm_pcd_cc_tbl_get_stats_t;
++
++
++/* } pcd compat structures */
++
++void compat_obj_delete(
++        ioc_compat_fm_obj_t *compat_id,
++        ioc_fm_obj_t *id);
++
++/* pcd compat functions { */
++void compat_copy_fm_pcd_plcr_profile(
++        ioc_compat_fm_pcd_plcr_profile_params_t *compat_param,
++        ioc_fm_pcd_plcr_profile_params_t *param,
++        uint8_t compat);
++
++void compat_copy_fm_pcd_cc_key(
++        ioc_compat_fm_pcd_cc_key_params_t *compat_param,
++        ioc_fm_pcd_cc_key_params_t *param,
++        uint8_t compat);
++
++void compat_copy_fm_pcd_cc_node_modify_key_and_next_engine(
++        ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param,
++        ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param,
++        uint8_t compat);
++
++void compat_copy_fm_pcd_cc_node_modify_next_engine(
++        ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param,
++        ioc_fm_pcd_cc_node_modify_next_engine_params_t *param,
++        uint8_t compat);
++
++void compat_fm_pcd_cc_tree_modify_next_engine(
++        ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *compat_param,
++        ioc_fm_pcd_cc_tree_modify_next_engine_params_t *param,
++        uint8_t compat);
++
++void compat_copy_fm_pcd_hash_table(
++        ioc_compat_fm_pcd_hash_table_params_t *compat_param,
++        ioc_fm_pcd_hash_table_params_t *param,
++        uint8_t compat);
++
++void compat_copy_fm_pcd_cc_grp(
++        ioc_compat_fm_pcd_cc_grp_params_t *compat_param,
++        ioc_fm_pcd_cc_grp_params_t *param,
++        uint8_t compat);
++
++void compat_copy_fm_pcd_cc_tree(
++        ioc_compat_fm_pcd_cc_tree_params_t *compat_param,
++        ioc_fm_pcd_cc_tree_params_t *param,
++        uint8_t compat);
++
++void compat_copy_fm_pcd_cc_tbl_get_stats(
++        ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param,
++        ioc_fm_pcd_cc_tbl_get_stats_t *param,
++        uint8_t compat);
++
++void compat_fm_pcd_prs_sw(
++        ioc_compat_fm_pcd_prs_sw_params_t *compat_param,
++        ioc_fm_pcd_prs_sw_params_t *param,
++        uint8_t compat);
++
++void compat_copy_fm_pcd_kg_scheme(
++        ioc_compat_fm_pcd_kg_scheme_params_t *compat_param,
++        ioc_fm_pcd_kg_scheme_params_t *param,
++        uint8_t compat);
++
++void compat_copy_fm_pcd_kg_scheme_select(
++        ioc_compat_fm_pcd_kg_scheme_select_t *compat_param,
++        ioc_fm_pcd_kg_scheme_select_t *param,
++        uint8_t compat);
++
++void compat_copy_fm_pcd_kg_schemes_params(
++        ioc_compat_fm_pcd_port_schemes_params_t *compat_param,
++        ioc_fm_pcd_port_schemes_params_t *param,
++        uint8_t compat);
++
++void compat_copy_fm_port_pcd_kg(
++        ioc_compat_fm_port_pcd_kg_params_t *compat_param,
++        ioc_fm_port_pcd_kg_params_t *param,
++        uint8_t compat);
++
++void compat_copy_fm_port_pcd(
++        ioc_compat_fm_port_pcd_params_t *compat_param,
++        ioc_fm_port_pcd_params_t *param,
++        uint8_t compat);
++
++#if (DPAA_VERSION >= 11)
++void compat_copy_fm_port_vsp_alloc_params(
++        ioc_compat_fm_port_vsp_alloc_params_t *compat_param,
++        ioc_fm_port_vsp_alloc_params_t *param,
++        uint8_t compat);
++#endif /* (DPAA_VERSION >= 11) */
++
++void compat_copy_fm_pcd_net_env(
++        ioc_compat_fm_pcd_net_env_params_t *compat_param,
++        ioc_fm_pcd_net_env_params_t *param,
++        uint8_t compat);
++
++void compat_copy_fm_pcd_cc_node_modify_key(
++        ioc_compat_fm_pcd_cc_node_modify_key_params_t *compat_param,
++        ioc_fm_pcd_cc_node_modify_key_params_t *param,
++        uint8_t compat);
++
++void compat_copy_keys(
++        ioc_compat_keys_params_t *compat_param,
++        ioc_keys_params_t *param,
++        uint8_t compat);
++
++void compat_copy_fm_pcd_cc_node(
++        ioc_compat_fm_pcd_cc_node_params_t *compat_param,
++        ioc_fm_pcd_cc_node_params_t *param,
++        uint8_t compat);
++
++void compat_fm_pcd_manip_set_node(
++        ioc_compat_fm_pcd_manip_params_t *compat_param,
++        ioc_fm_pcd_manip_params_t *param,
++        uint8_t compat);
++
++void compat_copy_fm_pcd_manip_get_stats(
++      ioc_compat_fm_pcd_manip_get_stats_t *compat_param,
++      ioc_fm_pcd_manip_get_stats_t *param,
++      uint8_t compat);
++
++void compat_copy_fm_port_pcd_modify_tree(
++        ioc_compat_fm_obj_t *compat_id,
++        ioc_fm_obj_t *id,
++        uint8_t compat);
++
++#if (DPAA_VERSION >= 11)
++void compat_copy_fm_pcd_frm_replic_group_params(
++      ioc_compat_fm_pcd_frm_replic_group_params_t *compat_param,
++      ioc_fm_pcd_frm_replic_group_params_t *param,
++      uint8_t compat);
++
++void compat_copy_fm_pcd_frm_replic_member(
++      ioc_compat_fm_pcd_frm_replic_member_t *compat_param,
++      ioc_fm_pcd_frm_replic_member_t *param,
++      uint8_t compat);
++
++void compat_copy_fm_pcd_frm_replic_member_params(
++      ioc_compat_fm_pcd_frm_replic_member_params_t *compat_param,
++      ioc_fm_pcd_frm_replic_member_params_t *param,
++      uint8_t compat);
++
++void compat_copy_fm_vsp_params(
++    ioc_compat_fm_vsp_params_t *compat_param,
++    ioc_fm_vsp_params_t *param,
++    uint8_t compat);
++
++void compat_copy_fm_buf_pool_depletion_params(
++    ioc_compat_fm_buf_pool_depletion_params_t *compat_param,
++    ioc_fm_buf_pool_depletion_params_t *param,
++    uint8_t compat);
++
++void compat_copy_fm_buffer_prefix_content_params(
++    ioc_compat_fm_buffer_prefix_content_params_t *compat_param,
++    ioc_fm_buffer_prefix_content_params_t *param,
++    uint8_t compat);
++
++void compat_copy_fm_vsp_config_no_sg_params(
++    ioc_compat_fm_vsp_config_no_sg_params_t *compat_param,
++    ioc_fm_vsp_config_no_sg_params_t *param,
++    uint8_t compat);
++
++void compat_copy_fm_vsp_prs_result_params(
++    ioc_compat_fm_vsp_prs_result_params_t *compat_param,
++    ioc_fm_vsp_prs_result_params_t *param,
++    uint8_t compat);
++
++#endif /* (DPAA_VERSION >= 11) */
++
++void compat_copy_fm_pcd_kg_scheme_spc(
++        ioc_compat_fm_pcd_kg_scheme_spc_t *compat_param,
++        ioc_fm_pcd_kg_scheme_spc_t *param,
++        uint8_t compat);
++
++/* } pcd compat functions */
++#endif
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources.h
+@@ -0,0 +1,121 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ @File          lnxwrp_resources.h
++
++ @Description   FMD wrapper resource allocation functions.
++
++*/
++
++#ifndef LNXWRP_RESOURCES_H_
++#define LNXWRP_RESOURCES_H_
++
++#if !defined(FMAN_RESOURCES_UNIT_TEST)
++#include "lnxwrp_fm.h"
++#else
++#include "lnxwrp_resources_ut.h"
++#endif
++
++#define ROUND(X) ((2*(X)+1)/2)
++#define CEIL(X) ((X)+1)
++/* #define ROUND_DIV(X, Y) (((X)+(Y)/2)/(Y)) */
++#define ROUND_DIV(X, Y) ((2*(X)+(Y))/(2*(Y)))
++#define CEIL_DIV(X, Y) (((X)+(Y)-1)/(Y))
++
++/* used for resource calculus */
++#define DPDE_1G 2     /* DQDP 1g - from LLD:
++                              DEFAULT_PORT_txFifoDeqPipelineDepth_1G */
++#define DPDE_10G 8    /* DQDP 10g - from LLD:
++                              DEFAULT_PORT_txFifoDeqPipelineDepth_10G */
++
++int fm_set_active_fman_ports(struct platform_device *of_dev,
++                        t_LnxWrpFmDev *p_LnxWrpFmDev);
++
++/* Calculate the fifosize based on MURAM allocation, number of ports, dpde
++ * value and s/g software support (! Kernel does not suport s/g).
++ *
++ * Algorithm summary:
++ * - Calculate the the minimum fifosize required for every type of port
++ * (TX,RX for 1G, 2.5G and 10G).
++ * - Set TX the minimum fifosize required.
++ * - Distribute the remaining buffers (after all TX were set) to RX ports
++ * based on:
++ *   1G   RX = Remaining_buffers * 1/(1+2.5+10)
++ *   2.5G RX = Remaining_buffers * 2.5/(1+2.5+10)
++ *   10G  RX = Remaining_buffers * 10/(1+2.5+10)
++ * - if the RX is smaller than the minimum required, then set the minimum
++ * required
++ * - In the end distribuite the leftovers if there are any (due to
++ * unprecise calculus) or if over allocation cat some buffers from all RX
++ * ports w/o pass over minimum required treshold, but if there must be
++ * pass the treshold in order to cat the over allocation ,then this
++ * configuration can not be set - KERN_ALERT.
++*/
++int fm_precalculate_fifosizes(t_LnxWrpFmDev *p_LnxWrpFmDev,
++                         int muram_fifo_size);
++
++#if !defined(FMAN_RESOURCES_UNIT_TEST)
++int fm_config_precalculate_fifosize(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev);
++#endif
++
++/* Compute FMan open DMA based on total number of open DMAs and
++ * number of available fman ports.
++ *
++ * By default 10g ports are set to input parameters. The other ports
++ * tries to keep the proportion rx=2tx open dmas or tresholds.
++ *
++ * If leftovers, then those will be set as shared.
++ *
++ * If after computing overflow appears, then it decrements open dma
++ * for all ports w/o cross the tresholds. If the tresholds are meet
++ * and is still overflow, then it returns error.
++*/
++int fm_precalculate_open_dma(t_LnxWrpFmDev *p_LnxWrpFmDev,
++                        int max_fm_open_dma,
++                        int default_tx_10g_dmas,
++                        int default_rx_10g_dmas,
++                        int min_tx_10g_treshold, int min_rx_10g_treshold);
++
++#if !defined(FMAN_RESOURCES_UNIT_TEST)
++int fm_config_precalculate_open_dma(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev);
++#endif
++
++/* Compute FMan tnums based on available tnums and number of ports.
++ * Set defaults (minim tresholds) and then distribute leftovers.*/
++int fm_precalculate_tnums(t_LnxWrpFmDev *p_LnxWrpFmDev, int max_fm_tnums);
++
++#if !defined(FMAN_RESOURCES_UNIT_TEST)
++int fm_config_precalculate_tnums(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev);
++#endif
++
++#endif /* LNXWRP_RESOURCES_H_ */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.c
+@@ -0,0 +1,191 @@
++/* Copyright (c) 2012 Freescale Semiconductor, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "lnxwrp_resources.h"
++#include "lnxwrp_resources_ut.h"
++
++#define KILOBYTE 0x400 /* 1024 */
++
++typedef enum e_board_type {
++      e_p3041,
++      e_p4080,
++      e_p5020,
++      e_p1023
++} e_board_type;
++
++uint8_t board_type;
++uint32_t muram_size = 0;
++uint32_t dmas_num = 0;
++uint32_t task_num = 0;
++uint32_t frame_size = 0;
++uint32_t oh_num = 0;
++uint32_t num_ports_1g = 0;
++uint32_t num_ports_10g = 0;
++uint32_t num_ports_2g5 = 0;
++uint32_t fsl_fman_phy_maxfrm = 0;
++uint32_t dpa_rx_extra_headroom = 0;
++
++void show_help(void){
++      printf(" help: \n");
++      printf(" -b <board_type> -f <max_fram_size(mtu)> -o <num_oh_ports> -g1"
++              " <num_1g_ports> -g10 <num_10g_ports> -g25 <num_2g5_ports>\n");
++      printf("    Maxim num of DMAS availbale:  P3/P4/P5:32 ,  P1023:16 \n");
++      printf("    Maxim num of TNUMs availbale: P3/P4/P5:128,  P1023:32 \n");
++      printf("    Muram size:                   P3/P4/P5:160K, P1023:64K \n");
++      printf("    Number of ports:\n");
++      printf("        P3/P5: 5p 1g, 1p 10g, 7p oh \n");
++      printf("        P4   : 4p 1g, 1p 10g, 7p oh \n");
++      printf("        P1   : 2p 1g, 0p 10g, 4p oh \n");
++      printf("    MTU: Default:1522, Jumbo:9600 \n");
++}
++
++int fm_set_param(t_LnxWrpFmDev *p_LnxWrpFmDev) {
++      struct fm_active_ports *fm_active_ports_info = NULL;
++      fm_active_ports_info = &p_LnxWrpFmDev->fm_active_ports_info;
++
++      switch(board_type){
++              case e_p3041:
++              case e_p5020:
++                      muram_size = 160*KILOBYTE;
++                      dmas_num = 32;
++                      task_num = 128;
++                      if ((num_ports_1g+num_ports_2g5) > 5 || num_ports_10g > 1 || oh_num > 7)
++                              goto err_fm_set_param;
++              break;
++              case e_p4080:
++                      muram_size = 160*KILOBYTE;
++                      dmas_num = 32;
++                      task_num = 128;
++                      if ((num_ports_1g+num_ports_2g5) > 4 || num_ports_10g > 1 || oh_num > 7)
++                              goto err_fm_set_param;
++              break;
++              case e_p1023:
++                      muram_size = 64*KILOBYTE;
++                      dmas_num = 16;
++                      task_num = 128;
++                      if ((num_ports_1g+num_ports_2g5) > 2 || oh_num > 4)
++                              goto err_fm_set_param;
++              break;
++              default:
++                      goto err_fm_set_param;
++              break;
++      }
++
++      p_LnxWrpFmDev->id = 0;
++      fsl_fman_phy_maxfrm = frame_size;
++      dpa_rx_extra_headroom = 0; /* ATTENTION: can be != 0 */
++      fm_active_ports_info->num_oh_ports = oh_num;
++      fm_active_ports_info->num_tx_ports = num_ports_1g;
++      fm_active_ports_info->num_rx_ports = num_ports_1g;
++      fm_active_ports_info->num_tx25_ports = num_ports_2g5;
++      fm_active_ports_info->num_rx25_ports = num_ports_2g5;
++      fm_active_ports_info->num_tx10_ports = num_ports_10g;
++      fm_active_ports_info->num_rx10_ports = num_ports_10g;
++
++      return 0;
++
++err_fm_set_param:
++      printf(" ERR: To many ports!!! \n");
++      return -1;
++}
++
++int main (int argc, char *argv[]){
++      t_LnxWrpFmDev LnxWrpFmDev;
++      t_LnxWrpFmDev *p_LnxWrpFmDev = &LnxWrpFmDev;
++      int tokens_cnt = 1;
++
++      char *token = NULL;
++
++      while(tokens_cnt < argc)
++      {
++              token = argv[tokens_cnt++];
++              if (strcmp(token, "-b") == 0){
++                      if(strcmp(argv[tokens_cnt],"p3") == 0)
++                              board_type = e_p3041;
++                      else if(strcmp(argv[tokens_cnt],"p4") == 0)
++                              board_type = e_p4080;
++                      else if(strcmp(argv[tokens_cnt],"p5") == 0)
++                              board_type = e_p5020;
++                      else if(strcmp(argv[tokens_cnt],"p1") == 0)
++                              board_type = e_p1023;
++                      else
++                              show_help();
++                      tokens_cnt++;
++              }
++              else if(strcmp(token, "-d") == 0){
++                      dmas_num = atoi(argv[tokens_cnt++]);
++              }
++              else if(strcmp(token, "-t") == 0)
++                      task_num = atoi(argv[tokens_cnt++]);
++              else if(strcmp(token, "-f") == 0)
++                      frame_size = atoi(argv[tokens_cnt++]);
++              else if(strcmp(token, "-o") == 0)
++                      oh_num = atoi(argv[tokens_cnt++]);
++              else if(strcmp(token, "-g1") == 0)
++                      num_ports_1g = atoi(argv[tokens_cnt++]);
++              else if(strcmp(token, "-g10") == 0)
++                      num_ports_10g = atoi(argv[tokens_cnt++]);
++              else if(strcmp(token, "-g25") == 0)
++                      num_ports_2g5 = atoi(argv[tokens_cnt++]);
++              else {
++                      show_help();
++                      return -1;
++              }
++      }
++
++      if(fm_set_param(p_LnxWrpFmDev) < 0){
++              show_help();
++              return -1;
++      }
++
++      if(fm_precalculate_fifosizes(
++              p_LnxWrpFmDev,
++              128*KILOBYTE)
++              != 0)
++              return -1;
++      if(fm_precalculate_open_dma(
++              p_LnxWrpFmDev,
++              dmas_num,                   /* max open dmas:dpaa_integration_ext.h */
++              FM_DEFAULT_TX10G_OPENDMA,   /* default TX 10g open dmas */
++              FM_DEFAULT_RX10G_OPENDMA,   /* default RX 10g open dmas */
++              FM_10G_OPENDMA_MIN_TRESHOLD,/* TX 10g minimum treshold */
++              FM_10G_OPENDMA_MIN_TRESHOLD)/* RX 10g minimum treshold */
++              != 0)
++              return -1;
++      if(fm_precalculate_tnums(
++              p_LnxWrpFmDev,
++              task_num) /* max TNUMS: dpa integration file. */
++              != 0)
++               return -1;
++
++      return 0;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.h
+@@ -0,0 +1,144 @@
++/* Copyright (c) 2012 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef FM_RESS_TEST_H_
++#define FM_RESS_TEST_H_
++
++#include <stdint.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <assert.h>
++#include <string.h>
++#include <stdlib.h>
++
++#define _Packed
++#define _PackedType __attribute__ ((packed))
++#define MAX(x, y) (((x) > (y)) ? (x) : (y))
++#define MIN(x, y) (((x) < (y)) ? (x) : (y))
++#define KERN_ALERT ""
++#define KERN_INFO ""
++#define ASSERT_COND assert
++#define printk printf
++#define NET_IP_ALIGN 0
++#define FM_FIFO_ALLOCATION_OLD_ALG
++
++#if defined(CONFIG_FMAN_DISABLE_OH_AND_DISTRIBUTE_RESOURCES)
++#define FM_10G_OPENDMA_MIN_TRESHOLD 8 /* 10g minimum treshold if only HC is enabled and no OH port enabled */
++#define FM_OPENDMA_RX_TX_RAPORT 2 /* RX = 2*TX */
++#else
++#define FM_10G_OPENDMA_MIN_TRESHOLD 7 /* 10g minimum treshold if 7 OH ports are enabled */
++#define FM_OPENDMA_RX_TX_RAPORT 1 /* RX = TX */
++#endif
++#define FM_DEFAULT_TX10G_OPENDMA 8 /* default TX 10g open dmas */
++#define FM_DEFAULT_RX10G_OPENDMA 8 /* default RX 10g open dmas */
++
++/* information about all active ports for an FMan.
++ * !Some ports may be disabled by u-boot, thus will not be available */
++struct fm_active_ports {
++    uint32_t num_oh_ports;
++    uint32_t num_tx_ports;
++    uint32_t num_rx_ports;
++    uint32_t num_tx25_ports;
++    uint32_t num_rx25_ports;
++    uint32_t num_tx10_ports;
++    uint32_t num_rx10_ports;
++};
++
++/* FMan resources precalculated at fm probe based
++ * on available FMan port. */
++struct fm_resource_settings {
++    /* buffers - fifo sizes */
++    uint32_t tx1g_num_buffers;
++    uint32_t rx1g_num_buffers;
++    uint32_t tx2g5_num_buffers; /* Not supported yet by LLD */
++    uint32_t rx2g5_num_buffers; /* Not supported yet by LLD */
++    uint32_t tx10g_num_buffers;
++    uint32_t rx10g_num_buffers;
++    uint32_t oh_num_buffers;
++    uint32_t shared_ext_buffers;
++
++
++    /* open DMAs */
++    uint32_t tx_1g_dmas;
++    uint32_t rx_1g_dmas;
++    uint32_t tx_2g5_dmas; /* Not supported yet by LLD */
++    uint32_t rx_2g5_dmas; /* Not supported yet by LLD */
++    uint32_t tx_10g_dmas;
++    uint32_t rx_10g_dmas;
++    uint32_t oh_dmas;
++    uint32_t shared_ext_open_dma;
++
++    /* Tnums */
++    uint32_t tx_1g_tnums;
++    uint32_t rx_1g_tnums;
++    uint32_t tx_2g5_tnums; /* Not supported yet by LLD */
++    uint32_t rx_2g5_tnums; /* Not supported yet by LLD */
++    uint32_t tx_10g_tnums;
++    uint32_t rx_10g_tnums;
++    uint32_t oh_tnums;
++    uint32_t shared_ext_tnums;
++};
++
++typedef struct {
++      uint8_t                     id;
++    struct fm_active_ports      fm_active_ports_info;
++    struct fm_resource_settings fm_resource_settings_info;
++} t_LnxWrpFmDev;
++
++typedef struct {
++      uint8_t                     id;
++} t_LnxWrpFmPortDev;
++
++typedef _Packed struct t_FmPrsResult {
++      volatile uint8_t     lpid;               /**< Logical port id */
++      volatile uint8_t     shimr;              /**< Shim header result  */
++      volatile uint16_t    l2r;                /**< Layer 2 result */
++      volatile uint16_t    l3r;                /**< Layer 3 result */
++      volatile uint8_t     l4r;                /**< Layer 4 result */
++      volatile uint8_t     cplan;              /**< Classification plan id */
++      volatile uint16_t    nxthdr;             /**< Next Header  */
++      volatile uint16_t    cksum;              /**< Checksum */
++      volatile uint32_t    lcv;                /**< LCV */
++      volatile uint8_t     shim_off[3];        /**< Shim offset */
++      volatile uint8_t     eth_off;            /**< ETH offset */
++      volatile uint8_t     llc_snap_off;       /**< LLC_SNAP offset */
++      volatile uint8_t     vlan_off[2];        /**< VLAN offset */
++      volatile uint8_t     etype_off;          /**< ETYPE offset */
++      volatile uint8_t     pppoe_off;          /**< PPP offset */
++      volatile uint8_t     mpls_off[2];        /**< MPLS offset */
++      volatile uint8_t     ip_off[2];          /**< IP offset */
++      volatile uint8_t     gre_off;            /**< GRE offset */
++      volatile uint8_t     l4_off;             /**< Layer 4 offset */
++      volatile uint8_t     nxthdr_off;         /**< Parser end point */
++} _PackedType t_FmPrsResult;
++
++#endif
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.make
+@@ -0,0 +1,28 @@
++CC=gcc
++
++LNXWRP_RESS_UT=lnxwrp_resources_ut
++OBJ=lnxwrp_resources
++
++INC_PATH=
++LIB_PATH=
++
++INC=$(addprefix -I,$(INC_PATH))
++LIB=$(addprefix -L,$(LIB_PATH))
++
++CFLAGS= -gdwarf-2 -g -O0 -Wall
++XFLAGS= -DFMAN_RESOURCES_UNIT_TEST
++
++all: $(LNXWRP_RESS_UT)
++
++$(LNXWRP_RESS_UT):$(addsuffix .o,$(OBJ)) $(LNXWRP_RESS_UT).o
++      $(CC) -o $(LNXWRP_RESS_UT) $(LNXWRP_RESS_UT).o $(addsuffix .o,$(OBJ))
++
++%.o: %.c
++      @(echo "        (CC)  $@")
++      @($(CC) $(INC) $(CFLAGS) $(XFLAGS) -o $(@) -c $<)
++
++.PHONY: clean
++
++clean:
++      rm -f *.o
++      rm -f $(LNXWRP_RESS_UT)
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.c
+@@ -0,0 +1,60 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ @File          lnxwrp_sysfs.c
++
++ @Description   FM wrapper sysfs related functions.
++
++*/
++
++#include <linux/types.h>
++#include "lnxwrp_sysfs.h"
++
++uint8_t fm_find_statistic_counter_by_name(const char *attr_name,
++                              const struct sysfs_stats_t *sysfs_stats,
++                              uint8_t *offset)
++{
++      int i = 0;
++
++      while (sysfs_stats[i].stat_name != NULL) {
++              if (strcmp(sysfs_stats[i].stat_name, attr_name) == 0) {
++                      if (offset != NULL)
++                              *offset = i;
++                      return sysfs_stats[i].stat_counter;
++              }
++
++              i++;
++      }
++      WARN(1, "FMD: Should never get here!");
++      return 0;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.h
+@@ -0,0 +1,60 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef LNXWRP_SYSFS_H_
++#define LNXWRP_SYSFS_H_
++
++/* Linux Headers ------------------- */
++#include <linux/version.h>
++
++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
++#define MODVERSIONS
++#endif
++#ifdef MODVERSIONS
++#include <config/modversions.h>
++#endif /* MODVERSIONS */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/sysfs.h>
++
++struct sysfs_stats_t {
++      const char *stat_name;
++      uint8_t stat_counter;
++};
++
++uint8_t fm_find_statistic_counter_by_name(const char *attr_name,
++                              const struct sysfs_stats_t *sysfs_stats,
++                              uint8_t *offset);
++
++#endif /* LNXWRP_SYSFS_H_ */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c
+@@ -0,0 +1,1855 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "lnxwrp_sysfs.h"
++#include "lnxwrp_sysfs_fm.h"
++#include "lnxwrp_fm.h"
++
++#include "../../sdk_fman/Peripherals/FM/inc/fm_common.h"
++#include "../../sdk_fman/Peripherals/FM/Pcd/fm_pcd.h"
++#include "../../sdk_fman/Peripherals/FM/Pcd/fm_kg.h"
++#include "../../sdk_fman/Peripherals/FM/Pcd/fm_plcr.h"
++
++#if defined(__ERR_MODULE__)
++#undef __ERR_MODULE__
++#endif
++
++#include "../../sdk_fman/Peripherals/FM/fm.h"
++#include <linux/delay.h>
++
++
++static int fm_get_counter(void *h_fm, e_FmCounters cnt_e, uint32_t *cnt_val);
++
++enum fm_dma_match_stats {
++      FM_DMA_COUNTERS_CMQ_NOT_EMPTY,
++      FM_DMA_COUNTERS_BUS_ERROR,
++      FM_DMA_COUNTERS_READ_BUF_ECC_ERROR,
++      FM_DMA_COUNTERS_WRITE_BUF_ECC_SYS_ERROR,
++      FM_DMA_COUNTERS_WRITE_BUF_ECC_FM_ERROR
++};
++
++static const struct sysfs_stats_t fm_sysfs_stats[] = {
++      /* FM statistics */
++      {
++       .stat_name = "enq_total_frame",
++       .stat_counter = e_FM_COUNTERS_ENQ_TOTAL_FRAME,
++       },
++      {
++       .stat_name = "deq_total_frame",
++       .stat_counter = e_FM_COUNTERS_DEQ_TOTAL_FRAME,
++       },
++      {
++       .stat_name = "deq_0",
++       .stat_counter = e_FM_COUNTERS_DEQ_0,
++       },
++      {
++       .stat_name = "deq_1",
++       .stat_counter = e_FM_COUNTERS_DEQ_1,
++       },
++      {
++       .stat_name = "deq_2",
++       .stat_counter = e_FM_COUNTERS_DEQ_2,
++       },
++      {
++       .stat_name = "deq_3",
++       .stat_counter = e_FM_COUNTERS_DEQ_3,
++       },
++      {
++       .stat_name = "deq_from_default",
++       .stat_counter = e_FM_COUNTERS_DEQ_FROM_DEFAULT,
++       },
++      {
++       .stat_name = "deq_from_context",
++       .stat_counter = e_FM_COUNTERS_DEQ_FROM_CONTEXT,
++       },
++      {
++       .stat_name = "deq_from_fd",
++       .stat_counter = e_FM_COUNTERS_DEQ_FROM_FD,
++       },
++      {
++       .stat_name = "deq_confirm",
++       .stat_counter = e_FM_COUNTERS_DEQ_CONFIRM,
++       },
++      /* FM:DMA  statistics */
++      {
++       .stat_name = "cmq_not_empty",
++       .stat_counter = FM_DMA_COUNTERS_CMQ_NOT_EMPTY,
++       },
++      {
++       .stat_name = "bus_error",
++       .stat_counter = FM_DMA_COUNTERS_BUS_ERROR,
++       },
++      {
++       .stat_name = "read_buf_ecc_error",
++       .stat_counter = FM_DMA_COUNTERS_READ_BUF_ECC_ERROR,
++       },
++      {
++       .stat_name = "write_buf_ecc_sys_error",
++       .stat_counter = FM_DMA_COUNTERS_WRITE_BUF_ECC_SYS_ERROR,
++       },
++      {
++       .stat_name = "write_buf_ecc_fm_error",
++       .stat_counter = FM_DMA_COUNTERS_WRITE_BUF_ECC_FM_ERROR,
++       },
++      /* FM:PCD  statistics */
++      {
++       .stat_name = "pcd_kg_total",
++       .stat_counter = e_FM_PCD_KG_COUNTERS_TOTAL,
++       },
++      {
++       .stat_name = "pcd_plcr_yellow",
++       .stat_counter = e_FM_PCD_PLCR_COUNTERS_YELLOW,
++       },
++      {
++       .stat_name = "pcd_plcr_red",
++       .stat_counter = e_FM_PCD_PLCR_COUNTERS_RED,
++       },
++      {
++       .stat_name = "pcd_plcr_recolored_to_red",
++       .stat_counter = e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED,
++       },
++      {
++       .stat_name = "pcd_plcr_recolored_to_yellow",
++       .stat_counter = e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW,
++       },
++      {
++       .stat_name = "pcd_plcr_total",
++       .stat_counter = e_FM_PCD_PLCR_COUNTERS_TOTAL,
++       },
++      {
++       .stat_name = "pcd_plcr_length_mismatch",
++       .stat_counter = e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH,
++       },
++      {
++       .stat_name = "pcd_prs_parse_dispatch",
++       .stat_counter = e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH,
++       },
++      {
++       .stat_name = "pcd_prs_l2_parse_result_returned",
++       .stat_counter = e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED,
++       },
++      {
++       .stat_name = "pcd_prs_l3_parse_result_returned",
++       .stat_counter = e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED,
++       },
++      {
++       .stat_name = "pcd_prs_l4_parse_result_returned",
++       .stat_counter = e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED,
++       },
++      {
++       .stat_name = "pcd_prs_shim_parse_result_returned",
++       .stat_counter = e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED,
++       },
++      {
++       .stat_name = "pcd_prs_l2_parse_result_returned_with_err",
++       .stat_counter =
++       e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR,
++       },
++      {
++       .stat_name = "pcd_prs_l3_parse_result_returned_with_err",
++       .stat_counter =
++       e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR,
++       },
++      {
++       .stat_name = "pcd_prs_l4_parse_result_returned_with_err",
++       .stat_counter =
++       e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR,
++       },
++      {
++       .stat_name = "pcd_prs_shim_parse_result_returned_with_err",
++       .stat_counter =
++       e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR,
++       },
++      {
++       .stat_name = "pcd_prs_soft_prs_cycles",
++       .stat_counter = e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES,
++       },
++      {
++       .stat_name = "pcd_prs_soft_prs_stall_cycles",
++       .stat_counter = e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES,
++       },
++      {
++       .stat_name = "pcd_prs_hard_prs_cycle_incl_stall_cycles",
++       .stat_counter =
++       e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES,
++       },
++      {
++       .stat_name = "pcd_prs_muram_read_cycles",
++       .stat_counter = e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES,
++       },
++      {
++       .stat_name = "pcd_prs_muram_read_stall_cycles",
++       .stat_counter = e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES,
++       },
++      {
++       .stat_name = "pcd_prs_muram_write_cycles",
++       .stat_counter = e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES,
++       },
++      {
++       .stat_name = "pcd_prs_muram_write_stall_cycles",
++       .stat_counter = e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES,
++       },
++      {
++       .stat_name = "pcd_prs_fpm_command_stall_cycles",
++       .stat_counter = e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES,
++       },
++      {}
++};
++
++
++static ssize_t show_fm_risc_load(struct device *dev,
++                      struct device_attribute *attr, char *buf)
++{
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++      unsigned long flags;
++      int m =0;
++      int err =0;
++      unsigned n = 0;
++      t_FmCtrlMon     util;
++      uint8_t         i =0 ;
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev)
++              return -EIO;
++
++      local_irq_save(flags);
++
++      /* Calculate risc load */
++      FM_CtrlMonStart(p_wrp_fm_dev->h_Dev);
++      msleep(1000);
++      FM_CtrlMonStop(p_wrp_fm_dev->h_Dev);
++
++      for (i = 0; i < FM_NUM_OF_CTRL; i++) {
++              err |= FM_CtrlMonGetCounters(p_wrp_fm_dev->h_Dev, i, &util);
++              m = snprintf(&buf[n],PAGE_SIZE,"\tRisc%u: util-%u%%, efficiency-%u%%\n",
++                              i, util.percentCnt[0], util.percentCnt[1]);
++              n=m+n;
++      }
++
++      local_irq_restore(flags);
++
++      return n;
++}
++
++/* Fm stats and regs dumps via sysfs */
++static ssize_t show_fm_dma_stats(struct device *dev,
++                              struct device_attribute *attr, char *buf)
++{
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++      t_FmDmaStatus dma_status;
++      unsigned long flags = 0;
++      unsigned n = 0;
++      uint8_t counter_value = 0, counter = 0;
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev)
++              return -EIO;
++
++      counter = fm_find_statistic_counter_by_name(
++                      attr->attr.name,
++                      fm_sysfs_stats, NULL);
++
++      local_irq_save(flags);
++
++      memset(&dma_status, 0, sizeof(dma_status));
++      FM_GetDmaStatus(p_wrp_fm_dev->h_Dev, &dma_status);
++
++      switch (counter) {
++      case FM_DMA_COUNTERS_CMQ_NOT_EMPTY:
++              counter_value = dma_status.cmqNotEmpty;
++              break;
++      case FM_DMA_COUNTERS_BUS_ERROR:
++              counter_value = dma_status.busError;
++              break;
++      case FM_DMA_COUNTERS_READ_BUF_ECC_ERROR:
++              counter_value = dma_status.readBufEccError;
++              break;
++      case FM_DMA_COUNTERS_WRITE_BUF_ECC_SYS_ERROR:
++              counter_value = dma_status.writeBufEccSysError;
++              break;
++      case FM_DMA_COUNTERS_WRITE_BUF_ECC_FM_ERROR:
++              counter_value = dma_status.writeBufEccFmError;
++              break;
++      default:
++              WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__,
++                      __func__);
++              break;
++      };
++
++      n = snprintf(buf, PAGE_SIZE, "\tFM %u counter: %c\n",
++              p_wrp_fm_dev->id, counter_value ? 'T' : 'F');
++
++      local_irq_restore(flags);
++
++      return n;
++}
++
++static ssize_t show_fm_stats(struct device *dev,
++                           struct device_attribute *attr, char *buf)
++{
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++      unsigned long flags = 0;
++      unsigned n = 0, cnt_e = 0;
++      uint32_t cnt_val;
++      int err;
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev)
++              return -EIO;
++
++      cnt_e = fm_find_statistic_counter_by_name(
++                      attr->attr.name,
++                      fm_sysfs_stats, NULL);
++
++      err = fm_get_counter(p_wrp_fm_dev->h_Dev,
++              (e_FmCounters) cnt_e, &cnt_val);
++
++      if (err)
++              return err;
++
++      local_irq_save(flags);
++
++      n = snprintf(buf, PAGE_SIZE, "\tFM %d counter: %d\n",
++                      p_wrp_fm_dev->id, cnt_val);
++
++      local_irq_restore(flags);
++
++      return n;
++}
++
++static ssize_t show_fm_muram_free_sz(struct device *dev,
++                              struct device_attribute *attr, char *buf)
++{
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++      unsigned long flags = 0;
++      unsigned n = 0;
++      uint64_t muram_free_size = 0;
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev)
++              return -EIO;
++
++      muram_free_size = FM_MURAM_GetFreeMemSize(p_wrp_fm_dev->h_MuramDev);
++
++      local_irq_save(flags);
++
++      n = snprintf(buf, PAGE_SIZE, "\tFM %d muram_free_size: %lld\n",
++                      p_wrp_fm_dev->id, muram_free_size);
++
++      local_irq_restore(flags);
++
++      return n;
++}
++
++static ssize_t show_fm_ctrl_code_ver(struct device *dev,
++                              struct device_attribute *attr, char *buf)
++{
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++      unsigned long flags = 0;
++      unsigned n = 0;
++      t_FmCtrlCodeRevisionInfo rv_info;
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev)
++              return -EIO;
++
++      FM_GetFmanCtrlCodeRevision((t_Fm *)p_wrp_fm_dev->h_Dev, &rv_info);
++
++      local_irq_save(flags);
++
++      FM_DMP_LN(buf, n, "- FM %d ctrl code pkg info:\n", p_wrp_fm_dev->id);
++      FM_DMP_LN(buf, n, "Package rev: %d\n", rv_info.packageRev);
++      FM_DMP_LN(buf, n, "major rev: %d\n", rv_info.majorRev);
++      FM_DMP_LN(buf, n, "minor rev: %d\n", rv_info.minorRev);
++
++      local_irq_restore(flags);
++
++      return n;
++}
++
++static ssize_t show_fm_pcd_stats(struct device *dev,
++                              struct device_attribute *attr, char *buf)
++{
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++      unsigned long flags = 0;
++      unsigned n = 0, counter = 0;
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev ||
++                      !p_wrp_fm_dev->h_PcdDev)
++              return -EIO;
++
++      counter = fm_find_statistic_counter_by_name(
++                      attr->attr.name,
++                      fm_sysfs_stats, NULL);
++
++      local_irq_save(flags);
++
++      n = snprintf(buf, PAGE_SIZE, "\tFM %d counter: %d\n",
++                      p_wrp_fm_dev->id,
++                      FM_PCD_GetCounter(p_wrp_fm_dev->h_PcdDev,
++                                      (e_FmPcdCounters) counter));
++
++      local_irq_restore(flags);
++
++      return n;
++}
++
++static ssize_t show_fm_tnum_dbg(struct device *dev,
++                              struct device_attribute *attr,
++                              char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++#endif
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      local_irq_save(flags);
++
++      if (!p_wrp_fm_dev->active)
++              return -EIO;
++      else {
++              int tn_s;
++
++              if (!sscanf(attr->attr.name, "tnum_dbg_%d", &tn_s))
++                      return -EINVAL;
++
++              n = fm_dump_tnum_dbg(p_wrp_fm_dev->h_Dev,
++                                      tn_s, tn_s + 15, buf, n);
++      }
++      local_irq_restore(flags);
++#else
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                      "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++      return n;
++}
++
++static ssize_t show_fm_cls_plan(struct device *dev,
++                              struct device_attribute *attr,
++                              char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++#endif
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      local_irq_save(flags);
++
++      n = snprintf(buf, PAGE_SIZE, "\n FM-KG classification plan dump.\n");
++
++      if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev)
++              return -EIO;
++      else {
++              int cpn;
++
++              if (!sscanf(attr->attr.name, "cls_plan_%d", &cpn))
++                      return -EINVAL;
++
++              n = fm_dump_cls_plan(p_wrp_fm_dev->h_PcdDev, cpn, buf, n);
++      }
++      local_irq_restore(flags);
++#else
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                      "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++      return n;
++}
++
++static ssize_t show_fm_profiles(struct device *dev,
++                              struct device_attribute *attr,
++                              char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++#endif
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      local_irq_save(flags);
++
++      n = snprintf(buf, PAGE_SIZE, "FM policer profile dump.\n");
++
++      if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev)
++              return -EIO;
++      else {
++              int pn;
++
++              if (!sscanf(attr->attr.name, "profile_%d", &pn))
++                      return -EINVAL;
++
++              n = fm_profile_dump_regs(p_wrp_fm_dev->h_PcdDev, pn, buf, n);
++      }
++      local_irq_restore(flags);
++#else
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                      "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++      return n;
++}
++
++static ssize_t show_fm_schemes(struct device *dev,
++                              struct device_attribute *attr,
++                              char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++#endif
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      local_irq_save(flags);
++
++      n = snprintf(buf, PAGE_SIZE, "FM-KG driver schemes dump.\n");
++
++      if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev)
++              return -EIO;
++      else {
++              int sn;
++
++              if (!sscanf(attr->attr.name, "scheme_%d", &sn))
++                      return -EINVAL;
++
++              n = fm_dump_scheme(p_wrp_fm_dev->h_PcdDev, sn, buf, n);
++      }
++      local_irq_restore(flags);
++#else
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                   "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++      return n;
++}
++
++/* FM */
++static DEVICE_ATTR(enq_total_frame, S_IRUGO, show_fm_stats, NULL);
++static DEVICE_ATTR(deq_total_frame, S_IRUGO, show_fm_stats, NULL);
++static DEVICE_ATTR(fm_risc_load_val, S_IRUGO, show_fm_risc_load, NULL);
++static DEVICE_ATTR(deq_0, S_IRUGO, show_fm_stats, NULL);
++static DEVICE_ATTR(deq_1, S_IRUGO, show_fm_stats, NULL);
++static DEVICE_ATTR(deq_2, S_IRUGO, show_fm_stats, NULL);
++static DEVICE_ATTR(deq_3, S_IRUGO, show_fm_stats, NULL);
++static DEVICE_ATTR(deq_from_default, S_IRUGO, show_fm_stats, NULL);
++static DEVICE_ATTR(deq_from_context, S_IRUGO, show_fm_stats, NULL);
++static DEVICE_ATTR(deq_from_fd, S_IRUGO, show_fm_stats, NULL);
++static DEVICE_ATTR(deq_confirm, S_IRUGO, show_fm_stats, NULL);
++/* FM:DMA */
++static DEVICE_ATTR(cmq_not_empty, S_IRUGO, show_fm_dma_stats, NULL);
++static DEVICE_ATTR(bus_error, S_IRUGO, show_fm_dma_stats, NULL);
++static DEVICE_ATTR(read_buf_ecc_error, S_IRUGO, show_fm_dma_stats, NULL);
++static DEVICE_ATTR(write_buf_ecc_sys_error, S_IRUGO, show_fm_dma_stats, NULL);
++static DEVICE_ATTR(write_buf_ecc_fm_error, S_IRUGO, show_fm_dma_stats, NULL);
++/* FM:PCD */
++static DEVICE_ATTR(pcd_kg_total, S_IRUGO, show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_plcr_yellow, S_IRUGO, show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_plcr_red, S_IRUGO, show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_plcr_recolored_to_red, S_IRUGO, show_fm_pcd_stats,
++                 NULL);
++static DEVICE_ATTR(pcd_plcr_recolored_to_yellow, S_IRUGO, show_fm_pcd_stats,
++                 NULL);
++static DEVICE_ATTR(pcd_plcr_total, S_IRUGO, show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_plcr_length_mismatch, S_IRUGO, show_fm_pcd_stats,
++                 NULL);
++static DEVICE_ATTR(pcd_prs_parse_dispatch, S_IRUGO, show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_prs_l2_parse_result_returned, S_IRUGO,
++                 show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_prs_l3_parse_result_returned, S_IRUGO,
++                 show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_prs_l4_parse_result_returned, S_IRUGO,
++                 show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_prs_shim_parse_result_returned, S_IRUGO,
++                 show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_prs_l2_parse_result_returned_with_err, S_IRUGO,
++                 show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_prs_l3_parse_result_returned_with_err, S_IRUGO,
++                 show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_prs_l4_parse_result_returned_with_err, S_IRUGO,
++                 show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_prs_shim_parse_result_returned_with_err, S_IRUGO,
++                 show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_prs_soft_prs_cycles, S_IRUGO, show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_prs_soft_prs_stall_cycles, S_IRUGO, show_fm_pcd_stats,
++                 NULL);
++static DEVICE_ATTR(pcd_prs_hard_prs_cycle_incl_stall_cycles, S_IRUGO,
++                 show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_prs_muram_read_cycles, S_IRUGO, show_fm_pcd_stats,
++                 NULL);
++static DEVICE_ATTR(pcd_prs_muram_read_stall_cycles, S_IRUGO,
++                 show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_prs_muram_write_cycles, S_IRUGO, show_fm_pcd_stats,
++                 NULL);
++static DEVICE_ATTR(pcd_prs_muram_write_stall_cycles, S_IRUGO,
++                 show_fm_pcd_stats, NULL);
++static DEVICE_ATTR(pcd_prs_fpm_command_stall_cycles, S_IRUGO,
++                 show_fm_pcd_stats, NULL);
++
++static DEVICE_ATTR(tnum_dbg_0, S_IRUGO, show_fm_tnum_dbg, NULL);
++static DEVICE_ATTR(tnum_dbg_16, S_IRUGO, show_fm_tnum_dbg, NULL);
++static DEVICE_ATTR(tnum_dbg_32, S_IRUGO, show_fm_tnum_dbg, NULL);
++static DEVICE_ATTR(tnum_dbg_48, S_IRUGO, show_fm_tnum_dbg, NULL);
++static DEVICE_ATTR(tnum_dbg_64, S_IRUGO, show_fm_tnum_dbg, NULL);
++static DEVICE_ATTR(tnum_dbg_80, S_IRUGO, show_fm_tnum_dbg, NULL);
++static DEVICE_ATTR(tnum_dbg_96, S_IRUGO, show_fm_tnum_dbg, NULL);
++static DEVICE_ATTR(tnum_dbg_112, S_IRUGO, show_fm_tnum_dbg, NULL);
++
++static DEVICE_ATTR(cls_plan_0, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_1, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_2, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_3, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_4, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_5, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_6, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_7, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_8, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_9, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_10, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_11, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_12, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_13, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_14, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_15, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_16, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_17, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_18, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_19, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_20, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_21, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_22, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_23, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_24, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_25, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_26, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_27, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_28, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_29, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_30, S_IRUGO, show_fm_cls_plan, NULL);
++static DEVICE_ATTR(cls_plan_31, S_IRUGO, show_fm_cls_plan, NULL);
++
++static DEVICE_ATTR(profile_0, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_1, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_2, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_3, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_4, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_5, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_6, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_7, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_8, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_9, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_10, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_11, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_12, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_13, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_14, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_15, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_16, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_17, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_18, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_19, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_20, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_21, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_22, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_23, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_24, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_25, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_26, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_27, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_28, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_29, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_30, S_IRUGO, show_fm_profiles, NULL);
++static DEVICE_ATTR(profile_31, S_IRUGO, show_fm_profiles, NULL);
++
++static DEVICE_ATTR(scheme_0, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_1, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_2, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_3, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_4, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_5, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_6, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_7, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_8, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_9, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_10, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_11, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_12, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_13, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_14, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_15, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_16, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_17, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_18, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_19, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_20, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_21, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_22, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_23, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_24, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_25, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_26, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_27, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_28, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_29, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_30, S_IRUGO, show_fm_schemes, NULL);
++static DEVICE_ATTR(scheme_31, S_IRUGO, show_fm_schemes, NULL);
++
++
++static struct attribute *fm_dev_stats_attributes[] = {
++      &dev_attr_enq_total_frame.attr,
++      &dev_attr_deq_total_frame.attr,
++      &dev_attr_deq_0.attr,
++      &dev_attr_deq_1.attr,
++      &dev_attr_deq_2.attr,
++      &dev_attr_deq_3.attr,
++      &dev_attr_deq_from_default.attr,
++      &dev_attr_deq_from_context.attr,
++      &dev_attr_deq_from_fd.attr,
++      &dev_attr_deq_confirm.attr,
++      &dev_attr_cmq_not_empty.attr,
++      &dev_attr_bus_error.attr,
++      &dev_attr_read_buf_ecc_error.attr,
++      &dev_attr_write_buf_ecc_sys_error.attr,
++      &dev_attr_write_buf_ecc_fm_error.attr,
++      &dev_attr_pcd_kg_total.attr,
++      &dev_attr_pcd_plcr_yellow.attr,
++      &dev_attr_pcd_plcr_red.attr,
++      &dev_attr_pcd_plcr_recolored_to_red.attr,
++      &dev_attr_pcd_plcr_recolored_to_yellow.attr,
++      &dev_attr_pcd_plcr_total.attr,
++      &dev_attr_pcd_plcr_length_mismatch.attr,
++      &dev_attr_pcd_prs_parse_dispatch.attr,
++      &dev_attr_pcd_prs_l2_parse_result_returned.attr,
++      &dev_attr_pcd_prs_l3_parse_result_returned.attr,
++      &dev_attr_pcd_prs_l4_parse_result_returned.attr,
++      &dev_attr_pcd_prs_shim_parse_result_returned.attr,
++      &dev_attr_pcd_prs_l2_parse_result_returned_with_err.attr,
++      &dev_attr_pcd_prs_l3_parse_result_returned_with_err.attr,
++      &dev_attr_pcd_prs_l4_parse_result_returned_with_err.attr,
++      &dev_attr_pcd_prs_shim_parse_result_returned_with_err.attr,
++      &dev_attr_pcd_prs_soft_prs_cycles.attr,
++      &dev_attr_pcd_prs_soft_prs_stall_cycles.attr,
++      &dev_attr_pcd_prs_hard_prs_cycle_incl_stall_cycles.attr,
++      &dev_attr_pcd_prs_muram_read_cycles.attr,
++      &dev_attr_pcd_prs_muram_read_stall_cycles.attr,
++      &dev_attr_pcd_prs_muram_write_cycles.attr,
++      &dev_attr_pcd_prs_muram_write_stall_cycles.attr,
++      &dev_attr_pcd_prs_fpm_command_stall_cycles.attr,
++      NULL
++};
++
++static struct attribute *fm_dev_tnums_dbg_attributes[] = {
++      &dev_attr_tnum_dbg_0.attr,
++      &dev_attr_tnum_dbg_16.attr,
++      &dev_attr_tnum_dbg_32.attr,
++      &dev_attr_tnum_dbg_48.attr,
++      &dev_attr_tnum_dbg_64.attr,
++      &dev_attr_tnum_dbg_80.attr,
++      &dev_attr_tnum_dbg_96.attr,
++      &dev_attr_tnum_dbg_112.attr,
++      NULL
++};
++
++static struct attribute *fm_dev_cls_plans_attributes[] = {
++      &dev_attr_cls_plan_0.attr,
++      &dev_attr_cls_plan_1.attr,
++      &dev_attr_cls_plan_2.attr,
++      &dev_attr_cls_plan_3.attr,
++      &dev_attr_cls_plan_4.attr,
++      &dev_attr_cls_plan_5.attr,
++      &dev_attr_cls_plan_6.attr,
++      &dev_attr_cls_plan_7.attr,
++      &dev_attr_cls_plan_8.attr,
++      &dev_attr_cls_plan_9.attr,
++      &dev_attr_cls_plan_10.attr,
++      &dev_attr_cls_plan_11.attr,
++      &dev_attr_cls_plan_12.attr,
++      &dev_attr_cls_plan_13.attr,
++      &dev_attr_cls_plan_14.attr,
++      &dev_attr_cls_plan_15.attr,
++      &dev_attr_cls_plan_16.attr,
++      &dev_attr_cls_plan_17.attr,
++      &dev_attr_cls_plan_18.attr,
++      &dev_attr_cls_plan_19.attr,
++      &dev_attr_cls_plan_20.attr,
++      &dev_attr_cls_plan_21.attr,
++      &dev_attr_cls_plan_22.attr,
++      &dev_attr_cls_plan_23.attr,
++      &dev_attr_cls_plan_24.attr,
++      &dev_attr_cls_plan_25.attr,
++      &dev_attr_cls_plan_26.attr,
++      &dev_attr_cls_plan_27.attr,
++      &dev_attr_cls_plan_28.attr,
++      &dev_attr_cls_plan_29.attr,
++      &dev_attr_cls_plan_30.attr,
++      &dev_attr_cls_plan_31.attr,
++      NULL
++};
++
++static struct attribute *fm_dev_profiles_attributes[] = {
++      &dev_attr_profile_0.attr,
++      &dev_attr_profile_1.attr,
++      &dev_attr_profile_2.attr,
++      &dev_attr_profile_3.attr,
++      &dev_attr_profile_4.attr,
++      &dev_attr_profile_5.attr,
++      &dev_attr_profile_6.attr,
++      &dev_attr_profile_7.attr,
++      &dev_attr_profile_8.attr,
++      &dev_attr_profile_9.attr,
++      &dev_attr_profile_10.attr,
++      &dev_attr_profile_11.attr,
++      &dev_attr_profile_12.attr,
++      &dev_attr_profile_13.attr,
++      &dev_attr_profile_14.attr,
++      &dev_attr_profile_15.attr,
++      &dev_attr_profile_16.attr,
++      &dev_attr_profile_17.attr,
++      &dev_attr_profile_18.attr,
++      &dev_attr_profile_19.attr,
++      &dev_attr_profile_20.attr,
++      &dev_attr_profile_21.attr,
++      &dev_attr_profile_22.attr,
++      &dev_attr_profile_23.attr,
++      &dev_attr_profile_24.attr,
++      &dev_attr_profile_25.attr,
++      &dev_attr_profile_26.attr,
++      &dev_attr_profile_27.attr,
++      &dev_attr_profile_28.attr,
++      &dev_attr_profile_29.attr,
++      &dev_attr_profile_30.attr,
++      &dev_attr_profile_31.attr,
++      NULL
++};
++
++static struct attribute *fm_dev_schemes_attributes[] = {
++      &dev_attr_scheme_0.attr,
++      &dev_attr_scheme_1.attr,
++      &dev_attr_scheme_2.attr,
++      &dev_attr_scheme_3.attr,
++      &dev_attr_scheme_4.attr,
++      &dev_attr_scheme_5.attr,
++      &dev_attr_scheme_6.attr,
++      &dev_attr_scheme_7.attr,
++      &dev_attr_scheme_8.attr,
++      &dev_attr_scheme_9.attr,
++      &dev_attr_scheme_10.attr,
++      &dev_attr_scheme_11.attr,
++      &dev_attr_scheme_12.attr,
++      &dev_attr_scheme_13.attr,
++      &dev_attr_scheme_14.attr,
++      &dev_attr_scheme_15.attr,
++      &dev_attr_scheme_16.attr,
++      &dev_attr_scheme_17.attr,
++      &dev_attr_scheme_18.attr,
++      &dev_attr_scheme_19.attr,
++      &dev_attr_scheme_20.attr,
++      &dev_attr_scheme_21.attr,
++      &dev_attr_scheme_22.attr,
++      &dev_attr_scheme_23.attr,
++      &dev_attr_scheme_24.attr,
++      &dev_attr_scheme_25.attr,
++      &dev_attr_scheme_26.attr,
++      &dev_attr_scheme_27.attr,
++      &dev_attr_scheme_28.attr,
++      &dev_attr_scheme_29.attr,
++      &dev_attr_scheme_30.attr,
++      &dev_attr_scheme_31.attr,
++      NULL
++};
++
++static const struct attribute_group fm_dev_stats_attr_grp = {
++      .name = "statistics",
++      .attrs = fm_dev_stats_attributes
++};
++
++static const struct attribute_group fm_dev_tnums_dbg_attr_grp = {
++      .name = "tnums_dbg",
++      .attrs = fm_dev_tnums_dbg_attributes
++};
++
++static const struct attribute_group fm_dev_cls_plans_attr_grp = {
++      .name = "cls_plans",
++      .attrs = fm_dev_cls_plans_attributes
++};
++
++static const struct attribute_group fm_dev_schemes_attr_grp = {
++      .name = "schemes",
++      .attrs = fm_dev_schemes_attributes
++};
++
++static const struct attribute_group fm_dev_profiles_attr_grp = {
++      .name = "profiles",
++      .attrs = fm_dev_profiles_attributes
++};
++
++static ssize_t show_fm_regs(struct device *dev,
++                              struct device_attribute *attr,
++                              char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++#endif
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      local_irq_save(flags);
++
++      n = snprintf(buf, PAGE_SIZE, "FM driver registers dump.\n");
++
++      if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev)
++              return -EIO;
++      else
++              n = fm_dump_regs(p_wrp_fm_dev->h_Dev, buf, n);
++
++      local_irq_restore(flags);
++#else
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                      "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++      return n;
++}
++
++static ssize_t show_fm_kg_pe_regs(struct device *dev,
++                              struct device_attribute *attr,
++                              char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++#endif
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      local_irq_save(flags);
++
++      n = snprintf(buf, PAGE_SIZE,
++                      "\n FM-KG Port Partition Config registers dump.\n");
++
++      if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev)
++              return -EIO;
++      else
++              n = fm_kg_pe_dump_regs(p_wrp_fm_dev->h_PcdDev, buf, n);
++
++      local_irq_restore(flags);
++#else
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                      "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++      return n;
++}
++
++static ssize_t show_fm_kg_regs(struct device *dev,
++                              struct device_attribute *attr,
++                              char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++#endif
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      local_irq_save(flags);
++
++      n = snprintf(buf, PAGE_SIZE, "FM-KG registers dump.\n");
++
++      if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev)
++              return -EIO;
++      else
++              n = fm_kg_dump_regs(p_wrp_fm_dev->h_PcdDev, buf, n);
++
++      local_irq_restore(flags);
++#else
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                      "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++      return n;
++}
++
++
++static ssize_t show_fm_fpm_regs(struct device *dev,
++                              struct device_attribute *attr,
++                              char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++#endif
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      local_irq_save(flags);
++
++      n = snprintf(buf, PAGE_SIZE, "FM-FPM registers dump.\n");
++
++      if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev)
++              return -EIO;
++      else
++              n = fm_fpm_dump_regs(p_wrp_fm_dev->h_Dev, buf, n);
++
++      local_irq_restore(flags);
++#else
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                      "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++      return n;
++}
++
++static ssize_t show_prs_regs(struct device *dev,
++                           struct device_attribute *attr, char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++#endif
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE, "FM Policer registers dump.\n");
++
++      if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev)
++              return -EIO;
++      else
++              n = fm_prs_dump_regs(p_wrp_fm_dev->h_PcdDev, buf, n);
++
++      local_irq_restore(flags);
++#else
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                   "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++      return n;
++}
++
++static ssize_t show_plcr_regs(struct device *dev,
++                              struct device_attribute *attr,
++                              char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++#endif
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return -EINVAL;
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE, "FM Policer registers dump.\n");
++
++      if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev)
++              return -EIO;
++      else
++              n = fm_plcr_dump_regs(p_wrp_fm_dev->h_PcdDev, buf, n);
++
++      local_irq_restore(flags);
++#else
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                      "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++
++#endif /* (defined(DEBUG_ERRORS) && ... */
++
++      return n;
++}
++
++static DEVICE_ATTR(fm_regs, S_IRUGO, show_fm_regs, NULL);
++static DEVICE_ATTR(fm_fpm_regs, S_IRUGO, show_fm_fpm_regs, NULL);
++static DEVICE_ATTR(fm_kg_regs, S_IRUGO, show_fm_kg_regs, NULL);
++static DEVICE_ATTR(fm_kg_pe_regs, S_IRUGO, show_fm_kg_pe_regs, NULL);
++static DEVICE_ATTR(fm_plcr_regs, S_IRUGO, show_plcr_regs, NULL);
++static DEVICE_ATTR(fm_prs_regs, S_IRUGO, show_prs_regs, NULL);
++static DEVICE_ATTR(fm_muram_free_size, S_IRUGO, show_fm_muram_free_sz, NULL);
++static DEVICE_ATTR(fm_ctrl_code_ver, S_IRUGO, show_fm_ctrl_code_ver, NULL);
++
++int fm_sysfs_create(struct device *dev)
++{
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++
++      if (dev == NULL)
++              return -EIO;
++
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++
++      /* store to remove them when module is disabled */
++      p_wrp_fm_dev->dev_attr_regs = &dev_attr_fm_regs;
++      p_wrp_fm_dev->dev_attr_risc_load = &dev_attr_fm_risc_load_val;
++      p_wrp_fm_dev->dev_fm_fpm_attr_regs = &dev_attr_fm_fpm_regs;
++      p_wrp_fm_dev->dev_fm_kg_attr_regs = &dev_attr_fm_kg_regs;
++      p_wrp_fm_dev->dev_fm_kg_pe_attr_regs = &dev_attr_fm_kg_pe_regs;
++      p_wrp_fm_dev->dev_plcr_attr_regs = &dev_attr_fm_plcr_regs;
++      p_wrp_fm_dev->dev_prs_attr_regs = &dev_attr_fm_prs_regs;
++      p_wrp_fm_dev->dev_attr_muram_free_size = &dev_attr_fm_muram_free_size;
++      p_wrp_fm_dev->dev_attr_fm_ctrl_code_ver = &dev_attr_fm_ctrl_code_ver;
++
++      /* Create sysfs statistics group for FM module */
++      if (sysfs_create_group(&dev->kobj, &fm_dev_stats_attr_grp) != 0)
++              return -EIO;
++
++      if (sysfs_create_group(&dev->kobj, &fm_dev_schemes_attr_grp) != 0)
++              return -EIO;
++
++      if (sysfs_create_group(&dev->kobj, &fm_dev_profiles_attr_grp) != 0)
++              return -EIO;
++
++      if (sysfs_create_group(&dev->kobj, &fm_dev_tnums_dbg_attr_grp) != 0)
++              return -EIO;
++
++      if (sysfs_create_group(&dev->kobj, &fm_dev_cls_plans_attr_grp) != 0)
++              return -EIO;
++
++      /* Registers dump entry - in future will be moved to debugfs */
++      if (device_create_file(dev, &dev_attr_fm_regs) != 0)
++              return -EIO;
++
++      if (device_create_file(dev, &dev_attr_fm_risc_load_val) != 0)
++              return -EIO;
++
++      if (device_create_file(dev, &dev_attr_fm_fpm_regs) != 0)
++              return -EIO;
++
++      if (device_create_file(dev, &dev_attr_fm_kg_regs) != 0)
++              return -EIO;
++
++      if (device_create_file(dev, &dev_attr_fm_kg_pe_regs) != 0)
++              return -EIO;
++
++      if (device_create_file(dev, &dev_attr_fm_plcr_regs) != 0)
++              return -EIO;
++
++      if (device_create_file(dev, &dev_attr_fm_prs_regs) != 0)
++              return -EIO;
++
++      /* muram free size */
++      if (device_create_file(dev, &dev_attr_fm_muram_free_size) != 0)
++              return -EIO;
++
++      /* fm ctrl code version */
++      if (device_create_file(dev, &dev_attr_fm_ctrl_code_ver) != 0)
++              return -EIO;
++
++      return 0;
++}
++
++void fm_sysfs_destroy(struct device *dev)
++{
++      t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
++
++      if (WARN_ON(dev == NULL))
++              return;
++
++      p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_wrp_fm_dev == NULL))
++              return;
++
++      sysfs_remove_group(&dev->kobj, &fm_dev_stats_attr_grp);
++      sysfs_remove_group(&dev->kobj, &fm_dev_schemes_attr_grp);
++      sysfs_remove_group(&dev->kobj, &fm_dev_profiles_attr_grp);
++      sysfs_remove_group(&dev->kobj, &fm_dev_cls_plans_attr_grp);
++      sysfs_remove_group(&dev->kobj, &fm_dev_tnums_dbg_attr_grp);
++      device_remove_file(dev, p_wrp_fm_dev->dev_attr_regs);
++      device_remove_file(dev, p_wrp_fm_dev->dev_fm_fpm_attr_regs);
++      device_remove_file(dev, p_wrp_fm_dev->dev_fm_kg_attr_regs);
++      device_remove_file(dev, p_wrp_fm_dev->dev_fm_kg_pe_attr_regs);
++      device_remove_file(dev, p_wrp_fm_dev->dev_plcr_attr_regs);
++      device_remove_file(dev, p_wrp_fm_dev->dev_prs_attr_regs);
++      device_remove_file(dev, p_wrp_fm_dev->dev_attr_muram_free_size);
++      device_remove_file(dev, p_wrp_fm_dev->dev_attr_fm_ctrl_code_ver);
++}
++
++int fm_dump_regs(void *h_fm, char *buf, int nn)
++{
++      t_Fm            *p_Fm = (t_Fm *)h_fm;
++      uint8_t         i = 0;
++      int             n = nn;
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++
++      FM_DMP_TITLE(buf, n, p_Fm->p_FmDmaRegs, "FM-DMA Regs");
++
++      FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmsr);
++      FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmemsr);
++      FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmmr);
++      FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmtr);
++      FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmhy);
++      FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmsetr);
++      FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmtah);
++      FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmtal);
++      FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmtcid);
++      FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmra);
++      FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmrd);
++      FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmwcr);
++      FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmebcr);
++      FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmdcr);
++
++      FM_DMP_TITLE(buf, n, &p_Fm->p_FmDmaRegs->fmdmplr, "fmdmplr");
++
++      for (i = 0; i < FM_MAX_NUM_OF_HW_PORT_IDS / 2 ; ++i)
++              FM_DMP_MEM_32(buf, n, &p_Fm->p_FmDmaRegs->fmdmplr[i]);
++
++      FM_DMP_TITLE(buf, n, p_Fm->p_FmBmiRegs, "FM-BMI COMMON Regs");
++      FM_DMP_V32(buf, n, p_Fm->p_FmBmiRegs, fmbm_init);
++      FM_DMP_V32(buf, n, p_Fm->p_FmBmiRegs, fmbm_cfg1);
++      FM_DMP_V32(buf, n, p_Fm->p_FmBmiRegs, fmbm_cfg2);
++      FM_DMP_V32(buf, n, p_Fm->p_FmBmiRegs, fmbm_ievr);
++      FM_DMP_V32(buf, n, p_Fm->p_FmBmiRegs, fmbm_ier);
++
++      FM_DMP_TITLE(buf, n, &p_Fm->p_FmBmiRegs->fmbm_arb, "fmbm_arb");
++      for (i = 0; i < 8 ; ++i)
++              FM_DMP_MEM_32(buf, n, &p_Fm->p_FmBmiRegs->fmbm_arb[i]);
++
++      FM_DMP_TITLE(buf, n, p_Fm->p_FmQmiRegs, "FM-QMI COMMON Regs");
++      FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_gc);
++      FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_eie);
++      FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_eien);
++      FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_eif);
++      FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_ie);
++      FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_ien);
++      FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_if);
++      FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_gs);
++      FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_etfc);
++
++      return n;
++}
++
++int fm_dump_tnum_dbg(void *h_fm, int tn_s, int tn_e, char *buf, int nn)
++{
++      t_Fm            *p_Fm = (t_Fm *)h_fm;
++      uint8_t         i, j = 0;
++      int             n = nn;
++
++      FM_DMP_TITLE(buf, n, NULL, "Tnums and Tnum dbg regs %d - %d",
++                      tn_s, tn_e);
++
++      iowrite32be(tn_s << 24, &p_Fm->p_FmFpmRegs->fmfp_dra);
++
++      mb();
++
++      for (j = tn_s; j <= tn_e; j++) {
++              FM_DMP_LN(buf, n, "> fmfp_ts[%d]\n", j);
++              FM_DMP_MEM_32(buf, n, &p_Fm->p_FmFpmRegs->fmfp_ts[j]);
++              FM_DMP_V32(buf, n, p_Fm->p_FmFpmRegs, fmfp_dra);
++              FM_DMP_LN(buf, n, "> fmfp_drd[0-3]\n");
++
++              for (i = 0; i < 4 ; ++i)
++                      FM_DMP_MEM_32(buf, n, &p_Fm->p_FmFpmRegs->fmfp_drd[i]);
++
++              FM_DMP_LN(buf, n, "\n");
++
++      }
++
++      return n;
++}
++
++int fm_dump_cls_plan(void *h_fm_pcd, int cpn, char *buf, int nn)
++{
++      t_FmPcd                         *p_pcd = (t_FmPcd *)h_fm_pcd;
++      int                             i = 0;
++      uint32_t                        tmp;
++      unsigned long                   i_flg;
++      int                             n = nn;
++      u_FmPcdKgIndirectAccessRegs     *idac;
++      spinlock_t                      *p_lk;
++
++      p_lk = (spinlock_t *)p_pcd->p_FmPcdKg->h_HwSpinlock;
++      idac = p_pcd->p_FmPcdKg->p_IndirectAccessRegs;
++
++      spin_lock_irqsave(p_lk, i_flg);
++
++      /* Read ClsPlan Block Action Regs */
++      tmp =  (uint32_t)(FM_KG_KGAR_GO |
++              FM_KG_KGAR_READ |
++              FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY |
++              DUMMY_PORT_ID |
++              ((uint32_t)cpn << FM_PCD_KG_KGAR_NUM_SHIFT) |
++              FM_PCD_KG_KGAR_WSEL_MASK);
++
++      if (fman_kg_write_ar_wait(p_pcd->p_FmPcdKg->p_FmPcdKgRegs, tmp)) {
++              FM_DMP_LN(buf, nn, "Keygen scheme access violation");
++              spin_unlock_irqrestore(p_lk, i_flg);
++              return nn;
++      }
++      FM_DMP_TITLE(buf, n, &idac->clsPlanRegs,
++                      "ClsPlan %d Indirect Access Regs", cpn);
++
++      for (i = 0; i < 8; i++)
++              FM_DMP_MEM_32(buf, n, &idac->clsPlanRegs.kgcpe[i]);
++
++      spin_unlock_irqrestore(p_lk, i_flg);
++
++      return n;
++}
++
++int fm_profile_dump_regs(void *h_fm_pcd, int ppn, char *buf, int nn)
++{
++      t_FmPcd                         *p_pcd = (t_FmPcd *)h_fm_pcd;
++      t_FmPcdPlcrProfileRegs          *p_prof_regs;
++      t_FmPcdPlcrRegs                 *p_plcr_regs;
++      t_FmPcdPlcr                     *p_plcr;
++      uint32_t                        tmp;
++      unsigned long                   i_flg;
++      int                             n = nn;
++      int                             toc = 10;
++      spinlock_t                      *p_lk;
++
++      p_plcr = p_pcd->p_FmPcdPlcr;
++      p_prof_regs = &p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->profileRegs;
++      p_plcr_regs = p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
++
++      p_lk = (spinlock_t *)((t_FmPcdPlcr *)p_plcr)->h_HwSpinlock;
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++      FM_DMP_TITLE(buf, n, p_plcr_regs, "FM-PCD policer-profile regs");
++
++      tmp =  (uint32_t)(FM_PCD_PLCR_PAR_GO |
++                      FM_PCD_PLCR_PAR_R |
++                      ((uint32_t)ppn << FM_PCD_PLCR_PAR_PNUM_SHIFT) |
++                      FM_PCD_PLCR_PAR_PWSEL_MASK);
++
++      spin_lock_irqsave(p_lk, i_flg);
++
++      iowrite32be(tmp, &p_plcr_regs->fmpl_par);
++
++      mb();
++
++      /* wait for the porfile regs to be present */
++      do {
++              --toc;
++              udelay(10);
++              if (!toc) {
++                      /* looks like PLCR_PAR_GO refuses to clear */
++                      spin_unlock_irqrestore(p_lk, i_flg);
++                      FM_DMP_LN(buf, n, "Profile regs not accessible -");
++                      FM_DMP_LN(buf, n, " check profile init process\n");
++                      return n;
++              }
++      } while ((ioread32be(&p_plcr_regs->fmpl_par) & FM_PCD_PLCR_PAR_GO));
++
++      FM_DMP_TITLE(buf, n, p_prof_regs, "Profile %d regs", ppn);
++
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_pemode);
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_pegnia);
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_peynia);
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_pernia);
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_pecir);
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_pecbs);
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_pepepir_eir);
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_pepbs_ebs);
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_pelts);
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_pects);
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_pepts_ets);
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_pegpc);
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_peypc);
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_perpc);
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_perypc);
++      FM_DMP_V32(buf, n, p_prof_regs, fmpl_perrpc);
++
++      spin_unlock_irqrestore(p_lk, i_flg);
++
++      return n;
++}
++
++int fm_dump_scheme(void *h_fm_pcd, int scnum, char *buf, int nn)
++{
++      t_FmPcd                         *p_pcd = (t_FmPcd *)h_fm_pcd;
++      uint32_t                        tmp_ar;
++      unsigned long                   i_flg;
++      int                             i, n = nn;
++      spinlock_t                      *p_lk;
++      u_FmPcdKgIndirectAccessRegs     *idac;
++
++      idac = p_pcd->p_FmPcdKg->p_IndirectAccessRegs;
++      p_lk = (spinlock_t *)p_pcd->p_FmPcdKg->h_HwSpinlock;
++
++      spin_lock_irqsave(p_lk, i_flg);
++
++      tmp_ar = FmPcdKgBuildReadSchemeActionReg((uint8_t)scnum);
++      if (fman_kg_write_ar_wait(p_pcd->p_FmPcdKg->p_FmPcdKgRegs, tmp_ar)) {
++              FM_DMP_LN(buf, nn,
++                      "Keygen scheme access violation or no such scheme");
++              spin_unlock_irqrestore(p_lk, i_flg);
++              return nn;
++      }
++
++      FM_DMP_TITLE(buf, n, &idac->schemeRegs,
++                      "Scheme %d Indirect Access Regs", scnum);
++
++      FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_mode);
++      FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_ekfc);
++      FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_ekdv);
++      FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_bmch);
++      FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_bmcl);
++      FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_fqb);
++      FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_hc);
++      FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_ppc);
++
++      FM_DMP_TITLE(buf, n, &idac->schemeRegs.kgse_gec, "kgse_gec");
++
++      for (i = 0; i < FM_KG_NUM_OF_GENERIC_REGS; i++)
++              FM_DMP_MEM_32(buf, n, &idac->schemeRegs.kgse_gec[i]);
++
++      FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_spc);
++      FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_dv0);
++      FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_dv1);
++      FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_ccbs);
++      FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_mv);
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++
++      spin_unlock_irqrestore(p_lk, i_flg);
++
++      return n;
++}
++
++int fm_kg_pe_dump_regs(void *h_fm_pcd, char *buf, int nn)
++{
++      t_FmPcd                         *p_pcd = (t_FmPcd *)h_fm_pcd;
++      int                             i = 0;
++      uint8_t                         prt_id = 0;
++      uint32_t                        tmp_ar;
++      unsigned long                   i_flg;
++      int                             n = nn;
++      u_FmPcdKgIndirectAccessRegs     *idac;
++      t_FmPcdKg                       *p_kg;
++      spinlock_t                      *p_lk;
++
++      p_kg = p_pcd->p_FmPcdKg;
++      idac = p_pcd->p_FmPcdKg->p_IndirectAccessRegs;
++      p_lk = (spinlock_t *)p_kg->h_HwSpinlock;
++
++      spin_lock_irqsave(p_lk, i_flg);
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++
++      for (i = 0; i < FM_MAX_NUM_OF_PORTS; i++) {
++              SW_PORT_INDX_TO_HW_PORT_ID(prt_id, i);
++
++              tmp_ar = FmPcdKgBuildReadPortSchemeBindActionReg(prt_id);
++
++              if (fman_kg_write_ar_wait(p_kg->p_FmPcdKgRegs, tmp_ar)) {
++                      FM_DMP_LN(buf, nn, "Keygen scheme access violation");
++                      spin_unlock_irqrestore(p_lk, i_flg);
++                      return nn;
++              }
++              FM_DMP_TITLE(buf, n, &idac->portRegs, "Port %d regs", prt_id);
++              FM_DMP_V32(buf, n, &idac->portRegs, fmkg_pe_sp);
++              FM_DMP_V32(buf, n, &idac->portRegs, fmkg_pe_cpp);
++      }
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++
++      spin_unlock_irqrestore(p_lk, i_flg);
++
++      return n;
++}
++
++int fm_kg_dump_regs(void *h_fm_pcd, char *buf, int nn)
++{
++      t_FmPcd         *p_pcd = (t_FmPcd *)h_fm_pcd;
++      int                     n = nn;
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++      FM_DMP_TITLE(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs,
++                      "FmPcdKgRegs Regs");
++
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_gcr);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_eer);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_eeer);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_seer);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_seeer);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_gsr);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_tpc);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_serc);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_fdor);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_gdv0r);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_gdv1r);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_feer);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_ar);
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++
++      return n;
++}
++
++
++int fm_fpm_dump_regs(void *h_fm, char *buf, int nn)
++{
++      t_Fm            *p_fm = (t_Fm *)h_fm;
++      uint8_t         i;
++      int             n = nn;
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++
++      FM_DMP_TITLE(buf, n, p_fm->p_FmFpmRegs, "FM-FPM Regs");
++
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_tnc);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_prc);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_brkc);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_mxd);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_dist1);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_dist2);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_epi);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_rie);
++
++      FM_DMP_TITLE(buf, n, &p_fm->p_FmFpmRegs->fmfp_fcev, "fmfp_fcev");
++      for (i = 0; i < 4; ++i)
++              FM_DMP_MEM_32(buf, n, &p_fm->p_FmFpmRegs->fmfp_fcev[i]);
++
++      FM_DMP_TITLE(buf, n, &p_fm->p_FmFpmRegs->fmfp_cee, "fmfp_cee");
++      for (i = 0; i < 4; ++i)
++              FM_DMP_MEM_32(buf, n, &p_fm->p_FmFpmRegs->fmfp_cee[i]);
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_tsc1);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_tsc2);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_tsp);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_tsf);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_rcr);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_extc);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_ext1);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_ext2);
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_ip_rev_1);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_ip_rev_2);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_rstc);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_cld);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_npi);
++      FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_ee);
++
++      FM_DMP_TITLE(buf, n, &p_fm->p_FmFpmRegs->fmfp_cev, "fmfp_cev");
++      for (i = 0; i < 4; ++i)
++              FM_DMP_MEM_32(buf, n, &p_fm->p_FmFpmRegs->fmfp_cev[i]);
++
++      FM_DMP_TITLE(buf, n, &p_fm->p_FmFpmRegs->fmfp_ps, "fmfp_ps");
++      for (i = 0; i < 64; ++i)
++              FM_DMP_MEM_32(buf, n, &p_fm->p_FmFpmRegs->fmfp_ps[i]);
++
++      return n;
++}
++
++int fm_prs_dump_regs(void *h_fm_pcd, char *buf, int nn)
++{
++      t_FmPcd         *p_pcd = (t_FmPcd *)h_fm_pcd;
++      int             n = nn;
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++
++      FM_DMP_TITLE(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs,
++                      "FM-PCD parser regs");
++
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_rpclim);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_rpimac);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, pmeec);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_pevr);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_pever);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_perr);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_perer);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_ppsc);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_pds);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l2rrs);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l3rrs);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l4rrs);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_srrs);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l2rres);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l3rres);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l4rres);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_srres);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_spcs);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_spscs);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_hxscs);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_mrcs);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_mwcs);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_mrscs);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_mwscs);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_fcscs);
++
++      return n;
++}
++
++int fm_plcr_dump_regs(void *h_fm_pcd, char *buf, int nn)
++{
++      t_FmPcd         *p_pcd = (t_FmPcd *)h_fm_pcd;
++      int             i = 0;
++      int             n = nn;
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++
++      FM_DMP_TITLE(buf, n,
++                      p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,
++                      "FM policer regs");
++
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_gcr);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_gsr);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_evr);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_ier);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_ifr);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_eevr);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_eier);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_eifr);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_rpcnt);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_ypcnt);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_rrpcnt);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_rypcnt);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_tpcnt);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_flmcnt);
++
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_serc);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_upcr);
++      FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_dpmr);
++
++      FM_DMP_TITLE(buf, n,
++                      &p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_pmr,
++                      "fmpl_pmr");
++
++      for (i = 0; i < 63; ++i)
++              FM_DMP_MEM_32(buf, n,
++                      &p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_pmr[i]);
++
++      return n;
++}
++
++int fm_get_counter(void *h_fm, e_FmCounters cnt_e, uint32_t *cnt_val)
++{
++      t_Fm            *p_fm = (t_Fm *)h_fm;
++
++      /* When applicable (when there is an "enable counters" bit),
++      check that counters are enabled */
++
++      switch (cnt_e) {
++      case (e_FM_COUNTERS_DEQ_1):
++      case (e_FM_COUNTERS_DEQ_2):
++      case (e_FM_COUNTERS_DEQ_3):
++              if (p_fm->p_FmStateStruct->revInfo.majorRev >= 6)
++                      return -EINVAL; /* counter not available */
++
++      case (e_FM_COUNTERS_ENQ_TOTAL_FRAME):
++      case (e_FM_COUNTERS_DEQ_TOTAL_FRAME):
++      case (e_FM_COUNTERS_DEQ_0):
++      case (e_FM_COUNTERS_DEQ_FROM_DEFAULT):
++      case (e_FM_COUNTERS_DEQ_FROM_CONTEXT):
++      case (e_FM_COUNTERS_DEQ_FROM_FD):
++      case (e_FM_COUNTERS_DEQ_CONFIRM):
++              if (!(ioread32be(&p_fm->p_FmQmiRegs->fmqm_gc) &
++                      QMI_CFG_EN_COUNTERS))
++                      return -EINVAL; /* Requested counter not available */
++              break;
++      default:
++              break;
++      }
++
++      switch (cnt_e) {
++      case (e_FM_COUNTERS_ENQ_TOTAL_FRAME):
++              *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_etfc);
++              return 0;
++      case (e_FM_COUNTERS_DEQ_TOTAL_FRAME):
++              *cnt_val =  ioread32be(&p_fm->p_FmQmiRegs->fmqm_dtfc);
++              return 0;
++      case (e_FM_COUNTERS_DEQ_0):
++              *cnt_val =  ioread32be(&p_fm->p_FmQmiRegs->fmqm_dc0);
++              return 0;
++      case (e_FM_COUNTERS_DEQ_1):
++              *cnt_val =  ioread32be(&p_fm->p_FmQmiRegs->fmqm_dc1);
++              return 0;
++      case (e_FM_COUNTERS_DEQ_2):
++              *cnt_val =  ioread32be(&p_fm->p_FmQmiRegs->fmqm_dc2);
++              return 0;
++      case (e_FM_COUNTERS_DEQ_3):
++              *cnt_val =  ioread32be(&p_fm->p_FmQmiRegs->fmqm_dc3);
++              return 0;
++      case (e_FM_COUNTERS_DEQ_FROM_DEFAULT):
++              *cnt_val =  ioread32be(&p_fm->p_FmQmiRegs->fmqm_dfdc);
++              return 0;
++      case (e_FM_COUNTERS_DEQ_FROM_CONTEXT):
++              *cnt_val =  ioread32be(&p_fm->p_FmQmiRegs->fmqm_dfcc);
++              return 0;
++      case (e_FM_COUNTERS_DEQ_FROM_FD):
++              *cnt_val =  ioread32be(&p_fm->p_FmQmiRegs->fmqm_dffc);
++              return 0;
++      case (e_FM_COUNTERS_DEQ_CONFIRM):
++              *cnt_val =  ioread32be(&p_fm->p_FmQmiRegs->fmqm_dcc);
++              return 0;
++      }
++      /* should never get here */
++      return -EINVAL; /* counter not available */
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.h
+@@ -0,0 +1,136 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++#ifndef LNXWRP_SYSFS_FM_H_
++#define LNXWRP_SYSFS_FM_H_
++
++#include "lnxwrp_sysfs.h"
++
++int fm_sysfs_create(struct device *dev);
++void fm_sysfs_destroy(struct device *dev);
++int fm_dump_regs(void *h_dev, char *buf, int nn);
++int fm_fpm_dump_regs(void *h_dev, char *buf, int nn);
++int fm_kg_dump_regs(void *h_pcd, char *buf, int nn);
++int fm_kg_pe_dump_regs(void *h_pcd, char *buf, int nn);
++int fm_dump_scheme(void *h_pcd, int scnum, char *buf, int nn);
++int fm_dump_tnum_dbg(void *h_fm, int tn_s, int tn_e, char *buf, int nn);
++int fm_dump_cls_plan(void *h_pcd, int cpn, char *buf, int nn);
++int fm_plcr_dump_regs(void *h_pcd, char *buf, int nn);
++int fm_prs_dump_regs(void *h_pcd, char *buf, int nn);
++int fm_profile_dump_regs(void *h_pcd, int ppnum, char *buf, int nn);
++
++#define FM_DMP_PGSZ_ERR { \
++                      snprintf(&buf[PAGE_SIZE - 80], 70, \
++                      "\n Err: current sysfs buffer reached PAGE_SIZE\n");\
++                      n = PAGE_SIZE - 2; \
++                      }
++
++#define FM_DMP_LN(buf, n, ...) \
++      do { \
++              int k, m = n; \
++              m += k = snprintf(&buf[m], PAGE_SIZE - m, __VA_ARGS__); \
++              if (k < 0 || m > PAGE_SIZE - 90) \
++                      FM_DMP_PGSZ_ERR \
++              n = m; \
++      } while (0)
++
++#define FM_DMP_TITLE(buf, n, addr, ...) \
++      do { \
++              int k, m = n; \
++              m += k = snprintf(&buf[m], PAGE_SIZE - m, "\n"); \
++              if (k < 0 || m > PAGE_SIZE - 90) \
++                      FM_DMP_PGSZ_ERR \
++              m += k = snprintf(&buf[m], PAGE_SIZE - m, __VA_ARGS__); \
++              if (k < 0 || m > PAGE_SIZE - 90) \
++                      FM_DMP_PGSZ_ERR \
++              if (addr) {                           \
++                      phys_addr_t pa; \
++                      pa = virt_to_phys(addr); \
++                      m += k = \
++                      snprintf(&buf[m], PAGE_SIZE - m, " (0x%lX)", \
++                              (long unsigned int)(pa)); \
++                      if (k < 0 || m > PAGE_SIZE - 90) \
++                              FM_DMP_PGSZ_ERR \
++              } \
++              m += k = snprintf(&buf[m], PAGE_SIZE - m, \
++                      "\n----------------------------------------\n\n"); \
++                      if (k < 0 || m > PAGE_SIZE - 90) \
++                              FM_DMP_PGSZ_ERR \
++              n = m; \
++      } while (0)
++
++#define FM_DMP_SUBTITLE(buf, n, ...) \
++      do { \
++              int k, m = n; \
++              m += k = snprintf(&buf[m], PAGE_SIZE - m, "------- "); \
++              if (k < 0 || m > PAGE_SIZE - 90) \
++                      FM_DMP_PGSZ_ERR \
++              m += k = snprintf(&buf[m], PAGE_SIZE - m, __VA_ARGS__); \
++              if (k < 0 || m > PAGE_SIZE - 90) \
++                      FM_DMP_PGSZ_ERR \
++              m += k = snprintf(&buf[m], PAGE_SIZE - m, "\n"); \
++              if (k < 0 || m > PAGE_SIZE - 90) \
++                      FM_DMP_PGSZ_ERR \
++              n = m; \
++      } while (0)
++
++#define FM_DMP_MEM_32(buf, n, addr) \
++      { \
++              uint32_t val; \
++              phys_addr_t pa; \
++              int k, m = n; \
++              pa = virt_to_phys(addr); \
++              val = ioread32be((addr)); \
++              do { \
++                      m += k = snprintf(&buf[m], \
++                              PAGE_SIZE - m, "0x%010llX: 0x%08x\n", \
++                              pa, val); \
++                      if (k < 0 || m > PAGE_SIZE - 90) \
++                              FM_DMP_PGSZ_ERR \
++                      n += k; \
++              } while (0) ;\
++      }
++
++#define FM_DMP_V32(buf, n, st, phrase) \
++      do { \
++              int k, m = n; \
++              phys_addr_t pa = virt_to_phys(&((st)->phrase)); \
++              k = snprintf(&buf[m], PAGE_SIZE - m, \
++              "0x%010llX: 0x%08x%8s\t%s\n", (unsigned long long) pa, \
++              ioread32be((uint32_t *)&((st)->phrase)), "", #phrase); \
++              if (k < 0 || m > PAGE_SIZE - 90) \
++                      FM_DMP_PGSZ_ERR \
++              n += k; \
++      } while (0)
++
++#endif /* LNXWRP_SYSFS_FM_H_ */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.c
+@@ -0,0 +1,1268 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "lnxwrp_sysfs.h"
++#include "lnxwrp_fm.h"
++#include "debug_ext.h"
++#include "lnxwrp_sysfs_fm_port.h"
++#include "lnxwrp_sysfs_fm.h"
++
++#include "../../sdk_fman/Peripherals/FM/Port/fm_port.h"
++#include "../../sdk_fman/Peripherals/FM/Port/fm_port_dsar.h"
++
++#if defined(__ERR_MODULE__)
++#undef __ERR_MODULE__
++#endif
++
++#include "../../sdk_fman/Peripherals/FM/fm.h"
++
++static const struct sysfs_stats_t portSysfsStats[] = {
++      /* RX/TX/OH common statistics */
++      {
++       .stat_name = "port_frame",
++       .stat_counter = e_FM_PORT_COUNTERS_FRAME,
++       },
++      {
++       .stat_name = "port_discard_frame",
++       .stat_counter = e_FM_PORT_COUNTERS_DISCARD_FRAME,
++       },
++      {
++       .stat_name = "port_dealloc_buf",
++       .stat_counter = e_FM_PORT_COUNTERS_DEALLOC_BUF,
++       },
++      {
++       .stat_name = "port_enq_total",
++       .stat_counter = e_FM_PORT_COUNTERS_ENQ_TOTAL,
++       },
++      /* TX/OH */
++      {
++       .stat_name = "port_length_err",
++       .stat_counter = e_FM_PORT_COUNTERS_LENGTH_ERR,
++       },
++      {
++       .stat_name = "port_unsupprted_format",
++       .stat_counter = e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT,
++       },
++      {
++       .stat_name = "port_deq_total",
++       .stat_counter = e_FM_PORT_COUNTERS_DEQ_TOTAL,
++       },
++      {
++       .stat_name = "port_deq_from_default",
++       .stat_counter = e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT,
++       },
++      {
++       .stat_name = "port_deq_confirm",
++       .stat_counter = e_FM_PORT_COUNTERS_DEQ_CONFIRM,
++       },
++      /* RX/OH */
++      {
++       .stat_name = "port_rx_bad_frame",
++       .stat_counter = e_FM_PORT_COUNTERS_RX_BAD_FRAME,
++       },
++      {
++       .stat_name = "port_rx_large_frame",
++       .stat_counter = e_FM_PORT_COUNTERS_RX_LARGE_FRAME,
++       },
++      {
++       .stat_name = "port_rx_out_of_buffers_discard",
++       .stat_counter = e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD,
++       },
++      {
++       .stat_name = "port_rx_filter_frame",
++       .stat_counter = e_FM_PORT_COUNTERS_RX_FILTER_FRAME,
++       },
++      /* TODO: Particular statistics for OH ports */
++      {}
++};
++
++static ssize_t show_fm_port_stats(struct device *dev,
++              struct device_attribute *attr, char *buf)
++{
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
++      t_LnxWrpFmDev *p_LnxWrpFmDev;
++      unsigned long flags;
++      int n = 0;
++      uint8_t counter = 0;
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++      p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_LnxWrpFmPortDev == NULL))
++              return -EINVAL;
++
++      p_LnxWrpFmDev = (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev;
++      if (WARN_ON(p_LnxWrpFmDev == NULL))
++              return -EINVAL;
++
++      if (!p_LnxWrpFmDev->active || !p_LnxWrpFmDev->h_Dev)
++              return -EIO;
++
++      if (!p_LnxWrpFmPortDev->h_Dev) {
++              n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n");
++              return n;
++      }
++
++      counter = fm_find_statistic_counter_by_name(
++                      attr->attr.name,
++                      portSysfsStats, NULL);
++
++      if (counter == e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR) {
++              uint32_t fmRev = 0;
++              fmRev = 0xffff &
++                      ioread32(UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr +
++                      0x000c30c4));
++
++              if (fmRev == 0x0100) {
++                      local_irq_save(flags);
++                      n = snprintf(buf, PAGE_SIZE,
++                              "counter not available for revision 1\n");
++                      local_irq_restore(flags);
++              }
++              return n;
++      }
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE, "\t%s counter: %u\n",
++              p_LnxWrpFmPortDev->name,
++              FM_PORT_GetCounter(p_LnxWrpFmPortDev->h_Dev,
++                                      (e_FmPortCounters) counter));
++      local_irq_restore(flags);
++
++      return n;
++}
++
++/* FM PORT RX/TX/OH statistics */
++static DEVICE_ATTR(port_frame, S_IRUGO, show_fm_port_stats, NULL);
++static DEVICE_ATTR(port_discard_frame, S_IRUGO, show_fm_port_stats, NULL);
++static DEVICE_ATTR(port_dealloc_buf, S_IRUGO, show_fm_port_stats, NULL);
++static DEVICE_ATTR(port_enq_total, S_IRUGO, show_fm_port_stats, NULL);
++/* FM PORT TX/OH statistics */
++static DEVICE_ATTR(port_length_err, S_IRUGO, show_fm_port_stats, NULL);
++static DEVICE_ATTR(port_unsupprted_format, S_IRUGO, show_fm_port_stats, NULL);
++static DEVICE_ATTR(port_deq_total, S_IRUGO, show_fm_port_stats, NULL);
++static DEVICE_ATTR(port_deq_from_default, S_IRUGO, show_fm_port_stats, NULL);
++static DEVICE_ATTR(port_deq_confirm, S_IRUGO, show_fm_port_stats, NULL);
++/* FM PORT RX/OH statistics */
++static DEVICE_ATTR(port_rx_bad_frame, S_IRUGO, show_fm_port_stats, NULL);
++static DEVICE_ATTR(port_rx_large_frame, S_IRUGO, show_fm_port_stats, NULL);
++static DEVICE_ATTR(port_rx_out_of_buffers_discard, S_IRUGO,
++              show_fm_port_stats, NULL);
++static DEVICE_ATTR(port_rx_filter_frame, S_IRUGO, show_fm_port_stats, NULL);
++
++/* FM PORT TX statistics */
++static struct attribute *fm_tx_port_dev_stats_attributes[] = {
++      &dev_attr_port_frame.attr,
++      &dev_attr_port_discard_frame.attr,
++      &dev_attr_port_dealloc_buf.attr,
++      &dev_attr_port_enq_total.attr,
++      &dev_attr_port_length_err.attr,
++      &dev_attr_port_unsupprted_format.attr,
++      &dev_attr_port_deq_total.attr,
++      &dev_attr_port_deq_from_default.attr,
++      &dev_attr_port_deq_confirm.attr,
++      NULL
++};
++
++static const struct attribute_group fm_tx_port_dev_stats_attr_grp = {
++      .name = "statistics",
++      .attrs = fm_tx_port_dev_stats_attributes
++};
++
++/* FM PORT RX statistics */
++static struct attribute *fm_rx_port_dev_stats_attributes[] = {
++      &dev_attr_port_frame.attr,
++      &dev_attr_port_discard_frame.attr,
++      &dev_attr_port_dealloc_buf.attr,
++      &dev_attr_port_enq_total.attr,
++      &dev_attr_port_rx_bad_frame.attr,
++      &dev_attr_port_rx_large_frame.attr,
++      &dev_attr_port_rx_out_of_buffers_discard.attr,
++      &dev_attr_port_rx_filter_frame.attr,
++      NULL
++};
++
++static const struct attribute_group fm_rx_port_dev_stats_attr_grp = {
++      .name = "statistics",
++      .attrs = fm_rx_port_dev_stats_attributes
++};
++
++/* TODO: add particular OH ports statistics */
++static struct attribute *fm_oh_port_dev_stats_attributes[] = {
++      &dev_attr_port_frame.attr,
++      &dev_attr_port_discard_frame.attr,
++      &dev_attr_port_dealloc_buf.attr,
++      &dev_attr_port_enq_total.attr,
++      /*TX*/ &dev_attr_port_length_err.attr,
++      &dev_attr_port_unsupprted_format.attr,
++      &dev_attr_port_deq_total.attr,
++      &dev_attr_port_deq_from_default.attr,
++      &dev_attr_port_deq_confirm.attr,
++      /* &dev_attr_port_rx_bad_frame.attr, */
++      /* &dev_attr_port_rx_large_frame.attr, */
++      &dev_attr_port_rx_out_of_buffers_discard.attr,
++      /*&dev_attr_port_rx_filter_frame.attr, */
++      NULL
++};
++
++static const struct attribute_group fm_oh_port_dev_stats_attr_grp = {
++      .name = "statistics",
++      .attrs = fm_oh_port_dev_stats_attributes
++};
++
++static ssize_t show_fm_port_regs(struct device *dev,
++              struct device_attribute *attr, char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
++#endif
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      p_LnxWrpFmPortDev =
++              (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
++
++
++      local_irq_save(flags);
++
++      if (!p_LnxWrpFmPortDev->h_Dev) {
++              n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n");
++              return n;
++      } else {
++              n = snprintf(buf, PAGE_SIZE,
++                              "FM port driver registers dump.\n");
++              n = fm_port_dump_regs(p_LnxWrpFmPortDev->h_Dev, buf, n);
++      }
++
++      local_irq_restore(flags);
++
++      return n;
++#else
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                      "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++
++      return n;
++#endif
++}
++static int fm_port_dsar_dump_mem(void *h_dev, char *buf, int nn)
++{
++      t_FmPort *p_FmPort;
++      t_Fm *p_Fm;
++      uint8_t hardwarePortId;
++      uint32_t *param_page;
++      t_ArCommonDesc *ArCommonDescPtr;
++      uint32_t *mem;
++      int i, n = nn;
++
++      p_FmPort = (t_FmPort *)h_dev;
++      hardwarePortId = p_FmPort->hardwarePortId;
++      p_Fm = (t_Fm *)p_FmPort->h_Fm;
++
++      if (!FM_PORT_IsInDsar(p_FmPort))
++      {
++              FM_DMP_LN(buf, n, "port %u is not a DSAR port\n",
++                      hardwarePortId);
++              return n;
++      }
++      FM_DMP_LN(buf, n, "port %u DSAR mem\n", hardwarePortId);
++      FM_DMP_LN(buf, n, "========================\n");
++
++      /* do I need request_mem_region here? */
++      param_page = ioremap(p_FmPort->fmMuramPhysBaseAddr + ioread32be(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr), 4);
++      ArCommonDescPtr = (t_ArCommonDesc*)(ioremap(p_FmPort->fmMuramPhysBaseAddr + ioread32be(param_page), 300*4)); /* this should be changed*/
++      mem = (uint32_t*)ArCommonDescPtr;
++      for (i = 0; i < 300; i+=4)
++              FM_DMP_LN(buf, n, "%08x: %08x %08x %08x %08x\n", i*4, mem[i], mem[i + 1], mem[i + 2], mem[i + 3]);
++      iounmap(ArCommonDescPtr);
++      iounmap(param_page);
++      return n;
++}
++
++static int fm_port_dsar_dump_regs(void *h_dev, char *buf, int nn)
++{
++      t_FmPort *p_FmPort;
++      t_Fm *p_Fm;
++      uint8_t hardwarePortId;
++      uint32_t *param_page;
++      t_ArCommonDesc *ArCommonDescPtr;
++      int i, n = nn;
++
++      p_FmPort = (t_FmPort *)h_dev;
++      hardwarePortId = p_FmPort->hardwarePortId;
++      p_Fm = (t_Fm *)p_FmPort->h_Fm;
++
++      if (!FM_PORT_IsInDsar(p_FmPort))
++      {
++              FM_DMP_LN(buf, n, "port %u is not a DSAR port\n",
++                      hardwarePortId);
++              return n;
++      }
++      FM_DMP_LN(buf, n, "port %u DSAR information\n", hardwarePortId);
++      FM_DMP_LN(buf, n, "========================\n");
++
++      /* do I need request_mem_region here? */
++      param_page = ioremap(p_FmPort->fmMuramPhysBaseAddr + ioread32be(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr), 4);
++      ArCommonDescPtr = (t_ArCommonDesc*)(ioremap(p_FmPort->fmMuramPhysBaseAddr + ioread32be(param_page), sizeof(t_ArCommonDesc))); /* this should be changed*/
++      FM_DMP_LN(buf, n, "Tx port: 0x%x\n", ArCommonDescPtr->arTxPort);
++      FM_DMP_LN(buf, n, "Active HPNIA: 0x%08x\n", ArCommonDescPtr->activeHPNIA);
++      FM_DMP_LN(buf, n, "Snmp port: 0x%x\n", ArCommonDescPtr->snmpPort);
++      FM_DMP_LN(buf, n, "MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", ArCommonDescPtr->macStationAddr[0],
++              ArCommonDescPtr->macStationAddr[1], ArCommonDescPtr->macStationAddr[2],
++              ArCommonDescPtr->macStationAddr[3], ArCommonDescPtr->macStationAddr[4],
++              ArCommonDescPtr->macStationAddr[5]);
++      FM_DMP_LN(buf, n, "filterControl: 0x%02x\n", ArCommonDescPtr->filterControl);
++      FM_DMP_LN(buf, n, "tcpControlPass: 0x%04x\n", ArCommonDescPtr->tcpControlPass);
++      FM_DMP_LN(buf, n, "ipProtocolTblSize: 0x%x\n", ArCommonDescPtr->ipProtocolTblSize);
++      FM_DMP_LN(buf, n, "udpPortTblSize: 0x%x\n", ArCommonDescPtr->udpPortTblSize);
++      FM_DMP_LN(buf, n, "tcpPortTblSize: 0x%x\n", ArCommonDescPtr->tcpPortTblSize);
++      if (ArCommonDescPtr->p_ArStats)
++      {
++              t_ArStatistics *arStatistics = (t_ArStatistics*)
++                      ioremap(ioread32be(&ArCommonDescPtr->p_ArStats) +
++                      p_FmPort->fmMuramPhysBaseAddr,
++                      sizeof (t_ArStatistics));
++              FM_DMP_LN(buf, n, "\nDSAR statistics\n");
++              FM_DMP_LN(buf, n, "DSAR_Discarded:            0x%x\n", arStatistics->dsarDiscarded);
++              FM_DMP_LN(buf, n, "DSAR_Err_Discarded:        0x%x\n", arStatistics->dsarErrDiscarded);
++              FM_DMP_LN(buf, n, "DSAR_Frag_Discarded:       0x%x\n", arStatistics->dsarFragDiscarded);
++              FM_DMP_LN(buf, n, "DSAR_Tunnel_Discarded:     0x%x\n", arStatistics->dsarTunnelDiscarded);
++              FM_DMP_LN(buf, n, "DSAR_ARP_Discarded:        0x%x\n", arStatistics->dsarArpDiscarded);
++              FM_DMP_LN(buf, n, "DSAR_IP_Discarded:         0x%x\n", arStatistics->dsarIpDiscarded);
++              FM_DMP_LN(buf, n, "DSAR_TCP_Discarded:        0x%x\n", arStatistics->dsarTcpDiscarded);
++              FM_DMP_LN(buf, n, "DSAR_UDP_Discarded:        0x%x\n", arStatistics->dsarUdpDiscarded);
++              FM_DMP_LN(buf, n, "DSAR_ICMPv6_Checksum_Err:  0x%x\n", arStatistics->dsarIcmpV6ChecksumErr);
++              FM_DMP_LN(buf, n, "DSAR_ICMPv6_Other_Type:    0x%x\n", arStatistics->dsarIcmpV6OtherType);
++              FM_DMP_LN(buf, n, "DSAR_ICMPv4_Other_Type:    0x%x\n", arStatistics->dsarIcmpV4OtherType);
++              
++              iounmap(arStatistics);
++      }
++      if (ArCommonDescPtr->p_ArpDescriptor)
++      {
++              t_DsarArpDescriptor* ArpDescriptor = (t_DsarArpDescriptor*)
++                      ioremap(ioread32be(&ArCommonDescPtr->p_ArpDescriptor) +
++                      p_FmPort->fmMuramPhysBaseAddr,
++                      sizeof (t_DsarArpDescriptor));
++              FM_DMP_LN(buf, n, "\nARP\n");
++              FM_DMP_LN(buf, n, "===\n");
++              FM_DMP_LN(buf, n, "control bits 0x%04x\n", ArpDescriptor->control);
++              if (ArpDescriptor->numOfBindings)
++              {
++                      char ip_str[100];
++                      t_DsarArpBindingEntry* bindings = ioremap(
++                              ioread32be(&ArpDescriptor->p_Bindings) +
++                              p_FmPort->fmMuramPhysBaseAddr,
++                              ArpDescriptor->numOfBindings *
++                              sizeof(t_DsarArpBindingEntry));
++                      uint8_t* ip_addr = (uint8_t*)&bindings->ipv4Addr;
++                      FM_DMP_LN(buf, n, "      ip          vlan id\n");
++                      for (i = 0; i < ArpDescriptor->numOfBindings; i++)
++                      {
++                              n += snprintf(ip_str, 100, "%d.%d.%d.%d",
++                                      ip_addr[0], ip_addr[1],
++                                      ip_addr[2], ip_addr[3]);
++                              FM_DMP_LN(buf, n, "%-15s     0x%x\n",
++                                      ip_str, bindings->vlanId);
++                      }
++                      iounmap(bindings);
++              }
++              if (ArpDescriptor->p_Statistics)
++              {
++                      t_DsarArpStatistics* arpStats = ioremap(
++                              ioread32be(&ArpDescriptor->p_Statistics) +
++                              p_FmPort->fmMuramPhysBaseAddr,
++                              sizeof(t_DsarArpStatistics));
++                      FM_DMP_LN(buf, n, "statistics\n");
++                      FM_DMP_LN(buf, n, "INVAL_CNT:  0x%x\n", arpStats->invalCnt);
++                      FM_DMP_LN(buf, n, "ECHO_CNT:   0x%x\n", arpStats->echoCnt);
++                      FM_DMP_LN(buf, n, "CD_CNT:     0x%x\n", arpStats->cdCnt);
++                      FM_DMP_LN(buf, n, "AR_CNT:     0x%x\n", arpStats->arCnt);
++                      FM_DMP_LN(buf, n, "RATM_CNT:   0x%x\n", arpStats->ratmCnt);
++                      FM_DMP_LN(buf, n, "UKOP_CNT:   0x%x\n", arpStats->ukopCnt);
++                      FM_DMP_LN(buf, n, "NMTP_CNT:   0x%x\n", arpStats->nmtpCnt);
++                      FM_DMP_LN(buf, n, "NMVLAN_CNT: 0x%x\n", arpStats->nmVlanCnt);
++                      iounmap(arpStats);
++              }
++              
++              iounmap(ArpDescriptor);
++      }
++      if (ArCommonDescPtr->p_IcmpV4Descriptor)
++      {
++              t_DsarIcmpV4Descriptor* ICMPV4Descriptor =
++                      (t_DsarIcmpV4Descriptor*)ioremap(ioread32be(
++                      &ArCommonDescPtr->p_IcmpV4Descriptor) +
++                      p_FmPort->fmMuramPhysBaseAddr,
++                      sizeof (t_DsarIcmpV4Descriptor));
++              FM_DMP_LN(buf, n, "\nEcho ICMPv4\n");
++              FM_DMP_LN(buf, n, "===========\n");
++              FM_DMP_LN(buf, n, "control bits 0x%04x\n", ICMPV4Descriptor->control);
++              if (ICMPV4Descriptor->numOfBindings)
++              {
++                      char ip_str[100];
++                      t_DsarArpBindingEntry* bindings = ioremap(
++                              ioread32be(&ICMPV4Descriptor->p_Bindings) +
++                              p_FmPort->fmMuramPhysBaseAddr,
++                              ICMPV4Descriptor->numOfBindings *
++                              sizeof(t_DsarArpBindingEntry));
++                      uint8_t* ip_addr = (uint8_t*)&bindings->ipv4Addr;
++                      FM_DMP_LN(buf, n, "      ip          vlan id\n");
++                      for (i = 0; i < ICMPV4Descriptor->numOfBindings; i++)
++                      {
++                              n += snprintf(ip_str, 100, "%d.%d.%d.%d",
++                                      ip_addr[0], ip_addr[1],
++                                      ip_addr[2], ip_addr[3]);
++                              FM_DMP_LN(buf, n, "%-15s     0x%x\n",
++                                      ip_str, bindings->vlanId);
++                      }
++                      iounmap(bindings);
++              }
++              if (ICMPV4Descriptor->p_Statistics)
++              {
++                      t_DsarIcmpV4Statistics* icmpv4Stats = ioremap(
++                              ioread32be(&ICMPV4Descriptor->p_Statistics) +
++                              p_FmPort->fmMuramPhysBaseAddr,
++                              sizeof(t_DsarIcmpV4Statistics));
++                      FM_DMP_LN(buf, n, "statistics\n");
++                      FM_DMP_LN(buf, n, "INVAL_CNT:  0x%x\n", icmpv4Stats->invalCnt);
++                      FM_DMP_LN(buf, n, "NMVLAN_CNT: 0x%x\n", icmpv4Stats->nmVlanCnt);
++                      FM_DMP_LN(buf, n, "NMIP_CNT:   0x%x\n", icmpv4Stats->nmIpCnt);
++                      FM_DMP_LN(buf, n, "AR_CNT:     0x%x\n", icmpv4Stats->arCnt);
++                      FM_DMP_LN(buf, n, "CSERR_CNT:  0x%x\n", icmpv4Stats->cserrCnt);
++                      iounmap(icmpv4Stats);
++              }
++              iounmap(ICMPV4Descriptor);
++      }
++      if (ArCommonDescPtr->p_NdDescriptor)
++      {
++              t_DsarNdDescriptor *NDDescriptor =
++                      (t_DsarNdDescriptor*)ioremap(ioread32be(
++                      &ArCommonDescPtr->p_NdDescriptor) + p_FmPort->
++                      fmMuramPhysBaseAddr, sizeof (t_DsarNdDescriptor));
++              FM_DMP_LN(buf, n, "\nNDP\n");
++              FM_DMP_LN(buf, n, "===\n");
++              FM_DMP_LN(buf, n, "control bits 0x%04x\n", NDDescriptor->control);
++              FM_DMP_LN(buf, n, "solicited address 0x%08x\n", NDDescriptor->solicitedAddr);
++              if (NDDescriptor->numOfBindings)
++              {
++                      char ip_str[100];
++                      t_DsarIcmpV6BindingEntry* bindings = ioremap(
++                              ioread32be(&NDDescriptor->p_Bindings) +
++                              p_FmPort->fmMuramPhysBaseAddr,
++                              NDDescriptor->numOfBindings *
++                              sizeof(t_DsarIcmpV6BindingEntry));
++                      uint16_t* ip_addr = (uint16_t*)&bindings->ipv6Addr;
++                      FM_DMP_LN(buf, n, "                  ip                        vlan id\n");
++                      for (i = 0; i < NDDescriptor->numOfBindings; i++)
++                      {
++                              n += snprintf(ip_str, 100,
++                                      "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
++                              ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3],
++                              ip_addr[4], ip_addr[5], ip_addr[6], ip_addr[7]);
++                              FM_DMP_LN(buf, n, "%s     0x%x\n", ip_str, bindings->vlanId);
++                      }
++                      iounmap(bindings);
++              }
++              if (NDDescriptor->p_Statistics)
++              {
++                      t_NdStatistics* ndStats = ioremap(
++                              ioread32be(&NDDescriptor->p_Statistics) +
++                              p_FmPort->fmMuramPhysBaseAddr,
++                              sizeof(t_NdStatistics));
++                      FM_DMP_LN(buf, n, "statistics\n");
++                      FM_DMP_LN(buf, n, "INVAL_CNT:    0x%x\n", ndStats->invalCnt);
++                      FM_DMP_LN(buf, n, "NMVLAN_CNT:   0x%x\n", ndStats->nmVlanCnt);
++                      FM_DMP_LN(buf, n, "NMIP_CNT:     0x%x\n", ndStats->nmIpCnt);
++                      FM_DMP_LN(buf, n, "AR_CNT:       0x%x\n", ndStats->arCnt);
++                      FM_DMP_LN(buf, n, "USADVERT_CNT: 0x%x\n", ndStats->usadvertCnt);
++                      FM_DMP_LN(buf, n, "NMMCAST_CNT:  0x%x\n", ndStats->nmmcastCnt);
++                      FM_DMP_LN(buf, n, "NSLLA_CNT:    0x%x\n", ndStats->nsllaCnt);
++                      iounmap(ndStats);
++              }
++              iounmap(NDDescriptor);
++      }
++      if (ArCommonDescPtr->p_IcmpV6Descriptor)
++      {
++              t_DsarIcmpV6Descriptor *ICMPV6Descriptor =
++                      (t_DsarIcmpV6Descriptor*)ioremap(ioread32be(
++                      &ArCommonDescPtr->p_IcmpV6Descriptor) + p_FmPort->
++                      fmMuramPhysBaseAddr, sizeof (t_DsarIcmpV6Descriptor));
++              FM_DMP_LN(buf, n, "\nEcho ICMPv6\n");
++              FM_DMP_LN(buf, n, "===========\n");
++              FM_DMP_LN(buf, n, "control bits 0x%04x\n", ICMPV6Descriptor->control);
++              if (ICMPV6Descriptor->numOfBindings)
++              {
++                      char ip_str[100];
++                      t_DsarIcmpV6BindingEntry* bindings = ioremap(
++                              ioread32be(&ICMPV6Descriptor->p_Bindings) +
++                              p_FmPort->fmMuramPhysBaseAddr,
++                              ICMPV6Descriptor->numOfBindings *
++                              sizeof(t_DsarIcmpV6BindingEntry));
++                      uint16_t* ip_addr = (uint16_t*)&bindings->ipv6Addr;
++                      FM_DMP_LN(buf, n, "                  ip                        vlan id\n");
++                      for (i = 0; i < ICMPV6Descriptor->numOfBindings; i++)
++                      {
++                              n += snprintf(ip_str, 100,
++                                      "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
++                              ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3],
++                              ip_addr[4], ip_addr[5], ip_addr[6], ip_addr[7]);
++                              FM_DMP_LN(buf, n, "%s     0x%x\n", ip_str, bindings->vlanId);
++                      }
++                      iounmap(bindings);
++              }
++              if (ICMPV6Descriptor->p_Statistics)
++              {
++                      t_DsarIcmpV6Statistics* icmpv6Stats = ioremap(
++                              ioread32be(&ICMPV6Descriptor->p_Statistics) +
++                              p_FmPort->fmMuramPhysBaseAddr,
++                              sizeof(t_DsarIcmpV6Statistics));
++                      FM_DMP_LN(buf, n, "statistics\n");
++                      FM_DMP_LN(buf, n, "INVAL_CNT:    0x%x\n", icmpv6Stats->invalCnt);
++                      FM_DMP_LN(buf, n, "NMVLAN_CNT:   0x%x\n", icmpv6Stats->nmVlanCnt);
++                      FM_DMP_LN(buf, n, "NMIP_CNT:     0x%x\n", icmpv6Stats->nmIpCnt);
++                      FM_DMP_LN(buf, n, "AR_CNT:       0x%x\n", icmpv6Stats->arCnt);
++                      iounmap(icmpv6Stats);
++              }
++              iounmap(ICMPV6Descriptor);
++      }
++      if (ArCommonDescPtr->p_SnmpDescriptor)
++      {
++              t_DsarSnmpDescriptor *SnmpDescriptor =
++                      (t_DsarSnmpDescriptor*)ioremap(ioread32be(
++                      &ArCommonDescPtr->p_SnmpDescriptor) + p_FmPort->
++                      fmMuramPhysBaseAddr, sizeof (t_DsarSnmpDescriptor));
++              FM_DMP_LN(buf, n, "\nSNMP\n");
++              FM_DMP_LN(buf, n, "===========\n");
++              FM_DMP_LN(buf, n, "control bits 0x%04x\n", SnmpDescriptor->control);
++              FM_DMP_LN(buf, n, "max message length 0x%04x\n", SnmpDescriptor->maxSnmpMsgLength);
++              if (SnmpDescriptor->numOfIpv4Addresses)
++              {
++                      char ip_str[100];
++                      t_DsarSnmpIpv4AddrTblEntry* addrs = ioremap(
++                              ioread32be(&SnmpDescriptor->p_Ipv4AddrTbl) +
++                              p_FmPort->fmMuramPhysBaseAddr,
++                              SnmpDescriptor->numOfIpv4Addresses *
++                              sizeof(t_DsarSnmpIpv4AddrTblEntry));
++                      uint8_t* ip_addr = (uint8_t*)&addrs->ipv4Addr;
++                      FM_DMP_LN(buf, n, "      ip          vlan id\n");
++                      for (i = 0; i < SnmpDescriptor->numOfIpv4Addresses; i++)
++                      {
++                              n += snprintf(ip_str, 100, "%d.%d.%d.%d",
++                                      ip_addr[0], ip_addr[1],
++                                      ip_addr[2], ip_addr[3]);
++                              FM_DMP_LN(buf, n, "%-15s     0x%x\n", ip_str, addrs->vlanId);
++                      }
++                      iounmap(addrs);
++              }
++              if (SnmpDescriptor->p_Statistics)
++              {
++                      t_DsarSnmpStatistics* snmpStats = ioremap(
++                              ioread32be(&SnmpDescriptor->p_Statistics) +
++                              p_FmPort->fmMuramPhysBaseAddr,
++                              sizeof(t_DsarSnmpStatistics));
++                      FM_DMP_LN(buf, n, "statistics\n");
++                      FM_DMP_LN(buf, n, "snmpErrCnt:          0x%x\n", snmpStats->snmpErrCnt);
++                      FM_DMP_LN(buf, n, "snmpCommunityErrCnt: 0x%x\n", snmpStats->snmpCommunityErrCnt);
++                      FM_DMP_LN(buf, n, "snmpTotalDiscardCnt: 0x%x\n", snmpStats->snmpTotalDiscardCnt);
++                      FM_DMP_LN(buf, n, "snmpGetReqCnt:       0x%x\n", snmpStats->snmpGetReqCnt);
++                      FM_DMP_LN(buf, n, "snmpGetNextReqCnt:   0x%x\n", snmpStats->snmpGetNextReqCnt);
++                      iounmap(snmpStats);
++              }
++              iounmap(SnmpDescriptor);
++      }
++      iounmap(ArCommonDescPtr);
++      iounmap(param_page);
++      return n;
++}
++
++static ssize_t show_fm_port_dsar_mem(struct device *dev,
++              struct device_attribute *attr, char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
++#endif
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      p_LnxWrpFmPortDev =
++              (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
++
++      local_irq_save(flags);
++
++      if (!p_LnxWrpFmPortDev->h_Dev) {
++              n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n");
++              return n;
++      } else {
++              n = snprintf(buf, PAGE_SIZE,
++                              "FM port driver registers dump.\n");
++              n = fm_port_dsar_dump_mem(p_LnxWrpFmPortDev->h_Dev, buf, n);
++      }
++
++      local_irq_restore(flags);
++
++      return n;
++#else
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                      "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++
++      return n;
++#endif
++}
++
++static ssize_t show_fm_port_dsar_regs(struct device *dev,
++              struct device_attribute *attr, char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
++#endif
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      p_LnxWrpFmPortDev =
++              (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
++
++      local_irq_save(flags);
++
++      if (!p_LnxWrpFmPortDev->h_Dev) {
++              n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n");
++              return n;
++      } else {
++              n = snprintf(buf, PAGE_SIZE,
++                              "FM port driver registers dump.\n");
++              n = fm_port_dsar_dump_regs(p_LnxWrpFmPortDev->h_Dev, buf, n);
++      }
++
++      local_irq_restore(flags);
++
++      return n;
++#else
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                      "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++
++      return n;
++#endif
++}
++
++#if (DPAA_VERSION >= 11)
++static ssize_t show_fm_port_ipv4_options(struct device *dev,
++              struct device_attribute *attr, char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
++#endif
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      p_LnxWrpFmPortDev =
++              (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
++
++      local_irq_save(flags);
++
++      if (!p_LnxWrpFmPortDev->h_Dev) {
++              n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n");
++              return n;
++      } else if (((t_FmPort *)p_LnxWrpFmPortDev->h_Dev)->p_ParamsPage
++                                      == NULL) {
++              n = snprintf(buf, PAGE_SIZE,
++                      "\tPort: FMan-controller params page not set\n");
++              return n;
++      } else {
++              n = snprintf(buf, PAGE_SIZE,
++                      "Counter for fragmented pkt with IP header options\n");
++              n = fm_port_dump_ipv4_opt(p_LnxWrpFmPortDev->h_Dev, buf, n);
++      }
++
++      local_irq_restore(flags);
++
++      return n;
++#else
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                      "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++
++      return n;
++#endif
++}
++
++#endif
++
++static ssize_t show_fm_port_bmi_regs(struct device *dev,
++              struct device_attribute *attr, char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
++#endif
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      p_LnxWrpFmPortDev =
++              (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
++
++      local_irq_save(flags);
++
++      if (!p_LnxWrpFmPortDev->h_Dev) {
++              n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n");
++              return n;
++      } else {
++              n = snprintf(buf, PAGE_SIZE,
++                              "FM port driver registers dump.\n");
++              n = fm_port_dump_regs_bmi(p_LnxWrpFmPortDev->h_Dev, buf, n);
++      }
++
++      local_irq_restore(flags);
++
++      return n;
++#else
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                      "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++
++      return n;
++#endif
++}
++
++static ssize_t show_fm_port_qmi_regs(struct device *dev,
++              struct device_attribute *attr, char *buf)
++{
++      unsigned long flags;
++      unsigned n = 0;
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
++#endif
++
++      if (attr == NULL || buf == NULL || dev == NULL)
++              return -EINVAL;
++
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++      p_LnxWrpFmPortDev =
++              (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
++
++      local_irq_save(flags);
++
++      if (!p_LnxWrpFmPortDev->h_Dev) {
++              n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n");
++              return n;
++      } else {
++              n = snprintf(buf, PAGE_SIZE,
++                              "FM port driver registers dump.\n");
++              n = fm_port_dump_regs_qmi(p_LnxWrpFmPortDev->h_Dev, buf, n);
++      }
++
++      local_irq_restore(flags);
++
++      return n;
++#else
++
++      local_irq_save(flags);
++      n = snprintf(buf, PAGE_SIZE,
++                      "Debug level is too low to dump registers!!!\n");
++      local_irq_restore(flags);
++
++      return n;
++#endif
++}
++
++static DEVICE_ATTR(fm_port_regs, S_IRUGO | S_IRUSR, show_fm_port_regs, NULL);
++static DEVICE_ATTR(fm_port_qmi_regs, S_IRUGO | S_IRUSR, show_fm_port_qmi_regs, NULL);
++static DEVICE_ATTR(fm_port_bmi_regs, S_IRUGO | S_IRUSR, show_fm_port_bmi_regs, NULL);
++#if (DPAA_VERSION >= 11)
++static DEVICE_ATTR(fm_port_ipv4_opt, S_IRUGO | S_IRUSR, show_fm_port_ipv4_options, NULL);
++#endif
++static DEVICE_ATTR(fm_port_dsar_regs, S_IRUGO | S_IRUSR, show_fm_port_dsar_regs, NULL);
++static DEVICE_ATTR(fm_port_dsar_mem, S_IRUGO | S_IRUSR, show_fm_port_dsar_mem, NULL);
++
++int fm_port_sysfs_create(struct device *dev)
++{
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
++
++      if (dev == NULL)
++              return -EINVAL;
++
++      p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_LnxWrpFmPortDev == NULL))
++              return -EINVAL;
++
++      /* store to remove them when module is disabled */
++      p_LnxWrpFmPortDev->dev_attr_regs = &dev_attr_fm_port_regs;
++      p_LnxWrpFmPortDev->dev_attr_qmi_regs = &dev_attr_fm_port_qmi_regs;
++      p_LnxWrpFmPortDev->dev_attr_bmi_regs = &dev_attr_fm_port_bmi_regs;
++#if (DPAA_VERSION >= 11)
++      p_LnxWrpFmPortDev->dev_attr_ipv4_opt = &dev_attr_fm_port_ipv4_opt;
++#endif
++      p_LnxWrpFmPortDev->dev_attr_dsar_regs = &dev_attr_fm_port_dsar_regs;
++      p_LnxWrpFmPortDev->dev_attr_dsar_mem = &dev_attr_fm_port_dsar_mem;
++      /* Registers dump entry - in future will be moved to debugfs */
++      if (device_create_file(dev, &dev_attr_fm_port_regs) != 0)
++              return -EIO;
++      if (device_create_file(dev, &dev_attr_fm_port_qmi_regs) != 0)
++              return -EIO;
++      if (device_create_file(dev, &dev_attr_fm_port_bmi_regs) != 0)
++              return -EIO;
++#if (DPAA_VERSION >= 11)
++      if (device_create_file(dev, &dev_attr_fm_port_ipv4_opt) != 0)
++              return -EIO;
++#endif
++      if (device_create_file(dev, &dev_attr_fm_port_dsar_regs) != 0)
++              return -EIO;
++      if (device_create_file(dev, &dev_attr_fm_port_dsar_mem) != 0)
++              return -EIO;
++              
++      /* FM Ports statistics */
++      switch (p_LnxWrpFmPortDev->settings.param.portType) {
++      case e_FM_PORT_TYPE_TX:
++      case e_FM_PORT_TYPE_TX_10G:
++              if (sysfs_create_group
++                      (&dev->kobj, &fm_tx_port_dev_stats_attr_grp) != 0)
++                      return -EIO;
++              break;
++      case e_FM_PORT_TYPE_RX:
++      case e_FM_PORT_TYPE_RX_10G:
++              if (sysfs_create_group
++                      (&dev->kobj, &fm_rx_port_dev_stats_attr_grp) != 0)
++                      return -EIO;
++              break;
++      case e_FM_PORT_TYPE_DUMMY:
++      case e_FM_PORT_TYPE_OH_OFFLINE_PARSING:
++              if (sysfs_create_group
++                      (&dev->kobj, &fm_oh_port_dev_stats_attr_grp) != 0)
++                      return -EIO;
++              break;
++      default:
++              WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__,
++                      __func__);
++              return -EINVAL;
++              break;
++      };
++
++      return 0;
++}
++
++void fm_port_sysfs_destroy(struct device *dev)
++{
++      t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = NULL;
++
++      /* this function has never been tested !!! */
++
++      if (WARN_ON(dev == NULL))
++              return;
++
++      p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
++      if (WARN_ON(p_LnxWrpFmPortDev == NULL))
++              return;
++
++      /* The name attribute will be freed also by these 2 functions? */
++      switch (p_LnxWrpFmPortDev->settings.param.portType) {
++      case e_FM_PORT_TYPE_TX:
++      case e_FM_PORT_TYPE_TX_10G:
++              sysfs_remove_group(&dev->kobj, &fm_tx_port_dev_stats_attr_grp);
++              break;
++      case e_FM_PORT_TYPE_RX:
++      case e_FM_PORT_TYPE_RX_10G:
++              sysfs_remove_group(&dev->kobj, &fm_rx_port_dev_stats_attr_grp);
++              break;
++      case e_FM_PORT_TYPE_DUMMY:
++      case e_FM_PORT_TYPE_OH_OFFLINE_PARSING:
++              sysfs_remove_group(&dev->kobj, &fm_oh_port_dev_stats_attr_grp);
++              break;
++      default:
++              WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__,
++                   __func__);
++              break;
++      };
++
++      device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_regs);
++      device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_qmi_regs);
++      device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_bmi_regs);
++#if (DPAA_VERSION >= 11)
++      device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_ipv4_opt);
++#endif
++      device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_dsar_regs);
++      device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_dsar_mem);
++}
++
++
++int fm_port_dump_regs(void *h_dev, char *buf, int nn)
++{
++      t_FmPort *p_FmPort;
++      t_Fm *p_Fm;
++      uint8_t hardwarePortId;
++      int n = nn;
++
++      p_FmPort = (t_FmPort *)h_dev;
++      hardwarePortId = p_FmPort->hardwarePortId;
++      p_Fm = (t_Fm *)p_FmPort->h_Fm;
++
++      FM_DMP_TITLE(buf, n, &p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId - 1],
++                      "fmbm_pp for port %u", hardwarePortId);
++      FM_DMP_MEM_32(buf, n,
++                      &p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId - 1]);
++
++      FM_DMP_TITLE(buf, n, &p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId - 1],
++                      "fmbm_pfs for port %u", hardwarePortId);
++      FM_DMP_MEM_32(buf, n,
++              &p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId - 1]);
++
++      FM_DMP_TITLE(buf, n,
++                      &p_Fm->p_FmBmiRegs->fmbm_spliodn[hardwarePortId - 1],
++                      "fmbm_spliodn for port %u", hardwarePortId);
++      FM_DMP_MEM_32(buf, n,
++                      &p_Fm->p_FmBmiRegs->fmbm_spliodn[hardwarePortId - 1]);
++
++      FM_DMP_TITLE(buf, n, &p_Fm->p_FmFpmRegs->fmfp_ps[hardwarePortId],
++                      "fmfp_psfor port %u", hardwarePortId);
++      FM_DMP_MEM_32(buf, n, &p_Fm->p_FmFpmRegs->fmfp_ps[hardwarePortId]);
++
++      FM_DMP_TITLE(buf, n, &p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId / 2],
++                      "fmdmplrfor port %u", hardwarePortId);
++      FM_DMP_MEM_32(buf, n,
++                      &p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId / 2]);
++      return n;
++}
++
++#if (DPAA_VERSION >= 11)
++
++int fm_port_dump_ipv4_opt(void *h_dev, char *buf, int nn)
++{
++      t_FmPort *p_FmPort;
++      int n = nn;
++
++      p_FmPort = (t_FmPort *)h_dev;
++
++      FM_DMP_V32(buf, n, p_FmPort->p_ParamsPage, ipfOptionsCounter);
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++
++      return n;
++}
++#endif
++
++int fm_port_dump_regs_bmi(void *h_dev, char *buf, int nn)
++{
++      t_FmPort *p_FmPort;
++      u_FmPortBmiRegs *p_bmi;
++
++      char            arr[20];
++      uint8_t         flag;
++      int             i = 0;
++      int             n = nn;
++
++      p_FmPort = (t_FmPort *)h_dev;
++      p_bmi = p_FmPort->p_FmPortBmiRegs;
++
++      memset(arr, 0, sizeof(arr));
++      switch (p_FmPort->portType) {
++      case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
++              strcpy(arr, "OFFLINE-PARSING");
++              flag = 0;
++              break;
++      case (e_FM_PORT_TYPE_OH_HOST_COMMAND):
++              strcpy(arr, "HOST-COMMAND");
++              flag = 0;
++              break;
++      case (e_FM_PORT_TYPE_RX):
++              strcpy(arr, "RX");
++              flag = 1;
++              break;
++      case (e_FM_PORT_TYPE_RX_10G):
++              strcpy(arr, "RX-10G");
++              flag = 1;
++              break;
++      case (e_FM_PORT_TYPE_TX):
++              strcpy(arr, "TX");
++              flag = 2;
++              break;
++      case (e_FM_PORT_TYPE_TX_10G):
++              strcpy(arr, "TX-10G");
++              flag = 2;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      FM_DMP_TITLE(buf, n, NULL,
++              "FMan-Port (%s #%d) registers:",
++              arr, p_FmPort->portId);
++
++      FM_DMP_TITLE(buf, n, p_bmi, "Bmi Port Regs");
++
++      switch (flag) {
++      case (0):
++              FM_DMP_SUBTITLE(buf, n, "\n");
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ocfg);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ost);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_oda);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_oicp);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofdne);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofne);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofca);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofpne);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_opso);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_opp);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_occb);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_oim);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofp);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofed);
++
++              FM_DMP_TITLE(buf, n,
++                      &(p_bmi->ohPortBmiRegs.fmbm_oprai), "fmbm_oprai");
++              for (i = 0; i < FM_PORT_PRS_RESULT_NUM_OF_WORDS; ++i) {
++                      FM_DMP_MEM_32(buf, n,
++                              &(p_bmi->ohPortBmiRegs.fmbm_oprai[i]));
++              }
++              FM_DMP_SUBTITLE(buf, n, "\n");
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofqid);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_oefqid);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofsdm);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofsem);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofene);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_orlmts);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_orlmt);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ocmne);
++              {
++#ifndef FM_NO_OP_OBSERVED_POOLS
++              if (p_FmPort->fmRevInfo.majorRev == 4) {
++                      FM_DMP_TITLE(buf, n,
++                              &p_bmi->ohPortBmiRegs.fmbm_oebmpi,
++                              "fmbm_oebmpi");
++
++                      for (i = 0; i < FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS; ++i) {
++                              FM_DMP_MEM_32(buf, n,
++                                      &(p_bmi->ohPortBmiRegs.fmbm_oebmpi[i]));
++                      }
++                      FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ocgm);
++              }
++#endif /* !FM_NO_OP_OBSERVED_POOLS */
++              }
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ostc);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofrc);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofdc);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofledc);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofufdc);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_offc);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofwdc);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofldec);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_opc);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_opcp);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_occn);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_otuc);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_oduc);
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofuc);
++              FM_DMP_TITLE(buf, n, &(p_bmi->ohPortBmiRegs.fmbm_odcfg),
++                              "fmbm_odcfg");
++              for (i = 0; i < 3; ++i) {
++                      FM_DMP_MEM_32(buf, n,
++                              &(p_bmi->ohPortBmiRegs.fmbm_odcfg[i]));
++              }
++              FM_DMP_SUBTITLE(buf, n, "\n");
++
++              FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ogpr);
++      break;
++      case (1):
++              FM_DMP_SUBTITLE(buf, n, "\n");
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rcfg);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rst);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rda);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfp);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_reth);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfed);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_ricp);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rebm);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfne);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfca);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfpne);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rpso);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rpp);
++              FM_DMP_TITLE(buf, n, &(p_bmi->rxPortBmiRegs.fmbm_rprai),
++                      "fmbm_rprai");
++              for (i = 0; i < FM_PORT_PRS_RESULT_NUM_OF_WORDS; ++i) {
++                      FM_DMP_MEM_32(buf, n,
++                              &(p_bmi->rxPortBmiRegs.fmbm_rprai[i]));
++              }
++              FM_DMP_SUBTITLE(buf, n, "\n");
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfqid);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_refqid);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfsdm);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfsem);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfene);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rcmne);
++              FM_DMP_TITLE(buf, n, &p_bmi->rxPortBmiRegs.fmbm_ebmpi,
++                              "fmbm_ebmpi");
++              for (i = 0; i < FM_PORT_MAX_NUM_OF_EXT_POOLS; ++i) {
++                      FM_DMP_MEM_32(buf, n,
++                              &(p_bmi->rxPortBmiRegs.fmbm_ebmpi[i]));
++              }
++              FM_DMP_TITLE(buf, n, &p_bmi->rxPortBmiRegs.fmbm_acnt,
++                              "fmbm_acnt");
++              for (i = 0; i < FM_PORT_MAX_NUM_OF_EXT_POOLS; ++i) {
++                      FM_DMP_MEM_32(buf, n,
++                              &(p_bmi->rxPortBmiRegs.fmbm_acnt[i]));
++              }
++              FM_DMP_TITLE(buf, n, &p_bmi->rxPortBmiRegs.fmbm_rcgm,
++                              "fmbm_rcgm");
++              for (i = 0; i < FM_PORT_NUM_OF_CONGESTION_GRPS / 32; ++i) {
++                      FM_DMP_MEM_32(buf, n,
++                              &(p_bmi->rxPortBmiRegs.fmbm_rcgm[i]));
++              }
++
++              FM_DMP_SUBTITLE(buf, n, "\n");
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rmpd);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rstc);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfrc);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfbc);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rlfc);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rffc);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfcd);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfldec);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rodc);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rpc);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rpcp);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rccn);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rtuc);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rrquc);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rduc);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfuc);
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rpac);
++              FM_DMP_TITLE(buf, n, &(p_bmi->rxPortBmiRegs.fmbm_rdcfg),
++                              "fmbm_rdcfg");
++              for (i = 0; i < 3; ++i) {
++                      FM_DMP_MEM_32(buf, n,
++                              &(p_bmi->rxPortBmiRegs.fmbm_rdcfg[i]));
++              }
++              FM_DMP_SUBTITLE(buf, n, "\n");
++              FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rgpr);
++              break;
++      case (2):
++              FM_DMP_SUBTITLE(buf, n, "\n");
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tcfg);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tst);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tda);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfp);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfed);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_ticp);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfdne);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfca);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tcfqid);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfeqid);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfene);
++#if (DPAA_VERSION >= 11)
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfne);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tcmne);
++#endif /* (DPAA_VERSION >= 11) */
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_trlmts);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_trlmt);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tstc);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfrc);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfdc);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfledc);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfufdc);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tpc);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tpcp);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tccn);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_ttuc);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_ttcquc);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tduc);
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfuc);
++              FM_DMP_TITLE(buf, n, &(p_bmi->txPortBmiRegs.fmbm_tdcfg),
++                              "fmbm_tdcfg");
++              for (i = 0; i < 3 ; ++i) {
++                      FM_DMP_MEM_32(buf, n,
++                              &(p_bmi->txPortBmiRegs.fmbm_tdcfg[i]));
++              }
++              FM_DMP_SUBTITLE(buf, n, "\n");
++              FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tgpr);
++              break;
++      }
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++
++      return n;
++}
++
++int fm_port_dump_regs_qmi(void *h_dev, char *buf, int nn)
++{
++      t_FmPort *p_FmPort;
++      int n = nn;
++
++      p_FmPort = (t_FmPort *)h_dev;
++
++      FM_DMP_TITLE(buf, n, p_FmPort->p_FmPortQmiRegs, "Qmi Port Regs");
++
++      FM_DMP_V32(buf, n, p_FmPort->p_FmPortQmiRegs, fmqm_pnc);
++      FM_DMP_V32(buf, n, p_FmPort->p_FmPortQmiRegs, fmqm_pns);
++      FM_DMP_V32(buf, n, p_FmPort->p_FmPortQmiRegs, fmqm_pnts);
++      FM_DMP_V32(buf, n, p_FmPort->p_FmPortQmiRegs, fmqm_pnen);
++      FM_DMP_V32(buf, n, p_FmPort->p_FmPortQmiRegs, fmqm_pnetfc);
++      FM_DMP_V32(buf, n,
++              &p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs, fmqm_pndn);
++      FM_DMP_V32(buf, n,
++              &p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs, fmqm_pndc);
++      FM_DMP_V32(buf, n,
++              &p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs, fmqm_pndtfc);
++      FM_DMP_V32(buf, n,
++              &p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs, fmqm_pndfdc);
++      FM_DMP_V32(buf, n,
++              &p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs, fmqm_pndcc);
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++
++      return n;
++}
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.h
+@@ -0,0 +1,56 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ @File          lnxwrp_sysfs_fm_port.h
++
++ @Description   FM port sysfs functions.
++
++*/
++
++#ifndef LNXWRP_SYSFS_FM_PORT_H_
++#define LNXWRP_SYSFS_FM_PORT_H_
++
++#include "lnxwrp_sysfs.h"
++
++int fm_port_sysfs_create(struct device *dev);
++void fm_port_sysfs_destroy(struct device *dev);
++
++int fm_port_dump_regs(void *h_dev, char *buf, int n);
++int fm_port_dump_regs_bmi(void *h_dev, char *buf, int n);
++int fm_port_dump_regs_qmi(void *h_dev, char *buf, int n);
++
++#if (DPAA_VERSION >= 11)
++int fm_port_dump_ipv4_opt(void *h_dev, char *buf, int n);
++#endif
++
++#endif /* LNXWRP_SYSFS_FM_PORT_H_ */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/xx/Makefile
+@@ -0,0 +1,18 @@
++#
++# Makefile for the Freescale Ethernet controllers
++#
++ccflags-y           += -DVERSION=\"\"
++#
++#Include netcomm SW specific definitions
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++
++obj-y         += fsl-ncsw-xx.o
++
++ifneq ($(CONFIG_FMAN_ARM),y)
++fsl-ncsw-xx-objs      :=  xx_linux.o \
++                              module_strings.o
++else
++fsl-ncsw-xx-objs      := xx_arm_linux.o \
++                              module_strings.o
++endif
++
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/xx/module_strings.c
+@@ -0,0 +1,46 @@
++/*
++ * Copyright 2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* Module names for debug messages */
++const char *moduleStrings[] =
++{
++    "",                         /* MODULE_UNKNOWN */
++    "FM",                       /* MODULE_FM */
++    "FM-MURAM",                 /* MODULE_FM_MURAM */
++    "FM-PCD",                   /* MODULE_FM_PCD */
++    "FM-RTC",                   /* MODULE_FM_RTC */
++    "FM-MAC",                   /* MODULE_FM_MAC */
++    "FM-Port",                  /* MODULE_FM_PORT */
++    "MM",                       /* MODULE_MM */
++    "FM-SP",                    /* MODULE_FM_SP */
++    "FM-MACSEC"                 /* MODULE_FM_MACSEC */
++};
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_arm_linux.c
+@@ -0,0 +1,905 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**************************************************************************//**
++ @File          xx_arm_linux.c
++
++ @Description   XX routines implementation for Linux.
++*//***************************************************************************/
++#include <linux/version.h>
++
++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
++#define MODVERSIONS
++#endif
++#ifdef MODVERSIONS
++#include <config/modversions.h>
++#endif /* MODVERSIONS */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/ptrace.h>
++#include <linux/errno.h>
++#include <linux/ioport.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/fs.h>
++#include <linux/vmalloc.h>
++#include <linux/init.h>
++#include <linux/timer.h>
++#include <linux/spinlock.h>
++#include <linux/delay.h>
++#include <linux/proc_fs.h>
++#include <linux/smp.h>
++#include <linux/of.h>
++#include <linux/irqdomain.h>
++
++#include <linux/workqueue.h>
++
++#ifdef BIGPHYSAREA_ENABLE
++#include <linux/bigphysarea.h>
++#endif /* BIGPHYSAREA_ENABLE */
++
++//#include <sysdev/fsl_soc.h>
++#include <asm/pgtable.h>
++#include <asm/irq.h>
++#include <asm/bitops.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/atomic.h>
++#include <asm/string.h>
++#include <asm/byteorder.h>
++#include <asm/page.h>
++
++#include "error_ext.h"
++#include "std_ext.h"
++#include "list_ext.h"
++#include "mm_ext.h"
++#include "sys_io_ext.h"
++#include "xx.h"
++
++
++#define __ERR_MODULE__      MODULE_UNKNOWN
++
++#ifdef BIGPHYSAREA_ENABLE
++#define MAX_ALLOCATION_SIZE     128 * 1024 /* Maximum size allocated with kmalloc is 128K */
++
++
++/* TODO: large allocations => use big phys area */
++/******************************************************************************
++ * routine:     get_nr_pages
++ *
++ * description:
++ *     calculates the number of memory pages for a given size (in bytes)
++ *
++ * arguments:
++ *     size       - the number of bytes
++ *
++ * return code:
++ *     The number of pages
++ *
++ *****************************************************************************/
++static __inline__ uint32_t get_nr_pages (uint32_t size)
++{
++    return (uint32_t)((size >> PAGE_SHIFT) + (size & PAGE_SHIFT ? 1 : 0));
++}
++
++static bool in_big_phys_area (uint32_t addr)
++{
++    uint32_t base, size;
++
++    bigphysarea_get_details (&base, &size);
++    return ((addr >= base) && (addr < base + size));
++}
++#endif /* BIGPHYSAREA_ENABLE */
++
++void * xx_Malloc(uint32_t n)
++{
++    void        *a;
++    uint32_t    flags;
++
++    flags = XX_DisableAllIntr();
++#ifdef BIGPHYSAREA_ENABLE
++    if (n >= MAX_ALLOCATION_SIZE)
++        a = (void*)bigphysarea_alloc_pages(get_nr_pages(n), 0, GFP_ATOMIC);
++    else
++#endif /* BIGPHYSAREA_ENABLE */
++    a = (void *)kmalloc((uint32_t)n, GFP_ATOMIC);
++    if (!a)
++        XX_Print("No memory for XX_Malloc\n");
++    XX_RestoreAllIntr(flags);
++
++    return a;
++}
++
++void xx_Free(void *p)
++{
++#ifdef BIGPHYSAREA_ENABLE
++    if (in_big_phys_area ((uint32_t)p))
++        bigphysarea_free_pages(p);
++    else
++#endif /* BIGPHYSAREA_ENABLE */
++    kfree(p);
++}
++
++void XX_Exit(int status)
++{
++    WARN(1, "\n\nFMD: fatal error, driver can't go on!!!\n\n");
++}
++
++#define BUF_SIZE    512
++void XX_Print(char *str, ...)
++{
++    va_list args;
++#ifdef CONFIG_SMP
++    char buf[BUF_SIZE];
++#endif /* CONFIG_SMP */
++
++    va_start(args, str);
++#ifdef CONFIG_SMP
++    if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE)
++        printk(KERN_WARNING "Illegal string to print!\n    more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE);
++    printk(KERN_CRIT "cpu %d: %s",  raw_smp_processor_id(), buf);
++#else
++    vprintk(str, args);
++#endif /* CONFIG_SMP */
++    va_end(args);
++}
++
++void XX_Fprint(void *file, char *str, ...)
++{
++    va_list args;
++#ifdef CONFIG_SMP
++    char buf[BUF_SIZE];
++#endif /* CONFIG_SMP */
++
++    va_start(args, str);
++#ifdef CONFIG_SMP
++    if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE)
++        printk(KERN_WARNING "Illegal string to print!\n    more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE);
++    printk (KERN_CRIT "cpu %d: %s", smp_processor_id(), buf);
++
++#else
++    vprintk(str, args);
++#endif /* CONFIG_SMP */
++    va_end(args);
++}
++
++#ifdef DEBUG_XX_MALLOC
++typedef void (*t_ffn)(void *);
++typedef struct {
++    t_ffn       f_free;
++    void        *mem;
++    char        *fname;
++    int         fline;
++    uint32_t    size;
++    t_List      node;
++} t_MemDebug;
++#define MEMDBG_OBJECT(p_List) LIST_OBJECT(p_List, t_MemDebug, node)
++
++LIST(memDbgLst);
++
++
++void * XX_MallocDebug(uint32_t size, char *fname, int line)
++{
++    void       *mem;
++    t_MemDebug *p_MemDbg;
++
++    p_MemDbg = (t_MemDebug *)xx_Malloc(sizeof(t_MemDebug));
++    if (p_MemDbg == NULL)
++        return NULL;
++
++    mem = xx_Malloc(size);
++    if (mem == NULL)
++    {
++        XX_Free(p_MemDbg);
++        return NULL;
++    }
++
++    INIT_LIST(&p_MemDbg->node);
++    p_MemDbg->f_free = xx_Free;
++    p_MemDbg->mem    = mem;
++    p_MemDbg->fname  = fname;
++    p_MemDbg->fline  = line;
++    p_MemDbg->size   = size+sizeof(t_MemDebug);
++    LIST_AddToTail(&p_MemDbg->node, &memDbgLst);
++
++    return mem;
++}
++
++void * XX_MallocSmartDebug(uint32_t size,
++                           int      memPartitionId,
++                           uint32_t align,
++                           char     *fname,
++                           int      line)
++{
++    void       *mem;
++    t_MemDebug *p_MemDbg;
++
++    p_MemDbg = (t_MemDebug *)XX_Malloc(sizeof(t_MemDebug));
++    if (p_MemDbg == NULL)
++        return NULL;
++
++    mem = xx_MallocSmart((uint32_t)size, memPartitionId, align);
++    if (mem == NULL)
++    {
++        XX_Free(p_MemDbg);
++        return NULL;
++    }
++
++    INIT_LIST(&p_MemDbg->node);
++    p_MemDbg->f_free = xx_FreeSmart;
++    p_MemDbg->mem    = mem;
++    p_MemDbg->fname  = fname;
++    p_MemDbg->fline  = line;
++    p_MemDbg->size   = size+sizeof(t_MemDebug);
++    LIST_AddToTail(&p_MemDbg->node, &memDbgLst);
++
++    return mem;
++}
++
++static void debug_free(void *mem)
++{
++    t_List      *p_MemDbgLh = NULL;
++    t_MemDebug  *p_MemDbg;
++    bool        found = FALSE;
++
++    if (LIST_IsEmpty(&memDbgLst))
++    {
++        REPORT_ERROR(MAJOR, E_ALREADY_FREE, ("Unbalanced free (0x%08x)", mem));
++        return;
++    }
++
++    LIST_FOR_EACH(p_MemDbgLh, &memDbgLst)
++    {
++        p_MemDbg = MEMDBG_OBJECT(p_MemDbgLh);
++        if (p_MemDbg->mem == mem)
++        {
++            found = TRUE;
++            break;
++        }
++    }
++
++    if (!found)
++    {
++        REPORT_ERROR(MAJOR, E_NOT_FOUND,
++                     ("Attempt to free unallocated address (0x%08x)",mem));
++        dump_stack();
++        return;
++    }
++
++    LIST_Del(p_MemDbgLh);
++    p_MemDbg->f_free(mem);
++    p_MemDbg->f_free(p_MemDbg);
++}
++
++void XX_FreeSmart(void *p)
++{
++    debug_free(p);
++}
++
++
++void XX_Free(void *p)
++{
++    debug_free(p);
++}
++
++#else /* not DEBUG_XX_MALLOC */
++void * XX_Malloc(uint32_t size)
++{
++    return xx_Malloc(size);
++}
++
++void * XX_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment)
++{
++    return xx_MallocSmart(size,memPartitionId, alignment);
++}
++
++void XX_FreeSmart(void *p)
++{
++    xx_FreeSmart(p);
++}
++
++
++void XX_Free(void *p)
++{
++    xx_Free(p);
++}
++#endif /* not DEBUG_XX_MALLOC */
++
++
++#if (defined(REPORT_EVENTS) && (REPORT_EVENTS > 0))
++void XX_EventById(uint32_t event, t_Handle appId, uint16_t flags, char *msg)
++{
++    e_Event eventCode = (e_Event)event;
++
++    UNUSED(eventCode);
++    UNUSED(appId);
++    UNUSED(flags);
++    UNUSED(msg);
++}
++#endif /* (defined(REPORT_EVENTS) && ... */
++
++
++uint32_t XX_DisableAllIntr(void)
++{
++    unsigned long flags;
++
++#ifdef local_irq_save_nort
++    local_irq_save_nort(flags);
++#else
++    local_irq_save(flags);
++#endif
++
++    return (uint32_t)flags;
++}
++
++void XX_RestoreAllIntr(uint32_t flags)
++{
++#ifdef local_irq_restore_nort
++    local_irq_restore_nort((unsigned long)flags);
++#else
++    local_irq_restore((unsigned long)flags);
++#endif
++}
++
++t_Error XX_Call( uint32_t qid, t_Error (* f)(t_Handle), t_Handle id, t_Handle appId, uint16_t flags )
++{
++    UNUSED(qid);
++    UNUSED(appId);
++    UNUSED(flags);
++
++    return f(id);
++}
++
++int XX_IsICacheEnable(void)
++{
++    return TRUE;
++}
++
++int XX_IsDCacheEnable(void)
++{
++    return TRUE;
++}
++
++
++typedef struct {
++    t_Isr       *f_Isr;
++    t_Handle    handle;
++} t_InterruptHandler;
++
++
++t_Handle interruptHandlers[0x00010000];
++
++static irqreturn_t LinuxInterruptHandler (int irq, void *dev_id)
++{
++    t_InterruptHandler *p_IntrHndl = (t_InterruptHandler *)dev_id;
++    p_IntrHndl->f_Isr(p_IntrHndl->handle);
++    return IRQ_HANDLED;
++}
++
++t_Error XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle)
++{
++    const char *device;
++    t_InterruptHandler *p_IntrHndl;
++
++    device = GetDeviceName(irq);
++    if (device == NULL)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Interrupt source - %d", irq));
++
++    p_IntrHndl = (t_InterruptHandler *)XX_Malloc(sizeof(t_InterruptHandler));
++    if (p_IntrHndl == NULL)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++    p_IntrHndl->f_Isr = f_Isr;
++    p_IntrHndl->handle = handle;
++    interruptHandlers[irq] = p_IntrHndl;
++
++    if (request_irq(GetDeviceIrqNum(irq), LinuxInterruptHandler, 0, device, p_IntrHndl) < 0)
++        RETURN_ERROR(MAJOR, E_BUSY, ("Can't get IRQ %s\n", device));
++    disable_irq(GetDeviceIrqNum(irq));
++
++    return E_OK;
++}
++
++t_Error XX_FreeIntr(int irq)
++{
++    t_InterruptHandler *p_IntrHndl = interruptHandlers[irq];
++    free_irq(GetDeviceIrqNum(irq), p_IntrHndl);
++    XX_Free(p_IntrHndl);
++    interruptHandlers[irq] = 0;
++    return E_OK;
++}
++
++t_Error XX_EnableIntr(int irq)
++{
++    enable_irq(GetDeviceIrqNum(irq));
++    return E_OK;
++}
++
++t_Error XX_DisableIntr(int irq)
++{
++    disable_irq(GetDeviceIrqNum(irq));
++    return E_OK;
++}
++
++
++/*****************************************************************************/
++/*                       Tasklet Service Routines                            */
++/*****************************************************************************/
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++typedef struct
++{
++    t_Handle            h_Data;
++    void                (*f_Callback) (void *);
++    struct delayed_work dwork;
++} t_Tasklet;
++
++static void GenericTaskletCallback(struct work_struct *p_Work)
++{
++    t_Tasklet *p_Task = container_of(p_Work, t_Tasklet, dwork.work);
++
++    p_Task->f_Callback(p_Task->h_Data);
++}
++#endif    /* LINUX_VERSION_CODE */
++
++
++t_TaskletHandle XX_InitTasklet (void (*routine)(void *), void *data)
++{
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++    struct work_struct *p_Task;
++    p_Task = (struct work_struct *)XX_Malloc(sizeof(struct work_struct));
++    INIT_WORK(p_Task, routine, data);
++#else
++    t_Tasklet *p_Task = (t_Tasklet *)XX_Malloc(sizeof(t_Tasklet));
++    p_Task->h_Data = data;
++    p_Task->f_Callback = routine;
++    INIT_DELAYED_WORK(&p_Task->dwork, GenericTaskletCallback);
++#endif    /* LINUX_VERSION_CODE */
++
++    return (t_TaskletHandle)p_Task;
++}
++
++
++void XX_FreeTasklet (t_TaskletHandle h_Tasklet)
++{
++    if (h_Tasklet)
++        XX_Free(h_Tasklet);
++}
++
++int XX_ScheduleTask(t_TaskletHandle h_Tasklet, int immediate)
++{
++    int ans;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++    if (immediate)
++        ans = schedule_work(h_Tasklet);
++    else
++        ans = schedule_delayed_work(h_Tasklet, 1);
++#else
++    if (immediate)
++        ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, 0);
++    else
++        ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, HZ);
++#endif /* LINUX_VERSION_CODE */
++
++    return ans;
++}
++
++void XX_FlushScheduledTasks(void)
++{
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++    flush_scheduled_tasks();
++#else
++    flush_scheduled_work();
++#endif    /* LINUX_VERSION_CODE */
++}
++
++int XX_TaskletIsQueued(t_TaskletHandle h_Tasklet)
++{
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++    return (int)(((struct work_struct *)h_Tasklet)->pending);
++#else
++    return (int)delayed_work_pending(&((t_Tasklet *)h_Tasklet)->dwork);
++#endif    /* LINUX_VERSION_CODE */
++}
++
++void XX_SetTaskletData(t_TaskletHandle h_Tasklet, t_Handle data)
++{
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++    ((struct tq_struct *)h_Tasklet)->data = data;
++#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++    ((struct work_struct *)h_Tasklet)->data = data;
++#else
++    ((t_Tasklet *)h_Tasklet)->h_Data = data;
++#endif    /* LINUX_VERSION_CODE */
++}
++
++t_Handle XX_GetTaskletData(t_TaskletHandle h_Tasklet)
++{
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++    return (t_Handle)(((struct work_struct *)h_Tasklet)->data);
++#else
++    return ((t_Tasklet *)h_Tasklet)->h_Data;
++#endif    /* LINUX_VERSION_CODE */
++}
++
++
++/*****************************************************************************/
++/*                         Spinlock Service Routines                         */
++/*****************************************************************************/
++
++t_Handle XX_InitSpinlock(void)
++{
++    spinlock_t *p_Spinlock = (spinlock_t *)XX_Malloc(sizeof(spinlock_t));
++    if (!p_Spinlock)
++        return NULL;
++
++    spin_lock_init(p_Spinlock);
++
++    return (t_Handle)p_Spinlock;
++}
++
++void XX_FreeSpinlock(t_Handle h_Spinlock)
++{
++    if (h_Spinlock)
++        XX_Free(h_Spinlock);
++}
++
++void XX_LockSpinlock(t_Handle h_Spinlock)
++{
++    spin_lock((spinlock_t *)h_Spinlock);
++}
++
++void XX_UnlockSpinlock(t_Handle h_Spinlock)
++{
++    spin_unlock((spinlock_t *)h_Spinlock);
++}
++
++uint32_t XX_LockIntrSpinlock(t_Handle h_Spinlock)
++{
++    unsigned long intrFlags;
++    spin_lock_irqsave((spinlock_t *)h_Spinlock, intrFlags);
++    return intrFlags;
++}
++
++void XX_UnlockIntrSpinlock(t_Handle h_Spinlock, uint32_t intrFlags)
++{
++     spin_unlock_irqrestore((spinlock_t *)h_Spinlock, (unsigned long)intrFlags);
++}
++
++
++/*****************************************************************************/
++/*                        Timers Service Routines                            */
++/*****************************************************************************/
++/* The time now is in mili sec. resolution */
++uint32_t XX_CurrentTime(void)
++{
++    return (jiffies*1000)/HZ;
++}
++
++
++t_Handle XX_CreateTimer(void)
++{
++    struct timer_list *p_Timer = (struct timer_list *)XX_Malloc(sizeof(struct timer_list));
++    if (p_Timer)
++    {
++        memset(p_Timer, 0, sizeof(struct timer_list));
++        init_timer(p_Timer);
++    }
++    return (t_Handle)p_Timer;
++}
++
++void XX_FreeTimer(t_Handle h_Timer)
++{
++    if (h_Timer)
++        XX_Free(h_Timer);
++}
++
++void XX_StartTimer(t_Handle h_Timer,
++                   uint32_t msecs,
++                   bool     periodic,
++                   void     (*f_TimerExpired)(t_Handle),
++                   t_Handle h_Arg)
++{
++    int                 tmp_jiffies = (msecs*HZ)/1000;
++    struct timer_list   *p_Timer = (struct timer_list *)h_Timer;
++
++    SANITY_CHECK_RETURN((periodic == FALSE), E_NOT_SUPPORTED);
++
++    p_Timer->function = (void (*)(unsigned long))f_TimerExpired;
++    p_Timer->data = (unsigned long)h_Arg;
++    if ((msecs*HZ)%1000)
++        tmp_jiffies++;
++    p_Timer->expires = (jiffies + tmp_jiffies);
++
++    add_timer((struct timer_list *)h_Timer);
++}
++
++void XX_SetTimerData(t_Handle h_Timer, t_Handle data)
++{
++    struct timer_list   *p_Timer = (struct timer_list *)h_Timer;
++
++    p_Timer->data = (unsigned long)data;
++}
++
++t_Handle XX_GetTimerData(t_Handle h_Timer)
++{
++    struct timer_list   *p_Timer = (struct timer_list *)h_Timer;
++
++    return (t_Handle)p_Timer->data;
++}
++
++uint32_t   XX_GetExpirationTime(t_Handle h_Timer)
++{
++    struct timer_list   *p_Timer = (struct timer_list *)h_Timer;
++
++    return (uint32_t)p_Timer->expires;
++}
++
++void XX_StopTimer(t_Handle h_Timer)
++{
++    del_timer((struct timer_list *)h_Timer);
++}
++
++void XX_ModTimer(t_Handle h_Timer, uint32_t msecs)
++{
++    int tmp_jiffies = (msecs*HZ)/1000;
++
++    if ((msecs*HZ)%1000)
++        tmp_jiffies++;
++    mod_timer((struct timer_list *)h_Timer, jiffies + tmp_jiffies);
++}
++
++int XX_TimerIsActive(t_Handle h_Timer)
++{
++  return timer_pending((struct timer_list *)h_Timer);
++}
++
++uint32_t XX_Sleep(uint32_t msecs)
++{
++    int tmp_jiffies = (msecs*HZ)/1000;
++
++    if ((msecs*HZ)%1000)
++        tmp_jiffies++;
++    return schedule_timeout(tmp_jiffies);
++}
++
++/*BEWARE!!!!! UDelay routine is BUSY WAITTING!!!!!*/
++void XX_UDelay(uint32_t usecs)
++{
++    udelay(usecs);
++}
++
++/* TODO: verify that these are correct */
++#define MSG_BODY_SIZE       512
++typedef t_Error (t_MsgHandler) (t_Handle h_Mod, uint32_t msgId, uint8_t msgBody[MSG_BODY_SIZE]);
++typedef void (t_MsgCompletionCB) (t_Handle h_Arg, uint8_t msgBody[MSG_BODY_SIZE]);
++t_Error XX_SendMessage(char                 *p_DestAddr,
++                       uint32_t             msgId,
++                       uint8_t              msgBody[MSG_BODY_SIZE],
++                       t_MsgCompletionCB    *f_CompletionCB,
++                       t_Handle             h_CBArg);
++
++typedef struct {
++    char            *p_Addr;
++    t_MsgHandler    *f_MsgHandlerCB;
++    t_Handle        h_Mod;
++    t_List          node;
++} t_MsgHndlr;
++#define MSG_HNDLR_OBJECT(ptr)  LIST_OBJECT(ptr, t_MsgHndlr, node)
++
++LIST(msgHndlrList);
++
++static void EnqueueMsgHndlr(t_MsgHndlr *p_MsgHndlr)
++{
++    uint32_t   intFlags;
++
++    intFlags = XX_DisableAllIntr();
++    LIST_AddToTail(&p_MsgHndlr->node, &msgHndlrList);
++    XX_RestoreAllIntr(intFlags);
++}
++/* TODO: add this for multi-platform support
++static t_MsgHndlr * DequeueMsgHndlr(void)
++{
++    t_MsgHndlr *p_MsgHndlr = NULL;
++    uint32_t   intFlags;
++
++    intFlags = XX_DisableAllIntr();
++    if (!LIST_IsEmpty(&msgHndlrList))
++    {
++        p_MsgHndlr = MSG_HNDLR_OBJECT(msgHndlrList.p_Next);
++        LIST_DelAndInit(&p_MsgHndlr->node);
++    }
++    XX_RestoreAllIntr(intFlags);
++
++    return p_MsgHndlr;
++}
++*/
++static t_MsgHndlr * FindMsgHndlr(char *p_Addr)
++{
++    t_MsgHndlr  *p_MsgHndlr;
++    t_List      *p_Pos;
++
++    LIST_FOR_EACH(p_Pos, &msgHndlrList)
++    {
++        p_MsgHndlr = MSG_HNDLR_OBJECT(p_Pos);
++        if (strstr(p_MsgHndlr->p_Addr, p_Addr))
++            return p_MsgHndlr;
++    }
++
++    return NULL;
++}
++
++t_Error XX_RegisterMessageHandler   (char *p_Addr, t_MsgHandler *f_MsgHandlerCB, t_Handle h_Mod)
++{
++    t_MsgHndlr  *p_MsgHndlr;
++    uint32_t    len;
++
++    p_MsgHndlr = (t_MsgHndlr*)XX_Malloc(sizeof(t_MsgHndlr));
++    if (!p_MsgHndlr)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("message handler object!!!"));
++    memset(p_MsgHndlr, 0, sizeof(t_MsgHndlr));
++
++    len = strlen(p_Addr);
++    p_MsgHndlr->p_Addr = (char*)XX_Malloc(len+1);
++    strncpy(p_MsgHndlr->p_Addr,p_Addr, (uint32_t)(len+1));
++
++    p_MsgHndlr->f_MsgHandlerCB = f_MsgHandlerCB;
++    p_MsgHndlr->h_Mod = h_Mod;
++    INIT_LIST(&p_MsgHndlr->node);
++    EnqueueMsgHndlr(p_MsgHndlr);
++
++    return E_OK;
++}
++
++t_Error XX_UnregisterMessageHandler (char *p_Addr)
++{
++    t_MsgHndlr *p_MsgHndlr = FindMsgHndlr(p_Addr);
++    if (!p_MsgHndlr)
++        RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!"));
++
++    LIST_Del(&p_MsgHndlr->node);
++    XX_Free(p_MsgHndlr->p_Addr);
++    XX_Free(p_MsgHndlr);
++
++    return E_OK;
++}
++
++t_Error XX_SendMessage(char                 *p_DestAddr,
++                       uint32_t             msgId,
++                       uint8_t              msgBody[MSG_BODY_SIZE],
++                       t_MsgCompletionCB    *f_CompletionCB,
++                       t_Handle             h_CBArg)
++{
++    t_Error     ans;
++    t_MsgHndlr  *p_MsgHndlr = FindMsgHndlr(p_DestAddr);
++    if (!p_MsgHndlr)
++        RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!"));
++
++    ans = p_MsgHndlr->f_MsgHandlerCB(p_MsgHndlr->h_Mod, msgId, msgBody);
++
++    if (f_CompletionCB)
++        f_CompletionCB(h_CBArg, msgBody);
++
++    return ans;
++}
++
++t_Error XX_IpcRegisterMsgHandler(char                   addr[XX_IPC_MAX_ADDR_NAME_LENGTH],
++                                 t_IpcMsgHandler        *f_MsgHandler,
++                                 t_Handle               h_Module,
++                                 uint32_t               replyLength)
++{
++    UNUSED(addr);UNUSED(f_MsgHandler);UNUSED(h_Module);UNUSED(replyLength);
++    return E_OK;
++}
++
++t_Error XX_IpcUnregisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH])
++{
++    UNUSED(addr);
++    return E_OK;
++}
++
++
++t_Error XX_IpcSendMessage(t_Handle           h_Session,
++                          uint8_t            *p_Msg,
++                          uint32_t           msgLength,
++                          uint8_t            *p_Reply,
++                          uint32_t           *p_ReplyLength,
++                          t_IpcMsgCompletion *f_Completion,
++                          t_Handle           h_Arg)
++{
++    UNUSED(h_Session); UNUSED(p_Msg); UNUSED(msgLength); UNUSED(p_Reply);
++    UNUSED(p_ReplyLength); UNUSED(f_Completion); UNUSED(h_Arg);
++    return E_OK;
++}
++
++t_Handle XX_IpcInitSession(char destAddr[XX_IPC_MAX_ADDR_NAME_LENGTH],
++                           char srcAddr[XX_IPC_MAX_ADDR_NAME_LENGTH])
++{
++    UNUSED(destAddr); UNUSED(srcAddr);
++    return E_OK;
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
++int GetDeviceIrqNum(int irq)
++{
++    struct device_node  *iPar;
++    struct irq_domain   *irqHost;
++    uint32_t            hwIrq;
++
++    /* Get the interrupt controller */
++    iPar = of_find_node_by_name(NULL, "mpic");
++    hwIrq = 0;
++
++    ASSERT_COND(iPar != NULL);
++    /* Get the irq host */
++    irqHost = irq_find_host(iPar);
++    of_node_put(iPar);
++
++    /* Create irq mapping */
++    return irq_create_mapping(irqHost, hwIrq);
++}
++#else
++#error "kernel not supported!!!"
++#endif    /* LINUX_VERSION_CODE */
++
++void * XX_PhysToVirt(physAddress_t addr)
++{
++    return UINT_TO_PTR(SYS_PhysToVirt((uint64_t)addr));
++}
++
++physAddress_t XX_VirtToPhys(void * addr)
++{
++    return (physAddress_t)SYS_VirtToPhys(PTR_TO_UINT(addr));
++}
++
++void * xx_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment)
++{
++    uintptr_t   *returnCode, tmp;
++
++    if (alignment < sizeof(uintptr_t))
++        alignment = sizeof(uintptr_t);
++    size += alignment + sizeof(returnCode);
++    tmp = (uintptr_t)xx_Malloc(size);
++    if (tmp == 0)
++        return NULL;
++    returnCode = (uintptr_t*)((tmp + alignment + sizeof(returnCode)) & ~((uintptr_t)alignment - 1));
++    *(returnCode - 1) = tmp;
++
++    return (void*)returnCode;
++}
++
++void xx_FreeSmart(void *p)
++{
++    xx_Free((void*)(*((uintptr_t *)(p) - 1)));
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_linux.c
+@@ -0,0 +1,918 @@
++/*
++ * Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**************************************************************************//**
++ @File          xx_linux.c
++
++ @Description   XX routines implementation for Linux.
++*//***************************************************************************/
++#include <linux/version.h>
++
++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
++#define MODVERSIONS
++#endif
++#ifdef MODVERSIONS
++#include <config/modversions.h>
++#endif /* MODVERSIONS */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/ptrace.h>
++#include <linux/errno.h>
++#include <linux/ioport.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/fs.h>
++#include <linux/vmalloc.h>
++#include <linux/init.h>
++#include <linux/timer.h>
++#include <linux/spinlock.h>
++#include <linux/delay.h>
++#include <linux/proc_fs.h>
++#include <linux/smp.h>
++#include <linux/of.h>
++#ifdef CONFIG_FMAN_ARM
++#include <linux/irqdomain.h>
++#endif
++
++#include <linux/workqueue.h>
++
++#ifdef BIGPHYSAREA_ENABLE
++#include <linux/bigphysarea.h>
++#endif /* BIGPHYSAREA_ENABLE */
++
++#ifndef CONFIG_FMAN_ARM
++#include <sysdev/fsl_soc.h>
++#endif
++#include <asm/pgtable.h>
++#include <asm/irq.h>
++#include <asm/bitops.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/atomic.h>
++#include <asm/string.h>
++#include <asm/byteorder.h>
++#include <asm/page.h>
++
++#include "error_ext.h"
++#include "std_ext.h"
++#include "list_ext.h"
++#include "mm_ext.h"
++#include "sys_io_ext.h"
++#include "xx.h"
++
++
++#define __ERR_MODULE__      MODULE_UNKNOWN
++
++#ifdef BIGPHYSAREA_ENABLE
++#define MAX_ALLOCATION_SIZE     128 * 1024 /* Maximum size allocated with kmalloc is 128K */
++
++
++/* TODO: large allocations => use big phys area */
++/******************************************************************************
++ * routine:     get_nr_pages
++ *
++ * description:
++ *     calculates the number of memory pages for a given size (in bytes)
++ *
++ * arguments:
++ *     size       - the number of bytes
++ *
++ * return code:
++ *     The number of pages
++ *
++ *****************************************************************************/
++static __inline__ uint32_t get_nr_pages (uint32_t size)
++{
++    return (uint32_t)((size >> PAGE_SHIFT) + (size & PAGE_SHIFT ? 1 : 0));
++}
++
++static bool in_big_phys_area (uint32_t addr)
++{
++    uint32_t base, size;
++
++    bigphysarea_get_details (&base, &size);
++    return ((addr >= base) && (addr < base + size));
++}
++#endif /* BIGPHYSAREA_ENABLE */
++
++void * xx_Malloc(uint32_t n)
++{
++    void        *a;
++    uint32_t    flags;
++
++    flags = XX_DisableAllIntr();
++#ifdef BIGPHYSAREA_ENABLE
++    if (n >= MAX_ALLOCATION_SIZE)
++        a = (void*)bigphysarea_alloc_pages(get_nr_pages(n), 0, GFP_ATOMIC);
++    else
++#endif /* BIGPHYSAREA_ENABLE */
++    a = (void *)kmalloc((uint32_t)n, GFP_ATOMIC);
++    if (!a)
++        XX_Print("No memory for XX_Malloc\n");
++    XX_RestoreAllIntr(flags);
++
++    return a;
++}
++
++void xx_Free(void *p)
++{
++#ifdef BIGPHYSAREA_ENABLE
++    if (in_big_phys_area ((uint32_t)p))
++        bigphysarea_free_pages(p);
++    else
++#endif /* BIGPHYSAREA_ENABLE */
++    kfree(p);
++}
++
++void XX_Exit(int status)
++{
++    WARN(1, "\n\nFMD: fatal error, driver can't go on!!!\n\n");
++}
++
++#define BUF_SIZE    512
++void XX_Print(char *str, ...)
++{
++    va_list args;
++#ifdef CONFIG_SMP
++    char buf[BUF_SIZE];
++#endif /* CONFIG_SMP */
++
++    va_start(args, str);
++#ifdef CONFIG_SMP
++    if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE)
++        printk(KERN_WARNING "Illegal string to print!\n    more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE);
++    printk(KERN_CRIT "cpu%d/%d: %s", raw_smp_processor_id(), NR_CPUS, buf);
++#else
++    vprintk(str, args);
++#endif /* CONFIG_SMP */
++    va_end(args);
++}
++
++void XX_Fprint(void *file, char *str, ...)
++{
++    va_list args;
++#ifdef CONFIG_SMP
++    char buf[BUF_SIZE];
++#endif /* CONFIG_SMP */
++
++    va_start(args, str);
++#ifdef CONFIG_SMP
++    if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE)
++        printk(KERN_WARNING "Illegal string to print!\n    more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE);
++    printk (KERN_CRIT "cpu%d/%d: %s", raw_smp_processor_id(), NR_CPUS, buf);
++
++#else
++    vprintk(str, args);
++#endif /* CONFIG_SMP */
++    va_end(args);
++}
++
++#ifdef DEBUG_XX_MALLOC
++typedef void (*t_ffn)(void *);
++typedef struct {
++    t_ffn       f_free;
++    void        *mem;
++    char        *fname;
++    int         fline;
++    uint32_t    size;
++    t_List      node;
++} t_MemDebug;
++#define MEMDBG_OBJECT(p_List) LIST_OBJECT(p_List, t_MemDebug, node)
++
++LIST(memDbgLst);
++
++
++void * XX_MallocDebug(uint32_t size, char *fname, int line)
++{
++    void       *mem;
++    t_MemDebug *p_MemDbg;
++
++    p_MemDbg = (t_MemDebug *)xx_Malloc(sizeof(t_MemDebug));
++    if (p_MemDbg == NULL)
++        return NULL;
++
++    mem = xx_Malloc(size);
++    if (mem == NULL)
++    {
++        XX_Free(p_MemDbg);
++        return NULL;
++    }
++
++    INIT_LIST(&p_MemDbg->node);
++    p_MemDbg->f_free = xx_Free;
++    p_MemDbg->mem    = mem;
++    p_MemDbg->fname  = fname;
++    p_MemDbg->fline  = line;
++    p_MemDbg->size   = size+sizeof(t_MemDebug);
++    LIST_AddToTail(&p_MemDbg->node, &memDbgLst);
++
++    return mem;
++}
++
++void * XX_MallocSmartDebug(uint32_t size,
++                           int      memPartitionId,
++                           uint32_t align,
++                           char     *fname,
++                           int      line)
++{
++    void       *mem;
++    t_MemDebug *p_MemDbg;
++
++    p_MemDbg = (t_MemDebug *)XX_Malloc(sizeof(t_MemDebug));
++    if (p_MemDbg == NULL)
++        return NULL;
++
++    mem = xx_MallocSmart((uint32_t)size, memPartitionId, align);
++    if (mem == NULL)
++    {
++        XX_Free(p_MemDbg);
++        return NULL;
++    }
++
++    INIT_LIST(&p_MemDbg->node);
++    p_MemDbg->f_free = xx_FreeSmart;
++    p_MemDbg->mem    = mem;
++    p_MemDbg->fname  = fname;
++    p_MemDbg->fline  = line;
++    p_MemDbg->size   = size+sizeof(t_MemDebug);
++    LIST_AddToTail(&p_MemDbg->node, &memDbgLst);
++
++    return mem;
++}
++
++static void debug_free(void *mem)
++{
++    t_List      *p_MemDbgLh = NULL;
++    t_MemDebug  *p_MemDbg;
++    bool        found = FALSE;
++
++    if (LIST_IsEmpty(&memDbgLst))
++    {
++        REPORT_ERROR(MAJOR, E_ALREADY_FREE, ("Unbalanced free (0x%08x)", mem));
++        return;
++    }
++
++    LIST_FOR_EACH(p_MemDbgLh, &memDbgLst)
++    {
++        p_MemDbg = MEMDBG_OBJECT(p_MemDbgLh);
++        if (p_MemDbg->mem == mem)
++        {
++            found = TRUE;
++            break;
++        }
++    }
++
++    if (!found)
++    {
++        REPORT_ERROR(MAJOR, E_NOT_FOUND,
++                     ("Attempt to free unallocated address (0x%08x)",mem));
++        dump_stack();
++        return;
++    }
++
++    LIST_Del(p_MemDbgLh);
++    p_MemDbg->f_free(mem);
++    p_MemDbg->f_free(p_MemDbg);
++}
++
++void XX_FreeSmart(void *p)
++{
++    debug_free(p);
++}
++
++
++void XX_Free(void *p)
++{
++    debug_free(p);
++}
++
++#else /* not DEBUG_XX_MALLOC */
++void * XX_Malloc(uint32_t size)
++{
++    return xx_Malloc(size);
++}
++
++void * XX_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment)
++{
++    return xx_MallocSmart(size,memPartitionId, alignment);
++}
++
++void XX_FreeSmart(void *p)
++{
++    xx_FreeSmart(p);
++}
++
++
++void XX_Free(void *p)
++{
++    xx_Free(p);
++}
++#endif /* not DEBUG_XX_MALLOC */
++
++
++#if (defined(REPORT_EVENTS) && (REPORT_EVENTS > 0))
++void XX_EventById(uint32_t event, t_Handle appId, uint16_t flags, char *msg)
++{
++    e_Event eventCode = (e_Event)event;
++
++    UNUSED(eventCode);
++    UNUSED(appId);
++    UNUSED(flags);
++    UNUSED(msg);
++}
++#endif /* (defined(REPORT_EVENTS) && ... */
++
++
++uint32_t XX_DisableAllIntr(void)
++{
++    unsigned long flags;
++
++#ifdef local_irq_save_nort
++    local_irq_save_nort(flags);
++#else
++    local_irq_save(flags);
++#endif
++
++    return (uint32_t)flags;
++}
++
++void XX_RestoreAllIntr(uint32_t flags)
++{
++#ifdef local_irq_restore_nort
++    local_irq_restore_nort((unsigned long)flags);
++#else
++    local_irq_restore((unsigned long)flags);
++#endif
++}
++
++t_Error XX_Call( uint32_t qid, t_Error (* f)(t_Handle), t_Handle id, t_Handle appId, uint16_t flags )
++{
++    UNUSED(qid);
++    UNUSED(appId);
++    UNUSED(flags);
++
++    return f(id);
++}
++
++int XX_IsICacheEnable(void)
++{
++    return TRUE;
++}
++
++int XX_IsDCacheEnable(void)
++{
++    return TRUE;
++}
++
++
++typedef struct {
++    t_Isr       *f_Isr;
++    t_Handle    handle;
++} t_InterruptHandler;
++
++
++t_Handle interruptHandlers[0x00010000];
++
++#ifdef CONFIG_FMAN_ARM
++static irqreturn_t LinuxInterruptHandler (int irq, void *dev_id)
++{
++    t_InterruptHandler *p_IntrHndl = (t_InterruptHandler *)dev_id;
++    p_IntrHndl->f_Isr(p_IntrHndl->handle);
++    return IRQ_HANDLED;
++}
++#endif
++
++t_Error XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle)
++{
++#ifdef CONFIG_FMAN_ARM
++    const char *device;
++    t_InterruptHandler *p_IntrHndl;
++
++    device = GetDeviceName(irq);
++    if (device == NULL)
++        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Interrupt source - %d", irq));
++
++    p_IntrHndl = (t_InterruptHandler *)XX_Malloc(sizeof(t_InterruptHandler));
++    if (p_IntrHndl == NULL)
++        RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
++    p_IntrHndl->f_Isr = f_Isr;
++    p_IntrHndl->handle = handle;
++    interruptHandlers[irq] = p_IntrHndl;
++
++    if (request_irq(GetDeviceIrqNum(irq), LinuxInterruptHandler, 0, device, p_IntrHndl) < 0)
++        RETURN_ERROR(MAJOR, E_BUSY, ("Can't get IRQ %s\n", device));
++    disable_irq(GetDeviceIrqNum(irq));
++#endif
++    return E_OK;
++}
++
++t_Error XX_FreeIntr(int irq)
++{
++    t_InterruptHandler *p_IntrHndl = interruptHandlers[irq];
++    free_irq(GetDeviceIrqNum(irq), p_IntrHndl);
++    XX_Free(p_IntrHndl);
++    interruptHandlers[irq] = 0;
++    return E_OK;
++}
++
++t_Error XX_EnableIntr(int irq)
++{
++    enable_irq(GetDeviceIrqNum(irq));
++    return E_OK;
++}
++
++t_Error XX_DisableIntr(int irq)
++{
++    disable_irq(GetDeviceIrqNum(irq));
++    return E_OK;
++}
++
++
++/*****************************************************************************/
++/*                       Tasklet Service Routines                            */
++/*****************************************************************************/
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++typedef struct
++{
++    t_Handle            h_Data;
++    void                (*f_Callback) (void *);
++    struct delayed_work dwork;
++} t_Tasklet;
++
++static void GenericTaskletCallback(struct work_struct *p_Work)
++{
++    t_Tasklet *p_Task = container_of(p_Work, t_Tasklet, dwork.work);
++
++    p_Task->f_Callback(p_Task->h_Data);
++}
++#endif    /* LINUX_VERSION_CODE */
++
++
++t_TaskletHandle XX_InitTasklet (void (*routine)(void *), void *data)
++{
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++    struct work_struct *p_Task;
++    p_Task = (struct work_struct *)XX_Malloc(sizeof(struct work_struct));
++    INIT_WORK(p_Task, routine, data);
++#else
++    t_Tasklet *p_Task = (t_Tasklet *)XX_Malloc(sizeof(t_Tasklet));
++    p_Task->h_Data = data;
++    p_Task->f_Callback = routine;
++    INIT_DELAYED_WORK(&p_Task->dwork, GenericTaskletCallback);
++#endif    /* LINUX_VERSION_CODE */
++
++    return (t_TaskletHandle)p_Task;
++}
++
++
++void XX_FreeTasklet (t_TaskletHandle h_Tasklet)
++{
++    if (h_Tasklet)
++        XX_Free(h_Tasklet);
++}
++
++int XX_ScheduleTask(t_TaskletHandle h_Tasklet, int immediate)
++{
++    int ans;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++    if (immediate)
++        ans = schedule_work(h_Tasklet);
++    else
++        ans = schedule_delayed_work(h_Tasklet, 1);
++#else
++    if (immediate)
++        ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, 0);
++    else
++        ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, HZ);
++#endif /* LINUX_VERSION_CODE */
++
++    return ans;
++}
++
++void XX_FlushScheduledTasks(void)
++{
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++    flush_scheduled_tasks();
++#else
++    flush_scheduled_work();
++#endif    /* LINUX_VERSION_CODE */
++}
++
++int XX_TaskletIsQueued(t_TaskletHandle h_Tasklet)
++{
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++    return (int)(((struct work_struct *)h_Tasklet)->pending);
++#else
++    return (int)delayed_work_pending(&((t_Tasklet *)h_Tasklet)->dwork);
++#endif    /* LINUX_VERSION_CODE */
++}
++
++void XX_SetTaskletData(t_TaskletHandle h_Tasklet, t_Handle data)
++{
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++    ((struct tq_struct *)h_Tasklet)->data = data;
++#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++    ((struct work_struct *)h_Tasklet)->data = data;
++#else
++    ((t_Tasklet *)h_Tasklet)->h_Data = data;
++#endif    /* LINUX_VERSION_CODE */
++}
++
++t_Handle XX_GetTaskletData(t_TaskletHandle h_Tasklet)
++{
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++    return (t_Handle)(((struct work_struct *)h_Tasklet)->data);
++#else
++    return ((t_Tasklet *)h_Tasklet)->h_Data;
++#endif    /* LINUX_VERSION_CODE */
++}
++
++
++/*****************************************************************************/
++/*                         Spinlock Service Routines                         */
++/*****************************************************************************/
++
++t_Handle XX_InitSpinlock(void)
++{
++    spinlock_t *p_Spinlock = (spinlock_t *)XX_Malloc(sizeof(spinlock_t));
++    if (!p_Spinlock)
++        return NULL;
++
++    spin_lock_init(p_Spinlock);
++
++    return (t_Handle)p_Spinlock;
++}
++
++void XX_FreeSpinlock(t_Handle h_Spinlock)
++{
++    if (h_Spinlock)
++        XX_Free(h_Spinlock);
++}
++
++void XX_LockSpinlock(t_Handle h_Spinlock)
++{
++    spin_lock((spinlock_t *)h_Spinlock);
++}
++
++void XX_UnlockSpinlock(t_Handle h_Spinlock)
++{
++    spin_unlock((spinlock_t *)h_Spinlock);
++}
++
++uint32_t XX_LockIntrSpinlock(t_Handle h_Spinlock)
++{
++    unsigned long intrFlags;
++    spin_lock_irqsave((spinlock_t *)h_Spinlock, intrFlags);
++    return intrFlags;
++}
++
++void XX_UnlockIntrSpinlock(t_Handle h_Spinlock, uint32_t intrFlags)
++{
++     spin_unlock_irqrestore((spinlock_t *)h_Spinlock, (unsigned long)intrFlags);
++}
++
++
++/*****************************************************************************/
++/*                        Timers Service Routines                            */
++/*****************************************************************************/
++/* The time now is in mili sec. resolution */
++uint32_t XX_CurrentTime(void)
++{
++    return (jiffies*1000)/HZ;
++}
++
++
++t_Handle XX_CreateTimer(void)
++{
++    struct timer_list *p_Timer = (struct timer_list *)XX_Malloc(sizeof(struct timer_list));
++    if (p_Timer)
++    {
++        memset(p_Timer, 0, sizeof(struct timer_list));
++        init_timer(p_Timer);
++    }
++    return (t_Handle)p_Timer;
++}
++
++void XX_FreeTimer(t_Handle h_Timer)
++{
++    if (h_Timer)
++        XX_Free(h_Timer);
++}
++
++void XX_StartTimer(t_Handle h_Timer,
++                   uint32_t msecs,
++                   bool     periodic,
++                   void     (*f_TimerExpired)(t_Handle),
++                   t_Handle h_Arg)
++{
++    int                 tmp_jiffies = (msecs*HZ)/1000;
++    struct timer_list   *p_Timer = (struct timer_list *)h_Timer;
++
++    SANITY_CHECK_RETURN((periodic == FALSE), E_NOT_SUPPORTED);
++
++    p_Timer->function = (void (*)(unsigned long))f_TimerExpired;
++    p_Timer->data = (unsigned long)h_Arg;
++    if ((msecs*HZ)%1000)
++        tmp_jiffies++;
++    p_Timer->expires = (jiffies + tmp_jiffies);
++
++    add_timer((struct timer_list *)h_Timer);
++}
++
++void XX_SetTimerData(t_Handle h_Timer, t_Handle data)
++{
++    struct timer_list   *p_Timer = (struct timer_list *)h_Timer;
++
++    p_Timer->data = (unsigned long)data;
++}
++
++t_Handle XX_GetTimerData(t_Handle h_Timer)
++{
++    struct timer_list   *p_Timer = (struct timer_list *)h_Timer;
++
++    return (t_Handle)p_Timer->data;
++}
++
++uint32_t   XX_GetExpirationTime(t_Handle h_Timer)
++{
++    struct timer_list   *p_Timer = (struct timer_list *)h_Timer;
++
++    return (uint32_t)p_Timer->expires;
++}
++
++void XX_StopTimer(t_Handle h_Timer)
++{
++    del_timer((struct timer_list *)h_Timer);
++}
++
++void XX_ModTimer(t_Handle h_Timer, uint32_t msecs)
++{
++    int tmp_jiffies = (msecs*HZ)/1000;
++
++    if ((msecs*HZ)%1000)
++        tmp_jiffies++;
++    mod_timer((struct timer_list *)h_Timer, jiffies + tmp_jiffies);
++}
++
++int XX_TimerIsActive(t_Handle h_Timer)
++{
++  return timer_pending((struct timer_list *)h_Timer);
++}
++
++uint32_t XX_Sleep(uint32_t msecs)
++{
++    int tmp_jiffies = (msecs*HZ)/1000;
++
++    if ((msecs*HZ)%1000)
++        tmp_jiffies++;
++    return schedule_timeout(tmp_jiffies);
++}
++
++/*BEWARE!!!!! UDelay routine is BUSY WAITTING!!!!!*/
++void XX_UDelay(uint32_t usecs)
++{
++    udelay(usecs);
++}
++
++/* TODO: verify that these are correct */
++#define MSG_BODY_SIZE       512
++typedef t_Error (t_MsgHandler) (t_Handle h_Mod, uint32_t msgId, uint8_t msgBody[MSG_BODY_SIZE]);
++typedef void (t_MsgCompletionCB) (t_Handle h_Arg, uint8_t msgBody[MSG_BODY_SIZE]);
++t_Error XX_SendMessage(char                 *p_DestAddr,
++                       uint32_t             msgId,
++                       uint8_t              msgBody[MSG_BODY_SIZE],
++                       t_MsgCompletionCB    *f_CompletionCB,
++                       t_Handle             h_CBArg);
++
++typedef struct {
++    char            *p_Addr;
++    t_MsgHandler    *f_MsgHandlerCB;
++    t_Handle        h_Mod;
++    t_List          node;
++} t_MsgHndlr;
++#define MSG_HNDLR_OBJECT(ptr)  LIST_OBJECT(ptr, t_MsgHndlr, node)
++
++LIST(msgHndlrList);
++
++static void EnqueueMsgHndlr(t_MsgHndlr *p_MsgHndlr)
++{
++    uint32_t   intFlags;
++
++    intFlags = XX_DisableAllIntr();
++    LIST_AddToTail(&p_MsgHndlr->node, &msgHndlrList);
++    XX_RestoreAllIntr(intFlags);
++}
++/* TODO: add this for multi-platform support
++static t_MsgHndlr * DequeueMsgHndlr(void)
++{
++    t_MsgHndlr *p_MsgHndlr = NULL;
++    uint32_t   intFlags;
++
++    intFlags = XX_DisableAllIntr();
++    if (!LIST_IsEmpty(&msgHndlrList))
++    {
++        p_MsgHndlr = MSG_HNDLR_OBJECT(msgHndlrList.p_Next);
++        LIST_DelAndInit(&p_MsgHndlr->node);
++    }
++    XX_RestoreAllIntr(intFlags);
++
++    return p_MsgHndlr;
++}
++*/
++static t_MsgHndlr * FindMsgHndlr(char *p_Addr)
++{
++    t_MsgHndlr  *p_MsgHndlr;
++    t_List      *p_Pos;
++
++    LIST_FOR_EACH(p_Pos, &msgHndlrList)
++    {
++        p_MsgHndlr = MSG_HNDLR_OBJECT(p_Pos);
++        if (strstr(p_MsgHndlr->p_Addr, p_Addr))
++            return p_MsgHndlr;
++    }
++
++    return NULL;
++}
++
++t_Error XX_RegisterMessageHandler   (char *p_Addr, t_MsgHandler *f_MsgHandlerCB, t_Handle h_Mod)
++{
++    t_MsgHndlr  *p_MsgHndlr;
++    uint32_t    len;
++
++    p_MsgHndlr = (t_MsgHndlr*)XX_Malloc(sizeof(t_MsgHndlr));
++    if (!p_MsgHndlr)
++        RETURN_ERROR(MINOR, E_NO_MEMORY, ("message handler object!!!"));
++    memset(p_MsgHndlr, 0, sizeof(t_MsgHndlr));
++
++    len = strlen(p_Addr);
++    p_MsgHndlr->p_Addr = (char*)XX_Malloc(len+1);
++    strncpy(p_MsgHndlr->p_Addr,p_Addr, (uint32_t)(len+1));
++
++    p_MsgHndlr->f_MsgHandlerCB = f_MsgHandlerCB;
++    p_MsgHndlr->h_Mod = h_Mod;
++    INIT_LIST(&p_MsgHndlr->node);
++    EnqueueMsgHndlr(p_MsgHndlr);
++
++    return E_OK;
++}
++
++t_Error XX_UnregisterMessageHandler (char *p_Addr)
++{
++    t_MsgHndlr *p_MsgHndlr = FindMsgHndlr(p_Addr);
++    if (!p_MsgHndlr)
++        RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!"));
++
++    LIST_Del(&p_MsgHndlr->node);
++    XX_Free(p_MsgHndlr->p_Addr);
++    XX_Free(p_MsgHndlr);
++
++    return E_OK;
++}
++
++t_Error XX_SendMessage(char                 *p_DestAddr,
++                       uint32_t             msgId,
++                       uint8_t              msgBody[MSG_BODY_SIZE],
++                       t_MsgCompletionCB    *f_CompletionCB,
++                       t_Handle             h_CBArg)
++{
++    t_Error     ans;
++    t_MsgHndlr  *p_MsgHndlr = FindMsgHndlr(p_DestAddr);
++    if (!p_MsgHndlr)
++        RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!"));
++
++    ans = p_MsgHndlr->f_MsgHandlerCB(p_MsgHndlr->h_Mod, msgId, msgBody);
++
++    if (f_CompletionCB)
++        f_CompletionCB(h_CBArg, msgBody);
++
++    return ans;
++}
++
++t_Error XX_IpcRegisterMsgHandler(char                   addr[XX_IPC_MAX_ADDR_NAME_LENGTH],
++                                 t_IpcMsgHandler        *f_MsgHandler,
++                                 t_Handle               h_Module,
++                                 uint32_t               replyLength)
++{
++    UNUSED(addr);UNUSED(f_MsgHandler);UNUSED(h_Module);UNUSED(replyLength);
++    return E_OK;
++}
++
++t_Error XX_IpcUnregisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH])
++{
++    UNUSED(addr);
++    return E_OK;
++}
++
++
++t_Error XX_IpcSendMessage(t_Handle           h_Session,
++                          uint8_t            *p_Msg,
++                          uint32_t           msgLength,
++                          uint8_t            *p_Reply,
++                          uint32_t           *p_ReplyLength,
++                          t_IpcMsgCompletion *f_Completion,
++                          t_Handle           h_Arg)
++{
++    UNUSED(h_Session); UNUSED(p_Msg); UNUSED(msgLength); UNUSED(p_Reply);
++    UNUSED(p_ReplyLength); UNUSED(f_Completion); UNUSED(h_Arg);
++    return E_OK;
++}
++
++t_Handle XX_IpcInitSession(char destAddr[XX_IPC_MAX_ADDR_NAME_LENGTH],
++                           char srcAddr[XX_IPC_MAX_ADDR_NAME_LENGTH])
++{
++    UNUSED(destAddr); UNUSED(srcAddr);
++    return E_OK;
++}
++
++/*Forced to introduce due to PRINT_FMT_PARAMS define*/
++uint32_t E500_GetId(void)
++{
++    return raw_smp_processor_id();
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
++int GetDeviceIrqNum(int irq)
++{
++    struct device_node  *iPar;
++    struct irq_domain   *irqHost;
++    uint32_t            hwIrq;
++
++    /* Get the interrupt controller */
++    iPar = of_find_node_by_name(NULL, "mpic");
++    hwIrq = 0;
++
++    ASSERT_COND(iPar != NULL);
++    /* Get the irq host */
++    irqHost = irq_find_host(iPar);
++    of_node_put(iPar);
++
++    /* Create irq mapping */
++    return irq_create_mapping(irqHost, hwIrq);
++}
++#else
++#error "kernel not supported!!!"
++#endif    /* LINUX_VERSION_CODE */
++
++void * XX_PhysToVirt(physAddress_t addr)
++{
++    return UINT_TO_PTR(SYS_PhysToVirt((uint64_t)addr));
++}
++
++physAddress_t XX_VirtToPhys(void * addr)
++{
++    return (physAddress_t)SYS_VirtToPhys(PTR_TO_UINT(addr));
++}
++
++void * xx_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment)
++{
++    uintptr_t   *returnCode, tmp;
++
++    if (alignment < sizeof(uintptr_t))
++        alignment = sizeof(uintptr_t);
++    size += alignment + sizeof(returnCode);
++    tmp = (uintptr_t)xx_Malloc(size);
++    if (tmp == 0)
++        return NULL;
++    returnCode = (uintptr_t*)((tmp + alignment + sizeof(returnCode)) & ~((uintptr_t)alignment - 1));
++    *(returnCode - 1) = tmp;
++
++    return (void*)returnCode;
++}
++
++void xx_FreeSmart(void *p)
++{
++    xx_Free((void*)(*((uintptr_t *)(p) - 1)));
++}
+--- /dev/null
++++ b/include/linux/fsl/svr.h
+@@ -0,0 +1,97 @@
++/*
++ * MPC85xx cpu type detection
++ *
++ * Copyright 2011-2012 Freescale Semiconductor, Inc.
++ *
++ * This is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#ifndef FSL_SVR_H
++#define FSL_SVR_H
++
++#define SVR_REV(svr)  ((svr) & 0xFF)          /* SOC design resision */
++#define SVR_MAJ(svr)  (((svr) >>  4) & 0xF)   /* Major revision field*/
++#define SVR_MIN(svr)  (((svr) >>  0) & 0xF)   /* Minor revision field*/
++
++/* Some parts define SVR[0:23] as the SOC version */
++#define SVR_SOC_VER(svr) (((svr) >> 8) & 0xFFF7FF)    /* SOC Version fields */
++
++#define SVR_8533      0x803400
++#define SVR_8535      0x803701
++#define SVR_8536      0x803700
++#define SVR_8540      0x803000
++#define SVR_8541      0x807200
++#define SVR_8543      0x803200
++#define SVR_8544      0x803401
++#define SVR_8545      0x803102
++#define SVR_8547      0x803101
++#define SVR_8548      0x803100
++#define SVR_8555      0x807100
++#define SVR_8560      0x807000
++#define SVR_8567      0x807501
++#define SVR_8568      0x807500
++#define SVR_8569      0x808000
++#define SVR_8572      0x80E000
++#define SVR_P1010     0x80F100
++#define SVR_P1011     0x80E500
++#define SVR_P1012     0x80E501
++#define SVR_P1013     0x80E700
++#define SVR_P1014     0x80F101
++#define SVR_P1017     0x80F700
++#define SVR_P1020     0x80E400
++#define SVR_P1021     0x80E401
++#define SVR_P1022     0x80E600
++#define SVR_P1023     0x80F600
++#define SVR_P1024     0x80E402
++#define SVR_P1025     0x80E403
++#define SVR_P2010     0x80E300
++#define SVR_P2020     0x80E200
++#define SVR_P2040     0x821000
++#define SVR_P2041     0x821001
++#define SVR_P3041     0x821103
++#define SVR_P4040     0x820100
++#define SVR_P4080     0x820000
++#define SVR_P5010     0x822100
++#define SVR_P5020     0x822000
++#define SVR_P5021     0X820500
++#define SVR_P5040     0x820400
++#define SVR_T4240     0x824000
++#define SVR_T4120     0x824001
++#define SVR_T4160     0x824100
++#define SVR_T4080     0x824102
++#define SVR_C291      0x850000
++#define SVR_C292      0x850020
++#define SVR_C293      0x850030
++#define SVR_B4860     0X868000
++#define SVR_G4860     0x868001
++#define SVR_G4060     0x868003
++#define SVR_B4440     0x868100
++#define SVR_G4440     0x868101
++#define SVR_B4420     0x868102
++#define SVR_B4220     0x868103
++#define SVR_T1040     0x852000
++#define SVR_T1041     0x852001
++#define SVR_T1042     0x852002
++#define SVR_T1020     0x852100
++#define SVR_T1021     0x852101
++#define SVR_T1022     0x852102
++#define SVR_T1023     0x854100
++#define SVR_T1024     0x854000
++#define SVR_T2080     0x853000
++#define SVR_T2081     0x853100
++
++#define SVR_8610      0x80A000
++#define SVR_8641      0x809000
++#define SVR_8641D     0x809001
++
++#define SVR_9130      0x860001
++#define SVR_9131      0x860000
++#define SVR_9132      0x861000
++#define SVR_9232      0x861400
++
++#define SVR_Unknown   0xFFFFFF
++
++#endif
+--- /dev/null
++++ b/include/uapi/linux/fmd/Kbuild
+@@ -0,0 +1,5 @@
++header-y += integrations/
++header-y += Peripherals/
++
++header-y += ioctls.h
++header-y += net_ioctls.h
+--- /dev/null
++++ b/include/uapi/linux/fmd/Peripherals/Kbuild
+@@ -0,0 +1,4 @@
++header-y += fm_ioctls.h
++header-y += fm_port_ioctls.h
++header-y += fm_pcd_ioctls.h
++header-y += fm_test_ioctls.h
+--- /dev/null
++++ b/include/uapi/linux/fmd/Peripherals/fm_ioctls.h
+@@ -0,0 +1,628 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**************************************************************************//**
++ @File          fm_ioctls.h
++
++ @Description   FM Char device ioctls
++*//***************************************************************************/
++#ifndef __FM_IOCTLS_H
++#define __FM_IOCTLS_H
++
++
++/**************************************************************************//**
++ @Group         lnx_ioctl_FM_grp Frame Manager Linux IOCTL API
++
++ @Description   FM Linux ioctls definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Collection    FM IOCTL device ('/dev') definitions
++*//***************************************************************************/
++#define DEV_FM_NAME                 "fm" /**< Name of the FM chardev */
++
++#define DEV_FM_MINOR_BASE           0
++#define DEV_FM_PCD_MINOR_BASE       (DEV_FM_MINOR_BASE + 1)                                 /*/dev/fmx-pcd */
++#define DEV_FM_OH_PORTS_MINOR_BASE  (DEV_FM_PCD_MINOR_BASE + 1)                             /*/dev/fmx-port-ohy */
++#define DEV_FM_RX_PORTS_MINOR_BASE  (DEV_FM_OH_PORTS_MINOR_BASE + FM_MAX_NUM_OF_OH_PORTS)   /*/dev/fmx-port-rxy */
++#define DEV_FM_TX_PORTS_MINOR_BASE  (DEV_FM_RX_PORTS_MINOR_BASE + FM_MAX_NUM_OF_RX_PORTS)   /*/dev/fmx-port-txy */
++#define DEV_FM_MAX_MINORS           (DEV_FM_TX_PORTS_MINOR_BASE + FM_MAX_NUM_OF_TX_PORTS)
++
++#define FM_IOC_NUM(n)       (n)
++#define FM_PCD_IOC_NUM(n)   (n+20)
++#define FM_PORT_IOC_NUM(n)  (n+70)
++/* @} */
++
++#define IOC_FM_MAX_NUM_OF_PORTS         64
++
++
++/**************************************************************************//**
++ @Description   Enum for defining port types
++                (must match enum e_FmPortType defined in fm_ext.h)
++*//***************************************************************************/
++typedef enum ioc_fm_port_type {
++    e_IOC_FM_PORT_TYPE_OH_OFFLINE_PARSING = 0,  /**< Offline parsing port */
++    e_IOC_FM_PORT_TYPE_RX,                      /**< 1G Rx port */
++    e_IOC_FM_PORT_TYPE_RX_10G,                  /**< 10G Rx port */
++    e_IOC_FM_PORT_TYPE_TX,                      /**< 1G Tx port */
++    e_IOC_FM_PORT_TYPE_TX_10G,                  /**< 10G Tx port */
++    e_IOC_FM_PORT_TYPE_DUMMY
++} ioc_fm_port_type;
++
++
++/**************************************************************************//**
++ @Group         lnx_ioctl_FM_lib_grp FM library
++
++ @Description   FM API functions, definitions and enums
++                The FM module is the main driver module and is a mandatory module
++                for FM driver users. Before any further module initialization,
++                this module must be initialized.
++                The FM is a "single-tone" module. It is responsible of the common
++                HW modules: FPM, DMA, common QMI, common BMI initializations and
++                run-time control routines. This module must be initialized always
++                when working with any of the FM modules.
++                NOTE - We assumes that the FML will be initialize only by core No. 0!
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   FM Exceptions
++*//***************************************************************************/
++typedef enum ioc_fm_exceptions {
++    e_IOC_FM_EX_DMA_BUS_ERROR,              /**< DMA bus error. */
++    e_IOC_EX_DMA_READ_ECC,               /**< Read Buffer ECC error (Valid for FM rev < 6)*/
++    e_IOC_EX_DMA_SYSTEM_WRITE_ECC,       /**< Write Buffer ECC error on system side (Valid for FM rev < 6)*/
++    e_IOC_EX_DMA_FM_WRITE_ECC,           /**< Write Buffer ECC error on FM side (Valid for FM rev < 6)*/
++    e_IOC_EX_DMA_SINGLE_PORT_ECC,        /**< Single Port ECC error on FM side (Valid for FM rev > 6)*/
++    e_IOC_EX_FPM_STALL_ON_TASKS,         /**< Stall of tasks on FPM */
++    e_IOC_EX_FPM_SINGLE_ECC,             /**< Single ECC on FPM. */
++    e_IOC_EX_FPM_DOUBLE_ECC,             /**< Double ECC error on FPM ram access */
++    e_IOC_EX_QMI_SINGLE_ECC,             /**< Single ECC on QMI. */
++    e_IOC_EX_QMI_DOUBLE_ECC,             /**< Double bit ECC occurred on QMI */
++    e_IOC_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,/**< Dequeue from unknown port id */
++    e_IOC_EX_BMI_LIST_RAM_ECC,           /**< Linked List RAM ECC error */
++    e_IOC_EX_BMI_STORAGE_PROFILE_ECC,    /**< Storage Profile ECC Error */
++    e_IOC_EX_BMI_STATISTICS_RAM_ECC,     /**< Statistics Count RAM ECC Error Enable */
++    e_IOC_EX_BMI_DISPATCH_RAM_ECC,       /**< Dispatch RAM ECC Error Enable */
++    e_IOC_EX_IRAM_ECC,                   /**< Double bit ECC occurred on IRAM*/
++    e_IOC_EX_MURAM_ECC                   /**< Double bit ECC occurred on MURAM*/
++} ioc_fm_exceptions;
++
++/**************************************************************************//**
++ @Group         lnx_ioctl_FM_runtime_control_grp FM Runtime Control Unit
++
++ @Description   FM Runtime control unit API functions, definitions and enums.
++                The FM driver provides a set of control routines for each module.
++                These routines may only be called after the module was fully
++                initialized (both configuration and initialization routines were
++                called). They are typically used to get information from hardware
++                (status, counters/statistics, revision etc.), to modify a current
++                state or to force/enable a required action. Run-time control may
++                be called whenever necessary and as many times as needed.
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Collection   General FM defines.
++ *//***************************************************************************/
++#define IOC_FM_MAX_NUM_OF_VALID_PORTS  (FM_MAX_NUM_OF_OH_PORTS + \
++                                        FM_MAX_NUM_OF_1G_RX_PORTS +  \
++                                        FM_MAX_NUM_OF_10G_RX_PORTS + \
++                                        FM_MAX_NUM_OF_1G_TX_PORTS +  \
++                                        FM_MAX_NUM_OF_10G_TX_PORTS)
++/* @} */
++
++/**************************************************************************//**
++ @Description   Structure for Port bandwidth requirement. Port is identified
++                by type and relative id.
++                (must be identical to t_FmPortBandwidth defined in fm_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_port_bandwidth_t {
++    ioc_fm_port_type    type;           /**< FM port type */
++    uint8_t             relative_port_id; /**< Type relative port id */
++    uint8_t             bandwidth;      /**< bandwidth - (in term of percents) */
++} ioc_fm_port_bandwidth_t;
++
++/**************************************************************************//**
++ @Description   A Structure containing an array of Port bandwidth requirements.
++                The user should state the ports requiring bandwidth in terms of
++                percentage - i.e. all port's bandwidths in the array must add
++                up to 100.
++                (must be identical to t_FmPortsBandwidthParams defined in fm_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_port_bandwidth_params {
++    uint8_t                     num_of_ports;
++                                /**< num of ports listed in the array below */
++    ioc_fm_port_bandwidth_t     ports_bandwidths[IOC_FM_MAX_NUM_OF_VALID_PORTS];
++                                /**< for each port, it's bandwidth (all port's
++                                  bandwidths must add up to 100.*/
++} ioc_fm_port_bandwidth_params;
++
++/**************************************************************************//**
++ @Description   enum for defining FM counters
++*//***************************************************************************/
++typedef enum ioc_fm_counters {
++    e_IOC_FM_COUNTERS_ENQ_TOTAL_FRAME,              /**< QMI total enqueued frames counter */
++    e_IOC_FM_COUNTERS_DEQ_TOTAL_FRAME,              /**< QMI total dequeued frames counter */
++    e_IOC_FM_COUNTERS_DEQ_0,                        /**< QMI 0 frames from QMan counter */
++    e_IOC_FM_COUNTERS_DEQ_1,                        /**< QMI 1 frames from QMan counter */
++    e_IOC_FM_COUNTERS_DEQ_2,                        /**< QMI 2 frames from QMan counter */
++    e_IOC_FM_COUNTERS_DEQ_3,                        /**< QMI 3 frames from QMan counter */
++    e_IOC_FM_COUNTERS_DEQ_FROM_DEFAULT,             /**< QMI dequeue from default queue counter */
++    e_IOC_FM_COUNTERS_DEQ_FROM_CONTEXT,             /**< QMI dequeue from FQ context counter */
++    e_IOC_FM_COUNTERS_DEQ_FROM_FD,                  /**< QMI dequeue from FD command field counter */
++    e_IOC_FM_COUNTERS_DEQ_CONFIRM,                  /**< QMI dequeue confirm counter */
++} ioc_fm_counters;
++
++typedef struct ioc_fm_obj_t {
++    void            *obj;
++} ioc_fm_obj_t;
++
++/**************************************************************************//**
++ @Description   A structure for returning revision information
++                (must match struct t_FmRevisionInfo declared in fm_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_revision_info_t {
++    uint8_t         major;               /**< Major revision */
++    uint8_t         minor;               /**< Minor revision */
++} ioc_fm_revision_info_t;
++
++/**************************************************************************//**
++ @Description   A structure for FM counters
++*//***************************************************************************/
++typedef struct ioc_fm_counters_params_t {
++    ioc_fm_counters cnt;                /**< The requested counter */
++    uint32_t        val;                /**< The requested value to get/set from/into the counter */
++} ioc_fm_counters_params_t;
++
++typedef union ioc_fm_api_version_t {
++    struct {
++        uint8_t major;
++        uint8_t minor;
++        uint8_t respin;
++        uint8_t reserved;
++    } version;
++    uint32_t ver;
++} ioc_fm_api_version_t;
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Description   A structure of information about each of the external
++                buffer pools used by a port or storage-profile.
++                (must be identical to t_FmExtPoolParams defined in fm_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_ext_pool_params {
++    uint8_t                 id;     /**< External buffer pool id */
++    uint16_t                size;   /**< External buffer pool buffer size */
++} ioc_fm_ext_pool_params;
++
++/**************************************************************************//**
++ @Description   A structure for informing the driver about the external
++                buffer pools allocated in the BM and used by a port or a
++                storage-profile.
++                (must be identical to t_FmExtPools defined in fm_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_ext_pools {
++    uint8_t                 num_of_pools_used;     /**< Number of pools use by this port */
++    ioc_fm_ext_pool_params  ext_buf_pool[FM_PORT_MAX_NUM_OF_EXT_POOLS];
++                                                /**< Parameters for each port */
++} ioc_fm_ext_pools;
++
++typedef struct ioc_fm_vsp_params_t {
++    void                *p_fm;              /**< A handle to the FM object this VSP related to */
++    ioc_fm_ext_pools    ext_buf_pools;        /**< Which external buffer pools are used
++                                                 (up to FM_PORT_MAX_NUM_OF_EXT_POOLS), and their sizes.
++                                                 parameter associated with Rx / OP port */
++    uint16_t            liodn_offset;        /**< VSP's LIODN offset */
++    struct {
++        ioc_fm_port_type port_type;          /**< Port type */
++        uint8_t         port_id;             /**< Port Id - relative to type */
++    } port_params;
++    uint8_t             relative_profile_id;  /**< VSP Id - relative to VSP's range
++                                                 defined in relevant FM object */
++    void                *id;                /**< return value */
++} ioc_fm_vsp_params_t;
++#endif /* (DPAA_VERSION >= 11) */
++
++/**************************************************************************//**
++ @Description   A structure for defining BM pool depletion criteria
++*//***************************************************************************/
++typedef struct ioc_fm_buf_pool_depletion_t {
++    bool        pools_grp_mode_enable;              /**< select mode in which pause frames will be sent after
++                                                         a number of pools (all together!) are depleted */
++    uint8_t     num_of_pools;                       /**< the number of depleted pools that will invoke
++                                                         pause frames transmission. */
++    bool        pools_to_consider[BM_MAX_NUM_OF_POOLS];
++                                                    /**< For each pool, TRUE if it should be considered for
++                                                         depletion (Note - this pool must be used by this port!). */
++    bool        single_pool_mode_enable;            /**< select mode in which pause frames will be sent after
++                                                         a single-pool is depleted; */
++    bool        pools_to_consider_for_single_mode[BM_MAX_NUM_OF_POOLS];
++                                                    /**< For each pool, TRUE if it should be considered for
++                                                         depletion (Note - this pool must be used by this port!) */
++#if (DPAA_VERSION >= 11)
++    bool        pfc_priorities_en[FM_MAX_NUM_OF_PFC_PRIORITIES];
++                                                    /**< This field is used by the MAC as the Priority Enable Vector in the PFC frame
++                                                         which is transmitted */
++#endif /* (DPAA_VERSION >= 11) */
++} ioc_fm_buf_pool_depletion_t;
++
++#if (DPAA_VERSION >= 11)
++typedef struct ioc_fm_buf_pool_depletion_params_t {
++    void        *p_fm_vsp;
++    ioc_fm_buf_pool_depletion_t fm_buf_pool_depletion;
++} ioc_fm_buf_pool_depletion_params_t;
++#endif /* (DPAA_VERSION >= 11) */
++
++typedef struct ioc_fm_buffer_prefix_content_t {
++    uint16_t    priv_data_size;       /**< Number of bytes to be left at the beginning
++                                         of the external buffer; Note that the private-area will
++                                         start from the base of the buffer address. */
++    bool        pass_prs_result;      /**< TRUE to pass the parse result to/from the FM;
++                                         User may use FM_PORT_GetBufferPrsResult() in order to
++                                         get the parser-result from a buffer. */
++    bool        pass_time_stamp;      /**< TRUE to pass the timeStamp to/from the FM
++                                         User may use FM_PORT_GetBufferTimeStamp() in order to
++                                         get the parser-result from a buffer. */
++    bool        pass_hash_result;     /**< TRUE to pass the KG hash result to/from the FM
++                                         User may use FM_PORT_GetBufferHashResult() in order to
++                                         get the parser-result from a buffer. */
++    bool        pass_all_other_pcd_info; /**< Add all other Internal-Context information:
++                                         AD, hash-result, key, etc. */
++    uint16_t    data_align;          /**< 0 to use driver's default alignment [64],
++                                         other value for selecting a data alignment (must be a power of 2);
++                                         if write optimization is used, must be >= 16. */
++    uint8_t     manip_extra_space;    /**< Maximum extra size needed (insertion-size minus removal-size);
++                                         Note that this field impacts the size of the buffer-prefix
++                                         (i.e. it pushes the data offset);
++                                         This field is irrelevant if DPAA_VERSION==10 */
++} ioc_fm_buffer_prefix_content_t;
++
++typedef struct ioc_fm_buffer_prefix_content_params_t {
++    void        *p_fm_vsp;
++    ioc_fm_buffer_prefix_content_t fm_buffer_prefix_content;
++} ioc_fm_buffer_prefix_content_params_t;
++
++#if (DPAA_VERSION >= 11)
++typedef struct ioc_fm_vsp_config_no_sg_params_t {
++    void        *p_fm_vsp;
++    bool        no_sg;
++} ioc_fm_vsp_config_no_sg_params_t;
++
++typedef struct ioc_fm_vsp_prs_result_params_t {
++    void        *p_fm_vsp;
++    void        *p_data;
++} ioc_fm_vsp_prs_result_params_t;
++#endif
++
++typedef struct fm_ctrl_mon_t {
++    uint8_t     percent_cnt[2];
++} fm_ctrl_mon_t;
++
++typedef struct ioc_fm_ctrl_mon_counters_params_t {
++    uint8_t     fm_ctrl_index;
++    fm_ctrl_mon_t *p_mon;
++} ioc_fm_ctrl_mon_counters_params_t;
++
++/**************************************************************************//**
++ @Function      FM_IOC_SET_PORTS_BANDWIDTH
++
++ @Description   Sets relative weights between ports when accessing common resources.
++
++ @Param[in]     ioc_fm_port_bandwidth_params    Port bandwidth percentages,
++ their sum must equal 100.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++#define FM_IOC_SET_PORTS_BANDWIDTH                             _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(2), ioc_fm_port_bandwidth_params)
++
++/**************************************************************************//**
++ @Function      FM_IOC_GET_REVISION
++
++ @Description   Returns the FM revision
++
++ @Param[out]    ioc_fm_revision_info_t  A structure of revision information parameters.
++
++ @Return        None.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++#define FM_IOC_GET_REVISION                                    _IOR(FM_IOC_TYPE_BASE, FM_IOC_NUM(3), ioc_fm_revision_info_t)
++
++/**************************************************************************//**
++ @Function      FM_IOC_GET_COUNTER
++
++ @Description   Reads one of the FM counters.
++
++ @Param[in,out] ioc_fm_counters_params_t The requested counter parameters.
++
++ @Return        Counter's current value.
++
++ @Cautions      Allowed only following FM_Init().
++                Note that it is user's responsibilty to call this routine only
++                for enabled counters, and there will be no indication if a
++                disabled counter is accessed.
++*//***************************************************************************/
++#define FM_IOC_GET_COUNTER                                    _IOWR(FM_IOC_TYPE_BASE, FM_IOC_NUM(4), ioc_fm_counters_params_t)
++
++/**************************************************************************//**
++ @Function      FM_IOC_SET_COUNTER
++
++ @Description   Sets a value to an enabled counter. Use "0" to reset the counter.
++
++ @Param[in]     ioc_fm_counters_params_t The requested counter parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++#define FM_IOC_SET_COUNTER                                    _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(5), ioc_fm_counters_params_t)
++
++/**************************************************************************//**
++ @Function      FM_IOC_FORCE_INTR
++
++ @Description   Causes an interrupt event on the requested source.
++
++ @Param[in]     ioc_fm_exceptions   An exception to be forced.
++
++ @Return        E_OK on success; Error code if the exception is not enabled,
++                or is not able to create interrupt.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++#define FM_IOC_FORCE_INTR                                    _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(6), ioc_fm_exceptions)
++
++/**************************************************************************//**
++ @Function      FM_IOC_GET_API_VERSION
++
++ @Description   Reads the FMD IOCTL API version.
++
++ @Param[in,out] ioc_fm_api_version_t The requested counter parameters.
++
++ @Return        Version's value.
++*//***************************************************************************/
++#define FM_IOC_GET_API_VERSION                               _IOR(FM_IOC_TYPE_BASE, FM_IOC_NUM(7), ioc_fm_api_version_t)
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Function      FM_VSP_Config
++
++ @Description   Creates descriptor for the FM VSP module.
++
++                The routine returns a handle (descriptor) to the FM VSP object.
++                This descriptor must be passed as first parameter to all other
++                FM VSP function calls.
++
++                No actual initialization or configuration of FM hardware is
++                done by this routine.
++
++@Param[in]      p_FmVspParams   Pointer to data structure of parameters
++
++ @Retval        Handle to FM VSP object, or NULL for Failure.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_IOC_VSP_CONFIG_COMPAT                             _IOWR(FM_IOC_TYPE_BASE, FM_IOC_NUM(8), ioc_compat_fm_vsp_params_t)
++#endif
++#define FM_IOC_VSP_CONFIG                                    _IOWR(FM_IOC_TYPE_BASE, FM_IOC_NUM(8), ioc_fm_vsp_params_t)
++
++/**************************************************************************//**
++ @Function      FM_VSP_Init
++
++ @Description   Initializes the FM VSP module
++
++ @Param[in]     h_FmVsp - FM VSP module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_IOC_VSP_INIT_COMPAT                               _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(9), ioc_compat_fm_obj_t)
++#endif
++#define FM_IOC_VSP_INIT                                      _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(9), ioc_fm_obj_t)
++
++/**************************************************************************//**
++ @Function      FM_VSP_Free
++
++ @Description   Frees all resources that were assigned to FM VSP module.
++
++                Calling this routine invalidates the descriptor.
++
++ @Param[in]     h_FmVsp - FM VSP module descriptor
++
++ @Return        E_OK on success; Error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_IOC_VSP_FREE_COMPAT                               _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(10), ioc_compat_fm_obj_t)
++#endif
++#define FM_IOC_VSP_FREE                                      _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(10), ioc_fm_obj_t)
++
++/**************************************************************************//**
++ @Function      FM_VSP_ConfigPoolDepletion
++
++ @Description   Calling this routine enables pause frame generation depending on the
++                depletion status of BM pools. It also defines the conditions to activate
++                this functionality. By default, this functionality is disabled.
++
++ @Param[in]     ioc_fm_buf_pool_depletion_params_t      A structure holding the required parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_VSP_Config() and before FM_VSP_Init().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_IOC_VSP_CONFIG_POOL_DEPLETION_COMPAT              _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(11), ioc_compat_fm_buf_pool_depletion_params_t)
++#endif
++#define FM_IOC_VSP_CONFIG_POOL_DEPLETION                     _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(11), ioc_fm_buf_pool_depletion_params_t)
++
++/**************************************************************************//**
++ @Function      FM_VSP_ConfigBufferPrefixContent
++
++ @Description   Defines the structure, size and content of the application buffer.
++
++                The prefix will
++                In VSPs defined for Tx ports, if 'passPrsResult', the application
++                should set a value to their offsets in the prefix of
++                the FM will save the first 'privDataSize', than,
++                depending on 'passPrsResult' and 'passTimeStamp', copy parse result
++                and timeStamp, and the packet itself (in this order), to the
++                application buffer, and to offset.
++
++                Calling this routine changes the buffer margins definitions
++                in the internal driver data base from its default
++                configuration: Data size:  [DEFAULT_FM_SP_bufferPrefixContent_privDataSize]
++                               Pass Parser result: [DEFAULT_FM_SP_bufferPrefixContent_passPrsResult].
++                               Pass timestamp: [DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp].
++
++ @Param[in]     ioc_fm_buffer_prefix_content_params_t   A structure holding the required parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_VSP_Config() and before FM_VSP_Init().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_IOC_VSP_CONFIG_BUFFER_PREFIX_CONTENT_COMPAT       _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(12), ioc_compat_fm_buffer_prefix_content_params_t)
++#endif
++#define FM_IOC_VSP_CONFIG_BUFFER_PREFIX_CONTENT              _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(12), ioc_fm_buffer_prefix_content_params_t)
++
++/**************************************************************************//**
++ @Function      FM_VSP_ConfigNoScatherGather
++
++ @Description   Calling this routine changes the possibility to receive S/G frame
++                in the internal driver data base
++                from its default configuration: optimize = [DEFAULT_FM_SP_noScatherGather]
++
++ @Param[in]     ioc_fm_vsp_config_no_sg_params_t        A structure holding the required parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_VSP_Config() and before FM_VSP_Init().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_IOC_VSP_CONFIG_NO_SG_COMPAT                     _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(13), ioc_compat_fm_vsp_config_no_sg_params_t)
++#endif
++#define FM_IOC_VSP_CONFIG_NO_SG                            _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(13), ioc_fm_vsp_config_no_sg_params_t)
++
++/**************************************************************************//**
++ @Function      FM_VSP_GetBufferPrsResult
++
++ @Description   Returns the pointer to the parse result in the data buffer.
++                In Rx ports this is relevant after reception, if parse
++                result is configured to be part of the data passed to the
++                application. For non Rx ports it may be used to get the pointer
++                of the area in the buffer where parse result should be
++                initialized - if so configured.
++                See FM_VSP_ConfigBufferPrefixContent for data buffer prefix
++                configuration.
++
++ @Param[in]     ioc_fm_vsp_prs_result_params_t  A structure holding the required parameters.
++
++ @Return        Parse result pointer on success, NULL if parse result was not
++                configured for this port.
++
++ @Cautions      Allowed only following FM_VSP_Init().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_IOC_VSP_GET_BUFFER_PRS_RESULT_COMPAT            _IOWR(FM_IOC_TYPE_BASE, FM_IOC_NUM(14), ioc_compat_fm_vsp_prs_result_params_t)
++#endif
++#define FM_IOC_VSP_GET_BUFFER_PRS_RESULT                   _IOWR(FM_IOC_TYPE_BASE, FM_IOC_NUM(14), ioc_fm_vsp_prs_result_params_t)
++#endif /* (DPAA_VERSION >= 11) */
++
++/**************************************************************************//**
++ @Function      FM_CtrlMonStart
++
++ @Description   Start monitoring utilization of all available FM controllers.
++
++                In order to obtain FM controllers utilization the following sequence
++                should be used:
++                -# FM_CtrlMonStart()
++                -# FM_CtrlMonStop()
++                -# FM_CtrlMonGetCounters() - issued for each FM controller
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++#define FM_IOC_CTRL_MON_START                              _IO(FM_IOC_TYPE_BASE, FM_IOC_NUM(15))
++
++
++/**************************************************************************//**
++ @Function      FM_CtrlMonStop
++
++ @Description   Stop monitoring utilization of all available FM controllers.
++
++                In order to obtain FM controllers utilization the following sequence
++                should be used:
++                -# FM_CtrlMonStart()
++                -# FM_CtrlMonStop()
++                -# FM_CtrlMonGetCounters() - issued for each FM controller
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++#define FM_IOC_CTRL_MON_STOP                               _IO(FM_IOC_TYPE_BASE, FM_IOC_NUM(16))
++
++/**************************************************************************//**
++ @Function      FM_CtrlMonGetCounters
++
++ @Description   Obtain FM controller utilization parameters.
++
++                In order to obtain FM controllers utilization the following sequence
++                should be used:
++                -# FM_CtrlMonStart()
++                -# FM_CtrlMonStop()
++                -# FM_CtrlMonGetCounters() - issued for each FM controller
++
++ @Param[in]     ioc_fm_ctrl_mon_counters_params_t       A structure holding the required parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_IOC_CTRL_MON_GET_COUNTERS_COMPAT                _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(17), ioc_compat_fm_ctrl_mon_counters_params_t)
++#endif
++#define FM_IOC_CTRL_MON_GET_COUNTERS                       _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(17), ioc_fm_ctrl_mon_counters_params_t)
++
++/** @} */ /* end of lnx_ioctl_FM_runtime_control_grp group */
++/** @} */ /* end of lnx_ioctl_FM_lib_grp group */
++/** @} */ /* end of lnx_ioctl_FM_grp */
++
++#define FMD_API_VERSION_MAJOR 21
++#define FMD_API_VERSION_MINOR 1 
++#define FMD_API_VERSION_RESPIN 0
++
++#endif /* __FM_IOCTLS_H */
+--- /dev/null
++++ b/include/uapi/linux/fmd/Peripherals/fm_pcd_ioctls.h
+@@ -0,0 +1,3084 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/******************************************************************************
++ @File          fm_pcd_ioctls.h
++
++ @Description   FM PCD ...
++*//***************************************************************************/
++#ifndef __FM_PCD_IOCTLS_H
++#define __FM_PCD_IOCTLS_H
++
++#include "net_ioctls.h"
++#include "fm_ioctls.h"
++
++
++/**************************************************************************//**
++
++ @Group         lnx_ioctl_FM_grp Frame Manager Linux IOCTL API
++
++ @Description   Frame Manager Linux ioctls definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         lnx_ioctl_FM_PCD_grp FM PCD
++
++ @Description   Frame Manager PCD API functions, definitions and enums
++
++                The FM PCD module is responsible for the initialization of all
++                global classifying FM modules. This includes the parser general and
++                common registers, the key generator global and common registers,
++                and the policer global and common registers.
++                In addition, the FM PCD SW module will initialize all required
++                key generator schemes, coarse classification flows, and policer
++                profiles. When an FM module is configured to work with one of these
++                entities, it will register to it using the FM PORT API. The PCD
++                module will manage the PCD resources - i.e. resource management of
++                KeyGen schemes, etc.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Collection    General PCD defines
++*//***************************************************************************/
++#define IOC_FM_PCD_MAX_NUM_OF_PRIVATE_HDRS              2                   /**< Number of units/headers saved for user */
++
++#define IOC_FM_PCD_PRS_NUM_OF_HDRS                      16                  /**< Number of headers supported by HW parser */
++#define IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS         (32 - IOC_FM_PCD_MAX_NUM_OF_PRIVATE_HDRS)
++                                                                            /**< Number of distinction units is limited by
++                                                                             register size (32 bits) minus reserved bits
++                                                                             for private headers. */
++#define IOC_FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS      4                   /**< Maximum number of interchangeable headers
++                                                                             in a distinction unit */
++#define IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS               8                   /**< Total number of generic KeyGen registers */
++#define IOC_FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY       35                  /**< Max number allowed on any configuration;
++                                                                             For HW implementation reasons, in most
++                                                                             cases less than this will be allowed; The
++                                                                             driver will return an initialization error
++                                                                             if resource is unavailable. */
++#define IOC_FM_PCD_KG_NUM_OF_EXTRACT_MASKS              4                   /**< Total number of masks allowed on KeyGen extractions. */
++#define IOC_FM_PCD_KG_NUM_OF_DEFAULT_GROUPS             16                  /**< Number of default value logical groups */
++
++#define IOC_FM_PCD_PRS_NUM_OF_LABELS                    32                  /**< Maximum number of SW parser labels */
++#define IOC_FM_PCD_SW_PRS_SIZE                          0x00000800          /**< Total size of SW parser area */
++
++#define IOC_FM_PCD_MAX_MANIP_INSRT_TEMPLATE_SIZE        128                 /**< Maximum size of insertion template for
++                                                                             insert manipulation */
++
++#if DPAA_VERSION >= 11
++#define IOC_FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES        64                  /**< Maximum possible entries for frame replicator group */
++#endif /* DPAA_VERSION >= 11 */
++/* @} */
++
++#ifdef FM_CAPWAP_SUPPORT
++#error "FM_CAPWAP_SUPPORT not implemented!"
++#endif
++
++
++/**************************************************************************//**
++ @Group         lnx_ioctl_FM_PCD_init_grp FM PCD Initialization Unit
++
++ @Description   Frame Manager PCD Initialization Unit API
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   PCD counters
++                (must match enum e_FmPcdCounters defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_counters {
++    e_IOC_FM_PCD_KG_COUNTERS_TOTAL,                                 /**< KeyGen counter */
++    e_IOC_FM_PCD_PLCR_COUNTERS_RED,                                 /**< Policer counter - counts the total number of RED packets that exit the Policer. */
++    e_IOC_FM_PCD_PLCR_COUNTERS_YELLOW,                              /**< Policer counter - counts the total number of YELLOW packets that exit the Policer. */
++    e_IOC_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED,                    /**< Policer counter - counts the number of packets that changed color to RED by the Policer;
++                                                                         This is a subset of e_IOC_FM_PCD_PLCR_COUNTERS_RED packet count, indicating active color changes. */
++    e_IOC_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW,                 /**< Policer counter - counts the number of packets that changed color to YELLOW by the Policer;
++                                                                         This is a subset of e_IOC_FM_PCD_PLCR_COUNTERS_YELLOW packet count, indicating active color changes. */
++    e_IOC_FM_PCD_PLCR_COUNTERS_TOTAL,                               /**< Policer counter - counts the total number of packets passed in the Policer. */
++    e_IOC_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH,                     /**< Policer counter - counts the number of packets with length mismatch. */
++    e_IOC_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH,                       /**< Parser counter - counts the number of times the parser block is dispatched. */
++    e_IOC_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED,             /**< Parser counter - counts the number of times L2 parse result is returned (including errors). */
++    e_IOC_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED,             /**< Parser counter - counts the number of times L3 parse result is returned (including errors). */
++    e_IOC_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED,             /**< Parser counter - counts the number of times L4 parse result is returned (including errors). */
++    e_IOC_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED,           /**< Parser counter - counts the number of times SHIM parse result is returned (including errors). */
++    e_IOC_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR,    /**< Parser counter - counts the number of times L2 parse result is returned with errors. */
++    e_IOC_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR,    /**< Parser counter - counts the number of times L3 parse result is returned with errors. */
++    e_IOC_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR,    /**< Parser counter - counts the number of times L4 parse result is returned with errors. */
++    e_IOC_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR,  /**< Parser counter - counts the number of times SHIM parse result is returned with errors. */
++    e_IOC_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES,                      /**< Parser counter - counts the number of cycles spent executing soft parser instruction (including stall cycles). */
++    e_IOC_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES,                /**< Parser counter - counts the number of cycles stalled waiting for parser internal memory reads while executing soft parser instruction. */
++    e_IOC_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES,     /**< Parser counter - counts the number of cycles spent executing hard parser (including stall cycles). */
++    e_IOC_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES,                    /**< MURAM counter - counts the number of cycles while performing FMan Memory read. */
++    e_IOC_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES,              /**< MURAM counter - counts the number of cycles stalled while performing FMan Memory read. */
++    e_IOC_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES,                   /**< MURAM counter - counts the number of cycles while performing FMan Memory write. */
++    e_IOC_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES,             /**< MURAM counter - counts the number of cycles stalled while performing FMan Memory write. */
++    e_IOC_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES              /**< FPM counter - counts the number of cycles stalled while performing a FPM Command. */
++} ioc_fm_pcd_counters;
++
++/**************************************************************************//**
++ @Description   PCD interrupts
++                (must match enum e_FmPcdExceptions defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_exceptions {
++    e_IOC_FM_PCD_KG_EXCEPTION_DOUBLE_ECC,                   /**< KeyGen double-bit ECC error is detected on internal memory read access. */
++    e_IOC_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW,             /**< KeyGen scheme configuration error indicating a key size larger than 56 bytes. */
++    e_IOC_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC,                 /**< Policer double-bit ECC error has been detected on PRAM read access. */
++    e_IOC_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR,           /**< Policer access to a non-initialized profile has been detected. */
++    e_IOC_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE,    /**< Policer RAM self-initialization complete */
++    e_IOC_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE,     /**< Policer atomic action complete */
++    e_IOC_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC,                  /**< Parser double-bit ECC error */
++    e_IOC_FM_PCD_PRS_EXCEPTION_SINGLE_ECC                   /**< Parser single-bit ECC error */
++} ioc_fm_pcd_exceptions;
++
++/** @} */ /* end of lnx_ioctl_FM_PCD_init_grp group */
++
++
++/**************************************************************************//**
++ @Group         lnx_ioctl_FM_PCD_Runtime_grp FM PCD Runtime Unit
++
++ @Description   Frame Manager PCD Runtime Unit
++
++                The runtime control allows creation of PCD infrastructure modules
++                such as Network Environment Characteristics, Classification Plan
++                Groups and Coarse Classification Trees.
++                It also allows on-the-fly initialization, modification and removal
++                of PCD modules such as KeyGen schemes, coarse classification nodes
++                and Policer profiles.
++
++                In order to explain the programming model of the PCD driver interface
++                a few terms should be explained, and will be used below.
++                  - Distinction Header - One of the 16 protocols supported by the FM parser,
++                    or one of the SHIM headers (1 or 2). May be a header with a special
++                    option (see below).
++                  - Interchangeable Headers Group - This is a group of Headers recognized
++                    by either one of them. For example, if in a specific context the user
++                    chooses to treat IPv4 and IPV6 in the same way, they may create an
++                    interchangeable Headers Unit consisting of these 2 headers.
++                  - A Distinction Unit - a Distinction Header or an Interchangeable Headers
++                    Group.
++                  - Header with special option - applies to Ethernet, MPLS, VLAN, IPv4 and
++                    IPv6, includes multicast, broadcast and other protocol specific options.
++                    In terms of hardware it relates to the options available in the classification
++                    plan.
++                  - Network Environment Characteristics - a set of Distinction Units that define
++                    the total recognizable header selection for a certain environment. This is
++                    NOT the list of all headers that will ever appear in a flow, but rather
++                    everything that needs distinction in a flow, where distinction is made by KeyGen
++                    schemes and coarse classification action descriptors.
++
++                The PCD runtime modules initialization is done in stages. The first stage after
++                initializing the PCD module itself is to establish a Network Flows Environment
++                Definition. The application may choose to establish one or more such environments.
++                Later, when needed, the application will have to state, for some of its modules,
++                to which single environment it belongs.
++
++ @{
++*//***************************************************************************/
++
++
++/**************************************************************************//**
++ @Description   structure for FM counters
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_counters_params_t {
++    ioc_fm_pcd_counters cnt;                /**< The requested counter */
++    uint32_t            val;                /**< The requested value to get/set from/into the counter */
++} ioc_fm_pcd_counters_params_t;
++
++/**************************************************************************//**
++ @Description   structure for FM exception definitios
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_exception_params_t {
++    ioc_fm_pcd_exceptions exception;        /**< The requested exception */
++    bool                  enable;           /**< TRUE to enable interrupt, FALSE to mask it. */
++} ioc_fm_pcd_exception_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for SW parser labels
++                (must be identical to struct t_FmPcdPrsLabelParams defined in fm_pcd_ext.h)
++ *//***************************************************************************/
++typedef struct ioc_fm_pcd_prs_label_params_t {
++    uint32_t                instruction_offset;             /**< SW parser label instruction offset (2 bytes
++                                                                 resolution), relative to Parser RAM. */
++    ioc_net_header_type     hdr;                            /**< The existence of this header will invoke
++                                                                 the SW parser code. */
++    uint8_t                 index_per_hdr;                  /**< Normally 0, if more than one SW parser
++                                                                 attachments for the same header, use this
++                                                                 index to distinguish between them. */
++} ioc_fm_pcd_prs_label_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for SW parser
++                (Must match struct t_FmPcdPrsSwParams defined in fm_pcd_ext.h)
++ *//***************************************************************************/
++typedef struct ioc_fm_pcd_prs_sw_params_t {
++    bool                    override;                   /**< FALSE to invoke a check that nothing else
++                                                             was loaded to this address, including
++                                                             internal patches.
++                                                             TRUE to override any existing code.*/
++    uint32_t                size;                       /**< SW parser code size */
++    uint16_t                base;                       /**< SW parser base (in instruction counts!
++                                                             must be larger than 0x20)*/
++    uint8_t                 *p_code;                    /**< SW parser code */
++    uint32_t                sw_prs_data_params[IOC_FM_PCD_PRS_NUM_OF_HDRS];
++                                                        /**< SW parser data (parameters) */
++    uint8_t                 num_of_labels;              /**< Number of labels for SW parser. */
++    ioc_fm_pcd_prs_label_params_t labels_table[IOC_FM_PCD_PRS_NUM_OF_LABELS];
++                                                        /**< SW parser labels table,
++                                                             containing num_of_labels entries */
++} ioc_fm_pcd_prs_sw_params_t;
++
++/**************************************************************************//**
++ @Description   A structure to set the a KeyGen default value
++ *//***************************************************************************/
++typedef struct ioc_fm_pcd_kg_dflt_value_params_t {
++    uint8_t                         valueId;                /**< 0,1 - one of 2 global default values */
++    uint32_t                        value;                  /**< The requested default value */
++} ioc_fm_pcd_kg_dflt_value_params_t;
++
++
++/**************************************************************************//**
++ @Function      FM_PCD_Enable
++
++ @Description   This routine should be called after PCD is initialized for enabling all
++                PCD engines according to their existing configuration.
++
++ @Return        0 on success; Error code otherwise.
++
++ @Cautions      Allowed only when PCD is disabled.
++*//***************************************************************************/
++#define FM_PCD_IOC_ENABLE  _IO(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(1))
++
++/**************************************************************************//**
++ @Function      FM_PCD_Disable
++
++ @Description   This routine may be called when PCD is enabled in order to
++                disable all PCD engines. It may be called
++                only when none of the ports in the system are using the PCD.
++
++ @Return        0 on success; Error code otherwise.
++
++ @Cautions      Allowed only when PCD is enabled.
++*//***************************************************************************/
++#define FM_PCD_IOC_DISABLE  _IO(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(2))
++
++ /**************************************************************************//**
++ @Function      FM_PCD_PrsLoadSw
++
++ @Description   This routine may be called only when all ports in the
++                system are actively using the classification plan scheme.
++                In such cases it is recommended in order to save resources.
++                The driver automatically saves 8 classification plans for
++                ports that do NOT use the classification plan mechanism, to
++                avoid this (in order to save those entries) this routine may
++                be called.
++
++ @Param[in]     ioc_fm_pcd_prs_sw_params_t  A pointer to the image of the software parser code.
++
++ @Return        0 on success; Error code otherwise.
++
++ @Cautions      Allowed only when PCD is disabled.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_PRS_LOAD_SW_COMPAT  _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(3), ioc_compat_fm_pcd_prs_sw_params_t)
++#endif
++#define FM_PCD_IOC_PRS_LOAD_SW  _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(3), ioc_fm_pcd_prs_sw_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_KgSetDfltValue
++
++ @Description   Calling this routine sets a global default value to be used
++                by the KeyGen when parser does not recognize a required
++                field/header.
++                By default default values are 0.
++
++ @Param[in]     ioc_fm_pcd_kg_dflt_value_params_t   A pointer to a structure with the relevant parameters
++
++ @Return        0 on success; Error code otherwise.
++
++ @Cautions      Allowed only when PCD is disabled.
++*//***************************************************************************/
++#define FM_PCD_IOC_KG_SET_DFLT_VALUE  _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(6), ioc_fm_pcd_kg_dflt_value_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_KgSetAdditionalDataAfterParsing
++
++ @Description   Calling this routine allows the keygen to access data past
++                the parser finishing point.
++
++ @Param[in]     uint8_t   payload-offset; the number of bytes beyond the parser location.
++
++ @Return        0 on success; Error code otherwise.
++
++ @Cautions      Allowed only when PCD is disabled.
++*//***************************************************************************/
++#define FM_PCD_IOC_KG_SET_ADDITIONAL_DATA_AFTER_PARSING  _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(7), uint8_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_SetException
++
++ @Description   Calling this routine enables/disables PCD interrupts.
++
++ @Param[in]     ioc_fm_pcd_exception_params_t     Arguments struct with exception to be enabled/disabled.
++
++ @Return        0 on success; Error code otherwise.
++*//***************************************************************************/
++#define FM_PCD_IOC_SET_EXCEPTION _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(8), ioc_fm_pcd_exception_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_GetCounter
++
++ @Description   Reads one of the FM PCD counters.
++
++ @Param[in,out] ioc_fm_pcd_counters_params_t The requested counter parameters.
++
++ @Return        0 on success; Error code otherwise.
++
++ @Cautions      Note that it is user's responsibilty to call this routine only
++                for enabled counters, and there will be no indication if a
++                disabled counter is accessed.
++*//***************************************************************************/
++#define FM_PCD_IOC_GET_COUNTER  _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(9), ioc_fm_pcd_counters_params_t)
++
++/**************************************************************************//**
++
++ @Function      FM_PCD_KgSchemeGetCounter
++
++ @Description   Reads scheme packet counter.
++
++ @Param[in]     h_Scheme        scheme handle as returned by FM_PCD_KgSchemeSet().
++
++ @Return        Counter's current value.
++
++ @Cautions      Allowed only following FM_PCD_Init() & FM_PCD_KgSchemeSet().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_KG_SCHEME_GET_CNTR_COMPAT  _IOR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(4), ioc_compat_fm_pcd_kg_scheme_spc_t)
++#endif
++#define FM_PCD_IOC_KG_SCHEME_GET_CNTR  _IOR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(4), ioc_fm_pcd_kg_scheme_spc_t)
++
++#if 0
++TODO: unused IOCTL
++/**************************************************************************//**
++ @Function      FM_PCD_ModifyCounter
++
++ @Description   Writes a value to an enabled counter. Use "0" to reset the counter.
++
++ @Param[in]     ioc_fm_pcd_counters_params_t - The requested counter parameters.
++
++ @Return        0 on success; Error code otherwise.
++*//***************************************************************************/
++#define FM_PCD_IOC_MODIFY_COUNTER   _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(10), ioc_fm_pcd_counters_params_t)
++#define FM_PCD_IOC_SET_COUNTER      FM_PCD_IOC_MODIFY_COUNTER
++#endif
++
++/**************************************************************************//**
++ @Function      FM_PCD_ForceIntr
++
++ @Description   Causes an interrupt event on the requested source.
++
++ @Param[in]     ioc_fm_pcd_exceptions - An exception to be forced.
++
++ @Return        0 on success; error code if the exception is not enabled,
++                or is not able to create interrupt.
++*//***************************************************************************/
++#define FM_PCD_IOC_FORCE_INTR _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(11), ioc_fm_pcd_exceptions)
++
++/**************************************************************************//**
++ @Collection    Definitions of coarse classification parameters as required by KeyGen
++                (when coarse classification is the next engine after this scheme).
++*//***************************************************************************/
++#define IOC_FM_PCD_MAX_NUM_OF_CC_TREES              8
++#define IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS             16
++#define IOC_FM_PCD_MAX_NUM_OF_CC_UNITS              4
++#define IOC_FM_PCD_MAX_NUM_OF_KEYS                  256
++#define IOC_FM_PCD_MAX_NUM_OF_FLOWS                 (4*KILOBYTE)
++#define IOC_FM_PCD_MAX_SIZE_OF_KEY                  56
++#define IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP     16
++#define IOC_FM_PCD_LAST_KEY_INDEX                   0xffff
++#define IOC_FM_PCD_MANIP_DSCP_VALUES                64
++/* @} */
++
++/**************************************************************************//**
++ @Collection    A set of definitions to allow protocol
++                special option description.
++*//***************************************************************************/
++typedef uint32_t            ioc_protocol_opt_t;      /**< A general type to define a protocol option. */
++
++typedef ioc_protocol_opt_t  ioc_eth_protocol_opt_t;  /**< Ethernet protocol options. */
++#define IOC_ETH_BROADCAST               0x80000000   /**< Ethernet Broadcast. */
++#define IOC_ETH_MULTICAST               0x40000000   /**< Ethernet Multicast. */
++
++typedef ioc_protocol_opt_t  ioc_vlan_protocol_opt_t; /**< Vlan protocol options. */
++#define IOC_VLAN_STACKED                0x20000000   /**< Stacked VLAN. */
++
++typedef ioc_protocol_opt_t  ioc_mpls_protocol_opt_t; /**< MPLS protocol options. */
++#define IOC_MPLS_STACKED                0x10000000   /**< Stacked MPLS. */
++
++typedef ioc_protocol_opt_t  ioc_ipv4_protocol_opt_t; /**< IPv4 protocol options. */
++#define IOC_IPV4_BROADCAST_1            0x08000000   /**< IPv4 Broadcast. */
++#define IOC_IPV4_MULTICAST_1            0x04000000   /**< IPv4 Multicast. */
++#define IOC_IPV4_UNICAST_2              0x02000000   /**< Tunneled IPv4 - Unicast. */
++#define IOC_IPV4_MULTICAST_BROADCAST_2  0x01000000   /**< Tunneled IPv4 - Broadcast/Multicast. */
++
++#define IOC_IPV4_FRAG_1                 0x00000008   /**< IPV4 reassembly option.
++                                                          IPV4 Reassembly manipulation requires network
++                                                          environment with IPV4 header and IPV4_FRAG_1 option  */
++
++typedef ioc_protocol_opt_t  ioc_ipv6_protocol_opt_t; /**< IPv6 protocol options. */
++#define IOC_IPV6_MULTICAST_1            0x00800000   /**< IPv6 Multicast. */
++#define IOC_IPV6_UNICAST_2              0x00400000   /**< Tunneled IPv6 - Unicast. */
++#define IOC_IPV6_MULTICAST_2            0x00200000   /**< Tunneled IPv6 - Multicast. */
++
++#define IOC_IPV6_FRAG_1                 0x00000004   /**< IPV6 reassembly option.
++                                                          IPV6 Reassembly manipulation requires network
++                                                          environment with IPV6 header and IPV6_FRAG_1 option  */
++#if (DPAA_VERSION >= 11)
++typedef ioc_protocol_opt_t   ioc_capwap_protocol_opt_t;      /**< CAPWAP protocol options. */
++#define CAPWAP_FRAG_1               0x00000008  /**< CAPWAP reassembly option.
++                                                     CAPWAP Reassembly manipulation requires network
++                                                     environment with CAPWAP header and CAPWAP_FRAG_1 option;
++                                                     in case where fragment found, the fragment-extension offset
++                                                     may be found at 'shim2' (in parser-result). */
++#endif /* (DPAA_VERSION >= 11) */
++
++/* @} */
++
++#define IOC_FM_PCD_MANIP_MAX_HDR_SIZE               256
++#define IOC_FM_PCD_MANIP_DSCP_TO_VLAN_TRANS         64
++/**************************************************************************//**
++ @Collection    A set of definitions to support Header Manipulation selection.
++*//***************************************************************************/
++typedef uint32_t                        ioc_hdr_manip_flags_t;              /**< A general type to define a HMan update command flags. */
++
++typedef ioc_hdr_manip_flags_t           ioc_ipv4_hdr_manip_update_flags_t;  /**< IPv4 protocol HMan update command flags. */
++
++#define IOC_HDR_MANIP_IPV4_TOS          0x80000000          /**< update TOS with the given value ('tos' field
++                                                                 of ioc_fm_pcd_manip_hdr_field_update_ipv4_t) */
++#define IOC_HDR_MANIP_IPV4_ID           0x40000000          /**< update IP ID with the given value ('id' field
++                                                                 of ioc_fm_pcd_manip_hdr_field_update_ipv4_t) */
++#define IOC_HDR_MANIP_IPV4_TTL          0x20000000          /**< Decrement TTL by 1 */
++#define IOC_HDR_MANIP_IPV4_SRC          0x10000000          /**< update IP source address with the given value
++                                                                 ('src' field of ioc_fm_pcd_manip_hdr_field_update_ipv4_t) */
++#define IOC_HDR_MANIP_IPV4_DST          0x08000000          /**< update IP destination address with the given value
++                                                                 ('dst' field of ioc_fm_pcd_manip_hdr_field_update_ipv4_t) */
++
++typedef ioc_hdr_manip_flags_t           ioc_ipv6_hdr_manip_update_flags_t;  /**< IPv6 protocol HMan update command flags. */
++
++#define IOC_HDR_MANIP_IPV6_TC           0x80000000          /**< update Traffic Class address with the given value
++                                                                 ('traffic_class' field of ioc_fm_pcd_manip_hdr_field_update_ipv6_t) */
++#define IOC_HDR_MANIP_IPV6_HL           0x40000000          /**< Decrement Hop Limit by 1 */
++#define IOC_HDR_MANIP_IPV6_SRC          0x20000000          /**< update IP source address with the given value
++                                                                 ('src' field of ioc_fm_pcd_manip_hdr_field_update_ipv6_t) */
++#define IOC_HDR_MANIP_IPV6_DST          0x10000000          /**< update IP destination address with the given value
++                                                                 ('dst' field of ioc_fm_pcd_manip_hdr_field_update_ipv6_t) */
++
++typedef ioc_hdr_manip_flags_t           ioc_tcp_udp_hdr_manip_update_flags_t;/**< TCP/UDP protocol HMan update command flags. */
++
++#define IOC_HDR_MANIP_TCP_UDP_SRC       0x80000000          /**< update TCP/UDP source address with the given value
++                                                                 ('src' field of ioc_fm_pcd_manip_hdr_field_update_tcp_udp_t) */
++#define IOC_HDR_MANIP_TCP_UDP_DST       0x40000000          /**< update TCP/UDP destination address with the given value
++                                                                 ('dst' field of ioc_fm_pcd_manip_hdr_field_update_tcp_udp_t) */
++#define IOC_HDR_MANIP_TCP_UDP_CHECKSUM  0x20000000          /**< update TCP/UDP checksum */
++
++/* @} */
++
++/**************************************************************************//**
++ @Description   A type used for returning the order of the key extraction.
++                each value in this array represents the index of the extraction
++                command as defined by the user in the initialization extraction array.
++                The valid size of this array is the user define number of extractions
++                required (also marked by the second '0' in this array).
++*//***************************************************************************/
++typedef    uint8_t    ioc_fm_pcd_kg_key_order_t [IOC_FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY];
++
++/**************************************************************************//**
++ @Description   All PCD engines
++                (must match enum e_FmPcdEngine defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_engine {
++    e_IOC_FM_PCD_INVALID = 0,   /**< Invalid PCD engine */
++    e_IOC_FM_PCD_DONE,          /**< No PCD Engine indicated */
++    e_IOC_FM_PCD_KG,            /**< KeyGen */
++    e_IOC_FM_PCD_CC,            /**< Coarse Classifier */
++    e_IOC_FM_PCD_PLCR,          /**< Policer */
++    e_IOC_FM_PCD_PRS,           /**< Parser */
++#if DPAA_VERSION >= 11
++    e_IOC_FM_PCD_FR,            /**< Frame Replicator */
++#endif /* DPAA_VERSION >= 11 */
++    e_IOC_FM_PCD_HASH           /**< Hash Table */
++} ioc_fm_pcd_engine;
++
++/**************************************************************************//**
++ @Description   An enum for selecting extraction by header types
++                (Must match enum e_FmPcdExtractByHdrType defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_extract_by_hdr_type {
++    e_IOC_FM_PCD_EXTRACT_FROM_HDR,      /**< Extract bytes from header */
++    e_IOC_FM_PCD_EXTRACT_FROM_FIELD,    /**< Extract bytes from header field */
++    e_IOC_FM_PCD_EXTRACT_FULL_FIELD     /**< Extract a full field */
++} ioc_fm_pcd_extract_by_hdr_type;
++
++/**************************************************************************//**
++ @Description   An enum for selecting extraction source (when it is not the header)
++                (Must match enum e_FmPcdExtractFrom defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_extract_from {
++    e_IOC_FM_PCD_EXTRACT_FROM_FRAME_START,          /**< KG & CC: Extract from beginning of frame */
++    e_IOC_FM_PCD_EXTRACT_FROM_DFLT_VALUE,           /**< KG only: Extract from a default value */
++    e_IOC_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE,    /**< KG only: Extract from the point where parsing had finished */
++    e_IOC_FM_PCD_EXTRACT_FROM_KEY,                  /**< CC only: Field where saved KEY */
++    e_IOC_FM_PCD_EXTRACT_FROM_HASH,                 /**< CC only: Field where saved HASH */
++    e_IOC_FM_PCD_EXTRACT_FROM_PARSE_RESULT,         /**< KG & CC: Extract from the parser result */
++    e_IOC_FM_PCD_EXTRACT_FROM_ENQ_FQID,             /**< KG & CC: Extract from enqueue FQID */
++    e_IOC_FM_PCD_EXTRACT_FROM_FLOW_ID               /**< CC only: Field where saved Dequeue FQID */
++} ioc_fm_pcd_extract_from;
++
++/**************************************************************************//**
++ @Description   An enum for selecting extraction type
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_extract_type {
++    e_IOC_FM_PCD_EXTRACT_BY_HDR,                /**< Extract according to header */
++    e_IOC_FM_PCD_EXTRACT_NON_HDR,               /**< Extract from data that is not the header */
++    e_IOC_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO   /**< Extract private info as specified by user */
++} ioc_fm_pcd_extract_type;
++
++/**************************************************************************//**
++ @Description   An enum for selecting a default
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_kg_extract_dflt_select {
++    e_IOC_FM_PCD_KG_DFLT_GBL_0,          /**< Default selection is KG register 0 */
++    e_IOC_FM_PCD_KG_DFLT_GBL_1,          /**< Default selection is KG register 1 */
++    e_IOC_FM_PCD_KG_DFLT_PRIVATE_0,      /**< Default selection is a per scheme register 0 */
++    e_IOC_FM_PCD_KG_DFLT_PRIVATE_1,      /**< Default selection is a per scheme register 1 */
++    e_IOC_FM_PCD_KG_DFLT_ILLEGAL         /**< Illegal selection */
++} ioc_fm_pcd_kg_extract_dflt_select;
++
++/**************************************************************************//**
++ @Description   Enumeration type defining all default groups - each group shares
++                a default value, one of four user-initialized values.
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_kg_known_fields_dflt_types {
++    e_IOC_FM_PCD_KG_MAC_ADDR,               /**< MAC Address */
++    e_IOC_FM_PCD_KG_TCI,                    /**< TCI field */
++    e_IOC_FM_PCD_KG_ENET_TYPE,              /**< ENET Type */
++    e_IOC_FM_PCD_KG_PPP_SESSION_ID,         /**< PPP Session id */
++    e_IOC_FM_PCD_KG_PPP_PROTOCOL_ID,        /**< PPP Protocol id */
++    e_IOC_FM_PCD_KG_MPLS_LABEL,             /**< MPLS label */
++    e_IOC_FM_PCD_KG_IP_ADDR,                /**< IP addr */
++    e_IOC_FM_PCD_KG_PROTOCOL_TYPE,          /**< Protocol type */
++    e_IOC_FM_PCD_KG_IP_TOS_TC,              /**< TOS or TC */
++    e_IOC_FM_PCD_KG_IPV6_FLOW_LABEL,        /**< IPV6 flow label */
++    e_IOC_FM_PCD_KG_IPSEC_SPI,              /**< IPSEC SPI */
++    e_IOC_FM_PCD_KG_L4_PORT,                /**< L4 Port */
++    e_IOC_FM_PCD_KG_TCP_FLAG,               /**< TCP Flag */
++    e_IOC_FM_PCD_KG_GENERIC_FROM_DATA,      /**< grouping implemented by SW,
++                                                 any data extraction that is not the full
++                                                 field described above  */
++    e_IOC_FM_PCD_KG_GENERIC_FROM_DATA_NO_V, /**< grouping implemented by SW,
++                                                 any data extraction without validation */
++    e_IOC_FM_PCD_KG_GENERIC_NOT_FROM_DATA   /**< grouping implemented by SW,
++                                                 extraction from parser result or
++                                                 direct use of default value  */
++} ioc_fm_pcd_kg_known_fields_dflt_types;
++
++/**************************************************************************//**
++ @Description   Enumeration type for defining header index for scenarios with
++                multiple (tunneled) headers
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_hdr_index {
++    e_IOC_FM_PCD_HDR_INDEX_NONE     =   0,      /**< used when multiple headers not used, also
++                                                     to specify regular IP (not tunneled). */
++    e_IOC_FM_PCD_HDR_INDEX_1,                   /**< may be used for VLAN, MPLS, tunneled IP */
++    e_IOC_FM_PCD_HDR_INDEX_2,                   /**< may be used for MPLS, tunneled IP */
++    e_IOC_FM_PCD_HDR_INDEX_3,                   /**< may be used for MPLS */
++    e_IOC_FM_PCD_HDR_INDEX_LAST     =   0xFF    /**< may be used for VLAN, MPLS */
++} ioc_fm_pcd_hdr_index;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting the policer profile functional type
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_profile_type_selection {
++    e_IOC_FM_PCD_PLCR_PORT_PRIVATE,             /**< Port dedicated profile */
++    e_IOC_FM_PCD_PLCR_SHARED                    /**< Shared profile (shared within partition) */
++} ioc_fm_pcd_profile_type_selection;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting the policer profile algorithm
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_plcr_algorithm_selection {
++    e_IOC_FM_PCD_PLCR_PASS_THROUGH, /**< Policer pass through */
++    e_IOC_FM_PCD_PLCR_RFC_2698,     /**< Policer algorithm RFC 2698 */
++    e_IOC_FM_PCD_PLCR_RFC_4115      /**< Policer algorithm RFC 4115 */
++} ioc_fm_pcd_plcr_algorithm_selection;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting a policer profile color mode
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_plcr_color_mode {
++    e_IOC_FM_PCD_PLCR_COLOR_BLIND,  /**< Color blind */
++    e_IOC_FM_PCD_PLCR_COLOR_AWARE   /**< Color aware */
++} ioc_fm_pcd_plcr_color_mode;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting a policer profile color
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_plcr_color {
++    e_IOC_FM_PCD_PLCR_GREEN,    /**< Green */
++    e_IOC_FM_PCD_PLCR_YELLOW,   /**< Yellow */
++    e_IOC_FM_PCD_PLCR_RED,      /**< Red */
++    e_IOC_FM_PCD_PLCR_OVERRIDE  /**< Color override */
++} ioc_fm_pcd_plcr_color;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting the policer profile packet frame length selector
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_plcr_frame_length_select {
++  e_IOC_FM_PCD_PLCR_L2_FRM_LEN,     /**< L2 frame length */
++  e_IOC_FM_PCD_PLCR_L3_FRM_LEN,     /**< L3 frame length */
++  e_IOC_FM_PCD_PLCR_L4_FRM_LEN,     /**< L4 frame length */
++  e_IOC_FM_PCD_PLCR_FULL_FRM_LEN    /**< Full frame length */
++} ioc_fm_pcd_plcr_frame_length_select;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting roll-back frame
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_plcr_roll_back_frame_select {
++  e_IOC_FM_PCD_PLCR_ROLLBACK_L2_FRM_LEN,    /**< Rollback L2 frame length */
++  e_IOC_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN   /**< Rollback Full frame length */
++} ioc_fm_pcd_plcr_roll_back_frame_select;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting the policer profile packet or byte mode
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_plcr_rate_mode {
++    e_IOC_FM_PCD_PLCR_BYTE_MODE,    /**< Byte mode */
++    e_IOC_FM_PCD_PLCR_PACKET_MODE   /**< Packet mode */
++} ioc_fm_pcd_plcr_rate_mode;
++
++/**************************************************************************//**
++ @Description   Enumeration type for defining action of frame
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_done_action {
++    e_IOC_FM_PCD_ENQ_FRAME = 0,     /**< Enqueue frame */
++    e_IOC_FM_PCD_DROP_FRAME         /**< Drop frame */
++} ioc_fm_pcd_done_action;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting the policer counter
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_plcr_profile_counters {
++    e_IOC_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER,               /**< Green packets counter */
++    e_IOC_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER,              /**< Yellow packets counter */
++    e_IOC_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER,                 /**< Red packets counter */
++    e_IOC_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER,   /**< Recolored yellow packets counter */
++    e_IOC_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER       /**< Recolored red packets counter */
++} ioc_fm_pcd_plcr_profile_counters;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting the PCD action after extraction
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_action {
++    e_IOC_FM_PCD_ACTION_NONE,                           /**< NONE  */
++    e_IOC_FM_PCD_ACTION_EXACT_MATCH,                    /**< Exact match on the selected extraction*/
++    e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP                  /**< Indexed lookup on the selected extraction*/
++} ioc_fm_pcd_action;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of insert manipulation
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_hdr_insrt_type {
++    e_IOC_FM_PCD_MANIP_INSRT_GENERIC,                   /**< Insert according to offset & size */
++    e_IOC_FM_PCD_MANIP_INSRT_BY_HDR,                    /**< Insert according to protocol */
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++    e_IOC_FM_PCD_MANIP_INSRT_BY_TEMPLATE                /**< Insert template to start of frame */
++#endif /* FM_CAPWAP_SUPPORT */
++} ioc_fm_pcd_manip_hdr_insrt_type;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of remove manipulation
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_hdr_rmv_type {
++    e_IOC_FM_PCD_MANIP_RMV_GENERIC,                     /**< Remove according to offset & size */
++    e_IOC_FM_PCD_MANIP_RMV_BY_HDR                       /**< Remove according to offset & size */
++} ioc_fm_pcd_manip_hdr_rmv_type;
++
++/**************************************************************************//**
++ @Description   An enum for selecting specific L2 fields removal
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_hdr_rmv_specific_l2 {
++    e_IOC_FM_PCD_MANIP_HDR_RMV_ETHERNET,                /**< Ethernet/802.3 MAC */
++    e_IOC_FM_PCD_MANIP_HDR_RMV_STACKED_QTAGS,           /**< stacked QTags */
++    e_IOC_FM_PCD_MANIP_HDR_RMV_ETHERNET_AND_MPLS,       /**< MPLS and Ethernet/802.3 MAC header until
++                                                             the header which follows the MPLS header */
++    e_IOC_FM_PCD_MANIP_HDR_RMV_MPLS                     /**< Remove MPLS header (Unlimited MPLS labels) */
++} ioc_fm_pcd_manip_hdr_rmv_specific_l2;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting specific fields updates
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_hdr_field_update_type {
++    e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN,           /**< VLAN updates */
++    e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4,           /**< IPV4 updates */
++    e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6,           /**< IPV6 updates */
++    e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP,        /**< TCP_UDP updates */
++} ioc_fm_pcd_manip_hdr_field_update_type;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting VLAN updates
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_hdr_field_update_vlan {
++    e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_VPRI,      /**< Replace VPri of outer most VLAN tag. */
++    e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN    /**< DSCP to VLAN priority bits translation */
++} ioc_fm_pcd_manip_hdr_field_update_vlan;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting specific L2 fields removal
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_hdr_insrt_specific_l2 {
++    e_IOC_FM_PCD_MANIP_HDR_INSRT_MPLS                   /**< Insert MPLS header (Unlimited MPLS labels) */
++} ioc_fm_pcd_manip_hdr_insrt_specific_l2;
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Description   Enumeration type for selecting QoS mapping mode
++
++                Note: In all cases except 'e_FM_PCD_MANIP_HDR_QOS_MAPPING_NONE'
++                User should instruct the port to read the parser-result
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_hdr_qos_mapping_mode {
++    e_IOC_FM_PCD_MANIP_HDR_QOS_MAPPING_NONE = 0, /**< No mapping, QoS field will not be changed */
++    e_IOC_FM_PCD_MANIP_HDR_QOS_MAPPING_AS_IS, /**< QoS field will be overwritten by the last byte in the parser-result. */
++} ioc_fm_pcd_manip_hdr_qos_mapping_mode;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting QoS source
++
++                Note: In all cases except 'e_FM_PCD_MANIP_HDR_QOS_SRC_NONE'
++                User should left room for the parser-result on input/output buffer
++                and instruct the port to read/write the parser-result to the buffer (RPD should be set)
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_hdr_qos_src {
++    e_IOC_FM_PCD_MANIP_HDR_QOS_SRC_NONE = 0, /**< TODO */
++    e_IOC_FM_PCD_MANIP_HDR_QOS_SRC_USER_DEFINED, /**< QoS will be taken from the last byte in the parser-result. */
++} ioc_fm_pcd_manip_hdr_qos_src;
++#endif /* (DPAA_VERSION >= 11) */
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of header insertion
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_hdr_insrt_by_hdr_type {
++    e_IOC_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2,         /**< Specific L2 fields insertion */
++#if (DPAA_VERSION >= 11)
++    e_IOC_FM_PCD_MANIP_INSRT_BY_HDR_IP,                 /**< IP insertion */
++    e_IOC_FM_PCD_MANIP_INSRT_BY_HDR_UDP,                /**< UDP insertion */
++    e_IOC_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE,             /**< UDP lite insertion */
++    e_IOC_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP                 /**< CAPWAP insertion */
++#endif /* (DPAA_VERSION >= 11) */
++} ioc_fm_pcd_manip_hdr_insrt_by_hdr_type;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting specific custom command
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_hdr_custom_type {
++    e_IOC_FM_PCD_MANIP_HDR_CUSTOM_IP_REPLACE,           /**< Replace IPv4/IPv6 */
++} ioc_fm_pcd_manip_hdr_custom_type;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting specific custom command
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_hdr_custom_ip_replace {
++    e_IOC_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV4_BY_IPV6, /**< Replace IPv4 by IPv6 */
++    e_IOC_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4  /**< Replace IPv6 by IPv4 */
++} ioc_fm_pcd_manip_hdr_custom_ip_replace;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of header removal
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_hdr_rmv_by_hdr_type {
++    e_IOC_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2 = 0,       /**< Specific L2 fields removal */
++#if (DPAA_VERSION >= 11)
++    e_IOC_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP,                  /**< CAPWAP removal */
++#endif /* (DPAA_VERSION >= 11) */
++#if (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++    e_IOC_FM_PCD_MANIP_RMV_BY_HDR_FROM_START,           /**< Locate from data that is not the header */
++#endif /* (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
++} ioc_fm_pcd_manip_hdr_rmv_by_hdr_type;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of timeout mode
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_reassem_time_out_mode {
++    e_IOC_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAMES,         /**< Limits the time of the reassembly process
++                                                             from the first fragment to the last */
++    e_IOC_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAG            /**< Limits the time of receiving the fragment */
++} ioc_fm_pcd_manip_reassem_time_out_mode;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of WaysNumber mode
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_reassem_ways_number {
++    e_IOC_FM_PCD_MANIP_ONE_WAY_HASH = 1,    /**< One way hash    */
++    e_IOC_FM_PCD_MANIP_TWO_WAYS_HASH,       /**< Two ways hash   */
++    e_IOC_FM_PCD_MANIP_THREE_WAYS_HASH,     /**< Three ways hash */
++    e_IOC_FM_PCD_MANIP_FOUR_WAYS_HASH,      /**< Four ways hash  */
++    e_IOC_FM_PCD_MANIP_FIVE_WAYS_HASH,      /**< Five ways hash  */
++    e_IOC_FM_PCD_MANIP_SIX_WAYS_HASH,       /**< Six ways hash   */
++    e_IOC_FM_PCD_MANIP_SEVEN_WAYS_HASH,     /**< Seven ways hash */
++    e_IOC_FM_PCD_MANIP_EIGHT_WAYS_HASH      /**< Eight ways hash */
++} ioc_fm_pcd_manip_reassem_ways_number;
++
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of statistics mode
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_stats {
++    e_IOC_FM_PCD_STATS_PER_FLOWID = 0       /**< Flow ID is used as index for getting statistics */
++} ioc_fm_pcd_stats;
++#endif
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting manipulation type
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_type {
++    e_IOC_FM_PCD_MANIP_HDR = 0,             /**< Header manipulation */
++    e_IOC_FM_PCD_MANIP_REASSEM,             /**< Reassembly */
++    e_IOC_FM_PCD_MANIP_FRAG,                /**< Fragmentation */
++    e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD      /**< Special Offloading */
++} ioc_fm_pcd_manip_type;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of statistics mode
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_cc_stats_mode {
++    e_IOC_FM_PCD_CC_STATS_MODE_NONE = 0,        /**< No statistics support */
++    e_IOC_FM_PCD_CC_STATS_MODE_FRAME,           /**< Frame count statistics */
++    e_IOC_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME,  /**< Byte and frame count statistics */
++#if (DPAA_VERSION >= 11)
++    e_IOC_FM_PCD_CC_STATS_MODE_RMON,            /**< Byte and frame length range count statistics */
++#endif /* (DPAA_VERSION >= 11) */
++} ioc_fm_pcd_cc_stats_mode;
++
++/**************************************************************************//**
++ @Description   Enumeration type for determining the action in case an IP packet
++                is larger than MTU but its DF (Don't Fragment) bit is set.
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_dont_frag_action {
++    e_IOC_FM_PCD_MANIP_DISCARD_PACKET = 0,      /**< Discard packet */
++    e_IOC_FM_PCD_MANIP_ENQ_TO_ERR_Q_OR_DISCARD_PACKET =  e_IOC_FM_PCD_MANIP_DISCARD_PACKET,
++                                                /**< Obsolete, cannot enqueue to error queue;
++                                                     In practice, selects to discard packets;
++                                                     Will be removed in the future */
++    e_IOC_FM_PCD_MANIP_FRAGMENT_PACKECT,        /**< Fragment packet and continue normal processing */
++    e_IOC_FM_PCD_MANIP_CONTINUE_WITHOUT_FRAG    /**< Continue normal processing without fragmenting the packet */
++} ioc_fm_pcd_manip_dont_frag_action;
++
++/**************************************************************************//**
++ @Description   Enumeration type for selecting type of special offload manipulation
++*//***************************************************************************/
++typedef enum ioc_fm_pcd_manip_special_offload_type {
++    e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC,    /**< IPSec offload manipulation */
++#if (DPAA_VERSION >= 11)
++    e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD_CAPWAP    /**< CAPWAP offload manipulation */
++#endif /* (DPAA_VERSION >= 11) */
++} ioc_fm_pcd_manip_special_offload_type;
++
++/**************************************************************************//**
++ @Description   A union of protocol dependent special options
++                (Must match union u_FmPcdHdrProtocolOpt defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef union ioc_fm_pcd_hdr_protocol_opt_u {
++    ioc_eth_protocol_opt_t    eth_opt;     /**< Ethernet options */
++    ioc_vlan_protocol_opt_t   vlan_opt;    /**< Vlan options */
++    ioc_mpls_protocol_opt_t   mpls_opt;    /**< MPLS options */
++    ioc_ipv4_protocol_opt_t   ipv4_opt;    /**< IPv4 options */
++    ioc_ipv6_protocol_opt_t   ipv6_opt;    /**< IPv6 options */
++#if (DPAA_VERSION >= 11)
++    ioc_capwap_protocol_opt_t capwap_opt;  /**< CAPWAP options */
++#endif /* (DPAA_VERSION >= 11) */
++} ioc_fm_pcd_hdr_protocol_opt_u;
++
++/**************************************************************************//**
++ @Description   A union holding all known protocol fields
++*//***************************************************************************/
++typedef union ioc_fm_pcd_fields_u {
++    ioc_header_field_eth_t              eth;            /**< Ethernet               */
++    ioc_header_field_vlan_t             vlan;           /**< VLAN                   */
++    ioc_header_field_llc_snap_t         llc_snap;       /**< LLC SNAP               */
++    ioc_header_field_pppoe_t            pppoe;          /**< PPPoE                  */
++    ioc_header_field_mpls_t             mpls;           /**< MPLS                   */
++    ioc_header_field_ip_t               ip;             /**< IP                     */
++    ioc_header_field_ipv4_t             ipv4;           /**< IPv4                   */
++    ioc_header_field_ipv6_t             ipv6;           /**< IPv6                   */
++    ioc_header_field_udp_t              udp;            /**< UDP                    */
++    ioc_header_field_udp_lite_t         udp_lite;       /**< UDP_Lite               */
++    ioc_header_field_tcp_t              tcp;            /**< TCP                    */
++    ioc_header_field_sctp_t             sctp;           /**< SCTP                   */
++    ioc_header_field_dccp_t             dccp;           /**< DCCP                   */
++    ioc_header_field_gre_t              gre;            /**< GRE                    */
++    ioc_header_field_minencap_t         minencap;       /**< Minimal Encapsulation  */
++    ioc_header_field_ipsec_ah_t         ipsec_ah;       /**< IPSec AH               */
++    ioc_header_field_ipsec_esp_t        ipsec_esp;      /**< IPSec ESP              */
++    ioc_header_field_udp_encap_esp_t    udp_encap_esp;  /**< UDP Encapsulation ESP  */
++} ioc_fm_pcd_fields_u;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header extraction for key generation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_from_hdr_t {
++    uint8_t             size;           /**< Size in byte */
++    uint8_t             offset;         /**< Byte offset */
++} ioc_fm_pcd_from_hdr_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining field extraction for key generation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_from_field_t {
++    ioc_fm_pcd_fields_u field;          /**< Field selection */
++    uint8_t             size;           /**< Size in byte */
++    uint8_t             offset;         /**< Byte offset */
++} ioc_fm_pcd_from_field_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining a single network environment unit
++                A distinction unit should be defined if it will later be used
++                by one or more PCD engines to distinguish between flows.
++                (Must match struct t_FmPcdDistinctionUnit defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_distinction_unit_t {
++    struct {
++        ioc_net_header_type             hdr;                /**< One of the headers supported by the FM */
++        ioc_fm_pcd_hdr_protocol_opt_u   opt;                /**< Select only one option! */
++    } hdrs[IOC_FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS];
++} ioc_fm_pcd_distinction_unit_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining all different distinction units supported
++                by a specific PCD Network Environment Characteristics module.
++
++                Each unit represent a protocol or a group of protocols that may
++                be used later by the different PCD engines to distinguish between flows.
++                (Must match struct t_FmPcdNetEnvParams defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_net_env_params_t {
++    uint8_t                         num_of_distinction_units;/**< Number of different units to be identified */
++    ioc_fm_pcd_distinction_unit_t   units[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS];
++                                                            /**< An array of num_of_distinction_units of the
++                                                                     different units to be identified */
++    void                            *id;                    /**< Output parameter; Returns the net-env Id to be used */
++} ioc_fm_pcd_net_env_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining a single extraction action when
++                creating a key
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_extract_entry_t {
++    ioc_fm_pcd_extract_type                 type;           /**< Extraction type select */
++    union {
++        struct {
++            ioc_net_header_type             hdr;            /**< Header selection */
++            bool                            ignore_protocol_validation;
++                                                            /**< Ignore protocol validation */
++            ioc_fm_pcd_hdr_index            hdr_index;      /**< Relevant only for MPLS, VLAN and tunneled
++                                                                 IP. Otherwise should be cleared.*/
++            ioc_fm_pcd_extract_by_hdr_type  type;           /**< Header extraction type select */
++            union {
++                ioc_fm_pcd_from_hdr_t       from_hdr;       /**< Extract bytes from header parameters */
++                ioc_fm_pcd_from_field_t     from_field;     /**< Extract bytes from field parameters */
++                ioc_fm_pcd_fields_u         full_field;     /**< Extract full field parameters */
++            } extract_by_hdr_type;
++        } extract_by_hdr;                                   /**< Used when type = e_IOC_FM_PCD_KG_EXTRACT_BY_HDR */
++        struct {
++            ioc_fm_pcd_extract_from         src;            /**< Non-header extraction source */
++            ioc_fm_pcd_action               action;         /**< Relevant for CC Only */
++            uint16_t                        ic_indx_mask;   /**< Relevant only for CC when
++                                                                 action = e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP;
++                                                                 Note that the number of bits that are set within
++                                                                 this mask must be log2 of the CC-node 'num_of_keys'.
++                                                                 Note that the mask cannot be set on the lower bits. */
++            uint8_t                         offset;         /**< Byte offset */
++            uint8_t                         size;           /**< Size in bytes */
++        } extract_non_hdr;                                  /**< Used when type = e_IOC_FM_PCD_KG_EXTRACT_NON_HDR */
++    } extract_params;
++} ioc_fm_pcd_extract_entry_t;
++
++/**************************************************************************//**
++ @Description   A structure for defining masks for each extracted
++                field in the key.
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_kg_extract_mask_t {
++    uint8_t                extract_array_index;         /**< Index in the extraction array, as initialized by user */
++    uint8_t                offset;                      /**< Byte offset */
++    uint8_t                mask;                        /**< A byte mask (selected bits will be ignored) */
++} ioc_fm_pcd_kg_extract_mask_t;
++
++/**************************************************************************//**
++ @Description   A structure for defining default selection per groups
++                of fields
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_kg_extract_dflt_t {
++    ioc_fm_pcd_kg_known_fields_dflt_types    type;          /**< Default type select*/
++    ioc_fm_pcd_kg_extract_dflt_select        dflt_select;   /**< Default register select */
++} ioc_fm_pcd_kg_extract_dflt_t;
++
++
++/**************************************************************************//**
++ @Description   A structure for defining all parameters needed for
++                generation a key and using a hash function
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_kg_key_extract_and_hash_params_t {
++    uint32_t                            private_dflt0;          /**< Scheme default register 0 */
++    uint32_t                            private_dflt1;          /**< Scheme default register 1 */
++    uint8_t                             num_of_used_extracts;   /**< defines the valid size of the following array */
++    ioc_fm_pcd_extract_entry_t          extract_array [IOC_FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY];
++                                                                /**< An array of extraction definitions. */
++    uint8_t                             num_of_used_dflts;      /**< defines the valid size of the following array */
++    ioc_fm_pcd_kg_extract_dflt_t        dflts[IOC_FM_PCD_KG_NUM_OF_DEFAULT_GROUPS];
++                                                                /**< For each extraction used in this scheme, specify the required
++                                                                     default register to be used when header is not found.
++                                                                     types not specified in this array will get undefined value. */
++    uint8_t                             num_of_used_masks;      /**< Defines the valid size of the following array */
++    ioc_fm_pcd_kg_extract_mask_t        masks[IOC_FM_PCD_KG_NUM_OF_EXTRACT_MASKS];
++    uint8_t                             hash_shift;             /**< Hash result right shift.
++                                                                     Selects the 24 bits out of the 64 hash result.
++                                                                     0 means using the 24 LSB's, otherwise use the
++                                                                     24 LSB's after shifting right.*/
++    uint32_t                            hash_distribution_num_of_fqids; /**< must be > 1 and a power of 2. Represents the range
++                                                                             of queues for the key and hash functionality */
++    uint8_t                             hash_distribution_fqids_shift;  /**< selects the FQID bits that will be effected by the hash */
++    bool                                symmetric_hash;         /**< TRUE to generate the same hash for frames with swapped source and
++                                                                     destination fields on all layers; If TRUE, driver will check that for
++                                                                     all layers, if SRC extraction is selected, DST extraction must also be
++                                                                     selected, and vice versa. */
++} ioc_fm_pcd_kg_key_extract_and_hash_params_t;
++
++/**************************************************************************//**
++ @Description   A structure of parameters for defining a single
++                Qid mask (extracted OR).
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_kg_extracted_or_params_t {
++    ioc_fm_pcd_extract_type                 type;               /**< Extraction type select */
++    union {
++        struct {                                                 /**< used when type = e_IOC_FM_PCD_KG_EXTRACT_BY_HDR */
++            ioc_net_header_type             hdr;
++            ioc_fm_pcd_hdr_index            hdr_index;          /**< Relevant only for MPLS, VLAN and tunneled
++                                                                     IP. Otherwise should be cleared.*/
++            bool                            ignore_protocol_validation;
++
++        } extract_by_hdr;
++        ioc_fm_pcd_extract_from             src;                /**< used when type = e_IOC_FM_PCD_KG_EXTRACT_NON_HDR */
++    } extract_params;
++    uint8_t                                 extraction_offset;  /**< Offset for extraction */
++    ioc_fm_pcd_kg_extract_dflt_select       dflt_value;         /**< Select register from which extraction is taken if
++                                                                     field not found */
++    uint8_t                                 mask;               /**< Mask LSB byte of extraction (specified bits are ignored) */
++    uint8_t                         bit_offset_in_fqid;    /**< 0-31, Selects which bits of the 24 FQID bits to effect using
++                                                             the extracted byte; Assume byte is placed as the 8 MSB's in
++                                                             a 32 bit word where the lower bits
++                                                             are the FQID; i.e if bitOffsetInFqid=1 than its LSB
++                                                             will effect the FQID MSB, if bitOffsetInFqid=24 than the
++                                                             extracted byte will effect the 8 LSB's of the FQID,
++                                                             if bitOffsetInFqid=31 than the byte's MSB will effect
++                                                             the FQID's LSB; 0 means - no effect on FQID;
++                                                             Note that one, and only one of
++                                                             bitOffsetInFqid or bitOffsetInPlcrProfile must be set (i.e,
++                                                             extracted byte must effect either FQID or Policer profile).*/
++    uint8_t                         bit_offset_in_plcr_profile;
++                                                        /**< 0-15, Selects which bits of the 8 policer profile id bits to
++                                                             effect using the extracted byte; Assume byte is placed
++                                                             as the 8 MSB's in a 16 bit word where the lower bits
++                                                             are the policer profile id; i.e if bitOffsetInPlcrProfile=1
++                                                             than its LSB will effect the profile MSB, if bitOffsetInFqid=8
++                                                             than the extracted byte will effect the whole policer profile id,
++                                                             if bitOffsetInFqid=15 than the byte's MSB will effect
++                                                             the Policer Profile id's LSB;
++                                                             0 means - no effect on policer profile; Note that one, and only one of
++                                                             bitOffsetInFqid or bitOffsetInPlcrProfile must be set (i.e,
++                                                             extracted byte must effect either FQID or Policer profile).*/
++} ioc_fm_pcd_kg_extracted_or_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for configuring scheme counter
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_kg_scheme_counter_t {
++    bool        update;     /**< FALSE to keep the current counter state
++                                 and continue from that point, TRUE to update/reset
++                                 the counter when the scheme is written. */
++    uint32_t    value;      /**< If update=TRUE, this value will be written into the
++                                 counter; clear this field to reset the counter. */
++} ioc_fm_pcd_kg_scheme_counter_t;
++
++
++/**************************************************************************//**
++ @Description   A structure for retrieving FMKG_SE_SPC
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_kg_scheme_spc_t {
++    uint32_t    val;       /**< return value */
++    void        *id;       /**< scheme handle */
++} ioc_fm_pcd_kg_scheme_spc_t;
++
++/**************************************************************************//**
++ @Description   A structure for defining policer profile parameters as required by keygen
++                (when policer is the next engine after this scheme).
++                (Must match struct t_FmPcdKgPlcrProfile defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_kg_plcr_profile_t {
++    bool                shared_profile;                 /**< TRUE if this profile is shared between ports
++                                                             (i.e. managed by master partition) May not be TRUE
++                                                             if profile is after Coarse Classification*/
++    bool                direct;                         /**< If TRUE, direct_relative_profile_id only selects the profile
++                                                             id, if FALSE fqid_offset_relative_profile_id_base is used
++                                                             together with fqid_offset_shift and num_of_profiles
++                                                             parameters, to define a range of profiles from
++                                                             which the KeyGen result will determine the
++                                                             destination policer profile.  */
++    union {
++        uint16_t        direct_relative_profile_id;     /**< Used if 'direct' is TRUE, to select policer profile.
++                                                             This parameter should indicate the policer profile offset within the port's
++                                                             policer profiles or SHARED window. */
++        struct {
++            uint8_t     fqid_offset_shift;              /**< Shift of KG results without the qid base */
++            uint8_t     fqid_offset_relative_profile_id_base;
++                                                        /**< OR of KG results without the qid base
++                                                             This parameter should indicate the policer profile
++                                                             offset within the port's policer profiles window
++                                                             or SHARED window depends on shared_profile */
++            uint8_t     num_of_profiles;                /**< Range of profiles starting at base */
++        } indirect_profile;                             /**< Indirect profile parameters */
++    } profile_select;                                   /**< Direct/indirect profile selection and parameters */
++} ioc_fm_pcd_kg_plcr_profile_t;
++
++#if DPAA_VERSION >= 11
++/**************************************************************************//**
++ @Description   Parameters for configuring a storage profile for a KeyGen scheme.
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_kg_storage_profile_t {
++    bool                direct;                     /**< If TRUE, directRelativeProfileId only selects the
++                                                         profile id;
++                                                         If FALSE, fqidOffsetRelativeProfileIdBase is used
++                                                         together with fqidOffsetShift and numOfProfiles
++                                                         parameters to define a range of profiles from which
++                                                         the KeyGen result will determine the destination
++                                                         storage profile. */
++    union {
++        uint16_t        direct_relative_profileId;    /**< Used when 'direct' is TRUE, to select a storage profile;
++                                                         should indicate the storage profile offset within the
++                                                         port's storage profiles window. */
++        struct {
++            uint8_t     fqid_offset_shift;            /**< Shift of KeyGen results without the FQID base */
++            uint8_t     fqid_offset_relative_profile_id_base;
++                                                    /**< OR of KeyGen results without the FQID base;
++                                                         should indicate the policer profile offset within the
++                                                         port's storage profiles window. */
++            uint8_t     num_of_profiles;              /**< Range of profiles starting at base. */
++        } indirect_profile;                          /**< Indirect profile parameters. */
++    } profile_select;                                /**< Direct/indirect profile selection and parameters. */
++} ioc_fm_pcd_kg_storage_profile_t;
++#endif /* DPAA_VERSION >= 11 */
++
++/**************************************************************************//**
++ @Description   Parameters for defining CC as the next engine after KeyGen
++                (Must match struct t_FmPcdKgCc defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_kg_cc_t {
++    void                            *tree_id;           /**< CC Tree id */
++    uint8_t                         grp_id;             /**< CC group id within the CC tree */
++    bool                            plcr_next;          /**< TRUE if after CC, in case of data frame,
++                                                             policing is required. */
++    bool                            bypass_plcr_profile_generation;
++                                                        /**< TRUE to bypass KeyGen policer profile generation;
++                                                             selected profile is the one set at port initialization. */
++    ioc_fm_pcd_kg_plcr_profile_t    plcr_profile;       /**< Valid only if plcr_next = TRUE and
++                                                             bypass_plcr_profile_generation = FALSE */
++} ioc_fm_pcd_kg_cc_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining initializing a KeyGen scheme
++                (Must match struct t_FmPcdKgSchemeParams defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_kg_scheme_params_t {
++    bool                                modify;         /**< TRUE to change an existing scheme */
++    union {
++        uint8_t                         relative_scheme_id;
++                                                        /**< if modify=FALSE: partition-relative scheme id */
++        void                            *scheme_id;     /**< if modify=TRUE: the id of an existing scheme */
++    } scm_id;
++    bool                                always_direct;  /**< This scheme is reached only directly, i.e. no need
++                                                             for match vector; KeyGen will ignore it when matching */
++    struct {                                            /**< HL relevant only if always_direct=FALSE */
++        void                            *net_env_id;    /**< The id of the Network Environment as returned
++                                                             by FM_PCD_NetEnvCharacteristicsSet() */
++        uint8_t                         num_of_distinction_units;
++                                                        /**< Number of NetEnv units listed in unit_ids array */
++        uint8_t                         unit_ids[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS];
++                                                        /**< Indexes as passed to SetNetEnvCharacteristics (?) array */
++    } net_env_params;
++    bool                                use_hash;       /**< use the KG Hash functionality */
++    ioc_fm_pcd_kg_key_extract_and_hash_params_t key_extract_and_hash_params;
++                                                        /**< used only if useHash = TRUE */
++    bool                                bypass_fqid_generation;
++                                                        /**< Normally - FALSE, TRUE to avoid FQID update in the IC;
++                                                             In such a case FQID after KG will be the default FQID
++                                                             defined for the relevant port, or the FQID defined by CC
++                                                             in cases where CC was the previous engine. */
++    uint32_t                            base_fqid;      /**< Base FQID; Relevant only if bypass_fqid_generation = FALSE;
++                                                             If hash is used and an even distribution is expected
++                                                             according to hash_distribution_num_of_fqids, base_fqid must be aligned to
++                                                             hash_distribution_num_of_fqids. */
++    uint8_t                             num_of_used_extracted_ors;
++                                                        /**< Number of FQID masks listed in extracted_ors array*/
++    ioc_fm_pcd_kg_extracted_or_params_t extracted_ors[IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS];
++                                                        /**< IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS
++                                                             registers are shared between qid_masks
++                                                             functionality and some of the extraction
++                                                             actions; Normally only some will be used
++                                                             for qid_mask. Driver will return error if
++                                                             resource is full at initialization time. */
++#if DPAA_VERSION >= 11
++    bool                                override_storage_profile;
++                                                        /**< TRUE if KeyGen override previously decided storage profile */
++    ioc_fm_pcd_kg_storage_profile_t     storage_profile;/**< Used when override_storage_profile=TRUE */
++#endif /* DPAA_VERSION >= 11 */
++    ioc_fm_pcd_engine                   next_engine;     /**< may be BMI, PLCR or CC */
++    union {                                              /**< depends on nextEngine */
++        ioc_fm_pcd_done_action          done_action;     /**< Used when next engine is BMI (done) */
++        ioc_fm_pcd_kg_plcr_profile_t    plcr_profile;    /**< Used when next engine is PLCR */
++        ioc_fm_pcd_kg_cc_t              cc;              /**< Used when next engine is CC */
++    } kg_next_engine_params;
++    ioc_fm_pcd_kg_scheme_counter_t      scheme_counter;  /**< A structure of parameters for updating
++                                                              the scheme counter */
++    void                                *id;             /**< Returns the scheme Id to be used */
++} ioc_fm_pcd_kg_scheme_params_t;
++
++/**************************************************************************//**
++ @Collection
++*//***************************************************************************/
++#if DPAA_VERSION >= 11
++#define IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR      10  /* Maximal supported number of frame length ranges */
++#define IOC_FM_PCD_CC_STATS_FLR_SIZE            2   /* Size in bytes of a frame length range limit */
++#endif /* DPAA_VERSION >= 11 */
++#define IOC_FM_PCD_CC_STATS_FLR_COUNT_SIZE      4   /* Size in bytes of a frame length range counter */
++/* @} */
++
++/**************************************************************************//**
++ @Description   Parameters for defining CC as the next engine after a CC node.
++                (Must match struct t_FmPcdCcNextCcParams defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_cc_next_cc_params_t {
++    void        *cc_node_id;                             /**< Id of the next CC node */
++} ioc_fm_pcd_cc_next_cc_params_t;
++
++#if DPAA_VERSION >= 11
++/**************************************************************************//**
++ @Description   A structure for defining Frame Replicator as the next engine after a CC node.
++                (Must match struct t_FmPcdCcNextFrParams defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_cc_next_fr_params_t {
++    void*       frm_replic_id;              /**< The id of the next frame replicator group */
++} ioc_fm_pcd_cc_next_fr_params_t;
++#endif /* DPAA_VERSION >= 11 */
++
++/**************************************************************************//**
++ @Description   A structure for defining PLCR params when PLCR is the
++                next engine after a CC node
++                (Must match struct t_FmPcdCcNextPlcrParams defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_cc_next_plcr_params_t {
++    bool        override_params;            /**< TRUE if CC override previously decided parameters*/
++    bool        shared_profile;             /**< Relevant only if overrideParams=TRUE:
++                                                TRUE if this profile is shared between ports */
++    uint16_t    new_relative_profile_id;    /**< Relevant only if overrideParams=TRUE:
++                                                (otherwise profile id is taken from keygen);
++                                                This parameter should indicate the policer
++                                                profile offset within the port's
++                                                policer profiles or from SHARED window.*/
++    uint32_t    new_fqid;                   /**< Relevant only if overrideParams=TRUE:
++                                                FQID for enquing the frame;
++                                                In earlier chips  if policer next engine is KEYGEN,
++                                                this parameter can be 0, because the KEYGEN always decides
++                                                the enqueue FQID.*/
++#if DPAA_VERSION >= 11
++    uint8_t     new_relative_storage_profile_id;
++                                            /**< Indicates the relative storage profile offset within
++                                                 the port's storage profiles window;
++                                                 Relevant only if the port was configured with VSP. */
++#endif /* DPAA_VERSION >= 11 */
++} ioc_fm_pcd_cc_next_plcr_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for defining enqueue params when BMI is the
++                next engine after a CC node
++                (Must match struct t_FmPcdCcNextEnqueueParams defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_cc_next_enqueue_params_t {
++    ioc_fm_pcd_done_action  action;         /**< Action - when next engine is BMI (done) */
++    bool                    override_fqid;  /**< TRUE if CC override previously decided fqid and vspid,
++                                                 relevant if action = e_IOC_FM_PCD_ENQ_FRAME */
++    uint32_t                new_fqid;       /**< Valid if overrideFqid=TRUE, FQID for enqueuing the frame
++                                                 (otherwise FQID is taken from KeyGen),
++                                                 relevant if action = e_IOC_FM_PCD_ENQ_FRAME*/
++#if DPAA_VERSION >= 11
++    uint8_t                 new_relative_storage_profile_id;
++                                            /**< Valid if override_fqid=TRUE, Indicates the relative virtual
++                                                 storage profile offset within the port's storage profiles
++                                                 window; Relevant only if the port was configured with VSP. */
++#endif /* DPAA_VERSION >= 11 */
++
++} ioc_fm_pcd_cc_next_enqueue_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for defining KG params when KG is the next engine after a CC node
++                (Must match struct t_FmPcdCcNextKgParams defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_cc_next_kg_params_t {
++    bool       override_fqid;               /**< TRUE if CC override previously decided fqid and vspid,
++                                                 Note - this parameters are irrelevant for earlier chips */
++    uint32_t   new_fqid;                    /**< Valid if overrideFqid=TRUE, FQID for enqueuing the frame
++                                                 (otherwise FQID is taken from KeyGen),
++                                                 Note - this parameters are irrelevant for earlier chips */
++#if DPAA_VERSION >= 11
++    uint8_t              new_relative_storage_profile_id;
++                                            /**< Valid if override_fqid=TRUE, Indicates the relative virtual
++                                                 storage profile offset within the port's storage profiles
++                                                 window; Relevant only if the port was configured with VSP. */
++#endif /* DPAA_VERSION >= 11 */
++    void       *p_direct_scheme;            /**< Direct scheme id to go to. */
++} ioc_fm_pcd_cc_next_kg_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining the next engine after a CC node.
++                (Must match struct t_FmPcdCcNextEngineParams defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_cc_next_engine_params_t {
++    ioc_fm_pcd_engine                           next_engine;    /**< User has to initialize parameters
++                                                                     according to nextEngine definition */
++    union {
++            ioc_fm_pcd_cc_next_cc_params_t      cc_params;      /**< Parameters in case next engine is CC */
++            ioc_fm_pcd_cc_next_plcr_params_t    plcr_params;    /**< Parameters in case next engine is PLCR */
++            ioc_fm_pcd_cc_next_enqueue_params_t enqueue_params; /**< Parameters in case next engine is BMI */
++            ioc_fm_pcd_cc_next_kg_params_t      kg_params;      /**< Parameters in case next engine is KG */
++#if DPAA_VERSION >= 11
++            ioc_fm_pcd_cc_next_fr_params_t      fr_params;      /**< Parameters in case next engine is FR */
++#endif /* DPAA_VERSION >= 11 */
++    } params;                                                   /**< Union used for all the next-engine parameters options */
++    void                                        *manip_id;      /**< Handle to Manipulation object.
++                                                                     Relevant if next engine is of type result
++                                                                     (e_IOC_FM_PCD_PLCR, e_IOC_FM_PCD_KG, e_IOC_FM_PCD_DONE) */
++    bool                                        statistics_en;  /**< If TRUE, statistics counters are incremented
++                                                                      for each frame passing through this
++                                                                      Coarse Classification entry. */
++} ioc_fm_pcd_cc_next_engine_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining a single CC key
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_cc_key_params_t {
++    uint8_t                 *p_key;         /**< pointer to the key of the size defined in key_size */
++    uint8_t                 *p_mask;        /**< pointer to the Mask per key of the size defined
++                                                 in keySize. p_key and p_mask (if defined) has to be
++                                                 of the same size defined in the key_size */
++    ioc_fm_pcd_cc_next_engine_params_t  cc_next_engine_params;
++                                            /**< parameters for the next for the defined Key in p_key */
++
++} ioc_fm_pcd_cc_key_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining CC keys parameters
++                The driver supports two methods for CC node allocation: dynamic and static.
++                Static mode was created in order to prevent runtime alloc/free
++                of FMan memory (MURAM), which may cause fragmentation; in this mode,
++                the driver automatically allocates the memory according to
++                'max_num_of_keys' parameter. The driver calculates the maximal memory
++                size that may be used for this CC-Node taking into consideration
++                'mask_support' and 'statistics_mode' parameters.
++                When 'action' = e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP in the extraction
++                parameters of this node, 'max_num_of_keys' must be equal to 'num_of_keys'.
++                In dynamic mode, 'max_num_of_keys' must be zero. At initialization,
++                all required structures are allocated according to 'num_of_keys'
++                parameter. During runtime modification, these structures are
++                re-allocated according to the updated number of keys.
++
++                Please note that 'action' and 'ic_indx_mask' mentioned in the
++                specific parameter explanations are passed in the extraction
++                parameters of the node (fields of extractccparams.extractnonhdr).
++*//***************************************************************************/
++typedef struct ioc_keys_params_t {
++    uint16_t                    max_num_of_keys;/**< Maximum number of keys that will (ever) be used in this CC-Node;
++                                                     A value of zero may be used for dynamic memory allocation. */
++    bool                        mask_support;   /**< This parameter is relevant only if a node is initialized with
++                                                     action = e_IOC_FM_PCD_ACTION_EXACT_MATCH and max_num_of_keys > 0;
++                                                     Should be TRUE to reserve table memory for key masks, even if
++                                                     initial keys do not contain masks, or if the node was initialized
++                                                     as 'empty' (without keys); this will allow user to add keys with
++                                                     masks at runtime. */
++    ioc_fm_pcd_cc_stats_mode    statistics_mode;/**< Determines the supported statistics mode for all node's keys.
++                                                     To enable statistics gathering, statistics should be enabled per
++                                                     every key, using 'statistics_en' in next engine parameters structure
++                                                     of that key;
++                                                     If 'max_num_of_keys' is set, all required structures will be
++                                                     preallocated for all keys. */
++#if (DPAA_VERSION >= 11)
++    uint16_t                    frame_length_ranges[IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR];
++                                                /**< Relevant only for 'RMON' statistics mode
++                                                     (this feature is supported only on B4860 device);
++                                                     Holds a list of programmable thresholds. For each received frame,
++                                                     its length in bytes is examined against these range thresholds and
++                                                     the appropriate counter is incremented by 1. For example, to belong
++                                                     to range i, the following should hold:
++                                                     range i-1 threshold < frame length <= range i threshold
++                                                     Each range threshold must be larger then its preceding range
++                                                     threshold. Last range threshold must be 0xFFFF. */
++#endif /* (DPAA_VERSION >= 11) */
++    uint16_t                    num_of_keys;    /**< Number of initial keys;
++                                                     Note that in case of 'action' = e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP,
++                                                     this field should be power-of-2 of the number of bits that are
++                                                     set in 'ic_indx_mask'. */
++    uint8_t                     key_size;       /**< Size of key - for extraction of type FULL_FIELD, 'key_size' has
++                                                     to be the standard size of the selected key; For other extraction
++                                                     types, 'key_size' has to be as size of extraction; When 'action' =
++                                                     e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP, 'keySize' must be 2. */
++    ioc_fm_pcd_cc_key_params_t  key_params[IOC_FM_PCD_MAX_NUM_OF_KEYS];
++                                                /**< An array with 'num_of_keys' entries, each entry specifies the
++                                                     corresponding key parameters;
++                                                     When 'action' = e_IOC_FM_PCD_ACTION_EXACT_MATCH, this value must not
++                                                     exceed 255 (IOC_FM_PCD_MAX_NUM_OF_KEYS-1) as the last entry is saved
++                                                     for the 'miss' entry. */
++    ioc_fm_pcd_cc_next_engine_params_t  cc_next_engine_params_for_miss;
++                                                /**< Parameters for defining the next engine when a key is not matched;
++                                                     Not relevant if action = e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP. */
++} ioc_keys_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining a CC node
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_cc_node_params_t {
++    ioc_fm_pcd_extract_entry_t          extract_cc_params;  /**< Extraction parameters */
++    ioc_keys_params_t                   keys_params;        /**< Keys definition matching the selected extraction */
++    void                                *id;                /**< Output parameter; returns the CC node Id to be used */
++} ioc_fm_pcd_cc_node_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining a hash table
++                (Must match struct t_FmPcdHashTableParams defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_hash_table_params_t {
++    uint16_t                    max_num_of_keys;            /**< Maximum Number Of Keys that will (ever) be used in this Hash-table */
++    ioc_fm_pcd_cc_stats_mode    statistics_mode;            /**< If not e_IOC_FM_PCD_CC_STATS_MODE_NONE, the required structures for the
++                                                                 requested statistics mode will be allocated according to max_num_of_keys. */
++    uint8_t                     kg_hash_shift;              /**< KG-Hash-shift as it was configured in the KG-scheme
++                                                                 that leads to this hash-table. */
++    uint16_t                    hash_res_mask;              /**< Mask that will be used on the hash-result;
++                                                                 The number-of-sets for this hash will be calculated
++                                                                 as (2^(number of bits set in 'hash_res_mask'));
++                                                                 The 4 lower bits must be cleared. */
++    uint8_t                     hash_shift;                 /**< Byte offset from the beginning of the KeyGen hash result to the
++                                                                 2-bytes to be used as hash index. */
++    uint8_t                     match_key_size;             /**< Size of the exact match keys held by the hash buckets */
++
++    ioc_fm_pcd_cc_next_engine_params_t   cc_next_engine_params_for_miss;
++                                                            /**< Parameters for defining the next engine when a key is not matched */
++    void                        *id;
++} ioc_fm_pcd_hash_table_params_t;
++
++/**************************************************************************//**
++ @Description   A structure with the arguments for the FM_PCD_HashTableAddKey ioctl() call
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_hash_table_add_key_params_t {
++    void                        *p_hash_tbl;
++    uint8_t                     key_size;
++    ioc_fm_pcd_cc_key_params_t  key_params;
++} ioc_fm_pcd_hash_table_add_key_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining a CC tree group.
++
++                This structure defines a CC group in terms of NetEnv units
++                and the action to be taken in each case. The unit_ids list must
++                be given in order from low to high indices.
++
++                ioc_fm_pcd_cc_next_engine_params_t is a list of 2^num_of_distinction_units
++                structures where each defines the next action to be taken for
++                each units combination. for example:
++                num_of_distinction_units = 2
++                unit_ids = {1,3}
++                next_engine_per_entries_in_grp[0] = ioc_fm_pcd_cc_next_engine_params_t for the case that
++                                                    unit 1 - not found; unit 3 - not found;
++                next_engine_per_entries_in_grp[1] = ioc_fm_pcd_cc_next_engine_params_t for the case that
++                                                    unit 1 - not found; unit 3 - found;
++                next_engine_per_entries_in_grp[2] = ioc_fm_pcd_cc_next_engine_params_t for the case that
++                                                    unit 1 - found; unit 3 - not found;
++                next_engine_per_entries_in_grp[3] = ioc_fm_pcd_cc_next_engine_params_t for the case that
++                                                    unit 1 - found; unit 3 - found;
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_cc_grp_params_t {
++    uint8_t                             num_of_distinction_units;   /**< Up to 4 */
++    uint8_t                             unit_ids [IOC_FM_PCD_MAX_NUM_OF_CC_UNITS];
++                                                                    /**< Indexes of the units as defined in
++                                                                         FM_PCD_NetEnvCharacteristicsSet() */
++    ioc_fm_pcd_cc_next_engine_params_t  next_engine_per_entries_in_grp[IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP];
++                                                                    /**< Maximum entries per group is 16 */
++} ioc_fm_pcd_cc_grp_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining the CC tree groups
++                (Must match struct t_FmPcdCcTreeParams defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_cc_tree_params_t {
++        void                            *net_env_id;    /**< Id of the Network Environment as returned
++                                                             by FM_PCD_NetEnvCharacteristicsSet() */
++        uint8_t                         num_of_groups;  /**< Number of CC groups within the CC tree */
++        ioc_fm_pcd_cc_grp_params_t      fm_pcd_cc_group_params [IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS];
++                                                        /**< Parameters for each group. */
++        void                            *id;            /**< Output parameter; Returns the tree Id to be used */
++} ioc_fm_pcd_cc_tree_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining policer byte rate
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_plcr_byte_rate_mode_param_t {
++    ioc_fm_pcd_plcr_frame_length_select     frame_length_selection;     /**< Frame length selection */
++    ioc_fm_pcd_plcr_roll_back_frame_select  roll_back_frame_selection;  /**< relevant option only e_IOC_FM_PCD_PLCR_L2_FRM_LEN,
++                                                                             e_IOC_FM_PCD_PLCR_FULL_FRM_LEN */
++} ioc_fm_pcd_plcr_byte_rate_mode_param_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining the policer profile (based on
++                RFC-2698 or RFC-4115 attributes).
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_plcr_non_passthrough_alg_param_t {
++    ioc_fm_pcd_plcr_rate_mode               rate_mode;                      /**< Byte / Packet */
++    ioc_fm_pcd_plcr_byte_rate_mode_param_t  byte_mode_param;                /**< Valid for Byte NULL for Packet */
++    uint32_t                                committed_info_rate;            /**< KBits/Sec or Packets/Sec */
++    uint32_t                                committed_burst_size;           /**< KBits or Packets */
++    uint32_t                                peak_or_excess_info_rate;       /**< KBits/Sec or Packets/Sec */
++    uint32_t                                peak_or_excess_burst_size;      /**< KBits or Packets */
++} ioc_fm_pcd_plcr_non_passthrough_alg_param_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining the next engine after policer
++*//***************************************************************************/
++typedef union ioc_fm_pcd_plcr_next_engine_params_u {
++        ioc_fm_pcd_done_action     action;              /**< Action - when next engine is BMI (done) */
++        void                       *p_profile;          /**< Policer profile handle -  used when next engine
++                                                             is PLCR, must be a SHARED profile */
++        void                       *p_direct_scheme;    /**< Direct scheme select - when next engine is Keygen */
++} ioc_fm_pcd_plcr_next_engine_params_u;
++
++typedef struct ioc_fm_pcd_port_params_t {
++    ioc_fm_port_type                    port_type;          /**< Type of port for this profile */
++    uint8_t                             port_id;            /**< FM-Port id of port for this profile */
++} ioc_fm_pcd_port_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining the policer profile entry
++                (Must match struct t_FmPcdPlcrProfileParams defined in fm_pcd_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_plcr_profile_params_t {
++    bool                                        modify;                     /**< TRUE to change an existing profile */
++    union {
++        struct {
++            ioc_fm_pcd_profile_type_selection   profile_type;               /**< Type of policer profile */
++            ioc_fm_pcd_port_params_t            *p_fm_port;                 /**< Relevant for per-port profiles only */
++            uint16_t                            relative_profile_id;        /**< Profile id - relative to shared group or to port */
++        } new_params;                                                       /**< Use it when modify = FALSE */
++        void                                    *p_profile;                 /**< A handle to a profile - use it when modify=TRUE */
++    } profile_select;
++    ioc_fm_pcd_plcr_algorithm_selection         alg_selection;              /**< Profile Algorithm PASS_THROUGH, RFC_2698, RFC_4115 */
++    ioc_fm_pcd_plcr_color_mode                  color_mode;                 /**< COLOR_BLIND, COLOR_AWARE */
++
++    union {
++        ioc_fm_pcd_plcr_color                   dflt_color;                 /**< For Color-Blind Pass-Through mode; the policer will re-color
++                                                                                 any incoming packet with the default value. */
++        ioc_fm_pcd_plcr_color                   override;                   /**< For Color-Aware modes; the profile response to a
++                                                                                 pre-color value of 2'b11. */
++    } color;
++
++    ioc_fm_pcd_plcr_non_passthrough_alg_param_t non_passthrough_alg_param;  /**< RFC2698 or RFC4115 parameters */
++
++    ioc_fm_pcd_engine                           next_engine_on_green;       /**< Next engine for green-colored frames */
++    ioc_fm_pcd_plcr_next_engine_params_u        params_on_green;            /**< Next engine parameters for green-colored frames  */
++
++    ioc_fm_pcd_engine                           next_engine_on_yellow;      /**< Next engine for yellow-colored frames */
++    ioc_fm_pcd_plcr_next_engine_params_u        params_on_yellow;           /**< Next engine parameters for yellow-colored frames  */
++
++    ioc_fm_pcd_engine                           next_engine_on_red;         /**< Next engine for red-colored frames */
++    ioc_fm_pcd_plcr_next_engine_params_u        params_on_red;              /**< Next engine parameters for red-colored frames  */
++
++    bool                                        trap_profile_on_flow_A;     /**< Obsolete - do not use */
++    bool                                        trap_profile_on_flow_B;     /**< Obsolete - do not use */
++    bool                                        trap_profile_on_flow_C;     /**< Obsolete - do not use */
++
++    void                                        *id;                        /**< output parameter; Returns the profile Id to be used */
++} ioc_fm_pcd_plcr_profile_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for modifying CC tree next engine
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_cc_tree_modify_next_engine_params_t {
++    void                                *id;                /**< CC tree Id to be used */
++    uint8_t                             grp_indx;           /**< A Group index in the tree */
++    uint8_t                             indx;               /**< Entry index in the group defined by grp_index */
++    ioc_fm_pcd_cc_next_engine_params_t  cc_next_engine_params;
++                                                            /**< Parameters for the next for the defined Key in the p_Key */
++} ioc_fm_pcd_cc_tree_modify_next_engine_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for modifying CC node next engine
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_cc_node_modify_next_engine_params_t {
++    void                                *id;                /**< CC node Id to be used */
++    uint16_t                            key_indx;           /**< Key index for Next Engine Params modifications;
++                                                                 NOTE: This parameter is IGNORED for miss-key!  */
++    uint8_t                             key_size;           /**< Key size of added key */
++    ioc_fm_pcd_cc_next_engine_params_t  cc_next_engine_params;
++                                                            /**< parameters for the next for the defined Key in the p_Key */
++} ioc_fm_pcd_cc_node_modify_next_engine_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for remove CC node key
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_cc_node_remove_key_params_t {
++    void                                *id;                /**< CC node Id to be used */
++    uint16_t                            key_indx;           /**< Key index for Next Engine Params modifications;
++                                                                 NOTE: This parameter is IGNORED for miss-key!  */
++} ioc_fm_pcd_cc_node_remove_key_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for modifying CC node key and next engine
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t {
++    void                                *id;                /**< CC node Id to be used */
++    uint16_t                            key_indx;           /**< Key index for Next Engine Params modifications;
++                                                                 NOTE: This parameter is IGNORED for miss-key!  */
++    uint8_t                             key_size;           /**< Key size of added key */
++    ioc_fm_pcd_cc_key_params_t          key_params;         /**< it's array with numOfKeys entries each entry in
++                                                                 the array of the type ioc_fm_pcd_cc_key_params_t */
++} ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for modifying CC node key
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_cc_node_modify_key_params_t {
++    void                                *id;                /**< CC node Id to be used */
++    uint16_t                            key_indx;           /**< Key index for Next Engine Params modifications;
++                                                                 NOTE: This parameter is IGNORED for miss-key!  */
++    uint8_t                             key_size;           /**< Key size of added key */
++    uint8_t                             *p_key;             /**< Pointer to the key of the size defined in key_size */
++    uint8_t                             *p_mask;            /**< Pointer to the Mask per key of the size defined
++                                                                 in keySize. p_Key and p_Mask (if defined) have to be
++                                                                 of the same size as defined in the key_size */
++} ioc_fm_pcd_cc_node_modify_key_params_t;
++
++/**************************************************************************//**
++ @Description   A structure with the arguments for the FM_PCD_HashTableRemoveKey ioctl() call
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_hash_table_remove_key_params_t {
++    void       *p_hash_tbl;     /**< The id of the hash table */
++    uint8_t     key_size;       /**< The size of the key to remove */
++    uint8_t    *p_key;          /**< Pointer to the key to remove */
++} ioc_fm_pcd_hash_table_remove_key_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for selecting a location for requested manipulation
++*//***************************************************************************/
++typedef struct ioc_fm_manip_hdr_info_t {
++    ioc_net_header_type                 hdr;            /**< Header selection */
++    ioc_fm_pcd_hdr_index                hdr_index;      /**< Relevant only for MPLS, VLAN and tunneled IP. Otherwise should be cleared. */
++    bool                                by_field;       /**< TRUE if the location of manipulation is according to some field in the specific header*/
++    ioc_fm_pcd_fields_u                 full_field;     /**< Relevant only when by_field = TRUE: Extract field */
++} ioc_fm_manip_hdr_info_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header removal by header type
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_rmv_by_hdr_params_t {
++    ioc_fm_pcd_manip_hdr_rmv_by_hdr_type        type;  /**< Selection of header removal location */
++    union {
++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
++        struct {
++            bool                                include;/**< If FALSE, remove until the specified header (not including the header);
++                                                             If TRUE, remove also the specified header. */
++            ioc_fm_manip_hdr_info_t             hdr_info;
++        } from_start_by_hdr;                           /**< Relevant when type = e_IOC_FM_PCD_MANIP_RMV_BY_HDR_FROM_START */
++#endif /* FM_CAPWAP_SUPPORT */
++#if (DPAA_VERSION >= 11)
++        ioc_fm_manip_hdr_info_t                hdr_info;        /**< Relevant when type = e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START */
++#endif /* (DPAA_VERSION >= 11) */
++        ioc_fm_pcd_manip_hdr_rmv_specific_l2    specific_l2;/**< Relevant when type = e_IOC_FM_PCD_MANIP_BY_HDR_SPECIFIC_L2;
++                                                                 Defines which L2 headers to remove. */
++    } u;
++} ioc_fm_pcd_manip_hdr_rmv_by_hdr_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for configuring IP fragmentation manipulation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_frag_ip_params_t {
++    uint16_t                    size_for_fragmentation;     /**< If length of the frame is greater than this value,
++                                                                 IP fragmentation will be executed.*/
++#if DPAA_VERSION == 10
++    uint8_t                     scratch_bpid;               /**< Absolute buffer pool id according to BM configuration.*/
++#endif /* DPAA_VERSION == 10 */
++    bool                        sg_bpid_en;                 /**< Enable a dedicated buffer pool id for the Scatter/Gather buffer allocation;
++                                                                 If disabled, the Scatter/Gather buffer will be allocated from the same pool as the
++                                                                 received frame's buffer. */
++    uint8_t                     sg_bpid;                    /**< Scatter/Gather buffer pool id;
++                                                                 This parameter is relevant when 'sg_bpid_en=TRUE';
++                                                                 Same LIODN number is used for these buffers as for the received frames buffers, so buffers
++                                                                 of this pool need to be allocated in the same memory area as the received buffers.
++                                                                 If the received buffers arrive from different sources, the Scatter/Gather BP id should be
++                                                                 mutual to all these sources. */
++    ioc_fm_pcd_manip_dont_frag_action  dont_frag_action;    /**< Dont Fragment Action - If an IP packet is larger
++                                                                 than MTU and its DF bit is set, then this field will
++                                                                 determine the action to be taken.*/
++} ioc_fm_pcd_manip_frag_ip_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for configuring IP reassembly manipulation.
++
++                This is a common structure for both IPv4 and IPv6 reassembly
++                manipulation. For reassembly of both IPv4 and IPv6, make sure to
++                set the 'hdr' field in ioc_fm_pcd_manip_reassem_params_t to IOC_HEADER_TYPE_IPv6.
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_reassem_ip_params_t {
++    uint8_t                         relative_scheme_id[2];    /**< Partition relative scheme id:
++                                                                 relativeSchemeId[0] -  Relative scheme ID for IPV4 Reassembly manipulation;
++                                                                 relativeSchemeId[1] -  Relative scheme ID for IPV6 Reassembly manipulation;
++                                                                 NOTE: The following comment is relevant only for FMAN v2 devices:
++                                                                 Relative scheme ID for IPv4/IPv6 Reassembly manipulation must be smaller than
++                                                                 the user schemes id to ensure that the reassembly's schemes will be first match.
++                                                                 The remaining schemes, if defined, should have higher relative scheme ID. */
++#if DPAA_VERSION >= 11
++    uint32_t                        non_consistent_sp_fqid; /**< In case that other fragments of the frame corresponds to different storage
++                                                                 profile than the opening fragment (Non-Consistent-SP state)
++                                                                 then one of two possible scenarios occurs:
++                                                                 if 'nonConsistentSpFqid != 0', the reassembled frame will be enqueued to
++                                                                 this fqid, otherwise a 'Non Consistent SP' bit will be set in the FD[status].*/
++#else
++    uint8_t                         sg_bpid;                /**< Buffer pool id for the S/G frame created by the reassembly process */
++#endif /* DPAA_VERSION >= 11 */
++    uint8_t                         data_mem_id;            /**< Memory partition ID for the IPR's external tables structure */
++    uint16_t                        data_liodn_offset;      /**< LIODN offset for access the IPR's external tables structure. */
++    uint16_t                        min_frag_size[2];       /**< Minimum fragment size:
++                                                                 minFragSize[0] - for ipv4, minFragSize[1] - for ipv6 */
++    ioc_fm_pcd_manip_reassem_ways_number   num_of_frames_per_hash_entry[2];
++                                                            /**< Number of frames per hash entry needed for reassembly process:
++                                                                 numOfFramesPerHashEntry[0] - for ipv4 (max value is e_IOC_FM_PCD_MANIP_EIGHT_WAYS_HASH);
++                                                                 numOfFramesPerHashEntry[1] - for ipv6 (max value is e_IOC_FM_PCD_MANIP_SIX_WAYS_HASH). */
++    uint16_t                        max_num_frames_in_process;/**< Number of frames which can be processed by Reassembly in the same time;
++                                                                 Must be power of 2;
++                                                                 In the case numOfFramesPerHashEntry == e_IOC_FM_PCD_MANIP_FOUR_WAYS_HASH,
++                                                                 maxNumFramesInProcess has to be in the range of 4 - 512;
++                                                                 In the case numOfFramesPerHashEntry == e_IOC_FM_PCD_MANIP_EIGHT_WAYS_HASH,
++                                                                 maxNumFramesInProcess has to be in the range of 8 - 2048. */
++    ioc_fm_pcd_manip_reassem_time_out_mode  time_out_mode;  /**< Expiration delay initialized by Reassembly process */
++    uint32_t                        fqid_for_time_out_frames;/**< FQID in which time out frames will enqueue during Time Out Process  */
++    uint32_t                        timeout_threshold_for_reassm_process;
++                                                            /**< Represents the time interval in microseconds which defines
++                                                                 if opened frame (at least one fragment was processed but not all the fragments)is found as too old*/
++} ioc_fm_pcd_manip_reassem_ip_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining IPSEC manipulation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_special_offload_ipsec_params_t {
++    bool    decryption;                     /**< TRUE if being used in decryption direction;
++                                                 FALSE if being used in encryption direction. */
++    bool    ecn_copy;                       /**< TRUE to copy the ECN bits from inner/outer to outer/inner
++                                                 (direction depends on the 'decryption' field). */
++    bool    dscp_copy;                      /**< TRUE to copy the DSCP bits from inner/outer to outer/inner
++                                                 (direction depends on the 'decryption' field). */
++    bool    variable_ip_hdr_len;            /**< TRUE for supporting variable IP header length in decryption. */
++    bool    variable_ip_version;            /**< TRUE for supporting both IP version on the same SA in encryption */
++    uint8_t outer_ip_hdr_len;               /**< If 'variable_ip_version == TRUE' than this field must be set to non-zero value;
++                                                 It is specifies the length of the outer IP header that was configured in the
++                                                 corresponding SA. */
++    uint16_t    arw_size;                   /**< if <> '0' then will perform ARW check for this SA;
++                                                 The value must be a multiplication of 16 */
++    void    *arw_addr;                      /**< if arwSize <> '0' then this field must be set to non-zero value;
++                                                 MUST be allocated from FMAN's MURAM that the post-sec op-port belong
++                                                 Must be 4B aligned. Required MURAM size is '(NEXT_POWER_OF_2(arwSize+32))/8+4' Bytes */
++} ioc_fm_pcd_manip_special_offload_ipsec_params_t;
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Description   Parameters for configuring CAPWAP fragmentation manipulation
++
++ Restrictions:
++     - Maximum number of fragments per frame is 16.
++     - Transmit confirmation is not supported.
++     - Fragmentation nodes must be set as the last PCD action (i.e. the
++       corresponding CC node key must have next engine set to e_FM_PCD_DONE).
++     - Only BMan buffers shall be used for frames to be fragmented.
++     - NOTE: The following comment is relevant only for FMAN v3 devices: IPF
++       does not support VSP. Therefore, on the same port where we have IPF we
++       cannot support VSP.
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_frag_capwap_params_t {
++    uint16_t                    size_for_fragmentation;   /**< If length of the frame is greater than this value,
++                                                             CAPWAP fragmentation will be executed.*/
++    bool                        sg_bpid_en;               /**< Enable a dedicated buffer pool id for the Scatter/Gather buffer allocation;
++                                                             If disabled, the Scatter/Gather buffer will be allocated from the same pool as the
++                                                             received frame's buffer. */
++    uint8_t                     sg_bpid;                 /**< Scatter/Gather buffer pool id;
++                                                             This parameters is relevant when 'sgBpidEn=TRUE';
++                                                             Same LIODN number is used for these buffers as for the received frames buffers, so buffers
++                                                             of this pool need to be allocated in the same memory area as the received buffers.
++                                                             If the received buffers arrive from different sources, the Scatter/Gather BP id should be
++                                                             mutual to all these sources. */
++    bool                        compress_mode_en;         /**< CAPWAP Header Options Compress Enable mode;
++                                                             When this mode is enabled then only the first fragment include the CAPWAP header options
++                                                             field (if user provides it in the input frame) and all other fragments exclude the CAPWAP
++                                                             options field (CAPWAP header is updated accordingly).*/
++} ioc_fm_pcd_manip_frag_capwap_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for configuring CAPWAP reassembly manipulation.
++
++ Restrictions:
++    - Application must define one scheme to catch the reassembled frames.
++    - Maximum number of fragments per frame is 16.
++
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_reassem_capwap_params_t {
++    uint8_t                         relative_scheme_id;    /**< Partition relative scheme id;
++                                                                 NOTE: this id must be smaller than the user schemes id to ensure that the reassembly scheme will be first match;
++                                                                 Rest schemes, if defined, should have higher relative scheme ID. */
++    uint8_t                         data_mem_id;              /**< Memory partition ID for the IPR's external tables structure */
++    uint16_t                        data_liodn_offset;        /**< LIODN offset for access the IPR's external tables structure. */
++    uint16_t                        max_reassembled_frame_length;/**< The maximum CAPWAP reassembled frame length in bytes;
++                                                                   If maxReassembledFrameLength == 0, any successful reassembled frame length is
++                                                                   considered as a valid length;
++                                                                   if maxReassembledFrameLength > 0, a successful reassembled frame which its length
++                                                                   exceeds this value is considered as an error frame (FD status[CRE] bit is set). */
++    ioc_fm_pcd_manip_reassem_ways_number   num_of_frames_per_hash_entry;
++                                                            /**< Number of frames per hash entry needed for reassembly process */
++    uint16_t                        max_num_frames_in_process;  /**< Number of frames which can be processed by reassembly in the same time;
++                                                                 Must be power of 2;
++                                                                 In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH,
++                                                                 maxNumFramesInProcess has to be in the range of 4 - 512;
++                                                                 In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH,
++                                                                 maxNumFramesInProcess has to be in the range of 8 - 2048. */
++    ioc_fm_pcd_manip_reassem_time_out_mode  time_out_mode;            /**< Expiration delay initialized by Reassembly process */
++    uint32_t                        fqid_for_time_out_frames;   /**< FQID in which time out frames will enqueue during Time Out Process;
++                                                                 Recommended value for this field is 0; in this way timed-out frames will be discarded */
++    uint32_t                        timeout_threshold_for_reassm_process;
++                                                            /**< Represents the time interval in microseconds which defines
++                                                                 if opened frame (at least one fragment was processed but not all the fragments)is found as too old*/
++} ioc_fm_pcd_manip_reassem_capwap_params_t;
++
++/**************************************************************************//**
++ @Description   structure for defining CAPWAP manipulation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_special_offload_capwap_params_t {
++    bool                    dtls;   /**< TRUE if continue to SEC DTLS encryption */
++    ioc_fm_pcd_manip_hdr_qos_src   qos_src; /**< TODO */
++} ioc_fm_pcd_manip_special_offload_capwap_params_t;
++
++#endif /* (DPAA_VERSION >= 11) */
++
++/**************************************************************************//**
++ @Description   Parameters for defining special offload manipulation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_special_offload_params_t {
++    ioc_fm_pcd_manip_special_offload_type               type;       /**< Type of special offload manipulation */
++    union
++    {
++        ioc_fm_pcd_manip_special_offload_ipsec_params_t ipsec;      /**< Parameters for IPSec; Relevant when
++                                                                         type = e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC */
++
++#if (DPAA_VERSION >= 11)
++        ioc_fm_pcd_manip_special_offload_capwap_params_t  capwap;     /**< Parameters for CAPWAP; Relevant when
++                                                                type = e_FM_PCD_MANIP_SPECIAL_OFFLOAD_CAPWAP */
++#endif /* (DPAA_VERSION >= 11) */
++    } u;
++} ioc_fm_pcd_manip_special_offload_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining generic removal manipulation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_rmv_generic_params_t {
++    uint8_t                         offset;         /**< Offset from beginning of header to the start
++                                                         location of the removal */
++    uint8_t                         size;           /**< Size of removed section */
++} ioc_fm_pcd_manip_hdr_rmv_generic_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining insertion manipulation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_insrt_t {
++    uint8_t size;           /**< size of inserted section */
++    uint8_t *p_data;        /**< data to be inserted */
++} ioc_fm_pcd_manip_hdr_insrt_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining generic insertion manipulation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_insrt_generic_params_t {
++    uint8_t                         offset;         /**< Offset from beginning of header to the start
++                                                         location of the insertion */
++    uint8_t                         size;           /**< Size of inserted section */
++    bool                            replace;        /**< TRUE to override (replace) existing data at
++                                                         'offset', FALSE to insert */
++    uint8_t                         *p_data;        /**< Pointer to data to be inserted */
++} ioc_fm_pcd_manip_hdr_insrt_generic_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header manipulation VLAN DSCP To Vpri translation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_field_update_vlan_dscp_to_vpri_t {
++    uint8_t                         dscp_to_vpri_table[IOC_FM_PCD_MANIP_DSCP_TO_VLAN_TRANS];
++                                                    /**< A table of VPri values for each DSCP value;
++                                                         The index is the D_SCP value (0-0x3F) and the
++                                                         value is the corresponding VPRI (0-15). */
++    uint8_t                         vpri_def_val;   /**< 0-7, Relevant only if if update_type =
++                                                         e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN,
++                                                         this field is the Q Tag default value if the
++                                                         IP header is not found. */
++} ioc_fm_pcd_manip_hdr_field_update_vlan_dscp_to_vpri_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header manipulation VLAN fields updates
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_field_update_vlan_t {
++    ioc_fm_pcd_manip_hdr_field_update_vlan  update_type;    /**< Selects VLAN update type */
++    union {
++        uint8_t                                     vpri;   /**< 0-7, Relevant only if If update_type =
++                                                                 e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_PRI, this
++                                                                 is the new VLAN pri. */
++        ioc_fm_pcd_manip_hdr_field_update_vlan_dscp_to_vpri_t    dscp_to_vpri;
++                                                            /**<  Parameters structure, Relevant only if update_type =
++                                                                  e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN. */
++    } u;
++} ioc_fm_pcd_manip_hdr_field_update_vlan_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header manipulation IPV4 fields updates
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_field_update_ipv4_t {
++    ioc_ipv4_hdr_manip_update_flags_t       valid_updates;  /**< ORed flag, selecting the required updates */
++    uint8_t                                 tos;            /**< 8 bit New TOS; Relevant if valid_updates contains
++                                                                 IOC_HDR_MANIP_IPV4_TOS */
++    uint16_t                                id;             /**< 16 bit New IP ID; Relevant only if valid_updates
++                                                                 contains IOC_HDR_MANIP_IPV4_ID */
++    uint32_t                                src;            /**< 32 bit New IP SRC; Relevant only if valid_updates
++                                                                 contains IOC_HDR_MANIP_IPV4_SRC */
++    uint32_t                                dst;            /**< 32 bit New IP DST; Relevant only if valid_updates
++                                                                 contains IOC_HDR_MANIP_IPV4_DST */
++} ioc_fm_pcd_manip_hdr_field_update_ipv4_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header manipulation IPV6 fields updates
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_field_update_ipv6_t {
++    ioc_ipv6_hdr_manip_update_flags_t       valid_updates;  /**< ORed flag, selecting the required updates */
++    uint8_t                                 traffic_class;  /**< 8 bit New Traffic Class; Relevant if valid_updates contains
++                                                                 IOC_HDR_MANIP_IPV6_TC */
++    uint8_t                                 src[IOC_NET_HEADER_FIELD_IPv6_ADDR_SIZE];
++                                                            /**< 16 byte new IP SRC; Relevant only if valid_updates
++                                                                 contains IOC_HDR_MANIP_IPV6_SRC */
++    uint8_t                                 dst[IOC_NET_HEADER_FIELD_IPv6_ADDR_SIZE];
++                                                            /**< 16 byte new IP DST; Relevant only if valid_updates
++                                                                 contains IOC_HDR_MANIP_IPV6_DST */
++} ioc_fm_pcd_manip_hdr_field_update_ipv6_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header manipulation TCP/UDP fields updates
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_field_update_tcp_udp_t {
++    ioc_tcp_udp_hdr_manip_update_flags_t    valid_updates;  /**< ORed flag, selecting the required updates */
++    uint16_t                                src;            /**< 16 bit New TCP/UDP SRC; Relevant only if valid_updates
++                                                                 contains IOC_HDR_MANIP_TCP_UDP_SRC */
++    uint16_t                                dst;            /**< 16 bit New TCP/UDP DST; Relevant only if valid_updates
++                                                                 contains IOC_HDR_MANIP_TCP_UDP_DST */
++} ioc_fm_pcd_manip_hdr_field_update_tcp_udp_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header manipulation fields updates
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_field_update_params_t {
++    ioc_fm_pcd_manip_hdr_field_update_type          type;   /**< Type of header field update manipulation */
++    union {
++        ioc_fm_pcd_manip_hdr_field_update_vlan_t    vlan;   /**< Parameters for VLAN update. Relevant when
++                                                                 type = e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN */
++        ioc_fm_pcd_manip_hdr_field_update_ipv4_t    ipv4;   /**< Parameters for IPv4 update. Relevant when
++                                                                 type = e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4 */
++        ioc_fm_pcd_manip_hdr_field_update_ipv6_t    ipv6;   /**< Parameters for IPv6 update. Relevant when
++                                                                 type = e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6 */
++        ioc_fm_pcd_manip_hdr_field_update_tcp_udp_t tcp_udp;/**< Parameters for TCP/UDP update. Relevant when
++                                                                 type = e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP */
++    } u;
++} ioc_fm_pcd_manip_hdr_field_update_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining custom header manipulation for IP replacement
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_custom_ip_hdr_replace_t {
++    ioc_fm_pcd_manip_hdr_custom_ip_replace  replace_type;   /**< Selects replace update type */
++    bool                                    dec_ttl_hl;     /**< Decrement TTL (IPV4) or Hop limit (IPV6) by 1 */
++    bool                                    update_ipv4_id; /**< Relevant when replace_type =
++                                                                 e_IOC_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4 */
++    uint16_t                                id;             /**< 16 bit New IP ID; Relevant only if
++                                                                 update_ipv4_id = TRUE */
++    uint8_t                                 hdr_size;       /**< The size of the new IP header */
++    uint8_t                                 hdr[IOC_FM_PCD_MANIP_MAX_HDR_SIZE];
++                                                            /**< The new IP header */
++} ioc_fm_pcd_manip_hdr_custom_ip_hdr_replace_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining custom header manipulation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_custom_params_t {
++    ioc_fm_pcd_manip_hdr_custom_type                type;   /**< Type of header field update manipulation */
++    union {
++        ioc_fm_pcd_manip_hdr_custom_ip_hdr_replace_t    ip_hdr_replace;
++                                                            /**< Parameters IP header replacement */
++    } u;
++} ioc_fm_pcd_manip_hdr_custom_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining specific L2 insertion manipulation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_insrt_specific_l2_params_t {
++    ioc_fm_pcd_manip_hdr_insrt_specific_l2  specific_l2;    /**< Selects which L2 headers to insert */
++    bool                                    update;         /**< TRUE to update MPLS header */
++    uint8_t                                 size;           /**< size of inserted section */
++    uint8_t                                *p_data;         /**< data to be inserted */
++} ioc_fm_pcd_manip_hdr_insrt_specific_l2_params_t;
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Description   Parameters for defining IP insertion manipulation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_insrt_ip_params_t {
++    bool    calc_l4_checksum; /**< Calculate L4 checksum. */
++    ioc_fm_pcd_manip_hdr_qos_mapping_mode   mapping_mode; /**< TODO */
++    uint8_t last_pid_offset;     /**< the offset of the last Protocol within
++                                 the inserted header */
++    uint16_t  id;           /**< 16 bit New IP ID */
++    bool                            dont_frag_overwrite;
++    /**< IPv4 only. DF is overwritten with the hash-result next-to-last byte.
++     * This byte is configured to be overwritten when RPD is set. */
++    uint8_t                         last_dst_offset;
++    /**< IPv6 only. if routing extension exist, user should set the offset of the destination address
++     * in order to calculate UDP checksum pseudo header;
++     * Otherwise set it to '0'. */
++    ioc_fm_pcd_manip_hdr_insrt_t insrt; /**< size and data to be inserted. */
++} ioc_fm_pcd_manip_hdr_insrt_ip_params_t;
++#endif /* (DPAA_VERSION >= 11) */
++
++/**************************************************************************//**
++ @Description   Parameters for defining header insertion manipulation by header type
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_insrt_by_hdr_params_t {
++    ioc_fm_pcd_manip_hdr_insrt_by_hdr_type          type;   /**< Selects manipulation type */
++    union {
++       ioc_fm_pcd_manip_hdr_insrt_specific_l2_params_t  specific_l2_params;
++                                                            /**< Used when type = e_IOC_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2:
++                                                                 Selects which L2 headers to remove */
++#if (DPAA_VERSION >= 11)
++        ioc_fm_pcd_manip_hdr_insrt_ip_params_t      ip_params;  /**< Used when type = e_FM_PCD_MANIP_INSRT_BY_HDR_IP */
++        ioc_fm_pcd_manip_hdr_insrt_t                insrt;     /**< Used when type is one of e_FM_PCD_MANIP_INSRT_BY_HDR_UDP,
++                                                                e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE, or
++                                                                e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP */
++#endif /* (DPAA_VERSION >= 11) */
++    } u;
++} ioc_fm_pcd_manip_hdr_insrt_by_hdr_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header insertion manipulation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_insrt_params_t {
++    ioc_fm_pcd_manip_hdr_insrt_type                     type;   /**< Type of insertion manipulation */
++    union {
++        ioc_fm_pcd_manip_hdr_insrt_by_hdr_params_t      by_hdr; /**< Parameters for defining header insertion manipulation by header type,
++                                                                     relevant if 'type' = e_IOC_FM_PCD_MANIP_INSRT_BY_HDR */
++        ioc_fm_pcd_manip_hdr_insrt_generic_params_t     generic;/**< Parameters for defining generic header insertion manipulation,
++                                                                     relevant if type = e_IOC_FM_PCD_MANIP_INSRT_GENERIC */
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++        ioc_fm_pcd_manip_hdr_insrt_by_template_params_t by_template;
++                                                                /**< Parameters for defining header insertion manipulation by template,
++                                                                     relevant if 'type' = e_IOC_FM_PCD_MANIP_INSRT_BY_TEMPLATE */
++#endif /* FM_CAPWAP_SUPPORT */
++    } u;
++} ioc_fm_pcd_manip_hdr_insrt_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header removal manipulation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_rmv_params_t {
++    ioc_fm_pcd_manip_hdr_rmv_type                  type;       /**< Type of header removal manipulation */
++    union {
++        ioc_fm_pcd_manip_hdr_rmv_by_hdr_params_t   by_hdr;     /**< Parameters for defining header removal manipulation by header type,
++                                                                    relevant if type = e_IOC_FM_PCD_MANIP_RMV_BY_HDR */
++        ioc_fm_pcd_manip_hdr_rmv_generic_params_t  generic;    /**< Parameters for defining generic header removal manipulation,
++                                                                    relevant if type = e_IOC_FM_PCD_MANIP_RMV_GENERIC */
++    } u;
++} ioc_fm_pcd_manip_hdr_rmv_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining header manipulation node
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_hdr_params_t {
++    bool                                        rmv;                  /**< TRUE, to define removal manipulation */
++    ioc_fm_pcd_manip_hdr_rmv_params_t           rmv_params;           /**< Parameters for removal manipulation, relevant if 'rmv' = TRUE */
++
++    bool                                        insrt;                /**< TRUE, to define insertion manipulation */
++    ioc_fm_pcd_manip_hdr_insrt_params_t         insrt_params;         /**< Parameters for insertion manipulation, relevant if 'insrt' = TRUE */
++
++    bool                                        field_update;         /**< TRUE, to define field update manipulation */
++    ioc_fm_pcd_manip_hdr_field_update_params_t  field_update_params;  /**< Parameters for field update manipulation, relevant if 'fieldUpdate' = TRUE */
++
++    bool                                        custom;               /**< TRUE, to define custom manipulation */
++    ioc_fm_pcd_manip_hdr_custom_params_t        custom_params;        /**< Parameters for custom manipulation, relevant if 'custom' = TRUE */
++
++    bool                                        dont_parse_after_manip;/**< FALSE to activate the parser a second time after
++                                                                            completing the manipulation on the frame */
++} ioc_fm_pcd_manip_hdr_params_t;
++
++
++/**************************************************************************//**
++ @Description   structure for defining fragmentation manipulation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_frag_params_t {
++    ioc_net_header_type                     hdr;            /**< Header selection */
++    union {
++#if (DPAA_VERSION >= 11)
++        ioc_fm_pcd_manip_frag_capwap_params_t    capwap_frag;   /**< Parameters for defining CAPWAP fragmentation,
++                                                           relevant if 'hdr' = HEADER_TYPE_CAPWAP */
++#endif /* (DPAA_VERSION >= 11) */
++        ioc_fm_pcd_manip_frag_ip_params_t   ip_frag;        /**< Parameters for defining IP fragmentation,
++                                                                 relevant if 'hdr' = HEADER_TYPE_Ipv4 or HEADER_TYPE_Ipv6 */
++    } u;
++} ioc_fm_pcd_manip_frag_params_t;
++
++/**************************************************************************//**
++ @Description   structure for defining reassemble manipulation
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_reassem_params_t {
++    ioc_net_header_type                         hdr;        /**< Header selection */
++    union {
++#if (DPAA_VERSION >= 11)
++        ioc_fm_pcd_manip_reassem_capwap_params_t capwap_reassem;  /**< Parameters for defining CAPWAP reassembly,
++                                                           relevant if 'hdr' = HEADER_TYPE_CAPWAP */
++#endif /* (DPAA_VERSION >= 11) */
++        ioc_fm_pcd_manip_reassem_ip_params_t    ip_reassem; /**< Parameters for defining IP reassembly,
++                                                                 relevant if 'hdr' = HEADER_TYPE_Ipv4 or HEADER_TYPE_Ipv6 */
++    } u;
++} ioc_fm_pcd_manip_reassem_params_t;
++
++/**************************************************************************//**
++ @Description   Parameters for defining a manipulation node
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_params_t {
++    ioc_fm_pcd_manip_type                           type;   /**< Selects type of manipulation node */
++    union {
++        ioc_fm_pcd_manip_hdr_params_t               hdr;    /**< Parameters for defining header manipulation node */
++        ioc_fm_pcd_manip_reassem_params_t           reassem;/**< Parameters for defining reassembly manipulation node */
++        ioc_fm_pcd_manip_frag_params_t              frag;   /**< Parameters for defining fragmentation manipulation node */
++        ioc_fm_pcd_manip_special_offload_params_t   special_offload;/**< Parameters for defining special offload manipulation node */
++    } u;
++    void                                            *p_next_manip;/**< Handle to another (previously defined) manipulation node;
++                                                                 Allows concatenation of manipulation actions
++                                                                 This parameter is optional and may be NULL. */
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++    bool                                            frag_or_reasm;/**< TRUE, if defined fragmentation/reassembly manipulation */
++    ioc_fm_pcd_manip_frag_or_reasm_params_t         frag_or_reasm_params;/**< Parameters for fragmentation/reassembly manipulation,
++                                                                            relevant if frag_or_reasm = TRUE */
++#endif /* FM_CAPWAP_SUPPORT */
++    void                                           *id;
++} ioc_fm_pcd_manip_params_t;
++
++/**************************************************************************//**
++ @Description   Structure for retrieving IP reassembly statistics
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_reassem_ip_stats_t {
++    /* common counters for both IPv4 and IPv6 */
++    uint32_t    timeout;                        /**< Counts the number of TimeOut occurrences */
++    uint32_t    rfd_pool_busy;                    /**< Counts the number of failed attempts to allocate
++                                                     a Reassembly Frame Descriptor */
++    uint32_t    internal_buffer_busy;             /**< Counts the number of times an internal buffer busy occurred */
++    uint32_t    external_buffer_busy;             /**< Counts the number of times external buffer busy occurred */
++    uint32_t    sg_fragments;                    /**< Counts the number of Scatter/Gather fragments */
++    uint32_t    dma_semaphore_depletion;          /**< Counts the number of failed attempts to allocate a DMA semaphore */
++#if (DPAA_VERSION >= 11)
++    uint32_t        non_consistent_sp;            /**< Counts the number of Non Consistent Storage Profile events for
++                                                     successfully reassembled frames */
++#endif /* (DPAA_VERSION >= 11) */
++struct {
++        uint32_t    successfully_reassembled;    /**< Counts the number of successfully reassembled frames */
++        uint32_t    valid_fragments;             /**< Counts the total number of valid fragments that
++                                                     have been processed for all frames */
++        uint32_t    processed_fragments;         /**< Counts the number of processed fragments
++                                                     (valid and error fragments) for all frames */
++        uint32_t    malformed_fragments;         /**< Counts the number of malformed fragments processed for all frames */
++        uint32_t    discarded_fragments;         /**< Counts the number of fragments discarded by the reassembly process */
++        uint32_t    auto_learn_busy;              /**< Counts the number of times a busy condition occurs when attempting
++                                                     to access an IP-Reassembly Automatic Learning Hash set */
++        uint32_t    more_than16fragments;        /**< Counts the fragment occurrences in which the number of fragments-per-frame
++                                                     exceeds 16 */
++    } specific_hdr_statistics[2];                 /**< slot '0' is for IPv4, slot '1' is for IPv6 */
++} ioc_fm_pcd_manip_reassem_ip_stats_t;
++
++/**************************************************************************//**
++ @Description   Structure for retrieving IP fragmentation statistics
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_frag_ip_stats_t {
++    uint32_t    total_frames;            /**< Number of frames that passed through the manipulation node */
++    uint32_t    fragmented_frames;       /**< Number of frames that were fragmented */
++    uint32_t    generated_fragments;     /**< Number of fragments that were generated */
++} ioc_fm_pcd_manip_frag_ip_stats_t;
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Description   Structure for retrieving CAPWAP reassembly statistics
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_reassem_capwap_stats_t {
++    uint32_t    timeout;                    /**< Counts the number of timeout occurrences */
++    uint32_t    rfd_pool_busy;                /**< Counts the number of failed attempts to allocate
++                                                 a Reassembly Frame Descriptor */
++    uint32_t    internal_buffer_busy;         /**< Counts the number of times an internal buffer busy occurred */
++    uint32_t    external_buffer_busy;         /**< Counts the number of times external buffer busy occurred */
++    uint32_t    sg_fragments;                /**< Counts the number of Scatter/Gather fragments */
++    uint32_t    dma_semaphore_depletion;      /**< Counts the number of failed attempts to allocate a DMA semaphore */
++    uint32_t    successfully_reassembled;    /**< Counts the number of successfully reassembled frames */
++    uint32_t    valid_fragments;             /**< Counts the total number of valid fragments that
++                                                 have been processed for all frames */
++    uint32_t    processed_fragments;         /**< Counts the number of processed fragments
++                                                 (valid and error fragments) for all frames */
++    uint32_t    malformed_fragments;         /**< Counts the number of malformed fragments processed for all frames */
++    uint32_t    autoLearn_busy;              /**< Counts the number of times a busy condition occurs when attempting
++                                                 to access an Reassembly Automatic Learning Hash set */
++    uint32_t    discarded_fragments;         /**< Counts the number of fragments discarded by the reassembly process */
++    uint32_t    more_than16fragments;        /**< Counts the fragment occurrences in which the number of fragments-per-frame
++                                                 exceeds 16 */
++    uint32_t    exceed_max_reassembly_frame_len;/**< ounts the number of times that a successful reassembled frame
++                                                 length exceeds MaxReassembledFrameLength value */
++} ioc_fm_pcd_manip_reassem_capwap_stats_t;
++
++/**************************************************************************//**
++ @Description   Structure for retrieving CAPWAP fragmentation statistics
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_frag_capwap_stats_t {
++    uint32_t    total_frames;            /**< Number of frames that passed through the manipulation node */
++    uint32_t    fragmented_frames;       /**< Number of frames that were fragmented */
++    uint32_t    generated_fragments;     /**< Number of fragments that were generated */
++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
++    uint8_t     sg_allocation_failure;    /**< Number of allocation failure of s/g buffers */
++#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */
++} ioc_fm_pcd_manip_frag_capwap_stats_t;
++#endif /* (DPAA_VERSION >= 11) */
++
++/**************************************************************************//**
++ @Description   Structure for retrieving reassembly statistics
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_reassem_stats_t {
++    union {
++        ioc_fm_pcd_manip_reassem_ip_stats_t  ip_reassem;  /**< Structure for IP reassembly statistics */
++#if (DPAA_VERSION >= 11)
++        ioc_fm_pcd_manip_reassem_capwap_stats_t  capwap_reassem;  /**< Structure for CAPWAP reassembly statistics */
++#endif /* (DPAA_VERSION >= 11) */
++    } u;
++} ioc_fm_pcd_manip_reassem_stats_t;
++
++/**************************************************************************//**
++ @Description   structure for retrieving fragmentation statistics
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_frag_stats_t {
++    union {
++        ioc_fm_pcd_manip_frag_ip_stats_t     ip_frag;     /**< Structure for IP fragmentation statistics */
++#if (DPAA_VERSION >= 11)
++        ioc_fm_pcd_manip_frag_capwap_stats_t capwap_frag; /**< Structure for CAPWAP fragmentation statistics */
++#endif /* (DPAA_VERSION >= 11) */
++    } u;
++} ioc_fm_pcd_manip_frag_stats_t;
++
++/**************************************************************************//**
++ @Description   structure for defining manipulation statistics
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_stats_t {
++    union {
++        ioc_fm_pcd_manip_reassem_stats_t  reassem;    /**< Structure for reassembly statistics */
++        ioc_fm_pcd_manip_frag_stats_t     frag;       /**< Structure for fragmentation statistics */
++    } u;
++} ioc_fm_pcd_manip_stats_t;
++
++/**************************************************************************//**
++ @Description   Parameters for acquiring manipulation statistics
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_manip_get_stats_t {
++      void                            *id;
++      ioc_fm_pcd_manip_stats_t        stats;
++} ioc_fm_pcd_manip_get_stats_t;
++
++#if DPAA_VERSION >= 11
++/**************************************************************************//**
++ @Description   Parameters for defining frame replicator group and its members
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_frm_replic_group_params_t {
++    uint8_t                     max_num_of_entries;    /**< Maximal number of members in the group  - must be at least two */
++    uint8_t                     num_of_entries;       /**< Number of members in the group - must be at least 1 */
++    ioc_fm_pcd_cc_next_engine_params_t   next_engine_params[IOC_FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES];
++                                                    /**< Array of members' parameters */
++    void                        *id;
++} ioc_fm_pcd_frm_replic_group_params_t;
++
++typedef struct ioc_fm_pcd_frm_replic_member_t {
++    void *h_replic_group;
++    uint16_t member_index;
++} ioc_fm_pcd_frm_replic_member_t;
++
++typedef struct ioc_fm_pcd_frm_replic_member_params_t {
++    ioc_fm_pcd_frm_replic_member_t member;
++    ioc_fm_pcd_cc_next_engine_params_t next_engine_params;
++} ioc_fm_pcd_frm_replic_member_params_t;
++#endif /* DPAA_VERSION >= 11 */
++
++
++typedef struct ioc_fm_pcd_cc_key_statistics_t {
++    uint32_t    byte_count;      /**< This counter reflects byte count of frames that
++                                     were matched by this key. */
++    uint32_t    frame_count;     /**< This counter reflects count of frames that
++                                     were matched by this key. */
++#if (DPAA_VERSION >= 11)
++    uint32_t    frame_length_range_count[IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR];
++                                /**< These counters reflect how many frames matched
++                                     this key in 'RMON' statistics mode:
++                                     Each counter holds the number of frames of a
++                                     specific frames length range, according to the
++                                     ranges provided at initialization. */
++#endif /* (DPAA_VERSION >= 11) */
++} ioc_fm_pcd_cc_key_statistics_t;
++
++
++typedef struct ioc_fm_pcd_cc_tbl_get_stats_t {
++    void                            *id;
++    uint16_t                        key_index;
++    ioc_fm_pcd_cc_key_statistics_t  statistics;
++} ioc_fm_pcd_cc_tbl_get_stats_t;
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableGetKeyStatistics
++
++ @Description   This routine may be used to get statistics counters of specific key
++                in a CC Node.
++
++                If 'e_FM_PCD_CC_STATS_MODE_FRAME' and
++                'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node,
++                these counters reflect how many frames passed that were matched
++                this key; The total frames count will be returned in the counter
++                of the first range (as only one frame length range was defined).
++                If 'e_FM_PCD_CC_STATS_MODE_RMON' was set for this node, the total
++                frame count will be separated to frame length counters, based on
++                provided frame length ranges.
++
++ @Param[in]     h_CcNode        A handle to the node
++ @Param[in]     keyIndex        Key index for adding
++ @Param[out]    p_KeyStatistics Key statistics counters
++
++ @Return        The specific key statistics.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet().
++*//***************************************************************************/
++
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_MATCH_TABLE_GET_KEY_STAT_COMPAT   _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(12), ioc_compat_fm_pcd_cc_tbl_get_stats_t)
++#endif
++#define FM_PCD_IOC_MATCH_TABLE_GET_KEY_STAT  _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(12), ioc_fm_pcd_cc_tbl_get_stats_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableGetMissStatistics
++
++ @Description   This routine may be used to get statistics counters of miss entry
++                in a CC Node.
++
++                If 'e_FM_PCD_CC_STATS_MODE_FRAME' and
++                'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node,
++                these counters reflect how many frames were not matched to any
++                existing key and therefore passed through the miss entry; The
++                total frames count will be returned in the counter of the
++                first range (as only one frame length range was defined).
++
++ @Param[in]     h_CcNode            A handle to the node
++ @Param[out]    p_MissStatistics    Statistics counters for 'miss'
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet().
++*//***************************************************************************/
++
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_MATCH_TABLE_GET_MISS_STAT_COMPAT   _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(13), ioc_compat_fm_pcd_cc_tbl_get_stats_t)
++#endif
++#define FM_PCD_IOC_MATCH_TABLE_GET_MISS_STAT  _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(13), ioc_fm_pcd_cc_tbl_get_stats_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_HashTableGetMissStatistics
++
++ @Description   This routine may be used to get statistics counters of 'miss'
++                entry of the a hash table.
++
++                If 'e_FM_PCD_CC_STATS_MODE_FRAME' and
++                'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node,
++                these counters reflect how many frames were not matched to any
++                existing key and therefore passed through the miss entry;
++
++ @Param[in]     h_HashTbl           A handle to a hash table
++ @Param[out]    p_MissStatistics    Statistics counters for 'miss'
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_HashTableSet().
++*//***************************************************************************/
++
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_HASH_TABLE_GET_MISS_STAT_COMPAT   _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(14), ioc_compat_fm_pcd_cc_tbl_get_stats_t)
++#endif
++#define FM_PCD_IOC_HASH_TABLE_GET_MISS_STAT  _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(14), ioc_fm_pcd_cc_tbl_get_stats_t)
++
++
++/**************************************************************************//**
++ @Function      FM_PCD_NetEnvCharacteristicsSet
++
++ @Description   Define a set of Network Environment Characteristics.
++
++                When setting an environment it is important to understand its
++                application. It is not meant to describe the flows that will run
++                on the ports using this environment, but what the user means TO DO
++                with the PCD mechanisms in order to parse-classify-distribute those
++                frames.
++                By specifying a distinction unit, the user means it would use that option
++                for distinction between frames at either a KeyGen scheme or a coarse
++                classification action descriptor. Using interchangeable headers to define a
++                unit means that the user is indifferent to which of the interchangeable
++                headers is present in the frame, and wants the distinction to be based
++                on the presence of either one of them.
++
++                Depending on context, there are limitations to the use of environments. A
++                port using the PCD functionality is bound to an environment. Some or even
++                all ports may share an environment but also an environment per port is
++                possible. When initializing a scheme, a classification plan group (see below),
++                or a coarse classification tree, one of the initialized environments must be
++                stated and related to. When a port is bound to a scheme, a classification
++                plan group, or a coarse classification tree, it MUST be bound to the same
++                environment.
++
++                The different PCD modules, may relate (for flows definition) ONLY on
++                distinction units as defined by their environment. When initializing a
++                scheme for example, it may not choose to select IPV4 as a match for
++                recognizing flows unless it was defined in the relating environment. In
++                fact, to guide the user through the configuration of the PCD, each module's
++                characterization in terms of flows is not done using protocol names, but using
++                environment indexes.
++
++                In terms of HW implementation, the list of distinction units sets the LCV vectors
++                and later used for match vector, classification plan vectors and coarse classification
++                indexing.
++
++ @Param[in,out] ioc_fm_pcd_net_env_params_t   A structure defining the distiction units for this configuration.
++
++ @Return        0 on success; Error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET_COMPAT   _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(20), ioc_compat_fm_pcd_net_env_params_t)
++#endif
++#define FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET  _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(20), ioc_fm_pcd_net_env_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_NetEnvCharacteristicsDelete
++
++ @Description   Deletes a set of Network Environment Charecteristics.
++
++ @Param[in]     ioc_fm_obj_t - The id of a Network Environment object.
++
++ @Return        0 on success; Error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE_COMPAT  _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(21), ioc_compat_fm_obj_t)
++#endif
++#define FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE   _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(21), ioc_fm_obj_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_KgSchemeSet
++
++ @Description   Initializing or modifying and enabling a scheme for the KeyGen.
++                This routine should be called for adding or modifying a scheme.
++                When a scheme needs modifying, the API requires that it will be
++                rewritten. In such a case 'modify' should be TRUE. If the
++                routine is called for a valid scheme and 'modify' is FALSE,
++                it will return error.
++
++ @Param[in,out] ioc_fm_pcd_kg_scheme_params_t   A structure of parameters for defining the scheme
++
++ @Return        0 on success; Error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_KG_SCHEME_SET_COMPAT     _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(24), ioc_compat_fm_pcd_kg_scheme_params_t)
++#endif
++#define FM_PCD_IOC_KG_SCHEME_SET    _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(24), ioc_fm_pcd_kg_scheme_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_KgSchemeDelete
++
++ @Description   Deleting an initialized scheme.
++
++ @Param[in]     ioc_fm_obj_t        scheme id as initalized by application at FM_PCD_IOC_KG_SET_SCHEME
++
++ @Return        0 on success; Error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_KG_SCHEME_DELETE_COMPAT  _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(25), ioc_compat_fm_obj_t)
++#endif
++#define FM_PCD_IOC_KG_SCHEME_DELETE     _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(25), ioc_fm_obj_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_CcRootBuild
++
++ @Description   This routine must be called to define a complete coarse
++                classification tree. This is the way to define coarse
++                classification to a certain flow - the KeyGen schemes
++                may point only to trees defined in this way.
++
++ @Param[in,out] ioc_fm_pcd_cc_tree_params_t     A structure of parameters to define the tree.
++
++ @Return        0 on success; Error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_CC_ROOT_BUILD_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(26), compat_uptr_t)
++#endif
++#define FM_PCD_IOC_CC_ROOT_BUILD    _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(26), void *) /* workaround ...*/
++
++/**************************************************************************//**
++ @Function      FM_PCD_CcRootDelete
++
++ @Description   Deleting a built tree.
++
++ @Param[in]     ioc_fm_obj_t - The id of a CC tree.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_CC_ROOT_DELETE_COMPAT    _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(27), ioc_compat_fm_obj_t)
++#endif
++#define FM_PCD_IOC_CC_ROOT_DELETE    _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(27), ioc_fm_obj_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableSet
++
++ @Description   This routine should be called for each CC (coarse classification)
++                node. The whole CC tree should be built bottom up so that each
++                node points to already defined nodes. p_NodeId returns the node
++                Id to be used by other nodes.
++
++ @Param[in,out] ioc_fm_pcd_cc_node_params_t       A structure for defining the CC node params
++
++ @Return        0 on success; Error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_MATCH_TABLE_SET_COMPAT    _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(28), compat_uptr_t)
++#endif
++#define FM_PCD_IOC_MATCH_TABLE_SET    _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(28), void *) /* workaround ...*/
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableDelete
++
++ @Description   Deleting a built node.
++
++ @Param[in]     ioc_fm_obj_t - The id of a CC node.
++
++ @Return        0 on success; Error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_MATCH_TABLE_DELETE_COMPAT    _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(29), ioc_compat_fm_obj_t)
++#endif
++#define FM_PCD_IOC_MATCH_TABLE_DELETE   _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(29), ioc_fm_obj_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_CcRootModifyNextEngine
++
++ @Description   Modify the Next Engine Parameters in the entry of the tree.
++
++ @Param[in]     ioc_fm_pcd_cc_tree_modify_next_engine_params_t - Pointer to a structure with the relevant parameters
++
++ @Return        0 on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_CcRootBuild().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE_COMPAT   _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(30), ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t)
++#endif
++#define FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE   _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(30), ioc_fm_pcd_cc_tree_modify_next_engine_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableModifyNextEngine
++
++ @Description   Modify the Next Engine Parameters in the relevant key entry of the node.
++
++ @Param[in]     ioc_fm_pcd_cc_node_modify_next_engine_params_t  A pointer to a structure with the relevant parameters
++
++ @Return        0 on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE_COMPAT   _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(31), ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)
++#endif
++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE   _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(31), ioc_fm_pcd_cc_node_modify_next_engine_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableModifyMissNextEngine
++
++ @Description   Modify the Next Engine Parameters of the Miss key case of the node.
++
++ @Param[in]     ioc_fm_pcd_cc_node_modify_next_engine_params_t - Pointer to a structure with the relevant parameters
++
++ @Return        0 on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE_COMPAT   _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(32), ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)
++#endif
++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(32), ioc_fm_pcd_cc_node_modify_next_engine_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableRemoveKey
++
++ @Description   Remove the key (including next engine parameters of this key)
++                defined by the index of the relevant node.
++
++ @Param[in]     ioc_fm_pcd_cc_node_remove_key_params_t  A pointer to a structure with the relevant parameters
++
++ @Return        0 on success; Error code otherwise.
++
++ @Cautions      Allowed only after FM_PCD_MatchTableSet() has been called for this
++                node and for all of the nodes that lead to it.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY_COMPAT    _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(33), ioc_compat_fm_pcd_cc_node_remove_key_params_t)
++#endif
++#define FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY   _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(33), ioc_fm_pcd_cc_node_remove_key_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableAddKey
++
++ @Description   Add the key (including next engine parameters of this key in the
++                index defined by the keyIndex. Note that 'FM_PCD_LAST_KEY_INDEX'
++                may be used when the user doesn't care about the position of the
++                key in the table - in that case, the key will be automatically
++                added by the driver in the last available entry.
++
++ @Param[in]     ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t  A pointer to a structure with the relevant parameters
++
++ @Return        0 on success; Error code otherwise.
++
++ @Cautions      Allowed only after FM_PCD_MatchTableSet() has been called for this
++                node and for all of the nodes that lead to it.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_MATCH_TABLE_ADD_KEY_COMPAT   _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(34), ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)
++#endif
++#define FM_PCD_IOC_MATCH_TABLE_ADD_KEY  _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(34), ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableModifyKeyAndNextEngine
++
++ @Description   Modify the key and Next Engine Parameters of this key in the index defined by key_index.
++
++ @Param[in]     ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t  A pointer to a structure with the relevant parameters
++
++ @Return        0 on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_MatchTableSet() not only of the relevnt node but also
++                the node that points to this node
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE_COMPAT    _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(35), ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)
++#endif
++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE   _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(35), ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_MatchTableModifyKey
++
++ @Description   Modify the key at the index defined by key_index.
++
++ @Param[in]     ioc_fm_pcd_cc_node_modify_key_params_t - Pointer to a structure with the relevant parameters
++
++ @Return        0 on success; Error code otherwise.
++
++ @Cautions      Allowed only after FM_PCD_MatchTableSet() has been called for this
++                node and for all of the nodes that lead to it.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_COMPAT    _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(36), ioc_compat_fm_pcd_cc_node_modify_key_params_t)
++#endif
++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY   _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(36), ioc_fm_pcd_cc_node_modify_key_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_HashTableSet
++
++ @Description   This routine initializes a hash table structure.
++                KeyGen hash result determines the hash bucket.
++                Next, KeyGen key is compared against all keys of this
++                bucket (exact match).
++                Number of sets (number of buckets) of the hash equals to the
++                number of 1-s in 'hash_res_mask' in the provided parameters.
++                Number of hash table ways is then calculated by dividing
++                'max_num_of_keys' equally between the hash sets. This is the maximal
++                number of keys that a hash bucket may hold.
++                The hash table is initialized empty and keys may be
++                added to it following the initialization. Keys masks are not
++                supported in current hash table implementation.
++                The initialized hash table can be integrated as a node in a
++                CC tree.
++
++ @Param[in,out] ioc_fm_pcd_hash_table_params_t - Pointer to a structure with the relevant parameters
++
++ @Return        0 on success; Error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_HASH_TABLE_SET_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(37), ioc_compat_fm_pcd_hash_table_params_t)
++#endif
++#define FM_PCD_IOC_HASH_TABLE_SET _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(37), ioc_fm_pcd_hash_table_params_t)
++
++
++/**************************************************************************//**
++ @Function      FM_PCD_HashTableDelete
++
++ @Description   This routine deletes the provided hash table and released all
++                its allocated resources.
++
++ @Param[in]     ioc_fm_obj_t - The ID of a hash table.
++
++ @Return        0 on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_HashTableSet().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_HASH_TABLE_DELETE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(37), ioc_compat_fm_obj_t)
++#endif
++#define FM_PCD_IOC_HASH_TABLE_DELETE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(37), ioc_fm_obj_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_HashTableAddKey
++
++ @Description   This routine adds the provided key (including next engine
++                parameters of this key) to the hash table.
++                The key is added as the last key of the bucket that it is
++                mapped to.
++
++ @Param[in]     ioc_fm_pcd_hash_table_add_key_params_t - Pointer to a structure with the relevant parameters
++
++ @Return        0 on success; error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_HashTableSet().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_HASH_TABLE_ADD_KEY_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(39), ioc_compat_fm_pcd_hash_table_add_key_params_t)
++#endif
++#define FM_PCD_IOC_HASH_TABLE_ADD_KEY _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(39), ioc_fm_pcd_hash_table_add_key_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_HashTableRemoveKey
++
++ @Description   This routine removes the requested key (including next engine
++                parameters of this key) from the hash table.
++
++ @Param[in]     ioc_fm_pcd_hash_table_remove_key_params_t - Pointer to a structure with the relevant parameters
++
++ @Return        0 on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_HashTableSet().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_HASH_TABLE_REMOVE_KEY_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(40), ioc_compat_fm_pcd_hash_table_remove_key_params_t)
++#endif
++#define FM_PCD_IOC_HASH_TABLE_REMOVE_KEY _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(40), ioc_fm_pcd_hash_table_remove_key_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_PlcrProfileSet
++
++ @Description   Sets a profile entry in the policer profile table.
++                The routine overrides any existing value.
++
++ @Param[in,out] ioc_fm_pcd_plcr_profile_params_t    A structure of parameters for defining a
++                                                    policer profile entry.
++
++ @Return        0 on success; Error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_PLCR_PROFILE_SET_COMPAT     _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(41), ioc_compat_fm_pcd_plcr_profile_params_t)
++#endif
++#define FM_PCD_IOC_PLCR_PROFILE_SET     _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(41), ioc_fm_pcd_plcr_profile_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_PlcrProfileDelete
++
++ @Description   Delete a profile entry in the policer profile table.
++                The routine set entry to invalid.
++
++ @Param[in]     ioc_fm_obj_t        The id of a policer profile.
++
++ @Return        0 on success; Error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_PLCR_PROFILE_DELETE_COMPAT   _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(41), ioc_compat_fm_obj_t)
++#endif
++#define FM_PCD_IOC_PLCR_PROFILE_DELETE  _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(41), ioc_fm_obj_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_ManipNodeSet
++
++ @Description   This routine should be called for defining a manipulation
++                node. A manipulation node must be defined before the CC node
++                that precedes it.
++
++ @Param[in]     ioc_fm_pcd_manip_params_t - A structure of parameters defining the manipulation
++
++ @Return        A handle to the initialized object on success; NULL code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_MANIP_NODE_SET_COMPAT    _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(43), ioc_compat_fm_pcd_manip_params_t)
++#endif
++#define FM_PCD_IOC_MANIP_NODE_SET   _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(43), ioc_fm_pcd_manip_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_ManipNodeReplace
++
++ @Description   Change existing manipulation node to be according to new requirement.
++                (Here, it's implemented as a variant of the same IOCTL as for
++                FM_PCD_ManipNodeSet(), and one that when called, the 'id' member
++                in its 'ioc_fm_pcd_manip_params_t' argument is set to contain
++                the manip node's handle)
++
++ @Param[in]     ioc_fm_pcd_manip_params_t - A structure of parameters defining the manipulation
++
++ @Return        0 on success; error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_ManipNodeSet().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_MANIP_NODE_REPLACE_COMPAT    FM_PCD_IOC_MANIP_NODE_SET_COMPAT
++#endif
++#define FM_PCD_IOC_MANIP_NODE_REPLACE           FM_PCD_IOC_MANIP_NODE_SET
++
++/**************************************************************************//**
++ @Function      FM_PCD_ManipNodeDelete
++
++ @Description   Delete an existing manipulation node.
++
++ @Param[in]     ioc_fm_obj_t       The id of the manipulation node to delete.
++
++ @Return        0 on success; error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_ManipNodeSet().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_MANIP_NODE_DELETE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(44), ioc_compat_fm_obj_t)
++#endif
++#define FM_PCD_IOC_MANIP_NODE_DELETE    _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(44), ioc_fm_obj_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_ManipGetStatistics
++
++ @Description   Retrieve the manipulation statistics.
++
++ @Param[in]     h_ManipNode         A handle to a manipulation node.
++ @Param[out]    p_FmPcdManipStats   A structure for retrieving the manipulation statistics
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_ManipNodeSet().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_MANIP_GET_STATS_COMPAT  _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(50), ioc_compat_fm_pcd_manip_get_stats_t)
++#endif
++#define FM_PCD_IOC_MANIP_GET_STATS   _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(50), ioc_fm_pcd_manip_get_stats_t)
++
++/**************************************************************************//**
++@Function      FM_PCD_SetAdvancedOffloadSupport
++
++@Description   This routine must be called in order to support the following features:
++               IP-fragmentation, IP-reassembly, IPsec, Header-manipulation, frame-replicator.
++
++@Param[in]     h_FmPcd         FM PCD module descriptor.
++
++@Return        0 on success; error code otherwise.
++
++@Cautions      Allowed only when PCD is disabled.
++*//***************************************************************************/
++#define FM_PCD_IOC_SET_ADVANCED_OFFLOAD_SUPPORT _IO(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(45))
++
++#if (DPAA_VERSION >= 11)
++/**************************************************************************//**
++ @Function      FM_PCD_FrmReplicSetGroup
++
++ @Description   Initialize a Frame Replicator group.
++
++ @Param[in]     h_FmPcd                FM PCD module descriptor.
++ @Param[in]     p_FrmReplicGroupParam  A structure of parameters for the initialization of
++                                       the frame replicator group.
++
++ @Return        A handle to the initialized object on success; NULL code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_Init().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_FRM_REPLIC_GROUP_SET_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(46), ioc_compat_fm_pcd_frm_replic_group_params_t)
++#endif
++#define FM_PCD_IOC_FRM_REPLIC_GROUP_SET _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(46), ioc_fm_pcd_frm_replic_group_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_FrmReplicDeleteGroup
++
++ @Description   Delete a Frame Replicator group.
++
++ @Param[in]     h_FrmReplicGroup  A handle to the frame replicator group.
++
++ @Return        E_OK on success;  Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_FrmReplicSetGroup().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_FRM_REPLIC_GROUP_DELETE_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(47), ioc_compat_fm_obj_t)
++#endif
++#define FM_PCD_IOC_FRM_REPLIC_GROUP_DELETE _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(47), ioc_fm_obj_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_FrmReplicAddMember
++
++ @Description   Add the member in the index defined by the memberIndex.
++
++ @Param[in]     h_FrmReplicGroup   A handle to the frame replicator group.
++ @Param[in]     memberIndex        member index for adding.
++ @Param[in]     p_MemberParams     A pointer to the new member parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_FrmReplicSetGroup() of this group.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_FRM_REPLIC_MEMBER_ADD_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(48), ioc_compat_fm_pcd_frm_replic_member_params_t)
++#endif
++#define FM_PCD_IOC_FRM_REPLIC_MEMBER_ADD _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(48), ioc_fm_pcd_frm_replic_member_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PCD_FrmReplicRemoveMember
++
++ @Description   Remove the member defined by the index from the relevant group.
++
++ @Param[in]     h_FrmReplicGroup   A handle to the frame replicator group.
++ @Param[in]     memberIndex        member index for removing.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PCD_FrmReplicSetGroup() of this group.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_FRM_REPLIC_MEMBER_REMOVE_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(49), ioc_compat_fm_pcd_frm_replic_member_t)
++#endif
++#define FM_PCD_IOC_FRM_REPLIC_MEMBER_REMOVE _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(49), ioc_fm_pcd_frm_replic_member_t)
++
++#endif
++
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++/**************************************************************************//**
++ @Function      FM_PCD_StatisticsSetNode
++
++ @Description   This routine should be called for defining a statistics node.
++
++ @Param[in,out] ioc_fm_pcd_stats_params_t A structure of parameters defining the statistics
++
++ @Return        0 on success; Error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_STATISTICS_SET_NODE_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(45), void *)
++#endif
++#define FM_PCD_IOC_STATISTICS_SET_NODE _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(45), void *)
++
++#endif /* FM_CAPWAP_SUPPORT */
++
++#ifdef NCSW_BACKWARD_COMPATIBLE_API
++#if defined(CONFIG_COMPAT)
++#define FM_PCD_IOC_SET_NET_ENV_CHARACTERISTICS_COMPAT \
++                                                FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET_COMPAT
++#define FM_PCD_IOC_DELETE_NET_ENV_CHARACTERISTICS_COMPAT \
++                                                FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE_COMPAT
++#define FM_PCD_IOC_KG_SET_SCHEME_COMPAT         FM_PCD_IOC_KG_SCHEME_SET_COMPAT
++#define FM_PCD_IOC_KG_DEL_SCHEME_COMPAT         FM_PCD_IOC_KG_SCHEME_DELETE_COMPAT
++#define FM_PCD_IOC_CC_BUILD_TREE_COMPAT         FM_PCD_IOC_CC_ROOT_BUILD_COMPAT
++#define FM_PCD_IOC_CC_DELETE_TREE_COMPAT        FM_PCD_IOC_CC_ROOT_DELETE_COMPAT
++#define FM_PCD_IOC_CC_DELETE_NODE_COMPAT        FM_PCD_IOC_MATCH_TABLE_DELETE_COMPAT
++#define FM_PCD_IOC_CC_TREE_MODIFY_NEXT_ENGINE_COMPAT \
++                                                FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE_COMPAT
++#define FM_PCD_IOC_CC_NODE_MODIFY_NEXT_ENGINE_COMPAT \
++                                                FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE_COMPAT
++#define FM_PCD_IOC_CC_NODE_MODIFY_MISS_NEXT_ENGINE_COMPAT \
++                                                FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE_COMPAT
++#define FM_PCD_IOC_CC_NODE_REMOVE_KEY_COMPAT    FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY_COMPAT
++#define FM_PCD_IOC_CC_NODE_ADD_KEY_COMPAT       FM_PCD_IOC_MATCH_TABLE_ADD_KEY_COMPAT
++#define FM_PCD_IOC_CC_NODE_MODIFY_KEY_AND_NEXT_ENGINE_COMPAT \
++                                                FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE_COMPAT
++#define FM_PCD_IOC_CC_NODE_MODIFY_KEY_COMPAT    FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_COMPAT
++#define FM_PCD_IOC_PLCR_SET_PROFILE_COMPAT      FM_PCD_IOC_PLCR_PROFILE_SET_COMPAT
++#define FM_PCD_IOC_PLCR_DEL_PROFILE_COMPAT      FM_PCD_IOC_PLCR_PROFILE_DELETE_COMPAT
++#define FM_PCD_IOC_MANIP_SET_NODE_COMPAT        FM_PCD_IOC_MANIP_NODE_SET_COMPAT
++#define FM_PCD_IOC_MANIP_DELETE_NODE_COMPAT     FM_PCD_IOC_MANIP_NODE_DELETE_COMPAT
++#endif
++#define FM_PCD_IOC_SET_NET_ENV_CHARACTERISTICS  FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET
++#define FM_PCD_IOC_DELETE_NET_ENV_CHARACTERISTICS \
++                                                FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE
++#define FM_PCD_IOC_KG_SET_SCHEME                FM_PCD_IOC_KG_SCHEME_SET
++#define FM_PCD_IOC_KG_DEL_SCHEME                FM_PCD_IOC_KG_SCHEME_DELETE
++#define FM_PCD_IOC_CC_BUILD_TREE                FM_PCD_IOC_CC_ROOT_BUILD
++#define FM_PCD_IOC_CC_DELETE_TREE               FM_PCD_IOC_CC_ROOT_DELETE
++#define FM_PCD_IOC_CC_DELETE_NODE               FM_PCD_IOC_MATCH_TABLE_DELETE
++#define FM_PCD_IOC_CC_TREE_MODIFY_NEXT_ENGINE   FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE
++#define FM_PCD_IOC_CC_NODE_MODIFY_NEXT_ENGINE   FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE
++#define FM_PCD_IOC_CC_NODE_MODIFY_MISS_NEXT_ENGINE \
++                                                FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE
++#define FM_PCD_IOC_CC_NODE_REMOVE_KEY           FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY
++#define FM_PCD_IOC_CC_NODE_ADD_KEY              FM_PCD_IOC_MATCH_TABLE_ADD_KEY
++#define FM_PCD_IOC_CC_NODE_MODIFY_KEY_AND_NEXT_ENGINE \
++                                                FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE
++#define FM_PCD_IOC_CC_NODE_MODIFY_KEY           FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY
++#define FM_PCD_IOC_PLCR_SET_PROFILE             FM_PCD_IOC_PLCR_PROFILE_SET
++#define FM_PCD_IOC_PLCR_DEL_PROFILE             FM_PCD_IOC_PLCR_PROFILE_DELETE
++#define FM_PCD_IOC_MANIP_SET_NODE               FM_PCD_IOC_MANIP_NODE_SET
++#define FM_PCD_IOC_MANIP_DELETE_NODE            FM_PCD_IOC_MANIP_NODE_DELETE
++#endif /* NCSW_BACKWARD_COMPATIBLE_API */
++
++#endif /* __FM_PCD_IOCTLS_H */
++/** @} */ /* end of lnx_ioctl_FM_PCD_Runtime_grp group */
++/** @} */ /* end of lnx_ioctl_FM_PCD_grp group */
++/** @} */ /* end of lnx_ioctl_FM_grp group */
+--- /dev/null
++++ b/include/uapi/linux/fmd/Peripherals/fm_port_ioctls.h
+@@ -0,0 +1,948 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/******************************************************************************
++ @File          fm_port_ioctls.h
++
++ @Description   FM Port routines
++*//***************************************************************************/
++#ifndef __FM_PORT_IOCTLS_H
++#define __FM_PORT_IOCTLS_H
++
++#include "enet_ext.h"
++#include "net_ioctls.h"
++#include "fm_ioctls.h"
++#include "fm_pcd_ioctls.h"
++
++
++/**************************************************************************//**
++
++ @Group         lnx_ioctl_FM_grp Frame Manager Linux IOCTL API
++
++ @Description   FM Linux ioctls definitions and enums
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Group         lnx_ioctl_FM_PORT_grp FM Port
++
++ @Description   FM Port API
++
++                The FM uses a general module called "port" to represent a Tx port
++                (MAC), an Rx port (MAC), offline parsing flow or host command
++                flow. There may be up to 17 (may change) ports in an FM - 5 Tx
++                ports (4 for the 1G MACs, 1 for the 10G MAC), 5 Rx Ports, and 7
++                Host command/Offline parsing ports. The SW driver manages these
++                ports as sub-modules of the FM, i.e. after an FM is initialized,
++                its ports may be initialized and operated upon.
++
++                The port is initialized aware of its type, but other functions on
++                a port may be indifferent to its type. When necessary, the driver
++                verifies coherency and returns error if applicable.
++
++                On initialization, user specifies the port type and it's index
++                (relative to the port's type). Host command and Offline parsing
++                ports share the same id range, I.e user may not initialized host
++                command port 0 and offline parsing port 0.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   An enum for defining port PCD modes.
++                (Must match enum e_FmPortPcdSupport defined in fm_port_ext.h)
++
++                This enum defines the superset of PCD engines support - i.e. not
++                all engines have to be used, but all have to be enabled. The real
++                flow of a specific frame depends on the PCD configuration and the
++                frame headers and payload.
++                Note: the first engine and the first engine after the parser (if
++                exists) should be in order, the order is important as it will
++                define the flow of the port. However, as for the rest engines
++                (the ones that follows), the order is not important anymore as
++                it is defined by the PCD graph itself.
++*//***************************************************************************/
++typedef enum ioc_fm_port_pcd_support {
++      e_IOC_FM_PORT_PCD_SUPPORT_NONE = 0                /**< BMI to BMI, PCD is not used */
++    , e_IOC_FM_PORT_PCD_SUPPORT_PRS_ONLY                /**< Use only Parser */
++    , e_IOC_FM_PORT_PCD_SUPPORT_PLCR_ONLY               /**< Use only Policer */
++    , e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR            /**< Use Parser and Policer */
++    , e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG              /**< Use Parser and Keygen */
++    , e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC       /**< Use Parser, Keygen and Coarse Classification */
++    , e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR
++                                                        /**< Use all PCD engines */
++    , e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR     /**< Use Parser, Keygen and Policer */
++    , e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_CC              /**< Use Parser and Coarse Classification */
++    , e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_CC_AND_PLCR     /**< Use Parser and Coarse Classification and Policer */
++    , e_IOC_FM_PORT_PCD_SUPPORT_CC_ONLY                 /**< Use only Coarse Classification */
++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
++    , e_IOC_FM_PORT_PCD_SUPPORT_CC_AND_KG               /**< Use Coarse Classification,and Keygen */
++    , e_IOC_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR      /**< Use Coarse Classification, Keygen and Policer */
++#endif /* FM_CAPWAP_SUPPORT */
++} ioc_fm_port_pcd_support;
++
++
++/**************************************************************************//**
++ @Collection   FM Frame error
++*//***************************************************************************/
++typedef uint32_t    ioc_fm_port_frame_err_select_t;     /**< typedef for defining Frame Descriptor errors */
++
++/* @} */
++
++
++/**************************************************************************//**
++ @Description   An enum for defining Dual Tx rate limiting scale.
++                (Must match e_FmPortDualRateLimiterScaleDown defined in fm_port_ext.h)
++*//***************************************************************************/
++typedef enum ioc_fm_port_dual_rate_limiter_scale_down {
++    e_IOC_FM_PORT_DUAL_RATE_LIMITER_NONE = 0,           /**< Use only single rate limiter  */
++    e_IOC_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_2,    /**< Divide high rate limiter by 2 */
++    e_IOC_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_4,    /**< Divide high rate limiter by 4 */
++    e_IOC_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8     /**< Divide high rate limiter by 8 */
++} ioc_fm_port_dual_rate_limiter_scale_down;
++
++/**************************************************************************//**
++ @Description   A structure for defining Tx rate limiting
++                (Must match struct t_FmPortRateLimit defined in fm_port_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_port_rate_limit_t {
++    uint16_t                            max_burst_size;         /**< in KBytes for Tx ports, in frames
++                                                                     for offline parsing ports. (note that
++                                                                     for early chips burst size is
++                                                                     rounded up to a multiply of 1000 frames).*/
++    uint32_t                            rate_limit;             /**< in Kb/sec for Tx ports, in frame/sec for
++                                                                     offline parsing ports. Rate limit refers to
++                                                                     data rate (rather than line rate). */
++    ioc_fm_port_dual_rate_limiter_scale_down rate_limit_divider;    /**< For offline parsing ports only. Not-valid
++                                                                     for some earlier chip revisions */
++} ioc_fm_port_rate_limit_t;
++
++
++
++/**************************************************************************//**
++ @Group         lnx_ioctl_FM_PORT_runtime_control_grp FM Port Runtime Control Unit
++
++ @Description   FM Port Runtime control unit API functions, definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   An enum for defining FM Port counters.
++                (Must match enum e_FmPortCounters defined in fm_port_ext.h)
++*//***************************************************************************/
++typedef enum ioc_fm_port_counters {
++    e_IOC_FM_PORT_COUNTERS_CYCLE,                       /**< BMI performance counter */
++    e_IOC_FM_PORT_COUNTERS_TASK_UTIL,                   /**< BMI performance counter */
++    e_IOC_FM_PORT_COUNTERS_QUEUE_UTIL,                  /**< BMI performance counter */
++    e_IOC_FM_PORT_COUNTERS_DMA_UTIL,                    /**< BMI performance counter */
++    e_IOC_FM_PORT_COUNTERS_FIFO_UTIL,                   /**< BMI performance counter */
++    e_IOC_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION,         /**< BMI Rx only performance counter */
++    e_IOC_FM_PORT_COUNTERS_FRAME,                       /**< BMI statistics counter */
++    e_IOC_FM_PORT_COUNTERS_DISCARD_FRAME,               /**< BMI statistics counter */
++    e_IOC_FM_PORT_COUNTERS_DEALLOC_BUF,                 /**< BMI deallocate buffer statistics counter */
++    e_IOC_FM_PORT_COUNTERS_RX_BAD_FRAME,                /**< BMI Rx only statistics counter */
++    e_IOC_FM_PORT_COUNTERS_RX_LARGE_FRAME,              /**< BMI Rx only statistics counter */
++    e_IOC_FM_PORT_COUNTERS_RX_FILTER_FRAME,             /**< BMI Rx & OP only statistics counter */
++    e_IOC_FM_PORT_COUNTERS_RX_LIST_DMA_ERR,             /**< BMI Rx, OP & HC only statistics counter */
++    e_IOC_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD,   /**< BMI Rx, OP & HC statistics counter */
++    e_IOC_FM_PORT_COUNTERS_PREPARE_TO_ENQUEUE_COUNTER,  /**< BMI Rx, OP & HC only statistics counter */
++    e_IOC_FM_PORT_COUNTERS_WRED_DISCARD,                /**< BMI OP & HC only statistics counter */
++    e_IOC_FM_PORT_COUNTERS_LENGTH_ERR,                  /**< BMI non-Rx statistics counter */
++    e_IOC_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT,           /**< BMI non-Rx statistics counter */
++    e_IOC_FM_PORT_COUNTERS_DEQ_TOTAL,                   /**< QMI total QM dequeues counter */
++    e_IOC_FM_PORT_COUNTERS_ENQ_TOTAL,                   /**< QMI total QM enqueues counter */
++    e_IOC_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT,            /**< QMI counter */
++    e_IOC_FM_PORT_COUNTERS_DEQ_CONFIRM                  /**< QMI counter */
++} ioc_fm_port_counters;
++
++typedef struct ioc_fm_port_bmi_stats_t {
++    uint32_t cnt_cycle;
++    uint32_t cnt_task_util;
++    uint32_t cnt_queue_util;
++    uint32_t cnt_dma_util;
++    uint32_t cnt_fifo_util;
++    uint32_t cnt_rx_pause_activation;
++    uint32_t cnt_frame;
++    uint32_t cnt_discard_frame;
++    uint32_t cnt_dealloc_buf;
++    uint32_t cnt_rx_bad_frame;
++    uint32_t cnt_rx_large_frame;
++    uint32_t cnt_rx_filter_frame;
++    uint32_t cnt_rx_list_dma_err;
++    uint32_t cnt_rx_out_of_buffers_discard;
++    uint32_t cnt_wred_discard;
++    uint32_t cnt_length_err;
++    uint32_t cnt_unsupported_format;
++} ioc_fm_port_bmi_stats_t;
++
++/**************************************************************************//**
++ @Description   Structure for Port id parameters.
++                (Description may be inaccurate;
++                must match struct t_FmPortCongestionGrps defined in fm_port_ext.h)
++
++                Fields commented 'IN' are passed by the port module to be used
++                by the FM module.
++                Fields commented 'OUT' will be filled by FM before returning to port.
++*//***************************************************************************/
++typedef struct ioc_fm_port_congestion_groups_t {
++    uint16_t    num_of_congestion_grps_to_consider;     /**< The number of required congestion groups
++                                                             to define the size of the following array */
++    uint8_t     congestion_grps_to_consider [FM_PORT_NUM_OF_CONGESTION_GRPS];
++                                                        /**< An array of CG indexes;
++                                                             Note that the size of the array should be
++                                                             'num_of_congestion_grps_to_consider'. */
++#if DPAA_VERSION >= 11
++    bool        pfc_priorities_enable[FM_PORT_NUM_OF_CONGESTION_GRPS][FM_MAX_NUM_OF_PFC_PRIORITIES];
++                                                        /**< A matrix that represents the map between the CG ids
++                                                             defined in 'congestion_grps_to_consider' to the priorities
++                                                             mapping array. */
++#endif /* DPAA_VERSION >= 11 */
++} ioc_fm_port_congestion_groups_t;
++
++
++
++/**************************************************************************//**
++ @Function      FM_PORT_Disable
++
++ @Description   Gracefully disable an FM port. The port will not start new tasks after all
++                tasks associated with the port are terminated.
++
++ @Return        0 on success; error code otherwise.
++
++ @Cautions      This is a blocking routine, it returns after port is
++                gracefully stopped, i.e. the port will not except new frames,
++                but it will finish all frames or tasks which were already began
++*//***************************************************************************/
++#define FM_PORT_IOC_DISABLE   _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(1))
++
++/**************************************************************************//**
++ @Function      FM_PORT_Enable
++
++ @Description   A runtime routine provided to allow disable/enable of port.
++
++ @Return        0 on success; error code otherwise.
++*//***************************************************************************/
++#define FM_PORT_IOC_ENABLE   _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(2))
++
++/**************************************************************************//**
++ @Function      FM_PORT_SetRateLimit
++
++ @Description   Calling this routine enables rate limit algorithm.
++                By default, this functionality is disabled.
++                Note that rate-limit mechanism uses the FM time stamp.
++                The selected rate limit specified here would be
++                rounded DOWN to the nearest 16M.
++
++                May be used for Tx and offline parsing ports only
++
++ @Param[in]     ioc_fm_port_rate_limit A structure of rate limit parameters
++
++ @Return        0 on success; error code otherwise.
++*//***************************************************************************/
++#define FM_PORT_IOC_SET_RATE_LIMIT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(3), ioc_fm_port_rate_limit_t)
++
++/**************************************************************************//**
++ @Function      FM_PORT_DeleteRateLimit
++
++ @Description   Calling this routine disables the previously enabled rate limit.
++
++                May be used for Tx and offline parsing ports only
++
++ @Return        0 on success; error code otherwise.
++*//***************************************************************************/
++#define FM_PORT_IOC_DELETE_RATE_LIMIT   _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(5))
++#define FM_PORT_IOC_REMOVE_RATE_LIMIT   FM_PORT_IOC_DELETE_RATE_LIMIT
++
++
++/**************************************************************************//**
++ @Function      FM_PORT_AddCongestionGrps
++
++ @Description   This routine effects the corresponding Tx port.
++                It should be called in order to enable pause
++                frame transmission in case of congestion in one or more
++                of the congestion groups relevant to this port.
++                Each call to this routine may add one or more congestion
++                groups to be considered relevant to this port.
++
++                May be used for Rx, or RX+OP ports only (depending on chip)
++
++ @Param[in]     ioc_fm_port_congestion_groups_t - A pointer to an array of
++                                                congestion group ids to consider.
++
++ @Return        0 on success; error code otherwise.
++*//***************************************************************************/
++#define FM_PORT_IOC_ADD_CONGESTION_GRPS    _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(34), ioc_fm_port_congestion_groups_t)
++
++/**************************************************************************//**
++ @Function      FM_PORT_RemoveCongestionGrps
++
++ @Description   This routine effects the corresponding Tx port. It should be
++                called when congestion groups were
++                defined for this port and are no longer relevant, or pause
++                frames transmitting is not required on their behalf.
++                Each call to this routine may remove one or more congestion
++                groups to be considered relevant to this port.
++
++                May be used for Rx, or RX+OP ports only (depending on chip)
++
++ @Param[in]     ioc_fm_port_congestion_groups_t - A pointer to an array of
++                                                congestion group ids to consider.
++
++ @Return        0 on success; error code otherwise.
++*//***************************************************************************/
++#define FM_PORT_IOC_REMOVE_CONGESTION_GRPS    _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(35), ioc_fm_port_congestion_groups_t)
++
++/**************************************************************************//**
++ @Function      FM_PORT_SetErrorsRoute
++
++ @Description   Errors selected for this routine will cause a frame with that error
++                to be enqueued to error queue.
++                Errors not selected for this routine will cause a frame with that error
++                to be enqueued to the one of the other port queues.
++                By default all errors are defined to be enqueued to error queue.
++                Errors that were configured to be discarded (at initialization)
++                may not be selected here.
++
++                May be used for Rx and offline parsing ports only
++
++ @Param[in]     ioc_fm_port_frame_err_select_t  A list of errors to enqueue to error queue
++
++ @Return        0 on success; error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++                (szbs001: How is it possible to have one function that needs to be
++                          called BEFORE FM_PORT_Init() implemented as an ioctl,
++                          which will ALWAYS be called AFTER the FM_PORT_Init()
++                          for that port!?!?!?!???!?!??!?!?)
++*//***************************************************************************/
++#define FM_PORT_IOC_SET_ERRORS_ROUTE   _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(4), ioc_fm_port_frame_err_select_t)
++
++
++/**************************************************************************//**
++ @Group         lnx_ioctl_FM_PORT_pcd_runtime_control_grp FM Port PCD Runtime Control Unit
++
++ @Description   FM Port PCD Runtime control unit API functions, definitions and enums.
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   A structure defining the KG scheme after the parser.
++                (Must match struct t_FmPcdKgSchemeSelect defined in fm_port_ext.h)
++
++                This is relevant only to change scheme selection mode - from
++                direct to indirect and vice versa, or when the scheme is selected directly,
++                to select the scheme id.
++
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_kg_scheme_select_t {
++    bool        direct;                     /**< TRUE to use 'scheme_id' directly, FALSE to use LCV.*/
++    void       *scheme_id;                  /**< Relevant for 'direct'=TRUE only.
++                                                 'scheme_id' selects the scheme after parser. */
++} ioc_fm_pcd_kg_scheme_select_t;
++
++/**************************************************************************//**
++ @Description   Scheme IDs structure
++                (Must match struct t_FmPcdPortSchemesParams defined in fm_port_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_port_schemes_params_t {
++    uint8_t     num_of_schemes;                         /**< Number of schemes for port to be bound to. */
++    void        *scheme_ids[FM_PCD_KG_NUM_OF_SCHEMES];  /**< Array of 'num_of_schemes' schemes for the
++                                                             port to be bound to */
++} ioc_fm_pcd_port_schemes_params_t;
++
++/**************************************************************************//**
++ @Description   A union for defining port protocol parameters for parser
++                (Must match union u_FmPcdHdrPrsOpts defined in fm_port_ext.h)
++*//***************************************************************************/
++typedef union ioc_fm_pcd_hdr_prs_opts_u {
++    /* MPLS */
++    struct {
++        bool                label_interpretation_enable;/**< When this bit is set, the last MPLS label will be
++                                                             interpreted as described in HW spec table. When the bit
++                                                             is cleared, the parser will advance to MPLS next parse */
++        ioc_net_header_type next_parse;                 /**< must be equal or higher than IPv4 */
++    } mpls_prs_options;
++
++    /* VLAN */
++    struct {
++        uint16_t            tag_protocol_id1;           /**< User defined Tag Protocol Identifier, to be recognized
++                                                             on VLAN TAG on top of 0x8100 and 0x88A8 */
++        uint16_t            tag_protocol_id2;           /**< User defined Tag Protocol Identifier, to be recognized
++                                                             on VLAN TAG on top of 0x8100 and 0x88A8 */
++    } vlan_prs_options;
++
++    /* PPP */
++    struct{
++        bool                enable_mtu_check;           /**< Check validity of MTU according to RFC2516 */
++    } pppoe_prs_options;
++
++    /* IPV6 */
++    struct {
++        bool                routing_hdr_disable;        /**< Disable routing header */
++    } ipv6_prs_options;
++
++    /* UDP */
++    struct {
++        bool                pad_ignore_checksum;        /**< TRUE to ignore pad in checksum */
++    } udp_prs_options;
++
++    /* TCP */
++    struct {
++        bool                pad_ignore_checksum;        /**< TRUE to ignore pad in checksum */
++    } tcp_prs_options;
++} ioc_fm_pcd_hdr_prs_opts_u;
++
++/**************************************************************************//**
++ @Description   A structure for defining each header for the parser
++                (must match struct t_FmPcdPrsAdditionalHdrParams defined in fm_port_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_prs_additional_hdr_params_t {
++    ioc_net_header_type         hdr;                /**< Selected header */
++    bool                        err_disable;        /**< TRUE to disable error indication */
++    bool                        soft_prs_enable;    /**< Enable jump to SW parser when this
++                                                         header is recognized by the HW parser. */
++    uint8_t                     index_per_hdr;      /**< Normally 0, if more than one sw parser
++                                                         attachments exists for the same header,
++                                                         (in the main sw parser code) use this
++                                                         index to distinguish between them. */
++    bool                        use_prs_opts;       /**< TRUE to use parser options. */
++    ioc_fm_pcd_hdr_prs_opts_u   prs_opts;           /**< A unuion according to header type,
++                                                         defining the parser options selected.*/
++} ioc_fm_pcd_prs_additional_hdr_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for defining port PCD parameters
++                (Must match t_FmPortPcdPrsParams defined in fm_port_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_port_pcd_prs_params_t {
++    uint8_t                         prs_res_priv_info;      /**< The private info provides a method of inserting
++                                                                 port information into the parser result. This information
++                                                                 may be extracted by KeyGen and be used for frames
++                                                                 distribution when a per-port distinction is required,
++                                                                 it may also be used as a port logical id for analyzing
++                                                                 incoming frames. */
++    uint8_t                         parsing_offset;         /**< Number of bytes from begining of packet to start parsing */
++    ioc_net_header_type             first_prs_hdr;          /**< The type of the first header axpected at 'parsing_offset' */
++    bool                            include_in_prs_statistics; /**< TRUE to include this port in the parser statistics */
++    uint8_t                         num_of_hdrs_with_additional_params;
++                                                            /**< Normally 0, some headers may get special parameters */
++    ioc_fm_pcd_prs_additional_hdr_params_t  additional_params[IOC_FM_PCD_PRS_NUM_OF_HDRS];
++                                                            /**< 'num_of_hdrs_with_additional_params' structures
++                                                                  additional parameters for each header that requires them */
++    bool                            set_vlan_tpid1;         /**< TRUE to configure user selection of Ethertype to
++                                                                 indicate a VLAN tag (in addition to the TPID values
++                                                                 0x8100 and 0x88A8). */
++    uint16_t                        vlan_tpid1;             /**< extra tag to use if set_vlan_tpid1=TRUE. */
++    bool                            set_vlan_tpid2;         /**< TRUE to configure user selection of Ethertype to
++                                                                 indicate a VLAN tag (in addition to the TPID values
++                                                                 0x8100 and 0x88A8). */
++    uint16_t                        vlan_tpid2;             /**< extra tag to use if set_vlan_tpid1=TRUE. */
++} ioc_fm_port_pcd_prs_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for defining coarse alassification parameters
++                (Must match t_FmPortPcdCcParams defined in fm_port_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_port_pcd_cc_params_t {
++    void                *cc_tree_id; /**< CC tree id */
++} ioc_fm_port_pcd_cc_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for defining keygen parameters
++                (Must match t_FmPortPcdKgParams defined in fm_port_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_port_pcd_kg_params_t {
++    uint8_t             num_of_schemes;                 /**< Number of schemes for port to be bound to. */
++    void               *scheme_ids[FM_PCD_KG_NUM_OF_SCHEMES];
++                                                        /**< Array of 'num_of_schemes' schemes for the
++                                                             port to be bound to */
++    bool                direct_scheme;                  /**< TRUE for going from parser to a specific scheme,
++                                                             regardless of parser result */
++    void               *direct_scheme_id;               /**< Scheme id, as returned by FM_PCD_KgSetScheme;
++                                                             relevant only if direct=TRUE. */
++} ioc_fm_port_pcd_kg_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for defining policer parameters
++                (Must match t_FmPortPcdPlcrParams defined in fm_port_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_port_pcd_plcr_params_t {
++    void                *plcr_profile_id;               /**< Selected profile handle;
++                                                             relevant in one of the following cases:
++                                                             e_IOC_FM_PORT_PCD_SUPPORT_PLCR_ONLY or
++                                                             e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR were selected,
++                                                             or if any flow uses a KG scheme where policer
++                                                                profile is not generated (bypass_plcr_profile_generation selected) */
++} ioc_fm_port_pcd_plcr_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for defining port PCD parameters
++                (Must match struct t_FmPortPcdParams defined in fm_port_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_port_pcd_params_t {
++    ioc_fm_port_pcd_support         pcd_support;    /**< Relevant for Rx and offline ports only.
++                                                         Describes the active PCD engines for this port. */
++    void                            *net_env_id;    /**< HL Unused in PLCR only mode */
++    ioc_fm_port_pcd_prs_params_t    *p_prs_params;  /**< Parser parameters for this port */
++    ioc_fm_port_pcd_cc_params_t     *p_cc_params;   /**< Coarse classification parameters for this port */
++    ioc_fm_port_pcd_kg_params_t     *p_kg_params;   /**< Keygen parameters for this port */
++    ioc_fm_port_pcd_plcr_params_t   *p_plcr_params; /**< Policer parameters for this port */
++    void                            *p_ip_reassembly_manip;/**< IP Reassembly manipulation */
++#if (DPAA_VERSION >= 11)
++    void                            *p_capwap_reassembly_manip;/**< CAPWAP Reassembly manipulation */
++#endif /* (DPAA_VERSION >= 11) */
++} ioc_fm_port_pcd_params_t;
++
++/**************************************************************************//**
++ @Description   A structure for defining the Parser starting point
++                (Must match struct t_FmPcdPrsStart defined in fm_port_ext.h)
++*//***************************************************************************/
++typedef struct ioc_fm_pcd_prs_start_t {
++    uint8_t             parsing_offset; /**< Number of bytes from begining of packet to
++                                             start parsing */
++    ioc_net_header_type first_prs_hdr;  /**< The type of the first header axpected at
++                                             'parsing_offset' */
++} ioc_fm_pcd_prs_start_t;
++
++
++/**************************************************************************//**
++ @Description   FQID parameters structure
++*//***************************************************************************/
++typedef struct ioc_fm_port_pcd_fqids_params_t {
++    uint32_t            num_fqids;  /**< Number of fqids to be allocated for the port */
++    uint8_t             alignment;  /**< Alignment required for this port */
++    uint32_t            base_fqid;  /**< output parameter - the base fqid */
++} ioc_fm_port_pcd_fqids_params_t;
++
++
++/**************************************************************************//**
++ @Function      FM_PORT_IOC_ALLOC_PCD_FQIDS
++
++ @Description   Allocates FQID's
++
++                May be used for Rx and offline parsing ports only
++
++ @Param[in,out] ioc_fm_port_pcd_fqids_params_t  Parameters for allocating FQID's
++
++ @Return        0 on success; error code otherwise.
++*//***************************************************************************/
++#define FM_PORT_IOC_ALLOC_PCD_FQIDS   _IOWR(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(19), ioc_fm_port_pcd_fqids_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PORT_IOC_FREE_PCD_FQIDS
++
++ @Description   Frees previously-allocated FQIDs
++
++                May be used for Rx and offline parsing ports only
++
++ @Param[in]           uint32_t        Base FQID of previously allocated range.
++
++ @Return        0 on success; error code otherwise.
++*//***************************************************************************/
++#define FM_PORT_IOC_FREE_PCD_FQIDS   _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(19), uint32_t)
++
++
++/**************************************************************************//**
++ @Function      FM_PORT_SetPCD
++
++ @Description   Calling this routine defines the port's PCD configuration.
++                It changes it from its default configuration which is PCD
++                disabled (BMI to BMI) and configures it according to the passed
++                parameters.
++
++                May be used for Rx and offline parsing ports only
++
++ @Param[in]     ioc_fm_port_pcd_params_t    A Structure of parameters defining the port's PCD
++                                            configuration.
++
++ @Return        0 on success; error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PORT_IOC_SET_PCD_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(20), ioc_compat_fm_port_pcd_params_t)
++#endif
++#define FM_PORT_IOC_SET_PCD _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(20), ioc_fm_port_pcd_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PORT_DeletePCD
++
++ @Description   Calling this routine releases the port's PCD configuration.
++                The port returns to its default configuration which is PCD
++                disabled (BMI to BMI) and all PCD configuration is removed.
++
++                May be used for Rx and offline parsing ports which are
++                in PCD mode only
++
++ @Return        0 on success; error code otherwise.
++*//***************************************************************************/
++#define FM_PORT_IOC_DELETE_PCD _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(21))
++
++/**************************************************************************//**
++ @Function      FM_PORT_AttachPCD
++
++ @Description   This routine may be called after FM_PORT_DetachPCD was called,
++                to return to the originally configured PCD support flow.
++                The couple of routines are used to allow PCD configuration changes
++                that demand that PCD will not be used while changes take place.
++
++                May be used for Rx and offline parsing ports which are
++                in PCD mode only
++
++ @Return        0 on success; error code otherwise.
++*//***************************************************************************/
++#define FM_PORT_IOC_ATTACH_PCD _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(23))
++
++/**************************************************************************//**
++ @Function      FM_PORT_DetachPCD
++
++ @Description   Calling this routine detaches the port from its PCD functionality.
++                The port returns to its default flow which is BMI to BMI.
++
++                May be used for Rx and offline parsing ports which are
++                in PCD mode only
++
++ @Return        0 on success; error code otherwise.
++*//***************************************************************************/
++#define FM_PORT_IOC_DETACH_PCD _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(22))
++
++/**************************************************************************//**
++ @Function      FM_PORT_PcdPlcrAllocProfiles
++
++ @Description   This routine may be called only for ports that use the Policer in
++                order to allocate private policer profiles.
++
++ @Param[in]     uint16_t       The number of required policer profiles
++
++ @Return        0 on success; error code otherwise.
++
++ @Cautions      Allowed before FM_PORT_SetPCD() only.
++*//***************************************************************************/
++#define FM_PORT_IOC_PCD_PLCR_ALLOC_PROFILES     _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(24), uint16_t)
++
++/**************************************************************************//**
++ @Function      FM_PORT_PcdPlcrFreeProfiles
++
++ @Description   This routine should be called for freeing private policer profiles.
++
++ @Return        0 on success; error code otherwise.
++
++ @Cautions      Allowed before FM_PORT_SetPCD() only.
++*//***************************************************************************/
++#define FM_PORT_IOC_PCD_PLCR_FREE_PROFILES     _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(25))
++
++/**************************************************************************//**
++ @Function      FM_PORT_PcdKgModifyInitialScheme
++
++ @Description   This routine may be called only for ports that use the keygen in
++                order to change the initial scheme frame should be routed to.
++                The change may be of a scheme id (in case of direct mode),
++                from direct to indirect, or from indirect to direct - specifying the scheme id.
++
++ @Param[in]     ioc_fm_pcd_kg_scheme_select_t   A structure of parameters for defining whether
++                                                a scheme is direct/indirect, and if direct - scheme id.
++
++ @Return        0 on success; error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(26), ioc_compat_fm_pcd_kg_scheme_select_t)
++#endif
++#define FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(26), ioc_fm_pcd_kg_scheme_select_t)
++
++/**************************************************************************//**
++ @Function      FM_PORT_PcdPlcrModifyInitialProfile
++
++ @Description   This routine may be called for ports with flows
++                e_IOC_FM_PCD_SUPPORT_PLCR_ONLY or e_IOC_FM_PCD_SUPPORT_PRS_AND_PLCR  only,
++                to change the initial Policer profile frame should be routed to.
++                The change may be of a profile and/or absolute/direct mode selection.
++
++ @Param[in]     ioc_fm_obj_t       Policer profile Id as returned from FM_PCD_PlcrSetProfile.
++
++ @Return        0 on success; error code otherwise.
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(27), ioc_compat_fm_obj_t)
++#endif
++#define FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(27), ioc_fm_obj_t)
++
++/**************************************************************************//**
++ @Function      FM_PORT_PcdCcModifyTree
++
++ @Description   This routine may be called to change this port connection to
++                a pre-initializes coarse classification Tree.
++
++ @Param[in]     ioc_fm_obj_t    Id of new coarse classification tree selected for this port.
++
++ @Return        0 on success; error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_SetPCD() and FM_PORT_DetachPCD()
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PORT_IOC_PCD_CC_MODIFY_TREE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(28), ioc_compat_fm_obj_t)
++#endif
++#define FM_PORT_IOC_PCD_CC_MODIFY_TREE _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(28), ioc_fm_obj_t)
++
++/**************************************************************************//**
++ @Function      FM_PORT_PcdKgBindSchemes
++
++ @Description   These routines may be called for modifying the binding of ports
++                to schemes. The scheme itself is not added,
++                just this specific port starts using it.
++
++ @Param[in]     ioc_fm_pcd_port_schemes_params_t    Schemes parameters structre
++
++ @Return        0 on success; error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_SetPCD().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PORT_IOC_PCD_KG_BIND_SCHEMES_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(30), ioc_compat_fm_pcd_port_schemes_params_t)
++#endif
++#define FM_PORT_IOC_PCD_KG_BIND_SCHEMES _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(30), ioc_fm_pcd_port_schemes_params_t)
++
++/**************************************************************************//**
++ @Function      FM_PORT_PcdKgUnbindSchemes
++
++ @Description   These routines may be called for modifying the binding of ports
++                to schemes. The scheme itself is not removed or invalidated,
++                just this specific port stops using it.
++
++ @Param[in]     ioc_fm_pcd_port_schemes_params_t    Schemes parameters structre
++
++ @Return        0 on success; error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_SetPCD().
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(31), ioc_compat_fm_pcd_port_schemes_params_t)
++#endif
++#define FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(31), ioc_fm_pcd_port_schemes_params_t)
++
++typedef struct ioc_fm_port_mac_addr_params_t {
++    uint8_t addr[ENET_NUM_OCTETS_PER_ADDRESS];
++} ioc_fm_port_mac_addr_params_t;
++
++/**************************************************************************//**
++ @Function      FM_MAC_AddHashMacAddr
++
++ @Description   Add an Address to the hash table. This is for filter purpose only.
++
++ @Param[in]     ioc_fm_port_mac_addr_params_t - Ethernet Mac address
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init(). It is a filter only address.
++ @Cautions      Some address need to be filtered out in upper FM blocks.
++*//***************************************************************************/
++#define FM_PORT_IOC_ADD_RX_HASH_MAC_ADDR   _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(36), ioc_fm_port_mac_addr_params_t)
++
++/**************************************************************************//**
++ @Function      FM_MAC_RemoveHashMacAddr
++
++ @Description   Delete an Address to the hash table. This is for filter purpose only.
++
++ @Param[in]     ioc_fm_port_mac_addr_params_t - Ethernet Mac address
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init().
++*//***************************************************************************/
++#define FM_PORT_IOC_REMOVE_RX_HASH_MAC_ADDR   _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(37), ioc_fm_port_mac_addr_params_t)
++
++typedef struct ioc_fm_port_tx_pause_frames_params_t {
++    uint8_t  priority;
++    uint16_t pause_time;
++    uint16_t thresh_time;
++} ioc_fm_port_tx_pause_frames_params_t;
++
++/**************************************************************************//**
++ @Function      FM_MAC_SetTxPauseFrames
++
++ @Description   Enable/Disable transmission of Pause-Frames.
++                The routine changes the default configuration:
++                pause-time - [0xf000]
++                threshold-time - [0]
++
++ @Param[in]     ioc_fm_port_tx_pause_frames_params_t A structure holding the required parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_MAC_Init().
++                PFC is supported only on new mEMAC; i.e. in MACs that don't have
++                PFC support (10G-MAC and dTSEC), user should use 'FM_MAC_NO_PFC'
++                in the 'priority' field.
++*//***************************************************************************/
++#define FM_PORT_IOC_SET_TX_PAUSE_FRAMES       _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(40), ioc_fm_port_tx_pause_frames_params_t)
++
++typedef struct ioc_fm_port_mac_statistics_t {
++    /* RMON */
++        uint64_t  e_stat_pkts_64;            /**< r-10G tr-DT 64 byte frame counter */
++        uint64_t  e_stat_pkts_65_to_127;     /**< r-10G 65 to 127 byte frame counter */
++        uint64_t  e_stat_pkts_128_to_255;    /**< r-10G 128 to 255 byte frame counter */
++        uint64_t  e_stat_pkts_256_to_511;    /**< r-10G 256 to 511 byte frame counter */
++        uint64_t  e_stat_pkts_512_to_1023;   /**< r-10G 512 to 1023 byte frame counter */
++        uint64_t  e_stat_pkts_1024_to_1518;  /**< r-10G 1024 to 1518 byte frame counter */
++        uint64_t  e_stat_pkts_1519_to_1522;  /**< r-10G 1519 to 1522 byte good frame count */
++    /* */
++        uint64_t  e_stat_fragments;          /**< Total number of packets that were less than 64 octets long with a wrong CRC.*/
++        uint64_t  e_stat_jabbers;            /**< Total number of packets longer than valid maximum length octets */
++        uint64_t  e_stat_drop_events;        /**< number of dropped packets due to internal errors of the MAC Client (during recieve). */
++        uint64_t  e_stat_CRC_align_errors;   /**< Incremented when frames of correct length but with CRC error are received.*/
++        uint64_t  e_stat_undersize_pkts;     /**< Incremented for frames under 64 bytes with a valid FCS and otherwise well formed;
++                                                This count does not include range length errors */
++        uint64_t  e_stat_oversize_pkts;      /**< Incremented for frames which exceed 1518 (non VLAN) or 1522 (VLAN) and contains
++                                                a valid FCS and otherwise well formed */
++    /* Pause */
++        uint64_t  te_stat_pause;             /**< Pause MAC Control received */
++        uint64_t  re_stat_pause;             /**< Pause MAC Control sent */
++    /* MIB II */
++        uint64_t  if_in_octets;              /**< Total number of byte received. */
++        uint64_t  if_in_pkts;                /**< Total number of packets received.*/
++        uint64_t  if_in_ucast_pkts;          /**< Total number of unicast frame received;
++                                             NOTE: this counter is not supported on dTSEC MAC */
++        uint64_t  if_in_mcast_pkts;          /**< Total number of multicast frame received*/
++        uint64_t  if_in_bcast_pkts;          /**< Total number of broadcast frame received */
++        uint64_t  if_in_discards;            /**< Frames received, but discarded due to problems within the MAC RX. */
++        uint64_t  if_in_errors;              /**< Number of frames received with error:
++                                                   - FIFO Overflow Error
++                                                   - CRC Error
++                                                   - Frame Too Long Error
++                                                   - Alignment Error
++                                                   - The dedicated Error Code (0xfe, not a code error) was received */
++        uint64_t  if_out_octets;             /**< Total number of byte sent. */
++        uint64_t  if_out_pkts;               /**< Total number of packets sent .*/
++        uint64_t  if_out_ucast_pkts;         /**< Total number of unicast frame sent;
++                                             NOTE: this counter is not supported on dTSEC MAC */
++        uint64_t  if_out_mcast_pkts;         /**< Total number of multicast frame sent */
++        uint64_t  if_out_bcast_pkts;         /**< Total number of multicast frame sent */
++        uint64_t  if_out_discards;           /**< Frames received, but discarded due to problems within the MAC TX N/A!.*/
++        uint64_t  if_out_errors;             /**< Number of frames transmitted with error:
++                                                   - FIFO Overflow Error
++                                                   - FIFO Underflow Error
++                                                   - Other */
++} ioc_fm_port_mac_statistics_t;
++
++/**************************************************************************//**
++ @Function      FM_MAC_GetStatistics
++
++ @Description   get all MAC statistics counters
++
++ @Param[out]    ioc_fm_port_mac_statistics_t    A structure holding the statistics
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++#define FM_PORT_IOC_GET_MAC_STATISTICS        _IOR(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(41), ioc_fm_port_mac_statistics_t)
++
++/**************************************************************************//**
++ @Function      FM_PORT_ConfigBufferPrefixContent
++
++ @Description   Defines the structure, size and content of the application buffer.
++                The prefix will
++                In Tx ports, if 'passPrsResult', the application
++                should set a value to their offsets in the prefix of
++                the FM will save the first 'privDataSize', than,
++                depending on 'passPrsResult' and 'passTimeStamp', copy parse result
++                and timeStamp, and the packet itself (in this order), to the
++                application buffer, and to offset.
++                Calling this routine changes the buffer margins definitions
++                in the internal driver data base from its default
++                configuration: Data size:  [DEFAULT_FM_SP_bufferPrefixContent_privDataSize]
++                               Pass Parser result: [DEFAULT_FM_SP_bufferPrefixContent_passPrsResult].
++                               Pass timestamp: [DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp].
++
++                May be used for all ports
++
++ @Param[in]     ioc_fm_buffer_prefix_content_t  A structure holding the required parameters.
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Config() and before FM_PORT_Init().
++*//***************************************************************************/
++#define FM_PORT_IOC_CONFIG_BUFFER_PREFIX_CONTENT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(39), ioc_fm_buffer_prefix_content_t)
++
++#if (DPAA_VERSION >= 11)
++typedef struct ioc_fm_port_vsp_alloc_params_t {
++    uint8_t     num_of_profiles;          /**< Number of Virtual Storage Profiles */
++    uint8_t     dflt_relative_id;         /**< The default Virtual-Storage-Profile-id dedicated to Rx/OP port
++                                             The same default Virtual-Storage-Profile-id will be for coupled Tx port
++                                             if relevant function called for Rx port */
++    void    *p_fm_tx_port;             /**< Handle to coupled Tx Port; not relevant for OP port. */
++}ioc_fm_port_vsp_alloc_params_t;
++
++/**************************************************************************//**
++ @Function      FM_PORT_VSPAlloc
++
++ @Description   This routine allocated VSPs per port and forces the port to work
++                in VSP mode. Note that the port is initialized by default with the
++                physical-storage-profile only.
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[in]     p_Params    A structure of parameters for allocation VSP's per port
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init(), and before FM_PORT_SetPCD()
++                and also before FM_PORT_Enable() (i.e. the port should be disabled).
++*//***************************************************************************/
++#if defined(CONFIG_COMPAT)
++#define FM_PORT_IOC_VSP_ALLOC_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(38), ioc_compat_fm_port_vsp_alloc_params_t)
++#endif
++#define FM_PORT_IOC_VSP_ALLOC _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(38), ioc_fm_port_vsp_alloc_params_t)
++#endif /* (DPAA_VERSION >= 11) */
++
++/**************************************************************************//**
++ @Function      FM_PORT_GetBmiCounters
++
++ @Description   Read port's BMI stat counters and place them into
++                a designated structure of counters.
++
++ @Param[in]     h_FmPort    A handle to a FM Port module.
++ @Param[out]    p_BmiStats  counters structure
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_PORT_Init().
++*//***************************************************************************/
++
++#define FM_PORT_IOC_GET_BMI_COUNTERS _IOR(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(42), ioc_fm_port_bmi_stats_t)
++
++
++/** @} */ /* end of lnx_ioctl_FM_PORT_pcd_runtime_control_grp group */
++/** @} */ /* end of lnx_ioctl_FM_PORT_runtime_control_grp group */
++
++/** @} */ /* end of lnx_ioctl_FM_PORT_grp group */
++/** @} */ /* end of lnx_ioctl_FM_grp group */
++#endif /* __FM_PORT_IOCTLS_H */
+--- /dev/null
++++ b/include/uapi/linux/fmd/Peripherals/fm_test_ioctls.h
+@@ -0,0 +1,208 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**************************************************************************//**
++ @File          fm_test_ioctls.h
++
++ @Description   FM Char device ioctls
++*//***************************************************************************/
++#ifndef __FM_TEST_IOCTLS_H
++#define __FM_TEST_IOCTLS_H
++
++#include "ioctls.h"
++
++
++/**************************************************************************//**
++ @Group         lnx_ioctl_FMT_grp Frame Manager Test Linux IOCTL API
++
++ @Description   FM-Test Linux ioctls definitions and enums
++
++ @{
++*//***************************************************************************/
++
++#define IOC_FMT_MAX_NUM_OF_PORTS        26
++
++/**************************************************************************//**
++ @Collection    TEST Parameters
++*//***************************************************************************/
++/**************************************************************************//**
++  @Description: Name of the FM-Test chardev
++*//***************************************************************************/
++#define DEV_FM_TEST_NAME                "fm-test-port"
++
++#define DEV_FM_TEST_PORTS_MINOR_BASE    0
++#define DEV_FM_TEST_MAX_MINORS          (DEV_FM_TEST_PORTS_MINOR_BASE + IOC_FMT_MAX_NUM_OF_PORTS)
++
++#define FMT_PORT_IOC_NUM(n)             n
++/* @} */
++
++/**************************************************************************//**
++ @Group         lnx_ioctl_FMT_lib_grp FM-Test library
++
++ @Description   TODO
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   TODO
++*//***************************************************************************/
++typedef uint8_t ioc_fmt_xxx_t;
++
++#define FM_PRS_MAX 32
++#define FM_TIME_STAMP_MAX 8
++
++/**************************************************************************//**
++ @Description   FM Port buffer content description
++*//***************************************************************************/
++typedef struct ioc_fmt_buff_context_t {
++    void            *p_user_priv;
++    uint8_t         fm_prs_res[FM_PRS_MAX];
++    uint8_t         fm_time_stamp[FM_TIME_STAMP_MAX];
++} ioc_fmt_buff_context_t;
++
++#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
++typedef struct ioc_fmt_compat_buff_context_t {
++    compat_uptr_t         p_user_priv;
++    uint8_t               fm_prs_res[FM_PRS_MAX];
++    uint8_t               fm_time_stamp[FM_TIME_STAMP_MAX];
++} ioc_fmt_compat_buff_context_t;
++#endif
++
++/**************************************************************************//**
++ @Description   Buffer descriptor
++*//***************************************************************************/
++typedef struct ioc_fmt_buff_desc_t {
++    uint32_t               qid;
++    void                   *p_data;
++    uint32_t               size;
++    uint32_t               status;
++    ioc_fmt_buff_context_t buff_context;
++} ioc_fmt_buff_desc_t;
++
++#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
++typedef struct ioc_fmt_compat_buff_desc_t {
++    uint32_t                qid;
++    compat_uptr_t           p_data;
++    uint32_t                size;
++    uint32_t                status;
++    ioc_fmt_compat_buff_context_t buff_context;
++} ioc_fmt_compat_buff_desc_t;
++#endif
++
++/**************************************************************************//**
++ @Group         lnx_ioctl_FMT_runtime_control_grp FM-Test Runtime Control Unit
++
++ @Description   TODO
++ @{
++*//***************************************************************************/
++
++/** @} */ /* end of lnx_ioctl_FMT_runtime_control_grp group */
++
++
++/**************************************************************************//**
++ @Group         lnx_ioctl_FMTP_lib_grp FM-Port-Test library
++
++ @Description   TODO
++
++ @{
++*//***************************************************************************/
++
++/**************************************************************************//**
++ @Description   FM-Test FM port type
++*//***************************************************************************/
++typedef enum ioc_fmt_port_type {
++    e_IOC_FMT_PORT_T_RXTX,  /**< Standard port */
++    e_IOC_FMT_PORT_T_OP,    /**< Offline-parsing port */
++} ioc_fmt_port_type;
++
++/**************************************************************************//**
++ @Description   TODO
++*//***************************************************************************/
++typedef struct ioc_fmt_port_param_t {
++    uint8_t             fm_id;
++    ioc_fmt_port_type   fm_port_type;
++    uint8_t             fm_port_id;
++    uint32_t            num_tx_queues;
++} ioc_fmt_port_param_t;
++
++
++/**************************************************************************//**
++ @Function      FMT_PORT_IOC_INIT
++
++ @Description   TODO
++
++ @Param[in]     ioc_fmt_port_param_t  TODO
++
++ @Cautions      Allowed only after the FM equivalent port is already initialized.
++*//***************************************************************************/
++#define FMT_PORT_IOC_INIT           _IOW(FMT_IOC_TYPE_BASE, FMT_PORT_IOC_NUM(0), ioc_fmt_port_param_t)
++
++/**************************************************************************//**
++ @Function      FMT_PORT_IOC_SET_DIAG_MODE
++
++ @Description   TODO
++
++ @Param[in]     ioc_diag_mode  TODO
++
++ @Cautions      Allowed only following FMT_PORT_IOC_INIT().
++*//***************************************************************************/
++#define FMT_PORT_IOC_SET_DIAG_MODE  _IOW(FMT_IOC_TYPE_BASE, FMT_PORT_IOC_NUM(1), ioc_diag_mode)
++
++/**************************************************************************//**
++ @Function      FMT_PORT_IOC_SET_IP_HEADER_MANIP
++
++ @Description   Set IP header manipulations for this port.
++
++ @Param[in]     int     1 to enable; 0 to disable
++
++ @Cautions      Allowed only following FMT_PORT_IOC_INIT().
++*//***************************************************************************/
++#define FMT_PORT_IOC_SET_IP_HEADER_MANIP  _IOW(FMT_IOC_TYPE_BASE, FMT_PORT_IOC_NUM(2), int)
++
++/**************************************************************************//**
++ @Function      FMT_PORT_IOC_SET_DPAECHO_MODE
++
++ @Description   Set DPA in echo mode - all frame are sent back.
++
++ @Param[in]     int     1 to enable; 0 to disable
++
++ @Cautions      Allowed only following FMT_PORT_IOC_INIT().
++*//***************************************************************************/
++#define FMT_PORT_IOC_SET_DPAECHO_MODE     _IOW(FMT_IOC_TYPE_BASE, FMT_PORT_IOC_NUM(3), int)
++
++/** @} */ /* end of lnx_ioctl_FMTP_lib_grp group */
++/** @} */ /* end of lnx_ioctl_FMT_lib_grp group */
++/** @} */ /* end of lnx_ioctl_FMT_grp */
++
++
++#endif /* __FM_TEST_IOCTLS_H */
+--- /dev/null
++++ b/include/uapi/linux/fmd/integrations/Kbuild
+@@ -0,0 +1 @@
++header-y += integration_ioctls.h
+--- /dev/null
++++ b/include/uapi/linux/fmd/integrations/integration_ioctls.h
+@@ -0,0 +1,56 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**************************************************************************//**
++ @File          integration_ioctls.h
++
++ @Description   External header file for Integration unit routines.
++*//***************************************************************************/
++
++#ifndef __INTG_IOCTLS_H
++#define __INTG_IOCTLS_H
++
++
++#define FM_IOC_TYPE_BASE            (NCSW_IOC_TYPE_BASE+1)
++#define FMT_IOC_TYPE_BASE           (NCSW_IOC_TYPE_BASE+3)
++
++/*#define FM_IOCTL_DBG*/
++
++#if defined(FM_IOCTL_DBG)
++    #define _fm_ioctl_dbg(format, arg...) \
++        printk("fm ioctl [%s:%u](cpu:%u) - " format, \
++            __func__, __LINE__, smp_processor_id(), ##arg)
++#else
++#   define _fm_ioctl_dbg(arg...)
++#endif
++
++#endif /* __INTG_IOCTLS_H */
+--- /dev/null
++++ b/include/uapi/linux/fmd/ioctls.h
+@@ -0,0 +1,96 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/**************************************************************************//**
++ @File          ioctls.h
++
++ @Description   Structures and definitions for Command Relay Ioctls
++*//***************************************************************************/
++
++#ifndef __IOCTLS_H__
++#define __IOCTLS_H__
++
++#include <asm/ioctl.h>
++
++#include "integration_ioctls.h"
++
++
++/**************************************************************************//**
++ @Group         lnx_ioctl_ncsw_grp    NetCommSw Linux User-Space (IOCTL) API
++ @{
++*//***************************************************************************/
++
++#define NCSW_IOC_TYPE_BASE          0xe0    /**< defines the IOCTL type for all
++                                                 the NCSW Linux module commands */
++
++
++/**************************************************************************//**
++ @Description   IOCTL Memory allocation types.
++*//***************************************************************************/
++typedef enum ioc_mem_type {
++    e_IOC_MEM_INVALID      = 0x00000000,  /**< Invalid memory type (error) */
++    e_IOC_MEM_CACHABLE_SYS = 0x00000001,  /**< Primary DDR, cacheable segment */
++    e_IOC_MEM_NOCACHE_SYS  = 0x00000004,  /**< Primary DDR, non-cacheable segment */
++    e_IOC_MEM_SECONDARY    = 0x00000002,  /**< Either secondary DDR or SDRAM */
++    e_IOC_MEM_PRAM         = 0x00000008   /**< Multi-user RAM identifier */
++} ioc_mem_type;
++
++/**************************************************************************//**
++ @Description   Enumeration (bit flags) of communication modes (Transmit,
++                receive or both).
++*//***************************************************************************/
++typedef enum ioc_comm_mode {
++      e_IOC_COMM_MODE_NONE         = 0  /**< No transmit/receive communication */
++    , e_IOC_COMM_MODE_RX           = 1  /**< Only receive communication */
++    , e_IOC_COMM_MODE_TX           = 2  /**< Only transmit communication */
++    , e_IOC_COMM_MODE_RX_AND_TX    = 3  /**< Both transmit and receive communication */
++} ioc_comm_mode;
++
++/**************************************************************************//**
++ @Description   General Diagnostic Mode
++*//***************************************************************************/
++typedef enum ioc_diag_mode
++{
++    e_IOC_DIAG_MODE_NONE = 0,
++    e_IOC_DIAG_MODE_CTRL_LOOPBACK,      /**< loopback in the controller; E.g. MAC, TDM, etc. */
++    e_IOC_DIAG_MODE_CHIP_LOOPBACK,      /**< loopback in the chip but not in controller;
++                                         E.g. IO-pins, SerDes, etc. */
++    e_IOC_DIAG_MODE_PHY_LOOPBACK,       /**< loopback in the external PHY */
++    e_IOC_DIAG_MODE_LINE_LOOPBACK,      /**< loopback in the external line */
++    e_IOC_DIAG_MODE_CTRL_ECHO,          /**< */
++    e_IOC_DIAG_MODE_PHY_ECHO            /**< */
++} ioc_diag_mode;
++
++/** @} */ /* end of lnx_ioctl_ncsw_grp */
++
++
++#endif /* __IOCTLS_H__ */
+--- /dev/null
++++ b/include/uapi/linux/fmd/net_ioctls.h
+@@ -0,0 +1,430 @@
++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *       names of its contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/**************************************************************************//**
++ @File          net_ioctls.h
++
++ @Description   This file contains common and general netcomm headers definitions.
++*//***************************************************************************/
++#ifndef __NET_IOCTLS_H
++#define __NET_IOCTLS_H
++
++#include "ioctls.h"
++
++
++typedef uint8_t ioc_header_field_ppp_t;
++
++#define IOC_NET_HEADER_FIELD_PPP_PID                        (1)
++#define IOC_NET_HEADER_FIELD_PPP_COMPRESSED                 (IOC_NET_HEADER_FIELD_PPP_PID << 1)
++#define IOC_NET_HEADER_FIELD_PPP_ALL_FIELDS                 ((IOC_NET_HEADER_FIELD_PPP_PID << 2) - 1)
++
++
++typedef uint8_t ioc_header_field_pppoe_t;
++
++#define IOC_NET_HEADER_FIELD_PPPoE_VER                      (1)
++#define IOC_NET_HEADER_FIELD_PPPoE_TYPE                     (IOC_NET_HEADER_FIELD_PPPoE_VER << 1)
++#define IOC_NET_HEADER_FIELD_PPPoE_CODE                     (IOC_NET_HEADER_FIELD_PPPoE_VER << 2)
++#define IOC_NET_HEADER_FIELD_PPPoE_SID                      (IOC_NET_HEADER_FIELD_PPPoE_VER << 3)
++#define IOC_NET_HEADER_FIELD_PPPoE_LEN                      (IOC_NET_HEADER_FIELD_PPPoE_VER << 4)
++#define IOC_NET_HEADER_FIELD_PPPoE_SESSION                  (IOC_NET_HEADER_FIELD_PPPoE_VER << 5)
++#define IOC_NET_HEADER_FIELD_PPPoE_PID                      (IOC_NET_HEADER_FIELD_PPPoE_VER << 6)
++#define IOC_NET_HEADER_FIELD_PPPoE_ALL_FIELDS               ((IOC_NET_HEADER_FIELD_PPPoE_VER << 7) - 1)
++
++#define IOC_NET_HEADER_FIELD_PPPMUX_PID                     (1)
++#define IOC_NET_HEADER_FIELD_PPPMUX_CKSUM                   (IOC_NET_HEADER_FIELD_PPPMUX_PID << 1)
++#define IOC_NET_HEADER_FIELD_PPPMUX_COMPRESSED              (IOC_NET_HEADER_FIELD_PPPMUX_PID << 2)
++#define IOC_NET_HEADER_FIELD_PPPMUX_ALL_FIELDS              ((IOC_NET_HEADER_FIELD_PPPMUX_PID << 3) - 1)
++
++#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF            (1)
++#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_LXT            (IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 1)
++#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_LEN            (IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 2)
++#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PID            (IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 3)
++#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_USE_PID        (IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 4)
++#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_ALL_FIELDS     ((IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 5) - 1)
++
++
++typedef uint8_t ioc_header_field_eth_t;
++
++#define IOC_NET_HEADER_FIELD_ETH_DA                         (1)
++#define IOC_NET_HEADER_FIELD_ETH_SA                         (IOC_NET_HEADER_FIELD_ETH_DA << 1)
++#define IOC_NET_HEADER_FIELD_ETH_LENGTH                     (IOC_NET_HEADER_FIELD_ETH_DA << 2)
++#define IOC_NET_HEADER_FIELD_ETH_TYPE                       (IOC_NET_HEADER_FIELD_ETH_DA << 3)
++#define IOC_NET_HEADER_FIELD_ETH_FINAL_CKSUM                (IOC_NET_HEADER_FIELD_ETH_DA << 4)
++#define IOC_NET_HEADER_FIELD_ETH_PADDING                    (IOC_NET_HEADER_FIELD_ETH_DA << 5)
++#define IOC_NET_HEADER_FIELD_ETH_ALL_FIELDS                 ((IOC_NET_HEADER_FIELD_ETH_DA << 6) - 1)
++
++#define IOC_NET_HEADER_FIELD_ETH_ADDR_SIZE                 6
++
++typedef uint16_t ioc_header_field_ip_t;
++
++#define IOC_NET_HEADER_FIELD_IP_VER                         (1)
++#define IOC_NET_HEADER_FIELD_IP_DSCP                        (IOC_NET_HEADER_FIELD_IP_VER << 2)
++#define IOC_NET_HEADER_FIELD_IP_ECN                         (IOC_NET_HEADER_FIELD_IP_VER << 3)
++#define IOC_NET_HEADER_FIELD_IP_PROTO                       (IOC_NET_HEADER_FIELD_IP_VER << 4)
++
++#define IOC_NET_HEADER_FIELD_IP_PROTO_SIZE                  1
++
++typedef uint16_t ioc_header_field_ipv4_t;
++
++#define IOC_NET_HEADER_FIELD_IPv4_VER                       (1)
++#define IOC_NET_HEADER_FIELD_IPv4_HDR_LEN                   (IOC_NET_HEADER_FIELD_IPv4_VER << 1)
++#define IOC_NET_HEADER_FIELD_IPv4_TOS                       (IOC_NET_HEADER_FIELD_IPv4_VER << 2)
++#define IOC_NET_HEADER_FIELD_IPv4_TOTAL_LEN                 (IOC_NET_HEADER_FIELD_IPv4_VER << 3)
++#define IOC_NET_HEADER_FIELD_IPv4_ID                        (IOC_NET_HEADER_FIELD_IPv4_VER << 4)
++#define IOC_NET_HEADER_FIELD_IPv4_FLAG_D                    (IOC_NET_HEADER_FIELD_IPv4_VER << 5)
++#define IOC_NET_HEADER_FIELD_IPv4_FLAG_M                    (IOC_NET_HEADER_FIELD_IPv4_VER << 6)
++#define IOC_NET_HEADER_FIELD_IPv4_OFFSET                    (IOC_NET_HEADER_FIELD_IPv4_VER << 7)
++#define IOC_NET_HEADER_FIELD_IPv4_TTL                       (IOC_NET_HEADER_FIELD_IPv4_VER << 8)
++#define IOC_NET_HEADER_FIELD_IPv4_PROTO                     (IOC_NET_HEADER_FIELD_IPv4_VER << 9)
++#define IOC_NET_HEADER_FIELD_IPv4_CKSUM                     (IOC_NET_HEADER_FIELD_IPv4_VER << 10)
++#define IOC_NET_HEADER_FIELD_IPv4_SRC_IP                    (IOC_NET_HEADER_FIELD_IPv4_VER << 11)
++#define IOC_NET_HEADER_FIELD_IPv4_DST_IP                    (IOC_NET_HEADER_FIELD_IPv4_VER << 12)
++#define IOC_NET_HEADER_FIELD_IPv4_OPTS                      (IOC_NET_HEADER_FIELD_IPv4_VER << 13)
++#define IOC_NET_HEADER_FIELD_IPv4_OPTS_COUNT                (IOC_NET_HEADER_FIELD_IPv4_VER << 14)
++#define IOC_NET_HEADER_FIELD_IPv4_ALL_FIELDS                ((IOC_NET_HEADER_FIELD_IPv4_VER << 15) - 1)
++
++#define IOC_NET_HEADER_FIELD_IPv4_ADDR_SIZE                 4
++#define IOC_NET_HEADER_FIELD_IPv4_PROTO_SIZE                1
++
++
++typedef uint8_t ioc_header_field_ipv6_t;
++
++#define IOC_NET_HEADER_FIELD_IPv6_VER                       (1)
++#define IOC_NET_HEADER_FIELD_IPv6_TC                        (IOC_NET_HEADER_FIELD_IPv6_VER << 1)
++#define IOC_NET_HEADER_FIELD_IPv6_SRC_IP                    (IOC_NET_HEADER_FIELD_IPv6_VER << 2)
++#define IOC_NET_HEADER_FIELD_IPv6_DST_IP                    (IOC_NET_HEADER_FIELD_IPv6_VER << 3)
++#define IOC_NET_HEADER_FIELD_IPv6_NEXT_HDR                  (IOC_NET_HEADER_FIELD_IPv6_VER << 4)
++#define IOC_NET_HEADER_FIELD_IPv6_FL                        (IOC_NET_HEADER_FIELD_IPv6_VER << 5)
++#define IOC_NET_HEADER_FIELD_IPv6_HOP_LIMIT                 (IOC_NET_HEADER_FIELD_IPv6_VER << 6)
++#define IOC_NET_HEADER_FIELD_IPv6_ALL_FIELDS                ((IOC_NET_HEADER_FIELD_IPv6_VER << 7) - 1)
++
++#define IOC_NET_HEADER_FIELD_IPv6_ADDR_SIZE                 16
++#define IOC_NET_HEADER_FIELD_IPv6_NEXT_HDR_SIZE             1
++
++#define IOC_NET_HEADER_FIELD_ICMP_TYPE                      (1)
++#define IOC_NET_HEADER_FIELD_ICMP_CODE                      (IOC_NET_HEADER_FIELD_ICMP_TYPE << 1)
++#define IOC_NET_HEADER_FIELD_ICMP_CKSUM                     (IOC_NET_HEADER_FIELD_ICMP_TYPE << 2)
++#define IOC_NET_HEADER_FIELD_ICMP_ID                        (IOC_NET_HEADER_FIELD_ICMP_TYPE << 3)
++#define IOC_NET_HEADER_FIELD_ICMP_SQ_NUM                    (IOC_NET_HEADER_FIELD_ICMP_TYPE << 4)
++#define IOC_NET_HEADER_FIELD_ICMP_ALL_FIELDS                ((IOC_NET_HEADER_FIELD_ICMP_TYPE << 5) - 1)
++
++#define IOC_NET_HEADER_FIELD_ICMP_CODE_SIZE                 1
++#define IOC_NET_HEADER_FIELD_ICMP_TYPE_SIZE                 1
++
++#define IOC_NET_HEADER_FIELD_IGMP_VERSION                   (1)
++#define IOC_NET_HEADER_FIELD_IGMP_TYPE                      (IOC_NET_HEADER_FIELD_IGMP_VERSION << 1)
++#define IOC_NET_HEADER_FIELD_IGMP_CKSUM                     (IOC_NET_HEADER_FIELD_IGMP_VERSION << 2)
++#define IOC_NET_HEADER_FIELD_IGMP_DATA                      (IOC_NET_HEADER_FIELD_IGMP_VERSION << 3)
++#define IOC_NET_HEADER_FIELD_IGMP_ALL_FIELDS                ((IOC_NET_HEADER_FIELD_IGMP_VERSION << 4) - 1)
++
++
++typedef uint16_t ioc_header_field_tcp_t;
++
++#define IOC_NET_HEADER_FIELD_TCP_PORT_SRC                   (1)
++#define IOC_NET_HEADER_FIELD_TCP_PORT_DST                   (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 1)
++#define IOC_NET_HEADER_FIELD_TCP_SEQ                        (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 2)
++#define IOC_NET_HEADER_FIELD_TCP_ACK                        (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 3)
++#define IOC_NET_HEADER_FIELD_TCP_OFFSET                     (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 4)
++#define IOC_NET_HEADER_FIELD_TCP_FLAGS                      (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 5)
++#define IOC_NET_HEADER_FIELD_TCP_WINDOW                     (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 6)
++#define IOC_NET_HEADER_FIELD_TCP_CKSUM                      (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 7)
++#define IOC_NET_HEADER_FIELD_TCP_URGPTR                     (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 8)
++#define IOC_NET_HEADER_FIELD_TCP_OPTS                       (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 9)
++#define IOC_NET_HEADER_FIELD_TCP_OPTS_COUNT                 (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 10)
++#define IOC_NET_HEADER_FIELD_TCP_ALL_FIELDS                 ((IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 11) - 1)
++
++#define IOC_NET_HEADER_FIELD_TCP_PORT_SIZE                  2
++
++
++typedef uint8_t ioc_header_field_sctp_t;
++
++#define IOC_NET_HEADER_FIELD_SCTP_PORT_SRC                  (1)
++#define IOC_NET_HEADER_FIELD_SCTP_PORT_DST                  (IOC_NET_HEADER_FIELD_SCTP_PORT_SRC << 1)
++#define IOC_NET_HEADER_FIELD_SCTP_VER_TAG                   (IOC_NET_HEADER_FIELD_SCTP_PORT_SRC << 2)
++#define IOC_NET_HEADER_FIELD_SCTP_CKSUM                     (IOC_NET_HEADER_FIELD_SCTP_PORT_SRC << 3)
++#define IOC_NET_HEADER_FIELD_SCTP_ALL_FIELDS                ((IOC_NET_HEADER_FIELD_SCTP_PORT_SRC << 4) - 1)
++
++#define IOC_NET_HEADER_FIELD_SCTP_PORT_SIZE                 2
++
++typedef uint8_t ioc_header_field_dccp_t;
++
++#define IOC_NET_HEADER_FIELD_DCCP_PORT_SRC                  (1)
++#define IOC_NET_HEADER_FIELD_DCCP_PORT_DST                  (IOC_NET_HEADER_FIELD_DCCP_PORT_SRC << 1)
++#define IOC_NET_HEADER_FIELD_DCCP_ALL_FIELDS                ((IOC_NET_HEADER_FIELD_DCCP_PORT_SRC << 2) - 1)
++
++#define IOC_NET_HEADER_FIELD_DCCP_PORT_SIZE                 2
++
++
++typedef uint8_t ioc_header_field_udp_t;
++
++#define IOC_NET_HEADER_FIELD_UDP_PORT_SRC                   (1)
++#define IOC_NET_HEADER_FIELD_UDP_PORT_DST                   (IOC_NET_HEADER_FIELD_UDP_PORT_SRC << 1)
++#define IOC_NET_HEADER_FIELD_UDP_LEN                        (IOC_NET_HEADER_FIELD_UDP_PORT_SRC << 2)
++#define IOC_NET_HEADER_FIELD_UDP_CKSUM                      (IOC_NET_HEADER_FIELD_UDP_PORT_SRC << 3)
++#define IOC_NET_HEADER_FIELD_UDP_ALL_FIELDS                 ((IOC_NET_HEADER_FIELD_UDP_PORT_SRC << 4) - 1)
++
++#define IOC_NET_HEADER_FIELD_UDP_PORT_SIZE                  2
++
++typedef uint8_t ioc_header_field_udp_lite_t;
++
++#define IOC_NET_HEADER_FIELD_UDP_LITE_PORT_SRC              (1)
++#define IOC_NET_HEADER_FIELD_UDP_LITE_PORT_DST              (IOC_NET_HEADER_FIELD_UDP_LITE_PORT_SRC << 1)
++#define IOC_NET_HEADER_FIELD_UDP_LITE_ALL_FIELDS            ((IOC_NET_HEADER_FIELD_UDP_LITE_PORT_SRC << 2) - 1)
++
++#define IOC_NET_HEADER_FIELD_UDP_LITE_PORT_SIZE             2
++
++typedef uint8_t ioc_header_field_udp_encap_esp_t;
++
++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC         (1)
++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST         (IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 1)
++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN              (IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 2)
++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM            (IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 3)
++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI              (IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 4)
++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM     (IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 5)
++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_ALL_FIELDS       ((IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 6) - 1)
++
++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SIZE        2
++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI_SIZE         4
++
++#define IOC_NET_HEADER_FIELD_IPHC_CID                       (1)
++#define IOC_NET_HEADER_FIELD_IPHC_CID_TYPE                  (IOC_NET_HEADER_FIELD_IPHC_CID << 1)
++#define IOC_NET_HEADER_FIELD_IPHC_HCINDEX                   (IOC_NET_HEADER_FIELD_IPHC_CID << 2)
++#define IOC_NET_HEADER_FIELD_IPHC_GEN                       (IOC_NET_HEADER_FIELD_IPHC_CID << 3)
++#define IOC_NET_HEADER_FIELD_IPHC_D_BIT                     (IOC_NET_HEADER_FIELD_IPHC_CID << 4)
++#define IOC_NET_HEADER_FIELD_IPHC_ALL_FIELDS                ((IOC_NET_HEADER_FIELD_IPHC_CID << 5) - 1)
++
++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE           (1)
++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_FLAGS          (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 1)
++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_LENGTH         (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 2)
++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TSN            (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 3)
++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_ID      (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 4)
++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_SQN     (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 5)
++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_PAYLOAD_PID    (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 6)
++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_UNORDERED      (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 7)
++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_BEGGINING      (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 8)
++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_END            (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 9)
++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_ALL_FIELDS     ((IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 10) - 1)
++
++#define IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT                (1)
++#define IOC_NET_HEADER_FIELD_L2TPv2_LENGTH_BIT              (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 1)
++#define IOC_NET_HEADER_FIELD_L2TPv2_SEQUENCE_BIT            (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 2)
++#define IOC_NET_HEADER_FIELD_L2TPv2_OFFSET_BIT              (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 3)
++#define IOC_NET_HEADER_FIELD_L2TPv2_PRIORITY_BIT            (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 4)
++#define IOC_NET_HEADER_FIELD_L2TPv2_VERSION                 (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 5)
++#define IOC_NET_HEADER_FIELD_L2TPv2_LEN                     (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 6)
++#define IOC_NET_HEADER_FIELD_L2TPv2_TUNNEL_ID               (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 7)
++#define IOC_NET_HEADER_FIELD_L2TPv2_SESSION_ID              (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 8)
++#define IOC_NET_HEADER_FIELD_L2TPv2_NS                      (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 9)
++#define IOC_NET_HEADER_FIELD_L2TPv2_NR                      (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 10)
++#define IOC_NET_HEADER_FIELD_L2TPv2_OFFSET_SIZE             (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 11)
++#define IOC_NET_HEADER_FIELD_L2TPv2_FIRST_BYTE              (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 12)
++#define IOC_NET_HEADER_FIELD_L2TPv2_ALL_FIELDS              ((IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 13) - 1)
++
++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT           (1)
++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_LENGTH_BIT         (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 1)
++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_SEQUENCE_BIT       (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 2)
++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_VERSION            (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 3)
++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_LENGTH             (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 4)
++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_CONTROL            (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 5)
++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_SENT               (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 6)
++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_RECV               (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 7)
++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_FIRST_BYTE         (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 8)
++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_ALL_FIELDS         ((IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 9) - 1)
++
++#define IOC_NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT           (1)
++#define IOC_NET_HEADER_FIELD_L2TPv3_SESS_VERSION            (IOC_NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 1)
++#define IOC_NET_HEADER_FIELD_L2TPv3_SESS_ID                 (IOC_NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 2)
++#define IOC_NET_HEADER_FIELD_L2TPv3_SESS_COOKIE             (IOC_NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 3)
++#define IOC_NET_HEADER_FIELD_L2TPv3_SESS_ALL_FIELDS         ((IOC_NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 4) - 1)
++
++
++typedef uint8_t ioc_header_field_vlan_t;
++
++#define IOC_NET_HEADER_FIELD_VLAN_VPRI                      (1)
++#define IOC_NET_HEADER_FIELD_VLAN_CFI                       (IOC_NET_HEADER_FIELD_VLAN_VPRI << 1)
++#define IOC_NET_HEADER_FIELD_VLAN_VID                       (IOC_NET_HEADER_FIELD_VLAN_VPRI << 2)
++#define IOC_NET_HEADER_FIELD_VLAN_LENGTH                    (IOC_NET_HEADER_FIELD_VLAN_VPRI << 3)
++#define IOC_NET_HEADER_FIELD_VLAN_TYPE                      (IOC_NET_HEADER_FIELD_VLAN_VPRI << 4)
++#define IOC_NET_HEADER_FIELD_VLAN_ALL_FIELDS                ((IOC_NET_HEADER_FIELD_VLAN_VPRI << 5) - 1)
++
++#define IOC_NET_HEADER_FIELD_VLAN_TCI                       (IOC_NET_HEADER_FIELD_VLAN_VPRI | \
++                                                             IOC_NET_HEADER_FIELD_VLAN_CFI | \
++                                                             IOC_NET_HEADER_FIELD_VLAN_VID)
++
++
++typedef uint8_t ioc_header_field_llc_t;
++
++#define IOC_NET_HEADER_FIELD_LLC_DSAP                       (1)
++#define IOC_NET_HEADER_FIELD_LLC_SSAP                       (IOC_NET_HEADER_FIELD_LLC_DSAP << 1)
++#define IOC_NET_HEADER_FIELD_LLC_CTRL                       (IOC_NET_HEADER_FIELD_LLC_DSAP << 2)
++#define IOC_NET_HEADER_FIELD_LLC_ALL_FIELDS                 ((IOC_NET_HEADER_FIELD_LLC_DSAP << 3) - 1)
++
++#define IOC_NET_HEADER_FIELD_NLPID_NLPID                    (1)
++#define IOC_NET_HEADER_FIELD_NLPID_ALL_FIELDS               ((IOC_NET_HEADER_FIELD_NLPID_NLPID << 1) - 1)
++
++
++typedef uint8_t ioc_header_field_snap_t;
++
++#define IOC_NET_HEADER_FIELD_SNAP_OUI                       (1)
++#define IOC_NET_HEADER_FIELD_SNAP_PID                       (IOC_NET_HEADER_FIELD_SNAP_OUI << 1)
++#define IOC_NET_HEADER_FIELD_SNAP_ALL_FIELDS                ((IOC_NET_HEADER_FIELD_SNAP_OUI << 2) - 1)
++
++
++typedef uint8_t ioc_header_field_llc_snap_t;
++
++#define IOC_NET_HEADER_FIELD_LLC_SNAP_TYPE                  (1)
++#define IOC_NET_HEADER_FIELD_LLC_SNAP_ALL_FIELDS            ((IOC_NET_HEADER_FIELD_LLC_SNAP_TYPE << 1) - 1)
++
++#define IOC_NET_HEADER_FIELD_ARP_HTYPE                      (1)
++#define IOC_NET_HEADER_FIELD_ARP_PTYPE                      (IOC_NET_HEADER_FIELD_ARP_HTYPE << 1)
++#define IOC_NET_HEADER_FIELD_ARP_HLEN                       (IOC_NET_HEADER_FIELD_ARP_HTYPE << 2)
++#define IOC_NET_HEADER_FIELD_ARP_PLEN                       (IOC_NET_HEADER_FIELD_ARP_HTYPE << 3)
++#define IOC_NET_HEADER_FIELD_ARP_OPER                       (IOC_NET_HEADER_FIELD_ARP_HTYPE << 4)
++#define IOC_NET_HEADER_FIELD_ARP_SHA                        (IOC_NET_HEADER_FIELD_ARP_HTYPE << 5)
++#define IOC_NET_HEADER_FIELD_ARP_SPA                        (IOC_NET_HEADER_FIELD_ARP_HTYPE << 6)
++#define IOC_NET_HEADER_FIELD_ARP_THA                        (IOC_NET_HEADER_FIELD_ARP_HTYPE << 7)
++#define IOC_NET_HEADER_FIELD_ARP_TPA                        (IOC_NET_HEADER_FIELD_ARP_HTYPE << 8)
++#define IOC_NET_HEADER_FIELD_ARP_ALL_FIELDS                 ((IOC_NET_HEADER_FIELD_ARP_HTYPE << 9) - 1)
++
++#define IOC_NET_HEADER_FIELD_RFC2684_LLC                    (1)
++#define IOC_NET_HEADER_FIELD_RFC2684_NLPID                  (IOC_NET_HEADER_FIELD_RFC2684_LLC << 1)
++#define IOC_NET_HEADER_FIELD_RFC2684_OUI                    (IOC_NET_HEADER_FIELD_RFC2684_LLC << 2)
++#define IOC_NET_HEADER_FIELD_RFC2684_PID                    (IOC_NET_HEADER_FIELD_RFC2684_LLC << 3)
++#define IOC_NET_HEADER_FIELD_RFC2684_VPN_OUI                (IOC_NET_HEADER_FIELD_RFC2684_LLC << 4)
++#define IOC_NET_HEADER_FIELD_RFC2684_VPN_IDX                (IOC_NET_HEADER_FIELD_RFC2684_LLC << 5)
++#define IOC_NET_HEADER_FIELD_RFC2684_ALL_FIELDS             ((IOC_NET_HEADER_FIELD_RFC2684_LLC << 6) - 1)
++
++#define IOC_NET_HEADER_FIELD_USER_DEFINED_SRCPORT           (1)
++#define IOC_NET_HEADER_FIELD_USER_DEFINED_PCDID             (IOC_NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 1)
++#define IOC_NET_HEADER_FIELD_USER_DEFINED_ALL_FIELDS        ((IOC_NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 2) - 1)
++
++#define IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER                 (1)
++#define IOC_NET_HEADER_FIELD_PAYLOAD_SIZE                   (IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 1)
++#define IOC_NET_HEADER_FIELD_MAX_FRM_SIZE                   (IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 2)
++#define IOC_NET_HEADER_FIELD_MIN_FRM_SIZE                   (IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 3)
++#define IOC_NET_HEADER_FIELD_PAYLOAD_TYPE                   (IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 4)
++#define IOC_NET_HEADER_FIELD_FRAME_SIZE                     (IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 5)
++#define IOC_NET_HEADER_FIELD_PAYLOAD_ALL_FIELDS             ((IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 6) - 1)
++
++
++typedef uint8_t ioc_header_field_gre_t;
++
++#define IOC_NET_HEADER_FIELD_GRE_TYPE                       (1)
++#define IOC_NET_HEADER_FIELD_GRE_ALL_FIELDS                 ((IOC_NET_HEADER_FIELD_GRE_TYPE << 1) - 1)
++
++
++typedef uint8_t ioc_header_field_minencap_t;
++
++#define IOC_NET_HEADER_FIELD_MINENCAP_SRC_IP                (1)
++#define IOC_NET_HEADER_FIELD_MINENCAP_DST_IP                (IOC_NET_HEADER_FIELD_MINENCAP_SRC_IP << 1)
++#define IOC_NET_HEADER_FIELD_MINENCAP_TYPE                  (IOC_NET_HEADER_FIELD_MINENCAP_SRC_IP << 2)
++#define IOC_NET_HEADER_FIELD_MINENCAP_ALL_FIELDS            ((IOC_NET_HEADER_FIELD_MINENCAP_SRC_IP << 3) - 1)
++
++
++typedef uint8_t ioc_header_field_ipsec_ah_t;
++
++#define IOC_NET_HEADER_FIELD_IPSEC_AH_SPI                   (1)
++#define IOC_NET_HEADER_FIELD_IPSEC_AH_NH                    (IOC_NET_HEADER_FIELD_IPSEC_AH_SPI << 1)
++#define IOC_NET_HEADER_FIELD_IPSEC_AH_ALL_FIELDS            ((IOC_NET_HEADER_FIELD_IPSEC_AH_SPI << 2) - 1)
++
++
++typedef uint8_t ioc_header_field_ipsec_esp_t;
++
++#define IOC_NET_HEADER_FIELD_IPSEC_ESP_SPI                  (1)
++#define IOC_NET_HEADER_FIELD_IPSEC_ESP_SEQUENCE_NUM         (IOC_NET_HEADER_FIELD_IPSEC_ESP_SPI << 1)
++#define IOC_NET_HEADER_FIELD_IPSEC_ESP_ALL_FIELDS           ((IOC_NET_HEADER_FIELD_IPSEC_ESP_SPI << 2) - 1)
++
++#define IOC_NET_HEADER_FIELD_IPSEC_ESP_SPI_SIZE             4
++
++
++typedef uint8_t ioc_header_field_mpls_t;
++
++#define IOC_NET_HEADER_FIELD_MPLS_LABEL_STACK               (1)
++#define IOC_NET_HEADER_FIELD_MPLS_LABEL_STACK_ALL_FIELDS    ((IOC_NET_HEADER_FIELD_MPLS_LABEL_STACK << 1) - 1)
++
++
++typedef uint8_t ioc_header_field_macsec_t;
++
++#define IOC_NET_HEADER_FIELD_MACSEC_SECTAG                  (1)
++#define IOC_NET_HEADER_FIELD_MACSEC_ALL_FIELDS              ((IOC_NET_HEADER_FIELD_MACSEC_SECTAG << 1) - 1)
++
++
++typedef enum {
++    e_IOC_NET_HEADER_TYPE_NONE = 0,
++    e_IOC_NET_HEADER_TYPE_PAYLOAD,
++    e_IOC_NET_HEADER_TYPE_ETH,
++    e_IOC_NET_HEADER_TYPE_VLAN,
++    e_IOC_NET_HEADER_TYPE_IPv4,
++    e_IOC_NET_HEADER_TYPE_IPv6,
++    e_IOC_NET_HEADER_TYPE_IP,
++    e_IOC_NET_HEADER_TYPE_TCP,
++    e_IOC_NET_HEADER_TYPE_UDP,
++    e_IOC_NET_HEADER_TYPE_UDP_LITE,
++    e_IOC_NET_HEADER_TYPE_IPHC,
++    e_IOC_NET_HEADER_TYPE_SCTP,
++    e_IOC_NET_HEADER_TYPE_SCTP_CHUNK_DATA,
++    e_IOC_NET_HEADER_TYPE_PPPoE,
++    e_IOC_NET_HEADER_TYPE_PPP,
++    e_IOC_NET_HEADER_TYPE_PPPMUX,
++    e_IOC_NET_HEADER_TYPE_PPPMUX_SUBFRAME,
++    e_IOC_NET_HEADER_TYPE_L2TPv2,
++    e_IOC_NET_HEADER_TYPE_L2TPv3_CTRL,
++    e_IOC_NET_HEADER_TYPE_L2TPv3_SESS,
++    e_IOC_NET_HEADER_TYPE_LLC,
++    e_IOC_NET_HEADER_TYPE_LLC_SNAP,
++    e_IOC_NET_HEADER_TYPE_NLPID,
++    e_IOC_NET_HEADER_TYPE_SNAP,
++    e_IOC_NET_HEADER_TYPE_MPLS,
++    e_IOC_NET_HEADER_TYPE_IPSEC_AH,
++    e_IOC_NET_HEADER_TYPE_IPSEC_ESP,
++    e_IOC_NET_HEADER_TYPE_UDP_ENCAP_ESP, /* RFC 3948 */
++    e_IOC_NET_HEADER_TYPE_MACSEC,
++    e_IOC_NET_HEADER_TYPE_GRE,
++    e_IOC_NET_HEADER_TYPE_MINENCAP,
++    e_IOC_NET_HEADER_TYPE_DCCP,
++    e_IOC_NET_HEADER_TYPE_ICMP,
++    e_IOC_NET_HEADER_TYPE_IGMP,
++    e_IOC_NET_HEADER_TYPE_ARP,
++    e_IOC_NET_HEADER_TYPE_CAPWAP,
++    e_IOC_NET_HEADER_TYPE_CAPWAP_DTLS,
++    e_IOC_NET_HEADER_TYPE_RFC2684,
++    e_IOC_NET_HEADER_TYPE_USER_DEFINED_L2,
++    e_IOC_NET_HEADER_TYPE_USER_DEFINED_L3,
++    e_IOC_NET_HEADER_TYPE_USER_DEFINED_L4,
++    e_IOC_NET_HEADER_TYPE_USER_DEFINED_SHIM1,
++    e_IOC_NET_HEADER_TYPE_USER_DEFINED_SHIM2,
++    e_IOC_NET_MAX_HEADER_TYPE_COUNT
++} ioc_net_header_type;
++
++
++#endif /* __NET_IOCTLS_H */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0009-dpa-SDK-DPAA-1.x-Ethernet-driver.patch b/target/linux/layerscape/patches-5.4/701-net-0009-dpa-SDK-DPAA-1.x-Ethernet-driver.patch
new file mode 100644 (file)
index 0000000..29b52d2
--- /dev/null
@@ -0,0 +1,12969 @@
+From f7f94b1e7e9c6044a23bab1c5e773f6259f2d3e0 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Wed, 10 May 2017 16:39:42 +0300
+Subject: [PATCH] dpa: SDK DPAA 1.x Ethernet driver
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/Kconfig    |  173 ++
+ drivers/net/ethernet/freescale/sdk_dpaa/Makefile   |   46 +
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_1588.c    |  580 ++++++
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_1588.h    |  138 ++
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.c |  180 ++
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.h |   43 +
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c | 1210 ++++++++++++
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h |  697 +++++++
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_base.c    |  263 +++
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_base.h    |   50 +
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 1991 ++++++++++++++++++++
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h   |  236 +++
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_common.c  | 1812 ++++++++++++++++++
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_common.h  |  226 +++
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c   |  381 ++++
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c  | 1113 +++++++++++
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_sysfs.c   |  278 +++
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_trace.h   |  144 ++
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c |  544 ++++++
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ptp.c |  290 +++
+ drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c  |  909 +++++++++
+ drivers/net/ethernet/freescale/sdk_dpaa/mac.c      |  489 +++++
+ drivers/net/ethernet/freescale/sdk_dpaa/mac.h      |  135 ++
+ .../net/ethernet/freescale/sdk_dpaa/offline_port.c |  848 +++++++++
+ .../net/ethernet/freescale/sdk_dpaa/offline_port.h |   59 +
+ 25 files changed, 12835 insertions(+)
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/Kconfig
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/Makefile
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sysfs.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_trace.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ptp.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/mac.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/mac.h
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/offline_port.c
+ create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/offline_port.h
+
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig
+@@ -0,0 +1,173 @@
++menuconfig FSL_SDK_DPAA_ETH
++      tristate "DPAA Ethernet"
++      depends on (FSL_SOC || ARM64 || ARM) && FSL_SDK_BMAN && FSL_SDK_QMAN && FSL_SDK_FMAN && !FSL_DPAA_ETH
++      select PHYLIB
++      help
++        Data Path Acceleration Architecture Ethernet driver,
++        supporting the Freescale QorIQ chips.
++        Depends on Freescale Buffer Manager and Queue Manager
++        driver and Frame Manager Driver.
++
++if FSL_SDK_DPAA_ETH
++
++config FSL_DPAA_HOOKS
++      bool "DPAA Ethernet driver hooks"
++
++config FSL_DPAA_CEETM
++      bool "DPAA CEETM QoS"
++      depends on NET_SCHED
++      default n
++      help
++      Enable QoS offloading support through the CEETM hardware block.
++
++config FSL_DPAA_OFFLINE_PORTS
++      bool "Offline Ports support"
++      depends on FSL_SDK_DPAA_ETH
++      default y
++      help
++        The Offline Parsing / Host Command ports (short: OH ports, of Offline ports) provide
++        most of the functionality of the regular, online ports, except they receive their
++        frames from a core or an accelerator on the SoC, via QMan frame queues,
++        rather than directly from the network.
++        Offline ports are configured via PCD (Parse-Classify-Distribute) schemes, just like
++        any online FMan port. They deliver the processed frames to frame queues, according
++        to the applied PCD configurations.
++
++        Choosing this feature will not impact the functionality and/or performance of the system,
++        so it is safe to have it.
++
++config FSL_DPAA_ADVANCED_DRIVERS
++        bool "Advanced DPAA Ethernet drivers"
++        depends on FSL_SDK_DPAA_ETH
++        default y
++        help
++        Besides the standard DPAA Ethernet driver the DPAA Proxy initialization driver
++        is needed to support advanced scenarios. Select this to also build the advanced
++        drivers.
++
++config FSL_DPAA_ETH_JUMBO_FRAME
++      bool "Optimize for jumbo frames"
++      default n
++      help
++        Optimize the DPAA Ethernet driver throughput for large frames
++        termination traffic (e.g. 4K and above).
++        NOTE: This option can only be used if FSL_FM_MAX_FRAME_SIZE
++        is set to 9600 bytes.
++        Using this option in combination with small frames increases
++        significantly the driver's memory footprint and may even deplete
++        the system memory. Also, the skb truesize is altered and messages
++        from the stack that warn against this are bypassed.
++        This option is not available on LS1043.
++
++config FSL_DPAA_TS
++      bool "Linux compliant timestamping"
++      depends on FSL_SDK_DPAA_ETH
++      default n
++      help
++        Enable Linux API compliant timestamping support.
++
++config FSL_DPAA_1588
++        bool "IEEE 1588-compliant timestamping"
++        depends on FSL_SDK_DPAA_ETH
++        select FSL_DPAA_TS
++        default n
++        help
++         Enable IEEE1588 support code.
++
++config FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
++      bool "Use driver's Tx queue selection mechanism"
++      default y
++      depends on FSL_SDK_DPAA_ETH
++      help
++        The DPAA-Ethernet driver defines a ndo_select_queue() callback for optimal selection
++        of the egress FQ. That will override the XPS support for this netdevice.
++        If for whatever reason you want to be in control of the egress FQ-to-CPU selection and mapping,
++        or simply don't want to use the driver's ndo_select_queue() callback, then unselect this
++        and use the standard XPS support instead.
++
++config FSL_DPAA_ETH_MAX_BUF_COUNT
++      int "Maximum nuber of buffers in private bpool"
++      depends on FSL_SDK_DPAA_ETH
++      range 64 2048
++      default "128"
++      help
++        The maximum number of buffers to be by default allocated in the DPAA-Ethernet private port's
++        buffer pool. One needn't normally modify this, as it has probably been tuned for performance
++        already. This cannot be lower than DPAA_ETH_REFILL_THRESHOLD.
++
++config FSL_DPAA_ETH_REFILL_THRESHOLD
++      int "Private bpool refill threshold"
++      depends on FSL_SDK_DPAA_ETH
++      range 32 FSL_DPAA_ETH_MAX_BUF_COUNT
++      default "80"
++      help
++        The DPAA-Ethernet driver will start replenishing buffer pools whose count
++        falls below this threshold. This must be related to DPAA_ETH_MAX_BUF_COUNT. One needn't normally
++        modify this value unless one has very specific performance reasons.
++
++config FSL_DPAA_CS_THRESHOLD_1G
++      hex "Egress congestion threshold on 1G ports"
++      depends on FSL_SDK_DPAA_ETH
++      range 0x1000 0x10000000
++      default "0x06000000"
++      help
++        The size in bytes of the egress Congestion State notification threshold on 1G ports.
++        The 1G dTSECs can quite easily be flooded by cores doing Tx in a tight loop
++        (e.g. by sending UDP datagrams at "while(1) speed"),
++        and the larger the frame size, the more acute the problem.
++        So we have to find a balance between these factors:
++             - avoiding the device staying congested for a prolonged time (risking
++                 the netdev watchdog to fire - see also the tx_timeout module param);
++               - affecting performance of protocols such as TCP, which otherwise
++               behave well under the congestion notification mechanism;
++             - preventing the Tx cores from tightly-looping (as if the congestion
++               threshold was too low to be effective);
++             - running out of memory if the CS threshold is set too high.
++
++config FSL_DPAA_CS_THRESHOLD_10G
++      hex "Egress congestion threshold on 10G ports"
++      depends on FSL_SDK_DPAA_ETH
++      range 0x1000 0x20000000
++      default "0x10000000"
++      help
++        The size in bytes of the egress Congestion State notification threshold on 10G ports.
++
++config FSL_DPAA_INGRESS_CS_THRESHOLD
++      hex "Ingress congestion threshold on FMan ports"
++      depends on FSL_SDK_DPAA_ETH
++      default "0x10000000"
++      help
++        The size in bytes of the ingress tail-drop threshold on FMan ports.
++        Traffic piling up above this value will be rejected by QMan and discarded by FMan.
++
++config FSL_DPAA_ETH_DEBUGFS
++      bool "DPAA Ethernet debugfs interface"
++      depends on DEBUG_FS && FSL_SDK_DPAA_ETH
++      default y
++      help
++        This option compiles debugfs code for the DPAA Ethernet driver.
++
++config FSL_DPAA_ETH_DEBUG
++      bool "DPAA Ethernet Debug Support"
++      depends on FSL_SDK_DPAA_ETH
++      default n
++      help
++        This option compiles debug code for the DPAA Ethernet driver.
++
++config FSL_DPAA_DBG_LOOP
++      bool "DPAA Ethernet Debug loopback"
++      depends on FSL_DPAA_ETH_DEBUGFS && FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
++      default n
++      help
++        This option allows to divert all received traffic on a certain interface A towards a
++        selected interface B. This option is used to benchmark the HW + Ethernet driver in
++        isolation from the Linux networking stack. The loops are controlled by debugfs entries,
++        one for each interface. By default all loops are disabled (target value is -1). I.e. to
++        change the loop setting for interface 4 and divert all received traffic to interface 5
++        write Tx interface number in the receive interface debugfs file:
++              # cat /sys/kernel/debug/powerpc/fsl_dpa/eth4_loop
++                      4->-1
++              # echo 5 > /sys/kernel/debug/powerpc/fsl_dpa/eth4_loop
++              # cat /sys/kernel/debug/powerpc/fsl_dpa/eth4_loop
++                      4->5
++endif # FSL_SDK_DPAA_ETH
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/Makefile
+@@ -0,0 +1,46 @@
++#
++# Makefile for the Freescale Ethernet controllers
++#
++ccflags-y += -DVERSION=\"\"
++#
++# Include netcomm SW specific definitions
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++
++ccflags-y += -I$(NET_DPA)
++
++obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_mac.o fsl_dpa.o
++obj-$(CONFIG_PTP_1588_CLOCK_DPAA) += dpaa_ptp.o
++
++fsl_dpa-objs += dpaa_ethtool.o dpaa_eth_sysfs.o dpaa_eth.o dpaa_eth_sg.o dpaa_eth_common.o
++ifeq ($(CONFIG_FSL_DPAA_DBG_LOOP),y)
++fsl_dpa-objs += dpaa_debugfs.o
++endif
++ifeq ($(CONFIG_FSL_DPAA_1588),y)
++fsl_dpa-objs += dpaa_1588.o
++endif
++ifeq ($(CONFIG_FSL_DPAA_CEETM),y)
++ccflags-y += -Idrivers/net/ethernet/freescale/sdk_fman/src/wrapper
++fsl_dpa-objs += dpaa_eth_ceetm.o
++endif
++
++fsl_mac-objs += mac.o mac-api.o
++
++# Advanced drivers
++ifeq ($(CONFIG_FSL_DPAA_ADVANCED_DRIVERS),y)
++obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_advanced.o
++obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_proxy.o
++
++fsl_advanced-objs += dpaa_eth_base.o
++# suport for multiple drivers per kernel module comes in kernel 3.14
++# so we are forced to generate several modules for the advanced drivers
++fsl_proxy-objs += dpaa_eth_proxy.o
++
++ifeq ($(CONFIG_FSL_DPAA_OFFLINE_PORTS),y)
++obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_oh.o
++
++fsl_oh-objs += offline_port.o
++endif
++endif
++
++# Needed by the tracing framework
++CFLAGS_dpaa_eth.o := -I$(src)
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.c
+@@ -0,0 +1,580 @@
++/* Copyright (C) 2011 Freescale Semiconductor, Inc.
++ * Copyright (C) 2009 IXXAT Automation, GmbH
++ *
++ * DPAA Ethernet Driver -- IEEE 1588 interface functionality
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++#include <linux/io.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/vmalloc.h>
++#include <linux/spinlock.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <linux/udp.h>
++#include <asm/div64.h>
++#include "dpaa_eth.h"
++#include "dpaa_eth_common.h"
++#include "dpaa_1588.h"
++#include "mac.h"
++
++static int dpa_ptp_init_circ(struct dpa_ptp_circ_buf *ptp_buf, u32 size)
++{
++      struct circ_buf *circ_buf = &ptp_buf->circ_buf;
++
++      circ_buf->buf = vmalloc(sizeof(struct dpa_ptp_data) * size);
++      if (!circ_buf->buf)
++              return 1;
++
++      circ_buf->head = 0;
++      circ_buf->tail = 0;
++      ptp_buf->size = size;
++      spin_lock_init(&ptp_buf->ptp_lock);
++
++      return 0;
++}
++
++static void dpa_ptp_reset_circ(struct dpa_ptp_circ_buf *ptp_buf, u32 size)
++{
++      struct circ_buf *circ_buf = &ptp_buf->circ_buf;
++
++      circ_buf->head = 0;
++      circ_buf->tail = 0;
++      ptp_buf->size = size;
++}
++
++static int dpa_ptp_insert(struct dpa_ptp_circ_buf *ptp_buf,
++                        struct dpa_ptp_data *data)
++{
++      struct circ_buf *circ_buf = &ptp_buf->circ_buf;
++      int size = ptp_buf->size;
++      struct dpa_ptp_data *tmp;
++      unsigned long flags;
++      int head, tail;
++
++      spin_lock_irqsave(&ptp_buf->ptp_lock, flags);
++
++      head = circ_buf->head;
++      tail = circ_buf->tail;
++
++      if (CIRC_SPACE(head, tail, size) <= 0)
++              circ_buf->tail = (tail + 1) & (size - 1);
++
++      tmp = (struct dpa_ptp_data *)(circ_buf->buf) + head;
++      memcpy(tmp, data, sizeof(struct dpa_ptp_data));
++
++      circ_buf->head = (head + 1) & (size - 1);
++
++      spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags);
++
++      return 0;
++}
++
++static int dpa_ptp_is_ident_match(struct dpa_ptp_ident *dst,
++                                struct dpa_ptp_ident *src)
++{
++      int ret;
++
++      if ((dst->version != src->version) || (dst->msg_type != src->msg_type))
++              return 0;
++
++      if ((dst->netw_prot == src->netw_prot)
++                      || src->netw_prot == DPA_PTP_PROT_DONTCARE) {
++              if (dst->seq_id != src->seq_id)
++                      return 0;
++
++              ret = memcmp(dst->snd_port_id, src->snd_port_id,
++                              DPA_PTP_SOURCE_PORT_LENGTH);
++              if (ret)
++                      return 0;
++              else
++                      return 1;
++      }
++
++      return 0;
++}
++
++static int dpa_ptp_find_and_remove(struct dpa_ptp_circ_buf *ptp_buf,
++                                 struct dpa_ptp_ident *ident,
++                                 struct dpa_ptp_time *ts)
++{
++      struct circ_buf *circ_buf = &ptp_buf->circ_buf;
++      int size = ptp_buf->size;
++      int head, tail, idx;
++      unsigned long flags;
++      struct dpa_ptp_data *tmp, *tmp2;
++      struct dpa_ptp_ident *tmp_ident;
++
++      spin_lock_irqsave(&ptp_buf->ptp_lock, flags);
++
++      head = circ_buf->head;
++      tail = idx = circ_buf->tail;
++
++      if (CIRC_CNT(head, tail, size) == 0) {
++              spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags);
++              return 1;
++      }
++
++      while (idx != head) {
++              tmp = (struct dpa_ptp_data *)(circ_buf->buf) + idx;
++              tmp_ident = &tmp->ident;
++              if (dpa_ptp_is_ident_match(tmp_ident, ident))
++                      break;
++              idx = (idx + 1) & (size - 1);
++      }
++
++      if (idx == head) {
++              spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags);
++              return 1;
++      }
++
++      ts->sec = tmp->ts.sec;
++      ts->nsec = tmp->ts.nsec;
++
++      if (idx != tail) {
++              if (CIRC_CNT(idx, tail, size) > TS_ACCUMULATION_THRESHOLD) {
++                      tail = circ_buf->tail =
++                              (idx - TS_ACCUMULATION_THRESHOLD) & (size - 1);
++              }
++
++              while (CIRC_CNT(idx, tail, size) > 0) {
++                      tmp = (struct dpa_ptp_data *)(circ_buf->buf) + idx;
++                      idx = (idx - 1) & (size - 1);
++                      tmp2 = (struct dpa_ptp_data *)(circ_buf->buf) + idx;
++                      *tmp = *tmp2;
++              }
++      }
++      circ_buf->tail = (tail + 1) & (size - 1);
++
++      spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags);
++
++      return 0;
++}
++
++/* Parse the PTP packets
++ *
++ * The PTP header can be found in an IPv4 packet, IPv6 patcket or in
++ * an IEEE802.3 ethernet frame. This function returns the position of
++ * the PTP packet or NULL if no PTP found
++ */
++static u8 *dpa_ptp_parse_packet(struct sk_buff *skb, u16 *eth_type)
++{
++      u8 *pos = skb->data + ETH_ALEN + ETH_ALEN;
++      u8 *ptp_loc = NULL;
++      u8 msg_type;
++      u32 access_len = ETH_ALEN + ETH_ALEN + DPA_ETYPE_LEN;
++      struct iphdr *iph;
++      struct udphdr *udph;
++      struct ipv6hdr *ipv6h;
++
++      /* when we can receive S/G frames we need to check the data we want to
++       * access is in the linear skb buffer
++       */
++      if (!pskb_may_pull(skb, access_len))
++              return NULL;
++
++      *eth_type = *((u16 *)pos);
++
++      /* Check if inner tag is here */
++      if (*eth_type == ETH_P_8021Q) {
++              access_len += DPA_VLAN_TAG_LEN;
++
++              if (!pskb_may_pull(skb, access_len))
++                      return NULL;
++
++              pos += DPA_VLAN_TAG_LEN;
++              *eth_type = *((u16 *)pos);
++      }
++
++      pos += DPA_ETYPE_LEN;
++
++      switch (*eth_type) {
++      /* Transport of PTP over Ethernet */
++      case ETH_P_1588:
++              ptp_loc = pos;
++
++              if (!pskb_may_pull(skb, access_len + PTP_OFFS_MSG_TYPE + 1))
++                      return NULL;
++
++              msg_type = *((u8 *)(ptp_loc + PTP_OFFS_MSG_TYPE)) & 0xf;
++              if ((msg_type == PTP_MSGTYPE_SYNC)
++                      || (msg_type == PTP_MSGTYPE_DELREQ)
++                      || (msg_type == PTP_MSGTYPE_PDELREQ)
++                      || (msg_type == PTP_MSGTYPE_PDELRESP))
++                              return ptp_loc;
++              break;
++      /* Transport of PTP over IPv4 */
++      case ETH_P_IP:
++              iph = (struct iphdr *)pos;
++              access_len += sizeof(struct iphdr);
++
++              if (!pskb_may_pull(skb, access_len))
++                      return NULL;
++
++              if (ntohs(iph->protocol) != IPPROTO_UDP)
++                      return NULL;
++
++              access_len += iph->ihl * 4 - sizeof(struct iphdr) +
++                              sizeof(struct udphdr);
++
++              if (!pskb_may_pull(skb, access_len))
++                      return NULL;
++
++              pos += iph->ihl * 4;
++              udph = (struct udphdr *)pos;
++              if (ntohs(udph->dest) != 319)
++                      return NULL;
++              ptp_loc = pos + sizeof(struct udphdr);
++              break;
++      /* Transport of PTP over IPv6 */
++      case ETH_P_IPV6:
++              ipv6h = (struct ipv6hdr *)pos;
++
++              access_len += sizeof(struct ipv6hdr) + sizeof(struct udphdr);
++
++              if (ntohs(ipv6h->nexthdr) != IPPROTO_UDP)
++                      return NULL;
++
++              pos += sizeof(struct ipv6hdr);
++              udph = (struct udphdr *)pos;
++              if (ntohs(udph->dest) != 319)
++                      return NULL;
++              ptp_loc = pos + sizeof(struct udphdr);
++              break;
++      default:
++              break;
++      }
++
++      return ptp_loc;
++}
++
++static int dpa_ptp_store_stamp(const struct dpa_priv_s *priv,
++              struct sk_buff *skb, void *data, enum port_type rx_tx,
++              struct dpa_ptp_data *ptp_data)
++{
++      u64 nsec;
++      u32 mod;
++      u8 *ptp_loc;
++      u16 eth_type;
++
++      ptp_loc = dpa_ptp_parse_packet(skb, &eth_type);
++      if (!ptp_loc)
++              return -EINVAL;
++
++      switch (eth_type) {
++      case ETH_P_IP:
++              ptp_data->ident.netw_prot = DPA_PTP_PROT_IPV4;
++              break;
++      case ETH_P_IPV6:
++              ptp_data->ident.netw_prot = DPA_PTP_PROT_IPV6;
++              break;
++      case ETH_P_1588:
++              ptp_data->ident.netw_prot = DPA_PTP_PROT_802_3;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      if (!pskb_may_pull(skb, ptp_loc - skb->data + PTP_OFFS_SEQ_ID + 2))
++              return -EINVAL;
++
++      ptp_data->ident.version = *(ptp_loc + PTP_OFFS_VER_PTP) & 0xf;
++      ptp_data->ident.msg_type = *(ptp_loc + PTP_OFFS_MSG_TYPE) & 0xf;
++      ptp_data->ident.seq_id = *((u16 *)(ptp_loc + PTP_OFFS_SEQ_ID));
++      memcpy(ptp_data->ident.snd_port_id, ptp_loc + PTP_OFFS_SRCPRTID,
++                      DPA_PTP_SOURCE_PORT_LENGTH);
++
++      nsec = dpa_get_timestamp_ns(priv, rx_tx, data);
++      mod = do_div(nsec, NANOSEC_PER_SECOND);
++      ptp_data->ts.sec = nsec;
++      ptp_data->ts.nsec = mod;
++
++      return 0;
++}
++
++void dpa_ptp_store_txstamp(const struct dpa_priv_s *priv,
++                              struct sk_buff *skb, void *data)
++{
++      struct dpa_ptp_tsu *tsu = priv->tsu;
++      struct dpa_ptp_data ptp_tx_data;
++
++      if (dpa_ptp_store_stamp(priv, skb, data, TX, &ptp_tx_data))
++              return;
++
++      dpa_ptp_insert(&tsu->tx_timestamps, &ptp_tx_data);
++}
++
++void dpa_ptp_store_rxstamp(const struct dpa_priv_s *priv,
++                              struct sk_buff *skb, void *data)
++{
++      struct dpa_ptp_tsu *tsu = priv->tsu;
++      struct dpa_ptp_data ptp_rx_data;
++
++      if (dpa_ptp_store_stamp(priv, skb, data, RX, &ptp_rx_data))
++              return;
++
++      dpa_ptp_insert(&tsu->rx_timestamps, &ptp_rx_data);
++}
++
++static uint8_t dpa_get_tx_timestamp(struct dpa_ptp_tsu *ptp_tsu,
++                                  struct dpa_ptp_ident *ident,
++                                  struct dpa_ptp_time *ts)
++{
++      struct dpa_ptp_tsu *tsu = ptp_tsu;
++      struct dpa_ptp_time tmp;
++      int flag;
++
++      flag = dpa_ptp_find_and_remove(&tsu->tx_timestamps, ident, &tmp);
++      if (!flag) {
++              ts->sec = tmp.sec;
++              ts->nsec = tmp.nsec;
++              return 0;
++      }
++
++      return -1;
++}
++
++static uint8_t dpa_get_rx_timestamp(struct dpa_ptp_tsu *ptp_tsu,
++                                  struct dpa_ptp_ident *ident,
++                                  struct dpa_ptp_time *ts)
++{
++      struct dpa_ptp_tsu *tsu = ptp_tsu;
++      struct dpa_ptp_time tmp;
++      int flag;
++
++      flag = dpa_ptp_find_and_remove(&tsu->rx_timestamps, ident, &tmp);
++      if (!flag) {
++              ts->sec = tmp.sec;
++              ts->nsec = tmp.nsec;
++              return 0;
++      }
++
++      return -1;
++}
++
++static void dpa_set_fiper_alarm(struct dpa_ptp_tsu *tsu,
++              struct dpa_ptp_time *cnt_time)
++{
++      struct mac_device *mac_dev = tsu->dpa_priv->mac_dev;
++      u64 tmp, fiper;
++
++      if (mac_dev->fm_rtc_disable)
++              mac_dev->fm_rtc_disable(get_fm_handle(tsu->dpa_priv->net_dev));
++
++      /* TMR_FIPER1 will pulse every second after ALARM1 expired */
++      tmp = (u64)cnt_time->sec * NANOSEC_PER_SECOND + (u64)cnt_time->nsec;
++      fiper = NANOSEC_PER_SECOND - DPA_PTP_NOMINAL_FREQ_PERIOD_NS;
++      if (mac_dev->fm_rtc_set_alarm)
++              mac_dev->fm_rtc_set_alarm(get_fm_handle(tsu->dpa_priv->net_dev),
++                                        0, tmp);
++      if (mac_dev->fm_rtc_set_fiper)
++              mac_dev->fm_rtc_set_fiper(get_fm_handle(tsu->dpa_priv->net_dev),
++                                        0, fiper);
++
++      if (mac_dev->fm_rtc_enable)
++              mac_dev->fm_rtc_enable(get_fm_handle(tsu->dpa_priv->net_dev));
++}
++
++static void dpa_get_curr_cnt(struct dpa_ptp_tsu *tsu,
++              struct dpa_ptp_time *curr_time)
++{
++      struct mac_device *mac_dev = tsu->dpa_priv->mac_dev;
++      u64 tmp;
++      u32 mod;
++
++      if (mac_dev->fm_rtc_get_cnt)
++              mac_dev->fm_rtc_get_cnt(get_fm_handle(tsu->dpa_priv->net_dev),
++                                      &tmp);
++
++      mod = do_div(tmp, NANOSEC_PER_SECOND);
++      curr_time->sec = (u32)tmp;
++      curr_time->nsec = mod;
++}
++
++static void dpa_set_1588cnt(struct dpa_ptp_tsu *tsu,
++              struct dpa_ptp_time *cnt_time)
++{
++      struct mac_device *mac_dev = tsu->dpa_priv->mac_dev;
++      u64 tmp;
++
++      tmp = (u64)cnt_time->sec * NANOSEC_PER_SECOND + (u64)cnt_time->nsec;
++
++      if (mac_dev->fm_rtc_set_cnt)
++              mac_dev->fm_rtc_set_cnt(get_fm_handle(tsu->dpa_priv->net_dev),
++                                      tmp);
++
++      /* Restart fiper two seconds later */
++      cnt_time->sec += 2;
++      cnt_time->nsec = 0;
++      dpa_set_fiper_alarm(tsu, cnt_time);
++}
++
++static void dpa_get_drift(struct dpa_ptp_tsu *tsu, u32 *addend)
++{
++      struct mac_device *mac_dev = tsu->dpa_priv->mac_dev;
++      u32 drift;
++
++      if (mac_dev->fm_rtc_get_drift)
++              mac_dev->fm_rtc_get_drift(get_fm_handle(tsu->dpa_priv->net_dev),
++                                        &drift);
++
++      *addend = drift;
++}
++
++static void dpa_set_drift(struct dpa_ptp_tsu *tsu, u32 addend)
++{
++      struct mac_device *mac_dev = tsu->dpa_priv->mac_dev;
++
++      if (mac_dev->fm_rtc_set_drift)
++              mac_dev->fm_rtc_set_drift(get_fm_handle(tsu->dpa_priv->net_dev),
++                                        addend);
++}
++
++static void dpa_flush_timestamp(struct dpa_ptp_tsu *tsu)
++{
++      dpa_ptp_reset_circ(&tsu->rx_timestamps, DEFAULT_PTP_RX_BUF_SZ);
++      dpa_ptp_reset_circ(&tsu->tx_timestamps, DEFAULT_PTP_TX_BUF_SZ);
++}
++
++int dpa_ioctl_1588(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++      struct dpa_priv_s *priv = netdev_priv(dev);
++      struct dpa_ptp_tsu *tsu = priv->tsu;
++      struct mac_device *mac_dev = priv->mac_dev;
++      struct dpa_ptp_data ptp_data;
++      struct dpa_ptp_data *ptp_data_user;
++      struct dpa_ptp_time act_time;
++      u32 addend;
++      int retval = 0;
++
++      if (!tsu || !tsu->valid)
++              return -ENODEV;
++
++      switch (cmd) {
++      case PTP_ENBL_TXTS_IOCTL:
++              tsu->hwts_tx_en_ioctl = 1;
++              if (mac_dev->fm_rtc_enable)
++                      mac_dev->fm_rtc_enable(get_fm_handle(dev));
++              if (mac_dev->ptp_enable)
++                      mac_dev->ptp_enable(mac_dev->get_mac_handle(mac_dev));
++              break;
++      case PTP_DSBL_TXTS_IOCTL:
++              tsu->hwts_tx_en_ioctl = 0;
++              if (mac_dev->fm_rtc_disable)
++                      mac_dev->fm_rtc_disable(get_fm_handle(dev));
++              if (mac_dev->ptp_disable)
++                      mac_dev->ptp_disable(mac_dev->get_mac_handle(mac_dev));
++              break;
++      case PTP_ENBL_RXTS_IOCTL:
++              tsu->hwts_rx_en_ioctl = 1;
++              break;
++      case PTP_DSBL_RXTS_IOCTL:
++              tsu->hwts_rx_en_ioctl = 0;
++              break;
++      case PTP_GET_RX_TIMESTAMP:
++              ptp_data_user = (struct dpa_ptp_data *)ifr->ifr_data;
++              if (copy_from_user(&ptp_data.ident,
++                              &ptp_data_user->ident, sizeof(ptp_data.ident)))
++                      return -EINVAL;
++
++              if (dpa_get_rx_timestamp(tsu, &ptp_data.ident, &ptp_data.ts))
++                      return -EAGAIN;
++
++              if (copy_to_user((void __user *)&ptp_data_user->ts,
++                              &ptp_data.ts, sizeof(ptp_data.ts)))
++                      return -EFAULT;
++              break;
++      case PTP_GET_TX_TIMESTAMP:
++              ptp_data_user = (struct dpa_ptp_data *)ifr->ifr_data;
++              if (copy_from_user(&ptp_data.ident,
++                              &ptp_data_user->ident, sizeof(ptp_data.ident)))
++                      return -EINVAL;
++
++              if (dpa_get_tx_timestamp(tsu, &ptp_data.ident, &ptp_data.ts))
++                      return -EAGAIN;
++
++              if (copy_to_user((void __user *)&ptp_data_user->ts,
++                              &ptp_data.ts, sizeof(ptp_data.ts)))
++                      return -EFAULT;
++              break;
++      case PTP_GET_TIME:
++              dpa_get_curr_cnt(tsu, &act_time);
++              if (copy_to_user(ifr->ifr_data, &act_time, sizeof(act_time)))
++                      return -EFAULT;
++              break;
++      case PTP_SET_TIME:
++              if (copy_from_user(&act_time, ifr->ifr_data, sizeof(act_time)))
++                      return -EINVAL;
++              dpa_set_1588cnt(tsu, &act_time);
++              break;
++      case PTP_GET_ADJ:
++              dpa_get_drift(tsu, &addend);
++              if (copy_to_user(ifr->ifr_data, &addend, sizeof(addend)))
++                      return -EFAULT;
++              break;
++      case PTP_SET_ADJ:
++              if (copy_from_user(&addend, ifr->ifr_data, sizeof(addend)))
++                      return -EINVAL;
++              dpa_set_drift(tsu, addend);
++              break;
++      case PTP_SET_FIPER_ALARM:
++              if (copy_from_user(&act_time, ifr->ifr_data, sizeof(act_time)))
++                      return -EINVAL;
++              dpa_set_fiper_alarm(tsu, &act_time);
++              break;
++      case PTP_CLEANUP_TS:
++              dpa_flush_timestamp(tsu);
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      return retval;
++}
++
++int dpa_ptp_init(struct dpa_priv_s *priv)
++{
++      struct dpa_ptp_tsu *tsu;
++
++      /* Allocate memory for PTP structure */
++      tsu = kzalloc(sizeof(struct dpa_ptp_tsu), GFP_KERNEL);
++      if (!tsu)
++              return -ENOMEM;
++
++      tsu->valid = TRUE;
++      tsu->dpa_priv = priv;
++
++      dpa_ptp_init_circ(&tsu->rx_timestamps, DEFAULT_PTP_RX_BUF_SZ);
++      dpa_ptp_init_circ(&tsu->tx_timestamps, DEFAULT_PTP_TX_BUF_SZ);
++
++      priv->tsu = tsu;
++
++      return 0;
++}
++EXPORT_SYMBOL(dpa_ptp_init);
++
++void dpa_ptp_cleanup(struct dpa_priv_s *priv)
++{
++      struct dpa_ptp_tsu *tsu = priv->tsu;
++
++      tsu->valid = FALSE;
++      vfree(tsu->rx_timestamps.circ_buf.buf);
++      vfree(tsu->tx_timestamps.circ_buf.buf);
++
++      kfree(tsu);
++}
++EXPORT_SYMBOL(dpa_ptp_cleanup);
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.h
+@@ -0,0 +1,138 @@
++/* Copyright (C) 2011 Freescale Semiconductor, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++#ifndef __DPAA_1588_H__
++#define __DPAA_1588_H__
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/circ_buf.h>
++#include <linux/fsl_qman.h>
++
++#define DEFAULT_PTP_RX_BUF_SZ         256
++#define DEFAULT_PTP_TX_BUF_SZ         256
++
++/* 1588 private ioctl calls */
++#define PTP_ENBL_TXTS_IOCTL   SIOCDEVPRIVATE
++#define PTP_DSBL_TXTS_IOCTL   (SIOCDEVPRIVATE + 1)
++#define PTP_ENBL_RXTS_IOCTL   (SIOCDEVPRIVATE + 2)
++#define PTP_DSBL_RXTS_IOCTL   (SIOCDEVPRIVATE + 3)
++#define PTP_GET_TX_TIMESTAMP  (SIOCDEVPRIVATE + 4)
++#define PTP_GET_RX_TIMESTAMP  (SIOCDEVPRIVATE + 5)
++#define PTP_SET_TIME          (SIOCDEVPRIVATE + 6)
++#define PTP_GET_TIME          (SIOCDEVPRIVATE + 7)
++#define PTP_SET_FIPER_ALARM   (SIOCDEVPRIVATE + 8)
++#define PTP_SET_ADJ           (SIOCDEVPRIVATE + 9)
++#define PTP_GET_ADJ           (SIOCDEVPRIVATE + 10)
++#define PTP_CLEANUP_TS                (SIOCDEVPRIVATE + 11)
++
++/* PTP V2 message type */
++enum {
++      PTP_MSGTYPE_SYNC                = 0x0,
++      PTP_MSGTYPE_DELREQ              = 0x1,
++      PTP_MSGTYPE_PDELREQ             = 0x2,
++      PTP_MSGTYPE_PDELRESP            = 0x3,
++      PTP_MSGTYPE_FLWUP               = 0x8,
++      PTP_MSGTYPE_DELRESP             = 0x9,
++      PTP_MSGTYPE_PDELRES_FLWUP       = 0xA,
++      PTP_MSGTYPE_ANNOUNCE            = 0xB,
++      PTP_MSGTYPE_SGNLNG              = 0xC,
++      PTP_MSGTYPE_MNGMNT              = 0xD,
++};
++
++/* Byte offset of data in the PTP V2 headers */
++#define PTP_OFFS_MSG_TYPE             0
++#define PTP_OFFS_VER_PTP              1
++#define PTP_OFFS_MSG_LEN              2
++#define PTP_OFFS_DOM_NMB              4
++#define PTP_OFFS_FLAGS                        6
++#define PTP_OFFS_CORFIELD             8
++#define PTP_OFFS_SRCPRTID             20
++#define PTP_OFFS_SEQ_ID                       30
++#define PTP_OFFS_CTRL                 32
++#define PTP_OFFS_LOGMEAN              33
++
++#define PTP_IP_OFFS                   14
++#define PTP_UDP_OFFS                  34
++#define PTP_HEADER_OFFS                       42
++#define PTP_MSG_TYPE_OFFS             (PTP_HEADER_OFFS + PTP_OFFS_MSG_TYPE)
++#define PTP_SPORT_ID_OFFS             (PTP_HEADER_OFFS + PTP_OFFS_SRCPRTID)
++#define PTP_SEQ_ID_OFFS                       (PTP_HEADER_OFFS + PTP_OFFS_SEQ_ID)
++#define PTP_CTRL_OFFS                 (PTP_HEADER_OFFS + PTP_OFFS_CTRL)
++
++/* 1588-2008 network protocol enumeration values */
++#define DPA_PTP_PROT_IPV4             1
++#define DPA_PTP_PROT_IPV6             2
++#define DPA_PTP_PROT_802_3            3
++#define DPA_PTP_PROT_DONTCARE         0xFFFF
++
++#define DPA_PTP_SOURCE_PORT_LENGTH    10
++#define DPA_PTP_HEADER_SZE            34
++#define DPA_ETYPE_LEN                 2
++#define DPA_VLAN_TAG_LEN              4
++#define NANOSEC_PER_SECOND            1000000000
++
++/* The threshold between the current found one and the oldest one */
++#define TS_ACCUMULATION_THRESHOLD     50
++
++/* Struct needed to identify a timestamp */
++struct dpa_ptp_ident {
++      u8      version;
++      u8      msg_type;
++      u16     netw_prot;
++      u16     seq_id;
++      u8      snd_port_id[DPA_PTP_SOURCE_PORT_LENGTH];
++};
++
++/* Timestamp format in 1588-2008 */
++struct dpa_ptp_time {
++      u64     sec;    /* just 48 bit used */
++      u32     nsec;
++};
++
++/* needed for timestamp data over ioctl */
++struct dpa_ptp_data {
++      struct dpa_ptp_ident    ident;
++      struct dpa_ptp_time     ts;
++};
++
++struct dpa_ptp_circ_buf {
++      struct circ_buf circ_buf;
++      u32 size;
++      spinlock_t ptp_lock;
++};
++
++/* PTP TSU control structure */
++struct dpa_ptp_tsu {
++      struct dpa_priv_s *dpa_priv;
++      bool valid;
++      struct dpa_ptp_circ_buf rx_timestamps;
++      struct dpa_ptp_circ_buf tx_timestamps;
++
++      /* HW timestamping over ioctl enabled flag */
++      int hwts_tx_en_ioctl;
++      int hwts_rx_en_ioctl;
++};
++
++extern int dpa_ptp_init(struct dpa_priv_s *priv);
++extern void dpa_ptp_cleanup(struct dpa_priv_s *priv);
++extern void dpa_ptp_store_txstamp(const struct dpa_priv_s *priv,
++                              struct sk_buff *skb, void *data);
++extern void dpa_ptp_store_rxstamp(const struct dpa_priv_s *priv,
++                              struct sk_buff *skb, void *data);
++extern int dpa_ioctl_1588(struct net_device *dev, struct ifreq *ifr, int cmd);
++#endif
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.c
+@@ -0,0 +1,180 @@
++/* Copyright 2008-2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/module.h>
++#include <linux/fsl_qman.h>   /* struct qm_mcr_querycgr */
++#include <linux/debugfs.h>
++#include "dpaa_debugfs.h"
++#include "dpaa_eth.h" /* struct dpa_priv_s, dpa_percpu_priv_s, dpa_bp */
++
++#define DPA_DEBUGFS_DESCRIPTION "FSL DPAA Ethernet debugfs entries"
++#define DPA_ETH_DEBUGFS_ROOT "fsl_dpa"
++
++static struct dentry *dpa_debugfs_root;
++
++static int __cold dpa_debugfs_loop_open(struct inode *inode, struct file *file);
++static ssize_t dpa_loop_write(struct file *f,
++      const char __user *buf, size_t count, loff_t *off);
++
++static const struct file_operations dpa_debugfs_lp_fops = {
++      .open           = dpa_debugfs_loop_open,
++      .write          = dpa_loop_write,
++      .read           = seq_read,
++      .llseek         = seq_lseek,
++      .release        = single_release,
++};
++
++static int dpa_debugfs_loop_show(struct seq_file *file, void *offset)
++{
++      struct dpa_priv_s *priv;
++
++      BUG_ON(offset == NULL);
++
++      priv = netdev_priv((struct net_device *)file->private);
++      seq_printf(file, "%d->%d\n", priv->loop_id, priv->loop_to);
++
++      return 0;
++}
++
++static int user_input_convert(const char __user *user_buf, size_t count,
++                            long *val)
++{
++      char buf[12];
++
++      if (count > sizeof(buf) - 1)
++              return -EINVAL;
++      if (copy_from_user(buf, user_buf, count))
++              return -EFAULT;
++      buf[count] = '\0';
++      if (kstrtol(buf, 0, val))
++              return -EINVAL;
++      return 0;
++}
++
++static ssize_t dpa_loop_write(struct file *f,
++      const char __user *buf, size_t count, loff_t *off)
++{
++      struct dpa_priv_s *priv;
++      struct net_device *netdev;
++      struct seq_file *sf;
++      int ret;
++      long val;
++
++      ret = user_input_convert(buf, count, &val);
++      if (ret)
++              return ret;
++
++      sf = (struct seq_file *)f->private_data;
++      netdev = (struct net_device *)sf->private;
++      priv = netdev_priv(netdev);
++
++      priv->loop_to = ((val < 0) || (val > 20)) ? -1 : val;
++
++      return count;
++}
++
++static int __cold dpa_debugfs_loop_open(struct inode *inode, struct file *file)
++{
++      int                      _errno;
++      const struct net_device *net_dev;
++
++      _errno = single_open(file, dpa_debugfs_loop_show, inode->i_private);
++      if (unlikely(_errno < 0)) {
++              net_dev = (struct net_device *)inode->i_private;
++
++              if (netif_msg_drv((struct dpa_priv_s *)netdev_priv(net_dev)))
++                      netdev_err(net_dev, "single_open() = %d\n",
++                                      _errno);
++      }
++
++      return _errno;
++}
++
++
++int dpa_netdev_debugfs_create(struct net_device *net_dev)
++{
++      struct dpa_priv_s *priv = netdev_priv(net_dev);
++      static int cnt;
++      char loop_file_name[100];
++
++      if (unlikely(dpa_debugfs_root == NULL)) {
++              pr_err(KBUILD_MODNAME ": %s:%hu:%s(): \t%s\n",
++                                 KBUILD_BASENAME".c", __LINE__, __func__,
++                                 "root debugfs missing, possible module ordering issue");
++              return -ENOMEM;
++      }
++
++      sprintf(loop_file_name, "eth%d_loop", ++cnt);
++      priv->debugfs_loop_file = debugfs_create_file(loop_file_name,
++                                                       S_IRUGO,
++                                                       dpa_debugfs_root,
++                                                       net_dev,
++                                                       &dpa_debugfs_lp_fops);
++      if (unlikely(priv->debugfs_loop_file == NULL)) {
++              netdev_err(net_dev, "debugfs_create_file(%s/%s)",
++                              dpa_debugfs_root->d_iname,
++                              loop_file_name);
++
++              return -ENOMEM;
++      }
++      return 0;
++}
++
++void dpa_netdev_debugfs_remove(struct net_device *net_dev)
++{
++      struct dpa_priv_s *priv = netdev_priv(net_dev);
++
++      debugfs_remove(priv->debugfs_loop_file);
++}
++
++int __init dpa_debugfs_module_init(void)
++{
++      int      _errno = 0;
++
++      pr_info(KBUILD_MODNAME ": " DPA_DEBUGFS_DESCRIPTION "\n");
++
++      dpa_debugfs_root = debugfs_create_dir(DPA_ETH_DEBUGFS_ROOT, NULL);
++
++      if (unlikely(dpa_debugfs_root == NULL)) {
++              _errno = -ENOMEM;
++              pr_err(KBUILD_MODNAME ": %s:%hu:%s():\n",
++                                 KBUILD_BASENAME".c", __LINE__, __func__);
++              pr_err("\tdebugfs_create_dir(%s/"KBUILD_MODNAME") = %d\n",
++                         DPA_ETH_DEBUGFS_ROOT, _errno);
++      }
++
++      return _errno;
++}
++
++void __exit dpa_debugfs_module_exit(void)
++{
++      debugfs_remove(dpa_debugfs_root);
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.h
+@@ -0,0 +1,43 @@
++/* Copyright 2008-2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef DPAA_DEBUGFS_H_
++#define DPAA_DEBUGFS_H_
++
++#include <linux/netdevice.h>
++#include <linux/dcache.h>     /* struct dentry needed in dpaa_eth.h */
++
++int dpa_netdev_debugfs_create(struct net_device *net_dev);
++void dpa_netdev_debugfs_remove(struct net_device *net_dev);
++int __init dpa_debugfs_module_init(void);
++void __exit dpa_debugfs_module_exit(void);
++
++#endif /* DPAA_DEBUGFS_H_ */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
+@@ -0,0 +1,1210 @@
++/* Copyright 2008-2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
++      KBUILD_BASENAME".c", __LINE__, __func__
++#else
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": " fmt
++#endif
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/of_mdio.h>
++#include <linux/of_net.h>
++#include <linux/kthread.h>
++#include <linux/io.h>
++#include <linux/if_arp.h>     /* arp_hdr_len() */
++#include <linux/if_vlan.h>    /* VLAN_HLEN */
++#include <linux/icmp.h>               /* struct icmphdr */
++#include <linux/ip.h>         /* struct iphdr */
++#include <linux/ipv6.h>               /* struct ipv6hdr */
++#include <linux/udp.h>                /* struct udphdr */
++#include <linux/tcp.h>                /* struct tcphdr */
++#include <linux/net.h>                /* net_ratelimit() */
++#include <linux/if_ether.h>   /* ETH_P_IP and ETH_P_IPV6 */
++#include <linux/highmem.h>
++#include <linux/percpu.h>
++#include <linux/dma-mapping.h>
++#include <linux/fsl_bman.h>
++#ifdef CONFIG_SOC_BUS
++#include <linux/sys_soc.h>      /* soc_device_match */
++#endif
++
++#include "fsl_fman.h"
++#include "fm_ext.h"
++#include "fm_port_ext.h"
++
++#include "mac.h"
++#include "dpaa_eth.h"
++#include "dpaa_eth_common.h"
++#ifdef CONFIG_FSL_DPAA_DBG_LOOP
++#include "dpaa_debugfs.h"
++#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
++
++/* CREATE_TRACE_POINTS only needs to be defined once. Other dpa files
++ * using trace events only need to #include <trace/events/sched.h>
++ */
++#define CREATE_TRACE_POINTS
++#include "dpaa_eth_trace.h"
++
++#define DPA_NAPI_WEIGHT               64
++
++/* Valid checksum indication */
++#define DPA_CSUM_VALID                0xFFFF
++
++#define DPA_DESCRIPTION "FSL DPAA Ethernet driver"
++
++MODULE_LICENSE("Dual BSD/GPL");
++
++MODULE_AUTHOR("Andy Fleming <afleming@freescale.com>");
++
++MODULE_DESCRIPTION(DPA_DESCRIPTION);
++
++static uint8_t debug = -1;
++module_param(debug, byte, S_IRUGO);
++MODULE_PARM_DESC(debug, "Module/Driver verbosity level");
++
++/* This has to work in tandem with the DPA_CS_THRESHOLD_xxx values. */
++static uint16_t tx_timeout = 1000;
++module_param(tx_timeout, ushort, S_IRUGO);
++MODULE_PARM_DESC(tx_timeout, "The Tx timeout in ms");
++
++static const char rtx[][3] = {
++      [RX] = "RX",
++      [TX] = "TX"
++};
++
++#ifndef CONFIG_PPC
++bool dpaa_errata_a010022;
++EXPORT_SYMBOL(dpaa_errata_a010022);
++#endif
++
++/* BM */
++
++#define DPAA_ETH_MAX_PAD (L1_CACHE_BYTES * 8)
++
++static uint8_t dpa_priv_common_bpid;
++
++#ifdef CONFIG_FSL_DPAA_DBG_LOOP
++struct net_device *dpa_loop_netdevs[20];
++#endif
++
++#ifdef CONFIG_PM
++
++static int dpaa_suspend(struct device *dev)
++{
++      struct net_device       *net_dev;
++      struct dpa_priv_s       *priv;
++      struct mac_device       *mac_dev;
++      int                     err = 0;
++
++      net_dev = dev_get_drvdata(dev);
++
++      if (net_dev->flags & IFF_UP) {
++              priv = netdev_priv(net_dev);
++              mac_dev = priv->mac_dev;
++
++              if (priv->wol & DPAA_WOL_MAGIC) {
++                      err = priv->mac_dev->set_wol(mac_dev->port_dev[RX],
++                              priv->mac_dev->get_mac_handle(mac_dev), true);
++                      if (err) {
++                              netdev_err(net_dev, "set_wol() = %d\n", err);
++                              goto set_wol_failed;
++                      }
++              }
++
++              err = fm_port_suspend(mac_dev->port_dev[RX]);
++              if (err) {
++                      netdev_err(net_dev, "fm_port_suspend(RX) = %d\n", err);
++                      goto rx_port_suspend_failed;
++              }
++
++              err = fm_port_suspend(mac_dev->port_dev[TX]);
++              if (err) {
++                      netdev_err(net_dev, "fm_port_suspend(TX) = %d\n", err);
++                      goto tx_port_suspend_failed;
++              }
++      }
++
++      return 0;
++
++tx_port_suspend_failed:
++      fm_port_resume(mac_dev->port_dev[RX]);
++rx_port_suspend_failed:
++      if (priv->wol & DPAA_WOL_MAGIC) {
++              priv->mac_dev->set_wol(mac_dev->port_dev[RX],
++                      priv->mac_dev->get_mac_handle(mac_dev), false);
++      }
++set_wol_failed:
++      return err;
++}
++
++static int dpaa_resume(struct device *dev)
++{
++      struct net_device       *net_dev;
++      struct dpa_priv_s       *priv;
++      struct mac_device       *mac_dev;
++      int                     err = 0;
++
++      net_dev = dev_get_drvdata(dev);
++
++      if (net_dev->flags & IFF_UP) {
++              priv = netdev_priv(net_dev);
++              mac_dev = priv->mac_dev;
++
++              err = fm_mac_resume(mac_dev->get_mac_handle(mac_dev));
++              if (err) {
++                      netdev_err(net_dev, "fm_mac_resume = %d\n", err);
++                      goto resume_failed;
++              }
++
++              err = fm_port_resume(mac_dev->port_dev[TX]);
++              if (err) {
++                      netdev_err(net_dev, "fm_port_resume(TX) = %d\n", err);
++                      goto resume_failed;
++              }
++
++              err = fm_port_resume(mac_dev->port_dev[RX]);
++              if (err) {
++                      netdev_err(net_dev, "fm_port_resume(RX) = %d\n", err);
++                      goto resume_failed;
++              }
++
++              if (priv->wol & DPAA_WOL_MAGIC) {
++                      err = priv->mac_dev->set_wol(mac_dev->port_dev[RX],
++                              priv->mac_dev->get_mac_handle(mac_dev), false);
++                      if (err) {
++                              netdev_err(net_dev, "set_wol() = %d\n", err);
++                              goto resume_failed;
++                      }
++              }
++      }
++
++      return 0;
++
++resume_failed:
++      return err;
++}
++
++static const struct dev_pm_ops dpaa_pm_ops = {
++      .suspend = dpaa_suspend,
++      .resume = dpaa_resume,
++};
++
++#define DPAA_PM_OPS (&dpaa_pm_ops)
++
++#else /* CONFIG_PM */
++
++#define DPAA_PM_OPS NULL
++
++#endif /* CONFIG_PM */
++
++/* Checks whether the checksum field in Parse Results array is valid
++ * (equals 0xFFFF) and increments the .cse counter otherwise
++ */
++static inline void
++dpa_csum_validation(const struct dpa_priv_s   *priv,
++              struct dpa_percpu_priv_s *percpu_priv,
++              const struct qm_fd *fd)
++{
++      dma_addr_t addr = qm_fd_addr(fd);
++      struct dpa_bp *dpa_bp = priv->dpa_bp;
++      void *frm = phys_to_virt(addr);
++      fm_prs_result_t *parse_result;
++
++      if (unlikely(!frm))
++              return;
++
++      dma_sync_single_for_cpu(dpa_bp->dev, addr, DPA_RX_PRIV_DATA_SIZE +
++                              DPA_PARSE_RESULTS_SIZE, DMA_BIDIRECTIONAL);
++
++      parse_result = (fm_prs_result_t *)(frm + DPA_RX_PRIV_DATA_SIZE);
++
++      if (parse_result->cksum != DPA_CSUM_VALID)
++              percpu_priv->rx_errors.cse++;
++}
++
++static void _dpa_rx_error(struct net_device *net_dev,
++              const struct dpa_priv_s *priv,
++              struct dpa_percpu_priv_s *percpu_priv,
++              const struct qm_fd *fd,
++              u32 fqid)
++{
++      /* limit common, possibly innocuous Rx FIFO Overflow errors'
++       * interference with zero-loss convergence benchmark results.
++       */
++      if (likely(fd->status & FM_FD_STAT_ERR_PHYSICAL))
++              pr_warn_once("fsl-dpa: non-zero error counters in fman statistics (sysfs)\n");
++      else
++              if (netif_msg_hw(priv) && net_ratelimit())
++                      netdev_dbg(net_dev, "Err FD status = 0x%08x\n",
++                                      fd->status & FM_FD_STAT_RX_ERRORS);
++#ifdef CONFIG_FSL_DPAA_HOOKS
++      if (dpaa_eth_hooks.rx_error &&
++              dpaa_eth_hooks.rx_error(net_dev, fd, fqid) == DPAA_ETH_STOLEN)
++              /* it's up to the hook to perform resource cleanup */
++              return;
++#endif
++      percpu_priv->stats.rx_errors++;
++
++      if (fd->status & FM_PORT_FRM_ERR_DMA)
++              percpu_priv->rx_errors.dme++;
++      if (fd->status & FM_PORT_FRM_ERR_PHYSICAL)
++              percpu_priv->rx_errors.fpe++;
++      if (fd->status & FM_PORT_FRM_ERR_SIZE)
++              percpu_priv->rx_errors.fse++;
++      if (fd->status & FM_PORT_FRM_ERR_PRS_HDR_ERR)
++              percpu_priv->rx_errors.phe++;
++      if (fd->status & FM_FD_STAT_L4CV)
++              dpa_csum_validation(priv, percpu_priv, fd);
++
++      dpa_fd_release(net_dev, fd);
++}
++
++static void _dpa_tx_error(struct net_device           *net_dev,
++                        const struct dpa_priv_s       *priv,
++                        struct dpa_percpu_priv_s      *percpu_priv,
++                        const struct qm_fd            *fd,
++                        u32                            fqid)
++{
++      struct sk_buff *skb;
++
++      if (netif_msg_hw(priv) && net_ratelimit())
++              netdev_warn(net_dev, "FD status = 0x%08x\n",
++                              fd->status & FM_FD_STAT_TX_ERRORS);
++#ifdef CONFIG_FSL_DPAA_HOOKS
++      if (dpaa_eth_hooks.tx_error &&
++              dpaa_eth_hooks.tx_error(net_dev, fd, fqid) == DPAA_ETH_STOLEN)
++              /* now the hook must ensure proper cleanup */
++              return;
++#endif
++      percpu_priv->stats.tx_errors++;
++
++      /* If we intended the buffers from this frame to go into the bpools
++       * when the FMan transmit was done, we need to put it in manually.
++       */
++      if (fd->bpid != 0xff) {
++              dpa_fd_release(net_dev, fd);
++              return;
++      }
++
++      skb = _dpa_cleanup_tx_fd(priv, fd);
++      dev_kfree_skb(skb);
++}
++
++/* Helper function to factor out frame validation logic on all Rx paths. Its
++ * purpose is to extract from the Parse Results structure information about
++ * the integrity of the frame, its checksum, the length of the parsed headers
++ * and whether the frame is suitable for GRO.
++ *
++ * Assumes no parser errors, since any error frame is dropped before this
++ * function is called.
++ *
++ * @skb               will have its ip_summed field overwritten;
++ * @use_gro   will only be written with 0, if the frame is definitely not
++ *            GRO-able; otherwise, it will be left unchanged;
++ * @hdr_size  will be written with a safe value, at least the size of the
++ *            headers' length.
++ */
++void __hot _dpa_process_parse_results(const fm_prs_result_t *parse_results,
++                                    const struct qm_fd *fd,
++                                    struct sk_buff *skb, int *use_gro)
++{
++      if (fd->status & FM_FD_STAT_L4CV) {
++              /* The parser has run and performed L4 checksum validation.
++               * We know there were no parser errors (and implicitly no
++               * L4 csum error), otherwise we wouldn't be here.
++               */
++              skb->ip_summed = CHECKSUM_UNNECESSARY;
++
++              /* Don't go through GRO for certain types of traffic that
++               * we know are not GRO-able, such as dgram-based protocols.
++               * In the worst-case scenarios, such as small-pkt terminating
++               * UDP, the extra GRO processing would be overkill.
++               *
++               * The only protocol the Parser supports that is also GRO-able
++               * is currently TCP.
++               */
++              if (!fm_l4_frame_is_tcp(parse_results))
++                      *use_gro = 0;
++
++              return;
++      }
++
++      /* We're here because either the parser didn't run or the L4 checksum
++       * was not verified. This may include the case of a UDP frame with
++       * checksum zero or an L4 proto other than TCP/UDP
++       */
++      skb->ip_summed = CHECKSUM_NONE;
++
++      /* Bypass GRO for unknown traffic or if no PCDs are applied */
++      *use_gro = 0;
++}
++
++int dpaa_eth_poll(struct napi_struct *napi, int budget)
++{
++      struct dpa_napi_portal *np =
++                      container_of(napi, struct dpa_napi_portal, napi);
++
++      int cleaned = qman_p_poll_dqrr(np->p, budget);
++
++      if (cleaned < budget) {
++              int tmp;
++              napi_complete(napi);
++              tmp = qman_p_irqsource_add(np->p, QM_PIRQ_DQRI);
++              DPA_BUG_ON(tmp);
++      }
++
++      return cleaned;
++}
++EXPORT_SYMBOL(dpaa_eth_poll);
++
++static void __hot _dpa_tx_conf(struct net_device      *net_dev,
++                        const struct dpa_priv_s       *priv,
++                        struct dpa_percpu_priv_s      *percpu_priv,
++                        const struct qm_fd            *fd,
++                        u32                            fqid)
++{
++      struct sk_buff  *skb;
++
++      /* do we need the timestamp for the error frames? */
++
++      if (unlikely(fd->status & FM_FD_STAT_TX_ERRORS) != 0) {
++              if (netif_msg_hw(priv) && net_ratelimit())
++                      netdev_warn(net_dev, "FD status = 0x%08x\n",
++                                      fd->status & FM_FD_STAT_TX_ERRORS);
++
++              percpu_priv->stats.tx_errors++;
++      }
++
++      /* hopefully we need not get the timestamp before the hook */
++#ifdef CONFIG_FSL_DPAA_HOOKS
++      if (dpaa_eth_hooks.tx_confirm && dpaa_eth_hooks.tx_confirm(net_dev,
++              fd, fqid) == DPAA_ETH_STOLEN)
++              /* it's the hook that must now perform cleanup */
++              return;
++#endif
++      /* This might not perfectly reflect the reality, if the core dequeuing
++       * the Tx confirmation is different from the one that did the enqueue,
++       * but at least it'll show up in the total count.
++       */
++      percpu_priv->tx_confirm++;
++
++      skb = _dpa_cleanup_tx_fd(priv, fd);
++
++      dev_kfree_skb(skb);
++}
++
++enum qman_cb_dqrr_result
++priv_rx_error_dqrr(struct qman_portal         *portal,
++                    struct qman_fq                    *fq,
++                    const struct qm_dqrr_entry        *dq)
++{
++      struct net_device               *net_dev;
++      struct dpa_priv_s               *priv;
++      struct dpa_percpu_priv_s        *percpu_priv;
++      int                             *count_ptr;
++
++      net_dev = ((struct dpa_fq *)fq)->net_dev;
++      priv = netdev_priv(net_dev);
++
++      percpu_priv = raw_cpu_ptr(priv->percpu_priv);
++      count_ptr = raw_cpu_ptr(priv->dpa_bp->percpu_count);
++
++      if (dpaa_eth_napi_schedule(percpu_priv, portal))
++              return qman_cb_dqrr_stop;
++
++      if (unlikely(dpaa_eth_refill_bpools(priv->dpa_bp, count_ptr)))
++              /* Unable to refill the buffer pool due to insufficient
++               * system memory. Just release the frame back into the pool,
++               * otherwise we'll soon end up with an empty buffer pool.
++               */
++              dpa_fd_release(net_dev, &dq->fd);
++      else
++              _dpa_rx_error(net_dev, priv, percpu_priv, &dq->fd, fq->fqid);
++
++      return qman_cb_dqrr_consume;
++}
++
++
++enum qman_cb_dqrr_result __hot
++priv_rx_default_dqrr(struct qman_portal               *portal,
++                      struct qman_fq                  *fq,
++                      const struct qm_dqrr_entry      *dq)
++{
++      struct net_device               *net_dev;
++      struct dpa_priv_s               *priv;
++      struct dpa_percpu_priv_s        *percpu_priv;
++      int                             *count_ptr;
++      struct dpa_bp                   *dpa_bp;
++
++      net_dev = ((struct dpa_fq *)fq)->net_dev;
++      priv = netdev_priv(net_dev);
++      dpa_bp = priv->dpa_bp;
++
++      /* Trace the Rx fd */
++      trace_dpa_rx_fd(net_dev, fq, &dq->fd);
++
++      /* IRQ handler, non-migratable; safe to use raw_cpu_ptr here */
++      percpu_priv = raw_cpu_ptr(priv->percpu_priv);
++      count_ptr = raw_cpu_ptr(dpa_bp->percpu_count);
++
++      if (unlikely(dpaa_eth_napi_schedule(percpu_priv, portal)))
++              return qman_cb_dqrr_stop;
++
++      /* Vale of plenty: make sure we didn't run out of buffers */
++
++      if (unlikely(dpaa_eth_refill_bpools(dpa_bp, count_ptr)))
++              /* Unable to refill the buffer pool due to insufficient
++               * system memory. Just release the frame back into the pool,
++               * otherwise we'll soon end up with an empty buffer pool.
++               */
++              dpa_fd_release(net_dev, &dq->fd);
++      else
++              _dpa_rx(net_dev, portal, priv, percpu_priv, &dq->fd, fq->fqid,
++                      count_ptr);
++
++      return qman_cb_dqrr_consume;
++}
++
++enum qman_cb_dqrr_result
++priv_tx_conf_error_dqrr(struct qman_portal            *portal,
++                    struct qman_fq                    *fq,
++                    const struct qm_dqrr_entry        *dq)
++{
++      struct net_device               *net_dev;
++      struct dpa_priv_s               *priv;
++      struct dpa_percpu_priv_s        *percpu_priv;
++
++      net_dev = ((struct dpa_fq *)fq)->net_dev;
++      priv = netdev_priv(net_dev);
++
++      percpu_priv = raw_cpu_ptr(priv->percpu_priv);
++
++      if (dpaa_eth_napi_schedule(percpu_priv, portal))
++              return qman_cb_dqrr_stop;
++
++      _dpa_tx_error(net_dev, priv, percpu_priv, &dq->fd, fq->fqid);
++
++      return qman_cb_dqrr_consume;
++}
++
++enum qman_cb_dqrr_result __hot
++priv_tx_conf_default_dqrr(struct qman_portal          *portal,
++                      struct qman_fq                  *fq,
++                      const struct qm_dqrr_entry      *dq)
++{
++      struct net_device               *net_dev;
++      struct dpa_priv_s               *priv;
++      struct dpa_percpu_priv_s        *percpu_priv;
++
++      net_dev = ((struct dpa_fq *)fq)->net_dev;
++      priv = netdev_priv(net_dev);
++
++      /* Trace the fd */
++      trace_dpa_tx_conf_fd(net_dev, fq, &dq->fd);
++
++      /* Non-migratable context, safe to use raw_cpu_ptr */
++      percpu_priv = raw_cpu_ptr(priv->percpu_priv);
++
++      if (dpaa_eth_napi_schedule(percpu_priv, portal))
++              return qman_cb_dqrr_stop;
++
++      _dpa_tx_conf(net_dev, priv, percpu_priv, &dq->fd, fq->fqid);
++
++      return qman_cb_dqrr_consume;
++}
++
++void priv_ern(struct qman_portal      *portal,
++                     struct qman_fq           *fq,
++                     const struct qm_mr_entry *msg)
++{
++      struct net_device       *net_dev;
++      const struct dpa_priv_s *priv;
++      struct sk_buff *skb;
++      struct dpa_percpu_priv_s        *percpu_priv;
++      struct qm_fd fd = msg->ern.fd;
++
++      net_dev = ((struct dpa_fq *)fq)->net_dev;
++      priv = netdev_priv(net_dev);
++      /* Non-migratable context, safe to use raw_cpu_ptr */
++      percpu_priv = raw_cpu_ptr(priv->percpu_priv);
++
++      percpu_priv->stats.tx_dropped++;
++      percpu_priv->stats.tx_fifo_errors++;
++      count_ern(percpu_priv, msg);
++
++      /* If we intended this buffer to go into the pool
++       * when the FM was done, we need to put it in
++       * manually.
++       */
++      if (msg->ern.fd.bpid != 0xff) {
++              dpa_fd_release(net_dev, &fd);
++              return;
++      }
++
++      skb = _dpa_cleanup_tx_fd(priv, &fd);
++      dev_kfree_skb_any(skb);
++}
++
++const struct dpa_fq_cbs_t private_fq_cbs = {
++      .rx_defq = { .cb = { .dqrr = priv_rx_default_dqrr } },
++      .tx_defq = { .cb = { .dqrr = priv_tx_conf_default_dqrr } },
++      .rx_errq = { .cb = { .dqrr = priv_rx_error_dqrr } },
++      .tx_errq = { .cb = { .dqrr = priv_tx_conf_error_dqrr } },
++      .egress_ern = { .cb = { .ern = priv_ern } }
++};
++EXPORT_SYMBOL(private_fq_cbs);
++
++static void dpaa_eth_napi_enable(struct dpa_priv_s *priv)
++{
++      struct dpa_percpu_priv_s *percpu_priv;
++      int i, j;
++
++      for_each_possible_cpu(i) {
++              percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
++
++              for (j = 0; j < qman_portal_max; j++)
++                      napi_enable(&percpu_priv->np[j].napi);
++      }
++}
++
++static void dpaa_eth_napi_disable(struct dpa_priv_s *priv)
++{
++      struct dpa_percpu_priv_s *percpu_priv;
++      int i, j;
++
++      for_each_possible_cpu(i) {
++              percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
++
++              for (j = 0; j < qman_portal_max; j++)
++                      napi_disable(&percpu_priv->np[j].napi);
++      }
++}
++
++static int __cold dpa_eth_priv_start(struct net_device *net_dev)
++{
++      int err;
++      struct dpa_priv_s *priv;
++
++      priv = netdev_priv(net_dev);
++
++      dpaa_eth_napi_enable(priv);
++
++      err = dpa_start(net_dev);
++      if (err < 0)
++              dpaa_eth_napi_disable(priv);
++
++      return err;
++}
++
++
++
++static int __cold dpa_eth_priv_stop(struct net_device *net_dev)
++{
++      int _errno;
++      struct dpa_priv_s *priv;
++
++      _errno = dpa_stop(net_dev);
++      /* Allow NAPI to consume any frame still in the Rx/TxConfirm
++       * ingress queues. This is to avoid a race between the current
++       * context and ksoftirqd which could leave NAPI disabled while
++       * in fact there's still Rx traffic to be processed.
++       */
++      usleep_range(5000, 10000);
++
++      priv = netdev_priv(net_dev);
++      dpaa_eth_napi_disable(priv);
++
++      return _errno;
++}
++
++#ifdef CONFIG_NET_POLL_CONTROLLER
++static void dpaa_eth_poll_controller(struct net_device *net_dev)
++{
++      struct dpa_priv_s *priv = netdev_priv(net_dev);
++      struct dpa_percpu_priv_s *percpu_priv =
++              raw_cpu_ptr(priv->percpu_priv);
++      struct qman_portal *p;
++      const struct qman_portal_config *pc;
++      struct dpa_napi_portal *np;
++
++      p = (struct qman_portal *)qman_get_affine_portal(smp_processor_id());
++      pc = qman_p_get_portal_config(p);
++      np = &percpu_priv->np[pc->index];
++
++      qman_p_irqsource_remove(np->p, QM_PIRQ_DQRI);
++      qman_p_poll_dqrr(np->p, np->napi.weight);
++      qman_p_irqsource_add(np->p, QM_PIRQ_DQRI);
++}
++#endif
++
++static const struct net_device_ops dpa_private_ops = {
++      .ndo_open = dpa_eth_priv_start,
++      .ndo_start_xmit = dpa_tx,
++      .ndo_stop = dpa_eth_priv_stop,
++      .ndo_tx_timeout = dpa_timeout,
++      .ndo_get_stats64 = dpa_get_stats64,
++      .ndo_set_mac_address = dpa_set_mac_address,
++      .ndo_validate_addr = eth_validate_addr,
++#ifdef CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
++      .ndo_select_queue = dpa_select_queue,
++#endif
++      .ndo_change_mtu = dpa_change_mtu,
++      .ndo_set_rx_mode = dpa_set_rx_mode,
++      .ndo_init = dpa_ndo_init,
++      .ndo_set_features = dpa_set_features,
++      .ndo_fix_features = dpa_fix_features,
++      .ndo_do_ioctl = dpa_ioctl,
++#ifdef CONFIG_NET_POLL_CONTROLLER
++      .ndo_poll_controller = dpaa_eth_poll_controller,
++#endif
++};
++
++static int dpa_private_napi_add(struct net_device *net_dev)
++{
++      struct dpa_priv_s *priv = netdev_priv(net_dev);
++      struct dpa_percpu_priv_s *percpu_priv;
++      int i, cpu;
++
++      for_each_possible_cpu(cpu) {
++              percpu_priv = per_cpu_ptr(priv->percpu_priv, cpu);
++
++              percpu_priv->np = devm_kzalloc(net_dev->dev.parent,
++                      qman_portal_max * sizeof(struct dpa_napi_portal),
++                      GFP_KERNEL);
++
++              if (unlikely(percpu_priv->np == NULL)) {
++                      dev_err(net_dev->dev.parent, "devm_kzalloc() failed\n");
++                      return -ENOMEM;
++              }
++
++              for (i = 0; i < qman_portal_max; i++)
++                      netif_napi_add(net_dev, &percpu_priv->np[i].napi,
++                                      dpaa_eth_poll, DPA_NAPI_WEIGHT);
++      }
++
++      return 0;
++}
++
++void dpa_private_napi_del(struct net_device *net_dev)
++{
++      struct dpa_priv_s *priv = netdev_priv(net_dev);
++      struct dpa_percpu_priv_s *percpu_priv;
++      int i, cpu;
++
++      for_each_possible_cpu(cpu) {
++              percpu_priv = per_cpu_ptr(priv->percpu_priv, cpu);
++
++              if (percpu_priv->np) {
++                      for (i = 0; i < qman_portal_max; i++)
++                              netif_napi_del(&percpu_priv->np[i].napi);
++
++                      devm_kfree(net_dev->dev.parent, percpu_priv->np);
++              }
++      }
++}
++EXPORT_SYMBOL(dpa_private_napi_del);
++
++static int dpa_private_netdev_init(struct net_device *net_dev)
++{
++      int i;
++      struct dpa_priv_s *priv = netdev_priv(net_dev);
++      struct dpa_percpu_priv_s *percpu_priv;
++      const uint8_t *mac_addr;
++
++      /* Although we access another CPU's private data here
++       * we do it at initialization so it is safe
++       */
++      for_each_possible_cpu(i) {
++              percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
++              percpu_priv->net_dev = net_dev;
++      }
++
++      net_dev->netdev_ops = &dpa_private_ops;
++      mac_addr = priv->mac_dev->addr;
++
++      net_dev->mem_start = priv->mac_dev->res->start;
++      net_dev->mem_end = priv->mac_dev->res->end;
++
++      net_dev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
++              NETIF_F_LLTX);
++
++      /* Advertise S/G and HIGHDMA support for private interfaces */
++      net_dev->hw_features |= NETIF_F_SG | NETIF_F_HIGHDMA;
++      /* Recent kernels enable GSO automatically, if
++       * we declare NETIF_F_SG. For conformity, we'll
++       * still declare GSO explicitly.
++       */
++      net_dev->features |= NETIF_F_GSO;
++
++      /* Advertise GRO support */
++      net_dev->features |= NETIF_F_GRO;
++
++      return dpa_netdev_init(net_dev, mac_addr, tx_timeout);
++}
++
++static struct dpa_bp * __cold
++dpa_priv_bp_probe(struct device *dev)
++{
++      struct dpa_bp *dpa_bp;
++
++      dpa_bp = devm_kzalloc(dev, sizeof(*dpa_bp), GFP_KERNEL);
++      if (unlikely(dpa_bp == NULL)) {
++              dev_err(dev, "devm_kzalloc() failed\n");
++              return ERR_PTR(-ENOMEM);
++      }
++
++      dpa_bp->percpu_count = devm_alloc_percpu(dev, *dpa_bp->percpu_count);
++      dpa_bp->target_count = CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT;
++
++      dpa_bp->seed_cb = dpa_bp_priv_seed;
++      dpa_bp->free_buf_cb = _dpa_bp_free_pf;
++
++      return dpa_bp;
++}
++
++/* Place all ingress FQs (Rx Default, Rx Error, PCD FQs) in a dedicated CGR.
++ * We won't be sending congestion notifications to FMan; for now, we just use
++ * this CGR to generate enqueue rejections to FMan in order to drop the frames
++ * before they reach our ingress queues and eat up memory.
++ */
++static int dpaa_eth_priv_ingress_cgr_init(struct dpa_priv_s *priv)
++{
++      struct qm_mcc_initcgr initcgr;
++      u32 cs_th;
++      int err;
++
++      err = qman_alloc_cgrid(&priv->ingress_cgr.cgrid);
++      if (err < 0) {
++              pr_err("Error %d allocating CGR ID\n", err);
++              goto out_error;
++      }
++
++      /* Enable CS TD, but disable Congestion State Change Notifications. */
++      initcgr.we_mask = QM_CGR_WE_CS_THRES;
++      initcgr.cgr.cscn_en = QM_CGR_EN;
++      cs_th = CONFIG_FSL_DPAA_INGRESS_CS_THRESHOLD;
++      qm_cgr_cs_thres_set64(&initcgr.cgr.cs_thres, cs_th, 1);
++
++      initcgr.we_mask |= QM_CGR_WE_CSTD_EN;
++      initcgr.cgr.cstd_en = QM_CGR_EN;
++
++      /* This is actually a hack, because this CGR will be associated with
++       * our affine SWP. However, we'll place our ingress FQs in it.
++       */
++      err = qman_create_cgr(&priv->ingress_cgr, QMAN_CGR_FLAG_USE_INIT,
++              &initcgr);
++      if (err < 0) {
++              pr_err("Error %d creating ingress CGR with ID %d\n", err,
++                      priv->ingress_cgr.cgrid);
++              qman_release_cgrid(priv->ingress_cgr.cgrid);
++              goto out_error;
++      }
++      pr_debug("Created ingress CGR %d for netdev with hwaddr %pM\n",
++               priv->ingress_cgr.cgrid, priv->mac_dev->addr);
++
++      /* struct qman_cgr allows special cgrid values (i.e. outside the 0..255
++       * range), but we have no common initialization path between the
++       * different variants of the DPAA Eth driver, so we do it here rather
++       * than modifying every other variant than "private Eth".
++       */
++      priv->use_ingress_cgr = true;
++
++out_error:
++      return err;
++}
++
++static int dpa_priv_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp,
++              size_t count)
++{
++      struct dpa_priv_s *priv = netdev_priv(net_dev);
++      int i;
++
++      if (netif_msg_probe(priv))
++              dev_dbg(net_dev->dev.parent,
++                      "Using private BM buffer pools\n");
++
++      priv->bp_count = count;
++
++      for (i = 0; i < count; i++) {
++              int err;
++              err = dpa_bp_alloc(&dpa_bp[i]);
++              if (err < 0) {
++                      dpa_bp_free(priv);
++                      priv->dpa_bp = NULL;
++                      return err;
++              }
++
++              priv->dpa_bp = &dpa_bp[i];
++      }
++
++      dpa_priv_common_bpid = priv->dpa_bp->bpid;
++      return 0;
++}
++
++static const struct of_device_id dpa_match[];
++
++#ifdef CONFIG_FSL_DPAA_DBG_LOOP
++static int dpa_new_loop_id(void)
++{
++      static int if_id;
++
++      return if_id++;
++}
++#endif
++
++static int
++dpaa_eth_priv_probe(struct platform_device *_of_dev)
++{
++      int err = 0, i, channel;
++      struct device *dev;
++      struct device_node *dpa_node;
++      struct dpa_bp *dpa_bp;
++      size_t count = 1;
++      struct net_device *net_dev = NULL;
++      struct dpa_priv_s *priv = NULL;
++      struct dpa_percpu_priv_s *percpu_priv;
++      struct fm_port_fqs port_fqs;
++      struct dpa_buffer_layout_s *buf_layout = NULL;
++      struct mac_device *mac_dev;
++
++      dev = &_of_dev->dev;
++
++      dpa_node = dev->of_node;
++
++      if (!of_device_is_available(dpa_node))
++              return -ENODEV;
++
++      /* Get the buffer pools assigned to this interface;
++       * run only once the default pool probing code
++       */
++      dpa_bp = (dpa_bpid2pool(dpa_priv_common_bpid)) ? :
++                      dpa_priv_bp_probe(dev);
++      if (IS_ERR(dpa_bp))
++              return PTR_ERR(dpa_bp);
++
++      /* Allocate this early, so we can store relevant information in
++       * the private area (needed by 1588 code in dpa_mac_probe)
++       */
++      net_dev = alloc_etherdev_mq(sizeof(*priv), DPAA_ETH_TX_QUEUES);
++      if (!net_dev) {
++              dev_err(dev, "alloc_etherdev_mq() failed\n");
++              goto alloc_etherdev_mq_failed;
++      }
++
++      /* Do this here, so we can be verbose early */
++      SET_NETDEV_DEV(net_dev, dev);
++      dev_set_drvdata(dev, net_dev);
++
++      priv = netdev_priv(net_dev);
++      priv->net_dev = net_dev;
++      strcpy(priv->if_type, "private");
++
++      priv->msg_enable = netif_msg_init(debug, -1);
++
++#ifdef CONFIG_FSL_DPAA_DBG_LOOP
++      priv->loop_id = dpa_new_loop_id();
++      priv->loop_to = -1; /* disabled by default */
++      dpa_loop_netdevs[priv->loop_id] = net_dev;
++#endif
++
++      mac_dev = dpa_mac_probe(_of_dev);
++      if (IS_ERR(mac_dev) || !mac_dev) {
++              err = PTR_ERR(mac_dev);
++              goto mac_probe_failed;
++      }
++
++      /* We have physical ports, so we need to establish
++       * the buffer layout.
++       */
++      buf_layout = devm_kzalloc(dev, 2 * sizeof(*buf_layout),
++                                GFP_KERNEL);
++      if (!buf_layout) {
++              dev_err(dev, "devm_kzalloc() failed\n");
++              goto alloc_failed;
++      }
++      dpa_set_buffers_layout(mac_dev, buf_layout);
++
++      /* For private ports, need to compute the size of the default
++       * buffer pool, based on FMan port buffer layout;also update
++       * the maximum buffer size for private ports if necessary
++       */
++      dpa_bp->size = dpa_bp_size(&buf_layout[RX]);
++
++#ifdef CONFIG_FSL_DPAA_ETH_JUMBO_FRAME
++      /* We only want to use jumbo frame optimization if we actually have
++       * L2 MAX FRM set for jumbo frames as well.
++       */
++#ifndef CONFIG_PPC
++      if (likely(!dpaa_errata_a010022))
++#endif
++      if(fm_get_max_frm() < 9600)
++              dev_warn(dev,
++                      "Invalid configuration: if jumbo frames support is on, FSL_FM_MAX_FRAME_SIZE should be set to 9600\n");
++#endif
++
++      INIT_LIST_HEAD(&priv->dpa_fq_list);
++
++      memset(&port_fqs, 0, sizeof(port_fqs));
++
++      err = dpa_fq_probe_mac(dev, &priv->dpa_fq_list, &port_fqs, true, RX);
++      if (!err)
++              err = dpa_fq_probe_mac(dev, &priv->dpa_fq_list,
++                                     &port_fqs, true, TX);
++
++      if (err < 0)
++              goto fq_probe_failed;
++
++      /* bp init */
++
++      err = dpa_priv_bp_create(net_dev, dpa_bp, count);
++
++      if (err < 0)
++              goto bp_create_failed;
++
++      priv->mac_dev = mac_dev;
++
++      channel = dpa_get_channel();
++
++      if (channel < 0) {
++              err = channel;
++              goto get_channel_failed;
++      }
++
++      priv->channel = (uint16_t)channel;
++      dpaa_eth_add_channel(priv->channel);
++
++      dpa_fq_setup(priv, &private_fq_cbs, priv->mac_dev->port_dev[TX]);
++
++      /* Create a congestion group for this netdev, with
++       * dynamically-allocated CGR ID.
++       * Must be executed after probing the MAC, but before
++       * assigning the egress FQs to the CGRs.
++       */
++      err = dpaa_eth_cgr_init(priv);
++      if (err < 0) {
++              dev_err(dev, "Error initializing CGR\n");
++              goto tx_cgr_init_failed;
++      }
++      err = dpaa_eth_priv_ingress_cgr_init(priv);
++      if (err < 0) {
++              dev_err(dev, "Error initializing ingress CGR\n");
++              goto rx_cgr_init_failed;
++      }
++
++      /* Add the FQs to the interface, and make them active */
++      err = dpa_fqs_init(dev,  &priv->dpa_fq_list, false);
++      if (err < 0)
++              goto fq_alloc_failed;
++
++      priv->buf_layout = buf_layout;
++      priv->tx_headroom = dpa_get_headroom(&priv->buf_layout[TX]);
++      priv->rx_headroom = dpa_get_headroom(&priv->buf_layout[RX]);
++
++      /* All real interfaces need their ports initialized */
++      dpaa_eth_init_ports(mac_dev, dpa_bp, count, &port_fqs,
++                      buf_layout, dev);
++
++#ifdef CONFIG_FMAN_PFC
++      for (i = 0; i < CONFIG_FMAN_PFC_COS_COUNT; i++) {
++              err = fm_port_set_pfc_priorities_mapping_to_qman_wq(
++                              mac_dev->port_dev[TX], i, i);
++              if (unlikely(err != 0)) {
++                      dev_err(dev, "Error maping PFC %u to WQ %u\n", i, i);
++                      goto pfc_mapping_failed;
++              }
++      }
++#endif
++
++      priv->percpu_priv = devm_alloc_percpu(dev, *priv->percpu_priv);
++
++      if (priv->percpu_priv == NULL) {
++              dev_err(dev, "devm_alloc_percpu() failed\n");
++              err = -ENOMEM;
++              goto alloc_percpu_failed;
++      }
++      for_each_possible_cpu(i) {
++              percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
++              memset(percpu_priv, 0, sizeof(*percpu_priv));
++      }
++
++      /* Initialize NAPI */
++      err = dpa_private_napi_add(net_dev);
++
++      if (err < 0)
++              goto napi_add_failed;
++
++      err = dpa_private_netdev_init(net_dev);
++
++      if (err < 0)
++              goto netdev_init_failed;
++
++      dpaa_eth_sysfs_init(&net_dev->dev);
++
++#ifdef CONFIG_PM
++      device_set_wakeup_capable(dev, true);
++#endif
++
++      pr_info("fsl_dpa: Probed interface %s\n", net_dev->name);
++
++      return 0;
++
++netdev_init_failed:
++napi_add_failed:
++      dpa_private_napi_del(net_dev);
++alloc_percpu_failed:
++#ifdef CONFIG_FMAN_PFC
++pfc_mapping_failed:
++#endif
++      dpa_fq_free(dev, &priv->dpa_fq_list);
++fq_alloc_failed:
++      qman_delete_cgr_safe(&priv->ingress_cgr);
++      qman_release_cgrid(priv->ingress_cgr.cgrid);
++rx_cgr_init_failed:
++      qman_delete_cgr_safe(&priv->cgr_data.cgr);
++      qman_release_cgrid(priv->cgr_data.cgr.cgrid);
++tx_cgr_init_failed:
++get_channel_failed:
++      dpa_bp_free(priv);
++bp_create_failed:
++fq_probe_failed:
++alloc_failed:
++mac_probe_failed:
++      dev_set_drvdata(dev, NULL);
++      free_netdev(net_dev);
++alloc_etherdev_mq_failed:
++      if (atomic_read(&dpa_bp->refs) == 0)
++              devm_kfree(dev, dpa_bp);
++
++      return err;
++}
++
++static const struct of_device_id dpa_match[] = {
++      {
++              .compatible     = "fsl,dpa-ethernet"
++      },
++      {}
++};
++MODULE_DEVICE_TABLE(of, dpa_match);
++
++static struct platform_driver dpa_driver = {
++      .driver = {
++              .name           = KBUILD_MODNAME,
++              .of_match_table = dpa_match,
++              .owner          = THIS_MODULE,
++              .pm             = DPAA_PM_OPS,
++      },
++      .probe          = dpaa_eth_priv_probe,
++      .remove         = dpa_remove
++};
++
++#ifndef CONFIG_PPC
++static bool __init __cold soc_has_errata_a010022(void)
++{
++#ifdef CONFIG_SOC_BUS
++      const struct soc_device_attribute soc_msi_matches[] = {
++              { .family = "QorIQ LS1043A",
++                .data = NULL },
++              { },
++      };
++
++      if (soc_device_match(soc_msi_matches))
++              return true;
++
++      return false;
++#else
++      return true; /* cannot identify SoC */
++#endif
++}
++#endif
++
++static int __init __cold dpa_load(void)
++{
++      int      _errno;
++
++      pr_info(DPA_DESCRIPTION "\n");
++
++#ifdef CONFIG_FSL_DPAA_DBG_LOOP
++      dpa_debugfs_module_init();
++#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
++
++      /* initialise dpaa_eth mirror values */
++      dpa_rx_extra_headroom = fm_get_rx_extra_headroom();
++      dpa_max_frm = fm_get_max_frm();
++      dpa_num_cpus = num_possible_cpus();
++
++#ifndef CONFIG_PPC
++      /* Detect if the current SoC requires the 4K alignment workaround */
++      dpaa_errata_a010022 = soc_has_errata_a010022();
++#endif
++
++#ifdef CONFIG_FSL_DPAA_DBG_LOOP
++      memset(dpa_loop_netdevs, 0, sizeof(dpa_loop_netdevs));
++#endif
++
++      _errno = platform_driver_register(&dpa_driver);
++      if (unlikely(_errno < 0)) {
++              pr_err(KBUILD_MODNAME
++                      ": %s:%hu:%s(): platform_driver_register() = %d\n",
++                      KBUILD_BASENAME".c", __LINE__, __func__, _errno);
++      }
++
++      pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
++              KBUILD_BASENAME".c", __func__);
++
++      return _errno;
++}
++module_init(dpa_load);
++
++static void __exit __cold dpa_unload(void)
++{
++      pr_debug(KBUILD_MODNAME ": -> %s:%s()\n",
++              KBUILD_BASENAME".c", __func__);
++
++      platform_driver_unregister(&dpa_driver);
++
++#ifdef CONFIG_FSL_DPAA_DBG_LOOP
++      dpa_debugfs_module_exit();
++#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
++
++      /* Only one channel is used and needs to be relased after all
++       * interfaces are removed
++       */
++      dpa_release_channel();
++
++      pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
++              KBUILD_BASENAME".c", __func__);
++}
++module_exit(dpa_unload);
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
+@@ -0,0 +1,697 @@
++/* Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __DPA_H
++#define __DPA_H
++
++#include <linux/netdevice.h>
++#include <linux/fsl_qman.h>   /* struct qman_fq */
++
++#include "fm_ext.h"
++#include "dpaa_eth_trace.h"
++
++extern int dpa_rx_extra_headroom;
++extern int dpa_max_frm;
++extern int dpa_num_cpus;
++
++#define dpa_get_rx_extra_headroom() dpa_rx_extra_headroom
++#define dpa_get_max_frm() dpa_max_frm
++
++#define dpa_get_max_mtu()     \
++      (dpa_get_max_frm() - (VLAN_ETH_HLEN + ETH_FCS_LEN))
++
++#define __hot
++
++/* Simple enum of FQ types - used for array indexing */
++enum port_type {RX, TX};
++
++/* TODO: This structure should be renamed & moved to the FMD wrapper */
++struct dpa_buffer_layout_s {
++      uint16_t        priv_data_size;
++      bool            parse_results;
++      bool            time_stamp;
++      bool            hash_results;
++      uint8_t         manip_extra_space;
++      uint16_t        data_align;
++};
++
++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
++#define DPA_BUG_ON(cond)      BUG_ON(cond)
++#else
++#define DPA_BUG_ON(cond)
++#endif
++
++#define DPA_TX_PRIV_DATA_SIZE 16
++#define DPA_PARSE_RESULTS_SIZE sizeof(fm_prs_result_t)
++#define DPA_TIME_STAMP_SIZE 8
++#define DPA_HASH_RESULTS_SIZE 8
++#define DPA_RX_PRIV_DATA_SIZE   (DPA_TX_PRIV_DATA_SIZE + \
++                                      dpa_get_rx_extra_headroom())
++
++#define FM_FD_STAT_RX_ERRORS                                          \
++      (FM_PORT_FRM_ERR_DMA | FM_PORT_FRM_ERR_PHYSICAL | \
++       FM_PORT_FRM_ERR_SIZE | FM_PORT_FRM_ERR_CLS_DISCARD | \
++       FM_PORT_FRM_ERR_EXTRACTION | FM_PORT_FRM_ERR_NO_SCHEME | \
++       FM_PORT_FRM_ERR_ILL_PLCR | FM_PORT_FRM_ERR_PRS_TIMEOUT | \
++       FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | FM_PORT_FRM_ERR_PRS_HDR_ERR)
++
++#define FM_FD_STAT_TX_ERRORS \
++      (FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT | \
++       FM_PORT_FRM_ERR_LENGTH | FM_PORT_FRM_ERR_DMA)
++
++#ifndef CONFIG_FSL_DPAA_ETH_JUMBO_FRAME
++/* The raw buffer size must be cacheline aligned.
++ * Normally we use 2K buffers.
++ */
++#define DPA_BP_RAW_SIZE               2048
++#else
++/* For jumbo frame optimizations, use buffers large enough to accommodate
++ * 9.6K frames, FD maximum offset, skb sh_info overhead and some extra
++ * space to account for further alignments.
++ */
++#define DPA_MAX_FRM_SIZE      9600
++#ifdef CONFIG_PPC
++#define DPA_BP_RAW_SIZE \
++      ((DPA_MAX_FRM_SIZE + DPA_MAX_FD_OFFSET + \
++        sizeof(struct skb_shared_info) + 128) & ~(SMP_CACHE_BYTES - 1))
++#else /* CONFIG_PPC */
++#define DPA_BP_RAW_SIZE ((unlikely(dpaa_errata_a010022)) ? 2048 : \
++      ((DPA_MAX_FRM_SIZE + DPA_MAX_FD_OFFSET + \
++        sizeof(struct skb_shared_info) + 128) & ~(SMP_CACHE_BYTES - 1)))
++#endif /* CONFIG_PPC */
++#endif /* CONFIG_FSL_DPAA_ETH_JUMBO_FRAME */
++
++/* This is what FMan is ever allowed to use.
++ * FMan-DMA requires 16-byte alignment for Rx buffers, but SKB_DATA_ALIGN is
++ * even stronger (SMP_CACHE_BYTES-aligned), so we just get away with that,
++ * via SKB_WITH_OVERHEAD(). We can't rely on netdev_alloc_frag() giving us
++ * half-page-aligned buffers (can we?), so we reserve some more space
++ * for start-of-buffer alignment.
++ */
++#define dpa_bp_size(buffer_layout)    (SKB_WITH_OVERHEAD(DPA_BP_RAW_SIZE) - \
++                                              SMP_CACHE_BYTES)
++/* We must ensure that skb_shinfo is always cacheline-aligned. */
++#define DPA_SKB_SIZE(size)    ((size) & ~(SMP_CACHE_BYTES - 1))
++
++/* Maximum size of a buffer for which recycling is allowed.
++ * We need an upper limit such that forwarded skbs that get reallocated on Tx
++ * aren't allowed to grow unboundedly. On the other hand, we need to make sure
++ * that skbs allocated by us will not fail to be recycled due to their size.
++ *
++ * For a requested size, the kernel allocator provides the next power of two
++ * sized block, which the stack will use as is, regardless of the actual size
++ * it required; since we must accommodate at most 9.6K buffers (L2 maximum
++ * supported frame size), set the recycling upper limit to 16K.
++ */
++#define DPA_RECYCLE_MAX_SIZE  16384
++
++#if defined(CONFIG_FSL_SDK_FMAN_TEST)
++/*TODO: temporary for fman pcd testing */
++#define FMAN_PCD_TESTS_MAX_NUM_RANGES 20
++#endif
++
++#define DPAA_ETH_FQ_DELTA     0x10000
++
++#define DPAA_ETH_PCD_FQ_BASE(device_addr) \
++      (((device_addr) & 0x1fffff) >> 6)
++
++#define DPAA_ETH_PCD_FQ_HI_PRIO_BASE(device_addr) \
++      (DPAA_ETH_FQ_DELTA + DPAA_ETH_PCD_FQ_BASE(device_addr))
++
++/* Largest value that the FQD's OAL field can hold.
++ * This is DPAA-1.x specific.
++ * TODO: This rather belongs in fsl_qman.h
++ */
++#define FSL_QMAN_MAX_OAL      127
++
++/* Maximum offset value for a contig or sg FD (represented on 9 bits) */
++#define DPA_MAX_FD_OFFSET     ((1 << 9) - 1)
++
++/* Default alignment for start of data in an Rx FD */
++#define DPA_FD_DATA_ALIGNMENT  16
++
++/* Values for the L3R field of the FM Parse Results
++ */
++/* L3 Type field: First IP Present IPv4 */
++#define FM_L3_PARSE_RESULT_IPV4       0x8000
++/* L3 Type field: First IP Present IPv6 */
++#define FM_L3_PARSE_RESULT_IPV6       0x4000
++
++/* Values for the L4R field of the FM Parse Results
++ * See $8.8.4.7.20 - L4 HXS - L4 Results from DPAA-Rev2 Reference Manual.
++ */
++/* L4 Type field: UDP */
++#define FM_L4_PARSE_RESULT_UDP        0x40
++/* L4 Type field: TCP */
++#define FM_L4_PARSE_RESULT_TCP        0x20
++/* FD status field indicating whether the FM Parser has attempted to validate
++ * the L4 csum of the frame.
++ * Note that having this bit set doesn't necessarily imply that the checksum
++ * is valid. One would have to check the parse results to find that out.
++ */
++#define FM_FD_STAT_L4CV               0x00000004
++
++
++#define FM_FD_STAT_ERR_PHYSICAL       FM_PORT_FRM_ERR_PHYSICAL
++
++/* Check if the parsed frame was found to be a TCP segment.
++ *
++ * @parse_result_ptr must be of type (fm_prs_result_t *).
++ */
++#define fm_l4_frame_is_tcp(parse_result_ptr) \
++      ((parse_result_ptr)->l4r & FM_L4_PARSE_RESULT_TCP)
++
++/* number of Tx queues to FMan */
++#ifdef CONFIG_FMAN_PFC
++#define DPAA_ETH_TX_QUEUES    (NR_CPUS * CONFIG_FMAN_PFC_COS_COUNT)
++#else
++#define DPAA_ETH_TX_QUEUES    NR_CPUS
++#endif
++
++#define DPAA_ETH_RX_QUEUES    128
++
++/* Convenience macros for storing/retrieving the skb back-pointers. They must
++ * accommodate both recycling and confirmation paths - i.e. cases when the buf
++ * was allocated by ourselves, respectively by the stack. In the former case,
++ * we could store the skb at negative offset; in the latter case, we can't,
++ * so we'll use 0 as offset.
++ *
++ * NB: @off is an offset from a (struct sk_buff **) pointer!
++ */
++#define DPA_WRITE_SKB_PTR(skb, skbh, addr, off) \
++{ \
++      skbh = (struct sk_buff **)addr; \
++      *(skbh + (off)) = skb; \
++}
++#define DPA_READ_SKB_PTR(skb, skbh, addr, off) \
++{ \
++      skbh = (struct sk_buff **)addr; \
++      skb = *(skbh + (off)); \
++}
++
++#ifdef CONFIG_PM
++/* Magic Packet wakeup */
++#define DPAA_WOL_MAGIC                0x00000001
++#endif
++
++#if defined(CONFIG_FSL_SDK_FMAN_TEST)
++struct pcd_range {
++      uint32_t                         base;
++      uint32_t                         count;
++};
++#endif
++
++/* More detailed FQ types - used for fine-grained WQ assignments */
++enum dpa_fq_type {
++      FQ_TYPE_RX_DEFAULT = 1, /* Rx Default FQs */
++      FQ_TYPE_RX_ERROR,       /* Rx Error FQs */
++      FQ_TYPE_RX_PCD,         /* User-defined PCDs */
++      FQ_TYPE_TX,             /* "Real" Tx FQs */
++      FQ_TYPE_TX_CONFIRM,     /* Tx default Conf FQ (actually an Rx FQ) */
++      FQ_TYPE_TX_CONF_MQ,     /* Tx conf FQs (one for each Tx FQ) */
++      FQ_TYPE_TX_ERROR,       /* Tx Error FQs (these are actually Rx FQs) */
++      FQ_TYPE_RX_PCD_HI_PRIO, /* User-defined high-priority PCDs */
++};
++
++struct dpa_fq {
++      struct qman_fq           fq_base;
++      struct list_head         list;
++      struct net_device       *net_dev;
++      bool                     init;
++      uint32_t fqid;
++      uint32_t flags;
++      uint16_t channel;
++      uint8_t wq;
++      enum dpa_fq_type fq_type;
++};
++
++struct dpa_fq_cbs_t {
++      struct qman_fq rx_defq;
++      struct qman_fq tx_defq;
++      struct qman_fq rx_errq;
++      struct qman_fq tx_errq;
++      struct qman_fq egress_ern;
++};
++
++struct fqid_cell {
++      uint32_t start;
++      uint32_t count;
++};
++
++struct dpa_bp {
++      struct bman_pool                *pool;
++      uint8_t                         bpid;
++      struct device                   *dev;
++      union {
++              /* The buffer pools used for the private ports are initialized
++               * with target_count buffers for each CPU; at runtime the
++               * number of buffers per CPU is constantly brought back to this
++               * level
++               */
++              int target_count;
++              /* The configured value for the number of buffers in the pool,
++               * used for shared port buffer pools
++               */
++              int config_count;
++      };
++      size_t                          size;
++      bool                            seed_pool;
++      /* physical address of the contiguous memory used by the pool to store
++       * the buffers
++       */
++      dma_addr_t                      paddr;
++      /* virtual address of the contiguous memory used by the pool to store
++       * the buffers
++       */
++      void __iomem                    *vaddr;
++      /* current number of buffers in the bpool alloted to this CPU */
++      int __percpu *percpu_count;
++      atomic_t refs;
++      /* some bpools need to be seeded before use by this cb */
++      int (*seed_cb)(struct dpa_bp *);
++      /* some bpools need to be emptied before freeing; this cb is used
++       * for freeing of individual buffers taken from the pool
++       */
++      void (*free_buf_cb)(void *addr);
++};
++
++struct dpa_rx_errors {
++      u64 dme;                /* DMA Error */
++      u64 fpe;                /* Frame Physical Error */
++      u64 fse;                /* Frame Size Error */
++      u64 phe;                /* Header Error */
++      u64 cse;                /* Checksum Validation Error */
++};
++
++/* Counters for QMan ERN frames - one counter per rejection code */
++struct dpa_ern_cnt {
++      u64 cg_tdrop;           /* Congestion group taildrop */
++      u64 wred;               /* WRED congestion */
++      u64 err_cond;           /* Error condition */
++      u64 early_window;       /* Order restoration, frame too early */
++      u64 late_window;        /* Order restoration, frame too late */
++      u64 fq_tdrop;           /* FQ taildrop */
++      u64 fq_retired;         /* FQ is retired */
++      u64 orp_zero;           /* ORP disabled */
++};
++
++struct dpa_napi_portal {
++      struct napi_struct napi;
++      struct qman_portal *p;
++};
++
++struct dpa_percpu_priv_s {
++      struct net_device *net_dev;
++      struct dpa_napi_portal *np;
++      u64 in_interrupt;
++      u64 tx_returned;
++      u64 tx_confirm;
++      /* fragmented (non-linear) skbuffs received from the stack */
++      u64 tx_frag_skbuffs;
++      /* number of S/G frames received */
++      u64 rx_sg;
++
++      struct rtnl_link_stats64 stats;
++      struct dpa_rx_errors rx_errors;
++      struct dpa_ern_cnt ern_cnt;
++};
++
++struct dpa_priv_s {
++      struct dpa_percpu_priv_s        __percpu *percpu_priv;
++      struct dpa_bp *dpa_bp;
++      /* Store here the needed Tx headroom for convenience and speed
++       * (even though it can be computed based on the fields of buf_layout)
++       */
++      uint16_t tx_headroom;
++      struct net_device *net_dev;
++      struct mac_device       *mac_dev;
++      struct qman_fq          *egress_fqs[DPAA_ETH_TX_QUEUES];
++      struct qman_fq          *conf_fqs[DPAA_ETH_TX_QUEUES];
++
++      size_t bp_count;
++
++      uint16_t                 channel;       /* "fsl,qman-channel-id" */
++      struct list_head         dpa_fq_list;
++
++#ifdef CONFIG_FSL_DPAA_DBG_LOOP
++      struct dentry           *debugfs_loop_file;
++#endif
++
++      uint32_t                 msg_enable;    /* net_device message level */
++#ifdef CONFIG_FSL_DPAA_1588
++      struct dpa_ptp_tsu       *tsu;
++#endif
++
++#if defined(CONFIG_FSL_SDK_FMAN_TEST)
++/* TODO: this is temporary until pcd support is implemented in dpaa */
++      int                     priv_pcd_num_ranges;
++      struct pcd_range        priv_pcd_ranges[FMAN_PCD_TESTS_MAX_NUM_RANGES];
++#endif
++
++      struct {
++              /**
++               * All egress queues to a given net device belong to one
++               * (and the same) congestion group.
++               */
++              struct qman_cgr cgr;
++              /* If congested, when it began. Used for performance stats. */
++              u32 congestion_start_jiffies;
++              /* Number of jiffies the Tx port was congested. */
++              u32 congested_jiffies;
++              /**
++               * Counter for the number of times the CGR
++               * entered congestion state
++               */
++              u32 cgr_congested_count;
++      } cgr_data;
++      /* Use a per-port CGR for ingress traffic. */
++      bool use_ingress_cgr;
++      struct qman_cgr ingress_cgr;
++
++#ifdef CONFIG_FSL_DPAA_TS
++      bool ts_tx_en; /* Tx timestamping enabled */
++      bool ts_rx_en; /* Rx timestamping enabled */
++#endif /* CONFIG_FSL_DPAA_TS */
++
++      struct dpa_buffer_layout_s *buf_layout;
++      uint16_t rx_headroom;
++      char if_type[30];
++
++      void *peer;
++#ifdef CONFIG_PM
++      u32 wol;
++#endif
++#ifdef CONFIG_FSL_DPAA_DBG_LOOP
++      int loop_id;
++      int loop_to;
++#endif
++#ifdef CONFIG_FSL_DPAA_CEETM
++      bool ceetm_en; /* CEETM QoS enabled */
++#endif
++};
++
++struct fm_port_fqs {
++      struct dpa_fq *tx_defq;
++      struct dpa_fq *tx_errq;
++      struct dpa_fq *rx_defq;
++      struct dpa_fq *rx_errq;
++};
++
++
++#ifdef CONFIG_FSL_DPAA_DBG_LOOP
++extern struct net_device *dpa_loop_netdevs[20];
++#endif
++
++/* functions with different implementation for SG and non-SG: */
++int dpa_bp_priv_seed(struct dpa_bp *dpa_bp);
++int dpaa_eth_refill_bpools(struct dpa_bp *dpa_bp, int *count_ptr);
++void __hot _dpa_rx(struct net_device *net_dev,
++              struct qman_portal *portal,
++              const struct dpa_priv_s *priv,
++              struct dpa_percpu_priv_s *percpu_priv,
++              const struct qm_fd *fd,
++              u32 fqid,
++              int *count_ptr);
++int __hot dpa_tx(struct sk_buff *skb, struct net_device *net_dev);
++int __hot dpa_tx_extended(struct sk_buff *skb, struct net_device *net_dev,
++              struct qman_fq *egress_fq, struct qman_fq *conf_fq);
++struct sk_buff *_dpa_cleanup_tx_fd(const struct dpa_priv_s *priv,
++                                 const struct qm_fd *fd);
++void __hot _dpa_process_parse_results(const fm_prs_result_t *parse_results,
++                                    const struct qm_fd *fd,
++                                    struct sk_buff *skb,
++                                    int *use_gro);
++#ifndef CONFIG_FSL_DPAA_TS
++bool dpa_skb_is_recyclable(struct sk_buff *skb);
++bool dpa_buf_is_recyclable(struct sk_buff *skb,
++                         uint32_t min_size,
++                         uint16_t min_offset,
++                         unsigned char **new_buf_start);
++#endif
++int __hot skb_to_contig_fd(struct dpa_priv_s *priv,
++                         struct sk_buff *skb, struct qm_fd *fd,
++                         int *count_ptr, int *offset);
++int __hot skb_to_sg_fd(struct dpa_priv_s *priv,
++                     struct sk_buff *skb, struct qm_fd *fd);
++int __cold __attribute__((nonnull))
++      _dpa_fq_free(struct device *dev, struct qman_fq *fq);
++
++/* Turn on HW checksum computation for this outgoing frame.
++ * If the current protocol is not something we support in this regard
++ * (or if the stack has already computed the SW checksum), we do nothing.
++ *
++ * Returns 0 if all goes well (or HW csum doesn't apply), and a negative value
++ * otherwise.
++ *
++ * Note that this function may modify the fd->cmd field and the skb data buffer
++ * (the Parse Results area).
++ */
++int dpa_enable_tx_csum(struct dpa_priv_s *priv,
++      struct sk_buff *skb, struct qm_fd *fd, char *parse_results);
++
++static inline int dpaa_eth_napi_schedule(struct dpa_percpu_priv_s *percpu_priv,
++                      struct qman_portal *portal)
++{
++      /* In case of threaded ISR for RT enable kernel,
++       * in_irq() does not return appropriate value, so use
++       * in_serving_softirq to distinguish softirq or irq context.
++       */
++      if (unlikely(in_irq() || !in_serving_softirq())) {
++              /* Disable QMan IRQ and invoke NAPI */
++              int ret = qman_p_irqsource_remove(portal, QM_PIRQ_DQRI);
++              if (likely(!ret)) {
++                      const struct qman_portal_config *pc =
++                                      qman_p_get_portal_config(portal);
++                      struct dpa_napi_portal *np =
++                                      &percpu_priv->np[pc->index];
++
++                      np->p = portal;
++                      napi_schedule(&np->napi);
++                      percpu_priv->in_interrupt++;
++                      return 1;
++              }
++      }
++      return 0;
++}
++
++static inline ssize_t __const __must_check __attribute__((nonnull))
++dpa_fd_length(const struct qm_fd *fd)
++{
++      return fd->length20;
++}
++
++static inline ssize_t __const __must_check __attribute__((nonnull))
++dpa_fd_offset(const struct qm_fd *fd)
++{
++      return fd->offset;
++}
++
++/* Verifies if the skb length is below the interface MTU */
++static inline int dpa_check_rx_mtu(struct sk_buff *skb, int mtu)
++{
++      if (unlikely(skb->len > mtu))
++              if ((skb->protocol != htons(ETH_P_8021Q))
++                              || (skb->len > mtu + 4))
++                      return -1;
++
++      return 0;
++}
++
++static inline uint16_t dpa_get_headroom(struct dpa_buffer_layout_s *bl)
++{
++      uint16_t headroom;
++      /* The frame headroom must accommodate:
++       * - the driver private data area
++       * - parse results, hash results, timestamp if selected
++       * - manip extra space
++       * If either hash results or time stamp are selected, both will
++       * be copied to/from the frame headroom, as TS is located between PR and
++       * HR in the IC and IC copy size has a granularity of 16bytes
++       * (see description of FMBM_RICP and FMBM_TICP registers in DPAARM)
++       *
++       * Also make sure the headroom is a multiple of data_align bytes
++       */
++      headroom = (uint16_t)(bl->priv_data_size +
++                 (bl->parse_results ? DPA_PARSE_RESULTS_SIZE : 0) +
++                 (bl->hash_results || bl->time_stamp ?
++                  DPA_TIME_STAMP_SIZE + DPA_HASH_RESULTS_SIZE : 0) +
++                 bl->manip_extra_space);
++
++      return bl->data_align ? ALIGN(headroom, bl->data_align) : headroom;
++}
++
++int fm_mac_dump_regs(struct mac_device *h_dev, char *buf, int n);
++int fm_mac_dump_rx_stats(struct mac_device *h_dev, char *buf, int n);
++int fm_mac_dump_tx_stats(struct mac_device *h_dev, char *buf, int n);
++
++void dpaa_eth_sysfs_remove(struct device *dev);
++void dpaa_eth_sysfs_init(struct device *dev);
++int dpaa_eth_poll(struct napi_struct *napi, int budget);
++
++void dpa_private_napi_del(struct net_device *net_dev);
++
++/* Equivalent to a memset(0), but works faster */
++static inline void clear_fd(struct qm_fd *fd)
++{
++      fd->opaque_addr = 0;
++      fd->opaque = 0;
++      fd->cmd = 0;
++}
++
++static inline int _dpa_tx_fq_to_id(const struct dpa_priv_s *priv,
++              struct qman_fq *tx_fq)
++{
++      int i;
++
++      for (i = 0; i < DPAA_ETH_TX_QUEUES; i++)
++              if (priv->egress_fqs[i] == tx_fq)
++                      return i;
++
++      return -EINVAL;
++}
++
++static inline int __hot dpa_xmit(struct dpa_priv_s *priv,
++                      struct rtnl_link_stats64 *percpu_stats,
++                      struct qm_fd *fd, struct qman_fq *egress_fq,
++                      struct qman_fq *conf_fq)
++{
++      int err, i;
++
++      if (fd->bpid == 0xff)
++              fd->cmd |= qman_fq_fqid(conf_fq);
++
++      /* Trace this Tx fd */
++      trace_dpa_tx_fd(priv->net_dev, egress_fq, fd);
++
++      for (i = 0; i < 100000; i++) {
++              err = qman_enqueue(egress_fq, fd, 0);
++              if (err != -EBUSY)
++                      break;
++      }
++
++      if (unlikely(err < 0)) {
++              /* TODO differentiate b/w -EBUSY (EQCR full) and other codes? */
++              percpu_stats->tx_errors++;
++              percpu_stats->tx_fifo_errors++;
++              return err;
++      }
++
++      percpu_stats->tx_packets++;
++      percpu_stats->tx_bytes += dpa_fd_length(fd);
++
++      return 0;
++}
++
++/* Use multiple WQs for FQ assignment:
++ *    - Tx Confirmation queues go to WQ1.
++ *    - Rx Default, Tx and PCD queues go to WQ3 (no differentiation between
++ *      Rx and Tx traffic, or between Rx Default and Rx PCD frames).
++ *    - Rx Error and Tx Error queues go to WQ2 (giving them a better chance
++ *      to be scheduled, in case there are many more FQs in WQ3).
++ * This ensures that Tx-confirmed buffers are timely released. In particular,
++ * it avoids congestion on the Tx Confirm FQs, which can pile up PFDRs if they
++ * are greatly outnumbered by other FQs in the system (usually PCDs), while
++ * dequeue scheduling is round-robin.
++ */
++static inline void _dpa_assign_wq(struct dpa_fq *fq)
++{
++      switch (fq->fq_type) {
++      case FQ_TYPE_TX_CONFIRM:
++      case FQ_TYPE_TX_CONF_MQ:
++              fq->wq = 1;
++              break;
++      case FQ_TYPE_RX_DEFAULT:
++      case FQ_TYPE_TX:
++              fq->wq = 3;
++              break;
++      case FQ_TYPE_RX_ERROR:
++      case FQ_TYPE_TX_ERROR:
++      case FQ_TYPE_RX_PCD_HI_PRIO:
++              fq->wq = 2;
++              break;
++      case FQ_TYPE_RX_PCD:
++              fq->wq = 5;
++              break;
++      default:
++              WARN(1, "Invalid FQ type %d for FQID %d!\n",
++                     fq->fq_type, fq->fqid);
++      }
++}
++
++#ifdef CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
++/* Use in lieu of skb_get_queue_mapping() */
++#ifdef CONFIG_FMAN_PFC
++#define dpa_get_queue_mapping(skb) \
++      (((skb)->priority < CONFIG_FMAN_PFC_COS_COUNT) ? \
++              ((skb)->priority * dpa_num_cpus + smp_processor_id()) : \
++              ((CONFIG_FMAN_PFC_COS_COUNT - 1) * \
++                      dpa_num_cpus + smp_processor_id()));
++
++#else
++#define dpa_get_queue_mapping(skb) \
++      raw_smp_processor_id()
++#endif
++#else
++/* Use the queue selected by XPS */
++#define dpa_get_queue_mapping(skb) \
++      skb_get_queue_mapping(skb)
++#endif
++
++#ifdef CONFIG_PTP_1588_CLOCK_DPAA
++struct ptp_priv_s {
++      struct device_node *node;
++      struct platform_device *of_dev;
++      struct mac_device *mac_dev;
++};
++extern struct ptp_priv_s ptp_priv;
++#endif
++
++static inline void _dpa_bp_free_pf(void *addr)
++{
++      put_page(virt_to_head_page(addr));
++}
++
++/* TODO: LS1043A SoC has a HW issue regarding FMan DMA transactions; The issue
++ * manifests itself at high traffic rates when frames exceed 4K memory
++ * boundaries; For the moment, we use a SW workaround to avoid frames larger
++ * than 4K or that exceed 4K alignments.
++ */
++
++#ifndef CONFIG_PPC
++extern bool dpaa_errata_a010022; /* SoC affected by A010022 errata */
++
++#define HAS_DMA_ISSUE(start, size) \
++      (((u64)(start) + (size)) > (((u64)(start) + 0x1000) & ~0xFFF))
++#define BOUNDARY_4K(start, size) (((u64)(start) + (u64)(size)) & ~0xFFF)
++
++#endif  /* !CONFIG_PPC */
++
++#endif        /* __DPA_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c
+@@ -0,0 +1,263 @@
++/* Copyright 2008-2013 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
++      KBUILD_BASENAME".c", __LINE__, __func__
++#else
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": " fmt
++#endif
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/of_platform.h>
++#include <linux/of_net.h>
++#include <linux/etherdevice.h>
++#include <linux/kthread.h>
++#include <linux/percpu.h>
++#include <linux/highmem.h>
++#include <linux/sort.h>
++#include <linux/fsl_qman.h>
++#include "dpaa_eth.h"
++#include "dpaa_eth_common.h"
++#include "dpaa_eth_base.h"
++
++#define DPA_DESCRIPTION "FSL DPAA Advanced drivers:"
++
++MODULE_LICENSE("Dual BSD/GPL");
++
++uint8_t advanced_debug = -1;
++module_param(advanced_debug, byte, S_IRUGO);
++MODULE_PARM_DESC(advanced_debug, "Module/Driver verbosity level");
++EXPORT_SYMBOL(advanced_debug);
++
++static int dpa_bp_cmp(const void *dpa_bp0, const void *dpa_bp1)
++{
++      return ((struct dpa_bp *)dpa_bp0)->size -
++                      ((struct dpa_bp *)dpa_bp1)->size;
++}
++
++struct dpa_bp * __cold __must_check /* __attribute__((nonnull)) */
++dpa_bp_probe(struct platform_device *_of_dev, size_t *count)
++{
++      int                      i, lenp, na, ns, err;
++      struct device           *dev;
++      struct device_node      *dev_node;
++      const __be32            *bpool_cfg;
++      struct dpa_bp           *dpa_bp;
++      u32                     bpid;
++
++      dev = &_of_dev->dev;
++
++      *count = of_count_phandle_with_args(dev->of_node,
++                      "fsl,bman-buffer-pools", NULL);
++      if (*count < 1) {
++              dev_err(dev, "missing fsl,bman-buffer-pools device tree entry\n");
++              return ERR_PTR(-EINVAL);
++      }
++
++      dpa_bp = devm_kzalloc(dev, *count * sizeof(*dpa_bp), GFP_KERNEL);
++      if (dpa_bp == NULL) {
++              dev_err(dev, "devm_kzalloc() failed\n");
++              return ERR_PTR(-ENOMEM);
++      }
++
++      dev_node = of_find_node_by_path("/");
++      if (unlikely(dev_node == NULL)) {
++              dev_err(dev, "of_find_node_by_path(/) failed\n");
++              return ERR_PTR(-EINVAL);
++      }
++
++      na = of_n_addr_cells(dev_node);
++      ns = of_n_size_cells(dev_node);
++
++      for (i = 0; i < *count; i++) {
++              of_node_put(dev_node);
++
++              dev_node = of_parse_phandle(dev->of_node,
++                              "fsl,bman-buffer-pools", i);
++              if (dev_node == NULL) {
++                      dev_err(dev, "of_find_node_by_phandle() failed\n");
++                      return ERR_PTR(-EFAULT);
++              }
++
++              if (unlikely(!of_device_is_compatible(dev_node, "fsl,bpool"))) {
++                      dev_err(dev,
++                              "!of_device_is_compatible(%s, fsl,bpool)\n",
++                              dev_node->full_name);
++                      dpa_bp = ERR_PTR(-EINVAL);
++                      goto _return_of_node_put;
++              }
++
++              err = of_property_read_u32(dev_node, "fsl,bpid", &bpid);
++              if (err) {
++                      dev_err(dev, "Cannot find buffer pool ID in the device tree\n");
++                      dpa_bp = ERR_PTR(-EINVAL);
++                      goto _return_of_node_put;
++              }
++              dpa_bp[i].bpid = (uint8_t)bpid;
++
++              bpool_cfg = of_get_property(dev_node, "fsl,bpool-ethernet-cfg",
++                                      &lenp);
++              if (bpool_cfg && (lenp == (2 * ns + na) * sizeof(*bpool_cfg))) {
++                      const uint32_t *seed_pool;
++
++                      dpa_bp[i].config_count =
++                              (int)of_read_number(bpool_cfg, ns);
++                      dpa_bp[i].size  =
++                              (size_t)of_read_number(bpool_cfg + ns, ns);
++                      dpa_bp[i].paddr =
++                              of_read_number(bpool_cfg + 2 * ns, na);
++
++                      seed_pool = of_get_property(dev_node,
++                                      "fsl,bpool-ethernet-seeds", &lenp);
++                      dpa_bp[i].seed_pool = !!seed_pool;
++
++              } else {
++                      dev_err(dev,
++                              "Missing/invalid fsl,bpool-ethernet-cfg device tree entry for node %s\n",
++                              dev_node->full_name);
++                      dpa_bp = ERR_PTR(-EINVAL);
++                      goto _return_of_node_put;
++              }
++      }
++
++      sort(dpa_bp, *count, sizeof(*dpa_bp), dpa_bp_cmp, NULL);
++
++      return dpa_bp;
++
++_return_of_node_put:
++      if (dev_node)
++              of_node_put(dev_node);
++
++      return dpa_bp;
++}
++EXPORT_SYMBOL(dpa_bp_probe);
++
++int dpa_bp_shared_port_seed(struct dpa_bp *bp)
++{
++      void __iomem **ptr;
++
++      /* In MAC-less and Shared-MAC scenarios the physical
++       * address of the buffer pool in device tree is set
++       * to 0 to specify that another entity (USDPAA) will
++       * allocate and seed the buffers
++       */
++      if (!bp->paddr)
++              return 0;
++
++      /* allocate memory region for buffers */
++      devm_request_mem_region(bp->dev, bp->paddr,
++                      bp->size * bp->config_count, KBUILD_MODNAME);
++      /* managed ioremap unmapping */
++      ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
++      if (!ptr)
++              return -EIO;
++#ifndef CONFIG_PPC
++      bp->vaddr = ioremap_cache_ns(bp->paddr, bp->size * bp->config_count);
++#else
++      bp->vaddr = ioremap_prot(bp->paddr, bp->size * bp->config_count, 0);
++#endif
++      if (bp->vaddr == NULL) {
++              pr_err("Could not map memory for pool %d\n", bp->bpid);
++              devres_free(ptr);
++              return -EIO;
++      }
++      *ptr = bp->vaddr;
++      devres_add(bp->dev, ptr);
++
++      /* seed pool with buffers from that memory region */
++      if (bp->seed_pool) {
++              int count = bp->target_count;
++              dma_addr_t addr = bp->paddr;
++
++              while (count) {
++                      struct bm_buffer bufs[8];
++                      uint8_t num_bufs = 0;
++
++                      do {
++                              BUG_ON(addr > 0xffffffffffffull);
++                              bufs[num_bufs].bpid = bp->bpid;
++                              bm_buffer_set64(&bufs[num_bufs++], addr);
++                              addr += bp->size;
++
++                      } while (--count && (num_bufs < 8));
++
++                      while (bman_release(bp->pool, bufs, num_bufs, 0))
++                              cpu_relax();
++              }
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(dpa_bp_shared_port_seed);
++
++int dpa_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp,
++              size_t count)
++{
++      struct dpa_priv_s *priv = netdev_priv(net_dev);
++      int i;
++
++      priv->dpa_bp = dpa_bp;
++      priv->bp_count = count;
++
++      for (i = 0; i < count; i++) {
++              int err;
++              err = dpa_bp_alloc(&dpa_bp[i]);
++              if (err < 0) {
++                      dpa_bp_free(priv);
++                      priv->dpa_bp = NULL;
++                      return err;
++              }
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(dpa_bp_create);
++
++static int __init __cold dpa_advanced_load(void)
++{
++      pr_info(DPA_DESCRIPTION "\n");
++
++      return 0;
++}
++module_init(dpa_advanced_load);
++
++static void __exit __cold dpa_advanced_unload(void)
++{
++      pr_debug(KBUILD_MODNAME ": -> %s:%s()\n",
++               KBUILD_BASENAME".c", __func__);
++
++}
++module_exit(dpa_advanced_unload);
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.h
+@@ -0,0 +1,50 @@
++/* Copyright 2008-2013 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __DPAA_ETH_BASE_H
++#define __DPAA_ETH_BASE_H
++
++#include <linux/etherdevice.h> /* struct net_device */
++#include <linux/fsl_bman.h> /* struct bm_buffer */
++#include <linux/of_platform.h> /* struct platform_device */
++#include <linux/net_tstamp.h> /* struct hwtstamp_config */
++
++extern uint8_t advanced_debug;
++extern const struct dpa_fq_cbs_t shared_fq_cbs;
++extern int __hot dpa_shared_tx(struct sk_buff *skb, struct net_device *net_dev);
++
++struct dpa_bp * __cold __must_check /* __attribute__((nonnull)) */
++dpa_bp_probe(struct platform_device *_of_dev, size_t *count);
++int dpa_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp,
++              size_t count);
++int dpa_bp_shared_port_seed(struct dpa_bp *bp);
++
++#endif /* __DPAA_ETH_BASE_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -0,0 +1,1991 @@
++/* Copyright 2008-2016 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/init.h>
++#include "dpaa_eth_ceetm.h"
++
++#define DPA_CEETM_DESCRIPTION "FSL DPAA CEETM qdisc"
++
++const struct nla_policy ceetm_policy[TCA_CEETM_MAX + 1] = {
++      [TCA_CEETM_COPT] = { .len = sizeof(struct tc_ceetm_copt) },
++      [TCA_CEETM_QOPS] = { .len = sizeof(struct tc_ceetm_qopt) },
++};
++
++struct Qdisc_ops ceetm_qdisc_ops;
++
++/* Obtain the DCP and the SP ids from the FMan port */
++static void get_dcp_and_sp(struct net_device *dev, enum qm_dc_portal *dcp_id,
++                         unsigned int *sp_id)
++{
++      uint32_t channel;
++      t_LnxWrpFmPortDev *port_dev;
++      struct dpa_priv_s *dpa_priv = netdev_priv(dev);
++      struct mac_device *mac_dev = dpa_priv->mac_dev;
++
++      port_dev = (t_LnxWrpFmPortDev *)mac_dev->port_dev[TX];
++      channel = port_dev->txCh;
++
++      *sp_id = channel & CHANNEL_SP_MASK;
++      pr_debug(KBUILD_BASENAME " : FM sub-portal ID %d\n", *sp_id);
++
++      if (channel < DCP0_MAX_CHANNEL) {
++              *dcp_id = qm_dc_portal_fman0;
++              pr_debug(KBUILD_BASENAME " : DCP ID 0\n");
++      } else {
++              *dcp_id = qm_dc_portal_fman1;
++              pr_debug(KBUILD_BASENAME " : DCP ID 1\n");
++      }
++}
++
++/* Enqueue Rejection Notification callback */
++static void ceetm_ern(struct qman_portal *portal, struct qman_fq *fq,
++                    const struct qm_mr_entry *msg)
++{
++      struct net_device *net_dev;
++      struct ceetm_class *cls;
++      struct ceetm_class_stats *cstats = NULL;
++      const struct dpa_priv_s *dpa_priv;
++      struct dpa_percpu_priv_s *dpa_percpu_priv;
++      struct sk_buff *skb;
++      struct qm_fd fd = msg->ern.fd;
++
++      net_dev = ((struct ceetm_fq *)fq)->net_dev;
++      dpa_priv = netdev_priv(net_dev);
++      dpa_percpu_priv = raw_cpu_ptr(dpa_priv->percpu_priv);
++
++      /* Increment DPA counters */
++      dpa_percpu_priv->stats.tx_dropped++;
++      dpa_percpu_priv->stats.tx_fifo_errors++;
++
++      /* Increment CEETM counters */
++      cls = ((struct ceetm_fq *)fq)->ceetm_cls;
++      switch (cls->type) {
++      case CEETM_PRIO:
++              cstats = this_cpu_ptr(cls->prio.cstats);
++              break;
++      case CEETM_WBFS:
++              cstats = this_cpu_ptr(cls->wbfs.cstats);
++              break;
++      }
++
++      if (cstats)
++              cstats->ern_drop_count++;
++
++      if (fd.bpid != 0xff) {
++              dpa_fd_release(net_dev, &fd);
++              return;
++      }
++
++      skb = _dpa_cleanup_tx_fd(dpa_priv, &fd);
++      dev_kfree_skb_any(skb);
++}
++
++/* Congestion State Change Notification callback */
++static void ceetm_cscn(struct qm_ceetm_ccg *ccg, void *cb_ctx, int congested)
++{
++      struct ceetm_fq *ceetm_fq = (struct ceetm_fq *)cb_ctx;
++      struct dpa_priv_s *dpa_priv = netdev_priv(ceetm_fq->net_dev);
++      struct ceetm_class *cls = ceetm_fq->ceetm_cls;
++      struct ceetm_class_stats *cstats = NULL;
++
++      switch (cls->type) {
++      case CEETM_PRIO:
++              cstats = this_cpu_ptr(cls->prio.cstats);
++              break;
++      case CEETM_WBFS:
++              cstats = this_cpu_ptr(cls->wbfs.cstats);
++              break;
++      }
++
++      if (congested) {
++              dpa_priv->cgr_data.congestion_start_jiffies = jiffies;
++              netif_tx_stop_all_queues(dpa_priv->net_dev);
++              dpa_priv->cgr_data.cgr_congested_count++;
++              if (cstats)
++                      cstats->congested_count++;
++      } else {
++              dpa_priv->cgr_data.congested_jiffies +=
++                      (jiffies - dpa_priv->cgr_data.congestion_start_jiffies);
++              netif_tx_wake_all_queues(dpa_priv->net_dev);
++      }
++}
++
++/* Allocate a ceetm fq */
++static int ceetm_alloc_fq(struct ceetm_fq **fq, struct net_device *dev,
++                        struct ceetm_class *cls)
++{
++      *fq = kzalloc(sizeof(**fq), GFP_KERNEL);
++      if (!*fq)
++              return -ENOMEM;
++
++      (*fq)->net_dev = dev;
++      (*fq)->ceetm_cls = cls;
++      return 0;
++}
++
++/* Configure a ceetm Class Congestion Group */
++static int ceetm_config_ccg(struct qm_ceetm_ccg **ccg,
++                          struct qm_ceetm_channel *channel, unsigned int id,
++                          struct ceetm_fq *fq, struct dpa_priv_s *dpa_priv)
++{
++      int err;
++      u32 cs_th;
++      u16 ccg_mask;
++      struct qm_ceetm_ccg_params ccg_params;
++
++      err = qman_ceetm_ccg_claim(ccg, channel, id, ceetm_cscn, fq);
++      if (err)
++              return err;
++
++      /* Configure the count mode (frames/bytes), enable congestion state
++       * notifications, configure the congestion entry and exit thresholds,
++       * enable tail-drop, configure the tail-drop mode, and set the
++       * overhead accounting limit
++       */
++      ccg_mask = QM_CCGR_WE_MODE |
++                 QM_CCGR_WE_CSCN_EN |
++                 QM_CCGR_WE_CS_THRES_IN | QM_CCGR_WE_CS_THRES_OUT |
++                 QM_CCGR_WE_TD_EN | QM_CCGR_WE_TD_MODE |
++                 QM_CCGR_WE_OAL;
++
++      ccg_params.mode = 0; /* count bytes */
++      ccg_params.cscn_en = 1; /* generate notifications */
++      ccg_params.td_en = 1; /* enable tail-drop */
++      ccg_params.td_mode = 0; /* tail-drop on congestion state */
++      ccg_params.oal = (signed char)(min(sizeof(struct sk_buff) +
++                        dpa_priv->tx_headroom, (size_t)FSL_QMAN_MAX_OAL));
++
++      /* Set the congestion state thresholds according to the link speed */
++      if (dpa_priv->mac_dev->if_support & SUPPORTED_10000baseT_Full)
++              cs_th = CONFIG_FSL_DPAA_CS_THRESHOLD_10G;
++      else
++              cs_th = CONFIG_FSL_DPAA_CS_THRESHOLD_1G;
++
++      qm_cgr_cs_thres_set64(&ccg_params.cs_thres_in, cs_th, 1);
++      qm_cgr_cs_thres_set64(&ccg_params.cs_thres_out,
++                            cs_th * CEETM_CCGR_RATIO, 1);
++
++      err = qman_ceetm_ccg_set(*ccg, ccg_mask, &ccg_params);
++      if (err)
++              return err;
++
++      return 0;
++}
++
++/* Configure a ceetm Logical Frame Queue */
++static int ceetm_config_lfq(struct qm_ceetm_cq *cq, struct ceetm_fq *fq,
++                          struct qm_ceetm_lfq **lfq)
++{
++      int err;
++      u64 context_a;
++      u32 context_b;
++
++      err = qman_ceetm_lfq_claim(lfq, cq);
++      if (err)
++              return err;
++
++      /* Get the former contexts in order to preserve context B */
++      err = qman_ceetm_lfq_get_context(*lfq, &context_a, &context_b);
++      if (err)
++              return err;
++
++      context_a = CEETM_CONTEXT_A;
++      err = qman_ceetm_lfq_set_context(*lfq, context_a, context_b);
++      if (err)
++              return err;
++
++      (*lfq)->ern = ceetm_ern;
++
++      err = qman_ceetm_create_fq(*lfq, &fq->fq);
++      if (err)
++              return err;
++
++      return 0;
++}
++
++/* Configure a prio ceetm class */
++static int ceetm_config_prio_cls(struct ceetm_class *cls,
++                               struct net_device *dev,
++                               struct qm_ceetm_channel *channel,
++                               unsigned int id)
++{
++      int err;
++      struct dpa_priv_s *dpa_priv = netdev_priv(dev);
++
++      err = ceetm_alloc_fq(&cls->prio.fq, dev, cls);
++      if (err)
++              return err;
++
++      /* Claim and configure the CCG */
++      err = ceetm_config_ccg(&cls->prio.ccg, channel, id, cls->prio.fq,
++                             dpa_priv);
++      if (err)
++              return err;
++
++      /* Claim and configure the CQ */
++      err = qman_ceetm_cq_claim(&cls->prio.cq, channel, id, cls->prio.ccg);
++      if (err)
++              return err;
++
++      if (cls->shaped) {
++              err = qman_ceetm_channel_set_cq_cr_eligibility(channel, id, 1);
++              if (err)
++                      return err;
++
++              err = qman_ceetm_channel_set_cq_er_eligibility(channel, id, 1);
++              if (err)
++                      return err;
++      }
++
++      /* Claim and configure a LFQ */
++      err = ceetm_config_lfq(cls->prio.cq, cls->prio.fq, &cls->prio.lfq);
++      if (err)
++              return err;
++
++      return 0;
++}
++
++/* Configure a wbfs ceetm class */
++static int ceetm_config_wbfs_cls(struct ceetm_class *cls,
++                               struct net_device *dev,
++                               struct qm_ceetm_channel *channel,
++                               unsigned int id, int type)
++{
++      int err;
++      struct dpa_priv_s *dpa_priv = netdev_priv(dev);
++
++      err = ceetm_alloc_fq(&cls->wbfs.fq, dev, cls);
++      if (err)
++              return err;
++
++      /* Claim and configure the CCG */
++      err = ceetm_config_ccg(&cls->wbfs.ccg, channel, id, cls->wbfs.fq,
++                             dpa_priv);
++      if (err)
++              return err;
++
++      /* Claim and configure the CQ */
++      if (type == WBFS_GRP_B)
++              err = qman_ceetm_cq_claim_B(&cls->wbfs.cq, channel, id,
++                                          cls->wbfs.ccg);
++      else
++              err = qman_ceetm_cq_claim_A(&cls->wbfs.cq, channel, id,
++                                          cls->wbfs.ccg);
++      if (err)
++              return err;
++
++      /* Configure the CQ weight: real number multiplied by 100 to get rid
++       * of the fraction
++       */
++      err = qman_ceetm_set_queue_weight_in_ratio(cls->wbfs.cq,
++                                                 cls->wbfs.weight * 100);
++      if (err)
++              return err;
++
++      /* Claim and configure a LFQ */
++      err = ceetm_config_lfq(cls->wbfs.cq, cls->wbfs.fq, &cls->wbfs.lfq);
++      if (err)
++              return err;
++
++      return 0;
++}
++
++/* Find class in qdisc hash table using given handle */
++static inline struct ceetm_class *ceetm_find(u32 handle, struct Qdisc *sch)
++{
++      struct ceetm_qdisc *priv = qdisc_priv(sch);
++      struct Qdisc_class_common *clc;
++
++      pr_debug(KBUILD_BASENAME " : %s : find class %X in qdisc %X\n",
++               __func__, handle, sch->handle);
++
++      clc = qdisc_class_find(&priv->clhash, handle);
++      return clc ? container_of(clc, struct ceetm_class, common) : NULL;
++}
++
++/* Insert a class in the qdisc's class hash */
++static void ceetm_link_class(struct Qdisc *sch,
++                           struct Qdisc_class_hash *clhash,
++                           struct Qdisc_class_common *common)
++{
++      sch_tree_lock(sch);
++      qdisc_class_hash_insert(clhash, common);
++      sch_tree_unlock(sch);
++      qdisc_class_hash_grow(sch, clhash);
++}
++
++/* Destroy a ceetm class */
++static void ceetm_cls_destroy(struct Qdisc *sch, struct ceetm_class *cl)
++{
++      if (!cl)
++              return;
++
++      pr_debug(KBUILD_BASENAME " : %s : destroy class %X from under %X\n",
++               __func__, cl->common.classid, sch->handle);
++
++      switch (cl->type) {
++      case CEETM_ROOT:
++              if (cl->root.child) {
++                      qdisc_destroy(cl->root.child);
++                      cl->root.child = NULL;
++              }
++
++              if (cl->root.ch && qman_ceetm_channel_release(cl->root.ch))
++                      pr_err(KBUILD_BASENAME
++                             " : %s : error releasing the channel %d\n",
++                             __func__, cl->root.ch->idx);
++
++              break;
++
++      case CEETM_PRIO:
++              if (cl->prio.child) {
++                      qdisc_destroy(cl->prio.child);
++                      cl->prio.child = NULL;
++              }
++
++              if (cl->prio.lfq && qman_ceetm_lfq_release(cl->prio.lfq))
++                      pr_err(KBUILD_BASENAME
++                             " : %s : error releasing the LFQ %d\n",
++                             __func__, cl->prio.lfq->idx);
++
++              if (cl->prio.cq && qman_ceetm_cq_release(cl->prio.cq))
++                      pr_err(KBUILD_BASENAME
++                             " : %s : error releasing the CQ %d\n",
++                             __func__, cl->prio.cq->idx);
++
++              if (cl->prio.ccg && qman_ceetm_ccg_release(cl->prio.ccg))
++                      pr_err(KBUILD_BASENAME
++                             " : %s : error releasing the CCG %d\n",
++                             __func__, cl->prio.ccg->idx);
++
++              kfree(cl->prio.fq);
++
++              if (cl->prio.cstats)
++                      free_percpu(cl->prio.cstats);
++
++              break;
++
++      case CEETM_WBFS:
++              if (cl->wbfs.lfq && qman_ceetm_lfq_release(cl->wbfs.lfq))
++                      pr_err(KBUILD_BASENAME
++                             " : %s : error releasing the LFQ %d\n",
++                             __func__, cl->wbfs.lfq->idx);
++
++              if (cl->wbfs.cq && qman_ceetm_cq_release(cl->wbfs.cq))
++                      pr_err(KBUILD_BASENAME
++                             " : %s : error releasing the CQ %d\n",
++                             __func__, cl->wbfs.cq->idx);
++
++              if (cl->wbfs.ccg && qman_ceetm_ccg_release(cl->wbfs.ccg))
++                      pr_err(KBUILD_BASENAME
++                             " : %s : error releasing the CCG %d\n",
++                             __func__, cl->wbfs.ccg->idx);
++
++              kfree(cl->wbfs.fq);
++
++              if (cl->wbfs.cstats)
++                      free_percpu(cl->wbfs.cstats);
++      }
++
++      tcf_destroy_chain(&cl->filter_list);
++      kfree(cl);
++}
++
++/* Destroy a ceetm qdisc */
++static void ceetm_destroy(struct Qdisc *sch)
++{
++      unsigned int ntx, i;
++      struct hlist_node *next;
++      struct ceetm_class *cl;
++      struct ceetm_qdisc *priv = qdisc_priv(sch);
++      struct net_device *dev = qdisc_dev(sch);
++
++      pr_debug(KBUILD_BASENAME " : %s : destroy qdisc %X\n",
++               __func__, sch->handle);
++
++      /* All filters need to be removed before destroying the classes */
++      tcf_destroy_chain(&priv->filter_list);
++
++      for (i = 0; i < priv->clhash.hashsize; i++) {
++              hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode)
++                      tcf_destroy_chain(&cl->filter_list);
++      }
++
++      for (i = 0; i < priv->clhash.hashsize; i++) {
++              hlist_for_each_entry_safe(cl, next, &priv->clhash.hash[i],
++                                        common.hnode)
++                      ceetm_cls_destroy(sch, cl);
++      }
++
++      qdisc_class_hash_destroy(&priv->clhash);
++
++      switch (priv->type) {
++      case CEETM_ROOT:
++              dpa_disable_ceetm(dev);
++
++              if (priv->root.lni && qman_ceetm_lni_release(priv->root.lni))
++                      pr_err(KBUILD_BASENAME
++                             " : %s : error releasing the LNI %d\n",
++                             __func__, priv->root.lni->idx);
++
++              if (priv->root.sp && qman_ceetm_sp_release(priv->root.sp))
++                      pr_err(KBUILD_BASENAME
++                             " : %s : error releasing the SP %d\n",
++                             __func__, priv->root.sp->idx);
++
++              if (priv->root.qstats)
++                      free_percpu(priv->root.qstats);
++
++              if (!priv->root.qdiscs)
++                      break;
++
++              /* Remove the pfifo qdiscs */
++              for (ntx = 0; ntx < dev->num_tx_queues; ntx++)
++                      if (priv->root.qdiscs[ntx])
++                              qdisc_destroy(priv->root.qdiscs[ntx]);
++
++              kfree(priv->root.qdiscs);
++              break;
++
++      case CEETM_PRIO:
++              if (priv->prio.parent)
++                      priv->prio.parent->root.child = NULL;
++              break;
++
++      case CEETM_WBFS:
++              if (priv->wbfs.parent)
++                      priv->wbfs.parent->prio.child = NULL;
++              break;
++      }
++}
++
++static int ceetm_dump(struct Qdisc *sch, struct sk_buff *skb)
++{
++      struct Qdisc *qdisc;
++      unsigned int ntx, i;
++      struct nlattr *nest;
++      struct tc_ceetm_qopt qopt;
++      struct ceetm_qdisc_stats *qstats;
++      struct net_device *dev = qdisc_dev(sch);
++      struct ceetm_qdisc *priv = qdisc_priv(sch);
++
++      pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
++
++      sch_tree_lock(sch);
++      memset(&qopt, 0, sizeof(qopt));
++      qopt.type = priv->type;
++      qopt.shaped = priv->shaped;
++
++      switch (priv->type) {
++      case CEETM_ROOT:
++              /* Gather statistics from the underlying pfifo qdiscs */
++              sch->q.qlen = 0;
++              memset(&sch->bstats, 0, sizeof(sch->bstats));
++              memset(&sch->qstats, 0, sizeof(sch->qstats));
++
++              for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
++                      qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping;
++                      sch->q.qlen             += qdisc->q.qlen;
++                      sch->bstats.bytes       += qdisc->bstats.bytes;
++                      sch->bstats.packets     += qdisc->bstats.packets;
++                      sch->qstats.qlen        += qdisc->qstats.qlen;
++                      sch->qstats.backlog     += qdisc->qstats.backlog;
++                      sch->qstats.drops       += qdisc->qstats.drops;
++                      sch->qstats.requeues    += qdisc->qstats.requeues;
++                      sch->qstats.overlimits  += qdisc->qstats.overlimits;
++              }
++
++              for_each_online_cpu(i) {
++                      qstats = per_cpu_ptr(priv->root.qstats, i);
++                      sch->qstats.drops += qstats->drops;
++              }
++
++              qopt.rate = priv->root.rate;
++              qopt.ceil = priv->root.ceil;
++              qopt.overhead = priv->root.overhead;
++              break;
++
++      case CEETM_PRIO:
++              qopt.qcount = priv->prio.qcount;
++              break;
++
++      case CEETM_WBFS:
++              qopt.qcount = priv->wbfs.qcount;
++              qopt.cr = priv->wbfs.cr;
++              qopt.er = priv->wbfs.er;
++              break;
++
++      default:
++              pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
++              sch_tree_unlock(sch);
++              return -EINVAL;
++      }
++
++      nest = nla_nest_start(skb, TCA_OPTIONS);
++      if (!nest)
++              goto nla_put_failure;
++      if (nla_put(skb, TCA_CEETM_QOPS, sizeof(qopt), &qopt))
++              goto nla_put_failure;
++      nla_nest_end(skb, nest);
++
++      sch_tree_unlock(sch);
++      return skb->len;
++
++nla_put_failure:
++      sch_tree_unlock(sch);
++      nla_nest_cancel(skb, nest);
++      return -EMSGSIZE;
++}
++
++/* Configure a root ceetm qdisc */
++static int ceetm_init_root(struct Qdisc *sch, struct ceetm_qdisc *priv,
++                         struct tc_ceetm_qopt *qopt)
++{
++      struct netdev_queue *dev_queue;
++      struct Qdisc *qdisc;
++      enum qm_dc_portal dcp_id;
++      unsigned int i, sp_id, parent_id;
++      int err;
++      u64 bps;
++      struct qm_ceetm_sp *sp;
++      struct qm_ceetm_lni *lni;
++      struct net_device *dev = qdisc_dev(sch);
++      struct dpa_priv_s *dpa_priv = netdev_priv(dev);
++      struct mac_device *mac_dev = dpa_priv->mac_dev;
++
++      pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
++
++      /* Validate inputs */
++      if (sch->parent != TC_H_ROOT) {
++              pr_err("CEETM: a root ceetm qdisc can not be attached to a class\n");
++              tcf_destroy_chain(&priv->filter_list);
++              qdisc_class_hash_destroy(&priv->clhash);
++              return -EINVAL;
++      }
++
++      if (!mac_dev) {
++              pr_err("CEETM: the interface is lacking a mac\n");
++              err = -EINVAL;
++              goto err_init_root;
++      }
++
++      /* pre-allocate underlying pfifo qdiscs */
++      priv->root.qdiscs = kcalloc(dev->num_tx_queues,
++                                  sizeof(priv->root.qdiscs[0]),
++                                  GFP_KERNEL);
++      if (!priv->root.qdiscs) {
++              err = -ENOMEM;
++              goto err_init_root;
++      }
++
++      for (i = 0; i < dev->num_tx_queues; i++) {
++              dev_queue = netdev_get_tx_queue(dev, i);
++              parent_id = TC_H_MAKE(TC_H_MAJ(sch->handle),
++                                    TC_H_MIN(i + PFIFO_MIN_OFFSET));
++
++              qdisc = qdisc_create_dflt(dev_queue, &pfifo_qdisc_ops,
++                                        parent_id);
++              if (!qdisc) {
++                      err = -ENOMEM;
++                      goto err_init_root;
++              }
++
++              priv->root.qdiscs[i] = qdisc;
++              qdisc->flags |= TCQ_F_ONETXQUEUE;
++      }
++
++      sch->flags |= TCQ_F_MQROOT;
++
++      priv->root.qstats = alloc_percpu(struct ceetm_qdisc_stats);
++      if (!priv->root.qstats) {
++              pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n",
++                     __func__);
++              err = -ENOMEM;
++              goto err_init_root;
++      }
++
++      priv->shaped = qopt->shaped;
++      priv->root.rate = qopt->rate;
++      priv->root.ceil = qopt->ceil;
++      priv->root.overhead = qopt->overhead;
++
++      /* Claim the SP */
++      get_dcp_and_sp(dev, &dcp_id, &sp_id);
++      err = qman_ceetm_sp_claim(&sp, dcp_id, sp_id);
++      if (err) {
++              pr_err(KBUILD_BASENAME " : %s : failed to claim the SP\n",
++                     __func__);
++              goto err_init_root;
++      }
++
++      priv->root.sp = sp;
++
++      /* Claim the LNI - will use the same id as the SP id since SPs 0-7
++       * are connected to the TX FMan ports
++       */
++      err = qman_ceetm_lni_claim(&lni, dcp_id, sp_id);
++      if (err) {
++              pr_err(KBUILD_BASENAME " : %s : failed to claim the LNI\n",
++                     __func__);
++              goto err_init_root;
++      }
++
++      priv->root.lni = lni;
++
++      err = qman_ceetm_sp_set_lni(sp, lni);
++      if (err) {
++              pr_err(KBUILD_BASENAME " : %s : failed to link the SP and LNI\n",
++                     __func__);
++              goto err_init_root;
++      }
++
++      lni->sp = sp;
++
++      /* Configure the LNI shaper */
++      if (priv->shaped) {
++              err = qman_ceetm_lni_enable_shaper(lni, 1, priv->root.overhead);
++              if (err) {
++                      pr_err(KBUILD_BASENAME " : %s : failed to configure the LNI shaper\n",
++                             __func__);
++                      goto err_init_root;
++              }
++
++              bps = priv->root.rate << 3; /* Bps -> bps */
++              err = qman_ceetm_lni_set_commit_rate_bps(lni, bps, dev->mtu);
++              if (err) {
++                      pr_err(KBUILD_BASENAME " : %s : failed to configure the LNI shaper\n",
++                             __func__);
++                      goto err_init_root;
++              }
++
++              bps = priv->root.ceil << 3; /* Bps -> bps */
++              err = qman_ceetm_lni_set_excess_rate_bps(lni, bps, dev->mtu);
++              if (err) {
++                      pr_err(KBUILD_BASENAME " : %s : failed to configure the LNI shaper\n",
++                             __func__);
++                      goto err_init_root;
++              }
++      }
++
++      /* TODO default configuration */
++
++      dpa_enable_ceetm(dev);
++      return 0;
++
++err_init_root:
++      ceetm_destroy(sch);
++      return err;
++}
++
++/* Configure a prio ceetm qdisc */
++static int ceetm_init_prio(struct Qdisc *sch, struct ceetm_qdisc *priv,
++                         struct tc_ceetm_qopt *qopt)
++{
++      int err;
++      unsigned int i;
++      struct ceetm_class *parent_cl, *child_cl;
++      struct Qdisc *parent_qdisc;
++      struct net_device *dev = qdisc_dev(sch);
++
++      pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
++
++      if (sch->parent == TC_H_ROOT) {
++              pr_err("CEETM: a prio ceetm qdisc can not be root\n");
++              err = -EINVAL;
++              goto err_init_prio;
++      }
++
++      parent_qdisc = qdisc_lookup(dev, TC_H_MAJ(sch->parent));
++      if (strcmp(parent_qdisc->ops->id, ceetm_qdisc_ops.id)) {
++              pr_err("CEETM: a ceetm qdisc can not be attached to other qdisc/class types\n");
++              err = -EINVAL;
++              goto err_init_prio;
++      }
++
++      /* Obtain the parent root ceetm_class */
++      parent_cl = ceetm_find(sch->parent, parent_qdisc);
++
++      if (!parent_cl || parent_cl->type != CEETM_ROOT) {
++              pr_err("CEETM: a prio ceetm qdiscs can be added only under a root ceetm class\n");
++              err = -EINVAL;
++              goto err_init_prio;
++      }
++
++      priv->prio.parent = parent_cl;
++      parent_cl->root.child = sch;
++
++      priv->shaped = parent_cl->shaped;
++      priv->prio.qcount = qopt->qcount;
++
++      /* Create and configure qcount child classes */
++      for (i = 0; i < priv->prio.qcount; i++) {
++              child_cl = kzalloc(sizeof(*child_cl), GFP_KERNEL);
++              if (!child_cl) {
++                      pr_err(KBUILD_BASENAME " : %s : kzalloc() failed\n",
++                             __func__);
++                      err = -ENOMEM;
++                      goto err_init_prio;
++              }
++
++              child_cl->prio.cstats = alloc_percpu(struct ceetm_class_stats);
++              if (!child_cl->prio.cstats) {
++                      pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n",
++                             __func__);
++                      err = -ENOMEM;
++                      goto err_init_prio_cls;
++              }
++
++              child_cl->common.classid = TC_H_MAKE(sch->handle, (i + 1));
++              child_cl->refcnt = 1;
++              child_cl->parent = sch;
++              child_cl->type = CEETM_PRIO;
++              child_cl->shaped = priv->shaped;
++              child_cl->prio.child = NULL;
++
++              /* All shaped CQs have CR and ER enabled by default */
++              child_cl->prio.cr = child_cl->shaped;
++              child_cl->prio.er = child_cl->shaped;
++              child_cl->prio.fq = NULL;
++              child_cl->prio.cq = NULL;
++
++              /* Configure the corresponding hardware CQ */
++              err = ceetm_config_prio_cls(child_cl, dev,
++                                          parent_cl->root.ch, i);
++              if (err) {
++                      pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm prio class %X\n",
++                             __func__, child_cl->common.classid);
++                      goto err_init_prio_cls;
++              }
++
++              /* Add class handle in Qdisc */
++              ceetm_link_class(sch, &priv->clhash, &child_cl->common);
++              pr_debug(KBUILD_BASENAME " : %s : added ceetm prio class %X associated with CQ %d and CCG %d\n",
++                       __func__, child_cl->common.classid,
++                      child_cl->prio.cq->idx, child_cl->prio.ccg->idx);
++      }
++
++      return 0;
++
++err_init_prio_cls:
++      ceetm_cls_destroy(sch, child_cl);
++err_init_prio:
++      ceetm_destroy(sch);
++      return err;
++}
++
++/* Configure a wbfs ceetm qdisc */
++static int ceetm_init_wbfs(struct Qdisc *sch, struct ceetm_qdisc *priv,
++                         struct tc_ceetm_qopt *qopt)
++{
++      int err, group_b, small_group;
++      unsigned int i, id, prio_a, prio_b;
++      struct ceetm_class *parent_cl, *child_cl, *root_cl;
++      struct Qdisc *parent_qdisc;
++      struct ceetm_qdisc *parent_priv;
++      struct qm_ceetm_channel *channel;
++      struct net_device *dev = qdisc_dev(sch);
++
++      pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
++
++      /* Validate inputs */
++      if (sch->parent == TC_H_ROOT) {
++              pr_err("CEETM: a wbfs ceetm qdiscs can not be root\n");
++              err = -EINVAL;
++              goto err_init_wbfs;
++      }
++
++      /* Obtain the parent prio ceetm qdisc */
++      parent_qdisc = qdisc_lookup(dev, TC_H_MAJ(sch->parent));
++      if (strcmp(parent_qdisc->ops->id, ceetm_qdisc_ops.id)) {
++              pr_err("CEETM: a ceetm qdisc can not be attached to other qdisc/class types\n");
++              err = -EINVAL;
++              goto err_init_wbfs;
++      }
++
++      /* Obtain the parent prio ceetm class */
++      parent_cl = ceetm_find(sch->parent, parent_qdisc);
++      parent_priv = qdisc_priv(parent_qdisc);
++
++      if (!parent_cl || parent_cl->type != CEETM_PRIO) {
++              pr_err("CEETM: a wbfs ceetm qdiscs can be added only under a prio ceetm class\n");
++              err = -EINVAL;
++              goto err_init_wbfs;
++      }
++
++      if (!qopt->qcount || !qopt->qweight[0]) {
++              pr_err("CEETM: qcount and qweight are mandatory for a wbfs ceetm qdisc\n");
++              err = -EINVAL;
++              goto err_init_wbfs;
++      }
++
++      priv->shaped = parent_cl->shaped;
++
++      if (!priv->shaped && (qopt->cr || qopt->er)) {
++              pr_err("CEETM: CR/ER can be enabled only for shaped wbfs ceetm qdiscs\n");
++              err = -EINVAL;
++              goto err_init_wbfs;
++      }
++
++      if (priv->shaped && !(qopt->cr || qopt->er)) {
++              pr_err("CEETM: either CR or ER must be enabled for shaped wbfs ceetm qdiscs\n");
++              err = -EINVAL;
++              goto err_init_wbfs;
++      }
++
++      /* Obtain the parent root ceetm class */
++      root_cl = parent_priv->prio.parent;
++      if ((root_cl->root.wbfs_grp_a && root_cl->root.wbfs_grp_b) ||
++          root_cl->root.wbfs_grp_large) {
++              pr_err("CEETM: no more wbfs classes are available\n");
++              err = -EINVAL;
++              goto err_init_wbfs;
++      }
++
++      if ((root_cl->root.wbfs_grp_a || root_cl->root.wbfs_grp_b) &&
++          qopt->qcount == CEETM_MAX_WBFS_QCOUNT) {
++              pr_err("CEETM: only %d wbfs classes are available\n",
++                     CEETM_MIN_WBFS_QCOUNT);
++              err = -EINVAL;
++              goto err_init_wbfs;
++      }
++
++      priv->wbfs.parent = parent_cl;
++      parent_cl->prio.child = sch;
++
++      priv->wbfs.qcount = qopt->qcount;
++      priv->wbfs.cr = qopt->cr;
++      priv->wbfs.er = qopt->er;
++
++      channel = root_cl->root.ch;
++
++      /* Configure the hardware wbfs channel groups */
++      if (priv->wbfs.qcount == CEETM_MAX_WBFS_QCOUNT) {
++              /* Configure the large group A */
++              priv->wbfs.group_type = WBFS_GRP_LARGE;
++              small_group = false;
++              group_b = false;
++              prio_a = TC_H_MIN(parent_cl->common.classid) - 1;
++              prio_b = prio_a;
++
++      } else if (root_cl->root.wbfs_grp_a) {
++              /* Configure the group B */
++              priv->wbfs.group_type = WBFS_GRP_B;
++
++              err = qman_ceetm_channel_get_group(channel, &small_group,
++                                                 &prio_a, &prio_b);
++              if (err) {
++                      pr_err(KBUILD_BASENAME " : %s : failed to get group details\n",
++                             __func__);
++                      goto err_init_wbfs;
++              }
++
++              small_group = true;
++              group_b = true;
++              prio_b = TC_H_MIN(parent_cl->common.classid) - 1;
++              /* If group A isn't configured, configure it as group B */
++              prio_a = prio_a ? : prio_b;
++
++      } else {
++              /* Configure the small group A */
++              priv->wbfs.group_type = WBFS_GRP_A;
++
++              err = qman_ceetm_channel_get_group(channel, &small_group,
++                                                 &prio_a, &prio_b);
++              if (err) {
++                      pr_err(KBUILD_BASENAME " : %s : failed to get group details\n",
++                             __func__);
++                      goto err_init_wbfs;
++              }
++
++              small_group = true;
++              group_b = false;
++              prio_a = TC_H_MIN(parent_cl->common.classid) - 1;
++              /* If group B isn't configured, configure it as group A */
++              prio_b = prio_b ? : prio_a;
++      }
++
++      err = qman_ceetm_channel_set_group(channel, small_group, prio_a,
++                                         prio_b);
++      if (err)
++              goto err_init_wbfs;
++
++      if (priv->shaped) {
++              err = qman_ceetm_channel_set_group_cr_eligibility(channel,
++                                                                group_b,
++                                                              priv->wbfs.cr);
++              if (err) {
++                      pr_err(KBUILD_BASENAME " : %s : failed to set group CR eligibility\n",
++                             __func__);
++                      goto err_init_wbfs;
++              }
++
++              err = qman_ceetm_channel_set_group_er_eligibility(channel,
++                                                                group_b,
++                                                              priv->wbfs.er);
++              if (err) {
++                      pr_err(KBUILD_BASENAME " : %s : failed to set group ER eligibility\n",
++                             __func__);
++                      goto err_init_wbfs;
++              }
++      }
++
++      /* Create qcount child classes */
++      for (i = 0; i < priv->wbfs.qcount; i++) {
++              child_cl = kzalloc(sizeof(*child_cl), GFP_KERNEL);
++              if (!child_cl) {
++                      pr_err(KBUILD_BASENAME " : %s : kzalloc() failed\n",
++                             __func__);
++                      err = -ENOMEM;
++                      goto err_init_wbfs;
++              }
++
++              child_cl->wbfs.cstats = alloc_percpu(struct ceetm_class_stats);
++              if (!child_cl->wbfs.cstats) {
++                      pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n",
++                             __func__);
++                      err = -ENOMEM;
++                      goto err_init_wbfs_cls;
++              }
++
++              child_cl->common.classid = TC_H_MAKE(sch->handle, (i + 1));
++              child_cl->refcnt = 1;
++              child_cl->parent = sch;
++              child_cl->type = CEETM_WBFS;
++              child_cl->shaped = priv->shaped;
++              child_cl->wbfs.fq = NULL;
++              child_cl->wbfs.cq = NULL;
++              child_cl->wbfs.weight = qopt->qweight[i];
++
++              if (priv->wbfs.group_type == WBFS_GRP_B)
++                      id = WBFS_GRP_B_OFFSET + i;
++              else
++                      id = WBFS_GRP_A_OFFSET + i;
++
++              err = ceetm_config_wbfs_cls(child_cl, dev, channel, id,
++                                          priv->wbfs.group_type);
++              if (err) {
++                      pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm wbfs class %X\n",
++                             __func__, child_cl->common.classid);
++                      goto err_init_wbfs_cls;
++              }
++
++              /* Add class handle in Qdisc */
++              ceetm_link_class(sch, &priv->clhash, &child_cl->common);
++              pr_debug(KBUILD_BASENAME " : %s : added ceetm wbfs class %X associated with CQ %d and CCG %d\n",
++                       __func__, child_cl->common.classid,
++                       child_cl->wbfs.cq->idx, child_cl->wbfs.ccg->idx);
++      }
++
++      /* Signal the root class that a group has been configured */
++      switch (priv->wbfs.group_type) {
++      case WBFS_GRP_LARGE:
++              root_cl->root.wbfs_grp_large = true;
++              break;
++      case WBFS_GRP_A:
++              root_cl->root.wbfs_grp_a = true;
++              break;
++      case WBFS_GRP_B:
++              root_cl->root.wbfs_grp_b = true;
++              break;
++      }
++
++      return 0;
++
++err_init_wbfs_cls:
++      ceetm_cls_destroy(sch, child_cl);
++err_init_wbfs:
++      ceetm_destroy(sch);
++      return err;
++}
++
++/* Configure a generic ceetm qdisc */
++static int ceetm_init(struct Qdisc *sch, struct nlattr *opt)
++{
++      struct tc_ceetm_qopt *qopt;
++      struct nlattr *tb[TCA_CEETM_QOPS + 1];
++      int ret;
++      struct ceetm_qdisc *priv = qdisc_priv(sch);
++      struct net_device *dev = qdisc_dev(sch);
++
++      pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
++
++      if (!netif_is_multiqueue(dev))
++              return -EOPNOTSUPP;
++
++      if (!opt) {
++              pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
++              return -EINVAL;
++      }
++
++      ret = nla_parse_nested(tb, TCA_CEETM_QOPS, opt, ceetm_policy);
++      if (ret < 0) {
++              pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
++              return ret;
++      }
++
++      if (!tb[TCA_CEETM_QOPS]) {
++              pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
++              return -EINVAL;
++      }
++
++      if (TC_H_MIN(sch->handle)) {
++              pr_err("CEETM: a qdisc should not have a minor\n");
++              return -EINVAL;
++      }
++
++      qopt = nla_data(tb[TCA_CEETM_QOPS]);
++
++      /* Initialize the class hash list. Each qdisc has its own class hash */
++      ret = qdisc_class_hash_init(&priv->clhash);
++      if (ret < 0) {
++              pr_err(KBUILD_BASENAME " : %s : qdisc_class_hash_init failed\n",
++                     __func__);
++              return ret;
++      }
++
++      priv->type = qopt->type;
++
++      switch (priv->type) {
++      case CEETM_ROOT:
++              ret = ceetm_init_root(sch, priv, qopt);
++              break;
++      case CEETM_PRIO:
++              ret = ceetm_init_prio(sch, priv, qopt);
++              break;
++      case CEETM_WBFS:
++              ret = ceetm_init_wbfs(sch, priv, qopt);
++              break;
++      default:
++              pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
++              ceetm_destroy(sch);
++              ret = -EINVAL;
++      }
++
++      return ret;
++}
++
++/* Edit a root ceetm qdisc */
++static int ceetm_change_root(struct Qdisc *sch, struct ceetm_qdisc *priv,
++                           struct net_device *dev,
++                           struct tc_ceetm_qopt *qopt)
++{
++      int err = 0;
++      u64 bps;
++
++      if (priv->shaped != (bool)qopt->shaped) {
++              pr_err("CEETM: qdisc %X is %s\n", sch->handle,
++                     priv->shaped ? "shaped" : "unshaped");
++              return -EINVAL;
++      }
++
++      /* Nothing to modify for unshaped qdiscs */
++      if (!priv->shaped)
++              return 0;
++
++      /* Configure the LNI shaper */
++      if (priv->root.overhead != qopt->overhead) {
++              err = qman_ceetm_lni_enable_shaper(priv->root.lni, 1,
++                                                 qopt->overhead);
++              if (err)
++                      goto change_err;
++              priv->root.overhead = qopt->overhead;
++      }
++
++      if (priv->root.rate != qopt->rate) {
++              bps = qopt->rate << 3; /* Bps -> bps */
++              err = qman_ceetm_lni_set_commit_rate_bps(priv->root.lni, bps,
++                                                       dev->mtu);
++              if (err)
++                      goto change_err;
++              priv->root.rate = qopt->rate;
++      }
++
++      if (priv->root.ceil != qopt->ceil) {
++              bps = qopt->ceil << 3; /* Bps -> bps */
++              err = qman_ceetm_lni_set_excess_rate_bps(priv->root.lni, bps,
++                                                       dev->mtu);
++              if (err)
++                      goto change_err;
++              priv->root.ceil = qopt->ceil;
++      }
++
++      return 0;
++
++change_err:
++      pr_err(KBUILD_BASENAME " : %s : failed to configure the root ceetm qdisc %X\n",
++             __func__, sch->handle);
++      return err;
++}
++
++/* Edit a wbfs ceetm qdisc */
++static int ceetm_change_wbfs(struct Qdisc *sch, struct ceetm_qdisc *priv,
++                           struct tc_ceetm_qopt *qopt)
++{
++      int err;
++      bool group_b;
++      struct qm_ceetm_channel *channel;
++      struct ceetm_class *prio_class, *root_class;
++      struct ceetm_qdisc *prio_qdisc;
++
++      if (qopt->qcount) {
++              pr_err("CEETM: the qcount can not be modified\n");
++              return -EINVAL;
++      }
++
++      if (qopt->qweight[0]) {
++              pr_err("CEETM: the qweight can be modified through the wbfs classes\n");
++              return -EINVAL;
++      }
++
++      if (!priv->shaped && (qopt->cr || qopt->er)) {
++              pr_err("CEETM: CR/ER can be enabled only for shaped wbfs ceetm qdiscs\n");
++              return -EINVAL;
++      }
++
++      if (priv->shaped && !(qopt->cr || qopt->er)) {
++              pr_err("CEETM: either CR or ER must be enabled for shaped wbfs ceetm qdiscs\n");
++              return -EINVAL;
++      }
++
++      /* Nothing to modify for unshaped qdiscs */
++      if (!priv->shaped)
++              return 0;
++
++      prio_class = priv->wbfs.parent;
++      prio_qdisc = qdisc_priv(prio_class->parent);
++      root_class = prio_qdisc->prio.parent;
++      channel = root_class->root.ch;
++      group_b = priv->wbfs.group_type == WBFS_GRP_B;
++
++      if (qopt->cr != priv->wbfs.cr) {
++              err = qman_ceetm_channel_set_group_cr_eligibility(channel,
++                                                                group_b,
++                                                                qopt->cr);
++              if (err)
++                      goto change_err;
++              priv->wbfs.cr = qopt->cr;
++      }
++
++      if (qopt->er != priv->wbfs.er) {
++              err = qman_ceetm_channel_set_group_er_eligibility(channel,
++                                                                group_b,
++                                                                qopt->er);
++              if (err)
++                      goto change_err;
++              priv->wbfs.er = qopt->er;
++      }
++
++      return 0;
++
++change_err:
++      pr_err(KBUILD_BASENAME " : %s : failed to configure the wbfs ceetm qdisc %X\n",
++             __func__, sch->handle);
++      return err;
++}
++
++/* Edit a ceetm qdisc */
++static int ceetm_change(struct Qdisc *sch, struct nlattr *opt)
++{
++      struct tc_ceetm_qopt *qopt;
++      struct nlattr *tb[TCA_CEETM_QOPS + 1];
++      int ret;
++      struct ceetm_qdisc *priv = qdisc_priv(sch);
++      struct net_device *dev = qdisc_dev(sch);
++
++      pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
++
++      ret = nla_parse_nested(tb, TCA_CEETM_QOPS, opt, ceetm_policy);
++      if (ret < 0) {
++              pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
++              return ret;
++      }
++
++      if (!tb[TCA_CEETM_QOPS]) {
++              pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
++              return -EINVAL;
++      }
++
++      if (TC_H_MIN(sch->handle)) {
++              pr_err("CEETM: a qdisc should not have a minor\n");
++              return -EINVAL;
++      }
++
++      qopt = nla_data(tb[TCA_CEETM_QOPS]);
++
++      if (priv->type != qopt->type) {
++              pr_err("CEETM: qdisc %X is not of the provided type\n",
++                     sch->handle);
++              return -EINVAL;
++      }
++
++      switch (priv->type) {
++      case CEETM_ROOT:
++              ret = ceetm_change_root(sch, priv, dev, qopt);
++              break;
++      case CEETM_PRIO:
++              pr_err("CEETM: prio qdiscs can not be modified\n");
++              ret = -EINVAL;
++              break;
++      case CEETM_WBFS:
++              ret = ceetm_change_wbfs(sch, priv, qopt);
++              break;
++      default:
++              pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
++              ret = -EINVAL;
++      }
++
++      return ret;
++}
++
++/* Attach the underlying pfifo qdiscs */
++static void ceetm_attach(struct Qdisc *sch)
++{
++      struct net_device *dev = qdisc_dev(sch);
++      struct ceetm_qdisc *priv = qdisc_priv(sch);
++      struct Qdisc *qdisc, *old_qdisc;
++      unsigned int i;
++
++      pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
++
++      for (i = 0; i < dev->num_tx_queues; i++) {
++              qdisc = priv->root.qdiscs[i];
++              old_qdisc = dev_graft_qdisc(qdisc->dev_queue, qdisc);
++              if (old_qdisc)
++                      qdisc_destroy(old_qdisc);
++      }
++}
++
++static unsigned long ceetm_cls_get(struct Qdisc *sch, u32 classid)
++{
++      struct ceetm_class *cl;
++
++      pr_debug(KBUILD_BASENAME " : %s : classid %X from qdisc %X\n",
++               __func__, classid, sch->handle);
++      cl = ceetm_find(classid, sch);
++
++      if (cl)
++              cl->refcnt++; /* Will decrement in put() */
++      return (unsigned long)cl;
++}
++
++static void ceetm_cls_put(struct Qdisc *sch, unsigned long arg)
++{
++      struct ceetm_class *cl = (struct ceetm_class *)arg;
++
++      pr_debug(KBUILD_BASENAME " : %s : classid %X from qdisc %X\n",
++               __func__, cl->common.classid, sch->handle);
++      cl->refcnt--;
++
++      if (cl->refcnt == 0)
++              ceetm_cls_destroy(sch, cl);
++}
++
++static int ceetm_cls_change_root(struct ceetm_class *cl,
++                               struct tc_ceetm_copt *copt,
++                               struct net_device *dev)
++{
++      int err;
++      u64 bps;
++
++      if ((bool)copt->shaped != cl->shaped) {
++              pr_err("CEETM: class %X is %s\n", cl->common.classid,
++                     cl->shaped ? "shaped" : "unshaped");
++              return -EINVAL;
++      }
++
++      if (cl->shaped && cl->root.rate != copt->rate) {
++              bps = copt->rate << 3; /* Bps -> bps */
++              err = qman_ceetm_channel_set_commit_rate_bps(cl->root.ch, bps,
++                                                           dev->mtu);
++              if (err)
++                      goto change_cls_err;
++              cl->root.rate = copt->rate;
++      }
++
++      if (cl->shaped && cl->root.ceil != copt->ceil) {
++              bps = copt->ceil << 3; /* Bps -> bps */
++              err = qman_ceetm_channel_set_excess_rate_bps(cl->root.ch, bps,
++                                                           dev->mtu);
++              if (err)
++                      goto change_cls_err;
++              cl->root.ceil = copt->ceil;
++      }
++
++      if (!cl->shaped && cl->root.tbl != copt->tbl) {
++              err = qman_ceetm_channel_set_weight(cl->root.ch, copt->tbl);
++              if (err)
++                      goto change_cls_err;
++              cl->root.tbl = copt->tbl;
++      }
++
++      return 0;
++
++change_cls_err:
++      pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm root class %X\n",
++             __func__, cl->common.classid);
++      return err;
++}
++
++static int ceetm_cls_change_prio(struct ceetm_class *cl,
++                               struct tc_ceetm_copt *copt)
++{
++      int err;
++
++      if (!cl->shaped && (copt->cr || copt->er)) {
++              pr_err("CEETM: only shaped classes can have CR and ER enabled\n");
++              return -EINVAL;
++      }
++
++      if (cl->prio.cr != (bool)copt->cr) {
++              err = qman_ceetm_channel_set_cq_cr_eligibility(
++                                              cl->prio.cq->parent,
++                                              cl->prio.cq->idx,
++                                              copt->cr);
++              if (err)
++                      goto change_cls_err;
++              cl->prio.cr = copt->cr;
++      }
++
++      if (cl->prio.er != (bool)copt->er) {
++              err = qman_ceetm_channel_set_cq_er_eligibility(
++                                              cl->prio.cq->parent,
++                                              cl->prio.cq->idx,
++                                              copt->er);
++              if (err)
++                      goto change_cls_err;
++              cl->prio.er = copt->er;
++      }
++
++      return 0;
++
++change_cls_err:
++      pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm prio class %X\n",
++             __func__, cl->common.classid);
++      return err;
++}
++
++static int ceetm_cls_change_wbfs(struct ceetm_class *cl,
++                               struct tc_ceetm_copt *copt)
++{
++      int err;
++
++      if (copt->weight != cl->wbfs.weight) {
++              /* Configure the CQ weight: real number multiplied by 100 to
++               * get rid of the fraction
++               */
++              err = qman_ceetm_set_queue_weight_in_ratio(cl->wbfs.cq,
++                                                         copt->weight * 100);
++
++              if (err) {
++                      pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm wbfs class %X\n",
++                             __func__, cl->common.classid);
++                      return err;
++              }
++
++              cl->wbfs.weight = copt->weight;
++      }
++
++      return 0;
++}
++
++/* Add a ceetm root class or configure a ceetm root/prio/wbfs class */
++static int ceetm_cls_change(struct Qdisc *sch, u32 classid, u32 parentid,
++                          struct nlattr **tca, unsigned long *arg)
++{
++      int err;
++      u64 bps;
++      struct ceetm_qdisc *priv;
++      struct ceetm_class *cl = (struct ceetm_class *)*arg;
++      struct nlattr *opt = tca[TCA_OPTIONS];
++      struct nlattr *tb[__TCA_CEETM_MAX];
++      struct tc_ceetm_copt *copt;
++      struct qm_ceetm_channel *channel;
++      struct net_device *dev = qdisc_dev(sch);
++
++      pr_debug(KBUILD_BASENAME " : %s : classid %X under qdisc %X\n",
++               __func__, classid, sch->handle);
++
++      if (strcmp(sch->ops->id, ceetm_qdisc_ops.id)) {
++              pr_err("CEETM: a ceetm class can not be attached to other qdisc/class types\n");
++              return -EINVAL;
++      }
++
++      priv = qdisc_priv(sch);
++
++      if (!opt) {
++              pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
++              return -EINVAL;
++      }
++
++      if (!cl && sch->handle != parentid) {
++              pr_err("CEETM: classes can be attached to the root ceetm qdisc only\n");
++              return -EINVAL;
++      }
++
++      if (!cl && priv->type != CEETM_ROOT) {
++              pr_err("CEETM: only root ceetm classes can be attached to the root ceetm qdisc\n");
++              return -EINVAL;
++      }
++
++      err = nla_parse_nested(tb, TCA_CEETM_COPT, opt, ceetm_policy);
++      if (err < 0) {
++              pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
++              return -EINVAL;
++      }
++
++      if (!tb[TCA_CEETM_COPT]) {
++              pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
++              return -EINVAL;
++      }
++
++      if (TC_H_MIN(classid) >= PFIFO_MIN_OFFSET) {
++              pr_err("CEETM: only minors 0x01 to 0x20 can be used for ceetm root classes\n");
++              return -EINVAL;
++      }
++
++      copt = nla_data(tb[TCA_CEETM_COPT]);
++
++      /* Configure an existing ceetm class */
++      if (cl) {
++              if (copt->type != cl->type) {
++                      pr_err("CEETM: class %X is not of the provided type\n",
++                             cl->common.classid);
++                      return -EINVAL;
++              }
++
++              switch (copt->type) {
++              case CEETM_ROOT:
++                      return ceetm_cls_change_root(cl, copt, dev);
++
++              case CEETM_PRIO:
++                      return ceetm_cls_change_prio(cl, copt);
++
++              case CEETM_WBFS:
++                      return ceetm_cls_change_wbfs(cl, copt);
++
++              default:
++                      pr_err(KBUILD_BASENAME " : %s : invalid class\n",
++                             __func__);
++                      return -EINVAL;
++              }
++      }
++
++      /* Add a new root ceetm class */
++      if (copt->type != CEETM_ROOT) {
++              pr_err("CEETM: only root ceetm classes can be attached to the root ceetm qdisc\n");
++              return -EINVAL;
++      }
++
++      if (copt->shaped && !priv->shaped) {
++              pr_err("CEETM: can not add a shaped ceetm root class under an unshaped ceetm root qdisc\n");
++              return -EINVAL;
++      }
++
++      cl = kzalloc(sizeof(*cl), GFP_KERNEL);
++      if (!cl)
++              return -ENOMEM;
++
++      cl->type = copt->type;
++      cl->shaped = copt->shaped;
++      cl->root.rate = copt->rate;
++      cl->root.ceil = copt->ceil;
++      cl->root.tbl = copt->tbl;
++
++      cl->common.classid = classid;
++      cl->refcnt = 1;
++      cl->parent = sch;
++      cl->root.child = NULL;
++      cl->root.wbfs_grp_a = false;
++      cl->root.wbfs_grp_b = false;
++      cl->root.wbfs_grp_large = false;
++
++      /* Claim a CEETM channel */
++      err = qman_ceetm_channel_claim(&channel, priv->root.lni);
++      if (err) {
++              pr_err(KBUILD_BASENAME " : %s : failed to claim a channel\n",
++                     __func__);
++              goto claim_err;
++      }
++
++      cl->root.ch = channel;
++
++      if (cl->shaped) {
++              /* Configure the channel shaper */
++              err = qman_ceetm_channel_enable_shaper(channel, 1);
++              if (err)
++                      goto channel_err;
++
++              bps = cl->root.rate << 3; /* Bps -> bps */
++              err = qman_ceetm_channel_set_commit_rate_bps(channel, bps,
++                                                           dev->mtu);
++              if (err)
++                      goto channel_err;
++
++              bps = cl->root.ceil << 3; /* Bps -> bps */
++              err = qman_ceetm_channel_set_excess_rate_bps(channel, bps,
++                                                           dev->mtu);
++              if (err)
++                      goto channel_err;
++
++      } else {
++              /* Configure the uFQ algorithm */
++              err = qman_ceetm_channel_set_weight(channel, cl->root.tbl);
++              if (err)
++                      goto channel_err;
++      }
++
++      /* Add class handle in Qdisc */
++      ceetm_link_class(sch, &priv->clhash, &cl->common);
++
++      pr_debug(KBUILD_BASENAME " : %s : configured class %X associated with channel %d\n",
++               __func__, classid, channel->idx);
++      *arg = (unsigned long)cl;
++      return 0;
++
++channel_err:
++      pr_err(KBUILD_BASENAME " : %s : failed to configure the channel %d\n",
++             __func__, channel->idx);
++      if (qman_ceetm_channel_release(channel))
++              pr_err(KBUILD_BASENAME " : %s : failed to release the channel %d\n",
++                     __func__, channel->idx);
++claim_err:
++      kfree(cl);
++      return err;
++}
++
++static void ceetm_cls_walk(struct Qdisc *sch, struct qdisc_walker *arg)
++{
++      struct ceetm_qdisc *priv = qdisc_priv(sch);
++      struct ceetm_class *cl;
++      unsigned int i;
++
++      pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
++
++      if (arg->stop)
++              return;
++
++      for (i = 0; i < priv->clhash.hashsize; i++) {
++              hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode) {
++                      if (arg->count < arg->skip) {
++                              arg->count++;
++                              continue;
++                      }
++                      if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
++                              arg->stop = 1;
++                              return;
++                      }
++                      arg->count++;
++              }
++      }
++}
++
++static int ceetm_cls_dump(struct Qdisc *sch, unsigned long arg,
++                        struct sk_buff *skb, struct tcmsg *tcm)
++{
++      struct ceetm_class *cl = (struct ceetm_class *)arg;
++      struct nlattr *nest;
++      struct tc_ceetm_copt copt;
++
++      pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
++               __func__, cl->common.classid, sch->handle);
++
++      sch_tree_lock(sch);
++
++      tcm->tcm_parent = ((struct Qdisc *)cl->parent)->handle;
++      tcm->tcm_handle = cl->common.classid;
++
++      memset(&copt, 0, sizeof(copt));
++
++      copt.shaped = cl->shaped;
++      copt.type = cl->type;
++
++      switch (cl->type) {
++      case CEETM_ROOT:
++              if (cl->root.child)
++                      tcm->tcm_info = cl->root.child->handle;
++
++              copt.rate = cl->root.rate;
++              copt.ceil = cl->root.ceil;
++              copt.tbl = cl->root.tbl;
++              break;
++
++      case CEETM_PRIO:
++              if (cl->prio.child)
++                      tcm->tcm_info = cl->prio.child->handle;
++
++              copt.cr = cl->prio.cr;
++              copt.er = cl->prio.er;
++              break;
++
++      case CEETM_WBFS:
++              copt.weight = cl->wbfs.weight;
++              break;
++      }
++
++      nest = nla_nest_start(skb, TCA_OPTIONS);
++      if (!nest)
++              goto nla_put_failure;
++      if (nla_put(skb, TCA_CEETM_COPT, sizeof(copt), &copt))
++              goto nla_put_failure;
++      nla_nest_end(skb, nest);
++      sch_tree_unlock(sch);
++      return skb->len;
++
++nla_put_failure:
++      sch_tree_unlock(sch);
++      nla_nest_cancel(skb, nest);
++      return -EMSGSIZE;
++}
++
++static int ceetm_cls_delete(struct Qdisc *sch, unsigned long arg)
++{
++      struct ceetm_qdisc *priv = qdisc_priv(sch);
++      struct ceetm_class *cl = (struct ceetm_class *)arg;
++
++      pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
++               __func__, cl->common.classid, sch->handle);
++
++      sch_tree_lock(sch);
++      qdisc_class_hash_remove(&priv->clhash, &cl->common);
++      cl->refcnt--;
++
++      /* The refcnt should be at least 1 since we have incremented it in
++       * get(). Will decrement again in put() where we will call destroy()
++       * to actually free the memory if it reaches 0.
++       */
++      WARN_ON(cl->refcnt == 0);
++
++      sch_tree_unlock(sch);
++      return 0;
++}
++
++/* Get the class' child qdisc, if any */
++static struct Qdisc *ceetm_cls_leaf(struct Qdisc *sch, unsigned long arg)
++{
++      struct ceetm_class *cl = (struct ceetm_class *)arg;
++
++      pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
++               __func__, cl->common.classid, sch->handle);
++
++      switch (cl->type) {
++      case CEETM_ROOT:
++              return cl->root.child;
++
++      case CEETM_PRIO:
++              return cl->prio.child;
++      }
++
++      return NULL;
++}
++
++static int ceetm_cls_graft(struct Qdisc *sch, unsigned long arg,
++                         struct Qdisc *new, struct Qdisc **old)
++{
++      if (new && strcmp(new->ops->id, ceetm_qdisc_ops.id)) {
++              pr_err("CEETM: only ceetm qdiscs can be attached to ceetm classes\n");
++              return -EOPNOTSUPP;
++      }
++
++      return 0;
++}
++
++static int ceetm_cls_dump_stats(struct Qdisc *sch, unsigned long arg,
++                              struct gnet_dump *d)
++{
++      unsigned int i;
++      struct ceetm_class *cl = (struct ceetm_class *)arg;
++      struct gnet_stats_basic_packed tmp_bstats;
++      struct ceetm_class_stats *cstats = NULL;
++      struct qm_ceetm_cq *cq = NULL;
++      struct tc_ceetm_xstats xstats;
++
++      memset(&xstats, 0, sizeof(xstats));
++      memset(&tmp_bstats, 0, sizeof(tmp_bstats));
++
++      switch (cl->type) {
++      case CEETM_ROOT:
++              return 0;
++      case CEETM_PRIO:
++              cq = cl->prio.cq;
++              break;
++      case CEETM_WBFS:
++              cq = cl->wbfs.cq;
++              break;
++      }
++
++      for_each_online_cpu(i) {
++              switch (cl->type) {
++              case CEETM_PRIO:
++                      cstats = per_cpu_ptr(cl->prio.cstats, i);
++                      break;
++              case CEETM_WBFS:
++                      cstats = per_cpu_ptr(cl->wbfs.cstats, i);
++                      break;
++              }
++
++              if (cstats) {
++                      xstats.ern_drop_count += cstats->ern_drop_count;
++                      xstats.congested_count += cstats->congested_count;
++                      tmp_bstats.bytes += cstats->bstats.bytes;
++                      tmp_bstats.packets += cstats->bstats.packets;
++              }
++      }
++
++      if (gnet_stats_copy_basic(d, NULL, &tmp_bstats) < 0)
++              return -1;
++
++      if (cq && qman_ceetm_cq_get_dequeue_statistics(cq, 0,
++                                                     &xstats.frame_count,
++                                                     &xstats.byte_count))
++              return -1;
++
++      return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
++}
++
++static struct tcf_proto **ceetm_tcf_chain(struct Qdisc *sch, unsigned long arg)
++{
++      struct ceetm_qdisc *priv = qdisc_priv(sch);
++      struct ceetm_class *cl = (struct ceetm_class *)arg;
++      struct tcf_proto **fl = cl ? &cl->filter_list : &priv->filter_list;
++
++      pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
++               cl ? cl->common.classid : 0, sch->handle);
++      return fl;
++}
++
++static unsigned long ceetm_tcf_bind(struct Qdisc *sch, unsigned long parent,
++                                  u32 classid)
++{
++      struct ceetm_class *cl = ceetm_find(classid, sch);
++
++      pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
++               cl ? cl->common.classid : 0, sch->handle);
++      return (unsigned long)cl;
++}
++
++static void ceetm_tcf_unbind(struct Qdisc *sch, unsigned long arg)
++{
++      struct ceetm_class *cl = (struct ceetm_class *)arg;
++
++      pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
++               cl ? cl->common.classid : 0, sch->handle);
++}
++
++const struct Qdisc_class_ops ceetm_cls_ops = {
++      .graft          =       ceetm_cls_graft,
++      .leaf           =       ceetm_cls_leaf,
++      .get            =       ceetm_cls_get,
++      .put            =       ceetm_cls_put,
++      .change         =       ceetm_cls_change,
++      .delete         =       ceetm_cls_delete,
++      .walk           =       ceetm_cls_walk,
++      .tcf_chain      =       ceetm_tcf_chain,
++      .bind_tcf       =       ceetm_tcf_bind,
++      .unbind_tcf     =       ceetm_tcf_unbind,
++      .dump           =       ceetm_cls_dump,
++      .dump_stats     =       ceetm_cls_dump_stats,
++};
++
++struct Qdisc_ops ceetm_qdisc_ops __read_mostly = {
++      .id             =       "ceetm",
++      .priv_size      =       sizeof(struct ceetm_qdisc),
++      .cl_ops         =       &ceetm_cls_ops,
++      .init           =       ceetm_init,
++      .destroy        =       ceetm_destroy,
++      .change         =       ceetm_change,
++      .dump           =       ceetm_dump,
++      .attach         =       ceetm_attach,
++      .owner          =       THIS_MODULE,
++};
++
++/* Run the filters and classifiers attached to the qdisc on the provided skb */
++static struct ceetm_class *ceetm_classify(struct sk_buff *skb,
++                                        struct Qdisc *sch, int *qerr,
++                                        bool *act_drop)
++{
++      struct ceetm_qdisc *priv = qdisc_priv(sch);
++      struct ceetm_class *cl = NULL, *wbfs_cl;
++      struct tcf_result res;
++      struct tcf_proto *tcf;
++      int result;
++
++      *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
++      tcf = priv->filter_list;
++      while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) {
++#ifdef CONFIG_NET_CLS_ACT
++              switch (result) {
++              case TC_ACT_QUEUED:
++              case TC_ACT_STOLEN:
++                      *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
++              case TC_ACT_SHOT:
++                      /* No valid class found due to action */
++                      *act_drop = true;
++                      return NULL;
++              }
++#endif
++              cl = (void *)res.class;
++              if (!cl) {
++                      if (res.classid == sch->handle) {
++                              /* The filter leads to the qdisc */
++                              /* TODO default qdisc */
++                              return NULL;
++                      }
++
++                      cl = ceetm_find(res.classid, sch);
++                      if (!cl)
++                              /* The filter leads to an invalid class */
++                              break;
++              }
++
++              /* The class might have its own filters attached */
++              tcf = cl->filter_list;
++      }
++
++      if (!cl) {
++              /* No valid class found */
++              /* TODO default qdisc */
++              return NULL;
++      }
++
++      switch (cl->type) {
++      case CEETM_ROOT:
++              if (cl->root.child) {
++                      /* Run the prio qdisc classifiers */
++                      return ceetm_classify(skb, cl->root.child, qerr,
++                                              act_drop);
++              } else {
++                      /* The root class does not have a child prio qdisc */
++                      /* TODO default qdisc */
++                      return NULL;
++              }
++      case CEETM_PRIO:
++              if (cl->prio.child) {
++                      /* If filters lead to a wbfs class, return it.
++                       * Otherwise, return the prio class
++                       */
++                      wbfs_cl = ceetm_classify(skb, cl->prio.child, qerr,
++                                               act_drop);
++                      /* A NULL result might indicate either an erroneous
++                       * filter, or no filters at all. We will assume the
++                       * latter
++                       */
++                      return wbfs_cl ? : cl;
++              }
++      }
++
++      /* For wbfs and childless prio classes, return the class directly */
++      return cl;
++}
++
++int __hot ceetm_tx(struct sk_buff *skb, struct net_device *net_dev)
++{
++      int ret;
++      bool act_drop = false;
++      struct Qdisc *sch = net_dev->qdisc;
++      struct ceetm_class *cl;
++      struct dpa_priv_s *priv_dpa;
++      struct qman_fq *egress_fq, *conf_fq;
++      struct ceetm_qdisc *priv = qdisc_priv(sch);
++      struct ceetm_qdisc_stats *qstats = this_cpu_ptr(priv->root.qstats);
++      struct ceetm_class_stats *cstats;
++      const int queue_mapping = dpa_get_queue_mapping(skb);
++      spinlock_t *root_lock = qdisc_lock(sch);
++
++      spin_lock(root_lock);
++      cl = ceetm_classify(skb, sch, &ret, &act_drop);
++      spin_unlock(root_lock);
++
++#ifdef CONFIG_NET_CLS_ACT
++      if (act_drop) {
++              if (ret & __NET_XMIT_BYPASS)
++                      qstats->drops++;
++              goto drop;
++      }
++#endif
++      /* TODO default class */
++      if (unlikely(!cl)) {
++              qstats->drops++;
++              goto drop;
++      }
++
++      priv_dpa = netdev_priv(net_dev);
++      conf_fq = priv_dpa->conf_fqs[queue_mapping];
++
++      /* Choose the proper tx fq and update the basic stats (bytes and
++       * packets sent by the class)
++       */
++      switch (cl->type) {
++      case CEETM_PRIO:
++              egress_fq = &cl->prio.fq->fq;
++              cstats = this_cpu_ptr(cl->prio.cstats);
++              break;
++      case CEETM_WBFS:
++              egress_fq = &cl->wbfs.fq->fq;
++              cstats = this_cpu_ptr(cl->wbfs.cstats);
++              break;
++      default:
++              qstats->drops++;
++              goto drop;
++      }
++
++      bstats_update(&cstats->bstats, skb);
++      return dpa_tx_extended(skb, net_dev, egress_fq, conf_fq);
++
++drop:
++      dev_kfree_skb_any(skb);
++      return NET_XMIT_SUCCESS;
++}
++
++static int __init ceetm_register(void)
++{
++      int _errno = 0;
++
++      pr_info(KBUILD_MODNAME ": " DPA_CEETM_DESCRIPTION "\n");
++
++      _errno = register_qdisc(&ceetm_qdisc_ops);
++      if (unlikely(_errno))
++              pr_err(KBUILD_MODNAME
++                     ": %s:%hu:%s(): register_qdisc() = %d\n",
++                     KBUILD_BASENAME ".c", __LINE__, __func__, _errno);
++
++      return _errno;
++}
++
++static void __exit ceetm_unregister(void)
++{
++      pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
++               KBUILD_BASENAME ".c", __func__);
++
++      unregister_qdisc(&ceetm_qdisc_ops);
++}
++
++module_init(ceetm_register);
++module_exit(ceetm_unregister);
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h
+@@ -0,0 +1,236 @@
++/* Copyright 2008-2016 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __DPAA_ETH_CEETM_H
++#define __DPAA_ETH_CEETM_H
++
++#include <net/pkt_sched.h>
++#include <net/netlink.h>
++#include <lnxwrp_fm.h>
++
++#include "mac.h"
++#include "dpaa_eth_common.h"
++
++/* Mask to determine the sub-portal id from a channel number */
++#define CHANNEL_SP_MASK               0x1f
++/* The number of the last channel that services DCP0, connected to FMan 0.
++ * Value validated for B4 and T series platforms.
++ */
++#define DCP0_MAX_CHANNEL      0x80f
++/* A2V=1 - field A2 is valid
++ * A0V=1 - field A0 is valid - enables frame confirmation
++ * OVOM=1 - override operation mode bits with values from A2
++ * EBD=1 - external buffers are deallocated at the end of the FMan flow
++ * NL=0 - the BMI releases all the internal buffers
++ */
++#define CEETM_CONTEXT_A               0x1a00000080000000
++/* The ratio between the superior and inferior congestion state thresholds. The
++ * lower threshold is set to 7/8 of the superior one (as the default for WQ
++ * scheduling).
++ */
++#define CEETM_CCGR_RATIO      0.875
++/* For functional purposes, there are num_tx_queues pfifo qdiscs through which
++ * frames reach the driver. Their handles start from 1:21. Handles 1:1 to 1:20
++ * are reserved for the maximum 32 CEETM channels (majors and minors are in
++ * hex).
++ */
++#define PFIFO_MIN_OFFSET      0x21
++
++/* A maximum of 8 CQs can be linked to a CQ channel or to a WBFS scheduler. */
++#define CEETM_MAX_PRIO_QCOUNT 8
++#define CEETM_MAX_WBFS_QCOUNT 8
++#define CEETM_MIN_WBFS_QCOUNT 4
++
++/* The id offsets of the CQs belonging to WBFS groups (ids 8-11/15 for group A
++ * and/or 12-15 for group B).
++ */
++#define WBFS_GRP_A_OFFSET     8
++#define WBFS_GRP_B_OFFSET     12
++
++#define WBFS_GRP_A    1
++#define WBFS_GRP_B    2
++#define WBFS_GRP_LARGE        3
++
++enum {
++      TCA_CEETM_UNSPEC,
++      TCA_CEETM_COPT,
++      TCA_CEETM_QOPS,
++      __TCA_CEETM_MAX,
++};
++
++/* CEETM configuration types */
++enum {
++      CEETM_ROOT = 1,
++      CEETM_PRIO,
++      CEETM_WBFS
++};
++
++#define TCA_CEETM_MAX (__TCA_CEETM_MAX - 1)
++extern const struct nla_policy ceetm_policy[TCA_CEETM_MAX + 1];
++
++struct ceetm_class;
++struct ceetm_qdisc_stats;
++struct ceetm_class_stats;
++
++struct ceetm_fq {
++      struct qman_fq fq;
++      struct net_device *net_dev;
++      struct ceetm_class *ceetm_cls;
++};
++
++struct root_q {
++      struct Qdisc **qdiscs;
++      __u16 overhead;
++      __u32 rate;
++      __u32 ceil;
++      struct qm_ceetm_sp *sp;
++      struct qm_ceetm_lni *lni;
++      struct ceetm_qdisc_stats __percpu *qstats;
++};
++
++struct prio_q {
++      __u16 qcount;
++      struct ceetm_class *parent;
++};
++
++struct wbfs_q {
++      __u16 qcount;
++      int group_type;
++      struct ceetm_class *parent;
++      __u16 cr;
++      __u16 er;
++};
++
++struct ceetm_qdisc {
++      int type; /* LNI/CHNL/WBFS */
++      bool shaped;
++      union {
++              struct root_q root;
++              struct prio_q prio;
++              struct wbfs_q wbfs;
++      };
++      struct Qdisc_class_hash clhash;
++      struct tcf_proto *filter_list; /* qdisc attached filters */
++};
++
++/* CEETM Qdisc configuration parameters */
++struct tc_ceetm_qopt {
++      __u32 type;
++      __u16 shaped;
++      __u16 qcount;
++      __u16 overhead;
++      __u32 rate;
++      __u32 ceil;
++      __u16 cr;
++      __u16 er;
++      __u8 qweight[CEETM_MAX_WBFS_QCOUNT];
++};
++
++struct root_c {
++      unsigned int rate;
++      unsigned int ceil;
++      unsigned int tbl;
++      bool wbfs_grp_a;
++      bool wbfs_grp_b;
++      bool wbfs_grp_large;
++      struct Qdisc *child;
++      struct qm_ceetm_channel *ch;
++};
++
++struct prio_c {
++      bool cr;
++      bool er;
++      struct ceetm_fq *fq; /* Hardware FQ instance Handle */
++      struct qm_ceetm_lfq *lfq;
++      struct qm_ceetm_cq *cq; /* Hardware Class Queue instance Handle */
++      struct qm_ceetm_ccg *ccg;
++      /* only one wbfs can be linked to one priority CQ */
++      struct Qdisc *child;
++      struct ceetm_class_stats __percpu *cstats;
++};
++
++struct wbfs_c {
++      __u8 weight; /* The weight of the class between 1 and 248 */
++      struct ceetm_fq *fq; /* Hardware FQ instance Handle */
++      struct qm_ceetm_lfq *lfq;
++      struct qm_ceetm_cq *cq; /* Hardware Class Queue instance Handle */
++      struct qm_ceetm_ccg *ccg;
++      struct ceetm_class_stats __percpu *cstats;
++};
++
++struct ceetm_class {
++      struct Qdisc_class_common common;
++      int refcnt; /* usage count of this class */
++      struct tcf_proto *filter_list; /* class attached filters */
++      struct Qdisc *parent;
++      bool shaped;
++      int type; /* ROOT/PRIO/WBFS */
++      union {
++              struct root_c root;
++              struct prio_c prio;
++              struct wbfs_c wbfs;
++      };
++};
++
++/* CEETM Class configuration parameters */
++struct tc_ceetm_copt {
++      __u32 type;
++      __u16 shaped;
++      __u32 rate;
++      __u32 ceil;
++      __u16 tbl;
++      __u16 cr;
++      __u16 er;
++      __u8 weight;
++};
++
++/* CEETM stats */
++struct ceetm_qdisc_stats {
++      __u32 drops;
++};
++
++struct ceetm_class_stats {
++      /* Software counters */
++      struct gnet_stats_basic_packed bstats;
++      __u32 ern_drop_count;
++      __u32 congested_count;
++};
++
++struct tc_ceetm_xstats {
++      __u32 ern_drop_count;
++      __u32 congested_count;
++      /* Hardware counters */
++      __u64 frame_count;
++      __u64 byte_count;
++};
++
++int __hot ceetm_tx(struct sk_buff *skb, struct net_device *net_dev);
++#endif
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
+@@ -0,0 +1,1812 @@
++/* Copyright 2008-2013 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include <linux/of_net.h>
++#include <linux/etherdevice.h>
++#include <linux/kthread.h>
++#include <linux/percpu.h>
++#include <linux/highmem.h>
++#include <linux/sort.h>
++#include <linux/fsl_qman.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <linux/if_vlan.h>    /* vlan_eth_hdr */
++#include "dpaa_eth.h"
++#include "dpaa_eth_common.h"
++#ifdef CONFIG_FSL_DPAA_1588
++#include "dpaa_1588.h"
++#endif
++#ifdef CONFIG_FSL_DPAA_DBG_LOOP
++#include "dpaa_debugfs.h"
++#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
++#include "mac.h"
++
++/* Size in bytes of the FQ taildrop threshold */
++#define DPA_FQ_TD             0x200000
++
++#ifdef CONFIG_PTP_1588_CLOCK_DPAA
++struct ptp_priv_s ptp_priv;
++#endif
++
++static struct dpa_bp *dpa_bp_array[64];
++
++int dpa_max_frm;
++EXPORT_SYMBOL(dpa_max_frm);
++
++int dpa_rx_extra_headroom;
++EXPORT_SYMBOL(dpa_rx_extra_headroom);
++
++int dpa_num_cpus = NR_CPUS;
++
++static const struct fqid_cell tx_confirm_fqids[] = {
++      {0, DPAA_ETH_TX_QUEUES}
++};
++
++static struct fqid_cell default_fqids[][3] = {
++      [RX] = { {0, 1}, {0, 1}, {0, DPAA_ETH_RX_QUEUES} },
++      [TX] = { {0, 1}, {0, 1}, {0, DPAA_ETH_TX_QUEUES} }
++};
++
++static const char fsl_qman_frame_queues[][25] = {
++      [RX] = "fsl,qman-frame-queues-rx",
++      [TX] = "fsl,qman-frame-queues-tx"
++};
++#ifdef CONFIG_FSL_DPAA_HOOKS
++/* A set of callbacks for hooking into the fastpath at different points. */
++struct dpaa_eth_hooks_s dpaa_eth_hooks;
++EXPORT_SYMBOL(dpaa_eth_hooks);
++/* This function should only be called on the probe paths, since it makes no
++ * effort to guarantee consistency of the destination hooks structure.
++ */
++void fsl_dpaa_eth_set_hooks(struct dpaa_eth_hooks_s *hooks)
++{
++      if (hooks)
++              dpaa_eth_hooks = *hooks;
++      else
++              pr_err("NULL pointer to hooks!\n");
++}
++EXPORT_SYMBOL(fsl_dpaa_eth_set_hooks);
++#endif
++
++int dpa_netdev_init(struct net_device *net_dev,
++                  const uint8_t *mac_addr,
++                  uint16_t tx_timeout)
++{
++      int err;
++      struct dpa_priv_s *priv = netdev_priv(net_dev);
++      struct device *dev = net_dev->dev.parent;
++
++      net_dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
++
++      net_dev->features |= net_dev->hw_features;
++      net_dev->vlan_features = net_dev->features;
++
++      memcpy(net_dev->perm_addr, mac_addr, net_dev->addr_len);
++      memcpy(net_dev->dev_addr, mac_addr, net_dev->addr_len);
++
++      net_dev->ethtool_ops = &dpa_ethtool_ops;
++
++      net_dev->needed_headroom = priv->tx_headroom;
++      net_dev->watchdog_timeo = msecs_to_jiffies(tx_timeout);
++
++      err = register_netdev(net_dev);
++      if (err < 0) {
++              dev_err(dev, "register_netdev() = %d\n", err);
++              return err;
++      }
++
++#ifdef CONFIG_FSL_DPAA_DBG_LOOP
++      /* create debugfs entry for this net_device */
++      err = dpa_netdev_debugfs_create(net_dev);
++      if (err) {
++              unregister_netdev(net_dev);
++              return err;
++      }
++#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
++
++      return 0;
++}
++EXPORT_SYMBOL(dpa_netdev_init);
++
++int __cold dpa_start(struct net_device *net_dev)
++{
++      int err, i;
++      struct dpa_priv_s *priv;
++      struct mac_device *mac_dev;
++
++      priv = netdev_priv(net_dev);
++      mac_dev = priv->mac_dev;
++
++      err = mac_dev->init_phy(net_dev, priv->mac_dev);
++      if (err < 0) {
++              if (netif_msg_ifup(priv))
++                      netdev_err(net_dev, "init_phy() = %d\n", err);
++              return err;
++      }
++
++      for_each_port_device(i, mac_dev->port_dev) {
++              err = fm_port_enable(mac_dev->port_dev[i]);
++              if (err)
++                      goto mac_start_failed;
++      }
++
++      err = priv->mac_dev->start(mac_dev);
++      if (err < 0) {
++              if (netif_msg_ifup(priv))
++                      netdev_err(net_dev, "mac_dev->start() = %d\n", err);
++              goto mac_start_failed;
++      }
++
++      netif_tx_start_all_queues(net_dev);
++
++      return 0;
++
++mac_start_failed:
++      for_each_port_device(i, mac_dev->port_dev)
++              fm_port_disable(mac_dev->port_dev[i]);
++
++      return err;
++}
++EXPORT_SYMBOL(dpa_start);
++
++int __cold dpa_stop(struct net_device *net_dev)
++{
++      int _errno, i, err;
++      struct dpa_priv_s *priv;
++      struct mac_device *mac_dev;
++
++      priv = netdev_priv(net_dev);
++      mac_dev = priv->mac_dev;
++
++      netif_tx_stop_all_queues(net_dev);
++      /* Allow the Fman (Tx) port to process in-flight frames before we
++       * try switching it off.
++       */
++      usleep_range(5000, 10000);
++
++      _errno = mac_dev->stop(mac_dev);
++      if (unlikely(_errno < 0))
++              if (netif_msg_ifdown(priv))
++                      netdev_err(net_dev, "mac_dev->stop() = %d\n",
++                                      _errno);
++
++      for_each_port_device(i, mac_dev->port_dev) {
++              err = fm_port_disable(mac_dev->port_dev[i]);
++              _errno = err ? err : _errno;
++      }
++
++      if (mac_dev->phy_dev)
++              phy_disconnect(mac_dev->phy_dev);
++      mac_dev->phy_dev = NULL;
++
++      return _errno;
++}
++EXPORT_SYMBOL(dpa_stop);
++
++void __cold dpa_timeout(struct net_device *net_dev)
++{
++      const struct dpa_priv_s *priv;
++      struct dpa_percpu_priv_s *percpu_priv;
++
++      priv = netdev_priv(net_dev);
++      percpu_priv = raw_cpu_ptr(priv->percpu_priv);
++
++      if (netif_msg_timer(priv))
++              netdev_crit(net_dev, "Transmit timeout!\n");
++
++      percpu_priv->stats.tx_errors++;
++}
++EXPORT_SYMBOL(dpa_timeout);
++
++/* net_device */
++
++/**
++ * @param net_dev the device for which statistics are calculated
++ * @param stats the function fills this structure with the device's statistics
++ * @return the address of the structure containing the statistics
++ *
++ * Calculates the statistics for the given device by adding the statistics
++ * collected by each CPU.
++ */
++void __cold
++dpa_get_stats64(struct net_device *net_dev,
++              struct rtnl_link_stats64 *stats)
++{
++      struct dpa_priv_s *priv = netdev_priv(net_dev);
++      u64 *cpustats;
++      u64 *netstats = (u64 *)stats;
++      int i, j;
++      struct dpa_percpu_priv_s        *percpu_priv;
++      int numstats = sizeof(struct rtnl_link_stats64) / sizeof(u64);
++
++      for_each_possible_cpu(i) {
++              percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
++
++              cpustats = (u64 *)&percpu_priv->stats;
++
++              for (j = 0; j < numstats; j++)
++                      netstats[j] += cpustats[j];
++      }
++}
++EXPORT_SYMBOL(dpa_get_stats64);
++
++int dpa_change_mtu(struct net_device *net_dev, int new_mtu)
++{
++      const int max_mtu = dpa_get_max_mtu();
++
++      /* Make sure we don't exceed the Ethernet controller's MAXFRM */
++      if (new_mtu < 68 || new_mtu > max_mtu) {
++              netdev_err(net_dev, "Invalid L3 mtu %d (must be between %d and %d).\n",
++                              new_mtu, 68, max_mtu);
++              return -EINVAL;
++      }
++      net_dev->mtu = new_mtu;
++
++      return 0;
++}
++EXPORT_SYMBOL(dpa_change_mtu);
++
++/* .ndo_init callback */
++int dpa_ndo_init(struct net_device *net_dev)
++{
++      /* If fsl_fm_max_frm is set to a higher value than the all-common 1500,
++       * we choose conservatively and let the user explicitly set a higher
++       * MTU via ifconfig. Otherwise, the user may end up with different MTUs
++       * in the same LAN.
++       * If on the other hand fsl_fm_max_frm has been chosen below 1500,
++       * start with the maximum allowed.
++       */
++      int init_mtu = min(dpa_get_max_mtu(), ETH_DATA_LEN);
++
++      pr_debug("Setting initial MTU on net device: %d\n", init_mtu);
++      net_dev->mtu = init_mtu;
++
++      return 0;
++}
++EXPORT_SYMBOL(dpa_ndo_init);
++
++int dpa_set_features(struct net_device *dev, netdev_features_t features)
++{
++      /* Not much to do here for now */
++      dev->features = features;
++      return 0;
++}
++EXPORT_SYMBOL(dpa_set_features);
++
++netdev_features_t dpa_fix_features(struct net_device *dev,
++              netdev_features_t features)
++{
++      netdev_features_t unsupported_features = 0;
++
++      /* In theory we should never be requested to enable features that
++       * we didn't set in netdev->features and netdev->hw_features at probe
++       * time, but double check just to be on the safe side.
++       * We don't support enabling Rx csum through ethtool yet
++       */
++      unsupported_features |= NETIF_F_RXCSUM;
++
++      features &= ~unsupported_features;
++
++      return features;
++}
++EXPORT_SYMBOL(dpa_fix_features);
++
++#ifdef CONFIG_FSL_DPAA_TS
++u64 dpa_get_timestamp_ns(const struct dpa_priv_s *priv, enum port_type rx_tx,
++                      const void *data)
++{
++      u64 *ts, ns;
++
++      ts = fm_port_get_buffer_time_stamp(priv->mac_dev->port_dev[rx_tx],
++                                         data);
++
++      if (!ts || *ts == 0)
++              return 0;
++
++      be64_to_cpus(ts);
++
++      /* multiple DPA_PTP_NOMINAL_FREQ_PERIOD_NS for case of non power of 2 */
++      ns = *ts << DPA_PTP_NOMINAL_FREQ_PERIOD_SHIFT;
++
++      return ns;
++}
++
++int dpa_get_ts(const struct dpa_priv_s *priv, enum port_type rx_tx,
++      struct skb_shared_hwtstamps *shhwtstamps, const void *data)
++{
++      u64 ns;
++
++      ns = dpa_get_timestamp_ns(priv, rx_tx, data);
++
++      if (ns == 0)
++              return -EINVAL;
++
++      memset(shhwtstamps, 0, sizeof(*shhwtstamps));
++      shhwtstamps->hwtstamp = ns_to_ktime(ns);
++
++      return 0;
++}
++
++static void dpa_ts_tx_enable(struct net_device *dev)
++{
++      struct dpa_priv_s *priv = netdev_priv(dev);
++      struct mac_device *mac_dev = priv->mac_dev;
++
++      if (mac_dev->fm_rtc_enable)
++              mac_dev->fm_rtc_enable(get_fm_handle(dev));
++      if (mac_dev->ptp_enable)
++              mac_dev->ptp_enable(mac_dev->get_mac_handle(mac_dev));
++
++      priv->ts_tx_en = true;
++}
++
++static void dpa_ts_tx_disable(struct net_device *dev)
++{
++      struct dpa_priv_s *priv = netdev_priv(dev);
++
++#if 0
++/* the RTC might be needed by the Rx Ts, cannot disable here
++ * no separate ptp_disable API for Rx/Tx, cannot disable here
++ */
++      struct mac_device *mac_dev = priv->mac_dev;
++
++      if (mac_dev->fm_rtc_disable)
++              mac_dev->fm_rtc_disable(get_fm_handle(dev));
++
++      if (mac_dev->ptp_disable)
++              mac_dev->ptp_disable(mac_dev->get_mac_handle(mac_dev));
++#endif
++
++      priv->ts_tx_en = false;
++}
++
++static void dpa_ts_rx_enable(struct net_device *dev)
++{
++      struct dpa_priv_s *priv = netdev_priv(dev);
++      struct mac_device *mac_dev = priv->mac_dev;
++
++      if (mac_dev->fm_rtc_enable)
++              mac_dev->fm_rtc_enable(get_fm_handle(dev));
++      if (mac_dev->ptp_enable)
++              mac_dev->ptp_enable(mac_dev->get_mac_handle(mac_dev));
++
++      priv->ts_rx_en = true;
++}
++
++static void dpa_ts_rx_disable(struct net_device *dev)
++{
++      struct dpa_priv_s *priv = netdev_priv(dev);
++
++#if 0
++/* the RTC might be needed by the Tx Ts, cannot disable here
++ * no separate ptp_disable API for Rx/Tx, cannot disable here
++ */
++      struct mac_device *mac_dev = priv->mac_dev;
++
++      if (mac_dev->fm_rtc_disable)
++              mac_dev->fm_rtc_disable(get_fm_handle(dev));
++
++      if (mac_dev->ptp_disable)
++              mac_dev->ptp_disable(mac_dev->get_mac_handle(mac_dev));
++#endif
++
++      priv->ts_rx_en = false;
++}
++
++static int dpa_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++      struct hwtstamp_config config;
++
++      if (copy_from_user(&config, rq->ifr_data, sizeof(config)))
++              return -EFAULT;
++
++      switch (config.tx_type) {
++      case HWTSTAMP_TX_OFF:
++              dpa_ts_tx_disable(dev);
++              break;
++      case HWTSTAMP_TX_ON:
++              dpa_ts_tx_enable(dev);
++              break;
++      default:
++              return -ERANGE;
++      }
++
++      if (config.rx_filter == HWTSTAMP_FILTER_NONE)
++              dpa_ts_rx_disable(dev);
++      else {
++              dpa_ts_rx_enable(dev);
++              /* TS is set for all frame types, not only those requested */
++              config.rx_filter = HWTSTAMP_FILTER_ALL;
++      }
++
++      return copy_to_user(rq->ifr_data, &config, sizeof(config)) ?
++                      -EFAULT : 0;
++}
++#endif /* CONFIG_FSL_DPAA_TS */
++
++int dpa_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++#ifdef CONFIG_FSL_DPAA_1588
++      struct dpa_priv_s *priv = netdev_priv(dev);
++#endif
++      int ret = 0;
++
++      /* at least one timestamping feature must be enabled */
++#ifdef CONFIG_FSL_DPAA_TS
++      if (!netif_running(dev))
++#endif
++              return -EINVAL;
++
++#ifdef CONFIG_FSL_DPAA_TS
++      if (cmd == SIOCSHWTSTAMP)
++              return dpa_ts_ioctl(dev, rq, cmd);
++#endif /* CONFIG_FSL_DPAA_TS */
++
++#ifdef CONFIG_FSL_DPAA_1588
++      if ((cmd >= PTP_ENBL_TXTS_IOCTL) && (cmd <= PTP_CLEANUP_TS)) {
++              if (priv->tsu && priv->tsu->valid)
++                      ret = dpa_ioctl_1588(dev, rq, cmd);
++              else
++                      ret = -ENODEV;
++      }
++#endif
++
++      return ret;
++}
++EXPORT_SYMBOL(dpa_ioctl);
++
++int __cold dpa_remove(struct platform_device *of_dev)
++{
++      int                     err;
++      struct device           *dev;
++      struct net_device       *net_dev;
++      struct dpa_priv_s       *priv;
++
++      dev = &of_dev->dev;
++      net_dev = dev_get_drvdata(dev);
++
++      priv = netdev_priv(net_dev);
++
++      dpaa_eth_sysfs_remove(dev);
++
++      dev_set_drvdata(dev, NULL);
++      unregister_netdev(net_dev);
++
++      err = dpa_fq_free(dev, &priv->dpa_fq_list);
++
++      qman_delete_cgr_safe(&priv->ingress_cgr);
++      qman_release_cgrid(priv->ingress_cgr.cgrid);
++      qman_delete_cgr_safe(&priv->cgr_data.cgr);
++      qman_release_cgrid(priv->cgr_data.cgr.cgrid);
++
++      dpa_private_napi_del(net_dev);
++
++      dpa_bp_free(priv);
++
++      if (priv->buf_layout)
++              devm_kfree(dev, priv->buf_layout);
++
++#ifdef CONFIG_FSL_DPAA_DBG_LOOP
++      /* remove debugfs entry for this net_device */
++      dpa_netdev_debugfs_remove(net_dev);
++#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
++
++#ifdef CONFIG_FSL_DPAA_1588
++      if (priv->tsu && priv->tsu->valid)
++              dpa_ptp_cleanup(priv);
++#endif
++
++      free_netdev(net_dev);
++
++      return err;
++}
++EXPORT_SYMBOL(dpa_remove);
++
++struct mac_device * __cold __must_check
++__attribute__((nonnull))
++dpa_mac_probe(struct platform_device *_of_dev)
++{
++      struct device           *dpa_dev, *dev;
++      struct device_node      *mac_node;
++      struct platform_device  *of_dev;
++      struct mac_device       *mac_dev;
++#ifdef CONFIG_FSL_DPAA_1588
++      int                      lenp;
++      const phandle           *phandle_prop;
++      struct net_device       *net_dev = NULL;
++      struct dpa_priv_s       *priv = NULL;
++      struct device_node      *timer_node;
++#endif
++      dpa_dev = &_of_dev->dev;
++
++      mac_node = of_parse_phandle(_of_dev->dev.of_node, "fsl,fman-mac", 0);
++      if (unlikely(mac_node == NULL)) {
++              dev_err(dpa_dev, "Cannot find MAC device device tree node\n");
++              return ERR_PTR(-EFAULT);
++      }
++
++      of_dev = of_find_device_by_node(mac_node);
++      if (unlikely(of_dev == NULL)) {
++              dev_err(dpa_dev, "of_find_device_by_node(%s) failed\n",
++                              mac_node->full_name);
++              of_node_put(mac_node);
++              return ERR_PTR(-EINVAL);
++      }
++      of_node_put(mac_node);
++
++      dev = &of_dev->dev;
++
++      mac_dev = dev_get_drvdata(dev);
++      if (unlikely(mac_dev == NULL)) {
++              dev_err(dpa_dev, "dev_get_drvdata(%s) failed\n",
++                              dev_name(dev));
++              return ERR_PTR(-EINVAL);
++      }
++
++#ifdef CONFIG_FSL_DPAA_1588
++      phandle_prop = of_get_property(mac_node, "ptimer-handle", &lenp);
++      if (phandle_prop && ((mac_dev->phy_if != PHY_INTERFACE_MODE_SGMII) ||
++                      ((mac_dev->phy_if == PHY_INTERFACE_MODE_SGMII) &&
++                       (mac_dev->speed == SPEED_1000)))) {
++              timer_node = of_find_node_by_phandle(*phandle_prop);
++              if (timer_node)
++                      net_dev = dev_get_drvdata(dpa_dev);
++              if (timer_node && net_dev) {
++                      priv = netdev_priv(net_dev);
++                      if (!dpa_ptp_init(priv))
++                              dev_info(dev, "%s: ptp 1588 is initialized.\n",
++                                              mac_node->full_name);
++              }
++      }
++#endif
++
++#ifdef CONFIG_PTP_1588_CLOCK_DPAA
++      if ((mac_dev->phy_if != PHY_INTERFACE_MODE_SGMII) ||
++          ((mac_dev->phy_if == PHY_INTERFACE_MODE_SGMII) &&
++                       (mac_dev->speed == SPEED_1000))) {
++              ptp_priv.node = of_parse_phandle(mac_node, "ptimer-handle", 0);
++              if (ptp_priv.node) {
++                      ptp_priv.of_dev = of_find_device_by_node(ptp_priv.node);
++                      if (unlikely(ptp_priv.of_dev == NULL)) {
++                              dev_err(dpa_dev,
++                      "Cannot find device represented by timer_node\n");
++                              of_node_put(ptp_priv.node);
++                              return ERR_PTR(-EINVAL);
++                      }
++                      ptp_priv.mac_dev = mac_dev;
++              }
++      }
++#endif
++      return mac_dev;
++}
++EXPORT_SYMBOL(dpa_mac_probe);
++
++int dpa_set_mac_address(struct net_device *net_dev, void *addr)
++{
++      const struct dpa_priv_s *priv;
++      int                      _errno;
++      struct mac_device       *mac_dev;
++
++      priv = netdev_priv(net_dev);
++
++      _errno = eth_mac_addr(net_dev, addr);
++      if (_errno < 0) {
++              if (netif_msg_drv(priv))
++                      netdev_err(net_dev,
++                                     "eth_mac_addr() = %d\n",
++                                     _errno);
++              return _errno;
++      }
++
++      mac_dev = priv->mac_dev;
++
++      _errno = mac_dev->change_addr(mac_dev->get_mac_handle(mac_dev),
++                      net_dev->dev_addr);
++      if (_errno < 0) {
++              if (netif_msg_drv(priv))
++                      netdev_err(net_dev,
++                                     "mac_dev->change_addr() = %d\n",
++                                     _errno);
++              return _errno;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(dpa_set_mac_address);
++
++void dpa_set_rx_mode(struct net_device *net_dev)
++{
++      int                      _errno;
++      const struct dpa_priv_s *priv;
++
++      priv = netdev_priv(net_dev);
++
++      if (!!(net_dev->flags & IFF_PROMISC) != priv->mac_dev->promisc) {
++              priv->mac_dev->promisc = !priv->mac_dev->promisc;
++              _errno = priv->mac_dev->set_promisc(
++                              priv->mac_dev->get_mac_handle(priv->mac_dev),
++                              priv->mac_dev->promisc);
++              if (unlikely(_errno < 0) && netif_msg_drv(priv))
++                      netdev_err(net_dev,
++                                         "mac_dev->set_promisc() = %d\n",
++                                         _errno);
++      }
++
++      _errno = priv->mac_dev->set_multi(net_dev, priv->mac_dev);
++      if (unlikely(_errno < 0) && netif_msg_drv(priv))
++              netdev_err(net_dev, "mac_dev->set_multi() = %d\n", _errno);
++}
++EXPORT_SYMBOL(dpa_set_rx_mode);
++
++void dpa_set_buffers_layout(struct mac_device *mac_dev,
++              struct dpa_buffer_layout_s *layout)
++{
++      struct fm_port_params params;
++
++      /* Rx */
++      layout[RX].priv_data_size = (uint16_t)DPA_RX_PRIV_DATA_SIZE;
++      layout[RX].parse_results = true;
++      layout[RX].hash_results = true;
++#ifdef CONFIG_FSL_DPAA_TS
++      layout[RX].time_stamp = true;
++#endif
++      fm_port_get_buff_layout_ext_params(mac_dev->port_dev[RX], &params);
++      layout[RX].manip_extra_space = params.manip_extra_space;
++      /* a value of zero for data alignment means "don't care", so align to
++       * a non-zero value to prevent FMD from using its own default
++       */
++      layout[RX].data_align = params.data_align ? : DPA_FD_DATA_ALIGNMENT;
++
++      /* Tx */
++      layout[TX].priv_data_size = DPA_TX_PRIV_DATA_SIZE;
++      layout[TX].parse_results = true;
++      layout[TX].hash_results = true;
++#ifdef CONFIG_FSL_DPAA_TS
++      layout[TX].time_stamp = true;
++#endif
++      fm_port_get_buff_layout_ext_params(mac_dev->port_dev[TX], &params);
++      layout[TX].manip_extra_space = params.manip_extra_space;
++      layout[TX].data_align = params.data_align ? : DPA_FD_DATA_ALIGNMENT;
++}
++EXPORT_SYMBOL(dpa_set_buffers_layout);
++
++int __attribute__((nonnull))
++dpa_bp_alloc(struct dpa_bp *dpa_bp)
++{
++      int err;
++      struct bman_pool_params  bp_params;
++      struct platform_device *pdev;
++
++      if (dpa_bp->size == 0 || dpa_bp->config_count == 0) {
++              pr_err("Buffer pool is not properly initialized! Missing size or initial number of buffers");
++              return -EINVAL;
++      }
++
++      memset(&bp_params, 0, sizeof(struct bman_pool_params));
++#ifdef CONFIG_FMAN_PFC
++      bp_params.flags = BMAN_POOL_FLAG_THRESH;
++      bp_params.thresholds[0] = bp_params.thresholds[2] =
++                      CONFIG_FSL_DPAA_ETH_REFILL_THRESHOLD;
++      bp_params.thresholds[1] = bp_params.thresholds[3] =
++                      CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT;
++#endif
++
++      /* If the pool is already specified, we only create one per bpid */
++      if (dpa_bpid2pool_use(dpa_bp->bpid))
++              return 0;
++
++      if (dpa_bp->bpid == 0)
++              bp_params.flags |= BMAN_POOL_FLAG_DYNAMIC_BPID;
++      else
++              bp_params.bpid = dpa_bp->bpid;
++
++      dpa_bp->pool = bman_new_pool(&bp_params);
++      if (unlikely(dpa_bp->pool == NULL)) {
++              pr_err("bman_new_pool() failed\n");
++              return -ENODEV;
++      }
++
++      dpa_bp->bpid = (uint8_t)bman_get_params(dpa_bp->pool)->bpid;
++
++      pdev = platform_device_register_simple("dpaa_eth_bpool",
++                      dpa_bp->bpid, NULL, 0);
++      if (IS_ERR(pdev)) {
++              pr_err("platform_device_register_simple() failed\n");
++              err = PTR_ERR(pdev);
++              goto pdev_register_failed;
++      }
++      {
++              struct dma_map_ops *ops = get_dma_ops(&pdev->dev);
++              ops->dma_supported = NULL;
++      }
++      err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40));
++      if (err) {
++              pr_err("dma_coerce_mask_and_coherent() failed\n");
++              goto pdev_mask_failed;
++      }
++#ifdef CONFIG_FMAN_ARM
++      /* force coherency */
++      pdev->dev.archdata.dma_coherent = true;
++      arch_setup_dma_ops(&pdev->dev, 0, 0, NULL, true);
++#endif
++
++      dpa_bp->dev = &pdev->dev;
++
++      if (dpa_bp->seed_cb) {
++              err = dpa_bp->seed_cb(dpa_bp);
++              if (err)
++                      goto pool_seed_failed;
++      }
++
++      dpa_bpid2pool_map(dpa_bp->bpid, dpa_bp);
++
++      return 0;
++
++pool_seed_failed:
++pdev_mask_failed:
++      platform_device_unregister(pdev);
++pdev_register_failed:
++      bman_free_pool(dpa_bp->pool);
++
++      return err;
++}
++EXPORT_SYMBOL(dpa_bp_alloc);
++
++void dpa_bp_drain(struct dpa_bp *bp)
++{
++      int ret, num = 8;
++
++      do {
++              struct bm_buffer bmb[8];
++              int i;
++
++              ret = bman_acquire(bp->pool, bmb, num, 0);
++              if (ret < 0) {
++                      if (num == 8) {
++                              /* we have less than 8 buffers left;
++                               * drain them one by one
++                               */
++                              num = 1;
++                              ret = 1;
++                              continue;
++                      } else {
++                              /* Pool is fully drained */
++                              break;
++                      }
++              }
++
++              for (i = 0; i < num; i++) {
++                      dma_addr_t addr = bm_buf_addr(&bmb[i]);
++
++                      dma_unmap_single(bp->dev, addr, bp->size,
++                                      DMA_BIDIRECTIONAL);
++
++                      bp->free_buf_cb(phys_to_virt(addr));
++              }
++      } while (ret > 0);
++}
++EXPORT_SYMBOL(dpa_bp_drain);
++
++static void __cold __attribute__((nonnull))
++_dpa_bp_free(struct dpa_bp *dpa_bp)
++{
++      struct dpa_bp *bp = dpa_bpid2pool(dpa_bp->bpid);
++
++      /* the mapping between bpid and dpa_bp is done very late in the
++       * allocation procedure; if something failed before the mapping, the bp
++       * was not configured, therefore we don't need the below instructions
++       */
++      if (!bp)
++              return;
++
++      if (!atomic_dec_and_test(&bp->refs))
++              return;
++
++      if (bp->free_buf_cb)
++              dpa_bp_drain(bp);
++
++      dpa_bp_array[bp->bpid] = NULL;
++      bman_free_pool(bp->pool);
++
++      if (bp->dev)
++              platform_device_unregister(to_platform_device(bp->dev));
++}
++
++void __cold __attribute__((nonnull))
++dpa_bp_free(struct dpa_priv_s *priv)
++{
++      int i;
++
++      if (priv->dpa_bp)
++              for (i = 0; i < priv->bp_count; i++)
++                      _dpa_bp_free(&priv->dpa_bp[i]);
++}
++EXPORT_SYMBOL(dpa_bp_free);
++
++struct dpa_bp *dpa_bpid2pool(int bpid)
++{
++      return dpa_bp_array[bpid];
++}
++EXPORT_SYMBOL(dpa_bpid2pool);
++
++void dpa_bpid2pool_map(int bpid, struct dpa_bp *dpa_bp)
++{
++      dpa_bp_array[bpid] = dpa_bp;
++      atomic_set(&dpa_bp->refs, 1);
++}
++
++bool dpa_bpid2pool_use(int bpid)
++{
++      if (dpa_bpid2pool(bpid)) {
++              atomic_inc(&dpa_bp_array[bpid]->refs);
++              return true;
++      }
++
++      return false;
++}
++
++#ifdef CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
++u16 dpa_select_queue(struct net_device *net_dev, struct sk_buff *skb,
++                   struct net_device *sb_dev,
++                   select_queue_fallback_t fallback)
++{
++      return dpa_get_queue_mapping(skb);
++}
++EXPORT_SYMBOL(dpa_select_queue);
++#endif
++
++struct dpa_fq *dpa_fq_alloc(struct device *dev,
++                          u32 fq_start,
++                          u32 fq_count,
++                          struct list_head *list,
++                          enum dpa_fq_type fq_type)
++{
++      int i;
++      struct dpa_fq *dpa_fq;
++
++      dpa_fq = devm_kzalloc(dev, sizeof(*dpa_fq) * fq_count, GFP_KERNEL);
++      if (dpa_fq == NULL)
++              return NULL;
++
++      for (i = 0; i < fq_count; i++) {
++              dpa_fq[i].fq_type = fq_type;
++              if (fq_type == FQ_TYPE_RX_PCD_HI_PRIO)
++                      dpa_fq[i].fqid = fq_start ?
++                                       DPAA_ETH_FQ_DELTA + fq_start + i : 0;
++              else
++                      dpa_fq[i].fqid = fq_start ? fq_start + i : 0;
++
++              list_add_tail(&dpa_fq[i].list, list);
++      }
++
++#ifdef CONFIG_FMAN_PFC
++      if (fq_type == FQ_TYPE_TX)
++              for (i = 0; i < fq_count; i++)
++                      dpa_fq[i].wq = i / dpa_num_cpus;
++      else
++#endif
++              for (i = 0; i < fq_count; i++)
++                      _dpa_assign_wq(dpa_fq + i);
++
++      return dpa_fq;
++}
++EXPORT_SYMBOL(dpa_fq_alloc);
++
++/* Probing of FQs for MACful ports */
++int dpa_fq_probe_mac(struct device *dev, struct list_head *list,
++                          struct fm_port_fqs *port_fqs,
++                          bool alloc_tx_conf_fqs,
++                          enum port_type ptype)
++{
++      struct fqid_cell *fqids = NULL;
++      const void *fqids_off = NULL;
++      struct dpa_fq *dpa_fq = NULL;
++      struct device_node *np = dev->of_node;
++      int num_ranges;
++      int i, lenp;
++
++      if (ptype == TX && alloc_tx_conf_fqs) {
++              if (!dpa_fq_alloc(dev, tx_confirm_fqids->start,
++                                tx_confirm_fqids->count, list,
++                                FQ_TYPE_TX_CONF_MQ))
++                      goto fq_alloc_failed;
++      }
++
++      fqids_off = of_get_property(np, fsl_qman_frame_queues[ptype], &lenp);
++      if (fqids_off == NULL) {
++              /* No dts definition, so use the defaults. */
++              fqids = default_fqids[ptype];
++              num_ranges = 3;
++      } else {
++              num_ranges = lenp / sizeof(*fqids);
++
++              fqids = devm_kzalloc(dev, sizeof(*fqids) * num_ranges,
++                              GFP_KERNEL);
++              if (fqids == NULL)
++                      goto fqids_alloc_failed;
++
++              /* convert to CPU endianess */
++              for (i = 0; i < num_ranges; i++) {
++                      fqids[i].start = be32_to_cpup(fqids_off +
++                                      i * sizeof(*fqids));
++                      fqids[i].count = be32_to_cpup(fqids_off +
++                                      i * sizeof(*fqids) + sizeof(__be32));
++              }
++      }
++
++      for (i = 0; i < num_ranges; i++) {
++              switch (i) {
++              case 0:
++                      /* The first queue is the error queue */
++                      if (fqids[i].count != 1)
++                              goto invalid_error_queue;
++
++                      dpa_fq = dpa_fq_alloc(dev, fqids[i].start,
++                                            fqids[i].count, list,
++                                            ptype == RX ?
++                                              FQ_TYPE_RX_ERROR :
++                                              FQ_TYPE_TX_ERROR);
++                      if (dpa_fq == NULL)
++                              goto fq_alloc_failed;
++
++                      if (ptype == RX)
++                              port_fqs->rx_errq = &dpa_fq[0];
++                      else
++                              port_fqs->tx_errq = &dpa_fq[0];
++                      break;
++              case 1:
++                      /* the second queue is the default queue */
++                      if (fqids[i].count != 1)
++                              goto invalid_default_queue;
++
++                      dpa_fq = dpa_fq_alloc(dev, fqids[i].start,
++                                            fqids[i].count, list,
++                                            ptype == RX ?
++                                              FQ_TYPE_RX_DEFAULT :
++                                              FQ_TYPE_TX_CONFIRM);
++                      if (dpa_fq == NULL)
++                              goto fq_alloc_failed;
++
++                      if (ptype == RX)
++                              port_fqs->rx_defq = &dpa_fq[0];
++                      else
++                              port_fqs->tx_defq = &dpa_fq[0];
++                      break;
++              default:
++                      /* all subsequent queues are either RX* PCD or Tx */
++                      if (ptype == RX) {
++                              if (!dpa_fq_alloc(dev, fqids[i].start,
++                                                fqids[i].count, list,
++                                                FQ_TYPE_RX_PCD) ||
++                                  !dpa_fq_alloc(dev, fqids[i].start,
++                                                fqids[i].count, list,
++                                                FQ_TYPE_RX_PCD_HI_PRIO))
++                                      goto fq_alloc_failed;
++                      } else {
++                              if (!dpa_fq_alloc(dev, fqids[i].start,
++                                                fqids[i].count, list,
++                                                FQ_TYPE_TX))
++                                      goto fq_alloc_failed;
++                      }
++                      break;
++              }
++      }
++
++      return 0;
++
++fq_alloc_failed:
++fqids_alloc_failed:
++      dev_err(dev, "Cannot allocate memory for frame queues\n");
++      return -ENOMEM;
++
++invalid_default_queue:
++invalid_error_queue:
++      dev_err(dev, "Too many default or error queues\n");
++      return -EINVAL;
++}
++EXPORT_SYMBOL(dpa_fq_probe_mac);
++
++static u32 rx_pool_channel;
++static DEFINE_SPINLOCK(rx_pool_channel_init);
++
++int dpa_get_channel(void)
++{
++      spin_lock(&rx_pool_channel_init);
++      if (!rx_pool_channel) {
++              u32 pool;
++              int ret = qman_alloc_pool(&pool);
++              if (!ret)
++                      rx_pool_channel = pool;
++      }
++      spin_unlock(&rx_pool_channel_init);
++      if (!rx_pool_channel)
++              return -ENOMEM;
++      return rx_pool_channel;
++}
++EXPORT_SYMBOL(dpa_get_channel);
++
++void dpa_release_channel(void)
++{
++      qman_release_pool(rx_pool_channel);
++}
++EXPORT_SYMBOL(dpa_release_channel);
++
++void dpaa_eth_add_channel(u16 channel)
++{
++      const cpumask_t *cpus = qman_affine_cpus();
++      u32 pool = QM_SDQCR_CHANNELS_POOL_CONV(channel);
++      int cpu;
++      struct qman_portal *portal;
++
++      for_each_cpu(cpu, cpus) {
++              portal = (struct qman_portal *)qman_get_affine_portal(cpu);
++              qman_p_static_dequeue_add(portal, pool);
++      }
++}
++EXPORT_SYMBOL(dpaa_eth_add_channel);
++
++/**
++ * Congestion group state change notification callback.
++ * Stops the device's egress queues while they are congested and
++ * wakes them upon exiting congested state.
++ * Also updates some CGR-related stats.
++ */
++static void dpaa_eth_cgscn(struct qman_portal *qm, struct qman_cgr *cgr,
++
++      int congested)
++{
++      struct dpa_priv_s *priv = (struct dpa_priv_s *)container_of(cgr,
++              struct dpa_priv_s, cgr_data.cgr);
++
++      if (congested) {
++              priv->cgr_data.congestion_start_jiffies = jiffies;
++              netif_tx_stop_all_queues(priv->net_dev);
++              priv->cgr_data.cgr_congested_count++;
++      } else {
++              priv->cgr_data.congested_jiffies +=
++                      (jiffies - priv->cgr_data.congestion_start_jiffies);
++              netif_tx_wake_all_queues(priv->net_dev);
++      }
++}
++
++int dpaa_eth_cgr_init(struct dpa_priv_s *priv)
++{
++      struct qm_mcc_initcgr initcgr;
++      u32 cs_th;
++      int err;
++
++      err = qman_alloc_cgrid(&priv->cgr_data.cgr.cgrid);
++      if (err < 0) {
++              pr_err("Error %d allocating CGR ID\n", err);
++              goto out_error;
++      }
++      priv->cgr_data.cgr.cb = dpaa_eth_cgscn;
++
++      /* Enable Congestion State Change Notifications and CS taildrop */
++      initcgr.we_mask = QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES;
++      initcgr.cgr.cscn_en = QM_CGR_EN;
++
++      /* Set different thresholds based on the MAC speed.
++       * TODO: this may turn suboptimal if the MAC is reconfigured at a speed
++       * lower than its max, e.g. if a dTSEC later negotiates a 100Mbps link.
++       * In such cases, we ought to reconfigure the threshold, too.
++       */
++      if (priv->mac_dev->if_support & SUPPORTED_10000baseT_Full)
++              cs_th = CONFIG_FSL_DPAA_CS_THRESHOLD_10G;
++      else
++              cs_th = CONFIG_FSL_DPAA_CS_THRESHOLD_1G;
++      qm_cgr_cs_thres_set64(&initcgr.cgr.cs_thres, cs_th, 1);
++
++      initcgr.we_mask |= QM_CGR_WE_CSTD_EN;
++      initcgr.cgr.cstd_en = QM_CGR_EN;
++
++      err = qman_create_cgr(&priv->cgr_data.cgr, QMAN_CGR_FLAG_USE_INIT,
++              &initcgr);
++      if (err < 0) {
++              pr_err("Error %d creating CGR with ID %d\n", err,
++                      priv->cgr_data.cgr.cgrid);
++              qman_release_cgrid(priv->cgr_data.cgr.cgrid);
++              goto out_error;
++      }
++      pr_debug("Created CGR %d for netdev with hwaddr %pM on QMan channel %d\n",
++               priv->cgr_data.cgr.cgrid, priv->mac_dev->addr,
++               priv->cgr_data.cgr.chan);
++
++out_error:
++      return err;
++}
++EXPORT_SYMBOL(dpaa_eth_cgr_init);
++
++static inline void dpa_setup_ingress(const struct dpa_priv_s *priv,
++                                   struct dpa_fq *fq,
++                                   const struct qman_fq *template)
++{
++      fq->fq_base = *template;
++      fq->net_dev = priv->net_dev;
++
++      fq->flags = QMAN_FQ_FLAG_NO_ENQUEUE;
++      fq->channel = priv->channel;
++}
++
++static inline void dpa_setup_egress(const struct dpa_priv_s *priv,
++                                  struct dpa_fq *fq,
++                                  struct fm_port *port,
++                                  const struct qman_fq *template)
++{
++      fq->fq_base = *template;
++      fq->net_dev = priv->net_dev;
++
++      if (port) {
++              fq->flags = QMAN_FQ_FLAG_TO_DCPORTAL;
++              fq->channel = (uint16_t)fm_get_tx_port_channel(port);
++      } else {
++              fq->flags = QMAN_FQ_FLAG_NO_MODIFY;
++      }
++}
++
++void dpa_fq_setup(struct dpa_priv_s *priv, const struct dpa_fq_cbs_t *fq_cbs,
++              struct fm_port *tx_port)
++{
++      struct dpa_fq *fq;
++      uint16_t portals[NR_CPUS];
++      int cpu, portal_cnt = 0, num_portals = 0;
++      uint32_t pcd_fqid, pcd_fqid_hi_prio;
++      const cpumask_t *affine_cpus = qman_affine_cpus();
++      int egress_cnt = 0, conf_cnt = 0;
++
++      /* Prepare for PCD FQs init */
++      for_each_cpu(cpu, affine_cpus)
++              portals[num_portals++] = qman_affine_channel(cpu);
++      if (num_portals == 0)
++              dev_err(priv->net_dev->dev.parent,
++                      "No Qman software (affine) channels found");
++
++      pcd_fqid = (priv->mac_dev) ?
++              DPAA_ETH_PCD_FQ_BASE(priv->mac_dev->res->start) : 0;
++      pcd_fqid_hi_prio = (priv->mac_dev) ?
++              DPAA_ETH_PCD_FQ_HI_PRIO_BASE(priv->mac_dev->res->start) : 0;
++
++      /* Initialize each FQ in the list */
++      list_for_each_entry(fq, &priv->dpa_fq_list, list) {
++              switch (fq->fq_type) {
++              case FQ_TYPE_RX_DEFAULT:
++                      BUG_ON(!priv->mac_dev);
++                      dpa_setup_ingress(priv, fq, &fq_cbs->rx_defq);
++                      break;
++              case FQ_TYPE_RX_ERROR:
++                      BUG_ON(!priv->mac_dev);
++                      dpa_setup_ingress(priv, fq, &fq_cbs->rx_errq);
++                      break;
++              case FQ_TYPE_RX_PCD:
++                      /* For MACless we can't have dynamic Rx queues */
++                      BUG_ON(!priv->mac_dev && !fq->fqid);
++                      dpa_setup_ingress(priv, fq, &fq_cbs->rx_defq);
++                      if (!fq->fqid)
++                              fq->fqid = pcd_fqid++;
++                      fq->channel = portals[portal_cnt];
++                      portal_cnt = (portal_cnt + 1) % num_portals;
++                      break;
++              case FQ_TYPE_RX_PCD_HI_PRIO:
++                      /* For MACless we can't have dynamic Hi Pri Rx queues */
++                      BUG_ON(!priv->mac_dev && !fq->fqid);
++                      dpa_setup_ingress(priv, fq, &fq_cbs->rx_defq);
++                      if (!fq->fqid)
++                              fq->fqid = pcd_fqid_hi_prio++;
++                      fq->channel = portals[portal_cnt];
++                      portal_cnt = (portal_cnt + 1) % num_portals;
++                      break;
++              case FQ_TYPE_TX:
++                      dpa_setup_egress(priv, fq, tx_port,
++                                       &fq_cbs->egress_ern);
++                      /* If we have more Tx queues than the number of cores,
++                       * just ignore the extra ones.
++                       */
++                      if (egress_cnt < DPAA_ETH_TX_QUEUES)
++                              priv->egress_fqs[egress_cnt++] = &fq->fq_base;
++                      break;
++              case FQ_TYPE_TX_CONFIRM:
++                      BUG_ON(!priv->mac_dev);
++                      dpa_setup_ingress(priv, fq, &fq_cbs->tx_defq);
++                      break;
++              case FQ_TYPE_TX_CONF_MQ:
++                      BUG_ON(!priv->mac_dev);
++                      dpa_setup_ingress(priv, fq, &fq_cbs->tx_defq);
++                      priv->conf_fqs[conf_cnt++] = &fq->fq_base;
++                      break;
++              case FQ_TYPE_TX_ERROR:
++                      BUG_ON(!priv->mac_dev);
++                      dpa_setup_ingress(priv, fq, &fq_cbs->tx_errq);
++                      break;
++              default:
++                      dev_warn(priv->net_dev->dev.parent,
++                               "Unknown FQ type detected!\n");
++                      break;
++              }
++      }
++
++      /* The number of Tx queues may be smaller than the number of cores, if
++       * the Tx queue range is specified in the device tree instead of being
++       * dynamically allocated.
++       * Make sure all CPUs receive a corresponding Tx queue.
++       */
++      while (egress_cnt < DPAA_ETH_TX_QUEUES) {
++              list_for_each_entry(fq, &priv->dpa_fq_list, list) {
++                      if (fq->fq_type != FQ_TYPE_TX)
++                              continue;
++                      priv->egress_fqs[egress_cnt++] = &fq->fq_base;
++                      if (egress_cnt == DPAA_ETH_TX_QUEUES)
++                              break;
++              }
++      }
++}
++EXPORT_SYMBOL(dpa_fq_setup);
++
++int dpa_fq_init(struct dpa_fq *dpa_fq, bool td_enable)
++{
++      int                      _errno;
++      const struct dpa_priv_s *priv;
++      struct device           *dev;
++      struct qman_fq          *fq;
++      struct qm_mcc_initfq     initfq;
++      struct qman_fq          *confq;
++      int                     queue_id;
++
++      priv = netdev_priv(dpa_fq->net_dev);
++      dev = dpa_fq->net_dev->dev.parent;
++
++      if (dpa_fq->fqid == 0)
++              dpa_fq->flags |= QMAN_FQ_FLAG_DYNAMIC_FQID;
++
++      dpa_fq->init = !(dpa_fq->flags & QMAN_FQ_FLAG_NO_MODIFY);
++
++      _errno = qman_create_fq(dpa_fq->fqid, dpa_fq->flags, &dpa_fq->fq_base);
++      if (_errno) {
++              dev_err(dev, "qman_create_fq() failed\n");
++              return _errno;
++      }
++      fq = &dpa_fq->fq_base;
++
++      if (dpa_fq->init) {
++              memset(&initfq, 0, sizeof(initfq));
++
++              initfq.we_mask = QM_INITFQ_WE_FQCTRL;
++              /* FIXME: why would we want to keep an empty FQ in cache? */
++              initfq.fqd.fq_ctrl = QM_FQCTRL_PREFERINCACHE;
++
++              /* Try to reduce the number of portal interrupts for
++               * Tx Confirmation FQs.
++               */
++              if (dpa_fq->fq_type == FQ_TYPE_TX_CONFIRM)
++                      initfq.fqd.fq_ctrl |= QM_FQCTRL_HOLDACTIVE;
++
++              /* FQ placement */
++              initfq.we_mask |= QM_INITFQ_WE_DESTWQ;
++
++              initfq.fqd.dest.channel = dpa_fq->channel;
++              initfq.fqd.dest.wq = dpa_fq->wq;
++
++              /* Put all egress queues in a congestion group of their own.
++               * Sensu stricto, the Tx confirmation queues are Rx FQs,
++               * rather than Tx - but they nonetheless account for the
++               * memory footprint on behalf of egress traffic. We therefore
++               * place them in the netdev's CGR, along with the Tx FQs.
++               */
++              if (dpa_fq->fq_type == FQ_TYPE_TX ||
++                              dpa_fq->fq_type == FQ_TYPE_TX_CONFIRM ||
++                              dpa_fq->fq_type == FQ_TYPE_TX_CONF_MQ) {
++                      initfq.we_mask |= QM_INITFQ_WE_CGID;
++                      initfq.fqd.fq_ctrl |= QM_FQCTRL_CGE;
++                      initfq.fqd.cgid = (uint8_t)priv->cgr_data.cgr.cgrid;
++                      /* Set a fixed overhead accounting, in an attempt to
++                       * reduce the impact of fixed-size skb shells and the
++                       * driver's needed headroom on system memory. This is
++                       * especially the case when the egress traffic is
++                       * composed of small datagrams.
++                       * Unfortunately, QMan's OAL value is capped to an
++                       * insufficient value, but even that is better than
++                       * no overhead accounting at all.
++                       */
++                      initfq.we_mask |= QM_INITFQ_WE_OAC;
++                      initfq.fqd.oac_init.oac = QM_OAC_CG;
++                      initfq.fqd.oac_init.oal =
++                              (signed char)(min(sizeof(struct sk_buff) +
++                              priv->tx_headroom, (size_t)FSL_QMAN_MAX_OAL));
++              }
++
++              if (td_enable) {
++                      initfq.we_mask |= QM_INITFQ_WE_TDTHRESH;
++                      qm_fqd_taildrop_set(&initfq.fqd.td,
++                                      DPA_FQ_TD, 1);
++                      initfq.fqd.fq_ctrl = QM_FQCTRL_TDE;
++              }
++
++              /* Configure the Tx confirmation queue, now that we know
++               * which Tx queue it pairs with.
++               */
++              if (dpa_fq->fq_type == FQ_TYPE_TX) {
++                      queue_id = _dpa_tx_fq_to_id(priv, &dpa_fq->fq_base);
++                      if (queue_id >= 0) {
++                              confq = priv->conf_fqs[queue_id];
++                              if (confq) {
++                                      initfq.we_mask |= QM_INITFQ_WE_CONTEXTA;
++                      /* ContextA: OVOM=1 (use contextA2 bits instead of ICAD)
++                       *           A2V=1 (contextA A2 field is valid)
++                       *           A0V=1 (contextA A0 field is valid)
++                       *           B0V=1 (contextB field is valid)
++                       * ContextA A2: EBD=1 (deallocate buffers inside FMan)
++                       * ContextB B0(ASPID): 0 (absolute Virtual Storage ID)
++                       */
++                                      initfq.fqd.context_a.hi = 0x1e000000;
++                                      initfq.fqd.context_a.lo = 0x80000000;
++                              }
++                      }
++              }
++
++              /* Put all *private* ingress queues in our "ingress CGR". */
++              if (priv->use_ingress_cgr &&
++                              (dpa_fq->fq_type == FQ_TYPE_RX_DEFAULT ||
++                               dpa_fq->fq_type == FQ_TYPE_RX_ERROR ||
++                               dpa_fq->fq_type == FQ_TYPE_RX_PCD ||
++                               dpa_fq->fq_type == FQ_TYPE_RX_PCD_HI_PRIO)) {
++                      initfq.we_mask |= QM_INITFQ_WE_CGID;
++                      initfq.fqd.fq_ctrl |= QM_FQCTRL_CGE;
++                      initfq.fqd.cgid = (uint8_t)priv->ingress_cgr.cgrid;
++                      /* Set a fixed overhead accounting, just like for the
++                       * egress CGR.
++                       */
++                      initfq.we_mask |= QM_INITFQ_WE_OAC;
++                      initfq.fqd.oac_init.oac = QM_OAC_CG;
++                      initfq.fqd.oac_init.oal =
++                              (signed char)(min(sizeof(struct sk_buff) +
++                              priv->tx_headroom, (size_t)FSL_QMAN_MAX_OAL));
++              }
++
++              /* Initialization common to all ingress queues */
++              if (dpa_fq->flags & QMAN_FQ_FLAG_NO_ENQUEUE) {
++                      initfq.we_mask |= QM_INITFQ_WE_CONTEXTA;
++                      initfq.fqd.fq_ctrl |=
++                              QM_FQCTRL_CTXASTASHING | QM_FQCTRL_AVOIDBLOCK;
++                      initfq.fqd.context_a.stashing.exclusive =
++                              QM_STASHING_EXCL_DATA | QM_STASHING_EXCL_CTX |
++                              QM_STASHING_EXCL_ANNOTATION;
++                      initfq.fqd.context_a.stashing.data_cl = 2;
++                      initfq.fqd.context_a.stashing.annotation_cl = 1;
++                      initfq.fqd.context_a.stashing.context_cl =
++                              DIV_ROUND_UP(sizeof(struct qman_fq), 64);
++              }
++
++              _errno = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &initfq);
++              if (_errno < 0) {
++                      if (DPA_RX_PCD_HI_PRIO_FQ_INIT_FAIL(dpa_fq, _errno)) {
++                              dpa_fq->init = 0;
++                      } else {
++                              dev_err(dev, "qman_init_fq(%u) = %d\n",
++                                      qman_fq_fqid(fq), _errno);
++                              qman_destroy_fq(fq, 0);
++                      }
++                      return _errno;
++              }
++      }
++
++      dpa_fq->fqid = qman_fq_fqid(fq);
++
++      return 0;
++}
++EXPORT_SYMBOL(dpa_fq_init);
++
++int __cold __attribute__((nonnull))
++_dpa_fq_free(struct device *dev, struct qman_fq *fq)
++{
++      int                      _errno, __errno;
++      struct dpa_fq           *dpa_fq;
++      const struct dpa_priv_s *priv;
++
++      _errno = 0;
++
++      dpa_fq = container_of(fq, struct dpa_fq, fq_base);
++      priv = netdev_priv(dpa_fq->net_dev);
++
++      if (dpa_fq->init) {
++              _errno = qman_retire_fq(fq, NULL);
++              if (unlikely(_errno < 0) && netif_msg_drv(priv))
++                      dev_err(dev, "qman_retire_fq(%u) = %d\n",
++                                      qman_fq_fqid(fq), _errno);
++
++              __errno = qman_oos_fq(fq);
++              if (unlikely(__errno < 0) && netif_msg_drv(priv)) {
++                      dev_err(dev, "qman_oos_fq(%u) = %d\n",
++                                      qman_fq_fqid(fq), __errno);
++                      if (_errno >= 0)
++                              _errno = __errno;
++              }
++      }
++
++      qman_destroy_fq(fq, 0);
++      list_del(&dpa_fq->list);
++
++      return _errno;
++}
++EXPORT_SYMBOL(_dpa_fq_free);
++
++int __cold __attribute__((nonnull))
++dpa_fq_free(struct device *dev, struct list_head *list)
++{
++      int              _errno, __errno;
++      struct dpa_fq   *dpa_fq, *tmp;
++
++      _errno = 0;
++      list_for_each_entry_safe(dpa_fq, tmp, list, list) {
++              __errno = _dpa_fq_free(dev, (struct qman_fq *)dpa_fq);
++              if (unlikely(__errno < 0) && _errno >= 0)
++                      _errno = __errno;
++      }
++
++      return _errno;
++}
++EXPORT_SYMBOL(dpa_fq_free);
++
++int dpa_fqs_init(struct device *dev, struct list_head *list, bool td_enable)
++{
++      int  _errno, __errno;
++      struct dpa_fq   *dpa_fq, *tmp;
++      static bool print_msg __read_mostly;
++
++      _errno = 0;
++      print_msg = true;
++      list_for_each_entry_safe(dpa_fq, tmp, list, list) {
++              __errno = dpa_fq_init(dpa_fq, td_enable);
++              if (unlikely(__errno < 0) && _errno >= 0) {
++                      if (DPA_RX_PCD_HI_PRIO_FQ_INIT_FAIL(dpa_fq, __errno)) {
++                              if (print_msg) {
++                                      dev_warn(dev,
++                                               "Skip RX PCD High Priority FQs initialization\n");
++                                      print_msg = false;
++                              }
++                              if (_dpa_fq_free(dev, (struct qman_fq *)dpa_fq))
++                                      dev_warn(dev,
++                                               "Error freeing frame queues\n");
++                      } else {
++                              _errno = __errno;
++                              break;
++                      }
++              }
++      }
++
++      return _errno;
++}
++EXPORT_SYMBOL(dpa_fqs_init);
++static void
++dpaa_eth_init_tx_port(struct fm_port *port, struct dpa_fq *errq,
++              struct dpa_fq *defq, struct dpa_buffer_layout_s *buf_layout)
++{
++      struct fm_port_params tx_port_param;
++      bool frag_enabled = false;
++
++      memset(&tx_port_param, 0, sizeof(tx_port_param));
++      dpaa_eth_init_port(tx, port, tx_port_param, errq->fqid, defq->fqid,
++                         buf_layout, frag_enabled);
++}
++
++static void
++dpaa_eth_init_rx_port(struct fm_port *port, struct dpa_bp *bp, size_t count,
++              struct dpa_fq *errq, struct dpa_fq *defq,
++              struct dpa_buffer_layout_s *buf_layout)
++{
++      struct fm_port_params rx_port_param;
++      int i;
++      bool frag_enabled = false;
++
++      memset(&rx_port_param, 0, sizeof(rx_port_param));
++      count = min(ARRAY_SIZE(rx_port_param.pool_param), count);
++      rx_port_param.num_pools = (uint8_t)count;
++      for (i = 0; i < count; i++) {
++              if (i >= rx_port_param.num_pools)
++                      break;
++              rx_port_param.pool_param[i].id = bp[i].bpid;
++              rx_port_param.pool_param[i].size = (uint16_t)bp[i].size;
++      }
++
++      dpaa_eth_init_port(rx, port, rx_port_param, errq->fqid, defq->fqid,
++                         buf_layout, frag_enabled);
++}
++
++#if defined(CONFIG_FSL_SDK_FMAN_TEST)
++/* Defined as weak, to be implemented by fman pcd tester. */
++int dpa_alloc_pcd_fqids(struct device *, uint32_t, uint8_t, uint32_t *)
++__attribute__((weak));
++
++int dpa_free_pcd_fqids(struct device *, uint32_t) __attribute__((weak));
++#else
++int dpa_alloc_pcd_fqids(struct device *, uint32_t, uint8_t, uint32_t *);
++
++int dpa_free_pcd_fqids(struct device *, uint32_t);
++
++#endif /* CONFIG_FSL_SDK_FMAN_TEST */
++
++
++int dpa_alloc_pcd_fqids(struct device *dev, uint32_t num,
++                              uint8_t alignment, uint32_t *base_fqid)
++{
++      dev_crit(dev, "callback not implemented!\n");
++
++      return 0;
++}
++
++int dpa_free_pcd_fqids(struct device *dev, uint32_t base_fqid)
++{
++
++      dev_crit(dev, "callback not implemented!\n");
++
++      return 0;
++}
++
++void dpaa_eth_init_ports(struct mac_device *mac_dev,
++              struct dpa_bp *bp, size_t count,
++              struct fm_port_fqs *port_fqs,
++              struct dpa_buffer_layout_s *buf_layout,
++              struct device *dev)
++{
++      struct fm_port_pcd_param rx_port_pcd_param;
++      struct fm_port *rxport = mac_dev->port_dev[RX];
++      struct fm_port *txport = mac_dev->port_dev[TX];
++
++      dpaa_eth_init_tx_port(txport, port_fqs->tx_errq,
++                            port_fqs->tx_defq, &buf_layout[TX]);
++      dpaa_eth_init_rx_port(rxport, bp, count, port_fqs->rx_errq,
++                            port_fqs->rx_defq, &buf_layout[RX]);
++
++      rx_port_pcd_param.cba = dpa_alloc_pcd_fqids;
++      rx_port_pcd_param.cbf = dpa_free_pcd_fqids;
++      rx_port_pcd_param.dev = dev;
++      fm_port_pcd_bind(rxport, &rx_port_pcd_param);
++}
++EXPORT_SYMBOL(dpaa_eth_init_ports);
++
++void dpa_release_sgt(struct qm_sg_entry *sgt)
++{
++      struct dpa_bp *dpa_bp;
++      struct bm_buffer bmb[DPA_BUFF_RELEASE_MAX];
++      uint8_t i = 0, j;
++
++      memset(bmb, 0, DPA_BUFF_RELEASE_MAX * sizeof(struct bm_buffer));
++
++      do {
++              dpa_bp = dpa_bpid2pool(qm_sg_entry_get_bpid(&sgt[i]));
++              DPA_BUG_ON(!dpa_bp);
++
++              j = 0;
++              do {
++                      DPA_BUG_ON(qm_sg_entry_get_ext(&sgt[i]));
++                      bm_buffer_set64(&bmb[j], qm_sg_addr(&sgt[i]));
++
++                      j++; i++;
++              } while (j < ARRAY_SIZE(bmb) &&
++                      !qm_sg_entry_get_final(&sgt[i-1]) &&
++                      qm_sg_entry_get_bpid(&sgt[i-1]) ==
++                      qm_sg_entry_get_bpid(&sgt[i]));
++
++              while (bman_release(dpa_bp->pool, bmb, j, 0))
++                      cpu_relax();
++      } while (!qm_sg_entry_get_final(&sgt[i-1]));
++}
++EXPORT_SYMBOL(dpa_release_sgt);
++
++void __attribute__((nonnull))
++dpa_fd_release(const struct net_device *net_dev, const struct qm_fd *fd)
++{
++      struct qm_sg_entry      *sgt;
++      struct dpa_bp           *dpa_bp;
++      struct bm_buffer        bmb;
++      dma_addr_t              addr;
++      void                    *vaddr;
++
++      bmb.opaque = 0;
++      bm_buffer_set64(&bmb, qm_fd_addr(fd));
++
++      dpa_bp = dpa_bpid2pool(fd->bpid);
++      DPA_BUG_ON(!dpa_bp);
++
++      if (fd->format == qm_fd_sg) {
++              vaddr = phys_to_virt(qm_fd_addr(fd));
++              sgt = vaddr + dpa_fd_offset(fd);
++
++              dma_unmap_single(dpa_bp->dev, qm_fd_addr(fd), dpa_bp->size,
++                               DMA_BIDIRECTIONAL);
++
++              dpa_release_sgt(sgt);
++              addr = dma_map_single(dpa_bp->dev, vaddr, dpa_bp->size,
++                                    DMA_BIDIRECTIONAL);
++              if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) {
++                      dev_err(dpa_bp->dev, "DMA mapping failed");
++                      return;
++              }
++              bm_buffer_set64(&bmb, addr);
++      }
++
++      while (bman_release(dpa_bp->pool, &bmb, 1, 0))
++              cpu_relax();
++}
++EXPORT_SYMBOL(dpa_fd_release);
++
++void count_ern(struct dpa_percpu_priv_s *percpu_priv,
++                    const struct qm_mr_entry *msg)
++{
++      switch (msg->ern.rc & QM_MR_RC_MASK) {
++      case QM_MR_RC_CGR_TAILDROP:
++              percpu_priv->ern_cnt.cg_tdrop++;
++              break;
++      case QM_MR_RC_WRED:
++              percpu_priv->ern_cnt.wred++;
++              break;
++      case QM_MR_RC_ERROR:
++              percpu_priv->ern_cnt.err_cond++;
++              break;
++      case QM_MR_RC_ORPWINDOW_EARLY:
++              percpu_priv->ern_cnt.early_window++;
++              break;
++      case QM_MR_RC_ORPWINDOW_LATE:
++              percpu_priv->ern_cnt.late_window++;
++              break;
++      case QM_MR_RC_FQ_TAILDROP:
++              percpu_priv->ern_cnt.fq_tdrop++;
++              break;
++      case QM_MR_RC_ORPWINDOW_RETIRED:
++              percpu_priv->ern_cnt.fq_retired++;
++              break;
++      case QM_MR_RC_ORP_ZERO:
++              percpu_priv->ern_cnt.orp_zero++;
++              break;
++      }
++}
++EXPORT_SYMBOL(count_ern);
++
++/**
++ * Turn on HW checksum computation for this outgoing frame.
++ * If the current protocol is not something we support in this regard
++ * (or if the stack has already computed the SW checksum), we do nothing.
++ *
++ * Returns 0 if all goes well (or HW csum doesn't apply), and a negative value
++ * otherwise.
++ *
++ * Note that this function may modify the fd->cmd field and the skb data buffer
++ * (the Parse Results area).
++ */
++int dpa_enable_tx_csum(struct dpa_priv_s *priv,
++      struct sk_buff *skb, struct qm_fd *fd, char *parse_results)
++{
++      fm_prs_result_t *parse_result;
++      struct iphdr *iph;
++      struct ipv6hdr *ipv6h = NULL;
++      u8 l4_proto;
++      u16 ethertype = ntohs(skb->protocol);
++      int retval = 0;
++
++      if (skb->ip_summed != CHECKSUM_PARTIAL)
++              return 0;
++
++      /* Note: L3 csum seems to be already computed in sw, but we can't choose
++       * L4 alone from the FM configuration anyway.
++       */
++
++      /* Fill in some fields of the Parse Results array, so the FMan
++       * can find them as if they came from the FMan Parser.
++       */
++      parse_result = (fm_prs_result_t *)parse_results;
++
++      /* If we're dealing with VLAN, get the real Ethernet type */
++      if (ethertype == ETH_P_8021Q) {
++              /* We can't always assume the MAC header is set correctly
++               * by the stack, so reset to beginning of skb->data
++               */
++              skb_reset_mac_header(skb);
++              ethertype = ntohs(vlan_eth_hdr(skb)->h_vlan_encapsulated_proto);
++      }
++
++      /* Fill in the relevant L3 parse result fields
++       * and read the L4 protocol type
++       */
++      switch (ethertype) {
++      case ETH_P_IP:
++              parse_result->l3r = cpu_to_be16(FM_L3_PARSE_RESULT_IPV4);
++              iph = ip_hdr(skb);
++              DPA_BUG_ON(iph == NULL);
++              l4_proto = iph->protocol;
++              break;
++      case ETH_P_IPV6:
++              parse_result->l3r = cpu_to_be16(FM_L3_PARSE_RESULT_IPV6);
++              ipv6h = ipv6_hdr(skb);
++              DPA_BUG_ON(ipv6h == NULL);
++              l4_proto = ipv6h->nexthdr;
++              break;
++      default:
++              /* We shouldn't even be here */
++              if (netif_msg_tx_err(priv) && net_ratelimit())
++                      netdev_alert(priv->net_dev,
++                                   "Can't compute HW csum for L3 proto 0x%x\n",
++                                   ntohs(skb->protocol));
++              retval = -EIO;
++              goto return_error;
++      }
++
++      /* Fill in the relevant L4 parse result fields */
++      switch (l4_proto) {
++      case IPPROTO_UDP:
++              parse_result->l4r = FM_L4_PARSE_RESULT_UDP;
++              break;
++      case IPPROTO_TCP:
++              parse_result->l4r = FM_L4_PARSE_RESULT_TCP;
++              break;
++      default:
++              /* This can as well be a BUG() */
++              if (netif_msg_tx_err(priv) && net_ratelimit())
++                      netdev_alert(priv->net_dev,
++                                   "Can't compute HW csum for L4 proto 0x%x\n",
++                                   l4_proto);
++              retval = -EIO;
++              goto return_error;
++      }
++
++      /* At index 0 is IPOffset_1 as defined in the Parse Results */
++      parse_result->ip_off[0] = (uint8_t)skb_network_offset(skb);
++      parse_result->l4_off = (uint8_t)skb_transport_offset(skb);
++
++      /* Enable L3 (and L4, if TCP or UDP) HW checksum. */
++      fd->cmd |= FM_FD_CMD_RPD | FM_FD_CMD_DTC;
++
++      /* On P1023 and similar platforms fd->cmd interpretation could
++       * be disabled by setting CONTEXT_A bit ICMD; currently this bit
++       * is not set so we do not need to check; in the future, if/when
++       * using context_a we need to check this bit
++       */
++
++return_error:
++      return retval;
++}
++EXPORT_SYMBOL(dpa_enable_tx_csum);
++
++#ifdef CONFIG_FSL_DPAA_CEETM
++void dpa_enable_ceetm(struct net_device *dev)
++{
++      struct dpa_priv_s *priv = netdev_priv(dev);
++      priv->ceetm_en = true;
++}
++EXPORT_SYMBOL(dpa_enable_ceetm);
++
++void dpa_disable_ceetm(struct net_device *dev)
++{
++      struct dpa_priv_s *priv = netdev_priv(dev);
++      priv->ceetm_en = false;
++}
++EXPORT_SYMBOL(dpa_disable_ceetm);
++#endif
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
+@@ -0,0 +1,226 @@
++/* Copyright 2008-2013 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __DPAA_ETH_COMMON_H
++#define __DPAA_ETH_COMMON_H
++
++#include <linux/etherdevice.h> /* struct net_device */
++#include <linux/fsl_bman.h> /* struct bm_buffer */
++#include <linux/of_platform.h> /* struct platform_device */
++#include <linux/net_tstamp.h> /* struct hwtstamp_config */
++
++#include "dpaa_eth.h"
++#include "lnxwrp_fsl_fman.h"
++
++#define dpaa_eth_init_port(type, port, param, errq_id, defq_id, buf_layout,\
++                         frag_enabled) \
++{ \
++      param.errq = errq_id; \
++      param.defq = defq_id; \
++      param.priv_data_size = buf_layout->priv_data_size; \
++      param.parse_results = buf_layout->parse_results; \
++      param.hash_results = buf_layout->hash_results; \
++      param.frag_enable = frag_enabled; \
++      param.time_stamp = buf_layout->time_stamp; \
++      param.manip_extra_space = buf_layout->manip_extra_space; \
++      param.data_align = buf_layout->data_align; \
++      fm_set_##type##_port_params(port, &param); \
++}
++
++#define DPA_SGT_MAX_ENTRIES 16 /* maximum number of entries in SG Table */
++
++#define DPA_SGT_ENTRIES_THRESHOLD     DPA_SGT_MAX_ENTRIES
++
++#define DPA_BUFF_RELEASE_MAX 8 /* maximum number of buffers released at once */
++
++#define DPA_RX_PCD_HI_PRIO_FQ_INIT_FAIL(dpa_fq, _errno) \
++      (((dpa_fq)->fq_type == FQ_TYPE_RX_PCD_HI_PRIO) && \
++        (_errno == -EIO))
++/* return codes for the dpaa-eth hooks */
++enum dpaa_eth_hook_result {
++      /* fd/skb was retained by the hook.
++       *
++       * On the Rx path, this means the Ethernet driver will _not_
++       * deliver the skb to the stack. Instead, the hook implementation
++       * is expected to properly dispose of the skb.
++       *
++       * On the Tx path, the Ethernet driver's dpa_tx() function will
++       * immediately return NETDEV_TX_OK. The hook implementation is expected
++       * to free the skb. *DO*NOT* release it to BMan, or enqueue it to FMan,
++       * unless you know exactly what you're doing!
++       *
++       * On the confirmation/error paths, the Ethernet driver will _not_
++       * perform any fd cleanup, nor update the interface statistics.
++       */
++      DPAA_ETH_STOLEN,
++      /* fd/skb was returned to the Ethernet driver for regular processing.
++       * The hook is not allowed to, for instance, reallocate the skb (as if
++       * by linearizing, copying, cloning or reallocating the headroom).
++       */
++      DPAA_ETH_CONTINUE
++};
++
++typedef enum dpaa_eth_hook_result (*dpaa_eth_ingress_hook_t)(
++              struct sk_buff *skb, struct net_device *net_dev, u32 fqid);
++typedef enum dpaa_eth_hook_result (*dpaa_eth_egress_hook_t)(
++              struct sk_buff *skb, struct net_device *net_dev);
++typedef enum dpaa_eth_hook_result (*dpaa_eth_confirm_hook_t)(
++              struct net_device *net_dev, const struct qm_fd *fd, u32 fqid);
++
++/* used in napi related functions */
++extern u16 qman_portal_max;
++
++/* from dpa_ethtool.c */
++extern const struct ethtool_ops dpa_ethtool_ops;
++
++#ifdef CONFIG_FSL_DPAA_HOOKS
++/* Various hooks used for unit-testing and/or fastpath optimizations.
++ * Currently only one set of such hooks is supported.
++ */
++struct dpaa_eth_hooks_s {
++      /* Invoked on the Tx private path, immediately after receiving the skb
++       * from the stack.
++       */
++      dpaa_eth_egress_hook_t  tx;
++
++      /* Invoked on the Rx private path, right before passing the skb
++       * up the stack. At that point, the packet's protocol id has already
++       * been set. The skb's data pointer is now at the L3 header, and
++       * skb->mac_header points to the L2 header. skb->len has been adjusted
++       * to be the length of L3+payload (i.e., the length of the
++       * original frame minus the L2 header len).
++       * For more details on what the skb looks like, see eth_type_trans().
++       */
++      dpaa_eth_ingress_hook_t rx_default;
++
++      /* Driver hook for the Rx error private path. */
++      dpaa_eth_confirm_hook_t rx_error;
++      /* Driver hook for the Tx confirmation private path. */
++      dpaa_eth_confirm_hook_t tx_confirm;
++      /* Driver hook for the Tx error private path. */
++      dpaa_eth_confirm_hook_t tx_error;
++};
++
++void fsl_dpaa_eth_set_hooks(struct dpaa_eth_hooks_s *hooks);
++
++extern struct dpaa_eth_hooks_s dpaa_eth_hooks;
++#endif
++
++int dpa_netdev_init(struct net_device *net_dev,
++                  const uint8_t *mac_addr,
++                  uint16_t tx_timeout);
++int __cold dpa_start(struct net_device *net_dev);
++int __cold dpa_stop(struct net_device *net_dev);
++void __cold dpa_timeout(struct net_device *net_dev);
++void __cold
++dpa_get_stats64(struct net_device *net_dev,
++              struct rtnl_link_stats64 *stats);
++int dpa_change_mtu(struct net_device *net_dev, int new_mtu);
++int dpa_ndo_init(struct net_device *net_dev);
++int dpa_set_features(struct net_device *dev, netdev_features_t features);
++netdev_features_t dpa_fix_features(struct net_device *dev,
++              netdev_features_t features);
++#ifdef CONFIG_FSL_DPAA_TS
++u64 dpa_get_timestamp_ns(const struct dpa_priv_s *priv,
++                      enum port_type rx_tx, const void *data);
++/* Updates the skb shared hw timestamp from the hardware timestamp */
++int dpa_get_ts(const struct dpa_priv_s *priv, enum port_type rx_tx,
++      struct skb_shared_hwtstamps *shhwtstamps, const void *data);
++#endif /* CONFIG_FSL_DPAA_TS */
++int dpa_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
++int __cold dpa_remove(struct platform_device *of_dev);
++struct mac_device * __cold __must_check
++__attribute__((nonnull)) dpa_mac_probe(struct platform_device *_of_dev);
++int dpa_set_mac_address(struct net_device *net_dev, void *addr);
++void dpa_set_rx_mode(struct net_device *net_dev);
++void dpa_set_buffers_layout(struct mac_device *mac_dev,
++              struct dpa_buffer_layout_s *layout);
++int __attribute__((nonnull))
++dpa_bp_alloc(struct dpa_bp *dpa_bp);
++void __cold __attribute__((nonnull))
++dpa_bp_free(struct dpa_priv_s *priv);
++struct dpa_bp *dpa_bpid2pool(int bpid);
++void dpa_bpid2pool_map(int bpid, struct dpa_bp *dpa_bp);
++bool dpa_bpid2pool_use(int bpid);
++void dpa_bp_drain(struct dpa_bp *bp);
++#ifdef CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
++u16 dpa_select_queue(struct net_device *net_dev, struct sk_buff *skb,
++                   struct net_device *sb_dev,
++                   select_queue_fallback_t fallback);
++#endif
++struct dpa_fq *dpa_fq_alloc(struct device *dev,
++                          u32 fq_start,
++                          u32 fq_count,
++                          struct list_head *list,
++                          enum dpa_fq_type fq_type);
++int dpa_fq_probe_mac(struct device *dev, struct list_head *list,
++                   struct fm_port_fqs *port_fqs,
++                   bool tx_conf_fqs_per_core,
++                   enum port_type ptype);
++int dpa_get_channel(void);
++void dpa_release_channel(void);
++void dpaa_eth_add_channel(u16 channel);
++int dpaa_eth_cgr_init(struct dpa_priv_s *priv);
++void dpa_fq_setup(struct dpa_priv_s *priv, const struct dpa_fq_cbs_t *fq_cbs,
++              struct fm_port *tx_port);
++int dpa_fq_init(struct dpa_fq *dpa_fq, bool td_enable);
++int dpa_fqs_init(struct device *dev, struct list_head *list, bool td_enable);
++int __cold __attribute__((nonnull))
++dpa_fq_free(struct device *dev, struct list_head *list);
++void dpaa_eth_init_ports(struct mac_device *mac_dev,
++              struct dpa_bp *bp, size_t count,
++              struct fm_port_fqs *port_fqs,
++              struct dpa_buffer_layout_s *buf_layout,
++              struct device *dev);
++void dpa_release_sgt(struct qm_sg_entry *sgt);
++void __attribute__((nonnull))
++dpa_fd_release(const struct net_device *net_dev, const struct qm_fd *fd);
++void count_ern(struct dpa_percpu_priv_s *percpu_priv,
++                    const struct qm_mr_entry *msg);
++int dpa_enable_tx_csum(struct dpa_priv_s *priv,
++      struct sk_buff *skb, struct qm_fd *fd, char *parse_results);
++#ifdef CONFIG_FSL_DPAA_CEETM
++void dpa_enable_ceetm(struct net_device *dev);
++void dpa_disable_ceetm(struct net_device *dev);
++#endif
++struct proxy_device {
++              struct mac_device *mac_dev;
++};
++
++/* mac device control functions exposed by proxy interface*/
++int dpa_proxy_start(struct net_device *net_dev);
++int dpa_proxy_stop(struct proxy_device *proxy_dev, struct net_device *net_dev);
++int dpa_proxy_set_mac_address(struct proxy_device *proxy_dev,
++                        struct net_device *net_dev);
++int dpa_proxy_set_rx_mode(struct proxy_device *proxy_dev,
++                    struct net_device *net_dev);
++
++#endif /* __DPAA_ETH_COMMON_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c
+@@ -0,0 +1,381 @@
++/* Copyright 2008-2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
++      KBUILD_BASENAME".c", __LINE__, __func__
++#else
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": " fmt
++#endif
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include "dpaa_eth.h"
++#include "dpaa_eth_common.h"
++#include "dpaa_eth_base.h"
++#include "lnxwrp_fsl_fman.h" /* fm_get_rx_extra_headroom(), fm_get_max_frm() */
++#include "mac.h"
++
++#define DPA_DESCRIPTION "FSL DPAA Proxy initialization driver"
++
++MODULE_LICENSE("Dual BSD/GPL");
++
++MODULE_DESCRIPTION(DPA_DESCRIPTION);
++
++static int __cold dpa_eth_proxy_remove(struct platform_device *of_dev);
++#ifdef CONFIG_PM
++
++static int proxy_suspend(struct device *dev)
++{
++      struct proxy_device *proxy_dev = dev_get_drvdata(dev);
++      struct mac_device *mac_dev = proxy_dev->mac_dev;
++      int err = 0;
++
++      err = fm_port_suspend(mac_dev->port_dev[RX]);
++      if (err)
++              goto port_suspend_failed;
++
++      err = fm_port_suspend(mac_dev->port_dev[TX]);
++      if (err)
++              err = fm_port_resume(mac_dev->port_dev[RX]);
++
++port_suspend_failed:
++      return err;
++}
++
++static int proxy_resume(struct device *dev)
++{
++      struct proxy_device *proxy_dev = dev_get_drvdata(dev);
++      struct mac_device       *mac_dev = proxy_dev->mac_dev;
++      int                     err = 0;
++
++      err = fm_port_resume(mac_dev->port_dev[TX]);
++      if (err)
++              goto port_resume_failed;
++
++      err = fm_port_resume(mac_dev->port_dev[RX]);
++      if (err)
++              err = fm_port_suspend(mac_dev->port_dev[TX]);
++
++port_resume_failed:
++      return err;
++}
++
++static const struct dev_pm_ops proxy_pm_ops = {
++      .suspend = proxy_suspend,
++      .resume = proxy_resume,
++};
++
++#define PROXY_PM_OPS (&proxy_pm_ops)
++
++#else /* CONFIG_PM */
++
++#define PROXY_PM_OPS NULL
++
++#endif /* CONFIG_PM */
++
++static int dpaa_eth_proxy_probe(struct platform_device *_of_dev)
++{
++      int err = 0, i;
++      struct device *dev;
++      struct device_node *dpa_node;
++      struct dpa_bp *dpa_bp;
++      struct list_head proxy_fq_list;
++      size_t count;
++      struct fm_port_fqs port_fqs;
++      struct dpa_buffer_layout_s *buf_layout = NULL;
++      struct mac_device *mac_dev;
++      struct proxy_device *proxy_dev;
++
++      dev = &_of_dev->dev;
++
++      dpa_node = dev->of_node;
++
++      if (!of_device_is_available(dpa_node))
++              return -ENODEV;
++
++      /* Get the buffer pools assigned to this interface */
++      dpa_bp = dpa_bp_probe(_of_dev, &count);
++      if (IS_ERR(dpa_bp))
++              return PTR_ERR(dpa_bp);
++
++      mac_dev = dpa_mac_probe(_of_dev);
++      if (IS_ERR(mac_dev))
++              return PTR_ERR(mac_dev);
++
++      proxy_dev = devm_kzalloc(dev, sizeof(*proxy_dev), GFP_KERNEL);
++      if (!proxy_dev) {
++              dev_err(dev, "devm_kzalloc() failed\n");
++              return -ENOMEM;
++      }
++
++      proxy_dev->mac_dev = mac_dev;
++      dev_set_drvdata(dev, proxy_dev);
++
++      /* We have physical ports, so we need to establish
++       * the buffer layout.
++       */
++      buf_layout = devm_kzalloc(dev, 2 * sizeof(*buf_layout),
++                                GFP_KERNEL);
++      if (!buf_layout) {
++              dev_err(dev, "devm_kzalloc() failed\n");
++              return -ENOMEM;
++      }
++      dpa_set_buffers_layout(mac_dev, buf_layout);
++
++      INIT_LIST_HEAD(&proxy_fq_list);
++
++      memset(&port_fqs, 0, sizeof(port_fqs));
++
++      err = dpa_fq_probe_mac(dev, &proxy_fq_list, &port_fqs, true, RX);
++      if (!err)
++              err = dpa_fq_probe_mac(dev, &proxy_fq_list, &port_fqs, true,
++                                     TX);
++      if (err < 0) {
++              devm_kfree(dev, buf_layout);
++              return err;
++      }
++
++      /* Proxy initializer - Just configures the MAC on behalf of
++       * another partition.
++       */
++      dpaa_eth_init_ports(mac_dev, dpa_bp, count, &port_fqs,
++                      buf_layout, dev);
++
++      /* Proxy interfaces need to be started, and the allocated
++       * memory freed
++       */
++      devm_kfree(dev, buf_layout);
++      devm_kfree(dev, dpa_bp);
++
++      /* Free FQ structures */
++      devm_kfree(dev, port_fqs.rx_defq);
++      devm_kfree(dev, port_fqs.rx_errq);
++      devm_kfree(dev, port_fqs.tx_defq);
++      devm_kfree(dev, port_fqs.tx_errq);
++
++      for_each_port_device(i, mac_dev->port_dev) {
++              err = fm_port_enable(mac_dev->port_dev[i]);
++              if (err)
++                      goto port_enable_fail;
++      }
++
++      dev_info(dev, "probed MAC device with MAC address: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
++                   mac_dev->addr[0], mac_dev->addr[1], mac_dev->addr[2],
++                   mac_dev->addr[3], mac_dev->addr[4], mac_dev->addr[5]);
++
++      return 0; /* Proxy interface initialization ended */
++
++port_enable_fail:
++      for_each_port_device(i, mac_dev->port_dev)
++              fm_port_disable(mac_dev->port_dev[i]);
++      dpa_eth_proxy_remove(_of_dev);
++
++      return err;
++}
++
++int dpa_proxy_set_mac_address(struct proxy_device *proxy_dev,
++                        struct net_device *net_dev)
++{
++      struct mac_device       *mac_dev;
++      int                      _errno;
++
++      mac_dev = proxy_dev->mac_dev;
++
++      _errno = mac_dev->change_addr(mac_dev->get_mac_handle(mac_dev),
++                      net_dev->dev_addr);
++      if (_errno < 0)
++              return _errno;
++
++      return 0;
++}
++EXPORT_SYMBOL(dpa_proxy_set_mac_address);
++
++int dpa_proxy_set_rx_mode(struct proxy_device *proxy_dev,
++                     struct net_device *net_dev)
++{
++      struct mac_device *mac_dev = proxy_dev->mac_dev;
++      int _errno;
++
++      if (!!(net_dev->flags & IFF_PROMISC) != mac_dev->promisc) {
++              mac_dev->promisc = !mac_dev->promisc;
++              _errno = mac_dev->set_promisc(mac_dev->get_mac_handle(mac_dev),
++                              mac_dev->promisc);
++              if (unlikely(_errno < 0))
++                      netdev_err(net_dev, "mac_dev->set_promisc() = %d\n",
++                                      _errno);
++      }
++
++      _errno = mac_dev->set_multi(net_dev, mac_dev);
++      if (unlikely(_errno < 0))
++              return _errno;
++
++      return 0;
++}
++EXPORT_SYMBOL(dpa_proxy_set_rx_mode);
++
++int dpa_proxy_start(struct net_device *net_dev)
++{
++      struct mac_device       *mac_dev;
++      const struct dpa_priv_s *priv;
++      struct proxy_device     *proxy_dev;
++      int                      _errno;
++      int                     i;
++
++      priv = netdev_priv(net_dev);
++      proxy_dev = (struct proxy_device *)priv->peer;
++      mac_dev = proxy_dev->mac_dev;
++
++      _errno = mac_dev->init_phy(net_dev, mac_dev);
++      if (_errno < 0) {
++              if (netif_msg_drv(priv))
++                      netdev_err(net_dev, "init_phy() = %d\n",
++                                      _errno);
++              return _errno;
++      }
++
++      for_each_port_device(i, mac_dev->port_dev) {
++              _errno = fm_port_enable(mac_dev->port_dev[i]);
++              if (_errno)
++                      goto port_enable_fail;
++      }
++
++      _errno = mac_dev->start(mac_dev);
++      if (_errno < 0) {
++              if (netif_msg_drv(priv))
++                      netdev_err(net_dev, "mac_dev->start() = %d\n",
++                                      _errno);
++              goto port_enable_fail;
++      }
++
++      return _errno;
++
++port_enable_fail:
++      for_each_port_device(i, mac_dev->port_dev)
++              fm_port_disable(mac_dev->port_dev[i]);
++
++      return _errno;
++}
++EXPORT_SYMBOL(dpa_proxy_start);
++
++int dpa_proxy_stop(struct proxy_device *proxy_dev, struct net_device *net_dev)
++{
++      struct mac_device *mac_dev = proxy_dev->mac_dev;
++      const struct dpa_priv_s *priv = netdev_priv(net_dev);
++      int _errno, i, err;
++
++      _errno = mac_dev->stop(mac_dev);
++      if (_errno < 0) {
++              if (netif_msg_drv(priv))
++                      netdev_err(net_dev, "mac_dev->stop() = %d\n",
++                                      _errno);
++              return _errno;
++      }
++
++      for_each_port_device(i, mac_dev->port_dev) {
++              err = fm_port_disable(mac_dev->port_dev[i]);
++              _errno = err ? err : _errno;
++      }
++
++      if (mac_dev->phy_dev)
++              phy_disconnect(mac_dev->phy_dev);
++      mac_dev->phy_dev = NULL;
++
++      return _errno;
++}
++EXPORT_SYMBOL(dpa_proxy_stop);
++
++static int __cold dpa_eth_proxy_remove(struct platform_device *of_dev)
++{
++      struct device *dev = &of_dev->dev;
++      struct proxy_device *proxy_dev = dev_get_drvdata(dev);
++
++      kfree(proxy_dev);
++
++      dev_set_drvdata(dev, NULL);
++
++      return 0;
++}
++
++static const struct of_device_id dpa_proxy_match[] = {
++      {
++              .compatible     = "fsl,dpa-ethernet-init"
++      },
++      {}
++};
++MODULE_DEVICE_TABLE(of, dpa_proxy_match);
++
++static struct platform_driver dpa_proxy_driver = {
++      .driver = {
++              .name           = KBUILD_MODNAME "-proxy",
++              .of_match_table = dpa_proxy_match,
++              .owner          = THIS_MODULE,
++              .pm             = PROXY_PM_OPS,
++      },
++      .probe          = dpaa_eth_proxy_probe,
++      .remove         = dpa_eth_proxy_remove
++};
++
++static int __init __cold dpa_proxy_load(void)
++{
++      int      _errno;
++
++      pr_info(DPA_DESCRIPTION "\n");
++
++      /* Initialize dpaa_eth mirror values */
++      dpa_rx_extra_headroom = fm_get_rx_extra_headroom();
++      dpa_max_frm = fm_get_max_frm();
++
++      _errno = platform_driver_register(&dpa_proxy_driver);
++      if (unlikely(_errno < 0)) {
++              pr_err(KBUILD_MODNAME
++                      ": %s:%hu:%s(): platform_driver_register() = %d\n",
++                      KBUILD_BASENAME".c", __LINE__, __func__, _errno);
++      }
++
++      pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
++              KBUILD_BASENAME".c", __func__);
++
++      return _errno;
++}
++module_init(dpa_proxy_load);
++
++static void __exit __cold dpa_proxy_unload(void)
++{
++      platform_driver_unregister(&dpa_proxy_driver);
++
++      pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
++              KBUILD_BASENAME".c", __func__);
++}
++module_exit(dpa_proxy_unload);
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -0,0 +1,1113 @@
++/* Copyright 2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
++      KBUILD_BASENAME".c", __LINE__, __func__
++#else
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": " fmt
++#endif
++
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <linux/highmem.h>
++#include <linux/fsl_bman.h>
++
++#include "dpaa_eth.h"
++#include "dpaa_eth_common.h"
++#ifdef CONFIG_FSL_DPAA_1588
++#include "dpaa_1588.h"
++#endif
++#ifdef CONFIG_FSL_DPAA_CEETM
++#include "dpaa_eth_ceetm.h"
++#endif
++
++/* DMA map and add a page frag back into the bpool.
++ * @vaddr fragment must have been allocated with netdev_alloc_frag(),
++ * specifically for fitting into @dpa_bp.
++ */
++static void dpa_bp_recycle_frag(struct dpa_bp *dpa_bp, unsigned long vaddr,
++                              int *count_ptr)
++{
++      struct bm_buffer bmb;
++      dma_addr_t addr;
++
++      bmb.opaque = 0;
++
++      addr = dma_map_single(dpa_bp->dev, (void *)vaddr, dpa_bp->size,
++                            DMA_BIDIRECTIONAL);
++      if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) {
++              dev_err(dpa_bp->dev, "DMA mapping failed");
++              return;
++      }
++
++      bm_buffer_set64(&bmb, addr);
++
++      while (bman_release(dpa_bp->pool, &bmb, 1, 0))
++              cpu_relax();
++
++      (*count_ptr)++;
++}
++
++static int _dpa_bp_add_8_bufs(const struct dpa_bp *dpa_bp)
++{
++      struct bm_buffer bmb[8];
++      void *new_buf;
++      dma_addr_t addr;
++      uint8_t i;
++      struct device *dev = dpa_bp->dev;
++      struct sk_buff *skb, **skbh;
++
++      memset(bmb, 0, sizeof(struct bm_buffer) * 8);
++
++      for (i = 0; i < 8; i++) {
++              /* We'll prepend the skb back-pointer; can't use the DPA
++               * priv space, because FMan will overwrite it (from offset 0)
++               * if it ends up being the second, third, etc. fragment
++               * in a S/G frame.
++               *
++               * We only need enough space to store a pointer, but allocate
++               * an entire cacheline for performance reasons.
++               */
++#ifndef CONFIG_PPC
++              if (unlikely(dpaa_errata_a010022))
++                      new_buf = page_address(alloc_page(GFP_ATOMIC));
++              else
++#endif
++              new_buf = netdev_alloc_frag(SMP_CACHE_BYTES + DPA_BP_RAW_SIZE);
++
++              if (unlikely(!new_buf))
++                      goto netdev_alloc_failed;
++              new_buf = PTR_ALIGN(new_buf + SMP_CACHE_BYTES, SMP_CACHE_BYTES);
++
++              skb = build_skb(new_buf, DPA_SKB_SIZE(dpa_bp->size) +
++                      SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
++              if (unlikely(!skb)) {
++                      put_page(virt_to_head_page(new_buf));
++                      goto build_skb_failed;
++              }
++              DPA_WRITE_SKB_PTR(skb, skbh, new_buf, -1);
++
++              addr = dma_map_single(dev, new_buf,
++                              dpa_bp->size, DMA_BIDIRECTIONAL);
++              if (unlikely(dma_mapping_error(dev, addr)))
++                      goto dma_map_failed;
++
++              bm_buffer_set64(&bmb[i], addr);
++      }
++
++release_bufs:
++      /* Release the buffers. In case bman is busy, keep trying
++       * until successful. bman_release() is guaranteed to succeed
++       * in a reasonable amount of time
++       */
++      while (unlikely(bman_release(dpa_bp->pool, bmb, i, 0)))
++              cpu_relax();
++      return i;
++
++dma_map_failed:
++      kfree_skb(skb);
++
++build_skb_failed:
++netdev_alloc_failed:
++      net_err_ratelimited("dpa_bp_add_8_bufs() failed\n");
++      WARN_ONCE(1, "Memory allocation failure on Rx\n");
++
++      bm_buffer_set64(&bmb[i], 0);
++      /* Avoid releasing a completely null buffer; bman_release() requires
++       * at least one buffer.
++       */
++      if (likely(i))
++              goto release_bufs;
++
++      return 0;
++}
++
++/* Cold path wrapper over _dpa_bp_add_8_bufs(). */
++static void dpa_bp_add_8_bufs(const struct dpa_bp *dpa_bp, int cpu)
++{
++      int *count_ptr = per_cpu_ptr(dpa_bp->percpu_count, cpu);
++      *count_ptr += _dpa_bp_add_8_bufs(dpa_bp);
++}
++
++int dpa_bp_priv_seed(struct dpa_bp *dpa_bp)
++{
++      int i;
++
++      /* Give each CPU an allotment of "config_count" buffers */
++      for_each_possible_cpu(i) {
++              int j;
++
++              /* Although we access another CPU's counters here
++               * we do it at boot time so it is safe
++               */
++              for (j = 0; j < dpa_bp->config_count; j += 8)
++                      dpa_bp_add_8_bufs(dpa_bp, i);
++      }
++      return 0;
++}
++EXPORT_SYMBOL(dpa_bp_priv_seed);
++
++/* Add buffers/(pages) for Rx processing whenever bpool count falls below
++ * REFILL_THRESHOLD.
++ */
++int dpaa_eth_refill_bpools(struct dpa_bp *dpa_bp, int *countptr)
++{
++      int count = *countptr;
++      int new_bufs;
++
++      if (unlikely(count < CONFIG_FSL_DPAA_ETH_REFILL_THRESHOLD)) {
++              do {
++                      new_bufs = _dpa_bp_add_8_bufs(dpa_bp);
++                      if (unlikely(!new_bufs)) {
++                              /* Avoid looping forever if we've temporarily
++                               * run out of memory. We'll try again at the
++                               * next NAPI cycle.
++                               */
++                              break;
++                      }
++                      count += new_bufs;
++              } while (count < CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT);
++
++              *countptr = count;
++              if (unlikely(count < CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT))
++                      return -ENOMEM;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(dpaa_eth_refill_bpools);
++
++/* Cleanup function for outgoing frame descriptors that were built on Tx path,
++ * either contiguous frames or scatter/gather ones.
++ * Skb freeing is not handled here.
++ *
++ * This function may be called on error paths in the Tx function, so guard
++ * against cases when not all fd relevant fields were filled in.
++ *
++ * Return the skb backpointer, since for S/G frames the buffer containing it
++ * gets freed here.
++ */
++struct sk_buff *_dpa_cleanup_tx_fd(const struct dpa_priv_s *priv,
++      const struct qm_fd *fd)
++{
++      const struct qm_sg_entry *sgt;
++      int i;
++      struct dpa_bp *dpa_bp = priv->dpa_bp;
++      dma_addr_t addr = qm_fd_addr(fd);
++      dma_addr_t sg_addr;
++      struct sk_buff **skbh;
++      struct sk_buff *skb = NULL;
++      const enum dma_data_direction dma_dir = DMA_TO_DEVICE;
++      int nr_frags;
++      int sg_len;
++
++      /* retrieve skb back pointer */
++      DPA_READ_SKB_PTR(skb, skbh, phys_to_virt(addr), 0);
++
++      if (unlikely(fd->format == qm_fd_sg)) {
++              nr_frags = skb_shinfo(skb)->nr_frags;
++              dma_unmap_single(dpa_bp->dev, addr, dpa_fd_offset(fd) +
++                               sizeof(struct qm_sg_entry) * (1 + nr_frags),
++                               dma_dir);
++
++              /* The sgt buffer has been allocated with netdev_alloc_frag(),
++               * it's from lowmem.
++               */
++              sgt = phys_to_virt(addr + dpa_fd_offset(fd));
++#ifdef CONFIG_FSL_DPAA_1588
++              if (priv->tsu && priv->tsu->valid &&
++                              priv->tsu->hwts_tx_en_ioctl)
++                      dpa_ptp_store_txstamp(priv, skb, (void *)skbh);
++#endif
++#ifdef CONFIG_FSL_DPAA_TS
++              if (unlikely(priv->ts_tx_en &&
++                      skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
++                      struct skb_shared_hwtstamps shhwtstamps;
++
++                      dpa_get_ts(priv, TX, &shhwtstamps, (void *)skbh);
++                      skb_tstamp_tx(skb, &shhwtstamps);
++              }
++#endif /* CONFIG_FSL_DPAA_TS */
++
++              /* sgt[0] is from lowmem, was dma_map_single()-ed */
++              sg_addr = qm_sg_addr(&sgt[0]);
++              sg_len = qm_sg_entry_get_len(&sgt[0]);
++              dma_unmap_single(dpa_bp->dev, sg_addr, sg_len, dma_dir);
++
++              /* remaining pages were mapped with dma_map_page() */
++              for (i = 1; i <= nr_frags; i++) {
++                      DPA_BUG_ON(qm_sg_entry_get_ext(&sgt[i]));
++                      sg_addr = qm_sg_addr(&sgt[i]);
++                      sg_len = qm_sg_entry_get_len(&sgt[i]);
++                      dma_unmap_page(dpa_bp->dev, sg_addr, sg_len, dma_dir);
++              }
++
++              /* Free the page frag that we allocated on Tx */
++              put_page(virt_to_head_page(sgt));
++      } else {
++              dma_unmap_single(dpa_bp->dev, addr,
++                               skb_tail_pointer(skb) - (u8 *)skbh, dma_dir);
++#ifdef CONFIG_FSL_DPAA_TS
++              /* get the timestamp for non-SG frames */
++#ifdef CONFIG_FSL_DPAA_1588
++              if (priv->tsu && priv->tsu->valid &&
++                                              priv->tsu->hwts_tx_en_ioctl)
++                      dpa_ptp_store_txstamp(priv, skb, (void *)skbh);
++#endif
++              if (unlikely(priv->ts_tx_en &&
++                              skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
++                      struct skb_shared_hwtstamps shhwtstamps;
++
++                      dpa_get_ts(priv, TX, &shhwtstamps, (void *)skbh);
++                      skb_tstamp_tx(skb, &shhwtstamps);
++              }
++#endif
++      }
++
++      return skb;
++}
++EXPORT_SYMBOL(_dpa_cleanup_tx_fd);
++
++#ifndef CONFIG_FSL_DPAA_TS
++bool dpa_skb_is_recyclable(struct sk_buff *skb)
++{
++      /* No recycling possible if skb buffer is kmalloc'ed  */
++      if (skb->head_frag == 0)
++              return false;
++
++      /* or if it's an userspace buffer */
++      if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY)
++              return false;
++
++      /* or if it's cloned or shared */
++      if (skb_shared(skb) || skb_cloned(skb) ||
++          skb->fclone != SKB_FCLONE_UNAVAILABLE)
++              return false;
++
++      return true;
++}
++EXPORT_SYMBOL(dpa_skb_is_recyclable);
++
++bool dpa_buf_is_recyclable(struct sk_buff *skb,
++                                uint32_t min_size,
++                                uint16_t min_offset,
++                                unsigned char **new_buf_start)
++{
++      unsigned char *new;
++
++      /* In order to recycle a buffer, the following conditions must be met:
++       * - buffer size no less than the buffer pool size
++       * - buffer size no higher than an upper limit (to avoid moving too much
++       *   system memory to the buffer pools)
++       * - buffer address aligned to cacheline bytes
++       * - offset of data from start of buffer no lower than a minimum value
++       * - offset of data from start of buffer no higher than a maximum value
++       */
++      new = min(skb_end_pointer(skb) - min_size, skb->data - min_offset);
++
++      /* left align to the nearest cacheline */
++      new = (unsigned char *)((unsigned long)new & ~(SMP_CACHE_BYTES - 1));
++
++      if (likely(new >= skb->head &&
++                 new >= (skb->data - DPA_MAX_FD_OFFSET) &&
++                 skb_end_pointer(skb) - new <= DPA_RECYCLE_MAX_SIZE)) {
++              *new_buf_start = new;
++              return true;
++      }
++
++      return false;
++}
++EXPORT_SYMBOL(dpa_buf_is_recyclable);
++#endif
++
++/* Build a linear skb around the received buffer.
++ * We are guaranteed there is enough room at the end of the data buffer to
++ * accommodate the shared info area of the skb.
++ */
++static struct sk_buff *__hot contig_fd_to_skb(const struct dpa_priv_s *priv,
++      const struct qm_fd *fd, int *use_gro)
++{
++      dma_addr_t addr = qm_fd_addr(fd);
++      ssize_t fd_off = dpa_fd_offset(fd);
++      void *vaddr;
++      const fm_prs_result_t *parse_results;
++      struct sk_buff *skb = NULL, **skbh;
++
++      vaddr = phys_to_virt(addr);
++      DPA_BUG_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES));
++
++      /* Retrieve the skb and adjust data and tail pointers, to make sure
++       * forwarded skbs will have enough space on Tx if extra headers
++       * are added.
++       */
++      DPA_READ_SKB_PTR(skb, skbh, vaddr, -1);
++
++#ifdef CONFIG_FSL_DPAA_ETH_JUMBO_FRAME
++      /* When using jumbo Rx buffers, we risk having frames dropped due to
++       * the socket backlog reaching its maximum allowed size.
++       * Use the frame length for the skb truesize instead of the buffer
++       * size, as this is the size of the data that actually gets copied to
++       * userspace.
++       * The stack may increase the payload. In this case, it will want to
++       * warn us that the frame length is larger than the truesize. We
++       * bypass the warning.
++       */
++#ifndef CONFIG_PPC
++      /* We do not support Jumbo frames on LS1043 and thus we edit
++       * the skb truesize only when the 4k errata is not present.
++       */
++      if (likely(!dpaa_errata_a010022))
++#endif
++      skb->truesize = SKB_TRUESIZE(dpa_fd_length(fd));
++#endif
++
++      DPA_BUG_ON(fd_off != priv->rx_headroom);
++      skb_reserve(skb, fd_off);
++      skb_put(skb, dpa_fd_length(fd));
++
++      /* Peek at the parse results for csum validation */
++      parse_results = (const fm_prs_result_t *)(vaddr +
++                              DPA_RX_PRIV_DATA_SIZE);
++      _dpa_process_parse_results(parse_results, fd, skb, use_gro);
++
++#ifdef CONFIG_FSL_DPAA_1588
++      if (priv->tsu && priv->tsu->valid && priv->tsu->hwts_rx_en_ioctl)
++              dpa_ptp_store_rxstamp(priv, skb, vaddr);
++#endif
++#ifdef CONFIG_FSL_DPAA_TS
++      if (priv->ts_rx_en)
++              dpa_get_ts(priv, RX, skb_hwtstamps(skb), vaddr);
++#endif /* CONFIG_FSL_DPAA_TS */
++
++      return skb;
++}
++
++
++/* Build an skb with the data of the first S/G entry in the linear portion and
++ * the rest of the frame as skb fragments.
++ *
++ * The page fragment holding the S/G Table is recycled here.
++ */
++static struct sk_buff *__hot sg_fd_to_skb(const struct dpa_priv_s *priv,
++                             const struct qm_fd *fd, int *use_gro,
++                             int *count_ptr)
++{
++      const struct qm_sg_entry *sgt;
++      dma_addr_t addr = qm_fd_addr(fd);
++      ssize_t fd_off = dpa_fd_offset(fd);
++      dma_addr_t sg_addr;
++      void *vaddr, *sg_vaddr;
++      struct dpa_bp *dpa_bp;
++      struct page *page, *head_page;
++      int frag_offset, frag_len;
++      int page_offset;
++      int i;
++      const fm_prs_result_t *parse_results;
++      struct sk_buff *skb = NULL, *skb_tmp, **skbh;
++
++      vaddr = phys_to_virt(addr);
++      DPA_BUG_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES));
++
++      dpa_bp = priv->dpa_bp;
++      /* Iterate through the SGT entries and add data buffers to the skb */
++      sgt = vaddr + fd_off;
++      for (i = 0; i < DPA_SGT_MAX_ENTRIES; i++) {
++              /* Extension bit is not supported */
++              DPA_BUG_ON(qm_sg_entry_get_ext(&sgt[i]));
++
++              /* We use a single global Rx pool */
++              DPA_BUG_ON(dpa_bp !=
++                         dpa_bpid2pool(qm_sg_entry_get_bpid(&sgt[i])));
++
++              sg_addr = qm_sg_addr(&sgt[i]);
++              sg_vaddr = phys_to_virt(sg_addr);
++              DPA_BUG_ON(!IS_ALIGNED((unsigned long)sg_vaddr,
++                              SMP_CACHE_BYTES));
++
++              dma_unmap_single(dpa_bp->dev, sg_addr, dpa_bp->size,
++                               DMA_BIDIRECTIONAL);
++              if (i == 0) {
++                      DPA_READ_SKB_PTR(skb, skbh, sg_vaddr, -1);
++                      DPA_BUG_ON(skb->head != sg_vaddr);
++#ifdef CONFIG_FSL_DPAA_1588
++                      if (priv->tsu && priv->tsu->valid &&
++                          priv->tsu->hwts_rx_en_ioctl)
++                              dpa_ptp_store_rxstamp(priv, skb, vaddr);
++#endif
++#ifdef CONFIG_FSL_DPAA_TS
++                      if (priv->ts_rx_en)
++                              dpa_get_ts(priv, RX, skb_hwtstamps(skb), vaddr);
++#endif /* CONFIG_FSL_DPAA_TS */
++
++                      /* In the case of a SG frame, FMan stores the Internal
++                       * Context in the buffer containing the sgt.
++                       * Inspect the parse results before anything else.
++                       */
++                      parse_results = (const fm_prs_result_t *)(vaddr +
++                                              DPA_RX_PRIV_DATA_SIZE);
++                      _dpa_process_parse_results(parse_results, fd, skb,
++                                                 use_gro);
++
++                      /* Make sure forwarded skbs will have enough space
++                       * on Tx, if extra headers are added.
++                       */
++                      DPA_BUG_ON(fd_off != priv->rx_headroom);
++                      skb_reserve(skb, fd_off);
++                      skb_put(skb, qm_sg_entry_get_len(&sgt[i]));
++              } else {
++                      /* Not the first S/G entry; all data from buffer will
++                       * be added in an skb fragment; fragment index is offset
++                       * by one since first S/G entry was incorporated in the
++                       * linear part of the skb.
++                       *
++                       * Caution: 'page' may be a tail page.
++                       */
++                      DPA_READ_SKB_PTR(skb_tmp, skbh, sg_vaddr, -1);
++                      page = virt_to_page(sg_vaddr);
++                      head_page = virt_to_head_page(sg_vaddr);
++
++                      /* Free (only) the skbuff shell because its data buffer
++                       * is already a frag in the main skb.
++                       */
++                      get_page(head_page);
++                      dev_kfree_skb(skb_tmp);
++
++                      /* Compute offset in (possibly tail) page */
++                      page_offset = ((unsigned long)sg_vaddr &
++                                      (PAGE_SIZE - 1)) +
++                              (page_address(page) - page_address(head_page));
++                      /* page_offset only refers to the beginning of sgt[i];
++                       * but the buffer itself may have an internal offset.
++                       */
++                      frag_offset = qm_sg_entry_get_offset(&sgt[i]) +
++                                      page_offset;
++                      frag_len = qm_sg_entry_get_len(&sgt[i]);
++                      /* skb_add_rx_frag() does no checking on the page; if
++                       * we pass it a tail page, we'll end up with
++                       * bad page accounting and eventually with segafults.
++                       */
++                      skb_add_rx_frag(skb, i - 1, head_page, frag_offset,
++                              frag_len, dpa_bp->size);
++              }
++              /* Update the pool count for the current {cpu x bpool} */
++              (*count_ptr)--;
++
++              if (qm_sg_entry_get_final(&sgt[i]))
++                      break;
++      }
++      WARN_ONCE(i == DPA_SGT_MAX_ENTRIES, "No final bit on SGT\n");
++
++      /* recycle the SGT fragment */
++      DPA_BUG_ON(dpa_bp != dpa_bpid2pool(fd->bpid));
++      dpa_bp_recycle_frag(dpa_bp, (unsigned long)vaddr, count_ptr);
++      return skb;
++}
++
++#ifdef CONFIG_FSL_DPAA_DBG_LOOP
++static inline int dpa_skb_loop(const struct dpa_priv_s *priv,
++              struct sk_buff *skb)
++{
++      if (unlikely(priv->loop_to < 0))
++              return 0; /* loop disabled by default */
++
++      skb_push(skb, ETH_HLEN); /* compensate for eth_type_trans */
++      dpa_tx(skb, dpa_loop_netdevs[priv->loop_to]);
++
++      return 1; /* Frame Tx on the selected interface */
++}
++#endif
++
++void __hot _dpa_rx(struct net_device *net_dev,
++              struct qman_portal *portal,
++              const struct dpa_priv_s *priv,
++              struct dpa_percpu_priv_s *percpu_priv,
++              const struct qm_fd *fd,
++              u32 fqid,
++              int *count_ptr)
++{
++      struct dpa_bp *dpa_bp;
++      struct sk_buff *skb;
++      dma_addr_t addr = qm_fd_addr(fd);
++      u32 fd_status = fd->status;
++      unsigned int skb_len;
++      struct rtnl_link_stats64 *percpu_stats = &percpu_priv->stats;
++      int use_gro = net_dev->features & NETIF_F_GRO;
++
++      if (unlikely(fd_status & FM_FD_STAT_RX_ERRORS) != 0) {
++              if (netif_msg_hw(priv) && net_ratelimit())
++                      netdev_warn(net_dev, "FD status = 0x%08x\n",
++                                      fd_status & FM_FD_STAT_RX_ERRORS);
++
++              percpu_stats->rx_errors++;
++              goto _release_frame;
++      }
++
++      dpa_bp = priv->dpa_bp;
++      DPA_BUG_ON(dpa_bp != dpa_bpid2pool(fd->bpid));
++
++      /* prefetch the first 64 bytes of the frame or the SGT start */
++      dma_unmap_single(dpa_bp->dev, addr, dpa_bp->size, DMA_BIDIRECTIONAL);
++      prefetch(phys_to_virt(addr) + dpa_fd_offset(fd));
++
++      /* The only FD types that we may receive are contig and S/G */
++      DPA_BUG_ON((fd->format != qm_fd_contig) && (fd->format != qm_fd_sg));
++
++      if (likely(fd->format == qm_fd_contig)) {
++#ifdef CONFIG_FSL_DPAA_HOOKS
++              /* Execute the Rx processing hook, if it exists. */
++              if (dpaa_eth_hooks.rx_default &&
++                      dpaa_eth_hooks.rx_default((void *)fd, net_dev,
++                                      fqid) == DPAA_ETH_STOLEN) {
++                      /* won't count the rx bytes in */
++                      return;
++              }
++#endif
++              skb = contig_fd_to_skb(priv, fd, &use_gro);
++      } else {
++              skb = sg_fd_to_skb(priv, fd, &use_gro, count_ptr);
++              percpu_priv->rx_sg++;
++      }
++
++      /* Account for either the contig buffer or the SGT buffer (depending on
++       * which case we were in) having been removed from the pool.
++       */
++      (*count_ptr)--;
++      skb->protocol = eth_type_trans(skb, net_dev);
++
++      /* IP Reassembled frames are allowed to be larger than MTU */
++      if (unlikely(dpa_check_rx_mtu(skb, net_dev->mtu) &&
++              !(fd_status & FM_FD_IPR))) {
++              percpu_stats->rx_dropped++;
++              goto drop_bad_frame;
++      }
++
++      skb_len = skb->len;
++
++#ifdef CONFIG_FSL_DPAA_DBG_LOOP
++      if (dpa_skb_loop(priv, skb)) {
++              percpu_stats->rx_packets++;
++              percpu_stats->rx_bytes += skb_len;
++              return;
++      }
++#endif
++
++      if (use_gro) {
++              gro_result_t gro_result;
++              const struct qman_portal_config *pc =
++                                      qman_p_get_portal_config(portal);
++              struct dpa_napi_portal *np = &percpu_priv->np[pc->index];
++
++              np->p = portal;
++              gro_result = napi_gro_receive(&np->napi, skb);
++              /* If frame is dropped by the stack, rx_dropped counter is
++               * incremented automatically, so no need for us to update it
++               */
++              if (unlikely(gro_result == GRO_DROP))
++                      goto packet_dropped;
++      } else if (unlikely(netif_receive_skb(skb) == NET_RX_DROP))
++              goto packet_dropped;
++
++      percpu_stats->rx_packets++;
++      percpu_stats->rx_bytes += skb_len;
++
++packet_dropped:
++      return;
++
++drop_bad_frame:
++      dev_kfree_skb(skb);
++      return;
++
++_release_frame:
++      dpa_fd_release(net_dev, fd);
++}
++
++int __hot skb_to_contig_fd(struct dpa_priv_s *priv,
++                         struct sk_buff *skb, struct qm_fd *fd,
++                         int *count_ptr, int *offset)
++{
++      struct sk_buff **skbh;
++      dma_addr_t addr;
++      struct dpa_bp *dpa_bp = priv->dpa_bp;
++      struct net_device *net_dev = priv->net_dev;
++      int err;
++      enum dma_data_direction dma_dir;
++      unsigned char *buffer_start;
++      int dma_map_size;
++
++#ifndef CONFIG_FSL_DPAA_TS
++      /* Check recycling conditions; only if timestamp support is not
++       * enabled, otherwise we need the fd back on tx confirmation
++       */
++
++      /* We can recycle the buffer if:
++       * - the pool is not full
++       * - the buffer meets the skb recycling conditions
++       * - the buffer meets our own (size, offset, align) conditions
++       */
++      if (likely((*count_ptr < dpa_bp->target_count) &&
++                 dpa_skb_is_recyclable(skb) &&
++                 dpa_buf_is_recyclable(skb, dpa_bp->size,
++                                       priv->tx_headroom, &buffer_start))) {
++              /* Buffer is recyclable; use the new start address
++               * and set fd parameters and DMA mapping direction
++               */
++              fd->bpid = dpa_bp->bpid;
++              DPA_BUG_ON(skb->data - buffer_start > DPA_MAX_FD_OFFSET);
++              fd->offset = (uint16_t)(skb->data - buffer_start);
++              dma_dir = DMA_BIDIRECTIONAL;
++              dma_map_size = dpa_bp->size;
++
++              DPA_WRITE_SKB_PTR(skb, skbh, buffer_start, -1);
++              *offset = skb_headroom(skb) - fd->offset;
++      } else
++#endif
++      {
++              /* Not recyclable.
++               * We are guaranteed to have at least tx_headroom bytes
++               * available, so just use that for offset.
++               */
++              fd->bpid = 0xff;
++              buffer_start = skb->data - priv->tx_headroom;
++              fd->offset = priv->tx_headroom;
++              dma_dir = DMA_TO_DEVICE;
++              dma_map_size = skb_tail_pointer(skb) - buffer_start;
++
++              /* The buffer will be Tx-confirmed, but the TxConf cb must
++               * necessarily look at our Tx private data to retrieve the
++               * skbuff. (In short: can't use DPA_WRITE_SKB_PTR() here.)
++               */
++              DPA_WRITE_SKB_PTR(skb, skbh, buffer_start, 0);
++      }
++
++      /* Enable L3/L4 hardware checksum computation.
++       *
++       * We must do this before dma_map_single(DMA_TO_DEVICE), because we may
++       * need to write into the skb.
++       */
++      err = dpa_enable_tx_csum(priv, skb, fd,
++                               ((char *)skbh) + DPA_TX_PRIV_DATA_SIZE);
++      if (unlikely(err < 0)) {
++              if (netif_msg_tx_err(priv) && net_ratelimit())
++                      netdev_err(net_dev, "HW csum error: %d\n", err);
++              return err;
++      }
++
++      /* Fill in the rest of the FD fields */
++      fd->format = qm_fd_contig;
++      fd->length20 = skb->len;
++      fd->cmd |= FM_FD_CMD_FCO;
++
++      /* Map the entire buffer size that may be seen by FMan, but no more */
++      addr = dma_map_single(dpa_bp->dev, skbh, dma_map_size, dma_dir);
++      if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) {
++              if (netif_msg_tx_err(priv) && net_ratelimit())
++                      netdev_err(net_dev, "dma_map_single() failed\n");
++              return -EINVAL;
++      }
++      qm_fd_addr_set64(fd, addr);
++
++      return 0;
++}
++EXPORT_SYMBOL(skb_to_contig_fd);
++
++#ifndef CONFIG_PPC
++struct sk_buff *split_skb_at_4k_boundaries(struct sk_buff *skb)
++{
++      unsigned int length, nr_frags, moved_len = 0;
++      u64 page_start;
++      struct page *page;
++      skb_frag_t *frag;
++      int i = 0, j = 0;
++
++      /* make sure skb is not shared */
++      skb = skb_share_check(skb, GFP_ATOMIC);
++      if (!skb)
++              return NULL;
++
++      nr_frags = skb_shinfo(skb)->nr_frags;
++      page_start = (u64)skb->data;
++
++      /* split the linear part at the first 4k boundary and create one (big)
++       * fragment with the rest
++       */
++      if (HAS_DMA_ISSUE(skb->data, skb_headlen(skb))) {
++              /* we'll add one more frag, make sure there's room */
++              if (nr_frags + 1 > DPA_SGT_MAX_ENTRIES)
++                      return NULL;
++
++              /* next page boundary */
++              page_start = (page_start + 0x1000) & ~0xFFF;
++              page = virt_to_page(page_start);
++
++              /* move the rest of fragments to make room for a new one at j */
++              for (i = nr_frags - 1; i >= j;  i--)
++                      skb_shinfo(skb)->frags[i + 1] = skb_shinfo(skb)->frags[i];
++
++              /* move length bytes to a paged fragment at j */
++              length = min((u64)0x1000,
++                           (u64)skb->data + skb_headlen(skb) - page_start);
++              skb->data_len += length;
++              moved_len += length;
++              skb_fill_page_desc(skb, j++, page, 0, length);
++              get_page(page);
++              skb_shinfo(skb)->nr_frags = ++nr_frags;
++      }
++      /* adjust the tail pointer */
++      skb->tail -= moved_len;
++      j = 0;
++
++      /* split any paged fragment that crosses a 4K boundary */
++      while (j < nr_frags) {
++              frag = &skb_shinfo(skb)->frags[j];
++
++              /* if there is a 4K boundary between the fragment's offset and end */
++              if (HAS_DMA_ISSUE(frag->page_offset, frag->size)) {
++                      /* we'll add one more frag, make sure there's room */
++                      if (nr_frags + 1 > DPA_SGT_MAX_ENTRIES)
++                              return NULL;
++
++                      /* new page boundary */
++                      page_start = (u64)page_address(skb_frag_page(frag)) +
++                                                frag->page_offset + 0x1000;
++                      page_start = (u64)page_start & ~0xFFF;
++                      page = virt_to_page(page_start);
++
++                      /* move the rest of fragments to make room for a new one at j+1 */
++                      for (i = nr_frags - 1; i > j;  i--)
++                              skb_shinfo(skb)->frags[i + 1] =
++                                              skb_shinfo(skb)->frags[i];
++
++                      /* move length bytes to a new paged fragment at j+1 */
++                      length = (u64)page_address(skb_frag_page(frag)) +
++                               frag->page_offset + frag->size - page_start;
++                      frag->size -= length;
++                      skb_fill_page_desc(skb, j + 1, page, 0, length);
++                      get_page(page);
++                      skb_shinfo(skb)->nr_frags = ++nr_frags;
++              }
++
++              /* move to next frag */
++              j++;
++      }
++
++      return skb;
++}
++#endif
++
++int __hot skb_to_sg_fd(struct dpa_priv_s *priv,
++                     struct sk_buff *skb, struct qm_fd *fd)
++{
++      struct dpa_bp *dpa_bp = priv->dpa_bp;
++      dma_addr_t addr;
++      dma_addr_t sg_addr;
++      struct sk_buff **skbh;
++      struct net_device *net_dev = priv->net_dev;
++      int sg_len, sgt_size;
++      int err;
++
++      struct qm_sg_entry *sgt;
++      void *sgt_buf;
++      skb_frag_t *frag;
++      int i = 0, j = 0;
++      int nr_frags;
++      const enum dma_data_direction dma_dir = DMA_TO_DEVICE;
++
++      nr_frags = skb_shinfo(skb)->nr_frags;
++      fd->format = qm_fd_sg;
++
++      sgt_size = sizeof(struct qm_sg_entry) * (1 + nr_frags);
++
++      /* Get a page frag to store the SGTable, or a full page if the errata
++       * is in place and we need to avoid crossing a 4k boundary.
++       */
++#ifndef CONFIG_PPC
++      if (unlikely(dpaa_errata_a010022))
++              sgt_buf = page_address(alloc_page(GFP_ATOMIC));
++      else
++#endif
++              sgt_buf = netdev_alloc_frag(priv->tx_headroom + sgt_size);
++      if (unlikely(!sgt_buf)) {
++              dev_err(dpa_bp->dev, "netdev_alloc_frag() failed\n");
++              return -ENOMEM;
++      }
++
++      /* it seems that the memory allocator does not zero the allocated mem */
++      memset(sgt_buf, 0, priv->tx_headroom + sgt_size);
++
++      /* Enable L3/L4 hardware checksum computation.
++       *
++       * We must do this before dma_map_single(DMA_TO_DEVICE), because we may
++       * need to write into the skb.
++       */
++      err = dpa_enable_tx_csum(priv, skb, fd,
++                               sgt_buf + DPA_TX_PRIV_DATA_SIZE);
++      if (unlikely(err < 0)) {
++              if (netif_msg_tx_err(priv) && net_ratelimit())
++                      netdev_err(net_dev, "HW csum error: %d\n", err);
++              goto csum_failed;
++      }
++
++      /* Assign the data from skb->data to the first SG list entry */
++      sgt = (struct qm_sg_entry *)(sgt_buf + priv->tx_headroom);
++      sg_len = skb_headlen(skb);
++      qm_sg_entry_set_bpid(&sgt[0], 0xff);
++      qm_sg_entry_set_offset(&sgt[0], 0);
++      qm_sg_entry_set_len(&sgt[0], sg_len);
++      qm_sg_entry_set_ext(&sgt[0], 0);
++      qm_sg_entry_set_final(&sgt[0], 0);
++
++      addr = dma_map_single(dpa_bp->dev, skb->data, sg_len, dma_dir);
++      if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) {
++              dev_err(dpa_bp->dev, "DMA mapping failed");
++              err = -EINVAL;
++              goto sg0_map_failed;
++      }
++
++      qm_sg_entry_set64(&sgt[0], addr);
++
++      /* populate the rest of SGT entries */
++      for (i = 1; i <= nr_frags; i++) {
++              frag = &skb_shinfo(skb)->frags[i - 1];
++              qm_sg_entry_set_bpid(&sgt[i], 0xff);
++              qm_sg_entry_set_offset(&sgt[i], 0);
++              qm_sg_entry_set_len(&sgt[i], frag->size);
++              qm_sg_entry_set_ext(&sgt[i], 0);
++
++              if (i == nr_frags)
++                      qm_sg_entry_set_final(&sgt[i], 1);
++              else
++                      qm_sg_entry_set_final(&sgt[i], 0);
++
++              DPA_BUG_ON(!skb_frag_page(frag));
++              addr = skb_frag_dma_map(dpa_bp->dev, frag, 0, frag->size,
++                                      dma_dir);
++              if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) {
++                      dev_err(dpa_bp->dev, "DMA mapping failed");
++                      err = -EINVAL;
++                      goto sg_map_failed;
++              }
++
++              /* keep the offset in the address */
++              qm_sg_entry_set64(&sgt[i], addr);
++      }
++
++      fd->length20 = skb->len;
++      fd->offset = priv->tx_headroom;
++
++      /* DMA map the SGT page */
++      DPA_WRITE_SKB_PTR(skb, skbh, sgt_buf, 0);
++      addr = dma_map_single(dpa_bp->dev, sgt_buf,
++                            priv->tx_headroom + sgt_size,
++                            dma_dir);
++
++      if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) {
++              dev_err(dpa_bp->dev, "DMA mapping failed");
++              err = -EINVAL;
++              goto sgt_map_failed;
++      }
++
++      qm_fd_addr_set64(fd, addr);
++      fd->bpid = 0xff;
++      fd->cmd |= FM_FD_CMD_FCO;
++
++      return 0;
++
++sgt_map_failed:
++sg_map_failed:
++      for (j = 0; j < i; j++) {
++              sg_addr = qm_sg_addr(&sgt[j]);
++              dma_unmap_page(dpa_bp->dev, sg_addr,
++                             qm_sg_entry_get_len(&sgt[j]), dma_dir);
++      }
++sg0_map_failed:
++csum_failed:
++      put_page(virt_to_head_page(sgt_buf));
++
++      return err;
++}
++EXPORT_SYMBOL(skb_to_sg_fd);
++
++int __hot dpa_tx(struct sk_buff *skb, struct net_device *net_dev)
++{
++      struct dpa_priv_s       *priv;
++      const int queue_mapping = dpa_get_queue_mapping(skb);
++      struct qman_fq *egress_fq, *conf_fq;
++
++#ifdef CONFIG_FSL_DPAA_HOOKS
++      /* If there is a Tx hook, run it. */
++      if (dpaa_eth_hooks.tx &&
++              dpaa_eth_hooks.tx(skb, net_dev) == DPAA_ETH_STOLEN)
++              /* won't update any Tx stats */
++              return NETDEV_TX_OK;
++#endif
++
++      priv = netdev_priv(net_dev);
++
++#ifdef CONFIG_FSL_DPAA_CEETM
++      if (priv->ceetm_en)
++              return ceetm_tx(skb, net_dev);
++#endif
++
++      egress_fq = priv->egress_fqs[queue_mapping];
++      conf_fq = priv->conf_fqs[queue_mapping];
++
++      return dpa_tx_extended(skb, net_dev, egress_fq, conf_fq);
++}
++
++int __hot dpa_tx_extended(struct sk_buff *skb, struct net_device *net_dev,
++              struct qman_fq *egress_fq, struct qman_fq *conf_fq)
++{
++      struct dpa_priv_s       *priv;
++      struct qm_fd             fd;
++      struct dpa_percpu_priv_s *percpu_priv;
++      struct rtnl_link_stats64 *percpu_stats;
++      int err = 0;
++      const bool nonlinear = skb_is_nonlinear(skb);
++      int *countptr, offset = 0;
++
++      priv = netdev_priv(net_dev);
++      /* Non-migratable context, safe to use raw_cpu_ptr */
++      percpu_priv = raw_cpu_ptr(priv->percpu_priv);
++      percpu_stats = &percpu_priv->stats;
++      countptr = raw_cpu_ptr(priv->dpa_bp->percpu_count);
++
++      clear_fd(&fd);
++
++#ifdef CONFIG_FSL_DPAA_1588
++      if (priv->tsu && priv->tsu->valid && priv->tsu->hwts_tx_en_ioctl)
++              fd.cmd |= FM_FD_CMD_UPD;
++#endif
++#ifdef CONFIG_FSL_DPAA_TS
++      if (unlikely(priv->ts_tx_en &&
++                      skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
++              fd.cmd |= FM_FD_CMD_UPD;
++      skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
++#endif /* CONFIG_FSL_DPAA_TS */
++
++#ifndef CONFIG_PPC
++      if (unlikely(dpaa_errata_a010022)) {
++              skb = split_skb_at_4k_boundaries(skb);
++              if (!skb)
++                      goto skb_to_fd_failed;
++      }
++#endif
++
++      /* MAX_SKB_FRAGS is larger than our DPA_SGT_MAX_ENTRIES; make sure
++       * we don't feed FMan with more fragments than it supports.
++       * Btw, we're using the first sgt entry to store the linear part of
++       * the skb, so we're one extra frag short.
++       */
++      if (nonlinear &&
++              likely(skb_shinfo(skb)->nr_frags < DPA_SGT_MAX_ENTRIES)) {
++              /* Just create a S/G fd based on the skb */
++              err = skb_to_sg_fd(priv, skb, &fd);
++              percpu_priv->tx_frag_skbuffs++;
++      } else {
++              /* Make sure we have enough headroom to accommodate private
++               * data, parse results, etc. Normally this shouldn't happen if
++               * we're here via the standard kernel stack.
++               */
++              if (unlikely(skb_headroom(skb) < priv->tx_headroom)) {
++                      struct sk_buff *skb_new;
++
++                      skb_new = skb_realloc_headroom(skb, priv->tx_headroom);
++                      if (unlikely(!skb_new)) {
++                              dev_kfree_skb(skb);
++                              percpu_stats->tx_errors++;
++                              return NETDEV_TX_OK;
++                      }
++                      dev_kfree_skb(skb);
++                      skb = skb_new;
++              }
++
++              /* We're going to store the skb backpointer at the beginning
++               * of the data buffer, so we need a privately owned skb
++               */
++
++              /* Code borrowed from skb_unshare(). */
++              if (skb_cloned(skb)) {
++                      struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);
++                      kfree_skb(skb);
++                      skb = nskb;
++                      /* skb_copy() has now linearized the skbuff. */
++              } else if (unlikely(nonlinear)) {
++                      /* We are here because the egress skb contains
++                       * more fragments than we support. In this case,
++                       * we have no choice but to linearize it ourselves.
++                       */
++                      err = __skb_linearize(skb);
++              }
++              if (unlikely(!skb || err < 0))
++                      /* Common out-of-memory error path */
++                      goto enomem;
++
++              err = skb_to_contig_fd(priv, skb, &fd, countptr, &offset);
++      }
++      if (unlikely(err < 0))
++              goto skb_to_fd_failed;
++
++      if (fd.bpid != 0xff) {
++              skb_recycle(skb);
++              /* skb_recycle() reserves NET_SKB_PAD as skb headroom,
++               * but we need the skb to look as if returned by build_skb().
++               * We need to manually adjust the tailptr as well.
++               */
++              skb->data = skb->head + offset;
++              skb_reset_tail_pointer(skb);
++
++              (*countptr)++;
++              percpu_priv->tx_returned++;
++      }
++
++      if (unlikely(dpa_xmit(priv, percpu_stats, &fd, egress_fq, conf_fq) < 0))
++              goto xmit_failed;
++
++      return NETDEV_TX_OK;
++
++xmit_failed:
++      if (fd.bpid != 0xff) {
++              (*countptr)--;
++              percpu_priv->tx_returned--;
++              dpa_fd_release(net_dev, &fd);
++              percpu_stats->tx_errors++;
++              return NETDEV_TX_OK;
++      }
++      _dpa_cleanup_tx_fd(priv, &fd);
++skb_to_fd_failed:
++enomem:
++      percpu_stats->tx_errors++;
++      dev_kfree_skb(skb);
++      return NETDEV_TX_OK;
++}
++EXPORT_SYMBOL(dpa_tx_extended);
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sysfs.c
+@@ -0,0 +1,278 @@
++/* Copyright 2008-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kthread.h>
++#include <linux/io.h>
++#include <linux/of_net.h>
++#include "dpaa_eth.h"
++#include "mac.h"              /* struct mac_device */
++#ifdef CONFIG_FSL_DPAA_1588
++#include "dpaa_1588.h"
++#endif
++
++static ssize_t dpaa_eth_show_addr(struct device *dev,
++              struct device_attribute *attr, char *buf)
++{
++      struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
++      struct mac_device *mac_dev = priv->mac_dev;
++
++      if (mac_dev)
++              return sprintf(buf, "%llx",
++                              (unsigned long long)mac_dev->res->start);
++      else
++              return sprintf(buf, "none");
++}
++
++static ssize_t dpaa_eth_show_type(struct device *dev,
++              struct device_attribute *attr, char *buf)
++{
++      struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
++      ssize_t res = 0;
++
++      if (priv)
++              res = sprintf(buf, "%s", priv->if_type);
++
++      return res;
++}
++
++static ssize_t dpaa_eth_show_fqids(struct device *dev,
++              struct device_attribute *attr, char *buf)
++{
++      struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
++      ssize_t bytes = 0;
++      int i = 0;
++      char *str;
++      struct dpa_fq *fq;
++      struct dpa_fq *tmp;
++      struct dpa_fq *prev = NULL;
++      u32 first_fqid = 0;
++      u32 last_fqid = 0;
++      char *prevstr = NULL;
++
++      list_for_each_entry_safe(fq, tmp, &priv->dpa_fq_list, list) {
++              switch (fq->fq_type) {
++              case FQ_TYPE_RX_DEFAULT:
++                      str = "Rx default";
++                      break;
++              case FQ_TYPE_RX_ERROR:
++                      str = "Rx error";
++                      break;
++              case FQ_TYPE_RX_PCD:
++                      str = "Rx PCD";
++                      break;
++              case FQ_TYPE_TX_CONFIRM:
++                      str = "Tx default confirmation";
++                      break;
++              case FQ_TYPE_TX_CONF_MQ:
++                      str = "Tx confirmation (mq)";
++                      break;
++              case FQ_TYPE_TX_ERROR:
++                      str = "Tx error";
++                      break;
++              case FQ_TYPE_TX:
++                      str = "Tx";
++                      break;
++              case FQ_TYPE_RX_PCD_HI_PRIO:
++                      str ="Rx PCD High Priority";
++                      break;
++              default:
++                      str = "Unknown";
++              }
++
++              if (prev && (abs(fq->fqid - prev->fqid) != 1 ||
++                                      str != prevstr)) {
++                      if (last_fqid == first_fqid)
++                              bytes += sprintf(buf + bytes,
++                                      "%s: %d\n", prevstr, prev->fqid);
++                      else
++                              bytes += sprintf(buf + bytes,
++                                      "%s: %d - %d\n", prevstr,
++                                      first_fqid, last_fqid);
++              }
++
++              if (prev && abs(fq->fqid - prev->fqid) == 1 && str == prevstr)
++                      last_fqid = fq->fqid;
++              else
++                      first_fqid = last_fqid = fq->fqid;
++
++              prev = fq;
++              prevstr = str;
++              i++;
++      }
++
++      if (prev) {
++              if (last_fqid == first_fqid)
++                      bytes += sprintf(buf + bytes, "%s: %d\n", prevstr,
++                                      prev->fqid);
++              else
++                      bytes += sprintf(buf + bytes, "%s: %d - %d\n", prevstr,
++                                      first_fqid, last_fqid);
++      }
++
++      return bytes;
++}
++
++static ssize_t dpaa_eth_show_bpids(struct device *dev,
++              struct device_attribute *attr, char *buf)
++{
++      ssize_t bytes = 0;
++      struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
++      struct dpa_bp *dpa_bp = priv->dpa_bp;
++      int i = 0;
++
++      for (i = 0; i < priv->bp_count; i++)
++              bytes += snprintf(buf + bytes, PAGE_SIZE, "%u\n",
++                              dpa_bp[i].bpid);
++
++      return bytes;
++}
++
++static ssize_t dpaa_eth_show_mac_regs(struct device *dev,
++              struct device_attribute *attr, char *buf)
++{
++      struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
++      struct mac_device *mac_dev = priv->mac_dev;
++      int n = 0;
++
++      if (mac_dev)
++              n = fm_mac_dump_regs(mac_dev, buf, n);
++      else
++              return sprintf(buf, "no mac registers\n");
++
++      return n;
++}
++
++static ssize_t dpaa_eth_show_mac_rx_stats(struct device *dev,
++              struct device_attribute *attr, char *buf)
++{
++      struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
++      struct mac_device *mac_dev = priv->mac_dev;
++      int n = 0;
++
++      if (mac_dev)
++              n = fm_mac_dump_rx_stats(mac_dev, buf, n);
++      else
++              return sprintf(buf, "no mac rx stats\n");
++
++      return n;
++}
++
++static ssize_t dpaa_eth_show_mac_tx_stats(struct device *dev,
++              struct device_attribute *attr, char *buf)
++{
++      struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
++      struct mac_device *mac_dev = priv->mac_dev;
++      int n = 0;
++
++      if (mac_dev)
++              n = fm_mac_dump_tx_stats(mac_dev, buf, n);
++      else
++              return sprintf(buf, "no mac tx stats\n");
++
++      return n;
++}
++
++#ifdef CONFIG_FSL_DPAA_1588
++static ssize_t dpaa_eth_show_ptp_1588(struct device *dev,
++                      struct device_attribute *attr, char *buf)
++{
++      struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
++
++      if (priv->tsu && priv->tsu->valid)
++              return sprintf(buf, "1\n");
++      else
++              return sprintf(buf, "0\n");
++}
++
++static ssize_t dpaa_eth_set_ptp_1588(struct device *dev,
++                                      struct device_attribute *attr,
++                                      const char *buf, size_t count)
++{
++      struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
++      unsigned int num;
++      unsigned long flags;
++
++      if (kstrtouint(buf, 0, &num) < 0)
++              return -EINVAL;
++
++      local_irq_save(flags);
++
++      if (num) {
++              if (priv->tsu)
++                      priv->tsu->valid = TRUE;
++      } else {
++              if (priv->tsu)
++                      priv->tsu->valid = FALSE;
++      }
++
++      local_irq_restore(flags);
++
++      return count;
++}
++#endif
++
++static struct device_attribute dpaa_eth_attrs[] = {
++      __ATTR(device_addr, S_IRUGO, dpaa_eth_show_addr, NULL),
++      __ATTR(device_type, S_IRUGO, dpaa_eth_show_type, NULL),
++      __ATTR(fqids, S_IRUGO, dpaa_eth_show_fqids, NULL),
++      __ATTR(bpids, S_IRUGO, dpaa_eth_show_bpids, NULL),
++      __ATTR(mac_regs, S_IRUGO, dpaa_eth_show_mac_regs, NULL),
++      __ATTR(mac_rx_stats, S_IRUGO, dpaa_eth_show_mac_rx_stats, NULL),
++      __ATTR(mac_tx_stats, S_IRUGO, dpaa_eth_show_mac_tx_stats, NULL),
++#ifdef CONFIG_FSL_DPAA_1588
++      __ATTR(ptp_1588, S_IRUGO | S_IWUSR, dpaa_eth_show_ptp_1588,
++                                      dpaa_eth_set_ptp_1588),
++#endif
++};
++
++void dpaa_eth_sysfs_init(struct device *dev)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(dpaa_eth_attrs); i++)
++              if (device_create_file(dev, &dpaa_eth_attrs[i])) {
++                      dev_err(dev, "Error creating sysfs file\n");
++                      while (i > 0)
++                              device_remove_file(dev, &dpaa_eth_attrs[--i]);
++                      return;
++              }
++}
++EXPORT_SYMBOL(dpaa_eth_sysfs_init);
++
++void dpaa_eth_sysfs_remove(struct device *dev)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(dpaa_eth_attrs); i++)
++              device_remove_file(dev, &dpaa_eth_attrs[i]);
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_trace.h
+@@ -0,0 +1,144 @@
++/* Copyright 2013 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#undef TRACE_SYSTEM
++#define TRACE_SYSTEM  dpaa_eth
++
++#if !defined(_DPAA_ETH_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
++#define _DPAA_ETH_TRACE_H
++
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include "dpaa_eth.h"
++#include <linux/tracepoint.h>
++
++#define fd_format_name(format)        { qm_fd_##format, #format }
++#define fd_format_list        \
++      fd_format_name(contig), \
++      fd_format_name(sg)
++#define TR_FMT "[%s] fqid=%d, fd: addr=0x%llx, format=%s, off=%u, len=%u," \
++      " status=0x%08x"
++
++/* This is used to declare a class of events.
++ * individual events of this type will be defined below.
++ */
++
++/* Store details about a frame descriptor and the FQ on which it was
++ * transmitted/received.
++ */
++DECLARE_EVENT_CLASS(dpaa_eth_fd,
++      /* Trace function prototype */
++      TP_PROTO(struct net_device *netdev,
++               struct qman_fq *fq,
++               const struct qm_fd *fd),
++
++      /* Repeat argument list here */
++      TP_ARGS(netdev, fq, fd),
++
++      /* A structure containing the relevant information we want to record.
++       * Declare name and type for each normal element, name, type and size
++       * for arrays. Use __string for variable length strings.
++       */
++      TP_STRUCT__entry(
++              __field(u32,    fqid)
++              __field(u64,    fd_addr)
++              __field(u8,     fd_format)
++              __field(u16,    fd_offset)
++              __field(u32,    fd_length)
++              __field(u32,    fd_status)
++              __string(name,  netdev->name)
++      ),
++
++      /* The function that assigns values to the above declared fields */
++      TP_fast_assign(
++              __entry->fqid = fq->fqid;
++              __entry->fd_addr = qm_fd_addr_get64(fd);
++              __entry->fd_format = fd->format;
++              __entry->fd_offset = dpa_fd_offset(fd);
++              __entry->fd_length = dpa_fd_length(fd);
++              __entry->fd_status = fd->status;
++              __assign_str(name, netdev->name);
++      ),
++
++      /* This is what gets printed when the trace event is triggered */
++      /* TODO: print the status using __print_flags() */
++      TP_printk(TR_FMT,
++                __get_str(name), __entry->fqid, __entry->fd_addr,
++                __print_symbolic(__entry->fd_format, fd_format_list),
++                __entry->fd_offset, __entry->fd_length, __entry->fd_status)
++);
++
++/* Now declare events of the above type. Format is:
++ * DEFINE_EVENT(class, name, proto, args), with proto and args same as for class
++ */
++
++/* Tx (egress) fd */
++DEFINE_EVENT(dpaa_eth_fd, dpa_tx_fd,
++
++      TP_PROTO(struct net_device *netdev,
++               struct qman_fq *fq,
++               const struct qm_fd *fd),
++
++      TP_ARGS(netdev, fq, fd)
++);
++
++/* Rx fd */
++DEFINE_EVENT(dpaa_eth_fd, dpa_rx_fd,
++
++      TP_PROTO(struct net_device *netdev,
++               struct qman_fq *fq,
++               const struct qm_fd *fd),
++
++      TP_ARGS(netdev, fq, fd)
++);
++
++/* Tx confirmation fd */
++DEFINE_EVENT(dpaa_eth_fd, dpa_tx_conf_fd,
++
++      TP_PROTO(struct net_device *netdev,
++               struct qman_fq *fq,
++               const struct qm_fd *fd),
++
++      TP_ARGS(netdev, fq, fd)
++);
++
++/* If only one event of a certain type needs to be declared, use TRACE_EVENT().
++ * The syntax is the same as for DECLARE_EVENT_CLASS().
++ */
++
++#endif /* _DPAA_ETH_TRACE_H */
++
++/* This must be outside ifdef _DPAA_ETH_TRACE_H */
++#undef TRACE_INCLUDE_PATH
++#define TRACE_INCLUDE_PATH .
++#undef TRACE_INCLUDE_FILE
++#define TRACE_INCLUDE_FILE    dpaa_eth_trace
++#include <trace/define_trace.h>
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c
+@@ -0,0 +1,544 @@
++/* Copyright 2008-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
++      KBUILD_BASENAME".c", __LINE__, __func__
++#else
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": " fmt
++#endif
++
++#include <linux/string.h>
++
++#include "dpaa_eth.h"
++#include "mac.h"                /* struct mac_device */
++#include "dpaa_eth_common.h"
++
++static const char dpa_stats_percpu[][ETH_GSTRING_LEN] = {
++      "interrupts",
++      "rx packets",
++      "tx packets",
++      "tx recycled",
++      "tx confirm",
++      "tx S/G",
++      "rx S/G",
++      "tx error",
++      "rx error",
++      "bp count"
++};
++
++static char dpa_stats_global[][ETH_GSTRING_LEN] = {
++      /* dpa rx errors */
++      "rx dma error",
++      "rx frame physical error",
++      "rx frame size error",
++      "rx header error",
++      "rx csum error",
++
++      /* demultiplexing errors */
++      "qman cg_tdrop",
++      "qman wred",
++      "qman error cond",
++      "qman early window",
++      "qman late window",
++      "qman fq tdrop",
++      "qman fq retired",
++      "qman orp disabled",
++
++      /* congestion related stats */
++      "congestion time (ms)",
++      "entered congestion",
++      "congested (0/1)"
++};
++
++#define DPA_STATS_PERCPU_LEN ARRAY_SIZE(dpa_stats_percpu)
++#define DPA_STATS_GLOBAL_LEN ARRAY_SIZE(dpa_stats_global)
++
++static int __cold dpa_get_settings(struct net_device *net_dev,
++              struct ethtool_cmd *et_cmd)
++{
++      int                      _errno;
++      struct dpa_priv_s       *priv;
++
++      priv = netdev_priv(net_dev);
++
++      if (priv->mac_dev == NULL) {
++              netdev_info(net_dev, "This is a MAC-less interface\n");
++              return -ENODEV;
++      }
++      if (unlikely(priv->mac_dev->phy_dev == NULL)) {
++              netdev_dbg(net_dev, "phy device not initialized\n");
++              return 0;
++      }
++
++      _errno = phy_ethtool_gset(priv->mac_dev->phy_dev, et_cmd);
++      if (unlikely(_errno < 0))
++              netdev_err(net_dev, "phy_ethtool_gset() = %d\n", _errno);
++
++      return _errno;
++}
++
++static int __cold dpa_set_settings(struct net_device *net_dev,
++              struct ethtool_cmd *et_cmd)
++{
++      int                      _errno;
++      struct dpa_priv_s       *priv;
++
++      priv = netdev_priv(net_dev);
++
++      if (priv->mac_dev == NULL) {
++              netdev_info(net_dev, "This is a MAC-less interface\n");
++              return -ENODEV;
++      }
++      if (unlikely(priv->mac_dev->phy_dev == NULL)) {
++              netdev_err(net_dev, "phy device not initialized\n");
++              return -ENODEV;
++      }
++
++      _errno = phy_ethtool_sset(priv->mac_dev->phy_dev, et_cmd);
++      if (unlikely(_errno < 0))
++              netdev_err(net_dev, "phy_ethtool_sset() = %d\n", _errno);
++
++      return _errno;
++}
++
++static void __cold dpa_get_drvinfo(struct net_device *net_dev,
++              struct ethtool_drvinfo *drvinfo)
++{
++      int              _errno;
++
++      strncpy(drvinfo->driver, KBUILD_MODNAME,
++              sizeof(drvinfo->driver) - 1)[sizeof(drvinfo->driver)-1] = 0;
++      _errno = snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
++                        "%X", 0);
++
++      if (unlikely(_errno >= sizeof(drvinfo->fw_version))) {
++              /* Truncated output */
++              netdev_notice(net_dev, "snprintf() = %d\n", _errno);
++      } else if (unlikely(_errno < 0)) {
++              netdev_warn(net_dev, "snprintf() = %d\n", _errno);
++              memset(drvinfo->fw_version, 0, sizeof(drvinfo->fw_version));
++      }
++      strncpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent),
++              sizeof(drvinfo->bus_info)-1)[sizeof(drvinfo->bus_info)-1] = 0;
++}
++
++static uint32_t __cold dpa_get_msglevel(struct net_device *net_dev)
++{
++      return ((struct dpa_priv_s *)netdev_priv(net_dev))->msg_enable;
++}
++
++static void __cold dpa_set_msglevel(struct net_device *net_dev,
++              uint32_t msg_enable)
++{
++      ((struct dpa_priv_s *)netdev_priv(net_dev))->msg_enable = msg_enable;
++}
++
++static int __cold dpa_nway_reset(struct net_device *net_dev)
++{
++      int                      _errno;
++      struct dpa_priv_s       *priv;
++
++      priv = netdev_priv(net_dev);
++
++      if (priv->mac_dev == NULL) {
++              netdev_info(net_dev, "This is a MAC-less interface\n");
++              return -ENODEV;
++      }
++      if (unlikely(priv->mac_dev->phy_dev == NULL)) {
++              netdev_err(net_dev, "phy device not initialized\n");
++              return -ENODEV;
++      }
++
++      _errno = 0;
++      if (priv->mac_dev->phy_dev->autoneg) {
++              _errno = phy_start_aneg(priv->mac_dev->phy_dev);
++              if (unlikely(_errno < 0))
++                      netdev_err(net_dev, "phy_start_aneg() = %d\n",
++                                      _errno);
++      }
++
++      return _errno;
++}
++
++static void __cold dpa_get_pauseparam(struct net_device *net_dev,
++              struct ethtool_pauseparam *epause)
++{
++      struct dpa_priv_s       *priv;
++      struct mac_device       *mac_dev;
++      struct phy_device       *phy_dev;
++
++      priv = netdev_priv(net_dev);
++      mac_dev = priv->mac_dev;
++
++      if (mac_dev == NULL) {
++              netdev_info(net_dev, "This is a MAC-less interface\n");
++              return;
++      }
++
++      phy_dev = mac_dev->phy_dev;
++      if (unlikely(phy_dev == NULL)) {
++              netdev_err(net_dev, "phy device not initialized\n");
++              return;
++      }
++
++      epause->autoneg = mac_dev->autoneg_pause;
++      epause->rx_pause = mac_dev->rx_pause_active;
++      epause->tx_pause = mac_dev->tx_pause_active;
++}
++
++static int __cold dpa_set_pauseparam(struct net_device *net_dev,
++              struct ethtool_pauseparam *epause)
++{
++      struct dpa_priv_s       *priv;
++      struct mac_device       *mac_dev;
++      struct phy_device       *phy_dev;
++      int _errno;
++      u32 newadv, oldadv;
++      bool rx_pause, tx_pause;
++
++      priv = netdev_priv(net_dev);
++      mac_dev = priv->mac_dev;
++
++      if (mac_dev == NULL) {
++              netdev_info(net_dev, "This is a MAC-less interface\n");
++              return -ENODEV;
++      }
++
++      phy_dev = mac_dev->phy_dev;
++      if (unlikely(phy_dev == NULL)) {
++              netdev_err(net_dev, "phy device not initialized\n");
++              return -ENODEV;
++      }
++
++      if (!(phy_dev->supported & SUPPORTED_Pause) ||
++                      (!(phy_dev->supported & SUPPORTED_Asym_Pause) &&
++                      (epause->rx_pause != epause->tx_pause)))
++              return -EINVAL;
++
++      /* The MAC should know how to handle PAUSE frame autonegotiation before
++       * adjust_link is triggered by a forced renegotiation of sym/asym PAUSE
++       * settings.
++       */
++      mac_dev->autoneg_pause = !!epause->autoneg;
++      mac_dev->rx_pause_req = !!epause->rx_pause;
++      mac_dev->tx_pause_req = !!epause->tx_pause;
++
++      /* Determine the sym/asym advertised PAUSE capabilities from the desired
++       * rx/tx pause settings.
++       */
++      newadv = 0;
++      if (epause->rx_pause)
++              newadv = ADVERTISED_Pause | ADVERTISED_Asym_Pause;
++      if (epause->tx_pause)
++              newadv |= ADVERTISED_Asym_Pause;
++
++      oldadv = phy_dev->advertising &
++                      (ADVERTISED_Pause | ADVERTISED_Asym_Pause);
++
++      /* If there are differences between the old and the new advertised
++       * values, restart PHY autonegotiation and advertise the new values.
++       */
++      if (oldadv != newadv) {
++              phy_dev->advertising &= ~(ADVERTISED_Pause
++                              | ADVERTISED_Asym_Pause);
++              phy_dev->advertising |= newadv;
++              if (phy_dev->autoneg) {
++                      _errno = phy_start_aneg(phy_dev);
++                      if (unlikely(_errno < 0))
++                              netdev_err(net_dev, "phy_start_aneg() = %d\n",
++                                              _errno);
++              }
++      }
++
++      get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
++      _errno = set_mac_active_pause(mac_dev, rx_pause, tx_pause);
++      if (unlikely(_errno < 0))
++              netdev_err(net_dev, "set_mac_active_pause() = %d\n", _errno);
++
++      return _errno;
++}
++
++#ifdef CONFIG_PM
++static void dpa_get_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol)
++{
++      struct dpa_priv_s *priv = netdev_priv(net_dev);
++
++      wol->supported = 0;
++      wol->wolopts = 0;
++
++      if (!priv->wol || !device_can_wakeup(net_dev->dev.parent))
++              return;
++
++      if (priv->wol & DPAA_WOL_MAGIC) {
++              wol->supported = WAKE_MAGIC;
++              wol->wolopts = WAKE_MAGIC;
++      }
++}
++
++static int dpa_set_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol)
++{
++      struct dpa_priv_s *priv = netdev_priv(net_dev);
++
++      if (priv->mac_dev == NULL) {
++              netdev_info(net_dev, "This is a MAC-less interface\n");
++              return -ENODEV;
++      }
++
++      if (unlikely(priv->mac_dev->phy_dev == NULL)) {
++              netdev_dbg(net_dev, "phy device not initialized\n");
++              return -ENODEV;
++      }
++
++      if (!device_can_wakeup(net_dev->dev.parent) ||
++              (wol->wolopts & ~WAKE_MAGIC))
++              return -EOPNOTSUPP;
++
++      priv->wol = 0;
++
++      if (wol->wolopts & WAKE_MAGIC) {
++              priv->wol = DPAA_WOL_MAGIC;
++              device_set_wakeup_enable(net_dev->dev.parent, 1);
++      } else {
++              device_set_wakeup_enable(net_dev->dev.parent, 0);
++      }
++
++      return 0;
++}
++#endif
++
++static int dpa_get_eee(struct net_device *net_dev, struct ethtool_eee *et_eee)
++{
++      struct dpa_priv_s *priv;
++
++      priv = netdev_priv(net_dev);
++      if (priv->mac_dev == NULL) {
++              netdev_info(net_dev, "This is a MAC-less interface\n");
++              return -ENODEV;
++      }
++
++      if (unlikely(priv->mac_dev->phy_dev == NULL)) {
++              netdev_err(net_dev, "phy device not initialized\n");
++              return -ENODEV;
++      }
++
++      return phy_ethtool_get_eee(priv->mac_dev->phy_dev, et_eee);
++}
++
++static int dpa_set_eee(struct net_device *net_dev, struct ethtool_eee *et_eee)
++{
++      struct dpa_priv_s *priv;
++
++      priv = netdev_priv(net_dev);
++      if (priv->mac_dev == NULL) {
++              netdev_info(net_dev, "This is a MAC-less interface\n");
++              return -ENODEV;
++      }
++
++      if (unlikely(priv->mac_dev->phy_dev == NULL)) {
++              netdev_err(net_dev, "phy device not initialized\n");
++              return -ENODEV;
++      }
++
++      return phy_ethtool_set_eee(priv->mac_dev->phy_dev, et_eee);
++}
++
++static int dpa_get_sset_count(struct net_device *net_dev, int type)
++{
++      unsigned int total_stats, num_stats;
++
++      num_stats   = num_online_cpus() + 1;
++      total_stats = num_stats * DPA_STATS_PERCPU_LEN + DPA_STATS_GLOBAL_LEN;
++
++      switch (type) {
++      case ETH_SS_STATS:
++              return total_stats;
++      default:
++              return -EOPNOTSUPP;
++      }
++}
++
++static void copy_stats(struct dpa_percpu_priv_s *percpu_priv, int num_cpus,
++                      int crr_cpu, u64 bp_count, u64 *data)
++{
++      int num_stat_values = num_cpus + 1;
++      int crr_stat = 0;
++
++      /* update current CPU's stats and also add them to the total values */
++      data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->in_interrupt;
++      data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->in_interrupt;
++
++      data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->stats.rx_packets;
++      data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->stats.rx_packets;
++
++      data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->stats.tx_packets;
++      data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->stats.tx_packets;
++
++      data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->tx_returned;
++      data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->tx_returned;
++
++      data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->tx_confirm;
++      data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->tx_confirm;
++
++      data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->tx_frag_skbuffs;
++      data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->tx_frag_skbuffs;
++
++      data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->rx_sg;
++      data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->rx_sg;
++
++      data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->stats.tx_errors;
++      data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->stats.tx_errors;
++
++      data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->stats.rx_errors;
++      data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->stats.rx_errors;
++
++      data[crr_stat * num_stat_values + crr_cpu] = bp_count;
++      data[crr_stat++ * num_stat_values + num_cpus] += bp_count;
++}
++
++static void dpa_get_ethtool_stats(struct net_device *net_dev,
++              struct ethtool_stats *stats, u64 *data)
++{
++      u64 bp_count, cg_time, cg_num, cg_status;
++      struct dpa_percpu_priv_s *percpu_priv;
++      struct qm_mcr_querycgr query_cgr;
++      struct dpa_rx_errors rx_errors;
++      struct dpa_ern_cnt ern_cnt;
++      struct dpa_priv_s *priv;
++      unsigned int num_cpus, offset;
++      struct dpa_bp *dpa_bp;
++      int total_stats, i;
++
++      total_stats = dpa_get_sset_count(net_dev, ETH_SS_STATS);
++      priv     = netdev_priv(net_dev);
++      dpa_bp   = priv->dpa_bp;
++      num_cpus = num_online_cpus();
++      bp_count = 0;
++
++      memset(&rx_errors, 0, sizeof(struct dpa_rx_errors));
++      memset(&ern_cnt, 0, sizeof(struct dpa_ern_cnt));
++      memset(data, 0, total_stats * sizeof(u64));
++
++      for_each_online_cpu(i) {
++              percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
++
++              if (dpa_bp->percpu_count)
++                      bp_count = *(per_cpu_ptr(dpa_bp->percpu_count, i));
++
++              rx_errors.dme += percpu_priv->rx_errors.dme;
++              rx_errors.fpe += percpu_priv->rx_errors.fpe;
++              rx_errors.fse += percpu_priv->rx_errors.fse;
++              rx_errors.phe += percpu_priv->rx_errors.phe;
++              rx_errors.cse += percpu_priv->rx_errors.cse;
++
++              ern_cnt.cg_tdrop     += percpu_priv->ern_cnt.cg_tdrop;
++              ern_cnt.wred         += percpu_priv->ern_cnt.wred;
++              ern_cnt.err_cond     += percpu_priv->ern_cnt.err_cond;
++              ern_cnt.early_window += percpu_priv->ern_cnt.early_window;
++              ern_cnt.late_window  += percpu_priv->ern_cnt.late_window;
++              ern_cnt.fq_tdrop     += percpu_priv->ern_cnt.fq_tdrop;
++              ern_cnt.fq_retired   += percpu_priv->ern_cnt.fq_retired;
++              ern_cnt.orp_zero     += percpu_priv->ern_cnt.orp_zero;
++
++              copy_stats(percpu_priv, num_cpus, i, bp_count, data);
++      }
++
++      offset = (num_cpus + 1) * DPA_STATS_PERCPU_LEN;
++      memcpy(data + offset, &rx_errors, sizeof(struct dpa_rx_errors));
++
++      offset += sizeof(struct dpa_rx_errors) / sizeof(u64);
++      memcpy(data + offset, &ern_cnt, sizeof(struct dpa_ern_cnt));
++
++      /* gather congestion related counters */
++      cg_num    = 0;
++      cg_status = 0;
++      cg_time   = jiffies_to_msecs(priv->cgr_data.congested_jiffies);
++      if (qman_query_cgr(&priv->cgr_data.cgr, &query_cgr) == 0) {
++              cg_num    = priv->cgr_data.cgr_congested_count;
++              cg_status = query_cgr.cgr.cs;
++
++              /* reset congestion stats (like QMan API does */
++              priv->cgr_data.congested_jiffies   = 0;
++              priv->cgr_data.cgr_congested_count = 0;
++      }
++
++      offset += sizeof(struct dpa_ern_cnt) / sizeof(u64);
++      data[offset++] = cg_time;
++      data[offset++] = cg_num;
++      data[offset++] = cg_status;
++}
++
++static void dpa_get_strings(struct net_device *net_dev, u32 stringset, u8 *data)
++{
++      unsigned int i, j, num_cpus, size;
++      char stat_string_cpu[ETH_GSTRING_LEN];
++      u8 *strings;
++
++      strings   = data;
++      num_cpus  = num_online_cpus();
++      size      = DPA_STATS_GLOBAL_LEN * ETH_GSTRING_LEN;
++
++      for (i = 0; i < DPA_STATS_PERCPU_LEN; i++) {
++              for (j = 0; j < num_cpus; j++) {
++                      snprintf(stat_string_cpu, ETH_GSTRING_LEN, "%s [CPU %d]", dpa_stats_percpu[i], j);
++                      memcpy(strings, stat_string_cpu, ETH_GSTRING_LEN);
++                      strings += ETH_GSTRING_LEN;
++              }
++              snprintf(stat_string_cpu, ETH_GSTRING_LEN, "%s [TOTAL]", dpa_stats_percpu[i]);
++              memcpy(strings, stat_string_cpu, ETH_GSTRING_LEN);
++              strings += ETH_GSTRING_LEN;
++      }
++      memcpy(strings, dpa_stats_global, size);
++}
++
++const struct ethtool_ops dpa_ethtool_ops = {
++      .get_settings = dpa_get_settings,
++      .set_settings = dpa_set_settings,
++      .get_drvinfo = dpa_get_drvinfo,
++      .get_msglevel = dpa_get_msglevel,
++      .set_msglevel = dpa_set_msglevel,
++      .nway_reset = dpa_nway_reset,
++      .get_pauseparam = dpa_get_pauseparam,
++      .set_pauseparam = dpa_set_pauseparam,
++      .self_test = NULL, /* TODO invoke the cold-boot unit-test? */
++      .get_link = ethtool_op_get_link,
++      .get_eee = dpa_get_eee,
++      .set_eee = dpa_set_eee,
++      .get_sset_count = dpa_get_sset_count,
++      .get_ethtool_stats = dpa_get_ethtool_stats,
++      .get_strings = dpa_get_strings,
++#ifdef CONFIG_PM
++      .get_wol = dpa_get_wol,
++      .set_wol = dpa_set_wol,
++#endif
++};
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ptp.c
+@@ -0,0 +1,290 @@
++/*
++ * DPAA Ethernet Driver -- PTP 1588 clock using the dTSEC
++ *
++ * Author: Yangbo Lu <yangbo.lu@freescale.com>
++ *
++ * Copyright 2014 Freescale Semiconductor, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++*/
++
++#include <linux/device.h>
++#include <linux/hrtimer.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_platform.h>
++#include <linux/timex.h>
++#include <linux/io.h>
++
++#include <linux/ptp_clock_kernel.h>
++
++#include "dpaa_eth.h"
++#include "mac.h"
++
++struct ptp_clock *clock;
++
++static struct mac_device *mac_dev;
++static u32 freqCompensation;
++
++/* Bit definitions for the TMR_CTRL register */
++#define ALM1P                 (1<<31) /* Alarm1 output polarity */
++#define ALM2P                 (1<<30) /* Alarm2 output polarity */
++#define FS                    (1<<28) /* FIPER start indication */
++#define PP1L                  (1<<27) /* Fiper1 pulse loopback mode enabled. */
++#define PP2L                  (1<<26) /* Fiper2 pulse loopback mode enabled. */
++#define TCLK_PERIOD_SHIFT     (16) /* 1588 timer reference clock period. */
++#define TCLK_PERIOD_MASK      (0x3ff)
++#define RTPE                  (1<<15) /* Record Tx Timestamp to PAL Enable. */
++#define FRD                   (1<<14) /* FIPER Realignment Disable */
++#define ESFDP                 (1<<11) /* External Tx/Rx SFD Polarity. */
++#define ESFDE                 (1<<10) /* External Tx/Rx SFD Enable. */
++#define ETEP2                 (1<<9) /* External trigger 2 edge polarity */
++#define ETEP1                 (1<<8) /* External trigger 1 edge polarity */
++#define COPH                  (1<<7) /* Generated clock output phase. */
++#define CIPH                  (1<<6) /* External oscillator input clock phase */
++#define TMSR                  (1<<5) /* Timer soft reset. */
++#define BYP                   (1<<3) /* Bypass drift compensated clock */
++#define TE                    (1<<2) /* 1588 timer enable. */
++#define CKSEL_SHIFT           (0)    /* 1588 Timer reference clock source */
++#define CKSEL_MASK            (0x3)
++
++/* Bit definitions for the TMR_TEVENT register */
++#define ETS2                  (1<<25) /* External trigger 2 timestamp sampled */
++#define ETS1                  (1<<24) /* External trigger 1 timestamp sampled */
++#define ALM2                  (1<<17) /* Current time = alarm time register 2 */
++#define ALM1                  (1<<16) /* Current time = alarm time register 1 */
++#define PP1                   (1<<7)  /* periodic pulse generated on FIPER1 */
++#define PP2                   (1<<6)  /* periodic pulse generated on FIPER2 */
++#define PP3                   (1<<5)  /* periodic pulse generated on FIPER3 */
++
++/* Bit definitions for the TMR_TEMASK register */
++#define ETS2EN                (1<<25) /* External trigger 2 timestamp enable */
++#define ETS1EN                (1<<24) /* External trigger 1 timestamp enable */
++#define ALM2EN                (1<<17) /* Timer ALM2 event enable */
++#define ALM1EN                (1<<16) /* Timer ALM1 event enable */
++#define PP1EN                 (1<<7) /* Periodic pulse event 1 enable */
++#define PP2EN                 (1<<6) /* Periodic pulse event 2 enable */
++
++/* Bit definitions for the TMR_PEVENT register */
++#define TXP2                  (1<<9) /* PTP transmitted timestamp im TXTS2 */
++#define TXP1                  (1<<8) /* PTP transmitted timestamp in TXTS1 */
++#define RXP                   (1<<0) /* PTP frame has been received */
++
++/* Bit definitions for the TMR_PEMASK register */
++#define TXP2EN                (1<<9) /* Transmit PTP packet event 2 enable */
++#define TXP1EN                (1<<8) /* Transmit PTP packet event 1 enable */
++#define RXPEN                 (1<<0) /* Receive PTP packet event enable */
++
++/* Bit definitions for the TMR_STAT register */
++#define STAT_VEC_SHIFT        (0) /* Timer general purpose status vector */
++#define STAT_VEC_MASK         (0x3f)
++
++/* Bit definitions for the TMR_PRSC register */
++#define PRSC_OCK_SHIFT        (0) /* Output clock division/prescale factor. */
++#define PRSC_OCK_MASK         (0xffff)
++
++
++#define N_EXT_TS      2
++
++static void set_alarm(void)
++{
++      u64 ns;
++
++      if (mac_dev->fm_rtc_get_cnt)
++              mac_dev->fm_rtc_get_cnt(mac_dev->fm_dev, &ns);
++      ns += 1500000000ULL;
++      ns = div_u64(ns, 1000000000UL) * 1000000000ULL;
++      ns -= DPA_PTP_NOMINAL_FREQ_PERIOD_NS;
++      if (mac_dev->fm_rtc_set_alarm)
++              mac_dev->fm_rtc_set_alarm(mac_dev->fm_dev, 0, ns);
++}
++
++static void set_fipers(void)
++{
++      u64 fiper;
++
++      if (mac_dev->fm_rtc_disable)
++              mac_dev->fm_rtc_disable(mac_dev->fm_dev);
++
++      set_alarm();
++      fiper = 1000000000ULL - DPA_PTP_NOMINAL_FREQ_PERIOD_NS;
++      if (mac_dev->fm_rtc_set_fiper)
++              mac_dev->fm_rtc_set_fiper(mac_dev->fm_dev, 0, fiper);
++
++      if (mac_dev->fm_rtc_enable)
++              mac_dev->fm_rtc_enable(mac_dev->fm_dev);
++}
++
++/* PTP clock operations */
++
++static int ptp_dpa_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
++{
++      u64 adj;
++      u32 diff, tmr_add;
++      int neg_adj = 0;
++
++      if (ppb < 0) {
++              neg_adj = 1;
++              ppb = -ppb;
++      }
++
++      tmr_add = freqCompensation;
++      adj = tmr_add;
++      adj *= ppb;
++      diff = div_u64(adj, 1000000000ULL);
++
++      tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff;
++
++      if (mac_dev->fm_rtc_set_drift)
++              mac_dev->fm_rtc_set_drift(mac_dev->fm_dev, tmr_add);
++
++      return 0;
++}
++
++static int ptp_dpa_adjtime(struct ptp_clock_info *ptp, s64 delta)
++{
++      s64 now;
++
++      if (mac_dev->fm_rtc_get_cnt)
++              mac_dev->fm_rtc_get_cnt(mac_dev->fm_dev, &now);
++
++      now += delta;
++
++      if (mac_dev->fm_rtc_set_cnt)
++              mac_dev->fm_rtc_set_cnt(mac_dev->fm_dev, now);
++      set_fipers();
++
++      return 0;
++}
++
++static int ptp_dpa_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
++{
++      u64 ns;
++      u32 remainder;
++
++      if (mac_dev->fm_rtc_get_cnt)
++              mac_dev->fm_rtc_get_cnt(mac_dev->fm_dev, &ns);
++
++      ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
++      ts->tv_nsec = remainder;
++      return 0;
++}
++
++static int ptp_dpa_settime(struct ptp_clock_info *ptp,
++                             const struct timespec64 *ts)
++{
++      u64 ns;
++
++      ns = ts->tv_sec * 1000000000ULL;
++      ns += ts->tv_nsec;
++
++      if (mac_dev->fm_rtc_set_cnt)
++              mac_dev->fm_rtc_set_cnt(mac_dev->fm_dev, ns);
++      set_fipers();
++      return 0;
++}
++
++static int ptp_dpa_enable(struct ptp_clock_info *ptp,
++                            struct ptp_clock_request *rq, int on)
++{
++      u32 bit;
++
++      switch (rq->type) {
++      case PTP_CLK_REQ_EXTTS:
++              switch (rq->extts.index) {
++              case 0:
++                      bit = ETS1EN;
++                      break;
++              case 1:
++                      bit = ETS2EN;
++                      break;
++              default:
++                      return -EINVAL;
++              }
++              if (on) {
++                      if (mac_dev->fm_rtc_enable_interrupt)
++                              mac_dev->fm_rtc_enable_interrupt(
++                                      mac_dev->fm_dev, bit);
++              } else {
++                      if (mac_dev->fm_rtc_disable_interrupt)
++                              mac_dev->fm_rtc_disable_interrupt(
++                                      mac_dev->fm_dev, bit);
++              }
++              return 0;
++
++      case PTP_CLK_REQ_PPS:
++              if (on) {
++                      if (mac_dev->fm_rtc_enable_interrupt)
++                              mac_dev->fm_rtc_enable_interrupt(
++                                      mac_dev->fm_dev, PP1EN);
++              } else {
++                      if (mac_dev->fm_rtc_disable_interrupt)
++                              mac_dev->fm_rtc_disable_interrupt(
++                                      mac_dev->fm_dev, PP1EN);
++              }
++              return 0;
++
++      default:
++              break;
++      }
++
++      return -EOPNOTSUPP;
++}
++
++static struct ptp_clock_info ptp_dpa_caps = {
++      .owner          = THIS_MODULE,
++      .name           = "dpaa clock",
++      .max_adj        = 512000,
++      .n_alarm        = 0,
++      .n_ext_ts       = N_EXT_TS,
++      .n_per_out      = 0,
++      .pps            = 1,
++      .adjfreq        = ptp_dpa_adjfreq,
++      .adjtime        = ptp_dpa_adjtime,
++      .gettime64      = ptp_dpa_gettime,
++      .settime64      = ptp_dpa_settime,
++      .enable         = ptp_dpa_enable,
++};
++
++static int __init __cold dpa_ptp_load(void)
++{
++      struct device *ptp_dev;
++      struct timespec64 now;
++      int dpa_phc_index;
++      int err;
++
++      if (!(ptp_priv.of_dev && ptp_priv.mac_dev))
++              return -ENODEV;
++
++      ptp_dev = &ptp_priv.of_dev->dev;
++      mac_dev = ptp_priv.mac_dev;
++
++      if (mac_dev->fm_rtc_get_drift)
++              mac_dev->fm_rtc_get_drift(mac_dev->fm_dev, &freqCompensation);
++
++      getnstimeofday64(&now);
++      ptp_dpa_settime(&ptp_dpa_caps, &now);
++
++      clock = ptp_clock_register(&ptp_dpa_caps, ptp_dev);
++      if (IS_ERR(clock)) {
++              err = PTR_ERR(clock);
++              return err;
++      }
++      dpa_phc_index = ptp_clock_index(clock);
++      return 0;
++}
++module_init(dpa_ptp_load);
++
++static void __exit __cold dpa_ptp_unload(void)
++{
++      if (mac_dev->fm_rtc_disable_interrupt)
++              mac_dev->fm_rtc_disable_interrupt(mac_dev->fm_dev, 0xffffffff);
++      ptp_clock_unregister(clock);
++}
++module_exit(dpa_ptp_unload);
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c
+@@ -0,0 +1,909 @@
++/* Copyright 2008-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
++      KBUILD_BASENAME".c", __LINE__, __func__
++#else
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": " fmt
++#endif
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/of_platform.h>
++#include <linux/of_mdio.h>
++#include <linux/phy.h>
++#include <linux/netdevice.h>
++
++#include "dpaa_eth.h"
++#include "mac.h"
++#include "lnxwrp_fsl_fman.h"
++
++#include "error_ext.h"        /* GET_ERROR_TYPE, E_OK */
++
++#include "fsl_fman_dtsec.h"
++#include "fsl_fman_tgec.h"
++#include "fsl_fman_memac.h"
++#include "../sdk_fman/src/wrapper/lnxwrp_sysfs_fm.h"
++
++#define MAC_DESCRIPTION "FSL FMan MAC API based driver"
++
++MODULE_LICENSE("Dual BSD/GPL");
++
++MODULE_AUTHOR("Emil Medve <Emilian.Medve@Freescale.com>");
++
++MODULE_DESCRIPTION(MAC_DESCRIPTION);
++
++struct mac_priv_s {
++      struct fm_mac_dev *fm_mac;
++};
++
++const char    *mac_driver_description __initconst = MAC_DESCRIPTION;
++const size_t   mac_sizeof_priv[] = {
++      [DTSEC] = sizeof(struct mac_priv_s),
++      [XGMAC] = sizeof(struct mac_priv_s),
++      [MEMAC] = sizeof(struct mac_priv_s)
++};
++
++static const enet_mode_t _100[] = {
++      [PHY_INTERFACE_MODE_MII]        = e_ENET_MODE_MII_100,
++      [PHY_INTERFACE_MODE_RMII]       = e_ENET_MODE_RMII_100
++};
++
++static const enet_mode_t _1000[] = {
++      [PHY_INTERFACE_MODE_GMII]       = e_ENET_MODE_GMII_1000,
++      [PHY_INTERFACE_MODE_SGMII]      = e_ENET_MODE_SGMII_1000,
++      [PHY_INTERFACE_MODE_QSGMII]     = e_ENET_MODE_QSGMII_1000,
++      [PHY_INTERFACE_MODE_TBI]        = e_ENET_MODE_TBI_1000,
++      [PHY_INTERFACE_MODE_RGMII]      = e_ENET_MODE_RGMII_1000,
++      [PHY_INTERFACE_MODE_RGMII_ID]   = e_ENET_MODE_RGMII_1000,
++      [PHY_INTERFACE_MODE_RGMII_RXID] = e_ENET_MODE_RGMII_1000,
++      [PHY_INTERFACE_MODE_RGMII_TXID] = e_ENET_MODE_RGMII_1000,
++      [PHY_INTERFACE_MODE_RTBI]       = e_ENET_MODE_RTBI_1000
++};
++
++static enet_mode_t __cold __attribute__((nonnull))
++macdev2enetinterface(const struct mac_device *mac_dev)
++{
++      switch (mac_dev->max_speed) {
++      case SPEED_100:
++              return _100[mac_dev->phy_if];
++      case SPEED_1000:
++              return _1000[mac_dev->phy_if];
++      case SPEED_2500:
++              return e_ENET_MODE_SGMII_2500;
++      case SPEED_10000:
++              return e_ENET_MODE_XGMII_10000;
++      default:
++              return e_ENET_MODE_MII_100;
++      }
++}
++
++static void mac_exception(handle_t _mac_dev, e_FmMacExceptions exception)
++{
++      struct mac_device       *mac_dev;
++
++      mac_dev = (struct mac_device *)_mac_dev;
++
++      if (e_FM_MAC_EX_10G_RX_FIFO_OVFL == exception) {
++              /* don't flag RX FIFO after the first */
++              fm_mac_set_exception(mac_dev->get_mac_handle(mac_dev),
++                  e_FM_MAC_EX_10G_RX_FIFO_OVFL, false);
++              dev_err(mac_dev->dev, "10G MAC got RX FIFO Error = %x\n",
++                              exception);
++      }
++
++      dev_dbg(mac_dev->dev, "%s:%s() -> %d\n", KBUILD_BASENAME".c", __func__,
++              exception);
++}
++
++static int __cold init(struct mac_device *mac_dev)
++{
++      int                                     _errno;
++      struct mac_priv_s       *priv;
++      t_FmMacParams           param;
++      uint32_t                        version;
++
++      priv = macdev_priv(mac_dev);
++
++      param.baseAddr =  (typeof(param.baseAddr))(uintptr_t)devm_ioremap(
++              mac_dev->dev, mac_dev->res->start, 0x2000);
++      param.enetMode  = macdev2enetinterface(mac_dev);
++      memcpy(&param.addr, mac_dev->addr, min(sizeof(param.addr),
++              sizeof(mac_dev->addr)));
++      param.macId             = mac_dev->cell_index;
++      param.h_Fm              = (handle_t)mac_dev->fm;
++      param.mdioIrq           = NO_IRQ;
++      param.f_Exception       = mac_exception;
++      param.f_Event           = mac_exception;
++      param.h_App             = mac_dev;
++
++      priv->fm_mac = fm_mac_config(&param);
++      if (unlikely(priv->fm_mac == NULL)) {
++              _errno = -EINVAL;
++              goto _return;
++      }
++
++      fm_mac_set_handle(mac_dev->fm_dev, priv->fm_mac,
++              (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) ?
++                      param.macId : param.macId + FM_MAX_NUM_OF_1G_MACS);
++
++      _errno = fm_mac_config_max_frame_length(priv->fm_mac,
++                                        fm_get_max_frm());
++      if (unlikely(_errno < 0))
++              goto _return_fm_mac_free;
++
++      if (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) {
++              /* 10G always works with pad and CRC */
++              _errno = fm_mac_config_pad_and_crc(priv->fm_mac, true);
++              if (unlikely(_errno < 0))
++                      goto _return_fm_mac_free;
++
++              _errno = fm_mac_config_half_duplex(priv->fm_mac,
++                              mac_dev->half_duplex);
++              if (unlikely(_errno < 0))
++                      goto _return_fm_mac_free;
++      } else {
++              _errno = fm_mac_config_reset_on_init(priv->fm_mac, true);
++              if (unlikely(_errno < 0))
++                      goto _return_fm_mac_free;
++      }
++
++      _errno = fm_mac_init(priv->fm_mac);
++      if (unlikely(_errno < 0))
++              goto _return_fm_mac_free;
++
++#ifndef CONFIG_FMAN_MIB_CNT_OVF_IRQ_EN
++      /* For 1G MAC, disable by default the MIB counters overflow interrupt */
++      if (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) {
++              _errno = fm_mac_set_exception(mac_dev->get_mac_handle(mac_dev),
++                              e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL, FALSE);
++              if (unlikely(_errno < 0))
++                      goto _return_fm_mac_free;
++      }
++#endif /* !CONFIG_FMAN_MIB_CNT_OVF_IRQ_EN */
++
++      /* For 10G MAC, disable Tx ECC exception */
++      if (macdev2enetinterface(mac_dev) == e_ENET_MODE_XGMII_10000) {
++              _errno = fm_mac_set_exception(mac_dev->get_mac_handle(mac_dev),
++                                        e_FM_MAC_EX_10G_1TX_ECC_ER, FALSE);
++              if (unlikely(_errno < 0))
++                      goto _return_fm_mac_free;
++      }
++
++      _errno = fm_mac_get_version(priv->fm_mac, &version);
++      if (unlikely(_errno < 0))
++              goto _return_fm_mac_free;
++
++      dev_info(mac_dev->dev, "FMan %s version: 0x%08x\n",
++              ((macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) ?
++                      "dTSEC" : "XGEC"), version);
++
++      goto _return;
++
++
++_return_fm_mac_free:
++      fm_mac_free(mac_dev->get_mac_handle(mac_dev));
++
++_return:
++      return _errno;
++}
++
++static int __cold memac_init(struct mac_device *mac_dev)
++{
++      int                     _errno;
++      struct mac_priv_s       *priv;
++      t_FmMacParams           param;
++
++      priv = macdev_priv(mac_dev);
++
++      param.baseAddr =  (typeof(param.baseAddr))(uintptr_t)devm_ioremap(
++              mac_dev->dev, mac_dev->res->start, 0x2000);
++      param.enetMode  = macdev2enetinterface(mac_dev);
++      memcpy(&param.addr, mac_dev->addr, sizeof(mac_dev->addr));
++      param.macId             = mac_dev->cell_index;
++      param.h_Fm              = (handle_t)mac_dev->fm;
++      param.mdioIrq           = NO_IRQ;
++      param.f_Exception       = mac_exception;
++      param.f_Event           = mac_exception;
++      param.h_App             = mac_dev;
++
++      priv->fm_mac = fm_mac_config(&param);
++      if (unlikely(priv->fm_mac == NULL)) {
++              _errno = -EINVAL;
++              goto _return;
++      }
++
++      fm_mac_set_handle(mac_dev->fm_dev, priv->fm_mac,
++              (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) ?
++                      param.macId : param.macId + FM_MAX_NUM_OF_1G_MACS);
++
++      _errno = fm_mac_config_max_frame_length(priv->fm_mac, fm_get_max_frm());
++      if (unlikely(_errno < 0))
++              goto _return_fm_mac_free;
++
++      _errno = fm_mac_config_reset_on_init(priv->fm_mac, true);
++      if (unlikely(_errno < 0))
++              goto _return_fm_mac_free;
++
++      _errno = fm_mac_init(priv->fm_mac);
++      if (unlikely(_errno < 0))
++              goto _return_fm_mac_free;
++
++      dev_info(mac_dev->dev, "FMan MEMAC\n");
++
++      goto _return;
++
++_return_fm_mac_free:
++      fm_mac_free(priv->fm_mac);
++
++_return:
++      return _errno;
++}
++
++static int __cold start(struct mac_device *mac_dev)
++{
++      int      _errno;
++      struct phy_device *phy_dev = mac_dev->phy_dev;
++
++      _errno = fm_mac_enable(mac_dev->get_mac_handle(mac_dev));
++
++      if (!_errno && phy_dev)
++              phy_start(phy_dev);
++
++      return _errno;
++}
++
++static int __cold stop(struct mac_device *mac_dev)
++{
++      if (mac_dev->phy_dev)
++              phy_stop(mac_dev->phy_dev);
++
++      return fm_mac_disable(mac_dev->get_mac_handle(mac_dev));
++}
++
++static int __cold set_multi(struct net_device *net_dev,
++                          struct mac_device *mac_dev)
++{
++      struct mac_priv_s       *mac_priv;
++      struct mac_address      *old_addr, *tmp;
++      struct netdev_hw_addr   *ha;
++      int                     _errno;
++
++      mac_priv = macdev_priv(mac_dev);
++
++      /* Clear previous address list */
++      list_for_each_entry_safe(old_addr, tmp, &mac_dev->mc_addr_list, list) {
++              _errno = fm_mac_remove_hash_mac_addr(mac_priv->fm_mac,
++                              (t_EnetAddr *)old_addr->addr);
++              if (_errno < 0)
++                      return _errno;
++
++              list_del(&old_addr->list);
++              kfree(old_addr);
++      }
++
++      /* Add all the addresses from the new list */
++      netdev_for_each_mc_addr(ha, net_dev) {
++              _errno = fm_mac_add_hash_mac_addr(mac_priv->fm_mac,
++                              (t_EnetAddr *)ha->addr);
++              if (_errno < 0)
++                      return _errno;
++
++              tmp = kmalloc(sizeof(struct mac_address), GFP_ATOMIC);
++              if (!tmp) {
++                      dev_err(mac_dev->dev, "Out of memory\n");
++                      return -ENOMEM;
++              }
++              memcpy(tmp->addr, ha->addr, ETH_ALEN);
++              list_add(&tmp->list, &mac_dev->mc_addr_list);
++      }
++      return 0;
++}
++
++/* Avoid redundant calls to FMD, if the MAC driver already contains the desired
++ * active PAUSE settings. Otherwise, the new active settings should be reflected
++ * in FMan.
++ */
++int set_mac_active_pause(struct mac_device *mac_dev, bool rx, bool tx)
++{
++      struct fm_mac_dev *fm_mac_dev = mac_dev->get_mac_handle(mac_dev);
++      int _errno = 0;
++
++      if (unlikely(rx != mac_dev->rx_pause_active)) {
++              _errno = fm_mac_set_rx_pause_frames(fm_mac_dev, rx);
++              if (likely(_errno == 0))
++                      mac_dev->rx_pause_active = rx;
++      }
++
++      if (unlikely(tx != mac_dev->tx_pause_active)) {
++              _errno = fm_mac_set_tx_pause_frames(fm_mac_dev, tx);
++              if (likely(_errno == 0))
++                      mac_dev->tx_pause_active = tx;
++      }
++
++      return _errno;
++}
++EXPORT_SYMBOL(set_mac_active_pause);
++
++/* Determine the MAC RX/TX PAUSE frames settings based on PHY
++ * autonegotiation or values set by eththool.
++ */
++void get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause, bool *tx_pause)
++{
++      struct phy_device *phy_dev = mac_dev->phy_dev;
++      u16 lcl_adv, rmt_adv;
++      u8 flowctrl;
++
++      *rx_pause = *tx_pause = false;
++
++      if (!phy_dev->duplex)
++              return;
++
++      /* If PAUSE autonegotiation is disabled, the TX/RX PAUSE settings
++       * are those set by ethtool.
++       */
++      if (!mac_dev->autoneg_pause) {
++              *rx_pause = mac_dev->rx_pause_req;
++              *tx_pause = mac_dev->tx_pause_req;
++              return;
++      }
++
++      /* Else if PAUSE autonegotiation is enabled, the TX/RX PAUSE
++       * settings depend on the result of the link negotiation.
++       */
++
++      /* get local capabilities */
++      lcl_adv = 0;
++      if (phy_dev->advertising & ADVERTISED_Pause)
++              lcl_adv |= ADVERTISE_PAUSE_CAP;
++      if (phy_dev->advertising & ADVERTISED_Asym_Pause)
++              lcl_adv |= ADVERTISE_PAUSE_ASYM;
++
++      /* get link partner capabilities */
++      rmt_adv = 0;
++      if (phy_dev->pause)
++              rmt_adv |= LPA_PAUSE_CAP;
++      if (phy_dev->asym_pause)
++              rmt_adv |= LPA_PAUSE_ASYM;
++
++      /* Calculate TX/RX settings based on local and peer advertised
++       * symmetric/asymmetric PAUSE capabilities.
++       */
++      flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
++      if (flowctrl & FLOW_CTRL_RX)
++              *rx_pause = true;
++      if (flowctrl & FLOW_CTRL_TX)
++              *tx_pause = true;
++}
++EXPORT_SYMBOL(get_pause_cfg);
++
++static void adjust_link_void(struct net_device *net_dev)
++{
++}
++
++static void adjust_link(struct net_device *net_dev)
++{
++      struct dpa_priv_s *priv = netdev_priv(net_dev);
++      struct mac_device *mac_dev = priv->mac_dev;
++      struct phy_device *phy_dev = mac_dev->phy_dev;
++      struct fm_mac_dev *fm_mac_dev;
++      bool rx_pause, tx_pause;
++      int _errno;
++
++      fm_mac_dev = mac_dev->get_mac_handle(mac_dev);
++      fm_mac_adjust_link(fm_mac_dev, phy_dev->link, phy_dev->speed,
++                      phy_dev->duplex);
++
++      get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
++      _errno = set_mac_active_pause(mac_dev, rx_pause, tx_pause);
++      if (unlikely(_errno < 0))
++              netdev_err(net_dev, "set_mac_active_pause() = %d\n", _errno);
++}
++
++/* Initializes driver's PHY state, and attaches to the PHY.
++ * Returns 0 on success.
++ */
++static int dtsec_init_phy(struct net_device *net_dev,
++                        struct mac_device *mac_dev)
++{
++      struct phy_device       *phy_dev;
++
++      if (of_phy_is_fixed_link(mac_dev->phy_node))
++              phy_dev = of_phy_attach(net_dev, mac_dev->phy_node,
++                                      0, mac_dev->phy_if);
++      else
++              phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
++                                       &adjust_link, 0, mac_dev->phy_if);
++      if (unlikely(phy_dev == NULL) || IS_ERR(phy_dev)) {
++              netdev_err(net_dev, "Could not connect to PHY %s\n",
++                              mac_dev->phy_node ?
++                                      mac_dev->phy_node->full_name :
++                                      mac_dev->fixed_bus_id);
++              return phy_dev == NULL ? -ENODEV : PTR_ERR(phy_dev);
++      }
++
++      /* Remove any features not supported by the controller */
++      phy_dev->supported &= mac_dev->if_support;
++      /* Enable the symmetric and asymmetric PAUSE frame advertisements,
++       * as most of the PHY drivers do not enable them by default.
++       */
++      phy_dev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause);
++      phy_dev->advertising = phy_dev->supported;
++
++      mac_dev->phy_dev = phy_dev;
++
++      return 0;
++}
++
++static int xgmac_init_phy(struct net_device *net_dev,
++                        struct mac_device *mac_dev)
++{
++      struct phy_device *phy_dev;
++
++      if (of_phy_is_fixed_link(mac_dev->phy_node))
++              phy_dev = of_phy_attach(net_dev, mac_dev->phy_node,
++                                      0, mac_dev->phy_if);
++      else
++              phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
++                                       &adjust_link_void, 0, mac_dev->phy_if);
++      if (unlikely(phy_dev == NULL) || IS_ERR(phy_dev)) {
++              netdev_err(net_dev, "Could not attach to PHY %s\n",
++                              mac_dev->phy_node ?
++                                      mac_dev->phy_node->full_name :
++                                      mac_dev->fixed_bus_id);
++              return phy_dev == NULL ? -ENODEV : PTR_ERR(phy_dev);
++      }
++
++      phy_dev->supported &= mac_dev->if_support;
++      /* Enable the symmetric and asymmetric PAUSE frame advertisements,
++       * as most of the PHY drivers do not enable them by default.
++       */
++      phy_dev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause);
++      phy_dev->advertising = phy_dev->supported;
++
++      mac_dev->phy_dev = phy_dev;
++
++      return 0;
++}
++
++static int memac_init_phy(struct net_device *net_dev,
++                        struct mac_device *mac_dev)
++{
++      struct phy_device       *phy_dev;
++
++      if (of_phy_is_fixed_link(mac_dev->phy_node)) {
++              phy_dev = of_phy_attach(net_dev, mac_dev->phy_node,
++                                      0, mac_dev->phy_if);
++      } else if ((macdev2enetinterface(mac_dev) == e_ENET_MODE_XGMII_10000) ||
++                 (macdev2enetinterface(mac_dev) == e_ENET_MODE_SGMII_2500)) {
++              phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
++                                       &adjust_link_void, 0,
++                                       mac_dev->phy_if);
++      } else {
++              phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
++                                       &adjust_link, 0, mac_dev->phy_if);
++      }
++
++      if (unlikely(phy_dev == NULL) || IS_ERR(phy_dev)) {
++              netdev_err(net_dev, "Could not connect to PHY %s\n",
++                      mac_dev->phy_node ?
++                              mac_dev->phy_node->full_name :
++                              mac_dev->fixed_bus_id);
++              return phy_dev == NULL ? -ENODEV : PTR_ERR(phy_dev);
++      }
++
++      /* Remove any features not supported by the controller */
++      phy_dev->supported &= mac_dev->if_support;
++      /* Enable the symmetric and asymmetric PAUSE frame advertisements,
++       * as most of the PHY drivers do not enable them by default.
++       */
++      phy_dev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause);
++      phy_dev->advertising = phy_dev->supported;
++
++      mac_dev->phy_dev = phy_dev;
++
++      return 0;
++}
++
++static int __cold uninit(struct fm_mac_dev *fm_mac_dev)
++{
++      int                      _errno, __errno;
++
++      _errno = fm_mac_disable(fm_mac_dev);
++      __errno = fm_mac_free(fm_mac_dev);
++
++      if (unlikely(__errno < 0))
++              _errno = __errno;
++
++      return _errno;
++}
++
++static struct fm_mac_dev *get_mac_handle(struct mac_device *mac_dev)
++{
++      const struct mac_priv_s *priv;
++      priv = macdev_priv(mac_dev);
++      return priv->fm_mac;
++}
++
++static int dtsec_dump_regs(struct mac_device *h_mac, char *buf, int nn)
++{
++      struct dtsec_regs       *p_mm = (struct dtsec_regs *) h_mac->vaddr;
++      int                     i = 0, n = nn;
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++
++      FM_DMP_TITLE(buf, n, p_mm, "FM MAC - DTSEC-%d", h_mac->cell_index);
++
++      FM_DMP_V32(buf, n, p_mm, tsec_id);
++      FM_DMP_V32(buf, n, p_mm, tsec_id2);
++      FM_DMP_V32(buf, n, p_mm, ievent);
++      FM_DMP_V32(buf, n, p_mm, imask);
++      FM_DMP_V32(buf, n, p_mm, ecntrl);
++      FM_DMP_V32(buf, n, p_mm, ptv);
++      FM_DMP_V32(buf, n, p_mm, tmr_ctrl);
++      FM_DMP_V32(buf, n, p_mm, tmr_pevent);
++      FM_DMP_V32(buf, n, p_mm, tmr_pemask);
++      FM_DMP_V32(buf, n, p_mm, tctrl);
++      FM_DMP_V32(buf, n, p_mm, rctrl);
++      FM_DMP_V32(buf, n, p_mm, maccfg1);
++      FM_DMP_V32(buf, n, p_mm, maccfg2);
++      FM_DMP_V32(buf, n, p_mm, ipgifg);
++      FM_DMP_V32(buf, n, p_mm, hafdup);
++      FM_DMP_V32(buf, n, p_mm, maxfrm);
++
++      FM_DMP_V32(buf, n, p_mm, macstnaddr1);
++      FM_DMP_V32(buf, n, p_mm, macstnaddr2);
++
++      for (i = 0; i < 7; ++i) {
++              FM_DMP_V32(buf, n, p_mm, macaddr[i].exact_match1);
++              FM_DMP_V32(buf, n, p_mm, macaddr[i].exact_match2);
++      }
++
++      FM_DMP_V32(buf, n, p_mm, car1);
++      FM_DMP_V32(buf, n, p_mm, car2);
++
++      return n;
++}
++
++static int xgmac_dump_regs(struct mac_device *h_mac, char *buf, int nn)
++{
++      struct tgec_regs        *p_mm = (struct tgec_regs *) h_mac->vaddr;
++      int                     n = nn;
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++      FM_DMP_TITLE(buf, n, p_mm, "FM MAC - TGEC -%d", h_mac->cell_index);
++
++      FM_DMP_V32(buf, n, p_mm, tgec_id);
++      FM_DMP_V32(buf, n, p_mm, command_config);
++      FM_DMP_V32(buf, n, p_mm, mac_addr_0);
++      FM_DMP_V32(buf, n, p_mm, mac_addr_1);
++      FM_DMP_V32(buf, n, p_mm, maxfrm);
++      FM_DMP_V32(buf, n, p_mm, pause_quant);
++      FM_DMP_V32(buf, n, p_mm, rx_fifo_sections);
++      FM_DMP_V32(buf, n, p_mm, tx_fifo_sections);
++      FM_DMP_V32(buf, n, p_mm, rx_fifo_almost_f_e);
++      FM_DMP_V32(buf, n, p_mm, tx_fifo_almost_f_e);
++      FM_DMP_V32(buf, n, p_mm, hashtable_ctrl);
++      FM_DMP_V32(buf, n, p_mm, mdio_cfg_status);
++      FM_DMP_V32(buf, n, p_mm, mdio_command);
++      FM_DMP_V32(buf, n, p_mm, mdio_data);
++      FM_DMP_V32(buf, n, p_mm, mdio_regaddr);
++      FM_DMP_V32(buf, n, p_mm, status);
++      FM_DMP_V32(buf, n, p_mm, tx_ipg_len);
++      FM_DMP_V32(buf, n, p_mm, mac_addr_2);
++      FM_DMP_V32(buf, n, p_mm, mac_addr_3);
++      FM_DMP_V32(buf, n, p_mm, rx_fifo_ptr_rd);
++      FM_DMP_V32(buf, n, p_mm, rx_fifo_ptr_wr);
++      FM_DMP_V32(buf, n, p_mm, tx_fifo_ptr_rd);
++      FM_DMP_V32(buf, n, p_mm, tx_fifo_ptr_wr);
++      FM_DMP_V32(buf, n, p_mm, imask);
++      FM_DMP_V32(buf, n, p_mm, ievent);
++
++      return n;
++}
++
++static int memac_dump_regs(struct mac_device *h_mac, char *buf, int nn)
++{
++      struct memac_regs       *p_mm = (struct memac_regs *) h_mac->vaddr;
++      int                     i = 0, n = nn;
++
++      FM_DMP_SUBTITLE(buf, n, "\n");
++      FM_DMP_TITLE(buf, n, p_mm, "FM MAC - MEMAC -%d", h_mac->cell_index);
++
++      FM_DMP_V32(buf, n, p_mm, command_config);
++      FM_DMP_V32(buf, n, p_mm, mac_addr0.mac_addr_l);
++      FM_DMP_V32(buf, n, p_mm, mac_addr0.mac_addr_u);
++      FM_DMP_V32(buf, n, p_mm, maxfrm);
++      FM_DMP_V32(buf, n, p_mm, hashtable_ctrl);
++      FM_DMP_V32(buf, n, p_mm, ievent);
++      FM_DMP_V32(buf, n, p_mm, tx_ipg_length);
++      FM_DMP_V32(buf, n, p_mm, imask);
++
++      for (i = 0; i < 4; ++i)
++              FM_DMP_V32(buf, n, p_mm, pause_quanta[i]);
++
++      for (i = 0; i < 4; ++i)
++              FM_DMP_V32(buf, n, p_mm, pause_thresh[i]);
++
++      FM_DMP_V32(buf, n, p_mm, rx_pause_status);
++
++      for (i = 0; i < MEMAC_NUM_OF_PADDRS; ++i) {
++              FM_DMP_V32(buf, n, p_mm, mac_addr[i].mac_addr_l);
++              FM_DMP_V32(buf, n, p_mm, mac_addr[i].mac_addr_u);
++      }
++
++      FM_DMP_V32(buf, n, p_mm, lpwake_timer);
++      FM_DMP_V32(buf, n, p_mm, sleep_timer);
++      FM_DMP_V32(buf, n, p_mm, statn_config);
++        FM_DMP_V32(buf, n, p_mm, if_mode);
++        FM_DMP_V32(buf, n, p_mm, if_status);
++        FM_DMP_V32(buf, n, p_mm, hg_config);
++        FM_DMP_V32(buf, n, p_mm, hg_pause_quanta);
++        FM_DMP_V32(buf, n, p_mm, hg_pause_thresh);
++        FM_DMP_V32(buf, n, p_mm, hgrx_pause_status);
++        FM_DMP_V32(buf, n, p_mm, hg_fifos_status);
++        FM_DMP_V32(buf, n, p_mm, rhm);
++        FM_DMP_V32(buf, n, p_mm, thm);
++
++      return n;
++}
++
++static int memac_dump_regs_rx(struct mac_device *h_mac, char *buf, int nn)
++{
++        struct memac_regs       *p_mm = (struct memac_regs *) h_mac->vaddr;
++        int                     n = nn;
++
++        FM_DMP_SUBTITLE(buf, n, "\n");
++        FM_DMP_TITLE(buf, n, p_mm, "FM MAC - MEMAC -%d Rx stats", h_mac->cell_index);
++
++      /* Rx Statistics Counter */
++      FM_DMP_V32(buf, n, p_mm, reoct_l);
++      FM_DMP_V32(buf, n, p_mm, reoct_u);
++      FM_DMP_V32(buf, n, p_mm, roct_l);
++      FM_DMP_V32(buf, n, p_mm, roct_u);
++      FM_DMP_V32(buf, n, p_mm, raln_l);
++      FM_DMP_V32(buf, n, p_mm, raln_u);
++      FM_DMP_V32(buf, n, p_mm, rxpf_l);
++      FM_DMP_V32(buf, n, p_mm, rxpf_u);
++      FM_DMP_V32(buf, n, p_mm, rfrm_l);
++      FM_DMP_V32(buf, n, p_mm, rfrm_u);
++      FM_DMP_V32(buf, n, p_mm, rfcs_l);
++      FM_DMP_V32(buf, n, p_mm, rfcs_u);
++      FM_DMP_V32(buf, n, p_mm, rvlan_l);
++      FM_DMP_V32(buf, n, p_mm, rvlan_u);
++      FM_DMP_V32(buf, n, p_mm, rerr_l);
++      FM_DMP_V32(buf, n, p_mm, rerr_u);
++      FM_DMP_V32(buf, n, p_mm, ruca_l);
++      FM_DMP_V32(buf, n, p_mm, ruca_u);
++      FM_DMP_V32(buf, n, p_mm, rmca_l);
++      FM_DMP_V32(buf, n, p_mm, rmca_u);
++      FM_DMP_V32(buf, n, p_mm, rbca_l);
++      FM_DMP_V32(buf, n, p_mm, rbca_u);
++      FM_DMP_V32(buf, n, p_mm, rdrp_l);
++      FM_DMP_V32(buf, n, p_mm, rdrp_u);
++      FM_DMP_V32(buf, n, p_mm, rpkt_l);
++      FM_DMP_V32(buf, n, p_mm, rpkt_u);
++      FM_DMP_V32(buf, n, p_mm, rund_l);
++      FM_DMP_V32(buf, n, p_mm, rund_u);
++      FM_DMP_V32(buf, n, p_mm, r64_l);
++      FM_DMP_V32(buf, n, p_mm, r64_u);
++      FM_DMP_V32(buf, n, p_mm, r127_l);
++      FM_DMP_V32(buf, n, p_mm, r127_u);
++      FM_DMP_V32(buf, n, p_mm, r255_l);
++      FM_DMP_V32(buf, n, p_mm, r255_u);
++      FM_DMP_V32(buf, n, p_mm, r511_l);
++      FM_DMP_V32(buf, n, p_mm, r511_u);
++      FM_DMP_V32(buf, n, p_mm, r1023_l);
++      FM_DMP_V32(buf, n, p_mm, r1023_u);
++      FM_DMP_V32(buf, n, p_mm, r1518_l);
++      FM_DMP_V32(buf, n, p_mm, r1518_u);
++      FM_DMP_V32(buf, n, p_mm, r1519x_l);
++      FM_DMP_V32(buf, n, p_mm, r1519x_u);
++      FM_DMP_V32(buf, n, p_mm, rovr_l);
++      FM_DMP_V32(buf, n, p_mm, rovr_u);
++      FM_DMP_V32(buf, n, p_mm, rjbr_l);
++      FM_DMP_V32(buf, n, p_mm, rjbr_u);
++      FM_DMP_V32(buf, n, p_mm, rfrg_l);
++      FM_DMP_V32(buf, n, p_mm, rfrg_u);
++      FM_DMP_V32(buf, n, p_mm, rcnp_l);
++      FM_DMP_V32(buf, n, p_mm, rcnp_u);
++      FM_DMP_V32(buf, n, p_mm, rdrntp_l);
++      FM_DMP_V32(buf, n, p_mm, rdrntp_u);
++
++      return n;
++}
++
++static int memac_dump_regs_tx(struct mac_device *h_mac, char *buf, int nn)
++{
++        struct memac_regs       *p_mm = (struct memac_regs *) h_mac->vaddr;
++        int                     n = nn;
++
++        FM_DMP_SUBTITLE(buf, n, "\n");
++        FM_DMP_TITLE(buf, n, p_mm, "FM MAC - MEMAC -%d Tx stats", h_mac->cell_index);
++
++
++      /* Tx Statistics Counter */
++      FM_DMP_V32(buf, n, p_mm, teoct_l);
++      FM_DMP_V32(buf, n, p_mm, teoct_u);
++      FM_DMP_V32(buf, n, p_mm, toct_l);
++      FM_DMP_V32(buf, n, p_mm, toct_u);
++      FM_DMP_V32(buf, n, p_mm, txpf_l);
++      FM_DMP_V32(buf, n, p_mm, txpf_u);
++      FM_DMP_V32(buf, n, p_mm, tfrm_l);
++      FM_DMP_V32(buf, n, p_mm, tfrm_u);
++      FM_DMP_V32(buf, n, p_mm, tfcs_l);
++      FM_DMP_V32(buf, n, p_mm, tfcs_u);
++      FM_DMP_V32(buf, n, p_mm, tvlan_l);
++      FM_DMP_V32(buf, n, p_mm, tvlan_u);
++      FM_DMP_V32(buf, n, p_mm, terr_l);
++      FM_DMP_V32(buf, n, p_mm, terr_u);
++      FM_DMP_V32(buf, n, p_mm, tuca_l);
++      FM_DMP_V32(buf, n, p_mm, tuca_u);
++      FM_DMP_V32(buf, n, p_mm, tmca_l);
++      FM_DMP_V32(buf, n, p_mm, tmca_u);
++      FM_DMP_V32(buf, n, p_mm, tbca_l);
++      FM_DMP_V32(buf, n, p_mm, tbca_u);
++      FM_DMP_V32(buf, n, p_mm, tpkt_l);
++      FM_DMP_V32(buf, n, p_mm, tpkt_u);
++      FM_DMP_V32(buf, n, p_mm, tund_l);
++      FM_DMP_V32(buf, n, p_mm, tund_u);
++      FM_DMP_V32(buf, n, p_mm, t64_l);
++      FM_DMP_V32(buf, n, p_mm, t64_u);
++      FM_DMP_V32(buf, n, p_mm, t127_l);
++      FM_DMP_V32(buf, n, p_mm, t127_u);
++      FM_DMP_V32(buf, n, p_mm, t255_l);
++      FM_DMP_V32(buf, n, p_mm, t255_u);
++      FM_DMP_V32(buf, n, p_mm, t511_l);
++      FM_DMP_V32(buf, n, p_mm, t511_u);
++      FM_DMP_V32(buf, n, p_mm, t1023_l);
++      FM_DMP_V32(buf, n, p_mm, t1023_u);
++      FM_DMP_V32(buf, n, p_mm, t1518_l);
++      FM_DMP_V32(buf, n, p_mm, t1518_u);
++      FM_DMP_V32(buf, n, p_mm, t1519x_l);
++      FM_DMP_V32(buf, n, p_mm, t1519x_u);
++      FM_DMP_V32(buf, n, p_mm, tcnp_l);
++      FM_DMP_V32(buf, n, p_mm, tcnp_u);
++
++      return n;
++}
++
++int fm_mac_dump_regs(struct mac_device *h_mac, char *buf, int nn)
++{
++      int     n = nn;
++
++      n = h_mac->dump_mac_regs(h_mac, buf, n);
++
++      return n;
++}
++EXPORT_SYMBOL(fm_mac_dump_regs);
++
++int fm_mac_dump_rx_stats(struct mac_device *h_mac, char *buf, int nn)
++{
++      int     n = nn;
++
++      if(h_mac->dump_mac_rx_stats)
++              n = h_mac->dump_mac_rx_stats(h_mac, buf, n);
++
++      return n;
++}
++EXPORT_SYMBOL(fm_mac_dump_rx_stats);
++
++int fm_mac_dump_tx_stats(struct mac_device *h_mac, char *buf, int nn)
++{
++      int     n = nn;
++
++      if(h_mac->dump_mac_tx_stats)
++              n = h_mac->dump_mac_tx_stats(h_mac, buf, n);
++
++      return n;
++}
++EXPORT_SYMBOL(fm_mac_dump_tx_stats);
++
++static void __cold setup_dtsec(struct mac_device *mac_dev)
++{
++      mac_dev->init_phy       = dtsec_init_phy;
++      mac_dev->init           = init;
++      mac_dev->start          = start;
++      mac_dev->stop           = stop;
++      mac_dev->set_promisc    = fm_mac_set_promiscuous;
++      mac_dev->change_addr    = fm_mac_modify_mac_addr;
++      mac_dev->set_multi      = set_multi;
++      mac_dev->uninit         = uninit;
++      mac_dev->ptp_enable             = fm_mac_enable_1588_time_stamp;
++      mac_dev->ptp_disable            = fm_mac_disable_1588_time_stamp;
++      mac_dev->get_mac_handle         = get_mac_handle;
++      mac_dev->set_tx_pause           = fm_mac_set_tx_pause_frames;
++      mac_dev->set_rx_pause           = fm_mac_set_rx_pause_frames;
++      mac_dev->fm_rtc_enable          = fm_rtc_enable;
++      mac_dev->fm_rtc_disable         = fm_rtc_disable;
++      mac_dev->fm_rtc_get_cnt         = fm_rtc_get_cnt;
++      mac_dev->fm_rtc_set_cnt         = fm_rtc_set_cnt;
++      mac_dev->fm_rtc_get_drift       = fm_rtc_get_drift;
++      mac_dev->fm_rtc_set_drift       = fm_rtc_set_drift;
++      mac_dev->fm_rtc_set_alarm       = fm_rtc_set_alarm;
++      mac_dev->fm_rtc_set_fiper       = fm_rtc_set_fiper;
++      mac_dev->set_wol                = fm_mac_set_wol;
++      mac_dev->dump_mac_regs          = dtsec_dump_regs;
++}
++
++static void __cold setup_xgmac(struct mac_device *mac_dev)
++{
++      mac_dev->init_phy       = xgmac_init_phy;
++      mac_dev->init           = init;
++      mac_dev->start          = start;
++      mac_dev->stop           = stop;
++      mac_dev->set_promisc    = fm_mac_set_promiscuous;
++      mac_dev->change_addr    = fm_mac_modify_mac_addr;
++      mac_dev->set_multi      = set_multi;
++      mac_dev->uninit         = uninit;
++      mac_dev->get_mac_handle = get_mac_handle;
++      mac_dev->set_tx_pause   = fm_mac_set_tx_pause_frames;
++      mac_dev->set_rx_pause   = fm_mac_set_rx_pause_frames;
++      mac_dev->set_wol        = fm_mac_set_wol;
++      mac_dev->dump_mac_regs  = xgmac_dump_regs;
++}
++
++static void __cold setup_memac(struct mac_device *mac_dev)
++{
++      mac_dev->init_phy       = memac_init_phy;
++      mac_dev->init           = memac_init;
++      mac_dev->start          = start;
++      mac_dev->stop           = stop;
++      mac_dev->set_promisc    = fm_mac_set_promiscuous;
++      mac_dev->change_addr    = fm_mac_modify_mac_addr;
++      mac_dev->set_multi      = set_multi;
++      mac_dev->uninit         = uninit;
++      mac_dev->get_mac_handle         = get_mac_handle;
++      mac_dev->set_tx_pause           = fm_mac_set_tx_pause_frames;
++      mac_dev->set_rx_pause           = fm_mac_set_rx_pause_frames;
++      mac_dev->fm_rtc_enable          = fm_rtc_enable;
++      mac_dev->fm_rtc_disable         = fm_rtc_disable;
++      mac_dev->fm_rtc_get_cnt         = fm_rtc_get_cnt;
++      mac_dev->fm_rtc_set_cnt         = fm_rtc_set_cnt;
++      mac_dev->fm_rtc_get_drift       = fm_rtc_get_drift;
++      mac_dev->fm_rtc_set_drift       = fm_rtc_set_drift;
++      mac_dev->fm_rtc_set_alarm       = fm_rtc_set_alarm;
++      mac_dev->fm_rtc_set_fiper       = fm_rtc_set_fiper;
++      mac_dev->set_wol                = fm_mac_set_wol;
++      mac_dev->dump_mac_regs          = memac_dump_regs;
++      mac_dev->dump_mac_rx_stats      = memac_dump_regs_rx;
++      mac_dev->dump_mac_tx_stats      = memac_dump_regs_tx;
++}
++
++void (*const mac_setup[])(struct mac_device *mac_dev) = {
++      [DTSEC] = setup_dtsec,
++      [XGMAC] = setup_xgmac,
++      [MEMAC] = setup_memac
++};
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac.c
+@@ -0,0 +1,489 @@
++/* Copyright 2008-2012 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
++      KBUILD_BASENAME".c", __LINE__, __func__
++#else
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": " fmt
++#endif
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/of_platform.h>
++#include <linux/of_net.h>
++#include <linux/of_mdio.h>
++#include <linux/phy_fixed.h>
++#include <linux/device.h>
++#include <linux/phy.h>
++#include <linux/io.h>
++
++#include "lnxwrp_fm_ext.h"
++
++#include "mac.h"
++
++#define DTSEC_SUPPORTED \
++      (SUPPORTED_10baseT_Half \
++      | SUPPORTED_10baseT_Full \
++      | SUPPORTED_100baseT_Half \
++      | SUPPORTED_100baseT_Full \
++      | SUPPORTED_Autoneg \
++      | SUPPORTED_Pause \
++      | SUPPORTED_Asym_Pause \
++      | SUPPORTED_MII)
++
++static const char phy_str[][11] = {
++      [PHY_INTERFACE_MODE_MII]        = "mii",
++      [PHY_INTERFACE_MODE_GMII]       = "gmii",
++      [PHY_INTERFACE_MODE_SGMII]      = "sgmii",
++      [PHY_INTERFACE_MODE_QSGMII]     = "qsgmii",
++      [PHY_INTERFACE_MODE_TBI]        = "tbi",
++      [PHY_INTERFACE_MODE_RMII]       = "rmii",
++      [PHY_INTERFACE_MODE_RGMII]      = "rgmii",
++      [PHY_INTERFACE_MODE_RGMII_ID]   = "rgmii-id",
++      [PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid",
++      [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
++      [PHY_INTERFACE_MODE_RTBI]       = "rtbi",
++      [PHY_INTERFACE_MODE_XGMII]      = "xgmii",
++      [PHY_INTERFACE_MODE_SGMII_2500] = "sgmii-2500",
++};
++
++static phy_interface_t __pure __attribute__((nonnull)) str2phy(const char *str)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(phy_str); i++)
++              if (strcmp(str, phy_str[i]) == 0)
++                      return (phy_interface_t)i;
++
++      return PHY_INTERFACE_MODE_MII;
++}
++
++static const uint16_t phy2speed[] = {
++      [PHY_INTERFACE_MODE_MII]        = SPEED_100,
++      [PHY_INTERFACE_MODE_GMII]       = SPEED_1000,
++      [PHY_INTERFACE_MODE_SGMII]      = SPEED_1000,
++      [PHY_INTERFACE_MODE_QSGMII]     = SPEED_1000,
++      [PHY_INTERFACE_MODE_TBI]        = SPEED_1000,
++      [PHY_INTERFACE_MODE_RMII]       = SPEED_100,
++      [PHY_INTERFACE_MODE_RGMII]      = SPEED_1000,
++      [PHY_INTERFACE_MODE_RGMII_ID]   = SPEED_1000,
++      [PHY_INTERFACE_MODE_RGMII_RXID] = SPEED_1000,
++      [PHY_INTERFACE_MODE_RGMII_TXID] = SPEED_1000,
++      [PHY_INTERFACE_MODE_RTBI]       = SPEED_1000,
++      [PHY_INTERFACE_MODE_XGMII]      = SPEED_10000,
++      [PHY_INTERFACE_MODE_SGMII_2500] = SPEED_2500,
++};
++
++static struct mac_device * __cold
++alloc_macdev(struct device *dev, size_t sizeof_priv,
++              void (*setup)(struct mac_device *mac_dev))
++{
++      struct mac_device       *mac_dev;
++
++      mac_dev = devm_kzalloc(dev, sizeof(*mac_dev) + sizeof_priv, GFP_KERNEL);
++      if (unlikely(mac_dev == NULL))
++              mac_dev = ERR_PTR(-ENOMEM);
++      else {
++              mac_dev->dev = dev;
++              dev_set_drvdata(dev, mac_dev);
++              setup(mac_dev);
++      }
++
++      return mac_dev;
++}
++
++static int __cold free_macdev(struct mac_device *mac_dev)
++{
++      dev_set_drvdata(mac_dev->dev, NULL);
++
++      return mac_dev->uninit(mac_dev->get_mac_handle(mac_dev));
++}
++
++static const struct of_device_id mac_match[] = {
++      [DTSEC] = {
++              .compatible     = "fsl,fman-1g-mac"
++      },
++      [XGMAC] = {
++              .compatible     = "fsl,fman-10g-mac"
++      },
++      [MEMAC] = {
++              .compatible     = "fsl,fman-memac"
++      },
++      {}
++};
++MODULE_DEVICE_TABLE(of, mac_match);
++
++static int __cold mac_probe(struct platform_device *_of_dev)
++{
++      int                      _errno, i;
++      struct device           *dev;
++      struct device_node      *mac_node, *dev_node;
++      struct mac_device       *mac_dev;
++      struct platform_device  *of_dev;
++      struct resource          res;
++      const uint8_t           *mac_addr;
++      const char              *char_prop;
++      int                     nph;
++      u32                     cell_index;
++      const struct of_device_id *match;
++
++      dev = &_of_dev->dev;
++      mac_node = dev->of_node;
++
++      match = of_match_device(mac_match, dev);
++      if (!match)
++              return -EINVAL;
++
++      for (i = 0; i < ARRAY_SIZE(mac_match) - 1 && match != mac_match + i;
++                      i++)
++              ;
++      BUG_ON(i >= ARRAY_SIZE(mac_match) - 1);
++
++      mac_dev = alloc_macdev(dev, mac_sizeof_priv[i], mac_setup[i]);
++      if (IS_ERR(mac_dev)) {
++              _errno = PTR_ERR(mac_dev);
++              dev_err(dev, "alloc_macdev() = %d\n", _errno);
++              goto _return;
++      }
++
++      INIT_LIST_HEAD(&mac_dev->mc_addr_list);
++
++      /* Get the FM node */
++      dev_node = of_get_parent(mac_node);
++      if (unlikely(dev_node == NULL)) {
++              dev_err(dev, "of_get_parent(%s) failed\n",
++                              mac_node->full_name);
++              _errno = -EINVAL;
++              goto _return_dev_set_drvdata;
++      }
++
++      of_dev = of_find_device_by_node(dev_node);
++      if (unlikely(of_dev == NULL)) {
++              dev_err(dev, "of_find_device_by_node(%s) failed\n",
++                              dev_node->full_name);
++              _errno = -EINVAL;
++              goto _return_of_node_put;
++      }
++
++      mac_dev->fm_dev = fm_bind(&of_dev->dev);
++      if (unlikely(mac_dev->fm_dev == NULL)) {
++              dev_err(dev, "fm_bind(%s) failed\n", dev_node->full_name);
++              _errno = -ENODEV;
++              goto _return_of_node_put;
++      }
++
++      mac_dev->fm = (void *)fm_get_handle(mac_dev->fm_dev);
++      of_node_put(dev_node);
++
++      /* Get the address of the memory mapped registers */
++      _errno = of_address_to_resource(mac_node, 0, &res);
++      if (unlikely(_errno < 0)) {
++              dev_err(dev, "of_address_to_resource(%s) = %d\n",
++                              mac_node->full_name, _errno);
++              goto _return_dev_set_drvdata;
++      }
++
++      mac_dev->res = __devm_request_region(
++              dev,
++              fm_get_mem_region(mac_dev->fm_dev),
++              res.start, res.end + 1 - res.start, "mac");
++      if (unlikely(mac_dev->res == NULL)) {
++              dev_err(dev, "__devm_request_mem_region(mac) failed\n");
++              _errno = -EBUSY;
++              goto _return_dev_set_drvdata;
++      }
++
++      mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start,
++                                    mac_dev->res->end + 1
++                                    - mac_dev->res->start);
++      if (unlikely(mac_dev->vaddr == NULL)) {
++              dev_err(dev, "devm_ioremap() failed\n");
++              _errno = -EIO;
++              goto _return_dev_set_drvdata;
++      }
++
++#define TBIPA_OFFSET          0x1c
++#define TBIPA_DEFAULT_ADDR    5 /* override if used as external PHY addr. */
++      mac_dev->tbi_node = of_parse_phandle(mac_node, "tbi-handle", 0);
++      if (mac_dev->tbi_node) {
++              u32 tbiaddr = TBIPA_DEFAULT_ADDR;
++              const __be32 *tbi_reg;
++              void __iomem *addr;
++
++              tbi_reg = of_get_property(mac_dev->tbi_node, "reg", NULL);
++              if (tbi_reg)
++                      tbiaddr = be32_to_cpup(tbi_reg);
++              addr = mac_dev->vaddr + TBIPA_OFFSET;
++              /* TODO: out_be32 does not exist on ARM */
++              out_be32(addr, tbiaddr);
++      }
++
++      if (!of_device_is_available(mac_node)) {
++              devm_iounmap(dev, mac_dev->vaddr);
++              __devm_release_region(dev, fm_get_mem_region(mac_dev->fm_dev),
++                      res.start, res.end + 1 - res.start);
++              fm_unbind(mac_dev->fm_dev);
++              devm_kfree(dev, mac_dev);
++              dev_set_drvdata(dev, NULL);
++              return -ENODEV;
++      }
++
++      /* Get the cell-index */
++      _errno = of_property_read_u32(mac_node, "cell-index", &cell_index);
++      if (unlikely(_errno)) {
++              dev_err(dev, "Cannot read cell-index of mac node %s from device tree\n",
++                              mac_node->full_name);
++              goto _return_dev_set_drvdata;
++      }
++      mac_dev->cell_index = (uint8_t)cell_index;
++      if (mac_dev->cell_index >= 8)
++              mac_dev->cell_index -= 8;
++
++      /* Get the MAC address */
++      mac_addr = of_get_mac_address(mac_node);
++      if (unlikely(mac_addr == NULL)) {
++              dev_err(dev, "of_get_mac_address(%s) failed\n",
++                              mac_node->full_name);
++              _errno = -EINVAL;
++              goto _return_dev_set_drvdata;
++      }
++      memcpy(mac_dev->addr, mac_addr, sizeof(mac_dev->addr));
++
++      /* Verify the number of port handles */
++      nph = of_count_phandle_with_args(mac_node, "fsl,fman-ports", NULL);
++      if (unlikely(nph < 0)) {
++              dev_err(dev, "Cannot read port handles of mac node %s from device tree\n",
++                              mac_node->full_name);
++              _errno = nph;
++              goto _return_dev_set_drvdata;
++      }
++
++      if (nph != ARRAY_SIZE(mac_dev->port_dev)) {
++              dev_err(dev, "Not supported number of port handles of mac node %s from device tree\n",
++                              mac_node->full_name);
++              _errno = -EINVAL;
++              goto _return_dev_set_drvdata;
++      }
++
++      for_each_port_device(i, mac_dev->port_dev) {
++              dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i);
++              if (unlikely(dev_node == NULL)) {
++                      dev_err(dev, "Cannot find port node referenced by mac node %s from device tree\n",
++                                      mac_node->full_name);
++                      _errno = -EINVAL;
++                      goto _return_of_node_put;
++              }
++
++              of_dev = of_find_device_by_node(dev_node);
++              if (unlikely(of_dev == NULL)) {
++                      dev_err(dev, "of_find_device_by_node(%s) failed\n",
++                                      dev_node->full_name);
++                      _errno = -EINVAL;
++                      goto _return_of_node_put;
++              }
++
++              mac_dev->port_dev[i] = fm_port_bind(&of_dev->dev);
++              if (unlikely(mac_dev->port_dev[i] == NULL)) {
++                      dev_err(dev, "dev_get_drvdata(%s) failed\n",
++                                      dev_node->full_name);
++                      _errno = -EINVAL;
++                      goto _return_of_node_put;
++              }
++              of_node_put(dev_node);
++      }
++
++      /* Get the PHY connection type */
++      _errno = of_property_read_string(mac_node, "phy-connection-type",
++                      &char_prop);
++      if (unlikely(_errno)) {
++              dev_warn(dev,
++                       "Cannot read PHY connection type of mac node %s from device tree. Defaulting to MII\n",
++                       mac_node->full_name);
++              mac_dev->phy_if = PHY_INTERFACE_MODE_MII;
++      } else
++              mac_dev->phy_if = str2phy(char_prop);
++
++      mac_dev->link           = false;
++      mac_dev->half_duplex    = false;
++      mac_dev->speed          = phy2speed[mac_dev->phy_if];
++      mac_dev->max_speed      = mac_dev->speed;
++      mac_dev->if_support = DTSEC_SUPPORTED;
++      /* We don't support half-duplex in SGMII mode */
++      if (strstr(char_prop, "sgmii") || strstr(char_prop, "qsgmii") ||
++          strstr(char_prop, "sgmii-2500"))
++              mac_dev->if_support &= ~(SUPPORTED_10baseT_Half |
++                                      SUPPORTED_100baseT_Half);
++
++      /* Gigabit support (no half-duplex) */
++      if (mac_dev->max_speed == SPEED_1000 ||
++          mac_dev->max_speed == SPEED_2500)
++              mac_dev->if_support |= SUPPORTED_1000baseT_Full;
++
++      /* The 10G interface only supports one mode */
++      if (strstr(char_prop, "xgmii"))
++              mac_dev->if_support = SUPPORTED_10000baseT_Full;
++
++      /* Get the rest of the PHY information */
++      mac_dev->phy_node = of_parse_phandle(mac_node, "phy-handle", 0);
++      if (!mac_dev->phy_node) {
++              struct phy_device *phy;
++
++              if (!of_phy_is_fixed_link(mac_node)) {
++                      dev_err(dev, "Wrong PHY information of mac node %s\n",
++                              mac_node->full_name);
++                      goto _return_dev_set_drvdata;
++              }
++
++              _errno = of_phy_register_fixed_link(mac_node);
++              if (_errno)
++                      goto _return_dev_set_drvdata;
++
++              mac_dev->fixed_link = devm_kzalloc(mac_dev->dev,
++                                                 sizeof(*mac_dev->fixed_link),
++                                                 GFP_KERNEL);
++              if (!mac_dev->fixed_link)
++                      goto _return_dev_set_drvdata;
++
++              mac_dev->phy_node = of_node_get(mac_node);
++              phy = of_phy_find_device(mac_dev->phy_node);
++              if (!phy)
++                      goto _return_dev_set_drvdata;
++
++              mac_dev->fixed_link->link = phy->link;
++              mac_dev->fixed_link->speed = phy->speed;
++              mac_dev->fixed_link->duplex = phy->duplex;
++              mac_dev->fixed_link->pause = phy->pause;
++              mac_dev->fixed_link->asym_pause = phy->asym_pause;
++      }
++
++      _errno = mac_dev->init(mac_dev);
++      if (unlikely(_errno < 0)) {
++              dev_err(dev, "mac_dev->init() = %d\n", _errno);
++              goto _return_dev_set_drvdata;
++      }
++
++      /* pause frame autonegotiation enabled*/
++      mac_dev->autoneg_pause = true;
++
++      /* by intializing the values to false, force FMD to enable PAUSE frames
++       * on RX and TX
++       */
++      mac_dev->rx_pause_req = mac_dev->tx_pause_req = true;
++      mac_dev->rx_pause_active = mac_dev->tx_pause_active = false;
++      _errno = set_mac_active_pause(mac_dev, true, true);
++      if (unlikely(_errno < 0))
++              dev_err(dev, "set_mac_active_pause() = %d\n", _errno);
++
++      dev_info(dev,
++              "FMan MAC address: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
++                   mac_dev->addr[0], mac_dev->addr[1], mac_dev->addr[2],
++                   mac_dev->addr[3], mac_dev->addr[4], mac_dev->addr[5]);
++
++      goto _return;
++
++_return_of_node_put:
++      of_node_put(dev_node);
++_return_dev_set_drvdata:
++      dev_set_drvdata(dev, NULL);
++_return:
++      return _errno;
++}
++
++static int __cold mac_remove(struct platform_device *of_dev)
++{
++      int                      i, _errno;
++      struct device           *dev;
++      struct mac_device       *mac_dev;
++
++      dev = &of_dev->dev;
++      mac_dev = (struct mac_device *)dev_get_drvdata(dev);
++
++      for_each_port_device(i, mac_dev->port_dev)
++              fm_port_unbind(mac_dev->port_dev[i]);
++
++      fm_unbind(mac_dev->fm_dev);
++
++      _errno = free_macdev(mac_dev);
++
++      return _errno;
++}
++
++static struct platform_driver mac_driver = {
++      .driver = {
++              .name           = KBUILD_MODNAME,
++              .of_match_table = mac_match,
++              .owner          = THIS_MODULE,
++      },
++      .probe          = mac_probe,
++      .remove         = mac_remove
++};
++
++static int __init __cold mac_load(void)
++{
++      int      _errno;
++
++      pr_debug(KBUILD_MODNAME ": -> %s:%s()\n",
++              KBUILD_BASENAME".c", __func__);
++
++      pr_info(KBUILD_MODNAME ": %s\n", mac_driver_description);
++
++      _errno = platform_driver_register(&mac_driver);
++      if (unlikely(_errno < 0)) {
++              pr_err(KBUILD_MODNAME ": %s:%hu:%s(): platform_driver_register() = %d\n",
++                         KBUILD_BASENAME".c", __LINE__, __func__, _errno);
++              goto _return;
++      }
++
++      goto _return;
++
++_return:
++      pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
++              KBUILD_BASENAME".c", __func__);
++
++      return _errno;
++}
++module_init(mac_load);
++
++static void __exit __cold mac_unload(void)
++{
++      pr_debug(KBUILD_MODNAME ": -> %s:%s()\n",
++              KBUILD_BASENAME".c", __func__);
++
++      platform_driver_unregister(&mac_driver);
++
++      pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
++              KBUILD_BASENAME".c", __func__);
++}
++module_exit(mac_unload);
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac.h
+@@ -0,0 +1,135 @@
++/* Copyright 2008-2011 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __MAC_H
++#define __MAC_H
++
++#include <linux/device.h>     /* struct device, BUS_ID_SIZE */
++#include <linux/if_ether.h>   /* ETH_ALEN */
++#include <linux/phy.h>                /* phy_interface_t, struct phy_device */
++#include <linux/list.h>
++
++#include "lnxwrp_fsl_fman.h"  /* struct port_device */
++
++enum {DTSEC, XGMAC, MEMAC};
++
++struct mac_device {
++      struct device           *dev;
++      void                    *priv;
++      uint8_t                  cell_index;
++      struct resource         *res;
++      void __iomem            *vaddr;
++      uint8_t                  addr[ETH_ALEN];
++      bool                     promisc;
++
++      struct fm               *fm_dev;
++      struct fm_port          *port_dev[2];
++
++      phy_interface_t          phy_if;
++      u32                      if_support;
++      bool                     link;
++      bool                     half_duplex;
++      uint16_t                 speed;
++      uint16_t                 max_speed;
++      struct device_node      *phy_node;
++      char                     fixed_bus_id[MII_BUS_ID_SIZE + 3];
++      struct device_node      *tbi_node;
++      struct phy_device       *phy_dev;
++      void                    *fm;
++      /* List of multicast addresses */
++      struct list_head         mc_addr_list;
++      struct fixed_phy_status  *fixed_link;
++
++      bool autoneg_pause;
++      bool rx_pause_req;
++      bool tx_pause_req;
++      bool rx_pause_active;
++      bool tx_pause_active;
++
++      struct fm_mac_dev *(*get_mac_handle)(struct mac_device *mac_dev);
++      int (*init_phy)(struct net_device *net_dev, struct mac_device *mac_dev);
++      int (*init)(struct mac_device *mac_dev);
++      int (*start)(struct mac_device *mac_dev);
++      int (*stop)(struct mac_device *mac_dev);
++      int (*set_promisc)(struct fm_mac_dev *fm_mac_dev, bool enable);
++      int (*change_addr)(struct fm_mac_dev *fm_mac_dev, uint8_t *addr);
++      int (*set_multi)(struct net_device *net_dev,
++                       struct mac_device *mac_dev);
++      int (*uninit)(struct fm_mac_dev *fm_mac_dev);
++      int (*ptp_enable)(struct fm_mac_dev *fm_mac_dev);
++      int (*ptp_disable)(struct fm_mac_dev *fm_mac_dev);
++      int (*set_rx_pause)(struct fm_mac_dev *fm_mac_dev, bool en);
++      int (*set_tx_pause)(struct fm_mac_dev *fm_mac_dev, bool en);
++      int (*fm_rtc_enable)(struct fm *fm_dev);
++      int (*fm_rtc_disable)(struct fm *fm_dev);
++      int (*fm_rtc_get_cnt)(struct fm *fm_dev, uint64_t *ts);
++      int (*fm_rtc_set_cnt)(struct fm *fm_dev, uint64_t ts);
++      int (*fm_rtc_get_drift)(struct fm *fm_dev, uint32_t *drift);
++      int (*fm_rtc_set_drift)(struct fm *fm_dev, uint32_t drift);
++      int (*fm_rtc_set_alarm)(struct fm *fm_dev, uint32_t id, uint64_t time);
++      int (*fm_rtc_set_fiper)(struct fm *fm_dev, uint32_t id,
++                              uint64_t fiper);
++#ifdef CONFIG_PTP_1588_CLOCK_DPAA
++      int (*fm_rtc_enable_interrupt)(struct fm *fm_dev, uint32_t events);
++      int (*fm_rtc_disable_interrupt)(struct fm *fm_dev, uint32_t events);
++#endif
++      int (*set_wol)(struct fm_port *port, struct fm_mac_dev *fm_mac_dev,
++                      bool en);
++      int (*dump_mac_regs)(struct mac_device *h_mac, char *buf, int nn);
++      int (*dump_mac_rx_stats)(struct mac_device *h_mac, char *buf, int nn);
++      int (*dump_mac_tx_stats)(struct mac_device *h_mac, char *buf, int nn);
++};
++
++struct mac_address {
++      uint8_t addr[ETH_ALEN];
++      struct list_head list;
++};
++
++#define get_fm_handle(net_dev) \
++      (((struct dpa_priv_s *)netdev_priv(net_dev))->mac_dev->fm_dev)
++
++#define for_each_port_device(i, port_dev)     \
++      for (i = 0; i < ARRAY_SIZE(port_dev); i++)
++
++static inline __attribute((nonnull)) void *macdev_priv(
++              const struct mac_device *mac_dev)
++{
++      return (void *)mac_dev + sizeof(*mac_dev);
++}
++
++extern const char     *mac_driver_description;
++extern const size_t    mac_sizeof_priv[];
++extern void (*const mac_setup[])(struct mac_device *mac_dev);
++
++int set_mac_active_pause(struct mac_device *mac_dev, bool rx, bool tx);
++void get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause, bool *tx_pause);
++
++#endif        /* __MAC_H */
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/offline_port.c
+@@ -0,0 +1,848 @@
++/* Copyright 2011-2012 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* Offline Parsing / Host Command port driver for FSL QorIQ FMan.
++ * Validates device-tree configuration and sets up the offline ports.
++ */
++
++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
++      KBUILD_BASENAME".c", __LINE__, __func__
++#else
++#define pr_fmt(fmt) \
++      KBUILD_MODNAME ": " fmt
++#endif
++
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include <linux/fsl_qman.h>
++
++#include "offline_port.h"
++#include "dpaa_eth.h"
++#include "dpaa_eth_common.h"
++
++#define OH_MOD_DESCRIPTION    "FSL FMan Offline Parsing port driver"
++/* Manip extra space and data alignment for fragmentation */
++#define FRAG_MANIP_SPACE 128
++#define FRAG_DATA_ALIGN 64
++
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("Bogdan Hamciuc <bogdan.hamciuc@freescale.com>");
++MODULE_DESCRIPTION(OH_MOD_DESCRIPTION);
++
++
++static const struct of_device_id oh_port_match_table[] = {
++      {
++              .compatible     = "fsl,dpa-oh"
++      },
++      {
++              .compatible     = "fsl,dpa-oh-shared"
++      },
++      {}
++};
++MODULE_DEVICE_TABLE(of, oh_port_match_table);
++
++#ifdef CONFIG_PM
++
++static int oh_suspend(struct device *dev)
++{
++      struct dpa_oh_config_s  *oh_config;
++
++      oh_config = dev_get_drvdata(dev);
++      return fm_port_suspend(oh_config->oh_port);
++}
++
++static int oh_resume(struct device *dev)
++{
++      struct dpa_oh_config_s  *oh_config;
++
++      oh_config = dev_get_drvdata(dev);
++      return fm_port_resume(oh_config->oh_port);
++}
++
++static const struct dev_pm_ops oh_pm_ops = {
++      .suspend = oh_suspend,
++      .resume = oh_resume,
++};
++
++#define OH_PM_OPS (&oh_pm_ops)
++
++#else /* CONFIG_PM */
++
++#define OH_PM_OPS NULL
++
++#endif /* CONFIG_PM */
++
++/* Creates Frame Queues */
++static uint32_t oh_fq_create(struct qman_fq *fq,
++      uint32_t fq_id, uint16_t channel,
++      uint16_t wq_id)
++{
++      struct qm_mcc_initfq fq_opts;
++      uint32_t create_flags, init_flags;
++      uint32_t ret = 0;
++
++      if (fq == NULL)
++              return 1;
++
++      /* Set flags for FQ create */
++      create_flags = QMAN_FQ_FLAG_LOCKED | QMAN_FQ_FLAG_TO_DCPORTAL;
++
++      /* Create frame queue */
++      ret = qman_create_fq(fq_id, create_flags, fq);
++      if (ret != 0)
++              return 1;
++
++      /* Set flags for FQ init */
++      init_flags = QMAN_INITFQ_FLAG_SCHED;
++
++      /* Set FQ init options. Specify destination WQ ID and channel */
++      fq_opts.we_mask = QM_INITFQ_WE_DESTWQ;
++      fq_opts.fqd.dest.wq = wq_id;
++      fq_opts.fqd.dest.channel = channel;
++
++      /* Initialize frame queue */
++      ret = qman_init_fq(fq, init_flags, &fq_opts);
++      if (ret != 0) {
++              qman_destroy_fq(fq, 0);
++              return 1;
++      }
++
++      return 0;
++}
++
++static void dump_fq(struct device *dev, int fqid, uint16_t channel)
++{
++      if (channel) {
++              /* display fqs with a valid (!= 0) destination channel */
++              dev_info(dev, "FQ ID:%d Channel ID:%d\n", fqid, channel);
++      }
++}
++
++static void dump_fq_duple(struct device *dev, struct qman_fq *fqs,
++              int fqs_count, uint16_t channel_id)
++{
++      int i;
++      for (i = 0; i < fqs_count; i++)
++              dump_fq(dev, (fqs + i)->fqid, channel_id);
++}
++
++static void dump_oh_config(struct device *dev, struct dpa_oh_config_s *conf)
++{
++      struct list_head *fq_list;
++      struct fq_duple *fqd;
++      int i;
++
++      dev_info(dev, "Default egress frame queue: %d\n", conf->default_fqid);
++      dev_info(dev, "Default error frame queue: %d\n", conf->error_fqid);
++
++      /* TX queues (old initialization) */
++      dev_info(dev, "Initialized queues:");
++      for (i = 0; i < conf->egress_cnt; i++)
++              dump_fq_duple(dev, conf->egress_fqs, conf->egress_cnt,
++                              conf->channel);
++
++      /* initialized ingress queues */
++      list_for_each(fq_list, &conf->fqs_ingress_list) {
++              fqd = list_entry(fq_list, struct fq_duple, fq_list);
++              dump_fq_duple(dev, fqd->fqs, fqd->fqs_count, fqd->channel_id);
++      }
++
++      /* initialized egress queues */
++      list_for_each(fq_list, &conf->fqs_egress_list) {
++              fqd = list_entry(fq_list, struct fq_duple, fq_list);
++              dump_fq_duple(dev, fqd->fqs, fqd->fqs_count, fqd->channel_id);
++      }
++}
++
++/* Destroys Frame Queues */
++static void oh_fq_destroy(struct qman_fq *fq)
++{
++      int _errno = 0;
++
++      _errno = qman_retire_fq(fq, NULL);
++      if (unlikely(_errno < 0))
++              pr_err(KBUILD_MODNAME": %s:%hu:%s(): qman_retire_fq(%u)=%d\n",
++                      KBUILD_BASENAME".c", __LINE__, __func__,
++                      qman_fq_fqid(fq), _errno);
++
++      _errno = qman_oos_fq(fq);
++      if (unlikely(_errno < 0)) {
++              pr_err(KBUILD_MODNAME": %s:%hu:%s(): qman_oos_fq(%u)=%d\n",
++                      KBUILD_BASENAME".c", __LINE__, __func__,
++                      qman_fq_fqid(fq), _errno);
++      }
++
++      qman_destroy_fq(fq, 0);
++}
++
++/* Allocation code for the OH port's PCD frame queues */
++static int __cold oh_alloc_pcd_fqids(struct device *dev,
++      uint32_t num,
++      uint8_t alignment,
++      uint32_t *base_fqid)
++{
++      dev_crit(dev, "callback not implemented!\n");
++      BUG();
++
++      return 0;
++}
++
++static int __cold oh_free_pcd_fqids(struct device *dev, uint32_t base_fqid)
++{
++      dev_crit(dev, "callback not implemented!\n");
++      BUG();
++
++      return 0;
++}
++
++static void oh_set_buffer_layout(struct fm_port *port,
++                               struct dpa_buffer_layout_s *layout)
++{
++      struct fm_port_params params;
++
++      layout->priv_data_size = DPA_TX_PRIV_DATA_SIZE;
++      layout->parse_results = true;
++      layout->hash_results = true;
++      layout->time_stamp = false;
++
++      fm_port_get_buff_layout_ext_params(port, &params);
++      layout->manip_extra_space = params.manip_extra_space;
++      layout->data_align = params.data_align;
++}
++
++static int
++oh_port_probe(struct platform_device *_of_dev)
++{
++      struct device *dpa_oh_dev;
++      struct device_node *dpa_oh_node;
++      int lenp, _errno = 0, fq_idx, duple_idx;
++      int n_size, i, j, ret, duples_count;
++      struct platform_device *oh_of_dev;
++      struct device_node *oh_node, *bpool_node = NULL, *root_node;
++      struct device *oh_dev;
++      struct dpa_oh_config_s *oh_config = NULL;
++      const __be32 *oh_all_queues;
++      const __be32 *channel_ids;
++      const __be32 *oh_tx_queues;
++      uint32_t queues_count;
++      uint32_t crt_fqid_base;
++      uint32_t crt_fq_count;
++      bool frag_enabled = false;
++      struct fm_port_params oh_port_tx_params;
++      struct fm_port_pcd_param oh_port_pcd_params;
++      struct dpa_buffer_layout_s buf_layout;
++
++      /* True if the current partition owns the OH port. */
++      bool init_oh_port;
++
++      const struct of_device_id *match;
++      int crt_ext_pools_count;
++      u32 ext_pool_size;
++      u32 port_id;
++      u32 channel_id;
++
++      int channel_ids_count;
++      int channel_idx;
++      struct fq_duple *fqd;
++      struct list_head *fq_list, *fq_list_tmp;
++
++      const __be32 *bpool_cfg;
++      uint32_t bpid;
++
++      memset(&oh_port_tx_params, 0, sizeof(oh_port_tx_params));
++      dpa_oh_dev = &_of_dev->dev;
++      dpa_oh_node = dpa_oh_dev->of_node;
++      BUG_ON(dpa_oh_node == NULL);
++
++      match = of_match_device(oh_port_match_table, dpa_oh_dev);
++      if (!match)
++              return -EINVAL;
++
++      dev_dbg(dpa_oh_dev, "Probing OH port...\n");
++
++      /* Find the referenced OH node */
++      oh_node = of_parse_phandle(dpa_oh_node, "fsl,fman-oh-port", 0);
++      if (oh_node == NULL) {
++              dev_err(dpa_oh_dev,
++                      "Can't find OH node referenced from node %s\n",
++                      dpa_oh_node->full_name);
++              return -EINVAL;
++      }
++      dev_info(dpa_oh_dev, "Found OH node handle compatible with %s\n",
++              match->compatible);
++
++      _errno = of_property_read_u32(oh_node, "cell-index", &port_id);
++      if (_errno) {
++              dev_err(dpa_oh_dev, "No port id found in node %s\n",
++                      dpa_oh_node->full_name);
++              goto return_kfree;
++      }
++
++      _errno = of_property_read_u32(oh_node, "fsl,qman-channel-id",
++                      &channel_id);
++      if (_errno) {
++              dev_err(dpa_oh_dev, "No channel id found in node %s\n",
++                      dpa_oh_node->full_name);
++              goto return_kfree;
++      }
++
++      oh_of_dev = of_find_device_by_node(oh_node);
++      BUG_ON(oh_of_dev == NULL);
++      oh_dev = &oh_of_dev->dev;
++
++      /* The OH port must be initialized exactly once.
++       * The following scenarios are of interest:
++       *      - the node is Linux-private (will always initialize it);
++       *      - the node is shared between two Linux partitions
++       *        (only one of them will initialize it);
++       *      - the node is shared between a Linux and a LWE partition
++       *        (Linux will initialize it) - "fsl,dpa-oh-shared"
++       */
++
++      /* Check if the current partition owns the OH port
++       * and ought to initialize it. It may be the case that we leave this
++       * to another (also Linux) partition.
++       */
++      init_oh_port = strcmp(match->compatible, "fsl,dpa-oh-shared");
++
++      /* If we aren't the "owner" of the OH node, we're done here. */
++      if (!init_oh_port) {
++              dev_dbg(dpa_oh_dev,
++                      "Not owning the shared OH port %s, will not initialize it.\n",
++                      oh_node->full_name);
++              of_node_put(oh_node);
++              return 0;
++      }
++
++      /* Allocate OH dev private data */
++      oh_config = devm_kzalloc(dpa_oh_dev, sizeof(*oh_config), GFP_KERNEL);
++      if (oh_config == NULL) {
++              dev_err(dpa_oh_dev,
++                      "Can't allocate private data for OH node %s referenced from node %s!\n",
++                      oh_node->full_name, dpa_oh_node->full_name);
++              _errno = -ENOMEM;
++              goto return_kfree;
++      }
++
++      INIT_LIST_HEAD(&oh_config->fqs_ingress_list);
++      INIT_LIST_HEAD(&oh_config->fqs_egress_list);
++
++      /* FQs that enter OH port */
++      lenp = 0;
++      oh_all_queues = of_get_property(dpa_oh_node,
++              "fsl,qman-frame-queues-ingress", &lenp);
++      if (lenp % (2 * sizeof(*oh_all_queues))) {
++              dev_warn(dpa_oh_dev,
++                      "Wrong ingress queues format for OH node %s referenced from node %s!\n",
++                      oh_node->full_name, dpa_oh_node->full_name);
++              /* just ignore the last unpaired value */
++      }
++
++      duples_count = lenp / (2 * sizeof(*oh_all_queues));
++      dev_err(dpa_oh_dev, "Allocating %d ingress frame queues duples\n",
++                      duples_count);
++      for (duple_idx = 0; duple_idx < duples_count; duple_idx++) {
++              crt_fqid_base = be32_to_cpu(oh_all_queues[2 * duple_idx]);
++              crt_fq_count = be32_to_cpu(oh_all_queues[2 * duple_idx + 1]);
++
++              fqd = devm_kzalloc(dpa_oh_dev,
++                              sizeof(struct fq_duple), GFP_KERNEL);
++              if (!fqd) {
++                      dev_err(dpa_oh_dev, "Can't allocate structures for ingress frame queues for OH node %s referenced from node %s!\n",
++                                      oh_node->full_name,
++                                      dpa_oh_node->full_name);
++                      _errno = -ENOMEM;
++                      goto return_kfree;
++              }
++
++              fqd->fqs = devm_kzalloc(dpa_oh_dev,
++                              crt_fq_count * sizeof(struct qman_fq),
++                              GFP_KERNEL);
++              if (!fqd->fqs) {
++                      dev_err(dpa_oh_dev, "Can't allocate structures for ingress frame queues for OH node %s referenced from node %s!\n",
++                                      oh_node->full_name,
++                                      dpa_oh_node->full_name);
++                      _errno = -ENOMEM;
++                      goto return_kfree;
++              }
++
++              for (j = 0; j < crt_fq_count; j++)
++                      (fqd->fqs + j)->fqid = crt_fqid_base + j;
++              fqd->fqs_count = crt_fq_count;
++              fqd->channel_id = (uint16_t)channel_id;
++              list_add(&fqd->fq_list, &oh_config->fqs_ingress_list);
++      }
++
++      /* create the ingress queues */
++      list_for_each(fq_list, &oh_config->fqs_ingress_list) {
++              fqd = list_entry(fq_list, struct fq_duple, fq_list);
++
++              for (j = 0; j < fqd->fqs_count; j++) {
++                      ret = oh_fq_create(fqd->fqs + j,
++                                      (fqd->fqs + j)->fqid,
++                                      fqd->channel_id, 3);
++                      if (ret != 0) {
++                              dev_err(dpa_oh_dev, "Unable to create ingress frame queue %d for OH node %s referenced from node %s!\n",
++                                              (fqd->fqs + j)->fqid,
++                                              oh_node->full_name,
++                                              dpa_oh_node->full_name);
++                              _errno = -EINVAL;
++                              goto return_kfree;
++                      }
++              }
++      }
++
++      /* FQs that exit OH port */
++      lenp = 0;
++      oh_all_queues = of_get_property(dpa_oh_node,
++              "fsl,qman-frame-queues-egress", &lenp);
++      if (lenp % (2 * sizeof(*oh_all_queues))) {
++              dev_warn(dpa_oh_dev,
++                      "Wrong egress queues format for OH node %s referenced from node %s!\n",
++                      oh_node->full_name, dpa_oh_node->full_name);
++              /* just ignore the last unpaired value */
++      }
++
++      duples_count = lenp / (2 * sizeof(*oh_all_queues));
++      dev_dbg(dpa_oh_dev, "Allocating %d egress frame queues duples\n",
++                      duples_count);
++      for (duple_idx = 0; duple_idx < duples_count; duple_idx++) {
++              crt_fqid_base = be32_to_cpu(oh_all_queues[2 * duple_idx]);
++              crt_fq_count = be32_to_cpu(oh_all_queues[2 * duple_idx + 1]);
++
++              fqd = devm_kzalloc(dpa_oh_dev,
++                              sizeof(struct fq_duple), GFP_KERNEL);
++              if (!fqd) {
++                      dev_err(dpa_oh_dev, "Can't allocate structures for egress frame queues for OH node %s referenced from node %s!\n",
++                                      oh_node->full_name,
++                                      dpa_oh_node->full_name);
++                      _errno = -ENOMEM;
++                      goto return_kfree;
++              }
++
++              fqd->fqs = devm_kzalloc(dpa_oh_dev,
++                              crt_fq_count * sizeof(struct qman_fq),
++                              GFP_KERNEL);
++              if (!fqd->fqs) {
++                      dev_err(dpa_oh_dev,
++                                      "Can't allocate structures for egress frame queues for OH node %s referenced from node %s!\n",
++                                      oh_node->full_name,
++                                      dpa_oh_node->full_name);
++                      _errno = -ENOMEM;
++                      goto return_kfree;
++              }
++
++              for (j = 0; j < crt_fq_count; j++)
++                      (fqd->fqs + j)->fqid = crt_fqid_base + j;
++              fqd->fqs_count = crt_fq_count;
++              /* channel ID is specified in another attribute */
++              fqd->channel_id = 0;
++              list_add_tail(&fqd->fq_list, &oh_config->fqs_egress_list);
++
++              /* allocate the queue */
++
++      }
++
++      /* channel_ids for FQs that exit OH port */
++      lenp = 0;
++      channel_ids = of_get_property(dpa_oh_node,
++              "fsl,qman-channel-ids-egress", &lenp);
++
++      channel_ids_count = lenp / (sizeof(*channel_ids));
++      if (channel_ids_count != duples_count) {
++              dev_warn(dpa_oh_dev,
++                      "Not all egress queues have a channel id for OH node %s referenced from node %s!\n",
++                      oh_node->full_name, dpa_oh_node->full_name);
++              /* just ignore the queues that do not have a Channel ID */
++      }
++
++      channel_idx = 0;
++      list_for_each(fq_list, &oh_config->fqs_egress_list) {
++              if (channel_idx + 1 > channel_ids_count)
++                      break;
++              fqd = list_entry(fq_list, struct fq_duple, fq_list);
++              fqd->channel_id =
++                      (uint16_t)be32_to_cpu(channel_ids[channel_idx++]);
++      }
++
++      /* create egress queues */
++      list_for_each(fq_list, &oh_config->fqs_egress_list) {
++              fqd = list_entry(fq_list, struct fq_duple, fq_list);
++
++              if (fqd->channel_id == 0) {
++                      /* missing channel id in dts */
++                      continue;
++              }
++
++              for (j = 0; j < fqd->fqs_count; j++) {
++                      ret = oh_fq_create(fqd->fqs + j,
++                                      (fqd->fqs + j)->fqid,
++                                      fqd->channel_id, 3);
++                      if (ret != 0) {
++                              dev_err(dpa_oh_dev, "Unable to create egress frame queue %d for OH node %s referenced from node %s!\n",
++                                              (fqd->fqs + j)->fqid,
++                                              oh_node->full_name,
++                                              dpa_oh_node->full_name);
++                              _errno = -EINVAL;
++                              goto return_kfree;
++                      }
++              }
++      }
++
++      /* Read FQ ids/nums for the DPA OH node */
++      oh_all_queues = of_get_property(dpa_oh_node,
++              "fsl,qman-frame-queues-oh", &lenp);
++      if (oh_all_queues == NULL) {
++              dev_err(dpa_oh_dev,
++                      "No frame queues have been defined for OH node %s referenced from node %s\n",
++                      oh_node->full_name, dpa_oh_node->full_name);
++              _errno = -EINVAL;
++              goto return_kfree;
++      }
++
++      /* Check that the OH error and default FQs are there */
++      BUG_ON(lenp % (2 * sizeof(*oh_all_queues)));
++      queues_count = lenp / (2 * sizeof(*oh_all_queues));
++      if (queues_count != 2) {
++              dev_err(dpa_oh_dev,
++                      "Error and Default queues must be defined for OH node %s referenced from node %s\n",
++                      oh_node->full_name, dpa_oh_node->full_name);
++              _errno = -EINVAL;
++              goto return_kfree;
++      }
++
++      /* Read the FQIDs defined for this OH port */
++      dev_dbg(dpa_oh_dev, "Reading %d queues...\n", queues_count);
++      fq_idx = 0;
++
++      /* Error FQID - must be present */
++      crt_fqid_base = be32_to_cpu(oh_all_queues[fq_idx++]);
++      crt_fq_count = be32_to_cpu(oh_all_queues[fq_idx++]);
++      if (crt_fq_count != 1) {
++              dev_err(dpa_oh_dev,
++                      "Only 1 Error FQ allowed in OH node %s referenced from node %s (read: %d FQIDs).\n",
++                      oh_node->full_name, dpa_oh_node->full_name,
++                      crt_fq_count);
++              _errno = -EINVAL;
++              goto return_kfree;
++      }
++      oh_config->error_fqid = crt_fqid_base;
++      dev_dbg(dpa_oh_dev, "Read Error FQID 0x%x for OH port %s.\n",
++              oh_config->error_fqid, oh_node->full_name);
++
++      /* Default FQID - must be present */
++      crt_fqid_base = be32_to_cpu(oh_all_queues[fq_idx++]);
++      crt_fq_count = be32_to_cpu(oh_all_queues[fq_idx++]);
++      if (crt_fq_count != 1) {
++              dev_err(dpa_oh_dev,
++                      "Only 1 Default FQ allowed in OH node %s referenced from %s (read: %d FQIDs).\n",
++                      oh_node->full_name, dpa_oh_node->full_name,
++                      crt_fq_count);
++              _errno = -EINVAL;
++              goto return_kfree;
++      }
++      oh_config->default_fqid = crt_fqid_base;
++      dev_dbg(dpa_oh_dev, "Read Default FQID 0x%x for OH port %s.\n",
++              oh_config->default_fqid, oh_node->full_name);
++
++      /* TX FQID - presence is optional */
++      oh_tx_queues = of_get_property(dpa_oh_node, "fsl,qman-frame-queues-tx",
++                      &lenp);
++      if (oh_tx_queues == NULL) {
++              dev_dbg(dpa_oh_dev,
++                      "No tx queues have been defined for OH node %s referenced from node %s\n",
++                      oh_node->full_name, dpa_oh_node->full_name);
++              goto config_port;
++      }
++
++      /* Check that queues-tx has only a base and a count defined */
++      BUG_ON(lenp % (2 * sizeof(*oh_tx_queues)));
++      queues_count = lenp / (2 * sizeof(*oh_tx_queues));
++      if (queues_count != 1) {
++              dev_err(dpa_oh_dev,
++                      "TX queues must be defined in only one <base count> tuple for OH node %s referenced from node %s\n",
++                      oh_node->full_name, dpa_oh_node->full_name);
++              _errno = -EINVAL;
++              goto return_kfree;
++      }
++
++      fq_idx = 0;
++      crt_fqid_base = be32_to_cpu(oh_tx_queues[fq_idx++]);
++      crt_fq_count = be32_to_cpu(oh_tx_queues[fq_idx++]);
++      oh_config->egress_cnt = crt_fq_count;
++
++      /* Allocate TX queues */
++      dev_dbg(dpa_oh_dev, "Allocating %d queues for TX...\n", crt_fq_count);
++      oh_config->egress_fqs = devm_kzalloc(dpa_oh_dev,
++              crt_fq_count * sizeof(struct qman_fq), GFP_KERNEL);
++      if (oh_config->egress_fqs == NULL) {
++              dev_err(dpa_oh_dev,
++                      "Can't allocate private data for TX queues for OH node %s referenced from node %s!\n",
++                      oh_node->full_name, dpa_oh_node->full_name);
++              _errno = -ENOMEM;
++              goto return_kfree;
++      }
++
++      /* Create TX queues */
++      for (i = 0; i < crt_fq_count; i++) {
++              ret = oh_fq_create(oh_config->egress_fqs + i,
++                      crt_fqid_base + i, (uint16_t)channel_id, 3);
++              if (ret != 0) {
++                      dev_err(dpa_oh_dev,
++                              "Unable to create TX frame queue %d for OH node %s referenced from node %s!\n",
++                              crt_fqid_base + i, oh_node->full_name,
++                              dpa_oh_node->full_name);
++                      _errno = -EINVAL;
++                      goto return_kfree;
++              }
++      }
++
++config_port:
++      /* Get a handle to the fm_port so we can set
++       * its configuration params
++       */
++      oh_config->oh_port = fm_port_bind(oh_dev);
++      if (oh_config->oh_port == NULL) {
++              dev_err(dpa_oh_dev, "NULL drvdata from fm port dev %s!\n",
++                      oh_node->full_name);
++              _errno = -EINVAL;
++              goto return_kfree;
++      }
++
++      oh_set_buffer_layout(oh_config->oh_port, &buf_layout);
++
++      /* read the pool handlers */
++      crt_ext_pools_count = of_count_phandle_with_args(dpa_oh_node,
++                      "fsl,bman-buffer-pools", NULL);
++      if (crt_ext_pools_count <= 0) {
++              dev_info(dpa_oh_dev,
++                       "OH port %s has no buffer pool. Fragmentation will not be enabled\n",
++                      oh_node->full_name);
++              goto init_port;
++      }
++
++      /* used for reading ext_pool_size*/
++      root_node = of_find_node_by_path("/");
++      if (root_node == NULL) {
++              dev_err(dpa_oh_dev, "of_find_node_by_path(/) failed\n");
++              _errno = -EINVAL;
++              goto return_kfree;
++      }
++
++      n_size = of_n_size_cells(root_node);
++      of_node_put(root_node);
++
++      dev_dbg(dpa_oh_dev, "OH port number of pools = %d\n",
++                      crt_ext_pools_count);
++
++      oh_port_tx_params.num_pools = (uint8_t)crt_ext_pools_count;
++
++      for (i = 0; i < crt_ext_pools_count; i++) {
++              bpool_node = of_parse_phandle(dpa_oh_node,
++                              "fsl,bman-buffer-pools", i);
++              if (bpool_node == NULL) {
++                      dev_err(dpa_oh_dev, "Invalid Buffer pool node\n");
++                      _errno = -EINVAL;
++                      goto return_kfree;
++              }
++
++              _errno = of_property_read_u32(bpool_node, "fsl,bpid", &bpid);
++              if (_errno) {
++                      dev_err(dpa_oh_dev, "Invalid Buffer Pool ID\n");
++                      _errno = -EINVAL;
++                      goto return_kfree;
++              }
++
++              oh_port_tx_params.pool_param[i].id = (uint8_t)bpid;
++              dev_dbg(dpa_oh_dev, "OH port bpool id = %u\n", bpid);
++
++              bpool_cfg = of_get_property(bpool_node,
++                              "fsl,bpool-ethernet-cfg", &lenp);
++              if (bpool_cfg == NULL) {
++                      dev_err(dpa_oh_dev, "Invalid Buffer pool config params\n");
++                      _errno = -EINVAL;
++                      goto return_kfree;
++              }
++
++              ext_pool_size = of_read_number(bpool_cfg + n_size, n_size);
++              oh_port_tx_params.pool_param[i].size = (uint16_t)ext_pool_size;
++              dev_dbg(dpa_oh_dev, "OH port bpool size = %u\n",
++                      ext_pool_size);
++              of_node_put(bpool_node);
++
++      }
++
++      if (buf_layout.data_align != FRAG_DATA_ALIGN ||
++          buf_layout.manip_extra_space != FRAG_MANIP_SPACE)
++              goto init_port;
++
++      frag_enabled = true;
++      dev_info(dpa_oh_dev, "IP Fragmentation enabled for OH port %d",
++                      port_id);
++
++init_port:
++      of_node_put(oh_node);
++      /* Set Tx params */
++      dpaa_eth_init_port(tx, oh_config->oh_port, oh_port_tx_params,
++              oh_config->error_fqid, oh_config->default_fqid, (&buf_layout),
++              frag_enabled);
++      /* Set PCD params */
++      oh_port_pcd_params.cba = oh_alloc_pcd_fqids;
++      oh_port_pcd_params.cbf = oh_free_pcd_fqids;
++      oh_port_pcd_params.dev = dpa_oh_dev;
++      fm_port_pcd_bind(oh_config->oh_port, &oh_port_pcd_params);
++
++      dev_set_drvdata(dpa_oh_dev, oh_config);
++
++      /* Enable the OH port */
++      _errno = fm_port_enable(oh_config->oh_port);
++      if (_errno)
++              goto return_kfree;
++
++      dev_info(dpa_oh_dev, "OH port %s enabled.\n", oh_node->full_name);
++
++      /* print of all referenced & created queues */
++      dump_oh_config(dpa_oh_dev, oh_config);
++
++      return 0;
++
++return_kfree:
++      if (bpool_node)
++              of_node_put(bpool_node);
++      if (oh_node)
++              of_node_put(oh_node);
++      if (oh_config && oh_config->egress_fqs)
++              devm_kfree(dpa_oh_dev, oh_config->egress_fqs);
++
++      list_for_each_safe(fq_list, fq_list_tmp, &oh_config->fqs_ingress_list) {
++              fqd = list_entry(fq_list, struct fq_duple, fq_list);
++              list_del(fq_list);
++              devm_kfree(dpa_oh_dev, fqd->fqs);
++              devm_kfree(dpa_oh_dev, fqd);
++      }
++
++      list_for_each_safe(fq_list, fq_list_tmp, &oh_config->fqs_egress_list) {
++              fqd = list_entry(fq_list, struct fq_duple, fq_list);
++              list_del(fq_list);
++              devm_kfree(dpa_oh_dev, fqd->fqs);
++              devm_kfree(dpa_oh_dev, fqd);
++      }
++
++      devm_kfree(dpa_oh_dev, oh_config);
++      return _errno;
++}
++
++static int __cold oh_port_remove(struct platform_device *_of_dev)
++{
++      int _errno = 0, i;
++      struct dpa_oh_config_s *oh_config;
++
++      pr_info("Removing OH port...\n");
++
++      oh_config = dev_get_drvdata(&_of_dev->dev);
++      if (oh_config == NULL) {
++              pr_err(KBUILD_MODNAME
++                      ": %s:%hu:%s(): No OH config in device private data!\n",
++                      KBUILD_BASENAME".c", __LINE__, __func__);
++              _errno = -ENODEV;
++              goto return_error;
++      }
++
++      if (oh_config->egress_fqs)
++              for (i = 0; i < oh_config->egress_cnt; i++)
++                      oh_fq_destroy(oh_config->egress_fqs + i);
++
++      if (oh_config->oh_port == NULL) {
++              pr_err(KBUILD_MODNAME
++                      ": %s:%hu:%s(): No fm port in device private data!\n",
++                      KBUILD_BASENAME".c", __LINE__, __func__);
++              _errno = -EINVAL;
++              goto free_egress_fqs;
++      }
++
++      _errno = fm_port_disable(oh_config->oh_port);
++
++free_egress_fqs:
++      if (oh_config->egress_fqs)
++              devm_kfree(&_of_dev->dev, oh_config->egress_fqs);
++      devm_kfree(&_of_dev->dev, oh_config);
++      dev_set_drvdata(&_of_dev->dev, NULL);
++
++return_error:
++      return _errno;
++}
++
++static struct platform_driver oh_port_driver = {
++      .driver = {
++              .name           = KBUILD_MODNAME,
++              .of_match_table = oh_port_match_table,
++              .owner          = THIS_MODULE,
++              .pm             = OH_PM_OPS,
++      },
++      .probe          = oh_port_probe,
++      .remove         = oh_port_remove
++};
++
++static int __init __cold oh_port_load(void)
++{
++      int _errno;
++
++      pr_info(OH_MOD_DESCRIPTION "\n");
++
++      _errno = platform_driver_register(&oh_port_driver);
++      if (_errno < 0) {
++              pr_err(KBUILD_MODNAME
++                      ": %s:%hu:%s(): platform_driver_register() = %d\n",
++                      KBUILD_BASENAME".c", __LINE__, __func__, _errno);
++      }
++
++      pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
++              KBUILD_BASENAME".c", __func__);
++      return _errno;
++}
++module_init(oh_port_load);
++
++static void __exit __cold oh_port_unload(void)
++{
++      pr_debug(KBUILD_MODNAME ": -> %s:%s()\n",
++              KBUILD_BASENAME".c", __func__);
++
++      platform_driver_unregister(&oh_port_driver);
++
++      pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
++              KBUILD_BASENAME".c", __func__);
++}
++module_exit(oh_port_unload);
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/offline_port.h
+@@ -0,0 +1,59 @@
++/* Copyright 2011 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __OFFLINE_PORT_H
++#define __OFFLINE_PORT_H
++
++struct fm_port;
++struct qman_fq;
++
++/* fqs are defined in duples (base_fq, fq_count) */
++struct fq_duple {
++      struct qman_fq *fqs;
++      int fqs_count;
++      uint16_t channel_id;
++      struct list_head fq_list;
++};
++
++/* OH port configuration */
++struct dpa_oh_config_s {
++      uint32_t                error_fqid;
++      uint32_t                default_fqid;
++      struct fm_port          *oh_port;
++      uint32_t                egress_cnt;
++      struct qman_fq          *egress_fqs;
++      uint16_t                channel;
++
++      struct list_head fqs_ingress_list;
++      struct list_head fqs_egress_list;
++};
++
++#endif /* __OFFLINE_PORT_H */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0010-dpaa_eth-ls1043a-errata-check-if-the-skb-is-linear-a.patch b/target/linux/layerscape/patches-5.4/701-net-0010-dpaa_eth-ls1043a-errata-check-if-the-skb-is-linear-a.patch
new file mode 100644 (file)
index 0000000..e601766
--- /dev/null
@@ -0,0 +1,31 @@
+From 62fbf7ebdc28867ae613c3be9c62b30bc36edb1d Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 27 Feb 2017 17:35:24 +0200
+Subject: [PATCH] dpaa_eth: ls1043a errata: check if the skb is linear after 4k
+ splitting
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -993,7 +993,7 @@ int __hot dpa_tx_extended(struct sk_buff
+       struct dpa_percpu_priv_s *percpu_priv;
+       struct rtnl_link_stats64 *percpu_stats;
+       int err = 0;
+-      const bool nonlinear = skb_is_nonlinear(skb);
++      bool nonlinear;
+       int *countptr, offset = 0;
+       priv = netdev_priv(net_dev);
+@@ -1023,6 +1023,8 @@ int __hot dpa_tx_extended(struct sk_buff
+       }
+ #endif
++      nonlinear = skb_is_nonlinear(skb);
++
+       /* MAX_SKB_FRAGS is larger than our DPA_SGT_MAX_ENTRIES; make sure
+        * we don't feed FMan with more fragments than it supports.
+        * Btw, we're using the first sgt entry to store the linear part of
diff --git a/target/linux/layerscape/patches-5.4/701-net-0011-dpaa_eth-ceetm-adapt-to-net-sched-API-changes.patch b/target/linux/layerscape/patches-5.4/701-net-0011-dpaa_eth-ceetm-adapt-to-net-sched-API-changes.patch
new file mode 100644 (file)
index 0000000..b7e970d
--- /dev/null
@@ -0,0 +1,24 @@
+From 23057cf5bf562358918a219083a4b022d36c4b73 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 13 Jun 2017 14:40:54 +0300
+Subject: [PATCH] dpaa_eth: ceetm: adapt to net/sched API changes
+
+The tc_classify and tc_classify_compat calls have been merged. Adapt to
+the new API.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -1839,7 +1839,7 @@ static struct ceetm_class *ceetm_classif
+       *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
+       tcf = priv->filter_list;
+-      while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) {
++      while (tcf && (result = tc_classify(skb, tcf, &res, false)) >= 0) {
+ #ifdef CONFIG_NET_CLS_ACT
+               switch (result) {
+               case TC_ACT_QUEUED:
diff --git a/target/linux/layerscape/patches-5.4/701-net-0012-dpaa_eth-ceetm-adapt-to-the-new-gnet-stats-API.patch b/target/linux/layerscape/patches-5.4/701-net-0012-dpaa_eth-ceetm-adapt-to-the-new-gnet-stats-API.patch
new file mode 100644 (file)
index 0000000..0580541
--- /dev/null
@@ -0,0 +1,22 @@
+From e7db22d2a5f57c41ec0a211b5d03b8768a173139 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 13 Jun 2017 16:26:00 +0300
+Subject: [PATCH] dpaa_eth: ceetm: adapt to the new gnet stats API
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -1759,7 +1759,8 @@ static int ceetm_cls_dump_stats(struct Q
+               }
+       }
+-      if (gnet_stats_copy_basic(d, NULL, &tmp_bstats) < 0)
++      if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch),
++                                d, NULL, &tmp_bstats) < 0)
+               return -1;
+       if (cq && qman_ceetm_cq_get_dequeue_statistics(cq, 0,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0013-dpaa_eth-ceetm-update-include-paths-for-tc-filters.patch b/target/linux/layerscape/patches-5.4/701-net-0013-dpaa_eth-ceetm-update-include-paths-for-tc-filters.patch
new file mode 100644 (file)
index 0000000..d413739
--- /dev/null
@@ -0,0 +1,22 @@
+From eb4edd5a72383c960801b2c3302036a1d3932775 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 13 Jun 2017 16:29:37 +0300
+Subject: [PATCH] dpaa_eth: ceetm: update include paths for tc filters
+
+The tcf_destroy_chain call prototype has been moved.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h
+@@ -33,6 +33,7 @@
+ #define __DPAA_ETH_CEETM_H
+ #include <net/pkt_sched.h>
++#include <net/pkt_cls.h>
+ #include <net/netlink.h>
+ #include <lnxwrp_fm.h>
diff --git a/target/linux/layerscape/patches-5.4/701-net-0014-dpa_eth-remove-unused-code.patch b/target/linux/layerscape/patches-5.4/701-net-0014-dpa_eth-remove-unused-code.patch
new file mode 100644 (file)
index 0000000..7d3ff7a
--- /dev/null
@@ -0,0 +1,87 @@
+From fb2390ac7b8fc635bc136a400419fd3eec1d006f Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Wed, 7 Jun 2017 16:10:34 +0300
+Subject: [PATCH] dpa_eth: remove unused code
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_base.c    | 58 ----------------------
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_base.h    |  1 -
+ 2 files changed, 59 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c
+@@ -165,64 +165,6 @@ _return_of_node_put:
+ }
+ EXPORT_SYMBOL(dpa_bp_probe);
+-int dpa_bp_shared_port_seed(struct dpa_bp *bp)
+-{
+-      void __iomem **ptr;
+-
+-      /* In MAC-less and Shared-MAC scenarios the physical
+-       * address of the buffer pool in device tree is set
+-       * to 0 to specify that another entity (USDPAA) will
+-       * allocate and seed the buffers
+-       */
+-      if (!bp->paddr)
+-              return 0;
+-
+-      /* allocate memory region for buffers */
+-      devm_request_mem_region(bp->dev, bp->paddr,
+-                      bp->size * bp->config_count, KBUILD_MODNAME);
+-      /* managed ioremap unmapping */
+-      ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
+-      if (!ptr)
+-              return -EIO;
+-#ifndef CONFIG_PPC
+-      bp->vaddr = ioremap_cache_ns(bp->paddr, bp->size * bp->config_count);
+-#else
+-      bp->vaddr = ioremap_prot(bp->paddr, bp->size * bp->config_count, 0);
+-#endif
+-      if (bp->vaddr == NULL) {
+-              pr_err("Could not map memory for pool %d\n", bp->bpid);
+-              devres_free(ptr);
+-              return -EIO;
+-      }
+-      *ptr = bp->vaddr;
+-      devres_add(bp->dev, ptr);
+-
+-      /* seed pool with buffers from that memory region */
+-      if (bp->seed_pool) {
+-              int count = bp->target_count;
+-              dma_addr_t addr = bp->paddr;
+-
+-              while (count) {
+-                      struct bm_buffer bufs[8];
+-                      uint8_t num_bufs = 0;
+-
+-                      do {
+-                              BUG_ON(addr > 0xffffffffffffull);
+-                              bufs[num_bufs].bpid = bp->bpid;
+-                              bm_buffer_set64(&bufs[num_bufs++], addr);
+-                              addr += bp->size;
+-
+-                      } while (--count && (num_bufs < 8));
+-
+-                      while (bman_release(bp->pool, bufs, num_bufs, 0))
+-                              cpu_relax();
+-              }
+-      }
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL(dpa_bp_shared_port_seed);
+-
+ int dpa_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp,
+               size_t count)
+ {
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.h
+@@ -45,6 +45,5 @@ struct dpa_bp * __cold __must_check /* _
+ dpa_bp_probe(struct platform_device *_of_dev, size_t *count);
+ int dpa_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp,
+               size_t count);
+-int dpa_bp_shared_port_seed(struct dpa_bp *bp);
+ #endif /* __DPAA_ETH_BASE_H */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0015-fmd-use-ptp-timer-for-Fman-RTC-node-name.patch b/target/linux/layerscape/patches-5.4/701-net-0015-fmd-use-ptp-timer-for-Fman-RTC-node-name.patch
new file mode 100644 (file)
index 0000000..4a68c1f
--- /dev/null
@@ -0,0 +1,28 @@
+From 7a31dff8328002acd4fdc76287bf9923c3392b02 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Sat, 17 Jun 2017 16:29:13 +0800
+Subject: [PATCH] fmd: use ptp-timer for Fman RTC node name
+
+Layerscape DPAA platforms have updated dts to use ptp-timer
+instead of rtc for Fman RTC node name. This patch is to
+update it in driver.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
+@@ -684,9 +684,9 @@ static t_LnxWrpFmDev * ReadFmDevTreeNode
+     /* Get the RTC base address and size */
+     memset(ids, 0, sizeof(ids));
+-    if (WARN_ON(strlen("rtc") >= sizeof(ids[0].name)))
++    if (WARN_ON(strlen("ptp-timer") >= sizeof(ids[0].name)))
+         return NULL;
+-    strcpy(ids[0].name, "rtc");
++    strcpy(ids[0].name, "ptp-timer");
+     if (WARN_ON(strlen("fsl,fman-rtc") >= sizeof(ids[0].compatible)))
+         return NULL;
+     strcpy(ids[0].compatible, "fsl,fman-rtc");
diff --git a/target/linux/layerscape/patches-5.4/701-net-0016-dpaa_eth-use-ptp-timer-phandle-instead-of-ptimer-han.patch b/target/linux/layerscape/patches-5.4/701-net-0016-dpaa_eth-use-ptp-timer-phandle-instead-of-ptimer-han.patch
new file mode 100644 (file)
index 0000000..6995700
--- /dev/null
@@ -0,0 +1,34 @@
+From b022befd58e4f7306069c6d9831179e0c3a9b1b1 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Sat, 17 Jun 2017 16:16:58 +0800
+Subject: [PATCH] dpaa_eth: use ptp-timer phandle instead of ptimer-handle
+
+Layerscape DPAA platforms have updated dts to use ptp-timer phandle
+instead of ptimer-handle for Fman RTC node. This patch is to
+update it in driver.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
+@@ -575,7 +575,7 @@ dpa_mac_probe(struct platform_device *_o
+       }
+ #ifdef CONFIG_FSL_DPAA_1588
+-      phandle_prop = of_get_property(mac_node, "ptimer-handle", &lenp);
++      phandle_prop = of_get_property(mac_node, "ptp-timer", &lenp);
+       if (phandle_prop && ((mac_dev->phy_if != PHY_INTERFACE_MODE_SGMII) ||
+                       ((mac_dev->phy_if == PHY_INTERFACE_MODE_SGMII) &&
+                        (mac_dev->speed == SPEED_1000)))) {
+@@ -595,7 +595,7 @@ dpa_mac_probe(struct platform_device *_o
+       if ((mac_dev->phy_if != PHY_INTERFACE_MODE_SGMII) ||
+           ((mac_dev->phy_if == PHY_INTERFACE_MODE_SGMII) &&
+                        (mac_dev->speed == SPEED_1000))) {
+-              ptp_priv.node = of_parse_phandle(mac_node, "ptimer-handle", 0);
++              ptp_priv.node = of_parse_phandle(mac_node, "ptp-timer", 0);
+               if (ptp_priv.node) {
+                       ptp_priv.of_dev = of_find_device_by_node(ptp_priv.node);
+                       if (unlikely(ptp_priv.of_dev == NULL)) {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0017-dpaa_eth-move-global-variable-clock-into-ptp_priv_s-.patch b/target/linux/layerscape/patches-5.4/701-net-0017-dpaa_eth-move-global-variable-clock-into-ptp_priv_s-.patch
new file mode 100644 (file)
index 0000000..617d3e5
--- /dev/null
@@ -0,0 +1,52 @@
+From bbb23c33bbfc0fdb6098f0c61950f4a7c03379aa Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Mon, 19 Jun 2017 18:46:04 +0800
+Subject: [PATCH] dpaa_eth: move global variable 'clock' into ptp_priv_s struct
+
+This patch is to move global variable 'clock' for DPAA PTP
+clock pointer into ptp_priv_s struct.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h | 1 +
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ptp.c | 5 +++--
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
+@@ -669,6 +669,7 @@ static inline void _dpa_assign_wq(struct
+ struct ptp_priv_s {
+       struct device_node *node;
+       struct platform_device *of_dev;
++      struct ptp_clock *clock;
+       struct mac_device *mac_dev;
+ };
+ extern struct ptp_priv_s ptp_priv;
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ptp.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ptp.c
+@@ -27,8 +27,6 @@
+ #include "dpaa_eth.h"
+ #include "mac.h"
+-struct ptp_clock *clock;
+-
+ static struct mac_device *mac_dev;
+ static u32 freqCompensation;
+@@ -256,6 +254,7 @@ static int __init __cold dpa_ptp_load(vo
+ {
+       struct device *ptp_dev;
+       struct timespec64 now;
++      struct ptp_clock *clock = ptp_priv.clock;
+       int dpa_phc_index;
+       int err;
+@@ -283,6 +282,8 @@ module_init(dpa_ptp_load);
+ static void __exit __cold dpa_ptp_unload(void)
+ {
++      struct ptp_clock *clock = ptp_priv.clock;
++
+       if (mac_dev->fm_rtc_disable_interrupt)
+               mac_dev->fm_rtc_disable_interrupt(mac_dev->fm_dev, 0xffffffff);
+       ptp_clock_unregister(clock);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0018-sdk_dpaa-use-new-api-ethtool_ksettings_-get-set.patch b/target/linux/layerscape/patches-5.4/701-net-0018-sdk_dpaa-use-new-api-ethtool_ksettings_-get-set.patch
new file mode 100644 (file)
index 0000000..0df382e
--- /dev/null
@@ -0,0 +1,65 @@
+From c77e142beed7241a1360f2dedbe34e2f697512c9 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Tue, 29 Aug 2017 09:51:45 +0300
+Subject: [PATCH] sdk_dpaa: use new api ethtool_ksettings_{get|set}
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c   | 20 +++++++++-----------
+ 1 file changed, 9 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c
+@@ -84,8 +84,8 @@ static char dpa_stats_global[][ETH_GSTRI
+ #define DPA_STATS_PERCPU_LEN ARRAY_SIZE(dpa_stats_percpu)
+ #define DPA_STATS_GLOBAL_LEN ARRAY_SIZE(dpa_stats_global)
+-static int __cold dpa_get_settings(struct net_device *net_dev,
+-              struct ethtool_cmd *et_cmd)
++static int __cold dpa_get_ksettings(struct net_device *net_dev,
++              struct ethtool_link_ksettings *cmd)
+ {
+       int                      _errno;
+       struct dpa_priv_s       *priv;
+@@ -101,15 +101,13 @@ static int __cold dpa_get_settings(struc
+               return 0;
+       }
+-      _errno = phy_ethtool_gset(priv->mac_dev->phy_dev, et_cmd);
+-      if (unlikely(_errno < 0))
+-              netdev_err(net_dev, "phy_ethtool_gset() = %d\n", _errno);
++      phy_ethtool_ksettings_get(priv->mac_dev->phy_dev, cmd);
+       return _errno;
+ }
+-static int __cold dpa_set_settings(struct net_device *net_dev,
+-              struct ethtool_cmd *et_cmd)
++static int __cold dpa_set_ksettings(struct net_device *net_dev,
++              struct ethtool_link_ksettings *cmd)
+ {
+       int                      _errno;
+       struct dpa_priv_s       *priv;
+@@ -125,9 +123,9 @@ static int __cold dpa_set_settings(struc
+               return -ENODEV;
+       }
+-      _errno = phy_ethtool_sset(priv->mac_dev->phy_dev, et_cmd);
++      _errno = phy_ethtool_ksettings_set(priv->mac_dev->phy_dev, cmd);
+       if (unlikely(_errno < 0))
+-              netdev_err(net_dev, "phy_ethtool_sset() = %d\n", _errno);
++              netdev_err(net_dev, "phy_ethtool_ksettings_set() = %d\n", _errno);
+       return _errno;
+ }
+@@ -522,8 +520,8 @@ static void dpa_get_strings(struct net_d
+ }
+ const struct ethtool_ops dpa_ethtool_ops = {
+-      .get_settings = dpa_get_settings,
+-      .set_settings = dpa_set_settings,
++      .get_link_ksettings = dpa_get_ksettings,
++      .set_link_ksettings = dpa_set_ksettings,
+       .get_drvinfo = dpa_get_drvinfo,
+       .get_msglevel = dpa_get_msglevel,
+       .set_msglevel = dpa_set_msglevel,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0019-sdk_dpaa-fix-dpa_set_ksettings.patch b/target/linux/layerscape/patches-5.4/701-net-0019-sdk_dpaa-fix-dpa_set_ksettings.patch
new file mode 100644 (file)
index 0000000..432591e
--- /dev/null
@@ -0,0 +1,21 @@
+From 3ffb14b6f3ddd9d8befe08482e31bc34103cf953 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Thu, 31 Aug 2017 09:08:15 +0300
+Subject: [PATCH] sdk_dpaa: fix dpa_set_ksettings
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c
+@@ -107,7 +107,7 @@ static int __cold dpa_get_ksettings(stru
+ }
+ static int __cold dpa_set_ksettings(struct net_device *net_dev,
+-              struct ethtool_link_ksettings *cmd)
++              const struct ethtool_link_ksettings *cmd)
+ {
+       int                      _errno;
+       struct dpa_priv_s       *priv;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0020-dpaa_eth-memac-set-adjust_link-callback-for-fixed-li.patch b/target/linux/layerscape/patches-5.4/701-net-0020-dpaa_eth-memac-set-adjust_link-callback-for-fixed-li.patch
new file mode 100644 (file)
index 0000000..c2a76ae
--- /dev/null
@@ -0,0 +1,28 @@
+From 47113bd7cb07c2399f536a2dd8f4b3a6c599dfcd Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Thu, 31 Aug 2017 13:16:47 +0300
+Subject: [PATCH] dpaa_eth: memac: set adjust_link callback for fixed link
+ interfaces
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c
+@@ -503,11 +503,9 @@ static int memac_init_phy(struct net_dev
+ {
+       struct phy_device       *phy_dev;
+-      if (of_phy_is_fixed_link(mac_dev->phy_node)) {
+-              phy_dev = of_phy_attach(net_dev, mac_dev->phy_node,
+-                                      0, mac_dev->phy_if);
+-      } else if ((macdev2enetinterface(mac_dev) == e_ENET_MODE_XGMII_10000) ||
+-                 (macdev2enetinterface(mac_dev) == e_ENET_MODE_SGMII_2500)) {
++      if ((macdev2enetinterface(mac_dev) == e_ENET_MODE_XGMII_10000) ||
++          (macdev2enetinterface(mac_dev) == e_ENET_MODE_SGMII_2500) ||
++          of_phy_is_fixed_link(mac_dev->phy_node)) {
+               phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
+                                        &adjust_link_void, 0,
+                                        mac_dev->phy_if);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0021-sdk_dpaa-ls1043a-errata-resplit-the-skb-after-copy.patch b/target/linux/layerscape/patches-5.4/701-net-0021-sdk_dpaa-ls1043a-errata-resplit-the-skb-after-copy.patch
new file mode 100644 (file)
index 0000000..a9512cc
--- /dev/null
@@ -0,0 +1,31 @@
+From 3532c45dc451d2bb7d88a33a554a86422828c9aa Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Thu, 13 Jul 2017 17:26:02 +0300
+Subject: [PATCH] sdk_dpaa: ls1043a errata: resplit the skb after copy
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -1016,6 +1016,7 @@ int __hot dpa_tx_extended(struct sk_buff
+ #endif /* CONFIG_FSL_DPAA_TS */
+ #ifndef CONFIG_PPC
++resplit_4k:
+       if (unlikely(dpaa_errata_a010022)) {
+               skb = split_skb_at_4k_boundaries(skb);
+               if (!skb)
+@@ -1062,6 +1063,10 @@ int __hot dpa_tx_extended(struct sk_buff
+                       struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);
+                       kfree_skb(skb);
+                       skb = nskb;
++#ifndef CONFIG_PPC
++                      if (unlikely(dpaa_errata_a010022))
++                              goto resplit_4k;
++#endif
+                       /* skb_copy() has now linearized the skbuff. */
+               } else if (unlikely(nonlinear)) {
+                       /* We are here because the egress skb contains
diff --git a/target/linux/layerscape/patches-5.4/701-net-0022-sdk_dpaa-ls1043a-errata-realign-and-linearize-egress.patch b/target/linux/layerscape/patches-5.4/701-net-0022-sdk_dpaa-ls1043a-errata-realign-and-linearize-egress.patch
new file mode 100644 (file)
index 0000000..3e89b3d
--- /dev/null
@@ -0,0 +1,205 @@
+From 9821d27a36704d19c57d4b6c52585b9868703633 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 4 Sep 2017 13:41:17 +0300
+Subject: [PATCH] sdk_dpaa: ls1043a errata: realign and linearize egress skbs
+
+Allocate a new page and copy the skb's contents to it in order to
+guarantee that 4k boundary crossings do not occur.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c  | 159 +++++++++++----------
+ 1 file changed, 84 insertions(+), 75 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -742,86 +742,94 @@ int __hot skb_to_contig_fd(struct dpa_pr
+ EXPORT_SYMBOL(skb_to_contig_fd);
+ #ifndef CONFIG_PPC
+-struct sk_buff *split_skb_at_4k_boundaries(struct sk_buff *skb)
++/* Verify the conditions that trigger the A010022 errata: 4K memory address
++ * crossings.
++ */
++bool a010022_check_skb(struct sk_buff *skb)
+ {
+-      unsigned int length, nr_frags, moved_len = 0;
+-      u64 page_start;
+-      struct page *page;
++      int nr_frags, i = 0;
+       skb_frag_t *frag;
+-      int i = 0, j = 0;
+-      /* make sure skb is not shared */
+-      skb = skb_share_check(skb, GFP_ATOMIC);
+-      if (!skb)
+-              return NULL;
++      /* Check if the headroom crosses a boundary */
++      if (HAS_DMA_ISSUE(skb->head, skb_headroom(skb)))
++              return true;
++
++      /* Check if the non-paged data crosses a boundary */
++      if (HAS_DMA_ISSUE(skb->data, skb_headlen(skb)))
++              return true;
++
++      /* Check if the entire linear skb crosses a boundary */
++      if (HAS_DMA_ISSUE(skb->head, skb_end_offset(skb)))
++              return true;
+       nr_frags = skb_shinfo(skb)->nr_frags;
+-      page_start = (u64)skb->data;
+-      /* split the linear part at the first 4k boundary and create one (big)
+-       * fragment with the rest
+-       */
+-      if (HAS_DMA_ISSUE(skb->data, skb_headlen(skb))) {
+-              /* we'll add one more frag, make sure there's room */
+-              if (nr_frags + 1 > DPA_SGT_MAX_ENTRIES)
+-                      return NULL;
+-
+-              /* next page boundary */
+-              page_start = (page_start + 0x1000) & ~0xFFF;
+-              page = virt_to_page(page_start);
+-
+-              /* move the rest of fragments to make room for a new one at j */
+-              for (i = nr_frags - 1; i >= j;  i--)
+-                      skb_shinfo(skb)->frags[i + 1] = skb_shinfo(skb)->frags[i];
+-
+-              /* move length bytes to a paged fragment at j */
+-              length = min((u64)0x1000,
+-                           (u64)skb->data + skb_headlen(skb) - page_start);
+-              skb->data_len += length;
+-              moved_len += length;
+-              skb_fill_page_desc(skb, j++, page, 0, length);
+-              get_page(page);
+-              skb_shinfo(skb)->nr_frags = ++nr_frags;
++      while (i < nr_frags) {
++              frag = &skb_shinfo(skb)->frags[i];
++
++              /* Check if the paged fragment crosses a boundary from its
++               * offset to its end.
++               */
++              if (HAS_DMA_ISSUE(frag->page_offset, frag->size))
++                      return true;
++
++              i++;
+       }
+-      /* adjust the tail pointer */
+-      skb->tail -= moved_len;
+-      j = 0;
+-
+-      /* split any paged fragment that crosses a 4K boundary */
+-      while (j < nr_frags) {
+-              frag = &skb_shinfo(skb)->frags[j];
+-
+-              /* if there is a 4K boundary between the fragment's offset and end */
+-              if (HAS_DMA_ISSUE(frag->page_offset, frag->size)) {
+-                      /* we'll add one more frag, make sure there's room */
+-                      if (nr_frags + 1 > DPA_SGT_MAX_ENTRIES)
+-                              return NULL;
+-
+-                      /* new page boundary */
+-                      page_start = (u64)page_address(skb_frag_page(frag)) +
+-                                                frag->page_offset + 0x1000;
+-                      page_start = (u64)page_start & ~0xFFF;
+-                      page = virt_to_page(page_start);
+-
+-                      /* move the rest of fragments to make room for a new one at j+1 */
+-                      for (i = nr_frags - 1; i > j;  i--)
+-                              skb_shinfo(skb)->frags[i + 1] =
+-                                              skb_shinfo(skb)->frags[i];
+-
+-                      /* move length bytes to a new paged fragment at j+1 */
+-                      length = (u64)page_address(skb_frag_page(frag)) +
+-                               frag->page_offset + frag->size - page_start;
+-                      frag->size -= length;
+-                      skb_fill_page_desc(skb, j + 1, page, 0, length);
+-                      get_page(page);
+-                      skb_shinfo(skb)->nr_frags = ++nr_frags;
+-              }
+-              /* move to next frag */
+-              j++;
++      return false;
++}
++
++/* Realign the skb by copying its contents at the start of a newly allocated
++ * page. Build a new skb around the new buffer and release the old one.
++ * A performance drop should be expected.
++ */
++struct sk_buff *a010022_realign_skb(struct sk_buff *skb)
++{
++      int headroom = skb_headroom(skb);
++      struct sk_buff *nskb = NULL;
++      struct page *npage;
++      void *npage_addr;
++      int nsize;
++
++      npage = alloc_page(GFP_ATOMIC);
++      if (unlikely(!npage)) {
++              WARN_ONCE(1, "Memory allocation failure\n");
++              return NULL;
++      }
++      npage_addr = page_address(npage);
++
++      /* For the new skb we only need the old one's data (both non-paged and
++       * paged) and a headroom large enough to fit our private info. We can
++       * skip the old tailroom.
++       *
++       * Make sure the new linearized buffer will not exceed a page's size.
++       */
++      nsize = headroom + skb->len +
++              SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
++      if (unlikely(nsize > 4096))
++              goto err;
++
++      nskb = build_skb(npage_addr, nsize);
++      if (unlikely(!nskb))
++              goto err;
++
++      /* Code borrowed and adapted from skb_copy() */
++      skb_reserve(nskb, headroom);
++      skb_put(nskb, skb->len);
++      if (skb_copy_bits(skb, 0, nskb->data, skb->len)) {
++              WARN_ONCE(1, "skb parsing failure\n");
++              goto err;
+       }
++      copy_skb_header(nskb, skb);
++
++      dev_kfree_skb(skb);
++      return nskb;
+-      return skb;
++err:
++      if (nskb)
++              dev_kfree_skb(nskb);
++      put_page(npage);
++      return NULL;
+ }
+ #endif
+@@ -1016,9 +1024,9 @@ int __hot dpa_tx_extended(struct sk_buff
+ #endif /* CONFIG_FSL_DPAA_TS */
+ #ifndef CONFIG_PPC
+-resplit_4k:
+-      if (unlikely(dpaa_errata_a010022)) {
+-              skb = split_skb_at_4k_boundaries(skb);
++realign_4k:
++      if (unlikely(dpaa_errata_a010022) && a010022_check_skb(skb)) {
++              skb = a010022_realign_skb(skb);
+               if (!skb)
+                       goto skb_to_fd_failed;
+       }
+@@ -1064,8 +1072,9 @@ resplit_4k:
+                       kfree_skb(skb);
+                       skb = nskb;
+ #ifndef CONFIG_PPC
+-                      if (unlikely(dpaa_errata_a010022))
+-                              goto resplit_4k;
++                      if (unlikely(dpaa_errata_a010022) &&
++                          a010022_check_skb(skb))
++                              goto realign_4k;
+ #endif
+                       /* skb_copy() has now linearized the skbuff. */
+               } else if (unlikely(nonlinear)) {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0023-sdk_dpaa-ls1043a-errata-realign-skb-in-place-if-need.patch b/target/linux/layerscape/patches-5.4/701-net-0023-sdk_dpaa-ls1043a-errata-realign-skb-in-place-if-need.patch
new file mode 100644 (file)
index 0000000..1eda4ae
--- /dev/null
@@ -0,0 +1,34 @@
+From 5a2ba8a9c6b2686aa94a8d5ac35beddf38cba24a Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 4 Sep 2017 13:46:00 +0300
+Subject: [PATCH] sdk_dpaa: ls1043a errata: realign skb in place if needed
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -1024,7 +1024,6 @@ int __hot dpa_tx_extended(struct sk_buff
+ #endif /* CONFIG_FSL_DPAA_TS */
+ #ifndef CONFIG_PPC
+-realign_4k:
+       if (unlikely(dpaa_errata_a010022) && a010022_check_skb(skb)) {
+               skb = a010022_realign_skb(skb);
+               if (!skb)
+@@ -1073,8 +1072,11 @@ realign_4k:
+                       skb = nskb;
+ #ifndef CONFIG_PPC
+                       if (unlikely(dpaa_errata_a010022) &&
+-                          a010022_check_skb(skb))
+-                              goto realign_4k;
++                          a010022_check_skb(skb)) {
++                              skb = realign_skb(skb);
++                              if (!skb)
++                                      goto skb_to_fd_failed;
++                      }
+ #endif
+                       /* skb_copy() has now linearized the skbuff. */
+               } else if (unlikely(nonlinear)) {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0024-sdk_dpaa-ls1043a-errata-verify-and-resize-headroom-a.patch b/target/linux/layerscape/patches-5.4/701-net-0024-sdk_dpaa-ls1043a-errata-verify-and-resize-headroom-a.patch
new file mode 100644 (file)
index 0000000..6014de9
--- /dev/null
@@ -0,0 +1,106 @@
+From f6413a7e32d1f98a258e0ed9abd4df3159902fd3 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 4 Sep 2017 13:57:21 +0300
+Subject: [PATCH] sdk_dpaa: ls1043a errata: verify and resize headroom
+ alignment
+
+If the skb's headroom isn't aligned to 16 bytes, reallocate the entire
+skb and resize its headroom to priv->tx_headroom. Update the pointers
+to the network and transport headers accordingly.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c  | 38 +++++++++++++++-------
+ 1 file changed, 27 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -742,14 +742,19 @@ int __hot skb_to_contig_fd(struct dpa_pr
+ EXPORT_SYMBOL(skb_to_contig_fd);
+ #ifndef CONFIG_PPC
+-/* Verify the conditions that trigger the A010022 errata: 4K memory address
+- * crossings.
++/* Verify the conditions that trigger the A010022 errata: data unaligned to
++ * 16 bytes and 4K memory address crossings.
+  */
+-bool a010022_check_skb(struct sk_buff *skb)
++static bool a010022_check_skb(struct sk_buff *skb, struct dpa_priv_s *priv)
+ {
+       int nr_frags, i = 0;
+       skb_frag_t *frag;
++      /* Check if the headroom is aligned */
++      if (((u16)skb->data - priv->tx_headroom) %
++          priv->buf_layout[TX].data_align != 0)
++              return true;
++
+       /* Check if the headroom crosses a boundary */
+       if (HAS_DMA_ISSUE(skb->head, skb_headroom(skb)))
+               return true;
+@@ -767,7 +772,7 @@ bool a010022_check_skb(struct sk_buff *s
+       while (i < nr_frags) {
+               frag = &skb_shinfo(skb)->frags[i];
+-              /* Check if the paged fragment crosses a boundary from its
++              /* Check if a paged fragment crosses a boundary from its
+                * offset to its end.
+                */
+               if (HAS_DMA_ISSUE(frag->page_offset, frag->size))
+@@ -783,13 +788,17 @@ bool a010022_check_skb(struct sk_buff *s
+  * page. Build a new skb around the new buffer and release the old one.
+  * A performance drop should be expected.
+  */
+-struct sk_buff *a010022_realign_skb(struct sk_buff *skb)
++static struct sk_buff *a010022_realign_skb(struct sk_buff *skb,
++                                         struct dpa_priv_s *priv)
+ {
+-      int headroom = skb_headroom(skb);
++      int trans_offset = skb_transport_offset(skb);
++      int net_offset = skb_network_offset(skb);
+       struct sk_buff *nskb = NULL;
++      int nsize, headroom;
+       struct page *npage;
+       void *npage_addr;
+-      int nsize;
++
++      headroom = priv->tx_headroom;
+       npage = alloc_page(GFP_ATOMIC);
+       if (unlikely(!npage)) {
+@@ -822,6 +831,13 @@ struct sk_buff *a010022_realign_skb(stru
+       }
+       copy_skb_header(nskb, skb);
++      /* We move the headroom when we align it so we have to reset the
++       * network and transport header offsets relative to the new data
++       * pointer. The checksum offload relies on these offsets.
++       */
++      skb_set_network_header(nskb, net_offset);
++      skb_set_transport_header(nskb, trans_offset);
++
+       dev_kfree_skb(skb);
+       return nskb;
+@@ -1024,8 +1040,8 @@ int __hot dpa_tx_extended(struct sk_buff
+ #endif /* CONFIG_FSL_DPAA_TS */
+ #ifndef CONFIG_PPC
+-      if (unlikely(dpaa_errata_a010022) && a010022_check_skb(skb)) {
+-              skb = a010022_realign_skb(skb);
++      if (unlikely(dpaa_errata_a010022) && a010022_check_skb(skb, priv)) {
++              skb = a010022_realign_skb(skb, priv);
+               if (!skb)
+                       goto skb_to_fd_failed;
+       }
+@@ -1072,8 +1088,8 @@ int __hot dpa_tx_extended(struct sk_buff
+                       skb = nskb;
+ #ifndef CONFIG_PPC
+                       if (unlikely(dpaa_errata_a010022) &&
+-                          a010022_check_skb(skb)) {
+-                              skb = realign_skb(skb);
++                          a010022_check_skb(skb, priv)) {
++                              skb = a010022_realign_skb(skb, priv);
+                               if (!skb)
+                                       goto skb_to_fd_failed;
+                       }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0025-sdk_dpaa-ls1043a-errata-do-not-recycle-the-realigned.patch b/target/linux/layerscape/patches-5.4/701-net-0025-sdk_dpaa-ls1043a-errata-do-not-recycle-the-realigned.patch
new file mode 100644 (file)
index 0000000..4030385
--- /dev/null
@@ -0,0 +1,61 @@
+From e8c0a77a831843a66b3ac0048aa6c76bc39b0332 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 4 Sep 2017 14:03:01 +0300
+Subject: [PATCH] sdk_dpaa: ls1043a errata: do not recycle the realigned
+ buffers
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h    | 10 ++++++----
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c |  9 +++++++++
+ 2 files changed, 15 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
+@@ -680,15 +680,17 @@ static inline void _dpa_bp_free_pf(void
+       put_page(virt_to_head_page(addr));
+ }
+-/* TODO: LS1043A SoC has a HW issue regarding FMan DMA transactions; The issue
+- * manifests itself at high traffic rates when frames exceed 4K memory
+- * boundaries; For the moment, we use a SW workaround to avoid frames larger
+- * than 4K or that exceed 4K alignments.
++/* LS1043A SoC has a HW issue regarding FMan DMA transactions; The issue
++ * manifests itself at high traffic rates when frames cross 4K memory
++ * boundaries or when they are not aligned to 16 bytes; For the moment, we
++ * use a SW workaround to avoid frames larger than 4K or that exceed 4K
++ * alignments and to realign the frames to 16 bytes.
+  */
+ #ifndef CONFIG_PPC
+ extern bool dpaa_errata_a010022; /* SoC affected by A010022 errata */
++#define NONREC_MARK   0x01
+ #define HAS_DMA_ISSUE(start, size) \
+       (((u64)(start) + (size)) > (((u64)(start) + 0x1000) & ~0xFFF))
+ #define BOUNDARY_4K(start, size) (((u64)(start) + (u64)(size)) & ~0xFFF)
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -302,6 +302,12 @@ EXPORT_SYMBOL(_dpa_cleanup_tx_fd);
+ #ifndef CONFIG_FSL_DPAA_TS
+ bool dpa_skb_is_recyclable(struct sk_buff *skb)
+ {
++#ifndef CONFIG_PPC
++      /* Do no recycle skbs realigned by the errata workaround */
++      if (unlikely(dpaa_errata_a010022) && skb->mark == NONREC_MARK)
++              return false;
++#endif
++
+       /* No recycling possible if skb buffer is kmalloc'ed  */
+       if (skb->head_frag == 0)
+               return false;
+@@ -838,6 +844,9 @@ static struct sk_buff *a010022_realign_s
+       skb_set_network_header(nskb, net_offset);
+       skb_set_transport_header(nskb, trans_offset);
++      /* We don't want the buffer to be recycled so we mark it accordingly */
++      nskb->mark = NONREC_MARK;
++
+       dev_kfree_skb(skb);
+       return nskb;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0026-sdk_dpaa-ls1043a-errata-fix-arm32-build.patch b/target/linux/layerscape/patches-5.4/701-net-0026-sdk_dpaa-ls1043a-errata-fix-arm32-build.patch
new file mode 100644 (file)
index 0000000..3799f8a
--- /dev/null
@@ -0,0 +1,39 @@
+From 211d0b5127a468cf0e2db20b4854252e6784cf08 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 4 Sep 2017 14:35:21 +0300
+Subject: [PATCH] sdk_dpaa: ls1043a errata: fix arm32 build
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h    | 6 ++----
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 2 +-
+ 2 files changed, 3 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
+@@ -689,12 +689,10 @@ static inline void _dpa_bp_free_pf(void
+ #ifndef CONFIG_PPC
+ extern bool dpaa_errata_a010022; /* SoC affected by A010022 errata */
+-
+ #define NONREC_MARK   0x01
+ #define HAS_DMA_ISSUE(start, size) \
+-      (((u64)(start) + (size)) > (((u64)(start) + 0x1000) & ~0xFFF))
+-#define BOUNDARY_4K(start, size) (((u64)(start) + (u64)(size)) & ~0xFFF)
+-
++      (((uintptr_t)(start) + (size)) > \
++       (((uintptr_t)(start) + 0x1000) & ~0xFFF))
+ #endif  /* !CONFIG_PPC */
+ #endif        /* __DPA_H */
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -757,7 +757,7 @@ static bool a010022_check_skb(struct sk_
+       skb_frag_t *frag;
+       /* Check if the headroom is aligned */
+-      if (((u16)skb->data - priv->tx_headroom) %
++      if (((uintptr_t)skb->data - priv->tx_headroom) %
+           priv->buf_layout[TX].data_align != 0)
+               return true;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0027-drivers-staging-fsl_qbman-Fix-SWP-Mask-in-Error-Hand.patch b/target/linux/layerscape/patches-5.4/701-net-0027-drivers-staging-fsl_qbman-Fix-SWP-Mask-in-Error-Hand.patch
new file mode 100644 (file)
index 0000000..7d04535
--- /dev/null
@@ -0,0 +1,25 @@
+From 456090fba3aabfe929be7532dbac9de82918e2ad Mon Sep 17 00:00:00 2001
+From: Roy Pledge <roy.pledge@nxp.com>
+Date: Tue, 5 Sep 2017 16:47:49 -0400
+Subject: [PATCH] drivers/staging/fsl_qbman: Fix SWP Mask in Error Handling
+
+If an ECC error occurs QBMan stores data in a register for
+debug purposes. If the memory is software portal memory then
+15 bits are used. This patch adjusts the mask to be correct.
+
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+---
+ drivers/staging/fsl_qbman/qman_config.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl_qbman/qman_config.c
++++ b/drivers/staging/fsl_qbman/qman_config.c
+@@ -254,7 +254,7 @@ static const struct qman_error_info_mdat
+       QMAN_ERR_MDATA(0x01FF, 72, "WQ context memory"),
+       QMAN_ERR_MDATA(0x00FF, 240, "CGR memory"),
+       QMAN_ERR_MDATA(0x00FF, 302, "Internal Order Restoration List memory"),
+-      QMAN_ERR_MDATA(0x01FF, 256, "SW portal ring memory"),
++      QMAN_ERR_MDATA(0x7FFF, 256, "SW portal ring memory"),
+       QMAN_ERR_MDATA(0x07FF, 181, "CEETM class queue descriptor memory"),
+       QMAN_ERR_MDATA(0x0FFF, 140, "CEETM extended SFDR memory"),
+       QMAN_ERR_MDATA(0x0FFF, 25, "CEETM logical FQ mapping memory"),
diff --git a/target/linux/layerscape/patches-5.4/701-net-0028-sdk_dpaa-avoid-crashing-on-OOM.patch b/target/linux/layerscape/patches-5.4/701-net-0028-sdk_dpaa-avoid-crashing-on-OOM.patch
new file mode 100644 (file)
index 0000000..3e42322
--- /dev/null
@@ -0,0 +1,27 @@
+From 8254c87e00992f6b14472076f435cba52ad9ff9d Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Thu, 31 Aug 2017 17:42:07 +0300
+Subject: [PATCH] sdk_dpaa: avoid crashing on OOM
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -100,8 +100,12 @@ static int _dpa_bp_add_8_bufs(const stru
+                * an entire cacheline for performance reasons.
+                */
+ #ifndef CONFIG_PPC
+-              if (unlikely(dpaa_errata_a010022))
+-                      new_buf = page_address(alloc_page(GFP_ATOMIC));
++              if (unlikely(dpaa_errata_a010022)) {
++                      struct page *new_page = alloc_page(GFP_ATOMIC);
++                      if (unlikely(!new_page))
++                              goto netdev_alloc_failed;
++                      new_buf = page_address(new_page);
++              }
+               else
+ #endif
+               new_buf = netdev_alloc_frag(SMP_CACHE_BYTES + DPA_BP_RAW_SIZE);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0029-sdk_dpaa-update-the-xmit-timestamp-to-avoid-watchdog.patch b/target/linux/layerscape/patches-5.4/701-net-0029-sdk_dpaa-update-the-xmit-timestamp-to-avoid-watchdog.patch
new file mode 100644 (file)
index 0000000..7f925f8
--- /dev/null
@@ -0,0 +1,75 @@
+From 7207c6eaead4fbcf6dfec2a185550cd30aba5071 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Thu, 7 Sep 2017 14:49:09 +0300
+Subject: [PATCH] sdk_dpaa: update the xmit timestamp to avoid watchdog
+ timeouts
+
+Update txq0's trans_start in order to prevent the netdev watchdog from
+triggering too quickly. Since we set the LLTX flag, the stack won't update
+the jiffies for other tx queues. Prevent the watchdog from checking the
+other tx queues by adding the NETIF_HW_ACCEL_MQ flag.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c    | 3 +++
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 1 +
+ include/linux/netdev_features.h                       | 2 ++
+ net/sched/sch_generic.c                               | 7 +++++++
+ 4 files changed, 13 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
+@@ -772,6 +772,9 @@ static int dpa_private_netdev_init(struc
+       /* Advertise GRO support */
+       net_dev->features |= NETIF_F_GRO;
++      /* Advertise NETIF_F_HW_ACCEL_MQ to avoid Tx timeout warnings */
++      net_dev->features |= NETIF_F_HW_ACCEL_MQ;
++
+       return dpa_netdev_init(net_dev, mac_addr, tx_timeout);
+ }
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -1140,6 +1140,7 @@ int __hot dpa_tx_extended(struct sk_buff
+       if (unlikely(dpa_xmit(priv, percpu_stats, &fd, egress_fq, conf_fq) < 0))
+               goto xmit_failed;
++      netif_trans_update(net_dev);
+       return NETDEV_TX_OK;
+ xmit_failed:
+--- a/include/linux/netdev_features.h
++++ b/include/linux/netdev_features.h
+@@ -77,6 +77,7 @@ enum {
+       NETIF_F_RX_UDP_TUNNEL_PORT_BIT, /* Offload of RX port for UDP tunnels */
+       NETIF_F_HW_TLS_TX_BIT,          /* Hardware TLS TX offload */
+       NETIF_F_HW_TLS_RX_BIT,          /* Hardware TLS RX offload */
++      NETIF_F_HW_ACCEL_MQ_BIT,        /* Hardware-accelerated multiqueue */
+       NETIF_F_GRO_HW_BIT,             /* Hardware Generic receive offload */
+       NETIF_F_HW_TLS_RECORD_BIT,      /* Offload TLS record */
+@@ -150,6 +151,7 @@ enum {
+ #define NETIF_F_GSO_UDP_L4    __NETIF_F(GSO_UDP_L4)
+ #define NETIF_F_HW_TLS_TX     __NETIF_F(HW_TLS_TX)
+ #define NETIF_F_HW_TLS_RX     __NETIF_F(HW_TLS_RX)
++#define NETIF_F_HW_ACCEL_MQ   __NETIF_F(HW_ACCEL_MQ)
+ /* Finds the next feature with the highest number of the range of start till 0.
+  */
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -440,6 +440,13 @@ static void dev_watchdog(struct timer_li
+                                       txq->trans_timeout++;
+                                       break;
+                               }
++
++                              /* Devices with HW_ACCEL_MQ have multiple txqs
++                               * but update only the first one's transmission
++                               * timestamp so avoid checking the rest.
++                               */
++                              if (dev->features & NETIF_F_HW_ACCEL_MQ)
++                                      break;
+                       }
+                       if (some_queue_timedout) {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0030-sdk_fman-resolve-arm32-compilation-issues-for-linux-.patch b/target/linux/layerscape/patches-5.4/701-net-0030-sdk_fman-resolve-arm32-compilation-issues-for-linux-.patch
new file mode 100644 (file)
index 0000000..6c0db1e
--- /dev/null
@@ -0,0 +1,81 @@
+From 1a1f2bd221d72f8e4fcb66b6b6763a158965f746 Mon Sep 17 00:00:00 2001
+From: Iordache Florinel-R70177 <florinel.iordache@nxp.com>
+Date: Mon, 11 Sep 2017 16:10:58 +0300
+Subject: [PATCH] sdk_fman: resolve arm32 compilation issues for linux-4.13
+
+Signed-off-by: Iordache Florinel-R70177 <florinel.iordache@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c | 2 ++
+ .../ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c | 2 ++
+ .../ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c | 2 ++
+ drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c    | 2 ++
+ drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c | 2 ++
+ drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c           | 2 ++
+ 6 files changed, 12 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c
+@@ -31,6 +31,8 @@
+  */
++#include "std_ext.h"
++#include "error_ext.h"
+ #include "fsl_fman_dtsec.h"
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c
+@@ -31,6 +31,8 @@
+  */
++#include "std_ext.h"
++#include "error_ext.h"
+ #include "common/general.h"
+ #include "fsl_fman_dtsec_mii_acc.h"
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c
+@@ -31,6 +31,8 @@
+  */
++#include "std_ext.h"
++#include "error_ext.h"
+ #include "fsl_fman_memac_mii_acc.h"
+ static void write_phy_reg_10g(struct memac_mii_access_mem_map *mii_regs,
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c
+@@ -30,6 +30,8 @@
+  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
++#include "std_ext.h"
++#include "error_ext.h"
+ #include "fsl_fman_kg.h"
+ /****************************************/
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c
+@@ -31,6 +31,8 @@
+  */
++#include "std_ext.h"
++#include "error_ext.h"
+ #include "common/general.h"
+ #include "fman_common.h"
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c
+@@ -31,6 +31,8 @@
+  */
++#include "std_ext.h"
++#include "error_ext.h"
+ #include <linux/math64.h>
+ #include "fsl_fman.h"
+ #include "dpaa_integration_ext.h"
diff --git a/target/linux/layerscape/patches-5.4/701-net-0031-sdk_dpaa-ls1043a-errata-maintain-timestamp-info.patch b/target/linux/layerscape/patches-5.4/701-net-0031-sdk_dpaa-ls1043a-errata-maintain-timestamp-info.patch
new file mode 100644 (file)
index 0000000..e7fd78c
--- /dev/null
@@ -0,0 +1,101 @@
+From 2af4c8f51e2a55173f412ea51d5715378bba15be Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Thu, 14 Sep 2017 10:40:53 +0300
+Subject: [PATCH] sdk_dpaa: ls1043a errata: maintain timestamp info
+
+When creating a new skb for the errata workaround, maintain the socket
+and timestamp configurations for timestamp hardware offloading.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c  | 44 +++++++++++++++-------
+ 1 file changed, 31 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -42,6 +42,7 @@
+ #include <linux/skbuff.h>
+ #include <linux/highmem.h>
+ #include <linux/fsl_bman.h>
++#include <net/sock.h>
+ #include "dpaa_eth.h"
+ #include "dpaa_eth_common.h"
+@@ -808,7 +809,11 @@ static struct sk_buff *a010022_realign_s
+       struct page *npage;
+       void *npage_addr;
+-      headroom = priv->tx_headroom;
++      /* Guarantee the minimum required headroom */
++      if (skb_headroom(skb) >= priv->tx_headroom)
++              headroom = skb_headroom(skb);
++      else
++              headroom = priv->tx_headroom;
+       npage = alloc_page(GFP_ATOMIC);
+       if (unlikely(!npage)) {
+@@ -832,8 +837,11 @@ static struct sk_buff *a010022_realign_s
+       if (unlikely(!nskb))
+               goto err;
+-      /* Code borrowed and adapted from skb_copy() */
+-      skb_reserve(nskb, headroom);
++      /* Reserve only the needed headroom in order to guarantee the data's
++       * alignment.
++       * Code borrowed and adapted from skb_copy().
++       */
++      skb_reserve(nskb, priv->tx_headroom);
+       skb_put(nskb, skb->len);
+       if (skb_copy_bits(skb, 0, nskb->data, skb->len)) {
+               WARN_ONCE(1, "skb parsing failure\n");
+@@ -841,6 +849,16 @@ static struct sk_buff *a010022_realign_s
+       }
+       copy_skb_header(nskb, skb);
++#ifdef CONFIG_FSL_DPAA_TS
++      /* Copy relevant timestamp info from the old skb to the new */
++      if (priv->ts_tx_en) {
++              skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags;
++              skb_shinfo(nskb)->hwtstamps = skb_shinfo(skb)->hwtstamps;
++              skb_shinfo(nskb)->tskey = skb_shinfo(skb)->tskey;
++              if (skb->sk)
++                      skb_set_owner_w(nskb, skb->sk);
++      }
++#endif
+       /* We move the headroom when we align it so we have to reset the
+        * network and transport header offsets relative to the new data
+        * pointer. The checksum offload relies on these offsets.
+@@ -1041,6 +1059,16 @@ int __hot dpa_tx_extended(struct sk_buff
+       clear_fd(&fd);
++#ifndef CONFIG_PPC
++      if (unlikely(dpaa_errata_a010022) && a010022_check_skb(skb, priv)) {
++              skb = a010022_realign_skb(skb, priv);
++              if (!skb)
++                      goto skb_to_fd_failed;
++      }
++#endif
++
++      nonlinear = skb_is_nonlinear(skb);
++
+ #ifdef CONFIG_FSL_DPAA_1588
+       if (priv->tsu && priv->tsu->valid && priv->tsu->hwts_tx_en_ioctl)
+               fd.cmd |= FM_FD_CMD_UPD;
+@@ -1052,16 +1080,6 @@ int __hot dpa_tx_extended(struct sk_buff
+       skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ #endif /* CONFIG_FSL_DPAA_TS */
+-#ifndef CONFIG_PPC
+-      if (unlikely(dpaa_errata_a010022) && a010022_check_skb(skb, priv)) {
+-              skb = a010022_realign_skb(skb, priv);
+-              if (!skb)
+-                      goto skb_to_fd_failed;
+-      }
+-#endif
+-
+-      nonlinear = skb_is_nonlinear(skb);
+-
+       /* MAX_SKB_FRAGS is larger than our DPA_SGT_MAX_ENTRIES; make sure
+        * we don't feed FMan with more fragments than it supports.
+        * Btw, we're using the first sgt entry to store the linear part of
diff --git a/target/linux/layerscape/patches-5.4/701-net-0032-sdk_dpaa-ls1043a-errata-restrict-the-max-mtu.patch b/target/linux/layerscape/patches-5.4/701-net-0032-sdk_dpaa-ls1043a-errata-restrict-the-max-mtu.patch
new file mode 100644 (file)
index 0000000..7b70452
--- /dev/null
@@ -0,0 +1,33 @@
+From b204d76e9a64ec99f0151b7ca018f3b6df2bb1b7 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 19 Sep 2017 11:30:50 +0300
+Subject: [PATCH] sdk_dpaa: ls1043a errata: restrict the max mtu
+
+We can not allow for Jumbo frames and large MTU values on LS1043A due to
+the A-010022 FMan errata. All outgoing frames larger than 4K bytes are dropped.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
+@@ -263,7 +263,16 @@ EXPORT_SYMBOL(dpa_get_stats64);
+ int dpa_change_mtu(struct net_device *net_dev, int new_mtu)
+ {
+-      const int max_mtu = dpa_get_max_mtu();
++      int max_mtu = dpa_get_max_mtu();
++
++#ifndef CONFIG_PPC
++      /* Due to the A010022 FMan errata, we can not use contig frames larger
++       * than 4K, nor S/G frames. We need to prevent the user from setting a
++       * large MTU.
++       */
++      if (unlikely(dpaa_errata_a010022))
++              max_mtu = DPA_BP_RAW_SIZE;
++#endif
+       /* Make sure we don't exceed the Ethernet controller's MAXFRM */
+       if (new_mtu < 68 || new_mtu > max_mtu) {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0033-sdk_dpaa-adapt-to-the-new-API-for-MTU-changes.patch b/target/linux/layerscape/patches-5.4/701-net-0033-sdk_dpaa-adapt-to-the-new-API-for-MTU-changes.patch
new file mode 100644 (file)
index 0000000..a69e4c5
--- /dev/null
@@ -0,0 +1,86 @@
+From 828ec34f1fade88f1e751b7000959aaddfe44e5c Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Thu, 21 Sep 2017 10:50:57 +0300
+Subject: [PATCH] sdk_dpaa: adapt to the new API for MTU changes
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c | 14 +++++++++++-
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_common.c  | 25 ----------------------
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_common.h  |  1 -
+ 3 files changed, 13 insertions(+), 27 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
+@@ -681,7 +681,6 @@ static const struct net_device_ops dpa_p
+ #ifdef CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
+       .ndo_select_queue = dpa_select_queue,
+ #endif
+-      .ndo_change_mtu = dpa_change_mtu,
+       .ndo_set_rx_mode = dpa_set_rx_mode,
+       .ndo_init = dpa_ndo_init,
+       .ndo_set_features = dpa_set_features,
+@@ -758,6 +757,19 @@ static int dpa_private_netdev_init(struc
+       net_dev->mem_start = priv->mac_dev->res->start;
+       net_dev->mem_end = priv->mac_dev->res->end;
++      /* Configure the maximum MTU according to the FMan's MAXFRM */
++      net_dev->min_mtu = ETH_MIN_MTU;
++      net_dev->max_mtu = dpa_get_max_mtu();
++
++#ifndef CONFIG_PPC
++      /* Due to the A010022 FMan errata, we can not use contig frames larger
++       * than 4K, nor S/G frames. We need to prevent the user from setting a
++       * large MTU.
++       */
++      if (unlikely(dpaa_errata_a010022))
++              net_dev->max_mtu = DPA_BP_RAW_SIZE;
++#endif
++
+       net_dev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+               NETIF_F_LLTX);
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
+@@ -261,31 +261,6 @@ dpa_get_stats64(struct net_device *net_d
+ }
+ EXPORT_SYMBOL(dpa_get_stats64);
+-int dpa_change_mtu(struct net_device *net_dev, int new_mtu)
+-{
+-      int max_mtu = dpa_get_max_mtu();
+-
+-#ifndef CONFIG_PPC
+-      /* Due to the A010022 FMan errata, we can not use contig frames larger
+-       * than 4K, nor S/G frames. We need to prevent the user from setting a
+-       * large MTU.
+-       */
+-      if (unlikely(dpaa_errata_a010022))
+-              max_mtu = DPA_BP_RAW_SIZE;
+-#endif
+-
+-      /* Make sure we don't exceed the Ethernet controller's MAXFRM */
+-      if (new_mtu < 68 || new_mtu > max_mtu) {
+-              netdev_err(net_dev, "Invalid L3 mtu %d (must be between %d and %d).\n",
+-                              new_mtu, 68, max_mtu);
+-              return -EINVAL;
+-      }
+-      net_dev->mtu = new_mtu;
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL(dpa_change_mtu);
+-
+ /* .ndo_init callback */
+ int dpa_ndo_init(struct net_device *net_dev)
+ {
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
+@@ -143,7 +143,6 @@ void __cold dpa_timeout(struct net_devic
+ void __cold
+ dpa_get_stats64(struct net_device *net_dev,
+               struct rtnl_link_stats64 *stats);
+-int dpa_change_mtu(struct net_device *net_dev, int new_mtu);
+ int dpa_ndo_init(struct net_device *net_dev);
+ int dpa_set_features(struct net_device *dev, netdev_features_t features);
+ netdev_features_t dpa_fix_features(struct net_device *dev,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0034-Extend-FM-MAC-Statistics-with-frame-size-counters-re.patch b/target/linux/layerscape/patches-5.4/701-net-0034-Extend-FM-MAC-Statistics-with-frame-size-counters-re.patch
new file mode 100644 (file)
index 0000000..d880cc8
--- /dev/null
@@ -0,0 +1,406 @@
+From 60f5101cdfbabd4cc29c02d69aa43a84fab52cf7 Mon Sep 17 00:00:00 2001
+From: Iordache Florinel-R70177 <florinel.iordache@nxp.com>
+Date: Thu, 12 Oct 2017 11:13:41 +0300
+Subject: [PATCH] Extend FM MAC Statistics with frame size counters (request
+ from Nokia)
+
+Signed-off-by: Iordache Florinel-R70177 <florinel.iordache@nxp.com>
+---
+ .../freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c  |  1 +
+ .../freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c | 16 ++++++
+ .../freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h |  1 +
+ .../sdk_fman/Peripherals/FM/MAC/fman_memac.c       | 21 ++++++++
+ .../freescale/sdk_fman/Peripherals/FM/MAC/memac.c  | 57 ++++++++++++++++++++++
+ .../freescale/sdk_fman/Peripherals/FM/MAC/tgec.c   | 42 ++++++++++++++++
+ .../sdk_fman/inc/Peripherals/fm_mac_ext.h          | 28 +++++++++++
+ .../freescale/sdk_fman/inc/flib/fsl_fman_memac.h   |  7 +++
+ .../sdk_fman/src/inc/wrapper/lnxwrp_exp_sym.h      |  2 +
+ .../sdk_fman/src/wrapper/lnxwrp_ioctls_fm.c        | 41 ++++++++++++++++
+ .../uapi/linux/fmd/Peripherals/fm_port_ioctls.h    | 25 ++++++++++
+ 11 files changed, 241 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c
+@@ -1389,6 +1389,7 @@ static void InitFmMacControllerDriver(t_
+     p_FmMacControllerDriver->f_FM_MAC_ResetCounters             = DtsecResetCounters;
+     p_FmMacControllerDriver->f_FM_MAC_GetStatistics             = DtsecGetStatistics;
++    p_FmMacControllerDriver->f_FM_MAC_GetFrameSizeCounters            = NULL;
+     p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr             = DtsecModifyMacAddress;
+     p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr            = DtsecAddHashMacAddress;
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c
+@@ -461,6 +461,22 @@ t_Error FM_MAC_GetStatistics (t_Handle h
+ /* ......................................................................... */
++t_Error FM_MAC_GetFrameSizeCounters(t_Handle h_FmMac, t_FmMacFrameSizeCounters *p_FrameSizeCounters, e_CommMode type)
++{
++    t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
++
++    SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
++
++    memset(p_FrameSizeCounters, 0, sizeof(t_FmMacFrameSizeCounters));
++
++    if (p_FmMacControllerDriver->f_FM_MAC_GetFrameSizeCounters)
++        return p_FmMacControllerDriver->f_FM_MAC_GetFrameSizeCounters(h_FmMac, p_FrameSizeCounters, type);
++
++    RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
++}
++
++/* ......................................................................... */
++
+ t_Error FM_MAC_ModifyMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr)
+ {
+     t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h
+@@ -106,6 +106,7 @@ typedef struct {
+     t_Error (*f_FM_MAC_ResetCounters) (t_Handle h_FmMac);
+     t_Error (*f_FM_MAC_GetStatistics) (t_Handle h_FmMac, t_FmMacStatistics *p_Statistics);
++    t_Error (*f_FM_MAC_GetFrameSizeCounters) (t_Handle h_FmMac, t_FmMacFrameSizeCounters *p_FrameSizeCounters, e_CommMode type);
+     t_Error (*f_FM_MAC_ModifyMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
+     t_Error (*f_FM_MAC_AddHashMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac.c
+@@ -360,24 +360,45 @@ uint64_t fman_memac_get_counter(struct m
+     case E_MEMAC_COUNTER_R64:
+         ret_val = GET_MEMAC_CNTR_64(r64);
+         break;
++    case E_MEMAC_COUNTER_T64:
++        ret_val = GET_MEMAC_CNTR_64(t64);
++        break;
+     case E_MEMAC_COUNTER_R127:
+         ret_val = GET_MEMAC_CNTR_64(r127);
+         break;
++    case E_MEMAC_COUNTER_T127:
++        ret_val = GET_MEMAC_CNTR_64(t127);
++        break;
+     case E_MEMAC_COUNTER_R255:
+         ret_val = GET_MEMAC_CNTR_64(r255);
+         break;
++    case E_MEMAC_COUNTER_T255:
++        ret_val = GET_MEMAC_CNTR_64(t255);
++        break;
+     case E_MEMAC_COUNTER_R511:
+         ret_val = GET_MEMAC_CNTR_64(r511);
+         break;
++    case E_MEMAC_COUNTER_T511:
++        ret_val = GET_MEMAC_CNTR_64(t511);
++        break;
+     case E_MEMAC_COUNTER_R1023:
+         ret_val = GET_MEMAC_CNTR_64(r1023);
+         break;
++    case E_MEMAC_COUNTER_T1023:
++        ret_val = GET_MEMAC_CNTR_64(t1023);
++        break;
+     case E_MEMAC_COUNTER_R1518:
+         ret_val = GET_MEMAC_CNTR_64(r1518);
+         break;
++    case E_MEMAC_COUNTER_T1518:
++        ret_val = GET_MEMAC_CNTR_64(t1518);
++        break;
+     case E_MEMAC_COUNTER_R1519X:
+         ret_val = GET_MEMAC_CNTR_64(r1519x);
+         break;
++    case E_MEMAC_COUNTER_T1519X:
++        ret_val = GET_MEMAC_CNTR_64(t1519x);
++        break;
+     case E_MEMAC_COUNTER_RFRG:
+         ret_val = GET_MEMAC_CNTR_64(rfrg);
+         break;
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c
+@@ -593,6 +593,62 @@ static t_Error MemacGetStatistics(t_Hand
+ /* ......................................................................... */
++static t_Error MemacGetFrameSizeCounters(t_Handle h_Memac, t_FmMacFrameSizeCounters *p_FrameSizeCounters, e_CommMode type)
++{
++    t_Memac     *p_Memac = (t_Memac *)h_Memac;
++
++    SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FrameSizeCounters, E_NULL_POINTER);
++
++    switch (type)
++    {
++    case e_COMM_MODE_NONE:
++      break;
++
++    case e_COMM_MODE_RX:
++        p_FrameSizeCounters->count_pkts_64             = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R64);
++        p_FrameSizeCounters->count_pkts_65_to_127      = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R127);
++        p_FrameSizeCounters->count_pkts_128_to_255     = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R255);
++        p_FrameSizeCounters->count_pkts_256_to_511     = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R511);
++        p_FrameSizeCounters->count_pkts_512_to_1023    = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1023);
++        p_FrameSizeCounters->count_pkts_1024_to_1518   = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1518);
++        p_FrameSizeCounters->count_pkts_1519_to_1522   = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1519X);
++      break;
++
++    case e_COMM_MODE_TX:
++        p_FrameSizeCounters->count_pkts_64             = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T64);
++        p_FrameSizeCounters->count_pkts_65_to_127      = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T127);
++        p_FrameSizeCounters->count_pkts_128_to_255     = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T255);
++        p_FrameSizeCounters->count_pkts_256_to_511     = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T511);
++        p_FrameSizeCounters->count_pkts_512_to_1023    = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1023);
++        p_FrameSizeCounters->count_pkts_1024_to_1518   = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1518);
++        p_FrameSizeCounters->count_pkts_1519_to_1522   = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1519X);
++      break;
++
++    case e_COMM_MODE_RX_AND_TX:
++        p_FrameSizeCounters->count_pkts_64             = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R64)
++                                                       + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T64);
++        p_FrameSizeCounters->count_pkts_65_to_127      = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R127)
++                                                       + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T127);
++        p_FrameSizeCounters->count_pkts_128_to_255     = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R255)
++                                                       + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T255);
++        p_FrameSizeCounters->count_pkts_256_to_511     = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R511)
++                                                       + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T511);
++        p_FrameSizeCounters->count_pkts_512_to_1023    = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1023)
++                                                       + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1023);
++        p_FrameSizeCounters->count_pkts_1024_to_1518   = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1518)
++                                                       + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1518);
++        p_FrameSizeCounters->count_pkts_1519_to_1522   = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1519X)
++                                                       + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1519X);
++      break;
++    }
++
++    return E_OK;
++}
++
++/* ......................................................................... */
++
+ static t_Error MemacModifyMacAddress (t_Handle h_Memac, t_EnetAddr *p_EnetAddr)
+ {
+     t_Memac     *p_Memac = (t_Memac *)h_Memac;
+@@ -1025,6 +1081,7 @@ static void InitFmMacControllerDriver(t_
+     p_FmMacControllerDriver->f_FM_MAC_ResetCounters             = MemacResetCounters;
+     p_FmMacControllerDriver->f_FM_MAC_GetStatistics             = MemacGetStatistics;
++    p_FmMacControllerDriver->f_FM_MAC_GetFrameSizeCounters      = MemacGetFrameSizeCounters;
+     p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr             = MemacModifyMacAddress;
+     p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr            = MemacAddHashMacAddress;
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.c
+@@ -438,6 +438,47 @@ static t_Error TgecGetStatistics(t_Handl
+ /* ......................................................................... */
++static t_Error TgecGetFrameSizeCounters(t_Handle h_Tgec, t_FmMacFrameSizeCounters *p_FrameSizeCounters, e_CommMode type)
++{
++    t_Tgec              *p_Tgec = (t_Tgec *)h_Tgec;
++    struct tgec_regs    *p_TgecMemMap;
++
++    SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER);
++    SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
++    SANITY_CHECK_RETURN_ERROR(p_FrameSizeCounters, E_NULL_POINTER);
++
++    p_TgecMemMap = p_Tgec->p_MemMap;
++
++    switch (type)
++    {
++    case e_COMM_MODE_NONE:
++      break;
++
++    case e_COMM_MODE_RX:
++        p_FrameSizeCounters->count_pkts_64             = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R64);
++        p_FrameSizeCounters->count_pkts_65_to_127      = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R127);
++        p_FrameSizeCounters->count_pkts_128_to_255     = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R255);
++        p_FrameSizeCounters->count_pkts_256_to_511     = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R511);
++        p_FrameSizeCounters->count_pkts_512_to_1023    = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1023);
++        p_FrameSizeCounters->count_pkts_1024_to_1518   = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1518);
++        p_FrameSizeCounters->count_pkts_1519_to_1522   = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1519X);
++      break;
++
++    case e_COMM_MODE_TX:
++      //Tx counters not supported
++      break;
++
++    case e_COMM_MODE_RX_AND_TX:
++      //Tx counters not supported
++      break;
++    }
++
++    return E_OK;
++}
++
++
++/* ......................................................................... */
++
+ static t_Error TgecEnable1588TimeStamp(t_Handle h_Tgec)
+ {
+     t_Tgec      *p_Tgec = (t_Tgec *)h_Tgec;
+@@ -905,6 +946,7 @@ static void InitFmMacControllerDriver(t_
+     p_FmMacControllerDriver->f_FM_MAC_ResetCounters             = TgecResetCounters;
+     p_FmMacControllerDriver->f_FM_MAC_GetStatistics             = TgecGetStatistics;
++    p_FmMacControllerDriver->f_FM_MAC_GetFrameSizeCounters      = TgecGetFrameSizeCounters;
+     p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr             = TgecModifyMacAddress;
+     p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr            = TgecAddHashMacAddress;
+--- a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_mac_ext.h
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_mac_ext.h
+@@ -197,6 +197,19 @@ typedef struct t_FmMacStatistics {
+                                                - Other */
+ } t_FmMacStatistics;
++/**************************************************************************//**
++ @Description   FM MAC Frame Size Counters
++*//***************************************************************************/
++typedef struct t_FmMacFrameSizeCounters {
++
++        uint64_t  count_pkts_64;            /**< 64 byte frame counter */
++        uint64_t  count_pkts_65_to_127;     /**< 65 to 127 byte frame counter */
++        uint64_t  count_pkts_128_to_255;    /**< 128 to 255 byte frame counter */
++        uint64_t  count_pkts_256_to_511;    /**< 256 to 511 byte frame counter */
++        uint64_t  count_pkts_512_to_1023;   /**< 512 to 1023 byte frame counter */
++        uint64_t  count_pkts_1024_to_1518;  /**< 1024 to 1518 byte frame counter */
++        uint64_t  count_pkts_1519_to_1522;  /**< 1519 to 1522 byte good frame count */
++} t_FmMacFrameSizeCounters;
+ /**************************************************************************//**
+  @Group         FM_mac_init_grp FM MAC Initialization Unit
+@@ -654,6 +667,21 @@ t_Error FM_MAC_SetStatistics(t_Handle h_
+ t_Error FM_MAC_GetStatistics(t_Handle h_FmMac, t_FmMacStatistics *p_Statistics);
+ /**************************************************************************//**
++ @Function      FM_MAC_GetFrameSizeCounters
++
++ @Description   get MAC statistics counters for different frame size
++
++ @Param[in]     h_FmMac       -  A handle to a FM MAC Module.
++ @Param[in]     p_FrameSizeCounters  -  Structure with counters
++ @Param[in]     type                                  -  Type of counters to be read
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++t_Error FM_MAC_GetFrameSizeCounters(t_Handle h_FmMac, t_FmMacFrameSizeCounters *p_FrameSizeCounters, e_CommMode type);
++
++/**************************************************************************//**
+  @Function      FM_MAC_ModifyMacAddr
+  @Description   Replace the main MAC Address
+--- a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac.h
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac.h
+@@ -146,12 +146,19 @@ _val &= ~TX_FIFO_SECTIONS_TX_EMPTY_MASK;
+ enum memac_counters {
+       E_MEMAC_COUNTER_R64,
++      E_MEMAC_COUNTER_T64,
+       E_MEMAC_COUNTER_R127,
++      E_MEMAC_COUNTER_T127,
+       E_MEMAC_COUNTER_R255,
++      E_MEMAC_COUNTER_T255,
+       E_MEMAC_COUNTER_R511,
++      E_MEMAC_COUNTER_T511,
+       E_MEMAC_COUNTER_R1023,
++      E_MEMAC_COUNTER_T1023,
+       E_MEMAC_COUNTER_R1518,
++      E_MEMAC_COUNTER_T1518,
+       E_MEMAC_COUNTER_R1519X,
++      E_MEMAC_COUNTER_T1519X,
+       E_MEMAC_COUNTER_RFRG,
+       E_MEMAC_COUNTER_RJBR,
+       E_MEMAC_COUNTER_RDRP,
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_exp_sym.h
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_exp_sym.h
+@@ -123,6 +123,8 @@ EXPORT_SYMBOL(FM_PCD_SetAdvancedOffloadS
+ /* FMAN MAC exported routines */
+ EXPORT_SYMBOL(FM_MAC_GetStatistics);
++EXPORT_SYMBOL(FM_MAC_GetFrameSizeCounters);
++
+ EXPORT_SYMBOL(FM_GetSpecialOperationCoding);
+ #endif /* __LNXWRP_EXP_SYM_H */
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm.c
+@@ -4608,6 +4608,47 @@ t_Error LnxwrpFmPortIOCTL(t_LnxWrpFmPort
+             break;
+         }
++        case FM_PORT_IOC_GET_MAC_FRAME_SIZE_COUNTERS:
++        {
++            t_LnxWrpFmDev *p_LnxWrpFmDev =
++                    (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev;
++            ioc_fm_port_mac_frame_size_counters_t param;
++            t_FmMacFrameSizeCounters frameSizeCounters;
++            int mac_id = p_LnxWrpFmPortDev->id;
++
++            if (!p_LnxWrpFmDev)
++                RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Port not initialized or other error!"));
++
++            if (&p_LnxWrpFmDev->txPorts[mac_id] != p_LnxWrpFmPortDev &&
++                &p_LnxWrpFmDev->rxPorts[mac_id] != p_LnxWrpFmPortDev)
++                mac_id += FM_MAX_NUM_OF_1G_MACS; /* 10G port */
++
++            if (!p_LnxWrpFmDev->macs[mac_id].h_Dev)
++                RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Port not initialized or other error!"));
++
++            if (copy_from_user(&param, (ioc_fm_port_mac_frame_size_counters_t *)arg,
++                        sizeof(ioc_fm_port_mac_frame_size_counters_t)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++            if (FM_MAC_GetFrameSizeCounters(p_LnxWrpFmDev->macs[mac_id].h_Dev,
++                        &frameSizeCounters, param.type))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++            param.count_pkts_64 = frameSizeCounters.count_pkts_64;
++            param.count_pkts_65_to_127 = frameSizeCounters.count_pkts_65_to_127;
++            param.count_pkts_128_to_255 = frameSizeCounters.count_pkts_128_to_255;
++            param.count_pkts_256_to_511 = frameSizeCounters.count_pkts_256_to_511;
++            param.count_pkts_512_to_1023 = frameSizeCounters.count_pkts_512_to_1023;
++            param.count_pkts_1024_to_1518 = frameSizeCounters.count_pkts_1024_to_1518;
++            param.count_pkts_1519_to_1522 = frameSizeCounters.count_pkts_1519_to_1522;
++
++            if (copy_to_user((ioc_fm_port_mac_frame_size_counters_t *)arg, &param,
++                        sizeof(ioc_fm_port_mac_frame_size_counters_t)))
++                RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
++
++            break;
++        }
++
+         case FM_PORT_IOC_GET_BMI_COUNTERS:
+         {
+             t_LnxWrpFmDev *p_LnxWrpFmDev =
+--- a/include/uapi/linux/fmd/Peripherals/fm_port_ioctls.h
++++ b/include/uapi/linux/fmd/Peripherals/fm_port_ioctls.h
+@@ -939,6 +939,31 @@ typedef struct ioc_fm_port_vsp_alloc_par
+ #define FM_PORT_IOC_GET_BMI_COUNTERS _IOR(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(42), ioc_fm_port_bmi_stats_t)
++typedef struct ioc_fm_port_mac_frame_size_counters_t {
++
++        e_CommMode type;
++        uint64_t  count_pkts_64;            /**< 64 byte frame counter */
++        uint64_t  count_pkts_65_to_127;     /**< 65 to 127 byte frame counter */
++        uint64_t  count_pkts_128_to_255;    /**< 128 to 255 byte frame counter */
++        uint64_t  count_pkts_256_to_511;    /**< 256 to 511 byte frame counter */
++        uint64_t  count_pkts_512_to_1023;   /**< 512 to 1023 byte frame counter */
++        uint64_t  count_pkts_1024_to_1518;  /**< 1024 to 1518 byte frame counter */
++        uint64_t  count_pkts_1519_to_1522;  /**< 1519 to 1522 byte good frame count */
++} ioc_fm_port_mac_frame_size_counters_t;
++
++/**************************************************************************//**
++ @Function      FM_MAC_GetFrameSizeCounters
++
++ @Description   get MAC statistics counters for different frame size
++
++ @Param[out]    ioc_fm_port_mac_frame_size_counters_t    A structure holding the counters
++
++ @Return        E_OK on success; Error code otherwise.
++
++ @Cautions      Allowed only following FM_Init().
++*//***************************************************************************/
++#define FM_PORT_IOC_GET_MAC_FRAME_SIZE_COUNTERS        _IOR(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(43), ioc_fm_port_mac_frame_size_counters_t)
++
+ /** @} */ /* end of lnx_ioctl_FM_PORT_pcd_runtime_control_grp group */
+ /** @} */ /* end of lnx_ioctl_FM_PORT_runtime_control_grp group */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0035-sdk_dpaa-accept-frames-on-RX-even-if-larger-than-MTU.patch b/target/linux/layerscape/patches-5.4/701-net-0035-sdk_dpaa-accept-frames-on-RX-even-if-larger-than-MTU.patch
new file mode 100644 (file)
index 0000000..d868498
--- /dev/null
@@ -0,0 +1,64 @@
+From ab1371fec54bdd16b5f6c56c76d817404c696d4b Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 18 Oct 2017 16:38:30 +0300
+Subject: [PATCH] sdk_dpaa: accept frames on RX even if larger than MTU
+
+Documentation/networking/netdevices.txt mentions that interfaces must
+be able to receive frames at least the size of the configured MTU. The
+behavior for received frames larger than the MTU is unspecified. We have
+been dropping these frames in software. Remove this behavior and accept
+them.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h    | 11 -----------
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 11 -----------
+ 2 files changed, 22 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
+@@ -514,17 +514,6 @@ dpa_fd_offset(const struct qm_fd *fd)
+       return fd->offset;
+ }
+-/* Verifies if the skb length is below the interface MTU */
+-static inline int dpa_check_rx_mtu(struct sk_buff *skb, int mtu)
+-{
+-      if (unlikely(skb->len > mtu))
+-              if ((skb->protocol != htons(ETH_P_8021Q))
+-                              || (skb->len > mtu + 4))
+-                      return -1;
+-
+-      return 0;
+-}
+-
+ static inline uint16_t dpa_get_headroom(struct dpa_buffer_layout_s *bl)
+ {
+       uint16_t headroom;
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -616,13 +616,6 @@ void __hot _dpa_rx(struct net_device *ne
+       (*count_ptr)--;
+       skb->protocol = eth_type_trans(skb, net_dev);
+-      /* IP Reassembled frames are allowed to be larger than MTU */
+-      if (unlikely(dpa_check_rx_mtu(skb, net_dev->mtu) &&
+-              !(fd_status & FM_FD_IPR))) {
+-              percpu_stats->rx_dropped++;
+-              goto drop_bad_frame;
+-      }
+-
+       skb_len = skb->len;
+ #ifdef CONFIG_FSL_DPAA_DBG_LOOP
+@@ -655,10 +648,6 @@ void __hot _dpa_rx(struct net_device *ne
+ packet_dropped:
+       return;
+-drop_bad_frame:
+-      dev_kfree_skb(skb);
+-      return;
+-
+ _release_frame:
+       dpa_fd_release(net_dev, fd);
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0036-sdk-dpa-use-netdev-dev-for-DMA-mapping.patch b/target/linux/layerscape/patches-5.4/701-net-0036-sdk-dpa-use-netdev-dev-for-DMA-mapping.patch
new file mode 100644 (file)
index 0000000..39631c3
--- /dev/null
@@ -0,0 +1,121 @@
+From e1ae30545347709590bab5f4a3c27e7f639c6ead Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Wed, 18 Oct 2017 19:36:59 +0300
+Subject: [PATCH] sdk: dpa: use netdev dev for DMA mapping
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c |  2 +-
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_base.c    |  2 +-
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_common.c  | 35 ++++------------------
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_common.h  |  2 +-
+ 4 files changed, 9 insertions(+), 32 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
+@@ -875,7 +875,7 @@ static int dpa_priv_bp_create(struct net
+       for (i = 0; i < count; i++) {
+               int err;
+-              err = dpa_bp_alloc(&dpa_bp[i]);
++              err = dpa_bp_alloc(&dpa_bp[i], net_dev->dev.parent);
+               if (err < 0) {
+                       dpa_bp_free(priv);
+                       priv->dpa_bp = NULL;
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c
+@@ -176,7 +176,7 @@ int dpa_bp_create(struct net_device *net
+       for (i = 0; i < count; i++) {
+               int err;
+-              err = dpa_bp_alloc(&dpa_bp[i]);
++              err = dpa_bp_alloc(&dpa_bp[i], net_dev->dev.parent);
+               if (err < 0) {
+                       dpa_bp_free(priv);
+                       priv->dpa_bp = NULL;
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
+@@ -686,11 +686,10 @@ void dpa_set_buffers_layout(struct mac_d
+ EXPORT_SYMBOL(dpa_set_buffers_layout);
+ int __attribute__((nonnull))
+-dpa_bp_alloc(struct dpa_bp *dpa_bp)
++dpa_bp_alloc(struct dpa_bp *dpa_bp, struct device *dev)
+ {
+       int err;
+       struct bman_pool_params  bp_params;
+-      struct platform_device *pdev;
+       if (dpa_bp->size == 0 || dpa_bp->config_count == 0) {
+               pr_err("Buffer pool is not properly initialized! Missing size or initial number of buffers");
+@@ -723,44 +722,25 @@ dpa_bp_alloc(struct dpa_bp *dpa_bp)
+       dpa_bp->bpid = (uint8_t)bman_get_params(dpa_bp->pool)->bpid;
+-      pdev = platform_device_register_simple("dpaa_eth_bpool",
+-                      dpa_bp->bpid, NULL, 0);
+-      if (IS_ERR(pdev)) {
+-              pr_err("platform_device_register_simple() failed\n");
+-              err = PTR_ERR(pdev);
+-              goto pdev_register_failed;
+-      }
+-      {
+-              struct dma_map_ops *ops = get_dma_ops(&pdev->dev);
+-              ops->dma_supported = NULL;
+-      }
+-      err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40));
++      err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40));
+       if (err) {
+               pr_err("dma_coerce_mask_and_coherent() failed\n");
+-              goto pdev_mask_failed;
++              goto bman_free_pool;
+       }
+-#ifdef CONFIG_FMAN_ARM
+-      /* force coherency */
+-      pdev->dev.archdata.dma_coherent = true;
+-      arch_setup_dma_ops(&pdev->dev, 0, 0, NULL, true);
+-#endif
+-      dpa_bp->dev = &pdev->dev;
++      dpa_bp->dev = dev;
+       if (dpa_bp->seed_cb) {
+               err = dpa_bp->seed_cb(dpa_bp);
+               if (err)
+-                      goto pool_seed_failed;
++                      goto bman_free_pool;
+       }
+       dpa_bpid2pool_map(dpa_bp->bpid, dpa_bp);
+       return 0;
+-pool_seed_failed:
+-pdev_mask_failed:
+-      platform_device_unregister(pdev);
+-pdev_register_failed:
++bman_free_pool:
+       bman_free_pool(dpa_bp->pool);
+       return err;
+@@ -822,9 +802,6 @@ _dpa_bp_free(struct dpa_bp *dpa_bp)
+       dpa_bp_array[bp->bpid] = NULL;
+       bman_free_pool(bp->pool);
+-
+-      if (bp->dev)
+-              platform_device_unregister(to_platform_device(bp->dev));
+ }
+ void __cold __attribute__((nonnull))
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
+@@ -163,7 +163,7 @@ void dpa_set_rx_mode(struct net_device *
+ void dpa_set_buffers_layout(struct mac_device *mac_dev,
+               struct dpa_buffer_layout_s *layout);
+ int __attribute__((nonnull))
+-dpa_bp_alloc(struct dpa_bp *dpa_bp);
++dpa_bp_alloc(struct dpa_bp *dpa_bp, struct device *dev);
+ void __cold __attribute__((nonnull))
+ dpa_bp_free(struct dpa_priv_s *priv);
+ struct dpa_bp *dpa_bpid2pool(int bpid);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0037-Added-MII-IOCTL-support-for-SIOCGMIIREG.patch b/target/linux/layerscape/patches-5.4/701-net-0037-Added-MII-IOCTL-support-for-SIOCGMIIREG.patch
new file mode 100644 (file)
index 0000000..77c1927
--- /dev/null
@@ -0,0 +1,35 @@
+From 7f87217ebf1ca84ad63d995d88eda45341273fad Mon Sep 17 00:00:00 2001
+From: Vicentiu Galanopulo <vicentiu.galanopulo@nxp.com>
+Date: Tue, 7 Nov 2017 16:15:03 +0200
+Subject: [PATCH] Added MII IOCTL support for SIOCGMIIREG
+
+Signed-off-by: Vicentiu Galanopulo <vicentiu.galanopulo@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
+@@ -444,14 +444,18 @@ int dpa_ioctl(struct net_device *dev, st
+ #ifdef CONFIG_FSL_DPAA_1588
+       struct dpa_priv_s *priv = netdev_priv(dev);
+ #endif
+-      int ret = 0;
++      int ret = -EINVAL;
+-      /* at least one timestamping feature must be enabled */
+-#ifdef CONFIG_FSL_DPAA_TS
+       if (!netif_running(dev))
+-#endif
+               return -EINVAL;
++      if (cmd == SIOCGMIIREG) {
++              if (!dev->phydev)
++                      ret = -EINVAL;
++              else
++                      ret = phy_mii_ioctl(dev->phydev, rq, cmd);
++      }
++
+ #ifdef CONFIG_FSL_DPAA_TS
+       if (cmd == SIOCSHWTSTAMP)
+               return dpa_ts_ioctl(dev, rq, cmd);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0038-sdk_dpaa-ls1043a-errata-stop-advertising-S-G-and-GSO.patch b/target/linux/layerscape/patches-5.4/701-net-0038-sdk_dpaa-ls1043a-errata-stop-advertising-S-G-and-GSO.patch
new file mode 100644 (file)
index 0000000..a7c8708
--- /dev/null
@@ -0,0 +1,52 @@
+From 4dc65101fc94270fec94599701343128c77da8fb Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 8 Nov 2017 14:37:27 +0200
+Subject: [PATCH] sdk_dpaa: ls1043a errata: stop advertising S/G and GSO
+ support
+
+The errata prevents us from transmitting S/G frames. Instead of
+linearizing them ourselves, stop advertising S/G support and have the
+stack do it for us.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c | 21 ++++++++++++---------
+ 1 file changed, 12 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
+@@ -761,15 +761,6 @@ static int dpa_private_netdev_init(struc
+       net_dev->min_mtu = ETH_MIN_MTU;
+       net_dev->max_mtu = dpa_get_max_mtu();
+-#ifndef CONFIG_PPC
+-      /* Due to the A010022 FMan errata, we can not use contig frames larger
+-       * than 4K, nor S/G frames. We need to prevent the user from setting a
+-       * large MTU.
+-       */
+-      if (unlikely(dpaa_errata_a010022))
+-              net_dev->max_mtu = DPA_BP_RAW_SIZE;
+-#endif
+-
+       net_dev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+               NETIF_F_LLTX);
+@@ -787,6 +778,18 @@ static int dpa_private_netdev_init(struc
+       /* Advertise NETIF_F_HW_ACCEL_MQ to avoid Tx timeout warnings */
+       net_dev->features |= NETIF_F_HW_ACCEL_MQ;
++#ifndef CONFIG_PPC
++      /* Due to the A010022 FMan errata, we can not use contig frames larger
++       * than 4K, nor S/G frames. We need to prevent the user from setting a
++       * large MTU. We also stop advertising S/G and GSO support.
++       */
++      if (unlikely(dpaa_errata_a010022)) {
++              net_dev->max_mtu = DPA_BP_RAW_SIZE;
++              net_dev->hw_features &= ~NETIF_F_SG;
++              net_dev->features &= ~NETIF_F_GSO;
++      }
++#endif
++
+       return dpa_netdev_init(net_dev, mac_addr, tx_timeout);
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0039-staging-fsl_qbman-Calculate-valid-bit-from-MC-RR.patch b/target/linux/layerscape/patches-5.4/701-net-0039-staging-fsl_qbman-Calculate-valid-bit-from-MC-RR.patch
new file mode 100644 (file)
index 0000000..1e4cfe8
--- /dev/null
@@ -0,0 +1,47 @@
+From 5ebee96094c5a97a89a986108242cca9d853ff55 Mon Sep 17 00:00:00 2001
+From: Roy Pledge <roy.pledge@nxp.com>
+Date: Wed, 27 Sep 2017 14:50:08 -0400
+Subject: [PATCH] staging/fsl_qbman: Calculate valid bit from MC-RR
+
+Use the management commmand response registers to determine
+the next expected valid bit when initializing a software
+portal. This avoids using the wrong valid bit in cases
+where a command was partially written but then not
+completed.
+
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+---
+ drivers/staging/fsl_qbman/qman_low.h | 19 +++++++++++++++++--
+ 1 file changed, 17 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/fsl_qbman/qman_low.h
++++ b/drivers/staging/fsl_qbman/qman_low.h
+@@ -1095,11 +1095,26 @@ static inline void qm_mr_set_ithresh(str
+ static inline int qm_mc_init(struct qm_portal *portal)
+ {
++      u8 rr0, rr1;
+       register struct qm_mc *mc = &portal->mc;
++
+       mc->cr = portal->addr.addr_ce + QM_CL_CR;
+       mc->rr = portal->addr.addr_ce + QM_CL_RR0;
+-      mc->rridx = (__raw_readb(&mc->cr->__dont_write_directly__verb) &
+-                      QM_MCC_VERB_VBIT) ?  0 : 1;
++
++      /*
++       * The expected valid bit polarity for the next CR command is 0
++       * if RR1 contains a valid response, and is 1 if RR0 contains a
++       * valid response. If both RR contain all 0, this indicates either
++       * that no command has been executed since reset (in which case the
++       * expected valid bit polarity is 1)
++       */
++      rr0 = __raw_readb(&mc->rr->verb);
++      rr1 = __raw_readb(&(mc->rr+1)->verb);
++      if ((rr0 == 0 && rr1 == 0) || rr0 != 0)
++              mc->rridx = 1;
++      else
++              mc->rridx = 0;
++
+       mc->vbit = mc->rridx ? QM_MCC_VERB_VBIT : 0;
+ #ifdef CONFIG_FSL_DPA_CHECKING
+       mc->state = qman_mc_idle;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0040-fsl_qbman-usdpaa-Invalidate-software-portals-before-.patch b/target/linux/layerscape/patches-5.4/701-net-0040-fsl_qbman-usdpaa-Invalidate-software-portals-before-.patch
new file mode 100644 (file)
index 0000000..5148f44
--- /dev/null
@@ -0,0 +1,64 @@
+From 6506f95ad4d47500275c2f3a48abb7f3de11c54b Mon Sep 17 00:00:00 2001
+From: Roy Pledge <roy.pledge@nxp.com>
+Date: Thu, 25 May 2017 16:59:08 -0400
+Subject: [PATCH] fsl_qbman/usdpaa: Invalidate software portals before use
+
+Invalidate the cache for the software portals before using them
+since the portals are non coherent. This ensures that the core
+using the portal is seeing the most up to date information in
+case the cache contained older data. This is important during
+the cleanup phase if cleanup occurs on a differnt core than
+what the application was using.
+
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+---
+ drivers/staging/fsl_qbman/fsl_usdpaa.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+--- a/drivers/staging/fsl_qbman/fsl_usdpaa.c
++++ b/drivers/staging/fsl_qbman/fsl_usdpaa.c
+@@ -371,6 +371,16 @@ static int usdpaa_open(struct inode *ino
+ #define DQRR_MAXFILL 15
++
++/* Invalidate a portal */
++void dbci_portal(void *addr)
++{
++      int i;
++
++      for (i = 0; i < 0x4000; i += 64)
++              dcbi(addr + i);
++}
++
+ /* Reset a QMan portal to its default state */
+ static int init_qm_portal(struct qm_portal_config *config,
+                         struct qm_portal *portal)
+@@ -384,6 +394,13 @@ static int init_qm_portal(struct qm_port
+       /* Make sure interrupts are inhibited */
+       qm_out(IIR, 1);
++      /*
++       * Invalidate the entire CE portal are to ensure no stale
++       * cachelines are present.  This should be done on all
++       * cores as the portal is mapped as M=0 (non-coherent).
++       */
++      on_each_cpu(dbci_portal, portal->addr.addr_ce, 1);
++
+       /* Initialize the DQRR.  This will stop any dequeue
+          commands that are in progress */
+       if (qm_dqrr_init(portal, config, qm_dqrr_dpush, qm_dqrr_pvb,
+@@ -435,6 +452,13 @@ static int init_bm_portal(struct bm_port
+       portal->addr.addr_ce = config->addr_virt[DPA_PORTAL_CE];
+       portal->addr.addr_ci = config->addr_virt[DPA_PORTAL_CI];
++      /*
++       * Invalidate the entire CE portal are to ensure no stale
++       * cachelines are present.  This should be done on all
++       * cores as the portal is mapped as M=0 (non-coherent).
++       */
++      on_each_cpu(dbci_portal, portal->addr.addr_ce, 1);
++
+       if (bm_rcr_init(portal, bm_rcr_pvb, bm_rcr_cce)) {
+               pr_err("Bman RCR initialisation failed\n");
+       return 1;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0041-net-ethernet-Rename-PHY_INTERFACE_MODE_SGMII_2500.patch b/target/linux/layerscape/patches-5.4/701-net-0041-net-ethernet-Rename-PHY_INTERFACE_MODE_SGMII_2500.patch
new file mode 100644 (file)
index 0000000..1dd0d9f
--- /dev/null
@@ -0,0 +1,34 @@
+From 15096410c230acd29b2b1bf7958b71e1f990414a Mon Sep 17 00:00:00 2001
+From: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+Date: Wed, 29 Nov 2017 06:48:54 +0530
+Subject: [PATCH] net: ethernet: Rename PHY_INTERFACE_MODE_SGMII_2500
+
+Rename PHY_INTERFACE_MODE_SGMII_2500 to PHY_INTERFACE_MODE_2500SGMII
+Convention is to put the number(2500) first and then the
+interface mode(SGMII)
+
+Signed-off-by: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/mac.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/mac.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac.c
+@@ -76,7 +76,7 @@ static const char phy_str[][11] = {
+       [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
+       [PHY_INTERFACE_MODE_RTBI]       = "rtbi",
+       [PHY_INTERFACE_MODE_XGMII]      = "xgmii",
+-      [PHY_INTERFACE_MODE_SGMII_2500] = "sgmii-2500",
++      [PHY_INTERFACE_MODE_2500SGMII] = "sgmii-2500",
+ };
+ static phy_interface_t __pure __attribute__((nonnull)) str2phy(const char *str)
+@@ -103,7 +103,7 @@ static const uint16_t phy2speed[] = {
+       [PHY_INTERFACE_MODE_RGMII_TXID] = SPEED_1000,
+       [PHY_INTERFACE_MODE_RTBI]       = SPEED_1000,
+       [PHY_INTERFACE_MODE_XGMII]      = SPEED_10000,
+-      [PHY_INTERFACE_MODE_SGMII_2500] = SPEED_2500,
++      [PHY_INTERFACE_MODE_2500SGMII] = SPEED_2500,
+ };
+ static struct mac_device * __cold
diff --git a/target/linux/layerscape/patches-5.4/701-net-0042-sdk_dpaa-ceetm-add-independent-CEETM-congestion-thre.patch b/target/linux/layerscape/patches-5.4/701-net-0042-sdk_dpaa-ceetm-add-independent-CEETM-congestion-thre.patch
new file mode 100644 (file)
index 0000000..461280b
--- /dev/null
@@ -0,0 +1,61 @@
+From aa54d82b06962bb620852ed20270f7783be68897 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Fri, 24 Nov 2017 10:29:12 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: add independent CEETM congestion thresholds
+
+Configure the CEETM egress congestion thresholds independently from the
+default Ethernet driver's Work Queues. Allow the user to edit the
+thresholds through menuconfig.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/Kconfig    | 23 ++++++++++++++++++++++
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   |  4 ++--
+ 2 files changed, 25 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig
+@@ -20,6 +20,29 @@ config FSL_DPAA_CEETM
+       help
+       Enable QoS offloading support through the CEETM hardware block.
++config FSL_DPAA_CEETM_CCS_THRESHOLD_1G
++      hex "CEETM egress congestion threshold on 1G ports"
++      depends on FSL_DPAA_CEETM
++      range 0x1000 0x10000000
++      default "0x000a0000"
++      help
++        The size in bytes of the CEETM egress Class Congestion State threshold on 1G ports.
++        The threshold needs to be configured keeping in mind the following factors:
++             - A threshold too large will buffer frames for a long time in the TX queues,
++             when a small shaping rate is configured. This will cause buffer pool depletion
++             or out of memory errors. This in turn will cause frame loss on RX;
++             - A threshold too small will cause unnecessary frame loss by entering
++             congestion too often.
++
++config FSL_DPAA_CEETM_CCS_THRESHOLD_10G
++      hex "CEETM egress congestion threshold on 10G ports"
++      depends on FSL_DPAA_CEETM
++      range 0x1000 0x20000000
++      default "0x00640000"
++      help
++        The size in bytes of the CEETM egress Class Congestion State threshold on 10G ports.
++        See FSL_DPAA_CEETM_CCS_THRESHOLD_1G for details.
++
+ config FSL_DPAA_OFFLINE_PORTS
+       bool "Offline Ports support"
+       depends on FSL_SDK_DPAA_ETH
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -185,9 +185,9 @@ static int ceetm_config_ccg(struct qm_ce
+       /* Set the congestion state thresholds according to the link speed */
+       if (dpa_priv->mac_dev->if_support & SUPPORTED_10000baseT_Full)
+-              cs_th = CONFIG_FSL_DPAA_CS_THRESHOLD_10G;
++              cs_th = CONFIG_FSL_DPAA_CEETM_CCS_THRESHOLD_10G;
+       else
+-              cs_th = CONFIG_FSL_DPAA_CS_THRESHOLD_1G;
++              cs_th = CONFIG_FSL_DPAA_CEETM_CCS_THRESHOLD_1G;
+       qm_cgr_cs_thres_set64(&ccg_params.cs_thres_in, cs_th, 1);
+       qm_cgr_cs_thres_set64(&ccg_params.cs_thres_out,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0043-sdk_dpaa-ceetm-stop-transmitting-frames-when-the-CQ-.patch b/target/linux/layerscape/patches-5.4/701-net-0043-sdk_dpaa-ceetm-stop-transmitting-frames-when-the-CQ-.patch
new file mode 100644 (file)
index 0000000..1f1afe3
--- /dev/null
@@ -0,0 +1,100 @@
+From 3aa939c73c176690a9ebe646612cd097f281efe5 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Fri, 24 Nov 2017 10:48:31 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: stop transmitting frames when the CQ is
+ congested
+
+When the egress CQ is congested, drop the frames instead of enqueueing
+them. This is more efficient than enqueueing and receiving them back on
+the ERN queue.
+
+We also can't stop the netdev queues because that would affect all the CQs
+and would hinder prioritization.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 22 ++++++++++++++++------
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h   |  1 +
+ 2 files changed, 17 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -125,16 +125,16 @@ static void ceetm_cscn(struct qm_ceetm_c
+               break;
+       }
++      ceetm_fq->congested = congested;
++
+       if (congested) {
+               dpa_priv->cgr_data.congestion_start_jiffies = jiffies;
+-              netif_tx_stop_all_queues(dpa_priv->net_dev);
+               dpa_priv->cgr_data.cgr_congested_count++;
+               if (cstats)
+                       cstats->congested_count++;
+       } else {
+               dpa_priv->cgr_data.congested_jiffies +=
+                       (jiffies - dpa_priv->cgr_data.congestion_start_jiffies);
+-              netif_tx_wake_all_queues(dpa_priv->net_dev);
+       }
+ }
+@@ -148,6 +148,7 @@ static int ceetm_alloc_fq(struct ceetm_f
+       (*fq)->net_dev = dev;
+       (*fq)->ceetm_cls = cls;
++      (*fq)->congested = 0;
+       return 0;
+ }
+@@ -1913,7 +1914,8 @@ int __hot ceetm_tx(struct sk_buff *skb,
+       struct Qdisc *sch = net_dev->qdisc;
+       struct ceetm_class *cl;
+       struct dpa_priv_s *priv_dpa;
+-      struct qman_fq *egress_fq, *conf_fq;
++      struct ceetm_fq *ceetm_fq;
++      struct qman_fq *conf_fq;
+       struct ceetm_qdisc *priv = qdisc_priv(sch);
+       struct ceetm_qdisc_stats *qstats = this_cpu_ptr(priv->root.qstats);
+       struct ceetm_class_stats *cstats;
+@@ -1945,11 +1947,11 @@ int __hot ceetm_tx(struct sk_buff *skb,
+        */
+       switch (cl->type) {
+       case CEETM_PRIO:
+-              egress_fq = &cl->prio.fq->fq;
++              ceetm_fq = cl->prio.fq;
+               cstats = this_cpu_ptr(cl->prio.cstats);
+               break;
+       case CEETM_WBFS:
+-              egress_fq = &cl->wbfs.fq->fq;
++              ceetm_fq = cl->wbfs.fq;
+               cstats = this_cpu_ptr(cl->wbfs.cstats);
+               break;
+       default:
+@@ -1957,8 +1959,16 @@ int __hot ceetm_tx(struct sk_buff *skb,
+               goto drop;
+       }
++      /* If the FQ is congested, avoid enqueuing the frame and dropping it
++       * when it returns on the ERN path. Drop it here directly instead.
++       */
++      if (unlikely(ceetm_fq->congested)) {
++              qstats->drops++;
++              goto drop;
++      }
++
+       bstats_update(&cstats->bstats, skb);
+-      return dpa_tx_extended(skb, net_dev, egress_fq, conf_fq);
++      return dpa_tx_extended(skb, net_dev, &ceetm_fq->fq, conf_fq);
+ drop:
+       dev_kfree_skb_any(skb);
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h
+@@ -105,6 +105,7 @@ struct ceetm_fq {
+       struct qman_fq fq;
+       struct net_device *net_dev;
+       struct ceetm_class *ceetm_cls;
++      int congested; /* Congestion status */
+ };
+ struct root_q {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0044-sdk_dpaa-ceetm-coding-style-fixes-and-added-comments.patch b/target/linux/layerscape/patches-5.4/701-net-0044-sdk_dpaa-ceetm-coding-style-fixes-and-added-comments.patch
new file mode 100644 (file)
index 0000000..982344d
--- /dev/null
@@ -0,0 +1,91 @@
+From e21cd0d3ef6f039c674b9e22581aaaabdf3a40f7 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Fri, 24 Nov 2017 11:55:51 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: coding style fixes and added comments
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 38 ++++++++++++++--------
+ 1 file changed, 24 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -69,15 +69,17 @@ static void get_dcp_and_sp(struct net_de
+ static void ceetm_ern(struct qman_portal *portal, struct qman_fq *fq,
+                     const struct qm_mr_entry *msg)
+ {
+-      struct net_device *net_dev;
+-      struct ceetm_class *cls;
++      struct dpa_percpu_priv_s *dpa_percpu_priv;
+       struct ceetm_class_stats *cstats = NULL;
+       const struct dpa_priv_s *dpa_priv;
+-      struct dpa_percpu_priv_s *dpa_percpu_priv;
+-      struct sk_buff *skb;
+       struct qm_fd fd = msg->ern.fd;
++      struct net_device *net_dev;
++      struct ceetm_fq *ceetm_fq;
++      struct ceetm_class *cls;
++      struct sk_buff *skb;
+-      net_dev = ((struct ceetm_fq *)fq)->net_dev;
++      ceetm_fq = container_of(fq, struct ceetm_fq, fq);
++      net_dev = ceetm_fq->net_dev;
+       dpa_priv = netdev_priv(net_dev);
+       dpa_percpu_priv = raw_cpu_ptr(dpa_priv->percpu_priv);
+@@ -86,7 +88,7 @@ static void ceetm_ern(struct qman_portal
+       dpa_percpu_priv->stats.tx_fifo_errors++;
+       /* Increment CEETM counters */
+-      cls = ((struct ceetm_fq *)fq)->ceetm_cls;
++      cls = ceetm_fq->ceetm_cls;
+       switch (cls->type) {
+       case CEETM_PRIO:
+               cstats = this_cpu_ptr(cls->prio.cstats);
+@@ -99,11 +101,15 @@ static void ceetm_ern(struct qman_portal
+       if (cstats)
+               cstats->ern_drop_count++;
++      /* Release the buffers that were supposed to be recycled. */
+       if (fd.bpid != 0xff) {
+               dpa_fd_release(net_dev, &fd);
+               return;
+       }
++      /* Release the frames that were supposed to return on the
++       * confirmation path.
++       */
+       skb = _dpa_cleanup_tx_fd(dpa_priv, &fd);
+       dev_kfree_skb_any(skb);
+ }
+@@ -1909,18 +1915,22 @@ static struct ceetm_class *ceetm_classif
+ int __hot ceetm_tx(struct sk_buff *skb, struct net_device *net_dev)
+ {
+-      int ret;
+-      bool act_drop = false;
++      const int queue_mapping = dpa_get_queue_mapping(skb);
+       struct Qdisc *sch = net_dev->qdisc;
+-      struct ceetm_class *cl;
++      struct ceetm_class_stats *cstats;
++      struct ceetm_qdisc_stats *qstats;
+       struct dpa_priv_s *priv_dpa;
+       struct ceetm_fq *ceetm_fq;
++      struct ceetm_qdisc *priv;
+       struct qman_fq *conf_fq;
+-      struct ceetm_qdisc *priv = qdisc_priv(sch);
+-      struct ceetm_qdisc_stats *qstats = this_cpu_ptr(priv->root.qstats);
+-      struct ceetm_class_stats *cstats;
+-      const int queue_mapping = dpa_get_queue_mapping(skb);
+-      spinlock_t *root_lock = qdisc_lock(sch);
++      struct ceetm_class *cl;
++      spinlock_t *root_lock;
++      bool act_drop = false;
++      int ret;
++
++      root_lock = qdisc_lock(sch);
++      priv = qdisc_priv(sch);
++      qstats = this_cpu_ptr(priv->root.qstats);
+       spin_lock(root_lock);
+       cl = ceetm_classify(skb, sch, &ret, &act_drop);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0045-sdk_dpaa-ceetm-increment-the-interface-s-ern-counter.patch b/target/linux/layerscape/patches-5.4/701-net-0045-sdk_dpaa-ceetm-increment-the-interface-s-ern-counter.patch
new file mode 100644 (file)
index 0000000..f15e529
--- /dev/null
@@ -0,0 +1,21 @@
+From 0f57c89199c5664a14e9a4c88a382d642e9398a1 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Thu, 7 Dec 2017 17:49:34 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: increment the interface's ern counters when
+ needed
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -86,6 +86,7 @@ static void ceetm_ern(struct qman_portal
+       /* Increment DPA counters */
+       dpa_percpu_priv->stats.tx_dropped++;
+       dpa_percpu_priv->stats.tx_fifo_errors++;
++      count_ern(dpa_percpu_priv, msg);
+       /* Increment CEETM counters */
+       cls = ceetm_fq->ceetm_cls;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0046-sdk_dpaa-update-buffer-recycling-conditions.patch b/target/linux/layerscape/patches-5.4/701-net-0046-sdk_dpaa-update-buffer-recycling-conditions.patch
new file mode 100644 (file)
index 0000000..daad074
--- /dev/null
@@ -0,0 +1,31 @@
+From b95f457bb7ba38f03a71b474e35f53670322f0db Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 15 Jan 2018 17:41:01 +0200
+Subject: [PATCH] sdk_dpaa: update buffer recycling conditions
+
+Guarantee there is enough space inside the skb's headroom to store the
+skb back-pointer before recycling the buffer. The back-pointer is stored
+right before the buffer's start.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -350,7 +350,13 @@ bool dpa_buf_is_recyclable(struct sk_buf
+       /* left align to the nearest cacheline */
+       new = (unsigned char *)((unsigned long)new & ~(SMP_CACHE_BYTES - 1));
+-      if (likely(new >= skb->head &&
++      /* Make sure there is enough space to store the skb back-pointer in
++       * the headroom, right before the start of the buffer.
++       *
++       * Guarantee that both maximum size and maximum data offsets aren't
++       * crossed.
++       */
++      if (likely(new >= (skb->head + sizeof(void *)) &&
+                  new >= (skb->data - DPA_MAX_FD_OFFSET) &&
+                  skb_end_pointer(skb) - new <= DPA_RECYCLE_MAX_SIZE)) {
+               *new_buf_start = new;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0047-sdk_dpaa-update-comments-about-recycling-and-back-po.patch b/target/linux/layerscape/patches-5.4/701-net-0047-sdk_dpaa-update-comments-about-recycling-and-back-po.patch
new file mode 100644 (file)
index 0000000..a54dce9
--- /dev/null
@@ -0,0 +1,67 @@
+From 2d7b6e7daf076b63f461ce9c4ec6022ddc3d15bb Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 15 Jan 2018 17:42:42 +0200
+Subject: [PATCH] sdk_dpaa: update comments about recycling and back-pointer
+ storage
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 18 ++++++++++++++++--
+ 1 file changed, 16 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -121,6 +121,10 @@ static int _dpa_bp_add_8_bufs(const stru
+                       put_page(virt_to_head_page(new_buf));
+                       goto build_skb_failed;
+               }
++
++              /* Store the skb back-pointer before the start of the buffer.
++               * Otherwise it will be overwritten by the FMan.
++               */
+               DPA_WRITE_SKB_PTR(skb, skbh, new_buf, -1);
+               addr = dma_map_single(dev, new_buf,
+@@ -344,7 +348,10 @@ bool dpa_buf_is_recyclable(struct sk_buf
+        * - buffer address aligned to cacheline bytes
+        * - offset of data from start of buffer no lower than a minimum value
+        * - offset of data from start of buffer no higher than a maximum value
++       * - the skb back-pointer is stored safely
+        */
++
++      /* guarantee both the minimum size and the minimum data offset */
+       new = min(skb_end_pointer(skb) - min_size, skb->data - min_offset);
+       /* left align to the nearest cacheline */
+@@ -694,6 +701,9 @@ int __hot skb_to_contig_fd(struct dpa_pr
+               dma_dir = DMA_BIDIRECTIONAL;
+               dma_map_size = dpa_bp->size;
++              /* Store the skb back-pointer before the start of the buffer.
++               * Otherwise it will be overwritten by the FMan.
++               */
+               DPA_WRITE_SKB_PTR(skb, skbh, buffer_start, -1);
+               *offset = skb_headroom(skb) - fd->offset;
+       } else
+@@ -711,7 +721,7 @@ int __hot skb_to_contig_fd(struct dpa_pr
+               /* The buffer will be Tx-confirmed, but the TxConf cb must
+                * necessarily look at our Tx private data to retrieve the
+-               * skbuff. (In short: can't use DPA_WRITE_SKB_PTR() here.)
++               * skbuff. Store the back-pointer inside the buffer.
+                */
+               DPA_WRITE_SKB_PTR(skb, skbh, buffer_start, 0);
+       }
+@@ -975,7 +985,11 @@ int __hot skb_to_sg_fd(struct dpa_priv_s
+       fd->length20 = skb->len;
+       fd->offset = priv->tx_headroom;
+-      /* DMA map the SGT page */
++      /* DMA map the SGT page
++       *
++       * It's safe to store the skb back-pointer inside the buffer since
++       * S/G frames are non-recyclable.
++       */
+       DPA_WRITE_SKB_PTR(skb, skbh, sgt_buf, 0);
+       addr = dma_map_single(dpa_bp->dev, sgt_buf,
+                             priv->tx_headroom + sgt_size,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0048-sdk_dpaa-ceetm-pass-extended-ACK-struct-to-parsing-f.patch b/target/linux/layerscape/patches-5.4/701-net-0048-sdk_dpaa-ceetm-pass-extended-ACK-struct-to-parsing-f.patch
new file mode 100644 (file)
index 0000000..d0c12a4
--- /dev/null
@@ -0,0 +1,40 @@
+From 62fedbc6ed6f4117168af52a7ff12e3450809d30 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 17 Jan 2018 16:31:57 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: pass extended ACK struct to parsing
+ functions
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -1053,7 +1053,7 @@ static int ceetm_init(struct Qdisc *sch,
+               return -EINVAL;
+       }
+-      ret = nla_parse_nested(tb, TCA_CEETM_QOPS, opt, ceetm_policy);
++      ret = nla_parse_nested(tb, TCA_CEETM_QOPS, opt, ceetm_policy, NULL);
+       if (ret < 0) {
+               pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+               return ret;
+@@ -1230,7 +1230,7 @@ static int ceetm_change(struct Qdisc *sc
+       pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+-      ret = nla_parse_nested(tb, TCA_CEETM_QOPS, opt, ceetm_policy);
++      ret = nla_parse_nested(tb, TCA_CEETM_QOPS, opt, ceetm_policy, NULL);
+       if (ret < 0) {
+               pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+               return ret;
+@@ -1463,7 +1463,7 @@ static int ceetm_cls_change(struct Qdisc
+               return -EINVAL;
+       }
+-      err = nla_parse_nested(tb, TCA_CEETM_COPT, opt, ceetm_policy);
++      err = nla_parse_nested(tb, TCA_CEETM_COPT, opt, ceetm_policy, NULL);
+       if (err < 0) {
+               pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+               return -EINVAL;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0049-sdk_dpaa-ceetm-adapt-to-new-tcf-classify-API.patch b/target/linux/layerscape/patches-5.4/701-net-0049-sdk_dpaa-ceetm-adapt-to-new-tcf-classify-API.patch
new file mode 100644 (file)
index 0000000..454cfe3
--- /dev/null
@@ -0,0 +1,21 @@
+From 9befbfedde09b0e3abdc56d8f98e2111af39e872 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 17 Jan 2018 16:36:05 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: adapt to new tcf classify API
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -1848,7 +1848,7 @@ static struct ceetm_class *ceetm_classif
+       *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
+       tcf = priv->filter_list;
+-      while (tcf && (result = tc_classify(skb, tcf, &res, false)) >= 0) {
++      while (tcf && (result = tcf_classify(skb, tcf, &res, false)) >= 0) {
+ #ifdef CONFIG_NET_CLS_ACT
+               switch (result) {
+               case TC_ACT_QUEUED:
diff --git a/target/linux/layerscape/patches-5.4/701-net-0050-sdk_dpaa-ceetm-introduce-a-TRAP-control-action.patch b/target/linux/layerscape/patches-5.4/701-net-0050-sdk_dpaa-ceetm-introduce-a-TRAP-control-action.patch
new file mode 100644 (file)
index 0000000..4b31221
--- /dev/null
@@ -0,0 +1,20 @@
+From e71adc0bb320c602791fa08a14626704a57bbb4d Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 17 Jan 2018 16:38:09 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: introduce a TRAP control action
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -1853,6 +1853,7 @@ static struct ceetm_class *ceetm_classif
+               switch (result) {
+               case TC_ACT_QUEUED:
+               case TC_ACT_STOLEN:
++              case TC_ACT_TRAP:
+                       *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
+               case TC_ACT_SHOT:
+                       /* No valid class found due to action */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0051-sdk_dpaa-ceetm-use-the-tcf-block-infrastructure.patch b/target/linux/layerscape/patches-5.4/701-net-0051-sdk_dpaa-ceetm-use-the-tcf-block-infrastructure.patch
new file mode 100644 (file)
index 0000000..0e3d016
--- /dev/null
@@ -0,0 +1,126 @@
+From ae72322610af7eb13fc9a67567fdac610d3d3d3d Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 17 Jan 2018 16:44:19 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: use the tcf block infrastructure
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 31 +++++++++++++++-------
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h   |  2 ++
+ 2 files changed, 24 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -423,7 +423,7 @@ static void ceetm_cls_destroy(struct Qdi
+                       free_percpu(cl->wbfs.cstats);
+       }
+-      tcf_destroy_chain(&cl->filter_list);
++      tcf_block_put(cl->block);
+       kfree(cl);
+ }
+@@ -440,11 +440,13 @@ static void ceetm_destroy(struct Qdisc *
+                __func__, sch->handle);
+       /* All filters need to be removed before destroying the classes */
+-      tcf_destroy_chain(&priv->filter_list);
++      tcf_block_put(priv->block);
+       for (i = 0; i < priv->clhash.hashsize; i++) {
+-              hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode)
+-                      tcf_destroy_chain(&cl->filter_list);
++              hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode) {
++                      tcf_block_put(cl->block);
++                      cl->block = NULL;
++              }
+       }
+       for (i = 0; i < priv->clhash.hashsize; i++) {
+@@ -594,7 +596,7 @@ static int ceetm_init_root(struct Qdisc
+       /* Validate inputs */
+       if (sch->parent != TC_H_ROOT) {
+               pr_err("CEETM: a root ceetm qdisc can not be attached to a class\n");
+-              tcf_destroy_chain(&priv->filter_list);
++              tcf_block_put(priv->block);
+               qdisc_class_hash_destroy(&priv->clhash);
+               return -EINVAL;
+       }
+@@ -1053,6 +1055,10 @@ static int ceetm_init(struct Qdisc *sch,
+               return -EINVAL;
+       }
++      ret = tcf_block_get(&priv->block, &priv->filter_list);
++      if (ret)
++              return ret;
++
+       ret = nla_parse_nested(tb, TCA_CEETM_QOPS, opt, ceetm_policy, NULL);
+       if (ret < 0) {
+               pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+@@ -1521,6 +1527,12 @@ static int ceetm_cls_change(struct Qdisc
+       if (!cl)
+               return -ENOMEM;
++      err = tcf_block_get(&cl->block, &cl->filter_list);
++      if (err) {
++              kfree(cl);
++              return err;
++      }
++
+       cl->type = copt->type;
+       cl->shaped = copt->shaped;
+       cl->root.rate = copt->rate;
+@@ -1585,6 +1597,7 @@ channel_err:
+               pr_err(KBUILD_BASENAME " : %s : failed to release the channel %d\n",
+                      __func__, channel->idx);
+ claim_err:
++      tcf_block_put(cl->block);
+       kfree(cl);
+       return err;
+ }
+@@ -1779,15 +1792,15 @@ static int ceetm_cls_dump_stats(struct Q
+       return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
+ }
+-static struct tcf_proto **ceetm_tcf_chain(struct Qdisc *sch, unsigned long arg)
++static struct tcf_block *ceetm_tcf_block(struct Qdisc *sch, unsigned long arg)
+ {
+       struct ceetm_qdisc *priv = qdisc_priv(sch);
+       struct ceetm_class *cl = (struct ceetm_class *)arg;
+-      struct tcf_proto **fl = cl ? &cl->filter_list : &priv->filter_list;
++      struct tcf_block *block = cl ? cl->block : priv->block;
+       pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
+                cl ? cl->common.classid : 0, sch->handle);
+-      return fl;
++      return block;
+ }
+ static unsigned long ceetm_tcf_bind(struct Qdisc *sch, unsigned long parent,
+@@ -1816,7 +1829,7 @@ const struct Qdisc_class_ops ceetm_cls_o
+       .change         =       ceetm_cls_change,
+       .delete         =       ceetm_cls_delete,
+       .walk           =       ceetm_cls_walk,
+-      .tcf_chain      =       ceetm_tcf_chain,
++      .tcf_block      =       ceetm_tcf_block,
+       .bind_tcf       =       ceetm_tcf_bind,
+       .unbind_tcf     =       ceetm_tcf_unbind,
+       .dump           =       ceetm_cls_dump,
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h
+@@ -141,6 +141,7 @@ struct ceetm_qdisc {
+       };
+       struct Qdisc_class_hash clhash;
+       struct tcf_proto *filter_list; /* qdisc attached filters */
++      struct tcf_block *block;
+ };
+ /* CEETM Qdisc configuration parameters */
+@@ -192,6 +193,7 @@ struct ceetm_class {
+       struct Qdisc_class_common common;
+       int refcnt; /* usage count of this class */
+       struct tcf_proto *filter_list; /* class attached filters */
++      struct tcf_block *block;
+       struct Qdisc *parent;
+       bool shaped;
+       int type; /* ROOT/PRIO/WBFS */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0052-sdk_dpaa-ceetm-remove-tc-class-reference-counting.patch b/target/linux/layerscape/patches-5.4/701-net-0052-sdk_dpaa-ceetm-remove-tc-class-reference-counting.patch
new file mode 100644 (file)
index 0000000..473720b
--- /dev/null
@@ -0,0 +1,106 @@
+From 024d664114310fe103c2c31f2253bed58238951d Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 17 Jan 2018 16:47:07 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: remove tc class reference counting
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 38 +++-------------------
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h   |  1 -
+ 2 files changed, 4 insertions(+), 35 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -774,7 +774,6 @@ static int ceetm_init_prio(struct Qdisc
+               }
+               child_cl->common.classid = TC_H_MAKE(sch->handle, (i + 1));
+-              child_cl->refcnt = 1;
+               child_cl->parent = sch;
+               child_cl->type = CEETM_PRIO;
+               child_cl->shaped = priv->shaped;
+@@ -986,7 +985,6 @@ static int ceetm_init_wbfs(struct Qdisc
+               }
+               child_cl->common.classid = TC_H_MAKE(sch->handle, (i + 1));
+-              child_cl->refcnt = 1;
+               child_cl->parent = sch;
+               child_cl->type = CEETM_WBFS;
+               child_cl->shaped = priv->shaped;
+@@ -1297,29 +1295,9 @@ static void ceetm_attach(struct Qdisc *s
+       }
+ }
+-static unsigned long ceetm_cls_get(struct Qdisc *sch, u32 classid)
++static unsigned long ceetm_cls_search(struct Qdisc *sch, u32 handle)
+ {
+-      struct ceetm_class *cl;
+-
+-      pr_debug(KBUILD_BASENAME " : %s : classid %X from qdisc %X\n",
+-               __func__, classid, sch->handle);
+-      cl = ceetm_find(classid, sch);
+-
+-      if (cl)
+-              cl->refcnt++; /* Will decrement in put() */
+-      return (unsigned long)cl;
+-}
+-
+-static void ceetm_cls_put(struct Qdisc *sch, unsigned long arg)
+-{
+-      struct ceetm_class *cl = (struct ceetm_class *)arg;
+-
+-      pr_debug(KBUILD_BASENAME " : %s : classid %X from qdisc %X\n",
+-               __func__, cl->common.classid, sch->handle);
+-      cl->refcnt--;
+-
+-      if (cl->refcnt == 0)
+-              ceetm_cls_destroy(sch, cl);
++      return (unsigned long)ceetm_find(handle, sch);
+ }
+ static int ceetm_cls_change_root(struct ceetm_class *cl,
+@@ -1540,7 +1518,6 @@ static int ceetm_cls_change(struct Qdisc
+       cl->root.tbl = copt->tbl;
+       cl->common.classid = classid;
+-      cl->refcnt = 1;
+       cl->parent = sch;
+       cl->root.child = NULL;
+       cl->root.wbfs_grp_a = false;
+@@ -1696,15 +1673,9 @@ static int ceetm_cls_delete(struct Qdisc
+       sch_tree_lock(sch);
+       qdisc_class_hash_remove(&priv->clhash, &cl->common);
+-      cl->refcnt--;
+-
+-      /* The refcnt should be at least 1 since we have incremented it in
+-       * get(). Will decrement again in put() where we will call destroy()
+-       * to actually free the memory if it reaches 0.
+-       */
+-      WARN_ON(cl->refcnt == 0);
+       sch_tree_unlock(sch);
++      ceetm_cls_destroy(sch, cl);
+       return 0;
+ }
+@@ -1824,8 +1795,7 @@ static void ceetm_tcf_unbind(struct Qdis
+ const struct Qdisc_class_ops ceetm_cls_ops = {
+       .graft          =       ceetm_cls_graft,
+       .leaf           =       ceetm_cls_leaf,
+-      .get            =       ceetm_cls_get,
+-      .put            =       ceetm_cls_put,
++      .find           =       ceetm_cls_search,
+       .change         =       ceetm_cls_change,
+       .delete         =       ceetm_cls_delete,
+       .walk           =       ceetm_cls_walk,
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h
+@@ -191,7 +191,6 @@ struct wbfs_c {
+ struct ceetm_class {
+       struct Qdisc_class_common common;
+-      int refcnt; /* usage count of this class */
+       struct tcf_proto *filter_list; /* class attached filters */
+       struct tcf_block *block;
+       struct Qdisc *parent;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0053-sdk_dpaa-ceetm-store-Qdisc-pointer-in-struct-block.patch b/target/linux/layerscape/patches-5.4/701-net-0053-sdk_dpaa-ceetm-store-Qdisc-pointer-in-struct-block.patch
new file mode 100644 (file)
index 0000000..7c826cf
--- /dev/null
@@ -0,0 +1,30 @@
+From c041c49fc99382976c916438994c3a1caf4ab066 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 17 Jan 2018 17:10:29 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: store Qdisc pointer in struct block
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -1053,7 +1053,7 @@ static int ceetm_init(struct Qdisc *sch,
+               return -EINVAL;
+       }
+-      ret = tcf_block_get(&priv->block, &priv->filter_list);
++      ret = tcf_block_get(&priv->block, &priv->filter_list, sch);
+       if (ret)
+               return ret;
+@@ -1505,7 +1505,7 @@ static int ceetm_cls_change(struct Qdisc
+       if (!cl)
+               return -ENOMEM;
+-      err = tcf_block_get(&cl->block, &cl->filter_list);
++      err = tcf_block_get(&cl->block, &cl->filter_list, sch);
+       if (err) {
+               kfree(cl);
+               return err;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0054-dpaa_eth-workaround-for-ERR010022.patch b/target/linux/layerscape/patches-5.4/701-net-0054-dpaa_eth-workaround-for-ERR010022.patch
new file mode 100644 (file)
index 0000000..3c66e5a
--- /dev/null
@@ -0,0 +1,299 @@
+From fced03d891377fa04153fb0538bc8ca95ba05020 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Tue, 14 Nov 2017 08:12:12 +0200
+Subject: [PATCH] dpaa_eth: workaround for ERR010022
+
+On LS1043A SoC there is a known erratum ERR010022 that results in split DMA
+transfers in the FMan under certain conditions. This, combined with a fixed
+size FIFO of ongoing DMA transfers that may overflow when a split occurs,
+results in the FMan stalling DMA transfers under high traffic. To avoid the
+problem, one needs to prevent the DMA transfer splits to occur by preparing
+the buffers as follows.
+
+In order to prevent split transactions, all frames need to be aligned to 16
+bytes and not cross 4K address boundaries. To allow Jumbo frames (up to
+9.6K), all data must be aligned to 256 byes. This way, 4K boundary crossings
+will not trigger any transaction splits.
+
+The errata is prevented from manifesting by realigning all outgoing frames to
+256 byte boundaries. In the process, all S/G frames are linearized.
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 204 +++++++++++++++++++++++--
+ 1 file changed, 194 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+@@ -54,6 +54,10 @@
+ #include <linux/phy_fixed.h>
+ #include <soc/fsl/bman.h>
+ #include <soc/fsl/qman.h>
++#if !defined(CONFIG_PPC) && defined(CONFIG_SOC_BUS)
++#include <linux/sys_soc.h>      /* soc_device_match */
++#endif
++
+ #include "fman.h"
+ #include "fman_port.h"
+ #include "mac.h"
+@@ -73,6 +77,10 @@ static u16 tx_timeout = 1000;
+ module_param(tx_timeout, ushort, 0444);
+ MODULE_PARM_DESC(tx_timeout, "The Tx timeout in ms");
++#ifndef CONFIG_PPC
++bool dpaa_errata_a010022;
++#endif
++
+ #define FM_FD_STAT_RX_ERRORS                                          \
+       (FM_FD_ERR_DMA | FM_FD_ERR_PHYSICAL     | \
+        FM_FD_ERR_SIZE | FM_FD_ERR_CLS_DISCARD | \
+@@ -1495,7 +1503,19 @@ static int dpaa_bp_add_8_bufs(const stru
+       u8 i;
+       for (i = 0; i < 8; i++) {
++#ifndef CONFIG_PPC
++              if (dpaa_errata_a010022) {
++                      struct page *page = alloc_page(GFP_KERNEL);
++
++                      if (unlikely(!page))
++                              goto release_previous_buffs;
++                      new_buf = page_address(page);
++              } else {
++                      new_buf = netdev_alloc_frag(dpaa_bp->raw_size);
++              }
++#else
+               new_buf = netdev_alloc_frag(dpaa_bp->raw_size);
++#endif
+               if (unlikely(!new_buf)) {
+                       dev_err(dev, "netdev_alloc_frag() failed, size %zu\n",
+                               dpaa_bp->raw_size);
+@@ -1663,9 +1683,15 @@ static struct sk_buff *dpaa_cleanup_tx_f
+               }
+       }
+-      if (qm_fd_get_format(fd) == qm_fd_sg)
+-              /* Free the page frag that we allocated on Tx */
+-              skb_free_frag(phys_to_virt(addr));
++      if (qm_fd_get_format(fd) == qm_fd_sg) {
++#ifndef CONFIG_PPC
++              if (dpaa_errata_a010022)
++                      put_page(virt_to_page(sgt));
++              else
++#endif
++                      /* Free the page frag that we allocated on Tx */
++                      skb_free_frag(phys_to_virt(addr));
++      }
+       return skb;
+ }
+@@ -1922,14 +1948,26 @@ static int skb_to_sg_fd(struct dpaa_priv
+       size_t frag_len;
+       void *sgt_buf;
+-      /* get a page frag to store the SGTable */
+-      sz = SKB_DATA_ALIGN(priv->tx_headroom + DPAA_SGT_SIZE);
+-      sgt_buf = netdev_alloc_frag(sz);
+-      if (unlikely(!sgt_buf)) {
+-              netdev_err(net_dev, "netdev_alloc_frag() failed for size %d\n",
+-                         sz);
+-              return -ENOMEM;
++#ifndef CONFIG_PPC
++      if (unlikely(dpaa_errata_a010022)) {
++              struct page *page = alloc_page(GFP_ATOMIC);
++              if (unlikely(!page))
++                      return -ENOMEM;
++              sgt_buf = page_address(page);
++      } else {
++#endif
++              /* get a page frag to store the SGTable */
++              sz = SKB_DATA_ALIGN(priv->tx_headroom + DPAA_SGT_SIZE);
++              sgt_buf = netdev_alloc_frag(sz);
++              if (unlikely(!sgt_buf)) {
++                      netdev_err(net_dev,
++                                 "netdev_alloc_frag() failed for size %d\n",
++                                 sz);
++                      return -ENOMEM;
++              }
++#ifndef CONFIG_PPC
+       }
++#endif
+       /* Enable L3/L4 hardware checksum computation.
+        *
+@@ -2049,6 +2087,122 @@ static inline int dpaa_xmit(struct dpaa_
+       return 0;
+ }
++#ifndef CONFIG_PPC
++/* On LS1043A SoC there is a known erratum ERR010022 that results in split DMA
++ * transfers in the FMan under certain conditions. This, combined with a fixed
++ * size FIFO of ongoing DMA transfers that may overflow when a split occurs,
++ * results in the FMan stalling DMA transfers under high traffic. To avoid the
++ * problem, one needs to prevent the DMA transfer splits to occur by preparing
++ * the buffers
++ */
++
++#define DPAA_A010022_HEADROOM 256
++#define CROSS_4K_BOUND(start, size) \
++      (((start) + (size)) > (((start) + 0x1000) & ~0xFFF))
++
++static bool dpaa_errata_a010022_has_dma_issue(struct sk_buff *skb,
++                                            struct dpaa_priv *priv)
++{
++      int nr_frags, i = 0;
++       skb_frag_t *frag;
++
++      /* Transfers that do not start at 16B aligned addresses will be split;
++       * Transfers that cross a 4K page boundary will also be split
++       */
++
++      /* Check if the frame data is aligned to 16 bytes */
++      if ((uintptr_t)skb->data % DPAA_FD_DATA_ALIGNMENT)
++              return true;
++
++      /* Check if the headroom crosses a boundary */
++      if (CROSS_4K_BOUND((uintptr_t)skb->head, skb_headroom(skb)))
++              return true;
++
++      /* Check if the non-paged data crosses a boundary */
++      if (CROSS_4K_BOUND((uintptr_t)skb->data, skb_headlen(skb)))
++              return true;
++
++      nr_frags = skb_shinfo(skb)->nr_frags;
++
++      while (i < nr_frags) {
++              frag = &skb_shinfo(skb)->frags[i];
++
++              /* Check if a paged fragment crosses a boundary from its
++               * offset to its end.
++               */
++              if (CROSS_4K_BOUND((uintptr_t)frag->page_offset, frag->size))
++                      return true;
++
++              i++;
++      }
++
++      return false;
++}
++
++static struct sk_buff *dpaa_errata_a010022_prevent(struct sk_buff *skb,
++                                                 struct dpaa_priv *priv)
++{
++      int trans_offset = skb_transport_offset(skb);
++      int net_offset = skb_network_offset(skb);
++      int nsize, npage_order, headroom;
++      struct sk_buff *nskb = NULL;
++      struct page *npage;
++      void *npage_addr;
++
++      if (!dpaa_errata_a010022_has_dma_issue(skb, priv))
++              return skb;
++
++      /* For the new skb we only need the old one's data (both non-paged and
++       * paged). We can skip the old tailroom.
++       *
++       * The headroom also needs to fit our private info (64 bytes) but we
++       * reserve 256 bytes instead in order to guarantee that the data is
++       * aligned to 256.
++       */
++      headroom = DPAA_A010022_HEADROOM;
++      nsize = headroom + skb->len +
++              SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
++
++      /* Reserve enough memory to accommodate Jumbo frames */
++      npage_order = (nsize - 1) / PAGE_SIZE;
++      npage = alloc_pages(GFP_ATOMIC | __GFP_COMP, npage_order);
++      if (unlikely(!npage)) {
++              WARN_ONCE(1, "Memory allocation failure\n");
++              return NULL;
++      }
++      npage_addr = page_address(npage);
++
++      nskb = build_skb(npage_addr, nsize);
++      if (unlikely(!nskb))
++              goto err;
++
++      /* Code borrowed and adapted from skb_copy() */
++      skb_reserve(nskb, headroom);
++      skb_put(nskb, skb->len);
++      if (skb_copy_bits(skb, 0, nskb->data, skb->len)) {
++              WARN_ONCE(1, "skb parsing failure\n");
++              goto err;
++      }
++      copy_skb_header(nskb, skb);
++
++      /* We move the headroom when we align it so we have to reset the
++       * network and transport header offsets relative to the new data
++       * pointer. The checksum offload relies on these offsets.
++       */
++      skb_set_network_header(nskb, net_offset);
++      skb_set_transport_header(nskb, trans_offset);
++
++      dev_kfree_skb(skb);
++      return nskb;
++
++err:
++      if (nskb)
++              dev_kfree_skb(nskb);
++      put_page(npage);
++      return NULL;
++}
++#endif
++
+ static netdev_tx_t
+ dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
+ {
+@@ -2095,6 +2249,15 @@ dpaa_start_xmit(struct sk_buff *skb, str
+               nonlinear = skb_is_nonlinear(skb);
+       }
++#ifndef CONFIG_PPC
++      if (unlikely(dpaa_errata_a010022)) {
++              skb = dpaa_errata_a010022_prevent(skb, priv);
++              if (!skb)
++                      goto enomem;
++              nonlinear = skb_is_nonlinear(skb);
++      }
++#endif
++
+       if (nonlinear) {
+               /* Just create a S/G fd based on the skb */
+               err = skb_to_sg_fd(priv, skb, &fd);
+@@ -2992,6 +3155,23 @@ static int dpaa_remove(struct platform_d
+       return err;
+ }
++#ifndef CONFIG_PPC
++static bool __init soc_has_errata_a010022(void)
++{
++#ifdef CONFIG_SOC_BUS
++      const struct soc_device_attribute soc_msi_matches[] = {
++              { .family = "QorIQ LS1043A",
++                .data = NULL },
++              { },
++      };
++
++      if (!soc_device_match(soc_msi_matches))
++              return false;
++#endif
++      return true; /* cannot identify SoC or errata applies */
++}
++#endif
++
+ static const struct platform_device_id dpaa_devtype[] = {
+       {
+               .name = "dpaa-ethernet",
+@@ -3016,6 +3196,10 @@ static int __init dpaa_load(void)
+       pr_debug("FSL DPAA Ethernet driver\n");
++#ifndef CONFIG_PPC
++      /* Detect if the current SoC requires the DMA transfer alignment workaround */
++      dpaa_errata_a010022 = soc_has_errata_a010022();
++#endif
+       /* initialize dpaa_eth mirror values */
+       dpaa_rx_extra_headroom = fman_get_rx_extra_headroom();
+       dpaa_max_frm = fman_get_max_frm();
diff --git a/target/linux/layerscape/patches-5.4/701-net-0055-sdk_fman-DPAA-dTSEC-ports-fail-to-work-when-link-cha.patch b/target/linux/layerscape/patches-5.4/701-net-0055-sdk_fman-DPAA-dTSEC-ports-fail-to-work-when-link-cha.patch
new file mode 100644 (file)
index 0000000..e17c2a7
--- /dev/null
@@ -0,0 +1,131 @@
+From 2b3d05ed1cb560b3a0b0721435c2fd73a19bd9bc Mon Sep 17 00:00:00 2001
+From: Iordache Florinel-R70177 <florinel.iordache@nxp.com>
+Date: Mon, 29 May 2017 09:25:24 +0300
+Subject: [PATCH] sdk_fman: DPAA-dTSEC ports fail to work when link changes
+
+Signed-off-by: Iordache Florinel-R70177 <florinel.iordache@nxp.com>
+---
+ .../freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c  | 57 ++++++++++++++++++----
+ 1 file changed, 48 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c
+@@ -386,6 +386,7 @@ static void FreeInitResources(t_Dtsec *p
+ static t_Error GracefulStop(t_Dtsec *p_Dtsec, e_CommMode mode)
+ {
+     struct dtsec_regs *p_MemMap;
++    int pollTimeout = 0;
+     ASSERT_COND(p_Dtsec);
+@@ -408,16 +409,32 @@ static t_Error GracefulStop(t_Dtsec *p_D
+     }
+     if (mode & e_COMM_MODE_TX)
+-#if defined(FM_GTS_ERRATA_DTSEC_A004) || defined(FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012)
+-    if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2)
+-        DBG(INFO, ("GTS not supported due to DTSEC_A004 errata."));
+-#else  /* not defined(FM_GTS_ERRATA_DTSEC_A004) ||... */
+-#ifdef FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014
+-        DBG(INFO, ("GTS not supported due to DTSEC_A0014 errata."));
+-#else  /* FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 */
++    {
++#if defined(FM_GTS_ERRATA_DTSEC_A004)
++        if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2)
++            DBG(INFO, ("GTS not supported due to DTSEC_A004 errata."));
++#else  /* not defined(FM_GTS_ERRATA_DTSEC_A004) */
++
+         fman_dtsec_stop_tx(p_MemMap);
+-#endif /* FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 */
+-#endif /* defined(FM_GTS_ERRATA_DTSEC_A004) ||...  */
++
++#if defined(FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014) || defined(FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012)
++        XX_UDelay(10);
++#endif /* FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 || FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012 */
++#endif /* defined(FM_GTS_ERRATA_DTSEC_A004) */
++    }
++
++    /* Poll GRSC/GTSC bits in IEVENT register until both are set */
++#if defined(FM_GRS_ERRATA_DTSEC_A002) || defined(FM_GTS_ERRATA_DTSEC_A004) || defined(FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012) || defined(FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014) || defined(FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839)
++    XX_UDelay(10);
++#else
++    while (fman_dtsec_get_event(p_MemMap, DTSEC_IMASK_GRSCEN | DTSEC_IMASK_GTSCEN) != (DTSEC_IMASK_GRSCEN | DTSEC_IMASK_GTSCEN))
++    {
++        if (pollTimeout == 100)
++            break;
++        XX_UDelay(1);
++        pollTimeout++;
++    }
++#endif
+     return E_OK;
+ }
+@@ -632,7 +649,12 @@ static t_Error DtsecSetTxPauseFrames(t_H
+                       " value should be greater than 320."));
+ #endif /* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 */
++    GracefulStop(p_Dtsec, e_COMM_MODE_RX_AND_TX);
++
+     fman_dtsec_set_tx_pause_frames(p_Dtsec->p_MemMap, pauseTime);
++
++    GracefulRestart(p_Dtsec, e_COMM_MODE_RX_AND_TX);
++
+     return E_OK;
+ }
+@@ -653,8 +675,12 @@ static t_Error DtsecRxIgnoreMacPause(t_H
+     SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE);
+     SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++    GracefulStop(p_Dtsec, e_COMM_MODE_RX_AND_TX);
++
+     fman_dtsec_handle_rx_pause(p_Dtsec->p_MemMap, accept_pause);
++    GracefulRestart(p_Dtsec, e_COMM_MODE_RX_AND_TX);
++
+     return E_OK;
+ }
+@@ -787,8 +813,13 @@ static t_Error DtsecModifyMacAddress (t_
+     /* Initialize MAC Station Address registers (1 & 2)    */
+     /* Station address have to be swapped (big endian to little endian */
+     p_Dtsec->addr = ENET_ADDR_TO_UINT64(*p_EnetAddr);
++
++    GracefulStop(p_Dtsec, e_COMM_MODE_RX_AND_TX);
++
+     fman_dtsec_set_mac_address(p_Dtsec->p_MemMap, (uint8_t *)(*p_EnetAddr));
++    GracefulRestart(p_Dtsec, e_COMM_MODE_RX_AND_TX);
++
+     return E_OK;
+ }
+@@ -1076,8 +1107,12 @@ static t_Error DtsecSetWakeOnLan(t_Handl
+     SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE);
+     SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
++    GracefulStop(p_Dtsec, e_COMM_MODE_RX_AND_TX);
++
+     fman_dtsec_set_wol(p_Dtsec->p_MemMap, en);
++    GracefulRestart(p_Dtsec, e_COMM_MODE_RX_AND_TX);
++
+     return E_OK;
+ }
+@@ -1098,11 +1133,15 @@ static t_Error DtsecAdjustLink(t_Handle
+     enet_speed = (enum enet_speed) ENET_SPEED_FROM_MODE(p_Dtsec->enetMode);
+     p_Dtsec->halfDuplex = !fullDuplex;
++    GracefulStop(p_Dtsec, e_COMM_MODE_RX_AND_TX);
++
+     err = fman_dtsec_adjust_link(p_Dtsec->p_MemMap, enet_interface, enet_speed, fullDuplex);
+     if (err == -EINVAL)
+         RETURN_ERROR(MAJOR, E_CONFLICT, ("Ethernet interface does not support Half Duplex mode"));
++    GracefulRestart(p_Dtsec, e_COMM_MODE_RX_AND_TX);
++
+     return (t_Error)err;
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0056-sdk-dpa-adapt-compatibles-to-upstream-binding-docume.patch b/target/linux/layerscape/patches-5.4/701-net-0056-sdk-dpa-adapt-compatibles-to-upstream-binding-docume.patch
new file mode 100644 (file)
index 0000000..c1903a2
--- /dev/null
@@ -0,0 +1,25 @@
+From d3ec1bf411a208028d06ffbb0f0ed461096977a8 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Fri, 20 Oct 2017 16:42:26 +0300
+Subject: [PATCH] sdk: dpa: adapt compatibles to upstream binding document
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/mac.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/mac.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac.c
+@@ -133,10 +133,10 @@ static int __cold free_macdev(struct mac
+ static const struct of_device_id mac_match[] = {
+       [DTSEC] = {
+-              .compatible     = "fsl,fman-1g-mac"
++              .compatible     = "fsl,fman-dtsec"
+       },
+       [XGMAC] = {
+-              .compatible     = "fsl,fman-10g-mac"
++              .compatible     = "fsl,fman-xgec"
+       },
+       [MEMAC] = {
+               .compatible     = "fsl,fman-memac"
diff --git a/target/linux/layerscape/patches-5.4/701-net-0057-sdk_fman-fix-probing-of-10G-ports-on-T102x.patch b/target/linux/layerscape/patches-5.4/701-net-0057-sdk_fman-fix-probing-of-10G-ports-on-T102x.patch
new file mode 100644 (file)
index 0000000..e772c95
--- /dev/null
@@ -0,0 +1,87 @@
+From 7dd27606d9b7f28a7367e4b9444bed7d573f4b6c Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Fri, 23 Mar 2018 16:33:19 +0200
+Subject: [PATCH] sdk_fman: fix probing of 10G ports on T102x
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../sdk_fman/src/wrapper/lnxwrp_fm_port.c          | 24 +++++++++++++++++-----
+ 1 file changed, 19 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c
+@@ -388,7 +388,14 @@ static t_LnxWrpFmPortDev *ReadFmPortDevT
+                       settings.param.specificParams.nonRxParams.qmChannel =
+                       p_LnxWrpFmPortDev->txCh;
+       } else if (of_device_is_compatible(port_node, "fsl,fman-port-10g-tx")) {
++#ifndef CONFIG_FMAN_ARM
++              /* On T102x, the 10G TX port IDs start from 0x28 */
++              if (IS_T1023_T1024)
++                      tmp_prop -= 0x28;
++              else
++#endif
+               tmp_prop -= 0x30;
++
+               if (unlikely(tmp_prop>= FM_MAX_NUM_OF_10G_TX_PORTS)) {
+                       REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+                                       ("of_get_property(%s, cell-index) failed",
+@@ -399,7 +406,7 @@ static t_LnxWrpFmPortDev *ReadFmPortDevT
+                       FM_MAX_NUM_OF_1G_TX_PORTS];
+ #ifndef CONFIG_FMAN_ARM
+               if (IS_T1023_T1024)
+-                      p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[*uint32_prop];
++                      p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[tmp_prop];
+ #endif
+               p_LnxWrpFmPortDev->id = tmp_prop;
+@@ -437,7 +444,14 @@ static t_LnxWrpFmPortDev *ReadFmPortDevT
+               if (p_LnxWrpFmDev->pcdActive)
+                       p_LnxWrpFmPortDev->defPcd = p_LnxWrpFmDev->defPcd;
+       } else if (of_device_is_compatible(port_node, "fsl,fman-port-10g-rx")) {
++#ifndef CONFIG_FMAN_ARM
++              /* On T102x, the 10G RX port IDs start from 0x08 */
++              if (IS_T1023_T1024)
++                      tmp_prop -= 0x8;
++              else
++#endif
+               tmp_prop -= 0x10;
++
+               if (unlikely(tmp_prop >= FM_MAX_NUM_OF_10G_RX_PORTS)) {
+                       REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+                                       ("of_get_property(%s, cell-index) failed",
+@@ -449,7 +463,7 @@ static t_LnxWrpFmPortDev *ReadFmPortDevT
+ #ifndef CONFIG_FMAN_ARM
+               if (IS_T1023_T1024)
+-                      p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[*uint32_prop];
++                      p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[tmp_prop];
+ #endif
+               p_LnxWrpFmPortDev->id = tmp_prop;
+@@ -637,7 +651,7 @@ static t_Error CheckNConfigFmPortAdvArgs
+     uint32_prop = (uint32_t *)of_get_property(port_node, "ar-tables-sizes",
+       &lenp);
+     if (uint32_prop) {
+-    
++
+       if (WARN_ON(lenp != sizeof(uint32_t)*8))
+             RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
+       if (WARN_ON(p_LnxWrpFmPortDev->settings.param.portType !=
+@@ -671,7 +685,7 @@ static t_Error CheckNConfigFmPortAdvArgs
+         if (uint32_prop) {
+               if (WARN_ON(lenp != sizeof(uint32_t)*3))
+                 RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
+-         
++
+             p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_ip_prot_filtering  =
+               (uint16_t)be32_to_cpu(uint32_prop[0]);
+             p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_tcp_port_filtering =
+@@ -679,7 +693,7 @@ static t_Error CheckNConfigFmPortAdvArgs
+             p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_udp_port_filtering =
+               (uint16_t)be32_to_cpu(uint32_prop[2]);
+         }
+-        
++
+         if ((err = FM_PORT_ConfigDsarSupport(p_LnxWrpFmPortDev->h_Dev,
+               (t_FmPortDsarTablesSizes*)&p_LnxWrpFmPortDev->dsar_table_sizes)) != E_OK)
+               RETURN_ERROR(MINOR, err, NO_MSG);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0058-sdk_fman-probe-OH-ports-on-PPC.patch b/target/linux/layerscape/patches-5.4/701-net-0058-sdk_fman-probe-OH-ports-on-PPC.patch
new file mode 100644 (file)
index 0000000..31d86dd
--- /dev/null
@@ -0,0 +1,38 @@
+From 11a68a2d48fee4524163c5ce36477bafb6515a98 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 26 Mar 2018 10:48:19 +0300
+Subject: [PATCH] sdk_fman: probe OH ports on PPC
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c
+@@ -303,7 +303,13 @@ static t_LnxWrpFmPortDev *ReadFmPortDevT
+       tmp_prop = be32_to_cpu(*uint32_prop);
+       if (WARN_ON(lenp != sizeof(uint32_t)))
+               return NULL;
+-      if (of_device_is_compatible(port_node, "fsl,fman-port-oh")) {
++      if (of_device_is_compatible(port_node, "fsl,fman-port-oh") ||
++          of_device_is_compatible(port_node, "fsl,fman-v2-port-oh") ||
++          of_device_is_compatible(port_node, "fsl,fman-v3-port-oh")) {
++#ifndef CONFIG_FMAN_ARM
++              /* On PPC, OH ports start from cell-index 0x2 */
++              tmp_prop -= 0x2;
++#endif
+               if (unlikely(tmp_prop >= FM_MAX_NUM_OF_OH_PORTS)) {
+                       REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+                                    ("of_get_property(%s, cell-index) failed",
+@@ -1433,6 +1439,10 @@ static const struct of_device_id fm_port
+       {
+        .compatible = "fsl,fman-port-oh"},
+       {
++       .compatible = "fsl,fman-v2-port-oh"},
++      {
++       .compatible = "fsl,fman-v3-port-oh"},
++      {
+        .compatible = "fsl,fman-port-1g-rx"},
+       {
+        .compatible = "fsl,fman-port-10g-rx"},
diff --git a/target/linux/layerscape/patches-5.4/701-net-0059-sdk_fman-on-P-series-platforms-the-OH-ports-start-at.patch b/target/linux/layerscape/patches-5.4/701-net-0059-sdk_fman-on-P-series-platforms-the-OH-ports-start-at.patch
new file mode 100644 (file)
index 0000000..6afc1c0
--- /dev/null
@@ -0,0 +1,33 @@
+From 7eb5f0a192efbe1fa94490881858ed45c5373233 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 2 Apr 2018 18:19:27 +0300
+Subject: [PATCH] sdk_fman: on P-series platforms, the OH ports start at offset
+ 1
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c
+@@ -307,9 +307,17 @@ static t_LnxWrpFmPortDev *ReadFmPortDevT
+           of_device_is_compatible(port_node, "fsl,fman-v2-port-oh") ||
+           of_device_is_compatible(port_node, "fsl,fman-v3-port-oh")) {
+ #ifndef CONFIG_FMAN_ARM
+-              /* On PPC, OH ports start from cell-index 0x2 */
++#ifdef CONFIG_FMAN_P3040_P4080_P5020
++              /* On PPC FMan v2, OH ports start from cell-index 0x1 */
++              tmp_prop -= 0x1;
++#else
++              /* On PPC FMan v3 (Low and High), OH ports start from
++               * cell-index 0x2
++               */
+               tmp_prop -= 0x2;
+-#endif
++#endif // CONFIG_FMAN_P3040_P4080_P5020
++#endif // CONFIG_FMAN_ARM
++
+               if (unlikely(tmp_prop >= FM_MAX_NUM_OF_OH_PORTS)) {
+                       REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+                                    ("of_get_property(%s, cell-index) failed",
diff --git a/target/linux/layerscape/patches-5.4/701-net-0060-sdk_fman-disable-timer-code.patch b/target/linux/layerscape/patches-5.4/701-net-0060-sdk_fman-disable-timer-code.patch
new file mode 100644 (file)
index 0000000..6b8df30
--- /dev/null
@@ -0,0 +1,32 @@
+From de27589a9862f51d2f62eda586f18dfc128af143 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Wed, 18 Apr 2018 08:58:09 +0300
+Subject: [PATCH] sdk_fman: disable timer code
+
+The (unused) timer code is no longer compatible with the newer
+kernel API. Disabling the incompatible code.
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_linux.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_linux.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_linux.c
+@@ -614,7 +614,7 @@ uint32_t XX_CurrentTime(void)
+     return (jiffies*1000)/HZ;
+ }
+-
++#if 0
+ t_Handle XX_CreateTimer(void)
+ {
+     struct timer_list *p_Timer = (struct timer_list *)XX_Malloc(sizeof(struct timer_list));
+@@ -691,6 +691,7 @@ int XX_TimerIsActive(t_Handle h_Timer)
+ {
+   return timer_pending((struct timer_list *)h_Timer);
+ }
++#endif
+ uint32_t XX_Sleep(uint32_t msecs)
+ {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0061-sdk_fman-disable-timer-code-in-arm-code.patch b/target/linux/layerscape/patches-5.4/701-net-0061-sdk_fman-disable-timer-code-in-arm-code.patch
new file mode 100644 (file)
index 0000000..9822f52
--- /dev/null
@@ -0,0 +1,32 @@
+From 796f8a61e866183425a54fd8b45d5ccaebadad78 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Wed, 18 Apr 2018 23:02:36 +0300
+Subject: [PATCH] sdk_fman: disable timer code in arm code
+
+The (unused) timer code is no longer compatible with the newer
+kernel API. Disabling the incompatible code in the arm64 code.
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_arm_linux.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_arm_linux.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_arm_linux.c
+@@ -607,7 +607,7 @@ uint32_t XX_CurrentTime(void)
+     return (jiffies*1000)/HZ;
+ }
+-
++#if 0
+ t_Handle XX_CreateTimer(void)
+ {
+     struct timer_list *p_Timer = (struct timer_list *)XX_Malloc(sizeof(struct timer_list));
+@@ -684,6 +684,7 @@ int XX_TimerIsActive(t_Handle h_Timer)
+ {
+   return timer_pending((struct timer_list *)h_Timer);
+ }
++#endif
+ uint32_t XX_Sleep(uint32_t msecs)
+ {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0062-sdk_dpa-adapt-ceetm-code-to-new-kernel-API.patch b/target/linux/layerscape/patches-5.4/701-net-0062-sdk_dpa-adapt-ceetm-code-to-new-kernel-API.patch
new file mode 100644 (file)
index 0000000..0df0aae
--- /dev/null
@@ -0,0 +1,108 @@
+From 4026225a854760fa355e393a386b6c96d794bce2 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Tue, 24 Apr 2018 17:07:25 +0300
+Subject: [PATCH] sdk_dpa: adapt ceetm code to new kernel API
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 26 +++++++++++++---------
+ 1 file changed, 16 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -577,7 +577,8 @@ nla_put_failure:
+ /* Configure a root ceetm qdisc */
+ static int ceetm_init_root(struct Qdisc *sch, struct ceetm_qdisc *priv,
+-                         struct tc_ceetm_qopt *qopt)
++                         struct tc_ceetm_qopt *qopt,
++                         struct netlink_ext_ack *extack)
+ {
+       struct netdev_queue *dev_queue;
+       struct Qdisc *qdisc;
+@@ -622,7 +623,7 @@ static int ceetm_init_root(struct Qdisc
+                                     TC_H_MIN(i + PFIFO_MIN_OFFSET));
+               qdisc = qdisc_create_dflt(dev_queue, &pfifo_qdisc_ops,
+-                                        parent_id);
++                                        parent_id, extack);
+               if (!qdisc) {
+                       err = -ENOMEM;
+                       goto err_init_root;
+@@ -1035,7 +1036,8 @@ err_init_wbfs:
+ }
+ /* Configure a generic ceetm qdisc */
+-static int ceetm_init(struct Qdisc *sch, struct nlattr *opt)
++static int ceetm_init(struct Qdisc *sch, struct nlattr *opt,
++                    struct netlink_ext_ack *extack)
+ {
+       struct tc_ceetm_qopt *qopt;
+       struct nlattr *tb[TCA_CEETM_QOPS + 1];
+@@ -1053,7 +1055,7 @@ static int ceetm_init(struct Qdisc *sch,
+               return -EINVAL;
+       }
+-      ret = tcf_block_get(&priv->block, &priv->filter_list, sch);
++      ret = tcf_block_get(&priv->block, &priv->filter_list, sch, extack);
+       if (ret)
+               return ret;
+@@ -1087,7 +1089,7 @@ static int ceetm_init(struct Qdisc *sch,
+       switch (priv->type) {
+       case CEETM_ROOT:
+-              ret = ceetm_init_root(sch, priv, qopt);
++              ret = ceetm_init_root(sch, priv, qopt, extack);
+               break;
+       case CEETM_PRIO:
+               ret = ceetm_init_prio(sch, priv, qopt);
+@@ -1224,7 +1226,8 @@ change_err:
+ }
+ /* Edit a ceetm qdisc */
+-static int ceetm_change(struct Qdisc *sch, struct nlattr *opt)
++static int ceetm_change(struct Qdisc *sch, struct nlattr *opt,
++                      struct netlink_ext_ack *extack)
+ {
+       struct tc_ceetm_qopt *qopt;
+       struct nlattr *tb[TCA_CEETM_QOPS + 1];
+@@ -1410,7 +1413,8 @@ static int ceetm_cls_change_wbfs(struct
+ /* Add a ceetm root class or configure a ceetm root/prio/wbfs class */
+ static int ceetm_cls_change(struct Qdisc *sch, u32 classid, u32 parentid,
+-                          struct nlattr **tca, unsigned long *arg)
++                          struct nlattr **tca, unsigned long *arg,
++                          struct netlink_ext_ack *extack)
+ {
+       int err;
+       u64 bps;
+@@ -1505,7 +1509,7 @@ static int ceetm_cls_change(struct Qdisc
+       if (!cl)
+               return -ENOMEM;
+-      err = tcf_block_get(&cl->block, &cl->filter_list, sch);
++      err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack);
+       if (err) {
+               kfree(cl);
+               return err;
+@@ -1699,7 +1703,8 @@ static struct Qdisc *ceetm_cls_leaf(stru
+ }
+ static int ceetm_cls_graft(struct Qdisc *sch, unsigned long arg,
+-                         struct Qdisc *new, struct Qdisc **old)
++                         struct Qdisc *new, struct Qdisc **old,
++                         struct netlink_ext_ack *extack)
+ {
+       if (new && strcmp(new->ops->id, ceetm_qdisc_ops.id)) {
+               pr_err("CEETM: only ceetm qdiscs can be attached to ceetm classes\n");
+@@ -1763,7 +1768,8 @@ static int ceetm_cls_dump_stats(struct Q
+       return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
+ }
+-static struct tcf_block *ceetm_tcf_block(struct Qdisc *sch, unsigned long arg)
++static struct tcf_block *ceetm_tcf_block(struct Qdisc *sch, unsigned long arg,
++                                       struct netlink_ext_ack *extack)
+ {
+       struct ceetm_qdisc *priv = qdisc_priv(sch);
+       struct ceetm_class *cl = (struct ceetm_class *)arg;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0063-sdk_dpaa-propagate-the-skb-ownership-information.patch b/target/linux/layerscape/patches-5.4/701-net-0063-sdk_dpaa-propagate-the-skb-ownership-information.patch
new file mode 100644 (file)
index 0000000..f906dc9
--- /dev/null
@@ -0,0 +1,33 @@
+From 1a5fe4c83c7ba997a7fc433fcfc4818d48689ecc Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Wed, 25 Apr 2018 18:49:32 +0300
+Subject: [PATCH] sdk_dpaa: propagate the skb ownership information
+
+Some skbs on the Tx path may be reallocated by the driver
+due to insufficient headroom, in which case the socket
+value gets lost.
+
+Make sure we propagate the skb ownership information to the
+new skb, since it's needed by the Tx timestamp function in
+the kernel.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -1113,6 +1113,11 @@ int __hot dpa_tx_extended(struct sk_buff
+                               percpu_stats->tx_errors++;
+                               return NETDEV_TX_OK;
+                       }
++
++                      /* propagate the skb ownership information */
++                      if (skb->sk)
++                              skb_set_owner_w(skb_new, skb->sk);
++
+                       dev_kfree_skb(skb);
+                       skb = skb_new;
+               }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0064-memac_init_phy-RGMII-fixed-link-pass-adjust_link-cal.patch b/target/linux/layerscape/patches-5.4/701-net-0064-memac_init_phy-RGMII-fixed-link-pass-adjust_link-cal.patch
new file mode 100644 (file)
index 0000000..7271c34
--- /dev/null
@@ -0,0 +1,85 @@
+From 79eacb8b197f7459a75c7d3ec33ceef88475d5a1 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 4 May 2018 19:23:59 +0300
+Subject: [PATCH] memac_init_phy: RGMII fixed-link: pass adjust_link callback
+ to of_phy_connect
+
+* The mEMAC configuration for RGMII is held in the IF_MODE register
+* In the driver, IF_MODE is configured in 2 places (both in fman_memac.c):
+    - fman_memac_init: sets the IF_MODE bit macro IF_MODE_RGMII_AUTO
+      (this translates to setting ENA = 1 - Enable automatic speed selection
+      - RGMII PHY in-band status information is used to select the speed
+      of operation).
+    - fman_memac_adjust_link: brings the RGMII port in ENA = 0 mode
+      (link speed not determined autonomously by the MAC, but set according
+      to SSP).
+* The issue with the current code is that in the case of RGMII fixed-link,
+  the of_phy_attach function is being called, instead of of_phy_connect
+  with a callback that calls fman_memac_adjust_link.
+* For this reason, the RGMII port is left in a state with ENA = 1. In
+  most (if not all) RGMII fixed-link setups, the link partner will not
+  send any in-bank link speed information that is expected by the mEMAC.
+* The effect is that the link speed setting will probably not be correct
+  (and will definitely not be according to the "fixed-link" property in
+  the DTS).
+* The adjust_link callback seems to be called by the PHY state machine,
+  even for fixed links, exactly once: on "link up". Therefore, this
+  patch ensures that on link up, RGMII fixed links are configured to the
+  link speed that is set in the DTS, and not left with IF_MODE[ENA] = 1.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c | 38 ++++++++++++++++++-----
+ 1 file changed, 31 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c
+@@ -502,17 +502,41 @@ static int memac_init_phy(struct net_dev
+                         struct mac_device *mac_dev)
+ {
+       struct phy_device       *phy_dev;
++      void (*adjust_link_handler)(struct net_device *);
+       if ((macdev2enetinterface(mac_dev) == e_ENET_MODE_XGMII_10000) ||
+-          (macdev2enetinterface(mac_dev) == e_ENET_MODE_SGMII_2500) ||
+-          of_phy_is_fixed_link(mac_dev->phy_node)) {
+-              phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
+-                                       &adjust_link_void, 0,
+-                                       mac_dev->phy_if);
++          (macdev2enetinterface(mac_dev) == e_ENET_MODE_SGMII_2500)) {
++              /* Pass a void link state handler to the PHY state machine
++               * for XGMII (10G) and SGMII 2.5G, as the hardware does not
++               * permit dynamic link speed adjustments. */
++              adjust_link_handler = adjust_link_void;
++      } else if (macdev2enetinterface(mac_dev) & e_ENET_IF_RGMII) {
++              /* Regular RGMII ports connected to a PHY, as well as
++               * ports that are marked as "fixed-link" in the DTS,
++               * will have the adjust_link callback. This calls
++               * fman_memac_adjust_link in order to configure the
++               * IF_MODE register, which is needed in both cases.
++               */
++              adjust_link_handler = adjust_link;
++      } else if (of_phy_is_fixed_link(mac_dev->phy_node)) {
++              /* Pass a void link state handler for fixed-link
++               * interfaces that are not RGMII. Only RGMII has been
++               * tested and confirmed to work with fixed-link. Other
++               * MII interfaces may need further work.
++               * TODO: Change this as needed.
++               */
++              adjust_link_handler = adjust_link_void;
+       } else {
+-              phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
+-                                       &adjust_link, 0, mac_dev->phy_if);
++              /* MII, RMII, SMII, GMII, SGMII, BASEX ports,
++               * that are NOT fixed-link.
++               * TODO: May not be needed for interfaces that
++               * pass through the SerDes block (*SGMII, XFI).
++               */
++              adjust_link_handler = adjust_link;
+       }
++      phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
++                               adjust_link_handler, 0,
++                               mac_dev->phy_if);
+       if (unlikely(phy_dev == NULL) || IS_ERR(phy_dev)) {
+               netdev_err(net_dev, "Could not connect to PHY %s\n",
diff --git a/target/linux/layerscape/patches-5.4/701-net-0065-sdk_dpaa-ceetm-avoid-use-after-free-scenarios.patch b/target/linux/layerscape/patches-5.4/701-net-0065-sdk_dpaa-ceetm-avoid-use-after-free-scenarios.patch
new file mode 100644 (file)
index 0000000..f3d591e
--- /dev/null
@@ -0,0 +1,67 @@
+From fad6f73dc4367adb852ce6953f93f12cbb97b894 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Fri, 18 May 2018 10:33:37 +0300
+Subject: [PATCH] sdk_dpaa: ceetm: avoid use-after-free scenarios
+
+Once the pfiofo qdiscs are grafted to the netdev queues, they are destroyed
+by the kernel when required. Remove references to the pfifo qdiscs after
+grafting, in order to avoid double free scenarios.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 23 +++++++++++++++++++---
+ 1 file changed, 20 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -477,7 +477,9 @@ static void ceetm_destroy(struct Qdisc *
+               if (!priv->root.qdiscs)
+                       break;
+-              /* Remove the pfifo qdiscs */
++              /* Destroy the pfifo qdiscs in case they haven't been attached
++               * to the netdev queues yet.
++               */
+               for (ntx = 0; ntx < dev->num_tx_queues; ntx++)
+                       if (priv->root.qdiscs[ntx])
+                               qdisc_destroy(priv->root.qdiscs[ntx]);
+@@ -608,7 +610,16 @@ static int ceetm_init_root(struct Qdisc
+               goto err_init_root;
+       }
+-      /* pre-allocate underlying pfifo qdiscs */
++      /* Pre-allocate underlying pfifo qdiscs.
++       *
++       * We want to offload shaping and scheduling decisions to the hardware.
++       * The pfifo qdiscs will be attached to the netdev queues and will
++       * guide the traffic from the IP stack down to the driver with minimum
++       * interference.
++       *
++       * The CEETM qdiscs and classes will be crossed when the traffic
++       * reaches the driver.
++       */
+       priv->root.qdiscs = kcalloc(dev->num_tx_queues,
+                                   sizeof(priv->root.qdiscs[0]),
+                                   GFP_KERNEL);
+@@ -1280,7 +1291,10 @@ static int ceetm_change(struct Qdisc *sc
+       return ret;
+ }
+-/* Attach the underlying pfifo qdiscs */
++/* Graft the underlying pfifo qdiscs to the netdev queues.
++ * It's safe to remove our references at this point, since the kernel will
++ * destroy the qdiscs on its own and no cleanup from our part is required.
++ */
+ static void ceetm_attach(struct Qdisc *sch)
+ {
+       struct net_device *dev = qdisc_dev(sch);
+@@ -1296,6 +1310,9 @@ static void ceetm_attach(struct Qdisc *s
+               if (old_qdisc)
+                       qdisc_destroy(old_qdisc);
+       }
++
++      kfree(priv->root.qdiscs);
++      priv->root.qdiscs = NULL;
+ }
+ static unsigned long ceetm_cls_search(struct Qdisc *sch, u32 handle)
diff --git a/target/linux/layerscape/patches-5.4/701-net-0066-sdk_dpaa-ceetm-stop-the-netdev-queues-when-switching.patch b/target/linux/layerscape/patches-5.4/701-net-0066-sdk_dpaa-ceetm-stop-the-netdev-queues-when-switching.patch
new file mode 100644 (file)
index 0000000..49c0e2e
--- /dev/null
@@ -0,0 +1,23 @@
+From ceecb6c2de60f19c674d4e59dde2523db7a9099b Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 19 Mar 2018 18:39:59 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: stop the netdev queues when switching ceetm
+ on
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -1100,7 +1100,9 @@ static int ceetm_init(struct Qdisc *sch,
+       switch (priv->type) {
+       case CEETM_ROOT:
++              netif_tx_stop_all_queues(dev);
+               ret = ceetm_init_root(sch, priv, qopt, extack);
++              netif_tx_wake_all_queues(dev);
+               break;
+       case CEETM_PRIO:
+               ret = ceetm_init_prio(sch, priv, qopt);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0067-fsl_qbman-ceetm-export-the-qman_ceetm_query_cq-call.patch b/target/linux/layerscape/patches-5.4/701-net-0067-fsl_qbman-ceetm-export-the-qman_ceetm_query_cq-call.patch
new file mode 100644 (file)
index 0000000..da4a480
--- /dev/null
@@ -0,0 +1,31 @@
+From d4ef67474d985f6a95ea54a7e0c11d6d0ffa9fe9 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 26 Mar 2018 17:12:17 +0300
+Subject: [PATCH] fsl_qbman: ceetm: export the qman_ceetm_query_cq call
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ include/linux/fsl_qman.h | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/include/linux/fsl_qman.h
++++ b/include/linux/fsl_qman.h
+@@ -3813,6 +3813,18 @@ int qman_ceetm_query_lfqmt(int lfqid,
+                          struct qm_mcr_ceetm_lfqmt_query *lfqmt_query);
+ /**
++ * qman_ceetm_query_cq - Queries a CEETM CQ
++ * @cqid: the channel ID (first byte) followed by the CQ idx
++ * @dcpid: CEETM portal ID
++ * @cq_query: storage for the queried CQ fields
++ *
++ * Returns zero for success or -EIO if the query command returns error.
++ *
++*/
++int qman_ceetm_query_cq(unsigned int cqid, unsigned int dcpid,
++                      struct qm_mcr_ceetm_cq_query *cq_query);
++
++/**
+  * qman_ceetm_query_write_statistics - Query (and optionally write) statistics
+  * @cid: Target ID (CQID or CCGRID)
+  * @dcp_idx: CEETM portal ID
diff --git a/target/linux/layerscape/patches-5.4/701-net-0068-sdk_dpaa-ceetm-propagate-the-ceetm-channel-through-t.patch b/target/linux/layerscape/patches-5.4/701-net-0068-sdk_dpaa-ceetm-propagate-the-ceetm-channel-through-t.patch
new file mode 100644 (file)
index 0000000..f106702
--- /dev/null
@@ -0,0 +1,298 @@
+From dfd2deb8bc482588999a4f03b5ab5d049e50fdb0 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 30 May 2018 14:51:35 +0300
+Subject: [PATCH] sdk_dpaa: ceetm: propagate the ceetm channel through the
+ qdisc tree
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 61 +++++++++-------------
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h   |  4 +-
+ 2 files changed, 29 insertions(+), 36 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -242,7 +242,6 @@ static int ceetm_config_lfq(struct qm_ce
+ /* Configure a prio ceetm class */
+ static int ceetm_config_prio_cls(struct ceetm_class *cls,
+                                struct net_device *dev,
+-                               struct qm_ceetm_channel *channel,
+                                unsigned int id)
+ {
+       int err;
+@@ -253,22 +252,22 @@ static int ceetm_config_prio_cls(struct
+               return err;
+       /* Claim and configure the CCG */
+-      err = ceetm_config_ccg(&cls->prio.ccg, channel, id, cls->prio.fq,
++      err = ceetm_config_ccg(&cls->prio.ccg, cls->ch, id, cls->prio.fq,
+                              dpa_priv);
+       if (err)
+               return err;
+       /* Claim and configure the CQ */
+-      err = qman_ceetm_cq_claim(&cls->prio.cq, channel, id, cls->prio.ccg);
++      err = qman_ceetm_cq_claim(&cls->prio.cq, cls->ch, id, cls->prio.ccg);
+       if (err)
+               return err;
+       if (cls->shaped) {
+-              err = qman_ceetm_channel_set_cq_cr_eligibility(channel, id, 1);
++              err = qman_ceetm_channel_set_cq_cr_eligibility(cls->ch, id, 1);
+               if (err)
+                       return err;
+-              err = qman_ceetm_channel_set_cq_er_eligibility(channel, id, 1);
++              err = qman_ceetm_channel_set_cq_er_eligibility(cls->ch, id, 1);
+               if (err)
+                       return err;
+       }
+@@ -284,7 +283,6 @@ static int ceetm_config_prio_cls(struct
+ /* Configure a wbfs ceetm class */
+ static int ceetm_config_wbfs_cls(struct ceetm_class *cls,
+                                struct net_device *dev,
+-                               struct qm_ceetm_channel *channel,
+                                unsigned int id, int type)
+ {
+       int err;
+@@ -295,17 +293,17 @@ static int ceetm_config_wbfs_cls(struct
+               return err;
+       /* Claim and configure the CCG */
+-      err = ceetm_config_ccg(&cls->wbfs.ccg, channel, id, cls->wbfs.fq,
++      err = ceetm_config_ccg(&cls->wbfs.ccg, cls->ch, id, cls->wbfs.fq,
+                              dpa_priv);
+       if (err)
+               return err;
+       /* Claim and configure the CQ */
+       if (type == WBFS_GRP_B)
+-              err = qman_ceetm_cq_claim_B(&cls->wbfs.cq, channel, id,
++              err = qman_ceetm_cq_claim_B(&cls->wbfs.cq, cls->ch, id,
+                                           cls->wbfs.ccg);
+       else
+-              err = qman_ceetm_cq_claim_A(&cls->wbfs.cq, channel, id,
++              err = qman_ceetm_cq_claim_A(&cls->wbfs.cq, cls->ch, id,
+                                           cls->wbfs.ccg);
+       if (err)
+               return err;
+@@ -366,10 +364,10 @@ static void ceetm_cls_destroy(struct Qdi
+                       cl->root.child = NULL;
+               }
+-              if (cl->root.ch && qman_ceetm_channel_release(cl->root.ch))
++              if (cl->ch && qman_ceetm_channel_release(cl->ch))
+                       pr_err(KBUILD_BASENAME
+                              " : %s : error releasing the channel %d\n",
+-                             __func__, cl->root.ch->idx);
++                             __func__, cl->ch->idx);
+               break;
+@@ -766,6 +764,7 @@ static int ceetm_init_prio(struct Qdisc
+       priv->shaped = parent_cl->shaped;
+       priv->prio.qcount = qopt->qcount;
++      priv->prio.ch = parent_cl->ch;
+       /* Create and configure qcount child classes */
+       for (i = 0; i < priv->prio.qcount; i++) {
+@@ -790,6 +789,7 @@ static int ceetm_init_prio(struct Qdisc
+               child_cl->type = CEETM_PRIO;
+               child_cl->shaped = priv->shaped;
+               child_cl->prio.child = NULL;
++              child_cl->ch = priv->prio.ch;
+               /* All shaped CQs have CR and ER enabled by default */
+               child_cl->prio.cr = child_cl->shaped;
+@@ -798,8 +798,7 @@ static int ceetm_init_prio(struct Qdisc
+               child_cl->prio.cq = NULL;
+               /* Configure the corresponding hardware CQ */
+-              err = ceetm_config_prio_cls(child_cl, dev,
+-                                          parent_cl->root.ch, i);
++              err = ceetm_config_prio_cls(child_cl, dev, i);
+               if (err) {
+                       pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm prio class %X\n",
+                              __func__, child_cl->common.classid);
+@@ -831,7 +830,6 @@ static int ceetm_init_wbfs(struct Qdisc
+       struct ceetm_class *parent_cl, *child_cl, *root_cl;
+       struct Qdisc *parent_qdisc;
+       struct ceetm_qdisc *parent_priv;
+-      struct qm_ceetm_channel *channel;
+       struct net_device *dev = qdisc_dev(sch);
+       pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+@@ -904,8 +902,7 @@ static int ceetm_init_wbfs(struct Qdisc
+       priv->wbfs.qcount = qopt->qcount;
+       priv->wbfs.cr = qopt->cr;
+       priv->wbfs.er = qopt->er;
+-
+-      channel = root_cl->root.ch;
++      priv->wbfs.ch = parent_cl->ch;
+       /* Configure the hardware wbfs channel groups */
+       if (priv->wbfs.qcount == CEETM_MAX_WBFS_QCOUNT) {
+@@ -920,7 +917,7 @@ static int ceetm_init_wbfs(struct Qdisc
+               /* Configure the group B */
+               priv->wbfs.group_type = WBFS_GRP_B;
+-              err = qman_ceetm_channel_get_group(channel, &small_group,
++              err = qman_ceetm_channel_get_group(priv->wbfs.ch, &small_group,
+                                                  &prio_a, &prio_b);
+               if (err) {
+                       pr_err(KBUILD_BASENAME " : %s : failed to get group details\n",
+@@ -938,7 +935,7 @@ static int ceetm_init_wbfs(struct Qdisc
+               /* Configure the small group A */
+               priv->wbfs.group_type = WBFS_GRP_A;
+-              err = qman_ceetm_channel_get_group(channel, &small_group,
++              err = qman_ceetm_channel_get_group(priv->wbfs.ch, &small_group,
+                                                  &prio_a, &prio_b);
+               if (err) {
+                       pr_err(KBUILD_BASENAME " : %s : failed to get group details\n",
+@@ -953,13 +950,13 @@ static int ceetm_init_wbfs(struct Qdisc
+               prio_b = prio_b ? : prio_a;
+       }
+-      err = qman_ceetm_channel_set_group(channel, small_group, prio_a,
++      err = qman_ceetm_channel_set_group(priv->wbfs.ch, small_group, prio_a,
+                                          prio_b);
+       if (err)
+               goto err_init_wbfs;
+       if (priv->shaped) {
+-              err = qman_ceetm_channel_set_group_cr_eligibility(channel,
++              err = qman_ceetm_channel_set_group_cr_eligibility(priv->wbfs.ch,
+                                                                 group_b,
+                                                               priv->wbfs.cr);
+               if (err) {
+@@ -968,7 +965,7 @@ static int ceetm_init_wbfs(struct Qdisc
+                       goto err_init_wbfs;
+               }
+-              err = qman_ceetm_channel_set_group_er_eligibility(channel,
++              err = qman_ceetm_channel_set_group_er_eligibility(priv->wbfs.ch,
+                                                                 group_b,
+                                                               priv->wbfs.er);
+               if (err) {
+@@ -1003,13 +1000,14 @@ static int ceetm_init_wbfs(struct Qdisc
+               child_cl->wbfs.fq = NULL;
+               child_cl->wbfs.cq = NULL;
+               child_cl->wbfs.weight = qopt->qweight[i];
++              child_cl->ch = priv->wbfs.ch;
+               if (priv->wbfs.group_type == WBFS_GRP_B)
+                       id = WBFS_GRP_B_OFFSET + i;
+               else
+                       id = WBFS_GRP_A_OFFSET + i;
+-              err = ceetm_config_wbfs_cls(child_cl, dev, channel, id,
++              err = ceetm_config_wbfs_cls(child_cl, dev, id,
+                                           priv->wbfs.group_type);
+               if (err) {
+                       pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm wbfs class %X\n",
+@@ -1178,9 +1176,6 @@ static int ceetm_change_wbfs(struct Qdis
+ {
+       int err;
+       bool group_b;
+-      struct qm_ceetm_channel *channel;
+-      struct ceetm_class *prio_class, *root_class;
+-      struct ceetm_qdisc *prio_qdisc;
+       if (qopt->qcount) {
+               pr_err("CEETM: the qcount can not be modified\n");
+@@ -1206,14 +1201,10 @@ static int ceetm_change_wbfs(struct Qdis
+       if (!priv->shaped)
+               return 0;
+-      prio_class = priv->wbfs.parent;
+-      prio_qdisc = qdisc_priv(prio_class->parent);
+-      root_class = prio_qdisc->prio.parent;
+-      channel = root_class->root.ch;
+       group_b = priv->wbfs.group_type == WBFS_GRP_B;
+       if (qopt->cr != priv->wbfs.cr) {
+-              err = qman_ceetm_channel_set_group_cr_eligibility(channel,
++              err = qman_ceetm_channel_set_group_cr_eligibility(priv->wbfs.ch,
+                                                                 group_b,
+                                                                 qopt->cr);
+               if (err)
+@@ -1222,7 +1213,7 @@ static int ceetm_change_wbfs(struct Qdis
+       }
+       if (qopt->er != priv->wbfs.er) {
+-              err = qman_ceetm_channel_set_group_er_eligibility(channel,
++              err = qman_ceetm_channel_set_group_er_eligibility(priv->wbfs.ch,
+                                                                 group_b,
+                                                                 qopt->er);
+               if (err)
+@@ -1337,7 +1328,7 @@ static int ceetm_cls_change_root(struct
+       if (cl->shaped && cl->root.rate != copt->rate) {
+               bps = copt->rate << 3; /* Bps -> bps */
+-              err = qman_ceetm_channel_set_commit_rate_bps(cl->root.ch, bps,
++              err = qman_ceetm_channel_set_commit_rate_bps(cl->ch, bps,
+                                                            dev->mtu);
+               if (err)
+                       goto change_cls_err;
+@@ -1346,7 +1337,7 @@ static int ceetm_cls_change_root(struct
+       if (cl->shaped && cl->root.ceil != copt->ceil) {
+               bps = copt->ceil << 3; /* Bps -> bps */
+-              err = qman_ceetm_channel_set_excess_rate_bps(cl->root.ch, bps,
++              err = qman_ceetm_channel_set_excess_rate_bps(cl->ch, bps,
+                                                            dev->mtu);
+               if (err)
+                       goto change_cls_err;
+@@ -1354,7 +1345,7 @@ static int ceetm_cls_change_root(struct
+       }
+       if (!cl->shaped && cl->root.tbl != copt->tbl) {
+-              err = qman_ceetm_channel_set_weight(cl->root.ch, copt->tbl);
++              err = qman_ceetm_channel_set_weight(cl->ch, copt->tbl);
+               if (err)
+                       goto change_cls_err;
+               cl->root.tbl = copt->tbl;
+@@ -1555,7 +1546,7 @@ static int ceetm_cls_change(struct Qdisc
+               goto claim_err;
+       }
+-      cl->root.ch = channel;
++      cl->ch = channel;
+       if (cl->shaped) {
+               /* Configure the channel shaper */
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h
+@@ -121,12 +121,14 @@ struct root_q {
+ struct prio_q {
+       __u16 qcount;
+       struct ceetm_class *parent;
++      struct qm_ceetm_channel *ch;
+ };
+ struct wbfs_q {
+       __u16 qcount;
+       int group_type;
+       struct ceetm_class *parent;
++      struct qm_ceetm_channel *ch;
+       __u16 cr;
+       __u16 er;
+ };
+@@ -165,7 +167,6 @@ struct root_c {
+       bool wbfs_grp_b;
+       bool wbfs_grp_large;
+       struct Qdisc *child;
+-      struct qm_ceetm_channel *ch;
+ };
+ struct prio_c {
+@@ -194,6 +195,7 @@ struct ceetm_class {
+       struct tcf_proto *filter_list; /* class attached filters */
+       struct tcf_block *block;
+       struct Qdisc *parent;
++      struct qm_ceetm_channel *ch;
+       bool shaped;
+       int type; /* ROOT/PRIO/WBFS */
+       union {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0069-sdk_dpaa-ceetm-reset-the-wbfs-groups-and-priorities-.patch b/target/linux/layerscape/patches-5.4/701-net-0069-sdk_dpaa-ceetm-reset-the-wbfs-groups-and-priorities-.patch
new file mode 100644 (file)
index 0000000..fb6ac75
--- /dev/null
@@ -0,0 +1,24 @@
+From 3aa80007715ecfd944e02029b59fec5c74c8598e Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 30 May 2018 15:04:37 +0300
+Subject: [PATCH] sdk_dpaa: ceetm: reset the wbfs groups and priorities on
+ teardown
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -491,6 +491,10 @@ static void ceetm_destroy(struct Qdisc *
+               break;
+       case CEETM_WBFS:
++              /* Reset the WBFS groups and priorities */
++              if (priv->wbfs.ch)
++                      qman_ceetm_channel_set_group(priv->wbfs.ch, 1, 0, 0);
++
+               if (priv->wbfs.parent)
+                       priv->wbfs.parent->prio.child = NULL;
+               break;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0070-sdk_dpaa-ceetm-WQ-CEETM-mode-switchover-cleanup.patch b/target/linux/layerscape/patches-5.4/701-net-0070-sdk_dpaa-ceetm-WQ-CEETM-mode-switchover-cleanup.patch
new file mode 100644 (file)
index 0000000..76c0eca
--- /dev/null
@@ -0,0 +1,54 @@
+From c095bbc29eeae597c47c90d41fab472be9e14ca6 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 30 May 2018 15:26:47 +0300
+Subject: [PATCH] sdk_dpaa: ceetm: WQ/CEETM mode switchover cleanup
+
+Wait for the WQ TX FQs to empty before switching from WQ to CEETM mode.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 26 ++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -65,6 +65,31 @@ static void get_dcp_and_sp(struct net_de
+       }
+ }
++/* Wait for the DPAA Eth driver WQ TX FQs to empty */
++static void dpaa_drain_fqs(struct net_device *dev)
++{
++      const struct dpa_priv_s *priv = netdev_priv(dev);
++      struct qm_mcr_queryfq_np np;
++      struct qman_fq *fq;
++      int ret, i;
++
++      for (i = 0; i < DPAA_ETH_TX_QUEUES; i ++) {
++              fq = priv->egress_fqs[i];
++              while (true) {
++                      ret = qman_query_fq_np(fq, &np);
++                      if (unlikely(ret)) {
++                              pr_err(KBUILD_BASENAME
++                                     " : %s : unable to query FQ %x: %d\n",
++                                     __func__, fq->fqid, ret);
++                              break;
++                      }
++
++                      if (np.frm_cnt == 0)
++                              break;
++              }
++      }
++}
++
+ /* Enqueue Rejection Notification callback */
+ static void ceetm_ern(struct qman_portal *portal, struct qman_fq *fq,
+                     const struct qm_mr_entry *msg)
+@@ -1103,6 +1128,7 @@ static int ceetm_init(struct Qdisc *sch,
+       switch (priv->type) {
+       case CEETM_ROOT:
+               netif_tx_stop_all_queues(dev);
++              dpaa_drain_fqs(dev);
+               ret = ceetm_init_root(sch, priv, qopt, extack);
+               netif_tx_wake_all_queues(dev);
+               break;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0071-sdk_dpaa-ceetm-drain-the-ceetm-CQs-on-destroy.patch b/target/linux/layerscape/patches-5.4/701-net-0071-sdk_dpaa-ceetm-drain-the-ceetm-CQs-on-destroy.patch
new file mode 100644 (file)
index 0000000..bdca236
--- /dev/null
@@ -0,0 +1,116 @@
+From fe7ed61721646077de5eb06a105e60634374a00c Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Thu, 31 May 2018 10:45:50 +0300
+Subject: [PATCH] sdk_dpaa: ceetm: drain the ceetm CQs on destroy
+
+The CEETM CQs must be empty when configured. To guarantee this, stop all
+transmissions and wait for them to drain before releasing them. On the
+next configuration, we are certain they will be empty.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 62 ++++++++++++++++++++++
+ 1 file changed, 62 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -90,6 +90,51 @@ static void dpaa_drain_fqs(struct net_de
+       }
+ }
++/* Wait for the DPAA CEETM TX CQs to empty */
++static void ceetm_drain_class(struct ceetm_class *cl)
++{
++      struct qm_mcr_ceetm_cq_query cq_query;
++      struct qm_ceetm_cq *cq;
++      unsigned int idx;
++      int ret;
++
++      if (!cl)
++              return;
++
++      switch (cl->type) {
++      case CEETM_ROOT:
++              /* The ROOT classes aren't directly linked to CEETM CQs */
++              return;
++      case CEETM_PRIO:
++              cq = (struct qm_ceetm_cq*)cl->prio.cq;
++              break;
++      case CEETM_WBFS:
++              cq = (struct qm_ceetm_cq*)cl->wbfs.cq;
++              break;
++      }
++
++      if (!cq || !cl->ch)
++              return;
++
++      /* Build the query CQID by merging the channel and the CQ IDs */
++      idx = (cq->parent->idx << 4) | cq->idx;
++
++      while (true) {
++              ret = qman_ceetm_query_cq(idx,
++                                        cl->ch->dcp_idx,
++                                        &cq_query);
++              if (unlikely(ret)) {
++                      pr_err(KBUILD_BASENAME
++                             " : %s : unable to query CQ %x: %d\n",
++                             __func__, idx, ret);
++                      break;
++              }
++
++              if (cq_query.frm_cnt == 0)
++                      break;
++      }
++}
++
+ /* Enqueue Rejection Notification callback */
+ static void ceetm_ern(struct qman_portal *portal, struct qman_fq *fq,
+                     const struct qm_mr_entry *msg)
+@@ -376,6 +421,8 @@ static void ceetm_link_class(struct Qdis
+ /* Destroy a ceetm class */
+ static void ceetm_cls_destroy(struct Qdisc *sch, struct ceetm_class *cl)
+ {
++      struct net_device *dev = qdisc_dev(sch);
++
+       if (!cl)
+               return;
+@@ -402,6 +449,12 @@ static void ceetm_cls_destroy(struct Qdi
+                       cl->prio.child = NULL;
+               }
++              /* We must make sure the CQ is empty before releasing it.
++               * Pause all transmissions while we wait for it to drain.
++               */
++              netif_tx_stop_all_queues(dev);
++              ceetm_drain_class(cl);
++
+               if (cl->prio.lfq && qman_ceetm_lfq_release(cl->prio.lfq))
+                       pr_err(KBUILD_BASENAME
+                              " : %s : error releasing the LFQ %d\n",
+@@ -422,9 +475,16 @@ static void ceetm_cls_destroy(struct Qdi
+               if (cl->prio.cstats)
+                       free_percpu(cl->prio.cstats);
++              netif_tx_wake_all_queues(dev);
+               break;
+       case CEETM_WBFS:
++              /* We must make sure the CQ is empty before releasing it.
++               * Pause all transmissions while we wait for it to drain.
++               */
++              netif_tx_stop_all_queues(dev);
++              ceetm_drain_class(cl);
++
+               if (cl->wbfs.lfq && qman_ceetm_lfq_release(cl->wbfs.lfq))
+                       pr_err(KBUILD_BASENAME
+                              " : %s : error releasing the LFQ %d\n",
+@@ -444,6 +504,8 @@ static void ceetm_cls_destroy(struct Qdi
+               if (cl->wbfs.cstats)
+                       free_percpu(cl->wbfs.cstats);
++
++              netif_tx_wake_all_queues(dev);
+       }
+       tcf_block_put(cl->block);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0072-sdk_dpaa-ls1043a-errata-adapt-to-new-skb-copy-API.patch b/target/linux/layerscape/patches-5.4/701-net-0072-sdk_dpaa-ls1043a-errata-adapt-to-new-skb-copy-API.patch
new file mode 100644 (file)
index 0000000..fa3fe9e
--- /dev/null
@@ -0,0 +1,21 @@
+From 6589b195949605efaa26c71baa2beb3bbf77ee5d Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 3 Jul 2018 10:03:05 +0300
+Subject: [PATCH] sdk_dpaa: ls1043a errata: adapt to new skb copy API
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -852,7 +852,7 @@ static struct sk_buff *a010022_realign_s
+               WARN_ONCE(1, "skb parsing failure\n");
+               goto err;
+       }
+-      copy_skb_header(nskb, skb);
++      skb_copy_header(nskb, skb);
+ #ifdef CONFIG_FSL_DPAA_TS
+       /* Copy relevant timestamp info from the old skb to the new */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0073-dpaa_eth-ERR010022-adapt-to-new-skb-copy-API.patch b/target/linux/layerscape/patches-5.4/701-net-0073-dpaa_eth-ERR010022-adapt-to-new-skb-copy-API.patch
new file mode 100644 (file)
index 0000000..5812922
--- /dev/null
@@ -0,0 +1,21 @@
+From 41047fc3ae025e75a8ac9da8714dbaaef6e63aec Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 3 Jul 2018 10:04:12 +0300
+Subject: [PATCH] dpaa_eth: ERR010022: adapt to new skb copy API
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+@@ -2183,7 +2183,7 @@ static struct sk_buff *dpaa_errata_a0100
+               WARN_ONCE(1, "skb parsing failure\n");
+               goto err;
+       }
+-      copy_skb_header(nskb, skb);
++      skb_copy_header(nskb, skb);
+       /* We move the headroom when we align it so we have to reset the
+        * network and transport header offsets relative to the new data
diff --git a/target/linux/layerscape/patches-5.4/701-net-0074-sdk_dpaa-enable-Jumbo-frame-support-on-LS1043A.patch b/target/linux/layerscape/patches-5.4/701-net-0074-sdk_dpaa-enable-Jumbo-frame-support-on-LS1043A.patch
new file mode 100644 (file)
index 0000000..37da91a
--- /dev/null
@@ -0,0 +1,154 @@
+From fcf41cba6f3ac0f33a5e9e0c7d79dbbbff586271 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 15 May 2018 11:48:42 +0300
+Subject: [PATCH] sdk_dpaa: enable Jumbo frame support on LS1043A
+
+Due to the A010022 errata restrictions, Jumbo frames on LS1043A require two
+conditions to be met:
+- on TX, the data is stored in a contiguous buffer of up to 9600 bytes
+- the data is aligned to 256 bytes
+
+The conditions are met by realigning all outgoing frames to 256 bytes.
+Also, compound pages of varying orders are allocated to accommodate the
+outgoing contiguous buffers.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/Kconfig    |  1 -
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c |  9 ++---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h |  5 +--
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c  | 40 ++++++++--------------
+ 4 files changed, 20 insertions(+), 35 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig
+@@ -80,7 +80,6 @@ config FSL_DPAA_ETH_JUMBO_FRAME
+         significantly the driver's memory footprint and may even deplete
+         the system memory. Also, the skb truesize is altered and messages
+         from the stack that warn against this are bypassed.
+-        This option is not available on LS1043.
+ config FSL_DPAA_TS
+       bool "Linux compliant timestamping"
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
+@@ -779,12 +779,10 @@ static int dpa_private_netdev_init(struc
+       net_dev->features |= NETIF_F_HW_ACCEL_MQ;
+ #ifndef CONFIG_PPC
+-      /* Due to the A010022 FMan errata, we can not use contig frames larger
+-       * than 4K, nor S/G frames. We need to prevent the user from setting a
+-       * large MTU. We also stop advertising S/G and GSO support.
++      /* Due to the A010022 FMan errata, we can not use S/G frames. We need
++       * to stop advertising S/G and GSO support.
+        */
+       if (unlikely(dpaa_errata_a010022)) {
+-              net_dev->max_mtu = DPA_BP_RAW_SIZE;
+               net_dev->hw_features &= ~NETIF_F_SG;
+               net_dev->features &= ~NETIF_F_GSO;
+       }
+@@ -985,9 +983,6 @@ dpaa_eth_priv_probe(struct platform_devi
+       /* We only want to use jumbo frame optimization if we actually have
+        * L2 MAX FRM set for jumbo frames as well.
+        */
+-#ifndef CONFIG_PPC
+-      if (likely(!dpaa_errata_a010022))
+-#endif
+       if(fm_get_max_frm() < 9600)
+               dev_warn(dev,
+                       "Invalid configuration: if jumbo frames support is on, FSL_FM_MAX_FRAME_SIZE should be set to 9600\n");
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
+@@ -672,8 +672,8 @@ static inline void _dpa_bp_free_pf(void
+ /* LS1043A SoC has a HW issue regarding FMan DMA transactions; The issue
+  * manifests itself at high traffic rates when frames cross 4K memory
+  * boundaries or when they are not aligned to 16 bytes; For the moment, we
+- * use a SW workaround to avoid frames larger than 4K or that exceed 4K
+- * alignments and to realign the frames to 16 bytes.
++ * use a SW workaround that realigns frames to 256 bytes. Scatter/Gather
++ * frames aren't supported on egress.
+  */
+ #ifndef CONFIG_PPC
+@@ -682,6 +682,7 @@ extern bool dpaa_errata_a010022; /* SoC
+ #define HAS_DMA_ISSUE(start, size) \
+       (((uintptr_t)(start) + (size)) > \
+        (((uintptr_t)(start) + 0x1000) & ~0xFFF))
++#define DPAA_A010022_HEADROOM 256
+ #endif  /* !CONFIG_PPC */
+ #endif        /* __DPA_H */
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -407,12 +407,6 @@ static struct sk_buff *__hot contig_fd_t
+        * warn us that the frame length is larger than the truesize. We
+        * bypass the warning.
+        */
+-#ifndef CONFIG_PPC
+-      /* We do not support Jumbo frames on LS1043 and thus we edit
+-       * the skb truesize only when the 4k errata is not present.
+-       */
+-      if (likely(!dpaa_errata_a010022))
+-#endif
+       skb->truesize = SKB_TRUESIZE(dpa_fd_length(fd));
+ #endif
+@@ -809,35 +803,31 @@ static struct sk_buff *a010022_realign_s
+ {
+       int trans_offset = skb_transport_offset(skb);
+       int net_offset = skb_network_offset(skb);
++      int nsize, headroom, npage_order;
+       struct sk_buff *nskb = NULL;
+-      int nsize, headroom;
+       struct page *npage;
+       void *npage_addr;
+-      /* Guarantee the minimum required headroom */
+-      if (skb_headroom(skb) >= priv->tx_headroom)
+-              headroom = skb_headroom(skb);
+-      else
+-              headroom = priv->tx_headroom;
++      /* The headroom needs to accommodate our private data (64 bytes) but
++       * we reserve 256 bytes instead to guarantee 256 data alignment.
++       */
++      headroom = DPAA_A010022_HEADROOM;
++
++      /* For the new skb we only need the old one's data (both non-paged and
++       * paged). We can skip the old tailroom.
++       */
++      nsize = headroom + skb->len +
++              SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+-      npage = alloc_page(GFP_ATOMIC);
++      /* Reserve enough memory to accommodate Jumbo frames */
++      npage_order = (nsize - 1) / PAGE_SIZE;
++      npage = alloc_pages(GFP_ATOMIC | __GFP_COMP, npage_order);
+       if (unlikely(!npage)) {
+               WARN_ONCE(1, "Memory allocation failure\n");
+               return NULL;
+       }
+       npage_addr = page_address(npage);
+-      /* For the new skb we only need the old one's data (both non-paged and
+-       * paged) and a headroom large enough to fit our private info. We can
+-       * skip the old tailroom.
+-       *
+-       * Make sure the new linearized buffer will not exceed a page's size.
+-       */
+-      nsize = headroom + skb->len +
+-              SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+-      if (unlikely(nsize > 4096))
+-              goto err;
+-
+       nskb = build_skb(npage_addr, nsize);
+       if (unlikely(!nskb))
+               goto err;
+@@ -846,7 +836,7 @@ static struct sk_buff *a010022_realign_s
+        * alignment.
+        * Code borrowed and adapted from skb_copy().
+        */
+-      skb_reserve(nskb, priv->tx_headroom);
++      skb_reserve(nskb, headroom);
+       skb_put(nskb, skb->len);
+       if (skb_copy_bits(skb, 0, nskb->data, skb->len)) {
+               WARN_ONCE(1, "skb parsing failure\n");
diff --git a/target/linux/layerscape/patches-5.4/701-net-0075-sdk_dpaa-reserve-256-bytes-for-the-SGT-on-TX.patch b/target/linux/layerscape/patches-5.4/701-net-0075-sdk_dpaa-reserve-256-bytes-for-the-SGT-on-TX.patch
new file mode 100644 (file)
index 0000000..2056276
--- /dev/null
@@ -0,0 +1,57 @@
+From 29757ae2e4a0e8e1e816c9eeef59121908320669 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 20 Jun 2018 18:00:42 +0300
+Subject: [PATCH] sdk_dpaa: reserve 256 bytes for the SGT on TX
+
+The FMan reads 256 bytes from the start of the SGT regardless of its
+size. We reserve the same amount of memory on TX to access.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h |  6 ++++--
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c     | 10 +++++++---
+ 2 files changed, 11 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
+@@ -55,10 +55,12 @@
+       fm_set_##type##_port_params(port, &param); \
+ }
++/* The SGT needs to be 256 bytes long. Even if the table has only one entry,
++ * the FMan will read 256 bytes from its start.
++ */
++#define DPA_SGT_SIZE 256
+ #define DPA_SGT_MAX_ENTRIES 16 /* maximum number of entries in SG Table */
+-#define DPA_SGT_ENTRIES_THRESHOLD     DPA_SGT_MAX_ENTRIES
+-
+ #define DPA_BUFF_RELEASE_MAX 8 /* maximum number of buffers released at once */
+ #define DPA_RX_PCD_HI_PRIO_FQ_INIT_FAIL(dpa_fq, _errno) \
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -246,8 +246,8 @@ struct sk_buff *_dpa_cleanup_tx_fd(const
+       if (unlikely(fd->format == qm_fd_sg)) {
+               nr_frags = skb_shinfo(skb)->nr_frags;
+-              dma_unmap_single(dpa_bp->dev, addr, dpa_fd_offset(fd) +
+-                               sizeof(struct qm_sg_entry) * (1 + nr_frags),
++              dma_unmap_single(dpa_bp->dev, addr,
++                               dpa_fd_offset(fd) + DPA_SGT_SIZE,
+                                dma_dir);
+               /* The sgt buffer has been allocated with netdev_alloc_frag(),
+@@ -896,7 +896,11 @@ int __hot skb_to_sg_fd(struct dpa_priv_s
+       nr_frags = skb_shinfo(skb)->nr_frags;
+       fd->format = qm_fd_sg;
+-      sgt_size = sizeof(struct qm_sg_entry) * (1 + nr_frags);
++      /* The FMan reads 256 bytes from the start of the SGT regardless of
++       * its size. In accordance, we reserve the same amount of memory as
++       * well.
++       */
++      sgt_size = DPA_SGT_SIZE;
+       /* Get a page frag to store the SGTable, or a full page if the errata
+        * is in place and we need to avoid crossing a 4k boundary.
diff --git a/target/linux/layerscape/patches-5.4/701-net-0076-fsl_qbman-usdpaa-change-to-debug-print-in-interrupt-.patch b/target/linux/layerscape/patches-5.4/701-net-0076-fsl_qbman-usdpaa-change-to-debug-print-in-interrupt-.patch
new file mode 100644 (file)
index 0000000..71c327b
--- /dev/null
@@ -0,0 +1,21 @@
+From 9be590a85edd0298fb9ad21a26d849ccbadb7530 Mon Sep 17 00:00:00 2001
+From: Nipun Gupta <nipun.gupta@nxp.com>
+Date: Wed, 8 Aug 2018 13:04:18 +0530
+Subject: [PATCH] fsl_qbman/usdpaa: change to debug print in interrupt handler
+
+Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
+---
+ drivers/staging/fsl_qbman/fsl_usdpaa_irq.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl_qbman/fsl_usdpaa_irq.c
++++ b/drivers/staging/fsl_qbman/fsl_usdpaa_irq.c
+@@ -102,7 +102,7 @@ static irqreturn_t usdpaa_irq_handler(in
+       /* Set the inhibit register.  This will be reenabled
+          once the USDPAA code handles the IRQ */
+       out_be32(ctx->inhibit_addr, 0x1);
+-      pr_info("Inhibit at %p count %d", ctx->inhibit_addr, ctx->irq_count);
++      pr_debug("Inhibit at %p count %d", ctx->inhibit_addr, ctx->irq_count);
+       return IRQ_HANDLED;
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0077-staging-fsl_qbman-Consume-all-frames-in-DQRR-during-.patch b/target/linux/layerscape/patches-5.4/701-net-0077-staging-fsl_qbman-Consume-all-frames-in-DQRR-during-.patch
new file mode 100644 (file)
index 0000000..ec79adc
--- /dev/null
@@ -0,0 +1,23 @@
+From 9b4ae951eeabc09fda80e446434ef8f03849522e Mon Sep 17 00:00:00 2001
+From: Roy Pledge <roy.pledge@nxp.com>
+Date: Fri, 22 Jun 2018 15:47:07 -0400
+Subject: [PATCH] staging/fsl_qbman: Consume all frames in DQRR during init
+
+The qm_dqrr_cdc_consume_n() function takes a bitmask, not an index.
+
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+---
+ drivers/staging/fsl_qbman/qman_low.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl_qbman/qman_low.h
++++ b/drivers/staging/fsl_qbman/qman_low.h
+@@ -658,7 +658,7 @@ static inline int qm_dqrr_init(struct qm
+                       qm_dqrr_cce_consume(portal, dqrr->fill);
+                       break;
+               case qm_dqrr_cdc:
+-                      qm_dqrr_cdc_consume_n(portal, (QM_DQRR_SIZE - 1));
++                      qm_dqrr_cdc_consume_n(portal, (1<<QM_DQRR_SIZE) - 1);
+                       break;
+               default:
+                       DPA_ASSERT(0);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0078-staging-fsl_qbman-Recalcuate-cursor-after-consuming-.patch b/target/linux/layerscape/patches-5.4/701-net-0078-staging-fsl_qbman-Recalcuate-cursor-after-consuming-.patch
new file mode 100644 (file)
index 0000000..cbb8efa
--- /dev/null
@@ -0,0 +1,26 @@
+From c9d41c728cb9fc5c100030d39d81be3d8e0b26d7 Mon Sep 17 00:00:00 2001
+From: Roy Pledge <roy.pledge@nxp.com>
+Date: Wed, 8 Aug 2018 17:13:48 -0400
+Subject: [PATCH] staging/fsl_qbman: Recalcuate cursor after consuming ring
+
+If the dqrr_init() function consumes frames during init
+the cursor needs to be updated before anything starts
+to use the ring.
+
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+---
+ drivers/staging/fsl_qbman/qman_low.h | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/staging/fsl_qbman/qman_low.h
++++ b/drivers/staging/fsl_qbman/qman_low.h
+@@ -682,6 +682,9 @@ static inline int qm_dqrr_init(struct qm
+               (0 ? 0x10 : 0);                         /* Ignore SP */
+       qm_out(CFG, cfg);
+       qm_dqrr_set_maxfill(portal, max_fill);
++
++      /* Recalculate cursor as we may have consumed frames */
++      dqrr->cursor = dqrr->ring + dqrr->ci;
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0079-fmd-use-fsl-fman-ptp-timer-compatible-for-ptp-probe.patch b/target/linux/layerscape/patches-5.4/701-net-0079-fmd-use-fsl-fman-ptp-timer-compatible-for-ptp-probe.patch
new file mode 100644 (file)
index 0000000..2748089
--- /dev/null
@@ -0,0 +1,38 @@
+From 3fa6171fbe38125b2841d7947e976b172db47c45 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Wed, 5 Sep 2018 14:50:10 +0800
+Subject: [PATCH] fmd: use "fsl,fman-ptp-timer" compatible for ptp probe
+
+Current ptp compatible "fsl,fman-rtc" used for ptp probe
+in fmd driver couldn't involve PowerPC DPAA FMan PTP timer.
+Let's use "fsl,fman-ptp-timer" instead to support DPAA FMan
+PTP timer of both ARM and PowerPC.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
+@@ -687,9 +687,9 @@ static t_LnxWrpFmDev * ReadFmDevTreeNode
+     if (WARN_ON(strlen("ptp-timer") >= sizeof(ids[0].name)))
+         return NULL;
+     strcpy(ids[0].name, "ptp-timer");
+-    if (WARN_ON(strlen("fsl,fman-rtc") >= sizeof(ids[0].compatible)))
++    if (WARN_ON(strlen("fsl,fman-ptp-timer") >= sizeof(ids[0].compatible)))
+         return NULL;
+-    strcpy(ids[0].compatible, "fsl,fman-rtc");
++    strcpy(ids[0].compatible, "fsl,fman-ptp-timer");
+     for_each_child_of_node(fm_node, dev_node) {
+         if (likely(of_match_node(ids, dev_node) != NULL)) {
+             _errno = of_address_to_resource(dev_node, 0, &res);
+@@ -920,7 +920,7 @@ static t_Error ConfigureFmDev(t_LnxWrpFm
+     if (p_LnxWrpFmDev->fmRtcPhysBaseAddr)
+     {
+-        dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize, "fman-rtc");
++        dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize, "fman-ptp-timer");
+         if (unlikely(dev_res == NULL))
+             RETURN_ERROR(MAJOR, E_INVALID_STATE, ("__devm_request_region() failed"));
diff --git a/target/linux/layerscape/patches-5.4/701-net-0080-sdk_dpaa-store-the-skb-backpointer-in-the-skb-headro.patch b/target/linux/layerscape/patches-5.4/701-net-0080-sdk_dpaa-store-the-skb-backpointer-in-the-skb-headro.patch
new file mode 100644 (file)
index 0000000..12e5d15
--- /dev/null
@@ -0,0 +1,84 @@
+From 1f00fa355829b510beb900ce1136f40802e6076e Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 10 Sep 2018 14:31:05 +0300
+Subject: [PATCH] sdk_dpaa: store the skb backpointer in the skb headroom
+
+The skb backpointer is stored right before the FMan buffer, in order to
+avoid overwriting. The memory area storing the backpointer was outside of
+the skb. This made it hard to guarantee its size.
+
+This patch changes the layout of the skb at buffer seed time: the area
+reserved for storing the skb backpointer is part of the skb's headroom.
+This makes it easier to track if the backpointer can be safely stored
+when recycling the buffer.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c  | 33 ++++++++++++++++------
+ 1 file changed, 24 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -82,8 +82,8 @@ static void dpa_bp_recycle_frag(struct d
+ static int _dpa_bp_add_8_bufs(const struct dpa_bp *dpa_bp)
+ {
++      void *new_buf, *fman_buf;
+       struct bm_buffer bmb[8];
+-      void *new_buf;
+       dma_addr_t addr;
+       uint8_t i;
+       struct device *dev = dpa_bp->dev;
+@@ -113,21 +113,37 @@ static int _dpa_bp_add_8_bufs(const stru
+               if (unlikely(!new_buf))
+                       goto netdev_alloc_failed;
+-              new_buf = PTR_ALIGN(new_buf + SMP_CACHE_BYTES, SMP_CACHE_BYTES);
++              new_buf = PTR_ALIGN(new_buf, SMP_CACHE_BYTES);
+-              skb = build_skb(new_buf, DPA_SKB_SIZE(dpa_bp->size) +
+-                      SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
++              /* Apart from the buffer that will be used by the FMan, the
++               * skb also guarantees enough space to hold the backpointer
++               * in the headroom and the shared info at the end.
++               */
++              skb = build_skb(new_buf,
++                              SMP_CACHE_BYTES + DPA_SKB_SIZE(dpa_bp->size) +
++                              SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
+               if (unlikely(!skb)) {
+                       put_page(virt_to_head_page(new_buf));
+                       goto build_skb_failed;
+               }
+-              /* Store the skb back-pointer before the start of the buffer.
+-               * Otherwise it will be overwritten by the FMan.
++              /* Reserve SMP_CACHE_BYTES in the skb's headroom to store the
++               * backpointer. This area will not be synced to, or
++               * overwritten by, the FMan.
++               */
++              skb_reserve(skb, SMP_CACHE_BYTES);
++
++              /* We don't sync the first SMP_CACHE_BYTES of the buffer to
++               * the FMan. The skb backpointer is stored at the end of the
++               * reserved headroom. Otherwise it will be overwritten by the
++               * FMan.
++               * The buffer synced with the FMan starts right after the
++               * reserved headroom.
+                */
+-              DPA_WRITE_SKB_PTR(skb, skbh, new_buf, -1);
++              fman_buf = new_buf + SMP_CACHE_BYTES;
++              DPA_WRITE_SKB_PTR(skb, skbh, fman_buf, -1);
+-              addr = dma_map_single(dev, new_buf,
++              addr = dma_map_single(dev, fman_buf,
+                               dpa_bp->size, DMA_BIDIRECTIONAL);
+               if (unlikely(dma_mapping_error(dev, addr)))
+                       goto dma_map_failed;
+@@ -477,7 +493,6 @@ static struct sk_buff *__hot sg_fd_to_sk
+                                DMA_BIDIRECTIONAL);
+               if (i == 0) {
+                       DPA_READ_SKB_PTR(skb, skbh, sg_vaddr, -1);
+-                      DPA_BUG_ON(skb->head != sg_vaddr);
+ #ifdef CONFIG_FSL_DPAA_1588
+                       if (priv->tsu && priv->tsu->valid &&
+                           priv->tsu->hwts_rx_en_ioctl)
diff --git a/target/linux/layerscape/patches-5.4/701-net-0081-sdk_dpaa-ls1043a-errata-align-skb_shinfo.patch b/target/linux/layerscape/patches-5.4/701-net-0081-sdk_dpaa-ls1043a-errata-align-skb_shinfo.patch
new file mode 100644 (file)
index 0000000..3c224c6
--- /dev/null
@@ -0,0 +1,27 @@
+From 7c96998ebc8cc9c71216b80de3f77114f29b148a Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 17 Sep 2018 12:39:24 +0300
+Subject: [PATCH] sdk_dpaa: ls1043a errata: align skb_shinfo
+
+Make sure the skb shared info is cache-line aligned when realigning
+egress frames.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -830,8 +830,10 @@ static struct sk_buff *a010022_realign_s
+       /* For the new skb we only need the old one's data (both non-paged and
+        * paged). We can skip the old tailroom.
++       *
++       * Make sure the skb_shinfo is cache-line aligned.
+        */
+-      nsize = headroom + skb->len +
++      nsize = SMP_CACHE_BYTES + DPA_SKB_SIZE(headroom + skb->len) +
+               SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+       /* Reserve enough memory to accommodate Jumbo frames */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0082-sdk_dpaa-ls1043a-errata-move-comment.patch b/target/linux/layerscape/patches-5.4/701-net-0082-sdk_dpaa-ls1043a-errata-move-comment.patch
new file mode 100644 (file)
index 0000000..05875d2
--- /dev/null
@@ -0,0 +1,35 @@
+From 182afda3f2537022ac2e0b7f421977ba96ce864e Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 17 Sep 2018 12:44:51 +0300
+Subject: [PATCH] sdk_dpaa: ls1043a errata: move comment
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h    | 3 +++
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 3 ---
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
+@@ -682,6 +682,9 @@ extern bool dpaa_errata_a010022; /* SoC
+ #define HAS_DMA_ISSUE(start, size) \
+       (((uintptr_t)(start) + (size)) > \
+        (((uintptr_t)(start) + 0x1000) & ~0xFFF))
++/* The headroom needs to accommodate our private data (64 bytes) but
++ * we reserve 256 bytes instead to guarantee 256 data alignment.
++ */
+ #define DPAA_A010022_HEADROOM 256
+ #endif  /* !CONFIG_PPC */
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -823,9 +823,6 @@ static struct sk_buff *a010022_realign_s
+       struct page *npage;
+       void *npage_addr;
+-      /* The headroom needs to accommodate our private data (64 bytes) but
+-       * we reserve 256 bytes instead to guarantee 256 data alignment.
+-       */
+       headroom = DPAA_A010022_HEADROOM;
+       /* For the new skb we only need the old one's data (both non-paged and
diff --git a/target/linux/layerscape/patches-5.4/701-net-0083-sdk_dpaa-ceetm-lower-the-default-congestion-threshol.patch b/target/linux/layerscape/patches-5.4/701-net-0083-sdk_dpaa-ceetm-lower-the-default-congestion-threshol.patch
new file mode 100644 (file)
index 0000000..81881fa
--- /dev/null
@@ -0,0 +1,39 @@
+From c18056f0a2648457cdaf06450addd217091f4bea Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 2 Oct 2018 16:49:28 +0300
+Subject: [PATCH] sdk_dpaa: ceetm: lower the default congestion thresholds
+
+The congestion thresholds need to be set in such a way that:
+    a) the threshold is high enough so that frames aren't dropped
+    unnecessarily
+    b) the threshold is low enough so that the latency isn't too big
+
+The current thresholds are set too high. In forwarding scenarios, the
+latency is too large and frames are dropped on ingress due to a lack of
+buffers.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/Kconfig | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig
+@@ -24,7 +24,7 @@ config FSL_DPAA_CEETM_CCS_THRESHOLD_1G
+       hex "CEETM egress congestion threshold on 1G ports"
+       depends on FSL_DPAA_CEETM
+       range 0x1000 0x10000000
+-      default "0x000a0000"
++      default "0x00005000"
+       help
+         The size in bytes of the CEETM egress Class Congestion State threshold on 1G ports.
+         The threshold needs to be configured keeping in mind the following factors:
+@@ -38,7 +38,7 @@ config FSL_DPAA_CEETM_CCS_THRESHOLD_10G
+       hex "CEETM egress congestion threshold on 10G ports"
+       depends on FSL_DPAA_CEETM
+       range 0x1000 0x20000000
+-      default "0x00640000"
++      default "0x00032000"
+       help
+         The size in bytes of the CEETM egress Class Congestion State threshold on 10G ports.
+         See FSL_DPAA_CEETM_CCS_THRESHOLD_1G for details.
diff --git a/target/linux/layerscape/patches-5.4/701-net-0084-staging-fsl_qbman-remove-bootmem-header.patch b/target/linux/layerscape/patches-5.4/701-net-0084-staging-fsl_qbman-remove-bootmem-header.patch
new file mode 100644 (file)
index 0000000..a7e1afc
--- /dev/null
@@ -0,0 +1,25 @@
+From 1e42763e2e015dd98ee0fbfe30de4c0124251cb1 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 9 Oct 2018 17:49:07 +0300
+Subject: [PATCH] staging/fsl_qbman: remove bootmem header
+
+The bootmem allocator was removed in [1]. The memblock allocator is
+supposed to be used directly instead. We already include it.
+
+[1] afd505b ("mm: remove include/linux/bootmem.h")
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/staging/fsl_qbman/dpa_sys.h | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/staging/fsl_qbman/dpa_sys.h
++++ b/drivers/staging/fsl_qbman/dpa_sys.h
+@@ -36,7 +36,6 @@
+ #include <linux/errno.h>
+ #include <linux/io.h>
+ #include <linux/dma-mapping.h>
+-#include <linux/bootmem.h>
+ #include <linux/slab.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
diff --git a/target/linux/layerscape/patches-5.4/701-net-0085-staging-fsl_qbman-stop-using-current_kernel_time.patch b/target/linux/layerscape/patches-5.4/701-net-0085-staging-fsl_qbman-stop-using-current_kernel_time.patch
new file mode 100644 (file)
index 0000000..71f16e9
--- /dev/null
@@ -0,0 +1,40 @@
+From 91c2f372e3f70ab5b5afff5af60348fd5656d739 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 10 Oct 2018 17:30:18 +0300
+Subject: [PATCH] staging/fsl_qbman: stop using current_kernel_time()
+
+The current_kernel_time() call was removed in [1] in order to avoid
+overflows in 2038. Use ktime_get_coarse_real_ts64() instead.
+
+[1] 9765164 ("y2038: remove unused time interfaces")
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/staging/fsl_qbman/qbman_driver.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/fsl_qbman/qbman_driver.c
++++ b/drivers/staging/fsl_qbman/qbman_driver.c
+@@ -57,7 +57,10 @@ static __init int qbman_init(void)
+               };
+               struct qm_mcr_queryfq_np np;
+               int err, retry = CONFIG_FSL_QMAN_INIT_TIMEOUT;
+-              struct timespec nowts, diffts, startts = current_kernel_time();
++              struct timespec64 nowts, diffts, startts;
++
++              ktime_get_coarse_real_ts64(&startts);
++
+               /* Loop while querying given fqid succeeds or time out */
+               while (1) {
+                       err = qman_query_fq_np(&fq, &np);
+@@ -68,8 +71,8 @@ static __init int qbman_init(void)
+                               pr_err("QMan: I/O error, continuing anyway\n");
+                               break;
+                       }
+-                      nowts = current_kernel_time();
+-                      diffts = timespec_sub(nowts, startts);
++                      ktime_get_coarse_real_ts64(&nowts);
++                      diffts = timespec64_sub(nowts, startts);
+                       if (diffts.tv_sec > 0) {
+                               if (!retry--) {
+                                       pr_err("QMan: time out, control-plane"
diff --git a/target/linux/layerscape/patches-5.4/701-net-0086-sdk_dpaa-ceetm-avoid-double-frees-on-error-paths.patch b/target/linux/layerscape/patches-5.4/701-net-0086-sdk_dpaa-ceetm-avoid-double-frees-on-error-paths.patch
new file mode 100644 (file)
index 0000000..efab833
--- /dev/null
@@ -0,0 +1,334 @@
+From 1ffba0c4d1122688268e59832a5e2bbc0917cac7 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 3 Oct 2018 16:37:06 +0300
+Subject: [PATCH] sdk_dpaa: ceetm: avoid double frees on error paths
+
+The stack calls the destroy() callback when a qdisc init() fails.
+We stop calling it ourselves and trust the stack do the cleanup.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 94 ++++++++--------------
+ 1 file changed, 34 insertions(+), 60 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -687,16 +687,13 @@ static int ceetm_init_root(struct Qdisc
+       /* Validate inputs */
+       if (sch->parent != TC_H_ROOT) {
+-              pr_err("CEETM: a root ceetm qdisc can not be attached to a class\n");
+-              tcf_block_put(priv->block);
+-              qdisc_class_hash_destroy(&priv->clhash);
++              pr_err("CEETM: a root ceetm qdisc must be root\n");
+               return -EINVAL;
+       }
+       if (!mac_dev) {
+               pr_err("CEETM: the interface is lacking a mac\n");
+-              err = -EINVAL;
+-              goto err_init_root;
++              return -EINVAL;
+       }
+       /* Pre-allocate underlying pfifo qdiscs.
+@@ -713,8 +710,7 @@ static int ceetm_init_root(struct Qdisc
+                                   sizeof(priv->root.qdiscs[0]),
+                                   GFP_KERNEL);
+       if (!priv->root.qdiscs) {
+-              err = -ENOMEM;
+-              goto err_init_root;
++              return -ENOMEM;
+       }
+       for (i = 0; i < dev->num_tx_queues; i++) {
+@@ -724,10 +720,8 @@ static int ceetm_init_root(struct Qdisc
+               qdisc = qdisc_create_dflt(dev_queue, &pfifo_qdisc_ops,
+                                         parent_id, extack);
+-              if (!qdisc) {
+-                      err = -ENOMEM;
+-                      goto err_init_root;
+-              }
++              if (!qdisc)
++                      return -ENOMEM;
+               priv->root.qdiscs[i] = qdisc;
+               qdisc->flags |= TCQ_F_ONETXQUEUE;
+@@ -739,8 +733,7 @@ static int ceetm_init_root(struct Qdisc
+       if (!priv->root.qstats) {
+               pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n",
+                      __func__);
+-              err = -ENOMEM;
+-              goto err_init_root;
++              return -ENOMEM;
+       }
+       priv->shaped = qopt->shaped;
+@@ -754,7 +747,7 @@ static int ceetm_init_root(struct Qdisc
+       if (err) {
+               pr_err(KBUILD_BASENAME " : %s : failed to claim the SP\n",
+                      __func__);
+-              goto err_init_root;
++              return err;
+       }
+       priv->root.sp = sp;
+@@ -766,7 +759,7 @@ static int ceetm_init_root(struct Qdisc
+       if (err) {
+               pr_err(KBUILD_BASENAME " : %s : failed to claim the LNI\n",
+                      __func__);
+-              goto err_init_root;
++              return err;
+       }
+       priv->root.lni = lni;
+@@ -775,7 +768,7 @@ static int ceetm_init_root(struct Qdisc
+       if (err) {
+               pr_err(KBUILD_BASENAME " : %s : failed to link the SP and LNI\n",
+                      __func__);
+-              goto err_init_root;
++              return err;
+       }
+       lni->sp = sp;
+@@ -786,7 +779,7 @@ static int ceetm_init_root(struct Qdisc
+               if (err) {
+                       pr_err(KBUILD_BASENAME " : %s : failed to configure the LNI shaper\n",
+                              __func__);
+-                      goto err_init_root;
++                      return err;
+               }
+               bps = priv->root.rate << 3; /* Bps -> bps */
+@@ -794,7 +787,7 @@ static int ceetm_init_root(struct Qdisc
+               if (err) {
+                       pr_err(KBUILD_BASENAME " : %s : failed to configure the LNI shaper\n",
+                              __func__);
+-                      goto err_init_root;
++                      return err;
+               }
+               bps = priv->root.ceil << 3; /* Bps -> bps */
+@@ -802,7 +795,7 @@ static int ceetm_init_root(struct Qdisc
+               if (err) {
+                       pr_err(KBUILD_BASENAME " : %s : failed to configure the LNI shaper\n",
+                              __func__);
+-                      goto err_init_root;
++                      return err;
+               }
+       }
+@@ -810,10 +803,6 @@ static int ceetm_init_root(struct Qdisc
+       dpa_enable_ceetm(dev);
+       return 0;
+-
+-err_init_root:
+-      ceetm_destroy(sch);
+-      return err;
+ }
+ /* Configure a prio ceetm qdisc */
+@@ -830,15 +819,13 @@ static int ceetm_init_prio(struct Qdisc
+       if (sch->parent == TC_H_ROOT) {
+               pr_err("CEETM: a prio ceetm qdisc can not be root\n");
+-              err = -EINVAL;
+-              goto err_init_prio;
++              return -EINVAL;
+       }
+       parent_qdisc = qdisc_lookup(dev, TC_H_MAJ(sch->parent));
+       if (strcmp(parent_qdisc->ops->id, ceetm_qdisc_ops.id)) {
+               pr_err("CEETM: a ceetm qdisc can not be attached to other qdisc/class types\n");
+-              err = -EINVAL;
+-              goto err_init_prio;
++              return -EINVAL;
+       }
+       /* Obtain the parent root ceetm_class */
+@@ -846,8 +833,7 @@ static int ceetm_init_prio(struct Qdisc
+       if (!parent_cl || parent_cl->type != CEETM_ROOT) {
+               pr_err("CEETM: a prio ceetm qdiscs can be added only under a root ceetm class\n");
+-              err = -EINVAL;
+-              goto err_init_prio;
++              return -EINVAL;
+       }
+       priv->prio.parent = parent_cl;
+@@ -863,8 +849,7 @@ static int ceetm_init_prio(struct Qdisc
+               if (!child_cl) {
+                       pr_err(KBUILD_BASENAME " : %s : kzalloc() failed\n",
+                              __func__);
+-                      err = -ENOMEM;
+-                      goto err_init_prio;
++                      return -ENOMEM;
+               }
+               child_cl->prio.cstats = alloc_percpu(struct ceetm_class_stats);
+@@ -907,8 +892,7 @@ static int ceetm_init_prio(struct Qdisc
+ err_init_prio_cls:
+       ceetm_cls_destroy(sch, child_cl);
+-err_init_prio:
+-      ceetm_destroy(sch);
++      /* Note: ceetm_destroy() will be called by our caller */
+       return err;
+ }
+@@ -928,16 +912,14 @@ static int ceetm_init_wbfs(struct Qdisc
+       /* Validate inputs */
+       if (sch->parent == TC_H_ROOT) {
+               pr_err("CEETM: a wbfs ceetm qdiscs can not be root\n");
+-              err = -EINVAL;
+-              goto err_init_wbfs;
++              return -EINVAL;
+       }
+       /* Obtain the parent prio ceetm qdisc */
+       parent_qdisc = qdisc_lookup(dev, TC_H_MAJ(sch->parent));
+       if (strcmp(parent_qdisc->ops->id, ceetm_qdisc_ops.id)) {
+               pr_err("CEETM: a ceetm qdisc can not be attached to other qdisc/class types\n");
+-              err = -EINVAL;
+-              goto err_init_wbfs;
++              return -EINVAL;
+       }
+       /* Obtain the parent prio ceetm class */
+@@ -946,28 +928,24 @@ static int ceetm_init_wbfs(struct Qdisc
+       if (!parent_cl || parent_cl->type != CEETM_PRIO) {
+               pr_err("CEETM: a wbfs ceetm qdiscs can be added only under a prio ceetm class\n");
+-              err = -EINVAL;
+-              goto err_init_wbfs;
++              return -EINVAL;
+       }
+       if (!qopt->qcount || !qopt->qweight[0]) {
+               pr_err("CEETM: qcount and qweight are mandatory for a wbfs ceetm qdisc\n");
+-              err = -EINVAL;
+-              goto err_init_wbfs;
++              return -EINVAL;
+       }
+       priv->shaped = parent_cl->shaped;
+       if (!priv->shaped && (qopt->cr || qopt->er)) {
+               pr_err("CEETM: CR/ER can be enabled only for shaped wbfs ceetm qdiscs\n");
+-              err = -EINVAL;
+-              goto err_init_wbfs;
++              return -EINVAL;
+       }
+       if (priv->shaped && !(qopt->cr || qopt->er)) {
+               pr_err("CEETM: either CR or ER must be enabled for shaped wbfs ceetm qdiscs\n");
+-              err = -EINVAL;
+-              goto err_init_wbfs;
++              return -EINVAL;
+       }
+       /* Obtain the parent root ceetm class */
+@@ -975,16 +953,14 @@ static int ceetm_init_wbfs(struct Qdisc
+       if ((root_cl->root.wbfs_grp_a && root_cl->root.wbfs_grp_b) ||
+           root_cl->root.wbfs_grp_large) {
+               pr_err("CEETM: no more wbfs classes are available\n");
+-              err = -EINVAL;
+-              goto err_init_wbfs;
++              return -EINVAL;
+       }
+       if ((root_cl->root.wbfs_grp_a || root_cl->root.wbfs_grp_b) &&
+           qopt->qcount == CEETM_MAX_WBFS_QCOUNT) {
+               pr_err("CEETM: only %d wbfs classes are available\n",
+                      CEETM_MIN_WBFS_QCOUNT);
+-              err = -EINVAL;
+-              goto err_init_wbfs;
++              return -EINVAL;
+       }
+       priv->wbfs.parent = parent_cl;
+@@ -1013,7 +989,7 @@ static int ceetm_init_wbfs(struct Qdisc
+               if (err) {
+                       pr_err(KBUILD_BASENAME " : %s : failed to get group details\n",
+                              __func__);
+-                      goto err_init_wbfs;
++                      return err;
+               }
+               small_group = true;
+@@ -1031,7 +1007,7 @@ static int ceetm_init_wbfs(struct Qdisc
+               if (err) {
+                       pr_err(KBUILD_BASENAME " : %s : failed to get group details\n",
+                              __func__);
+-                      goto err_init_wbfs;
++                      return err;
+               }
+               small_group = true;
+@@ -1044,7 +1020,7 @@ static int ceetm_init_wbfs(struct Qdisc
+       err = qman_ceetm_channel_set_group(priv->wbfs.ch, small_group, prio_a,
+                                          prio_b);
+       if (err)
+-              goto err_init_wbfs;
++              return err;
+       if (priv->shaped) {
+               err = qman_ceetm_channel_set_group_cr_eligibility(priv->wbfs.ch,
+@@ -1053,7 +1029,7 @@ static int ceetm_init_wbfs(struct Qdisc
+               if (err) {
+                       pr_err(KBUILD_BASENAME " : %s : failed to set group CR eligibility\n",
+                              __func__);
+-                      goto err_init_wbfs;
++                      return err;
+               }
+               err = qman_ceetm_channel_set_group_er_eligibility(priv->wbfs.ch,
+@@ -1062,7 +1038,7 @@ static int ceetm_init_wbfs(struct Qdisc
+               if (err) {
+                       pr_err(KBUILD_BASENAME " : %s : failed to set group ER eligibility\n",
+                              __func__);
+-                      goto err_init_wbfs;
++                      return err;
+               }
+       }
+@@ -1072,8 +1048,7 @@ static int ceetm_init_wbfs(struct Qdisc
+               if (!child_cl) {
+                       pr_err(KBUILD_BASENAME " : %s : kzalloc() failed\n",
+                              __func__);
+-                      err = -ENOMEM;
+-                      goto err_init_wbfs;
++                      return -ENOMEM;
+               }
+               child_cl->wbfs.cstats = alloc_percpu(struct ceetm_class_stats);
+@@ -1130,8 +1105,7 @@ static int ceetm_init_wbfs(struct Qdisc
+ err_init_wbfs_cls:
+       ceetm_cls_destroy(sch, child_cl);
+-err_init_wbfs:
+-      ceetm_destroy(sch);
++      /* Note: ceetm_destroy() will be called by our caller */
+       return err;
+ }
+@@ -1202,7 +1176,7 @@ static int ceetm_init(struct Qdisc *sch,
+               break;
+       default:
+               pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
+-              ceetm_destroy(sch);
++              /* Note: ceetm_destroy() will be called by our caller */
+               ret = -EINVAL;
+       }
+@@ -1549,7 +1523,7 @@ static int ceetm_cls_change(struct Qdisc
+       }
+       if (!cl && priv->type != CEETM_ROOT) {
+-              pr_err("CEETM: only root ceetm classes can be attached to the root ceetm qdisc\n");
++              pr_err("CEETM: root ceetm classes can be attached to the root ceetm qdisc only\n");
+               return -EINVAL;
+       }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0087-sdk_dpaa-ceetm-rename-qdisc_destroy-to-qdisc_put.patch b/target/linux/layerscape/patches-5.4/701-net-0087-sdk_dpaa-ceetm-rename-qdisc_destroy-to-qdisc_put.patch
new file mode 100644 (file)
index 0000000..745952b
--- /dev/null
@@ -0,0 +1,48 @@
+From b8f8c14491160043dd880d1e62c01903402352b2 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 24 Oct 2018 13:35:16 +0300
+Subject: [PATCH] sdk_dpaa: ceetm: rename qdisc_destroy() to qdisc_put()
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -432,7 +432,7 @@ static void ceetm_cls_destroy(struct Qdi
+       switch (cl->type) {
+       case CEETM_ROOT:
+               if (cl->root.child) {
+-                      qdisc_destroy(cl->root.child);
++                      qdisc_put(cl->root.child);
+                       cl->root.child = NULL;
+               }
+@@ -445,7 +445,7 @@ static void ceetm_cls_destroy(struct Qdi
+       case CEETM_PRIO:
+               if (cl->prio.child) {
+-                      qdisc_destroy(cl->prio.child);
++                      qdisc_put(cl->prio.child);
+                       cl->prio.child = NULL;
+               }
+@@ -567,7 +567,7 @@ static void ceetm_destroy(struct Qdisc *
+                */
+               for (ntx = 0; ntx < dev->num_tx_queues; ntx++)
+                       if (priv->root.qdiscs[ntx])
+-                              qdisc_destroy(priv->root.qdiscs[ntx]);
++                              qdisc_put(priv->root.qdiscs[ntx]);
+               kfree(priv->root.qdiscs);
+               break;
+@@ -1367,7 +1367,7 @@ static void ceetm_attach(struct Qdisc *s
+               qdisc = priv->root.qdiscs[i];
+               old_qdisc = dev_graft_qdisc(qdisc->dev_queue, qdisc);
+               if (old_qdisc)
+-                      qdisc_destroy(old_qdisc);
++                      qdisc_put(old_qdisc);
+       }
+       kfree(priv->root.qdiscs);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0088-sdk_dpaa-remove-FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE.patch b/target/linux/layerscape/patches-5.4/701-net-0088-sdk_dpaa-remove-FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE.patch
new file mode 100644 (file)
index 0000000..dbbe46d
--- /dev/null
@@ -0,0 +1,127 @@
+From 357ab2939dbddfb6849c55be9de577db078d9037 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Fri, 12 Oct 2018 16:56:57 +0300
+Subject: [PATCH] sdk_dpaa: remove FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
+
+Remove FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE and record the
+receive CPU in skb queue mapping to maintain the same CPU
+for tx in forwarding scenarios.
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/Kconfig           | 13 +------------
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c        |  2 +-
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h        | 12 ++----------
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c |  3 +--
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h |  2 +-
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c     |  2 ++
+ 6 files changed, 8 insertions(+), 26 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig
+@@ -96,17 +96,6 @@ config FSL_DPAA_1588
+         help
+          Enable IEEE1588 support code.
+-config FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
+-      bool "Use driver's Tx queue selection mechanism"
+-      default y
+-      depends on FSL_SDK_DPAA_ETH
+-      help
+-        The DPAA-Ethernet driver defines a ndo_select_queue() callback for optimal selection
+-        of the egress FQ. That will override the XPS support for this netdevice.
+-        If for whatever reason you want to be in control of the egress FQ-to-CPU selection and mapping,
+-        or simply don't want to use the driver's ndo_select_queue() callback, then unselect this
+-        and use the standard XPS support instead.
+-
+ config FSL_DPAA_ETH_MAX_BUF_COUNT
+       int "Maximum nuber of buffers in private bpool"
+       depends on FSL_SDK_DPAA_ETH
+@@ -178,7 +167,7 @@ config FSL_DPAA_ETH_DEBUG
+ config FSL_DPAA_DBG_LOOP
+       bool "DPAA Ethernet Debug loopback"
+-      depends on FSL_DPAA_ETH_DEBUGFS && FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
++      depends on FSL_DPAA_ETH_DEBUGFS
+       default n
+       help
+         This option allows to divert all received traffic on a certain interface A towards a
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
+@@ -678,7 +678,7 @@ static const struct net_device_ops dpa_p
+       .ndo_get_stats64 = dpa_get_stats64,
+       .ndo_set_mac_address = dpa_set_mac_address,
+       .ndo_validate_addr = eth_validate_addr,
+-#ifdef CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
++#ifdef CONFIG_FMAN_PFC
+       .ndo_select_queue = dpa_select_queue,
+ #endif
+       .ndo_set_rx_mode = dpa_set_rx_mode,
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
+@@ -635,23 +635,15 @@ static inline void _dpa_assign_wq(struct
+       }
+ }
+-#ifdef CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
+-/* Use in lieu of skb_get_queue_mapping() */
+ #ifdef CONFIG_FMAN_PFC
++/* Use in lieu of skb_get_queue_mapping() */
+ #define dpa_get_queue_mapping(skb) \
+       (((skb)->priority < CONFIG_FMAN_PFC_COS_COUNT) ? \
+               ((skb)->priority * dpa_num_cpus + smp_processor_id()) : \
+               ((CONFIG_FMAN_PFC_COS_COUNT - 1) * \
+                       dpa_num_cpus + smp_processor_id()));
+-
+ #else
+-#define dpa_get_queue_mapping(skb) \
+-      raw_smp_processor_id()
+-#endif
+-#else
+-/* Use the queue selected by XPS */
+-#define dpa_get_queue_mapping(skb) \
+-      skb_get_queue_mapping(skb)
++#define dpa_get_queue_mapping(skb) skb_get_queue_mapping(skb)
+ #endif
+ #ifdef CONFIG_PTP_1588_CLOCK_DPAA
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
+@@ -841,14 +841,13 @@ bool dpa_bpid2pool_use(int bpid)
+       return false;
+ }
+-#ifdef CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
++#ifdef CONFIG_FMAN_PFC
+ u16 dpa_select_queue(struct net_device *net_dev, struct sk_buff *skb,
+                    struct net_device *sb_dev,
+                    select_queue_fallback_t fallback)
+ {
+       return dpa_get_queue_mapping(skb);
+ }
+-EXPORT_SYMBOL(dpa_select_queue);
+ #endif
+ struct dpa_fq *dpa_fq_alloc(struct device *dev,
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
+@@ -172,7 +172,7 @@ struct dpa_bp *dpa_bpid2pool(int bpid);
+ void dpa_bpid2pool_map(int bpid, struct dpa_bp *dpa_bp);
+ bool dpa_bpid2pool_use(int bpid);
+ void dpa_bp_drain(struct dpa_bp *bp);
+-#ifdef CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
++#ifdef CONFIG_FMAN_PFC
+ u16 dpa_select_queue(struct net_device *net_dev, struct sk_buff *skb,
+                    struct net_device *sb_dev,
+                    select_queue_fallback_t fallback);
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -648,6 +648,8 @@ void __hot _dpa_rx(struct net_device *ne
+       }
+ #endif
++      skb_record_rx_queue(skb, raw_smp_processor_id());
++
+       if (use_gro) {
+               gro_result_t gro_result;
+               const struct qman_portal_config *pc =
diff --git a/target/linux/layerscape/patches-5.4/701-net-0089-fsl-fman-backup-and-restore-ICID-registers.patch b/target/linux/layerscape/patches-5.4/701-net-0089-fsl-fman-backup-and-restore-ICID-registers.patch
new file mode 100644 (file)
index 0000000..3b5acba
--- /dev/null
@@ -0,0 +1,116 @@
+From ef2b0593c906a85ca59ed5957ae7a7361974349c Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 6 Feb 2018 16:21:17 +0200
+Subject: [PATCH] fsl/fman: backup and restore ICID registers
+
+During probing, FMAN is reset thus losing all its register
+settings. Backup port ICID registers before reset and restore
+them after, similarly to how it's done on powerpc / PAMU based
+platforms.
+This also has the side effect of disabling the old code path
+(liodn backup/restore handling) that obviously make no sense
+in the context of SMMU on ARMs.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Acked-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/fman/fman.c | 35 +++++++++++++++++++++++++++++-
+ drivers/net/ethernet/freescale/fman/fman.h |  4 ++++
+ 2 files changed, 38 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/fman/fman.c
++++ b/drivers/net/ethernet/freescale/fman/fman.c
+@@ -634,6 +634,7 @@ static void set_port_order_restoration(s
+       iowrite32be(tmp, &fpm_rg->fmfp_prc);
+ }
++#ifdef CONFIG_PPC
+ static void set_port_liodn(struct fman *fman, u8 port_id,
+                          u32 liodn_base, u32 liodn_ofst)
+ {
+@@ -651,6 +652,27 @@ static void set_port_liodn(struct fman *
+       iowrite32be(tmp, &fman->dma_regs->fmdmplr[port_id / 2]);
+       iowrite32be(liodn_ofst, &fman->bmi_regs->fmbm_spliodn[port_id - 1]);
+ }
++#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++static void save_restore_port_icids(struct fman *fman, bool save)
++{
++      int port_idxes[] = {
++              0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc,
++              0xd, 0xe, 0xf, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
++              0x10, 0x11, 0x30, 0x31
++      };
++      int idx, i;
++
++      for (i = 0; i < ARRAY_SIZE(port_idxes); i++) {
++              idx = port_idxes[i];
++              if (save)
++                      fman->sp_icids[idx] =
++                              ioread32be(&fman->bmi_regs->fmbm_spliodn[idx]);
++              else
++                      iowrite32be(fman->sp_icids[idx],
++                                  &fman->bmi_regs->fmbm_spliodn[idx]);
++      }
++}
++#endif
+ static void enable_rams_ecc(struct fman_fpm_regs __iomem *fpm_rg)
+ {
+@@ -1919,7 +1941,10 @@ _return:
+ static int fman_init(struct fman *fman)
+ {
+       struct fman_cfg *cfg = NULL;
+-      int err = 0, i, count;
++      int err = 0, count;
++#ifdef CONFIG_PPC
++      int i;
++#endif
+       if (is_init_done(fman->cfg))
+               return -EINVAL;
+@@ -1939,6 +1964,7 @@ static int fman_init(struct fman *fman)
+       memset_io((void __iomem *)(fman->base_addr + CGP_OFFSET), 0,
+                 fman->state->fm_port_num_of_cg);
++#ifdef CONFIG_PPC
+       /* Save LIODN info before FMan reset
+        * Skipping non-existent port 0 (i = 1)
+        */
+@@ -1958,6 +1984,9 @@ static int fman_init(struct fman *fman)
+               }
+               fman->liodn_base[i] = liodn_base;
+       }
++#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++      save_restore_port_icids(fman, true);
++#endif
+       err = fman_reset(fman);
+       if (err)
+@@ -2186,8 +2215,12 @@ int fman_set_port_params(struct fman *fm
+       if (err)
+               goto return_err;
++#ifdef CONFIG_PPC
+       set_port_liodn(fman, port_id, fman->liodn_base[port_id],
+                      fman->liodn_offset[port_id]);
++#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++      save_restore_port_icids(fman, false);
++#endif
+       if (fman->state->rev_info.major < 6)
+               set_port_order_restoration(fman->fpm_regs, port_id);
+--- a/drivers/net/ethernet/freescale/fman/fman.h
++++ b/drivers/net/ethernet/freescale/fman/fman.h
+@@ -347,8 +347,12 @@ struct fman {
+       unsigned long fifo_offset;
+       size_t fifo_size;
++#ifdef CONFIG_PPC
+       u32 liodn_base[64];
+       u32 liodn_offset[64];
++#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
++      u32 sp_icids[64];
++#endif
+       struct fman_dts_params dts_params;
+ };
diff --git a/target/linux/layerscape/patches-5.4/701-net-0090-fsl-fman-add-API-to-get-the-device-behind-a-fman-por.patch b/target/linux/layerscape/patches-5.4/701-net-0090-fsl-fman-add-API-to-get-the-device-behind-a-fman-por.patch
new file mode 100644 (file)
index 0000000..58ed29c
--- /dev/null
@@ -0,0 +1,48 @@
+From 975717f04388a052cab9d3c3b6828d065372b82a Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 3 Apr 2018 17:11:07 +0300
+Subject: [PATCH] fsl/fman: add API to get the device behind a fman port
+
+Add an API that retrieves the 'struct device' that the specified fman
+port probed against. The new API will be used in a subsequent iommu
+enablement related patch.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Acked-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/fman/fman_port.c | 14 ++++++++++++++
+ drivers/net/ethernet/freescale/fman/fman_port.h |  2 ++
+ 2 files changed, 16 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/fman/fman_port.c
++++ b/drivers/net/ethernet/freescale/fman/fman_port.c
+@@ -1728,6 +1728,20 @@ u32 fman_port_get_qman_channel_id(struct
+ }
+ EXPORT_SYMBOL(fman_port_get_qman_channel_id);
++/**
++ * fman_port_get_device
++ * port:      Pointer to the FMan port device
++ *
++ * Get the 'struct device' associated to the specified FMan port device
++ *
++ * Return: pointer to associated 'struct device'
++ */
++struct device *fman_port_get_device(struct fman_port *port)
++{
++      return port->dev;
++}
++EXPORT_SYMBOL(fman_port_get_device);
++
+ int fman_port_get_hash_result_offset(struct fman_port *port, u32 *offset)
+ {
+       if (port->buffer_offsets.hash_result_offset == ILLEGAL_BASE)
+--- a/drivers/net/ethernet/freescale/fman/fman_port.h
++++ b/drivers/net/ethernet/freescale/fman/fman_port.h
+@@ -157,4 +157,6 @@ int fman_port_get_tstamp(struct fman_por
+ struct fman_port *fman_port_bind(struct device *dev);
++struct device *fman_port_get_device(struct fman_port *port);
++
+ #endif /* __FMAN_PORT_H */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0091-dpaa_eth-defer-probing-after-qbman.patch b/target/linux/layerscape/patches-5.4/701-net-0091-dpaa_eth-defer-probing-after-qbman.patch
new file mode 100644 (file)
index 0000000..a86f7d9
--- /dev/null
@@ -0,0 +1,57 @@
+From 9e1f89c4c637087dc8dc1a3f9f6bda5bff66e4ac Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 6 Feb 2018 14:40:32 +0200
+Subject: [PATCH] dpaa_eth: defer probing after qbman
+
+Enabling SMMU altered the order of device probing causing the dpaa1
+ethernet driver to get probed before qbman and causing a boot crash.
+Add predictability in the probing order by deferring the ethernet
+driver probe after qbman and portals by using the recently introduced
+qbman APIs.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Acked-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 31 ++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+@@ -2947,6 +2947,37 @@ static int dpaa_eth_probe(struct platfor
+       int err = 0, i, channel;
+       struct device *dev;
++      err = bman_is_probed();
++      if (!err)
++              return -EPROBE_DEFER;
++      if (err < 0) {
++              dev_err(&pdev->dev, "failing probe due to bman probe error\n");
++              return -ENODEV;
++      }
++      err = qman_is_probed();
++      if (!err)
++              return -EPROBE_DEFER;
++      if (err < 0) {
++              dev_err(&pdev->dev, "failing probe due to qman probe error\n");
++              return -ENODEV;
++      }
++      err = bman_portals_probed();
++      if (!err)
++              return -EPROBE_DEFER;
++      if (err < 0) {
++              dev_err(&pdev->dev,
++                      "failing probe due to bman portals probe error\n");
++              return -ENODEV;
++      }
++      err = qman_portals_probed();
++      if (!err)
++              return -EPROBE_DEFER;
++      if (err < 0) {
++              dev_err(&pdev->dev,
++                      "failing probe due to qman portals probe error\n");
++              return -ENODEV;
++      }
++
+       /* device used for DMA mapping */
+       dev = pdev->dev.parent;
+       err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40));
diff --git a/target/linux/layerscape/patches-5.4/701-net-0092-dpaa_eth-base-dma-mappings-on-the-fman-rx-port.patch b/target/linux/layerscape/patches-5.4/701-net-0092-dpaa_eth-base-dma-mappings-on-the-fman-rx-port.patch
new file mode 100644 (file)
index 0000000..01cb5ed
--- /dev/null
@@ -0,0 +1,60 @@
+From 13296e938da191216395952cf49ddda96e67359c Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Thu, 5 Apr 2018 12:37:57 +0300
+Subject: [PATCH] dpaa_eth: base dma mappings on the fman rx port
+
+The dma transactions initiator is the rx fman port so that's the device
+that the dma mappings should be done. Previously the mappings were done
+through the MAC device which makes no sense because it's neither dma-able
+nor connected in any way to smmu.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Acked-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+@@ -2978,8 +2978,15 @@ static int dpaa_eth_probe(struct platfor
+               return -ENODEV;
+       }
++      mac_dev = dpaa_mac_dev_get(pdev);
++      if (IS_ERR(mac_dev)) {
++              dev_err(&pdev->dev, "dpaa_mac_dev_get() failed\n");
++              err = PTR_ERR(mac_dev);
++              goto probe_err;
++      }
++
+       /* device used for DMA mapping */
+-      dev = pdev->dev.parent;
++      dev = fman_port_get_device(mac_dev->port[RX]);
+       err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40));
+       if (err) {
+               dev_err(dev, "dma_coerce_mask_and_coherent() failed\n");
+@@ -3004,13 +3011,6 @@ static int dpaa_eth_probe(struct platfor
+       priv->msg_enable = netif_msg_init(debug, DPAA_MSG_DEFAULT);
+-      mac_dev = dpaa_mac_dev_get(pdev);
+-      if (IS_ERR(mac_dev)) {
+-              dev_err(dev, "dpaa_mac_dev_get() failed\n");
+-              err = PTR_ERR(mac_dev);
+-              goto free_netdev;
+-      }
+-
+       /* If fsl_fm_max_frm is set to a higher value than the all-common 1500,
+        * we choose conservatively and let the user explicitly set a higher
+        * MTU via ifconfig. Otherwise, the user may end up with different MTUs
+@@ -3146,9 +3146,9 @@ delete_egress_cgr:
+       qman_release_cgrid(priv->cgr_data.cgr.cgrid);
+ free_dpaa_bps:
+       dpaa_bps_free(priv);
+-free_netdev:
+       dev_set_drvdata(dev, NULL);
+       free_netdev(net_dev);
++probe_err:
+       return err;
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0093-dpaa_eth-fix-iova-handling-for-contiguous-frames.patch b/target/linux/layerscape/patches-5.4/701-net-0093-dpaa_eth-fix-iova-handling-for-contiguous-frames.patch
new file mode 100644 (file)
index 0000000..430bed1
--- /dev/null
@@ -0,0 +1,129 @@
+From 39e4cf29431dec8aaad599d9734f7a0468a9c20b Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Wed, 4 Apr 2018 12:31:05 +0300
+Subject: [PATCH] dpaa_eth: fix iova handling for contiguous frames
+
+The driver relies on the no longer valid assumption that dma addresses
+(iovas) are identical to physical addressees and uses phys_to_virt() to
+make iova -> vaddr conversions. Fix this by adding a function that does
+proper iova -> phys conversions using the iommu api and update the code
+to use it.
+Also, a dma_unmap_single() call had to be moved further down the code
+because iova -> vaddr conversions were required before the unmap.
+For now only the contiguous frame case is handled and the SG case is
+split in a following patch.
+While at it, clean-up a redundant dpaa_bpid2pool() and pass the bp
+as parameter.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Acked-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 44 ++++++++++++++------------
+ 1 file changed, 24 insertions(+), 20 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+@@ -50,6 +50,7 @@
+ #include <linux/highmem.h>
+ #include <linux/percpu.h>
+ #include <linux/dma-mapping.h>
++#include <linux/iommu.h>
+ #include <linux/sort.h>
+ #include <linux/phy_fixed.h>
+ #include <soc/fsl/bman.h>
+@@ -1615,6 +1616,17 @@ static int dpaa_eth_refill_bpools(struct
+       return 0;
+ }
++static phys_addr_t dpaa_iova_to_phys(struct device *dev, dma_addr_t addr)
++{
++      struct iommu_domain *domain;
++
++      domain = iommu_get_domain_for_dev(dev);
++      if (domain)
++              return iommu_iova_to_phys(domain, addr);
++      else
++              return addr;
++}
++
+ /* Cleanup function for outgoing frame descriptors that were built on Tx path,
+  * either contiguous frames or scatter/gather ones.
+  * Skb freeing is not handled here.
+@@ -1639,7 +1651,7 @@ static struct sk_buff *dpaa_cleanup_tx_f
+       int nr_frags, i;
+       u64 ns;
+-      skbh = (struct sk_buff **)phys_to_virt(addr);
++      skbh = (struct sk_buff **)phys_to_virt(dpaa_iova_to_phys(dev, addr));
+       skb = *skbh;
+       if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) {
+@@ -1718,25 +1730,21 @@ static u8 rx_csum_offload(const struct d
+  * accommodate the shared info area of the skb.
+  */
+ static struct sk_buff *contig_fd_to_skb(const struct dpaa_priv *priv,
+-                                      const struct qm_fd *fd)
++                                      const struct qm_fd *fd,
++                                      struct dpaa_bp *dpaa_bp,
++                                      void *vaddr)
+ {
+       ssize_t fd_off = qm_fd_get_offset(fd);
+-      dma_addr_t addr = qm_fd_addr(fd);
+-      struct dpaa_bp *dpaa_bp;
+       struct sk_buff *skb;
+-      void *vaddr;
+-      vaddr = phys_to_virt(addr);
+       WARN_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES));
+-      dpaa_bp = dpaa_bpid2pool(fd->bpid);
+-      if (!dpaa_bp)
+-              goto free_buffer;
+-
+       skb = build_skb(vaddr, dpaa_bp->size +
+                       SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
+-      if (WARN_ONCE(!skb, "Build skb failure on Rx\n"))
+-              goto free_buffer;
++      if (WARN_ONCE(!skb, "Build skb failure on Rx\n")) {
++              skb_free_frag(vaddr);
++              return NULL;
++      }
+       WARN_ON(fd_off != priv->rx_headroom);
+       skb_reserve(skb, fd_off);
+       skb_put(skb, qm_fd_get_length(fd));
+@@ -1744,10 +1752,6 @@ static struct sk_buff *contig_fd_to_skb(
+       skb->ip_summed = rx_csum_offload(priv, fd);
+       return skb;
+-
+-free_buffer:
+-      skb_free_frag(vaddr);
+-      return NULL;
+ }
+ /* Build an skb with the data of the first S/G entry in the linear portion and
+@@ -2476,12 +2480,12 @@ static enum qman_cb_dqrr_result rx_defau
+       if (!dpaa_bp)
+               return qman_cb_dqrr_consume;
+-      dma_unmap_single(dpaa_bp->dev, addr, dpaa_bp->size, DMA_FROM_DEVICE);
+-
+       /* prefetch the first 64 bytes of the frame or the SGT start */
+-      vaddr = phys_to_virt(addr);
++      vaddr = phys_to_virt(dpaa_iova_to_phys(dpaa_bp->dev, addr));
+       prefetch(vaddr + qm_fd_get_offset(fd));
++      dma_unmap_single(dpaa_bp->dev, addr, dpaa_bp->size, DMA_FROM_DEVICE);
++
+       /* The only FD types that we may receive are contig and S/G */
+       WARN_ON((fd_format != qm_fd_contig) && (fd_format != qm_fd_sg));
+@@ -2492,7 +2496,7 @@ static enum qman_cb_dqrr_result rx_defau
+       (*count_ptr)--;
+       if (likely(fd_format == qm_fd_contig))
+-              skb = contig_fd_to_skb(priv, fd);
++              skb = contig_fd_to_skb(priv, fd, dpaa_bp, vaddr);
+       else
+               skb = sg_fd_to_skb(priv, fd);
+       if (!skb)
diff --git a/target/linux/layerscape/patches-5.4/701-net-0094-dpaa_eth-fix-iova-handling-for-sg-frames.patch b/target/linux/layerscape/patches-5.4/701-net-0094-dpaa_eth-fix-iova-handling-for-sg-frames.patch
new file mode 100644 (file)
index 0000000..273d7e5
--- /dev/null
@@ -0,0 +1,126 @@
+From 73cc32aace5fe123182337c3abd769a1d6edd9fe Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Wed, 4 Apr 2018 15:12:28 +0300
+Subject: [PATCH] dpaa_eth: fix iova handling for sg frames
+
+The driver relies on the no longer valid assumption that dma addresses
+(iovas) are identical to physical addressees and uses phys_to_virt() to
+make iova -> vaddr conversions. Fix this also for scatter-gather frames
+using the iova -> phys conversion function added in the previous patch.
+While at it, clean-up a redundant dpaa_bpid2pool() and pass the bp
+as parameter.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Acked-by: Madalin Bucur <madalin.bucur@nxp.com>
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 41 +++++++++++++++-----------
+ 1 file changed, 24 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+@@ -1656,14 +1656,17 @@ static struct sk_buff *dpaa_cleanup_tx_f
+       if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) {
+               nr_frags = skb_shinfo(skb)->nr_frags;
+-              dma_unmap_single(dev, addr,
+-                               qm_fd_get_offset(fd) + DPAA_SGT_SIZE,
+-                               dma_dir);
+               /* The sgt buffer has been allocated with netdev_alloc_frag(),
+                * it's from lowmem.
+                */
+-              sgt = phys_to_virt(addr + qm_fd_get_offset(fd));
++              sgt = phys_to_virt(dpaa_iova_to_phys(dev,
++                                                   addr +
++                                                   qm_fd_get_offset(fd)));
++
++              dma_unmap_single(dev, addr,
++                               qm_fd_get_offset(fd) + DPAA_SGT_SIZE,
++                               dma_dir);
+               /* sgt[0] is from lowmem, was dma_map_single()-ed */
+               dma_unmap_single(dev, qm_sg_addr(&sgt[0]),
+@@ -1702,7 +1705,7 @@ static struct sk_buff *dpaa_cleanup_tx_f
+               else
+ #endif
+                       /* Free the page frag that we allocated on Tx */
+-                      skb_free_frag(phys_to_virt(addr));
++                      skb_free_frag(phys_to_virt(skbh));
+       }
+       return skb;
+@@ -1760,14 +1763,14 @@ static struct sk_buff *contig_fd_to_skb(
+  * The page fragment holding the S/G Table is recycled here.
+  */
+ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
+-                                  const struct qm_fd *fd)
++                                  const struct qm_fd *fd,
++                                  struct dpaa_bp *dpaa_bp,
++                                  void *vaddr)
+ {
+       ssize_t fd_off = qm_fd_get_offset(fd);
+-      dma_addr_t addr = qm_fd_addr(fd);
+       const struct qm_sg_entry *sgt;
+       struct page *page, *head_page;
+-      struct dpaa_bp *dpaa_bp;
+-      void *vaddr, *sg_vaddr;
++      void *sg_vaddr;
+       int frag_off, frag_len;
+       struct sk_buff *skb;
+       dma_addr_t sg_addr;
+@@ -1776,7 +1779,6 @@ static struct sk_buff *sg_fd_to_skb(cons
+       int *count_ptr;
+       int i;
+-      vaddr = phys_to_virt(addr);
+       WARN_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES));
+       /* Iterate through the SGT entries and add data buffers to the skb */
+@@ -1787,14 +1789,18 @@ static struct sk_buff *sg_fd_to_skb(cons
+               WARN_ON(qm_sg_entry_is_ext(&sgt[i]));
+               sg_addr = qm_sg_addr(&sgt[i]);
+-              sg_vaddr = phys_to_virt(sg_addr);
+-              WARN_ON(!IS_ALIGNED((unsigned long)sg_vaddr,
+-                                  SMP_CACHE_BYTES));
+               /* We may use multiple Rx pools */
+               dpaa_bp = dpaa_bpid2pool(sgt[i].bpid);
+-              if (!dpaa_bp)
++              if (!dpaa_bp) {
++                      pr_info("%s: fail to get dpaa_bp for sg bpid %d\n",
++                              __func__, sgt[i].bpid);
+                       goto free_buffers;
++              }
++              sg_vaddr = phys_to_virt(dpaa_iova_to_phys(dpaa_bp->dev,
++                                                        sg_addr));
++              WARN_ON(!IS_ALIGNED((unsigned long)sg_vaddr,
++                                  SMP_CACHE_BYTES));
+               count_ptr = this_cpu_ptr(dpaa_bp->percpu_count);
+               dma_unmap_single(dpaa_bp->dev, sg_addr, dpaa_bp->size,
+@@ -1866,10 +1872,11 @@ free_buffers:
+       /* free all the SG entries */
+       for (i = 0; i < DPAA_SGT_MAX_ENTRIES ; i++) {
+               sg_addr = qm_sg_addr(&sgt[i]);
+-              sg_vaddr = phys_to_virt(sg_addr);
+-              skb_free_frag(sg_vaddr);
+               dpaa_bp = dpaa_bpid2pool(sgt[i].bpid);
+               if (dpaa_bp) {
++                      sg_addr = dpaa_iova_to_phys(dpaa_bp->dev, sg_addr);
++                      sg_vaddr = phys_to_virt(sg_addr);
++                      skb_free_frag(sg_vaddr);
+                       count_ptr = this_cpu_ptr(dpaa_bp->percpu_count);
+                       (*count_ptr)--;
+               }
+@@ -2498,7 +2505,7 @@ static enum qman_cb_dqrr_result rx_defau
+       if (likely(fd_format == qm_fd_contig))
+               skb = contig_fd_to_skb(priv, fd, dpaa_bp, vaddr);
+       else
+-              skb = sg_fd_to_skb(priv, fd);
++              skb = sg_fd_to_skb(priv, fd, dpaa_bp, vaddr);
+       if (!skb)
+               return qman_cb_dqrr_consume;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0095-sdk_dpaa-ceetm-guard-against-an-out-of-bounds-queue-.patch b/target/linux/layerscape/patches-5.4/701-net-0095-sdk_dpaa-ceetm-guard-against-an-out-of-bounds-queue-.patch
new file mode 100644 (file)
index 0000000..6c41d0f
--- /dev/null
@@ -0,0 +1,34 @@
+From cfda91fdd3396b97f2c08f0d8ed7749fbd87bb7b Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 30 Oct 2018 17:34:31 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: guard against an out of bounds queue index
+
+Make sure the queue mapping recorded in the skb is not larger than our
+egress queue count.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -1982,7 +1982,7 @@ static struct ceetm_class *ceetm_classif
+ int __hot ceetm_tx(struct sk_buff *skb, struct net_device *net_dev)
+ {
+-      const int queue_mapping = dpa_get_queue_mapping(skb);
++      int queue_mapping = dpa_get_queue_mapping(skb);
+       struct Qdisc *sch = net_dev->qdisc;
+       struct ceetm_class_stats *cstats;
+       struct ceetm_qdisc_stats *qstats;
+@@ -2016,6 +2016,9 @@ int __hot ceetm_tx(struct sk_buff *skb,
+               goto drop;
+       }
++      if (unlikely(queue_mapping >= DPAA_ETH_TX_QUEUES))
++              queue_mapping = queue_mapping % DPAA_ETH_TX_QUEUES;
++
+       priv_dpa = netdev_priv(net_dev);
+       conf_fq = priv_dpa->conf_fqs[queue_mapping];
diff --git a/target/linux/layerscape/patches-5.4/701-net-0096-sdk_dpaa-guard-against-an-out-of-bounds-queue-index.patch b/target/linux/layerscape/patches-5.4/701-net-0096-sdk_dpaa-guard-against-an-out-of-bounds-queue-index.patch
new file mode 100644 (file)
index 0000000..9616177
--- /dev/null
@@ -0,0 +1,34 @@
+From 56203e34ec05e39a088036b5d9db7fde7a7af742 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 30 Oct 2018 18:18:30 +0200
+Subject: [PATCH] sdk_dpaa: guard against an out of bounds queue index
+
+Make sure the queue mapping recorded in the skb is not larger than our
+egress queue count.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -1035,7 +1035,7 @@ EXPORT_SYMBOL(skb_to_sg_fd);
+ int __hot dpa_tx(struct sk_buff *skb, struct net_device *net_dev)
+ {
+       struct dpa_priv_s       *priv;
+-      const int queue_mapping = dpa_get_queue_mapping(skb);
++      int queue_mapping = dpa_get_queue_mapping(skb);
+       struct qman_fq *egress_fq, *conf_fq;
+ #ifdef CONFIG_FSL_DPAA_HOOKS
+@@ -1053,6 +1053,9 @@ int __hot dpa_tx(struct sk_buff *skb, st
+               return ceetm_tx(skb, net_dev);
+ #endif
++      if (unlikely(queue_mapping >= DPAA_ETH_TX_QUEUES))
++              queue_mapping = queue_mapping % DPAA_ETH_TX_QUEUES;
++
+       egress_fq = priv->egress_fqs[queue_mapping];
+       conf_fq = priv->conf_fqs[queue_mapping];
diff --git a/target/linux/layerscape/patches-5.4/701-net-0097-sdk_dpaa-set-the-skb-queue-mapping-when-looping.patch b/target/linux/layerscape/patches-5.4/701-net-0097-sdk_dpaa-set-the-skb-queue-mapping-when-looping.patch
new file mode 100644 (file)
index 0000000..f4a0b3e
--- /dev/null
@@ -0,0 +1,26 @@
+From ae59df58bacb7d3daf2cf736f286a368ee703778 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 30 Oct 2018 18:18:57 +0200
+Subject: [PATCH] sdk_dpaa: set the skb queue mapping when looping
+
+Save the current CPU ID on ingress, when FSL_DPAA_DBG_LOOP is set.
+Use the skb_set_queue_mapping() call instead of skb_record_rx_queue()
+because the stack isn't involved and won't compensate for the additional
+offset.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -575,6 +575,8 @@ static inline int dpa_skb_loop(const str
+               return 0; /* loop disabled by default */
+       skb_push(skb, ETH_HLEN); /* compensate for eth_type_trans */
++      /* Save the current CPU ID in order to maintain core affinity */
++      skb_set_queue_mapping(skb, raw_smp_processor_id());
+       dpa_tx(skb, dpa_loop_netdevs[priv->loop_to]);
+       return 1; /* Frame Tx on the selected interface */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0098-sdk_dpaa-remove-ptp-clock-driver.patch b/target/linux/layerscape/patches-5.4/701-net-0098-sdk_dpaa-remove-ptp-clock-driver.patch
new file mode 100644 (file)
index 0000000..a34d952
--- /dev/null
@@ -0,0 +1,392 @@
+From 0738b02f733717693226db401784e884a0714d41 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Wed, 31 Oct 2018 16:59:01 +0800
+Subject: [PATCH] sdk_dpaa: remove ptp clock driver
+
+Removed dpaa_ptp driver since we could use common
+ptp_qoriq driver in drivers/ptp/ instead.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/Makefile   |   1 -
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h |  10 -
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_common.c  |  21 --
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ptp.c | 291 ---------------------
+ drivers/net/ethernet/freescale/sdk_dpaa/mac.h      |   3 +-
+ 5 files changed, 1 insertion(+), 325 deletions(-)
+ delete mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ptp.c
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/Makefile
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/Makefile
+@@ -9,7 +9,6 @@ include $(srctree)/drivers/net/ethernet/
+ ccflags-y += -I$(NET_DPA)
+ obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_mac.o fsl_dpa.o
+-obj-$(CONFIG_PTP_1588_CLOCK_DPAA) += dpaa_ptp.o
+ fsl_dpa-objs += dpaa_ethtool.o dpaa_eth_sysfs.o dpaa_eth.o dpaa_eth_sg.o dpaa_eth_common.o
+ ifeq ($(CONFIG_FSL_DPAA_DBG_LOOP),y)
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
+@@ -646,16 +646,6 @@ static inline void _dpa_assign_wq(struct
+ #define dpa_get_queue_mapping(skb) skb_get_queue_mapping(skb)
+ #endif
+-#ifdef CONFIG_PTP_1588_CLOCK_DPAA
+-struct ptp_priv_s {
+-      struct device_node *node;
+-      struct platform_device *of_dev;
+-      struct ptp_clock *clock;
+-      struct mac_device *mac_dev;
+-};
+-extern struct ptp_priv_s ptp_priv;
+-#endif
+-
+ static inline void _dpa_bp_free_pf(void *addr)
+ {
+       put_page(virt_to_head_page(addr));
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
+@@ -55,10 +55,6 @@
+ /* Size in bytes of the FQ taildrop threshold */
+ #define DPA_FQ_TD             0x200000
+-#ifdef CONFIG_PTP_1588_CLOCK_DPAA
+-struct ptp_priv_s ptp_priv;
+-#endif
+-
+ static struct dpa_bp *dpa_bp_array[64];
+ int dpa_max_frm;
+@@ -579,23 +575,6 @@ dpa_mac_probe(struct platform_device *_o
+       }
+ #endif
+-#ifdef CONFIG_PTP_1588_CLOCK_DPAA
+-      if ((mac_dev->phy_if != PHY_INTERFACE_MODE_SGMII) ||
+-          ((mac_dev->phy_if == PHY_INTERFACE_MODE_SGMII) &&
+-                       (mac_dev->speed == SPEED_1000))) {
+-              ptp_priv.node = of_parse_phandle(mac_node, "ptp-timer", 0);
+-              if (ptp_priv.node) {
+-                      ptp_priv.of_dev = of_find_device_by_node(ptp_priv.node);
+-                      if (unlikely(ptp_priv.of_dev == NULL)) {
+-                              dev_err(dpa_dev,
+-                      "Cannot find device represented by timer_node\n");
+-                              of_node_put(ptp_priv.node);
+-                              return ERR_PTR(-EINVAL);
+-                      }
+-                      ptp_priv.mac_dev = mac_dev;
+-              }
+-      }
+-#endif
+       return mac_dev;
+ }
+ EXPORT_SYMBOL(dpa_mac_probe);
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ptp.c
++++ /dev/null
+@@ -1,291 +0,0 @@
+-/*
+- * DPAA Ethernet Driver -- PTP 1588 clock using the dTSEC
+- *
+- * Author: Yangbo Lu <yangbo.lu@freescale.com>
+- *
+- * Copyright 2014 Freescale Semiconductor, Inc.
+- *
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License as published by the
+- * Free Software Foundation; either version 2 of the License, or (at your
+- * option) any later version.
+-*/
+-
+-#include <linux/device.h>
+-#include <linux/hrtimer.h>
+-#include <linux/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/of_platform.h>
+-#include <linux/timex.h>
+-#include <linux/io.h>
+-
+-#include <linux/ptp_clock_kernel.h>
+-
+-#include "dpaa_eth.h"
+-#include "mac.h"
+-
+-static struct mac_device *mac_dev;
+-static u32 freqCompensation;
+-
+-/* Bit definitions for the TMR_CTRL register */
+-#define ALM1P                 (1<<31) /* Alarm1 output polarity */
+-#define ALM2P                 (1<<30) /* Alarm2 output polarity */
+-#define FS                    (1<<28) /* FIPER start indication */
+-#define PP1L                  (1<<27) /* Fiper1 pulse loopback mode enabled. */
+-#define PP2L                  (1<<26) /* Fiper2 pulse loopback mode enabled. */
+-#define TCLK_PERIOD_SHIFT     (16) /* 1588 timer reference clock period. */
+-#define TCLK_PERIOD_MASK      (0x3ff)
+-#define RTPE                  (1<<15) /* Record Tx Timestamp to PAL Enable. */
+-#define FRD                   (1<<14) /* FIPER Realignment Disable */
+-#define ESFDP                 (1<<11) /* External Tx/Rx SFD Polarity. */
+-#define ESFDE                 (1<<10) /* External Tx/Rx SFD Enable. */
+-#define ETEP2                 (1<<9) /* External trigger 2 edge polarity */
+-#define ETEP1                 (1<<8) /* External trigger 1 edge polarity */
+-#define COPH                  (1<<7) /* Generated clock output phase. */
+-#define CIPH                  (1<<6) /* External oscillator input clock phase */
+-#define TMSR                  (1<<5) /* Timer soft reset. */
+-#define BYP                   (1<<3) /* Bypass drift compensated clock */
+-#define TE                    (1<<2) /* 1588 timer enable. */
+-#define CKSEL_SHIFT           (0)    /* 1588 Timer reference clock source */
+-#define CKSEL_MASK            (0x3)
+-
+-/* Bit definitions for the TMR_TEVENT register */
+-#define ETS2                  (1<<25) /* External trigger 2 timestamp sampled */
+-#define ETS1                  (1<<24) /* External trigger 1 timestamp sampled */
+-#define ALM2                  (1<<17) /* Current time = alarm time register 2 */
+-#define ALM1                  (1<<16) /* Current time = alarm time register 1 */
+-#define PP1                   (1<<7)  /* periodic pulse generated on FIPER1 */
+-#define PP2                   (1<<6)  /* periodic pulse generated on FIPER2 */
+-#define PP3                   (1<<5)  /* periodic pulse generated on FIPER3 */
+-
+-/* Bit definitions for the TMR_TEMASK register */
+-#define ETS2EN                (1<<25) /* External trigger 2 timestamp enable */
+-#define ETS1EN                (1<<24) /* External trigger 1 timestamp enable */
+-#define ALM2EN                (1<<17) /* Timer ALM2 event enable */
+-#define ALM1EN                (1<<16) /* Timer ALM1 event enable */
+-#define PP1EN                 (1<<7) /* Periodic pulse event 1 enable */
+-#define PP2EN                 (1<<6) /* Periodic pulse event 2 enable */
+-
+-/* Bit definitions for the TMR_PEVENT register */
+-#define TXP2                  (1<<9) /* PTP transmitted timestamp im TXTS2 */
+-#define TXP1                  (1<<8) /* PTP transmitted timestamp in TXTS1 */
+-#define RXP                   (1<<0) /* PTP frame has been received */
+-
+-/* Bit definitions for the TMR_PEMASK register */
+-#define TXP2EN                (1<<9) /* Transmit PTP packet event 2 enable */
+-#define TXP1EN                (1<<8) /* Transmit PTP packet event 1 enable */
+-#define RXPEN                 (1<<0) /* Receive PTP packet event enable */
+-
+-/* Bit definitions for the TMR_STAT register */
+-#define STAT_VEC_SHIFT        (0) /* Timer general purpose status vector */
+-#define STAT_VEC_MASK         (0x3f)
+-
+-/* Bit definitions for the TMR_PRSC register */
+-#define PRSC_OCK_SHIFT        (0) /* Output clock division/prescale factor. */
+-#define PRSC_OCK_MASK         (0xffff)
+-
+-
+-#define N_EXT_TS      2
+-
+-static void set_alarm(void)
+-{
+-      u64 ns;
+-
+-      if (mac_dev->fm_rtc_get_cnt)
+-              mac_dev->fm_rtc_get_cnt(mac_dev->fm_dev, &ns);
+-      ns += 1500000000ULL;
+-      ns = div_u64(ns, 1000000000UL) * 1000000000ULL;
+-      ns -= DPA_PTP_NOMINAL_FREQ_PERIOD_NS;
+-      if (mac_dev->fm_rtc_set_alarm)
+-              mac_dev->fm_rtc_set_alarm(mac_dev->fm_dev, 0, ns);
+-}
+-
+-static void set_fipers(void)
+-{
+-      u64 fiper;
+-
+-      if (mac_dev->fm_rtc_disable)
+-              mac_dev->fm_rtc_disable(mac_dev->fm_dev);
+-
+-      set_alarm();
+-      fiper = 1000000000ULL - DPA_PTP_NOMINAL_FREQ_PERIOD_NS;
+-      if (mac_dev->fm_rtc_set_fiper)
+-              mac_dev->fm_rtc_set_fiper(mac_dev->fm_dev, 0, fiper);
+-
+-      if (mac_dev->fm_rtc_enable)
+-              mac_dev->fm_rtc_enable(mac_dev->fm_dev);
+-}
+-
+-/* PTP clock operations */
+-
+-static int ptp_dpa_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+-{
+-      u64 adj;
+-      u32 diff, tmr_add;
+-      int neg_adj = 0;
+-
+-      if (ppb < 0) {
+-              neg_adj = 1;
+-              ppb = -ppb;
+-      }
+-
+-      tmr_add = freqCompensation;
+-      adj = tmr_add;
+-      adj *= ppb;
+-      diff = div_u64(adj, 1000000000ULL);
+-
+-      tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff;
+-
+-      if (mac_dev->fm_rtc_set_drift)
+-              mac_dev->fm_rtc_set_drift(mac_dev->fm_dev, tmr_add);
+-
+-      return 0;
+-}
+-
+-static int ptp_dpa_adjtime(struct ptp_clock_info *ptp, s64 delta)
+-{
+-      s64 now;
+-
+-      if (mac_dev->fm_rtc_get_cnt)
+-              mac_dev->fm_rtc_get_cnt(mac_dev->fm_dev, &now);
+-
+-      now += delta;
+-
+-      if (mac_dev->fm_rtc_set_cnt)
+-              mac_dev->fm_rtc_set_cnt(mac_dev->fm_dev, now);
+-      set_fipers();
+-
+-      return 0;
+-}
+-
+-static int ptp_dpa_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
+-{
+-      u64 ns;
+-      u32 remainder;
+-
+-      if (mac_dev->fm_rtc_get_cnt)
+-              mac_dev->fm_rtc_get_cnt(mac_dev->fm_dev, &ns);
+-
+-      ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
+-      ts->tv_nsec = remainder;
+-      return 0;
+-}
+-
+-static int ptp_dpa_settime(struct ptp_clock_info *ptp,
+-                             const struct timespec64 *ts)
+-{
+-      u64 ns;
+-
+-      ns = ts->tv_sec * 1000000000ULL;
+-      ns += ts->tv_nsec;
+-
+-      if (mac_dev->fm_rtc_set_cnt)
+-              mac_dev->fm_rtc_set_cnt(mac_dev->fm_dev, ns);
+-      set_fipers();
+-      return 0;
+-}
+-
+-static int ptp_dpa_enable(struct ptp_clock_info *ptp,
+-                            struct ptp_clock_request *rq, int on)
+-{
+-      u32 bit;
+-
+-      switch (rq->type) {
+-      case PTP_CLK_REQ_EXTTS:
+-              switch (rq->extts.index) {
+-              case 0:
+-                      bit = ETS1EN;
+-                      break;
+-              case 1:
+-                      bit = ETS2EN;
+-                      break;
+-              default:
+-                      return -EINVAL;
+-              }
+-              if (on) {
+-                      if (mac_dev->fm_rtc_enable_interrupt)
+-                              mac_dev->fm_rtc_enable_interrupt(
+-                                      mac_dev->fm_dev, bit);
+-              } else {
+-                      if (mac_dev->fm_rtc_disable_interrupt)
+-                              mac_dev->fm_rtc_disable_interrupt(
+-                                      mac_dev->fm_dev, bit);
+-              }
+-              return 0;
+-
+-      case PTP_CLK_REQ_PPS:
+-              if (on) {
+-                      if (mac_dev->fm_rtc_enable_interrupt)
+-                              mac_dev->fm_rtc_enable_interrupt(
+-                                      mac_dev->fm_dev, PP1EN);
+-              } else {
+-                      if (mac_dev->fm_rtc_disable_interrupt)
+-                              mac_dev->fm_rtc_disable_interrupt(
+-                                      mac_dev->fm_dev, PP1EN);
+-              }
+-              return 0;
+-
+-      default:
+-              break;
+-      }
+-
+-      return -EOPNOTSUPP;
+-}
+-
+-static struct ptp_clock_info ptp_dpa_caps = {
+-      .owner          = THIS_MODULE,
+-      .name           = "dpaa clock",
+-      .max_adj        = 512000,
+-      .n_alarm        = 0,
+-      .n_ext_ts       = N_EXT_TS,
+-      .n_per_out      = 0,
+-      .pps            = 1,
+-      .adjfreq        = ptp_dpa_adjfreq,
+-      .adjtime        = ptp_dpa_adjtime,
+-      .gettime64      = ptp_dpa_gettime,
+-      .settime64      = ptp_dpa_settime,
+-      .enable         = ptp_dpa_enable,
+-};
+-
+-static int __init __cold dpa_ptp_load(void)
+-{
+-      struct device *ptp_dev;
+-      struct timespec64 now;
+-      struct ptp_clock *clock = ptp_priv.clock;
+-      int dpa_phc_index;
+-      int err;
+-
+-      if (!(ptp_priv.of_dev && ptp_priv.mac_dev))
+-              return -ENODEV;
+-
+-      ptp_dev = &ptp_priv.of_dev->dev;
+-      mac_dev = ptp_priv.mac_dev;
+-
+-      if (mac_dev->fm_rtc_get_drift)
+-              mac_dev->fm_rtc_get_drift(mac_dev->fm_dev, &freqCompensation);
+-
+-      getnstimeofday64(&now);
+-      ptp_dpa_settime(&ptp_dpa_caps, &now);
+-
+-      clock = ptp_clock_register(&ptp_dpa_caps, ptp_dev);
+-      if (IS_ERR(clock)) {
+-              err = PTR_ERR(clock);
+-              return err;
+-      }
+-      dpa_phc_index = ptp_clock_index(clock);
+-      return 0;
+-}
+-module_init(dpa_ptp_load);
+-
+-static void __exit __cold dpa_ptp_unload(void)
+-{
+-      struct ptp_clock *clock = ptp_priv.clock;
+-
+-      if (mac_dev->fm_rtc_disable_interrupt)
+-              mac_dev->fm_rtc_disable_interrupt(mac_dev->fm_dev, 0xffffffff);
+-      ptp_clock_unregister(clock);
+-}
+-module_exit(dpa_ptp_unload);
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/mac.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac.h
+@@ -97,10 +97,9 @@ struct mac_device {
+       int (*fm_rtc_set_alarm)(struct fm *fm_dev, uint32_t id, uint64_t time);
+       int (*fm_rtc_set_fiper)(struct fm *fm_dev, uint32_t id,
+                               uint64_t fiper);
+-#ifdef CONFIG_PTP_1588_CLOCK_DPAA
+       int (*fm_rtc_enable_interrupt)(struct fm *fm_dev, uint32_t events);
+       int (*fm_rtc_disable_interrupt)(struct fm *fm_dev, uint32_t events);
+-#endif
++
+       int (*set_wol)(struct fm_port *port, struct fm_mac_dev *fm_mac_dev,
+                       bool en);
+       int (*dump_mac_regs)(struct mac_device *h_mac, char *buf, int nn);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0099-sdk_fman-suspend-the-FMan-to-Deep-Sleep-on-PPC-only.patch b/target/linux/layerscape/patches-5.4/701-net-0099-sdk_fman-suspend-the-FMan-to-Deep-Sleep-on-PPC-only.patch
new file mode 100644 (file)
index 0000000..677dbbc
--- /dev/null
@@ -0,0 +1,56 @@
+From 2223efd48766e22bbf56ba6000078af9e32c7772 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 17 Dec 2018 15:20:42 +0200
+Subject: [PATCH] sdk_fman: suspend the FMan to Deep Sleep on PPC only
+
+The SCFG_FMCLKDPSLPCR register is present on PPC targets only. This
+feature does not apply to ARM SoCs.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c    | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
+@@ -251,7 +251,7 @@ static irqreturn_t fm_irq(int irq, void
+ #ifdef CONFIG_PM_SLEEP
+     if (fman_get_normal_pending(p_Fm->p_FmFpmRegs) & INTR_EN_WAKEUP)
+     {
+-        pm_wakeup_event(p_LnxWrpFmDev->dev, 200);        
++        pm_wakeup_event(p_LnxWrpFmDev->dev, 200);
+     }
+ #endif
+     FM_EventIsr(p_LnxWrpFmDev->h_Dev);
+@@ -1107,7 +1107,7 @@ static t_Error InitFmDev(t_LnxWrpFmDev
+         p_LnxWrpFmDev->fmDevSettings.param.fmMacClkRatio =
+             !!(get_rcwsr(4) & 0x1); /* RCW[FM_MAC_RAT1] */
+-    {   
++    {
+     /* T4 Devices ClkRatio is always 1 regardless of RCW[FM_MAC_RAT1] */
+         uint32_t svr;
+         svr = mfspr(SPRN_SVR);
+@@ -1320,7 +1320,7 @@ static const struct of_device_id fm_matc
+ MODULE_DEVICE_TABLE(of, fm_match);
+ #endif /* !MODULE */
+-#ifdef CONFIG_PM
++#if defined CONFIG_PM && (defined CONFIG_PPC || defined CONFIG_PPC64)
+ #define SCFG_FMCLKDPSLPCR_ADDR 0xFFE0FC00C
+ #define SCFG_FMCLKDPSLPCR_DS_VAL 0x48402000
+@@ -1373,11 +1373,11 @@ static const struct dev_pm_ops fm_pm_ops
+ #define FM_PM_OPS (&fm_pm_ops)
+-#else /* CONFIG_PM */
++#else /* CONFIG_PM && (CONFIG_PPC || CONFIG_PPC64) */
+ #define FM_PM_OPS NULL
+-#endif /* CONFIG_PM */
++#endif /* CONFIG_PM && (CONFIG_PPC || CONFIG_PPC64) */
+ static struct platform_driver fm_driver = {
+     .driver = {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0100-sdk_fman-disable-ptp-timer-probe.patch b/target/linux/layerscape/patches-5.4/701-net-0100-sdk_fman-disable-ptp-timer-probe.patch
new file mode 100644 (file)
index 0000000..6976abe
--- /dev/null
@@ -0,0 +1,36 @@
+From c96c8b30729c5e3ab2dc36d344f4d1a1a2ae400c Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Wed, 31 Oct 2018 17:07:40 +0800
+Subject: [PATCH] sdk_fman: disable ptp timer probe
+
+DPAA PTP timer was managed by ptp_qoriq driver in drivers/ptp/.
+We will no longer manage it in sdk_fman driver and use related
+APIs.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
+@@ -682,6 +682,11 @@ static t_LnxWrpFmDev * ReadFmDevTreeNode
+         }
+     }
++/* DPAA PTP timer was managed by ptp_qoriq driver in drivers/ptp/.
++ * We will no longer manage it in sdk_fman driver and use related
++ * APIs.
++ */
++#if 0
+     /* Get the RTC base address and size */
+     memset(ids, 0, sizeof(ids));
+     if (WARN_ON(strlen("ptp-timer") >= sizeof(ids[0].name)))
+@@ -704,6 +709,7 @@ static t_LnxWrpFmDev * ReadFmDevTreeNode
+             p_LnxWrpFmDev->fmRtcMemSize = res.end + 1 - res.start;
+         }
+     }
++#endif
+ #if (DPAA_VERSION >= 11)
+     /* Get the VSP base address */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0101-sdk_dpaa-add-the-get_ts_info-interface-for-ethtool.patch b/target/linux/layerscape/patches-5.4/701-net-0101-sdk_dpaa-add-the-get_ts_info-interface-for-ethtool.patch
new file mode 100644 (file)
index 0000000..2343fba
--- /dev/null
@@ -0,0 +1,79 @@
+From 0ade532080c8cc777cd2af78b11040a353b89880 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Thu, 1 Nov 2018 10:34:52 +0800
+Subject: [PATCH] sdk_dpaa: add the get_ts_info interface for ethtool
+
+Added the get_ts_info interface for ethtool to check
+the timestamping capability.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c | 45 ++++++++++++++++++++++
+ 1 file changed, 45 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c
+@@ -39,6 +39,9 @@
+ #endif
+ #include <linux/string.h>
++#include <linux/of_platform.h>
++#include <linux/net_tstamp.h>
++#include <linux/fsl/ptp_qoriq.h>
+ #include "dpaa_eth.h"
+ #include "mac.h"                /* struct mac_device */
+@@ -519,6 +522,47 @@ static void dpa_get_strings(struct net_d
+       memcpy(strings, dpa_stats_global, size);
+ }
++static int dpaa_get_ts_info(struct net_device *net_dev,
++                          struct ethtool_ts_info *info)
++{
++      struct dpa_priv_s *priv = netdev_priv(net_dev);
++      struct device *dev = priv->mac_dev->dev;
++      struct device_node *mac_node = dev->of_node;
++      struct device_node *fman_node = NULL, *ptp_node = NULL;
++      struct platform_device *ptp_dev = NULL;
++      struct qoriq_ptp *ptp = NULL;
++
++      info->phc_index = -1;
++
++      fman_node = of_get_parent(mac_node);
++      if (fman_node)
++              ptp_node = of_parse_phandle(fman_node, "ptimer-handle", 0);
++
++      if (ptp_node)
++              ptp_dev = of_find_device_by_node(ptp_node);
++
++      if (ptp_dev)
++              ptp = platform_get_drvdata(ptp_dev);
++
++      if (ptp)
++              info->phc_index = ptp->phc_index;
++
++#ifdef CONFIG_FSL_DPAA_TS
++      info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
++                              SOF_TIMESTAMPING_RX_HARDWARE |
++                              SOF_TIMESTAMPING_RAW_HARDWARE;
++      info->tx_types = (1 << HWTSTAMP_TX_OFF) |
++                       (1 << HWTSTAMP_TX_ON);
++      info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
++                         (1 << HWTSTAMP_FILTER_ALL);
++#else
++      info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
++                              SOF_TIMESTAMPING_SOFTWARE;
++#endif
++
++      return 0;
++}
++
+ const struct ethtool_ops dpa_ethtool_ops = {
+       .get_link_ksettings = dpa_get_ksettings,
+       .set_link_ksettings = dpa_set_ksettings,
+@@ -539,4 +583,5 @@ const struct ethtool_ops dpa_ethtool_ops
+       .get_wol = dpa_get_wol,
+       .set_wol = dpa_set_wol,
+ #endif
++      .get_ts_info = dpaa_get_ts_info,
+ };
diff --git a/target/linux/layerscape/patches-5.4/701-net-0102-sdk_fman-share-the-event-interrupt.patch b/target/linux/layerscape/patches-5.4/701-net-0102-sdk_fman-share-the-event-interrupt.patch
new file mode 100644 (file)
index 0000000..2dc042e
--- /dev/null
@@ -0,0 +1,24 @@
+From 078d5cda5fc94e1d40d8d44bc4a0067341f02e72 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Thu, 1 Nov 2018 12:10:59 +0800
+Subject: [PATCH] sdk_fman: share the event interrupt
+
+This patch is to share fman event interrupt because
+the 1588 timer driver will also use this interrupt.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
+@@ -883,7 +883,7 @@ static t_Error ConfigureFmDev(t_LnxWrpFm
+     if (unlikely(_errno < 0))
+         RETURN_ERROR(MAJOR, E_INVALID_STATE, ("can_request_irq() = %d", _errno));
+ #endif
+-    _errno = devm_request_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->irq, fm_irq, 0, "fman", p_LnxWrpFmDev);
++    _errno = devm_request_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->irq, fm_irq, IRQF_SHARED, "fman", p_LnxWrpFmDev);
+     if (unlikely(_errno < 0))
+         RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_irq(%d) = %d", p_LnxWrpFmDev->irq, _errno));
diff --git a/target/linux/layerscape/patches-5.4/701-net-0103-sdk_dpaa-fix-hardware-timestamp-value.patch b/target/linux/layerscape/patches-5.4/701-net-0103-sdk_dpaa-fix-hardware-timestamp-value.patch
new file mode 100644 (file)
index 0000000..e219c39
--- /dev/null
@@ -0,0 +1,37 @@
+From c96c65930fb5a348d96b88f4edeea1ddf8229c28 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Thu, 1 Nov 2018 15:34:17 +0800
+Subject: [PATCH] sdk_dpaa: fix hardware timestamp value
+
+The hardware timestamp value got didn't need to be multiplied
+by nominal frequency since ptp_qoriq driver initialized the
+counter to add clock period, not the clock tick.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
+@@ -306,7 +306,7 @@ EXPORT_SYMBOL(dpa_fix_features);
+ u64 dpa_get_timestamp_ns(const struct dpa_priv_s *priv, enum port_type rx_tx,
+                       const void *data)
+ {
+-      u64 *ts, ns;
++      u64 *ts;
+       ts = fm_port_get_buffer_time_stamp(priv->mac_dev->port_dev[rx_tx],
+                                          data);
+@@ -316,10 +316,7 @@ u64 dpa_get_timestamp_ns(const struct dp
+       be64_to_cpus(ts);
+-      /* multiple DPA_PTP_NOMINAL_FREQ_PERIOD_NS for case of non power of 2 */
+-      ns = *ts << DPA_PTP_NOMINAL_FREQ_PERIOD_SHIFT;
+-
+-      return ns;
++      return *ts;
+ }
+ int dpa_get_ts(const struct dpa_priv_s *priv, enum port_type rx_tx,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0104-sdk_dpaa-remove-useless-1588-timer-enablement.patch b/target/linux/layerscape/patches-5.4/701-net-0104-sdk_dpaa-remove-useless-1588-timer-enablement.patch
new file mode 100644 (file)
index 0000000..7454be5
--- /dev/null
@@ -0,0 +1,33 @@
+From 988cd7a6bcbb738d6ad334a94fda07c965da862e Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Wed, 5 Dec 2018 16:31:13 +0800
+Subject: [PATCH] sdk_dpaa: remove useless 1588 timer enablement
+
+1588 timer had been enabled to run at ptp_qoriq driver
+probing stage. So removed the useless enablement.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
+@@ -340,8 +340,6 @@ static void dpa_ts_tx_enable(struct net_
+       struct dpa_priv_s *priv = netdev_priv(dev);
+       struct mac_device *mac_dev = priv->mac_dev;
+-      if (mac_dev->fm_rtc_enable)
+-              mac_dev->fm_rtc_enable(get_fm_handle(dev));
+       if (mac_dev->ptp_enable)
+               mac_dev->ptp_enable(mac_dev->get_mac_handle(mac_dev));
+@@ -373,8 +371,6 @@ static void dpa_ts_rx_enable(struct net_
+       struct dpa_priv_s *priv = netdev_priv(dev);
+       struct mac_device *mac_dev = priv->mac_dev;
+-      if (mac_dev->fm_rtc_enable)
+-              mac_dev->fm_rtc_enable(get_fm_handle(dev));
+       if (mac_dev->ptp_enable)
+               mac_dev->ptp_enable(mac_dev->get_mac_handle(mac_dev));
diff --git a/target/linux/layerscape/patches-5.4/701-net-0105-sdk-qbman-fix-issue-in-qman_delete_cgr_safe.patch b/target/linux/layerscape/patches-5.4/701-net-0105-sdk-qbman-fix-issue-in-qman_delete_cgr_safe.patch
new file mode 100644 (file)
index 0000000..830a2ec
--- /dev/null
@@ -0,0 +1,60 @@
+From a16c129c9dfae01921faaed98587d318459d5cfc Mon Sep 17 00:00:00 2001
+From: Zhao Qiang <qiang.zhao@nxp.com>
+Date: Wed, 30 May 2018 17:09:02 +0800
+Subject: [PATCH] sdk/qbman: fix issue in qman_delete_cgr_safe()
+
+The wait_for_completion() call in qman_delete_cgr_safe()
+was triggering a scheduling while atomic bug, replacing the
+kthread with a smp_call_function_single() call to fix it.
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
+---
+ drivers/staging/fsl_qbman/qman_high.c | 29 ++++++-----------------------
+ 1 file changed, 6 insertions(+), 23 deletions(-)
+
+--- a/drivers/staging/fsl_qbman/qman_high.c
++++ b/drivers/staging/fsl_qbman/qman_high.c
+@@ -3075,36 +3075,19 @@ struct cgr_comp {
+       struct completion completion;
+ };
+-static int qman_delete_cgr_thread(void *p)
++static void qman_delete_cgr_smp_call(void *p)
+ {
+-      struct cgr_comp *cgr_comp = (struct cgr_comp *)p;
+-      int res;
+-
+-      res = qman_delete_cgr((struct qman_cgr *)cgr_comp->cgr);
+-      complete(&cgr_comp->completion);
+-
+-      return res;
++      qman_delete_cgr((struct qman_cgr *)p);
+ }
+ void qman_delete_cgr_safe(struct qman_cgr *cgr)
+ {
+-      struct task_struct *thread;
+-      struct cgr_comp cgr_comp;
+-
+       preempt_disable();
+       if (qman_cgr_cpus[cgr->cgrid] != smp_processor_id()) {
+-              init_completion(&cgr_comp.completion);
+-              cgr_comp.cgr = cgr;
+-              thread = kthread_create(qman_delete_cgr_thread, &cgr_comp,
+-                                      "cgr_del");
+-
+-              if (likely(!IS_ERR(thread))) {
+-                      kthread_bind(thread, qman_cgr_cpus[cgr->cgrid]);
+-                      wake_up_process(thread);
+-                      wait_for_completion(&cgr_comp.completion);
+-                      preempt_enable();
+-                      return;
+-              }
++              smp_call_function_single(qman_cgr_cpus[cgr->cgrid],
++                                       qman_delete_cgr_smp_call, cgr, true);
++              preempt_enable();
++              return;
+       }
+       qman_delete_cgr(cgr);
+       preempt_enable();
diff --git a/target/linux/layerscape/patches-5.4/701-net-0106-sdk_fman-avoid-array-overflow-error-in-fman-port-ini.patch b/target/linux/layerscape/patches-5.4/701-net-0106-sdk_fman-avoid-array-overflow-error-in-fman-port-ini.patch
new file mode 100644 (file)
index 0000000..4490bc3
--- /dev/null
@@ -0,0 +1,26 @@
+From 5dc04d9dc9ac5d6eca6f1602a7b1c3b5a61625f4 Mon Sep 17 00:00:00 2001
+From: Florinel Iordache <florinel.iordache@nxp.com>
+Date: Mon, 4 Feb 2019 09:45:54 +0200
+Subject: [PATCH] sdk_fman: avoid array overflow error in fman port init
+
+Perform a verification of external buffer pools used which can cause array
+overflow error in port init function SetExtBufferPools() if it was set to
+value 1 via fman port API
+
+Signed-off-by: Florinel Iordache <florinel.iordache@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c
+@@ -581,7 +581,8 @@ static t_Error SetExtBufferPools(t_FmPor
+     p_FmPort->rxPoolsParams.numOfPools = p_ExtBufPools->numOfPoolsUsed;
+     p_FmPort->rxPoolsParams.largestBufSize =
+             sizesArray[orderedArray[p_ExtBufPools->numOfPoolsUsed - 1]];
+-    p_FmPort->rxPoolsParams.secondLargestBufSize =
++    if (p_ExtBufPools->numOfPoolsUsed > 1)
++        p_FmPort->rxPoolsParams.secondLargestBufSize =
+             sizesArray[orderedArray[p_ExtBufPools->numOfPoolsUsed - 2]];
+     /* FMBM_RMPD reg. - pool depletion */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0107-fsl_qbman-Adjust-platform-device-creation-for-QMan-p.patch b/target/linux/layerscape/patches-5.4/701-net-0107-fsl_qbman-Adjust-platform-device-creation-for-QMan-p.patch
new file mode 100644 (file)
index 0000000..cd81c00
--- /dev/null
@@ -0,0 +1,103 @@
+From fddd729bd2150e83365528cefb9f1fef581e04c5 Mon Sep 17 00:00:00 2001
+From: Vakul Garg <vakul.garg@nxp.com>
+Date: Sun, 6 Jan 2019 19:05:37 +0530
+Subject: [PATCH] fsl_qbman: Adjust platform device creation for QMan portals
+
+Fix the platform device creation in QMan portals such that
+dma mappings are done properly.
+
+Signed-off-by: Vakul Garg <vakul.garg@nxp.com>
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+---
+ drivers/staging/fsl_qbman/qman_high.c | 47 +++++++++++++++++++----------------
+ 1 file changed, 25 insertions(+), 22 deletions(-)
+
+--- a/drivers/staging/fsl_qbman/qman_high.c
++++ b/drivers/staging/fsl_qbman/qman_high.c
+@@ -575,6 +575,7 @@ struct qman_portal *qman_create_portal(
+       char buf[16];
+       int ret;
+       u32 isdr;
++      struct platform_device_info pdev_info;
+       if (!portal) {
+               portal = kmalloc(sizeof(*portal), GFP_KERNEL);
+@@ -671,27 +672,22 @@ struct qman_portal *qman_create_portal(
+       portal->dqrr_disable_ref = 0;
+       portal->cb_dc_ern = NULL;
+       sprintf(buf, "qportal-%d", config->public_cfg.channel);
+-      portal->pdev = platform_device_alloc(buf, -1);
++
++      memset(&pdev_info, 0, sizeof(pdev_info));
++      pdev_info.name = buf;
++      pdev_info.id = PLATFORM_DEVID_NONE;
++      pdev_info.dma_mask = DMA_BIT_MASK(40);
++
++      portal->pdev = platform_device_register_full(&pdev_info);
+       if (!portal->pdev) {
+               pr_err("qman_portal - platform_device_alloc() failed\n");
+-              goto fail_devalloc;
+-      }
+-#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+-      portal->pdev->dev.coherent_dma_mask = DMA_BIT_MASK(40);
+-      portal->pdev->dev.dma_mask = &portal->pdev->dev.coherent_dma_mask;
+-#else
+-      if (dma_set_mask(&portal->pdev->dev, DMA_BIT_MASK(40))) {
+-              pr_err("qman_portal - dma_set_mask() failed\n");
+-              goto fail_devadd;
++              goto fail_devregister;
+       }
+-#endif
++
++      arch_setup_dma_ops(&portal->pdev->dev, 0, 0, NULL, true);
++
+       portal->pdev->dev.pm_domain = &qman_portal_device_pm_domain;
+       portal->pdev->dev.platform_data = portal;
+-      ret = platform_device_add(portal->pdev);
+-      if (ret) {
+-              pr_err("qman_portal - platform_device_add() failed\n");
+-              goto fail_devadd;
+-      }
+       dpa_rbtree_init(&portal->retire_table);
+       isdr = 0xffffffff;
+       qm_isr_disable_write(__p, isdr);
+@@ -751,10 +747,8 @@ fail_eqcr_empty:
+ fail_affinity:
+       free_irq(config->public_cfg.irq, portal);
+ fail_irq:
+-      platform_device_del(portal->pdev);
+-fail_devadd:
+-      platform_device_put(portal->pdev);
+-fail_devalloc:
++      platform_device_unregister(portal->pdev);
++fail_devregister:
+       if (num_ceetms)
+               for (ret = 0; ret < num_ceetms; ret++)
+                       kfree(portal->ccgrs[ret]);
+@@ -852,8 +846,7 @@ void qman_destroy_portal(struct qman_por
+       qm_dqrr_finish(&qm->p);
+       qm_eqcr_finish(&qm->p);
+-      platform_device_del(qm->pdev);
+-      platform_device_put(qm->pdev);
++      platform_device_unregister(qm->pdev);
+       qm->config = NULL;
+       if (qm->alloced)
+@@ -1809,6 +1802,16 @@ int qman_init_fq(struct qman_fq *fq, u32
+               } else {
+                       phys_fq = dma_map_single(&p->pdev->dev, fq, sizeof(*fq),
+                                               DMA_TO_DEVICE);
++                      if (dma_mapping_error(&p->pdev->dev, phys_fq)) {
++                              dev_err(&p->pdev->dev,
++                                      "dma_map_single failed for fqid: %u\n",
++                                      fq->fqid);
++                              FQUNLOCK(fq);
++                              PORTAL_IRQ_UNLOCK(p, irqflags);
++                              put_affine_portal();
++                              return -EIO;
++                      }
++
+                       qm_fqd_stashing_set64(&mcc->initfq.fqd, phys_fq);
+               }
+       }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0108-sdk_dpaa-ls1043a-errata-impose-S-G-frame-realignment.patch b/target/linux/layerscape/patches-5.4/701-net-0108-sdk_dpaa-ls1043a-errata-impose-S-G-frame-realignment.patch
new file mode 100644 (file)
index 0000000..8de2802
--- /dev/null
@@ -0,0 +1,81 @@
+From bfc02cc199dc6259c2f4e2af8f77c88fe8ba4cc5 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 5 Mar 2019 11:55:54 +0200
+Subject: [PATCH] sdk_dpaa: ls1043a errata: impose S/G frame realignment
+
+Scatter/Gather frames are not support on LS1043A beacuse they trigger
+the A010022 errata.
+
+Even though we do not advertise S/G support to the stack, we need to
+make sure that if S/G frames do reach the driver somehow, they trigger
+the errata workaround.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h |  7 ++++---
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c  | 23 +++++-----------------
+ 2 files changed, 9 insertions(+), 21 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
+@@ -653,9 +653,10 @@ static inline void _dpa_bp_free_pf(void
+ /* LS1043A SoC has a HW issue regarding FMan DMA transactions; The issue
+  * manifests itself at high traffic rates when frames cross 4K memory
+- * boundaries or when they are not aligned to 16 bytes; For the moment, we
+- * use a SW workaround that realigns frames to 256 bytes. Scatter/Gather
+- * frames aren't supported on egress.
++ * boundaries, when they are not aligned to 16 bytes or when they have
++ * Scatter/Gather fragments; For the moment, we use a SW workaround that
++ * realigns frames to 256 bytes. Scatter/Gather frames aren't supported
++ * on egress.
+  */
+ #ifndef CONFIG_PPC
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -772,18 +772,19 @@ EXPORT_SYMBOL(skb_to_contig_fd);
+ #ifndef CONFIG_PPC
+ /* Verify the conditions that trigger the A010022 errata: data unaligned to
+- * 16 bytes and 4K memory address crossings.
++ * 16 bytes, 4K memory address crossings and S/G fragments.
+  */
+ static bool a010022_check_skb(struct sk_buff *skb, struct dpa_priv_s *priv)
+ {
+-      int nr_frags, i = 0;
+-      skb_frag_t *frag;
+-
+       /* Check if the headroom is aligned */
+       if (((uintptr_t)skb->data - priv->tx_headroom) %
+           priv->buf_layout[TX].data_align != 0)
+               return true;
++      /* Check for paged data in the skb. We do not support S/G fragments */
++      if (skb_is_nonlinear(skb))
++              return true;
++
+       /* Check if the headroom crosses a boundary */
+       if (HAS_DMA_ISSUE(skb->head, skb_headroom(skb)))
+               return true;
+@@ -796,20 +797,6 @@ static bool a010022_check_skb(struct sk_
+       if (HAS_DMA_ISSUE(skb->head, skb_end_offset(skb)))
+               return true;
+-      nr_frags = skb_shinfo(skb)->nr_frags;
+-
+-      while (i < nr_frags) {
+-              frag = &skb_shinfo(skb)->frags[i];
+-
+-              /* Check if a paged fragment crosses a boundary from its
+-               * offset to its end.
+-               */
+-              if (HAS_DMA_ISSUE(frag->page_offset, frag->size))
+-                      return true;
+-
+-              i++;
+-      }
+-
+       return false;
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0109-sdk_dpaa-remove-the-QM_FQCTRL_PREFERINCACHE-flag.patch b/target/linux/layerscape/patches-5.4/701-net-0109-sdk_dpaa-remove-the-QM_FQCTRL_PREFERINCACHE-flag.patch
new file mode 100644 (file)
index 0000000..e96f873
--- /dev/null
@@ -0,0 +1,24 @@
+From 3cf2ff1c53b41c60fcb7667a11c4947fe5136de7 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Thu, 7 Mar 2019 16:33:37 +0200
+Subject: [PATCH] sdk_dpaa: remove the QM_FQCTRL_PREFERINCACHE flag
+
+Only a limited number of FQs can be in the cache, setting the
+QM_FQCTRL_PREFERINCACHE flag for all FQs is not useful.
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
+@@ -1237,8 +1237,6 @@ int dpa_fq_init(struct dpa_fq *dpa_fq, b
+               memset(&initfq, 0, sizeof(initfq));
+               initfq.we_mask = QM_INITFQ_WE_FQCTRL;
+-              /* FIXME: why would we want to keep an empty FQ in cache? */
+-              initfq.fqd.fq_ctrl = QM_FQCTRL_PREFERINCACHE;
+               /* Try to reduce the number of portal interrupts for
+                * Tx Confirmation FQs.
diff --git a/target/linux/layerscape/patches-5.4/701-net-0110-sdk_dpaa-adapt-to-kernel-5.1.0-rc1.patch b/target/linux/layerscape/patches-5.4/701-net-0110-sdk_dpaa-adapt-to-kernel-5.1.0-rc1.patch
new file mode 100644 (file)
index 0000000..72fa196
--- /dev/null
@@ -0,0 +1,165 @@
+From 68b77d267414d790e5cbd76f46a77501559e5748 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 26 Mar 2019 18:27:11 +0200
+Subject: [PATCH] sdk_dpaa: adapt to kernel 5.1.0 rc1
+
+Apply fixes corresponding to the following upstream patches:
+3c1bcc8 net: ethernet: Convert phydev advertize and supported from u32 to link mode
+1e562c8 ptp_qoriq: make structure/function names more consistent
+70814e8 net: ethernet: Add helper for set_pauseparam for Asym Pause
+22b7d29 net: ethernet: Add helper to determine if pause configuration is supported
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c | 31 +++-------------------
+ drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c  | 27 +++++++++----------
+ 2 files changed, 16 insertions(+), 42 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c
+@@ -225,7 +225,6 @@ static int __cold dpa_set_pauseparam(str
+       struct mac_device       *mac_dev;
+       struct phy_device       *phy_dev;
+       int _errno;
+-      u32 newadv, oldadv;
+       bool rx_pause, tx_pause;
+       priv = netdev_priv(net_dev);
+@@ -242,9 +241,7 @@ static int __cold dpa_set_pauseparam(str
+               return -ENODEV;
+       }
+-      if (!(phy_dev->supported & SUPPORTED_Pause) ||
+-                      (!(phy_dev->supported & SUPPORTED_Asym_Pause) &&
+-                      (epause->rx_pause != epause->tx_pause)))
++      if (!phy_validate_pause(phy_dev, epause))
+               return -EINVAL;
+       /* The MAC should know how to handle PAUSE frame autonegotiation before
+@@ -258,29 +255,7 @@ static int __cold dpa_set_pauseparam(str
+       /* Determine the sym/asym advertised PAUSE capabilities from the desired
+        * rx/tx pause settings.
+        */
+-      newadv = 0;
+-      if (epause->rx_pause)
+-              newadv = ADVERTISED_Pause | ADVERTISED_Asym_Pause;
+-      if (epause->tx_pause)
+-              newadv |= ADVERTISED_Asym_Pause;
+-
+-      oldadv = phy_dev->advertising &
+-                      (ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+-
+-      /* If there are differences between the old and the new advertised
+-       * values, restart PHY autonegotiation and advertise the new values.
+-       */
+-      if (oldadv != newadv) {
+-              phy_dev->advertising &= ~(ADVERTISED_Pause
+-                              | ADVERTISED_Asym_Pause);
+-              phy_dev->advertising |= newadv;
+-              if (phy_dev->autoneg) {
+-                      _errno = phy_start_aneg(phy_dev);
+-                      if (unlikely(_errno < 0))
+-                              netdev_err(net_dev, "phy_start_aneg() = %d\n",
+-                                              _errno);
+-              }
+-      }
++      phy_set_asym_pause(phy_dev, epause->rx_pause, epause->tx_pause);
+       get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
+       _errno = set_mac_active_pause(mac_dev, rx_pause, tx_pause);
+@@ -530,7 +505,7 @@ static int dpaa_get_ts_info(struct net_d
+       struct device_node *mac_node = dev->of_node;
+       struct device_node *fman_node = NULL, *ptp_node = NULL;
+       struct platform_device *ptp_dev = NULL;
+-      struct qoriq_ptp *ptp = NULL;
++      struct ptp_qoriq *ptp = NULL;
+       info->phc_index = -1;
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c
+@@ -385,11 +385,7 @@ void get_pause_cfg(struct mac_device *ma
+        */
+       /* get local capabilities */
+-      lcl_adv = 0;
+-      if (phy_dev->advertising & ADVERTISED_Pause)
+-              lcl_adv |= ADVERTISE_PAUSE_CAP;
+-      if (phy_dev->advertising & ADVERTISED_Asym_Pause)
+-              lcl_adv |= ADVERTISE_PAUSE_ASYM;
++      lcl_adv = linkmode_adv_to_lcl_adv_t(phy_dev->advertising);
+       /* get link partner capabilities */
+       rmt_adv = 0;
+@@ -439,6 +435,7 @@ static int dtsec_init_phy(struct net_dev
+                         struct mac_device *mac_dev)
+ {
+       struct phy_device       *phy_dev;
++      __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+       if (of_phy_is_fixed_link(mac_dev->phy_node))
+               phy_dev = of_phy_attach(net_dev, mac_dev->phy_node,
+@@ -455,12 +452,12 @@ static int dtsec_init_phy(struct net_dev
+       }
+       /* Remove any features not supported by the controller */
+-      phy_dev->supported &= mac_dev->if_support;
++      ethtool_convert_legacy_u32_to_link_mode(mask, mac_dev->if_support);
++      linkmode_and(phy_dev->supported, phy_dev->supported, mask);
+       /* Enable the symmetric and asymmetric PAUSE frame advertisements,
+        * as most of the PHY drivers do not enable them by default.
+        */
+-      phy_dev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+-      phy_dev->advertising = phy_dev->supported;
++      phy_support_asym_pause(phy_dev);
+       mac_dev->phy_dev = phy_dev;
+@@ -471,6 +468,7 @@ static int xgmac_init_phy(struct net_dev
+                         struct mac_device *mac_dev)
+ {
+       struct phy_device *phy_dev;
++      __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+       if (of_phy_is_fixed_link(mac_dev->phy_node))
+               phy_dev = of_phy_attach(net_dev, mac_dev->phy_node,
+@@ -486,12 +484,12 @@ static int xgmac_init_phy(struct net_dev
+               return phy_dev == NULL ? -ENODEV : PTR_ERR(phy_dev);
+       }
+-      phy_dev->supported &= mac_dev->if_support;
++      ethtool_convert_legacy_u32_to_link_mode(mask, mac_dev->if_support);
++      linkmode_and(phy_dev->supported, phy_dev->supported, mask);
+       /* Enable the symmetric and asymmetric PAUSE frame advertisements,
+        * as most of the PHY drivers do not enable them by default.
+        */
+-      phy_dev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+-      phy_dev->advertising = phy_dev->supported;
++      phy_support_asym_pause(phy_dev);
+       mac_dev->phy_dev = phy_dev;
+@@ -502,6 +500,7 @@ static int memac_init_phy(struct net_dev
+                         struct mac_device *mac_dev)
+ {
+       struct phy_device       *phy_dev;
++      __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+       void (*adjust_link_handler)(struct net_device *);
+       if ((macdev2enetinterface(mac_dev) == e_ENET_MODE_XGMII_10000) ||
+@@ -547,12 +546,12 @@ static int memac_init_phy(struct net_dev
+       }
+       /* Remove any features not supported by the controller */
+-      phy_dev->supported &= mac_dev->if_support;
++      ethtool_convert_legacy_u32_to_link_mode(mask, mac_dev->if_support);
++      linkmode_and(phy_dev->supported, phy_dev->supported, mask);
+       /* Enable the symmetric and asymmetric PAUSE frame advertisements,
+        * as most of the PHY drivers do not enable them by default.
+        */
+-      phy_dev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+-      phy_dev->advertising = phy_dev->supported;
++      phy_support_asym_pause(phy_dev);
+       mac_dev->phy_dev = phy_dev;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0111-sdk_qbman-Avoid-variable-length-array-in-USDPAA.patch b/target/linux/layerscape/patches-5.4/701-net-0111-sdk_qbman-Avoid-variable-length-array-in-USDPAA.patch
new file mode 100644 (file)
index 0000000..39cfc2d
--- /dev/null
@@ -0,0 +1,100 @@
+From 0ad840e46732e95df274a84b042dcb210be9f946 Mon Sep 17 00:00:00 2001
+From: Roy Pledge <roy.pledge@nxp.com>
+Date: Thu, 28 Mar 2019 09:56:35 -0400
+Subject: [PATCH] sdk_qbman: Avoid variable length array in USDPAA
+
+As of Linux 5.0 variable length arrays on the stack are no
+longer allowed. Change to a dynamic array and create a common
+exit point in the function for cleanup.
+
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+---
+ drivers/staging/fsl_qbman/fsl_usdpaa.c | 36 +++++++++++++++++-----------------
+ 1 file changed, 18 insertions(+), 18 deletions(-)
+
+--- a/drivers/staging/fsl_qbman/fsl_usdpaa.c
++++ b/drivers/staging/fsl_qbman/fsl_usdpaa.c
+@@ -559,6 +559,7 @@ static bool check_portal_channel(void *c
+ static int usdpaa_release(struct inode *inode, struct file *filp)
+ {
++      int err = 0;
+       struct ctx *ctx = filp->private_data;
+       struct mem_mapping *map, *tmpmap;
+       struct portal_mapping *portal, *tmpportal;
+@@ -569,9 +570,14 @@ static int usdpaa_release(struct inode *
+       struct qm_portal_config *qm_alloced_portal = NULL;
+       struct bm_portal_config *bm_alloced_portal = NULL;
+-      struct qm_portal *portal_array[qman_portal_max];
++      struct qm_portal **portal_array;
+       int portal_count = 0;
++      portal_array = kmalloc_array(qman_portal_max,
++                                   sizeof(struct qm_portal *), GFP_KERNEL);
++      if (!portal_array)
++              return -ENOMEM;
++
+       /* Ensure the release operation cannot be migrated to another
+          CPU as CPU specific variables may be needed during cleanup */
+ #ifdef CONFIG_PREEMPT_RT_FULL
+@@ -612,18 +618,14 @@ static int usdpaa_release(struct inode *
+               qm_alloced_portal = qm_get_unused_portal();
+               if (!qm_alloced_portal) {
+                       pr_crit("No QMan portal avalaible for cleanup\n");
+-#ifdef CONFIG_PREEMPT_RT_FULL
+-                      migrate_enable();
+-#endif
+-                      return -1;
++                      err = -1;
++                      goto done;
+               }
+               qm_cleanup_portal = kmalloc(sizeof(struct qm_portal),
+                                           GFP_KERNEL);
+               if (!qm_cleanup_portal) {
+-#ifdef CONFIG_PREEMPT_RT_FULL
+-                      migrate_enable();
+-#endif
+-                      return -ENOMEM;
++                      err = -ENOMEM;
++                      goto done;
+               }
+               init_qm_portal(qm_alloced_portal, qm_cleanup_portal);
+               portal_array[portal_count] = qm_cleanup_portal;
+@@ -633,18 +635,14 @@ static int usdpaa_release(struct inode *
+               bm_alloced_portal = bm_get_unused_portal();
+               if (!bm_alloced_portal) {
+                       pr_crit("No BMan portal avalaible for cleanup\n");
+-#ifdef CONFIG_PREEMPT_RT_FULL
+-                      migrate_enable();
+-#endif
+-                      return -1;
++                      err = -1;
++                      goto done;
+               }
+               bm_cleanup_portal = kmalloc(sizeof(struct bm_portal),
+                                           GFP_KERNEL);
+               if (!bm_cleanup_portal) {
+-#ifdef CONFIG_PREEMPT_RT_FULL
+-                      migrate_enable();
+-#endif
+-                      return -ENOMEM;
++                      err = -ENOMEM;
++                      goto done;
+               }
+               init_bm_portal(bm_alloced_portal, bm_cleanup_portal);
+       }
+@@ -721,10 +719,12 @@ static int usdpaa_release(struct inode *
+       }
+       kfree(ctx);
++done:
+ #ifdef CONFIG_PREEMPT_RT_FULL
+       migrate_enable();
+ #endif
+-      return 0;
++      kfree(portal_array);
++      return err;
+ }
+ static int check_mmap_dma(struct ctx *ctx, struct vm_area_struct *vma,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0112-sdk_dpaa-Rework-QBMan-portal-mappings.patch b/target/linux/layerscape/patches-5.4/701-net-0112-sdk_dpaa-Rework-QBMan-portal-mappings.patch
new file mode 100644 (file)
index 0000000..1752d1e
--- /dev/null
@@ -0,0 +1,65 @@
+From d0e3e315f49a0a35c7e0bdae934f33ee6b3042a0 Mon Sep 17 00:00:00 2001
+From: Roy Pledge <roy.pledge@nxp.com>
+Date: Wed, 1 May 2019 16:08:53 -0400
+Subject: [PATCH] sdk_dpaa: Rework QBMan portal mappings
+
+Rework the QBMan portal mappings in the SDK driver to
+match the mechanism used in the upstream varient.
+
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+---
+ drivers/staging/fsl_qbman/bman_driver.c | 16 ++++++++--------
+ drivers/staging/fsl_qbman/qman_driver.c | 17 +++++++++--------
+ 2 files changed, 17 insertions(+), 16 deletions(-)
+
+--- a/drivers/staging/fsl_qbman/bman_driver.c
++++ b/drivers/staging/fsl_qbman/bman_driver.c
+@@ -199,14 +199,14 @@ static struct bm_portal_config * __init
+                                 resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]));
+ #else
+-      pcfg->addr_virt[DPA_PORTAL_CE] = ioremap_prot(
+-                              pcfg->addr_phys[DPA_PORTAL_CE].start,
+-                              (unsigned long)len,
+-                              0);
+-      pcfg->addr_virt[DPA_PORTAL_CI] = ioremap_prot(
+-                              pcfg->addr_phys[DPA_PORTAL_CI].start,
+-                              resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]),
+-                              _PAGE_GUARDED | _PAGE_NO_CACHE);
++      pcfg->addr_virt[DPA_PORTAL_CE] =
++              memremap(pcfg->addr_phys[DPA_PORTAL_CE].start,
++                       (unsigned long)len, MEMREMAP_WB);
++
++      pcfg->addr_virt[DPA_PORTAL_CI] =
++              ioremap(pcfg->addr_phys[DPA_PORTAL_CI].start,
++                      resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]));
++
+ #endif
+       /* disable bp depletion */
+       __raw_writel(0x0, pcfg->addr_virt[DPA_PORTAL_CI] + BM_REG_SCN(0));
+--- a/drivers/staging/fsl_qbman/qman_driver.c
++++ b/drivers/staging/fsl_qbman/qman_driver.c
+@@ -459,14 +459,15 @@ static struct qm_portal_config * __init
+                                 pcfg->addr_phys[DPA_PORTAL_CI].start,
+                                 resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]));
+ #else
+-      pcfg->addr_virt[DPA_PORTAL_CE] = ioremap_prot(
+-                              pcfg->addr_phys[DPA_PORTAL_CE].start,
+-                              (unsigned long)len,
+-                              0);
+-      pcfg->addr_virt[DPA_PORTAL_CI] = ioremap_prot(
+-                              pcfg->addr_phys[DPA_PORTAL_CI].start,
+-                              resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]),
+-                              _PAGE_GUARDED | _PAGE_NO_CACHE);
++
++      pcfg->addr_virt[DPA_PORTAL_CE] =
++              memremap(pcfg->addr_phys[DPA_PORTAL_CE].start,
++                       (unsigned long)len, MEMREMAP_WB);
++
++      pcfg->addr_virt[DPA_PORTAL_CI] =
++              ioremap(pcfg->addr_phys[DPA_PORTAL_CI].start,
++                      resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]));
++
+ #endif
+       return pcfg;
+ err:
diff --git a/target/linux/layerscape/patches-5.4/701-net-0113-sdk_qbman-Fix-error-in-IP-revision-comparison.patch b/target/linux/layerscape/patches-5.4/701-net-0113-sdk_qbman-Fix-error-in-IP-revision-comparison.patch
new file mode 100644 (file)
index 0000000..e2cd46a
--- /dev/null
@@ -0,0 +1,28 @@
+From e180239ef07855f44f3bab4cfa5ac47c6775d822 Mon Sep 17 00:00:00 2001
+From: Roy Pledge <roy.pledge@nxp.com>
+Date: Mon, 6 May 2019 11:18:57 -0400
+Subject: [PATCH] sdk_qbman: Fix error in IP revision comparison
+
+The comparison for QMAN_REV31 was incorrect as it
+would always fail due to the wrong mask.
+
+This fixes the following error in newer GCC versions:
+"error: bitwise comparison always evaluates to false
+       [-Werror=tautological-compare]"
+
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+---
+ drivers/staging/fsl_qbman/qman_config.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl_qbman/qman_config.c
++++ b/drivers/staging/fsl_qbman/qman_config.c
+@@ -812,7 +812,7 @@ int qman_set_sdest(u16 channel, unsigned
+       if (!qman_have_ccsr())
+               return -ENODEV;
+-      if ((qman_ip_rev & 0xFF00) == QMAN_REV31) {
++      if ((qman_ip_rev & 0xFFFF) == QMAN_REV31) {
+               /* LS1043A - only one L2 cache */
+               cpu_idx = 0;
+       }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0114-sdk_dpaa-SGMII-2500-needs-AN-disabled.patch b/target/linux/layerscape/patches-5.4/701-net-0114-sdk_dpaa-SGMII-2500-needs-AN-disabled.patch
new file mode 100644 (file)
index 0000000..b986d35
--- /dev/null
@@ -0,0 +1,58 @@
+From e36f12a1d319b53d5f52b91671188a74e0a1fb41 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Tue, 23 Apr 2019 16:38:19 +0300
+Subject: [PATCH] sdk_dpaa: SGMII 2500 needs AN disabled
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ .../ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c | 14 ++++++++++----
+ .../ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h |  1 +
+ 2 files changed, 11 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c
+@@ -84,6 +84,7 @@ static void SetupSgmiiInternalPhy(t_Mema
+ {
+     uint16_t    tmpReg16;
+     e_EnetMode  enetMode;
++    bool autoneg_disabled = p_Memac->enetMode == e_ENET_MODE_SGMII_2500;
+      /* In case the higher MACs are used (i.e. the MACs that should support 10G),
+         speed=10000 is provided for SGMII ports. Temporary modify enet mode
+@@ -92,8 +93,9 @@ static void SetupSgmiiInternalPhy(t_Mema
+     /* SGMII mode + AN enable */
+     tmpReg16 = PHY_SGMII_IF_MODE_AN | PHY_SGMII_IF_MODE_SGMII;
+-    if ((p_Memac->enetMode) == e_ENET_MODE_SGMII_2500)
+-        tmpReg16 = PHY_SGMII_CR_PHY_RESET | PHY_SGMII_IF_SPEED_GIGABIT | PHY_SGMII_IF_MODE_SGMII;
++    /* unless SGMII 2500 where AN needs to be disabled  */
++    if (autoneg_disabled)
++        tmpReg16 = PHY_SGMII_IF_SPEED_GIGABIT | PHY_SGMII_IF_MODE_SGMII;
+     p_Memac->enetMode = MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_Memac->enetMode), e_ENET_SPEED_1000);
+     MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x14, tmpReg16);
+@@ -116,8 +118,12 @@ static void SetupSgmiiInternalPhy(t_Mema
+     MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x13, 0x0007);
+     MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x12, 0xa120);
+-    /* Restart AN */
+-    tmpReg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN;
++    if (!autoneg_disabled)
++        /* Restart AN */
++        tmpReg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN;
++    else
++        /* Disable AN */
++        tmpReg16 = PHY_SGMII_CR_DEF_VAL & ~PHY_SGMII_CR_AN_EN;
+     MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x0, tmpReg16);
+     /* Restore original enet mode */
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h
+@@ -93,6 +93,7 @@ typedef struct
+ #define PHY_SGMII_CR_PHY_RESET          0x8000
+ #define PHY_SGMII_CR_RESET_AN           0x0200
+ #define PHY_SGMII_CR_DEF_VAL            0x1140
++#define PHY_SGMII_CR_AN_EN              0x1000
+ #define PHY_SGMII_DEV_ABILITY_SGMII     0x4001
+ #define PHY_SGMII_DEV_ABILITY_1000X     0x01A0
+ #define PHY_SGMII_IF_SPEED_GIGABIT    0x0008
diff --git a/target/linux/layerscape/patches-5.4/701-net-0115-sdk_qbman-Update-cpus_allowed-to-cpus_mask-to-cope-w.patch b/target/linux/layerscape/patches-5.4/701-net-0115-sdk_qbman-Update-cpus_allowed-to-cpus_mask-to-cope-w.patch
new file mode 100644 (file)
index 0000000..900747b
--- /dev/null
@@ -0,0 +1,39 @@
+From 0bd330ec1fd657b5d04f0ab668b9fbaf7473fe8c Mon Sep 17 00:00:00 2001
+From: Li Yang <leoyang.li@nxp.com>
+Date: Tue, 11 Jun 2019 18:51:31 -0500
+Subject: [PATCH] sdk_qbman: Update cpus_allowed to cpus_mask to cope with
+ upstream change
+
+Signed-off-by: Li Yang <leoyang.li@nxp.com>
+---
+ drivers/staging/fsl_qbman/fsl_usdpaa_irq.c | 4 ++--
+ drivers/staging/fsl_qbman/qman_driver.c    | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/fsl_qbman/fsl_usdpaa_irq.c
++++ b/drivers/staging/fsl_qbman/fsl_usdpaa_irq.c
+@@ -145,11 +145,11 @@ static int map_irq(struct file *fp, stru
+               fput(ctx->usdpaa_filp);
+               return ret;
+       }
+-      ret = irq_set_affinity(ctx->irq_num, &current->cpus_allowed);
++      ret = irq_set_affinity(ctx->irq_num, &current->cpus_mask);
+       if (ret)
+               pr_err("USDPAA irq_set_affinity() failed, ret= %d\n", ret);
+-      ret = irq_set_affinity_hint(ctx->irq_num, &current->cpus_allowed);
++      ret = irq_set_affinity_hint(ctx->irq_num, &current->cpus_mask);
+       if (ret)
+               pr_err("USDPAA irq_set_affinity_hint() failed, ret= %d\n", ret);
+--- a/drivers/staging/fsl_qbman/qman_driver.c
++++ b/drivers/staging/fsl_qbman/qman_driver.c
+@@ -646,7 +646,7 @@ static struct qman_portal *init_pcfg(str
+ static void init_slave(int cpu)
+ {
+       struct qman_portal *p;
+-      struct cpumask oldmask = current->cpus_allowed;
++      struct cpumask oldmask = current->cpus_mask;
+       set_cpus_allowed_ptr(current, get_cpu_mask(cpu));
+       p = qman_create_affine_slave(shared_portals[shared_portals_idx++], cpu);
+       if (!p)
diff --git a/target/linux/layerscape/patches-5.4/701-net-0116-sdk_dpaa-ceetm-align-to-upstream-API-changes.patch b/target/linux/layerscape/patches-5.4/701-net-0116-sdk_dpaa-ceetm-align-to-upstream-API-changes.patch
new file mode 100644 (file)
index 0000000..c96a8f4
--- /dev/null
@@ -0,0 +1,61 @@
+From 17a9864b376f8ad0e19736ce53a3d7798679a0b8 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 3 Jul 2019 15:27:01 +0300
+Subject: [PATCH] sdk_dpaa: ceetm: align to upstream API changes
+
+Align to the following upstream patches:
+8cb0817 netlink: make validation more configurable for future strictness
+ae0be8d netlink: make nla_nest_start() add NLA_F_NESTED flag
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -650,7 +650,7 @@ static int ceetm_dump(struct Qdisc *sch,
+               return -EINVAL;
+       }
+-      nest = nla_nest_start(skb, TCA_OPTIONS);
++      nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
+       if (!nest)
+               goto nla_put_failure;
+       if (nla_put(skb, TCA_CEETM_QOPS, sizeof(qopt), &qopt))
+@@ -1133,7 +1133,7 @@ static int ceetm_init(struct Qdisc *sch,
+       if (ret)
+               return ret;
+-      ret = nla_parse_nested(tb, TCA_CEETM_QOPS, opt, ceetm_policy, NULL);
++      ret = nla_parse_nested_deprecated(tb, TCA_CEETM_QOPS, opt, ceetm_policy, NULL);
+       if (ret < 0) {
+               pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+               return ret;
+@@ -1307,7 +1307,7 @@ static int ceetm_change(struct Qdisc *sc
+       pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+-      ret = nla_parse_nested(tb, TCA_CEETM_QOPS, opt, ceetm_policy, NULL);
++      ret = nla_parse_nested_deprecated(tb, TCA_CEETM_QOPS, opt, ceetm_policy, NULL);
+       if (ret < 0) {
+               pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+               return ret;
+@@ -1527,7 +1527,7 @@ static int ceetm_cls_change(struct Qdisc
+               return -EINVAL;
+       }
+-      err = nla_parse_nested(tb, TCA_CEETM_COPT, opt, ceetm_policy, NULL);
++      err = nla_parse_nested_deprecated(tb, TCA_CEETM_COPT, opt, ceetm_policy, NULL);
+       if (err < 0) {
+               pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+               return -EINVAL;
+@@ -1728,7 +1728,7 @@ static int ceetm_cls_dump(struct Qdisc *
+               break;
+       }
+-      nest = nla_nest_start(skb, TCA_OPTIONS);
++      nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
+       if (!nest)
+               goto nla_put_failure;
+       if (nla_put(skb, TCA_CEETM_COPT, sizeof(copt), &copt))
diff --git a/target/linux/layerscape/patches-5.4/701-net-0117-dpaa_eth-ERR010022-align-skb_shinfo.patch b/target/linux/layerscape/patches-5.4/701-net-0117-dpaa_eth-ERR010022-align-skb_shinfo.patch
new file mode 100644 (file)
index 0000000..fbf1254
--- /dev/null
@@ -0,0 +1,23 @@
+From d640266a4307a4c857b27c90d56c9161dd615bcb Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 22 Jul 2019 14:50:10 +0300
+Subject: [PATCH] dpaa_eth: ERR010022: align skb_shinfo
+
+Cache-line align the new skb's shared info field.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+@@ -2171,7 +2171,7 @@ static struct sk_buff *dpaa_errata_a0100
+        * aligned to 256.
+        */
+       headroom = DPAA_A010022_HEADROOM;
+-      nsize = headroom + skb->len +
++      nsize = ALIGN(headroom + skb->len, SMP_CACHE_BYTES) +
+               SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+       /* Reserve enough memory to accommodate Jumbo frames */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0118-dpaa_eth-ERR010022-preserve-timestamping.patch b/target/linux/layerscape/patches-5.4/701-net-0118-dpaa_eth-ERR010022-preserve-timestamping.patch
new file mode 100644 (file)
index 0000000..cd4f6f4
--- /dev/null
@@ -0,0 +1,31 @@
+From 2039a9ff462d50251fd800ce4418f76230373783 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 22 Jul 2019 14:50:36 +0300
+Subject: [PATCH] dpaa_eth: ERR010022: preserve timestamping
+
+Maintain all timestamping fields when copying the skb.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+@@ -2196,6 +2196,15 @@ static struct sk_buff *dpaa_errata_a0100
+       }
+       skb_copy_header(nskb, skb);
++      /* Copy relevant timestamp info from the old skb to the new */
++      if (priv->tx_tstamp) {
++              skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags;
++              skb_shinfo(nskb)->hwtstamps = skb_shinfo(skb)->hwtstamps;
++              skb_shinfo(nskb)->tskey = skb_shinfo(skb)->tskey;
++              if (skb->sk)
++                      skb_set_owner_w(nskb, skb->sk);
++      }
++
+       /* We move the headroom when we align it so we have to reset the
+        * network and transport header offsets relative to the new data
+        * pointer. The checksum offload relies on these offsets.
diff --git a/target/linux/layerscape/patches-5.4/701-net-0119-sdk_dpaa-ceetm-update-Makefile-to-use-absolute-inclu.patch b/target/linux/layerscape/patches-5.4/701-net-0119-sdk_dpaa-ceetm-update-Makefile-to-use-absolute-inclu.patch
new file mode 100644 (file)
index 0000000..e163f99
--- /dev/null
@@ -0,0 +1,25 @@
+From 1d862091e7b7f49eb8533c74b6f7de34d6feb56c Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 12 Aug 2019 15:58:07 +0300
+Subject: [PATCH] sdk_dpaa: ceetm: update Makefile to use absolute include
+ paths
+
+Explicitly mention the root source tree directory when building. This
+allows the build process to start from a different location.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/Makefile
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/Makefile
+@@ -18,7 +18,7 @@ ifeq ($(CONFIG_FSL_DPAA_1588),y)
+ fsl_dpa-objs += dpaa_1588.o
+ endif
+ ifeq ($(CONFIG_FSL_DPAA_CEETM),y)
+-ccflags-y += -Idrivers/net/ethernet/freescale/sdk_fman/src/wrapper
++ccflags-y += -I$(srctree)/drivers/net/ethernet/freescale/sdk_fman/src/wrapper
+ fsl_dpa-objs += dpaa_eth_ceetm.o
+ endif
diff --git a/target/linux/layerscape/patches-5.4/701-net-0120-sdk_dpaa-net-Rename-skb_frag_t-size-to-bv_len.patch b/target/linux/layerscape/patches-5.4/701-net-0120-sdk_dpaa-net-Rename-skb_frag_t-size-to-bv_len.patch
new file mode 100644 (file)
index 0000000..4d22250
--- /dev/null
@@ -0,0 +1,38 @@
+From 1af9f383a9448da530de9f681e8fccf12435aac8 Mon Sep 17 00:00:00 2001
+From: Li Yang <leoyang.li@nxp.com>
+Date: Tue, 27 Aug 2019 19:03:59 -0500
+Subject: [PATCH] sdk_dpaa: net: Rename skb_frag_t size to bv_len
+
+Update for upstream data structure change similar to
+
+commit b8b576a16f79efbdde49348147f491b176537d88
+Author: Matthew Wilcox (Oracle) <willy@infradead.org>
+Date:   Mon Jul 22 20:08:30 2019 -0700
+
+    net: Rename skb_frag_t size to bv_len
+
+Signed-off-by: Li Yang <leoyang.li@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -960,7 +960,7 @@ int __hot skb_to_sg_fd(struct dpa_priv_s
+               frag = &skb_shinfo(skb)->frags[i - 1];
+               qm_sg_entry_set_bpid(&sgt[i], 0xff);
+               qm_sg_entry_set_offset(&sgt[i], 0);
+-              qm_sg_entry_set_len(&sgt[i], frag->size);
++              qm_sg_entry_set_len(&sgt[i], frag->bv_len);
+               qm_sg_entry_set_ext(&sgt[i], 0);
+               if (i == nr_frags)
+@@ -969,7 +969,7 @@ int __hot skb_to_sg_fd(struct dpa_priv_s
+                       qm_sg_entry_set_final(&sgt[i], 0);
+               DPA_BUG_ON(!skb_frag_page(frag));
+-              addr = skb_frag_dma_map(dpa_bp->dev, frag, 0, frag->size,
++              addr = skb_frag_dma_map(dpa_bp->dev, frag, 0, frag->bv_len,
+                                       dma_dir);
+               if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) {
+                       dev_err(dpa_bp->dev, "DMA mapping failed");
diff --git a/target/linux/layerscape/patches-5.4/701-net-0121-dpaa_eth-Rename-skb_frag_t-size-to-bv_len.patch b/target/linux/layerscape/patches-5.4/701-net-0121-dpaa_eth-Rename-skb_frag_t-size-to-bv_len.patch
new file mode 100644 (file)
index 0000000..c923687
--- /dev/null
@@ -0,0 +1,21 @@
+From e282d30e20d34d8d543866b662fdc16a5499a0ab Mon Sep 17 00:00:00 2001
+From: Li Yang <leoyang.li@nxp.com>
+Date: Sat, 7 Sep 2019 18:29:45 -0500
+Subject: [PATCH] dpaa_eth: Rename skb_frag_t size to bv_len
+
+Signed-off-by: Li Yang <leoyang.li@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+@@ -2141,7 +2141,7 @@ static bool dpaa_errata_a010022_has_dma_
+               /* Check if a paged fragment crosses a boundary from its
+                * offset to its end.
+                */
+-              if (CROSS_4K_BOUND((uintptr_t)frag->page_offset, frag->size))
++              if (CROSS_4K_BOUND((uintptr_t)frag->page_offset, frag->bv_len))
+                       return true;
+               i++;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0122-config-enable-SDK-FMan-driver.patch b/target/linux/layerscape/patches-5.4/701-net-0122-config-enable-SDK-FMan-driver.patch
new file mode 100644 (file)
index 0000000..47d8011
--- /dev/null
@@ -0,0 +1,20 @@
+From d6b59a9bf9d88cbfe41b96603824ffffea305b0f Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Fri, 19 May 2017 09:08:36 +0300
+Subject: [PATCH] config: enable SDK FMan driver
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/ethernet/freescale/Kconfig
++++ b/drivers/net/ethernet/freescale/Kconfig
+@@ -95,6 +95,7 @@ config GIANFAR
+         This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
+         and MPC86xx family of chips, the eTSEC on LS1021A and the FEC
+         on the 8540.
++source "drivers/net/ethernet/freescale/sdk_fman/Kconfig"
+ source "drivers/net/ethernet/freescale/dpaa/Kconfig"
+ source "drivers/net/ethernet/freescale/dpaa2/Kconfig"
diff --git a/target/linux/layerscape/patches-5.4/701-net-0123-config-enable-SDK-DPAA-driver.patch b/target/linux/layerscape/patches-5.4/701-net-0123-config-enable-SDK-DPAA-driver.patch
new file mode 100644 (file)
index 0000000..e025c14
--- /dev/null
@@ -0,0 +1,21 @@
+From d3d61dea25b1e122353895d8154c2e5f51c11a5a Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Fri, 19 May 2017 09:30:19 +0300
+Subject: [PATCH] config: enable SDK DPAA driver
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/Kconfig
++++ b/drivers/net/ethernet/freescale/Kconfig
+@@ -96,7 +96,7 @@ config GIANFAR
+         and MPC86xx family of chips, the eTSEC on LS1021A and the FEC
+         on the 8540.
+ source "drivers/net/ethernet/freescale/sdk_fman/Kconfig"
+-
++source "drivers/net/ethernet/freescale/sdk_dpaa/Kconfig"
+ source "drivers/net/ethernet/freescale/dpaa/Kconfig"
+ source "drivers/net/ethernet/freescale/dpaa2/Kconfig"
+ source "drivers/net/ethernet/freescale/enetc/Kconfig"
diff --git a/target/linux/layerscape/patches-5.4/701-net-0124-config-enable-SDK-QBMan.patch b/target/linux/layerscape/patches-5.4/701-net-0124-config-enable-SDK-QBMan.patch
new file mode 100644 (file)
index 0000000..14eb62c
--- /dev/null
@@ -0,0 +1,21 @@
+From b784a6d9b093b7bfd4e47a5b34aac73d1f46b476 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Fri, 19 May 2017 11:35:21 +0300
+Subject: [PATCH] config: enable SDK QBMan
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+[ Aisheng: fix minor conflcit due to removed vboxsf/Kconfig ]
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ drivers/staging/Kconfig | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/staging/Kconfig
++++ b/drivers/staging/Kconfig
+@@ -125,4 +125,6 @@ source "drivers/staging/exfat/Kconfig"
+ source "drivers/staging/qlge/Kconfig"
++source "drivers/staging/fsl_qbman/Kconfig"
++
+ endif # STAGING
diff --git a/target/linux/layerscape/patches-5.4/701-net-0125-config-add-SDK-QBMan-driver.patch b/target/linux/layerscape/patches-5.4/701-net-0125-config-add-SDK-QBMan-driver.patch
new file mode 100644 (file)
index 0000000..c89ecfa
--- /dev/null
@@ -0,0 +1,19 @@
+From c9c1e4d58aa598440904280e3261760fa6f0864e Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Fri, 19 May 2017 11:39:25 +0300
+Subject: [PATCH] config: add SDK QBMan driver
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+[ Aisheng: fix minor conflict due to removed CONFIG_VBOXSF_FS ]
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ drivers/staging/Makefile | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/staging/Makefile
++++ b/drivers/staging/Makefile
+@@ -53,3 +53,4 @@ obj-$(CONFIG_UWB)            += uwb/
+ obj-$(CONFIG_USB_WUSB)                += wusbcore/
+ obj-$(CONFIG_EXFAT_FS)                += exfat/
+ obj-$(CONFIG_QLGE)            += qlge/
++obj-$(CONFIG_FSL_SDK_DPA)      += fsl_qbman/
diff --git a/target/linux/layerscape/patches-5.4/701-net-0126-net-Makefile-re-add-DPAA-SDK-drivers.patch b/target/linux/layerscape/patches-5.4/701-net-0126-net-Makefile-re-add-DPAA-SDK-drivers.patch
new file mode 100644 (file)
index 0000000..9aa4c46
--- /dev/null
@@ -0,0 +1,22 @@
+From 67d8e64b7f996a6398ff3aef6834e12540d3f51f Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Fri, 30 Jun 2017 09:19:52 +0300
+Subject: [PATCH] net: Makefile: re-add DPAA SDK drivers
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/Makefile | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/Makefile
++++ b/drivers/net/ethernet/freescale/Makefile
+@@ -19,6 +19,9 @@ gianfar_driver-objs := gianfar.o \
+ obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
+ ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o
++obj-$(if $(CONFIG_FSL_SDK_FMAN),y) += sdk_fman/
++obj-$(if $(CONFIG_FSL_SDK_DPAA_ETH),y) += sdk_dpaa/
++
+ obj-$(CONFIG_FSL_FMAN) += fman/
+ obj-$(CONFIG_FSL_DPAA_ETH) += dpaa/
diff --git a/target/linux/layerscape/patches-5.4/701-net-0127-ptp-support-ptp_qoriq-for-sdk-dpaa.patch b/target/linux/layerscape/patches-5.4/701-net-0127-ptp-support-ptp_qoriq-for-sdk-dpaa.patch
new file mode 100644 (file)
index 0000000..831b368
--- /dev/null
@@ -0,0 +1,25 @@
+From 46b406426b67d869176d4a4b4b321f71f28753dc Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Thu, 17 Jan 2019 14:34:51 +0800
+Subject: [PATCH] ptp: support ptp_qoriq for sdk dpaa
+
+The ptp_qoriq driver could be used for both sdk version
+dpaa driver and upstream version dpaa driver. So added
+sdk dpaa dependency for ptp_qoriq driver.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/ptp/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/ptp/Kconfig
++++ b/drivers/ptp/Kconfig
+@@ -44,7 +44,7 @@ config PTP_1588_CLOCK_DTE
+ config PTP_1588_CLOCK_QORIQ
+       tristate "Freescale QorIQ 1588 timer as PTP clock"
+-      depends on GIANFAR || FSL_DPAA_ETH || FSL_DPAA2_ETH || FSL_ENETC || FSL_ENETC_VF || COMPILE_TEST
++      depends on GIANFAR || FSL_DPAA_ETH || FSL_SDK_DPAA_ETH || FSL_DPAA2_ETH || FSL_ENETC || FSL_ENETC_VF || COMPILE_TEST
+       depends on PTP_1588_CLOCK
+       default y
+       help
diff --git a/target/linux/layerscape/patches-5.4/701-net-0128-net-dpaa-fix-build-failure-due-to-skb_frag_t-struct-.patch b/target/linux/layerscape/patches-5.4/701-net-0128-net-dpaa-fix-build-failure-due-to-skb_frag_t-struct-.patch
new file mode 100644 (file)
index 0000000..2a6ccab
--- /dev/null
@@ -0,0 +1,40 @@
+From bd9aa7c077105fda307bbc685949d5bb01ed1bd8 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Sun, 29 Sep 2019 22:38:34 +0800
+Subject: [PATCH] net: dpaa: fix build failure due to skb_frag_t struct change
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We met below build break due to new kernel change:
+8842d285bafa ("net: Convert skb_frag_t to bio_vec")
+
+../drivers/net/ethernet/freescale/dpaa/dpaa_eth.c: In function ‘dpaa_errata_a010022_has_dma_issue’:
+../drivers/net/ethernet/freescale/dpaa/dpaa_eth.c:2137:37: error: ‘skb_frag_t’ has no member named ‘page_offset’
+   if (CROSS_4K_BOUND((uintptr_t)frag->page_offset, frag->bv_len))
+                                     ^
+../drivers/net/ethernet/freescale/dpaa/dpaa_eth.c:2105:5: note: in definition of macro ‘CROSS_4K_BOUND’
+  (((start) + (size)) > (((start) + 0x1000) & ~0xFFF))
+     ^
+../drivers/net/ethernet/freescale/dpaa/dpaa_eth.c:2137:37: error: ‘skb_frag_t’ has no member named ‘page_offset’
+   if (CROSS_4K_BOUND((uintptr_t)frag->page_offset, frag->bv_len))
+                                     ^
+../drivers/net/ethernet/freescale/dpaa/dpaa_eth.c:2105:27: note: in definition of macro ‘CROSS_4K_BOUND’
+  (((start) + (size)) > (((start) + 0x1000) & ~0xFFF))
+
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+@@ -2141,7 +2141,7 @@ static bool dpaa_errata_a010022_has_dma_
+               /* Check if a paged fragment crosses a boundary from its
+                * offset to its end.
+                */
+-              if (CROSS_4K_BOUND((uintptr_t)frag->page_offset, frag->bv_len))
++              if (CROSS_4K_BOUND(skb_frag_off(frag), skb_frag_size(frag)))
+                       return true;
+               i++;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0129-sdk_dpa-align-to-upstream-PHY_INTERFACE_MODE.patch b/target/linux/layerscape/patches-5.4/701-net-0129-sdk_dpa-align-to-upstream-PHY_INTERFACE_MODE.patch
new file mode 100644 (file)
index 0000000..171ef61
--- /dev/null
@@ -0,0 +1,30 @@
+From 3343551eb8a692aafcbf1a7eaf0b79965aa60ba9 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Wed, 16 Oct 2019 11:53:54 +0300
+Subject: [PATCH] sdk_dpa: align to upstream PHY_INTERFACE_MODE
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/mac.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/mac.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac.c
+@@ -76,7 +76,7 @@ static const char phy_str[][11] = {
+       [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
+       [PHY_INTERFACE_MODE_RTBI]       = "rtbi",
+       [PHY_INTERFACE_MODE_XGMII]      = "xgmii",
+-      [PHY_INTERFACE_MODE_2500SGMII] = "sgmii-2500",
++      [PHY_INTERFACE_MODE_2500BASEX] = "sgmii-2500",
+ };
+ static phy_interface_t __pure __attribute__((nonnull)) str2phy(const char *str)
+@@ -103,7 +103,7 @@ static const uint16_t phy2speed[] = {
+       [PHY_INTERFACE_MODE_RGMII_TXID] = SPEED_1000,
+       [PHY_INTERFACE_MODE_RTBI]       = SPEED_1000,
+       [PHY_INTERFACE_MODE_XGMII]      = SPEED_10000,
+-      [PHY_INTERFACE_MODE_2500SGMII] = SPEED_2500,
++      [PHY_INTERFACE_MODE_2500BASEX] = SPEED_2500,
+ };
+ static struct mac_device * __cold
diff --git a/target/linux/layerscape/patches-5.4/701-net-0130-bus-fsl-mc-move-fsl_mc_command-struct-in-a-uapi-head.patch b/target/linux/layerscape/patches-5.4/701-net-0130-bus-fsl-mc-move-fsl_mc_command-struct-in-a-uapi-head.patch
new file mode 100644 (file)
index 0000000..47b3d10
--- /dev/null
@@ -0,0 +1,86 @@
+From c2939a719ebc7b39453f47ad2d8d30fc06ef4be6 Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Tue, 13 Mar 2018 13:57:00 +0200
+Subject: [PATCH] bus: fsl-mc: move fsl_mc_command struct in a uapi header
+
+Define "struct fsl_mc_command" as a structure that can cross the
+user/kernel boundary.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+---
+ MAINTAINERS                 |  2 ++
+ include/linux/fsl/mc.h      |  8 +-------
+ include/uapi/linux/fsl_mc.h | 25 +++++++++++++++++++++++++
+ 3 files changed, 28 insertions(+), 7 deletions(-)
+ create mode 100644 include/uapi/linux/fsl_mc.h
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -13436,6 +13436,8 @@ S:     Maintained
+ F:    drivers/bus/fsl-mc/
+ F:    Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
+ F:    Documentation/networking/device_drivers/freescale/dpaa2/overview.rst
++F:    Documentation/networking/dpaa2/overview.rst
++F:    include/uapi/linux/fsl_mc.h
+ QT1010 MEDIA DRIVER
+ M:    Antti Palosaari <crope@iki.fi>
+--- a/include/linux/fsl/mc.h
++++ b/include/linux/fsl/mc.h
+@@ -12,6 +12,7 @@
+ #include <linux/device.h>
+ #include <linux/mod_devicetable.h>
+ #include <linux/interrupt.h>
++#include <uapi/linux/fsl_mc.h>
+ #define FSL_MC_VENDOR_FREESCALE       0x1957
+@@ -199,8 +200,6 @@ struct fsl_mc_device {
+ #define to_fsl_mc_device(_dev) \
+       container_of(_dev, struct fsl_mc_device, dev)
+-#define MC_CMD_NUM_OF_PARAMS  7
+-
+ struct mc_cmd_header {
+       u8 src_id;
+       u8 flags_hw;
+@@ -210,11 +209,6 @@ struct mc_cmd_header {
+       __le16 cmd_id;
+ };
+-struct fsl_mc_command {
+-      __le64 header;
+-      __le64 params[MC_CMD_NUM_OF_PARAMS];
+-};
+-
+ enum mc_cmd_status {
+       MC_CMD_STATUS_OK = 0x0, /* Completed successfully */
+       MC_CMD_STATUS_READY = 0x1, /* Ready to be processed */
+--- /dev/null
++++ b/include/uapi/linux/fsl_mc.h
+@@ -0,0 +1,25 @@
++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
++/*
++ * Management Complex (MC) userspace public interface
++ *
++ * Copyright 2018 NXP
++ *
++ */
++#ifndef _UAPI_FSL_MC_H_
++#define _UAPI_FSL_MC_H_
++
++#include <linux/types.h>
++
++#define MC_CMD_NUM_OF_PARAMS  7
++
++/**
++ * struct fsl_mc_command - Management Complex (MC) command structure
++ * @header: MC command header
++ * @params: MC command parameters
++ */
++struct fsl_mc_command {
++      __le64 header;
++      __le64 params[MC_CMD_NUM_OF_PARAMS];
++};
++
++#endif /* _UAPI_FSL_MC_H_ */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0131-bus-fsl-mc-add-fsl-mc-userspace-support.patch b/target/linux/layerscape/patches-5.4/701-net-0131-bus-fsl-mc-add-fsl-mc-userspace-support.patch
new file mode 100644 (file)
index 0000000..106ce0d
--- /dev/null
@@ -0,0 +1,371 @@
+From 5b5567547d0088ec96160634c4e342bb06e52f19 Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Wed, 14 Mar 2018 19:25:27 +0200
+Subject: [PATCH] bus: fsl-mc: add fsl-mc userspace support
+
+Adding userspace support for the MC (Management Complex) means exporting
+an ioctl capable device file representing the root resource container.
+
+This new functionality in the fsl-mc bus driver intends to provide
+userspace applications an interface to interact with the MC firmware.
+
+Commands that are composed in userspace are sent to the MC firmware
+through the FSL_MC_SEND_MC_COMMAND ioctl.  By default the implicit MC
+I/O portal is used for this operation, but if the implicit one is busy,
+a dynamic portal is allocated and then freed upon execution.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+---
+ Documentation/ioctl/ioctl-number.rst |   1 +
+ drivers/bus/fsl-mc/Kconfig           |   7 ++
+ drivers/bus/fsl-mc/Makefile          |   3 +
+ drivers/bus/fsl-mc/dprc-driver.c     |  14 ++-
+ drivers/bus/fsl-mc/fsl-mc-private.h  |  39 ++++++++
+ drivers/bus/fsl-mc/fsl-mc-uapi.c     | 168 +++++++++++++++++++++++++++++++++++
+ include/uapi/linux/fsl_mc.h          |   9 ++
+ 7 files changed, 240 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/bus/fsl-mc/fsl-mc-uapi.c
+
+--- a/Documentation/ioctl/ioctl-number.rst
++++ b/Documentation/ioctl/ioctl-number.rst
+@@ -180,6 +180,7 @@ Code  Seq#    Include File
+ 'R'   00-1F  linux/random.h                                          conflict!
+ 'R'   01     linux/rfkill.h                                          conflict!
+ 'R'   C0-DF  net/bluetooth/rfcomm.h
++'R'   E0     uapi/linux/fsl_mc.h
+ 'S'   all    linux/cdrom.h                                           conflict!
+ 'S'   80-81  scsi/scsi_ioctl.h                                       conflict!
+ 'S'   82-FF  scsi/scsi.h                                             conflict!
+--- a/drivers/bus/fsl-mc/Kconfig
++++ b/drivers/bus/fsl-mc/Kconfig
+@@ -14,3 +14,10 @@ config FSL_MC_BUS
+         architecture.  The fsl-mc bus driver handles discovery of
+         DPAA2 objects (which are represented as Linux devices) and
+         binding objects to drivers.
++
++config FSL_MC_UAPI_SUPPORT
++      bool "Management Complex (MC) userspace support"
++      depends on FSL_MC_BUS
++      help
++        Provides userspace support for creating/destroying/configuring
++        DPAA2 objects in the Management Complex.
+--- a/drivers/bus/fsl-mc/Makefile
++++ b/drivers/bus/fsl-mc/Makefile
+@@ -16,3 +16,6 @@ mc-bus-driver-objs := fsl-mc-bus.o \
+                     fsl-mc-allocator.o \
+                     fsl-mc-msi.o \
+                     dpmcp.o
++
++# MC userspace support
++obj-$(CONFIG_FSL_MC_UAPI_SUPPORT) += fsl-mc-uapi.o
+--- a/drivers/bus/fsl-mc/dprc-driver.c
++++ b/drivers/bus/fsl-mc/dprc-driver.c
+@@ -647,6 +647,12 @@ static int dprc_probe(struct fsl_mc_devi
+               } else {
+                       dev_set_msi_domain(&mc_dev->dev, mc_msi_domain);
+                       msi_domain_set = true;
++
++                      error = fsl_mc_uapi_create_device_file(mc_bus);
++                      if (error < 0) {
++                              error = -EPROBE_DEFER;
++                              goto error_cleanup_msi_domain;
++                      }
+               }
+       }
+@@ -654,7 +660,7 @@ static int dprc_probe(struct fsl_mc_devi
+                         &mc_dev->mc_handle);
+       if (error < 0) {
+               dev_err(&mc_dev->dev, "dprc_open() failed: %d\n", error);
+-              goto error_cleanup_msi_domain;
++              goto error_cleanup_uapi;
+       }
+       error = dprc_get_attributes(mc_dev->mc_io, 0, mc_dev->mc_handle,
+@@ -706,6 +712,10 @@ static int dprc_probe(struct fsl_mc_devi
+ error_cleanup_open:
+       (void)dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
++error_cleanup_uapi:
++      if (fsl_mc_is_root_dprc(&mc_dev->dev))
++              fsl_mc_uapi_remove_device_file(mc_bus);
++
+ error_cleanup_msi_domain:
+       if (msi_domain_set)
+               dev_set_msi_domain(&mc_dev->dev, NULL);
+@@ -774,6 +784,8 @@ static int dprc_remove(struct fsl_mc_dev
+       if (!fsl_mc_is_root_dprc(&mc_dev->dev)) {
+               fsl_destroy_mc_io(mc_dev->mc_io);
+               mc_dev->mc_io = NULL;
++      } else {
++              fsl_mc_uapi_remove_device_file(mc_bus);
+       }
+       dev_info(&mc_dev->dev, "DPRC device unbound from driver");
+--- a/drivers/bus/fsl-mc/fsl-mc-private.h
++++ b/drivers/bus/fsl-mc/fsl-mc-private.h
+@@ -10,6 +10,8 @@
+ #include <linux/fsl/mc.h>
+ #include <linux/mutex.h>
++#include <linux/ioctl.h>
++#include <linux/miscdevice.h>
+ /*
+  * Data Path Management Complex (DPMNG) General API
+@@ -505,6 +507,22 @@ struct fsl_mc_resource_pool {
+ };
+ /**
++ * struct fsl_mc_uapi - information associated with a device file
++ * @misc: struct miscdevice linked to the root dprc
++ * @device: newly created device in /dev
++ * @mutex: mutex lock to serialize the open/release operations
++ * @local_instance_in_use: local MC I/O instance in use or not
++ * @static_mc_io: pointer to the static MC I/O object
++ */
++struct fsl_mc_uapi {
++      struct miscdevice misc;
++      struct device *device;
++      struct mutex mutex; /* serialize open/release operations */
++      u32 local_instance_in_use;
++      struct fsl_mc_io *static_mc_io;
++};
++
++/**
+  * struct fsl_mc_bus - logical bus that corresponds to a physical DPRC
+  * @mc_dev: fsl-mc device for the bus device itself.
+  * @resource_pools: array of resource pools (one pool per resource type)
+@@ -513,6 +531,7 @@ struct fsl_mc_resource_pool {
+  * @irq_resources: Pointer to array of IRQ objects for the IRQ pool
+  * @scan_mutex: Serializes bus scanning
+  * @dprc_attr: DPRC attributes
++ * @uapi_misc: struct that abstracts the interaction with userspace
+  */
+ struct fsl_mc_bus {
+       struct fsl_mc_device mc_dev;
+@@ -520,6 +539,7 @@ struct fsl_mc_bus {
+       struct fsl_mc_device_irq *irq_resources;
+       struct mutex scan_mutex;    /* serializes bus scanning */
+       struct dprc_attributes dprc_attr;
++      struct fsl_mc_uapi uapi_misc;
+ };
+ #define to_fsl_mc_bus(_mc_dev) \
+@@ -574,4 +594,23 @@ void fsl_destroy_mc_io(struct fsl_mc_io
+ bool fsl_mc_is_root_dprc(struct device *dev);
++#ifdef CONFIG_FSL_MC_UAPI_SUPPORT
++
++int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus);
++
++void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus);
++
++#else
++
++static inline int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus)
++{
++      return 0;
++}
++
++static inline void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus)
++{
++}
++
++#endif
++
+ #endif /* _FSL_MC_PRIVATE_H_ */
+--- /dev/null
++++ b/drivers/bus/fsl-mc/fsl-mc-uapi.c
+@@ -0,0 +1,168 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Management Complex (MC) userspace support
++ *
++ * Copyright 2018 NXP
++ *
++ */
++
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/uaccess.h>
++#include <linux/miscdevice.h>
++
++#include "fsl-mc-private.h"
++
++struct uapi_priv_data {
++      struct fsl_mc_uapi *uapi;
++      struct fsl_mc_io *mc_io;
++};
++
++static int fsl_mc_uapi_send_command(unsigned long arg,
++                                  struct fsl_mc_io *mc_io)
++{
++      struct fsl_mc_command mc_cmd;
++      int error;
++
++      error = copy_from_user(&mc_cmd, (void __user *)arg, sizeof(mc_cmd));
++      if (error)
++              return -EFAULT;
++
++      error = mc_send_command(mc_io, &mc_cmd);
++      if (error)
++              return error;
++
++      error = copy_to_user((void __user *)arg, &mc_cmd, sizeof(mc_cmd));
++      if (error)
++              return -EFAULT;
++
++      return 0;
++}
++
++static int fsl_mc_uapi_dev_open(struct inode *inode, struct file *filep)
++{
++      struct fsl_mc_device *root_mc_device;
++      struct uapi_priv_data *priv_data;
++      struct fsl_mc_io *dynamic_mc_io;
++      struct fsl_mc_uapi *mc_uapi;
++      struct fsl_mc_bus *mc_bus;
++      int error;
++
++      priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL);
++      if (!priv_data)
++              return -ENOMEM;
++
++      mc_uapi = container_of(filep->private_data, struct fsl_mc_uapi, misc);
++      mc_bus = container_of(mc_uapi, struct fsl_mc_bus, uapi_misc);
++      root_mc_device = &mc_bus->mc_dev;
++
++      mutex_lock(&mc_uapi->mutex);
++
++      if (!mc_uapi->local_instance_in_use) {
++              priv_data->mc_io = mc_uapi->static_mc_io;
++              mc_uapi->local_instance_in_use = 1;
++      } else {
++              error = fsl_mc_portal_allocate(root_mc_device, 0,
++                                             &dynamic_mc_io);
++              if (error) {
++                      dev_dbg(&root_mc_device->dev,
++                              "Could not allocate MC portal\n");
++                      goto error_portal_allocate;
++              }
++
++              priv_data->mc_io = dynamic_mc_io;
++      }
++      priv_data->uapi = mc_uapi;
++      filep->private_data = priv_data;
++
++      mutex_unlock(&mc_uapi->mutex);
++
++      return 0;
++
++error_portal_allocate:
++      mutex_unlock(&mc_uapi->mutex);
++
++      return error;
++}
++
++static int fsl_mc_uapi_dev_release(struct inode *inode, struct file *filep)
++{
++      struct uapi_priv_data *priv_data;
++      struct fsl_mc_uapi *mc_uapi;
++      struct fsl_mc_io *mc_io;
++
++      priv_data = filep->private_data;
++      mc_uapi = priv_data->uapi;
++      mc_io = priv_data->mc_io;
++
++      mutex_lock(&mc_uapi->mutex);
++
++      if (mc_io == mc_uapi->static_mc_io)
++              mc_uapi->local_instance_in_use = 0;
++      else
++              fsl_mc_portal_free(mc_io);
++
++      kfree(filep->private_data);
++      filep->private_data =  NULL;
++
++      mutex_unlock(&mc_uapi->mutex);
++
++      return 0;
++}
++
++static long fsl_mc_uapi_dev_ioctl(struct file *file,
++                                unsigned int cmd,
++                                unsigned long arg)
++{
++      struct uapi_priv_data *priv_data = file->private_data;
++      struct fsl_mc_device *root_mc_device;
++      struct fsl_mc_bus *mc_bus;
++      int error;
++
++      mc_bus = container_of(priv_data->uapi, struct fsl_mc_bus, uapi_misc);
++      root_mc_device = &mc_bus->mc_dev;
++
++      switch (cmd) {
++      case FSL_MC_SEND_MC_COMMAND:
++              error = fsl_mc_uapi_send_command(arg, priv_data->mc_io);
++              break;
++      default:
++              dev_dbg(&root_mc_device->dev, "unexpected ioctl call number\n");
++              error = -EINVAL;
++      }
++
++      return error;
++}
++
++static const struct file_operations fsl_mc_uapi_dev_fops = {
++      .owner = THIS_MODULE,
++      .open = fsl_mc_uapi_dev_open,
++      .release = fsl_mc_uapi_dev_release,
++      .unlocked_ioctl = fsl_mc_uapi_dev_ioctl,
++};
++
++int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus)
++{
++      struct fsl_mc_device *mc_dev = &mc_bus->mc_dev;
++      struct fsl_mc_uapi *mc_uapi = &mc_bus->uapi_misc;
++      int error;
++
++      mc_uapi->misc.minor = MISC_DYNAMIC_MINOR;
++      mc_uapi->misc.name = dev_name(&mc_dev->dev);
++      mc_uapi->misc.fops = &fsl_mc_uapi_dev_fops;
++
++      error = misc_register(&mc_uapi->misc);
++      if (error)
++              return error;
++
++      mc_uapi->static_mc_io = mc_bus->mc_dev.mc_io;
++
++      mutex_init(&mc_uapi->mutex);
++
++      return 0;
++}
++
++void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus)
++{
++      misc_deregister(&mc_bus->uapi_misc.misc);
++}
+--- a/include/uapi/linux/fsl_mc.h
++++ b/include/uapi/linux/fsl_mc.h
+@@ -16,10 +16,19 @@
+  * struct fsl_mc_command - Management Complex (MC) command structure
+  * @header: MC command header
+  * @params: MC command parameters
++ *
++ * Used by FSL_MC_SEND_MC_COMMAND
+  */
+ struct fsl_mc_command {
+       __le64 header;
+       __le64 params[MC_CMD_NUM_OF_PARAMS];
+ };
++#define FSL_MC_SEND_CMD_IOCTL_TYPE    'R'
++#define FSL_MC_SEND_CMD_IOCTL_SEQ     0xE0
++
++#define FSL_MC_SEND_MC_COMMAND \
++      _IOWR(FSL_MC_SEND_CMD_IOCTL_TYPE, FSL_MC_SEND_CMD_IOCTL_SEQ, \
++      struct fsl_mc_command)
++
+ #endif /* _UAPI_FSL_MC_H_ */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0132-bus-fsl-mc-add-root-dprc-rescan-attribute.patch b/target/linux/layerscape/patches-5.4/701-net-0132-bus-fsl-mc-add-root-dprc-rescan-attribute.patch
new file mode 100644 (file)
index 0000000..76e5477
--- /dev/null
@@ -0,0 +1,100 @@
+From 64bd4f6f266110d908e51787a81ed0bc9d325941 Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Mon, 5 Mar 2018 18:37:32 +0200
+Subject: [PATCH] bus: fsl-mc: add root dprc rescan attribute
+
+Introduce the rescan attribute as a device attribute to
+synchronize the fsl-mc bus objects and the MC firmware.
+
+To rescan the root dprc only, e.g.
+echo 1 > /sys/bus/fsl-mc/devices/dprc.1/rescan
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+---
+ Documentation/ABI/stable/sysfs-bus-fsl-mc |  9 ++++++++
+ MAINTAINERS                               |  1 +
+ drivers/bus/fsl-mc/dprc-driver.c          | 36 +++++++++++++++++++++++++++++++
+ 3 files changed, 46 insertions(+)
+ create mode 100644 Documentation/ABI/stable/sysfs-bus-fsl-mc
+
+--- /dev/null
++++ b/Documentation/ABI/stable/sysfs-bus-fsl-mc
+@@ -0,0 +1,9 @@
++What:         /sys/bus/fsl-mc/devices/dprc.*/rescan
++Date:         November 2018
++KernelVersion:        5.0
++Contact:      Ioana Ciornei <ioana.ciornei@nxp.com>
++Description:  Writing a non-zero value to this attribute will
++              force a rescan of dprc.X container in the system and
++              synchronize the objects under dprc.X and the
++              Management Complex firmware.
++Users:                Userspace drivers and management tools
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -13438,6 +13438,7 @@ F:     Documentation/devicetree/bindings/mis
+ F:    Documentation/networking/device_drivers/freescale/dpaa2/overview.rst
+ F:    Documentation/networking/dpaa2/overview.rst
+ F:    include/uapi/linux/fsl_mc.h
++F:    Documentation/ABI/stable/sysfs-bus-fsl-mc
+ QT1010 MEDIA DRIVER
+ M:    Antti Palosaari <crope@iki.fi>
+--- a/drivers/bus/fsl-mc/dprc-driver.c
++++ b/drivers/bus/fsl-mc/dprc-driver.c
+@@ -354,6 +354,33 @@ static int dprc_scan_container(struct fs
+       return 0;
+ }
++static ssize_t rescan_store(struct device *dev,
++                          struct device_attribute *attr,
++                          const char *buf, size_t count)
++{
++      struct fsl_mc_device *root_mc_dev;
++      struct fsl_mc_bus *root_mc_bus;
++      unsigned long val;
++
++      if (!fsl_mc_is_root_dprc(dev))
++              return -EINVAL;
++
++      root_mc_dev = to_fsl_mc_device(dev);
++      root_mc_bus = to_fsl_mc_bus(root_mc_dev);
++
++      if (kstrtoul(buf, 0, &val) < 0)
++              return -EINVAL;
++
++      if (val) {
++              mutex_lock(&root_mc_bus->scan_mutex);
++              dprc_scan_objects(root_mc_dev, NULL);
++              mutex_unlock(&root_mc_bus->scan_mutex);
++      }
++
++      return count;
++}
++static DEVICE_ATTR_WO(rescan);
++
+ /**
+  * dprc_irq0_handler - Regular ISR for DPRC interrupt 0
+  *
+@@ -692,6 +719,13 @@ static int dprc_probe(struct fsl_mc_devi
+       mutex_init(&mc_bus->scan_mutex);
++      error = device_create_file(&mc_dev->dev, &dev_attr_rescan);
++      if (error < 0) {
++              dev_err(&mc_dev->dev, "device_create_file() failed: %d\n",
++                      error);
++              goto error_cleanup_open;
++      }
++
+       /*
+        * Discover MC objects in DPRC object:
+        */
+@@ -788,6 +822,8 @@ static int dprc_remove(struct fsl_mc_dev
+               fsl_mc_uapi_remove_device_file(mc_bus);
+       }
++      device_remove_file(&mc_dev->dev, &dev_attr_rescan);
++
+       dev_info(&mc_dev->dev, "DPRC device unbound from driver");
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0133-bus-fsl-mc-add-bus-rescan-attribute.patch b/target/linux/layerscape/patches-5.4/701-net-0133-bus-fsl-mc-add-bus-rescan-attribute.patch
new file mode 100644 (file)
index 0000000..ea22ddb
--- /dev/null
@@ -0,0 +1,115 @@
+From 4eba1e0209a52798e1b6a233840a28fc5132cd9c Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Mon, 5 Mar 2018 18:38:46 +0200
+Subject: [PATCH] bus: fsl-mc: add bus rescan attribute
+
+Introduce the rescan attribute as a bus attribute to
+synchronize the fsl-mc bus objects and the MC firmware.
+
+To rescan the fsl-mc bus, e.g.,
+echo 1 > /sys/bus/fsl-mc/rescan
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+---
+ Documentation/ABI/stable/sysfs-bus-fsl-mc | 10 ++++++++
+ drivers/bus/fsl-mc/dprc-driver.c          |  4 +--
+ drivers/bus/fsl-mc/fsl-mc-bus.c           | 41 +++++++++++++++++++++++++++++++
+ drivers/bus/fsl-mc/fsl-mc-private.h       |  2 ++
+ 4 files changed, 55 insertions(+), 2 deletions(-)
+
+--- a/Documentation/ABI/stable/sysfs-bus-fsl-mc
++++ b/Documentation/ABI/stable/sysfs-bus-fsl-mc
+@@ -7,3 +7,13 @@ Description:  Writing a non-zero value to
+               synchronize the objects under dprc.X and the
+               Management Complex firmware.
+ Users:                Userspace drivers and management tools
++
++What:         /sys/bus/fsl-mc/rescan
++Date:         November 2018
++KernelVersion:        5.0
++Contact:      Ioana Ciornei <ioana.ciornei@nxp.com>
++Description:  Writing a non-zero value to this attribute will
++              force a rescan of fsl-mc bus in the system and
++              synchronize the objects under fsl-mc bus and the
++              Management Complex firmware.
++Users:                Userspace drivers and management tools
+--- a/drivers/bus/fsl-mc/dprc-driver.c
++++ b/drivers/bus/fsl-mc/dprc-driver.c
+@@ -214,8 +214,8 @@ static void dprc_add_new_devices(struct
+  * populated before they can get allocation requests from probe callbacks
+  * of the device drivers for the non-allocatable devices.
+  */
+-static int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
+-                           unsigned int *total_irq_count)
++int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
++                    unsigned int *total_irq_count)
+ {
+       int num_child_objects;
+       int dprc_get_obj_failures;
+--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
+@@ -154,12 +154,53 @@ static struct attribute *fsl_mc_dev_attr
+ ATTRIBUTE_GROUPS(fsl_mc_dev);
++static int scan_fsl_mc_bus(struct device *dev, void *data)
++{
++      struct fsl_mc_device *root_mc_dev;
++      struct fsl_mc_bus *root_mc_bus;
++
++      if (!fsl_mc_is_root_dprc(dev))
++              goto exit;
++
++      root_mc_dev = to_fsl_mc_device(dev);
++      root_mc_bus = to_fsl_mc_bus(root_mc_dev);
++      mutex_lock(&root_mc_bus->scan_mutex);
++      dprc_scan_objects(root_mc_dev, NULL);
++      mutex_unlock(&root_mc_bus->scan_mutex);
++
++exit:
++      return 0;
++}
++
++static ssize_t rescan_store(struct bus_type *bus,
++                          const char *buf, size_t count)
++{
++      unsigned long val;
++
++      if (kstrtoul(buf, 0, &val) < 0)
++              return -EINVAL;
++
++      if (val)
++              bus_for_each_dev(bus, NULL, NULL, scan_fsl_mc_bus);
++
++      return count;
++}
++static BUS_ATTR_WO(rescan);
++
++static struct attribute *fsl_mc_bus_attrs[] = {
++      &bus_attr_rescan.attr,
++      NULL,
++};
++
++ATTRIBUTE_GROUPS(fsl_mc_bus);
++
+ struct bus_type fsl_mc_bus_type = {
+       .name = "fsl-mc",
+       .match = fsl_mc_bus_match,
+       .uevent = fsl_mc_bus_uevent,
+       .dma_configure  = fsl_mc_dma_configure,
+       .dev_groups = fsl_mc_dev_groups,
++      .bus_groups = fsl_mc_bus_groups,
+ };
+ EXPORT_SYMBOL_GPL(fsl_mc_bus_type);
+--- a/drivers/bus/fsl-mc/fsl-mc-private.h
++++ b/drivers/bus/fsl-mc/fsl-mc-private.h
+@@ -556,6 +556,8 @@ int __init dprc_driver_init(void);
+ void dprc_driver_exit(void);
++int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
++                    unsigned int *total_irq_count);
+ int __init fsl_mc_allocator_driver_init(void);
+ void fsl_mc_allocator_driver_exit(void);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0134-bus-fsl-mc-Add-dprc-reset-container-support.patch b/target/linux/layerscape/patches-5.4/701-net-0134-bus-fsl-mc-Add-dprc-reset-container-support.patch
new file mode 100644 (file)
index 0000000..a609905
--- /dev/null
@@ -0,0 +1,99 @@
+From 350201cc09a58dcf5c49f636238b01637f5ee06d Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Fri, 13 Apr 2018 11:35:10 +0300
+Subject: [PATCH] bus: fsl-mc: Add dprc-reset-container support
+
+DPRC-reset is required for VFIO and is missing from
+mc-bus support.
+This patch added reset-container support.
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ drivers/bus/fsl-mc/dprc.c           | 41 +++++++++++++++++++++++++++++++++++++
+ drivers/bus/fsl-mc/fsl-mc-private.h | 10 +++++++++
+ 2 files changed, 51 insertions(+)
+
+--- a/drivers/bus/fsl-mc/dprc.c
++++ b/drivers/bus/fsl-mc/dprc.c
+@@ -73,6 +73,47 @@ int dprc_close(struct fsl_mc_io *mc_io,
+ EXPORT_SYMBOL_GPL(dprc_close);
+ /**
++ * dprc_reset_container - Reset child container.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPRC object
++ * @child_container_id:       ID of the container to reset
++ *
++ * In case a software context crashes or becomes non-responsive, the parent
++ * may wish to reset its resources container before the software context is
++ * restarted.
++ *
++ * This routine informs all objects assigned to the child container that the
++ * container is being reset, so they may perform any cleanup operations that are
++ * needed. All objects handles that were owned by the child container shall be
++ * closed.
++ *
++ * Note that such request may be submitted even if the child software context
++ * has not crashed, but the resulting object cleanup operations will not be
++ * aware of that.
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dprc_reset_container(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token,
++                       int child_container_id)
++{
++      struct fsl_mc_command cmd = { 0 };
++      struct dprc_cmd_reset_container *cmd_params;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPRC_CMDID_RESET_CONT,
++                                        cmd_flags, token);
++      cmd_params = (struct dprc_cmd_reset_container *)cmd.params;
++      cmd_params->child_container_id = cpu_to_le32(child_container_id);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++EXPORT_SYMBOL_GPL(dprc_reset_container);
++
++/**
+  * dprc_set_irq() - Set IRQ information for the DPRC to trigger an interrupt.
+  * @mc_io:    Pointer to MC portal's I/O object
+  * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
+--- a/drivers/bus/fsl-mc/fsl-mc-private.h
++++ b/drivers/bus/fsl-mc/fsl-mc-private.h
+@@ -93,6 +93,7 @@ int dpmcp_reset(struct fsl_mc_io *mc_io,
+ #define DPRC_CMDID_GET_API_VERSION              DPRC_CMD(0xa05)
+ #define DPRC_CMDID_GET_ATTR                     DPRC_CMD(0x004)
++#define DPRC_CMDID_RESET_CONT                   DPRC_CMD(0x005)
+ #define DPRC_CMDID_SET_IRQ                      DPRC_CMD(0x010)
+ #define DPRC_CMDID_SET_IRQ_ENABLE               DPRC_CMD(0x012)
+@@ -111,6 +112,10 @@ struct dprc_cmd_open {
+       __le32 container_id;
+ };
++struct dprc_cmd_reset_container {
++      __le32 child_container_id;
++};
++
+ struct dprc_cmd_set_irq {
+       /* cmd word 0 */
+       __le32 irq_val;
+@@ -394,6 +399,11 @@ int dprc_get_container_id(struct fsl_mc_
+                         u32 cmd_flags,
+                         int *container_id);
++int dprc_reset_container(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token,
++                       int child_container_id);
++
+ /*
+  * Data Path Buffer Pool (DPBP) API
+  */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0135-bus-fsl-mc-Propagate-driver_override-for-a-child-DPR.patch b/target/linux/layerscape/patches-5.4/701-net-0135-bus-fsl-mc-Propagate-driver_override-for-a-child-DPR.patch
new file mode 100644 (file)
index 0000000..b750c72
--- /dev/null
@@ -0,0 +1,196 @@
+From ab5ad879bf30318213a717ab50944b5590bc09c1 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Fri, 13 Apr 2018 11:52:44 +0300
+Subject: [PATCH] bus: fsl-mc: Propagate driver_override for a child DPRC's
+ children
+
+When a child DPRC is bound to the vfio_fsl_mc driver via
+driver_override, its own children should not be bound to corresponding
+host kernel drivers, but instead should be bound to the vfio_fsl_mc
+driver as well.
+
+Currently, when a child container is scanned by the vfio_fsl_mc
+driver, child devices found are automatically bound to corresponding
+host kernel drivers (e.g., DPMCP and DPBP objects are bound to the
+fsl_mc_allocator driver, DPNI objects are bound to the ldpaa_eth
+driver, etc), Then, the user has to manually unbind these child
+devices from their drivers, set the driver_override sysfs attribute
+to vfio_fsl_mc driver, for each of them and rebind them.
+
+Signed-off-by: J. German Rivera <German.Rivera@freescale.com>
+Signed-off-by: Stuart Yoder <stuart.yoder@nxp.com>
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ drivers/bus/fsl-mc/dprc-driver.c    | 16 +++++++++++-----
+ drivers/bus/fsl-mc/fsl-mc-bus.c     | 19 +++++++++++++++++--
+ drivers/bus/fsl-mc/fsl-mc-private.h |  2 ++
+ include/linux/fsl/mc.h              |  2 ++
+ 4 files changed, 32 insertions(+), 7 deletions(-)
+
+--- a/drivers/bus/fsl-mc/dprc-driver.c
++++ b/drivers/bus/fsl-mc/dprc-driver.c
+@@ -156,6 +156,8 @@ static void check_plugged_state_change(s
+  * dprc_add_new_devices - Adds devices to the logical bus for a DPRC
+  *
+  * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
++ * @driver_override: driver override to apply to new objects found in the
++ * DPRC, or NULL, if none.
+  * @obj_desc_array: array of device descriptors for child devices currently
+  * present in the physical DPRC.
+  * @num_child_objects_in_mc: number of entries in obj_desc_array
+@@ -165,6 +167,7 @@ static void check_plugged_state_change(s
+  * in the physical DPRC.
+  */
+ static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev,
++                               const char *driver_override,
+                                struct fsl_mc_obj_desc *obj_desc_array,
+                                int num_child_objects_in_mc)
+ {
+@@ -189,7 +192,7 @@ static void dprc_add_new_devices(struct
+               }
+               error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev,
+-                                        &child_dev);
++                                        driver_override, &child_dev);
+               if (error < 0)
+                       continue;
+       }
+@@ -199,6 +202,8 @@ static void dprc_add_new_devices(struct
+  * dprc_scan_objects - Discover objects in a DPRC
+  *
+  * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
++ * @driver_override: driver override to apply to new objects found in the
++ * DPRC, or NULL, if none.
+  * @total_irq_count: If argument is provided the function populates the
+  * total number of IRQs created by objects in the DPRC.
+  *
+@@ -215,6 +220,7 @@ static void dprc_add_new_devices(struct
+  * of the device drivers for the non-allocatable devices.
+  */
+ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
++                    const char *driver_override,
+                     unsigned int *total_irq_count)
+ {
+       int num_child_objects;
+@@ -315,7 +321,7 @@ int dprc_scan_objects(struct fsl_mc_devi
+       dprc_remove_devices(mc_bus_dev, child_obj_desc_array,
+                           num_child_objects);
+-      dprc_add_new_devices(mc_bus_dev, child_obj_desc_array,
++      dprc_add_new_devices(mc_bus_dev, driver_override, child_obj_desc_array,
+                            num_child_objects);
+       if (child_obj_desc_array)
+@@ -344,7 +350,7 @@ static int dprc_scan_container(struct fs
+        * Discover objects in the DPRC:
+        */
+       mutex_lock(&mc_bus->scan_mutex);
+-      error = dprc_scan_objects(mc_bus_dev, NULL);
++      error = dprc_scan_objects(mc_bus_dev, NULL, NULL);
+       mutex_unlock(&mc_bus->scan_mutex);
+       if (error < 0) {
+               fsl_mc_cleanup_all_resource_pools(mc_bus_dev);
+@@ -373,7 +379,7 @@ static ssize_t rescan_store(struct devic
+       if (val) {
+               mutex_lock(&root_mc_bus->scan_mutex);
+-              dprc_scan_objects(root_mc_dev, NULL);
++              dprc_scan_objects(root_mc_dev, NULL, NULL);
+               mutex_unlock(&root_mc_bus->scan_mutex);
+       }
+@@ -442,7 +448,7 @@ static irqreturn_t dprc_irq0_handler_thr
+                     DPRC_IRQ_EVENT_OBJ_CREATED)) {
+               unsigned int irq_count;
+-              error = dprc_scan_objects(mc_dev, &irq_count);
++              error = dprc_scan_objects(mc_dev, NULL, &irq_count);
+               if (error < 0) {
+                       /*
+                        * If the error is -ENXIO, we ignore it, as it indicates
+--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
+@@ -165,7 +165,7 @@ static int scan_fsl_mc_bus(struct device
+       root_mc_dev = to_fsl_mc_device(dev);
+       root_mc_bus = to_fsl_mc_bus(root_mc_dev);
+       mutex_lock(&root_mc_bus->scan_mutex);
+-      dprc_scan_objects(root_mc_dev, NULL);
++      dprc_scan_objects(root_mc_dev, NULL, NULL);
+       mutex_unlock(&root_mc_bus->scan_mutex);
+ exit:
+@@ -597,6 +597,7 @@ static void fsl_mc_device_release(struct
+ int fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc,
+                     struct fsl_mc_io *mc_io,
+                     struct device *parent_dev,
++                    const char *driver_override,
+                     struct fsl_mc_device **new_mc_dev)
+ {
+       int error;
+@@ -629,6 +630,19 @@ int fsl_mc_device_add(struct fsl_mc_obj_
+       mc_dev->obj_desc = *obj_desc;
+       mc_dev->mc_io = mc_io;
++
++      if (driver_override) {
++              /*
++               * We trust driver_override, so we don't need to use
++               * kstrndup() here
++               */
++              mc_dev->driver_override = kstrdup(driver_override, GFP_KERNEL);
++              if (!mc_dev->driver_override) {
++                      error = -ENOMEM;
++                      goto error_cleanup_dev;
++              }
++      }
++
+       device_initialize(&mc_dev->dev);
+       mc_dev->dev.parent = parent_dev;
+       mc_dev->dev.bus = &fsl_mc_bus_type;
+@@ -924,7 +938,8 @@ static int fsl_mc_bus_probe(struct platf
+       obj_desc.irq_count = 1;
+       obj_desc.region_count = 0;
+-      error = fsl_mc_device_add(&obj_desc, mc_io, &pdev->dev, &mc_bus_dev);
++      error = fsl_mc_device_add(&obj_desc, mc_io, &pdev->dev, NULL,
++                               &mc_bus_dev);
+       if (error < 0)
+               goto error_cleanup_mc_io;
+--- a/drivers/bus/fsl-mc/fsl-mc-private.h
++++ b/drivers/bus/fsl-mc/fsl-mc-private.h
+@@ -558,6 +558,7 @@ struct fsl_mc_bus {
+ int __must_check fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc,
+                                  struct fsl_mc_io *mc_io,
+                                  struct device *parent_dev,
++                                 const char *driver_override,
+                                  struct fsl_mc_device **new_mc_dev);
+ void fsl_mc_device_remove(struct fsl_mc_device *mc_dev);
+@@ -567,6 +568,7 @@ int __init dprc_driver_init(void);
+ void dprc_driver_exit(void);
+ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
++                    const char *driver_override,
+                     unsigned int *total_irq_count);
+ int __init fsl_mc_allocator_driver_init(void);
+--- a/include/linux/fsl/mc.h
++++ b/include/linux/fsl/mc.h
+@@ -162,6 +162,7 @@ struct fsl_mc_obj_desc {
+  * @regions: pointer to array of MMIO region entries
+  * @irqs: pointer to array of pointers to interrupts allocated to this device
+  * @resource: generic resource associated with this MC object device, if any.
++ * @driver_override: Driver name to force a match
+  *
+  * Generic device object for MC object devices that are "attached" to a
+  * MC bus.
+@@ -195,6 +196,7 @@ struct fsl_mc_device {
+       struct fsl_mc_device_irq **irqs;
+       struct fsl_mc_resource *resource;
+       struct device_link *consumer_link;
++      const char *driver_override;
+ };
+ #define to_fsl_mc_device(_dev) \
diff --git a/target/linux/layerscape/patches-5.4/701-net-0136-bus-fsl-mc-add-device-binding-path-driver_override.patch b/target/linux/layerscape/patches-5.4/701-net-0136-bus-fsl-mc-add-device-binding-path-driver_override.patch
new file mode 100644 (file)
index 0000000..23a0e9b
--- /dev/null
@@ -0,0 +1,106 @@
+From f2991d30ff590bf932483a6dfc16c7ebe2f83341 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Fri, 13 Apr 2018 12:42:40 +0300
+Subject: [PATCH] bus: fsl-mc: add device binding path 'driver_override'
+
+This patch is required for vfio-fsl-mc meta driver to successfully bind
+layerscape container devices for device passthrough. This patch adds
+a mechanism to allow a layerscape device to specify a driver rather than
+a layerscape driver provide a device match.
+
+This patch is based on following proposed patches for PCI and platform
+devices
+- https://lkml.org/lkml/2014/4/8/571  :- For Platform devices
+- http://lists-archives.com/linux-kernel/28030441-pci-introduce-new-device-binding-path-using-pci_dev-driver_override.html
+:- For PCI devices
+
+Example to allow a device (dprc.1) to specifically bind
+with driver (vfio-fsl-mc):-
+ - echo vfio-fsl-mc > /sys/bus/fsl-mc/devices/dprc.1/driver_override
+ - echo dprc.1 > /sys/bus/fsl-mc/drivers/fsl_mc_dprc/unbind
+ - echo dprc.1 > /sys/bus/fsl-mc/drivers/vfio-fsl-mc/bind
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ drivers/bus/fsl-mc/fsl-mc-bus.c | 53 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 53 insertions(+)
+
+--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
+@@ -83,6 +83,12 @@ static int fsl_mc_bus_match(struct devic
+       struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv);
+       bool found = false;
++      /* When driver_override is set, only bind to the matching driver */
++      if (mc_dev->driver_override) {
++              found = !strcmp(mc_dev->driver_override, mc_drv->driver.name);
++              goto out;
++      }
++
+       if (!mc_drv->match_id_table)
+               goto out;
+@@ -147,8 +153,52 @@ static ssize_t modalias_show(struct devi
+ }
+ static DEVICE_ATTR_RO(modalias);
++static ssize_t driver_override_store(struct device *dev,
++                                   struct device_attribute *attr,
++                                   const char *buf, size_t count)
++{
++      struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
++      const char *driver_override, *old = mc_dev->driver_override;
++      char *cp;
++
++      if (WARN_ON(dev->bus != &fsl_mc_bus_type))
++              return -EINVAL;
++
++      if (count >= (PAGE_SIZE - 1))
++              return -EINVAL;
++
++      driver_override = kstrndup(buf, count, GFP_KERNEL);
++      if (!driver_override)
++              return -ENOMEM;
++
++      cp = strchr(driver_override, '\n');
++      if (cp)
++              *cp = '\0';
++
++      if (strlen(driver_override)) {
++              mc_dev->driver_override = driver_override;
++      } else {
++              kfree(driver_override);
++              mc_dev->driver_override = NULL;
++      }
++
++      kfree(old);
++
++      return count;
++}
++
++static ssize_t driver_override_show(struct device *dev,
++                                  struct device_attribute *attr, char *buf)
++{
++      struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
++
++      return snprintf(buf, PAGE_SIZE, "%s\n", mc_dev->driver_override);
++}
++static DEVICE_ATTR_RW(driver_override);
++
+ static struct attribute *fsl_mc_dev_attrs[] = {
+       &dev_attr_modalias.attr,
++      &dev_attr_driver_override.attr,
+       NULL,
+ };
+@@ -749,6 +799,9 @@ EXPORT_SYMBOL_GPL(fsl_mc_device_add);
+  */
+ void fsl_mc_device_remove(struct fsl_mc_device *mc_dev)
+ {
++      kfree(mc_dev->driver_override);
++      mc_dev->driver_override = NULL;
++
+       /*
+        * The device-specific remove callback will get invoked by device_del()
+        */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0137-bus-fsl-mc-move-fsl_mc_device_remove-to-common-heade.patch b/target/linux/layerscape/patches-5.4/701-net-0137-bus-fsl-mc-move-fsl_mc_device_remove-to-common-heade.patch
new file mode 100644 (file)
index 0000000..8153648
--- /dev/null
@@ -0,0 +1,37 @@
+From b5beccaa8629e69acbae8332e84532958e1f24cc Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Fri, 13 Apr 2018 13:25:04 +0300
+Subject: [PATCH] bus: fsl-mc: move fsl_mc_device_remove to common header
+
+VFIO fsl-mc driver need this function on device remove,
+moving this to common header file
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ drivers/bus/fsl-mc/fsl-mc-private.h | 2 --
+ include/linux/fsl/mc.h              | 2 ++
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/bus/fsl-mc/fsl-mc-private.h
++++ b/drivers/bus/fsl-mc/fsl-mc-private.h
+@@ -561,8 +561,6 @@ int __must_check fsl_mc_device_add(struc
+                                  const char *driver_override,
+                                  struct fsl_mc_device **new_mc_dev);
+-void fsl_mc_device_remove(struct fsl_mc_device *mc_dev);
+-
+ int __init dprc_driver_init(void);
+ void dprc_driver_exit(void);
+--- a/include/linux/fsl/mc.h
++++ b/include/linux/fsl/mc.h
+@@ -366,6 +366,8 @@ int mc_send_command(struct fsl_mc_io *mc
+       module_driver(__fsl_mc_driver, fsl_mc_driver_register, \
+                     fsl_mc_driver_unregister)
++void fsl_mc_device_remove(struct fsl_mc_device *mc_dev);
++
+ /*
+  * Macro to avoid include chaining to get THIS_MODULE
+  */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0138-bus-fsl-mc-increase-MC_CMD_COMPLETION_TIMEOUT_MS-val.patch b/target/linux/layerscape/patches-5.4/701-net-0138-bus-fsl-mc-increase-MC_CMD_COMPLETION_TIMEOUT_MS-val.patch
new file mode 100644 (file)
index 0000000..2bf3b15
--- /dev/null
@@ -0,0 +1,27 @@
+From a41f550c0252dc24892b463212379c41b1e10fec Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Fri, 13 Apr 2018 13:27:31 +0300
+Subject: [PATCH] bus: fsl-mc: increase MC_CMD_COMPLETION_TIMEOUT_MS value to
+ 15s
+
+With recent MC release, a timeout of 500ms is not enough in most
+circumstances. If MC firmware will respond faster, we should
+decrease this value.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ drivers/bus/fsl-mc/mc-sys.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/bus/fsl-mc/mc-sys.c
++++ b/drivers/bus/fsl-mc/mc-sys.c
+@@ -19,7 +19,7 @@
+ /**
+  * Timeout in milliseconds to wait for the completion of an MC command
+  */
+-#define MC_CMD_COMPLETION_TIMEOUT_MS  500
++#define MC_CMD_COMPLETION_TIMEOUT_MS  15000
+ /*
+  * usleep_range() min and max values used to throttle down polling
diff --git a/target/linux/layerscape/patches-5.4/701-net-0139-bus-fsl-mc-added-missing-fields-to-dprc_rsp_get_obj_.patch b/target/linux/layerscape/patches-5.4/701-net-0139-bus-fsl-mc-added-missing-fields-to-dprc_rsp_get_obj_.patch
new file mode 100644 (file)
index 0000000..cfadd79
--- /dev/null
@@ -0,0 +1,46 @@
+From 7c72e64115a9145df5b8faf2182ef17b065261a9 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Fri, 13 Apr 2018 15:04:45 +0300
+Subject: [PATCH] bus: fsl-mc: added missing fields to dprc_rsp_get_obj_region
+ structure
+
+'type' and 'flags' fields were missing from dprc_rsp_get_obj_region
+structure therefore the MC Bus driver was not receiving proper flags
+from MC like DPRC_REGION_CACHEABLE.
+
+Signed-off-by: Cristian Sovaiala <cristian.sovaiala@freescale.com>
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ drivers/bus/fsl-mc/dprc.c           | 2 ++
+ drivers/bus/fsl-mc/fsl-mc-private.h | 5 +++--
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/bus/fsl-mc/dprc.c
++++ b/drivers/bus/fsl-mc/dprc.c
+@@ -524,6 +524,8 @@ int dprc_get_obj_region(struct fsl_mc_io
+       rsp_params = (struct dprc_rsp_get_obj_region *)cmd.params;
+       region_desc->base_offset = le64_to_cpu(rsp_params->base_offset);
+       region_desc->size = le32_to_cpu(rsp_params->size);
++      region_desc->type = rsp_params->type;
++      region_desc->flags = le32_to_cpu(rsp_params->flags);
+       if (major_ver > 6 || (major_ver == 6 && minor_ver >= 3))
+               region_desc->base_address = le64_to_cpu(rsp_params->base_addr);
+       else
+--- a/drivers/bus/fsl-mc/fsl-mc-private.h
++++ b/drivers/bus/fsl-mc/fsl-mc-private.h
+@@ -207,12 +207,13 @@ struct dprc_cmd_get_obj_region {
+ struct dprc_rsp_get_obj_region {
+       /* response word 0 */
+-      __le64 pad;
++      __le64 pad0;
+       /* response word 1 */
+       __le64 base_offset;
+       /* response word 2 */
+       __le32 size;
+-      __le32 pad2;
++      u8 type;
++      u8 pad2[3];
+       /* response word 3 */
+       __le32 flags;
+       __le32 pad3;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0140-bus-fsl-mc-define-macros-for-iommu-enablement-for-fs.patch b/target/linux/layerscape/patches-5.4/701-net-0140-bus-fsl-mc-define-macros-for-iommu-enablement-for-fs.patch
new file mode 100644 (file)
index 0000000..b29ae07
--- /dev/null
@@ -0,0 +1,29 @@
+From e6c39c2219f9d308ea57c09fc1b0b5b151b52b7d Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Mon, 16 Apr 2018 11:33:11 +0300
+Subject: [PATCH] bus: fsl-mc: define macros for iommu enablement for fsl-mc
+ bus
+
+Macros to get coherency and the container device of the devices on
+fsl-mc bus are required to suport SMMU for this bus. This patch
+defines the same.
+
+Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ include/linux/fsl/mc.h | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/include/linux/fsl/mc.h
++++ b/include/linux/fsl/mc.h
+@@ -356,6 +356,10 @@ int mc_send_command(struct fsl_mc_io *mc
+ #define fsl_mc_cont_dev(_dev) (fsl_mc_is_cont_dev(_dev) ? \
+       (_dev) : (_dev)->parent)
++#define fsl_mc_is_dev_coherent(_dev) \
++      (!((to_fsl_mc_device(_dev))->obj_desc.flags & \
++      FSL_MC_OBJ_FLAG_NO_MEM_SHAREABILITY))
++
+ /*
+  * module_fsl_mc_driver() - Helper macro for drivers that don't do
+  * anything special in module init/exit.  This eliminates a lot of
diff --git a/target/linux/layerscape/patches-5.4/701-net-0141-bus-fsl-mc-Extend-ICID-size-from-16bit-to-32bit.patch b/target/linux/layerscape/patches-5.4/701-net-0141-bus-fsl-mc-Extend-ICID-size-from-16bit-to-32bit.patch
new file mode 100644 (file)
index 0000000..c7d25f5
--- /dev/null
@@ -0,0 +1,73 @@
+From 7c5fca3084c38905df08b8f33cf14ad21ab41b77 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Mon, 16 Apr 2018 11:54:46 +0300
+Subject: [PATCH] bus: fsl-mc: Extend ICID size from 16bit to 32bit
+
+Extend the ICID from 16-bit to 32-bit.
+Primary reason for this is enabling DPAA2 drivers
+in Virtual Machine where device-id range is defined
+for DPAA2 devices is 0x10000-0x20000.
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ drivers/bus/fsl-mc/dprc.c           | 2 +-
+ drivers/bus/fsl-mc/fsl-mc-bus.c     | 2 +-
+ drivers/bus/fsl-mc/fsl-mc-private.h | 5 ++---
+ include/linux/fsl/mc.h              | 2 +-
+ 4 files changed, 5 insertions(+), 6 deletions(-)
+
+--- a/drivers/bus/fsl-mc/dprc.c
++++ b/drivers/bus/fsl-mc/dprc.c
+@@ -322,7 +322,7 @@ int dprc_get_attributes(struct fsl_mc_io
+       /* retrieve response parameters */
+       rsp_params = (struct dprc_rsp_get_attributes *)cmd.params;
+       attr->container_id = le32_to_cpu(rsp_params->container_id);
+-      attr->icid = le16_to_cpu(rsp_params->icid);
++      attr->icid = le32_to_cpu(rsp_params->icid);
+       attr->options = le32_to_cpu(rsp_params->options);
+       attr->portal_id = le32_to_cpu(rsp_params->portal_id);
+--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
+@@ -489,7 +489,7 @@ common_cleanup:
+ }
+ static int get_dprc_icid(struct fsl_mc_io *mc_io,
+-                       int container_id, u16 *icid)
++                       int container_id, u32 *icid)
+ {
+       struct dprc_attributes attr;
+       int error;
+--- a/drivers/bus/fsl-mc/fsl-mc-private.h
++++ b/drivers/bus/fsl-mc/fsl-mc-private.h
+@@ -157,8 +157,7 @@ struct dprc_cmd_clear_irq_status {
+ struct dprc_rsp_get_attributes {
+       /* response word 0 */
+       __le32 container_id;
+-      __le16 icid;
+-      __le16 pad;
++      __le32 icid;
+       /* response word 1 */
+       __le32 options;
+       __le32 portal_id;
+@@ -320,7 +319,7 @@ int dprc_clear_irq_status(struct fsl_mc_
+  */
+ struct dprc_attributes {
+       int container_id;
+-      u16 icid;
++      u32 icid;
+       int portal_id;
+       u64 options;
+ };
+--- a/include/linux/fsl/mc.h
++++ b/include/linux/fsl/mc.h
+@@ -188,7 +188,7 @@ struct fsl_mc_device {
+       struct device dev;
+       u64 dma_mask;
+       u16 flags;
+-      u16 icid;
++      u32 icid;
+       u16 mc_handle;
+       struct fsl_mc_io *mc_io;
+       struct fsl_mc_obj_desc obj_desc;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0142-bus-fsl-mc-Some-apis-are-made-public-for-vfio.patch b/target/linux/layerscape/patches-5.4/701-net-0142-bus-fsl-mc-Some-apis-are-made-public-for-vfio.patch
new file mode 100644 (file)
index 0000000..404ea7e
--- /dev/null
@@ -0,0 +1,960 @@
+From e8dd5b8ee227cc60f10073faaa0f74b36aa4f40f Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Mon, 16 Apr 2018 12:26:38 +0300
+Subject: [PATCH] bus: fsl-mc: Some apis are made public for vfio
+
+Some of the APIs and data-structures are required for VFIO.
+This patch moves dprc.h to public header files.
+Also some APIs of mc-bus are made public for vfio.
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ drivers/bus/fsl-mc/fsl-mc-allocator.c |   2 +
+ drivers/bus/fsl-mc/fsl-mc-bus.c       |   5 +-
+ drivers/bus/fsl-mc/fsl-mc-private.h   | 414 ---------------------------------
+ include/linux/fsl/mc.h                | 420 ++++++++++++++++++++++++++++++++++
+ 4 files changed, 425 insertions(+), 416 deletions(-)
+
+--- a/drivers/bus/fsl-mc/fsl-mc-allocator.c
++++ b/drivers/bus/fsl-mc/fsl-mc-allocator.c
+@@ -547,6 +547,7 @@ void fsl_mc_init_all_resource_pools(stru
+               mutex_init(&res_pool->mutex);
+       }
+ }
++EXPORT_SYMBOL_GPL(fsl_mc_init_all_resource_pools);
+ static void fsl_mc_cleanup_resource_pool(struct fsl_mc_device *mc_bus_dev,
+                                        enum fsl_mc_pool_type pool_type)
+@@ -571,6 +572,7 @@ void fsl_mc_cleanup_all_resource_pools(s
+       for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++)
+               fsl_mc_cleanup_resource_pool(mc_bus_dev, pool_type);
+ }
++EXPORT_SYMBOL_GPL(fsl_mc_cleanup_all_resource_pools);
+ /**
+  * fsl_mc_allocator_probe - callback invoked when an allocatable device is
+--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
+@@ -447,8 +447,8 @@ static int mc_get_version(struct fsl_mc_
+ /**
+  * fsl_mc_get_root_dprc - function to traverse to the root dprc
+  */
+-static void fsl_mc_get_root_dprc(struct device *dev,
+-                               struct device **root_dprc_dev)
++void fsl_mc_get_root_dprc(struct device *dev,
++                        struct device **root_dprc_dev)
+ {
+       if (!dev) {
+               *root_dprc_dev = NULL;
+@@ -460,6 +460,7 @@ static void fsl_mc_get_root_dprc(struct
+                       *root_dprc_dev = (*root_dprc_dev)->parent;
+       }
+ }
++EXPORT_SYMBOL_GPL(fsl_mc_get_root_dprc);
+ static int get_dprc_attr(struct fsl_mc_io *mc_io,
+                        int container_id, struct dprc_attributes *attr)
+--- a/drivers/bus/fsl-mc/fsl-mc-private.h
++++ b/drivers/bus/fsl-mc/fsl-mc-private.h
+@@ -10,8 +10,6 @@
+ #include <linux/fsl/mc.h>
+ #include <linux/mutex.h>
+-#include <linux/ioctl.h>
+-#include <linux/miscdevice.h>
+ /*
+  * Data Path Management Complex (DPMNG) General API
+@@ -72,339 +70,6 @@ int dpmcp_reset(struct fsl_mc_io *mc_io,
+               u16 token);
+ /*
+- * Data Path Resource Container (DPRC) API
+- */
+-
+-/* Minimal supported DPRC Version */
+-#define DPRC_MIN_VER_MAJOR                    6
+-#define DPRC_MIN_VER_MINOR                    0
+-
+-/* DPRC command versioning */
+-#define DPRC_CMD_BASE_VERSION                 1
+-#define DPRC_CMD_2ND_VERSION                  2
+-#define DPRC_CMD_ID_OFFSET                    4
+-
+-#define DPRC_CMD(id)  (((id) << DPRC_CMD_ID_OFFSET) | DPRC_CMD_BASE_VERSION)
+-#define DPRC_CMD_V2(id)       (((id) << DPRC_CMD_ID_OFFSET) | DPRC_CMD_2ND_VERSION)
+-
+-/* DPRC command IDs */
+-#define DPRC_CMDID_CLOSE                        DPRC_CMD(0x800)
+-#define DPRC_CMDID_OPEN                         DPRC_CMD(0x805)
+-#define DPRC_CMDID_GET_API_VERSION              DPRC_CMD(0xa05)
+-
+-#define DPRC_CMDID_GET_ATTR                     DPRC_CMD(0x004)
+-#define DPRC_CMDID_RESET_CONT                   DPRC_CMD(0x005)
+-
+-#define DPRC_CMDID_SET_IRQ                      DPRC_CMD(0x010)
+-#define DPRC_CMDID_SET_IRQ_ENABLE               DPRC_CMD(0x012)
+-#define DPRC_CMDID_SET_IRQ_MASK                 DPRC_CMD(0x014)
+-#define DPRC_CMDID_GET_IRQ_STATUS               DPRC_CMD(0x016)
+-#define DPRC_CMDID_CLEAR_IRQ_STATUS             DPRC_CMD(0x017)
+-
+-#define DPRC_CMDID_GET_CONT_ID                  DPRC_CMD(0x830)
+-#define DPRC_CMDID_GET_OBJ_COUNT                DPRC_CMD(0x159)
+-#define DPRC_CMDID_GET_OBJ                      DPRC_CMD(0x15A)
+-#define DPRC_CMDID_GET_OBJ_REG                  DPRC_CMD(0x15E)
+-#define DPRC_CMDID_GET_OBJ_REG_V2               DPRC_CMD_V2(0x15E)
+-#define DPRC_CMDID_SET_OBJ_IRQ                  DPRC_CMD(0x15F)
+-
+-struct dprc_cmd_open {
+-      __le32 container_id;
+-};
+-
+-struct dprc_cmd_reset_container {
+-      __le32 child_container_id;
+-};
+-
+-struct dprc_cmd_set_irq {
+-      /* cmd word 0 */
+-      __le32 irq_val;
+-      u8 irq_index;
+-      u8 pad[3];
+-      /* cmd word 1 */
+-      __le64 irq_addr;
+-      /* cmd word 2 */
+-      __le32 irq_num;
+-};
+-
+-#define DPRC_ENABLE           0x1
+-
+-struct dprc_cmd_set_irq_enable {
+-      u8 enable;
+-      u8 pad[3];
+-      u8 irq_index;
+-};
+-
+-struct dprc_cmd_set_irq_mask {
+-      __le32 mask;
+-      u8 irq_index;
+-};
+-
+-struct dprc_cmd_get_irq_status {
+-      __le32 status;
+-      u8 irq_index;
+-};
+-
+-struct dprc_rsp_get_irq_status {
+-      __le32 status;
+-};
+-
+-struct dprc_cmd_clear_irq_status {
+-      __le32 status;
+-      u8 irq_index;
+-};
+-
+-struct dprc_rsp_get_attributes {
+-      /* response word 0 */
+-      __le32 container_id;
+-      __le32 icid;
+-      /* response word 1 */
+-      __le32 options;
+-      __le32 portal_id;
+-};
+-
+-struct dprc_rsp_get_obj_count {
+-      __le32 pad;
+-      __le32 obj_count;
+-};
+-
+-struct dprc_cmd_get_obj {
+-      __le32 obj_index;
+-};
+-
+-struct dprc_rsp_get_obj {
+-      /* response word 0 */
+-      __le32 pad0;
+-      __le32 id;
+-      /* response word 1 */
+-      __le16 vendor;
+-      u8 irq_count;
+-      u8 region_count;
+-      __le32 state;
+-      /* response word 2 */
+-      __le16 version_major;
+-      __le16 version_minor;
+-      __le16 flags;
+-      __le16 pad1;
+-      /* response word 3-4 */
+-      u8 type[16];
+-      /* response word 5-6 */
+-      u8 label[16];
+-};
+-
+-struct dprc_cmd_get_obj_region {
+-      /* cmd word 0 */
+-      __le32 obj_id;
+-      __le16 pad0;
+-      u8 region_index;
+-      u8 pad1;
+-      /* cmd word 1-2 */
+-      __le64 pad2[2];
+-      /* cmd word 3-4 */
+-      u8 obj_type[16];
+-};
+-
+-struct dprc_rsp_get_obj_region {
+-      /* response word 0 */
+-      __le64 pad0;
+-      /* response word 1 */
+-      __le64 base_offset;
+-      /* response word 2 */
+-      __le32 size;
+-      u8 type;
+-      u8 pad2[3];
+-      /* response word 3 */
+-      __le32 flags;
+-      __le32 pad3;
+-      /* response word 4 */
+-      /* base_addr may be zero if older MC firmware is used */
+-      __le64 base_addr;
+-};
+-
+-struct dprc_cmd_set_obj_irq {
+-      /* cmd word 0 */
+-      __le32 irq_val;
+-      u8 irq_index;
+-      u8 pad[3];
+-      /* cmd word 1 */
+-      __le64 irq_addr;
+-      /* cmd word 2 */
+-      __le32 irq_num;
+-      __le32 obj_id;
+-      /* cmd word 3-4 */
+-      u8 obj_type[16];
+-};
+-
+-/*
+- * DPRC API for managing and querying DPAA resources
+- */
+-int dprc_open(struct fsl_mc_io *mc_io,
+-            u32 cmd_flags,
+-            int container_id,
+-            u16 *token);
+-
+-int dprc_close(struct fsl_mc_io *mc_io,
+-             u32 cmd_flags,
+-             u16 token);
+-
+-/* DPRC IRQ events */
+-
+-/* IRQ event - Indicates that a new object added to the container */
+-#define DPRC_IRQ_EVENT_OBJ_ADDED              0x00000001
+-/* IRQ event - Indicates that an object was removed from the container */
+-#define DPRC_IRQ_EVENT_OBJ_REMOVED            0x00000002
+-/*
+- * IRQ event - Indicates that one of the descendant containers that opened by
+- * this container is destroyed
+- */
+-#define DPRC_IRQ_EVENT_CONTAINER_DESTROYED    0x00000010
+-
+-/*
+- * IRQ event - Indicates that on one of the container's opened object is
+- * destroyed
+- */
+-#define DPRC_IRQ_EVENT_OBJ_DESTROYED          0x00000020
+-
+-/* Irq event - Indicates that object is created at the container */
+-#define DPRC_IRQ_EVENT_OBJ_CREATED            0x00000040
+-
+-/**
+- * struct dprc_irq_cfg - IRQ configuration
+- * @paddr:    Address that must be written to signal a message-based interrupt
+- * @val:      Value to write into irq_addr address
+- * @irq_num:  A user defined number associated with this IRQ
+- */
+-struct dprc_irq_cfg {
+-           phys_addr_t paddr;
+-           u32 val;
+-           int irq_num;
+-};
+-
+-int dprc_set_irq(struct fsl_mc_io *mc_io,
+-               u32 cmd_flags,
+-               u16 token,
+-               u8 irq_index,
+-               struct dprc_irq_cfg *irq_cfg);
+-
+-int dprc_set_irq_enable(struct fsl_mc_io *mc_io,
+-                      u32 cmd_flags,
+-                      u16 token,
+-                      u8 irq_index,
+-                      u8 en);
+-
+-int dprc_set_irq_mask(struct fsl_mc_io *mc_io,
+-                    u32 cmd_flags,
+-                    u16 token,
+-                    u8 irq_index,
+-                    u32 mask);
+-
+-int dprc_get_irq_status(struct fsl_mc_io *mc_io,
+-                      u32 cmd_flags,
+-                      u16 token,
+-                      u8 irq_index,
+-                      u32 *status);
+-
+-int dprc_clear_irq_status(struct fsl_mc_io *mc_io,
+-                        u32 cmd_flags,
+-                        u16 token,
+-                        u8 irq_index,
+-                        u32 status);
+-
+-/**
+- * struct dprc_attributes - Container attributes
+- * @container_id: Container's ID
+- * @icid: Container's ICID
+- * @portal_id: Container's portal ID
+- * @options: Container's options as set at container's creation
+- */
+-struct dprc_attributes {
+-      int container_id;
+-      u32 icid;
+-      int portal_id;
+-      u64 options;
+-};
+-
+-int dprc_get_attributes(struct fsl_mc_io *mc_io,
+-                      u32 cmd_flags,
+-                      u16 token,
+-                      struct dprc_attributes *attributes);
+-
+-int dprc_get_obj_count(struct fsl_mc_io *mc_io,
+-                     u32 cmd_flags,
+-                     u16 token,
+-                     int *obj_count);
+-
+-int dprc_get_obj(struct fsl_mc_io *mc_io,
+-               u32 cmd_flags,
+-               u16 token,
+-               int obj_index,
+-               struct fsl_mc_obj_desc *obj_desc);
+-
+-int dprc_set_obj_irq(struct fsl_mc_io *mc_io,
+-                   u32 cmd_flags,
+-                   u16 token,
+-                   char *obj_type,
+-                   int obj_id,
+-                   u8 irq_index,
+-                   struct dprc_irq_cfg *irq_cfg);
+-
+-/* Region flags */
+-/* Cacheable - Indicates that region should be mapped as cacheable */
+-#define DPRC_REGION_CACHEABLE 0x00000001
+-#define DPRC_REGION_SHAREABLE 0x00000002
+-
+-/**
+- * enum dprc_region_type - Region type
+- * @DPRC_REGION_TYPE_MC_PORTAL: MC portal region
+- * @DPRC_REGION_TYPE_QBMAN_PORTAL: Qbman portal region
+- */
+-enum dprc_region_type {
+-      DPRC_REGION_TYPE_MC_PORTAL,
+-      DPRC_REGION_TYPE_QBMAN_PORTAL,
+-      DPRC_REGION_TYPE_QBMAN_MEM_BACKED_PORTAL
+-};
+-
+-/**
+- * struct dprc_region_desc - Mappable region descriptor
+- * @base_offset: Region offset from region's base address.
+- *    For DPMCP and DPRC objects, region base is offset from SoC MC portals
+- *    base address; For DPIO, region base is offset from SoC QMan portals
+- *    base address
+- * @size: Region size (in bytes)
+- * @flags: Region attributes
+- * @type: Portal region type
+- */
+-struct dprc_region_desc {
+-      u32 base_offset;
+-      u32 size;
+-      u32 flags;
+-      enum dprc_region_type type;
+-      u64 base_address;
+-};
+-
+-int dprc_get_obj_region(struct fsl_mc_io *mc_io,
+-                      u32 cmd_flags,
+-                      u16 token,
+-                      char *obj_type,
+-                      int obj_id,
+-                      u8 region_index,
+-                      struct dprc_region_desc *region_desc);
+-
+-int dprc_get_api_version(struct fsl_mc_io *mc_io,
+-                       u32 cmd_flags,
+-                       u16 *major_ver,
+-                       u16 *minor_ver);
+-
+-int dprc_get_container_id(struct fsl_mc_io *mc_io,
+-                        u32 cmd_flags,
+-                        int *container_id);
+-
+-int dprc_reset_container(struct fsl_mc_io *mc_io,
+-                       u32 cmd_flags,
+-                       u16 token,
+-                       int child_container_id);
+-
+-/*
+  * Data Path Buffer Pool (DPBP) API
+  */
+@@ -491,70 +156,6 @@ struct dpcon_cmd_set_notification {
+       __le64 user_ctx;
+ };
+-/**
+- * Maximum number of total IRQs that can be pre-allocated for an MC bus'
+- * IRQ pool
+- */
+-#define FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS        256
+-
+-/**
+- * struct fsl_mc_resource_pool - Pool of MC resources of a given
+- * type
+- * @type: type of resources in the pool
+- * @max_count: maximum number of resources in the pool
+- * @free_count: number of free resources in the pool
+- * @mutex: mutex to serialize access to the pool's free list
+- * @free_list: anchor node of list of free resources in the pool
+- * @mc_bus: pointer to the MC bus that owns this resource pool
+- */
+-struct fsl_mc_resource_pool {
+-      enum fsl_mc_pool_type type;
+-      int max_count;
+-      int free_count;
+-      struct mutex mutex;     /* serializes access to free_list */
+-      struct list_head free_list;
+-      struct fsl_mc_bus *mc_bus;
+-};
+-
+-/**
+- * struct fsl_mc_uapi - information associated with a device file
+- * @misc: struct miscdevice linked to the root dprc
+- * @device: newly created device in /dev
+- * @mutex: mutex lock to serialize the open/release operations
+- * @local_instance_in_use: local MC I/O instance in use or not
+- * @static_mc_io: pointer to the static MC I/O object
+- */
+-struct fsl_mc_uapi {
+-      struct miscdevice misc;
+-      struct device *device;
+-      struct mutex mutex; /* serialize open/release operations */
+-      u32 local_instance_in_use;
+-      struct fsl_mc_io *static_mc_io;
+-};
+-
+-/**
+- * struct fsl_mc_bus - logical bus that corresponds to a physical DPRC
+- * @mc_dev: fsl-mc device for the bus device itself.
+- * @resource_pools: array of resource pools (one pool per resource type)
+- * for this MC bus. These resources represent allocatable entities
+- * from the physical DPRC.
+- * @irq_resources: Pointer to array of IRQ objects for the IRQ pool
+- * @scan_mutex: Serializes bus scanning
+- * @dprc_attr: DPRC attributes
+- * @uapi_misc: struct that abstracts the interaction with userspace
+- */
+-struct fsl_mc_bus {
+-      struct fsl_mc_device mc_dev;
+-      struct fsl_mc_resource_pool resource_pools[FSL_MC_NUM_POOL_TYPES];
+-      struct fsl_mc_device_irq *irq_resources;
+-      struct mutex scan_mutex;    /* serializes bus scanning */
+-      struct dprc_attributes dprc_attr;
+-      struct fsl_mc_uapi uapi_misc;
+-};
+-
+-#define to_fsl_mc_bus(_mc_dev) \
+-      container_of(_mc_dev, struct fsl_mc_bus, mc_dev)
+-
+ int __must_check fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc,
+                                  struct fsl_mc_io *mc_io,
+                                  struct device *parent_dev,
+@@ -565,17 +166,10 @@ int __init dprc_driver_init(void);
+ void dprc_driver_exit(void);
+-int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
+-                    const char *driver_override,
+-                    unsigned int *total_irq_count);
+ int __init fsl_mc_allocator_driver_init(void);
+ void fsl_mc_allocator_driver_exit(void);
+-void fsl_mc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev);
+-
+-void fsl_mc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev);
+-
+ int __must_check fsl_mc_resource_allocate(struct fsl_mc_bus *mc_bus,
+                                         enum fsl_mc_pool_type pool_type,
+                                         struct fsl_mc_resource
+@@ -588,14 +182,6 @@ int fsl_mc_msi_domain_alloc_irqs(struct
+ void fsl_mc_msi_domain_free_irqs(struct device *dev);
+-int fsl_mc_find_msi_domain(struct device *mc_platform_dev,
+-                         struct irq_domain **mc_msi_domain);
+-
+-int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus,
+-                           unsigned int irq_count);
+-
+-void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus);
+-
+ int __must_check fsl_create_mc_io(struct device *dev,
+                                 phys_addr_t mc_portal_phys_addr,
+                                 u32 mc_portal_size,
+--- a/include/linux/fsl/mc.h
++++ b/include/linux/fsl/mc.h
+@@ -12,6 +12,8 @@
+ #include <linux/device.h>
+ #include <linux/mod_devicetable.h>
+ #include <linux/interrupt.h>
++#include <linux/ioctl.h>
++#include <linux/miscdevice.h>
+ #include <uapi/linux/fsl_mc.h>
+ #define FSL_MC_VENDOR_FREESCALE       0x1957
+@@ -49,6 +51,9 @@ struct fsl_mc_driver {
+ #define to_fsl_mc_driver(_drv) \
+       container_of(_drv, struct fsl_mc_driver, driver)
++#define to_fsl_mc_bus(_mc_dev) \
++      container_of(_mc_dev, struct fsl_mc_bus, mc_dev)
++
+ /**
+  * enum fsl_mc_pool_type - Types of allocatable MC bus resources
+  *
+@@ -469,6 +474,339 @@ static inline bool is_fsl_mc_bus_dpseci(
+ }
+ /*
++ * Data Path Resource Container (DPRC) API
++ */
++
++/* Minimal supported DPRC Version */
++#define DPRC_MIN_VER_MAJOR                    6
++#define DPRC_MIN_VER_MINOR                    0
++
++/* DPRC command versioning */
++#define DPRC_CMD_BASE_VERSION                 1
++#define DPRC_CMD_2ND_VERSION                  2
++#define DPRC_CMD_ID_OFFSET                    4
++
++#define DPRC_CMD(id)  (((id) << DPRC_CMD_ID_OFFSET) | DPRC_CMD_BASE_VERSION)
++#define DPRC_CMD_V2(id)       (((id) << DPRC_CMD_ID_OFFSET) | DPRC_CMD_2ND_VERSION)
++
++/* DPRC command IDs */
++#define DPRC_CMDID_CLOSE                        DPRC_CMD(0x800)
++#define DPRC_CMDID_OPEN                         DPRC_CMD(0x805)
++#define DPRC_CMDID_GET_API_VERSION              DPRC_CMD(0xa05)
++
++#define DPRC_CMDID_GET_ATTR                     DPRC_CMD(0x004)
++#define DPRC_CMDID_RESET_CONT                   DPRC_CMD(0x005)
++
++#define DPRC_CMDID_SET_IRQ                      DPRC_CMD(0x010)
++#define DPRC_CMDID_SET_IRQ_ENABLE               DPRC_CMD(0x012)
++#define DPRC_CMDID_SET_IRQ_MASK                 DPRC_CMD(0x014)
++#define DPRC_CMDID_GET_IRQ_STATUS               DPRC_CMD(0x016)
++#define DPRC_CMDID_CLEAR_IRQ_STATUS             DPRC_CMD(0x017)
++
++#define DPRC_CMDID_GET_CONT_ID                  DPRC_CMD(0x830)
++#define DPRC_CMDID_GET_OBJ_COUNT                DPRC_CMD(0x159)
++#define DPRC_CMDID_GET_OBJ                      DPRC_CMD(0x15A)
++#define DPRC_CMDID_GET_OBJ_REG                  DPRC_CMD(0x15E)
++#define DPRC_CMDID_GET_OBJ_REG_V2               DPRC_CMD_V2(0x15E)
++#define DPRC_CMDID_SET_OBJ_IRQ                  DPRC_CMD(0x15F)
++
++struct dprc_cmd_open {
++      __le32 container_id;
++};
++
++struct dprc_cmd_reset_container {
++      __le32 child_container_id;
++};
++
++struct dprc_cmd_set_irq {
++      /* cmd word 0 */
++      __le32 irq_val;
++      u8 irq_index;
++      u8 pad[3];
++      /* cmd word 1 */
++      __le64 irq_addr;
++      /* cmd word 2 */
++      __le32 irq_num;
++};
++
++#define DPRC_ENABLE           0x1
++
++struct dprc_cmd_set_irq_enable {
++      u8 enable;
++      u8 pad[3];
++      u8 irq_index;
++};
++
++struct dprc_cmd_set_irq_mask {
++      __le32 mask;
++      u8 irq_index;
++};
++
++struct dprc_cmd_get_irq_status {
++      __le32 status;
++      u8 irq_index;
++};
++
++struct dprc_rsp_get_irq_status {
++      __le32 status;
++};
++
++struct dprc_cmd_clear_irq_status {
++      __le32 status;
++      u8 irq_index;
++};
++
++struct dprc_rsp_get_attributes {
++      /* response word 0 */
++      __le32 container_id;
++      __le32 icid;
++      /* response word 1 */
++      __le32 options;
++      __le32 portal_id;
++};
++
++struct dprc_rsp_get_obj_count {
++      __le32 pad;
++      __le32 obj_count;
++};
++
++struct dprc_cmd_get_obj {
++      __le32 obj_index;
++};
++
++struct dprc_rsp_get_obj {
++      /* response word 0 */
++      __le32 pad0;
++      __le32 id;
++      /* response word 1 */
++      __le16 vendor;
++      u8 irq_count;
++      u8 region_count;
++      __le32 state;
++      /* response word 2 */
++      __le16 version_major;
++      __le16 version_minor;
++      __le16 flags;
++      __le16 pad1;
++      /* response word 3-4 */
++      u8 type[16];
++      /* response word 5-6 */
++      u8 label[16];
++};
++
++struct dprc_cmd_get_obj_region {
++      /* cmd word 0 */
++      __le32 obj_id;
++      __le16 pad0;
++      u8 region_index;
++      u8 pad1;
++      /* cmd word 1-2 */
++      __le64 pad2[2];
++      /* cmd word 3-4 */
++      u8 obj_type[16];
++};
++
++struct dprc_rsp_get_obj_region {
++      /* response word 0 */
++      __le64 pad0;
++      /* response word 1 */
++      __le64 base_offset;
++      /* response word 2 */
++      __le32 size;
++      u8 type;
++      u8 pad2[3];
++      /* response word 3 */
++      __le32 flags;
++      __le32 pad3;
++      /* response word 4 */
++      /* base_addr may be zero if older MC firmware is used */
++      __le64 base_addr;
++};
++
++struct dprc_cmd_set_obj_irq {
++      /* cmd word 0 */
++      __le32 irq_val;
++      u8 irq_index;
++      u8 pad[3];
++      /* cmd word 1 */
++      __le64 irq_addr;
++      /* cmd word 2 */
++      __le32 irq_num;
++      __le32 obj_id;
++      /* cmd word 3-4 */
++      u8 obj_type[16];
++};
++
++/*
++ * DPRC API for managing and querying DPAA resources
++ */
++int dprc_open(struct fsl_mc_io *mc_io,
++            u32 cmd_flags,
++            int container_id,
++            u16 *token);
++
++int dprc_close(struct fsl_mc_io *mc_io,
++             u32 cmd_flags,
++             u16 token);
++
++/* DPRC IRQ events */
++
++/* IRQ event - Indicates that a new object added to the container */
++#define DPRC_IRQ_EVENT_OBJ_ADDED              0x00000001
++/* IRQ event - Indicates that an object was removed from the container */
++#define DPRC_IRQ_EVENT_OBJ_REMOVED            0x00000002
++/*
++ * IRQ event - Indicates that one of the descendant containers that opened by
++ * this container is destroyed
++ */
++#define DPRC_IRQ_EVENT_CONTAINER_DESTROYED    0x00000010
++
++/*
++ * IRQ event - Indicates that on one of the container's opened object is
++ * destroyed
++ */
++#define DPRC_IRQ_EVENT_OBJ_DESTROYED          0x00000020
++
++/* Irq event - Indicates that object is created at the container */
++#define DPRC_IRQ_EVENT_OBJ_CREATED            0x00000040
++
++/**
++ * struct dprc_irq_cfg - IRQ configuration
++ * @paddr:    Address that must be written to signal a message-based interrupt
++ * @val:      Value to write into irq_addr address
++ * @irq_num:  A user defined number associated with this IRQ
++ */
++struct dprc_irq_cfg {
++           phys_addr_t paddr;
++           u32 val;
++           int irq_num;
++};
++
++int dprc_set_irq(struct fsl_mc_io *mc_io,
++               u32 cmd_flags,
++               u16 token,
++               u8 irq_index,
++               struct dprc_irq_cfg *irq_cfg);
++
++int dprc_set_irq_enable(struct fsl_mc_io *mc_io,
++                      u32 cmd_flags,
++                      u16 token,
++                      u8 irq_index,
++                      u8 en);
++
++int dprc_set_irq_mask(struct fsl_mc_io *mc_io,
++                    u32 cmd_flags,
++                    u16 token,
++                    u8 irq_index,
++                    u32 mask);
++
++int dprc_get_irq_status(struct fsl_mc_io *mc_io,
++                      u32 cmd_flags,
++                      u16 token,
++                      u8 irq_index,
++                      u32 *status);
++
++int dprc_clear_irq_status(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        u8 irq_index,
++                        u32 status);
++
++/**
++ * struct dprc_attributes - Container attributes
++ * @container_id: Container's ID
++ * @icid: Container's ICID
++ * @portal_id: Container's portal ID
++ * @options: Container's options as set at container's creation
++ */
++struct dprc_attributes {
++      int container_id;
++      u32 icid;
++      int portal_id;
++      u64 options;
++};
++
++int dprc_get_attributes(struct fsl_mc_io *mc_io,
++                      u32 cmd_flags,
++                      u16 token,
++                      struct dprc_attributes *attributes);
++
++int dprc_get_obj_count(struct fsl_mc_io *mc_io,
++                     u32 cmd_flags,
++                     u16 token,
++                     int *obj_count);
++
++int dprc_get_obj(struct fsl_mc_io *mc_io,
++               u32 cmd_flags,
++               u16 token,
++               int obj_index,
++               struct fsl_mc_obj_desc *obj_desc);
++
++int dprc_set_obj_irq(struct fsl_mc_io *mc_io,
++                   u32 cmd_flags,
++                   u16 token,
++                   char *obj_type,
++                   int obj_id,
++                   u8 irq_index,
++                   struct dprc_irq_cfg *irq_cfg);
++
++/* Region flags */
++/* Cacheable - Indicates that region should be mapped as cacheable */
++#define DPRC_REGION_CACHEABLE 0x00000001
++#define DPRC_REGION_SHAREABLE 0x00000002
++
++/**
++ * enum dprc_region_type - Region type
++ * @DPRC_REGION_TYPE_MC_PORTAL: MC portal region
++ * @DPRC_REGION_TYPE_QBMAN_PORTAL: Qbman portal region
++ */
++enum dprc_region_type {
++      DPRC_REGION_TYPE_MC_PORTAL,
++      DPRC_REGION_TYPE_QBMAN_PORTAL,
++      DPRC_REGION_TYPE_QBMAN_MEM_BACKED_PORTAL
++};
++
++/**
++ * struct dprc_region_desc - Mappable region descriptor
++ * @base_offset: Region offset from region's base address.
++ *    For DPMCP and DPRC objects, region base is offset from SoC MC portals
++ *    base address; For DPIO, region base is offset from SoC QMan portals
++ *    base address
++ * @size: Region size (in bytes)
++ * @flags: Region attributes
++ * @type: Portal region type
++ */
++struct dprc_region_desc {
++      u32 base_offset;
++      u32 size;
++      u32 flags;
++      enum dprc_region_type type;
++      u64 base_address;
++};
++
++int dprc_get_obj_region(struct fsl_mc_io *mc_io,
++                      u32 cmd_flags,
++                      u16 token,
++                      char *obj_type,
++                      int obj_id,
++                      u8 region_index,
++                      struct dprc_region_desc *region_desc);
++
++int dprc_get_api_version(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 *major_ver,
++                       u16 *minor_ver);
++
++int dprc_get_container_id(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        int *container_id);
++
++int dprc_reset_container(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token,
++                       int child_container_id);
++
++/*
+  * Data Path Buffer Pool (DPBP) API
+  * Contains initialization APIs and runtime control APIs for DPBP
+  */
+@@ -576,4 +914,86 @@ int dpcon_set_notification(struct fsl_mc
+                          u16 token,
+                          struct dpcon_notification_cfg *cfg);
++struct irq_domain;
++struct msi_domain_info;
++
++/**
++ * Maximum number of total IRQs that can be pre-allocated for an MC bus'
++ * IRQ pool
++ */
++#define FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS        256
++
++/**
++ * struct fsl_mc_resource_pool - Pool of MC resources of a given
++ * type
++ * @type: type of resources in the pool
++ * @max_count: maximum number of resources in the pool
++ * @free_count: number of free resources in the pool
++ * @mutex: mutex to serialize access to the pool's free list
++ * @free_list: anchor node of list of free resources in the pool
++ * @mc_bus: pointer to the MC bus that owns this resource pool
++ */
++struct fsl_mc_resource_pool {
++      enum fsl_mc_pool_type type;
++      int max_count;
++      int free_count;
++      struct mutex mutex;     /* serializes access to free_list */
++      struct list_head free_list;
++      struct fsl_mc_bus *mc_bus;
++};
++
++/**
++ * struct fsl_mc_uapi - information associated with a device file
++ * @misc: struct miscdevice linked to the root dprc
++ * @device: newly created device in /dev
++ * @mutex: mutex lock to serialize the open/release operations
++ * @local_instance_in_use: local MC I/O instance in use or not
++ * @static_mc_io: pointer to the static MC I/O object
++ */
++struct fsl_mc_uapi {
++      struct miscdevice misc;
++      struct device *device;
++      struct mutex mutex; /* serialize open/release operations */
++      u32 local_instance_in_use;
++      struct fsl_mc_io *static_mc_io;
++};
++
++/**
++ * struct fsl_mc_bus - logical bus that corresponds to a physical DPRC
++ * @mc_dev: fsl-mc device for the bus device itself.
++ * @resource_pools: array of resource pools (one pool per resource type)
++ * for this MC bus. These resources represent allocatable entities
++ * from the physical DPRC.
++ * @irq_resources: Pointer to array of IRQ objects for the IRQ pool
++ * @scan_mutex: Serializes bus scanning
++ * @dprc_attr: DPRC attributes
++ * @uapi_misc: struct that abstracts the interaction with userspace
++ */
++struct fsl_mc_bus {
++      struct fsl_mc_device mc_dev;
++      struct fsl_mc_resource_pool resource_pools[FSL_MC_NUM_POOL_TYPES];
++      struct fsl_mc_device_irq *irq_resources;
++      struct mutex scan_mutex;    /* serializes bus scanning */
++      struct dprc_attributes dprc_attr;
++      struct fsl_mc_uapi uapi_misc;
++};
++
++int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
++                    const char *driver_override,
++                    unsigned int *total_irq_count);
++
++int fsl_mc_find_msi_domain(struct device *mc_platform_dev,
++                         struct irq_domain **mc_msi_domain);
++
++int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus,
++                           unsigned int irq_count);
++
++void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus);
++
++void fsl_mc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev);
++
++void fsl_mc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev);
++
++void fsl_mc_get_root_dprc(struct device *dev, struct device **root_dprc_dev);
++
+ #endif /* _FSL_MC_H_ */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0143-bus-fsl-mc-add-support-for-dpdmux-device-type.patch b/target/linux/layerscape/patches-5.4/701-net-0143-bus-fsl-mc-add-support-for-dpdmux-device-type.patch
new file mode 100644 (file)
index 0000000..d5cf3c5
--- /dev/null
@@ -0,0 +1,54 @@
+From 5b4e5d281abfa29cf3808b4a3a3ab994f80d6cca Mon Sep 17 00:00:00 2001
+From: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+Date: Tue, 24 Apr 2018 14:51:56 +0300
+Subject: [PATCH] bus: fsl-mc: add support for dpdmux device type
+
+Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+---
+ drivers/bus/fsl-mc/fsl-mc-bus.c | 5 +++++
+ include/linux/fsl/mc.h          | 6 ++++++
+ 2 files changed, 11 insertions(+)
+
+--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
+@@ -270,6 +270,10 @@ struct device_type fsl_mc_bus_dpsw_type
+       .name = "fsl_mc_bus_dpsw"
+ };
++struct device_type fsl_mc_bus_dpdmux_type = {
++      .name = "fsl_mc_bus_dpdmux"
++};
++
+ struct device_type fsl_mc_bus_dpbp_type = {
+       .name = "fsl_mc_bus_dpbp"
+ };
+@@ -304,6 +308,7 @@ static struct device_type *fsl_mc_get_de
+               { &fsl_mc_bus_dpni_type, "dpni" },
+               { &fsl_mc_bus_dpio_type, "dpio" },
+               { &fsl_mc_bus_dpsw_type, "dpsw" },
++              { &fsl_mc_bus_dpdmux_type, "dpdmux" },
+               { &fsl_mc_bus_dpbp_type, "dpbp" },
+               { &fsl_mc_bus_dpcon_type, "dpcon" },
+               { &fsl_mc_bus_dpmcp_type, "dpmcp" },
+--- a/include/linux/fsl/mc.h
++++ b/include/linux/fsl/mc.h
+@@ -416,6 +416,7 @@ extern struct device_type fsl_mc_bus_dpr
+ extern struct device_type fsl_mc_bus_dpni_type;
+ extern struct device_type fsl_mc_bus_dpio_type;
+ extern struct device_type fsl_mc_bus_dpsw_type;
++extern struct device_type fsl_mc_bus_dpdmux_type;
+ extern struct device_type fsl_mc_bus_dpbp_type;
+ extern struct device_type fsl_mc_bus_dpcon_type;
+ extern struct device_type fsl_mc_bus_dpmcp_type;
+@@ -443,6 +444,11 @@ static inline bool is_fsl_mc_bus_dpsw(co
+       return mc_dev->dev.type == &fsl_mc_bus_dpsw_type;
+ }
++static inline bool is_fsl_mc_bus_dpdmux(const struct fsl_mc_device *mc_dev)
++{
++      return mc_dev->dev.type == &fsl_mc_bus_dpdmux_type;
++}
++
+ static inline bool is_fsl_mc_bus_dpbp(const struct fsl_mc_device *mc_dev)
+ {
+       return mc_dev->dev.type == &fsl_mc_bus_dpbp_type;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0144-bus-fsl-mc-add-support-for-dpdcei-device-type.patch b/target/linux/layerscape/patches-5.4/701-net-0144-bus-fsl-mc-add-support-for-dpdcei-device-type.patch
new file mode 100644 (file)
index 0000000..0ab2421
--- /dev/null
@@ -0,0 +1,54 @@
+From 6de672cdae08f6dbd94c115481f3472a7af50c19 Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Wed, 25 Apr 2018 13:35:16 +0300
+Subject: [PATCH] bus: fsl-mc: add support for dpdcei device type
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+---
+ drivers/bus/fsl-mc/fsl-mc-bus.c | 5 +++++
+ include/linux/fsl/mc.h          | 6 ++++++
+ 2 files changed, 11 insertions(+)
+
+--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
+@@ -298,6 +298,10 @@ struct device_type fsl_mc_bus_dpseci_typ
+       .name = "fsl_mc_bus_dpseci"
+ };
++struct device_type fsl_mc_bus_dpdcei_type = {
++      .name = "fsl_mc_bus_dpdcei"
++};
++
+ static struct device_type *fsl_mc_get_device_type(const char *type)
+ {
+       static const struct {
+@@ -315,6 +319,7 @@ static struct device_type *fsl_mc_get_de
+               { &fsl_mc_bus_dpmac_type, "dpmac" },
+               { &fsl_mc_bus_dprtc_type, "dprtc" },
+               { &fsl_mc_bus_dpseci_type, "dpseci" },
++              { &fsl_mc_bus_dpdcei_type, "dpdcei" },
+               { NULL, NULL }
+       };
+       int i;
+--- a/include/linux/fsl/mc.h
++++ b/include/linux/fsl/mc.h
+@@ -423,6 +423,7 @@ extern struct device_type fsl_mc_bus_dpm
+ extern struct device_type fsl_mc_bus_dpmac_type;
+ extern struct device_type fsl_mc_bus_dprtc_type;
+ extern struct device_type fsl_mc_bus_dpseci_type;
++extern struct device_type fsl_mc_bus_dpdcei_type;
+ static inline bool is_fsl_mc_bus_dprc(const struct fsl_mc_device *mc_dev)
+ {
+@@ -479,6 +480,11 @@ static inline bool is_fsl_mc_bus_dpseci(
+       return mc_dev->dev.type == &fsl_mc_bus_dpseci_type;
+ }
++static inline bool is_fsl_mc_bus_dpdcei(const struct fsl_mc_device *mc_dev)
++{
++      return mc_dev->dev.type == &fsl_mc_bus_dpdcei_type;
++}
++
+ /*
+  * Data Path Resource Container (DPRC) API
+  */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0145-bus-fsl-mc-add-support-for-dpaiop-dpci-and-dpdmai-de.patch b/target/linux/layerscape/patches-5.4/701-net-0145-bus-fsl-mc-add-support-for-dpaiop-dpci-and-dpdmai-de.patch
new file mode 100644 (file)
index 0000000..c57d16e
--- /dev/null
@@ -0,0 +1,77 @@
+From 0b8b5f7ff79b83ccfcb82fe0f571ddd77f577d19 Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Thu, 3 May 2018 15:37:04 +0300
+Subject: [PATCH] bus: fsl-mc: add support for dpaiop, dpci and dpdmai device
+ type
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+---
+ drivers/bus/fsl-mc/fsl-mc-bus.c | 15 +++++++++++++++
+ include/linux/fsl/mc.h          | 18 ++++++++++++++++++
+ 2 files changed, 33 insertions(+)
+
+--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
+@@ -302,6 +302,18 @@ struct device_type fsl_mc_bus_dpdcei_typ
+       .name = "fsl_mc_bus_dpdcei"
+ };
++struct device_type fsl_mc_bus_dpaiop_type = {
++      .name = "fsl_mc_bus_dpaiop"
++};
++
++struct device_type fsl_mc_bus_dpci_type = {
++      .name = "fsl_mc_bus_dpci"
++};
++
++struct device_type fsl_mc_bus_dpdmai_type = {
++      .name = "fsl_mc_bus_dpdmai"
++};
++
+ static struct device_type *fsl_mc_get_device_type(const char *type)
+ {
+       static const struct {
+@@ -320,6 +332,9 @@ static struct device_type *fsl_mc_get_de
+               { &fsl_mc_bus_dprtc_type, "dprtc" },
+               { &fsl_mc_bus_dpseci_type, "dpseci" },
+               { &fsl_mc_bus_dpdcei_type, "dpdcei" },
++              { &fsl_mc_bus_dpaiop_type, "dpaiop" },
++              { &fsl_mc_bus_dpci_type, "dpci" },
++              { &fsl_mc_bus_dpdmai_type, "dpdmai" },
+               { NULL, NULL }
+       };
+       int i;
+--- a/include/linux/fsl/mc.h
++++ b/include/linux/fsl/mc.h
+@@ -424,6 +424,9 @@ extern struct device_type fsl_mc_bus_dpm
+ extern struct device_type fsl_mc_bus_dprtc_type;
+ extern struct device_type fsl_mc_bus_dpseci_type;
+ extern struct device_type fsl_mc_bus_dpdcei_type;
++extern struct device_type fsl_mc_bus_dpaiop_type;
++extern struct device_type fsl_mc_bus_dpci_type;
++extern struct device_type fsl_mc_bus_dpdmai_type;
+ static inline bool is_fsl_mc_bus_dprc(const struct fsl_mc_device *mc_dev)
+ {
+@@ -485,6 +488,21 @@ static inline bool is_fsl_mc_bus_dpdcei(
+       return mc_dev->dev.type == &fsl_mc_bus_dpdcei_type;
+ }
++static inline bool is_fsl_mc_bus_dpaiop(const struct fsl_mc_device *mc_dev)
++{
++      return mc_dev->dev.type == &fsl_mc_bus_dpaiop_type;
++}
++
++static inline bool is_fsl_mc_bus_dpci(const struct fsl_mc_device *mc_dev)
++{
++      return mc_dev->dev.type == &fsl_mc_bus_dpci_type;
++}
++
++static inline bool is_fsl_mc_bus_dpdmai(const struct fsl_mc_device *mc_dev)
++{
++      return mc_dev->dev.type == &fsl_mc_bus_dpdmai_type;
++}
++
+ /*
+  * Data Path Resource Container (DPRC) API
+  */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0146-bus-fsl-mc-DMA-configure-to-have-force-dma-as-defaul.patch b/target/linux/layerscape/patches-5.4/701-net-0146-bus-fsl-mc-DMA-configure-to-have-force-dma-as-defaul.patch
new file mode 100644 (file)
index 0000000..c0a4d01
--- /dev/null
@@ -0,0 +1,27 @@
+From b6b91c9f49f8459eab973aa3b52b4e8a3a00daa1 Mon Sep 17 00:00:00 2001
+From: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Date: Mon, 27 Aug 2018 13:22:34 +0530
+Subject: [PATCH] bus: fsl-mc: DMA configure to have force-dma as default
+
+Implicit dma setting from bus works when dma-ranges
+specified but not otherwise. We need to continue
+to go for force_dma as default for cases dma-ranges not
+specified. Example dynamic device tree generation for
+generic kvm virtual machines.
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+---
+ drivers/bus/fsl-mc/fsl-mc-bus.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
+@@ -140,7 +140,7 @@ static int fsl_mc_dma_configure(struct d
+       while (dev_is_fsl_mc(dma_dev))
+               dma_dev = dma_dev->parent;
+-      return of_dma_configure(dev, dma_dev->of_node, 0);
++      return of_dma_configure(dev, dma_dev->of_node, 1);
+ }
+ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0147-bus-fsl-mc-Allocate-mc-portal-from-root-dprc-contain.patch b/target/linux/layerscape/patches-5.4/701-net-0147-bus-fsl-mc-Allocate-mc-portal-from-root-dprc-contain.patch
new file mode 100644 (file)
index 0000000..655c478
--- /dev/null
@@ -0,0 +1,45 @@
+From 703972946a42cf1f83bf50cf389d618d61b69500 Mon Sep 17 00:00:00 2001
+From: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Date: Mon, 10 Dec 2018 14:42:51 +0530
+Subject: [PATCH] bus: fsl-mc: Allocate mc-portal from root dprc container
+
+Root dprc container have allocate-able mc-portals which
+can be allocated by kernel drivers.
+
+As per current design mc-portal is allocated from parent
+dprc container if requesting device is not root-dprc.
+This works fine if the requesting device is child of
+root dprc container, because their parent is root-dprc
+container. But if request device is grandchild of root
+dprc container then it tries to allocate from it's parent
+root dprc-container and it fails.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+---
+ drivers/bus/fsl-mc/mc-io.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/bus/fsl-mc/mc-io.c
++++ b/drivers/bus/fsl-mc/mc-io.c
+@@ -169,14 +169,16 @@ int __must_check fsl_mc_portal_allocate(
+       int error = -EINVAL;
+       struct fsl_mc_resource *resource = NULL;
+       struct fsl_mc_io *mc_io = NULL;
++      struct device *root_dprc_dev;
+-      if (mc_dev->flags & FSL_MC_IS_DPRC) {
++      if (fsl_mc_is_root_dprc(&mc_dev->dev)) {
+               mc_bus_dev = mc_dev;
+       } else {
+-              if (!dev_is_fsl_mc(mc_dev->dev.parent))
+-                      return error;
++              fsl_mc_get_root_dprc(&mc_dev->dev, &root_dprc_dev);
++              if (WARN_ON(!root_dprc_dev))
++                      return -EINVAL;
+-              mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
++              mc_bus_dev = to_fsl_mc_device(root_dprc_dev);
+       }
+       mc_bus = to_fsl_mc_bus(mc_bus_dev);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0148-bus-fsl-mc-use-raw-spin-lock-to-serialize-mc-cmds.patch b/target/linux/layerscape/patches-5.4/701-net-0148-bus-fsl-mc-use-raw-spin-lock-to-serialize-mc-cmds.patch
new file mode 100644 (file)
index 0000000..42934e2
--- /dev/null
@@ -0,0 +1,58 @@
+From 035546179039d430b32b2cace256552455abf061 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Thu, 29 Aug 2019 11:39:45 +0300
+Subject: [PATCH] bus: fsl-mc: use raw spin lock to serialize mc cmds
+
+Replace the spinlock that serializes the MC commands with a raw
+spinlock. This is needed for the RT kernel because there are MC
+commands sent in interrupt context.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ drivers/bus/fsl-mc/mc-io.c  | 2 +-
+ drivers/bus/fsl-mc/mc-sys.c | 4 ++--
+ include/linux/fsl/mc.h      | 2 +-
+ 3 files changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/bus/fsl-mc/mc-io.c
++++ b/drivers/bus/fsl-mc/mc-io.c
+@@ -82,7 +82,7 @@ int __must_check fsl_create_mc_io(struct
+       mc_io->portal_phys_addr = mc_portal_phys_addr;
+       mc_io->portal_size = mc_portal_size;
+       if (flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)
+-              spin_lock_init(&mc_io->spinlock);
++              raw_spin_lock_init(&mc_io->spinlock);
+       else
+               mutex_init(&mc_io->mutex);
+--- a/drivers/bus/fsl-mc/mc-sys.c
++++ b/drivers/bus/fsl-mc/mc-sys.c
+@@ -251,7 +251,7 @@ int mc_send_command(struct fsl_mc_io *mc
+               return -EINVAL;
+       if (mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)
+-              spin_lock_irqsave(&mc_io->spinlock, irq_flags);
++              raw_spin_lock_irqsave(&mc_io->spinlock, irq_flags);
+       else
+               mutex_lock(&mc_io->mutex);
+@@ -287,7 +287,7 @@ int mc_send_command(struct fsl_mc_io *mc
+       error = 0;
+ common_exit:
+       if (mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)
+-              spin_unlock_irqrestore(&mc_io->spinlock, irq_flags);
++              raw_spin_unlock_irqrestore(&mc_io->spinlock, irq_flags);
+       else
+               mutex_unlock(&mc_io->mutex);
+--- a/include/linux/fsl/mc.h
++++ b/include/linux/fsl/mc.h
+@@ -340,7 +340,7 @@ struct fsl_mc_io {
+                * This field is only meaningful if the
+                * FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag is set
+                */
+-              spinlock_t spinlock;    /* serializes mc_send_command() */
++              raw_spinlock_t spinlock; /* serializes mc_send_command() */
+       };
+ };
diff --git a/target/linux/layerscape/patches-5.4/701-net-0149-soc-fsl-dpio-change-CENA-regs-to-be-cacheable.patch b/target/linux/layerscape/patches-5.4/701-net-0149-soc-fsl-dpio-change-CENA-regs-to-be-cacheable.patch
new file mode 100644 (file)
index 0000000..3465548
--- /dev/null
@@ -0,0 +1,61 @@
+From e2b0ebb44e91e3492f26d21218fb7ea5e14190ec Mon Sep 17 00:00:00 2001
+From: Haiying Wang <Haiying.Wang@nxp.com>
+Date: Thu, 20 Apr 2017 11:54:22 -0400
+Subject: [PATCH] soc: fsl: dpio: change CENA regs to be cacheable
+
+Change cache enabled regsiter accessed to be cacheable
+plus non-shareable to meet the performance requirement.
+QMan's CENA region contains registers and structures that
+are 64byte in size and are inteneded to be accessed using a
+single 64 byte bus transaction, therefore this portal
+memory should be configured as cache-enabled. Also because
+the write allocate stash transcations of QBMan should be
+issued as cachable and non-coherent(non-sharable), we
+need to configure this region to be non-shareable.
+
+Signed-off-by: Haiying Wang <Haiying.Wang@nxp.com>
+---
+ drivers/soc/fsl/dpio/dpio-driver.c | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+--- a/drivers/soc/fsl/dpio/dpio-driver.c
++++ b/drivers/soc/fsl/dpio/dpio-driver.c
+@@ -27,6 +27,11 @@ MODULE_LICENSE("Dual BSD/GPL");
+ MODULE_AUTHOR("Freescale Semiconductor, Inc");
+ MODULE_DESCRIPTION("DPIO Driver");
++#define PROT_NORMAL_NS                (PTE_TYPE_PAGE | PTE_AF | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL))
++
++#define ioremap_cache_ns(addr, size)  __ioremap((addr), (size), __pgprot(PROT_NORMAL_NS))
++
++
+ struct dpio_priv {
+       struct dpaa2_io *io;
+ };
+@@ -200,13 +205,11 @@ static int dpaa2_dpio_probe(struct fsl_m
+       if (dpio_dev->obj_desc.region_count < 3) {
+               /* No support for DDR backed portals, use classic mapping */
+               /*
+-               * Set the CENA regs to be the cache inhibited area of the
+-               * portal to avoid coherency issues if a user migrates to
+-               * another core.
++               * Set the CENA regs to be the cache enabled area of the portal to
++               * achieve the best performance.
+                */
+-              desc.regs_cena = devm_memremap(dev, dpio_dev->regions[1].start,
+-                                      resource_size(&dpio_dev->regions[1]),
+-                                      MEMREMAP_WC);
++              desc.regs_cena = ioremap_cache_ns(dpio_dev->regions[0].start,
++                                              resource_size(&dpio_dev->regions[0]));
+       } else {
+               desc.regs_cena = devm_memremap(dev, dpio_dev->regions[2].start,
+                                       resource_size(&dpio_dev->regions[2]),
+@@ -214,7 +217,7 @@ static int dpaa2_dpio_probe(struct fsl_m
+       }
+       if (IS_ERR(desc.regs_cena)) {
+-              dev_err(dev, "devm_memremap failed\n");
++              dev_err(dev, "ioremap_cache_ns failed\n");
+               err = PTR_ERR(desc.regs_cena);
+               goto err_allocate_irqs;
+       }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0150-soc-fsl-dpio-enable-qbman-CENA-portal-memory-access.patch b/target/linux/layerscape/patches-5.4/701-net-0150-soc-fsl-dpio-enable-qbman-CENA-portal-memory-access.patch
new file mode 100644 (file)
index 0000000..d246046
--- /dev/null
@@ -0,0 +1,110 @@
+From 8464c7b6e7c491ae06b18103881611c98678cf1f Mon Sep 17 00:00:00 2001
+From: Haiying Wang <Haiying.Wang@nxp.com>
+Date: Thu, 13 Apr 2017 14:54:01 -0400
+Subject: [PATCH] soc: fsl: dpio: enable qbman CENA portal memory access
+
+Once we enable the cacheable portal memory, we need to do
+cache flush for enqueue, vdq, buffer release, and management
+commands, as well as invalidate and prefetch for the valid bit
+of management command response and next index of dqrr.
+
+Signed-off-by: Haiying Wang <Haiying.Wang@nxp.com>
+---
+ drivers/soc/fsl/dpio/qbman-portal.c | 23 +++++++++++++++++------
+ 1 file changed, 17 insertions(+), 6 deletions(-)
+
+--- a/drivers/soc/fsl/dpio/qbman-portal.c
++++ b/drivers/soc/fsl/dpio/qbman-portal.c
+@@ -90,6 +90,14 @@ enum qbman_sdqcr_fc {
+       qbman_sdqcr_fc_up_to_3 = 1
+ };
++#define dccvac(p) { asm volatile("dc cvac, %0;" : : "r" (p) : "memory"); }
++#define dcivac(p) { asm volatile("dc ivac, %0" : : "r"(p) : "memory"); }
++static inline void qbman_inval_prefetch(struct qbman_swp *p, uint32_t offset)
++{
++      dcivac(p->addr_cena + offset);
++      prefetch(p->addr_cena + offset);
++}
++
+ /* Portal Access */
+ static inline u32 qbman_read_register(struct qbman_swp *p, u32 offset)
+@@ -190,7 +198,7 @@ struct qbman_swp *qbman_swp_init(const s
+               memset(p->addr_cena, 0, 64 * 1024);
+       reg = qbman_set_swp_cfg(p->dqrr.dqrr_size,
+-                              1, /* Writes Non-cacheable */
++                              0, /* Writes cacheable */
+                               0, /* EQCR_CI stashing threshold */
+                               3, /* RPM: Valid bit mode, RCR in array mode */
+                               2, /* DCM: Discrete consumption ack mode */
+@@ -329,6 +337,7 @@ void qbman_swp_mc_submit(struct qbman_sw
+       if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
+               dma_wmb();
+               *v = cmd_verb | p->mc.valid_bit;
++              dccvac(cmd);
+       } else {
+               *v = cmd_verb | p->mc.valid_bit;
+               dma_wmb();
+@@ -345,6 +354,7 @@ void *qbman_swp_mc_result(struct qbman_s
+       u32 *ret, verb;
+       if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
++              qbman_inval_prefetch(p, QBMAN_CENA_SWP_RR(p->mc.valid_bit));
+               ret = qbman_get_cmd(p, QBMAN_CENA_SWP_RR(p->mc.valid_bit));
+               /* Remove the valid-bit - command completed if the rest
+                * is non-zero.
+@@ -481,6 +491,7 @@ int qbman_swp_enqueue(struct qbman_swp *
+               /* Set the verb byte, have to substitute in the valid-bit */
+               dma_wmb();
+               p->verb = d->verb | EQAR_VB(eqar);
++              dccvac(p);
+       } else {
+               p->verb = d->verb | EQAR_VB(eqar);
+               dma_wmb();
+@@ -677,6 +688,7 @@ int qbman_swp_pull(struct qbman_swp *s,
+               /* Set the verb byte, have to substitute in the valid-bit */
+               p->verb = d->verb | s->vdq.valid_bit;
+               s->vdq.valid_bit ^= QB_VALID_BIT;
++              dccvac(p);
+       } else {
+               p->verb = d->verb | s->vdq.valid_bit;
+               s->vdq.valid_bit ^= QB_VALID_BIT;
+@@ -736,8 +748,7 @@ const struct dpaa2_dq *qbman_swp_dqrr_ne
+                                s->dqrr.next_idx, pi);
+                       s->dqrr.reset_bug = 0;
+               }
+-              prefetch(qbman_get_cmd(s,
+-                                     QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)));
++              qbman_inval_prefetch(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
+       }
+       if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000)
+@@ -755,8 +766,7 @@ const struct dpaa2_dq *qbman_swp_dqrr_ne
+        * knew from reading PI.
+        */
+       if ((verb & QB_VALID_BIT) != s->dqrr.valid_bit) {
+-              prefetch(qbman_get_cmd(s,
+-                                     QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)));
++              qbman_inval_prefetch(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
+               return NULL;
+       }
+       /*
+@@ -779,7 +789,7 @@ const struct dpaa2_dq *qbman_swp_dqrr_ne
+           (flags & DPAA2_DQ_STAT_EXPIRED))
+               atomic_inc(&s->vdq.available);
+-      prefetch(qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)));
++      qbman_inval_prefetch(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
+       return p;
+ }
+@@ -911,6 +921,7 @@ int qbman_swp_release(struct qbman_swp *
+                */
+               dma_wmb();
+               p->verb = d->verb | RAR_VB(rar) | num_buffers;
++              dccvac(p);
+       } else {
+               p->verb = d->verb | RAR_VB(rar) | num_buffers;
+               dma_wmb();
diff --git a/target/linux/layerscape/patches-5.4/701-net-0151-soc-fsl-dpio-Prefer-the-CPU-affine-DPIO.patch b/target/linux/layerscape/patches-5.4/701-net-0151-soc-fsl-dpio-Prefer-the-CPU-affine-DPIO.patch
new file mode 100644 (file)
index 0000000..e9fdc7d
--- /dev/null
@@ -0,0 +1,35 @@
+From 33b7977ba754b6ec4e65aaae34de92d4086ea0bd Mon Sep 17 00:00:00 2001
+From: Roy Pledge <roy.pledge@nxp.com>
+Date: Wed, 13 Sep 2017 17:03:06 -0400
+Subject: [PATCH] soc: fsl: dpio: Prefer the CPU affine DPIO
+
+Use the cpu affine DPIO unless there isn't one which can happen
+if less DPIOs than cores are assign to the kernel.
+
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+---
+ drivers/soc/fsl/dpio/dpio-service.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/soc/fsl/dpio/dpio-service.c
++++ b/drivers/soc/fsl/dpio/dpio-service.c
+@@ -58,7 +58,7 @@ static inline struct dpaa2_io *service_s
+        * If cpu == -1, choose the current cpu, with no guarantees about
+        * potentially being migrated away.
+        */
+-      if (unlikely(cpu < 0))
++      if (cpu < 0)
+               cpu = smp_processor_id();
+       /* If a specific cpu was requested, pick it up immediately */
+@@ -70,6 +70,10 @@ static inline struct dpaa2_io *service_s
+       if (d)
+               return d;
++      d = service_select_by_cpu(d, -1);
++      if (d)
++              return d;
++
+       spin_lock(&dpio_list_lock);
+       d = list_entry(dpio_list.next, struct dpaa2_io, node);
+       list_del(&d->node);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0152-soc-fsl-dpio-Add-Support-for-Order-Restoration.patch b/target/linux/layerscape/patches-5.4/701-net-0152-soc-fsl-dpio-Add-Support-for-Order-Restoration.patch
new file mode 100644 (file)
index 0000000..a03f3e2
--- /dev/null
@@ -0,0 +1,214 @@
+From c91f8c8c94c5e8a25d0d46d6cb26c0c48ba04f8f Mon Sep 17 00:00:00 2001
+From: Roy Pledge <roy.pledge@nxp.com>
+Date: Wed, 4 Oct 2017 15:36:06 -0400
+Subject: [PATCH] soc: fsl: dpio: Add Support for Order Restoration
+
+Add DPIO support for HW assisted order restoration
+
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+---
+ drivers/soc/fsl/dpio/dpio-service.c | 105 ++++++++++++++++++++++++++++++++++++
+ drivers/soc/fsl/dpio/qbman-portal.c |  37 +++++++++++++
+ drivers/soc/fsl/dpio/qbman-portal.h |   3 ++
+ include/soc/fsl/dpaa2-io.h          |  14 ++++-
+ 4 files changed, 158 insertions(+), 1 deletion(-)
+
+--- a/drivers/soc/fsl/dpio/dpio-service.c
++++ b/drivers/soc/fsl/dpio/dpio-service.c
+@@ -707,3 +707,108 @@ int dpaa2_io_query_bp_count(struct dpaa2
+       return 0;
+ }
+ EXPORT_SYMBOL_GPL(dpaa2_io_query_bp_count);
++
++/**
++ * dpaa2_io_service_enqueue_orp_fq() - Enqueue a frame to a frame queue with
++ * order restoration
++ * @d: the given DPIO service.
++ * @fqid: the given frame queue id.
++ * @fd: the frame descriptor which is enqueued.
++ * @orpid: the order restoration point ID
++ * @seqnum: the order sequence number
++ * @last: must be set for the final frame if seqnum is shared (spilt frame)
++ *
++ * Performs an enqueue to a frame queue using the specified order restoration
++ * point. The QMan device will ensure the order of frames placed on the
++ * queue will be ordered as per the sequence number.
++ *
++ * In the case a frame is split it is possible to enqueue using the same
++ * sequence number more than once. The final frame in a shared sequence number
++ * most be indicated by setting last = 1. For non shared sequence numbers
++ * last = 1 must always be set.
++ *
++ * Return 0 for successful enqueue, or -EBUSY if the enqueue ring is not ready,
++ * or -ENODEV if there is no dpio service.
++ */
++int dpaa2_io_service_enqueue_orp_fq(struct dpaa2_io *d, u32 fqid,
++                                  const struct dpaa2_fd *fd, u16 orpid,
++                                  u16 seqnum, int last)
++{
++      struct qbman_eq_desc ed;
++
++      d = service_select(d);
++      if (!d)
++              return -ENODEV;
++      qbman_eq_desc_clear(&ed);
++      qbman_eq_desc_set_orp(&ed, 0, orpid, seqnum, !last);
++      qbman_eq_desc_set_fq(&ed, fqid);
++      return qbman_swp_enqueue(d->swp, &ed, fd);
++}
++EXPORT_SYMBOL(dpaa2_io_service_enqueue_orp_fq);
++
++/**
++ * dpaa2_io_service_enqueue_orp_qd() - Enqueue a frame to a queueing destination
++ * with order restoration
++ * @d: the given DPIO service.
++ * @qdid: the given queuing destination id.
++ * @fd: the frame descriptor which is enqueued.
++ * @orpid: the order restoration point ID
++ * @seqnum: the order sequence number
++ * @last: must be set for the final frame if seqnum is shared (spilt frame)
++ *
++ * Performs an enqueue to a frame queue using the specified order restoration
++ * point. The QMan device will ensure the order of frames placed on the
++ * queue will be ordered as per the sequence number.
++ *
++ * In the case a frame is split it is possible to enqueue using the same
++ * sequence number more than once. The final frame in a shared sequence number
++ * most be indicated by setting last = 1. For non shared sequence numbers
++ * last = 1 must always be set.
++ *
++ * Return 0 for successful enqueue, or -EBUSY if the enqueue ring is not ready,
++ * or -ENODEV if there is no dpio service.
++ */
++int dpaa2_io_service_enqueue_orp_qd(struct dpaa2_io *d, u32 qdid, u8 prio,
++                                  u16 qdbin, const struct dpaa2_fd *fd,
++                                  u16 orpid, u16 seqnum, int last)
++{
++      struct qbman_eq_desc ed;
++
++      d = service_select(d);
++      if (!d)
++              return -ENODEV;
++      qbman_eq_desc_clear(&ed);
++      qbman_eq_desc_set_orp(&ed, 0, orpid, seqnum, !last);
++      qbman_eq_desc_set_qd(&ed, qdid, qdbin, prio);
++      return qbman_swp_enqueue(d->swp, &ed, fd);
++}
++EXPORT_SYMBOL_GPL(dpaa2_io_service_enqueue_orp_qd);
++
++/**
++ * dpaa2_io_service_orp_seqnum_drop() - Remove a sequence number from
++ * an order restoration list
++ * @d: the given DPIO service.
++ * @orpid: Order restoration point to remove a sequence number from
++ * @seqnum: Sequence number to remove
++ *
++ * Removes a frames sequence number from an order restoration point without
++ * enqueing the frame. Used to indicate that the order restoration hardware
++ * should not expect to see this sequence number. Typically used to indicate
++ * a frame was terminated or dropped from a flow.
++ *
++ * Return 0 for successful enqueue, or -EBUSY if the enqueue ring is not ready,
++ * or -ENODEV if there is no dpio service.
++ */
++int dpaa2_io_service_orp_seqnum_drop(struct dpaa2_io *d, u16 orpid, u16 seqnum)
++{
++      struct qbman_eq_desc ed;
++      struct dpaa2_fd fd;
++
++      d = service_select(d);
++      if (!d)
++              return -ENODEV;
++      qbman_eq_desc_clear(&ed);
++      qbman_eq_desc_set_orp_hole(&ed, orpid, seqnum);
++      return qbman_swp_enqueue(d->swp, &ed, &fd);
++}
++EXPORT_SYMBOL_GPL(dpaa2_io_service_orp_seqnum_drop);
+--- a/drivers/soc/fsl/dpio/qbman-portal.c
++++ b/drivers/soc/fsl/dpio/qbman-portal.c
+@@ -413,6 +413,43 @@ void qbman_eq_desc_set_no_orp(struct qbm
+               d->verb |= enqueue_rejects_to_fq;
+ }
++/**
++ * qbman_eq_desc_set_orp() - Set order-restoration in the enqueue descriptor
++ * @d: the enqueue descriptor.
++ * @response_success: 1 = enqueue with response always; 0 = enqueue with
++ * rejections returned on a FQ.
++ * @oprid: the order point record id.
++ * @seqnum: the order restoration sequence number.
++ * @incomplete: indicates whether this is the last fragments using the same
++ * sequence number.
++ */
++void qbman_eq_desc_set_orp(struct qbman_eq_desc *d, int respond_success,
++                         u16 oprid, u16 seqnum, int incomplete)
++{
++      d->verb |= (1 << QB_ENQUEUE_CMD_ORP_ENABLE_SHIFT);
++      if (respond_success)
++              d->verb |= enqueue_response_always;
++      else
++              d->verb |= enqueue_rejects_to_fq;
++      d->orpid = cpu_to_le16(oprid);
++      d->seqnum = cpu_to_le16((!!incomplete << 14) | seqnum);
++}
++
++/**
++ * qbman_eq_desc_set_orp_hole() - fill a hole in the order-restoration sequence
++ * without any enqueue
++ * @d: the enqueue descriptor.
++ * @oprid: the order point record id.
++ * @seqnum: the order restoration sequence number.
++ */
++void qbman_eq_desc_set_orp_hole(struct qbman_eq_desc *d, u16 oprid,
++                              u16 seqnum)
++{
++      d->verb |= (1 << QB_ENQUEUE_CMD_ORP_ENABLE_SHIFT) | enqueue_empty;
++      d->orpid = cpu_to_le16(oprid);
++      d->seqnum = cpu_to_le16(seqnum);
++}
++
+ /*
+  * Exactly one of the following descriptor "targets" should be set. (Calling any
+  * one of these will replace the effect of any prior call to one of these.)
+--- a/drivers/soc/fsl/dpio/qbman-portal.h
++++ b/drivers/soc/fsl/dpio/qbman-portal.h
+@@ -167,6 +167,9 @@ int qbman_result_has_new_result(struct q
+ void qbman_eq_desc_clear(struct qbman_eq_desc *d);
+ void qbman_eq_desc_set_no_orp(struct qbman_eq_desc *d, int respond_success);
++void qbman_eq_desc_set_orp(struct qbman_eq_desc *d, int respond_success,
++                         u16 oprid, u16 seqnum, int incomplete);
++void qbman_eq_desc_set_orp_hole(struct qbman_eq_desc *d, u16 oprid, u16 seqnum);
+ void qbman_eq_desc_set_token(struct qbman_eq_desc *d, u8 token);
+ void qbman_eq_desc_set_fq(struct qbman_eq_desc *d, u32 fqid);
+ void qbman_eq_desc_set_qd(struct qbman_eq_desc *d, u32 qdid,
+--- a/include/soc/fsl/dpaa2-io.h
++++ b/include/soc/fsl/dpaa2-io.h
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+ /*
+  * Copyright 2014-2016 Freescale Semiconductor Inc.
+- * Copyright NXP
++ * Copyright 2017 NXP
+  *
+  */
+ #ifndef __FSL_DPAA2_IO_H
+@@ -121,6 +121,18 @@ struct dpaa2_io_store *dpaa2_io_store_cr
+ void dpaa2_io_store_destroy(struct dpaa2_io_store *s);
+ struct dpaa2_dq *dpaa2_io_store_next(struct dpaa2_io_store *s, int *is_last);
++/* Order Restoration Support */
++int dpaa2_io_service_enqueue_orp_fq(struct dpaa2_io *d, u32 fqid,
++                                  const struct dpaa2_fd *fd, u16 orpid,
++                                  u16 seqnum, int last);
++
++int dpaa2_io_service_enqueue_orp_qd(struct dpaa2_io *d, u32 qdid, u8 prio,
++                                  u16 qdbin, const struct dpaa2_fd *fd,
++                                  u16 orpid, u16 seqnum, int last);
++
++int dpaa2_io_service_orp_seqnum_drop(struct dpaa2_io *d, u16 orpid,
++                                   u16 seqnum);
++
+ int dpaa2_io_query_fq_count(struct dpaa2_io *d, u32 fqid,
+                           u32 *fcnt, u32 *bcnt);
+ int dpaa2_io_query_bp_count(struct dpaa2_io *d, u16 bpid,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0153-soc-fsl-dpio-Fix-order-restoration-API-for-QBMan-5.0.patch b/target/linux/layerscape/patches-5.4/701-net-0153-soc-fsl-dpio-Fix-order-restoration-API-for-QBMan-5.0.patch
new file mode 100644 (file)
index 0000000..6ca8b59
--- /dev/null
@@ -0,0 +1,144 @@
+From 72a6312eda9b142ac5910e5f4b652fa8ae8d222d Mon Sep 17 00:00:00 2001
+From: Roy Pledge <roy.pledge@nxp.com>
+Date: Thu, 25 Oct 2018 16:55:53 -0400
+Subject: [PATCH] soc: fsl: dpio: Fix order restoration API for QBMan 5.0
+
+The mechanism for indicating to HW that a frame was dropped
+when performing HW order restoration changed in QBMan 5.0 to
+use a management command instead of a special enqueue command.
+This patch implements that change when running on a QBMan 5.0
+and above device.
+
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+---
+ drivers/soc/fsl/dpio/dpio-service.c | 10 +++++++
+ drivers/soc/fsl/dpio/qbman-portal.c | 59 ++++++++++++++++++++++++++++++++-----
+ drivers/soc/fsl/dpio/qbman-portal.h |  9 ++++++
+ 3 files changed, 71 insertions(+), 7 deletions(-)
+
+--- a/drivers/soc/fsl/dpio/dpio-service.c
++++ b/drivers/soc/fsl/dpio/dpio-service.c
+@@ -803,10 +803,20 @@ int dpaa2_io_service_orp_seqnum_drop(str
+ {
+       struct qbman_eq_desc ed;
+       struct dpaa2_fd fd;
++      unsigned long irqflags;
++      int ret;
+       d = service_select(d);
+       if (!d)
+               return -ENODEV;
++
++      if ((d->swp->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) {
++              spin_lock_irqsave(&d->lock_mgmt_cmd, irqflags);
++              ret = qbman_orp_drop(d->swp, orpid, seqnum);
++              spin_unlock_irqrestore(&d->lock_mgmt_cmd, irqflags);
++              return ret;
++      }
++
+       qbman_eq_desc_clear(&ed);
+       qbman_eq_desc_set_orp_hole(&ed, orpid, seqnum);
+       return qbman_swp_enqueue(d->swp, &ed, &fd);
+--- a/drivers/soc/fsl/dpio/qbman-portal.c
++++ b/drivers/soc/fsl/dpio/qbman-portal.c
+@@ -12,19 +12,13 @@
+ #include "qbman-portal.h"
+-#define QMAN_REV_4000   0x04000000
+-#define QMAN_REV_4100   0x04010000
+-#define QMAN_REV_4101   0x04010001
+-#define QMAN_REV_5000   0x05000000
+-
+-#define QMAN_REV_MASK   0xffff0000
+-
+ /* All QBMan command and result structures use this "valid bit" encoding */
+ #define QB_VALID_BIT ((u32)0x80)
+ /* QBMan portal management command codes */
+ #define QBMAN_MC_ACQUIRE       0x30
+ #define QBMAN_WQCHAN_CONFIGURE 0x46
++#define QBMAN_MC_ORP           0x63
+ /* CINH register offsets */
+ #define QBMAN_CINH_SWP_EQCR_PI      0x800
+@@ -1246,3 +1240,54 @@ u32 qbman_bp_info_num_free_bufs(struct q
+ {
+       return le32_to_cpu(a->fill);
+ }
++
++struct qbman_orp_cmd_desc {
++      u8 verb;
++      u8 reserved;
++      u8 cid;
++      u8 reserved2;
++      u16 orpid;
++      u16 seqnum;
++      u8 reserved3[56];
++};
++
++struct qbman_orp_cmd_rslt {
++      u8 verb;
++      u8 rslt;
++      u8 cid;
++      u8 reserved1[61];
++};
++
++int qbman_orp_drop(struct qbman_swp *s, u16 orpid, u16 seqnum)
++{
++      struct qbman_orp_cmd_desc *p;
++      struct qbman_orp_cmd_rslt *r;
++      void *resp;
++
++      p = (struct qbman_orp_cmd_desc *)qbman_swp_mc_start(s);
++      if (!p)
++              return -EBUSY;
++
++      p->cid = 0x7;
++      p->orpid = cpu_to_le16(orpid);
++      p->seqnum = cpu_to_le16(seqnum);
++
++      resp = qbman_swp_mc_complete(s, p, QBMAN_MC_ORP);
++      if (!resp) {
++              pr_err("qbman: Drop sequence num %d orpid 0x%x failed, no response\n",
++                     seqnum, orpid);
++              return -EIO;
++      }
++      r = (struct qbman_orp_cmd_rslt *)resp;
++      /* Decode the outcome */
++      WARN_ON((r->verb & QBMAN_RESPONSE_VERB_MASK) != QBMAN_MC_ORP);
++
++      /* Determine success or failure */
++      if (r->rslt != QBMAN_MC_RSLT_OK) {
++              pr_err("Drop seqnum %d of prpid 0x%x failed, code=0x%02x\n",
++                     seqnum, orpid, r->rslt);
++              return -EIO;
++      }
++
++      return 0;
++}
+--- a/drivers/soc/fsl/dpio/qbman-portal.h
++++ b/drivers/soc/fsl/dpio/qbman-portal.h
+@@ -9,6 +9,13 @@
+ #include <soc/fsl/dpaa2-fd.h>
++#define QMAN_REV_4000   0x04000000
++#define QMAN_REV_4100   0x04010000
++#define QMAN_REV_4101   0x04010001
++#define QMAN_REV_5000   0x05000000
++
++#define QMAN_REV_MASK   0xffff0000
++
+ struct dpaa2_dq;
+ struct qbman_swp;
+@@ -178,6 +185,8 @@ void qbman_eq_desc_set_qd(struct qbman_e
+ int qbman_swp_enqueue(struct qbman_swp *p, const struct qbman_eq_desc *d,
+                     const struct dpaa2_fd *fd);
++int qbman_orp_drop(struct qbman_swp *s, u16 orpid, u16 seqnum);
++
+ void qbman_release_desc_clear(struct qbman_release_desc *d);
+ void qbman_release_desc_set_bpid(struct qbman_release_desc *d, u16 bpid);
+ void qbman_release_desc_set_rcdi(struct qbman_release_desc *d, int enable);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0154-soc-fsl-dpio-add-support-for-opr.patch b/target/linux/layerscape/patches-5.4/701-net-0154-soc-fsl-dpio-add-support-for-opr.patch
new file mode 100644 (file)
index 0000000..8bd1e54
--- /dev/null
@@ -0,0 +1,100 @@
+From a0fd93952b6f0b408d96b29a0b9beb8bb2d8a24d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Horia=20Geant=C4=83?= <horia.geanta@nxp.com>
+Date: Wed, 10 Oct 2018 15:59:55 +0300
+Subject: [PATCH] soc: fsl: dpio: add support for opr
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Order preservation is a feature that will be supported
+in dpni, dpseci and dpci devices.
+This is a preliminary patch for the changes to be
+introduced in the corresponding drivers.
+
+Signed-off-by: Radu Alexe <radu.alexe@nxp.com>
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ include/soc/fsl/dpaa2-global.h | 74 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 74 insertions(+)
+
+--- a/include/soc/fsl/dpaa2-global.h
++++ b/include/soc/fsl/dpaa2-global.h
+@@ -189,4 +189,78 @@ static inline bool dpaa2_cscn_state_cong
+       return !!(cscn->scn.state & DPAA2_CSCN_STATE_CG);
+ }
++/* Data Path Order Restoration API
++ * Contains initialization APIs and runtime APIs for the Order Restoration
++ */
++
++/** Order Restoration properties */
++
++/**
++ * Create a new Order Point Record option
++ */
++#define OPR_OPT_CREATE 0x1
++/**
++ * Retire an existing Order Point Record option
++ */
++#define OPR_OPT_RETIRE 0x2
++
++/**
++ * struct opr_cfg - Structure representing OPR configuration
++ * @oprrws: Order point record (OPR) restoration window size (0 to 5)
++ *                    0 - Window size is 32 frames.
++ *                    1 - Window size is 64 frames.
++ *                    2 - Window size is 128 frames.
++ *                    3 - Window size is 256 frames.
++ *                    4 - Window size is 512 frames.
++ *                    5 - Window size is 1024 frames.
++ * @oa: OPR auto advance NESN window size (0 disabled, 1 enabled)
++ * @olws: OPR acceptable late arrival window size (0 to 3)
++ *                    0 - Disabled. Late arrivals are always rejected.
++ *                    1 - Window size is 32 frames.
++ *                    2 - Window size is the same as the OPR restoration
++ *                            window size configured in the OPRRWS field.
++ *                    3 - Window size is 8192 frames. Late arrivals are
++ *                            always accepted.
++ * @oeane: Order restoration list (ORL) resource exhaustion
++ *                    advance NESN enable (0 disabled, 1 enabled)
++ * @oloe: OPR loose ordering enable (0 disabled, 1 enabled)
++ */
++struct opr_cfg {
++      u8 oprrws;
++      u8 oa;
++      u8 olws;
++      u8 oeane;
++      u8 oloe;
++};
++
++/**
++ * struct opr_qry - Structure representing OPR configuration
++ * @enable: Enabled state
++ * @rip: Retirement In Progress
++ * @ndsn: Next dispensed sequence number
++ * @nesn: Next expected sequence number
++ * @ea_hseq: Early arrival head sequence number
++ * @hseq_nlis: HSEQ not last in sequence
++ * @ea_tseq: Early arrival tail sequence number
++ * @tseq_nlis: TSEQ not last in sequence
++ * @ea_tptr: Early arrival tail pointer
++ * @ea_hptr: Early arrival head pointer
++ * @opr_id: Order Point Record ID
++ * @opr_vid: Order Point Record Virtual ID
++ */
++struct opr_qry {
++      char enable;
++      char rip;
++      u16 ndsn;
++      u16 nesn;
++      u16 ea_hseq;
++      char hseq_nlis;
++      u16 ea_tseq;
++      char tseq_nlis;
++      u16 ea_tptr;
++      u16 ea_hptr;
++      u16 opr_id;
++      u16 opr_vid;
++};
++
+ #endif /* __FSL_DPAA2_GLOBAL_H */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0155-soc-fsl-dpio-aligned-access-of-qbman-cacheable-regio.patch b/target/linux/layerscape/patches-5.4/701-net-0155-soc-fsl-dpio-aligned-access-of-qbman-cacheable-regio.patch
new file mode 100644 (file)
index 0000000..92e4dca
--- /dev/null
@@ -0,0 +1,73 @@
+From 353725d455cc27aa2008456c2711e7fae2b8a631 Mon Sep 17 00:00:00 2001
+From: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Date: Wed, 7 Mar 2018 21:35:37 +0530
+Subject: [PATCH] soc: fsl: dpio: aligned access of qbman cacheable region
+
+Alignment requirement on ARM is lenient (In Linux) for regions
+mapped as "Memory Type" but have very strict policy for regions
+mapped as "Device Type". Unaligned access to regions mapped
+as "Device Type" will always result to unaligned fault.
+
+DPIO driver have un-aligned access to QBman cacheable region
+and the Linux driver maps the region as "Memory Type". On Host
+Linux this works because MMU Stage-1 configured by driver allows
+unaligned access. In Virtual Machine cases, final region mapping type
+is governed by combination of Stage-1 and Stage-2 MMU mapping.
+
+Linux driver in VM controls maps the region as "Memory Type" in
+Stage-1 MMU while Stage-2 is controlled by KVM. And current KVM
+implementation does not allow device region to be mapped as
+"Memory Type". Till we have a working/upstream-able solution
+for Virtual Machine, we need to change un-aligned access in DPIO
+driver to be aligned
+
+While we reached to this point as we observed below alignment
+exception in Virtual Machine when accessing qbman cacheable region.
+
+  kvm [2347]: Unsupported FSC: EC=0x24 xFSC=0x21
+  ESR_EL2=0x92000061
+  error: kvm run failed Bad address
+  PC=ffff000008398e78  SP=ffff800009bcb540
+  X00=ffff000008041000 X01=ffff800009bcb580 X02=ffff800009bcb650
+  X03=0000000000000180
+  X04=ffff000008041001 X05=ffff800009bcb581 X06=0200000000000000
+  X07=0000000000000000
+  X08=0000000000000000 X09=ffff000008041000 X10=0000000000000001
+  X11=0000000000de6cb0
+  X12=00000000fa83b2da X13=0000000000000001 X14=000000007f605ec8
+  X15=00000000e26f5d5e
+  X16=000000008521af1e X17=000000001076277e X18=ffff800009bcb5c0
+  X19=ffff800079da2b00
+  X20=ffff800009bcb650 X21=0000000000000002 X22=0000000000000000
+  X23=0000000000000000
+  X24=0000000000000000 X25=ffff8000099e7440 X26=ffff000008da6000
+  X27=ffff000008e7f000
+  X28=00000000499e7440 X29=ffff800009bcb540 X30=ffff00000839a160
+  PSTATE=20000145 --C- EL1h
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+---
+ drivers/soc/fsl/dpio/qbman-portal.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/soc/fsl/dpio/qbman-portal.c
++++ b/drivers/soc/fsl/dpio/qbman-portal.c
+@@ -515,7 +515,17 @@ int qbman_swp_enqueue(struct qbman_swp *
+               return -EBUSY;
+       p = qbman_get_cmd(s, QBMAN_CENA_SWP_EQCR(EQAR_IDX(eqar)));
+-      memcpy(&p->dca, &d->dca, 31);
++      /* This is mapped as DEVICE type memory, writes are
++       * with address alignment:
++       * desc.dca address alignment = 1
++       * desc.seqnum address alignment = 2
++       * desc.orpid address alignment = 4
++       * desc.tgtid address alignment = 8
++       */
++      p->dca = d->dca;
++      p->seqnum = d->seqnum;
++      p->orpid = d->orpid;
++      memcpy(&p->tgtid, &d->tgtid, 24);
+       memcpy(&p->fd, fd, sizeof(*fd));
+       if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0156-staging-fsl-dpaa2-mac-Add-APIs-for-DPMAC-objects.patch b/target/linux/layerscape/patches-5.4/701-net-0156-staging-fsl-dpaa2-mac-Add-APIs-for-DPMAC-objects.patch
new file mode 100644 (file)
index 0000000..110d5da
--- /dev/null
@@ -0,0 +1,1162 @@
+From 344af44442388ea7f34cb4c4d88fa1162f8d4ddf Mon Sep 17 00:00:00 2001
+From: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+Date: Wed, 12 Apr 2017 12:38:57 +0000
+Subject: [PATCH] staging: fsl-dpaa2/mac: Add APIs for DPMAC objects
+
+Add the command build/parse APIs for operating on DPMAC
+objects through the DPAA2 Management Complex.
+
+Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
+Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/dpmac-cmd.h | 172 +++++++++
+ drivers/staging/fsl-dpaa2/mac/dpmac.c     | 620 ++++++++++++++++++++++++++++++
+ drivers/staging/fsl-dpaa2/mac/dpmac.h     | 342 ++++++++++++++++
+ 3 files changed, 1134 insertions(+)
+ create mode 100644 drivers/staging/fsl-dpaa2/mac/dpmac-cmd.h
+ create mode 100644 drivers/staging/fsl-dpaa2/mac/dpmac.c
+ create mode 100644 drivers/staging/fsl-dpaa2/mac/dpmac.h
+
+--- /dev/null
++++ b/drivers/staging/fsl-dpaa2/mac/dpmac-cmd.h
+@@ -0,0 +1,172 @@
++/* Copyright 2013-2016 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the name of the above-listed copyright holders nor the
++ * names of any contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++#ifndef _FSL_DPMAC_CMD_H
++#define _FSL_DPMAC_CMD_H
++
++/* DPMAC Version */
++#define DPMAC_VER_MAJOR                               4
++#define DPMAC_VER_MINOR                               2
++#define DPMAC_CMD_BASE_VERSION                        1
++#define DPMAC_CMD_ID_OFFSET                   4
++
++#define DPMAC_CMD(id) (((id) << DPMAC_CMD_ID_OFFSET) | DPMAC_CMD_BASE_VERSION)
++
++/* Command IDs */
++#define DPMAC_CMDID_CLOSE             DPMAC_CMD(0x800)
++#define DPMAC_CMDID_OPEN              DPMAC_CMD(0x80c)
++#define DPMAC_CMDID_CREATE            DPMAC_CMD(0x90c)
++#define DPMAC_CMDID_DESTROY           DPMAC_CMD(0x98c)
++#define DPMAC_CMDID_GET_API_VERSION   DPMAC_CMD(0xa0c)
++
++#define DPMAC_CMDID_GET_ATTR          DPMAC_CMD(0x004)
++#define DPMAC_CMDID_RESET             DPMAC_CMD(0x005)
++
++#define DPMAC_CMDID_SET_IRQ_ENABLE    DPMAC_CMD(0x012)
++#define DPMAC_CMDID_GET_IRQ_ENABLE    DPMAC_CMD(0x013)
++#define DPMAC_CMDID_SET_IRQ_MASK      DPMAC_CMD(0x014)
++#define DPMAC_CMDID_GET_IRQ_MASK      DPMAC_CMD(0x015)
++#define DPMAC_CMDID_GET_IRQ_STATUS    DPMAC_CMD(0x016)
++#define DPMAC_CMDID_CLEAR_IRQ_STATUS  DPMAC_CMD(0x017)
++
++#define DPMAC_CMDID_GET_LINK_CFG      DPMAC_CMD(0x0c2)
++#define DPMAC_CMDID_SET_LINK_STATE    DPMAC_CMD(0x0c3)
++#define DPMAC_CMDID_GET_COUNTER               DPMAC_CMD(0x0c4)
++
++#define DPMAC_CMDID_SET_PORT_MAC_ADDR DPMAC_CMD(0x0c5)
++
++/* Macros for accessing command fields smaller than 1byte */
++#define DPMAC_MASK(field)        \
++      GENMASK(DPMAC_##field##_SHIFT + DPMAC_##field##_SIZE - 1, \
++              DPMAC_##field##_SHIFT)
++#define dpmac_set_field(var, field, val) \
++      ((var) |= (((val) << DPMAC_##field##_SHIFT) & DPMAC_MASK(field)))
++#define dpmac_get_field(var, field)      \
++      (((var) & DPMAC_MASK(field)) >> DPMAC_##field##_SHIFT)
++
++struct dpmac_cmd_open {
++      u32 dpmac_id;
++};
++
++struct dpmac_cmd_create {
++      u32 mac_id;
++};
++
++struct dpmac_cmd_destroy {
++      u32 dpmac_id;
++};
++
++struct dpmac_cmd_set_irq_enable {
++      u8 enable;
++      u8 pad[3];
++      u8 irq_index;
++};
++
++struct dpmac_cmd_get_irq_enable {
++      u32 pad;
++      u8 irq_index;
++};
++
++struct dpmac_rsp_get_irq_enable {
++      u8 enabled;
++};
++
++struct dpmac_cmd_set_irq_mask {
++      u32 mask;
++      u8 irq_index;
++};
++
++struct dpmac_cmd_get_irq_mask {
++      u32 pad;
++      u8 irq_index;
++};
++
++struct dpmac_rsp_get_irq_mask {
++      u32 mask;
++};
++
++struct dpmac_cmd_get_irq_status {
++      u32 status;
++      u8 irq_index;
++};
++
++struct dpmac_rsp_get_irq_status {
++      u32 status;
++};
++
++struct dpmac_cmd_clear_irq_status {
++      u32 status;
++      u8 irq_index;
++};
++
++struct dpmac_rsp_get_attributes {
++      u8 eth_if;
++      u8 link_type;
++      u16 id;
++      u32 max_rate;
++};
++
++struct dpmac_rsp_get_link_cfg {
++      u64 options;
++      u32 rate;
++};
++
++#define DPMAC_STATE_SIZE      1
++#define DPMAC_STATE_SHIFT     0
++
++struct dpmac_cmd_set_link_state {
++      u64 options;
++      u32 rate;
++      u32 pad;
++      /* only least significant bit is valid */
++      u8 up;
++};
++
++struct dpmac_cmd_get_counter {
++      u8 type;
++};
++
++struct dpmac_rsp_get_counter {
++      u64 pad;
++      u64 counter;
++};
++
++struct dpmac_rsp_get_api_version {
++      u16 major;
++      u16 minor;
++};
++
++struct dpmac_cmd_set_port_mac_addr {
++      u8 pad[2];
++      u8 addr[6];
++};
++
++#endif /* _FSL_DPMAC_CMD_H */
+--- /dev/null
++++ b/drivers/staging/fsl-dpaa2/mac/dpmac.c
+@@ -0,0 +1,620 @@
++/* Copyright 2013-2016 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the name of the above-listed copyright holders nor the
++ * names of any contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++#include "../../fsl-mc/include/mc-sys.h"
++#include "../../fsl-mc/include/mc-cmd.h"
++#include "dpmac.h"
++#include "dpmac-cmd.h"
++
++/**
++ * dpmac_open() - Open a control session for the specified object.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @dpmac_id: DPMAC unique ID
++ * @token:    Returned token; use in subsequent API calls
++ *
++ * This function can be used to open a control session for an
++ * already created object; an object may have been declared in
++ * the DPL or by calling the dpmac_create function.
++ * This function returns a unique authentication token,
++ * associated with the specific object ID and the specific MC
++ * portal; this token must be used in all subsequent commands for
++ * this specific object
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpmac_open(struct fsl_mc_io *mc_io,
++             u32 cmd_flags,
++             int dpmac_id,
++             u16 *token)
++{
++      struct dpmac_cmd_open *cmd_params;
++      struct mc_command cmd = { 0 };
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_OPEN,
++                                        cmd_flags,
++                                        0);
++      cmd_params = (struct dpmac_cmd_open *)cmd.params;
++      cmd_params->dpmac_id = cpu_to_le32(dpmac_id);
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      *token = mc_cmd_hdr_read_token(&cmd);
++
++      return err;
++}
++
++/**
++ * dpmac_close() - Close the control session of the object
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPMAC object
++ *
++ * After this function is called, no further operations are
++ * allowed on the object without opening a new control session.
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpmac_close(struct fsl_mc_io *mc_io,
++              u32 cmd_flags,
++              u16 token)
++{
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CLOSE, cmd_flags,
++                                        token);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpmac_create() - Create the DPMAC object.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @dprc_token: Parent container token; '0' for default container
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @cfg:      Configuration structure
++ * @obj_id:   Returned object id
++ *
++ * Create the DPMAC object, allocate required resources and
++ * perform required initialization.
++ *
++ * The function accepts an authentication token of a parent
++ * container that this object should be assigned to. The token
++ * can be '0' so the object will be assigned to the default container.
++ * The newly created object can be opened with the returned
++ * object id and using the container's associated tokens and MC portals.
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpmac_create(struct fsl_mc_io *mc_io,
++               u16 dprc_token,
++               u32 cmd_flags,
++               const struct dpmac_cfg *cfg,
++               u32 *obj_id)
++{
++      struct dpmac_cmd_create *cmd_params;
++      struct mc_command cmd = { 0 };
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CREATE,
++                                        cmd_flags,
++                                        dprc_token);
++      cmd_params = (struct dpmac_cmd_create *)cmd.params;
++      cmd_params->mac_id = cpu_to_le32(cfg->mac_id);
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      *obj_id = mc_cmd_read_object_id(&cmd);
++
++      return 0;
++}
++
++/**
++ * dpmac_destroy() - Destroy the DPMAC object and release all its resources.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @dprc_token: Parent container token; '0' for default container
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @object_id:        The object id; it must be a valid id within the container that
++ * created this object;
++ *
++ * The function accepts the authentication token of the parent container that
++ * created the object (not the one that currently owns the object). The object
++ * is searched within parent using the provided 'object_id'.
++ * All tokens to the object must be closed before calling destroy.
++ *
++ * Return:    '0' on Success; error code otherwise.
++ */
++int dpmac_destroy(struct fsl_mc_io *mc_io,
++                u16 dprc_token,
++                u32 cmd_flags,
++                u32 object_id)
++{
++      struct dpmac_cmd_destroy *cmd_params;
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_DESTROY,
++                                        cmd_flags,
++                                        dprc_token);
++      cmd_params = (struct dpmac_cmd_destroy *)cmd.params;
++      cmd_params->dpmac_id = cpu_to_le32(object_id);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpmac_set_irq_enable() - Set overall interrupt state.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPMAC object
++ * @irq_index:        The interrupt index to configure
++ * @en:               Interrupt state - enable = 1, disable = 0
++ *
++ * Allows GPP software to control when interrupts are generated.
++ * Each interrupt can have up to 32 causes.  The enable/disable control's the
++ * overall interrupt state. if the interrupt is disabled no causes will cause
++ * an interrupt.
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpmac_set_irq_enable(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token,
++                       u8 irq_index,
++                       u8 en)
++{
++      struct dpmac_cmd_set_irq_enable *cmd_params;
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_IRQ_ENABLE,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpmac_cmd_set_irq_enable *)cmd.params;
++      cmd_params->irq_index = irq_index;
++      cmd_params->enable = en;
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpmac_get_irq_enable() - Get overall interrupt state
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPMAC object
++ * @irq_index:        The interrupt index to configure
++ * @en:               Returned interrupt state - enable = 1, disable = 0
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpmac_get_irq_enable(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token,
++                       u8 irq_index,
++                       u8 *en)
++{
++      struct dpmac_cmd_get_irq_enable *cmd_params;
++      struct dpmac_rsp_get_irq_enable *rsp_params;
++      struct mc_command cmd = { 0 };
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_IRQ_ENABLE,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpmac_cmd_get_irq_enable *)cmd.params;
++      cmd_params->irq_index = irq_index;
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      rsp_params = (struct dpmac_rsp_get_irq_enable *)cmd.params;
++      *en = rsp_params->enabled;
++
++      return 0;
++}
++
++/**
++ * dpmac_set_irq_mask() - Set interrupt mask.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPMAC object
++ * @irq_index:        The interrupt index to configure
++ * @mask:     Event mask to trigger interrupt;
++ *            each bit:
++ *                    0 = ignore event
++ *                    1 = consider event for asserting IRQ
++ *
++ * Every interrupt can have up to 32 causes and the interrupt model supports
++ * masking/unmasking each cause independently
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpmac_set_irq_mask(struct fsl_mc_io *mc_io,
++                     u32 cmd_flags,
++                     u16 token,
++                     u8 irq_index,
++                     u32 mask)
++{
++      struct dpmac_cmd_set_irq_mask *cmd_params;
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_IRQ_MASK,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpmac_cmd_set_irq_mask *)cmd.params;
++      cmd_params->mask = cpu_to_le32(mask);
++      cmd_params->irq_index = irq_index;
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpmac_get_irq_mask() - Get interrupt mask.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPMAC object
++ * @irq_index:        The interrupt index to configure
++ * @mask:     Returned event mask to trigger interrupt
++ *
++ * Every interrupt can have up to 32 causes and the interrupt model supports
++ * masking/unmasking each cause independently
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpmac_get_irq_mask(struct fsl_mc_io *mc_io,
++                     u32 cmd_flags,
++                     u16 token,
++                     u8 irq_index,
++                     u32 *mask)
++{
++      struct dpmac_cmd_get_irq_mask *cmd_params;
++      struct dpmac_rsp_get_irq_mask *rsp_params;
++      struct mc_command cmd = { 0 };
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_IRQ_MASK,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpmac_cmd_get_irq_mask *)cmd.params;
++      cmd_params->irq_index = irq_index;
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      rsp_params = (struct dpmac_rsp_get_irq_mask *)cmd.params;
++      *mask = le32_to_cpu(rsp_params->mask);
++
++      return 0;
++}
++
++/**
++ * dpmac_get_irq_status() - Get the current status of any pending interrupts.
++ *
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPMAC object
++ * @irq_index:        The interrupt index to configure
++ * @status:   Returned interrupts status - one bit per cause:
++ *                    0 = no interrupt pending
++ *                    1 = interrupt pending
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpmac_get_irq_status(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token,
++                       u8 irq_index,
++                       u32 *status)
++{
++      struct dpmac_cmd_get_irq_status *cmd_params;
++      struct dpmac_rsp_get_irq_status *rsp_params;
++      struct mc_command cmd = { 0 };
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_IRQ_STATUS,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpmac_cmd_get_irq_status *)cmd.params;
++      cmd_params->status = cpu_to_le32(*status);
++      cmd_params->irq_index = irq_index;
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      rsp_params = (struct dpmac_rsp_get_irq_status *)cmd.params;
++      *status = le32_to_cpu(rsp_params->status);
++
++      return 0;
++}
++
++/**
++ * dpmac_clear_irq_status() - Clear a pending interrupt's status
++ *
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPMAC object
++ * @irq_index:        The interrupt index to configure
++ * @status:   Bits to clear (W1C) - one bit per cause:
++ *                    0 = don't change
++ *                    1 = clear status bit
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpmac_clear_irq_status(struct fsl_mc_io *mc_io,
++                         u32 cmd_flags,
++                         u16 token,
++                         u8 irq_index,
++                         u32 status)
++{
++      struct dpmac_cmd_clear_irq_status *cmd_params;
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CLEAR_IRQ_STATUS,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpmac_cmd_clear_irq_status *)cmd.params;
++      cmd_params->status = cpu_to_le32(status);
++      cmd_params->irq_index = irq_index;
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpmac_get_attributes - Retrieve DPMAC attributes.
++ *
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPMAC object
++ * @attr:     Returned object's attributes
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpmac_get_attributes(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token,
++                       struct dpmac_attr *attr)
++{
++      struct dpmac_rsp_get_attributes *rsp_params;
++      struct mc_command cmd = { 0 };
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_ATTR,
++                                        cmd_flags,
++                                        token);
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      rsp_params = (struct dpmac_rsp_get_attributes *)cmd.params;
++      attr->eth_if = rsp_params->eth_if;
++      attr->link_type = rsp_params->link_type;
++      attr->id = le16_to_cpu(rsp_params->id);
++      attr->max_rate = le32_to_cpu(rsp_params->max_rate);
++
++      return 0;
++}
++
++/**
++ * dpmac_get_link_cfg() - Get Ethernet link configuration
++ * @mc_io:    Pointer to opaque I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPMAC object
++ * @cfg:      Returned structure with the link configuration
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpmac_get_link_cfg(struct fsl_mc_io *mc_io,
++                     u32 cmd_flags,
++                     u16 token,
++                     struct dpmac_link_cfg *cfg)
++{
++      struct dpmac_rsp_get_link_cfg *rsp_params;
++      struct mc_command cmd = { 0 };
++      int err = 0;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_LINK_CFG,
++                                        cmd_flags,
++                                        token);
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      rsp_params = (struct dpmac_rsp_get_link_cfg *)cmd.params;
++      cfg->options = le64_to_cpu(rsp_params->options);
++      cfg->rate = le32_to_cpu(rsp_params->rate);
++
++      return 0;
++}
++
++/**
++ * dpmac_set_link_state() - Set the Ethernet link status
++ * @mc_io:    Pointer to opaque I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPMAC object
++ * @link_state:       Link state configuration
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpmac_set_link_state(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token,
++                       struct dpmac_link_state *link_state)
++{
++      struct dpmac_cmd_set_link_state *cmd_params;
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_LINK_STATE,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpmac_cmd_set_link_state *)cmd.params;
++      cmd_params->options = cpu_to_le64(link_state->options);
++      cmd_params->rate = cpu_to_le32(link_state->rate);
++      cmd_params->up = dpmac_get_field(link_state->up, STATE);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpmac_get_counter() - Read a specific DPMAC counter
++ * @mc_io:    Pointer to opaque I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPMAC object
++ * @type:     The requested counter
++ * @counter:  Returned counter value
++ *
++ * Return:    The requested counter; '0' otherwise.
++ */
++int dpmac_get_counter(struct fsl_mc_io *mc_io,
++                    u32 cmd_flags,
++                    u16 token,
++                    enum dpmac_counter type,
++                    u64 *counter)
++{
++      struct dpmac_cmd_get_counter *dpmac_cmd;
++      struct dpmac_rsp_get_counter *dpmac_rsp;
++      struct mc_command cmd = { 0 };
++      int err = 0;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_COUNTER,
++                                        cmd_flags,
++                                        token);
++      dpmac_cmd = (struct dpmac_cmd_get_counter *)cmd.params;
++      dpmac_cmd->type = type;
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      dpmac_rsp = (struct dpmac_rsp_get_counter *)cmd.params;
++      *counter = le64_to_cpu(dpmac_rsp->counter);
++
++      return 0;
++}
++
++/* untested */
++int dpmac_set_port_mac_addr(struct fsl_mc_io *mc_io,
++                          u32 cmd_flags,
++                          u16 token,
++                          const u8 addr[6])
++{
++      struct dpmac_cmd_set_port_mac_addr *dpmac_cmd;
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_PORT_MAC_ADDR,
++                                        cmd_flags,
++                                        token);
++      dpmac_cmd = (struct dpmac_cmd_set_port_mac_addr *)cmd.params;
++      dpmac_cmd->addr[0] = addr[5];
++      dpmac_cmd->addr[1] = addr[4];
++      dpmac_cmd->addr[2] = addr[3];
++      dpmac_cmd->addr[3] = addr[2];
++      dpmac_cmd->addr[4] = addr[1];
++      dpmac_cmd->addr[5] = addr[0];
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpmac_get_api_version() - Get Data Path MAC version
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @major_ver:        Major version of data path mac API
++ * @minor_ver:        Minor version of data path mac API
++ *
++ * Return:  '0' on Success; Error code otherwise.
++ */
++int dpmac_get_api_version(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 *major_ver,
++                        u16 *minor_ver)
++{
++      struct dpmac_rsp_get_api_version *rsp_params;
++      struct mc_command cmd = { 0 };
++      int err;
++
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_API_VERSION,
++                                      cmd_flags,
++                                      0);
++
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      rsp_params = (struct dpmac_rsp_get_api_version *)cmd.params;
++      *major_ver = le16_to_cpu(rsp_params->major);
++      *minor_ver = le16_to_cpu(rsp_params->minor);
++
++      return 0;
++}
+--- /dev/null
++++ b/drivers/staging/fsl-dpaa2/mac/dpmac.h
+@@ -0,0 +1,342 @@
++/* Copyright 2013-2016 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the name of the above-listed copyright holders nor the
++ * names of any contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++#ifndef __FSL_DPMAC_H
++#define __FSL_DPMAC_H
++
++/* Data Path MAC API
++ * Contains initialization APIs and runtime control APIs for DPMAC
++ */
++
++struct fsl_mc_io;
++
++int dpmac_open(struct fsl_mc_io *mc_io,
++             u32 cmd_flags,
++             int dpmac_id,
++             u16 *token);
++
++int dpmac_close(struct fsl_mc_io *mc_io,
++              u32 cmd_flags,
++              u16 token);
++
++/**
++ * enum dpmac_link_type -  DPMAC link type
++ * @DPMAC_LINK_TYPE_NONE: No link
++ * @DPMAC_LINK_TYPE_FIXED: Link is fixed type
++ * @DPMAC_LINK_TYPE_PHY: Link by PHY ID
++ * @DPMAC_LINK_TYPE_BACKPLANE: Backplane link type
++ */
++enum dpmac_link_type {
++      DPMAC_LINK_TYPE_NONE,
++      DPMAC_LINK_TYPE_FIXED,
++      DPMAC_LINK_TYPE_PHY,
++      DPMAC_LINK_TYPE_BACKPLANE
++};
++
++/**
++ * enum dpmac_eth_if - DPMAC Ethrnet interface
++ * @DPMAC_ETH_IF_MII: MII interface
++ * @DPMAC_ETH_IF_RMII: RMII interface
++ * @DPMAC_ETH_IF_SMII: SMII interface
++ * @DPMAC_ETH_IF_GMII: GMII interface
++ * @DPMAC_ETH_IF_RGMII: RGMII interface
++ * @DPMAC_ETH_IF_SGMII: SGMII interface
++ * @DPMAC_ETH_IF_QSGMII: QSGMII interface
++ * @DPMAC_ETH_IF_XAUI: XAUI interface
++ * @DPMAC_ETH_IF_XFI: XFI interface
++ */
++enum dpmac_eth_if {
++      DPMAC_ETH_IF_MII,
++      DPMAC_ETH_IF_RMII,
++      DPMAC_ETH_IF_SMII,
++      DPMAC_ETH_IF_GMII,
++      DPMAC_ETH_IF_RGMII,
++      DPMAC_ETH_IF_SGMII,
++      DPMAC_ETH_IF_QSGMII,
++      DPMAC_ETH_IF_XAUI,
++      DPMAC_ETH_IF_XFI
++};
++
++/**
++ * struct dpmac_cfg - Structure representing DPMAC configuration
++ * @mac_id:   Represents the Hardware MAC ID; in case of multiple WRIOP,
++ *            the MAC IDs are continuous.
++ *            For example:  2 WRIOPs, 16 MACs in each:
++ *                            MAC IDs for the 1st WRIOP: 1-16,
++ *                            MAC IDs for the 2nd WRIOP: 17-32.
++ */
++struct dpmac_cfg {
++      u16 mac_id;
++};
++
++int dpmac_create(struct fsl_mc_io *mc_io,
++               u16 dprc_token,
++               u32 cmd_flags,
++               const struct dpmac_cfg *cfg,
++               u32 *obj_id);
++
++int dpmac_destroy(struct fsl_mc_io *mc_io,
++                u16 dprc_token,
++                u32 cmd_flags,
++                u32 object_id);
++
++/**
++ * DPMAC IRQ Index and Events
++ */
++
++/**
++ * IRQ index
++ */
++#define DPMAC_IRQ_INDEX                               0
++/**
++ * IRQ event - indicates a change in link state
++ */
++#define DPMAC_IRQ_EVENT_LINK_CFG_REQ          0x00000001
++/**
++ * IRQ event - Indicates that the link state changed
++ */
++#define DPMAC_IRQ_EVENT_LINK_CHANGED          0x00000002
++
++int dpmac_set_irq_enable(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token,
++                       u8 irq_index,
++                       u8 en);
++
++int dpmac_get_irq_enable(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token,
++                       u8 irq_index,
++                       u8 *en);
++
++int dpmac_set_irq_mask(struct fsl_mc_io *mc_io,
++                     u32 cmd_flags,
++                     u16 token,
++                     u8 irq_index,
++                     u32 mask);
++
++int dpmac_get_irq_mask(struct fsl_mc_io *mc_io,
++                     u32 cmd_flags,
++                     u16 token,
++                     u8 irq_index,
++                     u32 *mask);
++
++int dpmac_get_irq_status(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token,
++                       u8 irq_index,
++                       u32 *status);
++
++int dpmac_clear_irq_status(struct fsl_mc_io *mc_io,
++                         u32 cmd_flags,
++                         u16 token,
++                         u8 irq_index,
++                         u32 status);
++
++/**
++ * struct dpmac_attr - Structure representing DPMAC attributes
++ * @id:               DPMAC object ID
++ * @max_rate: Maximum supported rate - in Mbps
++ * @eth_if:   Ethernet interface
++ * @link_type:        link type
++ */
++struct dpmac_attr {
++      u16 id;
++      u32 max_rate;
++      enum dpmac_eth_if eth_if;
++      enum dpmac_link_type link_type;
++};
++
++int dpmac_get_attributes(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token,
++                       struct dpmac_attr *attr);
++
++/**
++ * DPMAC link configuration/state options
++ */
++
++/**
++ * Enable auto-negotiation
++ */
++#define DPMAC_LINK_OPT_AUTONEG                0x0000000000000001ULL
++/**
++ * Enable half-duplex mode
++ */
++#define DPMAC_LINK_OPT_HALF_DUPLEX    0x0000000000000002ULL
++/**
++ * Enable pause frames
++ */
++#define DPMAC_LINK_OPT_PAUSE          0x0000000000000004ULL
++/**
++ * Enable a-symmetric pause frames
++ */
++#define DPMAC_LINK_OPT_ASYM_PAUSE     0x0000000000000008ULL
++
++/**
++ * struct dpmac_link_cfg - Structure representing DPMAC link configuration
++ * @rate: Link's rate - in Mbps
++ * @options: Enable/Disable DPMAC link cfg features (bitmap)
++ */
++struct dpmac_link_cfg {
++      u32 rate;
++      u64 options;
++};
++
++int dpmac_get_link_cfg(struct fsl_mc_io *mc_io,
++                     u32 cmd_flags,
++                     u16 token,
++                     struct dpmac_link_cfg *cfg);
++
++/**
++ * struct dpmac_link_state - DPMAC link configuration request
++ * @rate: Rate in Mbps
++ * @options: Enable/Disable DPMAC link cfg features (bitmap)
++ * @up: Link state
++ */
++struct dpmac_link_state {
++      u32 rate;
++      u64 options;
++      int up;
++};
++
++int dpmac_set_link_state(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token,
++                       struct dpmac_link_state *link_state);
++
++/**
++ * enum dpmac_counter - DPMAC counter types
++ * @DPMAC_CNT_ING_FRAME_64: counts 64-bytes frames, good or bad.
++ * @DPMAC_CNT_ING_FRAME_127: counts 65- to 127-bytes frames, good or bad.
++ * @DPMAC_CNT_ING_FRAME_255: counts 128- to 255-bytes frames, good or bad.
++ * @DPMAC_CNT_ING_FRAME_511: counts 256- to 511-bytes frames, good or bad.
++ * @DPMAC_CNT_ING_FRAME_1023: counts 512- to 1023-bytes frames, good or bad.
++ * @DPMAC_CNT_ING_FRAME_1518: counts 1024- to 1518-bytes frames, good or bad.
++ * @DPMAC_CNT_ING_FRAME_1519_MAX: counts 1519-bytes frames and larger
++ *                              (up to max frame length specified),
++ *                              good or bad.
++ * @DPMAC_CNT_ING_FRAG: counts frames which are shorter than 64 bytes received
++ *                    with a wrong CRC
++ * @DPMAC_CNT_ING_JABBER: counts frames longer than the maximum frame length
++ *                      specified, with a bad frame check sequence.
++ * @DPMAC_CNT_ING_FRAME_DISCARD: counts dropped frames due to internal errors.
++ *                             Occurs when a receive FIFO overflows.
++ *                             Includes also frames truncated as a result of
++ *                             the receive FIFO overflow.
++ * @DPMAC_CNT_ING_ALIGN_ERR: counts frames with an alignment error
++ *                         (optional used for wrong SFD).
++ * @DPMAC_CNT_EGR_UNDERSIZED: counts frames transmitted that was less than 64
++ *                          bytes long with a good CRC.
++ * @DPMAC_CNT_ING_OVERSIZED: counts frames longer than the maximum frame length
++ *                         specified, with a good frame check sequence.
++ * @DPMAC_CNT_ING_VALID_PAUSE_FRAME: counts valid pause frames (regular and PFC)
++ * @DPMAC_CNT_EGR_VALID_PAUSE_FRAME: counts valid pause frames transmitted
++ *                                 (regular and PFC).
++ * @DPMAC_CNT_ING_BYTE: counts bytes received except preamble for all valid
++ *                    frames and valid pause frames.
++ * @DPMAC_CNT_ING_MCAST_FRAME: counts received multicast frames.
++ * @DPMAC_CNT_ING_BCAST_FRAME: counts received broadcast frames.
++ * @DPMAC_CNT_ING_ALL_FRAME: counts each good or bad frames received.
++ * @DPMAC_CNT_ING_UCAST_FRAME: counts received unicast frames.
++ * @DPMAC_CNT_ING_ERR_FRAME: counts frames received with an error
++ *                         (except for undersized/fragment frame).
++ * @DPMAC_CNT_EGR_BYTE: counts bytes transmitted except preamble for all valid
++ *                    frames and valid pause frames transmitted.
++ * @DPMAC_CNT_EGR_MCAST_FRAME: counts transmitted multicast frames.
++ * @DPMAC_CNT_EGR_BCAST_FRAME: counts transmitted broadcast frames.
++ * @DPMAC_CNT_EGR_UCAST_FRAME: counts transmitted unicast frames.
++ * @DPMAC_CNT_EGR_ERR_FRAME: counts frames transmitted with an error.
++ * @DPMAC_CNT_ING_GOOD_FRAME: counts frames received without error, including
++ *                          pause frames.
++ * @DPMAC_CNT_ENG_GOOD_FRAME: counts frames transmitted without error, including
++ *                          pause frames.
++ */
++enum dpmac_counter {
++      DPMAC_CNT_ING_FRAME_64,
++      DPMAC_CNT_ING_FRAME_127,
++      DPMAC_CNT_ING_FRAME_255,
++      DPMAC_CNT_ING_FRAME_511,
++      DPMAC_CNT_ING_FRAME_1023,
++      DPMAC_CNT_ING_FRAME_1518,
++      DPMAC_CNT_ING_FRAME_1519_MAX,
++      DPMAC_CNT_ING_FRAG,
++      DPMAC_CNT_ING_JABBER,
++      DPMAC_CNT_ING_FRAME_DISCARD,
++      DPMAC_CNT_ING_ALIGN_ERR,
++      DPMAC_CNT_EGR_UNDERSIZED,
++      DPMAC_CNT_ING_OVERSIZED,
++      DPMAC_CNT_ING_VALID_PAUSE_FRAME,
++      DPMAC_CNT_EGR_VALID_PAUSE_FRAME,
++      DPMAC_CNT_ING_BYTE,
++      DPMAC_CNT_ING_MCAST_FRAME,
++      DPMAC_CNT_ING_BCAST_FRAME,
++      DPMAC_CNT_ING_ALL_FRAME,
++      DPMAC_CNT_ING_UCAST_FRAME,
++      DPMAC_CNT_ING_ERR_FRAME,
++      DPMAC_CNT_EGR_BYTE,
++      DPMAC_CNT_EGR_MCAST_FRAME,
++      DPMAC_CNT_EGR_BCAST_FRAME,
++      DPMAC_CNT_EGR_UCAST_FRAME,
++      DPMAC_CNT_EGR_ERR_FRAME,
++      DPMAC_CNT_ING_GOOD_FRAME,
++      DPMAC_CNT_ENG_GOOD_FRAME
++};
++
++int dpmac_get_counter(struct fsl_mc_io *mc_io,
++                    u32 cmd_flags,
++                    u16 token,
++                    enum dpmac_counter type,
++                    u64 *counter);
++
++/**
++ * dpmac_set_port_mac_addr() - Set a MAC address associated with the physical
++ *              port.  This is not used for filtering, MAC is always in
++ *              promiscuous mode, it is passed to DPNIs through DPNI API for
++ *              application used.
++ * @mc_io:    Pointer to opaque I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPMAC object
++ * @addr:     MAC address to set
++ *
++ * Return:    The requested counter; '0' otherwise.
++ */
++int dpmac_set_port_mac_addr(struct fsl_mc_io *mc_io,
++                          u32 cmd_flags,
++                          u16 token,
++                          const u8 addr[6]);
++
++int dpmac_get_api_version(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 *major_ver,
++                        u16 *minor_ver);
++
++#endif /* __FSL_DPMAC_H */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0157-staging-fsl-dpaa2-mac-Add-Freescale-DPAA2-mac-driver.patch b/target/linux/layerscape/patches-5.4/701-net-0157-staging-fsl-dpaa2-mac-Add-Freescale-DPAA2-mac-driver.patch
new file mode 100644 (file)
index 0000000..750c6ce
--- /dev/null
@@ -0,0 +1,765 @@
+From 50ba3c63dc3f4fbeac32fc5675a00756723d786d Mon Sep 17 00:00:00 2001
+From: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+Date: Wed, 12 Apr 2017 12:42:07 +0000
+Subject: [PATCH] staging: fsl-dpaa2/mac: Add Freescale DPAA2 mac driver
+
+Introduce the DPAA2 mac driver, which manages Datapath
+Media Access Control (DPMAC) objects discovered on the
+MC bus.
+
+This driver works as a proxy between phylib including phy
+drivers and the Management Complex firmware. It receives
+updates on link state changes from PHY lib and forwards
+them to the Management Complex and receives interrupts
+from the Management Complex whenever a request is made to
+change the link state.
+
+This is a squashed commit containing contributions of the
+following owners:
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
+Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+Signed-off-by: Stuart Yoder <stuart.yoder@freescale.com>
+Signed-off-by: J. German Rivera <German.Rivera@freescale.com>
+Signed-off-by: Itai Katz <itai.katz@freescale.com>
+
+Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/Kconfig      |   2 +
+ drivers/staging/fsl-dpaa2/Makefile     |   1 +
+ drivers/staging/fsl-dpaa2/mac/Kconfig  |  23 ++
+ drivers/staging/fsl-dpaa2/mac/Makefile |  10 +
+ drivers/staging/fsl-dpaa2/mac/mac.c    | 670 +++++++++++++++++++++++++++++++++
+ 5 files changed, 706 insertions(+)
+ create mode 100644 drivers/staging/fsl-dpaa2/mac/Kconfig
+ create mode 100644 drivers/staging/fsl-dpaa2/mac/Makefile
+ create mode 100644 drivers/staging/fsl-dpaa2/mac/mac.c
+
+--- a/drivers/staging/fsl-dpaa2/Kconfig
++++ b/drivers/staging/fsl-dpaa2/Kconfig
+@@ -17,3 +17,5 @@ config FSL_DPAA2_ETHSW
+       help
+         Driver for Freescale DPAA2 Ethernet Switch. Select
+         BRIDGE to have support for bridge tools.
++
++source "drivers/staging/fsl-dpaa2/mac/Kconfig"
+--- a/drivers/staging/fsl-dpaa2/Makefile
++++ b/drivers/staging/fsl-dpaa2/Makefile
+@@ -4,3 +4,4 @@
+ #
+ obj-$(CONFIG_FSL_DPAA2_ETHSW)         += ethsw/
++obj-$(CONFIG_FSL_DPAA2_MAC)           += mac/
+--- /dev/null
++++ b/drivers/staging/fsl-dpaa2/mac/Kconfig
+@@ -0,0 +1,23 @@
++config FSL_DPAA2_MAC
++      tristate "DPAA2 MAC / PHY interface"
++      depends on FSL_MC_BUS && FSL_DPAA2
++      select MDIO_BUS_MUX_MMIOREG
++      select FSL_XGMAC_MDIO
++      select FIXED_PHY
++      ---help---
++      Prototype driver for DPAA2 MAC / PHY interface object.
++      This driver works as a proxy between phylib including phy drivers and
++      the MC firmware.  It receives updates on link state changes from PHY
++      lib and forwards them to MC and receives interrupt from MC whenever
++      a request is made to change the link state.
++
++
++config FSL_DPAA2_MAC_NETDEVS
++      bool "Expose net interfaces for PHYs"
++      default n
++      depends on FSL_DPAA2_MAC
++      ---help---
++      Exposes macX net interfaces which allow direct control over MACs and
++      PHYs.
++      .
++      Leave disabled if unsure.
+--- /dev/null
++++ b/drivers/staging/fsl-dpaa2/mac/Makefile
+@@ -0,0 +1,10 @@
++
++obj-$(CONFIG_FSL_DPAA2_MAC) += dpaa2-mac.o
++
++dpaa2-mac-objs := mac.o dpmac.o
++
++all:
++      make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
++
++clean:
++      make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
+--- /dev/null
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -0,0 +1,670 @@
++/* Copyright 2015 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/module.h>
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/msi.h>
++#include <linux/rtnetlink.h>
++#include <linux/if_vlan.h>
++
++#include <uapi/linux/if_bridge.h>
++#include <net/netlink.h>
++
++#include <linux/of.h>
++#include <linux/of_mdio.h>
++#include <linux/of_net.h>
++#include <linux/phy.h>
++#include <linux/phy_fixed.h>
++
++#include "../../fsl-mc/include/mc.h"
++#include "../../fsl-mc/include/mc-sys.h"
++
++#include "dpmac.h"
++#include "dpmac-cmd.h"
++
++struct dpaa2_mac_priv {
++      struct net_device               *netdev;
++      struct fsl_mc_device            *mc_dev;
++      struct dpmac_attr               attr;
++      struct dpmac_link_state         old_state;
++};
++
++/* TODO: fix the 10G modes, mapping can't be right:
++ *  XGMII is paralel
++ *  XAUI is serial, using 8b/10b encoding
++ *  XFI is also serial but using 64b/66b encoding
++ * they can't all map to XGMII...
++ *
++ * This must be kept in sync with enum dpmac_eth_if.
++ */
++static phy_interface_t dpaa2_mac_iface_mode[] =  {
++      PHY_INTERFACE_MODE_MII,         /* DPMAC_ETH_IF_MII */
++      PHY_INTERFACE_MODE_RMII,        /* DPMAC_ETH_IF_RMII */
++      PHY_INTERFACE_MODE_SMII,        /* DPMAC_ETH_IF_SMII */
++      PHY_INTERFACE_MODE_GMII,        /* DPMAC_ETH_IF_GMII */
++      PHY_INTERFACE_MODE_RGMII,       /* DPMAC_ETH_IF_RGMII */
++      PHY_INTERFACE_MODE_SGMII,       /* DPMAC_ETH_IF_SGMII */
++      PHY_INTERFACE_MODE_QSGMII,      /* DPMAC_ETH_IF_QSGMII */
++      PHY_INTERFACE_MODE_XGMII,       /* DPMAC_ETH_IF_XAUI */
++      PHY_INTERFACE_MODE_XGMII,       /* DPMAC_ETH_IF_XFI */
++};
++
++static void dpaa2_mac_link_changed(struct net_device *netdev)
++{
++      struct phy_device       *phydev;
++      struct dpmac_link_state state = { 0 };
++      struct dpaa2_mac_priv   *priv = netdev_priv(netdev);
++      int                     err;
++
++      /* the PHY just notified us of link state change */
++      phydev = netdev->phydev;
++
++      state.up = !!phydev->link;
++      if (phydev->link) {
++              state.rate = phydev->speed;
++
++              if (!phydev->duplex)
++                      state.options |= DPMAC_LINK_OPT_HALF_DUPLEX;
++              if (phydev->autoneg)
++                      state.options |= DPMAC_LINK_OPT_AUTONEG;
++
++              netif_carrier_on(netdev);
++      } else {
++              netif_carrier_off(netdev);
++      }
++
++      if (priv->old_state.up != state.up ||
++          priv->old_state.rate != state.rate ||
++          priv->old_state.options != state.options) {
++              priv->old_state = state;
++              phy_print_status(phydev);
++      }
++
++      /* We must interrogate MC at all times, because we don't know
++       * when and whether a potential DPNI may have read the link state.
++       */
++      err = dpmac_set_link_state(priv->mc_dev->mc_io, 0,
++                                 priv->mc_dev->mc_handle, &state);
++      if (unlikely(err))
++              dev_err(&priv->mc_dev->dev, "dpmac_set_link_state: %d\n", err);
++}
++
++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
++static netdev_tx_t dpaa2_mac_drop_frame(struct sk_buff *skb,
++                                      struct net_device *dev)
++{
++      /* we don't support I/O for now, drop the frame */
++      dev_kfree_skb_any(skb);
++      return NETDEV_TX_OK;
++}
++
++static int dpaa2_mac_open(struct net_device *netdev)
++{
++      /* start PHY state machine */
++      phy_start(netdev->phydev);
++
++      return 0;
++}
++
++static int dpaa2_mac_stop(struct net_device *netdev)
++{
++      if (!netdev->phydev)
++              goto done;
++
++      /* stop PHY state machine */
++      phy_stop(netdev->phydev);
++
++      /* signal link down to firmware */
++      netdev->phydev->link = 0;
++      dpaa2_mac_link_changed(netdev);
++
++done:
++      return 0;
++}
++
++static int dpaa2_mac_get_settings(struct net_device *netdev,
++                                struct ethtool_cmd *cmd)
++{
++      return phy_ethtool_gset(netdev->phydev, cmd);
++}
++
++static int dpaa2_mac_set_settings(struct net_device *netdev,
++                                struct ethtool_cmd *cmd)
++{
++      return phy_ethtool_sset(netdev->phydev, cmd);
++}
++
++static void dpaa2_mac_get_stats(struct net_device *netdev,
++                              struct rtnl_link_stats64 *storage)
++{
++      struct dpaa2_mac_priv   *priv = netdev_priv(netdev);
++      u64                     tmp;
++      int                     err;
++
++      err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++                              DPMAC_CNT_EGR_MCAST_FRAME,
++                              &storage->tx_packets);
++      if (err)
++              goto error;
++      err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++                              DPMAC_CNT_EGR_BCAST_FRAME, &tmp);
++      if (err)
++              goto error;
++      storage->tx_packets += tmp;
++      err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++                              DPMAC_CNT_EGR_UCAST_FRAME, &tmp);
++      if (err)
++              goto error;
++      storage->tx_packets += tmp;
++
++      err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++                              DPMAC_CNT_EGR_UNDERSIZED, &storage->tx_dropped);
++      if (err)
++              goto error;
++      err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++                              DPMAC_CNT_EGR_BYTE, &storage->tx_bytes);
++      if (err)
++              goto error;
++      err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++                              DPMAC_CNT_EGR_ERR_FRAME, &storage->tx_errors);
++      if (err)
++              goto error;
++
++      err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++                              DPMAC_CNT_ING_ALL_FRAME, &storage->rx_packets);
++      if (err)
++              goto error;
++      err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++                              DPMAC_CNT_ING_MCAST_FRAME, &storage->multicast);
++      if (err)
++              goto error;
++      err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++                              DPMAC_CNT_ING_FRAME_DISCARD,
++                              &storage->rx_dropped);
++      if (err)
++              goto error;
++      err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++                              DPMAC_CNT_ING_ALIGN_ERR, &storage->rx_errors);
++      if (err)
++              goto error;
++      err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++                              DPMAC_CNT_ING_OVERSIZED, &tmp);
++      if (err)
++              goto error;
++      storage->rx_errors += tmp;
++      err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle,
++                              DPMAC_CNT_ING_BYTE, &storage->rx_bytes);
++      if (err)
++              goto error;
++
++      return;
++error:
++      netdev_err(netdev, "dpmac_get_counter err %d\n", err);
++}
++
++static struct {
++      enum dpmac_counter id;
++      char name[ETH_GSTRING_LEN];
++} dpaa2_mac_counters[] =  {
++      {DPMAC_CNT_ING_ALL_FRAME,               "rx all frames"},
++      {DPMAC_CNT_ING_GOOD_FRAME,              "rx frames ok"},
++      {DPMAC_CNT_ING_ERR_FRAME,               "rx frame errors"},
++      {DPMAC_CNT_ING_FRAME_DISCARD,           "rx frame discards"},
++      {DPMAC_CNT_ING_UCAST_FRAME,             "rx u-cast"},
++      {DPMAC_CNT_ING_BCAST_FRAME,             "rx b-cast"},
++      {DPMAC_CNT_ING_MCAST_FRAME,             "rx m-cast"},
++      {DPMAC_CNT_ING_FRAME_64,                "rx 64 bytes"},
++      {DPMAC_CNT_ING_FRAME_127,               "rx 65-127 bytes"},
++      {DPMAC_CNT_ING_FRAME_255,               "rx 128-255 bytes"},
++      {DPMAC_CNT_ING_FRAME_511,               "rx 256-511 bytes"},
++      {DPMAC_CNT_ING_FRAME_1023,              "rx 512-1023 bytes"},
++      {DPMAC_CNT_ING_FRAME_1518,              "rx 1024-1518 bytes"},
++      {DPMAC_CNT_ING_FRAME_1519_MAX,          "rx 1519-max bytes"},
++      {DPMAC_CNT_ING_FRAG,                    "rx frags"},
++      {DPMAC_CNT_ING_JABBER,                  "rx jabber"},
++      {DPMAC_CNT_ING_ALIGN_ERR,               "rx align errors"},
++      {DPMAC_CNT_ING_OVERSIZED,               "rx oversized"},
++      {DPMAC_CNT_ING_VALID_PAUSE_FRAME,       "rx pause"},
++      {DPMAC_CNT_ING_BYTE,                    "rx bytes"},
++      {DPMAC_CNT_ENG_GOOD_FRAME,              "tx frames ok"},
++      {DPMAC_CNT_EGR_UCAST_FRAME,             "tx u-cast"},
++      {DPMAC_CNT_EGR_MCAST_FRAME,             "tx m-cast"},
++      {DPMAC_CNT_EGR_BCAST_FRAME,             "tx b-cast"},
++      {DPMAC_CNT_EGR_ERR_FRAME,               "tx frame errors"},
++      {DPMAC_CNT_EGR_UNDERSIZED,              "tx undersized"},
++      {DPMAC_CNT_EGR_VALID_PAUSE_FRAME,       "tx b-pause"},
++      {DPMAC_CNT_EGR_BYTE,                    "tx bytes"},
++
++};
++
++static void dpaa2_mac_get_strings(struct net_device *netdev,
++                                u32 stringset, u8 *data)
++{
++      int i;
++
++      switch (stringset) {
++      case ETH_SS_STATS:
++              for (i = 0; i < ARRAY_SIZE(dpaa2_mac_counters); i++)
++                      memcpy(data + i * ETH_GSTRING_LEN,
++                             dpaa2_mac_counters[i].name,
++                             ETH_GSTRING_LEN);
++              break;
++      }
++}
++
++static void dpaa2_mac_get_ethtool_stats(struct net_device *netdev,
++                                      struct ethtool_stats *stats,
++                                      u64 *data)
++{
++      struct dpaa2_mac_priv   *priv = netdev_priv(netdev);
++      int                     i;
++      int                     err;
++
++      for (i = 0; i < ARRAY_SIZE(dpaa2_mac_counters); i++) {
++              err = dpmac_get_counter(priv->mc_dev->mc_io,
++                                      0,
++                                      priv->mc_dev->mc_handle,
++                                      dpaa2_mac_counters[i].id, &data[i]);
++              if (err)
++                      netdev_err(netdev, "dpmac_get_counter[%s] err %d\n",
++                                 dpaa2_mac_counters[i].name, err);
++      }
++}
++
++static int dpaa2_mac_get_sset_count(struct net_device *dev, int sset)
++{
++      switch (sset) {
++      case ETH_SS_STATS:
++              return ARRAY_SIZE(dpaa2_mac_counters);
++      default:
++              return -EOPNOTSUPP;
++      }
++}
++
++static const struct net_device_ops dpaa2_mac_ndo_ops = {
++      .ndo_start_xmit         = &dpaa2_mac_drop_frame,
++      .ndo_open               = &dpaa2_mac_open,
++      .ndo_stop               = &dpaa2_mac_stop,
++      .ndo_get_stats64        = &dpaa2_mac_get_stats,
++};
++
++static const struct ethtool_ops dpaa2_mac_ethtool_ops = {
++      .get_settings           = &dpaa2_mac_get_settings,
++      .set_settings           = &dpaa2_mac_set_settings,
++      .get_strings            = &dpaa2_mac_get_strings,
++      .get_ethtool_stats      = &dpaa2_mac_get_ethtool_stats,
++      .get_sset_count         = &dpaa2_mac_get_sset_count,
++};
++#endif /* CONFIG_FSL_DPAA2_MAC_NETDEVS */
++
++static void configure_link(struct dpaa2_mac_priv *priv,
++                         struct dpmac_link_cfg *cfg)
++{
++      struct phy_device *phydev = priv->netdev->phydev;
++
++      if (unlikely(!phydev))
++              return;
++
++      phydev->speed = cfg->rate;
++      phydev->duplex  = !!(cfg->options & DPMAC_LINK_OPT_HALF_DUPLEX);
++
++      if (cfg->options & DPMAC_LINK_OPT_AUTONEG) {
++              phydev->autoneg = 1;
++              phydev->advertising |= ADVERTISED_Autoneg;
++      } else {
++              phydev->autoneg = 0;
++              phydev->advertising &= ~ADVERTISED_Autoneg;
++      }
++
++      phy_start_aneg(phydev);
++}
++
++static irqreturn_t dpaa2_mac_irq_handler(int irq_num, void *arg)
++{
++      struct device *dev = (struct device *)arg;
++      struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
++      struct dpaa2_mac_priv *priv = dev_get_drvdata(dev);
++      struct dpmac_link_cfg link_cfg;
++      u32 status;
++      int err;
++
++      err = dpmac_get_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle,
++                                 DPMAC_IRQ_INDEX, &status);
++      if (unlikely(err || !status))
++              return IRQ_NONE;
++
++      /* DPNI-initiated link configuration; 'ifconfig up' also calls this */
++      if (status & DPMAC_IRQ_EVENT_LINK_CFG_REQ) {
++              err = dpmac_get_link_cfg(mc_dev->mc_io, 0, mc_dev->mc_handle,
++                                       &link_cfg);
++              if (unlikely(err))
++                      goto out;
++
++              configure_link(priv, &link_cfg);
++      }
++
++out:
++      dpmac_clear_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle,
++                             DPMAC_IRQ_INDEX, status);
++
++      return IRQ_HANDLED;
++}
++
++static int setup_irqs(struct fsl_mc_device *mc_dev)
++{
++      int err = 0;
++      struct fsl_mc_device_irq *irq;
++
++      err = fsl_mc_allocate_irqs(mc_dev);
++      if (err) {
++              dev_err(&mc_dev->dev, "fsl_mc_allocate_irqs err %d\n", err);
++              return err;
++      }
++
++      irq = mc_dev->irqs[0];
++      err = devm_request_threaded_irq(&mc_dev->dev, irq->msi_desc->irq,
++                                      NULL, &dpaa2_mac_irq_handler,
++                                      IRQF_NO_SUSPEND | IRQF_ONESHOT,
++                                      dev_name(&mc_dev->dev), &mc_dev->dev);
++      if (err) {
++              dev_err(&mc_dev->dev, "devm_request_threaded_irq err %d\n",
++                      err);
++              goto free_irq;
++      }
++
++      err = dpmac_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle,
++                               DPMAC_IRQ_INDEX, DPMAC_IRQ_EVENT_LINK_CFG_REQ);
++      if (err) {
++              dev_err(&mc_dev->dev, "dpmac_set_irq_mask err %d\n", err);
++              goto free_irq;
++      }
++      err = dpmac_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle,
++                                 DPMAC_IRQ_INDEX, 1);
++      if (err) {
++              dev_err(&mc_dev->dev, "dpmac_set_irq_enable err %d\n", err);
++              goto free_irq;
++      }
++
++      return 0;
++
++free_irq:
++      fsl_mc_free_irqs(mc_dev);
++
++      return err;
++}
++
++static void teardown_irqs(struct fsl_mc_device *mc_dev)
++{
++      int err;
++
++      err = dpmac_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle,
++                                 DPMAC_IRQ_INDEX, 0);
++      if (err)
++              dev_err(&mc_dev->dev, "dpmac_set_irq_enable err %d\n", err);
++
++      fsl_mc_free_irqs(mc_dev);
++}
++
++static struct device_node *find_dpmac_node(struct device *dev, u16 dpmac_id)
++{
++      struct device_node *dpmacs, *dpmac = NULL;
++      struct device_node *mc_node = dev->of_node;
++      u32 id;
++      int err;
++
++      dpmacs = of_find_node_by_name(mc_node, "dpmacs");
++      if (!dpmacs) {
++              dev_err(dev, "No dpmacs subnode in device-tree\n");
++              return NULL;
++      }
++
++      while ((dpmac = of_get_next_child(dpmacs, dpmac))) {
++              err = of_property_read_u32(dpmac, "reg", &id);
++              if (err)
++                      continue;
++              if (id == dpmac_id)
++                      return dpmac;
++      }
++
++      return NULL;
++}
++
++static int dpaa2_mac_probe(struct fsl_mc_device *mc_dev)
++{
++      struct device           *dev;
++      struct dpaa2_mac_priv   *priv = NULL;
++      struct device_node      *phy_node, *dpmac_node;
++      struct net_device       *netdev;
++      phy_interface_t         if_mode;
++      int                     err = 0;
++
++      dev = &mc_dev->dev;
++
++      /* prepare a net_dev structure to make the phy lib API happy */
++      netdev = alloc_etherdev(sizeof(*priv));
++      if (!netdev) {
++              dev_err(dev, "alloc_etherdev error\n");
++              err = -ENOMEM;
++              goto err_exit;
++      }
++      priv = netdev_priv(netdev);
++      priv->mc_dev = mc_dev;
++      priv->netdev = netdev;
++
++      SET_NETDEV_DEV(netdev, dev);
++
++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
++      snprintf(netdev->name, IFNAMSIZ, "mac%d", mc_dev->obj_desc.id);
++#endif
++
++      dev_set_drvdata(dev, priv);
++
++      err = fsl_mc_portal_allocate(mc_dev, 0, &mc_dev->mc_io);
++      if (err || !mc_dev->mc_io) {
++              dev_err(dev, "fsl_mc_portal_allocate error: %d\n", err);
++              err = -ENODEV;
++              goto err_free_netdev;
++      }
++
++      err = dpmac_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id,
++                       &mc_dev->mc_handle);
++      if (err || !mc_dev->mc_handle) {
++              dev_err(dev, "dpmac_open error: %d\n", err);
++              err = -ENODEV;
++              goto err_free_mcp;
++      }
++
++      err = dpmac_get_attributes(mc_dev->mc_io, 0,
++                                 mc_dev->mc_handle, &priv->attr);
++      if (err) {
++              dev_err(dev, "dpmac_get_attributes err %d\n", err);
++              err = -EINVAL;
++              goto err_close;
++      }
++
++      /* Look up the DPMAC node in the device-tree. */
++      dpmac_node = find_dpmac_node(dev, priv->attr.id);
++      if (!dpmac_node) {
++              dev_err(dev, "No dpmac@%d subnode found.\n", priv->attr.id);
++              err = -ENODEV;
++              goto err_close;
++      }
++
++      err = setup_irqs(mc_dev);
++      if (err) {
++              err = -EFAULT;
++              goto err_close;
++      }
++
++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
++      /* OPTIONAL, register netdev just to make it visible to the user */
++      netdev->netdev_ops = &dpaa2_mac_ndo_ops;
++      netdev->ethtool_ops = &dpaa2_mac_ethtool_ops;
++
++      /* phy starts up enabled so netdev should be up too */
++      netdev->flags |= IFF_UP;
++
++      err = register_netdev(priv->netdev);
++      if (err < 0) {
++              dev_err(dev, "register_netdev error %d\n", err);
++              err = -ENODEV;
++              goto err_free_irq;
++      }
++#endif /* CONFIG_FSL_DPAA2_MAC_NETDEVS */
++
++      /* probe the PHY as a fixed-link if the link type declared in DPC
++       * explicitly mandates this
++       */
++      if (priv->attr.link_type == DPMAC_LINK_TYPE_FIXED)
++              goto probe_fixed_link;
++
++      if (priv->attr.eth_if < ARRAY_SIZE(dpaa2_mac_iface_mode)) {
++              if_mode = dpaa2_mac_iface_mode[priv->attr.eth_if];
++              dev_dbg(dev, "\tusing if mode %s for eth_if %d\n",
++                      phy_modes(if_mode), priv->attr.eth_if);
++      } else {
++              dev_warn(dev, "Unexpected interface mode %d, will probe as fixed link\n",
++                       priv->attr.eth_if);
++              goto probe_fixed_link;
++      }
++
++      /* try to connect to the PHY */
++      phy_node = of_parse_phandle(dpmac_node, "phy-handle", 0);
++      if (!phy_node) {
++              if (!phy_node) {
++                      dev_err(dev, "dpmac node has no phy-handle property\n");
++                      err = -ENODEV;
++                      goto err_no_phy;
++              }
++      }
++      netdev->phydev = of_phy_connect(netdev, phy_node,
++                                      &dpaa2_mac_link_changed, 0, if_mode);
++      if (!netdev->phydev) {
++              /* No need for dev_err(); the kernel's loud enough as it is. */
++              dev_dbg(dev, "Can't of_phy_connect() now.\n");
++              /* We might be waiting for the MDIO MUX to probe, so defer
++               * our own probing.
++               */
++              err = -EPROBE_DEFER;
++              goto err_defer;
++      }
++      dev_info(dev, "Connected to %s PHY.\n", phy_modes(if_mode));
++
++probe_fixed_link:
++      if (!netdev->phydev) {
++              struct fixed_phy_status status = {
++                      .link = 1,
++                      /* fixed-phys don't support 10Gbps speed for now */
++                      .speed = 1000,
++                      .duplex = 1,
++              };
++
++              /* try to register a fixed link phy */
++              netdev->phydev = fixed_phy_register(PHY_POLL, &status, NULL);
++              if (!netdev->phydev || IS_ERR(netdev->phydev)) {
++                      dev_err(dev, "error trying to register fixed PHY\n");
++                      /* So we don't crash unregister_netdev() later on */
++                      netdev->phydev = NULL;
++                      err = -EFAULT;
++                      goto err_no_phy;
++              }
++              dev_info(dev, "Registered fixed PHY.\n");
++      }
++
++      /* start PHY state machine */
++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
++      dpaa2_mac_open(netdev);
++#else /* CONFIG_FSL_DPAA2_MAC_NETDEVS */
++      phy_start(netdev->phydev);
++#endif /* CONFIG_FSL_DPAA2_MAC_NETDEVS */
++      return 0;
++
++err_defer:
++err_no_phy:
++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
++      unregister_netdev(netdev);
++err_free_irq:
++#endif
++      teardown_irqs(mc_dev);
++err_close:
++      dpmac_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
++err_free_mcp:
++      fsl_mc_portal_free(mc_dev->mc_io);
++err_free_netdev:
++      free_netdev(netdev);
++err_exit:
++      return err;
++}
++
++static int dpaa2_mac_remove(struct fsl_mc_device *mc_dev)
++{
++      struct device           *dev = &mc_dev->dev;
++      struct dpaa2_mac_priv   *priv = dev_get_drvdata(dev);
++
++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
++      unregister_netdev(priv->netdev);
++#endif
++      teardown_irqs(priv->mc_dev);
++      dpmac_close(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle);
++      fsl_mc_portal_free(priv->mc_dev->mc_io);
++      free_netdev(priv->netdev);
++
++      dev_set_drvdata(dev, NULL);
++      kfree(priv);
++
++      return 0;
++}
++
++static const struct fsl_mc_device_id dpaa2_mac_match_id_table[] = {
++      {
++              .vendor = FSL_MC_VENDOR_FREESCALE,
++              .obj_type = "dpmac",
++      },
++      { .vendor = 0x0 }
++};
++MODULE_DEVICE_TABLE(fslmc, dpaa2_mac_match_id_table);
++
++static struct fsl_mc_driver dpaa2_mac_drv = {
++      .driver = {
++              .name           = KBUILD_MODNAME,
++              .owner          = THIS_MODULE,
++      },
++      .probe          = dpaa2_mac_probe,
++      .remove         = dpaa2_mac_remove,
++      .match_id_table = dpaa2_mac_match_id_table,
++};
++
++module_fsl_mc_driver(dpaa2_mac_drv);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("DPAA2 PHY proxy interface driver");
diff --git a/target/linux/layerscape/patches-5.4/701-net-0158-staging-fsl-dpaa2-mac-Remove-link-type-from-phy-sel-.patch b/target/linux/layerscape/patches-5.4/701-net-0158-staging-fsl-dpaa2-mac-Remove-link-type-from-phy-sel-.patch
new file mode 100644 (file)
index 0000000..8a51f15
--- /dev/null
@@ -0,0 +1,40 @@
+From 01fc2236f7fe0c094c26635e738331abec0ac103 Mon Sep 17 00:00:00 2001
+From: costi <constantin.tudor@freescale.com>
+Date: Tue, 7 Mar 2017 16:13:07 +0200
+Subject: [PATCH] staging: fsl-dpaa2/mac: Remove link type from phy sel logic
+
+Signed-off-by: Constantin Tudor <constantin.tudor@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 13 ++++---------
+ 1 file changed, 4 insertions(+), 9 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -545,8 +545,11 @@ static int dpaa2_mac_probe(struct fsl_mc
+       /* probe the PHY as a fixed-link if the link type declared in DPC
+        * explicitly mandates this
+        */
+-      if (priv->attr.link_type == DPMAC_LINK_TYPE_FIXED)
++
++      phy_node = of_parse_phandle(dpmac_node, "phy-handle", 0);
++      if (!phy_node) {
+               goto probe_fixed_link;
++      }
+       if (priv->attr.eth_if < ARRAY_SIZE(dpaa2_mac_iface_mode)) {
+               if_mode = dpaa2_mac_iface_mode[priv->attr.eth_if];
+@@ -559,14 +562,6 @@ static int dpaa2_mac_probe(struct fsl_mc
+       }
+       /* try to connect to the PHY */
+-      phy_node = of_parse_phandle(dpmac_node, "phy-handle", 0);
+-      if (!phy_node) {
+-              if (!phy_node) {
+-                      dev_err(dev, "dpmac node has no phy-handle property\n");
+-                      err = -ENODEV;
+-                      goto err_no_phy;
+-              }
+-      }
+       netdev->phydev = of_phy_connect(netdev, phy_node,
+                                       &dpaa2_mac_link_changed, 0, if_mode);
+       if (!netdev->phydev) {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0159-staging-fsl-dpaa2-mac-Update-ethtool-ops.patch b/target/linux/layerscape/patches-5.4/701-net-0159-staging-fsl-dpaa2-mac-Update-ethtool-ops.patch
new file mode 100644 (file)
index 0000000..5276ee1
--- /dev/null
@@ -0,0 +1,55 @@
+From f964e8840c12e0659c4cfe7aa7d66b310e09ca51 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Tue, 22 Aug 2017 15:00:29 +0300
+Subject: [PATCH] staging: fsl-dpaa2/mac: Update ethtool ops
+
+Ethtool ops get/set_settings() are deprecated, so implement
+get/set_link_ksettings() instead.
+
+These now call the corresponding phy_ethtool_ksettings_*
+generic functions, as the old ones also got deprecated
+and removed from the kernel entirely.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 18 ++++++++++--------
+ 1 file changed, 10 insertions(+), 8 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -152,16 +152,18 @@ done:
+       return 0;
+ }
+-static int dpaa2_mac_get_settings(struct net_device *netdev,
+-                                struct ethtool_cmd *cmd)
++static int dpaa2_mac_get_link_ksettings(struct net_device *netdev,
++                                      struct ethtool_link_ksettings *ks)
+ {
+-      return phy_ethtool_gset(netdev->phydev, cmd);
++      phy_ethtool_ksettings_get(netdev->phydev, ks);
++
++      return 0;
+ }
+-static int dpaa2_mac_set_settings(struct net_device *netdev,
+-                                struct ethtool_cmd *cmd)
++static int dpaa2_mac_set_link_ksettings(struct net_device *netdev,
++                                      const struct ethtool_link_ksettings *ks)
+ {
+-      return phy_ethtool_sset(netdev->phydev, cmd);
++      return phy_ethtool_ksettings_set(netdev->phydev, ks);
+ }
+ static void dpaa2_mac_get_stats(struct net_device *netdev,
+@@ -319,8 +321,8 @@ static const struct net_device_ops dpaa2
+ };
+ static const struct ethtool_ops dpaa2_mac_ethtool_ops = {
+-      .get_settings           = &dpaa2_mac_get_settings,
+-      .set_settings           = &dpaa2_mac_set_settings,
++      .get_link_ksettings     = &dpaa2_mac_get_link_ksettings,
++      .set_link_ksettings     = &dpaa2_mac_set_link_ksettings,
+       .get_strings            = &dpaa2_mac_get_strings,
+       .get_ethtool_stats      = &dpaa2_mac_get_ethtool_stats,
+       .get_sset_count         = &dpaa2_mac_get_sset_count,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0160-staging-fsl-dpaa2-mac-Comply-with-mc-bus-header-upda.patch b/target/linux/layerscape/patches-5.4/701-net-0160-staging-fsl-dpaa2-mac-Comply-with-mc-bus-header-upda.patch
new file mode 100644 (file)
index 0000000..7b101f2
--- /dev/null
@@ -0,0 +1,36 @@
+From ed2efc45fb3130739ac3d9578054c67ee8ec6470 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Wed, 23 Aug 2017 17:51:23 +0300
+Subject: [PATCH] staging: fsl-dpaa2/mac: Comply with mc bus header updates
+
+The fsl-mc bus driver reorganized some of its headers, so
+update our includes accordingly.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/dpmac.c | 3 +--
+ drivers/staging/fsl-dpaa2/mac/mac.c   | 1 -
+ 2 files changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/dpmac.c
++++ b/drivers/staging/fsl-dpaa2/mac/dpmac.c
+@@ -29,8 +29,7 @@
+  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  * POSSIBILITY OF SUCH DAMAGE.
+  */
+-#include "../../fsl-mc/include/mc-sys.h"
+-#include "../../fsl-mc/include/mc-cmd.h"
++#include "../../fsl-mc/include/mc.h"
+ #include "dpmac.h"
+ #include "dpmac-cmd.h"
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -47,7 +47,6 @@
+ #include <linux/phy_fixed.h>
+ #include "../../fsl-mc/include/mc.h"
+-#include "../../fsl-mc/include/mc-sys.h"
+ #include "dpmac.h"
+ #include "dpmac-cmd.h"
diff --git a/target/linux/layerscape/patches-5.4/701-net-0161-staging-fsl-dpaa2-mac-Request-atomic-context-MC-port.patch b/target/linux/layerscape/patches-5.4/701-net-0161-staging-fsl-dpaa2-mac-Request-atomic-context-MC-port.patch
new file mode 100644 (file)
index 0000000..95d0fb6
--- /dev/null
@@ -0,0 +1,28 @@
+From 001bad547937cdd667adee45b5c7ebe78a1de1d0 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Fri, 22 Sep 2017 12:20:02 +0300
+Subject: [PATCH] staging: fsl-dpaa2/mac: Request atomic context MC portals
+
+The MAC driver may need to issue MC commands while in atomic
+context (e.g. dpaa2_mac_get_stats can be called from a critical
+section), so we need to use MC portals that don't sleep while
+waiting for a command response to arrive.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -490,7 +490,9 @@ static int dpaa2_mac_probe(struct fsl_mc
+       dev_set_drvdata(dev, priv);
+-      err = fsl_mc_portal_allocate(mc_dev, 0, &mc_dev->mc_io);
++      /* We may need to issue MC commands while in atomic context */
++      err = fsl_mc_portal_allocate(mc_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
++                                   &mc_dev->mc_io);
+       if (err || !mc_dev->mc_io) {
+               dev_err(dev, "fsl_mc_portal_allocate error: %d\n", err);
+               err = -ENODEV;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0162-staging-fsl-dpaa2-mac-Remove-redundant-free.patch b/target/linux/layerscape/patches-5.4/701-net-0162-staging-fsl-dpaa2-mac-Remove-redundant-free.patch
new file mode 100644 (file)
index 0000000..30a85ab
--- /dev/null
@@ -0,0 +1,24 @@
+From c21f8562457b994b7e4ba46cba9fd05dc0e25e20 Mon Sep 17 00:00:00 2001
+From: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+Date: Thu, 28 Sep 2017 10:58:24 +0000
+Subject: [PATCH] staging: fsl-dpaa2/mac: Remove redundant free
+
+free_netdev (put_device) already handles freeing the private data
+structure, and KASAN will complain due to a free after free if we
+explicitly do the same afterwards.
+
+Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -638,7 +638,6 @@ static int dpaa2_mac_remove(struct fsl_m
+       free_netdev(priv->netdev);
+       dev_set_drvdata(dev, NULL);
+-      kfree(priv);
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0163-staging-fsl-dpaa2-mac-Cleanup-code.patch b/target/linux/layerscape/patches-5.4/701-net-0163-staging-fsl-dpaa2-mac-Cleanup-code.patch
new file mode 100644 (file)
index 0000000..7aa7b28
--- /dev/null
@@ -0,0 +1,89 @@
+From c2dfd6095bd7f812c9a1aa4d381022579702af4d Mon Sep 17 00:00:00 2001
+From: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+Date: Thu, 5 Oct 2017 08:05:55 +0000
+Subject: [PATCH] staging: fsl-dpaa2/mac: Cleanup code
+
+- move dpaa2_mac_open and dpaa2_mac_stop out of
+  CONFIG_FSL_DPAA2_MAC_NETDEVS, since their implementation is necessary
+  regardless of it
+- reorder ndo ops to match function implementation order
+- update comment to describe the phy connection mode that's to be used -
+  it no longer depends on DPC, but on the device tree
+
+Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 31 +++++++++++++------------------
+ 1 file changed, 13 insertions(+), 18 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -118,15 +118,6 @@ static void dpaa2_mac_link_changed(struc
+               dev_err(&priv->mc_dev->dev, "dpmac_set_link_state: %d\n", err);
+ }
+-#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
+-static netdev_tx_t dpaa2_mac_drop_frame(struct sk_buff *skb,
+-                                      struct net_device *dev)
+-{
+-      /* we don't support I/O for now, drop the frame */
+-      dev_kfree_skb_any(skb);
+-      return NETDEV_TX_OK;
+-}
+-
+ static int dpaa2_mac_open(struct net_device *netdev)
+ {
+       /* start PHY state machine */
+@@ -151,6 +142,15 @@ done:
+       return 0;
+ }
++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
++static netdev_tx_t dpaa2_mac_drop_frame(struct sk_buff *skb,
++                                      struct net_device *dev)
++{
++      /* we don't support I/O for now, drop the frame */
++      dev_kfree_skb_any(skb);
++      return NETDEV_TX_OK;
++}
++
+ static int dpaa2_mac_get_link_ksettings(struct net_device *netdev,
+                                       struct ethtool_link_ksettings *ks)
+ {
+@@ -313,9 +313,9 @@ static int dpaa2_mac_get_sset_count(stru
+ }
+ static const struct net_device_ops dpaa2_mac_ndo_ops = {
+-      .ndo_start_xmit         = &dpaa2_mac_drop_frame,
+       .ndo_open               = &dpaa2_mac_open,
+       .ndo_stop               = &dpaa2_mac_stop,
++      .ndo_start_xmit         = &dpaa2_mac_drop_frame,
+       .ndo_get_stats64        = &dpaa2_mac_get_stats,
+ };
+@@ -545,10 +545,9 @@ static int dpaa2_mac_probe(struct fsl_mc
+       }
+ #endif /* CONFIG_FSL_DPAA2_MAC_NETDEVS */
+-      /* probe the PHY as a fixed-link if the link type declared in DPC
+-       * explicitly mandates this
++      /* probe the PHY as a fixed-link if there's a phy-handle defined
++       * in the device tree
+        */
+-
+       phy_node = of_parse_phandle(dpmac_node, "phy-handle", 0);
+       if (!phy_node) {
+               goto probe_fixed_link;
+@@ -599,12 +598,8 @@ probe_fixed_link:
+               dev_info(dev, "Registered fixed PHY.\n");
+       }
+-      /* start PHY state machine */
+-#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
+       dpaa2_mac_open(netdev);
+-#else /* CONFIG_FSL_DPAA2_MAC_NETDEVS */
+-      phy_start(netdev->phydev);
+-#endif /* CONFIG_FSL_DPAA2_MAC_NETDEVS */
++
+       return 0;
+ err_defer:
diff --git a/target/linux/layerscape/patches-5.4/701-net-0164-staging-fsl-dpaa2-mac-Free-phydev-on-unbind.patch b/target/linux/layerscape/patches-5.4/701-net-0164-staging-fsl-dpaa2-mac-Free-phydev-on-unbind.patch
new file mode 100644 (file)
index 0000000..62cce28
--- /dev/null
@@ -0,0 +1,31 @@
+From 665b0217a4c99c14b680878f87bfa83c664de737 Mon Sep 17 00:00:00 2001
+From: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+Date: Thu, 28 Sep 2017 11:07:33 +0000
+Subject: [PATCH] staging: fsl-dpaa2/mac: Free phydev on unbind
+
+Stop polling and unregister / disconnect the phydev structure on DPAA2
+mac driver unbind.
+
+Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -623,6 +623,15 @@ static int dpaa2_mac_remove(struct fsl_m
+ {
+       struct device           *dev = &mc_dev->dev;
+       struct dpaa2_mac_priv   *priv = dev_get_drvdata(dev);
++      struct net_device       *netdev = priv->netdev;
++
++      dpaa2_mac_stop(netdev);
++
++      if (phy_is_pseudo_fixed_link(netdev->phydev))
++              fixed_phy_unregister(netdev->phydev);
++      else
++              phy_disconnect(netdev->phydev);
++      netdev->phydev = NULL;
+ #ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
+       unregister_netdev(priv->netdev);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0165-staging-fsl-dpaa2-mac-defer-probe-if-no-mc-portal-is.patch b/target/linux/layerscape/patches-5.4/701-net-0165-staging-fsl-dpaa2-mac-defer-probe-if-no-mc-portal-is.patch
new file mode 100644 (file)
index 0000000..083e742
--- /dev/null
@@ -0,0 +1,23 @@
+From 8bfccd1f7b096d5e5a6db2cda9d5e983b4422da2 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Wed, 29 Nov 2017 17:39:05 +0200
+Subject: [PATCH] staging: fsl-dpaa2/mac: defer probe if no mc portal is found
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -494,8 +494,8 @@ static int dpaa2_mac_probe(struct fsl_mc
+       err = fsl_mc_portal_allocate(mc_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
+                                    &mc_dev->mc_io);
+       if (err || !mc_dev->mc_io) {
+-              dev_err(dev, "fsl_mc_portal_allocate error: %d\n", err);
+-              err = -ENODEV;
++              dev_dbg(dev, "fsl_mc_portal_allocate error: %d\n", err);
++              err = -EPROBE_DEFER;
+               goto err_free_netdev;
+       }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0166-staging-fsl-dpaa2-mac-make-compatible-with-upstream-.patch b/target/linux/layerscape/patches-5.4/701-net-0166-staging-fsl-dpaa2-mac-make-compatible-with-upstream-.patch
new file mode 100644 (file)
index 0000000..d2e5bf4
--- /dev/null
@@ -0,0 +1,180 @@
+From 642686661c3324b4ae6c14f1cdbd2ea613525f09 Mon Sep 17 00:00:00 2001
+From: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+Date: Fri, 13 Apr 2018 09:57:12 +0300
+Subject: [PATCH] staging: fsl-dpaa2/mac: make compatible with upstream MC bus
+
+Update the mc.h include path.
+Rename struct mc_command to struct fsl_mc_command.
+
+Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/dpmac.c | 34 +++++++++++++++++-----------------
+ drivers/staging/fsl-dpaa2/mac/mac.c   |  2 +-
+ 2 files changed, 18 insertions(+), 18 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/dpmac.c
++++ b/drivers/staging/fsl-dpaa2/mac/dpmac.c
+@@ -29,7 +29,7 @@
+  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  * POSSIBILITY OF SUCH DAMAGE.
+  */
+-#include "../../fsl-mc/include/mc.h"
++#include <linux/fsl/mc.h>
+ #include "dpmac.h"
+ #include "dpmac-cmd.h"
+@@ -56,7 +56,7 @@ int dpmac_open(struct fsl_mc_io *mc_io,
+              u16 *token)
+ {
+       struct dpmac_cmd_open *cmd_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       int err;
+       /* prepare command */
+@@ -92,7 +92,7 @@ int dpmac_close(struct fsl_mc_io *mc_io,
+               u32 cmd_flags,
+               u16 token)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CLOSE, cmd_flags,
+@@ -128,7 +128,7 @@ int dpmac_create(struct fsl_mc_io *mc_io
+                u32 *obj_id)
+ {
+       struct dpmac_cmd_create *cmd_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       int err;
+       /* prepare command */
+@@ -170,7 +170,7 @@ int dpmac_destroy(struct fsl_mc_io *mc_i
+                 u32 object_id)
+ {
+       struct dpmac_cmd_destroy *cmd_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPMAC_CMDID_DESTROY,
+@@ -205,7 +205,7 @@ int dpmac_set_irq_enable(struct fsl_mc_i
+                        u8 en)
+ {
+       struct dpmac_cmd_set_irq_enable *cmd_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_IRQ_ENABLE,
+@@ -237,7 +237,7 @@ int dpmac_get_irq_enable(struct fsl_mc_i
+ {
+       struct dpmac_cmd_get_irq_enable *cmd_params;
+       struct dpmac_rsp_get_irq_enable *rsp_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       int err;
+       /* prepare command */
+@@ -282,7 +282,7 @@ int dpmac_set_irq_mask(struct fsl_mc_io
+                      u32 mask)
+ {
+       struct dpmac_cmd_set_irq_mask *cmd_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_IRQ_MASK,
+@@ -317,7 +317,7 @@ int dpmac_get_irq_mask(struct fsl_mc_io
+ {
+       struct dpmac_cmd_get_irq_mask *cmd_params;
+       struct dpmac_rsp_get_irq_mask *rsp_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       int err;
+       /* prepare command */
+@@ -360,7 +360,7 @@ int dpmac_get_irq_status(struct fsl_mc_i
+ {
+       struct dpmac_cmd_get_irq_status *cmd_params;
+       struct dpmac_rsp_get_irq_status *rsp_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       int err;
+       /* prepare command */
+@@ -403,7 +403,7 @@ int dpmac_clear_irq_status(struct fsl_mc
+                          u32 status)
+ {
+       struct dpmac_cmd_clear_irq_status *cmd_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CLEAR_IRQ_STATUS,
+@@ -433,7 +433,7 @@ int dpmac_get_attributes(struct fsl_mc_i
+                        struct dpmac_attr *attr)
+ {
+       struct dpmac_rsp_get_attributes *rsp_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       int err;
+       /* prepare command */
+@@ -471,7 +471,7 @@ int dpmac_get_link_cfg(struct fsl_mc_io
+                      struct dpmac_link_cfg *cfg)
+ {
+       struct dpmac_rsp_get_link_cfg *rsp_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       int err = 0;
+       /* prepare command */
+@@ -506,7 +506,7 @@ int dpmac_set_link_state(struct fsl_mc_i
+                        struct dpmac_link_state *link_state)
+ {
+       struct dpmac_cmd_set_link_state *cmd_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_LINK_STATE,
+@@ -539,7 +539,7 @@ int dpmac_get_counter(struct fsl_mc_io *
+ {
+       struct dpmac_cmd_get_counter *dpmac_cmd;
+       struct dpmac_rsp_get_counter *dpmac_rsp;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       int err = 0;
+       /* prepare command */
+@@ -567,7 +567,7 @@ int dpmac_set_port_mac_addr(struct fsl_m
+                           const u8 addr[6])
+ {
+       struct dpmac_cmd_set_port_mac_addr *dpmac_cmd;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_PORT_MAC_ADDR,
+@@ -600,7 +600,7 @@ int dpmac_get_api_version(struct fsl_mc_
+                         u16 *minor_ver)
+ {
+       struct dpmac_rsp_get_api_version *rsp_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       int err;
+       cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_API_VERSION,
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -46,7 +46,7 @@
+ #include <linux/phy.h>
+ #include <linux/phy_fixed.h>
+-#include "../../fsl-mc/include/mc.h"
++#include <linux/fsl/mc.h>
+ #include "dpmac.h"
+ #include "dpmac-cmd.h"
diff --git a/target/linux/layerscape/patches-5.4/701-net-0167-staging-fsl-dpaa2-mac-probe-phy-as-fixed-link-based-.patch b/target/linux/layerscape/patches-5.4/701-net-0167-staging-fsl-dpaa2-mac-probe-phy-as-fixed-link-based-.patch
new file mode 100644 (file)
index 0000000..f46bfee
--- /dev/null
@@ -0,0 +1,35 @@
+From fc7b4295a24771be99eb1afb374608562706f4d8 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Thu, 18 Oct 2018 20:02:44 +0300
+Subject: [PATCH] staging: fsl-dpaa2/mac: probe phy as fixed link based on
+ dpmac properties
+
+Keep in sync the PHY type settings in DPC and Linux device tree.
+
+If the dpmac is connected to a fixed link PHY based on dpc config,
+treat it as a fixed-link device, regardless of whether the "phy-handle"
+property is present in the device tree node or not.
+
+Signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com>
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -545,9 +545,11 @@ static int dpaa2_mac_probe(struct fsl_mc
+       }
+ #endif /* CONFIG_FSL_DPAA2_MAC_NETDEVS */
+-      /* probe the PHY as a fixed-link if there's a phy-handle defined
+-       * in the device tree
+-       */
++      /* probe the PHY as fixed-link if the DPMAC attribute indicates so */
++      if (priv->attr.link_type == DPMAC_LINK_TYPE_FIXED)
++              goto probe_fixed_link;
++
++      /* or if there's no phy-handle defined in the device tree */
+       phy_node = of_parse_phandle(dpmac_node, "phy-handle", 0);
+       if (!phy_node) {
+               goto probe_fixed_link;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0168-staging-fsl-dpaa2-mac-Fix-uninitialized-variable.patch b/target/linux/layerscape/patches-5.4/701-net-0168-staging-fsl-dpaa2-mac-Fix-uninitialized-variable.patch
new file mode 100644 (file)
index 0000000..6cad0a9
--- /dev/null
@@ -0,0 +1,23 @@
+From 8d1d6c6778c00d47eee8073bb991c6799d757c35 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Fri, 19 Oct 2018 17:00:17 +0300
+Subject: [PATCH] staging: fsl-dpaa2/mac: Fix uninitialized variable
+
+Reported by coverity.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -355,7 +355,7 @@ static irqreturn_t dpaa2_mac_irq_handler
+       struct device *dev = (struct device *)arg;
+       struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
+       struct dpaa2_mac_priv *priv = dev_get_drvdata(dev);
+-      struct dpmac_link_cfg link_cfg;
++      struct dpmac_link_cfg link_cfg = { 0 };
+       u32 status;
+       int err;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0169-staging-fsl-dpaa2-mac-read-phy-mode-from-device-tree.patch b/target/linux/layerscape/patches-5.4/701-net-0169-staging-fsl-dpaa2-mac-read-phy-mode-from-device-tree.patch
new file mode 100644 (file)
index 0000000..1833319
--- /dev/null
@@ -0,0 +1,49 @@
+From 781d22f6cf6aded86e80be995b5c875c61512567 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Thu, 18 Oct 2018 20:12:38 +0300
+Subject: [PATCH] staging: fsl-dpaa2/mac: read phy mode from device tree
+
+If the a dpmac node defines its phy mode in the device tree using
+the 'phy-mode' or the 'phy-connection-type' attributes this will take
+precedence over the interface mode reported by the MC in the
+dpmac attributes structure.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -466,7 +466,7 @@ static int dpaa2_mac_probe(struct fsl_mc
+       struct dpaa2_mac_priv   *priv = NULL;
+       struct device_node      *phy_node, *dpmac_node;
+       struct net_device       *netdev;
+-      phy_interface_t         if_mode;
++      int                     if_mode;
+       int                     err = 0;
+       dev = &mc_dev->dev;
+@@ -555,6 +555,13 @@ static int dpaa2_mac_probe(struct fsl_mc
+               goto probe_fixed_link;
+       }
++      if_mode = of_get_phy_mode(dpmac_node);
++      if (if_mode >= 0) {
++              dev_dbg(dev, "\tusing if mode %s for eth_if %d\n",
++                      phy_modes(if_mode), priv->attr.eth_if);
++              goto phy_connect;
++      }
++
+       if (priv->attr.eth_if < ARRAY_SIZE(dpaa2_mac_iface_mode)) {
+               if_mode = dpaa2_mac_iface_mode[priv->attr.eth_if];
+               dev_dbg(dev, "\tusing if mode %s for eth_if %d\n",
+@@ -565,6 +572,7 @@ static int dpaa2_mac_probe(struct fsl_mc
+               goto probe_fixed_link;
+       }
++phy_connect:
+       /* try to connect to the PHY */
+       netdev->phydev = of_phy_connect(netdev, phy_node,
+                                       &dpaa2_mac_link_changed, 0, if_mode);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0170-staging-fsl-dpaa2-mac-Add-more-PHY-modes.patch b/target/linux/layerscape/patches-5.4/701-net-0170-staging-fsl-dpaa2-mac-Add-more-PHY-modes.patch
new file mode 100644 (file)
index 0000000..376b508
--- /dev/null
@@ -0,0 +1,26 @@
+From 8b85f5295ffa083516fc496343d4328cf1deb605 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Fri, 19 Oct 2018 13:22:12 +0300
+Subject: [PATCH] staging: fsl-dpaa2/mac: Add more PHY modes
+
+Add support for CAUI, USXGMII and 1000BASE-X.
+
+Signed-off-by: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
+Signed-off-by: Valentin Catalin Neacsu <valentin-catalin.neacsu@nxp.com>
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -76,6 +76,9 @@ static phy_interface_t dpaa2_mac_iface_m
+       PHY_INTERFACE_MODE_QSGMII,      /* DPMAC_ETH_IF_QSGMII */
+       PHY_INTERFACE_MODE_XGMII,       /* DPMAC_ETH_IF_XAUI */
+       PHY_INTERFACE_MODE_XGMII,       /* DPMAC_ETH_IF_XFI */
++      PHY_INTERFACE_MODE_XGMII,        /* DPMAC_ETH_IF_CAUI */
++      PHY_INTERFACE_MODE_XGMII,       /* DPMAC_ETH_IF_1000BASEX */
++      PHY_INTERFACE_MODE_XGMII,       /* DPMAC_ETH_IF_USXGMII */
+ };
+ static void dpaa2_mac_link_changed(struct net_device *netdev)
diff --git a/target/linux/layerscape/patches-5.4/701-net-0171-staging-fsl-dpaa2-mac-Check-DPMAC-version.patch b/target/linux/layerscape/patches-5.4/701-net-0171-staging-fsl-dpaa2-mac-Check-DPMAC-version.patch
new file mode 100644 (file)
index 0000000..ca3506b
--- /dev/null
@@ -0,0 +1,99 @@
+From 2dc96021dc08d24eed822f66cb8fb5a454fee236 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Fri, 19 Oct 2018 16:20:07 +0300
+Subject: [PATCH] staging: fsl-dpaa2/mac: Check DPMAC version
+
+Read the current API version exposed by the DPMAC object.
+Add a check at probe time to make sure it is compatible with
+the set of MC commands we intend to use on it.
+Also, print the version number through ethtool driver info.
+
+Signed-off-by: Catalin Neacsu <valentin-catalin.neacsu@nxp.com>
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 39 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 39 insertions(+)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -56,6 +56,8 @@ struct dpaa2_mac_priv {
+       struct fsl_mc_device            *mc_dev;
+       struct dpmac_attr               attr;
+       struct dpmac_link_state         old_state;
++      u16                             dpmac_ver_major;
++      u16                             dpmac_ver_minor;
+ };
+ /* TODO: fix the 10G modes, mapping can't be right:
+@@ -81,6 +83,14 @@ static phy_interface_t dpaa2_mac_iface_m
+       PHY_INTERFACE_MODE_XGMII,       /* DPMAC_ETH_IF_USXGMII */
+ };
++static int cmp_dpmac_ver(struct dpaa2_mac_priv *priv,
++                       u16 ver_major, u16 ver_minor)
++{
++      if (priv->dpmac_ver_major == ver_major)
++              return priv->dpmac_ver_minor - ver_minor;
++      return priv->dpmac_ver_major - ver_major;
++}
++
+ static void dpaa2_mac_link_changed(struct net_device *netdev)
+ {
+       struct phy_device       *phydev;
+@@ -154,6 +164,18 @@ static netdev_tx_t dpaa2_mac_drop_frame(
+       return NETDEV_TX_OK;
+ }
++static void dpaa2_mac_get_drvinfo(struct net_device *net_dev,
++                                struct ethtool_drvinfo *drvinfo)
++{
++      struct dpaa2_mac_priv *priv = netdev_priv(net_dev);
++
++      strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
++      snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
++               "%u.%u", priv->dpmac_ver_major, priv->dpmac_ver_minor);
++      strlcpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent),
++              sizeof(drvinfo->bus_info));
++}
++
+ static int dpaa2_mac_get_link_ksettings(struct net_device *netdev,
+                                       struct ethtool_link_ksettings *ks)
+ {
+@@ -323,6 +345,7 @@ static const struct net_device_ops dpaa2
+ };
+ static const struct ethtool_ops dpaa2_mac_ethtool_ops = {
++      .get_drvinfo            = &dpaa2_mac_get_drvinfo,
+       .get_link_ksettings     = &dpaa2_mac_get_link_ksettings,
+       .set_link_ksettings     = &dpaa2_mac_set_link_ksettings,
+       .get_strings            = &dpaa2_mac_get_strings,
+@@ -510,6 +533,21 @@ static int dpaa2_mac_probe(struct fsl_mc
+               goto err_free_mcp;
+       }
++      err = dpmac_get_api_version(mc_dev->mc_io, 0, &priv->dpmac_ver_major,
++                                  &priv->dpmac_ver_minor);
++      if (err) {
++              dev_err(dev, "dpmac_get_api_version failed\n");
++              goto err_version;
++      }
++
++      if (cmp_dpmac_ver(priv, DPMAC_VER_MAJOR, DPMAC_VER_MINOR) < 0) {
++              dev_err(dev, "DPMAC version %u.%u lower than supported %u.%u\n",
++                      priv->dpmac_ver_major, priv->dpmac_ver_minor,
++                      DPMAC_VER_MAJOR, DPMAC_VER_MINOR);
++              err = -ENOTSUPP;
++              goto err_version;
++      }
++
+       err = dpmac_get_attributes(mc_dev->mc_io, 0,
+                                  mc_dev->mc_handle, &priv->attr);
+       if (err) {
+@@ -622,6 +660,7 @@ err_no_phy:
+ err_free_irq:
+ #endif
+       teardown_irqs(mc_dev);
++err_version:
+ err_close:
+       dpmac_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
+ err_free_mcp:
diff --git a/target/linux/layerscape/patches-5.4/701-net-0172-staging-fsl-dpaa2-mac-Fix-dpmac_set_link_state-comma.patch b/target/linux/layerscape/patches-5.4/701-net-0172-staging-fsl-dpaa2-mac-Fix-dpmac_set_link_state-comma.patch
new file mode 100644 (file)
index 0000000..867dbf1
--- /dev/null
@@ -0,0 +1,24 @@
+From c27bca038be891762760c5e4b3a79368c663b47b Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Fri, 19 Oct 2018 17:45:50 +0300
+Subject: [PATCH] staging: fsl-dpaa2/mac: Fix dpmac_set_link_state() command
+
+The instruction writing link state value in the MC command
+structure wasn't correct, but it happened to work nonetheless.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/dpmac.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/dpmac.c
++++ b/drivers/staging/fsl-dpaa2/mac/dpmac.c
+@@ -515,7 +515,7 @@ int dpmac_set_link_state(struct fsl_mc_i
+       cmd_params = (struct dpmac_cmd_set_link_state *)cmd.params;
+       cmd_params->options = cpu_to_le64(link_state->options);
+       cmd_params->rate = cpu_to_le32(link_state->rate);
+-      cmd_params->up = dpmac_get_field(link_state->up, STATE);
++      dpmac_set_field(cmd_params->up, STATE, link_state->up);
+       /* send command to mc*/
+       return mc_send_command(mc_io, &cmd);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0173-staging-fsl-dpaa2-mac-Add-support-for-new-link-state.patch b/target/linux/layerscape/patches-5.4/701-net-0173-staging-fsl-dpaa2-mac-Add-support-for-new-link-state.patch
new file mode 100644 (file)
index 0000000..601a4bf
--- /dev/null
@@ -0,0 +1,235 @@
+From d84bd24a4d6e5b05f7eb1a544dfd0bd98c7f5bb1 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Wed, 17 Oct 2018 20:14:24 +0300
+Subject: [PATCH] staging: fsl-dpaa2/mac: Add support for new link state APIs
+
+Add v2 of dpmac_set_link_state() and dpmac_get_link_cfg() commands.
+The new version allows setting & getting advertised and supported
+link options.
+
+Signed-off-by: Valentin Catalin Neacsu <valentin-catalin.neacsu@nxp.com>
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/dpmac-cmd.h | 24 +++++++++++
+ drivers/staging/fsl-dpaa2/mac/dpmac.c     | 70 +++++++++++++++++++++++++++++++
+ drivers/staging/fsl-dpaa2/mac/dpmac.h     | 32 ++++++++++++++
+ 3 files changed, 126 insertions(+)
+
+--- a/drivers/staging/fsl-dpaa2/mac/dpmac-cmd.h
++++ b/drivers/staging/fsl-dpaa2/mac/dpmac-cmd.h
+@@ -36,9 +36,11 @@
+ #define DPMAC_VER_MAJOR                               4
+ #define DPMAC_VER_MINOR                               2
+ #define DPMAC_CMD_BASE_VERSION                        1
++#define DPMAC_CMD_2ND_VERSION                 2
+ #define DPMAC_CMD_ID_OFFSET                   4
+ #define DPMAC_CMD(id) (((id) << DPMAC_CMD_ID_OFFSET) | DPMAC_CMD_BASE_VERSION)
++#define DPMAC_CMD_V2(id) (((id) << DPMAC_CMD_ID_OFFSET) | DPMAC_CMD_2ND_VERSION)
+ /* Command IDs */
+ #define DPMAC_CMDID_CLOSE             DPMAC_CMD(0x800)
+@@ -58,7 +60,9 @@
+ #define DPMAC_CMDID_CLEAR_IRQ_STATUS  DPMAC_CMD(0x017)
+ #define DPMAC_CMDID_GET_LINK_CFG      DPMAC_CMD(0x0c2)
++#define DPMAC_CMDID_GET_LINK_CFG_V2   DPMAC_CMD_V2(0x0c2)
+ #define DPMAC_CMDID_SET_LINK_STATE    DPMAC_CMD(0x0c3)
++#define DPMAC_CMDID_SET_LINK_STATE_V2 DPMAC_CMD_V2(0x0c3)
+ #define DPMAC_CMDID_GET_COUNTER               DPMAC_CMD(0x0c4)
+ #define DPMAC_CMDID_SET_PORT_MAC_ADDR DPMAC_CMD(0x0c5)
+@@ -139,8 +143,17 @@ struct dpmac_rsp_get_link_cfg {
+       u32 rate;
+ };
++struct dpmac_rsp_get_link_cfg_v2 {
++      u64 options;
++      u32 rate;
++      u32 pad;
++      u64 advertising;
++};
++
+ #define DPMAC_STATE_SIZE      1
+ #define DPMAC_STATE_SHIFT     0
++#define DPMAC_STATE_VALID_SIZE        1
++#define DPMAC_STATE_VALID_SHIFT       1
+ struct dpmac_cmd_set_link_state {
+       u64 options;
+@@ -150,6 +163,17 @@ struct dpmac_cmd_set_link_state {
+       u8 up;
+ };
++struct dpmac_cmd_set_link_state_v2 {
++      u64 options;
++      u32 rate;
++      u32 pad0;
++      /* from lsb: up:1, state_valid:1 */
++      u8 state;
++      u8 pad1[7];
++      u64 supported;
++      u64 advertising;
++};
++
+ struct dpmac_cmd_get_counter {
+       u8 type;
+ };
+--- a/drivers/staging/fsl-dpaa2/mac/dpmac.c
++++ b/drivers/staging/fsl-dpaa2/mac/dpmac.c
+@@ -492,6 +492,42 @@ int dpmac_get_link_cfg(struct fsl_mc_io
+ }
+ /**
++ * dpmac_get_link_cfg_v2() - Get Ethernet link configuration
++ * @mc_io:      Pointer to opaque I/O object
++ * @cmd_flags:  Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:      Token of DPMAC object
++ * @cfg:        Returned structure with the link configuration
++ *
++ * Return:      '0' on Success; Error code otherwise.
++ */
++int dpmac_get_link_cfg_v2(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        struct dpmac_link_cfg *cfg)
++{
++      struct dpmac_rsp_get_link_cfg_v2 *rsp_params;
++      struct fsl_mc_command cmd = { 0 };
++      int err = 0;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_LINK_CFG_V2,
++                                        cmd_flags,
++                                        token);
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      rsp_params = (struct dpmac_rsp_get_link_cfg_v2 *)cmd.params;
++      cfg->options = le64_to_cpu(rsp_params->options);
++      cfg->rate = le32_to_cpu(rsp_params->rate);
++      cfg->advertising = le64_to_cpu(rsp_params->advertising);
++
++      return 0;
++}
++
++/**
+  * dpmac_set_link_state() - Set the Ethernet link status
+  * @mc_io:    Pointer to opaque I/O object
+  * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
+@@ -519,6 +555,40 @@ int dpmac_set_link_state(struct fsl_mc_i
+       /* send command to mc*/
+       return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpmac_set_link_state_v2() - Set the Ethernet link status
++ * @mc_io:      Pointer to opaque I/O object
++ * @cmd_flags:  Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:      Token of DPMAC object
++ * @link_state: Link state configuration
++ *
++ * Return:      '0' on Success; Error code otherwise.
++ */
++int dpmac_set_link_state_v2(struct fsl_mc_io *mc_io,
++                          u32 cmd_flags,
++                          u16 token,
++                          struct dpmac_link_state *link_state)
++{
++      struct dpmac_cmd_set_link_state_v2 *cmd_params;
++      struct fsl_mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_LINK_STATE_V2,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpmac_cmd_set_link_state_v2 *)cmd.params;
++      cmd_params->options = cpu_to_le64(link_state->options);
++      cmd_params->rate = cpu_to_le32(link_state->rate);
++      dpmac_set_field(cmd_params->state, STATE, link_state->up);
++      dpmac_set_field(cmd_params->state, STATE_VALID,
++                      link_state->state_valid);
++      cmd_params->supported = cpu_to_le64(link_state->supported);
++      cmd_params->advertising = cpu_to_le64(link_state->advertising);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
+ }
+ /**
+--- a/drivers/staging/fsl-dpaa2/mac/dpmac.h
++++ b/drivers/staging/fsl-dpaa2/mac/dpmac.h
+@@ -202,13 +202,29 @@ int dpmac_get_attributes(struct fsl_mc_i
+ #define DPMAC_LINK_OPT_ASYM_PAUSE     0x0000000000000008ULL
+ /**
++ * Advertised link speeds
++ */
++#define DPMAC_ADVERTISED_10BASET_FULL         0x0000000000000001ULL
++#define DPMAC_ADVERTISED_100BASET_FULL                0x0000000000000002ULL
++#define DPMAC_ADVERTISED_1000BASET_FULL               0x0000000000000004ULL
++#define DPMAC_ADVERTISED_10000BASET_FULL      0x0000000000000010ULL
++#define DPMAC_ADVERTISED_2500BASEX_FULL               0x0000000000000020ULL
++
++/**
++ * Advertise auto-negotiation enable
++ */
++#define DPMAC_ADVERTISED_AUTONEG              0x0000000000000008ULL
++
++/**
+  * struct dpmac_link_cfg - Structure representing DPMAC link configuration
+  * @rate: Link's rate - in Mbps
+  * @options: Enable/Disable DPMAC link cfg features (bitmap)
++ * @advertising: Speeds that are advertised for autoneg (bitmap)
+  */
+ struct dpmac_link_cfg {
+       u32 rate;
+       u64 options;
++      u64 advertising;
+ };
+ int dpmac_get_link_cfg(struct fsl_mc_io *mc_io,
+@@ -216,16 +232,27 @@ int dpmac_get_link_cfg(struct fsl_mc_io
+                      u16 token,
+                      struct dpmac_link_cfg *cfg);
++int dpmac_get_link_cfg_v2(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        struct dpmac_link_cfg *cfg);
++
+ /**
+  * struct dpmac_link_state - DPMAC link configuration request
+  * @rate: Rate in Mbps
+  * @options: Enable/Disable DPMAC link cfg features (bitmap)
+  * @up: Link state
++ * @state_valid: Ignore/Update the state of the link
++ * @supported: Speeds capability of the phy (bitmap)
++ * @advertising: Speeds that are advertised for autoneg (bitmap)
+  */
+ struct dpmac_link_state {
+       u32 rate;
+       u64 options;
+       int up;
++      int state_valid;
++      u64 supported;
++      u64 advertising;
+ };
+ int dpmac_set_link_state(struct fsl_mc_io *mc_io,
+@@ -233,6 +260,11 @@ int dpmac_set_link_state(struct fsl_mc_i
+                        u16 token,
+                        struct dpmac_link_state *link_state);
++int dpmac_set_link_state_v2(struct fsl_mc_io *mc_io,
++                          u32 cmd_flags,
++                          u16 token,
++                          struct dpmac_link_state *link_state);
++
+ /**
+  * enum dpmac_counter - DPMAC counter types
+  * @DPMAC_CNT_ING_FRAME_64: counts 64-bytes frames, good or bad.
diff --git a/target/linux/layerscape/patches-5.4/701-net-0174-staging-fsl-dpaa2-mac-Add-autoneg-support.patch b/target/linux/layerscape/patches-5.4/701-net-0174-staging-fsl-dpaa2-mac-Add-autoneg-support.patch
new file mode 100644 (file)
index 0000000..fb296c5
--- /dev/null
@@ -0,0 +1,132 @@
+From 52ab0053f3f8ab374c48630dd03e44fec8138113 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Thu, 18 Oct 2018 18:59:41 +0300
+Subject: [PATCH] staging: fsl-dpaa2/mac: Add autoneg support
+
+For MC versions that support it, use the new DPMAC link APIs, which
+allow setting/getting of advertised and supported link modes.
+
+A mapping between DPMAC link modes and phydev ones is created to
+help converting from one to the other.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Signed-off-by: Valentin Catalin Neacsu <valentin-catalin.neacsu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 78 +++++++++++++++++++++++++++++++------
+ 1 file changed, 67 insertions(+), 11 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -1,4 +1,5 @@
+ /* Copyright 2015 Freescale Semiconductor Inc.
++ * Copyright 2018 NXP
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions are met:
+@@ -91,6 +92,43 @@ static int cmp_dpmac_ver(struct dpaa2_ma
+       return priv->dpmac_ver_major - ver_major;
+ }
++#define DPMAC_LINK_AUTONEG_VER_MAJOR          4
++#define DPMAC_LINK_AUTONEG_VER_MINOR          3
++
++struct dpaa2_mac_link_mode_map {
++      u64 dpmac_lm;
++      u64 ethtool_lm;
++};
++
++static const struct dpaa2_mac_link_mode_map dpaa2_mac_lm_map[] = {
++      {DPMAC_ADVERTISED_10BASET_FULL, ETHTOOL_LINK_MODE_10baseT_Full_BIT},
++      {DPMAC_ADVERTISED_100BASET_FULL, ETHTOOL_LINK_MODE_100baseT_Full_BIT},
++      {DPMAC_ADVERTISED_1000BASET_FULL, ETHTOOL_LINK_MODE_1000baseT_Full_BIT},
++      {DPMAC_ADVERTISED_10000BASET_FULL, ETHTOOL_LINK_MODE_10000baseT_Full_BIT},
++      {DPMAC_ADVERTISED_2500BASEX_FULL, ETHTOOL_LINK_MODE_2500baseT_Full_BIT},
++      {DPMAC_ADVERTISED_AUTONEG, ETHTOOL_LINK_MODE_Autoneg_BIT},
++};
++
++static void link_mode_dpmac2phydev(u64 dpmac_lm, unsigned long *phydev_lm)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(dpaa2_mac_lm_map); i++) {
++              if (dpmac_lm & dpaa2_mac_lm_map[i].dpmac_lm)
++                      linkmode_set_bit(dpaa2_mac_lm_map[i].ethtool_lm, phydev_lm);
++      }
++}
++
++static void link_mode_phydev2dpmac(unsigned long *phydev_lm, u64 *dpni_lm)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(dpaa2_mac_lm_map); i++) {
++              if (linkmode_test_bit(dpaa2_mac_lm_map[i].ethtool_lm, phydev_lm))
++                      *dpni_lm |= dpaa2_mac_lm_map[i].dpmac_lm;
++      }
++}
++
+ static void dpaa2_mac_link_changed(struct net_device *netdev)
+ {
+       struct phy_device       *phydev;
+@@ -122,11 +160,18 @@ static void dpaa2_mac_link_changed(struc
+               phy_print_status(phydev);
+       }
+-      /* We must interrogate MC at all times, because we don't know
+-       * when and whether a potential DPNI may have read the link state.
+-       */
+-      err = dpmac_set_link_state(priv->mc_dev->mc_io, 0,
+-                                 priv->mc_dev->mc_handle, &state);
++      if (cmp_dpmac_ver(priv, DPMAC_LINK_AUTONEG_VER_MAJOR,
++                        DPMAC_LINK_AUTONEG_VER_MINOR) < 0) {
++              err = dpmac_set_link_state(priv->mc_dev->mc_io, 0,
++                                         priv->mc_dev->mc_handle, &state);
++      } else {
++              link_mode_phydev2dpmac(phydev->supported, &state.supported);
++              link_mode_phydev2dpmac(phydev->advertising, &state.advertising);
++              state.state_valid = 1;
++
++              err = dpmac_set_link_state_v2(priv->mc_dev->mc_io, 0,
++                                            priv->mc_dev->mc_handle, &state);
++      }
+       if (unlikely(err))
+               dev_err(&priv->mc_dev->dev, "dpmac_set_link_state: %d\n", err);
+ }
+@@ -365,12 +410,17 @@ static void configure_link(struct dpaa2_
+       phydev->speed = cfg->rate;
+       phydev->duplex  = !!(cfg->options & DPMAC_LINK_OPT_HALF_DUPLEX);
++      if (cfg->advertising != 0) {
++              linkmode_zero(phydev->advertising);
++              link_mode_dpmac2phydev(cfg->advertising, phydev->advertising);
++      }
++
+       if (cfg->options & DPMAC_LINK_OPT_AUTONEG) {
+-              phydev->autoneg = 1;
+-              phydev->advertising |= ADVERTISED_Autoneg;
++              phydev->autoneg = AUTONEG_ENABLE;
++              linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->advertising);
+       } else {
+-              phydev->autoneg = 0;
+-              phydev->advertising &= ~ADVERTISED_Autoneg;
++              phydev->autoneg = AUTONEG_DISABLE;
++              linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->advertising);
+       }
+       phy_start_aneg(phydev);
+@@ -392,8 +442,14 @@ static irqreturn_t dpaa2_mac_irq_handler
+       /* DPNI-initiated link configuration; 'ifconfig up' also calls this */
+       if (status & DPMAC_IRQ_EVENT_LINK_CFG_REQ) {
+-              err = dpmac_get_link_cfg(mc_dev->mc_io, 0, mc_dev->mc_handle,
+-                                       &link_cfg);
++              if (cmp_dpmac_ver(priv, DPMAC_LINK_AUTONEG_VER_MAJOR,
++                                DPMAC_LINK_AUTONEG_VER_MINOR) < 0)
++                      err = dpmac_get_link_cfg(mc_dev->mc_io, 0,
++                                               mc_dev->mc_handle, &link_cfg);
++              else
++                      err = dpmac_get_link_cfg_v2(mc_dev->mc_io, 0,
++                                                  mc_dev->mc_handle,
++                                                  &link_cfg);
+               if (unlikely(err))
+                       goto out;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0175-staging-fsl-dpaa2-mac-connect-to-the-fixed-phy.patch b/target/linux/layerscape/patches-5.4/701-net-0175-staging-fsl-dpaa2-mac-connect-to-the-fixed-phy.patch
new file mode 100644 (file)
index 0000000..8d0e122
--- /dev/null
@@ -0,0 +1,92 @@
+From 69e35d8266713d36ad31b04d9b7cb32913d243c0 Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Tue, 27 Nov 2018 15:23:47 +0200
+Subject: [PATCH] staging: fsl-dpaa2/mac: connect to the fixed phy
+
+This patch is formed from 2 parts:
+   - first it moves the code that determines the if_mode to the
+     beginning so that it's used for both fixed link and phy mode.
+   - secondly, when in fixed link mode, call the phy_connect_phy
+     function as needed.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 39 ++++++++++++++++++++++++-------------
+ 1 file changed, 25 insertions(+), 14 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -642,21 +642,12 @@ static int dpaa2_mac_probe(struct fsl_mc
+       }
+ #endif /* CONFIG_FSL_DPAA2_MAC_NETDEVS */
+-      /* probe the PHY as fixed-link if the DPMAC attribute indicates so */
+-      if (priv->attr.link_type == DPMAC_LINK_TYPE_FIXED)
+-              goto probe_fixed_link;
+-
+-      /* or if there's no phy-handle defined in the device tree */
+-      phy_node = of_parse_phandle(dpmac_node, "phy-handle", 0);
+-      if (!phy_node) {
+-              goto probe_fixed_link;
+-      }
+-
++      /* get the interface mode from the dpmac of node or from the MC attributes */
+       if_mode = of_get_phy_mode(dpmac_node);
+       if (if_mode >= 0) {
+               dev_dbg(dev, "\tusing if mode %s for eth_if %d\n",
+                       phy_modes(if_mode), priv->attr.eth_if);
+-              goto phy_connect;
++              goto link_type;
+       }
+       if (priv->attr.eth_if < ARRAY_SIZE(dpaa2_mac_iface_mode)) {
+@@ -664,12 +655,23 @@ static int dpaa2_mac_probe(struct fsl_mc
+               dev_dbg(dev, "\tusing if mode %s for eth_if %d\n",
+                       phy_modes(if_mode), priv->attr.eth_if);
+       } else {
+-              dev_warn(dev, "Unexpected interface mode %d, will probe as fixed link\n",
+-                       priv->attr.eth_if);
++              dev_err(dev, "Unexpected interface mode %d\n",
++                      priv->attr.eth_if);
++              err = -EINVAL;
++              goto err_no_if_mode;
++      }
++
++link_type:
++      /* probe the PHY as fixed-link if the DPMAC attribute indicates so */
++      if (priv->attr.link_type == DPMAC_LINK_TYPE_FIXED)
++              goto probe_fixed_link;
++
++      /* or if there's no phy-handle defined in the device tree */
++      phy_node = of_parse_phandle(dpmac_node, "phy-handle", 0);
++      if (!phy_node) {
+               goto probe_fixed_link;
+       }
+-phy_connect:
+       /* try to connect to the PHY */
+       netdev->phydev = of_phy_connect(netdev, phy_node,
+                                       &dpaa2_mac_link_changed, 0, if_mode);
+@@ -702,6 +704,14 @@ probe_fixed_link:
+                       err = -EFAULT;
+                       goto err_no_phy;
+               }
++
++              err = phy_connect_direct(netdev, netdev->phydev,
++                                       &dpaa2_mac_link_changed, if_mode);
++              if (err) {
++                      dev_err(dev, "error trying to connect to PHY\n");
++                      goto err_no_phy;
++              }
++
+               dev_info(dev, "Registered fixed PHY.\n");
+       }
+@@ -709,6 +719,7 @@ probe_fixed_link:
+       return 0;
++err_no_if_mode:
+ err_defer:
+ err_no_phy:
+ #ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
diff --git a/target/linux/layerscape/patches-5.4/701-net-0176-staging-fsl-dpaa2-mac-add-pause-frames-support-for-m.patch b/target/linux/layerscape/patches-5.4/701-net-0176-staging-fsl-dpaa2-mac-add-pause-frames-support-for-m.patch
new file mode 100644 (file)
index 0000000..24c978b
--- /dev/null
@@ -0,0 +1,51 @@
+From 182bf3ddfc0168ca2df3da477b143bab17543b65 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Wed, 13 Mar 2019 19:12:47 +0200
+Subject: [PATCH] staging: fsl-dpaa2/mac: add pause frames support for managed
+ phys
+
+Read the configured dpmac options and depending on the supported
+features set the according advertising bit.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -148,6 +148,11 @@ static void dpaa2_mac_link_changed(struc
+               if (phydev->autoneg)
+                       state.options |= DPMAC_LINK_OPT_AUTONEG;
++              if (phydev->pause && linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising))
++                      state.options |= DPMAC_LINK_OPT_PAUSE;
++              if (phydev->pause && linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising))
++                      state.options |= DPMAC_LINK_OPT_ASYM_PAUSE;
++
+               netif_carrier_on(netdev);
+       } else {
+               netif_carrier_off(netdev);
+@@ -415,6 +420,20 @@ static void configure_link(struct dpaa2_
+               link_mode_dpmac2phydev(cfg->advertising, phydev->advertising);
+       }
++      if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported)) {
++              if (cfg->options & DPMAC_LINK_OPT_PAUSE)
++                      linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising);
++              else
++                      linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising);
++      }
++
++      if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->supported)) {
++              if (cfg->options & DPMAC_LINK_OPT_ASYM_PAUSE)
++                      linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising);
++              else
++                      linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising);
++      }
++
+       if (cfg->options & DPMAC_LINK_OPT_AUTONEG) {
+               phydev->autoneg = AUTONEG_ENABLE;
+               linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->advertising);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0177-staging-dpaa2-mac-Update-interface-mode-array.patch b/target/linux/layerscape/patches-5.4/701-net-0177-staging-dpaa2-mac-Update-interface-mode-array.patch
new file mode 100644 (file)
index 0000000..1b1d6a7
--- /dev/null
@@ -0,0 +1,32 @@
+From 3548421e09d714c23eb74ed7302221df8274d356 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Wed, 24 Jul 2019 20:26:06 +0300
+Subject: [PATCH] staging: dpaa2-mac: Update interface mode array
+
+We used to set PHY_INTERFACE_MODE_XGMII as a placeholder
+for interface modes listed by MC but not defined in the
+linux kernel. Some of these modes have been added in upstream,
+so update the interface mode array to better match actual PHYs.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -77,11 +77,11 @@ static phy_interface_t dpaa2_mac_iface_m
+       PHY_INTERFACE_MODE_RGMII,       /* DPMAC_ETH_IF_RGMII */
+       PHY_INTERFACE_MODE_SGMII,       /* DPMAC_ETH_IF_SGMII */
+       PHY_INTERFACE_MODE_QSGMII,      /* DPMAC_ETH_IF_QSGMII */
+-      PHY_INTERFACE_MODE_XGMII,       /* DPMAC_ETH_IF_XAUI */
++      PHY_INTERFACE_MODE_XAUI,        /* DPMAC_ETH_IF_XAUI */
+       PHY_INTERFACE_MODE_XGMII,       /* DPMAC_ETH_IF_XFI */
+       PHY_INTERFACE_MODE_XGMII,        /* DPMAC_ETH_IF_CAUI */
+-      PHY_INTERFACE_MODE_XGMII,       /* DPMAC_ETH_IF_1000BASEX */
+-      PHY_INTERFACE_MODE_XGMII,       /* DPMAC_ETH_IF_USXGMII */
++      PHY_INTERFACE_MODE_1000BASEX,   /* DPMAC_ETH_IF_1000BASEX */
++      PHY_INTERFACE_MODE_USXGMII,     /* DPMAC_ETH_IF_USXGMII */
+ };
+ static int cmp_dpmac_ver(struct dpaa2_mac_priv *priv,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0178-staging-dpaa2-mac-add-link-up-down-events-for-dpmac.patch b/target/linux/layerscape/patches-5.4/701-net-0178-staging-dpaa2-mac-add-link-up-down-events-for-dpmac.patch
new file mode 100644 (file)
index 0000000..9fbd8c7
--- /dev/null
@@ -0,0 +1,91 @@
+From 3b07b109823a593f43e794cbf44ba3a84ceefbdb Mon Sep 17 00:00:00 2001
+From: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
+Date: Fri, 23 Aug 2019 18:02:27 +0300
+Subject: [PATCH] staging: dpaa2-mac: add link up/down events for dpmac
+
+Fix a limitation that affects the networking behavior when the user
+issues ifconfig down/up on a DPNI and the link remains down.
+The actual problem was that the mac driver was not aware of the
+dpni link change event. Now, the event is sent by firmware and
+phylib state machine is manipulated conveniently.
+
+Signed-off-by: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/dpmac.h |  5 +++++
+ drivers/staging/fsl-dpaa2/mac/mac.c   | 15 ++++++++++++---
+ 2 files changed, 17 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/dpmac.h
++++ b/drivers/staging/fsl-dpaa2/mac/dpmac.h
+@@ -124,6 +124,11 @@ int dpmac_destroy(struct fsl_mc_io *mc_i
+  * IRQ event - Indicates that the link state changed
+  */
+ #define DPMAC_IRQ_EVENT_LINK_CHANGED          0x00000002
++/**
++ * IRQ event - Indicate if the phy needs to suspend or resume
++ */
++#define DPMAC_IRQ_EVENT_LINK_UP_REQ           0x00000004
++#define DPMAC_IRQ_EVENT_LINK_DOWN_REQ         0x00000008
+ int dpmac_set_irq_enable(struct fsl_mc_io *mc_io,
+                        u32 cmd_flags,
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -181,6 +181,7 @@ static void dpaa2_mac_link_changed(struc
+               dev_err(&priv->mc_dev->dev, "dpmac_set_link_state: %d\n", err);
+ }
++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS
+ static int dpaa2_mac_open(struct net_device *netdev)
+ {
+       /* start PHY state machine */
+@@ -188,6 +189,7 @@ static int dpaa2_mac_open(struct net_dev
+       return 0;
+ }
++#endif
+ static int dpaa2_mac_stop(struct net_device *netdev)
+ {
+@@ -450,6 +452,7 @@ static irqreturn_t dpaa2_mac_irq_handler
+       struct device *dev = (struct device *)arg;
+       struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
+       struct dpaa2_mac_priv *priv = dev_get_drvdata(dev);
++      struct net_device *ndev = priv->netdev;
+       struct dpmac_link_cfg link_cfg = { 0 };
+       u32 status;
+       int err;
+@@ -475,6 +478,12 @@ static irqreturn_t dpaa2_mac_irq_handler
+               configure_link(priv, &link_cfg);
+       }
++      if (status & DPMAC_IRQ_EVENT_LINK_UP_REQ)
++              phy_start(ndev->phydev);
++
++      if (status & DPMAC_IRQ_EVENT_LINK_DOWN_REQ)
++              phy_stop(ndev->phydev);
++
+ out:
+       dpmac_clear_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle,
+                              DPMAC_IRQ_INDEX, status);
+@@ -505,7 +514,9 @@ static int setup_irqs(struct fsl_mc_devi
+       }
+       err = dpmac_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle,
+-                               DPMAC_IRQ_INDEX, DPMAC_IRQ_EVENT_LINK_CFG_REQ);
++                               DPMAC_IRQ_INDEX, DPMAC_IRQ_EVENT_LINK_CFG_REQ |
++                               DPMAC_IRQ_EVENT_LINK_UP_REQ |
++                               DPMAC_IRQ_EVENT_LINK_DOWN_REQ);
+       if (err) {
+               dev_err(&mc_dev->dev, "dpmac_set_irq_mask err %d\n", err);
+               goto free_irq;
+@@ -734,8 +745,6 @@ probe_fixed_link:
+               dev_info(dev, "Registered fixed PHY.\n");
+       }
+-      dpaa2_mac_open(netdev);
+-
+       return 0;
+ err_no_if_mode:
diff --git a/target/linux/layerscape/patches-5.4/701-net-0179-staging-dpaa2-evb-Add-Edge-Virtual-Bridge-driver.patch b/target/linux/layerscape/patches-5.4/701-net-0179-staging-dpaa2-evb-Add-Edge-Virtual-Bridge-driver.patch
new file mode 100644 (file)
index 0000000..51d10b3
--- /dev/null
@@ -0,0 +1,3182 @@
+From 5d027b67938155d14814437c89fc535dff94cc10 Mon Sep 17 00:00:00 2001
+From: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+Date: Thu, 13 Apr 2017 16:03:37 +0300
+Subject: [PATCH] staging: dpaa2-evb: Add Edge Virtual Bridge driver
+
+This contains the following patches migrated from sdk-v2.0.x branch:
+
+dpaa2-evb: Added Edge Virtual Bridge driver
+dpaa2-evb: Add VLAN_8021Q dependency
+dpaa2-evb: Update dpdmux binary interface to 5.0
+dpaa2-evb: Add support to set max frame length.
+dpaa2-evb: Fix interrupt handling
+dpaa2-evb: Add object version check
+staging: dpaa2-evb: update dpdmux command ids set for MC v10.x
+dpaa2-evb: replace uintX_t types by kernel preferred kernel uX types
+dpaa2-evb: uprev binary interface to v6.0
+dpaa2-evb: move comments from declaration to definition
+dpaa2-evb: delete extraneous tabs
+dpaa2-evb: align function parameters
+dpaa2-evb: convert mc command build/parse to use C structs
+
+Initial patches have been signed-off by:
+Alex Marginean <alexandru.marginean@freescale.com>
+J. German Rivera <German.Rivera@freescale.com>
+Bogdan Hamciuc <bogdan.hamciuc@freescale.com>
+Mihaela Panescu <mihaela.panescu@freescale.com>
+Catalin Horghidan <catalin.horghidan@nxp.com>
+Ioana Ciornei <ioana.ciornei@nxp.com>
+Stuart Yoder <stuart.yoder@freescale.com>
+
+Updated FLIBs to the latest available for MC 10.x and fixed check-patch
+warnings. Updated maintainer to myself and removed the DPAA2 Ethernet
+dependency.
+
+Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/Kconfig          |    1 +
+ drivers/staging/fsl-dpaa2/Makefile         |    1 +
+ drivers/staging/fsl-dpaa2/evb/Kconfig      |    7 +
+ drivers/staging/fsl-dpaa2/evb/Makefile     |   10 +
+ drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h |  279 +++++++
+ drivers/staging/fsl-dpaa2/evb/dpdmux.c     | 1111 +++++++++++++++++++++++++
+ drivers/staging/fsl-dpaa2/evb/dpdmux.h     |  453 ++++++++++
+ drivers/staging/fsl-dpaa2/evb/evb.c        | 1238 ++++++++++++++++++++++++++++
+ 8 files changed, 3100 insertions(+)
+ create mode 100644 drivers/staging/fsl-dpaa2/evb/Kconfig
+ create mode 100644 drivers/staging/fsl-dpaa2/evb/Makefile
+ create mode 100644 drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h
+ create mode 100644 drivers/staging/fsl-dpaa2/evb/dpdmux.c
+ create mode 100644 drivers/staging/fsl-dpaa2/evb/dpdmux.h
+ create mode 100644 drivers/staging/fsl-dpaa2/evb/evb.c
+
+--- a/drivers/staging/fsl-dpaa2/Kconfig
++++ b/drivers/staging/fsl-dpaa2/Kconfig
+@@ -19,3 +19,4 @@ config FSL_DPAA2_ETHSW
+         BRIDGE to have support for bridge tools.
+ source "drivers/staging/fsl-dpaa2/mac/Kconfig"
++source "drivers/staging/fsl-dpaa2/evb/Kconfig"
+--- a/drivers/staging/fsl-dpaa2/Makefile
++++ b/drivers/staging/fsl-dpaa2/Makefile
+@@ -5,3 +5,4 @@
+ obj-$(CONFIG_FSL_DPAA2_ETHSW)         += ethsw/
+ obj-$(CONFIG_FSL_DPAA2_MAC)           += mac/
++obj-$(CONFIG_FSL_DPAA2_EVB)           += evb/
+--- /dev/null
++++ b/drivers/staging/fsl-dpaa2/evb/Kconfig
+@@ -0,0 +1,7 @@
++config FSL_DPAA2_EVB
++      tristate "DPAA2 Edge Virtual Bridge"
++      depends on FSL_MC_BUS && FSL_DPAA2
++      select VLAN_8021Q
++      default y
++      ---help---
++      Prototype driver for DPAA2 Edge Virtual Bridge.
+--- /dev/null
++++ b/drivers/staging/fsl-dpaa2/evb/Makefile
+@@ -0,0 +1,10 @@
++
++obj-$(CONFIG_FSL_DPAA2_EVB) += dpaa2-evb.o
++
++dpaa2-evb-objs := evb.o dpdmux.o
++
++all:
++      make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
++
++clean:
++      make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
+--- /dev/null
++++ b/drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h
+@@ -0,0 +1,279 @@
++/* Copyright 2013-2016 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the name of the above-listed copyright holders nor the
++ * names of any contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++#ifndef _FSL_DPDMUX_CMD_H
++#define _FSL_DPDMUX_CMD_H
++
++/* DPDMUX Version */
++#define DPDMUX_VER_MAJOR              6
++#define DPDMUX_VER_MINOR              1
++
++#define DPDMUX_CMD_BASE_VER           1
++#define DPDMUX_CMD_ID_OFFSET          4
++
++#define DPDMUX_CMD(id)        (((id) << DPDMUX_CMD_ID_OFFSET) | DPDMUX_CMD_BASE_VER)
++
++/* Command IDs */
++#define DPDMUX_CMDID_CLOSE                    DPDMUX_CMD(0x800)
++#define DPDMUX_CMDID_OPEN                     DPDMUX_CMD(0x806)
++#define DPDMUX_CMDID_CREATE                   DPDMUX_CMD(0x906)
++#define DPDMUX_CMDID_DESTROY                  DPDMUX_CMD(0x986)
++#define DPDMUX_CMDID_GET_API_VERSION          DPDMUX_CMD(0xa06)
++
++#define DPDMUX_CMDID_ENABLE                   DPDMUX_CMD(0x002)
++#define DPDMUX_CMDID_DISABLE                  DPDMUX_CMD(0x003)
++#define DPDMUX_CMDID_GET_ATTR                 DPDMUX_CMD(0x004)
++#define DPDMUX_CMDID_RESET                    DPDMUX_CMD(0x005)
++#define DPDMUX_CMDID_IS_ENABLED                       DPDMUX_CMD(0x006)
++
++#define DPDMUX_CMDID_SET_IRQ_ENABLE           DPDMUX_CMD(0x012)
++#define DPDMUX_CMDID_GET_IRQ_ENABLE           DPDMUX_CMD(0x013)
++#define DPDMUX_CMDID_SET_IRQ_MASK             DPDMUX_CMD(0x014)
++#define DPDMUX_CMDID_GET_IRQ_MASK             DPDMUX_CMD(0x015)
++#define DPDMUX_CMDID_GET_IRQ_STATUS           DPDMUX_CMD(0x016)
++#define DPDMUX_CMDID_CLEAR_IRQ_STATUS         DPDMUX_CMD(0x017)
++
++#define DPDMUX_CMDID_SET_MAX_FRAME_LENGTH     DPDMUX_CMD(0x0a1)
++
++#define DPDMUX_CMDID_UL_RESET_COUNTERS                DPDMUX_CMD(0x0a3)
++
++#define DPDMUX_CMDID_IF_SET_ACCEPTED_FRAMES   DPDMUX_CMD(0x0a7)
++#define DPDMUX_CMDID_IF_GET_ATTR              DPDMUX_CMD(0x0a8)
++#define DPDMUX_CMDID_IF_ENABLE                        DPDMUX_CMD(0x0a9)
++#define DPDMUX_CMDID_IF_DISABLE                       DPDMUX_CMD(0x0aa)
++
++#define DPDMUX_CMDID_IF_ADD_L2_RULE           DPDMUX_CMD(0x0b0)
++#define DPDMUX_CMDID_IF_REMOVE_L2_RULE                DPDMUX_CMD(0x0b1)
++#define DPDMUX_CMDID_IF_GET_COUNTER           DPDMUX_CMD(0x0b2)
++#define DPDMUX_CMDID_IF_SET_LINK_CFG          DPDMUX_CMD(0x0b3)
++#define DPDMUX_CMDID_IF_GET_LINK_STATE                DPDMUX_CMD(0x0b4)
++
++#define DPDMUX_CMDID_SET_CUSTOM_KEY           DPDMUX_CMD(0x0b5)
++#define DPDMUX_CMDID_ADD_CUSTOM_CLS_ENTRY     DPDMUX_CMD(0x0b6)
++#define DPDMUX_CMDID_REMOVE_CUSTOM_CLS_ENTRY  DPDMUX_CMD(0x0b7)
++
++#define DPDMUX_MASK(field)        \
++      GENMASK(DPDMUX_##field##_SHIFT + DPDMUX_##field##_SIZE - 1, \
++              DPDMUX_##field##_SHIFT)
++#define dpdmux_set_field(var, field, val) \
++      ((var) |= (((val) << DPDMUX_##field##_SHIFT) & DPDMUX_MASK(field)))
++#define dpdmux_get_field(var, field)      \
++      (((var) & DPDMUX_MASK(field)) >> DPDMUX_##field##_SHIFT)
++
++struct dpdmux_cmd_open {
++      u32 dpdmux_id;
++};
++
++struct dpdmux_cmd_create {
++      u8 method;
++      u8 manip;
++      u16 num_ifs;
++      u32 pad;
++
++      u16 adv_max_dmat_entries;
++      u16 adv_max_mc_groups;
++      u16 adv_max_vlan_ids;
++      u16 pad1;
++
++      u64 options;
++};
++
++struct dpdmux_cmd_destroy {
++      u32 dpdmux_id;
++};
++
++#define DPDMUX_ENABLE_SHIFT   0
++#define DPDMUX_ENABLE_SIZE    1
++
++struct dpdmux_rsp_is_enabled {
++      u8 en;
++};
++
++struct dpdmux_cmd_set_irq_enable {
++      u8 enable;
++      u8 pad[3];
++      u8 irq_index;
++};
++
++struct dpdmux_cmd_get_irq_enable {
++      u32 pad;
++      u8 irq_index;
++};
++
++struct dpdmux_rsp_get_irq_enable {
++      u8 enable;
++};
++
++struct dpdmux_cmd_set_irq_mask {
++      u32 mask;
++      u8 irq_index;
++};
++
++struct dpdmux_cmd_get_irq_mask {
++      u32 pad;
++      u8 irq_index;
++};
++
++struct dpdmux_rsp_get_irq_mask {
++      u32 mask;
++};
++
++struct dpdmux_cmd_get_irq_status {
++      u32 status;
++      u8 irq_index;
++};
++
++struct dpdmux_rsp_get_irq_status {
++      u32 status;
++};
++
++struct dpdmux_cmd_clear_irq_status {
++      u32 status;
++      u8 irq_index;
++};
++
++struct dpdmux_rsp_get_attr {
++      u8 method;
++      u8 manip;
++      u16 num_ifs;
++      u16 mem_size;
++      u16 pad;
++
++      u64 pad1;
++
++      u32 id;
++      u32 pad2;
++
++      u64 options;
++};
++
++struct dpdmux_cmd_set_max_frame_length {
++      u16 max_frame_length;
++};
++
++#define DPDMUX_ACCEPTED_FRAMES_TYPE_SHIFT     0
++#define DPDMUX_ACCEPTED_FRAMES_TYPE_SIZE      4
++#define DPDMUX_UNACCEPTED_FRAMES_ACTION_SHIFT 4
++#define DPDMUX_UNACCEPTED_FRAMES_ACTION_SIZE  4
++
++struct dpdmux_cmd_if_set_accepted_frames {
++      u16 if_id;
++      u8 frames_options;
++};
++
++struct dpdmux_cmd_if {
++      u16 if_id;
++};
++
++struct dpdmux_rsp_if_get_attr {
++      u8 pad[3];
++      u8 enabled;
++      u8 pad1[3];
++      u8 accepted_frames_type;
++      u32 rate;
++};
++
++struct dpdmux_cmd_if_l2_rule {
++      u16 if_id;
++      u8 mac_addr5;
++      u8 mac_addr4;
++      u8 mac_addr3;
++      u8 mac_addr2;
++      u8 mac_addr1;
++      u8 mac_addr0;
++
++      u32 pad;
++      u16 vlan_id;
++};
++
++struct dpdmux_cmd_if_get_counter {
++      u16 if_id;
++      u8 counter_type;
++};
++
++struct dpdmux_rsp_if_get_counter {
++      u64 pad;
++      u64 counter;
++};
++
++struct dpdmux_cmd_if_set_link_cfg {
++      u16 if_id;
++      u16 pad[3];
++
++      u32 rate;
++      u32 pad1;
++
++      u64 options;
++};
++
++struct dpdmux_cmd_if_get_link_state {
++      u16 if_id;
++};
++
++struct dpdmux_rsp_if_get_link_state {
++      u32 pad;
++      u8 up;
++      u8 pad1[3];
++
++      u32 rate;
++      u32 pad2;
++
++      u64 options;
++};
++
++struct dpdmux_rsp_get_api_version {
++      u16 major;
++      u16 minor;
++};
++
++struct dpdmux_set_custom_key {
++      u64 pad[6];
++      u64 key_cfg_iova;
++};
++
++struct dpdmux_cmd_add_custom_cls_entry {
++      u8 pad[3];
++      u8 key_size;
++      u16 pad1;
++      u16 dest_if;
++      u64 key_iova;
++      u64 mask_iova;
++};
++
++struct dpdmux_cmd_remove_custom_cls_entry {
++      u8 pad[3];
++      u8 key_size;
++      u32 pad1;
++      u64 key_iova;
++      u64 mask_iova;
++};
++
++#endif /* _FSL_DPDMUX_CMD_H */
+--- /dev/null
++++ b/drivers/staging/fsl-dpaa2/evb/dpdmux.c
+@@ -0,0 +1,1111 @@
++/* Copyright 2013-2016 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the name of the above-listed copyright holders nor the
++ * names of any contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++#include "../../fsl-mc/include/mc.h"
++#include "dpdmux.h"
++#include "dpdmux-cmd.h"
++
++/**
++ * dpdmux_open() - Open a control session for the specified object
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @dpdmux_id:                DPDMUX unique ID
++ * @token:            Returned token; use in subsequent API calls
++ *
++ * This function can be used to open a control session for an
++ * already created object; an object may have been declared in
++ * the DPL or by calling the dpdmux_create() function.
++ * This function returns a unique authentication token,
++ * associated with the specific object ID and the specific MC
++ * portal; this token must be used in all subsequent commands for
++ * this specific object.
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_open(struct fsl_mc_io *mc_io,
++              u32 cmd_flags,
++              int dpdmux_id,
++              u16 *token)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_open *cmd_params;
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_OPEN,
++                                        cmd_flags,
++                                        0);
++      cmd_params = (struct dpdmux_cmd_open *)cmd.params;
++      cmd_params->dpdmux_id = cpu_to_le32(dpdmux_id);
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      *token = mc_cmd_hdr_read_token(&cmd);
++
++      return 0;
++}
++
++/**
++ * dpdmux_close() - Close the control session of the object
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:            Token of DPDMUX object
++ *
++ * After this function is called, no further operations are
++ * allowed on the object without opening a new control session.
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_close(struct fsl_mc_io *mc_io,
++               u32 cmd_flags,
++               u16 token)
++{
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CLOSE,
++                                        cmd_flags,
++                                        token);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_create() - Create the DPDMUX object
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @dprc_token:       Parent container token; '0' for default container
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @cfg:      Configuration structure
++ * @obj_id: returned object id
++ *
++ * Create the DPDMUX object, allocate required resources and
++ * perform required initialization.
++ *
++ * The object can be created either by declaring it in the
++ * DPL file, or by calling this function.
++ *
++ * The function accepts an authentication token of a parent
++ * container that this object should be assigned to. The token
++ * can be '0' so the object will be assigned to the default container.
++ * The newly created object can be opened with the returned
++ * object id and using the container's associated tokens and MC portals.
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_create(struct fsl_mc_io *mc_io,
++                u16 dprc_token,
++                u32 cmd_flags,
++                const struct dpdmux_cfg *cfg,
++                u32 *obj_id)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_create *cmd_params;
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CREATE,
++                                        cmd_flags,
++                                        dprc_token);
++      cmd_params = (struct dpdmux_cmd_create *)cmd.params;
++      cmd_params->method = cfg->method;
++      cmd_params->manip = cfg->manip;
++      cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs);
++      cmd_params->adv_max_dmat_entries =
++                      cpu_to_le16(cfg->adv.max_dmat_entries);
++      cmd_params->adv_max_mc_groups = cpu_to_le16(cfg->adv.max_mc_groups);
++      cmd_params->adv_max_vlan_ids = cpu_to_le16(cfg->adv.max_vlan_ids);
++      cmd_params->options = cpu_to_le64(cfg->adv.options);
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      *obj_id = mc_cmd_hdr_read_token(&cmd);
++
++      return 0;
++}
++
++/**
++ * dpdmux_destroy() - Destroy the DPDMUX object and release all its resources.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @dprc_token: Parent container token; '0' for default container
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @object_id:        The object id; it must be a valid id within the container that
++ * created this object;
++ *
++ * The function accepts the authentication token of the parent container that
++ * created the object (not the one that currently owns the object). The object
++ * is searched within parent using the provided 'object_id'.
++ * All tokens to the object must be closed before calling destroy.
++ *
++ * Return:    '0' on Success; error code otherwise.
++ */
++int dpdmux_destroy(struct fsl_mc_io *mc_io,
++                 u16 dprc_token,
++                 u32 cmd_flags,
++                 u32 object_id)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_destroy *cmd_params;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_DESTROY,
++                                        cmd_flags,
++                                        dprc_token);
++      cmd_params = (struct dpdmux_cmd_destroy *)cmd.params;
++      cmd_params->dpdmux_id = cpu_to_le32(object_id);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_enable() - Enable DPDMUX functionality
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_enable(struct fsl_mc_io *mc_io,
++                u32 cmd_flags,
++                u16 token)
++{
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_ENABLE,
++                                        cmd_flags,
++                                        token);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_disable() - Disable DPDMUX functionality
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_disable(struct fsl_mc_io *mc_io,
++                 u32 cmd_flags,
++                 u16 token)
++{
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_DISABLE,
++                                        cmd_flags,
++                                        token);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_is_enabled() - Check if the DPDMUX is enabled.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ * @en:               Returns '1' if object is enabled; '0' otherwise
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_is_enabled(struct fsl_mc_io *mc_io,
++                    u32 cmd_flags,
++                    u16 token,
++                    int *en)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_rsp_is_enabled *rsp_params;
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IS_ENABLED,
++                                        cmd_flags,
++                                        token);
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      rsp_params = (struct dpdmux_rsp_is_enabled *)cmd.params;
++      *en = dpdmux_get_field(rsp_params->en, ENABLE);
++
++      return 0;
++}
++
++/**
++ * dpdmux_reset() - Reset the DPDMUX, returns the object to initial state.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_reset(struct fsl_mc_io *mc_io,
++               u32 cmd_flags,
++               u16 token)
++{
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_RESET,
++                                        cmd_flags,
++                                        token);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_set_irq_enable() - Set overall interrupt state.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ * @irq_index:        The interrupt index to configure
++ * @en:               Interrupt state - enable = 1, disable = 0
++ *
++ * Allows GPP software to control when interrupts are generated.
++ * Each interrupt can have up to 32 causes.  The enable/disable control's the
++ * overall interrupt state. if the interrupt is disabled no causes will cause
++ * an interrupt.
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_set_irq_enable(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        u8 irq_index,
++                        u8 en)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_set_irq_enable *cmd_params;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_IRQ_ENABLE,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_set_irq_enable *)cmd.params;
++      cmd_params->enable = en;
++      cmd_params->irq_index = irq_index;
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_get_irq_enable() - Get overall interrupt state.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ * @irq_index:        The interrupt index to configure
++ * @en:               Returned interrupt state - enable = 1, disable = 0
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_get_irq_enable(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        u8 irq_index,
++                        u8 *en)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_get_irq_enable *cmd_params;
++      struct dpdmux_rsp_get_irq_enable *rsp_params;
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_ENABLE,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_get_irq_enable *)cmd.params;
++      cmd_params->irq_index = irq_index;
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      rsp_params = (struct dpdmux_rsp_get_irq_enable *)cmd.params;
++      *en = rsp_params->enable;
++
++      return 0;
++}
++
++/**
++ * dpdmux_set_irq_mask() - Set interrupt mask.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ * @irq_index:        The interrupt index to configure
++ * @mask:     event mask to trigger interrupt;
++ *            each bit:
++ *                    0 = ignore event
++ *                    1 = consider event for asserting IRQ
++ *
++ * Every interrupt can have up to 32 causes and the interrupt model supports
++ * masking/unmasking each cause independently
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_set_irq_mask(struct fsl_mc_io *mc_io,
++                      u32 cmd_flags,
++                      u16 token,
++                      u8 irq_index,
++                      u32 mask)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_set_irq_mask *cmd_params;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_IRQ_MASK,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_set_irq_mask *)cmd.params;
++      cmd_params->mask = cpu_to_le32(mask);
++      cmd_params->irq_index = irq_index;
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_get_irq_mask() - Get interrupt mask.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ * @irq_index:        The interrupt index to configure
++ * @mask:     Returned event mask to trigger interrupt
++ *
++ * Every interrupt can have up to 32 causes and the interrupt model supports
++ * masking/unmasking each cause independently
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_get_irq_mask(struct fsl_mc_io *mc_io,
++                      u32 cmd_flags,
++                      u16 token,
++                      u8 irq_index,
++                      u32 *mask)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_get_irq_mask *cmd_params;
++      struct dpdmux_rsp_get_irq_mask *rsp_params;
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_MASK,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_get_irq_mask *)cmd.params;
++      cmd_params->irq_index = irq_index;
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      rsp_params = (struct dpdmux_rsp_get_irq_mask *)cmd.params;
++      *mask = le32_to_cpu(rsp_params->mask);
++
++      return 0;
++}
++
++/**
++ * dpdmux_get_irq_status() - Get the current status of any pending interrupts.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ * @irq_index:        The interrupt index to configure
++ * @status:   Returned interrupts status - one bit per cause:
++ *                    0 = no interrupt pending
++ *                    1 = interrupt pending
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_get_irq_status(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        u8 irq_index,
++                        u32 *status)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_get_irq_status *cmd_params;
++      struct dpdmux_rsp_get_irq_status *rsp_params;
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_STATUS,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_get_irq_status *)cmd.params;
++      cmd_params->status = cpu_to_le32(*status);
++      cmd_params->irq_index = irq_index;
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      rsp_params = (struct dpdmux_rsp_get_irq_status *)cmd.params;
++      *status = le32_to_cpu(rsp_params->status);
++
++      return 0;
++}
++
++/**
++ * dpdmux_clear_irq_status() - Clear a pending interrupt's status
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ * @irq_index:        The interrupt index to configure
++ * @status:   bits to clear (W1C) - one bit per cause:
++ *                    0 = don't change
++ *                    1 = clear status bit
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_clear_irq_status(struct fsl_mc_io *mc_io,
++                          u32 cmd_flags,
++                          u16 token,
++                          u8 irq_index,
++                          u32 status)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_clear_irq_status *cmd_params;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CLEAR_IRQ_STATUS,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_clear_irq_status *)cmd.params;
++      cmd_params->status = cpu_to_le32(status);
++      cmd_params->irq_index = irq_index;
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_get_attributes() - Retrieve DPDMUX attributes
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ * @attr:     Returned object's attributes
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_get_attributes(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        struct dpdmux_attr *attr)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_rsp_get_attr *rsp_params;
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_ATTR,
++                                        cmd_flags,
++                                        token);
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      rsp_params = (struct dpdmux_rsp_get_attr *)cmd.params;
++      attr->id = le32_to_cpu(rsp_params->id);
++      attr->options = le64_to_cpu(rsp_params->options);
++      attr->method = rsp_params->method;
++      attr->manip = rsp_params->manip;
++      attr->num_ifs = le16_to_cpu(rsp_params->num_ifs);
++      attr->mem_size = le16_to_cpu(rsp_params->mem_size);
++
++      return 0;
++}
++
++/**
++ * dpdmux_if_enable() - Enable Interface
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ * @if_id:    Interface Identifier
++ *
++ * Return:    Completion status. '0' on Success; Error code otherwise.
++ */
++int dpdmux_if_enable(struct fsl_mc_io *mc_io,
++                   u32 cmd_flags,
++                   u16 token,
++                   u16 if_id)
++{
++      struct dpdmux_cmd_if *cmd_params;
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_ENABLE,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_if *)cmd.params;
++      cmd_params->if_id = cpu_to_le16(if_id);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_if_disable() - Disable Interface
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ * @if_id:    Interface Identifier
++ *
++ * Return:    Completion status. '0' on Success; Error code otherwise.
++ */
++int dpdmux_if_disable(struct fsl_mc_io *mc_io,
++                    u32 cmd_flags,
++                    u16 token,
++                    u16 if_id)
++{
++      struct dpdmux_cmd_if *cmd_params;
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_DISABLE,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_if *)cmd.params;
++      cmd_params->if_id = cpu_to_le16(if_id);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_set_max_frame_length() - Set the maximum frame length in DPDMUX
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:            Token of DPDMUX object
++ * @max_frame_length: The required maximum frame length
++ *
++ * Update the maximum frame length on all DMUX interfaces.
++ * In case of VEPA, the maximum frame length on all dmux interfaces
++ * will be updated with the minimum value of the mfls of the connected
++ * dpnis and the actual value of dmux mfl.
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_set_max_frame_length(struct fsl_mc_io *mc_io,
++                              u32 cmd_flags,
++                              u16 token,
++                              u16 max_frame_length)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_set_max_frame_length *cmd_params;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_MAX_FRAME_LENGTH,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_set_max_frame_length *)cmd.params;
++      cmd_params->max_frame_length = cpu_to_le16(max_frame_length);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_ul_reset_counters() - Function resets the uplink counter
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_ul_reset_counters(struct fsl_mc_io *mc_io,
++                           u32 cmd_flags,
++                           u16 token)
++{
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_UL_RESET_COUNTERS,
++                                        cmd_flags,
++                                        token);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_if_set_accepted_frames() - Set the accepted frame types
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ * @if_id:    Interface ID (0 for uplink, or 1-num_ifs);
++ * @cfg:      Frame types configuration
++ *
++ * if 'DPDMUX_ADMIT_ONLY_VLAN_TAGGED' is set - untagged frames or
++ * priority-tagged frames are discarded.
++ * if 'DPDMUX_ADMIT_ONLY_UNTAGGED' is set - untagged frames or
++ * priority-tagged frames are accepted.
++ * if 'DPDMUX_ADMIT_ALL' is set (default mode) - all VLAN tagged,
++ * untagged and priority-tagged frame are accepted;
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_if_set_accepted_frames(struct fsl_mc_io *mc_io,
++                                u32 cmd_flags,
++                                u16 token,
++                                u16 if_id,
++                                const struct dpdmux_accepted_frames *cfg)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_if_set_accepted_frames *cmd_params;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_SET_ACCEPTED_FRAMES,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_if_set_accepted_frames *)cmd.params;
++      cmd_params->if_id = cpu_to_le16(if_id);
++      dpdmux_set_field(cmd_params->frames_options, ACCEPTED_FRAMES_TYPE,
++                       cfg->type);
++      dpdmux_set_field(cmd_params->frames_options, UNACCEPTED_FRAMES_ACTION,
++                       cfg->unaccept_act);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_if_get_attributes() - Obtain DPDMUX interface attributes
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ * @if_id:    Interface ID (0 for uplink, or 1-num_ifs);
++ * @attr:     Interface attributes
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_if_get_attributes(struct fsl_mc_io *mc_io,
++                           u32 cmd_flags,
++                           u16 token,
++                           u16 if_id,
++                           struct dpdmux_if_attr *attr)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_if *cmd_params;
++      struct dpdmux_rsp_if_get_attr *rsp_params;
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_ATTR,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_if *)cmd.params;
++      cmd_params->if_id = cpu_to_le16(if_id);
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      rsp_params = (struct dpdmux_rsp_if_get_attr *)cmd.params;
++      attr->rate = le32_to_cpu(rsp_params->rate);
++      attr->enabled = dpdmux_get_field(rsp_params->enabled, ENABLE);
++      attr->accept_frame_type =
++                      dpdmux_get_field(rsp_params->accepted_frames_type,
++                                       ACCEPTED_FRAMES_TYPE);
++
++      return 0;
++}
++
++/**
++ * dpdmux_if_remove_l2_rule() - Remove L2 rule from DPDMUX table
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ * @if_id:    Destination interface ID
++ * @rule:     L2 rule
++ *
++ * Function removes a L2 rule from DPDMUX table
++ * or adds an interface to an existing multicast address
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_if_remove_l2_rule(struct fsl_mc_io *mc_io,
++                           u32 cmd_flags,
++                           u16 token,
++                           u16 if_id,
++                           const struct dpdmux_l2_rule *rule)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_if_l2_rule *cmd_params;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_REMOVE_L2_RULE,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_if_l2_rule *)cmd.params;
++      cmd_params->if_id = cpu_to_le16(if_id);
++      cmd_params->vlan_id = cpu_to_le16(rule->vlan_id);
++      cmd_params->mac_addr5 = rule->mac_addr[5];
++      cmd_params->mac_addr4 = rule->mac_addr[4];
++      cmd_params->mac_addr3 = rule->mac_addr[3];
++      cmd_params->mac_addr2 = rule->mac_addr[2];
++      cmd_params->mac_addr1 = rule->mac_addr[1];
++      cmd_params->mac_addr0 = rule->mac_addr[0];
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_if_add_l2_rule() - Add L2 rule into DPDMUX table
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMUX object
++ * @if_id:    Destination interface ID
++ * @rule:     L2 rule
++ *
++ * Function adds a L2 rule into DPDMUX table
++ * or adds an interface to an existing multicast address
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_if_add_l2_rule(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        u16 if_id,
++                        const struct dpdmux_l2_rule *rule)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_if_l2_rule *cmd_params;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_ADD_L2_RULE,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_if_l2_rule *)cmd.params;
++      cmd_params->if_id = cpu_to_le16(if_id);
++      cmd_params->vlan_id = cpu_to_le16(rule->vlan_id);
++      cmd_params->mac_addr5 = rule->mac_addr[5];
++      cmd_params->mac_addr4 = rule->mac_addr[4];
++      cmd_params->mac_addr3 = rule->mac_addr[3];
++      cmd_params->mac_addr2 = rule->mac_addr[2];
++      cmd_params->mac_addr1 = rule->mac_addr[1];
++      cmd_params->mac_addr0 = rule->mac_addr[0];
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_if_get_counter() - Functions obtains specific counter of an interface
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPDMUX object
++ * @if_id:  Interface Id
++ * @counter_type: counter type
++ * @counter: Returned specific counter information
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_if_get_counter(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        u16 if_id,
++                        enum dpdmux_counter_type counter_type,
++                        u64 *counter)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_if_get_counter *cmd_params;
++      struct dpdmux_rsp_if_get_counter *rsp_params;
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_COUNTER,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_if_get_counter *)cmd.params;
++      cmd_params->if_id = cpu_to_le16(if_id);
++      cmd_params->counter_type = counter_type;
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      rsp_params = (struct dpdmux_rsp_if_get_counter *)cmd.params;
++      *counter = le64_to_cpu(rsp_params->counter);
++
++      return 0;
++}
++
++/**
++ * dpdmux_if_set_link_cfg() - set the link configuration.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSW object
++ * @if_id: interface id
++ * @cfg: Link configuration
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmux_if_set_link_cfg(struct fsl_mc_io *mc_io,
++                         u32 cmd_flags,
++                         u16 token,
++                         u16 if_id,
++                         struct dpdmux_link_cfg *cfg)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_if_set_link_cfg *cmd_params;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_SET_LINK_CFG,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_if_set_link_cfg *)cmd.params;
++      cmd_params->if_id = cpu_to_le16(if_id);
++      cmd_params->rate = cpu_to_le32(cfg->rate);
++      cmd_params->options = cpu_to_le64(cfg->options);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_if_get_link_state - Return the link state
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSW object
++ * @if_id: interface id
++ * @state: link state
++ *
++ * @returns   '0' on Success; Error code otherwise.
++ */
++int dpdmux_if_get_link_state(struct fsl_mc_io *mc_io,
++                           u32 cmd_flags,
++                           u16 token,
++                           u16 if_id,
++                           struct dpdmux_link_state *state)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_cmd_if_get_link_state *cmd_params;
++      struct dpdmux_rsp_if_get_link_state *rsp_params;
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_LINK_STATE,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_if_get_link_state *)cmd.params;
++      cmd_params->if_id = cpu_to_le16(if_id);
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      rsp_params = (struct dpdmux_rsp_if_get_link_state *)cmd.params;
++      state->rate = le32_to_cpu(rsp_params->rate);
++      state->options = le64_to_cpu(rsp_params->options);
++      state->up = dpdmux_get_field(rsp_params->up, ENABLE);
++
++      return 0;
++}
++
++/**
++ * dpdmux_set_custom_key - Set a custom classification key.
++ *
++ * This API is only available for DPDMUX instance created with
++ * DPDMUX_METHOD_CUSTOM.  This API must be called before populating the
++ * classification table using dpdmux_add_custom_cls_entry.
++ *
++ * Calls to dpdmux_set_custom_key remove all existing classification entries
++ * that may have been added previously using dpdmux_add_custom_cls_entry.
++ *
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSW object
++ * @if_id: interface id
++ * @key_cfg_iova: DMA address of a configuration structure set up using
++ *              dpkg_prepare_key_cfg. Maximum key size is 24 bytes.
++ *
++ * @returns   '0' on Success; Error code otherwise.
++ */
++int dpdmux_set_custom_key(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        u64 key_cfg_iova)
++{
++      struct dpdmux_set_custom_key *cmd_params;
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_CUSTOM_KEY,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_set_custom_key *)cmd.params;
++      cmd_params->key_cfg_iova = cpu_to_le64(key_cfg_iova);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_add_custom_cls_entry - Adds a custom classification entry.
++ *
++ * This API is only available for DPDMUX instances created with
++ * DPDMUX_METHOD_CUSTOM.  Before calling this function a classification key
++ * composition rule must be set up using dpdmux_set_custom_key.
++ *
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSW object
++ * @rule: Classification rule to insert.  Rules cannot be duplicated, if a
++ *    matching rule already exists, the action will be replaced.
++ * @action: Action to perform for matching traffic.
++ *
++ * @returns   '0' on Success; Error code otherwise.
++ */
++int dpdmux_add_custom_cls_entry(struct fsl_mc_io *mc_io,
++                              u32 cmd_flags,
++                              u16 token,
++                              struct dpdmux_rule_cfg *rule,
++                              struct dpdmux_cls_action *action)
++{
++      struct dpdmux_cmd_add_custom_cls_entry *cmd_params;
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_ADD_CUSTOM_CLS_ENTRY,
++                                        cmd_flags,
++                                        token);
++
++      cmd_params = (struct dpdmux_cmd_add_custom_cls_entry *)cmd.params;
++      cmd_params->key_size = rule->key_size;
++      cmd_params->dest_if = cpu_to_le16(action->dest_if);
++      cmd_params->key_iova = cpu_to_le64(rule->key_iova);
++      cmd_params->mask_iova = cpu_to_le64(rule->mask_iova);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_remove_custom_cls_entry - Removes a custom classification entry.
++ *
++ * This API is only available for DPDMUX instances created with
++ * DPDMUX_METHOD_CUSTOM.  The API can be used to remove classification
++ * entries previously inserted using dpdmux_add_custom_cls_entry.
++ *
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSW object
++ * @rule: Classification rule to remove
++ *
++ * @returns   '0' on Success; Error code otherwise.
++ */
++int dpdmux_remove_custom_cls_entry(struct fsl_mc_io *mc_io,
++                                 u32 cmd_flags,
++                                 u16 token,
++                                 struct dpdmux_rule_cfg *rule)
++{
++      struct dpdmux_cmd_remove_custom_cls_entry *cmd_params;
++      struct mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_REMOVE_CUSTOM_CLS_ENTRY,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpdmux_cmd_remove_custom_cls_entry *)cmd.params;
++      cmd_params->key_size = rule->key_size;
++      cmd_params->key_iova = cpu_to_le64(rule->key_iova);
++      cmd_params->mask_iova = cpu_to_le64(rule->mask_iova);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmux_get_api_version() - Get Data Path Demux API version
++ * @mc_io:  Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @major_ver:        Major version of data path demux API
++ * @minor_ver:        Minor version of data path demux API
++ *
++ * Return:  '0' on Success; Error code otherwise.
++ */
++int dpdmux_get_api_version(struct fsl_mc_io *mc_io,
++                         u32 cmd_flags,
++                         u16 *major_ver,
++                         u16 *minor_ver)
++{
++      struct mc_command cmd = { 0 };
++      struct dpdmux_rsp_get_api_version *rsp_params;
++      int err;
++
++      cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_API_VERSION,
++                                      cmd_flags,
++                                      0);
++
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      rsp_params = (struct dpdmux_rsp_get_api_version *)cmd.params;
++      *major_ver = le16_to_cpu(rsp_params->major);
++      *minor_ver = le16_to_cpu(rsp_params->minor);
++
++      return 0;
++}
+--- /dev/null
++++ b/drivers/staging/fsl-dpaa2/evb/dpdmux.h
+@@ -0,0 +1,453 @@
++/* Copyright 2013-2015 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the name of the above-listed copyright holders nor the
++ * names of any contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++#ifndef __FSL_DPDMUX_H
++#define __FSL_DPDMUX_H
++
++struct fsl_mc_io;
++
++/* Data Path Demux API
++ * Contains API for handling DPDMUX topology and functionality
++ */
++
++int dpdmux_open(struct fsl_mc_io *mc_io,
++              u32 cmd_flags,
++              int dpdmux_id,
++              u16 *token);
++
++int dpdmux_close(struct fsl_mc_io *mc_io,
++               u32 cmd_flags,
++               u16 token);
++
++/**
++ * DPDMUX general options
++ */
++
++/**
++ * Enable bridging between internal interfaces
++ */
++#define DPDMUX_OPT_BRIDGE_EN  0x0000000000000002ULL
++
++/**
++ * Mask support for classification
++ */
++#define DPDMUX_OPT_CLS_MASK_SUPPORT           0x0000000000000020ULL
++
++#define DPDMUX_IRQ_INDEX_IF   0x0000
++#define DPDMUX_IRQ_INDEX      0x0001
++
++/**
++ * IRQ event - Indicates that the link state changed
++ */
++#define DPDMUX_IRQ_EVENT_LINK_CHANGED 0x0001
++
++/**
++ * enum dpdmux_manip - DPDMUX manipulation operations
++ * @DPDMUX_MANIP_NONE:        No manipulation on frames
++ * @DPDMUX_MANIP_ADD_REMOVE_S_VLAN: Add S-VLAN on egress, remove it on ingress
++ */
++enum dpdmux_manip {
++      DPDMUX_MANIP_NONE = 0x0,
++      DPDMUX_MANIP_ADD_REMOVE_S_VLAN = 0x1
++};
++
++/**
++ * enum dpdmux_method - DPDMUX method options
++ * @DPDMUX_METHOD_NONE: no DPDMUX method
++ * @DPDMUX_METHOD_C_VLAN_MAC: DPDMUX based on C-VLAN and MAC address
++ * @DPDMUX_METHOD_MAC: DPDMUX based on MAC address
++ * @DPDMUX_METHOD_C_VLAN: DPDMUX based on C-VLAN
++ * @DPDMUX_METHOD_S_VLAN: DPDMUX based on S-VLAN
++ */
++enum dpdmux_method {
++      DPDMUX_METHOD_NONE = 0x0,
++      DPDMUX_METHOD_C_VLAN_MAC = 0x1,
++      DPDMUX_METHOD_MAC = 0x2,
++      DPDMUX_METHOD_C_VLAN = 0x3,
++      DPDMUX_METHOD_S_VLAN = 0x4,
++      DPDMUX_METHOD_CUSTOM = 0x5
++};
++
++/**
++ * struct dpdmux_cfg - DPDMUX configuration parameters
++ * @method: Defines the operation method for the DPDMUX address table
++ * @manip: Required manipulation operation
++ * @num_ifs: Number of interfaces (excluding the uplink interface)
++ * @adv: Advanced parameters; default is all zeros;
++ *     use this structure to change default settings
++ */
++struct dpdmux_cfg {
++      enum dpdmux_method method;
++      enum dpdmux_manip manip;
++      u16 num_ifs;
++      /**
++       * struct adv - Advanced parameters
++       * @options: DPDMUX options - combination of 'DPDMUX_OPT_<X>' flags
++       * @max_dmat_entries: Maximum entries in DPDMUX address table
++       *              0 - indicates default: 64 entries per interface.
++       * @max_mc_groups: Number of multicast groups in DPDMUX table
++       *              0 - indicates default: 32 multicast groups
++       * @max_vlan_ids: max vlan ids allowed in the system -
++       *              relevant only case of working in mac+vlan method.
++       *              0 - indicates default 16 vlan ids.
++       */
++      struct {
++              u64 options;
++              u16 max_dmat_entries;
++              u16 max_mc_groups;
++              u16 max_vlan_ids;
++      } adv;
++};
++
++int dpdmux_create(struct fsl_mc_io *mc_io,
++                u16 dprc_token,
++                u32 cmd_flags,
++                const struct dpdmux_cfg *cfg,
++                u32 *obj_id);
++
++int dpdmux_destroy(struct fsl_mc_io *mc_io,
++                 u16 dprc_token,
++                 u32 cmd_flags,
++                 u32 object_id);
++
++int dpdmux_enable(struct fsl_mc_io *mc_io,
++                u32 cmd_flags,
++                u16 token);
++
++int dpdmux_disable(struct fsl_mc_io *mc_io,
++                 u32 cmd_flags,
++                 u16 token);
++
++int dpdmux_is_enabled(struct fsl_mc_io *mc_io,
++                    u32 cmd_flags,
++                    u16 token,
++                    int *en);
++
++int dpdmux_reset(struct fsl_mc_io *mc_io,
++               u32 cmd_flags,
++               u16 token);
++
++int dpdmux_set_irq_enable(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        u8 irq_index,
++                        u8 en);
++
++int dpdmux_get_irq_enable(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        u8 irq_index,
++                        u8 *en);
++
++int dpdmux_set_irq_mask(struct fsl_mc_io *mc_io,
++                      u32 cmd_flags,
++                      u16 token,
++                      u8 irq_index,
++                      u32 mask);
++
++int dpdmux_get_irq_mask(struct fsl_mc_io *mc_io,
++                      u32 cmd_flags,
++                      u16 token,
++                      u8 irq_index,
++                      u32 *mask);
++
++int dpdmux_get_irq_status(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        u8 irq_index,
++                        u32 *status);
++
++int dpdmux_clear_irq_status(struct fsl_mc_io *mc_io,
++                          u32 cmd_flags,
++                          u16 token,
++                          u8 irq_index,
++                          u32 status);
++
++/**
++ * struct dpdmux_attr - Structure representing DPDMUX attributes
++ * @id: DPDMUX object ID
++ * @options: Configuration options (bitmap)
++ * @method: DPDMUX address table method
++ * @manip: DPDMUX manipulation type
++ * @num_ifs: Number of interfaces (excluding the uplink interface)
++ * @mem_size: DPDMUX frame storage memory size
++ */
++struct dpdmux_attr {
++      int id;
++      u64 options;
++      enum dpdmux_method method;
++      enum dpdmux_manip manip;
++      u16 num_ifs;
++      u16 mem_size;
++};
++
++int dpdmux_get_attributes(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        struct dpdmux_attr *attr);
++
++int dpdmux_set_max_frame_length(struct fsl_mc_io *mc_io,
++                              u32 cmd_flags,
++                              u16 token,
++                              u16 max_frame_length);
++
++/**
++ * enum dpdmux_counter_type - Counter types
++ * @DPDMUX_CNT_ING_FRAME: Counts ingress frames
++ * @DPDMUX_CNT_ING_BYTE: Counts ingress bytes
++ * @DPDMUX_CNT_ING_FLTR_FRAME: Counts filtered ingress frames
++ * @DPDMUX_CNT_ING_FRAME_DISCARD: Counts discarded ingress frames
++ * @DPDMUX_CNT_ING_MCAST_FRAME: Counts ingress multicast frames
++ * @DPDMUX_CNT_ING_MCAST_BYTE: Counts ingress multicast bytes
++ * @DPDMUX_CNT_ING_BCAST_FRAME: Counts ingress broadcast frames
++ * @DPDMUX_CNT_ING_BCAST_BYTES: Counts ingress broadcast bytes
++ * @DPDMUX_CNT_EGR_FRAME: Counts egress frames
++ * @DPDMUX_CNT_EGR_BYTE: Counts egress bytes
++ * @DPDMUX_CNT_EGR_FRAME_DISCARD: Counts discarded egress frames
++ */
++enum dpdmux_counter_type {
++      DPDMUX_CNT_ING_FRAME = 0x0,
++      DPDMUX_CNT_ING_BYTE = 0x1,
++      DPDMUX_CNT_ING_FLTR_FRAME = 0x2,
++      DPDMUX_CNT_ING_FRAME_DISCARD = 0x3,
++      DPDMUX_CNT_ING_MCAST_FRAME = 0x4,
++      DPDMUX_CNT_ING_MCAST_BYTE = 0x5,
++      DPDMUX_CNT_ING_BCAST_FRAME = 0x6,
++      DPDMUX_CNT_ING_BCAST_BYTES = 0x7,
++      DPDMUX_CNT_EGR_FRAME = 0x8,
++      DPDMUX_CNT_EGR_BYTE = 0x9,
++      DPDMUX_CNT_EGR_FRAME_DISCARD = 0xa
++};
++
++/**
++ * enum dpdmux_accepted_frames_type - DPDMUX frame types
++ * @DPDMUX_ADMIT_ALL: The device accepts VLAN tagged, untagged and
++ *                    priority-tagged frames
++ * @DPDMUX_ADMIT_ONLY_VLAN_TAGGED: The device discards untagged frames or
++ *                            priority-tagged frames that are received on this
++ *                            interface
++ * @DPDMUX_ADMIT_ONLY_UNTAGGED: Untagged frames or priority-tagged frames
++ *                            received on this interface are accepted
++ */
++enum dpdmux_accepted_frames_type {
++      DPDMUX_ADMIT_ALL = 0,
++      DPDMUX_ADMIT_ONLY_VLAN_TAGGED = 1,
++      DPDMUX_ADMIT_ONLY_UNTAGGED = 2
++};
++
++/**
++ * enum dpdmux_action - DPDMUX action for un-accepted frames
++ * @DPDMUX_ACTION_DROP: Drop un-accepted frames
++ * @DPDMUX_ACTION_REDIRECT_TO_CTRL: Redirect un-accepted frames to the
++ *                                    control interface
++ */
++enum dpdmux_action {
++      DPDMUX_ACTION_DROP = 0,
++      DPDMUX_ACTION_REDIRECT_TO_CTRL = 1
++};
++
++/**
++ * struct dpdmux_accepted_frames - Frame types configuration
++ * @type: Defines ingress accepted frames
++ * @unaccept_act: Defines action on frames not accepted
++ */
++struct dpdmux_accepted_frames {
++      enum dpdmux_accepted_frames_type type;
++      enum dpdmux_action unaccept_act;
++};
++
++int dpdmux_if_set_accepted_frames(struct fsl_mc_io *mc_io,
++                                u32 cmd_flags,
++                                u16 token,
++                                u16 if_id,
++                                const struct dpdmux_accepted_frames *cfg);
++
++/**
++ * struct dpdmux_if_attr - Structure representing frame types configuration
++ * @rate: Configured interface rate (in bits per second)
++ * @enabled: Indicates if interface is enabled
++ * @accept_frame_type: Indicates type of accepted frames for the interface
++ */
++struct dpdmux_if_attr {
++      u32 rate;
++      int enabled;
++      enum dpdmux_accepted_frames_type accept_frame_type;
++};
++
++int dpdmux_if_get_attributes(struct fsl_mc_io *mc_io,
++                           u32 cmd_flags,
++                           u16 token,
++                           u16 if_id,
++                           struct dpdmux_if_attr *attr);
++
++int dpdmux_if_enable(struct fsl_mc_io *mc_io,
++                   u32 cmd_flags,
++                   u16 token,
++                   u16 if_id);
++
++int dpdmux_if_disable(struct fsl_mc_io *mc_io,
++                    u32 cmd_flags,
++                    u16 token,
++                    u16 if_id);
++
++/**
++ * struct dpdmux_l2_rule - Structure representing L2 rule
++ * @mac_addr: MAC address
++ * @vlan_id: VLAN ID
++ */
++struct dpdmux_l2_rule {
++      u8 mac_addr[6];
++      u16 vlan_id;
++};
++
++int dpdmux_if_remove_l2_rule(struct fsl_mc_io *mc_io,
++                           u32 cmd_flags,
++                           u16 token,
++                           u16 if_id,
++                           const struct dpdmux_l2_rule *rule);
++
++int dpdmux_if_add_l2_rule(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        u16 if_id,
++                        const struct dpdmux_l2_rule *rule);
++
++int dpdmux_if_get_counter(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        u16 if_id,
++                        enum dpdmux_counter_type counter_type,
++                        u64 *counter);
++
++int dpdmux_ul_reset_counters(struct fsl_mc_io *mc_io,
++                           u32 cmd_flags,
++                           u16 token);
++
++/**
++ * Enable auto-negotiation
++ */
++#define DPDMUX_LINK_OPT_AUTONEG               0x0000000000000001ULL
++/**
++ * Enable half-duplex mode
++ */
++#define DPDMUX_LINK_OPT_HALF_DUPLEX   0x0000000000000002ULL
++/**
++ * Enable pause frames
++ */
++#define DPDMUX_LINK_OPT_PAUSE         0x0000000000000004ULL
++/**
++ * Enable a-symmetric pause frames
++ */
++#define DPDMUX_LINK_OPT_ASYM_PAUSE    0x0000000000000008ULL
++
++/**
++ * struct dpdmux_link_cfg - Structure representing DPDMUX link configuration
++ * @rate: Rate
++ * @options: Mask of available options; use 'DPDMUX_LINK_OPT_<X>' values
++ */
++struct dpdmux_link_cfg {
++      u32 rate;
++      u64 options;
++};
++
++int dpdmux_if_set_link_cfg(struct fsl_mc_io *mc_io,
++                         u32 cmd_flags,
++                         u16 token,
++                         u16 if_id,
++                         struct dpdmux_link_cfg *cfg);
++/**
++ * struct dpdmux_link_state - Structure representing DPDMUX link state
++ * @rate: Rate
++ * @options: Mask of available options; use 'DPDMUX_LINK_OPT_<X>' values
++ * @up: 0 - down, 1 - up
++ */
++struct dpdmux_link_state {
++      u32 rate;
++      u64 options;
++      int      up;
++};
++
++int dpdmux_if_get_link_state(struct fsl_mc_io *mc_io,
++                           u32 cmd_flags,
++                           u16 token,
++                           u16 if_id,
++                           struct dpdmux_link_state *state);
++
++int dpdmux_set_custom_key(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        u64 key_cfg_iova);
++
++/**
++ * struct dpdmux_rule_cfg - Custom classification rule.
++ *
++ * @key_iova: DMA address of buffer storing the look-up value
++ * @mask_iova: DMA address of the mask used for TCAM classification
++ * @key_size: size, in bytes, of the look-up value. This must match the size
++ *    of the look-up key defined using dpdmux_set_custom_key, otherwise the
++ *    entry will never be hit
++ */
++struct dpdmux_rule_cfg {
++      u64 key_iova;
++      u64 mask_iova;
++      u8 key_size;
++};
++
++/**
++ * struct dpdmux_cls_action - Action to execute for frames matching the
++ *    classification entry
++ *
++ * @dest_if: Interface to forward the frames to. Port numbering is similar to
++ *    the one used to connect interfaces:
++ *    - 0 is the uplink port,
++ *    - all others are downlink ports.
++ */
++struct dpdmux_cls_action {
++      u16 dest_if;
++};
++
++int dpdmux_add_custom_cls_entry(struct fsl_mc_io *mc_io,
++                              u32 cmd_flags,
++                              u16 token,
++                              struct dpdmux_rule_cfg *rule,
++                              struct dpdmux_cls_action *action);
++
++int dpdmux_remove_custom_cls_entry(struct fsl_mc_io *mc_io,
++                                 u32 cmd_flags,
++                                 u16 token,
++                                 struct dpdmux_rule_cfg *rule);
++
++int dpdmux_get_api_version(struct fsl_mc_io *mc_io,
++                         u32 cmd_flags,
++                         u16 *major_ver,
++                         u16 *minor_ver);
++
++#endif /* __FSL_DPDMUX_H */
+--- /dev/null
++++ b/drivers/staging/fsl-dpaa2/evb/evb.c
+@@ -0,0 +1,1238 @@
++/* Copyright 2015 Freescale Semiconductor Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++#include <linux/module.h>
++#include <linux/msi.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/if_vlan.h>
++
++#include <uapi/linux/if_bridge.h>
++#include <net/netlink.h>
++
++#include "../../fsl-mc/include/mc.h"
++
++#include "dpdmux.h"
++#include "dpdmux-cmd.h"
++
++/* Minimal supported DPDMUX version */
++#define DPDMUX_MIN_VER_MAJOR                  6
++#define DPDMUX_MIN_VER_MINOR                  0
++
++/* IRQ index */
++#define DPDMUX_MAX_IRQ_NUM                    2
++
++/* MAX FRAME LENGTH (currently 10k) */
++#define EVB_MAX_FRAME_LENGTH                  (10 * 1024)
++/* MIN FRAME LENGTH (64 bytes + 4 bytes CRC) */
++#define EVB_MIN_FRAME_LENGTH                  68
++
++struct evb_port_priv {
++      struct net_device       *netdev;
++      struct list_head        list;
++      u16                     port_index;
++      struct evb_priv         *evb_priv;
++      u8                      vlans[VLAN_VID_MASK + 1];
++};
++
++struct evb_priv {
++      /* keep first */
++      struct evb_port_priv    uplink;
++
++      struct fsl_mc_io        *mc_io;
++      struct list_head        port_list;
++      struct dpdmux_attr      attr;
++      u16                     mux_handle;
++      int                     dev_id;
++};
++
++static int _evb_port_carrier_state_sync(struct net_device *netdev)
++{
++      struct evb_port_priv            *port_priv = netdev_priv(netdev);
++      struct dpdmux_link_state        state;
++      int err;
++
++      err = dpdmux_if_get_link_state(port_priv->evb_priv->mc_io, 0,
++                                     port_priv->evb_priv->mux_handle,
++                                     port_priv->port_index, &state);
++      if (unlikely(err)) {
++              netdev_err(netdev, "dpdmux_if_get_link_state() err %d\n", err);
++              return err;
++      }
++
++      WARN_ONCE(state.up > 1, "Garbage read into link_state");
++
++      if (state.up)
++              netif_carrier_on(port_priv->netdev);
++      else
++              netif_carrier_off(port_priv->netdev);
++
++      return 0;
++}
++
++static int evb_port_open(struct net_device *netdev)
++{
++      int                     err;
++
++      /* FIXME: enable port when support added */
++
++      err = _evb_port_carrier_state_sync(netdev);
++      if (err) {
++              netdev_err(netdev, "ethsw_port_carrier_state_sync err %d\n",
++                         err);
++              return err;
++      }
++
++      return 0;
++}
++
++static netdev_tx_t evb_dropframe(struct sk_buff *skb, struct net_device *dev)
++{
++      /* we don't support I/O for now, drop the frame */
++      dev_kfree_skb_any(skb);
++      return NETDEV_TX_OK;
++}
++
++static int evb_links_state_update(struct evb_priv *priv)
++{
++      struct evb_port_priv    *port_priv;
++      struct list_head        *pos;
++      int err;
++
++      list_for_each(pos, &priv->port_list) {
++              port_priv = list_entry(pos, struct evb_port_priv, list);
++
++              err = _evb_port_carrier_state_sync(port_priv->netdev);
++              if (err)
++                      netdev_err(port_priv->netdev,
++                                 "_evb_port_carrier_state_sync err %d\n",
++                                 err);
++      }
++
++      return 0;
++}
++
++static irqreturn_t evb_irq0_handler(int irq_num, void *arg)
++{
++      return IRQ_WAKE_THREAD;
++}
++
++static irqreturn_t _evb_irq0_handler_thread(int irq_num, void *arg)
++{
++      struct device           *dev = (struct device *)arg;
++      struct fsl_mc_device    *evb_dev = to_fsl_mc_device(dev);
++      struct net_device       *netdev = dev_get_drvdata(dev);
++      struct evb_priv         *priv = netdev_priv(netdev);
++      struct fsl_mc_io        *io = priv->mc_io;
++      u16 token = priv->mux_handle;
++      int irq_index = DPDMUX_IRQ_INDEX_IF;
++
++      /* Mask the events and the if_id reserved bits to be cleared on read */
++      u32 status = DPDMUX_IRQ_EVENT_LINK_CHANGED | 0xFFFF0000;
++      int err;
++
++      /* Sanity check */
++      if (WARN_ON(!evb_dev || !evb_dev->irqs || !evb_dev->irqs[irq_index]))
++              goto out;
++      if (WARN_ON(evb_dev->irqs[irq_index]->msi_desc->irq != irq_num))
++              goto out;
++
++      err = dpdmux_get_irq_status(io, 0, token, irq_index, &status);
++      if (unlikely(err)) {
++              netdev_err(netdev, "Can't get irq status (err %d)", err);
++              err = dpdmux_clear_irq_status(io, 0, token, irq_index,
++                                            0xFFFFFFFF);
++              if (unlikely(err))
++                      netdev_err(netdev, "Can't clear irq status (err %d)",
++                                 err);
++              goto out;
++      }
++
++      if (status & DPDMUX_IRQ_EVENT_LINK_CHANGED) {
++              err = evb_links_state_update(priv);
++              if (unlikely(err))
++                      goto out;
++      }
++
++out:
++      return IRQ_HANDLED;
++}
++
++static int evb_setup_irqs(struct fsl_mc_device *evb_dev)
++{
++      struct device           *dev = &evb_dev->dev;
++      struct net_device       *netdev = dev_get_drvdata(dev);
++      struct evb_priv         *priv = netdev_priv(netdev);
++      int err = 0;
++      struct fsl_mc_device_irq *irq;
++      const int irq_index = DPDMUX_IRQ_INDEX_IF;
++      u32 mask = DPDMUX_IRQ_EVENT_LINK_CHANGED;
++
++      err = fsl_mc_allocate_irqs(evb_dev);
++      if (unlikely(err)) {
++              dev_err(dev, "MC irqs allocation failed\n");
++              return err;
++      }
++
++      if (WARN_ON(evb_dev->obj_desc.irq_count != DPDMUX_MAX_IRQ_NUM)) {
++              err = -EINVAL;
++              goto free_irq;
++      }
++
++      err = dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle,
++                                  irq_index, 0);
++      if (unlikely(err)) {
++              dev_err(dev, "dpdmux_set_irq_enable err %d\n", err);
++              goto free_irq;
++      }
++
++      irq = evb_dev->irqs[irq_index];
++
++      err = devm_request_threaded_irq(dev, irq->msi_desc->irq,
++                                      evb_irq0_handler,
++                                      _evb_irq0_handler_thread,
++                                      IRQF_NO_SUSPEND | IRQF_ONESHOT,
++                                      dev_name(dev), dev);
++      if (unlikely(err)) {
++              dev_err(dev, "devm_request_threaded_irq(): %d", err);
++              goto free_irq;
++      }
++
++      err = dpdmux_set_irq_mask(priv->mc_io, 0, priv->mux_handle,
++                                irq_index, mask);
++      if (unlikely(err)) {
++              dev_err(dev, "dpdmux_set_irq_mask(): %d", err);
++              goto free_devm_irq;
++      }
++
++      err = dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle,
++                                  irq_index, 1);
++      if (unlikely(err)) {
++              dev_err(dev, "dpdmux_set_irq_enable(): %d", err);
++              goto free_devm_irq;
++      }
++
++      return 0;
++
++free_devm_irq:
++      devm_free_irq(dev, irq->msi_desc->irq, dev);
++free_irq:
++      fsl_mc_free_irqs(evb_dev);
++      return err;
++}
++
++static void evb_teardown_irqs(struct fsl_mc_device *evb_dev)
++{
++      struct device           *dev = &evb_dev->dev;
++      struct net_device       *netdev = dev_get_drvdata(dev);
++      struct evb_priv         *priv = netdev_priv(netdev);
++
++      dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle,
++                            DPDMUX_IRQ_INDEX_IF, 0);
++
++      devm_free_irq(dev,
++                    evb_dev->irqs[DPDMUX_IRQ_INDEX_IF]->msi_desc->irq,
++                    dev);
++      fsl_mc_free_irqs(evb_dev);
++}
++
++static int evb_port_add_rule(struct net_device *netdev,
++                           const unsigned char *addr, u16 vid)
++{
++      struct evb_port_priv    *port_priv = netdev_priv(netdev);
++      struct dpdmux_l2_rule   rule = { .vlan_id = vid };
++      int                     err;
++
++      if (addr)
++              ether_addr_copy(rule.mac_addr, addr);
++
++      err = dpdmux_if_add_l2_rule(port_priv->evb_priv->mc_io,
++                                  0,
++                                  port_priv->evb_priv->mux_handle,
++                                  port_priv->port_index, &rule);
++      if (unlikely(err))
++              netdev_err(netdev, "dpdmux_if_add_l2_rule err %d\n", err);
++      return err;
++}
++
++static int evb_port_del_rule(struct net_device *netdev,
++                           const unsigned char *addr, u16 vid)
++{
++      struct evb_port_priv    *port_priv = netdev_priv(netdev);
++      struct dpdmux_l2_rule   rule = { .vlan_id = vid };
++      int err;
++
++      if (addr)
++              ether_addr_copy(rule.mac_addr, addr);
++
++      err = dpdmux_if_remove_l2_rule(port_priv->evb_priv->mc_io,
++                                     0,
++                                     port_priv->evb_priv->mux_handle,
++                                     port_priv->port_index, &rule);
++      if (unlikely(err))
++              netdev_err(netdev, "dpdmux_if_remove_l2_rule err %d\n", err);
++      return err;
++}
++
++static bool _lookup_address(struct net_device *netdev,
++                          const unsigned char *addr)
++{
++      struct netdev_hw_addr      *ha;
++      struct netdev_hw_addr_list *list = (is_unicast_ether_addr(addr)) ?
++                                         &netdev->uc : &netdev->mc;
++
++      netif_addr_lock_bh(netdev);
++      list_for_each_entry(ha, &list->list, list) {
++              if (ether_addr_equal(ha->addr, addr)) {
++                      netif_addr_unlock_bh(netdev);
++                      return true;
++              }
++      }
++      netif_addr_unlock_bh(netdev);
++      return false;
++}
++
++static inline int evb_port_fdb_prep(struct nlattr *tb[],
++                                  struct net_device *netdev,
++                                  const unsigned char *addr, u16 *vid,
++                                  bool del)
++{
++      struct evb_port_priv    *port_priv = netdev_priv(netdev);
++      struct evb_priv         *evb_priv = port_priv->evb_priv;
++
++      *vid = 0;
++
++      if (evb_priv->attr.method != DPDMUX_METHOD_MAC &&
++          evb_priv->attr.method != DPDMUX_METHOD_C_VLAN_MAC) {
++              netdev_err(netdev,
++                         "EVB mode does not support MAC classification\n");
++              return -EOPNOTSUPP;
++      }
++
++      /* check if the address is configured on this port */
++      if (_lookup_address(netdev, addr)) {
++              if (!del)
++                      return -EEXIST;
++      } else {
++              if (del)
++                      return -ENOENT;
++      }
++
++      if (tb[NDA_VLAN] && evb_priv->attr.method == DPDMUX_METHOD_C_VLAN_MAC) {
++              if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) {
++                      netdev_err(netdev, "invalid vlan size %d\n",
++                                 nla_len(tb[NDA_VLAN]));
++                      return -EINVAL;
++              }
++
++              *vid = nla_get_u16(tb[NDA_VLAN]);
++
++              if (!*vid || *vid >= VLAN_VID_MASK) {
++                      netdev_err(netdev, "invalid vid value 0x%04x\n", *vid);
++                      return -EINVAL;
++              }
++      } else if (evb_priv->attr.method == DPDMUX_METHOD_C_VLAN_MAC) {
++              netdev_err(netdev,
++                         "EVB mode requires explicit VLAN configuration\n");
++              return -EINVAL;
++      } else if (tb[NDA_VLAN]) {
++              netdev_warn(netdev, "VLAN not supported, argument ignored\n");
++      }
++
++      return 0;
++}
++
++static int evb_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
++                          struct net_device *netdev,
++                          const unsigned char *addr, u16 vid, u16 flags,
++                          struct netlink_ext_ack *extack)
++{
++      u16 _vid;
++      int err;
++
++      /* TODO: add replace support when added to iproute bridge */
++      if (!(flags & NLM_F_REQUEST)) {
++              netdev_err(netdev,
++                         "evb_port_fdb_add unexpected flags value %08x\n",
++                         flags);
++              return -EINVAL;
++      }
++
++      err = evb_port_fdb_prep(tb, netdev, addr, &_vid, 0);
++      if (unlikely(err))
++              return err;
++
++      err = evb_port_add_rule(netdev, addr, _vid);
++      if (unlikely(err))
++              return err;
++
++      if (is_unicast_ether_addr(addr)) {
++              err = dev_uc_add(netdev, addr);
++              if (unlikely(err)) {
++                      netdev_err(netdev, "dev_uc_add err %d\n", err);
++                      return err;
++              }
++      } else {
++              err = dev_mc_add(netdev, addr);
++              if (unlikely(err)) {
++                      netdev_err(netdev, "dev_mc_add err %d\n", err);
++                      return err;
++              }
++      }
++
++      return 0;
++}
++
++static int evb_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
++                          struct net_device *netdev,
++                          const unsigned char *addr, u16 vid)
++{
++      u16 _vid;
++      int err;
++
++      err = evb_port_fdb_prep(tb, netdev, addr, &_vid, 1);
++      if (unlikely(err))
++              return err;
++
++      err = evb_port_del_rule(netdev, addr, _vid);
++      if (unlikely(err))
++              return err;
++
++      if (is_unicast_ether_addr(addr)) {
++              err = dev_uc_del(netdev, addr);
++              if (unlikely(err)) {
++                      netdev_err(netdev, "dev_uc_del err %d\n", err);
++                      return err;
++              }
++      } else {
++              err = dev_mc_del(netdev, addr);
++              if (unlikely(err)) {
++                      netdev_err(netdev, "dev_mc_del err %d\n", err);
++                      return err;
++              }
++      }
++
++      return 0;
++}
++
++static int evb_change_mtu(struct net_device *netdev,
++                        int mtu)
++{
++      struct evb_port_priv    *port_priv = netdev_priv(netdev);
++      struct evb_priv         *evb_priv = port_priv->evb_priv;
++      struct list_head        *pos;
++      int                     err = 0;
++
++      /* This operation is not permitted on downlinks */
++      if (port_priv->port_index > 0)
++              return -EPERM;
++
++      if (mtu < EVB_MIN_FRAME_LENGTH || mtu > EVB_MAX_FRAME_LENGTH) {
++              netdev_err(netdev, "Invalid MTU %d. Valid range is: %d..%d\n",
++                         mtu, EVB_MIN_FRAME_LENGTH, EVB_MAX_FRAME_LENGTH);
++              return -EINVAL;
++      }
++
++      err = dpdmux_set_max_frame_length(evb_priv->mc_io,
++                                        0,
++                                        evb_priv->mux_handle,
++                                        (uint16_t)mtu);
++
++      if (unlikely(err)) {
++              netdev_err(netdev, "dpdmux_ul_set_max_frame_length err %d\n",
++                         err);
++              return err;
++      }
++
++      /* Update the max frame length for downlinks */
++      list_for_each(pos, &evb_priv->port_list) {
++              port_priv = list_entry(pos, struct evb_port_priv, list);
++              port_priv->netdev->mtu = mtu;
++      }
++
++      netdev->mtu = mtu;
++      return 0;
++}
++
++static const struct nla_policy ifla_br_policy[IFLA_MAX + 1] = {
++      [IFLA_BRIDGE_FLAGS]     = { .type = NLA_U16 },
++      [IFLA_BRIDGE_MODE]      = { .type = NLA_U16 },
++      [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY,
++                              .len = sizeof(struct bridge_vlan_info), },
++};
++
++static int evb_setlink_af_spec(struct net_device *netdev,
++                             struct nlattr **tb)
++{
++      struct bridge_vlan_info *vinfo;
++      struct evb_port_priv    *port_priv = netdev_priv(netdev);
++      int                     err = 0;
++
++      if (!tb[IFLA_BRIDGE_VLAN_INFO]) {
++              netdev_err(netdev, "no VLAN INFO in nlmsg\n");
++              return -EOPNOTSUPP;
++      }
++
++      vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]);
++
++      if (!vinfo->vid || vinfo->vid > VLAN_VID_MASK)
++              return -EINVAL;
++
++      err = evb_port_add_rule(netdev, NULL, vinfo->vid);
++      if (unlikely(err))
++              return err;
++
++      port_priv->vlans[vinfo->vid] = 1;
++
++      return 0;
++}
++
++static int evb_setlink(struct net_device *netdev,
++                     struct nlmsghdr *nlh,
++                     u16 flags,
++                     struct netlink_ext_ack *extack)
++{
++      struct evb_port_priv    *port_priv = netdev_priv(netdev);
++      struct evb_priv         *evb_priv = port_priv->evb_priv;
++      struct nlattr           *attr;
++      struct nlattr           *tb[(IFLA_BRIDGE_MAX > IFLA_BRPORT_MAX) ?
++                                      IFLA_BRIDGE_MAX : IFLA_BRPORT_MAX + 1];
++      int                     err = 0;
++
++      if (evb_priv->attr.method != DPDMUX_METHOD_C_VLAN &&
++          evb_priv->attr.method != DPDMUX_METHOD_S_VLAN) {
++              netdev_err(netdev,
++                         "EVB mode does not support VLAN only classification\n");
++              return -EOPNOTSUPP;
++      }
++
++      attr = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
++      if (attr) {
++              err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, attr,
++                                     ifla_br_policy);
++              if (unlikely(err)) {
++                      netdev_err(netdev,
++                                 "nla_parse_nested for br_policy err %d\n",
++                                 err);
++                      return err;
++              }
++
++              err = evb_setlink_af_spec(netdev, tb);
++              return err;
++      }
++
++      netdev_err(netdev, "nlmsg_find_attr found no AF_SPEC\n");
++      return -EOPNOTSUPP;
++}
++
++static int __nla_put_netdev(struct sk_buff *skb, struct net_device *netdev)
++{
++      struct evb_port_priv    *port_priv = netdev_priv(netdev);
++      struct evb_priv         *evb_priv = port_priv->evb_priv;
++      u8                      operstate = netif_running(netdev) ?
++                              netdev->operstate : IF_OPER_DOWN;
++      int                     iflink;
++      int                     err;
++
++      err = nla_put_string(skb, IFLA_IFNAME, netdev->name);
++      if (unlikely(err))
++              goto nla_put_err;
++      err = nla_put_u32(skb, IFLA_MASTER, evb_priv->uplink.netdev->ifindex);
++      if (unlikely(err))
++              goto nla_put_err;
++      err = nla_put_u32(skb, IFLA_MTU, netdev->mtu);
++      if (unlikely(err))
++              goto nla_put_err;
++      err = nla_put_u8(skb, IFLA_OPERSTATE, operstate);
++      if (unlikely(err))
++              goto nla_put_err;
++      if (netdev->addr_len) {
++              err = nla_put(skb, IFLA_ADDRESS, netdev->addr_len,
++                            netdev->dev_addr);
++              if (unlikely(err))
++                      goto nla_put_err;
++      }
++
++      iflink = dev_get_iflink(netdev);
++      if (netdev->ifindex != iflink) {
++              err = nla_put_u32(skb, IFLA_LINK, iflink);
++              if (unlikely(err))
++                      goto nla_put_err;
++      }
++
++      return 0;
++
++nla_put_err:
++      netdev_err(netdev, "nla_put_ err %d\n", err);
++      return err;
++}
++
++static int __nla_put_port(struct sk_buff *skb, struct net_device *netdev)
++{
++      struct nlattr   *nest;
++      int             err;
++
++      nest = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED);
++      if (!nest) {
++              netdev_err(netdev, "nla_nest_start failed\n");
++              return -ENOMEM;
++      }
++
++      err = nla_put_u8(skb, IFLA_BRPORT_STATE, BR_STATE_FORWARDING);
++      if (unlikely(err))
++              goto nla_put_err;
++      err = nla_put_u16(skb, IFLA_BRPORT_PRIORITY, 0);
++      if (unlikely(err))
++              goto nla_put_err;
++      err = nla_put_u32(skb, IFLA_BRPORT_COST, 0);
++      if (unlikely(err))
++              goto nla_put_err;
++      err = nla_put_u8(skb, IFLA_BRPORT_MODE, 0);
++      if (unlikely(err))
++              goto nla_put_err;
++      err = nla_put_u8(skb, IFLA_BRPORT_GUARD, 0);
++      if (unlikely(err))
++              goto nla_put_err;
++      err = nla_put_u8(skb, IFLA_BRPORT_PROTECT, 0);
++      if (unlikely(err))
++              goto nla_put_err;
++      err = nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, 0);
++      if (unlikely(err))
++              goto nla_put_err;
++      err = nla_put_u8(skb, IFLA_BRPORT_LEARNING, 0);
++      if (unlikely(err))
++              goto nla_put_err;
++      err = nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, 1);
++      if (unlikely(err))
++              goto nla_put_err;
++      nla_nest_end(skb, nest);
++
++      return 0;
++
++nla_put_err:
++      netdev_err(netdev, "nla_put_ err %d\n", err);
++      nla_nest_cancel(skb, nest);
++      return err;
++}
++
++static int __nla_put_vlan(struct sk_buff *skb,  struct net_device *netdev)
++{
++      struct evb_port_priv    *port_priv = netdev_priv(netdev);
++      struct nlattr           *nest;
++      struct bridge_vlan_info vinfo;
++      const u8                *vlans = port_priv->vlans;
++      u16                     i;
++      int                     err;
++
++      nest = nla_nest_start(skb, IFLA_AF_SPEC);
++      if (!nest) {
++              netdev_err(netdev, "nla_nest_start failed");
++              return -ENOMEM;
++      }
++
++      for (i = 0; i < VLAN_VID_MASK + 1; i++) {
++              if (!vlans[i])
++                      continue;
++
++              vinfo.flags = 0;
++              vinfo.vid = i;
++
++              err = nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
++                            sizeof(vinfo), &vinfo);
++              if (unlikely(err))
++                      goto nla_put_err;
++      }
++
++      nla_nest_end(skb, nest);
++
++      return 0;
++
++nla_put_err:
++      netdev_err(netdev, "nla_put_ err %d\n", err);
++      nla_nest_cancel(skb, nest);
++      return err;
++}
++
++static int evb_getlink(struct sk_buff *skb, u32 pid, u32 seq,
++                     struct net_device *netdev, u32 filter_mask, int nlflags)
++{
++      struct evb_port_priv    *port_priv = netdev_priv(netdev);
++      struct evb_priv         *evb_priv = port_priv->evb_priv;
++      struct ifinfomsg        *hdr;
++      struct nlmsghdr         *nlh;
++      int                     err;
++
++      if (evb_priv->attr.method != DPDMUX_METHOD_C_VLAN &&
++          evb_priv->attr.method != DPDMUX_METHOD_S_VLAN) {
++              return 0;
++      }
++
++      nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*hdr), NLM_F_MULTI);
++      if (!nlh)
++              return -EMSGSIZE;
++
++      hdr = nlmsg_data(nlh);
++      memset(hdr, 0, sizeof(*hdr));
++      hdr->ifi_family = AF_BRIDGE;
++      hdr->ifi_type = netdev->type;
++      hdr->ifi_index = netdev->ifindex;
++      hdr->ifi_flags = dev_get_flags(netdev);
++
++      err = __nla_put_netdev(skb, netdev);
++      if (unlikely(err))
++              goto nla_put_err;
++
++      err = __nla_put_port(skb, netdev);
++      if (unlikely(err))
++              goto nla_put_err;
++
++      /* Check if the VID information is requested */
++      if (filter_mask & RTEXT_FILTER_BRVLAN) {
++              err = __nla_put_vlan(skb, netdev);
++              if (unlikely(err))
++                      goto nla_put_err;
++      }
++
++      nlmsg_end(skb, nlh);
++      return skb->len;
++
++nla_put_err:
++      nlmsg_cancel(skb, nlh);
++      return -EMSGSIZE;
++}
++
++static int evb_dellink(struct net_device *netdev,
++                     struct nlmsghdr *nlh,
++                     u16 flags)
++{
++      struct nlattr           *tb[IFLA_BRIDGE_MAX + 1];
++      struct nlattr           *spec;
++      struct bridge_vlan_info *vinfo;
++      struct evb_port_priv    *port_priv = netdev_priv(netdev);
++      int                     err = 0;
++
++      spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
++      if (!spec)
++              return 0;
++
++      err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, spec, ifla_br_policy);
++      if (unlikely(err))
++              return err;
++
++      if (!tb[IFLA_BRIDGE_VLAN_INFO])
++              return -EOPNOTSUPP;
++
++      vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]);
++
++      if (!vinfo->vid || vinfo->vid > VLAN_VID_MASK)
++              return -EINVAL;
++
++      err = evb_port_del_rule(netdev, NULL, vinfo->vid);
++      if (unlikely(err)) {
++              netdev_err(netdev, "evb_port_del_rule err %d\n", err);
++              return err;
++      }
++      port_priv->vlans[vinfo->vid] = 0;
++
++      return 0;
++}
++
++void evb_port_get_stats(struct net_device *netdev,
++                      struct rtnl_link_stats64 *storage)
++{
++      struct evb_port_priv    *port_priv = netdev_priv(netdev);
++      u64                     tmp;
++      int                     err;
++
++      err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
++                                  0,
++                                  port_priv->evb_priv->mux_handle,
++                                  port_priv->port_index,
++                                  DPDMUX_CNT_ING_FRAME, &storage->rx_packets);
++      if (unlikely(err))
++              goto error;
++
++      err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
++                                  0,
++                                  port_priv->evb_priv->mux_handle,
++                                  port_priv->port_index,
++                                  DPDMUX_CNT_ING_BYTE, &storage->rx_bytes);
++      if (unlikely(err))
++              goto error;
++
++      err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
++                                  0,
++                                  port_priv->evb_priv->mux_handle,
++                                  port_priv->port_index,
++                                  DPDMUX_CNT_ING_FLTR_FRAME, &tmp);
++      if (unlikely(err))
++              goto error;
++
++      err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
++                                  0,
++                                  port_priv->evb_priv->mux_handle,
++                                  port_priv->port_index,
++                                  DPDMUX_CNT_ING_FRAME_DISCARD,
++                                  &storage->rx_dropped);
++      if (unlikely(err)) {
++              storage->rx_dropped = tmp;
++              goto error;
++      }
++      storage->rx_dropped += tmp;
++
++      err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
++                                  0,
++                                  port_priv->evb_priv->mux_handle,
++                                  port_priv->port_index,
++                                  DPDMUX_CNT_ING_MCAST_FRAME,
++                                  &storage->multicast);
++      if (unlikely(err))
++              goto error;
++
++      err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
++                                  0,
++                                  port_priv->evb_priv->mux_handle,
++                                  port_priv->port_index,
++                                  DPDMUX_CNT_EGR_FRAME, &storage->tx_packets);
++      if (unlikely(err))
++              goto error;
++
++      err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
++                                  0,
++                                  port_priv->evb_priv->mux_handle,
++                                  port_priv->port_index,
++                                  DPDMUX_CNT_EGR_BYTE, &storage->tx_bytes);
++      if (unlikely(err))
++              goto error;
++
++      err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
++                                  0,
++                                  port_priv->evb_priv->mux_handle,
++                                  port_priv->port_index,
++                                  DPDMUX_CNT_EGR_FRAME_DISCARD,
++                                  &storage->tx_dropped);
++      if (unlikely(err))
++              goto error;
++
++      return;
++
++error:
++      netdev_err(netdev, "dpdmux_if_get_counter err %d\n", err);
++}
++
++static const struct net_device_ops evb_port_ops = {
++      .ndo_open               = &evb_port_open,
++
++      .ndo_start_xmit         = &evb_dropframe,
++
++      .ndo_fdb_add            = &evb_port_fdb_add,
++      .ndo_fdb_del            = &evb_port_fdb_del,
++
++      .ndo_get_stats64        = &evb_port_get_stats,
++      .ndo_change_mtu         = &evb_change_mtu,
++};
++
++static struct {
++      enum dpdmux_counter_type id;
++      char name[ETH_GSTRING_LEN];
++} evb_ethtool_counters[] =  {
++      {DPDMUX_CNT_ING_FRAME,          "rx frames"},
++      {DPDMUX_CNT_ING_BYTE,           "rx bytes"},
++      {DPDMUX_CNT_ING_FLTR_FRAME,     "rx filtered frames"},
++      {DPDMUX_CNT_ING_FRAME_DISCARD,  "rx discarded frames"},
++      {DPDMUX_CNT_ING_BCAST_FRAME,    "rx b-cast frames"},
++      {DPDMUX_CNT_ING_BCAST_BYTES,    "rx b-cast bytes"},
++      {DPDMUX_CNT_ING_MCAST_FRAME,    "rx m-cast frames"},
++      {DPDMUX_CNT_ING_MCAST_BYTE,     "rx m-cast bytes"},
++      {DPDMUX_CNT_EGR_FRAME,          "tx frames"},
++      {DPDMUX_CNT_EGR_BYTE,           "tx bytes"},
++      {DPDMUX_CNT_EGR_FRAME_DISCARD,  "tx discarded frames"},
++};
++
++static int evb_ethtool_get_sset_count(struct net_device *dev, int sset)
++{
++      switch (sset) {
++      case ETH_SS_STATS:
++              return ARRAY_SIZE(evb_ethtool_counters);
++      default:
++              return -EOPNOTSUPP;
++      }
++}
++
++static void evb_ethtool_get_strings(struct net_device *netdev,
++                                  u32 stringset, u8 *data)
++{
++      int i;
++
++      switch (stringset) {
++      case ETH_SS_STATS:
++              for (i = 0; i < ARRAY_SIZE(evb_ethtool_counters); i++)
++                      memcpy(data + i * ETH_GSTRING_LEN,
++                             evb_ethtool_counters[i].name, ETH_GSTRING_LEN);
++              break;
++      }
++}
++
++static void evb_ethtool_get_stats(struct net_device *netdev,
++                                struct ethtool_stats *stats,
++                                u64 *data)
++{
++      struct evb_port_priv    *port_priv = netdev_priv(netdev);
++      int                     i;
++      int                     err;
++
++      for (i = 0; i < ARRAY_SIZE(evb_ethtool_counters); i++) {
++              err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
++                                          0,
++                                          port_priv->evb_priv->mux_handle,
++                                          port_priv->port_index,
++                                          evb_ethtool_counters[i].id,
++                                          &data[i]);
++              if (err)
++                      netdev_err(netdev, "dpdmux_if_get_counter[%s] err %d\n",
++                                 evb_ethtool_counters[i].name, err);
++      }
++}
++
++static const struct ethtool_ops evb_port_ethtool_ops = {
++      .get_strings            = &evb_ethtool_get_strings,
++      .get_ethtool_stats      = &evb_ethtool_get_stats,
++      .get_sset_count         = &evb_ethtool_get_sset_count,
++};
++
++static int evb_open(struct net_device *netdev)
++{
++      struct evb_priv *priv = netdev_priv(netdev);
++      int             err = 0;
++
++      err = dpdmux_enable(priv->mc_io, 0, priv->mux_handle);
++      if (unlikely(err))
++              netdev_err(netdev, "dpdmux_enable err %d\n", err);
++
++      return err;
++}
++
++static int evb_close(struct net_device *netdev)
++{
++      struct evb_priv *priv = netdev_priv(netdev);
++      int             err = 0;
++
++      err = dpdmux_disable(priv->mc_io, 0, priv->mux_handle);
++      if (unlikely(err))
++              netdev_err(netdev, "dpdmux_disable err %d\n", err);
++
++      return err;
++}
++
++static const struct net_device_ops evb_ops = {
++      .ndo_start_xmit         = &evb_dropframe,
++      .ndo_open               = &evb_open,
++      .ndo_stop               = &evb_close,
++
++      .ndo_bridge_setlink     = &evb_setlink,
++      .ndo_bridge_getlink     = &evb_getlink,
++      .ndo_bridge_dellink     = &evb_dellink,
++
++      .ndo_get_stats64        = &evb_port_get_stats,
++      .ndo_change_mtu         = &evb_change_mtu,
++};
++
++static int evb_takedown(struct fsl_mc_device *evb_dev)
++{
++      struct device           *dev = &evb_dev->dev;
++      struct net_device       *netdev = dev_get_drvdata(dev);
++      struct evb_priv         *priv = netdev_priv(netdev);
++      int                     err;
++
++      err = dpdmux_close(priv->mc_io, 0, priv->mux_handle);
++      if (unlikely(err))
++              dev_warn(dev, "dpdmux_close err %d\n", err);
++
++      return 0;
++}
++
++static int evb_init(struct fsl_mc_device *evb_dev)
++{
++      struct device           *dev = &evb_dev->dev;
++      struct net_device       *netdev = dev_get_drvdata(dev);
++      struct evb_priv         *priv = netdev_priv(netdev);
++      u16                     version_major;
++      u16                     version_minor;
++      int                     err = 0;
++
++      priv->dev_id = evb_dev->obj_desc.id;
++
++      err = dpdmux_open(priv->mc_io, 0, priv->dev_id, &priv->mux_handle);
++      if (unlikely(err)) {
++              dev_err(dev, "dpdmux_open err %d\n", err);
++              goto err_exit;
++      }
++      if (!priv->mux_handle) {
++              dev_err(dev, "dpdmux_open returned null handle but no error\n");
++              err = -EFAULT;
++              goto err_exit;
++      }
++
++      err = dpdmux_get_attributes(priv->mc_io, 0, priv->mux_handle,
++                                  &priv->attr);
++      if (unlikely(err)) {
++              dev_err(dev, "dpdmux_get_attributes err %d\n", err);
++              goto err_close;
++      }
++
++      err = dpdmux_get_api_version(priv->mc_io, 0,
++                                   &version_major,
++                                   &version_minor);
++      if (unlikely(err)) {
++              dev_err(dev, "dpdmux_get_api_version err %d\n", err);
++              goto err_close;
++      }
++
++      /* Minimum supported DPDMUX version check */
++      if (version_major < DPDMUX_MIN_VER_MAJOR ||
++          (version_major == DPDMUX_MIN_VER_MAJOR &&
++           version_minor < DPDMUX_MIN_VER_MINOR)) {
++              dev_err(dev, "DPDMUX version %d.%d not supported. Use %d.%d or greater.\n",
++                      version_major, version_minor,
++                      DPDMUX_MIN_VER_MAJOR, DPDMUX_MIN_VER_MAJOR);
++              err = -ENOTSUPP;
++              goto err_close;
++      }
++
++      err = dpdmux_reset(priv->mc_io, 0, priv->mux_handle);
++      if (unlikely(err)) {
++              dev_err(dev, "dpdmux_reset err %d\n", err);
++              goto err_close;
++      }
++
++      return 0;
++
++err_close:
++      dpdmux_close(priv->mc_io, 0, priv->mux_handle);
++err_exit:
++      return err;
++}
++
++static int evb_remove(struct fsl_mc_device *evb_dev)
++{
++      struct device           *dev = &evb_dev->dev;
++      struct net_device       *netdev = dev_get_drvdata(dev);
++      struct evb_priv         *priv = netdev_priv(netdev);
++      struct evb_port_priv    *port_priv;
++      struct list_head        *pos;
++
++      list_for_each(pos, &priv->port_list) {
++              port_priv = list_entry(pos, struct evb_port_priv, list);
++
++              rtnl_lock();
++              netdev_upper_dev_unlink(port_priv->netdev, netdev);
++              rtnl_unlock();
++
++              unregister_netdev(port_priv->netdev);
++              free_netdev(port_priv->netdev);
++      }
++
++      evb_teardown_irqs(evb_dev);
++
++      unregister_netdev(netdev);
++
++      evb_takedown(evb_dev);
++      fsl_mc_portal_free(priv->mc_io);
++
++      dev_set_drvdata(dev, NULL);
++      free_netdev(netdev);
++
++      return 0;
++}
++
++static int evb_probe(struct fsl_mc_device *evb_dev)
++{
++      struct device           *dev;
++      struct evb_priv         *priv = NULL;
++      struct net_device       *netdev = NULL;
++      char                    port_name[IFNAMSIZ];
++      int                     i;
++      int                     err = 0;
++
++      dev = &evb_dev->dev;
++
++      /* register switch device, it's for management only - no I/O */
++      netdev = alloc_etherdev(sizeof(*priv));
++      if (!netdev) {
++              dev_err(dev, "alloc_etherdev error\n");
++              return -ENOMEM;
++      }
++      netdev->netdev_ops = &evb_ops;
++
++      dev_set_drvdata(dev, netdev);
++
++      priv = netdev_priv(netdev);
++
++      err = fsl_mc_portal_allocate(evb_dev, 0, &priv->mc_io);
++      if (unlikely(err)) {
++              dev_err(dev, "fsl_mc_portal_allocate err %d\n", err);
++              goto err_free_netdev;
++      }
++      if (!priv->mc_io) {
++              dev_err(dev, "fsl_mc_portal_allocate returned null handle but no error\n");
++              err = -EFAULT;
++              goto err_free_netdev;
++      }
++
++      err = evb_init(evb_dev);
++      if (unlikely(err)) {
++              dev_err(dev, "evb init err %d\n", err);
++              goto err_free_cmdport;
++      }
++
++      INIT_LIST_HEAD(&priv->port_list);
++      netdev->flags |= IFF_PROMISC | IFF_MASTER;
++
++      dev_alloc_name(netdev, "evb%d");
++
++      /* register switch ports */
++      snprintf(port_name, IFNAMSIZ, "%sp%%d", netdev->name);
++
++      /* only register downlinks? */
++      for (i = 0; i < priv->attr.num_ifs + 1; i++) {
++              struct net_device *port_netdev;
++              struct evb_port_priv *port_priv;
++
++              if (i) {
++                      port_netdev =
++                              alloc_etherdev(sizeof(struct evb_port_priv));
++                      if (!port_netdev) {
++                              dev_err(dev, "alloc_etherdev error\n");
++                              goto err_takedown;
++                      }
++
++                      port_priv = netdev_priv(port_netdev);
++
++                      port_netdev->flags |= IFF_PROMISC | IFF_SLAVE;
++
++                      dev_alloc_name(port_netdev, port_name);
++              } else {
++                      port_netdev = netdev;
++                      port_priv = &priv->uplink;
++              }
++
++              port_priv->netdev = port_netdev;
++              port_priv->evb_priv = priv;
++              port_priv->port_index = i;
++
++              SET_NETDEV_DEV(port_netdev, dev);
++
++              if (i) {
++                      port_netdev->netdev_ops = &evb_port_ops;
++
++                      err = register_netdev(port_netdev);
++                      if (err < 0) {
++                              dev_err(dev, "register_netdev err %d\n", err);
++                              free_netdev(port_netdev);
++                              goto err_takedown;
++                      }
++
++                      rtnl_lock();
++                      err = netdev_master_upper_dev_link(port_netdev, netdev,
++                                                         NULL, NULL);
++                      if (unlikely(err)) {
++                              dev_err(dev, "netdev_master_upper_dev_link err %d\n",
++                                      err);
++                              unregister_netdev(port_netdev);
++                              free_netdev(port_netdev);
++                              rtnl_unlock();
++                              goto err_takedown;
++                      }
++                      rtmsg_ifinfo(RTM_NEWLINK, port_netdev,
++                                   IFF_SLAVE, GFP_KERNEL);
++                      rtnl_unlock();
++
++                      list_add(&port_priv->list, &priv->port_list);
++              } else {
++                      err = register_netdev(netdev);
++
++                      if (err < 0) {
++                              dev_err(dev, "register_netdev error %d\n", err);
++                              goto err_takedown;
++                      }
++              }
++
++              port_netdev->ethtool_ops = &evb_port_ethtool_ops;
++
++              /* ports are up from init */
++              rtnl_lock();
++              err = dev_open(port_netdev, NULL);
++              rtnl_unlock();
++              if (unlikely(err))
++                      dev_warn(dev, "dev_open err %d\n", err);
++      }
++
++      /* setup irqs */
++      err = evb_setup_irqs(evb_dev);
++      if (unlikely(err)) {
++              dev_warn(dev, "evb_setup_irqs err %d\n", err);
++              goto err_takedown;
++      }
++
++      dev_info(dev, "probed evb device with %d ports\n",
++               priv->attr.num_ifs);
++      return 0;
++
++err_takedown:
++      evb_remove(evb_dev);
++err_free_cmdport:
++      fsl_mc_portal_free(priv->mc_io);
++err_free_netdev:
++      return err;
++}
++
++static const struct fsl_mc_device_id evb_match_id_table[] = {
++      {
++              .vendor = FSL_MC_VENDOR_FREESCALE,
++              .obj_type = "dpdmux",
++      },
++      {}
++};
++
++static struct fsl_mc_driver evb_drv = {
++      .driver = {
++              .name           = KBUILD_MODNAME,
++              .owner          = THIS_MODULE,
++      },
++      .probe          = evb_probe,
++      .remove         = evb_remove,
++      .match_id_table = evb_match_id_table,
++};
++
++module_fsl_mc_driver(evb_drv);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Layerscape DPAA Edge Virtual Bridge driver (prototype)");
diff --git a/target/linux/layerscape/patches-5.4/701-net-0180-staging-dpaa2-evb-Fix-W-1-warnings.patch b/target/linux/layerscape/patches-5.4/701-net-0180-staging-dpaa2-evb-Fix-W-1-warnings.patch
new file mode 100644 (file)
index 0000000..7f1ffdb
--- /dev/null
@@ -0,0 +1,41 @@
+From 18d400e71c415adc8a5e5c91e461968907d26606 Mon Sep 17 00:00:00 2001
+From: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+Date: Thu, 6 Apr 2017 11:02:57 +0300
+Subject: [PATCH] staging: dpaa2-evb: Fix W=1 warnings
+
+Fix warnings triggered by '-Wsign-compare' flag.
+
+Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/evb/evb.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/evb/evb.c
++++ b/drivers/staging/fsl-dpaa2/evb/evb.c
+@@ -162,7 +162,7 @@ static irqreturn_t _evb_irq0_handler_thr
+       /* Sanity check */
+       if (WARN_ON(!evb_dev || !evb_dev->irqs || !evb_dev->irqs[irq_index]))
+               goto out;
+-      if (WARN_ON(evb_dev->irqs[irq_index]->msi_desc->irq != irq_num))
++      if (WARN_ON(evb_dev->irqs[irq_index]->msi_desc->irq != (u32)irq_num))
+               goto out;
+       err = dpdmux_get_irq_status(io, 0, token, irq_index, &status);
+@@ -890,7 +890,7 @@ static int evb_ethtool_get_sset_count(st
+ static void evb_ethtool_get_strings(struct net_device *netdev,
+                                   u32 stringset, u8 *data)
+ {
+-      int i;
++      u32 i;
+       switch (stringset) {
+       case ETH_SS_STATS:
+@@ -906,7 +906,7 @@ static void evb_ethtool_get_stats(struct
+                                 u64 *data)
+ {
+       struct evb_port_priv    *port_priv = netdev_priv(netdev);
+-      int                     i;
++      u32                     i;
+       int                     err;
+       for (i = 0; i < ARRAY_SIZE(evb_ethtool_counters); i++) {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0181-staging-dpaa2-evb-Improve-ethtool-support.patch b/target/linux/layerscape/patches-5.4/701-net-0181-staging-dpaa2-evb-Improve-ethtool-support.patch
new file mode 100644 (file)
index 0000000..5a566ee
--- /dev/null
@@ -0,0 +1,153 @@
+From b505f9a736c3850aa1dfefd7a803d797c2233aab Mon Sep 17 00:00:00 2001
+From: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+Date: Thu, 13 Apr 2017 13:10:34 +0300
+Subject: [PATCH] staging: dpaa2-evb: Improve ethtool support
+
+Improve ethtool support by adding ops for:
+- driver info
+- link status
+- auto-negotiation setting and result
+- speed setting and result
+
+Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/evb/evb.c | 114 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 114 insertions(+)
+
+--- a/drivers/staging/fsl-dpaa2/evb/evb.c
++++ b/drivers/staging/fsl-dpaa2/evb/evb.c
+@@ -43,6 +43,8 @@
+ #include "dpdmux.h"
+ #include "dpdmux-cmd.h"
++static const char evb_drv_version[] = "0.1";
++
+ /* Minimal supported DPDMUX version */
+ #define DPDMUX_MIN_VER_MAJOR                  6
+ #define DPDMUX_MIN_VER_MINOR                  0
+@@ -860,6 +862,114 @@ static const struct net_device_ops evb_p
+       .ndo_change_mtu         = &evb_change_mtu,
+ };
++static void evb_get_drvinfo(struct net_device *netdev,
++                          struct ethtool_drvinfo *drvinfo)
++{
++      struct evb_port_priv *port_priv = netdev_priv(netdev);
++      u16 version_major, version_minor;
++      int err;
++
++      strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
++      strlcpy(drvinfo->version, evb_drv_version, sizeof(drvinfo->version));
++
++      err = dpdmux_get_api_version(port_priv->evb_priv->mc_io, 0,
++                                   &version_major,
++                                   &version_minor);
++      if (err)
++              strlcpy(drvinfo->fw_version, "N/A",
++                      sizeof(drvinfo->fw_version));
++      else
++              snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
++                       "%u.%u", version_major, version_minor);
++
++      strlcpy(drvinfo->bus_info, dev_name(netdev->dev.parent->parent),
++              sizeof(drvinfo->bus_info));
++}
++
++static int evb_get_link_ksettings(struct net_device *netdev,
++                                struct ethtool_link_ksettings *link_settings)
++{
++      struct evb_port_priv *port_priv = netdev_priv(netdev);
++      struct dpdmux_link_state state = {0};
++      int err = 0;
++
++      err = dpdmux_if_get_link_state(port_priv->evb_priv->mc_io, 0,
++                                     port_priv->evb_priv->mux_handle,
++                                     port_priv->port_index,
++                                     &state);
++      if (err) {
++              netdev_err(netdev, "ERROR %d getting link state", err);
++              goto out;
++      }
++
++      /* At the moment, we have no way of interrogating the DPMAC
++       * from the DPDMUX side or there may not exist a DPMAC at all.
++       * Report only autoneg state, duplexity and speed.
++       */
++      if (state.options & DPDMUX_LINK_OPT_AUTONEG)
++              link_settings->base.autoneg = AUTONEG_ENABLE;
++      if (!(state.options & DPDMUX_LINK_OPT_HALF_DUPLEX))
++              link_settings->base.duplex = DUPLEX_FULL;
++      link_settings->base.speed = state.rate;
++
++out:
++      return err;
++}
++
++static int evb_set_link_ksettings(struct net_device *netdev,
++                                const struct ethtool_link_ksettings *link_settings)
++{
++      struct evb_port_priv *port_priv = netdev_priv(netdev);
++      struct dpdmux_link_state state = {0};
++      struct dpdmux_link_cfg cfg = {0};
++      int err = 0;
++
++      netdev_dbg(netdev, "Setting link parameters...");
++
++      err = dpdmux_if_get_link_state(port_priv->evb_priv->mc_io, 0,
++                                     port_priv->evb_priv->mux_handle,
++                                     port_priv->port_index,
++                                     &state);
++      if (err) {
++              netdev_err(netdev, "ERROR %d getting link state", err);
++              goto out;
++      }
++
++      /* Due to a temporary MC limitation, the DPDMUX port must be down
++       * in order to be able to change link settings. Taking steps to let
++       * the user know that.
++       */
++      if (netif_running(netdev)) {
++              netdev_info(netdev,
++                          "Sorry, interface must be brought down first.\n");
++              return -EACCES;
++      }
++
++      cfg.options = state.options;
++      cfg.rate = link_settings->base.speed;
++      if (link_settings->base.autoneg == AUTONEG_ENABLE)
++              cfg.options |= DPDMUX_LINK_OPT_AUTONEG;
++      else
++              cfg.options &= ~DPDMUX_LINK_OPT_AUTONEG;
++      if (link_settings->base.duplex == DUPLEX_HALF)
++              cfg.options |= DPDMUX_LINK_OPT_HALF_DUPLEX;
++      else
++              cfg.options &= ~DPDMUX_LINK_OPT_HALF_DUPLEX;
++
++      err = dpdmux_if_set_link_cfg(port_priv->evb_priv->mc_io, 0,
++                                   port_priv->evb_priv->mux_handle,
++                                   port_priv->port_index,
++                                   &cfg);
++      if (err)
++              /* ethtool will be loud enough if we return an error; no point
++               * in putting our own error message on the console by default
++               */
++              netdev_dbg(netdev, "ERROR %d setting link cfg", err);
++
++out:
++      return err;
++}
++
+ static struct {
+       enum dpdmux_counter_type id;
+       char name[ETH_GSTRING_LEN];
+@@ -923,6 +1033,10 @@ static void evb_ethtool_get_stats(struct
+ }
+ static const struct ethtool_ops evb_port_ethtool_ops = {
++      .get_drvinfo            = &evb_get_drvinfo,
++      .get_link               = &ethtool_op_get_link,
++      .get_link_ksettings     = &evb_get_link_ksettings,
++      .set_link_ksettings     = &evb_set_link_ksettings,
+       .get_strings            = &evb_ethtool_get_strings,
+       .get_ethtool_stats      = &evb_ethtool_get_stats,
+       .get_sset_count         = &evb_ethtool_get_sset_count,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0182-staging-dpaa2-evb-Update-MTU-update-procedure.patch b/target/linux/layerscape/patches-5.4/701-net-0182-staging-dpaa2-evb-Update-MTU-update-procedure.patch
new file mode 100644 (file)
index 0000000..a3c87ea
--- /dev/null
@@ -0,0 +1,57 @@
+From e9c0434a55a0ddf28b1e7868890eb7557b2c28f9 Mon Sep 17 00:00:00 2001
+From: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+Date: Thu, 17 Aug 2017 19:47:22 +0300
+Subject: [PATCH] staging: dpaa2-evb: Update MTU update procedure
+
+Set limits on the MTU to accommodate netdevice update. There is no need to
+check the limits before setting the new value.
+
+Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/evb/evb.c | 18 ++++++++----------
+ 1 file changed, 8 insertions(+), 10 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/evb/evb.c
++++ b/drivers/staging/fsl-dpaa2/evb/evb.c
+@@ -53,9 +53,9 @@ static const char evb_drv_version[] = "0
+ #define DPDMUX_MAX_IRQ_NUM                    2
+ /* MAX FRAME LENGTH (currently 10k) */
+-#define EVB_MAX_FRAME_LENGTH                  (10 * 1024)
+-/* MIN FRAME LENGTH (64 bytes + 4 bytes CRC) */
+-#define EVB_MIN_FRAME_LENGTH                  68
++#define EVB_MAX_FRAME_LENGTH          (10 * 1024)
++#define EVB_MAX_MTU                   (EVB_MAX_FRAME_LENGTH - VLAN_ETH_HLEN)
++#define EVB_MIN_MTU                   68
+ struct evb_port_priv {
+       struct net_device       *netdev;
+@@ -457,16 +457,10 @@ static int evb_change_mtu(struct net_dev
+       if (port_priv->port_index > 0)
+               return -EPERM;
+-      if (mtu < EVB_MIN_FRAME_LENGTH || mtu > EVB_MAX_FRAME_LENGTH) {
+-              netdev_err(netdev, "Invalid MTU %d. Valid range is: %d..%d\n",
+-                         mtu, EVB_MIN_FRAME_LENGTH, EVB_MAX_FRAME_LENGTH);
+-              return -EINVAL;
+-      }
+-
+       err = dpdmux_set_max_frame_length(evb_priv->mc_io,
+                                         0,
+                                         evb_priv->mux_handle,
+-                                        (uint16_t)mtu);
++                                        (uint16_t)(mtu + VLAN_ETH_HLEN));
+       if (unlikely(err)) {
+               netdev_err(netdev, "dpdmux_ul_set_max_frame_length err %d\n",
+@@ -1291,6 +1285,10 @@ static int evb_probe(struct fsl_mc_devic
+                       list_add(&port_priv->list, &priv->port_list);
+               } else {
++                      /* Set MTU limits only on uplink */
++                      port_netdev->min_mtu = EVB_MIN_MTU;
++                      port_netdev->max_mtu = EVB_MAX_MTU;
++
+                       err = register_netdev(netdev);
+                       if (err < 0) {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0183-staging-dpaa2-evb-Update-netlink-parsing-parameters.patch b/target/linux/layerscape/patches-5.4/701-net-0183-staging-dpaa2-evb-Update-netlink-parsing-parameters.patch
new file mode 100644 (file)
index 0000000..fd647cd
--- /dev/null
@@ -0,0 +1,32 @@
+From 49c58cd6735d5f8f6683543ea66bb348aaa91321 Mon Sep 17 00:00:00 2001
+From: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+Date: Fri, 18 Aug 2017 12:34:24 +0300
+Subject: [PATCH] staging: dpaa2-evb: Update netlink parsing parameters
+
+Accommodate extended ACL reporting addded to netlink parsing functions.
+
+Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/evb/evb.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/evb/evb.c
++++ b/drivers/staging/fsl-dpaa2/evb/evb.c
+@@ -533,7 +533,7 @@ static int evb_setlink(struct net_device
+       attr = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
+       if (attr) {
+               err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, attr,
+-                                     ifla_br_policy);
++                                     ifla_br_policy, NULL);
+               if (unlikely(err)) {
+                       netdev_err(netdev,
+                                  "nla_parse_nested for br_policy err %d\n",
+@@ -739,7 +739,7 @@ static int evb_dellink(struct net_device
+       if (!spec)
+               return 0;
+-      err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, spec, ifla_br_policy);
++      err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, spec, ifla_br_policy, NULL);
+       if (unlikely(err))
+               return err;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0184-staging-dpaa2-evb-Update-netdev_master_upper_dev_lin.patch b/target/linux/layerscape/patches-5.4/701-net-0184-staging-dpaa2-evb-Update-netdev_master_upper_dev_lin.patch
new file mode 100644 (file)
index 0000000..bfc6759
--- /dev/null
@@ -0,0 +1,22 @@
+From e8fcf855b73cd52ff51d3b99d0bf8afdf6267c2f Mon Sep 17 00:00:00 2001
+From: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+Date: Fri, 20 Oct 2017 16:14:38 +0300
+Subject: [PATCH] staging: dpaa2-evb: Update netdev_master_upper_dev_link
+ parameters
+
+Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/evb/evb.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl-dpaa2/evb/evb.c
++++ b/drivers/staging/fsl-dpaa2/evb/evb.c
+@@ -1270,7 +1270,7 @@ static int evb_probe(struct fsl_mc_devic
+                       rtnl_lock();
+                       err = netdev_master_upper_dev_link(port_netdev, netdev,
+-                                                         NULL, NULL);
++                                                         NULL, NULL, NULL);
+                       if (unlikely(err)) {
+                               dev_err(dev, "netdev_master_upper_dev_link err %d\n",
+                                       err);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0185-staging-dpaa2-evb-Use-MC-portal-in-atomic-context.patch b/target/linux/layerscape/patches-5.4/701-net-0185-staging-dpaa2-evb-Use-MC-portal-in-atomic-context.patch
new file mode 100644 (file)
index 0000000..dae6a0b
--- /dev/null
@@ -0,0 +1,25 @@
+From 918a96ed5ff4cbb499242279e3c76ab7bee43c88 Mon Sep 17 00:00:00 2001
+From: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+Date: Tue, 3 Apr 2018 13:53:00 +0300
+Subject: [PATCH] staging: dpaa2-evb: Use MC portal in atomic context
+
+Avoid triggering stack trace when retrieving interface counters via
+ifconfig by allocating MC portal with atomic I/O enabled.
+
+Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/evb/evb.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl-dpaa2/evb/evb.c
++++ b/drivers/staging/fsl-dpaa2/evb/evb.c
+@@ -1204,7 +1204,8 @@ static int evb_probe(struct fsl_mc_devic
+       priv = netdev_priv(netdev);
+-      err = fsl_mc_portal_allocate(evb_dev, 0, &priv->mc_io);
++      err = fsl_mc_portal_allocate(evb_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
++                                   &priv->mc_io);
+       if (unlikely(err)) {
+               dev_err(dev, "fsl_mc_portal_allocate err %d\n", err);
+               goto err_free_netdev;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0186-staging-dpaa2-evb-change-mc_command-in-fsl_mc_comman.patch b/target/linux/layerscape/patches-5.4/701-net-0186-staging-dpaa2-evb-change-mc_command-in-fsl_mc_comman.patch
new file mode 100644 (file)
index 0000000..a6e080d
--- /dev/null
@@ -0,0 +1,284 @@
+From 92ee95e52191107f8c8adea810232920358ae0e0 Mon Sep 17 00:00:00 2001
+From: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+Date: Thu, 12 Apr 2018 15:19:10 +0300
+Subject: [PATCH] staging: dpaa2-evb: change mc_command in fsl_mc_command
+
+Adapt to the upstream changes.
+
+Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/evb/dpdmux.c | 60 +++++++++++++++++-----------------
+ 1 file changed, 30 insertions(+), 30 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/evb/dpdmux.c
++++ b/drivers/staging/fsl-dpaa2/evb/dpdmux.c
+@@ -55,7 +55,7 @@ int dpdmux_open(struct fsl_mc_io *mc_io,
+               int dpdmux_id,
+               u16 *token)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_open *cmd_params;
+       int err;
+@@ -92,7 +92,7 @@ int dpdmux_close(struct fsl_mc_io *mc_io
+                u32 cmd_flags,
+                u16 token)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CLOSE,
+@@ -131,7 +131,7 @@ int dpdmux_create(struct fsl_mc_io *mc_i
+                 const struct dpdmux_cfg *cfg,
+                 u32 *obj_id)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_create *cmd_params;
+       int err;
+@@ -180,7 +180,7 @@ int dpdmux_destroy(struct fsl_mc_io *mc_
+                  u32 cmd_flags,
+                  u32 object_id)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_destroy *cmd_params;
+       /* prepare command */
+@@ -206,7 +206,7 @@ int dpdmux_enable(struct fsl_mc_io *mc_i
+                 u32 cmd_flags,
+                 u16 token)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_ENABLE,
+@@ -229,7 +229,7 @@ int dpdmux_disable(struct fsl_mc_io *mc_
+                  u32 cmd_flags,
+                  u16 token)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_DISABLE,
+@@ -254,7 +254,7 @@ int dpdmux_is_enabled(struct fsl_mc_io *
+                     u16 token,
+                     int *en)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_rsp_is_enabled *rsp_params;
+       int err;
+@@ -287,7 +287,7 @@ int dpdmux_reset(struct fsl_mc_io *mc_io
+                u32 cmd_flags,
+                u16 token)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_RESET,
+@@ -319,7 +319,7 @@ int dpdmux_set_irq_enable(struct fsl_mc_
+                         u8 irq_index,
+                         u8 en)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_set_irq_enable *cmd_params;
+       /* prepare command */
+@@ -350,7 +350,7 @@ int dpdmux_get_irq_enable(struct fsl_mc_
+                         u8 irq_index,
+                         u8 *en)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_get_irq_enable *cmd_params;
+       struct dpdmux_rsp_get_irq_enable *rsp_params;
+       int err;
+@@ -396,7 +396,7 @@ int dpdmux_set_irq_mask(struct fsl_mc_io
+                       u8 irq_index,
+                       u32 mask)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_set_irq_mask *cmd_params;
+       /* prepare command */
+@@ -430,7 +430,7 @@ int dpdmux_get_irq_mask(struct fsl_mc_io
+                       u8 irq_index,
+                       u32 *mask)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_get_irq_mask *cmd_params;
+       struct dpdmux_rsp_get_irq_mask *rsp_params;
+       int err;
+@@ -472,7 +472,7 @@ int dpdmux_get_irq_status(struct fsl_mc_
+                         u8 irq_index,
+                         u32 *status)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_get_irq_status *cmd_params;
+       struct dpdmux_rsp_get_irq_status *rsp_params;
+       int err;
+@@ -515,7 +515,7 @@ int dpdmux_clear_irq_status(struct fsl_m
+                           u8 irq_index,
+                           u32 status)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_clear_irq_status *cmd_params;
+       /* prepare command */
+@@ -544,7 +544,7 @@ int dpdmux_get_attributes(struct fsl_mc_
+                         u16 token,
+                         struct dpdmux_attr *attr)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_rsp_get_attr *rsp_params;
+       int err;
+@@ -585,7 +585,7 @@ int dpdmux_if_enable(struct fsl_mc_io *m
+                    u16 if_id)
+ {
+       struct dpdmux_cmd_if *cmd_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_ENABLE,
+@@ -613,7 +613,7 @@ int dpdmux_if_disable(struct fsl_mc_io *
+                     u16 if_id)
+ {
+       struct dpdmux_cmd_if *cmd_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_DISABLE,
+@@ -645,7 +645,7 @@ int dpdmux_set_max_frame_length(struct f
+                               u16 token,
+                               u16 max_frame_length)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_set_max_frame_length *cmd_params;
+       /* prepare command */
+@@ -671,7 +671,7 @@ int dpdmux_ul_reset_counters(struct fsl_
+                            u32 cmd_flags,
+                            u16 token)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_UL_RESET_COUNTERS,
+@@ -705,7 +705,7 @@ int dpdmux_if_set_accepted_frames(struct
+                                 u16 if_id,
+                                 const struct dpdmux_accepted_frames *cfg)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_if_set_accepted_frames *cmd_params;
+       /* prepare command */
+@@ -739,7 +739,7 @@ int dpdmux_if_get_attributes(struct fsl_
+                            u16 if_id,
+                            struct dpdmux_if_attr *attr)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_if *cmd_params;
+       struct dpdmux_rsp_if_get_attr *rsp_params;
+       int err;
+@@ -786,7 +786,7 @@ int dpdmux_if_remove_l2_rule(struct fsl_
+                            u16 if_id,
+                            const struct dpdmux_l2_rule *rule)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_if_l2_rule *cmd_params;
+       /* prepare command */
+@@ -826,7 +826,7 @@ int dpdmux_if_add_l2_rule(struct fsl_mc_
+                         u16 if_id,
+                         const struct dpdmux_l2_rule *rule)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_if_l2_rule *cmd_params;
+       /* prepare command */
+@@ -865,7 +865,7 @@ int dpdmux_if_get_counter(struct fsl_mc_
+                         enum dpdmux_counter_type counter_type,
+                         u64 *counter)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_if_get_counter *cmd_params;
+       struct dpdmux_rsp_if_get_counter *rsp_params;
+       int err;
+@@ -906,7 +906,7 @@ int dpdmux_if_set_link_cfg(struct fsl_mc
+                          u16 if_id,
+                          struct dpdmux_link_cfg *cfg)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_if_set_link_cfg *cmd_params;
+       /* prepare command */
+@@ -938,7 +938,7 @@ int dpdmux_if_get_link_state(struct fsl_
+                            u16 if_id,
+                            struct dpdmux_link_state *state)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_cmd_if_get_link_state *cmd_params;
+       struct dpdmux_rsp_if_get_link_state *rsp_params;
+       int err;
+@@ -989,7 +989,7 @@ int dpdmux_set_custom_key(struct fsl_mc_
+                         u64 key_cfg_iova)
+ {
+       struct dpdmux_set_custom_key *cmd_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_CUSTOM_KEY,
+@@ -1025,7 +1025,7 @@ int dpdmux_add_custom_cls_entry(struct f
+                               struct dpdmux_cls_action *action)
+ {
+       struct dpdmux_cmd_add_custom_cls_entry *cmd_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_ADD_CUSTOM_CLS_ENTRY,
+@@ -1062,7 +1062,7 @@ int dpdmux_remove_custom_cls_entry(struc
+                                  struct dpdmux_rule_cfg *rule)
+ {
+       struct dpdmux_cmd_remove_custom_cls_entry *cmd_params;
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_REMOVE_CUSTOM_CLS_ENTRY,
+@@ -1091,7 +1091,7 @@ int dpdmux_get_api_version(struct fsl_mc
+                          u16 *major_ver,
+                          u16 *minor_ver)
+ {
+-      struct mc_command cmd = { 0 };
++      struct fsl_mc_command cmd = { 0 };
+       struct dpdmux_rsp_get_api_version *rsp_params;
+       int err;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0187-staging-dpaa2-evb-Fix-MC-bus-include.patch b/target/linux/layerscape/patches-5.4/701-net-0187-staging-dpaa2-evb-Fix-MC-bus-include.patch
new file mode 100644 (file)
index 0000000..f5cb38e
--- /dev/null
@@ -0,0 +1,35 @@
+From 64be51568219eb436b46d7f6d0c85fd81bce4fde Mon Sep 17 00:00:00 2001
+From: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+Date: Thu, 12 Apr 2018 15:55:30 +0300
+Subject: [PATCH] staging: dpaa2-evb: Fix MC bus include
+
+Adapt to upstream changes.
+
+Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/evb/dpdmux.c | 2 +-
+ drivers/staging/fsl-dpaa2/evb/evb.c    | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/evb/dpdmux.c
++++ b/drivers/staging/fsl-dpaa2/evb/dpdmux.c
+@@ -29,7 +29,7 @@
+  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  * POSSIBILITY OF SUCH DAMAGE.
+  */
+-#include "../../fsl-mc/include/mc.h"
++#include <linux/fsl/mc.h>
+ #include "dpdmux.h"
+ #include "dpdmux-cmd.h"
+--- a/drivers/staging/fsl-dpaa2/evb/evb.c
++++ b/drivers/staging/fsl-dpaa2/evb/evb.c
+@@ -38,7 +38,7 @@
+ #include <uapi/linux/if_bridge.h>
+ #include <net/netlink.h>
+-#include "../../fsl-mc/include/mc.h"
++#include <linux/fsl/mc.h>
+ #include "dpdmux.h"
+ #include "dpdmux-cmd.h"
diff --git a/target/linux/layerscape/patches-5.4/701-net-0188-staging-dpaa2-evb-Defer-probe-if-no-mc-portal-is-fou.patch b/target/linux/layerscape/patches-5.4/701-net-0188-staging-dpaa2-evb-Defer-probe-if-no-mc-portal-is-fou.patch
new file mode 100644 (file)
index 0000000..d95ecf8
--- /dev/null
@@ -0,0 +1,29 @@
+From ac03137b2283c45ad0538188728d9691fa7a4883 Mon Sep 17 00:00:00 2001
+From: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+Date: Mon, 30 Apr 2018 11:27:27 +0300
+Subject: [PATCH] staging: dpaa2-evb: Defer probe if no mc portal is found
+
+Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/evb/evb.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/evb/evb.c
++++ b/drivers/staging/fsl-dpaa2/evb/evb.c
+@@ -1206,10 +1206,14 @@ static int evb_probe(struct fsl_mc_devic
+       err = fsl_mc_portal_allocate(evb_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
+                                    &priv->mc_io);
+-      if (unlikely(err)) {
+-              dev_err(dev, "fsl_mc_portal_allocate err %d\n", err);
++      if (err) {
++              if (err == -ENXIO)
++                      err = -EPROBE_DEFER;
++              else
++                      dev_err(dev, "fsl_mc_portal_allocate err %d\n", err);
+               goto err_free_netdev;
+       }
++
+       if (!priv->mc_io) {
+               dev_err(dev, "fsl_mc_portal_allocate returned null handle but no error\n");
+               err = -EFAULT;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0189-staging-dpaa2-evb-Update-netlink-attributes-API.patch b/target/linux/layerscape/patches-5.4/701-net-0189-staging-dpaa2-evb-Update-netlink-attributes-API.patch
new file mode 100644 (file)
index 0000000..5db172e
--- /dev/null
@@ -0,0 +1,53 @@
+From 50a9c893a750c4eef7fbf60f5b6eb4833e35a943 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Wed, 24 Jul 2019 21:43:49 +0300
+Subject: [PATCH] staging: dpaa2-evb: Update netlink attributes API
+
+Account for upstream changes in some nla functions.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/evb/evb.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/evb/evb.c
++++ b/drivers/staging/fsl-dpaa2/evb/evb.c
+@@ -532,8 +532,8 @@ static int evb_setlink(struct net_device
+       attr = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
+       if (attr) {
+-              err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, attr,
+-                                     ifla_br_policy, NULL);
++              err = nla_parse_nested_deprecated(tb, IFLA_BRIDGE_MAX, attr,
++                                                ifla_br_policy, NULL);
+               if (unlikely(err)) {
+                       netdev_err(netdev,
+                                  "nla_parse_nested for br_policy err %d\n",
+@@ -596,7 +596,7 @@ static int __nla_put_port(struct sk_buff
+       struct nlattr   *nest;
+       int             err;
+-      nest = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED);
++      nest = nla_nest_start_noflag(skb, IFLA_PROTINFO | NLA_F_NESTED);
+       if (!nest) {
+               netdev_err(netdev, "nla_nest_start failed\n");
+               return -ENOMEM;
+@@ -648,7 +648,7 @@ static int __nla_put_vlan(struct sk_buff
+       u16                     i;
+       int                     err;
+-      nest = nla_nest_start(skb, IFLA_AF_SPEC);
++      nest = nla_nest_start_noflag(skb, IFLA_AF_SPEC);
+       if (!nest) {
+               netdev_err(netdev, "nla_nest_start failed");
+               return -ENOMEM;
+@@ -739,7 +739,8 @@ static int evb_dellink(struct net_device
+       if (!spec)
+               return 0;
+-      err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, spec, ifla_br_policy, NULL);
++      err = nla_parse_nested_deprecated(tb, IFLA_BRIDGE_MAX, spec,
++                                        ifla_br_policy, NULL);
+       if (unlikely(err))
+               return err;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0190-dpaa2-eth-Cleanup-dead-code.patch b/target/linux/layerscape/patches-5.4/701-net-0190-dpaa2-eth-Cleanup-dead-code.patch
new file mode 100644 (file)
index 0000000..18dc4e1
--- /dev/null
@@ -0,0 +1,35 @@
+From f56f2b85c6a670c74f28daad249920d4ee4161a9 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Tue, 3 Sep 2019 21:20:07 +0300
+Subject: [PATCH] dpaa2-eth: Cleanup dead code
+
+Remove one function call whose result was not used anywhere.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -2046,7 +2046,6 @@ static struct fsl_mc_device *setup_dpcon
+ {
+       struct fsl_mc_device *dpcon;
+       struct device *dev = priv->net_dev->dev.parent;
+-      struct dpcon_attr attrs;
+       int err;
+       err = fsl_mc_object_allocate(to_fsl_mc_device(dev),
+@@ -2071,12 +2070,6 @@ static struct fsl_mc_device *setup_dpcon
+               goto close;
+       }
+-      err = dpcon_get_attributes(priv->mc_io, 0, dpcon->mc_handle, &attrs);
+-      if (err) {
+-              dev_err(dev, "dpcon_get_attributes() failed\n");
+-              goto close;
+-      }
+-
+       err = dpcon_enable(priv->mc_io, 0, dpcon->mc_handle);
+       if (err) {
+               dev_err(dev, "dpcon_enable() failed\n");
diff --git a/target/linux/layerscape/patches-5.4/701-net-0191-dpaa2-eth-Avoid-unbounded-while-loops.patch b/target/linux/layerscape/patches-5.4/701-net-0191-dpaa2-eth-Avoid-unbounded-while-loops.patch
new file mode 100644 (file)
index 0000000..72b41a4
--- /dev/null
@@ -0,0 +1,160 @@
+From 3420c5bf9d08df074b67c7feda8a37d951d0b232 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Wed, 18 Sep 2019 13:31:07 +0300
+Subject: [PATCH] dpaa2-eth: Avoid unbounded while loops
+
+Throughout the driver there are several places where we wait
+indefinitely for DPIO portal commands to be executed, while
+the portal returns a busy response code.
+
+Even though in theory we are guaranteed the portals become
+available eventually, in practice the QBMan hardware module
+may become unresponsive in various corner cases.
+
+Make sure we can never get stuck in an infinite while loop
+by adding a retry counter for all portal commands.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 30 ++++++++++++++++++++----
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h |  8 +++++++
+ 2 files changed, 33 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -221,6 +221,7 @@ static void xdp_release_buf(struct dpaa2
+                           struct dpaa2_eth_channel *ch,
+                           dma_addr_t addr)
+ {
++      int retries = 0;
+       int err;
+       ch->xdp.drop_bufs[ch->xdp.drop_cnt++] = addr;
+@@ -229,8 +230,11 @@ static void xdp_release_buf(struct dpaa2
+       while ((err = dpaa2_io_service_release(ch->dpio, priv->bpid,
+                                              ch->xdp.drop_bufs,
+-                                             ch->xdp.drop_cnt)) == -EBUSY)
++                                             ch->xdp.drop_cnt)) == -EBUSY) {
++              if (retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES)
++                      break;
+               cpu_relax();
++      }
+       if (err) {
+               free_bufs(priv, ch->xdp.drop_bufs, ch->xdp.drop_cnt);
+@@ -458,7 +462,7 @@ static int consume_frames(struct dpaa2_e
+       struct dpaa2_eth_fq *fq = NULL;
+       struct dpaa2_dq *dq;
+       const struct dpaa2_fd *fd;
+-      int cleaned = 0;
++      int cleaned = 0, retries = 0;
+       int is_last;
+       do {
+@@ -469,6 +473,11 @@ static int consume_frames(struct dpaa2_e
+                        * the store until we get some sort of valid response
+                        * token (either a valid frame or an "empty dequeue")
+                        */
++                      if (retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES) {
++                              netdev_err_once(priv->net_dev,
++                                              "Unable to read a valid dequeue response\n");
++                              return 0;
++                      }
+                       continue;
+               }
+@@ -477,6 +486,7 @@ static int consume_frames(struct dpaa2_e
+               fq->consume(priv, ch, fd, fq);
+               cleaned++;
++              retries = 0;
+       } while (!is_last);
+       if (!cleaned)
+@@ -949,6 +959,7 @@ static int add_bufs(struct dpaa2_eth_pri
+       u64 buf_array[DPAA2_ETH_BUFS_PER_CMD];
+       struct page *page;
+       dma_addr_t addr;
++      int retries = 0;
+       int i, err;
+       for (i = 0; i < DPAA2_ETH_BUFS_PER_CMD; i++) {
+@@ -980,8 +991,11 @@ static int add_bufs(struct dpaa2_eth_pri
+ release_bufs:
+       /* In case the portal is busy, retry until successful */
+       while ((err = dpaa2_io_service_release(ch->dpio, bpid,
+-                                             buf_array, i)) == -EBUSY)
++                                             buf_array, i)) == -EBUSY) {
++              if (retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES)
++                      break;
+               cpu_relax();
++      }
+       /* If release command failed, clean up and bail out;
+        * not much else we can do about it
+@@ -1032,16 +1046,21 @@ static int seed_pool(struct dpaa2_eth_pr
+ static void drain_bufs(struct dpaa2_eth_priv *priv, int count)
+ {
+       u64 buf_array[DPAA2_ETH_BUFS_PER_CMD];
++      int retries = 0;
+       int ret;
+       do {
+               ret = dpaa2_io_service_acquire(NULL, priv->bpid,
+                                              buf_array, count);
+               if (ret < 0) {
++                      if (ret == -EBUSY &&
++                          retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES)
++                              continue;
+                       netdev_err(priv->net_dev, "dpaa2_io_service_acquire() failed\n");
+                       return;
+               }
+               free_bufs(priv, buf_array, ret);
++              retries = 0;
+       } while (ret);
+ }
+@@ -1094,7 +1113,7 @@ static int pull_channel(struct dpaa2_eth
+                                                   ch->store);
+               dequeues++;
+               cpu_relax();
+-      } while (err == -EBUSY);
++      } while (err == -EBUSY && dequeues < DPAA2_ETH_SWP_BUSY_RETRIES);
+       ch->stats.dequeue_portal_busy += dequeues;
+       if (unlikely(err))
+@@ -1118,6 +1137,7 @@ static int dpaa2_eth_poll(struct napi_st
+       struct netdev_queue *nq;
+       int store_cleaned, work_done;
+       struct list_head rx_list;
++      int retries = 0;
+       int err;
+       ch = container_of(napi, struct dpaa2_eth_channel, napi);
+@@ -1163,7 +1183,7 @@ static int dpaa2_eth_poll(struct napi_st
+       do {
+               err = dpaa2_io_service_rearm(ch->dpio, &ch->nctx);
+               cpu_relax();
+-      } while (err == -EBUSY);
++      } while (err == -EBUSY && retries++ < DPAA2_ETH_SWP_BUSY_RETRIES);
+       WARN_ONCE(err, "CDAN notifications rearm failed on core %d",
+                 ch->nctx.desired_cpu);
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -245,6 +245,14 @@ static inline struct dpaa2_faead *dpaa2_
+  */
+ #define DPAA2_ETH_ENQUEUE_RETRIES     10
++/* Number of times to retry DPIO portal operations while waiting
++ * for portal to finish executing current command and become
++ * available. We want to avoid being stuck in a while loop in case
++ * hardware becomes unresponsive, but not give up too easily if
++ * the portal really is busy for valid reasons
++ */
++#define DPAA2_ETH_SWP_BUSY_RETRIES    1000
++
+ /* Driver statistics, other than those in struct rtnl_link_stats64.
+  * These are usually collected per-CPU and aggregated by ethtool.
+  */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0192-dpaa2-eth-Add-support-for-Rx-traffic-classes.patch b/target/linux/layerscape/patches-5.4/701-net-0192-dpaa2-eth-Add-support-for-Rx-traffic-classes.patch
new file mode 100644 (file)
index 0000000..43e9b5a
--- /dev/null
@@ -0,0 +1,263 @@
+From 936ce2452068cb0f6d48ca7d77d6b975802c19ae Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Tue, 3 Sep 2019 14:13:32 +0300
+Subject: [PATCH] dpaa2-eth: Add support for Rx traffic classes
+
+The firmware reserves for each DPNI a number of RX frame queues
+equal to the number of configured flows x number of configured
+traffic classes.
+
+Current driver configuration directs all incoming traffic to
+FQs corresponding to TC0, leaving all other priority levels unused.
+
+Start adding support for multiple ingress traffic classes, by
+configuring the FQs associated with all priority levels, not just
+TC0. All settings that are per-TC, such as those related to
+hashing and flow steering, are also updated.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ .../ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c   |  7 ++-
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c   | 70 +++++++++++++++-------
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h   |  4 +-
+ .../net/ethernet/freescale/dpaa2/dpaa2-ethtool.c   | 19 ++++--
+ 4 files changed, 68 insertions(+), 32 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c
+@@ -81,8 +81,8 @@ static int dpaa2_dbg_fqs_show(struct seq
+       int i, err;
+       seq_printf(file, "FQ stats for %s:\n", priv->net_dev->name);
+-      seq_printf(file, "%s%16s%16s%16s%16s\n",
+-                 "VFQID", "CPU", "Type", "Frames", "Pending frames");
++      seq_printf(file, "%s%16s%16s%16s%16s%16s\n",
++                 "VFQID", "CPU", "TC", "Type", "Frames", "Pending frames");
+       for (i = 0; i <  priv->num_fqs; i++) {
+               fq = &priv->fq[i];
+@@ -90,9 +90,10 @@ static int dpaa2_dbg_fqs_show(struct seq
+               if (err)
+                       fcnt = 0;
+-              seq_printf(file, "%5d%16d%16s%16llu%16u\n",
++              seq_printf(file, "%5d%16d%16d%16s%16llu%16u\n",
+                          fq->fqid,
+                          fq->target_cpu,
++                         fq->tc,
+                          fq_type_to_str(fq),
+                          fq->stats.frames,
+                          fcnt);
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -1231,6 +1231,7 @@ static void disable_ch_napi(struct dpaa2
+ static void dpaa2_eth_set_rx_taildrop(struct dpaa2_eth_priv *priv, bool enable)
+ {
+       struct dpni_taildrop td = {0};
++      struct dpaa2_eth_fq *fq;
+       int i, err;
+       if (priv->rx_td_enabled == enable)
+@@ -1240,11 +1241,12 @@ static void dpaa2_eth_set_rx_taildrop(st
+       td.threshold = DPAA2_ETH_TAILDROP_THRESH;
+       for (i = 0; i < priv->num_fqs; i++) {
+-              if (priv->fq[i].type != DPAA2_RX_FQ)
++              fq = &priv->fq[i];
++              if (fq->type != DPAA2_RX_FQ)
+                       continue;
+               err = dpni_set_taildrop(priv->mc_io, 0, priv->mc_token,
+-                                      DPNI_CP_QUEUE, DPNI_QUEUE_RX, 0,
+-                                      priv->fq[i].flowid, &td);
++                                      DPNI_CP_QUEUE, DPNI_QUEUE_RX,
++                                      fq->tc, fq->flowid, &td);
+               if (err) {
+                       netdev_err(priv->net_dev,
+                                  "dpni_set_taildrop() failed\n");
+@@ -2338,7 +2340,7 @@ static void set_fq_affinity(struct dpaa2
+ static void setup_fqs(struct dpaa2_eth_priv *priv)
+ {
+-      int i;
++      int i, j;
+       /* We have one TxConf FQ per Tx flow.
+        * The number of Tx and Rx queues is the same.
+@@ -2350,10 +2352,13 @@ static void setup_fqs(struct dpaa2_eth_p
+               priv->fq[priv->num_fqs++].flowid = (u16)i;
+       }
+-      for (i = 0; i < dpaa2_eth_queue_count(priv); i++) {
+-              priv->fq[priv->num_fqs].type = DPAA2_RX_FQ;
+-              priv->fq[priv->num_fqs].consume = dpaa2_eth_rx;
+-              priv->fq[priv->num_fqs++].flowid = (u16)i;
++      for (j = 0; j < dpaa2_eth_tc_count(priv); j++) {
++              for (i = 0; i < dpaa2_eth_queue_count(priv); i++) {
++                      priv->fq[priv->num_fqs].type = DPAA2_RX_FQ;
++                      priv->fq[priv->num_fqs].consume = dpaa2_eth_rx;
++                      priv->fq[priv->num_fqs].tc = (u8)j;
++                      priv->fq[priv->num_fqs++].flowid = (u16)i;
++              }
+       }
+       /* For each FQ, decide on which core to process incoming frames */
+@@ -2694,7 +2699,7 @@ static int setup_rx_flow(struct dpaa2_et
+       int err;
+       err = dpni_get_queue(priv->mc_io, 0, priv->mc_token,
+-                           DPNI_QUEUE_RX, 0, fq->flowid, &queue, &qid);
++                           DPNI_QUEUE_RX, fq->tc, fq->flowid, &queue, &qid);
+       if (err) {
+               dev_err(dev, "dpni_get_queue(RX) failed\n");
+               return err;
+@@ -2707,7 +2712,7 @@ static int setup_rx_flow(struct dpaa2_et
+       queue.destination.priority = 1;
+       queue.user_context = (u64)(uintptr_t)fq;
+       err = dpni_set_queue(priv->mc_io, 0, priv->mc_token,
+-                           DPNI_QUEUE_RX, 0, fq->flowid,
++                           DPNI_QUEUE_RX, fq->tc, fq->flowid,
+                            DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST,
+                            &queue);
+       if (err) {
+@@ -2716,6 +2721,10 @@ static int setup_rx_flow(struct dpaa2_et
+       }
+       /* xdp_rxq setup */
++      /* only once for each channel */
++      if (fq->tc > 0)
++              return 0;
++
+       err = xdp_rxq_info_reg(&fq->channel->xdp_rxq, priv->net_dev,
+                              fq->flowid);
+       if (err) {
+@@ -2853,7 +2862,7 @@ static int config_legacy_hash_key(struct
+ {
+       struct device *dev = priv->net_dev->dev.parent;
+       struct dpni_rx_tc_dist_cfg dist_cfg;
+-      int err;
++      int i, err = 0;
+       memset(&dist_cfg, 0, sizeof(dist_cfg));
+@@ -2861,9 +2870,14 @@ static int config_legacy_hash_key(struct
+       dist_cfg.dist_size = dpaa2_eth_queue_count(priv);
+       dist_cfg.dist_mode = DPNI_DIST_MODE_HASH;
+-      err = dpni_set_rx_tc_dist(priv->mc_io, 0, priv->mc_token, 0, &dist_cfg);
+-      if (err)
+-              dev_err(dev, "dpni_set_rx_tc_dist failed\n");
++      for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
++              err = dpni_set_rx_tc_dist(priv->mc_io, 0, priv->mc_token,
++                                        i, &dist_cfg);
++              if (err) {
++                      dev_err(dev, "dpni_set_rx_tc_dist failed\n");
++                      break;
++              }
++      }
+       return err;
+ }
+@@ -2873,7 +2887,7 @@ static int config_hash_key(struct dpaa2_
+ {
+       struct device *dev = priv->net_dev->dev.parent;
+       struct dpni_rx_dist_cfg dist_cfg;
+-      int err;
++      int i, err = 0;
+       memset(&dist_cfg, 0, sizeof(dist_cfg));
+@@ -2881,9 +2895,15 @@ static int config_hash_key(struct dpaa2_
+       dist_cfg.dist_size = dpaa2_eth_queue_count(priv);
+       dist_cfg.enable = 1;
+-      err = dpni_set_rx_hash_dist(priv->mc_io, 0, priv->mc_token, &dist_cfg);
+-      if (err)
+-              dev_err(dev, "dpni_set_rx_hash_dist failed\n");
++      for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
++              dist_cfg.tc = i;
++              err = dpni_set_rx_hash_dist(priv->mc_io, 0, priv->mc_token,
++                                          &dist_cfg);
++              if (err) {
++                      dev_err(dev, "dpni_set_rx_hash_dist failed\n");
++                      break;
++              }
++      }
+       return err;
+ }
+@@ -2893,7 +2913,7 @@ static int config_cls_key(struct dpaa2_e
+ {
+       struct device *dev = priv->net_dev->dev.parent;
+       struct dpni_rx_dist_cfg dist_cfg;
+-      int err;
++      int i, err = 0;
+       memset(&dist_cfg, 0, sizeof(dist_cfg));
+@@ -2901,9 +2921,15 @@ static int config_cls_key(struct dpaa2_e
+       dist_cfg.dist_size = dpaa2_eth_queue_count(priv);
+       dist_cfg.enable = 1;
+-      err = dpni_set_rx_fs_dist(priv->mc_io, 0, priv->mc_token, &dist_cfg);
+-      if (err)
+-              dev_err(dev, "dpni_set_rx_fs_dist failed\n");
++      for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
++              dist_cfg.tc = i;
++              err = dpni_set_rx_fs_dist(priv->mc_io, 0, priv->mc_token,
++                                        &dist_cfg);
++              if (err) {
++                      dev_err(dev, "dpni_set_rx_fs_dist failed\n");
++                      break;
++              }
++      }
+       return err;
+ }
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -291,7 +291,9 @@ struct dpaa2_eth_ch_stats {
+ /* Maximum number of queues associated with a DPNI */
+ #define DPAA2_ETH_MAX_TCS             8
+-#define DPAA2_ETH_MAX_RX_QUEUES               16
++#define DPAA2_ETH_MAX_RX_QUEUES_PER_TC        16
++#define DPAA2_ETH_MAX_RX_QUEUES               \
++      (DPAA2_ETH_MAX_RX_QUEUES_PER_TC * DPAA2_ETH_MAX_TCS)
+ #define DPAA2_ETH_MAX_TX_QUEUES               16
+ #define DPAA2_ETH_MAX_QUEUES          (DPAA2_ETH_MAX_RX_QUEUES + \
+                                       DPAA2_ETH_MAX_TX_QUEUES)
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
+@@ -502,7 +502,7 @@ static int do_cls_rule(struct net_device
+       dma_addr_t key_iova;
+       u64 fields = 0;
+       void *key_buf;
+-      int err;
++      int i, err;
+       if (fs->ring_cookie != RX_CLS_FLOW_DISC &&
+           fs->ring_cookie >= dpaa2_eth_queue_count(priv))
+@@ -562,11 +562,18 @@ static int do_cls_rule(struct net_device
+                       fs_act.options |= DPNI_FS_OPT_DISCARD;
+               else
+                       fs_act.flow_id = fs->ring_cookie;
+-              err = dpni_add_fs_entry(priv->mc_io, 0, priv->mc_token, 0,
+-                                      fs->location, &rule_cfg, &fs_act);
+-      } else {
+-              err = dpni_remove_fs_entry(priv->mc_io, 0, priv->mc_token, 0,
+-                                         &rule_cfg);
++      }
++      for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
++              if (add)
++                      err = dpni_add_fs_entry(priv->mc_io, 0, priv->mc_token,
++                                              i, fs->location, &rule_cfg,
++                                              &fs_act);
++              else
++                      err = dpni_remove_fs_entry(priv->mc_io, 0,
++                                                 priv->mc_token, i,
++                                                 &rule_cfg);
++              if (err)
++                      break;
+       }
+       dma_unmap_single(dev, key_iova, rule_cfg.key_size * 2, DMA_TO_DEVICE);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0193-dpaa2-eth-Trim-debugfs-FQ-stats.patch b/target/linux/layerscape/patches-5.4/701-net-0193-dpaa2-eth-Trim-debugfs-FQ-stats.patch
new file mode 100644 (file)
index 0000000..1327b37
--- /dev/null
@@ -0,0 +1,28 @@
+From 2b19aa3f602c9d9d71959c6306c385927fb9578c Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Tue, 17 Sep 2019 16:53:03 +0300
+Subject: [PATCH] dpaa2-eth: Trim debugfs FQ stats
+
+With the addition of multiple traffic classes support, the number
+of available frame queues grew significantly, overly inflating the
+debugfs FQ statistics entry. Update it to only show the queues
+which are actually in use (i.e. have a non-zero frame counter).
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c
+@@ -90,6 +90,10 @@ static int dpaa2_dbg_fqs_show(struct seq
+               if (err)
+                       fcnt = 0;
++              /* Skip FQs with no traffic */
++              if (!fq->stats.frames && !fcnt)
++                      continue;
++
+               seq_printf(file, "%5d%16d%16d%16s%16llu%16u\n",
+                          fq->fqid,
+                          fq->target_cpu,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0194-dpaa2-eth-Distribute-ingress-frames-based-on-VLAN-pr.patch b/target/linux/layerscape/patches-5.4/701-net-0194-dpaa2-eth-Distribute-ingress-frames-based-on-VLAN-pr.patch
new file mode 100644 (file)
index 0000000..317ed78
--- /dev/null
@@ -0,0 +1,397 @@
+From ea2e3b62b170e0f896aa837c8fec8085fb1063f8 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Tue, 3 Sep 2019 21:11:35 +0300
+Subject: [PATCH] dpaa2-eth: Distribute ingress frames based on VLAN prio
+
+Configure static ingress classification based on VLAN PCP field.
+If the DPNI doesn't have enough traffic classes to accommodate all
+priority levels, the lowest ones end up on TC 0 (default on miss).
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 116 ++++++++++++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h |   1 +
+ drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h  |  34 ++++++
+ drivers/net/ethernet/freescale/dpaa2/dpni.c      | 131 +++++++++++++++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpni.h      |  36 +++++++
+ 5 files changed, 318 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -2603,6 +2603,118 @@ out_err:
+       priv->enqueue = dpaa2_eth_enqueue_qd;
+ }
++/* Configure ingress classification based on VLAN PCP */
++static int set_vlan_qos(struct dpaa2_eth_priv *priv)
++{
++      struct device *dev = priv->net_dev->dev.parent;
++      struct dpkg_profile_cfg kg_cfg = {0};
++      struct dpni_qos_tbl_cfg qos_cfg = {0};
++      struct dpni_rule_cfg key_params;
++      void *dma_mem, *key, *mask;
++      u8 key_size = 2;        /* VLAN TCI field */
++      int i, pcp, err;
++
++      /* VLAN-based classification only makes sense if we have multiple
++       * traffic classes.
++       * Also, we need to extract just the 3-bit PCP field from the VLAN
++       * header and we can only do that by using a mask
++       */
++      if (dpaa2_eth_tc_count(priv) == 1 || !dpaa2_eth_fs_mask_enabled(priv)) {
++              dev_dbg(dev, "VLAN-based QoS classification not supported\n");
++              return -ENOTSUPP;
++      }
++
++      dma_mem = kzalloc(DPAA2_CLASSIFIER_DMA_SIZE, GFP_KERNEL);
++      if (!dma_mem)
++              return -ENOMEM;
++
++      kg_cfg.num_extracts = 1;
++      kg_cfg.extracts[0].type = DPKG_EXTRACT_FROM_HDR;
++      kg_cfg.extracts[0].extract.from_hdr.prot = NET_PROT_VLAN;
++      kg_cfg.extracts[0].extract.from_hdr.type = DPKG_FULL_FIELD;
++      kg_cfg.extracts[0].extract.from_hdr.field = NH_FLD_VLAN_TCI;
++
++      err =  dpni_prepare_key_cfg(&kg_cfg, dma_mem);
++      if (err) {
++              dev_err(dev, "dpni_prepare_key_cfg failed\n");
++              goto out_free_tbl;
++      }
++
++      /* set QoS table */
++      qos_cfg.default_tc = 0;
++      qos_cfg.discard_on_miss = 0;
++      qos_cfg.key_cfg_iova = dma_map_single(dev, dma_mem,
++                                            DPAA2_CLASSIFIER_DMA_SIZE,
++                                            DMA_TO_DEVICE);
++      if (dma_mapping_error(dev, qos_cfg.key_cfg_iova)) {
++              dev_err(dev, "QoS table DMA mapping failed\n");
++              err = -ENOMEM;
++              goto out_free_tbl;
++      }
++
++      err = dpni_set_qos_table(priv->mc_io, 0, priv->mc_token, &qos_cfg);
++      if (err) {
++              dev_err(dev, "dpni_set_qos_table failed\n");
++              goto out_unmap_tbl;
++      }
++
++      /* Add QoS table entries */
++      key = kzalloc(key_size * 2, GFP_KERNEL);
++      if (!key) {
++              err = -ENOMEM;
++              goto out_unmap_tbl;
++      }
++      mask = key + key_size;
++      *(u16 *)mask = cpu_to_be16(VLAN_PRIO_MASK);
++
++      key_params.key_iova = dma_map_single(dev, key, key_size * 2,
++                                           DMA_TO_DEVICE);
++      if (dma_mapping_error(dev, key_params.key_iova)) {
++              dev_err(dev, "Qos table entry DMA mapping failed\n");
++              err = -ENOMEM;
++              goto out_free_key;
++      }
++
++      key_params.mask_iova = key_params.key_iova + key_size;
++      key_params.key_size = key_size;
++
++      /* We add rules for PCP-based distribution starting with highest
++       * priority (VLAN PCP = 7). If this DPNI doesn't have enough traffic
++       * classes to accommodate all priority levels, the lowest ones end up
++       * on TC 0 which was configured as default
++       */
++      for (i = dpaa2_eth_tc_count(priv) - 1, pcp = 7; i >= 0; i--, pcp--) {
++              *(u16 *)key = cpu_to_be16(pcp << VLAN_PRIO_SHIFT);
++              dma_sync_single_for_device(dev, key_params.key_iova,
++                                         key_size * 2, DMA_TO_DEVICE);
++
++              err = dpni_add_qos_entry(priv->mc_io, 0, priv->mc_token,
++                                       &key_params, i, i);
++              if (err) {
++                      dev_err(dev, "dpni_add_qos_entry failed\n");
++                      dpni_clear_qos_table(priv->mc_io, 0, priv->mc_token);
++                      goto out_unmap_key;
++              }
++      }
++
++      priv->vlan_cls_enabled = true;
++
++      /* Table and key memory is not persistent, clean everything up after
++       * configuration is finished
++       */
++out_unmap_key:
++      dma_unmap_single(dev, key_params.key_iova, key_size * 2, DMA_TO_DEVICE);
++out_free_key:
++      kfree(key);
++out_unmap_tbl:
++      dma_unmap_single(dev, qos_cfg.key_cfg_iova, DPAA2_CLASSIFIER_DMA_SIZE,
++                       DMA_TO_DEVICE);
++out_free_tbl:
++      kfree(dma_mem);
++
++      return err;
++}
++
+ /* Configure the DPNI object this interface is associated with */
+ static int setup_dpni(struct fsl_mc_device *ls_dev)
+ {
+@@ -2665,6 +2777,10 @@ static int setup_dpni(struct fsl_mc_devi
+                       goto close;
+       }
++      err = set_vlan_qos(priv);
++      if (err && err != -ENOTSUPP)
++              goto close;
++
+       priv->cls_rules = devm_kzalloc(dev, sizeof(struct dpaa2_eth_cls_rule) *
+                                      dpaa2_eth_fs_count(priv), GFP_KERNEL);
+       if (!priv->cls_rules)
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -413,6 +413,7 @@ struct dpaa2_eth_priv {
+       u64 rx_cls_fields;
+       struct dpaa2_eth_cls_rule *cls_rules;
+       u8 rx_cls_enabled;
++      u8 vlan_cls_enabled;
+       struct bpf_prog *xdp_prog;
+ #ifdef CONFIG_DEBUG_FS
+       struct dpaa2_debugfs dbg;
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
+@@ -59,6 +59,10 @@
+ #define DPNI_CMDID_SET_RX_TC_DIST                     DPNI_CMD(0x235)
++#define DPNI_CMDID_SET_QOS_TBL                                DPNI_CMD(0x240)
++#define DPNI_CMDID_ADD_QOS_ENT                                DPNI_CMD(0x241)
++#define DPNI_CMDID_REMOVE_QOS_ENT                     DPNI_CMD(0x242)
++#define DPNI_CMDID_CLR_QOS_TBL                                DPNI_CMD(0x243)
+ #define DPNI_CMDID_ADD_FS_ENT                         DPNI_CMD(0x244)
+ #define DPNI_CMDID_REMOVE_FS_ENT                      DPNI_CMD(0x245)
+ #define DPNI_CMDID_CLR_FS_ENT                         DPNI_CMD(0x246)
+@@ -567,4 +571,34 @@ struct dpni_cmd_remove_fs_entry {
+       __le64 mask_iova;
+ };
++#define DPNI_DISCARD_ON_MISS_SHIFT    0
++#define DPNI_DISCARD_ON_MISS_SIZE     1
++
++struct dpni_cmd_set_qos_table {
++      __le32 pad;
++      u8 default_tc;
++      /* only the LSB */
++      u8 discard_on_miss;
++      __le16 pad1[21];
++      __le64 key_cfg_iova;
++};
++
++struct dpni_cmd_add_qos_entry {
++      __le16 pad;
++      u8 tc_id;
++      u8 key_size;
++      __le16 index;
++      __le16 pad1;
++      __le64 key_iova;
++      __le64 mask_iova;
++};
++
++struct dpni_cmd_remove_qos_entry {
++      u8 pad[3];
++      u8 key_size;
++      __le32 pad1;
++      __le64 key_iova;
++      __le64 mask_iova;
++};
++
+ #endif /* _FSL_DPNI_CMD_H */
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c
+@@ -1786,3 +1786,134 @@ int dpni_remove_fs_entry(struct fsl_mc_i
+       /* send command to mc*/
+       return mc_send_command(mc_io, &cmd);
+ }
++
++/**
++ * dpni_set_qos_table() - Set QoS mapping table
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPNI object
++ * @cfg:      QoS table configuration
++ *
++ * This function and all QoS-related functions require that
++ *'max_tcs > 1' was set at DPNI creation.
++ *
++ * warning: Before calling this function, call dpkg_prepare_key_cfg() to
++ *                    prepare the key_cfg_iova parameter
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpni_set_qos_table(struct fsl_mc_io *mc_io,
++                     u32 cmd_flags,
++                     u16 token,
++                     const struct dpni_qos_tbl_cfg *cfg)
++{
++      struct dpni_cmd_set_qos_table *cmd_params;
++      struct fsl_mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_QOS_TBL,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpni_cmd_set_qos_table *)cmd.params;
++      cmd_params->default_tc = cfg->default_tc;
++      cmd_params->key_cfg_iova = cpu_to_le64(cfg->key_cfg_iova);
++      dpni_set_field(cmd_params->discard_on_miss, DISCARD_ON_MISS,
++                     cfg->discard_on_miss);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpni_add_qos_entry() - Add QoS mapping entry (to select a traffic class)
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPNI object
++ * @cfg:      QoS rule to add
++ * @tc_id:    Traffic class selection (0-7)
++ * @index:    Location in the QoS table where to insert the entry.
++ *            Only relevant if MASKING is enabled for QoS classification on
++ *            this DPNI, it is ignored for exact match.
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpni_add_qos_entry(struct fsl_mc_io *mc_io,
++                     u32 cmd_flags,
++                     u16 token,
++                     const struct dpni_rule_cfg *cfg,
++                     u8 tc_id,
++                     u16 index)
++{
++      struct dpni_cmd_add_qos_entry *cmd_params;
++      struct fsl_mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_QOS_ENT,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpni_cmd_add_qos_entry *)cmd.params;
++      cmd_params->tc_id = tc_id;
++      cmd_params->key_size = cfg->key_size;
++      cmd_params->index = cpu_to_le16(index);
++      cmd_params->key_iova = cpu_to_le64(cfg->key_iova);
++      cmd_params->mask_iova = cpu_to_le64(cfg->mask_iova);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpni_remove_qos_entry() - Remove QoS mapping entry
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPNI object
++ * @cfg:      QoS rule to remove
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpni_remove_qos_entry(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        const struct dpni_rule_cfg *cfg)
++{
++      struct dpni_cmd_remove_qos_entry *cmd_params;
++      struct fsl_mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_QOS_ENT,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpni_cmd_remove_qos_entry *)cmd.params;
++      cmd_params->key_size = cfg->key_size;
++      cmd_params->key_iova = cpu_to_le64(cfg->key_iova);
++      cmd_params->mask_iova = cpu_to_le64(cfg->mask_iova);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpni_clear_qos_table() - Clear all QoS mapping entries
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPNI object
++ *
++ * Following this function call, all frames are directed to
++ * the default traffic class (0)
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpni_clear_qos_table(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token)
++{
++      struct fsl_mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLR_QOS_TBL,
++                                        cmd_flags,
++                                        token);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h
+@@ -716,6 +716,26 @@ int dpni_set_rx_hash_dist(struct fsl_mc_
+                         const struct dpni_rx_dist_cfg *cfg);
+ /**
++ * struct dpni_qos_tbl_cfg - Structure representing QOS table configuration
++ * @key_cfg_iova: I/O virtual address of 256 bytes DMA-able memory filled with
++ *            key extractions to be used as the QoS criteria by calling
++ *            dpkg_prepare_key_cfg()
++ * @discard_on_miss: Set to '1' to discard frames in case of no match (miss);
++ *            '0' to use the 'default_tc' in such cases
++ * @default_tc: Used in case of no-match and 'discard_on_miss'= 0
++ */
++struct dpni_qos_tbl_cfg {
++      u64 key_cfg_iova;
++      int discard_on_miss;
++      u8 default_tc;
++};
++
++int dpni_set_qos_table(struct fsl_mc_io *mc_io,
++                     u32 cmd_flags,
++                     u16 token,
++                     const struct dpni_qos_tbl_cfg *cfg);
++
++/**
+  * enum dpni_dest - DPNI destination types
+  * @DPNI_DEST_NONE: Unassigned destination; The queue is set in parked mode and
+  *            does not generate FQDAN notifications; user is expected to
+@@ -961,6 +981,22 @@ int dpni_remove_fs_entry(struct fsl_mc_i
+                        u8 tc_id,
+                        const struct dpni_rule_cfg *cfg);
++int dpni_add_qos_entry(struct fsl_mc_io *mc_io,
++                     u32 cmd_flags,
++                     u16 token,
++                     const struct dpni_rule_cfg *cfg,
++                     u8 tc_id,
++                     u16 index);
++
++int dpni_remove_qos_entry(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token,
++                        const struct dpni_rule_cfg *cfg);
++
++int dpni_clear_qos_table(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token);
++
+ int dpni_get_api_version(struct fsl_mc_io *mc_io,
+                        u32 cmd_flags,
+                        u16 *major_ver,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0195-dpaa2-eth-Add-helper-functions.patch b/target/linux/layerscape/patches-5.4/701-net-0195-dpaa2-eth-Add-helper-functions.patch
new file mode 100644 (file)
index 0000000..a63977d
--- /dev/null
@@ -0,0 +1,61 @@
+From 1ffb57beaefe23ceeb526bc238351f7725502571 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Mon, 16 Sep 2019 21:04:49 +0300
+Subject: [PATCH] dpaa2-eth: Add helper functions
+
+Add convenient helper functions that determines whether Rx/Tx pause
+frames are enabled based on link state flags received from firmware.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c     |  3 +--
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h     | 11 +++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c |  5 ++---
+ 3 files changed, 14 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -1276,8 +1276,7 @@ static int link_state_update(struct dpaa
+        * Rx FQ taildrop configuration as well. We configure taildrop
+        * only when pause frame generation is disabled.
+        */
+-      tx_pause = !!(state.options & DPNI_LINK_OPT_PAUSE) ^
+-                 !!(state.options & DPNI_LINK_OPT_ASYM_PAUSE);
++      tx_pause = dpaa2_eth_tx_pause_enabled(state.options);
+       dpaa2_eth_set_rx_taildrop(priv, !tx_pause);
+       /* Chech link state; speed / duplex changes are not treated yet */
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -494,6 +494,17 @@ enum dpaa2_eth_rx_dist {
+       (dpaa2_eth_cmp_dpni_ver((priv), DPNI_PAUSE_VER_MAJOR,   \
+                               DPNI_PAUSE_VER_MINOR) >= 0)
++static inline bool dpaa2_eth_tx_pause_enabled(u64 link_options)
++{
++      return !!(link_options & DPNI_LINK_OPT_PAUSE) ^
++             !!(link_options & DPNI_LINK_OPT_ASYM_PAUSE);
++}
++
++static inline bool dpaa2_eth_rx_pause_enabled(u64 link_options)
++{
++      return !!(link_options & DPNI_LINK_OPT_PAUSE);
++}
++
+ static inline
+ unsigned int dpaa2_eth_needed_headroom(struct dpaa2_eth_priv *priv,
+                                      struct sk_buff *skb)
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
+@@ -99,9 +99,8 @@ static void dpaa2_eth_get_pauseparam(str
+       struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+       u64 link_options = priv->link_state.options;
+-      pause->rx_pause = !!(link_options & DPNI_LINK_OPT_PAUSE);
+-      pause->tx_pause = pause->rx_pause ^
+-                        !!(link_options & DPNI_LINK_OPT_ASYM_PAUSE);
++      pause->rx_pause = dpaa2_eth_rx_pause_enabled(link_options);
++      pause->tx_pause = dpaa2_eth_tx_pause_enabled(link_options);
+       pause->autoneg = AUTONEG_DISABLE;
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0196-dpaa2-eth-Minor-cleanup-in-dpaa2_eth_set_rx_taildrop.patch b/target/linux/layerscape/patches-5.4/701-net-0196-dpaa2-eth-Minor-cleanup-in-dpaa2_eth_set_rx_taildrop.patch
new file mode 100644 (file)
index 0000000..03c7ad5
--- /dev/null
@@ -0,0 +1,92 @@
+From 965b47cbf16a6d1bc8235e1bff038abc9b4cf142 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Wed, 4 Sep 2019 19:45:01 +0300
+Subject: [PATCH] dpaa2-eth: Minor cleanup in dpaa2_eth_set_rx_taildrop()
+
+Make clear the setting refers to FQ-based taildrop and the threshold
+value is given in bytes (the default option).
+
+Reverse the logic of the second argument (pass tx_pause transparently).
+This will be helpful further on.
+
+Also don't set the device's Rx taildrop flag unless configuration
+succeeds.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 19 +++++++++++--------
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h |  4 ++--
+ 2 files changed, 13 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -1228,17 +1228,20 @@ static void disable_ch_napi(struct dpaa2
+       }
+ }
+-static void dpaa2_eth_set_rx_taildrop(struct dpaa2_eth_priv *priv, bool enable)
++static void dpaa2_eth_set_rx_taildrop(struct dpaa2_eth_priv *priv,
++                                    bool tx_pause)
+ {
+       struct dpni_taildrop td = {0};
+       struct dpaa2_eth_fq *fq;
+       int i, err;
+-      if (priv->rx_td_enabled == enable)
++      td.enable = !tx_pause;
++      if (priv->rx_td_enabled == td.enable)
+               return;
+-      td.enable = enable;
+-      td.threshold = DPAA2_ETH_TAILDROP_THRESH;
++      /* FQ taildrop: thrshold is in bytes, per frame queue */
++      td.threshold = DPAA2_ETH_FQ_TAILDROP_THRESH;
++      td.units = DPNI_CONGESTION_UNIT_BYTES;
+       for (i = 0; i < priv->num_fqs; i++) {
+               fq = &priv->fq[i];
+@@ -1249,12 +1252,12 @@ static void dpaa2_eth_set_rx_taildrop(st
+                                       fq->tc, fq->flowid, &td);
+               if (err) {
+                       netdev_err(priv->net_dev,
+-                                 "dpni_set_taildrop() failed\n");
+-                      break;
++                                 "dpni_set_taildrop(FQ) failed\n");
++                      return;
+               }
+       }
+-      priv->rx_td_enabled = enable;
++      priv->rx_td_enabled = td.enable;
+ }
+ static void update_tx_fqids(struct dpaa2_eth_priv *priv);
+@@ -1277,7 +1280,7 @@ static int link_state_update(struct dpaa
+        * only when pause frame generation is disabled.
+        */
+       tx_pause = dpaa2_eth_tx_pause_enabled(state.options);
+-      dpaa2_eth_set_rx_taildrop(priv, !tx_pause);
++      dpaa2_eth_set_rx_taildrop(priv, tx_pause);
+       /* Chech link state; speed / duplex changes are not treated yet */
+       if (priv->link_state.up == state.up)
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -39,7 +39,7 @@
+  * frames in the Rx queues (length of the current frame is not
+  * taken into account when making the taildrop decision)
+  */
+-#define DPAA2_ETH_TAILDROP_THRESH     (64 * 1024)
++#define DPAA2_ETH_FQ_TAILDROP_THRESH  (64 * 1024)
+ /* Maximum number of Tx confirmation frames to be processed
+  * in a single NAPI call
+@@ -51,7 +51,7 @@
+  * how many 64B frames fit inside the taildrop threshold and add a margin
+  * to accommodate the buffer refill delay.
+  */
+-#define DPAA2_ETH_MAX_FRAMES_PER_QUEUE        (DPAA2_ETH_TAILDROP_THRESH / 64)
++#define DPAA2_ETH_MAX_FRAMES_PER_QUEUE        (DPAA2_ETH_FQ_TAILDROP_THRESH / 64)
+ #define DPAA2_ETH_NUM_BUFS            (DPAA2_ETH_MAX_FRAMES_PER_QUEUE + 256)
+ #define DPAA2_ETH_REFILL_THRESH \
+       (DPAA2_ETH_NUM_BUFS - DPAA2_ETH_BUFS_PER_CMD)
diff --git a/target/linux/layerscape/patches-5.4/701-net-0197-dpaa2-eth-Add-congestion-group-taildrop.patch b/target/linux/layerscape/patches-5.4/701-net-0197-dpaa2-eth-Add-congestion-group-taildrop.patch
new file mode 100644 (file)
index 0000000..9125b94
--- /dev/null
@@ -0,0 +1,64 @@
+From fa204fc76c3936c55315ba9423fa7c920af2f9a9 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Wed, 4 Sep 2019 20:32:56 +0300
+Subject: [PATCH] dpaa2-eth: Add congestion group taildrop
+
+The increase in number of ingress frame queues means we now risk
+depleting the buffer pool before the FQ taildrop kicks in.
+
+Congestion group taildrop allows us to control the number of frames
+that can accumulate on a group of Rx frame queues belonging to the
+same traffic class.
+
+This setting coexists with the frame queue based taildrop: whichever
+limit gets hit first triggers the frame drop.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 16 ++++++++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h |  9 +++++++++
+ 2 files changed, 25 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -1257,6 +1257,22 @@ static void dpaa2_eth_set_rx_taildrop(st
+               }
+       }
++      /* Congestion group taildrop: threshold is in frames, per group
++       * of FQs belonging to the same traffic class
++       */
++      td.threshold = DPAA2_ETH_CG_TAILDROP_THRESH(priv);
++      td.units = DPNI_CONGESTION_UNIT_FRAMES;
++      for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
++              err = dpni_set_taildrop(priv->mc_io, 0, priv->mc_token,
++                                      DPNI_CP_GROUP, DPNI_QUEUE_RX,
++                                      i, 0, &td);
++              if (err) {
++                      netdev_err(priv->net_dev,
++                                 "dpni_set_taildrop(CG) failed\n");
++                      return;
++              }
++      }
++
+       priv->rx_td_enabled = td.enable;
+ }
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -56,6 +56,15 @@
+ #define DPAA2_ETH_REFILL_THRESH \
+       (DPAA2_ETH_NUM_BUFS - DPAA2_ETH_BUFS_PER_CMD)
++/* Congestion group taildrop threshold: number of frames allowed to accumulate
++ * at any moment in a group of Rx queues belonging to the same traffic class.
++ * Choose value such that we don't risk depleting the buffer pool before the
++ * taildrop kicks in
++ */
++#define DPAA2_ETH_CG_TAILDROP_THRESH(priv)                            \
++      (DPAA2_ETH_MAX_FRAMES_PER_QUEUE * dpaa2_eth_queue_count(priv) / \
++       dpaa2_eth_tc_count(priv))
++
+ /* Maximum number of buffers that can be acquired/released through a single
+  * QBMan command
+  */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0198-dpaa2-eth-Update-FQ-taildrop-threshold-and-buffer-po.patch b/target/linux/layerscape/patches-5.4/701-net-0198-dpaa2-eth-Update-FQ-taildrop-threshold-and-buffer-po.patch
new file mode 100644 (file)
index 0000000..d9f025f
--- /dev/null
@@ -0,0 +1,77 @@
+From 0c7cb8b132f28cd150eb578a73c959de736364a2 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Mon, 16 Sep 2019 13:15:02 +0300
+Subject: [PATCH] dpaa2-eth: Update FQ taildrop threshold and buffer pool count
+
+Now that we have congestion group taildrop configured at all
+times, we can afford to increase the frame queue taildrop
+threshold; this will ensure a better response when receiving
+bursts of large-sized frames.
+
+Also decouple the buffer pool count from the Rx FQ taildrop
+threshold, as above change would increase it too much. Instead,
+keep the old count as a hardcoded value.
+
+With the new limits, we try to ensure that:
+* we allow enough leeway for large frame bursts (by buffering
+enough of them in queues to avoid heavy dropping in case of
+bursty traffic, but when overall ingress bandwidth is manageable)
+* allow pending frames to be evenly spread between ingress FQs,
+regardless of frame size
+* avoid dropping frames due to the buffer pool being empty; this
+is not a bad behaviour per se, but system overall response is
+more linear and predictable when frames are dropped at frame
+queue/group level.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h | 23 +++++++++++------------
+ 1 file changed, 11 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -35,24 +35,24 @@
+ /* Convert L3 MTU to L2 MFL */
+ #define DPAA2_ETH_L2_MAX_FRM(mtu)     ((mtu) + VLAN_ETH_HLEN)
+-/* Set the taildrop threshold (in bytes) to allow the enqueue of several jumbo
+- * frames in the Rx queues (length of the current frame is not
+- * taken into account when making the taildrop decision)
++/* Set the taildrop threshold (in bytes) to allow the enqueue of a large
++ * enuough number of jumbo frames in the Rx queues (length of the current
++ * frame is not taken into account when making the taildrop decision)
+  */
+-#define DPAA2_ETH_FQ_TAILDROP_THRESH  (64 * 1024)
++#define DPAA2_ETH_FQ_TAILDROP_THRESH  (1024 * 1024)
+ /* Maximum number of Tx confirmation frames to be processed
+  * in a single NAPI call
+  */
+ #define DPAA2_ETH_TXCONF_PER_NAPI     256
+-/* Buffer quota per queue. Must be large enough such that for minimum sized
+- * frames taildrop kicks in before the bpool gets depleted, so we compute
+- * how many 64B frames fit inside the taildrop threshold and add a margin
+- * to accommodate the buffer refill delay.
++/* Buffer qouta per channel. We want to keep in check number of ingress frames
++ * in flight: for small sized frames, congestion group taildrop may kick in
++ * first; for large sizes, Rx FQ taildrop threshold will ensure only a
++ * reasonable number of frames will be pending at any given time.
++ * Ingress frame drop due to buffer pool depletion should be a corner case only
+  */
+-#define DPAA2_ETH_MAX_FRAMES_PER_QUEUE        (DPAA2_ETH_FQ_TAILDROP_THRESH / 64)
+-#define DPAA2_ETH_NUM_BUFS            (DPAA2_ETH_MAX_FRAMES_PER_QUEUE + 256)
++#define DPAA2_ETH_NUM_BUFS            1280
+ #define DPAA2_ETH_REFILL_THRESH \
+       (DPAA2_ETH_NUM_BUFS - DPAA2_ETH_BUFS_PER_CMD)
+@@ -62,8 +62,7 @@
+  * taildrop kicks in
+  */
+ #define DPAA2_ETH_CG_TAILDROP_THRESH(priv)                            \
+-      (DPAA2_ETH_MAX_FRAMES_PER_QUEUE * dpaa2_eth_queue_count(priv) / \
+-       dpaa2_eth_tc_count(priv))
++      (1024 * dpaa2_eth_queue_count(priv) / dpaa2_eth_tc_count(priv))
+ /* Maximum number of buffers that can be acquired/released through a single
+  * QBMan command
diff --git a/target/linux/layerscape/patches-5.4/701-net-0199-dpaa2-eth-Add-DCB-ops.patch b/target/linux/layerscape/patches-5.4/701-net-0199-dpaa2-eth-Add-DCB-ops.patch
new file mode 100644 (file)
index 0000000..3bf2826
--- /dev/null
@@ -0,0 +1,154 @@
+From a893019278e8030fbe251cdaa9d93b8257d1c083 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Thu, 5 Sep 2019 19:31:32 +0300
+Subject: [PATCH] dpaa2-eth: Add DCB ops
+
+Add a skeleton implementation of DCB PFC ops. Actual hardware
+configuration to be added in further commits.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/Kconfig     |  9 +++
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 84 ++++++++++++++++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h |  5 ++
+ 3 files changed, 98 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/Kconfig
++++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig
+@@ -8,6 +8,15 @@ config FSL_DPAA2_ETH
+         The driver manages network objects discovered on the Freescale
+         MC bus.
++if FSL_DPAA2_ETH
++config FSL_DPAA2_ETH_DCB
++      bool "Data Center Bridging (DCB) Support"
++      default n
++      depends on DCB
++      help
++        Enable Priority-Based Flow Control (PFC) support in the driver
++endif
++
+ config FSL_DPAA2_PTP_CLOCK
+       tristate "Freescale DPAA2 PTP Clock"
+       depends on FSL_DPAA2_ETH && PTP_1588_CLOCK_QORIQ
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -3607,6 +3607,81 @@ static void del_ch_napi(struct dpaa2_eth
+       }
+ }
++#ifdef CONFIG_FSL_DPAA2_ETH_DCB
++static int dpaa2_eth_dcbnl_ieee_getpfc(struct net_device *net_dev,
++                                     struct ieee_pfc *pfc)
++{
++      struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
++
++      memcpy(pfc, &priv->pfc, sizeof(priv->pfc));
++      pfc->pfc_cap = dpaa2_eth_tc_count(priv);
++
++      return 0;
++}
++
++static int dpaa2_eth_dcbnl_ieee_setpfc(struct net_device *net_dev,
++                                     struct ieee_pfc *pfc)
++{
++      struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
++
++      if (pfc->mbc || pfc->delay)
++              return -EOPNOTSUPP;
++
++      /* If same PFC enabled mask, nothing to do */
++      if (priv->pfc.pfc_en == pfc->pfc_en)
++              return 0;
++
++      memcpy(&priv->pfc, pfc, sizeof(priv->pfc));
++
++      return 0;
++}
++
++static u8 dpaa2_eth_dcbnl_getdcbx(struct net_device *net_dev)
++{
++      struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
++
++      return priv->dcbx_mode;
++}
++
++static u8 dpaa2_eth_dcbnl_setdcbx(struct net_device *net_dev, u8 mode)
++{
++      struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
++
++      priv->dcbx_mode = mode;
++      return 0;
++}
++
++static u8 dpaa2_eth_dcbnl_getcap(struct net_device *net_dev, int capid, u8 *cap)
++{
++      struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
++
++      switch (capid) {
++      case DCB_CAP_ATTR_PFC:
++              *cap = true;
++              break;
++      case DCB_CAP_ATTR_PFC_TCS:
++              *cap = 1 << (dpaa2_eth_tc_count(priv) - 1);
++              break;
++      case DCB_CAP_ATTR_DCBX:
++              *cap = priv->dcbx_mode;
++              break;
++      default:
++              *cap = false;
++              break;
++      }
++
++      return 0;
++}
++
++const struct dcbnl_rtnl_ops dpaa2_eth_dcbnl_ops = {
++      .ieee_getpfc    = dpaa2_eth_dcbnl_ieee_getpfc,
++      .ieee_setpfc    = dpaa2_eth_dcbnl_ieee_setpfc,
++      .getdcbx        = dpaa2_eth_dcbnl_getdcbx,
++      .setdcbx        = dpaa2_eth_dcbnl_setdcbx,
++      .getcap         = dpaa2_eth_dcbnl_getcap,
++};
++#endif
++
+ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
+ {
+       struct device *dev;
+@@ -3696,6 +3771,15 @@ static int dpaa2_eth_probe(struct fsl_mc
+       if (err)
+               goto err_alloc_rings;
++#ifdef CONFIG_FSL_DPAA2_ETH_DCB
++      if (dpaa2_eth_has_pause_support(priv) && priv->vlan_cls_enabled) {
++              priv->dcbx_mode = DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE;
++              net_dev->dcbnl_ops = &dpaa2_eth_dcbnl_ops;
++      } else {
++              dev_dbg(dev, "PFC not supported\n");
++      }
++#endif
++
+       err = setup_irqs(dpni_dev);
+       if (err) {
+               netdev_warn(net_dev, "Failed to set link interrupt, fall back to polling\n");
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -6,6 +6,7 @@
+ #ifndef __DPAA2_ETH_H
+ #define __DPAA2_ETH_H
++#include <linux/dcbnl.h>
+ #include <linux/netdevice.h>
+ #include <linux/if_vlan.h>
+ #include <linux/fsl/mc.h>
+@@ -422,6 +423,10 @@ struct dpaa2_eth_priv {
+       struct dpaa2_eth_cls_rule *cls_rules;
+       u8 rx_cls_enabled;
+       u8 vlan_cls_enabled;
++#ifdef CONFIG_FSL_DPAA2_ETH_DCB
++      u8 dcbx_mode;
++      struct ieee_pfc pfc;
++#endif
+       struct bpf_prog *xdp_prog;
+ #ifdef CONFIG_DEBUG_FS
+       struct dpaa2_debugfs dbg;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0200-dpaa2-eth-Enable-Rx-PFC.patch b/target/linux/layerscape/patches-5.4/701-net-0200-dpaa2-eth-Enable-Rx-PFC.patch
new file mode 100644 (file)
index 0000000..69a0999
--- /dev/null
@@ -0,0 +1,86 @@
+From 7a342f60e569047e1632f6af91f503993769a2ec Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Tue, 17 Sep 2019 19:51:15 +0300
+Subject: [PATCH] dpaa2-eth: Enable Rx PFC
+
+Instruct the hardware to respond to received PFC frames.
+
+Current firmware doesn't allow us to selectively enable PFC
+on the Rx side for some priorities only, so we will react to
+all incoming PFC frames (and stop transmitting on the traffic
+classes specified in the frame).
+
+PFC depends on the PAUSE flag also being set in link options.
+Don't set it implicitly when user configures PFC, but issue
+a warning if the two settings are not in sync.
+
+For the Tx side, setting the PFC_PAUSE flag in the link options
+is necessary but not sufficient, so PFC frame generation is
+not enabled yet.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 23 +++++++++++++++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpni.h      |  5 +++++
+ 2 files changed, 28 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -3613,6 +3613,9 @@ static int dpaa2_eth_dcbnl_ieee_getpfc(s
+ {
+       struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
++      if (!(priv->link_state.options & DPNI_LINK_OPT_PFC_PAUSE))
++              return 0;
++
+       memcpy(pfc, &priv->pfc, sizeof(priv->pfc));
+       pfc->pfc_cap = dpaa2_eth_tc_count(priv);
+@@ -3623,6 +3626,8 @@ static int dpaa2_eth_dcbnl_ieee_setpfc(s
+                                      struct ieee_pfc *pfc)
+ {
+       struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
++      struct dpni_link_cfg link_cfg = {0};
++      int err;
+       if (pfc->mbc || pfc->delay)
+               return -EOPNOTSUPP;
+@@ -3631,6 +3636,24 @@ static int dpaa2_eth_dcbnl_ieee_setpfc(s
+       if (priv->pfc.pfc_en == pfc->pfc_en)
+               return 0;
++      /* We allow PFC configuration even if it won't have any effect until
++       * general pause frames are enabled
++       */
++      if (!dpaa2_eth_rx_pause_enabled(priv->link_state.options))
++              netdev_warn(net_dev, "Pause support must be enabled in order for PFC to work!\n");
++
++      link_cfg.rate = priv->link_state.rate;
++      link_cfg.options = priv->link_state.options;
++      if (pfc->pfc_en)
++              link_cfg.options |= DPNI_LINK_OPT_PFC_PAUSE;
++      else
++              link_cfg.options &= ~DPNI_LINK_OPT_PFC_PAUSE;
++      err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &link_cfg);
++      if (err) {
++              netdev_err(net_dev, "dpni_set_link_cfg failed\n");
++              return err;
++      }
++
+       memcpy(&priv->pfc, pfc, sizeof(priv->pfc));
+       return 0;
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h
+@@ -514,6 +514,11 @@ int dpni_get_statistics(struct fsl_mc_io
+ #define DPNI_LINK_OPT_ASYM_PAUSE      0x0000000000000008ULL
+ /**
++ * Enable priority flow control pause frames
++ */
++#define DPNI_LINK_OPT_PFC_PAUSE               0x0000000000000010ULL
++
++/**
+  * struct - Structure representing DPNI link configuration
+  * @rate: Rate
+  * @options: Mask of available options; use 'DPNI_LINK_OPT_<X>' values
diff --git a/target/linux/layerscape/patches-5.4/701-net-0201-dpaa2-eth-Enable-Tx-PFC.patch b/target/linux/layerscape/patches-5.4/701-net-0201-dpaa2-eth-Enable-Tx-PFC.patch
new file mode 100644 (file)
index 0000000..4efc155
--- /dev/null
@@ -0,0 +1,263 @@
+From 07fb72fb5b3d2faeeb742ae573aa54a4a1eeee12 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Tue, 17 Sep 2019 20:36:08 +0300
+Subject: [PATCH] dpaa2-eth: Enable Tx PFC
+
+Configure the hardware to generate PFC frames based on Rx congestion
+notifications. When a certain number of frames accumulate in the
+ingress queues corresponding to a traffic class, priority flow control
+frames are generated for that TC.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 49 ++++++++++++++++++++-
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h | 11 +++++
+ drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h  | 25 +++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpni.c      | 46 +++++++++++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpni.h      | 56 ++++++++++++++++++++++++
+ 5 files changed, 186 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -3622,6 +3622,47 @@ static int dpaa2_eth_dcbnl_ieee_getpfc(s
+       return 0;
+ }
++static inline bool is_prio_enabled(u8 pfc_en, u8 tc)
++{
++      return !!(pfc_en & (1 << tc));
++}
++
++static int set_pfc_cn(struct dpaa2_eth_priv *priv, u8 pfc_en)
++{
++      struct dpni_congestion_notification_cfg cfg = {0};
++      int i, err;
++
++      cfg.notification_mode = DPNI_CONG_OPT_FLOW_CONTROL;
++      cfg.units = DPNI_CONGESTION_UNIT_FRAMES;
++      cfg.message_iova = 0ULL;
++      cfg.message_ctx = 0ULL;
++
++      for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
++              if (is_prio_enabled(pfc_en, i)) {
++                      cfg.threshold_entry = DPAA2_ETH_CN_THRESH_ENTRY(priv);
++                      cfg.threshold_exit = DPAA2_ETH_CN_THRESH_EXIT(priv);
++              } else {
++                      /* For priorities not set in the pfc_en mask, we leave
++                       * the congestion thresholds at zero, which effectively
++                       * disables generation of PFC frames for them
++                       */
++                      cfg.threshold_entry = 0;
++                      cfg.threshold_exit = 0;
++              }
++
++              err = dpni_set_congestion_notification(priv->mc_io, 0,
++                                                     priv->mc_token,
++                                                     DPNI_QUEUE_RX, i, &cfg);
++              if (err) {
++                      netdev_err(priv->net_dev,
++                                 "dpni_set_congestion_notification failed\n");
++                      return err;
++              }
++      }
++
++      return 0;
++}
++
+ static int dpaa2_eth_dcbnl_ieee_setpfc(struct net_device *net_dev,
+                                      struct ieee_pfc *pfc)
+ {
+@@ -3639,7 +3680,8 @@ static int dpaa2_eth_dcbnl_ieee_setpfc(s
+       /* We allow PFC configuration even if it won't have any effect until
+        * general pause frames are enabled
+        */
+-      if (!dpaa2_eth_rx_pause_enabled(priv->link_state.options))
++      if (!dpaa2_eth_rx_pause_enabled(priv->link_state.options) ||
++          !dpaa2_eth_tx_pause_enabled(priv->link_state.options))
+               netdev_warn(net_dev, "Pause support must be enabled in order for PFC to work!\n");
+       link_cfg.rate = priv->link_state.rate;
+@@ -3654,6 +3696,11 @@ static int dpaa2_eth_dcbnl_ieee_setpfc(s
+               return err;
+       }
++      /* Configure congestion notifications for the enabled priorities */
++      err = set_pfc_cn(priv, pfc->pfc_en);
++      if (err)
++              return err;
++
+       memcpy(&priv->pfc, pfc, sizeof(priv->pfc));
+       return 0;
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -65,6 +65,17 @@
+ #define DPAA2_ETH_CG_TAILDROP_THRESH(priv)                            \
+       (1024 * dpaa2_eth_queue_count(priv) / dpaa2_eth_tc_count(priv))
++/* Congestion group notification threshold: when this many frames accumulate
++ * on the Rx queues belonging to the same TC, the MAC is instructed to send
++ * PFC frames for that TC.
++ * When number of pending frames drops below exit threshold transmission of
++ * PFC frames is stopped.
++ */
++#define DPAA2_ETH_CN_THRESH_ENTRY(priv) \
++      (DPAA2_ETH_CG_TAILDROP_THRESH(priv) / 2)
++#define DPAA2_ETH_CN_THRESH_EXIT(priv) \
++      (DPAA2_ETH_CN_THRESH_ENTRY(priv) * 3 / 4)
++
+ /* Maximum number of buffers that can be acquired/released through a single
+  * QBMan command
+  */
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
+@@ -601,4 +601,29 @@ struct dpni_cmd_remove_qos_entry {
+       __le64 mask_iova;
+ };
++#define DPNI_DEST_TYPE_SHIFT          0
++#define DPNI_DEST_TYPE_SIZE           4
++#define DPNI_CONG_UNITS_SHIFT         4
++#define DPNI_CONG_UNITS_SIZE          2
++
++struct dpni_cmd_set_congestion_notification {
++      /* cmd word 0 */
++      u8 qtype;
++      u8 tc;
++      u8 pad[6];
++      /* cmd word 1 */
++      __le32 dest_id;
++      __le16 notification_mode;
++      u8 dest_priority;
++      /* from LSB: dest_type: 4 units:2 */
++      u8 type_units;
++      /* cmd word 2 */
++      __le64 message_iova;
++      /* cmd word 3 */
++      __le64 message_ctx;
++      /* cmd word 4 */
++      __le32 threshold_entry;
++      __le32 threshold_exit;
++};
++
+ #endif /* _FSL_DPNI_CMD_H */
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c
+@@ -1355,6 +1355,52 @@ int dpni_set_rx_tc_dist(struct fsl_mc_io
+ }
+ /**
++ * dpni_set_congestion_notification() - Set traffic class congestion
++ *                                    notification configuration
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPNI object
++ * @qtype:    Type of queue - Rx, Tx and Tx confirm types are supported
++ * @tc_id:    Traffic class selection (0-7)
++ * @cfg:      Congestion notification configuration
++ *
++ * Return:    '0' on Success; error code otherwise.
++ */
++int dpni_set_congestion_notification(
++                      struct fsl_mc_io *mc_io,
++                      u32 cmd_flags,
++                      u16 token,
++                      enum dpni_queue_type qtype,
++                      u8 tc_id,
++                      const struct dpni_congestion_notification_cfg *cfg)
++{
++      struct dpni_cmd_set_congestion_notification *cmd_params;
++      struct fsl_mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header =
++              mc_encode_cmd_header(DPNI_CMDID_SET_CONGESTION_NOTIFICATION,
++                                   cmd_flags,
++                                   token);
++      cmd_params = (struct dpni_cmd_set_congestion_notification *)cmd.params;
++      cmd_params->qtype = qtype;
++      cmd_params->tc = tc_id;
++      cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id);
++      cmd_params->notification_mode = cpu_to_le16(cfg->notification_mode);
++      cmd_params->dest_priority = cfg->dest_cfg.priority;
++      dpni_set_field(cmd_params->type_units, DEST_TYPE,
++                     cfg->dest_cfg.dest_type);
++      dpni_set_field(cmd_params->type_units, CONG_UNITS, cfg->units);
++      cmd_params->message_iova = cpu_to_le64(cfg->message_iova);
++      cmd_params->message_ctx = cpu_to_le64(cfg->message_ctx);
++      cmd_params->threshold_entry = cpu_to_le32(cfg->threshold_entry);
++      cmd_params->threshold_exit = cpu_to_le32(cfg->threshold_exit);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
+  * dpni_set_queue() - Set queue parameters
+  * @mc_io:    Pointer to MC portal's I/O object
+  * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h
+@@ -883,6 +883,62 @@ enum dpni_congestion_point {
+ };
+ /**
++ * struct dpni_dest_cfg - Structure representing DPNI destination parameters
++ * @dest_type:        Destination type
++ * @dest_id:  Either DPIO ID or DPCON ID, depending on the destination type
++ * @priority: Priority selection within the DPIO or DPCON channel; valid
++ *            values are 0-1 or 0-7, depending on the number of priorities
++ *            in that channel; not relevant for 'DPNI_DEST_NONE' option
++ */
++struct dpni_dest_cfg {
++      enum dpni_dest dest_type;
++      int dest_id;
++      u8 priority;
++};
++
++/* DPNI congestion options */
++
++/**
++ * This congestion will trigger flow control or priority flow control.
++ * This will have effect only if flow control is enabled with
++ * dpni_set_link_cfg().
++ */
++#define DPNI_CONG_OPT_FLOW_CONTROL            0x00000040
++
++/**
++ * struct dpni_congestion_notification_cfg - congestion notification
++ *                                    configuration
++ * @units: Units type
++ * @threshold_entry: Above this threshold we enter a congestion state.
++ *            set it to '0' to disable it
++ * @threshold_exit: Below this threshold we exit the congestion state.
++ * @message_ctx: The context that will be part of the CSCN message
++ * @message_iova: I/O virtual address (must be in DMA-able memory),
++ *            must be 16B aligned; valid only if 'DPNI_CONG_OPT_WRITE_MEM_<X>'
++ *            is contained in 'options'
++ * @dest_cfg: CSCN can be send to either DPIO or DPCON WQ channel
++ * @notification_mode: Mask of available options; use 'DPNI_CONG_OPT_<X>' values
++ */
++
++struct dpni_congestion_notification_cfg {
++      enum dpni_congestion_unit units;
++      u32 threshold_entry;
++      u32 threshold_exit;
++      u64 message_ctx;
++      u64 message_iova;
++      struct dpni_dest_cfg dest_cfg;
++      u16 notification_mode;
++};
++
++int dpni_set_congestion_notification(
++                      struct fsl_mc_io *mc_io,
++                      u32 cmd_flags,
++                      u16 token,
++                      enum dpni_queue_type qtype,
++                      u8 tc_id,
++                      const struct dpni_congestion_notification_cfg *cfg);
++
++/**
+  * struct dpni_taildrop - Structure representing the taildrop
+  * @enable:   Indicates whether the taildrop is active or not.
+  * @units:    Indicates the unit of THRESHOLD. Queue taildrop only supports
diff --git a/target/linux/layerscape/patches-5.4/701-net-0202-dpaa2-eth-Keep-congestion-group-taildrop-enabled-whe.patch b/target/linux/layerscape/patches-5.4/701-net-0202-dpaa2-eth-Keep-congestion-group-taildrop-enabled-whe.patch
new file mode 100644 (file)
index 0000000..513fcc4
--- /dev/null
@@ -0,0 +1,138 @@
+From b58fa682dceaee9e2576f9ba3f36942c650414ae Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Tue, 17 Sep 2019 21:14:04 +0300
+Subject: [PATCH] dpaa2-eth: Keep congestion group taildrop enabled when PFC on
+
+Leave congestion group taildrop enabled for all traffic classes
+when PFC is enabled. Notification threshold is low enough such
+that it will be hit first and this also ensures that FQs on
+traffic classes which are not PFC enabled won't drain the buffer
+pool.
+
+FQ taildrop threshold is kept disabled as long as any form of
+flow control is on. Since FQ taildrop works with bytes, not number
+of frames, we can't guarantee it will not interfere with the
+congestion notification mechanism for all frame sizes.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 35 ++++++++++++++++++------
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h |  4 ++-
+ 2 files changed, 30 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -1229,17 +1229,21 @@ static void disable_ch_napi(struct dpaa2
+ }
+ static void dpaa2_eth_set_rx_taildrop(struct dpaa2_eth_priv *priv,
+-                                    bool tx_pause)
++                                    bool tx_pause, bool pfc)
+ {
+       struct dpni_taildrop td = {0};
+       struct dpaa2_eth_fq *fq;
+       int i, err;
++      /* FQ taildrop: threshold is in bytes, per frame queue. Enabled if
++       * flow control is disabled (as it might interfere with either the
++       * buffer pool depletion trigger for pause frames or with the group
++       * congestion trigger for PFC frames)
++       */
+       td.enable = !tx_pause;
+-      if (priv->rx_td_enabled == td.enable)
+-              return;
++      if (priv->rx_fqtd_enabled == td.enable)
++              goto set_cgtd;
+-      /* FQ taildrop: thrshold is in bytes, per frame queue */
+       td.threshold = DPAA2_ETH_FQ_TAILDROP_THRESH;
+       td.units = DPNI_CONGESTION_UNIT_BYTES;
+@@ -1257,9 +1261,20 @@ static void dpaa2_eth_set_rx_taildrop(st
+               }
+       }
++      priv->rx_fqtd_enabled = td.enable;
++
++set_cgtd:
+       /* Congestion group taildrop: threshold is in frames, per group
+        * of FQs belonging to the same traffic class
++       * Enabled if general Tx pause disabled or if PFCs are enabled
++       * (congestion group threhsold for PFC generation is lower than the
++       * CG taildrop threshold, so it won't interfere with it; we also
++       * want frames in non-PFC enabled traffic classes to be kept in check)
+        */
++      td.enable = !tx_pause || (tx_pause && pfc);
++      if (priv->rx_cgtd_enabled == td.enable)
++              return;
++
+       td.threshold = DPAA2_ETH_CG_TAILDROP_THRESH(priv);
+       td.units = DPNI_CONGESTION_UNIT_FRAMES;
+       for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
+@@ -1273,7 +1288,7 @@ static void dpaa2_eth_set_rx_taildrop(st
+               }
+       }
+-      priv->rx_td_enabled = td.enable;
++      priv->rx_cgtd_enabled = td.enable;
+ }
+ static void update_tx_fqids(struct dpaa2_eth_priv *priv);
+@@ -1296,7 +1311,7 @@ static int link_state_update(struct dpaa
+        * only when pause frame generation is disabled.
+        */
+       tx_pause = dpaa2_eth_tx_pause_enabled(state.options);
+-      dpaa2_eth_set_rx_taildrop(priv, tx_pause);
++      dpaa2_eth_set_rx_taildrop(priv, tx_pause, priv->pfc_enabled);
+       /* Chech link state; speed / duplex changes are not treated yet */
+       if (priv->link_state.up == state.up)
+@@ -3668,6 +3683,7 @@ static int dpaa2_eth_dcbnl_ieee_setpfc(s
+ {
+       struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+       struct dpni_link_cfg link_cfg = {0};
++      bool tx_pause;
+       int err;
+       if (pfc->mbc || pfc->delay)
+@@ -3680,8 +3696,8 @@ static int dpaa2_eth_dcbnl_ieee_setpfc(s
+       /* We allow PFC configuration even if it won't have any effect until
+        * general pause frames are enabled
+        */
+-      if (!dpaa2_eth_rx_pause_enabled(priv->link_state.options) ||
+-          !dpaa2_eth_tx_pause_enabled(priv->link_state.options))
++      tx_pause = dpaa2_eth_tx_pause_enabled(priv->link_state.options);
++      if (!dpaa2_eth_rx_pause_enabled(priv->link_state.options) || !tx_pause)
+               netdev_warn(net_dev, "Pause support must be enabled in order for PFC to work!\n");
+       link_cfg.rate = priv->link_state.rate;
+@@ -3702,6 +3718,9 @@ static int dpaa2_eth_dcbnl_ieee_setpfc(s
+               return err;
+       memcpy(&priv->pfc, pfc, sizeof(priv->pfc));
++      priv->pfc_enabled = !!pfc->pfc_en;
++
++      dpaa2_eth_set_rx_taildrop(priv, tx_pause, priv->pfc_enabled);
+       return 0;
+ }
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -422,7 +422,8 @@ struct dpaa2_eth_priv {
+       struct dpaa2_eth_drv_stats __percpu *percpu_extras;
+       u16 mc_token;
+-      u8 rx_td_enabled;
++      u8 rx_fqtd_enabled;
++      u8 rx_cgtd_enabled;
+       struct dpni_link_state link_state;
+       bool do_link_poll;
+@@ -434,6 +435,7 @@ struct dpaa2_eth_priv {
+       struct dpaa2_eth_cls_rule *cls_rules;
+       u8 rx_cls_enabled;
+       u8 vlan_cls_enabled;
++      u8 pfc_enabled;
+ #ifdef CONFIG_FSL_DPAA2_ETH_DCB
+       u8 dcbx_mode;
+       struct ieee_pfc pfc;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0203-dpaa2-eth-Add-Tx-shaping-API.patch b/target/linux/layerscape/patches-5.4/701-net-0203-dpaa2-eth-Add-Tx-shaping-API.patch
new file mode 100644 (file)
index 0000000..f1bbc55
--- /dev/null
@@ -0,0 +1,94 @@
+From bec2af878c58bbd12f9009948d4fc58ad9c7c1d3 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Fri, 5 May 2017 18:45:50 +0300
+Subject: [PATCH] dpaa2-eth: Add Tx shaping API
+
+DPNIs can be configured to accept a maximum Tx rate and
+burst size. Add the MC API for controlling these parameters.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h |  8 +++++++
+ drivers/net/ethernet/freescale/dpaa2/dpni.c     | 29 +++++++++++++++++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpni.h     | 15 +++++++++++++
+ 3 files changed, 52 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
+@@ -315,6 +315,14 @@ struct dpni_rsp_get_link_state {
+       __le64 options;
+ };
++struct dpni_cmd_set_tx_shaping {
++      /* cmd word 0 */
++      __le16 max_burst_size;
++      __le16 pad[3];
++      /* cmd word 1 */
++      __le32 rate_limit;
++};
++
+ struct dpni_cmd_set_max_frame_length {
+       __le16 max_frame_length;
+ };
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c
+@@ -926,6 +926,35 @@ int dpni_get_link_state(struct fsl_mc_io
+ }
+ /**
++ * dpni_set_tx_shaping() - Set the transmit shaping
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPNI object
++ * @tx_shaper:        Tx shaping configuration
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpni_set_tx_shaping(struct fsl_mc_io *mc_io,
++                      u32 cmd_flags,
++                      u16 token,
++                      const struct dpni_tx_shaping_cfg *tx_shaper)
++{
++      struct fsl_mc_command cmd = { 0 };
++      struct dpni_cmd_set_tx_shaping *cmd_params;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_SHAPING,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpni_cmd_set_tx_shaping *)cmd.params;
++      cmd_params->max_burst_size = cpu_to_le16(tx_shaper->max_burst_size);
++      cmd_params->rate_limit = cpu_to_le32(tx_shaper->rate_limit);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
+  * dpni_set_max_frame_length() - Set the maximum received frame length.
+  * @mc_io:    Pointer to MC portal's I/O object
+  * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h
+@@ -555,6 +555,21 @@ int dpni_get_link_state(struct fsl_mc_io
+                       u16                     token,
+                       struct dpni_link_state  *state);
++/**
++ * struct dpni_tx_shaping - Structure representing DPNI tx shaping configuration
++ * @rate_limit: rate in Mbps
++ * @max_burst_size: burst size in bytes (up to 64KB)
++ */
++struct dpni_tx_shaping_cfg {
++      u32     rate_limit;
++      u16     max_burst_size;
++};
++
++int dpni_set_tx_shaping(struct fsl_mc_io                      *mc_io,
++                      u32                                     cmd_flags,
++                      u16                                     token,
++                      const struct dpni_tx_shaping_cfg        *tx_shaper);
++
+ int dpni_set_max_frame_length(struct fsl_mc_io        *mc_io,
+                             u32               cmd_flags,
+                             u16               token,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0204-dpaa2-eth-Add-Tx-shaping-support.patch b/target/linux/layerscape/patches-5.4/701-net-0204-dpaa2-eth-Add-Tx-shaping-support.patch
new file mode 100644 (file)
index 0000000..e1354b1
--- /dev/null
@@ -0,0 +1,142 @@
+From ef0cc7d01f3eeca37c6bf864903af1c0cf0a792d Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Fri, 5 May 2017 18:11:08 +0300
+Subject: [PATCH] dpaa2-eth: Add Tx shaping support
+
+Add support in sysfs for controlling DPNI Tx shaping
+parameters: rate limit (in Mbps) and max burst size (in bytes).
+The settings are per port.
+
+TODO: See how to integrate Tx shaping support using
+standard Linux tools (ethtool)
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 80 ++++++++++++++++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h |  4 ++
+ 2 files changed, 84 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -3771,6 +3771,83 @@ const struct dcbnl_rtnl_ops dpaa2_eth_dc
+ };
+ #endif
++/* SysFS support */
++static ssize_t dpaa2_eth_show_tx_shaping(struct device *dev,
++                                       struct device_attribute *attr,
++                                       char *buf)
++{
++      struct dpaa2_eth_priv *priv = netdev_priv(to_net_dev(dev));
++      /* No MC API for getting the shaping config. We're stateful. */
++      struct dpni_tx_shaping_cfg *scfg = &priv->shaping_cfg;
++
++      return sprintf(buf, "%u %hu\n", scfg->rate_limit, scfg->max_burst_size);
++}
++
++static ssize_t dpaa2_eth_write_tx_shaping(struct device *dev,
++                                        struct device_attribute *attr,
++                                        const char *buf,
++                                        size_t count)
++{
++      int err, items;
++      struct dpaa2_eth_priv *priv = netdev_priv(to_net_dev(dev));
++      struct dpni_tx_shaping_cfg scfg;
++
++      items = sscanf(buf, "%u %hu", &scfg.rate_limit, &scfg.max_burst_size);
++      if (items != 2) {
++              pr_err("Expected format: \"rate_limit(Mbps) max_burst_size(bytes)\"\n");
++              return -EINVAL;
++      }
++      /* Size restriction as per MC API documentation */
++      if (scfg.max_burst_size > DPAA2_ETH_MAX_BURST_SIZE) {
++              pr_err("max_burst_size must be <= %d\n",
++                     DPAA2_ETH_MAX_BURST_SIZE);
++              return -EINVAL;
++      }
++
++      err = dpni_set_tx_shaping(priv->mc_io, 0, priv->mc_token, &scfg);
++      if (err) {
++              dev_err(dev, "dpni_set_tx_shaping() failed\n");
++              return -EPERM;
++      }
++      /* If successful, save the current configuration for future inquiries */
++      priv->shaping_cfg = scfg;
++
++      return count;
++}
++
++static struct device_attribute dpaa2_eth_attrs[] = {
++      __ATTR(tx_shaping,
++             0600,
++             dpaa2_eth_show_tx_shaping,
++             dpaa2_eth_write_tx_shaping),
++};
++
++static void dpaa2_eth_sysfs_init(struct device *dev)
++{
++      int i, err;
++
++      for (i = 0; i < ARRAY_SIZE(dpaa2_eth_attrs); i++) {
++              err = device_create_file(dev, &dpaa2_eth_attrs[i]);
++              if (err) {
++                      dev_err(dev, "ERROR creating sysfs file\n");
++                      goto undo;
++              }
++      }
++      return;
++
++undo:
++      while (i > 0)
++              device_remove_file(dev, &dpaa2_eth_attrs[--i]);
++}
++
++static void dpaa2_eth_sysfs_remove(struct device *dev)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(dpaa2_eth_attrs); i++)
++              device_remove_file(dev, &dpaa2_eth_attrs[i]);
++}
++
+ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
+ {
+       struct device *dev;
+@@ -3890,6 +3967,7 @@ static int dpaa2_eth_probe(struct fsl_mc
+ #ifdef CONFIG_DEBUG_FS
+       dpaa2_dbg_add(priv);
+ #endif
++      dpaa2_eth_sysfs_init(&net_dev->dev);
+       dev_info(dev, "Probed interface %s\n", net_dev->name);
+       return 0;
+@@ -3937,6 +4015,8 @@ static int dpaa2_eth_remove(struct fsl_m
+ #ifdef CONFIG_DEBUG_FS
+       dpaa2_dbg_remove(priv);
+ #endif
++      dpaa2_eth_sysfs_remove(&net_dev->dev);
++
+       unregister_netdev(net_dev);
+       if (priv->do_link_poll)
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -42,6 +42,9 @@
+  */
+ #define DPAA2_ETH_FQ_TAILDROP_THRESH  (1024 * 1024)
++/* Maximum burst size value for Tx shaping */
++#define DPAA2_ETH_MAX_BURST_SIZE      0xF7FF
++
+ /* Maximum number of Tx confirmation frames to be processed
+  * in a single NAPI call
+  */
+@@ -444,6 +447,7 @@ struct dpaa2_eth_priv {
+ #ifdef CONFIG_DEBUG_FS
+       struct dpaa2_debugfs dbg;
+ #endif
++      struct dpni_tx_shaping_cfg shaping_cfg;
+ };
+ #define DPAA2_RXH_SUPPORTED   (RXH_L2DA | RXH_VLAN | RXH_L3_PROTO \
diff --git a/target/linux/layerscape/patches-5.4/701-net-0205-dpaa2-eth-Add-Rx-error-queue.patch b/target/linux/layerscape/patches-5.4/701-net-0205-dpaa2-eth-Add-Rx-error-queue.patch
new file mode 100644 (file)
index 0000000..6912418
--- /dev/null
@@ -0,0 +1,202 @@
+From 73b0aa73b401810424afa90bf58663a56ad9d51a Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Fri, 5 May 2017 19:07:50 +0300
+Subject: [PATCH] dpaa2-eth: Add Rx error queue
+
+Until now all error frames on the ingress path were discarded
+in hardware. For debug purposes, add an option to have these
+frames delivered to the cpu, on a dedicated queue.
+
+TODO: Remove Kconfig option, find another way to enable
+Rx error queue support
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/Kconfig     | 10 +++
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 97 ++++++++++++++++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h |  5 +-
+ 3 files changed, 111 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/Kconfig
++++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig
+@@ -15,6 +15,16 @@ config FSL_DPAA2_ETH_DCB
+       depends on DCB
+       help
+         Enable Priority-Based Flow Control (PFC) support in the driver
++
++config FSL_DPAA2_ETH_USE_ERR_QUEUE
++      bool "Enable Rx error queue"
++      default n
++      help
++        Allow Rx error frames to be enqueued on an error queue
++        and processed by the driver (by default they are dropped
++        in hardware).
++        This may impact performance, recommended for debugging
++        purposes only.
+ endif
+ config FSL_DPAA2_PTP_CLOCK
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -449,6 +449,53 @@ err_frame_format:
+       percpu_stats->rx_dropped++;
+ }
++#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE
++/* Processing of Rx frames received on the error FQ
++ * We check and print the error bits and then free the frame
++ */
++static void dpaa2_eth_rx_err(struct dpaa2_eth_priv *priv,
++                           struct dpaa2_eth_channel *ch,
++                           const struct dpaa2_fd *fd,
++                           struct dpaa2_eth_fq *fq __always_unused)
++{
++      struct device *dev = priv->net_dev->dev.parent;
++      dma_addr_t addr = dpaa2_fd_get_addr(fd);
++      void *vaddr;
++      struct rtnl_link_stats64 *percpu_stats;
++      struct dpaa2_fas *fas;
++      u32 status = 0;
++      u32 fd_errors;
++      bool has_fas_errors = false;
++
++      vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr);
++      dma_unmap_single(dev, addr, DPAA2_ETH_RX_BUF_SIZE, DMA_BIDIRECTIONAL);
++
++      /* check frame errors in the FD field */
++      fd_errors = dpaa2_fd_get_ctrl(fd) & DPAA2_FD_RX_ERR_MASK;
++      if (likely(fd_errors)) {
++              has_fas_errors = (fd_errors & FD_CTRL_FAERR) &&
++                               !!(dpaa2_fd_get_frc(fd) & DPAA2_FD_FRC_FASV);
++              if (net_ratelimit())
++                      netdev_dbg(priv->net_dev, "RX frame FD err: %08x\n",
++                                 fd_errors);
++      }
++
++      /* check frame errors in the FAS field */
++      if (has_fas_errors) {
++              fas = dpaa2_get_fas(vaddr, false);
++              status = le32_to_cpu(fas->status);
++              if (net_ratelimit())
++                      netdev_dbg(priv->net_dev, "Rx frame FAS err: 0x%08x\n",
++                                 status & DPAA2_FAS_RX_ERR_MASK);
++      }
++      free_rx_fd(priv, fd, vaddr);
++
++      percpu_stats = this_cpu_ptr(priv->percpu_stats);
++      percpu_stats->rx_errors++;
++      ch->buf_count--;
++}
++#endif
++
+ /* Consume all frames pull-dequeued into the store. This is the simplest way to
+  * make sure we don't accidentally issue another volatile dequeue which would
+  * overwrite (leak) frames already in the store.
+@@ -2351,6 +2398,7 @@ static void set_fq_affinity(struct dpaa2
+               fq = &priv->fq[i];
+               switch (fq->type) {
+               case DPAA2_RX_FQ:
++              case DPAA2_RX_ERR_FQ:
+                       fq->target_cpu = rx_cpu;
+                       rx_cpu = cpumask_next(rx_cpu, &priv->dpio_cpumask);
+                       if (rx_cpu >= nr_cpu_ids)
+@@ -2394,6 +2442,12 @@ static void setup_fqs(struct dpaa2_eth_p
+               }
+       }
++#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE
++      /* We have exactly one Rx error queue per DPNI */
++      priv->fq[priv->num_fqs].type = DPAA2_RX_ERR_FQ;
++      priv->fq[priv->num_fqs++].consume = dpaa2_eth_rx_err;
++#endif
++
+       /* For each FQ, decide on which core to process incoming frames */
+       set_fq_affinity(priv);
+ }
+@@ -2939,6 +2993,40 @@ static int setup_tx_flow(struct dpaa2_et
+       return 0;
+ }
++#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE
++static int setup_rx_err_flow(struct dpaa2_eth_priv *priv,
++                           struct dpaa2_eth_fq *fq)
++{
++      struct device *dev = priv->net_dev->dev.parent;
++      struct dpni_queue q = { { 0 } };
++      struct dpni_queue_id qid;
++      u8 q_opt = DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST;
++      int err;
++
++      err = dpni_get_queue(priv->mc_io, 0, priv->mc_token,
++                           DPNI_QUEUE_RX_ERR, 0, 0, &q, &qid);
++      if (err) {
++              dev_err(dev, "dpni_get_queue() failed (%d)\n", err);
++              return err;
++      }
++
++      fq->fqid = qid.fqid;
++
++      q.destination.id = fq->channel->dpcon_id;
++      q.destination.type = DPNI_DEST_DPCON;
++      q.destination.priority = 1;
++      q.user_context = (u64)fq;
++      err = dpni_set_queue(priv->mc_io, 0, priv->mc_token,
++                           DPNI_QUEUE_RX_ERR, 0, 0, q_opt, &q);
++      if (err) {
++              dev_err(dev, "dpni_set_queue() failed (%d)\n", err);
++              return err;
++      }
++
++      return 0;
++}
++#endif
++
+ /* Supported header fields for Rx hash distribution key */
+ static const struct dpaa2_eth_dist_fields dist_fields[] = {
+       {
+@@ -3308,7 +3396,11 @@ static int bind_dpni(struct dpaa2_eth_pr
+       /* Configure handling of error frames */
+       err_cfg.errors = DPAA2_FAS_RX_ERR_MASK;
+       err_cfg.set_frame_annotation = 1;
++#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE
++      err_cfg.error_action = DPNI_ERROR_ACTION_SEND_TO_ERROR_QUEUE;
++#else
+       err_cfg.error_action = DPNI_ERROR_ACTION_DISCARD;
++#endif
+       err = dpni_set_errors_behavior(priv->mc_io, 0, priv->mc_token,
+                                      &err_cfg);
+       if (err) {
+@@ -3325,6 +3417,11 @@ static int bind_dpni(struct dpaa2_eth_pr
+               case DPAA2_TX_CONF_FQ:
+                       err = setup_tx_flow(priv, &priv->fq[i]);
+                       break;
++#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE
++              case DPAA2_RX_ERR_FQ:
++                      err = setup_rx_err_flow(priv, &priv->fq[i]);
++                      break;
++#endif
+               default:
+                       dev_err(dev, "Invalid FQ type %d\n", priv->fq[i].type);
+                       return -EINVAL;
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -318,8 +318,10 @@ struct dpaa2_eth_ch_stats {
+ #define DPAA2_ETH_MAX_RX_QUEUES               \
+       (DPAA2_ETH_MAX_RX_QUEUES_PER_TC * DPAA2_ETH_MAX_TCS)
+ #define DPAA2_ETH_MAX_TX_QUEUES               16
++#define DPAA2_ETH_MAX_RX_ERR_QUEUES   1
+ #define DPAA2_ETH_MAX_QUEUES          (DPAA2_ETH_MAX_RX_QUEUES + \
+-                                      DPAA2_ETH_MAX_TX_QUEUES)
++                                      DPAA2_ETH_MAX_TX_QUEUES + \
++                                      DPAA2_ETH_MAX_RX_ERR_QUEUES)
+ #define DPAA2_ETH_MAX_NETDEV_QUEUES   \
+       (DPAA2_ETH_MAX_TX_QUEUES * DPAA2_ETH_MAX_TCS)
+@@ -328,6 +330,7 @@ struct dpaa2_eth_ch_stats {
+ enum dpaa2_eth_fq_type {
+       DPAA2_RX_FQ = 0,
+       DPAA2_TX_CONF_FQ,
++      DPAA2_RX_ERR_FQ
+ };
+ struct dpaa2_eth_priv;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0206-dpaa2-eth-Add-API-for-counters-reset.patch b/target/linux/layerscape/patches-5.4/701-net-0206-dpaa2-eth-Add-API-for-counters-reset.patch
new file mode 100644 (file)
index 0000000..30f9208
--- /dev/null
@@ -0,0 +1,70 @@
+From 991c03df1b0543ed02a5d4e803ac8fa9d993fb8e Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Tue, 9 May 2017 16:36:39 +0300
+Subject: [PATCH] dpaa2-eth: Add API for counters reset
+
+Add DPNI object API function for resetting interface
+hardware counters.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h |  1 +
+ drivers/net/ethernet/freescale/dpaa2/dpni.c     | 23 +++++++++++++++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpni.h     |  4 ++++
+ 3 files changed, 28 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
+@@ -68,6 +68,7 @@
+ #define DPNI_CMDID_CLR_FS_ENT                         DPNI_CMD(0x246)
+ #define DPNI_CMDID_GET_STATISTICS                     DPNI_CMD(0x25D)
++#define DPNI_CMDID_RESET_STATISTICS                   DPNI_CMD(0x25E)
+ #define DPNI_CMDID_GET_QUEUE                          DPNI_CMD(0x25F)
+ #define DPNI_CMDID_SET_QUEUE                          DPNI_CMD(0x260)
+ #define DPNI_CMDID_GET_TAILDROP                               DPNI_CMD(0x261)
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c
+@@ -1582,6 +1582,29 @@ int dpni_get_statistics(struct fsl_mc_io
+ }
+ /**
++ * dpni_reset_statistics() - Clears DPNI statistics
++ * @mc_io:            Pointer to MC portal's I/O object
++ * @cmd_flags:                Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:            Token of DPNI object
++ *
++ * Return:  '0' on Success; Error code otherwise.
++ */
++int dpni_reset_statistics(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token)
++{
++      struct fsl_mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPNI_CMDID_RESET_STATISTICS,
++                                        cmd_flags,
++                                        token);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
+  * dpni_set_taildrop() - Set taildrop per queue or TC
+  * @mc_io:    Pointer to MC portal's I/O object
+  * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h
+@@ -496,6 +496,10 @@ int dpni_get_statistics(struct fsl_mc_io
+                       u8                      page,
+                       union dpni_statistics   *stat);
++int dpni_reset_statistics(struct fsl_mc_io *mc_io,
++                        u32 cmd_flags,
++                        u16 token);
++
+ /**
+  * Enable auto-negotiation
+  */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0207-dpaa2-eth-Add-reset-controls-for-debugfs-stats.patch b/target/linux/layerscape/patches-5.4/701-net-0207-dpaa2-eth-Add-reset-controls-for-debugfs-stats.patch
new file mode 100644 (file)
index 0000000..01d7b01
--- /dev/null
@@ -0,0 +1,92 @@
+From aa80ddbb30e9ffd75e2dcaa58abf6383a5520942 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Wed, 13 Feb 2019 12:23:41 +0200
+Subject: [PATCH] dpaa2-eth: Add reset controls for debugfs stats
+
+Allow the user to reset statistics counters through debugfs entries.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ .../ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c   | 64 ++++++++++++++++++++++
+ 1 file changed, 64 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c
+@@ -167,6 +167,62 @@ static const struct file_operations dpaa
+       .release = single_release,
+ };
++static ssize_t dpaa2_dbg_reset_write(struct file *file, const char __user *buf,
++                                   size_t count, loff_t *offset)
++{
++      struct dpaa2_eth_priv *priv = file->private_data;
++      struct rtnl_link_stats64 *percpu_stats;
++      struct dpaa2_eth_drv_stats *percpu_extras;
++      struct dpaa2_eth_fq *fq;
++      struct dpaa2_eth_channel *ch;
++      int i;
++
++      for_each_online_cpu(i) {
++              percpu_stats = per_cpu_ptr(priv->percpu_stats, i);
++              memset(percpu_stats, 0, sizeof(*percpu_stats));
++
++              percpu_extras = per_cpu_ptr(priv->percpu_extras, i);
++              memset(percpu_extras, 0, sizeof(*percpu_extras));
++      }
++
++      for (i = 0; i < priv->num_fqs; i++) {
++              fq = &priv->fq[i];
++              memset(&fq->stats, 0, sizeof(fq->stats));
++      }
++
++      for (i = 0; i < priv->num_channels; i++) {
++              ch = priv->channel[i];
++              memset(&ch->stats, 0, sizeof(ch->stats));
++      }
++
++      return count;
++}
++
++static const struct file_operations dpaa2_dbg_reset_ops = {
++      .open = simple_open,
++      .write = dpaa2_dbg_reset_write,
++};
++
++static ssize_t dpaa2_dbg_reset_mc_write(struct file *file,
++                                      const char __user *buf,
++                                      size_t count, loff_t *offset)
++{
++      struct dpaa2_eth_priv *priv = file->private_data;
++      int err;
++
++      err = dpni_reset_statistics(priv->mc_io, 0, priv->mc_token);
++      if (err)
++              netdev_err(priv->net_dev,
++                         "dpni_reset_statistics() failed %d\n", err);
++
++      return count;
++}
++
++static const struct file_operations dpaa2_dbg_reset_mc_ops = {
++      .open = simple_open,
++      .write = dpaa2_dbg_reset_mc_write,
++};
++
+ void dpaa2_dbg_add(struct dpaa2_eth_priv *priv)
+ {
+       struct dentry *dir;
+@@ -183,6 +239,14 @@ void dpaa2_dbg_add(struct dpaa2_eth_priv
+       /* per-fq stats file */
+       debugfs_create_file("ch_stats", 0444, dir, priv, &dpaa2_dbg_ch_ops);
++
++      /* reset stats */
++      debugfs_create_file("reset_stats", 0200, dir, priv,
++                          &dpaa2_dbg_reset_ops);
++
++      /* reset MC stats */
++      debugfs_create_file("reset_mc_stats", 0222, dir, priv,
++                          &dpaa2_dbg_reset_mc_ops);
+ }
+ void dpaa2_dbg_remove(struct dpaa2_eth_priv *priv)
diff --git a/target/linux/layerscape/patches-5.4/701-net-0208-dpaa2-eth-Add-channel-stat.patch b/target/linux/layerscape/patches-5.4/701-net-0208-dpaa2-eth-Add-channel-stat.patch
new file mode 100644 (file)
index 0000000..074078e
--- /dev/null
@@ -0,0 +1,73 @@
+From 5a43b0405561fb6feffb7042493b58014ac27a4d Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Tue, 12 Feb 2019 22:05:16 +0200
+Subject: [PATCH] dpaa2-eth: Add channel stat
+
+Compute average number of frames processed for each CDAN
+received on a channel and print it in the detailed channel
+stats.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c | 8 +++++---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c         | 1 +
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h         | 2 ++
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c     | 2 +-
+ 4 files changed, 9 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c
+@@ -132,16 +132,18 @@ static int dpaa2_dbg_ch_show(struct seq_
+       int i;
+       seq_printf(file, "Channel stats for %s:\n", priv->net_dev->name);
+-      seq_printf(file, "%s%16s%16s%16s%16s\n",
+-                 "CHID", "CPU", "Deq busy", "CDANs", "Buf count");
++      seq_printf(file, "%s%16s%16s%16s%16s%16s%16s\n",
++                 "CHID", "CPU", "Deq busy", "Frames", "CDANs", "Avg Frm/CDAN", "Buf count");
+       for (i = 0; i < priv->num_channels; i++) {
+               ch = priv->channel[i];
+-              seq_printf(file, "%4d%16d%16llu%16llu%16d\n",
++              seq_printf(file, "%4d%16d%16llu%16llu%16llu%16llu%16d\n",
+                          ch->ch_id,
+                          ch->nctx.desired_cpu,
+                          ch->stats.dequeue_portal_busy,
++                         ch->stats.frames,
+                          ch->stats.cdan,
++                         ch->stats.frames / ch->stats.cdan,
+                          ch->buf_count);
+       }
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -540,6 +540,7 @@ static int consume_frames(struct dpaa2_e
+               return 0;
+       fq->stats.frames += cleaned;
++      ch->stats.frames += cleaned;
+       /* A dequeue operation only pulls frames from a single queue
+        * into the store. Return the frame queue as an out param.
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -310,6 +310,8 @@ struct dpaa2_eth_ch_stats {
+       __u64 xdp_tx;
+       __u64 xdp_tx_err;
+       __u64 xdp_redirect;
++      /* Must be last, does not show up in ethtool stats */
++      __u64 frames;
+ };
+ /* Maximum number of queues associated with a DPNI */
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
+@@ -234,7 +234,7 @@ static void dpaa2_eth_get_ethtool_stats(
+       /* Per-channel stats */
+       for (k = 0; k < priv->num_channels; k++) {
+               ch_stats = &priv->channel[k]->stats;
+-              for (j = 0; j < sizeof(*ch_stats) / sizeof(__u64); j++)
++              for (j = 0; j < sizeof(*ch_stats) / sizeof(__u64) - 1; j++)
+                       *((__u64 *)data + i + j) += *((__u64 *)ch_stats + j);
+       }
+       i += j;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0209-dpaa2-eth-Update-dpni_set_tx_shaping-cmd-to-v2.patch b/target/linux/layerscape/patches-5.4/701-net-0209-dpaa2-eth-Update-dpni_set_tx_shaping-cmd-to-v2.patch
new file mode 100644 (file)
index 0000000..23deef6
--- /dev/null
@@ -0,0 +1,147 @@
+From 81efe5fd6fac6db454ccccb1e6c280419d0885c4 Mon Sep 17 00:00:00 2001
+From: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+Date: Mon, 13 Nov 2017 17:29:21 +0200
+Subject: [PATCH] dpaa2-eth: Update dpni_set_tx_shaping cmd to v2
+
+Support dual rate shaping (committed, excess) and the coupled parameter.
+
+Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c |  5 +++--
+ drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h  | 18 ++++++++++++++----
+ drivers/net/ethernet/freescale/dpaa2/dpni.c      | 23 ++++++++++++++++-------
+ drivers/net/ethernet/freescale/dpaa2/dpni.h      | 10 ++++++----
+ 4 files changed, 39 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -3888,7 +3888,7 @@ static ssize_t dpaa2_eth_write_tx_shapin
+ {
+       int err, items;
+       struct dpaa2_eth_priv *priv = netdev_priv(to_net_dev(dev));
+-      struct dpni_tx_shaping_cfg scfg;
++      struct dpni_tx_shaping_cfg scfg, ercfg = {0};
+       items = sscanf(buf, "%u %hu", &scfg.rate_limit, &scfg.max_burst_size);
+       if (items != 2) {
+@@ -3902,7 +3902,8 @@ static ssize_t dpaa2_eth_write_tx_shapin
+               return -EINVAL;
+       }
+-      err = dpni_set_tx_shaping(priv->mc_io, 0, priv->mc_token, &scfg);
++      err = dpni_set_tx_shaping(priv->mc_io, 0, priv->mc_token, &scfg,
++                                &ercfg, 0);
+       if (err) {
+               dev_err(dev, "dpni_set_tx_shaping() failed\n");
+               return -EPERM;
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
+@@ -11,9 +11,11 @@
+ #define DPNI_VER_MAJOR                                7
+ #define DPNI_VER_MINOR                                0
+ #define DPNI_CMD_BASE_VERSION                 1
++#define DPNI_CMD_2ND_VERSION                  2
+ #define DPNI_CMD_ID_OFFSET                    4
+ #define DPNI_CMD(id)  (((id) << DPNI_CMD_ID_OFFSET) | DPNI_CMD_BASE_VERSION)
++#define DPNI_CMD_V2(id)       (((id) << DPNI_CMD_ID_OFFSET) | DPNI_CMD_2ND_VERSION)
+ #define DPNI_CMDID_OPEN                                       DPNI_CMD(0x801)
+ #define DPNI_CMDID_CLOSE                              DPNI_CMD(0x800)
+@@ -45,7 +47,7 @@
+ #define DPNI_CMDID_SET_MAX_FRAME_LENGTH                       DPNI_CMD(0x216)
+ #define DPNI_CMDID_GET_MAX_FRAME_LENGTH                       DPNI_CMD(0x217)
+ #define DPNI_CMDID_SET_LINK_CFG                               DPNI_CMD(0x21A)
+-#define DPNI_CMDID_SET_TX_SHAPING                     DPNI_CMD(0x21B)
++#define DPNI_CMDID_SET_TX_SHAPING                     DPNI_CMD_V2(0x21B)
+ #define DPNI_CMDID_SET_MCAST_PROMISC                  DPNI_CMD(0x220)
+ #define DPNI_CMDID_GET_MCAST_PROMISC                  DPNI_CMD(0x221)
+@@ -316,12 +318,20 @@ struct dpni_rsp_get_link_state {
+       __le64 options;
+ };
++#define DPNI_COUPLED_SHIFT    0
++#define DPNI_COUPLED_SIZE     1
++
+ struct dpni_cmd_set_tx_shaping {
+       /* cmd word 0 */
+-      __le16 max_burst_size;
+-      __le16 pad[3];
++      __le16 tx_cr_max_burst_size;
++      __le16 tx_er_max_burst_size;
++      __le32 pad;
+       /* cmd word 1 */
+-      __le32 rate_limit;
++      __le32 tx_cr_rate_limit;
++      __le32 tx_er_rate_limit;
++      /* cmd word 2 */
++      /* from LSB: coupled:1 */
++      u8 coupled;
+ };
+ struct dpni_cmd_set_max_frame_length {
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c
+@@ -927,17 +927,21 @@ int dpni_get_link_state(struct fsl_mc_io
+ /**
+  * dpni_set_tx_shaping() - Set the transmit shaping
+- * @mc_io:    Pointer to MC portal's I/O object
+- * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
+- * @token:    Token of DPNI object
+- * @tx_shaper:        Tx shaping configuration
++ * @mc_io:            Pointer to MC portal's I/O object
++ * @cmd_flags:                Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:            Token of DPNI object
++ * @tx_cr_shaper:     TX committed rate shaping configuration
++ * @tx_er_shaper:     TX excess rate shaping configuration
++ * @coupled:          Committed and excess rate shapers are coupled
+  *
+  * Return:    '0' on Success; Error code otherwise.
+  */
+ int dpni_set_tx_shaping(struct fsl_mc_io *mc_io,
+                       u32 cmd_flags,
+                       u16 token,
+-                      const struct dpni_tx_shaping_cfg *tx_shaper)
++                      const struct dpni_tx_shaping_cfg *tx_cr_shaper,
++                      const struct dpni_tx_shaping_cfg *tx_er_shaper,
++                      int coupled)
+ {
+       struct fsl_mc_command cmd = { 0 };
+       struct dpni_cmd_set_tx_shaping *cmd_params;
+@@ -947,8 +951,13 @@ int dpni_set_tx_shaping(struct fsl_mc_io
+                                         cmd_flags,
+                                         token);
+       cmd_params = (struct dpni_cmd_set_tx_shaping *)cmd.params;
+-      cmd_params->max_burst_size = cpu_to_le16(tx_shaper->max_burst_size);
+-      cmd_params->rate_limit = cpu_to_le32(tx_shaper->rate_limit);
++      cmd_params->tx_cr_max_burst_size =
++                              cpu_to_le16(tx_cr_shaper->max_burst_size);
++      cmd_params->tx_er_max_burst_size =
++                              cpu_to_le16(tx_er_shaper->max_burst_size);
++      cmd_params->tx_cr_rate_limit = cpu_to_le32(tx_cr_shaper->rate_limit);
++      cmd_params->tx_er_rate_limit = cpu_to_le32(tx_er_shaper->rate_limit);
++      dpni_set_field(cmd_params->coupled, COUPLED, coupled);
+       /* send command to mc*/
+       return mc_send_command(mc_io, &cmd);
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h
+@@ -569,10 +569,12 @@ struct dpni_tx_shaping_cfg {
+       u16     max_burst_size;
+ };
+-int dpni_set_tx_shaping(struct fsl_mc_io                      *mc_io,
+-                      u32                                     cmd_flags,
+-                      u16                                     token,
+-                      const struct dpni_tx_shaping_cfg        *tx_shaper);
++int dpni_set_tx_shaping(struct fsl_mc_io *mc_io,
++                      u32 cmd_flags,
++                      u16 token,
++                      const struct dpni_tx_shaping_cfg *tx_cr_shaper,
++                      const struct dpni_tx_shaping_cfg *tx_er_shaper,
++                      int coupled);
+ int dpni_set_max_frame_length(struct fsl_mc_io        *mc_io,
+                             u32               cmd_flags,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0210-dpaa2-eth-Add-dpni_set_tx_priorities-API.patch b/target/linux/layerscape/patches-5.4/701-net-0210-dpaa2-eth-Add-dpni_set_tx_priorities-API.patch
new file mode 100644 (file)
index 0000000..4ce16b6
--- /dev/null
@@ -0,0 +1,158 @@
+From 97308e74e2ae781d37437137686965395b94327b Mon Sep 17 00:00:00 2001
+From: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+Date: Mon, 16 Oct 2017 15:27:55 +0000
+Subject: [PATCH] dpaa2-eth: Add dpni_set_tx_priorities API
+
+Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h | 19 ++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpni.c     | 49 +++++++++++++++++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpni.h     | 44 ++++++++++++++++++++++
+ 3 files changed, 112 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
+@@ -69,6 +69,7 @@
+ #define DPNI_CMDID_REMOVE_FS_ENT                      DPNI_CMD(0x245)
+ #define DPNI_CMDID_CLR_FS_ENT                         DPNI_CMD(0x246)
++#define DPNI_CMDID_SET_TX_PRIORITIES                  DPNI_CMD_V2(0x250)
+ #define DPNI_CMDID_GET_STATISTICS                     DPNI_CMD(0x25D)
+ #define DPNI_CMDID_RESET_STATISTICS                   DPNI_CMD(0x25E)
+ #define DPNI_CMDID_GET_QUEUE                          DPNI_CMD(0x25F)
+@@ -393,6 +394,24 @@ struct dpni_cmd_clear_mac_filters {
+       u8 flags;
+ };
++#define DPNI_SEPARATE_GRP_SHIFT 0
++#define DPNI_SEPARATE_GRP_SIZE  1
++#define DPNI_MODE_1_SHIFT             0
++#define DPNI_MODE_1_SIZE              4
++#define DPNI_MODE_2_SHIFT             4
++#define DPNI_MODE_2_SIZE              4
++
++struct dpni_cmd_set_tx_priorities {
++      __le16 flags;
++      u8 prio_group_A;
++      u8 prio_group_B;
++      __le32 pad0;
++      u8 modes[4];
++      __le32 pad1;
++      __le64 pad2;
++      __le16 delta_bandwidth[8];
++};
++
+ #define DPNI_DIST_MODE_SHIFT          0
+ #define DPNI_DIST_MODE_SIZE           4
+ #define DPNI_MISS_ACTION_SHIFT                4
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c
+@@ -1355,6 +1355,55 @@ int dpni_clear_mac_filters(struct fsl_mc
+ }
+ /**
++ * dpni_set_tx_priorities() - Set transmission TC priority configuration
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPNI object
++ * @cfg:      Transmission selection configuration
++ *
++ * warning:   Allowed only when DPNI is disabled
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpni_set_tx_priorities(struct fsl_mc_io *mc_io,
++                         u32 cmd_flags,
++                         u16 token,
++                         const struct dpni_tx_priorities_cfg *cfg)
++{
++      struct dpni_cmd_set_tx_priorities *cmd_params;
++      struct fsl_mc_command cmd = { 0 };
++      int i;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_PRIORITIES,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpni_cmd_set_tx_priorities *)cmd.params;
++      dpni_set_field(cmd_params->flags,
++                     SEPARATE_GRP,
++                     cfg->separate_groups);
++      cmd_params->prio_group_A = cfg->prio_group_A;
++      cmd_params->prio_group_B = cfg->prio_group_B;
++
++      for (i = 0; i + 1 < DPNI_MAX_TC; i += 2) {
++              dpni_set_field(cmd_params->modes[i / 2],
++                             MODE_1,
++                             cfg->tc_sched[i].mode);
++              dpni_set_field(cmd_params->modes[i / 2],
++                             MODE_2,
++                             cfg->tc_sched[i + 1].mode);
++      }
++
++      for (i = 0; i < DPNI_MAX_TC; i++) {
++              cmd_params->delta_bandwidth[i] =
++                              cpu_to_le16(cfg->tc_sched[i].delta_bandwidth);
++      }
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
+  * dpni_set_rx_tc_dist() - Set Rx traffic class distribution configuration
+  * @mc_io:    Pointer to MC portal's I/O object
+  * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h
+@@ -677,6 +677,50 @@ int dpni_prepare_key_cfg(const struct dp
+                        u8 *key_cfg_buf);
+ /**
++ * enum dpni_tx_schedule_mode - DPNI Tx scheduling mode
++ * @DPNI_TX_SCHED_STRICT_PRIORITY: strict priority
++ * @DPNI_TX_SCHED_WEIGHTED_A: weighted based scheduling in group A
++ * @DPNI_TX_SCHED_WEIGHTED_B: weighted based scheduling in group B
++ */
++enum dpni_tx_schedule_mode {
++      DPNI_TX_SCHED_STRICT_PRIORITY = 0,
++      DPNI_TX_SCHED_WEIGHTED_A,
++      DPNI_TX_SCHED_WEIGHTED_B,
++};
++
++/**
++ * struct dpni_tx_schedule_cfg - Structure representing Tx scheduling conf
++ * @mode:             Scheduling mode
++ * @delta_bandwidth:  Bandwidth represented in weights from 100 to 10000;
++ *    not applicable for 'strict-priority' mode;
++ */
++struct dpni_tx_schedule_cfg {
++      enum dpni_tx_schedule_mode mode;
++      u16 delta_bandwidth;
++};
++
++/**
++ * struct dpni_tx_priorities_cfg - Structure representing transmission
++ *                                    priorities for DPNI TCs
++ * @tc_sched: An array of traffic-classes
++ * @prio_group_A: Priority of group A
++ * @prio_group_B: Priority of group B
++ * @separate_groups: Treat A and B groups as separate
++ * @ceetm_ch_idx: ceetm channel index to apply the changes
++ */
++struct dpni_tx_priorities_cfg {
++      struct dpni_tx_schedule_cfg tc_sched[DPNI_MAX_TC];
++      u8 prio_group_A;
++      u8 prio_group_B;
++      u8 separate_groups;
++};
++
++int dpni_set_tx_priorities(struct fsl_mc_io *mc_io,
++                         u32 cmd_flags,
++                         u16 token,
++                         const struct dpni_tx_priorities_cfg *cfg);
++
++/**
+  * struct dpni_rx_tc_dist_cfg - Rx traffic class distribution configuration
+  * @dist_size: Set the distribution size;
+  *    supported values: 1,2,3,4,6,7,8,12,14,16,24,28,32,48,56,64,96,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0211-dpaa2-eth-Update-dpni_get_statistics.patch b/target/linux/layerscape/patches-5.4/701-net-0211-dpaa2-eth-Update-dpni_get_statistics.patch
new file mode 100644 (file)
index 0000000..f04674a
--- /dev/null
@@ -0,0 +1,95 @@
+From fa4e59c0fe5e6e2fd8ba29cdcaa03988b3d301c6 Mon Sep 17 00:00:00 2001
+From: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+Date: Mon, 23 Oct 2017 08:31:25 +0000
+Subject: [PATCH] dpaa2-eth: Update dpni_get_statistics
+
+Statistics struct now contains an addditional page, with CEETM stats.
+Also update the cmd version, and the call where it's used.
+
+Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c     | 2 +-
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c | 2 +-
+ drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h      | 3 ++-
+ drivers/net/ethernet/freescale/dpaa2/dpni.c          | 4 ++++
+ drivers/net/ethernet/freescale/dpaa2/dpni.h          | 1 +
+ 5 files changed, 9 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -1479,7 +1479,7 @@ static void wait_for_egress_fq_empty(str
+               goto out;
+       do {
+-              err = dpni_get_statistics(priv->mc_io, 0, priv->mc_token, 6,
++              err = dpni_get_statistics(priv->mc_io, 0, priv->mc_token, 6, 0,
+                                         &stats);
+               if (err)
+                       goto out;
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
+@@ -211,7 +211,7 @@ static void dpaa2_eth_get_ethtool_stats(
+               if (j == 4 || j == 5)
+                       continue;
+               err = dpni_get_statistics(priv->mc_io, 0, priv->mc_token,
+-                                        j, &dpni_stats);
++                                        j, 0, &dpni_stats);
+               if (err == -EINVAL)
+                       /* Older firmware versions don't support all pages */
+                       memset(&dpni_stats, 0, sizeof(dpni_stats));
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
+@@ -70,7 +70,7 @@
+ #define DPNI_CMDID_CLR_FS_ENT                         DPNI_CMD(0x246)
+ #define DPNI_CMDID_SET_TX_PRIORITIES                  DPNI_CMD_V2(0x250)
+-#define DPNI_CMDID_GET_STATISTICS                     DPNI_CMD(0x25D)
++#define DPNI_CMDID_GET_STATISTICS                     DPNI_CMD_V2(0x25D)
+ #define DPNI_CMDID_RESET_STATISTICS                   DPNI_CMD(0x25E)
+ #define DPNI_CMDID_GET_QUEUE                          DPNI_CMD(0x25F)
+ #define DPNI_CMDID_SET_QUEUE                          DPNI_CMD(0x260)
+@@ -287,6 +287,7 @@ struct dpni_rsp_get_tx_data_offset {
+ struct dpni_cmd_get_statistics {
+       u8 page_number;
++      u8 param;
+ };
+ struct dpni_rsp_get_statistics {
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c
+@@ -1604,6 +1604,8 @@ int dpni_get_queue(struct fsl_mc_io *mc_
+  * @token:    Token of DPNI object
+  * @page:     Selects the statistics page to retrieve, see
+  *            DPNI_GET_STATISTICS output. Pages are numbered 0 to 6.
++ * @param:    Custom parameter for some pages used to select a certain
++ *            statistic source, for example the TC.
+  * @stat:     Structure containing the statistics
+  *
+  * Return:    '0' on Success; Error code otherwise.
+@@ -1612,6 +1614,7 @@ int dpni_get_statistics(struct fsl_mc_io
+                       u32 cmd_flags,
+                       u16 token,
+                       u8 page,
++                      u8 param,
+                       union dpni_statistics *stat)
+ {
+       struct fsl_mc_command cmd = { 0 };
+@@ -1625,6 +1628,7 @@ int dpni_get_statistics(struct fsl_mc_io
+                                         token);
+       cmd_params = (struct dpni_cmd_get_statistics *)cmd.params;
+       cmd_params->page_number = page;
++      cmd_params->param = param;
+       /* send command to mc */
+       err = mc_send_command(mc_io, &cmd);
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h
+@@ -494,6 +494,7 @@ int dpni_get_statistics(struct fsl_mc_io
+                       u32                     cmd_flags,
+                       u16                     token,
+                       u8                      page,
++                      u8                      param,
+                       union dpni_statistics   *stat);
+ int dpni_reset_statistics(struct fsl_mc_io *mc_io,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0212-dpaa2-eth-Add-API-for-ceetm_id-tc-in-set-congestion.patch b/target/linux/layerscape/patches-5.4/701-net-0212-dpaa2-eth-Add-API-for-ceetm_id-tc-in-set-congestion.patch
new file mode 100644 (file)
index 0000000..719f4c0
--- /dev/null
@@ -0,0 +1,64 @@
+From 551cd6add98fb3bde24ee8e4ffa76aec9fd9d40c Mon Sep 17 00:00:00 2001
+From: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+Date: Mon, 2 Oct 2017 14:45:56 +0000
+Subject: [PATCH] dpaa2-eth: Add API for ceetm_id + tc in set congestion
+
+Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpni.c | 15 ++++++++++++---
+ drivers/net/ethernet/freescale/dpaa2/dpni.h |  6 ++++++
+ 2 files changed, 18 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c
+@@ -1448,7 +1448,10 @@ int dpni_set_rx_tc_dist(struct fsl_mc_io
+  * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
+  * @token:    Token of DPNI object
+  * @qtype:    Type of queue - Rx, Tx and Tx confirm types are supported
+- * @tc_id:    Traffic class selection (0-7)
++ * @tc_id:    bits 7-4 contain ceetm channel index (valid only for TX);
++ *            bits 3-0 contain traffic class.
++ *            Use macro DPNI_BUILD_CH_TC() to build correct value for
++ *            tc_id parameter
+  * @cfg:      Congestion notification configuration
+  *
+  * Return:    '0' on Success; error code otherwise.
+@@ -1674,7 +1677,10 @@ int dpni_reset_statistics(struct fsl_mc_
+  * @cg_point: Congestion point
+  * @q_type:   Queue type on which the taildrop is configured.
+  *            Only Rx queues are supported for now
+- * @tc:               Traffic class to apply this taildrop to
++ * @tc:               bits 7-4 contain ceetm channel index (valid only for TX);
++ *            bits 3-0 contain traffic class.
++ *            Use macro DPNI_BUILD_CH_TC() to build correct value for
++ *            tc parameter.
+  * @q_index:  Index of the queue if the DPNI supports multiple queues for
+  *            traffic distribution. Ignored if CONGESTION_POINT is not 0.
+  * @taildrop: Taildrop structure
+@@ -1718,7 +1724,10 @@ int dpni_set_taildrop(struct fsl_mc_io *
+  * @cg_point: Congestion point
+  * @q_type:   Queue type on which the taildrop is configured.
+  *            Only Rx queues are supported for now
+- * @tc:               Traffic class to apply this taildrop to
++ * @tc:               bits 7-4 contain ceetm channel index (valid only for TX);
++ *            bits 3-0 contain traffic class.
++ *            Use macro DPNI_BUILD_CH_TC() to build correct value for
++ *            tc parameter.
+  * @q_index:  Index of the queue if the DPNI supports multiple queues for
+  *            traffic distribution. Ignored if CONGESTION_POINT is not 0.
+  * @taildrop: Taildrop structure
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h
+@@ -996,6 +996,12 @@ struct dpni_congestion_notification_cfg
+       u16 notification_mode;
+ };
++/** Compose TC parameter for function dpni_set_congestion_notification()
++ * and dpni_get_congestion_notification().
++ */
++#define DPNI_BUILD_CH_TC(ceetm_ch_idx, tc) \
++      ((((ceetm_ch_idx) & 0x0F) << 4) | ((tc) & 0x0F))
++
+ int dpni_set_congestion_notification(
+                       struct fsl_mc_io *mc_io,
+                       u32 cmd_flags,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0213-dpaa2-eth-Add-CEETM-qdisc-support.patch b/target/linux/layerscape/patches-5.4/701-net-0213-dpaa2-eth-Add-CEETM-qdisc-support.patch
new file mode 100644 (file)
index 0000000..3e586e4
--- /dev/null
@@ -0,0 +1,1619 @@
+From 68622c8bb029f9fd4c83ffa3bd979fa62a3599d0 Mon Sep 17 00:00:00 2001
+From: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+Date: Mon, 13 Nov 2017 17:26:13 +0200
+Subject: [PATCH] dpaa2-eth: Add CEETM qdisc support
+
+Features include:
+- dual rate shaping support
+- per-channel shaping and classification
+- strict / weighted scheduling among num_tc classes
+- TD enabled for configured class queues
+- prio class (leaf) firmware statistics support
+- weights normalized based on max
+- tc filters based classification
+
+Only 1 CEETM ch supported, only channel shaping supported.
+
+Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/Kconfig       |    7 +
+ drivers/net/ethernet/freescale/dpaa2/Makefile      |    1 +
+ .../net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.c | 1219 ++++++++++++++++++++
+ .../net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.h |  207 ++++
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c   |   53 +-
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h   |    7 +
+ 6 files changed, 1482 insertions(+), 12 deletions(-)
+ create mode 100644 drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.c
+ create mode 100644 drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.h
+
+--- a/drivers/net/ethernet/freescale/dpaa2/Kconfig
++++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig
+@@ -25,6 +25,13 @@ config FSL_DPAA2_ETH_USE_ERR_QUEUE
+         in hardware).
+         This may impact performance, recommended for debugging
+         purposes only.
++
++config FSL_DPAA2_ETH_CEETM
++      depends on NET_SCHED
++      bool "DPAA2 Ethernet CEETM QoS"
++      default n
++      help
++        Enable QoS offloading support through the CEETM hardware block.
+ endif
+ config FSL_DPAA2_PTP_CLOCK
+--- a/drivers/net/ethernet/freescale/dpaa2/Makefile
++++ b/drivers/net/ethernet/freescale/dpaa2/Makefile
+@@ -8,6 +8,7 @@ obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK)      += fsl
+ fsl-dpaa2-eth-objs    := dpaa2-eth.o dpaa2-ethtool.o dpni.o
+ fsl-dpaa2-eth-${CONFIG_DEBUG_FS} += dpaa2-eth-debugfs.o
++fsl-dpaa2-eth-${CONFIG_FSL_DPAA2_ETH_CEETM} += dpaa2-eth-ceetm.o
+ fsl-dpaa2-ptp-objs    := dpaa2-ptp.o dprtc.o
+ # Needed by the tracing framework
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.c
+@@ -0,0 +1,1219 @@
++/* Copyright 2017 NXP
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++
++#include "dpaa2-eth-ceetm.h"
++#include "dpaa2-eth.h"
++
++#define DPAA2_CEETM_DESCRIPTION "FSL DPAA2 CEETM qdisc"
++/* Conversion formula from userspace passed Bps to expected Mbit */
++#define dpaa2_eth_bps_to_mbit(rate) (rate >> 17)
++
++static const struct nla_policy dpaa2_ceetm_policy[DPAA2_CEETM_TCA_MAX] = {
++      [DPAA2_CEETM_TCA_COPT] = { .len = sizeof(struct dpaa2_ceetm_tc_copt) },
++      [DPAA2_CEETM_TCA_QOPS] = { .len = sizeof(struct dpaa2_ceetm_tc_qopt) },
++};
++
++struct Qdisc_ops dpaa2_ceetm_qdisc_ops;
++
++static inline int dpaa2_eth_set_ch_shaping(struct dpaa2_eth_priv *priv,
++                                         struct dpni_tx_shaping_cfg *scfg,
++                                         struct dpni_tx_shaping_cfg *ecfg,
++                                         int coupled, int ch_id)
++{
++      int err = 0;
++
++      netdev_dbg(priv->net_dev, "%s: ch_id %d rate %d mbps\n", __func__,
++                 ch_id, scfg->rate_limit);
++      err = dpni_set_tx_shaping(priv->mc_io, 0, priv->mc_token, scfg,
++                                ecfg, coupled);
++      if (err)
++              netdev_err(priv->net_dev, "dpni_set_tx_shaping err\n");
++
++      return err;
++}
++
++static inline int dpaa2_eth_reset_ch_shaping(struct dpaa2_eth_priv *priv,
++                                           int ch_id)
++{
++      struct dpni_tx_shaping_cfg cfg = { 0 };
++
++      return dpaa2_eth_set_ch_shaping(priv, &cfg, &cfg, 0, ch_id);
++}
++
++static inline int
++dpaa2_eth_update_shaping_cfg(struct net_device *dev,
++                           struct dpaa2_ceetm_shaping_cfg cfg,
++                           struct dpni_tx_shaping_cfg *scfg,
++                           struct dpni_tx_shaping_cfg *ecfg)
++{
++      scfg->rate_limit = dpaa2_eth_bps_to_mbit(cfg.cir);
++      ecfg->rate_limit = dpaa2_eth_bps_to_mbit(cfg.eir);
++
++      if (cfg.cbs > DPAA2_ETH_MAX_BURST_SIZE) {
++              netdev_err(dev, "Committed burst size must be under %d\n",
++                         DPAA2_ETH_MAX_BURST_SIZE);
++              return -EINVAL;
++      }
++
++      scfg->max_burst_size = cfg.cbs;
++
++      if (cfg.ebs > DPAA2_ETH_MAX_BURST_SIZE) {
++              netdev_err(dev, "Excess burst size must be under %d\n",
++                         DPAA2_ETH_MAX_BURST_SIZE);
++              return -EINVAL;
++      }
++
++      ecfg->max_burst_size = cfg.ebs;
++
++      if ((!cfg.cir || !cfg.eir) && cfg.coupled) {
++              netdev_err(dev, "Coupling can be set when both CIR and EIR are finite\n");
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++enum update_tx_prio {
++      DPAA2_ETH_ADD_CQ,
++      DPAA2_ETH_DEL_CQ,
++};
++
++/* Normalize weights based on max passed value */
++static inline int dpaa2_eth_normalize_tx_prio(struct dpaa2_ceetm_qdisc *priv)
++{
++      struct dpni_tx_schedule_cfg *sched_cfg;
++      struct dpaa2_ceetm_class *cl;
++      u32 qpri;
++      u16 weight_max = 0, increment;
++      int i;
++
++      /* Check the boundaries of the provided values */
++      for (i = 0; i < priv->clhash.hashsize; i++)
++              hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode)
++                      weight_max = (weight_max == 0 ? cl->prio.weight :
++                                   (weight_max < cl->prio.weight ?
++                                    cl->prio.weight : weight_max));
++
++      /* If there are no elements, there's nothing to do */
++      if (weight_max == 0)
++              return 0;
++
++      increment = (DPAA2_CEETM_MAX_WEIGHT - DPAA2_CEETM_MIN_WEIGHT) /
++                  weight_max;
++
++      for (i = 0; i < priv->clhash.hashsize; i++) {
++              hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode) {
++                      if (cl->prio.mode == STRICT_PRIORITY)
++                              continue;
++
++                      qpri = cl->prio.qpri;
++                      sched_cfg = &priv->prio.tx_prio_cfg.tc_sched[qpri];
++
++                      sched_cfg->delta_bandwidth =
++                              DPAA2_CEETM_MIN_WEIGHT +
++                              (cl->prio.weight * increment);
++
++                      pr_debug("%s: Normalized CQ qpri %d weight to %d\n",
++                               __func__, qpri, sched_cfg->delta_bandwidth);
++              }
++      }
++
++      return 0;
++}
++
++static inline int dpaa2_eth_update_tx_prio(struct dpaa2_eth_priv *priv,
++                                         struct dpaa2_ceetm_class *cl,
++                                         enum update_tx_prio type)
++{
++      struct dpaa2_ceetm_qdisc *sch = qdisc_priv(cl->parent);
++      struct dpni_tx_schedule_cfg *sched_cfg;
++      struct dpni_taildrop td = {0};
++      u8 ch_id = 0, tc_id = 0;
++      u32 qpri = 0;
++      int err = 0;
++
++      qpri = cl->prio.qpri;
++      tc_id = DPNI_BUILD_CH_TC(ch_id, qpri);
++
++      switch (type) {
++      case DPAA2_ETH_ADD_CQ:
++              /* Enable taildrop */
++              td.enable = 1;
++              td.units = DPNI_CONGESTION_UNIT_FRAMES;
++              td.threshold = DPAA2_CEETM_TD_THRESHOLD;
++              err = dpni_set_taildrop(priv->mc_io, 0, priv->mc_token,
++                                      DPNI_CP_GROUP, DPNI_QUEUE_TX, tc_id,
++                                      0, &td);
++              if (err) {
++                      netdev_err(priv->net_dev, "Error enabling Tx taildrop %d\n",
++                                 err);
++                      return err;
++              }
++              break;
++      case DPAA2_ETH_DEL_CQ:
++              /* Disable taildrop */
++              td.enable = 0;
++              err = dpni_set_taildrop(priv->mc_io, 0, priv->mc_token,
++                                      DPNI_CP_GROUP, DPNI_QUEUE_TX, tc_id,
++                                      0, &td);
++              if (err) {
++                      netdev_err(priv->net_dev, "Error disabling Tx taildrop %d\n",
++                                 err);
++                      return err;
++              }
++              break;
++      }
++
++      /* We can zero out the structure in the tx_prio_conf array */
++      if (type == DPAA2_ETH_DEL_CQ) {
++              sched_cfg = &sch->prio.tx_prio_cfg.tc_sched[qpri];
++              memset(sched_cfg, 0, sizeof(*sched_cfg));
++      }
++
++      /* Normalize priorities */
++      err = dpaa2_eth_normalize_tx_prio(sch);
++
++      /* Debug print goes here */
++      print_hex_dump_debug("tx_prio: ", DUMP_PREFIX_OFFSET, 16, 1,
++                           &sch->prio.tx_prio_cfg,
++                           sizeof(sch->prio.tx_prio_cfg), 0);
++
++      /* Call dpni_set_tx_priorities for the entire prio qdisc */
++      err = dpni_set_tx_priorities(priv->mc_io, 0, priv->mc_token,
++                                   &sch->prio.tx_prio_cfg);
++      if (err)
++              netdev_err(priv->net_dev, "dpni_set_tx_priorities err %d\n",
++                         err);
++
++      return err;
++}
++
++static void dpaa2_eth_ceetm_enable(struct dpaa2_eth_priv *priv)
++{
++      priv->ceetm_en = true;
++}
++
++static void dpaa2_eth_ceetm_disable(struct dpaa2_eth_priv *priv)
++{
++      priv->ceetm_en = false;
++}
++
++/* Find class in qdisc hash table using given handle */
++static inline struct dpaa2_ceetm_class *dpaa2_ceetm_find(u32 handle,
++                                                       struct Qdisc *sch)
++{
++      struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
++      struct Qdisc_class_common *clc;
++
++      pr_debug(KBUILD_BASENAME " : %s : find class %X in qdisc %X\n",
++               __func__, handle, sch->handle);
++
++      clc = qdisc_class_find(&priv->clhash, handle);
++      return clc ? container_of(clc, struct dpaa2_ceetm_class, common) : NULL;
++}
++
++/* Insert a class in the qdisc's class hash */
++static void dpaa2_ceetm_link_class(struct Qdisc *sch,
++                                 struct Qdisc_class_hash *clhash,
++                                 struct Qdisc_class_common *common)
++{
++      sch_tree_lock(sch);
++      qdisc_class_hash_insert(clhash, common);
++      sch_tree_unlock(sch);
++      qdisc_class_hash_grow(sch, clhash);
++}
++
++/* Destroy a ceetm class */
++static void dpaa2_ceetm_cls_destroy(struct Qdisc *sch,
++                                  struct dpaa2_ceetm_class *cl)
++{
++      struct net_device *dev = qdisc_dev(sch);
++      struct dpaa2_eth_priv *priv = netdev_priv(dev);
++
++      if (!cl)
++              return;
++
++      pr_debug(KBUILD_BASENAME " : %s : destroy class %X from under %X\n",
++               __func__, cl->common.classid, sch->handle);
++
++      /* Recurse into child first */
++      if (cl->child) {
++              qdisc_put(cl->child);
++              cl->child = NULL;
++      }
++
++      switch (cl->type) {
++      case CEETM_ROOT:
++              if (dpaa2_eth_reset_ch_shaping(priv, cl->root.ch_id))
++                      netdev_err(dev, "Error resetting channel shaping\n");
++
++              break;
++
++      case CEETM_PRIO:
++              if (dpaa2_eth_update_tx_prio(priv, cl, DPAA2_ETH_DEL_CQ))
++                      netdev_err(dev, "Error resetting tx_priorities\n");
++
++              if (cl->prio.cstats)
++                      free_percpu(cl->prio.cstats);
++
++              break;
++      }
++
++      tcf_block_put(cl->block);
++      kfree(cl);
++}
++
++/* Destroy a ceetm qdisc */
++static void dpaa2_ceetm_destroy(struct Qdisc *sch)
++{
++      unsigned int i;
++      struct hlist_node *next;
++      struct dpaa2_ceetm_class *cl;
++      struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
++      struct net_device *dev = qdisc_dev(sch);
++      struct dpaa2_eth_priv *priv_eth = netdev_priv(dev);
++
++      pr_debug(KBUILD_BASENAME " : %s : destroy qdisc %X\n",
++               __func__, sch->handle);
++
++      /* All filters need to be removed before destroying the classes */
++      tcf_block_put(priv->block);
++
++      for (i = 0; i < priv->clhash.hashsize; i++) {
++              hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode)
++                      tcf_block_put(cl->block);
++      }
++
++      for (i = 0; i < priv->clhash.hashsize; i++) {
++              hlist_for_each_entry_safe(cl, next, &priv->clhash.hash[i],
++                                        common.hnode)
++                      dpaa2_ceetm_cls_destroy(sch, cl);
++      }
++
++      qdisc_class_hash_destroy(&priv->clhash);
++
++      switch (priv->type) {
++      case CEETM_ROOT:
++              dpaa2_eth_ceetm_disable(priv_eth);
++
++              if (priv->root.qstats)
++                      free_percpu(priv->root.qstats);
++
++              if (!priv->root.qdiscs)
++                      break;
++
++              /* Destroy the pfifo qdiscs in case they haven't been attached
++               * to the netdev queues yet.
++               */
++              for (i = 0; i < dev->num_tx_queues; i++)
++                      if (priv->root.qdiscs[i])
++                              qdisc_put(priv->root.qdiscs[i]);
++
++              kfree(priv->root.qdiscs);
++              break;
++
++      case CEETM_PRIO:
++              if (priv->prio.parent)
++                      priv->prio.parent->child = NULL;
++              break;
++      }
++}
++
++static int dpaa2_ceetm_dump(struct Qdisc *sch, struct sk_buff *skb)
++{
++      struct Qdisc *qdisc;
++      unsigned int ntx, i;
++      struct nlattr *nest;
++      struct dpaa2_ceetm_tc_qopt qopt;
++      struct dpaa2_ceetm_qdisc_stats *qstats;
++      struct net_device *dev = qdisc_dev(sch);
++      struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
++
++      pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
++
++      sch_tree_lock(sch);
++      memset(&qopt, 0, sizeof(qopt));
++      qopt.type = priv->type;
++      qopt.shaped = priv->shaped;
++
++      switch (priv->type) {
++      case CEETM_ROOT:
++              /* Gather statistics from the underlying pfifo qdiscs */
++              sch->q.qlen = 0;
++              memset(&sch->bstats, 0, sizeof(sch->bstats));
++              memset(&sch->qstats, 0, sizeof(sch->qstats));
++
++              for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
++                      qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping;
++                      sch->q.qlen             += qdisc->q.qlen;
++                      sch->bstats.bytes       += qdisc->bstats.bytes;
++                      sch->bstats.packets     += qdisc->bstats.packets;
++                      sch->qstats.qlen        += qdisc->qstats.qlen;
++                      sch->qstats.backlog     += qdisc->qstats.backlog;
++                      sch->qstats.drops       += qdisc->qstats.drops;
++                      sch->qstats.requeues    += qdisc->qstats.requeues;
++                      sch->qstats.overlimits  += qdisc->qstats.overlimits;
++              }
++
++              for_each_online_cpu(i) {
++                      qstats = per_cpu_ptr(priv->root.qstats, i);
++                      sch->qstats.drops += qstats->drops;
++              }
++
++              break;
++
++      case CEETM_PRIO:
++              qopt.prio_group_A = priv->prio.tx_prio_cfg.prio_group_A;
++              qopt.prio_group_B = priv->prio.tx_prio_cfg.prio_group_B;
++              qopt.separate_groups = priv->prio.tx_prio_cfg.separate_groups;
++              break;
++
++      default:
++              pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
++              sch_tree_unlock(sch);
++              return -EINVAL;
++      }
++
++      nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
++      if (!nest)
++              goto nla_put_failure;
++      if (nla_put(skb, DPAA2_CEETM_TCA_QOPS, sizeof(qopt), &qopt))
++              goto nla_put_failure;
++      nla_nest_end(skb, nest);
++
++      sch_tree_unlock(sch);
++      return skb->len;
++
++nla_put_failure:
++      sch_tree_unlock(sch);
++      nla_nest_cancel(skb, nest);
++      return -EMSGSIZE;
++}
++
++static int dpaa2_ceetm_change_prio(struct Qdisc *sch,
++                                 struct dpaa2_ceetm_qdisc *priv,
++                                 struct dpaa2_ceetm_tc_qopt *qopt)
++{
++      /* TODO: Once LX2 support is added */
++      /* priv->shaped = parent_cl->shaped; */
++      priv->prio.tx_prio_cfg.prio_group_A = qopt->prio_group_A;
++      priv->prio.tx_prio_cfg.prio_group_B = qopt->prio_group_B;
++      priv->prio.tx_prio_cfg.separate_groups = qopt->separate_groups;
++
++      return 0;
++}
++
++/* Edit a ceetm qdisc */
++static int dpaa2_ceetm_change(struct Qdisc *sch, struct nlattr *opt,
++                            struct netlink_ext_ack *extack)
++{
++      struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
++      struct nlattr *tb[DPAA2_CEETM_TCA_QOPS + 1];
++      struct dpaa2_ceetm_tc_qopt *qopt;
++      int err;
++
++      pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
++
++      err = nla_parse_nested_deprecated(tb, DPAA2_CEETM_TCA_QOPS, opt,
++                                        dpaa2_ceetm_policy, extack);
++      if (err < 0) {
++              pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
++                     "nla_parse_nested_deprecated");
++              return err;
++      }
++
++      if (!tb[DPAA2_CEETM_TCA_QOPS]) {
++              pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
++                     "tb");
++              return -EINVAL;
++      }
++
++      if (TC_H_MIN(sch->handle)) {
++              pr_err("CEETM: a qdisc should not have a minor\n");
++              return -EINVAL;
++      }
++
++      qopt = nla_data(tb[DPAA2_CEETM_TCA_QOPS]);
++
++      if (priv->type != qopt->type) {
++              pr_err("CEETM: qdisc %X is not of the provided type\n",
++                     sch->handle);
++              return -EINVAL;
++      }
++
++      switch (priv->type) {
++      case CEETM_PRIO:
++              err = dpaa2_ceetm_change_prio(sch, priv, qopt);
++              break;
++      default:
++              pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
++              err = -EINVAL;
++      }
++
++      return err;
++}
++
++/* Configure a root ceetm qdisc */
++static int dpaa2_ceetm_init_root(struct Qdisc *sch,
++                               struct dpaa2_ceetm_qdisc *priv,
++                               struct dpaa2_ceetm_tc_qopt *qopt,
++                               struct netlink_ext_ack *extack)
++{
++      struct net_device *dev = qdisc_dev(sch);
++      struct dpaa2_eth_priv *priv_eth = netdev_priv(dev);
++      struct netdev_queue *dev_queue;
++      unsigned int i, parent_id;
++      struct Qdisc *qdisc;
++
++      pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
++
++      /* Validate inputs */
++      if (sch->parent != TC_H_ROOT) {
++              pr_err("CEETM: a root ceetm qdisc must be root\n");
++              return -EINVAL;
++      }
++
++      /* Pre-allocate underlying pfifo qdiscs.
++       *
++       * We want to offload shaping and scheduling decisions to the hardware.
++       * The pfifo qdiscs will be attached to the netdev queues and will
++       * guide the traffic from the IP stack down to the driver with minimum
++       * interference.
++       *
++       * The CEETM qdiscs and classes will be crossed when the traffic
++       * reaches the driver.
++       */
++      priv->root.qdiscs = kcalloc(dev->num_tx_queues,
++                                  sizeof(priv->root.qdiscs[0]),
++                                  GFP_KERNEL);
++      if (!priv->root.qdiscs)
++              return -ENOMEM;
++
++      for (i = 0; i < dev->num_tx_queues; i++) {
++              dev_queue = netdev_get_tx_queue(dev, i);
++              parent_id = TC_H_MAKE(TC_H_MAJ(sch->handle),
++                                    TC_H_MIN(i + PFIFO_MIN_OFFSET));
++
++              qdisc = qdisc_create_dflt(dev_queue, &pfifo_qdisc_ops,
++                                        parent_id, extack);
++              if (!qdisc)
++                      return -ENOMEM;
++
++              priv->root.qdiscs[i] = qdisc;
++              qdisc->flags |= TCQ_F_ONETXQUEUE;
++      }
++
++      sch->flags |= TCQ_F_MQROOT;
++
++      priv->root.qstats = alloc_percpu(struct dpaa2_ceetm_qdisc_stats);
++      if (!priv->root.qstats) {
++              pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n",
++                     __func__);
++              return -ENOMEM;
++      }
++
++      dpaa2_eth_ceetm_enable(priv_eth);
++      return 0;
++}
++
++/* Configure a prio ceetm qdisc */
++static int dpaa2_ceetm_init_prio(struct Qdisc *sch,
++                               struct dpaa2_ceetm_qdisc *priv,
++                               struct dpaa2_ceetm_tc_qopt *qopt)
++{
++      struct net_device *dev = qdisc_dev(sch);
++      struct dpaa2_ceetm_class *parent_cl;
++      struct Qdisc *parent_qdisc;
++
++      pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
++
++      if (sch->parent == TC_H_ROOT) {
++              pr_err("CEETM: a prio ceetm qdisc can not be root\n");
++              return -EINVAL;
++      }
++
++      parent_qdisc = qdisc_lookup(dev, TC_H_MAJ(sch->parent));
++      if (strcmp(parent_qdisc->ops->id, dpaa2_ceetm_qdisc_ops.id)) {
++              pr_err("CEETM: a ceetm qdisc can not be attached to other qdisc/class types\n");
++              return -EINVAL;
++      }
++
++      /* Obtain the parent root ceetm_class */
++      parent_cl = dpaa2_ceetm_find(sch->parent, parent_qdisc);
++
++      if (!parent_cl || parent_cl->type != CEETM_ROOT) {
++              pr_err("CEETM: a prio ceetm qdiscs can be added only under a root ceetm class\n");
++              return -EINVAL;
++      }
++
++      priv->prio.parent = parent_cl;
++      parent_cl->child = sch;
++
++      return dpaa2_ceetm_change_prio(sch, priv, qopt);
++}
++
++/* Configure a generic ceetm qdisc */
++static int dpaa2_ceetm_init(struct Qdisc *sch, struct nlattr *opt,
++                          struct netlink_ext_ack *extack)
++{
++      struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
++      struct net_device *dev = qdisc_dev(sch);
++      struct nlattr *tb[DPAA2_CEETM_TCA_QOPS + 1];
++      struct dpaa2_ceetm_tc_qopt *qopt;
++      int err;
++
++      pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
++
++      if (!netif_is_multiqueue(dev))
++              return -EOPNOTSUPP;
++
++      err = tcf_block_get(&priv->block, &priv->filter_list, sch, extack);
++      if (err) {
++              pr_err("CEETM: unable to get tcf_block\n");
++              return err;
++      }
++
++      if (!opt) {
++              pr_err(KBUILD_BASENAME " : %s : tc error - opt = NULL\n",
++                     __func__);
++              return -EINVAL;
++      }
++
++      err = nla_parse_nested_deprecated(tb, DPAA2_CEETM_TCA_QOPS, opt,
++                                        dpaa2_ceetm_policy, extack);
++      if (err < 0) {
++              pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
++                     "nla_parse_nested_deprecated");
++              return err;
++      }
++
++      if (!tb[DPAA2_CEETM_TCA_QOPS]) {
++              pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
++                     "tb");
++              return -EINVAL;
++      }
++
++      if (TC_H_MIN(sch->handle)) {
++              pr_err("CEETM: a qdisc should not have a minor\n");
++              return -EINVAL;
++      }
++
++      qopt = nla_data(tb[DPAA2_CEETM_TCA_QOPS]);
++
++      /* Initialize the class hash list. Each qdisc has its own class hash */
++      err = qdisc_class_hash_init(&priv->clhash);
++      if (err < 0) {
++              pr_err(KBUILD_BASENAME " : %s : qdisc_class_hash_init failed\n",
++                     __func__);
++              return err;
++      }
++
++      priv->type = qopt->type;
++      priv->shaped = qopt->shaped;
++
++      switch (priv->type) {
++      case CEETM_ROOT:
++              err = dpaa2_ceetm_init_root(sch, priv, qopt, extack);
++              break;
++      case CEETM_PRIO:
++              err = dpaa2_ceetm_init_prio(sch, priv, qopt);
++              break;
++      default:
++              pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
++              /* Note: dpaa2_ceetm_destroy() will be called by our caller */
++              err = -EINVAL;
++      }
++
++      return err;
++}
++
++/* Attach the underlying pfifo qdiscs */
++static void dpaa2_ceetm_attach(struct Qdisc *sch)
++{
++      struct net_device *dev = qdisc_dev(sch);
++      struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
++      struct Qdisc *qdisc, *old_qdisc;
++      unsigned int i;
++
++      pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
++
++      for (i = 0; i < dev->num_tx_queues; i++) {
++              qdisc = priv->root.qdiscs[i];
++              old_qdisc = dev_graft_qdisc(qdisc->dev_queue, qdisc);
++              if (old_qdisc)
++                      qdisc_put(old_qdisc);
++      }
++
++      /* Remove the references to the pfifo qdiscs since the kernel will
++       * destroy them when needed. No cleanup from our part is required from
++       * this point on.
++       */
++      kfree(priv->root.qdiscs);
++      priv->root.qdiscs = NULL;
++}
++
++static unsigned long dpaa2_ceetm_cls_find(struct Qdisc *sch, u32 classid)
++{
++      struct dpaa2_ceetm_class *cl;
++
++      pr_debug(KBUILD_BASENAME " : %s : classid %X from qdisc %X\n",
++               __func__, classid, sch->handle);
++      cl = dpaa2_ceetm_find(classid, sch);
++
++      return (unsigned long)cl;
++}
++
++static int dpaa2_ceetm_cls_change_root(struct dpaa2_ceetm_class *cl,
++                                     struct dpaa2_ceetm_tc_copt *copt,
++                                     struct net_device *dev)
++{
++      struct dpaa2_eth_priv *priv = netdev_priv(dev);
++      struct dpni_tx_shaping_cfg scfg = { 0 }, ecfg = { 0 };
++      int err = 0;
++
++      pr_debug(KBUILD_BASENAME " : %s : class %X\n", __func__,
++               cl->common.classid);
++
++      if (!cl->shaped)
++              return 0;
++
++      if (dpaa2_eth_update_shaping_cfg(dev, copt->shaping_cfg,
++                                       &scfg, &ecfg))
++              return -EINVAL;
++
++      err = dpaa2_eth_set_ch_shaping(priv, &scfg, &ecfg,
++                                     copt->shaping_cfg.coupled,
++                                     cl->root.ch_id);
++      if (err)
++              return err;
++
++      memcpy(&cl->root.shaping_cfg, &copt->shaping_cfg,
++             sizeof(struct dpaa2_ceetm_shaping_cfg));
++
++      return err;
++}
++
++static int dpaa2_ceetm_cls_change_prio(struct dpaa2_ceetm_class *cl,
++                                     struct dpaa2_ceetm_tc_copt *copt,
++                                     struct net_device *dev)
++{
++      struct dpaa2_ceetm_qdisc *sch = qdisc_priv(cl->parent);
++      struct dpni_tx_schedule_cfg *sched_cfg;
++      struct dpaa2_eth_priv *priv = netdev_priv(dev);
++      int err;
++
++      pr_debug(KBUILD_BASENAME " : %s : class %X mode %d weight %d\n",
++               __func__, cl->common.classid, copt->mode, copt->weight);
++
++      if (!cl->prio.cstats) {
++              cl->prio.cstats = alloc_percpu(struct dpaa2_ceetm_class_stats);
++              if (!cl->prio.cstats) {
++                      pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n",
++                             __func__);
++                      return -ENOMEM;
++              }
++      }
++
++      cl->prio.mode = copt->mode;
++      cl->prio.weight = copt->weight;
++
++      sched_cfg = &sch->prio.tx_prio_cfg.tc_sched[cl->prio.qpri];
++
++      switch (copt->mode) {
++      case STRICT_PRIORITY:
++              sched_cfg->mode = DPNI_TX_SCHED_STRICT_PRIORITY;
++              break;
++      case WEIGHTED_A:
++              sched_cfg->mode = DPNI_TX_SCHED_WEIGHTED_A;
++              break;
++      case WEIGHTED_B:
++              sched_cfg->mode = DPNI_TX_SCHED_WEIGHTED_B;
++              break;
++      }
++
++      err = dpaa2_eth_update_tx_prio(priv, cl, DPAA2_ETH_ADD_CQ);
++
++      return err;
++}
++
++/* Add a new ceetm class */
++static int dpaa2_ceetm_cls_add(struct Qdisc *sch, u32 classid,
++                             struct dpaa2_ceetm_tc_copt *copt,
++                             unsigned long *arg,
++                             struct netlink_ext_ack *extack)
++{
++      struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
++      struct net_device *dev = qdisc_dev(sch);
++      struct dpaa2_eth_priv *priv_eth = netdev_priv(dev);
++      struct dpaa2_ceetm_class *cl;
++      int err;
++
++      if (copt->type == CEETM_ROOT &&
++          priv->clhash.hashelems == dpaa2_eth_ch_count(priv_eth)) {
++              pr_err("CEETM: only %d channel%s per DPNI allowed, sorry\n",
++                     dpaa2_eth_ch_count(priv_eth),
++                     dpaa2_eth_ch_count(priv_eth) == 1 ? "" : "s");
++              return -EINVAL;
++      }
++
++      if (copt->type == CEETM_PRIO &&
++          priv->clhash.hashelems == dpaa2_eth_tc_count(priv_eth)) {
++              pr_err("CEETM: only %d queue%s per channel allowed, sorry\n",
++                     dpaa2_eth_tc_count(priv_eth),
++                     dpaa2_eth_tc_count(priv_eth) == 1 ? "" : "s");
++              return -EINVAL;
++      }
++
++      cl = kzalloc(sizeof(*cl), GFP_KERNEL);
++      if (!cl)
++              return -ENOMEM;
++
++      err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack);
++      if (err) {
++              pr_err("%s: Unable to set new root class\n", __func__);
++              goto out_free;
++      }
++
++      cl->common.classid = classid;
++      cl->parent = sch;
++      cl->child = NULL;
++
++      /* Add class handle in Qdisc */
++      dpaa2_ceetm_link_class(sch, &priv->clhash, &cl->common);
++
++      cl->shaped = copt->shaped;
++      cl->type = copt->type;
++
++      /* Claim a CEETM channel / tc - DPAA2. will assume transition from
++       * classid to qdid/qpri, starting from qdid / qpri 0
++       */
++      switch (copt->type) {
++      case CEETM_ROOT:
++              cl->root.ch_id = classid - sch->handle - 1;
++              err = dpaa2_ceetm_cls_change_root(cl, copt, dev);
++              break;
++      case CEETM_PRIO:
++              cl->prio.qpri = classid - sch->handle - 1;
++              err = dpaa2_ceetm_cls_change_prio(cl, copt, dev);
++              break;
++      }
++
++      if (err) {
++              pr_err("%s: Unable to set new %s class\n", __func__,
++                     (copt->type == CEETM_ROOT ? "root" : "prio"));
++              goto out_free;
++      }
++
++      switch (copt->type) {
++      case CEETM_ROOT:
++              pr_debug(KBUILD_BASENAME " : %s : configured root class %X associated with channel qdid %d\n",
++                       __func__, classid, cl->root.ch_id);
++              break;
++      case CEETM_PRIO:
++              pr_debug(KBUILD_BASENAME " : %s : configured prio class %X associated with queue qpri %d\n",
++                       __func__, classid, cl->prio.qpri);
++              break;
++      }
++
++      *arg = (unsigned long)cl;
++      return 0;
++
++out_free:
++      kfree(cl);
++      return err;
++}
++
++/* Add or configure a ceetm class */
++static int dpaa2_ceetm_cls_change(struct Qdisc *sch, u32 classid, u32 parentid,
++                                struct nlattr **tca, unsigned long *arg,
++                                struct netlink_ext_ack *extack)
++{
++      struct dpaa2_ceetm_qdisc *priv;
++      struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)*arg;
++      struct nlattr *opt = tca[TCA_OPTIONS];
++      struct nlattr *tb[DPAA2_CEETM_TCA_MAX];
++      struct dpaa2_ceetm_tc_copt *copt;
++      struct net_device *dev = qdisc_dev(sch);
++      int err;
++
++      pr_debug(KBUILD_BASENAME " : %s : classid %X under qdisc %X\n",
++               __func__, classid, sch->handle);
++
++      if (strcmp(sch->ops->id, dpaa2_ceetm_qdisc_ops.id)) {
++              pr_err("CEETM: a ceetm class can not be attached to other qdisc/class types\n");
++              return -EINVAL;
++      }
++
++      priv = qdisc_priv(sch);
++
++      if (!opt) {
++              pr_err(KBUILD_BASENAME " : %s : tc error NULL opt\n", __func__);
++              return -EINVAL;
++      }
++
++      err = nla_parse_nested_deprecated(tb, DPAA2_CEETM_TCA_COPT, opt,
++                                        dpaa2_ceetm_policy, extack);
++      if (err < 0) {
++              pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
++                     "nla_parse_nested_deprecated");
++              return -EINVAL;
++      }
++
++      if (!tb[DPAA2_CEETM_TCA_COPT]) {
++              pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
++                     "tb");
++              return -EINVAL;
++      }
++
++      copt = nla_data(tb[DPAA2_CEETM_TCA_COPT]);
++
++      /* Configure an existing ceetm class */
++      if (cl) {
++              if (copt->type != cl->type) {
++                      pr_err("CEETM: class %X is not of the provided type\n",
++                             cl->common.classid);
++                      return -EINVAL;
++              }
++
++              switch (copt->type) {
++              case CEETM_ROOT:
++                      return dpaa2_ceetm_cls_change_root(cl, copt, dev);
++              case CEETM_PRIO:
++                      return dpaa2_ceetm_cls_change_prio(cl, copt, dev);
++
++              default:
++                      pr_err(KBUILD_BASENAME " : %s : invalid class\n",
++                             __func__);
++                      return -EINVAL;
++              }
++      }
++
++      return dpaa2_ceetm_cls_add(sch, classid, copt, arg, extack);
++}
++
++static void dpaa2_ceetm_cls_walk(struct Qdisc *sch, struct qdisc_walker *arg)
++{
++      struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
++      struct dpaa2_ceetm_class *cl;
++      unsigned int i;
++
++      pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
++
++      if (arg->stop)
++              return;
++
++      for (i = 0; i < priv->clhash.hashsize; i++) {
++              hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode) {
++                      if (arg->count < arg->skip) {
++                              arg->count++;
++                              continue;
++                      }
++                      if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
++                              arg->stop = 1;
++                              return;
++                      }
++                      arg->count++;
++              }
++      }
++}
++
++static int dpaa2_ceetm_cls_dump(struct Qdisc *sch, unsigned long arg,
++                              struct sk_buff *skb, struct tcmsg *tcm)
++{
++      struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
++      struct nlattr *nest;
++      struct dpaa2_ceetm_tc_copt copt;
++
++      pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
++               __func__, cl->common.classid, sch->handle);
++
++      sch_tree_lock(sch);
++
++      tcm->tcm_parent = ((struct Qdisc *)cl->parent)->handle;
++      tcm->tcm_handle = cl->common.classid;
++
++      memset(&copt, 0, sizeof(copt));
++
++      copt.shaped = cl->shaped;
++      copt.type = cl->type;
++
++      switch (cl->type) {
++      case CEETM_ROOT:
++              if (cl->child)
++                      tcm->tcm_info = cl->child->handle;
++
++              memcpy(&copt.shaping_cfg, &cl->root.shaping_cfg,
++                     sizeof(struct dpaa2_ceetm_shaping_cfg));
++
++              break;
++
++      case CEETM_PRIO:
++              if (cl->child)
++                      tcm->tcm_info = cl->child->handle;
++
++              copt.mode = cl->prio.mode;
++              copt.weight = cl->prio.weight;
++
++              break;
++      }
++
++      nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
++      if (!nest)
++              goto nla_put_failure;
++      if (nla_put(skb, DPAA2_CEETM_TCA_COPT, sizeof(copt), &copt))
++              goto nla_put_failure;
++      nla_nest_end(skb, nest);
++      sch_tree_unlock(sch);
++      return skb->len;
++
++nla_put_failure:
++      sch_tree_unlock(sch);
++      nla_nest_cancel(skb, nest);
++      return -EMSGSIZE;
++}
++
++static int dpaa2_ceetm_cls_delete(struct Qdisc *sch, unsigned long arg)
++{
++      struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
++      struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
++
++      pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
++               __func__, cl->common.classid, sch->handle);
++
++      sch_tree_lock(sch);
++      qdisc_class_hash_remove(&priv->clhash, &cl->common);
++      sch_tree_unlock(sch);
++      return 0;
++}
++
++/* Get the class' child qdisc, if any */
++static struct Qdisc *dpaa2_ceetm_cls_leaf(struct Qdisc *sch, unsigned long arg)
++{
++      struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
++
++      pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
++               __func__, cl->common.classid, sch->handle);
++
++      switch (cl->type) {
++      case CEETM_ROOT:
++      case CEETM_PRIO:
++              return cl->child;
++      }
++
++      return NULL;
++}
++
++static int dpaa2_ceetm_cls_graft(struct Qdisc *sch, unsigned long arg,
++                               struct Qdisc *new, struct Qdisc **old,
++                               struct netlink_ext_ack *extack)
++{
++      if (new && strcmp(new->ops->id, dpaa2_ceetm_qdisc_ops.id)) {
++              pr_err("CEETM: only ceetm qdiscs can be attached to ceetm classes\n");
++              return -EOPNOTSUPP;
++      }
++
++      return 0;
++}
++
++static int dpaa2_ceetm_cls_dump_stats(struct Qdisc *sch, unsigned long arg,
++                                    struct gnet_dump *d)
++{
++      struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
++      struct gnet_stats_basic_packed tmp_bstats;
++      struct dpaa2_ceetm_tc_xstats xstats;
++      union dpni_statistics dpni_stats;
++      struct net_device *dev = qdisc_dev(sch);
++      struct dpaa2_eth_priv *priv_eth = netdev_priv(dev);
++      u8 ch_id = 0;
++      int err;
++
++      memset(&xstats, 0, sizeof(xstats));
++      memset(&tmp_bstats, 0, sizeof(tmp_bstats));
++
++      if (cl->type == CEETM_ROOT)
++              return 0;
++
++      err = dpni_get_statistics(priv_eth->mc_io, 0, priv_eth->mc_token, 3,
++                                DPNI_BUILD_CH_TC(ch_id, cl->prio.qpri),
++                                &dpni_stats);
++      if (err)
++              netdev_warn(dev, "dpni_get_stats(%d) failed - %d\n", 3, err);
++
++      xstats.ceetm_dequeue_bytes = dpni_stats.page_3.egress_dequeue_bytes;
++      xstats.ceetm_dequeue_frames = dpni_stats.page_3.egress_dequeue_frames;
++      xstats.ceetm_reject_bytes = dpni_stats.page_3.egress_reject_bytes;
++      xstats.ceetm_reject_frames = dpni_stats.page_3.egress_reject_frames;
++
++      return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
++}
++
++static struct tcf_block *dpaa2_ceetm_tcf_block(struct Qdisc *sch,
++                                             unsigned long arg,
++                                             struct netlink_ext_ack *extack)
++{
++      struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
++      struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
++
++      pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
++               cl ? cl->common.classid : 0, sch->handle);
++      return cl ? cl->block : priv->block;
++}
++
++static unsigned long dpaa2_ceetm_tcf_bind(struct Qdisc *sch,
++                                        unsigned long parent,
++                                        u32 classid)
++{
++      struct dpaa2_ceetm_class *cl = dpaa2_ceetm_find(classid, sch);
++
++      pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
++               cl ? cl->common.classid : 0, sch->handle);
++      return (unsigned long)cl;
++}
++
++static void dpaa2_ceetm_tcf_unbind(struct Qdisc *sch, unsigned long arg)
++{
++      struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
++
++      pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
++               cl ? cl->common.classid : 0, sch->handle);
++}
++
++const struct Qdisc_class_ops dpaa2_ceetm_cls_ops = {
++      .graft          =       dpaa2_ceetm_cls_graft,
++      .leaf           =       dpaa2_ceetm_cls_leaf,
++      .find           =       dpaa2_ceetm_cls_find,
++      .change         =       dpaa2_ceetm_cls_change,
++      .delete         =       dpaa2_ceetm_cls_delete,
++      .walk           =       dpaa2_ceetm_cls_walk,
++      .tcf_block      =       dpaa2_ceetm_tcf_block,
++      .bind_tcf       =       dpaa2_ceetm_tcf_bind,
++      .unbind_tcf     =       dpaa2_ceetm_tcf_unbind,
++      .dump           =       dpaa2_ceetm_cls_dump,
++      .dump_stats     =       dpaa2_ceetm_cls_dump_stats,
++};
++
++struct Qdisc_ops dpaa2_ceetm_qdisc_ops __read_mostly = {
++      .id             =       "ceetm",
++      .priv_size      =       sizeof(struct dpaa2_ceetm_qdisc),
++      .cl_ops         =       &dpaa2_ceetm_cls_ops,
++      .init           =       dpaa2_ceetm_init,
++      .destroy        =       dpaa2_ceetm_destroy,
++      .change         =       dpaa2_ceetm_change,
++      .dump           =       dpaa2_ceetm_dump,
++      .attach         =       dpaa2_ceetm_attach,
++      .owner          =       THIS_MODULE,
++};
++
++/* Run the filters and classifiers attached to the qdisc on the provided skb */
++int dpaa2_ceetm_classify(struct sk_buff *skb, struct Qdisc *sch,
++                       int *qdid, u8 *qpri)
++{
++      struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
++      struct dpaa2_ceetm_class *cl = NULL;
++      struct tcf_result res;
++      struct tcf_proto *tcf;
++      int result;
++
++      tcf = rcu_dereference_bh(priv->filter_list);
++      while (tcf && (result = tcf_classify(skb, tcf, &res, false)) >= 0) {
++#ifdef CONFIG_NET_CLS_ACT
++              switch (result) {
++              case TC_ACT_QUEUED:
++              case TC_ACT_STOLEN:
++              case TC_ACT_SHOT:
++                      /* No valid class found due to action */
++                      return -1;
++              }
++#endif
++              cl = (void *)res.class;
++              if (!cl) {
++                      /* The filter leads to the qdisc */
++                      if (res.classid == sch->handle)
++                              return 0;
++
++                      cl = dpaa2_ceetm_find(res.classid, sch);
++                      /* The filter leads to an invalid class */
++                      if (!cl)
++                              break;
++              }
++
++              /* The class might have its own filters attached */
++              tcf = rcu_dereference_bh(cl->filter_list);
++      }
++
++      /* No valid class found */
++      if (!cl)
++              return 0;
++
++      switch (cl->type) {
++      case CEETM_ROOT:
++              *qdid = cl->root.ch_id;
++
++              /* The root class does not have a child prio qdisc */
++              if (!cl->child)
++                      return 0;
++
++              /* Run the prio qdisc classifiers */
++              return dpaa2_ceetm_classify(skb, cl->child, qdid, qpri);
++
++      case CEETM_PRIO:
++              *qpri = cl->prio.qpri;
++              break;
++      }
++
++      return 0;
++}
++
++int __init dpaa2_ceetm_register(void)
++{
++      int err = 0;
++
++      pr_debug(KBUILD_MODNAME ": " DPAA2_CEETM_DESCRIPTION "\n");
++
++      err = register_qdisc(&dpaa2_ceetm_qdisc_ops);
++      if (unlikely(err))
++              pr_err(KBUILD_MODNAME
++                     ": %s:%hu:%s(): register_qdisc() = %d\n",
++                     KBUILD_BASENAME ".c", __LINE__, __func__, err);
++
++      return err;
++}
++
++void __exit dpaa2_ceetm_unregister(void)
++{
++      pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
++               KBUILD_BASENAME ".c", __func__);
++
++      unregister_qdisc(&dpaa2_ceetm_qdisc_ops);
++}
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.h
+@@ -0,0 +1,207 @@
++/* Copyright 2017 NXP
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of Freescale Semiconductor nor the
++ *     names of its contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __DPAA2_ETH_CEETM_H
++#define __DPAA2_ETH_CEETM_H
++
++#include <net/pkt_sched.h>
++#include <net/pkt_cls.h>
++#include <net/netlink.h>
++
++#include "dpaa2-eth.h"
++
++/* For functional purposes, there are num_tx_queues pfifo qdiscs through which
++ * frames reach the driver. Their handles start from 1:21. Handles 1:1 to 1:20
++ * are reserved for the maximum 32 CEETM channels (majors and minors are in
++ * hex).
++ */
++#define PFIFO_MIN_OFFSET              0x21
++
++#define DPAA2_CEETM_MIN_WEIGHT                100
++#define DPAA2_CEETM_MAX_WEIGHT                24800
++
++#define DPAA2_CEETM_TD_THRESHOLD      1000
++
++enum wbfs_group_type {
++      WBFS_GRP_A,
++      WBFS_GRP_B,
++      WBFS_GRP_LARGE
++};
++
++enum {
++      DPAA2_CEETM_TCA_UNSPEC,
++      DPAA2_CEETM_TCA_COPT,
++      DPAA2_CEETM_TCA_QOPS,
++      DPAA2_CEETM_TCA_MAX,
++};
++
++/* CEETM configuration types */
++enum dpaa2_ceetm_type {
++      CEETM_ROOT = 1,
++      CEETM_PRIO,
++};
++
++enum {
++      STRICT_PRIORITY = 0,
++      WEIGHTED_A,
++      WEIGHTED_B,
++};
++
++struct dpaa2_ceetm_shaping_cfg {
++      __u64 cir; /* committed information rate */
++      __u64 eir; /* excess information rate */
++      __u16 cbs; /* committed burst size */
++      __u16 ebs; /* excess burst size */
++      __u8 coupled; /* shaper coupling */
++};
++
++extern const struct nla_policy ceetm_policy[DPAA2_CEETM_TCA_MAX];
++
++struct dpaa2_ceetm_class;
++struct dpaa2_ceetm_qdisc_stats;
++struct dpaa2_ceetm_class_stats;
++
++/* corresponds to CEETM shaping at LNI level */
++struct dpaa2_root_q {
++      struct Qdisc **qdiscs;
++      struct dpaa2_ceetm_qdisc_stats __percpu *qstats;
++};
++
++/* corresponds to the number of priorities a channel serves */
++struct dpaa2_prio_q {
++      struct dpaa2_ceetm_class *parent;
++      struct dpni_tx_priorities_cfg tx_prio_cfg;
++};
++
++struct dpaa2_ceetm_qdisc {
++      struct Qdisc_class_hash clhash;
++      struct tcf_proto *filter_list; /* qdisc attached filters */
++      struct tcf_block *block;
++
++      enum dpaa2_ceetm_type type; /* ROOT/PRIO */
++      bool shaped;
++      union {
++              struct dpaa2_root_q root;
++              struct dpaa2_prio_q prio;
++      };
++};
++
++/* CEETM Qdisc configuration parameters */
++struct dpaa2_ceetm_tc_qopt {
++      enum dpaa2_ceetm_type type;
++      __u16 shaped;
++      __u8 prio_group_A;
++      __u8 prio_group_B;
++      __u8 separate_groups;
++};
++
++/* root class - corresponds to a channel */
++struct dpaa2_root_c {
++      struct dpaa2_ceetm_shaping_cfg shaping_cfg;
++      u32 ch_id;
++};
++
++/* prio class - corresponds to a strict priority queue (group) */
++struct dpaa2_prio_c {
++      struct dpaa2_ceetm_class_stats __percpu *cstats;
++      u32 qpri;
++      u8 mode;
++      u16 weight;
++};
++
++struct dpaa2_ceetm_class {
++      struct Qdisc_class_common common;
++      struct tcf_proto *filter_list; /* class attached filters */
++      struct tcf_block *block;
++      struct Qdisc *parent;
++      struct Qdisc *child;
++
++      enum dpaa2_ceetm_type type; /* ROOT/PRIO */
++      bool shaped;
++      union {
++              struct dpaa2_root_c root;
++              struct dpaa2_prio_c prio;
++      };
++};
++
++/* CEETM Class configuration parameters */
++struct dpaa2_ceetm_tc_copt {
++      enum dpaa2_ceetm_type type;
++      struct dpaa2_ceetm_shaping_cfg shaping_cfg;
++      __u16 shaped;
++      __u8 mode;
++      __u16 weight;
++};
++
++/* CEETM stats */
++struct dpaa2_ceetm_qdisc_stats {
++      __u32 drops;
++};
++
++struct dpaa2_ceetm_class_stats {
++      /* Software counters */
++      struct gnet_stats_basic_packed bstats;
++      __u32 ern_drop_count;
++};
++
++struct dpaa2_ceetm_tc_xstats {
++      __u64 ceetm_dequeue_bytes;
++      __u64 ceetm_dequeue_frames;
++      __u64 ceetm_reject_bytes;
++      __u64 ceetm_reject_frames;
++};
++
++#ifdef CONFIG_FSL_DPAA2_ETH_CEETM
++int __init dpaa2_ceetm_register(void);
++void __exit dpaa2_ceetm_unregister(void);
++int dpaa2_ceetm_classify(struct sk_buff *skb, struct Qdisc *sch,
++                       int *qdid, u8 *qpri);
++#else
++static inline int dpaa2_ceetm_register(void)
++{
++      return 0;
++}
++
++static inline void dpaa2_ceetm_unregister(void) {}
++
++static inline int dpaa2_ceetm_classify(struct sk_buff *skb, struct Qdisc *sch,
++                                     int *qdid, u8 *qpri)
++{
++      return 0;
++}
++#endif
++
++static inline bool dpaa2_eth_ceetm_is_enabled(struct dpaa2_eth_priv *priv)
++{
++      return priv->ceetm_en;
++}
++
++#endif
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -18,6 +18,7 @@
+ #include <net/sock.h>
+ #include "dpaa2-eth.h"
++#include "dpaa2-eth-ceetm.h"
+ /* CREATE_TRACE_POINTS only needs to be defined once. Other dpa files
+  * using trace events only need to #include <trace/events/sched.h>
+@@ -816,7 +817,7 @@ static netdev_tx_t dpaa2_eth_tx(struct s
+       unsigned int needed_headroom;
+       u32 fd_len;
+       u8 prio = 0;
+-      int err, i;
++      int err, i, ch_id = 0;
+       percpu_stats = this_cpu_ptr(priv->percpu_stats);
+       percpu_extras = this_cpu_ptr(priv->percpu_extras);
+@@ -887,6 +888,15 @@ static netdev_tx_t dpaa2_eth_tx(struct s
+       }
+       fq = &priv->fq[queue_mapping];
++      if (dpaa2_eth_ceetm_is_enabled(priv)) {
++              err = dpaa2_ceetm_classify(skb, net_dev->qdisc, &ch_id, &prio);
++              if (err) {
++                      free_tx_fd(priv, fq, &fd, false);
++                      percpu_stats->tx_dropped++;
++                      return NETDEV_TX_OK;
++              }
++      }
++
+       fd_len = dpaa2_fd_get_len(&fd);
+       nq = netdev_get_tx_queue(net_dev, queue_mapping);
+       netdev_tx_sent_queue(nq, fd_len);
+@@ -2075,17 +2085,13 @@ static int update_xps(struct dpaa2_eth_p
+       return err;
+ }
+-static int dpaa2_eth_setup_tc(struct net_device *net_dev,
+-                            enum tc_setup_type type, void *type_data)
++static int dpaa2_eth_setup_mqprio(struct net_device *net_dev,
++                                struct tc_mqprio_qopt *mqprio)
+ {
+       struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+-      struct tc_mqprio_qopt *mqprio = type_data;
+       u8 num_tc, num_queues;
+       int i;
+-      if (type != TC_SETUP_QDISC_MQPRIO)
+-              return -EINVAL;
+-
+       mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
+       num_queues = dpaa2_eth_queue_count(priv);
+       num_tc = mqprio->num_tc;
+@@ -2117,6 +2123,20 @@ out:
+       return 0;
+ }
++static int dpaa2_eth_setup_tc(struct net_device *net_dev,
++                            enum tc_setup_type type,
++                            void *type_data)
++{
++      switch (type) {
++      case TC_SETUP_BLOCK:
++              return 0;
++      case TC_SETUP_QDISC_MQPRIO:
++              return dpaa2_eth_setup_mqprio(net_dev, type_data);
++      default:
++              return -EOPNOTSUPP;
++      }
++}
++
+ static const struct net_device_ops dpaa2_eth_ops = {
+       .ndo_open = dpaa2_eth_open,
+       .ndo_start_xmit = dpaa2_eth_tx,
+@@ -4166,18 +4186,27 @@ static int __init dpaa2_eth_driver_init(
+       dpaa2_eth_dbg_init();
+       err = fsl_mc_driver_register(&dpaa2_eth_driver);
+-      if (err) {
+-              dpaa2_eth_dbg_exit();
+-              return err;
+-      }
++      if (err)
++              goto out_debugfs_err;
++
++      err = dpaa2_ceetm_register();
++      if (err)
++              goto out_ceetm_err;
+       return 0;
++
++out_ceetm_err:
++      fsl_mc_driver_unregister(&dpaa2_eth_driver);
++out_debugfs_err:
++      dpaa2_eth_dbg_exit();
++      return err;
+ }
+ static void __exit dpaa2_eth_driver_exit(void)
+ {
+-      dpaa2_eth_dbg_exit();
++      dpaa2_ceetm_unregister();
+       fsl_mc_driver_unregister(&dpaa2_eth_driver);
++      dpaa2_eth_dbg_exit();
+ }
+ module_init(dpaa2_eth_driver_init);
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -453,6 +453,8 @@ struct dpaa2_eth_priv {
+       struct dpaa2_debugfs dbg;
+ #endif
+       struct dpni_tx_shaping_cfg shaping_cfg;
++
++      bool ceetm_en;
+ };
+ #define DPAA2_RXH_SUPPORTED   (RXH_L2DA | RXH_VLAN | RXH_L3_PROTO \
+@@ -573,6 +575,11 @@ static inline unsigned int dpaa2_eth_rx_
+       return priv->tx_data_offset - DPAA2_ETH_RX_HWA_SIZE;
+ }
++static inline int dpaa2_eth_ch_count(struct dpaa2_eth_priv *priv)
++{
++      return 1;
++}
++
+ int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags);
+ int dpaa2_eth_set_cls(struct net_device *net_dev, u64 key);
+ int dpaa2_eth_cls_key_size(u64 key);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0214-dpaa2-eth-Re-add-get_link_ksettings-ethtool-op.patch b/target/linux/layerscape/patches-5.4/701-net-0214-dpaa2-eth-Re-add-get_link_ksettings-ethtool-op.patch
new file mode 100644 (file)
index 0000000..25a9e90
--- /dev/null
@@ -0,0 +1,83 @@
+From 0a5243abf168351ea8409caf329448a3e18ab62f Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Tue, 24 Sep 2019 13:24:40 +0300
+Subject: [PATCH] dpaa2-eth: Re-add get_link_ksettings ethtool op
+
+Which was removed from upstream driver since without a MAC driver
+we have no support for changing link parameters there.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ .../net/ethernet/freescale/dpaa2/dpaa2-ethtool.c   | 47 +++++++++++++++++++++-
+ 1 file changed, 46 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
+@@ -85,7 +85,8 @@ dpaa2_eth_get_link_ksettings(struct net_
+ {
+       struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+-      link_settings->base.autoneg = AUTONEG_DISABLE;
++      if (priv->link_state.options & DPNI_LINK_OPT_AUTONEG)
++              link_settings->base.autoneg = AUTONEG_ENABLE;
+       if (!(priv->link_state.options & DPNI_LINK_OPT_HALF_DUPLEX))
+               link_settings->base.duplex = DUPLEX_FULL;
+       link_settings->base.speed = priv->link_state.rate;
+@@ -93,6 +94,49 @@ dpaa2_eth_get_link_ksettings(struct net_
+       return 0;
+ }
++#define DPNI_DYNAMIC_LINK_SET_VER_MAJOR               7
++#define DPNI_DYNAMIC_LINK_SET_VER_MINOR               1
++static int
++dpaa2_eth_set_link_ksettings(struct net_device *net_dev,
++                           const struct ethtool_link_ksettings *link_settings)
++{
++      struct dpni_link_cfg cfg = {0};
++      struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
++      int err = 0;
++
++      /* If using an older MC version, the DPNI must be down
++       * in order to be able to change link settings. Taking steps to let
++       * the user know that.
++       */
++      if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_DYNAMIC_LINK_SET_VER_MAJOR,
++                                 DPNI_DYNAMIC_LINK_SET_VER_MINOR) < 0) {
++              if (netif_running(net_dev)) {
++                      netdev_info(net_dev, "Interface must be brought down first.\n");
++                      return -EACCES;
++              }
++      }
++
++      cfg.rate = link_settings->base.speed;
++      cfg.options = priv->link_state.options;
++      if (link_settings->base.autoneg == AUTONEG_ENABLE)
++              cfg.options |= DPNI_LINK_OPT_AUTONEG;
++      else
++              cfg.options &= ~DPNI_LINK_OPT_AUTONEG;
++      if (link_settings->base.duplex  == DUPLEX_HALF)
++              cfg.options |= DPNI_LINK_OPT_HALF_DUPLEX;
++      else
++              cfg.options &= ~DPNI_LINK_OPT_HALF_DUPLEX;
++
++      err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &cfg);
++      if (err)
++              /* ethtool will be loud enough if we return an error; no point
++               * in putting our own error message on the console by default
++               */
++              netdev_dbg(net_dev, "ERROR %d setting link cfg\n", err);
++
++      return err;
++}
++
+ static void dpaa2_eth_get_pauseparam(struct net_device *net_dev,
+                                    struct ethtool_pauseparam *pause)
+ {
+@@ -734,6 +778,7 @@ const struct ethtool_ops dpaa2_ethtool_o
+       .get_drvinfo = dpaa2_eth_get_drvinfo,
+       .get_link = ethtool_op_get_link,
+       .get_link_ksettings = dpaa2_eth_get_link_ksettings,
++      .set_link_ksettings = dpaa2_eth_set_link_ksettings,
+       .get_pauseparam = dpaa2_eth_get_pauseparam,
+       .set_pauseparam = dpaa2_eth_set_pauseparam,
+       .get_sset_count = dpaa2_eth_get_sset_count,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0215-dpaa2-eth-Add-support-for-new-link-state-APIs.patch b/target/linux/layerscape/patches-5.4/701-net-0215-dpaa2-eth-Add-support-for-new-link-state-APIs.patch
new file mode 100644 (file)
index 0000000..19aa2e1
--- /dev/null
@@ -0,0 +1,229 @@
+From 0153f87972bfa3ef33bf369b8e91142f7c2b284a Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Wed, 17 Oct 2018 20:14:24 +0300
+Subject: [PATCH] dpaa2-eth: Add support for new link state APIs
+
+Add v2 of dpni_get_link_state() and dpni_set_link_cfg() commands.
+The new version allows setting & getting advertised and supported
+link options.
+
+Signed-off-by: Valentin Catalin Neacsu <valentin-catalin.neacsu@nxp.com>
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h | 33 ++++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpni.c     | 70 +++++++++++++++++++++++++
+ drivers/net/ethernet/freescale/dpaa2/dpni.h     | 27 ++++++++++
+ 3 files changed, 130 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
+@@ -44,9 +44,11 @@
+ #define DPNI_CMDID_GET_QDID                           DPNI_CMD(0x210)
+ #define DPNI_CMDID_GET_TX_DATA_OFFSET                 DPNI_CMD(0x212)
+ #define DPNI_CMDID_GET_LINK_STATE                     DPNI_CMD(0x215)
++#define DPNI_CMDID_GET_LINK_STATE_V2                  DPNI_CMD_V2(0x215)
+ #define DPNI_CMDID_SET_MAX_FRAME_LENGTH                       DPNI_CMD(0x216)
+ #define DPNI_CMDID_GET_MAX_FRAME_LENGTH                       DPNI_CMD(0x217)
+ #define DPNI_CMDID_SET_LINK_CFG                               DPNI_CMD(0x21A)
++#define DPNI_CMDID_SET_LINK_CFG_V2                    DPNI_CMD_V2(0x21A)
+ #define DPNI_CMDID_SET_TX_SHAPING                     DPNI_CMD_V2(0x21B)
+ #define DPNI_CMDID_SET_MCAST_PROMISC                  DPNI_CMD(0x220)
+@@ -304,8 +306,22 @@ struct dpni_cmd_link_cfg {
+       __le64 options;
+ };
++struct dpni_cmd_set_link_cfg_v2 {
++      /* cmd word 0 */
++      __le64 pad0;
++      /* cmd word 1 */
++      __le32 rate;
++      __le32 pad1;
++      /* cmd word 2 */
++      __le64 options;
++      /* cmd word 3 */
++      __le64 advertising;
++};
++
+ #define DPNI_LINK_STATE_SHIFT         0
+ #define DPNI_LINK_STATE_SIZE          1
++#define DPNI_STATE_VALID_SHIFT                1
++#define DPNI_STATE_VALID_SIZE         1
+ struct dpni_rsp_get_link_state {
+       /* response word 0 */
+@@ -320,6 +336,23 @@ struct dpni_rsp_get_link_state {
+       __le64 options;
+ };
++struct dpni_rsp_get_link_state_v2 {
++      /* response word 0 */
++      __le32 pad0;
++      /* from LSB: up:1, valid:1 */
++      u8 flags;
++      u8 pad1[3];
++      /* response word 1 */
++      __le32 rate;
++      __le32 pad2;
++      /* response word 2 */
++      __le64 options;
++      /* cmd word 3 */
++      __le64 supported;
++      /* cmd word 4 */
++      __le64 advertising;
++};
++
+ #define DPNI_COUPLED_SHIFT    0
+ #define DPNI_COUPLED_SIZE     1
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c
+@@ -853,6 +853,36 @@ int dpni_set_link_cfg(struct fsl_mc_io *
+ }
+ /**
++ * dpni_set_link_cfg_v2() - set the link configuration.
++ * @mc_io:      Pointer to MC portal's I/O object
++ * @cmd_flags:  Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:      Token of DPNI object
++ * @cfg:        Link configuration
++ *
++ * Return:      '0' on Success; Error code otherwise.
++ */
++int dpni_set_link_cfg_v2(struct fsl_mc_io *mc_io,
++                       u32 cmd_flags,
++                       u16 token,
++                       const struct dpni_link_cfg *cfg)
++{
++      struct fsl_mc_command cmd = { 0 };
++      struct dpni_cmd_set_link_cfg_v2 *cmd_params;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_LINK_CFG_V2,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpni_cmd_set_link_cfg_v2 *)cmd.params;
++      cmd_params->rate = cpu_to_le32(cfg->rate);
++      cmd_params->options = cpu_to_le64(cfg->options);
++      cmd_params->advertising = cpu_to_le64(cfg->advertising);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
+  * dpni_get_link_cfg() - return the link configuration
+  * @mc_io:    Pointer to MC portal's I/O object
+  * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
+@@ -924,6 +954,46 @@ int dpni_get_link_state(struct fsl_mc_io
+       return 0;
+ }
++
++/**
++ * dpni_get_link_state_v2() - Return the link state (either up or down)
++ * @mc_io:      Pointer to MC portal's I/O object
++ * @cmd_flags:  Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:      Token of DPNI object
++ * @state:      Returned link state;
++ *
++ * Return:      '0' on Success; Error code otherwise.
++ */
++int dpni_get_link_state_v2(struct fsl_mc_io *mc_io,
++                         u32 cmd_flags,
++                         u16 token,
++                         struct dpni_link_state *state)
++{
++      struct fsl_mc_command cmd = { 0 };
++      struct dpni_rsp_get_link_state_v2 *rsp_params;
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_LINK_STATE_V2,
++                                        cmd_flags,
++                                        token);
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      rsp_params = (struct dpni_rsp_get_link_state_v2 *)cmd.params;
++      state->up = dpni_get_field(rsp_params->flags, LINK_STATE);
++      state->state_valid = dpni_get_field(rsp_params->flags, STATE_VALID);
++      state->rate = le32_to_cpu(rsp_params->rate);
++      state->options = le64_to_cpu(rsp_params->options);
++      state->supported = le64_to_cpu(rsp_params->supported);
++      state->advertising = le64_to_cpu(rsp_params->advertising);
++
++      return 0;
++}
+ /**
+  * dpni_set_tx_shaping() - Set the transmit shaping
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h
+@@ -522,6 +522,19 @@ int dpni_reset_statistics(struct fsl_mc_
+  * Enable priority flow control pause frames
+  */
+ #define DPNI_LINK_OPT_PFC_PAUSE               0x0000000000000010ULL
++/**
++ * Advertised link speeds
++ */
++#define DPNI_ADVERTISED_10BASET_FULL           0x0000000000000001ULL
++#define DPNI_ADVERTISED_100BASET_FULL          0x0000000000000002ULL
++#define DPNI_ADVERTISED_1000BASET_FULL         0x0000000000000004ULL
++#define DPNI_ADVERTISED_10000BASET_FULL        0x0000000000000010ULL
++#define DPNI_ADVERTISED_2500BASEX_FULL         0x0000000000000020ULL
++
++/**
++ * Advertise auto-negotiation enabled
++ */
++#define DPNI_ADVERTISED_AUTONEG                0x0000000000000008ULL
+ /**
+  * struct - Structure representing DPNI link configuration
+@@ -531,6 +544,7 @@ int dpni_reset_statistics(struct fsl_mc_
+ struct dpni_link_cfg {
+       u32 rate;
+       u64 options;
++      u64 advertising;
+ };
+ int dpni_set_link_cfg(struct fsl_mc_io                        *mc_io,
+@@ -538,6 +552,11 @@ int dpni_set_link_cfg(struct fsl_mc_io
+                     u16                               token,
+                     const struct dpni_link_cfg        *cfg);
++int dpni_set_link_cfg_v2(struct fsl_mc_io             *mc_io,
++                       u32                            cmd_flags,
++                       u16                            token,
++                       const struct dpni_link_cfg     *cfg);
++
+ int dpni_get_link_cfg(struct fsl_mc_io                        *mc_io,
+                     u32                               cmd_flags,
+                     u16                               token,
+@@ -552,7 +571,10 @@ int dpni_get_link_cfg(struct fsl_mc_io
+ struct dpni_link_state {
+       u32     rate;
+       u64     options;
++      u64     supported;
++      u64     advertising;
+       int     up;
++      int     state_valid;
+ };
+ int dpni_get_link_state(struct fsl_mc_io      *mc_io,
+@@ -560,6 +582,11 @@ int dpni_get_link_state(struct fsl_mc_io
+                       u16                     token,
+                       struct dpni_link_state  *state);
++int dpni_get_link_state_v2(struct fsl_mc_io   *mc_io,
++                         u32                  cmd_flags,
++                         u16                  token,
++                         struct dpni_link_state       *state);
++
+ /**
+  * struct dpni_tx_shaping - Structure representing DPNI tx shaping configuration
+  * @rate_limit: rate in Mbps
diff --git a/target/linux/layerscape/patches-5.4/701-net-0216-dpaa2-eth-Add-autoneg-support.patch b/target/linux/layerscape/patches-5.4/701-net-0216-dpaa2-eth-Add-autoneg-support.patch
new file mode 100644 (file)
index 0000000..a49562e
--- /dev/null
@@ -0,0 +1,129 @@
+From c6365855a6d9aef3b75e301d26872bc51398c2f3 Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Thu, 18 Oct 2018 18:59:41 +0300
+Subject: [PATCH] dpaa2-eth: Add autoneg support
+
+For MC versions that support it, use the new DPNI link APIs, which
+allow setting/getting of advertised and supported link modes.
+
+A mapping between DPNI link modes and ethtool ones is created to
+help converting from one to the other.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Signed-off-by: Valentin Catalin Neacsu <valentin-catalin.neacsu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c   |  8 ++-
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h   |  3 ++
+ .../net/ethernet/freescale/dpaa2/dpaa2-ethtool.c   | 57 ++++++++++++++++++++--
+ 3 files changed, 62 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -1357,7 +1357,13 @@ static int link_state_update(struct dpaa
+       bool tx_pause;
+       int err;
+-      err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state);
++      if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_LINK_AUTONEG_VER_MAJOR,
++                                 DPNI_LINK_AUTONEG_VER_MINOR) < 0)
++              err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token,
++                                        &state);
++      else
++              err = dpni_get_link_state_v2(priv->mc_io, 0, priv->mc_token,
++                                           &state);
+       if (unlikely(err)) {
+               netdev_err(priv->net_dev,
+                          "dpni_get_link_state() failed\n");
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -542,6 +542,9 @@ static inline bool dpaa2_eth_rx_pause_en
+       return !!(link_options & DPNI_LINK_OPT_PAUSE);
+ }
++#define DPNI_LINK_AUTONEG_VER_MAJOR   7
++#define DPNI_LINK_AUTONEG_VER_MINOR   8
++
+ static inline
+ unsigned int dpaa2_eth_needed_headroom(struct dpaa2_eth_priv *priv,
+                                      struct sk_buff *skb)
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
+@@ -79,6 +79,41 @@ static void dpaa2_eth_get_drvinfo(struct
+               sizeof(drvinfo->bus_info));
+ }
++struct dpaa2_eth_link_mode_map {
++      u64 dpni_lm;
++      u64 ethtool_lm;
++};
++
++static const struct dpaa2_eth_link_mode_map dpaa2_eth_lm_map[] = {
++      {DPNI_ADVERTISED_10BASET_FULL, ETHTOOL_LINK_MODE_10baseT_Full_BIT},
++      {DPNI_ADVERTISED_100BASET_FULL, ETHTOOL_LINK_MODE_100baseT_Full_BIT},
++      {DPNI_ADVERTISED_1000BASET_FULL, ETHTOOL_LINK_MODE_1000baseT_Full_BIT},
++      {DPNI_ADVERTISED_10000BASET_FULL, ETHTOOL_LINK_MODE_10000baseT_Full_BIT},
++      {DPNI_ADVERTISED_2500BASEX_FULL, ETHTOOL_LINK_MODE_2500baseT_Full_BIT},
++      {DPNI_ADVERTISED_AUTONEG, ETHTOOL_LINK_MODE_Autoneg_BIT},
++};
++
++static void link_mode_dpni2ethtool(u64 dpni_lm, unsigned long *ethtool_lm)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(dpaa2_eth_lm_map); i++) {
++              if (dpni_lm & dpaa2_eth_lm_map[i].dpni_lm)
++                      __set_bit(dpaa2_eth_lm_map[i].ethtool_lm, ethtool_lm);
++      }
++}
++
++static void link_mode_ethtool2dpni(const unsigned long *ethtool_lm,
++                                 u64 *dpni_lm)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(dpaa2_eth_lm_map); i++) {
++              if (test_bit(dpaa2_eth_lm_map[i].ethtool_lm, ethtool_lm))
++                      *dpni_lm |= dpaa2_eth_lm_map[i].dpni_lm;
++      }
++}
++
+ static int
+ dpaa2_eth_get_link_ksettings(struct net_device *net_dev,
+                            struct ethtool_link_ksettings *link_settings)
+@@ -91,6 +126,14 @@ dpaa2_eth_get_link_ksettings(struct net_
+               link_settings->base.duplex = DUPLEX_FULL;
+       link_settings->base.speed = priv->link_state.rate;
++      if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_LINK_AUTONEG_VER_MAJOR,
++                                 DPNI_LINK_AUTONEG_VER_MINOR) >= 0) {
++              link_mode_dpni2ethtool(priv->link_state.supported,
++                                     link_settings->link_modes.supported);
++              link_mode_dpni2ethtool(priv->link_state.advertising,
++                                     link_settings->link_modes.advertising);
++      }
++
+       return 0;
+ }
+@@ -127,12 +170,16 @@ dpaa2_eth_set_link_ksettings(struct net_
+       else
+               cfg.options &= ~DPNI_LINK_OPT_HALF_DUPLEX;
+-      err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &cfg);
++      if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_LINK_AUTONEG_VER_MAJOR,
++                                 DPNI_LINK_AUTONEG_VER_MINOR) < 0) {
++              err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &cfg);
++      } else {
++              link_mode_ethtool2dpni(link_settings->link_modes.advertising,
++                                     &cfg.advertising);
++              dpni_set_link_cfg_v2(priv->mc_io, 0, priv->mc_token, &cfg);
++      }
+       if (err)
+-              /* ethtool will be loud enough if we return an error; no point
+-               * in putting our own error message on the console by default
+-               */
+-              netdev_dbg(net_dev, "ERROR %d setting link cfg\n", err);
++              netdev_err(net_dev, "dpni_set_link_cfg failed");
+       return err;
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0217-dpaa2-eth-Don-t-use-netif_receive_skb_list-for-TCP-f.patch b/target/linux/layerscape/patches-5.4/701-net-0217-dpaa2-eth-Don-t-use-netif_receive_skb_list-for-TCP-f.patch
new file mode 100644 (file)
index 0000000..74b4b6d
--- /dev/null
@@ -0,0 +1,125 @@
+From 01e74b70dd8183aa191cd594ec9fa2879357811f Mon Sep 17 00:00:00 2001
+From: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Date: Mon, 22 Jul 2019 18:52:39 +0300
+Subject: [PATCH] dpaa2-eth: Don't use netif_receive_skb_list for TCP frames
+
+Using Rx skb bulking for all frames may negatively impact the
+performance in some TCP termination scenarios, as it effectively
+bypasses GRO.
+
+Look at the hardware parse results of each ingress frame to see
+if a TCP header is present or not; for TCP frames fall back to
+the old implementation.
+
+Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 15 ++++++-
+ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h | 51 ++++++++++++++++++++++++
+ 2 files changed, 65 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -353,6 +353,16 @@ out:
+       return xdp_act;
+ }
++static bool frame_is_tcp(const struct dpaa2_fd *fd, struct dpaa2_fas *fas)
++{
++      struct dpaa2_fapr *fapr = dpaa2_get_fapr(fas, false);
++
++      if (!(dpaa2_fd_get_frc(fd) & DPAA2_FD_FRC_FAPRV))
++              return false;
++
++      return !!(fapr->faf_hi & DPAA2_FAF_HI_TCP_PRESENT);
++}
++
+ /* Main Rx frame processing routine */
+ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv,
+                        struct dpaa2_eth_channel *ch,
+@@ -440,7 +450,10 @@ static void dpaa2_eth_rx(struct dpaa2_et
+       percpu_stats->rx_packets++;
+       percpu_stats->rx_bytes += dpaa2_fd_get_len(fd);
+-      list_add_tail(&skb->list, ch->rx_list);
++      if (frame_is_tcp(fd, fas))
++              napi_gro_receive(&ch->napi, skb);
++      else
++              list_add_tail(&skb->list, ch->rx_list);
+       return;
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -178,6 +178,49 @@ struct dpaa2_fas {
+  */
+ #define DPAA2_TS_OFFSET                       0x8
++/* Frame annotation parse results */
++struct dpaa2_fapr {
++      /* 64-bit word 1 */
++      __le32 faf_lo;
++      __le16 faf_ext;
++      __le16 nxt_hdr;
++      /* 64-bit word 2 */
++      __le64 faf_hi;
++      /* 64-bit word 3 */
++      u8 last_ethertype_offset;
++      u8 vlan_tci_offset_n;
++      u8 vlan_tci_offset_1;
++      u8 llc_snap_offset;
++      u8 eth_offset;
++      u8 ip1_pid_offset;
++      u8 shim_offset_2;
++      u8 shim_offset_1;
++      /* 64-bit word 4 */
++      u8 l5_offset;
++      u8 l4_offset;
++      u8 gre_offset;
++      u8 l3_offset_n;
++      u8 l3_offset_1;
++      u8 mpls_offset_n;
++      u8 mpls_offset_1;
++      u8 pppoe_offset;
++      /* 64-bit word 5 */
++      __le16 running_sum;
++      __le16 gross_running_sum;
++      u8 ipv6_frag_offset;
++      u8 nxt_hdr_offset;
++      u8 routing_hdr_offset_2;
++      u8 routing_hdr_offset_1;
++      /* 64-bit word 6 */
++      u8 reserved[5]; /* Soft-parsing context */
++      u8 ip_proto_offset_n;
++      u8 nxt_hdr_frag_offset;
++      u8 parse_error_code;
++};
++
++#define DPAA2_FAPR_OFFSET             0x10
++#define DPAA2_FAPR_SIZE                       sizeof((struct dpaa2_fapr))
++
+ /* Frame annotation egress action descriptor */
+ #define DPAA2_FAEAD_OFFSET            0x58
+@@ -208,6 +251,11 @@ static inline __le64 *dpaa2_get_ts(void
+       return dpaa2_get_hwa(buf_addr, swa) + DPAA2_TS_OFFSET;
+ }
++static inline struct dpaa2_fapr *dpaa2_get_fapr(void *buf_addr, bool swa)
++{
++      return dpaa2_get_hwa(buf_addr, swa) + DPAA2_FAPR_OFFSET;
++}
++
+ static inline struct dpaa2_faead *dpaa2_get_faead(void *buf_addr, bool swa)
+ {
+       return dpaa2_get_hwa(buf_addr, swa) + DPAA2_FAEAD_OFFSET;
+@@ -259,6 +307,9 @@ static inline struct dpaa2_faead *dpaa2_
+                                        DPAA2_FAS_L3CE         | \
+                                        DPAA2_FAS_L4CE)
++/* TCP indication in Frame Annotation Parse Results */
++#define DPAA2_FAF_HI_TCP_PRESENT      BIT(23)
++
+ /* Time in milliseconds between link state updates */
+ #define DPAA2_ETH_LINK_STATE_REFRESH  1000
diff --git a/target/linux/layerscape/patches-5.4/701-net-0218-bus-fsl-mc-Add-a-new-parameter-to-dprc_scan_objects-.patch b/target/linux/layerscape/patches-5.4/701-net-0218-bus-fsl-mc-Add-a-new-parameter-to-dprc_scan_objects-.patch
new file mode 100644 (file)
index 0000000..0fbf3d2
--- /dev/null
@@ -0,0 +1,127 @@
+From 653fc2595283df6deb92ca3058c8d5dc1e129e91 Mon Sep 17 00:00:00 2001
+From: Diana Craciun <diana.craciun@nxp.com>
+Date: Fri, 13 Sep 2019 17:17:30 +0300
+Subject: [PATCH] bus/fsl-mc: Add a new parameter to dprc_scan_objects function
+
+Prepare the dprc_scan_objects function to be used by
+the VFIO mc driver code. The function is used to scan the mc
+objects by the bus driver. The same functionality is
+needed by the VFIO mc driver, but in this case the
+interrupt configuration is delayed until the userspace
+configures them. In order to use the same function in both
+drivers add a new parameter.
+
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ drivers/bus/fsl-mc/dprc-driver.c | 33 +++++++++++++++++++--------------
+ drivers/bus/fsl-mc/fsl-mc-bus.c  |  2 +-
+ include/linux/fsl/mc.h           |  1 +
+ 3 files changed, 21 insertions(+), 15 deletions(-)
+
+--- a/drivers/bus/fsl-mc/dprc-driver.c
++++ b/drivers/bus/fsl-mc/dprc-driver.c
+@@ -3,6 +3,7 @@
+  * Freescale data path resource container (DPRC) driver
+  *
+  * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
++ * Copyright 2019 NXP
+  * Author: German Rivera <German.Rivera@freescale.com>
+  *
+  */
+@@ -204,6 +205,8 @@ static void dprc_add_new_devices(struct
+  * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
+  * @driver_override: driver override to apply to new objects found in the
+  * DPRC, or NULL, if none.
++ * @alloc_interrupts: if true the function allocates the interrupt pool,
++ * otherwise the interrupt allocation is delayed
+  * @total_irq_count: If argument is provided the function populates the
+  * total number of IRQs created by objects in the DPRC.
+  *
+@@ -221,6 +224,7 @@ static void dprc_add_new_devices(struct
+  */
+ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
+                     const char *driver_override,
++                        bool alloc_interrupts,
+                     unsigned int *total_irq_count)
+ {
+       int num_child_objects;
+@@ -302,19 +306,20 @@ int dprc_scan_objects(struct fsl_mc_devi
+        * Allocate IRQ's before binding the scanned devices with their
+        * respective drivers.
+        */
+-      if (dev_get_msi_domain(&mc_bus_dev->dev) && !mc_bus->irq_resources) {
+-              if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) {
+-                      dev_warn(&mc_bus_dev->dev,
+-                               "IRQs needed (%u) exceed IRQs preallocated (%u)\n",
+-                               irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
+-              }
++      if (alloc_interrupts) {
++              if (dev_get_msi_domain(&mc_bus_dev->dev) && !mc_bus->irq_resources) {
++                      if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) {
++                              dev_warn(&mc_bus_dev->dev,
++                                       "IRQs needed (%u) exceed IRQs preallocated (%u)\n",
++                                       irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
++                      }
+-              error = fsl_mc_populate_irq_pool(mc_bus,
+-                              FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
+-              if (error < 0)
+-                      return error;
++                      error = fsl_mc_populate_irq_pool(mc_bus,
++                                      FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
++                      if (error < 0)
++                              return error;
++              }
+       }
+-
+       if (total_irq_count)
+               *total_irq_count = irq_count;
+@@ -350,7 +355,7 @@ static int dprc_scan_container(struct fs
+        * Discover objects in the DPRC:
+        */
+       mutex_lock(&mc_bus->scan_mutex);
+-      error = dprc_scan_objects(mc_bus_dev, NULL, NULL);
++      error = dprc_scan_objects(mc_bus_dev, NULL, true, NULL);
+       mutex_unlock(&mc_bus->scan_mutex);
+       if (error < 0) {
+               fsl_mc_cleanup_all_resource_pools(mc_bus_dev);
+@@ -379,7 +384,7 @@ static ssize_t rescan_store(struct devic
+       if (val) {
+               mutex_lock(&root_mc_bus->scan_mutex);
+-              dprc_scan_objects(root_mc_dev, NULL, NULL);
++              dprc_scan_objects(root_mc_dev, NULL, true, NULL);
+               mutex_unlock(&root_mc_bus->scan_mutex);
+       }
+@@ -448,7 +453,7 @@ static irqreturn_t dprc_irq0_handler_thr
+                     DPRC_IRQ_EVENT_OBJ_CREATED)) {
+               unsigned int irq_count;
+-              error = dprc_scan_objects(mc_dev, NULL, &irq_count);
++              error = dprc_scan_objects(mc_dev, NULL, true, &irq_count);
+               if (error < 0) {
+                       /*
+                        * If the error is -ENXIO, we ignore it, as it indicates
+--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
+@@ -215,7 +215,7 @@ static int scan_fsl_mc_bus(struct device
+       root_mc_dev = to_fsl_mc_device(dev);
+       root_mc_bus = to_fsl_mc_bus(root_mc_dev);
+       mutex_lock(&root_mc_bus->scan_mutex);
+-      dprc_scan_objects(root_mc_dev, NULL, NULL);
++      dprc_scan_objects(root_mc_dev, NULL, true, NULL);
+       mutex_unlock(&root_mc_bus->scan_mutex);
+ exit:
+--- a/include/linux/fsl/mc.h
++++ b/include/linux/fsl/mc.h
+@@ -1010,6 +1010,7 @@ struct fsl_mc_bus {
+ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
+                     const char *driver_override,
++                        bool alloc_interrupts,
+                     unsigned int *total_irq_count);
+ int fsl_mc_find_msi_domain(struct device *mc_platform_dev,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0219-bus-fsl-mc-Extend-functions-from-the-bus-driver-to-b.patch b/target/linux/layerscape/patches-5.4/701-net-0219-bus-fsl-mc-Extend-functions-from-the-bus-driver-to-b.patch
new file mode 100644 (file)
index 0000000..8fcdac5
--- /dev/null
@@ -0,0 +1,49 @@
+From 49878e0759161d357782802f954886bae7bcc83b Mon Sep 17 00:00:00 2001
+From: Diana Craciun <diana.craciun@nxp.com>
+Date: Thu, 21 Nov 2019 15:06:47 +0200
+Subject: [PATCH] bus/fsl-mc: Extend functions from the bus driver to be used
+ by vfio-mc
+
+The bus/dpcr driver use some common functions, export those
+functions to be accessible from the vfio-mc driver.
+
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ drivers/bus/fsl-mc/fsl-mc-private.h | 8 --------
+ include/linux/fsl/mc.h              | 8 ++++++++
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+--- a/drivers/bus/fsl-mc/fsl-mc-private.h
++++ b/drivers/bus/fsl-mc/fsl-mc-private.h
+@@ -182,14 +182,6 @@ int fsl_mc_msi_domain_alloc_irqs(struct
+ void fsl_mc_msi_domain_free_irqs(struct device *dev);
+-int __must_check fsl_create_mc_io(struct device *dev,
+-                                phys_addr_t mc_portal_phys_addr,
+-                                u32 mc_portal_size,
+-                                struct fsl_mc_device *dpmcp_dev,
+-                                u32 flags, struct fsl_mc_io **new_mc_io);
+-
+-void fsl_destroy_mc_io(struct fsl_mc_io *mc_io);
+-
+ bool fsl_mc_is_root_dprc(struct device *dev);
+ #ifdef CONFIG_FSL_MC_UAPI_SUPPORT
+--- a/include/linux/fsl/mc.h
++++ b/include/linux/fsl/mc.h
+@@ -1013,6 +1013,14 @@ int dprc_scan_objects(struct fsl_mc_devi
+                         bool alloc_interrupts,
+                     unsigned int *total_irq_count);
++int __must_check fsl_create_mc_io(struct device *dev,
++                                phys_addr_t mc_portal_phys_addr,
++                                u32 mc_portal_size,
++                                struct fsl_mc_device *dpmcp_dev,
++                                u32 flags, struct fsl_mc_io **new_mc_io);
++
++void fsl_destroy_mc_io(struct fsl_mc_io *mc_io);
++
+ int fsl_mc_find_msi_domain(struct device *mc_platform_dev,
+                          struct irq_domain **mc_msi_domain);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0220-bus-fsl-mc-Set-the-QMAN-BMAN-region-flags.patch b/target/linux/layerscape/patches-5.4/701-net-0220-bus-fsl-mc-Set-the-QMAN-BMAN-region-flags.patch
new file mode 100644 (file)
index 0000000..f4f53b2
--- /dev/null
@@ -0,0 +1,30 @@
+From 3c771fc6111d2703274d269b2b34183ce8be4df4 Mon Sep 17 00:00:00 2001
+From: Diana Craciun <diana.craciun@nxp.com>
+Date: Mon, 18 Nov 2019 11:37:59 +0200
+Subject: [PATCH] bus/fsl-mc: Set the QMAN/BMAN region flags
+
+The QMAN region can be memory mapped, so it should be
+of type IORESOURCE_MEM. Also use the bus specific bits
+in order to pass additional information about the region.
+
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ drivers/bus/fsl-mc/fsl-mc-bus.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
+@@ -627,11 +627,8 @@ static int fsl_mc_device_get_mmio_region
+               regions[i].end = regions[i].start + region_desc.size - 1;
+               regions[i].name = "fsl-mc object MMIO region";
+-              regions[i].flags = IORESOURCE_IO;
+-              if (region_desc.flags & DPRC_REGION_CACHEABLE)
+-                      regions[i].flags |= IORESOURCE_CACHEABLE;
+-              if (region_desc.flags & DPRC_REGION_SHAREABLE)
+-                      regions[i].flags |= IORESOURCE_MEM;
++              regions[i].flags = region_desc.flags & IORESOURCE_BITS;
++              regions[i].flags |= IORESOURCE_MEM;
+       }
+       mc_dev->regions = regions;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0221-soc-fsl-dpio-Adding-QMAN-multiple-enqueue-interface.patch b/target/linux/layerscape/patches-5.4/701-net-0221-soc-fsl-dpio-Adding-QMAN-multiple-enqueue-interface.patch
new file mode 100644 (file)
index 0000000..3c76eef
--- /dev/null
@@ -0,0 +1,304 @@
+From 1da6ba0350da068295d5bc5556193b21da38a388 Mon Sep 17 00:00:00 2001
+From: Youri Querry <youri.querry_1@nxp.com>
+Date: Mon, 4 Nov 2019 10:32:37 -0500
+Subject: [PATCH] soc: fsl: dpio: Adding QMAN multiple enqueue interface.
+
+Update of QMAN the interface to enqueue frame. We now support multiple
+enqueue (qbman_swp_enqueue_multiple) and multiple enqueue with
+a table of descriptor (qbman_swp_enqueue_multiple_desc).
+
+Signed-off-by: Youri Querry <youri.querry_1@nxp.com>
+---
+ drivers/soc/fsl/dpio/dpio-service.c | 69 ++++++++++++++++++++++++++++++++--
+ drivers/soc/fsl/dpio/qbman-portal.c | 75 +++++++++++++++++++++++++++++++------
+ drivers/soc/fsl/dpio/qbman-portal.h | 17 +++++++++
+ include/soc/fsl/dpaa2-io.h          |  6 ++-
+ 4 files changed, 152 insertions(+), 15 deletions(-)
+
+--- a/drivers/soc/fsl/dpio/dpio-service.c
++++ b/drivers/soc/fsl/dpio/dpio-service.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+ /*
+  * Copyright 2014-2016 Freescale Semiconductor Inc.
+- * Copyright 2016 NXP
++ * Copyright 2016-2019 NXP
+  *
+  */
+ #include <linux/types.h>
+@@ -437,6 +437,69 @@ int dpaa2_io_service_enqueue_fq(struct d
+ EXPORT_SYMBOL(dpaa2_io_service_enqueue_fq);
+ /**
++ * dpaa2_io_service_enqueue_multiple_fq() - Enqueue multiple frames
++ * to a frame queue using one fqid.
++ * @d: the given DPIO service.
++ * @fqid: the given frame queue id.
++ * @fd: the frame descriptor which is enqueued.
++ * @nb: number of frames to be enqueud
++ *
++ * Return 0 for successful enqueue, -EBUSY if the enqueue ring is not ready,
++ * or -ENODEV if there is no dpio service.
++ */
++int dpaa2_io_service_enqueue_multiple_fq(struct dpaa2_io *d,
++                              u32 fqid,
++                              const struct dpaa2_fd *fd,
++                              int nb)
++{
++      struct qbman_eq_desc ed;
++
++      d = service_select(d);
++      if (!d)
++              return -ENODEV;
++
++      qbman_eq_desc_clear(&ed);
++      qbman_eq_desc_set_no_orp(&ed, 0);
++      qbman_eq_desc_set_fq(&ed, fqid);
++
++      return qbman_swp_enqueue_multiple(d->swp, &ed, fd, 0, nb);
++}
++EXPORT_SYMBOL(dpaa2_io_service_enqueue_multiple_fq);
++
++/**
++ * dpaa2_io_service_enqueue_multiple_desc_fq() - Enqueue multiple frames
++ * to different frame queue using a list of fqids.
++ * @d: the given DPIO service.
++ * @fqid: the given list of frame queue ids.
++ * @fd: the frame descriptor which is enqueued.
++ * @nb: number of frames to be enqueud
++ *
++ * Return 0 for successful enqueue, -EBUSY if the enqueue ring is not ready,
++ * or -ENODEV if there is no dpio service.
++ */
++int dpaa2_io_service_enqueue_multiple_desc_fq(struct dpaa2_io *d,
++                              u32 *fqid,
++                              const struct dpaa2_fd *fd,
++                              int nb)
++{
++      int i;
++      struct qbman_eq_desc ed[32];
++
++      d = service_select(d);
++      if (!d)
++              return -ENODEV;
++
++      for (i = 0; i < nb; i++) {
++              qbman_eq_desc_clear(&ed[i]);
++              qbman_eq_desc_set_no_orp(&ed[i], 0);
++              qbman_eq_desc_set_fq(&ed[i], fqid[i]);
++      }
++
++      return qbman_swp_enqueue_multiple_desc(d->swp, &ed[0], fd, nb);
++}
++EXPORT_SYMBOL(dpaa2_io_service_enqueue_multiple_desc_fq);
++
++/**
+  * dpaa2_io_service_enqueue_qd() - Enqueue a frame to a QD.
+  * @d: the given DPIO service.
+  * @qdid: the given queuing destination id.
+@@ -530,7 +593,7 @@ EXPORT_SYMBOL_GPL(dpaa2_io_service_acqui
+ /**
+  * dpaa2_io_store_create() - Create the dma memory storage for dequeue result.
+- * @max_frames: the maximum number of dequeued result for frames, must be <= 16.
++ * @max_frames: the maximum number of dequeued result for frames, must be <= 32.
+  * @dev:        the device to allow mapping/unmapping the DMAable region.
+  *
+  * The size of the storage is "max_frames*sizeof(struct dpaa2_dq)".
+@@ -545,7 +608,7 @@ struct dpaa2_io_store *dpaa2_io_store_cr
+       struct dpaa2_io_store *ret;
+       size_t size;
+-      if (!max_frames || (max_frames > 16))
++      if (!max_frames || (max_frames > 32))
+               return NULL;
+       ret = kmalloc(sizeof(*ret), GFP_KERNEL);
+--- a/drivers/soc/fsl/dpio/qbman-portal.c
++++ b/drivers/soc/fsl/dpio/qbman-portal.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+ /*
+  * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
+- * Copyright 2016 NXP
++ * Copyright 2016-2019 NXP
+  *
+  */
+@@ -86,7 +86,7 @@ enum qbman_sdqcr_fc {
+ #define dccvac(p) { asm volatile("dc cvac, %0;" : : "r" (p) : "memory"); }
+ #define dcivac(p) { asm volatile("dc ivac, %0" : : "r"(p) : "memory"); }
+-static inline void qbman_inval_prefetch(struct qbman_swp *p, uint32_t offset)
++static inline void qbman_inval_prefetch(struct qbman_swp *p, u32 offset)
+ {
+       dcivac(p->addr_cena + offset);
+       prefetch(p->addr_cena + offset);
+@@ -158,7 +158,7 @@ static inline u32 qbman_set_swp_cfg(u8 m
+  */
+ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
+ {
+-      struct qbman_swp *p = kmalloc(sizeof(*p), GFP_KERNEL);
++      struct qbman_swp *p = kzalloc(sizeof(*p), GFP_KERNEL);
+       u32 reg;
+       if (!p)
+@@ -380,7 +380,6 @@ enum qb_enqueue_commands {
+ };
+ #define QB_ENQUEUE_CMD_ORP_ENABLE_SHIFT      2
+-#define QB_ENQUEUE_CMD_IRQ_ON_DISPATCH_SHIFT 3
+ #define QB_ENQUEUE_CMD_TARGET_TYPE_SHIFT     4
+ /**
+@@ -508,7 +507,7 @@ static inline void qbman_write_eqcr_am_r
+ int qbman_swp_enqueue(struct qbman_swp *s, const struct qbman_eq_desc *d,
+                     const struct dpaa2_fd *fd)
+ {
+-      struct qbman_eq_desc *p;
++      struct qbman_eq_desc_with_fd *p;
+       u32 eqar = qbman_read_register(s, QBMAN_CINH_SWP_EQAR);
+       if (!EQAR_SUCCESS(eqar))
+@@ -522,19 +521,19 @@ int qbman_swp_enqueue(struct qbman_swp *
+        * desc.orpid address alignment = 4
+        * desc.tgtid address alignment = 8
+        */
+-      p->dca = d->dca;
+-      p->seqnum = d->seqnum;
+-      p->orpid = d->orpid;
+-      memcpy(&p->tgtid, &d->tgtid, 24);
++      p->desc.dca = d->dca;
++      p->desc.seqnum = d->seqnum;
++      p->desc.orpid = d->orpid;
++      memcpy(&p->desc.tgtid, &d->tgtid, 24);
+       memcpy(&p->fd, fd, sizeof(*fd));
+       if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
+               /* Set the verb byte, have to substitute in the valid-bit */
+               dma_wmb();
+-              p->verb = d->verb | EQAR_VB(eqar);
++              p->desc.verb = d->verb | EQAR_VB(eqar);
+               dccvac(p);
+       } else {
+-              p->verb = d->verb | EQAR_VB(eqar);
++              p->desc.verb = d->verb | EQAR_VB(eqar);
+               dma_wmb();
+               qbman_write_eqcr_am_rt_register(s, EQAR_IDX(eqar));
+       }
+@@ -542,6 +541,60 @@ int qbman_swp_enqueue(struct qbman_swp *
+       return 0;
+ }
++/**
++ * qbman_swp_enqueue_multiple() - Issue a multi enqueue command
++ * using one enqueue descriptor
++ * @s:  the software portal used for enqueue
++ * @d:  the enqueue descriptor
++ * @fd: table pointer of frame descriptor table to be enqueued
++ * @flags: table pointer of flags, not used for the moment
++ * @num_frames: number of fd to be enqueued
++ *
++ * Return the number of fd enqueued, or a negative error number.
++ */
++int qbman_swp_enqueue_multiple(struct qbman_swp *s,
++                             const struct qbman_eq_desc *d,
++                             const struct dpaa2_fd *fd,
++                             uint32_t *flags,
++                             int num_frames)
++{
++      int count = 0;
++
++      while (count < num_frames) {
++              if (qbman_swp_enqueue(s, d, fd) != 0)
++                      break;
++              count++;
++      }
++
++      return count;
++}
++
++/**
++ * qbman_swp_enqueue_multiple_desc() - Issue a multi enqueue command
++ * using multiple enqueue descriptor
++ * @s:  the software portal used for enqueue
++ * @d:  table of minimal enqueue descriptor
++ * @fd: table pointer of frame descriptor table to be enqueued
++ * @num_frames: number of fd to be enqueued
++ *
++ * Return the number of fd enqueued, or a negative error number.
++ */
++int qbman_swp_enqueue_multiple_desc(struct qbman_swp *s,
++                                  const struct qbman_eq_desc *d,
++                                  const struct dpaa2_fd *fd,
++                                  int num_frames)
++{
++      int count = 0;
++
++      while (count < num_frames) {
++              if (qbman_swp_enqueue(s, &(d[count]), fd) != 0)
++                      break;
++              count++;
++      }
++
++      return count;
++}
++
+ /* Static (push) dequeue */
+ /**
+--- a/drivers/soc/fsl/dpio/qbman-portal.h
++++ b/drivers/soc/fsl/dpio/qbman-portal.h
+@@ -88,6 +88,10 @@ struct qbman_eq_desc {
+       u8 wae;
+       u8 rspid;
+       __le64 rsp_addr;
++};
++
++struct qbman_eq_desc_with_fd {
++      struct qbman_eq_desc desc;
+       u8 fd[32];
+ };
+@@ -205,6 +209,19 @@ void *qbman_swp_mc_start(struct qbman_sw
+ void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, u8 cmd_verb);
+ void *qbman_swp_mc_result(struct qbman_swp *p);
++int
++qbman_swp_enqueue_multiple(struct qbman_swp *s,
++                         const struct qbman_eq_desc *d,
++                         const struct dpaa2_fd *fd,
++                         uint32_t *flags,
++                         int num_frames);
++
++int
++qbman_swp_enqueue_multiple_desc(struct qbman_swp *s,
++                              const struct qbman_eq_desc *d,
++                              const struct dpaa2_fd *fd,
++                              int num_frames);
++
+ /**
+  * qbman_result_is_DQ() - check if the dequeue result is a dequeue response
+  * @dq: the dequeue result to be checked
+--- a/include/soc/fsl/dpaa2-io.h
++++ b/include/soc/fsl/dpaa2-io.h
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+ /*
+  * Copyright 2014-2016 Freescale Semiconductor Inc.
+- * Copyright 2017 NXP
++ * Copyright 2017-2019 NXP
+  *
+  */
+ #ifndef __FSL_DPAA2_IO_H
+@@ -109,6 +109,10 @@ int dpaa2_io_service_pull_channel(struct
+ int dpaa2_io_service_enqueue_fq(struct dpaa2_io *d, u32 fqid,
+                               const struct dpaa2_fd *fd);
++int dpaa2_io_service_enqueue_multiple_fq(struct dpaa2_io *d, u32 fqid,
++                              const struct dpaa2_fd *fd, int number_of_frame);
++int dpaa2_io_service_enqueue_multiple_desc_fq(struct dpaa2_io *d, u32 *fqid,
++                              const struct dpaa2_fd *fd, int number_of_frame);
+ int dpaa2_io_service_enqueue_qd(struct dpaa2_io *d, u32 qdid, u8 prio,
+                               u16 qdbin, const struct dpaa2_fd *fd);
+ int dpaa2_io_service_release(struct dpaa2_io *d, u16 bpid,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0222-soc-fsl-dpio-QMAN-performance-improvement.-Function-.patch b/target/linux/layerscape/patches-5.4/701-net-0222-soc-fsl-dpio-QMAN-performance-improvement.-Function-.patch
new file mode 100644 (file)
index 0000000..79606f7
--- /dev/null
@@ -0,0 +1,789 @@
+From 5c88fa1440b2e4d0bdd46dad5370eb8c2181951b Mon Sep 17 00:00:00 2001
+From: Youri Querry <youri.querry_1@nxp.com>
+Date: Mon, 4 Nov 2019 11:00:24 -0500
+Subject: [PATCH] soc: fsl: dpio: QMAN performance improvement. Function
+ pointer indirection.
+
+We are making the access decision in the initialization and
+setting the function pointers accordingly.
+
+Signed-off-by: Youri Querry <youri.querry_1@nxp.com>
+---
+ drivers/soc/fsl/dpio/qbman-portal.c | 455 ++++++++++++++++++++++++++++++------
+ drivers/soc/fsl/dpio/qbman-portal.h | 130 ++++++++++-
+ 2 files changed, 508 insertions(+), 77 deletions(-)
+
+--- a/drivers/soc/fsl/dpio/qbman-portal.c
++++ b/drivers/soc/fsl/dpio/qbman-portal.c
+@@ -84,6 +84,82 @@ enum qbman_sdqcr_fc {
+       qbman_sdqcr_fc_up_to_3 = 1
+ };
++/* Internal Function declaration */
++static int qbman_swp_enqueue_direct(struct qbman_swp *s,
++                                  const struct qbman_eq_desc *d,
++                                  const struct dpaa2_fd *fd);
++static int qbman_swp_enqueue_mem_back(struct qbman_swp *s,
++                                    const struct qbman_eq_desc *d,
++                                    const struct dpaa2_fd *fd);
++static int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s,
++                                           const struct qbman_eq_desc *d,
++                                           const struct dpaa2_fd *fd,
++                                           uint32_t *flags,
++                                           int num_frames);
++static int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s,
++                                             const struct qbman_eq_desc *d,
++                                             const struct dpaa2_fd *fd,
++                                             uint32_t *flags,
++                                             int num_frames);
++static int
++qbman_swp_enqueue_multiple_desc_direct(struct qbman_swp *s,
++                                     const struct qbman_eq_desc *d,
++                                     const struct dpaa2_fd *fd,
++                                     int num_frames);
++static
++int qbman_swp_enqueue_multiple_desc_mem_back(struct qbman_swp *s,
++                                           const struct qbman_eq_desc *d,
++                                           const struct dpaa2_fd *fd,
++                                           int num_frames);
++static int qbman_swp_pull_direct(struct qbman_swp *s,
++                               struct qbman_pull_desc *d);
++static int qbman_swp_pull_mem_back(struct qbman_swp *s,
++                                 struct qbman_pull_desc *d);
++
++const struct dpaa2_dq *qbman_swp_dqrr_next_direct(struct qbman_swp *s);
++const struct dpaa2_dq *qbman_swp_dqrr_next_mem_back(struct qbman_swp *s);
++
++static int qbman_swp_release_direct(struct qbman_swp *s,
++                                  const struct qbman_release_desc *d,
++                                  const u64 *buffers,
++                                  unsigned int num_buffers);
++static int qbman_swp_release_mem_back(struct qbman_swp *s,
++                                    const struct qbman_release_desc *d,
++                                    const u64 *buffers,
++                                    unsigned int num_buffers);
++
++/* Function pointers */
++int (*qbman_swp_enqueue_ptr)(struct qbman_swp *s,
++                           const struct qbman_eq_desc *d,
++                           const struct dpaa2_fd *fd)
++      = qbman_swp_enqueue_direct;
++
++int (*qbman_swp_enqueue_multiple_ptr)(struct qbman_swp *s,
++                                    const struct qbman_eq_desc *d,
++                                    const struct dpaa2_fd *fd,
++                                    uint32_t *flags,
++                                           int num_frames)
++      = qbman_swp_enqueue_multiple_direct;
++
++int
++(*qbman_swp_enqueue_multiple_desc_ptr)(struct qbman_swp *s,
++                                     const struct qbman_eq_desc *d,
++                                     const struct dpaa2_fd *fd,
++                                     int num_frames)
++      = qbman_swp_enqueue_multiple_desc_direct;
++
++int (*qbman_swp_pull_ptr)(struct qbman_swp *s, struct qbman_pull_desc *d)
++                      = qbman_swp_pull_direct;
++
++const struct dpaa2_dq *(*qbman_swp_dqrr_next_ptr)(struct qbman_swp *s)
++                      = qbman_swp_dqrr_next_direct;
++
++int (*qbman_swp_release_ptr)(struct qbman_swp *s,
++                           const struct qbman_release_desc *d,
++                           const u64 *buffers,
++                           unsigned int num_buffers)
++                      = qbman_swp_release_direct;
++
+ #define dccvac(p) { asm volatile("dc cvac, %0;" : : "r" (p) : "memory"); }
+ #define dcivac(p) { asm volatile("dc ivac, %0" : : "r"(p) : "memory"); }
+ static inline void qbman_inval_prefetch(struct qbman_swp *p, u32 offset)
+@@ -227,6 +303,19 @@ struct qbman_swp *qbman_swp_init(const s
+        * applied when dequeues from a specific channel are enabled.
+        */
+       qbman_write_register(p, QBMAN_CINH_SWP_SDQCR, 0);
++
++      if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) {
++              qbman_swp_enqueue_ptr =
++                      qbman_swp_enqueue_mem_back;
++              qbman_swp_enqueue_multiple_ptr =
++                      qbman_swp_enqueue_multiple_mem_back;
++              qbman_swp_enqueue_multiple_desc_ptr =
++                      qbman_swp_enqueue_multiple_desc_mem_back;
++              qbman_swp_pull_ptr = qbman_swp_pull_mem_back;
++              qbman_swp_dqrr_next_ptr = qbman_swp_dqrr_next_mem_back;
++              qbman_swp_release_ptr = qbman_swp_release_mem_back;
++      }
++
+       return p;
+ }
+@@ -494,7 +583,7 @@ static inline void qbman_write_eqcr_am_r
+ }
+ /**
+- * qbman_swp_enqueue() - Issue an enqueue command
++ * qbman_swp_enqueue_direct() - Issue an enqueue command
+  * @s:  the software portal used for enqueue
+  * @d:  the enqueue descriptor
+  * @fd: the frame descriptor to be enqueued
+@@ -504,7 +593,7 @@ static inline void qbman_write_eqcr_am_r
+  *
+  * Return 0 for successful enqueue, -EBUSY if the EQCR is not ready.
+  */
+-int qbman_swp_enqueue(struct qbman_swp *s, const struct qbman_eq_desc *d,
++int qbman_swp_enqueue_direct(struct qbman_swp *s, const struct qbman_eq_desc *d,
+                     const struct dpaa2_fd *fd)
+ {
+       struct qbman_eq_desc_with_fd *p;
+@@ -527,22 +616,58 @@ int qbman_swp_enqueue(struct qbman_swp *
+       memcpy(&p->desc.tgtid, &d->tgtid, 24);
+       memcpy(&p->fd, fd, sizeof(*fd));
+-      if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
+-              /* Set the verb byte, have to substitute in the valid-bit */
+-              dma_wmb();
+-              p->desc.verb = d->verb | EQAR_VB(eqar);
+-              dccvac(p);
+-      } else {
+-              p->desc.verb = d->verb | EQAR_VB(eqar);
+-              dma_wmb();
+-              qbman_write_eqcr_am_rt_register(s, EQAR_IDX(eqar));
+-      }
++      /* Set the verb byte, have to substitute in the valid-bit */
++      dma_wmb();
++      p->desc.verb = d->verb | EQAR_VB(eqar);
++      dccvac(p);
+       return 0;
+ }
+ /**
+- * qbman_swp_enqueue_multiple() - Issue a multi enqueue command
++ * qbman_swp_enqueue_mem_back() - Issue an enqueue command
++ * @s:  the software portal used for enqueue
++ * @d:  the enqueue descriptor
++ * @fd: the frame descriptor to be enqueued
++ *
++ * Please note that 'fd' should only be NULL if the "action" of the
++ * descriptor is "orp_hole" or "orp_nesn".
++ *
++ * Return 0 for successful enqueue, -EBUSY if the EQCR is not ready.
++ */
++int qbman_swp_enqueue_mem_back(struct qbman_swp *s,
++                             const struct qbman_eq_desc *d,
++                             const struct dpaa2_fd *fd)
++{
++      struct qbman_eq_desc_with_fd *p;
++      u32 eqar = qbman_read_register(s, QBMAN_CINH_SWP_EQAR);
++
++      if (!EQAR_SUCCESS(eqar))
++              return -EBUSY;
++
++      p = qbman_get_cmd(s, QBMAN_CENA_SWP_EQCR(EQAR_IDX(eqar)));
++      /* This is mapped as DEVICE type memory, writes are
++       * with address alignment:
++       * desc.dca address alignment = 1
++       * desc.seqnum address alignment = 2
++       * desc.orpid address alignment = 4
++       * desc.tgtid address alignment = 8
++       */
++      p->desc.dca = d->dca;
++      p->desc.seqnum = d->seqnum;
++      p->desc.orpid = d->orpid;
++      memcpy(&p->desc.tgtid, &d->tgtid, 24);
++      memcpy(&p->fd, fd, sizeof(*fd));
++
++      p->desc.verb = d->verb | EQAR_VB(eqar);
++      dma_wmb();
++      qbman_write_eqcr_am_rt_register(s, EQAR_IDX(eqar));
++
++      return 0;
++}
++
++/**
++ * qbman_swp_enqueue_multiple_direct() - Issue a multi enqueue command
+  * using one enqueue descriptor
+  * @s:  the software portal used for enqueue
+  * @d:  the enqueue descriptor
+@@ -552,16 +677,16 @@ int qbman_swp_enqueue(struct qbman_swp *
+  *
+  * Return the number of fd enqueued, or a negative error number.
+  */
+-int qbman_swp_enqueue_multiple(struct qbman_swp *s,
+-                             const struct qbman_eq_desc *d,
+-                             const struct dpaa2_fd *fd,
+-                             uint32_t *flags,
+-                             int num_frames)
++int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s,
++                                    const struct qbman_eq_desc *d,
++                                    const struct dpaa2_fd *fd,
++                                    uint32_t *flags,
++                                    int num_frames)
+ {
+       int count = 0;
+       while (count < num_frames) {
+-              if (qbman_swp_enqueue(s, d, fd) != 0)
++              if (qbman_swp_enqueue_direct(s, d, fd) != 0)
+                       break;
+               count++;
+       }
+@@ -570,7 +695,35 @@ int qbman_swp_enqueue_multiple(struct qb
+ }
+ /**
+- * qbman_swp_enqueue_multiple_desc() - Issue a multi enqueue command
++ * qbman_swp_enqueue_multiple_mem_back() - Issue a multi enqueue command
++ * using one enqueue descriptor
++ * @s:  the software portal used for enqueue
++ * @d:  the enqueue descriptor
++ * @fd: table pointer of frame descriptor table to be enqueued
++ * @flags: table pointer of flags, not used for the moment
++ * @num_frames: number of fd to be enqueued
++ *
++ * Return the number of fd enqueued, or a negative error number.
++ */
++int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s,
++                                    const struct qbman_eq_desc *d,
++                                    const struct dpaa2_fd *fd,
++                                    uint32_t *flags,
++                                    int num_frames)
++{
++      int count = 0;
++
++      while (count < num_frames) {
++              if (qbman_swp_enqueue_mem_back(s, d, fd) != 0)
++                      break;
++              count++;
++      }
++
++      return count;
++}
++
++/**
++ * qbman_swp_enqueue_multiple_desc_direct() - Issue a multi enqueue command
+  * using multiple enqueue descriptor
+  * @s:  the software portal used for enqueue
+  * @d:  table of minimal enqueue descriptor
+@@ -579,15 +732,41 @@ int qbman_swp_enqueue_multiple(struct qb
+  *
+  * Return the number of fd enqueued, or a negative error number.
+  */
+-int qbman_swp_enqueue_multiple_desc(struct qbman_swp *s,
+-                                  const struct qbman_eq_desc *d,
+-                                  const struct dpaa2_fd *fd,
+-                                  int num_frames)
++int qbman_swp_enqueue_multiple_desc_direct(struct qbman_swp *s,
++                                         const struct qbman_eq_desc *d,
++                                         const struct dpaa2_fd *fd,
++                                         int num_frames)
+ {
+       int count = 0;
+       while (count < num_frames) {
+-              if (qbman_swp_enqueue(s, &(d[count]), fd) != 0)
++              if (qbman_swp_enqueue_direct(s, &(d[count]), fd) != 0)
++                      break;
++              count++;
++      }
++
++      return count;
++}
++
++/**
++ * qbman_swp_enqueue_multiple_desc_mem_back() - Issue a multi enqueue command
++ * using multiple enqueue descriptor
++ * @s:  the software portal used for enqueue
++ * @d:  table of minimal enqueue descriptor
++ * @fd: table pointer of frame descriptor table to be enqueued
++ * @num_frames: number of fd to be enqueued
++ *
++ * Return the number of fd enqueued, or a negative error number.
++ */
++int qbman_swp_enqueue_multiple_desc_mem_back(struct qbman_swp *s,
++                                         const struct qbman_eq_desc *d,
++                                         const struct dpaa2_fd *fd,
++                                         int num_frames)
++{
++      int count = 0;
++
++      while (count < num_frames) {
++              if (qbman_swp_enqueue_mem_back(s, &(d[count]), fd) != 0)
+                       break;
+               count++;
+       }
+@@ -750,7 +929,7 @@ void qbman_pull_desc_set_channel(struct
+ }
+ /**
+- * qbman_swp_pull() - Issue the pull dequeue command
++ * qbman_swp_pull_direct() - Issue the pull dequeue command
+  * @s: the software portal object
+  * @d: the software portal descriptor which has been configured with
+  *     the set of qbman_pull_desc_set_*() calls
+@@ -758,7 +937,7 @@ void qbman_pull_desc_set_channel(struct
+  * Return 0 for success, and -EBUSY if the software portal is not ready
+  * to do pull dequeue.
+  */
+-int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d)
++int qbman_swp_pull_direct(struct qbman_swp *s, struct qbman_pull_desc *d)
+ {
+       struct qbman_pull_desc *p;
+@@ -776,19 +955,46 @@ int qbman_swp_pull(struct qbman_swp *s,
+       p->dq_src = d->dq_src;
+       p->rsp_addr = d->rsp_addr;
+       p->rsp_addr_virt = d->rsp_addr_virt;
++      dma_wmb();
++      /* Set the verb byte, have to substitute in the valid-bit */
++      p->verb = d->verb | s->vdq.valid_bit;
++      s->vdq.valid_bit ^= QB_VALID_BIT;
++      dccvac(p);
+-      if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
+-              dma_wmb();
+-              /* Set the verb byte, have to substitute in the valid-bit */
+-              p->verb = d->verb | s->vdq.valid_bit;
+-              s->vdq.valid_bit ^= QB_VALID_BIT;
+-              dccvac(p);
+-      } else {
+-              p->verb = d->verb | s->vdq.valid_bit;
+-              s->vdq.valid_bit ^= QB_VALID_BIT;
+-              dma_wmb();
+-              qbman_write_register(s, QBMAN_CINH_SWP_VDQCR_RT, QMAN_RT_MODE);
++      return 0;
++}
++
++/**
++ * qbman_swp_pull_mem_back() - Issue the pull dequeue command
++ * @s: the software portal object
++ * @d: the software portal descriptor which has been configured with
++ *     the set of qbman_pull_desc_set_*() calls
++ *
++ * Return 0 for success, and -EBUSY if the software portal is not ready
++ * to do pull dequeue.
++ */
++int qbman_swp_pull_mem_back(struct qbman_swp *s, struct qbman_pull_desc *d)
++{
++      struct qbman_pull_desc *p;
++
++      if (!atomic_dec_and_test(&s->vdq.available)) {
++              atomic_inc(&s->vdq.available);
++              return -EBUSY;
+       }
++      s->vdq.storage = (void *)(uintptr_t)d->rsp_addr_virt;
++      if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000)
++              p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR);
++      else
++              p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR_MEM);
++      p->numf = d->numf;
++      p->tok = QMAN_DQ_TOKEN_VALID;
++      p->dq_src = d->dq_src;
++      p->rsp_addr = d->rsp_addr;
++      p->rsp_addr_virt = d->rsp_addr_virt;
++      p->verb = d->verb | s->vdq.valid_bit;
++      s->vdq.valid_bit ^= QB_VALID_BIT;
++      dma_wmb();
++      qbman_write_register(s, QBMAN_CINH_SWP_VDQCR_RT, QMAN_RT_MODE);
+       return 0;
+ }
+@@ -796,14 +1002,14 @@ int qbman_swp_pull(struct qbman_swp *s,
+ #define QMAN_DQRR_PI_MASK   0xf
+ /**
+- * qbman_swp_dqrr_next() - Get an valid DQRR entry
++ * qbman_swp_dqrr_next_direct() - Get an valid DQRR entry
+  * @s: the software portal object
+  *
+  * Return NULL if there are no unconsumed DQRR entries. Return a DQRR entry
+  * only once, so repeated calls can return a sequence of DQRR entries, without
+  * requiring they be consumed immediately or in any particular order.
+  */
+-const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s)
++const struct dpaa2_dq *qbman_swp_dqrr_next_direct(struct qbman_swp *s)
+ {
+       u32 verb;
+       u32 response_verb;
+@@ -845,10 +1051,97 @@ const struct dpaa2_dq *qbman_swp_dqrr_ne
+               qbman_inval_prefetch(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
+       }
+-      if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000)
+-              p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
+-      else
+-              p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR_MEM(s->dqrr.next_idx));
++      p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
++      verb = p->dq.verb;
++
++      /*
++       * If the valid-bit isn't of the expected polarity, nothing there. Note,
++       * in the DQRR reset bug workaround, we shouldn't need to skip these
++       * check, because we've already determined that a new entry is available
++       * and we've invalidated the cacheline before reading it, so the
++       * valid-bit behaviour is repaired and should tell us what we already
++       * knew from reading PI.
++       */
++      if ((verb & QB_VALID_BIT) != s->dqrr.valid_bit) {
++              qbman_inval_prefetch(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
++              return NULL;
++      }
++      /*
++       * There's something there. Move "next_idx" attention to the next ring
++       * entry (and prefetch it) before returning what we found.
++       */
++      s->dqrr.next_idx++;
++      s->dqrr.next_idx &= s->dqrr.dqrr_size - 1; /* Wrap around */
++      if (!s->dqrr.next_idx)
++              s->dqrr.valid_bit ^= QB_VALID_BIT;
++
++      /*
++       * If this is the final response to a volatile dequeue command
++       * indicate that the vdq is available
++       */
++      flags = p->dq.stat;
++      response_verb = verb & QBMAN_RESULT_MASK;
++      if ((response_verb == QBMAN_RESULT_DQ) &&
++          (flags & DPAA2_DQ_STAT_VOLATILE) &&
++          (flags & DPAA2_DQ_STAT_EXPIRED))
++              atomic_inc(&s->vdq.available);
++
++      qbman_inval_prefetch(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
++
++      return p;
++}
++
++/**
++ * qbman_swp_dqrr_next_mem_back() - Get an valid DQRR entry
++ * @s: the software portal object
++ *
++ * Return NULL if there are no unconsumed DQRR entries. Return a DQRR entry
++ * only once, so repeated calls can return a sequence of DQRR entries, without
++ * requiring they be consumed immediately or in any particular order.
++ */
++const struct dpaa2_dq *qbman_swp_dqrr_next_mem_back(struct qbman_swp *s)
++{
++      u32 verb;
++      u32 response_verb;
++      u32 flags;
++      struct dpaa2_dq *p;
++
++      /* Before using valid-bit to detect if something is there, we have to
++       * handle the case of the DQRR reset bug...
++       */
++      if (unlikely(s->dqrr.reset_bug)) {
++              /*
++               * We pick up new entries by cache-inhibited producer index,
++               * which means that a non-coherent mapping would require us to
++               * invalidate and read *only* once that PI has indicated that
++               * there's an entry here. The first trip around the DQRR ring
++               * will be much less efficient than all subsequent trips around
++               * it...
++               */
++              u8 pi = qbman_read_register(s, QBMAN_CINH_SWP_DQPI) &
++                      QMAN_DQRR_PI_MASK;
++
++              /* there are new entries if pi != next_idx */
++              if (pi == s->dqrr.next_idx)
++                      return NULL;
++
++              /*
++               * if next_idx is/was the last ring index, and 'pi' is
++               * different, we can disable the workaround as all the ring
++               * entries have now been DMA'd to so valid-bit checking is
++               * repaired. Note: this logic needs to be based on next_idx
++               * (which increments one at a time), rather than on pi (which
++               * can burst and wrap-around between our snapshots of it).
++               */
++              if (s->dqrr.next_idx == (s->dqrr.dqrr_size - 1)) {
++                      pr_debug("next_idx=%d, pi=%d, clear reset bug\n",
++                               s->dqrr.next_idx, pi);
++                      s->dqrr.reset_bug = 0;
++              }
++              qbman_inval_prefetch(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
++      }
++
++      p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR_MEM(s->dqrr.next_idx));
+       verb = p->dq.verb;
+       /*
+@@ -976,7 +1269,7 @@ void qbman_release_desc_set_rcdi(struct
+ #define RAR_SUCCESS(rar) ((rar) & 0x100)
+ /**
+- * qbman_swp_release() - Issue a buffer release command
++ * qbman_swp_release_direct() - Issue a buffer release command
+  * @s:           the software portal object
+  * @d:           the release descriptor
+  * @buffers:     a pointer pointing to the buffer address to be released
+@@ -984,8 +1277,9 @@ void qbman_release_desc_set_rcdi(struct
+  *
+  * Return 0 for success, -EBUSY if the release command ring is not ready.
+  */
+-int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d,
+-                    const u64 *buffers, unsigned int num_buffers)
++int qbman_swp_release_direct(struct qbman_swp *s,
++                           const struct qbman_release_desc *d,
++                           const u64 *buffers, unsigned int num_buffers)
+ {
+       int i;
+       struct qbman_release_desc *p;
+@@ -999,29 +1293,60 @@ int qbman_swp_release(struct qbman_swp *
+               return -EBUSY;
+       /* Start the release command */
+-      if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000)
+-              p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR(RAR_IDX(rar)));
+-      else
+-              p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR_MEM(RAR_IDX(rar)));
++      p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR(RAR_IDX(rar)));
++
+       /* Copy the caller's buffer pointers to the command */
+       for (i = 0; i < num_buffers; i++)
+               p->buf[i] = cpu_to_le64(buffers[i]);
+       p->bpid = d->bpid;
+-      if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
+-              /*
+-               * Set the verb byte, have to substitute in the valid-bit
+-               * and the number of buffers.
+-               */
+-              dma_wmb();
+-              p->verb = d->verb | RAR_VB(rar) | num_buffers;
+-              dccvac(p);
+-      } else {
+-              p->verb = d->verb | RAR_VB(rar) | num_buffers;
+-              dma_wmb();
+-              qbman_write_register(s, QBMAN_CINH_SWP_RCR_AM_RT +
+-                                   RAR_IDX(rar)  * 4, QMAN_RT_MODE);
+-      }
++      /*
++       * Set the verb byte, have to substitute in the valid-bit
++       * and the number of buffers.
++       */
++      dma_wmb();
++      p->verb = d->verb | RAR_VB(rar) | num_buffers;
++      dccvac(p);
++
++      return 0;
++}
++
++/**
++ * qbman_swp_release_mem_back() - Issue a buffer release command
++ * @s:           the software portal object
++ * @d:           the release descriptor
++ * @buffers:     a pointer pointing to the buffer address to be released
++ * @num_buffers: number of buffers to be released,  must be less than 8
++ *
++ * Return 0 for success, -EBUSY if the release command ring is not ready.
++ */
++int qbman_swp_release_mem_back(struct qbman_swp *s,
++                             const struct qbman_release_desc *d,
++                             const u64 *buffers, unsigned int num_buffers)
++{
++      int i;
++      struct qbman_release_desc *p;
++      u32 rar;
++
++      if (!num_buffers || (num_buffers > 7))
++              return -EINVAL;
++
++      rar = qbman_read_register(s, QBMAN_CINH_SWP_RAR);
++      if (!RAR_SUCCESS(rar))
++              return -EBUSY;
++
++      /* Start the release command */
++      p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR_MEM(RAR_IDX(rar)));
++
++      /* Copy the caller's buffer pointers to the command */
++      for (i = 0; i < num_buffers; i++)
++              p->buf[i] = cpu_to_le64(buffers[i]);
++      p->bpid = d->bpid;
++
++      p->verb = d->verb | RAR_VB(rar) | num_buffers;
++      dma_wmb();
++      qbman_write_register(s, QBMAN_CINH_SWP_RCR_AM_RT +
++                           RAR_IDX(rar)  * 4, QMAN_RT_MODE);
+       return 0;
+ }
+--- a/drivers/soc/fsl/dpio/qbman-portal.h
++++ b/drivers/soc/fsl/dpio/qbman-portal.h
+@@ -145,6 +145,33 @@ struct qbman_swp {
+       } dqrr;
+ };
++/* Function pointers */
++extern
++int (*qbman_swp_enqueue_ptr)(struct qbman_swp *s,
++                           const struct qbman_eq_desc *d,
++                           const struct dpaa2_fd *fd);
++extern
++int (*qbman_swp_enqueue_multiple_ptr)(struct qbman_swp *s,
++                                    const struct qbman_eq_desc *d,
++                                    const struct dpaa2_fd *fd,
++                                    uint32_t *flags,
++                                    int num_frames);
++extern
++int (*qbman_swp_enqueue_multiple_desc_ptr)(struct qbman_swp *s,
++                                         const struct qbman_eq_desc *d,
++                                         const struct dpaa2_fd *fd,
++                                         int num_frames);
++extern
++int (*qbman_swp_pull_ptr)(struct qbman_swp *s, struct qbman_pull_desc *d);
++extern
++const struct dpaa2_dq *(*qbman_swp_dqrr_next_ptr)(struct qbman_swp *s);
++extern
++int (*qbman_swp_release_ptr)(struct qbman_swp *s,
++                           const struct qbman_release_desc *d,
++                           const u64 *buffers,
++                           unsigned int num_buffers);
++
++/* Functions */
+ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d);
+ void qbman_swp_finish(struct qbman_swp *p);
+ u32 qbman_swp_interrupt_read_status(struct qbman_swp *p);
+@@ -169,9 +196,6 @@ void qbman_pull_desc_set_wq(struct qbman
+ void qbman_pull_desc_set_channel(struct qbman_pull_desc *d, u32 chid,
+                                enum qbman_pull_type_e dct);
+-int qbman_swp_pull(struct qbman_swp *p, struct qbman_pull_desc *d);
+-
+-const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s);
+ void qbman_swp_dqrr_consume(struct qbman_swp *s, const struct dpaa2_dq *dq);
+ int qbman_result_has_new_result(struct qbman_swp *p, const struct dpaa2_dq *dq);
+@@ -186,17 +210,12 @@ void qbman_eq_desc_set_fq(struct qbman_e
+ void qbman_eq_desc_set_qd(struct qbman_eq_desc *d, u32 qdid,
+                         u32 qd_bin, u32 qd_prio);
+-int qbman_swp_enqueue(struct qbman_swp *p, const struct qbman_eq_desc *d,
+-                    const struct dpaa2_fd *fd);
+-
+ int qbman_orp_drop(struct qbman_swp *s, u16 orpid, u16 seqnum);
+ void qbman_release_desc_clear(struct qbman_release_desc *d);
+ void qbman_release_desc_set_bpid(struct qbman_release_desc *d, u16 bpid);
+ void qbman_release_desc_set_rcdi(struct qbman_release_desc *d, int enable);
+-int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d,
+-                    const u64 *buffers, unsigned int num_buffers);
+ int qbman_swp_acquire(struct qbman_swp *s, u16 bpid, u64 *buffers,
+                     unsigned int num_buffers);
+ int qbman_swp_alt_fq_state(struct qbman_swp *s, u32 fqid,
+@@ -209,18 +228,60 @@ void *qbman_swp_mc_start(struct qbman_sw
+ void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, u8 cmd_verb);
+ void *qbman_swp_mc_result(struct qbman_swp *p);
+-int
++/**
++ * qbman_swp_enqueue() - Issue an enqueue command
++ * @s:  the software portal used for enqueue
++ * @d:  the enqueue descriptor
++ * @fd: the frame descriptor to be enqueued
++ *
++ * Return 0 for successful enqueue, -EBUSY if the EQCR is not ready.
++ */
++static inline int
++qbman_swp_enqueue(struct qbman_swp *s, const struct qbman_eq_desc *d,
++                const struct dpaa2_fd *fd)
++{
++      return qbman_swp_enqueue_ptr(s, d, fd);
++}
++
++/**
++ * qbman_swp_enqueue_multiple() - Issue a multi enqueue command
++ * using one enqueue descriptor
++ * @s:  the software portal used for enqueue
++ * @d:  the enqueue descriptor
++ * @fd: table pointer of frame descriptor table to be enqueued
++ * @flags: table pointer of QBMAN_ENQUEUE_FLAG_DCA flags, not used if NULL
++ * @num_frames: number of fd to be enqueued
++ *
++ * Return the number of fd enqueued, or a negative error number.
++ */
++static inline int
+ qbman_swp_enqueue_multiple(struct qbman_swp *s,
+                          const struct qbman_eq_desc *d,
+                          const struct dpaa2_fd *fd,
+                          uint32_t *flags,
+-                         int num_frames);
++                         int num_frames)
++{
++      return qbman_swp_enqueue_multiple_ptr(s, d, fd, flags, num_frames);
++}
+-int
++/**
++ * qbman_swp_enqueue_multiple_desc() - Issue a multi enqueue command
++ * using multiple enqueue descriptor
++ * @s:  the software portal used for enqueue
++ * @d:  table of minimal enqueue descriptor
++ * @fd: table pointer of frame descriptor table to be enqueued
++ * @num_frames: number of fd to be enqueued
++ *
++ * Return the number of fd enqueued, or a negative error number.
++ */
++static inline int
+ qbman_swp_enqueue_multiple_desc(struct qbman_swp *s,
+                               const struct qbman_eq_desc *d,
+                               const struct dpaa2_fd *fd,
+-                              int num_frames);
++                              int num_frames)
++{
++      return qbman_swp_enqueue_multiple_desc_ptr(s, d, fd, num_frames);
++}
+ /**
+  * qbman_result_is_DQ() - check if the dequeue result is a dequeue response
+@@ -533,4 +594,49 @@ int qbman_bp_query(struct qbman_swp *s,
+ u32 qbman_bp_info_num_free_bufs(struct qbman_bp_query_rslt *a);
++/**
++ * qbman_swp_release() - Issue a buffer release command
++ * @s:           the software portal object
++ * @d:           the release descriptor
++ * @buffers:     a pointer pointing to the buffer address to be released
++ * @num_buffers: number of buffers to be released,  must be less than 8
++ *
++ * Return 0 for success, -EBUSY if the release command ring is not ready.
++ */
++static inline int qbman_swp_release(struct qbman_swp *s,
++                                  const struct qbman_release_desc *d,
++                                  const u64 *buffers,
++                                  unsigned int num_buffers)
++{
++      return qbman_swp_release_ptr(s, d, buffers, num_buffers);
++}
++
++/**
++ * qbman_swp_pull() - Issue the pull dequeue command
++ * @s: the software portal object
++ * @d: the software portal descriptor which has been configured with
++ *     the set of qbman_pull_desc_set_*() calls
++ *
++ * Return 0 for success, and -EBUSY if the software portal is not ready
++ * to do pull dequeue.
++ */
++static inline int qbman_swp_pull(struct qbman_swp *s,
++                               struct qbman_pull_desc *d)
++{
++      return qbman_swp_pull_ptr(s, d);
++}
++
++/**
++ * qbman_swp_dqrr_next() - Get an valid DQRR entry
++ * @s: the software portal object
++ *
++ * Return NULL if there are no unconsumed DQRR entries. Return a DQRR entry
++ * only once, so repeated calls can return a sequence of DQRR entries, without
++ * requiring they be consumed immediately or in any particular order.
++ */
++static inline const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s)
++{
++      return qbman_swp_dqrr_next_ptr(s);
++}
++
+ #endif /* __FSL_QBMAN_PORTAL_H */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0223-soc-fsl-dpio-Replace-QMAN-array-mode-by-ring-mode-en.patch b/target/linux/layerscape/patches-5.4/701-net-0223-soc-fsl-dpio-Replace-QMAN-array-mode-by-ring-mode-en.patch
new file mode 100644 (file)
index 0000000..f287cab
--- /dev/null
@@ -0,0 +1,649 @@
+From 0b8c6bbb0a561f15598f6701089a992bdea3963c Mon Sep 17 00:00:00 2001
+From: Youri Querry <youri.querry_1@nxp.com>
+Date: Mon, 4 Nov 2019 11:03:09 -0500
+Subject: [PATCH] soc: fsl: dpio: Replace QMAN array mode by ring mode enqueue.
+
+This change of algorithm will enable faster bulk enqueue.
+This will grately benefit XDP bulk enqueue.
+
+Signed-off-by: Youri Querry <youri.querry_1@nxp.com>
+---
+ drivers/soc/fsl/dpio/qbman-portal.c | 420 +++++++++++++++++++++++++++---------
+ drivers/soc/fsl/dpio/qbman-portal.h |  13 ++
+ 2 files changed, 335 insertions(+), 98 deletions(-)
+
+--- a/drivers/soc/fsl/dpio/qbman-portal.c
++++ b/drivers/soc/fsl/dpio/qbman-portal.c
+@@ -8,6 +8,7 @@
+ #include <asm/cacheflush.h>
+ #include <linux/io.h>
+ #include <linux/slab.h>
++#include <linux/spinlock.h>
+ #include <soc/fsl/dpaa2-global.h>
+ #include "qbman-portal.h"
+@@ -22,6 +23,7 @@
+ /* CINH register offsets */
+ #define QBMAN_CINH_SWP_EQCR_PI      0x800
++#define QBMAN_CINH_SWP_EQCR_CI            0x840
+ #define QBMAN_CINH_SWP_EQAR    0x8c0
+ #define QBMAN_CINH_SWP_CR_RT        0x900
+ #define QBMAN_CINH_SWP_VDQCR_RT     0x940
+@@ -45,6 +47,8 @@
+ #define QBMAN_CENA_SWP_CR      0x600
+ #define QBMAN_CENA_SWP_RR(vb)  (0x700 + ((u32)(vb) >> 1))
+ #define QBMAN_CENA_SWP_VDQCR   0x780
++#define QBMAN_CENA_SWP_EQCR_CI 0x840
++#define QBMAN_CENA_SWP_EQCR_CI_MEMBACK 0x1840
+ /* CENA register offsets in memory-backed mode */
+ #define QBMAN_CENA_SWP_DQRR_MEM(n)  (0x800 + ((u32)(n) << 6))
+@@ -72,6 +76,12 @@
+ /* opaque token for static dequeues */
+ #define QMAN_SDQCR_TOKEN    0xbb
++#define QBMAN_EQCR_DCA_IDXMASK          0x0f
++#define QBMAN_ENQUEUE_FLAG_DCA          (1ULL << 31)
++
++#define EQ_DESC_SIZE_WITHOUT_FD 29
++#define EQ_DESC_SIZE_FD_START 32
++
+ enum qbman_sdqcr_dct {
+       qbman_sdqcr_dct_null = 0,
+       qbman_sdqcr_dct_prio_ics,
+@@ -224,6 +234,15 @@ static inline u32 qbman_set_swp_cfg(u8 m
+ #define QMAN_RT_MODE     0x00000100
++static inline u8 qm_cyc_diff(u8 ringsize, u8 first, u8 last)
++{
++      /* 'first' is included, 'last' is excluded */
++      if (first <= last)
++              return last - first;
++      else
++              return (2 * ringsize) - (first - last);
++}
++
+ /**
+  * qbman_swp_init() - Create a functional object representing the given
+  *                    QBMan portal descriptor.
+@@ -236,6 +255,10 @@ struct qbman_swp *qbman_swp_init(const s
+ {
+       struct qbman_swp *p = kzalloc(sizeof(*p), GFP_KERNEL);
+       u32 reg;
++      u32 mask_size;
++      u32 eqcr_pi;
++
++      spin_lock_init(&p->access_spinlock);
+       if (!p)
+               return NULL;
+@@ -264,25 +287,38 @@ struct qbman_swp *qbman_swp_init(const s
+       p->addr_cena = d->cena_bar;
+       p->addr_cinh = d->cinh_bar;
+-      if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000)
+-              memset(p->addr_cena, 0, 64 * 1024);
++      if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
+-      reg = qbman_set_swp_cfg(p->dqrr.dqrr_size,
+-                              0, /* Writes cacheable */
+-                              0, /* EQCR_CI stashing threshold */
+-                              3, /* RPM: Valid bit mode, RCR in array mode */
+-                              2, /* DCM: Discrete consumption ack mode */
+-                              3, /* EPM: Valid bit mode, EQCR in array mode */
+-                              1, /* mem stashing drop enable == TRUE */
+-                              1, /* mem stashing priority == TRUE */
+-                              1, /* mem stashing enable == TRUE */
+-                              1, /* dequeue stashing priority == TRUE */
+-                              0, /* dequeue stashing enable == FALSE */
+-                              0); /* EQCR_CI stashing priority == FALSE */
+-      if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000)
++              reg = qbman_set_swp_cfg(p->dqrr.dqrr_size,
++                      0, /* Writes Non-cacheable */
++                      0, /* EQCR_CI stashing threshold */
++                      3, /* RPM: RCR in array mode */
++                      2, /* DCM: Discrete consumption ack */
++                      2, /* EPM: EQCR in ring mode */
++                      1, /* mem stashing drop enable enable */
++                      1, /* mem stashing priority enable */
++                      1, /* mem stashing enable */
++                      1, /* dequeue stashing priority enable */
++                      0, /* dequeue stashing enable enable */
++                      0); /* EQCR_CI stashing priority enable */
++      } else {
++              memset(p->addr_cena, 0, 64 * 1024);
++              reg = qbman_set_swp_cfg(p->dqrr.dqrr_size,
++                      0, /* Writes Non-cacheable */
++                      1, /* EQCR_CI stashing threshold */
++                      3, /* RPM: RCR in array mode */
++                      2, /* DCM: Discrete consumption ack */
++                      0, /* EPM: EQCR in ring mode */
++                      1, /* mem stashing drop enable */
++                      1, /* mem stashing priority enable */
++                      1, /* mem stashing enable */
++                      1, /* dequeue stashing priority enable */
++                      0, /* dequeue stashing enable */
++                      0); /* EQCR_CI stashing priority enable */
+               reg |= 1 << SWP_CFG_CPBS_SHIFT | /* memory-backed mode */
+                      1 << SWP_CFG_VPM_SHIFT |  /* VDQCR read triggered mode */
+                      1 << SWP_CFG_CPM_SHIFT;   /* CR read triggered mode */
++      }
+       qbman_write_register(p, QBMAN_CINH_SWP_CFG, reg);
+       reg = qbman_read_register(p, QBMAN_CINH_SWP_CFG);
+@@ -304,7 +340,9 @@ struct qbman_swp *qbman_swp_init(const s
+        */
+       qbman_write_register(p, QBMAN_CINH_SWP_SDQCR, 0);
++      p->eqcr.pi_ring_size = 8;
+       if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) {
++              p->eqcr.pi_ring_size = 32;
+               qbman_swp_enqueue_ptr =
+                       qbman_swp_enqueue_mem_back;
+               qbman_swp_enqueue_multiple_ptr =
+@@ -316,6 +354,15 @@ struct qbman_swp *qbman_swp_init(const s
+               qbman_swp_release_ptr = qbman_swp_release_mem_back;
+       }
++      for (mask_size = p->eqcr.pi_ring_size; mask_size > 0; mask_size >>= 1)
++              p->eqcr.pi_ci_mask = (p->eqcr.pi_ci_mask << 1) + 1;
++      eqcr_pi = qbman_read_register(p, QBMAN_CINH_SWP_EQCR_PI);
++      p->eqcr.pi = eqcr_pi & p->eqcr.pi_ci_mask;
++      p->eqcr.pi_vb = eqcr_pi & QB_VALID_BIT;
++      p->eqcr.ci = qbman_read_register(p, QBMAN_CINH_SWP_EQCR_CI)
++                      & p->eqcr.pi_ci_mask;
++      p->eqcr.available = p->eqcr.pi_ring_size;
++
+       return p;
+ }
+@@ -468,8 +515,9 @@ enum qb_enqueue_commands {
+       enqueue_rejects_to_fq = 2
+ };
+-#define QB_ENQUEUE_CMD_ORP_ENABLE_SHIFT      2
+-#define QB_ENQUEUE_CMD_TARGET_TYPE_SHIFT     4
++#define QB_ENQUEUE_CMD_ORP_ENABLE_SHIFT         2
++#define QB_ENQUEUE_CMD_TARGET_TYPE_SHIFT        4
++#define QB_ENQUEUE_CMD_DCA_EN_SHIFT             7
+ /**
+  * qbman_eq_desc_clear() - Clear the contents of a descriptor to
+@@ -582,6 +630,7 @@ static inline void qbman_write_eqcr_am_r
+                                    QMAN_RT_MODE);
+ }
++#define QB_RT_BIT ((u32)0x100)
+ /**
+  * qbman_swp_enqueue_direct() - Issue an enqueue command
+  * @s:  the software portal used for enqueue
+@@ -593,35 +642,19 @@ static inline void qbman_write_eqcr_am_r
+  *
+  * Return 0 for successful enqueue, -EBUSY if the EQCR is not ready.
+  */
+-int qbman_swp_enqueue_direct(struct qbman_swp *s, const struct qbman_eq_desc *d,
+-                    const struct dpaa2_fd *fd)
++static
++int qbman_swp_enqueue_direct(struct qbman_swp *s,
++                           const struct qbman_eq_desc *d,
++                           const struct dpaa2_fd *fd)
+ {
+-      struct qbman_eq_desc_with_fd *p;
+-      u32 eqar = qbman_read_register(s, QBMAN_CINH_SWP_EQAR);
+-
+-      if (!EQAR_SUCCESS(eqar))
+-              return -EBUSY;
++      int flags = 0;
++      int ret = qbman_swp_enqueue_multiple_direct(s, d, fd, &flags, 1);
+-      p = qbman_get_cmd(s, QBMAN_CENA_SWP_EQCR(EQAR_IDX(eqar)));
+-      /* This is mapped as DEVICE type memory, writes are
+-       * with address alignment:
+-       * desc.dca address alignment = 1
+-       * desc.seqnum address alignment = 2
+-       * desc.orpid address alignment = 4
+-       * desc.tgtid address alignment = 8
+-       */
+-      p->desc.dca = d->dca;
+-      p->desc.seqnum = d->seqnum;
+-      p->desc.orpid = d->orpid;
+-      memcpy(&p->desc.tgtid, &d->tgtid, 24);
+-      memcpy(&p->fd, fd, sizeof(*fd));
+-
+-      /* Set the verb byte, have to substitute in the valid-bit */
+-      dma_wmb();
+-      p->desc.verb = d->verb | EQAR_VB(eqar);
+-      dccvac(p);
+-
+-      return 0;
++      if (ret >= 0)
++              ret = 0;
++      else
++              ret = -EBUSY;
++      return  ret;
+ }
+ /**
+@@ -635,35 +668,19 @@ int qbman_swp_enqueue_direct(struct qbma
+  *
+  * Return 0 for successful enqueue, -EBUSY if the EQCR is not ready.
+  */
++static
+ int qbman_swp_enqueue_mem_back(struct qbman_swp *s,
+                              const struct qbman_eq_desc *d,
+                              const struct dpaa2_fd *fd)
+ {
+-      struct qbman_eq_desc_with_fd *p;
+-      u32 eqar = qbman_read_register(s, QBMAN_CINH_SWP_EQAR);
+-
+-      if (!EQAR_SUCCESS(eqar))
+-              return -EBUSY;
+-
+-      p = qbman_get_cmd(s, QBMAN_CENA_SWP_EQCR(EQAR_IDX(eqar)));
+-      /* This is mapped as DEVICE type memory, writes are
+-       * with address alignment:
+-       * desc.dca address alignment = 1
+-       * desc.seqnum address alignment = 2
+-       * desc.orpid address alignment = 4
+-       * desc.tgtid address alignment = 8
+-       */
+-      p->desc.dca = d->dca;
+-      p->desc.seqnum = d->seqnum;
+-      p->desc.orpid = d->orpid;
+-      memcpy(&p->desc.tgtid, &d->tgtid, 24);
+-      memcpy(&p->fd, fd, sizeof(*fd));
+-
+-      p->desc.verb = d->verb | EQAR_VB(eqar);
+-      dma_wmb();
+-      qbman_write_eqcr_am_rt_register(s, EQAR_IDX(eqar));
++      int flags = 0;
++      int ret = qbman_swp_enqueue_multiple_mem_back(s, d, fd, &flags, 1);
+-      return 0;
++      if (ret >= 0)
++              ret = 0;
++      else
++              ret = -EBUSY;
++      return  ret;
+ }
+ /**
+@@ -672,26 +689,84 @@ int qbman_swp_enqueue_mem_back(struct qb
+  * @s:  the software portal used for enqueue
+  * @d:  the enqueue descriptor
+  * @fd: table pointer of frame descriptor table to be enqueued
+- * @flags: table pointer of flags, not used for the moment
++ * @flags: table pointer of QBMAN_ENQUEUE_FLAG_DCA flags, not used if NULL
+  * @num_frames: number of fd to be enqueued
+  *
+  * Return the number of fd enqueued, or a negative error number.
+  */
++static
+ int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s,
+                                     const struct qbman_eq_desc *d,
+                                     const struct dpaa2_fd *fd,
+                                     uint32_t *flags,
+                                     int num_frames)
+ {
+-      int count = 0;
++      uint32_t *p = NULL;
++      const uint32_t *cl = (uint32_t *)d;
++      uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask;
++      int i, num_enqueued = 0;
++      uint64_t addr_cena;
++
++      spin_lock(&s->access_spinlock);
++      half_mask = (s->eqcr.pi_ci_mask>>1);
++      full_mask = s->eqcr.pi_ci_mask;
++
++      if (!s->eqcr.available) {
++              eqcr_ci = s->eqcr.ci;
++              p = s->addr_cena + QBMAN_CENA_SWP_EQCR_CI;
++              s->eqcr.ci = qbman_read_register(s, QBMAN_CINH_SWP_EQCR_CI);
++
++              s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size,
++                                      eqcr_ci, s->eqcr.ci);
++              if (!s->eqcr.available) {
++                      spin_unlock(&s->access_spinlock);
++                      return 0;
++              }
++      }
+-      while (count < num_frames) {
+-              if (qbman_swp_enqueue_direct(s, d, fd) != 0)
+-                      break;
+-              count++;
++      eqcr_pi = s->eqcr.pi;
++      num_enqueued = (s->eqcr.available < num_frames) ?
++                      s->eqcr.available : num_frames;
++      s->eqcr.available -= num_enqueued;
++      /* Fill in the EQCR ring */
++      for (i = 0; i < num_enqueued; i++) {
++              p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
++              /* Skip copying the verb */
++              memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1);
++              memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)],
++                     &fd[i], sizeof(*fd));
++              eqcr_pi++;
+       }
+-      return count;
++      dma_wmb();
++
++      /* Set the verb byte, have to substitute in the valid-bit */
++      eqcr_pi = s->eqcr.pi;
++      for (i = 0; i < num_enqueued; i++) {
++              p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
++              p[0] = cl[0] | s->eqcr.pi_vb;
++              if (flags && (flags[i] & QBMAN_ENQUEUE_FLAG_DCA)) {
++                      struct qbman_eq_desc *d = (struct qbman_eq_desc *)p;
++
++                      d->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) |
++                              ((flags[i]) & QBMAN_EQCR_DCA_IDXMASK);
++              }
++              eqcr_pi++;
++              if (!(eqcr_pi & half_mask))
++                      s->eqcr.pi_vb ^= QB_VALID_BIT;
++      }
++
++      /* Flush all the cacheline without load/store in between */
++      eqcr_pi = s->eqcr.pi;
++      addr_cena = (size_t)s->addr_cena;
++      for (i = 0; i < num_enqueued; i++) {
++              dccvac((addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)));
++              eqcr_pi++;
++      }
++      s->eqcr.pi = eqcr_pi & full_mask;
++      spin_unlock(&s->access_spinlock);
++
++      return num_enqueued;
+ }
+ /**
+@@ -700,26 +775,80 @@ int qbman_swp_enqueue_multiple_direct(st
+  * @s:  the software portal used for enqueue
+  * @d:  the enqueue descriptor
+  * @fd: table pointer of frame descriptor table to be enqueued
+- * @flags: table pointer of flags, not used for the moment
++ * @flags: table pointer of QBMAN_ENQUEUE_FLAG_DCA flags, not used if NULL
+  * @num_frames: number of fd to be enqueued
+  *
+  * Return the number of fd enqueued, or a negative error number.
+  */
++static
+ int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s,
+-                                    const struct qbman_eq_desc *d,
+-                                    const struct dpaa2_fd *fd,
+-                                    uint32_t *flags,
+-                                    int num_frames)
+-{
+-      int count = 0;
++                                      const struct qbman_eq_desc *d,
++                                      const struct dpaa2_fd *fd,
++                                      uint32_t *flags,
++                                      int num_frames)
++{
++      uint32_t *p = NULL;
++      const uint32_t *cl = (uint32_t *)(d);
++      uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask;
++      int i, num_enqueued = 0;
++      unsigned long irq_flags;
++
++      spin_lock(&s->access_spinlock);
++      local_irq_save(irq_flags);
++
++      half_mask = (s->eqcr.pi_ci_mask>>1);
++      full_mask = s->eqcr.pi_ci_mask;
++      if (!s->eqcr.available) {
++              eqcr_ci = s->eqcr.ci;
++              p = s->addr_cena + QBMAN_CENA_SWP_EQCR_CI_MEMBACK;
++              s->eqcr.ci = __raw_readl(p) & full_mask;
++              s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size,
++                                      eqcr_ci, s->eqcr.ci);
++              if (!s->eqcr.available) {
++                      local_irq_restore(irq_flags);
++                      spin_unlock(&s->access_spinlock);
++                      return 0;
++              }
++      }
++
++      eqcr_pi = s->eqcr.pi;
++      num_enqueued = (s->eqcr.available < num_frames) ?
++                      s->eqcr.available : num_frames;
++      s->eqcr.available -= num_enqueued;
++      /* Fill in the EQCR ring */
++      for (i = 0; i < num_enqueued; i++) {
++              p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
++              /* Skip copying the verb */
++              memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1);
++              memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)],
++                     &fd[i], sizeof(*fd));
++              eqcr_pi++;
++      }
+-      while (count < num_frames) {
+-              if (qbman_swp_enqueue_mem_back(s, d, fd) != 0)
+-                      break;
+-              count++;
++      /* Set the verb byte, have to substitute in the valid-bit */
++      eqcr_pi = s->eqcr.pi;
++      for (i = 0; i < num_enqueued; i++) {
++              p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
++              p[0] = cl[0] | s->eqcr.pi_vb;
++              if (flags && (flags[i] & QBMAN_ENQUEUE_FLAG_DCA)) {
++                      struct qbman_eq_desc *d = (struct qbman_eq_desc *)p;
++
++                      d->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) |
++                              ((flags[i]) & QBMAN_EQCR_DCA_IDXMASK);
++              }
++              eqcr_pi++;
++              if (!(eqcr_pi & half_mask))
++                      s->eqcr.pi_vb ^= QB_VALID_BIT;
+       }
++      s->eqcr.pi = eqcr_pi & full_mask;
++
++      dma_wmb();
++      qbman_write_register(s, QBMAN_CINH_SWP_EQCR_PI,
++                              (QB_RT_BIT)|(s->eqcr.pi)|s->eqcr.pi_vb);
++      local_irq_restore(irq_flags);
++      spin_unlock(&s->access_spinlock);
+-      return count;
++      return num_enqueued;
+ }
+ /**
+@@ -732,20 +861,69 @@ int qbman_swp_enqueue_multiple_mem_back(
+  *
+  * Return the number of fd enqueued, or a negative error number.
+  */
++static
+ int qbman_swp_enqueue_multiple_desc_direct(struct qbman_swp *s,
+                                          const struct qbman_eq_desc *d,
+                                          const struct dpaa2_fd *fd,
+                                          int num_frames)
+ {
+-      int count = 0;
++      uint32_t *p;
++      const uint32_t *cl;
++      uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask;
++      int i, num_enqueued = 0;
++      uint64_t addr_cena;
++
++      half_mask = (s->eqcr.pi_ci_mask>>1);
++      full_mask = s->eqcr.pi_ci_mask;
++      if (!s->eqcr.available) {
++              eqcr_ci = s->eqcr.ci;
++              p = s->addr_cena + QBMAN_CENA_SWP_EQCR_CI;
++              s->eqcr.ci = qbman_read_register(s, QBMAN_CINH_SWP_EQCR_CI);
++              s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size,
++                                      eqcr_ci, s->eqcr.ci);
++              if (!s->eqcr.available)
++                      return 0;
++      }
+-      while (count < num_frames) {
+-              if (qbman_swp_enqueue_direct(s, &(d[count]), fd) != 0)
+-                      break;
+-              count++;
++      eqcr_pi = s->eqcr.pi;
++      num_enqueued = (s->eqcr.available < num_frames) ?
++                      s->eqcr.available : num_frames;
++      s->eqcr.available -= num_enqueued;
++      /* Fill in the EQCR ring */
++      for (i = 0; i < num_enqueued; i++) {
++              p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
++              cl = (uint32_t *)(&d[i]);
++              /* Skip copying the verb */
++              memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1);
++              memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)],
++                     &fd[i], sizeof(*fd));
++              eqcr_pi++;
+       }
+-      return count;
++      dma_wmb();
++
++      /* Set the verb byte, have to substitute in the valid-bit */
++      eqcr_pi = s->eqcr.pi;
++      for (i = 0; i < num_enqueued; i++) {
++              p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
++              cl = (uint32_t *)(&d[i]);
++              p[0] = cl[0] | s->eqcr.pi_vb;
++              eqcr_pi++;
++              if (!(eqcr_pi & half_mask))
++                      s->eqcr.pi_vb ^= QB_VALID_BIT;
++      }
++
++      /* Flush all the cacheline without load/store in between */
++      eqcr_pi = s->eqcr.pi;
++      addr_cena = (uint64_t)s->addr_cena;
++      for (i = 0; i < num_enqueued; i++) {
++              dccvac((uint64_t *)(addr_cena +
++                      QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)));
++              eqcr_pi++;
++      }
++      s->eqcr.pi = eqcr_pi & full_mask;
++
++      return num_enqueued;
+ }
+ /**
+@@ -758,20 +936,62 @@ int qbman_swp_enqueue_multiple_desc_dire
+  *
+  * Return the number of fd enqueued, or a negative error number.
+  */
++static
+ int qbman_swp_enqueue_multiple_desc_mem_back(struct qbman_swp *s,
+                                          const struct qbman_eq_desc *d,
+                                          const struct dpaa2_fd *fd,
+                                          int num_frames)
+ {
+-      int count = 0;
++      uint32_t *p;
++      const uint32_t *cl;
++      uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask;
++      int i, num_enqueued = 0;
++
++      half_mask = (s->eqcr.pi_ci_mask>>1);
++      full_mask = s->eqcr.pi_ci_mask;
++      if (!s->eqcr.available) {
++              eqcr_ci = s->eqcr.ci;
++              p = s->addr_cena + QBMAN_CENA_SWP_EQCR_CI_MEMBACK;
++              s->eqcr.ci = __raw_readl(p) & full_mask;
++              s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size,
++                                      eqcr_ci, s->eqcr.ci);
++              if (!s->eqcr.available)
++                      return 0;
++      }
+-      while (count < num_frames) {
+-              if (qbman_swp_enqueue_mem_back(s, &(d[count]), fd) != 0)
+-                      break;
+-              count++;
++      eqcr_pi = s->eqcr.pi;
++      num_enqueued = (s->eqcr.available < num_frames) ?
++                      s->eqcr.available : num_frames;
++      s->eqcr.available -= num_enqueued;
++      /* Fill in the EQCR ring */
++      for (i = 0; i < num_enqueued; i++) {
++              p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
++              cl = (uint32_t *)(&d[i]);
++              /* Skip copying the verb */
++              memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1);
++              memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)],
++                     &fd[i], sizeof(*fd));
++              eqcr_pi++;
+       }
+-      return count;
++      /* Set the verb byte, have to substitute in the valid-bit */
++      eqcr_pi = s->eqcr.pi;
++      for (i = 0; i < num_enqueued; i++) {
++              p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
++              cl = (uint32_t *)(&d[i]);
++              p[0] = cl[0] | s->eqcr.pi_vb;
++              eqcr_pi++;
++              if (!(eqcr_pi & half_mask))
++                      s->eqcr.pi_vb ^= QB_VALID_BIT;
++      }
++
++      s->eqcr.pi = eqcr_pi & full_mask;
++
++      dma_wmb();
++      qbman_write_register(s, QBMAN_CINH_SWP_EQCR_PI,
++                              (QB_RT_BIT)|(s->eqcr.pi)|s->eqcr.pi_vb);
++
++      return num_enqueued;
+ }
+ /* Static (push) dequeue */
+@@ -937,6 +1157,7 @@ void qbman_pull_desc_set_channel(struct
+  * Return 0 for success, and -EBUSY if the software portal is not ready
+  * to do pull dequeue.
+  */
++static
+ int qbman_swp_pull_direct(struct qbman_swp *s, struct qbman_pull_desc *d)
+ {
+       struct qbman_pull_desc *p;
+@@ -973,6 +1194,7 @@ int qbman_swp_pull_direct(struct qbman_s
+  * Return 0 for success, and -EBUSY if the software portal is not ready
+  * to do pull dequeue.
+  */
++static
+ int qbman_swp_pull_mem_back(struct qbman_swp *s, struct qbman_pull_desc *d)
+ {
+       struct qbman_pull_desc *p;
+@@ -991,6 +1213,8 @@ int qbman_swp_pull_mem_back(struct qbman
+       p->dq_src = d->dq_src;
+       p->rsp_addr = d->rsp_addr;
+       p->rsp_addr_virt = d->rsp_addr_virt;
++
++      /* Set the verb byte, have to substitute in the valid-bit */
+       p->verb = d->verb | s->vdq.valid_bit;
+       s->vdq.valid_bit ^= QB_VALID_BIT;
+       dma_wmb();
+--- a/drivers/soc/fsl/dpio/qbman-portal.h
++++ b/drivers/soc/fsl/dpio/qbman-portal.h
+@@ -143,6 +143,19 @@ struct qbman_swp {
+               u8 dqrr_size;
+               int reset_bug; /* indicates dqrr reset workaround is needed */
+       } dqrr;
++
++      struct {
++              u32 pi;
++              u32 pi_vb;
++              u32 pi_ring_size;
++              u32 pi_ci_mask;
++              u32 ci;
++              int available;
++              u32 pend;
++              u32 no_pfdr;
++      } eqcr;
++
++      spinlock_t access_spinlock;
+ };
+ /* Function pointers */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0224-bus-fsl-mc-add-autorescan-sysfs.patch b/target/linux/layerscape/patches-5.4/701-net-0224-bus-fsl-mc-add-autorescan-sysfs.patch
new file mode 100644 (file)
index 0000000..6128e7d
--- /dev/null
@@ -0,0 +1,157 @@
+From 02e92b21edb4df7285f27ea5f0403377dcabe22d Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Tue, 29 Oct 2019 22:48:55 +0200
+Subject: [PATCH] bus: fsl-mc: add autorescan sysfs
+
+Add the autorescan sysfs in order to enable/disable the DPRC IRQs on
+which automatic rescan of the bus is performed. This is important when
+dynamic creation of objects is needed to happen in a timely manner because
+object creation can be bundled together.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+---
+ drivers/bus/fsl-mc/dprc-driver.c    | 17 ++++++++++--
+ drivers/bus/fsl-mc/fsl-mc-bus.c     | 55 +++++++++++++++++++++++++++++++++++++
+ drivers/bus/fsl-mc/fsl-mc-private.h |  4 +++
+ include/linux/fsl/mc.h              |  1 +
+ 4 files changed, 75 insertions(+), 2 deletions(-)
+
+--- a/drivers/bus/fsl-mc/dprc-driver.c
++++ b/drivers/bus/fsl-mc/dprc-driver.c
+@@ -484,8 +484,9 @@ out:
+ /*
+  * Disable and clear interrupt for a given DPRC object
+  */
+-static int disable_dprc_irq(struct fsl_mc_device *mc_dev)
++int disable_dprc_irq(struct fsl_mc_device *mc_dev)
+ {
++      struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
+       int error;
+       struct fsl_mc_io *mc_io = mc_dev->mc_io;
+@@ -522,9 +523,18 @@ static int disable_dprc_irq(struct fsl_m
+               return error;
+       }
++      mc_bus->irq_enabled = 0;
++
+       return 0;
+ }
++int get_dprc_irq_state(struct fsl_mc_device *mc_dev)
++{
++      struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
++
++      return mc_bus->irq_enabled;
++}
++
+ static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev)
+ {
+       int error;
+@@ -551,8 +561,9 @@ static int register_dprc_irq_handler(str
+       return 0;
+ }
+-static int enable_dprc_irq(struct fsl_mc_device *mc_dev)
++int enable_dprc_irq(struct fsl_mc_device *mc_dev)
+ {
++      struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
+       int error;
+       /*
+@@ -580,6 +591,8 @@ static int enable_dprc_irq(struct fsl_mc
+               return error;
+       }
++      mc_bus->irq_enabled = 1;
++
+       return 0;
+ }
+--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
+@@ -237,8 +237,63 @@ static ssize_t rescan_store(struct bus_t
+ }
+ static BUS_ATTR_WO(rescan);
++static int fsl_mc_bus_set_autorescan(struct device *dev, void *data)
++{
++      struct fsl_mc_device *root_mc_dev;
++      unsigned long val;
++      char *buf = data;
++
++      if (!fsl_mc_is_root_dprc(dev))
++              goto exit;
++
++      root_mc_dev = to_fsl_mc_device(dev);
++
++      if (kstrtoul(buf, 0, &val) < 0)
++              return -EINVAL;
++
++      if (val)
++              enable_dprc_irq(root_mc_dev);
++      else
++              disable_dprc_irq(root_mc_dev);
++
++exit:
++      return 0;
++}
++
++static int fsl_mc_bus_get_autorescan(struct device *dev, void *data)
++{
++      struct fsl_mc_device *root_mc_dev;
++      char *buf = data;
++
++      if (!fsl_mc_is_root_dprc(dev))
++              goto exit;
++
++      root_mc_dev = to_fsl_mc_device(dev);
++
++      sprintf(buf, "%d\n", get_dprc_irq_state(root_mc_dev));
++exit:
++      return 0;
++}
++
++static ssize_t autorescan_store(struct bus_type *bus,
++                              const char *buf, size_t count)
++{
++      bus_for_each_dev(bus, NULL, (void *)buf, fsl_mc_bus_set_autorescan);
++
++      return count;
++}
++
++static ssize_t autorescan_show(struct bus_type *bus, char *buf)
++{
++      bus_for_each_dev(bus, NULL, (void *)buf, fsl_mc_bus_get_autorescan);
++      return strlen(buf);
++}
++
++static BUS_ATTR_RW(autorescan);
++
+ static struct attribute *fsl_mc_bus_attrs[] = {
+       &bus_attr_rescan.attr,
++      &bus_attr_autorescan.attr,
+       NULL,
+ };
+--- a/drivers/bus/fsl-mc/fsl-mc-private.h
++++ b/drivers/bus/fsl-mc/fsl-mc-private.h
+@@ -203,4 +203,8 @@ static inline void fsl_mc_uapi_remove_de
+ #endif
++int disable_dprc_irq(struct fsl_mc_device *mc_dev);
++int enable_dprc_irq(struct fsl_mc_device *mc_dev);
++int get_dprc_irq_state(struct fsl_mc_device *mc_dev);
++
+ #endif /* _FSL_MC_PRIVATE_H_ */
+--- a/include/linux/fsl/mc.h
++++ b/include/linux/fsl/mc.h
+@@ -1006,6 +1006,7 @@ struct fsl_mc_bus {
+       struct mutex scan_mutex;    /* serializes bus scanning */
+       struct dprc_attributes dprc_attr;
+       struct fsl_mc_uapi uapi_misc;
++      int irq_enabled;
+ };
+ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0225-enetc-Configure-the-Time-Aware-Scheduler-via-tc-tapr.patch b/target/linux/layerscape/patches-5.4/701-net-0225-enetc-Configure-the-Time-Aware-Scheduler-via-tc-tapr.patch
new file mode 100644 (file)
index 0000000..37ed557
--- /dev/null
@@ -0,0 +1,378 @@
+From 6ee2331a3a5627b062daf76aa5ed9f64fbbfa303 Mon Sep 17 00:00:00 2001
+From: Po Liu <po.liu@nxp.com>
+Date: Fri, 15 Nov 2019 03:33:33 +0000
+Subject: [PATCH] enetc: Configure the Time-Aware Scheduler via tc-taprio
+ offload
+
+ENETC supports in hardware for time-based egress shaping according
+to IEEE 802.1Qbv. This patch implement the Qbv enablement by the
+hardware offload method qdisc tc-taprio method.
+Also update cbdr writeback to up level since control bd ring may
+writeback data to control bd ring.
+
+Signed-off-by: Po Liu <Po.Liu@nxp.com>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/freescale/enetc/Kconfig      |  10 ++
+ drivers/net/ethernet/freescale/enetc/Makefile     |   2 +
+ drivers/net/ethernet/freescale/enetc/enetc.c      |  19 ++-
+ drivers/net/ethernet/freescale/enetc/enetc.h      |   7 ++
+ drivers/net/ethernet/freescale/enetc/enetc_cbdr.c |   5 +-
+ drivers/net/ethernet/freescale/enetc/enetc_hw.h   |  84 ++++++++++---
+ drivers/net/ethernet/freescale/enetc/enetc_qos.c  | 138 ++++++++++++++++++++++
+ 7 files changed, 243 insertions(+), 22 deletions(-)
+ create mode 100644 drivers/net/ethernet/freescale/enetc/enetc_qos.c
+
+--- a/drivers/net/ethernet/freescale/enetc/Kconfig
++++ b/drivers/net/ethernet/freescale/enetc/Kconfig
+@@ -50,3 +50,13 @@ config FSL_ENETC_HW_TIMESTAMPING
+         allocation has not been supported and it is too expensive to use
+         extended RX BDs if timestamping is not used, this option enables
+         extended RX BDs in order to support hardware timestamping.
++
++config FSL_ENETC_QOS
++      bool "ENETC hardware Time-sensitive Network support"
++      depends on (FSL_ENETC || FSL_ENETC_VF) && NET_SCH_TAPRIO
++      help
++        There are Time-Sensitive Network(TSN) capabilities(802.1Qbv/802.1Qci
++        /802.1Qbu etc.) supported by ENETC. These TSN capabilities can be set
++        enable/disable from user space via Qos commands(tc). In the kernel
++        side, it can be loaded by Qos driver. Currently, it is only support
++        taprio(802.1Qbv).
+--- a/drivers/net/ethernet/freescale/enetc/Makefile
++++ b/drivers/net/ethernet/freescale/enetc/Makefile
+@@ -5,9 +5,11 @@ common-objs := enetc.o enetc_cbdr.o enet
+ obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
+ fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs)
+ fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
++fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
+ obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
+ fsl-enetc-vf-y := enetc_vf.o $(common-objs)
++fsl-enetc-vf-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
+ obj-$(CONFIG_FSL_ENETC_MDIO) += fsl-enetc-mdio.o
+ fsl-enetc-mdio-y := enetc_pci_mdio.o enetc_mdio.o
+--- a/drivers/net/ethernet/freescale/enetc/enetc.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc.c
+@@ -1427,8 +1427,7 @@ int enetc_close(struct net_device *ndev)
+       return 0;
+ }
+-int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
+-                 void *type_data)
++int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
+ {
+       struct enetc_ndev_priv *priv = netdev_priv(ndev);
+       struct tc_mqprio_qopt *mqprio = type_data;
+@@ -1436,9 +1435,6 @@ int enetc_setup_tc(struct net_device *nd
+       u8 num_tc;
+       int i;
+-      if (type != TC_SETUP_QDISC_MQPRIO)
+-              return -EOPNOTSUPP;
+-
+       mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
+       num_tc = mqprio->num_tc;
+@@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *nd
+       return 0;
+ }
++int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
++                 void *type_data)
++{
++      switch (type) {
++      case TC_SETUP_QDISC_MQPRIO:
++              return enetc_setup_tc_mqprio(ndev, type_data);
++      case TC_SETUP_QDISC_TAPRIO:
++              return enetc_setup_tc_taprio(ndev, type_data);
++      default:
++              return -EOPNOTSUPP;
++      }
++}
++
+ struct net_device_stats *enetc_get_stats(struct net_device *ndev)
+ {
+       struct enetc_ndev_priv *priv = netdev_priv(ndev);
+--- a/drivers/net/ethernet/freescale/enetc/enetc.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc.h
+@@ -244,3 +244,10 @@ int enetc_set_fs_entry(struct enetc_si *
+ void enetc_set_rss_key(struct enetc_hw *hw, const u8 *bytes);
+ int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
+ int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
++int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
++
++#ifdef CONFIG_FSL_ENETC_QOS
++int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
++#else
++#define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
++#endif
+--- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
+@@ -32,7 +32,7 @@ static int enetc_cbd_unused(struct enetc
+               r->bd_count;
+ }
+-static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
++int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
+ {
+       struct enetc_cbdr *ring = &si->cbd_ring;
+       int timeout = ENETC_CBDR_TIMEOUT;
+@@ -66,6 +66,9 @@ static int enetc_send_cmd(struct enetc_s
+       if (!timeout)
+               return -EBUSY;
++      /* CBD may writeback data, feedback up level */
++      *cbd = *dest_cbd;
++
+       enetc_clean_cbdr(si);
+       return 0;
+--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+@@ -18,6 +18,7 @@
+ #define ENETC_SICTR0  0x18
+ #define ENETC_SICTR1  0x1c
+ #define ENETC_SIPCAPR0        0x20
++#define ENETC_SIPCAPR0_QBV    BIT(4)
+ #define ENETC_SIPCAPR0_RSS    BIT(8)
+ #define ENETC_SIPCAPR1        0x24
+ #define ENETC_SITGTGR 0x30
+@@ -440,22 +441,6 @@ union enetc_rx_bd {
+ #define EMETC_MAC_ADDR_FILT_RES       3 /* # of reserved entries at the beginning */
+ #define ENETC_MAX_NUM_VFS     2
+-struct enetc_cbd {
+-      union {
+-              struct {
+-                      __le32 addr[2];
+-                      __le32 opt[4];
+-              };
+-              __le32 data[6];
+-      };
+-      __le16 index;
+-      __le16 length;
+-      u8 cmd;
+-      u8 cls;
+-      u8 _res;
+-      u8 status_flags;
+-};
+-
+ #define ENETC_CBD_FLAGS_SF    BIT(7) /* short format */
+ #define ENETC_CBD_STATUS_MASK 0xf
+@@ -554,3 +539,70 @@ static inline void enetc_set_bdr_prio(st
+       val |= ENETC_TBMR_SET_PRIO(prio);
+       enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val);
+ }
++
++enum bdcr_cmd_class {
++      BDCR_CMD_UNSPEC = 0,
++      BDCR_CMD_MAC_FILTER,
++      BDCR_CMD_VLAN_FILTER,
++      BDCR_CMD_RSS,
++      BDCR_CMD_RFS,
++      BDCR_CMD_PORT_GCL,
++      BDCR_CMD_RECV_CLASSIFIER,
++      __BDCR_CMD_MAX_LEN,
++      BDCR_CMD_MAX_LEN = __BDCR_CMD_MAX_LEN - 1,
++};
++
++/* class 5, command 0 */
++struct tgs_gcl_conf {
++      u8      atc;    /* init gate value */
++      u8      res[7];
++      struct {
++              u8      res1[4];
++              __le16  acl_len;
++              u8      res2[2];
++      };
++};
++
++/* gate control list entry */
++struct gce {
++      __le32  period;
++      u8      gate;
++      u8      res[3];
++};
++
++/* tgs_gcl_conf address point to this data space */
++struct tgs_gcl_data {
++      __le32          btl;
++      __le32          bth;
++      __le32          ct;
++      __le32          cte;
++      struct gce      entry[0];
++};
++
++struct enetc_cbd {
++      union{
++              struct {
++                      __le32  addr[2];
++                      union {
++                              __le32  opt[4];
++                              struct tgs_gcl_conf     gcl_conf;
++                      };
++              };      /* Long format */
++              __le32 data[6];
++      };
++      __le16 index;
++      __le16 length;
++      u8 cmd;
++      u8 cls;
++      u8 _res;
++      u8 status_flags;
++};
++
++/* port time gating control register */
++#define ENETC_QBV_PTGCR_OFFSET                0x11a00
++#define ENETC_QBV_TGE                 BIT(31)
++#define ENETC_QBV_TGPE                        BIT(30)
++
++/* Port time gating capability register */
++#define ENETC_QBV_PTGCAPR_OFFSET      0x11a08
++#define ENETC_QBV_MAX_GCL_LEN_MASK    GENMASK(15, 0)
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
+@@ -0,0 +1,138 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
++/* Copyright 2019 NXP */
++
++#include "enetc.h"
++
++#include <net/pkt_sched.h>
++
++static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
++{
++      return enetc_rd(hw, ENETC_QBV_PTGCAPR_OFFSET)
++              & ENETC_QBV_MAX_GCL_LEN_MASK;
++}
++
++static int enetc_setup_taprio(struct net_device *ndev,
++                            struct tc_taprio_qopt_offload *admin_conf)
++{
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      struct enetc_cbd cbd = {.cmd = 0};
++      struct tgs_gcl_conf *gcl_config;
++      struct tgs_gcl_data *gcl_data;
++      struct gce *gce;
++      dma_addr_t dma;
++      u16 data_size;
++      u16 gcl_len;
++      u32 tge;
++      int err;
++      int i;
++
++      if (admin_conf->num_entries > enetc_get_max_gcl_len(&priv->si->hw))
++              return -EINVAL;
++      gcl_len = admin_conf->num_entries;
++
++      tge = enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET);
++      if (!admin_conf->enable) {
++              enetc_wr(&priv->si->hw,
++                       ENETC_QBV_PTGCR_OFFSET,
++                       tge & (~ENETC_QBV_TGE));
++              return 0;
++      }
++
++      if (admin_conf->cycle_time > U32_MAX ||
++          admin_conf->cycle_time_extension > U32_MAX)
++              return -EINVAL;
++
++      /* Configure the (administrative) gate control list using the
++       * control BD descriptor.
++       */
++      gcl_config = &cbd.gcl_conf;
++
++      data_size = struct_size(gcl_data, entry, gcl_len);
++      gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
++      if (!gcl_data)
++              return -ENOMEM;
++
++      gce = (struct gce *)(gcl_data + 1);
++
++      /* Set all gates open as default */
++      gcl_config->atc = 0xff;
++      gcl_config->acl_len = cpu_to_le16(gcl_len);
++
++      if (!admin_conf->base_time) {
++              gcl_data->btl =
++                      cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
++              gcl_data->bth =
++                      cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
++      } else {
++              gcl_data->btl =
++                      cpu_to_le32(lower_32_bits(admin_conf->base_time));
++              gcl_data->bth =
++                      cpu_to_le32(upper_32_bits(admin_conf->base_time));
++      }
++
++      gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
++      gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);
++
++      for (i = 0; i < gcl_len; i++) {
++              struct tc_taprio_sched_entry *temp_entry;
++              struct gce *temp_gce = gce + i;
++
++              temp_entry = &admin_conf->entries[i];
++
++              temp_gce->gate = (u8)temp_entry->gate_mask;
++              temp_gce->period = cpu_to_le32(temp_entry->interval);
++      }
++
++      cbd.length = cpu_to_le16(data_size);
++      cbd.status_flags = 0;
++
++      dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
++                           data_size, DMA_TO_DEVICE);
++      if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
++              netdev_err(priv->si->ndev, "DMA mapping failed!\n");
++              kfree(gcl_data);
++              return -ENOMEM;
++      }
++
++      cbd.addr[0] = lower_32_bits(dma);
++      cbd.addr[1] = upper_32_bits(dma);
++      cbd.cls = BDCR_CMD_PORT_GCL;
++      cbd.status_flags = 0;
++
++      enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
++               tge | ENETC_QBV_TGE);
++
++      err = enetc_send_cmd(priv->si, &cbd);
++      if (err)
++              enetc_wr(&priv->si->hw,
++                       ENETC_QBV_PTGCR_OFFSET,
++                       tge & (~ENETC_QBV_TGE));
++
++      dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE);
++      kfree(gcl_data);
++
++      return err;
++}
++
++int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data)
++{
++      struct tc_taprio_qopt_offload *taprio = type_data;
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      int err;
++      int i;
++
++      for (i = 0; i < priv->num_tx_rings; i++)
++              enetc_set_bdr_prio(&priv->si->hw,
++                                 priv->tx_ring[i]->index,
++                                 taprio->enable ? i : 0);
++
++      err = enetc_setup_taprio(ndev, taprio);
++
++      if (err)
++              for (i = 0; i < priv->num_tx_rings; i++)
++                      enetc_set_bdr_prio(&priv->si->hw,
++                                         priv->tx_ring[i]->index,
++                                         taprio->enable ? 0 : i);
++
++      return err;
++}
diff --git a/target/linux/layerscape/patches-5.4/701-net-0226-enetc-update-TSN-Qbv-PSPEED-set-according-to-adjust-.patch b/target/linux/layerscape/patches-5.4/701-net-0226-enetc-update-TSN-Qbv-PSPEED-set-according-to-adjust-.patch
new file mode 100644 (file)
index 0000000..4e19ed3
--- /dev/null
@@ -0,0 +1,171 @@
+From 877119a3f6bce2d9091faa4e51490917be8a3158 Mon Sep 17 00:00:00 2001
+From: Po Liu <po.liu@nxp.com>
+Date: Fri, 15 Nov 2019 03:33:41 +0000
+Subject: [PATCH] enetc: update TSN Qbv PSPEED set according to adjust link
+ speed
+
+ENETC has a register PSPEED to indicate the link speed of hardware.
+It is need to update accordingly. PSPEED field needs to be updated
+with the port speed for QBV scheduling purposes. Or else there is
+chance for gate slot not free by frame taking the MAC if PSPEED and
+phy speed not match. So update PSPEED when link adjust. This is
+implement by the adjust_link.
+
+Signed-off-by: Po Liu <Po.Liu@nxp.com>
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/freescale/enetc/enetc.c     | 13 +++++++--
+ drivers/net/ethernet/freescale/enetc/enetc.h     |  8 ++++++
+ drivers/net/ethernet/freescale/enetc/enetc_hw.h  |  5 ++++
+ drivers/net/ethernet/freescale/enetc/enetc_pf.c  |  3 +++
+ drivers/net/ethernet/freescale/enetc/enetc_qos.c | 34 ++++++++++++++++++++++++
+ 5 files changed, 61 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc.c
+@@ -742,9 +742,14 @@ void enetc_get_si_caps(struct enetc_si *
+       si->num_rss = 0;
+       val = enetc_rd(hw, ENETC_SIPCAPR0);
+       if (val & ENETC_SIPCAPR0_RSS) {
+-              val = enetc_rd(hw, ENETC_SIRSSCAPR);
+-              si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(val);
++              u32 rss;
++
++              rss = enetc_rd(hw, ENETC_SIRSSCAPR);
++              si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(rss);
+       }
++
++      if (val & ENETC_SIPCAPR0_QBV)
++              si->hw_features |= ENETC_SI_F_QBV;
+ }
+ static int enetc_dma_alloc_bdr(struct enetc_bdr *r, size_t bd_size)
+@@ -1314,8 +1319,12 @@ static void enetc_disable_interrupts(str
+ static void adjust_link(struct net_device *ndev)
+ {
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
+       struct phy_device *phydev = ndev->phydev;
++      if (priv->active_offloads & ENETC_F_QBV)
++              enetc_sched_speed_set(ndev);
++
+       phy_print_status(phydev);
+ }
+--- a/drivers/net/ethernet/freescale/enetc/enetc.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc.h
+@@ -118,6 +118,8 @@ enum enetc_errata {
+       ENETC_ERR_UCMCSWP       = BIT(2),
+ };
++#define ENETC_SI_F_QBV BIT(0)
++
+ /* PCI IEP device data */
+ struct enetc_si {
+       struct pci_dev *pdev;
+@@ -133,6 +135,7 @@ struct enetc_si {
+       int num_fs_entries;
+       int num_rss; /* number of RSS buckets */
+       unsigned short pad;
++      int hw_features;
+ };
+ #define ENETC_SI_ALIGN        32
+@@ -173,6 +176,7 @@ struct enetc_cls_rule {
+ enum enetc_active_offloads {
+       ENETC_F_RX_TSTAMP       = BIT(0),
+       ENETC_F_TX_TSTAMP       = BIT(1),
++      ENETC_F_QBV             = BIT(2),
+ };
+ struct enetc_ndev_priv {
+@@ -188,6 +192,8 @@ struct enetc_ndev_priv {
+       u16 msg_enable;
+       int active_offloads;
++      u32 speed; /* store speed for compare update pspeed */
++
+       struct enetc_bdr *tx_ring[16];
+       struct enetc_bdr *rx_ring[16];
+@@ -248,6 +254,8 @@ int enetc_send_cmd(struct enetc_si *si,
+ #ifdef CONFIG_FSL_ENETC_QOS
+ int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
++void enetc_sched_speed_set(struct net_device *ndev);
+ #else
+ #define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
++#define enetc_sched_speed_set(ndev) (void)0
+ #endif
+--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+@@ -149,6 +149,11 @@ enum enetc_bdr_type {TX, RX};
+ #define ENETC_PORT_BASE               0x10000
+ #define ENETC_PMR             0x0000
+ #define ENETC_PMR_EN  GENMASK(18, 16)
++#define ENETC_PMR_PSPEED_MASK GENMASK(11, 8)
++#define ENETC_PMR_PSPEED_10M  0
++#define ENETC_PMR_PSPEED_100M BIT(8)
++#define ENETC_PMR_PSPEED_1000M        BIT(9)
++#define ENETC_PMR_PSPEED_2500M        BIT(10)
+ #define ENETC_PSR             0x0004 /* RO */
+ #define ENETC_PSIPMR          0x0018
+ #define ENETC_PSIPMR_SET_UP(n)        BIT(n) /* n = SI index */
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -742,6 +742,9 @@ static void enetc_pf_netdev_setup(struct
+       ndev->priv_flags |= IFF_UNICAST_FLT;
++      if (si->hw_features & ENETC_SI_F_QBV)
++              priv->active_offloads |= ENETC_F_QBV;
++
+       /* pick up primary MAC address from SI */
+       enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr);
+ }
+--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
+@@ -11,6 +11,40 @@ static u16 enetc_get_max_gcl_len(struct
+               & ENETC_QBV_MAX_GCL_LEN_MASK;
+ }
++void enetc_sched_speed_set(struct net_device *ndev)
++{
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      struct phy_device *phydev = ndev->phydev;
++      u32 old_speed = priv->speed;
++      u32 speed, pspeed;
++
++      if (phydev->speed == old_speed)
++              return;
++
++      speed = phydev->speed;
++      switch (speed) {
++      case SPEED_1000:
++              pspeed = ENETC_PMR_PSPEED_1000M;
++              break;
++      case SPEED_2500:
++              pspeed = ENETC_PMR_PSPEED_2500M;
++              break;
++      case SPEED_100:
++              pspeed = ENETC_PMR_PSPEED_100M;
++              break;
++      case SPEED_10:
++      default:
++              pspeed = ENETC_PMR_PSPEED_10M;
++              netdev_err(ndev, "Qbv PSPEED set speed link down.\n");
++      }
++
++      priv->speed = speed;
++      enetc_port_wr(&priv->si->hw, ENETC_PMR,
++                    (enetc_port_rd(&priv->si->hw, ENETC_PMR)
++                    & (~ENETC_PMR_PSPEED_MASK))
++                    | pspeed);
++}
++
+ static int enetc_setup_taprio(struct net_device *ndev,
+                             struct tc_taprio_qopt_offload *admin_conf)
+ {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0227-enetc-Fix-if_mode-extraction.patch b/target/linux/layerscape/patches-5.4/701-net-0227-enetc-Fix-if_mode-extraction.patch
new file mode 100644 (file)
index 0000000..37cbcd9
--- /dev/null
@@ -0,0 +1,46 @@
+From 7b75e86c2cfc9fa48b582b04e939f18a54bdfa2e Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Tue, 13 Aug 2019 13:59:24 +0300
+Subject: [PATCH] enetc: Fix if_mode extraction
+
+If if_mode not found then just handle it as fixed link
+(i.e mac2mac connection).
+
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_pf.c | 17 ++++++-----------
+ 1 file changed, 6 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -754,6 +754,7 @@ static int enetc_of_get_phy(struct enetc
+       struct enetc_pf *pf = enetc_si_priv(priv->si);
+       struct device_node *np = priv->dev->of_node;
+       struct device_node *mdio_np;
++      int phy_mode;
+       int err;
+       if (!np) {
+@@ -787,17 +788,11 @@ static int enetc_of_get_phy(struct enetc
+               }
+       }
+-      priv->if_mode = of_get_phy_mode(np);
+-      if ((int)priv->if_mode < 0) {
+-              dev_err(priv->dev, "missing phy type\n");
+-              of_node_put(priv->phy_node);
+-              if (of_phy_is_fixed_link(np))
+-                      of_phy_deregister_fixed_link(np);
+-              else
+-                      enetc_mdio_remove(pf);
+-
+-              return -EINVAL;
+-      }
++      phy_mode = of_get_phy_mode(np);
++      if (phy_mode < 0)
++              priv->if_mode = PHY_INTERFACE_MODE_NA; /* fixed link */
++      else
++              priv->if_mode = phy_mode;
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0228-enetc-Make-mdio-accessors-more-generic.patch b/target/linux/layerscape/patches-5.4/701-net-0228-enetc-Make-mdio-accessors-more-generic.patch
new file mode 100644 (file)
index 0000000..efface6
--- /dev/null
@@ -0,0 +1,221 @@
+From 141fc778365ac0f1584ade0fd419af871e681646 Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Mon, 12 Aug 2019 20:26:42 +0300
+Subject: [PATCH] enetc: Make mdio accessors more generic
+
+Refactoring needed to support multiple MDIO buses.
+'mdio_base' - MDIO registers base address - is being parameterized.
+The MDIO accessors are made more generic to be able to work with
+different MDIO register bases.
+Some includes get cleaned up in the process.
+
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_hw.h    |  1 +
+ drivers/net/ethernet/freescale/enetc/enetc_mdio.c  | 60 +++++++++++++---------
+ drivers/net/ethernet/freescale/enetc/enetc_mdio.h  |  2 +-
+ .../net/ethernet/freescale/enetc/enetc_pci_mdio.c  |  2 +
+ 4 files changed, 39 insertions(+), 26 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+@@ -198,6 +198,7 @@ enum enetc_bdr_type {TX, RX};
+ #define ENETC_PFPMR           0x1900
+ #define ENETC_PFPMR_PMACE     BIT(1)
+ #define ENETC_PFPMR_MWLM      BIT(0)
++#define ENETC_EMDIO_BASE      0x1c00
+ #define ENETC_PSIUMHFR0(n, err)       (((err) ? 0x1d08 : 0x1d00) + (n) * 0x10)
+ #define ENETC_PSIUMHFR1(n)    (0x1d04 + (n) * 0x10)
+ #define ENETC_PSIMMHFR0(n, err)       (((err) ? 0x1d00 : 0x1d08) + (n) * 0x10)
+--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
+@@ -6,19 +6,30 @@
+ #include <linux/iopoll.h>
+ #include <linux/of.h>
++#include "enetc_pf.h"
+ #include "enetc_mdio.h"
+-#define       ENETC_MDIO_REG_OFFSET   0x1c00
+ #define       ENETC_MDIO_CFG  0x0     /* MDIO configuration and status */
+ #define       ENETC_MDIO_CTL  0x4     /* MDIO control */
+ #define       ENETC_MDIO_DATA 0x8     /* MDIO data */
+ #define       ENETC_MDIO_ADDR 0xc     /* MDIO address */
+-#define enetc_mdio_rd(hw, off) \
+-      enetc_port_rd(hw, ENETC_##off + ENETC_MDIO_REG_OFFSET)
+-#define enetc_mdio_wr(hw, off, val) \
+-      enetc_port_wr(hw, ENETC_##off + ENETC_MDIO_REG_OFFSET, val)
+-#define enetc_mdio_rd_reg(off)        enetc_mdio_rd(hw, off)
++static inline u32 _enetc_mdio_rd(struct enetc_mdio_priv *mdio_priv, int off)
++{
++      return enetc_port_rd(mdio_priv->hw, mdio_priv->mdio_base + off);
++}
++
++static inline void _enetc_mdio_wr(struct enetc_mdio_priv *mdio_priv, int off,
++                                u32 val)
++{
++      enetc_port_wr(mdio_priv->hw, mdio_priv->mdio_base + off, val);
++}
++
++#define enetc_mdio_rd(mdio_priv, off) \
++      _enetc_mdio_rd(mdio_priv, ENETC_##off)
++#define enetc_mdio_wr(mdio_priv, off, val) \
++      _enetc_mdio_wr(mdio_priv, ENETC_##off, val)
++#define enetc_mdio_rd_reg(off)        enetc_mdio_rd(mdio_priv, off)
+ #define ENETC_MDC_DIV         258
+@@ -35,7 +46,7 @@
+ #define MDIO_DATA(x)          ((x) & 0xffff)
+ #define TIMEOUT       1000
+-static int enetc_mdio_wait_complete(struct enetc_hw *hw)
++static int enetc_mdio_wait_complete(struct enetc_mdio_priv *mdio_priv)
+ {
+       u32 val;
+@@ -46,7 +57,6 @@ static int enetc_mdio_wait_complete(stru
+ int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value)
+ {
+       struct enetc_mdio_priv *mdio_priv = bus->priv;
+-      struct enetc_hw *hw = mdio_priv->hw;
+       u32 mdio_ctl, mdio_cfg;
+       u16 dev_addr;
+       int ret;
+@@ -61,29 +71,29 @@ int enetc_mdio_write(struct mii_bus *bus
+               mdio_cfg &= ~MDIO_CFG_ENC45;
+       }
+-      enetc_mdio_wr(hw, MDIO_CFG, mdio_cfg);
++      enetc_mdio_wr(mdio_priv, MDIO_CFG, mdio_cfg);
+-      ret = enetc_mdio_wait_complete(hw);
++      ret = enetc_mdio_wait_complete(mdio_priv);
+       if (ret)
+               return ret;
+       /* set port and dev addr */
+       mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
+-      enetc_mdio_wr(hw, MDIO_CTL, mdio_ctl);
++      enetc_mdio_wr(mdio_priv, MDIO_CTL, mdio_ctl);
+       /* set the register address */
+       if (regnum & MII_ADDR_C45) {
+-              enetc_mdio_wr(hw, MDIO_ADDR, regnum & 0xffff);
++              enetc_mdio_wr(mdio_priv, MDIO_ADDR, regnum & 0xffff);
+-              ret = enetc_mdio_wait_complete(hw);
++              ret = enetc_mdio_wait_complete(mdio_priv);
+               if (ret)
+                       return ret;
+       }
+       /* write the value */
+-      enetc_mdio_wr(hw, MDIO_DATA, MDIO_DATA(value));
++      enetc_mdio_wr(mdio_priv, MDIO_DATA, MDIO_DATA(value));
+-      ret = enetc_mdio_wait_complete(hw);
++      ret = enetc_mdio_wait_complete(mdio_priv);
+       if (ret)
+               return ret;
+@@ -93,7 +103,6 @@ int enetc_mdio_write(struct mii_bus *bus
+ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
+ {
+       struct enetc_mdio_priv *mdio_priv = bus->priv;
+-      struct enetc_hw *hw = mdio_priv->hw;
+       u32 mdio_ctl, mdio_cfg;
+       u16 dev_addr, value;
+       int ret;
+@@ -107,41 +116,41 @@ int enetc_mdio_read(struct mii_bus *bus,
+               mdio_cfg &= ~MDIO_CFG_ENC45;
+       }
+-      enetc_mdio_wr(hw, MDIO_CFG, mdio_cfg);
++      enetc_mdio_wr(mdio_priv, MDIO_CFG, mdio_cfg);
+-      ret = enetc_mdio_wait_complete(hw);
++      ret = enetc_mdio_wait_complete(mdio_priv);
+       if (ret)
+               return ret;
+       /* set port and device addr */
+       mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
+-      enetc_mdio_wr(hw, MDIO_CTL, mdio_ctl);
++      enetc_mdio_wr(mdio_priv, MDIO_CTL, mdio_ctl);
+       /* set the register address */
+       if (regnum & MII_ADDR_C45) {
+-              enetc_mdio_wr(hw, MDIO_ADDR, regnum & 0xffff);
++              enetc_mdio_wr(mdio_priv, MDIO_ADDR, regnum & 0xffff);
+-              ret = enetc_mdio_wait_complete(hw);
++              ret = enetc_mdio_wait_complete(mdio_priv);
+               if (ret)
+                       return ret;
+       }
+       /* initiate the read */
+-      enetc_mdio_wr(hw, MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
++      enetc_mdio_wr(mdio_priv, MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
+-      ret = enetc_mdio_wait_complete(hw);
++      ret = enetc_mdio_wait_complete(mdio_priv);
+       if (ret)
+               return ret;
+       /* return all Fs if nothing was there */
+-      if (enetc_mdio_rd(hw, MDIO_CFG) & MDIO_CFG_RD_ER) {
++      if (enetc_mdio_rd(mdio_priv, MDIO_CFG) & MDIO_CFG_RD_ER) {
+               dev_dbg(&bus->dev,
+                       "Error while reading PHY%d reg at %d.%hhu\n",
+                       phy_id, dev_addr, regnum);
+               return 0xffff;
+       }
+-      value = enetc_mdio_rd(hw, MDIO_DATA) & 0xffff;
++      value = enetc_mdio_rd(mdio_priv, MDIO_DATA) & 0xffff;
+       return value;
+ }
+@@ -164,6 +173,7 @@ int enetc_mdio_probe(struct enetc_pf *pf
+       bus->parent = dev;
+       mdio_priv = bus->priv;
+       mdio_priv->hw = &pf->si->hw;
++      mdio_priv->mdio_base = ENETC_EMDIO_BASE;
+       snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
+       np = of_get_child_by_name(dev->of_node, "mdio");
+--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.h
+@@ -2,10 +2,10 @@
+ /* Copyright 2019 NXP */
+ #include <linux/phy.h>
+-#include "enetc_pf.h"
+ struct enetc_mdio_priv {
+       struct enetc_hw *hw;
++      int mdio_base;
+ };
+ int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value);
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
+@@ -1,6 +1,7 @@
+ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+ /* Copyright 2019 NXP */
+ #include <linux/of_mdio.h>
++#include "enetc_pf.h"
+ #include "enetc_mdio.h"
+ #define ENETC_MDIO_DEV_ID     0xee01
+@@ -31,6 +32,7 @@ static int enetc_pci_mdio_probe(struct p
+       bus->parent = dev;
+       mdio_priv = bus->priv;
+       mdio_priv->hw = hw;
++      mdio_priv->mdio_base = ENETC_EMDIO_BASE;
+       snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
+       pcie_flr(pdev);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0229-enetc-Initialize-SerDes-for-SGMII-and-SXGMII-protoco.patch b/target/linux/layerscape/patches-5.4/701-net-0229-enetc-Initialize-SerDes-for-SGMII-and-SXGMII-protoco.patch
new file mode 100644 (file)
index 0000000..ef78b50
--- /dev/null
@@ -0,0 +1,169 @@
+From 6943ed031ee75f13a950e293f92db68ea2ec2786 Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Wed, 14 Aug 2019 14:34:47 +0300
+Subject: [PATCH] enetc: Initialize SerDes for SGMII and SXGMII protocols
+
+ENETC has ethernet MACs capable of SGMII and SXGMII but
+in order to use these protocols some serdes configurations
+need to be performed.
+The serdes is configurable via an internal MDIO bus
+connected to an internal PCS device, all reads/writes are
+performed at address 0.
+This patch basically removes the dependecy on a bootloader
+regarding serdes initialization.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_hw.h   | 17 +++++++
+ drivers/net/ethernet/freescale/enetc/enetc_mdio.c | 24 +++++++++
+ drivers/net/ethernet/freescale/enetc/enetc_pf.c   | 59 +++++++++++++++++++++++
+ drivers/net/ethernet/freescale/enetc/enetc_pf.h   |  2 +
+ 4 files changed, 102 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+@@ -221,6 +221,23 @@ enum enetc_bdr_type {TX, RX};
+ #define ENETC_PM0_MAXFRM      0x8014
+ #define ENETC_SET_TX_MTU(val) ((val) << 16)
+ #define ENETC_SET_MAXFRM(val) ((val) & 0xffff)
++
++#define ENETC_PM_IMDIO_BASE   0x8030
++/* PCS registers */
++#define ENETC_PCS_CR                  0x0
++#define ENETC_PCS_CR_RESET_AN         0x1200
++#define ENETC_PCS_CR_DEF_VAL          0x0140
++#define ENETC_PCS_CR_LANE_RESET               0x8000
++#define ENETC_PCS_DEV_ABILITY         0x04
++#define ENETC_PCS_DEV_ABILITY_SGMII   0x4001
++#define ENETC_PCS_DEV_ABILITY_SXGMII  0x5001
++#define ENETC_PCS_LINK_TIMER1         0x12
++#define ENETC_PCS_LINK_TIMER1_VAL     0x06a0
++#define ENETC_PCS_LINK_TIMER2         0x13
++#define ENETC_PCS_LINK_TIMER2_VAL     0x0003
++#define ENETC_PCS_IF_MODE             0x14
++#define ENETC_PCS_IF_MODE_SGMII_AN    0x0003
++
+ #define ENETC_PM0_IF_MODE     0x8300
+ #define ENETC_PMO_IFM_RG      BIT(2)
+ #define ENETC_PM0_IFM_RLP     (BIT(5) | BIT(11))
+--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
+@@ -200,3 +200,27 @@ void enetc_mdio_remove(struct enetc_pf *
+       if (pf->mdio)
+               mdiobus_unregister(pf->mdio);
+ }
++
++int enetc_imdio_init(struct enetc_pf *pf)
++{
++      struct device *dev = &pf->si->pdev->dev;
++      struct enetc_mdio_priv *mdio_priv;
++      struct mii_bus *bus;
++
++      bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
++      if (!bus)
++              return -ENOMEM;
++
++      bus->name = "FSL ENETC internal MDIO Bus";
++      bus->read = enetc_mdio_read;
++      bus->write = enetc_mdio_write;
++      bus->parent = dev;
++      mdio_priv = bus->priv;
++      mdio_priv->hw = &pf->si->hw;
++      mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
++      snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
++
++      pf->imdio = bus;
++
++      return 0;
++}
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -807,6 +807,61 @@ static void enetc_of_put_phy(struct enet
+               of_node_put(priv->phy_node);
+ }
++static void enetc_configure_sgmii(struct mii_bus *imdio)
++{
++      /* Set to SGMII mode, use AN */
++      imdio->write(imdio, 0, ENETC_PCS_IF_MODE,
++                   ENETC_PCS_IF_MODE_SGMII_AN);
++
++      /* Dev ability - SGMII */
++      imdio->write(imdio, 0, ENETC_PCS_DEV_ABILITY,
++                   ENETC_PCS_DEV_ABILITY_SGMII);
++
++      /* Adjust link timer for SGMII */
++      imdio->write(imdio, 0, ENETC_PCS_LINK_TIMER1,
++                   ENETC_PCS_LINK_TIMER1_VAL);
++      imdio->write(imdio, 0, ENETC_PCS_LINK_TIMER2,
++                   ENETC_PCS_LINK_TIMER2_VAL);
++
++      /* restart PCS AN */
++      imdio->write(imdio, 0, ENETC_PCS_CR,
++                   ENETC_PCS_CR_RESET_AN | ENETC_PCS_CR_DEF_VAL);
++}
++
++static void enetc_configure_sxgmii(struct mii_bus *imdio)
++{
++      /* Dev ability - SXGMII */
++      imdio->write(imdio, 0, MII_ADDR_C45 | (MDIO_MMD_VEND2 << 16) |
++                   ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SXGMII);
++
++      /* Restart PCS AN */
++      imdio->write(imdio, 0, MII_ADDR_C45 | (MDIO_MMD_VEND2 << 16) |
++                   ENETC_PCS_CR,
++                   ENETC_PCS_CR_LANE_RESET | ENETC_PCS_CR_RESET_AN);
++}
++
++static int enetc_configure_serdes(struct enetc_ndev_priv *priv)
++{
++      struct enetc_pf *pf = enetc_si_priv(priv->si);
++      int err;
++
++      if (priv->if_mode != PHY_INTERFACE_MODE_SGMII &&
++          priv->if_mode != PHY_INTERFACE_MODE_XGMII)
++              return 0;
++
++      err = enetc_imdio_init(pf);
++      if (err)
++              return err;
++
++      if (priv->if_mode == PHY_INTERFACE_MODE_SGMII)
++              enetc_configure_sgmii(pf->imdio);
++
++      if (priv->if_mode == PHY_INTERFACE_MODE_XGMII)
++              enetc_configure_sxgmii(pf->imdio);
++
++      return 0;
++}
++
+ static int enetc_pf_probe(struct pci_dev *pdev,
+                         const struct pci_device_id *ent)
+ {
+@@ -871,6 +926,10 @@ static int enetc_pf_probe(struct pci_dev
+       if (err)
+               dev_warn(&pdev->dev, "Fallback to PHY-less operation\n");
++      err = enetc_configure_serdes(priv);
++      if (err)
++              dev_warn(&pdev->dev, "Attempted serdes config but failed\n");
++
+       err = register_netdev(ndev);
+       if (err)
+               goto err_reg_netdev;
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+@@ -44,6 +44,7 @@ struct enetc_pf {
+       DECLARE_BITMAP(active_vlans, VLAN_N_VID);
+       struct mii_bus *mdio; /* saved for cleanup */
++      struct mii_bus *imdio;
+ };
+ int enetc_msg_psi_init(struct enetc_pf *pf);
+@@ -53,3 +54,4 @@ void enetc_msg_handle_rxmsg(struct enetc
+ /* MDIO */
+ int enetc_mdio_probe(struct enetc_pf *pf);
+ void enetc_mdio_remove(struct enetc_pf *pf);
++int enetc_imdio_init(struct enetc_pf *pf);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0230-enetc-Drop-redundant-device-node-check.patch b/target/linux/layerscape/patches-5.4/701-net-0230-enetc-Drop-redundant-device-node-check.patch
new file mode 100644 (file)
index 0000000..a671241
--- /dev/null
@@ -0,0 +1,27 @@
+From 219e330d8b6b5e3f84a7a593969f948bf2fec558 Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Fri, 6 Sep 2019 16:17:20 +0300
+Subject: [PATCH] enetc: Drop redundant device node check
+
+The existence of the DT port node is the first thing checked
+at probe time, and probing won't continue if the node is missing.
+
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_pf.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -757,11 +757,6 @@ static int enetc_of_get_phy(struct enetc
+       int phy_mode;
+       int err;
+-      if (!np) {
+-              dev_err(priv->dev, "missing ENETC port node\n");
+-              return -ENODEV;
+-      }
+-
+       priv->phy_node = of_parse_phandle(np, "phy-handle", 0);
+       if (!priv->phy_node) {
+               if (!of_phy_is_fixed_link(np)) {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0231-enetc-Use-DT-protocol-information-to-set-up-the-port.patch b/target/linux/layerscape/patches-5.4/701-net-0231-enetc-Use-DT-protocol-information-to-set-up-the-port.patch
new file mode 100644 (file)
index 0000000..54fc619
--- /dev/null
@@ -0,0 +1,195 @@
+From 98f64a89977a32df96cdb8aaf3884086b2309924 Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Tue, 27 Aug 2019 15:14:11 +0300
+Subject: [PATCH] enetc: Use DT protocol information to set up the ports
+
+Use DT information rather than in-band information from bootloader to
+set up MAC for XGMII. For RGMII use the DT indication in addition to
+RGMII defaults in hardware.
+However, this implies that PHY connection information needs to be
+extracted before netdevice creation, when the ENETC Port MAC is
+being configured.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_pf.c | 55 ++++++++++++++-----------
+ drivers/net/ethernet/freescale/enetc/enetc_pf.h |  3 ++
+ 2 files changed, 33 insertions(+), 25 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -507,7 +507,8 @@ static void enetc_port_si_configure(stru
+       enetc_port_wr(hw, ENETC_PSIVLANFMR, ENETC_PSIVLANFMR_VS);
+ }
+-static void enetc_configure_port_mac(struct enetc_hw *hw)
++static void enetc_configure_port_mac(struct enetc_hw *hw,
++                                   phy_interface_t phy_mode)
+ {
+       enetc_port_wr(hw, ENETC_PM0_MAXFRM,
+                     ENETC_SET_MAXFRM(ENETC_RX_MAXFRM_SIZE));
+@@ -523,9 +524,11 @@ static void enetc_configure_port_mac(str
+                     ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC |
+                     ENETC_PM0_TX_EN | ENETC_PM0_RX_EN);
+       /* set auto-speed for RGMII */
+-      if (enetc_port_rd(hw, ENETC_PM0_IF_MODE) & ENETC_PMO_IFM_RG)
++      if (enetc_port_rd(hw, ENETC_PM0_IF_MODE) & ENETC_PMO_IFM_RG ||
++          phy_mode == PHY_INTERFACE_MODE_RGMII)
+               enetc_port_wr(hw, ENETC_PM0_IF_MODE, ENETC_PM0_IFM_RGAUTO);
+-      if (enetc_global_rd(hw, ENETC_G_EPFBLPR(1)) == ENETC_G_EPFBLPR1_XGMII)
++
++      if (phy_mode == PHY_INTERFACE_MODE_XGMII)
+               enetc_port_wr(hw, ENETC_PM0_IF_MODE, ENETC_PM0_IFM_XGMII);
+ }
+@@ -549,7 +552,7 @@ static void enetc_configure_port(struct
+       enetc_configure_port_pmac(hw);
+-      enetc_configure_port_mac(hw);
++      enetc_configure_port_mac(hw, pf->if_mode);
+       enetc_port_si_configure(pf->si);
+@@ -749,28 +752,28 @@ static void enetc_pf_netdev_setup(struct
+       enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr);
+ }
+-static int enetc_of_get_phy(struct enetc_ndev_priv *priv)
++static int enetc_of_get_phy(struct enetc_pf *pf)
+ {
+-      struct enetc_pf *pf = enetc_si_priv(priv->si);
+-      struct device_node *np = priv->dev->of_node;
++      struct device *dev = &pf->si->pdev->dev;
++      struct device_node *np = dev->of_node;
+       struct device_node *mdio_np;
+       int phy_mode;
+       int err;
+-      priv->phy_node = of_parse_phandle(np, "phy-handle", 0);
+-      if (!priv->phy_node) {
++      pf->phy_node = of_parse_phandle(np, "phy-handle", 0);
++      if (!pf->phy_node) {
+               if (!of_phy_is_fixed_link(np)) {
+-                      dev_err(priv->dev, "PHY not specified\n");
++                      dev_err(dev, "PHY not specified\n");
+                       return -ENODEV;
+               }
+               err = of_phy_register_fixed_link(np);
+               if (err < 0) {
+-                      dev_err(priv->dev, "fixed link registration failed\n");
++                      dev_err(dev, "fixed link registration failed\n");
+                       return err;
+               }
+-              priv->phy_node = of_node_get(np);
++              pf->phy_node = of_node_get(np);
+       }
+       mdio_np = of_get_child_by_name(np, "mdio");
+@@ -778,28 +781,28 @@ static int enetc_of_get_phy(struct enetc
+               of_node_put(mdio_np);
+               err = enetc_mdio_probe(pf);
+               if (err) {
+-                      of_node_put(priv->phy_node);
++                      of_node_put(pf->phy_node);
+                       return err;
+               }
+       }
+       phy_mode = of_get_phy_mode(np);
+       if (phy_mode < 0)
+-              priv->if_mode = PHY_INTERFACE_MODE_NA; /* fixed link */
++              pf->if_mode = PHY_INTERFACE_MODE_NA; /* fixed link */
+       else
+-              priv->if_mode = phy_mode;
++              pf->if_mode = phy_mode;
+       return 0;
+ }
+-static void enetc_of_put_phy(struct enetc_ndev_priv *priv)
++static void enetc_of_put_phy(struct enetc_pf *pf)
+ {
+-      struct device_node *np = priv->dev->of_node;
++      struct device_node *np = pf->si->pdev->dev.of_node;
+       if (np && of_phy_is_fixed_link(np))
+               of_phy_deregister_fixed_link(np);
+-      if (priv->phy_node)
+-              of_node_put(priv->phy_node);
++      if (pf->phy_node)
++              of_node_put(pf->phy_node);
+ }
+ static void enetc_configure_sgmii(struct mii_bus *imdio)
+@@ -888,6 +891,10 @@ static int enetc_pf_probe(struct pci_dev
+       pf->si = si;
+       pf->total_vfs = pci_sriov_get_totalvfs(pdev);
++      err = enetc_of_get_phy(pf);
++      if (err)
++              dev_warn(&pdev->dev, "Fallback to PHY-less operation\n");
++
+       enetc_configure_port(pf);
+       enetc_get_si_caps(si);
+@@ -902,6 +909,8 @@ static int enetc_pf_probe(struct pci_dev
+       enetc_pf_netdev_setup(si, ndev, &enetc_ndev_ops);
+       priv = netdev_priv(ndev);
++      priv->phy_node = pf->phy_node;
++      priv->if_mode = pf->if_mode;
+       enetc_init_si_rings_params(priv);
+@@ -917,10 +926,6 @@ static int enetc_pf_probe(struct pci_dev
+               goto err_alloc_msix;
+       }
+-      err = enetc_of_get_phy(priv);
+-      if (err)
+-              dev_warn(&pdev->dev, "Fallback to PHY-less operation\n");
+-
+       err = enetc_configure_serdes(priv);
+       if (err)
+               dev_warn(&pdev->dev, "Attempted serdes config but failed\n");
+@@ -937,7 +942,6 @@ static int enetc_pf_probe(struct pci_dev
+       return 0;
+ err_reg_netdev:
+-      enetc_of_put_phy(priv);
+       enetc_free_msix(priv);
+ err_alloc_msix:
+       enetc_free_si_resources(priv);
+@@ -945,6 +949,7 @@ err_alloc_si_res:
+       si->ndev = NULL;
+       free_netdev(ndev);
+ err_alloc_netdev:
++      enetc_of_put_phy(pf);
+ err_map_pf_space:
+       enetc_pci_remove(pdev);
+@@ -967,7 +972,7 @@ static void enetc_pf_remove(struct pci_d
+       unregister_netdev(si->ndev);
+       enetc_mdio_remove(pf);
+-      enetc_of_put_phy(priv);
++      enetc_of_put_phy(pf);
+       enetc_free_msix(priv);
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+@@ -45,6 +45,9 @@ struct enetc_pf {
+       struct mii_bus *mdio; /* saved for cleanup */
+       struct mii_bus *imdio;
++
++      struct device_node *phy_node;
++      phy_interface_t if_mode;
+ };
+ int enetc_msg_psi_init(struct enetc_pf *pf);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0232-enetc-Handle-USXGMII-protocol.patch b/target/linux/layerscape/patches-5.4/701-net-0232-enetc-Handle-USXGMII-protocol.patch
new file mode 100644 (file)
index 0000000..d1e7004
--- /dev/null
@@ -0,0 +1,45 @@
+From bb700603e66a1294049aa479ad560443496c893b Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Fri, 20 Sep 2019 19:41:10 +0300
+Subject: [PATCH] enetc: Handle USXGMII protocol
+
+Adds USXGMII protocol which is now supported in Linux.  XGMII is kept for
+compatibility although there is no plain XGMII support in ENETC.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_pf.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -528,7 +528,8 @@ static void enetc_configure_port_mac(str
+           phy_mode == PHY_INTERFACE_MODE_RGMII)
+               enetc_port_wr(hw, ENETC_PM0_IF_MODE, ENETC_PM0_IFM_RGAUTO);
+-      if (phy_mode == PHY_INTERFACE_MODE_XGMII)
++      if (phy_mode == PHY_INTERFACE_MODE_XGMII ||
++          phy_mode == PHY_INTERFACE_MODE_USXGMII)
+               enetc_port_wr(hw, ENETC_PM0_IF_MODE, ENETC_PM0_IFM_XGMII);
+ }
+@@ -844,7 +845,8 @@ static int enetc_configure_serdes(struct
+       int err;
+       if (priv->if_mode != PHY_INTERFACE_MODE_SGMII &&
+-          priv->if_mode != PHY_INTERFACE_MODE_XGMII)
++          priv->if_mode != PHY_INTERFACE_MODE_XGMII &&
++          priv->if_mode != PHY_INTERFACE_MODE_USXGMII)
+               return 0;
+       err = enetc_imdio_init(pf);
+@@ -854,7 +856,8 @@ static int enetc_configure_serdes(struct
+       if (priv->if_mode == PHY_INTERFACE_MODE_SGMII)
+               enetc_configure_sgmii(pf->imdio);
+-      if (priv->if_mode == PHY_INTERFACE_MODE_XGMII)
++      if (priv->if_mode == PHY_INTERFACE_MODE_XGMII ||
++          priv->if_mode == PHY_INTERFACE_MODE_USXGMII)
+               enetc_configure_sxgmii(pf->imdio);
+       return 0;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0233-enetc-Enable-live-mac-addr-change-for-PF.patch b/target/linux/layerscape/patches-5.4/701-net-0233-enetc-Enable-live-mac-addr-change-for-PF.patch
new file mode 100644 (file)
index 0000000..20b5968
--- /dev/null
@@ -0,0 +1,27 @@
+From 9a963c982be787902892354a6ad669a5644b8338 Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Mon, 16 Sep 2019 19:22:08 +0300
+Subject: [PATCH] enetc: Enable live mac addr change for PF
+
+Use device flag IFF_LIVE_ADDR_CHANGE to signal that
+the device supports changing the primary mac address
+for a ENETC port, when the PF eth interface is running.
+This capability is required by certain applications,
+like bonding mode 6 (Adaptive Load Balancing).
+
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_pf.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -744,7 +744,7 @@ static void enetc_pf_netdev_setup(struct
+               ndev->features &= ~NETIF_F_HW_CSUM;
+       }
+-      ndev->priv_flags |= IFF_UNICAST_FLT;
++      ndev->priv_flags |= IFF_UNICAST_FLT | IFF_LIVE_ADDR_CHANGE;
+       if (si->hw_features & ENETC_SI_F_QBV)
+               priv->active_offloads |= ENETC_F_QBV;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0234-enetc-WA-for-MDIO-register-access-issue.patch b/target/linux/layerscape/patches-5.4/701-net-0234-enetc-WA-for-MDIO-register-access-issue.patch
new file mode 100644 (file)
index 0000000..e3925cc
--- /dev/null
@@ -0,0 +1,409 @@
+From 0f62a794b41ad14a962c70445844d61a8097805e Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Tue, 20 Aug 2019 12:34:22 +0300
+Subject: [PATCH] enetc: WA for MDIO register access issue
+
+Due to a hardware issue access to MDIO registers concurrent with other
+ENETC register access may lead to the MDIO access being dropped or
+corrupted.  The workaround introduces locking for all register access in
+ENETC space.  To reduce performance impact, code except MDIO uses per-cpu
+locks, MDIO code having to acquire all per-CPU locks to perform an access.
+To further reduce the performance impact, datapath functions acquire the
+per-cpu lock fewer times and use _hot accessors.  All the rest of the code
+uses the _wa accessors which lock every time a register is accessed.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc.c      |  85 ++++++++++++++----
+ drivers/net/ethernet/freescale/enetc/enetc_hw.h   | 105 +++++++++++++++++++++-
+ drivers/net/ethernet/freescale/enetc/enetc_mdio.c |   4 +-
+ drivers/net/ethernet/freescale/enetc/enetc_pf.c   |   3 +
+ 4 files changed, 176 insertions(+), 21 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc.c
+@@ -20,8 +20,13 @@ netdev_tx_t enetc_xmit(struct sk_buff *s
+ {
+       struct enetc_ndev_priv *priv = netdev_priv(ndev);
+       struct enetc_bdr *tx_ring;
++      unsigned long flags;
++      /* pointer to per-cpu ENETC lock for register access issue WA */
++      spinlock_t *lock;
+       int count;
++      lock = this_cpu_ptr(&enetc_gregs);
++
+       tx_ring = priv->tx_ring[skb->queue_mapping];
+       if (unlikely(skb_shinfo(skb)->nr_frags > ENETC_MAX_SKB_FRAGS))
+@@ -34,7 +39,12 @@ netdev_tx_t enetc_xmit(struct sk_buff *s
+               return NETDEV_TX_BUSY;
+       }
++      spin_lock_irqsave(lock, flags);
++
+       count = enetc_map_tx_buffs(tx_ring, skb, priv->active_offloads);
++
++      spin_unlock_irqrestore(lock, flags);
++
+       if (unlikely(!count))
+               goto drop_packet_err;
+@@ -228,7 +238,7 @@ static int enetc_map_tx_buffs(struct ene
+       tx_ring->next_to_use = i;
+       /* let H/W know BD ring has been updated */
+-      enetc_wr_reg(tx_ring->tpir, i); /* includes wmb() */
++      enetc_wr_reg_hot(tx_ring->tpir, i); /* includes wmb() */
+       return count;
+@@ -249,13 +259,21 @@ dma_err:
+ static irqreturn_t enetc_msix(int irq, void *data)
+ {
+       struct enetc_int_vector *v = data;
++      unsigned long flags;
++      /* pointer to per-cpu ENETC lock for register access issue WA */
++      spinlock_t *lock;
+       int i;
++      lock = this_cpu_ptr(&enetc_gregs);
++      spin_lock_irqsave(lock, flags);
++
+       /* disable interrupts */
+-      enetc_wr_reg(v->rbier, 0);
++      enetc_wr_reg_hot(v->rbier, 0);
+       for_each_set_bit(i, &v->tx_rings_map, v->count_tx_rings)
+-              enetc_wr_reg(v->tbier_base + ENETC_BDR_OFF(i), 0);
++              enetc_wr_reg_hot(v->tbier_base + ENETC_BDR_OFF(i), 0);
++
++      spin_unlock_irqrestore(lock, flags);
+       napi_schedule_irqoff(&v->napi);
+@@ -271,6 +289,9 @@ static int enetc_poll(struct napi_struct
+       struct enetc_int_vector
+               *v = container_of(napi, struct enetc_int_vector, napi);
+       bool complete = true;
++      unsigned long flags;
++      /* pointer to per-cpu ENETC lock for register access issue WA */
++      spinlock_t *lock;
+       int work_done;
+       int i;
+@@ -287,19 +308,24 @@ static int enetc_poll(struct napi_struct
+       napi_complete_done(napi, work_done);
++      lock = this_cpu_ptr(&enetc_gregs);
++      spin_lock_irqsave(lock, flags);
++
+       /* enable interrupts */
+-      enetc_wr_reg(v->rbier, ENETC_RBIER_RXTIE);
++      enetc_wr_reg_hot(v->rbier, ENETC_RBIER_RXTIE);
+       for_each_set_bit(i, &v->tx_rings_map, v->count_tx_rings)
+-              enetc_wr_reg(v->tbier_base + ENETC_BDR_OFF(i),
+-                           ENETC_TBIER_TXTIE);
++              enetc_wr_reg_hot(v->tbier_base + ENETC_BDR_OFF(i),
++                               ENETC_TBIER_TXTIE);
++
++      spin_unlock_irqrestore(lock, flags);
+       return work_done;
+ }
+ static int enetc_bd_ready_count(struct enetc_bdr *tx_ring, int ci)
+ {
+-      int pi = enetc_rd_reg(tx_ring->tcir) & ENETC_TBCIR_IDX_MASK;
++      int pi = enetc_rd_reg_hot(tx_ring->tcir) & ENETC_TBCIR_IDX_MASK;
+       return pi >= ci ? pi - ci : tx_ring->bd_count - ci + pi;
+ }
+@@ -337,9 +363,18 @@ static bool enetc_clean_tx_ring(struct e
+       bool do_tstamp;
+       u64 tstamp = 0;
++      unsigned long flags;
++      /* pointer to per-cpu ENETC lock for register access issue WA */
++      spinlock_t *lock;
++
++      lock = this_cpu_ptr(&enetc_gregs);
++
+       i = tx_ring->next_to_clean;
+       tx_swbd = &tx_ring->tx_swbd[i];
++
++      spin_lock_irqsave(lock, flags);
+       bds_to_clean = enetc_bd_ready_count(tx_ring, i);
++      spin_unlock_irqrestore(lock, flags);
+       do_tstamp = false;
+@@ -382,16 +417,20 @@ static bool enetc_clean_tx_ring(struct e
+                       tx_swbd = tx_ring->tx_swbd;
+               }
++              spin_lock_irqsave(lock, flags);
++
+               /* BD iteration loop end */
+               if (is_eof) {
+                       tx_frm_cnt++;
+                       /* re-arm interrupt source */
+-                      enetc_wr_reg(tx_ring->idr, BIT(tx_ring->index) |
+-                                   BIT(16 + tx_ring->index));
++                      enetc_wr_reg_hot(tx_ring->idr, BIT(tx_ring->index) |
++                                       BIT(16 + tx_ring->index));
+               }
+               if (unlikely(!bds_to_clean))
+                       bds_to_clean = enetc_bd_ready_count(tx_ring, i);
++
++              spin_unlock_irqrestore(lock, flags);
+       }
+       tx_ring->next_to_clean = i;
+@@ -470,13 +509,14 @@ static int enetc_refill_rx_ring(struct e
+               rx_ring->next_to_alloc = i; /* keep track from page reuse */
+               rx_ring->next_to_use = i;
+               /* update ENETC's consumer index */
+-              enetc_wr_reg(rx_ring->rcir, i);
++              enetc_wr_reg_hot(rx_ring->rcir, i);
+       }
+       return j;
+ }
+ #ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
++/* Must be called with &enetc_gregs spinlock held */
+ static void enetc_get_rx_tstamp(struct net_device *ndev,
+                               union enetc_rx_bd *rxbd,
+                               struct sk_buff *skb)
+@@ -488,8 +528,8 @@ static void enetc_get_rx_tstamp(struct n
+       u64 tstamp;
+       if (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_TSTMP) {
+-              lo = enetc_rd(hw, ENETC_SICTR0);
+-              hi = enetc_rd(hw, ENETC_SICTR1);
++              lo = enetc_rd_reg_hot(hw->reg + ENETC_SICTR0);
++              hi = enetc_rd_reg_hot(hw->reg + ENETC_SICTR1);
+               tstamp_lo = le32_to_cpu(rxbd->r.tstamp);
+               if (lo <= tstamp_lo)
+                       hi -= 1;
+@@ -627,6 +667,12 @@ static int enetc_clean_rx_ring(struct en
+       int rx_frm_cnt = 0, rx_byte_cnt = 0;
+       int cleaned_cnt, i;
++      unsigned long flags;
++      /* pointer to per-cpu ENETC lock for register access issue WA */
++      spinlock_t *lock;
++
++      lock = this_cpu_ptr(&enetc_gregs);
++
+       cleaned_cnt = enetc_bd_unused(rx_ring);
+       /* next descriptor to process */
+       i = rx_ring->next_to_clean;
+@@ -637,6 +683,8 @@ static int enetc_clean_rx_ring(struct en
+               u32 bd_status;
+               u16 size;
++              spin_lock_irqsave(lock, flags);
++
+               if (cleaned_cnt >= ENETC_RXBD_BUNDLE) {
+                       int count = enetc_refill_rx_ring(rx_ring, cleaned_cnt);
+@@ -645,15 +693,19 @@ static int enetc_clean_rx_ring(struct en
+               rxbd = ENETC_RXBD(*rx_ring, i);
+               bd_status = le32_to_cpu(rxbd->r.lstatus);
+-              if (!bd_status)
++              if (!bd_status) {
++                      spin_unlock_irqrestore(lock, flags);
+                       break;
++              }
+-              enetc_wr_reg(rx_ring->idr, BIT(rx_ring->index));
++              enetc_wr_reg_hot(rx_ring->idr, BIT(rx_ring->index));
+               dma_rmb(); /* for reading other rxbd fields */
+               size = le16_to_cpu(rxbd->r.buf_len);
+               skb = enetc_map_rx_buff_to_skb(rx_ring, i, size);
+-              if (!skb)
++              if (!skb) {
++                      spin_unlock_irqrestore(lock, flags);
+                       break;
++              }
+               enetc_get_offloads(rx_ring, rxbd, skb);
+@@ -667,6 +719,7 @@ static int enetc_clean_rx_ring(struct en
+               if (unlikely(bd_status &
+                            ENETC_RXBD_LSTATUS(ENETC_RXBD_ERR_MASK))) {
++                      spin_unlock_irqrestore(lock, flags);
+                       dev_kfree_skb(skb);
+                       while (!(bd_status & ENETC_RXBD_LSTATUS_F)) {
+                               dma_rmb();
+@@ -710,6 +763,8 @@ static int enetc_clean_rx_ring(struct en
+               enetc_process_skb(rx_ring, skb);
++              spin_unlock_irqrestore(lock, flags);
++
+               napi_gro_receive(napi, skb);
+               rx_frm_cnt++;
+--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+@@ -321,8 +321,15 @@ struct enetc_hw {
+ };
+ /* general register accessors */
+-#define enetc_rd_reg(reg)     ioread32((reg))
+-#define enetc_wr_reg(reg, val)        iowrite32((val), (reg))
++#define enetc_rd_reg(reg)     enetc_rd_reg_wa((reg))
++#define enetc_wr_reg(reg, val)        enetc_wr_reg_wa((reg), (val))
++
++/* accessors for data-path, due to MDIO issue on LS1028 these should be called
++ * only under enetc_gregs per-cpu lock
++ */
++#define enetc_rd_reg_hot(reg) ioread32((reg))
++#define enetc_wr_reg_hot(reg, val)    iowrite32((val), (reg))
++
+ #ifdef ioread64
+ #define enetc_rd_reg64(reg)   ioread64((reg))
+ #else
+@@ -341,12 +348,102 @@ static inline u64 enetc_rd_reg64(void __
+ }
+ #endif
++extern DEFINE_PER_CPU(spinlock_t, enetc_gregs);
++
++static inline u32 enetc_rd_reg_wa(void *reg)
++{
++      unsigned long flags;
++      /* pointer to per-cpu ENETC lock for register access issue WA */
++      spinlock_t *lock;
++      u32 val;
++
++      lock = this_cpu_ptr(&enetc_gregs);
++      spin_lock_irqsave(lock, flags);
++      val = ioread32(reg);
++      spin_unlock_irqrestore(lock, flags);
++
++      return val;
++}
++
++static inline void enetc_wr_reg_wa(void *reg, u32 val)
++{
++      unsigned long flags;
++      /* pointer to per-cpu ENETC lock for register access issue WA */
++      spinlock_t *lock;
++
++      lock = this_cpu_ptr(&enetc_gregs);
++      spin_lock_irqsave(lock, flags);
++      iowrite32(val, reg);
++      spin_unlock_irqrestore(lock, flags);
++}
++
++/* NR_CPUS=256 in ARM64 defconfig and using it as array size triggers stack
++ * frame warnings for the functions below.  Use a custom define of 2 for now,
++ * LS1028 has just two cores.
++ */
++#define ENETC_NR_CPU_LOCKS    2
++
++static inline u32 enetc_rd_reg_wa_single(void *reg)
++{
++      u32 val;
++      int cpu;
++      /* per-cpu ENETC lock array for register access issue WA */
++      spinlock_t *lock[ENETC_NR_CPU_LOCKS];
++      unsigned long flags;
++
++      local_irq_save(flags);
++      preempt_disable();
++
++      for_each_online_cpu(cpu) {
++              lock[cpu] = per_cpu_ptr(&enetc_gregs, cpu);
++              spin_lock(lock[cpu]);
++      }
++
++      val = ioread32(reg);
++
++      for_each_online_cpu(cpu)
++              spin_unlock(lock[cpu]);
++      local_irq_restore(flags);
++
++      preempt_enable();
++
++      return val;
++}
++
++static inline void enetc_wr_reg_wa_single(void *reg, u32 val)
++{
++      int cpu;
++      /* per-cpu ENETC lock array for register access issue WA */
++      spinlock_t *lock[ENETC_NR_CPU_LOCKS];
++      unsigned long flags;
++
++      local_irq_save(flags);
++      preempt_disable();
++
++      for_each_online_cpu(cpu) {
++              lock[cpu] = per_cpu_ptr(&enetc_gregs, cpu);
++              spin_lock(lock[cpu]);
++      }
++
++      iowrite32(val, reg);
++
++      for_each_online_cpu(cpu)
++              spin_unlock(lock[cpu]);
++      local_irq_restore(flags);
++
++      preempt_enable();
++}
++
+ #define enetc_rd(hw, off)             enetc_rd_reg((hw)->reg + (off))
+ #define enetc_wr(hw, off, val)                enetc_wr_reg((hw)->reg + (off), val)
+ #define enetc_rd64(hw, off)           enetc_rd_reg64((hw)->reg + (off))
+ /* port register accessors - PF only */
+-#define enetc_port_rd(hw, off)                enetc_rd_reg((hw)->port + (off))
+-#define enetc_port_wr(hw, off, val)   enetc_wr_reg((hw)->port + (off), val)
++#define enetc_port_rd(hw, off)                enetc_rd_reg_wa((hw)->port + (off))
++#define enetc_port_wr(hw, off, val)   enetc_wr_reg_wa((hw)->port + (off), val)
++#define enetc_port_rd_single(hw, off)         enetc_rd_reg_wa_single(\
++                                                      (hw)->port + (off))
++#define enetc_port_wr_single(hw, off, val)    enetc_wr_reg_wa_single(\
++                                                      (hw)->port + (off), val)
+ /* global register accessors - PF only */
+ #define enetc_global_rd(hw, off)      enetc_rd_reg((hw)->global + (off))
+ #define enetc_global_wr(hw, off, val) enetc_wr_reg((hw)->global + (off), val)
+--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
+@@ -16,13 +16,13 @@
+ static inline u32 _enetc_mdio_rd(struct enetc_mdio_priv *mdio_priv, int off)
+ {
+-      return enetc_port_rd(mdio_priv->hw, mdio_priv->mdio_base + off);
++      return enetc_port_rd_single(mdio_priv->hw, mdio_priv->mdio_base + off);
+ }
+ static inline void _enetc_mdio_wr(struct enetc_mdio_priv *mdio_priv, int off,
+                                 u32 val)
+ {
+-      enetc_port_wr(mdio_priv->hw, mdio_priv->mdio_base + off, val);
++      enetc_port_wr_single(mdio_priv->hw, mdio_priv->mdio_base + off, val);
+ }
+ #define enetc_mdio_rd(mdio_priv, off) \
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -986,6 +986,9 @@ static void enetc_pf_remove(struct pci_d
+       enetc_pci_remove(pdev);
+ }
++DEFINE_PER_CPU(spinlock_t, enetc_gregs);
++EXPORT_PER_CPU_SYMBOL(enetc_gregs);
++
+ static const struct pci_device_id enetc_pf_id_table[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PF) },
+       { 0, } /* End of table. */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0235-enetc-Clean-up-of-ehtool-stats-len.patch b/target/linux/layerscape/patches-5.4/701-net-0235-enetc-Clean-up-of-ehtool-stats-len.patch
new file mode 100644 (file)
index 0000000..b085ea3
--- /dev/null
@@ -0,0 +1,44 @@
+From a5e4a018cf5c7ed9709141c41ba7b262aa79870d Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Tue, 22 Oct 2019 20:23:38 +0300
+Subject: [PATCH] enetc: Clean up of ehtool stats len
+
+Just refactoring stats len code to make it easier to
+add new stats counters.
+
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_ethtool.c | 20 +++++++++++++-------
+ 1 file changed, 13 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+@@ -195,15 +195,21 @@ static const char tx_ring_stats[][ETH_GS
+ static int enetc_get_sset_count(struct net_device *ndev, int sset)
+ {
+       struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      int len;
+-      if (sset == ETH_SS_STATS)
+-              return ARRAY_SIZE(enetc_si_counters) +
+-                      ARRAY_SIZE(tx_ring_stats) * priv->num_tx_rings +
+-                      ARRAY_SIZE(rx_ring_stats) * priv->num_rx_rings +
+-                      (enetc_si_is_pf(priv->si) ?
+-                      ARRAY_SIZE(enetc_port_counters) : 0);
++      if (sset != ETH_SS_STATS)
++              return -EOPNOTSUPP;
+-      return -EOPNOTSUPP;
++      len = ARRAY_SIZE(enetc_si_counters) +
++            ARRAY_SIZE(tx_ring_stats) * priv->num_tx_rings +
++            ARRAY_SIZE(rx_ring_stats) * priv->num_rx_rings;
++
++      if (!enetc_si_is_pf(priv->si))
++              return len;
++
++      len += ARRAY_SIZE(enetc_port_counters);
++
++      return len;
+ }
+ static void enetc_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
diff --git a/target/linux/layerscape/patches-5.4/701-net-0236-enetc-Replace-enetc_gregs-with-a-readers-writer-lock.patch b/target/linux/layerscape/patches-5.4/701-net-0236-enetc-Replace-enetc_gregs-with-a-readers-writer-lock.patch
new file mode 100644 (file)
index 0000000..979c2da
--- /dev/null
@@ -0,0 +1,385 @@
+From 659f899773f9f3fdc8325f61acc1017dd838126c Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Thu, 14 Nov 2019 17:30:50 +0200
+Subject: [PATCH] enetc: Replace enetc_gregs with a readers-writer lock
+
+The LS1028A MDIO errata tells us that any MDIO register access must not
+be concurrent with any other ENETC register access.
+
+That has been handled so far by a number of per-CPU spinlocks over the
+ENETC register map. This came as an optimization over a single spinlock,
+because the regular register accesses can still be concurrent with one
+another, as long as they aren't concurrent with MDIO.
+
+But this logic is broken in RT, because the enetc_rd_reg_wa and
+enetc_wr_reg_wa functions can be preempted in any context, and when they
+resume they may not run on the same CPU.
+
+This renders the logic to take the per-CPU spinlock pointless, since the
+spinlock may not be the correct one (corresponding to this CPU) after
+preemption has occurred.
+
+The following splat is telling us the same thing:
+
+[   19.073928] BUG: using smp_processor_id() in preemptible [00000000] code: systemd-network/3423
+[   19.073932] caller is debug_smp_processor_id+0x1c/0x30
+[   19.073935] CPU: 1 PID: 3423 Comm: systemd-network Not tainted 4.19.68-rt26 #1
+[   19.073936] Hardware name: LS1028A RDB Board (DT)
+[   19.073938] Call trace:
+[   19.073940]  dump_backtrace+0x0/0x1a0
+[   19.073942]  show_stack+0x24/0x30
+[   19.073945]  dump_stack+0x9c/0xdc
+[   19.073948]  check_preemption_disabled+0xe0/0x100
+[   19.073951]  debug_smp_processor_id+0x1c/0x30
+[   19.073954]  enetc_open+0x1b0/0xbc0
+[   19.073957]  __dev_open+0xdc/0x160
+[   19.073960]  __dev_change_flags+0x160/0x1d0
+[   19.073963]  dev_change_flags+0x34/0x70
+[   19.073966]  do_setlink+0x2a0/0xcd0
+[   19.073969]  rtnl_setlink+0xe4/0x140
+[   19.073972]  rtnetlink_rcv_msg+0x18c/0x500
+[   19.073975]  netlink_rcv_skb+0x60/0x120
+[   19.073978]  rtnetlink_rcv+0x28/0x40
+[   19.073982]  netlink_unicast+0x194/0x210
+[   19.073985]  netlink_sendmsg+0x194/0x330
+[   19.073987]  sock_sendmsg+0x34/0x50
+[   19.073990]  __sys_sendto+0xe4/0x150
+[   19.073992]  __arm64_sys_sendto+0x30/0x40
+[   19.073996]  el0_svc_common+0xa4/0x1a0
+[   19.073999]  el0_svc_handler+0x38/0x80
+[   19.074002]  el0_svc+0x8/0xc
+
+But there already exists a spinlock optimized for the single writer,
+multiple readers case: the rwlock_t. The writer in this case is the MDIO
+access code (irrelevant whether that MDIO access is a register read or
+write), and the reader is everybody else.
+
+This patch also fixes two more existing bugs in the errata workaround:
+- The MDIO access code was not unlocking the per-CPU spinlocks in the
+  reverse order of their locking order.
+- The per-CPU spinlock array was not initialized.
+
+Fixes: 5ec0d668d62e ("enetc: WA for MDIO register access issue")
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc.c    | 59 ++++++----------------
+ drivers/net/ethernet/freescale/enetc/enetc_hw.h | 67 ++++---------------------
+ drivers/net/ethernet/freescale/enetc/enetc_pf.c |  5 +-
+ 3 files changed, 30 insertions(+), 101 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc.c
+@@ -20,13 +20,8 @@ netdev_tx_t enetc_xmit(struct sk_buff *s
+ {
+       struct enetc_ndev_priv *priv = netdev_priv(ndev);
+       struct enetc_bdr *tx_ring;
+-      unsigned long flags;
+-      /* pointer to per-cpu ENETC lock for register access issue WA */
+-      spinlock_t *lock;
+       int count;
+-      lock = this_cpu_ptr(&enetc_gregs);
+-
+       tx_ring = priv->tx_ring[skb->queue_mapping];
+       if (unlikely(skb_shinfo(skb)->nr_frags > ENETC_MAX_SKB_FRAGS))
+@@ -39,11 +34,9 @@ netdev_tx_t enetc_xmit(struct sk_buff *s
+               return NETDEV_TX_BUSY;
+       }
+-      spin_lock_irqsave(lock, flags);
+-
++      read_lock(&enetc_mdio_lock);
+       count = enetc_map_tx_buffs(tx_ring, skb, priv->active_offloads);
+-
+-      spin_unlock_irqrestore(lock, flags);
++      read_unlock(&enetc_mdio_lock);
+       if (unlikely(!count))
+               goto drop_packet_err;
+@@ -259,13 +252,9 @@ dma_err:
+ static irqreturn_t enetc_msix(int irq, void *data)
+ {
+       struct enetc_int_vector *v = data;
+-      unsigned long flags;
+-      /* pointer to per-cpu ENETC lock for register access issue WA */
+-      spinlock_t *lock;
+       int i;
+-      lock = this_cpu_ptr(&enetc_gregs);
+-      spin_lock_irqsave(lock, flags);
++      read_lock(&enetc_mdio_lock);
+       /* disable interrupts */
+       enetc_wr_reg_hot(v->rbier, 0);
+@@ -273,7 +262,7 @@ static irqreturn_t enetc_msix(int irq, v
+       for_each_set_bit(i, &v->tx_rings_map, v->count_tx_rings)
+               enetc_wr_reg_hot(v->tbier_base + ENETC_BDR_OFF(i), 0);
+-      spin_unlock_irqrestore(lock, flags);
++      read_unlock(&enetc_mdio_lock);
+       napi_schedule_irqoff(&v->napi);
+@@ -289,9 +278,6 @@ static int enetc_poll(struct napi_struct
+       struct enetc_int_vector
+               *v = container_of(napi, struct enetc_int_vector, napi);
+       bool complete = true;
+-      unsigned long flags;
+-      /* pointer to per-cpu ENETC lock for register access issue WA */
+-      spinlock_t *lock;
+       int work_done;
+       int i;
+@@ -308,8 +294,7 @@ static int enetc_poll(struct napi_struct
+       napi_complete_done(napi, work_done);
+-      lock = this_cpu_ptr(&enetc_gregs);
+-      spin_lock_irqsave(lock, flags);
++      read_lock(&enetc_mdio_lock);
+       /* enable interrupts */
+       enetc_wr_reg_hot(v->rbier, ENETC_RBIER_RXTIE);
+@@ -318,7 +303,7 @@ static int enetc_poll(struct napi_struct
+               enetc_wr_reg_hot(v->tbier_base + ENETC_BDR_OFF(i),
+                                ENETC_TBIER_TXTIE);
+-      spin_unlock_irqrestore(lock, flags);
++      read_unlock(&enetc_mdio_lock);
+       return work_done;
+ }
+@@ -363,18 +348,12 @@ static bool enetc_clean_tx_ring(struct e
+       bool do_tstamp;
+       u64 tstamp = 0;
+-      unsigned long flags;
+-      /* pointer to per-cpu ENETC lock for register access issue WA */
+-      spinlock_t *lock;
+-
+-      lock = this_cpu_ptr(&enetc_gregs);
+-
+       i = tx_ring->next_to_clean;
+       tx_swbd = &tx_ring->tx_swbd[i];
+-      spin_lock_irqsave(lock, flags);
++      read_lock(&enetc_mdio_lock);
+       bds_to_clean = enetc_bd_ready_count(tx_ring, i);
+-      spin_unlock_irqrestore(lock, flags);
++      read_unlock(&enetc_mdio_lock);
+       do_tstamp = false;
+@@ -417,7 +396,7 @@ static bool enetc_clean_tx_ring(struct e
+                       tx_swbd = tx_ring->tx_swbd;
+               }
+-              spin_lock_irqsave(lock, flags);
++              read_lock(&enetc_mdio_lock);
+               /* BD iteration loop end */
+               if (is_eof) {
+@@ -430,7 +409,7 @@ static bool enetc_clean_tx_ring(struct e
+               if (unlikely(!bds_to_clean))
+                       bds_to_clean = enetc_bd_ready_count(tx_ring, i);
+-              spin_unlock_irqrestore(lock, flags);
++              read_unlock(&enetc_mdio_lock);
+       }
+       tx_ring->next_to_clean = i;
+@@ -516,7 +495,7 @@ static int enetc_refill_rx_ring(struct e
+ }
+ #ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
+-/* Must be called with &enetc_gregs spinlock held */
++/* Must be called with the read-side enetc_mdio_lock held */
+ static void enetc_get_rx_tstamp(struct net_device *ndev,
+                               union enetc_rx_bd *rxbd,
+                               struct sk_buff *skb)
+@@ -667,12 +646,6 @@ static int enetc_clean_rx_ring(struct en
+       int rx_frm_cnt = 0, rx_byte_cnt = 0;
+       int cleaned_cnt, i;
+-      unsigned long flags;
+-      /* pointer to per-cpu ENETC lock for register access issue WA */
+-      spinlock_t *lock;
+-
+-      lock = this_cpu_ptr(&enetc_gregs);
+-
+       cleaned_cnt = enetc_bd_unused(rx_ring);
+       /* next descriptor to process */
+       i = rx_ring->next_to_clean;
+@@ -683,7 +656,7 @@ static int enetc_clean_rx_ring(struct en
+               u32 bd_status;
+               u16 size;
+-              spin_lock_irqsave(lock, flags);
++              read_lock(&enetc_mdio_lock);
+               if (cleaned_cnt >= ENETC_RXBD_BUNDLE) {
+                       int count = enetc_refill_rx_ring(rx_ring, cleaned_cnt);
+@@ -694,7 +667,7 @@ static int enetc_clean_rx_ring(struct en
+               rxbd = ENETC_RXBD(*rx_ring, i);
+               bd_status = le32_to_cpu(rxbd->r.lstatus);
+               if (!bd_status) {
+-                      spin_unlock_irqrestore(lock, flags);
++                      read_unlock(&enetc_mdio_lock);
+                       break;
+               }
+@@ -703,7 +676,7 @@ static int enetc_clean_rx_ring(struct en
+               size = le16_to_cpu(rxbd->r.buf_len);
+               skb = enetc_map_rx_buff_to_skb(rx_ring, i, size);
+               if (!skb) {
+-                      spin_unlock_irqrestore(lock, flags);
++                      read_unlock(&enetc_mdio_lock);
+                       break;
+               }
+@@ -719,7 +692,7 @@ static int enetc_clean_rx_ring(struct en
+               if (unlikely(bd_status &
+                            ENETC_RXBD_LSTATUS(ENETC_RXBD_ERR_MASK))) {
+-                      spin_unlock_irqrestore(lock, flags);
++                      read_unlock(&enetc_mdio_lock);
+                       dev_kfree_skb(skb);
+                       while (!(bd_status & ENETC_RXBD_LSTATUS_F)) {
+                               dma_rmb();
+@@ -763,7 +736,7 @@ static int enetc_clean_rx_ring(struct en
+               enetc_process_skb(rx_ring, skb);
+-              spin_unlock_irqrestore(lock, flags);
++              read_unlock(&enetc_mdio_lock);
+               napi_gro_receive(napi, skb);
+--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+@@ -325,7 +325,7 @@ struct enetc_hw {
+ #define enetc_wr_reg(reg, val)        enetc_wr_reg_wa((reg), (val))
+ /* accessors for data-path, due to MDIO issue on LS1028 these should be called
+- * only under enetc_gregs per-cpu lock
++ * only under the rwlock_t enetc_mdio_lock
+  */
+ #define enetc_rd_reg_hot(reg) ioread32((reg))
+ #define enetc_wr_reg_hot(reg, val)    iowrite32((val), (reg))
+@@ -348,90 +348,45 @@ static inline u64 enetc_rd_reg64(void __
+ }
+ #endif
+-extern DEFINE_PER_CPU(spinlock_t, enetc_gregs);
++extern rwlock_t enetc_mdio_lock;
+ static inline u32 enetc_rd_reg_wa(void *reg)
+ {
+-      unsigned long flags;
+-      /* pointer to per-cpu ENETC lock for register access issue WA */
+-      spinlock_t *lock;
+       u32 val;
+-      lock = this_cpu_ptr(&enetc_gregs);
+-      spin_lock_irqsave(lock, flags);
++      read_lock(&enetc_mdio_lock);
+       val = ioread32(reg);
+-      spin_unlock_irqrestore(lock, flags);
++      read_unlock(&enetc_mdio_lock);
+       return val;
+ }
+ static inline void enetc_wr_reg_wa(void *reg, u32 val)
+ {
+-      unsigned long flags;
+-      /* pointer to per-cpu ENETC lock for register access issue WA */
+-      spinlock_t *lock;
+-
+-      lock = this_cpu_ptr(&enetc_gregs);
+-      spin_lock_irqsave(lock, flags);
++      read_lock(&enetc_mdio_lock);
+       iowrite32(val, reg);
+-      spin_unlock_irqrestore(lock, flags);
++      read_unlock(&enetc_mdio_lock);
+ }
+-/* NR_CPUS=256 in ARM64 defconfig and using it as array size triggers stack
+- * frame warnings for the functions below.  Use a custom define of 2 for now,
+- * LS1028 has just two cores.
+- */
+-#define ENETC_NR_CPU_LOCKS    2
+-
+ static inline u32 enetc_rd_reg_wa_single(void *reg)
+ {
+-      u32 val;
+-      int cpu;
+-      /* per-cpu ENETC lock array for register access issue WA */
+-      spinlock_t *lock[ENETC_NR_CPU_LOCKS];
+       unsigned long flags;
++      u32 val;
+-      local_irq_save(flags);
+-      preempt_disable();
+-
+-      for_each_online_cpu(cpu) {
+-              lock[cpu] = per_cpu_ptr(&enetc_gregs, cpu);
+-              spin_lock(lock[cpu]);
+-      }
+-
++      write_lock_irqsave(&enetc_mdio_lock, flags);
+       val = ioread32(reg);
+-
+-      for_each_online_cpu(cpu)
+-              spin_unlock(lock[cpu]);
+-      local_irq_restore(flags);
+-
+-      preempt_enable();
++      write_unlock_irqrestore(&enetc_mdio_lock, flags);
+       return val;
+ }
+ static inline void enetc_wr_reg_wa_single(void *reg, u32 val)
+ {
+-      int cpu;
+-      /* per-cpu ENETC lock array for register access issue WA */
+-      spinlock_t *lock[ENETC_NR_CPU_LOCKS];
+       unsigned long flags;
+-      local_irq_save(flags);
+-      preempt_disable();
+-
+-      for_each_online_cpu(cpu) {
+-              lock[cpu] = per_cpu_ptr(&enetc_gregs, cpu);
+-              spin_lock(lock[cpu]);
+-      }
+-
++      write_lock_irqsave(&enetc_mdio_lock, flags);
+       iowrite32(val, reg);
+-
+-      for_each_online_cpu(cpu)
+-              spin_unlock(lock[cpu]);
+-      local_irq_restore(flags);
+-
+-      preempt_enable();
++      write_unlock_irqrestore(&enetc_mdio_lock, flags);
+ }
+ #define enetc_rd(hw, off)             enetc_rd_reg((hw)->reg + (off))
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -986,8 +986,9 @@ static void enetc_pf_remove(struct pci_d
+       enetc_pci_remove(pdev);
+ }
+-DEFINE_PER_CPU(spinlock_t, enetc_gregs);
+-EXPORT_PER_CPU_SYMBOL(enetc_gregs);
++/* Lock for MDIO access errata on LS1028A */
++DEFINE_RWLOCK(enetc_mdio_lock);
++EXPORT_SYMBOL_GPL(enetc_mdio_lock);
+ static const struct pci_device_id enetc_pf_id_table[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PF) },
diff --git a/target/linux/layerscape/patches-5.4/701-net-0237-enetc-Remove-mdio-bus-on-PF-probe-error-path.patch b/target/linux/layerscape/patches-5.4/701-net-0237-enetc-Remove-mdio-bus-on-PF-probe-error-path.patch
new file mode 100644 (file)
index 0000000..e3d3697
--- /dev/null
@@ -0,0 +1,58 @@
+From 73204b342fbee1fd9364365c1213815cc715eee2 Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Thu, 14 Nov 2019 16:22:39 +0200
+Subject: [PATCH] enetc: Remove mdio bus on PF probe error path
+
+Fixes following kernel panic on the probing error
+path, when pci=nomsi bootarg is used (which is
+not supporrted by the enetc dirver):
+
+fsl_enetc 0000:00:00.0: MSIX alloc failed
+------------[ cut here ]------------
+kernel BUG at drivers/net/phy/mdio_bus.c:487!
+Internal error: Oops - BUG: 0 [#1] PREEMPT SMP
+Modules linked in:
+Process swapper/0 (pid: 1, stack limit = 0x(____ptrval____))
+CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.19.68-00004-g85dc4876e6e6 #1
+Hardware name: LS1028A RDB Board (DT)
+pstate: 80000005 (Nzcv daif -PAN -UAO)
+pc : mdiobus_free+0x5c/0x60
+lr : _devm_mdiobus_free+0x20/0x30
+[...]
+Call trace:
+ mdiobus_free+0x5c/0x60
+ _devm_mdiobus_free+0x20/0x30
+ release_nodes+0x148/0x238
+ devres_release_all+0x3c/0x68
+ really_probe+0x90/0x2a0
+ driver_probe_device+0x5c/0x100
+ __driver_attach+0xf0/0xf8
+ bus_for_each_dev+0x84/0xd8
+ driver_attach+0x30/0x40
+ bus_add_driver+0x1c4/0x230
+ driver_register+0x64/0x110
+ __pci_register_driver+0x58/0x68
+ enetc_pf_driver_init+0x28/0x30
+ do_one_initcall+0x54/0x268
+ kernel_init_freeable+0x2d0/0x37c
+ kernel_init+0x18/0x118
+ ret_from_fork+0x10/0x1c
+Code: 97e0dd79 f9400bf3 a8c27bfd d65f03c0 (d4210000)
+---[ end trace 1e4e5729f059b773 ]---
+
+Fixes: ebfcb23d62ab ("enetc: Add ENETC PF level external MDIO support")
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_pf.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -952,6 +952,7 @@ err_alloc_si_res:
+       si->ndev = NULL;
+       free_netdev(ndev);
+ err_alloc_netdev:
++      enetc_mdio_remove(pf);
+       enetc_of_put_phy(pf);
+ err_map_pf_space:
+       enetc_pci_remove(pdev);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0238-net-mscc-ocelot-break-apart-ocelot_vlan_port_apply.patch b/target/linux/layerscape/patches-5.4/701-net-0238-net-mscc-ocelot-break-apart-ocelot_vlan_port_apply.patch
new file mode 100644 (file)
index 0000000..42ea285
--- /dev/null
@@ -0,0 +1,314 @@
+From d00ac78e74e433109307f365ba90d34cd73aaf20 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Sat, 9 Nov 2019 15:02:47 +0200
+Subject: [PATCH] net: mscc: ocelot: break apart ocelot_vlan_port_apply
+
+This patch transforms the ocelot_vlan_port_apply function ("apply
+what?") into 3 standalone functions:
+
+- ocelot_port_vlan_filtering
+- ocelot_port_set_native_vlan
+- ocelot_port_set_pvid
+
+These functions have a prototype that is better aligned to the DSA API.
+
+The function also had some static initialization (TPID, drop frames with
+multicast source MAC) which was not being changed from any place, so
+that was just moved to ocelot_probe_port (one of the 6 callers of
+ocelot_vlan_port_apply).
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 168 ++++++++++++++++++++++---------------
+ 1 file changed, 100 insertions(+), 68 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -185,65 +185,97 @@ static void ocelot_vlan_mode(struct ocel
+       ocelot_write(ocelot, val, ANA_VLANMASK);
+ }
+-static void ocelot_vlan_port_apply(struct ocelot *ocelot,
+-                                 struct ocelot_port *port)
++static void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
++                                     bool vlan_aware)
+ {
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
+       u32 val;
+-      /* Ingress clasification (ANA_PORT_VLAN_CFG) */
+-      /* Default vlan to clasify for untagged frames (may be zero) */
+-      val = ANA_PORT_VLAN_CFG_VLAN_VID(port->pvid);
+-      if (port->vlan_aware)
+-              val |= ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA |
+-                     ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1);
+-
++      if (vlan_aware)
++              val = ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA |
++                    ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1);
++      else
++              val = 0;
+       ocelot_rmw_gix(ocelot, val,
+-                     ANA_PORT_VLAN_CFG_VLAN_VID_M |
+                      ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA |
+                      ANA_PORT_VLAN_CFG_VLAN_POP_CNT_M,
+-                     ANA_PORT_VLAN_CFG, port->chip_port);
++                     ANA_PORT_VLAN_CFG, port);
+-      /* Drop frames with multicast source address */
+-      val = ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA;
+-      if (port->vlan_aware && !port->vid)
++      if (vlan_aware && !ocelot_port->vid)
+               /* If port is vlan-aware and tagged, drop untagged and priority
+                * tagged frames.
+                */
+-              val |= ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA |
++              val = ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA |
++                    ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA |
++                    ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA;
++      else
++              val = 0;
++      ocelot_rmw_gix(ocelot, val,
++                     ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA |
+                      ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA |
+-                     ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA;
+-      ocelot_write_gix(ocelot, val, ANA_PORT_DROP_CFG, port->chip_port);
+-
+-      /* Egress configuration (REW_TAG_CFG): VLAN tag type to 8021Q. */
+-      val = REW_TAG_CFG_TAG_TPID_CFG(0);
++                     ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA,
++                     ANA_PORT_DROP_CFG, port);
+-      if (port->vlan_aware) {
+-              if (port->vid)
++      if (vlan_aware) {
++              if (ocelot_port->vid)
+                       /* Tag all frames except when VID == DEFAULT_VLAN */
+                       val |= REW_TAG_CFG_TAG_CFG(1);
+               else
+                       /* Tag all frames */
+                       val |= REW_TAG_CFG_TAG_CFG(3);
++      } else {
++              /* Port tagging disabled. */
++              val = REW_TAG_CFG_TAG_CFG(0);
+       }
+       ocelot_rmw_gix(ocelot, val,
+-                     REW_TAG_CFG_TAG_TPID_CFG_M |
+                      REW_TAG_CFG_TAG_CFG_M,
+-                     REW_TAG_CFG, port->chip_port);
++                     REW_TAG_CFG, port);
+-      /* Set default VLAN and tag type to 8021Q. */
+-      val = REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021Q) |
+-            REW_PORT_VLAN_CFG_PORT_VID(port->vid);
+-      ocelot_rmw_gix(ocelot, val,
+-                     REW_PORT_VLAN_CFG_PORT_TPID_M |
++      ocelot_port->vlan_aware = vlan_aware;
++}
++
++static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port,
++                                     u16 vid)
++{
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++
++      if (ocelot_port->vid != vid) {
++              /* Always permit deleting the native VLAN (vid = 0) */
++              if (ocelot_port->vid && vid) {
++                      dev_err(ocelot->dev,
++                              "Port already has a native VLAN: %d\n",
++                              ocelot_port->vid);
++                      return -EBUSY;
++              }
++              ocelot_port->vid = vid;
++      }
++
++      ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_VID(vid),
+                      REW_PORT_VLAN_CFG_PORT_VID_M,
+-                     REW_PORT_VLAN_CFG, port->chip_port);
++                     REW_PORT_VLAN_CFG, port);
++
++      return 0;
++}
++
++/* Default vlan to clasify for untagged frames (may be zero) */
++static void ocelot_port_set_pvid(struct ocelot *ocelot, int port, u16 pvid)
++{
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++
++      ocelot_rmw_gix(ocelot,
++                     ANA_PORT_VLAN_CFG_VLAN_VID(pvid),
++                     ANA_PORT_VLAN_CFG_VLAN_VID_M,
++                     ANA_PORT_VLAN_CFG, port);
++
++      ocelot_port->pvid = pvid;
+ }
+ static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid,
+                              bool untagged)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+-      struct ocelot *ocelot = port->ocelot;
++      struct ocelot_port *ocelot_port = netdev_priv(dev);
++      struct ocelot *ocelot = ocelot_port->ocelot;
++      int port = ocelot_port->chip_port;
+       int ret;
+       /* Add the port MAC address to with the right VLAN information */
+@@ -251,35 +283,30 @@ static int ocelot_vlan_vid_add(struct ne
+                         ENTRYTYPE_LOCKED);
+       /* Make the port a member of the VLAN */
+-      ocelot->vlan_mask[vid] |= BIT(port->chip_port);
++      ocelot->vlan_mask[vid] |= BIT(port);
+       ret = ocelot_vlant_set_mask(ocelot, vid, ocelot->vlan_mask[vid]);
+       if (ret)
+               return ret;
+       /* Default ingress vlan classification */
+       if (pvid)
+-              port->pvid = vid;
++              ocelot_port_set_pvid(ocelot, port, vid);
+       /* Untagged egress vlan clasification */
+-      if (untagged && port->vid != vid) {
+-              if (port->vid) {
+-                      dev_err(ocelot->dev,
+-                              "Port already has a native VLAN: %d\n",
+-                              port->vid);
+-                      return -EBUSY;
+-              }
+-              port->vid = vid;
++      if (untagged) {
++              ret = ocelot_port_set_native_vlan(ocelot, port, vid);
++              if (ret)
++                      return ret;
+       }
+-      ocelot_vlan_port_apply(ocelot, port);
+-
+       return 0;
+ }
+ static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+-      struct ocelot *ocelot = port->ocelot;
++      struct ocelot_port *ocelot_port = netdev_priv(dev);
++      struct ocelot *ocelot = ocelot_port->ocelot;
++      int port = ocelot_port->chip_port;
+       int ret;
+       /* 8021q removes VID 0 on module unload for all interfaces
+@@ -293,20 +320,18 @@ static int ocelot_vlan_vid_del(struct ne
+       ocelot_mact_forget(ocelot, dev->dev_addr, vid);
+       /* Stop the port from being a member of the vlan */
+-      ocelot->vlan_mask[vid] &= ~BIT(port->chip_port);
++      ocelot->vlan_mask[vid] &= ~BIT(port);
+       ret = ocelot_vlant_set_mask(ocelot, vid, ocelot->vlan_mask[vid]);
+       if (ret)
+               return ret;
+       /* Ingress */
+-      if (port->pvid == vid)
+-              port->pvid = 0;
++      if (ocelot_port->pvid == vid)
++              ocelot_port_set_pvid(ocelot, port, 0);
+       /* Egress */
+-      if (port->vid == vid)
+-              port->vid = 0;
+-
+-      ocelot_vlan_port_apply(ocelot, port);
++      if (ocelot_port->vid == vid)
++              ocelot_port_set_native_vlan(ocelot, port, 0);
+       return 0;
+ }
+@@ -1306,6 +1331,7 @@ static int ocelot_port_attr_set(struct n
+                               struct switchdev_trans *trans)
+ {
+       struct ocelot_port *ocelot_port = netdev_priv(dev);
++      struct ocelot *ocelot = ocelot_port->ocelot;
+       int err = 0;
+       switch (attr->id) {
+@@ -1317,8 +1343,8 @@ static int ocelot_port_attr_set(struct n
+               ocelot_port_attr_ageing_set(ocelot_port, attr->u.ageing_time);
+               break;
+       case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
+-              ocelot_port->vlan_aware = attr->u.vlan_filtering;
+-              ocelot_vlan_port_apply(ocelot_port->ocelot, ocelot_port);
++              ocelot_port_vlan_filtering(ocelot, ocelot_port->chip_port,
++                                         attr->u.vlan_filtering);
+               break;
+       case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
+               ocelot_port_attr_mc_set(ocelot_port, !attr->u.mc_disabled);
+@@ -1520,20 +1546,20 @@ static int ocelot_port_bridge_join(struc
+       return 0;
+ }
+-static void ocelot_port_bridge_leave(struct ocelot_port *ocelot_port,
+-                                   struct net_device *bridge)
++static int ocelot_port_bridge_leave(struct ocelot_port *ocelot_port,
++                                  struct net_device *bridge)
+ {
+       struct ocelot *ocelot = ocelot_port->ocelot;
++      int port = ocelot_port->chip_port;
+-      ocelot->bridge_mask &= ~BIT(ocelot_port->chip_port);
++      ocelot->bridge_mask &= ~BIT(port);
+       if (!ocelot->bridge_mask)
+               ocelot->hw_bridge_dev = NULL;
+-      /* Clear bridge vlan settings before calling ocelot_vlan_port_apply */
+-      ocelot_port->vlan_aware = 0;
+-      ocelot_port->pvid = 0;
+-      ocelot_port->vid = 0;
++      ocelot_port_vlan_filtering(ocelot, port, 0);
++      ocelot_port_set_pvid(ocelot, port, 0);
++      return ocelot_port_set_native_vlan(ocelot, port, 0);
+ }
+ static void ocelot_set_aggr_pgids(struct ocelot *ocelot)
+@@ -1687,11 +1713,8 @@ static int ocelot_netdevice_port_event(s
+                               err = ocelot_port_bridge_join(ocelot_port,
+                                                             info->upper_dev);
+                       else
+-                              ocelot_port_bridge_leave(ocelot_port,
+-                                                       info->upper_dev);
+-
+-                      ocelot_vlan_port_apply(ocelot_port->ocelot,
+-                                             ocelot_port);
++                              err = ocelot_port_bridge_leave(ocelot_port,
++                                                             info->upper_dev);
+               }
+               if (netif_is_lag_master(info->upper_dev)) {
+                       if (info->linking)
+@@ -2011,6 +2034,7 @@ int ocelot_probe_port(struct ocelot *oce
+ {
+       struct ocelot_port *ocelot_port;
+       struct net_device *dev;
++      u32 val;
+       int err;
+       dev = alloc_etherdev(sizeof(struct ocelot_port));
+@@ -2046,7 +2070,15 @@ int ocelot_probe_port(struct ocelot *oce
+       }
+       /* Basic L2 initialization */
+-      ocelot_vlan_port_apply(ocelot, ocelot_port);
++
++      /* Drop frames with multicast source address */
++      val = ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA;
++      ocelot_rmw_gix(ocelot, val, val, ANA_PORT_DROP_CFG, port);
++
++      /* Set default VLAN and tag type to 8021Q. */
++      ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021Q),
++                     REW_PORT_VLAN_CFG_PORT_TPID_M,
++                     REW_PORT_VLAN_CFG, port);
+       /* Enable vcap lookups */
+       ocelot_vcap_enable(ocelot, ocelot_port);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0239-net-mscc-ocelot-break-apart-vlan-operations-into-oce.patch b/target/linux/layerscape/patches-5.4/701-net-0239-net-mscc-ocelot-break-apart-vlan-operations-into-oce.patch
new file mode 100644 (file)
index 0000000..d2b2cfc
--- /dev/null
@@ -0,0 +1,108 @@
+From 829d9def89b452c4d13d15fd578dea524d9f8521 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Sat, 9 Nov 2019 15:02:48 +0200
+Subject: [PATCH] net: mscc: ocelot: break apart vlan operations into
+ ocelot_vlan_{add, del}
+
+We need an implementation of these functions that is agnostic to the
+higher layer (switchdev or dsa).
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 60 ++++++++++++++++++++++++++------------
+ 1 file changed, 42 insertions(+), 18 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -270,18 +270,11 @@ static void ocelot_port_set_pvid(struct
+       ocelot_port->pvid = pvid;
+ }
+-static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid,
+-                             bool untagged)
++static int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
++                         bool untagged)
+ {
+-      struct ocelot_port *ocelot_port = netdev_priv(dev);
+-      struct ocelot *ocelot = ocelot_port->ocelot;
+-      int port = ocelot_port->chip_port;
+       int ret;
+-      /* Add the port MAC address to with the right VLAN information */
+-      ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr, vid,
+-                        ENTRYTYPE_LOCKED);
+-
+       /* Make the port a member of the VLAN */
+       ocelot->vlan_mask[vid] |= BIT(port);
+       ret = ocelot_vlant_set_mask(ocelot, vid, ocelot->vlan_mask[vid]);
+@@ -302,22 +295,29 @@ static int ocelot_vlan_vid_add(struct ne
+       return 0;
+ }
+-static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid)
++static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid,
++                             bool untagged)
+ {
+       struct ocelot_port *ocelot_port = netdev_priv(dev);
+       struct ocelot *ocelot = ocelot_port->ocelot;
+       int port = ocelot_port->chip_port;
+       int ret;
+-      /* 8021q removes VID 0 on module unload for all interfaces
+-       * with VLAN filtering feature. We need to keep it to receive
+-       * untagged traffic.
+-       */
+-      if (vid == 0)
+-              return 0;
++      ret = ocelot_vlan_add(ocelot, port, vid, pvid, untagged);
++      if (ret)
++              return ret;
+-      /* Del the port MAC address to with the right VLAN information */
+-      ocelot_mact_forget(ocelot, dev->dev_addr, vid);
++      /* Add the port MAC address to with the right VLAN information */
++      ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr, vid,
++                        ENTRYTYPE_LOCKED);
++
++      return 0;
++}
++
++static int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid)
++{
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++      int ret;
+       /* Stop the port from being a member of the vlan */
+       ocelot->vlan_mask[vid] &= ~BIT(port);
+@@ -335,6 +335,30 @@ static int ocelot_vlan_vid_del(struct ne
+       return 0;
+ }
++
++static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid)
++{
++      struct ocelot_port *ocelot_port = netdev_priv(dev);
++      struct ocelot *ocelot = ocelot_port->ocelot;
++      int port = ocelot_port->chip_port;
++      int ret;
++
++      /* 8021q removes VID 0 on module unload for all interfaces
++       * with VLAN filtering feature. We need to keep it to receive
++       * untagged traffic.
++       */
++      if (vid == 0)
++              return 0;
++
++      ret = ocelot_vlan_del(ocelot, port, vid);
++      if (ret)
++              return ret;
++
++      /* Del the port MAC address to with the right VLAN information */
++      ocelot_mact_forget(ocelot, dev->dev_addr, vid);
++
++      return 0;
++}
+ static void ocelot_vlan_init(struct ocelot *ocelot)
+ {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0240-net-mscc-ocelot-break-out-fdb-operations-into-abstra.patch b/target/linux/layerscape/patches-5.4/701-net-0240-net-mscc-ocelot-break-out-fdb-operations-into-abstra.patch
new file mode 100644 (file)
index 0000000..118b91e
--- /dev/null
@@ -0,0 +1,251 @@
+From 0d1866b8c6f17a55207be651a3b3b93879fbdf1f Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Sat, 9 Nov 2019 15:02:49 +0200
+Subject: [PATCH] net: mscc: ocelot: break out fdb operations into abstract
+ implementations
+
+To be able to implement a DSA front-end over ocelot_fdb_add,
+ocelot_fdb_del, ocelot_fdb_dump, these need to have a simple function
+prototype that is independent of struct net_device, netlink skb, etc.
+
+So rename the ndo ops of the ocelot driver into
+ocelot_port_fdb_{add,del,dump}, and have them all call the abstract
+implementations. At the same time, refactor ocelot_port_fdb_do_dump into
+a function whose prototype is compatible with dsa_fdb_dump_cb_t, so that
+the do_dump implementations can live together and be called by the
+ocelot_fdb_dump through a function pointer.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 124 +++++++++++++++++++++++--------------
+ 1 file changed, 78 insertions(+), 46 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -21,6 +21,7 @@
+ #include <net/netevent.h>
+ #include <net/rtnetlink.h>
+ #include <net/switchdev.h>
++#include <net/dsa.h>
+ #include "ocelot.h"
+ #include "ocelot_ace.h"
+@@ -814,21 +815,18 @@ static void ocelot_get_stats64(struct ne
+       stats->collisions = ocelot_read(ocelot, SYS_COUNT_TX_COLLISION);
+ }
+-static int ocelot_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+-                        struct net_device *dev, const unsigned char *addr,
+-                        u16 vid, u16 flags,
+-                        struct netlink_ext_ack *extack)
++static int ocelot_fdb_add(struct ocelot *ocelot, int port,
++                        const unsigned char *addr, u16 vid)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+-      struct ocelot *ocelot = port->ocelot;
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
+       if (!vid) {
+-              if (!port->vlan_aware)
++              if (!ocelot_port->vlan_aware)
+                       /* If the bridge is not VLAN aware and no VID was
+                        * provided, set it to pvid to ensure the MAC entry
+                        * matches incoming untagged packets
+                        */
+-                      vid = port->pvid;
++                      vid = ocelot_port->pvid;
+               else
+                       /* If the bridge is VLAN aware a VID must be provided as
+                        * otherwise the learnt entry wouldn't match any frame.
+@@ -836,20 +834,37 @@ static int ocelot_fdb_add(struct ndmsg *
+                       return -EINVAL;
+       }
+-      return ocelot_mact_learn(ocelot, port->chip_port, addr, vid,
+-                               ENTRYTYPE_LOCKED);
++      return ocelot_mact_learn(ocelot, port, addr, vid, ENTRYTYPE_LOCKED);
+ }
+-static int ocelot_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
+-                        struct net_device *dev,
+-                        const unsigned char *addr, u16 vid)
++static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
++                             struct net_device *dev,
++                             const unsigned char *addr,
++                             u16 vid, u16 flags,
++                             struct netlink_ext_ack *extack)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+-      struct ocelot *ocelot = port->ocelot;
++      struct ocelot_port *ocelot_port = netdev_priv(dev);
++      struct ocelot *ocelot = ocelot_port->ocelot;
++      return ocelot_fdb_add(ocelot, ocelot_port->chip_port, addr, vid);
++}
++
++static int ocelot_fdb_del(struct ocelot *ocelot, int port,
++                        const unsigned char *addr, u16 vid)
++{
+       return ocelot_mact_forget(ocelot, addr, vid);
+ }
++static int ocelot_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
++                             struct net_device *dev,
++                             const unsigned char *addr, u16 vid)
++{
++      struct ocelot_port *ocelot_port = netdev_priv(dev);
++      struct ocelot *ocelot = ocelot_port->ocelot;
++
++      return ocelot_fdb_del(ocelot, ocelot_port->chip_port, addr, vid);
++}
++
+ struct ocelot_dump_ctx {
+       struct net_device *dev;
+       struct sk_buff *skb;
+@@ -857,9 +872,10 @@ struct ocelot_dump_ctx {
+       int idx;
+ };
+-static int ocelot_fdb_do_dump(struct ocelot_mact_entry *entry,
+-                            struct ocelot_dump_ctx *dump)
++static int ocelot_port_fdb_do_dump(const unsigned char *addr, u16 vid,
++                                 bool is_static, void *data)
+ {
++      struct ocelot_dump_ctx *dump = data;
+       u32 portid = NETLINK_CB(dump->cb->skb).portid;
+       u32 seq = dump->cb->nlh->nlmsg_seq;
+       struct nlmsghdr *nlh;
+@@ -880,12 +896,12 @@ static int ocelot_fdb_do_dump(struct oce
+       ndm->ndm_flags   = NTF_SELF;
+       ndm->ndm_type    = 0;
+       ndm->ndm_ifindex = dump->dev->ifindex;
+-      ndm->ndm_state   = NUD_REACHABLE;
++      ndm->ndm_state   = is_static ? NUD_NOARP : NUD_REACHABLE;
+-      if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, entry->mac))
++      if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, addr))
+               goto nla_put_failure;
+-      if (entry->vid && nla_put_u16(dump->skb, NDA_VLAN, entry->vid))
++      if (vid && nla_put_u16(dump->skb, NDA_VLAN, vid))
+               goto nla_put_failure;
+       nlmsg_end(dump->skb, nlh);
+@@ -899,12 +915,11 @@ nla_put_failure:
+       return -EMSGSIZE;
+ }
+-static inline int ocelot_mact_read(struct ocelot_port *port, int row, int col,
+-                                 struct ocelot_mact_entry *entry)
++static int ocelot_mact_read(struct ocelot *ocelot, int port, int row, int col,
++                          struct ocelot_mact_entry *entry)
+ {
+-      struct ocelot *ocelot = port->ocelot;
+-      char mac[ETH_ALEN];
+       u32 val, dst, macl, mach;
++      char mac[ETH_ALEN];
+       /* Set row and column to read from */
+       ocelot_field_write(ocelot, ANA_TABLES_MACTINDX_M_INDEX, row);
+@@ -927,7 +942,7 @@ static inline int ocelot_mact_read(struc
+        * do not report it.
+        */
+       dst = (val & ANA_TABLES_MACACCESS_DEST_IDX_M) >> 3;
+-      if (dst != port->chip_port)
++      if (dst != port)
+               return -EINVAL;
+       /* Get the entry's MAC address and VLAN id */
+@@ -947,43 +962,60 @@ static inline int ocelot_mact_read(struc
+       return 0;
+ }
+-static int ocelot_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
+-                         struct net_device *dev,
+-                         struct net_device *filter_dev, int *idx)
++static int ocelot_fdb_dump(struct ocelot *ocelot, int port,
++                         dsa_fdb_dump_cb_t *cb, void *data)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+-      int i, j, ret = 0;
+-      struct ocelot_dump_ctx dump = {
+-              .dev = dev,
+-              .skb = skb,
+-              .cb = cb,
+-              .idx = *idx,
+-      };
+-
+-      struct ocelot_mact_entry entry;
++      int i, j;
+       /* Loop through all the mac tables entries. There are 1024 rows of 4
+        * entries.
+        */
+       for (i = 0; i < 1024; i++) {
+               for (j = 0; j < 4; j++) {
+-                      ret = ocelot_mact_read(port, i, j, &entry);
++                      struct ocelot_mact_entry entry;
++                      bool is_static;
++                      int ret;
++
++                      ret = ocelot_mact_read(ocelot, port, i, j, &entry);
+                       /* If the entry is invalid (wrong port, invalid...),
+                        * skip it.
+                        */
+                       if (ret == -EINVAL)
+                               continue;
+                       else if (ret)
+-                              goto end;
++                              return ret;
++
++                      is_static = (entry.type == ENTRYTYPE_LOCKED);
+-                      ret = ocelot_fdb_do_dump(&entry, &dump);
++                      ret = cb(entry.mac, entry.vid, is_static, data);
+                       if (ret)
+-                              goto end;
++                              return ret;
+               }
+       }
+-end:
++      return 0;
++}
++
++static int ocelot_port_fdb_dump(struct sk_buff *skb,
++                              struct netlink_callback *cb,
++                              struct net_device *dev,
++                              struct net_device *filter_dev, int *idx)
++{
++      struct ocelot_port *ocelot_port = netdev_priv(dev);
++      struct ocelot *ocelot = ocelot_port->ocelot;
++      struct ocelot_dump_ctx dump = {
++              .dev = dev,
++              .skb = skb,
++              .cb = cb,
++              .idx = *idx,
++      };
++      int ret;
++
++      ret = ocelot_fdb_dump(ocelot, ocelot_port->chip_port,
++                            ocelot_port_fdb_do_dump, &dump);
++
+       *idx = dump.idx;
++
+       return ret;
+ }
+@@ -1129,9 +1161,9 @@ static const struct net_device_ops ocelo
+       .ndo_get_phys_port_name         = ocelot_port_get_phys_port_name,
+       .ndo_set_mac_address            = ocelot_port_set_mac_address,
+       .ndo_get_stats64                = ocelot_get_stats64,
+-      .ndo_fdb_add                    = ocelot_fdb_add,
+-      .ndo_fdb_del                    = ocelot_fdb_del,
+-      .ndo_fdb_dump                   = ocelot_fdb_dump,
++      .ndo_fdb_add                    = ocelot_port_fdb_add,
++      .ndo_fdb_del                    = ocelot_port_fdb_del,
++      .ndo_fdb_dump                   = ocelot_port_fdb_dump,
+       .ndo_vlan_rx_add_vid            = ocelot_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid           = ocelot_vlan_rx_kill_vid,
+       .ndo_set_features               = ocelot_set_features,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0241-net-mscc-ocelot-change-prototypes-of-hwtstamping-ioc.patch b/target/linux/layerscape/patches-5.4/701-net-0241-net-mscc-ocelot-change-prototypes-of-hwtstamping-ioc.patch
new file mode 100644 (file)
index 0000000..f5f1452
--- /dev/null
@@ -0,0 +1,83 @@
+From 1ba674f7023761476dc39b7b112b780bb86f2f66 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Sat, 9 Nov 2019 15:02:50 +0200
+Subject: [PATCH] net: mscc: ocelot: change prototypes of hwtstamping ioctls
+
+This is needed in order to present a simpler prototype to the DSA
+front-end of ocelot.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 25 +++++++++++++------------
+ 1 file changed, 13 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -1062,17 +1062,17 @@ static int ocelot_get_port_parent_id(str
+       return 0;
+ }
+-static int ocelot_hwstamp_get(struct ocelot_port *port, struct ifreq *ifr)
++static int ocelot_hwstamp_get(struct ocelot *ocelot, int port,
++                            struct ifreq *ifr)
+ {
+-      struct ocelot *ocelot = port->ocelot;
+-
+       return copy_to_user(ifr->ifr_data, &ocelot->hwtstamp_config,
+                           sizeof(ocelot->hwtstamp_config)) ? -EFAULT : 0;
+ }
+-static int ocelot_hwstamp_set(struct ocelot_port *port, struct ifreq *ifr)
++static int ocelot_hwstamp_set(struct ocelot *ocelot, int port,
++                            struct ifreq *ifr)
+ {
+-      struct ocelot *ocelot = port->ocelot;
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
+       struct hwtstamp_config cfg;
+       if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+@@ -1085,16 +1085,16 @@ static int ocelot_hwstamp_set(struct oce
+       /* Tx type sanity check */
+       switch (cfg.tx_type) {
+       case HWTSTAMP_TX_ON:
+-              port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
++              ocelot_port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
+               break;
+       case HWTSTAMP_TX_ONESTEP_SYNC:
+               /* IFH_REW_OP_ONE_STEP_PTP updates the correctional field, we
+                * need to update the origin time.
+                */
+-              port->ptp_cmd = IFH_REW_OP_ORIGIN_PTP;
++              ocelot_port->ptp_cmd = IFH_REW_OP_ORIGIN_PTP;
+               break;
+       case HWTSTAMP_TX_OFF:
+-              port->ptp_cmd = 0;
++              ocelot_port->ptp_cmd = 0;
+               break;
+       default:
+               return -ERANGE;
+@@ -1136,8 +1136,9 @@ static int ocelot_hwstamp_set(struct oce
+ static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+-      struct ocelot *ocelot = port->ocelot;
++      struct ocelot_port *ocelot_port = netdev_priv(dev);
++      struct ocelot *ocelot = ocelot_port->ocelot;
++      int port = ocelot_port->chip_port;
+       /* The function is only used for PTP operations for now */
+       if (!ocelot->ptp)
+@@ -1145,9 +1146,9 @@ static int ocelot_ioctl(struct net_devic
+       switch (cmd) {
+       case SIOCSHWTSTAMP:
+-              return ocelot_hwstamp_set(port, ifr);
++              return ocelot_hwstamp_set(ocelot, port, ifr);
+       case SIOCGHWTSTAMP:
+-              return ocelot_hwstamp_get(port, ifr);
++              return ocelot_hwstamp_get(ocelot, port, ifr);
+       default:
+               return -EOPNOTSUPP;
+       }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0242-net-mscc-ocelot-change-prototypes-of-switchdev-port-.patch b/target/linux/layerscape/patches-5.4/701-net-0242-net-mscc-ocelot-change-prototypes-of-switchdev-port-.patch
new file mode 100644 (file)
index 0000000..5cf0903
--- /dev/null
@@ -0,0 +1,192 @@
+From 2a07ee2b9608e665872e7d83bebd3acb7e45c2e6 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Sat, 9 Nov 2019 15:02:51 +0200
+Subject: [PATCH] net: mscc: ocelot: change prototypes of switchdev port
+ attribute handlers
+
+This is needed so that the Felix DSA front-end can call the Ocelot
+implementations.
+
+The implementation of the "mc_disabled" switchdev attribute has also
+been simplified by using the read-modify-write macro instead of
+open-coding that operation.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 88 +++++++++++++++++++-------------------
+ 1 file changed, 45 insertions(+), 43 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -1285,26 +1285,20 @@ static const struct ethtool_ops ocelot_e
+       .get_ts_info            = ocelot_get_ts_info,
+ };
+-static int ocelot_port_attr_stp_state_set(struct ocelot_port *ocelot_port,
+-                                        struct switchdev_trans *trans,
+-                                        u8 state)
++static void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port,
++                                      u8 state)
+ {
+-      struct ocelot *ocelot = ocelot_port->ocelot;
+       u32 port_cfg;
+-      int port, i;
+-
+-      if (switchdev_trans_ph_prepare(trans))
+-              return 0;
++      int p, i;
+-      if (!(BIT(ocelot_port->chip_port) & ocelot->bridge_mask))
+-              return 0;
++      if (!(BIT(port) & ocelot->bridge_mask))
++              return;
+-      port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG,
+-                                 ocelot_port->chip_port);
++      port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG, port);
+       switch (state) {
+       case BR_STATE_FORWARDING:
+-              ocelot->bridge_fwd_mask |= BIT(ocelot_port->chip_port);
++              ocelot->bridge_fwd_mask |= BIT(port);
+               /* Fallthrough */
+       case BR_STATE_LEARNING:
+               port_cfg |= ANA_PORT_PORT_CFG_LEARN_ENA;
+@@ -1312,19 +1306,18 @@ static int ocelot_port_attr_stp_state_se
+       default:
+               port_cfg &= ~ANA_PORT_PORT_CFG_LEARN_ENA;
+-              ocelot->bridge_fwd_mask &= ~BIT(ocelot_port->chip_port);
++              ocelot->bridge_fwd_mask &= ~BIT(port);
+               break;
+       }
+-      ocelot_write_gix(ocelot, port_cfg, ANA_PORT_PORT_CFG,
+-                       ocelot_port->chip_port);
++      ocelot_write_gix(ocelot, port_cfg, ANA_PORT_PORT_CFG, port);
+       /* Apply FWD mask. The loop is needed to add/remove the current port as
+        * a source for the other ports.
+        */
+-      for (port = 0; port < ocelot->num_phys_ports; port++) {
+-              if (ocelot->bridge_fwd_mask & BIT(port)) {
+-                      unsigned long mask = ocelot->bridge_fwd_mask & ~BIT(port);
++      for (p = 0; p < ocelot->num_phys_ports; p++) {
++              if (ocelot->bridge_fwd_mask & BIT(p)) {
++                      unsigned long mask = ocelot->bridge_fwd_mask & ~BIT(p);
+                       for (i = 0; i < ocelot->num_phys_ports; i++) {
+                               unsigned long bond_mask = ocelot->lags[i];
+@@ -1332,7 +1325,7 @@ static int ocelot_port_attr_stp_state_se
+                               if (!bond_mask)
+                                       continue;
+-                              if (bond_mask & BIT(port)) {
++                              if (bond_mask & BIT(p)) {
+                                       mask &= ~bond_mask;
+                                       break;
+                               }
+@@ -1340,47 +1333,55 @@ static int ocelot_port_attr_stp_state_se
+                       ocelot_write_rix(ocelot,
+                                        BIT(ocelot->num_phys_ports) | mask,
+-                                       ANA_PGID_PGID, PGID_SRC + port);
++                                       ANA_PGID_PGID, PGID_SRC + p);
+               } else {
+                       /* Only the CPU port, this is compatible with link
+                        * aggregation.
+                        */
+                       ocelot_write_rix(ocelot,
+                                        BIT(ocelot->num_phys_ports),
+-                                       ANA_PGID_PGID, PGID_SRC + port);
++                                       ANA_PGID_PGID, PGID_SRC + p);
+               }
+       }
++}
++
++static void ocelot_port_attr_stp_state_set(struct ocelot *ocelot, int port,
++                                         struct switchdev_trans *trans,
++                                         u8 state)
++{
++      if (switchdev_trans_ph_prepare(trans))
++              return;
+-      return 0;
++      ocelot_bridge_stp_state_set(ocelot, port, state);
+ }
+-static void ocelot_port_attr_ageing_set(struct ocelot_port *ocelot_port,
++static void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs)
++{
++      ocelot_write(ocelot, ANA_AUTOAGE_AGE_PERIOD(msecs / 2),
++                   ANA_AUTOAGE);
++}
++
++static void ocelot_port_attr_ageing_set(struct ocelot *ocelot, int port,
+                                       unsigned long ageing_clock_t)
+ {
+-      struct ocelot *ocelot = ocelot_port->ocelot;
+       unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);
+       u32 ageing_time = jiffies_to_msecs(ageing_jiffies) / 1000;
+-      ocelot_write(ocelot, ANA_AUTOAGE_AGE_PERIOD(ageing_time / 2),
+-                   ANA_AUTOAGE);
++      ocelot_set_ageing_time(ocelot, ageing_time);
+ }
+-static void ocelot_port_attr_mc_set(struct ocelot_port *port, bool mc)
++static void ocelot_port_attr_mc_set(struct ocelot *ocelot, int port, bool mc)
+ {
+-      struct ocelot *ocelot = port->ocelot;
+-      u32 val = ocelot_read_gix(ocelot, ANA_PORT_CPU_FWD_CFG,
+-                                port->chip_port);
++      u32 cpu_fwd_mcast = ANA_PORT_CPU_FWD_CFG_CPU_IGMP_REDIR_ENA |
++                          ANA_PORT_CPU_FWD_CFG_CPU_MLD_REDIR_ENA |
++                          ANA_PORT_CPU_FWD_CFG_CPU_IPMC_CTRL_COPY_ENA;
++      u32 val = 0;
+       if (mc)
+-              val |= ANA_PORT_CPU_FWD_CFG_CPU_IGMP_REDIR_ENA |
+-                     ANA_PORT_CPU_FWD_CFG_CPU_MLD_REDIR_ENA |
+-                     ANA_PORT_CPU_FWD_CFG_CPU_IPMC_CTRL_COPY_ENA;
+-      else
+-              val &= ~(ANA_PORT_CPU_FWD_CFG_CPU_IGMP_REDIR_ENA |
+-                       ANA_PORT_CPU_FWD_CFG_CPU_MLD_REDIR_ENA |
+-                       ANA_PORT_CPU_FWD_CFG_CPU_IPMC_CTRL_COPY_ENA);
++              val = cpu_fwd_mcast;
+-      ocelot_write_gix(ocelot, val, ANA_PORT_CPU_FWD_CFG, port->chip_port);
++      ocelot_rmw_gix(ocelot, val, cpu_fwd_mcast,
++                     ANA_PORT_CPU_FWD_CFG, port);
+ }
+ static int ocelot_port_attr_set(struct net_device *dev,
+@@ -1389,22 +1390,23 @@ static int ocelot_port_attr_set(struct n
+ {
+       struct ocelot_port *ocelot_port = netdev_priv(dev);
+       struct ocelot *ocelot = ocelot_port->ocelot;
++      int port = ocelot_port->chip_port;
+       int err = 0;
+       switch (attr->id) {
+       case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
+-              ocelot_port_attr_stp_state_set(ocelot_port, trans,
++              ocelot_port_attr_stp_state_set(ocelot, port, trans,
+                                              attr->u.stp_state);
+               break;
+       case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
+-              ocelot_port_attr_ageing_set(ocelot_port, attr->u.ageing_time);
++              ocelot_port_attr_ageing_set(ocelot, port, attr->u.ageing_time);
+               break;
+       case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
+-              ocelot_port_vlan_filtering(ocelot, ocelot_port->chip_port,
++              ocelot_port_vlan_filtering(ocelot, port,
+                                          attr->u.vlan_filtering);
+               break;
+       case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
+-              ocelot_port_attr_mc_set(ocelot_port, !attr->u.mc_disabled);
++              ocelot_port_attr_mc_set(ocelot, port, !attr->u.mc_disabled);
+               break;
+       default:
+               err = -EOPNOTSUPP;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0243-net-mscc-ocelot-refactor-struct-ocelot_port-out-of-f.patch b/target/linux/layerscape/patches-5.4/701-net-0243-net-mscc-ocelot-refactor-struct-ocelot_port-out-of-f.patch
new file mode 100644 (file)
index 0000000..5acd565
--- /dev/null
@@ -0,0 +1,388 @@
+From 9f374df14572a9b4fb0940d8d6721c930bc27da1 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Sat, 9 Nov 2019 15:02:52 +0200
+Subject: [PATCH] net: mscc: ocelot: refactor struct ocelot_port out of
+ function prototypes
+
+The ocelot_port structure has a net_device embedded in it, which makes
+it unsuitable for leaving it in the driver implementation functions.
+
+Leave ocelot_flower.c untouched. In that file, ocelot_port is used as an
+interface to the tc shared blocks. That will be addressed in the next
+patch.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c        | 79 ++++++++++++++-----------------
+ drivers/net/ethernet/mscc/ocelot_police.c | 36 +++++++-------
+ drivers/net/ethernet/mscc/ocelot_police.h |  4 +-
+ drivers/net/ethernet/mscc/ocelot_tc.c     |  5 +-
+ 4 files changed, 59 insertions(+), 65 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -133,11 +133,11 @@ static void ocelot_mact_init(struct ocel
+       ocelot_write(ocelot, MACACCESS_CMD_INIT, ANA_TABLES_MACACCESS);
+ }
+-static void ocelot_vcap_enable(struct ocelot *ocelot, struct ocelot_port *port)
++static void ocelot_vcap_enable(struct ocelot *ocelot, int port)
+ {
+       ocelot_write_gix(ocelot, ANA_PORT_VCAP_S2_CFG_S2_ENA |
+                        ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG(0xa),
+-                       ANA_PORT_VCAP_S2_CFG, port->chip_port);
++                       ANA_PORT_VCAP_S2_CFG, port);
+ }
+ static inline u32 ocelot_vlant_read_vlanaccess(struct ocelot *ocelot)
+@@ -170,19 +170,17 @@ static int ocelot_vlant_set_mask(struct
+       return ocelot_vlant_wait_for_completion(ocelot);
+ }
+-static void ocelot_vlan_mode(struct ocelot_port *port,
++static void ocelot_vlan_mode(struct ocelot *ocelot, int port,
+                            netdev_features_t features)
+ {
+-      struct ocelot *ocelot = port->ocelot;
+-      u8 p = port->chip_port;
+       u32 val;
+       /* Filtering */
+       val = ocelot_read(ocelot, ANA_VLANMASK);
+       if (features & NETIF_F_HW_VLAN_CTAG_FILTER)
+-              val |= BIT(p);
++              val |= BIT(port);
+       else
+-              val &= ~BIT(p);
++              val &= ~BIT(port);
+       ocelot_write(ocelot, val, ANA_VLANMASK);
+ }
+@@ -1034,18 +1032,20 @@ static int ocelot_vlan_rx_kill_vid(struc
+ static int ocelot_set_features(struct net_device *dev,
+                              netdev_features_t features)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+       netdev_features_t changed = dev->features ^ features;
++      struct ocelot_port *ocelot_port = netdev_priv(dev);
++      struct ocelot *ocelot = ocelot_port->ocelot;
++      int port = ocelot_port->chip_port;
+       if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) &&
+-          port->tc.offload_cnt) {
++          ocelot_port->tc.offload_cnt) {
+               netdev_err(dev,
+                          "Cannot disable HW TC offload while offloads active\n");
+               return -EBUSY;
+       }
+       if (changed & NETIF_F_HW_VLAN_CTAG_FILTER)
+-              ocelot_vlan_mode(port, features);
++              ocelot_vlan_mode(ocelot, port, features);
+       return 0;
+ }
+@@ -1586,11 +1586,9 @@ static int ocelot_port_obj_del(struct ne
+       return ret;
+ }
+-static int ocelot_port_bridge_join(struct ocelot_port *ocelot_port,
++static int ocelot_port_bridge_join(struct ocelot *ocelot, int port,
+                                  struct net_device *bridge)
+ {
+-      struct ocelot *ocelot = ocelot_port->ocelot;
+-
+       if (!ocelot->bridge_mask) {
+               ocelot->hw_bridge_dev = bridge;
+       } else {
+@@ -1600,17 +1598,14 @@ static int ocelot_port_bridge_join(struc
+                       return -ENODEV;
+       }
+-      ocelot->bridge_mask |= BIT(ocelot_port->chip_port);
++      ocelot->bridge_mask |= BIT(port);
+       return 0;
+ }
+-static int ocelot_port_bridge_leave(struct ocelot_port *ocelot_port,
++static int ocelot_port_bridge_leave(struct ocelot *ocelot, int port,
+                                   struct net_device *bridge)
+ {
+-      struct ocelot *ocelot = ocelot_port->ocelot;
+-      int port = ocelot_port->chip_port;
+-
+       ocelot->bridge_mask &= ~BIT(port);
+       if (!ocelot->bridge_mask)
+@@ -1679,14 +1674,12 @@ static void ocelot_setup_lag(struct ocel
+       }
+ }
+-static int ocelot_port_lag_join(struct ocelot_port *ocelot_port,
++static int ocelot_port_lag_join(struct ocelot *ocelot, int port,
+                               struct net_device *bond)
+ {
+-      struct ocelot *ocelot = ocelot_port->ocelot;
+-      int p = ocelot_port->chip_port;
+-      int lag, lp;
+       struct net_device *ndev;
+       u32 bond_mask = 0;
++      int lag, lp;
+       rcu_read_lock();
+       for_each_netdev_in_bond_rcu(bond, ndev) {
+@@ -1701,17 +1694,17 @@ static int ocelot_port_lag_join(struct o
+       /* If the new port is the lowest one, use it as the logical port from
+        * now on
+        */
+-      if (p == lp) {
+-              lag = p;
+-              ocelot->lags[p] = bond_mask;
+-              bond_mask &= ~BIT(p);
++      if (port == lp) {
++              lag = port;
++              ocelot->lags[port] = bond_mask;
++              bond_mask &= ~BIT(port);
+               if (bond_mask) {
+                       lp = __ffs(bond_mask);
+                       ocelot->lags[lp] = 0;
+               }
+       } else {
+               lag = lp;
+-              ocelot->lags[lp] |= BIT(p);
++              ocelot->lags[lp] |= BIT(port);
+       }
+       ocelot_setup_lag(ocelot, lag);
+@@ -1720,34 +1713,32 @@ static int ocelot_port_lag_join(struct o
+       return 0;
+ }
+-static void ocelot_port_lag_leave(struct ocelot_port *ocelot_port,
++static void ocelot_port_lag_leave(struct ocelot *ocelot, int port,
+                                 struct net_device *bond)
+ {
+-      struct ocelot *ocelot = ocelot_port->ocelot;
+-      int p = ocelot_port->chip_port;
+       u32 port_cfg;
+       int i;
+       /* Remove port from any lag */
+       for (i = 0; i < ocelot->num_phys_ports; i++)
+-              ocelot->lags[i] &= ~BIT(ocelot_port->chip_port);
++              ocelot->lags[i] &= ~BIT(port);
+       /* if it was the logical port of the lag, move the lag config to the
+        * next port
+        */
+-      if (ocelot->lags[p]) {
+-              int n = __ffs(ocelot->lags[p]);
++      if (ocelot->lags[port]) {
++              int n = __ffs(ocelot->lags[port]);
+-              ocelot->lags[n] = ocelot->lags[p];
+-              ocelot->lags[p] = 0;
++              ocelot->lags[n] = ocelot->lags[port];
++              ocelot->lags[port] = 0;
+               ocelot_setup_lag(ocelot, n);
+       }
+-      port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG, p);
++      port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG, port);
+       port_cfg &= ~ANA_PORT_PORT_CFG_PORTID_VAL_M;
+-      ocelot_write_gix(ocelot, port_cfg | ANA_PORT_PORT_CFG_PORTID_VAL(p),
+-                       ANA_PORT_PORT_CFG, p);
++      ocelot_write_gix(ocelot, port_cfg | ANA_PORT_PORT_CFG_PORTID_VAL(port),
++                       ANA_PORT_PORT_CFG, port);
+       ocelot_set_aggr_pgids(ocelot);
+ }
+@@ -1763,24 +1754,26 @@ static int ocelot_netdevice_port_event(s
+                                      struct netdev_notifier_changeupper_info *info)
+ {
+       struct ocelot_port *ocelot_port = netdev_priv(dev);
++      struct ocelot *ocelot = ocelot_port->ocelot;
++      int port = ocelot_port->chip_port;
+       int err = 0;
+       switch (event) {
+       case NETDEV_CHANGEUPPER:
+               if (netif_is_bridge_master(info->upper_dev)) {
+                       if (info->linking)
+-                              err = ocelot_port_bridge_join(ocelot_port,
++                              err = ocelot_port_bridge_join(ocelot, port,
+                                                             info->upper_dev);
+                       else
+-                              err = ocelot_port_bridge_leave(ocelot_port,
++                              err = ocelot_port_bridge_leave(ocelot, port,
+                                                              info->upper_dev);
+               }
+               if (netif_is_lag_master(info->upper_dev)) {
+                       if (info->linking)
+-                              err = ocelot_port_lag_join(ocelot_port,
++                              err = ocelot_port_lag_join(ocelot, port,
+                                                          info->upper_dev);
+                       else
+-                              ocelot_port_lag_leave(ocelot_port,
++                              ocelot_port_lag_leave(ocelot, port,
+                                                     info->upper_dev);
+               }
+               break;
+@@ -2140,7 +2133,7 @@ int ocelot_probe_port(struct ocelot *oce
+                      REW_PORT_VLAN_CFG, port);
+       /* Enable vcap lookups */
+-      ocelot_vcap_enable(ocelot, ocelot_port);
++      ocelot_vcap_enable(ocelot, port);
+       return 0;
+--- a/drivers/net/ethernet/mscc/ocelot_police.c
++++ b/drivers/net/ethernet/mscc/ocelot_police.c
+@@ -40,13 +40,12 @@ struct qos_policer_conf {
+       u8   ipg; /* Size of IPG when MSCC_QOS_RATE_MODE_LINE is chosen */
+ };
+-static int qos_policer_conf_set(struct ocelot_port *port, u32 pol_ix,
++static int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix,
+                               struct qos_policer_conf *conf)
+ {
+       u32 cf = 0, cir_ena = 0, frm_mode = POL_MODE_LINERATE;
+       u32 cir = 0, cbs = 0, pir = 0, pbs = 0;
+       bool cir_discard = 0, pir_discard = 0;
+-      struct ocelot *ocelot = port->ocelot;
+       u32 pbs_max = 0, cbs_max = 0;
+       u8 ipg = 20;
+       u32 value;
+@@ -123,22 +122,26 @@ static int qos_policer_conf_set(struct o
+       /* Check limits */
+       if (pir > GENMASK(15, 0)) {
+-              netdev_err(port->dev, "Invalid pir\n");
++              dev_err(ocelot->dev, "Invalid pir for port %d: %u (max %lu)\n",
++                      port, pir, GENMASK(15, 0));
+               return -EINVAL;
+       }
+       if (cir > GENMASK(15, 0)) {
+-              netdev_err(port->dev, "Invalid cir\n");
++              dev_err(ocelot->dev, "Invalid cir for port %d: %u (max %lu)\n",
++                      port, cir, GENMASK(15, 0));
+               return -EINVAL;
+       }
+       if (pbs > pbs_max) {
+-              netdev_err(port->dev, "Invalid pbs\n");
++              dev_err(ocelot->dev, "Invalid pbs for port %d: %u (max %u)\n",
++                      port, pbs, pbs_max);
+               return -EINVAL;
+       }
+       if (cbs > cbs_max) {
+-              netdev_err(port->dev, "Invalid cbs\n");
++              dev_err(ocelot->dev, "Invalid cbs for port %d: %u (max %u)\n",
++                      port, cbs, cbs_max);
+               return -EINVAL;
+       }
+@@ -171,10 +174,9 @@ static int qos_policer_conf_set(struct o
+       return 0;
+ }
+-int ocelot_port_policer_add(struct ocelot_port *port,
++int ocelot_port_policer_add(struct ocelot *ocelot, int port,
+                           struct ocelot_policer *pol)
+ {
+-      struct ocelot *ocelot = port->ocelot;
+       struct qos_policer_conf pp = { 0 };
+       int err;
+@@ -185,11 +187,10 @@ int ocelot_port_policer_add(struct ocelo
+       pp.pir = pol->rate;
+       pp.pbs = pol->burst;
+-      netdev_dbg(port->dev,
+-                 "%s: port %u pir %u kbps, pbs %u bytes\n",
+-                 __func__, port->chip_port, pp.pir, pp.pbs);
++      dev_dbg(ocelot->dev, "%s: port %u pir %u kbps, pbs %u bytes\n",
++              __func__, port, pp.pir, pp.pbs);
+-      err = qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp);
++      err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp);
+       if (err)
+               return err;
+@@ -198,22 +199,21 @@ int ocelot_port_policer_add(struct ocelo
+                      ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
+                      ANA_PORT_POL_CFG_PORT_POL_ENA |
+                      ANA_PORT_POL_CFG_POL_ORDER_M,
+-                     ANA_PORT_POL_CFG, port->chip_port);
++                     ANA_PORT_POL_CFG, port);
+       return 0;
+ }
+-int ocelot_port_policer_del(struct ocelot_port *port)
++int ocelot_port_policer_del(struct ocelot *ocelot, int port)
+ {
+-      struct ocelot *ocelot = port->ocelot;
+       struct qos_policer_conf pp = { 0 };
+       int err;
+-      netdev_dbg(port->dev, "%s: port %u\n", __func__, port->chip_port);
++      dev_dbg(ocelot->dev, "%s: port %u\n", __func__, port);
+       pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
+-      err = qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp);
++      err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp);
+       if (err)
+               return err;
+@@ -221,7 +221,7 @@ int ocelot_port_policer_del(struct ocelo
+                      ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
+                      ANA_PORT_POL_CFG_PORT_POL_ENA |
+                      ANA_PORT_POL_CFG_POL_ORDER_M,
+-                     ANA_PORT_POL_CFG, port->chip_port);
++                     ANA_PORT_POL_CFG, port);
+       return 0;
+ }
+--- a/drivers/net/ethernet/mscc/ocelot_police.h
++++ b/drivers/net/ethernet/mscc/ocelot_police.h
+@@ -14,9 +14,9 @@ struct ocelot_policer {
+       u32 burst; /* bytes */
+ };
+-int ocelot_port_policer_add(struct ocelot_port *port,
++int ocelot_port_policer_add(struct ocelot *ocelot, int port,
+                           struct ocelot_policer *pol);
+-int ocelot_port_policer_del(struct ocelot_port *port);
++int ocelot_port_policer_del(struct ocelot *ocelot, int port);
+ #endif /* _MSCC_OCELOT_POLICE_H_ */
+--- a/drivers/net/ethernet/mscc/ocelot_tc.c
++++ b/drivers/net/ethernet/mscc/ocelot_tc.c
+@@ -58,7 +58,8 @@ static int ocelot_setup_tc_cls_matchall(
+                                        PSCHED_NS2TICKS(action->police.burst),
+                                        PSCHED_TICKS_PER_SEC);
+-              err = ocelot_port_policer_add(port, &pol);
++              err = ocelot_port_policer_add(port->ocelot, port->chip_port,
++                                            &pol);
+               if (err) {
+                       NL_SET_ERR_MSG_MOD(extack, "Could not add policer\n");
+                       return err;
+@@ -71,7 +72,7 @@ static int ocelot_setup_tc_cls_matchall(
+               if (port->tc.police_id != f->cookie)
+                       return -ENOENT;
+-              err = ocelot_port_policer_del(port);
++              err = ocelot_port_policer_del(port->ocelot, port->chip_port);
+               if (err) {
+                       NL_SET_ERR_MSG_MOD(extack,
+                                          "Could not delete policer\n");
diff --git a/target/linux/layerscape/patches-5.4/701-net-0244-net-mscc-ocelot-separate-net_device-related-items-ou.patch b/target/linux/layerscape/patches-5.4/701-net-0244-net-mscc-ocelot-separate-net_device-related-items-ou.patch
new file mode 100644 (file)
index 0000000..9338120
--- /dev/null
@@ -0,0 +1,1171 @@
+From b0481fbc0d853fd164055293002c621827eba5ad Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Sat, 9 Nov 2019 15:02:53 +0200
+Subject: [PATCH] net: mscc: ocelot: separate net_device related items out of
+ ocelot_port
+
+The ocelot and ocelot_port structures will be used by a new DSA driver,
+so the ocelot_board.c file will have to allocate and work with a private
+structure (ocelot_port_private), which embeds the generic struct
+ocelot_port. This is because in DSA, at least one interface does not
+have a net_device, and the DSA driver API does not interact with that
+anyway.
+
+The ocelot_port structure is equivalent to dsa_port, and ocelot to
+dsa_switch. The members of ocelot_port which have an equivalent in
+dsa_port (such as dp->vlan_filtering) have been moved to
+ocelot_port_private.
+
+We want to enforce the coding convention that "ocelot_port" refers to
+the structure, and "port" refers to the integer index. One can retrieve
+the structure at any time from ocelot->ports[port].
+
+The patch is large but only contains variable renaming and mechanical
+movement of fields from one structure to another.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c        | 288 ++++++++++++++++--------------
+ drivers/net/ethernet/mscc/ocelot.h        |  21 ++-
+ drivers/net/ethernet/mscc/ocelot_ace.h    |   4 +-
+ drivers/net/ethernet/mscc/ocelot_board.c  |  25 ++-
+ drivers/net/ethernet/mscc/ocelot_flower.c |  32 ++--
+ drivers/net/ethernet/mscc/ocelot_tc.c     |  57 +++---
+ 6 files changed, 235 insertions(+), 192 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -229,8 +229,6 @@ static void ocelot_port_vlan_filtering(s
+       ocelot_rmw_gix(ocelot, val,
+                      REW_TAG_CFG_TAG_CFG_M,
+                      REW_TAG_CFG, port);
+-
+-      ocelot_port->vlan_aware = vlan_aware;
+ }
+ static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port,
+@@ -297,9 +295,10 @@ static int ocelot_vlan_add(struct ocelot
+ static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid,
+                              bool untagged)
+ {
+-      struct ocelot_port *ocelot_port = netdev_priv(dev);
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot_port *ocelot_port = &priv->port;
+       struct ocelot *ocelot = ocelot_port->ocelot;
+-      int port = ocelot_port->chip_port;
++      int port = priv->chip_port;
+       int ret;
+       ret = ocelot_vlan_add(ocelot, port, vid, pvid, untagged);
+@@ -337,9 +336,9 @@ static int ocelot_vlan_del(struct ocelot
+ static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid)
+ {
+-      struct ocelot_port *ocelot_port = netdev_priv(dev);
+-      struct ocelot *ocelot = ocelot_port->ocelot;
+-      int port = ocelot_port->chip_port;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
+       int ret;
+       /* 8021q removes VID 0 on module unload for all interfaces
+@@ -412,10 +411,11 @@ static u16 ocelot_wm_enc(u16 value)
+ static void ocelot_port_adjust_link(struct net_device *dev)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+-      struct ocelot *ocelot = port->ocelot;
+-      u8 p = port->chip_port;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot_port *ocelot_port = &priv->port;
++      struct ocelot *ocelot = ocelot_port->ocelot;
+       int speed, atop_wm, mode = 0;
++      u8 port = priv->chip_port;
+       switch (dev->phydev->speed) {
+       case SPEED_10:
+@@ -444,62 +444,66 @@ static void ocelot_port_adjust_link(stru
+               return;
+       /* Only full duplex supported for now */
+-      ocelot_port_writel(port, DEV_MAC_MODE_CFG_FDX_ENA |
++      ocelot_port_writel(ocelot_port, DEV_MAC_MODE_CFG_FDX_ENA |
+                          mode, DEV_MAC_MODE_CFG);
+       /* Set MAC IFG Gaps
+        * FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 0
+        * !FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 5
+        */
+-      ocelot_port_writel(port, DEV_MAC_IFG_CFG_TX_IFG(5), DEV_MAC_IFG_CFG);
++      ocelot_port_writel(ocelot_port, DEV_MAC_IFG_CFG_TX_IFG(5),
++                         DEV_MAC_IFG_CFG);
+       /* Load seed (0) and set MAC HDX late collision  */
+-      ocelot_port_writel(port, DEV_MAC_HDX_CFG_LATE_COL_POS(67) |
++      ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67) |
+                          DEV_MAC_HDX_CFG_SEED_LOAD,
+                          DEV_MAC_HDX_CFG);
+       mdelay(1);
+-      ocelot_port_writel(port, DEV_MAC_HDX_CFG_LATE_COL_POS(67),
++      ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67),
+                          DEV_MAC_HDX_CFG);
+       /* Disable HDX fast control */
+-      ocelot_port_writel(port, DEV_PORT_MISC_HDX_FAST_DIS, DEV_PORT_MISC);
++      ocelot_port_writel(ocelot_port, DEV_PORT_MISC_HDX_FAST_DIS,
++                         DEV_PORT_MISC);
+       /* SGMII only for now */
+-      ocelot_port_writel(port, PCS1G_MODE_CFG_SGMII_MODE_ENA, PCS1G_MODE_CFG);
+-      ocelot_port_writel(port, PCS1G_SD_CFG_SD_SEL, PCS1G_SD_CFG);
++      ocelot_port_writel(ocelot_port, PCS1G_MODE_CFG_SGMII_MODE_ENA,
++                         PCS1G_MODE_CFG);
++      ocelot_port_writel(ocelot_port, PCS1G_SD_CFG_SD_SEL, PCS1G_SD_CFG);
+       /* Enable PCS */
+-      ocelot_port_writel(port, PCS1G_CFG_PCS_ENA, PCS1G_CFG);
++      ocelot_port_writel(ocelot_port, PCS1G_CFG_PCS_ENA, PCS1G_CFG);
+       /* No aneg on SGMII */
+-      ocelot_port_writel(port, 0, PCS1G_ANEG_CFG);
++      ocelot_port_writel(ocelot_port, 0, PCS1G_ANEG_CFG);
+       /* No loopback */
+-      ocelot_port_writel(port, 0, PCS1G_LB_CFG);
++      ocelot_port_writel(ocelot_port, 0, PCS1G_LB_CFG);
+       /* Set Max Length and maximum tags allowed */
+-      ocelot_port_writel(port, VLAN_ETH_FRAME_LEN, DEV_MAC_MAXLEN_CFG);
+-      ocelot_port_writel(port, DEV_MAC_TAGS_CFG_TAG_ID(ETH_P_8021AD) |
++      ocelot_port_writel(ocelot_port, VLAN_ETH_FRAME_LEN,
++                         DEV_MAC_MAXLEN_CFG);
++      ocelot_port_writel(ocelot_port, DEV_MAC_TAGS_CFG_TAG_ID(ETH_P_8021AD) |
+                          DEV_MAC_TAGS_CFG_VLAN_AWR_ENA |
+                          DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA,
+                          DEV_MAC_TAGS_CFG);
+       /* Enable MAC module */
+-      ocelot_port_writel(port, DEV_MAC_ENA_CFG_RX_ENA |
++      ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA |
+                          DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG);
+       /* Take MAC, Port, Phy (intern) and PCS (SGMII/Serdes) clock out of
+        * reset */
+-      ocelot_port_writel(port, DEV_CLOCK_CFG_LINK_SPEED(speed),
++      ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(speed),
+                          DEV_CLOCK_CFG);
+       /* Set SMAC of Pause frame (00:00:00:00:00:00) */
+-      ocelot_port_writel(port, 0, DEV_MAC_FC_MAC_HIGH_CFG);
+-      ocelot_port_writel(port, 0, DEV_MAC_FC_MAC_LOW_CFG);
++      ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_HIGH_CFG);
++      ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_LOW_CFG);
+       /* No PFC */
+       ocelot_write_gix(ocelot, ANA_PFC_PFC_CFG_FC_LINK_SPEED(speed),
+-                       ANA_PFC_PFC_CFG, p);
++                       ANA_PFC_PFC_CFG, port);
+       /* Set Pause WM hysteresis
+        * 152 = 6 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ
+@@ -507,13 +511,13 @@ static void ocelot_port_adjust_link(stru
+        */
+       ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA |
+                        SYS_PAUSE_CFG_PAUSE_STOP(101) |
+-                       SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, p);
++                       SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, port);
+       /* Core: Enable port for frame transfer */
+       ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE |
+                        QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) |
+                        QSYS_SWITCH_PORT_MODE_PORT_ENA,
+-                       QSYS_SWITCH_PORT_MODE, p);
++                       QSYS_SWITCH_PORT_MODE, port);
+       /* Flow control */
+       ocelot_write_rix(ocelot, SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) |
+@@ -521,20 +525,21 @@ static void ocelot_port_adjust_link(stru
+                        SYS_MAC_FC_CFG_ZERO_PAUSE_ENA |
+                        SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) |
+                        SYS_MAC_FC_CFG_FC_LINK_SPEED(speed),
+-                       SYS_MAC_FC_CFG, p);
+-      ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, p);
++                       SYS_MAC_FC_CFG, port);
++      ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port);
+       /* Tail dropping watermark */
+       atop_wm = (ocelot->shared_queue_sz - 9 * VLAN_ETH_FRAME_LEN) / OCELOT_BUFFER_CELL_SZ;
+       ocelot_write_rix(ocelot, ocelot_wm_enc(9 * VLAN_ETH_FRAME_LEN),
+-                       SYS_ATOP, p);
++                       SYS_ATOP, port);
+       ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
+ }
+ static int ocelot_port_open(struct net_device *dev)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+-      struct ocelot *ocelot = port->ocelot;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
+       int err;
+       /* Enable receiving frames on the port, and activate auto-learning of
+@@ -542,43 +547,44 @@ static int ocelot_port_open(struct net_d
+        */
+       ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO |
+                        ANA_PORT_PORT_CFG_RECV_ENA |
+-                       ANA_PORT_PORT_CFG_PORTID_VAL(port->chip_port),
+-                       ANA_PORT_PORT_CFG, port->chip_port);
++                       ANA_PORT_PORT_CFG_PORTID_VAL(port),
++                       ANA_PORT_PORT_CFG, port);
+-      if (port->serdes) {
+-              err = phy_set_mode_ext(port->serdes, PHY_MODE_ETHERNET,
+-                                     port->phy_mode);
++      if (priv->serdes) {
++              err = phy_set_mode_ext(priv->serdes, PHY_MODE_ETHERNET,
++                                     priv->phy_mode);
+               if (err) {
+                       netdev_err(dev, "Could not set mode of SerDes\n");
+                       return err;
+               }
+       }
+-      err = phy_connect_direct(dev, port->phy, &ocelot_port_adjust_link,
+-                               port->phy_mode);
++      err = phy_connect_direct(dev, priv->phy, &ocelot_port_adjust_link,
++                               priv->phy_mode);
+       if (err) {
+               netdev_err(dev, "Could not attach to PHY\n");
+               return err;
+       }
+-      dev->phydev = port->phy;
++      dev->phydev = priv->phy;
+-      phy_attached_info(port->phy);
+-      phy_start(port->phy);
++      phy_attached_info(priv->phy);
++      phy_start(priv->phy);
+       return 0;
+ }
+ static int ocelot_port_stop(struct net_device *dev)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot_port *port = &priv->port;
+-      phy_disconnect(port->phy);
++      phy_disconnect(priv->phy);
+       dev->phydev = NULL;
+       ocelot_port_writel(port, 0, DEV_MAC_ENA_CFG);
+       ocelot_rmw_rix(port->ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA,
+-                       QSYS_SWITCH_PORT_MODE, port->chip_port);
++                     QSYS_SWITCH_PORT_MODE, priv->chip_port);
+       return 0;
+ }
+@@ -604,13 +610,15 @@ static int ocelot_gen_ifh(u32 *ifh, stru
+ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
++      struct ocelot_port_private *priv = netdev_priv(dev);
+       struct skb_shared_info *shinfo = skb_shinfo(skb);
+-      struct ocelot_port *port = netdev_priv(dev);
+-      struct ocelot *ocelot = port->ocelot;
+-      u32 val, ifh[IFH_LEN];
++      struct ocelot_port *ocelot_port = &priv->port;
++      struct ocelot *ocelot = ocelot_port->ocelot;
+       struct frame_info info = {};
+       u8 grp = 0; /* Send everything on CPU group 0 */
+       unsigned int i, count, last;
++      int port = priv->chip_port;
++      u32 val, ifh[IFH_LEN];
+       val = ocelot_read(ocelot, QS_INJ_STATUS);
+       if (!(val & QS_INJ_STATUS_FIFO_RDY(BIT(grp))) ||
+@@ -620,15 +628,15 @@ static int ocelot_port_xmit(struct sk_bu
+       ocelot_write_rix(ocelot, QS_INJ_CTRL_GAP_SIZE(1) |
+                        QS_INJ_CTRL_SOF, QS_INJ_CTRL, grp);
+-      info.port = BIT(port->chip_port);
++      info.port = BIT(port);
+       info.tag_type = IFH_TAG_TYPE_C;
+       info.vid = skb_vlan_tag_get(skb);
+       /* Check if timestamping is needed */
+       if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP) {
+-              info.rew_op = port->ptp_cmd;
+-              if (port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
+-                      info.rew_op |= (port->ts_id  % 4) << 3;
++              info.rew_op = ocelot_port->ptp_cmd;
++              if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
++                      info.rew_op |= (ocelot_port->ts_id  % 4) << 3;
+       }
+       ocelot_gen_ifh(ifh, &info);
+@@ -663,7 +671,7 @@ static int ocelot_port_xmit(struct sk_bu
+       dev->stats.tx_bytes += skb->len;
+       if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP &&
+-          port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
++          ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
+               struct ocelot_skb *oskb =
+                       kzalloc(sizeof(struct ocelot_skb), GFP_ATOMIC);
+@@ -673,10 +681,10 @@ static int ocelot_port_xmit(struct sk_bu
+               skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+               oskb->skb = skb;
+-              oskb->id = port->ts_id % 4;
+-              port->ts_id++;
++              oskb->id = ocelot_port->ts_id % 4;
++              ocelot_port->ts_id++;
+-              list_add_tail(&oskb->head, &port->skbs);
++              list_add_tail(&oskb->head, &ocelot_port->skbs);
+               return NETDEV_TX_OK;
+       }
+@@ -715,25 +723,29 @@ EXPORT_SYMBOL(ocelot_get_hwtimestamp);
+ static int ocelot_mc_unsync(struct net_device *dev, const unsigned char *addr)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot_port *ocelot_port = &priv->port;
++      struct ocelot *ocelot = ocelot_port->ocelot;
+-      return ocelot_mact_forget(port->ocelot, addr, port->pvid);
++      return ocelot_mact_forget(ocelot, addr, ocelot_port->pvid);
+ }
+ static int ocelot_mc_sync(struct net_device *dev, const unsigned char *addr)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot_port *ocelot_port = &priv->port;
++      struct ocelot *ocelot = ocelot_port->ocelot;
+-      return ocelot_mact_learn(port->ocelot, PGID_CPU, addr, port->pvid,
++      return ocelot_mact_learn(ocelot, PGID_CPU, addr, ocelot_port->pvid,
+                                ENTRYTYPE_LOCKED);
+ }
+ static void ocelot_set_rx_mode(struct net_device *dev)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+-      struct ocelot *ocelot = port->ocelot;
+-      int i;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
+       u32 val;
++      int i;
+       /* This doesn't handle promiscuous mode because the bridge core is
+        * setting IFF_PROMISC on all slave interfaces and all frames would be
+@@ -749,10 +761,11 @@ static void ocelot_set_rx_mode(struct ne
+ static int ocelot_port_get_phys_port_name(struct net_device *dev,
+                                         char *buf, size_t len)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      int port = priv->chip_port;
+       int ret;
+-      ret = snprintf(buf, len, "p%d", port->chip_port);
++      ret = snprintf(buf, len, "p%d", port);
+       if (ret >= len)
+               return -EINVAL;
+@@ -761,15 +774,16 @@ static int ocelot_port_get_phys_port_nam
+ static int ocelot_port_set_mac_address(struct net_device *dev, void *p)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+-      struct ocelot *ocelot = port->ocelot;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot_port *ocelot_port = &priv->port;
++      struct ocelot *ocelot = ocelot_port->ocelot;
+       const struct sockaddr *addr = p;
+       /* Learn the new net device MAC address in the mac table. */
+-      ocelot_mact_learn(ocelot, PGID_CPU, addr->sa_data, port->pvid,
++      ocelot_mact_learn(ocelot, PGID_CPU, addr->sa_data, ocelot_port->pvid,
+                         ENTRYTYPE_LOCKED);
+       /* Then forget the previous one. */
+-      ocelot_mact_forget(ocelot, dev->dev_addr, port->pvid);
++      ocelot_mact_forget(ocelot, dev->dev_addr, ocelot_port->pvid);
+       ether_addr_copy(dev->dev_addr, addr->sa_data);
+       return 0;
+@@ -778,11 +792,12 @@ static int ocelot_port_set_mac_address(s
+ static void ocelot_get_stats64(struct net_device *dev,
+                              struct rtnl_link_stats64 *stats)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+-      struct ocelot *ocelot = port->ocelot;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
+       /* Configure the port to read the stats from */
+-      ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port->chip_port),
++      ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port),
+                    SYS_STAT_CFG);
+       /* Get Rx stats */
+@@ -814,12 +829,13 @@ static void ocelot_get_stats64(struct ne
+ }
+ static int ocelot_fdb_add(struct ocelot *ocelot, int port,
+-                        const unsigned char *addr, u16 vid)
++                        const unsigned char *addr, u16 vid,
++                        bool vlan_aware)
+ {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+       if (!vid) {
+-              if (!ocelot_port->vlan_aware)
++              if (!vlan_aware)
+                       /* If the bridge is not VLAN aware and no VID was
+                        * provided, set it to pvid to ensure the MAC entry
+                        * matches incoming untagged packets
+@@ -841,10 +857,11 @@ static int ocelot_port_fdb_add(struct nd
+                              u16 vid, u16 flags,
+                              struct netlink_ext_ack *extack)
+ {
+-      struct ocelot_port *ocelot_port = netdev_priv(dev);
+-      struct ocelot *ocelot = ocelot_port->ocelot;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
+-      return ocelot_fdb_add(ocelot, ocelot_port->chip_port, addr, vid);
++      return ocelot_fdb_add(ocelot, port, addr, vid, priv->vlan_aware);
+ }
+ static int ocelot_fdb_del(struct ocelot *ocelot, int port,
+@@ -857,10 +874,11 @@ static int ocelot_port_fdb_del(struct nd
+                              struct net_device *dev,
+                              const unsigned char *addr, u16 vid)
+ {
+-      struct ocelot_port *ocelot_port = netdev_priv(dev);
+-      struct ocelot *ocelot = ocelot_port->ocelot;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
+-      return ocelot_fdb_del(ocelot, ocelot_port->chip_port, addr, vid);
++      return ocelot_fdb_del(ocelot, port, addr, vid);
+ }
+ struct ocelot_dump_ctx {
+@@ -999,18 +1017,18 @@ static int ocelot_port_fdb_dump(struct s
+                               struct net_device *dev,
+                               struct net_device *filter_dev, int *idx)
+ {
+-      struct ocelot_port *ocelot_port = netdev_priv(dev);
+-      struct ocelot *ocelot = ocelot_port->ocelot;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
+       struct ocelot_dump_ctx dump = {
+               .dev = dev,
+               .skb = skb,
+               .cb = cb,
+               .idx = *idx,
+       };
++      int port = priv->chip_port;
+       int ret;
+-      ret = ocelot_fdb_dump(ocelot, ocelot_port->chip_port,
+-                            ocelot_port_fdb_do_dump, &dump);
++      ret = ocelot_fdb_dump(ocelot, port, ocelot_port_fdb_do_dump, &dump);
+       *idx = dump.idx;
+@@ -1033,12 +1051,12 @@ static int ocelot_set_features(struct ne
+                              netdev_features_t features)
+ {
+       netdev_features_t changed = dev->features ^ features;
+-      struct ocelot_port *ocelot_port = netdev_priv(dev);
+-      struct ocelot *ocelot = ocelot_port->ocelot;
+-      int port = ocelot_port->chip_port;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
+       if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) &&
+-          ocelot_port->tc.offload_cnt) {
++          priv->tc.offload_cnt) {
+               netdev_err(dev,
+                          "Cannot disable HW TC offload while offloads active\n");
+               return -EBUSY;
+@@ -1053,8 +1071,8 @@ static int ocelot_set_features(struct ne
+ static int ocelot_get_port_parent_id(struct net_device *dev,
+                                    struct netdev_phys_item_id *ppid)
+ {
+-      struct ocelot_port *ocelot_port = netdev_priv(dev);
+-      struct ocelot *ocelot = ocelot_port->ocelot;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
+       ppid->id_len = sizeof(ocelot->base_mac);
+       memcpy(&ppid->id, &ocelot->base_mac, ppid->id_len);
+@@ -1136,9 +1154,9 @@ static int ocelot_hwstamp_set(struct oce
+ static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ {
+-      struct ocelot_port *ocelot_port = netdev_priv(dev);
+-      struct ocelot *ocelot = ocelot_port->ocelot;
+-      int port = ocelot_port->chip_port;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
+       /* The function is only used for PTP operations for now */
+       if (!ocelot->ptp)
+@@ -1175,8 +1193,8 @@ static const struct net_device_ops ocelo
+ static void ocelot_get_strings(struct net_device *netdev, u32 sset, u8 *data)
+ {
+-      struct ocelot_port *port = netdev_priv(netdev);
+-      struct ocelot *ocelot = port->ocelot;
++      struct ocelot_port_private *priv = netdev_priv(netdev);
++      struct ocelot *ocelot = priv->port.ocelot;
+       int i;
+       if (sset != ETH_SS_STATS)
+@@ -1230,8 +1248,9 @@ static void ocelot_check_stats_work(stru
+ static void ocelot_get_ethtool_stats(struct net_device *dev,
+                                    struct ethtool_stats *stats, u64 *data)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+-      struct ocelot *ocelot = port->ocelot;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
+       int i;
+       /* check and update now */
+@@ -1239,13 +1258,13 @@ static void ocelot_get_ethtool_stats(str
+       /* Copy all counters */
+       for (i = 0; i < ocelot->num_stats; i++)
+-              *data++ = ocelot->stats[port->chip_port * ocelot->num_stats + i];
++              *data++ = ocelot->stats[port * ocelot->num_stats + i];
+ }
+ static int ocelot_get_sset_count(struct net_device *dev, int sset)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+-      struct ocelot *ocelot = port->ocelot;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
+       if (sset != ETH_SS_STATS)
+               return -EOPNOTSUPP;
+@@ -1255,8 +1274,8 @@ static int ocelot_get_sset_count(struct
+ static int ocelot_get_ts_info(struct net_device *dev,
+                             struct ethtool_ts_info *info)
+ {
+-      struct ocelot_port *ocelot_port = netdev_priv(dev);
+-      struct ocelot *ocelot = ocelot_port->ocelot;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
+       if (!ocelot->ptp)
+               return ethtool_op_get_ts_info(dev, info);
+@@ -1388,9 +1407,9 @@ static int ocelot_port_attr_set(struct n
+                               const struct switchdev_attr *attr,
+                               struct switchdev_trans *trans)
+ {
+-      struct ocelot_port *ocelot_port = netdev_priv(dev);
+-      struct ocelot *ocelot = ocelot_port->ocelot;
+-      int port = ocelot_port->chip_port;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
+       int err = 0;
+       switch (attr->id) {
+@@ -1402,8 +1421,8 @@ static int ocelot_port_attr_set(struct n
+               ocelot_port_attr_ageing_set(ocelot, port, attr->u.ageing_time);
+               break;
+       case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
+-              ocelot_port_vlan_filtering(ocelot, port,
+-                                         attr->u.vlan_filtering);
++              priv->vlan_aware = attr->u.vlan_filtering;
++              ocelot_port_vlan_filtering(ocelot, port, priv->vlan_aware);
+               break;
+       case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
+               ocelot_port_attr_mc_set(ocelot, port, !attr->u.mc_disabled);
+@@ -1468,15 +1487,17 @@ static int ocelot_port_obj_add_mdb(struc
+                                  const struct switchdev_obj_port_mdb *mdb,
+                                  struct switchdev_trans *trans)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+-      struct ocelot *ocelot = port->ocelot;
+-      struct ocelot_multicast *mc;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot_port *ocelot_port = &priv->port;
++      struct ocelot *ocelot = ocelot_port->ocelot;
+       unsigned char addr[ETH_ALEN];
++      struct ocelot_multicast *mc;
++      int port = priv->chip_port;
+       u16 vid = mdb->vid;
+       bool new = false;
+       if (!vid)
+-              vid = port->pvid;
++              vid = ocelot_port->pvid;
+       mc = ocelot_multicast_get(ocelot, mdb->addr, vid);
+       if (!mc) {
+@@ -1500,7 +1521,7 @@ static int ocelot_port_obj_add_mdb(struc
+               ocelot_mact_forget(ocelot, addr, vid);
+       }
+-      mc->ports |= BIT(port->chip_port);
++      mc->ports |= BIT(port);
+       addr[2] = mc->ports << 0;
+       addr[1] = mc->ports << 8;
+@@ -1510,14 +1531,16 @@ static int ocelot_port_obj_add_mdb(struc
+ static int ocelot_port_obj_del_mdb(struct net_device *dev,
+                                  const struct switchdev_obj_port_mdb *mdb)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
+-      struct ocelot *ocelot = port->ocelot;
+-      struct ocelot_multicast *mc;
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot_port *ocelot_port = &priv->port;
++      struct ocelot *ocelot = ocelot_port->ocelot;
+       unsigned char addr[ETH_ALEN];
++      struct ocelot_multicast *mc;
++      int port = priv->chip_port;
+       u16 vid = mdb->vid;
+       if (!vid)
+-              vid = port->pvid;
++              vid = ocelot_port->pvid;
+       mc = ocelot_multicast_get(ocelot, mdb->addr, vid);
+       if (!mc)
+@@ -1529,7 +1552,7 @@ static int ocelot_port_obj_del_mdb(struc
+       addr[0] = 0;
+       ocelot_mact_forget(ocelot, addr, vid);
+-      mc->ports &= ~BIT(port->chip_port);
++      mc->ports &= ~BIT(port);
+       if (!mc->ports) {
+               list_del(&mc->list);
+               devm_kfree(ocelot->dev, mc);
+@@ -1683,9 +1706,9 @@ static int ocelot_port_lag_join(struct o
+       rcu_read_lock();
+       for_each_netdev_in_bond_rcu(bond, ndev) {
+-              struct ocelot_port *port = netdev_priv(ndev);
++              struct ocelot_port_private *priv = netdev_priv(ndev);
+-              bond_mask |= BIT(port->chip_port);
++              bond_mask |= BIT(priv->chip_port);
+       }
+       rcu_read_unlock();
+@@ -1753,20 +1776,23 @@ static int ocelot_netdevice_port_event(s
+                                      unsigned long event,
+                                      struct netdev_notifier_changeupper_info *info)
+ {
+-      struct ocelot_port *ocelot_port = netdev_priv(dev);
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot_port *ocelot_port = &priv->port;
+       struct ocelot *ocelot = ocelot_port->ocelot;
+-      int port = ocelot_port->chip_port;
++      int port = priv->chip_port;
+       int err = 0;
+       switch (event) {
+       case NETDEV_CHANGEUPPER:
+               if (netif_is_bridge_master(info->upper_dev)) {
+-                      if (info->linking)
++                      if (info->linking) {
+                               err = ocelot_port_bridge_join(ocelot, port,
+                                                             info->upper_dev);
+-                      else
++                      } else {
+                               err = ocelot_port_bridge_leave(ocelot, port,
+                                                              info->upper_dev);
++                              priv->vlan_aware = false;
++                      }
+               }
+               if (netif_is_lag_master(info->upper_dev)) {
+                       if (info->linking)
+@@ -2084,21 +2110,23 @@ int ocelot_probe_port(struct ocelot *oce
+                     void __iomem *regs,
+                     struct phy_device *phy)
+ {
++      struct ocelot_port_private *priv;
+       struct ocelot_port *ocelot_port;
+       struct net_device *dev;
+       u32 val;
+       int err;
+-      dev = alloc_etherdev(sizeof(struct ocelot_port));
++      dev = alloc_etherdev(sizeof(struct ocelot_port_private));
+       if (!dev)
+               return -ENOMEM;
+       SET_NETDEV_DEV(dev, ocelot->dev);
+-      ocelot_port = netdev_priv(dev);
+-      ocelot_port->dev = dev;
++      priv = netdev_priv(dev);
++      priv->dev = dev;
++      priv->phy = phy;
++      priv->chip_port = port;
++      ocelot_port = &priv->port;
+       ocelot_port->ocelot = ocelot;
+       ocelot_port->regs = regs;
+-      ocelot_port->chip_port = port;
+-      ocelot_port->phy = phy;
+       ocelot->ports[port] = ocelot_port;
+       dev->netdev_ops = &ocelot_port_netdev_ops;
+--- a/drivers/net/ethernet/mscc/ocelot.h
++++ b/drivers/net/ethernet/mscc/ocelot.h
+@@ -479,11 +479,9 @@ struct ocelot {
+ };
+ struct ocelot_port {
+-      struct net_device *dev;
+       struct ocelot *ocelot;
+-      struct phy_device *phy;
++
+       void __iomem *regs;
+-      u8 chip_port;
+       /* Ingress default VLAN (pvid) */
+       u16 pvid;
+@@ -491,18 +489,23 @@ struct ocelot_port {
+       /* Egress default VLAN (vid) */
+       u16 vid;
+-      u8 vlan_aware;
++      u8 ptp_cmd;
++      struct list_head skbs;
++      u8 ts_id;
++};
+-      u64 *stats;
++struct ocelot_port_private {
++      struct ocelot_port port;
++      struct net_device *dev;
++      struct phy_device *phy;
++      u8 chip_port;
++
++      u8 vlan_aware;
+       phy_interface_t phy_mode;
+       struct phy *serdes;
+       struct ocelot_port_tc tc;
+-
+-      u8 ptp_cmd;
+-      struct list_head skbs;
+-      u8 ts_id;
+ };
+ struct ocelot_skb {
+--- a/drivers/net/ethernet/mscc/ocelot_ace.h
++++ b/drivers/net/ethernet/mscc/ocelot_ace.h
+@@ -224,9 +224,9 @@ int ocelot_ace_rule_stats_update(struct
+ int ocelot_ace_init(struct ocelot *ocelot);
+ void ocelot_ace_deinit(void);
+-int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
++int ocelot_setup_tc_block_flower_bind(struct ocelot_port_private *priv,
+                                     struct flow_block_offload *f);
+-void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
++void ocelot_setup_tc_block_flower_unbind(struct ocelot_port_private *priv,
+                                        struct flow_block_offload *f);
+ #endif /* _MSCC_OCELOT_ACE_H_ */
+--- a/drivers/net/ethernet/mscc/ocelot_board.c
++++ b/drivers/net/ethernet/mscc/ocelot_board.c
+@@ -95,6 +95,8 @@ static irqreturn_t ocelot_xtr_irq_handle
+       do {
+               struct skb_shared_hwtstamps *shhwtstamps;
++              struct ocelot_port_private *priv;
++              struct ocelot_port *ocelot_port;
+               u64 tod_in_ns, full_ts_in_ns;
+               struct frame_info info = {};
+               struct net_device *dev;
+@@ -122,7 +124,10 @@ static irqreturn_t ocelot_xtr_irq_handle
+               ocelot_parse_ifh(ifh, &info);
+-              dev = ocelot->ports[info.port]->dev;
++              ocelot_port = ocelot->ports[info.port];
++              priv = container_of(ocelot_port, struct ocelot_port_private,
++                                  port);
++              dev = priv->dev;
+               skb = netdev_alloc_skb(dev, info.len);
+@@ -371,6 +376,8 @@ static int mscc_ocelot_probe(struct plat
+       ocelot_init(ocelot);
+       for_each_available_child_of_node(ports, portnp) {
++              struct ocelot_port_private *priv;
++              struct ocelot_port *ocelot_port;
+               struct device_node *phy_node;
+               struct phy_device *phy;
+               struct resource *res;
+@@ -406,13 +413,17 @@ static int mscc_ocelot_probe(struct plat
+                       goto out_put_ports;
+               }
++              ocelot_port = ocelot->ports[port];
++              priv = container_of(ocelot_port, struct ocelot_port_private,
++                                  port);
++
+               phy_mode = of_get_phy_mode(portnp);
+               if (phy_mode < 0)
+-                      ocelot->ports[port]->phy_mode = PHY_INTERFACE_MODE_NA;
+-              else
+-                      ocelot->ports[port]->phy_mode = phy_mode;
++                      phy_mode = PHY_INTERFACE_MODE_NA;
++
++              priv->phy_mode = phy_mode;
+-              switch (ocelot->ports[port]->phy_mode) {
++              switch (priv->phy_mode) {
+               case PHY_INTERFACE_MODE_NA:
+                       continue;
+               case PHY_INTERFACE_MODE_SGMII:
+@@ -421,7 +432,7 @@ static int mscc_ocelot_probe(struct plat
+                       /* Ensure clock signals and speed is set on all
+                        * QSGMII links
+                        */
+-                      ocelot_port_writel(ocelot->ports[port],
++                      ocelot_port_writel(ocelot_port,
+                                          DEV_CLOCK_CFG_LINK_SPEED
+                                          (OCELOT_SPEED_1000),
+                                          DEV_CLOCK_CFG);
+@@ -449,7 +460,7 @@ static int mscc_ocelot_probe(struct plat
+                       goto out_put_ports;
+               }
+-              ocelot->ports[port]->serdes = serdes;
++              priv->serdes = serdes;
+       }
+       register_netdevice_notifier(&ocelot_netdevice_nb);
+--- a/drivers/net/ethernet/mscc/ocelot_flower.c
++++ b/drivers/net/ethernet/mscc/ocelot_flower.c
+@@ -10,7 +10,7 @@
+ struct ocelot_port_block {
+       struct ocelot_acl_block *block;
+-      struct ocelot_port *port;
++      struct ocelot_port_private *priv;
+ };
+ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
+@@ -177,8 +177,8 @@ struct ocelot_ace_rule *ocelot_ace_rule_
+       if (!rule)
+               return NULL;
+-      rule->port = block->port;
+-      rule->chip_port = block->port->chip_port;
++      rule->port = &block->priv->port;
++      rule->chip_port = block->priv->chip_port;
+       return rule;
+ }
+@@ -202,7 +202,7 @@ static int ocelot_flower_replace(struct
+       if (ret)
+               return ret;
+-      port_block->port->tc.offload_cnt++;
++      port_block->priv->tc.offload_cnt++;
+       return 0;
+ }
+@@ -213,14 +213,14 @@ static int ocelot_flower_destroy(struct
+       int ret;
+       rule.prio = f->common.prio;
+-      rule.port = port_block->port;
++      rule.port = &port_block->priv->port;
+       rule.id = f->cookie;
+       ret = ocelot_ace_rule_offload_del(&rule);
+       if (ret)
+               return ret;
+-      port_block->port->tc.offload_cnt--;
++      port_block->priv->tc.offload_cnt--;
+       return 0;
+ }
+@@ -231,7 +231,7 @@ static int ocelot_flower_stats_update(st
+       int ret;
+       rule.prio = f->common.prio;
+-      rule.port = port_block->port;
++      rule.port = &port_block->priv->port;
+       rule.id = f->cookie;
+       ret = ocelot_ace_rule_stats_update(&rule);
+       if (ret)
+@@ -261,7 +261,7 @@ static int ocelot_setup_tc_block_cb_flow
+ {
+       struct ocelot_port_block *port_block = cb_priv;
+-      if (!tc_cls_can_offload_and_chain0(port_block->port->dev, type_data))
++      if (!tc_cls_can_offload_and_chain0(port_block->priv->dev, type_data))
+               return -EOPNOTSUPP;
+       switch (type) {
+@@ -275,7 +275,7 @@ static int ocelot_setup_tc_block_cb_flow
+ }
+ static struct ocelot_port_block*
+-ocelot_port_block_create(struct ocelot_port *port)
++ocelot_port_block_create(struct ocelot_port_private *priv)
+ {
+       struct ocelot_port_block *port_block;
+@@ -283,7 +283,7 @@ ocelot_port_block_create(struct ocelot_p
+       if (!port_block)
+               return NULL;
+-      port_block->port = port;
++      port_block->priv = priv;
+       return port_block;
+ }
+@@ -300,7 +300,7 @@ static void ocelot_tc_block_unbind(void
+       ocelot_port_block_destroy(port_block);
+ }
+-int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
++int ocelot_setup_tc_block_flower_bind(struct ocelot_port_private *priv,
+                                     struct flow_block_offload *f)
+ {
+       struct ocelot_port_block *port_block;
+@@ -311,14 +311,14 @@ int ocelot_setup_tc_block_flower_bind(st
+               return -EOPNOTSUPP;
+       block_cb = flow_block_cb_lookup(f->block,
+-                                      ocelot_setup_tc_block_cb_flower, port);
++                                      ocelot_setup_tc_block_cb_flower, priv);
+       if (!block_cb) {
+-              port_block = ocelot_port_block_create(port);
++              port_block = ocelot_port_block_create(priv);
+               if (!port_block)
+                       return -ENOMEM;
+               block_cb = flow_block_cb_alloc(ocelot_setup_tc_block_cb_flower,
+-                                             port, port_block,
++                                             priv, port_block,
+                                              ocelot_tc_block_unbind);
+               if (IS_ERR(block_cb)) {
+                       ret = PTR_ERR(block_cb);
+@@ -339,13 +339,13 @@ err_cb_register:
+       return ret;
+ }
+-void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
++void ocelot_setup_tc_block_flower_unbind(struct ocelot_port_private *priv,
+                                        struct flow_block_offload *f)
+ {
+       struct flow_block_cb *block_cb;
+       block_cb = flow_block_cb_lookup(f->block,
+-                                      ocelot_setup_tc_block_cb_flower, port);
++                                      ocelot_setup_tc_block_cb_flower, priv);
+       if (!block_cb)
+               return;
+--- a/drivers/net/ethernet/mscc/ocelot_tc.c
++++ b/drivers/net/ethernet/mscc/ocelot_tc.c
+@@ -9,17 +9,19 @@
+ #include "ocelot_ace.h"
+ #include <net/pkt_cls.h>
+-static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port,
++static int ocelot_setup_tc_cls_matchall(struct ocelot_port_private *priv,
+                                       struct tc_cls_matchall_offload *f,
+                                       bool ingress)
+ {
+       struct netlink_ext_ack *extack = f->common.extack;
++      struct ocelot *ocelot = priv->port.ocelot;
+       struct ocelot_policer pol = { 0 };
+       struct flow_action_entry *action;
++      int port = priv->chip_port;
+       int err;
+-      netdev_dbg(port->dev, "%s: port %u command %d cookie %lu\n",
+-                 __func__, port->chip_port, f->command, f->cookie);
++      netdev_dbg(priv->dev, "%s: port %u command %d cookie %lu\n",
++                 __func__, port, f->command, f->cookie);
+       if (!ingress) {
+               NL_SET_ERR_MSG_MOD(extack, "Only ingress is supported");
+@@ -34,7 +36,7 @@ static int ocelot_setup_tc_cls_matchall(
+                       return -EOPNOTSUPP;
+               }
+-              if (port->tc.block_shared) {
++              if (priv->tc.block_shared) {
+                       NL_SET_ERR_MSG_MOD(extack,
+                                          "Rate limit is not supported on shared blocks");
+                       return -EOPNOTSUPP;
+@@ -47,7 +49,7 @@ static int ocelot_setup_tc_cls_matchall(
+                       return -EOPNOTSUPP;
+               }
+-              if (port->tc.police_id && port->tc.police_id != f->cookie) {
++              if (priv->tc.police_id && priv->tc.police_id != f->cookie) {
+                       NL_SET_ERR_MSG_MOD(extack,
+                                          "Only one policer per port is supported\n");
+                       return -EEXIST;
+@@ -58,28 +60,27 @@ static int ocelot_setup_tc_cls_matchall(
+                                        PSCHED_NS2TICKS(action->police.burst),
+                                        PSCHED_TICKS_PER_SEC);
+-              err = ocelot_port_policer_add(port->ocelot, port->chip_port,
+-                                            &pol);
++              err = ocelot_port_policer_add(ocelot, port, &pol);
+               if (err) {
+                       NL_SET_ERR_MSG_MOD(extack, "Could not add policer\n");
+                       return err;
+               }
+-              port->tc.police_id = f->cookie;
+-              port->tc.offload_cnt++;
++              priv->tc.police_id = f->cookie;
++              priv->tc.offload_cnt++;
+               return 0;
+       case TC_CLSMATCHALL_DESTROY:
+-              if (port->tc.police_id != f->cookie)
++              if (priv->tc.police_id != f->cookie)
+                       return -ENOENT;
+-              err = ocelot_port_policer_del(port->ocelot, port->chip_port);
++              err = ocelot_port_policer_del(ocelot, port);
+               if (err) {
+                       NL_SET_ERR_MSG_MOD(extack,
+                                          "Could not delete policer\n");
+                       return err;
+               }
+-              port->tc.police_id = 0;
+-              port->tc.offload_cnt--;
++              priv->tc.police_id = 0;
++              priv->tc.offload_cnt--;
+               return 0;
+       case TC_CLSMATCHALL_STATS: /* fall through */
+       default:
+@@ -91,21 +92,21 @@ static int ocelot_setup_tc_block_cb(enum
+                                   void *type_data,
+                                   void *cb_priv, bool ingress)
+ {
+-      struct ocelot_port *port = cb_priv;
++      struct ocelot_port_private *priv = cb_priv;
+-      if (!tc_cls_can_offload_and_chain0(port->dev, type_data))
++      if (!tc_cls_can_offload_and_chain0(priv->dev, type_data))
+               return -EOPNOTSUPP;
+       switch (type) {
+       case TC_SETUP_CLSMATCHALL:
+-              netdev_dbg(port->dev, "tc_block_cb: TC_SETUP_CLSMATCHALL %s\n",
++              netdev_dbg(priv->dev, "tc_block_cb: TC_SETUP_CLSMATCHALL %s\n",
+                          ingress ? "ingress" : "egress");
+-              return ocelot_setup_tc_cls_matchall(port, type_data, ingress);
++              return ocelot_setup_tc_cls_matchall(priv, type_data, ingress);
+       case TC_SETUP_CLSFLOWER:
+               return 0;
+       default:
+-              netdev_dbg(port->dev, "tc_block_cb: type %d %s\n",
++              netdev_dbg(priv->dev, "tc_block_cb: type %d %s\n",
+                          type,
+                          ingress ? "ingress" : "egress");
+@@ -131,19 +132,19 @@ static int ocelot_setup_tc_block_cb_eg(e
+ static LIST_HEAD(ocelot_block_cb_list);
+-static int ocelot_setup_tc_block(struct ocelot_port *port,
++static int ocelot_setup_tc_block(struct ocelot_port_private *priv,
+                                struct flow_block_offload *f)
+ {
+       struct flow_block_cb *block_cb;
+       flow_setup_cb_t *cb;
+       int err;
+-      netdev_dbg(port->dev, "tc_block command %d, binder_type %d\n",
++      netdev_dbg(priv->dev, "tc_block command %d, binder_type %d\n",
+                  f->command, f->binder_type);
+       if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
+               cb = ocelot_setup_tc_block_cb_ig;
+-              port->tc.block_shared = f->block_shared;
++              priv->tc.block_shared = f->block_shared;
+       } else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
+               cb = ocelot_setup_tc_block_cb_eg;
+       } else {
+@@ -154,14 +155,14 @@ static int ocelot_setup_tc_block(struct
+       switch (f->command) {
+       case FLOW_BLOCK_BIND:
+-              if (flow_block_cb_is_busy(cb, port, &ocelot_block_cb_list))
++              if (flow_block_cb_is_busy(cb, priv, &ocelot_block_cb_list))
+                       return -EBUSY;
+-              block_cb = flow_block_cb_alloc(cb, port, port, NULL);
++              block_cb = flow_block_cb_alloc(cb, priv, priv, NULL);
+               if (IS_ERR(block_cb))
+                       return PTR_ERR(block_cb);
+-              err = ocelot_setup_tc_block_flower_bind(port, f);
++              err = ocelot_setup_tc_block_flower_bind(priv, f);
+               if (err < 0) {
+                       flow_block_cb_free(block_cb);
+                       return err;
+@@ -170,11 +171,11 @@ static int ocelot_setup_tc_block(struct
+               list_add_tail(&block_cb->driver_list, f->driver_block_list);
+               return 0;
+       case FLOW_BLOCK_UNBIND:
+-              block_cb = flow_block_cb_lookup(f->block, cb, port);
++              block_cb = flow_block_cb_lookup(f->block, cb, priv);
+               if (!block_cb)
+                       return -ENOENT;
+-              ocelot_setup_tc_block_flower_unbind(port, f);
++              ocelot_setup_tc_block_flower_unbind(priv, f);
+               flow_block_cb_remove(block_cb, f);
+               list_del(&block_cb->driver_list);
+               return 0;
+@@ -186,11 +187,11 @@ static int ocelot_setup_tc_block(struct
+ int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
+                   void *type_data)
+ {
+-      struct ocelot_port *port = netdev_priv(dev);
++      struct ocelot_port_private *priv = netdev_priv(dev);
+       switch (type) {
+       case TC_SETUP_BLOCK:
+-              return ocelot_setup_tc_block(port, type_data);
++              return ocelot_setup_tc_block(priv, type_data);
+       default:
+               return -EOPNOTSUPP;
+       }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0245-net-mscc-ocelot-refactor-ethtool-callbacks.patch b/target/linux/layerscape/patches-5.4/701-net-0245-net-mscc-ocelot-refactor-ethtool-callbacks.patch
new file mode 100644 (file)
index 0000000..655f60b
--- /dev/null
@@ -0,0 +1,133 @@
+From a155893c9c272b2ed1dc3b236d55ca8f651a6ea1 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Sat, 9 Nov 2019 15:02:54 +0200
+Subject: [PATCH] net: mscc: ocelot: refactor ethtool callbacks
+
+Convert them into an implementation that can be called from DSA as well.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 64 ++++++++++++++++++++++++++++----------
+ 1 file changed, 47 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -1191,10 +1191,9 @@ static const struct net_device_ops ocelo
+       .ndo_do_ioctl                   = ocelot_ioctl,
+ };
+-static void ocelot_get_strings(struct net_device *netdev, u32 sset, u8 *data)
++static void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset,
++                             u8 *data)
+ {
+-      struct ocelot_port_private *priv = netdev_priv(netdev);
+-      struct ocelot *ocelot = priv->port.ocelot;
+       int i;
+       if (sset != ETH_SS_STATS)
+@@ -1205,6 +1204,16 @@ static void ocelot_get_strings(struct ne
+                      ETH_GSTRING_LEN);
+ }
++static void ocelot_port_get_strings(struct net_device *netdev, u32 sset,
++                                  u8 *data)
++{
++      struct ocelot_port_private *priv = netdev_priv(netdev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
++
++      ocelot_get_strings(ocelot, port, sset, data);
++}
++
+ static void ocelot_update_stats(struct ocelot *ocelot)
+ {
+       int i, j;
+@@ -1245,12 +1254,8 @@ static void ocelot_check_stats_work(stru
+                          OCELOT_STATS_CHECK_DELAY);
+ }
+-static void ocelot_get_ethtool_stats(struct net_device *dev,
+-                                   struct ethtool_stats *stats, u64 *data)
++static void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
+ {
+-      struct ocelot_port_private *priv = netdev_priv(dev);
+-      struct ocelot *ocelot = priv->port.ocelot;
+-      int port = priv->chip_port;
+       int i;
+       /* check and update now */
+@@ -1261,25 +1266,37 @@ static void ocelot_get_ethtool_stats(str
+               *data++ = ocelot->stats[port * ocelot->num_stats + i];
+ }
+-static int ocelot_get_sset_count(struct net_device *dev, int sset)
++static void ocelot_port_get_ethtool_stats(struct net_device *dev,
++                                        struct ethtool_stats *stats,
++                                        u64 *data)
+ {
+       struct ocelot_port_private *priv = netdev_priv(dev);
+       struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
++      ocelot_get_ethtool_stats(ocelot, port, data);
++}
++
++static int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
++{
+       if (sset != ETH_SS_STATS)
+               return -EOPNOTSUPP;
++
+       return ocelot->num_stats;
+ }
+-static int ocelot_get_ts_info(struct net_device *dev,
+-                            struct ethtool_ts_info *info)
++static int ocelot_port_get_sset_count(struct net_device *dev, int sset)
+ {
+       struct ocelot_port_private *priv = netdev_priv(dev);
+       struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
+-      if (!ocelot->ptp)
+-              return ethtool_op_get_ts_info(dev, info);
++      return ocelot_get_sset_count(ocelot, port, sset);
++}
++static int ocelot_get_ts_info(struct ocelot *ocelot, int port,
++                            struct ethtool_ts_info *info)
++{
+       info->phc_index = ocelot->ptp_clock ?
+                         ptp_clock_index(ocelot->ptp_clock) : -1;
+       info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE |
+@@ -1295,13 +1312,26 @@ static int ocelot_get_ts_info(struct net
+       return 0;
+ }
++static int ocelot_port_get_ts_info(struct net_device *dev,
++                                 struct ethtool_ts_info *info)
++{
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
++
++      if (!ocelot->ptp)
++              return ethtool_op_get_ts_info(dev, info);
++
++      return ocelot_get_ts_info(ocelot, port, info);
++}
++
+ static const struct ethtool_ops ocelot_ethtool_ops = {
+-      .get_strings            = ocelot_get_strings,
+-      .get_ethtool_stats      = ocelot_get_ethtool_stats,
+-      .get_sset_count         = ocelot_get_sset_count,
++      .get_strings            = ocelot_port_get_strings,
++      .get_ethtool_stats      = ocelot_port_get_ethtool_stats,
++      .get_sset_count         = ocelot_port_get_sset_count,
+       .get_link_ksettings     = phy_ethtool_get_link_ksettings,
+       .set_link_ksettings     = phy_ethtool_set_link_ksettings,
+-      .get_ts_info            = ocelot_get_ts_info,
++      .get_ts_info            = ocelot_port_get_ts_info,
+ };
+ static void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0246-net-mscc-ocelot-limit-vlan-ingress-filtering-to-actu.patch b/target/linux/layerscape/patches-5.4/701-net-0246-net-mscc-ocelot-limit-vlan-ingress-filtering-to-actu.patch
new file mode 100644 (file)
index 0000000..532db74
--- /dev/null
@@ -0,0 +1,28 @@
+From acc105226493e7cfdb6e72d130c36f21e951fc1f Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Sat, 9 Nov 2019 15:02:55 +0200
+Subject: [PATCH] net: mscc: ocelot: limit vlan ingress filtering to actual
+ number of ports
+
+The VSC7514 switch (Ocelot) is a 10-port device, while VSC9959 (Felix)
+is 6-port. Therefore the VLAN filtering mask would be out of bounds when
+calling for this new switch. Fix that.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -389,7 +389,8 @@ static void ocelot_vlan_init(struct ocel
+       /* Set vlan ingress filter mask to all ports but the CPU port by
+        * default.
+        */
+-      ocelot_write(ocelot, GENMASK(9, 0), ANA_VLANMASK);
++      ocelot_write(ocelot, GENMASK(ocelot->num_phys_ports - 1, 0),
++                   ANA_VLANMASK);
+       for (port = 0; port < ocelot->num_phys_ports; port++) {
+               ocelot_write_gix(ocelot, 0, REW_PORT_VLAN_CFG, port);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0247-net-mscc-ocelot-move-port-initialization-into-separa.patch b/target/linux/layerscape/patches-5.4/701-net-0247-net-mscc-ocelot-move-port-initialization-into-separa.patch
new file mode 100644 (file)
index 0000000..4ac2755
--- /dev/null
@@ -0,0 +1,89 @@
+From 66f4bb358787f4f52de0614a92f9e4130d1e0e01 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Sat, 9 Nov 2019 15:02:56 +0200
+Subject: [PATCH] net: mscc: ocelot: move port initialization into separate
+ function
+
+We need a function for the DSA front-end that does none of the
+net_device registration, but initializes the hardware ports.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 45 ++++++++++++++++++++------------------
+ 1 file changed, 24 insertions(+), 21 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -2137,6 +2137,28 @@ static int ocelot_init_timestamp(struct
+       return 0;
+ }
++static void ocelot_init_port(struct ocelot *ocelot, int port)
++{
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++
++      INIT_LIST_HEAD(&ocelot_port->skbs);
++
++      /* Basic L2 initialization */
++
++      /* Drop frames with multicast source address */
++      ocelot_rmw_gix(ocelot, ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA,
++                     ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA,
++                     ANA_PORT_DROP_CFG, port);
++
++      /* Set default VLAN and tag type to 8021Q. */
++      ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021Q),
++                     REW_PORT_VLAN_CFG_PORT_TPID_M,
++                     REW_PORT_VLAN_CFG, port);
++
++      /* Enable vcap lookups */
++      ocelot_vcap_enable(ocelot, port);
++}
++
+ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
+                     void __iomem *regs,
+                     struct phy_device *phy)
+@@ -2144,7 +2166,6 @@ int ocelot_probe_port(struct ocelot *oce
+       struct ocelot_port_private *priv;
+       struct ocelot_port *ocelot_port;
+       struct net_device *dev;
+-      u32 val;
+       int err;
+       dev = alloc_etherdev(sizeof(struct ocelot_port_private));
+@@ -2172,32 +2193,14 @@ int ocelot_probe_port(struct ocelot *oce
+       ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr, ocelot_port->pvid,
+                         ENTRYTYPE_LOCKED);
+-      INIT_LIST_HEAD(&ocelot_port->skbs);
++      ocelot_init_port(ocelot, port);
+       err = register_netdev(dev);
+       if (err) {
+               dev_err(ocelot->dev, "register_netdev failed\n");
+-              goto err_register_netdev;
++              free_netdev(dev);
+       }
+-      /* Basic L2 initialization */
+-
+-      /* Drop frames with multicast source address */
+-      val = ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA;
+-      ocelot_rmw_gix(ocelot, val, val, ANA_PORT_DROP_CFG, port);
+-
+-      /* Set default VLAN and tag type to 8021Q. */
+-      ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021Q),
+-                     REW_PORT_VLAN_CFG_PORT_TPID_M,
+-                     REW_PORT_VLAN_CFG, port);
+-
+-      /* Enable vcap lookups */
+-      ocelot_vcap_enable(ocelot, port);
+-
+-      return 0;
+-
+-err_register_netdev:
+-      free_netdev(dev);
+       return err;
+ }
+ EXPORT_SYMBOL(ocelot_probe_port);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0248-net-mscc-ocelot-separate-the-common-implementation-o.patch b/target/linux/layerscape/patches-5.4/701-net-0248-net-mscc-ocelot-separate-the-common-implementation-o.patch
new file mode 100644 (file)
index 0000000..f0b6393
--- /dev/null
@@ -0,0 +1,86 @@
+From ac918399cae8b62f58f50b40bf8037d0fa9353eb Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Sat, 9 Nov 2019 15:02:57 +0200
+Subject: [PATCH] net: mscc: ocelot: separate the common implementation of
+ ndo_open and ndo_stop
+
+Allow these functions to be called from the .port_enable and
+.port_disable callbacks of DSA.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 36 ++++++++++++++++++++++++++----------
+ 1 file changed, 26 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -536,13 +536,9 @@ static void ocelot_port_adjust_link(stru
+       ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
+ }
+-static int ocelot_port_open(struct net_device *dev)
++static void ocelot_port_enable(struct ocelot *ocelot, int port,
++                             struct phy_device *phy)
+ {
+-      struct ocelot_port_private *priv = netdev_priv(dev);
+-      struct ocelot *ocelot = priv->port.ocelot;
+-      int port = priv->chip_port;
+-      int err;
+-
+       /* Enable receiving frames on the port, and activate auto-learning of
+        * MAC addresses.
+        */
+@@ -550,6 +546,14 @@ static int ocelot_port_open(struct net_d
+                        ANA_PORT_PORT_CFG_RECV_ENA |
+                        ANA_PORT_PORT_CFG_PORTID_VAL(port),
+                        ANA_PORT_PORT_CFG, port);
++}
++
++static int ocelot_port_open(struct net_device *dev)
++{
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
++      int err;
+       if (priv->serdes) {
+               err = phy_set_mode_ext(priv->serdes, PHY_MODE_ETHERNET,
+@@ -571,21 +575,33 @@ static int ocelot_port_open(struct net_d
+       phy_attached_info(priv->phy);
+       phy_start(priv->phy);
++
++      ocelot_port_enable(ocelot, port, priv->phy);
++
+       return 0;
+ }
++static void ocelot_port_disable(struct ocelot *ocelot, int port)
++{
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++
++      ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG);
++      ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA,
++                     QSYS_SWITCH_PORT_MODE, port);
++}
++
+ static int ocelot_port_stop(struct net_device *dev)
+ {
+       struct ocelot_port_private *priv = netdev_priv(dev);
+-      struct ocelot_port *port = &priv->port;
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
+       phy_disconnect(priv->phy);
+       dev->phydev = NULL;
+-      ocelot_port_writel(port, 0, DEV_MAC_ENA_CFG);
+-      ocelot_rmw_rix(port->ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA,
+-                     QSYS_SWITCH_PORT_MODE, priv->chip_port);
++      ocelot_port_disable(ocelot, port);
++
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0249-net-mscc-ocelot-initialize-list-of-multicast-address.patch b/target/linux/layerscape/patches-5.4/701-net-0249-net-mscc-ocelot-initialize-list-of-multicast-address.patch
new file mode 100644 (file)
index 0000000..5e4b433
--- /dev/null
@@ -0,0 +1,37 @@
+From 0a7e5a60bdd559d092912adb34bc99c6457d3fb6 Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Sat, 9 Nov 2019 15:02:58 +0200
+Subject: [PATCH] net: mscc: ocelot: initialize list of multicast addresses in
+ common code
+
+This is just common path code that belongs to ocelot_init,
+it has nothing to do with a specific SoC/board instance.
+
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c       | 1 +
+ drivers/net/ethernet/mscc/ocelot_board.c | 1 -
+ 2 files changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -2247,6 +2247,7 @@ int ocelot_init(struct ocelot *ocelot)
+       if (!ocelot->stats_queue)
+               return -ENOMEM;
++      INIT_LIST_HEAD(&ocelot->multicast);
+       ocelot_mact_init(ocelot);
+       ocelot_vlan_init(ocelot);
+       ocelot_ace_init(ocelot);
+--- a/drivers/net/ethernet/mscc/ocelot_board.c
++++ b/drivers/net/ethernet/mscc/ocelot_board.c
+@@ -372,7 +372,6 @@ static int mscc_ocelot_probe(struct plat
+       ocelot->ports = devm_kcalloc(&pdev->dev, ocelot->num_phys_ports,
+                                    sizeof(struct ocelot_port *), GFP_KERNEL);
+-      INIT_LIST_HEAD(&ocelot->multicast);
+       ocelot_init(ocelot);
+       for_each_available_child_of_node(ports, portnp) {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0250-net-mscc-ocelot-refactor-adjust_link-into-a-netdev-i.patch b/target/linux/layerscape/patches-5.4/701-net-0250-net-mscc-ocelot-refactor-adjust_link-into-a-netdev-i.patch
new file mode 100644 (file)
index 0000000..7f80cd4
--- /dev/null
@@ -0,0 +1,72 @@
+From f8c221dc7383a50defcc5b96595e092159dbe928 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Sat, 9 Nov 2019 15:02:59 +0200
+Subject: [PATCH] net: mscc: ocelot: refactor adjust_link into a
+ netdev-independent function
+
+This will be called from the Felix DSA frontend, which will work in
+PHYLIB compatibility mode initially.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 27 +++++++++++++++++----------
+ 1 file changed, 17 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -410,15 +410,13 @@ static u16 ocelot_wm_enc(u16 value)
+       return value;
+ }
+-static void ocelot_port_adjust_link(struct net_device *dev)
++static void ocelot_adjust_link(struct ocelot *ocelot, int port,
++                             struct phy_device *phydev)
+ {
+-      struct ocelot_port_private *priv = netdev_priv(dev);
+-      struct ocelot_port *ocelot_port = &priv->port;
+-      struct ocelot *ocelot = ocelot_port->ocelot;
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
+       int speed, atop_wm, mode = 0;
+-      u8 port = priv->chip_port;
+-      switch (dev->phydev->speed) {
++      switch (phydev->speed) {
+       case SPEED_10:
+               speed = OCELOT_SPEED_10;
+               break;
+@@ -434,14 +432,14 @@ static void ocelot_port_adjust_link(stru
+               mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA;
+               break;
+       default:
+-              netdev_err(dev, "Unsupported PHY speed: %d\n",
+-                         dev->phydev->speed);
++              dev_err(ocelot->dev, "Unsupported PHY speed on port %d: %d\n",
++                      port, phydev->speed);
+               return;
+       }
+-      phy_print_status(dev->phydev);
++      phy_print_status(phydev);
+-      if (!dev->phydev->link)
++      if (!phydev->link)
+               return;
+       /* Only full duplex supported for now */
+@@ -536,6 +534,15 @@ static void ocelot_port_adjust_link(stru
+       ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
+ }
++static void ocelot_port_adjust_link(struct net_device *dev)
++{
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
++
++      ocelot_adjust_link(ocelot, port, dev->phydev);
++}
++
+ static void ocelot_port_enable(struct ocelot *ocelot, int port,
+                              struct phy_device *phy)
+ {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0251-net-mscc-ocelot-split-assignment-of-the-cpu-port-int.patch b/target/linux/layerscape/patches-5.4/701-net-0251-net-mscc-ocelot-split-assignment-of-the-cpu-port-int.patch
new file mode 100644 (file)
index 0000000..423db44
--- /dev/null
@@ -0,0 +1,163 @@
+From c6f39379529e74eccbe317e70bb11d18110c63d4 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Sat, 9 Nov 2019 15:03:00 +0200
+Subject: [PATCH] net: mscc: ocelot: split assignment of the cpu port into a
+ separate function
+
+Now that the places that configure routing destinations for the CPU port
+have been marked as such, allow callers to specify their own CPU port
+that is different than ocelot->num_phys_ports. A user will be the Felix
+DSA driver, where the CPU port is one of the physical ports (NPI mode).
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c       | 65 +++++++++++++++++++++-----------
+ drivers/net/ethernet/mscc/ocelot.h       | 12 ++++++
+ drivers/net/ethernet/mscc/ocelot_board.c |  2 +
+ 3 files changed, 57 insertions(+), 22 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -380,12 +380,6 @@ static void ocelot_vlan_init(struct ocel
+       ocelot->vlan_mask[0] = GENMASK(ocelot->num_phys_ports - 1, 0);
+       ocelot_vlant_set_mask(ocelot, 0, ocelot->vlan_mask[0]);
+-      /* Configure the CPU port to be VLAN aware */
+-      ocelot_write_gix(ocelot, ANA_PORT_VLAN_CFG_VLAN_VID(0) |
+-                               ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA |
+-                               ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1),
+-                       ANA_PORT_VLAN_CFG, ocelot->num_phys_ports);
+-
+       /* Set vlan ingress filter mask to all ports but the CPU port by
+        * default.
+        */
+@@ -2228,11 +2222,52 @@ int ocelot_probe_port(struct ocelot *oce
+ }
+ EXPORT_SYMBOL(ocelot_probe_port);
++void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu,
++                       enum ocelot_tag_prefix injection,
++                       enum ocelot_tag_prefix extraction)
++{
++      /* Configure and enable the CPU port. */
++      ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu);
++      ocelot_write_rix(ocelot, BIT(cpu), ANA_PGID_PGID, PGID_CPU);
++      ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_RECV_ENA |
++                       ANA_PORT_PORT_CFG_PORTID_VAL(cpu),
++                       ANA_PORT_PORT_CFG, cpu);
++
++      /* If the CPU port is a physical port, set up the port in Node
++       * Processor Interface (NPI) mode. This is the mode through which
++       * frames can be injected from and extracted to an external CPU.
++       * Only one port can be an NPI at the same time.
++       */
++      if (cpu < ocelot->num_phys_ports) {
++              ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M |
++                           QSYS_EXT_CPU_CFG_EXT_CPU_PORT(cpu),
++                           QSYS_EXT_CPU_CFG);
++      }
++
++      /* CPU port Injection/Extraction configuration */
++      ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE |
++                       QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) |
++                       QSYS_SWITCH_PORT_MODE_PORT_ENA,
++                       QSYS_SWITCH_PORT_MODE, cpu);
++      ocelot_write_rix(ocelot, SYS_PORT_MODE_INCL_XTR_HDR(extraction) |
++                       SYS_PORT_MODE_INCL_INJ_HDR(injection),
++                       SYS_PORT_MODE, cpu);
++
++      /* Configure the CPU port to be VLAN aware */
++      ocelot_write_gix(ocelot, ANA_PORT_VLAN_CFG_VLAN_VID(0) |
++                               ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA |
++                               ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1),
++                       ANA_PORT_VLAN_CFG, cpu);
++
++      ocelot->cpu = cpu;
++}
++EXPORT_SYMBOL(ocelot_set_cpu_port);
++
+ int ocelot_init(struct ocelot *ocelot)
+ {
+-      u32 port;
+-      int i, ret, cpu = ocelot->num_phys_ports;
+       char queue_name[32];
++      int i, ret;
++      u32 port;
+       ocelot->lags = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports,
+                                   sizeof(u32), GFP_KERNEL);
+@@ -2312,13 +2347,6 @@ int ocelot_init(struct ocelot *ocelot)
+               ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_SRC + port);
+       }
+-      /* Configure and enable the CPU port. */
+-      ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu);
+-      ocelot_write_rix(ocelot, BIT(cpu), ANA_PGID_PGID, PGID_CPU);
+-      ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_RECV_ENA |
+-                       ANA_PORT_PORT_CFG_PORTID_VAL(cpu),
+-                       ANA_PORT_PORT_CFG, cpu);
+-
+       /* Allow broadcast MAC frames. */
+       for (i = ocelot->num_phys_ports + 1; i < PGID_CPU; i++) {
+               u32 val = ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports - 1, 0));
+@@ -2331,13 +2359,6 @@ int ocelot_init(struct ocelot *ocelot)
+       ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV4);
+       ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV6);
+-      /* CPU port Injection/Extraction configuration */
+-      ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE |
+-                       QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) |
+-                       QSYS_SWITCH_PORT_MODE_PORT_ENA,
+-                       QSYS_SWITCH_PORT_MODE, cpu);
+-      ocelot_write_rix(ocelot, SYS_PORT_MODE_INCL_XTR_HDR(1) |
+-                       SYS_PORT_MODE_INCL_INJ_HDR(1), SYS_PORT_MODE, cpu);
+       /* Allow manual injection via DEVCPU_QS registers, and byte swap these
+        * registers endianness.
+        */
+--- a/drivers/net/ethernet/mscc/ocelot.h
++++ b/drivers/net/ethernet/mscc/ocelot.h
+@@ -427,6 +427,13 @@ struct ocelot_multicast {
+       u16 ports;
+ };
++enum ocelot_tag_prefix {
++      OCELOT_TAG_PREFIX_DISABLED      = 0,
++      OCELOT_TAG_PREFIX_NONE,
++      OCELOT_TAG_PREFIX_SHORT,
++      OCELOT_TAG_PREFIX_LONG,
++};
++
+ struct ocelot_port;
+ struct ocelot_stat_layout {
+@@ -455,6 +462,7 @@ struct ocelot {
+       u8 num_phys_ports;
+       u8 num_cpu_ports;
++      u8 cpu;
+       struct ocelot_port **ports;
+       u32 *lags;
+@@ -552,6 +560,10 @@ int ocelot_probe_port(struct ocelot *oce
+                     void __iomem *regs,
+                     struct phy_device *phy);
++void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu,
++                       enum ocelot_tag_prefix injection,
++                       enum ocelot_tag_prefix extraction);
++
+ extern struct notifier_block ocelot_netdevice_nb;
+ extern struct notifier_block ocelot_switchdev_nb;
+ extern struct notifier_block ocelot_switchdev_blocking_nb;
+--- a/drivers/net/ethernet/mscc/ocelot_board.c
++++ b/drivers/net/ethernet/mscc/ocelot_board.c
+@@ -373,6 +373,8 @@ static int mscc_ocelot_probe(struct plat
+                                    sizeof(struct ocelot_port *), GFP_KERNEL);
+       ocelot_init(ocelot);
++      ocelot_set_cpu_port(ocelot, ocelot->num_phys_ports,
++                          OCELOT_TAG_PREFIX_NONE, OCELOT_TAG_PREFIX_NONE);
+       for_each_available_child_of_node(ports, portnp) {
+               struct ocelot_port_private *priv;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0252-net-mscc-ocelot-don-t-hardcode-the-number-of-the-CPU.patch b/target/linux/layerscape/patches-5.4/701-net-0252-net-mscc-ocelot-don-t-hardcode-the-number-of-the-CPU.patch
new file mode 100644 (file)
index 0000000..aec70e6
--- /dev/null
@@ -0,0 +1,63 @@
+From d176f477fd2acded12356088c0f67dee059facb5 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Sat, 9 Nov 2019 15:03:01 +0200
+Subject: [PATCH] net: mscc: ocelot: don't hardcode the number of the CPU port
+
+VSC7514 is a 10-port switch with 2 extra "CPU ports" (targets in the
+queuing subsystem for terminating traffic locally).
+
+There are 2 issues with hardcoding the CPU port as #10:
+- It is not clear which snippets of the code are configuring something
+  for one of the CPU ports, and which snippets are just doing something
+  related to the number of physical ports.
+- Actually any physical port can act as a CPU port connected to an
+  external CPU (in addition to the local CPU). This is called NPI mode
+  (Node Processor Interface) and is the way that the 6-port VSC9959
+  (Felix) switch is integrated inside NXP LS1028A (the "local management
+  CPU" functionality is not used there).
+
+This patch makes it clear that the ocelot_bridge_stp_state_set function
+operates on the CPU port (by making it an implicit member of the
+bridging domain), and at the same time adds logic for the NPI port (aka
+a physical port) to play the role of a CPU port (it shouldn't be part of
+bridge_fwd_mask, as it's not explicitly enslaved to a bridge).
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -1383,7 +1383,7 @@ static void ocelot_bridge_stp_state_set(
+        * a source for the other ports.
+        */
+       for (p = 0; p < ocelot->num_phys_ports; p++) {
+-              if (ocelot->bridge_fwd_mask & BIT(p)) {
++              if (p == ocelot->cpu || (ocelot->bridge_fwd_mask & BIT(p))) {
+                       unsigned long mask = ocelot->bridge_fwd_mask & ~BIT(p);
+                       for (i = 0; i < ocelot->num_phys_ports; i++) {
+@@ -1398,15 +1398,18 @@ static void ocelot_bridge_stp_state_set(
+                               }
+                       }
+-                      ocelot_write_rix(ocelot,
+-                                       BIT(ocelot->num_phys_ports) | mask,
++                      /* Avoid the NPI port from looping back to itself */
++                      if (p != ocelot->cpu)
++                              mask |= BIT(ocelot->cpu);
++
++                      ocelot_write_rix(ocelot, mask,
+                                        ANA_PGID_PGID, PGID_SRC + p);
+               } else {
+                       /* Only the CPU port, this is compatible with link
+                        * aggregation.
+                        */
+                       ocelot_write_rix(ocelot,
+-                                       BIT(ocelot->num_phys_ports),
++                                       BIT(ocelot->cpu),
+                                        ANA_PGID_PGID, PGID_SRC + p);
+               }
+       }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0253-net-mscc-ocelot-move-resource-ioremap-and-regmap-ini.patch b/target/linux/layerscape/patches-5.4/701-net-0253-net-mscc-ocelot-move-resource-ioremap-and-regmap-ini.patch
new file mode 100644 (file)
index 0000000..47f53eb
--- /dev/null
@@ -0,0 +1,101 @@
+From 01c0da9c8cd3ff6cbe0ced8e28505d4195f60db4 Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Thu, 14 Nov 2019 17:03:20 +0200
+Subject: [PATCH] net: mscc: ocelot: move resource ioremap and regmap init to
+ common code
+
+Let's make this ioremap and regmap init code common.  It should not
+be platform dependent as it should be usable by PCI devices too.
+Use better names where necessary to avoid clashes.
+
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.h       |  4 +---
+ drivers/net/ethernet/mscc/ocelot_board.c | 17 ++++++++++-------
+ drivers/net/ethernet/mscc/ocelot_io.c    | 14 +++++---------
+ 3 files changed, 16 insertions(+), 19 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.h
++++ b/drivers/net/ethernet/mscc/ocelot.h
+@@ -546,9 +546,7 @@ void ocelot_port_writel(struct ocelot_po
+ int ocelot_regfields_init(struct ocelot *ocelot,
+                         const struct reg_field *const regfields);
+-struct regmap *ocelot_io_platform_init(struct ocelot *ocelot,
+-                                     struct platform_device *pdev,
+-                                     const char *name);
++struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res);
+ #define ocelot_field_write(ocelot, reg, val) regmap_field_write((ocelot)->regfields[(reg)], (val))
+ #define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val))
+--- a/drivers/net/ethernet/mscc/ocelot_board.c
++++ b/drivers/net/ethernet/mscc/ocelot_board.c
+@@ -276,7 +276,7 @@ static int mscc_ocelot_probe(struct plat
+               enum ocelot_target id;
+               char *name;
+               u8 optional:1;
+-      } res[] = {
++      } io_target[] = {
+               { SYS, "sys" },
+               { REW, "rew" },
+               { QSYS, "qsys" },
+@@ -296,20 +296,23 @@ static int mscc_ocelot_probe(struct plat
+       platform_set_drvdata(pdev, ocelot);
+       ocelot->dev = &pdev->dev;
+-      for (i = 0; i < ARRAY_SIZE(res); i++) {
++      for (i = 0; i < ARRAY_SIZE(io_target); i++) {
+               struct regmap *target;
++              struct resource *res;
+-              target = ocelot_io_platform_init(ocelot, pdev, res[i].name);
++              res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
++                                                 io_target[i].name);
++
++              target = ocelot_regmap_init(ocelot, res);
+               if (IS_ERR(target)) {
+-                      if (res[i].optional) {
+-                              ocelot->targets[res[i].id] = NULL;
++                      if (io_target[i].optional) {
++                              ocelot->targets[io_target[i].id] = NULL;
+                               continue;
+                       }
+-
+                       return PTR_ERR(target);
+               }
+-              ocelot->targets[res[i].id] = target;
++              ocelot->targets[io_target[i].id] = target;
+       }
+       hsio = syscon_regmap_lookup_by_compatible("mscc,ocelot-hsio");
+--- a/drivers/net/ethernet/mscc/ocelot_io.c
++++ b/drivers/net/ethernet/mscc/ocelot_io.c
+@@ -97,20 +97,16 @@ static struct regmap_config ocelot_regma
+       .reg_stride     = 4,
+ };
+-struct regmap *ocelot_io_platform_init(struct ocelot *ocelot,
+-                                     struct platform_device *pdev,
+-                                     const char *name)
++struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res)
+ {
+-      struct resource *res;
+       void __iomem *regs;
+-      res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+       regs = devm_ioremap_resource(ocelot->dev, res);
+       if (IS_ERR(regs))
+               return ERR_CAST(regs);
+-      ocelot_regmap_config.name = name;
+-      return devm_regmap_init_mmio(ocelot->dev, regs,
+-                                   &ocelot_regmap_config);
++      ocelot_regmap_config.name = res->name;
++
++      return devm_regmap_init_mmio(ocelot->dev, regs, &ocelot_regmap_config);
+ }
+-EXPORT_SYMBOL(ocelot_io_platform_init);
++EXPORT_SYMBOL(ocelot_regmap_init);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0254-net-mscc-ocelot-filter-out-ocelot-SoC-specific-PCS-c.patch b/target/linux/layerscape/patches-5.4/701-net-0254-net-mscc-ocelot-filter-out-ocelot-SoC-specific-PCS-c.patch
new file mode 100644 (file)
index 0000000..73a45bb
--- /dev/null
@@ -0,0 +1,147 @@
+From 6960d2c4f5e95ae304a62af249d6c92a2d952601 Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Thu, 14 Nov 2019 17:03:21 +0200
+Subject: [PATCH] net: mscc: ocelot: filter out ocelot SoC specific PCS config
+ from common path
+
+The adjust_link routine should be generic enough to be (re)used by
+any SoC that integrates a switch core compatible with the Ocelot
+core switch driver.  Currently all configurations are generic except
+for the PCS settings that are SoC specific.  Move these out to the
+Ocelot SoC/board instance.
+
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c       | 19 ++-----------------
+ drivers/net/ethernet/mscc/ocelot.h       |  8 +++++++-
+ drivers/net/ethernet/mscc/ocelot_board.c | 29 ++++++++++++++++++++++++++++-
+ drivers/net/ethernet/mscc/ocelot_regs.c  |  3 ++-
+ 4 files changed, 39 insertions(+), 20 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -455,23 +455,8 @@ static void ocelot_adjust_link(struct oc
+       ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67),
+                          DEV_MAC_HDX_CFG);
+-      /* Disable HDX fast control */
+-      ocelot_port_writel(ocelot_port, DEV_PORT_MISC_HDX_FAST_DIS,
+-                         DEV_PORT_MISC);
+-
+-      /* SGMII only for now */
+-      ocelot_port_writel(ocelot_port, PCS1G_MODE_CFG_SGMII_MODE_ENA,
+-                         PCS1G_MODE_CFG);
+-      ocelot_port_writel(ocelot_port, PCS1G_SD_CFG_SD_SEL, PCS1G_SD_CFG);
+-
+-      /* Enable PCS */
+-      ocelot_port_writel(ocelot_port, PCS1G_CFG_PCS_ENA, PCS1G_CFG);
+-
+-      /* No aneg on SGMII */
+-      ocelot_port_writel(ocelot_port, 0, PCS1G_ANEG_CFG);
+-
+-      /* No loopback */
+-      ocelot_port_writel(ocelot_port, 0, PCS1G_LB_CFG);
++      if (ocelot->ops->pcs_init)
++              ocelot->ops->pcs_init(ocelot, port);
+       /* Set Max Length and maximum tags allowed */
+       ocelot_port_writel(ocelot_port, VLAN_ETH_FRAME_LEN,
+--- a/drivers/net/ethernet/mscc/ocelot.h
++++ b/drivers/net/ethernet/mscc/ocelot.h
+@@ -435,13 +435,19 @@ enum ocelot_tag_prefix {
+ };
+ struct ocelot_port;
++struct ocelot;
+ struct ocelot_stat_layout {
+       u32 offset;
+       char name[ETH_GSTRING_LEN];
+ };
++struct ocelot_ops {
++      void (*pcs_init)(struct ocelot *ocelot, int port);
++};
++
+ struct ocelot {
++      const struct ocelot_ops *ops;
+       struct device *dev;
+       struct regmap *targets[TARGET_MAX];
+@@ -553,7 +559,7 @@ struct regmap *ocelot_regmap_init(struct
+ int ocelot_init(struct ocelot *ocelot);
+ void ocelot_deinit(struct ocelot *ocelot);
+-int ocelot_chip_init(struct ocelot *ocelot);
++int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops);
+ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
+                     void __iomem *regs,
+                     struct phy_device *phy);
+--- a/drivers/net/ethernet/mscc/ocelot_board.c
++++ b/drivers/net/ethernet/mscc/ocelot_board.c
+@@ -262,6 +262,33 @@ static const struct of_device_id mscc_oc
+ };
+ MODULE_DEVICE_TABLE(of, mscc_ocelot_match);
++static void ocelot_port_pcs_init(struct ocelot *ocelot, int port)
++{
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++
++      /* Disable HDX fast control */
++      ocelot_port_writel(ocelot_port, DEV_PORT_MISC_HDX_FAST_DIS,
++                         DEV_PORT_MISC);
++
++      /* SGMII only for now */
++      ocelot_port_writel(ocelot_port, PCS1G_MODE_CFG_SGMII_MODE_ENA,
++                         PCS1G_MODE_CFG);
++      ocelot_port_writel(ocelot_port, PCS1G_SD_CFG_SD_SEL, PCS1G_SD_CFG);
++
++      /* Enable PCS */
++      ocelot_port_writel(ocelot_port, PCS1G_CFG_PCS_ENA, PCS1G_CFG);
++
++      /* No aneg on SGMII */
++      ocelot_port_writel(ocelot_port, 0, PCS1G_ANEG_CFG);
++
++      /* No loopback */
++      ocelot_port_writel(ocelot_port, 0, PCS1G_LB_CFG);
++}
++
++static const struct ocelot_ops ocelot_ops = {
++      .pcs_init               = ocelot_port_pcs_init,
++};
++
+ static int mscc_ocelot_probe(struct platform_device *pdev)
+ {
+       struct device_node *np = pdev->dev.of_node;
+@@ -323,7 +350,7 @@ static int mscc_ocelot_probe(struct plat
+       ocelot->targets[HSIO] = hsio;
+-      err = ocelot_chip_init(ocelot);
++      err = ocelot_chip_init(ocelot, &ocelot_ops);
+       if (err)
+               return err;
+--- a/drivers/net/ethernet/mscc/ocelot_regs.c
++++ b/drivers/net/ethernet/mscc/ocelot_regs.c
+@@ -423,7 +423,7 @@ static void ocelot_pll5_init(struct ocel
+                    HSIO_PLL5G_CFG2_AMPC_SEL(0x10));
+ }
+-int ocelot_chip_init(struct ocelot *ocelot)
++int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops)
+ {
+       int ret;
+@@ -431,6 +431,7 @@ int ocelot_chip_init(struct ocelot *ocel
+       ocelot->stats_layout = ocelot_stats_layout;
+       ocelot->num_stats = ARRAY_SIZE(ocelot_stats_layout);
+       ocelot->shared_queue_sz = 224 * 1024;
++      ocelot->ops = ops;
+       ret = ocelot_regfields_init(ocelot, ocelot_regfields);
+       if (ret)
diff --git a/target/linux/layerscape/patches-5.4/701-net-0255-net-mscc-ocelot-move-invariant-configs-out-of-adjust.patch b/target/linux/layerscape/patches-5.4/701-net-0255-net-mscc-ocelot-move-invariant-configs-out-of-adjust.patch
new file mode 100644 (file)
index 0000000..454dd35
--- /dev/null
@@ -0,0 +1,154 @@
+From 861a32edce13ccba86647507fefcfd4910972dd7 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Thu, 14 Nov 2019 17:03:22 +0200
+Subject: [PATCH] net: mscc: ocelot: move invariant configs out of adjust_link
+
+It doesn't make sense to rewrite all these registers every time the PHY
+library notifies us about a link state change.
+
+In a future patch we will customize the MTU for the CPU port, and since
+the MTU was previously configured from adjust_link, if we don't make
+this change, its value would have got overridden.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 85 +++++++++++++++++++-------------------
+ 1 file changed, 43 insertions(+), 42 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -408,7 +408,7 @@ static void ocelot_adjust_link(struct oc
+                              struct phy_device *phydev)
+ {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+-      int speed, atop_wm, mode = 0;
++      int speed, mode = 0;
+       switch (phydev->speed) {
+       case SPEED_10:
+@@ -440,32 +440,9 @@ static void ocelot_adjust_link(struct oc
+       ocelot_port_writel(ocelot_port, DEV_MAC_MODE_CFG_FDX_ENA |
+                          mode, DEV_MAC_MODE_CFG);
+-      /* Set MAC IFG Gaps
+-       * FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 0
+-       * !FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 5
+-       */
+-      ocelot_port_writel(ocelot_port, DEV_MAC_IFG_CFG_TX_IFG(5),
+-                         DEV_MAC_IFG_CFG);
+-
+-      /* Load seed (0) and set MAC HDX late collision  */
+-      ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67) |
+-                         DEV_MAC_HDX_CFG_SEED_LOAD,
+-                         DEV_MAC_HDX_CFG);
+-      mdelay(1);
+-      ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67),
+-                         DEV_MAC_HDX_CFG);
+-
+       if (ocelot->ops->pcs_init)
+               ocelot->ops->pcs_init(ocelot, port);
+-      /* Set Max Length and maximum tags allowed */
+-      ocelot_port_writel(ocelot_port, VLAN_ETH_FRAME_LEN,
+-                         DEV_MAC_MAXLEN_CFG);
+-      ocelot_port_writel(ocelot_port, DEV_MAC_TAGS_CFG_TAG_ID(ETH_P_8021AD) |
+-                         DEV_MAC_TAGS_CFG_VLAN_AWR_ENA |
+-                         DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA,
+-                         DEV_MAC_TAGS_CFG);
+-
+       /* Enable MAC module */
+       ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA |
+                          DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG);
+@@ -475,22 +452,10 @@ static void ocelot_adjust_link(struct oc
+       ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(speed),
+                          DEV_CLOCK_CFG);
+-      /* Set SMAC of Pause frame (00:00:00:00:00:00) */
+-      ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_HIGH_CFG);
+-      ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_LOW_CFG);
+-
+       /* No PFC */
+       ocelot_write_gix(ocelot, ANA_PFC_PFC_CFG_FC_LINK_SPEED(speed),
+                        ANA_PFC_PFC_CFG, port);
+-      /* Set Pause WM hysteresis
+-       * 152 = 6 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ
+-       * 101 = 4 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ
+-       */
+-      ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA |
+-                       SYS_PAUSE_CFG_PAUSE_STOP(101) |
+-                       SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, port);
+-
+       /* Core: Enable port for frame transfer */
+       ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE |
+                        QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) |
+@@ -505,12 +470,6 @@ static void ocelot_adjust_link(struct oc
+                        SYS_MAC_FC_CFG_FC_LINK_SPEED(speed),
+                        SYS_MAC_FC_CFG, port);
+       ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port);
+-
+-      /* Tail dropping watermark */
+-      atop_wm = (ocelot->shared_queue_sz - 9 * VLAN_ETH_FRAME_LEN) / OCELOT_BUFFER_CELL_SZ;
+-      ocelot_write_rix(ocelot, ocelot_wm_enc(9 * VLAN_ETH_FRAME_LEN),
+-                       SYS_ATOP, port);
+-      ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
+ }
+ static void ocelot_port_adjust_link(struct net_device *dev)
+@@ -2145,11 +2104,53 @@ static int ocelot_init_timestamp(struct
+ static void ocelot_init_port(struct ocelot *ocelot, int port)
+ {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
++      int atop_wm;
+       INIT_LIST_HEAD(&ocelot_port->skbs);
+       /* Basic L2 initialization */
++      /* Set MAC IFG Gaps
++       * FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 0
++       * !FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 5
++       */
++      ocelot_port_writel(ocelot_port, DEV_MAC_IFG_CFG_TX_IFG(5),
++                         DEV_MAC_IFG_CFG);
++
++      /* Load seed (0) and set MAC HDX late collision  */
++      ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67) |
++                         DEV_MAC_HDX_CFG_SEED_LOAD,
++                         DEV_MAC_HDX_CFG);
++      mdelay(1);
++      ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67),
++                         DEV_MAC_HDX_CFG);
++
++      /* Set Max Length and maximum tags allowed */
++      ocelot_port_writel(ocelot_port, VLAN_ETH_FRAME_LEN,
++                         DEV_MAC_MAXLEN_CFG);
++      ocelot_port_writel(ocelot_port, DEV_MAC_TAGS_CFG_TAG_ID(ETH_P_8021AD) |
++                         DEV_MAC_TAGS_CFG_VLAN_AWR_ENA |
++                         DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA,
++                         DEV_MAC_TAGS_CFG);
++
++      /* Set SMAC of Pause frame (00:00:00:00:00:00) */
++      ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_HIGH_CFG);
++      ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_LOW_CFG);
++
++      /* Set Pause WM hysteresis
++       * 152 = 6 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ
++       * 101 = 4 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ
++       */
++      ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA |
++                       SYS_PAUSE_CFG_PAUSE_STOP(101) |
++                       SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, port);
++
++      /* Tail dropping watermark */
++      atop_wm = (ocelot->shared_queue_sz - 9 * VLAN_ETH_FRAME_LEN) / OCELOT_BUFFER_CELL_SZ;
++      ocelot_write_rix(ocelot, ocelot_wm_enc(9 * VLAN_ETH_FRAME_LEN),
++                       SYS_ATOP, port);
++      ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
++
+       /* Drop frames with multicast source address */
+       ocelot_rmw_gix(ocelot, ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA,
+                      ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0256-net-mscc-ocelot-create-a-helper-for-changing-the-por.patch b/target/linux/layerscape/patches-5.4/701-net-0256-net-mscc-ocelot-create-a-helper-for-changing-the-por.patch
new file mode 100644 (file)
index 0000000..1aefe34
--- /dev/null
@@ -0,0 +1,87 @@
+From e870793b277eeaf3c455971d9610f039fd9ab160 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Thu, 14 Nov 2019 17:03:23 +0200
+Subject: [PATCH] net: mscc: ocelot: create a helper for changing the port MTU
+
+Since in an NPI/DSA setup, not all ports will have the same MTU, we need
+to make sure the watermarks for pause frames and/or tail dropping logic
+that existed in the driver is still coherent for the new MTU values.
+
+We need to do this because the NPI (aka external CPU) port needs an
+increased MTU for the DSA tag. This will be done in a future patch.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 40 ++++++++++++++++++++++----------------
+ 1 file changed, 23 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -2101,11 +2101,32 @@ static int ocelot_init_timestamp(struct
+       return 0;
+ }
+-static void ocelot_init_port(struct ocelot *ocelot, int port)
++static void ocelot_port_set_mtu(struct ocelot *ocelot, int port, size_t mtu)
+ {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+       int atop_wm;
++      ocelot_port_writel(ocelot_port, mtu, DEV_MAC_MAXLEN_CFG);
++
++      /* Set Pause WM hysteresis
++       * 152 = 6 * mtu / OCELOT_BUFFER_CELL_SZ
++       * 101 = 4 * mtu / OCELOT_BUFFER_CELL_SZ
++       */
++      ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA |
++                       SYS_PAUSE_CFG_PAUSE_STOP(101) |
++                       SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, port);
++
++      /* Tail dropping watermark */
++      atop_wm = (ocelot->shared_queue_sz - 9 * mtu) / OCELOT_BUFFER_CELL_SZ;
++      ocelot_write_rix(ocelot, ocelot_wm_enc(9 * mtu),
++                       SYS_ATOP, port);
++      ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
++}
++
++static void ocelot_init_port(struct ocelot *ocelot, int port)
++{
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++
+       INIT_LIST_HEAD(&ocelot_port->skbs);
+       /* Basic L2 initialization */
+@@ -2126,8 +2147,7 @@ static void ocelot_init_port(struct ocel
+                          DEV_MAC_HDX_CFG);
+       /* Set Max Length and maximum tags allowed */
+-      ocelot_port_writel(ocelot_port, VLAN_ETH_FRAME_LEN,
+-                         DEV_MAC_MAXLEN_CFG);
++      ocelot_port_set_mtu(ocelot, port, VLAN_ETH_FRAME_LEN);
+       ocelot_port_writel(ocelot_port, DEV_MAC_TAGS_CFG_TAG_ID(ETH_P_8021AD) |
+                          DEV_MAC_TAGS_CFG_VLAN_AWR_ENA |
+                          DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA,
+@@ -2137,20 +2157,6 @@ static void ocelot_init_port(struct ocel
+       ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_HIGH_CFG);
+       ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_LOW_CFG);
+-      /* Set Pause WM hysteresis
+-       * 152 = 6 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ
+-       * 101 = 4 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ
+-       */
+-      ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA |
+-                       SYS_PAUSE_CFG_PAUSE_STOP(101) |
+-                       SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, port);
+-
+-      /* Tail dropping watermark */
+-      atop_wm = (ocelot->shared_queue_sz - 9 * VLAN_ETH_FRAME_LEN) / OCELOT_BUFFER_CELL_SZ;
+-      ocelot_write_rix(ocelot, ocelot_wm_enc(9 * VLAN_ETH_FRAME_LEN),
+-                       SYS_ATOP, port);
+-      ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
+-
+       /* Drop frames with multicast source address */
+       ocelot_rmw_gix(ocelot, ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA,
+                      ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0257-net-mscc-ocelot-export-a-constant-for-the-tag-length.patch b/target/linux/layerscape/patches-5.4/701-net-0257-net-mscc-ocelot-export-a-constant-for-the-tag-length.patch
new file mode 100644 (file)
index 0000000..9a45bad
--- /dev/null
@@ -0,0 +1,73 @@
+From f53826ed84b6ce7c588949263cc9dedf3c577aa6 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Thu, 14 Nov 2019 17:03:24 +0200
+Subject: [PATCH] net: mscc: ocelot: export a constant for the tag length in
+ bytes
+
+This constant will be used in a future patch to increase the MTU on NPI
+ports, and will also be used in the tagger driver for Felix.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c       | 4 ++--
+ drivers/net/ethernet/mscc/ocelot.h       | 4 ++--
+ drivers/net/ethernet/mscc/ocelot_board.c | 2 +-
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -576,11 +576,11 @@ static int ocelot_port_xmit(struct sk_bu
+       struct skb_shared_info *shinfo = skb_shinfo(skb);
+       struct ocelot_port *ocelot_port = &priv->port;
+       struct ocelot *ocelot = ocelot_port->ocelot;
++      u32 val, ifh[OCELOT_TAG_LEN / 4];
+       struct frame_info info = {};
+       u8 grp = 0; /* Send everything on CPU group 0 */
+       unsigned int i, count, last;
+       int port = priv->chip_port;
+-      u32 val, ifh[IFH_LEN];
+       val = ocelot_read(ocelot, QS_INJ_STATUS);
+       if (!(val & QS_INJ_STATUS_FIFO_RDY(BIT(grp))) ||
+@@ -603,7 +603,7 @@ static int ocelot_port_xmit(struct sk_bu
+       ocelot_gen_ifh(ifh, &info);
+-      for (i = 0; i < IFH_LEN; i++)
++      for (i = 0; i < OCELOT_TAG_LEN / 4; i++)
+               ocelot_write_rix(ocelot, (__force u32)cpu_to_be32(ifh[i]),
+                                QS_INJ_WR, grp);
+--- a/drivers/net/ethernet/mscc/ocelot.h
++++ b/drivers/net/ethernet/mscc/ocelot.h
+@@ -43,8 +43,6 @@
+ #define OCELOT_PTP_QUEUE_SZ   128
+-#define IFH_LEN 4
+-
+ struct frame_info {
+       u32 len;
+       u16 port;
+@@ -66,6 +64,8 @@ struct frame_info {
+ #define IFH_REW_OP_TWO_STEP_PTP               0x3
+ #define IFH_REW_OP_ORIGIN_PTP         0x5
++#define OCELOT_TAG_LEN                        16
++
+ #define OCELOT_SPEED_2500 0
+ #define OCELOT_SPEED_1000 1
+ #define OCELOT_SPEED_100  2
+--- a/drivers/net/ethernet/mscc/ocelot_board.c
++++ b/drivers/net/ethernet/mscc/ocelot_board.c
+@@ -105,7 +105,7 @@ static irqreturn_t ocelot_xtr_irq_handle
+               int sz, len, buf_len;
+               struct sk_buff *skb;
+-              for (i = 0; i < IFH_LEN; i++) {
++              for (i = 0; i < OCELOT_TAG_LEN / 4; i++) {
+                       err = ocelot_rx_frame_word(ocelot, grp, true, &ifh[i]);
+                       if (err != 4)
+                               break;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0258-net-mscc-ocelot-adjust-MTU-on-the-CPU-port-in-NPI-mo.patch b/target/linux/layerscape/patches-5.4/701-net-0258-net-mscc-ocelot-adjust-MTU-on-the-CPU-port-in-NPI-mo.patch
new file mode 100644 (file)
index 0000000..9adc0ff
--- /dev/null
@@ -0,0 +1,54 @@
+From b2f7c18c351737c2a053c39c09ef50870fd78c06 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Thu, 14 Nov 2019 17:03:25 +0200
+Subject: [PATCH] net: mscc: ocelot: adjust MTU on the CPU port in NPI mode
+
+When using the NPI port, the DSA tag is passed through Ethernet, so the
+switch's MAC needs to accept it as it comes from the DSA master. Increase
+the MTU on the external CPU port to account for the length of the
+injection header.
+
+Without this patch, MTU-sized frames are dropped by the switch's CPU
+port on xmit, which is especially obvious in TCP sessions.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 9 +++++++++
+ drivers/net/ethernet/mscc/ocelot.h | 2 ++
+ 2 files changed, 11 insertions(+)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -2234,9 +2234,18 @@ void ocelot_set_cpu_port(struct ocelot *
+        * Only one port can be an NPI at the same time.
+        */
+       if (cpu < ocelot->num_phys_ports) {
++              int mtu = VLAN_ETH_FRAME_LEN + OCELOT_TAG_LEN;
++
+               ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M |
+                            QSYS_EXT_CPU_CFG_EXT_CPU_PORT(cpu),
+                            QSYS_EXT_CPU_CFG);
++
++              if (injection == OCELOT_TAG_PREFIX_SHORT)
++                      mtu += OCELOT_SHORT_PREFIX_LEN;
++              else if (injection == OCELOT_TAG_PREFIX_LONG)
++                      mtu += OCELOT_LONG_PREFIX_LEN;
++
++              ocelot_port_set_mtu(ocelot, cpu, mtu);
+       }
+       /* CPU port Injection/Extraction configuration */
+--- a/drivers/net/ethernet/mscc/ocelot.h
++++ b/drivers/net/ethernet/mscc/ocelot.h
+@@ -65,6 +65,8 @@ struct frame_info {
+ #define IFH_REW_OP_ORIGIN_PTP         0x5
+ #define OCELOT_TAG_LEN                        16
++#define OCELOT_SHORT_PREFIX_LEN               4
++#define OCELOT_LONG_PREFIX_LEN                16
+ #define OCELOT_SPEED_2500 0
+ #define OCELOT_SPEED_1000 1
diff --git a/target/linux/layerscape/patches-5.4/701-net-0259-net-mscc-ocelot-separate-the-implementation-of-switc.patch b/target/linux/layerscape/patches-5.4/701-net-0259-net-mscc-ocelot-separate-the-implementation-of-switc.patch
new file mode 100644 (file)
index 0000000..5830dc0
--- /dev/null
@@ -0,0 +1,109 @@
+From c96a1cff5d03a56f380ce761aec9d11fcf61c7f1 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Thu, 14 Nov 2019 17:03:26 +0200
+Subject: [PATCH] net: mscc: ocelot: separate the implementation of switch
+ reset
+
+The Felix switch has a different reset procedure, so a function pointer
+needs to be created and added to the ocelot_ops structure.
+
+The reset procedure has been moved into ocelot_init.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c       |  8 +++++++
+ drivers/net/ethernet/mscc/ocelot.h       |  1 +
+ drivers/net/ethernet/mscc/ocelot_board.c | 37 +++++++++++++++++++++-----------
+ 3 files changed, 33 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -2273,6 +2273,14 @@ int ocelot_init(struct ocelot *ocelot)
+       int i, ret;
+       u32 port;
++      if (ocelot->ops->reset) {
++              ret = ocelot->ops->reset(ocelot);
++              if (ret) {
++                      dev_err(ocelot->dev, "Switch reset failed\n");
++                      return ret;
++              }
++      }
++
+       ocelot->lags = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports,
+                                   sizeof(u32), GFP_KERNEL);
+       if (!ocelot->lags)
+--- a/drivers/net/ethernet/mscc/ocelot.h
++++ b/drivers/net/ethernet/mscc/ocelot.h
+@@ -446,6 +446,7 @@ struct ocelot_stat_layout {
+ struct ocelot_ops {
+       void (*pcs_init)(struct ocelot *ocelot, int port);
++      int (*reset)(struct ocelot *ocelot);
+ };
+ struct ocelot {
+--- a/drivers/net/ethernet/mscc/ocelot_board.c
++++ b/drivers/net/ethernet/mscc/ocelot_board.c
+@@ -285,8 +285,32 @@ static void ocelot_port_pcs_init(struct
+       ocelot_port_writel(ocelot_port, 0, PCS1G_LB_CFG);
+ }
++static int ocelot_reset(struct ocelot *ocelot)
++{
++      int retries = 100;
++      u32 val;
++
++      regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], 1);
++      regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
++
++      do {
++              msleep(1);
++              regmap_field_read(ocelot->regfields[SYS_RESET_CFG_MEM_INIT],
++                                &val);
++      } while (val && --retries);
++
++      if (!retries)
++              return -ETIMEDOUT;
++
++      regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
++      regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1);
++
++      return 0;
++}
++
+ static const struct ocelot_ops ocelot_ops = {
+       .pcs_init               = ocelot_port_pcs_init,
++      .reset                  = ocelot_reset,
+ };
+ static int mscc_ocelot_probe(struct platform_device *pdev)
+@@ -297,7 +321,6 @@ static int mscc_ocelot_probe(struct plat
+       struct ocelot *ocelot;
+       struct regmap *hsio;
+       unsigned int i;
+-      u32 val;
+       struct {
+               enum ocelot_target id;
+@@ -377,18 +400,6 @@ static int mscc_ocelot_probe(struct plat
+               ocelot->ptp = 1;
+       }
+-      regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], 1);
+-      regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
+-
+-      do {
+-              msleep(1);
+-              regmap_field_read(ocelot->regfields[SYS_RESET_CFG_MEM_INIT],
+-                                &val);
+-      } while (val);
+-
+-      regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
+-      regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1);
+-
+       ocelot->num_cpu_ports = 1; /* 1 port on the switch, two groups */
+       ports = of_get_child_by_name(np, "ethernet-ports");
diff --git a/target/linux/layerscape/patches-5.4/701-net-0260-net-mscc-ocelot-publish-structure-definitions-to-inc.patch b/target/linux/layerscape/patches-5.4/701-net-0260-net-mscc-ocelot-publish-structure-definitions-to-inc.patch
new file mode 100644 (file)
index 0000000..a32b19e
--- /dev/null
@@ -0,0 +1,1414 @@
+From 417b5a156ca8ab4c986c9deacf58309ce4e09410 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Thu, 14 Nov 2019 17:03:27 +0200
+Subject: [PATCH] net: mscc: ocelot: publish structure definitions to
+ include/soc/mscc/ocelot.h
+
+We will be registering another switch driver based on ocelot, which
+lives under drivers/net/dsa.
+
+Make sure the Felix DSA front-end has the necessary abstractions to
+implement a new Ocelot driver instantiation. This includes the function
+prototypes for implementing DSA callbacks.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c |  78 +++---
+ drivers/net/ethernet/mscc/ocelot.h | 482 +--------------------------------
+ include/soc/mscc/ocelot.h          | 539 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 588 insertions(+), 511 deletions(-)
+ create mode 100644 include/soc/mscc/ocelot.h
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -21,7 +21,6 @@
+ #include <net/netevent.h>
+ #include <net/rtnetlink.h>
+ #include <net/switchdev.h>
+-#include <net/dsa.h>
+ #include "ocelot.h"
+ #include "ocelot_ace.h"
+@@ -184,8 +183,8 @@ static void ocelot_vlan_mode(struct ocel
+       ocelot_write(ocelot, val, ANA_VLANMASK);
+ }
+-static void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
+-                                     bool vlan_aware)
++void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
++                              bool vlan_aware)
+ {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+       u32 val;
+@@ -230,6 +229,7 @@ static void ocelot_port_vlan_filtering(s
+                      REW_TAG_CFG_TAG_CFG_M,
+                      REW_TAG_CFG, port);
+ }
++EXPORT_SYMBOL(ocelot_port_vlan_filtering);
+ static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port,
+                                      u16 vid)
+@@ -267,8 +267,8 @@ static void ocelot_port_set_pvid(struct
+       ocelot_port->pvid = pvid;
+ }
+-static int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
+-                         bool untagged)
++int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
++                  bool untagged)
+ {
+       int ret;
+@@ -291,6 +291,7 @@ static int ocelot_vlan_add(struct ocelot
+       return 0;
+ }
++EXPORT_SYMBOL(ocelot_vlan_add);
+ static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid,
+                              bool untagged)
+@@ -312,7 +313,7 @@ static int ocelot_vlan_vid_add(struct ne
+       return 0;
+ }
+-static int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid)
++int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid)
+ {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+       int ret;
+@@ -333,6 +334,7 @@ static int ocelot_vlan_del(struct ocelot
+       return 0;
+ }
++EXPORT_SYMBOL(ocelot_vlan_del);
+ static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid)
+ {
+@@ -404,8 +406,8 @@ static u16 ocelot_wm_enc(u16 value)
+       return value;
+ }
+-static void ocelot_adjust_link(struct ocelot *ocelot, int port,
+-                             struct phy_device *phydev)
++void ocelot_adjust_link(struct ocelot *ocelot, int port,
++                      struct phy_device *phydev)
+ {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+       int speed, mode = 0;
+@@ -471,6 +473,7 @@ static void ocelot_adjust_link(struct oc
+                        SYS_MAC_FC_CFG, port);
+       ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port);
+ }
++EXPORT_SYMBOL(ocelot_adjust_link);
+ static void ocelot_port_adjust_link(struct net_device *dev)
+ {
+@@ -481,8 +484,8 @@ static void ocelot_port_adjust_link(stru
+       ocelot_adjust_link(ocelot, port, dev->phydev);
+ }
+-static void ocelot_port_enable(struct ocelot *ocelot, int port,
+-                             struct phy_device *phy)
++void ocelot_port_enable(struct ocelot *ocelot, int port,
++                      struct phy_device *phy)
+ {
+       /* Enable receiving frames on the port, and activate auto-learning of
+        * MAC addresses.
+@@ -492,6 +495,7 @@ static void ocelot_port_enable(struct oc
+                        ANA_PORT_PORT_CFG_PORTID_VAL(port),
+                        ANA_PORT_PORT_CFG, port);
+ }
++EXPORT_SYMBOL(ocelot_port_enable);
+ static int ocelot_port_open(struct net_device *dev)
+ {
+@@ -526,7 +530,7 @@ static int ocelot_port_open(struct net_d
+       return 0;
+ }
+-static void ocelot_port_disable(struct ocelot *ocelot, int port)
++void ocelot_port_disable(struct ocelot *ocelot, int port)
+ {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+@@ -534,6 +538,7 @@ static void ocelot_port_disable(struct o
+       ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA,
+                      QSYS_SWITCH_PORT_MODE, port);
+ }
++EXPORT_SYMBOL(ocelot_port_disable);
+ static int ocelot_port_stop(struct net_device *dev)
+ {
+@@ -790,9 +795,8 @@ static void ocelot_get_stats64(struct ne
+       stats->collisions = ocelot_read(ocelot, SYS_COUNT_TX_COLLISION);
+ }
+-static int ocelot_fdb_add(struct ocelot *ocelot, int port,
+-                        const unsigned char *addr, u16 vid,
+-                        bool vlan_aware)
++int ocelot_fdb_add(struct ocelot *ocelot, int port,
++                 const unsigned char *addr, u16 vid, bool vlan_aware)
+ {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+@@ -812,6 +816,7 @@ static int ocelot_fdb_add(struct ocelot
+       return ocelot_mact_learn(ocelot, port, addr, vid, ENTRYTYPE_LOCKED);
+ }
++EXPORT_SYMBOL(ocelot_fdb_add);
+ static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+                              struct net_device *dev,
+@@ -826,11 +831,12 @@ static int ocelot_port_fdb_add(struct nd
+       return ocelot_fdb_add(ocelot, port, addr, vid, priv->vlan_aware);
+ }
+-static int ocelot_fdb_del(struct ocelot *ocelot, int port,
+-                        const unsigned char *addr, u16 vid)
++int ocelot_fdb_del(struct ocelot *ocelot, int port,
++                 const unsigned char *addr, u16 vid)
+ {
+       return ocelot_mact_forget(ocelot, addr, vid);
+ }
++EXPORT_SYMBOL(ocelot_fdb_del);
+ static int ocelot_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
+                              struct net_device *dev,
+@@ -940,8 +946,8 @@ static int ocelot_mact_read(struct ocelo
+       return 0;
+ }
+-static int ocelot_fdb_dump(struct ocelot *ocelot, int port,
+-                         dsa_fdb_dump_cb_t *cb, void *data)
++int ocelot_fdb_dump(struct ocelot *ocelot, int port,
++                  dsa_fdb_dump_cb_t *cb, void *data)
+ {
+       int i, j;
+@@ -973,6 +979,7 @@ static int ocelot_fdb_dump(struct ocelot
+       return 0;
+ }
++EXPORT_SYMBOL(ocelot_fdb_dump);
+ static int ocelot_port_fdb_dump(struct sk_buff *skb,
+                               struct netlink_callback *cb,
+@@ -1153,8 +1160,7 @@ static const struct net_device_ops ocelo
+       .ndo_do_ioctl                   = ocelot_ioctl,
+ };
+-static void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset,
+-                             u8 *data)
++void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
+ {
+       int i;
+@@ -1165,6 +1171,7 @@ static void ocelot_get_strings(struct oc
+               memcpy(data + i * ETH_GSTRING_LEN, ocelot->stats_layout[i].name,
+                      ETH_GSTRING_LEN);
+ }
++EXPORT_SYMBOL(ocelot_get_strings);
+ static void ocelot_port_get_strings(struct net_device *netdev, u32 sset,
+                                   u8 *data)
+@@ -1216,7 +1223,7 @@ static void ocelot_check_stats_work(stru
+                          OCELOT_STATS_CHECK_DELAY);
+ }
+-static void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
++void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
+ {
+       int i;
+@@ -1227,6 +1234,7 @@ static void ocelot_get_ethtool_stats(str
+       for (i = 0; i < ocelot->num_stats; i++)
+               *data++ = ocelot->stats[port * ocelot->num_stats + i];
+ }
++EXPORT_SYMBOL(ocelot_get_ethtool_stats);
+ static void ocelot_port_get_ethtool_stats(struct net_device *dev,
+                                         struct ethtool_stats *stats,
+@@ -1239,13 +1247,14 @@ static void ocelot_port_get_ethtool_stat
+       ocelot_get_ethtool_stats(ocelot, port, data);
+ }
+-static int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
++int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
+ {
+       if (sset != ETH_SS_STATS)
+               return -EOPNOTSUPP;
+       return ocelot->num_stats;
+ }
++EXPORT_SYMBOL(ocelot_get_sset_count);
+ static int ocelot_port_get_sset_count(struct net_device *dev, int sset)
+ {
+@@ -1256,8 +1265,8 @@ static int ocelot_port_get_sset_count(st
+       return ocelot_get_sset_count(ocelot, port, sset);
+ }
+-static int ocelot_get_ts_info(struct ocelot *ocelot, int port,
+-                            struct ethtool_ts_info *info)
++int ocelot_get_ts_info(struct ocelot *ocelot, int port,
++                     struct ethtool_ts_info *info)
+ {
+       info->phc_index = ocelot->ptp_clock ?
+                         ptp_clock_index(ocelot->ptp_clock) : -1;
+@@ -1273,6 +1282,7 @@ static int ocelot_get_ts_info(struct oce
+       return 0;
+ }
++EXPORT_SYMBOL(ocelot_get_ts_info);
+ static int ocelot_port_get_ts_info(struct net_device *dev,
+                                  struct ethtool_ts_info *info)
+@@ -1296,8 +1306,7 @@ static const struct ethtool_ops ocelot_e
+       .get_ts_info            = ocelot_port_get_ts_info,
+ };
+-static void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port,
+-                                      u8 state)
++void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state)
+ {
+       u32 port_cfg;
+       int p, i;
+@@ -1358,6 +1367,7 @@ static void ocelot_bridge_stp_state_set(
+               }
+       }
+ }
++EXPORT_SYMBOL(ocelot_bridge_stp_state_set);
+ static void ocelot_port_attr_stp_state_set(struct ocelot *ocelot, int port,
+                                          struct switchdev_trans *trans,
+@@ -1369,11 +1379,12 @@ static void ocelot_port_attr_stp_state_s
+       ocelot_bridge_stp_state_set(ocelot, port, state);
+ }
+-static void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs)
++void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs)
+ {
+       ocelot_write(ocelot, ANA_AUTOAGE_AGE_PERIOD(msecs / 2),
+                    ANA_AUTOAGE);
+ }
++EXPORT_SYMBOL(ocelot_set_ageing_time);
+ static void ocelot_port_attr_ageing_set(struct ocelot *ocelot, int port,
+                                       unsigned long ageing_clock_t)
+@@ -1604,8 +1615,8 @@ static int ocelot_port_obj_del(struct ne
+       return ret;
+ }
+-static int ocelot_port_bridge_join(struct ocelot *ocelot, int port,
+-                                 struct net_device *bridge)
++int ocelot_port_bridge_join(struct ocelot *ocelot, int port,
++                          struct net_device *bridge)
+ {
+       if (!ocelot->bridge_mask) {
+               ocelot->hw_bridge_dev = bridge;
+@@ -1620,9 +1631,10 @@ static int ocelot_port_bridge_join(struc
+       return 0;
+ }
++EXPORT_SYMBOL(ocelot_port_bridge_join);
+-static int ocelot_port_bridge_leave(struct ocelot *ocelot, int port,
+-                                  struct net_device *bridge)
++int ocelot_port_bridge_leave(struct ocelot *ocelot, int port,
++                           struct net_device *bridge)
+ {
+       ocelot->bridge_mask &= ~BIT(port);
+@@ -1633,6 +1645,7 @@ static int ocelot_port_bridge_leave(stru
+       ocelot_port_set_pvid(ocelot, port, 0);
+       return ocelot_port_set_native_vlan(ocelot, port, 0);
+ }
++EXPORT_SYMBOL(ocelot_port_bridge_leave);
+ static void ocelot_set_aggr_pgids(struct ocelot *ocelot)
+ {
+@@ -2123,7 +2136,7 @@ static void ocelot_port_set_mtu(struct o
+       ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
+ }
+-static void ocelot_init_port(struct ocelot *ocelot, int port)
++void ocelot_init_port(struct ocelot *ocelot, int port)
+ {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+@@ -2170,6 +2183,7 @@ static void ocelot_init_port(struct ocel
+       /* Enable vcap lookups */
+       ocelot_vcap_enable(ocelot, port);
+ }
++EXPORT_SYMBOL(ocelot_init_port);
+ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
+                     void __iomem *regs,
+--- a/drivers/net/ethernet/mscc/ocelot.h
++++ b/drivers/net/ethernet/mscc/ocelot.h
+@@ -18,6 +18,7 @@
+ #include <linux/ptp_clock_kernel.h>
+ #include <linux/regmap.h>
++#include <soc/mscc/ocelot.h>
+ #include "ocelot_ana.h"
+ #include "ocelot_dev.h"
+ #include "ocelot_qsys.h"
+@@ -52,376 +53,6 @@ struct frame_info {
+       u32 timestamp;  /* rew_val */
+ };
+-#define IFH_INJ_BYPASS        BIT(31)
+-#define IFH_INJ_POP_CNT_DISABLE (3 << 28)
+-
+-#define IFH_TAG_TYPE_C 0
+-#define IFH_TAG_TYPE_S 1
+-
+-#define IFH_REW_OP_NOOP                       0x0
+-#define IFH_REW_OP_DSCP                       0x1
+-#define IFH_REW_OP_ONE_STEP_PTP               0x2
+-#define IFH_REW_OP_TWO_STEP_PTP               0x3
+-#define IFH_REW_OP_ORIGIN_PTP         0x5
+-
+-#define OCELOT_TAG_LEN                        16
+-#define OCELOT_SHORT_PREFIX_LEN               4
+-#define OCELOT_LONG_PREFIX_LEN                16
+-
+-#define OCELOT_SPEED_2500 0
+-#define OCELOT_SPEED_1000 1
+-#define OCELOT_SPEED_100  2
+-#define OCELOT_SPEED_10   3
+-
+-#define TARGET_OFFSET 24
+-#define REG_MASK GENMASK(TARGET_OFFSET - 1, 0)
+-#define REG(reg, offset) [reg & REG_MASK] = offset
+-
+-enum ocelot_target {
+-      ANA = 1,
+-      QS,
+-      QSYS,
+-      REW,
+-      SYS,
+-      S2,
+-      HSIO,
+-      PTP,
+-      TARGET_MAX,
+-};
+-
+-enum ocelot_reg {
+-      ANA_ADVLEARN = ANA << TARGET_OFFSET,
+-      ANA_VLANMASK,
+-      ANA_PORT_B_DOMAIN,
+-      ANA_ANAGEFIL,
+-      ANA_ANEVENTS,
+-      ANA_STORMLIMIT_BURST,
+-      ANA_STORMLIMIT_CFG,
+-      ANA_ISOLATED_PORTS,
+-      ANA_COMMUNITY_PORTS,
+-      ANA_AUTOAGE,
+-      ANA_MACTOPTIONS,
+-      ANA_LEARNDISC,
+-      ANA_AGENCTRL,
+-      ANA_MIRRORPORTS,
+-      ANA_EMIRRORPORTS,
+-      ANA_FLOODING,
+-      ANA_FLOODING_IPMC,
+-      ANA_SFLOW_CFG,
+-      ANA_PORT_MODE,
+-      ANA_CUT_THRU_CFG,
+-      ANA_PGID_PGID,
+-      ANA_TABLES_ANMOVED,
+-      ANA_TABLES_MACHDATA,
+-      ANA_TABLES_MACLDATA,
+-      ANA_TABLES_STREAMDATA,
+-      ANA_TABLES_MACACCESS,
+-      ANA_TABLES_MACTINDX,
+-      ANA_TABLES_VLANACCESS,
+-      ANA_TABLES_VLANTIDX,
+-      ANA_TABLES_ISDXACCESS,
+-      ANA_TABLES_ISDXTIDX,
+-      ANA_TABLES_ENTRYLIM,
+-      ANA_TABLES_PTP_ID_HIGH,
+-      ANA_TABLES_PTP_ID_LOW,
+-      ANA_TABLES_STREAMACCESS,
+-      ANA_TABLES_STREAMTIDX,
+-      ANA_TABLES_SEQ_HISTORY,
+-      ANA_TABLES_SEQ_MASK,
+-      ANA_TABLES_SFID_MASK,
+-      ANA_TABLES_SFIDACCESS,
+-      ANA_TABLES_SFIDTIDX,
+-      ANA_MSTI_STATE,
+-      ANA_OAM_UPM_LM_CNT,
+-      ANA_SG_ACCESS_CTRL,
+-      ANA_SG_CONFIG_REG_1,
+-      ANA_SG_CONFIG_REG_2,
+-      ANA_SG_CONFIG_REG_3,
+-      ANA_SG_CONFIG_REG_4,
+-      ANA_SG_CONFIG_REG_5,
+-      ANA_SG_GCL_GS_CONFIG,
+-      ANA_SG_GCL_TI_CONFIG,
+-      ANA_SG_STATUS_REG_1,
+-      ANA_SG_STATUS_REG_2,
+-      ANA_SG_STATUS_REG_3,
+-      ANA_PORT_VLAN_CFG,
+-      ANA_PORT_DROP_CFG,
+-      ANA_PORT_QOS_CFG,
+-      ANA_PORT_VCAP_CFG,
+-      ANA_PORT_VCAP_S1_KEY_CFG,
+-      ANA_PORT_VCAP_S2_CFG,
+-      ANA_PORT_PCP_DEI_MAP,
+-      ANA_PORT_CPU_FWD_CFG,
+-      ANA_PORT_CPU_FWD_BPDU_CFG,
+-      ANA_PORT_CPU_FWD_GARP_CFG,
+-      ANA_PORT_CPU_FWD_CCM_CFG,
+-      ANA_PORT_PORT_CFG,
+-      ANA_PORT_POL_CFG,
+-      ANA_PORT_PTP_CFG,
+-      ANA_PORT_PTP_DLY1_CFG,
+-      ANA_PORT_PTP_DLY2_CFG,
+-      ANA_PORT_SFID_CFG,
+-      ANA_PFC_PFC_CFG,
+-      ANA_PFC_PFC_TIMER,
+-      ANA_IPT_OAM_MEP_CFG,
+-      ANA_IPT_IPT,
+-      ANA_PPT_PPT,
+-      ANA_FID_MAP_FID_MAP,
+-      ANA_AGGR_CFG,
+-      ANA_CPUQ_CFG,
+-      ANA_CPUQ_CFG2,
+-      ANA_CPUQ_8021_CFG,
+-      ANA_DSCP_CFG,
+-      ANA_DSCP_REWR_CFG,
+-      ANA_VCAP_RNG_TYPE_CFG,
+-      ANA_VCAP_RNG_VAL_CFG,
+-      ANA_VRAP_CFG,
+-      ANA_VRAP_HDR_DATA,
+-      ANA_VRAP_HDR_MASK,
+-      ANA_DISCARD_CFG,
+-      ANA_FID_CFG,
+-      ANA_POL_PIR_CFG,
+-      ANA_POL_CIR_CFG,
+-      ANA_POL_MODE_CFG,
+-      ANA_POL_PIR_STATE,
+-      ANA_POL_CIR_STATE,
+-      ANA_POL_STATE,
+-      ANA_POL_FLOWC,
+-      ANA_POL_HYST,
+-      ANA_POL_MISC_CFG,
+-      QS_XTR_GRP_CFG = QS << TARGET_OFFSET,
+-      QS_XTR_RD,
+-      QS_XTR_FRM_PRUNING,
+-      QS_XTR_FLUSH,
+-      QS_XTR_DATA_PRESENT,
+-      QS_XTR_CFG,
+-      QS_INJ_GRP_CFG,
+-      QS_INJ_WR,
+-      QS_INJ_CTRL,
+-      QS_INJ_STATUS,
+-      QS_INJ_ERR,
+-      QS_INH_DBG,
+-      QSYS_PORT_MODE = QSYS << TARGET_OFFSET,
+-      QSYS_SWITCH_PORT_MODE,
+-      QSYS_STAT_CNT_CFG,
+-      QSYS_EEE_CFG,
+-      QSYS_EEE_THRES,
+-      QSYS_IGR_NO_SHARING,
+-      QSYS_EGR_NO_SHARING,
+-      QSYS_SW_STATUS,
+-      QSYS_EXT_CPU_CFG,
+-      QSYS_PAD_CFG,
+-      QSYS_CPU_GROUP_MAP,
+-      QSYS_QMAP,
+-      QSYS_ISDX_SGRP,
+-      QSYS_TIMED_FRAME_ENTRY,
+-      QSYS_TFRM_MISC,
+-      QSYS_TFRM_PORT_DLY,
+-      QSYS_TFRM_TIMER_CFG_1,
+-      QSYS_TFRM_TIMER_CFG_2,
+-      QSYS_TFRM_TIMER_CFG_3,
+-      QSYS_TFRM_TIMER_CFG_4,
+-      QSYS_TFRM_TIMER_CFG_5,
+-      QSYS_TFRM_TIMER_CFG_6,
+-      QSYS_TFRM_TIMER_CFG_7,
+-      QSYS_TFRM_TIMER_CFG_8,
+-      QSYS_RED_PROFILE,
+-      QSYS_RES_QOS_MODE,
+-      QSYS_RES_CFG,
+-      QSYS_RES_STAT,
+-      QSYS_EGR_DROP_MODE,
+-      QSYS_EQ_CTRL,
+-      QSYS_EVENTS_CORE,
+-      QSYS_QMAXSDU_CFG_0,
+-      QSYS_QMAXSDU_CFG_1,
+-      QSYS_QMAXSDU_CFG_2,
+-      QSYS_QMAXSDU_CFG_3,
+-      QSYS_QMAXSDU_CFG_4,
+-      QSYS_QMAXSDU_CFG_5,
+-      QSYS_QMAXSDU_CFG_6,
+-      QSYS_QMAXSDU_CFG_7,
+-      QSYS_PREEMPTION_CFG,
+-      QSYS_CIR_CFG,
+-      QSYS_EIR_CFG,
+-      QSYS_SE_CFG,
+-      QSYS_SE_DWRR_CFG,
+-      QSYS_SE_CONNECT,
+-      QSYS_SE_DLB_SENSE,
+-      QSYS_CIR_STATE,
+-      QSYS_EIR_STATE,
+-      QSYS_SE_STATE,
+-      QSYS_HSCH_MISC_CFG,
+-      QSYS_TAG_CONFIG,
+-      QSYS_TAS_PARAM_CFG_CTRL,
+-      QSYS_PORT_MAX_SDU,
+-      QSYS_PARAM_CFG_REG_1,
+-      QSYS_PARAM_CFG_REG_2,
+-      QSYS_PARAM_CFG_REG_3,
+-      QSYS_PARAM_CFG_REG_4,
+-      QSYS_PARAM_CFG_REG_5,
+-      QSYS_GCL_CFG_REG_1,
+-      QSYS_GCL_CFG_REG_2,
+-      QSYS_PARAM_STATUS_REG_1,
+-      QSYS_PARAM_STATUS_REG_2,
+-      QSYS_PARAM_STATUS_REG_3,
+-      QSYS_PARAM_STATUS_REG_4,
+-      QSYS_PARAM_STATUS_REG_5,
+-      QSYS_PARAM_STATUS_REG_6,
+-      QSYS_PARAM_STATUS_REG_7,
+-      QSYS_PARAM_STATUS_REG_8,
+-      QSYS_PARAM_STATUS_REG_9,
+-      QSYS_GCL_STATUS_REG_1,
+-      QSYS_GCL_STATUS_REG_2,
+-      REW_PORT_VLAN_CFG = REW << TARGET_OFFSET,
+-      REW_TAG_CFG,
+-      REW_PORT_CFG,
+-      REW_DSCP_CFG,
+-      REW_PCP_DEI_QOS_MAP_CFG,
+-      REW_PTP_CFG,
+-      REW_PTP_DLY1_CFG,
+-      REW_RED_TAG_CFG,
+-      REW_DSCP_REMAP_DP1_CFG,
+-      REW_DSCP_REMAP_CFG,
+-      REW_STAT_CFG,
+-      REW_REW_STICKY,
+-      REW_PPT,
+-      SYS_COUNT_RX_OCTETS = SYS << TARGET_OFFSET,
+-      SYS_COUNT_RX_UNICAST,
+-      SYS_COUNT_RX_MULTICAST,
+-      SYS_COUNT_RX_BROADCAST,
+-      SYS_COUNT_RX_SHORTS,
+-      SYS_COUNT_RX_FRAGMENTS,
+-      SYS_COUNT_RX_JABBERS,
+-      SYS_COUNT_RX_CRC_ALIGN_ERRS,
+-      SYS_COUNT_RX_SYM_ERRS,
+-      SYS_COUNT_RX_64,
+-      SYS_COUNT_RX_65_127,
+-      SYS_COUNT_RX_128_255,
+-      SYS_COUNT_RX_256_1023,
+-      SYS_COUNT_RX_1024_1526,
+-      SYS_COUNT_RX_1527_MAX,
+-      SYS_COUNT_RX_PAUSE,
+-      SYS_COUNT_RX_CONTROL,
+-      SYS_COUNT_RX_LONGS,
+-      SYS_COUNT_RX_CLASSIFIED_DROPS,
+-      SYS_COUNT_TX_OCTETS,
+-      SYS_COUNT_TX_UNICAST,
+-      SYS_COUNT_TX_MULTICAST,
+-      SYS_COUNT_TX_BROADCAST,
+-      SYS_COUNT_TX_COLLISION,
+-      SYS_COUNT_TX_DROPS,
+-      SYS_COUNT_TX_PAUSE,
+-      SYS_COUNT_TX_64,
+-      SYS_COUNT_TX_65_127,
+-      SYS_COUNT_TX_128_511,
+-      SYS_COUNT_TX_512_1023,
+-      SYS_COUNT_TX_1024_1526,
+-      SYS_COUNT_TX_1527_MAX,
+-      SYS_COUNT_TX_AGING,
+-      SYS_RESET_CFG,
+-      SYS_SR_ETYPE_CFG,
+-      SYS_VLAN_ETYPE_CFG,
+-      SYS_PORT_MODE,
+-      SYS_FRONT_PORT_MODE,
+-      SYS_FRM_AGING,
+-      SYS_STAT_CFG,
+-      SYS_SW_STATUS,
+-      SYS_MISC_CFG,
+-      SYS_REW_MAC_HIGH_CFG,
+-      SYS_REW_MAC_LOW_CFG,
+-      SYS_TIMESTAMP_OFFSET,
+-      SYS_CMID,
+-      SYS_PAUSE_CFG,
+-      SYS_PAUSE_TOT_CFG,
+-      SYS_ATOP,
+-      SYS_ATOP_TOT_CFG,
+-      SYS_MAC_FC_CFG,
+-      SYS_MMGT,
+-      SYS_MMGT_FAST,
+-      SYS_EVENTS_DIF,
+-      SYS_EVENTS_CORE,
+-      SYS_CNT,
+-      SYS_PTP_STATUS,
+-      SYS_PTP_TXSTAMP,
+-      SYS_PTP_NXT,
+-      SYS_PTP_CFG,
+-      SYS_RAM_INIT,
+-      SYS_CM_ADDR,
+-      SYS_CM_DATA_WR,
+-      SYS_CM_DATA_RD,
+-      SYS_CM_OP,
+-      SYS_CM_DATA,
+-      S2_CORE_UPDATE_CTRL = S2 << TARGET_OFFSET,
+-      S2_CORE_MV_CFG,
+-      S2_CACHE_ENTRY_DAT,
+-      S2_CACHE_MASK_DAT,
+-      S2_CACHE_ACTION_DAT,
+-      S2_CACHE_CNT_DAT,
+-      S2_CACHE_TG_DAT,
+-      PTP_PIN_CFG = PTP << TARGET_OFFSET,
+-      PTP_PIN_TOD_SEC_MSB,
+-      PTP_PIN_TOD_SEC_LSB,
+-      PTP_PIN_TOD_NSEC,
+-      PTP_CFG_MISC,
+-      PTP_CLK_CFG_ADJ_CFG,
+-      PTP_CLK_CFG_ADJ_FREQ,
+-};
+-
+-enum ocelot_regfield {
+-      ANA_ADVLEARN_VLAN_CHK,
+-      ANA_ADVLEARN_LEARN_MIRROR,
+-      ANA_ANEVENTS_FLOOD_DISCARD,
+-      ANA_ANEVENTS_MSTI_DROP,
+-      ANA_ANEVENTS_ACLKILL,
+-      ANA_ANEVENTS_ACLUSED,
+-      ANA_ANEVENTS_AUTOAGE,
+-      ANA_ANEVENTS_VS2TTL1,
+-      ANA_ANEVENTS_STORM_DROP,
+-      ANA_ANEVENTS_LEARN_DROP,
+-      ANA_ANEVENTS_AGED_ENTRY,
+-      ANA_ANEVENTS_CPU_LEARN_FAILED,
+-      ANA_ANEVENTS_AUTO_LEARN_FAILED,
+-      ANA_ANEVENTS_LEARN_REMOVE,
+-      ANA_ANEVENTS_AUTO_LEARNED,
+-      ANA_ANEVENTS_AUTO_MOVED,
+-      ANA_ANEVENTS_DROPPED,
+-      ANA_ANEVENTS_CLASSIFIED_DROP,
+-      ANA_ANEVENTS_CLASSIFIED_COPY,
+-      ANA_ANEVENTS_VLAN_DISCARD,
+-      ANA_ANEVENTS_FWD_DISCARD,
+-      ANA_ANEVENTS_MULTICAST_FLOOD,
+-      ANA_ANEVENTS_UNICAST_FLOOD,
+-      ANA_ANEVENTS_DEST_KNOWN,
+-      ANA_ANEVENTS_BUCKET3_MATCH,
+-      ANA_ANEVENTS_BUCKET2_MATCH,
+-      ANA_ANEVENTS_BUCKET1_MATCH,
+-      ANA_ANEVENTS_BUCKET0_MATCH,
+-      ANA_ANEVENTS_CPU_OPERATION,
+-      ANA_ANEVENTS_DMAC_LOOKUP,
+-      ANA_ANEVENTS_SMAC_LOOKUP,
+-      ANA_ANEVENTS_SEQ_GEN_ERR_0,
+-      ANA_ANEVENTS_SEQ_GEN_ERR_1,
+-      ANA_TABLES_MACACCESS_B_DOM,
+-      ANA_TABLES_MACTINDX_BUCKET,
+-      ANA_TABLES_MACTINDX_M_INDEX,
+-      QSYS_TIMED_FRAME_ENTRY_TFRM_VLD,
+-      QSYS_TIMED_FRAME_ENTRY_TFRM_FP,
+-      QSYS_TIMED_FRAME_ENTRY_TFRM_PORTNO,
+-      QSYS_TIMED_FRAME_ENTRY_TFRM_TM_SEL,
+-      QSYS_TIMED_FRAME_ENTRY_TFRM_TM_T,
+-      SYS_RESET_CFG_CORE_ENA,
+-      SYS_RESET_CFG_MEM_ENA,
+-      SYS_RESET_CFG_MEM_INIT,
+-      REGFIELD_MAX
+-};
+-
+-enum ocelot_clk_pins {
+-      ALT_PPS_PIN     = 1,
+-      EXT_CLK_PIN,
+-      ALT_LDST_PIN,
+-      TOD_ACC_PIN
+-};
+-
+ struct ocelot_multicast {
+       struct list_head list;
+       unsigned char addr[ETH_ALEN];
+@@ -429,88 +60,6 @@ struct ocelot_multicast {
+       u16 ports;
+ };
+-enum ocelot_tag_prefix {
+-      OCELOT_TAG_PREFIX_DISABLED      = 0,
+-      OCELOT_TAG_PREFIX_NONE,
+-      OCELOT_TAG_PREFIX_SHORT,
+-      OCELOT_TAG_PREFIX_LONG,
+-};
+-
+-struct ocelot_port;
+-struct ocelot;
+-
+-struct ocelot_stat_layout {
+-      u32 offset;
+-      char name[ETH_GSTRING_LEN];
+-};
+-
+-struct ocelot_ops {
+-      void (*pcs_init)(struct ocelot *ocelot, int port);
+-      int (*reset)(struct ocelot *ocelot);
+-};
+-
+-struct ocelot {
+-      const struct ocelot_ops *ops;
+-      struct device *dev;
+-
+-      struct regmap *targets[TARGET_MAX];
+-      struct regmap_field *regfields[REGFIELD_MAX];
+-      const u32 *const *map;
+-      const struct ocelot_stat_layout *stats_layout;
+-      unsigned int num_stats;
+-
+-      u8 base_mac[ETH_ALEN];
+-
+-      struct net_device *hw_bridge_dev;
+-      u16 bridge_mask;
+-      u16 bridge_fwd_mask;
+-
+-      struct workqueue_struct *ocelot_owq;
+-
+-      int shared_queue_sz;
+-
+-      u8 num_phys_ports;
+-      u8 num_cpu_ports;
+-      u8 cpu;
+-      struct ocelot_port **ports;
+-
+-      u32 *lags;
+-
+-      /* Keep track of the vlan port masks */
+-      u32 vlan_mask[VLAN_N_VID];
+-
+-      struct list_head multicast;
+-
+-      /* Workqueue to check statistics for overflow with its lock */
+-      struct mutex stats_lock;
+-      u64 *stats;
+-      struct delayed_work stats_work;
+-      struct workqueue_struct *stats_queue;
+-
+-      u8 ptp:1;
+-      struct ptp_clock *ptp_clock;
+-      struct ptp_clock_info ptp_info;
+-      struct hwtstamp_config hwtstamp_config;
+-      struct mutex ptp_lock; /* Protects the PTP interface state */
+-      spinlock_t ptp_clock_lock; /* Protects the PTP clock */
+-};
+-
+-struct ocelot_port {
+-      struct ocelot *ocelot;
+-
+-      void __iomem *regs;
+-
+-      /* Ingress default VLAN (pvid) */
+-      u16 pvid;
+-
+-      /* Egress default VLAN (vid) */
+-      u16 vid;
+-
+-      u8 ptp_cmd;
+-      struct list_head skbs;
+-      u8 ts_id;
+-};
+-
+ struct ocelot_port_private {
+       struct ocelot_port port;
+       struct net_device *dev;
+@@ -531,37 +80,12 @@ struct ocelot_skb {
+       u8 id;
+ };
+-u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset);
+-#define ocelot_read_ix(ocelot, reg, gi, ri) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
+-#define ocelot_read_gix(ocelot, reg, gi) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi))
+-#define ocelot_read_rix(ocelot, reg, ri) __ocelot_read_ix(ocelot, reg, reg##_RSZ * (ri))
+-#define ocelot_read(ocelot, reg) __ocelot_read_ix(ocelot, reg, 0)
+-
+-void __ocelot_write_ix(struct ocelot *ocelot, u32 val, u32 reg, u32 offset);
+-#define ocelot_write_ix(ocelot, val, reg, gi, ri) __ocelot_write_ix(ocelot, val, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
+-#define ocelot_write_gix(ocelot, val, reg, gi) __ocelot_write_ix(ocelot, val, reg, reg##_GSZ * (gi))
+-#define ocelot_write_rix(ocelot, val, reg, ri) __ocelot_write_ix(ocelot, val, reg, reg##_RSZ * (ri))
+-#define ocelot_write(ocelot, val, reg) __ocelot_write_ix(ocelot, val, reg, 0)
+-
+-void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask, u32 reg,
+-                   u32 offset);
+-#define ocelot_rmw_ix(ocelot, val, m, reg, gi, ri) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
+-#define ocelot_rmw_gix(ocelot, val, m, reg, gi) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_GSZ * (gi))
+-#define ocelot_rmw_rix(ocelot, val, m, reg, ri) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_RSZ * (ri))
+-#define ocelot_rmw(ocelot, val, m, reg) __ocelot_rmw_ix(ocelot, val, m, reg, 0)
+-
+ u32 ocelot_port_readl(struct ocelot_port *port, u32 reg);
+ void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg);
+-int ocelot_regfields_init(struct ocelot *ocelot,
+-                        const struct reg_field *const regfields);
+-struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res);
+-
+ #define ocelot_field_write(ocelot, reg, val) regmap_field_write((ocelot)->regfields[(reg)], (val))
+ #define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val))
+-int ocelot_init(struct ocelot *ocelot);
+-void ocelot_deinit(struct ocelot *ocelot);
+ int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops);
+ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
+                     void __iomem *regs,
+@@ -575,7 +99,7 @@ extern struct notifier_block ocelot_netd
+ extern struct notifier_block ocelot_switchdev_nb;
+ extern struct notifier_block ocelot_switchdev_blocking_nb;
+-int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts);
+-void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts);
++#define ocelot_field_write(ocelot, reg, val) regmap_field_write((ocelot)->regfields[(reg)], (val))
++#define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val))
+ #endif
+--- /dev/null
++++ b/include/soc/mscc/ocelot.h
+@@ -0,0 +1,539 @@
++/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
++/* Copyright (c) 2017 Microsemi Corporation
++ */
++
++#ifndef _SOC_MSCC_OCELOT_H
++#define _SOC_MSCC_OCELOT_H
++
++#include <linux/ptp_clock_kernel.h>
++#include <linux/net_tstamp.h>
++#include <linux/if_vlan.h>
++#include <linux/regmap.h>
++#include <net/dsa.h>
++
++#define IFH_INJ_BYPASS                        BIT(31)
++#define IFH_INJ_POP_CNT_DISABLE               (3 << 28)
++
++#define IFH_TAG_TYPE_C                        0
++#define IFH_TAG_TYPE_S                        1
++
++#define IFH_REW_OP_NOOP                       0x0
++#define IFH_REW_OP_DSCP                       0x1
++#define IFH_REW_OP_ONE_STEP_PTP               0x2
++#define IFH_REW_OP_TWO_STEP_PTP               0x3
++#define IFH_REW_OP_ORIGIN_PTP         0x5
++
++#define OCELOT_TAG_LEN                        16
++#define OCELOT_SHORT_PREFIX_LEN               4
++#define OCELOT_LONG_PREFIX_LEN                16
++
++#define OCELOT_SPEED_2500             0
++#define OCELOT_SPEED_1000             1
++#define OCELOT_SPEED_100              2
++#define OCELOT_SPEED_10                       3
++
++#define TARGET_OFFSET                 24
++#define REG_MASK                      GENMASK(TARGET_OFFSET - 1, 0)
++#define REG(reg, offset)              [reg & REG_MASK] = offset
++
++#define REG_RESERVED_ADDR             0xffffffff
++#define REG_RESERVED(reg)             REG(reg, REG_RESERVED_ADDR)
++
++enum ocelot_target {
++      ANA = 1,
++      QS,
++      QSYS,
++      REW,
++      SYS,
++      S2,
++      HSIO,
++      PTP,
++      GCB,
++      TARGET_MAX,
++};
++
++enum ocelot_reg {
++      ANA_ADVLEARN = ANA << TARGET_OFFSET,
++      ANA_VLANMASK,
++      ANA_PORT_B_DOMAIN,
++      ANA_ANAGEFIL,
++      ANA_ANEVENTS,
++      ANA_STORMLIMIT_BURST,
++      ANA_STORMLIMIT_CFG,
++      ANA_ISOLATED_PORTS,
++      ANA_COMMUNITY_PORTS,
++      ANA_AUTOAGE,
++      ANA_MACTOPTIONS,
++      ANA_LEARNDISC,
++      ANA_AGENCTRL,
++      ANA_MIRRORPORTS,
++      ANA_EMIRRORPORTS,
++      ANA_FLOODING,
++      ANA_FLOODING_IPMC,
++      ANA_SFLOW_CFG,
++      ANA_PORT_MODE,
++      ANA_CUT_THRU_CFG,
++      ANA_PGID_PGID,
++      ANA_TABLES_ANMOVED,
++      ANA_TABLES_MACHDATA,
++      ANA_TABLES_MACLDATA,
++      ANA_TABLES_STREAMDATA,
++      ANA_TABLES_MACACCESS,
++      ANA_TABLES_MACTINDX,
++      ANA_TABLES_VLANACCESS,
++      ANA_TABLES_VLANTIDX,
++      ANA_TABLES_ISDXACCESS,
++      ANA_TABLES_ISDXTIDX,
++      ANA_TABLES_ENTRYLIM,
++      ANA_TABLES_PTP_ID_HIGH,
++      ANA_TABLES_PTP_ID_LOW,
++      ANA_TABLES_STREAMACCESS,
++      ANA_TABLES_STREAMTIDX,
++      ANA_TABLES_SEQ_HISTORY,
++      ANA_TABLES_SEQ_MASK,
++      ANA_TABLES_SFID_MASK,
++      ANA_TABLES_SFIDACCESS,
++      ANA_TABLES_SFIDTIDX,
++      ANA_MSTI_STATE,
++      ANA_OAM_UPM_LM_CNT,
++      ANA_SG_ACCESS_CTRL,
++      ANA_SG_CONFIG_REG_1,
++      ANA_SG_CONFIG_REG_2,
++      ANA_SG_CONFIG_REG_3,
++      ANA_SG_CONFIG_REG_4,
++      ANA_SG_CONFIG_REG_5,
++      ANA_SG_GCL_GS_CONFIG,
++      ANA_SG_GCL_TI_CONFIG,
++      ANA_SG_STATUS_REG_1,
++      ANA_SG_STATUS_REG_2,
++      ANA_SG_STATUS_REG_3,
++      ANA_PORT_VLAN_CFG,
++      ANA_PORT_DROP_CFG,
++      ANA_PORT_QOS_CFG,
++      ANA_PORT_VCAP_CFG,
++      ANA_PORT_VCAP_S1_KEY_CFG,
++      ANA_PORT_VCAP_S2_CFG,
++      ANA_PORT_PCP_DEI_MAP,
++      ANA_PORT_CPU_FWD_CFG,
++      ANA_PORT_CPU_FWD_BPDU_CFG,
++      ANA_PORT_CPU_FWD_GARP_CFG,
++      ANA_PORT_CPU_FWD_CCM_CFG,
++      ANA_PORT_PORT_CFG,
++      ANA_PORT_POL_CFG,
++      ANA_PORT_PTP_CFG,
++      ANA_PORT_PTP_DLY1_CFG,
++      ANA_PORT_PTP_DLY2_CFG,
++      ANA_PORT_SFID_CFG,
++      ANA_PFC_PFC_CFG,
++      ANA_PFC_PFC_TIMER,
++      ANA_IPT_OAM_MEP_CFG,
++      ANA_IPT_IPT,
++      ANA_PPT_PPT,
++      ANA_FID_MAP_FID_MAP,
++      ANA_AGGR_CFG,
++      ANA_CPUQ_CFG,
++      ANA_CPUQ_CFG2,
++      ANA_CPUQ_8021_CFG,
++      ANA_DSCP_CFG,
++      ANA_DSCP_REWR_CFG,
++      ANA_VCAP_RNG_TYPE_CFG,
++      ANA_VCAP_RNG_VAL_CFG,
++      ANA_VRAP_CFG,
++      ANA_VRAP_HDR_DATA,
++      ANA_VRAP_HDR_MASK,
++      ANA_DISCARD_CFG,
++      ANA_FID_CFG,
++      ANA_POL_PIR_CFG,
++      ANA_POL_CIR_CFG,
++      ANA_POL_MODE_CFG,
++      ANA_POL_PIR_STATE,
++      ANA_POL_CIR_STATE,
++      ANA_POL_STATE,
++      ANA_POL_FLOWC,
++      ANA_POL_HYST,
++      ANA_POL_MISC_CFG,
++      QS_XTR_GRP_CFG = QS << TARGET_OFFSET,
++      QS_XTR_RD,
++      QS_XTR_FRM_PRUNING,
++      QS_XTR_FLUSH,
++      QS_XTR_DATA_PRESENT,
++      QS_XTR_CFG,
++      QS_INJ_GRP_CFG,
++      QS_INJ_WR,
++      QS_INJ_CTRL,
++      QS_INJ_STATUS,
++      QS_INJ_ERR,
++      QS_INH_DBG,
++      QSYS_PORT_MODE = QSYS << TARGET_OFFSET,
++      QSYS_SWITCH_PORT_MODE,
++      QSYS_STAT_CNT_CFG,
++      QSYS_EEE_CFG,
++      QSYS_EEE_THRES,
++      QSYS_IGR_NO_SHARING,
++      QSYS_EGR_NO_SHARING,
++      QSYS_SW_STATUS,
++      QSYS_EXT_CPU_CFG,
++      QSYS_PAD_CFG,
++      QSYS_CPU_GROUP_MAP,
++      QSYS_QMAP,
++      QSYS_ISDX_SGRP,
++      QSYS_TIMED_FRAME_ENTRY,
++      QSYS_TFRM_MISC,
++      QSYS_TFRM_PORT_DLY,
++      QSYS_TFRM_TIMER_CFG_1,
++      QSYS_TFRM_TIMER_CFG_2,
++      QSYS_TFRM_TIMER_CFG_3,
++      QSYS_TFRM_TIMER_CFG_4,
++      QSYS_TFRM_TIMER_CFG_5,
++      QSYS_TFRM_TIMER_CFG_6,
++      QSYS_TFRM_TIMER_CFG_7,
++      QSYS_TFRM_TIMER_CFG_8,
++      QSYS_RED_PROFILE,
++      QSYS_RES_QOS_MODE,
++      QSYS_RES_CFG,
++      QSYS_RES_STAT,
++      QSYS_EGR_DROP_MODE,
++      QSYS_EQ_CTRL,
++      QSYS_EVENTS_CORE,
++      QSYS_QMAXSDU_CFG_0,
++      QSYS_QMAXSDU_CFG_1,
++      QSYS_QMAXSDU_CFG_2,
++      QSYS_QMAXSDU_CFG_3,
++      QSYS_QMAXSDU_CFG_4,
++      QSYS_QMAXSDU_CFG_5,
++      QSYS_QMAXSDU_CFG_6,
++      QSYS_QMAXSDU_CFG_7,
++      QSYS_PREEMPTION_CFG,
++      QSYS_CIR_CFG,
++      QSYS_EIR_CFG,
++      QSYS_SE_CFG,
++      QSYS_SE_DWRR_CFG,
++      QSYS_SE_CONNECT,
++      QSYS_SE_DLB_SENSE,
++      QSYS_CIR_STATE,
++      QSYS_EIR_STATE,
++      QSYS_SE_STATE,
++      QSYS_HSCH_MISC_CFG,
++      QSYS_TAG_CONFIG,
++      QSYS_TAS_PARAM_CFG_CTRL,
++      QSYS_PORT_MAX_SDU,
++      QSYS_PARAM_CFG_REG_1,
++      QSYS_PARAM_CFG_REG_2,
++      QSYS_PARAM_CFG_REG_3,
++      QSYS_PARAM_CFG_REG_4,
++      QSYS_PARAM_CFG_REG_5,
++      QSYS_GCL_CFG_REG_1,
++      QSYS_GCL_CFG_REG_2,
++      QSYS_PARAM_STATUS_REG_1,
++      QSYS_PARAM_STATUS_REG_2,
++      QSYS_PARAM_STATUS_REG_3,
++      QSYS_PARAM_STATUS_REG_4,
++      QSYS_PARAM_STATUS_REG_5,
++      QSYS_PARAM_STATUS_REG_6,
++      QSYS_PARAM_STATUS_REG_7,
++      QSYS_PARAM_STATUS_REG_8,
++      QSYS_PARAM_STATUS_REG_9,
++      QSYS_GCL_STATUS_REG_1,
++      QSYS_GCL_STATUS_REG_2,
++      REW_PORT_VLAN_CFG = REW << TARGET_OFFSET,
++      REW_TAG_CFG,
++      REW_PORT_CFG,
++      REW_DSCP_CFG,
++      REW_PCP_DEI_QOS_MAP_CFG,
++      REW_PTP_CFG,
++      REW_PTP_DLY1_CFG,
++      REW_RED_TAG_CFG,
++      REW_DSCP_REMAP_DP1_CFG,
++      REW_DSCP_REMAP_CFG,
++      REW_STAT_CFG,
++      REW_REW_STICKY,
++      REW_PPT,
++      SYS_COUNT_RX_OCTETS = SYS << TARGET_OFFSET,
++      SYS_COUNT_RX_UNICAST,
++      SYS_COUNT_RX_MULTICAST,
++      SYS_COUNT_RX_BROADCAST,
++      SYS_COUNT_RX_SHORTS,
++      SYS_COUNT_RX_FRAGMENTS,
++      SYS_COUNT_RX_JABBERS,
++      SYS_COUNT_RX_CRC_ALIGN_ERRS,
++      SYS_COUNT_RX_SYM_ERRS,
++      SYS_COUNT_RX_64,
++      SYS_COUNT_RX_65_127,
++      SYS_COUNT_RX_128_255,
++      SYS_COUNT_RX_256_1023,
++      SYS_COUNT_RX_1024_1526,
++      SYS_COUNT_RX_1527_MAX,
++      SYS_COUNT_RX_PAUSE,
++      SYS_COUNT_RX_CONTROL,
++      SYS_COUNT_RX_LONGS,
++      SYS_COUNT_RX_CLASSIFIED_DROPS,
++      SYS_COUNT_TX_OCTETS,
++      SYS_COUNT_TX_UNICAST,
++      SYS_COUNT_TX_MULTICAST,
++      SYS_COUNT_TX_BROADCAST,
++      SYS_COUNT_TX_COLLISION,
++      SYS_COUNT_TX_DROPS,
++      SYS_COUNT_TX_PAUSE,
++      SYS_COUNT_TX_64,
++      SYS_COUNT_TX_65_127,
++      SYS_COUNT_TX_128_511,
++      SYS_COUNT_TX_512_1023,
++      SYS_COUNT_TX_1024_1526,
++      SYS_COUNT_TX_1527_MAX,
++      SYS_COUNT_TX_AGING,
++      SYS_RESET_CFG,
++      SYS_SR_ETYPE_CFG,
++      SYS_VLAN_ETYPE_CFG,
++      SYS_PORT_MODE,
++      SYS_FRONT_PORT_MODE,
++      SYS_FRM_AGING,
++      SYS_STAT_CFG,
++      SYS_SW_STATUS,
++      SYS_MISC_CFG,
++      SYS_REW_MAC_HIGH_CFG,
++      SYS_REW_MAC_LOW_CFG,
++      SYS_TIMESTAMP_OFFSET,
++      SYS_CMID,
++      SYS_PAUSE_CFG,
++      SYS_PAUSE_TOT_CFG,
++      SYS_ATOP,
++      SYS_ATOP_TOT_CFG,
++      SYS_MAC_FC_CFG,
++      SYS_MMGT,
++      SYS_MMGT_FAST,
++      SYS_EVENTS_DIF,
++      SYS_EVENTS_CORE,
++      SYS_CNT,
++      SYS_PTP_STATUS,
++      SYS_PTP_TXSTAMP,
++      SYS_PTP_NXT,
++      SYS_PTP_CFG,
++      SYS_RAM_INIT,
++      SYS_CM_ADDR,
++      SYS_CM_DATA_WR,
++      SYS_CM_DATA_RD,
++      SYS_CM_OP,
++      SYS_CM_DATA,
++      S2_CORE_UPDATE_CTRL = S2 << TARGET_OFFSET,
++      S2_CORE_MV_CFG,
++      S2_CACHE_ENTRY_DAT,
++      S2_CACHE_MASK_DAT,
++      S2_CACHE_ACTION_DAT,
++      S2_CACHE_CNT_DAT,
++      S2_CACHE_TG_DAT,
++      PTP_PIN_CFG = PTP << TARGET_OFFSET,
++      PTP_PIN_TOD_SEC_MSB,
++      PTP_PIN_TOD_SEC_LSB,
++      PTP_PIN_TOD_NSEC,
++      PTP_CFG_MISC,
++      PTP_CLK_CFG_ADJ_CFG,
++      PTP_CLK_CFG_ADJ_FREQ,
++      GCB_SOFT_RST = GCB << TARGET_OFFSET,
++};
++
++enum ocelot_regfield {
++      ANA_ADVLEARN_VLAN_CHK,
++      ANA_ADVLEARN_LEARN_MIRROR,
++      ANA_ANEVENTS_FLOOD_DISCARD,
++      ANA_ANEVENTS_MSTI_DROP,
++      ANA_ANEVENTS_ACLKILL,
++      ANA_ANEVENTS_ACLUSED,
++      ANA_ANEVENTS_AUTOAGE,
++      ANA_ANEVENTS_VS2TTL1,
++      ANA_ANEVENTS_STORM_DROP,
++      ANA_ANEVENTS_LEARN_DROP,
++      ANA_ANEVENTS_AGED_ENTRY,
++      ANA_ANEVENTS_CPU_LEARN_FAILED,
++      ANA_ANEVENTS_AUTO_LEARN_FAILED,
++      ANA_ANEVENTS_LEARN_REMOVE,
++      ANA_ANEVENTS_AUTO_LEARNED,
++      ANA_ANEVENTS_AUTO_MOVED,
++      ANA_ANEVENTS_DROPPED,
++      ANA_ANEVENTS_CLASSIFIED_DROP,
++      ANA_ANEVENTS_CLASSIFIED_COPY,
++      ANA_ANEVENTS_VLAN_DISCARD,
++      ANA_ANEVENTS_FWD_DISCARD,
++      ANA_ANEVENTS_MULTICAST_FLOOD,
++      ANA_ANEVENTS_UNICAST_FLOOD,
++      ANA_ANEVENTS_DEST_KNOWN,
++      ANA_ANEVENTS_BUCKET3_MATCH,
++      ANA_ANEVENTS_BUCKET2_MATCH,
++      ANA_ANEVENTS_BUCKET1_MATCH,
++      ANA_ANEVENTS_BUCKET0_MATCH,
++      ANA_ANEVENTS_CPU_OPERATION,
++      ANA_ANEVENTS_DMAC_LOOKUP,
++      ANA_ANEVENTS_SMAC_LOOKUP,
++      ANA_ANEVENTS_SEQ_GEN_ERR_0,
++      ANA_ANEVENTS_SEQ_GEN_ERR_1,
++      ANA_TABLES_MACACCESS_B_DOM,
++      ANA_TABLES_MACTINDX_BUCKET,
++      ANA_TABLES_MACTINDX_M_INDEX,
++      QSYS_TIMED_FRAME_ENTRY_TFRM_VLD,
++      QSYS_TIMED_FRAME_ENTRY_TFRM_FP,
++      QSYS_TIMED_FRAME_ENTRY_TFRM_PORTNO,
++      QSYS_TIMED_FRAME_ENTRY_TFRM_TM_SEL,
++      QSYS_TIMED_FRAME_ENTRY_TFRM_TM_T,
++      SYS_RESET_CFG_CORE_ENA,
++      SYS_RESET_CFG_MEM_ENA,
++      SYS_RESET_CFG_MEM_INIT,
++      GCB_SOFT_RST_SWC_RST,
++      REGFIELD_MAX
++};
++
++enum ocelot_clk_pins {
++      ALT_PPS_PIN     = 1,
++      EXT_CLK_PIN,
++      ALT_LDST_PIN,
++      TOD_ACC_PIN
++};
++
++struct ocelot_stat_layout {
++      u32 offset;
++      char name[ETH_GSTRING_LEN];
++};
++
++enum ocelot_tag_prefix {
++      OCELOT_TAG_PREFIX_DISABLED      = 0,
++      OCELOT_TAG_PREFIX_NONE,
++      OCELOT_TAG_PREFIX_SHORT,
++      OCELOT_TAG_PREFIX_LONG,
++};
++
++struct ocelot;
++
++struct ocelot_ops {
++      void (*pcs_init)(struct ocelot *ocelot, int port);
++      int (*reset)(struct ocelot *ocelot);
++};
++
++struct ocelot_port {
++      struct ocelot                   *ocelot;
++
++      void __iomem                    *regs;
++
++      /* Ingress default VLAN (pvid) */
++      u16                             pvid;
++
++      /* Egress default VLAN (vid) */
++      u16                             vid;
++
++      u8                              ptp_cmd;
++      struct list_head                skbs;
++      u8                              ts_id;
++};
++
++struct ocelot {
++      struct device                   *dev;
++
++      const struct ocelot_ops         *ops;
++      struct regmap                   *targets[TARGET_MAX];
++      struct regmap_field             *regfields[REGFIELD_MAX];
++      const u32 *const                *map;
++      const struct ocelot_stat_layout *stats_layout;
++      unsigned int                    num_stats;
++
++      int                             shared_queue_sz;
++
++      struct net_device               *hw_bridge_dev;
++      u16                             bridge_mask;
++      u16                             bridge_fwd_mask;
++
++      struct ocelot_port              **ports;
++
++      u8                              base_mac[ETH_ALEN];
++
++      /* Keep track of the vlan port masks */
++      u32                             vlan_mask[VLAN_N_VID];
++
++      u8                              num_phys_ports;
++      u8                              num_cpu_ports;
++      u8                              cpu;
++
++      u32                             *lags;
++
++      struct list_head                multicast;
++
++      /* Workqueue to check statistics for overflow with its lock */
++      struct mutex                    stats_lock;
++      u64                             *stats;
++      struct delayed_work             stats_work;
++      struct workqueue_struct         *stats_queue;
++
++      u8                              ptp:1;
++      struct ptp_clock                *ptp_clock;
++      struct ptp_clock_info           ptp_info;
++      struct hwtstamp_config          hwtstamp_config;
++      /* Protects the PTP interface state */
++      struct mutex                    ptp_lock;
++      /* Protects the PTP clock */
++      spinlock_t                      ptp_clock_lock;
++
++      void (*port_pcs_init)(struct ocelot_port *port);
++};
++
++#define ocelot_read_ix(ocelot, reg, gi, ri) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
++#define ocelot_read_gix(ocelot, reg, gi) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi))
++#define ocelot_read_rix(ocelot, reg, ri) __ocelot_read_ix(ocelot, reg, reg##_RSZ * (ri))
++#define ocelot_read(ocelot, reg) __ocelot_read_ix(ocelot, reg, 0)
++
++#define ocelot_write_ix(ocelot, val, reg, gi, ri) __ocelot_write_ix(ocelot, val, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
++#define ocelot_write_gix(ocelot, val, reg, gi) __ocelot_write_ix(ocelot, val, reg, reg##_GSZ * (gi))
++#define ocelot_write_rix(ocelot, val, reg, ri) __ocelot_write_ix(ocelot, val, reg, reg##_RSZ * (ri))
++#define ocelot_write(ocelot, val, reg) __ocelot_write_ix(ocelot, val, reg, 0)
++
++#define ocelot_rmw_ix(ocelot, val, m, reg, gi, ri) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
++#define ocelot_rmw_gix(ocelot, val, m, reg, gi) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_GSZ * (gi))
++#define ocelot_rmw_rix(ocelot, val, m, reg, ri) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_RSZ * (ri))
++#define ocelot_rmw(ocelot, val, m, reg) __ocelot_rmw_ix(ocelot, val, m, reg, 0)
++
++/* I/O */
++u32 ocelot_port_readl(struct ocelot_port *port, u32 reg);
++void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg);
++u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset);
++void __ocelot_write_ix(struct ocelot *ocelot, u32 val, u32 reg, u32 offset);
++void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask, u32 reg,
++                   u32 offset);
++
++/* Hardware initialization */
++int ocelot_regfields_init(struct ocelot *ocelot,
++                        const struct reg_field *const regfields);
++struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res);
++void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu,
++                       enum ocelot_tag_prefix injection,
++                       enum ocelot_tag_prefix extraction);
++int ocelot_init(struct ocelot *ocelot);
++void ocelot_deinit(struct ocelot *ocelot);
++void ocelot_init_port(struct ocelot *ocelot, int port);
++
++/* DSA callbacks */
++void ocelot_port_enable(struct ocelot *ocelot, int port,
++                      struct phy_device *phy);
++void ocelot_port_disable(struct ocelot *ocelot, int port);
++void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data);
++void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data);
++int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset);
++int ocelot_get_ts_info(struct ocelot *ocelot, int port,
++                     struct ethtool_ts_info *info);
++void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs);
++void ocelot_adjust_link(struct ocelot *ocelot, int port,
++                      struct phy_device *phydev);
++void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
++                              bool vlan_aware);
++void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state);
++int ocelot_port_bridge_join(struct ocelot *ocelot, int port,
++                          struct net_device *bridge);
++int ocelot_port_bridge_leave(struct ocelot *ocelot, int port,
++                           struct net_device *bridge);
++int ocelot_fdb_dump(struct ocelot *ocelot, int port,
++                  dsa_fdb_dump_cb_t *cb, void *data);
++int ocelot_fdb_add(struct ocelot *ocelot, int port,
++                 const unsigned char *addr, u16 vid, bool vlan_aware);
++int ocelot_fdb_del(struct ocelot *ocelot, int port,
++                 const unsigned char *addr, u16 vid);
++int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
++                  bool untagged);
++int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid);
++int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts);
++void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts);
++
++#endif
diff --git a/target/linux/layerscape/patches-5.4/701-net-0261-net-mscc-ocelot-publish-ocelot_sys.h-to-include-soc-.patch b/target/linux/layerscape/patches-5.4/701-net-0261-net-mscc-ocelot-publish-ocelot_sys.h-to-include-soc-.patch
new file mode 100644 (file)
index 0000000..0f4ca77
--- /dev/null
@@ -0,0 +1,344 @@
+From 53069d6527fc1d2709d559206cdbf0d7357954b7 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Thu, 14 Nov 2019 17:03:28 +0200
+Subject: [PATCH] net: mscc: ocelot: publish ocelot_sys.h to include/soc/mscc
+
+The Felix DSA driver needs to write to SYS_RAM_INIT_RAM_INIT for its own
+chip initialization process.
+
+Also update the MAINTAINERS file such that the headers exported by the
+ocelot driver are under the same maintainers' umbrella as the driver
+itself.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ MAINTAINERS                            |   1 +
+ drivers/net/ethernet/mscc/ocelot.h     |   2 +-
+ drivers/net/ethernet/mscc/ocelot_sys.h | 144 ---------------------------------
+ include/soc/mscc/ocelot_sys.h          | 144 +++++++++++++++++++++++++++++++++
+ 4 files changed, 146 insertions(+), 145 deletions(-)
+ delete mode 100644 drivers/net/ethernet/mscc/ocelot_sys.h
+ create mode 100644 include/soc/mscc/ocelot_sys.h
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -10824,6 +10824,7 @@ M:     Microchip Linux Driver Support <UNGLi
+ L:    netdev@vger.kernel.org
+ S:    Supported
+ F:    drivers/net/ethernet/mscc/
++F:    include/soc/mscc/ocelot*
+ MICROSOFT SURFACE PRO 3 BUTTON DRIVER
+ M:    Chen Yu <yu.c.chen@intel.com>
+--- a/drivers/net/ethernet/mscc/ocelot.h
++++ b/drivers/net/ethernet/mscc/ocelot.h
+@@ -18,12 +18,12 @@
+ #include <linux/ptp_clock_kernel.h>
+ #include <linux/regmap.h>
++#include <soc/mscc/ocelot_sys.h>
+ #include <soc/mscc/ocelot.h>
+ #include "ocelot_ana.h"
+ #include "ocelot_dev.h"
+ #include "ocelot_qsys.h"
+ #include "ocelot_rew.h"
+-#include "ocelot_sys.h"
+ #include "ocelot_qs.h"
+ #include "ocelot_tc.h"
+ #include "ocelot_ptp.h"
+--- a/drivers/net/ethernet/mscc/ocelot_sys.h
++++ /dev/null
+@@ -1,144 +0,0 @@
+-/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+-/*
+- * Microsemi Ocelot Switch driver
+- *
+- * Copyright (c) 2017 Microsemi Corporation
+- */
+-
+-#ifndef _MSCC_OCELOT_SYS_H_
+-#define _MSCC_OCELOT_SYS_H_
+-
+-#define SYS_COUNT_RX_OCTETS_RSZ                           0x4
+-
+-#define SYS_COUNT_TX_OCTETS_RSZ                           0x4
+-
+-#define SYS_PORT_MODE_RSZ                                 0x4
+-
+-#define SYS_PORT_MODE_DATA_WO_TS(x)                       (((x) << 5) & GENMASK(6, 5))
+-#define SYS_PORT_MODE_DATA_WO_TS_M                        GENMASK(6, 5)
+-#define SYS_PORT_MODE_DATA_WO_TS_X(x)                     (((x) & GENMASK(6, 5)) >> 5)
+-#define SYS_PORT_MODE_INCL_INJ_HDR(x)                     (((x) << 3) & GENMASK(4, 3))
+-#define SYS_PORT_MODE_INCL_INJ_HDR_M                      GENMASK(4, 3)
+-#define SYS_PORT_MODE_INCL_INJ_HDR_X(x)                   (((x) & GENMASK(4, 3)) >> 3)
+-#define SYS_PORT_MODE_INCL_XTR_HDR(x)                     (((x) << 1) & GENMASK(2, 1))
+-#define SYS_PORT_MODE_INCL_XTR_HDR_M                      GENMASK(2, 1)
+-#define SYS_PORT_MODE_INCL_XTR_HDR_X(x)                   (((x) & GENMASK(2, 1)) >> 1)
+-#define SYS_PORT_MODE_INJ_HDR_ERR                         BIT(0)
+-
+-#define SYS_FRONT_PORT_MODE_RSZ                           0x4
+-
+-#define SYS_FRONT_PORT_MODE_HDX_MODE                      BIT(0)
+-
+-#define SYS_FRM_AGING_AGE_TX_ENA                          BIT(20)
+-#define SYS_FRM_AGING_MAX_AGE(x)                          ((x) & GENMASK(19, 0))
+-#define SYS_FRM_AGING_MAX_AGE_M                           GENMASK(19, 0)
+-
+-#define SYS_STAT_CFG_STAT_CLEAR_SHOT(x)                   (((x) << 10) & GENMASK(16, 10))
+-#define SYS_STAT_CFG_STAT_CLEAR_SHOT_M                    GENMASK(16, 10)
+-#define SYS_STAT_CFG_STAT_CLEAR_SHOT_X(x)                 (((x) & GENMASK(16, 10)) >> 10)
+-#define SYS_STAT_CFG_STAT_VIEW(x)                         ((x) & GENMASK(9, 0))
+-#define SYS_STAT_CFG_STAT_VIEW_M                          GENMASK(9, 0)
+-
+-#define SYS_SW_STATUS_RSZ                                 0x4
+-
+-#define SYS_SW_STATUS_PORT_RX_PAUSED                      BIT(0)
+-
+-#define SYS_MISC_CFG_PTP_RSRV_CLR                         BIT(1)
+-#define SYS_MISC_CFG_PTP_DIS_NEG_RO                       BIT(0)
+-
+-#define SYS_REW_MAC_HIGH_CFG_RSZ                          0x4
+-
+-#define SYS_REW_MAC_LOW_CFG_RSZ                           0x4
+-
+-#define SYS_TIMESTAMP_OFFSET_ETH_TYPE_CFG(x)              (((x) << 6) & GENMASK(21, 6))
+-#define SYS_TIMESTAMP_OFFSET_ETH_TYPE_CFG_M               GENMASK(21, 6)
+-#define SYS_TIMESTAMP_OFFSET_ETH_TYPE_CFG_X(x)            (((x) & GENMASK(21, 6)) >> 6)
+-#define SYS_TIMESTAMP_OFFSET_TIMESTAMP_OFFSET(x)          ((x) & GENMASK(5, 0))
+-#define SYS_TIMESTAMP_OFFSET_TIMESTAMP_OFFSET_M           GENMASK(5, 0)
+-
+-#define SYS_PAUSE_CFG_RSZ                                 0x4
+-
+-#define SYS_PAUSE_CFG_PAUSE_START(x)                      (((x) << 10) & GENMASK(18, 10))
+-#define SYS_PAUSE_CFG_PAUSE_START_M                       GENMASK(18, 10)
+-#define SYS_PAUSE_CFG_PAUSE_START_X(x)                    (((x) & GENMASK(18, 10)) >> 10)
+-#define SYS_PAUSE_CFG_PAUSE_STOP(x)                       (((x) << 1) & GENMASK(9, 1))
+-#define SYS_PAUSE_CFG_PAUSE_STOP_M                        GENMASK(9, 1)
+-#define SYS_PAUSE_CFG_PAUSE_STOP_X(x)                     (((x) & GENMASK(9, 1)) >> 1)
+-#define SYS_PAUSE_CFG_PAUSE_ENA                           BIT(0)
+-
+-#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START(x)              (((x) << 9) & GENMASK(17, 9))
+-#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START_M               GENMASK(17, 9)
+-#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START_X(x)            (((x) & GENMASK(17, 9)) >> 9)
+-#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_STOP(x)               ((x) & GENMASK(8, 0))
+-#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_STOP_M                GENMASK(8, 0)
+-
+-#define SYS_ATOP_RSZ                                      0x4
+-
+-#define SYS_MAC_FC_CFG_RSZ                                0x4
+-
+-#define SYS_MAC_FC_CFG_FC_LINK_SPEED(x)                   (((x) << 26) & GENMASK(27, 26))
+-#define SYS_MAC_FC_CFG_FC_LINK_SPEED_M                    GENMASK(27, 26)
+-#define SYS_MAC_FC_CFG_FC_LINK_SPEED_X(x)                 (((x) & GENMASK(27, 26)) >> 26)
+-#define SYS_MAC_FC_CFG_FC_LATENCY_CFG(x)                  (((x) << 20) & GENMASK(25, 20))
+-#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_M                   GENMASK(25, 20)
+-#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_X(x)                (((x) & GENMASK(25, 20)) >> 20)
+-#define SYS_MAC_FC_CFG_ZERO_PAUSE_ENA                     BIT(18)
+-#define SYS_MAC_FC_CFG_TX_FC_ENA                          BIT(17)
+-#define SYS_MAC_FC_CFG_RX_FC_ENA                          BIT(16)
+-#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG(x)                   ((x) & GENMASK(15, 0))
+-#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG_M                    GENMASK(15, 0)
+-
+-#define SYS_MMGT_RELCNT(x)                                (((x) << 16) & GENMASK(31, 16))
+-#define SYS_MMGT_RELCNT_M                                 GENMASK(31, 16)
+-#define SYS_MMGT_RELCNT_X(x)                              (((x) & GENMASK(31, 16)) >> 16)
+-#define SYS_MMGT_FREECNT(x)                               ((x) & GENMASK(15, 0))
+-#define SYS_MMGT_FREECNT_M                                GENMASK(15, 0)
+-
+-#define SYS_MMGT_FAST_FREEVLD(x)                          (((x) << 4) & GENMASK(7, 4))
+-#define SYS_MMGT_FAST_FREEVLD_M                           GENMASK(7, 4)
+-#define SYS_MMGT_FAST_FREEVLD_X(x)                        (((x) & GENMASK(7, 4)) >> 4)
+-#define SYS_MMGT_FAST_RELVLD(x)                           ((x) & GENMASK(3, 0))
+-#define SYS_MMGT_FAST_RELVLD_M                            GENMASK(3, 0)
+-
+-#define SYS_EVENTS_DIF_RSZ                                0x4
+-
+-#define SYS_EVENTS_DIF_EV_DRX(x)                          (((x) << 6) & GENMASK(8, 6))
+-#define SYS_EVENTS_DIF_EV_DRX_M                           GENMASK(8, 6)
+-#define SYS_EVENTS_DIF_EV_DRX_X(x)                        (((x) & GENMASK(8, 6)) >> 6)
+-#define SYS_EVENTS_DIF_EV_DTX(x)                          ((x) & GENMASK(5, 0))
+-#define SYS_EVENTS_DIF_EV_DTX_M                           GENMASK(5, 0)
+-
+-#define SYS_EVENTS_CORE_EV_FWR                            BIT(2)
+-#define SYS_EVENTS_CORE_EV_ANA(x)                         ((x) & GENMASK(1, 0))
+-#define SYS_EVENTS_CORE_EV_ANA_M                          GENMASK(1, 0)
+-
+-#define SYS_CNT_GSZ                                       0x4
+-
+-#define SYS_PTP_STATUS_PTP_TXSTAMP_OAM                    BIT(29)
+-#define SYS_PTP_STATUS_PTP_OVFL                           BIT(28)
+-#define SYS_PTP_STATUS_PTP_MESS_VLD                       BIT(27)
+-#define SYS_PTP_STATUS_PTP_MESS_ID(x)                     (((x) << 21) & GENMASK(26, 21))
+-#define SYS_PTP_STATUS_PTP_MESS_ID_M                      GENMASK(26, 21)
+-#define SYS_PTP_STATUS_PTP_MESS_ID_X(x)                   (((x) & GENMASK(26, 21)) >> 21)
+-#define SYS_PTP_STATUS_PTP_MESS_TXPORT(x)                 (((x) << 16) & GENMASK(20, 16))
+-#define SYS_PTP_STATUS_PTP_MESS_TXPORT_M                  GENMASK(20, 16)
+-#define SYS_PTP_STATUS_PTP_MESS_TXPORT_X(x)               (((x) & GENMASK(20, 16)) >> 16)
+-#define SYS_PTP_STATUS_PTP_MESS_SEQ_ID(x)                 ((x) & GENMASK(15, 0))
+-#define SYS_PTP_STATUS_PTP_MESS_SEQ_ID_M                  GENMASK(15, 0)
+-
+-#define SYS_PTP_TXSTAMP_PTP_TXSTAMP(x)                    ((x) & GENMASK(29, 0))
+-#define SYS_PTP_TXSTAMP_PTP_TXSTAMP_M                     GENMASK(29, 0)
+-#define SYS_PTP_TXSTAMP_PTP_TXSTAMP_SEC                   BIT(31)
+-
+-#define SYS_PTP_NXT_PTP_NXT                               BIT(0)
+-
+-#define SYS_PTP_CFG_PTP_STAMP_WID(x)                      (((x) << 2) & GENMASK(7, 2))
+-#define SYS_PTP_CFG_PTP_STAMP_WID_M                       GENMASK(7, 2)
+-#define SYS_PTP_CFG_PTP_STAMP_WID_X(x)                    (((x) & GENMASK(7, 2)) >> 2)
+-#define SYS_PTP_CFG_PTP_CF_ROLL_MODE(x)                   ((x) & GENMASK(1, 0))
+-#define SYS_PTP_CFG_PTP_CF_ROLL_MODE_M                    GENMASK(1, 0)
+-
+-#define SYS_RAM_INIT_RAM_INIT                             BIT(1)
+-#define SYS_RAM_INIT_RAM_CFG_HOOK                         BIT(0)
+-
+-#endif
+--- /dev/null
++++ b/include/soc/mscc/ocelot_sys.h
+@@ -0,0 +1,144 @@
++/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
++/*
++ * Microsemi Ocelot Switch driver
++ *
++ * Copyright (c) 2017 Microsemi Corporation
++ */
++
++#ifndef _MSCC_OCELOT_SYS_H_
++#define _MSCC_OCELOT_SYS_H_
++
++#define SYS_COUNT_RX_OCTETS_RSZ                           0x4
++
++#define SYS_COUNT_TX_OCTETS_RSZ                           0x4
++
++#define SYS_PORT_MODE_RSZ                                 0x4
++
++#define SYS_PORT_MODE_DATA_WO_TS(x)                       (((x) << 5) & GENMASK(6, 5))
++#define SYS_PORT_MODE_DATA_WO_TS_M                        GENMASK(6, 5)
++#define SYS_PORT_MODE_DATA_WO_TS_X(x)                     (((x) & GENMASK(6, 5)) >> 5)
++#define SYS_PORT_MODE_INCL_INJ_HDR(x)                     (((x) << 3) & GENMASK(4, 3))
++#define SYS_PORT_MODE_INCL_INJ_HDR_M                      GENMASK(4, 3)
++#define SYS_PORT_MODE_INCL_INJ_HDR_X(x)                   (((x) & GENMASK(4, 3)) >> 3)
++#define SYS_PORT_MODE_INCL_XTR_HDR(x)                     (((x) << 1) & GENMASK(2, 1))
++#define SYS_PORT_MODE_INCL_XTR_HDR_M                      GENMASK(2, 1)
++#define SYS_PORT_MODE_INCL_XTR_HDR_X(x)                   (((x) & GENMASK(2, 1)) >> 1)
++#define SYS_PORT_MODE_INJ_HDR_ERR                         BIT(0)
++
++#define SYS_FRONT_PORT_MODE_RSZ                           0x4
++
++#define SYS_FRONT_PORT_MODE_HDX_MODE                      BIT(0)
++
++#define SYS_FRM_AGING_AGE_TX_ENA                          BIT(20)
++#define SYS_FRM_AGING_MAX_AGE(x)                          ((x) & GENMASK(19, 0))
++#define SYS_FRM_AGING_MAX_AGE_M                           GENMASK(19, 0)
++
++#define SYS_STAT_CFG_STAT_CLEAR_SHOT(x)                   (((x) << 10) & GENMASK(16, 10))
++#define SYS_STAT_CFG_STAT_CLEAR_SHOT_M                    GENMASK(16, 10)
++#define SYS_STAT_CFG_STAT_CLEAR_SHOT_X(x)                 (((x) & GENMASK(16, 10)) >> 10)
++#define SYS_STAT_CFG_STAT_VIEW(x)                         ((x) & GENMASK(9, 0))
++#define SYS_STAT_CFG_STAT_VIEW_M                          GENMASK(9, 0)
++
++#define SYS_SW_STATUS_RSZ                                 0x4
++
++#define SYS_SW_STATUS_PORT_RX_PAUSED                      BIT(0)
++
++#define SYS_MISC_CFG_PTP_RSRV_CLR                         BIT(1)
++#define SYS_MISC_CFG_PTP_DIS_NEG_RO                       BIT(0)
++
++#define SYS_REW_MAC_HIGH_CFG_RSZ                          0x4
++
++#define SYS_REW_MAC_LOW_CFG_RSZ                           0x4
++
++#define SYS_TIMESTAMP_OFFSET_ETH_TYPE_CFG(x)              (((x) << 6) & GENMASK(21, 6))
++#define SYS_TIMESTAMP_OFFSET_ETH_TYPE_CFG_M               GENMASK(21, 6)
++#define SYS_TIMESTAMP_OFFSET_ETH_TYPE_CFG_X(x)            (((x) & GENMASK(21, 6)) >> 6)
++#define SYS_TIMESTAMP_OFFSET_TIMESTAMP_OFFSET(x)          ((x) & GENMASK(5, 0))
++#define SYS_TIMESTAMP_OFFSET_TIMESTAMP_OFFSET_M           GENMASK(5, 0)
++
++#define SYS_PAUSE_CFG_RSZ                                 0x4
++
++#define SYS_PAUSE_CFG_PAUSE_START(x)                      (((x) << 10) & GENMASK(18, 10))
++#define SYS_PAUSE_CFG_PAUSE_START_M                       GENMASK(18, 10)
++#define SYS_PAUSE_CFG_PAUSE_START_X(x)                    (((x) & GENMASK(18, 10)) >> 10)
++#define SYS_PAUSE_CFG_PAUSE_STOP(x)                       (((x) << 1) & GENMASK(9, 1))
++#define SYS_PAUSE_CFG_PAUSE_STOP_M                        GENMASK(9, 1)
++#define SYS_PAUSE_CFG_PAUSE_STOP_X(x)                     (((x) & GENMASK(9, 1)) >> 1)
++#define SYS_PAUSE_CFG_PAUSE_ENA                           BIT(0)
++
++#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START(x)              (((x) << 9) & GENMASK(17, 9))
++#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START_M               GENMASK(17, 9)
++#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START_X(x)            (((x) & GENMASK(17, 9)) >> 9)
++#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_STOP(x)               ((x) & GENMASK(8, 0))
++#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_STOP_M                GENMASK(8, 0)
++
++#define SYS_ATOP_RSZ                                      0x4
++
++#define SYS_MAC_FC_CFG_RSZ                                0x4
++
++#define SYS_MAC_FC_CFG_FC_LINK_SPEED(x)                   (((x) << 26) & GENMASK(27, 26))
++#define SYS_MAC_FC_CFG_FC_LINK_SPEED_M                    GENMASK(27, 26)
++#define SYS_MAC_FC_CFG_FC_LINK_SPEED_X(x)                 (((x) & GENMASK(27, 26)) >> 26)
++#define SYS_MAC_FC_CFG_FC_LATENCY_CFG(x)                  (((x) << 20) & GENMASK(25, 20))
++#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_M                   GENMASK(25, 20)
++#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_X(x)                (((x) & GENMASK(25, 20)) >> 20)
++#define SYS_MAC_FC_CFG_ZERO_PAUSE_ENA                     BIT(18)
++#define SYS_MAC_FC_CFG_TX_FC_ENA                          BIT(17)
++#define SYS_MAC_FC_CFG_RX_FC_ENA                          BIT(16)
++#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG(x)                   ((x) & GENMASK(15, 0))
++#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG_M                    GENMASK(15, 0)
++
++#define SYS_MMGT_RELCNT(x)                                (((x) << 16) & GENMASK(31, 16))
++#define SYS_MMGT_RELCNT_M                                 GENMASK(31, 16)
++#define SYS_MMGT_RELCNT_X(x)                              (((x) & GENMASK(31, 16)) >> 16)
++#define SYS_MMGT_FREECNT(x)                               ((x) & GENMASK(15, 0))
++#define SYS_MMGT_FREECNT_M                                GENMASK(15, 0)
++
++#define SYS_MMGT_FAST_FREEVLD(x)                          (((x) << 4) & GENMASK(7, 4))
++#define SYS_MMGT_FAST_FREEVLD_M                           GENMASK(7, 4)
++#define SYS_MMGT_FAST_FREEVLD_X(x)                        (((x) & GENMASK(7, 4)) >> 4)
++#define SYS_MMGT_FAST_RELVLD(x)                           ((x) & GENMASK(3, 0))
++#define SYS_MMGT_FAST_RELVLD_M                            GENMASK(3, 0)
++
++#define SYS_EVENTS_DIF_RSZ                                0x4
++
++#define SYS_EVENTS_DIF_EV_DRX(x)                          (((x) << 6) & GENMASK(8, 6))
++#define SYS_EVENTS_DIF_EV_DRX_M                           GENMASK(8, 6)
++#define SYS_EVENTS_DIF_EV_DRX_X(x)                        (((x) & GENMASK(8, 6)) >> 6)
++#define SYS_EVENTS_DIF_EV_DTX(x)                          ((x) & GENMASK(5, 0))
++#define SYS_EVENTS_DIF_EV_DTX_M                           GENMASK(5, 0)
++
++#define SYS_EVENTS_CORE_EV_FWR                            BIT(2)
++#define SYS_EVENTS_CORE_EV_ANA(x)                         ((x) & GENMASK(1, 0))
++#define SYS_EVENTS_CORE_EV_ANA_M                          GENMASK(1, 0)
++
++#define SYS_CNT_GSZ                                       0x4
++
++#define SYS_PTP_STATUS_PTP_TXSTAMP_OAM                    BIT(29)
++#define SYS_PTP_STATUS_PTP_OVFL                           BIT(28)
++#define SYS_PTP_STATUS_PTP_MESS_VLD                       BIT(27)
++#define SYS_PTP_STATUS_PTP_MESS_ID(x)                     (((x) << 21) & GENMASK(26, 21))
++#define SYS_PTP_STATUS_PTP_MESS_ID_M                      GENMASK(26, 21)
++#define SYS_PTP_STATUS_PTP_MESS_ID_X(x)                   (((x) & GENMASK(26, 21)) >> 21)
++#define SYS_PTP_STATUS_PTP_MESS_TXPORT(x)                 (((x) << 16) & GENMASK(20, 16))
++#define SYS_PTP_STATUS_PTP_MESS_TXPORT_M                  GENMASK(20, 16)
++#define SYS_PTP_STATUS_PTP_MESS_TXPORT_X(x)               (((x) & GENMASK(20, 16)) >> 16)
++#define SYS_PTP_STATUS_PTP_MESS_SEQ_ID(x)                 ((x) & GENMASK(15, 0))
++#define SYS_PTP_STATUS_PTP_MESS_SEQ_ID_M                  GENMASK(15, 0)
++
++#define SYS_PTP_TXSTAMP_PTP_TXSTAMP(x)                    ((x) & GENMASK(29, 0))
++#define SYS_PTP_TXSTAMP_PTP_TXSTAMP_M                     GENMASK(29, 0)
++#define SYS_PTP_TXSTAMP_PTP_TXSTAMP_SEC                   BIT(31)
++
++#define SYS_PTP_NXT_PTP_NXT                               BIT(0)
++
++#define SYS_PTP_CFG_PTP_STAMP_WID(x)                      (((x) << 2) & GENMASK(7, 2))
++#define SYS_PTP_CFG_PTP_STAMP_WID_M                       GENMASK(7, 2)
++#define SYS_PTP_CFG_PTP_STAMP_WID_X(x)                    (((x) & GENMASK(7, 2)) >> 2)
++#define SYS_PTP_CFG_PTP_CF_ROLL_MODE(x)                   ((x) & GENMASK(1, 0))
++#define SYS_PTP_CFG_PTP_CF_ROLL_MODE_M                    GENMASK(1, 0)
++
++#define SYS_RAM_INIT_RAM_INIT                             BIT(1)
++#define SYS_RAM_INIT_RAM_CFG_HOOK                         BIT(0)
++
++#endif
diff --git a/target/linux/layerscape/patches-5.4/701-net-0262-net-dsa-ocelot-add-tagger-for-Ocelot-Felix-switches.patch b/target/linux/layerscape/patches-5.4/701-net-0262-net-dsa-ocelot-add-tagger-for-Ocelot-Felix-switches.patch
new file mode 100644 (file)
index 0000000..f268500
--- /dev/null
@@ -0,0 +1,331 @@
+From 0254efd8d7e8f533b57bdf8665991fd5548c65a8 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Thu, 14 Nov 2019 17:03:29 +0200
+Subject: [PATCH] net: dsa: ocelot: add tagger for Ocelot/Felix switches
+
+While it is entirely possible that this tagger format is in fact more
+generic than just these 2 switch families, I don't have that knowledge.
+The Seville switch in NXP T1040 has a similar frame format, but there
+are enough differences (e.g. DEST field starts at bit 57 instead of 56)
+that calling this file tag_vitesse.c is a bit of a stretch at the
+moment. The frame format has been listed in a comment so that people who
+add support for further Vitesse switches can rework this tagger while
+keeping compatibility with Felix.
+
+The "ocelot" name was chosen instead of "felix" because even the Ocelot
+switch can act as a DSA device when it is used in NPI mode, and the Felix
+tagger format is almost identical. Currently it is only used for the
+Felix switch embedded in the NXP LS1028A chip.
+
+The ABI for this tagger should be considered "not stable" at the moment.
+The DSA tag is always placed before the Ethernet header and therefore,
+we are using the long prefix for RX tags to avoid putting the DSA master
+port in promiscuous mode. Once there will be an API in DSA for drivers
+to request DSA masters to be in promiscuous mode unconditionally, we
+will switch to the "no prefix" extraction frame header, which will save
+16 padding bytes for each RX frame.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ MAINTAINERS          |   7 ++
+ include/net/dsa.h    |   2 +
+ net/dsa/Kconfig      |   7 ++
+ net/dsa/Makefile     |   1 +
+ net/dsa/tag_ocelot.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 246 insertions(+)
+ create mode 100644 net/dsa/tag_ocelot.c
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -17354,6 +17354,13 @@ S:    Maintained
+ F:    drivers/input/serio/userio.c
+ F:    include/uapi/linux/userio.h
++VITESSE FELIX ETHERNET SWITCH DRIVER
++M:    Vladimir Oltean <vladimir.oltean@nxp.com>
++M:    Claudiu Manoil <claudiu.manoil@nxp.com>
++L:    netdev@vger.kernel.org
++S:    Maintained
++F:    net/dsa/tag_ocelot.c
++
+ VIVID VIRTUAL VIDEO DRIVER
+ M:    Hans Verkuil <hverkuil@xs4all.nl>
+ L:    linux-media@vger.kernel.org
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -42,6 +42,7 @@ struct phylink_link_state;
+ #define DSA_TAG_PROTO_8021Q_VALUE             12
+ #define DSA_TAG_PROTO_SJA1105_VALUE           13
+ #define DSA_TAG_PROTO_KSZ8795_VALUE           14
++#define DSA_TAG_PROTO_OCELOT_VALUE            15
+ enum dsa_tag_protocol {
+       DSA_TAG_PROTO_NONE              = DSA_TAG_PROTO_NONE_VALUE,
+@@ -59,6 +60,7 @@ enum dsa_tag_protocol {
+       DSA_TAG_PROTO_8021Q             = DSA_TAG_PROTO_8021Q_VALUE,
+       DSA_TAG_PROTO_SJA1105           = DSA_TAG_PROTO_SJA1105_VALUE,
+       DSA_TAG_PROTO_KSZ8795           = DSA_TAG_PROTO_KSZ8795_VALUE,
++      DSA_TAG_PROTO_OCELOT            = DSA_TAG_PROTO_OCELOT_VALUE,
+ };
+ struct packet_type;
+--- a/net/dsa/Kconfig
++++ b/net/dsa/Kconfig
+@@ -79,6 +79,13 @@ config NET_DSA_TAG_KSZ
+         Say Y if you want to enable support for tagging frames for the
+         Microchip 8795/9477/9893 families of switches.
++config NET_DSA_TAG_OCELOT
++      tristate "Tag driver for Ocelot family of switches"
++      select PACKING
++      help
++        Say Y or M if you want to enable support for tagging frames for the
++        Ocelot switches (VSC7511, VSC7512, VSC7513, VSC7514, VSC9959).
++
+ config NET_DSA_TAG_QCA
+       tristate "Tag driver for Qualcomm Atheros QCA8K switches"
+       help
+--- a/net/dsa/Makefile
++++ b/net/dsa/Makefile
+@@ -12,6 +12,7 @@ obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_g
+ obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
+ obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
+ obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
++obj-$(CONFIG_NET_DSA_TAG_OCELOT) += tag_ocelot.o
+ obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
+ obj-$(CONFIG_NET_DSA_TAG_SJA1105) += tag_sja1105.o
+ obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
+--- /dev/null
++++ b/net/dsa/tag_ocelot.c
+@@ -0,0 +1,229 @@
++// SPDX-License-Identifier: GPL-2.0
++/* Copyright 2019 NXP Semiconductors
++ */
++#include <soc/mscc/ocelot.h>
++#include <linux/packing.h>
++#include "dsa_priv.h"
++
++/* The CPU injection header and the CPU extraction header can have 3 types of
++ * prefixes: long, short and no prefix. The format of the header itself is the
++ * same in all 3 cases.
++ *
++ * Extraction with long prefix:
++ *
++ * +-------------------+-------------------+------+------+------------+-------+
++ * | ff:ff:ff:ff:ff:ff | ff:ff:ff:ff:ff:ff | 8880 | 000a | extraction | frame |
++ * |                   |                   |      |      |   header   |       |
++ * +-------------------+-------------------+------+------+------------+-------+
++ *        48 bits             48 bits      16 bits 16 bits  128 bits
++ *
++ * Extraction with short prefix:
++ *
++ *                                         +------+------+------------+-------+
++ *                                         | 8880 | 000a | extraction | frame |
++ *                                         |      |      |   header   |       |
++ *                                         +------+------+------------+-------+
++ *                                         16 bits 16 bits  128 bits
++ *
++ * Extraction with no prefix:
++ *
++ *                                                       +------------+-------+
++ *                                                       | extraction | frame |
++ *                                                       |   header   |       |
++ *                                                       +------------+-------+
++ *                                                          128 bits
++ *
++ *
++ * Injection with long prefix:
++ *
++ * +-------------------+-------------------+------+------+------------+-------+
++ * |      any dmac     |      any smac     | 8880 | 000a | injection  | frame |
++ * |                   |                   |      |      |   header   |       |
++ * +-------------------+-------------------+------+------+------------+-------+
++ *        48 bits             48 bits      16 bits 16 bits  128 bits
++ *
++ * Injection with short prefix:
++ *
++ *                                         +------+------+------------+-------+
++ *                                         | 8880 | 000a | injection  | frame |
++ *                                         |      |      |   header   |       |
++ *                                         +------+------+------------+-------+
++ *                                         16 bits 16 bits  128 bits
++ *
++ * Injection with no prefix:
++ *
++ *                                                       +------------+-------+
++ *                                                       | injection  | frame |
++ *                                                       |   header   |       |
++ *                                                       +------------+-------+
++ *                                                          128 bits
++ *
++ * The injection header looks like this (network byte order, bit 127
++ * is part of lowest address byte in memory, bit 0 is part of highest
++ * address byte):
++ *
++ *         +------+------+------+------+------+------+------+------+
++ * 127:120 |BYPASS| MASQ |          MASQ_PORT        |REW_OP|REW_OP|
++ *         +------+------+------+------+------+------+------+------+
++ * 119:112 |                         REW_OP                        |
++ *         +------+------+------+------+------+------+------+------+
++ * 111:104 |                         REW_VAL                       |
++ *         +------+------+------+------+------+------+------+------+
++ * 103: 96 |                         REW_VAL                       |
++ *         +------+------+------+------+------+------+------+------+
++ *  95: 88 |                         REW_VAL                       |
++ *         +------+------+------+------+------+------+------+------+
++ *  87: 80 |                         REW_VAL                       |
++ *         +------+------+------+------+------+------+------+------+
++ *  79: 72 |                          RSV                          |
++ *         +------+------+------+------+------+------+------+------+
++ *  71: 64 |            RSV            |           DEST            |
++ *         +------+------+------+------+------+------+------+------+
++ *  63: 56 |                         DEST                          |
++ *         +------+------+------+------+------+------+------+------+
++ *  55: 48 |                          RSV                          |
++ *         +------+------+------+------+------+------+------+------+
++ *  47: 40 |  RSV |         SRC_PORT          |     RSV     |TFRM_TIMER|
++ *         +------+------+------+------+------+------+------+------+
++ *  39: 32 |     TFRM_TIMER     |               RSV                |
++ *         +------+------+------+------+------+------+------+------+
++ *  31: 24 |  RSV |  DP  |   POP_CNT   |           CPUQ            |
++ *         +------+------+------+------+------+------+------+------+
++ *  23: 16 |           CPUQ            |      QOS_CLASS     |TAG_TYPE|
++ *         +------+------+------+------+------+------+------+------+
++ *  15:  8 |         PCP        |  DEI |            VID            |
++ *         +------+------+------+------+------+------+------+------+
++ *   7:  0 |                          VID                          |
++ *         +------+------+------+------+------+------+------+------+
++ *
++ * And the extraction header looks like this:
++ *
++ *         +------+------+------+------+------+------+------+------+
++ * 127:120 |  RSV |                  REW_OP                        |
++ *         +------+------+------+------+------+------+------+------+
++ * 119:112 |       REW_OP       |              REW_VAL             |
++ *         +------+------+------+------+------+------+------+------+
++ * 111:104 |                         REW_VAL                       |
++ *         +------+------+------+------+------+------+------+------+
++ * 103: 96 |                         REW_VAL                       |
++ *         +------+------+------+------+------+------+------+------+
++ *  95: 88 |                         REW_VAL                       |
++ *         +------+------+------+------+------+------+------+------+
++ *  87: 80 |       REW_VAL      |               LLEN               |
++ *         +------+------+------+------+------+------+------+------+
++ *  79: 72 | LLEN |                      WLEN                      |
++ *         +------+------+------+------+------+------+------+------+
++ *  71: 64 | WLEN |                      RSV                       |
++ *         +------+------+------+------+------+------+------+------+
++ *  63: 56 |                          RSV                          |
++ *         +------+------+------+------+------+------+------+------+
++ *  55: 48 |                          RSV                          |
++ *         +------+------+------+------+------+------+------+------+
++ *  47: 40 | RSV  |          SRC_PORT         |       ACL_ID       |
++ *         +------+------+------+------+------+------+------+------+
++ *  39: 32 |       ACL_ID       |  RSV |         SFLOW_ID          |
++ *         +------+------+------+------+------+------+------+------+
++ *  31: 24 |ACL_HIT| DP  |  LRN_FLAGS  |           CPUQ            |
++ *         +------+------+------+------+------+------+------+------+
++ *  23: 16 |           CPUQ            |      QOS_CLASS     |TAG_TYPE|
++ *         +------+------+------+------+------+------+------+------+
++ *  15:  8 |         PCP        |  DEI |            VID            |
++ *         +------+------+------+------+------+------+------+------+
++ *   7:  0 |                          VID                          |
++ *         +------+------+------+------+------+------+------+------+
++ */
++
++static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
++                                 struct net_device *netdev)
++{
++      struct dsa_port *dp = dsa_slave_to_port(netdev);
++      u64 bypass, dest, src, qos_class;
++      struct dsa_switch *ds = dp->ds;
++      int port = dp->index;
++      u8 *injection;
++
++      if (unlikely(skb_cow_head(skb, OCELOT_TAG_LEN) < 0)) {
++              netdev_err(netdev, "Cannot make room for tag.\n");
++              return NULL;
++      }
++
++      injection = skb_push(skb, OCELOT_TAG_LEN);
++
++      memset(injection, 0, OCELOT_TAG_LEN);
++
++      src = dsa_upstream_port(ds, port);
++      dest = BIT(port);
++      bypass = true;
++      qos_class = skb->priority;
++
++      packing(injection, &bypass,   127, 127, OCELOT_TAG_LEN, PACK, 0);
++      packing(injection, &dest,      68,  56, OCELOT_TAG_LEN, PACK, 0);
++      packing(injection, &src,       46,  43, OCELOT_TAG_LEN, PACK, 0);
++      packing(injection, &qos_class, 19,  17, OCELOT_TAG_LEN, PACK, 0);
++
++      return skb;
++}
++
++static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
++                                struct net_device *netdev,
++                                struct packet_type *pt)
++{
++      u64 src_port, qos_class;
++      u8 *start = skb->data;
++      u8 *extraction;
++
++      /* Revert skb->data by the amount consumed by the DSA master,
++       * so it points to the beginning of the frame.
++       */
++      skb_push(skb, ETH_HLEN);
++      /* We don't care about the long prefix, it is just for easy entrance
++       * into the DSA master's RX filter. Discard it now by moving it into
++       * the headroom.
++       */
++      skb_pull(skb, OCELOT_LONG_PREFIX_LEN);
++      /* And skb->data now points to the extraction frame header.
++       * Keep a pointer to it.
++       */
++      extraction = skb->data;
++      /* Now the EFH is part of the headroom as well */
++      skb_pull(skb, OCELOT_TAG_LEN);
++      /* Reset the pointer to the real MAC header */
++      skb_reset_mac_header(skb);
++      skb_reset_mac_len(skb);
++      /* And move skb->data to the correct location again */
++      skb_pull(skb, ETH_HLEN);
++
++      /* Remove from inet csum the extraction header */
++      skb_postpull_rcsum(skb, start, OCELOT_LONG_PREFIX_LEN + OCELOT_TAG_LEN);
++
++      packing(extraction, &src_port,  46, 43, OCELOT_TAG_LEN, UNPACK, 0);
++      packing(extraction, &qos_class, 19, 17, OCELOT_TAG_LEN, UNPACK, 0);
++
++      skb->dev = dsa_master_find_slave(netdev, 0, src_port);
++      if (!skb->dev)
++              /* The switch will reflect back some frames sent through
++               * sockets opened on the bare DSA master. These will come back
++               * with src_port equal to the index of the CPU port, for which
++               * there is no slave registered. So don't print any error
++               * message here (ignore and drop those frames).
++               */
++              return NULL;
++
++      skb->offload_fwd_mark = 1;
++      skb->priority = qos_class;
++
++      return skb;
++}
++
++static struct dsa_device_ops ocelot_netdev_ops = {
++      .name                   = "ocelot",
++      .proto                  = DSA_TAG_PROTO_OCELOT,
++      .xmit                   = ocelot_xmit,
++      .rcv                    = ocelot_rcv,
++      .overhead               = OCELOT_TAG_LEN + OCELOT_LONG_PREFIX_LEN,
++};
++
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_OCELOT);
++
++module_dsa_tag_driver(ocelot_netdev_ops);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0263-net-dsa-ocelot-add-driver-for-Felix-switch-family.patch b/target/linux/layerscape/patches-5.4/701-net-0263-net-dsa-ocelot-add-driver-for-Felix-switch-family.patch
new file mode 100644 (file)
index 0000000..079932d
--- /dev/null
@@ -0,0 +1,1163 @@
+From 469b6adff1484015369993dbb86a2936b6517a7d Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Thu, 14 Nov 2019 17:03:30 +0200
+Subject: [PATCH] net: dsa: ocelot: add driver for Felix switch family
+
+This supports an Ethernet switching core from Vitesse / Microsemi /
+Microchip (VSC9959) which is part of the Ocelot family (a brand name),
+and whose code name is Felix. The switch can be (and is) integrated on
+different SoCs as a PCIe endpoint device.
+
+The functionality is provided by the core of the Ocelot switch driver
+(drivers/net/ethernet/mscc). In this regard, the current driver is an
+instance of Microsemi's Ocelot core driver, with a DSA front-end. It
+inherits its name from VSC9959's code name, to distinguish itself from
+the switchdev ocelot driver.
+
+The patch adds the logic for probing a PCI device and defines the
+register map for the VSC9959 switch core, since it has some differences
+in register addresses and bitfield mappings compared to the other Ocelot
+switches (VSC7511, VSC7512, VSC7513, VSC7514).
+
+The Felix driver declares the register map as part of the "instance
+table". Currently the VSC9959 inside NXP LS1028A is the only instance,
+but presumably it can support other switches in the Ocelot family, when
+used in DSA mode (Linux running on the external CPU, and not on the
+embedded MIPS).
+
+In a few cases, some h/w operations have to be done differently on
+VSC9959 due to missing bitfields.  This is the case for the switch core
+reset and init.  Because for this operation Ocelot uses some bits that
+are not present on Felix, the latter has to use a register from the
+global registers block (GCB) instead.
+
+Although it is a PCI driver, it relies on DT bindings for compatibility
+with DSA (CPU port link, PHY library). It does not have any custom
+device tree bindings, since we would like to minimize its dependency on
+device tree though.
+
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ MAINTAINERS                            |   1 +
+ drivers/net/dsa/Kconfig                |   2 +
+ drivers/net/dsa/Makefile               |   1 +
+ drivers/net/dsa/ocelot/Kconfig         |  11 +
+ drivers/net/dsa/ocelot/Makefile        |   6 +
+ drivers/net/dsa/ocelot/felix.c         | 441 +++++++++++++++++++++++++
+ drivers/net/dsa/ocelot/felix.h         |  37 +++
+ drivers/net/dsa/ocelot/felix_vsc9959.c | 567 +++++++++++++++++++++++++++++++++
+ 8 files changed, 1066 insertions(+)
+ create mode 100644 drivers/net/dsa/ocelot/Kconfig
+ create mode 100644 drivers/net/dsa/ocelot/Makefile
+ create mode 100644 drivers/net/dsa/ocelot/felix.c
+ create mode 100644 drivers/net/dsa/ocelot/felix.h
+ create mode 100644 drivers/net/dsa/ocelot/felix_vsc9959.c
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -17359,6 +17359,7 @@ M:     Vladimir Oltean <vladimir.oltean@nxp.
+ M:    Claudiu Manoil <claudiu.manoil@nxp.com>
+ L:    netdev@vger.kernel.org
+ S:    Maintained
++F:    drivers/net/dsa/ocelot/*
+ F:    net/dsa/tag_ocelot.c
+ VIVID VIRTUAL VIDEO DRIVER
+--- a/drivers/net/dsa/Kconfig
++++ b/drivers/net/dsa/Kconfig
+@@ -52,6 +52,8 @@ source "drivers/net/dsa/microchip/Kconfi
+ source "drivers/net/dsa/mv88e6xxx/Kconfig"
++source "drivers/net/dsa/ocelot/Kconfig"
++
+ source "drivers/net/dsa/sja1105/Kconfig"
+ config NET_DSA_QCA8K
+--- a/drivers/net/dsa/Makefile
++++ b/drivers/net/dsa/Makefile
+@@ -20,4 +20,5 @@ obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI
+ obj-y                         += b53/
+ obj-y                         += microchip/
+ obj-y                         += mv88e6xxx/
++obj-y                         += ocelot/
+ obj-y                         += sja1105/
+--- /dev/null
++++ b/drivers/net/dsa/ocelot/Kconfig
+@@ -0,0 +1,11 @@
++# SPDX-License-Identifier: GPL-2.0-only
++config NET_DSA_MSCC_FELIX
++      tristate "Ocelot / Felix Ethernet switch support"
++      depends on NET_DSA && PCI
++      select MSCC_OCELOT_SWITCH
++      select NET_DSA_TAG_OCELOT
++      help
++        This driver supports the VSC9959 network switch, which is a member of
++        the Vitesse / Microsemi / Microchip Ocelot family of switching cores.
++        It is embedded as a PCIe function of the NXP LS1028A ENETC integrated
++        endpoint.
+--- /dev/null
++++ b/drivers/net/dsa/ocelot/Makefile
+@@ -0,0 +1,6 @@
++# SPDX-License-Identifier: GPL-2.0-only
++obj-$(CONFIG_NET_DSA_MSCC_FELIX) += mscc_felix.o
++
++mscc_felix-objs := \
++      felix.o \
++      felix_vsc9959.o
+--- /dev/null
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -0,0 +1,441 @@
++// SPDX-License-Identifier: GPL-2.0
++/* Copyright 2019 NXP Semiconductors
++ */
++#include <uapi/linux/if_bridge.h>
++#include <soc/mscc/ocelot.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/of.h>
++#include <net/dsa.h>
++#include "felix.h"
++
++static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds,
++                                                  int port)
++{
++      return DSA_TAG_PROTO_OCELOT;
++}
++
++static int felix_set_ageing_time(struct dsa_switch *ds,
++                               unsigned int ageing_time)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      ocelot_set_ageing_time(ocelot, ageing_time);
++
++      return 0;
++}
++
++static void felix_adjust_link(struct dsa_switch *ds, int port,
++                            struct phy_device *phydev)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      ocelot_adjust_link(ocelot, port, phydev);
++}
++
++static int felix_fdb_dump(struct dsa_switch *ds, int port,
++                        dsa_fdb_dump_cb_t *cb, void *data)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      return ocelot_fdb_dump(ocelot, port, cb, data);
++}
++
++static int felix_fdb_add(struct dsa_switch *ds, int port,
++                       const unsigned char *addr, u16 vid)
++{
++      struct ocelot *ocelot = ds->priv;
++      bool vlan_aware;
++
++      vlan_aware = dsa_port_is_vlan_filtering(dsa_to_port(ds, port));
++
++      return ocelot_fdb_add(ocelot, port, addr, vid, vlan_aware);
++}
++
++static int felix_fdb_del(struct dsa_switch *ds, int port,
++                       const unsigned char *addr, u16 vid)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      return ocelot_fdb_del(ocelot, port, addr, vid);
++}
++
++static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port,
++                                     u8 state)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      return ocelot_bridge_stp_state_set(ocelot, port, state);
++}
++
++static int felix_bridge_join(struct dsa_switch *ds, int port,
++                           struct net_device *br)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      return ocelot_port_bridge_join(ocelot, port, br);
++}
++
++static void felix_bridge_leave(struct dsa_switch *ds, int port,
++                             struct net_device *br)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      ocelot_port_bridge_leave(ocelot, port, br);
++}
++
++/* This callback needs to be present */
++static int felix_vlan_prepare(struct dsa_switch *ds, int port,
++                            const struct switchdev_obj_port_vlan *vlan)
++{
++      return 0;
++}
++
++static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      ocelot_port_vlan_filtering(ocelot, port, enabled);
++
++      return 0;
++}
++
++static void felix_vlan_add(struct dsa_switch *ds, int port,
++                         const struct switchdev_obj_port_vlan *vlan)
++{
++      struct ocelot *ocelot = ds->priv;
++      u16 vid;
++      int err;
++
++      for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
++              err = ocelot_vlan_add(ocelot, port, vid,
++                                    vlan->flags & BRIDGE_VLAN_INFO_PVID,
++                                    vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED);
++              if (err) {
++                      dev_err(ds->dev, "Failed to add VLAN %d to port %d: %d\n",
++                              vid, port, err);
++                      return;
++              }
++      }
++}
++
++static int felix_vlan_del(struct dsa_switch *ds, int port,
++                        const struct switchdev_obj_port_vlan *vlan)
++{
++      struct ocelot *ocelot = ds->priv;
++      u16 vid;
++      int err;
++
++      for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
++              err = ocelot_vlan_del(ocelot, port, vid);
++              if (err) {
++                      dev_err(ds->dev, "Failed to remove VLAN %d from port %d: %d\n",
++                              vid, port, err);
++                      return err;
++              }
++      }
++      return 0;
++}
++
++static int felix_port_enable(struct dsa_switch *ds, int port,
++                           struct phy_device *phy)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      ocelot_port_enable(ocelot, port, phy);
++
++      return 0;
++}
++
++static void felix_port_disable(struct dsa_switch *ds, int port)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      return ocelot_port_disable(ocelot, port);
++}
++
++static void felix_get_strings(struct dsa_switch *ds, int port,
++                            u32 stringset, u8 *data)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      return ocelot_get_strings(ocelot, port, stringset, data);
++}
++
++static void felix_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      ocelot_get_ethtool_stats(ocelot, port, data);
++}
++
++static int felix_get_sset_count(struct dsa_switch *ds, int port, int sset)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      return ocelot_get_sset_count(ocelot, port, sset);
++}
++
++static int felix_get_ts_info(struct dsa_switch *ds, int port,
++                           struct ethtool_ts_info *info)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      return ocelot_get_ts_info(ocelot, port, info);
++}
++
++static int felix_init_structs(struct felix *felix, int num_phys_ports)
++{
++      struct ocelot *ocelot = &felix->ocelot;
++      resource_size_t base;
++      int port, i, err;
++
++      ocelot->num_phys_ports = num_phys_ports;
++      ocelot->ports = devm_kcalloc(ocelot->dev, num_phys_ports,
++                                   sizeof(struct ocelot_port *), GFP_KERNEL);
++      if (!ocelot->ports)
++              return -ENOMEM;
++
++      ocelot->map             = felix->info->map;
++      ocelot->stats_layout    = felix->info->stats_layout;
++      ocelot->num_stats       = felix->info->num_stats;
++      ocelot->shared_queue_sz = felix->info->shared_queue_sz;
++      ocelot->ops             = felix->info->ops;
++
++      base = pci_resource_start(felix->pdev, felix->info->pci_bar);
++
++      for (i = 0; i < TARGET_MAX; i++) {
++              struct regmap *target;
++              struct resource *res;
++
++              if (!felix->info->target_io_res[i].name)
++                      continue;
++
++              res = &felix->info->target_io_res[i];
++              res->flags = IORESOURCE_MEM;
++              res->start += base;
++              res->end += base;
++
++              target = ocelot_regmap_init(ocelot, res);
++              if (IS_ERR(target)) {
++                      dev_err(ocelot->dev,
++                              "Failed to map device memory space\n");
++                      return PTR_ERR(target);
++              }
++
++              ocelot->targets[i] = target;
++      }
++
++      err = ocelot_regfields_init(ocelot, felix->info->regfields);
++      if (err) {
++              dev_err(ocelot->dev, "failed to init reg fields map\n");
++              return err;
++      }
++
++      for (port = 0; port < num_phys_ports; port++) {
++              struct ocelot_port *ocelot_port;
++              void __iomem *port_regs;
++              struct resource *res;
++
++              ocelot_port = devm_kzalloc(ocelot->dev,
++                                         sizeof(struct ocelot_port),
++                                         GFP_KERNEL);
++              if (!ocelot_port) {
++                      dev_err(ocelot->dev,
++                              "failed to allocate port memory\n");
++                      return -ENOMEM;
++              }
++
++              res = &felix->info->port_io_res[port];
++              res->flags = IORESOURCE_MEM;
++              res->start += base;
++              res->end += base;
++
++              port_regs = devm_ioremap_resource(ocelot->dev, res);
++              if (IS_ERR(port_regs)) {
++                      dev_err(ocelot->dev,
++                              "failed to map registers for port %d\n", port);
++                      return PTR_ERR(port_regs);
++              }
++
++              ocelot_port->ocelot = ocelot;
++              ocelot_port->regs = port_regs;
++              ocelot->ports[port] = ocelot_port;
++      }
++
++      return 0;
++}
++
++/* Hardware initialization done here so that we can allocate structures with
++ * devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing
++ * us to allocate structures twice (leak memory) and map PCI memory twice
++ * (which will not work).
++ */
++static int felix_setup(struct dsa_switch *ds)
++{
++      struct ocelot *ocelot = ds->priv;
++      struct felix *felix = ocelot_to_felix(ocelot);
++      int port, err;
++
++      err = felix_init_structs(felix, ds->num_ports);
++      if (err)
++              return err;
++
++      ocelot_init(ocelot);
++
++      for (port = 0; port < ds->num_ports; port++) {
++              ocelot_init_port(ocelot, port);
++
++              if (port == dsa_upstream_port(ds, port))
++                      ocelot_set_cpu_port(ocelot, port,
++                                          OCELOT_TAG_PREFIX_NONE,
++                                          OCELOT_TAG_PREFIX_LONG);
++      }
++
++      return 0;
++}
++
++static void felix_teardown(struct dsa_switch *ds)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      /* stop workqueue thread */
++      ocelot_deinit(ocelot);
++}
++
++static const struct dsa_switch_ops felix_switch_ops = {
++      .get_tag_protocol       = felix_get_tag_protocol,
++      .setup                  = felix_setup,
++      .teardown               = felix_teardown,
++      .set_ageing_time        = felix_set_ageing_time,
++      .get_strings            = felix_get_strings,
++      .get_ethtool_stats      = felix_get_ethtool_stats,
++      .get_sset_count         = felix_get_sset_count,
++      .get_ts_info            = felix_get_ts_info,
++      .adjust_link            = felix_adjust_link,
++      .port_enable            = felix_port_enable,
++      .port_disable           = felix_port_disable,
++      .port_fdb_dump          = felix_fdb_dump,
++      .port_fdb_add           = felix_fdb_add,
++      .port_fdb_del           = felix_fdb_del,
++      .port_bridge_join       = felix_bridge_join,
++      .port_bridge_leave      = felix_bridge_leave,
++      .port_stp_state_set     = felix_bridge_stp_state_set,
++      .port_vlan_prepare      = felix_vlan_prepare,
++      .port_vlan_filtering    = felix_vlan_filtering,
++      .port_vlan_add          = felix_vlan_add,
++      .port_vlan_del          = felix_vlan_del,
++};
++
++static struct felix_info *felix_instance_tbl[] = {
++      [FELIX_INSTANCE_VSC9959] = &felix_info_vsc9959,
++};
++
++static int felix_pci_probe(struct pci_dev *pdev,
++                         const struct pci_device_id *id)
++{
++      enum felix_instance instance = id->driver_data;
++      struct dsa_switch *ds;
++      struct ocelot *ocelot;
++      struct felix *felix;
++      int err;
++
++      err = pci_enable_device(pdev);
++      if (err) {
++              dev_err(&pdev->dev, "device enable failed\n");
++              goto err_pci_enable;
++      }
++
++      /* set up for high or low dma */
++      err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
++      if (err) {
++              err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
++              if (err) {
++                      dev_err(&pdev->dev,
++                              "DMA configuration failed: 0x%x\n", err);
++                      goto err_dma;
++              }
++      }
++
++      felix = kzalloc(sizeof(struct felix), GFP_KERNEL);
++      if (!felix) {
++              err = -ENOMEM;
++              dev_err(&pdev->dev, "Failed to allocate driver memory\n");
++              goto err_alloc_felix;
++      }
++
++      pci_set_drvdata(pdev, felix);
++      ocelot = &felix->ocelot;
++      ocelot->dev = &pdev->dev;
++      felix->pdev = pdev;
++      felix->info = felix_instance_tbl[instance];
++
++      pci_set_master(pdev);
++
++      ds = kzalloc(sizeof(struct dsa_switch), GFP_KERNEL);
++      if (!ds) {
++              err = -ENOMEM;
++              dev_err(&pdev->dev, "Failed to allocate DSA switch\n");
++              goto err_alloc_ds;
++      }
++
++      ds->dev = &pdev->dev;
++      ds->num_ports = felix->info->num_ports;
++      ds->ops = &felix_switch_ops;
++      ds->priv = ocelot;
++      felix->ds = ds;
++
++      err = dsa_register_switch(ds);
++      if (err) {
++              dev_err(&pdev->dev, "Failed to register DSA switch: %d\n", err);
++              goto err_register_ds;
++      }
++
++      return 0;
++
++err_register_ds:
++      kfree(ds);
++err_alloc_ds:
++err_alloc_felix:
++      kfree(felix);
++err_dma:
++      pci_disable_device(pdev);
++err_pci_enable:
++      return err;
++}
++
++static void felix_pci_remove(struct pci_dev *pdev)
++{
++      struct felix *felix;
++
++      felix = pci_get_drvdata(pdev);
++
++      dsa_unregister_switch(felix->ds);
++
++      kfree(felix->ds);
++      kfree(felix);
++
++      pci_disable_device(pdev);
++}
++
++static struct pci_device_id felix_ids[] = {
++      {
++              /* NXP LS1028A */
++              PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0xEEF0),
++              .driver_data = FELIX_INSTANCE_VSC9959,
++      },
++      { 0, }
++};
++MODULE_DEVICE_TABLE(pci, felix_ids);
++
++static struct pci_driver felix_pci_driver = {
++      .name           = KBUILD_MODNAME,
++      .id_table       = felix_ids,
++      .probe          = felix_pci_probe,
++      .remove         = felix_pci_remove,
++};
++
++module_pci_driver(felix_pci_driver);
++
++MODULE_DESCRIPTION("Felix Switch driver");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/drivers/net/dsa/ocelot/felix.h
+@@ -0,0 +1,37 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/* Copyright 2019 NXP Semiconductors
++ */
++#ifndef _MSCC_FELIX_H
++#define _MSCC_FELIX_H
++
++#define ocelot_to_felix(o)            container_of((o), struct felix, ocelot)
++
++/* Platform-specific information */
++struct felix_info {
++      struct resource                 *target_io_res;
++      struct resource                 *port_io_res;
++      const struct reg_field          *regfields;
++      const u32 *const                *map;
++      const struct ocelot_ops         *ops;
++      int                             shared_queue_sz;
++      const struct ocelot_stat_layout *stats_layout;
++      unsigned int                    num_stats;
++      int                             num_ports;
++      int                             pci_bar;
++};
++
++extern struct felix_info              felix_info_vsc9959;
++
++enum felix_instance {
++      FELIX_INSTANCE_VSC9959          = 0,
++};
++
++/* DSA glue / front-end for struct ocelot */
++struct felix {
++      struct dsa_switch               *ds;
++      struct pci_dev                  *pdev;
++      struct felix_info               *info;
++      struct ocelot                   ocelot;
++};
++
++#endif
+--- /dev/null
++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
+@@ -0,0 +1,567 @@
++// SPDX-License-Identifier: (GPL-2.0 OR MIT)
++/* Copyright 2017 Microsemi Corporation
++ * Copyright 2018-2019 NXP Semiconductors
++ */
++#include <soc/mscc/ocelot_sys.h>
++#include <soc/mscc/ocelot.h>
++#include <linux/iopoll.h>
++#include <linux/pci.h>
++#include "felix.h"
++
++static const u32 vsc9959_ana_regmap[] = {
++      REG(ANA_ADVLEARN,                       0x0089a0),
++      REG(ANA_VLANMASK,                       0x0089a4),
++      REG_RESERVED(ANA_PORT_B_DOMAIN),
++      REG(ANA_ANAGEFIL,                       0x0089ac),
++      REG(ANA_ANEVENTS,                       0x0089b0),
++      REG(ANA_STORMLIMIT_BURST,               0x0089b4),
++      REG(ANA_STORMLIMIT_CFG,                 0x0089b8),
++      REG(ANA_ISOLATED_PORTS,                 0x0089c8),
++      REG(ANA_COMMUNITY_PORTS,                0x0089cc),
++      REG(ANA_AUTOAGE,                        0x0089d0),
++      REG(ANA_MACTOPTIONS,                    0x0089d4),
++      REG(ANA_LEARNDISC,                      0x0089d8),
++      REG(ANA_AGENCTRL,                       0x0089dc),
++      REG(ANA_MIRRORPORTS,                    0x0089e0),
++      REG(ANA_EMIRRORPORTS,                   0x0089e4),
++      REG(ANA_FLOODING,                       0x0089e8),
++      REG(ANA_FLOODING_IPMC,                  0x008a08),
++      REG(ANA_SFLOW_CFG,                      0x008a0c),
++      REG(ANA_PORT_MODE,                      0x008a28),
++      REG(ANA_CUT_THRU_CFG,                   0x008a48),
++      REG(ANA_PGID_PGID,                      0x008400),
++      REG(ANA_TABLES_ANMOVED,                 0x007f1c),
++      REG(ANA_TABLES_MACHDATA,                0x007f20),
++      REG(ANA_TABLES_MACLDATA,                0x007f24),
++      REG(ANA_TABLES_STREAMDATA,              0x007f28),
++      REG(ANA_TABLES_MACACCESS,               0x007f2c),
++      REG(ANA_TABLES_MACTINDX,                0x007f30),
++      REG(ANA_TABLES_VLANACCESS,              0x007f34),
++      REG(ANA_TABLES_VLANTIDX,                0x007f38),
++      REG(ANA_TABLES_ISDXACCESS,              0x007f3c),
++      REG(ANA_TABLES_ISDXTIDX,                0x007f40),
++      REG(ANA_TABLES_ENTRYLIM,                0x007f00),
++      REG(ANA_TABLES_PTP_ID_HIGH,             0x007f44),
++      REG(ANA_TABLES_PTP_ID_LOW,              0x007f48),
++      REG(ANA_TABLES_STREAMACCESS,            0x007f4c),
++      REG(ANA_TABLES_STREAMTIDX,              0x007f50),
++      REG(ANA_TABLES_SEQ_HISTORY,             0x007f54),
++      REG(ANA_TABLES_SEQ_MASK,                0x007f58),
++      REG(ANA_TABLES_SFID_MASK,               0x007f5c),
++      REG(ANA_TABLES_SFIDACCESS,              0x007f60),
++      REG(ANA_TABLES_SFIDTIDX,                0x007f64),
++      REG(ANA_MSTI_STATE,                     0x008600),
++      REG(ANA_OAM_UPM_LM_CNT,                 0x008000),
++      REG(ANA_SG_ACCESS_CTRL,                 0x008a64),
++      REG(ANA_SG_CONFIG_REG_1,                0x007fb0),
++      REG(ANA_SG_CONFIG_REG_2,                0x007fb4),
++      REG(ANA_SG_CONFIG_REG_3,                0x007fb8),
++      REG(ANA_SG_CONFIG_REG_4,                0x007fbc),
++      REG(ANA_SG_CONFIG_REG_5,                0x007fc0),
++      REG(ANA_SG_GCL_GS_CONFIG,               0x007f80),
++      REG(ANA_SG_GCL_TI_CONFIG,               0x007f90),
++      REG(ANA_SG_STATUS_REG_1,                0x008980),
++      REG(ANA_SG_STATUS_REG_2,                0x008984),
++      REG(ANA_SG_STATUS_REG_3,                0x008988),
++      REG(ANA_PORT_VLAN_CFG,                  0x007800),
++      REG(ANA_PORT_DROP_CFG,                  0x007804),
++      REG(ANA_PORT_QOS_CFG,                   0x007808),
++      REG(ANA_PORT_VCAP_CFG,                  0x00780c),
++      REG(ANA_PORT_VCAP_S1_KEY_CFG,           0x007810),
++      REG(ANA_PORT_VCAP_S2_CFG,               0x00781c),
++      REG(ANA_PORT_PCP_DEI_MAP,               0x007820),
++      REG(ANA_PORT_CPU_FWD_CFG,               0x007860),
++      REG(ANA_PORT_CPU_FWD_BPDU_CFG,          0x007864),
++      REG(ANA_PORT_CPU_FWD_GARP_CFG,          0x007868),
++      REG(ANA_PORT_CPU_FWD_CCM_CFG,           0x00786c),
++      REG(ANA_PORT_PORT_CFG,                  0x007870),
++      REG(ANA_PORT_POL_CFG,                   0x007874),
++      REG(ANA_PORT_PTP_CFG,                   0x007878),
++      REG(ANA_PORT_PTP_DLY1_CFG,              0x00787c),
++      REG(ANA_PORT_PTP_DLY2_CFG,              0x007880),
++      REG(ANA_PORT_SFID_CFG,                  0x007884),
++      REG(ANA_PFC_PFC_CFG,                    0x008800),
++      REG_RESERVED(ANA_PFC_PFC_TIMER),
++      REG_RESERVED(ANA_IPT_OAM_MEP_CFG),
++      REG_RESERVED(ANA_IPT_IPT),
++      REG_RESERVED(ANA_PPT_PPT),
++      REG_RESERVED(ANA_FID_MAP_FID_MAP),
++      REG(ANA_AGGR_CFG,                       0x008a68),
++      REG(ANA_CPUQ_CFG,                       0x008a6c),
++      REG_RESERVED(ANA_CPUQ_CFG2),
++      REG(ANA_CPUQ_8021_CFG,                  0x008a74),
++      REG(ANA_DSCP_CFG,                       0x008ab4),
++      REG(ANA_DSCP_REWR_CFG,                  0x008bb4),
++      REG(ANA_VCAP_RNG_TYPE_CFG,              0x008bf4),
++      REG(ANA_VCAP_RNG_VAL_CFG,               0x008c14),
++      REG_RESERVED(ANA_VRAP_CFG),
++      REG_RESERVED(ANA_VRAP_HDR_DATA),
++      REG_RESERVED(ANA_VRAP_HDR_MASK),
++      REG(ANA_DISCARD_CFG,                    0x008c40),
++      REG(ANA_FID_CFG,                        0x008c44),
++      REG(ANA_POL_PIR_CFG,                    0x004000),
++      REG(ANA_POL_CIR_CFG,                    0x004004),
++      REG(ANA_POL_MODE_CFG,                   0x004008),
++      REG(ANA_POL_PIR_STATE,                  0x00400c),
++      REG(ANA_POL_CIR_STATE,                  0x004010),
++      REG_RESERVED(ANA_POL_STATE),
++      REG(ANA_POL_FLOWC,                      0x008c48),
++      REG(ANA_POL_HYST,                       0x008cb4),
++      REG_RESERVED(ANA_POL_MISC_CFG),
++};
++
++static const u32 vsc9959_qs_regmap[] = {
++      REG(QS_XTR_GRP_CFG,                     0x000000),
++      REG(QS_XTR_RD,                          0x000008),
++      REG(QS_XTR_FRM_PRUNING,                 0x000010),
++      REG(QS_XTR_FLUSH,                       0x000018),
++      REG(QS_XTR_DATA_PRESENT,                0x00001c),
++      REG(QS_XTR_CFG,                         0x000020),
++      REG(QS_INJ_GRP_CFG,                     0x000024),
++      REG(QS_INJ_WR,                          0x00002c),
++      REG(QS_INJ_CTRL,                        0x000034),
++      REG(QS_INJ_STATUS,                      0x00003c),
++      REG(QS_INJ_ERR,                         0x000040),
++      REG_RESERVED(QS_INH_DBG),
++};
++
++static const u32 vsc9959_s2_regmap[] = {
++      REG(S2_CORE_UPDATE_CTRL,                0x000000),
++      REG(S2_CORE_MV_CFG,                     0x000004),
++      REG(S2_CACHE_ENTRY_DAT,                 0x000008),
++      REG(S2_CACHE_MASK_DAT,                  0x000108),
++      REG(S2_CACHE_ACTION_DAT,                0x000208),
++      REG(S2_CACHE_CNT_DAT,                   0x000308),
++      REG(S2_CACHE_TG_DAT,                    0x000388),
++};
++
++static const u32 vsc9959_qsys_regmap[] = {
++      REG(QSYS_PORT_MODE,                     0x00f460),
++      REG(QSYS_SWITCH_PORT_MODE,              0x00f480),
++      REG(QSYS_STAT_CNT_CFG,                  0x00f49c),
++      REG(QSYS_EEE_CFG,                       0x00f4a0),
++      REG(QSYS_EEE_THRES,                     0x00f4b8),
++      REG(QSYS_IGR_NO_SHARING,                0x00f4bc),
++      REG(QSYS_EGR_NO_SHARING,                0x00f4c0),
++      REG(QSYS_SW_STATUS,                     0x00f4c4),
++      REG(QSYS_EXT_CPU_CFG,                   0x00f4e0),
++      REG_RESERVED(QSYS_PAD_CFG),
++      REG(QSYS_CPU_GROUP_MAP,                 0x00f4e8),
++      REG_RESERVED(QSYS_QMAP),
++      REG_RESERVED(QSYS_ISDX_SGRP),
++      REG_RESERVED(QSYS_TIMED_FRAME_ENTRY),
++      REG(QSYS_TFRM_MISC,                     0x00f50c),
++      REG(QSYS_TFRM_PORT_DLY,                 0x00f510),
++      REG(QSYS_TFRM_TIMER_CFG_1,              0x00f514),
++      REG(QSYS_TFRM_TIMER_CFG_2,              0x00f518),
++      REG(QSYS_TFRM_TIMER_CFG_3,              0x00f51c),
++      REG(QSYS_TFRM_TIMER_CFG_4,              0x00f520),
++      REG(QSYS_TFRM_TIMER_CFG_5,              0x00f524),
++      REG(QSYS_TFRM_TIMER_CFG_6,              0x00f528),
++      REG(QSYS_TFRM_TIMER_CFG_7,              0x00f52c),
++      REG(QSYS_TFRM_TIMER_CFG_8,              0x00f530),
++      REG(QSYS_RED_PROFILE,                   0x00f534),
++      REG(QSYS_RES_QOS_MODE,                  0x00f574),
++      REG(QSYS_RES_CFG,                       0x00c000),
++      REG(QSYS_RES_STAT,                      0x00c004),
++      REG(QSYS_EGR_DROP_MODE,                 0x00f578),
++      REG(QSYS_EQ_CTRL,                       0x00f57c),
++      REG_RESERVED(QSYS_EVENTS_CORE),
++      REG(QSYS_QMAXSDU_CFG_0,                 0x00f584),
++      REG(QSYS_QMAXSDU_CFG_1,                 0x00f5a0),
++      REG(QSYS_QMAXSDU_CFG_2,                 0x00f5bc),
++      REG(QSYS_QMAXSDU_CFG_3,                 0x00f5d8),
++      REG(QSYS_QMAXSDU_CFG_4,                 0x00f5f4),
++      REG(QSYS_QMAXSDU_CFG_5,                 0x00f610),
++      REG(QSYS_QMAXSDU_CFG_6,                 0x00f62c),
++      REG(QSYS_QMAXSDU_CFG_7,                 0x00f648),
++      REG(QSYS_PREEMPTION_CFG,                0x00f664),
++      REG_RESERVED(QSYS_CIR_CFG),
++      REG(QSYS_EIR_CFG,                       0x000004),
++      REG(QSYS_SE_CFG,                        0x000008),
++      REG(QSYS_SE_DWRR_CFG,                   0x00000c),
++      REG_RESERVED(QSYS_SE_CONNECT),
++      REG(QSYS_SE_DLB_SENSE,                  0x000040),
++      REG(QSYS_CIR_STATE,                     0x000044),
++      REG(QSYS_EIR_STATE,                     0x000048),
++      REG_RESERVED(QSYS_SE_STATE),
++      REG(QSYS_HSCH_MISC_CFG,                 0x00f67c),
++      REG(QSYS_TAG_CONFIG,                    0x00f680),
++      REG(QSYS_TAS_PARAM_CFG_CTRL,            0x00f698),
++      REG(QSYS_PORT_MAX_SDU,                  0x00f69c),
++      REG(QSYS_PARAM_CFG_REG_1,               0x00f440),
++      REG(QSYS_PARAM_CFG_REG_2,               0x00f444),
++      REG(QSYS_PARAM_CFG_REG_3,               0x00f448),
++      REG(QSYS_PARAM_CFG_REG_4,               0x00f44c),
++      REG(QSYS_PARAM_CFG_REG_5,               0x00f450),
++      REG(QSYS_GCL_CFG_REG_1,                 0x00f454),
++      REG(QSYS_GCL_CFG_REG_2,                 0x00f458),
++      REG(QSYS_PARAM_STATUS_REG_1,            0x00f400),
++      REG(QSYS_PARAM_STATUS_REG_2,            0x00f404),
++      REG(QSYS_PARAM_STATUS_REG_3,            0x00f408),
++      REG(QSYS_PARAM_STATUS_REG_4,            0x00f40c),
++      REG(QSYS_PARAM_STATUS_REG_5,            0x00f410),
++      REG(QSYS_PARAM_STATUS_REG_6,            0x00f414),
++      REG(QSYS_PARAM_STATUS_REG_7,            0x00f418),
++      REG(QSYS_PARAM_STATUS_REG_8,            0x00f41c),
++      REG(QSYS_PARAM_STATUS_REG_9,            0x00f420),
++      REG(QSYS_GCL_STATUS_REG_1,              0x00f424),
++      REG(QSYS_GCL_STATUS_REG_2,              0x00f428),
++};
++
++static const u32 vsc9959_rew_regmap[] = {
++      REG(REW_PORT_VLAN_CFG,                  0x000000),
++      REG(REW_TAG_CFG,                        0x000004),
++      REG(REW_PORT_CFG,                       0x000008),
++      REG(REW_DSCP_CFG,                       0x00000c),
++      REG(REW_PCP_DEI_QOS_MAP_CFG,            0x000010),
++      REG(REW_PTP_CFG,                        0x000050),
++      REG(REW_PTP_DLY1_CFG,                   0x000054),
++      REG(REW_RED_TAG_CFG,                    0x000058),
++      REG(REW_DSCP_REMAP_DP1_CFG,             0x000410),
++      REG(REW_DSCP_REMAP_CFG,                 0x000510),
++      REG_RESERVED(REW_STAT_CFG),
++      REG_RESERVED(REW_REW_STICKY),
++      REG_RESERVED(REW_PPT),
++};
++
++static const u32 vsc9959_sys_regmap[] = {
++      REG(SYS_COUNT_RX_OCTETS,                0x000000),
++      REG(SYS_COUNT_RX_MULTICAST,             0x000008),
++      REG(SYS_COUNT_RX_SHORTS,                0x000010),
++      REG(SYS_COUNT_RX_FRAGMENTS,             0x000014),
++      REG(SYS_COUNT_RX_JABBERS,               0x000018),
++      REG(SYS_COUNT_RX_64,                    0x000024),
++      REG(SYS_COUNT_RX_65_127,                0x000028),
++      REG(SYS_COUNT_RX_128_255,               0x00002c),
++      REG(SYS_COUNT_RX_256_1023,              0x000030),
++      REG(SYS_COUNT_RX_1024_1526,             0x000034),
++      REG(SYS_COUNT_RX_1527_MAX,              0x000038),
++      REG(SYS_COUNT_RX_LONGS,                 0x000044),
++      REG(SYS_COUNT_TX_OCTETS,                0x000200),
++      REG(SYS_COUNT_TX_COLLISION,             0x000210),
++      REG(SYS_COUNT_TX_DROPS,                 0x000214),
++      REG(SYS_COUNT_TX_64,                    0x00021c),
++      REG(SYS_COUNT_TX_65_127,                0x000220),
++      REG(SYS_COUNT_TX_128_511,               0x000224),
++      REG(SYS_COUNT_TX_512_1023,              0x000228),
++      REG(SYS_COUNT_TX_1024_1526,             0x00022c),
++      REG(SYS_COUNT_TX_1527_MAX,              0x000230),
++      REG(SYS_COUNT_TX_AGING,                 0x000278),
++      REG(SYS_RESET_CFG,                      0x000e00),
++      REG(SYS_SR_ETYPE_CFG,                   0x000e04),
++      REG(SYS_VLAN_ETYPE_CFG,                 0x000e08),
++      REG(SYS_PORT_MODE,                      0x000e0c),
++      REG(SYS_FRONT_PORT_MODE,                0x000e2c),
++      REG(SYS_FRM_AGING,                      0x000e44),
++      REG(SYS_STAT_CFG,                       0x000e48),
++      REG(SYS_SW_STATUS,                      0x000e4c),
++      REG_RESERVED(SYS_MISC_CFG),
++      REG(SYS_REW_MAC_HIGH_CFG,               0x000e6c),
++      REG(SYS_REW_MAC_LOW_CFG,                0x000e84),
++      REG(SYS_TIMESTAMP_OFFSET,               0x000e9c),
++      REG(SYS_PAUSE_CFG,                      0x000ea0),
++      REG(SYS_PAUSE_TOT_CFG,                  0x000ebc),
++      REG(SYS_ATOP,                           0x000ec0),
++      REG(SYS_ATOP_TOT_CFG,                   0x000edc),
++      REG(SYS_MAC_FC_CFG,                     0x000ee0),
++      REG(SYS_MMGT,                           0x000ef8),
++      REG_RESERVED(SYS_MMGT_FAST),
++      REG_RESERVED(SYS_EVENTS_DIF),
++      REG_RESERVED(SYS_EVENTS_CORE),
++      REG_RESERVED(SYS_CNT),
++      REG(SYS_PTP_STATUS,                     0x000f14),
++      REG(SYS_PTP_TXSTAMP,                    0x000f18),
++      REG(SYS_PTP_NXT,                        0x000f1c),
++      REG(SYS_PTP_CFG,                        0x000f20),
++      REG(SYS_RAM_INIT,                       0x000f24),
++      REG_RESERVED(SYS_CM_ADDR),
++      REG_RESERVED(SYS_CM_DATA_WR),
++      REG_RESERVED(SYS_CM_DATA_RD),
++      REG_RESERVED(SYS_CM_OP),
++      REG_RESERVED(SYS_CM_DATA),
++};
++
++static const u32 vsc9959_gcb_regmap[] = {
++      REG(GCB_SOFT_RST,                       0x000004),
++};
++
++static const u32 *vsc9959_regmap[] = {
++      [ANA]   = vsc9959_ana_regmap,
++      [QS]    = vsc9959_qs_regmap,
++      [QSYS]  = vsc9959_qsys_regmap,
++      [REW]   = vsc9959_rew_regmap,
++      [SYS]   = vsc9959_sys_regmap,
++      [S2]    = vsc9959_s2_regmap,
++      [GCB]   = vsc9959_gcb_regmap,
++};
++
++/* Addresses are relative to the PCI device's base address and
++ * will be fixed up at ioremap time.
++ */
++static struct resource vsc9959_target_io_res[] = {
++      [ANA] = {
++              .start  = 0x0280000,
++              .end    = 0x028ffff,
++              .name   = "ana",
++      },
++      [QS] = {
++              .start  = 0x0080000,
++              .end    = 0x00800ff,
++              .name   = "qs",
++      },
++      [QSYS] = {
++              .start  = 0x0200000,
++              .end    = 0x021ffff,
++              .name   = "qsys",
++      },
++      [REW] = {
++              .start  = 0x0030000,
++              .end    = 0x003ffff,
++              .name   = "rew",
++      },
++      [SYS] = {
++              .start  = 0x0010000,
++              .end    = 0x001ffff,
++              .name   = "sys",
++      },
++      [S2] = {
++              .start  = 0x0060000,
++              .end    = 0x00603ff,
++              .name   = "s2",
++      },
++      [GCB] = {
++              .start  = 0x0070000,
++              .end    = 0x00701ff,
++              .name   = "devcpu_gcb",
++      },
++};
++
++static struct resource vsc9959_port_io_res[] = {
++      {
++              .start  = 0x0100000,
++              .end    = 0x010ffff,
++              .name   = "port0",
++      },
++      {
++              .start  = 0x0110000,
++              .end    = 0x011ffff,
++              .name   = "port1",
++      },
++      {
++              .start  = 0x0120000,
++              .end    = 0x012ffff,
++              .name   = "port2",
++      },
++      {
++              .start  = 0x0130000,
++              .end    = 0x013ffff,
++              .name   = "port3",
++      },
++      {
++              .start  = 0x0140000,
++              .end    = 0x014ffff,
++              .name   = "port4",
++      },
++      {
++              .start  = 0x0150000,
++              .end    = 0x015ffff,
++              .name   = "port5",
++      },
++};
++
++static const struct reg_field vsc9959_regfields[] = {
++      [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6),
++      [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 5),
++      [ANA_ANEVENTS_FLOOD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 30, 30),
++      [ANA_ANEVENTS_AUTOAGE] = REG_FIELD(ANA_ANEVENTS, 26, 26),
++      [ANA_ANEVENTS_STORM_DROP] = REG_FIELD(ANA_ANEVENTS, 24, 24),
++      [ANA_ANEVENTS_LEARN_DROP] = REG_FIELD(ANA_ANEVENTS, 23, 23),
++      [ANA_ANEVENTS_AGED_ENTRY] = REG_FIELD(ANA_ANEVENTS, 22, 22),
++      [ANA_ANEVENTS_CPU_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 21, 21),
++      [ANA_ANEVENTS_AUTO_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 20, 20),
++      [ANA_ANEVENTS_LEARN_REMOVE] = REG_FIELD(ANA_ANEVENTS, 19, 19),
++      [ANA_ANEVENTS_AUTO_LEARNED] = REG_FIELD(ANA_ANEVENTS, 18, 18),
++      [ANA_ANEVENTS_AUTO_MOVED] = REG_FIELD(ANA_ANEVENTS, 17, 17),
++      [ANA_ANEVENTS_CLASSIFIED_DROP] = REG_FIELD(ANA_ANEVENTS, 15, 15),
++      [ANA_ANEVENTS_CLASSIFIED_COPY] = REG_FIELD(ANA_ANEVENTS, 14, 14),
++      [ANA_ANEVENTS_VLAN_DISCARD] = REG_FIELD(ANA_ANEVENTS, 13, 13),
++      [ANA_ANEVENTS_FWD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 12, 12),
++      [ANA_ANEVENTS_MULTICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 11, 11),
++      [ANA_ANEVENTS_UNICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 10, 10),
++      [ANA_ANEVENTS_DEST_KNOWN] = REG_FIELD(ANA_ANEVENTS, 9, 9),
++      [ANA_ANEVENTS_BUCKET3_MATCH] = REG_FIELD(ANA_ANEVENTS, 8, 8),
++      [ANA_ANEVENTS_BUCKET2_MATCH] = REG_FIELD(ANA_ANEVENTS, 7, 7),
++      [ANA_ANEVENTS_BUCKET1_MATCH] = REG_FIELD(ANA_ANEVENTS, 6, 6),
++      [ANA_ANEVENTS_BUCKET0_MATCH] = REG_FIELD(ANA_ANEVENTS, 5, 5),
++      [ANA_ANEVENTS_CPU_OPERATION] = REG_FIELD(ANA_ANEVENTS, 4, 4),
++      [ANA_ANEVENTS_DMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 3, 3),
++      [ANA_ANEVENTS_SMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 2, 2),
++      [ANA_ANEVENTS_SEQ_GEN_ERR_0] = REG_FIELD(ANA_ANEVENTS, 1, 1),
++      [ANA_ANEVENTS_SEQ_GEN_ERR_1] = REG_FIELD(ANA_ANEVENTS, 0, 0),
++      [ANA_TABLES_MACACCESS_B_DOM] = REG_FIELD(ANA_TABLES_MACACCESS, 16, 16),
++      [ANA_TABLES_MACTINDX_BUCKET] = REG_FIELD(ANA_TABLES_MACTINDX, 11, 12),
++      [ANA_TABLES_MACTINDX_M_INDEX] = REG_FIELD(ANA_TABLES_MACTINDX, 0, 10),
++      [SYS_RESET_CFG_CORE_ENA] = REG_FIELD(SYS_RESET_CFG, 0, 0),
++      [GCB_SOFT_RST_SWC_RST] = REG_FIELD(GCB_SOFT_RST, 0, 0),
++};
++
++static const struct ocelot_stat_layout vsc9959_stats_layout[] = {
++      { .offset = 0x00,       .name = "rx_octets", },
++      { .offset = 0x01,       .name = "rx_unicast", },
++      { .offset = 0x02,       .name = "rx_multicast", },
++      { .offset = 0x03,       .name = "rx_broadcast", },
++      { .offset = 0x04,       .name = "rx_shorts", },
++      { .offset = 0x05,       .name = "rx_fragments", },
++      { .offset = 0x06,       .name = "rx_jabbers", },
++      { .offset = 0x07,       .name = "rx_crc_align_errs", },
++      { .offset = 0x08,       .name = "rx_sym_errs", },
++      { .offset = 0x09,       .name = "rx_frames_below_65_octets", },
++      { .offset = 0x0A,       .name = "rx_frames_65_to_127_octets", },
++      { .offset = 0x0B,       .name = "rx_frames_128_to_255_octets", },
++      { .offset = 0x0C,       .name = "rx_frames_256_to_511_octets", },
++      { .offset = 0x0D,       .name = "rx_frames_512_to_1023_octets", },
++      { .offset = 0x0E,       .name = "rx_frames_1024_to_1526_octets", },
++      { .offset = 0x0F,       .name = "rx_frames_over_1526_octets", },
++      { .offset = 0x10,       .name = "rx_pause", },
++      { .offset = 0x11,       .name = "rx_control", },
++      { .offset = 0x12,       .name = "rx_longs", },
++      { .offset = 0x13,       .name = "rx_classified_drops", },
++      { .offset = 0x14,       .name = "rx_red_prio_0", },
++      { .offset = 0x15,       .name = "rx_red_prio_1", },
++      { .offset = 0x16,       .name = "rx_red_prio_2", },
++      { .offset = 0x17,       .name = "rx_red_prio_3", },
++      { .offset = 0x18,       .name = "rx_red_prio_4", },
++      { .offset = 0x19,       .name = "rx_red_prio_5", },
++      { .offset = 0x1A,       .name = "rx_red_prio_6", },
++      { .offset = 0x1B,       .name = "rx_red_prio_7", },
++      { .offset = 0x1C,       .name = "rx_yellow_prio_0", },
++      { .offset = 0x1D,       .name = "rx_yellow_prio_1", },
++      { .offset = 0x1E,       .name = "rx_yellow_prio_2", },
++      { .offset = 0x1F,       .name = "rx_yellow_prio_3", },
++      { .offset = 0x20,       .name = "rx_yellow_prio_4", },
++      { .offset = 0x21,       .name = "rx_yellow_prio_5", },
++      { .offset = 0x22,       .name = "rx_yellow_prio_6", },
++      { .offset = 0x23,       .name = "rx_yellow_prio_7", },
++      { .offset = 0x24,       .name = "rx_green_prio_0", },
++      { .offset = 0x25,       .name = "rx_green_prio_1", },
++      { .offset = 0x26,       .name = "rx_green_prio_2", },
++      { .offset = 0x27,       .name = "rx_green_prio_3", },
++      { .offset = 0x28,       .name = "rx_green_prio_4", },
++      { .offset = 0x29,       .name = "rx_green_prio_5", },
++      { .offset = 0x2A,       .name = "rx_green_prio_6", },
++      { .offset = 0x2B,       .name = "rx_green_prio_7", },
++      { .offset = 0x80,       .name = "tx_octets", },
++      { .offset = 0x81,       .name = "tx_unicast", },
++      { .offset = 0x82,       .name = "tx_multicast", },
++      { .offset = 0x83,       .name = "tx_broadcast", },
++      { .offset = 0x84,       .name = "tx_collision", },
++      { .offset = 0x85,       .name = "tx_drops", },
++      { .offset = 0x86,       .name = "tx_pause", },
++      { .offset = 0x87,       .name = "tx_frames_below_65_octets", },
++      { .offset = 0x88,       .name = "tx_frames_65_to_127_octets", },
++      { .offset = 0x89,       .name = "tx_frames_128_255_octets", },
++      { .offset = 0x8B,       .name = "tx_frames_256_511_octets", },
++      { .offset = 0x8C,       .name = "tx_frames_1024_1526_octets", },
++      { .offset = 0x8D,       .name = "tx_frames_over_1526_octets", },
++      { .offset = 0x8E,       .name = "tx_yellow_prio_0", },
++      { .offset = 0x8F,       .name = "tx_yellow_prio_1", },
++      { .offset = 0x90,       .name = "tx_yellow_prio_2", },
++      { .offset = 0x91,       .name = "tx_yellow_prio_3", },
++      { .offset = 0x92,       .name = "tx_yellow_prio_4", },
++      { .offset = 0x93,       .name = "tx_yellow_prio_5", },
++      { .offset = 0x94,       .name = "tx_yellow_prio_6", },
++      { .offset = 0x95,       .name = "tx_yellow_prio_7", },
++      { .offset = 0x96,       .name = "tx_green_prio_0", },
++      { .offset = 0x97,       .name = "tx_green_prio_1", },
++      { .offset = 0x98,       .name = "tx_green_prio_2", },
++      { .offset = 0x99,       .name = "tx_green_prio_3", },
++      { .offset = 0x9A,       .name = "tx_green_prio_4", },
++      { .offset = 0x9B,       .name = "tx_green_prio_5", },
++      { .offset = 0x9C,       .name = "tx_green_prio_6", },
++      { .offset = 0x9D,       .name = "tx_green_prio_7", },
++      { .offset = 0x9E,       .name = "tx_aged", },
++      { .offset = 0x100,      .name = "drop_local", },
++      { .offset = 0x101,      .name = "drop_tail", },
++      { .offset = 0x102,      .name = "drop_yellow_prio_0", },
++      { .offset = 0x103,      .name = "drop_yellow_prio_1", },
++      { .offset = 0x104,      .name = "drop_yellow_prio_2", },
++      { .offset = 0x105,      .name = "drop_yellow_prio_3", },
++      { .offset = 0x106,      .name = "drop_yellow_prio_4", },
++      { .offset = 0x107,      .name = "drop_yellow_prio_5", },
++      { .offset = 0x108,      .name = "drop_yellow_prio_6", },
++      { .offset = 0x109,      .name = "drop_yellow_prio_7", },
++      { .offset = 0x10A,      .name = "drop_green_prio_0", },
++      { .offset = 0x10B,      .name = "drop_green_prio_1", },
++      { .offset = 0x10C,      .name = "drop_green_prio_2", },
++      { .offset = 0x10D,      .name = "drop_green_prio_3", },
++      { .offset = 0x10E,      .name = "drop_green_prio_4", },
++      { .offset = 0x10F,      .name = "drop_green_prio_5", },
++      { .offset = 0x110,      .name = "drop_green_prio_6", },
++      { .offset = 0x111,      .name = "drop_green_prio_7", },
++};
++
++#define VSC9959_INIT_TIMEOUT                  50000
++#define VSC9959_GCB_RST_SLEEP                 100
++#define VSC9959_SYS_RAMINIT_SLEEP             80
++
++static int vsc9959_gcb_soft_rst_status(struct ocelot *ocelot)
++{
++      int val;
++
++      regmap_field_read(ocelot->regfields[GCB_SOFT_RST_SWC_RST], &val);
++
++      return val;
++}
++
++static int vsc9959_sys_ram_init_status(struct ocelot *ocelot)
++{
++      return ocelot_read(ocelot, SYS_RAM_INIT);
++}
++
++static int vsc9959_reset(struct ocelot *ocelot)
++{
++      int val, err;
++
++      /* soft-reset the switch core */
++      regmap_field_write(ocelot->regfields[GCB_SOFT_RST_SWC_RST], 1);
++
++      err = readx_poll_timeout(vsc9959_gcb_soft_rst_status, ocelot, val, !val,
++                               VSC9959_GCB_RST_SLEEP, VSC9959_INIT_TIMEOUT);
++      if (err) {
++              dev_err(ocelot->dev, "timeout: switch core reset\n");
++              return err;
++      }
++
++      /* initialize switch mem ~40us */
++      ocelot_write(ocelot, SYS_RAM_INIT_RAM_INIT, SYS_RAM_INIT);
++      err = readx_poll_timeout(vsc9959_sys_ram_init_status, ocelot, val, !val,
++                               VSC9959_SYS_RAMINIT_SLEEP,
++                               VSC9959_INIT_TIMEOUT);
++      if (err) {
++              dev_err(ocelot->dev, "timeout: switch sram init\n");
++              return err;
++      }
++
++      /* enable switch core */
++      regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1);
++
++      return 0;
++}
++
++static const struct ocelot_ops vsc9959_ops = {
++      .reset                  = vsc9959_reset,
++};
++
++struct felix_info felix_info_vsc9959 = {
++      .target_io_res          = vsc9959_target_io_res,
++      .port_io_res            = vsc9959_port_io_res,
++      .regfields              = vsc9959_regfields,
++      .map                    = vsc9959_regmap,
++      .ops                    = &vsc9959_ops,
++      .stats_layout           = vsc9959_stats_layout,
++      .num_stats              = ARRAY_SIZE(vsc9959_stats_layout),
++      .shared_queue_sz        = 128 * 1024,
++      .num_ports              = 6,
++      .pci_bar                = 4,
++};
diff --git a/target/linux/layerscape/patches-5.4/701-net-0264-net-dsa-felix-Fix-CPU-port-assignment-when-not-last-.patch b/target/linux/layerscape/patches-5.4/701-net-0264-net-dsa-felix-Fix-CPU-port-assignment-when-not-last-.patch
new file mode 100644 (file)
index 0000000..972ec16
--- /dev/null
@@ -0,0 +1,53 @@
+From 93a32fc4f43ae40a2140acd9258faada11a98ec0 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 18 Nov 2019 20:16:57 +0200
+Subject: [PATCH] net: dsa: felix: Fix CPU port assignment when not last port
+
+On the NXP LS1028A, there are 2 Ethernet links between the Felix switch
+and the ENETC:
+- eno2 <-> swp4, at 2.5G
+- eno3 <-> swp5, at 1G
+
+Only one of the above Ethernet port pairs can act as a DSA link for
+tagging.
+
+When adding initial support for the driver, it was tested only on the 1G
+eno3 <-> swp5 interface, due to the necessity of using PHYLIB initially
+(which treats fixed-link interfaces as emulated C22 PHYs, so it doesn't
+support fixed-link speeds higher than 1G).
+
+After making PHYLINK work, it appears that swp4 still can't act as CPU
+port. So it looks like ocelot_set_cpu_port was being called for swp4,
+but then it was called again for swp5, overwriting the CPU port assigned
+in the DT.
+
+It appears that when you call dsa_upstream_port for a port that is not
+defined in the device tree (such as swp5 when using swp4 as CPU port),
+its dp->cpu_dp pointer is not initialized by dsa_tree_setup_default_cpu,
+and this trips up the following condition in dsa_upstream_port:
+
+       if (!cpu_dp)
+               return port;
+
+So the moral of the story is: don't call dsa_upstream_port for a port
+that is not defined in the device tree, and therefore its dsa_port
+structure is not completely initialized (ds->num_ports is still 6).
+
+Fixes: 56051948773e ("net: dsa: ocelot: add driver for Felix switch family")
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/ocelot/felix.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -286,7 +286,7 @@ static int felix_setup(struct dsa_switch
+       for (port = 0; port < ds->num_ports; port++) {
+               ocelot_init_port(ocelot, port);
+-              if (port == dsa_upstream_port(ds, port))
++              if (dsa_is_cpu_port(ds, port))
+                       ocelot_set_cpu_port(ocelot, port,
+                                           OCELOT_TAG_PREFIX_NONE,
+                                           OCELOT_TAG_PREFIX_LONG);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0265-net-mscc-ocelot-export-ocelot_hwstamp_get-set-functi.patch b/target/linux/layerscape/patches-5.4/701-net-0265-net-mscc-ocelot-export-ocelot_hwstamp_get-set-functi.patch
new file mode 100644 (file)
index 0000000..469eea2
--- /dev/null
@@ -0,0 +1,57 @@
+From 1f7c79cacbb448420929fc3b5261b9616b5d8f6d Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Wed, 20 Nov 2019 16:23:14 +0800
+Subject: [PATCH] net: mscc: ocelot: export ocelot_hwstamp_get/set functions
+
+Export ocelot_hwstamp_get/set functions so that DSA driver
+is able to reuse them.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 8 ++++----
+ include/soc/mscc/ocelot.h          | 2 ++
+ 2 files changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -1049,15 +1049,14 @@ static int ocelot_get_port_parent_id(str
+       return 0;
+ }
+-static int ocelot_hwstamp_get(struct ocelot *ocelot, int port,
+-                            struct ifreq *ifr)
++int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr)
+ {
+       return copy_to_user(ifr->ifr_data, &ocelot->hwtstamp_config,
+                           sizeof(ocelot->hwtstamp_config)) ? -EFAULT : 0;
+ }
++EXPORT_SYMBOL(ocelot_hwstamp_get);
+-static int ocelot_hwstamp_set(struct ocelot *ocelot, int port,
+-                            struct ifreq *ifr)
++int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr)
+ {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+       struct hwtstamp_config cfg;
+@@ -1120,6 +1119,7 @@ static int ocelot_hwstamp_set(struct oce
+       return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+ }
++EXPORT_SYMBOL(ocelot_hwstamp_set);
+ static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ {
+--- a/include/soc/mscc/ocelot.h
++++ b/include/soc/mscc/ocelot.h
+@@ -533,6 +533,8 @@ int ocelot_fdb_del(struct ocelot *ocelot
+ int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
+                   bool untagged);
+ int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid);
++int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr);
++int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr);
+ int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts);
+ void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0266-net-mscc-ocelot-convert-to-use-ocelot_get_txtstamp.patch b/target/linux/layerscape/patches-5.4/701-net-0266-net-mscc-ocelot-convert-to-use-ocelot_get_txtstamp.patch
new file mode 100644 (file)
index 0000000..31469bd
--- /dev/null
@@ -0,0 +1,202 @@
+From dd8b8f6baf4917124ed268022f7ce4a08d35cc89 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Wed, 20 Nov 2019 16:23:15 +0800
+Subject: [PATCH] net: mscc: ocelot: convert to use ocelot_get_txtstamp()
+
+The method getting TX timestamp by reading timestamp FIFO and
+matching skbs list is common for DSA Felix driver too.
+So move code out of ocelot_board.c, convert to use
+ocelot_get_txtstamp() function and export it.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c       | 62 ++++++++++++++++++++++++++++++--
+ drivers/net/ethernet/mscc/ocelot.h       |  6 ----
+ drivers/net/ethernet/mscc/ocelot_board.c | 53 +--------------------------
+ include/soc/mscc/ocelot.h                |  9 ++++-
+ 4 files changed, 69 insertions(+), 61 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -661,7 +661,8 @@ out:
+       return NETDEV_TX_OK;
+ }
+-void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts)
++static void ocelot_get_hwtimestamp(struct ocelot *ocelot,
++                                 struct timespec64 *ts)
+ {
+       unsigned long flags;
+       u32 val;
+@@ -686,7 +687,64 @@ void ocelot_get_hwtimestamp(struct ocelo
+       spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
+ }
+-EXPORT_SYMBOL(ocelot_get_hwtimestamp);
++
++void ocelot_get_txtstamp(struct ocelot *ocelot)
++{
++      int budget = OCELOT_PTP_QUEUE_SZ;
++
++      while (budget--) {
++              struct skb_shared_hwtstamps shhwtstamps;
++              struct list_head *pos, *tmp;
++              struct sk_buff *skb = NULL;
++              struct ocelot_skb *entry;
++              struct ocelot_port *port;
++              struct timespec64 ts;
++              u32 val, id, txport;
++
++              val = ocelot_read(ocelot, SYS_PTP_STATUS);
++
++              /* Check if a timestamp can be retrieved */
++              if (!(val & SYS_PTP_STATUS_PTP_MESS_VLD))
++                      break;
++
++              WARN_ON(val & SYS_PTP_STATUS_PTP_OVFL);
++
++              /* Retrieve the ts ID and Tx port */
++              id = SYS_PTP_STATUS_PTP_MESS_ID_X(val);
++              txport = SYS_PTP_STATUS_PTP_MESS_TXPORT_X(val);
++
++              /* Retrieve its associated skb */
++              port = ocelot->ports[txport];
++
++              list_for_each_safe(pos, tmp, &port->skbs) {
++                      entry = list_entry(pos, struct ocelot_skb, head);
++                      if (entry->id != id)
++                              continue;
++
++                      skb = entry->skb;
++
++                      list_del(pos);
++                      kfree(entry);
++              }
++
++              /* Next ts */
++              ocelot_write(ocelot, SYS_PTP_NXT_PTP_NXT, SYS_PTP_NXT);
++
++              if (unlikely(!skb))
++                      continue;
++
++              /* Get the h/w timestamp */
++              ocelot_get_hwtimestamp(ocelot, &ts);
++
++              /* Set the timestamp into the skb */
++              memset(&shhwtstamps, 0, sizeof(shhwtstamps));
++              shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
++              skb_tstamp_tx(skb, &shhwtstamps);
++
++              dev_kfree_skb_any(skb);
++      }
++}
++EXPORT_SYMBOL(ocelot_get_txtstamp);
+ static int ocelot_mc_unsync(struct net_device *dev, const unsigned char *addr)
+ {
+--- a/drivers/net/ethernet/mscc/ocelot.h
++++ b/drivers/net/ethernet/mscc/ocelot.h
+@@ -74,12 +74,6 @@ struct ocelot_port_private {
+       struct ocelot_port_tc tc;
+ };
+-struct ocelot_skb {
+-      struct list_head head;
+-      struct sk_buff *skb;
+-      u8 id;
+-};
+-
+ u32 ocelot_port_readl(struct ocelot_port *port, u32 reg);
+ void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg);
+--- a/drivers/net/ethernet/mscc/ocelot_board.c
++++ b/drivers/net/ethernet/mscc/ocelot_board.c
+@@ -198,60 +198,9 @@ static irqreturn_t ocelot_xtr_irq_handle
+ static irqreturn_t ocelot_ptp_rdy_irq_handler(int irq, void *arg)
+ {
+-      int budget = OCELOT_PTP_QUEUE_SZ;
+       struct ocelot *ocelot = arg;
+-      while (budget--) {
+-              struct skb_shared_hwtstamps shhwtstamps;
+-              struct list_head *pos, *tmp;
+-              struct sk_buff *skb = NULL;
+-              struct ocelot_skb *entry;
+-              struct ocelot_port *port;
+-              struct timespec64 ts;
+-              u32 val, id, txport;
+-
+-              val = ocelot_read(ocelot, SYS_PTP_STATUS);
+-
+-              /* Check if a timestamp can be retrieved */
+-              if (!(val & SYS_PTP_STATUS_PTP_MESS_VLD))
+-                      break;
+-
+-              WARN_ON(val & SYS_PTP_STATUS_PTP_OVFL);
+-
+-              /* Retrieve the ts ID and Tx port */
+-              id = SYS_PTP_STATUS_PTP_MESS_ID_X(val);
+-              txport = SYS_PTP_STATUS_PTP_MESS_TXPORT_X(val);
+-
+-              /* Retrieve its associated skb */
+-              port = ocelot->ports[txport];
+-
+-              list_for_each_safe(pos, tmp, &port->skbs) {
+-                      entry = list_entry(pos, struct ocelot_skb, head);
+-                      if (entry->id != id)
+-                              continue;
+-
+-                      skb = entry->skb;
+-
+-                      list_del(pos);
+-                      kfree(entry);
+-              }
+-
+-              /* Next ts */
+-              ocelot_write(ocelot, SYS_PTP_NXT_PTP_NXT, SYS_PTP_NXT);
+-
+-              if (unlikely(!skb))
+-                      continue;
+-
+-              /* Get the h/w timestamp */
+-              ocelot_get_hwtimestamp(ocelot, &ts);
+-
+-              /* Set the timestamp into the skb */
+-              memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+-              shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
+-              skb_tstamp_tx(skb, &shhwtstamps);
+-
+-              dev_kfree_skb_any(skb);
+-      }
++      ocelot_get_txtstamp(ocelot);
+       return IRQ_HANDLED;
+ }
+--- a/include/soc/mscc/ocelot.h
++++ b/include/soc/mscc/ocelot.h
+@@ -406,6 +406,13 @@ struct ocelot_ops {
+       int (*reset)(struct ocelot *ocelot);
+ };
++struct ocelot_skb {
++      struct list_head head;
++      struct sk_buff *skb;
++      u8 id;
++};
++
++
+ struct ocelot_port {
+       struct ocelot                   *ocelot;
+@@ -536,6 +543,6 @@ int ocelot_vlan_del(struct ocelot *ocelo
+ int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr);
+ int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr);
+ int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts);
+-void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts);
++void ocelot_get_txtstamp(struct ocelot *ocelot);
+ #endif
diff --git a/target/linux/layerscape/patches-5.4/701-net-0267-net-mscc-ocelot-convert-to-use-ocelot_port_add_txtst.patch b/target/linux/layerscape/patches-5.4/701-net-0267-net-mscc-ocelot-convert-to-use-ocelot_port_add_txtst.patch
new file mode 100644 (file)
index 0000000..988c90e
--- /dev/null
@@ -0,0 +1,93 @@
+From c0c92f8d9a093faf64397b1874f074e071a5b4e2 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Wed, 20 Nov 2019 16:23:16 +0800
+Subject: [PATCH] net: mscc: ocelot: convert to use
+ ocelot_port_add_txtstamp_skb()
+
+Convert to use ocelot_port_add_txtstamp_skb() for adding skbs which
+require TX timestamp into list. Export it so that DSA Felix driver
+could reuse it too.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 43 ++++++++++++++++++++++++--------------
+ include/soc/mscc/ocelot.h          |  2 ++
+ 2 files changed, 29 insertions(+), 16 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -575,6 +575,32 @@ static int ocelot_gen_ifh(u32 *ifh, stru
+       return 0;
+ }
++int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port,
++                               struct sk_buff *skb)
++{
++      struct skb_shared_info *shinfo = skb_shinfo(skb);
++      struct ocelot *ocelot = ocelot_port->ocelot;
++
++      if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP &&
++          ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
++              struct ocelot_skb *oskb =
++                      kzalloc(sizeof(struct ocelot_skb), GFP_ATOMIC);
++
++              if (unlikely(!oskb))
++                      return -ENOMEM;
++
++              shinfo->tx_flags |= SKBTX_IN_PROGRESS;
++
++              oskb->skb = skb;
++              oskb->id = ocelot_port->ts_id % 4;
++
++              list_add_tail(&oskb->head, &ocelot_port->skbs);
++              return 0;
++      }
++      return -ENODATA;
++}
++EXPORT_SYMBOL(ocelot_port_add_txtstamp_skb);
++
+ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+       struct ocelot_port_private *priv = netdev_priv(dev);
+@@ -637,26 +663,11 @@ static int ocelot_port_xmit(struct sk_bu
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+-      if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP &&
+-          ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
+-              struct ocelot_skb *oskb =
+-                      kzalloc(sizeof(struct ocelot_skb), GFP_ATOMIC);
+-
+-              if (unlikely(!oskb))
+-                      goto out;
+-
+-              skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+-
+-              oskb->skb = skb;
+-              oskb->id = ocelot_port->ts_id % 4;
++      if (!ocelot_port_add_txtstamp_skb(ocelot_port, skb)) {
+               ocelot_port->ts_id++;
+-
+-              list_add_tail(&oskb->head, &ocelot_port->skbs);
+-
+               return NETDEV_TX_OK;
+       }
+-out:
+       dev_kfree_skb_any(skb);
+       return NETDEV_TX_OK;
+ }
+--- a/include/soc/mscc/ocelot.h
++++ b/include/soc/mscc/ocelot.h
+@@ -543,6 +543,8 @@ int ocelot_vlan_del(struct ocelot *ocelo
+ int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr);
+ int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr);
+ int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts);
++int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port,
++                               struct sk_buff *skb);
+ void ocelot_get_txtstamp(struct ocelot *ocelot);
+ #endif
diff --git a/target/linux/layerscape/patches-5.4/701-net-0268-net-dsa-ocelot-define-PTP-registers-for-felix_vsc995.patch b/target/linux/layerscape/patches-5.4/701-net-0268-net-dsa-ocelot-define-PTP-registers-for-felix_vsc995.patch
new file mode 100644 (file)
index 0000000..c3f9263
--- /dev/null
@@ -0,0 +1,53 @@
+From bd8d12b3bc7b5d63132a6d5da0890c6fc3bcad7e Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Wed, 20 Nov 2019 16:23:17 +0800
+Subject: [PATCH] net: dsa: ocelot: define PTP registers for felix_vsc9959
+
+This patch is to define PTP registers for felix_vsc9959.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/ocelot/felix_vsc9959.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
+@@ -282,6 +282,16 @@ static const u32 vsc9959_sys_regmap[] =
+       REG_RESERVED(SYS_CM_DATA),
+ };
++static const u32 vsc9959_ptp_regmap[] = {
++      REG(PTP_PIN_CFG,                   0x000000),
++      REG(PTP_PIN_TOD_SEC_MSB,           0x000004),
++      REG(PTP_PIN_TOD_SEC_LSB,           0x000008),
++      REG(PTP_PIN_TOD_NSEC,              0x00000c),
++      REG(PTP_CFG_MISC,                  0x0000a0),
++      REG(PTP_CLK_CFG_ADJ_CFG,           0x0000a4),
++      REG(PTP_CLK_CFG_ADJ_FREQ,          0x0000a8),
++};
++
+ static const u32 vsc9959_gcb_regmap[] = {
+       REG(GCB_SOFT_RST,                       0x000004),
+ };
+@@ -293,6 +303,7 @@ static const u32 *vsc9959_regmap[] = {
+       [REW]   = vsc9959_rew_regmap,
+       [SYS]   = vsc9959_sys_regmap,
+       [S2]    = vsc9959_s2_regmap,
++      [PTP]   = vsc9959_ptp_regmap,
+       [GCB]   = vsc9959_gcb_regmap,
+ };
+@@ -330,6 +341,11 @@ static struct resource vsc9959_target_io
+               .end    = 0x00603ff,
+               .name   = "s2",
+       },
++      [PTP] = {
++              .start  = 0x0090000,
++              .end    = 0x00900cb,
++              .name   = "ptp",
++      },
+       [GCB] = {
+               .start  = 0x0070000,
+               .end    = 0x00701ff,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0269-net-dsa-ocelot-add-hardware-timestamping-support-for.patch b/target/linux/layerscape/patches-5.4/701-net-0269-net-dsa-ocelot-add-hardware-timestamping-support-for.patch
new file mode 100644 (file)
index 0000000..d18f27e
--- /dev/null
@@ -0,0 +1,186 @@
+From 34bfb24b8ff5af09b014ea8530e1e8d89bb2a155 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Wed, 20 Nov 2019 16:23:18 +0800
+Subject: [PATCH] net: dsa: ocelot: add hardware timestamping support for Felix
+
+This patch is to reuse ocelot functions as possible to enable PTP
+clock and to support hardware timestamping on Felix.
+On TX path, timestamping works on packet which requires timestamp.
+The injection header will be configured accordingly, and skb clone
+requires timestamp will be added into a list. The TX timestamp
+is final handled in threaded interrupt handler when PTP timestamp
+FIFO is ready.
+On RX path, timestamping is always working. The RX timestamp could
+be got from extraction header.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/ocelot/felix.c | 89 ++++++++++++++++++++++++++++++++++++++++++
+ net/dsa/tag_ocelot.c           | 14 ++++++-
+ 2 files changed, 102 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -3,6 +3,7 @@
+  */
+ #include <uapi/linux/if_bridge.h>
+ #include <soc/mscc/ocelot.h>
++#include <linux/packing.h>
+ #include <linux/module.h>
+ #include <linux/pci.h>
+ #include <linux/of.h>
+@@ -303,6 +304,62 @@ static void felix_teardown(struct dsa_sw
+       ocelot_deinit(ocelot);
+ }
++static int felix_hwtstamp_get(struct dsa_switch *ds, int port,
++                            struct ifreq *ifr)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      return ocelot_hwstamp_get(ocelot, port, ifr);
++}
++
++static int felix_hwtstamp_set(struct dsa_switch *ds, int port,
++                            struct ifreq *ifr)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      return ocelot_hwstamp_set(ocelot, port, ifr);
++}
++
++static bool felix_rxtstamp(struct dsa_switch *ds, int port,
++                         struct sk_buff *skb, unsigned int type)
++{
++      struct skb_shared_hwtstamps *shhwtstamps;
++      struct ocelot *ocelot = ds->priv;
++      u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN;
++      u32 tstamp_lo, tstamp_hi;
++      struct timespec64 ts;
++      u64 tstamp, val;
++
++      ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
++      tstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
++
++      packing(extraction, &val,  116, 85, OCELOT_TAG_LEN, UNPACK, 0);
++      tstamp_lo = (u32)val;
++
++      tstamp_hi = tstamp >> 32;
++      if ((tstamp & 0xffffffff) < tstamp_lo)
++              tstamp_hi--;
++
++      tstamp = ((u64)tstamp_hi << 32) | tstamp_lo;
++
++      shhwtstamps = skb_hwtstamps(skb);
++      memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
++      shhwtstamps->hwtstamp = tstamp;
++      return false;
++}
++
++bool felix_txtstamp(struct dsa_switch *ds, int port,
++                  struct sk_buff *clone, unsigned int type)
++{
++      struct ocelot *ocelot = ds->priv;
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++
++      if (!ocelot_port_add_txtstamp_skb(ocelot_port, clone))
++              return true;
++
++      return false;
++}
++
+ static const struct dsa_switch_ops felix_switch_ops = {
+       .get_tag_protocol       = felix_get_tag_protocol,
+       .setup                  = felix_setup,
+@@ -325,12 +382,33 @@ static const struct dsa_switch_ops felix
+       .port_vlan_filtering    = felix_vlan_filtering,
+       .port_vlan_add          = felix_vlan_add,
+       .port_vlan_del          = felix_vlan_del,
++      .port_hwtstamp_get      = felix_hwtstamp_get,
++      .port_hwtstamp_set      = felix_hwtstamp_set,
++      .port_rxtstamp          = felix_rxtstamp,
++      .port_txtstamp          = felix_txtstamp,
+ };
+ static struct felix_info *felix_instance_tbl[] = {
+       [FELIX_INSTANCE_VSC9959] = &felix_info_vsc9959,
+ };
++static irqreturn_t felix_irq_handler(int irq, void *data)
++{
++      struct ocelot *ocelot = (struct ocelot *)data;
++
++      /* The INTB interrupt is used for both PTP TX timestamp interrupt
++       * and preemption status change interrupt on each port.
++       *
++       * - Get txtstamp if have
++       * - TODO: handle preemption. Without handling it, driver may get
++       *   interrupt storm.
++       */
++
++      ocelot_get_txtstamp(ocelot);
++
++      return IRQ_HANDLED;
++}
++
+ static int felix_pci_probe(struct pci_dev *pdev,
+                          const struct pci_device_id *id)
+ {
+@@ -372,6 +450,16 @@ static int felix_pci_probe(struct pci_de
+       pci_set_master(pdev);
++      err = devm_request_threaded_irq(&pdev->dev, pdev->irq, NULL,
++                                      &felix_irq_handler, IRQF_ONESHOT,
++                                      "felix-intb", ocelot);
++      if (err) {
++              dev_err(&pdev->dev, "Failed to request irq\n");
++              goto err_alloc_irq;
++      }
++
++      ocelot->ptp = 1;
++
+       ds = kzalloc(sizeof(struct dsa_switch), GFP_KERNEL);
+       if (!ds) {
+               err = -ENOMEM;
+@@ -396,6 +484,7 @@ static int felix_pci_probe(struct pci_de
+ err_register_ds:
+       kfree(ds);
+ err_alloc_ds:
++err_alloc_irq:
+ err_alloc_felix:
+       kfree(felix);
+ err_dma:
+--- a/net/dsa/tag_ocelot.c
++++ b/net/dsa/tag_ocelot.c
+@@ -137,9 +137,11 @@ static struct sk_buff *ocelot_xmit(struc
+                                  struct net_device *netdev)
+ {
+       struct dsa_port *dp = dsa_slave_to_port(netdev);
+-      u64 bypass, dest, src, qos_class;
++      u64 bypass, dest, src, qos_class, rew_op;
+       struct dsa_switch *ds = dp->ds;
+       int port = dp->index;
++      struct ocelot *ocelot = ds->priv;
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
+       u8 *injection;
+       if (unlikely(skb_cow_head(skb, OCELOT_TAG_LEN) < 0)) {
+@@ -161,6 +163,16 @@ static struct sk_buff *ocelot_xmit(struc
+       packing(injection, &src,       46,  43, OCELOT_TAG_LEN, PACK, 0);
+       packing(injection, &qos_class, 19,  17, OCELOT_TAG_LEN, PACK, 0);
++      if (ocelot->ptp && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
++              rew_op = ocelot_port->ptp_cmd;
++              if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
++                      rew_op |= (ocelot_port->ts_id  % 4) << 3;
++                      ocelot_port->ts_id++;
++              }
++
++              packing(injection, &rew_op, 125, 117, OCELOT_TAG_LEN, PACK, 0);
++      }
++
+       return skb;
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0270-net-mscc-ocelot-avoid-incorrect-consuming-in-skbs-li.patch b/target/linux/layerscape/patches-5.4/701-net-0270-net-mscc-ocelot-avoid-incorrect-consuming-in-skbs-li.patch
new file mode 100644 (file)
index 0000000..36fbffa
--- /dev/null
@@ -0,0 +1,25 @@
+From e6208c23045ece890eebfe0564f73ccc52603867 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Wed, 27 Nov 2019 15:27:56 +0800
+Subject: [PATCH] net: mscc: ocelot: avoid incorrect consuming in skbs list
+
+Break the matching loop when find the matching skb for TX timestamp.
+This is to avoid consuming more skbs incorrectly. The timestamp ID
+is from 0 to 3 while the FIFO could support 128 timestamps at most.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -736,6 +736,7 @@ void ocelot_get_txtstamp(struct ocelot *
+                       list_del(pos);
+                       kfree(entry);
++                      break;
+               }
+               /* Next ts */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0271-net-mscc-ocelot-use-skb-queue-instead-of-skbs-list.patch b/target/linux/layerscape/patches-5.4/701-net-0271-net-mscc-ocelot-use-skb-queue-instead-of-skbs-list.patch
new file mode 100644 (file)
index 0000000..6be37fc
--- /dev/null
@@ -0,0 +1,158 @@
+From e7e0b3b89da97e3186fbe3774a1ca9b77402d893 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Wed, 27 Nov 2019 15:27:57 +0800
+Subject: [PATCH] net: mscc: ocelot: use skb queue instead of skbs list
+
+Convert to use skb queue instead of the list of skbs.
+The skb queue could provide protection with lock.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 54 +++++++++++++-------------------------
+ include/soc/mscc/ocelot.h          |  9 +------
+ 2 files changed, 19 insertions(+), 44 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -583,18 +583,10 @@ int ocelot_port_add_txtstamp_skb(struct
+       if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP &&
+           ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
+-              struct ocelot_skb *oskb =
+-                      kzalloc(sizeof(struct ocelot_skb), GFP_ATOMIC);
+-
+-              if (unlikely(!oskb))
+-                      return -ENOMEM;
+-
+               shinfo->tx_flags |= SKBTX_IN_PROGRESS;
+-
+-              oskb->skb = skb;
+-              oskb->id = ocelot_port->ts_id % 4;
+-
+-              list_add_tail(&oskb->head, &ocelot_port->skbs);
++              /* Store timestamp ID in cb[0] of sk_buff */
++              skb->cb[0] = ocelot_port->ts_id % 4;
++              skb_queue_tail(&ocelot_port->tx_skbs, skb);
+               return 0;
+       }
+       return -ENODATA;
+@@ -704,12 +696,11 @@ void ocelot_get_txtstamp(struct ocelot *
+       int budget = OCELOT_PTP_QUEUE_SZ;
+       while (budget--) {
++              struct sk_buff *skb, *skb_tmp, *skb_match = NULL;
+               struct skb_shared_hwtstamps shhwtstamps;
+-              struct list_head *pos, *tmp;
+-              struct sk_buff *skb = NULL;
+-              struct ocelot_skb *entry;
+               struct ocelot_port *port;
+               struct timespec64 ts;
++              unsigned long flags;
+               u32 val, id, txport;
+               val = ocelot_read(ocelot, SYS_PTP_STATUS);
+@@ -727,22 +718,22 @@ void ocelot_get_txtstamp(struct ocelot *
+               /* Retrieve its associated skb */
+               port = ocelot->ports[txport];
+-              list_for_each_safe(pos, tmp, &port->skbs) {
+-                      entry = list_entry(pos, struct ocelot_skb, head);
+-                      if (entry->id != id)
+-                              continue;
++              spin_lock_irqsave(&port->tx_skbs.lock, flags);
+-                      skb = entry->skb;
+-
+-                      list_del(pos);
+-                      kfree(entry);
++              skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) {
++                      if (skb->cb[0] != id)
++                              continue;
++                      __skb_unlink(skb, &port->tx_skbs);
++                      skb_match = skb;
+                       break;
+               }
++              spin_unlock_irqrestore(&port->tx_skbs.lock, flags);
++
+               /* Next ts */
+               ocelot_write(ocelot, SYS_PTP_NXT_PTP_NXT, SYS_PTP_NXT);
+-              if (unlikely(!skb))
++              if (unlikely(!skb_match))
+                       continue;
+               /* Get the h/w timestamp */
+@@ -751,9 +742,9 @@ void ocelot_get_txtstamp(struct ocelot *
+               /* Set the timestamp into the skb */
+               memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+               shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
+-              skb_tstamp_tx(skb, &shhwtstamps);
++              skb_tstamp_tx(skb_match, &shhwtstamps);
+-              dev_kfree_skb_any(skb);
++              dev_kfree_skb_any(skb_match);
+       }
+ }
+ EXPORT_SYMBOL(ocelot_get_txtstamp);
+@@ -2210,7 +2201,7 @@ void ocelot_init_port(struct ocelot *oce
+ {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+-      INIT_LIST_HEAD(&ocelot_port->skbs);
++      skb_queue_head_init(&ocelot_port->tx_skbs);
+       /* Basic L2 initialization */
+@@ -2495,9 +2486,7 @@ EXPORT_SYMBOL(ocelot_init);
+ void ocelot_deinit(struct ocelot *ocelot)
+ {
+-      struct list_head *pos, *tmp;
+       struct ocelot_port *port;
+-      struct ocelot_skb *entry;
+       int i;
+       cancel_delayed_work(&ocelot->stats_work);
+@@ -2509,14 +2498,7 @@ void ocelot_deinit(struct ocelot *ocelot
+       for (i = 0; i < ocelot->num_phys_ports; i++) {
+               port = ocelot->ports[i];
+-
+-              list_for_each_safe(pos, tmp, &port->skbs) {
+-                      entry = list_entry(pos, struct ocelot_skb, head);
+-
+-                      list_del(pos);
+-                      dev_kfree_skb_any(entry->skb);
+-                      kfree(entry);
+-              }
++              skb_queue_purge(&port->tx_skbs);
+       }
+ }
+ EXPORT_SYMBOL(ocelot_deinit);
+--- a/include/soc/mscc/ocelot.h
++++ b/include/soc/mscc/ocelot.h
+@@ -406,13 +406,6 @@ struct ocelot_ops {
+       int (*reset)(struct ocelot *ocelot);
+ };
+-struct ocelot_skb {
+-      struct list_head head;
+-      struct sk_buff *skb;
+-      u8 id;
+-};
+-
+-
+ struct ocelot_port {
+       struct ocelot                   *ocelot;
+@@ -425,7 +418,7 @@ struct ocelot_port {
+       u16                             vid;
+       u8                              ptp_cmd;
+-      struct list_head                skbs;
++      struct sk_buff_head             tx_skbs;
+       u8                              ts_id;
+ };
diff --git a/target/linux/layerscape/patches-5.4/701-net-0272-net-mscc-ocelot-tsn-configuration-support.patch b/target/linux/layerscape/patches-5.4/701-net-0272-net-mscc-ocelot-tsn-configuration-support.patch
new file mode 100644 (file)
index 0000000..e6d3bf7
--- /dev/null
@@ -0,0 +1,1986 @@
+From eb5556db4c4fb8dff9a7b716c66a1ea3d3e696ce Mon Sep 17 00:00:00 2001
+From: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
+Date: Fri, 29 Nov 2019 11:02:43 +0800
+Subject: [PATCH] net: mscc: ocelot: tsn configuration support
+
+Support TSN configuration for ocelot switch. The TSN configuration
+fucntions are based on tsn netlink interface, it can support Qbv,
+Qbu, Qci, 802.1CB, and Qav configuration now.
+
+Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
+---
+ drivers/net/ethernet/mscc/Makefile          |    1 +
+ drivers/net/ethernet/mscc/ocelot.c          |   11 +-
+ drivers/net/ethernet/mscc/ocelot.h          |    2 +
+ drivers/net/ethernet/mscc/ocelot_ana.h      |   25 +-
+ drivers/net/ethernet/mscc/ocelot_dev_gmii.h |  153 +++
+ drivers/net/ethernet/mscc/ocelot_tsn.c      | 1572 +++++++++++++++++++++++++++
+ drivers/net/ethernet/mscc/ocelot_tsn.h      |   51 +
+ include/soc/mscc/ocelot.h                   |   52 +-
+ 8 files changed, 1857 insertions(+), 10 deletions(-)
+ create mode 100644 drivers/net/ethernet/mscc/ocelot_dev_gmii.h
+ create mode 100644 drivers/net/ethernet/mscc/ocelot_tsn.c
+ create mode 100644 drivers/net/ethernet/mscc/ocelot_tsn.h
+
+--- a/drivers/net/ethernet/mscc/Makefile
++++ b/drivers/net/ethernet/mscc/Makefile
+@@ -2,4 +2,5 @@
+ obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot_common.o
+ mscc_ocelot_common-y := ocelot.o ocelot_io.o
+ mscc_ocelot_common-y += ocelot_regs.o ocelot_tc.o ocelot_police.o ocelot_ace.o ocelot_flower.o
++mscc_ocelot_common-y += ocelot_tsn.o
+ obj-$(CONFIG_MSCC_OCELOT_SWITCH_OCELOT) += ocelot_board.o
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -780,7 +780,7 @@ static void ocelot_set_rx_mode(struct ne
+        * forwarded to the CPU port.
+        */
+       val = GENMASK(ocelot->num_phys_ports - 1, 0);
+-      for (i = ocelot->num_phys_ports + 1; i < PGID_CPU; i++)
++      for (i = ocelot->num_phys_ports + 1; i < PGID_MCRED; i++)
+               ocelot_write_rix(ocelot, val, ANA_PGID_PGID, i);
+       __dev_mc_sync(dev, ocelot_mc_sync, ocelot_mc_unsync);
+@@ -2412,10 +2412,11 @@ int ocelot_init(struct ocelot *ocelot)
+                    SYS_FRM_AGING_MAX_AGE(307692), SYS_FRM_AGING);
+       /* Setup flooding PGIDs */
+-      ocelot_write_rix(ocelot, ANA_FLOODING_FLD_MULTICAST(PGID_MC) |
+-                       ANA_FLOODING_FLD_BROADCAST(PGID_MC) |
+-                       ANA_FLOODING_FLD_UNICAST(PGID_UC),
+-                       ANA_FLOODING, 0);
++      for (i = 0; i < 8; i++)
++              ocelot_write_rix(ocelot, ANA_FLOODING_FLD_MULTICAST(PGID_MC) |
++                               ANA_FLOODING_FLD_BROADCAST(PGID_MC) |
++                               ANA_FLOODING_FLD_UNICAST(PGID_UC),
++                               ANA_FLOODING, i);
+       ocelot_write(ocelot, ANA_FLOODING_IPMC_FLD_MC6_DATA(PGID_MCIPV6) |
+                    ANA_FLOODING_IPMC_FLD_MC6_CTRL(PGID_MC) |
+                    ANA_FLOODING_IPMC_FLD_MC4_DATA(PGID_MCIPV4) |
+--- a/drivers/net/ethernet/mscc/ocelot.h
++++ b/drivers/net/ethernet/mscc/ocelot.h
+@@ -27,11 +27,13 @@
+ #include "ocelot_qs.h"
+ #include "ocelot_tc.h"
+ #include "ocelot_ptp.h"
++#include "ocelot_dev_gmii.h"
+ #define PGID_AGGR    64
+ #define PGID_SRC     80
+ /* Reserved PGIDs */
++#define PGID_MCRED   (PGID_AGGR - 25)
+ #define PGID_CPU     (PGID_AGGR - 5)
+ #define PGID_UC      (PGID_AGGR - 4)
+ #define PGID_MC      (PGID_AGGR - 3)
+--- a/drivers/net/ethernet/mscc/ocelot_ana.h
++++ b/drivers/net/ethernet/mscc/ocelot_ana.h
+@@ -227,6 +227,11 @@
+ #define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(x)             ((x) & GENMASK(1, 0))
+ #define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD_M              GENMASK(1, 0)
++#define SFIDACCESS_CMD_IDLE                             0
++#define SFIDACCESS_CMD_READ                             1
++#define SFIDACCESS_CMD_WRITE                            2
++#define SFIDACCESS_CMD_INIT                           3
++
+ #define ANA_TABLES_SFIDTIDX_SGID_VALID                    BIT(26)
+ #define ANA_TABLES_SFIDTIDX_SGID(x)                       (((x) << 18) & GENMASK(25, 18))
+ #define ANA_TABLES_SFIDTIDX_SGID_M                        GENMASK(25, 18)
+@@ -252,15 +257,23 @@
+ #define ANA_SG_CONFIG_REG_3_LIST_LENGTH_M                 GENMASK(18, 16)
+ #define ANA_SG_CONFIG_REG_3_LIST_LENGTH_X(x)              (((x) & GENMASK(18, 16)) >> 16)
+ #define ANA_SG_CONFIG_REG_3_GATE_ENABLE                   BIT(20)
+-#define ANA_SG_CONFIG_REG_3_INIT_IPS(x)                   (((x) << 24) & GENMASK(27, 24))
+-#define ANA_SG_CONFIG_REG_3_INIT_IPS_M                    GENMASK(27, 24)
+-#define ANA_SG_CONFIG_REG_3_INIT_IPS_X(x)                 (((x) & GENMASK(27, 24)) >> 24)
+-#define ANA_SG_CONFIG_REG_3_INIT_GATE_STATE               BIT(28)
++#define ANA_SG_CONFIG_REG_3_INIT_IPS(x)                   (((x) << 21) & GENMASK(24, 21))
++#define ANA_SG_CONFIG_REG_3_INIT_IPS_M                    GENMASK(24, 21)
++#define ANA_SG_CONFIG_REG_3_INIT_IPS_X(x)                 (((x) & GENMASK(24, 21)) >> 21)
++#define ANA_SG_CONFIG_REG_3_IPV_VALID                     BIT(24)
++#define ANA_SG_CONFIG_REG_3_IPV_INVALID(x)              (((x) << 24) & GENMASK(24, 24))
++#define ANA_SG_CONFIG_REG_3_INIT_IPV(x)                   (((x) << 21) & GENMASK(23, 21))
++#define ANA_SG_CONFIG_REG_3_INIT_IPV_M                    GENMASK(23, 21)
++#define ANA_SG_CONFIG_REG_3_INIT_IPV_X(x)                 (((x) & GENMASK(23, 21)) >> 21)
++#define ANA_SG_CONFIG_REG_3_INIT_GATE_STATE               BIT(25)
+ #define ANA_SG_GCL_GS_CONFIG_RSZ                          0x4
+ #define ANA_SG_GCL_GS_CONFIG_IPS(x)                       ((x) & GENMASK(3, 0))
+ #define ANA_SG_GCL_GS_CONFIG_IPS_M                        GENMASK(3, 0)
++#define ANA_SG_GCL_GS_CONFIG_IPV_VALID                    BIT(3)
++#define ANA_SG_GCL_GS_CONFIG_IPV(x)                       ((x) & GENMASK(2, 0))
++#define ANA_SG_GCL_GS_CONFIG_IPV_M                        GENMASK(2, 0)
+ #define ANA_SG_GCL_GS_CONFIG_GATE_STATE                   BIT(4)
+ #define ANA_SG_GCL_TI_CONFIG_RSZ                          0x4
+@@ -271,6 +284,10 @@
+ #define ANA_SG_STATUS_REG_3_IPS(x)                        (((x) << 20) & GENMASK(23, 20))
+ #define ANA_SG_STATUS_REG_3_IPS_M                         GENMASK(23, 20)
+ #define ANA_SG_STATUS_REG_3_IPS_X(x)                      (((x) & GENMASK(23, 20)) >> 20)
++#define ANA_SG_STATUS_REG_3_IPV_VALID                     BIT(23)
++#define ANA_SG_STATUS_REG_3_IPV(x)                        (((x) << 20) & GENMASK(22, 20))
++#define ANA_SG_STATUS_REG_3_IPV_M                         GENMASK(22, 20)
++#define ANA_SG_STATUS_REG_3_IPV_X(x)                      (((x) & GENMASK(22, 20)) >> 20)
+ #define ANA_SG_STATUS_REG_3_CONFIG_PENDING                BIT(24)
+ #define ANA_PORT_VLAN_CFG_GSZ                             0x100
+--- /dev/null
++++ b/drivers/net/ethernet/mscc/ocelot_dev_gmii.h
+@@ -0,0 +1,153 @@
++/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
++/* Microsemi Ocelot Switch driver
++ *
++ * Copyright (c) 2017 Microsemi Corporation
++ */
++
++#ifndef _MSCC_OCELOT_DEV_GMII_H_
++#define _MSCC_OCELOT_DEV_GMII_H_
++
++#define DEV_GMII_PORT_MODE_CLOCK_CFG                      0x0
++
++#define DEV_GMII_PORT_MODE_CLOCK_CFG_MAC_TX_RST           BIT(5)
++#define DEV_GMII_PORT_MODE_CLOCK_CFG_MAC_RX_RST           BIT(4)
++#define DEV_GMII_PORT_MODE_CLOCK_CFG_PORT_RST             BIT(3)
++#define DEV_GMII_PORT_MODE_CLOCK_CFG_PHY_RST              BIT(2)
++#define DEV_GMII_PORT_MODE_CLOCK_CFG_LINK_SPEED(x)        ((x) & GENMASK(1, 0))
++#define DEV_GMII_PORT_MODE_CLOCK_CFG_LINK_SPEED_M         GENMASK(1, 0)
++
++#define DEV_GMII_PORT_MODE_PORT_MISC                      0x4
++
++#define DEV_GMII_PORT_MODE_PORT_MISC_MPLS_RX_ENA          BIT(5)
++#define DEV_GMII_PORT_MODE_PORT_MISC_FWD_ERROR_ENA        BIT(4)
++#define DEV_GMII_PORT_MODE_PORT_MISC_FWD_PAUSE_ENA        BIT(3)
++#define DEV_GMII_PORT_MODE_PORT_MISC_FWD_CTRL_ENA         BIT(2)
++#define DEV_GMII_PORT_MODE_PORT_MISC_GMII_LOOP_ENA        BIT(1)
++#define DEV_GMII_PORT_MODE_PORT_MISC_DEV_LOOP_ENA         BIT(0)
++
++#define DEV_GMII_PORT_MODE_EVENTS                         0x8
++
++#define DEV_GMII_PORT_MODE_EEE_CFG                        0xc
++
++#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_ENA                BIT(22)
++#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_AGE(x)       (((x) << 15) & GENMASK(21, 15))
++#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_AGE_M        GENMASK(21, 15)
++#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_AGE_X(x)     (((x) & GENMASK(21, 15)) >> 15)
++#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_WAKEUP(x)    (((x) << 8) & GENMASK(14, 8))
++#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_WAKEUP_M     GENMASK(14, 8)
++#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_WAKEUP_X(x)  (((x) & GENMASK(14, 8)) >> 8)
++#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_HOLDOFF(x)   (((x) << 1) & GENMASK(7, 1))
++#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_HOLDOFF_M    GENMASK(7, 1)
++#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_HOLDOFF_X(x) (((x) & GENMASK(7, 1)) >> 1)
++#define DEV_GMII_PORT_MODE_EEE_CFG_PORT_LPI               BIT(0)
++
++#define DEV_GMII_PORT_MODE_RX_PATH_DELAY                  0x10
++
++#define DEV_GMII_PORT_MODE_TX_PATH_DELAY                  0x14
++
++#define DEV_GMII_PORT_MODE_PTP_PREDICT_CFG                0x18
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_ENA_CFG               0x1c
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_ENA_CFG_RX_ENA        BIT(4)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_ENA_CFG_TX_ENA        BIT(0)
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG              0x20
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG_FC_WORD_SYNC_ENA BIT(8)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG_GIGA_MODE_ENA BIT(4)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG_FDX_ENA      BIT(0)
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_MAXLEN_CFG            0x24
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG              0x28
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_TAG_ID(x)    (((x) << 16) & GENMASK(31, 16))
++#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_TAG_ID_M     GENMASK(31, 16)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_TAG_ID_X(x)  (((x) & GENMASK(31, 16)) >> 16)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_PB_ENA       BIT(1)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_VLAN_AWR_ENA BIT(0)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA BIT(2)
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_ADV_CHK_CFG           0x2c
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_ADV_CHK_CFG_LEN_DROP_ENA BIT(0)
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG               0x30
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RESTORE_OLD_IPG_CHECK BIT(17)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_REDUCED_TX_IFG BIT(16)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_TX_IFG(x)     (((x) << 8) & GENMASK(12, 8))
++#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_TX_IFG_M      GENMASK(12, 8)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_TX_IFG_X(x)   (((x) & GENMASK(12, 8)) >> 8)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG2(x)    (((x) << 4) & GENMASK(7, 4))
++#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG2_M     GENMASK(7, 4)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG2_X(x)  (((x) & GENMASK(7, 4)) >> 4)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG1(x)    ((x) & GENMASK(3, 0))
++#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG1_M     GENMASK(3, 0)
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG               0x34
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_BYPASS_COL_SYNC BIT(26)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_OB_ENA        BIT(25)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_WEXC_DIS      BIT(24)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED(x)       (((x) << 16) & GENMASK(23, 16))
++#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED_M        GENMASK(23, 16)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED_X(x)     (((x) & GENMASK(23, 16)) >> 16)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED_LOAD     BIT(12)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_RETRY_AFTER_EXC_COL_ENA BIT(8)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_LATE_COL_POS(x) ((x) & GENMASK(6, 0))
++#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_LATE_COL_POS_M GENMASK(6, 0)
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_DBG_CFG               0x38
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_DBG_CFG_TBI_MODE      BIT(4)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_DBG_CFG_IFG_CRS_EXT_CHK_ENA BIT(0)
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_FC_MAC_LOW_CFG        0x3c
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_FC_MAC_HIGH_CFG       0x40
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY                0x44
++
++#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_IPG_SHRINK_STICKY BIT(9)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_PREAM_SHRINK_STICKY BIT(8)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_CARRIER_EXT_STICKY BIT(7)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_CARRIER_EXT_ERR_STICKY BIT(6)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_JUNK_STICKY BIT(5)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_RETRANSMIT_STICKY BIT(4)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_JAM_STICKY  BIT(3)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_FIFO_OFLW_STICKY BIT(2)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_FRM_LEN_OVR_STICKY BIT(1)
++#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_ABORT_STICKY BIT(0)
++
++#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG                  0x48
++
++#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA        BIT(0)
++#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA        BIT(4)
++#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG_KEEP_S_AFTER_D   BIT(8)
++
++#define DEV_GMII_MM_CONFIG_VERIF_CONFIG                   0x4c
++
++#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_DIS    BIT(0)
++#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME(x) (((x) << 4) & GENMASK(11, 4))
++#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME_M GENMASK(11, 4)
++#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME_X(x) (((x) & GENMASK(11, 4)) >> 4)
++#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS(x) (((x) << 12) & GENMASK(13, 12))
++#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS_M GENMASK(13, 12)
++#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS_X(x) (((x) & GENMASK(13, 12)) >> 12)
++
++#define DEV_GMII_MM_STATISTICS_MM_STATUS                  0x50
++
++#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STATUS BIT(0)
++#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STICKY BIT(4)
++#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE(x) (((x) << 8) & GENMASK(10, 8))
++#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE_M GENMASK(10, 8)
++#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE_X(x) (((x) & GENMASK(10, 8)) >> 8)
++#define DEV_GMII_MM_STATISTICS_MM_STATUS_UNEXP_RX_PFRM_STICKY BIT(12)
++#define DEV_GMII_MM_STATISTICS_MM_STATUS_UNEXP_TX_PFRM_STICKY BIT(16)
++#define DEV_GMII_MM_STATISTICS_MM_STATUS_MM_RX_FRAME_STATUS BIT(20)
++#define DEV_GMII_MM_STATISTICS_MM_STATUS_MM_TX_FRAME_STATUS BIT(24)
++#define DEV_GMII_MM_STATISTICS_MM_STATUS_MM_TX_PRMPT_STATUS BIT(28)
++
++#endif
+--- /dev/null
++++ b/drivers/net/ethernet/mscc/ocelot_tsn.c
+@@ -0,0 +1,1572 @@
++// SPDX-License-Identifier: (GPL-2.0 OR MIT)
++/* Felix Switch TSN driver
++ *
++ * Copyright (c) 2018 Microsemi Corporation
++ * Copyright 2018-2019 NXP
++ */
++
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/iopoll.h>
++#include "ocelot.h"
++#include <soc/mscc/ocelot_sys.h>
++#include "ocelot_ana.h"
++#include "ocelot_qsys.h"
++#include "ocelot_rew.h"
++#include "ocelot_dev_gmii.h"
++#include "ocelot_tsn.h"
++
++#define MSCC_NUM_OUT_PORT 4 /* Number of physical output ports */
++#define SE_IX_PORT 64
++
++/* MSCC TSN parameters limited */
++#define NUM_MSCC_QOS_PRIO 8
++#define MSCC_PSFP_SFID_NUM 176
++#define MSCC_FRER_SSID_NUM 128
++
++/* Using the max number of MSCC_PSFP_SFID_NUM and MSCC_FRER_SSID_NUM */
++#define MSCC_STREAM_HANDLE_NUM        MSCC_PSFP_SFID_NUM
++
++int streamhandle_map[MSCC_STREAM_HANDLE_NUM] = {0};
++static struct mscc_switch_capa capa __ro_after_init = {
++      .num_tas_gcl    = 64,
++      .tas_ct_min     = 100,
++      .tas_ct_max     = 1000000000,
++      .tas_cte_max    = 999999999,
++      .tas_it_max     = 999999999,
++      .tas_it_min     = 1000,
++      .num_hsch       = 72,
++      .num_psfp_sfid  = MSCC_PSFP_SFID_NUM,
++      .num_psfp_sgid  = 184,
++      .psfp_fmi_max   = 246,
++      .psfp_fmi_min   = 63,
++      .num_sgi_gcl    = 4,
++      .sgi_ct_min     = 5000,
++      .sgi_ct_max     = 1000000000,
++      .sgi_cte_max    = 999999999,
++      .qos_pol_max    = 383,
++      /* Maximum allowed value of committed burst size(CBS) is 240 KB */
++      .pol_cbs_max    = 60,
++      /* Maximum allowed value of excess burst size(EBS) is 240 KB */
++      .pol_pbs_max    = 60,
++      .num_frer_ssid  = MSCC_FRER_SSID_NUM,
++      .frer_seq_len_min = 1,
++      .frer_seq_len_max = 28,
++      .frer_his_len_min = 1,
++      .frer_his_len_max = 32,
++      .qos_dscp_max   = 63,
++      .qos_cos_max    = NUM_MSCC_QOS_PRIO - 1,
++      .qos_dp_max     = 1,
++};
++
++static int qos_port_tas_gcl_set(struct ocelot *ocelot, const u8 gcl_ix,
++                              struct tsn_qbv_entry *control_list)
++{
++      if (gcl_ix >= capa.num_tas_gcl) {
++              dev_err(ocelot->dev, "Invalid gcl ix %u\n", gcl_ix);
++              return -EINVAL;
++      }
++      if (control_list->time_interval < capa.tas_it_min ||
++          control_list->time_interval > capa.tas_it_max) {
++              dev_err(ocelot->dev, "Invalid time_interval %u\n",
++                      control_list->time_interval);
++
++              return -EINVAL;
++      }
++
++      ocelot_write(ocelot,
++                   QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM(gcl_ix) |
++                   QSYS_GCL_CFG_REG_1_GATE_STATE(control_list->gate_state),
++                   QSYS_GCL_CFG_REG_1);
++
++      ocelot_write(ocelot,
++                   control_list->time_interval,
++                   QSYS_GCL_CFG_REG_2);
++
++      return 0;
++}
++
++static u32 tas_read_status(struct ocelot *ocelot)
++{
++      u32 val;
++
++      val = ocelot_read(ocelot, QSYS_TAS_PARAM_CFG_CTRL);
++
++      return val;
++}
++
++int ocelot_qbv_set(struct ocelot *ocelot, int port_id,
++                 struct tsn_qbv_conf *shaper_config)
++{
++      struct tsn_qbv_basic *admin_basic = &shaper_config->admin;
++      struct tsn_qbv_entry *control_list = admin_basic->control_list;
++      u32 base_time_nsec = admin_basic->base_time % 1000000000;
++      u64 base_time_sec = admin_basic->base_time / 1000000000;
++      u64 cur_time;
++      u32 val;
++      u8 speed;
++      int i;
++      int ret;
++
++      if (admin_basic->control_list_length > capa.num_tas_gcl) {
++              dev_err(ocelot->dev,
++                      "Invalid admin_control_list_length %u\n",
++                      admin_basic->control_list_length);
++              return -EINVAL;
++      }
++
++      if ((admin_basic->cycle_time < capa.tas_ct_min ||
++           admin_basic->cycle_time > capa.tas_ct_max) &&
++          shaper_config->gate_enabled) {
++              dev_err(ocelot->dev, "Invalid admin_cycle_time %u ns\n",
++                      admin_basic->cycle_time);
++              return -EINVAL;
++      }
++      if (admin_basic->cycle_time_extension > capa.tas_cte_max) {
++              dev_err(ocelot->dev,
++                      "Invalid admin_cycle_time_extension %u\n",
++                      admin_basic->cycle_time_extension);
++              return -EINVAL;
++      }
++
++      cur_time = ocelot_read(ocelot, PTP_CUR_SEC_MSB);
++      cur_time = cur_time << 32;
++      cur_time += ocelot_read(ocelot, PTP_CUR_SEC_LSB);
++
++      if (base_time_sec < cur_time) {
++              base_time_sec = cur_time;
++              base_time_nsec = ocelot_read(ocelot, PTP_CUR_NSEC);
++      }
++
++      /* Select port */
++      ocelot_rmw(ocelot,
++                 QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port_id),
++                 QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M,
++                 QSYS_TAS_PARAM_CFG_CTRL);
++
++      val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8);
++      if (val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING) {
++              ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE,
++                             QSYS_TAG_CONFIG, port_id);
++      }
++
++      if (!shaper_config->gate_enabled)
++              admin_basic->gate_states = 0xff;
++
++      val = ocelot_read_gix(ocelot, ANA_PFC_PFC_CFG, port_id);
++      speed = ANA_PFC_PFC_CFG_FC_LINK_SPEED(val);
++
++      ocelot_rmw_rix(ocelot,
++                     (shaper_config->gate_enabled ?
++                      QSYS_TAG_CONFIG_ENABLE : 0) |
++                     QSYS_TAG_CONFIG_INIT_GATE_STATE(admin_basic->gate_states) |
++                     QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES(0xff) |
++                     QSYS_TAG_CONFIG_LINK_SPEED(speed),
++                     QSYS_TAG_CONFIG_ENABLE |
++                     QSYS_TAG_CONFIG_INIT_GATE_STATE_M |
++                     QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_M |
++                     QSYS_TAG_CONFIG_LINK_SPEED_M,
++                     QSYS_TAG_CONFIG,
++                     port_id);
++
++      ocelot_write_rix(ocelot, shaper_config->maxsdu,
++                       QSYS_PORT_MAX_SDU, port_id);
++      /* TODO: add queue max SDU set */
++
++      if (shaper_config->gate_enabled) {
++              ocelot_write(ocelot, base_time_nsec,
++                           QSYS_PARAM_CFG_REG_1);
++
++              ocelot_write(ocelot, base_time_sec & GENMASK(31, 0),
++                           QSYS_PARAM_CFG_REG_2);
++
++              ocelot_write(ocelot,
++                           QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(base_time_sec >> 32) |
++                           QSYS_PARAM_CFG_REG_3_LIST_LENGTH(admin_basic->control_list_length),
++                           QSYS_PARAM_CFG_REG_3);
++
++              ocelot_write(ocelot, admin_basic->cycle_time,
++                           QSYS_PARAM_CFG_REG_4);
++
++              ocelot_write(ocelot, admin_basic->cycle_time_extension,
++                           QSYS_PARAM_CFG_REG_5);
++
++              for (i = 0; i < admin_basic->control_list_length; i++) {
++                      qos_port_tas_gcl_set(ocelot, i, control_list);
++                      control_list++;
++              }
++
++              /* Start configuration change */
++              ocelot_rmw(ocelot,
++                         QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
++                         QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
++                         QSYS_TAS_PARAM_CFG_CTRL);
++
++              ret = readx_poll_timeout(tas_read_status, ocelot, val,
++                                       !(QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE
++                                       & val), 10, 100000);
++              return ret;
++      }
++
++      return 0;
++}
++
++int ocelot_qbv_get(struct ocelot *ocelot, int port_id,
++                 struct tsn_qbv_conf *shaper_config)
++{
++      u32 val, reg;
++      int i;
++      u32 base_timel;
++      u32 base_timeh;
++      struct tsn_qbv_basic *admin = &shaper_config->admin;
++      struct tsn_qbv_entry *list;
++
++      ocelot_rmw(ocelot,
++                 QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port_id),
++                 QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M,
++                 QSYS_TAS_PARAM_CFG_CTRL);
++
++      val = ocelot_read_rix(ocelot, QSYS_TAG_CONFIG, port_id);
++      shaper_config->gate_enabled = (val & QSYS_TAG_CONFIG_ENABLE);
++      admin->gate_states = QSYS_TAG_CONFIG_INIT_GATE_STATE_X(val);
++
++      base_timel = ocelot_read(ocelot, QSYS_PARAM_CFG_REG_1);
++      base_timeh = ocelot_read(ocelot, QSYS_PARAM_CFG_REG_2);
++      reg = ocelot_read(ocelot, QSYS_PARAM_CFG_REG_3);
++      admin->base_time = base_timeh |
++              (((u64)QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(reg)) << 32);
++
++      admin->base_time = (admin->base_time * 1000000000) + base_timel;
++
++      admin->control_list_length =
++              QSYS_PARAM_CFG_REG_3_LIST_LENGTH_X(reg);
++
++      admin->cycle_time = ocelot_read(ocelot, QSYS_PARAM_CFG_REG_4);
++      admin->cycle_time_extension =
++              ocelot_read(ocelot, QSYS_PARAM_CFG_REG_5);
++
++      list = kmalloc_array(admin->control_list_length,
++                           sizeof(struct tsn_qbv_entry), GFP_KERNEL);
++      admin->control_list = list;
++
++      for (i = 0; i < admin->control_list_length; i++) {
++              ocelot_rmw(ocelot,
++                         QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM(i),
++                         QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM_M,
++                         QSYS_GCL_CFG_REG_1);
++
++              list->time_interval =
++                      ocelot_read(ocelot, QSYS_GCL_CFG_REG_2);
++
++              reg = ocelot_read(ocelot, QSYS_GCL_CFG_REG_1);
++              list->gate_state = QSYS_GCL_CFG_REG_1_GATE_STATE_X(reg);
++
++              list++;
++      }
++
++      return 0;
++}
++
++static int qbv_get_gatelist(struct ocelot *ocelot,
++                          struct tsn_qbv_basic *oper)
++{
++      u32 base_timel;
++      u32 base_timeh;
++      u32 val;
++      struct tsn_qbv_entry *glist;
++      int i;
++
++      base_timel = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_1);
++      base_timeh = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_2);
++      val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_3);
++      oper->base_time = base_timeh;
++      oper->base_time +=
++              ((u64)QSYS_PARAM_STATUS_REG_3_BASE_TIME_SEC_MSB(val)) <<
++              32;
++      oper->base_time = (oper->base_time * 1000000000) + base_timel;
++
++      oper->control_list_length =
++              QSYS_PARAM_STATUS_REG_3_LIST_LENGTH_X(val);
++
++      oper->cycle_time = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_4);
++      oper->cycle_time_extension = ocelot_read(ocelot,
++                                               QSYS_PARAM_STATUS_REG_5);
++
++      val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8);
++      oper->gate_states = QSYS_PARAM_STATUS_REG_8_OPER_GATE_STATE_X(val);
++
++      glist = kmalloc_array(oper->control_list_length,
++                            sizeof(struct tsn_qbv_entry), GFP_KERNEL);
++
++      oper->control_list = glist;
++
++      for (i = 0; i < oper->control_list_length; i++) {
++              ocelot_rmw(ocelot,
++                         QSYS_GCL_STATUS_REG_1_GCL_ENTRY_NUM(i),
++                         QSYS_GCL_STATUS_REG_1_GCL_ENTRY_NUM_M,
++                         QSYS_GCL_STATUS_REG_1);
++
++              val = ocelot_read(ocelot, QSYS_GCL_STATUS_REG_2);
++              glist->time_interval = val;
++              val = ocelot_read(ocelot, QSYS_GCL_STATUS_REG_1);
++              glist->gate_state =
++                      QSYS_GCL_STATUS_REG_1_GATE_STATE_X(val);
++
++              glist++;
++      }
++
++      return 0;
++}
++
++int ocelot_qbv_get_status(struct ocelot *ocelot, int port_id,
++                        struct tsn_qbv_status *qbvstatus)
++{
++      struct tsn_qbv_basic *oper = &qbvstatus->oper;
++      u32 val;
++      ptptime_t cur_time;
++
++      ocelot_rmw(ocelot,
++                 QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port_id),
++                 QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M,
++                 QSYS_TAS_PARAM_CFG_CTRL);
++
++      qbvstatus->supported_list_max = capa.num_tas_gcl;
++
++      val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8);
++      qbvstatus->config_pending =
++              (val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING) ? 1 : 0;
++
++      qbvstatus->config_change_time =
++              ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_7);
++
++      qbvstatus->config_change_time +=
++              ((u64)QSYS_PARAM_STATUS_REG_8_CFG_CHG_TIME_SEC_MSB(val)) <<
++              32;
++
++      qbvstatus->config_change_time =
++              (qbvstatus->config_change_time * 1000000000) +
++              ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_6);
++
++      qbvstatus->config_change_error =
++              ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_9);
++
++      cur_time = ocelot_read(ocelot, PTP_CUR_SEC_MSB);
++      cur_time = cur_time << 32;
++      cur_time += ocelot_read(ocelot, PTP_CUR_SEC_LSB);
++      cur_time = (cur_time * 1000000000) +
++                 ocelot_read(ocelot, PTP_CUR_NSEC);
++
++      qbvstatus->current_time = cur_time;
++      qbv_get_gatelist(ocelot, oper);
++
++      return 0;
++}
++
++int ocelot_cut_thru_set(struct ocelot *ocelot, int port_id, u8 cut_thru)
++{
++      ocelot_write_rix(ocelot, cut_thru, ANA_CUT_THRU_CFG, port_id);
++
++      return 0;
++}
++
++static int qos_shaper_conf_set(struct ocelot *ocelot, int port,
++                             u32 port_ix, u8 percent)
++{
++      u32 val;
++      int speed;
++      u32 cbs = 0;
++      u32 cir = 0;
++
++      if (percent > 100) {
++              dev_err(ocelot->dev, "percentage %d larger than 100\n",
++                      percent);
++              return -EINVAL;
++      }
++      if (port_ix >= capa.num_hsch) {
++              dev_err(ocelot->dev,
++                      "CIR_CFG: id %d is exceed num of HSCH instance\n",
++                      port_ix);
++              return -EINVAL;
++      }
++
++      val = ocelot_read_gix(ocelot, ANA_PFC_PFC_CFG, port);
++      speed = ANA_PFC_PFC_CFG_FC_LINK_SPEED(val);
++      switch (speed) {
++      case OCELOT_SPEED_10:
++              cir = 10000;
++              break;
++      case OCELOT_SPEED_100:
++              cir = 100000;
++              break;
++      case OCELOT_SPEED_1000:
++              cir = 1000000;
++              break;
++      case OCELOT_SPEED_2500:
++              cir = 2500000;
++              break;
++      }
++
++      cir = cir * percent / 100;
++      cir = DIV_ROUND_UP(cir, 100);  /* Rate unit is 100 kbps */
++      cir = (cir ? cir : 1);              /* Avoid using zero rate */
++      cbs = DIV_ROUND_UP(cbs, 4096); /* Burst unit is 4kB */
++      cbs = (cbs ? cbs : 1);          /* Avoid using zero burst size */
++      cir = min_t(u32, GENMASK(15, 0), cir);
++      cbs = min_t(u32, GENMASK(6, 0), cbs);
++      ocelot_write_gix(ocelot,
++                       QSYS_CIR_CFG_CIR_RATE(cir) |
++                       QSYS_CIR_CFG_CIR_BURST(cbs),
++                       QSYS_CIR_CFG,
++                       port_ix);
++
++      return 0;
++}
++
++static int qos_shaper_conf_get(struct ocelot *ocelot, int port,
++                             u32 port_ix)
++{
++      u32 val;
++      u32 bandwidth = 0;
++      u32 cir = 0;
++      int percentage;
++      int speed;
++
++      if (port_ix >= capa.num_hsch) {
++              dev_err(ocelot->dev,
++                      "CIR_CFG: id %d is exceed num of HSCH instance\n",
++                      port_ix);
++              return -EINVAL;
++      }
++
++      val = ocelot_read_gix(ocelot, ANA_PFC_PFC_CFG, port);
++      speed = ANA_PFC_PFC_CFG_FC_LINK_SPEED(val);
++      switch (speed) {
++      case OCELOT_SPEED_10:
++              bandwidth = 10000;
++              break;
++      case OCELOT_SPEED_100:
++              bandwidth = 100000;
++              break;
++      case OCELOT_SPEED_1000:
++              bandwidth = 1000000;
++              break;
++      case OCELOT_SPEED_2500:
++              bandwidth = 2500000;
++              break;
++      }
++
++      val = ocelot_read_gix(ocelot, QSYS_CIR_CFG, port_ix);
++
++      cir = QSYS_CIR_CFG_CIR_RATE_X(val);
++      cir *= 100;
++      percentage = cir * 100 / bandwidth;
++
++      return percentage;
++}
++
++int ocelot_cbs_set(struct ocelot *ocelot, int port, u8 tc, u8 bw)
++{
++      if (tc > capa.qos_cos_max) {
++              dev_err(ocelot->dev, "Invalid tc: %u\n", tc);
++              return -EINVAL;
++      }
++
++      qos_shaper_conf_set(ocelot, port, port * 8 + tc, bw);
++
++      ocelot_rmw_gix(ocelot,
++                     QSYS_SE_CFG_SE_AVB_ENA,
++                     QSYS_SE_CFG_SE_AVB_ENA,
++                     QSYS_SE_CFG,
++                     port * 8 + tc);
++
++      return 0;
++}
++
++int ocelot_cbs_get(struct ocelot *ocelot, int port, u8 tc)
++{
++      int ret;
++
++      if (tc > capa.qos_cos_max) {
++              dev_err(ocelot->dev, "Invalid tc: %u\n", tc);
++              return -EINVAL;
++      }
++
++      ret = qos_shaper_conf_get(ocelot, port, port * 8 + tc);
++
++      return ret;
++}
++
++int ocelot_qbu_set(struct ocelot *ocelot, int port, u8 preemptible)
++{
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++
++      ocelot_port_rmwl(ocelot_port,
++                       DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA |
++                       DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA,
++                       DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA |
++                       DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA,
++                       DEV_GMII_MM_CONFIG_ENABLE_CONFIG);
++
++      ocelot_rmw_rix(ocelot,
++                     QSYS_PREEMPTION_CFG_P_QUEUES(preemptible),
++                     QSYS_PREEMPTION_CFG_P_QUEUES_M,
++                     QSYS_PREEMPTION_CFG,
++                     port);
++
++      return 0;
++}
++
++int ocelot_qbu_get(struct ocelot *ocelot, int port,
++                 struct tsn_preempt_status *c)
++{
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++      u32 val;
++
++      val = ocelot_read_rix(ocelot,
++                            QSYS_PREEMPTION_CFG,
++                            port);
++
++      c->admin_state = QSYS_PREEMPTION_CFG_P_QUEUES(val);
++      c->hold_advance = QSYS_PREEMPTION_CFG_HOLD_ADVANCE_X(val);
++
++      val = ocelot_port_readl(ocelot_port,
++                              DEV_GMII_MM_STATISTICS_MM_STATUS);
++      c->preemption_active =
++              DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STATUS & val;
++
++      return 0;
++}
++
++int ocelot_cb_streamid_get(struct ocelot *ocelot, int port, u32 index,
++                         struct tsn_cb_streamid *streamid)
++{
++      u32 m_index;
++      u32 bucket;
++      u32 val, dst, reg;
++      u64 dmac;
++      u32 ldmac, hdmac;
++
++      if (index >= MSCC_STREAM_HANDLE_NUM) {
++              dev_err(ocelot->dev,
++                      "Invalid stream handle %u, maximum:%u\n",
++                      index, MSCC_STREAM_HANDLE_NUM - 1);
++              return -EINVAL;
++      }
++
++      index = streamhandle_map[index];
++      m_index = index / 4;
++      bucket =  index % 4;
++      streamid->type = 1;
++      regmap_field_write(ocelot->regfields[ANA_TABLES_MACTINDX_BUCKET],
++                         bucket);
++      regmap_field_write(ocelot->regfields[ANA_TABLES_MACTINDX_M_INDEX],
++                         m_index);
++
++      /*READ command MACACCESS.VALID(11 bit) must be 0 */
++      ocelot_write(ocelot,
++                   ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
++                   ANA_TABLES_MACACCESS);
++
++      val = ocelot_read(ocelot, ANA_TABLES_MACACCESS);
++      dst = ANA_TABLES_MACACCESS_DEST_IDX_X(val);
++      reg = ocelot_read_rix(ocelot, ANA_PGID_PGID, dst);
++      streamid->ofac_oport = ANA_PGID_PGID_PGID(reg);
++
++      /*Get the entry's MAC address and VLAN id*/
++      ldmac = ocelot_read(ocelot, ANA_TABLES_MACLDATA);
++      val = ocelot_read(ocelot, ANA_TABLES_MACHDATA);
++      val &= 0x1fffffff;
++      hdmac = val & 0xffff;
++      dmac = hdmac;
++      dmac = (dmac << 32) | ldmac;
++      streamid->para.nid.dmac = dmac;
++
++      streamid->para.nid.vid = ANA_TABLES_MACHDATA_VID_X(val);
++
++      val = ocelot_read(ocelot, ANA_TABLES_STREAMDATA);
++      if (!(val & ANA_TABLES_STREAMDATA_SFID_VALID))
++              return -EINVAL;
++
++      streamid->handle = ANA_TABLES_STREAMDATA_SFID(val);
++
++      return 0;
++}
++
++static int lookup_mactable(struct ocelot *ocelot, u16 vid, u64 mac)
++{
++      u32 mach, macl;
++      u32 reg1, reg2;
++      u32 index, bucket;
++
++      macl = mac & 0xffffffff;
++      mach = (mac >> 32) & 0xffff;
++      ocelot_write(ocelot, macl, ANA_TABLES_MACLDATA);
++      ocelot_write(ocelot, ANA_TABLES_MACHDATA_VID(vid) |
++                   ANA_TABLES_MACHDATA_MACHDATA(mach),
++                   ANA_TABLES_MACHDATA);
++
++      ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
++                   ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
++                   ANA_TABLES_MACACCESS);
++
++      reg1 = ocelot_read(ocelot, ANA_TABLES_MACLDATA);
++      reg2 = ocelot_read(ocelot, ANA_TABLES_MACHDATA);
++      if (reg1 == 0 && reg2 == 0)
++              return -1;
++
++      regmap_field_read(ocelot->regfields[ANA_TABLES_MACTINDX_BUCKET],
++                        &bucket);
++      regmap_field_read(ocelot->regfields[ANA_TABLES_MACTINDX_M_INDEX],
++                        &index);
++
++      index = index * 4 + bucket;
++
++      return index;
++}
++
++int ocelot_cb_streamid_set(struct ocelot *ocelot, int port,
++                         u32 index, bool enable,
++                         struct tsn_cb_streamid *streamid)
++{
++      struct regmap_field *rf;
++      u16 vid;
++      u64 mac;
++      u32 macl, mach;
++      u32 dst_idx;
++      int idx;
++      u32 reg;
++      int sfid, ssid;
++      u32 m_index, bucket;
++
++      if (!enable) {
++              if (index >= MSCC_STREAM_HANDLE_NUM) {
++                      dev_err(ocelot->dev,
++                              "Invalid index %u, maximum:%u\n",
++                              index, MSCC_STREAM_HANDLE_NUM - 1);
++                      return -EINVAL;
++              }
++              m_index = streamhandle_map[index] / 4;
++              bucket =  streamhandle_map[index] % 4;
++              rf = ocelot->regfields[ANA_TABLES_MACTINDX_BUCKET];
++              regmap_field_write(rf, bucket);
++              rf = ocelot->regfields[ANA_TABLES_MACTINDX_M_INDEX];
++              regmap_field_write(rf, m_index);
++
++              /*READ command MACACCESS.VALID(11 bit) must be 0 */
++              ocelot_write(ocelot,
++                           ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
++                           ANA_TABLES_MACACCESS);
++
++              ocelot_write(ocelot,
++                           ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_FORGET),
++                           ANA_TABLES_MACACCESS);
++
++              streamhandle_map[index] = 0;
++
++              return 0;
++      }
++
++      if (streamid->type != 1) {
++              dev_err(ocelot->dev, "Invalid stream type\n");
++              return -EINVAL;
++      }
++
++      if (streamid->handle >= MSCC_STREAM_HANDLE_NUM) {
++              dev_err(ocelot->dev,
++                      "Invalid stream handle %u, maximum:%u\n",
++                      streamid->handle, MSCC_STREAM_HANDLE_NUM - 1);
++              return -EINVAL;
++      }
++
++      sfid = streamid->handle;
++      ssid = (streamid->handle < MSCC_FRER_SSID_NUM ?
++              streamid->handle : (MSCC_FRER_SSID_NUM - 1));
++
++      mac = streamid->para.nid.dmac;
++      macl = mac & 0xffffffff;
++      mach = (mac >> 32) & 0xffff;
++      vid = streamid->para.nid.vid;
++
++      idx = lookup_mactable(ocelot, vid, mac);
++
++      if (idx < 0) {
++              ocelot_write(ocelot, macl, ANA_TABLES_MACLDATA);
++              ocelot_write(ocelot, ANA_TABLES_MACHDATA_VID(vid) |
++                           ANA_TABLES_MACHDATA_MACHDATA(mach),
++                           ANA_TABLES_MACHDATA);
++
++              ocelot_write(ocelot,
++                           ANA_TABLES_STREAMDATA_SFID_VALID |
++                           ANA_TABLES_STREAMDATA_SFID(sfid) |
++                           ANA_TABLES_STREAMDATA_SSID_VALID |
++                           ANA_TABLES_STREAMDATA_SSID(ssid),
++                           ANA_TABLES_STREAMDATA);
++
++              dst_idx = port;
++              ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
++                           ANA_TABLES_MACACCESS_ENTRYTYPE(1) |
++                           ANA_TABLES_MACACCESS_DEST_IDX(dst_idx) |
++                           ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_LEARN),
++                           ANA_TABLES_MACACCESS);
++
++              ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
++                           ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
++                           ANA_TABLES_MACACCESS);
++
++              regmap_field_read(ocelot->regfields[ANA_TABLES_MACTINDX_BUCKET],
++                                &bucket);
++              regmap_field_read(ocelot->regfields[ANA_TABLES_MACTINDX_M_INDEX],
++                                &m_index);
++
++              m_index = m_index * 4 + bucket;
++              streamhandle_map[streamid->handle] = m_index;
++
++              return 0;
++      }
++
++      ocelot_write(ocelot,
++                   ANA_TABLES_STREAMDATA_SFID_VALID |
++                   ANA_TABLES_STREAMDATA_SFID(sfid) |
++                   ANA_TABLES_STREAMDATA_SSID_VALID |
++                   ANA_TABLES_STREAMDATA_SSID(ssid),
++                   ANA_TABLES_STREAMDATA);
++
++      reg = ocelot_read(ocelot, ANA_TABLES_MACACCESS);
++      dst_idx = ANA_TABLES_MACACCESS_DEST_IDX_X(reg);
++      ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
++                   ANA_TABLES_MACACCESS_ENTRYTYPE(1) |
++                   ANA_TABLES_MACACCESS_DEST_IDX(dst_idx) |
++                   ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_WRITE),
++                   ANA_TABLES_MACACCESS);
++
++      streamhandle_map[streamid->handle] = idx;
++
++      return 0;
++}
++
++static int streamid_multi_forward_set(struct ocelot *ocelot, u32 index,
++                                    u8 fwdmask)
++{
++      u32 m_index;
++      u32 bucket;
++      u32 val;
++      int m, n, i;
++      u8 pgid_val, fwdport;
++      u32 dst_idx;
++
++      m_index = index / 4;
++      bucket =  index % 4;
++
++      regmap_field_write(ocelot->regfields[ANA_TABLES_MACTINDX_BUCKET],
++                         bucket);
++      regmap_field_write(ocelot->regfields[ANA_TABLES_MACTINDX_M_INDEX],
++                         m_index);
++
++      /*READ command MACACCESS.VALID(11 bit) must be 0 */
++      ocelot_write(ocelot,
++                   ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
++                   ANA_TABLES_MACACCESS);
++
++      val = ocelot_read(ocelot, ANA_TABLES_MACACCESS);
++      fwdport = ANA_TABLES_MACACCESS_DEST_IDX_X(val);
++
++      if (fwdport >= MSCC_NUM_OUT_PORT) {
++              dst_idx = fwdport;
++              return 0;
++      }
++
++      fwdmask |= (1 << fwdport);
++
++      m = ocelot->num_phys_ports - 1;
++      for (i = m; i >= MSCC_NUM_OUT_PORT; i--) {
++              if (fwdmask & (1 << i)) {
++                      dst_idx = PGID_MCRED +
++                                (m - i) * MSCC_NUM_OUT_PORT +
++                                fwdport;
++
++                      pgid_val = (1 << i) | (1 << fwdport);
++                      break;
++              }
++      }
++
++      if (i < MSCC_NUM_OUT_PORT) {
++              m = PGID_MCRED +
++                  (ocelot->num_phys_ports - MSCC_NUM_OUT_PORT) *
++                  MSCC_NUM_OUT_PORT;
++
++              for (; i > 0; i--) {
++                      if (fwdmask & (1 << i))
++                              break;
++
++                      m = m + (1 << i) - 1;
++              }
++              n = fwdmask & ((1 << i) - 1);
++              if (n) {
++                      dst_idx = m + n;
++                      pgid_val = fwdmask & ((1 << MSCC_NUM_OUT_PORT) - 1);
++              } else {
++                      dst_idx = fwdport;
++              }
++      }
++
++      if (dst_idx < PGID_MCRED)
++              return 0;
++
++      ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
++                   ANA_TABLES_MACACCESS_ENTRYTYPE(1) |
++                   ANA_TABLES_MACACCESS_DEST_IDX(dst_idx) |
++                   ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_WRITE),
++                   ANA_TABLES_MACACCESS);
++
++      ocelot_write_rix(ocelot, pgid_val, ANA_PGID_PGID, dst_idx);
++
++      return 0;
++}
++
++int ocelot_qci_sfi_get(struct ocelot *ocelot, int port, u32 index,
++                     struct tsn_qci_psfp_sfi_conf *sfi)
++{
++      u32 val, reg, fmeter_id, max_sdu;
++      u32 sfid = index;
++
++      if (sfid >= capa.num_psfp_sfid) {
++              dev_err(ocelot->dev, "Invalid index %u, maximum:%u\n",
++                      sfid, capa.num_psfp_sfid);
++              return -EINVAL;
++      }
++
++      ocelot_rmw(ocelot,
++                 ANA_TABLES_SFIDTIDX_SFID_INDEX(sfid),
++                 ANA_TABLES_SFIDTIDX_SFID_INDEX_M,
++                 ANA_TABLES_SFIDTIDX);
++
++      ocelot_write(ocelot,
++                   ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_READ),
++                   ANA_TABLES_SFIDACCESS);
++
++      val = ocelot_read(ocelot, ANA_TABLES_SFIDTIDX);
++      if (!(val & ANA_TABLES_SFIDTIDX_SGID_VALID))
++              return -EINVAL;
++
++      sfi->stream_gate_instance_id = ANA_TABLES_SFIDTIDX_SGID_X(val);
++      fmeter_id = ANA_TABLES_SFIDTIDX_POL_IDX_X(val);
++      sfi->stream_filter.flow_meter_instance_id = fmeter_id;
++
++      reg = ocelot_read(ocelot, ANA_TABLES_SFIDACCESS);
++      max_sdu = ANA_TABLES_SFIDACCESS_MAX_SDU_LEN_X(reg);
++      sfi->stream_filter.maximum_sdu_size  = max_sdu;
++
++      if (reg & ANA_TABLES_SFIDACCESS_IGR_PRIO_MATCH_ENA)
++              sfi->priority_spec = ANA_TABLES_SFIDACCESS_IGR_PRIO_X(reg);
++      else
++              dev_err(ocelot->dev, "priority not enable\n");
++
++      return 0;
++}
++
++int ocelot_qci_sfi_set(struct ocelot *ocelot, int port,
++                     u32 index, bool enable,
++                     struct tsn_qci_psfp_sfi_conf *sfi)
++{
++      int igr_prio = sfi->priority_spec;
++      u16 sgid  = sfi->stream_gate_instance_id;
++      u16 pol_idx;
++      int fmid = sfi->stream_filter.flow_meter_instance_id;
++      u16 max_sdu_len = sfi->stream_filter.maximum_sdu_size;
++      int sfid = index;
++      u32 val;
++
++      if (fmid == -1)
++              pol_idx = capa.psfp_fmi_max;
++      else
++              pol_idx = (u16)fmid;
++
++      if (sfid >= capa.num_psfp_sfid) {
++              dev_err(ocelot->dev, "Invalid index %u, maximum:%u\n",
++                      sfid, capa.num_psfp_sfid);
++              return -EINVAL;
++      }
++
++      if (!enable) {
++              val = ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE);
++              ocelot_write(ocelot,
++                           ANA_TABLES_SFIDTIDX_SFID_INDEX(sfid),
++                           ANA_TABLES_SFIDTIDX);
++              ocelot_write(ocelot, val, ANA_TABLES_SFIDACCESS);
++              return 0;
++      }
++
++      if (sgid >= capa.num_psfp_sgid) {
++              dev_err(ocelot->dev, "Invalid sgid %u, maximum:%u\n",
++                      sgid, capa.num_psfp_sgid);
++              return -EINVAL;
++      }
++      if (pol_idx > capa.psfp_fmi_max || pol_idx < capa.psfp_fmi_min) {
++              dev_err(ocelot->dev, "Invalid pol_idx %u, range:%d~%d\n",
++                      pol_idx, capa.psfp_fmi_min, capa.psfp_fmi_max);
++              return -EINVAL;
++      }
++
++      ocelot_write(ocelot, ANA_TABLES_SFIDTIDX_SGID_VALID |
++                   ANA_TABLES_SFIDTIDX_SGID(sgid) |
++                   ((fmid != -1) ? ANA_TABLES_SFIDTIDX_POL_ENA : 0) |
++                   ANA_TABLES_SFIDTIDX_POL_IDX(pol_idx) |
++                   ANA_TABLES_SFIDTIDX_SFID_INDEX(sfid),
++                   ANA_TABLES_SFIDTIDX);
++
++      ocelot_write(ocelot,
++                   ((igr_prio >= 0) ?
++                    ANA_TABLES_SFIDACCESS_IGR_PRIO_MATCH_ENA : 0) |
++                   ANA_TABLES_SFIDACCESS_IGR_PRIO(igr_prio) |
++                   ANA_TABLES_SFIDACCESS_MAX_SDU_LEN(max_sdu_len) |
++                   ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE),
++                   ANA_TABLES_SFIDACCESS);
++
++      return 0;
++}
++
++int ocelot_qci_sfi_counters_get(struct ocelot *ocelot, int port,
++                              u32 index,
++                              struct tsn_qci_psfp_sfi_counters *sfi_cnt)
++{
++      u32 sfid = index;
++      u32 match, not_pass, not_pass_sdu, red;
++
++      if (sfid >= capa.num_psfp_sfid) {
++              dev_err(ocelot->dev, "Invalid index %u, maximum:%u\n",
++                      sfid, capa.num_psfp_sfid);
++              return -EINVAL;
++      }
++
++      ocelot_rmw(ocelot,
++                 SYS_STAT_CFG_STAT_VIEW(sfid),
++                 SYS_STAT_CFG_STAT_VIEW_M,
++                 SYS_STAT_CFG);
++
++      match = ocelot_read_gix(ocelot, SYS_CNT, 0x200);
++      not_pass = ocelot_read_gix(ocelot, SYS_CNT, 0x201);
++      not_pass_sdu = ocelot_read_gix(ocelot, SYS_CNT, 0x202);
++      red = ocelot_read_gix(ocelot, SYS_CNT, 0x203);
++
++      sfi_cnt->matching_frames_count = match;
++      sfi_cnt->not_passing_frames_count = not_pass;
++      sfi_cnt->not_passing_sdu_count = not_pass_sdu;
++      sfi_cnt->red_frames_count  =  red;
++
++      sfi_cnt->passing_frames_count = match - not_pass;
++      sfi_cnt->passing_sdu_count = match - not_pass - not_pass_sdu;
++
++      return 0;
++}
++
++int ocelot_qci_max_cap_get(struct ocelot *ocelot,
++                         struct tsn_qci_psfp_stream_param *stream_para)
++{
++      /* MaxStreamFilterInstances */
++      stream_para->max_sf_instance = capa.num_psfp_sfid;
++      /* MaxStreamGateInstances */
++      stream_para->max_sg_instance = capa.num_psfp_sgid;
++      /* MaxFlowMeterInstances */
++      stream_para->max_fm_instance = capa.psfp_fmi_max -
++                                     capa.psfp_fmi_min + 1;
++      /* SupportedListMax */
++      stream_para->supported_list_max = capa.num_sgi_gcl;
++
++      return 0;
++}
++
++static int sgi_set_glist(struct ocelot *ocelot,
++                       struct tsn_qci_psfp_gcl *gcl, uint32_t num)
++{
++      u32 time_sum = 0;
++      int i;
++
++      if (num > capa.num_sgi_gcl)
++              return -EINVAL;
++
++      for (i = 0; i < num; i++) {
++              u32 val = ANA_SG_GCL_GS_CONFIG_IPS((gcl->ipv < 0) ?
++                                                 0 : gcl->ipv + 8);
++              val |= (gcl->gate_state ? ANA_SG_GCL_GS_CONFIG_GATE_STATE : 0);
++              ocelot_write_rix(ocelot, val, ANA_SG_GCL_GS_CONFIG, i);
++
++              time_sum += gcl->time_interval;
++              ocelot_write_rix(ocelot, time_sum, ANA_SG_GCL_TI_CONFIG, i);
++
++              gcl++;
++      }
++
++      return 0;
++}
++
++static u32 sgi_read_status(struct ocelot *ocelot)
++{
++      u32 val;
++
++      val = ocelot_read(ocelot, ANA_SG_ACCESS_CTRL);
++
++      return val;
++}
++
++int ocelot_qci_sgi_set(struct ocelot *ocelot, int port, u32 index,
++                     struct tsn_qci_psfp_sgi_conf *sgi_conf)
++{
++      struct tsn_qci_sg_control *admin_list = &sgi_conf->admin;
++      u32 sgid = index;
++      u32 list_length = sgi_conf->admin.control_list_length;
++      u32 cycle_time = sgi_conf->admin.cycle_time;
++      u32 cycle_time_ex = sgi_conf->admin.cycle_time_extension;
++      u32 l_basetime = sgi_conf->admin.base_time % 1000000000;
++      u64 h_basetime = sgi_conf->admin.base_time / 1000000000;
++      u64 cur_time;
++      u32 val;
++      int ret;
++
++      if (sgid >= capa.num_psfp_sgid) {
++              dev_err(ocelot->dev, "Invalid sgid %u, maximum:%u\n",
++                      sgid, capa.num_psfp_sgid);
++              return -EINVAL;
++      }
++      if ((cycle_time < capa.sgi_ct_min ||
++           cycle_time > capa.sgi_ct_max) &&
++           sgi_conf->gate_enabled) {
++              dev_err(ocelot->dev, "Invalid cycle_time %u ns\n",
++                      cycle_time);
++              return -EINVAL;
++      }
++      if (cycle_time_ex > capa.sgi_cte_max) {
++              dev_err(ocelot->dev,
++                      "Invalid cycle_time_extension %u\n",
++                      cycle_time_ex);
++              return -EINVAL;
++      }
++      if (list_length > capa.num_sgi_gcl) {
++              dev_err(ocelot->dev,
++                      "Invalid sgi_gcl len %u, maximum:%u\n",
++                      list_length, capa.num_sgi_gcl);
++              return -EINVAL;
++      }
++
++      /*configure SGID*/
++      ocelot_rmw(ocelot,
++                 ANA_SG_ACCESS_CTRL_SGID(sgid),
++                 ANA_SG_ACCESS_CTRL_SGID_M,
++                 ANA_SG_ACCESS_CTRL);
++
++      /*Disable SG*/
++      if (!sgi_conf->gate_enabled) {
++              ocelot_rmw(ocelot,
++                         ANA_SG_CONFIG_REG_3_INIT_GATE_STATE,
++                         ANA_SG_CONFIG_REG_3_INIT_GATE_STATE |
++                         ANA_SG_CONFIG_REG_3_GATE_ENABLE,
++                         ANA_SG_CONFIG_REG_3);
++              return 0;
++      }
++
++      /*admin parameters*/
++      cur_time = ocelot_read(ocelot, PTP_CUR_SEC_MSB);
++      cur_time = cur_time << 32;
++      cur_time += ocelot_read(ocelot, PTP_CUR_SEC_LSB);
++      if (h_basetime < cur_time) {
++              h_basetime = cur_time;
++              l_basetime = ocelot_read(ocelot, PTP_CUR_NSEC);
++      }
++
++      ocelot_write(ocelot, l_basetime, ANA_SG_CONFIG_REG_1);
++      ocelot_write(ocelot, h_basetime, ANA_SG_CONFIG_REG_2);
++
++      ocelot_write(ocelot,
++                   (sgi_conf->admin.init_ipv < 0 ?
++                    0 : ANA_SG_CONFIG_REG_3_IPV_VALID) |
++                   ANA_SG_CONFIG_REG_3_INIT_IPV(sgi_conf->admin.init_ipv) |
++                   ANA_SG_CONFIG_REG_3_GATE_ENABLE |
++                   ANA_SG_CONFIG_REG_3_LIST_LENGTH(list_length) |
++                   (sgi_conf->admin.gate_states > 0 ?
++                    ANA_SG_CONFIG_REG_3_INIT_GATE_STATE : 0) |
++                   ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB(h_basetime >> 32),
++                   ANA_SG_CONFIG_REG_3);
++
++      ocelot_write(ocelot, cycle_time, ANA_SG_CONFIG_REG_4);
++      ocelot_write(ocelot, cycle_time_ex, ANA_SG_CONFIG_REG_5);
++
++      ret = sgi_set_glist(ocelot, admin_list->gcl, list_length);
++      if (ret < 0)
++              return ret;
++
++      /* Start configuration change */
++      ocelot_rmw(ocelot,
++                 ANA_SG_ACCESS_CTRL_CONFIG_CHANGE,
++                 ANA_SG_ACCESS_CTRL_CONFIG_CHANGE,
++                 ANA_SG_ACCESS_CTRL);
++
++      ret = readx_poll_timeout(sgi_read_status, ocelot, val,
++                               (!(ANA_SG_ACCESS_CTRL_CONFIG_CHANGE & val)),
++                               10, 100000);
++
++      return ret;
++}
++
++static int sgi_get_glist(struct ocelot *ocelot,
++                       struct tsn_qci_psfp_gcl *gcl,
++                       uint32_t num)
++{
++      int i;
++      u16 val;
++      u32 time = 0;
++      u32 reg;
++
++      if (num > capa.num_sgi_gcl)
++              return -EINVAL;
++
++      for (i = 0; i < num; i++) {
++              val = ocelot_read_rix(ocelot, ANA_SG_GCL_GS_CONFIG, i);
++              gcl->gate_state = (val & ANA_SG_GCL_GS_CONFIG_GATE_STATE);
++
++              if (val & ANA_SG_GCL_GS_CONFIG_IPV_VALID)
++                      gcl->ipv = ANA_SG_GCL_GS_CONFIG_IPV(val);
++              else
++                      gcl->ipv = -1;
++
++              reg = ocelot_read_rix(ocelot, ANA_SG_GCL_TI_CONFIG, i);
++              gcl->time_interval = (reg - time);
++              time = reg;
++
++              gcl++;
++      }
++
++      return 0;
++}
++
++int ocelot_qci_sgi_get(struct ocelot *ocelot, int port, u32 index,
++                     struct tsn_qci_psfp_sgi_conf *sgi_conf)
++{
++      struct tsn_qci_sg_control *admin  = &sgi_conf->admin;
++      struct tsn_qci_psfp_gcl *glist;
++      u32 val, reg;
++      u32 list_num;
++      int ret;
++
++      if (index >= capa.num_psfp_sgid) {
++              dev_err(ocelot->dev, "Invalid sgid %u, maximum:%u\n",
++                      index, capa.num_psfp_sgid);
++              return -EINVAL;
++      }
++
++      ocelot_rmw(ocelot,
++                 ANA_SG_ACCESS_CTRL_SGID(index),
++                 ANA_SG_ACCESS_CTRL_SGID_M,
++                 ANA_SG_ACCESS_CTRL);
++
++      admin->cycle_time = ocelot_read(ocelot, ANA_SG_CONFIG_REG_4);
++      admin->cycle_time_extension =
++              ocelot_read(ocelot, ANA_SG_CONFIG_REG_5);
++
++      val = ocelot_read(ocelot, ANA_SG_CONFIG_REG_2);
++      admin->base_time = val;
++
++      reg = ocelot_read(ocelot, ANA_SG_CONFIG_REG_1);
++      val = ocelot_read(ocelot, ANA_SG_CONFIG_REG_3);
++
++      admin->base_time +=
++              ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB(val) << 32;
++
++      admin->base_time = admin->base_time * 1000000000 + reg;
++
++      if (val & ANA_SG_CONFIG_REG_3_IPV_VALID)
++              admin->init_ipv = ANA_SG_CONFIG_REG_3_INIT_IPV_X(val);
++      else
++              admin->init_ipv = -1;
++
++      if (val & ANA_SG_CONFIG_REG_3_GATE_ENABLE)
++              sgi_conf->gate_enabled = TRUE;
++
++      admin->control_list_length = ANA_SG_CONFIG_REG_3_LIST_LENGTH_X(val);
++
++      list_num = admin->control_list_length;
++
++      glist = kmalloc_array(list_num, sizeof(struct tsn_qci_psfp_gcl),
++                            GFP_KERNEL);
++      admin->gcl = glist;
++
++      ret = sgi_get_glist(ocelot, glist, list_num);
++
++      return ret;
++}
++
++int ocelot_qci_sgi_status_get(struct ocelot *ocelot, int port, u32 index,
++                            struct tsn_psfp_sgi_status *sgi_status)
++{
++      u32 val, reg;
++
++      if (index >= capa.num_psfp_sgid) {
++              dev_err(ocelot->dev, "Invalid sgid %u, maximum:%u\n",
++                      index, capa.num_psfp_sgid);
++              return -EINVAL;
++      }
++
++      ocelot_rmw(ocelot,
++                 ANA_SG_ACCESS_CTRL_SGID(index),
++                 ANA_SG_ACCESS_CTRL_SGID_M,
++                 ANA_SG_ACCESS_CTRL);
++
++      val = ocelot_read(ocelot, ANA_SG_STATUS_REG_2);
++      sgi_status->config_change_time = val;
++
++      reg = ocelot_read(ocelot, ANA_SG_STATUS_REG_1);
++      val = ocelot_read(ocelot, ANA_SG_STATUS_REG_3);
++      sgi_status->config_change_time +=
++              ANA_SG_STATUS_REG_3_CFG_CHG_TIME_SEC_MSB(val) << 32;
++      sgi_status->config_change_time =
++              sgi_status->config_change_time * 1000000000 + reg;
++
++      if (val & ANA_SG_STATUS_REG_3_CONFIG_PENDING)
++              sgi_status->config_pending  = TRUE;
++      else
++              sgi_status->config_pending = FALSE;
++
++      if (val & ANA_SG_STATUS_REG_3_GATE_STATE)
++              sgi_status->oper.gate_states  =  TRUE;
++      else
++              sgi_status->oper.gate_states  =  FALSE;
++      /*bit 3 encoding 0:IPV [0:2]is invalid . 1:IPV[0:2] is valid*/
++      if (val & ANA_SG_STATUS_REG_3_IPV_VALID)
++              sgi_status->oper.init_ipv = ANA_SG_STATUS_REG_3_IPV_X(val);
++      else
++              sgi_status->oper.init_ipv = -1;
++
++      return 0;
++}
++
++int ocelot_qci_fmi_set(struct ocelot *ocelot, int port, u32 index,
++                     bool enable, struct tsn_qci_psfp_fmi *fmi)
++{
++      u32 cir = 0, cbs = 0, pir = 0, pbs = 0;
++      u32 cir_ena = 0;
++      u32 pbs_max = 0, cbs_max = 0;
++      bool cir_discard = 0, pir_discard = 0;
++
++      if (index > capa.qos_pol_max) {
++              dev_err(ocelot->dev, "Invalid pol_idx %u, maximum: %u\n",
++                      index, capa.qos_pol_max);
++              return -EINVAL;
++      }
++
++      if (fmi->mark_red_enable && fmi->mark_red) {
++              fmi->eir = 0;
++              fmi->ebs = 0;
++              fmi->cir = 0;
++              fmi->cbs = 0;
++      }
++
++      pir = fmi->eir;
++      pbs = fmi->ebs;
++
++      if (!fmi->drop_on_yellow)
++              cir_ena = 1;
++
++      if (cir_ena) {
++              cir = fmi->cir;
++              cbs = fmi->cbs;
++              if (cir == 0 && cbs == 0) {
++                      cir_discard = 1;
++              } else {
++                      cir = DIV_ROUND_UP(cir, 100);
++                      cir *= 3;  /* Rate unit is 33 1/3 kbps */
++                      cbs = DIV_ROUND_UP(cbs, 4096);
++                      cbs = (cbs ? cbs : 1);
++                      cbs_max = capa.pol_cbs_max;
++                      if (fmi->cf)
++                              pir += fmi->cir;
++              }
++      }
++
++      if (pir == 0 && pbs == 0) {
++              pir_discard = 1;
++      } else {
++              pir = DIV_ROUND_UP(pir, 100);
++              pir *= 3;  /* Rate unit is 33 1/3 kbps */
++              pbs = DIV_ROUND_UP(pbs, 4096);
++              pbs = (pbs ? pbs : 1);
++              pbs_max = capa.pol_pbs_max;
++      }
++      pir = min_t(u32, GENMASK(15, 0), pir);
++      cir = min_t(u32, GENMASK(15, 0), cir);
++      pbs = min(pbs_max, pbs);
++      cbs = min(cbs_max, cbs);
++
++      ocelot_write_gix(ocelot, (ANA_POL_MODE_CFG_IPG_SIZE(20) |
++                       ANA_POL_MODE_CFG_FRM_MODE(1) |
++                       (fmi->cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) |
++                       (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) |
++                       ANA_POL_MODE_CFG_OVERSHOOT_ENA),
++                       ANA_POL_MODE_CFG, index);
++
++      ocelot_write_gix(ocelot, ANA_POL_PIR_CFG_PIR_RATE(pir) |
++                       ANA_POL_PIR_CFG_PIR_BURST(pbs),
++                       ANA_POL_PIR_CFG, index);
++
++      ocelot_write_gix(ocelot,
++                       (pir_discard ? GENMASK(22, 0) : 0),
++                       ANA_POL_PIR_STATE, index);
++
++      ocelot_write_gix(ocelot, ANA_POL_CIR_CFG_CIR_RATE(cir) |
++                       ANA_POL_CIR_CFG_CIR_BURST(cbs),
++                       ANA_POL_CIR_CFG, index);
++
++      ocelot_write_gix(ocelot,
++                       (cir_discard ? GENMASK(22, 0) : 0),
++                       ANA_POL_CIR_STATE, index);
++
++      return 0;
++}
++
++int ocelot_qci_fmi_get(struct ocelot *ocelot, int port, u32 index,
++                     struct tsn_qci_psfp_fmi *fmi,
++                     struct tsn_qci_psfp_fmi_counters *counters)
++{
++      u32 val, reg;
++
++      if (index > capa.qos_pol_max) {
++              dev_err(ocelot->dev, "Invalid pol_idx %u, maximum: %u\n",
++                      index, capa.qos_pol_max);
++              return -EINVAL;
++      }
++
++      val = ocelot_read_gix(ocelot, ANA_POL_PIR_CFG, index);
++      reg = ocelot_read_gix(ocelot, ANA_POL_CIR_CFG, index);
++
++      fmi->eir = ANA_POL_PIR_CFG_PIR_RATE_X(val);
++      fmi->eir = fmi->eir * 100 / 3;
++      fmi->ebs = ANA_POL_PIR_CFG_PIR_BURST(val);
++      fmi->ebs *= 4096;
++      fmi->cir = ANA_POL_CIR_CFG_CIR_RATE_X(reg);
++      fmi->cir = fmi->cir * 100 / 3;
++      fmi->cbs = ANA_POL_CIR_CFG_CIR_BURST(reg);
++      fmi->cbs *= 4096;
++      if (!(fmi->eir | fmi->ebs | fmi->cir | fmi->cbs))
++              fmi->mark_red = TRUE;
++      else
++              fmi->mark_red = FALSE;
++
++      val = ocelot_read_gix(ocelot, ANA_POL_MODE_CFG, index);
++      if (val & ANA_POL_MODE_CFG_DLB_COUPLED)
++              fmi->cf = TRUE;
++      else
++              fmi->cf = FALSE;
++      if (val & ANA_POL_MODE_CFG_CIR_ENA)
++              fmi->drop_on_yellow = FALSE;
++      else
++              fmi->drop_on_yellow = TRUE;
++
++      return 0;
++}
++
++int ocelot_seq_gen_set(struct ocelot *ocelot, int port, u32 index,
++                     struct tsn_seq_gen_conf *sg_conf)
++{
++      u8 iport_mask = sg_conf->iport_mask;
++      u8 split_mask = sg_conf->split_mask;
++      u8 seq_len = sg_conf->seq_len;
++      u32 seq_num = sg_conf->seq_num;
++
++      if (index >= capa.num_frer_ssid) {
++              dev_err(ocelot->dev, "Invalid SSID %u, maximum:%u\n",
++                      index, capa.num_frer_ssid - 1);
++              return -EINVAL;
++      }
++      if (seq_len < capa.frer_seq_len_min ||
++          seq_len > capa.frer_seq_len_max) {
++              dev_err(ocelot->dev,
++                      "Invalid seq_space_bits num %u,range:%d~%d\n",
++                      seq_len,
++                      capa.frer_seq_len_min,
++                      capa.frer_seq_len_max);
++              return -EINVAL;
++      }
++
++      streamid_multi_forward_set(ocelot,
++                                 streamhandle_map[index],
++                                 split_mask);
++
++      ocelot_write(ocelot,
++                   ANA_TABLES_SEQ_MASK_SPLIT_MASK(split_mask) |
++                   ANA_TABLES_SEQ_MASK_INPUT_PORT_MASK(iport_mask),
++                   ANA_TABLES_SEQ_MASK);
++
++      ocelot_write(ocelot,
++                   ANA_TABLES_STREAMTIDX_S_INDEX(index) |
++                   ANA_TABLES_STREAMTIDX_STREAM_SPLIT |
++                   ANA_TABLES_STREAMTIDX_SEQ_SPACE_LOG2(seq_len),
++                   ANA_TABLES_STREAMTIDX);
++
++      ocelot_write(ocelot,
++                   ANA_TABLES_STREAMACCESS_GEN_REC_SEQ_NUM(seq_num) |
++                   ANA_TABLES_STREAMACCESS_SEQ_GEN_REC_ENA |
++                   ANA_TABLES_STREAMACCESS_STREAM_TBL_CMD(SFIDACCESS_CMD_WRITE),
++                   ANA_TABLES_STREAMACCESS);
++
++      return 0;
++}
++
++int ocelot_seq_rec_set(struct ocelot *ocelot, int port, u32 index,
++                     struct tsn_seq_rec_conf *sr_conf)
++{
++      u8 seq_len = sr_conf->seq_len;
++      u8 hislen = sr_conf->his_len;
++
++      if (index >= capa.num_frer_ssid) {
++              dev_err(ocelot->dev, "Invalid SSID %u, maximum:%u\n",
++                      index, capa.num_frer_ssid - 1);
++              return -EINVAL;
++      }
++      if (seq_len < capa.frer_seq_len_min ||
++          seq_len > capa.frer_seq_len_max) {
++              dev_err(ocelot->dev,
++                      "Invalid seq_space_bits num %u,range:%d~%d\n",
++                      seq_len,
++                      capa.frer_seq_len_min,
++                      capa.frer_seq_len_max);
++              return -EINVAL;
++      }
++      if (hislen < capa.frer_his_len_min ||
++          hislen > capa.frer_his_len_max) {
++              dev_err(ocelot->dev,
++                      "Invalid history_bits num %u,range:%d~%d\n",
++                      hislen,
++                      capa.frer_his_len_min,
++                      capa.frer_his_len_max);
++              return -EINVAL;
++      }
++
++      ocelot_write(ocelot,
++                   ANA_TABLES_STREAMTIDX_S_INDEX(index) |
++                   ANA_TABLES_STREAMTIDX_FORCE_SF_BEHAVIOUR |
++                   ANA_TABLES_STREAMTIDX_SEQ_HISTORY_LEN(hislen) |
++                   ANA_TABLES_STREAMTIDX_RESET_ON_ROGUE |
++                   (sr_conf->rtag_pop_en ?
++                    ANA_TABLES_STREAMTIDX_REDTAG_POP : 0) |
++                   ANA_TABLES_STREAMTIDX_SEQ_SPACE_LOG2(seq_len),
++                   ANA_TABLES_STREAMTIDX);
++
++      ocelot_write(ocelot,
++                   ANA_TABLES_STREAMACCESS_SEQ_GEN_REC_ENA |
++                   ANA_TABLES_STREAMACCESS_GEN_REC_TYPE |
++                   ANA_TABLES_STREAMACCESS_STREAM_TBL_CMD(SFIDACCESS_CMD_WRITE),
++                   ANA_TABLES_STREAMACCESS);
++
++      return 0;
++}
++
++int ocelot_cb_get(struct ocelot *ocelot, int port, u32 index,
++                struct tsn_cb_status *c)
++{
++      u32 val;
++
++      if (index >= capa.num_frer_ssid) {
++              dev_err(ocelot->dev, "Invalid SSID %u, maximum:%u\n",
++                      index, capa.num_frer_ssid - 1);
++              return -EINVAL;
++      }
++
++      ocelot_write(ocelot,
++                   ANA_TABLES_STREAMTIDX_S_INDEX(index),
++                   ANA_TABLES_STREAMTIDX);
++
++      ocelot_write(ocelot,
++                   ANA_TABLES_STREAMACCESS_STREAM_TBL_CMD(SFIDACCESS_CMD_READ),
++                   ANA_TABLES_STREAMACCESS);
++
++      val = ocelot_read(ocelot, ANA_TABLES_STREAMACCESS);
++      c->gen_rec = (ANA_TABLES_STREAMACCESS_GEN_REC_TYPE & val) >> 2;
++      c->seq_num = ANA_TABLES_STREAMACCESS_GEN_REC_SEQ_NUM_X(val);
++
++      val = ocelot_read(ocelot, ANA_TABLES_STREAMTIDX);
++      c->err = ANA_TABLES_STREAMTIDX_SEQ_GEN_ERR_STATUS_X(val);
++      c->his_len = ANA_TABLES_STREAMTIDX_SEQ_HISTORY_LEN_X(val);
++      c->seq_len = ANA_TABLES_STREAMTIDX_SEQ_SPACE_LOG2(val);
++
++      val = ocelot_read(ocelot, ANA_TABLES_SEQ_MASK);
++      c->split_mask = ANA_TABLES_SEQ_MASK_SPLIT_MASK_X(val);
++      c->iport_mask = ANA_TABLES_SEQ_MASK_INPUT_PORT_MASK(val);
++
++      c->seq_his = ocelot_read(ocelot, ANA_TABLES_SEQ_HISTORY);
++
++      return 0;
++}
++
++int ocelot_pcp_map_enable(struct ocelot *ocelot, u8 port)
++{
++      int i;
++
++      ocelot_rmw_gix(ocelot,
++                     ANA_PORT_QOS_CFG_QOS_PCP_ENA,
++                     ANA_PORT_QOS_CFG_QOS_PCP_ENA,
++                     ANA_PORT_QOS_CFG,
++                     port);
++
++      for (i = 0; i < NUM_MSCC_QOS_PRIO * 2; i++) {
++              ocelot_rmw_ix(ocelot,
++                            (ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & i) |
++                            ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(i),
++                            ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL |
++                            ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL_M,
++                            ANA_PORT_PCP_DEI_MAP,
++                            port, i);
++      }
++
++      return 0;
++}
++
++int ocelot_rtag_parse_enable(struct ocelot *ocelot, u8 port)
++{
++      ocelot_rmw_rix(ocelot,
++                     ANA_PORT_MODE_REDTAG_PARSE_CFG,
++                     ANA_PORT_MODE_REDTAG_PARSE_CFG,
++                     ANA_PORT_MODE,
++                     port);
++
++      return 0;
++}
++
++int ocelot_dscp_set(struct ocelot *ocelot, int port,
++                  bool enable, const u8 dscp_ix,
++                  struct tsn_qos_switch_dscp_conf *c)
++{
++      u32 val, ri = dscp_ix;
++
++      c->dscp = 0;
++      c->trust = 1;
++      c->remark = 0;
++
++      if (dscp_ix > capa.qos_dscp_max) {
++              dev_err(ocelot->dev, "Invalid dscp_ix %u\n", dscp_ix);
++              return -EINVAL;
++      }
++      if (c->cos > capa.qos_cos_max) {
++              dev_err(ocelot->dev, "Invalid cos %d\n", c->cos);
++              return -EINVAL;
++      }
++      if (c->dpl > capa.qos_dp_max) {
++              dev_err(ocelot->dev, "Invalid dpl %d\n", c->dpl);
++              return -EINVAL;
++      }
++
++      ocelot_rmw_gix(ocelot,
++                     (enable ? ANA_PORT_QOS_CFG_QOS_DSCP_ENA : 0) |
++                     (c->dscp ? ANA_PORT_QOS_CFG_DSCP_TRANSLATE_ENA : 0),
++                     ANA_PORT_QOS_CFG_QOS_DSCP_ENA |
++                     ANA_PORT_QOS_CFG_DSCP_TRANSLATE_ENA,
++                     ANA_PORT_QOS_CFG,
++                     port);
++
++      val = (c->dpl ? ANA_DSCP_CFG_DP_DSCP_VAL : 0) |
++             ANA_DSCP_CFG_QOS_DSCP_VAL(c->cos) |
++             ANA_DSCP_CFG_DSCP_TRANSLATE_VAL(c->dscp) |
++             (c->trust ? ANA_DSCP_CFG_DSCP_TRUST_ENA : 0) |
++             (c->remark ? ANA_DSCP_CFG_DSCP_REWR_ENA : 0);
++
++      ocelot_write_rix(ocelot, val, ANA_DSCP_CFG, ri);
++
++      return 0;
++}
+--- /dev/null
++++ b/drivers/net/ethernet/mscc/ocelot_tsn.h
+@@ -0,0 +1,51 @@
++/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
++ *
++ * TSN_SWITCH driver
++ *
++ * Copyright 2018-2019 NXP
++ */
++
++#ifndef _MSCC_OCELOT_SWITCH_TSN_H_
++#define _MSCC_OCELOT_SWITCH_TSN_H_
++
++#define TRUE 1
++#define FALSE 0
++
++struct mscc_switch_capa {
++      u8 num_tas_gcl; /* Number of TAS Gate Control Lists */
++      u32 tas_ct_min; /* Minimum supported TAS CycleTime in nS */
++      u32 tas_ct_max; /* Maximum supported TAS CycleTime in nS */
++      u32 tas_cte_max; /* Maximum supported TAS CycleTimeExtension in nS
++                        */
++      u32 tas_it_max;
++      u32 tas_it_min;
++      u8 num_hsch;
++      u8 num_psfp_sfid;
++      u8 num_frer_ssid;
++      u8 num_psfp_sgid;
++      u16 psfp_fmi_max;
++      u16 psfp_fmi_min;
++      u8 num_sgi_gcl;
++      u32 sgi_ct_min;
++      u32 sgi_ct_max;
++      u32 sgi_cte_max;
++      u16 qos_pol_max;
++      u8 pol_cbs_max;
++      u8 pol_pbs_max;
++      u8 frer_seq_len_min;
++      u8 frer_seq_len_max;
++      u8 frer_his_len_min;
++      u8 frer_his_len_max;
++      u8 qos_dscp_max;
++      u8 qos_cos_max;
++      u8 qos_dp_max;
++};
++
++static inline void ocelot_port_rmwl(struct ocelot_port *port, u32 val,
++                                  u32 mask, u32 reg)
++{
++      u32 cur = ocelot_port_readl(port, reg);
++
++      ocelot_port_writel(port, (cur & (~mask)) | val, reg);
++}
++#endif
+--- a/include/soc/mscc/ocelot.h
++++ b/include/soc/mscc/ocelot.h
+@@ -10,6 +10,7 @@
+ #include <linux/if_vlan.h>
+ #include <linux/regmap.h>
+ #include <net/dsa.h>
++#include <net/tsn.h>
+ #define IFH_INJ_BYPASS                        BIT(31)
+ #define IFH_INJ_POP_CNT_DISABLE               (3 << 28)
+@@ -328,6 +329,10 @@ enum ocelot_reg {
+       PTP_CFG_MISC,
+       PTP_CLK_CFG_ADJ_CFG,
+       PTP_CLK_CFG_ADJ_FREQ,
++      PTP_CUR_NSF,
++      PTP_CUR_NSEC,
++      PTP_CUR_SEC_LSB,
++      PTP_CUR_SEC_MSB,
+       GCB_SOFT_RST = GCB << TARGET_OFFSET,
+ };
+@@ -539,5 +544,50 @@ int ocelot_ptp_gettime64(struct ptp_cloc
+ int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port,
+                                struct sk_buff *skb);
+ void ocelot_get_txtstamp(struct ocelot *ocelot);
+-
++int ocelot_qbv_set(struct ocelot *ocelot, int port_id,
++                 struct tsn_qbv_conf *shaper_config);
++int ocelot_qbv_get(struct ocelot *ocelot, int port_id,
++                 struct tsn_qbv_conf *shaper_config);
++int ocelot_qbv_get_status(struct ocelot *ocelot, int port_id,
++                        struct tsn_qbv_status *qbvstatus);
++int ocelot_cut_thru_set(struct ocelot *ocelot, int port_id, u8 cut_thru);
++int ocelot_cbs_set(struct ocelot *ocelot, int port, u8 tc, u8 bw);
++int ocelot_cbs_get(struct ocelot *ocelot, int port, u8 tc);
++int ocelot_qbu_set(struct ocelot *ocelot, int port, u8 preemptible);
++int ocelot_qbu_get(struct ocelot *ocelot, int port,
++                 struct tsn_preempt_status *c);
++int ocelot_cb_streamid_get(struct ocelot *ocelot, int port, u32 index,
++                         struct tsn_cb_streamid *streamid);
++int ocelot_cb_streamid_set(struct ocelot *ocelot, int port, u32 index,
++                         bool enable, struct tsn_cb_streamid *streamid);
++int ocelot_qci_sfi_get(struct ocelot *ocelot, int port, u32 index,
++                     struct tsn_qci_psfp_sfi_conf *sfi);
++int ocelot_qci_sfi_set(struct ocelot *ocelot, int port, u32 index,
++                     bool enable, struct tsn_qci_psfp_sfi_conf *sfi);
++int ocelot_qci_sfi_counters_get(struct ocelot *ocelot, int port, u32 index,
++                      struct tsn_qci_psfp_sfi_counters *sfi_counters);
++int ocelot_qci_max_cap_get(struct ocelot *ocelot,
++                         struct tsn_qci_psfp_stream_param *stream_para);
++int ocelot_qci_sgi_set(struct ocelot *ocelot, int port, u32 index,
++                     struct tsn_qci_psfp_sgi_conf *sgi_conf);
++int ocelot_qci_sgi_get(struct ocelot *ocelot, int port, u32 index,
++                     struct tsn_qci_psfp_sgi_conf *sgi_conf);
++int ocelot_qci_sgi_status_get(struct ocelot *ocelot, int port, u32 index,
++                            struct tsn_psfp_sgi_status *sgi_status);
++int ocelot_qci_fmi_set(struct ocelot *ocelot, int port, u32 index,
++                     bool enable, struct tsn_qci_psfp_fmi *fmi);
++int ocelot_qci_fmi_get(struct ocelot *ocelot, int port, u32 index,
++                     struct tsn_qci_psfp_fmi *fmi,
++                     struct tsn_qci_psfp_fmi_counters *counters);
++int ocelot_seq_gen_set(struct ocelot *ocelot, int port, u32 index,
++                     struct tsn_seq_gen_conf *sg_conf);
++int ocelot_seq_rec_set(struct ocelot *ocelot, int port, u32 index,
++                     struct tsn_seq_rec_conf *sr_conf);
++int ocelot_cb_get(struct ocelot *ocelot, int port, u32 index,
++                struct tsn_cb_status *c);
++int ocelot_pcp_map_enable(struct ocelot *ocelot, u8 port);
++int ocelot_rtag_parse_enable(struct ocelot *ocelot, u8 port);
++int ocelot_dscp_set(struct ocelot *ocelot, int port,
++                  bool enable, const u8 dscp_ix,
++                  struct tsn_qos_switch_dscp_conf *c);
+ #endif
diff --git a/target/linux/layerscape/patches-5.4/701-net-0273-net-dsa-ocelot-add-tsn-support-for-felix-switch.patch b/target/linux/layerscape/patches-5.4/701-net-0273-net-dsa-ocelot-add-tsn-support-for-felix-switch.patch
new file mode 100644 (file)
index 0000000..aae0e67
--- /dev/null
@@ -0,0 +1,671 @@
+From 36b446d44d66a6d6a072d3f5e87ebb05e0b88d98 Mon Sep 17 00:00:00 2001
+From: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
+Date: Fri, 29 Nov 2019 14:28:37 +0800
+Subject: [PATCH] net: dsa: ocelot: add tsn support for felix switch
+
+Support tsn capabilities in DSA felix switch driver. This felix tsn
+driver is using tsn configuration of ocelot, and registered on each
+switch port through DSA port setup.
+
+Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
+---
+ drivers/net/dsa/ocelot/Kconfig         |   8 +
+ drivers/net/dsa/ocelot/Makefile        |   2 +
+ drivers/net/dsa/ocelot/felix.c         |  50 ++++
+ drivers/net/dsa/ocelot/felix_tsn.c     | 432 +++++++++++++++++++++++++++++++++
+ drivers/net/dsa/ocelot/felix_tsn.h     |  61 +++++
+ drivers/net/dsa/ocelot/felix_vsc9959.c |   8 +-
+ include/net/dsa.h                      |   1 +
+ net/dsa/dsa2.c                         |   4 +
+ 8 files changed, 564 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/net/dsa/ocelot/felix_tsn.c
+ create mode 100644 drivers/net/dsa/ocelot/felix_tsn.h
+
+--- a/drivers/net/dsa/ocelot/Kconfig
++++ b/drivers/net/dsa/ocelot/Kconfig
+@@ -9,3 +9,11 @@ config NET_DSA_MSCC_FELIX
+         the Vitesse / Microsemi / Microchip Ocelot family of switching cores.
+         It is embedded as a PCIe function of the NXP LS1028A ENETC integrated
+         endpoint.
++
++config MSCC_FELIX_SWITCH_TSN
++      tristate "TSN on FELIX switch driver"
++      depends on NET_DSA_MSCC_FELIX
++      depends on TSN
++      help
++        This driver supports TSN on felix switch.
++
+--- a/drivers/net/dsa/ocelot/Makefile
++++ b/drivers/net/dsa/ocelot/Makefile
+@@ -4,3 +4,5 @@ obj-$(CONFIG_NET_DSA_MSCC_FELIX) += mscc
+ mscc_felix-objs := \
+       felix.o \
+       felix_vsc9959.o
++
++obj-$(CONFIG_MSCC_FELIX_SWITCH_TSN) += felix_tsn.o
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -9,6 +9,38 @@
+ #include <linux/of.h>
+ #include <net/dsa.h>
+ #include "felix.h"
++#include "felix_tsn.h"
++
++#ifdef CONFIG_MSCC_FELIX_SWITCH_TSN
++const struct tsn_ops switch_tsn_ops = {
++      .device_init                    = felix_tsn_init,
++      .get_capability                 = felix_tsn_get_cap,
++      .qbv_set                        = felix_qbv_set,
++      .qbv_get                        = felix_qbv_get,
++      .qbv_get_status                 = felix_qbv_get_status,
++      .qbu_set                        = felix_qbu_set,
++      .qbu_get                        = felix_qbu_get,
++      .cb_streamid_set                = felix_cb_streamid_set,
++      .cb_streamid_get                = felix_cb_streamid_get,
++      .cb_streamid_counters_get       = felix_cb_streamid_counters_get,
++      .qci_sfi_set                    = felix_qci_sfi_set,
++      .qci_sfi_get                    = felix_qci_sfi_get,
++      .qci_sfi_counters_get           = felix_qci_sfi_counters_get,
++      .qci_get_maxcap                 = felix_qci_max_cap_get,
++      .qci_sgi_set                    = felix_qci_sgi_set,
++      .qci_sgi_get                    = felix_qci_sgi_get,
++      .qci_sgi_status_get             = felix_qci_sgi_status_get,
++      .qci_fmi_set                    = felix_qci_fmi_set,
++      .qci_fmi_get                    = felix_qci_fmi_get,
++      .cbs_set                        = felix_cbs_set,
++      .cbs_get                        = felix_cbs_get,
++      .ct_set                         = felix_cut_thru_set,
++      .cbgen_set                      = felix_seq_gen_set,
++      .cbrec_set                      = felix_seq_rec_set,
++      .cb_get                         = felix_cb_get,
++      .dscp_set                       = felix_dscp_set,
++};
++#endif
+ static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds,
+                                                   int port)
+@@ -138,6 +170,21 @@ static int felix_vlan_del(struct dsa_swi
+       return 0;
+ }
++#ifdef CONFIG_MSCC_FELIX_SWITCH_TSN
++static int felix_tsn_enable(struct dsa_port *dp)
++{
++      struct net_device *dev;
++
++      if (dp->type == DSA_PORT_TYPE_USER) {
++              dev = dp->slave;
++              tsn_port_register(dev,
++                                (struct tsn_ops *)&switch_tsn_ops,
++                                GROUP_OFFSET_SWITCH);
++      }
++      return 0;
++}
++#endif
++
+ static int felix_port_enable(struct dsa_switch *ds, int port,
+                            struct phy_device *phy)
+ {
+@@ -386,6 +433,9 @@ static const struct dsa_switch_ops felix
+       .port_hwtstamp_set      = felix_hwtstamp_set,
+       .port_rxtstamp          = felix_rxtstamp,
+       .port_txtstamp          = felix_txtstamp,
++#ifdef CONFIG_MSCC_FELIX_SWITCH_TSN
++      .port_tsn_enable        = felix_tsn_enable,
++#endif
+ };
+ static struct felix_info *felix_instance_tbl[] = {
+--- /dev/null
++++ b/drivers/net/dsa/ocelot/felix_tsn.c
+@@ -0,0 +1,432 @@
++// SPDX-License-Identifier: (GPL-2.0 OR MIT)
++/* Felix Switch TSN driver
++ *
++ * Copyright 2018-2019 NXP
++ */
++
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <soc/mscc/ocelot.h>
++#include <net/tsn.h>
++#include "felix.h"
++
++static struct ocelot *felix_dev_to_ocelot(struct net_device *ndev)
++{
++      struct pci_dev *pdev;
++      struct felix *felix;
++
++      pdev = list_entry(ndev->dev.parent, struct pci_dev, dev);
++      felix = pci_get_drvdata(pdev);
++      if (!felix)
++              return NULL;
++
++      return &felix->ocelot;
++}
++
++static int felix_dev_to_port(struct net_device *ndev, struct ocelot *ocelot)
++{
++      struct felix *felix = ocelot_to_felix(ocelot);
++      struct dsa_switch *ds = felix->ds;
++      struct dsa_port *dp;
++      int i;
++
++      for (i = 0; i < ds->num_ports; i++) {
++              dp = &ds->ports[i];
++              if (dp->dn == ndev->dev.of_node)
++                      return dp->index;
++      }
++
++      return -ENODEV;
++}
++
++u32 felix_tsn_get_cap(struct net_device *ndev)
++{
++      u32 cap = 0;
++
++      cap = (TSN_CAP_QBV | TSN_CAP_QCI | TSN_CAP_QBU | TSN_CAP_CBS |
++             TSN_CAP_CB | TSN_CAP_TBS | TSN_CAP_CTH);
++
++      return cap;
++}
++
++int felix_qbv_set(struct net_device *ndev,
++                struct tsn_qbv_conf *shaper_config)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_qbv_set(ocelot, port, shaper_config);
++}
++
++int felix_qbv_get(struct net_device *ndev,
++                struct tsn_qbv_conf *shaper_config)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_qbv_get(ocelot, port, shaper_config);
++}
++
++int felix_qbv_get_status(struct net_device *ndev,
++                       struct tsn_qbv_status *qbvstatus)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_qbv_get_status(ocelot, port, qbvstatus);
++}
++
++int felix_qbu_set(struct net_device *ndev, u8 preemptible)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_qbu_set(ocelot, port, preemptible);
++}
++
++int felix_qbu_get(struct net_device *ndev, struct tsn_preempt_status *c)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_qbu_get(ocelot, port, c);
++}
++
++int felix_cb_streamid_set(struct net_device *ndev, u32 index, bool enable,
++                        struct tsn_cb_streamid *streamid)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_cb_streamid_set(ocelot, port, index, enable, streamid);
++}
++
++int felix_cb_streamid_get(struct net_device *ndev, u32 index,
++                        struct tsn_cb_streamid *streamid)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_cb_streamid_get(ocelot, port, index, streamid);
++}
++
++int felix_cb_streamid_counters_get(struct net_device *ndev, u32 index,
++                                 struct tsn_cb_streamid_counters *sc)
++{
++      return 0;
++}
++
++int felix_qci_sfi_set(struct net_device *ndev, u32 index, bool enable,
++                    struct tsn_qci_psfp_sfi_conf *sfi)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_qci_sfi_set(ocelot, port, index, enable, sfi);
++}
++
++int felix_qci_sfi_get(struct net_device *ndev, u32 index,
++                    struct tsn_qci_psfp_sfi_conf *sfi)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_qci_sfi_get(ocelot, port, index, sfi);
++}
++
++int felix_qci_sfi_counters_get(struct net_device *ndev, u32 index,
++                             struct tsn_qci_psfp_sfi_counters *sfi_cnt)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_qci_sfi_counters_get(ocelot, port, index, sfi_cnt);
++}
++
++int felix_qci_max_cap_get(struct net_device *ndev,
++                        struct tsn_qci_psfp_stream_param *stream_para)
++{
++      struct ocelot *ocelot;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++
++      return ocelot_qci_max_cap_get(ocelot, stream_para);
++}
++
++int felix_qci_sgi_set(struct net_device *ndev, u32 index,
++                    struct tsn_qci_psfp_sgi_conf *sgi_conf)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_qci_sgi_set(ocelot, port, index, sgi_conf);
++}
++
++int felix_qci_sgi_get(struct net_device *ndev, u32 index,
++                    struct tsn_qci_psfp_sgi_conf *sgi_conf)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_qci_sgi_get(ocelot, port, index, sgi_conf);
++}
++
++int felix_qci_sgi_status_get(struct net_device *ndev, u32 index,
++                           struct tsn_psfp_sgi_status *sgi_status)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_qci_sgi_status_get(ocelot, port, index, sgi_status);
++}
++
++int felix_qci_fmi_set(struct net_device *ndev, u32 index,
++                    bool enable, struct tsn_qci_psfp_fmi *fmi)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_qci_fmi_set(ocelot, port, index, enable, fmi);
++}
++
++int felix_qci_fmi_get(struct net_device *ndev, u32 index,
++                    struct tsn_qci_psfp_fmi *fmi,
++                    struct tsn_qci_psfp_fmi_counters *counters)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_qci_fmi_get(ocelot, port, index, fmi, counters);
++}
++
++int felix_cbs_set(struct net_device *ndev, u8 tc, u8 bw)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_cbs_set(ocelot, port, tc, bw);
++}
++
++int felix_cbs_get(struct net_device *ndev, u8 tc)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_cbs_get(ocelot, port, tc);
++}
++
++int felix_cut_thru_set(struct net_device *ndev, u8 cut_thru)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_cut_thru_set(ocelot, port, cut_thru);
++}
++
++int felix_seq_gen_set(struct net_device *ndev, u32 index,
++                    struct tsn_seq_gen_conf *sg_conf)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_seq_gen_set(ocelot, port, index, sg_conf);
++}
++
++int felix_seq_rec_set(struct net_device *ndev, u32 index,
++                    struct tsn_seq_rec_conf *sr_conf)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_seq_rec_set(ocelot, port, index, sr_conf);
++}
++
++int felix_cb_get(struct net_device *ndev, u32 index,
++               struct tsn_cb_status *c)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_cb_get(ocelot, port, index, c);
++}
++
++int felix_dscp_set(struct net_device *ndev, bool enable, const u8 dscp_ix,
++                 struct tsn_qos_switch_dscp_conf *c)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return -ENODEV;
++      port = felix_dev_to_port(ndev, ocelot);
++      if (port < 0)
++              return -ENODEV;
++
++      return ocelot_dscp_set(ocelot, port, enable, dscp_ix, c);
++}
++
++void felix_tsn_init(struct net_device *ndev)
++{
++      struct ocelot *ocelot;
++      int port;
++
++      ocelot = felix_dev_to_ocelot(ndev);
++      if (!ocelot)
++              return;
++      port = felix_dev_to_port(ndev, ocelot);
++
++      ocelot_pcp_map_enable(ocelot, port);
++      ocelot_rtag_parse_enable(ocelot, port);
++}
+--- /dev/null
++++ b/drivers/net/dsa/ocelot/felix_tsn.h
+@@ -0,0 +1,61 @@
++/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
++ *
++ * TSN_SWITCH driver
++ *
++ * Copyright 2018-2019 NXP
++ */
++
++#ifndef _MSCC_FELIX_SWITCH_TSN_H_
++#define _MSCC_FELIX_SWITCH_TSN_H_
++#include <net/tsn.h>
++
++u32 felix_tsn_get_cap(struct net_device *ndev);
++int felix_qbv_set(struct net_device *ndev,
++                struct tsn_qbv_conf *shaper_config);
++int felix_qbv_get(struct net_device *ndev,
++                struct tsn_qbv_conf *shaper_config);
++int felix_qbv_get_status(struct net_device *ndev,
++                       struct tsn_qbv_status *qbvstatus);
++int felix_cut_thru_set(struct net_device *ndev, u8 cut_thru);
++int felix_cbs_set(struct net_device *ndev, u8 tc, u8 bw);
++int felix_cbs_get(struct net_device *ndev, u8 tc);
++int felix_qbu_set(struct net_device *ndev, u8 preemptible);
++int felix_qbu_get(struct net_device *ndev, struct tsn_preempt_status *c);
++int felix_cb_streamid_get(struct net_device *ndev, u32 index,
++                        struct tsn_cb_streamid *streamid);
++int felix_cb_streamid_set(struct net_device *ndev, u32 index,
++                        bool enable, struct tsn_cb_streamid *streamid);
++int felix_cb_streamid_counters_get(struct net_device *ndev, u32 index,
++                                 struct tsn_cb_streamid_counters *sc);
++int felix_qci_sfi_get(struct net_device *ndev, u32 index,
++                    struct tsn_qci_psfp_sfi_conf *sfi);
++int felix_qci_sfi_set(struct net_device *ndev, u32 index,
++                    bool enable, struct tsn_qci_psfp_sfi_conf *sfi);
++int felix_cb_streamid_counters_get(struct net_device *ndev, u32 index,
++                                 struct tsn_cb_streamid_counters *s_counters);
++int felix_qci_sfi_counters_get(struct net_device *ndev, u32 index,
++                             struct tsn_qci_psfp_sfi_counters *sfi_counters);
++int felix_qci_max_cap_get(struct net_device *ndev,
++                        struct tsn_qci_psfp_stream_param *stream_para);
++int felix_qci_sgi_set(struct net_device *ndev, u32 index,
++                    struct tsn_qci_psfp_sgi_conf *sgi_conf);
++int felix_qci_sgi_get(struct net_device *ndev, u32 index,
++                    struct tsn_qci_psfp_sgi_conf *sgi_conf);
++int felix_qci_sgi_status_get(struct net_device *ndev, u16 index,
++                           struct tsn_psfp_sgi_status *sgi_status);
++int felix_qci_fmi_set(struct net_device *ndev, u32 index,
++                    bool enable, struct tsn_qci_psfp_fmi *fmi);
++int felix_qci_fmi_get(struct net_device *ndev, u32 index,
++                    struct tsn_qci_psfp_fmi *fmi,
++                    struct tsn_qci_psfp_fmi_counters *counters);
++int felix_seq_gen_set(struct net_device *ndev, u32 index,
++                    struct tsn_seq_gen_conf *sg_conf);
++int felix_seq_rec_set(struct net_device *ndev, u32 index,
++                    struct tsn_seq_rec_conf *sr_conf);
++int felix_cb_get(struct net_device *ndev, u32 index,
++               struct tsn_cb_status  *c);
++int felix_dscp_set(struct net_device *ndev, bool enable, const u8 dscp_ix,
++                 struct tsn_qos_switch_dscp_conf *c);
++
++void felix_tsn_init(struct net_device *ndev);
++#endif
+--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
+@@ -176,7 +176,7 @@ static const u32 vsc9959_qsys_regmap[] =
+       REG(QSYS_QMAXSDU_CFG_6,                 0x00f62c),
+       REG(QSYS_QMAXSDU_CFG_7,                 0x00f648),
+       REG(QSYS_PREEMPTION_CFG,                0x00f664),
+-      REG_RESERVED(QSYS_CIR_CFG),
++      REG(QSYS_CIR_CFG,                       0x000000),
+       REG(QSYS_EIR_CFG,                       0x000004),
+       REG(QSYS_SE_CFG,                        0x000008),
+       REG(QSYS_SE_DWRR_CFG,                   0x00000c),
+@@ -269,7 +269,7 @@ static const u32 vsc9959_sys_regmap[] =
+       REG_RESERVED(SYS_MMGT_FAST),
+       REG_RESERVED(SYS_EVENTS_DIF),
+       REG_RESERVED(SYS_EVENTS_CORE),
+-      REG_RESERVED(SYS_CNT),
++      REG(SYS_CNT,                            0x000000),
+       REG(SYS_PTP_STATUS,                     0x000f14),
+       REG(SYS_PTP_TXSTAMP,                    0x000f18),
+       REG(SYS_PTP_NXT,                        0x000f1c),
+@@ -290,6 +290,10 @@ static const u32 vsc9959_ptp_regmap[] =
+       REG(PTP_CFG_MISC,                  0x0000a0),
+       REG(PTP_CLK_CFG_ADJ_CFG,           0x0000a4),
+       REG(PTP_CLK_CFG_ADJ_FREQ,          0x0000a8),
++      REG(PTP_CUR_NSF,                   0x0000bc),
++      REG(PTP_CUR_NSEC,                  0x0000c0),
++      REG(PTP_CUR_SEC_LSB,               0x0000c4),
++      REG(PTP_CUR_SEC_MSB,               0x0000c8),
+ };
+ static const u32 vsc9959_gcb_regmap[] = {
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -545,6 +545,7 @@ struct dsa_switch_ops {
+        */
+       netdev_tx_t (*port_deferred_xmit)(struct dsa_switch *ds, int port,
+                                         struct sk_buff *skb);
++      int     (*port_tsn_enable)(struct dsa_port *dp);
+ };
+ struct dsa_switch_driver {
+--- a/net/dsa/dsa2.c
++++ b/net/dsa/dsa2.c
+@@ -323,6 +323,10 @@ static int dsa_port_setup(struct dsa_por
+               if (err)
+                       break;
++              /* Enable TSN function on switch port */
++              if (ds->ops->port_tsn_enable)
++                      ds->ops->port_tsn_enable(dp);
++
+               devlink_port_type_eth_set(dlp, dp->slave);
+               break;
+       }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0274-net-dsa-ocelot-alloc-memory-for-dsa-switch-instance.patch b/target/linux/layerscape/patches-5.4/701-net-0274-net-dsa-ocelot-alloc-memory-for-dsa-switch-instance.patch
new file mode 100644 (file)
index 0000000..97e6f9d
--- /dev/null
@@ -0,0 +1,25 @@
+From a9848cf13f495e12c55a01d437120efbb70ed747 Mon Sep 17 00:00:00 2001
+From: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
+Date: Fri, 29 Nov 2019 15:48:20 +0800
+Subject: [PATCH] net: dsa: ocelot: alloc memory for dsa switch instance
+
+The dsa switch instance hasn't alloc memory for switch ports in felix
+initialization driver, which will cause NULL pointer issue. Using
+dsa_switch_alloc to alloc memory for dsa switch instance.
+
+Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
+---
+ drivers/net/dsa/ocelot/felix.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -510,7 +510,7 @@ static int felix_pci_probe(struct pci_de
+       ocelot->ptp = 1;
+-      ds = kzalloc(sizeof(struct dsa_switch), GFP_KERNEL);
++      ds = dsa_switch_alloc(&pdev->dev, felix->info->num_ports);
+       if (!ds) {
+               err = -ENOMEM;
+               dev_err(&pdev->dev, "Failed to allocate DSA switch\n");
diff --git a/target/linux/layerscape/patches-5.4/701-net-0275-mii-Add-helpers-for-parsing-SGMII-auto-negotiation.patch b/target/linux/layerscape/patches-5.4/701-net-0275-mii-Add-helpers-for-parsing-SGMII-auto-negotiation.patch
new file mode 100644 (file)
index 0000000..c783143
--- /dev/null
@@ -0,0 +1,117 @@
+From bc447c21304c1297f340d3daaf69915ebbc1f882 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 30 Sep 2019 19:20:26 +0300
+Subject: [PATCH] mii: Add helpers for parsing SGMII auto-negotiation
+
+Typically a MAC PCS auto-configures itself after it receives the
+negotiated link settings from the PHY, but some MAC devices are more
+special and need manual manipulation of the SGMII AN result.
+
+Therefore, add the bit definitions for the SGMII registers 4 and 5
+(local device ability, link partner ability), as well as a link_mode
+conversion helper that can be used to feed the AN results into
+phy_resolve_aneg_linkmode.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ include/linux/mii.h      | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
+ include/uapi/linux/mii.h | 10 ++++++++++
+ 2 files changed, 60 insertions(+)
+
+--- a/include/linux/mii.h
++++ b/include/linux/mii.h
+@@ -373,6 +373,56 @@ static inline u32 mii_lpa_to_ethtool_lpa
+ }
+ /**
++ * mii_lpa_mod_linkmode_adv_sgmii
++ * @lp_advertising: pointer to destination link mode.
++ * @lpa: value of the MII_LPA register
++ *
++ * A small helper function that translates MII_LPA bits to
++ * linkmode advertisement settings for SGMII.
++ * Leaves other bits unchanged.
++ */
++static inline void
++mii_lpa_mod_linkmode_lpa_sgmii(unsigned long *lp_advertising, u32 lpa)
++{
++      u32 speed_duplex = lpa & LPA_SGMII_DPX_SPD_MASK;
++
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, lp_advertising,
++                       speed_duplex == LPA_SGMII_1000HALF);
++
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, lp_advertising,
++                       speed_duplex == LPA_SGMII_1000FULL);
++
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, lp_advertising,
++                       speed_duplex == LPA_SGMII_100HALF);
++
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, lp_advertising,
++                       speed_duplex == LPA_SGMII_100FULL);
++
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, lp_advertising,
++                       speed_duplex == LPA_SGMII_10HALF);
++
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, lp_advertising,
++                       speed_duplex == LPA_SGMII_10FULL);
++}
++
++/**
++ * mii_lpa_to_linkmode_adv_sgmii
++ * @advertising: pointer to destination link mode.
++ * @lpa: value of the MII_LPA register
++ *
++ * A small helper function that translates MII_ADVERTISE bits
++ * to linkmode advertisement settings when in SGMII mode.
++ * Clears the old value of advertising.
++ */
++static inline void mii_lpa_to_linkmode_lpa_sgmii(unsigned long *lp_advertising,
++                                               u32 lpa)
++{
++      linkmode_zero(lp_advertising);
++
++      mii_lpa_mod_linkmode_lpa_sgmii(lp_advertising, lpa);
++}
++
++/**
+  * mii_adv_mod_linkmode_adv_t
+  * @advertising:pointer to destination link mode.
+  * @adv: value of the MII_ADVERTISE register
+--- a/include/uapi/linux/mii.h
++++ b/include/uapi/linux/mii.h
+@@ -71,6 +71,7 @@
+ /* Advertisement control register. */
+ #define ADVERTISE_SLCT                0x001f  /* Selector bits               */
+ #define ADVERTISE_CSMA                0x0001  /* Only selector supported     */
++#define ADVERTISE_SGMII               0x0001  /* Can do SGMII                */
+ #define ADVERTISE_10HALF      0x0020  /* Try for 10mbps half-duplex  */
+ #define ADVERTISE_1000XFULL   0x0020  /* Try for 1000BASE-X full-duplex */
+ #define ADVERTISE_10FULL      0x0040  /* Try for 10mbps full-duplex  */
+@@ -94,6 +95,7 @@
+ /* Link partner ability register. */
+ #define LPA_SLCT              0x001f  /* Same as advertise selector  */
++#define LPA_SGMII             0x0001  /* Can do SGMII                */
+ #define LPA_10HALF            0x0020  /* Can do 10mbps half-duplex   */
+ #define LPA_1000XFULL         0x0020  /* Can do 1000BASE-X full-duplex */
+ #define LPA_10FULL            0x0040  /* Can do 10mbps full-duplex   */
+@@ -104,11 +106,19 @@
+ #define LPA_1000XPAUSE_ASYM   0x0100  /* Can do 1000BASE-X pause asym*/
+ #define LPA_100BASE4          0x0200  /* Can do 100mbps 4k packets   */
+ #define LPA_PAUSE_CAP         0x0400  /* Can pause                   */
++#define LPA_SGMII_DPX_SPD_MASK        0x1C00  /* SGMII duplex and speed bits */
++#define LPA_SGMII_10HALF      0x0000  /* Can do SGMII 10mbps half-duplex */
++#define LPA_SGMII_10FULL      0x1000  /* Can do SGMII 10mbps full-duplex */
++#define LPA_SGMII_100HALF     0x0400  /* Can do SGMII 100mbps half-duplex */
++#define LPA_SGMII_100FULL     0x1400  /* Can do SGMII 100mbps full-duplex */
+ #define LPA_PAUSE_ASYM                0x0800  /* Can pause asymetrically     */
++#define LPA_SGMII_1000HALF    0x0800  /* Can do SGMII 1000mbps half-duplex */
++#define LPA_SGMII_1000FULL    0x1800  /* Can do SGMII 1000mbps full-duplex */
+ #define LPA_RESV              0x1000  /* Unused...                   */
+ #define LPA_RFAULT            0x2000  /* Link partner faulted        */
+ #define LPA_LPACK             0x4000  /* Link partner acked us       */
+ #define LPA_NPAGE             0x8000  /* Next page bit               */
++#define LPA_SGMII_LINK                0x8000  /* Link partner has link       */
+ #define LPA_DUPLEX            (LPA_10FULL | LPA_100FULL)
+ #define LPA_100                       (LPA_100FULL | LPA_100HALF | LPA_100BASE4)
diff --git a/target/linux/layerscape/patches-5.4/701-net-0276-net-phylink-make-QSGMII-a-valid-PHY-mode-for-in-band.patch b/target/linux/layerscape/patches-5.4/701-net-0276-net-phylink-make-QSGMII-a-valid-PHY-mode-for-in-band.patch
new file mode 100644 (file)
index 0000000..d04ed91
--- /dev/null
@@ -0,0 +1,26 @@
+From 4446e9789e662fe53dfcfe34551b5b74a013086c Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 22 Nov 2019 13:46:46 +0200
+Subject: [PATCH] net: phylink: make QSGMII a valid PHY mode for in-band AN
+
+QSGMII is just SGMII clocked at a higher frequency (5 Gbaud vs 1.25
+Gbaud). Logically it is just 4 SGMII interfaces multiplexed onto the
+same physical lanes. Each MAC PCS has its own in-band AN process with
+the system side of the QSGMII PHY, which is identical to the regular
+SGMII AN process. So allow QSGMII as a valid in-band AN mode.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/phy/phylink.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -283,6 +283,7 @@ static int phylink_parse_mode(struct phy
+               switch (pl->link_config.interface) {
+               case PHY_INTERFACE_MODE_SGMII:
++              case PHY_INTERFACE_MODE_QSGMII:
+                       phylink_set(pl->supported, 10baseT_Half);
+                       phylink_set(pl->supported, 10baseT_Full);
+                       phylink_set(pl->supported, 100baseT_Half);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0277-net-phylink-call-mac_an_restart-for-SGMII-QSGMII-inb.patch b/target/linux/layerscape/patches-5.4/701-net-0277-net-phylink-call-mac_an_restart-for-SGMII-QSGMII-inb.patch
new file mode 100644 (file)
index 0000000..487a520
--- /dev/null
@@ -0,0 +1,29 @@
+From d526228a8159d136c914c8f71d5944cda2f93d9a Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Thu, 28 Nov 2019 03:21:53 +0200
+Subject: [PATCH] net: phylink: call mac_an_restart for SGMII/QSGMII inband
+ interfaces too
+
+It doesn't quite make sense why restarting the AN process should be
+unique to 802.3z (1000Base-X) modes. It is valid to put an SGMII PCS in
+in-band AN mode, therefore also make PHYLINK re-trigger an
+auto-negotiation if needed.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/phy/phylink.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -360,7 +360,9 @@ static void phylink_mac_config_up(struct
+ static void phylink_mac_an_restart(struct phylink *pl)
+ {
+       if (pl->link_config.an_enabled &&
+-          phy_interface_mode_is_8023z(pl->link_config.interface))
++          (phy_interface_mode_is_8023z(pl->link_config.interface) ||
++           pl->link_config.interface == PHY_INTERFACE_MODE_SGMII ||
++           pl->link_config.interface == PHY_INTERFACE_MODE_QSGMII))
+               pl->ops->mac_an_restart(pl->config);
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0278-enetc-export-enetc_mdio-definitionns-to-include-linu.patch b/target/linux/layerscape/patches-5.4/701-net-0278-enetc-export-enetc_mdio-definitionns-to-include-linu.patch
new file mode 100644 (file)
index 0000000..b558a78
--- /dev/null
@@ -0,0 +1,192 @@
+From 210fde07cd9e3f2dc826f538ccec4e90b54eb7e5 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 22 Nov 2019 17:47:56 +0200
+Subject: [PATCH] enetc: export enetc_mdio definitionns to include/linux/fsl
+
+The Felix DSA switch has an internal MDIO bus that has the same register
+map as the ENETC one, so the accessors can be reused.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_mdio.c  | 18 +++++++++-
+ drivers/net/ethernet/freescale/enetc/enetc_mdio.h  | 12 -------
+ .../net/ethernet/freescale/enetc/enetc_pci_mdio.c  | 41 +++++++++++++---------
+ include/linux/fsl/enetc_mdio.h                     | 21 +++++++++++
+ 4 files changed, 62 insertions(+), 30 deletions(-)
+ delete mode 100644 drivers/net/ethernet/freescale/enetc/enetc_mdio.h
+ create mode 100644 include/linux/fsl/enetc_mdio.h
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
+@@ -1,13 +1,13 @@
+ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+ /* Copyright 2019 NXP */
++#include <linux/fsl/enetc_mdio.h>
+ #include <linux/mdio.h>
+ #include <linux/of_mdio.h>
+ #include <linux/iopoll.h>
+ #include <linux/of.h>
+ #include "enetc_pf.h"
+-#include "enetc_mdio.h"
+ #define       ENETC_MDIO_CFG  0x0     /* MDIO configuration and status */
+ #define       ENETC_MDIO_CTL  0x4     /* MDIO control */
+@@ -99,6 +99,7 @@ int enetc_mdio_write(struct mii_bus *bus
+       return 0;
+ }
++EXPORT_SYMBOL_GPL(enetc_mdio_write);
+ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
+ {
+@@ -154,6 +155,21 @@ int enetc_mdio_read(struct mii_bus *bus,
+       return value;
+ }
++EXPORT_SYMBOL_GPL(enetc_mdio_read);
++
++struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
++{
++      struct enetc_hw *hw;
++
++      hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
++      if (!hw)
++              return ERR_PTR(-ENOMEM);
++
++      hw->port = port_regs;
++
++      return hw;
++}
++EXPORT_SYMBOL_GPL(enetc_hw_alloc);
+ int enetc_mdio_probe(struct enetc_pf *pf)
+ {
+--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.h
++++ /dev/null
+@@ -1,12 +0,0 @@
+-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+-/* Copyright 2019 NXP */
+-
+-#include <linux/phy.h>
+-
+-struct enetc_mdio_priv {
+-      struct enetc_hw *hw;
+-      int mdio_base;
+-};
+-
+-int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value);
+-int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum);
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
+@@ -1,8 +1,8 @@
+ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+ /* Copyright 2019 NXP */
++#include <linux/fsl/enetc_mdio.h>
+ #include <linux/of_mdio.h>
+ #include "enetc_pf.h"
+-#include "enetc_mdio.h"
+ #define ENETC_MDIO_DEV_ID     0xee01
+ #define ENETC_MDIO_DEV_NAME   "FSL PCIe IE Central MDIO"
+@@ -14,17 +14,29 @@ static int enetc_pci_mdio_probe(struct p
+ {
+       struct enetc_mdio_priv *mdio_priv;
+       struct device *dev = &pdev->dev;
++      void __iomem *port_regs;
+       struct enetc_hw *hw;
+       struct mii_bus *bus;
+       int err;
+-      hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
+-      if (!hw)
+-              return -ENOMEM;
++      port_regs = pci_iomap(pdev, 0, 0);
++      if (!port_regs) {
++              dev_err(dev, "iomap failed\n");
++              err = -ENXIO;
++              goto err_ioremap;
++      }
++
++      hw = enetc_hw_alloc(dev, port_regs);
++      if (IS_ERR(enetc_hw_alloc)) {
++              err = PTR_ERR(hw);
++              goto err_hw_alloc;
++      }
+       bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
+-      if (!bus)
+-              return -ENOMEM;
++      if (!bus) {
++              err = -ENOMEM;
++              goto err_mdiobus_alloc;
++      }
+       bus->name = ENETC_MDIO_BUS_NAME;
+       bus->read = enetc_mdio_read;
+@@ -39,7 +51,7 @@ static int enetc_pci_mdio_probe(struct p
+       err = pci_enable_device_mem(pdev);
+       if (err) {
+               dev_err(dev, "device enable failed\n");
+-              return err;
++              goto err_pci_enable;
+       }
+       err = pci_request_region(pdev, 0, KBUILD_MODNAME);
+@@ -48,13 +60,6 @@ static int enetc_pci_mdio_probe(struct p
+               goto err_pci_mem_reg;
+       }
+-      hw->port = pci_iomap(pdev, 0, 0);
+-      if (!hw->port) {
+-              err = -ENXIO;
+-              dev_err(dev, "iomap failed\n");
+-              goto err_ioremap;
+-      }
+-
+       err = of_mdiobus_register(bus, dev->of_node);
+       if (err)
+               goto err_mdiobus_reg;
+@@ -64,12 +69,14 @@ static int enetc_pci_mdio_probe(struct p
+       return 0;
+ err_mdiobus_reg:
+-      iounmap(mdio_priv->hw->port);
+-err_ioremap:
+       pci_release_mem_regions(pdev);
+ err_pci_mem_reg:
+       pci_disable_device(pdev);
+-
++err_pci_enable:
++err_mdiobus_alloc:
++      iounmap(port_regs);
++err_hw_alloc:
++err_ioremap:
+       return err;
+ }
+--- /dev/null
++++ b/include/linux/fsl/enetc_mdio.h
+@@ -0,0 +1,21 @@
++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
++/* Copyright 2019 NXP */
++
++#include <linux/phy.h>
++
++/* PCS registers */
++#define ENETC_PCS_LINK_TIMER1         0x12
++#define ENETC_PCS_LINK_TIMER1_VAL     0x06a0
++#define ENETC_PCS_LINK_TIMER2         0x13
++#define ENETC_PCS_LINK_TIMER2_VAL     0x0003
++#define ENETC_PCS_IF_MODE             0x14
++#define ENETC_PCS_IF_MODE_SGMII_AN    0x0003
++
++struct enetc_mdio_priv {
++      struct enetc_hw *hw;
++      int mdio_base;
++};
++
++int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value);
++int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum);
++struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0279-enetc-Set-MDIO_CFG_HOLD-to-the-recommended-value-of-.patch b/target/linux/layerscape/patches-5.4/701-net-0279-enetc-Set-MDIO_CFG_HOLD-to-the-recommended-value-of-.patch
new file mode 100644 (file)
index 0000000..02ead27
--- /dev/null
@@ -0,0 +1,58 @@
+From 5961ca6738507031a64f8580ceb8ab0b630d47a5 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Wed, 27 Nov 2019 19:21:13 +0200
+Subject: [PATCH] enetc: Set MDIO_CFG_HOLD to the recommended value of 2
+
+This increases the MDIO hold time to 5 enet_clk cycles from the previous
+value of 0. This is actually the out-of-reset value, that the driver was
+previously overwriting with 0. Zero worked for the external MDIO, but
+breaks communication with the internal MDIO buses on which the PCS of
+ENETC SI's and Felix switch are found.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_mdio.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
+@@ -31,15 +31,19 @@ static inline void _enetc_mdio_wr(struct
+       _enetc_mdio_wr(mdio_priv, ENETC_##off, val)
+ #define enetc_mdio_rd_reg(off)        enetc_mdio_rd(mdio_priv, off)
+-#define ENETC_MDC_DIV         258
+-
+ #define MDIO_CFG_CLKDIV(x)    ((((x) >> 1) & 0xff) << 8)
+ #define MDIO_CFG_BSY          BIT(0)
+ #define MDIO_CFG_RD_ER                BIT(1)
++#define MDIO_CFG_HOLD(x)      (((x) << 2) & GENMASK(4, 2))
+ #define MDIO_CFG_ENC45                BIT(6)
+  /* external MDIO only - driven on neg MDC edge */
+ #define MDIO_CFG_NEG          BIT(23)
++#define ENETC_EMDIO_CFG \
++      (MDIO_CFG_HOLD(2) | \
++       MDIO_CFG_CLKDIV(258) | \
++       MDIO_CFG_NEG)
++
+ #define MDIO_CTL_DEV_ADDR(x)  ((x) & 0x1f)
+ #define MDIO_CTL_PORT_ADDR(x) (((x) & 0x1f) << 5)
+ #define MDIO_CTL_READ         BIT(15)
+@@ -61,7 +65,7 @@ int enetc_mdio_write(struct mii_bus *bus
+       u16 dev_addr;
+       int ret;
+-      mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
++      mdio_cfg = ENETC_EMDIO_CFG;
+       if (regnum & MII_ADDR_C45) {
+               dev_addr = (regnum >> 16) & 0x1f;
+               mdio_cfg |= MDIO_CFG_ENC45;
+@@ -108,7 +112,7 @@ int enetc_mdio_read(struct mii_bus *bus,
+       u16 dev_addr, value;
+       int ret;
+-      mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
++      mdio_cfg = ENETC_EMDIO_CFG;
+       if (regnum & MII_ADDR_C45) {
+               dev_addr = (regnum >> 16) & 0x1f;
+               mdio_cfg |= MDIO_CFG_ENC45;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0280-net-mscc-ocelot-do-not-force-Felix-MACs-at-lower-spe.patch b/target/linux/layerscape/patches-5.4/701-net-0280-net-mscc-ocelot-do-not-force-Felix-MACs-at-lower-spe.patch
new file mode 100644 (file)
index 0000000..a31321f
--- /dev/null
@@ -0,0 +1,154 @@
+From 4ba6e00c2f45bf4189ec6a8ef71b45346ae804f2 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Thu, 28 Nov 2019 15:36:10 +0200
+Subject: [PATCH] net: mscc: ocelot: do not force Felix MACs at lower speeds
+ than gigabit
+
+In the LS1028A, the VSC9959 switch was integrated with an NXP PCS which
+performs SGMII AN and rate adaptation autonomously. The MAC does not
+need to know about this, and forcing the MAC speed to something else,
+when connected to a 10/100 link partner, actually breaks the GMII
+internal link between the MAC and the PCS.
+
+Add a quirk system in the ocelot driver, and a first quirk called "PCS
+performs rate adaptation", to distinguish the VSC7514 from the VSC9959
+regarding this behavior.
+
+Signed-off-by: Catalin Horghidan <catalin.horghidan@nxp.com>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/dsa/ocelot/felix.c         |  1 +
+ drivers/net/dsa/ocelot/felix.h         |  1 +
+ drivers/net/dsa/ocelot/felix_vsc9959.c |  1 +
+ drivers/net/ethernet/mscc/ocelot.c     | 32 ++++++++++++++++++--------------
+ include/soc/mscc/ocelot.h              |  7 +++++++
+ 5 files changed, 28 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -249,6 +249,7 @@ static int felix_init_structs(struct fel
+       ocelot->num_stats       = felix->info->num_stats;
+       ocelot->shared_queue_sz = felix->info->shared_queue_sz;
+       ocelot->ops             = felix->info->ops;
++      ocelot->quirks          = felix->info->quirks;
+       base = pci_resource_start(felix->pdev, felix->info->pci_bar);
+--- a/drivers/net/dsa/ocelot/felix.h
++++ b/drivers/net/dsa/ocelot/felix.h
+@@ -18,6 +18,7 @@ struct felix_info {
+       unsigned int                    num_stats;
+       int                             num_ports;
+       int                             pci_bar;
++      unsigned long                   quirks;
+ };
+ extern struct felix_info              felix_info_vsc9959;
+--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
+@@ -584,4 +584,5 @@ struct felix_info felix_info_vsc9959 = {
+       .shared_queue_sz        = 128 * 1024,
+       .num_ports              = 6,
+       .pci_bar                = 4,
++      .quirks                 = OCELOT_PCS_PERFORMS_RATE_ADAPTATION,
+ };
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -409,27 +409,32 @@ static u16 ocelot_wm_enc(u16 value)
+ void ocelot_adjust_link(struct ocelot *ocelot, int port,
+                       struct phy_device *phydev)
+ {
++      int speed, mac_speed, mac_mode = DEV_MAC_MODE_CFG_FDX_ENA;
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+-      int speed, mode = 0;
+-      switch (phydev->speed) {
++      if (ocelot->quirks & OCELOT_PCS_PERFORMS_RATE_ADAPTATION)
++              speed = SPEED_1000;
++      else
++              speed = phydev->speed;
++
++      switch (speed) {
+       case SPEED_10:
+-              speed = OCELOT_SPEED_10;
++              mac_speed = OCELOT_SPEED_10;
+               break;
+       case SPEED_100:
+-              speed = OCELOT_SPEED_100;
++              mac_speed = OCELOT_SPEED_100;
+               break;
+       case SPEED_1000:
+-              speed = OCELOT_SPEED_1000;
+-              mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA;
++              mac_speed = OCELOT_SPEED_1000;
++              mac_mode |= DEV_MAC_MODE_CFG_GIGA_MODE_ENA;
+               break;
+       case SPEED_2500:
+-              speed = OCELOT_SPEED_2500;
+-              mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA;
++              mac_speed = OCELOT_SPEED_2500;
++              mac_mode |= DEV_MAC_MODE_CFG_GIGA_MODE_ENA;
+               break;
+       default:
+               dev_err(ocelot->dev, "Unsupported PHY speed on port %d: %d\n",
+-                      port, phydev->speed);
++                      port, speed);
+               return;
+       }
+@@ -439,8 +444,7 @@ void ocelot_adjust_link(struct ocelot *o
+               return;
+       /* Only full duplex supported for now */
+-      ocelot_port_writel(ocelot_port, DEV_MAC_MODE_CFG_FDX_ENA |
+-                         mode, DEV_MAC_MODE_CFG);
++      ocelot_port_writel(ocelot_port, mac_mode, DEV_MAC_MODE_CFG);
+       if (ocelot->ops->pcs_init)
+               ocelot->ops->pcs_init(ocelot, port);
+@@ -451,11 +455,11 @@ void ocelot_adjust_link(struct ocelot *o
+       /* Take MAC, Port, Phy (intern) and PCS (SGMII/Serdes) clock out of
+        * reset */
+-      ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(speed),
++      ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(mac_speed),
+                          DEV_CLOCK_CFG);
+       /* No PFC */
+-      ocelot_write_gix(ocelot, ANA_PFC_PFC_CFG_FC_LINK_SPEED(speed),
++      ocelot_write_gix(ocelot, ANA_PFC_PFC_CFG_FC_LINK_SPEED(mac_speed),
+                        ANA_PFC_PFC_CFG, port);
+       /* Core: Enable port for frame transfer */
+@@ -469,7 +473,7 @@ void ocelot_adjust_link(struct ocelot *o
+                        SYS_MAC_FC_CFG_RX_FC_ENA | SYS_MAC_FC_CFG_TX_FC_ENA |
+                        SYS_MAC_FC_CFG_ZERO_PAUSE_ENA |
+                        SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) |
+-                       SYS_MAC_FC_CFG_FC_LINK_SPEED(speed),
++                       SYS_MAC_FC_CFG_FC_LINK_SPEED(mac_speed),
+                        SYS_MAC_FC_CFG, port);
+       ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port);
+ }
+--- a/include/soc/mscc/ocelot.h
++++ b/include/soc/mscc/ocelot.h
+@@ -404,6 +404,11 @@ enum ocelot_tag_prefix {
+       OCELOT_TAG_PREFIX_LONG,
+ };
++/* Hardware quirks (differences between switch instantiations) */
++enum {
++      OCELOT_PCS_PERFORMS_RATE_ADAPTATION     = BIT(0),
++};
++
+ struct ocelot;
+ struct ocelot_ops {
+@@ -464,6 +469,8 @@ struct ocelot {
+       struct delayed_work             stats_work;
+       struct workqueue_struct         *stats_queue;
++      unsigned long                   quirks;
++
+       u8                              ptp:1;
+       struct ptp_clock                *ptp_clock;
+       struct ptp_clock_info           ptp_info;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0281-net-mscc-ocelot-convert-to-PHYLINK.patch b/target/linux/layerscape/patches-5.4/701-net-0281-net-mscc-ocelot-convert-to-PHYLINK.patch
new file mode 100644 (file)
index 0000000..fcf28b8
--- /dev/null
@@ -0,0 +1,689 @@
+From 0a2b7489bf60d24a54e16147b416f339ebe4f511 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 18 Nov 2019 18:05:01 +0200
+Subject: [PATCH] net: mscc: ocelot: convert to PHYLINK
+
+This patch reworks ocelot_board.c (aka the MIPS on the VSC7514) to
+register a PHYLINK instance for each port. The registration code is
+local to the VSC7514, but the PHYLINK callback implementation is common
+so that the Felix DSA front-end can use it as well (but DSA does its own
+registration).
+
+Now Felix can use native PHYLINK callbacks instead of the PHYLIB
+adaptation layer in DSA, which had issues supporting fixed-link slave
+ports (no struct phy_device to pass to the adjust_link callback), as
+well as fixed-link CPU port at 2.5Gbps.
+
+The old code from ocelot_port_enable and ocelot_port_disable has been
+moved into ocelot_phylink_mac_link_up and ocelot_phylink_mac_link_down.
+
+The PHY connect operation has been moved from ocelot_port_open to
+mscc_ocelot_probe in ocelot_board.c.
+
+The phy_set_mode_ext() call for the SerDes PHY has also been moved into
+mscc_ocelot_probe from ocelot_port_open, and since that was the only
+reason why a reference to it was kept in ocelot_port_private, that
+reference was removed.
+
+Again, the usage of phy_interface_t phy_mode is now local to
+mscc_ocelot_probe only, after moving the PHY connect operation.
+So it was also removed from ocelot_port_private.
+*Maybe* in the future, it can be added back to the common struct
+ocelot_port, with the purpose of validating mismatches between
+state->phy_interface and ocelot_port->phy_mode in PHYLINK callbacks.
+But at the moment that is not critical, since other DSA drivers are not
+doing that either. No SFP+ modules are in use with Felix/Ocelot yet, to
+my knowledge.
+
+In-band AN is not yet supported, due to the fact that this is a mostly
+mechanical patch for the moment. The mac_an_restart PHYLINK operation
+needs to be implemented, as well as mac_link_state. Both are SerDes
+specific, and Felix does not have its PCS configured yet (it works just
+by virtue of U-Boot initialization at the moment).
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/dsa/ocelot/felix.c           |  65 +++++++++----
+ drivers/net/ethernet/mscc/Kconfig        |   2 +-
+ drivers/net/ethernet/mscc/ocelot.c       | 150 ++++++++++++++++--------------
+ drivers/net/ethernet/mscc/ocelot.h       |  13 +--
+ drivers/net/ethernet/mscc/ocelot_board.c | 154 +++++++++++++++++++++++++++----
+ include/soc/mscc/ocelot.h                |  22 ++++-
+ 6 files changed, 289 insertions(+), 117 deletions(-)
+
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -58,14 +58,6 @@ static int felix_set_ageing_time(struct
+       return 0;
+ }
+-static void felix_adjust_link(struct dsa_switch *ds, int port,
+-                            struct phy_device *phydev)
+-{
+-      struct ocelot *ocelot = ds->priv;
+-
+-      ocelot_adjust_link(ocelot, port, phydev);
+-}
+-
+ static int felix_fdb_dump(struct dsa_switch *ds, int port,
+                         dsa_fdb_dump_cb_t *cb, void *data)
+ {
+@@ -185,21 +177,59 @@ static int felix_tsn_enable(struct dsa_p
+ }
+ #endif
+-static int felix_port_enable(struct dsa_switch *ds, int port,
+-                           struct phy_device *phy)
++static void felix_phylink_validate(struct dsa_switch *ds, int port,
++                                 unsigned long *supported,
++                                 struct phylink_link_state *state)
+ {
+       struct ocelot *ocelot = ds->priv;
+-      ocelot_port_enable(ocelot, port, phy);
++      ocelot_phylink_validate(ocelot, port, supported, state);
++}
++
++static int felix_phylink_mac_pcs_get_state(struct dsa_switch *ds, int port,
++                                         struct phylink_link_state *state)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      ocelot_phylink_mac_pcs_get_state(ocelot, port, state);
+       return 0;
+ }
+-static void felix_port_disable(struct dsa_switch *ds, int port)
++static void felix_phylink_mac_config(struct dsa_switch *ds, int port,
++                                   unsigned int link_an_mode,
++                                   const struct phylink_link_state *state)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      ocelot_phylink_mac_config(ocelot, port, link_an_mode, state);
++}
++
++static void felix_phylink_mac_an_restart(struct dsa_switch *ds, int port)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      ocelot_phylink_mac_an_restart(ocelot, port);
++}
++
++static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port,
++                                      unsigned int link_an_mode,
++                                      phy_interface_t interface)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      ocelot_phylink_mac_link_down(ocelot, port, link_an_mode, interface);
++}
++
++static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
++                                    unsigned int link_an_mode,
++                                    phy_interface_t interface,
++                                    struct phy_device *phydev)
+ {
+       struct ocelot *ocelot = ds->priv;
+-      return ocelot_port_disable(ocelot, port);
++      ocelot_phylink_mac_link_up(ocelot, port, link_an_mode, interface,
++                                 phydev);
+ }
+ static void felix_get_strings(struct dsa_switch *ds, int port,
+@@ -417,9 +447,12 @@ static const struct dsa_switch_ops felix
+       .get_ethtool_stats      = felix_get_ethtool_stats,
+       .get_sset_count         = felix_get_sset_count,
+       .get_ts_info            = felix_get_ts_info,
+-      .adjust_link            = felix_adjust_link,
+-      .port_enable            = felix_port_enable,
+-      .port_disable           = felix_port_disable,
++      .phylink_validate       = felix_phylink_validate,
++      .phylink_mac_link_state = felix_phylink_mac_pcs_get_state,
++      .phylink_mac_config     = felix_phylink_mac_config,
++      .phylink_mac_an_restart = felix_phylink_mac_an_restart,
++      .phylink_mac_link_down  = felix_phylink_mac_link_down,
++      .phylink_mac_link_up    = felix_phylink_mac_link_up,
+       .port_fdb_dump          = felix_fdb_dump,
+       .port_fdb_add           = felix_fdb_add,
+       .port_fdb_del           = felix_fdb_del,
+--- a/drivers/net/ethernet/mscc/Kconfig
++++ b/drivers/net/ethernet/mscc/Kconfig
+@@ -15,7 +15,7 @@ config MSCC_OCELOT_SWITCH
+       tristate "Ocelot switch driver"
+       depends on NET_SWITCHDEV
+       depends on HAS_IOMEM
+-      select PHYLIB
++      select PHYLINK
+       select REGMAP_MMIO
+       help
+         This driver supports the Ocelot network switch device.
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -13,7 +13,7 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/netdevice.h>
+-#include <linux/phy.h>
++#include <linux/phylink.h>
+ #include <linux/ptp_clock_kernel.h>
+ #include <linux/skbuff.h>
+ #include <linux/iopoll.h>
+@@ -406,18 +406,66 @@ static u16 ocelot_wm_enc(u16 value)
+       return value;
+ }
+-void ocelot_adjust_link(struct ocelot *ocelot, int port,
+-                      struct phy_device *phydev)
++void ocelot_phylink_validate(struct ocelot *ocelot, int port,
++                           unsigned long *supported,
++                           struct phylink_link_state *state)
++{
++      __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
++
++      if (state->interface != PHY_INTERFACE_MODE_NA &&
++          state->interface != PHY_INTERFACE_MODE_GMII &&
++          state->interface != PHY_INTERFACE_MODE_SGMII &&
++          state->interface != PHY_INTERFACE_MODE_QSGMII) {
++              bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
++              return;
++      }
++
++      /* No half-duplex. */
++      phylink_set_port_modes(mask);
++      phylink_set(mask, Autoneg);
++      phylink_set(mask, Pause);
++      phylink_set(mask, Asym_Pause);
++      phylink_set(mask, 10baseT_Full);
++      phylink_set(mask, 100baseT_Full);
++      phylink_set(mask, 1000baseT_Full);
++      phylink_set(mask, 2500baseT_Full);
++
++      bitmap_and(supported, supported, mask,
++                 __ETHTOOL_LINK_MODE_MASK_NBITS);
++      bitmap_and(state->advertising, state->advertising, mask,
++                 __ETHTOOL_LINK_MODE_MASK_NBITS);
++}
++EXPORT_SYMBOL(ocelot_phylink_validate);
++
++void ocelot_phylink_mac_pcs_get_state(struct ocelot *ocelot, int port,
++                                    struct phylink_link_state *state)
++{
++      state->link = 1;
++}
++EXPORT_SYMBOL(ocelot_phylink_mac_pcs_get_state);
++
++void ocelot_phylink_mac_an_restart(struct ocelot *ocelot, int port)
++{
++      /* Not supported */
++}
++EXPORT_SYMBOL(ocelot_phylink_mac_an_restart);
++
++void ocelot_phylink_mac_config(struct ocelot *ocelot, int port,
++                             unsigned int link_an_mode,
++                             const struct phylink_link_state *state)
+ {
+       int speed, mac_speed, mac_mode = DEV_MAC_MODE_CFG_FDX_ENA;
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
++      u32 mac_fc_cfg;
+       if (ocelot->quirks & OCELOT_PCS_PERFORMS_RATE_ADAPTATION)
+               speed = SPEED_1000;
+       else
+-              speed = phydev->speed;
++              speed = state->speed;
+       switch (speed) {
++      case SPEED_UNKNOWN:
++              return;
+       case SPEED_10:
+               mac_speed = OCELOT_SPEED_10;
+               break;
+@@ -433,16 +481,11 @@ void ocelot_adjust_link(struct ocelot *o
+               mac_mode |= DEV_MAC_MODE_CFG_GIGA_MODE_ENA;
+               break;
+       default:
+-              dev_err(ocelot->dev, "Unsupported PHY speed on port %d: %d\n",
++              dev_err(ocelot->dev, "Unsupported speed on port %d: %d\n",
+                       port, speed);
+               return;
+       }
+-      phy_print_status(phydev);
+-
+-      if (!phydev->link)
+-              return;
+-
+       /* Only full duplex supported for now */
+       ocelot_port_writel(ocelot_port, mac_mode, DEV_MAC_MODE_CFG);
+@@ -469,27 +512,36 @@ void ocelot_adjust_link(struct ocelot *o
+                        QSYS_SWITCH_PORT_MODE, port);
+       /* Flow control */
+-      ocelot_write_rix(ocelot, SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) |
+-                       SYS_MAC_FC_CFG_RX_FC_ENA | SYS_MAC_FC_CFG_TX_FC_ENA |
+-                       SYS_MAC_FC_CFG_ZERO_PAUSE_ENA |
+-                       SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) |
+-                       SYS_MAC_FC_CFG_FC_LINK_SPEED(mac_speed),
+-                       SYS_MAC_FC_CFG, port);
++      mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(mac_speed);
++      if (state->pause & MLO_PAUSE_RX)
++              mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA;
++      if (state->pause & MLO_PAUSE_TX)
++              mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA |
++                            SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) |
++                            SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) |
++                            SYS_MAC_FC_CFG_ZERO_PAUSE_ENA;
++      ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port);
++
+       ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port);
+ }
+-EXPORT_SYMBOL(ocelot_adjust_link);
++EXPORT_SYMBOL(ocelot_phylink_mac_config);
+-static void ocelot_port_adjust_link(struct net_device *dev)
++void ocelot_phylink_mac_link_down(struct ocelot *ocelot, int port,
++                                unsigned int link_an_mode,
++                                phy_interface_t interface)
+ {
+-      struct ocelot_port_private *priv = netdev_priv(dev);
+-      struct ocelot *ocelot = priv->port.ocelot;
+-      int port = priv->chip_port;
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
+-      ocelot_adjust_link(ocelot, port, dev->phydev);
++      ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG);
++      ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA,
++                     QSYS_SWITCH_PORT_MODE, port);
+ }
++EXPORT_SYMBOL(ocelot_phylink_mac_link_down);
+-void ocelot_port_enable(struct ocelot *ocelot, int port,
+-                      struct phy_device *phy)
++void ocelot_phylink_mac_link_up(struct ocelot *ocelot, int port,
++                              unsigned int link_an_mode,
++                              phy_interface_t interface,
++                              struct phy_device *phy)
+ {
+       /* Enable receiving frames on the port, and activate auto-learning of
+        * MAC addresses.
+@@ -499,62 +551,22 @@ void ocelot_port_enable(struct ocelot *o
+                        ANA_PORT_PORT_CFG_PORTID_VAL(port),
+                        ANA_PORT_PORT_CFG, port);
+ }
+-EXPORT_SYMBOL(ocelot_port_enable);
++EXPORT_SYMBOL(ocelot_phylink_mac_link_up);
+ static int ocelot_port_open(struct net_device *dev)
+ {
+       struct ocelot_port_private *priv = netdev_priv(dev);
+-      struct ocelot *ocelot = priv->port.ocelot;
+-      int port = priv->chip_port;
+-      int err;
+-
+-      if (priv->serdes) {
+-              err = phy_set_mode_ext(priv->serdes, PHY_MODE_ETHERNET,
+-                                     priv->phy_mode);
+-              if (err) {
+-                      netdev_err(dev, "Could not set mode of SerDes\n");
+-                      return err;
+-              }
+-      }
+-
+-      err = phy_connect_direct(dev, priv->phy, &ocelot_port_adjust_link,
+-                               priv->phy_mode);
+-      if (err) {
+-              netdev_err(dev, "Could not attach to PHY\n");
+-              return err;
+-      }
+-      dev->phydev = priv->phy;
+-
+-      phy_attached_info(priv->phy);
+-      phy_start(priv->phy);
+-
+-      ocelot_port_enable(ocelot, port, priv->phy);
++      phylink_start(priv->phylink);
+       return 0;
+ }
+-void ocelot_port_disable(struct ocelot *ocelot, int port)
+-{
+-      struct ocelot_port *ocelot_port = ocelot->ports[port];
+-
+-      ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG);
+-      ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA,
+-                     QSYS_SWITCH_PORT_MODE, port);
+-}
+-EXPORT_SYMBOL(ocelot_port_disable);
+-
+ static int ocelot_port_stop(struct net_device *dev)
+ {
+       struct ocelot_port_private *priv = netdev_priv(dev);
+-      struct ocelot *ocelot = priv->port.ocelot;
+-      int port = priv->chip_port;
+-
+-      phy_disconnect(priv->phy);
+-
+-      dev->phydev = NULL;
+-      ocelot_port_disable(ocelot, port);
++      phylink_stop(priv->phylink);
+       return 0;
+ }
+@@ -2251,8 +2263,7 @@ void ocelot_init_port(struct ocelot *oce
+ EXPORT_SYMBOL(ocelot_init_port);
+ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
+-                    void __iomem *regs,
+-                    struct phy_device *phy)
++                    void __iomem *regs)
+ {
+       struct ocelot_port_private *priv;
+       struct ocelot_port *ocelot_port;
+@@ -2265,7 +2276,6 @@ int ocelot_probe_port(struct ocelot *oce
+       SET_NETDEV_DEV(dev, ocelot->dev);
+       priv = netdev_priv(dev);
+       priv->dev = dev;
+-      priv->phy = phy;
+       priv->chip_port = port;
+       ocelot_port = &priv->port;
+       ocelot_port->ocelot = ocelot;
+--- a/drivers/net/ethernet/mscc/ocelot.h
++++ b/drivers/net/ethernet/mscc/ocelot.h
+@@ -12,8 +12,7 @@
+ #include <linux/etherdevice.h>
+ #include <linux/if_vlan.h>
+ #include <linux/net_tstamp.h>
+-#include <linux/phy.h>
+-#include <linux/phy/phy.h>
++#include <linux/phylink.h>
+ #include <linux/platform_device.h>
+ #include <linux/ptp_clock_kernel.h>
+ #include <linux/regmap.h>
+@@ -65,14 +64,12 @@ struct ocelot_multicast {
+ struct ocelot_port_private {
+       struct ocelot_port port;
+       struct net_device *dev;
+-      struct phy_device *phy;
++      struct phylink *phylink;
++      struct phylink_config phylink_config;
+       u8 chip_port;
+       u8 vlan_aware;
+-      phy_interface_t phy_mode;
+-      struct phy *serdes;
+-
+       struct ocelot_port_tc tc;
+ };
+@@ -83,9 +80,7 @@ void ocelot_port_writel(struct ocelot_po
+ #define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val))
+ int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops);
+-int ocelot_probe_port(struct ocelot *ocelot, u8 port,
+-                    void __iomem *regs,
+-                    struct phy_device *phy);
++int ocelot_probe_port(struct ocelot *ocelot, u8 port, void __iomem *regs);
+ void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu,
+                        enum ocelot_tag_prefix injection,
+--- a/drivers/net/ethernet/mscc/ocelot_board.c
++++ b/drivers/net/ethernet/mscc/ocelot_board.c
+@@ -13,6 +13,7 @@
+ #include <linux/mfd/syscon.h>
+ #include <linux/skbuff.h>
+ #include <net/switchdev.h>
++#include <linux/phy/phy.h>
+ #include "ocelot.h"
+@@ -262,6 +263,91 @@ static const struct ocelot_ops ocelot_op
+       .reset                  = ocelot_reset,
+ };
++static void ocelot_port_phylink_validate(struct phylink_config *config,
++                                       unsigned long *supported,
++                                       struct phylink_link_state *state)
++{
++      struct net_device *ndev = to_net_dev(config->dev);
++      struct ocelot_port_private *priv = netdev_priv(ndev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
++
++      ocelot_phylink_validate(ocelot, port, supported, state);
++}
++
++static int
++ocelot_port_phylink_mac_pcs_get_state(struct phylink_config *config,
++                                    struct phylink_link_state *state)
++{
++      struct net_device *ndev = to_net_dev(config->dev);
++      struct ocelot_port_private *priv = netdev_priv(ndev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
++
++      ocelot_phylink_mac_pcs_get_state(ocelot, port, state);
++
++      return 0;
++}
++
++static void ocelot_port_phylink_mac_an_restart(struct phylink_config *config)
++{
++      struct net_device *ndev = to_net_dev(config->dev);
++      struct ocelot_port_private *priv = netdev_priv(ndev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
++
++      ocelot_phylink_mac_an_restart(ocelot, port);
++}
++
++static void
++ocelot_port_phylink_mac_config(struct phylink_config *config,
++                             unsigned int link_an_mode,
++                             const struct phylink_link_state *state)
++{
++      struct net_device *ndev = to_net_dev(config->dev);
++      struct ocelot_port_private *priv = netdev_priv(ndev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
++
++      ocelot_phylink_mac_config(ocelot, port, link_an_mode, state);
++}
++
++static void ocelot_port_phylink_mac_link_down(struct phylink_config *config,
++                                            unsigned int link_an_mode,
++                                            phy_interface_t interface)
++{
++      struct net_device *ndev = to_net_dev(config->dev);
++      struct ocelot_port_private *priv = netdev_priv(ndev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
++
++      return ocelot_phylink_mac_link_down(ocelot, port, link_an_mode,
++                                          interface);
++}
++
++static void ocelot_port_phylink_mac_link_up(struct phylink_config *config,
++                                          unsigned int link_an_mode,
++                                          phy_interface_t interface,
++                                          struct phy_device *phy)
++{
++      struct net_device *ndev = to_net_dev(config->dev);
++      struct ocelot_port_private *priv = netdev_priv(ndev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
++
++      return ocelot_phylink_mac_link_up(ocelot, port, link_an_mode,
++                                        interface, phy);
++}
++
++static const struct phylink_mac_ops ocelot_phylink_ops = {
++      .validate               = ocelot_port_phylink_validate,
++      .mac_link_state         = ocelot_port_phylink_mac_pcs_get_state,
++      .mac_an_restart         = ocelot_port_phylink_mac_an_restart,
++      .mac_config             = ocelot_port_phylink_mac_config,
++      .mac_link_down          = ocelot_port_phylink_mac_link_down,
++      .mac_link_up            = ocelot_port_phylink_mac_link_up,
++};
++
+ static int mscc_ocelot_probe(struct platform_device *pdev)
+ {
+       struct device_node *np = pdev->dev.of_node;
+@@ -369,8 +455,6 @@ static int mscc_ocelot_probe(struct plat
+       for_each_available_child_of_node(ports, portnp) {
+               struct ocelot_port_private *priv;
+               struct ocelot_port *ocelot_port;
+-              struct device_node *phy_node;
+-              struct phy_device *phy;
+               struct resource *res;
+               struct phy *serdes;
+               void __iomem *regs;
+@@ -389,16 +473,7 @@ static int mscc_ocelot_probe(struct plat
+               if (IS_ERR(regs))
+                       continue;
+-              phy_node = of_parse_phandle(portnp, "phy-handle", 0);
+-              if (!phy_node)
+-                      continue;
+-
+-              phy = of_phy_find_device(phy_node);
+-              of_node_put(phy_node);
+-              if (!phy)
+-                      continue;
+-
+-              err = ocelot_probe_port(ocelot, port, regs, phy);
++              err = ocelot_probe_port(ocelot, port, regs);
+               if (err) {
+                       of_node_put(portnp);
+                       goto out_put_ports;
+@@ -412,9 +487,7 @@ static int mscc_ocelot_probe(struct plat
+               if (phy_mode < 0)
+                       phy_mode = PHY_INTERFACE_MODE_NA;
+-              priv->phy_mode = phy_mode;
+-
+-              switch (priv->phy_mode) {
++              switch (phy_mode) {
+               case PHY_INTERFACE_MODE_NA:
+                       continue;
+               case PHY_INTERFACE_MODE_SGMII:
+@@ -451,7 +524,41 @@ static int mscc_ocelot_probe(struct plat
+                       goto out_put_ports;
+               }
+-              priv->serdes = serdes;
++              if (serdes) {
++                      err = phy_set_mode_ext(serdes, PHY_MODE_ETHERNET,
++                                             phy_mode);
++                      if (err) {
++                              dev_err(ocelot->dev,
++                                      "Could not set mode of SerDes\n");
++                              of_node_put(portnp);
++                              goto out_put_ports;
++                      }
++              }
++
++              priv->phylink_config.dev = &priv->dev->dev;
++              priv->phylink_config.type = PHYLINK_NETDEV;
++
++              priv->phylink = phylink_create(&priv->phylink_config,
++                                             of_fwnode_handle(portnp),
++                                             phy_mode, &ocelot_phylink_ops);
++              if (IS_ERR(priv->phylink)) {
++                      dev_err(ocelot->dev,
++                              "Could not create a phylink instance (%ld)\n",
++                              PTR_ERR(priv->phylink));
++                      err = PTR_ERR(priv->phylink);
++                      priv->phylink = NULL;
++                      of_node_put(portnp);
++                      goto out_put_ports;
++              }
++
++              err = phylink_of_phy_connect(priv->phylink, portnp, 0);
++              if (err) {
++                      dev_err(ocelot->dev, "Could not connect to PHY: %d\n",
++                              err);
++                      phylink_destroy(priv->phylink);
++                      of_node_put(portnp);
++                      goto out_put_ports;
++              }
+       }
+       register_netdevice_notifier(&ocelot_netdevice_nb);
+@@ -468,12 +575,27 @@ out_put_ports:
+ static int mscc_ocelot_remove(struct platform_device *pdev)
+ {
+       struct ocelot *ocelot = platform_get_drvdata(pdev);
++      int port;
+       ocelot_deinit(ocelot);
+       unregister_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);
+       unregister_switchdev_notifier(&ocelot_switchdev_nb);
+       unregister_netdevice_notifier(&ocelot_netdevice_nb);
++      for (port = 0; port < ocelot->num_phys_ports; port++) {
++              struct ocelot_port_private *priv;
++
++              priv = container_of(ocelot->ports[port],
++                                  struct ocelot_port_private,
++                                  port);
++
++              if (priv->phylink) {
++                      rtnl_lock();
++                      phylink_destroy(priv->phylink);
++                      rtnl_unlock();
++              }
++      }
++
+       return 0;
+ }
+--- a/include/soc/mscc/ocelot.h
++++ b/include/soc/mscc/ocelot.h
+@@ -518,17 +518,12 @@ void ocelot_deinit(struct ocelot *ocelot
+ void ocelot_init_port(struct ocelot *ocelot, int port);
+ /* DSA callbacks */
+-void ocelot_port_enable(struct ocelot *ocelot, int port,
+-                      struct phy_device *phy);
+-void ocelot_port_disable(struct ocelot *ocelot, int port);
+ void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data);
+ void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data);
+ int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset);
+ int ocelot_get_ts_info(struct ocelot *ocelot, int port,
+                      struct ethtool_ts_info *info);
+ void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs);
+-void ocelot_adjust_link(struct ocelot *ocelot, int port,
+-                      struct phy_device *phydev);
+ void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
+                               bool vlan_aware);
+ void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state);
+@@ -597,4 +592,21 @@ int ocelot_rtag_parse_enable(struct ocel
+ int ocelot_dscp_set(struct ocelot *ocelot, int port,
+                   bool enable, const u8 dscp_ix,
+                   struct tsn_qos_switch_dscp_conf *c);
++void ocelot_phylink_validate(struct ocelot *ocelot, int port,
++                           unsigned long *supported,
++                           struct phylink_link_state *state);
++void ocelot_phylink_mac_pcs_get_state(struct ocelot *ocelot, int port,
++                                    struct phylink_link_state *state);
++void ocelot_phylink_mac_an_restart(struct ocelot *ocelot, int port);
++void ocelot_phylink_mac_config(struct ocelot *ocelot, int port,
++                             unsigned int link_an_mode,
++                             const struct phylink_link_state *state);
++void ocelot_phylink_mac_link_down(struct ocelot *ocelot, int port,
++                                unsigned int link_an_mode,
++                                phy_interface_t interface);
++void ocelot_phylink_mac_link_up(struct ocelot *ocelot, int port,
++                              unsigned int link_an_mode,
++                              phy_interface_t interface,
++                              struct phy_device *phy);
++
+ #endif
diff --git a/target/linux/layerscape/patches-5.4/701-net-0282-net-mscc-ocelot-introduce-more-focused-PCS-ops-for-P.patch b/target/linux/layerscape/patches-5.4/701-net-0282-net-mscc-ocelot-introduce-more-focused-PCS-ops-for-P.patch
new file mode 100644 (file)
index 0000000..d7ae119
--- /dev/null
@@ -0,0 +1,169 @@
+From 07f63e91f5e81f7f36c1e646f72c394c7f60c05c Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 22 Nov 2019 13:46:34 +0200
+Subject: [PATCH] net: mscc: ocelot: introduce more focused PCS ops for PHYLINK
+
+The reason for doing this is that the 2 mainline Ocelot switches so far,
+VSC7514 and VSC9959, have radically different SoC/SerDes integration. So
+although the PHYLINK callbacks are common, the implementations will
+actually lie in device-specific function pointers.
+
+Also, there was a duplicated and unused function pointer for pcs_init in
+struct ocelot, remove that.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/ethernet/mscc/ocelot.c       | 36 ++++++++------------------------
+ drivers/net/ethernet/mscc/ocelot_board.c | 35 ++++++++++++++++++++++++++++++-
+ include/soc/mscc/ocelot.h                | 12 ++++++++---
+ 3 files changed, 52 insertions(+), 31 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -410,43 +410,25 @@ void ocelot_phylink_validate(struct ocel
+                            unsigned long *supported,
+                            struct phylink_link_state *state)
+ {
+-      __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+-
+-      if (state->interface != PHY_INTERFACE_MODE_NA &&
+-          state->interface != PHY_INTERFACE_MODE_GMII &&
+-          state->interface != PHY_INTERFACE_MODE_SGMII &&
+-          state->interface != PHY_INTERFACE_MODE_QSGMII) {
+-              bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+-              return;
+-      }
+-
+-      /* No half-duplex. */
+-      phylink_set_port_modes(mask);
+-      phylink_set(mask, Autoneg);
+-      phylink_set(mask, Pause);
+-      phylink_set(mask, Asym_Pause);
+-      phylink_set(mask, 10baseT_Full);
+-      phylink_set(mask, 100baseT_Full);
+-      phylink_set(mask, 1000baseT_Full);
+-      phylink_set(mask, 2500baseT_Full);
+-
+-      bitmap_and(supported, supported, mask,
+-                 __ETHTOOL_LINK_MODE_MASK_NBITS);
+-      bitmap_and(state->advertising, state->advertising, mask,
+-                 __ETHTOOL_LINK_MODE_MASK_NBITS);
++      if (ocelot->ops->pcs_validate)
++              ocelot->ops->pcs_validate(ocelot, port, supported, state);
+ }
+ EXPORT_SYMBOL(ocelot_phylink_validate);
+ void ocelot_phylink_mac_pcs_get_state(struct ocelot *ocelot, int port,
+                                     struct phylink_link_state *state)
+ {
+-      state->link = 1;
++      if (ocelot->ops->pcs_link_state)
++              ocelot->ops->pcs_link_state(ocelot, port, state);
++      else
++              state->link = 1;
+ }
+ EXPORT_SYMBOL(ocelot_phylink_mac_pcs_get_state);
+ void ocelot_phylink_mac_an_restart(struct ocelot *ocelot, int port)
+ {
+-      /* Not supported */
++      if (ocelot->ops->pcs_an_restart)
++              ocelot->ops->pcs_an_restart(ocelot, port);
+ }
+ EXPORT_SYMBOL(ocelot_phylink_mac_an_restart);
+@@ -490,7 +472,7 @@ void ocelot_phylink_mac_config(struct oc
+       ocelot_port_writel(ocelot_port, mac_mode, DEV_MAC_MODE_CFG);
+       if (ocelot->ops->pcs_init)
+-              ocelot->ops->pcs_init(ocelot, port);
++              ocelot->ops->pcs_init(ocelot, port, link_an_mode, state);
+       /* Enable MAC module */
+       ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA |
+--- a/drivers/net/ethernet/mscc/ocelot_board.c
++++ b/drivers/net/ethernet/mscc/ocelot_board.c
+@@ -212,7 +212,9 @@ static const struct of_device_id mscc_oc
+ };
+ MODULE_DEVICE_TABLE(of, mscc_ocelot_match);
+-static void ocelot_port_pcs_init(struct ocelot *ocelot, int port)
++static void ocelot_port_pcs_init(struct ocelot *ocelot, int port,
++                               unsigned int link_an_mode,
++                               const struct phylink_link_state *state)
+ {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+@@ -235,6 +237,36 @@ static void ocelot_port_pcs_init(struct
+       ocelot_port_writel(ocelot_port, 0, PCS1G_LB_CFG);
+ }
++void ocelot_port_pcs_validate(struct ocelot *ocelot, int port,
++                            unsigned long *supported,
++                            struct phylink_link_state *state)
++{
++      __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
++
++      if (state->interface != PHY_INTERFACE_MODE_NA &&
++          state->interface != PHY_INTERFACE_MODE_GMII &&
++          state->interface != PHY_INTERFACE_MODE_SGMII &&
++          state->interface != PHY_INTERFACE_MODE_QSGMII) {
++              bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
++              return;
++      }
++
++      /* No half-duplex. */
++      phylink_set_port_modes(mask);
++      phylink_set(mask, Autoneg);
++      phylink_set(mask, Pause);
++      phylink_set(mask, Asym_Pause);
++      phylink_set(mask, 10baseT_Full);
++      phylink_set(mask, 100baseT_Full);
++      phylink_set(mask, 1000baseT_Full);
++      phylink_set(mask, 2500baseT_Full);
++
++      bitmap_and(supported, supported, mask,
++                 __ETHTOOL_LINK_MODE_MASK_NBITS);
++      bitmap_and(state->advertising, state->advertising, mask,
++                 __ETHTOOL_LINK_MODE_MASK_NBITS);
++}
++
+ static int ocelot_reset(struct ocelot *ocelot)
+ {
+       int retries = 100;
+@@ -260,6 +292,7 @@ static int ocelot_reset(struct ocelot *o
+ static const struct ocelot_ops ocelot_ops = {
+       .pcs_init               = ocelot_port_pcs_init,
++      .pcs_validate           = ocelot_port_pcs_validate,
+       .reset                  = ocelot_reset,
+ };
+--- a/include/soc/mscc/ocelot.h
++++ b/include/soc/mscc/ocelot.h
+@@ -412,7 +412,15 @@ enum {
+ struct ocelot;
+ struct ocelot_ops {
+-      void (*pcs_init)(struct ocelot *ocelot, int port);
++      void (*pcs_init)(struct ocelot *ocelot, int port,
++                       unsigned int link_an_mode,
++                       const struct phylink_link_state *state);
++      void (*pcs_an_restart)(struct ocelot *ocelot, int port);
++      void (*pcs_link_state)(struct ocelot *ocelot, int port,
++                             struct phylink_link_state *state);
++      void (*pcs_validate)(struct ocelot *ocelot, int port,
++                           unsigned long *supported,
++                           struct phylink_link_state *state);
+       int (*reset)(struct ocelot *ocelot);
+ };
+@@ -479,8 +487,6 @@ struct ocelot {
+       struct mutex                    ptp_lock;
+       /* Protects the PTP clock */
+       spinlock_t                      ptp_clock_lock;
+-
+-      void (*port_pcs_init)(struct ocelot_port *port);
+ };
+ #define ocelot_read_ix(ocelot, reg, gi, ri) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
diff --git a/target/linux/layerscape/patches-5.4/701-net-0283-net-dsa-felix-Add-PCS-operations-for-PHYLINK.patch b/target/linux/layerscape/patches-5.4/701-net-0283-net-dsa-felix-Add-PCS-operations-for-PHYLINK.patch
new file mode 100644 (file)
index 0000000..e2de403
--- /dev/null
@@ -0,0 +1,442 @@
+From 0e219a6aa07754d81a25c9e4408d81d194cd2000 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 22 Nov 2019 13:45:52 +0200
+Subject: [PATCH] net: dsa: felix: Add PCS operations for PHYLINK
+
+This removes the bootloader dependency for SGMII PCS pre-configuration,
+as well as adds support for monitoring the in-band SGMII AN between the
+PCS and the system-side link partner (PHY or other MAC).
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/dsa/ocelot/felix.c         |  23 ++-
+ drivers/net/dsa/ocelot/felix.h         |   7 +-
+ drivers/net/dsa/ocelot/felix_vsc9959.c | 292 ++++++++++++++++++++++++++++++++-
+ 3 files changed, 314 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -265,7 +265,7 @@ static int felix_get_ts_info(struct dsa_
+ static int felix_init_structs(struct felix *felix, int num_phys_ports)
+ {
+       struct ocelot *ocelot = &felix->ocelot;
+-      resource_size_t base;
++      resource_size_t switch_base;
+       int port, i, err;
+       ocelot->num_phys_ports = num_phys_ports;
+@@ -281,7 +281,8 @@ static int felix_init_structs(struct fel
+       ocelot->ops             = felix->info->ops;
+       ocelot->quirks          = felix->info->quirks;
+-      base = pci_resource_start(felix->pdev, felix->info->pci_bar);
++      switch_base = pci_resource_start(felix->pdev,
++                                       felix->info->switch_pci_bar);
+       for (i = 0; i < TARGET_MAX; i++) {
+               struct regmap *target;
+@@ -292,8 +293,8 @@ static int felix_init_structs(struct fel
+               res = &felix->info->target_io_res[i];
+               res->flags = IORESOURCE_MEM;
+-              res->start += base;
+-              res->end += base;
++              res->start += switch_base;
++              res->end += switch_base;
+               target = ocelot_regmap_init(ocelot, res);
+               if (IS_ERR(target)) {
+@@ -327,8 +328,8 @@ static int felix_init_structs(struct fel
+               res = &felix->info->port_io_res[port];
+               res->flags = IORESOURCE_MEM;
+-              res->start += base;
+-              res->end += base;
++              res->start += switch_base;
++              res->end += switch_base;
+               port_regs = devm_ioremap_resource(ocelot->dev, res);
+               if (IS_ERR(port_regs)) {
+@@ -342,6 +343,12 @@ static int felix_init_structs(struct fel
+               ocelot->ports[port] = ocelot_port;
+       }
++      if (felix->info->mdio_bus_alloc) {
++              err = felix->info->mdio_bus_alloc(ocelot);
++              if (err < 0)
++                      return err;
++      }
++
+       return 0;
+ }
+@@ -377,6 +384,10 @@ static int felix_setup(struct dsa_switch
+ static void felix_teardown(struct dsa_switch *ds)
+ {
+       struct ocelot *ocelot = ds->priv;
++      struct felix *felix = ocelot_to_felix(ocelot);
++
++      if (felix->imdio)
++              mdiobus_unregister(felix->imdio);
+       /* stop workqueue thread */
+       ocelot_deinit(ocelot);
+--- a/drivers/net/dsa/ocelot/felix.h
++++ b/drivers/net/dsa/ocelot/felix.h
+@@ -10,6 +10,7 @@
+ struct felix_info {
+       struct resource                 *target_io_res;
+       struct resource                 *port_io_res;
++      struct resource                 *imdio_res;
+       const struct reg_field          *regfields;
+       const u32 *const                *map;
+       const struct ocelot_ops         *ops;
+@@ -17,8 +18,10 @@ struct felix_info {
+       const struct ocelot_stat_layout *stats_layout;
+       unsigned int                    num_stats;
+       int                             num_ports;
+-      int                             pci_bar;
++      int                             switch_pci_bar;
++      int                             imdio_pci_bar;
+       unsigned long                   quirks;
++      int (*mdio_bus_alloc)(struct ocelot *ocelot);
+ };
+ extern struct felix_info              felix_info_vsc9959;
+@@ -33,6 +36,8 @@ struct felix {
+       struct pci_dev                  *pdev;
+       struct felix_info               *info;
+       struct ocelot                   ocelot;
++      struct mii_bus                  *imdio;
++      struct phy_device               **pcs;
+ };
+ #endif
+--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
+@@ -2,6 +2,7 @@
+ /* Copyright 2017 Microsemi Corporation
+  * Copyright 2018-2019 NXP Semiconductors
+  */
++#include <linux/fsl/enetc_mdio.h>
+ #include <soc/mscc/ocelot_sys.h>
+ #include <soc/mscc/ocelot.h>
+ #include <linux/iopoll.h>
+@@ -390,6 +391,15 @@ static struct resource vsc9959_port_io_r
+       },
+ };
++/* Port MAC 0 Internal MDIO bus through which the SerDes acting as an
++ * SGMII/QSGMII MAC PCS can be found.
++ */
++static struct resource vsc9959_imdio_res = {
++      .start          = 0x8030,
++      .end            = 0x8040,
++      .name           = "imdio",
++};
++
+ static const struct reg_field vsc9959_regfields[] = {
+       [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6),
+       [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 5),
+@@ -569,13 +579,291 @@ static int vsc9959_reset(struct ocelot *
+       return 0;
+ }
++void vsc9959_pcs_validate(struct ocelot *ocelot, int port,
++                        unsigned long *supported,
++                        struct phylink_link_state *state)
++{
++      __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
++
++      if (state->interface != PHY_INTERFACE_MODE_NA &&
++          state->interface != PHY_INTERFACE_MODE_GMII &&
++          state->interface != PHY_INTERFACE_MODE_SGMII &&
++          state->interface != PHY_INTERFACE_MODE_QSGMII &&
++          state->interface != PHY_INTERFACE_MODE_USXGMII) {
++              bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
++              return;
++      }
++
++      /* No half-duplex. */
++      phylink_set_port_modes(mask);
++      phylink_set(mask, Autoneg);
++      phylink_set(mask, Pause);
++      phylink_set(mask, Asym_Pause);
++      phylink_set(mask, 10baseT_Full);
++      phylink_set(mask, 100baseT_Full);
++      phylink_set(mask, 1000baseT_Full);
++      phylink_set(mask, 1000baseX_Full);
++      phylink_set(mask, 2500baseT_Full);
++      phylink_set(mask, 2500baseX_Full);
++      phylink_set(mask, 1000baseKX_Full);
++
++      bitmap_and(supported, supported, mask,
++                 __ETHTOOL_LINK_MODE_MASK_NBITS);
++      bitmap_and(state->advertising, state->advertising, mask,
++                 __ETHTOOL_LINK_MODE_MASK_NBITS);
++}
++
++static void vsc9959_pcs_an_restart(struct ocelot *ocelot, int port)
++{
++      struct felix *felix = ocelot_to_felix(ocelot);
++      struct phy_device *pcs = felix->pcs[port];
++
++      if (!pcs)
++              return;
++
++      phy_set_bits(pcs, MII_BMCR, BMCR_ANRESTART);
++}
++
++static void vsc9959_pcs_init_sgmii(struct phy_device *pcs,
++                                 unsigned int link_an_mode,
++                                 const struct phylink_link_state *state)
++{
++      /* SGMII spec requires tx_config_Reg[15:0] to be exactly 0x4001
++       * for the MAC PCS in order to acknowledge the AN.
++       */
++      phy_write(pcs, MII_ADVERTISE, ADVERTISE_SGMII | ADVERTISE_LPACK);
++
++      /* Set to SGMII mode, use AN */
++      phy_write(pcs, ENETC_PCS_IF_MODE, ENETC_PCS_IF_MODE_SGMII_AN);
++
++      /* Adjust link timer for SGMII */
++      phy_write(pcs, ENETC_PCS_LINK_TIMER1, ENETC_PCS_LINK_TIMER1_VAL);
++      phy_write(pcs, ENETC_PCS_LINK_TIMER2, ENETC_PCS_LINK_TIMER2_VAL);
++
++      phy_write(pcs, MII_BMCR, BMCR_SPEED1000 |
++                               BMCR_FULLDPLX |
++                               BMCR_ANENABLE);
++}
++
++#define ADVERTISE_USXGMII_FDX         BIT(12)
++
++static void vsc9959_pcs_init_sxgmii(struct phy_device *pcs,
++                                  unsigned int link_an_mode,
++                                  const struct phylink_link_state *state)
++{
++      /* Configure device ability for the USXGMII Replicator */
++      phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_ADVERTISE,
++                    ADVERTISE_SGMII |
++                    ADVERTISE_LPACK |
++                    ADVERTISE_USXGMII_FDX);
++}
++
++static void vsc9959_pcs_init(struct ocelot *ocelot, int port,
++                           unsigned int link_an_mode,
++                           const struct phylink_link_state *state)
++{
++      struct felix *felix = ocelot_to_felix(ocelot);
++      struct phy_device *pcs = felix->pcs[port];
++
++      if (!pcs)
++              return;
++
++      if (link_an_mode == MLO_AN_FIXED) {
++              phydev_err(pcs, "Fixed modes are not yet supported.\n");
++              return;
++      }
++
++      pcs->interface = state->interface;
++      if (pcs->interface == PHY_INTERFACE_MODE_USXGMII)
++              pcs->is_c45 = true;
++      else
++              pcs->is_c45 = false;
++
++      /* The PCS does not implement the BMSR register fully, so capability
++       * detection via genphy_read_abilities does not work. Since we can get
++       * the PHY config word from the LPA register though, there is still
++       * value in using the generic phy_resolve_aneg_linkmode function. So
++       * populate the supported and advertising link modes manually here.
++       */
++      linkmode_set_bit_array(phy_basic_ports_array,
++                             ARRAY_SIZE(phy_basic_ports_array),
++                             pcs->supported);
++      linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, pcs->supported);
++      linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, pcs->supported);
++      linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pcs->supported);
++      linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, pcs->supported);
++      phy_advertise_supported(pcs);
++
++      switch (pcs->interface) {
++      case PHY_INTERFACE_MODE_SGMII:
++      case PHY_INTERFACE_MODE_QSGMII:
++              vsc9959_pcs_init_sgmii(pcs, link_an_mode, state);
++              break;
++      case PHY_INTERFACE_MODE_USXGMII:
++              vsc9959_pcs_init_sxgmii(pcs, link_an_mode, state);
++              break;
++      default:
++              dev_err(ocelot->dev, "Unsupported link mode %s\n",
++                      phy_modes(pcs->interface));
++      }
++}
++
++static void vsc9959_pcs_link_state(struct ocelot *ocelot, int port,
++                                 struct phylink_link_state *state)
++{
++      struct felix *felix = ocelot_to_felix(ocelot);
++      struct phy_device *pcs = felix->pcs[port];
++      int err;
++
++      if (!pcs)
++              return;
++
++      /* Reading PCS status not yet supported for USXGMII */
++      if (pcs->is_c45) {
++              state->link = 1;
++              return;
++      }
++
++      pcs->speed = SPEED_UNKNOWN;
++      pcs->duplex = DUPLEX_UNKNOWN;
++      pcs->pause = 0;
++      pcs->asym_pause = 0;
++
++      err = genphy_update_link(pcs);
++      if (err < 0)
++              return;
++
++      if (pcs->autoneg_complete) {
++              u16 lpa = phy_read(pcs, MII_LPA);
++
++              switch (state->interface) {
++              case PHY_INTERFACE_MODE_SGMII:
++              case PHY_INTERFACE_MODE_QSGMII:
++                      mii_lpa_to_linkmode_lpa_sgmii(pcs->lp_advertising, lpa);
++                      break;
++              default:
++                      return;
++              }
++
++              phy_resolve_aneg_linkmode(pcs);
++      }
++
++      state->an_complete = pcs->autoneg_complete;
++      state->an_enabled = pcs->autoneg;
++      state->link = pcs->link;
++      state->duplex = pcs->duplex;
++      state->speed = pcs->speed;
++      /* SGMII AN does not negotiate flow control, but that's ok,
++       * since phylink already knows that, and does:
++       *      link_state.pause |= pl->phy_state.pause;
++       */
++      state->pause = pcs->pause;
++
++      dev_dbg(ocelot->dev,
++              "%s: mode=%s/%s/%s adv=%*pb lpa=%*pb link=%u an_enabled=%u an_complete=%u\n",
++              __func__,
++              phy_modes(state->interface),
++              phy_speed_to_str(state->speed),
++              phy_duplex_to_str(state->duplex),
++              __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising,
++              __ETHTOOL_LINK_MODE_MASK_NBITS, state->lp_advertising,
++              state->link, state->an_enabled, state->an_complete);
++}
++
+ static const struct ocelot_ops vsc9959_ops = {
+       .reset                  = vsc9959_reset,
++      .pcs_init               = vsc9959_pcs_init,
++      .pcs_an_restart         = vsc9959_pcs_an_restart,
++      .pcs_link_state         = vsc9959_pcs_link_state,
++      .pcs_validate           = vsc9959_pcs_validate,
+ };
++static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
++{
++      struct felix *felix = ocelot_to_felix(ocelot);
++      struct enetc_mdio_priv *mdio_priv;
++      struct device *dev = ocelot->dev;
++      resource_size_t imdio_base;
++      void __iomem *imdio_regs;
++      struct resource *res;
++      struct enetc_hw *hw;
++      struct mii_bus *bus;
++      int port;
++      int rc;
++
++      felix->pcs = devm_kcalloc(dev, felix->info->num_ports,
++                                sizeof(struct phy_device),
++                                GFP_KERNEL);
++      if (!felix->pcs) {
++              dev_err(dev, "failed to allocate array for PCS PHYs\n");
++              return -ENOMEM;
++      }
++
++      imdio_base = pci_resource_start(felix->pdev,
++                                      felix->info->imdio_pci_bar);
++
++      res = felix->info->imdio_res;
++      res->flags = IORESOURCE_MEM;
++      res->start += imdio_base;
++      res->end += imdio_base;
++
++      imdio_regs = devm_ioremap_resource(dev, res);
++      if (IS_ERR(imdio_regs)) {
++              dev_err(dev, "failed to map internal MDIO registers\n");
++              return PTR_ERR(imdio_regs);
++      }
++
++      hw = enetc_hw_alloc(dev, imdio_regs);
++      if (IS_ERR(hw)) {
++              dev_err(dev, "failed to allocate ENETC HW structure\n");
++              return PTR_ERR(hw);
++      }
++
++      bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
++      if (!bus)
++              return -ENOMEM;
++
++      bus->name = "VSC9959 internal MDIO bus";
++      bus->read = enetc_mdio_read;
++      bus->write = enetc_mdio_write;
++      bus->parent = dev;
++      mdio_priv = bus->priv;
++      mdio_priv->hw = hw;
++      /* This gets added to imdio_regs, which already maps addresses
++       * starting with the proper offset.
++       */
++      mdio_priv->mdio_base = 0;
++      snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
++
++      /* Needed in order to initialize the bus mutex lock */
++      rc = mdiobus_register(bus);
++      if (rc < 0) {
++              dev_err(dev, "failed to register MDIO bus\n");
++              return rc;
++      }
++
++      felix->imdio = bus;
++
++      for (port = 0; port < felix->info->num_ports; port++) {
++              struct phy_device *pcs;
++              bool is_c45 = false;
++
++              pcs = get_phy_device(felix->imdio, port, is_c45);
++              if (IS_ERR(pcs))
++                      continue;
++
++              felix->pcs[port] = pcs;
++
++              dev_info(dev, "Found PCS at internal MDIO address %d\n", port);
++      }
++
++      return 0;
++}
++
+ struct felix_info felix_info_vsc9959 = {
+       .target_io_res          = vsc9959_target_io_res,
+       .port_io_res            = vsc9959_port_io_res,
++      .imdio_res              = &vsc9959_imdio_res,
+       .regfields              = vsc9959_regfields,
+       .map                    = vsc9959_regmap,
+       .ops                    = &vsc9959_ops,
+@@ -583,6 +871,8 @@ struct felix_info felix_info_vsc9959 = {
+       .num_stats              = ARRAY_SIZE(vsc9959_stats_layout),
+       .shared_queue_sz        = 128 * 1024,
+       .num_ports              = 6,
+-      .pci_bar                = 4,
++      .switch_pci_bar         = 4,
++      .imdio_pci_bar          = 0,
+       .quirks                 = OCELOT_PCS_PERFORMS_RATE_ADAPTATION,
++      .mdio_bus_alloc         = vsc9959_mdio_bus_alloc,
+ };
diff --git a/target/linux/layerscape/patches-5.4/701-net-0284-net-fsl_ppfe-dts-binding-for-ppfe.patch b/target/linux/layerscape/patches-5.4/701-net-0284-net-fsl_ppfe-dts-binding-for-ppfe.patch
new file mode 100644 (file)
index 0000000..6659f9b
--- /dev/null
@@ -0,0 +1,188 @@
+From 08861b67c94a28e3a1bbcfb04a141ab0eafa5dac Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Sat, 16 Sep 2017 07:05:49 +0530
+Subject: [PATCH] net: fsl_ppfe: dts binding for ppfe
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+Signed-off-by: Anjaneyulu Jagarlmudi <anji.jagarlmudi@nxp.com>
+---
+ .../devicetree/bindings/net/fsl_ppfe/pfe.txt       | 173 +++++++++++++++++++++
+ 1 file changed, 173 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/net/fsl_ppfe/pfe.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/net/fsl_ppfe/pfe.txt
+@@ -0,0 +1,173 @@
++=============================================================================
++NXP Programmable Packet Forwarding Engine Device Bindings
++
++CONTENTS
++  - PFE Node
++  - Ethernet Node
++
++=============================================================================
++PFE Node
++
++DESCRIPTION
++
++PFE Node has all the properties associated with Packet Forwarding Engine block.
++
++PROPERTIES
++
++- compatible
++              Usage: required
++              Value type: <stringlist>
++              Definition: Must include "fsl,pfe"
++
++- reg
++              Usage: required
++              Value type: <prop-encoded-array>
++              Definition: A standard property.
++              Specifies the offset of the following registers:
++              - PFE configuration registers
++              - DDR memory used by PFE
++
++- fsl,pfe-num-interfaces
++              Usage: required
++              Value type: <u32>
++              Definition: Must be present. Value can be either one or two.
++
++- interrupts
++              Usage: required
++              Value type: <prop-encoded-array>
++              Definition: Three interrupts are specified in this property.
++              - HIF interrupt
++              - HIF NO COPY interrupt
++              - Wake On LAN interrupt
++
++- interrupt-names
++              Usage: required
++              Value type: <stringlist>
++              Definition: Following strings are defined for the 3 interrupts.
++              "pfe_hif" - HIF interrupt
++              "pfe_hif_nocpy" - HIF NO COPY interrupt
++              "pfe_wol" - Wake On LAN interrupt
++
++- memory-region
++              Usage: required
++              Value type: <phandle>
++              Definition: phandle to a node describing reserved memory used by pfe.
++              Refer:- Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
++
++- fsl,pfe-scfg
++              Usage: required
++              Value type: <phandle>
++              Definition: phandle for scfg.
++
++- fsl,rcpm-wakeup
++              Usage: required
++              Value type: <phandle>
++              Definition: phandle for rcpm.
++
++- clocks
++              Usage: required
++              Value type: <phandle>
++              Definition: phandle for clockgen.
++
++- clock-names
++              Usage: required
++              Value type: <string>
++              Definition: phandle for clock name.
++
++EXAMPLE
++
++pfe: pfe@04000000 {
++      compatible = "fsl,pfe";
++      reg =   <0x0 0x04000000 0x0 0xc00000>,  /* AXI 16M */
++              <0x0 0x83400000 0x0 0xc00000>;  /* PFE DDR 12M */
++      reg-names = "pfe", "pfe-ddr";
++      fsl,pfe-num-interfaces = <0x2>;
++      interrupts = <0 172 0x4>,    /* HIF interrupt */
++                   <0 173 0x4>,    /*HIF_NOCPY interrupt */
++                   <0 174 0x4>;    /* WoL interrupt */
++      interrupt-names = "pfe_hif", "pfe_hif_nocpy", "pfe_wol";
++      memory-region = <&pfe_reserved>;
++      fsl,pfe-scfg = <&scfg 0>;
++      fsl,rcpm-wakeup = <&rcpm 0xf0000020>;
++      clocks = <&clockgen 4 0>;
++      clock-names = "pfe";
++
++      status = "okay";
++      pfe_mac0: ethernet@0 {
++      };
++
++      pfe_mac1: ethernet@1 {
++      };
++};
++
++=============================================================================
++Ethernet Node
++
++DESCRIPTION
++
++Ethernet Node has all the properties associated with PFE used by platforms to
++connect to PHY:
++
++PROPERTIES
++
++- compatible
++              Usage: required
++              Value type: <stringlist>
++              Definition: Must include "fsl,pfe-gemac-port"
++
++- reg
++              Usage: required
++              Value type: <prop-encoded-array>
++              Definition: A standard property.
++              Specifies the gemacid of the interface.
++
++- fsl,gemac-bus-id
++              Usage: required
++              Value type: <u32>
++              Definition: Must be present. Value should be the id of the bus
++              connected to gemac.
++
++- fsl,gemac-phy-id
++              Usage: required
++              Value type: <u32>
++              Definition: Must be present. Value should be the id of the phy
++              connected to gemac.
++
++- fsl,mdio-mux-val
++              Usage: required
++              Value type: <u32>
++              Definition: Must be present. Value can be either 0 or 2 or 3.
++              This value is used to configure the mux to enable mdio.
++
++- phy-mode
++              Usage: required
++              Value type: <string>
++              Definition: Must include "sgmii"
++
++- fsl,pfe-phy-if-flags
++              Usage: required
++              Value type: <u32>
++              Definition: Must be present. Value should be 0 by default.
++              If there is not phy connected, this need to be 1.
++
++- mdio
++              optional subnode that specifies the mdio bus. This has reg
++              property which is used to enable/disable the mdio bus.
++
++EXAMPLE
++
++ethernet@0 {
++      compatible = "fsl,pfe-gemac-port";
++      #address-cells = <1>;
++      #size-cells = <0>;
++      reg = <0x0>;    /* GEM_ID */
++      fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
++      fsl,gemac-phy-id = <0x2>;       /* PHY_ID */
++      fsl,mdio-mux-val = <0x0>;
++      phy-mode = "sgmii";
++      fsl,pfe-phy-if-flags = <0x0>;
++
++      mdio@0 {
++              reg = <0x1>; /* enabled/disabled */
++      };
++};
diff --git a/target/linux/layerscape/patches-5.4/701-net-0285-staging-fsl_ppfe-eth-header-files-for-pfe-driver.patch b/target/linux/layerscape/patches-5.4/701-net-0285-staging-fsl_ppfe-eth-header-files-for-pfe-driver.patch
new file mode 100644 (file)
index 0000000..b513786
--- /dev/null
@@ -0,0 +1,2622 @@
+From d9bd3a5f795f45fd6847f080231e1e760004dca9 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Sat, 16 Sep 2017 14:21:37 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: header files for pfe driver
+
+This patch has all pfe header files.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+Signed-off-by: Anjaneyulu Jagarlmudi <anji.jagarlmudi@nxp.com>
+---
+ drivers/staging/fsl_ppfe/include/pfe/cbus.h        |  78 +++++
+ drivers/staging/fsl_ppfe/include/pfe/cbus/bmu.h    |  55 +++
+ .../staging/fsl_ppfe/include/pfe/cbus/class_csr.h  | 289 ++++++++++++++++
+ .../staging/fsl_ppfe/include/pfe/cbus/emac_mtip.h  | 242 ++++++++++++++
+ drivers/staging/fsl_ppfe/include/pfe/cbus/gpi.h    |  86 +++++
+ drivers/staging/fsl_ppfe/include/pfe/cbus/hif.h    | 100 ++++++
+ .../staging/fsl_ppfe/include/pfe/cbus/hif_nocpy.h  |  50 +++
+ .../staging/fsl_ppfe/include/pfe/cbus/tmu_csr.h    | 168 ++++++++++
+ .../staging/fsl_ppfe/include/pfe/cbus/util_csr.h   |  61 ++++
+ drivers/staging/fsl_ppfe/include/pfe/pfe.h         | 372 +++++++++++++++++++++
+ drivers/staging/fsl_ppfe/pfe_ctrl.h                | 112 +++++++
+ drivers/staging/fsl_ppfe/pfe_debugfs.h             |  25 ++
+ drivers/staging/fsl_ppfe/pfe_eth.h                 | 184 ++++++++++
+ drivers/staging/fsl_ppfe/pfe_firmware.h            |  32 ++
+ drivers/staging/fsl_ppfe/pfe_hif.h                 | 211 ++++++++++++
+ drivers/staging/fsl_ppfe/pfe_hif_lib.h             | 239 +++++++++++++
+ drivers/staging/fsl_ppfe/pfe_hw.h                  |  27 ++
+ drivers/staging/fsl_ppfe/pfe_mod.h                 | 112 +++++++
+ drivers/staging/fsl_ppfe/pfe_perfmon.h             |  38 +++
+ drivers/staging/fsl_ppfe/pfe_sysfs.h               |  29 ++
+ 20 files changed, 2510 insertions(+)
+ create mode 100644 drivers/staging/fsl_ppfe/include/pfe/cbus.h
+ create mode 100644 drivers/staging/fsl_ppfe/include/pfe/cbus/bmu.h
+ create mode 100644 drivers/staging/fsl_ppfe/include/pfe/cbus/class_csr.h
+ create mode 100644 drivers/staging/fsl_ppfe/include/pfe/cbus/emac_mtip.h
+ create mode 100644 drivers/staging/fsl_ppfe/include/pfe/cbus/gpi.h
+ create mode 100644 drivers/staging/fsl_ppfe/include/pfe/cbus/hif.h
+ create mode 100644 drivers/staging/fsl_ppfe/include/pfe/cbus/hif_nocpy.h
+ create mode 100644 drivers/staging/fsl_ppfe/include/pfe/cbus/tmu_csr.h
+ create mode 100644 drivers/staging/fsl_ppfe/include/pfe/cbus/util_csr.h
+ create mode 100644 drivers/staging/fsl_ppfe/include/pfe/pfe.h
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_ctrl.h
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_debugfs.h
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_eth.h
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_firmware.h
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_hif.h
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_hif_lib.h
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_hw.h
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_mod.h
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_perfmon.h
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_sysfs.h
+
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/include/pfe/cbus.h
+@@ -0,0 +1,78 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _CBUS_H_
++#define _CBUS_H_
++
++#define EMAC1_BASE_ADDR       (CBUS_BASE_ADDR + 0x200000)
++#define EGPI1_BASE_ADDR       (CBUS_BASE_ADDR + 0x210000)
++#define EMAC2_BASE_ADDR       (CBUS_BASE_ADDR + 0x220000)
++#define EGPI2_BASE_ADDR       (CBUS_BASE_ADDR + 0x230000)
++#define BMU1_BASE_ADDR        (CBUS_BASE_ADDR + 0x240000)
++#define BMU2_BASE_ADDR        (CBUS_BASE_ADDR + 0x250000)
++#define ARB_BASE_ADDR (CBUS_BASE_ADDR + 0x260000)
++#define DDR_CONFIG_BASE_ADDR  (CBUS_BASE_ADDR + 0x270000)
++#define HIF_BASE_ADDR (CBUS_BASE_ADDR + 0x280000)
++#define HGPI_BASE_ADDR        (CBUS_BASE_ADDR + 0x290000)
++#define LMEM_BASE_ADDR        (CBUS_BASE_ADDR + 0x300000)
++#define LMEM_SIZE     0x10000
++#define LMEM_END      (LMEM_BASE_ADDR + LMEM_SIZE)
++#define TMU_CSR_BASE_ADDR     (CBUS_BASE_ADDR + 0x310000)
++#define CLASS_CSR_BASE_ADDR   (CBUS_BASE_ADDR + 0x320000)
++#define HIF_NOCPY_BASE_ADDR   (CBUS_BASE_ADDR + 0x350000)
++#define UTIL_CSR_BASE_ADDR    (CBUS_BASE_ADDR + 0x360000)
++#define CBUS_GPT_BASE_ADDR    (CBUS_BASE_ADDR + 0x370000)
++
++/*
++ * defgroup XXX_MEM_ACCESS_ADDR PE memory access through CSR
++ * XXX_MEM_ACCESS_ADDR register bit definitions.
++ */
++#define PE_MEM_ACCESS_WRITE   BIT(31) /* Internal Memory Write. */
++#define PE_MEM_ACCESS_IMEM    BIT(15)
++#define PE_MEM_ACCESS_DMEM    BIT(16)
++
++/* Byte Enables of the Internal memory access. These are interpred in BE */
++#define PE_MEM_ACCESS_BYTE_ENABLE(offset, size)       \
++      ({ typeof(size) size_ = (size);         \
++      (((BIT(size_) - 1) << (4 - (offset) - (size_))) & 0xf) << 24; })
++
++#include "cbus/emac_mtip.h"
++#include "cbus/gpi.h"
++#include "cbus/bmu.h"
++#include "cbus/hif.h"
++#include "cbus/tmu_csr.h"
++#include "cbus/class_csr.h"
++#include "cbus/hif_nocpy.h"
++#include "cbus/util_csr.h"
++
++/* PFE cores states */
++#define CORE_DISABLE  0x00000000
++#define CORE_ENABLE   0x00000001
++#define CORE_SW_RESET 0x00000002
++
++/* LMEM defines */
++#define LMEM_HDR_SIZE 0x0010
++#define LMEM_BUF_SIZE_LN2     0x7
++#define LMEM_BUF_SIZE BIT(LMEM_BUF_SIZE_LN2)
++
++/* DDR defines */
++#define DDR_HDR_SIZE  0x0100
++#define DDR_BUF_SIZE_LN2      0xb
++#define DDR_BUF_SIZE  BIT(DDR_BUF_SIZE_LN2)
++
++#endif /* _CBUS_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/include/pfe/cbus/bmu.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _BMU_H_
++#define _BMU_H_
++
++#define BMU_VERSION   0x000
++#define BMU_CTRL      0x004
++#define BMU_UCAST_CONFIG      0x008
++#define BMU_UCAST_BASE_ADDR   0x00c
++#define BMU_BUF_SIZE  0x010
++#define BMU_BUF_CNT   0x014
++#define BMU_THRES     0x018
++#define BMU_INT_SRC   0x020
++#define BMU_INT_ENABLE        0x024
++#define BMU_ALLOC_CTRL        0x030
++#define BMU_FREE_CTRL 0x034
++#define BMU_FREE_ERR_ADDR     0x038
++#define BMU_CURR_BUF_CNT      0x03c
++#define BMU_MCAST_CNT 0x040
++#define BMU_MCAST_ALLOC_CTRL  0x044
++#define BMU_REM_BUF_CNT       0x048
++#define BMU_LOW_WATERMARK     0x050
++#define BMU_HIGH_WATERMARK    0x054
++#define BMU_INT_MEM_ACCESS    0x100
++
++struct BMU_CFG {
++      unsigned long baseaddr;
++      u32 count;
++      u32 size;
++      u32 low_watermark;
++      u32 high_watermark;
++};
++
++#define BMU1_BUF_SIZE LMEM_BUF_SIZE_LN2
++#define BMU2_BUF_SIZE DDR_BUF_SIZE_LN2
++
++#define BMU2_MCAST_ALLOC_CTRL (BMU2_BASE_ADDR + BMU_MCAST_ALLOC_CTRL)
++
++#endif /* _BMU_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/include/pfe/cbus/class_csr.h
+@@ -0,0 +1,289 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _CLASS_CSR_H_
++#define _CLASS_CSR_H_
++
++/* @file class_csr.h.
++ * class_csr - block containing all the classifier control and status register.
++ * Mapped on CBUS and accessible from all PE's and ARM.
++ */
++#define CLASS_VERSION (CLASS_CSR_BASE_ADDR + 0x000)
++#define CLASS_TX_CTRL (CLASS_CSR_BASE_ADDR + 0x004)
++#define CLASS_INQ_PKTPTR      (CLASS_CSR_BASE_ADDR + 0x010)
++
++/* (ddr_hdr_size[24:16], lmem_hdr_size[5:0]) */
++#define CLASS_HDR_SIZE        (CLASS_CSR_BASE_ADDR + 0x014)
++
++/* LMEM header size for the Classifier block.\ Data in the LMEM
++ * is written from this offset.
++ */
++#define CLASS_HDR_SIZE_LMEM(off)      ((off) & 0x3f)
++
++/* DDR header size for the Classifier block.\ Data in the DDR
++ * is written from this offset.
++ */
++#define CLASS_HDR_SIZE_DDR(off)       (((off) & 0x1ff) << 16)
++
++#define CLASS_PE0_QB_DM_ADDR0 (CLASS_CSR_BASE_ADDR + 0x020)
++
++/* DMEM address of first [15:0] and second [31:16] buffers on QB side. */
++#define CLASS_PE0_QB_DM_ADDR1 (CLASS_CSR_BASE_ADDR + 0x024)
++
++/* DMEM address of third [15:0] and fourth [31:16] buffers on QB side. */
++#define CLASS_PE0_RO_DM_ADDR0 (CLASS_CSR_BASE_ADDR + 0x060)
++
++/* DMEM address of first [15:0] and second [31:16] buffers on RO side. */
++#define CLASS_PE0_RO_DM_ADDR1 (CLASS_CSR_BASE_ADDR + 0x064)
++
++/* DMEM address of third [15:0] and fourth [31:16] buffers on RO side. */
++
++/* @name Class PE memory access. Allows external PE's and HOST to
++ * read/write PMEM/DMEM memory ranges for each classifier PE.
++ */
++/* {sr_pe_mem_cmd[31], csr_pe_mem_wren[27:24], csr_pe_mem_addr[23:0]},
++ * See \ref XXX_MEM_ACCESS_ADDR for details.
++ */
++#define CLASS_MEM_ACCESS_ADDR (CLASS_CSR_BASE_ADDR + 0x100)
++
++/* Internal Memory Access Write Data [31:0] */
++#define CLASS_MEM_ACCESS_WDATA        (CLASS_CSR_BASE_ADDR + 0x104)
++
++/* Internal Memory Access Read Data [31:0] */
++#define CLASS_MEM_ACCESS_RDATA        (CLASS_CSR_BASE_ADDR + 0x108)
++#define CLASS_TM_INQ_ADDR     (CLASS_CSR_BASE_ADDR + 0x114)
++#define CLASS_PE_STATUS       (CLASS_CSR_BASE_ADDR + 0x118)
++
++#define CLASS_PHY1_RX_PKTS    (CLASS_CSR_BASE_ADDR + 0x11c)
++#define CLASS_PHY1_TX_PKTS    (CLASS_CSR_BASE_ADDR + 0x120)
++#define CLASS_PHY1_LP_FAIL_PKTS       (CLASS_CSR_BASE_ADDR + 0x124)
++#define CLASS_PHY1_INTF_FAIL_PKTS     (CLASS_CSR_BASE_ADDR + 0x128)
++#define CLASS_PHY1_INTF_MATCH_PKTS    (CLASS_CSR_BASE_ADDR + 0x12c)
++#define CLASS_PHY1_L3_FAIL_PKTS       (CLASS_CSR_BASE_ADDR + 0x130)
++#define CLASS_PHY1_V4_PKTS    (CLASS_CSR_BASE_ADDR + 0x134)
++#define CLASS_PHY1_V6_PKTS    (CLASS_CSR_BASE_ADDR + 0x138)
++#define CLASS_PHY1_CHKSUM_ERR_PKTS    (CLASS_CSR_BASE_ADDR + 0x13c)
++#define CLASS_PHY1_TTL_ERR_PKTS       (CLASS_CSR_BASE_ADDR + 0x140)
++#define CLASS_PHY2_RX_PKTS    (CLASS_CSR_BASE_ADDR + 0x144)
++#define CLASS_PHY2_TX_PKTS    (CLASS_CSR_BASE_ADDR + 0x148)
++#define CLASS_PHY2_LP_FAIL_PKTS       (CLASS_CSR_BASE_ADDR + 0x14c)
++#define CLASS_PHY2_INTF_FAIL_PKTS     (CLASS_CSR_BASE_ADDR + 0x150)
++#define CLASS_PHY2_INTF_MATCH_PKTS    (CLASS_CSR_BASE_ADDR + 0x154)
++#define CLASS_PHY2_L3_FAIL_PKTS       (CLASS_CSR_BASE_ADDR + 0x158)
++#define CLASS_PHY2_V4_PKTS    (CLASS_CSR_BASE_ADDR + 0x15c)
++#define CLASS_PHY2_V6_PKTS    (CLASS_CSR_BASE_ADDR + 0x160)
++#define CLASS_PHY2_CHKSUM_ERR_PKTS    (CLASS_CSR_BASE_ADDR + 0x164)
++#define CLASS_PHY2_TTL_ERR_PKTS       (CLASS_CSR_BASE_ADDR + 0x168)
++#define CLASS_PHY3_RX_PKTS    (CLASS_CSR_BASE_ADDR + 0x16c)
++#define CLASS_PHY3_TX_PKTS    (CLASS_CSR_BASE_ADDR + 0x170)
++#define CLASS_PHY3_LP_FAIL_PKTS       (CLASS_CSR_BASE_ADDR + 0x174)
++#define CLASS_PHY3_INTF_FAIL_PKTS     (CLASS_CSR_BASE_ADDR + 0x178)
++#define CLASS_PHY3_INTF_MATCH_PKTS    (CLASS_CSR_BASE_ADDR + 0x17c)
++#define CLASS_PHY3_L3_FAIL_PKTS       (CLASS_CSR_BASE_ADDR + 0x180)
++#define CLASS_PHY3_V4_PKTS    (CLASS_CSR_BASE_ADDR + 0x184)
++#define CLASS_PHY3_V6_PKTS    (CLASS_CSR_BASE_ADDR + 0x188)
++#define CLASS_PHY3_CHKSUM_ERR_PKTS    (CLASS_CSR_BASE_ADDR + 0x18c)
++#define CLASS_PHY3_TTL_ERR_PKTS       (CLASS_CSR_BASE_ADDR + 0x190)
++#define CLASS_PHY1_ICMP_PKTS  (CLASS_CSR_BASE_ADDR + 0x194)
++#define CLASS_PHY1_IGMP_PKTS  (CLASS_CSR_BASE_ADDR + 0x198)
++#define CLASS_PHY1_TCP_PKTS   (CLASS_CSR_BASE_ADDR + 0x19c)
++#define CLASS_PHY1_UDP_PKTS   (CLASS_CSR_BASE_ADDR + 0x1a0)
++#define CLASS_PHY2_ICMP_PKTS  (CLASS_CSR_BASE_ADDR + 0x1a4)
++#define CLASS_PHY2_IGMP_PKTS  (CLASS_CSR_BASE_ADDR + 0x1a8)
++#define CLASS_PHY2_TCP_PKTS   (CLASS_CSR_BASE_ADDR + 0x1ac)
++#define CLASS_PHY2_UDP_PKTS   (CLASS_CSR_BASE_ADDR + 0x1b0)
++#define CLASS_PHY3_ICMP_PKTS  (CLASS_CSR_BASE_ADDR + 0x1b4)
++#define CLASS_PHY3_IGMP_PKTS  (CLASS_CSR_BASE_ADDR + 0x1b8)
++#define CLASS_PHY3_TCP_PKTS   (CLASS_CSR_BASE_ADDR + 0x1bc)
++#define CLASS_PHY3_UDP_PKTS   (CLASS_CSR_BASE_ADDR + 0x1c0)
++#define CLASS_PHY4_ICMP_PKTS  (CLASS_CSR_BASE_ADDR + 0x1c4)
++#define CLASS_PHY4_IGMP_PKTS  (CLASS_CSR_BASE_ADDR + 0x1c8)
++#define CLASS_PHY4_TCP_PKTS   (CLASS_CSR_BASE_ADDR + 0x1cc)
++#define CLASS_PHY4_UDP_PKTS   (CLASS_CSR_BASE_ADDR + 0x1d0)
++#define CLASS_PHY4_RX_PKTS    (CLASS_CSR_BASE_ADDR + 0x1d4)
++#define CLASS_PHY4_TX_PKTS    (CLASS_CSR_BASE_ADDR + 0x1d8)
++#define CLASS_PHY4_LP_FAIL_PKTS       (CLASS_CSR_BASE_ADDR + 0x1dc)
++#define CLASS_PHY4_INTF_FAIL_PKTS     (CLASS_CSR_BASE_ADDR + 0x1e0)
++#define CLASS_PHY4_INTF_MATCH_PKTS    (CLASS_CSR_BASE_ADDR + 0x1e4)
++#define CLASS_PHY4_L3_FAIL_PKTS       (CLASS_CSR_BASE_ADDR + 0x1e8)
++#define CLASS_PHY4_V4_PKTS    (CLASS_CSR_BASE_ADDR + 0x1ec)
++#define CLASS_PHY4_V6_PKTS    (CLASS_CSR_BASE_ADDR + 0x1f0)
++#define CLASS_PHY4_CHKSUM_ERR_PKTS    (CLASS_CSR_BASE_ADDR + 0x1f4)
++#define CLASS_PHY4_TTL_ERR_PKTS       (CLASS_CSR_BASE_ADDR + 0x1f8)
++
++#define CLASS_PE_SYS_CLK_RATIO        (CLASS_CSR_BASE_ADDR + 0x200)
++#define CLASS_AFULL_THRES     (CLASS_CSR_BASE_ADDR + 0x204)
++#define CLASS_GAP_BETWEEN_READS       (CLASS_CSR_BASE_ADDR + 0x208)
++#define CLASS_MAX_BUF_CNT     (CLASS_CSR_BASE_ADDR + 0x20c)
++#define CLASS_TSQ_FIFO_THRES  (CLASS_CSR_BASE_ADDR + 0x210)
++#define CLASS_TSQ_MAX_CNT     (CLASS_CSR_BASE_ADDR + 0x214)
++#define CLASS_IRAM_DATA_0     (CLASS_CSR_BASE_ADDR + 0x218)
++#define CLASS_IRAM_DATA_1     (CLASS_CSR_BASE_ADDR + 0x21c)
++#define CLASS_IRAM_DATA_2     (CLASS_CSR_BASE_ADDR + 0x220)
++#define CLASS_IRAM_DATA_3     (CLASS_CSR_BASE_ADDR + 0x224)
++
++#define CLASS_BUS_ACCESS_ADDR (CLASS_CSR_BASE_ADDR + 0x228)
++
++#define CLASS_BUS_ACCESS_WDATA        (CLASS_CSR_BASE_ADDR + 0x22c)
++#define CLASS_BUS_ACCESS_RDATA        (CLASS_CSR_BASE_ADDR + 0x230)
++
++/* (route_entry_size[9:0], route_hash_size[23:16]
++ * (this is actually ln2(size)))
++ */
++#define CLASS_ROUTE_HASH_ENTRY_SIZE   (CLASS_CSR_BASE_ADDR + 0x234)
++
++#define CLASS_ROUTE_ENTRY_SIZE(size)   ((size) & 0x1ff)
++#define CLASS_ROUTE_HASH_SIZE(hash_bits) (((hash_bits) & 0xff) << 16)
++
++#define CLASS_ROUTE_TABLE_BASE        (CLASS_CSR_BASE_ADDR + 0x238)
++
++#define CLASS_ROUTE_MULTI     (CLASS_CSR_BASE_ADDR + 0x23c)
++#define CLASS_SMEM_OFFSET     (CLASS_CSR_BASE_ADDR + 0x240)
++#define CLASS_LMEM_BUF_SIZE   (CLASS_CSR_BASE_ADDR + 0x244)
++#define CLASS_VLAN_ID (CLASS_CSR_BASE_ADDR + 0x248)
++#define CLASS_BMU1_BUF_FREE   (CLASS_CSR_BASE_ADDR + 0x24c)
++#define CLASS_USE_TMU_INQ     (CLASS_CSR_BASE_ADDR + 0x250)
++#define CLASS_VLAN_ID1        (CLASS_CSR_BASE_ADDR + 0x254)
++
++#define CLASS_BUS_ACCESS_BASE (CLASS_CSR_BASE_ADDR + 0x258)
++#define CLASS_BUS_ACCESS_BASE_MASK    (0xFF000000)
++/* bit 31:24 of PE peripheral address are stored in CLASS_BUS_ACCESS_BASE */
++
++#define CLASS_HIF_PARSE       (CLASS_CSR_BASE_ADDR + 0x25c)
++
++#define CLASS_HOST_PE0_GP     (CLASS_CSR_BASE_ADDR + 0x260)
++#define CLASS_PE0_GP  (CLASS_CSR_BASE_ADDR + 0x264)
++#define CLASS_HOST_PE1_GP     (CLASS_CSR_BASE_ADDR + 0x268)
++#define CLASS_PE1_GP  (CLASS_CSR_BASE_ADDR + 0x26c)
++#define CLASS_HOST_PE2_GP     (CLASS_CSR_BASE_ADDR + 0x270)
++#define CLASS_PE2_GP  (CLASS_CSR_BASE_ADDR + 0x274)
++#define CLASS_HOST_PE3_GP     (CLASS_CSR_BASE_ADDR + 0x278)
++#define CLASS_PE3_GP  (CLASS_CSR_BASE_ADDR + 0x27c)
++#define CLASS_HOST_PE4_GP     (CLASS_CSR_BASE_ADDR + 0x280)
++#define CLASS_PE4_GP  (CLASS_CSR_BASE_ADDR + 0x284)
++#define CLASS_HOST_PE5_GP     (CLASS_CSR_BASE_ADDR + 0x288)
++#define CLASS_PE5_GP  (CLASS_CSR_BASE_ADDR + 0x28c)
++
++#define CLASS_PE_INT_SRC      (CLASS_CSR_BASE_ADDR + 0x290)
++#define CLASS_PE_INT_ENABLE   (CLASS_CSR_BASE_ADDR + 0x294)
++
++#define CLASS_TPID0_TPID1     (CLASS_CSR_BASE_ADDR + 0x298)
++#define CLASS_TPID2   (CLASS_CSR_BASE_ADDR + 0x29c)
++
++#define CLASS_L4_CHKSUM_ADDR  (CLASS_CSR_BASE_ADDR + 0x2a0)
++
++#define CLASS_PE0_DEBUG       (CLASS_CSR_BASE_ADDR + 0x2a4)
++#define CLASS_PE1_DEBUG       (CLASS_CSR_BASE_ADDR + 0x2a8)
++#define CLASS_PE2_DEBUG       (CLASS_CSR_BASE_ADDR + 0x2ac)
++#define CLASS_PE3_DEBUG       (CLASS_CSR_BASE_ADDR + 0x2b0)
++#define CLASS_PE4_DEBUG       (CLASS_CSR_BASE_ADDR + 0x2b4)
++#define CLASS_PE5_DEBUG       (CLASS_CSR_BASE_ADDR + 0x2b8)
++
++#define CLASS_STATE   (CLASS_CSR_BASE_ADDR + 0x2bc)
++
++/* CLASS defines */
++#define CLASS_PBUF_SIZE       0x100   /* Fixed by hardware */
++#define CLASS_PBUF_HEADER_OFFSET      0x80    /* Can be configured */
++
++/* Can be configured */
++#define CLASS_PBUF0_BASE_ADDR 0x000
++/* Can be configured */
++#define CLASS_PBUF1_BASE_ADDR (CLASS_PBUF0_BASE_ADDR + CLASS_PBUF_SIZE)
++/* Can be configured */
++#define CLASS_PBUF2_BASE_ADDR (CLASS_PBUF1_BASE_ADDR + CLASS_PBUF_SIZE)
++/* Can be configured */
++#define CLASS_PBUF3_BASE_ADDR (CLASS_PBUF2_BASE_ADDR + CLASS_PBUF_SIZE)
++
++#define CLASS_PBUF0_HEADER_BASE_ADDR  (CLASS_PBUF0_BASE_ADDR + \
++                                              CLASS_PBUF_HEADER_OFFSET)
++#define CLASS_PBUF1_HEADER_BASE_ADDR  (CLASS_PBUF1_BASE_ADDR + \
++                                              CLASS_PBUF_HEADER_OFFSET)
++#define CLASS_PBUF2_HEADER_BASE_ADDR  (CLASS_PBUF2_BASE_ADDR + \
++                                              CLASS_PBUF_HEADER_OFFSET)
++#define CLASS_PBUF3_HEADER_BASE_ADDR  (CLASS_PBUF3_BASE_ADDR + \
++                                              CLASS_PBUF_HEADER_OFFSET)
++
++#define CLASS_PE0_RO_DM_ADDR0_VAL     ((CLASS_PBUF1_BASE_ADDR << 16) | \
++                                              CLASS_PBUF0_BASE_ADDR)
++#define CLASS_PE0_RO_DM_ADDR1_VAL     ((CLASS_PBUF3_BASE_ADDR << 16) | \
++                                              CLASS_PBUF2_BASE_ADDR)
++
++#define CLASS_PE0_QB_DM_ADDR0_VAL     ((CLASS_PBUF1_HEADER_BASE_ADDR << 16) |\
++                                              CLASS_PBUF0_HEADER_BASE_ADDR)
++#define CLASS_PE0_QB_DM_ADDR1_VAL     ((CLASS_PBUF3_HEADER_BASE_ADDR << 16) |\
++                                              CLASS_PBUF2_HEADER_BASE_ADDR)
++
++#define CLASS_ROUTE_SIZE      128
++#define CLASS_MAX_ROUTE_SIZE  256
++#define CLASS_ROUTE_HASH_BITS 20
++#define CLASS_ROUTE_HASH_MASK (BIT(CLASS_ROUTE_HASH_BITS) - 1)
++
++/* Can be configured */
++#define       CLASS_ROUTE0_BASE_ADDR  0x400
++/* Can be configured */
++#define CLASS_ROUTE1_BASE_ADDR        (CLASS_ROUTE0_BASE_ADDR + CLASS_ROUTE_SIZE)
++/* Can be configured */
++#define CLASS_ROUTE2_BASE_ADDR        (CLASS_ROUTE1_BASE_ADDR + CLASS_ROUTE_SIZE)
++/* Can be configured */
++#define CLASS_ROUTE3_BASE_ADDR        (CLASS_ROUTE2_BASE_ADDR + CLASS_ROUTE_SIZE)
++
++#define CLASS_SA_SIZE 128
++#define CLASS_IPSEC_SA0_BASE_ADDR     0x600
++/* not used */
++#define CLASS_IPSEC_SA1_BASE_ADDR  (CLASS_IPSEC_SA0_BASE_ADDR + CLASS_SA_SIZE)
++/* not used */
++#define CLASS_IPSEC_SA2_BASE_ADDR  (CLASS_IPSEC_SA1_BASE_ADDR + CLASS_SA_SIZE)
++/* not used */
++#define CLASS_IPSEC_SA3_BASE_ADDR  (CLASS_IPSEC_SA2_BASE_ADDR + CLASS_SA_SIZE)
++
++/* generic purpose free dmem buffer, last portion of 2K dmem pbuf */
++#define CLASS_GP_DMEM_BUF_SIZE        (2048 - (CLASS_PBUF_SIZE * 4) - \
++                              (CLASS_ROUTE_SIZE * 4) - (CLASS_SA_SIZE))
++#define CLASS_GP_DMEM_BUF     ((void *)(CLASS_IPSEC_SA0_BASE_ADDR + \
++                                      CLASS_SA_SIZE))
++
++#define TWO_LEVEL_ROUTE               BIT(0)
++#define PHYNO_IN_HASH         BIT(1)
++#define HW_ROUTE_FETCH                BIT(3)
++#define HW_BRIDGE_FETCH               BIT(5)
++#define IP_ALIGNED            BIT(6)
++#define ARC_HIT_CHECK_EN      BIT(7)
++#define CLASS_TOE             BIT(11)
++#define HASH_NORMAL           (0 << 12)
++#define HASH_CRC_PORT         BIT(12)
++#define HASH_CRC_IP           (2 << 12)
++#define HASH_CRC_PORT_IP      (3 << 12)
++#define QB2BUS_LE             BIT(15)
++
++#define TCP_CHKSUM_DROP               BIT(0)
++#define UDP_CHKSUM_DROP               BIT(1)
++#define IPV4_CHKSUM_DROP      BIT(9)
++
++/*CLASS_HIF_PARSE bits*/
++#define HIF_PKT_CLASS_EN      BIT(0)
++#define HIF_PKT_OFFSET(ofst)  (((ofst) & 0xF) << 1)
++
++struct class_cfg {
++      u32 toe_mode;
++      unsigned long route_table_baseaddr;
++      u32 route_table_hash_bits;
++      u32 pe_sys_clk_ratio;
++      u32 resume;
++};
++
++#endif /* _CLASS_CSR_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/include/pfe/cbus/emac_mtip.h
+@@ -0,0 +1,242 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _EMAC_H_
++#define _EMAC_H_
++
++#include <linux/ethtool.h>
++
++#define EMAC_IEVENT_REG               0x004
++#define EMAC_IMASK_REG                0x008
++#define EMAC_R_DES_ACTIVE_REG 0x010
++#define EMAC_X_DES_ACTIVE_REG 0x014
++#define EMAC_ECNTRL_REG               0x024
++#define EMAC_MII_DATA_REG     0x040
++#define EMAC_MII_CTRL_REG     0x044
++#define EMAC_MIB_CTRL_STS_REG 0x064
++#define EMAC_RCNTRL_REG               0x084
++#define EMAC_TCNTRL_REG               0x0C4
++#define EMAC_PHY_ADDR_LOW     0x0E4
++#define EMAC_PHY_ADDR_HIGH    0x0E8
++#define EMAC_GAUR             0x120
++#define EMAC_GALR             0x124
++#define EMAC_TFWR_STR_FWD     0x144
++#define EMAC_RX_SECTION_FULL  0x190
++#define EMAC_RX_SECTION_EMPTY 0x194
++#define EMAC_TX_SECTION_EMPTY 0x1A0
++#define EMAC_TRUNC_FL         0x1B0
++
++#define RMON_T_DROP   0x200 /* Count of frames not cntd correctly */
++#define RMON_T_PACKETS        0x204 /* RMON TX packet count */
++#define RMON_T_BC_PKT 0x208 /* RMON TX broadcast pkts */
++#define RMON_T_MC_PKT 0x20c /* RMON TX multicast pkts */
++#define RMON_T_CRC_ALIGN      0x210 /* RMON TX pkts with CRC align err */
++#define RMON_T_UNDERSIZE      0x214 /* RMON TX pkts < 64 bytes, good CRC */
++#define RMON_T_OVERSIZE       0x218 /* RMON TX pkts > MAX_FL bytes good CRC */
++#define RMON_T_FRAG   0x21c /* RMON TX pkts < 64 bytes, bad CRC */
++#define RMON_T_JAB    0x220 /* RMON TX pkts > MAX_FL bytes, bad CRC */
++#define RMON_T_COL    0x224 /* RMON TX collision count */
++#define RMON_T_P64    0x228 /* RMON TX 64 byte pkts */
++#define RMON_T_P65TO127       0x22c /* RMON TX 65 to 127 byte pkts */
++#define RMON_T_P128TO255      0x230 /* RMON TX 128 to 255 byte pkts */
++#define RMON_T_P256TO511      0x234 /* RMON TX 256 to 511 byte pkts */
++#define RMON_T_P512TO1023     0x238 /* RMON TX 512 to 1023 byte pkts */
++#define RMON_T_P1024TO2047    0x23c /* RMON TX 1024 to 2047 byte pkts */
++#define RMON_T_P_GTE2048      0x240 /* RMON TX pkts > 2048 bytes */
++#define RMON_T_OCTETS 0x244 /* RMON TX octets */
++#define IEEE_T_DROP   0x248 /* Count of frames not counted crtly */
++#define IEEE_T_FRAME_OK       0x24c /* Frames tx'd OK */
++#define IEEE_T_1COL   0x250 /* Frames tx'd with single collision */
++#define IEEE_T_MCOL   0x254 /* Frames tx'd with multiple collision */
++#define IEEE_T_DEF    0x258 /* Frames tx'd after deferral delay */
++#define IEEE_T_LCOL   0x25c /* Frames tx'd with late collision */
++#define IEEE_T_EXCOL  0x260 /* Frames tx'd with excesv collisions */
++#define IEEE_T_MACERR 0x264 /* Frames tx'd with TX FIFO underrun */
++#define IEEE_T_CSERR  0x268 /* Frames tx'd with carrier sense err */
++#define IEEE_T_SQE    0x26c /* Frames tx'd with SQE err */
++#define IEEE_T_FDXFC  0x270 /* Flow control pause frames tx'd */
++#define IEEE_T_OCTETS_OK      0x274 /* Octet count for frames tx'd w/o err */
++#define RMON_R_PACKETS        0x284 /* RMON RX packet count */
++#define RMON_R_BC_PKT 0x288 /* RMON RX broadcast pkts */
++#define RMON_R_MC_PKT 0x28c /* RMON RX multicast pkts */
++#define RMON_R_CRC_ALIGN      0x290 /* RMON RX pkts with CRC alignment err */
++#define RMON_R_UNDERSIZE      0x294 /* RMON RX pkts < 64 bytes, good CRC */
++#define RMON_R_OVERSIZE       0x298 /* RMON RX pkts > MAX_FL bytes good CRC */
++#define RMON_R_FRAG   0x29c /* RMON RX pkts < 64 bytes, bad CRC */
++#define RMON_R_JAB    0x2a0 /* RMON RX pkts > MAX_FL bytes, bad CRC */
++#define RMON_R_RESVD_O        0x2a4 /* Reserved */
++#define RMON_R_P64    0x2a8 /* RMON RX 64 byte pkts */
++#define RMON_R_P65TO127       0x2ac /* RMON RX 65 to 127 byte pkts */
++#define RMON_R_P128TO255      0x2b0 /* RMON RX 128 to 255 byte pkts */
++#define RMON_R_P256TO511      0x2b4 /* RMON RX 256 to 511 byte pkts */
++#define RMON_R_P512TO1023     0x2b8 /* RMON RX 512 to 1023 byte pkts */
++#define RMON_R_P1024TO2047    0x2bc /* RMON RX 1024 to 2047 byte pkts */
++#define RMON_R_P_GTE2048      0x2c0 /* RMON RX pkts > 2048 bytes */
++#define RMON_R_OCTETS 0x2c4 /* RMON RX octets */
++#define IEEE_R_DROP   0x2c8 /* Count frames not counted correctly */
++#define IEEE_R_FRAME_OK       0x2cc /* Frames rx'd OK */
++#define IEEE_R_CRC    0x2d0 /* Frames rx'd with CRC err */
++#define IEEE_R_ALIGN  0x2d4 /* Frames rx'd with alignment err */
++#define IEEE_R_MACERR 0x2d8 /* Receive FIFO overflow count */
++#define IEEE_R_FDXFC  0x2dc /* Flow control pause frames rx'd */
++#define IEEE_R_OCTETS_OK      0x2e0 /* Octet cnt for frames rx'd w/o err */
++
++#define EMAC_SMAC_0_0 0x500 /*Supplemental MAC Address 0 (RW).*/
++#define EMAC_SMAC_0_1 0x504 /*Supplemental MAC Address 0 (RW).*/
++
++/* GEMAC definitions and settings */
++
++#define EMAC_PORT_0   0
++#define EMAC_PORT_1   1
++
++/* GEMAC Bit definitions */
++#define EMAC_IEVENT_HBERR              0x80000000
++#define EMAC_IEVENT_BABR               0x40000000
++#define EMAC_IEVENT_BABT               0x20000000
++#define EMAC_IEVENT_GRA                        0x10000000
++#define EMAC_IEVENT_TXF                        0x08000000
++#define EMAC_IEVENT_TXB                        0x04000000
++#define EMAC_IEVENT_RXF                        0x02000000
++#define EMAC_IEVENT_RXB                        0x01000000
++#define EMAC_IEVENT_MII                        0x00800000
++#define EMAC_IEVENT_EBERR              0x00400000
++#define EMAC_IEVENT_LC                         0x00200000
++#define EMAC_IEVENT_RL                         0x00100000
++#define EMAC_IEVENT_UN                         0x00080000
++
++#define EMAC_IMASK_HBERR                 0x80000000
++#define EMAC_IMASK_BABR                  0x40000000
++#define EMAC_IMASKT_BABT                 0x20000000
++#define EMAC_IMASK_GRA                   0x10000000
++#define EMAC_IMASKT_TXF                  0x08000000
++#define EMAC_IMASK_TXB                   0x04000000
++#define EMAC_IMASKT_RXF                  0x02000000
++#define EMAC_IMASK_RXB                   0x01000000
++#define EMAC_IMASK_MII                   0x00800000
++#define EMAC_IMASK_EBERR                 0x00400000
++#define EMAC_IMASK_LC                    0x00200000
++#define EMAC_IMASKT_RL                   0x00100000
++#define EMAC_IMASK_UN                    0x00080000
++
++#define EMAC_RCNTRL_MAX_FL_SHIFT         16
++#define EMAC_RCNTRL_LOOP                 0x00000001
++#define EMAC_RCNTRL_DRT                  0x00000002
++#define EMAC_RCNTRL_MII_MODE             0x00000004
++#define EMAC_RCNTRL_PROM                 0x00000008
++#define EMAC_RCNTRL_BC_REJ               0x00000010
++#define EMAC_RCNTRL_FCE                  0x00000020
++#define EMAC_RCNTRL_RGMII                0x00000040
++#define EMAC_RCNTRL_SGMII                0x00000080
++#define EMAC_RCNTRL_RMII                 0x00000100
++#define EMAC_RCNTRL_RMII_10T             0x00000200
++#define EMAC_RCNTRL_CRC_FWD            0x00004000
++
++#define EMAC_TCNTRL_GTS                  0x00000001
++#define EMAC_TCNTRL_HBC                  0x00000002
++#define EMAC_TCNTRL_FDEN                 0x00000004
++#define EMAC_TCNTRL_TFC_PAUSE            0x00000008
++#define EMAC_TCNTRL_RFC_PAUSE            0x00000010
++
++#define EMAC_ECNTRL_RESET                0x00000001      /* reset the EMAC */
++#define EMAC_ECNTRL_ETHER_EN             0x00000002      /* enable the EMAC */
++#define EMAC_ECNTRL_MAGIC_ENA          0x00000004
++#define EMAC_ECNTRL_SLEEP              0x00000008
++#define EMAC_ECNTRL_SPEED                0x00000020
++#define EMAC_ECNTRL_DBSWAP               0x00000100
++
++#define EMAC_X_WMRK_STRFWD               0x00000100
++
++#define EMAC_X_DES_ACTIVE_TDAR           0x01000000
++#define EMAC_R_DES_ACTIVE_RDAR           0x01000000
++
++#define EMAC_RX_SECTION_EMPTY_V               0x00010006
++/*
++ * The possible operating speeds of the MAC, currently supporting 10, 100 and
++ * 1000Mb modes.
++ */
++enum mac_speed {SPEED_10M, SPEED_100M, SPEED_1000M, SPEED_1000M_PCS};
++
++/* MII-related definitios */
++#define EMAC_MII_DATA_ST         0x40000000      /* Start of frame delimiter */
++#define EMAC_MII_DATA_OP_RD      0x20000000      /* Perform a read operation */
++#define EMAC_MII_DATA_OP_CL45_RD 0x30000000      /* Perform a read operation */
++#define EMAC_MII_DATA_OP_WR      0x10000000      /* Perform a write operation */
++#define EMAC_MII_DATA_OP_CL45_WR 0x10000000      /* Perform a write operation */
++#define EMAC_MII_DATA_PA_MSK     0x0f800000      /* PHY Address field mask */
++#define EMAC_MII_DATA_RA_MSK     0x007c0000      /* PHY Register field mask */
++#define EMAC_MII_DATA_TA         0x00020000      /* Turnaround */
++#define EMAC_MII_DATA_DATAMSK    0x0000ffff      /* PHY data field */
++
++#define EMAC_MII_DATA_RA_SHIFT   18      /* MII Register address bits */
++#define EMAC_MII_DATA_RA_MASK  0x1F      /* MII Register address mask */
++#define EMAC_MII_DATA_PA_SHIFT   23      /* MII PHY address bits */
++#define EMAC_MII_DATA_PA_MASK    0x1F      /* MII PHY address mask */
++
++#define EMAC_MII_DATA_RA(v) (((v) & EMAC_MII_DATA_RA_MASK) << \
++                              EMAC_MII_DATA_RA_SHIFT)
++#define EMAC_MII_DATA_PA(v) (((v) & EMAC_MII_DATA_RA_MASK) << \
++                              EMAC_MII_DATA_PA_SHIFT)
++#define EMAC_MII_DATA(v)    ((v) & 0xffff)
++
++#define EMAC_MII_SPEED_SHIFT  1
++#define EMAC_HOLDTIME_SHIFT   8
++#define EMAC_HOLDTIME_MASK    0x7
++#define EMAC_HOLDTIME(v)      (((v) & EMAC_HOLDTIME_MASK) << \
++                                      EMAC_HOLDTIME_SHIFT)
++
++/*
++ * The Address organisation for the MAC device.  All addresses are split into
++ * two 32-bit register fields.  The first one (bottom) is the lower 32-bits of
++ * the address and the other field are the high order bits - this may be 16-bits
++ * in the case of MAC addresses, or 32-bits for the hash address.
++ * In terms of memory storage, the first item (bottom) is assumed to be at a
++ * lower address location than 'top'. i.e. top should be at address location of
++ * 'bottom' + 4 bytes.
++ */
++struct pfe_mac_addr {
++      u32 bottom;     /* Lower 32-bits of address. */
++      u32 top;        /* Upper 32-bits of address. */
++};
++
++/*
++ * The following is the organisation of the address filters section of the MAC
++ * registers.  The Cadence MAC contains four possible specific address match
++ * addresses, if an incoming frame corresponds to any one of these four
++ * addresses then the frame will be copied to memory.
++ * It is not necessary for all four of the address match registers to be
++ * programmed, this is application dependent.
++ */
++struct spec_addr {
++      struct pfe_mac_addr one;        /* Specific address register 1. */
++      struct pfe_mac_addr two;        /* Specific address register 2. */
++      struct pfe_mac_addr three;      /* Specific address register 3. */
++      struct pfe_mac_addr four;       /* Specific address register 4. */
++};
++
++struct gemac_cfg {
++      u32 mode;
++      u32 speed;
++      u32 duplex;
++};
++
++/* EMAC Hash size */
++#define EMAC_HASH_REG_BITS       64
++
++#define EMAC_SPEC_ADDR_MAX    4
++
++#endif /* _EMAC_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/include/pfe/cbus/gpi.h
+@@ -0,0 +1,86 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _GPI_H_
++#define _GPI_H_
++
++#define GPI_VERSION   0x00
++#define GPI_CTRL      0x04
++#define GPI_RX_CONFIG 0x08
++#define GPI_HDR_SIZE  0x0c
++#define GPI_BUF_SIZE  0x10
++#define GPI_LMEM_ALLOC_ADDR   0x14
++#define GPI_LMEM_FREE_ADDR    0x18
++#define GPI_DDR_ALLOC_ADDR    0x1c
++#define GPI_DDR_FREE_ADDR     0x20
++#define GPI_CLASS_ADDR        0x24
++#define GPI_DRX_FIFO  0x28
++#define GPI_TRX_FIFO  0x2c
++#define GPI_INQ_PKTPTR        0x30
++#define GPI_DDR_DATA_OFFSET   0x34
++#define GPI_LMEM_DATA_OFFSET  0x38
++#define GPI_TMLF_TX   0x4c
++#define GPI_DTX_ASEQ  0x50
++#define GPI_FIFO_STATUS       0x54
++#define GPI_FIFO_DEBUG        0x58
++#define GPI_TX_PAUSE_TIME     0x5c
++#define GPI_LMEM_SEC_BUF_DATA_OFFSET  0x60
++#define GPI_DDR_SEC_BUF_DATA_OFFSET   0x64
++#define GPI_TOE_CHKSUM_EN     0x68
++#define GPI_OVERRUN_DROPCNT   0x6c
++#define GPI_CSR_MTIP_PAUSE_REG                0x74
++#define GPI_CSR_MTIP_PAUSE_QUANTUM    0x78
++#define GPI_CSR_RX_CNT                        0x7c
++#define GPI_CSR_TX_CNT                        0x80
++#define GPI_CSR_DEBUG1                        0x84
++#define GPI_CSR_DEBUG2                        0x88
++
++struct gpi_cfg {
++      u32 lmem_rtry_cnt;
++      u32 tmlf_txthres;
++      u32 aseq_len;
++      u32 mtip_pause_reg;
++};
++
++/* GPI commons defines */
++#define GPI_LMEM_BUF_EN       0x1
++#define GPI_DDR_BUF_EN        0x1
++
++/* EGPI 1 defines */
++#define EGPI1_LMEM_RTRY_CNT   0x40
++#define EGPI1_TMLF_TXTHRES    0xBC
++#define EGPI1_ASEQ_LEN        0x50
++
++/* EGPI 2 defines */
++#define EGPI2_LMEM_RTRY_CNT   0x40
++#define EGPI2_TMLF_TXTHRES    0xBC
++#define EGPI2_ASEQ_LEN        0x40
++
++/* EGPI 3 defines */
++#define EGPI3_LMEM_RTRY_CNT   0x40
++#define EGPI3_TMLF_TXTHRES    0xBC
++#define EGPI3_ASEQ_LEN        0x40
++
++/* HGPI defines */
++#define HGPI_LMEM_RTRY_CNT    0x40
++#define HGPI_TMLF_TXTHRES     0xBC
++#define HGPI_ASEQ_LEN 0x40
++
++#define EGPI_PAUSE_TIME               0x000007D0
++#define EGPI_PAUSE_ENABLE     0x40000000
++#endif /* _GPI_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/include/pfe/cbus/hif.h
+@@ -0,0 +1,100 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _HIF_H_
++#define _HIF_H_
++
++/* @file hif.h.
++ * hif - PFE hif block control and status register.
++ * Mapped on CBUS and accessible from all PE's and ARM.
++ */
++#define HIF_VERSION   (HIF_BASE_ADDR + 0x00)
++#define HIF_TX_CTRL   (HIF_BASE_ADDR + 0x04)
++#define HIF_TX_CURR_BD_ADDR   (HIF_BASE_ADDR + 0x08)
++#define HIF_TX_ALLOC  (HIF_BASE_ADDR + 0x0c)
++#define HIF_TX_BDP_ADDR       (HIF_BASE_ADDR + 0x10)
++#define HIF_TX_STATUS (HIF_BASE_ADDR + 0x14)
++#define HIF_RX_CTRL   (HIF_BASE_ADDR + 0x20)
++#define HIF_RX_BDP_ADDR       (HIF_BASE_ADDR + 0x24)
++#define HIF_RX_STATUS (HIF_BASE_ADDR + 0x30)
++#define HIF_INT_SRC   (HIF_BASE_ADDR + 0x34)
++#define HIF_INT_ENABLE        (HIF_BASE_ADDR + 0x38)
++#define HIF_POLL_CTRL (HIF_BASE_ADDR + 0x3c)
++#define HIF_RX_CURR_BD_ADDR   (HIF_BASE_ADDR + 0x40)
++#define HIF_RX_ALLOC  (HIF_BASE_ADDR + 0x44)
++#define HIF_TX_DMA_STATUS     (HIF_BASE_ADDR + 0x48)
++#define HIF_RX_DMA_STATUS     (HIF_BASE_ADDR + 0x4c)
++#define HIF_INT_COAL  (HIF_BASE_ADDR + 0x50)
++
++/* HIF_INT_SRC/ HIF_INT_ENABLE control bits */
++#define HIF_INT               BIT(0)
++#define HIF_RXBD_INT  BIT(1)
++#define HIF_RXPKT_INT BIT(2)
++#define HIF_TXBD_INT  BIT(3)
++#define HIF_TXPKT_INT BIT(4)
++
++/* HIF_TX_CTRL bits */
++#define HIF_CTRL_DMA_EN                       BIT(0)
++#define HIF_CTRL_BDP_POLL_CTRL_EN     BIT(1)
++#define HIF_CTRL_BDP_CH_START_WSTB    BIT(2)
++
++/* HIF_RX_STATUS bits */
++#define BDP_CSR_RX_DMA_ACTV     BIT(16)
++
++/* HIF_INT_ENABLE bits */
++#define HIF_INT_EN            BIT(0)
++#define HIF_RXBD_INT_EN               BIT(1)
++#define HIF_RXPKT_INT_EN      BIT(2)
++#define HIF_TXBD_INT_EN               BIT(3)
++#define HIF_TXPKT_INT_EN      BIT(4)
++
++/* HIF_POLL_CTRL bits*/
++#define HIF_RX_POLL_CTRL_CYCLE        0x0400
++#define HIF_TX_POLL_CTRL_CYCLE        0x0400
++
++/* HIF_INT_COAL bits*/
++#define HIF_INT_COAL_ENABLE   BIT(31)
++
++/* Buffer descriptor control bits */
++#define BD_CTRL_BUFLEN_MASK   0x3fff
++#define BD_BUF_LEN(x) ((x) & BD_CTRL_BUFLEN_MASK)
++#define BD_CTRL_CBD_INT_EN    BIT(16)
++#define BD_CTRL_PKT_INT_EN    BIT(17)
++#define BD_CTRL_LIFM          BIT(18)
++#define BD_CTRL_LAST_BD               BIT(19)
++#define BD_CTRL_DIR           BIT(20)
++#define BD_CTRL_LMEM_CPY      BIT(21) /* Valid only for HIF_NOCPY */
++#define BD_CTRL_PKT_XFER      BIT(24)
++#define BD_CTRL_DESC_EN               BIT(31)
++#define BD_CTRL_PARSE_DISABLE BIT(25)
++#define BD_CTRL_BRFETCH_DISABLE       BIT(26)
++#define BD_CTRL_RTFETCH_DISABLE       BIT(27)
++
++/* Buffer descriptor status bits*/
++#define BD_STATUS_CONN_ID(x)  ((x) & 0xffff)
++#define BD_STATUS_DIR_PROC_ID BIT(16)
++#define BD_STATUS_CONN_ID_EN  BIT(17)
++#define BD_STATUS_PE2PROC_ID(x)       (((x) & 7) << 18)
++#define BD_STATUS_LE_DATA     BIT(21)
++#define BD_STATUS_CHKSUM_EN   BIT(22)
++
++/* HIF Buffer descriptor status bits */
++#define DIR_PROC_ID   BIT(16)
++#define PROC_ID(id)   ((id) << 18)
++
++#endif /* _HIF_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/include/pfe/cbus/hif_nocpy.h
+@@ -0,0 +1,50 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _HIF_NOCPY_H_
++#define _HIF_NOCPY_H_
++
++#define HIF_NOCPY_VERSION     (HIF_NOCPY_BASE_ADDR + 0x00)
++#define HIF_NOCPY_TX_CTRL     (HIF_NOCPY_BASE_ADDR + 0x04)
++#define HIF_NOCPY_TX_CURR_BD_ADDR     (HIF_NOCPY_BASE_ADDR + 0x08)
++#define HIF_NOCPY_TX_ALLOC    (HIF_NOCPY_BASE_ADDR + 0x0c)
++#define HIF_NOCPY_TX_BDP_ADDR (HIF_NOCPY_BASE_ADDR + 0x10)
++#define HIF_NOCPY_TX_STATUS   (HIF_NOCPY_BASE_ADDR + 0x14)
++#define HIF_NOCPY_RX_CTRL     (HIF_NOCPY_BASE_ADDR + 0x20)
++#define HIF_NOCPY_RX_BDP_ADDR (HIF_NOCPY_BASE_ADDR + 0x24)
++#define HIF_NOCPY_RX_STATUS   (HIF_NOCPY_BASE_ADDR + 0x30)
++#define HIF_NOCPY_INT_SRC     (HIF_NOCPY_BASE_ADDR + 0x34)
++#define HIF_NOCPY_INT_ENABLE  (HIF_NOCPY_BASE_ADDR + 0x38)
++#define HIF_NOCPY_POLL_CTRL   (HIF_NOCPY_BASE_ADDR + 0x3c)
++#define HIF_NOCPY_RX_CURR_BD_ADDR     (HIF_NOCPY_BASE_ADDR + 0x40)
++#define HIF_NOCPY_RX_ALLOC    (HIF_NOCPY_BASE_ADDR + 0x44)
++#define HIF_NOCPY_TX_DMA_STATUS       (HIF_NOCPY_BASE_ADDR + 0x48)
++#define HIF_NOCPY_RX_DMA_STATUS       (HIF_NOCPY_BASE_ADDR + 0x4c)
++#define HIF_NOCPY_RX_INQ0_PKTPTR      (HIF_NOCPY_BASE_ADDR + 0x50)
++#define HIF_NOCPY_RX_INQ1_PKTPTR      (HIF_NOCPY_BASE_ADDR + 0x54)
++#define HIF_NOCPY_TX_PORT_NO  (HIF_NOCPY_BASE_ADDR + 0x60)
++#define HIF_NOCPY_LMEM_ALLOC_ADDR     (HIF_NOCPY_BASE_ADDR + 0x64)
++#define HIF_NOCPY_CLASS_ADDR  (HIF_NOCPY_BASE_ADDR + 0x68)
++#define HIF_NOCPY_TMU_PORT0_ADDR      (HIF_NOCPY_BASE_ADDR + 0x70)
++#define HIF_NOCPY_TMU_PORT1_ADDR      (HIF_NOCPY_BASE_ADDR + 0x74)
++#define HIF_NOCPY_TMU_PORT2_ADDR      (HIF_NOCPY_BASE_ADDR + 0x7c)
++#define HIF_NOCPY_TMU_PORT3_ADDR      (HIF_NOCPY_BASE_ADDR + 0x80)
++#define HIF_NOCPY_TMU_PORT4_ADDR      (HIF_NOCPY_BASE_ADDR + 0x84)
++#define HIF_NOCPY_INT_COAL    (HIF_NOCPY_BASE_ADDR + 0x90)
++
++#endif /* _HIF_NOCPY_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/include/pfe/cbus/tmu_csr.h
+@@ -0,0 +1,168 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _TMU_CSR_H_
++#define _TMU_CSR_H_
++
++#define TMU_VERSION   (TMU_CSR_BASE_ADDR + 0x000)
++#define TMU_INQ_WATERMARK     (TMU_CSR_BASE_ADDR + 0x004)
++#define TMU_PHY_INQ_PKTPTR    (TMU_CSR_BASE_ADDR + 0x008)
++#define TMU_PHY_INQ_PKTINFO   (TMU_CSR_BASE_ADDR + 0x00c)
++#define TMU_PHY_INQ_FIFO_CNT  (TMU_CSR_BASE_ADDR + 0x010)
++#define TMU_SYS_GENERIC_CONTROL       (TMU_CSR_BASE_ADDR + 0x014)
++#define TMU_SYS_GENERIC_STATUS        (TMU_CSR_BASE_ADDR + 0x018)
++#define TMU_SYS_GEN_CON0      (TMU_CSR_BASE_ADDR + 0x01c)
++#define TMU_SYS_GEN_CON1      (TMU_CSR_BASE_ADDR + 0x020)
++#define TMU_SYS_GEN_CON2      (TMU_CSR_BASE_ADDR + 0x024)
++#define TMU_SYS_GEN_CON3      (TMU_CSR_BASE_ADDR + 0x028)
++#define TMU_SYS_GEN_CON4      (TMU_CSR_BASE_ADDR + 0x02c)
++#define TMU_TEQ_DISABLE_DROPCHK       (TMU_CSR_BASE_ADDR + 0x030)
++#define TMU_TEQ_CTRL  (TMU_CSR_BASE_ADDR + 0x034)
++#define TMU_TEQ_QCFG  (TMU_CSR_BASE_ADDR + 0x038)
++#define TMU_TEQ_DROP_STAT     (TMU_CSR_BASE_ADDR + 0x03c)
++#define TMU_TEQ_QAVG  (TMU_CSR_BASE_ADDR + 0x040)
++#define TMU_TEQ_WREG_PROB     (TMU_CSR_BASE_ADDR + 0x044)
++#define TMU_TEQ_TRANS_STAT    (TMU_CSR_BASE_ADDR + 0x048)
++#define TMU_TEQ_HW_PROB_CFG0  (TMU_CSR_BASE_ADDR + 0x04c)
++#define TMU_TEQ_HW_PROB_CFG1  (TMU_CSR_BASE_ADDR + 0x050)
++#define TMU_TEQ_HW_PROB_CFG2  (TMU_CSR_BASE_ADDR + 0x054)
++#define TMU_TEQ_HW_PROB_CFG3  (TMU_CSR_BASE_ADDR + 0x058)
++#define TMU_TEQ_HW_PROB_CFG4  (TMU_CSR_BASE_ADDR + 0x05c)
++#define TMU_TEQ_HW_PROB_CFG5  (TMU_CSR_BASE_ADDR + 0x060)
++#define TMU_TEQ_HW_PROB_CFG6  (TMU_CSR_BASE_ADDR + 0x064)
++#define TMU_TEQ_HW_PROB_CFG7  (TMU_CSR_BASE_ADDR + 0x068)
++#define TMU_TEQ_HW_PROB_CFG8  (TMU_CSR_BASE_ADDR + 0x06c)
++#define TMU_TEQ_HW_PROB_CFG9  (TMU_CSR_BASE_ADDR + 0x070)
++#define TMU_TEQ_HW_PROB_CFG10 (TMU_CSR_BASE_ADDR + 0x074)
++#define TMU_TEQ_HW_PROB_CFG11 (TMU_CSR_BASE_ADDR + 0x078)
++#define TMU_TEQ_HW_PROB_CFG12 (TMU_CSR_BASE_ADDR + 0x07c)
++#define TMU_TEQ_HW_PROB_CFG13 (TMU_CSR_BASE_ADDR + 0x080)
++#define TMU_TEQ_HW_PROB_CFG14 (TMU_CSR_BASE_ADDR + 0x084)
++#define TMU_TEQ_HW_PROB_CFG15 (TMU_CSR_BASE_ADDR + 0x088)
++#define TMU_TEQ_HW_PROB_CFG16 (TMU_CSR_BASE_ADDR + 0x08c)
++#define TMU_TEQ_HW_PROB_CFG17 (TMU_CSR_BASE_ADDR + 0x090)
++#define TMU_TEQ_HW_PROB_CFG18 (TMU_CSR_BASE_ADDR + 0x094)
++#define TMU_TEQ_HW_PROB_CFG19 (TMU_CSR_BASE_ADDR + 0x098)
++#define TMU_TEQ_HW_PROB_CFG20 (TMU_CSR_BASE_ADDR + 0x09c)
++#define TMU_TEQ_HW_PROB_CFG21 (TMU_CSR_BASE_ADDR + 0x0a0)
++#define TMU_TEQ_HW_PROB_CFG22 (TMU_CSR_BASE_ADDR + 0x0a4)
++#define TMU_TEQ_HW_PROB_CFG23 (TMU_CSR_BASE_ADDR + 0x0a8)
++#define TMU_TEQ_HW_PROB_CFG24 (TMU_CSR_BASE_ADDR + 0x0ac)
++#define TMU_TEQ_HW_PROB_CFG25 (TMU_CSR_BASE_ADDR + 0x0b0)
++#define TMU_TDQ_IIFG_CFG      (TMU_CSR_BASE_ADDR + 0x0b4)
++/* [9:0] Scheduler Enable for each of the scheduler in the TDQ.
++ * This is a global Enable for all schedulers in PHY0
++ */
++#define TMU_TDQ0_SCH_CTRL     (TMU_CSR_BASE_ADDR + 0x0b8)
++
++#define TMU_LLM_CTRL  (TMU_CSR_BASE_ADDR + 0x0bc)
++#define TMU_LLM_BASE_ADDR     (TMU_CSR_BASE_ADDR + 0x0c0)
++#define TMU_LLM_QUE_LEN       (TMU_CSR_BASE_ADDR + 0x0c4)
++#define TMU_LLM_QUE_HEADPTR   (TMU_CSR_BASE_ADDR + 0x0c8)
++#define TMU_LLM_QUE_TAILPTR   (TMU_CSR_BASE_ADDR + 0x0cc)
++#define TMU_LLM_QUE_DROPCNT   (TMU_CSR_BASE_ADDR + 0x0d0)
++#define TMU_INT_EN    (TMU_CSR_BASE_ADDR + 0x0d4)
++#define TMU_INT_SRC   (TMU_CSR_BASE_ADDR + 0x0d8)
++#define TMU_INQ_STAT  (TMU_CSR_BASE_ADDR + 0x0dc)
++#define TMU_CTRL      (TMU_CSR_BASE_ADDR + 0x0e0)
++
++/* [31] Mem Access Command. 0 = Internal Memory Read, 1 = Internal memory
++ * Write [27:24] Byte Enables of the Internal memory access [23:0] Address of
++ * the internal memory. This address is used to access both the PM and DM of
++ * all the PE's
++ */
++#define TMU_MEM_ACCESS_ADDR   (TMU_CSR_BASE_ADDR + 0x0e4)
++
++/* Internal Memory Access Write Data */
++#define TMU_MEM_ACCESS_WDATA  (TMU_CSR_BASE_ADDR + 0x0e8)
++/* Internal Memory Access Read Data. The commands are blocked
++ * at the mem_access only
++ */
++#define TMU_MEM_ACCESS_RDATA  (TMU_CSR_BASE_ADDR + 0x0ec)
++
++/* [31:0] PHY0 in queue address (must be initialized with one of the
++ * xxx_INQ_PKTPTR cbus addresses)
++ */
++#define TMU_PHY0_INQ_ADDR     (TMU_CSR_BASE_ADDR + 0x0f0)
++/* [31:0] PHY1 in queue address (must be initialized with one of the
++ * xxx_INQ_PKTPTR cbus addresses)
++ */
++#define TMU_PHY1_INQ_ADDR     (TMU_CSR_BASE_ADDR + 0x0f4)
++/* [31:0] PHY2 in queue address (must be initialized with one of the
++ * xxx_INQ_PKTPTR cbus addresses)
++ */
++#define TMU_PHY2_INQ_ADDR     (TMU_CSR_BASE_ADDR + 0x0f8)
++/* [31:0] PHY3 in queue address (must be initialized with one of the
++ * xxx_INQ_PKTPTR cbus addresses)
++ */
++#define TMU_PHY3_INQ_ADDR     (TMU_CSR_BASE_ADDR + 0x0fc)
++#define TMU_BMU_INQ_ADDR      (TMU_CSR_BASE_ADDR + 0x100)
++#define TMU_TX_CTRL   (TMU_CSR_BASE_ADDR + 0x104)
++
++#define TMU_BUS_ACCESS_WDATA  (TMU_CSR_BASE_ADDR + 0x108)
++#define TMU_BUS_ACCESS        (TMU_CSR_BASE_ADDR + 0x10c)
++#define TMU_BUS_ACCESS_RDATA  (TMU_CSR_BASE_ADDR + 0x110)
++
++#define TMU_PE_SYS_CLK_RATIO  (TMU_CSR_BASE_ADDR + 0x114)
++#define TMU_PE_STATUS (TMU_CSR_BASE_ADDR + 0x118)
++#define TMU_TEQ_MAX_THRESHOLD (TMU_CSR_BASE_ADDR + 0x11c)
++/* [31:0] PHY4 in queue address (must be initialized with one of the
++ * xxx_INQ_PKTPTR cbus addresses)
++ */
++#define TMU_PHY4_INQ_ADDR     (TMU_CSR_BASE_ADDR + 0x134)
++/* [9:0] Scheduler Enable for each of the scheduler in the TDQ.
++ * This is a global Enable for all schedulers in PHY1
++ */
++#define TMU_TDQ1_SCH_CTRL     (TMU_CSR_BASE_ADDR + 0x138)
++/* [9:0] Scheduler Enable for each of the scheduler in the TDQ.
++ * This is a global Enable for all schedulers in PHY2
++ */
++#define TMU_TDQ2_SCH_CTRL     (TMU_CSR_BASE_ADDR + 0x13c)
++/* [9:0] Scheduler Enable for each of the scheduler in the TDQ.
++ * This is a global Enable for all schedulers in PHY3
++ */
++#define TMU_TDQ3_SCH_CTRL     (TMU_CSR_BASE_ADDR + 0x140)
++#define TMU_BMU_BUF_SIZE      (TMU_CSR_BASE_ADDR + 0x144)
++/* [31:0] PHY5 in queue address (must be initialized with one of the
++ * xxx_INQ_PKTPTR cbus addresses)
++ */
++#define TMU_PHY5_INQ_ADDR     (TMU_CSR_BASE_ADDR + 0x148)
++
++#define SW_RESET              BIT(0)  /* Global software reset */
++#define INQ_RESET             BIT(2)
++#define TEQ_RESET             BIT(3)
++#define TDQ_RESET             BIT(4)
++#define PE_RESET              BIT(5)
++#define MEM_INIT              BIT(6)
++#define MEM_INIT_DONE         BIT(7)
++#define LLM_INIT              BIT(8)
++#define LLM_INIT_DONE         BIT(9)
++#define ECC_MEM_INIT_DONE     BIT(10)
++
++struct tmu_cfg {
++      u32 pe_sys_clk_ratio;
++      unsigned long llm_base_addr;
++      u32 llm_queue_len;
++};
++
++/* Not HW related for pfe_ctrl / pfe common defines */
++#define DEFAULT_MAX_QDEPTH    80
++#define DEFAULT_Q0_QDEPTH     511 /*We keep one large queue for host tx qos */
++#define DEFAULT_TMU3_QDEPTH   127
++
++#endif /* _TMU_CSR_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/include/pfe/cbus/util_csr.h
+@@ -0,0 +1,61 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _UTIL_CSR_H_
++#define _UTIL_CSR_H_
++
++#define UTIL_VERSION  (UTIL_CSR_BASE_ADDR + 0x000)
++#define UTIL_TX_CTRL  (UTIL_CSR_BASE_ADDR + 0x004)
++#define UTIL_INQ_PKTPTR       (UTIL_CSR_BASE_ADDR + 0x010)
++
++#define UTIL_HDR_SIZE (UTIL_CSR_BASE_ADDR + 0x014)
++
++#define UTIL_PE0_QB_DM_ADDR0  (UTIL_CSR_BASE_ADDR + 0x020)
++#define UTIL_PE0_QB_DM_ADDR1  (UTIL_CSR_BASE_ADDR + 0x024)
++#define UTIL_PE0_RO_DM_ADDR0  (UTIL_CSR_BASE_ADDR + 0x060)
++#define UTIL_PE0_RO_DM_ADDR1  (UTIL_CSR_BASE_ADDR + 0x064)
++
++#define UTIL_MEM_ACCESS_ADDR  (UTIL_CSR_BASE_ADDR + 0x100)
++#define UTIL_MEM_ACCESS_WDATA (UTIL_CSR_BASE_ADDR + 0x104)
++#define UTIL_MEM_ACCESS_RDATA (UTIL_CSR_BASE_ADDR + 0x108)
++
++#define UTIL_TM_INQ_ADDR      (UTIL_CSR_BASE_ADDR + 0x114)
++#define UTIL_PE_STATUS        (UTIL_CSR_BASE_ADDR + 0x118)
++
++#define UTIL_PE_SYS_CLK_RATIO (UTIL_CSR_BASE_ADDR + 0x200)
++#define UTIL_AFULL_THRES      (UTIL_CSR_BASE_ADDR + 0x204)
++#define UTIL_GAP_BETWEEN_READS        (UTIL_CSR_BASE_ADDR + 0x208)
++#define UTIL_MAX_BUF_CNT      (UTIL_CSR_BASE_ADDR + 0x20c)
++#define UTIL_TSQ_FIFO_THRES   (UTIL_CSR_BASE_ADDR + 0x210)
++#define UTIL_TSQ_MAX_CNT      (UTIL_CSR_BASE_ADDR + 0x214)
++#define UTIL_IRAM_DATA_0      (UTIL_CSR_BASE_ADDR + 0x218)
++#define UTIL_IRAM_DATA_1      (UTIL_CSR_BASE_ADDR + 0x21c)
++#define UTIL_IRAM_DATA_2      (UTIL_CSR_BASE_ADDR + 0x220)
++#define UTIL_IRAM_DATA_3      (UTIL_CSR_BASE_ADDR + 0x224)
++
++#define UTIL_BUS_ACCESS_ADDR  (UTIL_CSR_BASE_ADDR + 0x228)
++#define UTIL_BUS_ACCESS_WDATA (UTIL_CSR_BASE_ADDR + 0x22c)
++#define UTIL_BUS_ACCESS_RDATA (UTIL_CSR_BASE_ADDR + 0x230)
++
++#define UTIL_INQ_AFULL_THRES  (UTIL_CSR_BASE_ADDR + 0x234)
++
++struct util_cfg {
++      u32 pe_sys_clk_ratio;
++};
++
++#endif /* _UTIL_CSR_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/include/pfe/pfe.h
+@@ -0,0 +1,372 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _PFE_H_
++#define _PFE_H_
++
++#include "cbus.h"
++
++#define CLASS_DMEM_BASE_ADDR(i)       (0x00000000 | ((i) << 20))
++/*
++ * Only valid for mem access register interface
++ */
++#define CLASS_IMEM_BASE_ADDR(i)       (0x00000000 | ((i) << 20))
++#define CLASS_DMEM_SIZE       0x00002000
++#define CLASS_IMEM_SIZE       0x00008000
++
++#define TMU_DMEM_BASE_ADDR(i) (0x00000000 + ((i) << 20))
++/*
++ * Only valid for mem access register interface
++ */
++#define TMU_IMEM_BASE_ADDR(i) (0x00000000 + ((i) << 20))
++#define TMU_DMEM_SIZE 0x00000800
++#define TMU_IMEM_SIZE 0x00002000
++
++#define UTIL_DMEM_BASE_ADDR   0x00000000
++#define UTIL_DMEM_SIZE        0x00002000
++
++#define PE_LMEM_BASE_ADDR     0xc3010000
++#define PE_LMEM_SIZE  0x8000
++#define PE_LMEM_END   (PE_LMEM_BASE_ADDR + PE_LMEM_SIZE)
++
++#define DMEM_BASE_ADDR        0x00000000
++#define DMEM_SIZE     0x2000  /* TMU has less... */
++#define DMEM_END      (DMEM_BASE_ADDR + DMEM_SIZE)
++
++#define PMEM_BASE_ADDR        0x00010000
++#define PMEM_SIZE     0x8000  /* TMU has less... */
++#define PMEM_END      (PMEM_BASE_ADDR + PMEM_SIZE)
++
++/* These check memory ranges from PE point of view/memory map */
++#define IS_DMEM(addr, len)                            \
++      ({ typeof(addr) addr_ = (addr);                 \
++      ((unsigned long)(addr_) >= DMEM_BASE_ADDR) &&   \
++      (((unsigned long)(addr_) + (len)) <= DMEM_END); })
++
++#define IS_PMEM(addr, len)                            \
++      ({ typeof(addr) addr_ = (addr);                 \
++      ((unsigned long)(addr_) >= PMEM_BASE_ADDR) &&   \
++      (((unsigned long)(addr_) + (len)) <= PMEM_END); })
++
++#define IS_PE_LMEM(addr, len)                         \
++      ({ typeof(addr) addr_ = (addr);                 \
++      ((unsigned long)(addr_) >=                      \
++      PE_LMEM_BASE_ADDR) &&                           \
++      (((unsigned long)(addr_) +                      \
++      (len)) <= PE_LMEM_END); })
++
++#define IS_PFE_LMEM(addr, len)                                \
++      ({ typeof(addr) addr_ = (addr);                 \
++      ((unsigned long)(addr_) >=                      \
++      CBUS_VIRT_TO_PFE(LMEM_BASE_ADDR)) &&            \
++      (((unsigned long)(addr_) + (len)) <=            \
++      CBUS_VIRT_TO_PFE(LMEM_END)); })
++
++#define __IS_PHYS_DDR(addr, len)                      \
++      ({ typeof(addr) addr_ = (addr);                 \
++      ((unsigned long)(addr_) >=                      \
++      DDR_PHYS_BASE_ADDR) &&                          \
++      (((unsigned long)(addr_) + (len)) <=            \
++      DDR_PHYS_END); })
++
++#define IS_PHYS_DDR(addr, len)        __IS_PHYS_DDR(DDR_PFE_TO_PHYS(addr), len)
++
++/*
++ * If using a run-time virtual address for the cbus base address use this code
++ */
++extern void *cbus_base_addr;
++extern void *ddr_base_addr;
++extern unsigned long ddr_phys_base_addr;
++extern unsigned int ddr_size;
++
++#define CBUS_BASE_ADDR        cbus_base_addr
++#define DDR_PHYS_BASE_ADDR    ddr_phys_base_addr
++#define DDR_BASE_ADDR ddr_base_addr
++#define DDR_SIZE      ddr_size
++
++#define DDR_PHYS_END  (DDR_PHYS_BASE_ADDR + DDR_SIZE)
++
++#define LS1012A_PFE_RESET_WA  /*
++                               * PFE doesn't have global reset and re-init
++                               * should takecare few things to make PFE
++                               * functional after reset
++                               */
++#define PFE_CBUS_PHYS_BASE_ADDR       0xc0000000      /* CBUS physical base address
++                                               * as seen by PE's.
++                                               */
++/* CBUS physical base address as seen by PE's. */
++#define PFE_CBUS_PHYS_BASE_ADDR_FROM_PFE      0xc0000000
++
++#define DDR_PHYS_TO_PFE(p)    (((unsigned long int)(p)) & 0x7FFFFFFF)
++#define DDR_PFE_TO_PHYS(p)    (((unsigned long int)(p)) | 0x80000000)
++#define CBUS_PHYS_TO_PFE(p)   (((p) - PFE_CBUS_PHYS_BASE_ADDR) + \
++                              PFE_CBUS_PHYS_BASE_ADDR_FROM_PFE)
++/* Translates to PFE address map */
++
++#define DDR_PHYS_TO_VIRT(p)   (((p) - DDR_PHYS_BASE_ADDR) + DDR_BASE_ADDR)
++#define DDR_VIRT_TO_PHYS(v)   (((v) - DDR_BASE_ADDR) + DDR_PHYS_BASE_ADDR)
++#define DDR_VIRT_TO_PFE(p)    (DDR_PHYS_TO_PFE(DDR_VIRT_TO_PHYS(p)))
++
++#define CBUS_VIRT_TO_PFE(v)   (((v) - CBUS_BASE_ADDR) + \
++                              PFE_CBUS_PHYS_BASE_ADDR)
++#define CBUS_PFE_TO_VIRT(p)   (((unsigned long int)(p) - \
++                              PFE_CBUS_PHYS_BASE_ADDR) + CBUS_BASE_ADDR)
++
++/* The below part of the code is used in QOS control driver from host */
++#define TMU_APB_BASE_ADDR       0xc1000000      /* TMU base address seen by
++                                               * pe's
++                                               */
++
++enum {
++      CLASS0_ID = 0,
++      CLASS1_ID,
++      CLASS2_ID,
++      CLASS3_ID,
++      CLASS4_ID,
++      CLASS5_ID,
++      TMU0_ID,
++      TMU1_ID,
++      TMU2_ID,
++      TMU3_ID,
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      UTIL_ID,
++#endif
++      MAX_PE
++};
++
++#define CLASS_MASK    (BIT(CLASS0_ID) | BIT(CLASS1_ID) |\
++                      BIT(CLASS2_ID) | BIT(CLASS3_ID) |\
++                      BIT(CLASS4_ID) | BIT(CLASS5_ID))
++#define CLASS_MAX_ID  CLASS5_ID
++
++#define TMU_MASK      (BIT(TMU0_ID) | BIT(TMU1_ID) |\
++                      BIT(TMU3_ID))
++
++#define TMU_MAX_ID    TMU3_ID
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++#define UTIL_MASK     BIT(UTIL_ID)
++#endif
++
++struct pe_status {
++      u32     cpu_state;
++      u32     activity_counter;
++      u32     rx;
++      union {
++      u32     tx;
++      u32     tmu_qstatus;
++      };
++      u32     drop;
++#if defined(CFG_PE_DEBUG)
++      u32     debug_indicator;
++      u32     debug[16];
++#endif
++} __aligned(16);
++
++struct pe_sync_mailbox {
++      u32 stop;
++      u32 stopped;
++};
++
++/* Drop counter definitions */
++
++#define       CLASS_NUM_DROP_COUNTERS 13
++#define       UTIL_NUM_DROP_COUNTERS  8
++
++/* PE information.
++ * Structure containing PE's specific information. It is used to create
++ * generic C functions common to all PE's.
++ * Before using the library functions this structure needs to be initialized
++ * with the different registers virtual addresses
++ * (according to the ARM MMU mmaping). The default initialization supports a
++ * virtual == physical mapping.
++ */
++struct pe_info {
++      u32 dmem_base_addr;     /* PE's dmem base address */
++      u32 pmem_base_addr;     /* PE's pmem base address */
++      u32 pmem_size;  /* PE's pmem size */
++
++      void *mem_access_wdata; /* PE's _MEM_ACCESS_WDATA register
++                               * address
++                               */
++      void *mem_access_addr;  /* PE's _MEM_ACCESS_ADDR register
++                               * address
++                               */
++      void *mem_access_rdata; /* PE's _MEM_ACCESS_RDATA register
++                               * address
++                               */
++};
++
++void pe_lmem_read(u32 *dst, u32 len, u32 offset);
++void pe_lmem_write(u32 *src, u32 len, u32 offset);
++
++void pe_dmem_memcpy_to32(int id, u32 dst, const void *src, unsigned int len);
++void pe_pmem_memcpy_to32(int id, u32 dst, const void *src, unsigned int len);
++
++u32 pe_pmem_read(int id, u32 addr, u8 size);
++
++void pe_dmem_write(int id, u32 val, u32 addr, u8 size);
++u32 pe_dmem_read(int id, u32 addr, u8 size);
++void class_pe_lmem_memcpy_to32(u32 dst, const void *src, unsigned int len);
++void class_pe_lmem_memset(u32 dst, int val, unsigned int len);
++void class_bus_write(u32 val, u32 addr, u8 size);
++u32 class_bus_read(u32 addr, u8 size);
++
++#define class_bus_readl(addr) class_bus_read(addr, 4)
++#define class_bus_readw(addr) class_bus_read(addr, 2)
++#define class_bus_readb(addr) class_bus_read(addr, 1)
++
++#define class_bus_writel(val, addr)   class_bus_write(val, addr, 4)
++#define class_bus_writew(val, addr)   class_bus_write(val, addr, 2)
++#define class_bus_writeb(val, addr)   class_bus_write(val, addr, 1)
++
++#define pe_dmem_readl(id, addr)       pe_dmem_read(id, addr, 4)
++#define pe_dmem_readw(id, addr)       pe_dmem_read(id, addr, 2)
++#define pe_dmem_readb(id, addr)       pe_dmem_read(id, addr, 1)
++
++#define pe_dmem_writel(id, val, addr) pe_dmem_write(id, val, addr, 4)
++#define pe_dmem_writew(id, val, addr) pe_dmem_write(id, val, addr, 2)
++#define pe_dmem_writeb(id, val, addr) pe_dmem_write(id, val, addr, 1)
++
++/*int pe_load_elf_section(int id, const void *data, elf32_shdr *shdr); */
++int pe_load_elf_section(int id, const void *data, struct elf32_shdr *shdr,
++                      struct device *dev);
++
++void pfe_lib_init(void *cbus_base, void *ddr_base, unsigned long ddr_phys_base,
++                unsigned int ddr_size);
++void bmu_init(void *base, struct BMU_CFG *cfg);
++void bmu_reset(void *base);
++void bmu_enable(void *base);
++void bmu_disable(void *base);
++void bmu_set_config(void *base, struct BMU_CFG *cfg);
++
++/*
++ * An enumerated type for loopback values.  This can be one of three values, no
++ * loopback -normal operation, local loopback with internal loopback module of
++ * MAC or PHY loopback which is through the external PHY.
++ */
++#ifndef __MAC_LOOP_ENUM__
++#define __MAC_LOOP_ENUM__
++enum mac_loop {LB_NONE, LB_EXT, LB_LOCAL};
++#endif
++
++void gemac_init(void *base, void *config);
++void gemac_disable_rx_checksum_offload(void *base);
++void gemac_enable_rx_checksum_offload(void *base);
++void gemac_set_mdc_div(void *base, int mdc_div);
++void gemac_set_speed(void *base, enum mac_speed gem_speed);
++void gemac_set_duplex(void *base, int duplex);
++void gemac_set_mode(void *base, int mode);
++void gemac_enable(void *base);
++void gemac_tx_disable(void *base);
++void gemac_tx_enable(void *base);
++void gemac_disable(void *base);
++void gemac_reset(void *base);
++void gemac_set_address(void *base, struct spec_addr *addr);
++struct spec_addr gemac_get_address(void *base);
++void gemac_set_loop(void *base, enum mac_loop gem_loop);
++void gemac_set_laddr1(void *base, struct pfe_mac_addr *address);
++void gemac_set_laddr2(void *base, struct pfe_mac_addr *address);
++void gemac_set_laddr3(void *base, struct pfe_mac_addr *address);
++void gemac_set_laddr4(void *base, struct pfe_mac_addr *address);
++void gemac_set_laddrN(void *base, struct pfe_mac_addr *address,
++                    unsigned int entry_index);
++void gemac_clear_laddr1(void *base);
++void gemac_clear_laddr2(void *base);
++void gemac_clear_laddr3(void *base);
++void gemac_clear_laddr4(void *base);
++void gemac_clear_laddrN(void *base, unsigned int entry_index);
++struct pfe_mac_addr gemac_get_hash(void *base);
++void gemac_set_hash(void *base, struct pfe_mac_addr *hash);
++struct pfe_mac_addr gem_get_laddr1(void *base);
++struct pfe_mac_addr gem_get_laddr2(void *base);
++struct pfe_mac_addr gem_get_laddr3(void *base);
++struct pfe_mac_addr gem_get_laddr4(void *base);
++struct pfe_mac_addr gem_get_laddrN(void *base, unsigned int entry_index);
++void gemac_set_config(void *base, struct gemac_cfg *cfg);
++void gemac_allow_broadcast(void *base);
++void gemac_no_broadcast(void *base);
++void gemac_enable_1536_rx(void *base);
++void gemac_disable_1536_rx(void *base);
++void gemac_enable_rx_jmb(void *base);
++void gemac_disable_rx_jmb(void *base);
++void gemac_enable_stacked_vlan(void *base);
++void gemac_disable_stacked_vlan(void *base);
++void gemac_enable_pause_rx(void *base);
++void gemac_disable_pause_rx(void *base);
++void gemac_enable_copy_all(void *base);
++void gemac_disable_copy_all(void *base);
++void gemac_set_bus_width(void *base, int width);
++void gemac_set_wol(void *base, u32 wol_conf);
++
++void gpi_init(void *base, struct gpi_cfg *cfg);
++void gpi_reset(void *base);
++void gpi_enable(void *base);
++void gpi_disable(void *base);
++void gpi_set_config(void *base, struct gpi_cfg *cfg);
++
++void class_init(struct class_cfg *cfg);
++void class_reset(void);
++void class_enable(void);
++void class_disable(void);
++void class_set_config(struct class_cfg *cfg);
++
++void tmu_reset(void);
++void tmu_init(struct tmu_cfg *cfg);
++void tmu_enable(u32 pe_mask);
++void tmu_disable(u32 pe_mask);
++u32  tmu_qstatus(u32 if_id);
++u32  tmu_pkts_processed(u32 if_id);
++
++void util_init(struct util_cfg *cfg);
++void util_reset(void);
++void util_enable(void);
++void util_disable(void);
++
++void hif_init(void);
++void hif_tx_enable(void);
++void hif_tx_disable(void);
++void hif_rx_enable(void);
++void hif_rx_disable(void);
++
++/* Get Chip Revision level
++ *
++ */
++static inline unsigned int CHIP_REVISION(void)
++{
++      /*For LS1012A return always 1 */
++      return 1;
++}
++
++/* Start HIF rx DMA
++ *
++ */
++static inline void hif_rx_dma_start(void)
++{
++      writel(HIF_CTRL_DMA_EN | HIF_CTRL_BDP_CH_START_WSTB, HIF_RX_CTRL);
++}
++
++/* Start HIF tx DMA
++ *
++ */
++static inline void hif_tx_dma_start(void)
++{
++      writel(HIF_CTRL_DMA_EN | HIF_CTRL_BDP_CH_START_WSTB, HIF_TX_CTRL);
++}
++
++#endif /* _PFE_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_ctrl.h
+@@ -0,0 +1,112 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _PFE_CTRL_H_
++#define _PFE_CTRL_H_
++
++#include <linux/dmapool.h>
++
++#include "pfe_mod.h"
++#include "pfe/pfe.h"
++
++#define DMA_BUF_SIZE_128      0x80    /* enough for 1 conntracks */
++#define DMA_BUF_SIZE_256      0x100
++/* enough for 2 conntracks, 1 bridge entry or 1 multicast entry */
++#define DMA_BUF_SIZE_512      0x200
++/* 512bytes dma allocated buffers used by rtp relay feature */
++#define DMA_BUF_MIN_ALIGNMENT 8
++#define DMA_BUF_BOUNDARY      (4 * 1024)
++/* bursts can not cross 4k boundary */
++
++#define CMD_TX_ENABLE 0x0501
++#define CMD_TX_DISABLE        0x0502
++
++#define CMD_RX_LRO            0x0011
++#define CMD_PKTCAP_ENABLE       0x0d01
++#define CMD_QM_EXPT_RATE      0x020c
++
++#define CLASS_DM_SH_STATIC            (0x800)
++#define CLASS_DM_CPU_TICKS            (CLASS_DM_SH_STATIC)
++#define CLASS_DM_SYNC_MBOX            (0x808)
++#define CLASS_DM_MSG_MBOX             (0x810)
++#define CLASS_DM_DROP_CNTR            (0x820)
++#define CLASS_DM_RESUME                       (0x854)
++#define CLASS_DM_PESTATUS             (0x860)
++
++#define TMU_DM_SH_STATIC              (0x80)
++#define TMU_DM_CPU_TICKS              (TMU_DM_SH_STATIC)
++#define TMU_DM_SYNC_MBOX              (0x88)
++#define TMU_DM_MSG_MBOX                       (0x90)
++#define TMU_DM_RESUME                 (0xA0)
++#define TMU_DM_PESTATUS                       (0xB0)
++#define TMU_DM_CONTEXT                        (0x300)
++#define TMU_DM_TX_TRANS                       (0x480)
++
++#define UTIL_DM_SH_STATIC             (0x0)
++#define UTIL_DM_CPU_TICKS             (UTIL_DM_SH_STATIC)
++#define UTIL_DM_SYNC_MBOX             (0x8)
++#define UTIL_DM_MSG_MBOX              (0x10)
++#define UTIL_DM_DROP_CNTR             (0x20)
++#define UTIL_DM_RESUME                        (0x40)
++#define UTIL_DM_PESTATUS              (0x50)
++
++struct pfe_ctrl {
++      struct mutex mutex; /* to serialize pfe control access */
++      spinlock_t lock;
++
++      void *dma_pool;
++      void *dma_pool_512;
++      void *dma_pool_128;
++
++      struct device *dev;
++
++      void *hash_array_baseaddr;              /*
++                                               * Virtual base address of
++                                               * the conntrack hash array
++                                               */
++      unsigned long hash_array_phys_baseaddr; /*
++                                               * Physical base address of
++                                               * the conntrack hash array
++                                               */
++
++      int (*event_cb)(u16, u16, u16*);
++
++      unsigned long sync_mailbox_baseaddr[MAX_PE]; /*
++                                                    * Sync mailbox PFE
++                                                    * internal address,
++                                                    * initialized
++                                                    * when parsing elf images
++                                                    */
++      unsigned long msg_mailbox_baseaddr[MAX_PE]; /*
++                                                   * Msg mailbox PFE internal
++                                                   * address, initialized
++                                                   * when parsing elf images
++                                                   */
++      unsigned int sys_clk;                   /* AXI clock value, in KHz */
++};
++
++int pfe_ctrl_init(struct pfe *pfe);
++void pfe_ctrl_exit(struct pfe *pfe);
++int pe_sync_stop(struct pfe_ctrl *ctrl, int pe_mask);
++void pe_start(struct pfe_ctrl *ctrl, int pe_mask);
++int pe_reset_all(struct pfe_ctrl *ctrl);
++void pfe_ctrl_suspend(struct pfe_ctrl *ctrl);
++void pfe_ctrl_resume(struct pfe_ctrl *ctrl);
++int relax(unsigned long end);
++
++#endif /* _PFE_CTRL_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_debugfs.h
+@@ -0,0 +1,25 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _PFE_DEBUGFS_H_
++#define _PFE_DEBUGFS_H_
++
++int pfe_debugfs_init(struct pfe *pfe);
++void pfe_debugfs_exit(struct pfe *pfe);
++
++#endif /* _PFE_DEBUGFS_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_eth.h
+@@ -0,0 +1,184 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _PFE_ETH_H_
++#define _PFE_ETH_H_
++#include <linux/kernel.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/phy.h>
++#include <linux/clk.h>
++#include <linux/interrupt.h>
++#include <linux/time.h>
++
++#define PFE_ETH_NAPI_STATS
++#define PFE_ETH_TX_STATS
++
++#define PFE_ETH_FRAGS_MAX (65536 / HIF_RX_PKT_MIN_SIZE)
++#define LRO_LEN_COUNT_MAX     32
++#define LRO_NB_COUNT_MAX      32
++
++#define PFE_PAUSE_FLAG_ENABLE         1
++#define PFE_PAUSE_FLAG_AUTONEG                2
++
++/* GEMAC configured by SW */
++/* GEMAC configured by phy lines (not for MII/GMII) */
++
++#define GEMAC_SW_FULL_DUPLEX    BIT(9)
++#define GEMAC_SW_SPEED_10M      (0 << 12)
++#define GEMAC_SW_SPEED_100M     BIT(12)
++#define GEMAC_SW_SPEED_1G       (2 << 12)
++
++#define GEMAC_NO_PHY            BIT(0)
++
++struct ls1012a_eth_platform_data {
++      /* device specific information */
++      u32 device_flags;
++      char name[16];
++
++      /* board specific information */
++      u32 mii_config;
++      u32 phy_flags;
++      u32 gem_id;
++      u32 bus_id;
++      u32 phy_id;
++      u32 mdio_muxval;
++      u8 mac_addr[ETH_ALEN];
++};
++
++struct ls1012a_mdio_platform_data {
++      int enabled;
++      int irq[32];
++      u32 phy_mask;
++      int mdc_div;
++};
++
++struct ls1012a_pfe_platform_data {
++      struct ls1012a_eth_platform_data ls1012a_eth_pdata[3];
++      struct ls1012a_mdio_platform_data ls1012a_mdio_pdata[3];
++};
++
++#define NUM_GEMAC_SUPPORT     2
++#define DRV_NAME              "pfe-eth"
++#define DRV_VERSION           "1.0"
++
++#define LS1012A_TX_FAST_RECOVERY_TIMEOUT_MS   3
++#define TX_POLL_TIMEOUT_MS    1000
++
++#define EMAC_TXQ_CNT  16
++#define EMAC_TXQ_DEPTH        (HIF_TX_DESC_NT)
++
++#define JUMBO_FRAME_SIZE      10258
++/*
++ * Client Tx queue threshold, for txQ flush condition.
++ * It must be smaller than the queue size (in case we ever change it in the
++ * future).
++ */
++#define HIF_CL_TX_FLUSH_MARK  32
++
++/*
++ * Max number of TX resources (HIF descriptors or skbs) that will be released
++ * in a single go during batch recycling.
++ * Should be lower than the flush mark so the SW can provide the HW with a
++ * continuous stream of packets instead of bursts.
++ */
++#define TX_FREE_MAX_COUNT 16
++#define EMAC_RXQ_CNT  3
++#define EMAC_RXQ_DEPTH        HIF_RX_DESC_NT
++/* make sure clients can receive a full burst of packets */
++#define EMAC_RMON_TXBYTES_POS 0x00
++#define EMAC_RMON_RXBYTES_POS 0x14
++
++#define EMAC_QUEUENUM_MASK      (emac_txq_cnt - 1)
++#define EMAC_MDIO_TIMEOUT     1000
++#define MAX_UC_SPEC_ADDR_REG 31
++
++struct pfe_eth_fast_timer {
++      int queuenum;
++      struct hrtimer timer;
++      void *base;
++};
++
++struct  pfe_eth_priv_s {
++      struct pfe              *pfe;
++      struct hif_client_s     client;
++      struct napi_struct      lro_napi;
++      struct napi_struct      low_napi;
++      struct napi_struct      high_napi;
++      int                     low_tmu_q;
++      int                     high_tmu_q;
++      struct net_device_stats stats;
++      struct net_device       *ndev;
++      int                     id;
++      int                     promisc;
++      unsigned int            msg_enable;
++      unsigned int            usr_features;
++
++      spinlock_t              lock; /* protect member variables */
++      unsigned int            event_status;
++      int                     irq;
++      void                    *EMAC_baseaddr;
++      /* This points to the EMAC base from where we access PHY */
++      void                    *PHY_baseaddr;
++      void                    *GPI_baseaddr;
++      /* PHY stuff */
++      struct phy_device       *phydev;
++      int                     oldspeed;
++      int                     oldduplex;
++      int                     oldlink;
++      /* mdio info */
++      int                     mdc_div;
++      struct mii_bus          *mii_bus;
++      struct clk              *gemtx_clk;
++      int                     wol;
++      int                     pause_flag;
++
++      int                     default_priority;
++      struct pfe_eth_fast_timer fast_tx_timeout[EMAC_TXQ_CNT];
++
++      struct ls1012a_eth_platform_data *einfo;
++      struct sk_buff *skb_inflight[EMAC_RXQ_CNT + 6];
++
++#ifdef PFE_ETH_TX_STATS
++      unsigned int stop_queue_total[EMAC_TXQ_CNT];
++      unsigned int stop_queue_hif[EMAC_TXQ_CNT];
++      unsigned int stop_queue_hif_client[EMAC_TXQ_CNT];
++      unsigned int stop_queue_credit[EMAC_TXQ_CNT];
++      unsigned int clean_fail[EMAC_TXQ_CNT];
++      unsigned int was_stopped[EMAC_TXQ_CNT];
++#endif
++
++#ifdef PFE_ETH_NAPI_STATS
++      unsigned int napi_counters[NAPI_MAX_COUNT];
++#endif
++      unsigned int frags_inflight[EMAC_RXQ_CNT + 6];
++};
++
++struct pfe_eth {
++      struct pfe_eth_priv_s *eth_priv[3];
++};
++
++int pfe_eth_init(struct pfe *pfe);
++void pfe_eth_exit(struct pfe *pfe);
++int pfe_eth_suspend(struct net_device *dev);
++int pfe_eth_resume(struct net_device *dev);
++int pfe_eth_mdio_reset(struct mii_bus *bus);
++
++#endif /* _PFE_ETH_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_firmware.h
+@@ -0,0 +1,32 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _PFE_FIRMWARE_H_
++#define _PFE_FIRMWARE_H_
++
++#define CLASS_FIRMWARE_FILENAME               "ppfe_class_ls1012a.elf"
++#define TMU_FIRMWARE_FILENAME         "ppfe_tmu_ls1012a.elf"
++
++#define PFE_FW_CHECK_PASS             0
++#define PFE_FW_CHECK_FAIL             1
++#define NUM_PFE_FW                            3
++
++int pfe_firmware_init(struct pfe *pfe);
++void pfe_firmware_exit(struct pfe *pfe);
++
++#endif /* _PFE_FIRMWARE_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_hif.h
+@@ -0,0 +1,211 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _PFE_HIF_H_
++#define _PFE_HIF_H_
++
++#include <linux/netdevice.h>
++
++#define HIF_NAPI_STATS
++
++#define HIF_CLIENT_QUEUES_MAX 16
++#define HIF_RX_POLL_WEIGHT    64
++
++#define HIF_RX_PKT_MIN_SIZE 0x800 /* 2KB */
++#define HIF_RX_PKT_MIN_SIZE_MASK ~(HIF_RX_PKT_MIN_SIZE - 1)
++#define ROUND_MIN_RX_SIZE(_sz) (((_sz) + (HIF_RX_PKT_MIN_SIZE - 1)) \
++                                      & HIF_RX_PKT_MIN_SIZE_MASK)
++#define PRESENT_OFST_IN_PAGE(_buf) (((unsigned long int)(_buf) & (PAGE_SIZE \
++                                      - 1)) & HIF_RX_PKT_MIN_SIZE_MASK)
++
++enum {
++      NAPI_SCHED_COUNT = 0,
++      NAPI_POLL_COUNT,
++      NAPI_PACKET_COUNT,
++      NAPI_DESC_COUNT,
++      NAPI_FULL_BUDGET_COUNT,
++      NAPI_CLIENT_FULL_COUNT,
++      NAPI_MAX_COUNT
++};
++
++/*
++ * HIF_TX_DESC_NT value should be always greter than 4,
++ * Otherwise HIF_TX_POLL_MARK will become zero.
++ */
++#define HIF_RX_DESC_NT                256
++#define HIF_TX_DESC_NT                2048
++
++#define HIF_FIRST_BUFFER      BIT(0)
++#define HIF_LAST_BUFFER               BIT(1)
++#define HIF_DONT_DMA_MAP      BIT(2)
++#define HIF_DATA_VALID                BIT(3)
++#define HIF_TSO                       BIT(4)
++
++enum {
++      PFE_CL_GEM0 = 0,
++      PFE_CL_GEM1,
++      HIF_CLIENTS_MAX
++};
++
++/*structure to store client queue info */
++struct hif_rx_queue {
++      struct rx_queue_desc *base;
++      u32     size;
++      u32     write_idx;
++};
++
++struct hif_tx_queue {
++      struct tx_queue_desc *base;
++      u32     size;
++      u32     ack_idx;
++};
++
++/*Structure to store the client info */
++struct hif_client {
++      int     rx_qn;
++      struct hif_rx_queue     rx_q[HIF_CLIENT_QUEUES_MAX];
++      int     tx_qn;
++      struct hif_tx_queue     tx_q[HIF_CLIENT_QUEUES_MAX];
++};
++
++/*HIF hardware buffer descriptor */
++struct hif_desc {
++      u32 ctrl;
++      u32 status;
++      u32 data;
++      u32 next;
++};
++
++struct __hif_desc {
++      u32 ctrl;
++      u32 status;
++      u32 data;
++};
++
++struct hif_desc_sw {
++      dma_addr_t data;
++      u16 len;
++      u8 client_id;
++      u8 q_no;
++      u16 flags;
++};
++
++struct hif_hdr {
++      u8 client_id;
++      u8 q_num;
++      u16 client_ctrl;
++      u16 client_ctrl1;
++};
++
++struct __hif_hdr {
++      union {
++              struct hif_hdr hdr;
++              u32 word[2];
++      };
++};
++
++struct hif_ipsec_hdr {
++      u16     sa_handle[2];
++} __packed;
++
++/*  HIF_CTRL_TX... defines */
++#define HIF_CTRL_TX_CHECKSUM          BIT(2)
++
++/*  HIF_CTRL_RX... defines */
++#define HIF_CTRL_RX_OFFSET_OFST         (24)
++#define HIF_CTRL_RX_CHECKSUMMED               BIT(2)
++#define HIF_CTRL_RX_CONTINUED         BIT(1)
++
++struct pfe_hif {
++      /* To store registered clients in hif layer */
++      struct hif_client client[HIF_CLIENTS_MAX];
++      struct hif_shm *shm;
++      int     irq;
++
++      void    *descr_baseaddr_v;
++      unsigned long   descr_baseaddr_p;
++
++      struct hif_desc *rx_base;
++      u32     rx_ring_size;
++      u32     rxtoclean_index;
++      void    *rx_buf_addr[HIF_RX_DESC_NT];
++      int     rx_buf_len[HIF_RX_DESC_NT];
++      unsigned int qno;
++      unsigned int client_id;
++      unsigned int client_ctrl;
++      unsigned int started;
++
++      struct hif_desc *tx_base;
++      u32     tx_ring_size;
++      u32     txtosend;
++      u32     txtoclean;
++      u32     txavail;
++      u32     txtoflush;
++      struct hif_desc_sw tx_sw_queue[HIF_TX_DESC_NT];
++
++/* tx_lock synchronizes hif packet tx as well as pfe_hif structure access */
++      spinlock_t tx_lock;
++/* lock synchronizes hif rx queue processing */
++      spinlock_t lock;
++      struct net_device       dummy_dev;
++      struct napi_struct      napi;
++      struct device *dev;
++
++#ifdef HIF_NAPI_STATS
++      unsigned int napi_counters[NAPI_MAX_COUNT];
++#endif
++      struct tasklet_struct   tx_cleanup_tasklet;
++};
++
++void __hif_xmit_pkt(struct pfe_hif *hif, unsigned int client_id, unsigned int
++                      q_no, void *data, u32 len, unsigned int flags);
++int hif_xmit_pkt(struct pfe_hif *hif, unsigned int client_id, unsigned int q_no,
++               void *data, unsigned int len);
++void __hif_tx_done_process(struct pfe_hif *hif, int count);
++void hif_process_client_req(struct pfe_hif *hif, int req, int data1, int
++                              data2);
++int pfe_hif_init(struct pfe *pfe);
++void pfe_hif_exit(struct pfe *pfe);
++void pfe_hif_rx_idle(struct pfe_hif *hif);
++static inline void hif_tx_done_process(struct pfe_hif *hif, int count)
++{
++      spin_lock_bh(&hif->tx_lock);
++      __hif_tx_done_process(hif, count);
++      spin_unlock_bh(&hif->tx_lock);
++}
++
++static inline void hif_tx_lock(struct pfe_hif *hif)
++{
++      spin_lock_bh(&hif->tx_lock);
++}
++
++static inline void hif_tx_unlock(struct pfe_hif *hif)
++{
++      spin_unlock_bh(&hif->tx_lock);
++}
++
++static inline int __hif_tx_avail(struct pfe_hif *hif)
++{
++      return hif->txavail;
++}
++
++#define __memcpy8(dst, src)           memcpy(dst, src, 8)
++#define __memcpy12(dst, src)          memcpy(dst, src, 12)
++#define __memcpy(dst, src, len)               memcpy(dst, src, len)
++
++#endif /* _PFE_HIF_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_hif_lib.h
+@@ -0,0 +1,239 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _PFE_HIF_LIB_H_
++#define _PFE_HIF_LIB_H_
++
++#include "pfe_hif.h"
++
++#define HIF_CL_REQ_TIMEOUT    10
++#define GFP_DMA_PFE 0
++
++enum {
++      REQUEST_CL_REGISTER = 0,
++      REQUEST_CL_UNREGISTER,
++      HIF_REQUEST_MAX
++};
++
++enum {
++      /* Event to indicate that client rx queue is reached water mark level */
++      EVENT_HIGH_RX_WM = 0,
++      /* Event to indicate that, packet received for client */
++      EVENT_RX_PKT_IND,
++      /* Event to indicate that, packet tx done for client */
++      EVENT_TXDONE_IND,
++      HIF_EVENT_MAX
++};
++
++/*structure to store client queue info */
++
++/*structure to store client queue info */
++struct hif_client_rx_queue {
++      struct rx_queue_desc *base;
++      u32     size;
++      u32     read_idx;
++      u32     write_idx;
++};
++
++struct hif_client_tx_queue {
++      struct tx_queue_desc *base;
++      u32     size;
++      u32     read_idx;
++      u32     write_idx;
++      u32     tx_pending;
++      unsigned long jiffies_last_packet;
++      u32     nocpy_flag;
++      u32     prev_tmu_tx_pkts;
++      u32     done_tmu_tx_pkts;
++};
++
++struct hif_client_s {
++      int     id;
++      int     tx_qn;
++      int     rx_qn;
++      void    *rx_qbase;
++      void    *tx_qbase;
++      int     tx_qsize;
++      int     rx_qsize;
++      int     cpu_id;
++      struct hif_client_tx_queue tx_q[HIF_CLIENT_QUEUES_MAX];
++      struct hif_client_rx_queue rx_q[HIF_CLIENT_QUEUES_MAX];
++      int (*event_handler)(void *priv, int event, int data);
++      unsigned long queue_mask[HIF_EVENT_MAX];
++      struct pfe *pfe;
++      void *priv;
++};
++
++/*
++ * Client specific shared memory
++ * It contains number of Rx/Tx queues, base addresses and queue sizes
++ */
++struct hif_client_shm {
++      u32 ctrl; /*0-7: number of Rx queues, 8-15: number of tx queues */
++      unsigned long rx_qbase; /*Rx queue base address */
++      u32 rx_qsize; /*each Rx queue size, all Rx queues are of same size */
++      unsigned long tx_qbase; /* Tx queue base address */
++      u32 tx_qsize; /*each Tx queue size, all Tx queues are of same size */
++};
++
++/*Client shared memory ctrl bit description */
++#define CLIENT_CTRL_RX_Q_CNT_OFST     0
++#define CLIENT_CTRL_TX_Q_CNT_OFST     8
++#define CLIENT_CTRL_RX_Q_CNT(ctrl)    (((ctrl) >> CLIENT_CTRL_RX_Q_CNT_OFST) \
++                                              & 0xFF)
++#define CLIENT_CTRL_TX_Q_CNT(ctrl)    (((ctrl) >> CLIENT_CTRL_TX_Q_CNT_OFST) \
++                                              & 0xFF)
++
++/*
++ * Shared memory used to communicate between HIF driver and host/client drivers
++ * Before starting the hif driver rx_buf_pool ans rx_buf_pool_cnt should be
++ * initialized with host buffers and buffers count in the pool.
++ * rx_buf_pool_cnt should be >= HIF_RX_DESC_NT.
++ *
++ */
++struct hif_shm {
++      u32 rx_buf_pool_cnt; /*Number of rx buffers available*/
++      /*Rx buffers required to initialize HIF rx descriptors */
++      void *rx_buf_pool[HIF_RX_DESC_NT];
++      unsigned long g_client_status[2]; /*Global client status bit mask */
++      /* Client specific shared memory */
++      struct hif_client_shm client[HIF_CLIENTS_MAX];
++};
++
++#define CL_DESC_OWN   BIT(31)
++/* This sets owner ship to HIF driver */
++#define CL_DESC_LAST  BIT(30)
++/* This indicates last packet for multi buffers handling */
++#define CL_DESC_FIRST BIT(29)
++/* This indicates first packet for multi buffers handling */
++
++#define CL_DESC_BUF_LEN(x)            ((x) & 0xFFFF)
++#define CL_DESC_FLAGS(x)              (((x) & 0xF) << 16)
++#define CL_DESC_GET_FLAGS(x)          (((x) >> 16) & 0xF)
++
++struct rx_queue_desc {
++      void *data;
++      u32     ctrl; /*0-15bit len, 16-20bit flags, 31bit owner*/
++      u32     client_ctrl;
++};
++
++struct tx_queue_desc {
++      void *data;
++      u32     ctrl; /*0-15bit len, 16-20bit flags, 31bit owner*/
++};
++
++/* HIF Rx is not working properly for 2-byte aligned buffers and
++ * ip_header should be 4byte aligned for better iperformance.
++ * "ip_header = 64 + 6(hif_header) + 14 (MAC Header)" will be 4byte aligned.
++ */
++#define PFE_PKT_HEADER_SZ     sizeof(struct hif_hdr)
++/* must be big enough for headroom, pkt size and skb shared info */
++#define PFE_BUF_SIZE          2048
++#define PFE_PKT_HEADROOM      128
++
++#define SKB_SHARED_INFO_SIZE   (sizeof(struct skb_shared_info))
++#define PFE_PKT_SIZE          (PFE_BUF_SIZE - PFE_PKT_HEADROOM \
++                               - SKB_SHARED_INFO_SIZE)
++#define MAX_L2_HDR_SIZE               14      /* Not correct for VLAN/PPPoE */
++#define MAX_L3_HDR_SIZE               20      /* Not correct for IPv6 */
++#define MAX_L4_HDR_SIZE               60      /* TCP with maximum options */
++#define MAX_HDR_SIZE          (MAX_L2_HDR_SIZE + MAX_L3_HDR_SIZE \
++                               + MAX_L4_HDR_SIZE)
++/* Used in page mode to clamp packet size to the maximum supported by the hif
++ *hw interface (<16KiB)
++ */
++#define MAX_PFE_PKT_SIZE      16380UL
++
++extern unsigned int pfe_pkt_size;
++extern unsigned int pfe_pkt_headroom;
++extern unsigned int page_mode;
++extern unsigned int lro_mode;
++extern unsigned int tx_qos;
++extern unsigned int emac_txq_cnt;
++
++int pfe_hif_lib_init(struct pfe *pfe);
++void pfe_hif_lib_exit(struct pfe *pfe);
++int hif_lib_client_register(struct hif_client_s *client);
++int hif_lib_client_unregister(struct  hif_client_s *client);
++void __hif_lib_xmit_pkt(struct hif_client_s *client, unsigned int qno, void
++                              *data, unsigned int len, u32 client_ctrl,
++                              unsigned int flags, void *client_data);
++int hif_lib_xmit_pkt(struct hif_client_s *client, unsigned int qno, void *data,
++                   unsigned int len, u32 client_ctrl, void *client_data);
++void hif_lib_indicate_client(int cl_id, int event, int data);
++int hif_lib_event_handler_start(struct hif_client_s *client, int event, int
++                                      data);
++int hif_lib_tmu_queue_start(struct hif_client_s *client, int qno);
++int hif_lib_tmu_queue_stop(struct hif_client_s *client, int qno);
++void *hif_lib_tx_get_next_complete(struct hif_client_s *client, int qno,
++                                 unsigned int *flags, int count);
++void *hif_lib_receive_pkt(struct hif_client_s *client, int qno, int *len, int
++                              *ofst, unsigned int *rx_ctrl,
++                              unsigned int *desc_ctrl, void **priv_data);
++void hif_lib_set_rx_cpu_affinity(struct hif_client_s *client, int cpu_id);
++void hif_lib_set_tx_queue_nocpy(struct hif_client_s *client, int qno, int
++                                      enable);
++static inline int hif_lib_tx_avail(struct hif_client_s *client, unsigned int
++                                      qno)
++{
++      struct hif_client_tx_queue *queue = &client->tx_q[qno];
++
++      return (queue->size - queue->tx_pending);
++}
++
++static inline int hif_lib_get_tx_wr_index(struct hif_client_s *client, unsigned
++                                              int qno)
++{
++      struct hif_client_tx_queue *queue = &client->tx_q[qno];
++
++      return queue->write_idx;
++}
++
++static inline int hif_lib_tx_pending(struct hif_client_s *client, unsigned int
++                                      qno)
++{
++      struct hif_client_tx_queue *queue = &client->tx_q[qno];
++
++      return queue->tx_pending;
++}
++
++#define hif_lib_tx_credit_avail(pfe, id, qno) \
++                              ((pfe)->tmu_credit.tx_credit[id][qno])
++
++#define hif_lib_tx_credit_max(pfe, id, qno) \
++                              ((pfe)->tmu_credit.tx_credit_max[id][qno])
++
++/*
++ * Test comment
++ */
++#define hif_lib_tx_credit_use(pfe, id, qno, credit)                   \
++      ({ typeof(pfe) pfe_ = pfe;                                      \
++              typeof(id) id_ = id;                                    \
++              typeof(qno) qno_ = qno_;                                \
++              typeof(credit) credit_ = credit;                        \
++              do {                                                    \
++                      if (tx_qos) {                                   \
++                              (pfe_)->tmu_credit.tx_credit[id_][qno_]\
++                                       -= credit_;                    \
++                              (pfe_)->tmu_credit.tx_packets[id_][qno_]\
++                                      += credit_;                     \
++                      }                                               \
++              } while (0);                                            \
++      })
++
++#endif /* _PFE_HIF_LIB_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_hw.h
+@@ -0,0 +1,27 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _PFE_HW_H_
++#define _PFE_HW_H_
++
++#define PE_SYS_CLK_RATIO      1       /* SYS/AXI = 250MHz, HFE = 500MHz */
++
++int pfe_hw_init(struct pfe *pfe, int resume);
++void pfe_hw_exit(struct pfe *pfe);
++
++#endif /* _PFE_HW_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_mod.h
+@@ -0,0 +1,112 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _PFE_MOD_H_
++#define _PFE_MOD_H_
++
++#include <linux/device.h>
++#include <linux/elf.h>
++
++struct pfe;
++
++#include "pfe_hw.h"
++#include "pfe_firmware.h"
++#include "pfe_ctrl.h"
++#include "pfe_hif.h"
++#include "pfe_hif_lib.h"
++#include "pfe_eth.h"
++#include "pfe_sysfs.h"
++#include "pfe_perfmon.h"
++#include "pfe_debugfs.h"
++
++#define PHYID_MAX_VAL 32
++
++struct pfe_tmu_credit {
++      /* Number of allowed TX packet in-flight, matches TMU queue size */
++      unsigned int tx_credit[NUM_GEMAC_SUPPORT][EMAC_TXQ_CNT];
++      unsigned int tx_credit_max[NUM_GEMAC_SUPPORT][EMAC_TXQ_CNT];
++      unsigned int tx_packets[NUM_GEMAC_SUPPORT][EMAC_TXQ_CNT];
++};
++
++struct pfe {
++      struct regmap   *scfg;
++      unsigned long ddr_phys_baseaddr;
++      void *ddr_baseaddr;
++      unsigned int ddr_size;
++      void *cbus_baseaddr;
++      void *apb_baseaddr;
++      unsigned long iram_phys_baseaddr;
++      void *iram_baseaddr;
++      unsigned long ipsec_phys_baseaddr;
++      void *ipsec_baseaddr;
++      int hif_irq;
++      int wol_irq;
++      int hif_client_irq;
++      struct device *dev;
++      struct dentry *dentry;
++      struct pfe_ctrl ctrl;
++      struct pfe_hif hif;
++      struct pfe_eth eth;
++      struct hif_client_s *hif_client[HIF_CLIENTS_MAX];
++#if defined(CFG_DIAGS)
++      struct pfe_diags diags;
++#endif
++      struct pfe_tmu_credit tmu_credit;
++      struct pfe_cpumon cpumon;
++      struct pfe_memmon memmon;
++      int wake;
++      int mdio_muxval[PHYID_MAX_VAL];
++      struct clk *hfe_clock;
++};
++
++extern struct pfe *pfe;
++
++int pfe_probe(struct pfe *pfe);
++int pfe_remove(struct pfe *pfe);
++
++/* DDR Mapping in reserved memory*/
++#define ROUTE_TABLE_BASEADDR  0
++#define ROUTE_TABLE_HASH_BITS 15      /* 32K entries */
++#define ROUTE_TABLE_SIZE      ((1 << ROUTE_TABLE_HASH_BITS) \
++                                * CLASS_ROUTE_SIZE)
++#define BMU2_DDR_BASEADDR     (ROUTE_TABLE_BASEADDR + ROUTE_TABLE_SIZE)
++#define BMU2_BUF_COUNT                (4096 - 256)
++/* This is to get a total DDR size of 12MiB */
++#define BMU2_DDR_SIZE         (DDR_BUF_SIZE * BMU2_BUF_COUNT)
++#define UTIL_CODE_BASEADDR    (BMU2_DDR_BASEADDR + BMU2_DDR_SIZE)
++#define UTIL_CODE_SIZE                (128 * SZ_1K)
++#define UTIL_DDR_DATA_BASEADDR        (UTIL_CODE_BASEADDR + UTIL_CODE_SIZE)
++#define UTIL_DDR_DATA_SIZE    (64 * SZ_1K)
++#define CLASS_DDR_DATA_BASEADDR       (UTIL_DDR_DATA_BASEADDR + UTIL_DDR_DATA_SIZE)
++#define CLASS_DDR_DATA_SIZE   (32 * SZ_1K)
++#define TMU_DDR_DATA_BASEADDR (CLASS_DDR_DATA_BASEADDR + CLASS_DDR_DATA_SIZE)
++#define TMU_DDR_DATA_SIZE     (32 * SZ_1K)
++#define TMU_LLM_BASEADDR      (TMU_DDR_DATA_BASEADDR + TMU_DDR_DATA_SIZE)
++#define TMU_LLM_QUEUE_LEN     (8 * 512)
++/* Must be power of two and at least 16 * 8 = 128 bytes */
++#define TMU_LLM_SIZE          (4 * 16 * TMU_LLM_QUEUE_LEN)
++/* (4 TMU's x 16 queues x queue_len) */
++
++#define DDR_MAX_SIZE          (TMU_LLM_BASEADDR + TMU_LLM_SIZE)
++
++/* LMEM Mapping */
++#define BMU1_LMEM_BASEADDR    0
++#define BMU1_BUF_COUNT                256
++#define BMU1_LMEM_SIZE                (LMEM_BUF_SIZE * BMU1_BUF_COUNT)
++
++#endif /* _PFE_MOD_H */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_perfmon.h
+@@ -0,0 +1,38 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _PFE_PERFMON_H_
++#define _PFE_PERFMON_H_
++
++#include "pfe/pfe.h"
++
++#define       CT_CPUMON_INTERVAL      (1 * TIMER_TICKS_PER_SEC)
++
++struct pfe_cpumon {
++      u32 cpu_usage_pct[MAX_PE];
++      u32 class_usage_pct;
++};
++
++struct pfe_memmon {
++      u32 kernel_memory_allocated;
++};
++
++int pfe_perfmon_init(struct pfe *pfe);
++void pfe_perfmon_exit(struct pfe *pfe);
++
++#endif /* _PFE_PERFMON_H_ */
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_sysfs.h
+@@ -0,0 +1,29 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _PFE_SYSFS_H_
++#define _PFE_SYSFS_H_
++
++#include <linux/proc_fs.h>
++
++u32 qm_read_drop_stat(u32 tmu, u32 queue, u32 *total_drops, int do_reset);
++
++int pfe_sysfs_init(struct pfe *pfe);
++void pfe_sysfs_exit(struct pfe *pfe);
++
++#endif /* _PFE_SYSFS_H_ */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0286-staging-fsl_ppfe-eth-introduce-pfe-driver.patch b/target/linux/layerscape/patches-5.4/701-net-0286-staging-fsl_ppfe-eth-introduce-pfe-driver.patch
new file mode 100644 (file)
index 0000000..230238f
--- /dev/null
@@ -0,0 +1,8000 @@
+From fccb0e1e07fc0750fd081ab52ed94ee13f6b360f Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Sat, 16 Sep 2017 14:22:17 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: introduce pfe driver
+
+       This patch introduces Linux support for NXP's LS1012A Packet
+Forwarding Engine (pfe_eth). LS1012A uses hardware packet forwarding
+engine to provide high performance Ethernet interfaces. The device
+includes two Ethernet ports.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+Signed-off-by: Anjaneyulu Jagarlmudi <anji.jagarlmudi@nxp.com>
+---
+ drivers/staging/fsl_ppfe/Kconfig                |   20 +
+ drivers/staging/fsl_ppfe/Makefile               |   19 +
+ drivers/staging/fsl_ppfe/TODO                   |    2 +
+ drivers/staging/fsl_ppfe/pfe_ctrl.c             |  238 +++
+ drivers/staging/fsl_ppfe/pfe_debugfs.c          |  111 ++
+ drivers/staging/fsl_ppfe/pfe_eth.c              | 2434 +++++++++++++++++++++++
+ drivers/staging/fsl_ppfe/pfe_firmware.c         |  314 +++
+ drivers/staging/fsl_ppfe/pfe_hal.c              | 1516 ++++++++++++++
+ drivers/staging/fsl_ppfe/pfe_hif.c              | 1094 ++++++++++
+ drivers/staging/fsl_ppfe/pfe_hif_lib.c          |  638 ++++++
+ drivers/staging/fsl_ppfe/pfe_hw.c               |  176 ++
+ drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c |  394 ++++
+ drivers/staging/fsl_ppfe/pfe_mod.c              |  141 ++
+ drivers/staging/fsl_ppfe/pfe_sysfs.c            |  818 ++++++++
+ 14 files changed, 7915 insertions(+)
+ create mode 100644 drivers/staging/fsl_ppfe/Kconfig
+ create mode 100644 drivers/staging/fsl_ppfe/Makefile
+ create mode 100644 drivers/staging/fsl_ppfe/TODO
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_ctrl.c
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_debugfs.c
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_eth.c
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_firmware.c
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_hal.c
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_hif.c
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_hif_lib.c
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_hw.c
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_mod.c
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_sysfs.c
+
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/Kconfig
+@@ -0,0 +1,20 @@
++#
++# Freescale Programmable Packet Forwarding Engine driver
++#
++config FSL_PPFE
++      bool "Freescale PPFE Driver"
++      default n
++      ---help---
++      Freescale LS1012A SoC has a Programmable Packet Forwarding Engine.
++      It provides two high performance ethernet interfaces.
++      This driver initializes, programs and controls the PPFE.
++      Use this driver to enable network connectivity on LS1012A platforms.
++
++if FSL_PPFE
++
++config FSL_PPFE_UTIL_DISABLED
++      bool "Disable PPFE UTIL Processor Engine"
++      ---help---
++      UTIL PE has to be enabled only if required.
++
++endif # FSL_PPFE
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/Makefile
+@@ -0,0 +1,19 @@
++#
++# Makefile for Freesecale PPFE driver
++#
++
++ccflags-y +=  -I$(src)/include  -I$(src)
++
++obj-m += pfe.o
++
++pfe-y += pfe_mod.o \
++      pfe_hw.o \
++      pfe_firmware.o \
++      pfe_ctrl.o \
++      pfe_hif.o \
++      pfe_hif_lib.o\
++      pfe_eth.o \
++      pfe_sysfs.o \
++      pfe_debugfs.o \
++      pfe_ls1012a_platform.o \
++      pfe_hal.o
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/TODO
+@@ -0,0 +1,2 @@
++TODO:
++      - provide pfe pe monitoring support
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_ctrl.c
+@@ -0,0 +1,238 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/module.h>
++#include <linux/list.h>
++#include <linux/kthread.h>
++
++#include "pfe_mod.h"
++#include "pfe_ctrl.h"
++
++#define TIMEOUT_MS    1000
++
++int relax(unsigned long end)
++{
++      if (time_after(jiffies, end)) {
++              if (time_after(jiffies, end + (TIMEOUT_MS * HZ) / 1000))
++                      return -1;
++
++              if (need_resched())
++                      schedule();
++      }
++
++      return 0;
++}
++
++void pfe_ctrl_suspend(struct pfe_ctrl *ctrl)
++{
++      int id;
++
++      mutex_lock(&ctrl->mutex);
++
++      for (id = CLASS0_ID; id <= CLASS_MAX_ID; id++)
++              pe_dmem_write(id, cpu_to_be32(0x1), CLASS_DM_RESUME, 4);
++
++      for (id = TMU0_ID; id <= TMU_MAX_ID; id++) {
++              if (id == TMU2_ID)
++                      continue;
++              pe_dmem_write(id, cpu_to_be32(0x1), TMU_DM_RESUME, 4);
++      }
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      pe_dmem_write(UTIL_ID, cpu_to_be32(0x1), UTIL_DM_RESUME, 4);
++#endif
++      mutex_unlock(&ctrl->mutex);
++}
++
++void pfe_ctrl_resume(struct pfe_ctrl *ctrl)
++{
++      int pe_mask = CLASS_MASK | TMU_MASK;
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      pe_mask |= UTIL_MASK;
++#endif
++      mutex_lock(&ctrl->mutex);
++      pe_start(&pfe->ctrl, pe_mask);
++      mutex_unlock(&ctrl->mutex);
++}
++
++/* PE sync stop.
++ * Stops packet processing for a list of PE's (specified using a bitmask).
++ * The caller must hold ctrl->mutex.
++ *
++ * @param ctrl                Control context
++ * @param pe_mask     Mask of PE id's to stop
++ *
++ */
++int pe_sync_stop(struct pfe_ctrl *ctrl, int pe_mask)
++{
++      struct pe_sync_mailbox *mbox;
++      int pe_stopped = 0;
++      unsigned long end = jiffies + 2;
++      int i;
++
++      pe_mask &= 0x2FF;  /*Exclude Util + TMU2 */
++
++      for (i = 0; i < MAX_PE; i++)
++              if (pe_mask & (1 << i)) {
++                      mbox = (void *)ctrl->sync_mailbox_baseaddr[i];
++
++                      pe_dmem_write(i, cpu_to_be32(0x1), (unsigned
++                                      long)&mbox->stop, 4);
++              }
++
++      while (pe_stopped != pe_mask) {
++              for (i = 0; i < MAX_PE; i++)
++                      if ((pe_mask & (1 << i)) && !(pe_stopped & (1 << i))) {
++                              mbox = (void *)ctrl->sync_mailbox_baseaddr[i];
++
++                              if (pe_dmem_read(i, (unsigned
++                                      long)&mbox->stopped, 4) &
++                                      cpu_to_be32(0x1))
++                                      pe_stopped |= (1 << i);
++                      }
++
++              if (relax(end) < 0)
++                      goto err;
++      }
++
++      return 0;
++
++err:
++      pr_err("%s: timeout, %x %x\n", __func__, pe_mask, pe_stopped);
++
++      for (i = 0; i < MAX_PE; i++)
++              if (pe_mask & (1 << i)) {
++                      mbox = (void *)ctrl->sync_mailbox_baseaddr[i];
++
++                      pe_dmem_write(i, cpu_to_be32(0x0), (unsigned
++                                      long)&mbox->stop, 4);
++      }
++
++      return -EIO;
++}
++
++/* PE start.
++ * Starts packet processing for a list of PE's (specified using a bitmask).
++ * The caller must hold ctrl->mutex.
++ *
++ * @param ctrl                Control context
++ * @param pe_mask     Mask of PE id's to start
++ *
++ */
++void pe_start(struct pfe_ctrl *ctrl, int pe_mask)
++{
++      struct pe_sync_mailbox *mbox;
++      int i;
++
++      for (i = 0; i < MAX_PE; i++)
++              if (pe_mask & (1 << i)) {
++                      mbox = (void *)ctrl->sync_mailbox_baseaddr[i];
++
++                      pe_dmem_write(i, cpu_to_be32(0x0), (unsigned
++                                      long)&mbox->stop, 4);
++              }
++}
++
++/* This function will ensure all PEs are put in to idle state */
++int pe_reset_all(struct pfe_ctrl *ctrl)
++{
++      struct pe_sync_mailbox *mbox;
++      int pe_stopped = 0;
++      unsigned long end = jiffies + 2;
++      int i;
++      int pe_mask  = CLASS_MASK | TMU_MASK;
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      pe_mask |= UTIL_MASK;
++#endif
++
++      for (i = 0; i < MAX_PE; i++)
++              if (pe_mask & (1 << i)) {
++                      mbox = (void *)ctrl->sync_mailbox_baseaddr[i];
++
++                      pe_dmem_write(i, cpu_to_be32(0x2), (unsigned
++                                      long)&mbox->stop, 4);
++              }
++
++      while (pe_stopped != pe_mask) {
++              for (i = 0; i < MAX_PE; i++)
++                      if ((pe_mask & (1 << i)) && !(pe_stopped & (1 << i))) {
++                              mbox = (void *)ctrl->sync_mailbox_baseaddr[i];
++
++                              if (pe_dmem_read(i, (unsigned long)
++                                                      &mbox->stopped, 4) &
++                                              cpu_to_be32(0x1))
++                                      pe_stopped |= (1 << i);
++                      }
++
++              if (relax(end) < 0)
++                      goto err;
++      }
++
++      return 0;
++
++err:
++      pr_err("%s: timeout, %x %x\n", __func__, pe_mask, pe_stopped);
++      return -EIO;
++}
++
++int pfe_ctrl_init(struct pfe *pfe)
++{
++      struct pfe_ctrl *ctrl = &pfe->ctrl;
++      int id;
++
++      pr_info("%s\n", __func__);
++
++      mutex_init(&ctrl->mutex);
++      spin_lock_init(&ctrl->lock);
++
++      for (id = CLASS0_ID; id <= CLASS_MAX_ID; id++) {
++              ctrl->sync_mailbox_baseaddr[id] = CLASS_DM_SYNC_MBOX;
++              ctrl->msg_mailbox_baseaddr[id] = CLASS_DM_MSG_MBOX;
++      }
++
++      for (id = TMU0_ID; id <= TMU_MAX_ID; id++) {
++              if (id == TMU2_ID)
++                      continue;
++              ctrl->sync_mailbox_baseaddr[id] = TMU_DM_SYNC_MBOX;
++              ctrl->msg_mailbox_baseaddr[id] = TMU_DM_MSG_MBOX;
++      }
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      ctrl->sync_mailbox_baseaddr[UTIL_ID] = UTIL_DM_SYNC_MBOX;
++      ctrl->msg_mailbox_baseaddr[UTIL_ID] = UTIL_DM_MSG_MBOX;
++#endif
++
++      ctrl->hash_array_baseaddr = pfe->ddr_baseaddr + ROUTE_TABLE_BASEADDR;
++      ctrl->hash_array_phys_baseaddr = pfe->ddr_phys_baseaddr +
++                                              ROUTE_TABLE_BASEADDR;
++
++      ctrl->dev = pfe->dev;
++
++      pr_info("%s finished\n", __func__);
++
++      return 0;
++}
++
++void pfe_ctrl_exit(struct pfe *pfe)
++{
++      pr_info("%s\n", __func__);
++}
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_debugfs.c
+@@ -0,0 +1,111 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/module.h>
++#include <linux/debugfs.h>
++#include <linux/platform_device.h>
++
++#include "pfe_mod.h"
++
++static int dmem_show(struct seq_file *s, void *unused)
++{
++      u32 dmem_addr, val;
++      int id = (long int)s->private;
++      int i;
++
++      for (dmem_addr = 0; dmem_addr < CLASS_DMEM_SIZE; dmem_addr += 8 * 4) {
++              seq_printf(s, "%04x:", dmem_addr);
++
++              for (i = 0; i < 8; i++) {
++                      val = pe_dmem_read(id, dmem_addr + i * 4, 4);
++                      seq_printf(s, " %02x %02x %02x %02x", val & 0xff,
++                                 (val >> 8) & 0xff, (val >> 16) & 0xff,
++                                 (val >> 24) & 0xff);
++              }
++
++              seq_puts(s, "\n");
++      }
++
++      return 0;
++}
++
++static int dmem_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, dmem_show, inode->i_private);
++}
++
++static const struct file_operations dmem_fops = {
++      .open           = dmem_open,
++      .read           = seq_read,
++      .llseek         = seq_lseek,
++      .release        = single_release,
++};
++
++int pfe_debugfs_init(struct pfe *pfe)
++{
++      struct dentry *d;
++
++      pr_info("%s\n", __func__);
++
++      pfe->dentry = debugfs_create_dir("pfe", NULL);
++      if (IS_ERR_OR_NULL(pfe->dentry))
++              goto err_dir;
++
++      d = debugfs_create_file("pe0_dmem", 0444, pfe->dentry, (void *)0,
++                              &dmem_fops);
++      if (IS_ERR_OR_NULL(d))
++              goto err_pe;
++
++      d = debugfs_create_file("pe1_dmem", 0444, pfe->dentry, (void *)1,
++                              &dmem_fops);
++      if (IS_ERR_OR_NULL(d))
++              goto err_pe;
++
++      d = debugfs_create_file("pe2_dmem", 0444, pfe->dentry, (void *)2,
++                              &dmem_fops);
++      if (IS_ERR_OR_NULL(d))
++              goto err_pe;
++
++      d = debugfs_create_file("pe3_dmem", 0444, pfe->dentry, (void *)3,
++                              &dmem_fops);
++      if (IS_ERR_OR_NULL(d))
++              goto err_pe;
++
++      d = debugfs_create_file("pe4_dmem", 0444, pfe->dentry, (void *)4,
++                              &dmem_fops);
++      if (IS_ERR_OR_NULL(d))
++              goto err_pe;
++
++      d = debugfs_create_file("pe5_dmem", 0444, pfe->dentry, (void *)5,
++                              &dmem_fops);
++      if (IS_ERR_OR_NULL(d))
++              goto err_pe;
++
++      return 0;
++
++err_pe:
++      debugfs_remove_recursive(pfe->dentry);
++
++err_dir:
++      return -1;
++}
++
++void pfe_debugfs_exit(struct pfe *pfe)
++{
++      debugfs_remove_recursive(pfe->dentry);
++}
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -0,0 +1,2434 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++/* @pfe_eth.c.
++ *  Ethernet driver for to handle exception path for PFE.
++ *  - uses HIF functions to send/receive packets.
++ *  - uses ctrl function to start/stop interfaces.
++ *  - uses direct register accesses to control phy operation.
++ */
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmapool.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/phy.h>
++#include <linux/timer.h>
++#include <linux/hrtimer.h>
++#include <linux/platform_device.h>
++
++#include <net/ip.h>
++#include <net/sock.h>
++
++#include <linux/io.h>
++#include <asm/irq.h>
++#include <linux/delay.h>
++#include <linux/regmap.h>
++#include <linux/i2c.h>
++
++#if defined(CONFIG_NF_CONNTRACK_MARK)
++#include <net/netfilter/nf_conntrack.h>
++#endif
++
++#include "pfe_mod.h"
++#include "pfe_eth.h"
++
++static void *cbus_emac_base[3];
++static void *cbus_gpi_base[3];
++
++/* Forward Declaration */
++static void pfe_eth_exit_one(struct pfe_eth_priv_s *priv);
++static void pfe_eth_flush_tx(struct pfe_eth_priv_s *priv);
++static void pfe_eth_flush_txQ(struct pfe_eth_priv_s *priv, int tx_q_num, int
++                              from_tx, int n_desc);
++
++unsigned int gemac_regs[] = {
++      0x0004, /* Interrupt event */
++      0x0008, /* Interrupt mask */
++      0x0024, /* Ethernet control */
++      0x0064, /* MIB Control/Status */
++      0x0084, /* Receive control/status */
++      0x00C4, /* Transmit control */
++      0x00E4, /* Physical address low */
++      0x00E8, /* Physical address high */
++      0x0144, /* Transmit FIFO Watermark and Store and Forward Control*/
++      0x0190, /* Receive FIFO Section Full Threshold */
++      0x01A0, /* Transmit FIFO Section Empty Threshold */
++      0x01B0, /* Frame Truncation Length */
++};
++
++/********************************************************************/
++/*                   SYSFS INTERFACE                              */
++/********************************************************************/
++
++#ifdef PFE_ETH_NAPI_STATS
++/*
++ * pfe_eth_show_napi_stats
++ */
++static ssize_t pfe_eth_show_napi_stats(struct device *dev,
++                                     struct device_attribute *attr,
++                                     char *buf)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(to_net_dev(dev));
++      ssize_t len = 0;
++
++      len += sprintf(buf + len, "sched:  %u\n",
++                      priv->napi_counters[NAPI_SCHED_COUNT]);
++      len += sprintf(buf + len, "poll:   %u\n",
++                      priv->napi_counters[NAPI_POLL_COUNT]);
++      len += sprintf(buf + len, "packet: %u\n",
++                      priv->napi_counters[NAPI_PACKET_COUNT]);
++      len += sprintf(buf + len, "budget: %u\n",
++                      priv->napi_counters[NAPI_FULL_BUDGET_COUNT]);
++      len += sprintf(buf + len, "desc:   %u\n",
++                      priv->napi_counters[NAPI_DESC_COUNT]);
++
++      return len;
++}
++
++/*
++ * pfe_eth_set_napi_stats
++ */
++static ssize_t pfe_eth_set_napi_stats(struct device *dev,
++                                    struct device_attribute *attr,
++                                    const char *buf, size_t count)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(to_net_dev(dev));
++
++      memset(priv->napi_counters, 0, sizeof(priv->napi_counters));
++
++      return count;
++}
++#endif
++#ifdef PFE_ETH_TX_STATS
++/* pfe_eth_show_tx_stats
++ *
++ */
++static ssize_t pfe_eth_show_tx_stats(struct device *dev,
++                                   struct device_attribute *attr,
++                                   char *buf)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(to_net_dev(dev));
++      ssize_t len = 0;
++      int i;
++
++      len += sprintf(buf + len, "TX queues stats:\n");
++
++      for (i = 0; i < emac_txq_cnt; i++) {
++              struct netdev_queue *tx_queue = netdev_get_tx_queue(priv->ndev,
++                                                                      i);
++
++              len += sprintf(buf + len, "\n");
++              __netif_tx_lock_bh(tx_queue);
++
++              hif_tx_lock(&pfe->hif);
++              len += sprintf(buf + len,
++                              "Queue %2d :  credits               = %10d\n"
++                              , i, hif_lib_tx_credit_avail(pfe, priv->id, i));
++              len += sprintf(buf + len,
++                               "            tx packets            = %10d\n"
++                              ,  pfe->tmu_credit.tx_packets[priv->id][i]);
++              hif_tx_unlock(&pfe->hif);
++
++              /* Don't output additionnal stats if queue never used */
++              if (!pfe->tmu_credit.tx_packets[priv->id][i])
++                      goto skip;
++
++              len += sprintf(buf + len,
++                               "            clean_fail            = %10d\n"
++                              , priv->clean_fail[i]);
++              len += sprintf(buf + len,
++                               "            stop_queue            = %10d\n"
++                              , priv->stop_queue_total[i]);
++              len += sprintf(buf + len,
++                               "            stop_queue_hif        = %10d\n"
++                              , priv->stop_queue_hif[i]);
++              len += sprintf(buf + len,
++                              "            stop_queue_hif_client = %10d\n"
++                              , priv->stop_queue_hif_client[i]);
++              len += sprintf(buf + len,
++                               "            stop_queue_credit     = %10d\n"
++                              , priv->stop_queue_credit[i]);
++skip:
++              __netif_tx_unlock_bh(tx_queue);
++      }
++      return len;
++}
++
++/* pfe_eth_set_tx_stats
++ *
++ */
++static ssize_t pfe_eth_set_tx_stats(struct device *dev,
++                                  struct device_attribute *attr,
++                                  const char *buf, size_t count)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(to_net_dev(dev));
++      int i;
++
++      for (i = 0; i < emac_txq_cnt; i++) {
++              struct netdev_queue *tx_queue = netdev_get_tx_queue(priv->ndev,
++                                                                      i);
++
++              __netif_tx_lock_bh(tx_queue);
++              priv->clean_fail[i] = 0;
++              priv->stop_queue_total[i] = 0;
++              priv->stop_queue_hif[i] = 0;
++              priv->stop_queue_hif_client[i] = 0;
++              priv->stop_queue_credit[i] = 0;
++              __netif_tx_unlock_bh(tx_queue);
++      }
++
++      return count;
++}
++#endif
++/* pfe_eth_show_txavail
++ *
++ */
++static ssize_t pfe_eth_show_txavail(struct device *dev,
++                                  struct device_attribute *attr,
++                                  char *buf)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(to_net_dev(dev));
++      ssize_t len = 0;
++      int i;
++
++      for (i = 0; i < emac_txq_cnt; i++) {
++              struct netdev_queue *tx_queue = netdev_get_tx_queue(priv->ndev,
++                                                                      i);
++
++              __netif_tx_lock_bh(tx_queue);
++
++              len += sprintf(buf + len, "%d",
++                              hif_lib_tx_avail(&priv->client, i));
++
++              __netif_tx_unlock_bh(tx_queue);
++
++              if (i == (emac_txq_cnt - 1))
++                      len += sprintf(buf + len, "\n");
++              else
++                      len += sprintf(buf + len, " ");
++      }
++
++      return len;
++}
++
++/* pfe_eth_show_default_priority
++ *
++ */
++static ssize_t pfe_eth_show_default_priority(struct device *dev,
++                                           struct device_attribute *attr,
++                                              char *buf)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(to_net_dev(dev));
++      unsigned long flags;
++      int rc;
++
++      spin_lock_irqsave(&priv->lock, flags);
++      rc = sprintf(buf, "%d\n", priv->default_priority);
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return rc;
++}
++
++/* pfe_eth_set_default_priority
++ *
++ */
++
++static ssize_t pfe_eth_set_default_priority(struct device *dev,
++                                          struct device_attribute *attr,
++                                          const char *buf, size_t count)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(to_net_dev(dev));
++      unsigned long flags;
++
++      spin_lock_irqsave(&priv->lock, flags);
++      priv->default_priority = kstrtoul(buf, 0, 0);
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return count;
++}
++
++static DEVICE_ATTR(txavail, 0444, pfe_eth_show_txavail, NULL);
++static DEVICE_ATTR(default_priority, 0644, pfe_eth_show_default_priority,
++                      pfe_eth_set_default_priority);
++
++#ifdef PFE_ETH_NAPI_STATS
++static DEVICE_ATTR(napi_stats, 0644, pfe_eth_show_napi_stats,
++                      pfe_eth_set_napi_stats);
++#endif
++
++#ifdef PFE_ETH_TX_STATS
++static DEVICE_ATTR(tx_stats, 0644, pfe_eth_show_tx_stats,
++                      pfe_eth_set_tx_stats);
++#endif
++
++/*
++ * pfe_eth_sysfs_init
++ *
++ */
++static int pfe_eth_sysfs_init(struct net_device *ndev)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++      int err;
++
++      /* Initialize the default values */
++
++      /*
++       * By default, packets without conntrack will use this default high
++       * priority queue
++       */
++      priv->default_priority = 15;
++
++      /* Create our sysfs files */
++      err = device_create_file(&ndev->dev, &dev_attr_default_priority);
++      if (err) {
++              netdev_err(ndev,
++                         "failed to create default_priority sysfs files\n");
++              goto err_priority;
++      }
++
++      err = device_create_file(&ndev->dev, &dev_attr_txavail);
++      if (err) {
++              netdev_err(ndev,
++                         "failed to create default_priority sysfs files\n");
++              goto err_txavail;
++      }
++
++#ifdef PFE_ETH_NAPI_STATS
++      err = device_create_file(&ndev->dev, &dev_attr_napi_stats);
++      if (err) {
++              netdev_err(ndev, "failed to create napi stats sysfs files\n");
++              goto err_napi;
++      }
++#endif
++
++#ifdef PFE_ETH_TX_STATS
++      err = device_create_file(&ndev->dev, &dev_attr_tx_stats);
++      if (err) {
++              netdev_err(ndev, "failed to create tx stats sysfs files\n");
++              goto err_tx;
++      }
++#endif
++
++      return 0;
++
++#ifdef PFE_ETH_TX_STATS
++err_tx:
++#endif
++#ifdef PFE_ETH_NAPI_STATS
++      device_remove_file(&ndev->dev, &dev_attr_napi_stats);
++
++err_napi:
++#endif
++      device_remove_file(&ndev->dev, &dev_attr_txavail);
++
++err_txavail:
++      device_remove_file(&ndev->dev, &dev_attr_default_priority);
++
++err_priority:
++      return -1;
++}
++
++/* pfe_eth_sysfs_exit
++ *
++ */
++void pfe_eth_sysfs_exit(struct net_device *ndev)
++{
++#ifdef PFE_ETH_TX_STATS
++      device_remove_file(&ndev->dev, &dev_attr_tx_stats);
++#endif
++
++#ifdef PFE_ETH_NAPI_STATS
++      device_remove_file(&ndev->dev, &dev_attr_napi_stats);
++#endif
++      device_remove_file(&ndev->dev, &dev_attr_txavail);
++      device_remove_file(&ndev->dev, &dev_attr_default_priority);
++}
++
++/*************************************************************************/
++/*            ETHTOOL INTERCAE                                         */
++/*************************************************************************/
++
++/*MTIP GEMAC */
++static const struct fec_stat {
++      char name[ETH_GSTRING_LEN];
++      u16 offset;
++} fec_stats[] = {
++      /* RMON TX */
++      { "tx_dropped", RMON_T_DROP },
++      { "tx_packets", RMON_T_PACKETS },
++      { "tx_broadcast", RMON_T_BC_PKT },
++      { "tx_multicast", RMON_T_MC_PKT },
++      { "tx_crc_errors", RMON_T_CRC_ALIGN },
++      { "tx_undersize", RMON_T_UNDERSIZE },
++      { "tx_oversize", RMON_T_OVERSIZE },
++      { "tx_fragment", RMON_T_FRAG },
++      { "tx_jabber", RMON_T_JAB },
++      { "tx_collision", RMON_T_COL },
++      { "tx_64byte", RMON_T_P64 },
++      { "tx_65to127byte", RMON_T_P65TO127 },
++      { "tx_128to255byte", RMON_T_P128TO255 },
++      { "tx_256to511byte", RMON_T_P256TO511 },
++      { "tx_512to1023byte", RMON_T_P512TO1023 },
++      { "tx_1024to2047byte", RMON_T_P1024TO2047 },
++      { "tx_GTE2048byte", RMON_T_P_GTE2048 },
++      { "tx_octets", RMON_T_OCTETS },
++
++      /* IEEE TX */
++      { "IEEE_tx_drop", IEEE_T_DROP },
++      { "IEEE_tx_frame_ok", IEEE_T_FRAME_OK },
++      { "IEEE_tx_1col", IEEE_T_1COL },
++      { "IEEE_tx_mcol", IEEE_T_MCOL },
++      { "IEEE_tx_def", IEEE_T_DEF },
++      { "IEEE_tx_lcol", IEEE_T_LCOL },
++      { "IEEE_tx_excol", IEEE_T_EXCOL },
++      { "IEEE_tx_macerr", IEEE_T_MACERR },
++      { "IEEE_tx_cserr", IEEE_T_CSERR },
++      { "IEEE_tx_sqe", IEEE_T_SQE },
++      { "IEEE_tx_fdxfc", IEEE_T_FDXFC },
++      { "IEEE_tx_octets_ok", IEEE_T_OCTETS_OK },
++
++      /* RMON RX */
++      { "rx_packets", RMON_R_PACKETS },
++      { "rx_broadcast", RMON_R_BC_PKT },
++      { "rx_multicast", RMON_R_MC_PKT },
++      { "rx_crc_errors", RMON_R_CRC_ALIGN },
++      { "rx_undersize", RMON_R_UNDERSIZE },
++      { "rx_oversize", RMON_R_OVERSIZE },
++      { "rx_fragment", RMON_R_FRAG },
++      { "rx_jabber", RMON_R_JAB },
++      { "rx_64byte", RMON_R_P64 },
++      { "rx_65to127byte", RMON_R_P65TO127 },
++      { "rx_128to255byte", RMON_R_P128TO255 },
++      { "rx_256to511byte", RMON_R_P256TO511 },
++      { "rx_512to1023byte", RMON_R_P512TO1023 },
++      { "rx_1024to2047byte", RMON_R_P1024TO2047 },
++      { "rx_GTE2048byte", RMON_R_P_GTE2048 },
++      { "rx_octets", RMON_R_OCTETS },
++
++      /* IEEE RX */
++      { "IEEE_rx_drop", IEEE_R_DROP },
++      { "IEEE_rx_frame_ok", IEEE_R_FRAME_OK },
++      { "IEEE_rx_crc", IEEE_R_CRC },
++      { "IEEE_rx_align", IEEE_R_ALIGN },
++      { "IEEE_rx_macerr", IEEE_R_MACERR },
++      { "IEEE_rx_fdxfc", IEEE_R_FDXFC },
++      { "IEEE_rx_octets_ok", IEEE_R_OCTETS_OK },
++};
++
++static void pfe_eth_fill_stats(struct net_device *ndev, struct ethtool_stats
++                              *stats, u64 *data)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(fec_stats); i++)
++              data[i] = readl(priv->EMAC_baseaddr + fec_stats[i].offset);
++}
++
++static void pfe_eth_gstrings(struct net_device *netdev,
++                           u32 stringset, u8 *data)
++{
++      int i;
++
++      switch (stringset) {
++      case ETH_SS_STATS:
++              for (i = 0; i < ARRAY_SIZE(fec_stats); i++)
++                      memcpy(data + i * ETH_GSTRING_LEN,
++                             fec_stats[i].name, ETH_GSTRING_LEN);
++              break;
++      }
++}
++
++static int pfe_eth_stats_count(struct net_device *ndev, int sset)
++{
++      switch (sset) {
++      case ETH_SS_STATS:
++              return ARRAY_SIZE(fec_stats);
++      default:
++              return -EOPNOTSUPP;
++      }
++}
++
++/*
++ * pfe_eth_gemac_reglen - Return the length of the register structure.
++ *
++ */
++static int pfe_eth_gemac_reglen(struct net_device *ndev)
++{
++      pr_info("%s()\n", __func__);
++      return (sizeof(gemac_regs) / sizeof(u32));
++}
++
++/*
++ * pfe_eth_gemac_get_regs - Return the gemac register structure.
++ *
++ */
++static void  pfe_eth_gemac_get_regs(struct net_device *ndev, struct ethtool_regs
++                                      *regs, void *regbuf)
++{
++      int i;
++
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++      u32 *buf = (u32 *)regbuf;
++
++      pr_info("%s()\n", __func__);
++      for (i = 0; i < sizeof(gemac_regs) / sizeof(u32); i++)
++              buf[i] = readl(priv->EMAC_baseaddr + gemac_regs[i]);
++}
++
++/*
++ * pfe_eth_set_wol - Set the magic packet option, in WoL register.
++ *
++ */
++static int pfe_eth_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++
++      if (wol->wolopts & ~WAKE_MAGIC)
++              return -EOPNOTSUPP;
++
++      /* for MTIP we store wol->wolopts */
++      priv->wol = wol->wolopts;
++
++      device_set_wakeup_enable(&ndev->dev, wol->wolopts & WAKE_MAGIC);
++
++      return 0;
++}
++
++/*
++ *
++ * pfe_eth_get_wol - Get the WoL options.
++ *
++ */
++static void pfe_eth_get_wol(struct net_device *ndev, struct ethtool_wolinfo
++                              *wol)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++
++      wol->supported = WAKE_MAGIC;
++      wol->wolopts = 0;
++
++      if (priv->wol & WAKE_MAGIC)
++              wol->wolopts = WAKE_MAGIC;
++
++      memset(&wol->sopass, 0, sizeof(wol->sopass));
++}
++
++/*
++ * pfe_eth_get_drvinfo -  Fills in the drvinfo structure with some basic info
++ *
++ */
++static void pfe_eth_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo
++                              *drvinfo)
++{
++      strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
++      strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
++      strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
++      strlcpy(drvinfo->bus_info, "N/A", sizeof(drvinfo->bus_info));
++}
++
++/*
++ * pfe_eth_set_settings - Used to send commands to PHY.
++ *
++ */
++static int pfe_eth_set_settings(struct net_device *ndev,
++                              const struct ethtool_link_ksettings *cmd)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++      struct phy_device *phydev = priv->phydev;
++
++      if (!phydev)
++              return -ENODEV;
++
++      return phy_ethtool_ksettings_set(phydev, cmd);
++}
++
++/*
++ * pfe_eth_getsettings - Return the current settings in the ethtool_cmd
++ * structure.
++ *
++ */
++static int pfe_eth_get_settings(struct net_device *ndev,
++                              struct ethtool_link_ksettings *cmd)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++      struct phy_device *phydev = priv->phydev;
++
++      if (!phydev)
++              return -ENODEV;
++
++      return phy_ethtool_ksettings_get(phydev, cmd);
++}
++
++/*
++ * pfe_eth_get_msglevel - Gets the debug message mask.
++ *
++ */
++static uint32_t pfe_eth_get_msglevel(struct net_device *ndev)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++
++      return priv->msg_enable;
++}
++
++/*
++ * pfe_eth_set_msglevel - Sets the debug message mask.
++ *
++ */
++static void pfe_eth_set_msglevel(struct net_device *ndev, uint32_t data)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++
++      priv->msg_enable = data;
++}
++
++#define HIF_RX_COAL_MAX_CLKS          (~(1 << 31))
++#define HIF_RX_COAL_CLKS_PER_USEC     (pfe->ctrl.sys_clk / 1000)
++#define HIF_RX_COAL_MAX_USECS         (HIF_RX_COAL_MAX_CLKS   / \
++                                              HIF_RX_COAL_CLKS_PER_USEC)
++
++/*
++ * pfe_eth_set_coalesce - Sets rx interrupt coalescing timer.
++ *
++ */
++static int pfe_eth_set_coalesce(struct net_device *ndev,
++                              struct ethtool_coalesce *ec)
++{
++      if (ec->rx_coalesce_usecs > HIF_RX_COAL_MAX_USECS)
++              return -EINVAL;
++
++      if (!ec->rx_coalesce_usecs) {
++              writel(0, HIF_INT_COAL);
++              return 0;
++      }
++
++      writel((ec->rx_coalesce_usecs * HIF_RX_COAL_CLKS_PER_USEC) |
++                      HIF_INT_COAL_ENABLE, HIF_INT_COAL);
++
++      return 0;
++}
++
++/*
++ * pfe_eth_get_coalesce - Gets rx interrupt coalescing timer value.
++ *
++ */
++static int pfe_eth_get_coalesce(struct net_device *ndev,
++                              struct ethtool_coalesce *ec)
++{
++      int reg_val = readl(HIF_INT_COAL);
++
++      if (reg_val & HIF_INT_COAL_ENABLE)
++              ec->rx_coalesce_usecs = (reg_val & HIF_RX_COAL_MAX_CLKS) /
++                                              HIF_RX_COAL_CLKS_PER_USEC;
++      else
++              ec->rx_coalesce_usecs = 0;
++
++      return 0;
++}
++
++/*
++ * pfe_eth_set_pauseparam - Sets pause parameters
++ *
++ */
++static int pfe_eth_set_pauseparam(struct net_device *ndev,
++                                struct ethtool_pauseparam *epause)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++
++      if (epause->tx_pause != epause->rx_pause) {
++              netdev_info(ndev,
++                          "hardware only support enable/disable both tx and rx\n");
++              return -EINVAL;
++      }
++
++      priv->pause_flag = 0;
++      priv->pause_flag |= epause->rx_pause ? PFE_PAUSE_FLAG_ENABLE : 0;
++      priv->pause_flag |= epause->autoneg ? PFE_PAUSE_FLAG_AUTONEG : 0;
++
++      if (epause->rx_pause || epause->autoneg) {
++              gemac_enable_pause_rx(priv->EMAC_baseaddr);
++              writel((readl(priv->GPI_baseaddr + GPI_TX_PAUSE_TIME) |
++                                      EGPI_PAUSE_ENABLE),
++                              priv->GPI_baseaddr + GPI_TX_PAUSE_TIME);
++              if (priv->phydev) {
++                      priv->phydev->supported |= ADVERTISED_Pause |
++                                                      ADVERTISED_Asym_Pause;
++                      priv->phydev->advertising |= ADVERTISED_Pause |
++                                                      ADVERTISED_Asym_Pause;
++              }
++      } else {
++              gemac_disable_pause_rx(priv->EMAC_baseaddr);
++              writel((readl(priv->GPI_baseaddr + GPI_TX_PAUSE_TIME) &
++                                      ~EGPI_PAUSE_ENABLE),
++                              priv->GPI_baseaddr + GPI_TX_PAUSE_TIME);
++              if (priv->phydev) {
++                      priv->phydev->supported &= ~(ADVERTISED_Pause |
++                                                      ADVERTISED_Asym_Pause);
++                      priv->phydev->advertising &= ~(ADVERTISED_Pause |
++                                                      ADVERTISED_Asym_Pause);
++              }
++      }
++
++      return 0;
++}
++
++/*
++ * pfe_eth_get_pauseparam - Gets pause parameters
++ *
++ */
++static void pfe_eth_get_pauseparam(struct net_device *ndev,
++                                 struct ethtool_pauseparam *epause)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++
++      epause->autoneg = (priv->pause_flag & PFE_PAUSE_FLAG_AUTONEG) != 0;
++      epause->tx_pause = (priv->pause_flag & PFE_PAUSE_FLAG_ENABLE) != 0;
++      epause->rx_pause = epause->tx_pause;
++}
++
++/*
++ * pfe_eth_get_hash
++ */
++#define PFE_HASH_BITS 6               /* #bits in hash */
++#define CRC32_POLY    0xEDB88320
++
++static int pfe_eth_get_hash(u8 *addr)
++{
++      unsigned int i, bit, data, crc, hash;
++
++      /* calculate crc32 value of mac address */
++      crc = 0xffffffff;
++
++      for (i = 0; i < 6; i++) {
++              data = addr[i];
++              for (bit = 0; bit < 8; bit++, data >>= 1) {
++                      crc = (crc >> 1) ^
++                              (((crc ^ data) & 1) ? CRC32_POLY : 0);
++              }
++      }
++
++      /*
++       * only upper 6 bits (PFE_HASH_BITS) are used
++       * which point to specific bit in the hash registers
++       */
++      hash = (crc >> (32 - PFE_HASH_BITS)) & 0x3f;
++
++      return hash;
++}
++
++const struct ethtool_ops pfe_ethtool_ops = {
++      .get_drvinfo = pfe_eth_get_drvinfo,
++      .get_regs_len = pfe_eth_gemac_reglen,
++      .get_regs = pfe_eth_gemac_get_regs,
++      .get_link = ethtool_op_get_link,
++      .get_wol  = pfe_eth_get_wol,
++      .set_wol  = pfe_eth_set_wol,
++      .set_pauseparam = pfe_eth_set_pauseparam,
++      .get_pauseparam = pfe_eth_get_pauseparam,
++      .get_strings = pfe_eth_gstrings,
++      .get_sset_count = pfe_eth_stats_count,
++      .get_ethtool_stats = pfe_eth_fill_stats,
++      .get_msglevel = pfe_eth_get_msglevel,
++      .set_msglevel = pfe_eth_set_msglevel,
++      .set_coalesce = pfe_eth_set_coalesce,
++      .get_coalesce = pfe_eth_get_coalesce,
++      .get_link_ksettings = pfe_eth_get_settings,
++      .set_link_ksettings = pfe_eth_set_settings,
++};
++
++/* pfe_eth_mdio_reset
++ */
++int pfe_eth_mdio_reset(struct mii_bus *bus)
++{
++      struct pfe_eth_priv_s *priv = (struct pfe_eth_priv_s *)bus->priv;
++      u32 phy_speed;
++
++      netif_info(priv, hw, priv->ndev, "%s\n", __func__);
++
++      mutex_lock(&bus->mdio_lock);
++
++      /*
++       * Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed)
++       *
++       * The formula for FEC MDC is 'ref_freq / (MII_SPEED x 2)' while
++       * for ENET-MAC is 'ref_freq / ((MII_SPEED + 1) x 2)'.
++       */
++      phy_speed = (DIV_ROUND_UP((pfe->ctrl.sys_clk * 1000), 4000000)
++                   << EMAC_MII_SPEED_SHIFT);
++      phy_speed |= EMAC_HOLDTIME(0x5);
++      __raw_writel(phy_speed, priv->PHY_baseaddr + EMAC_MII_CTRL_REG);
++
++      mutex_unlock(&bus->mdio_lock);
++
++      return 0;
++}
++
++/* pfe_eth_gemac_phy_timeout
++ *
++ */
++static int pfe_eth_gemac_phy_timeout(struct pfe_eth_priv_s *priv, int timeout)
++{
++      while (!(__raw_readl(priv->PHY_baseaddr + EMAC_IEVENT_REG) &
++                      EMAC_IEVENT_MII)) {
++              if (timeout-- <= 0)
++                      return -1;
++              usleep_range(10, 20);
++      }
++      __raw_writel(EMAC_IEVENT_MII, priv->PHY_baseaddr + EMAC_IEVENT_REG);
++      return 0;
++}
++
++static int pfe_eth_mdio_mux(u8 muxval)
++{
++      struct i2c_adapter *a;
++      struct i2c_msg msg;
++      unsigned char buf[2];
++      int ret;
++
++      a = i2c_get_adapter(0);
++      if (!a)
++              return -ENODEV;
++
++      /* set bit 1 (the second bit) of chip at 0x09, register 0x13 */
++      buf[0] = 0x54; /* reg number */
++      buf[1] = (muxval << 6) | 0x3; /* data */
++      msg.addr = 0x66;
++      msg.buf = buf;
++      msg.len = 2;
++      msg.flags = 0;
++      ret = i2c_transfer(a, &msg, 1);
++      i2c_put_adapter(a);
++      if (ret != 1)
++              return -ENODEV;
++      return 0;
++}
++
++static int pfe_eth_mdio_write_addr(struct mii_bus *bus, int mii_id,
++                                 int dev_addr, int regnum)
++{
++      struct pfe_eth_priv_s *priv = (struct pfe_eth_priv_s *)bus->priv;
++
++      __raw_writel(EMAC_MII_DATA_PA(mii_id) |
++                   EMAC_MII_DATA_RA(dev_addr) |
++                   EMAC_MII_DATA_TA | EMAC_MII_DATA(regnum),
++                   priv->PHY_baseaddr + EMAC_MII_DATA_REG);
++
++      if (pfe_eth_gemac_phy_timeout(priv, EMAC_MDIO_TIMEOUT)) {
++              netdev_err(priv->ndev, "%s: phy MDIO address write timeout\n",
++                         __func__);
++              return -1;
++      }
++
++      return 0;
++}
++
++static int pfe_eth_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
++                            u16 value)
++{
++      struct pfe_eth_priv_s *priv = (struct pfe_eth_priv_s *)bus->priv;
++
++      /*To access external PHYs on QDS board mux needs to be configured*/
++      if ((mii_id) && (pfe->mdio_muxval[mii_id]))
++              pfe_eth_mdio_mux(pfe->mdio_muxval[mii_id]);
++
++      if (regnum & MII_ADDR_C45) {
++              pfe_eth_mdio_write_addr(bus, mii_id, (regnum >> 16) & 0x1f,
++                                      regnum & 0xffff);
++              __raw_writel(EMAC_MII_DATA_OP_CL45_WR |
++                           EMAC_MII_DATA_PA(mii_id) |
++                           EMAC_MII_DATA_RA((regnum >> 16) & 0x1f) |
++                           EMAC_MII_DATA_TA | EMAC_MII_DATA(value),
++                           priv->PHY_baseaddr + EMAC_MII_DATA_REG);
++      } else {
++              /* start a write op */
++              __raw_writel(EMAC_MII_DATA_ST | EMAC_MII_DATA_OP_WR |
++                           EMAC_MII_DATA_PA(mii_id) |
++                           EMAC_MII_DATA_RA(regnum) |
++                           EMAC_MII_DATA_TA | EMAC_MII_DATA(value),
++                           priv->PHY_baseaddr + EMAC_MII_DATA_REG);
++      }
++
++      if (pfe_eth_gemac_phy_timeout(priv, EMAC_MDIO_TIMEOUT)) {
++              netdev_err(priv->ndev, "%s: phy MDIO write timeout\n",
++                         __func__);
++              return -1;
++      }
++      netif_info(priv, hw, priv->ndev, "%s: phy %x reg %x val %x\n", __func__,
++                 mii_id, regnum, value);
++
++      return 0;
++}
++
++static int pfe_eth_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
++{
++      struct pfe_eth_priv_s *priv = (struct pfe_eth_priv_s *)bus->priv;
++      u16 value = 0;
++
++      /*To access external PHYs on QDS board mux needs to be configured*/
++      if ((mii_id) && (pfe->mdio_muxval[mii_id]))
++              pfe_eth_mdio_mux(pfe->mdio_muxval[mii_id]);
++
++      if (regnum & MII_ADDR_C45) {
++              pfe_eth_mdio_write_addr(bus, mii_id, (regnum >> 16) & 0x1f,
++                                      regnum & 0xffff);
++              __raw_writel(EMAC_MII_DATA_OP_CL45_RD |
++                           EMAC_MII_DATA_PA(mii_id) |
++                           EMAC_MII_DATA_RA((regnum >> 16) & 0x1f) |
++                           EMAC_MII_DATA_TA,
++                           priv->PHY_baseaddr + EMAC_MII_DATA_REG);
++      } else {
++              /* start a read op */
++              __raw_writel(EMAC_MII_DATA_ST | EMAC_MII_DATA_OP_RD |
++                           EMAC_MII_DATA_PA(mii_id) |
++                           EMAC_MII_DATA_RA(regnum) |
++                           EMAC_MII_DATA_TA, priv->PHY_baseaddr +
++                           EMAC_MII_DATA_REG);
++      }
++
++      if (pfe_eth_gemac_phy_timeout(priv, EMAC_MDIO_TIMEOUT)) {
++              netdev_err(priv->ndev, "%s: phy MDIO read timeout\n", __func__);
++              return -1;
++      }
++
++      value = EMAC_MII_DATA(__raw_readl(priv->PHY_baseaddr +
++                                              EMAC_MII_DATA_REG));
++      netif_info(priv, hw, priv->ndev, "%s: phy %x reg %x val %x\n", __func__,
++                 mii_id, regnum, value);
++      return value;
++}
++
++static int pfe_eth_mdio_init(struct pfe_eth_priv_s *priv,
++                           struct ls1012a_mdio_platform_data *minfo)
++{
++      struct mii_bus *bus;
++      int rc;
++
++      netif_info(priv, drv, priv->ndev, "%s\n", __func__);
++      pr_info("%s\n", __func__);
++
++      bus = mdiobus_alloc();
++      if (!bus) {
++              netdev_err(priv->ndev, "mdiobus_alloc() failed\n");
++              rc = -ENOMEM;
++              goto err0;
++      }
++
++      bus->name = "ls1012a MDIO Bus";
++      bus->read = &pfe_eth_mdio_read;
++      bus->write = &pfe_eth_mdio_write;
++      bus->reset = &pfe_eth_mdio_reset;
++      snprintf(bus->id, MII_BUS_ID_SIZE, "ls1012a-%x", priv->id);
++      bus->priv = priv;
++
++      bus->phy_mask = minfo->phy_mask;
++      priv->mdc_div = minfo->mdc_div;
++
++      if (!priv->mdc_div)
++              priv->mdc_div = 64;
++
++      bus->irq[0] = minfo->irq[0];
++
++      bus->parent = priv->pfe->dev;
++
++      netif_info(priv, drv, priv->ndev, "%s: mdc_div: %d, phy_mask: %x\n",
++                 __func__, priv->mdc_div, bus->phy_mask);
++      rc = mdiobus_register(bus);
++      if (rc) {
++              netdev_err(priv->ndev, "mdiobus_register(%s) failed\n",
++                         bus->name);
++              goto err1;
++      }
++
++      priv->mii_bus = bus;
++      pfe_eth_mdio_reset(bus);
++
++      return 0;
++
++err1:
++      mdiobus_free(bus);
++err0:
++      return rc;
++}
++
++/* pfe_eth_mdio_exit
++ */
++static void pfe_eth_mdio_exit(struct mii_bus *bus)
++{
++      if (!bus)
++              return;
++
++      netif_info((struct pfe_eth_priv_s *)bus->priv, drv, ((struct
++                      pfe_eth_priv_s *)(bus->priv))->ndev, "%s\n", __func__);
++
++      mdiobus_unregister(bus);
++      mdiobus_free(bus);
++}
++
++/* pfe_get_phydev_speed
++ */
++static int pfe_get_phydev_speed(struct phy_device *phydev)
++{
++      switch (phydev->speed) {
++      case 10:
++                      return SPEED_10M;
++      case 100:
++                      return SPEED_100M;
++      case 1000:
++      default:
++                      return SPEED_1000M;
++      }
++}
++
++/* pfe_set_rgmii_speed
++ */
++#define RGMIIPCR      0x434
++/* RGMIIPCR bit definitions*/
++#define SCFG_RGMIIPCR_EN_AUTO           (0x00000008)
++#define SCFG_RGMIIPCR_SETSP_1000M       (0x00000004)
++#define SCFG_RGMIIPCR_SETSP_100M        (0x00000000)
++#define SCFG_RGMIIPCR_SETSP_10M         (0x00000002)
++#define SCFG_RGMIIPCR_SETFD             (0x00000001)
++
++static void pfe_set_rgmii_speed(struct phy_device *phydev)
++{
++      u32 rgmii_pcr;
++
++      regmap_read(pfe->scfg, RGMIIPCR, &rgmii_pcr);
++      rgmii_pcr  &= ~(SCFG_RGMIIPCR_SETSP_1000M | SCFG_RGMIIPCR_SETSP_10M);
++
++      switch (phydev->speed) {
++      case 10:
++                      rgmii_pcr |= SCFG_RGMIIPCR_SETSP_10M;
++                      break;
++      case 1000:
++                      rgmii_pcr |= SCFG_RGMIIPCR_SETSP_1000M;
++                      break;
++      case 100:
++      default:
++                      /* Default is 100M */
++                      break;
++      }
++      regmap_write(pfe->scfg, RGMIIPCR, rgmii_pcr);
++}
++
++/* pfe_get_phydev_duplex
++ */
++static int pfe_get_phydev_duplex(struct phy_device *phydev)
++{
++      /*return (phydev->duplex == DUPLEX_HALF) ? DUP_HALF:DUP_FULL ; */
++      return DUPLEX_FULL;
++}
++
++/* pfe_eth_adjust_link
++ */
++static void pfe_eth_adjust_link(struct net_device *ndev)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++      unsigned long flags;
++      struct phy_device *phydev = priv->phydev;
++      int new_state = 0;
++
++      netif_info(priv, drv, ndev, "%s\n", __func__);
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      if (phydev->link) {
++              /*
++               * Now we make sure that we can be in full duplex mode.
++               * If not, we operate in half-duplex mode.
++               */
++              if (phydev->duplex != priv->oldduplex) {
++                      new_state = 1;
++                      gemac_set_duplex(priv->EMAC_baseaddr,
++                                       pfe_get_phydev_duplex(phydev));
++                      priv->oldduplex = phydev->duplex;
++              }
++
++              if (phydev->speed != priv->oldspeed) {
++                      new_state = 1;
++                      gemac_set_speed(priv->EMAC_baseaddr,
++                                      pfe_get_phydev_speed(phydev));
++                      if (priv->einfo->mii_config == PHY_INTERFACE_MODE_RGMII)
++                              pfe_set_rgmii_speed(phydev);
++                      priv->oldspeed = phydev->speed;
++              }
++
++              if (!priv->oldlink) {
++                      new_state = 1;
++                      priv->oldlink = 1;
++              }
++
++      } else if (priv->oldlink) {
++              new_state = 1;
++              priv->oldlink = 0;
++              priv->oldspeed = 0;
++              priv->oldduplex = -1;
++      }
++
++      if (new_state && netif_msg_link(priv))
++              phy_print_status(phydev);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++}
++
++/* pfe_phy_exit
++ */
++static void pfe_phy_exit(struct net_device *ndev)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++
++      netif_info(priv, drv, ndev, "%s\n", __func__);
++
++      phy_disconnect(priv->phydev);
++      priv->phydev = NULL;
++}
++
++/* pfe_eth_stop
++ */
++static void pfe_eth_stop(struct net_device *ndev, int wake)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++
++      netif_info(priv, drv, ndev, "%s\n", __func__);
++
++      if (wake) {
++              gemac_tx_disable(priv->EMAC_baseaddr);
++      } else {
++              gemac_disable(priv->EMAC_baseaddr);
++              gpi_disable(priv->GPI_baseaddr);
++
++              if (priv->phydev)
++                      phy_stop(priv->phydev);
++      }
++}
++
++/* pfe_eth_start
++ */
++static int pfe_eth_start(struct pfe_eth_priv_s *priv)
++{
++      netif_info(priv, drv, priv->ndev, "%s\n", __func__);
++
++      if (priv->phydev)
++              phy_start(priv->phydev);
++
++      gpi_enable(priv->GPI_baseaddr);
++      gemac_enable(priv->EMAC_baseaddr);
++
++      return 0;
++}
++
++/*
++ * Configure on chip serdes through mdio
++ */
++static void ls1012a_configure_serdes(struct net_device *ndev)
++{
++      struct pfe_eth_priv_s *priv = pfe->eth.eth_priv[0];
++      int sgmii_2500 = 0;
++      struct mii_bus *bus = priv->mii_bus;
++
++      if (priv->einfo->mii_config == PHY_INTERFACE_MODE_SGMII_2500)
++              sgmii_2500 = 1;
++
++      netif_info(priv, drv, ndev, "%s\n", __func__);
++      /* PCS configuration done with corresponding GEMAC */
++
++      pfe_eth_mdio_read(bus, 0, 0);
++      pfe_eth_mdio_read(bus, 0, 1);
++
++       /*These settings taken from validtion team */
++      pfe_eth_mdio_write(bus, 0, 0x0, 0x8000);
++      if (sgmii_2500) {
++              pfe_eth_mdio_write(bus, 0, 0x14, 0x9);
++              pfe_eth_mdio_write(bus, 0, 0x4, 0x4001);
++              pfe_eth_mdio_write(bus, 0, 0x12, 0xa120);
++              pfe_eth_mdio_write(bus, 0, 0x13, 0x7);
++      } else {
++              pfe_eth_mdio_write(bus, 0, 0x14, 0xb);
++              pfe_eth_mdio_write(bus, 0, 0x4, 0x1a1);
++              pfe_eth_mdio_write(bus, 0, 0x12, 0x400);
++              pfe_eth_mdio_write(bus, 0, 0x13, 0x0);
++      }
++
++      pfe_eth_mdio_write(bus, 0, 0x0, 0x1140);
++}
++
++/*
++ * pfe_phy_init
++ *
++ */
++static int pfe_phy_init(struct net_device *ndev)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++      struct phy_device *phydev;
++      char phy_id[MII_BUS_ID_SIZE + 3];
++      char bus_id[MII_BUS_ID_SIZE];
++      phy_interface_t interface;
++
++      priv->oldlink = 0;
++      priv->oldspeed = 0;
++      priv->oldduplex = -1;
++
++      snprintf(bus_id, MII_BUS_ID_SIZE, "ls1012a-%d", 0);
++      snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
++               priv->einfo->phy_id);
++
++      netif_info(priv, drv, ndev, "%s: %s\n", __func__, phy_id);
++      interface = priv->einfo->mii_config;
++      if ((interface == PHY_INTERFACE_MODE_SGMII) ||
++          (interface == PHY_INTERFACE_MODE_SGMII_2500)) {
++              /*Configure SGMII PCS */
++              if (pfe->scfg) {
++                      /*Config MDIO from serdes */
++                      regmap_write(pfe->scfg, 0x484, 0x00000000);
++              }
++              ls1012a_configure_serdes(ndev);
++      }
++
++      if (pfe->scfg) {
++              /*Config MDIO from PAD */
++              regmap_write(pfe->scfg, 0x484, 0x80000000);
++      }
++
++      priv->oldlink = 0;
++      priv->oldspeed = 0;
++      priv->oldduplex = -1;
++      pr_info("%s interface %x\n", __func__, interface);
++      phydev = phy_connect(ndev, phy_id, &pfe_eth_adjust_link, interface);
++
++      if (IS_ERR(phydev)) {
++              netdev_err(ndev, "phy_connect() failed\n");
++              return PTR_ERR(phydev);
++      }
++
++      priv->phydev = phydev;
++      phydev->irq = PHY_POLL;
++
++      return 0;
++}
++
++/* pfe_gemac_init
++ */
++static int pfe_gemac_init(struct pfe_eth_priv_s *priv)
++{
++      struct gemac_cfg cfg;
++
++      netif_info(priv, ifup, priv->ndev, "%s\n", __func__);
++
++      cfg.speed = SPEED_1000M;
++      cfg.duplex = DUPLEX_FULL;
++
++      gemac_set_config(priv->EMAC_baseaddr, &cfg);
++      gemac_allow_broadcast(priv->EMAC_baseaddr);
++      gemac_enable_1536_rx(priv->EMAC_baseaddr);
++      gemac_enable_rx_jmb(priv->EMAC_baseaddr);
++      gemac_enable_stacked_vlan(priv->EMAC_baseaddr);
++      gemac_enable_pause_rx(priv->EMAC_baseaddr);
++      gemac_set_bus_width(priv->EMAC_baseaddr, 64);
++
++      /*GEM will perform checksum verifications*/
++      if (priv->ndev->features & NETIF_F_RXCSUM)
++              gemac_enable_rx_checksum_offload(priv->EMAC_baseaddr);
++      else
++              gemac_disable_rx_checksum_offload(priv->EMAC_baseaddr);
++
++      return 0;
++}
++
++/* pfe_eth_event_handler
++ */
++static int pfe_eth_event_handler(void *data, int event, int qno)
++{
++      struct pfe_eth_priv_s *priv = data;
++
++      switch (event) {
++      case EVENT_RX_PKT_IND:
++
++              if (qno == 0) {
++                      if (napi_schedule_prep(&priv->high_napi)) {
++                              netif_info(priv, intr, priv->ndev,
++                                         "%s: schedule high prio poll\n"
++                                         , __func__);
++
++#ifdef PFE_ETH_NAPI_STATS
++                              priv->napi_counters[NAPI_SCHED_COUNT]++;
++#endif
++
++                              __napi_schedule(&priv->high_napi);
++                      }
++              } else if (qno == 1) {
++                      if (napi_schedule_prep(&priv->low_napi)) {
++                              netif_info(priv, intr, priv->ndev,
++                                         "%s: schedule low prio poll\n"
++                                         , __func__);
++
++#ifdef PFE_ETH_NAPI_STATS
++                              priv->napi_counters[NAPI_SCHED_COUNT]++;
++#endif
++                              __napi_schedule(&priv->low_napi);
++                      }
++              } else if (qno == 2) {
++                      if (napi_schedule_prep(&priv->lro_napi)) {
++                              netif_info(priv, intr, priv->ndev,
++                                         "%s: schedule lro prio poll\n"
++                                         , __func__);
++
++#ifdef PFE_ETH_NAPI_STATS
++                              priv->napi_counters[NAPI_SCHED_COUNT]++;
++#endif
++                              __napi_schedule(&priv->lro_napi);
++                      }
++              }
++
++              break;
++
++      case EVENT_TXDONE_IND:
++              pfe_eth_flush_tx(priv);
++              hif_lib_event_handler_start(&priv->client, EVENT_TXDONE_IND, 0);
++              break;
++      case EVENT_HIGH_RX_WM:
++      default:
++              break;
++      }
++
++      return 0;
++}
++
++/* pfe_eth_open
++ */
++static int pfe_eth_open(struct net_device *ndev)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++      struct hif_client_s *client;
++      int rc;
++
++      netif_info(priv, ifup, ndev, "%s\n", __func__);
++
++      /* Register client driver with HIF */
++      client = &priv->client;
++      memset(client, 0, sizeof(*client));
++      client->id = PFE_CL_GEM0 + priv->id;
++      client->tx_qn = emac_txq_cnt;
++      client->rx_qn = EMAC_RXQ_CNT;
++      client->priv = priv;
++      client->pfe = priv->pfe;
++      client->event_handler = pfe_eth_event_handler;
++
++      client->tx_qsize = EMAC_TXQ_DEPTH;
++      client->rx_qsize = EMAC_RXQ_DEPTH;
++
++      rc = hif_lib_client_register(client);
++      if (rc) {
++              netdev_err(ndev, "%s: hif_lib_client_register(%d) failed\n",
++                         __func__, client->id);
++              goto err0;
++      }
++
++      netif_info(priv, drv, ndev, "%s: registered client: %p\n", __func__,
++                 client);
++
++      pfe_gemac_init(priv);
++
++      if (!is_valid_ether_addr(ndev->dev_addr)) {
++              netdev_err(ndev, "%s: invalid MAC address\n", __func__);
++              rc = -EADDRNOTAVAIL;
++              goto err1;
++      }
++
++      gemac_set_laddrN(priv->EMAC_baseaddr,
++                       (struct pfe_mac_addr *)ndev->dev_addr, 1);
++
++      napi_enable(&priv->high_napi);
++      napi_enable(&priv->low_napi);
++      napi_enable(&priv->lro_napi);
++
++      rc = pfe_eth_start(priv);
++
++      netif_tx_wake_all_queues(ndev);
++
++      return rc;
++
++err1:
++      hif_lib_client_unregister(&priv->client);
++
++err0:
++      return rc;
++}
++
++/*
++ *  pfe_eth_shutdown
++ */
++int pfe_eth_shutdown(struct net_device *ndev, int wake)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++      int i, qstatus;
++      unsigned long next_poll = jiffies + 1, end = jiffies +
++                              (TX_POLL_TIMEOUT_MS * HZ) / 1000;
++      int tx_pkts, prv_tx_pkts;
++
++      netif_info(priv, ifdown, ndev, "%s\n", __func__);
++
++      for (i = 0; i < emac_txq_cnt; i++)
++              hrtimer_cancel(&priv->fast_tx_timeout[i].timer);
++
++      netif_tx_stop_all_queues(ndev);
++
++      do {
++              tx_pkts = 0;
++              pfe_eth_flush_tx(priv);
++
++              for (i = 0; i < emac_txq_cnt; i++)
++                      tx_pkts += hif_lib_tx_pending(&priv->client, i);
++
++              if (tx_pkts) {
++                      /*Don't wait forever, break if we cross max timeout */
++                      if (time_after(jiffies, end)) {
++                              pr_err(
++                                      "(%s)Tx is not complete after %dmsec\n",
++                                      ndev->name, TX_POLL_TIMEOUT_MS);
++                              break;
++                      }
++
++                      pr_info("%s : (%s) Waiting for tx packets to free. Pending tx pkts = %d.\n"
++                              , __func__, ndev->name, tx_pkts);
++                      if (need_resched())
++                              schedule();
++              }
++
++      } while (tx_pkts);
++
++      end = jiffies + (TX_POLL_TIMEOUT_MS * HZ) / 1000;
++
++      prv_tx_pkts = tmu_pkts_processed(priv->id);
++      /*
++       * Wait till TMU transmits all pending packets
++       * poll tmu_qstatus and pkts processed by TMU for every 10ms
++       * Consider TMU is busy, If we see TMU qeueu pending or any packets
++       * processed by TMU
++       */
++      while (1) {
++              if (time_after(jiffies, next_poll)) {
++                      tx_pkts = tmu_pkts_processed(priv->id);
++                      qstatus = tmu_qstatus(priv->id) & 0x7ffff;
++
++                      if (!qstatus && (tx_pkts == prv_tx_pkts))
++                              break;
++                      /* Don't wait forever, break if we cross max
++                       * timeout(TX_POLL_TIMEOUT_MS)
++                       */
++                      if (time_after(jiffies, end)) {
++                              pr_err("TMU%d is busy after %dmsec\n",
++                                     priv->id, TX_POLL_TIMEOUT_MS);
++                              break;
++                      }
++                      prv_tx_pkts = tx_pkts;
++                      next_poll++;
++              }
++              if (need_resched())
++                      schedule();
++      }
++      /* Wait for some more time to complete transmitting packet if any */
++      next_poll = jiffies + 1;
++      while (1) {
++              if (time_after(jiffies, next_poll))
++                      break;
++              if (need_resched())
++                      schedule();
++      }
++
++      pfe_eth_stop(ndev, wake);
++
++      napi_disable(&priv->lro_napi);
++      napi_disable(&priv->low_napi);
++      napi_disable(&priv->high_napi);
++
++      hif_lib_client_unregister(&priv->client);
++
++      return 0;
++}
++
++/* pfe_eth_close
++ *
++ */
++static int pfe_eth_close(struct net_device *ndev)
++{
++      pfe_eth_shutdown(ndev, 0);
++
++      return 0;
++}
++
++/* pfe_eth_suspend
++ *
++ * return value : 1 if netdevice is configured to wakeup system
++ *                0 otherwise
++ */
++int pfe_eth_suspend(struct net_device *ndev)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++      int retval = 0;
++
++      if (priv->wol) {
++              gemac_set_wol(priv->EMAC_baseaddr, priv->wol);
++              retval = 1;
++      }
++      pfe_eth_shutdown(ndev, priv->wol);
++
++      return retval;
++}
++
++/* pfe_eth_resume
++ *
++ */
++int pfe_eth_resume(struct net_device *ndev)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++
++      if (priv->wol)
++              gemac_set_wol(priv->EMAC_baseaddr, 0);
++      gemac_tx_enable(priv->EMAC_baseaddr);
++
++      return pfe_eth_open(ndev);
++}
++
++/* pfe_eth_get_queuenum
++ */
++static int pfe_eth_get_queuenum(struct pfe_eth_priv_s *priv, struct sk_buff
++                                      *skb)
++{
++      int queuenum = 0;
++      unsigned long flags;
++
++      /* Get the Fast Path queue number */
++      /*
++       * Use conntrack mark (if conntrack exists), then packet mark (if any),
++       * then fallback to default
++       */
++#if defined(CONFIG_IP_NF_CONNTRACK_MARK) || defined(CONFIG_NF_CONNTRACK_MARK)
++      if (skb->_nfct) {
++              enum ip_conntrack_info cinfo;
++              struct nf_conn *ct;
++
++              ct = nf_ct_get(skb, &cinfo);
++
++              if (ct) {
++                      u32 connmark;
++
++                      connmark = ct->mark;
++
++                      if ((connmark & 0x80000000) && priv->id != 0)
++                              connmark >>= 16;
++
++                      queuenum = connmark & EMAC_QUEUENUM_MASK;
++              }
++      } else  {/* continued after #endif ... */
++#endif
++              if (skb->mark) {
++                      queuenum = skb->mark & EMAC_QUEUENUM_MASK;
++              } else {
++                      spin_lock_irqsave(&priv->lock, flags);
++                      queuenum = priv->default_priority & EMAC_QUEUENUM_MASK;
++                      spin_unlock_irqrestore(&priv->lock, flags);
++              }
++#if defined(CONFIG_IP_NF_CONNTRACK_MARK) || defined(CONFIG_NF_CONNTRACK_MARK)
++      }
++#endif
++      return queuenum;
++}
++
++/* pfe_eth_might_stop_tx
++ *
++ */
++static int pfe_eth_might_stop_tx(struct pfe_eth_priv_s *priv, int queuenum,
++                               struct netdev_queue *tx_queue,
++                               unsigned int n_desc,
++                               unsigned int n_segs)
++{
++      ktime_t kt;
++
++      if (unlikely((__hif_tx_avail(&pfe->hif) < n_desc) ||
++                   (hif_lib_tx_avail(&priv->client, queuenum) < n_desc) ||
++      (hif_lib_tx_credit_avail(pfe, priv->id, queuenum) < n_segs))) {
++#ifdef PFE_ETH_TX_STATS
++              if (__hif_tx_avail(&pfe->hif) < n_desc) {
++                      priv->stop_queue_hif[queuenum]++;
++              } else if (hif_lib_tx_avail(&priv->client, queuenum) < n_desc) {
++                      priv->stop_queue_hif_client[queuenum]++;
++              } else if (hif_lib_tx_credit_avail(pfe, priv->id, queuenum) <
++                      n_segs) {
++                      priv->stop_queue_credit[queuenum]++;
++              }
++              priv->stop_queue_total[queuenum]++;
++#endif
++              netif_tx_stop_queue(tx_queue);
++
++              kt = ktime_set(0, LS1012A_TX_FAST_RECOVERY_TIMEOUT_MS *
++                              NSEC_PER_MSEC);
++              hrtimer_start(&priv->fast_tx_timeout[queuenum].timer, kt,
++                            HRTIMER_MODE_REL);
++              return -1;
++      } else {
++              return 0;
++      }
++}
++
++#define SA_MAX_OP 2
++/* pfe_hif_send_packet
++ *
++ * At this level if TX fails we drop the packet
++ */
++static void pfe_hif_send_packet(struct sk_buff *skb, struct  pfe_eth_priv_s
++                                      *priv, int queuenum)
++{
++      struct skb_shared_info *sh = skb_shinfo(skb);
++      unsigned int nr_frags;
++      u32 ctrl = 0;
++
++      netif_info(priv, tx_queued, priv->ndev, "%s\n", __func__);
++
++      if (skb_is_gso(skb)) {
++              priv->stats.tx_dropped++;
++              return;
++      }
++
++      if (skb->ip_summed == CHECKSUM_PARTIAL)
++              ctrl = HIF_CTRL_TX_CHECKSUM;
++
++      nr_frags = sh->nr_frags;
++
++      if (nr_frags) {
++              skb_frag_t *f;
++              int i;
++
++              __hif_lib_xmit_pkt(&priv->client, queuenum, skb->data,
++                                 skb_headlen(skb), ctrl, HIF_FIRST_BUFFER,
++                                 skb);
++
++              for (i = 0; i < nr_frags - 1; i++) {
++                      f = &sh->frags[i];
++                      __hif_lib_xmit_pkt(&priv->client, queuenum,
++                                         skb_frag_address(f),
++                                         skb_frag_size(f),
++                                         0x0, 0x0, skb);
++              }
++
++              f = &sh->frags[i];
++
++              __hif_lib_xmit_pkt(&priv->client, queuenum,
++                                 skb_frag_address(f), skb_frag_size(f),
++                                 0x0, HIF_LAST_BUFFER | HIF_DATA_VALID,
++                                 skb);
++
++              netif_info(priv, tx_queued, priv->ndev,
++                         "%s: pkt sent successfully skb:%p nr_frags:%d len:%d\n",
++                         __func__, skb, nr_frags, skb->len);
++      } else {
++              __hif_lib_xmit_pkt(&priv->client, queuenum, skb->data,
++                                 skb->len, ctrl, HIF_FIRST_BUFFER |
++                                 HIF_LAST_BUFFER | HIF_DATA_VALID,
++                                 skb);
++              netif_info(priv, tx_queued, priv->ndev,
++                         "%s: pkt sent successfully skb:%p len:%d\n",
++                         __func__, skb, skb->len);
++      }
++      hif_tx_dma_start();
++      priv->stats.tx_packets++;
++      priv->stats.tx_bytes += skb->len;
++      hif_lib_tx_credit_use(pfe, priv->id, queuenum, 1);
++}
++
++/* pfe_eth_flush_txQ
++ */
++static void pfe_eth_flush_txQ(struct pfe_eth_priv_s *priv, int tx_q_num, int
++                              from_tx, int n_desc)
++{
++      struct sk_buff *skb;
++      struct netdev_queue *tx_queue = netdev_get_tx_queue(priv->ndev,
++                                                              tx_q_num);
++      unsigned int flags;
++
++      netif_info(priv, tx_done, priv->ndev, "%s\n", __func__);
++
++      if (!from_tx)
++              __netif_tx_lock_bh(tx_queue);
++
++      /* Clean HIF and client queue */
++      while ((skb = hif_lib_tx_get_next_complete(&priv->client,
++                                                 tx_q_num, &flags,
++                                                 HIF_TX_DESC_NT))) {
++              if (flags & HIF_DATA_VALID)
++                      dev_kfree_skb_any(skb);
++      }
++      if (!from_tx)
++              __netif_tx_unlock_bh(tx_queue);
++}
++
++/* pfe_eth_flush_tx
++ */
++static void pfe_eth_flush_tx(struct pfe_eth_priv_s *priv)
++{
++      int ii;
++
++      netif_info(priv, tx_done, priv->ndev, "%s\n", __func__);
++
++      for (ii = 0; ii < emac_txq_cnt; ii++)
++              pfe_eth_flush_txQ(priv, ii, 0, 0);
++}
++
++void pfe_tx_get_req_desc(struct sk_buff *skb, unsigned int *n_desc, unsigned int
++                              *n_segs)
++{
++      struct skb_shared_info *sh = skb_shinfo(skb);
++
++      /* Scattered data */
++      if (sh->nr_frags) {
++              *n_desc = sh->nr_frags + 1;
++              *n_segs = 1;
++      /* Regular case */
++      } else {
++              *n_desc = 1;
++              *n_segs = 1;
++      }
++}
++
++/* pfe_eth_send_packet
++ */
++static int pfe_eth_send_packet(struct sk_buff *skb, struct net_device *ndev)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++      int tx_q_num = skb_get_queue_mapping(skb);
++      int n_desc, n_segs;
++      struct netdev_queue *tx_queue = netdev_get_tx_queue(priv->ndev,
++                                                              tx_q_num);
++
++      netif_info(priv, tx_queued, ndev, "%s\n", __func__);
++
++      if ((!skb_is_gso(skb)) && (skb_headroom(skb) < (PFE_PKT_HEADER_SZ +
++                      sizeof(unsigned long)))) {
++              netif_warn(priv, tx_err, priv->ndev, "%s: copying skb\n",
++                         __func__);
++
++              if (pskb_expand_head(skb, (PFE_PKT_HEADER_SZ + sizeof(unsigned
++                                      long)), 0, GFP_ATOMIC)) {
++                      /* No need to re-transmit, no way to recover*/
++                      kfree_skb(skb);
++                      priv->stats.tx_dropped++;
++                      return NETDEV_TX_OK;
++              }
++      }
++
++      pfe_tx_get_req_desc(skb, &n_desc, &n_segs);
++
++      hif_tx_lock(&pfe->hif);
++      if (unlikely(pfe_eth_might_stop_tx(priv, tx_q_num, tx_queue, n_desc,
++                                         n_segs))) {
++#ifdef PFE_ETH_TX_STATS
++              if (priv->was_stopped[tx_q_num]) {
++                      priv->clean_fail[tx_q_num]++;
++                      priv->was_stopped[tx_q_num] = 0;
++              }
++#endif
++              hif_tx_unlock(&pfe->hif);
++              return NETDEV_TX_BUSY;
++      }
++
++      pfe_hif_send_packet(skb, priv, tx_q_num);
++
++      hif_tx_unlock(&pfe->hif);
++
++      tx_queue->trans_start = jiffies;
++
++#ifdef PFE_ETH_TX_STATS
++      priv->was_stopped[tx_q_num] = 0;
++#endif
++
++      return NETDEV_TX_OK;
++}
++
++/* pfe_eth_select_queue
++ *
++ */
++static u16 pfe_eth_select_queue(struct net_device *ndev, struct sk_buff *skb,
++                              struct net_device *sb_dev,
++                              select_queue_fallback_t fallback)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++
++      return pfe_eth_get_queuenum(priv, skb);
++}
++
++/* pfe_eth_get_stats
++ */
++static struct net_device_stats *pfe_eth_get_stats(struct net_device *ndev)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++
++      netif_info(priv, drv, ndev, "%s\n", __func__);
++
++      return &priv->stats;
++}
++
++/* pfe_eth_set_mac_address
++ */
++static int pfe_eth_set_mac_address(struct net_device *ndev, void *addr)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++      struct sockaddr *sa = addr;
++
++      netif_info(priv, drv, ndev, "%s\n", __func__);
++
++      if (!is_valid_ether_addr(sa->sa_data))
++              return -EADDRNOTAVAIL;
++
++      memcpy(ndev->dev_addr, sa->sa_data, ETH_ALEN);
++
++      gemac_set_laddrN(priv->EMAC_baseaddr,
++                       (struct pfe_mac_addr *)ndev->dev_addr, 1);
++
++      return 0;
++}
++
++/* pfe_eth_enet_addr_byte_mac
++ */
++int pfe_eth_enet_addr_byte_mac(u8 *enet_byte_addr,
++                             struct pfe_mac_addr *enet_addr)
++{
++      if (!enet_byte_addr || !enet_addr) {
++              return -1;
++
++      } else {
++              enet_addr->bottom = enet_byte_addr[0] |
++                      (enet_byte_addr[1] << 8) |
++                      (enet_byte_addr[2] << 16) |
++                      (enet_byte_addr[3] << 24);
++              enet_addr->top = enet_byte_addr[4] |
++                      (enet_byte_addr[5] << 8);
++              return 0;
++      }
++}
++
++/* pfe_eth_set_multi
++ */
++static void pfe_eth_set_multi(struct net_device *ndev)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++      struct pfe_mac_addr    hash_addr; /* hash register structure */
++      /* specific mac address register structure */
++      struct pfe_mac_addr    spec_addr;
++      int             result; /* index into hash register to set.. */
++      int             uc_count = 0;
++      struct netdev_hw_addr *ha;
++
++      if (ndev->flags & IFF_PROMISC) {
++              netif_info(priv, drv, ndev, "entering promiscuous mode\n");
++
++              priv->promisc = 1;
++              gemac_enable_copy_all(priv->EMAC_baseaddr);
++      } else {
++              priv->promisc = 0;
++              gemac_disable_copy_all(priv->EMAC_baseaddr);
++      }
++
++      /* Enable broadcast frame reception if required. */
++      if (ndev->flags & IFF_BROADCAST) {
++              gemac_allow_broadcast(priv->EMAC_baseaddr);
++      } else {
++              netif_info(priv, drv, ndev,
++                         "disabling broadcast frame reception\n");
++
++              gemac_no_broadcast(priv->EMAC_baseaddr);
++      }
++
++      if (ndev->flags & IFF_ALLMULTI) {
++              /* Set the hash to rx all multicast frames */
++              hash_addr.bottom = 0xFFFFFFFF;
++              hash_addr.top = 0xFFFFFFFF;
++              gemac_set_hash(priv->EMAC_baseaddr, &hash_addr);
++              netdev_for_each_uc_addr(ha, ndev) {
++                      if (uc_count >= MAX_UC_SPEC_ADDR_REG)
++                              break;
++                      pfe_eth_enet_addr_byte_mac(ha->addr, &spec_addr);
++                      gemac_set_laddrN(priv->EMAC_baseaddr, &spec_addr,
++                                       uc_count + 2);
++                      uc_count++;
++              }
++      } else if ((netdev_mc_count(ndev) > 0)  || (netdev_uc_count(ndev))) {
++              u8 *addr;
++
++              hash_addr.bottom = 0;
++              hash_addr.top = 0;
++
++              netdev_for_each_mc_addr(ha, ndev) {
++                      addr = ha->addr;
++
++                      netif_info(priv, drv, ndev,
++                                 "adding multicast address %X:%X:%X:%X:%X:%X to gem filter\n",
++                              addr[0], addr[1], addr[2],
++                              addr[3], addr[4], addr[5]);
++
++                      result = pfe_eth_get_hash(addr);
++
++                      if (result < EMAC_HASH_REG_BITS) {
++                              if (result < 32)
++                                      hash_addr.bottom |= (1 << result);
++                              else
++                                      hash_addr.top |= (1 << (result - 32));
++                      } else {
++                              break;
++                      }
++              }
++
++              uc_count = -1;
++              netdev_for_each_uc_addr(ha, ndev) {
++                      addr = ha->addr;
++
++                      if (++uc_count < MAX_UC_SPEC_ADDR_REG)   {
++                              netdev_info(ndev,
++                                          "adding unicast address %02x:%02x:%02x:%02x:%02x:%02x to gem filter\n",
++                                          addr[0], addr[1], addr[2],
++                                          addr[3], addr[4], addr[5]);
++                              pfe_eth_enet_addr_byte_mac(addr, &spec_addr);
++                              gemac_set_laddrN(priv->EMAC_baseaddr,
++                                               &spec_addr, uc_count + 2);
++                      } else {
++                              netif_info(priv, drv, ndev,
++                                         "adding unicast address %02x:%02x:%02x:%02x:%02x:%02x to gem hash\n",
++                                         addr[0], addr[1], addr[2],
++                                         addr[3], addr[4], addr[5]);
++
++                              result = pfe_eth_get_hash(addr);
++                              if (result >= EMAC_HASH_REG_BITS) {
++                                      break;
++
++                              } else {
++                                      if (result < 32)
++                                              hash_addr.bottom |= (1 <<
++                                                              result);
++                                      else
++                                              hash_addr.top |= (1 <<
++                                                              (result - 32));
++                              }
++                      }
++              }
++
++              gemac_set_hash(priv->EMAC_baseaddr, &hash_addr);
++      }
++
++      if (!(netdev_uc_count(ndev) >= MAX_UC_SPEC_ADDR_REG)) {
++              /*
++               *  Check if there are any specific address HW registers that
++               * need to be flushed
++               */
++              for (uc_count = netdev_uc_count(ndev); uc_count <
++                      MAX_UC_SPEC_ADDR_REG; uc_count++)
++                      gemac_clear_laddrN(priv->EMAC_baseaddr, uc_count + 2);
++      }
++
++      if (ndev->flags & IFF_LOOPBACK)
++              gemac_set_loop(priv->EMAC_baseaddr, LB_LOCAL);
++}
++
++/* pfe_eth_set_features
++ */
++static int pfe_eth_set_features(struct net_device *ndev, netdev_features_t
++                                      features)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++      int rc = 0;
++
++      if (features & NETIF_F_RXCSUM)
++              gemac_enable_rx_checksum_offload(priv->EMAC_baseaddr);
++      else
++              gemac_disable_rx_checksum_offload(priv->EMAC_baseaddr);
++      return rc;
++}
++
++/* pfe_eth_fast_tx_timeout
++ */
++static enum hrtimer_restart pfe_eth_fast_tx_timeout(struct hrtimer *timer)
++{
++      struct pfe_eth_fast_timer *fast_tx_timeout = container_of(timer, struct
++                                                      pfe_eth_fast_timer,
++                                                      timer);
++      struct pfe_eth_priv_s *priv =  container_of(fast_tx_timeout->base,
++                                                      struct pfe_eth_priv_s,
++                                                      fast_tx_timeout);
++      struct netdev_queue *tx_queue = netdev_get_tx_queue(priv->ndev,
++                                              fast_tx_timeout->queuenum);
++
++      if (netif_tx_queue_stopped(tx_queue)) {
++#ifdef PFE_ETH_TX_STATS
++              priv->was_stopped[fast_tx_timeout->queuenum] = 1;
++#endif
++              netif_tx_wake_queue(tx_queue);
++      }
++
++      return HRTIMER_NORESTART;
++}
++
++/* pfe_eth_fast_tx_timeout_init
++ */
++static void pfe_eth_fast_tx_timeout_init(struct pfe_eth_priv_s *priv)
++{
++      int i;
++
++      for (i = 0; i < emac_txq_cnt; i++) {
++              priv->fast_tx_timeout[i].queuenum = i;
++              hrtimer_init(&priv->fast_tx_timeout[i].timer, CLOCK_MONOTONIC,
++                           HRTIMER_MODE_REL);
++              priv->fast_tx_timeout[i].timer.function =
++                              pfe_eth_fast_tx_timeout;
++              priv->fast_tx_timeout[i].base = priv->fast_tx_timeout;
++      }
++}
++
++static struct sk_buff *pfe_eth_rx_skb(struct net_device *ndev,
++                                    struct    pfe_eth_priv_s *priv,
++                                    unsigned int qno)
++{
++      void *buf_addr;
++      unsigned int rx_ctrl;
++      unsigned int desc_ctrl = 0;
++      struct hif_ipsec_hdr *ipsec_hdr = NULL;
++      struct sk_buff *skb;
++      struct sk_buff *skb_frag, *skb_frag_last = NULL;
++      int length = 0, offset;
++
++      skb = priv->skb_inflight[qno];
++
++      if (skb) {
++              skb_frag_last = skb_shinfo(skb)->frag_list;
++              if (skb_frag_last) {
++                      while (skb_frag_last->next)
++                              skb_frag_last = skb_frag_last->next;
++              }
++      }
++
++      while (!(desc_ctrl & CL_DESC_LAST)) {
++              buf_addr = hif_lib_receive_pkt(&priv->client, qno, &length,
++                                             &offset, &rx_ctrl, &desc_ctrl,
++                                             (void **)&ipsec_hdr);
++              if (!buf_addr)
++                      goto incomplete;
++
++#ifdef PFE_ETH_NAPI_STATS
++              priv->napi_counters[NAPI_DESC_COUNT]++;
++#endif
++
++              /* First frag */
++              if (desc_ctrl & CL_DESC_FIRST) {
++                      skb = build_skb(buf_addr, 0);
++                      if (unlikely(!skb))
++                              goto pkt_drop;
++
++                      skb_reserve(skb, offset);
++                      skb_put(skb, length);
++                      skb->dev = ndev;
++
++                      if ((ndev->features & NETIF_F_RXCSUM) && (rx_ctrl &
++                                      HIF_CTRL_RX_CHECKSUMMED))
++                              skb->ip_summed = CHECKSUM_UNNECESSARY;
++                      else
++                              skb_checksum_none_assert(skb);
++
++              } else {
++                      /* Next frags */
++                      if (unlikely(!skb)) {
++                              pr_err("%s: NULL skb_inflight\n",
++                                     __func__);
++                              goto pkt_drop;
++                      }
++
++                      skb_frag = build_skb(buf_addr, 0);
++
++                      if (unlikely(!skb_frag)) {
++                              kfree(buf_addr);
++                              goto pkt_drop;
++                      }
++
++                      skb_reserve(skb_frag, offset);
++                      skb_put(skb_frag, length);
++
++                      skb_frag->dev = ndev;
++
++                      if (skb_shinfo(skb)->frag_list)
++                              skb_frag_last->next = skb_frag;
++                      else
++                              skb_shinfo(skb)->frag_list = skb_frag;
++
++                      skb->truesize += skb_frag->truesize;
++                      skb->data_len += length;
++                      skb->len += length;
++                      skb_frag_last = skb_frag;
++              }
++      }
++
++      priv->skb_inflight[qno] = NULL;
++      return skb;
++
++incomplete:
++      priv->skb_inflight[qno] = skb;
++      return NULL;
++
++pkt_drop:
++      priv->skb_inflight[qno] = NULL;
++
++      if (skb)
++              kfree_skb(skb);
++      else
++              kfree(buf_addr);
++
++      priv->stats.rx_errors++;
++
++      return NULL;
++}
++
++/* pfe_eth_poll
++ */
++static int pfe_eth_poll(struct pfe_eth_priv_s *priv, struct napi_struct *napi,
++                      unsigned int qno, int budget)
++{
++      struct net_device *ndev = priv->ndev;
++      struct sk_buff *skb;
++      int work_done = 0;
++      unsigned int len;
++
++      netif_info(priv, intr, priv->ndev, "%s\n", __func__);
++
++#ifdef PFE_ETH_NAPI_STATS
++      priv->napi_counters[NAPI_POLL_COUNT]++;
++#endif
++
++      do {
++              skb = pfe_eth_rx_skb(ndev, priv, qno);
++
++              if (!skb)
++                      break;
++
++              len = skb->len;
++
++              /* Packet will be processed */
++              skb->protocol = eth_type_trans(skb, ndev);
++
++              netif_receive_skb(skb);
++
++              priv->stats.rx_packets++;
++              priv->stats.rx_bytes += len;
++
++              work_done++;
++
++#ifdef PFE_ETH_NAPI_STATS
++              priv->napi_counters[NAPI_PACKET_COUNT]++;
++#endif
++
++      } while (work_done < budget);
++
++      /*
++       * If no Rx receive nor cleanup work was done, exit polling mode.
++       * No more netif_running(dev) check is required here , as this is
++       * checked in net/core/dev.c (2.6.33.5 kernel specific).
++       */
++      if (work_done < budget) {
++              napi_complete(napi);
++
++              hif_lib_event_handler_start(&priv->client, EVENT_RX_PKT_IND,
++                                          qno);
++      }
++#ifdef PFE_ETH_NAPI_STATS
++      else
++              priv->napi_counters[NAPI_FULL_BUDGET_COUNT]++;
++#endif
++
++      return work_done;
++}
++
++/*
++ * pfe_eth_lro_poll
++ */
++static int pfe_eth_lro_poll(struct napi_struct *napi, int budget)
++{
++      struct pfe_eth_priv_s *priv = container_of(napi, struct pfe_eth_priv_s,
++                                                      lro_napi);
++
++      netif_info(priv, intr, priv->ndev, "%s\n", __func__);
++
++      return pfe_eth_poll(priv, napi, 2, budget);
++}
++
++/* pfe_eth_low_poll
++ */
++static int pfe_eth_low_poll(struct napi_struct *napi, int budget)
++{
++      struct pfe_eth_priv_s *priv = container_of(napi, struct pfe_eth_priv_s,
++                                                      low_napi);
++
++      netif_info(priv, intr, priv->ndev, "%s\n", __func__);
++
++      return pfe_eth_poll(priv, napi, 1, budget);
++}
++
++/* pfe_eth_high_poll
++ */
++static int pfe_eth_high_poll(struct napi_struct *napi, int budget)
++{
++      struct pfe_eth_priv_s *priv = container_of(napi, struct pfe_eth_priv_s,
++                                                      high_napi);
++
++      netif_info(priv, intr, priv->ndev, "%s\n", __func__);
++
++      return pfe_eth_poll(priv, napi, 0, budget);
++}
++
++static const struct net_device_ops pfe_netdev_ops = {
++      .ndo_open = pfe_eth_open,
++      .ndo_stop = pfe_eth_close,
++      .ndo_start_xmit = pfe_eth_send_packet,
++      .ndo_select_queue = pfe_eth_select_queue,
++      .ndo_get_stats = pfe_eth_get_stats,
++      .ndo_set_mac_address = pfe_eth_set_mac_address,
++      .ndo_set_rx_mode = pfe_eth_set_multi,
++      .ndo_set_features = pfe_eth_set_features,
++      .ndo_validate_addr = eth_validate_addr,
++};
++
++/* pfe_eth_init_one
++ */
++static int pfe_eth_init_one(struct pfe *pfe, int id)
++{
++      struct net_device *ndev = NULL;
++      struct pfe_eth_priv_s *priv = NULL;
++      struct ls1012a_eth_platform_data *einfo;
++      struct ls1012a_mdio_platform_data *minfo;
++      struct ls1012a_pfe_platform_data *pfe_info;
++      int err;
++
++      /* Extract pltform data */
++      pfe_info = (struct ls1012a_pfe_platform_data *)
++                                      pfe->dev->platform_data;
++      if (!pfe_info) {
++              pr_err(
++                      "%s: pfe missing additional platform data\n"
++                      , __func__);
++              err = -ENODEV;
++              goto err0;
++      }
++
++      einfo = (struct ls1012a_eth_platform_data *)
++                              pfe_info->ls1012a_eth_pdata;
++
++      /* einfo never be NULL, but no harm in having this check */
++      if (!einfo) {
++              pr_err(
++                      "%s: pfe missing additional gemacs platform data\n"
++                      , __func__);
++              err = -ENODEV;
++              goto err0;
++      }
++
++      minfo = (struct ls1012a_mdio_platform_data *)
++                              pfe_info->ls1012a_mdio_pdata;
++
++      /* einfo never be NULL, but no harm in having this check */
++      if (!minfo) {
++              pr_err(
++                      "%s: pfe missing additional mdios platform data\n",
++                       __func__);
++              err = -ENODEV;
++              goto err0;
++      }
++
++      /* Create an ethernet device instance */
++      ndev = alloc_etherdev_mq(sizeof(*priv), emac_txq_cnt);
++
++      if (!ndev) {
++              pr_err("%s: gemac %d device allocation failed\n",
++                     __func__, einfo[id].gem_id);
++              err = -ENOMEM;
++              goto err0;
++      }
++
++      priv = netdev_priv(ndev);
++      priv->ndev = ndev;
++      priv->id = einfo[id].gem_id;
++      priv->pfe = pfe;
++
++      SET_NETDEV_DEV(priv->ndev, priv->pfe->dev);
++
++      pfe->eth.eth_priv[id] = priv;
++
++      /* Set the info in the priv to the current info */
++      priv->einfo = &einfo[id];
++      priv->EMAC_baseaddr = cbus_emac_base[id];
++      priv->PHY_baseaddr = cbus_emac_base[0];
++      priv->GPI_baseaddr = cbus_gpi_base[id];
++
++#define HIF_GEMAC_TMUQ_BASE   6
++      priv->low_tmu_q =  HIF_GEMAC_TMUQ_BASE + (id * 2);
++      priv->high_tmu_q        =  priv->low_tmu_q + 1;
++
++      spin_lock_init(&priv->lock);
++
++      pfe_eth_fast_tx_timeout_init(priv);
++
++      /* Copy the station address into the dev structure, */
++      memcpy(ndev->dev_addr, einfo[id].mac_addr, ETH_ALEN);
++
++      /* Initialize mdio */
++      if (minfo[id].enabled) {
++              err = pfe_eth_mdio_init(priv, &minfo[id]);
++              if (err) {
++                      netdev_err(ndev, "%s: pfe_eth_mdio_init() failed\n",
++                                 __func__);
++                      goto err2;
++              }
++      }
++
++      ndev->mtu = 1500;
++
++      /* Set MTU limits */
++      ndev->min_mtu = ETH_MIN_MTU;
++      ndev->max_mtu = JUMBO_FRAME_SIZE;
++
++      /* supported features */
++      ndev->hw_features = NETIF_F_SG;
++
++      /*Enable after checksum offload is validated */
++      ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM |
++              NETIF_F_IPV6_CSUM | NETIF_F_SG;
++
++      /* enabled by default */
++      ndev->features = ndev->hw_features;
++
++      priv->usr_features = ndev->features;
++
++      ndev->netdev_ops = &pfe_netdev_ops;
++
++      ndev->ethtool_ops = &pfe_ethtool_ops;
++
++      /* Enable basic messages by default */
++      priv->msg_enable = NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_LINK |
++                              NETIF_MSG_PROBE;
++
++      netif_napi_add(ndev, &priv->low_napi, pfe_eth_low_poll,
++                     HIF_RX_POLL_WEIGHT - 16);
++      netif_napi_add(ndev, &priv->high_napi, pfe_eth_high_poll,
++                     HIF_RX_POLL_WEIGHT - 16);
++      netif_napi_add(ndev, &priv->lro_napi, pfe_eth_lro_poll,
++                     HIF_RX_POLL_WEIGHT - 16);
++
++      err = register_netdev(ndev);
++
++      if (err) {
++              netdev_err(ndev, "register_netdev() failed\n");
++              goto err3;
++      }
++      device_init_wakeup(&ndev->dev, WAKE_MAGIC);
++
++      if (!(priv->einfo->phy_flags & GEMAC_NO_PHY)) {
++              err = pfe_phy_init(ndev);
++              if (err) {
++                      netdev_err(ndev, "%s: pfe_phy_init() failed\n",
++                                 __func__);
++                      goto err4;
++              }
++      }
++
++      netif_carrier_on(ndev);
++
++      /* Create all the sysfs files */
++      if (pfe_eth_sysfs_init(ndev))
++              goto err4;
++
++      netif_info(priv, probe, ndev, "%s: created interface, baseaddr: %p\n",
++                 __func__, priv->EMAC_baseaddr);
++
++      return 0;
++err4:
++      unregister_netdev(ndev);
++err3:
++      pfe_eth_mdio_exit(priv->mii_bus);
++err2:
++      free_netdev(priv->ndev);
++err0:
++      return err;
++}
++
++/* pfe_eth_init
++ */
++int pfe_eth_init(struct pfe *pfe)
++{
++      int ii = 0;
++      int err;
++
++      pr_info("%s\n", __func__);
++
++      cbus_emac_base[0] = EMAC1_BASE_ADDR;
++      cbus_emac_base[1] = EMAC2_BASE_ADDR;
++
++      cbus_gpi_base[0] = EGPI1_BASE_ADDR;
++      cbus_gpi_base[1] = EGPI2_BASE_ADDR;
++
++      for (ii = 0; ii < NUM_GEMAC_SUPPORT; ii++) {
++              err = pfe_eth_init_one(pfe, ii);
++              if (err)
++                      goto err0;
++      }
++
++      return 0;
++
++err0:
++      while (ii--)
++              pfe_eth_exit_one(pfe->eth.eth_priv[ii]);
++
++      /* Register three network devices in the kernel */
++      return err;
++}
++
++/* pfe_eth_exit_one
++ */
++static void pfe_eth_exit_one(struct pfe_eth_priv_s *priv)
++{
++      netif_info(priv, probe, priv->ndev, "%s\n", __func__);
++
++      pfe_eth_sysfs_exit(priv->ndev);
++
++      unregister_netdev(priv->ndev);
++
++      if (!(priv->einfo->phy_flags & GEMAC_NO_PHY))
++              pfe_phy_exit(priv->ndev);
++
++      if (priv->mii_bus)
++              pfe_eth_mdio_exit(priv->mii_bus);
++
++      free_netdev(priv->ndev);
++}
++
++/* pfe_eth_exit
++ */
++void pfe_eth_exit(struct pfe *pfe)
++{
++      int ii;
++
++      pr_info("%s\n", __func__);
++
++      for (ii = NUM_GEMAC_SUPPORT - 1; ii >= 0; ii--)
++              pfe_eth_exit_one(pfe->eth.eth_priv[ii]);
++}
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_firmware.c
+@@ -0,0 +1,314 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++/*
++ * @file
++ * Contains all the functions to handle parsing and loading of PE firmware
++ * files.
++ */
++#include <linux/firmware.h>
++
++#include "pfe_mod.h"
++#include "pfe_firmware.h"
++#include "pfe/pfe.h"
++
++static struct elf32_shdr *get_elf_section_header(const struct firmware *fw,
++                                               const char *section)
++{
++      struct elf32_hdr *elf_hdr = (struct elf32_hdr *)fw->data;
++      struct elf32_shdr *shdr;
++      struct elf32_shdr *shdr_shstr;
++      Elf32_Off e_shoff = be32_to_cpu(elf_hdr->e_shoff);
++      Elf32_Half e_shentsize = be16_to_cpu(elf_hdr->e_shentsize);
++      Elf32_Half e_shnum = be16_to_cpu(elf_hdr->e_shnum);
++      Elf32_Half e_shstrndx = be16_to_cpu(elf_hdr->e_shstrndx);
++      Elf32_Off shstr_offset;
++      Elf32_Word sh_name;
++      const char *name;
++      int i;
++
++      /* Section header strings */
++      shdr_shstr = (struct elf32_shdr *)(fw->data + e_shoff + e_shstrndx *
++                                      e_shentsize);
++      shstr_offset = be32_to_cpu(shdr_shstr->sh_offset);
++
++      for (i = 0; i < e_shnum; i++) {
++              shdr = (struct elf32_shdr *)(fw->data + e_shoff
++                                           + i * e_shentsize);
++
++              sh_name = be32_to_cpu(shdr->sh_name);
++
++              name = (const char *)(fw->data + shstr_offset + sh_name);
++
++              if (!strcmp(name, section))
++                      return shdr;
++      }
++
++      pr_err("%s: didn't find section %s\n", __func__, section);
++
++      return NULL;
++}
++
++#if defined(CFG_DIAGS)
++static int pfe_get_diags_info(const struct firmware *fw, struct pfe_diags_info
++                              *diags_info)
++{
++      struct elf32_shdr *shdr;
++      unsigned long offset, size;
++
++      shdr = get_elf_section_header(fw, ".pfe_diags_str");
++      if (shdr) {
++              offset = be32_to_cpu(shdr->sh_offset);
++              size = be32_to_cpu(shdr->sh_size);
++              diags_info->diags_str_base = be32_to_cpu(shdr->sh_addr);
++              diags_info->diags_str_size = size;
++              diags_info->diags_str_array = kmalloc(size, GFP_KERNEL);
++              memcpy(diags_info->diags_str_array, fw->data + offset, size);
++
++              return 0;
++      } else {
++              return -1;
++      }
++}
++#endif
++
++static void pfe_check_version_info(const struct firmware *fw)
++{
++      /*static char *version = NULL;*/
++      static char *version;
++
++      struct elf32_shdr *shdr = get_elf_section_header(fw, ".version");
++
++      if (shdr) {
++              if (!version) {
++                      /*
++                       * this is the first fw we load, use its version
++                       * string as reference (whatever it is)
++                       */
++                      version = (char *)(fw->data +
++                                      be32_to_cpu(shdr->sh_offset));
++
++                      pr_info("PFE binary version: %s\n", version);
++              } else {
++                      /*
++                       * already have loaded at least one firmware, check
++                       * sequence can start now
++                       */
++                      if (strcmp(version, (char *)(fw->data +
++                              be32_to_cpu(shdr->sh_offset)))) {
++                              pr_info(
++                              "WARNING: PFE firmware binaries from incompatible version\n");
++                      }
++              }
++      } else {
++              /*
++               * version cannot be verified, a potential issue that should
++               * be reported
++               */
++              pr_info(
++                       "WARNING: PFE firmware binaries from incompatible version\n");
++      }
++}
++
++/* PFE elf firmware loader.
++ * Loads an elf firmware image into a list of PE's (specified using a bitmask)
++ *
++ * @param pe_mask     Mask of PE id's to load firmware to
++ * @param fw          Pointer to the firmware image
++ *
++ * @return            0 on success, a negative value on error
++ *
++ */
++int pfe_load_elf(int pe_mask, const struct firmware *fw, struct pfe *pfe)
++{
++      struct elf32_hdr *elf_hdr = (struct elf32_hdr *)fw->data;
++      Elf32_Half sections = be16_to_cpu(elf_hdr->e_shnum);
++      struct elf32_shdr *shdr = (struct elf32_shdr *)(fw->data +
++                                      be32_to_cpu(elf_hdr->e_shoff));
++      int id, section;
++      int rc;
++
++      pr_info("%s\n", __func__);
++
++      /* Some sanity checks */
++      if (strncmp(&elf_hdr->e_ident[EI_MAG0], ELFMAG, SELFMAG)) {
++              pr_err("%s: incorrect elf magic number\n", __func__);
++              return -EINVAL;
++      }
++
++      if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32) {
++              pr_err("%s: incorrect elf class(%x)\n", __func__,
++                     elf_hdr->e_ident[EI_CLASS]);
++              return -EINVAL;
++      }
++
++      if (elf_hdr->e_ident[EI_DATA] != ELFDATA2MSB) {
++              pr_err("%s: incorrect elf data(%x)\n", __func__,
++                     elf_hdr->e_ident[EI_DATA]);
++              return -EINVAL;
++      }
++
++      if (be16_to_cpu(elf_hdr->e_type) != ET_EXEC) {
++              pr_err("%s: incorrect elf file type(%x)\n", __func__,
++                     be16_to_cpu(elf_hdr->e_type));
++              return -EINVAL;
++      }
++
++      for (section = 0; section < sections; section++, shdr++) {
++              if (!(be32_to_cpu(shdr->sh_flags) & (SHF_WRITE | SHF_ALLOC |
++                      SHF_EXECINSTR)))
++                      continue;
++
++              for (id = 0; id < MAX_PE; id++)
++                      if (pe_mask & (1 << id)) {
++                              rc = pe_load_elf_section(id, fw->data, shdr,
++                                                       pfe->dev);
++                              if (rc < 0)
++                                      goto err;
++                      }
++      }
++
++      pfe_check_version_info(fw);
++
++      return 0;
++
++err:
++      return rc;
++}
++
++/* PFE firmware initialization.
++ * Loads different firmware files from filesystem.
++ * Initializes PE IMEM/DMEM and UTIL-PE DDR
++ * Initializes control path symbol addresses (by looking them up in the elf
++ * firmware files
++ * Takes PE's out of reset
++ *
++ * @return    0 on success, a negative value on error
++ *
++ */
++int pfe_firmware_init(struct pfe *pfe)
++{
++      const struct firmware *class_fw, *tmu_fw;
++      int rc = 0;
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      const char *util_fw_name;
++      const struct firmware *util_fw;
++#endif
++
++      pr_info("%s\n", __func__);
++
++      if (request_firmware(&class_fw, CLASS_FIRMWARE_FILENAME, pfe->dev)) {
++              pr_err("%s: request firmware %s failed\n", __func__,
++                     CLASS_FIRMWARE_FILENAME);
++              rc = -ETIMEDOUT;
++              goto err0;
++      }
++
++      if (request_firmware(&tmu_fw, TMU_FIRMWARE_FILENAME, pfe->dev)) {
++              pr_err("%s: request firmware %s failed\n", __func__,
++                     TMU_FIRMWARE_FILENAME);
++              rc = -ETIMEDOUT;
++              goto err1;
++}
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      util_fw_name = UTIL_FIRMWARE_FILENAME;
++
++      if (request_firmware(&util_fw, util_fw_name, pfe->dev)) {
++              pr_err("%s: request firmware %s failed\n", __func__,
++                     util_fw_name);
++              rc = -ETIMEDOUT;
++              goto err2;
++      }
++#endif
++      rc = pfe_load_elf(CLASS_MASK, class_fw, pfe);
++      if (rc < 0) {
++              pr_err("%s: class firmware load failed\n", __func__);
++              goto err3;
++      }
++
++#if defined(CFG_DIAGS)
++      rc = pfe_get_diags_info(class_fw, &pfe->diags.class_diags_info);
++      if (rc < 0) {
++              pr_warn(
++                      "PFE diags won't be available for class PEs\n");
++              rc = 0;
++      }
++#endif
++
++      rc = pfe_load_elf(TMU_MASK, tmu_fw, pfe);
++      if (rc < 0) {
++              pr_err("%s: tmu firmware load failed\n", __func__);
++              goto err3;
++      }
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      rc = pfe_load_elf(UTIL_MASK, util_fw, pfe);
++      if (rc < 0) {
++              pr_err("%s: util firmware load failed\n", __func__);
++              goto err3;
++      }
++
++#if defined(CFG_DIAGS)
++      rc = pfe_get_diags_info(util_fw, &pfe->diags.util_diags_info);
++      if (rc < 0) {
++              pr_warn(
++                      "PFE diags won't be available for util PE\n");
++              rc = 0;
++      }
++#endif
++
++      util_enable();
++#endif
++
++      tmu_enable(0xf);
++      class_enable();
++
++err3:
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      release_firmware(util_fw);
++
++err2:
++#endif
++      release_firmware(tmu_fw);
++
++err1:
++      release_firmware(class_fw);
++
++err0:
++      return rc;
++}
++
++/* PFE firmware cleanup
++ * Puts PE's in reset
++ *
++ *
++ */
++void pfe_firmware_exit(struct pfe *pfe)
++{
++      pr_info("%s\n", __func__);
++
++      if (pe_reset_all(&pfe->ctrl) != 0)
++              pr_err("Error: Failed to stop PEs, PFE reload may not work correctly\n");
++
++      class_disable();
++      tmu_disable(0xf);
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      util_disable();
++#endif
++}
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_hal.c
+@@ -0,0 +1,1516 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "pfe_mod.h"
++#include "pfe/pfe.h"
++
++void *cbus_base_addr;
++void *ddr_base_addr;
++unsigned long ddr_phys_base_addr;
++unsigned int ddr_size;
++
++static struct pe_info pe[MAX_PE];
++
++/* Initializes the PFE library.
++ * Must be called before using any of the library functions.
++ *
++ * @param[in] cbus_base               CBUS virtual base address (as mapped in
++ * the host CPU address space)
++ * @param[in] ddr_base                PFE DDR range virtual base address (as
++ * mapped in the host CPU address space)
++ * @param[in] ddr_phys_base   PFE DDR range physical base address (as
++ * mapped in platform)
++ * @param[in] size            PFE DDR range size (as defined by the host
++ * software)
++ */
++void pfe_lib_init(void *cbus_base, void *ddr_base, unsigned long ddr_phys_base,
++                unsigned int size)
++{
++      cbus_base_addr = cbus_base;
++      ddr_base_addr = ddr_base;
++      ddr_phys_base_addr = ddr_phys_base;
++      ddr_size = size;
++
++      pe[CLASS0_ID].dmem_base_addr = CLASS_DMEM_BASE_ADDR(0);
++      pe[CLASS0_ID].pmem_base_addr = CLASS_IMEM_BASE_ADDR(0);
++      pe[CLASS0_ID].pmem_size = CLASS_IMEM_SIZE;
++      pe[CLASS0_ID].mem_access_wdata = CLASS_MEM_ACCESS_WDATA;
++      pe[CLASS0_ID].mem_access_addr = CLASS_MEM_ACCESS_ADDR;
++      pe[CLASS0_ID].mem_access_rdata = CLASS_MEM_ACCESS_RDATA;
++
++      pe[CLASS1_ID].dmem_base_addr = CLASS_DMEM_BASE_ADDR(1);
++      pe[CLASS1_ID].pmem_base_addr = CLASS_IMEM_BASE_ADDR(1);
++      pe[CLASS1_ID].pmem_size = CLASS_IMEM_SIZE;
++      pe[CLASS1_ID].mem_access_wdata = CLASS_MEM_ACCESS_WDATA;
++      pe[CLASS1_ID].mem_access_addr = CLASS_MEM_ACCESS_ADDR;
++      pe[CLASS1_ID].mem_access_rdata = CLASS_MEM_ACCESS_RDATA;
++
++      pe[CLASS2_ID].dmem_base_addr = CLASS_DMEM_BASE_ADDR(2);
++      pe[CLASS2_ID].pmem_base_addr = CLASS_IMEM_BASE_ADDR(2);
++      pe[CLASS2_ID].pmem_size = CLASS_IMEM_SIZE;
++      pe[CLASS2_ID].mem_access_wdata = CLASS_MEM_ACCESS_WDATA;
++      pe[CLASS2_ID].mem_access_addr = CLASS_MEM_ACCESS_ADDR;
++      pe[CLASS2_ID].mem_access_rdata = CLASS_MEM_ACCESS_RDATA;
++
++      pe[CLASS3_ID].dmem_base_addr = CLASS_DMEM_BASE_ADDR(3);
++      pe[CLASS3_ID].pmem_base_addr = CLASS_IMEM_BASE_ADDR(3);
++      pe[CLASS3_ID].pmem_size = CLASS_IMEM_SIZE;
++      pe[CLASS3_ID].mem_access_wdata = CLASS_MEM_ACCESS_WDATA;
++      pe[CLASS3_ID].mem_access_addr = CLASS_MEM_ACCESS_ADDR;
++      pe[CLASS3_ID].mem_access_rdata = CLASS_MEM_ACCESS_RDATA;
++
++      pe[CLASS4_ID].dmem_base_addr = CLASS_DMEM_BASE_ADDR(4);
++      pe[CLASS4_ID].pmem_base_addr = CLASS_IMEM_BASE_ADDR(4);
++      pe[CLASS4_ID].pmem_size = CLASS_IMEM_SIZE;
++      pe[CLASS4_ID].mem_access_wdata = CLASS_MEM_ACCESS_WDATA;
++      pe[CLASS4_ID].mem_access_addr = CLASS_MEM_ACCESS_ADDR;
++      pe[CLASS4_ID].mem_access_rdata = CLASS_MEM_ACCESS_RDATA;
++
++      pe[CLASS5_ID].dmem_base_addr = CLASS_DMEM_BASE_ADDR(5);
++      pe[CLASS5_ID].pmem_base_addr = CLASS_IMEM_BASE_ADDR(5);
++      pe[CLASS5_ID].pmem_size = CLASS_IMEM_SIZE;
++      pe[CLASS5_ID].mem_access_wdata = CLASS_MEM_ACCESS_WDATA;
++      pe[CLASS5_ID].mem_access_addr = CLASS_MEM_ACCESS_ADDR;
++      pe[CLASS5_ID].mem_access_rdata = CLASS_MEM_ACCESS_RDATA;
++
++      pe[TMU0_ID].dmem_base_addr = TMU_DMEM_BASE_ADDR(0);
++      pe[TMU0_ID].pmem_base_addr = TMU_IMEM_BASE_ADDR(0);
++      pe[TMU0_ID].pmem_size = TMU_IMEM_SIZE;
++      pe[TMU0_ID].mem_access_wdata = TMU_MEM_ACCESS_WDATA;
++      pe[TMU0_ID].mem_access_addr = TMU_MEM_ACCESS_ADDR;
++      pe[TMU0_ID].mem_access_rdata = TMU_MEM_ACCESS_RDATA;
++
++      pe[TMU1_ID].dmem_base_addr = TMU_DMEM_BASE_ADDR(1);
++      pe[TMU1_ID].pmem_base_addr = TMU_IMEM_BASE_ADDR(1);
++      pe[TMU1_ID].pmem_size = TMU_IMEM_SIZE;
++      pe[TMU1_ID].mem_access_wdata = TMU_MEM_ACCESS_WDATA;
++      pe[TMU1_ID].mem_access_addr = TMU_MEM_ACCESS_ADDR;
++      pe[TMU1_ID].mem_access_rdata = TMU_MEM_ACCESS_RDATA;
++
++      pe[TMU3_ID].dmem_base_addr = TMU_DMEM_BASE_ADDR(3);
++      pe[TMU3_ID].pmem_base_addr = TMU_IMEM_BASE_ADDR(3);
++      pe[TMU3_ID].pmem_size = TMU_IMEM_SIZE;
++      pe[TMU3_ID].mem_access_wdata = TMU_MEM_ACCESS_WDATA;
++      pe[TMU3_ID].mem_access_addr = TMU_MEM_ACCESS_ADDR;
++      pe[TMU3_ID].mem_access_rdata = TMU_MEM_ACCESS_RDATA;
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      pe[UTIL_ID].dmem_base_addr = UTIL_DMEM_BASE_ADDR;
++      pe[UTIL_ID].mem_access_wdata = UTIL_MEM_ACCESS_WDATA;
++      pe[UTIL_ID].mem_access_addr = UTIL_MEM_ACCESS_ADDR;
++      pe[UTIL_ID].mem_access_rdata = UTIL_MEM_ACCESS_RDATA;
++#endif
++}
++
++/* Writes a buffer to PE internal memory from the host
++ * through indirect access registers.
++ *
++ * @param[in] id              PE identification (CLASS0_ID, ..., TMU0_ID,
++ * ..., UTIL_ID)
++ * @param[in] src             Buffer source address
++ * @param[in] mem_access_addr DMEM destination address (must be 32bit
++ * aligned)
++ * @param[in] len             Number of bytes to copy
++ */
++void pe_mem_memcpy_to32(int id, u32 mem_access_addr, const void *src, unsigned
++int len)
++{
++      u32 offset = 0, val, addr;
++      unsigned int len32 = len >> 2;
++      int i;
++
++      addr = mem_access_addr | PE_MEM_ACCESS_WRITE |
++              PE_MEM_ACCESS_BYTE_ENABLE(0, 4);
++
++      for (i = 0; i < len32; i++, offset += 4, src += 4) {
++              val = *(u32 *)src;
++              writel(cpu_to_be32(val), pe[id].mem_access_wdata);
++              writel(addr + offset, pe[id].mem_access_addr);
++      }
++
++      len = (len & 0x3);
++      if (len) {
++              val = 0;
++
++              addr = (mem_access_addr | PE_MEM_ACCESS_WRITE |
++                      PE_MEM_ACCESS_BYTE_ENABLE(0, len)) + offset;
++
++              for (i = 0; i < len; i++, src++)
++                      val |= (*(u8 *)src) << (8 * i);
++
++              writel(cpu_to_be32(val), pe[id].mem_access_wdata);
++              writel(addr, pe[id].mem_access_addr);
++      }
++}
++
++/* Writes a buffer to PE internal data memory (DMEM) from the host
++ * through indirect access registers.
++ * @param[in] id              PE identification (CLASS0_ID, ..., TMU0_ID,
++ * ..., UTIL_ID)
++ * @param[in] src             Buffer source address
++ * @param[in] dst             DMEM destination address (must be 32bit
++ * aligned)
++ * @param[in] len             Number of bytes to copy
++ */
++void pe_dmem_memcpy_to32(int id, u32 dst, const void *src, unsigned int len)
++{
++      pe_mem_memcpy_to32(id, pe[id].dmem_base_addr | dst |
++                              PE_MEM_ACCESS_DMEM, src, len);
++}
++
++/* Writes a buffer to PE internal program memory (PMEM) from the host
++ * through indirect access registers.
++ * @param[in] id              PE identification (CLASS0_ID, ..., TMU0_ID,
++ * ..., TMU3_ID)
++ * @param[in] src             Buffer source address
++ * @param[in] dst             PMEM destination address (must be 32bit
++ * aligned)
++ * @param[in] len             Number of bytes to copy
++ */
++void pe_pmem_memcpy_to32(int id, u32 dst, const void *src, unsigned int len)
++{
++      pe_mem_memcpy_to32(id, pe[id].pmem_base_addr | (dst & (pe[id].pmem_size
++                              - 1)) | PE_MEM_ACCESS_IMEM, src, len);
++}
++
++/* Reads PE internal program memory (IMEM) from the host
++ * through indirect access registers.
++ * @param[in] id              PE identification (CLASS0_ID, ..., TMU0_ID,
++ * ..., TMU3_ID)
++ * @param[in] addr            PMEM read address (must be aligned on size)
++ * @param[in] size            Number of bytes to read (maximum 4, must not
++ * cross 32bit boundaries)
++ * @return                    the data read (in PE endianness, i.e BE).
++ */
++u32 pe_pmem_read(int id, u32 addr, u8 size)
++{
++      u32 offset = addr & 0x3;
++      u32 mask = 0xffffffff >> ((4 - size) << 3);
++      u32 val;
++
++      addr = pe[id].pmem_base_addr | ((addr & ~0x3) & (pe[id].pmem_size - 1))
++              | PE_MEM_ACCESS_IMEM | PE_MEM_ACCESS_BYTE_ENABLE(offset, size);
++
++      writel(addr, pe[id].mem_access_addr);
++      val = be32_to_cpu(readl(pe[id].mem_access_rdata));
++
++      return (val >> (offset << 3)) & mask;
++}
++
++/* Writes PE internal data memory (DMEM) from the host
++ * through indirect access registers.
++ * @param[in] id              PE identification (CLASS0_ID, ..., TMU0_ID,
++ * ..., UTIL_ID)
++ * @param[in] addr            DMEM write address (must be aligned on size)
++ * @param[in] val             Value to write (in PE endianness, i.e BE)
++ * @param[in] size            Number of bytes to write (maximum 4, must not
++ * cross 32bit boundaries)
++ */
++void pe_dmem_write(int id, u32 val, u32 addr, u8 size)
++{
++      u32 offset = addr & 0x3;
++
++      addr = pe[id].dmem_base_addr | (addr & ~0x3) | PE_MEM_ACCESS_WRITE |
++              PE_MEM_ACCESS_DMEM | PE_MEM_ACCESS_BYTE_ENABLE(offset, size);
++
++      /* Indirect access interface is byte swapping data being written */
++      writel(cpu_to_be32(val << (offset << 3)), pe[id].mem_access_wdata);
++      writel(addr, pe[id].mem_access_addr);
++}
++
++/* Reads PE internal data memory (DMEM) from the host
++ * through indirect access registers.
++ * @param[in] id              PE identification (CLASS0_ID, ..., TMU0_ID,
++ * ..., UTIL_ID)
++ * @param[in] addr            DMEM read address (must be aligned on size)
++ * @param[in] size            Number of bytes to read (maximum 4, must not
++ * cross 32bit boundaries)
++ * @return                    the data read (in PE endianness, i.e BE).
++ */
++u32 pe_dmem_read(int id, u32 addr, u8 size)
++{
++      u32 offset = addr & 0x3;
++      u32 mask = 0xffffffff >> ((4 - size) << 3);
++      u32 val;
++
++      addr = pe[id].dmem_base_addr | (addr & ~0x3) | PE_MEM_ACCESS_DMEM |
++                      PE_MEM_ACCESS_BYTE_ENABLE(offset, size);
++
++      writel(addr, pe[id].mem_access_addr);
++
++      /* Indirect access interface is byte swapping data being read */
++      val = be32_to_cpu(readl(pe[id].mem_access_rdata));
++
++      return (val >> (offset << 3)) & mask;
++}
++
++/* This function is used to write to CLASS internal bus peripherals (ccu,
++ * pe-lem) from the host
++ * through indirect access registers.
++ * @param[in] val     value to write
++ * @param[in] addr    Address to write to (must be aligned on size)
++ * @param[in] size    Number of bytes to write (1, 2 or 4)
++ *
++ */
++void class_bus_write(u32 val, u32 addr, u8 size)
++{
++      u32 offset = addr & 0x3;
++
++      writel((addr & CLASS_BUS_ACCESS_BASE_MASK), CLASS_BUS_ACCESS_BASE);
++
++      addr = (addr & ~CLASS_BUS_ACCESS_BASE_MASK) | PE_MEM_ACCESS_WRITE |
++                      (size << 24);
++
++      writel(cpu_to_be32(val << (offset << 3)), CLASS_BUS_ACCESS_WDATA);
++      writel(addr, CLASS_BUS_ACCESS_ADDR);
++}
++
++/* Reads from CLASS internal bus peripherals (ccu, pe-lem) from the host
++ * through indirect access registers.
++ * @param[in] addr    Address to read from (must be aligned on size)
++ * @param[in] size    Number of bytes to read (1, 2 or 4)
++ * @return            the read data
++ *
++ */
++u32 class_bus_read(u32 addr, u8 size)
++{
++      u32 offset = addr & 0x3;
++      u32 mask = 0xffffffff >> ((4 - size) << 3);
++      u32 val;
++
++      writel((addr & CLASS_BUS_ACCESS_BASE_MASK), CLASS_BUS_ACCESS_BASE);
++
++      addr = (addr & ~CLASS_BUS_ACCESS_BASE_MASK) | (size << 24);
++
++      writel(addr, CLASS_BUS_ACCESS_ADDR);
++      val = be32_to_cpu(readl(CLASS_BUS_ACCESS_RDATA));
++
++      return (val >> (offset << 3)) & mask;
++}
++
++/* Writes data to the cluster memory (PE_LMEM)
++ * @param[in] dst     PE LMEM destination address (must be 32bit aligned)
++ * @param[in] src     Buffer source address
++ * @param[in] len     Number of bytes to copy
++ */
++void class_pe_lmem_memcpy_to32(u32 dst, const void *src, unsigned int len)
++{
++      u32 len32 = len >> 2;
++      int i;
++
++      for (i = 0; i < len32; i++, src += 4, dst += 4)
++              class_bus_write(*(u32 *)src, dst, 4);
++
++      if (len & 0x2) {
++              class_bus_write(*(u16 *)src, dst, 2);
++              src += 2;
++              dst += 2;
++      }
++
++      if (len & 0x1) {
++              class_bus_write(*(u8 *)src, dst, 1);
++              src++;
++              dst++;
++      }
++}
++
++/* Writes value to the cluster memory (PE_LMEM)
++ * @param[in] dst     PE LMEM destination address (must be 32bit aligned)
++ * @param[in] val     Value to write
++ * @param[in] len     Number of bytes to write
++ */
++void class_pe_lmem_memset(u32 dst, int val, unsigned int len)
++{
++      u32 len32 = len >> 2;
++      int i;
++
++      val = val | (val << 8) | (val << 16) | (val << 24);
++
++      for (i = 0; i < len32; i++, dst += 4)
++              class_bus_write(val, dst, 4);
++
++      if (len & 0x2) {
++              class_bus_write(val, dst, 2);
++              dst += 2;
++      }
++
++      if (len & 0x1) {
++              class_bus_write(val, dst, 1);
++              dst++;
++      }
++}
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++
++/* Writes UTIL program memory (DDR) from the host.
++ *
++ * @param[in] addr    Address to write (virtual, must be aligned on size)
++ * @param[in] val             Value to write (in PE endianness, i.e BE)
++ * @param[in] size            Number of bytes to write (2 or 4)
++ */
++static void util_pmem_write(u32 val, void *addr, u8 size)
++{
++      void *addr64 = (void *)((unsigned long)addr & ~0x7);
++      unsigned long off = 8 - ((unsigned long)addr & 0x7) - size;
++
++      /*
++       * IMEM should  be loaded as a 64bit swapped value in a 64bit aligned
++       * location
++       */
++      if (size == 4)
++              writel(be32_to_cpu(val), addr64 + off);
++      else
++              writew(be16_to_cpu((u16)val), addr64 + off);
++}
++
++/* Writes a buffer to UTIL program memory (DDR) from the host.
++ *
++ * @param[in] dst     Address to write (virtual, must be at least 16bit
++ * aligned)
++ * @param[in] src     Buffer to write (in PE endianness, i.e BE, must have
++ * same alignment as dst)
++ * @param[in] len     Number of bytes to write (must be at least 16bit
++ * aligned)
++ */
++static void util_pmem_memcpy(void *dst, const void *src, unsigned int len)
++{
++      unsigned int len32;
++      int i;
++
++      if ((unsigned long)src & 0x2) {
++              util_pmem_write(*(u16 *)src, dst, 2);
++              src += 2;
++              dst += 2;
++              len -= 2;
++      }
++
++      len32 = len >> 2;
++
++      for (i = 0; i < len32; i++, dst += 4, src += 4)
++              util_pmem_write(*(u32 *)src, dst, 4);
++
++      if (len & 0x2)
++              util_pmem_write(*(u16 *)src, dst, len & 0x2);
++}
++#endif
++
++/* Loads an elf section into pmem
++ * Code needs to be at least 16bit aligned and only PROGBITS sections are
++ * supported
++ *
++ * @param[in] id      PE identification (CLASS0_ID, ..., TMU0_ID, ...,
++ * TMU3_ID)
++ * @param[in] data    pointer to the elf firmware
++ * @param[in] shdr    pointer to the elf section header
++ *
++ */
++static int pe_load_pmem_section(int id, const void *data,
++                              struct elf32_shdr *shdr)
++{
++      u32 offset = be32_to_cpu(shdr->sh_offset);
++      u32 addr = be32_to_cpu(shdr->sh_addr);
++      u32 size = be32_to_cpu(shdr->sh_size);
++      u32 type = be32_to_cpu(shdr->sh_type);
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      if (id == UTIL_ID) {
++              pr_err("%s: unsupported pmem section for UTIL\n",
++                     __func__);
++              return -EINVAL;
++      }
++#endif
++
++      if (((unsigned long)(data + offset) & 0x3) != (addr & 0x3)) {
++              pr_err(
++                      "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n"
++                      , __func__, addr, (unsigned long)data + offset);
++
++              return -EINVAL;
++      }
++
++      if (addr & 0x1) {
++              pr_err("%s: load address(%x) is not 16bit aligned\n",
++                     __func__, addr);
++              return -EINVAL;
++      }
++
++      if (size & 0x1) {
++              pr_err("%s: load size(%x) is not 16bit aligned\n",
++                     __func__, size);
++              return -EINVAL;
++      }
++
++      switch (type) {
++      case SHT_PROGBITS:
++              pe_pmem_memcpy_to32(id, addr, data + offset, size);
++
++              break;
++
++      default:
++              pr_err("%s: unsupported section type(%x)\n", __func__,
++                     type);
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++/* Loads an elf section into dmem
++ * Data needs to be at least 32bit aligned, NOBITS sections are correctly
++ * initialized to 0
++ *
++ * @param[in] id              PE identification (CLASS0_ID, ..., TMU0_ID,
++ * ..., UTIL_ID)
++ * @param[in] data            pointer to the elf firmware
++ * @param[in] shdr            pointer to the elf section header
++ *
++ */
++static int pe_load_dmem_section(int id, const void *data,
++                              struct elf32_shdr *shdr)
++{
++      u32 offset = be32_to_cpu(shdr->sh_offset);
++      u32 addr = be32_to_cpu(shdr->sh_addr);
++      u32 size = be32_to_cpu(shdr->sh_size);
++      u32 type = be32_to_cpu(shdr->sh_type);
++      u32 size32 = size >> 2;
++      int i;
++
++      if (((unsigned long)(data + offset) & 0x3) != (addr & 0x3)) {
++              pr_err(
++                      "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n",
++                      __func__, addr, (unsigned long)data + offset);
++
++              return -EINVAL;
++      }
++
++      if (addr & 0x3) {
++              pr_err("%s: load address(%x) is not 32bit aligned\n",
++                     __func__, addr);
++              return -EINVAL;
++      }
++
++      switch (type) {
++      case SHT_PROGBITS:
++              pe_dmem_memcpy_to32(id, addr, data + offset, size);
++              break;
++
++      case SHT_NOBITS:
++              for (i = 0; i < size32; i++, addr += 4)
++                      pe_dmem_write(id, 0, addr, 4);
++
++              if (size & 0x3)
++                      pe_dmem_write(id, 0, addr, size & 0x3);
++
++              break;
++
++      default:
++              pr_err("%s: unsupported section type(%x)\n", __func__,
++                     type);
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++/* Loads an elf section into DDR
++ * Data needs to be at least 32bit aligned, NOBITS sections are correctly
++ * initialized to 0
++ *
++ * @param[in] id              PE identification (CLASS0_ID, ..., TMU0_ID,
++ * ..., UTIL_ID)
++ * @param[in] data            pointer to the elf firmware
++ * @param[in] shdr            pointer to the elf section header
++ *
++ */
++static int pe_load_ddr_section(int id, const void *data,
++                             struct elf32_shdr *shdr,
++                             struct device *dev) {
++      u32 offset = be32_to_cpu(shdr->sh_offset);
++      u32 addr = be32_to_cpu(shdr->sh_addr);
++      u32 size = be32_to_cpu(shdr->sh_size);
++      u32 type = be32_to_cpu(shdr->sh_type);
++      u32 flags = be32_to_cpu(shdr->sh_flags);
++
++      switch (type) {
++      case SHT_PROGBITS:
++              if (flags & SHF_EXECINSTR) {
++                      if (id <= CLASS_MAX_ID) {
++                              /* DO the loading only once in DDR */
++                              if (id == CLASS0_ID) {
++                                      pr_err(
++                                              "%s: load address(%x) and elf file address(%lx) rcvd\n",
++                                              __func__, addr,
++                                              (unsigned long)data + offset);
++                                      if (((unsigned long)(data + offset)
++                                              & 0x3) != (addr & 0x3)) {
++                                              pr_err(
++                                                      "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n"
++                                                      , __func__, addr,
++                                              (unsigned long)data + offset);
++
++                                              return -EINVAL;
++                                      }
++
++                                      if (addr & 0x1) {
++                                              pr_err(
++                                                      "%s: load address(%x) is not 16bit aligned\n"
++                                                      , __func__, addr);
++                                              return -EINVAL;
++                                      }
++
++                                      if (size & 0x1) {
++                                              pr_err(
++                                                      "%s: load length(%x) is not 16bit aligned\n"
++                                                      , __func__, size);
++                                              return -EINVAL;
++                                      }
++                                      memcpy(DDR_PHYS_TO_VIRT(
++                                              DDR_PFE_TO_PHYS(addr)),
++                                              data + offset, size);
++                              }
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++                      } else if (id == UTIL_ID) {
++                              if (((unsigned long)(data + offset) & 0x3)
++                                      != (addr & 0x3)) {
++                                      pr_err(
++                                              "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n"
++                                              , __func__, addr,
++                                              (unsigned long)data + offset);
++
++                                      return -EINVAL;
++                              }
++
++                              if (addr & 0x1) {
++                                      pr_err(
++                                              "%s: load address(%x) is not 16bit aligned\n"
++                                              , __func__, addr);
++                                      return -EINVAL;
++                              }
++
++                              if (size & 0x1) {
++                                      pr_err(
++                                              "%s: load length(%x) is not 16bit aligned\n"
++                                              , __func__, size);
++                                      return -EINVAL;
++                              }
++
++                              util_pmem_memcpy(DDR_PHYS_TO_VIRT(
++                                                      DDR_PFE_TO_PHYS(addr)),
++                                                      data + offset, size);
++                      }
++#endif
++                      } else {
++                              pr_err(
++                                      "%s: unsupported ddr section type(%x) for PE(%d)\n"
++                                              , __func__, type, id);
++                              return -EINVAL;
++                      }
++
++              } else {
++                      memcpy(DDR_PHYS_TO_VIRT(DDR_PFE_TO_PHYS(addr)), data
++                              + offset, size);
++              }
++
++              break;
++
++      case SHT_NOBITS:
++              memset(DDR_PHYS_TO_VIRT(DDR_PFE_TO_PHYS(addr)), 0, size);
++
++              break;
++
++      default:
++              pr_err("%s: unsupported section type(%x)\n", __func__,
++                     type);
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++/* Loads an elf section into pe lmem
++ * Data needs to be at least 32bit aligned, NOBITS sections are correctly
++ * initialized to 0
++ *
++ * @param[in] id              PE identification (CLASS0_ID,..., CLASS5_ID)
++ * @param[in] data            pointer to the elf firmware
++ * @param[in] shdr            pointer to the elf section header
++ *
++ */
++static int pe_load_pe_lmem_section(int id, const void *data,
++                                 struct elf32_shdr *shdr)
++{
++      u32 offset = be32_to_cpu(shdr->sh_offset);
++      u32 addr = be32_to_cpu(shdr->sh_addr);
++      u32 size = be32_to_cpu(shdr->sh_size);
++      u32 type = be32_to_cpu(shdr->sh_type);
++
++      if (id > CLASS_MAX_ID) {
++              pr_err(
++                      "%s: unsupported pe-lmem section type(%x) for PE(%d)\n",
++                       __func__, type, id);
++              return -EINVAL;
++      }
++
++      if (((unsigned long)(data + offset) & 0x3) != (addr & 0x3)) {
++              pr_err(
++                      "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n",
++                      __func__, addr, (unsigned long)data + offset);
++
++              return -EINVAL;
++      }
++
++      if (addr & 0x3) {
++              pr_err("%s: load address(%x) is not 32bit aligned\n",
++                     __func__, addr);
++              return -EINVAL;
++      }
++
++      switch (type) {
++      case SHT_PROGBITS:
++              class_pe_lmem_memcpy_to32(addr, data + offset, size);
++              break;
++
++      case SHT_NOBITS:
++              class_pe_lmem_memset(addr, 0, size);
++              break;
++
++      default:
++              pr_err("%s: unsupported section type(%x)\n", __func__,
++                     type);
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++/* Loads an elf section into a PE
++ * For now only supports loading a section to dmem (all PE's), pmem (class and
++ * tmu PE's),
++ * DDDR (util PE code)
++ *
++ * @param[in] id              PE identification (CLASS0_ID, ..., TMU0_ID,
++ * ..., UTIL_ID)
++ * @param[in] data            pointer to the elf firmware
++ * @param[in] shdr            pointer to the elf section header
++ *
++ */
++int pe_load_elf_section(int id, const void *data, struct elf32_shdr *shdr,
++                      struct device *dev) {
++      u32 addr = be32_to_cpu(shdr->sh_addr);
++      u32 size = be32_to_cpu(shdr->sh_size);
++
++      if (IS_DMEM(addr, size))
++              return pe_load_dmem_section(id, data, shdr);
++      else if (IS_PMEM(addr, size))
++              return pe_load_pmem_section(id, data, shdr);
++      else if (IS_PFE_LMEM(addr, size))
++              return 0;
++      else if (IS_PHYS_DDR(addr, size))
++              return pe_load_ddr_section(id, data, shdr, dev);
++      else if (IS_PE_LMEM(addr, size))
++              return pe_load_pe_lmem_section(id, data, shdr);
++
++      pr_err("%s: unsupported memory range(%x)\n", __func__,
++             addr);
++      return 0;
++}
++
++/**************************** BMU ***************************/
++
++/* Initializes a BMU block.
++ * @param[in] base    BMU block base address
++ * @param[in] cfg     BMU configuration
++ */
++void bmu_init(void *base, struct BMU_CFG *cfg)
++{
++      bmu_disable(base);
++
++      bmu_set_config(base, cfg);
++
++      bmu_reset(base);
++}
++
++/* Resets a BMU block.
++ * @param[in] base    BMU block base address
++ */
++void bmu_reset(void *base)
++{
++      writel(CORE_SW_RESET, base + BMU_CTRL);
++
++      /* Wait for self clear */
++      while (readl(base + BMU_CTRL) & CORE_SW_RESET)
++              ;
++}
++
++/* Enabled a BMU block.
++ * @param[in] base    BMU block base address
++ */
++void bmu_enable(void *base)
++{
++      writel(CORE_ENABLE, base + BMU_CTRL);
++}
++
++/* Disables a BMU block.
++ * @param[in] base    BMU block base address
++ */
++void bmu_disable(void *base)
++{
++      writel(CORE_DISABLE, base + BMU_CTRL);
++}
++
++/* Sets the configuration of a BMU block.
++ * @param[in] base    BMU block base address
++ * @param[in] cfg     BMU configuration
++ */
++void bmu_set_config(void *base, struct BMU_CFG *cfg)
++{
++      writel(cfg->baseaddr, base + BMU_UCAST_BASE_ADDR);
++      writel(cfg->count & 0xffff, base + BMU_UCAST_CONFIG);
++      writel(cfg->size & 0xffff, base + BMU_BUF_SIZE);
++
++      /* Interrupts are never used */
++      writel(cfg->low_watermark, base + BMU_LOW_WATERMARK);
++      writel(cfg->high_watermark, base + BMU_HIGH_WATERMARK);
++      writel(0x0, base + BMU_INT_ENABLE);
++}
++
++/**************************** MTIP GEMAC ***************************/
++
++/* Enable Rx Checksum Engine. With this enabled, Frame with bad IP,
++ *   TCP or UDP checksums are discarded
++ *
++ * @param[in] base    GEMAC base address.
++ */
++void gemac_enable_rx_checksum_offload(void *base)
++{
++      /*Do not find configuration to do this */
++}
++
++/* Disable Rx Checksum Engine.
++ *
++ * @param[in] base    GEMAC base address.
++ */
++void gemac_disable_rx_checksum_offload(void *base)
++{
++      /*Do not find configuration to do this */
++}
++
++/* GEMAC set speed.
++ * @param[in] base    GEMAC base address
++ * @param[in] speed   GEMAC speed (10, 100 or 1000 Mbps)
++ */
++void gemac_set_speed(void *base, enum mac_speed gem_speed)
++{
++      u32 ecr = readl(base + EMAC_ECNTRL_REG) & ~EMAC_ECNTRL_SPEED;
++      u32 rcr = readl(base + EMAC_RCNTRL_REG) & ~EMAC_RCNTRL_RMII_10T;
++
++      switch (gem_speed) {
++      case SPEED_10M:
++                      rcr |= EMAC_RCNTRL_RMII_10T;
++                      break;
++
++      case SPEED_1000M:
++                      ecr |= EMAC_ECNTRL_SPEED;
++                      break;
++
++      case SPEED_100M:
++      default:
++                      /*It is in 100M mode */
++                      break;
++      }
++      writel(ecr, (base + EMAC_ECNTRL_REG));
++      writel(rcr, (base + EMAC_RCNTRL_REG));
++}
++
++/* GEMAC set duplex.
++ * @param[in] base    GEMAC base address
++ * @param[in] duplex  GEMAC duplex mode (Full, Half)
++ */
++void gemac_set_duplex(void *base, int duplex)
++{
++      if (duplex == DUPLEX_HALF) {
++              writel(readl(base + EMAC_TCNTRL_REG) & ~EMAC_TCNTRL_FDEN, base
++                      + EMAC_TCNTRL_REG);
++              writel(readl(base + EMAC_RCNTRL_REG) | EMAC_RCNTRL_DRT, (base
++                      + EMAC_RCNTRL_REG));
++      } else{
++              writel(readl(base + EMAC_TCNTRL_REG) | EMAC_TCNTRL_FDEN, base
++                      + EMAC_TCNTRL_REG);
++              writel(readl(base + EMAC_RCNTRL_REG) & ~EMAC_RCNTRL_DRT, (base
++                      + EMAC_RCNTRL_REG));
++      }
++}
++
++/* GEMAC set mode.
++ * @param[in] base    GEMAC base address
++ * @param[in] mode    GEMAC operation mode (MII, RMII, RGMII, SGMII)
++ */
++void gemac_set_mode(void *base, int mode)
++{
++      u32 val = readl(base + EMAC_RCNTRL_REG);
++
++      /*Remove loopbank*/
++      val &= ~EMAC_RCNTRL_LOOP;
++
++      /*Enable flow control and MII mode*/
++      val |= (EMAC_RCNTRL_FCE | EMAC_RCNTRL_MII_MODE);
++
++      writel(val, base + EMAC_RCNTRL_REG);
++}
++
++/* GEMAC enable function.
++ * @param[in] base    GEMAC base address
++ */
++void gemac_enable(void *base)
++{
++      writel(readl(base + EMAC_ECNTRL_REG) | EMAC_ECNTRL_ETHER_EN, base +
++              EMAC_ECNTRL_REG);
++}
++
++/* GEMAC disable function.
++ * @param[in] base    GEMAC base address
++ */
++void gemac_disable(void *base)
++{
++      writel(readl(base + EMAC_ECNTRL_REG) & ~EMAC_ECNTRL_ETHER_EN, base +
++              EMAC_ECNTRL_REG);
++}
++
++/* GEMAC TX disable function.
++ * @param[in] base    GEMAC base address
++ */
++void gemac_tx_disable(void *base)
++{
++      writel(readl(base + EMAC_TCNTRL_REG) | EMAC_TCNTRL_GTS, base +
++              EMAC_TCNTRL_REG);
++}
++
++void gemac_tx_enable(void *base)
++{
++      writel(readl(base + EMAC_TCNTRL_REG) & ~EMAC_TCNTRL_GTS, base +
++                      EMAC_TCNTRL_REG);
++}
++
++/* Sets the hash register of the MAC.
++ * This register is used for matching unicast and multicast frames.
++ *
++ * @param[in] base    GEMAC base address.
++ * @param[in] hash    64-bit hash to be configured.
++ */
++void gemac_set_hash(void *base, struct pfe_mac_addr *hash)
++{
++      writel(hash->bottom,  base + EMAC_GALR);
++      writel(hash->top, base + EMAC_GAUR);
++}
++
++void gemac_set_laddrN(void *base, struct pfe_mac_addr *address,
++                    unsigned int entry_index)
++{
++      if ((entry_index < 1) || (entry_index > EMAC_SPEC_ADDR_MAX))
++              return;
++
++      entry_index = entry_index - 1;
++      if (entry_index < 1) {
++              writel(htonl(address->bottom),  base + EMAC_PHY_ADDR_LOW);
++              writel((htonl(address->top) | 0x8808), base +
++                      EMAC_PHY_ADDR_HIGH);
++      } else {
++              writel(htonl(address->bottom),  base + ((entry_index - 1) * 8)
++                      + EMAC_SMAC_0_0);
++              writel((htonl(address->top) | 0x8808), base + ((entry_index -
++                      1) * 8) + EMAC_SMAC_0_1);
++      }
++}
++
++void gemac_clear_laddrN(void *base, unsigned int entry_index)
++{
++      if ((entry_index < 1) || (entry_index > EMAC_SPEC_ADDR_MAX))
++              return;
++
++      entry_index = entry_index - 1;
++      if (entry_index < 1) {
++              writel(0, base + EMAC_PHY_ADDR_LOW);
++              writel(0, base + EMAC_PHY_ADDR_HIGH);
++      } else {
++              writel(0,  base + ((entry_index - 1) * 8) + EMAC_SMAC_0_0);
++              writel(0, base + ((entry_index - 1) * 8) + EMAC_SMAC_0_1);
++      }
++}
++
++/* Set the loopback mode of the MAC.  This can be either no loopback for
++ * normal operation, local loopback through MAC internal loopback module or PHY
++ *   loopback for external loopback through a PHY.  This asserts the external
++ * loop pin.
++ *
++ * @param[in] base    GEMAC base address.
++ * @param[in] gem_loop        Loopback mode to be enabled. LB_LOCAL - MAC
++ * Loopback,
++ *                    LB_EXT - PHY Loopback.
++ */
++void gemac_set_loop(void *base, enum mac_loop gem_loop)
++{
++      pr_info("%s()\n", __func__);
++      writel(readl(base + EMAC_RCNTRL_REG) | EMAC_RCNTRL_LOOP, (base +
++              EMAC_RCNTRL_REG));
++}
++
++/* GEMAC allow frames
++ * @param[in] base    GEMAC base address
++ */
++void gemac_enable_copy_all(void *base)
++{
++      writel(readl(base + EMAC_RCNTRL_REG) | EMAC_RCNTRL_PROM, (base +
++              EMAC_RCNTRL_REG));
++}
++
++/* GEMAC do not allow frames
++ * @param[in] base    GEMAC base address
++ */
++void gemac_disable_copy_all(void *base)
++{
++      writel(readl(base + EMAC_RCNTRL_REG) & ~EMAC_RCNTRL_PROM, (base +
++              EMAC_RCNTRL_REG));
++}
++
++/* GEMAC allow broadcast function.
++ * @param[in] base    GEMAC base address
++ */
++void gemac_allow_broadcast(void *base)
++{
++      writel(readl(base + EMAC_RCNTRL_REG) & ~EMAC_RCNTRL_BC_REJ, base +
++              EMAC_RCNTRL_REG);
++}
++
++/* GEMAC no broadcast function.
++ * @param[in] base    GEMAC base address
++ */
++void gemac_no_broadcast(void *base)
++{
++      writel(readl(base + EMAC_RCNTRL_REG) | EMAC_RCNTRL_BC_REJ, base +
++              EMAC_RCNTRL_REG);
++}
++
++/* GEMAC enable 1536 rx function.
++ * @param[in] base    GEMAC base address
++ */
++void gemac_enable_1536_rx(void *base)
++{
++      /* Set 1536 as Maximum frame length */
++      writel(readl(base + EMAC_RCNTRL_REG) | (1536 << 16), base +
++              EMAC_RCNTRL_REG);
++}
++
++/* GEMAC enable jumbo function.
++ * @param[in] base    GEMAC base address
++ */
++void gemac_enable_rx_jmb(void *base)
++{
++      writel(readl(base + EMAC_RCNTRL_REG) | (JUMBO_FRAME_SIZE << 16), base
++              + EMAC_RCNTRL_REG);
++}
++
++/* GEMAC enable stacked vlan function.
++ * @param[in] base    GEMAC base address
++ */
++void gemac_enable_stacked_vlan(void *base)
++{
++      /* MTIP doesn't support stacked vlan */
++}
++
++/* GEMAC enable pause rx function.
++ * @param[in] base    GEMAC base address
++ */
++void gemac_enable_pause_rx(void *base)
++{
++      writel(readl(base + EMAC_RCNTRL_REG) | EMAC_RCNTRL_FCE,
++             base + EMAC_RCNTRL_REG);
++}
++
++/* GEMAC disable pause rx function.
++ * @param[in] base    GEMAC base address
++ */
++void gemac_disable_pause_rx(void *base)
++{
++      writel(readl(base + EMAC_RCNTRL_REG) & ~EMAC_RCNTRL_FCE,
++             base + EMAC_RCNTRL_REG);
++}
++
++/* GEMAC enable pause tx function.
++ * @param[in] base GEMAC base address
++ */
++void gemac_enable_pause_tx(void *base)
++{
++      writel(EMAC_RX_SECTION_EMPTY_V, base + EMAC_RX_SECTION_EMPTY);
++}
++
++/* GEMAC disable pause tx function.
++ * @param[in] base GEMAC base address
++ */
++void gemac_disable_pause_tx(void *base)
++{
++      writel(0x0, base + EMAC_RX_SECTION_EMPTY);
++}
++
++/* GEMAC wol configuration
++ * @param[in] base    GEMAC base address
++ * @param[in] wol_conf        WoL register configuration
++ */
++void gemac_set_wol(void *base, u32 wol_conf)
++{
++      u32  val = readl(base + EMAC_ECNTRL_REG);
++
++      if (wol_conf)
++              val |= (EMAC_ECNTRL_MAGIC_ENA | EMAC_ECNTRL_SLEEP);
++      else
++              val &= ~(EMAC_ECNTRL_MAGIC_ENA | EMAC_ECNTRL_SLEEP);
++      writel(val, base + EMAC_ECNTRL_REG);
++}
++
++/* Sets Gemac bus width to 64bit
++ * @param[in] base       GEMAC base address
++ * @param[in] width     gemac bus width to be set possible values are 32/64/128
++ */
++void gemac_set_bus_width(void *base, int width)
++{
++}
++
++/* Sets Gemac configuration.
++ * @param[in] base    GEMAC base address
++ * @param[in] cfg     GEMAC configuration
++ */
++void gemac_set_config(void *base, struct gemac_cfg *cfg)
++{
++      /*GEMAC config taken from VLSI */
++      writel(0x00000004, base + EMAC_TFWR_STR_FWD);
++      writel(0x00000005, base + EMAC_RX_SECTION_FULL);
++      writel(0x00003fff, base + EMAC_TRUNC_FL);
++      writel(0x00000030, base + EMAC_TX_SECTION_EMPTY);
++      writel(0x00000000, base + EMAC_MIB_CTRL_STS_REG);
++
++      gemac_set_mode(base, cfg->mode);
++
++      gemac_set_speed(base, cfg->speed);
++
++      gemac_set_duplex(base, cfg->duplex);
++}
++
++/**************************** GPI ***************************/
++
++/* Initializes a GPI block.
++ * @param[in] base    GPI base address
++ * @param[in] cfg     GPI configuration
++ */
++void gpi_init(void *base, struct gpi_cfg *cfg)
++{
++      gpi_reset(base);
++
++      gpi_disable(base);
++
++      gpi_set_config(base, cfg);
++}
++
++/* Resets a GPI block.
++ * @param[in] base    GPI base address
++ */
++void gpi_reset(void *base)
++{
++      writel(CORE_SW_RESET, base + GPI_CTRL);
++}
++
++/* Enables a GPI block.
++ * @param[in] base    GPI base address
++ */
++void gpi_enable(void *base)
++{
++      writel(CORE_ENABLE, base + GPI_CTRL);
++}
++
++/* Disables a GPI block.
++ * @param[in] base    GPI base address
++ */
++void gpi_disable(void *base)
++{
++      writel(CORE_DISABLE, base + GPI_CTRL);
++}
++
++/* Sets the configuration of a GPI block.
++ * @param[in] base    GPI base address
++ * @param[in] cfg     GPI configuration
++ */
++void gpi_set_config(void *base, struct gpi_cfg *cfg)
++{
++      writel(CBUS_VIRT_TO_PFE(BMU1_BASE_ADDR + BMU_ALLOC_CTRL),       base
++              + GPI_LMEM_ALLOC_ADDR);
++      writel(CBUS_VIRT_TO_PFE(BMU1_BASE_ADDR + BMU_FREE_CTRL),        base
++              + GPI_LMEM_FREE_ADDR);
++      writel(CBUS_VIRT_TO_PFE(BMU2_BASE_ADDR + BMU_ALLOC_CTRL),       base
++              + GPI_DDR_ALLOC_ADDR);
++      writel(CBUS_VIRT_TO_PFE(BMU2_BASE_ADDR + BMU_FREE_CTRL),        base
++              + GPI_DDR_FREE_ADDR);
++      writel(CBUS_VIRT_TO_PFE(CLASS_INQ_PKTPTR), base + GPI_CLASS_ADDR);
++      writel(DDR_HDR_SIZE, base + GPI_DDR_DATA_OFFSET);
++      writel(LMEM_HDR_SIZE, base + GPI_LMEM_DATA_OFFSET);
++      writel(0, base + GPI_LMEM_SEC_BUF_DATA_OFFSET);
++      writel(0, base + GPI_DDR_SEC_BUF_DATA_OFFSET);
++      writel((DDR_HDR_SIZE << 16) |   LMEM_HDR_SIZE,  base + GPI_HDR_SIZE);
++      writel((DDR_BUF_SIZE << 16) |   LMEM_BUF_SIZE,  base + GPI_BUF_SIZE);
++
++      writel(((cfg->lmem_rtry_cnt << 16) | (GPI_DDR_BUF_EN << 1) |
++              GPI_LMEM_BUF_EN), base + GPI_RX_CONFIG);
++      writel(cfg->tmlf_txthres, base + GPI_TMLF_TX);
++      writel(cfg->aseq_len,   base + GPI_DTX_ASEQ);
++      writel(1, base + GPI_TOE_CHKSUM_EN);
++
++      if (cfg->mtip_pause_reg) {
++              writel(cfg->mtip_pause_reg, base + GPI_CSR_MTIP_PAUSE_REG);
++              writel(EGPI_PAUSE_TIME, base + GPI_TX_PAUSE_TIME);
++      }
++}
++
++/**************************** CLASSIFIER ***************************/
++
++/* Initializes CLASSIFIER block.
++ * @param[in] cfg     CLASSIFIER configuration
++ */
++void class_init(struct class_cfg *cfg)
++{
++      class_reset();
++
++      class_disable();
++
++      class_set_config(cfg);
++}
++
++/* Resets CLASSIFIER block.
++ *
++ */
++void class_reset(void)
++{
++      writel(CORE_SW_RESET, CLASS_TX_CTRL);
++}
++
++/* Enables all CLASS-PE's cores.
++ *
++ */
++void class_enable(void)
++{
++      writel(CORE_ENABLE, CLASS_TX_CTRL);
++}
++
++/* Disables all CLASS-PE's cores.
++ *
++ */
++void class_disable(void)
++{
++      writel(CORE_DISABLE, CLASS_TX_CTRL);
++}
++
++/*
++ * Sets the configuration of the CLASSIFIER block.
++ * @param[in] cfg     CLASSIFIER configuration
++ */
++void class_set_config(struct class_cfg *cfg)
++{
++      u32 val;
++
++      /* Initialize route table */
++      if (!cfg->resume)
++              memset(DDR_PHYS_TO_VIRT(cfg->route_table_baseaddr), 0, (1 <<
++              cfg->route_table_hash_bits) * CLASS_ROUTE_SIZE);
++
++#if !defined(LS1012A_PFE_RESET_WA)
++      writel(cfg->pe_sys_clk_ratio,   CLASS_PE_SYS_CLK_RATIO);
++#endif
++
++      writel((DDR_HDR_SIZE << 16) | LMEM_HDR_SIZE,    CLASS_HDR_SIZE);
++      writel(LMEM_BUF_SIZE,                           CLASS_LMEM_BUF_SIZE);
++      writel(CLASS_ROUTE_ENTRY_SIZE(CLASS_ROUTE_SIZE) |
++              CLASS_ROUTE_HASH_SIZE(cfg->route_table_hash_bits),
++              CLASS_ROUTE_HASH_ENTRY_SIZE);
++      writel(HIF_PKT_CLASS_EN | HIF_PKT_OFFSET(sizeof(struct hif_hdr)),
++             CLASS_HIF_PARSE);
++
++      val = HASH_CRC_PORT_IP | QB2BUS_LE;
++
++#if defined(CONFIG_IP_ALIGNED)
++      val |= IP_ALIGNED;
++#endif
++
++      /*
++       *  Class PE packet steering will only work if TOE mode, bridge fetch or
++       * route fetch are enabled (see class/qb_fet.v). Route fetch would
++       * trigger additional memory copies (likely from DDR because of hash
++       * table size, which cannot be reduced because PE software still
++       * relies on hash value computed in HW), so when not in TOE mode we
++       * simply enable HW bridge fetch even though we don't use it.
++       */
++      if (cfg->toe_mode)
++              val |= CLASS_TOE;
++      else
++              val |= HW_BRIDGE_FETCH;
++
++      writel(val, CLASS_ROUTE_MULTI);
++
++      writel(DDR_PHYS_TO_PFE(cfg->route_table_baseaddr),
++             CLASS_ROUTE_TABLE_BASE);
++      writel(CLASS_PE0_RO_DM_ADDR0_VAL,               CLASS_PE0_RO_DM_ADDR0);
++      writel(CLASS_PE0_RO_DM_ADDR1_VAL,               CLASS_PE0_RO_DM_ADDR1);
++      writel(CLASS_PE0_QB_DM_ADDR0_VAL,               CLASS_PE0_QB_DM_ADDR0);
++      writel(CLASS_PE0_QB_DM_ADDR1_VAL,               CLASS_PE0_QB_DM_ADDR1);
++      writel(CBUS_VIRT_TO_PFE(TMU_PHY_INQ_PKTPTR),    CLASS_TM_INQ_ADDR);
++
++      writel(23, CLASS_AFULL_THRES);
++      writel(23, CLASS_TSQ_FIFO_THRES);
++
++      writel(24, CLASS_MAX_BUF_CNT);
++      writel(24, CLASS_TSQ_MAX_CNT);
++}
++
++/**************************** TMU ***************************/
++
++void tmu_reset(void)
++{
++      writel(SW_RESET, TMU_CTRL);
++}
++
++/* Initializes TMU block.
++ * @param[in] cfg     TMU configuration
++ */
++void tmu_init(struct tmu_cfg *cfg)
++{
++      int q, phyno;
++
++      tmu_disable(0xF);
++      mdelay(10);
++
++#if !defined(LS1012A_PFE_RESET_WA)
++      /* keep in soft reset */
++      writel(SW_RESET, TMU_CTRL);
++#endif
++      writel(0x3, TMU_SYS_GENERIC_CONTROL);
++      writel(750, TMU_INQ_WATERMARK);
++      writel(CBUS_VIRT_TO_PFE(EGPI1_BASE_ADDR +
++              GPI_INQ_PKTPTR),        TMU_PHY0_INQ_ADDR);
++      writel(CBUS_VIRT_TO_PFE(EGPI2_BASE_ADDR +
++              GPI_INQ_PKTPTR),        TMU_PHY1_INQ_ADDR);
++      writel(CBUS_VIRT_TO_PFE(HGPI_BASE_ADDR +
++              GPI_INQ_PKTPTR),        TMU_PHY3_INQ_ADDR);
++      writel(CBUS_VIRT_TO_PFE(HIF_NOCPY_RX_INQ0_PKTPTR), TMU_PHY4_INQ_ADDR);
++      writel(CBUS_VIRT_TO_PFE(UTIL_INQ_PKTPTR), TMU_PHY5_INQ_ADDR);
++      writel(CBUS_VIRT_TO_PFE(BMU2_BASE_ADDR + BMU_FREE_CTRL),
++             TMU_BMU_INQ_ADDR);
++
++      writel(0x3FF,   TMU_TDQ0_SCH_CTRL);     /*
++                                               * enabling all 10
++                                               * schedulers [9:0] of each TDQ
++                                               */
++      writel(0x3FF,   TMU_TDQ1_SCH_CTRL);
++      writel(0x3FF,   TMU_TDQ3_SCH_CTRL);
++
++#if !defined(LS1012A_PFE_RESET_WA)
++      writel(cfg->pe_sys_clk_ratio,   TMU_PE_SYS_CLK_RATIO);
++#endif
++
++#if !defined(LS1012A_PFE_RESET_WA)
++      writel(DDR_PHYS_TO_PFE(cfg->llm_base_addr),     TMU_LLM_BASE_ADDR);
++      /* Extra packet pointers will be stored from this address onwards */
++
++      writel(cfg->llm_queue_len,      TMU_LLM_QUE_LEN);
++      writel(5,                       TMU_TDQ_IIFG_CFG);
++      writel(DDR_BUF_SIZE,            TMU_BMU_BUF_SIZE);
++
++      writel(0x0,                     TMU_CTRL);
++
++      /* MEM init */
++      pr_info("%s: mem init\n", __func__);
++      writel(MEM_INIT,        TMU_CTRL);
++
++      while (!(readl(TMU_CTRL) & MEM_INIT_DONE))
++              ;
++
++      /* LLM init */
++      pr_info("%s: lmem init\n", __func__);
++      writel(LLM_INIT,        TMU_CTRL);
++
++      while (!(readl(TMU_CTRL) & LLM_INIT_DONE))
++              ;
++#endif
++      /* set up each queue for tail drop */
++      for (phyno = 0; phyno < 4; phyno++) {
++              if (phyno == 2)
++                      continue;
++              for (q = 0; q < 16; q++) {
++                      u32 qdepth;
++
++                      writel((phyno << 8) | q, TMU_TEQ_CTRL);
++                      writel(1 << 22, TMU_TEQ_QCFG); /*Enable tail drop */
++
++                      if (phyno == 3)
++                              qdepth = DEFAULT_TMU3_QDEPTH;
++                      else
++                              qdepth = (q == 0) ? DEFAULT_Q0_QDEPTH :
++                                              DEFAULT_MAX_QDEPTH;
++
++                      /* LOG: 68855 */
++                      /*
++                       * The following is a workaround for the reordered
++                       * packet and BMU2 buffer leakage issue.
++                       */
++                      if (CHIP_REVISION() == 0)
++                              qdepth = 31;
++
++                      writel(qdepth << 18, TMU_TEQ_HW_PROB_CFG2);
++                      writel(qdepth >> 14, TMU_TEQ_HW_PROB_CFG3);
++              }
++      }
++
++#ifdef CFG_LRO
++      /* Set TMU-3 queue 5 (LRO) in no-drop mode */
++      writel((3 << 8) | TMU_QUEUE_LRO, TMU_TEQ_CTRL);
++      writel(0, TMU_TEQ_QCFG);
++#endif
++
++      writel(0x05, TMU_TEQ_DISABLE_DROPCHK);
++
++      writel(0x0, TMU_CTRL);
++}
++
++/* Enables TMU-PE cores.
++ * @param[in] pe_mask TMU PE mask
++ */
++void tmu_enable(u32 pe_mask)
++{
++      writel(readl(TMU_TX_CTRL) | (pe_mask & 0xF), TMU_TX_CTRL);
++}
++
++/* Disables TMU cores.
++ * @param[in] pe_mask TMU PE mask
++ */
++void tmu_disable(u32 pe_mask)
++{
++      writel(readl(TMU_TX_CTRL) & ~(pe_mask & 0xF), TMU_TX_CTRL);
++}
++
++/* This will return the tmu queue status
++ * @param[in] if_id   gem interface id or TMU index
++ * @return            returns the bit mask of busy queues, zero means all
++ * queues are empty
++ */
++u32 tmu_qstatus(u32 if_id)
++{
++      return cpu_to_be32(pe_dmem_read(TMU0_ID + if_id, TMU_DM_PESTATUS +
++              offsetof(struct pe_status, tmu_qstatus), 4));
++}
++
++u32 tmu_pkts_processed(u32 if_id)
++{
++      return cpu_to_be32(pe_dmem_read(TMU0_ID + if_id, TMU_DM_PESTATUS +
++              offsetof(struct pe_status, rx), 4));
++}
++
++/**************************** UTIL ***************************/
++
++/* Resets UTIL block.
++ */
++void util_reset(void)
++{
++      writel(CORE_SW_RESET, UTIL_TX_CTRL);
++}
++
++/* Initializes UTIL block.
++ * @param[in] cfg     UTIL configuration
++ */
++void util_init(struct util_cfg *cfg)
++{
++      writel(cfg->pe_sys_clk_ratio,   UTIL_PE_SYS_CLK_RATIO);
++}
++
++/* Enables UTIL-PE core.
++ *
++ */
++void util_enable(void)
++{
++      writel(CORE_ENABLE, UTIL_TX_CTRL);
++}
++
++/* Disables UTIL-PE core.
++ *
++ */
++void util_disable(void)
++{
++      writel(CORE_DISABLE, UTIL_TX_CTRL);
++}
++
++/**************************** HIF ***************************/
++/* Initializes HIF copy block.
++ *
++ */
++void hif_init(void)
++{
++      /*Initialize HIF registers*/
++      writel((HIF_RX_POLL_CTRL_CYCLE << 16) | HIF_TX_POLL_CTRL_CYCLE,
++             HIF_POLL_CTRL);
++}
++
++/* Enable hif tx DMA and interrupt
++ *
++ */
++void hif_tx_enable(void)
++{
++      writel(HIF_CTRL_DMA_EN, HIF_TX_CTRL);
++      writel((readl(HIF_INT_ENABLE) | HIF_INT_EN | HIF_TXPKT_INT_EN),
++             HIF_INT_ENABLE);
++}
++
++/* Disable hif tx DMA and interrupt
++ *
++ */
++void hif_tx_disable(void)
++{
++      u32     hif_int;
++
++      writel(0, HIF_TX_CTRL);
++
++      hif_int = readl(HIF_INT_ENABLE);
++      hif_int &= HIF_TXPKT_INT_EN;
++      writel(hif_int, HIF_INT_ENABLE);
++}
++
++/* Enable hif rx DMA and interrupt
++ *
++ */
++void hif_rx_enable(void)
++{
++      hif_rx_dma_start();
++      writel((readl(HIF_INT_ENABLE) | HIF_INT_EN | HIF_RXPKT_INT_EN),
++             HIF_INT_ENABLE);
++}
++
++/* Disable hif rx DMA and interrupt
++ *
++ */
++void hif_rx_disable(void)
++{
++      u32     hif_int;
++
++      writel(0, HIF_RX_CTRL);
++
++      hif_int = readl(HIF_INT_ENABLE);
++      hif_int &= HIF_RXPKT_INT_EN;
++      writel(hif_int, HIF_INT_ENABLE);
++}
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_hif.c
+@@ -0,0 +1,1094 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmapool.h>
++#include <linux/sched.h>
++#include <linux/module.h>
++#include <linux/list.h>
++#include <linux/kthread.h>
++#include <linux/slab.h>
++
++#include <linux/io.h>
++#include <asm/irq.h>
++
++#include "pfe_mod.h"
++
++#define HIF_INT_MASK  (HIF_INT | HIF_RXPKT_INT | HIF_TXPKT_INT)
++
++unsigned char napi_first_batch;
++
++static void pfe_tx_do_cleanup(unsigned long data);
++
++static int pfe_hif_alloc_descr(struct pfe_hif *hif)
++{
++      void *addr;
++      dma_addr_t dma_addr;
++      int err = 0;
++
++      pr_info("%s\n", __func__);
++      addr = dma_alloc_coherent(pfe->dev,
++                                HIF_RX_DESC_NT * sizeof(struct hif_desc) +
++                                HIF_TX_DESC_NT * sizeof(struct hif_desc),
++                                &dma_addr, GFP_KERNEL);
++
++      if (!addr) {
++              pr_err("%s: Could not allocate buffer descriptors!\n"
++                      , __func__);
++              err = -ENOMEM;
++              goto err0;
++      }
++
++      hif->descr_baseaddr_p = dma_addr;
++      hif->descr_baseaddr_v = addr;
++      hif->rx_ring_size = HIF_RX_DESC_NT;
++      hif->tx_ring_size = HIF_TX_DESC_NT;
++
++      return 0;
++
++err0:
++      return err;
++}
++
++#if defined(LS1012A_PFE_RESET_WA)
++static void pfe_hif_disable_rx_desc(struct pfe_hif *hif)
++{
++      int ii;
++      struct hif_desc *desc = hif->rx_base;
++
++      /*Mark all descriptors as LAST_BD */
++      for (ii = 0; ii < hif->rx_ring_size; ii++) {
++              desc->ctrl |= BD_CTRL_LAST_BD;
++              desc++;
++      }
++}
++
++struct class_rx_hdr_t {
++      u32     next_ptr;       /* ptr to the start of the first DDR buffer */
++      u16     length;         /* total packet length */
++      u16     phyno;          /* input physical port number */
++      u32     status;         /* gemac status bits */
++      u32     status2;            /* reserved for software usage */
++};
++
++/* STATUS_BAD_FRAME_ERR is set for all errors (including checksums if enabled)
++ * except overflow
++ */
++#define STATUS_BAD_FRAME_ERR            BIT(16)
++#define STATUS_LENGTH_ERR               BIT(17)
++#define STATUS_CRC_ERR                  BIT(18)
++#define STATUS_TOO_SHORT_ERR            BIT(19)
++#define STATUS_TOO_LONG_ERR             BIT(20)
++#define STATUS_CODE_ERR                 BIT(21)
++#define STATUS_MC_HASH_MATCH            BIT(22)
++#define STATUS_CUMULATIVE_ARC_HIT       BIT(23)
++#define STATUS_UNICAST_HASH_MATCH       BIT(24)
++#define STATUS_IP_CHECKSUM_CORRECT      BIT(25)
++#define STATUS_TCP_CHECKSUM_CORRECT     BIT(26)
++#define STATUS_UDP_CHECKSUM_CORRECT     BIT(27)
++#define STATUS_OVERFLOW_ERR             BIT(28) /* GPI error */
++#define MIN_PKT_SIZE                  64
++
++static inline void copy_to_lmem(u32 *dst, u32 *src, int len)
++{
++      int i;
++
++      for (i = 0; i < len; i += sizeof(u32))  {
++              *dst = htonl(*src);
++              dst++; src++;
++      }
++}
++
++static void send_dummy_pkt_to_hif(void)
++{
++      void *lmem_ptr, *ddr_ptr, *lmem_virt_addr;
++      u32 physaddr;
++      struct class_rx_hdr_t local_hdr;
++      static u32 dummy_pkt[] =  {
++              0x33221100, 0x2b785544, 0xd73093cb, 0x01000608,
++              0x04060008, 0x2b780200, 0xd73093cb, 0x0a01a8c0,
++              0x33221100, 0xa8c05544, 0x00000301, 0x00000000,
++              0x00000000, 0x00000000, 0x00000000, 0xbe86c51f };
++
++      ddr_ptr = (void *)((u64)readl(BMU2_BASE_ADDR + BMU_ALLOC_CTRL));
++      if (!ddr_ptr)
++              return;
++
++      lmem_ptr = (void *)((u64)readl(BMU1_BASE_ADDR + BMU_ALLOC_CTRL));
++      if (!lmem_ptr)
++              return;
++
++      pr_info("Sending a dummy pkt to HIF %p %p\n", ddr_ptr, lmem_ptr);
++      physaddr = (u32)DDR_VIRT_TO_PFE(ddr_ptr);
++
++      lmem_virt_addr = (void *)CBUS_PFE_TO_VIRT((unsigned long int)lmem_ptr);
++
++      local_hdr.phyno = htons(0); /* RX_PHY_0 */
++      local_hdr.length = htons(MIN_PKT_SIZE);
++
++      local_hdr.next_ptr = htonl((u32)physaddr);
++      /*Mark checksum is correct */
++      local_hdr.status = htonl((STATUS_IP_CHECKSUM_CORRECT |
++                              STATUS_UDP_CHECKSUM_CORRECT |
++                              STATUS_TCP_CHECKSUM_CORRECT |
++                              STATUS_UNICAST_HASH_MATCH |
++                              STATUS_CUMULATIVE_ARC_HIT));
++      copy_to_lmem((u32 *)lmem_virt_addr, (u32 *)&local_hdr,
++                   sizeof(local_hdr));
++
++      copy_to_lmem((u32 *)(lmem_virt_addr + LMEM_HDR_SIZE), (u32 *)dummy_pkt,
++                   0x40);
++
++      writel((unsigned long int)lmem_ptr, CLASS_INQ_PKTPTR);
++}
++
++void pfe_hif_rx_idle(struct pfe_hif *hif)
++{
++      int hif_stop_loop = 10;
++      u32 rx_status;
++
++      pfe_hif_disable_rx_desc(hif);
++      pr_info("Bringing hif to idle state...");
++      writel(0, HIF_INT_ENABLE);
++      /*If HIF Rx BDP is busy send a dummy packet */
++      do {
++              rx_status = readl(HIF_RX_STATUS);
++              if (rx_status & BDP_CSR_RX_DMA_ACTV)
++                      send_dummy_pkt_to_hif();
++
++              usleep_range(100, 150);
++      } while (--hif_stop_loop);
++
++      if (readl(HIF_RX_STATUS) & BDP_CSR_RX_DMA_ACTV)
++              pr_info("Failed\n");
++      else
++              pr_info("Done\n");
++}
++#endif
++
++static void pfe_hif_free_descr(struct pfe_hif *hif)
++{
++      pr_info("%s\n", __func__);
++
++      dma_free_coherent(pfe->dev,
++                        hif->rx_ring_size * sizeof(struct hif_desc) +
++                        hif->tx_ring_size * sizeof(struct hif_desc),
++                        hif->descr_baseaddr_v, hif->descr_baseaddr_p);
++}
++
++void pfe_hif_desc_dump(struct pfe_hif *hif)
++{
++      struct hif_desc *desc;
++      unsigned long desc_p;
++      int ii = 0;
++
++      pr_info("%s\n", __func__);
++
++      desc = hif->rx_base;
++      desc_p = (u32)((u64)desc - (u64)hif->descr_baseaddr_v +
++                      hif->descr_baseaddr_p);
++
++      pr_info("HIF Rx desc base %p physical %x\n", desc, (u32)desc_p);
++      for (ii = 0; ii < hif->rx_ring_size; ii++) {
++              pr_info("status: %08x, ctrl: %08x, data: %08x, next: %x\n",
++                      readl(&desc->status), readl(&desc->ctrl),
++                      readl(&desc->data), readl(&desc->next));
++                      desc++;
++      }
++
++      desc = hif->tx_base;
++      desc_p = ((u64)desc - (u64)hif->descr_baseaddr_v +
++                      hif->descr_baseaddr_p);
++
++      pr_info("HIF Tx desc base %p physical %x\n", desc, (u32)desc_p);
++      for (ii = 0; ii < hif->tx_ring_size; ii++) {
++              pr_info("status: %08x, ctrl: %08x, data: %08x, next: %x\n",
++                      readl(&desc->status), readl(&desc->ctrl),
++                      readl(&desc->data), readl(&desc->next));
++              desc++;
++      }
++}
++
++/* pfe_hif_release_buffers */
++static void pfe_hif_release_buffers(struct pfe_hif *hif)
++{
++      struct hif_desc *desc;
++      int i = 0;
++
++      hif->rx_base = hif->descr_baseaddr_v;
++
++      pr_info("%s\n", __func__);
++
++      /*Free Rx buffers */
++      desc = hif->rx_base;
++      for (i = 0; i < hif->rx_ring_size; i++) {
++              if (readl(&desc->data)) {
++                      if ((i < hif->shm->rx_buf_pool_cnt) &&
++                          (!hif->shm->rx_buf_pool[i])) {
++                              /*
++                               * dma_unmap_single(hif->dev, desc->data,
++                               * hif->rx_buf_len[i], DMA_FROM_DEVICE);
++                               */
++                              dma_unmap_single(hif->dev,
++                                               DDR_PFE_TO_PHYS(
++                                               readl(&desc->data)),
++                                               hif->rx_buf_len[i],
++                                               DMA_FROM_DEVICE);
++                              hif->shm->rx_buf_pool[i] = hif->rx_buf_addr[i];
++                      } else {
++                              pr_err("%s: buffer pool already full\n"
++                                      , __func__);
++                      }
++              }
++
++              writel(0, &desc->data);
++              writel(0, &desc->status);
++              writel(0, &desc->ctrl);
++              desc++;
++      }
++}
++
++/*
++ * pfe_hif_init_buffers
++ * This function initializes the HIF Rx/Tx ring descriptors and
++ * initialize Rx queue with buffers.
++ */
++static int pfe_hif_init_buffers(struct pfe_hif *hif)
++{
++      struct hif_desc *desc, *first_desc_p;
++      u32 data;
++      int i = 0;
++
++      pr_info("%s\n", __func__);
++
++      /* Check enough Rx buffers available in the shared memory */
++      if (hif->shm->rx_buf_pool_cnt < hif->rx_ring_size)
++              return -ENOMEM;
++
++      hif->rx_base = hif->descr_baseaddr_v;
++      memset(hif->rx_base, 0, hif->rx_ring_size * sizeof(struct hif_desc));
++
++      /*Initialize Rx descriptors */
++      desc = hif->rx_base;
++      first_desc_p = (struct hif_desc *)hif->descr_baseaddr_p;
++
++      for (i = 0; i < hif->rx_ring_size; i++) {
++              /* Initialize Rx buffers from the shared memory */
++
++              data = (u32)dma_map_single(hif->dev, hif->shm->rx_buf_pool[i],
++                              pfe_pkt_size, DMA_FROM_DEVICE);
++              hif->rx_buf_addr[i] = hif->shm->rx_buf_pool[i];
++              hif->rx_buf_len[i] = pfe_pkt_size;
++              hif->shm->rx_buf_pool[i] = NULL;
++
++              if (likely(dma_mapping_error(hif->dev, data) == 0)) {
++                      writel(DDR_PHYS_TO_PFE(data), &desc->data);
++              } else {
++                      pr_err("%s : low on mem\n",  __func__);
++
++                      goto err;
++              }
++
++              writel(0, &desc->status);
++
++              /*
++               * Ensure everything else is written to DDR before
++               * writing bd->ctrl
++               */
++              wmb();
++
++              writel((BD_CTRL_PKT_INT_EN | BD_CTRL_LIFM
++                      | BD_CTRL_DIR | BD_CTRL_DESC_EN
++                      | BD_BUF_LEN(pfe_pkt_size)), &desc->ctrl);
++
++              /* Chain descriptors */
++              writel((u32)DDR_PHYS_TO_PFE(first_desc_p + i + 1), &desc->next);
++              desc++;
++      }
++
++      /* Overwrite last descriptor to chain it to first one*/
++      desc--;
++      writel((u32)DDR_PHYS_TO_PFE(first_desc_p), &desc->next);
++
++      hif->rxtoclean_index = 0;
++
++      /*Initialize Rx buffer descriptor ring base address */
++      writel(DDR_PHYS_TO_PFE(hif->descr_baseaddr_p), HIF_RX_BDP_ADDR);
++
++      hif->tx_base = hif->rx_base + hif->rx_ring_size;
++      first_desc_p = (struct hif_desc *)hif->descr_baseaddr_p +
++                              hif->rx_ring_size;
++      memset(hif->tx_base, 0, hif->tx_ring_size * sizeof(struct hif_desc));
++
++      /*Initialize tx descriptors */
++      desc = hif->tx_base;
++
++      for (i = 0; i < hif->tx_ring_size; i++) {
++              /* Chain descriptors */
++              writel((u32)DDR_PHYS_TO_PFE(first_desc_p + i + 1), &desc->next);
++              writel(0, &desc->ctrl);
++              desc++;
++      }
++
++      /* Overwrite last descriptor to chain it to first one */
++      desc--;
++      writel((u32)DDR_PHYS_TO_PFE(first_desc_p), &desc->next);
++      hif->txavail = hif->tx_ring_size;
++      hif->txtosend = 0;
++      hif->txtoclean = 0;
++      hif->txtoflush = 0;
++
++      /*Initialize Tx buffer descriptor ring base address */
++      writel((u32)DDR_PHYS_TO_PFE(first_desc_p), HIF_TX_BDP_ADDR);
++
++      return 0;
++
++err:
++      pfe_hif_release_buffers(hif);
++      return -ENOMEM;
++}
++
++/*
++ * pfe_hif_client_register
++ *
++ * This function used to register a client driver with the HIF driver.
++ *
++ * Return value:
++ * 0 - on Successful registration
++ */
++static int pfe_hif_client_register(struct pfe_hif *hif, u32 client_id,
++                                 struct hif_client_shm *client_shm)
++{
++      struct hif_client *client = &hif->client[client_id];
++      u32 i, cnt;
++      struct rx_queue_desc *rx_qbase;
++      struct tx_queue_desc *tx_qbase;
++      struct hif_rx_queue *rx_queue;
++      struct hif_tx_queue *tx_queue;
++      int err = 0;
++
++      pr_info("%s\n", __func__);
++
++      spin_lock_bh(&hif->tx_lock);
++
++      if (test_bit(client_id, &hif->shm->g_client_status[0])) {
++              pr_err("%s: client %d already registered\n",
++                     __func__, client_id);
++              err = -1;
++              goto unlock;
++      }
++
++      memset(client, 0, sizeof(struct hif_client));
++
++      /* Initialize client Rx queues baseaddr, size */
++
++      cnt = CLIENT_CTRL_RX_Q_CNT(client_shm->ctrl);
++      /* Check if client is requesting for more queues than supported */
++      if (cnt > HIF_CLIENT_QUEUES_MAX)
++              cnt = HIF_CLIENT_QUEUES_MAX;
++
++      client->rx_qn = cnt;
++      rx_qbase = (struct rx_queue_desc *)client_shm->rx_qbase;
++      for (i = 0; i < cnt; i++) {
++              rx_queue = &client->rx_q[i];
++              rx_queue->base = rx_qbase + i * client_shm->rx_qsize;
++              rx_queue->size = client_shm->rx_qsize;
++              rx_queue->write_idx = 0;
++      }
++
++      /* Initialize client Tx queues baseaddr, size */
++      cnt = CLIENT_CTRL_TX_Q_CNT(client_shm->ctrl);
++
++      /* Check if client is requesting for more queues than supported */
++      if (cnt > HIF_CLIENT_QUEUES_MAX)
++              cnt = HIF_CLIENT_QUEUES_MAX;
++
++      client->tx_qn = cnt;
++      tx_qbase = (struct tx_queue_desc *)client_shm->tx_qbase;
++      for (i = 0; i < cnt; i++) {
++              tx_queue = &client->tx_q[i];
++              tx_queue->base = tx_qbase + i * client_shm->tx_qsize;
++              tx_queue->size = client_shm->tx_qsize;
++              tx_queue->ack_idx = 0;
++      }
++
++      set_bit(client_id, &hif->shm->g_client_status[0]);
++
++unlock:
++      spin_unlock_bh(&hif->tx_lock);
++
++      return err;
++}
++
++/*
++ * pfe_hif_client_unregister
++ *
++ * This function used to unregister a client  from the HIF driver.
++ *
++ */
++static void pfe_hif_client_unregister(struct pfe_hif *hif, u32 client_id)
++{
++      pr_info("%s\n", __func__);
++
++      /*
++       * Mark client as no longer available (which prevents further packet
++       * receive for this client)
++       */
++      spin_lock_bh(&hif->tx_lock);
++
++      if (!test_bit(client_id, &hif->shm->g_client_status[0])) {
++              pr_err("%s: client %d not registered\n", __func__,
++                     client_id);
++
++              spin_unlock_bh(&hif->tx_lock);
++              return;
++      }
++
++      clear_bit(client_id, &hif->shm->g_client_status[0]);
++
++      spin_unlock_bh(&hif->tx_lock);
++}
++
++/*
++ * client_put_rxpacket-
++ * This functions puts the Rx pkt  in the given client Rx queue.
++ * It actually swap the Rx pkt in the client Rx descriptor buffer
++ * and returns the free buffer from it.
++ *
++ * If the function returns NULL means client Rx queue is full and
++ * packet couldn't send to client queue.
++ */
++static void *client_put_rxpacket(struct hif_rx_queue *queue, void *pkt, u32 len,
++                               u32 flags, u32 client_ctrl, u32 *rem_len)
++{
++      void *free_pkt = NULL;
++      struct rx_queue_desc *desc = queue->base + queue->write_idx;
++
++      if (readl(&desc->ctrl) & CL_DESC_OWN) {
++              if (page_mode) {
++                      int rem_page_size = PAGE_SIZE -
++                                      PRESENT_OFST_IN_PAGE(pkt);
++                      int cur_pkt_size = ROUND_MIN_RX_SIZE(len +
++                                      pfe_pkt_headroom);
++                      *rem_len = (rem_page_size - cur_pkt_size);
++                      if (*rem_len) {
++                              free_pkt = pkt + cur_pkt_size;
++                              get_page(virt_to_page(free_pkt));
++                      } else {
++                              free_pkt = (void
++                              *)__get_free_page(GFP_ATOMIC | GFP_DMA_PFE);
++                              *rem_len = pfe_pkt_size;
++                      }
++              } else {
++                      free_pkt = kmalloc(PFE_BUF_SIZE, GFP_ATOMIC |
++                                      GFP_DMA_PFE);
++                      *rem_len = PFE_BUF_SIZE - pfe_pkt_headroom;
++              }
++
++              if (free_pkt) {
++                      desc->data = pkt;
++                      desc->client_ctrl = client_ctrl;
++                      /*
++                       * Ensure everything else is written to DDR before
++                       * writing bd->ctrl
++                       */
++                      smp_wmb();
++                      writel(CL_DESC_BUF_LEN(len) | flags, &desc->ctrl);
++                      /* queue->write_idx = (queue->write_idx + 1)
++                       *                     & (queue->size - 1);
++                       */
++                      free_pkt += pfe_pkt_headroom;
++              }
++      }
++
++      return free_pkt;
++}
++
++/*
++ * pfe_hif_rx_process-
++ * This function does pfe hif rx queue processing.
++ * Dequeue packet from Rx queue and send it to corresponding client queue
++ */
++static int pfe_hif_rx_process(struct pfe_hif *hif, int budget)
++{
++      struct hif_desc *desc;
++      struct hif_hdr *pkt_hdr;
++      struct __hif_hdr hif_hdr;
++      void *free_buf;
++      int rtc, len, rx_processed = 0;
++      struct __hif_desc local_desc;
++      int flags;
++      unsigned int desc_p;
++      unsigned int buf_size = 0;
++
++      spin_lock_bh(&hif->lock);
++
++      rtc = hif->rxtoclean_index;
++
++      while (rx_processed < budget) {
++              desc = hif->rx_base + rtc;
++
++              __memcpy12(&local_desc, desc);
++
++              /* ACK pending Rx interrupt */
++              if (local_desc.ctrl & BD_CTRL_DESC_EN) {
++                      writel(HIF_INT | HIF_RXPKT_INT, HIF_INT_SRC);
++
++                      if (rx_processed == 0) {
++                              if (napi_first_batch == 1) {
++                                      desc_p = hif->descr_baseaddr_p +
++                                      ((unsigned long int)(desc) -
++                                      (unsigned long
++                                      int)hif->descr_baseaddr_v);
++                                      napi_first_batch = 0;
++                              }
++                      }
++
++                      __memcpy12(&local_desc, desc);
++
++                      if (local_desc.ctrl & BD_CTRL_DESC_EN)
++                              break;
++              }
++
++              napi_first_batch = 0;
++
++#ifdef HIF_NAPI_STATS
++              hif->napi_counters[NAPI_DESC_COUNT]++;
++#endif
++              len = BD_BUF_LEN(local_desc.ctrl);
++              /*
++               * dma_unmap_single(hif->dev, DDR_PFE_TO_PHYS(local_desc.data),
++               * hif->rx_buf_len[rtc], DMA_FROM_DEVICE);
++               */
++              dma_unmap_single(hif->dev, DDR_PFE_TO_PHYS(local_desc.data),
++                               hif->rx_buf_len[rtc], DMA_FROM_DEVICE);
++
++              pkt_hdr = (struct hif_hdr *)hif->rx_buf_addr[rtc];
++
++              /* Track last HIF header received */
++              if (!hif->started) {
++                      hif->started = 1;
++
++                      __memcpy8(&hif_hdr, pkt_hdr);
++
++                      hif->qno = hif_hdr.hdr.q_num;
++                      hif->client_id = hif_hdr.hdr.client_id;
++                      hif->client_ctrl = (hif_hdr.hdr.client_ctrl1 << 16) |
++                                              hif_hdr.hdr.client_ctrl;
++                      flags = CL_DESC_FIRST;
++
++              } else {
++                      flags = 0;
++              }
++
++              if (local_desc.ctrl & BD_CTRL_LIFM)
++                      flags |= CL_DESC_LAST;
++
++              /* Check for valid client id and still registered */
++              if ((hif->client_id >= HIF_CLIENTS_MAX) ||
++                  !(test_bit(hif->client_id,
++                      &hif->shm->g_client_status[0]))) {
++                      printk_ratelimited("%s: packet with invalid client id %d q_num %d\n",
++                                         __func__,
++                                         hif->client_id,
++                                         hif->qno);
++
++                      free_buf = pkt_hdr;
++
++                      goto pkt_drop;
++              }
++
++              /* Check to valid queue number */
++              if (hif->client[hif->client_id].rx_qn <= hif->qno) {
++                      pr_info("%s: packet with invalid queue: %d\n"
++                              , __func__, hif->qno);
++                      hif->qno = 0;
++              }
++
++              free_buf =
++              client_put_rxpacket(&hif->client[hif->client_id].rx_q[hif->qno],
++                                  (void *)pkt_hdr, len, flags,
++                      hif->client_ctrl, &buf_size);
++
++              hif_lib_indicate_client(hif->client_id, EVENT_RX_PKT_IND,
++                                      hif->qno);
++
++              if (unlikely(!free_buf)) {
++#ifdef HIF_NAPI_STATS
++                      hif->napi_counters[NAPI_CLIENT_FULL_COUNT]++;
++#endif
++                      /*
++                       * If we want to keep in polling mode to retry later,
++                       * we need to tell napi that we consumed
++                       * the full budget or we will hit a livelock scenario.
++                       * The core code keeps this napi instance
++                       * at the head of the list and none of the other
++                       * instances get to run
++                       */
++                      rx_processed = budget;
++
++                      if (flags & CL_DESC_FIRST)
++                              hif->started = 0;
++
++                      break;
++              }
++
++pkt_drop:
++              /*Fill free buffer in the descriptor */
++              hif->rx_buf_addr[rtc] = free_buf;
++              hif->rx_buf_len[rtc] = min(pfe_pkt_size, buf_size);
++              writel((DDR_PHYS_TO_PFE
++                      ((u32)dma_map_single(hif->dev,
++                      free_buf, hif->rx_buf_len[rtc], DMA_FROM_DEVICE))),
++                      &desc->data);
++              /*
++               * Ensure everything else is written to DDR before
++               * writing bd->ctrl
++               */
++              wmb();
++              writel((BD_CTRL_PKT_INT_EN | BD_CTRL_LIFM | BD_CTRL_DIR |
++                      BD_CTRL_DESC_EN | BD_BUF_LEN(hif->rx_buf_len[rtc])),
++                      &desc->ctrl);
++
++              rtc = (rtc + 1) & (hif->rx_ring_size - 1);
++
++              if (local_desc.ctrl & BD_CTRL_LIFM) {
++                      if (!(hif->client_ctrl & HIF_CTRL_RX_CONTINUED)) {
++                              rx_processed++;
++
++#ifdef HIF_NAPI_STATS
++                              hif->napi_counters[NAPI_PACKET_COUNT]++;
++#endif
++                      }
++                      hif->started = 0;
++              }
++      }
++
++      hif->rxtoclean_index = rtc;
++      spin_unlock_bh(&hif->lock);
++
++      /* we made some progress, re-start rx dma in case it stopped */
++      hif_rx_dma_start();
++
++      return rx_processed;
++}
++
++/*
++ * client_ack_txpacket-
++ * This function ack the Tx packet in the give client Tx queue by resetting
++ * ownership bit in the descriptor.
++ */
++static int client_ack_txpacket(struct pfe_hif *hif, unsigned int client_id,
++                             unsigned int q_no)
++{
++      struct hif_tx_queue *queue = &hif->client[client_id].tx_q[q_no];
++      struct tx_queue_desc *desc = queue->base + queue->ack_idx;
++
++      if (readl(&desc->ctrl) & CL_DESC_OWN) {
++              writel((readl(&desc->ctrl) & ~CL_DESC_OWN), &desc->ctrl);
++              /* queue->ack_idx = (queue->ack_idx + 1) & (queue->size - 1); */
++
++              return 0;
++
++      } else {
++              /*This should not happen */
++              pr_err("%s: %d %d %d %d %d %p %d\n", __func__,
++                     hif->txtosend, hif->txtoclean, hif->txavail,
++                      client_id, q_no, queue, queue->ack_idx);
++              WARN(1, "%s: doesn't own this descriptor", __func__);
++              return 1;
++      }
++}
++
++void __hif_tx_done_process(struct pfe_hif *hif, int count)
++{
++      struct hif_desc *desc;
++      struct hif_desc_sw *desc_sw;
++      int ttc, tx_avl;
++      int pkts_done[HIF_CLIENTS_MAX] = {0, 0};
++
++      ttc = hif->txtoclean;
++      tx_avl = hif->txavail;
++
++      while ((tx_avl < hif->tx_ring_size) && count--) {
++              desc = hif->tx_base + ttc;
++
++              if (readl(&desc->ctrl) & BD_CTRL_DESC_EN)
++                      break;
++
++              desc_sw = &hif->tx_sw_queue[ttc];
++
++              if (desc_sw->data) {
++                      /*
++                       * dmap_unmap_single(hif->dev, desc_sw->data,
++                       * desc_sw->len, DMA_TO_DEVICE);
++                       */
++                      dma_unmap_single(hif->dev, desc_sw->data,
++                                       desc_sw->len, DMA_TO_DEVICE);
++              }
++
++              if (desc_sw->client_id > HIF_CLIENTS_MAX)
++                      pr_err("Invalid cl id %d\n", desc_sw->client_id);
++
++              pkts_done[desc_sw->client_id]++;
++
++              client_ack_txpacket(hif, desc_sw->client_id, desc_sw->q_no);
++
++              ttc = (ttc + 1) & (hif->tx_ring_size - 1);
++              tx_avl++;
++      }
++
++      if (pkts_done[0])
++              hif_lib_indicate_client(0, EVENT_TXDONE_IND, 0);
++      if (pkts_done[1])
++              hif_lib_indicate_client(1, EVENT_TXDONE_IND, 0);
++
++      hif->txtoclean = ttc;
++      hif->txavail = tx_avl;
++
++      if (!count) {
++              tasklet_schedule(&hif->tx_cleanup_tasklet);
++      } else {
++              /*Enable Tx done interrupt */
++              writel(readl_relaxed(HIF_INT_ENABLE) | HIF_TXPKT_INT,
++                     HIF_INT_ENABLE);
++      }
++}
++
++static void pfe_tx_do_cleanup(unsigned long data)
++{
++      struct pfe_hif *hif = (struct pfe_hif *)data;
++
++      writel(HIF_INT | HIF_TXPKT_INT, HIF_INT_SRC);
++
++      hif_tx_done_process(hif, 64);
++}
++
++/*
++ * __hif_xmit_pkt -
++ * This function puts one packet in the HIF Tx queue
++ */
++void __hif_xmit_pkt(struct pfe_hif *hif, unsigned int client_id, unsigned int
++                      q_no, void *data, u32 len, unsigned int flags)
++{
++      struct hif_desc *desc;
++      struct hif_desc_sw *desc_sw;
++
++      desc = hif->tx_base + hif->txtosend;
++      desc_sw = &hif->tx_sw_queue[hif->txtosend];
++
++      desc_sw->len = len;
++      desc_sw->client_id = client_id;
++      desc_sw->q_no = q_no;
++      desc_sw->flags = flags;
++
++      if (flags & HIF_DONT_DMA_MAP) {
++              desc_sw->data = 0;
++              writel((u32)DDR_PHYS_TO_PFE(data), &desc->data);
++      } else {
++              desc_sw->data = dma_map_single(hif->dev, data, len,
++                                              DMA_TO_DEVICE);
++              writel((u32)DDR_PHYS_TO_PFE(desc_sw->data), &desc->data);
++      }
++
++      hif->txtosend = (hif->txtosend + 1) & (hif->tx_ring_size - 1);
++      hif->txavail--;
++
++      if ((!((flags & HIF_DATA_VALID) && (flags &
++                              HIF_LAST_BUFFER))))
++              goto skip_tx;
++
++      /*
++       * Ensure everything else is written to DDR before
++       * writing bd->ctrl
++       */
++      wmb();
++
++      do {
++              desc_sw = &hif->tx_sw_queue[hif->txtoflush];
++              desc = hif->tx_base + hif->txtoflush;
++
++              if (desc_sw->flags & HIF_LAST_BUFFER) {
++                      writel((BD_CTRL_LIFM |
++                             BD_CTRL_BRFETCH_DISABLE | BD_CTRL_RTFETCH_DISABLE
++                             | BD_CTRL_PARSE_DISABLE | BD_CTRL_DESC_EN |
++                              BD_CTRL_PKT_INT_EN | BD_BUF_LEN(desc_sw->len)),
++                              &desc->ctrl);
++              } else {
++                      writel((BD_CTRL_DESC_EN |
++                              BD_BUF_LEN(desc_sw->len)), &desc->ctrl);
++              }
++              hif->txtoflush = (hif->txtoflush + 1) & (hif->tx_ring_size - 1);
++      }
++      while (hif->txtoflush != hif->txtosend)
++              ;
++
++skip_tx:
++      return;
++}
++
++int hif_xmit_pkt(struct pfe_hif *hif, unsigned int client_id, unsigned int q_no,
++               void *data, unsigned int len)
++{
++      int rc = 0;
++
++      spin_lock_bh(&hif->tx_lock);
++
++      if (!hif->txavail) {
++              rc = 1;
++      } else {
++              __hif_xmit_pkt(hif, client_id, q_no, data, len,
++                             HIF_FIRST_BUFFER | HIF_LAST_BUFFER);
++              hif_tx_dma_start();
++      }
++
++      if (hif->txavail < (hif->tx_ring_size >> 1))
++              __hif_tx_done_process(hif, TX_FREE_MAX_COUNT);
++
++      spin_unlock_bh(&hif->tx_lock);
++
++      return rc;
++}
++
++static irqreturn_t wol_isr(int irq, void *dev_id)
++{
++      pr_info("WoL\n");
++      gemac_set_wol(EMAC1_BASE_ADDR, 0);
++      gemac_set_wol(EMAC2_BASE_ADDR, 0);
++      return IRQ_HANDLED;
++}
++
++/*
++ * hif_isr-
++ * This ISR routine processes Rx/Tx done interrupts from the HIF hardware block
++ */
++static irqreturn_t hif_isr(int irq, void *dev_id)
++{
++      struct pfe_hif *hif = (struct pfe_hif *)dev_id;
++      int int_status;
++      int int_enable_mask;
++
++      /*Read hif interrupt source register */
++      int_status = readl_relaxed(HIF_INT_SRC);
++      int_enable_mask = readl_relaxed(HIF_INT_ENABLE);
++
++      if ((int_status & HIF_INT) == 0)
++              return IRQ_NONE;
++
++      int_status &= ~(HIF_INT);
++
++      if (int_status & HIF_RXPKT_INT) {
++              int_status &= ~(HIF_RXPKT_INT);
++              int_enable_mask &= ~(HIF_RXPKT_INT);
++
++              napi_first_batch = 1;
++
++              if (napi_schedule_prep(&hif->napi)) {
++#ifdef HIF_NAPI_STATS
++                      hif->napi_counters[NAPI_SCHED_COUNT]++;
++#endif
++                      __napi_schedule(&hif->napi);
++              }
++      }
++      if (int_status & HIF_TXPKT_INT) {
++              int_status &= ~(HIF_TXPKT_INT);
++              int_enable_mask &= ~(HIF_TXPKT_INT);
++              /*Schedule tx cleanup tassklet */
++              tasklet_schedule(&hif->tx_cleanup_tasklet);
++      }
++
++      /*Disable interrupts, they will be enabled after they are serviced */
++      writel_relaxed(int_enable_mask, HIF_INT_ENABLE);
++
++      if (int_status) {
++              pr_info("%s : Invalid interrupt : %d\n", __func__,
++                      int_status);
++              writel(int_status, HIF_INT_SRC);
++      }
++
++      return IRQ_HANDLED;
++}
++
++void hif_process_client_req(struct pfe_hif *hif, int req, int data1, int data2)
++{
++      unsigned int client_id = data1;
++
++      if (client_id >= HIF_CLIENTS_MAX) {
++              pr_err("%s: client id %d out of bounds\n", __func__,
++                     client_id);
++              return;
++      }
++
++      switch (req) {
++      case REQUEST_CL_REGISTER:
++                      /* Request for register a client */
++                      pr_info("%s: register client_id %d\n",
++                              __func__, client_id);
++                      pfe_hif_client_register(hif, client_id, (struct
++                              hif_client_shm *)&hif->shm->client[client_id]);
++                      break;
++
++      case REQUEST_CL_UNREGISTER:
++                      pr_info("%s: unregister client_id %d\n",
++                              __func__, client_id);
++
++                      /* Request for unregister a client */
++                      pfe_hif_client_unregister(hif, client_id);
++
++                      break;
++
++      default:
++                      pr_err("%s: unsupported request %d\n",
++                             __func__, req);
++                      break;
++      }
++
++      /*
++       * Process client Tx queues
++       * Currently we don't have checking for tx pending
++       */
++}
++
++/*
++ * pfe_hif_rx_poll
++ *  This function is NAPI poll function to process HIF Rx queue.
++ */
++static int pfe_hif_rx_poll(struct napi_struct *napi, int budget)
++{
++      struct pfe_hif *hif = container_of(napi, struct pfe_hif, napi);
++      int work_done;
++
++#ifdef HIF_NAPI_STATS
++      hif->napi_counters[NAPI_POLL_COUNT]++;
++#endif
++
++      work_done = pfe_hif_rx_process(hif, budget);
++
++      if (work_done < budget) {
++              napi_complete(napi);
++              writel(readl_relaxed(HIF_INT_ENABLE) | HIF_RXPKT_INT,
++                     HIF_INT_ENABLE);
++      }
++#ifdef HIF_NAPI_STATS
++      else
++              hif->napi_counters[NAPI_FULL_BUDGET_COUNT]++;
++#endif
++
++      return work_done;
++}
++
++/*
++ * pfe_hif_init
++ * This function initializes the baseaddresses and irq, etc.
++ */
++int pfe_hif_init(struct pfe *pfe)
++{
++      struct pfe_hif *hif = &pfe->hif;
++      int err;
++
++      pr_info("%s\n", __func__);
++
++      hif->dev = pfe->dev;
++      hif->irq = pfe->hif_irq;
++
++      err = pfe_hif_alloc_descr(hif);
++      if (err)
++              goto err0;
++
++      if (pfe_hif_init_buffers(hif)) {
++              pr_err("%s: Could not initialize buffer descriptors\n"
++                      , __func__);
++              err = -ENOMEM;
++              goto err1;
++      }
++
++      /* Initialize NAPI for Rx processing */
++      init_dummy_netdev(&hif->dummy_dev);
++      netif_napi_add(&hif->dummy_dev, &hif->napi, pfe_hif_rx_poll,
++                     HIF_RX_POLL_WEIGHT);
++      napi_enable(&hif->napi);
++
++      spin_lock_init(&hif->tx_lock);
++      spin_lock_init(&hif->lock);
++
++      hif_init();
++      hif_rx_enable();
++      hif_tx_enable();
++
++      /* Disable tx done interrupt */
++      writel(HIF_INT_MASK, HIF_INT_ENABLE);
++
++      gpi_enable(HGPI_BASE_ADDR);
++
++      err = request_irq(hif->irq, hif_isr, 0, "pfe_hif", hif);
++      if (err) {
++              pr_err("%s: failed to get the hif IRQ = %d\n",
++                     __func__, hif->irq);
++              goto err1;
++      }
++
++      err = request_irq(pfe->wol_irq, wol_isr, 0, "pfe_wol", pfe);
++      if (err) {
++              pr_err("%s: failed to get the wol IRQ = %d\n",
++                     __func__, pfe->wol_irq);
++              goto err1;
++      }
++
++      tasklet_init(&hif->tx_cleanup_tasklet,
++                   (void(*)(unsigned long))pfe_tx_do_cleanup,
++                   (unsigned long)hif);
++
++      return 0;
++err1:
++      pfe_hif_free_descr(hif);
++err0:
++      return err;
++}
++
++/* pfe_hif_exit- */
++void pfe_hif_exit(struct pfe *pfe)
++{
++      struct pfe_hif *hif = &pfe->hif;
++
++      pr_info("%s\n", __func__);
++
++      tasklet_kill(&hif->tx_cleanup_tasklet);
++
++      spin_lock_bh(&hif->lock);
++      hif->shm->g_client_status[0] = 0;
++      /* Make sure all clients are disabled*/
++      hif->shm->g_client_status[1] = 0;
++
++      spin_unlock_bh(&hif->lock);
++
++      /*Disable Rx/Tx */
++      gpi_disable(HGPI_BASE_ADDR);
++      hif_rx_disable();
++      hif_tx_disable();
++
++      napi_disable(&hif->napi);
++      netif_napi_del(&hif->napi);
++
++      free_irq(pfe->wol_irq, pfe);
++      free_irq(hif->irq, hif);
++
++      pfe_hif_release_buffers(hif);
++      pfe_hif_free_descr(hif);
++}
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_hif_lib.c
+@@ -0,0 +1,638 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/workqueue.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmapool.h>
++#include <linux/sched.h>
++#include <linux/skbuff.h>
++#include <linux/moduleparam.h>
++#include <linux/cpu.h>
++
++#include "pfe_mod.h"
++#include "pfe_hif.h"
++#include "pfe_hif_lib.h"
++
++unsigned int lro_mode;
++unsigned int page_mode;
++unsigned int tx_qos;
++unsigned int pfe_pkt_size;
++unsigned int pfe_pkt_headroom;
++unsigned int emac_txq_cnt;
++
++/*
++ * @pfe_hal_lib.c.
++ * Common functions used by HIF client drivers
++ */
++
++/*HIF shared memory Global variable */
++struct hif_shm ghif_shm;
++
++/* Cleanup the HIF shared memory, release HIF rx_buffer_pool.
++ * This function should be called after pfe_hif_exit
++ *
++ * @param[in] hif_shm         Shared memory address location in DDR
++ */
++static void pfe_hif_shm_clean(struct hif_shm *hif_shm)
++{
++      int i;
++      void *pkt;
++
++      for (i = 0; i < hif_shm->rx_buf_pool_cnt; i++) {
++              pkt = hif_shm->rx_buf_pool[i];
++              if (pkt) {
++                      hif_shm->rx_buf_pool[i] = NULL;
++                      pkt -= pfe_pkt_headroom;
++
++                      if (page_mode)
++                              put_page(virt_to_page(pkt));
++                      else
++                              kfree(pkt);
++              }
++      }
++}
++
++/* Initialize shared memory used between HIF driver and clients,
++ * allocate rx_buffer_pool required for HIF Rx descriptors.
++ * This function should be called before initializing HIF driver.
++ *
++ * @param[in] hif_shm         Shared memory address location in DDR
++ * @rerurn                    0 - on succes, <0 on fail to initialize
++ */
++static int pfe_hif_shm_init(struct hif_shm *hif_shm)
++{
++      int i;
++      void *pkt;
++
++      memset(hif_shm, 0, sizeof(struct hif_shm));
++      hif_shm->rx_buf_pool_cnt = HIF_RX_DESC_NT;
++
++      for (i = 0; i < hif_shm->rx_buf_pool_cnt; i++) {
++              if (page_mode) {
++                      pkt = (void *)__get_free_page(GFP_KERNEL |
++                              GFP_DMA_PFE);
++              } else {
++                      pkt = kmalloc(PFE_BUF_SIZE, GFP_KERNEL | GFP_DMA_PFE);
++              }
++
++              if (pkt)
++                      hif_shm->rx_buf_pool[i] = pkt + pfe_pkt_headroom;
++              else
++                      goto err0;
++      }
++
++      return 0;
++
++err0:
++      pr_err("%s Low memory\n", __func__);
++      pfe_hif_shm_clean(hif_shm);
++      return -ENOMEM;
++}
++
++/*This function sends indication to HIF driver
++ *
++ * @param[in] hif     hif context
++ */
++static void hif_lib_indicate_hif(struct pfe_hif *hif, int req, int data1, int
++                                      data2)
++{
++      hif_process_client_req(hif, req, data1, data2);
++}
++
++void hif_lib_indicate_client(int client_id, int event_type, int qno)
++{
++      struct hif_client_s *client = pfe->hif_client[client_id];
++
++      if (!client || (event_type >= HIF_EVENT_MAX) || (qno >=
++              HIF_CLIENT_QUEUES_MAX))
++              return;
++
++      if (!test_and_set_bit(qno, &client->queue_mask[event_type]))
++              client->event_handler(client->priv, event_type, qno);
++}
++
++/*This function releases Rx queue descriptors memory and pre-filled buffers
++ *
++ * @param[in] client  hif_client context
++ */
++static void hif_lib_client_release_rx_buffers(struct hif_client_s *client)
++{
++      struct rx_queue_desc *desc;
++      int qno, ii;
++      void *buf;
++
++      for (qno = 0; qno < client->rx_qn; qno++) {
++              desc = client->rx_q[qno].base;
++
++              for (ii = 0; ii < client->rx_q[qno].size; ii++) {
++                      buf = (void *)desc->data;
++                      if (buf) {
++                              buf -= pfe_pkt_headroom;
++
++                              if (page_mode)
++                                      free_page((unsigned long)buf);
++                              else
++                                      kfree(buf);
++
++                              desc->ctrl = 0;
++                      }
++
++                      desc++;
++              }
++      }
++
++      kfree(client->rx_qbase);
++}
++
++/*This function allocates memory for the rxq descriptors and pre-fill rx queues
++ * with buffers.
++ * @param[in] client  client context
++ * @param[in] q_size  size of the rxQ, all queues are of same size
++ */
++static int hif_lib_client_init_rx_buffers(struct hif_client_s *client, int
++                                              q_size)
++{
++      struct rx_queue_desc *desc;
++      struct hif_client_rx_queue *queue;
++      int ii, qno;
++
++      /*Allocate memory for the client queues */
++      client->rx_qbase = kzalloc(client->rx_qn * q_size * sizeof(struct
++                              rx_queue_desc), GFP_KERNEL);
++      if (!client->rx_qbase)
++              goto err;
++
++      for (qno = 0; qno < client->rx_qn; qno++) {
++              queue = &client->rx_q[qno];
++
++              queue->base = client->rx_qbase + qno * q_size * sizeof(struct
++                              rx_queue_desc);
++              queue->size = q_size;
++              queue->read_idx = 0;
++              queue->write_idx = 0;
++
++              pr_debug("rx queue: %d, base: %p, size: %d\n", qno,
++                       queue->base, queue->size);
++      }
++
++      for (qno = 0; qno < client->rx_qn; qno++) {
++              queue = &client->rx_q[qno];
++              desc = queue->base;
++
++              for (ii = 0; ii < queue->size; ii++) {
++                      desc->ctrl = CL_DESC_BUF_LEN(pfe_pkt_size) |
++                                      CL_DESC_OWN;
++                      desc++;
++              }
++      }
++
++      return 0;
++
++err:
++      return 1;
++}
++
++#define inc_cl_idx(idxname)                                   \
++      ({ typeof(idxname) idxname_ = (idxname);                \
++      ((idxname_) = (idxname_ + 1) & (queue->size - 1)); })
++
++static void hif_lib_client_cleanup_tx_queue(struct hif_client_tx_queue *queue)
++{
++      pr_debug("%s\n", __func__);
++
++      /*
++       * Check if there are any pending packets. Client must flush the tx
++       * queues before unregistering, by calling by calling
++       * hif_lib_tx_get_next_complete()
++       *
++       * Hif no longer calls since we are no longer registered
++       */
++      if (queue->tx_pending)
++              pr_err("%s: pending transmit packets\n", __func__);
++}
++
++static void hif_lib_client_release_tx_buffers(struct hif_client_s *client)
++{
++      int qno;
++
++      pr_debug("%s\n", __func__);
++
++      for (qno = 0; qno < client->tx_qn; qno++)
++              hif_lib_client_cleanup_tx_queue(&client->tx_q[qno]);
++
++      kfree(client->tx_qbase);
++}
++
++static int hif_lib_client_init_tx_buffers(struct hif_client_s *client, int
++                                              q_size)
++{
++      struct hif_client_tx_queue *queue;
++      int qno;
++
++      client->tx_qbase = kzalloc(client->tx_qn * q_size * sizeof(struct
++                                      tx_queue_desc), GFP_KERNEL);
++      if (!client->tx_qbase)
++              return 1;
++
++      for (qno = 0; qno < client->tx_qn; qno++) {
++              queue = &client->tx_q[qno];
++
++              queue->base = client->tx_qbase + qno * q_size * sizeof(struct
++                              tx_queue_desc);
++              queue->size = q_size;
++              queue->read_idx = 0;
++              queue->write_idx = 0;
++              queue->tx_pending = 0;
++              queue->nocpy_flag = 0;
++              queue->prev_tmu_tx_pkts = 0;
++              queue->done_tmu_tx_pkts = 0;
++
++              pr_debug("tx queue: %d, base: %p, size: %d\n", qno,
++                       queue->base, queue->size);
++      }
++
++      return 0;
++}
++
++static int hif_lib_event_dummy(void *priv, int event_type, int qno)
++{
++      return 0;
++}
++
++int hif_lib_client_register(struct hif_client_s *client)
++{
++      struct hif_shm *hif_shm;
++      struct hif_client_shm *client_shm;
++      int err, i;
++      /* int loop_cnt = 0; */
++
++      pr_debug("%s\n", __func__);
++
++      /*Allocate memory before spin_lock*/
++      if (hif_lib_client_init_rx_buffers(client, client->rx_qsize)) {
++              err = -ENOMEM;
++              goto err_rx;
++      }
++
++      if (hif_lib_client_init_tx_buffers(client, client->tx_qsize)) {
++              err = -ENOMEM;
++              goto err_tx;
++      }
++
++      spin_lock_bh(&pfe->hif.lock);
++      if (!(client->pfe) || (client->id >= HIF_CLIENTS_MAX) ||
++          (pfe->hif_client[client->id])) {
++              err = -EINVAL;
++              goto err;
++      }
++
++      hif_shm = client->pfe->hif.shm;
++
++      if (!client->event_handler)
++              client->event_handler = hif_lib_event_dummy;
++
++      /*Initialize client specific shared memory */
++      client_shm = (struct hif_client_shm *)&hif_shm->client[client->id];
++      client_shm->rx_qbase = (unsigned long int)client->rx_qbase;
++      client_shm->rx_qsize = client->rx_qsize;
++      client_shm->tx_qbase = (unsigned long int)client->tx_qbase;
++      client_shm->tx_qsize = client->tx_qsize;
++      client_shm->ctrl = (client->tx_qn << CLIENT_CTRL_TX_Q_CNT_OFST) |
++                              (client->rx_qn << CLIENT_CTRL_RX_Q_CNT_OFST);
++      /* spin_lock_init(&client->rx_lock); */
++
++      for (i = 0; i < HIF_EVENT_MAX; i++) {
++              client->queue_mask[i] = 0;  /*
++                                           * By default all events are
++                                           * unmasked
++                                           */
++      }
++
++      /*Indicate to HIF driver*/
++      hif_lib_indicate_hif(&pfe->hif, REQUEST_CL_REGISTER, client->id, 0);
++
++      pr_debug("%s: client: %p, client_id: %d, tx_qsize: %d, rx_qsize: %d\n",
++               __func__, client, client->id, client->tx_qsize,
++               client->rx_qsize);
++
++      client->cpu_id = -1;
++
++      pfe->hif_client[client->id] = client;
++      spin_unlock_bh(&pfe->hif.lock);
++
++      return 0;
++
++err:
++      spin_unlock_bh(&pfe->hif.lock);
++      hif_lib_client_release_tx_buffers(client);
++
++err_tx:
++      hif_lib_client_release_rx_buffers(client);
++
++err_rx:
++      return err;
++}
++
++int hif_lib_client_unregister(struct hif_client_s *client)
++{
++      struct pfe *pfe = client->pfe;
++      u32 client_id = client->id;
++
++      pr_info(
++              "%s : client: %p, client_id: %d, txQ_depth: %d, rxQ_depth: %d\n"
++              , __func__, client, client->id, client->tx_qsize,
++              client->rx_qsize);
++
++      spin_lock_bh(&pfe->hif.lock);
++      hif_lib_indicate_hif(&pfe->hif, REQUEST_CL_UNREGISTER, client->id, 0);
++
++      hif_lib_client_release_tx_buffers(client);
++      hif_lib_client_release_rx_buffers(client);
++      pfe->hif_client[client_id] = NULL;
++      spin_unlock_bh(&pfe->hif.lock);
++
++      return 0;
++}
++
++int hif_lib_event_handler_start(struct hif_client_s *client, int event,
++                              int qno)
++{
++      struct hif_client_rx_queue *queue = &client->rx_q[qno];
++      struct rx_queue_desc *desc = queue->base + queue->read_idx;
++
++      if ((event >= HIF_EVENT_MAX) || (qno >= HIF_CLIENT_QUEUES_MAX)) {
++              pr_debug("%s: Unsupported event : %d  queue number : %d\n",
++                       __func__, event, qno);
++              return -1;
++      }
++
++      test_and_clear_bit(qno, &client->queue_mask[event]);
++
++      switch (event) {
++      case EVENT_RX_PKT_IND:
++              if (!(desc->ctrl & CL_DESC_OWN))
++                      hif_lib_indicate_client(client->id,
++                                              EVENT_RX_PKT_IND, qno);
++              break;
++
++      case EVENT_HIGH_RX_WM:
++      case EVENT_TXDONE_IND:
++      default:
++              break;
++      }
++
++      return 0;
++}
++
++/*
++ * This function gets one packet from the specified client queue
++ * It also refill the rx buffer
++ */
++void *hif_lib_receive_pkt(struct hif_client_s *client, int qno, int *len, int
++                              *ofst, unsigned int *rx_ctrl,
++                              unsigned int *desc_ctrl, void **priv_data)
++{
++      struct hif_client_rx_queue *queue = &client->rx_q[qno];
++      struct rx_queue_desc *desc;
++      void *pkt = NULL;
++
++      /*
++       * Following lock is to protect rx queue access from,
++       * hif_lib_event_handler_start.
++       * In general below lock is not required, because hif_lib_xmit_pkt and
++       * hif_lib_event_handler_start are called from napi poll and which is
++       * not re-entrant. But if some client use in different way this lock is
++       * required.
++       */
++      /*spin_lock_irqsave(&client->rx_lock, flags); */
++      desc = queue->base + queue->read_idx;
++      if (!(desc->ctrl & CL_DESC_OWN)) {
++              pkt = desc->data - pfe_pkt_headroom;
++
++              *rx_ctrl = desc->client_ctrl;
++              *desc_ctrl = desc->ctrl;
++
++              if (desc->ctrl & CL_DESC_FIRST) {
++                      u16 size = *rx_ctrl >> HIF_CTRL_RX_OFFSET_OFST;
++
++                      if (size) {
++                              *len = CL_DESC_BUF_LEN(desc->ctrl) -
++                                              PFE_PKT_HEADER_SZ - size;
++                              *ofst = pfe_pkt_headroom + PFE_PKT_HEADER_SZ
++                                                              + size;
++                              *priv_data = desc->data + PFE_PKT_HEADER_SZ;
++                      } else {
++                              *len = CL_DESC_BUF_LEN(desc->ctrl) -
++                                              PFE_PKT_HEADER_SZ;
++                              *ofst = pfe_pkt_headroom + PFE_PKT_HEADER_SZ;
++                              *priv_data = NULL;
++                      }
++
++              } else {
++                      *len = CL_DESC_BUF_LEN(desc->ctrl);
++                      *ofst = pfe_pkt_headroom;
++              }
++
++              /*
++               * Needed so we don't free a buffer/page
++               * twice on module_exit
++               */
++              desc->data = NULL;
++
++              /*
++               * Ensure everything else is written to DDR before
++               * writing bd->ctrl
++               */
++              smp_wmb();
++
++              desc->ctrl = CL_DESC_BUF_LEN(pfe_pkt_size) | CL_DESC_OWN;
++              inc_cl_idx(queue->read_idx);
++      }
++
++      /*spin_unlock_irqrestore(&client->rx_lock, flags); */
++      return pkt;
++}
++
++static inline void hif_hdr_write(struct hif_hdr *pkt_hdr, unsigned int
++                                      client_id, unsigned int qno,
++                                      u32 client_ctrl)
++{
++      /* Optimize the write since the destinaton may be non-cacheable */
++      if (!((unsigned long)pkt_hdr & 0x3)) {
++              ((u32 *)pkt_hdr)[0] = (client_ctrl << 16) | (qno << 8) |
++                                      client_id;
++      } else {
++              ((u16 *)pkt_hdr)[0] = (qno << 8) | (client_id & 0xFF);
++              ((u16 *)pkt_hdr)[1] = (client_ctrl & 0xFFFF);
++      }
++}
++
++/*This function puts the given packet in the specific client queue */
++void __hif_lib_xmit_pkt(struct hif_client_s *client, unsigned int qno, void
++                              *data, unsigned int len, u32 client_ctrl,
++                              unsigned int flags, void *client_data)
++{
++      struct hif_client_tx_queue *queue = &client->tx_q[qno];
++      struct tx_queue_desc *desc = queue->base + queue->write_idx;
++
++      /* First buffer */
++      if (flags & HIF_FIRST_BUFFER) {
++              data -= sizeof(struct hif_hdr);
++              len += sizeof(struct hif_hdr);
++
++              hif_hdr_write(data, client->id, qno, client_ctrl);
++      }
++
++      desc->data = client_data;
++      desc->ctrl = CL_DESC_OWN | CL_DESC_FLAGS(flags);
++
++      __hif_xmit_pkt(&pfe->hif, client->id, qno, data, len, flags);
++
++      inc_cl_idx(queue->write_idx);
++      queue->tx_pending++;
++      queue->jiffies_last_packet = jiffies;
++}
++
++/*This function puts the given packet in the specific client queue */
++int hif_lib_xmit_pkt(struct hif_client_s *client, unsigned int qno, void *data,
++                   unsigned int len, u32 client_ctrl, void *client_data)
++{
++      struct hif_client_tx_queue *queue = &client->tx_q[qno];
++      struct tx_queue_desc *desc = queue->base + queue->write_idx;
++
++      if (queue->tx_pending < queue->size) {
++              /*Construct pkt header */
++
++              data -= sizeof(struct hif_hdr);
++              len += sizeof(struct hif_hdr);
++
++              hif_hdr_write(data, client->id, qno, client_ctrl);
++
++              desc->data = client_data;
++              desc->ctrl = CL_DESC_OWN | CL_DESC_FLAGS(HIF_FIRST_BUFFER |
++                              HIF_LAST_BUFFER | HIF_DATA_VALID);
++
++              if (hif_xmit_pkt(&pfe->hif, client->id, qno, data, len))
++                      return 1;
++
++              inc_cl_idx(queue->write_idx);
++              queue->tx_pending++;
++              queue->jiffies_last_packet = jiffies;
++
++              return 0;
++      }
++
++      pr_debug("%s Tx client %d qno %d is full\n", __func__, client->id,
++               qno);
++      return 1;
++}
++
++void *hif_lib_tx_get_next_complete(struct hif_client_s *client, int qno,
++                                 unsigned int *flags, int count)
++{
++      struct hif_client_tx_queue *queue = &client->tx_q[qno];
++      struct tx_queue_desc *desc = queue->base + queue->read_idx;
++
++      pr_debug("%s: qno : %d rd_indx: %d pending:%d\n", __func__, qno,
++               queue->read_idx, queue->tx_pending);
++
++      if (!queue->tx_pending)
++              return NULL;
++
++      if (queue->nocpy_flag && !queue->done_tmu_tx_pkts) {
++              u32 tmu_tx_pkts = be32_to_cpu(pe_dmem_read(TMU0_ID +
++                      client->id, TMU_DM_TX_TRANS, 4));
++
++              if (queue->prev_tmu_tx_pkts > tmu_tx_pkts)
++                      queue->done_tmu_tx_pkts = UINT_MAX -
++                              queue->prev_tmu_tx_pkts + tmu_tx_pkts;
++              else
++                      queue->done_tmu_tx_pkts = tmu_tx_pkts -
++                                              queue->prev_tmu_tx_pkts;
++
++              queue->prev_tmu_tx_pkts  = tmu_tx_pkts;
++
++              if (!queue->done_tmu_tx_pkts)
++                      return NULL;
++      }
++
++      if (desc->ctrl & CL_DESC_OWN)
++              return NULL;
++
++      inc_cl_idx(queue->read_idx);
++      queue->tx_pending--;
++
++      *flags = CL_DESC_GET_FLAGS(desc->ctrl);
++
++      if (queue->done_tmu_tx_pkts && (*flags & HIF_LAST_BUFFER))
++              queue->done_tmu_tx_pkts--;
++
++      return desc->data;
++}
++
++static void hif_lib_tmu_credit_init(struct pfe *pfe)
++{
++      int i, q;
++
++      for (i = 0; i < NUM_GEMAC_SUPPORT; i++)
++              for (q = 0; q < emac_txq_cnt; q++) {
++                      pfe->tmu_credit.tx_credit_max[i][q] = (q == 0) ?
++                                      DEFAULT_Q0_QDEPTH : DEFAULT_MAX_QDEPTH;
++                      pfe->tmu_credit.tx_credit[i][q] =
++                                      pfe->tmu_credit.tx_credit_max[i][q];
++              }
++}
++
++int pfe_hif_lib_init(struct pfe *pfe)
++{
++      int rc;
++
++      pr_info("%s\n", __func__);
++
++      if (lro_mode) {
++              page_mode = 1;
++              pfe_pkt_size = min(PAGE_SIZE, MAX_PFE_PKT_SIZE);
++              pfe_pkt_headroom = 0;
++      } else {
++              page_mode = 0;
++              pfe_pkt_size = PFE_PKT_SIZE;
++              pfe_pkt_headroom = PFE_PKT_HEADROOM;
++      }
++
++      if (tx_qos)
++              emac_txq_cnt = EMAC_TXQ_CNT / 2;
++      else
++              emac_txq_cnt = EMAC_TXQ_CNT;
++
++      hif_lib_tmu_credit_init(pfe);
++      pfe->hif.shm = &ghif_shm;
++      rc = pfe_hif_shm_init(pfe->hif.shm);
++
++      return rc;
++}
++
++void pfe_hif_lib_exit(struct pfe *pfe)
++{
++      pr_info("%s\n", __func__);
++
++      pfe_hif_shm_clean(pfe->hif.shm);
++}
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_hw.c
+@@ -0,0 +1,176 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "pfe_mod.h"
++#include "pfe_hw.h"
++
++/* Functions to handle most of pfe hw register initialization */
++int pfe_hw_init(struct pfe *pfe, int resume)
++{
++      struct class_cfg class_cfg = {
++              .pe_sys_clk_ratio = PE_SYS_CLK_RATIO,
++              .route_table_baseaddr = pfe->ddr_phys_baseaddr +
++                                      ROUTE_TABLE_BASEADDR,
++              .route_table_hash_bits = ROUTE_TABLE_HASH_BITS,
++      };
++
++      struct tmu_cfg tmu_cfg = {
++              .pe_sys_clk_ratio = PE_SYS_CLK_RATIO,
++              .llm_base_addr = pfe->ddr_phys_baseaddr + TMU_LLM_BASEADDR,
++              .llm_queue_len = TMU_LLM_QUEUE_LEN,
++      };
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      struct util_cfg util_cfg = {
++              .pe_sys_clk_ratio = PE_SYS_CLK_RATIO,
++      };
++#endif
++
++      struct BMU_CFG bmu1_cfg = {
++              .baseaddr = CBUS_VIRT_TO_PFE(LMEM_BASE_ADDR +
++                                              BMU1_LMEM_BASEADDR),
++              .count = BMU1_BUF_COUNT,
++              .size = BMU1_BUF_SIZE,
++              .low_watermark = 10,
++              .high_watermark = 15,
++      };
++
++      struct BMU_CFG bmu2_cfg = {
++              .baseaddr = DDR_PHYS_TO_PFE(pfe->ddr_phys_baseaddr +
++                                              BMU2_DDR_BASEADDR),
++              .count = BMU2_BUF_COUNT,
++              .size = BMU2_BUF_SIZE,
++              .low_watermark = 250,
++              .high_watermark = 253,
++      };
++
++      struct gpi_cfg egpi1_cfg = {
++              .lmem_rtry_cnt = EGPI1_LMEM_RTRY_CNT,
++              .tmlf_txthres = EGPI1_TMLF_TXTHRES,
++              .aseq_len = EGPI1_ASEQ_LEN,
++              .mtip_pause_reg = CBUS_VIRT_TO_PFE(EMAC1_BASE_ADDR +
++                                              EMAC_TCNTRL_REG),
++      };
++
++      struct gpi_cfg egpi2_cfg = {
++              .lmem_rtry_cnt = EGPI2_LMEM_RTRY_CNT,
++              .tmlf_txthres = EGPI2_TMLF_TXTHRES,
++              .aseq_len = EGPI2_ASEQ_LEN,
++              .mtip_pause_reg = CBUS_VIRT_TO_PFE(EMAC2_BASE_ADDR +
++                                              EMAC_TCNTRL_REG),
++      };
++
++      struct gpi_cfg hgpi_cfg = {
++              .lmem_rtry_cnt = HGPI_LMEM_RTRY_CNT,
++              .tmlf_txthres = HGPI_TMLF_TXTHRES,
++              .aseq_len = HGPI_ASEQ_LEN,
++              .mtip_pause_reg = 0,
++      };
++
++      pr_info("%s\n", __func__);
++
++#if !defined(LS1012A_PFE_RESET_WA)
++      /* LS1012A needs this to make PE work correctly */
++      writel(0x3,     CLASS_PE_SYS_CLK_RATIO);
++      writel(0x3,     TMU_PE_SYS_CLK_RATIO);
++      writel(0x3,     UTIL_PE_SYS_CLK_RATIO);
++      usleep_range(10, 20);
++#endif
++
++      pr_info("CLASS version: %x\n", readl(CLASS_VERSION));
++      pr_info("TMU version: %x\n", readl(TMU_VERSION));
++
++      pr_info("BMU1 version: %x\n", readl(BMU1_BASE_ADDR +
++              BMU_VERSION));
++      pr_info("BMU2 version: %x\n", readl(BMU2_BASE_ADDR +
++              BMU_VERSION));
++
++      pr_info("EGPI1 version: %x\n", readl(EGPI1_BASE_ADDR +
++              GPI_VERSION));
++      pr_info("EGPI2 version: %x\n", readl(EGPI2_BASE_ADDR +
++              GPI_VERSION));
++      pr_info("HGPI version: %x\n", readl(HGPI_BASE_ADDR +
++              GPI_VERSION));
++
++      pr_info("HIF version: %x\n", readl(HIF_VERSION));
++      pr_info("HIF NOPCY version: %x\n", readl(HIF_NOCPY_VERSION));
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      pr_info("UTIL version: %x\n", readl(UTIL_VERSION));
++#endif
++      while (!(readl(TMU_CTRL) & ECC_MEM_INIT_DONE))
++              ;
++
++      hif_rx_disable();
++      hif_tx_disable();
++
++      bmu_init(BMU1_BASE_ADDR, &bmu1_cfg);
++
++      pr_info("bmu_init(1) done\n");
++
++      bmu_init(BMU2_BASE_ADDR, &bmu2_cfg);
++
++      pr_info("bmu_init(2) done\n");
++
++      class_cfg.resume = resume ? 1 : 0;
++
++      class_init(&class_cfg);
++
++      pr_info("class_init() done\n");
++
++      tmu_init(&tmu_cfg);
++
++      pr_info("tmu_init() done\n");
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      util_init(&util_cfg);
++
++      pr_info("util_init() done\n");
++#endif
++      gpi_init(EGPI1_BASE_ADDR, &egpi1_cfg);
++
++      pr_info("gpi_init(1) done\n");
++
++      gpi_init(EGPI2_BASE_ADDR, &egpi2_cfg);
++
++      pr_info("gpi_init(2) done\n");
++
++      gpi_init(HGPI_BASE_ADDR, &hgpi_cfg);
++
++      pr_info("gpi_init(hif) done\n");
++
++      bmu_enable(BMU1_BASE_ADDR);
++
++      pr_info("bmu_enable(1) done\n");
++
++      bmu_enable(BMU2_BASE_ADDR);
++
++      pr_info("bmu_enable(2) done\n");
++
++      return 0;
++}
++
++void pfe_hw_exit(struct pfe *pfe)
++{
++      pr_info("%s\n", __func__);
++
++      bmu_disable(BMU1_BASE_ADDR);
++      bmu_reset(BMU1_BASE_ADDR);
++
++      bmu_disable(BMU2_BASE_ADDR);
++      bmu_reset(BMU2_BASE_ADDR);
++}
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
+@@ -0,0 +1,394 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/of_net.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/clk.h>
++#include <linux/mfd/syscon.h>
++#include <linux/regmap.h>
++
++#include "pfe_mod.h"
++
++struct ls1012a_pfe_platform_data pfe_platform_data;
++
++static int pfe_get_gemac_if_proprties(struct device_node *parent, int port, int
++                                      if_cnt,
++                                      struct ls1012a_pfe_platform_data
++                                      *pdata)
++{
++      struct device_node *gem = NULL, *phy = NULL;
++      int size;
++      int ii = 0, phy_id = 0;
++      const u32 *addr;
++      const void *mac_addr;
++
++      for (ii = 0; ii < if_cnt; ii++) {
++              gem = of_get_next_child(parent, gem);
++              if (!gem)
++                      goto err;
++              addr = of_get_property(gem, "reg", &size);
++              if (addr && (be32_to_cpup(addr) == port))
++                      break;
++      }
++
++      if (ii >= if_cnt) {
++              pr_err("%s:%d Failed to find interface = %d\n",
++                     __func__, __LINE__, if_cnt);
++              goto err;
++      }
++
++      pdata->ls1012a_eth_pdata[port].gem_id = port;
++
++      mac_addr = of_get_mac_address(gem);
++
++      if (mac_addr) {
++              memcpy(pdata->ls1012a_eth_pdata[port].mac_addr, mac_addr,
++                     ETH_ALEN);
++      }
++
++      pdata->ls1012a_eth_pdata[port].mii_config = of_get_phy_mode(gem);
++
++      if ((pdata->ls1012a_eth_pdata[port].mii_config) < 0)
++              pr_err("%s:%d Incorrect Phy mode....\n", __func__,
++                     __LINE__);
++
++      addr = of_get_property(gem, "fsl,gemac-bus-id", &size);
++      if (!addr)
++              pr_err("%s:%d Invalid gemac-bus-id....\n", __func__,
++                     __LINE__);
++      else
++              pdata->ls1012a_eth_pdata[port].bus_id = be32_to_cpup(addr);
++
++      addr = of_get_property(gem, "fsl,gemac-phy-id", &size);
++      if (!addr) {
++              pr_err("%s:%d Invalid gemac-phy-id....\n", __func__,
++                     __LINE__);
++      } else {
++              phy_id = be32_to_cpup(addr);
++              pdata->ls1012a_eth_pdata[port].phy_id = phy_id;
++              pdata->ls1012a_mdio_pdata[0].phy_mask &= ~(1 << phy_id);
++      }
++
++      addr = of_get_property(gem, "fsl,mdio-mux-val", &size);
++      if (!addr)
++              pr_err("%s: Invalid mdio-mux-val....\n", __func__);
++      else
++              phy_id = be32_to_cpup(addr);
++              pdata->ls1012a_eth_pdata[port].mdio_muxval = phy_id;
++
++      if (pdata->ls1012a_eth_pdata[port].phy_id < 32)
++              pfe->mdio_muxval[pdata->ls1012a_eth_pdata[port].phy_id] =
++                       pdata->ls1012a_eth_pdata[port].mdio_muxval;
++
++      addr = of_get_property(gem, "fsl,pfe-phy-if-flags", &size);
++      if (!addr)
++              pr_err("%s:%d Invalid pfe-phy-if-flags....\n",
++                     __func__, __LINE__);
++      else
++              pdata->ls1012a_eth_pdata[port].phy_flags = be32_to_cpup(addr);
++
++      /* If PHY is enabled, read mdio properties */
++      if (pdata->ls1012a_eth_pdata[port].phy_flags & GEMAC_NO_PHY)
++              goto done;
++
++      phy = of_get_next_child(gem, NULL);
++
++      addr = of_get_property(phy, "reg", &size);
++
++      if (!addr)
++              pr_err("%s:%d Invalid phy enable flag....\n",
++                     __func__, __LINE__);
++      else
++              pdata->ls1012a_mdio_pdata[port].enabled = be32_to_cpup(addr);
++
++      pdata->ls1012a_mdio_pdata[port].irq[0] = PHY_POLL;
++
++done:
++
++      return 0;
++
++err:
++      return -1;
++}
++
++/*
++ *
++ * pfe_platform_probe -
++ *
++ *
++ */
++static int pfe_platform_probe(struct platform_device *pdev)
++{
++      struct resource res;
++      int ii, rc, interface_count = 0, size = 0;
++      const u32 *prop;
++      struct device_node  *np;
++      struct clk *pfe_clk;
++
++      np = pdev->dev.of_node;
++
++      if (!np) {
++              pr_err("Invalid device node\n");
++              return -EINVAL;
++      }
++
++      pfe = kzalloc(sizeof(*pfe), GFP_KERNEL);
++      if (!pfe) {
++              rc = -ENOMEM;
++              goto err_alloc;
++      }
++
++      platform_set_drvdata(pdev, pfe);
++
++      dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
++
++      if (of_address_to_resource(np, 1, &res)) {
++              rc = -ENOMEM;
++              pr_err("failed to get ddr resource\n");
++              goto err_ddr;
++      }
++
++      pfe->ddr_phys_baseaddr = res.start;
++      pfe->ddr_size = resource_size(&res);
++
++      pfe->ddr_baseaddr = phys_to_virt(res.start);
++      if (!pfe->ddr_baseaddr) {
++              pr_err("ioremap() ddr failed\n");
++              rc = -ENOMEM;
++              goto err_ddr;
++      }
++
++      pfe->scfg =
++              syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
++                                              "fsl,pfe-scfg");
++      if (IS_ERR(pfe->scfg)) {
++              dev_err(&pdev->dev, "No syscfg phandle specified\n");
++              return PTR_ERR(pfe->scfg);
++      }
++
++      pfe->cbus_baseaddr = of_iomap(np, 0);
++      if (!pfe->cbus_baseaddr) {
++              rc = -ENOMEM;
++              pr_err("failed to get axi resource\n");
++              goto err_axi;
++      }
++
++      pfe->hif_irq = platform_get_irq(pdev, 0);
++      if (pfe->hif_irq < 0) {
++              pr_err("platform_get_irq for hif failed\n");
++              rc = pfe->hif_irq;
++              goto err_hif_irq;
++      }
++
++      pfe->wol_irq = platform_get_irq(pdev, 2);
++      if (pfe->wol_irq < 0) {
++              pr_err("platform_get_irq for WoL failed\n");
++              rc = pfe->wol_irq;
++              goto err_hif_irq;
++      }
++
++      /* Read interface count */
++      prop = of_get_property(np, "fsl,pfe-num-interfaces", &size);
++      if (!prop) {
++              pr_err("Failed to read number of interfaces\n");
++              rc = -ENXIO;
++              goto err_prop;
++      }
++
++      interface_count = be32_to_cpup(prop);
++      if (interface_count <= 0) {
++              pr_err("No ethernet interface count : %d\n",
++                     interface_count);
++              rc = -ENXIO;
++              goto err_prop;
++      }
++
++      pfe_platform_data.ls1012a_mdio_pdata[0].phy_mask = 0xffffffff;
++
++      for (ii = 0; ii < interface_count; ii++) {
++              pfe_get_gemac_if_proprties(np, ii, interface_count,
++                                         &pfe_platform_data);
++      }
++
++      pfe->dev = &pdev->dev;
++
++      pfe->dev->platform_data = &pfe_platform_data;
++
++      /* declare WoL capabilities */
++      device_init_wakeup(&pdev->dev, true);
++
++      /* find the clocks */
++      pfe_clk = devm_clk_get(pfe->dev, "pfe");
++      if (IS_ERR(pfe_clk))
++              return PTR_ERR(pfe_clk);
++
++      /* PFE clock is (platform clock / 2) */
++      /* save sys_clk value as KHz */
++      pfe->ctrl.sys_clk = clk_get_rate(pfe_clk) / (2 * 1000);
++
++      rc = pfe_probe(pfe);
++      if (rc < 0)
++              goto err_probe;
++
++      return 0;
++
++err_probe:
++err_prop:
++err_hif_irq:
++      iounmap(pfe->cbus_baseaddr);
++
++err_axi:
++      iounmap(pfe->ddr_baseaddr);
++
++err_ddr:
++      platform_set_drvdata(pdev, NULL);
++
++      kfree(pfe);
++
++err_alloc:
++      return rc;
++}
++
++/*
++ * pfe_platform_remove -
++ */
++static int pfe_platform_remove(struct platform_device *pdev)
++{
++      struct pfe *pfe = platform_get_drvdata(pdev);
++      int rc;
++
++      pr_info("%s\n", __func__);
++
++      rc = pfe_remove(pfe);
++
++      iounmap(pfe->cbus_baseaddr);
++      iounmap(pfe->ddr_baseaddr);
++
++      platform_set_drvdata(pdev, NULL);
++
++      kfree(pfe);
++
++      return rc;
++}
++
++#ifdef CONFIG_PM
++#ifdef CONFIG_PM_SLEEP
++int pfe_platform_suspend(struct device *dev)
++{
++      struct pfe *pfe = platform_get_drvdata(to_platform_device(dev));
++      struct net_device *netdev;
++      int i;
++
++      pfe->wake = 0;
++
++      for (i = 0; i < (NUM_GEMAC_SUPPORT); i++) {
++              netdev = pfe->eth.eth_priv[i]->ndev;
++
++              netif_device_detach(netdev);
++
++              if (netif_running(netdev))
++                      if (pfe_eth_suspend(netdev))
++                              pfe->wake = 1;
++      }
++
++      /* Shutdown PFE only if we're not waking up the system */
++      if (!pfe->wake) {
++#if defined(LS1012A_PFE_RESET_WA)
++              pfe_hif_rx_idle(&pfe->hif);
++#endif
++              pfe_ctrl_suspend(&pfe->ctrl);
++              pfe_firmware_exit(pfe);
++
++              pfe_hif_exit(pfe);
++              pfe_hif_lib_exit(pfe);
++
++              pfe_hw_exit(pfe);
++      }
++
++      return 0;
++}
++
++static int pfe_platform_resume(struct device *dev)
++{
++      struct pfe *pfe = platform_get_drvdata(to_platform_device(dev));
++      struct net_device *netdev;
++      int i;
++
++      if (!pfe->wake) {
++              pfe_hw_init(pfe, 1);
++              pfe_hif_lib_init(pfe);
++              pfe_hif_init(pfe);
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++              util_enable();
++#endif
++              tmu_enable(0xf);
++              class_enable();
++              pfe_ctrl_resume(&pfe->ctrl);
++      }
++
++      for (i = 0; i < (NUM_GEMAC_SUPPORT); i++) {
++              netdev = pfe->eth.eth_priv[i]->ndev;
++
++              if (pfe->eth.eth_priv[i]->mii_bus)
++                      pfe_eth_mdio_reset(pfe->eth.eth_priv[i]->mii_bus);
++
++              if (netif_running(netdev))
++                      pfe_eth_resume(netdev);
++
++              netif_device_attach(netdev);
++      }
++      return 0;
++}
++#else
++#define pfe_platform_suspend NULL
++#define pfe_platform_resume NULL
++#endif
++
++static const struct dev_pm_ops pfe_platform_pm_ops = {
++      SET_SYSTEM_SLEEP_PM_OPS(pfe_platform_suspend, pfe_platform_resume)
++};
++#endif
++
++static const struct of_device_id pfe_match[] = {
++      {
++              .compatible = "fsl,pfe",
++      },
++      {},
++};
++MODULE_DEVICE_TABLE(of, pfe_match);
++
++static struct platform_driver pfe_platform_driver = {
++      .probe = pfe_platform_probe,
++      .remove = pfe_platform_remove,
++      .driver = {
++              .name = "pfe",
++              .of_match_table = pfe_match,
++#ifdef CONFIG_PM
++              .pm = &pfe_platform_pm_ops,
++#endif
++      },
++};
++
++module_platform_driver(pfe_platform_driver);
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("PFE Ethernet driver");
++MODULE_AUTHOR("NXP DNCPE");
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_mod.c
+@@ -0,0 +1,141 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/dma-mapping.h>
++#include "pfe_mod.h"
++
++struct pfe *pfe;
++
++/*
++ * pfe_probe -
++ */
++int pfe_probe(struct pfe *pfe)
++{
++      int rc;
++
++      if (pfe->ddr_size < DDR_MAX_SIZE) {
++              pr_err("%s: required DDR memory (%x) above platform ddr memory (%x)\n",
++                     __func__, (unsigned int)DDR_MAX_SIZE, pfe->ddr_size);
++              rc = -ENOMEM;
++              goto err_hw;
++      }
++
++      if (((int)(pfe->ddr_phys_baseaddr + BMU2_DDR_BASEADDR) &
++                      (8 * SZ_1M - 1)) != 0) {
++              pr_err("%s: BMU2 base address (0x%x) must be aligned on 8MB boundary\n",
++                     __func__, (int)pfe->ddr_phys_baseaddr +
++                      BMU2_DDR_BASEADDR);
++              rc = -ENOMEM;
++              goto err_hw;
++      }
++
++      pr_info("cbus_baseaddr: %lx, ddr_baseaddr: %lx, ddr_phys_baseaddr: %lx, ddr_size: %x\n",
++              (unsigned long)pfe->cbus_baseaddr,
++              (unsigned long)pfe->ddr_baseaddr,
++              pfe->ddr_phys_baseaddr, pfe->ddr_size);
++
++      pfe_lib_init(pfe->cbus_baseaddr, pfe->ddr_baseaddr,
++                   pfe->ddr_phys_baseaddr, pfe->ddr_size);
++
++      rc = pfe_hw_init(pfe, 0);
++      if (rc < 0)
++              goto err_hw;
++
++      rc = pfe_hif_lib_init(pfe);
++      if (rc < 0)
++              goto err_hif_lib;
++
++      rc = pfe_hif_init(pfe);
++      if (rc < 0)
++              goto err_hif;
++
++      rc = pfe_firmware_init(pfe);
++      if (rc < 0)
++              goto err_firmware;
++
++      rc = pfe_ctrl_init(pfe);
++      if (rc < 0)
++              goto err_ctrl;
++
++      rc = pfe_eth_init(pfe);
++      if (rc < 0)
++              goto err_eth;
++
++      rc = pfe_sysfs_init(pfe);
++      if (rc < 0)
++              goto err_sysfs;
++
++      rc = pfe_debugfs_init(pfe);
++      if (rc < 0)
++              goto err_debugfs;
++
++      return 0;
++
++err_debugfs:
++      pfe_sysfs_exit(pfe);
++
++err_sysfs:
++      pfe_eth_exit(pfe);
++
++err_eth:
++      pfe_ctrl_exit(pfe);
++
++err_ctrl:
++      pfe_firmware_exit(pfe);
++
++err_firmware:
++      pfe_hif_exit(pfe);
++
++err_hif:
++      pfe_hif_lib_exit(pfe);
++
++err_hif_lib:
++      pfe_hw_exit(pfe);
++
++err_hw:
++      return rc;
++}
++
++/*
++ * pfe_remove -
++ */
++int pfe_remove(struct pfe *pfe)
++{
++      pr_info("%s\n", __func__);
++
++      pfe_debugfs_exit(pfe);
++
++      pfe_sysfs_exit(pfe);
++
++      pfe_eth_exit(pfe);
++
++      pfe_ctrl_exit(pfe);
++
++#if defined(LS1012A_PFE_RESET_WA)
++      pfe_hif_rx_idle(&pfe->hif);
++#endif
++      pfe_firmware_exit(pfe);
++
++      pfe_hif_exit(pfe);
++
++      pfe_hif_lib_exit(pfe);
++
++      pfe_hw_exit(pfe);
++
++      return 0;
++}
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_sysfs.c
+@@ -0,0 +1,818 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include "pfe_mod.h"
++
++#define PE_EXCEPTION_DUMP_ADDRESS 0x1fa8
++#define NUM_QUEUES            16
++
++static char register_name[20][5] = {
++      "EPC", "ECAS", "EID", "ED",
++      "r0", "r1", "r2", "r3",
++      "r4", "r5", "r6", "r7",
++      "r8", "r9", "r10", "r11",
++      "r12", "r13", "r14", "r15",
++};
++
++static char exception_name[14][20] = {
++      "Reset",
++      "HardwareFailure",
++      "NMI",
++      "InstBreakpoint",
++      "DataBreakpoint",
++      "Unsupported",
++      "PrivilegeViolation",
++      "InstBusError",
++      "DataBusError",
++      "AlignmentError",
++      "ArithmeticError",
++      "SystemCall",
++      "MemoryManagement",
++      "Interrupt",
++};
++
++static unsigned long class_do_clear;
++static unsigned long tmu_do_clear;
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++static unsigned long util_do_clear;
++#endif
++
++static ssize_t display_pe_status(char *buf, int id, u32 dmem_addr, unsigned long
++                                      do_clear)
++{
++      ssize_t len = 0;
++      u32 val;
++      char statebuf[5];
++      struct pfe_cpumon *cpumon = &pfe->cpumon;
++      u32 debug_indicator;
++      u32 debug[20];
++
++      *(u32 *)statebuf = pe_dmem_read(id, dmem_addr, 4);
++      dmem_addr += 4;
++
++      statebuf[4] = '\0';
++      len += sprintf(buf + len, "state=%4s ", statebuf);
++
++      val = pe_dmem_read(id, dmem_addr, 4);
++      dmem_addr += 4;
++      len += sprintf(buf + len, "ctr=%08x ", cpu_to_be32(val));
++
++      val = pe_dmem_read(id, dmem_addr, 4);
++      if (do_clear && val)
++              pe_dmem_write(id, 0, dmem_addr, 4);
++      dmem_addr += 4;
++      len += sprintf(buf + len, "rx=%u ", cpu_to_be32(val));
++
++      val = pe_dmem_read(id, dmem_addr, 4);
++      if (do_clear && val)
++              pe_dmem_write(id, 0, dmem_addr, 4);
++      dmem_addr += 4;
++      if (id >= TMU0_ID && id <= TMU_MAX_ID)
++              len += sprintf(buf + len, "qstatus=%x", cpu_to_be32(val));
++      else
++              len += sprintf(buf + len, "tx=%u", cpu_to_be32(val));
++
++      val = pe_dmem_read(id, dmem_addr, 4);
++      if (do_clear && val)
++              pe_dmem_write(id, 0, dmem_addr, 4);
++      dmem_addr += 4;
++      if (val)
++              len += sprintf(buf + len, " drop=%u", cpu_to_be32(val));
++
++      len += sprintf(buf + len, " load=%d%%", cpumon->cpu_usage_pct[id]);
++
++      len += sprintf(buf + len, "\n");
++
++      debug_indicator = pe_dmem_read(id, dmem_addr, 4);
++      dmem_addr += 4;
++      if (!strncmp((char *)&debug_indicator, "DBUG", 4)) {
++              int j, last = 0;
++
++              for (j = 0; j < 16; j++) {
++                      debug[j] = pe_dmem_read(id, dmem_addr, 4);
++                      if (debug[j]) {
++                              if (do_clear)
++                                      pe_dmem_write(id, 0, dmem_addr, 4);
++                              last = j + 1;
++                      }
++                      dmem_addr += 4;
++              }
++              for (j = 0; j < last; j++) {
++                      len += sprintf(buf + len, "%08x%s",
++                      cpu_to_be32(debug[j]),
++                      (j & 0x7) == 0x7 || j == last - 1 ? "\n" : " ");
++              }
++      }
++
++      if (!strncmp(statebuf, "DEAD", 4)) {
++              u32 i, dump = PE_EXCEPTION_DUMP_ADDRESS;
++
++              len += sprintf(buf + len, "Exception details:\n");
++              for (i = 0; i < 20; i++) {
++                      debug[i] = pe_dmem_read(id, dump, 4);
++                      dump += 4;
++                      if (i == 2)
++                              len += sprintf(buf + len, "%4s = %08x (=%s) ",
++                              register_name[i], cpu_to_be32(debug[i]),
++                              exception_name[min((u32)
++                              cpu_to_be32(debug[i]), (u32)13)]);
++                      else
++                              len += sprintf(buf + len, "%4s = %08x%s",
++                              register_name[i], cpu_to_be32(debug[i]),
++                              (i & 0x3) == 0x3 || i == 19 ? "\n" : " ");
++              }
++      }
++
++      return len;
++}
++
++static ssize_t class_phy_stats(char *buf, int phy)
++{
++      ssize_t len = 0;
++      int off1 = phy * 0x28;
++      int off2 = phy * 0x10;
++
++      if (phy == 3)
++              off1 = CLASS_PHY4_RX_PKTS - CLASS_PHY1_RX_PKTS;
++
++      len += sprintf(buf + len, "phy: %d\n", phy);
++      len += sprintf(buf + len,
++                      "  rx:   %10u, tx:   %10u, intf:  %10u, ipv4:    %10u, ipv6: %10u\n",
++                      readl(CLASS_PHY1_RX_PKTS + off1),
++                      readl(CLASS_PHY1_TX_PKTS + off1),
++                      readl(CLASS_PHY1_INTF_MATCH_PKTS + off1),
++                      readl(CLASS_PHY1_V4_PKTS + off1),
++                      readl(CLASS_PHY1_V6_PKTS + off1));
++
++      len += sprintf(buf + len,
++                      "  icmp: %10u, igmp: %10u, tcp:   %10u, udp:     %10u\n",
++                      readl(CLASS_PHY1_ICMP_PKTS + off2),
++                      readl(CLASS_PHY1_IGMP_PKTS + off2),
++                      readl(CLASS_PHY1_TCP_PKTS + off2),
++                      readl(CLASS_PHY1_UDP_PKTS + off2));
++
++      len += sprintf(buf + len, "  err\n");
++      len += sprintf(buf + len,
++                      "  lp:   %10u, intf: %10u, l3:    %10u, chcksum: %10u, ttl:  %10u\n",
++                      readl(CLASS_PHY1_LP_FAIL_PKTS + off1),
++                      readl(CLASS_PHY1_INTF_FAIL_PKTS + off1),
++                      readl(CLASS_PHY1_L3_FAIL_PKTS + off1),
++                      readl(CLASS_PHY1_CHKSUM_ERR_PKTS + off1),
++                      readl(CLASS_PHY1_TTL_ERR_PKTS + off1));
++
++      return len;
++}
++
++/* qm_read_drop_stat
++ * This function is used to read the drop statistics from the TMU
++ * hw drop counter.  Since the hw counter is always cleared afer
++ * reading, this function maintains the previous drop count, and
++ * adds the new value to it.  That value can be retrieved by
++ * passing a pointer to it with the total_drops arg.
++ *
++ * @param tmu         TMU number (0 - 3)
++ * @param queue               queue number (0 - 15)
++ * @param total_drops pointer to location to store total drops (or NULL)
++ * @param do_reset    if TRUE, clear total drops after updating
++ */
++u32 qm_read_drop_stat(u32 tmu, u32 queue, u32 *total_drops, int do_reset)
++{
++      static u32 qtotal[TMU_MAX_ID + 1][NUM_QUEUES];
++      u32 val;
++
++      writel((tmu << 8) | queue, TMU_TEQ_CTRL);
++      writel((tmu << 8) | queue, TMU_LLM_CTRL);
++      val = readl(TMU_TEQ_DROP_STAT);
++      qtotal[tmu][queue] += val;
++      if (total_drops)
++              *total_drops = qtotal[tmu][queue];
++      if (do_reset)
++              qtotal[tmu][queue] = 0;
++      return val;
++}
++
++static ssize_t tmu_queue_stats(char *buf, int tmu, int queue)
++{
++      ssize_t len = 0;
++      u32 drops;
++
++      len += sprintf(buf + len, "%d-%02d, ", tmu, queue);
++
++      drops = qm_read_drop_stat(tmu, queue, NULL, 0);
++
++      /* Select queue */
++      writel((tmu << 8) | queue, TMU_TEQ_CTRL);
++      writel((tmu << 8) | queue, TMU_LLM_CTRL);
++
++      len += sprintf(buf + len,
++                      "(teq) drop: %10u, tx: %10u (llm) head: %08x, tail: %08x, drop: %10u\n",
++              drops, readl(TMU_TEQ_TRANS_STAT),
++              readl(TMU_LLM_QUE_HEADPTR), readl(TMU_LLM_QUE_TAILPTR),
++              readl(TMU_LLM_QUE_DROPCNT));
++
++      return len;
++}
++
++static ssize_t tmu_queues(char *buf, int tmu)
++{
++      ssize_t len = 0;
++      int queue;
++
++      for (queue = 0; queue < 16; queue++)
++              len += tmu_queue_stats(buf + len, tmu, queue);
++
++      return len;
++}
++
++static ssize_t block_version(char *buf, void *addr)
++{
++      ssize_t len = 0;
++      u32 val;
++
++      val = readl(addr);
++      len += sprintf(buf + len, "revision: %x, version: %x, id: %x\n",
++              (val >> 24) & 0xff, (val >> 16) & 0xff, val & 0xffff);
++
++      return len;
++}
++
++static ssize_t bmu(char *buf, int id, void *base)
++{
++      ssize_t len = 0;
++
++      len += sprintf(buf + len, "%s: %d\n  ", __func__, id);
++
++      len += block_version(buf + len, base + BMU_VERSION);
++
++      len += sprintf(buf + len, "  buf size:  %x\n", (1 << readl(base +
++                      BMU_BUF_SIZE)));
++      len += sprintf(buf + len, "  buf count: %x\n", readl(base +
++                      BMU_BUF_CNT));
++      len += sprintf(buf + len, "  buf rem:   %x\n", readl(base +
++                      BMU_REM_BUF_CNT));
++      len += sprintf(buf + len, "  buf curr:  %x\n", readl(base +
++                      BMU_CURR_BUF_CNT));
++      len += sprintf(buf + len, "  free err:  %x\n", readl(base +
++                      BMU_FREE_ERR_ADDR));
++
++      return len;
++}
++
++static ssize_t gpi(char *buf, int id, void *base)
++{
++      ssize_t len = 0;
++      u32 val;
++
++      len += sprintf(buf + len, "%s%d:\n  ", __func__, id);
++      len += block_version(buf + len, base + GPI_VERSION);
++
++      len += sprintf(buf + len, "  tx under stick: %x\n", readl(base +
++                      GPI_FIFO_STATUS));
++      val = readl(base + GPI_FIFO_DEBUG);
++      len += sprintf(buf + len, "  tx pkts:        %x\n", (val >> 23) &
++                      0x3f);
++      len += sprintf(buf + len, "  rx pkts:        %x\n", (val >> 18) &
++                      0x3f);
++      len += sprintf(buf + len, "  tx bytes:       %x\n", (val >> 9) &
++                      0x1ff);
++      len += sprintf(buf + len, "  rx bytes:       %x\n", (val >> 0) &
++                      0x1ff);
++      len += sprintf(buf + len, "  overrun:        %x\n", readl(base +
++                      GPI_OVERRUN_DROPCNT));
++
++      return len;
++}
++
++static ssize_t pfe_set_class(struct device *dev, struct device_attribute *attr,
++                           const char *buf, size_t count)
++{
++      class_do_clear = kstrtoul(buf, 0, 0);
++      return count;
++}
++
++static ssize_t pfe_show_class(struct device *dev, struct device_attribute *attr,
++                            char *buf)
++{
++      ssize_t len = 0;
++      int id;
++      u32 val;
++      struct pfe_cpumon *cpumon = &pfe->cpumon;
++
++      len += block_version(buf + len, CLASS_VERSION);
++
++      for (id = CLASS0_ID; id <= CLASS_MAX_ID; id++) {
++              len += sprintf(buf + len, "%d: ", id - CLASS0_ID);
++
++              val = readl(CLASS_PE0_DEBUG + id * 4);
++              len += sprintf(buf + len, "pc=1%04x ", val & 0xffff);
++
++              len += display_pe_status(buf + len, id, CLASS_DM_PESTATUS,
++                                              class_do_clear);
++      }
++      len += sprintf(buf + len, "aggregate load=%d%%\n\n",
++                      cpumon->class_usage_pct);
++
++      len += sprintf(buf + len, "pe status:   0x%x\n",
++                      readl(CLASS_PE_STATUS));
++      len += sprintf(buf + len, "max buf cnt: 0x%x   afull thres: 0x%x\n",
++                      readl(CLASS_MAX_BUF_CNT), readl(CLASS_AFULL_THRES));
++      len += sprintf(buf + len, "tsq max cnt: 0x%x   tsq fifo thres: 0x%x\n",
++                      readl(CLASS_TSQ_MAX_CNT), readl(CLASS_TSQ_FIFO_THRES));
++      len += sprintf(buf + len, "state:       0x%x\n", readl(CLASS_STATE));
++
++      len += class_phy_stats(buf + len, 0);
++      len += class_phy_stats(buf + len, 1);
++      len += class_phy_stats(buf + len, 2);
++      len += class_phy_stats(buf + len, 3);
++
++      return len;
++}
++
++static ssize_t pfe_set_tmu(struct device *dev, struct device_attribute *attr,
++                         const char *buf, size_t count)
++{
++      tmu_do_clear = kstrtoul(buf, 0, 0);
++      return count;
++}
++
++static ssize_t pfe_show_tmu(struct device *dev, struct device_attribute *attr,
++                          char *buf)
++{
++      ssize_t len = 0;
++      int id;
++      u32 val;
++
++      len += block_version(buf + len, TMU_VERSION);
++
++      for (id = TMU0_ID; id <= TMU_MAX_ID; id++) {
++              if (id == TMU2_ID)
++                      continue;
++              len += sprintf(buf + len, "%d: ", id - TMU0_ID);
++
++              len += display_pe_status(buf + len, id, TMU_DM_PESTATUS,
++                                              tmu_do_clear);
++      }
++
++      len += sprintf(buf + len, "pe status:    %x\n", readl(TMU_PE_STATUS));
++      len += sprintf(buf + len, "inq fifo cnt: %x\n",
++                      readl(TMU_PHY_INQ_FIFO_CNT));
++      val = readl(TMU_INQ_STAT);
++      len += sprintf(buf + len, "inq wr ptr:     %x\n", val & 0x3ff);
++      len += sprintf(buf + len, "inq rd ptr:     %x\n", val >> 10);
++
++      return len;
++}
++
++static unsigned long drops_do_clear;
++static u32 class_drop_counter[CLASS_NUM_DROP_COUNTERS];
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++static u32 util_drop_counter[UTIL_NUM_DROP_COUNTERS];
++#endif
++
++char *class_drop_description[CLASS_NUM_DROP_COUNTERS] = {
++      "ICC",
++      "Host Pkt Error",
++      "Rx Error",
++      "IPsec Outbound",
++      "IPsec Inbound",
++      "EXPT IPsec Error",
++      "Reassembly",
++      "Fragmenter",
++      "NAT-T",
++      "Socket",
++      "Multicast",
++      "NAT-PT",
++      "Tx Disabled",
++};
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++char *util_drop_description[UTIL_NUM_DROP_COUNTERS] = {
++      "IPsec Outbound",
++      "IPsec Inbound",
++      "IPsec Rate Limiter",
++      "Fragmenter",
++      "Socket",
++      "Tx Disabled",
++      "Rx Error",
++};
++#endif
++
++static ssize_t pfe_set_drops(struct device *dev, struct device_attribute *attr,
++                           const char *buf, size_t count)
++{
++      drops_do_clear = kstrtoul(buf, 0, 0);
++      return count;
++}
++
++static u32 tmu_drops[4][16];
++static ssize_t pfe_show_drops(struct device *dev, struct device_attribute *attr,
++                            char *buf)
++{
++      ssize_t len = 0;
++      int id, dropnum;
++      int tmu, queue;
++      u32 val;
++      u32 dmem_addr;
++      int num_class_drops = 0, num_tmu_drops = 0, num_util_drops = 0;
++      struct pfe_ctrl *ctrl = &pfe->ctrl;
++
++      memset(class_drop_counter, 0, sizeof(class_drop_counter));
++      for (id = CLASS0_ID; id <= CLASS_MAX_ID; id++) {
++              if (drops_do_clear)
++                      pe_sync_stop(ctrl, (1 << id));
++              for (dropnum = 0; dropnum < CLASS_NUM_DROP_COUNTERS;
++                      dropnum++) {
++                      dmem_addr = CLASS_DM_DROP_CNTR;
++                      val = be32_to_cpu(pe_dmem_read(id, dmem_addr, 4));
++                      class_drop_counter[dropnum] += val;
++                      num_class_drops += val;
++                      if (drops_do_clear)
++                              pe_dmem_write(id, 0, dmem_addr, 4);
++              }
++              if (drops_do_clear)
++                      pe_start(ctrl, (1 << id));
++      }
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      if (drops_do_clear)
++              pe_sync_stop(ctrl, (1 << UTIL_ID));
++      for (dropnum = 0; dropnum < UTIL_NUM_DROP_COUNTERS; dropnum++) {
++              dmem_addr = UTIL_DM_DROP_CNTR;
++              val = be32_to_cpu(pe_dmem_read(UTIL_ID, dmem_addr, 4));
++              util_drop_counter[dropnum] = val;
++              num_util_drops += val;
++              if (drops_do_clear)
++                      pe_dmem_write(UTIL_ID, 0, dmem_addr, 4);
++      }
++      if (drops_do_clear)
++              pe_start(ctrl, (1 << UTIL_ID));
++#endif
++      for (tmu = 0; tmu < 4; tmu++) {
++              for (queue = 0; queue < 16; queue++) {
++                      qm_read_drop_stat(tmu, queue, &tmu_drops[tmu][queue],
++                                        drops_do_clear);
++                      num_tmu_drops += tmu_drops[tmu][queue];
++              }
++      }
++
++      if (num_class_drops == 0 && num_util_drops == 0 && num_tmu_drops == 0)
++              len += sprintf(buf + len, "No PE drops\n\n");
++
++      if (num_class_drops > 0) {
++              len += sprintf(buf + len, "Class PE drops --\n");
++              for (dropnum = 0; dropnum < CLASS_NUM_DROP_COUNTERS;
++                      dropnum++) {
++                      if (class_drop_counter[dropnum] > 0)
++                              len += sprintf(buf + len, "  %s: %d\n",
++                                      class_drop_description[dropnum],
++                                      class_drop_counter[dropnum]);
++              }
++              len += sprintf(buf + len, "\n");
++      }
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      if (num_util_drops > 0) {
++              len += sprintf(buf + len, "Util PE drops --\n");
++              for (dropnum = 0; dropnum < UTIL_NUM_DROP_COUNTERS; dropnum++) {
++                      if (util_drop_counter[dropnum] > 0)
++                              len += sprintf(buf + len, "  %s: %d\n",
++                                      util_drop_description[dropnum],
++                                      util_drop_counter[dropnum]);
++              }
++              len += sprintf(buf + len, "\n");
++      }
++#endif
++      if (num_tmu_drops > 0) {
++              len += sprintf(buf + len, "TMU drops --\n");
++              for (tmu = 0; tmu < 4; tmu++) {
++                      for (queue = 0; queue < 16; queue++) {
++                              if (tmu_drops[tmu][queue] > 0)
++                                      len += sprintf(buf + len,
++                                              "  TMU%d-Q%d: %d\n"
++                                      , tmu, queue, tmu_drops[tmu][queue]);
++                      }
++              }
++              len += sprintf(buf + len, "\n");
++      }
++
++      return len;
++}
++
++static ssize_t pfe_show_tmu0_queues(struct device *dev, struct device_attribute
++                                      *attr, char *buf)
++{
++      return tmu_queues(buf, 0);
++}
++
++static ssize_t pfe_show_tmu1_queues(struct device *dev, struct device_attribute
++                                      *attr, char *buf)
++{
++      return tmu_queues(buf, 1);
++}
++
++static ssize_t pfe_show_tmu2_queues(struct device *dev, struct device_attribute
++                                      *attr, char *buf)
++{
++      return tmu_queues(buf, 2);
++}
++
++static ssize_t pfe_show_tmu3_queues(struct device *dev, struct device_attribute
++                                      *attr, char *buf)
++{
++      return tmu_queues(buf, 3);
++}
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++static ssize_t pfe_set_util(struct device *dev, struct device_attribute *attr,
++                          const char *buf, size_t count)
++{
++      util_do_clear = kstrtoul(buf, NULL, 0);
++      return count;
++}
++
++static ssize_t pfe_show_util(struct device *dev, struct device_attribute *attr,
++                           char *buf)
++{
++      ssize_t len = 0;
++      struct pfe_ctrl *ctrl = &pfe->ctrl;
++
++      len += block_version(buf + len, UTIL_VERSION);
++
++      pe_sync_stop(ctrl, (1 << UTIL_ID));
++      len += display_pe_status(buf + len, UTIL_ID, UTIL_DM_PESTATUS,
++                                      util_do_clear);
++      pe_start(ctrl, (1 << UTIL_ID));
++
++      len += sprintf(buf + len, "pe status:   %x\n", readl(UTIL_PE_STATUS));
++      len += sprintf(buf + len, "max buf cnt: %x\n",
++                      readl(UTIL_MAX_BUF_CNT));
++      len += sprintf(buf + len, "tsq max cnt: %x\n",
++                      readl(UTIL_TSQ_MAX_CNT));
++
++      return len;
++}
++#endif
++
++static ssize_t pfe_show_bmu(struct device *dev, struct device_attribute *attr,
++                          char *buf)
++{
++      ssize_t len = 0;
++
++      len += bmu(buf + len, 1, BMU1_BASE_ADDR);
++      len += bmu(buf + len, 2, BMU2_BASE_ADDR);
++
++      return len;
++}
++
++static ssize_t pfe_show_hif(struct device *dev, struct device_attribute *attr,
++                          char *buf)
++{
++      ssize_t len = 0;
++
++      len += sprintf(buf + len, "hif:\n  ");
++      len += block_version(buf + len, HIF_VERSION);
++
++      len += sprintf(buf + len, "  tx curr bd:    %x\n",
++                      readl(HIF_TX_CURR_BD_ADDR));
++      len += sprintf(buf + len, "  tx status:     %x\n",
++                      readl(HIF_TX_STATUS));
++      len += sprintf(buf + len, "  tx dma status: %x\n",
++                      readl(HIF_TX_DMA_STATUS));
++
++      len += sprintf(buf + len, "  rx curr bd:    %x\n",
++                      readl(HIF_RX_CURR_BD_ADDR));
++      len += sprintf(buf + len, "  rx status:     %x\n",
++                      readl(HIF_RX_STATUS));
++      len += sprintf(buf + len, "  rx dma status: %x\n",
++                      readl(HIF_RX_DMA_STATUS));
++
++      len += sprintf(buf + len, "hif nocopy:\n  ");
++      len += block_version(buf + len, HIF_NOCPY_VERSION);
++
++      len += sprintf(buf + len, "  tx curr bd:    %x\n",
++                      readl(HIF_NOCPY_TX_CURR_BD_ADDR));
++      len += sprintf(buf + len, "  tx status:     %x\n",
++                      readl(HIF_NOCPY_TX_STATUS));
++      len += sprintf(buf + len, "  tx dma status: %x\n",
++                      readl(HIF_NOCPY_TX_DMA_STATUS));
++
++      len += sprintf(buf + len, "  rx curr bd:    %x\n",
++                      readl(HIF_NOCPY_RX_CURR_BD_ADDR));
++      len += sprintf(buf + len, "  rx status:     %x\n",
++                      readl(HIF_NOCPY_RX_STATUS));
++      len += sprintf(buf + len, "  rx dma status: %x\n",
++                      readl(HIF_NOCPY_RX_DMA_STATUS));
++
++      return len;
++}
++
++static ssize_t pfe_show_gpi(struct device *dev, struct device_attribute *attr,
++                          char *buf)
++{
++      ssize_t len = 0;
++
++      len += gpi(buf + len, 0, EGPI1_BASE_ADDR);
++      len += gpi(buf + len, 1, EGPI2_BASE_ADDR);
++      len += gpi(buf + len, 3, HGPI_BASE_ADDR);
++
++      return len;
++}
++
++static ssize_t pfe_show_pfemem(struct device *dev, struct device_attribute
++                              *attr, char *buf)
++{
++      ssize_t len = 0;
++      struct pfe_memmon *memmon = &pfe->memmon;
++
++      len += sprintf(buf + len, "Kernel Memory: %d Bytes (%d KB)\n",
++              memmon->kernel_memory_allocated,
++              (memmon->kernel_memory_allocated + 1023) / 1024);
++
++      return len;
++}
++
++#ifdef HIF_NAPI_STATS
++static ssize_t pfe_show_hif_napi_stats(struct device *dev,
++                                     struct device_attribute *attr,
++                                     char *buf)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++      struct pfe *pfe = platform_get_drvdata(pdev);
++      ssize_t len = 0;
++
++      len += sprintf(buf + len, "sched:  %u\n",
++                      pfe->hif.napi_counters[NAPI_SCHED_COUNT]);
++      len += sprintf(buf + len, "poll:   %u\n",
++                      pfe->hif.napi_counters[NAPI_POLL_COUNT]);
++      len += sprintf(buf + len, "packet: %u\n",
++                      pfe->hif.napi_counters[NAPI_PACKET_COUNT]);
++      len += sprintf(buf + len, "budget: %u\n",
++                      pfe->hif.napi_counters[NAPI_FULL_BUDGET_COUNT]);
++      len += sprintf(buf + len, "desc:   %u\n",
++                      pfe->hif.napi_counters[NAPI_DESC_COUNT]);
++      len += sprintf(buf + len, "full:   %u\n",
++                      pfe->hif.napi_counters[NAPI_CLIENT_FULL_COUNT]);
++
++      return len;
++}
++
++static ssize_t pfe_set_hif_napi_stats(struct device *dev,
++                                    struct device_attribute *attr,
++                                      const char *buf, size_t count)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++      struct pfe *pfe = platform_get_drvdata(pdev);
++
++      memset(pfe->hif.napi_counters, 0, sizeof(pfe->hif.napi_counters));
++
++      return count;
++}
++
++static DEVICE_ATTR(hif_napi_stats, 0644, pfe_show_hif_napi_stats,
++                      pfe_set_hif_napi_stats);
++#endif
++
++static DEVICE_ATTR(class, 0644, pfe_show_class, pfe_set_class);
++static DEVICE_ATTR(tmu, 0644, pfe_show_tmu, pfe_set_tmu);
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++static DEVICE_ATTR(util, 0644, pfe_show_util, pfe_set_util);
++#endif
++static DEVICE_ATTR(bmu, 0444, pfe_show_bmu, NULL);
++static DEVICE_ATTR(hif, 0444, pfe_show_hif, NULL);
++static DEVICE_ATTR(gpi, 0444, pfe_show_gpi, NULL);
++static DEVICE_ATTR(drops, 0644, pfe_show_drops, pfe_set_drops);
++static DEVICE_ATTR(tmu0_queues, 0444, pfe_show_tmu0_queues, NULL);
++static DEVICE_ATTR(tmu1_queues, 0444, pfe_show_tmu1_queues, NULL);
++static DEVICE_ATTR(tmu2_queues, 0444, pfe_show_tmu2_queues, NULL);
++static DEVICE_ATTR(tmu3_queues, 0444, pfe_show_tmu3_queues, NULL);
++static DEVICE_ATTR(pfemem, 0444, pfe_show_pfemem, NULL);
++
++int pfe_sysfs_init(struct pfe *pfe)
++{
++      if (device_create_file(pfe->dev, &dev_attr_class))
++              goto err_class;
++
++      if (device_create_file(pfe->dev, &dev_attr_tmu))
++              goto err_tmu;
++
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      if (device_create_file(pfe->dev, &dev_attr_util))
++              goto err_util;
++#endif
++
++      if (device_create_file(pfe->dev, &dev_attr_bmu))
++              goto err_bmu;
++
++      if (device_create_file(pfe->dev, &dev_attr_hif))
++              goto err_hif;
++
++      if (device_create_file(pfe->dev, &dev_attr_gpi))
++              goto err_gpi;
++
++      if (device_create_file(pfe->dev, &dev_attr_drops))
++              goto err_drops;
++
++      if (device_create_file(pfe->dev, &dev_attr_tmu0_queues))
++              goto err_tmu0_queues;
++
++      if (device_create_file(pfe->dev, &dev_attr_tmu1_queues))
++              goto err_tmu1_queues;
++
++      if (device_create_file(pfe->dev, &dev_attr_tmu2_queues))
++              goto err_tmu2_queues;
++
++      if (device_create_file(pfe->dev, &dev_attr_tmu3_queues))
++              goto err_tmu3_queues;
++
++      if (device_create_file(pfe->dev, &dev_attr_pfemem))
++              goto err_pfemem;
++
++#ifdef HIF_NAPI_STATS
++      if (device_create_file(pfe->dev, &dev_attr_hif_napi_stats))
++              goto err_hif_napi_stats;
++#endif
++
++      return 0;
++
++#ifdef HIF_NAPI_STATS
++err_hif_napi_stats:
++      device_remove_file(pfe->dev, &dev_attr_pfemem);
++#endif
++
++err_pfemem:
++      device_remove_file(pfe->dev, &dev_attr_tmu3_queues);
++
++err_tmu3_queues:
++      device_remove_file(pfe->dev, &dev_attr_tmu2_queues);
++
++err_tmu2_queues:
++      device_remove_file(pfe->dev, &dev_attr_tmu1_queues);
++
++err_tmu1_queues:
++      device_remove_file(pfe->dev, &dev_attr_tmu0_queues);
++
++err_tmu0_queues:
++      device_remove_file(pfe->dev, &dev_attr_drops);
++
++err_drops:
++      device_remove_file(pfe->dev, &dev_attr_gpi);
++
++err_gpi:
++      device_remove_file(pfe->dev, &dev_attr_hif);
++
++err_hif:
++      device_remove_file(pfe->dev, &dev_attr_bmu);
++
++err_bmu:
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      device_remove_file(pfe->dev, &dev_attr_util);
++
++err_util:
++#endif
++      device_remove_file(pfe->dev, &dev_attr_tmu);
++
++err_tmu:
++      device_remove_file(pfe->dev, &dev_attr_class);
++
++err_class:
++      return -1;
++}
++
++void pfe_sysfs_exit(struct pfe *pfe)
++{
++#ifdef HIF_NAPI_STATS
++      device_remove_file(pfe->dev, &dev_attr_hif_napi_stats);
++#endif
++      device_remove_file(pfe->dev, &dev_attr_pfemem);
++      device_remove_file(pfe->dev, &dev_attr_tmu3_queues);
++      device_remove_file(pfe->dev, &dev_attr_tmu2_queues);
++      device_remove_file(pfe->dev, &dev_attr_tmu1_queues);
++      device_remove_file(pfe->dev, &dev_attr_tmu0_queues);
++      device_remove_file(pfe->dev, &dev_attr_drops);
++      device_remove_file(pfe->dev, &dev_attr_gpi);
++      device_remove_file(pfe->dev, &dev_attr_hif);
++      device_remove_file(pfe->dev, &dev_attr_bmu);
++#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
++      device_remove_file(pfe->dev, &dev_attr_util);
++#endif
++      device_remove_file(pfe->dev, &dev_attr_tmu);
++      device_remove_file(pfe->dev, &dev_attr_class);
++}
diff --git a/target/linux/layerscape/patches-5.4/701-net-0287-staging-fsl_ppfe-eth-fix-RGMII-tx-delay-issue.patch b/target/linux/layerscape/patches-5.4/701-net-0287-staging-fsl_ppfe-eth-fix-RGMII-tx-delay-issue.patch
new file mode 100644 (file)
index 0000000..47dc87d
--- /dev/null
@@ -0,0 +1,30 @@
+From b62abd01cce8c4548d380d4ff28984a0275ea8fb Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Wed, 11 Oct 2017 19:23:38 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: fix RGMII tx delay issue
+
+Recently logic to enable RGMII tx delay was changed by
+below patch.
+
+https://patchwork.kernel.org/patch/9447581/
+
+Based on the patch, appropriate change is made in PFE driver.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+Signed-off-by: Anjaneyulu Jagarlmudi <anji.jagarlmudi@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -1068,7 +1068,8 @@ static void pfe_eth_adjust_link(struct n
+                       new_state = 1;
+                       gemac_set_speed(priv->EMAC_baseaddr,
+                                       pfe_get_phydev_speed(phydev));
+-                      if (priv->einfo->mii_config == PHY_INTERFACE_MODE_RGMII)
++                      if (priv->einfo->mii_config ==
++                                      PHY_INTERFACE_MODE_RGMII_TXID)
+                               pfe_set_rgmii_speed(phydev);
+                       priv->oldspeed = phydev->speed;
+               }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0288-staging-fsl_ppfe-eth-remove-unused-functions.patch b/target/linux/layerscape/patches-5.4/701-net-0288-staging-fsl_ppfe-eth-remove-unused-functions.patch
new file mode 100644 (file)
index 0000000..2e9f490
--- /dev/null
@@ -0,0 +1,96 @@
+From accfaecbbcb882dcc2d47660a644c353ae337861 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Wed, 18 Oct 2017 14:29:30 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: remove unused functions
+
+Remove unused functions hif_xmit_pkt & hif_lib_xmit_pkt.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_hif.c     | 24 +-----------------------
+ drivers/staging/fsl_ppfe/pfe_hif_lib.c | 34 ----------------------------------
+ 2 files changed, 1 insertion(+), 57 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_hif.c
++++ b/drivers/staging/fsl_ppfe/pfe_hif.c
+@@ -844,29 +844,6 @@ skip_tx:
+       return;
+ }
+-int hif_xmit_pkt(struct pfe_hif *hif, unsigned int client_id, unsigned int q_no,
+-               void *data, unsigned int len)
+-{
+-      int rc = 0;
+-
+-      spin_lock_bh(&hif->tx_lock);
+-
+-      if (!hif->txavail) {
+-              rc = 1;
+-      } else {
+-              __hif_xmit_pkt(hif, client_id, q_no, data, len,
+-                             HIF_FIRST_BUFFER | HIF_LAST_BUFFER);
+-              hif_tx_dma_start();
+-      }
+-
+-      if (hif->txavail < (hif->tx_ring_size >> 1))
+-              __hif_tx_done_process(hif, TX_FREE_MAX_COUNT);
+-
+-      spin_unlock_bh(&hif->tx_lock);
+-
+-      return rc;
+-}
+-
+ static irqreturn_t wol_isr(int irq, void *dev_id)
+ {
+       pr_info("WoL\n");
+@@ -907,6 +884,7 @@ static irqreturn_t hif_isr(int irq, void
+                       __napi_schedule(&hif->napi);
+               }
+       }
++
+       if (int_status & HIF_TXPKT_INT) {
+               int_status &= ~(HIF_TXPKT_INT);
+               int_enable_mask &= ~(HIF_TXPKT_INT);
+--- a/drivers/staging/fsl_ppfe/pfe_hif_lib.c
++++ b/drivers/staging/fsl_ppfe/pfe_hif_lib.c
+@@ -512,40 +512,6 @@ void __hif_lib_xmit_pkt(struct hif_clien
+       queue->jiffies_last_packet = jiffies;
+ }
+-/*This function puts the given packet in the specific client queue */
+-int hif_lib_xmit_pkt(struct hif_client_s *client, unsigned int qno, void *data,
+-                   unsigned int len, u32 client_ctrl, void *client_data)
+-{
+-      struct hif_client_tx_queue *queue = &client->tx_q[qno];
+-      struct tx_queue_desc *desc = queue->base + queue->write_idx;
+-
+-      if (queue->tx_pending < queue->size) {
+-              /*Construct pkt header */
+-
+-              data -= sizeof(struct hif_hdr);
+-              len += sizeof(struct hif_hdr);
+-
+-              hif_hdr_write(data, client->id, qno, client_ctrl);
+-
+-              desc->data = client_data;
+-              desc->ctrl = CL_DESC_OWN | CL_DESC_FLAGS(HIF_FIRST_BUFFER |
+-                              HIF_LAST_BUFFER | HIF_DATA_VALID);
+-
+-              if (hif_xmit_pkt(&pfe->hif, client->id, qno, data, len))
+-                      return 1;
+-
+-              inc_cl_idx(queue->write_idx);
+-              queue->tx_pending++;
+-              queue->jiffies_last_packet = jiffies;
+-
+-              return 0;
+-      }
+-
+-      pr_debug("%s Tx client %d qno %d is full\n", __func__, client->id,
+-               qno);
+-      return 1;
+-}
+-
+ void *hif_lib_tx_get_next_complete(struct hif_client_s *client, int qno,
+                                  unsigned int *flags, int count)
+ {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0289-staging-fsl_ppfe-eth-fix-read-write-ack-idx-issue.patch b/target/linux/layerscape/patches-5.4/701-net-0289-staging-fsl_ppfe-eth-fix-read-write-ack-idx-issue.patch
new file mode 100644 (file)
index 0000000..4ed5b04
--- /dev/null
@@ -0,0 +1,77 @@
+From f44630f1e12462921245feb91fe94d225ba90f9c Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Wed, 18 Oct 2017 18:34:41 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: fix read/write/ack idx issue
+
+While fixing checkpatch errors some of the index increments
+were commented out. They are enabled.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_hif.c     | 8 ++++----
+ drivers/staging/fsl_ppfe/pfe_hif_lib.c | 9 +++------
+ 2 files changed, 7 insertions(+), 10 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_hif.c
++++ b/drivers/staging/fsl_ppfe/pfe_hif.c
+@@ -511,9 +511,9 @@ static void *client_put_rxpacket(struct
+                        */
+                       smp_wmb();
+                       writel(CL_DESC_BUF_LEN(len) | flags, &desc->ctrl);
+-                      /* queue->write_idx = (queue->write_idx + 1)
+-                       *                     & (queue->size - 1);
+-                       */
++                      queue->write_idx = (queue->write_idx + 1)
++                                          & (queue->size - 1);
++
+                       free_pkt += pfe_pkt_headroom;
+               }
+       }
+@@ -703,7 +703,7 @@ static int client_ack_txpacket(struct pf
+       if (readl(&desc->ctrl) & CL_DESC_OWN) {
+               writel((readl(&desc->ctrl) & ~CL_DESC_OWN), &desc->ctrl);
+-              /* queue->ack_idx = (queue->ack_idx + 1) & (queue->size - 1); */
++              queue->ack_idx = (queue->ack_idx + 1) & (queue->size - 1);
+               return 0;
+--- a/drivers/staging/fsl_ppfe/pfe_hif_lib.c
++++ b/drivers/staging/fsl_ppfe/pfe_hif_lib.c
+@@ -211,9 +211,6 @@ err:
+       return 1;
+ }
+-#define inc_cl_idx(idxname)                                   \
+-      ({ typeof(idxname) idxname_ = (idxname);                \
+-      ((idxname_) = (idxname_ + 1) & (queue->size - 1)); })
+ static void hif_lib_client_cleanup_tx_queue(struct hif_client_tx_queue *queue)
+ {
+@@ -465,7 +462,7 @@ void *hif_lib_receive_pkt(struct hif_cli
+               smp_wmb();
+               desc->ctrl = CL_DESC_BUF_LEN(pfe_pkt_size) | CL_DESC_OWN;
+-              inc_cl_idx(queue->read_idx);
++              queue->read_idx = (queue->read_idx + 1) & (queue->size - 1);
+       }
+       /*spin_unlock_irqrestore(&client->rx_lock, flags); */
+@@ -507,7 +504,7 @@ void __hif_lib_xmit_pkt(struct hif_clien
+       __hif_xmit_pkt(&pfe->hif, client->id, qno, data, len, flags);
+-      inc_cl_idx(queue->write_idx);
++      queue->write_idx = (queue->write_idx + 1) & (queue->size - 1);
+       queue->tx_pending++;
+       queue->jiffies_last_packet = jiffies;
+ }
+@@ -544,7 +541,7 @@ void *hif_lib_tx_get_next_complete(struc
+       if (desc->ctrl & CL_DESC_OWN)
+               return NULL;
+-      inc_cl_idx(queue->read_idx);
++      queue->read_idx = (queue->read_idx + 1) & (queue->size - 1);
+       queue->tx_pending--;
+       *flags = CL_DESC_GET_FLAGS(desc->ctrl);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0290-staging-fsl_ppfe-eth-Make-phy_ethtool_ksettings_get-.patch b/target/linux/layerscape/patches-5.4/701-net-0290-staging-fsl_ppfe-eth-Make-phy_ethtool_ksettings_get-.patch
new file mode 100644 (file)
index 0000000..59b15ff
--- /dev/null
@@ -0,0 +1,26 @@
+From 48d54be45c3b8735f90792e6480e7d6cf0ec1586 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Fri, 27 Oct 2017 11:20:47 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: Make phy_ethtool_ksettings_get return
+ void
+
+Make return value void since function never return meaningful value
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -577,7 +577,9 @@ static int pfe_eth_get_settings(struct n
+       if (!phydev)
+               return -ENODEV;
+-      return phy_ethtool_ksettings_get(phydev, cmd);
++      phy_ethtool_ksettings_get(phydev, cmd);
++
++      return 0;
+ }
+ /*
diff --git a/target/linux/layerscape/patches-5.4/701-net-0291-staging-fsl_ppfe-eth-add-function-to-update-tmu-cred.patch b/target/linux/layerscape/patches-5.4/701-net-0291-staging-fsl_ppfe-eth-add-function-to-update-tmu-cred.patch
new file mode 100644 (file)
index 0000000..72152bf
--- /dev/null
@@ -0,0 +1,68 @@
+From cc230f5618174506889f98ac6b79e72ac9d9d9e4 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Wed, 15 Nov 2017 13:45:27 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: add function to update tmu credits
+
+__hif_lib_update_credit function is used to update the tmu credits.
+If tx_qos is set, tmu credit is updated based on the number of packets
+transmitted by tmu.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+Signed-off-by: Anjaneyulu Jagarlmudi <anji.jagarlmudi@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_hif_lib.c | 33 +++++++++++++++++++++++++++++++++
+ drivers/staging/fsl_ppfe/pfe_hif_lib.h |  1 +
+ 2 files changed, 34 insertions(+)
+
+--- a/drivers/staging/fsl_ppfe/pfe_hif_lib.c
++++ b/drivers/staging/fsl_ppfe/pfe_hif_lib.c
+@@ -565,6 +565,39 @@ static void hif_lib_tmu_credit_init(stru
+               }
+ }
++/* __hif_lib_update_credit
++ *
++ * @param[in] client  hif client context
++ * @param[in] queue   queue number in match with TMU
++ */
++void __hif_lib_update_credit(struct hif_client_s *client, unsigned int queue)
++{
++      unsigned int tmu_tx_packets, tmp;
++
++      if (tx_qos) {
++              tmu_tx_packets = be32_to_cpu(pe_dmem_read(TMU0_ID +
++                      client->id, TMU_DM_TX_TRANS, 4));
++
++              /* tx_packets counter overflowed */
++              if (tmu_tx_packets >
++                  pfe->tmu_credit.tx_packets[client->id][queue]) {
++                      tmp = UINT_MAX - tmu_tx_packets +
++                      pfe->tmu_credit.tx_packets[client->id][queue];
++
++                      pfe->tmu_credit.tx_credit[client->id][queue] =
++                      pfe->tmu_credit.tx_credit_max[client->id][queue] - tmp;
++              } else {
++              /* TMU tx <= pfe_eth tx, normal case or both OF since
++               * last time
++               */
++                      pfe->tmu_credit.tx_credit[client->id][queue] =
++                      pfe->tmu_credit.tx_credit_max[client->id][queue] -
++                      (pfe->tmu_credit.tx_packets[client->id][queue] -
++                      tmu_tx_packets);
++              }
++      }
++}
++
+ int pfe_hif_lib_init(struct pfe *pfe)
+ {
+       int rc;
+--- a/drivers/staging/fsl_ppfe/pfe_hif_lib.h
++++ b/drivers/staging/fsl_ppfe/pfe_hif_lib.h
+@@ -185,6 +185,7 @@ void *hif_lib_tx_get_next_complete(struc
+ void *hif_lib_receive_pkt(struct hif_client_s *client, int qno, int *len, int
+                               *ofst, unsigned int *rx_ctrl,
+                               unsigned int *desc_ctrl, void **priv_data);
++void __hif_lib_update_credit(struct hif_client_s *client, unsigned int queue);
+ void hif_lib_set_rx_cpu_affinity(struct hif_client_s *client, int cpu_id);
+ void hif_lib_set_tx_queue_nocpy(struct hif_client_s *client, int qno, int
+                                       enable);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0292-staging-fsl_ppfe-eth-Avoid-packet-drop-at-TMU-queues.patch b/target/linux/layerscape/patches-5.4/701-net-0292-staging-fsl_ppfe-eth-Avoid-packet-drop-at-TMU-queues.patch
new file mode 100644 (file)
index 0000000..eeea374
--- /dev/null
@@ -0,0 +1,87 @@
+From 8b99b4595d2b5f4d0b2252b16de83572e03b337a Mon Sep 17 00:00:00 2001
+From: Kavi Akhila-B46177 <akhila.kavi@nxp.com>
+Date: Thu, 2 Nov 2017 12:05:35 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: Avoid packet drop at TMU queues
+
+Added flow control between TMU queues and PFE Linux driver,
+based on TMU credits availability.
+Added tx_qos module parameter to control this behavior.
+Use queue-0 as default queue to transmit packets.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+Signed-off-by: Akhila Kavi <akhila.kavi@nxp.com>
+Signed-off-by: Anjaneyulu Jagarlmudi <anji.jagarlmudi@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c     | 17 +++++++++++++----
+ drivers/staging/fsl_ppfe/pfe_hif_lib.c |  7 +++++--
+ 2 files changed, 18 insertions(+), 6 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -293,10 +293,10 @@ static int pfe_eth_sysfs_init(struct net
+       /* Initialize the default values */
+       /*
+-       * By default, packets without conntrack will use this default high
++       * By default, packets without conntrack will use this default low
+        * priority queue
+        */
+-      priv->default_priority = 15;
++      priv->default_priority = 0;
+       /* Create our sysfs files */
+       err = device_create_file(&ndev->dev, &dev_attr_default_priority);
+@@ -1566,10 +1566,17 @@ static int pfe_eth_might_stop_tx(struct
+                                unsigned int n_segs)
+ {
+       ktime_t kt;
++      int tried = 0;
++try_again:
+       if (unlikely((__hif_tx_avail(&pfe->hif) < n_desc) ||
+-                   (hif_lib_tx_avail(&priv->client, queuenum) < n_desc) ||
++      (hif_lib_tx_avail(&priv->client, queuenum) < n_desc) ||
+       (hif_lib_tx_credit_avail(pfe, priv->id, queuenum) < n_segs))) {
++              if (!tried) {
++                      __hif_lib_update_credit(&priv->client, queuenum);
++                      tried = 1;
++                      goto try_again;
++              }
+ #ifdef PFE_ETH_TX_STATS
+               if (__hif_tx_avail(&pfe->hif) < n_desc) {
+                       priv->stop_queue_hif[queuenum]++;
+@@ -1692,8 +1699,10 @@ static void pfe_eth_flush_tx(struct pfe_
+       netif_info(priv, tx_done, priv->ndev, "%s\n", __func__);
+-      for (ii = 0; ii < emac_txq_cnt; ii++)
++      for (ii = 0; ii < emac_txq_cnt; ii++) {
+               pfe_eth_flush_txQ(priv, ii, 0, 0);
++              __hif_lib_update_credit(&priv->client, ii);
++      }
+ }
+ void pfe_tx_get_req_desc(struct sk_buff *skb, unsigned int *n_desc, unsigned int
+--- a/drivers/staging/fsl_ppfe/pfe_hif_lib.c
++++ b/drivers/staging/fsl_ppfe/pfe_hif_lib.c
+@@ -34,7 +34,10 @@
+ unsigned int lro_mode;
+ unsigned int page_mode;
+-unsigned int tx_qos;
++unsigned int tx_qos = 1;
++module_param(tx_qos, uint, 0444);
++MODULE_PARM_DESC(tx_qos, "0: disable ,\n"
++                       "1: enable (default), guarantee no packet drop at TMU level\n");
+ unsigned int pfe_pkt_size;
+ unsigned int pfe_pkt_headroom;
+ unsigned int emac_txq_cnt;
+@@ -576,7 +579,7 @@ void __hif_lib_update_credit(struct hif_
+       if (tx_qos) {
+               tmu_tx_packets = be32_to_cpu(pe_dmem_read(TMU0_ID +
+-                      client->id, TMU_DM_TX_TRANS, 4));
++                      client->id, (TMU_DM_TX_TRANS + (queue * 4)), 4));
+               /* tx_packets counter overflowed */
+               if (tmu_tx_packets >
diff --git a/target/linux/layerscape/patches-5.4/701-net-0293-staging-fsl_ppfe-eth-Enable-PFE-in-clause-45-mode.patch b/target/linux/layerscape/patches-5.4/701-net-0293-staging-fsl_ppfe-eth-Enable-PFE-in-clause-45-mode.patch
new file mode 100644 (file)
index 0000000..dac3a93
--- /dev/null
@@ -0,0 +1,77 @@
+From 666f91f706c167b061ec29f45936a9f24e86e55c Mon Sep 17 00:00:00 2001
+From: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+Date: Wed, 29 Nov 2017 12:08:00 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: Enable PFE in clause 45 mode
+
+when we opearate in clause 45 mode, we need to call
+the function get_phy_device() with its 3rd argument as
+"true" and then the resultant phy device needs to be
+register with phy layer via phy_device_register()
+
+Signed-off-by: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c | 32 +++++++++++++++++++++++++++++---
+ 1 file changed, 29 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -923,7 +923,8 @@ static int pfe_eth_mdio_init(struct pfe_
+                            struct ls1012a_mdio_platform_data *minfo)
+ {
+       struct mii_bus *bus;
+-      int rc;
++      int rc, ii;
++      struct phy_device *phydev;
+       netif_info(priv, drv, priv->ndev, "%s\n", __func__);
+       pr_info("%s\n", __func__);
+@@ -962,6 +963,31 @@ static int pfe_eth_mdio_init(struct pfe_
+       }
+       priv->mii_bus = bus;
++
++      /* For clause 45 we need to call get_phy_device() with it's
++       * 3rd argument as true and then register the phy device
++       * via phy_device_register()
++       */
++
++      if (priv->einfo->mii_config == PHY_INTERFACE_MODE_2500SGMII) {
++              for (ii = 0; ii < NUM_GEMAC_SUPPORT; ii++) {
++                      phydev = get_phy_device(priv->mii_bus,
++                                      priv->einfo->phy_id + ii, true);
++                      if (!phydev || IS_ERR(phydev)) {
++                              rc = -EIO;
++                              netdev_err(priv->ndev, "fail to get device\n");
++                              goto err1;
++                      }
++                      rc = phy_device_register(phydev);
++                      if (rc) {
++                              phy_device_free(phydev);
++                              netdev_err(priv->ndev,
++                                      "phy_device_register() failed\n");
++                              goto err1;
++                      }
++              }
++      }
++
+       pfe_eth_mdio_reset(bus);
+       return 0;
+@@ -1149,7 +1175,7 @@ static void ls1012a_configure_serdes(str
+       int sgmii_2500 = 0;
+       struct mii_bus *bus = priv->mii_bus;
+-      if (priv->einfo->mii_config == PHY_INTERFACE_MODE_SGMII_2500)
++      if (priv->einfo->mii_config == PHY_INTERFACE_MODE_2500SGMII)
+               sgmii_2500 = 1;
+       netif_info(priv, drv, ndev, "%s\n", __func__);
+@@ -1198,7 +1224,7 @@ static int pfe_phy_init(struct net_devic
+       netif_info(priv, drv, ndev, "%s: %s\n", __func__, phy_id);
+       interface = priv->einfo->mii_config;
+       if ((interface == PHY_INTERFACE_MODE_SGMII) ||
+-          (interface == PHY_INTERFACE_MODE_SGMII_2500)) {
++          (interface == PHY_INTERFACE_MODE_2500SGMII)) {
+               /*Configure SGMII PCS */
+               if (pfe->scfg) {
+                       /*Config MDIO from serdes */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0294-staging-fsl_ppfe-eth-Disable-autonegotiation-for-2.5.patch b/target/linux/layerscape/patches-5.4/701-net-0294-staging-fsl_ppfe-eth-Disable-autonegotiation-for-2.5.patch
new file mode 100644 (file)
index 0000000..3c0abc8
--- /dev/null
@@ -0,0 +1,42 @@
+From caae8a691922c3702fcb813f5d794f311c0609c6 Mon Sep 17 00:00:00 2001
+From: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+Date: Wed, 29 Nov 2017 12:21:43 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: Disable autonegotiation for 2.5G SGMII
+
+PCS initialization sequence for 2.5G SGMII interface governs
+auto negotiation to be in disabled mode
+
+Signed-off-by: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -1174,6 +1174,7 @@ static void ls1012a_configure_serdes(str
+       struct pfe_eth_priv_s *priv = pfe->eth.eth_priv[0];
+       int sgmii_2500 = 0;
+       struct mii_bus *bus = priv->mii_bus;
++      u16 value = 0;
+       if (priv->einfo->mii_config == PHY_INTERFACE_MODE_2500SGMII)
+               sgmii_2500 = 1;
+@@ -1191,14 +1192,16 @@ static void ls1012a_configure_serdes(str
+               pfe_eth_mdio_write(bus, 0, 0x4, 0x4001);
+               pfe_eth_mdio_write(bus, 0, 0x12, 0xa120);
+               pfe_eth_mdio_write(bus, 0, 0x13, 0x7);
++              /* Autonegotiation need to be disabled for 2.5G SGMII mode*/
++              value = 0x0140;
++              pfe_eth_mdio_write(bus, 0, 0x0, value);
+       } else {
+               pfe_eth_mdio_write(bus, 0, 0x14, 0xb);
+               pfe_eth_mdio_write(bus, 0, 0x4, 0x1a1);
+               pfe_eth_mdio_write(bus, 0, 0x12, 0x400);
+               pfe_eth_mdio_write(bus, 0, 0x13, 0x0);
++              pfe_eth_mdio_write(bus, 0, 0x0, 0x1140);
+       }
+-
+-      pfe_eth_mdio_write(bus, 0, 0x0, 0x1140);
+ }
+ /*
diff --git a/target/linux/layerscape/patches-5.4/701-net-0295-staging-fsl_ppfe-eth-calculate-PFE_PKT_SIZE-with-SKB.patch b/target/linux/layerscape/patches-5.4/701-net-0295-staging-fsl_ppfe-eth-calculate-PFE_PKT_SIZE-with-SKB.patch
new file mode 100644 (file)
index 0000000..f42ec78
--- /dev/null
@@ -0,0 +1,30 @@
+From 2f59069dbb48ee86bee42bf36a4dfafe64028344 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Thu, 8 Mar 2018 13:58:38 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: calculate PFE_PKT_SIZE with
+ SKB_DATA_ALIGN
+
+pfe packet size was calculated without considering skb data alignment
+and this resulted in jumbo frames crashing kernel when the
+cacheline size increased from 64 to 128 bytes with
+commit 97303480753e ("arm64: Increase the max granular size").
+
+Modify pfe packet size caclulation to include skb data alignment of
+sizeof(struct skb_shared_info).
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_hif_lib.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_hif_lib.h
++++ b/drivers/staging/fsl_ppfe/pfe_hif_lib.h
+@@ -146,7 +146,7 @@ struct tx_queue_desc {
+ #define PFE_BUF_SIZE          2048
+ #define PFE_PKT_HEADROOM      128
+-#define SKB_SHARED_INFO_SIZE   (sizeof(struct skb_shared_info))
++#define SKB_SHARED_INFO_SIZE   SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
+ #define PFE_PKT_SIZE          (PFE_BUF_SIZE - PFE_PKT_HEADROOM \
+                                - SKB_SHARED_INFO_SIZE)
+ #define MAX_L2_HDR_SIZE               14      /* Not correct for VLAN/PPPoE */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0296-staging-fsl_ppfe-eth-support-for-userspace-networkin.patch b/target/linux/layerscape/patches-5.4/701-net-0296-staging-fsl_ppfe-eth-support-for-userspace-networkin.patch
new file mode 100644 (file)
index 0000000..b3f3fe9
--- /dev/null
@@ -0,0 +1,155 @@
+From 25d189ea016270d1d7ab67eafc57bc8989b5381c Mon Sep 17 00:00:00 2001
+From: Akhil Goyal <akhil.goyal@nxp.com>
+Date: Fri, 13 Apr 2018 15:41:28 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: support for userspace networking
+
+This patch adds the userspace mode support to fsl_ppfe network driver.
+In the new mode, basic hardware initialization is performed in kernel, while
+the datapath and HIF handling is the responsibility of the userspace.
+
+The new command line parameter is added to initialize the ppfe module
+in userspace mode. By default the module remains in kernelspace networking
+mode.
+To enable userspace mode, use "insmod pfe.ko us=1"
+
+Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
+Signed-off-by: Gagandeep Singh <g.singh@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c | 21 +++++++++++++++++++--
+ drivers/staging/fsl_ppfe/pfe_mod.c | 15 +++++++++++++++
+ drivers/staging/fsl_ppfe/pfe_mod.h |  2 ++
+ 3 files changed, 36 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -2296,6 +2296,8 @@ static int pfe_eth_init_one(struct pfe *
+               goto err0;
+       }
++      if (us)
++              emac_txq_cnt = EMAC_TXQ_CNT;
+       /* Create an ethernet device instance */
+       ndev = alloc_etherdev_mq(sizeof(*priv), emac_txq_cnt);
+@@ -2342,6 +2344,9 @@ static int pfe_eth_init_one(struct pfe *
+               }
+       }
++      if (us)
++              goto phy_init;
++
+       ndev->mtu = 1500;
+       /* Set MTU limits */
+@@ -2381,6 +2386,8 @@ static int pfe_eth_init_one(struct pfe *
+               netdev_err(ndev, "register_netdev() failed\n");
+               goto err3;
+       }
++
++phy_init:
+       device_init_wakeup(&ndev->dev, WAKE_MAGIC);
+       if (!(priv->einfo->phy_flags & GEMAC_NO_PHY)) {
+@@ -2392,6 +2399,12 @@ static int pfe_eth_init_one(struct pfe *
+               }
+       }
++      if (us) {
++              if (priv->phydev)
++                      phy_start(priv->phydev);
++              return 0;
++      }
++
+       netif_carrier_on(ndev);
+       /* Create all the sysfs files */
+@@ -2403,6 +2416,8 @@ static int pfe_eth_init_one(struct pfe *
+       return 0;
+ err4:
++      if (us)
++              goto err3;
+       unregister_netdev(ndev);
+ err3:
+       pfe_eth_mdio_exit(priv->mii_bus);
+@@ -2449,9 +2464,11 @@ static void pfe_eth_exit_one(struct pfe_
+ {
+       netif_info(priv, probe, priv->ndev, "%s\n", __func__);
+-      pfe_eth_sysfs_exit(priv->ndev);
++      if (!us) {
++              pfe_eth_sysfs_exit(priv->ndev);
+-      unregister_netdev(priv->ndev);
++              unregister_netdev(priv->ndev);
++      }
+       if (!(priv->einfo->phy_flags & GEMAC_NO_PHY))
+               pfe_phy_exit(priv->ndev);
+--- a/drivers/staging/fsl_ppfe/pfe_mod.c
++++ b/drivers/staging/fsl_ppfe/pfe_mod.c
+@@ -19,6 +19,10 @@
+ #include <linux/dma-mapping.h>
+ #include "pfe_mod.h"
++unsigned int us;
++module_param(us, uint, 0444);
++MODULE_PARM_DESC(us, "0: module enabled for kernel networking (DEFAULT)\n"
++                      "1: module enabled for userspace networking\n");
+ struct pfe *pfe;
+ /*
+@@ -56,6 +60,9 @@ int pfe_probe(struct pfe *pfe)
+       if (rc < 0)
+               goto err_hw;
++      if (us)
++              goto firmware_init;
++
+       rc = pfe_hif_lib_init(pfe);
+       if (rc < 0)
+               goto err_hif_lib;
+@@ -64,6 +71,7 @@ int pfe_probe(struct pfe *pfe)
+       if (rc < 0)
+               goto err_hif;
++firmware_init:
+       rc = pfe_firmware_init(pfe);
+       if (rc < 0)
+               goto err_firmware;
+@@ -99,6 +107,9 @@ err_ctrl:
+       pfe_firmware_exit(pfe);
+ err_firmware:
++      if (us)
++              goto err_hif_lib;
++
+       pfe_hif_exit(pfe);
+ err_hif:
+@@ -131,10 +142,14 @@ int pfe_remove(struct pfe *pfe)
+ #endif
+       pfe_firmware_exit(pfe);
++      if (us)
++              goto hw_exit;
++
+       pfe_hif_exit(pfe);
+       pfe_hif_lib_exit(pfe);
++hw_exit:
+       pfe_hw_exit(pfe);
+       return 0;
+--- a/drivers/staging/fsl_ppfe/pfe_mod.h
++++ b/drivers/staging/fsl_ppfe/pfe_mod.h
+@@ -22,6 +22,8 @@
+ #include <linux/device.h>
+ #include <linux/elf.h>
++extern unsigned int us;
++
+ struct pfe;
+ #include "pfe_hw.h"
diff --git a/target/linux/layerscape/patches-5.4/701-net-0297-staging-fsl_ppfe-eth-unregister-netdev-after-pfe_phy.patch b/target/linux/layerscape/patches-5.4/701-net-0297-staging-fsl_ppfe-eth-unregister-netdev-after-pfe_phy.patch
new file mode 100644 (file)
index 0000000..0731329
--- /dev/null
@@ -0,0 +1,44 @@
+From 4ebb4e490dd924d1a8ca7fe693a0dd1cfa150687 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Mon, 30 Apr 2018 11:40:01 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: unregister netdev after pfe_phy_exit
+
+rmmod pfe.ko throws below warning:
+
+kernfs: can not remove 'phydev', no directory
+------------[ cut here ]------------
+WARNING: CPU: 0 PID: 2230 at fs/kernfs/dir.c:1481
+kernfs_remove_by_name_ns+0x90/0xa0
+
+This is caused when the unregistered netdev structure is accessed to
+disconnect phy.
+
+Resolve the issue by unregistering netdev after disconnecting phy.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -2464,15 +2464,15 @@ static void pfe_eth_exit_one(struct pfe_
+ {
+       netif_info(priv, probe, priv->ndev, "%s\n", __func__);
+-      if (!us) {
++      if (!us)
+               pfe_eth_sysfs_exit(priv->ndev);
+-              unregister_netdev(priv->ndev);
+-      }
+-
+       if (!(priv->einfo->phy_flags & GEMAC_NO_PHY))
+               pfe_phy_exit(priv->ndev);
++      if (!us)
++              unregister_netdev(priv->ndev);
++
+       if (priv->mii_bus)
+               pfe_eth_mdio_exit(priv->mii_bus);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0298-staging-fsl_ppfe-eth-HW-parse-results-for-DPDK.patch b/target/linux/layerscape/patches-5.4/701-net-0298-staging-fsl_ppfe-eth-HW-parse-results-for-DPDK.patch
new file mode 100644 (file)
index 0000000..f8ec349
--- /dev/null
@@ -0,0 +1,47 @@
+From fd2bdf555ab192a96a44fa02f701095b24448d47 Mon Sep 17 00:00:00 2001
+From: anuj batham <anuj.batham@nxp.com>
+Date: Fri, 27 Apr 2018 14:38:09 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: HW parse results for DPDK
+
+HW Parse results are included in the packet headroom.
+Length and Offset calculation now accommodates parse info size.
+
+Signed-off-by: Archana Madhavan <archana.madhavan@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_hif_lib.c | 7 +++++--
+ drivers/staging/fsl_ppfe/pfe_hif_lib.h | 1 +
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_hif_lib.c
++++ b/drivers/staging/fsl_ppfe/pfe_hif_lib.c
+@@ -435,6 +435,7 @@ void *hif_lib_receive_pkt(struct hif_cli
+                       u16 size = *rx_ctrl >> HIF_CTRL_RX_OFFSET_OFST;
+                       if (size) {
++                              size += PFE_PARSE_INFO_SIZE;
+                               *len = CL_DESC_BUF_LEN(desc->ctrl) -
+                                               PFE_PKT_HEADER_SZ - size;
+                               *ofst = pfe_pkt_headroom + PFE_PKT_HEADER_SZ
+@@ -442,8 +443,10 @@ void *hif_lib_receive_pkt(struct hif_cli
+                               *priv_data = desc->data + PFE_PKT_HEADER_SZ;
+                       } else {
+                               *len = CL_DESC_BUF_LEN(desc->ctrl) -
+-                                              PFE_PKT_HEADER_SZ;
+-                              *ofst = pfe_pkt_headroom + PFE_PKT_HEADER_SZ;
++                                     PFE_PKT_HEADER_SZ - PFE_PARSE_INFO_SIZE;
++                              *ofst = pfe_pkt_headroom
++                                      + PFE_PKT_HEADER_SZ
++                                      + PFE_PARSE_INFO_SIZE;
+                               *priv_data = NULL;
+                       }
+--- a/drivers/staging/fsl_ppfe/pfe_hif_lib.h
++++ b/drivers/staging/fsl_ppfe/pfe_hif_lib.h
+@@ -23,6 +23,7 @@
+ #define HIF_CL_REQ_TIMEOUT    10
+ #define GFP_DMA_PFE 0
++#define PFE_PARSE_INFO_SIZE   16
+ enum {
+       REQUEST_CL_REGISTER = 0,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0299-staging-fsl_ppfe-eth-reorganize-pfe_netdev_ops.patch b/target/linux/layerscape/patches-5.4/701-net-0299-staging-fsl_ppfe-eth-reorganize-pfe_netdev_ops.patch
new file mode 100644 (file)
index 0000000..f17a53b
--- /dev/null
@@ -0,0 +1,30 @@
+From c4e167b4cd8c5b74b04bf69ebf93796a7be3d83d Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Wed, 20 Jun 2018 10:22:32 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: reorganize pfe_netdev_ops
+
+Reorganize members of struct pfe_netdev_ops to match with the order
+of members in struct net_device_ops defined in include/linux/netdevice.h
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -2243,11 +2243,11 @@ static const struct net_device_ops pfe_n
+       .ndo_stop = pfe_eth_close,
+       .ndo_start_xmit = pfe_eth_send_packet,
+       .ndo_select_queue = pfe_eth_select_queue,
+-      .ndo_get_stats = pfe_eth_get_stats,
+-      .ndo_set_mac_address = pfe_eth_set_mac_address,
+       .ndo_set_rx_mode = pfe_eth_set_multi,
+-      .ndo_set_features = pfe_eth_set_features,
++      .ndo_set_mac_address = pfe_eth_set_mac_address,
+       .ndo_validate_addr = eth_validate_addr,
++      .ndo_get_stats = pfe_eth_get_stats,
++      .ndo_set_features = pfe_eth_set_features,
+ };
+ /* pfe_eth_init_one
diff --git a/target/linux/layerscape/patches-5.4/701-net-0300-staging-fsl_ppfe-eth-use-mask-for-rx-max-frame-len.patch b/target/linux/layerscape/patches-5.4/701-net-0300-staging-fsl_ppfe-eth-use-mask-for-rx-max-frame-len.patch
new file mode 100644 (file)
index 0000000..457bc68
--- /dev/null
@@ -0,0 +1,46 @@
+From f5be11cd83a6d6d4de7bd7cbeb641bb1032c4f84 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Wed, 20 Jun 2018 10:22:50 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: use mask for rx max frame len
+
+Define and use PFE_RCR_MAX_FL_MASK to properly set Rx max frame
+length of MAC Receive Control Register.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_hal.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_hal.c
++++ b/drivers/staging/fsl_ppfe/pfe_hal.c
+@@ -19,6 +19,8 @@
+ #include "pfe_mod.h"
+ #include "pfe/pfe.h"
++#define PFE_RCR_MAX_FL_MASK   0xC000FFFF
++
+ void *cbus_base_addr;
+ void *ddr_base_addr;
+ unsigned long ddr_phys_base_addr;
+@@ -1011,8 +1013,8 @@ void gemac_no_broadcast(void *base)
+ void gemac_enable_1536_rx(void *base)
+ {
+       /* Set 1536 as Maximum frame length */
+-      writel(readl(base + EMAC_RCNTRL_REG) | (1536 << 16), base +
+-              EMAC_RCNTRL_REG);
++      writel((readl(base + EMAC_RCNTRL_REG) & PFE_RCR_MAX_FL_MASK)
++              | (1536 << 16), base +  EMAC_RCNTRL_REG);
+ }
+ /* GEMAC enable jumbo function.
+@@ -1020,8 +1022,8 @@ void gemac_enable_1536_rx(void *base)
+  */
+ void gemac_enable_rx_jmb(void *base)
+ {
+-      writel(readl(base + EMAC_RCNTRL_REG) | (JUMBO_FRAME_SIZE << 16), base
+-              + EMAC_RCNTRL_REG);
++      writel((readl(base + EMAC_RCNTRL_REG) & PFE_RCR_MAX_FL_MASK)
++              | (JUMBO_FRAME_SIZE << 16), base + EMAC_RCNTRL_REG);
+ }
+ /* GEMAC enable stacked vlan function.
diff --git a/target/linux/layerscape/patches-5.4/701-net-0301-staging-fsl_ppfe-eth-define-pfe-ndo_change_mtu-funct.patch b/target/linux/layerscape/patches-5.4/701-net-0301-staging-fsl_ppfe-eth-define-pfe-ndo_change_mtu-funct.patch
new file mode 100644 (file)
index 0000000..f35ea67
--- /dev/null
@@ -0,0 +1,73 @@
+From d9c44cf1a757823fb069dea0c15a830513175bf3 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Wed, 20 Jun 2018 10:23:01 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: define pfe ndo_change_mtu function
+
+Define ndo_change_mtu function for pfe. This sets the max Rx frame
+length to the new mtu.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/include/pfe/pfe.h |  1 +
+ drivers/staging/fsl_ppfe/pfe_eth.c         | 12 ++++++++++++
+ drivers/staging/fsl_ppfe/pfe_hal.c         | 11 +++++++++++
+ 3 files changed, 24 insertions(+)
+
+--- a/drivers/staging/fsl_ppfe/include/pfe/pfe.h
++++ b/drivers/staging/fsl_ppfe/include/pfe/pfe.h
+@@ -303,6 +303,7 @@ void gemac_allow_broadcast(void *base);
+ void gemac_no_broadcast(void *base);
+ void gemac_enable_1536_rx(void *base);
+ void gemac_disable_1536_rx(void *base);
++void gemac_set_rx_max_fl(void *base, int mtu);
+ void gemac_enable_rx_jmb(void *base);
+ void gemac_disable_rx_jmb(void *base);
+ void gemac_enable_stacked_vlan(void *base);
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -1345,6 +1345,17 @@ static int pfe_eth_event_handler(void *d
+       return 0;
+ }
++static int pfe_eth_change_mtu(struct net_device *ndev, int new_mtu)
++{
++      struct pfe_eth_priv_s *priv = netdev_priv(ndev);
++
++      ndev->mtu = new_mtu;
++      new_mtu += ETH_HLEN + ETH_FCS_LEN;
++      gemac_set_rx_max_fl(priv->EMAC_baseaddr, new_mtu);
++
++      return 0;
++}
++
+ /* pfe_eth_open
+  */
+ static int pfe_eth_open(struct net_device *ndev)
+@@ -2246,6 +2257,7 @@ static const struct net_device_ops pfe_n
+       .ndo_set_rx_mode = pfe_eth_set_multi,
+       .ndo_set_mac_address = pfe_eth_set_mac_address,
+       .ndo_validate_addr = eth_validate_addr,
++      .ndo_change_mtu = pfe_eth_change_mtu,
+       .ndo_get_stats = pfe_eth_get_stats,
+       .ndo_set_features = pfe_eth_set_features,
+ };
+--- a/drivers/staging/fsl_ppfe/pfe_hal.c
++++ b/drivers/staging/fsl_ppfe/pfe_hal.c
+@@ -1017,6 +1017,17 @@ void gemac_enable_1536_rx(void *base)
+               | (1536 << 16), base +  EMAC_RCNTRL_REG);
+ }
++/* GEMAC set rx Max frame length.
++ * @param[in] base    GEMAC base address
++ * @param[in] mtu     new mtu
++ */
++void gemac_set_rx_max_fl(void *base, int mtu)
++{
++      /* Set mtu as Maximum frame length */
++      writel((readl(base + EMAC_RCNTRL_REG) & PFE_RCR_MAX_FL_MASK)
++              | (mtu << 16), base + EMAC_RCNTRL_REG);
++}
++
+ /* GEMAC enable jumbo function.
+  * @param[in] base    GEMAC base address
+  */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0302-staging-fsl_ppfe-eth-remove-jumbo-frame-enable-from-.patch b/target/linux/layerscape/patches-5.4/701-net-0302-staging-fsl_ppfe-eth-remove-jumbo-frame-enable-from-.patch
new file mode 100644 (file)
index 0000000..a98c551
--- /dev/null
@@ -0,0 +1,46 @@
+From 162c09cee1b5b00e09fd99273fd2f8c460c0d989 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Wed, 20 Jun 2018 10:23:16 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: remove jumbo frame enable from gemac
+ init
+
+MAC Receive Control Register was configured to allow jumbo frames.
+This is removed as jumbo frames can be supported anytime by changing
+mtu which will in turn modify MAX_FL field of MAC RCR.
+Jumbo frames caused pfe to hang on LS1012A rev 1.0 Silicon due to
+erratum A-010897.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c | 1 -
+ drivers/staging/fsl_ppfe/pfe_hal.c | 9 ---------
+ 2 files changed, 10 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -1272,7 +1272,6 @@ static int pfe_gemac_init(struct pfe_eth
+       gemac_set_config(priv->EMAC_baseaddr, &cfg);
+       gemac_allow_broadcast(priv->EMAC_baseaddr);
+       gemac_enable_1536_rx(priv->EMAC_baseaddr);
+-      gemac_enable_rx_jmb(priv->EMAC_baseaddr);
+       gemac_enable_stacked_vlan(priv->EMAC_baseaddr);
+       gemac_enable_pause_rx(priv->EMAC_baseaddr);
+       gemac_set_bus_width(priv->EMAC_baseaddr, 64);
+--- a/drivers/staging/fsl_ppfe/pfe_hal.c
++++ b/drivers/staging/fsl_ppfe/pfe_hal.c
+@@ -1028,15 +1028,6 @@ void gemac_set_rx_max_fl(void *base, int
+               | (mtu << 16), base + EMAC_RCNTRL_REG);
+ }
+-/* GEMAC enable jumbo function.
+- * @param[in] base    GEMAC base address
+- */
+-void gemac_enable_rx_jmb(void *base)
+-{
+-      writel((readl(base + EMAC_RCNTRL_REG) & PFE_RCR_MAX_FL_MASK)
+-              | (JUMBO_FRAME_SIZE << 16), base + EMAC_RCNTRL_REG);
+-}
+-
+ /* GEMAC enable stacked vlan function.
+  * @param[in] base    GEMAC base address
+  */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0303-staging-fsl_ppfe-eth-disable-CRC-removal.patch b/target/linux/layerscape/patches-5.4/701-net-0303-staging-fsl_ppfe-eth-disable-CRC-removal.patch
new file mode 100644 (file)
index 0000000..c17f8a8
--- /dev/null
@@ -0,0 +1,28 @@
+From 26ddfc3e40c52ca9cb78c6ae4b4608f94d2e8cb5 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Wed, 20 Jun 2018 10:23:32 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: disable CRC removal
+
+Disable CRC removal from the packet, so that packets are forwarded
+as is to Linux.
+CRC configuration in MAC will be reflected in the packet received
+to Linux.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_hal.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_hal.c
++++ b/drivers/staging/fsl_ppfe/pfe_hal.c
+@@ -869,8 +869,8 @@ void gemac_set_mode(void *base, int mode
+       /*Remove loopbank*/
+       val &= ~EMAC_RCNTRL_LOOP;
+-      /*Enable flow control and MII mode*/
+-      val |= (EMAC_RCNTRL_FCE | EMAC_RCNTRL_MII_MODE);
++      /* Enable flow control and MII mode and terminate received CRC */
++      val |= (EMAC_RCNTRL_FCE | EMAC_RCNTRL_MII_MODE | EMAC_RCNTRL_CRC_FWD);
+       writel(val, base + EMAC_RCNTRL_REG);
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0304-staging-fsl_ppfe-eth-handle-ls1012a-errata_a010897.patch b/target/linux/layerscape/patches-5.4/701-net-0304-staging-fsl_ppfe-eth-handle-ls1012a-errata_a010897.patch
new file mode 100644 (file)
index 0000000..d7ee96a
--- /dev/null
@@ -0,0 +1,107 @@
+From a563dccef2871e37efcfcb2f3faee7c9f9381f6c Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Wed, 20 Jun 2018 10:23:41 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: handle ls1012a errata_a010897
+
+On LS1012A rev 1.0, Jumbo frames are not supported as it causes
+the PFE controller to hang. A reset of the entire chip is required
+to resume normal operation.
+
+To handle this errata, frames with length > 1900 are truncated for
+rev 1.0 of LS1012A.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c | 20 +++++++++++++++++++-
+ drivers/staging/fsl_ppfe/pfe_eth.h |  3 ++-
+ drivers/staging/fsl_ppfe/pfe_hal.c | 10 +++++++++-
+ 3 files changed, 30 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -44,6 +44,7 @@
+ #include <linux/delay.h>
+ #include <linux/regmap.h>
+ #include <linux/i2c.h>
++#include <linux/fsl/guts.h>
+ #if defined(CONFIG_NF_CONNTRACK_MARK)
+ #include <net/netfilter/nf_conntrack.h>
+@@ -52,6 +53,10 @@
+ #include "pfe_mod.h"
+ #include "pfe_eth.h"
++#define LS1012A_REV_1_0               0x87040010
++
++bool pfe_errata_a010897;
++
+ static void *cbus_emac_base[3];
+ static void *cbus_gpi_base[3];
+@@ -2362,7 +2367,15 @@ static int pfe_eth_init_one(struct pfe *
+       /* Set MTU limits */
+       ndev->min_mtu = ETH_MIN_MTU;
+-      ndev->max_mtu = JUMBO_FRAME_SIZE;
++
++/*
++ * Jumbo frames are not supported on LS1012A rev-1.0.
++ * So max mtu should be restricted to supported frame length.
++ */
++      if (pfe_errata_a010897)
++              ndev->max_mtu = JUMBO_FRAME_SIZE_V1 - ETH_HLEN - ETH_FCS_LEN;
++      else
++              ndev->max_mtu = JUMBO_FRAME_SIZE_V2 - ETH_HLEN - ETH_FCS_LEN;
+       /* supported features */
+       ndev->hw_features = NETIF_F_SG;
+@@ -2453,6 +2466,11 @@ int pfe_eth_init(struct pfe *pfe)
+       cbus_gpi_base[0] = EGPI1_BASE_ADDR;
+       cbus_gpi_base[1] = EGPI2_BASE_ADDR;
++      if (fsl_guts_get_svr() == LS1012A_REV_1_0)
++              pfe_errata_a010897 = true;
++      else
++              pfe_errata_a010897 = false;
++
+       for (ii = 0; ii < NUM_GEMAC_SUPPORT; ii++) {
+               err = pfe_eth_init_one(pfe, ii);
+               if (err)
+--- a/drivers/staging/fsl_ppfe/pfe_eth.h
++++ b/drivers/staging/fsl_ppfe/pfe_eth.h
+@@ -85,7 +85,8 @@ struct ls1012a_pfe_platform_data {
+ #define EMAC_TXQ_CNT  16
+ #define EMAC_TXQ_DEPTH        (HIF_TX_DESC_NT)
+-#define JUMBO_FRAME_SIZE      10258
++#define JUMBO_FRAME_SIZE_V1   1900
++#define JUMBO_FRAME_SIZE_V2   10258
+ /*
+  * Client Tx queue threshold, for txQ flush condition.
+  * It must be smaller than the queue size (in case we ever change it in the
+--- a/drivers/staging/fsl_ppfe/pfe_hal.c
++++ b/drivers/staging/fsl_ppfe/pfe_hal.c
+@@ -19,6 +19,9 @@
+ #include "pfe_mod.h"
+ #include "pfe/pfe.h"
++/* A-010897: Jumbo frame is not supported */
++extern bool pfe_errata_a010897;
++
+ #define PFE_RCR_MAX_FL_MASK   0xC000FFFF
+ void *cbus_base_addr;
+@@ -1102,7 +1105,12 @@ void gemac_set_config(void *base, struct
+       /*GEMAC config taken from VLSI */
+       writel(0x00000004, base + EMAC_TFWR_STR_FWD);
+       writel(0x00000005, base + EMAC_RX_SECTION_FULL);
+-      writel(0x00003fff, base + EMAC_TRUNC_FL);
++
++      if (pfe_errata_a010897)
++              writel(0x0000076c, base + EMAC_TRUNC_FL);
++      else
++              writel(0x00003fff, base + EMAC_TRUNC_FL);
++
+       writel(0x00000030, base + EMAC_TX_SECTION_EMPTY);
+       writel(0x00000000, base + EMAC_MIB_CTRL_STS_REG);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0305-staging-fsl_ppfe-eth-replace-magic-numbers.patch b/target/linux/layerscape/patches-5.4/701-net-0305-staging-fsl_ppfe-eth-replace-magic-numbers.patch
new file mode 100644 (file)
index 0000000..22d865c
--- /dev/null
@@ -0,0 +1,142 @@
+From cdebdc900ae5cb29dc1cce1c26865001534ab77d Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Thu, 4 Oct 2018 09:38:34 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: replace magic numbers
+
+Replace magic numbers and some cosmetic changes.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c | 83 ++++++++++++++++++++++++++++----------
+ 1 file changed, 61 insertions(+), 22 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -66,6 +66,36 @@ static void pfe_eth_flush_tx(struct pfe_
+ static void pfe_eth_flush_txQ(struct pfe_eth_priv_s *priv, int tx_q_num, int
+                               from_tx, int n_desc);
++/* MDIO registers */
++#define MDIO_SGMII_CR                 0x00
++#define MDIO_SGMII_SR                 0x01
++#define MDIO_SGMII_DEV_ABIL_SGMII     0x04
++#define MDIO_SGMII_LINK_TMR_L         0x12
++#define MDIO_SGMII_LINK_TMR_H         0x13
++#define MDIO_SGMII_IF_MODE            0x14
++
++/* SGMII Control defines */
++#define SGMII_CR_RST                  0x8000
++#define SGMII_CR_AN_EN                        0x1000
++#define SGMII_CR_RESTART_AN           0x0200
++#define SGMII_CR_FD                   0x0100
++#define SGMII_CR_SPEED_SEL1_1G                0x0040
++#define SGMII_CR_DEF_VAL              (SGMII_CR_AN_EN | SGMII_CR_FD | \
++                                       SGMII_CR_SPEED_SEL1_1G)
++
++/* SGMII IF Mode */
++#define SGMII_DUPLEX_HALF             0x10
++#define SGMII_SPEED_10MBPS            0x00
++#define SGMII_SPEED_100MBPS           0x04
++#define SGMII_SPEED_1GBPS             0x08
++#define SGMII_USE_SGMII_AN            0x02
++#define SGMII_EN                      0x01
++
++/* SGMII Device Ability for SGMII */
++#define SGMII_DEV_ABIL_ACK            0x4000
++#define SGMII_DEV_ABIL_EEE_CLK_STP_EN 0x0100
++#define SGMII_DEV_ABIL_SGMII          0x0001
++
+ unsigned int gemac_regs[] = {
+       0x0004, /* Interrupt event */
+       0x0008, /* Interrupt mask */
+@@ -1042,6 +1072,10 @@ static int pfe_get_phydev_speed(struct p
+ #define SCFG_RGMIIPCR_SETSP_10M         (0x00000002)
+ #define SCFG_RGMIIPCR_SETFD             (0x00000001)
++#define MDIOSELCR     0x484
++#define MDIOSEL_SERDES        0x0
++#define MDIOSEL_EXTPHY  0x80000000
++
+ static void pfe_set_rgmii_speed(struct phy_device *phydev)
+ {
+       u32 rgmii_pcr;
+@@ -1187,25 +1221,34 @@ static void ls1012a_configure_serdes(str
+       netif_info(priv, drv, ndev, "%s\n", __func__);
+       /* PCS configuration done with corresponding GEMAC */
+-      pfe_eth_mdio_read(bus, 0, 0);
+-      pfe_eth_mdio_read(bus, 0, 1);
++      pfe_eth_mdio_read(bus, 0, MDIO_SGMII_CR);
++      pfe_eth_mdio_read(bus, 0, MDIO_SGMII_SR);
++
++      pfe_eth_mdio_write(bus, 0, MDIO_SGMII_CR, SGMII_CR_RST);
+-       /*These settings taken from validtion team */
+-      pfe_eth_mdio_write(bus, 0, 0x0, 0x8000);
+       if (sgmii_2500) {
+-              pfe_eth_mdio_write(bus, 0, 0x14, 0x9);
+-              pfe_eth_mdio_write(bus, 0, 0x4, 0x4001);
+-              pfe_eth_mdio_write(bus, 0, 0x12, 0xa120);
+-              pfe_eth_mdio_write(bus, 0, 0x13, 0x7);
++              pfe_eth_mdio_write(bus, 0, MDIO_SGMII_IF_MODE, SGMII_SPEED_1GBPS
++                                                             | SGMII_EN);
++              pfe_eth_mdio_write(bus, 0, MDIO_SGMII_DEV_ABIL_SGMII,
++                                 SGMII_DEV_ABIL_ACK | SGMII_DEV_ABIL_SGMII);
++              pfe_eth_mdio_write(bus, 0, MDIO_SGMII_LINK_TMR_L, 0xa120);
++              pfe_eth_mdio_write(bus, 0, MDIO_SGMII_LINK_TMR_H, 0x7);
+               /* Autonegotiation need to be disabled for 2.5G SGMII mode*/
+-              value = 0x0140;
+-              pfe_eth_mdio_write(bus, 0, 0x0, value);
++              value = SGMII_CR_FD | SGMII_CR_SPEED_SEL1_1G;
++              pfe_eth_mdio_write(bus, 0, MDIO_SGMII_CR, value);
+       } else {
+-              pfe_eth_mdio_write(bus, 0, 0x14, 0xb);
+-              pfe_eth_mdio_write(bus, 0, 0x4, 0x1a1);
+-              pfe_eth_mdio_write(bus, 0, 0x12, 0x400);
+-              pfe_eth_mdio_write(bus, 0, 0x13, 0x0);
+-              pfe_eth_mdio_write(bus, 0, 0x0, 0x1140);
++              pfe_eth_mdio_write(bus, 0, MDIO_SGMII_IF_MODE,
++                                 SGMII_SPEED_1GBPS
++                                 | SGMII_USE_SGMII_AN
++                                 | SGMII_EN);
++              pfe_eth_mdio_write(bus, 0, MDIO_SGMII_DEV_ABIL_SGMII,
++                                 SGMII_DEV_ABIL_EEE_CLK_STP_EN
++                                 | 0xa0
++                                 | SGMII_DEV_ABIL_SGMII);
++              pfe_eth_mdio_write(bus, 0, MDIO_SGMII_LINK_TMR_L, 0x400);
++              pfe_eth_mdio_write(bus, 0, MDIO_SGMII_LINK_TMR_H, 0x0);
++              value = SGMII_CR_AN_EN | SGMII_CR_FD | SGMII_CR_SPEED_SEL1_1G;
++              pfe_eth_mdio_write(bus, 0, MDIO_SGMII_CR, value);
+       }
+ }
+@@ -1235,15 +1278,15 @@ static int pfe_phy_init(struct net_devic
+           (interface == PHY_INTERFACE_MODE_2500SGMII)) {
+               /*Configure SGMII PCS */
+               if (pfe->scfg) {
+-                      /*Config MDIO from serdes */
+-                      regmap_write(pfe->scfg, 0x484, 0x00000000);
++                      /* Config MDIO from serdes */
++                      regmap_write(pfe->scfg, MDIOSELCR, MDIOSEL_SERDES);
+               }
+               ls1012a_configure_serdes(ndev);
+       }
+       if (pfe->scfg) {
+               /*Config MDIO from PAD */
+-              regmap_write(pfe->scfg, 0x484, 0x80000000);
++              regmap_write(pfe->scfg, MDIOSELCR, MDIOSEL_EXTPHY);
+       }
+       priv->oldlink = 0;
+@@ -2339,10 +2382,6 @@ static int pfe_eth_init_one(struct pfe *
+       priv->PHY_baseaddr = cbus_emac_base[0];
+       priv->GPI_baseaddr = cbus_gpi_base[id];
+-#define HIF_GEMAC_TMUQ_BASE   6
+-      priv->low_tmu_q =  HIF_GEMAC_TMUQ_BASE + (id * 2);
+-      priv->high_tmu_q        =  priv->low_tmu_q + 1;
+-
+       spin_lock_init(&priv->lock);
+       pfe_eth_fast_tx_timeout_init(priv);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0306-staging-fsl_ppfe-eth-resolve-indentation-warning.patch b/target/linux/layerscape/patches-5.4/701-net-0306-staging-fsl_ppfe-eth-resolve-indentation-warning.patch
new file mode 100644 (file)
index 0000000..f57e266
--- /dev/null
@@ -0,0 +1,45 @@
+From 1af2e375a76c55d227b7d1b1f1ba1c9cf850946a Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Thu, 4 Oct 2018 09:39:00 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: resolve indentation warning
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolve the following indentation warning:
+
+drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c:
+In function ‘pfe_get_gemac_if_proprties’:
+drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c:96:2:
+warning: this ‘else’ clause does not guard...
+[-Wmisleading-indentation]
+  else
+  ^~~~
+drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c:98:3:
+note: ...this statement, but the latter is misleadingly indented as
+if it were guarded by the ‘else’
+   pdata->ls1012a_eth_pdata[port].mdio_muxval = phy_id;
+   ^~~~~
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
++++ b/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
+@@ -89,11 +89,12 @@ static int pfe_get_gemac_if_proprties(st
+       }
+       addr = of_get_property(gem, "fsl,mdio-mux-val", &size);
+-      if (!addr)
++      if (!addr) {
+               pr_err("%s: Invalid mdio-mux-val....\n", __func__);
+-      else
++      } else {
+               phy_id = be32_to_cpup(addr);
+               pdata->ls1012a_eth_pdata[port].mdio_muxval = phy_id;
++      }
+       if (pdata->ls1012a_eth_pdata[port].phy_id < 32)
+               pfe->mdio_muxval[pdata->ls1012a_eth_pdata[port].phy_id] =
diff --git a/target/linux/layerscape/patches-5.4/701-net-0307-staging-fsl_ppfe-eth-add-fixed-link-support.patch b/target/linux/layerscape/patches-5.4/701-net-0307-staging-fsl_ppfe-eth-add-fixed-link-support.patch
new file mode 100644 (file)
index 0000000..298c34a
--- /dev/null
@@ -0,0 +1,110 @@
+From 04373c37df836557ae7ebb769383baa1b57c5ffa Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Thu, 4 Oct 2018 09:38:17 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: add fixed-link support
+
+In cases where MAC is not connected to a normal MDIO-managed PHY
+device, and instead to a switch, it is configured as a "fixed-link".
+Code to handle this scenario is added here.
+
+phy_node in the dtb is checked to identify a fixed-link.
+On identification of a fixed-link, it is registered and connected.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c              | 21 ++++++++++++++++++++-
+ drivers/staging/fsl_ppfe/pfe_eth.h              |  2 ++
+ drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c |  4 ++++
+ 3 files changed, 26 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -39,6 +39,9 @@
+ #include <net/ip.h>
+ #include <net/sock.h>
++#include <linux/of.h>
++#include <linux/of_mdio.h>
++
+ #include <linux/io.h>
+ #include <asm/irq.h>
+ #include <linux/delay.h>
+@@ -1263,6 +1266,8 @@ static int pfe_phy_init(struct net_devic
+       char phy_id[MII_BUS_ID_SIZE + 3];
+       char bus_id[MII_BUS_ID_SIZE];
+       phy_interface_t interface;
++      struct device_node *phy_node;
++      int rc;
+       priv->oldlink = 0;
+       priv->oldspeed = 0;
+@@ -1293,7 +1298,20 @@ static int pfe_phy_init(struct net_devic
+       priv->oldspeed = 0;
+       priv->oldduplex = -1;
+       pr_info("%s interface %x\n", __func__, interface);
+-      phydev = phy_connect(ndev, phy_id, &pfe_eth_adjust_link, interface);
++
++      if (of_phy_is_fixed_link(priv->phy_node)) {
++              rc = of_phy_register_fixed_link(priv->phy_node);
++              if (rc)
++                      return rc;
++              phy_node = of_node_get(priv->phy_node);
++              phydev = of_phy_connect(ndev, phy_node, pfe_eth_adjust_link, 0,
++                                      priv->einfo->mii_config);
++              of_node_put(phy_node);
++
++      } else {
++              phydev = phy_connect(ndev, phy_id,
++                                   &pfe_eth_adjust_link, interface);
++      }
+       if (IS_ERR(phydev)) {
+               netdev_err(ndev, "phy_connect() failed\n");
+@@ -2371,6 +2389,7 @@ static int pfe_eth_init_one(struct pfe *
+       priv->ndev = ndev;
+       priv->id = einfo[id].gem_id;
+       priv->pfe = pfe;
++      priv->phy_node = einfo[id].phy_node;
+       SET_NETDEV_DEV(priv->ndev, priv->pfe->dev);
+--- a/drivers/staging/fsl_ppfe/pfe_eth.h
++++ b/drivers/staging/fsl_ppfe/pfe_eth.h
+@@ -61,6 +61,7 @@ struct ls1012a_eth_platform_data {
+       u32 phy_id;
+       u32 mdio_muxval;
+       u8 mac_addr[ETH_ALEN];
++      struct device_node      *phy_node;
+ };
+ struct ls1012a_mdio_platform_data {
+@@ -144,6 +145,7 @@ struct  pfe_eth_priv_s {
+       int                     oldspeed;
+       int                     oldduplex;
+       int                     oldlink;
++      struct device_node      *phy_node;
+       /* mdio info */
+       int                     mdc_div;
+       struct mii_bus          *mii_bus;
+--- a/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
++++ b/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
+@@ -18,8 +18,10 @@
+ #include <linux/module.h>
+ #include <linux/device.h>
++#include <linux/of.h>
+ #include <linux/of_net.h>
+ #include <linux/of_address.h>
++#include <linux/of_mdio.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+ #include <linux/clk.h>
+@@ -124,6 +126,8 @@ static int pfe_get_gemac_if_proprties(st
+       pdata->ls1012a_mdio_pdata[port].irq[0] = PHY_POLL;
+ done:
++      if (of_phy_is_fixed_link(gem))
++              pdata->ls1012a_eth_pdata[port].phy_node = of_node_get(gem);
+       return 0;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0308-staging-fsl_ppfe-add-support-for-a-char-dev-for-link.patch b/target/linux/layerscape/patches-5.4/701-net-0308-staging-fsl_ppfe-add-support-for-a-char-dev-for-link.patch
new file mode 100644 (file)
index 0000000..c445952
--- /dev/null
@@ -0,0 +1,364 @@
+From a41d4af2ed4b02edca9d7f69955893d407274dc2 Mon Sep 17 00:00:00 2001
+From: Shreyansh Jain <shreyansh.jain@nxp.com>
+Date: Wed, 6 Jun 2018 14:19:34 +0530
+Subject: [PATCH] staging: fsl_ppfe: add support for a char dev for link status
+
+Read and IOCTL support is added. Application would need to open,
+read/ioctl the /dev/pfe_us_cdev device.
+select is pending as it requires a wait_queue.
+
+Signed-off-by: Shreyansh Jain <shreyansh.jain@nxp.com>
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/Makefile   |   3 +-
+ drivers/staging/fsl_ppfe/pfe_cdev.c | 207 ++++++++++++++++++++++++++++++++++++
+ drivers/staging/fsl_ppfe/pfe_cdev.h |  52 +++++++++
+ drivers/staging/fsl_ppfe/pfe_eth.c  |  14 +++
+ drivers/staging/fsl_ppfe/pfe_mod.c  |  14 +++
+ 5 files changed, 289 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_cdev.c
+ create mode 100644 drivers/staging/fsl_ppfe/pfe_cdev.h
+
+--- a/drivers/staging/fsl_ppfe/Makefile
++++ b/drivers/staging/fsl_ppfe/Makefile
+@@ -16,4 +16,5 @@ pfe-y += pfe_mod.o \
+       pfe_sysfs.o \
+       pfe_debugfs.o \
+       pfe_ls1012a_platform.o \
+-      pfe_hal.o
++      pfe_hal.o \
++      pfe_cdev.o
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_cdev.c
+@@ -0,0 +1,207 @@
++/*
++ * Copyright 2018 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++/* @pfe_cdev.c.
++ *  Dummy device representing the PFE US in userspace.
++ *  - used for interacting with the kernel layer for link status
++ */
++
++#include "pfe_cdev.h"
++
++static int pfe_majno;
++static struct class *pfe_char_class;
++static struct device *pfe_char_dev;
++
++struct pfe_shared_info link_states[PFE_CDEV_ETH_COUNT];
++
++static int pfe_cdev_open(struct inode *inp, struct file *fp)
++{
++      pr_debug("PFE CDEV device opened.\n");
++      return 0;
++}
++
++static ssize_t pfe_cdev_read(struct file *fp, char *buf,
++                           size_t len, loff_t *off)
++{
++      int ret = 0;
++
++      pr_info("PFE CDEV attempt copying (%lu) size of user.\n",
++              sizeof(link_states));
++
++      pr_debug("Dump link_state on screen before copy_to_user\n");
++      for (; ret < PFE_CDEV_ETH_COUNT; ret++) {
++              pr_debug("%u  %u", link_states[ret].phy_id,
++                       link_states[ret].state);
++              pr_debug("\n");
++      }
++
++      /* Copy to user the value in buffer sized len */
++      ret = copy_to_user(buf, &link_states, sizeof(link_states));
++      if (ret != 0) {
++              pr_err("Failed to send (%d)bytes of (%lu) requested.\n",
++                     ret, len);
++              return -EFAULT;
++      }
++
++      /* offset set back to 0 as there is contextual reading offset */
++      *off = 0;
++      pr_debug("Read of (%lu) bytes performed.\n", sizeof(link_states));
++
++      return sizeof(link_states);
++}
++
++/**
++ * This function is for getting some commands from user through non-IOCTL
++ * channel. It can used to configure the device.
++ * TODO: To be filled in future, if require duplex communication with user
++ * space.
++ */
++static ssize_t pfe_cdev_write(struct file *fp, const char *buf,
++                            size_t len, loff_t *off)
++{
++      pr_info("PFE CDEV Write operation not supported!\n");
++
++      return -EFAULT;
++}
++
++static int pfe_cdev_release(struct inode *inp, struct file *fp)
++{
++      pr_info("PFE_CDEV: Device successfully closed\n");
++      return 0;
++}
++
++static long pfe_cdev_ioctl(struct file *fp, unsigned int cmd,
++                         unsigned long arg)
++{
++      int ret = -EFAULT;
++      int __user *argp = (int __user *)arg;
++
++      pr_debug("PFE CDEV IOCTL Called with cmd=(%u)\n", cmd);
++
++      switch (cmd) {
++      case PFE_CDEV_ETH0_STATE_GET:
++              /* Return an unsigned int (link state) for ETH0 */
++              *argp = link_states[0].state;
++              pr_debug("Returning state=%d for ETH0\n", *argp);
++              ret = 0;
++              break;
++      case PFE_CDEV_ETH1_STATE_GET:
++              /* Return an unsigned int (link state) for ETH0 */
++              *argp = link_states[1].state;
++              pr_debug("Returning state=%d for ETH1\n", *argp);
++              ret = 0;
++              break;
++      default:
++              pr_info("Unsupport cmd (%d) for PFE CDEV.\n", cmd);
++              break;
++      };
++
++      return ret;
++}
++
++static unsigned int pfe_cdev_poll(struct file *fp,
++                                struct poll_table_struct *wait)
++{
++      pr_info("PFE CDEV poll method not supported\n");
++      return 0;
++}
++
++static const struct file_operations pfe_cdev_fops = {
++      .open = pfe_cdev_open,
++      .read = pfe_cdev_read,
++      .write = pfe_cdev_write,
++      .release = pfe_cdev_release,
++      .unlocked_ioctl = pfe_cdev_ioctl,
++      .poll = pfe_cdev_poll,
++};
++
++int pfe_cdev_init(void)
++{
++      int ret;
++
++      pr_debug("PFE CDEV initialization begin\n");
++
++      /* Register the major number for the device */
++      pfe_majno = register_chrdev(0, PFE_CDEV_NAME, &pfe_cdev_fops);
++      if (pfe_majno < 0) {
++              pr_err("Unable to register PFE CDEV. PFE CDEV not available\n");
++              ret = pfe_majno;
++              goto cleanup;
++      }
++
++      pr_debug("PFE CDEV assigned major number: %d\n", pfe_majno);
++
++      /* Register the class for the device */
++      pfe_char_class = class_create(THIS_MODULE, PFE_CLASS_NAME);
++      if (IS_ERR(pfe_char_class)) {
++              pr_err(
++              "Failed to init class for PFE CDEV. PFE CDEV not available.\n");
++              goto cleanup;
++      }
++
++      pr_debug("PFE CDEV Class created successfully.\n");
++
++      /* Create the device without any parent and without any callback data */
++          pfe_char_dev = device_create(pfe_char_class, NULL,
++                                       MKDEV(pfe_majno, 0), NULL,
++                                       PFE_CDEV_NAME);
++      if (IS_ERR(pfe_char_dev)) {
++              pr_err("Unable to PFE CDEV device. PFE CDEV not available.\n");
++              ret = PTR_ERR(pfe_char_dev);
++              goto cleanup;
++      }
++
++      /* Information structure being shared with the userspace */
++      memset(link_states, 0, sizeof(struct pfe_shared_info) *
++                      PFE_CDEV_ETH_COUNT);
++
++      pr_info("PFE CDEV created: %s\n", PFE_CDEV_NAME);
++
++      ret = 0;
++      return ret;
++
++cleanup:
++      if (!IS_ERR(pfe_char_class))
++              class_destroy(pfe_char_class);
++
++      if (pfe_majno > 0)
++              unregister_chrdev(pfe_majno, PFE_CDEV_NAME);
++
++      ret = -EFAULT;
++      return ret;
++}
++
++void pfe_cdev_exit(void)
++{
++      if (!IS_ERR(pfe_char_dev))
++              device_destroy(pfe_char_class, MKDEV(pfe_majno, 0));
++
++      if (!IS_ERR(pfe_char_class)) {
++              class_unregister(pfe_char_class);
++              class_destroy(pfe_char_class);
++      }
++
++      if (pfe_majno > 0)
++              unregister_chrdev(pfe_majno, PFE_CDEV_NAME);
++
++      /* reset the variables */
++      pfe_majno = 0;
++      pfe_char_class = NULL;
++      pfe_char_dev = NULL;
++
++      pr_info("PFE CDEV Removed.\n");
++}
+--- /dev/null
++++ b/drivers/staging/fsl_ppfe/pfe_cdev.h
+@@ -0,0 +1,52 @@
++/*
++ * Copyright 2018 NXP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _PFE_CDEV_H_
++#define _PFE_CDEV_H_
++
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/err.h>
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/uaccess.h>
++#include <linux/poll.h>
++
++#define  PFE_CDEV_NAME "pfe_us_cdev"
++#define  PFE_CLASS_NAME  "ppfe_us"
++
++/* Extracted from ls1012a_pfe_platform_data, there are 3 interfaces which are
++ * supported by PFE driver. Should be updated if number of eth devices are
++ * changed.
++ */
++#define PFE_CDEV_ETH_COUNT 3
++
++struct pfe_shared_info {
++      uint32_t phy_id; /* Link phy ID */
++      uint8_t state;  /* Has either 0 or 1 */
++};
++
++extern struct pfe_shared_info link_states[PFE_CDEV_ETH_COUNT];
++
++/* IOCTL Commands */
++#define PFE_CDEV_ETH0_STATE_GET       0
++#define PFE_CDEV_ETH1_STATE_GET       1
++
++int pfe_cdev_init(void);
++void pfe_cdev_exit(void);
++
++#endif /* _PFE_CDEV_H_ */
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -55,6 +55,7 @@
+ #include "pfe_mod.h"
+ #include "pfe_eth.h"
++#include "pfe_cdev.h"
+ #define LS1012A_REV_1_0               0x87040010
+@@ -1160,6 +1161,19 @@ static void pfe_eth_adjust_link(struct n
+               phy_print_status(phydev);
+       spin_unlock_irqrestore(&priv->lock, flags);
++
++      /* Now, dump the details to the cdev.
++       * XXX: Locking would be required? (uniprocess arch)
++       *      Or, maybe move it in spinlock above
++       */
++      if (us && priv->einfo->gem_id < PFE_CDEV_ETH_COUNT) {
++              pr_debug("Changing link state from (%u) to (%u) for ID=(%u)\n",
++                       link_states[priv->einfo->gem_id].state,
++                       phydev->link,
++                       priv->einfo->gem_id);
++              link_states[priv->einfo->gem_id].phy_id = priv->einfo->gem_id;
++              link_states[priv->einfo->gem_id].state = phydev->link;
++      }
+ }
+ /* pfe_phy_exit
+--- a/drivers/staging/fsl_ppfe/pfe_mod.c
++++ b/drivers/staging/fsl_ppfe/pfe_mod.c
+@@ -18,6 +18,7 @@
+ #include <linux/dma-mapping.h>
+ #include "pfe_mod.h"
++#include "pfe_cdev.h"
+ unsigned int us;
+ module_param(us, uint, 0444);
+@@ -92,8 +93,18 @@ firmware_init:
+       if (rc < 0)
+               goto err_debugfs;
++      if (us) {
++              /* Creating a character device */
++              rc = pfe_cdev_init();
++              if (rc < 0)
++                      goto err_cdev;
++      }
++
+       return 0;
++err_cdev:
++      pfe_debugfs_exit(pfe);
++
+ err_debugfs:
+       pfe_sysfs_exit(pfe);
+@@ -129,6 +140,9 @@ int pfe_remove(struct pfe *pfe)
+ {
+       pr_info("%s\n", __func__);
++      if (us)
++              pfe_cdev_exit();
++
+       pfe_debugfs_exit(pfe);
+       pfe_sysfs_exit(pfe);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0309-staging-fsl_ppfe-enable-hif-event-from-userspace.patch b/target/linux/layerscape/patches-5.4/701-net-0309-staging-fsl_ppfe-enable-hif-event-from-userspace.patch
new file mode 100644 (file)
index 0000000..785f316
--- /dev/null
@@ -0,0 +1,118 @@
+From 0c072b46ecc8689be160bfdc750e95ad9879d706 Mon Sep 17 00:00:00 2001
+From: Akhil Goyal <akhil.goyal@nxp.com>
+Date: Thu, 5 Jul 2018 20:14:21 +0530
+Subject: [PATCH] staging: fsl_ppfe: enable hif event from userspace
+
+HIF interrupts are enabled using ioctl from user space,
+and epoll wait from user space wakes up when there is an HIF
+interrupt.
+
+Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_cdev.c | 57 +++++++++++++++++++++++++++++++++++++
+ drivers/staging/fsl_ppfe/pfe_cdev.h |  5 ++--
+ 2 files changed, 60 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_cdev.c
++++ b/drivers/staging/fsl_ppfe/pfe_cdev.c
+@@ -20,11 +20,18 @@
+  *  - used for interacting with the kernel layer for link status
+  */
++#include <linux/eventfd.h>
++#include <linux/irqreturn.h>
++#include <linux/io.h>
++#include <asm/irq.h>
++
+ #include "pfe_cdev.h"
++#include "pfe_mod.h"
+ static int pfe_majno;
+ static struct class *pfe_char_class;
+ static struct device *pfe_char_dev;
++struct eventfd_ctx *g_trigger;
+ struct pfe_shared_info link_states[PFE_CDEV_ETH_COUNT];
+@@ -80,10 +87,44 @@ static ssize_t pfe_cdev_write(struct fil
+ static int pfe_cdev_release(struct inode *inp, struct file *fp)
+ {
++      if (g_trigger) {
++              free_irq(pfe->hif_irq, g_trigger);
++              eventfd_ctx_put(g_trigger);
++              g_trigger = NULL;
++      }
++
+       pr_info("PFE_CDEV: Device successfully closed\n");
+       return 0;
+ }
++/*
++ * hif_us_isr-
++ * This ISR routine processes Rx/Tx done interrupts from the HIF hardware block
++ */
++static irqreturn_t hif_us_isr(int irq, void *arg)
++{
++      struct eventfd_ctx *trigger = (struct eventfd_ctx *)arg;
++      int int_status;
++      int int_enable_mask;
++
++      /*Read hif interrupt source register */
++      int_status = readl_relaxed(HIF_INT_SRC);
++      int_enable_mask = readl_relaxed(HIF_INT_ENABLE);
++
++      if ((int_status & HIF_INT) == 0)
++              return IRQ_NONE;
++
++      if (int_status & HIF_RXPKT_INT) {
++              int_enable_mask &= ~(HIF_RXPKT_INT);
++              eventfd_signal(trigger, 1);
++      }
++
++      /*Disable interrupts, they will be enabled after they are serviced */
++      writel_relaxed(int_enable_mask, HIF_INT_ENABLE);
++
++      return IRQ_HANDLED;
++}
++
+ static long pfe_cdev_ioctl(struct file *fp, unsigned int cmd,
+                          unsigned long arg)
+ {
+@@ -105,6 +146,22 @@ static long pfe_cdev_ioctl(struct file *
+               pr_debug("Returning state=%d for ETH1\n", *argp);
+               ret = 0;
+               break;
++      case PFE_CDEV_HIF_INTR_EN:
++              /* Return success/failure */
++              g_trigger = eventfd_ctx_fdget(*argp);
++              if (IS_ERR(g_trigger))
++                      return PTR_ERR(g_trigger);
++              ret = request_irq(pfe->hif_irq, hif_us_isr, 0, "pfe_hif",
++                                g_trigger);
++              if (ret) {
++                      pr_err("%s: failed to get the hif IRQ = %d\n",
++                             __func__, pfe->hif_irq);
++                      eventfd_ctx_put(g_trigger);
++                      g_trigger = NULL;
++              }
++              pr_debug("request_irq for hif interrupt: %d\n", pfe->hif_irq);
++              ret = 0;
++              break;
+       default:
+               pr_info("Unsupport cmd (%d) for PFE CDEV.\n", cmd);
+               break;
+--- a/drivers/staging/fsl_ppfe/pfe_cdev.h
++++ b/drivers/staging/fsl_ppfe/pfe_cdev.h
+@@ -43,8 +43,9 @@ struct pfe_shared_info {
+ extern struct pfe_shared_info link_states[PFE_CDEV_ETH_COUNT];
+ /* IOCTL Commands */
+-#define PFE_CDEV_ETH0_STATE_GET       0
+-#define PFE_CDEV_ETH1_STATE_GET       1
++#define PFE_CDEV_ETH0_STATE_GET               _IOR('R', 0, int)
++#define PFE_CDEV_ETH1_STATE_GET               _IOR('R', 1, int)
++#define PFE_CDEV_HIF_INTR_EN          _IOWR('R', 2, int)
+ int pfe_cdev_init(void);
+ void pfe_cdev_exit(void);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0310-staging-fsl_ppfe-performance-tuning-for-user-space.patch b/target/linux/layerscape/patches-5.4/701-net-0310-staging-fsl_ppfe-performance-tuning-for-user-space.patch
new file mode 100644 (file)
index 0000000..8eac290
--- /dev/null
@@ -0,0 +1,47 @@
+From 31fa4aeafa41a38c76085af4de7192c572e85119 Mon Sep 17 00:00:00 2001
+From: Akhil Goyal <akhil.goyal@nxp.com>
+Date: Fri, 20 Jul 2018 16:43:25 +0530
+Subject: [PATCH] staging: fsl_ppfe: performance tuning for user space
+
+interrupt coalescing of 100 usec is added.
+
+Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
+Signed-off-by: Sachin Saxena <sachin.saxena@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_cdev.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_cdev.c
++++ b/drivers/staging/fsl_ppfe/pfe_cdev.c
+@@ -116,15 +116,18 @@ static irqreturn_t hif_us_isr(int irq, v
+       if (int_status & HIF_RXPKT_INT) {
+               int_enable_mask &= ~(HIF_RXPKT_INT);
++              /* Disable interrupts, they will be enabled after
++               * they are serviced
++               */
++              writel_relaxed(int_enable_mask, HIF_INT_ENABLE);
++
+               eventfd_signal(trigger, 1);
+       }
+-      /*Disable interrupts, they will be enabled after they are serviced */
+-      writel_relaxed(int_enable_mask, HIF_INT_ENABLE);
+-
+       return IRQ_HANDLED;
+ }
++#define PFE_INTR_COAL_USECS   100
+ static long pfe_cdev_ioctl(struct file *fp, unsigned int cmd,
+                          unsigned long arg)
+ {
+@@ -159,6 +162,9 @@ static long pfe_cdev_ioctl(struct file *
+                       eventfd_ctx_put(g_trigger);
+                       g_trigger = NULL;
+               }
++              writel((PFE_INTR_COAL_USECS * (pfe->ctrl.sys_clk / 1000)) |
++                      HIF_INT_COAL_ENABLE, HIF_INT_COAL);
++
+               pr_debug("request_irq for hif interrupt: %d\n", pfe->hif_irq);
+               ret = 0;
+               break;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0311-staging-fsl_ppfe-eth-Update-to-use-SPDX-identifiers.patch b/target/linux/layerscape/patches-5.4/701-net-0311-staging-fsl_ppfe-eth-Update-to-use-SPDX-identifiers.patch
new file mode 100644 (file)
index 0000000..139682d
--- /dev/null
@@ -0,0 +1,563 @@
+From 9690960751950583eb80ad9d623c45e974359829 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Tue, 20 Nov 2018 21:50:23 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: Update to use SPDX identifiers
+
+Replace license text with corresponding SPDX identifiers and update the
+format of existing SPDX identifiers to follow the new guideline
+Documentation/process/license-rules.rst.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_cdev.c             | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_cdev.h             | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_ctrl.c             | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_ctrl.h             | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_debugfs.c          | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_debugfs.h          | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_eth.c              | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_eth.h              | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_firmware.c         | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_firmware.h         | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_hal.c              | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_hif.c              | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_hif.h              | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_hif_lib.c          | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_hif_lib.h          | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_hw.c               | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_hw.h               | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_mod.c              | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_mod.h              | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_perfmon.h          | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_sysfs.c            | 14 +-------------
+ drivers/staging/fsl_ppfe/pfe_sysfs.h            | 14 +-------------
+ 23 files changed, 23 insertions(+), 299 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_cdev.c
++++ b/drivers/staging/fsl_ppfe/pfe_cdev.c
+@@ -1,18 +1,6 @@
++// SPDX-License-Identifier: GPL-2.0+
+ /*
+  * Copyright 2018 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ /* @pfe_cdev.c.
+--- a/drivers/staging/fsl_ppfe/pfe_cdev.h
++++ b/drivers/staging/fsl_ppfe/pfe_cdev.h
+@@ -1,18 +1,6 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
+ /*
+  * Copyright 2018 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #ifndef _PFE_CDEV_H_
+--- a/drivers/staging/fsl_ppfe/pfe_ctrl.c
++++ b/drivers/staging/fsl_ppfe/pfe_ctrl.c
+@@ -1,19 +1,7 @@
++// SPDX-License-Identifier: GPL-2.0+
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #include <linux/kernel.h>
+--- a/drivers/staging/fsl_ppfe/pfe_ctrl.h
++++ b/drivers/staging/fsl_ppfe/pfe_ctrl.h
+@@ -1,19 +1,7 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #ifndef _PFE_CTRL_H_
+--- a/drivers/staging/fsl_ppfe/pfe_debugfs.c
++++ b/drivers/staging/fsl_ppfe/pfe_debugfs.c
+@@ -1,19 +1,7 @@
++// SPDX-License-Identifier: GPL-2.0+
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #include <linux/module.h>
+--- a/drivers/staging/fsl_ppfe/pfe_debugfs.h
++++ b/drivers/staging/fsl_ppfe/pfe_debugfs.h
+@@ -1,19 +1,7 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #ifndef _PFE_DEBUGFS_H_
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -1,19 +1,7 @@
++// SPDX-License-Identifier: GPL-2.0+
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ /* @pfe_eth.c.
+--- a/drivers/staging/fsl_ppfe/pfe_eth.h
++++ b/drivers/staging/fsl_ppfe/pfe_eth.h
+@@ -1,19 +1,7 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #ifndef _PFE_ETH_H_
+--- a/drivers/staging/fsl_ppfe/pfe_firmware.c
++++ b/drivers/staging/fsl_ppfe/pfe_firmware.c
+@@ -1,19 +1,7 @@
++// SPDX-License-Identifier: GPL-2.0+
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ /*
+--- a/drivers/staging/fsl_ppfe/pfe_firmware.h
++++ b/drivers/staging/fsl_ppfe/pfe_firmware.h
+@@ -1,19 +1,7 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #ifndef _PFE_FIRMWARE_H_
+--- a/drivers/staging/fsl_ppfe/pfe_hal.c
++++ b/drivers/staging/fsl_ppfe/pfe_hal.c
+@@ -1,19 +1,7 @@
++// SPDX-License-Identifier: GPL-2.0+
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #include "pfe_mod.h"
+--- a/drivers/staging/fsl_ppfe/pfe_hif.c
++++ b/drivers/staging/fsl_ppfe/pfe_hif.c
+@@ -1,19 +1,7 @@
++// SPDX-License-Identifier: GPL-2.0+
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #include <linux/kernel.h>
+--- a/drivers/staging/fsl_ppfe/pfe_hif.h
++++ b/drivers/staging/fsl_ppfe/pfe_hif.h
+@@ -1,19 +1,7 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #ifndef _PFE_HIF_H_
+--- a/drivers/staging/fsl_ppfe/pfe_hif_lib.c
++++ b/drivers/staging/fsl_ppfe/pfe_hif_lib.c
+@@ -1,19 +1,7 @@
++// SPDX-License-Identifier: GPL-2.0+
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #include <linux/version.h>
+--- a/drivers/staging/fsl_ppfe/pfe_hif_lib.h
++++ b/drivers/staging/fsl_ppfe/pfe_hif_lib.h
+@@ -1,19 +1,7 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #ifndef _PFE_HIF_LIB_H_
+--- a/drivers/staging/fsl_ppfe/pfe_hw.c
++++ b/drivers/staging/fsl_ppfe/pfe_hw.c
+@@ -1,19 +1,7 @@
++// SPDX-License-Identifier: GPL-2.0+
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #include "pfe_mod.h"
+--- a/drivers/staging/fsl_ppfe/pfe_hw.h
++++ b/drivers/staging/fsl_ppfe/pfe_hw.h
+@@ -1,19 +1,7 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #ifndef _PFE_HW_H_
+--- a/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
++++ b/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
+@@ -1,19 +1,7 @@
++// SPDX-License-Identifier: GPL-2.0+
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #include <linux/module.h>
+--- a/drivers/staging/fsl_ppfe/pfe_mod.c
++++ b/drivers/staging/fsl_ppfe/pfe_mod.c
+@@ -1,19 +1,7 @@
++// SPDX-License-Identifier: GPL-2.0+
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #include <linux/dma-mapping.h>
+--- a/drivers/staging/fsl_ppfe/pfe_mod.h
++++ b/drivers/staging/fsl_ppfe/pfe_mod.h
+@@ -1,19 +1,7 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #ifndef _PFE_MOD_H_
+--- a/drivers/staging/fsl_ppfe/pfe_perfmon.h
++++ b/drivers/staging/fsl_ppfe/pfe_perfmon.h
+@@ -1,19 +1,7 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #ifndef _PFE_PERFMON_H_
+--- a/drivers/staging/fsl_ppfe/pfe_sysfs.c
++++ b/drivers/staging/fsl_ppfe/pfe_sysfs.c
+@@ -1,19 +1,7 @@
++// SPDX-License-Identifier: GPL-2.0+
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #include <linux/module.h>
+--- a/drivers/staging/fsl_ppfe/pfe_sysfs.h
++++ b/drivers/staging/fsl_ppfe/pfe_sysfs.h
+@@ -1,19 +1,7 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
+ /*
+  * Copyright 2015-2016 Freescale Semiconductor, Inc.
+  * Copyright 2017 NXP
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #ifndef _PFE_SYSFS_H_
diff --git a/target/linux/layerscape/patches-5.4/701-net-0312-staging-fsl_ppfe-eth-misc-clean-up.patch b/target/linux/layerscape/patches-5.4/701-net-0312-staging-fsl_ppfe-eth-misc-clean-up.patch
new file mode 100644 (file)
index 0000000..6f1f7c5
--- /dev/null
@@ -0,0 +1,52 @@
+From 508121cfde12d0e35716bb7e524dc1f80c82262c Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Tue, 20 Nov 2018 21:50:40 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: misc clean up
+
+- remove redundant hwfeature init
+- remove unused vars from ls1012a_eth_platform_data
+- To handle ls1012a errata_a010897, PPFE driver requires GUTS driver
+to be compiled in. Select FSL_GUTS when PPFE driver is compiled.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/Kconfig   | 1 +
+ drivers/staging/fsl_ppfe/pfe_eth.c | 3 ---
+ drivers/staging/fsl_ppfe/pfe_eth.h | 4 ----
+ 3 files changed, 1 insertion(+), 7 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/Kconfig
++++ b/drivers/staging/fsl_ppfe/Kconfig
+@@ -3,6 +3,7 @@
+ #
+ config FSL_PPFE
+       bool "Freescale PPFE Driver"
++      select FSL_GUTS
+       default n
+       ---help---
+       Freescale LS1012A SoC has a Programmable Packet Forwarding Engine.
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -2437,9 +2437,6 @@ static int pfe_eth_init_one(struct pfe *
+       else
+               ndev->max_mtu = JUMBO_FRAME_SIZE_V2 - ETH_HLEN - ETH_FCS_LEN;
+-      /* supported features */
+-      ndev->hw_features = NETIF_F_SG;
+-
+       /*Enable after checksum offload is validated */
+       ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM |
+               NETIF_F_IPV6_CSUM | NETIF_F_SG;
+--- a/drivers/staging/fsl_ppfe/pfe_eth.h
++++ b/drivers/staging/fsl_ppfe/pfe_eth.h
+@@ -37,10 +37,6 @@
+ #define GEMAC_NO_PHY            BIT(0)
+ struct ls1012a_eth_platform_data {
+-      /* device specific information */
+-      u32 device_flags;
+-      char name[16];
+-
+       /* board specific information */
+       u32 mii_config;
+       u32 phy_flags;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0313-staging-fsl_ppfe-eth-reorganize-platform-phy-paramet.patch b/target/linux/layerscape/patches-5.4/701-net-0313-staging-fsl_ppfe-eth-reorganize-platform-phy-paramet.patch
new file mode 100644 (file)
index 0000000..7e4c6ae
--- /dev/null
@@ -0,0 +1,162 @@
+From bb13c3cfaaac3bb50a7f59d0cfa54ff463c2ca86 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Tue, 20 Nov 2018 21:50:51 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: reorganize platform phy parameters
+
+- Use "phy-handle" and of_* functions to get phy node and fixed-link
+parameters
+
+- Reorganize phy parameters and initialize them only if phy-handle
+or fixed-link is defined in the dtb.
+
+- correct typo pfe_get_gemac_if_proprties to pfe_get_gemac_if_properties
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c | 91 ++++++++++++++-----------
+ 1 file changed, 50 insertions(+), 41 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
++++ b/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
+@@ -20,12 +20,12 @@
+ struct ls1012a_pfe_platform_data pfe_platform_data;
+-static int pfe_get_gemac_if_proprties(struct device_node *parent, int port, int
++static int pfe_get_gemac_if_properties(struct device_node *parent, int port, int
+                                       if_cnt,
+                                       struct ls1012a_pfe_platform_data
+                                       *pdata)
+ {
+-      struct device_node *gem = NULL, *phy = NULL;
++      struct device_node *gem = NULL, *phy = NULL, *phy_node = NULL;
+       int size;
+       int ii = 0, phy_id = 0;
+       const u32 *addr;
+@@ -49,18 +49,11 @@ static int pfe_get_gemac_if_proprties(st
+       pdata->ls1012a_eth_pdata[port].gem_id = port;
+       mac_addr = of_get_mac_address(gem);
+-
+       if (mac_addr) {
+               memcpy(pdata->ls1012a_eth_pdata[port].mac_addr, mac_addr,
+                      ETH_ALEN);
+       }
+-      pdata->ls1012a_eth_pdata[port].mii_config = of_get_phy_mode(gem);
+-
+-      if ((pdata->ls1012a_eth_pdata[port].mii_config) < 0)
+-              pr_err("%s:%d Incorrect Phy mode....\n", __func__,
+-                     __LINE__);
+-
+       addr = of_get_property(gem, "fsl,gemac-bus-id", &size);
+       if (!addr)
+               pr_err("%s:%d Invalid gemac-bus-id....\n", __func__,
+@@ -68,16 +61,55 @@ static int pfe_get_gemac_if_proprties(st
+       else
+               pdata->ls1012a_eth_pdata[port].bus_id = be32_to_cpup(addr);
+-      addr = of_get_property(gem, "fsl,gemac-phy-id", &size);
+-      if (!addr) {
+-              pr_err("%s:%d Invalid gemac-phy-id....\n", __func__,
+-                     __LINE__);
++      phy_node = of_parse_phandle(gem, "phy-handle", 0);
++      pdata->ls1012a_eth_pdata[port].phy_node = phy_node;
++      if (phy_node) {
++              goto process_phynode;
++      } else if (of_phy_is_fixed_link(gem)) {
++              if (of_phy_register_fixed_link(gem) < 0) {
++                      pr_err("broken fixed-link specification\n");
++                      goto err;
++              }
++              phy_node = of_node_get(gem);
++              pdata->ls1012a_eth_pdata[port].phy_node = phy_node;
++      } else if (of_get_property(gem, "fsl,pfe-phy-if-flags", &size)) {
++              /* Use old dts properties for phy handling */
++              addr = of_get_property(gem, "fsl,pfe-phy-if-flags", &size);
++              pdata->ls1012a_eth_pdata[port].phy_flags = be32_to_cpup(addr);
++
++              addr = of_get_property(gem, "fsl,gemac-phy-id", &size);
++              if (!addr) {
++                      pr_err("%s:%d Invalid gemac-phy-id....\n", __func__,
++                             __LINE__);
++              } else {
++                      phy_id = be32_to_cpup(addr);
++                      pdata->ls1012a_eth_pdata[port].phy_id = phy_id;
++                      pdata->ls1012a_mdio_pdata[0].phy_mask &= ~(1 << phy_id);
++              }
++
++              /* If PHY is enabled, read mdio properties */
++              if (pdata->ls1012a_eth_pdata[port].phy_flags & GEMAC_NO_PHY)
++                      goto done;
++
++              phy = of_get_next_child(gem, NULL);
++              addr = of_get_property(phy, "reg", &size);
++              if (!addr)
++                      pr_err("%s:%d Invalid phy enable flag....\n",
++                             __func__, __LINE__);
++              else
++                      pdata->ls1012a_mdio_pdata[port].enabled =
++                                                      be32_to_cpup(addr);
+       } else {
+-              phy_id = be32_to_cpup(addr);
+-              pdata->ls1012a_eth_pdata[port].phy_id = phy_id;
+-              pdata->ls1012a_mdio_pdata[0].phy_mask &= ~(1 << phy_id);
++              pr_info("%s: No PHY or fixed-link\n", __func__);
++              return 0;
+       }
++process_phynode:
++      pdata->ls1012a_eth_pdata[port].mii_config = of_get_phy_mode(gem);
++      if ((pdata->ls1012a_eth_pdata[port].mii_config) < 0)
++              pr_err("%s:%d Incorrect Phy mode....\n", __func__,
++                     __LINE__);
++
+       addr = of_get_property(gem, "fsl,mdio-mux-val", &size);
+       if (!addr) {
+               pr_err("%s: Invalid mdio-mux-val....\n", __func__);
+@@ -90,33 +122,10 @@ static int pfe_get_gemac_if_proprties(st
+               pfe->mdio_muxval[pdata->ls1012a_eth_pdata[port].phy_id] =
+                        pdata->ls1012a_eth_pdata[port].mdio_muxval;
+-      addr = of_get_property(gem, "fsl,pfe-phy-if-flags", &size);
+-      if (!addr)
+-              pr_err("%s:%d Invalid pfe-phy-if-flags....\n",
+-                     __func__, __LINE__);
+-      else
+-              pdata->ls1012a_eth_pdata[port].phy_flags = be32_to_cpup(addr);
+-
+-      /* If PHY is enabled, read mdio properties */
+-      if (pdata->ls1012a_eth_pdata[port].phy_flags & GEMAC_NO_PHY)
+-              goto done;
+-
+-      phy = of_get_next_child(gem, NULL);
+-
+-      addr = of_get_property(phy, "reg", &size);
+-
+-      if (!addr)
+-              pr_err("%s:%d Invalid phy enable flag....\n",
+-                     __func__, __LINE__);
+-      else
+-              pdata->ls1012a_mdio_pdata[port].enabled = be32_to_cpup(addr);
+       pdata->ls1012a_mdio_pdata[port].irq[0] = PHY_POLL;
+ done:
+-      if (of_phy_is_fixed_link(gem))
+-              pdata->ls1012a_eth_pdata[port].phy_node = of_node_get(gem);
+-
+       return 0;
+ err:
+@@ -218,8 +227,8 @@ static int pfe_platform_probe(struct pla
+       pfe_platform_data.ls1012a_mdio_pdata[0].phy_mask = 0xffffffff;
+       for (ii = 0; ii < interface_count; ii++) {
+-              pfe_get_gemac_if_proprties(np, ii, interface_count,
+-                                         &pfe_platform_data);
++              pfe_get_gemac_if_properties(np, ii, interface_count,
++                                          &pfe_platform_data);
+       }
+       pfe->dev = &pdev->dev;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0314-staging-fsl_ppfe-eth-support-single-interface-initia.patch b/target/linux/layerscape/patches-5.4/701-net-0314-staging-fsl_ppfe-eth-support-single-interface-initia.patch
new file mode 100644 (file)
index 0000000..4c4cf6c
--- /dev/null
@@ -0,0 +1,271 @@
+From dff5fdd84a9ace2d9b8b56659c0855542829148a Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Fri, 23 Nov 2018 23:58:28 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: support single interface
+ initialization
+
+- arrange members of struct mii_bus in sequence matching phy.h
+- if mdio node is defined, use of_mdiobus_register to register
+  child nodes (phy devices) available on the mdio bus.
+- remove of_phy_register_fixed_link from pfe_phy_init as it is being
+  handled in pfe_get_gemac_if_properties
+- remove mdio enabled check
+- skip phy init, if no PHY or fixed-link
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c              | 110 +++++++++++++-----------
+ drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c |   4 +
+ 2 files changed, 66 insertions(+), 48 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -47,6 +47,7 @@
+ #define LS1012A_REV_1_0               0x87040010
++bool pfe_use_old_dts_phy;
+ bool pfe_errata_a010897;
+ static void *cbus_emac_base[3];
+@@ -950,7 +951,8 @@ static int pfe_eth_mdio_init(struct pfe_
+                            struct ls1012a_mdio_platform_data *minfo)
+ {
+       struct mii_bus *bus;
+-      int rc, ii;
++      struct device_node *mdio_node;
++      int rc = 0, ii;
+       struct phy_device *phydev;
+       netif_info(priv, drv, priv->ndev, "%s\n", __func__);
+@@ -964,25 +966,30 @@ static int pfe_eth_mdio_init(struct pfe_
+       }
+       bus->name = "ls1012a MDIO Bus";
++      snprintf(bus->id, MII_BUS_ID_SIZE, "ls1012a-%x", priv->id);
++
++      bus->priv = priv;
+       bus->read = &pfe_eth_mdio_read;
+       bus->write = &pfe_eth_mdio_write;
+       bus->reset = &pfe_eth_mdio_reset;
+-      snprintf(bus->id, MII_BUS_ID_SIZE, "ls1012a-%x", priv->id);
+-      bus->priv = priv;
+-
++      bus->parent = priv->pfe->dev;
+       bus->phy_mask = minfo->phy_mask;
+-      priv->mdc_div = minfo->mdc_div;
++      bus->irq[0] = minfo->irq[0];
++      priv->mdc_div = minfo->mdc_div;
+       if (!priv->mdc_div)
+               priv->mdc_div = 64;
+-
+-      bus->irq[0] = minfo->irq[0];
+-
+-      bus->parent = priv->pfe->dev;
+-
+       netif_info(priv, drv, priv->ndev, "%s: mdc_div: %d, phy_mask: %x\n",
+                  __func__, priv->mdc_div, bus->phy_mask);
+-      rc = mdiobus_register(bus);
++
++      mdio_node = of_get_child_by_name(priv->pfe->dev->of_node, "mdio");
++      if (mdio_node) {
++              rc = of_mdiobus_register(bus, mdio_node);
++              of_node_put(mdio_node);
++      } else {
++              rc = mdiobus_register(bus);
++      }
++
+       if (rc) {
+               netdev_err(priv->ndev, "mdiobus_register(%s) failed\n",
+                          bus->name);
+@@ -995,7 +1002,6 @@ static int pfe_eth_mdio_init(struct pfe_
+        * 3rd argument as true and then register the phy device
+        * via phy_device_register()
+        */
+-
+       if (priv->einfo->mii_config == PHY_INTERFACE_MODE_2500SGMII) {
+               for (ii = 0; ii < NUM_GEMAC_SUPPORT; ii++) {
+                       phydev = get_phy_device(priv->mii_bus,
+@@ -1268,8 +1274,6 @@ static int pfe_phy_init(struct net_devic
+       char phy_id[MII_BUS_ID_SIZE + 3];
+       char bus_id[MII_BUS_ID_SIZE];
+       phy_interface_t interface;
+-      struct device_node *phy_node;
+-      int rc;
+       priv->oldlink = 0;
+       priv->oldspeed = 0;
+@@ -1278,7 +1282,6 @@ static int pfe_phy_init(struct net_devic
+       snprintf(bus_id, MII_BUS_ID_SIZE, "ls1012a-%d", 0);
+       snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
+                priv->einfo->phy_id);
+-
+       netif_info(priv, drv, ndev, "%s: %s\n", __func__, phy_id);
+       interface = priv->einfo->mii_config;
+       if ((interface == PHY_INTERFACE_MODE_SGMII) ||
+@@ -1301,23 +1304,22 @@ static int pfe_phy_init(struct net_devic
+       priv->oldduplex = -1;
+       pr_info("%s interface %x\n", __func__, interface);
+-      if (of_phy_is_fixed_link(priv->phy_node)) {
+-              rc = of_phy_register_fixed_link(priv->phy_node);
+-              if (rc)
+-                      return rc;
+-              phy_node = of_node_get(priv->phy_node);
+-              phydev = of_phy_connect(ndev, phy_node, pfe_eth_adjust_link, 0,
++      if (priv->phy_node) {
++              phydev = of_phy_connect(ndev, priv->phy_node,
++                                      pfe_eth_adjust_link, 0,
+                                       priv->einfo->mii_config);
+-              of_node_put(phy_node);
++              if (!(phydev)) {
++                      netdev_err(ndev, "Unable to connect to phy\n");
++                      return -ENODEV;
++              }
+       } else {
+               phydev = phy_connect(ndev, phy_id,
+                                    &pfe_eth_adjust_link, interface);
+-      }
+-
+-      if (IS_ERR(phydev)) {
+-              netdev_err(ndev, "phy_connect() failed\n");
+-              return PTR_ERR(phydev);
++              if (IS_ERR(phydev)) {
++                      netdev_err(ndev, "Unable to connect to phy\n");
++                      return PTR_ERR(phydev);
++              }
+       }
+       priv->phydev = phydev;
+@@ -2411,13 +2413,10 @@ static int pfe_eth_init_one(struct pfe *
+       memcpy(ndev->dev_addr, einfo[id].mac_addr, ETH_ALEN);
+       /* Initialize mdio */
+-      if (minfo[id].enabled) {
+-              err = pfe_eth_mdio_init(priv, &minfo[id]);
+-              if (err) {
+-                      netdev_err(ndev, "%s: pfe_eth_mdio_init() failed\n",
+-                                 __func__);
+-                      goto err2;
+-              }
++      err = pfe_eth_mdio_init(priv, &minfo[id]);
++      if (err) {
++              netdev_err(ndev, "%s: pfe_eth_mdio_init() failed\n", __func__);
++              goto err1;
+       }
+       if (us)
+@@ -2462,22 +2461,26 @@ static int pfe_eth_init_one(struct pfe *
+                      HIF_RX_POLL_WEIGHT - 16);
+       err = register_netdev(ndev);
+-
+       if (err) {
+               netdev_err(ndev, "register_netdev() failed\n");
+-              goto err3;
++              goto err2;
++      }
++
++      if ((!(pfe_use_old_dts_phy) && !(priv->phy_node)) ||
++          ((pfe_use_old_dts_phy) &&
++            (priv->einfo->phy_flags & GEMAC_NO_PHY))) {
++              pr_info("%s: No PHY or fixed-link\n", __func__);
++              goto skip_phy_init;
+       }
+ phy_init:
+       device_init_wakeup(&ndev->dev, WAKE_MAGIC);
+-      if (!(priv->einfo->phy_flags & GEMAC_NO_PHY)) {
+-              err = pfe_phy_init(ndev);
+-              if (err) {
+-                      netdev_err(ndev, "%s: pfe_phy_init() failed\n",
+-                                 __func__);
+-                      goto err4;
+-              }
++      err = pfe_phy_init(ndev);
++      if (err) {
++              netdev_err(ndev, "%s: pfe_phy_init() failed\n",
++                         __func__);
++              goto err3;
+       }
+       if (us) {
+@@ -2488,6 +2491,7 @@ phy_init:
+       netif_carrier_on(ndev);
++skip_phy_init:
+       /* Create all the sysfs files */
+       if (pfe_eth_sysfs_init(ndev))
+               goto err4;
+@@ -2496,13 +2500,16 @@ phy_init:
+                  __func__, priv->EMAC_baseaddr);
+       return 0;
++
+ err4:
++      pfe_phy_exit(priv->ndev);
++err3:
+       if (us)
+-              goto err3;
++              goto err2;
+       unregister_netdev(ndev);
+-err3:
+-      pfe_eth_mdio_exit(priv->mii_bus);
+ err2:
++      pfe_eth_mdio_exit(priv->mii_bus);
++err1:
+       free_netdev(priv->ndev);
+ err0:
+       return err;
+@@ -2553,9 +2560,16 @@ static void pfe_eth_exit_one(struct pfe_
+       if (!us)
+               pfe_eth_sysfs_exit(priv->ndev);
+-      if (!(priv->einfo->phy_flags & GEMAC_NO_PHY))
+-              pfe_phy_exit(priv->ndev);
++      if ((!(pfe_use_old_dts_phy) && !(priv->phy_node)) ||
++          ((pfe_use_old_dts_phy) &&
++            (priv->einfo->phy_flags & GEMAC_NO_PHY))) {
++              pr_info("%s: No PHY or fixed-link\n", __func__);
++              goto skip_phy_exit;
++      }
++
++      pfe_phy_exit(priv->ndev);
++skip_phy_exit:
+       if (!us)
+               unregister_netdev(priv->ndev);
+--- a/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
++++ b/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
+@@ -18,6 +18,7 @@
+ #include "pfe_mod.h"
++extern bool pfe_use_old_dts_phy;
+ struct ls1012a_pfe_platform_data pfe_platform_data;
+ static int pfe_get_gemac_if_properties(struct device_node *parent, int port, int
+@@ -64,8 +65,10 @@ static int pfe_get_gemac_if_properties(s
+       phy_node = of_parse_phandle(gem, "phy-handle", 0);
+       pdata->ls1012a_eth_pdata[port].phy_node = phy_node;
+       if (phy_node) {
++              pfe_use_old_dts_phy = false;
+               goto process_phynode;
+       } else if (of_phy_is_fixed_link(gem)) {
++              pfe_use_old_dts_phy = false;
+               if (of_phy_register_fixed_link(gem) < 0) {
+                       pr_err("broken fixed-link specification\n");
+                       goto err;
+@@ -73,6 +76,7 @@ static int pfe_get_gemac_if_properties(s
+               phy_node = of_node_get(gem);
+               pdata->ls1012a_eth_pdata[port].phy_node = phy_node;
+       } else if (of_get_property(gem, "fsl,pfe-phy-if-flags", &size)) {
++              pfe_use_old_dts_phy = true;
+               /* Use old dts properties for phy handling */
+               addr = of_get_property(gem, "fsl,pfe-phy-if-flags", &size);
+               pdata->ls1012a_eth_pdata[port].phy_flags = be32_to_cpup(addr);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0315-net-fsl_ppfe-update-dts-properties-for-phy.patch b/target/linux/layerscape/patches-5.4/701-net-0315-net-fsl_ppfe-update-dts-properties-for-phy.patch
new file mode 100644 (file)
index 0000000..6c74496
--- /dev/null
@@ -0,0 +1,101 @@
+From 153d669864c9280698641a6708c5ddcffbfeda26 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Tue, 20 Nov 2018 21:51:53 +0530
+Subject: [PATCH] net: fsl_ppfe: update dts properties for phy
+
+Use commonly used phy-handle property and mdio subnode to handle
+phy properties.
+
+Deprecate bindings fsl,gemac-phy-id & fsl,pfe-phy-if-flags.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ .../devicetree/bindings/net/fsl_ppfe/pfe.txt       | 60 ++++++++++++++++------
+ 1 file changed, 43 insertions(+), 17 deletions(-)
+
+--- a/Documentation/devicetree/bindings/net/fsl_ppfe/pfe.txt
++++ b/Documentation/devicetree/bindings/net/fsl_ppfe/pfe.txt
+@@ -127,11 +127,12 @@ PROPERTIES
+               Definition: Must be present. Value should be the id of the bus
+               connected to gemac.
+-- fsl,gemac-phy-id
+-              Usage: required
+-              Value type: <u32>
+-              Definition: Must be present. Value should be the id of the phy
+-              connected to gemac.
++- fsl,gemac-phy-id (deprecated binding)
++               Usage: required
++               Value type: <u32>
++               Definition: This binding shouldn't be used with new platforms.
++             Must be present. Value should be the id of the phy
++               connected to gemac.
+ - fsl,mdio-mux-val
+               Usage: required
+@@ -144,15 +145,20 @@ PROPERTIES
+               Value type: <string>
+               Definition: Must include "sgmii"
+-- fsl,pfe-phy-if-flags
+-              Usage: required
+-              Value type: <u32>
+-              Definition: Must be present. Value should be 0 by default.
+-              If there is not phy connected, this need to be 1.
++- fsl,pfe-phy-if-flags (deprecated binding)
++               Usage: required
++               Value type: <u32>
++               Definition: This binding shouldn't be used with new platforms.
++               Must be present. Value should be 0 by default.
++               If there is not phy connected, this need to be 1.
++
++- phy-handle
++              Usage: optional
++              Value type: <phandle>
++              Definition: phandle to the PHY device connected to this device.
+-- mdio
+-              optional subnode that specifies the mdio bus. This has reg
+-              property which is used to enable/disable the mdio bus.
++- mdio : A required subnode which specifies the mdio bus in the PFE and used as
++a container for phy nodes according to ../phy.txt.
+ EXAMPLE
+@@ -162,12 +168,32 @@ ethernet@0 {
+       #size-cells = <0>;
+       reg = <0x0>;    /* GEM_ID */
+       fsl,gemac-bus-id = <0x0>;       /* BUS_ID */
+-      fsl,gemac-phy-id = <0x2>;       /* PHY_ID */
+       fsl,mdio-mux-val = <0x0>;
+       phy-mode = "sgmii";
+-      fsl,pfe-phy-if-flags = <0x0>;
++      phy-handle = <&sgmii_phy1>;
++};
++
++
++ethernet@1 {
++      compatible = "fsl,pfe-gemac-port";
++      #address-cells = <1>;
++      #size-cells = <0>;
++      reg = <0x1>;    /* GEM_ID */
++      fsl,gemac-bus-id = <0x1>;       /* BUS_ID */
++      fsl,mdio-mux-val = <0x0>;
++      phy-mode = "sgmii";
++      phy-handle = <&sgmii_phy2>;
++};
++
++mdio@0 {
++      #address-cells = <1>;
++      #size-cells = <0>;
++
++      sgmii_phy1: ethernet-phy@2 {
++              reg = <0x2>;
++      };
+-      mdio@0 {
+-              reg = <0x1>; /* enabled/disabled */
++      sgmii_phy2: ethernet-phy@1 {
++              reg = <0x1>;
+       };
+ };
diff --git a/target/linux/layerscape/patches-5.4/701-net-0316-staging-fsl_ppfe-eth-remove-unused-code.patch b/target/linux/layerscape/patches-5.4/701-net-0316-staging-fsl_ppfe-eth-remove-unused-code.patch
new file mode 100644 (file)
index 0000000..f1f2483
--- /dev/null
@@ -0,0 +1,51 @@
+From 4fa4a610e4c37741aa1d7763762f2231e4ca1d1d Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Fri, 7 Dec 2018 19:30:03 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: remove unused code
+
+- remove gemac-bus-id related code that is unused.
+- remove unused prototype gemac_set_mdc_div.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/include/pfe/pfe.h      | 1 -
+ drivers/staging/fsl_ppfe/pfe_eth.h              | 1 -
+ drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c | 7 -------
+ 3 files changed, 9 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/include/pfe/pfe.h
++++ b/drivers/staging/fsl_ppfe/include/pfe/pfe.h
+@@ -268,7 +268,6 @@ enum mac_loop {LB_NONE, LB_EXT, LB_LOCAL
+ void gemac_init(void *base, void *config);
+ void gemac_disable_rx_checksum_offload(void *base);
+ void gemac_enable_rx_checksum_offload(void *base);
+-void gemac_set_mdc_div(void *base, int mdc_div);
+ void gemac_set_speed(void *base, enum mac_speed gem_speed);
+ void gemac_set_duplex(void *base, int duplex);
+ void gemac_set_mode(void *base, int mode);
+--- a/drivers/staging/fsl_ppfe/pfe_eth.h
++++ b/drivers/staging/fsl_ppfe/pfe_eth.h
+@@ -41,7 +41,6 @@ struct ls1012a_eth_platform_data {
+       u32 mii_config;
+       u32 phy_flags;
+       u32 gem_id;
+-      u32 bus_id;
+       u32 phy_id;
+       u32 mdio_muxval;
+       u8 mac_addr[ETH_ALEN];
+--- a/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
++++ b/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
+@@ -55,13 +55,6 @@ static int pfe_get_gemac_if_properties(s
+                      ETH_ALEN);
+       }
+-      addr = of_get_property(gem, "fsl,gemac-bus-id", &size);
+-      if (!addr)
+-              pr_err("%s:%d Invalid gemac-bus-id....\n", __func__,
+-                     __LINE__);
+-      else
+-              pdata->ls1012a_eth_pdata[port].bus_id = be32_to_cpup(addr);
+-
+       phy_node = of_parse_phandle(gem, "phy-handle", 0);
+       pdata->ls1012a_eth_pdata[port].phy_node = phy_node;
+       if (phy_node) {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0317-staging-fsl_ppfe-eth-separate-mdio-init-from-mac-ini.patch b/target/linux/layerscape/patches-5.4/701-net-0317-staging-fsl_ppfe-eth-separate-mdio-init-from-mac-ini.patch
new file mode 100644 (file)
index 0000000..fbf13c8
--- /dev/null
@@ -0,0 +1,651 @@
+From 8848f975ce42674b8bc8dedb5c7b326a42088e99 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Mon, 10 Dec 2018 10:22:33 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: separate mdio init from mac init
+
+- separate mdio initialization from mac initialization
+- Define pfe_mdio_priv_s structure to hold mii_bus structure and other
+  related data.
+- Modify functions to work with the separted mdio init model.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c              | 232 ++++++++++--------------
+ drivers/staging/fsl_ppfe/pfe_eth.h              |  17 +-
+ drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c |  50 ++---
+ drivers/staging/fsl_ppfe/pfe_mod.h              |   1 +
+ 4 files changed, 126 insertions(+), 174 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -790,10 +790,9 @@ const struct ethtool_ops pfe_ethtool_ops
+  */
+ int pfe_eth_mdio_reset(struct mii_bus *bus)
+ {
+-      struct pfe_eth_priv_s *priv = (struct pfe_eth_priv_s *)bus->priv;
++      struct pfe_mdio_priv_s *priv = (struct pfe_mdio_priv_s *)bus->priv;
+       u32 phy_speed;
+-      netif_info(priv, hw, priv->ndev, "%s\n", __func__);
+       mutex_lock(&bus->mdio_lock);
+@@ -806,25 +805,25 @@ int pfe_eth_mdio_reset(struct mii_bus *b
+       phy_speed = (DIV_ROUND_UP((pfe->ctrl.sys_clk * 1000), 4000000)
+                    << EMAC_MII_SPEED_SHIFT);
+       phy_speed |= EMAC_HOLDTIME(0x5);
+-      __raw_writel(phy_speed, priv->PHY_baseaddr + EMAC_MII_CTRL_REG);
++      __raw_writel(phy_speed, priv->mdio_base + EMAC_MII_CTRL_REG);
+       mutex_unlock(&bus->mdio_lock);
+       return 0;
+ }
+-/* pfe_eth_gemac_phy_timeout
++/* pfe_eth_mdio_timeout
+  *
+  */
+-static int pfe_eth_gemac_phy_timeout(struct pfe_eth_priv_s *priv, int timeout)
++static int pfe_eth_mdio_timeout(struct pfe_mdio_priv_s *priv, int timeout)
+ {
+-      while (!(__raw_readl(priv->PHY_baseaddr + EMAC_IEVENT_REG) &
++      while (!(__raw_readl(priv->mdio_base + EMAC_IEVENT_REG) &
+                       EMAC_IEVENT_MII)) {
+               if (timeout-- <= 0)
+                       return -1;
+               usleep_range(10, 20);
+       }
+-      __raw_writel(EMAC_IEVENT_MII, priv->PHY_baseaddr + EMAC_IEVENT_REG);
++      __raw_writel(EMAC_IEVENT_MII, priv->mdio_base + EMAC_IEVENT_REG);
+       return 0;
+ }
+@@ -856,16 +855,15 @@ static int pfe_eth_mdio_mux(u8 muxval)
+ static int pfe_eth_mdio_write_addr(struct mii_bus *bus, int mii_id,
+                                  int dev_addr, int regnum)
+ {
+-      struct pfe_eth_priv_s *priv = (struct pfe_eth_priv_s *)bus->priv;
++      struct pfe_mdio_priv_s *priv = (struct pfe_mdio_priv_s *)bus->priv;
+       __raw_writel(EMAC_MII_DATA_PA(mii_id) |
+                    EMAC_MII_DATA_RA(dev_addr) |
+                    EMAC_MII_DATA_TA | EMAC_MII_DATA(regnum),
+-                   priv->PHY_baseaddr + EMAC_MII_DATA_REG);
++                   priv->mdio_base + EMAC_MII_DATA_REG);
+-      if (pfe_eth_gemac_phy_timeout(priv, EMAC_MDIO_TIMEOUT)) {
+-              netdev_err(priv->ndev, "%s: phy MDIO address write timeout\n",
+-                         __func__);
++      if (pfe_eth_mdio_timeout(priv, EMAC_MDIO_TIMEOUT)) {
++              dev_err(&bus->dev, "phy MDIO address write timeout\n");
+               return -1;
+       }
+@@ -875,7 +873,7 @@ static int pfe_eth_mdio_write_addr(struc
+ static int pfe_eth_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+                             u16 value)
+ {
+-      struct pfe_eth_priv_s *priv = (struct pfe_eth_priv_s *)bus->priv;
++      struct pfe_mdio_priv_s *priv = (struct pfe_mdio_priv_s *)bus->priv;
+       /*To access external PHYs on QDS board mux needs to be configured*/
+       if ((mii_id) && (pfe->mdio_muxval[mii_id]))
+@@ -888,30 +886,26 @@ static int pfe_eth_mdio_write(struct mii
+                            EMAC_MII_DATA_PA(mii_id) |
+                            EMAC_MII_DATA_RA((regnum >> 16) & 0x1f) |
+                            EMAC_MII_DATA_TA | EMAC_MII_DATA(value),
+-                           priv->PHY_baseaddr + EMAC_MII_DATA_REG);
++                           priv->mdio_base + EMAC_MII_DATA_REG);
+       } else {
+               /* start a write op */
+               __raw_writel(EMAC_MII_DATA_ST | EMAC_MII_DATA_OP_WR |
+                            EMAC_MII_DATA_PA(mii_id) |
+                            EMAC_MII_DATA_RA(regnum) |
+                            EMAC_MII_DATA_TA | EMAC_MII_DATA(value),
+-                           priv->PHY_baseaddr + EMAC_MII_DATA_REG);
++                           priv->mdio_base + EMAC_MII_DATA_REG);
+       }
+-      if (pfe_eth_gemac_phy_timeout(priv, EMAC_MDIO_TIMEOUT)) {
+-              netdev_err(priv->ndev, "%s: phy MDIO write timeout\n",
+-                         __func__);
++      if (pfe_eth_mdio_timeout(priv, EMAC_MDIO_TIMEOUT)) {
++              dev_err(&bus->dev, "%s: phy MDIO write timeout\n", __func__);
+               return -1;
+       }
+-      netif_info(priv, hw, priv->ndev, "%s: phy %x reg %x val %x\n", __func__,
+-                 mii_id, regnum, value);
+-
+       return 0;
+ }
+ static int pfe_eth_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+ {
+-      struct pfe_eth_priv_s *priv = (struct pfe_eth_priv_s *)bus->priv;
++      struct pfe_mdio_priv_s *priv = (struct pfe_mdio_priv_s *)bus->priv;
+       u16 value = 0;
+       /*To access external PHYs on QDS board mux needs to be configured*/
+@@ -925,65 +919,67 @@ static int pfe_eth_mdio_read(struct mii_
+                            EMAC_MII_DATA_PA(mii_id) |
+                            EMAC_MII_DATA_RA((regnum >> 16) & 0x1f) |
+                            EMAC_MII_DATA_TA,
+-                           priv->PHY_baseaddr + EMAC_MII_DATA_REG);
++                           priv->mdio_base + EMAC_MII_DATA_REG);
+       } else {
+               /* start a read op */
+               __raw_writel(EMAC_MII_DATA_ST | EMAC_MII_DATA_OP_RD |
+                            EMAC_MII_DATA_PA(mii_id) |
+                            EMAC_MII_DATA_RA(regnum) |
+-                           EMAC_MII_DATA_TA, priv->PHY_baseaddr +
++                           EMAC_MII_DATA_TA, priv->mdio_base +
+                            EMAC_MII_DATA_REG);
+       }
+-      if (pfe_eth_gemac_phy_timeout(priv, EMAC_MDIO_TIMEOUT)) {
+-              netdev_err(priv->ndev, "%s: phy MDIO read timeout\n", __func__);
++      if (pfe_eth_mdio_timeout(priv, EMAC_MDIO_TIMEOUT)) {
++              dev_err(&bus->dev, "%s: phy MDIO read timeout\n", __func__);
+               return -1;
+       }
+-      value = EMAC_MII_DATA(__raw_readl(priv->PHY_baseaddr +
++      value = EMAC_MII_DATA(__raw_readl(priv->mdio_base +
+                                               EMAC_MII_DATA_REG));
+-      netif_info(priv, hw, priv->ndev, "%s: phy %x reg %x val %x\n", __func__,
+-                 mii_id, regnum, value);
+       return value;
+ }
+-static int pfe_eth_mdio_init(struct pfe_eth_priv_s *priv,
+-                           struct ls1012a_mdio_platform_data *minfo)
++static int pfe_eth_mdio_init(struct pfe *pfe,
++                           struct ls1012a_pfe_platform_data *pfe_info,
++                           int ii)
+ {
++      struct pfe_mdio_priv_s *priv = NULL;
++      struct ls1012a_mdio_platform_data *mdio_info;
+       struct mii_bus *bus;
+       struct device_node *mdio_node;
+-      int rc = 0, ii;
+-      struct phy_device *phydev;
++      int rc = 0;
+-      netif_info(priv, drv, priv->ndev, "%s\n", __func__);
+-      pr_info("%s\n", __func__);
++      mdio_info = (struct ls1012a_mdio_platform_data *)
++                                      pfe_info->ls1012a_mdio_pdata;
++      mdio_info->id = ii;
+-      bus = mdiobus_alloc();
++      bus = mdiobus_alloc_size(sizeof(struct pfe_mdio_priv_s));
+       if (!bus) {
+-              netdev_err(priv->ndev, "mdiobus_alloc() failed\n");
++              pr_err("mdiobus_alloc() failed\n");
+               rc = -ENOMEM;
+-              goto err0;
++              goto err_mdioalloc;
+       }
+       bus->name = "ls1012a MDIO Bus";
+-      snprintf(bus->id, MII_BUS_ID_SIZE, "ls1012a-%x", priv->id);
++      snprintf(bus->id, MII_BUS_ID_SIZE, "ls1012a-%x", mdio_info->id);
+-      bus->priv = priv;
+       bus->read = &pfe_eth_mdio_read;
+       bus->write = &pfe_eth_mdio_write;
+       bus->reset = &pfe_eth_mdio_reset;
+-      bus->parent = priv->pfe->dev;
+-      bus->phy_mask = minfo->phy_mask;
+-      bus->irq[0] = minfo->irq[0];
++      bus->parent = pfe->dev;
++      bus->phy_mask = mdio_info->phy_mask;
++      bus->irq[0] = mdio_info->irq[0];
++      priv = bus->priv;
++      priv->mdio_base = cbus_emac_base[ii];
+-      priv->mdc_div = minfo->mdc_div;
++      priv->mdc_div = mdio_info->mdc_div;
+       if (!priv->mdc_div)
+               priv->mdc_div = 64;
+-      netif_info(priv, drv, priv->ndev, "%s: mdc_div: %d, phy_mask: %x\n",
+-                 __func__, priv->mdc_div, bus->phy_mask);
++              dev_info(bus->parent, "%s: mdc_div: %d, phy_mask: %x\n",
++                       __func__, priv->mdc_div, bus->phy_mask);
+-      mdio_node = of_get_child_by_name(priv->pfe->dev->of_node, "mdio");
+-      if (mdio_node) {
++      mdio_node = of_get_child_by_name(pfe->dev->of_node, "mdio");
++      if ((mdio_info->id == 0) && mdio_node) {
+               rc = of_mdiobus_register(bus, mdio_node);
+               of_node_put(mdio_node);
+       } else {
+@@ -991,56 +987,34 @@ static int pfe_eth_mdio_init(struct pfe_
+       }
+       if (rc) {
+-              netdev_err(priv->ndev, "mdiobus_register(%s) failed\n",
+-                         bus->name);
+-              goto err1;
++              dev_err(bus->parent, "mdiobus_register(%s) failed\n",
++                      bus->name);
++              goto err_mdioregister;
+       }
+       priv->mii_bus = bus;
+-
+-      /* For clause 45 we need to call get_phy_device() with it's
+-       * 3rd argument as true and then register the phy device
+-       * via phy_device_register()
+-       */
+-      if (priv->einfo->mii_config == PHY_INTERFACE_MODE_2500SGMII) {
+-              for (ii = 0; ii < NUM_GEMAC_SUPPORT; ii++) {
+-                      phydev = get_phy_device(priv->mii_bus,
+-                                      priv->einfo->phy_id + ii, true);
+-                      if (!phydev || IS_ERR(phydev)) {
+-                              rc = -EIO;
+-                              netdev_err(priv->ndev, "fail to get device\n");
+-                              goto err1;
+-                      }
+-                      rc = phy_device_register(phydev);
+-                      if (rc) {
+-                              phy_device_free(phydev);
+-                              netdev_err(priv->ndev,
+-                                      "phy_device_register() failed\n");
+-                              goto err1;
+-                      }
+-              }
+-      }
++      pfe->mdio.mdio_priv[ii] = priv;
+       pfe_eth_mdio_reset(bus);
+       return 0;
+-err1:
++err_mdioregister:
+       mdiobus_free(bus);
+-err0:
++err_mdioalloc:
+       return rc;
+ }
+ /* pfe_eth_mdio_exit
+  */
+-static void pfe_eth_mdio_exit(struct mii_bus *bus)
++static void pfe_eth_mdio_exit(struct pfe *pfe,
++                            int ii)
+ {
++      struct pfe_mdio_priv_s *mdio_priv = pfe->mdio.mdio_priv[ii];
++      struct mii_bus *bus = mdio_priv->mii_bus;
++
+       if (!bus)
+               return;
+-
+-      netif_info((struct pfe_eth_priv_s *)bus->priv, drv, ((struct
+-                      pfe_eth_priv_s *)(bus->priv))->ndev, "%s\n", __func__);
+-
+       mdiobus_unregister(bus);
+       mdiobus_free(bus);
+ }
+@@ -1221,15 +1195,16 @@ static int pfe_eth_start(struct pfe_eth_
+  */
+ static void ls1012a_configure_serdes(struct net_device *ndev)
+ {
+-      struct pfe_eth_priv_s *priv = pfe->eth.eth_priv[0];
++      struct pfe_eth_priv_s *eth_priv = netdev_priv(ndev);
++      struct pfe_mdio_priv_s *mdio_priv = pfe->mdio.mdio_priv[eth_priv->id];
+       int sgmii_2500 = 0;
+-      struct mii_bus *bus = priv->mii_bus;
++      struct mii_bus *bus = mdio_priv->mii_bus;
+       u16 value = 0;
+-      if (priv->einfo->mii_config == PHY_INTERFACE_MODE_2500SGMII)
++      if (eth_priv->einfo->mii_config == PHY_INTERFACE_MODE_2500SGMII)
+               sgmii_2500 = 1;
+-      netif_info(priv, drv, ndev, "%s\n", __func__);
++      netif_info(eth_priv, drv, ndev, "%s\n", __func__);
+       /* PCS configuration done with corresponding GEMAC */
+       pfe_eth_mdio_read(bus, 0, MDIO_SGMII_CR);
+@@ -2333,26 +2308,15 @@ static const struct net_device_ops pfe_n
+ /* pfe_eth_init_one
+  */
+-static int pfe_eth_init_one(struct pfe *pfe, int id)
++static int pfe_eth_init_one(struct pfe *pfe,
++                          struct ls1012a_pfe_platform_data *pfe_info,
++                          int id)
+ {
+       struct net_device *ndev = NULL;
+       struct pfe_eth_priv_s *priv = NULL;
+       struct ls1012a_eth_platform_data *einfo;
+-      struct ls1012a_mdio_platform_data *minfo;
+-      struct ls1012a_pfe_platform_data *pfe_info;
+       int err;
+-      /* Extract pltform data */
+-      pfe_info = (struct ls1012a_pfe_platform_data *)
+-                                      pfe->dev->platform_data;
+-      if (!pfe_info) {
+-              pr_err(
+-                      "%s: pfe missing additional platform data\n"
+-                      , __func__);
+-              err = -ENODEV;
+-              goto err0;
+-      }
+-
+       einfo = (struct ls1012a_eth_platform_data *)
+                               pfe_info->ls1012a_eth_pdata;
+@@ -2365,18 +2329,6 @@ static int pfe_eth_init_one(struct pfe *
+               goto err0;
+       }
+-      minfo = (struct ls1012a_mdio_platform_data *)
+-                              pfe_info->ls1012a_mdio_pdata;
+-
+-      /* einfo never be NULL, but no harm in having this check */
+-      if (!minfo) {
+-              pr_err(
+-                      "%s: pfe missing additional mdios platform data\n",
+-                       __func__);
+-              err = -ENODEV;
+-              goto err0;
+-      }
+-
+       if (us)
+               emac_txq_cnt = EMAC_TXQ_CNT;
+       /* Create an ethernet device instance */
+@@ -2402,7 +2354,6 @@ static int pfe_eth_init_one(struct pfe *
+       /* Set the info in the priv to the current info */
+       priv->einfo = &einfo[id];
+       priv->EMAC_baseaddr = cbus_emac_base[id];
+-      priv->PHY_baseaddr = cbus_emac_base[0];
+       priv->GPI_baseaddr = cbus_gpi_base[id];
+       spin_lock_init(&priv->lock);
+@@ -2412,13 +2363,6 @@ static int pfe_eth_init_one(struct pfe *
+       /* Copy the station address into the dev structure, */
+       memcpy(ndev->dev_addr, einfo[id].mac_addr, ETH_ALEN);
+-      /* Initialize mdio */
+-      err = pfe_eth_mdio_init(priv, &minfo[id]);
+-      if (err) {
+-              netdev_err(ndev, "%s: pfe_eth_mdio_init() failed\n", __func__);
+-              goto err1;
+-      }
+-
+       if (us)
+               goto phy_init;
+@@ -2463,7 +2407,7 @@ static int pfe_eth_init_one(struct pfe *
+       err = register_netdev(ndev);
+       if (err) {
+               netdev_err(ndev, "register_netdev() failed\n");
+-              goto err2;
++              goto err1;
+       }
+       if ((!(pfe_use_old_dts_phy) && !(priv->phy_node)) ||
+@@ -2480,7 +2424,7 @@ phy_init:
+       if (err) {
+               netdev_err(ndev, "%s: pfe_phy_init() failed\n",
+                          __func__);
+-              goto err3;
++              goto err2;
+       }
+       if (us) {
+@@ -2494,21 +2438,19 @@ phy_init:
+ skip_phy_init:
+       /* Create all the sysfs files */
+       if (pfe_eth_sysfs_init(ndev))
+-              goto err4;
++              goto err3;
+       netif_info(priv, probe, ndev, "%s: created interface, baseaddr: %p\n",
+                  __func__, priv->EMAC_baseaddr);
+       return 0;
+-err4:
+-      pfe_phy_exit(priv->ndev);
+ err3:
++      pfe_phy_exit(priv->ndev);
++err2:
+       if (us)
+-              goto err2;
++              goto err1;
+       unregister_netdev(ndev);
+-err2:
+-      pfe_eth_mdio_exit(priv->mii_bus);
+ err1:
+       free_netdev(priv->ndev);
+ err0:
+@@ -2521,6 +2463,7 @@ int pfe_eth_init(struct pfe *pfe)
+ {
+       int ii = 0;
+       int err;
++      struct ls1012a_pfe_platform_data *pfe_info;
+       pr_info("%s\n", __func__);
+@@ -2530,24 +2473,43 @@ int pfe_eth_init(struct pfe *pfe)
+       cbus_gpi_base[0] = EGPI1_BASE_ADDR;
+       cbus_gpi_base[1] = EGPI2_BASE_ADDR;
++      pfe_info = (struct ls1012a_pfe_platform_data *)
++                                      pfe->dev->platform_data;
++      if (!pfe_info) {
++              pr_err("%s: pfe missing additional platform data\n", __func__);
++              err = -ENODEV;
++              goto err_pdata;
++      }
++
++      for (ii = 0; ii < NUM_GEMAC_SUPPORT; ii++) {
++              err = pfe_eth_mdio_init(pfe, pfe_info, ii);
++              if (err) {
++                      pr_err("%s: pfe_eth_mdio_init() failed\n", __func__);
++                      goto err_mdio_init;
++              }
++      }
++
+       if (fsl_guts_get_svr() == LS1012A_REV_1_0)
+               pfe_errata_a010897 = true;
+       else
+               pfe_errata_a010897 = false;
+       for (ii = 0; ii < NUM_GEMAC_SUPPORT; ii++) {
+-              err = pfe_eth_init_one(pfe, ii);
++              err = pfe_eth_init_one(pfe, pfe_info, ii);
+               if (err)
+-                      goto err0;
++                      goto err_eth_init;
+       }
+       return 0;
+-err0:
+-      while (ii--)
++err_eth_init:
++      while (ii--) {
+               pfe_eth_exit_one(pfe->eth.eth_priv[ii]);
++              pfe_eth_mdio_exit(pfe, ii);
++      }
+-      /* Register three network devices in the kernel */
++err_mdio_init:
++err_pdata:
+       return err;
+ }
+@@ -2573,9 +2535,6 @@ skip_phy_exit:
+       if (!us)
+               unregister_netdev(priv->ndev);
+-      if (priv->mii_bus)
+-              pfe_eth_mdio_exit(priv->mii_bus);
+-
+       free_netdev(priv->ndev);
+ }
+@@ -2589,4 +2548,7 @@ void pfe_eth_exit(struct pfe *pfe)
+       for (ii = NUM_GEMAC_SUPPORT - 1; ii >= 0; ii--)
+               pfe_eth_exit_one(pfe->eth.eth_priv[ii]);
++
++      for (ii = NUM_GEMAC_SUPPORT - 1; ii >= 0; ii--)
++              pfe_eth_mdio_exit(pfe, ii);
+ }
+--- a/drivers/staging/fsl_ppfe/pfe_eth.h
++++ b/drivers/staging/fsl_ppfe/pfe_eth.h
+@@ -48,7 +48,7 @@ struct ls1012a_eth_platform_data {
+ };
+ struct ls1012a_mdio_platform_data {
+-      int enabled;
++      int id;
+       int irq[32];
+       u32 phy_mask;
+       int mdc_div;
+@@ -120,8 +120,6 @@ struct  pfe_eth_priv_s {
+       unsigned int            event_status;
+       int                     irq;
+       void                    *EMAC_baseaddr;
+-      /* This points to the EMAC base from where we access PHY */
+-      void                    *PHY_baseaddr;
+       void                    *GPI_baseaddr;
+       /* PHY stuff */
+       struct phy_device       *phydev;
+@@ -129,9 +127,6 @@ struct  pfe_eth_priv_s {
+       int                     oldduplex;
+       int                     oldlink;
+       struct device_node      *phy_node;
+-      /* mdio info */
+-      int                     mdc_div;
+-      struct mii_bus          *mii_bus;
+       struct clk              *gemtx_clk;
+       int                     wol;
+       int                     pause_flag;
+@@ -161,6 +156,16 @@ struct pfe_eth {
+       struct pfe_eth_priv_s *eth_priv[3];
+ };
++struct pfe_mdio_priv_s {
++      void __iomem *mdio_base;
++      int                     mdc_div;
++      struct mii_bus          *mii_bus;
++};
++
++struct pfe_mdio {
++      struct pfe_mdio_priv_s *mdio_priv[3];
++};
++
+ int pfe_eth_init(struct pfe *pfe);
+ void pfe_eth_exit(struct pfe *pfe);
+ int pfe_eth_suspend(struct net_device *dev);
+--- a/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
++++ b/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
+@@ -21,31 +21,18 @@
+ extern bool pfe_use_old_dts_phy;
+ struct ls1012a_pfe_platform_data pfe_platform_data;
+-static int pfe_get_gemac_if_properties(struct device_node *parent, int port, int
+-                                      if_cnt,
+-                                      struct ls1012a_pfe_platform_data
+-                                      *pdata)
++static int pfe_get_gemac_if_properties(struct device_node *gem,
++                                     int port,
++                                     struct ls1012a_pfe_platform_data *pdata)
+ {
+-      struct device_node *gem = NULL, *phy = NULL, *phy_node = NULL;
++      struct device_node *phy_node = NULL;
+       int size;
+-      int ii = 0, phy_id = 0;
++      int phy_id = 0;
+       const u32 *addr;
+       const void *mac_addr;
+-      for (ii = 0; ii < if_cnt; ii++) {
+-              gem = of_get_next_child(parent, gem);
+-              if (!gem)
+-                      goto err;
+-              addr = of_get_property(gem, "reg", &size);
+-              if (addr && (be32_to_cpup(addr) == port))
+-                      break;
+-      }
+-
+-      if (ii >= if_cnt) {
+-              pr_err("%s:%d Failed to find interface = %d\n",
+-                     __func__, __LINE__, if_cnt);
+-              goto err;
+-      }
++      addr = of_get_property(gem, "reg", &size);
++      port = be32_to_cpup(addr);
+       pdata->ls1012a_eth_pdata[port].gem_id = port;
+@@ -88,14 +75,6 @@ static int pfe_get_gemac_if_properties(s
+               if (pdata->ls1012a_eth_pdata[port].phy_flags & GEMAC_NO_PHY)
+                       goto done;
+-              phy = of_get_next_child(gem, NULL);
+-              addr = of_get_property(phy, "reg", &size);
+-              if (!addr)
+-                      pr_err("%s:%d Invalid phy enable flag....\n",
+-                             __func__, __LINE__);
+-              else
+-                      pdata->ls1012a_mdio_pdata[port].enabled =
+-                                                      be32_to_cpup(addr);
+       } else {
+               pr_info("%s: No PHY or fixed-link\n", __func__);
+               return 0;
+@@ -140,7 +119,7 @@ static int pfe_platform_probe(struct pla
+       struct resource res;
+       int ii, rc, interface_count = 0, size = 0;
+       const u32 *prop;
+-      struct device_node  *np;
++      struct device_node *np, *gem = NULL;
+       struct clk *pfe_clk;
+       np = pdev->dev.of_node;
+@@ -224,8 +203,13 @@ static int pfe_platform_probe(struct pla
+       pfe_platform_data.ls1012a_mdio_pdata[0].phy_mask = 0xffffffff;
+       for (ii = 0; ii < interface_count; ii++) {
+-              pfe_get_gemac_if_properties(np, ii, interface_count,
+-                                          &pfe_platform_data);
++              gem = of_get_next_child(np, gem);
++              if (gem)
++                      pfe_get_gemac_if_properties(gem, ii,
++                                                  &pfe_platform_data);
++              else
++                      pr_err("Unable to find interface %d\n", ii);
++
+       }
+       pfe->dev = &pdev->dev;
+@@ -347,8 +331,8 @@ static int pfe_platform_resume(struct de
+       for (i = 0; i < (NUM_GEMAC_SUPPORT); i++) {
+               netdev = pfe->eth.eth_priv[i]->ndev;
+-              if (pfe->eth.eth_priv[i]->mii_bus)
+-                      pfe_eth_mdio_reset(pfe->eth.eth_priv[i]->mii_bus);
++              if (pfe->mdio.mdio_priv[i]->mii_bus)
++                      pfe_eth_mdio_reset(pfe->mdio.mdio_priv[i]->mii_bus);
+               if (netif_running(netdev))
+                       pfe_eth_resume(netdev);
+--- a/drivers/staging/fsl_ppfe/pfe_mod.h
++++ b/drivers/staging/fsl_ppfe/pfe_mod.h
+@@ -52,6 +52,7 @@ struct pfe {
+       struct pfe_ctrl ctrl;
+       struct pfe_hif hif;
+       struct pfe_eth eth;
++      struct pfe_mdio mdio;
+       struct hif_client_s *hif_client[HIF_CLIENTS_MAX];
+ #if defined(CFG_DIAGS)
+       struct pfe_diags diags;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0318-staging-fsl_ppfe-eth-adapt-to-link-mode-based-phydev.patch b/target/linux/layerscape/patches-5.4/701-net-0318-staging-fsl_ppfe-eth-adapt-to-link-mode-based-phydev.patch
new file mode 100644 (file)
index 0000000..bf34d39
--- /dev/null
@@ -0,0 +1,56 @@
+From 002297dd2634e993257a00fe4458b0288ec7baea Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Wed, 27 Mar 2019 13:25:57 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: adapt to link mode based phydev
+ changes
+
+Setting link mode bits have changed with the integration of
+commit (3c1bcc8 net: ethernet: Convert phydev advertize and
+supported from u32 to link mode). Adapt to the new method of
+setting and clearing the link mode bits.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c | 24 ++++++++++++++++--------
+ 1 file changed, 16 insertions(+), 8 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -701,10 +701,14 @@ static int pfe_eth_set_pauseparam(struct
+                                       EGPI_PAUSE_ENABLE),
+                               priv->GPI_baseaddr + GPI_TX_PAUSE_TIME);
+               if (priv->phydev) {
+-                      priv->phydev->supported |= ADVERTISED_Pause |
+-                                                      ADVERTISED_Asym_Pause;
+-                      priv->phydev->advertising |= ADVERTISED_Pause |
+-                                                      ADVERTISED_Asym_Pause;
++                      linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
++                                       priv->phydev->supported);
++                      linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
++                                       priv->phydev->supported);
++                      linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
++                                       priv->phydev->advertising);
++                      linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
++                                       priv->phydev->advertising);
+               }
+       } else {
+               gemac_disable_pause_rx(priv->EMAC_baseaddr);
+@@ -712,10 +716,14 @@ static int pfe_eth_set_pauseparam(struct
+                                       ~EGPI_PAUSE_ENABLE),
+                               priv->GPI_baseaddr + GPI_TX_PAUSE_TIME);
+               if (priv->phydev) {
+-                      priv->phydev->supported &= ~(ADVERTISED_Pause |
+-                                                      ADVERTISED_Asym_Pause);
+-                      priv->phydev->advertising &= ~(ADVERTISED_Pause |
+-                                                      ADVERTISED_Asym_Pause);
++                      linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT,
++                                         priv->phydev->supported);
++                      linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
++                                         priv->phydev->supported);
++                      linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT,
++                                         priv->phydev->advertising);
++                      linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
++                                         priv->phydev->advertising);
+               }
+       }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0319-staging-fsl_ppfe-eth-use-generic-soc_device-infra-in.patch b/target/linux/layerscape/patches-5.4/701-net-0319-staging-fsl_ppfe-eth-use-generic-soc_device-infra-in.patch
new file mode 100644 (file)
index 0000000..11bd1ff
--- /dev/null
@@ -0,0 +1,50 @@
+From 3f64975a822c9144c7134d3cebadd4d8b88fead5 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Wed, 27 Mar 2019 19:31:35 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: use generic soc_device infra instead
+ of fsl_guts_get_svr()
+
+Commit ("soc: fsl: guts: make fsl_guts_get_svr() static") has
+made fsl_guts_get_svr() static and hence use generic soc_device
+infrastructure to check SoC revision.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -35,7 +35,7 @@
+ #include <linux/delay.h>
+ #include <linux/regmap.h>
+ #include <linux/i2c.h>
+-#include <linux/fsl/guts.h>
++#include <linux/sys_soc.h>
+ #if defined(CONFIG_NF_CONNTRACK_MARK)
+ #include <net/netfilter/nf_conntrack.h>
+@@ -104,6 +104,14 @@ unsigned int gemac_regs[] = {
+       0x01B0, /* Frame Truncation Length */
+ };
++const struct soc_device_attribute ls1012a_rev1_soc_attr[] = {
++      { .family = "QorIQ LS1012A",
++        .soc_id = "svr:0x87040010",
++        .revision = "1.0",
++        .data = NULL },
++      { },
++};
++
+ /********************************************************************/
+ /*                   SYSFS INTERFACE                              */
+ /********************************************************************/
+@@ -2497,7 +2505,7 @@ int pfe_eth_init(struct pfe *pfe)
+               }
+       }
+-      if (fsl_guts_get_svr() == LS1012A_REV_1_0)
++      if (soc_device_match(ls1012a_rev1_soc_attr))
+               pfe_errata_a010897 = true;
+       else
+               pfe_errata_a010897 = false;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0320-staging-fsl_ppfe-eth-use-memremap-to-map-RAM-area-us.patch b/target/linux/layerscape/patches-5.4/701-net-0320-staging-fsl_ppfe-eth-use-memremap-to-map-RAM-area-us.patch
new file mode 100644 (file)
index 0000000..115685c
--- /dev/null
@@ -0,0 +1,49 @@
+From 7872505a2194c9766c7986e761c0ae9bdd6e5e57 Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Tue, 26 Mar 2019 16:52:22 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: use memremap() to map RAM area used by
+ PFE
+
+RAM area used by PFE should be mapped using memremap() instead of
+directly traslating physical addr to virtual. This will ensure proper
+checks are done before the area is used.
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
++++ b/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
+@@ -148,9 +148,10 @@ static int pfe_platform_probe(struct pla
+       pfe->ddr_phys_baseaddr = res.start;
+       pfe->ddr_size = resource_size(&res);
+-      pfe->ddr_baseaddr = phys_to_virt(res.start);
++      pfe->ddr_baseaddr = memremap(res.start, resource_size(&res),
++                                   MEMREMAP_WB);
+       if (!pfe->ddr_baseaddr) {
+-              pr_err("ioremap() ddr failed\n");
++              pr_err("memremap() ddr failed\n");
+               rc = -ENOMEM;
+               goto err_ddr;
+       }
+@@ -240,7 +241,7 @@ err_hif_irq:
+       iounmap(pfe->cbus_baseaddr);
+ err_axi:
+-      iounmap(pfe->ddr_baseaddr);
++      memunmap(pfe->ddr_baseaddr);
+ err_ddr:
+       platform_set_drvdata(pdev, NULL);
+@@ -264,7 +265,8 @@ static int pfe_platform_remove(struct pl
+       rc = pfe_remove(pfe);
+       iounmap(pfe->cbus_baseaddr);
+-      iounmap(pfe->ddr_baseaddr);
++
++      memunmap(pfe->ddr_baseaddr);
+       platform_set_drvdata(pdev, NULL);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0321-staging-fsl_ppfe-eth-remove-fallback-argument-from-d.patch b/target/linux/layerscape/patches-5.4/701-net-0321-staging-fsl_ppfe-eth-remove-fallback-argument-from-d.patch
new file mode 100644 (file)
index 0000000..9d4169e
--- /dev/null
@@ -0,0 +1,25 @@
+From 52f6eea9b70007cb0c5d13b9268d37bfddbaf0f4 Mon Sep 17 00:00:00 2001
+From: Li Yang <leoyang.li@nxp.com>
+Date: Tue, 11 Jun 2019 18:24:37 -0500
+Subject: [PATCH] staging: fsl_ppfe/eth: remove 'fallback' argument from
+ dev->ndo_select_queue()
+
+To be consistent with upstream API change.
+
+Signed-off-by: Li Yang <leoyang.li@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_eth.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_eth.c
++++ b/drivers/staging/fsl_ppfe/pfe_eth.c
+@@ -1879,8 +1879,7 @@ static int pfe_eth_send_packet(struct sk
+  *
+  */
+ static u16 pfe_eth_select_queue(struct net_device *ndev, struct sk_buff *skb,
+-                              struct net_device *sb_dev,
+-                              select_queue_fallback_t fallback)
++                              struct net_device *sb_dev)
+ {
+       struct pfe_eth_priv_s *priv = netdev_priv(ndev);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0322-staging-fsl_ppfe-eth-prefix-header-search-paths-with.patch b/target/linux/layerscape/patches-5.4/701-net-0322-staging-fsl_ppfe-eth-prefix-header-search-paths-with.patch
new file mode 100644 (file)
index 0000000..339813a
--- /dev/null
@@ -0,0 +1,31 @@
+From 9b280449f99b5273b52d88574c7358a874f825a3 Mon Sep 17 00:00:00 2001
+From: Ting Liu <ting.liu@nxp.com>
+Date: Mon, 17 Jun 2019 09:27:53 +0200
+Subject: [PATCH] staging: fsl_ppfe/eth: prefix header search paths with
+ $(srctree)/
+
+Currently, the rules for configuring search paths in Kbuild have
+changed: https://lkml.org/lkml/2019/5/13/37
+
+This will lead the below error:
+
+fatal error: pfe/pfe.h: No such file or directory
+
+Fix it by adding $(srctree)/ prefix to the search paths.
+
+Signed-off-by: Ting Liu <ting.liu@nxp.com>
+---
+ drivers/staging/fsl_ppfe/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl_ppfe/Makefile
++++ b/drivers/staging/fsl_ppfe/Makefile
+@@ -2,7 +2,7 @@
+ # Makefile for Freesecale PPFE driver
+ #
+-ccflags-y +=  -I$(src)/include  -I$(src)
++ccflags-y +=  -I $(srctree)/$(src)/include  -I $(srctree)/$(src)
+ obj-m += pfe.o
diff --git a/target/linux/layerscape/patches-5.4/701-net-0323-staging-fsl_ppfe-eth-add-pfe-support-to-Kconfig-and-.patch b/target/linux/layerscape/patches-5.4/701-net-0323-staging-fsl_ppfe-eth-add-pfe-support-to-Kconfig-and-.patch
new file mode 100644 (file)
index 0000000..6819b0e
--- /dev/null
@@ -0,0 +1,48 @@
+From 022999fe6c4008d1ca6ec0f33d7f7c88db97f3fa Mon Sep 17 00:00:00 2001
+From: Calvin Johnson <calvin.johnson@nxp.com>
+Date: Wed, 1 Nov 2017 11:11:30 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: add pfe support to Kconfig and
+ Makefile
+
+Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
+[ Aisheng: fix minor conflict due to removed VBOXSF_FS ]
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ MAINTAINERS              | 8 ++++++++
+ drivers/staging/Kconfig  | 1 +
+ drivers/staging/Makefile | 1 +
+ 3 files changed, 10 insertions(+)
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -6574,6 +6574,14 @@ F:      drivers/ptp/ptp_qoriq_debugfs.c
+ F:    include/linux/fsl/ptp_qoriq.h
+ F:    Documentation/devicetree/bindings/ptp/ptp-qoriq.txt
++FREESCALE QORIQ PPFE ETHERNET DRIVER
++M:    Anji Jagarlmudi <anji.jagarlmudi@nxp.com>
++M:    Calvin Johnson <calvin.johnson@nxp.com>
++L:    netdev@vger.kernel.org
++S:    Maintained
++F:    drivers/staging/fsl_ppfe
++F:    Documentation/devicetree/bindings/net/fsl_ppfe/pfe.txt
++
+ FREESCALE QUAD SPI DRIVER
+ M:    Han Xu <han.xu@nxp.com>
+ L:    linux-spi@vger.kernel.org
+--- a/drivers/staging/Kconfig
++++ b/drivers/staging/Kconfig
+@@ -126,5 +126,6 @@ source "drivers/staging/exfat/Kconfig"
+ source "drivers/staging/qlge/Kconfig"
+ source "drivers/staging/fsl_qbman/Kconfig"
++source "drivers/staging/fsl_ppfe/Kconfig"
+ endif # STAGING
+--- a/drivers/staging/Makefile
++++ b/drivers/staging/Makefile
+@@ -54,3 +54,4 @@ obj-$(CONFIG_USB_WUSB)               += wusbcore/
+ obj-$(CONFIG_EXFAT_FS)                += exfat/
+ obj-$(CONFIG_QLGE)            += qlge/
+ obj-$(CONFIG_FSL_SDK_DPA)      += fsl_qbman/
++obj-$(CONFIG_FSL_PPFE)                += fsl_ppfe/
diff --git a/target/linux/layerscape/patches-5.4/701-net-0324-staging-fsl_ppfe-eth-Disable-termination-of-CRC-fwd.patch b/target/linux/layerscape/patches-5.4/701-net-0324-staging-fsl_ppfe-eth-Disable-termination-of-CRC-fwd.patch
new file mode 100644 (file)
index 0000000..3d9870d
--- /dev/null
@@ -0,0 +1,34 @@
+From 6d7e10038aba81d7273f72f36db64c71ae7f8f69 Mon Sep 17 00:00:00 2001
+From: Nagesh Koneti <koneti.nagesh@nxp.com>
+Date: Wed, 25 Sep 2019 12:01:19 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: Disable termination of CRC fwd.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+LS1012A MAC PCS block has an erratum that is seen with specific PHY AR803x.
+The issue is triggered by the (spec-compliant) operation of the AR803x PHY
+on the LS1012A-FRWY board.Due to this, good FCS packet is reported as error
+packet by MAC, so for these error packets FCS should be validated and
+discard only real error packets in PFE Rx packet path.
+
+Signed-off-by: Nagesh Koneti <koneti.nagesh@nxp.com>
+Signed-off-by: Nagesh Koneti <“koneti.nagesh@nxp.com”>
+---
+ drivers/staging/fsl_ppfe/pfe_hal.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_hal.c
++++ b/drivers/staging/fsl_ppfe/pfe_hal.c
+@@ -860,8 +860,9 @@ void gemac_set_mode(void *base, int mode
+       /*Remove loopbank*/
+       val &= ~EMAC_RCNTRL_LOOP;
+-      /* Enable flow control and MII mode and terminate received CRC */
+-      val |= (EMAC_RCNTRL_FCE | EMAC_RCNTRL_MII_MODE | EMAC_RCNTRL_CRC_FWD);
++      /* Enable flow control and MII mode.PFE firmware always expects
++       CRC should be forwarded by MAC to validate CRC in software.*/
++      val |= (EMAC_RCNTRL_FCE | EMAC_RCNTRL_MII_MODE);
+       writel(val, base + EMAC_RCNTRL_REG);
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0325-net-phy-add-10G-fixed-link-support.patch b/target/linux/layerscape/patches-5.4/701-net-0325-net-phy-add-10G-fixed-link-support.patch
new file mode 100644 (file)
index 0000000..a227baf
--- /dev/null
@@ -0,0 +1,20 @@
+From c8d3576df41025b341eb767168914990598a0caa Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 22 Aug 2017 18:35:11 +0300
+Subject: [PATCH] net: phy: add 10G fixed-link support
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/phy/swphy.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/phy/swphy.c
++++ b/drivers/net/phy/swphy.c
+@@ -71,6 +71,7 @@ static const struct swmii_regs duplex[]
+ static int swphy_decode_speed(int speed)
+ {
+       switch (speed) {
++      case 10000:
+       case 1000:
+               return SWMII_SPEED_1000;
+       case 100:
diff --git a/target/linux/layerscape/patches-5.4/701-net-0326-phy-Add-2.5G-SGMII-interface-mode.patch b/target/linux/layerscape/patches-5.4/701-net-0326-phy-Add-2.5G-SGMII-interface-mode.patch
new file mode 100644 (file)
index 0000000..a0c7291
--- /dev/null
@@ -0,0 +1,32 @@
+From 457577118b28909a35f62bffc16bb52f73900b53 Mon Sep 17 00:00:00 2001
+From: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+Date: Wed, 29 Nov 2017 15:27:57 +0530
+Subject: [PATCH] phy: Add 2.5G SGMII interface mode
+
+Add 2.5G SGMII interface mode(PHY_INTERFACE_MODE_2500SGMII)
+in existing phy_interface list
+
+Signed-off-by: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
+---
+ include/linux/phy.h | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -102,6 +102,7 @@ typedef enum {
+       /* 10GBASE-KR, XFI, SFI - single lane 10G Serdes */
+       PHY_INTERFACE_MODE_10GKR,
+       PHY_INTERFACE_MODE_USXGMII,
++      PHY_INTERFACE_MODE_2500SGMII,
+       PHY_INTERFACE_MODE_MAX,
+ } phy_interface_t;
+@@ -179,6 +180,8 @@ static inline const char *phy_modes(phy_
+               return "10gbase-kr";
+       case PHY_INTERFACE_MODE_USXGMII:
+               return "usxgmii";
++      case PHY_INTERFACE_MODE_2500SGMII:
++              return "sgmii-2500";
+       default:
+               return "unknown";
+       }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0327-at803x-Address-packet-drops-at-low-traffic-rate-due-.patch b/target/linux/layerscape/patches-5.4/701-net-0327-at803x-Address-packet-drops-at-low-traffic-rate-due-.patch
new file mode 100644 (file)
index 0000000..f6cf0e0
--- /dev/null
@@ -0,0 +1,86 @@
+From 53c3bd0d5a873c23841bb95e7b95c1c3630c50bd Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Thu, 12 Jul 2018 13:03:13 +0300
+Subject: [PATCH] at803x: Address packet drops at low traffic rate due to
+ SmartEEE feature
+
+* According to the AR8035 datasheet, smartEEE mode (active by default)
+  makes the PHY enters sleep after a configurable idle time. It does
+  this autonomously, without LPI (Low Power Idle) signals coming from MAC.
+* Tested with ping (default of 1 second interval) over back-to-back
+  RGMII between 2 boards having AR8035 at both ends:
+    - Without patch:
+  225 packets transmitted, 145 received, 35% packet loss, time 229334ms
+    - With patch:
+  144 packets transmitted, 144 received, 0% packet loss, time 146378ms
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/phy/Kconfig  | 10 ++++++++++
+ drivers/net/phy/at803x.c | 22 ++++++++++++++++++++++
+ 2 files changed, 32 insertions(+)
+
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -370,6 +370,16 @@ config AT803X_PHY
+       ---help---
+         Currently supports the AT8030 and AT8035 model
++config AT803X_PHY_SMART_EEE
++      depends on AT803X_PHY
++      default n
++      tristate "SmartEEE feature for AT803X PHYs"
++      ---help---
++        Enables the Atheros SmartEEE feature (not IEEE 802.3az). When 2 PHYs
++        which support this feature are connected back-to-back, they may
++        negotiate a low-power sleep mode autonomously, without the Ethernet
++        controller's knowledge.  May cause packet loss.
++
+ config BCM63XX_PHY
+       tristate "Broadcom 63xx SOCs internal PHY"
+       depends on BCM63XX || COMPILE_TEST
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -63,6 +63,8 @@
+ #define AT803X_DEBUG_REG_5                    0x05
+ #define AT803X_DEBUG_TX_CLK_DLY_EN            BIT(8)
++#define AT803X_LPI_EN                         BIT(8)
++
+ #define ATH8030_PHY_ID 0x004dd076
+ #define ATH8031_PHY_ID 0x004dd074
+ #define ATH8032_PHY_ID 0x004dd023
+@@ -257,6 +259,19 @@ static int at803x_probe(struct phy_devic
+       return 0;
+ }
++static void at803x_enable_smart_eee(struct phy_device *phydev, int on)
++{
++      int value;
++
++      /* 5.1.11 Smart_eee control3 */
++      value = phy_read_mmd(phydev, MDIO_MMD_PCS, 0x805D);
++      if (on)
++              value |= AT803X_LPI_EN;
++      else
++              value &= ~AT803X_LPI_EN;
++      phy_write_mmd(phydev, MDIO_MMD_PCS, 0x805D, value);
++}
++
+ static int at803x_config_init(struct phy_device *phydev)
+ {
+       int ret;
+@@ -282,6 +297,13 @@ static int at803x_config_init(struct phy
+                       return ret;
+       }
++
++#ifdef CONFIG_AT803X_PHY_SMART_EEE
++      at803x_enable_smart_eee(phydev, 1);
++#else
++      at803x_enable_smart_eee(phydev, 0);
++#endif
++
+       /* The RX and TX delay default is:
+        *   after HW reset: RX delay enabled and TX delay disabled
+        *   after SW reset: RX delay enabled, while TX delay retains the
diff --git a/target/linux/layerscape/patches-5.4/701-net-0328-net-phy-Inphi-IN112525_s03-retimer-support.patch b/target/linux/layerscape/patches-5.4/701-net-0328-net-phy-Inphi-IN112525_s03-retimer-support.patch
new file mode 100644 (file)
index 0000000..46f45df
--- /dev/null
@@ -0,0 +1,620 @@
+From 630ee8f358d961a7c8295d60a112e27cbfe4478d Mon Sep 17 00:00:00 2001
+From: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
+Date: Fri, 9 Nov 2018 06:20:36 +0200
+Subject: [PATCH] net/phy: Inphi IN112525_s03 retimer support
+
+Software controller for IN112525_s03 retimer
+
+Signed-off-by: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
+---
+ drivers/net/phy/Kconfig  |   5 +
+ drivers/net/phy/Makefile |   1 +
+ drivers/net/phy/inphi.c  | 578 +++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 584 insertions(+)
+ create mode 100644 drivers/net/phy/inphi.c
+
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -478,6 +478,11 @@ config ICPLUS_PHY
+       ---help---
+         Currently supports the IP175C and IP1001 PHYs.
++config INPHI_PHY
++      tristate "Inphi CDR 10G/25G Ethernet PHY"
++      ---help---
++        Currently supports the IN112525_S03 part @ 25G
++
+ config INTEL_XWAY_PHY
+       tristate "Intel XWAY PHYs"
+       ---help---
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -88,6 +88,7 @@ obj-$(CONFIG_DP83848_PHY)    += dp83848.o
+ obj-$(CONFIG_DP83867_PHY)     += dp83867.o
+ obj-$(CONFIG_FIXED_PHY)               += fixed_phy.o
+ obj-$(CONFIG_ICPLUS_PHY)      += icplus.o
++obj-$(CONFIG_INPHI_PHY)       += inphi.o
+ obj-$(CONFIG_INTEL_XWAY_PHY)  += intel-xway.o
+ obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
+ obj-$(CONFIG_LXT_PHY)         += lxt.o
+--- /dev/null
++++ b/drivers/net/phy/inphi.c
+@@ -0,0 +1,578 @@
++/*
++ * Copyright 2018 NXP
++ * Copyright 2018 INPHI
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright notice,
++ * this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright notice,
++ * this list of conditions and the following disclaimer in the documentation
++ * and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ *
++ * Inphi is a registered trademark of Inphi Corporation
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/phy.h>
++#include <linux/mdio.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/of_irq.h>
++#include <linux/workqueue.h>
++#include <linux/i2c.h>
++#include <linux/timer.h>
++#include <linux/delay.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/cdev.h>
++#include <linux/device.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++
++#define PHY_ID_IN112525  0x02107440
++
++#define INPHI_S03_DEVICE_ID_MSB 0x2
++#define INPHI_S03_DEVICE_ID_LSB 0x3
++
++#define ALL_LANES             4
++#define INPHI_POLL_DELAY      2500
++
++#define PHYCTRL_REG1  0x0012
++#define PHYCTRL_REG2  0x0014
++#define PHYCTRL_REG3  0x0120
++#define PHYCTRL_REG4  0x0121
++#define PHYCTRL_REG5  0x0180
++#define PHYCTRL_REG6  0x0580
++#define PHYCTRL_REG7  0x05C4
++#define PHYCTRL_REG8  0x01C8
++#define PHYCTRL_REG9  0x0521
++
++#define PHYSTAT_REG1  0x0021
++#define PHYSTAT_REG2  0x0022
++#define PHYSTAT_REG3  0x0123
++
++#define PHYMISC_REG1  0x0025
++#define PHYMISC_REG2  0x002c
++#define PHYMISC_REG3  0x00b3
++#define PHYMISC_REG4  0x0181
++#define PHYMISC_REG5  0x019D
++#define PHYMISC_REG6  0x0198
++#define PHYMISC_REG7  0x0199
++#define PHYMISC_REG8  0x0581
++#define PHYMISC_REG9  0x0598
++#define PHYMISC_REG10 0x059c
++#define PHYMISC_REG20 0x01B0
++#define PHYMISC_REG21 0x01BC
++#define PHYMISC_REG22 0x01C0
++
++#define RX_VCO_CODE_OFFSET    5
++
++#define mdio_wr(a, b) phy_write_mmd(inphi_phydev, MDIO_MMD_VEND1, (a), (b))
++#define mdio_rd(a)    phy_read_mmd(inphi_phydev, MDIO_MMD_VEND1, (a))
++
++#define VCO_CODE  390
++
++int vco_codes[ALL_LANES] = {
++      VCO_CODE,
++      VCO_CODE,
++      VCO_CODE,
++      VCO_CODE
++};
++
++static void mykmod_work_handler(struct work_struct *w);
++
++static struct workqueue_struct *wq;
++static DECLARE_DELAYED_WORK(mykmod_work, mykmod_work_handler);
++static unsigned long onesec;
++struct phy_device *inphi_phydev;
++
++int bit_test(int value, int bit_field)
++{
++      int result;
++      int bit_mask = (1 << bit_field);
++
++      result = ((value & bit_mask) == bit_mask);
++      return result;
++}
++
++int tx_pll_lock_test(int lane)
++{
++      int i, val, locked = 1;
++
++      if (lane == ALL_LANES) {
++              for (i = 0; i < ALL_LANES; i++) {
++                      val = mdio_rd(i * 0x100 + PHYSTAT_REG3);
++                      locked = locked & bit_test(val, 15);
++              }
++      } else {
++              val = mdio_rd(lane * 0x100 + PHYSTAT_REG3);
++              locked = locked & bit_test(val, 15);
++      }
++
++      return locked;
++}
++
++void rx_reset_assert(int lane)
++{
++      int mask, val;
++
++      if (lane == ALL_LANES) {
++              val = mdio_rd(PHYMISC_REG2);
++              mask = (1 << 15);
++              mdio_wr(PHYMISC_REG2, val + mask);
++      } else {
++              val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
++              mask = (1 << 6);
++              mdio_wr(lane * 0x100 + PHYCTRL_REG8, val + mask);
++      }
++}
++
++void rx_reset_de_assert(int lane)
++{
++      int mask, val;
++
++      if (lane == ALL_LANES) {
++              val = mdio_rd(PHYMISC_REG2);
++              mask = 0xffff - (1 << 15);
++              mdio_wr(PHYMISC_REG2, val & mask);
++      } else {
++              val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
++              mask = 0xffff - (1 << 6);
++              mdio_wr(lane * 0x100 + PHYCTRL_REG8, val & mask);
++      }
++}
++
++void rx_powerdown_assert(int lane)
++{
++      int mask, val;
++
++      val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
++      mask = (1 << 5);
++      mdio_wr(lane * 0x100 + PHYCTRL_REG8, val + mask);
++}
++
++void rx_powerdown_de_assert(int lane)
++{
++      int mask, val;
++
++      val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
++      mask = 0xffff - (1 << 5);
++      mdio_wr(lane * 0x100 + PHYCTRL_REG8, val & mask);
++}
++
++void tx_pll_assert(int lane)
++{
++      int val, recal;
++
++      if (lane == ALL_LANES) {
++              val = mdio_rd(PHYMISC_REG2);
++              recal = (1 << 12);
++              mdio_wr(PHYMISC_REG2, val | recal);
++      } else {
++              val = mdio_rd(lane * 0x100 + PHYCTRL_REG4);
++              recal = (1 << 15);
++              mdio_wr(lane * 0x100 + PHYCTRL_REG4, val | recal);
++      }
++}
++
++void tx_pll_de_assert(int lane)
++{
++      int recal, val;
++
++      if (lane == ALL_LANES) {
++              val = mdio_rd(PHYMISC_REG2);
++              recal = 0xefff;
++              mdio_wr(PHYMISC_REG2, val & recal);
++      } else {
++              val = mdio_rd(lane * 0x100 + PHYCTRL_REG4);
++              recal = 0x7fff;
++              mdio_wr(lane * 0x100 + PHYCTRL_REG4, val & recal);
++      }
++}
++
++void tx_core_assert(int lane)
++{
++      int recal, val, val2, core_reset;
++
++      if (lane == 4) {
++              val = mdio_rd(PHYMISC_REG2);
++              recal = 1 << 10;
++              mdio_wr(PHYMISC_REG2, val | recal);
++      } else {
++              val2 = mdio_rd(PHYMISC_REG3);
++              core_reset = (1 << (lane + 8));
++              mdio_wr(PHYMISC_REG3, val2 | core_reset);
++      }
++}
++
++void lol_disable(int lane)
++{
++      int val, mask;
++
++      val = mdio_rd(PHYMISC_REG3);
++      mask = 1 << (lane + 4);
++      mdio_wr(PHYMISC_REG3, val | mask);
++}
++
++void tx_core_de_assert(int lane)
++{
++      int val, recal, val2, core_reset;
++
++      if (lane == ALL_LANES) {
++              val = mdio_rd(PHYMISC_REG2);
++              recal = 0xffff - (1 << 10);
++              mdio_wr(PHYMISC_REG2, val & recal);
++      } else {
++              val2 = mdio_rd(PHYMISC_REG3);
++              core_reset = 0xffff - (1 << (lane + 8));
++              mdio_wr(PHYMISC_REG3, val2 & core_reset);
++      }
++}
++
++void tx_restart(int lane)
++{
++      tx_core_assert(lane);
++      tx_pll_assert(lane);
++      tx_pll_de_assert(lane);
++      usleep_range(1500, 1600);
++      tx_core_de_assert(lane);
++}
++
++void disable_lane(int lane)
++{
++      rx_reset_assert(lane);
++      rx_powerdown_assert(lane);
++      tx_core_assert(lane);
++      lol_disable(lane);
++}
++
++void toggle_reset(int lane)
++{
++      int reg, val, orig;
++
++      if (lane == ALL_LANES) {
++              mdio_wr(PHYMISC_REG2, 0x8000);
++              udelay(100);
++              mdio_wr(PHYMISC_REG2, 0x0000);
++      } else {
++              reg = lane * 0x100 + PHYCTRL_REG8;
++              val = (1 << 6);
++              orig = mdio_rd(reg);
++              mdio_wr(reg, orig + val);
++              udelay(100);
++              mdio_wr(reg, orig);
++      }
++}
++
++int az_complete_test(int lane)
++{
++      int success = 1, value;
++
++      if (lane == 0 || lane == ALL_LANES) {
++              value = mdio_rd(PHYCTRL_REG5);
++              success = success & bit_test(value, 2);
++      }
++      if (lane == 1 || lane == ALL_LANES) {
++              value = mdio_rd(PHYCTRL_REG5 + 0x100);
++              success = success & bit_test(value, 2);
++      }
++      if (lane == 2 || lane == ALL_LANES) {
++              value = mdio_rd(PHYCTRL_REG5 + 0x200);
++              success = success & bit_test(value, 2);
++      }
++      if (lane == 3 || lane == ALL_LANES) {
++              value = mdio_rd(PHYCTRL_REG5 + 0x300);
++              success = success & bit_test(value, 2);
++      }
++
++      return success;
++}
++
++void save_az_offsets(int lane)
++{
++      int i;
++
++#define AZ_OFFSET_LANE_UPDATE(reg, lane) \
++      mdio_wr((reg) + (lane) * 0x100,  \
++              (mdio_rd((reg) + (lane) * 0x100) >> 8))
++
++      if (lane == ALL_LANES) {
++              for (i = 0; i < ALL_LANES; i++) {
++                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20, i);
++                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 1, i);
++                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 2, i);
++                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 3, i);
++                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21, i);
++                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 1, i);
++                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 2, i);
++                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 3, i);
++                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG22, i);
++              }
++      } else {
++              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20, lane);
++              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 1, lane);
++              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 2, lane);
++              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 3, lane);
++              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21, lane);
++              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 1, lane);
++              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 2, lane);
++              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 3, lane);
++              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG22, lane);
++      }
++
++      mdio_wr(PHYCTRL_REG7, 0x0001);
++}
++
++void save_vco_codes(int lane)
++{
++      int i;
++
++      if (lane == ALL_LANES) {
++              for (i = 0; i < ALL_LANES; i++) {
++                      vco_codes[i] = mdio_rd(PHYMISC_REG5 + i * 0x100);
++                      mdio_wr(PHYMISC_REG5 + i * 0x100,
++                              vco_codes[i] + RX_VCO_CODE_OFFSET);
++              }
++      } else {
++              vco_codes[lane] = mdio_rd(PHYMISC_REG5 + lane * 0x100);
++              mdio_wr(PHYMISC_REG5 + lane * 0x100,
++                      vco_codes[lane] + RX_VCO_CODE_OFFSET);
++      }
++}
++
++int inphi_lane_recovery(int lane)
++{
++      int i, value, az_pass;
++
++      switch (lane) {
++      case 0:
++      case 1:
++      case 2:
++      case 3:
++              rx_reset_assert(lane);
++              mdelay(20);
++              break;
++      case ALL_LANES:
++              mdio_wr(PHYMISC_REG2, 0x9C00);
++              mdelay(20);
++              do {
++                      value = mdio_rd(PHYMISC_REG2);
++                      udelay(10);
++              } while (!bit_test(value, 4));
++              break;
++      default:
++              dev_err(&inphi_phydev->mdio.dev,
++                      "Incorrect usage of APIs in %s driver\n",
++                      inphi_phydev->drv->name);
++              break;
++      }
++
++      if (lane == ALL_LANES) {
++              for (i = 0; i < ALL_LANES; i++)
++                      mdio_wr(PHYMISC_REG7 + i * 0x100, VCO_CODE);
++      } else {
++              mdio_wr(PHYMISC_REG7 + lane * 0x100, VCO_CODE);
++      }
++
++      if (lane == ALL_LANES)
++              for (i = 0; i < ALL_LANES; i++)
++                      mdio_wr(PHYCTRL_REG5 + i * 0x100, 0x0418);
++      else
++              mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0418);
++
++      mdio_wr(PHYCTRL_REG7,   0x0000);
++
++      rx_reset_de_assert(lane);
++
++      if (lane == ALL_LANES) {
++              for (i = 0; i < ALL_LANES; i++) {
++                      mdio_wr(PHYCTRL_REG5 + i * 0x100, 0x0410);
++                      mdio_wr(PHYCTRL_REG5 + i * 0x100, 0x0412);
++              }
++      } else {
++              mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0410);
++              mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0412);
++      }
++
++      for (i = 0; i < 64; i++) {
++              mdelay(100);
++              az_pass = az_complete_test(lane);
++              if (az_pass) {
++                      save_az_offsets(lane);
++                      break;
++              }
++      }
++
++      if (!az_pass) {
++              pr_info("in112525: AZ calibration fail @ lane=%d\n", lane);
++              return -1;
++      }
++
++      if (lane == ALL_LANES) {
++              mdio_wr(PHYMISC_REG8, 0x0002);
++              mdio_wr(PHYMISC_REG9, 0x2028);
++              mdio_wr(PHYCTRL_REG6, 0x0010);
++              usleep_range(1000, 1200);
++              mdio_wr(PHYCTRL_REG6, 0x0110);
++              mdelay(30);
++              mdio_wr(PHYMISC_REG9, 0x3020);
++      } else {
++              mdio_wr(PHYMISC_REG4 + lane * 0x100, 0x0002);
++              mdio_wr(PHYMISC_REG6 + lane * 0x100, 0x2028);
++              mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0010);
++              usleep_range(1000, 1200);
++              mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0110);
++              mdelay(30);
++              mdio_wr(PHYMISC_REG6 + lane * 0x100, 0x3020);
++      }
++
++      if (lane == ALL_LANES) {
++              mdio_wr(PHYMISC_REG2, 0x1C00);
++              mdio_wr(PHYMISC_REG2, 0x0C00);
++      } else {
++              tx_restart(lane);
++              mdelay(11);
++      }
++
++      if (lane == ALL_LANES) {
++              if (bit_test(mdio_rd(PHYMISC_REG2), 6) == 0)
++                      return -1;
++      } else {
++              if (tx_pll_lock_test(lane) == 0)
++                      return -1;
++      }
++
++      save_vco_codes(lane);
++
++      if (lane == ALL_LANES) {
++              mdio_wr(PHYMISC_REG2, 0x0400);
++              mdio_wr(PHYMISC_REG2, 0x0000);
++              value = mdio_rd(PHYCTRL_REG1);
++              value = value & 0xffbf;
++              mdio_wr(PHYCTRL_REG2, value);
++      } else {
++              tx_core_de_assert(lane);
++      }
++
++      if (lane == ALL_LANES) {
++              mdio_wr(PHYMISC_REG1, 0x8000);
++              mdio_wr(PHYMISC_REG1, 0x0000);
++      }
++      mdio_rd(PHYMISC_REG1);
++      mdio_rd(PHYMISC_REG1);
++      usleep_range(1000, 1200);
++      mdio_rd(PHYSTAT_REG1);
++      mdio_rd(PHYSTAT_REG2);
++
++      return 0;
++}
++
++static void mykmod_work_handler(struct work_struct *w)
++{
++      int all_lanes_lock, lane0_lock, lane1_lock, lane2_lock, lane3_lock;
++
++      lane0_lock = bit_test(mdio_rd(0x123), 15);
++      lane1_lock = bit_test(mdio_rd(0x223), 15);
++      lane2_lock = bit_test(mdio_rd(0x323), 15);
++      lane3_lock = bit_test(mdio_rd(0x423), 15);
++
++      /* check if the chip had any successful lane lock from the previous
++       * stage (e.g. u-boot)
++       */
++      all_lanes_lock = lane0_lock | lane1_lock | lane2_lock | lane3_lock;
++
++      if (!all_lanes_lock) {
++              /* start fresh */
++              inphi_lane_recovery(ALL_LANES);
++      } else {
++              if (!lane0_lock)
++                      inphi_lane_recovery(0);
++              if (!lane1_lock)
++                      inphi_lane_recovery(1);
++              if (!lane2_lock)
++                      inphi_lane_recovery(2);
++              if (!lane3_lock)
++                      inphi_lane_recovery(3);
++      }
++
++      queue_delayed_work(wq, &mykmod_work, onesec);
++}
++
++int inphi_probe(struct phy_device *phydev)
++{
++      int phy_id = 0, id_lsb = 0, id_msb = 0;
++
++      /* Read device id from phy registers */
++      id_lsb = phy_read_mmd(phydev, MDIO_MMD_VEND1, INPHI_S03_DEVICE_ID_MSB);
++      if (id_lsb < 0)
++              return -ENXIO;
++
++      phy_id = id_lsb << 16;
++
++      id_msb = phy_read_mmd(phydev, MDIO_MMD_VEND1, INPHI_S03_DEVICE_ID_LSB);
++      if (id_msb < 0)
++              return -ENXIO;
++
++      phy_id |= id_msb;
++
++      /* Make sure the device tree binding matched the driver with the
++       * right device.
++       */
++      if (phy_id != phydev->drv->phy_id) {
++              dev_err(&phydev->mdio.dev,
++                      "Error matching phy with %s driver\n",
++                      phydev->drv->name);
++              return -ENODEV;
++      }
++
++      /* update the local phydev pointer, used inside all APIs */
++      inphi_phydev = phydev;
++      onesec = msecs_to_jiffies(INPHI_POLL_DELAY);
++
++      wq = create_singlethread_workqueue("inphi_kmod");
++      if (wq) {
++              queue_delayed_work(wq, &mykmod_work, onesec);
++      } else {
++              dev_err(&phydev->mdio.dev,
++                      "Error creating kernel workqueue for %s driver\n",
++                      phydev->drv->name);
++              return -ENOMEM;
++      }
++
++      return 0;
++}
++
++static struct phy_driver inphi_driver[] = {
++{
++      .phy_id         = PHY_ID_IN112525,
++      .phy_id_mask    = 0x0ff0fff0,
++      .name           = "Inphi 112525_S03",
++      .features       = PHY_GBIT_FEATURES,
++      .probe          = &inphi_probe,
++},
++};
++
++module_phy_driver(inphi_driver);
++
++static struct mdio_device_id __maybe_unused inphi_tbl[] = {
++      { PHY_ID_IN112525, 0x0ff0fff0},
++      {},
++};
++
++MODULE_DEVICE_TABLE(mdio, inphi_tbl);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0329-net-phy-Inphi-IN112525_s03-retimer-updates.patch b/target/linux/layerscape/patches-5.4/701-net-0329-net-phy-Inphi-IN112525_s03-retimer-updates.patch
new file mode 100644 (file)
index 0000000..2f38fd0
--- /dev/null
@@ -0,0 +1,74 @@
+From a1b049babfd0ae224179dc82ec69cb9bbf585699 Mon Sep 17 00:00:00 2001
+From: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
+Date: Sun, 16 Dec 2018 22:35:44 +0200
+Subject: [PATCH] net/phy: Inphi IN112525_s03 retimer updates
+
+The retimer doesn't get probed in linux due to the fact that it's a
+non-standard clause-45 device. Hardcoding the phyid in device-tree
+and adding custom routines for registry read/write operations
+solves the issue.
+
+Signed-off-by: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
+---
+ drivers/net/phy/inphi.c | 30 +++++++++++++++++++++++-------
+ 1 file changed, 23 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/phy/inphi.c
++++ b/drivers/net/phy/inphi.c
+@@ -82,11 +82,7 @@
+ #define PHYMISC_REG22 0x01C0
+ #define RX_VCO_CODE_OFFSET    5
+-
+-#define mdio_wr(a, b) phy_write_mmd(inphi_phydev, MDIO_MMD_VEND1, (a), (b))
+-#define mdio_rd(a)    phy_read_mmd(inphi_phydev, MDIO_MMD_VEND1, (a))
+-
+-#define VCO_CODE  390
++#define VCO_CODE              390
+ int vco_codes[ALL_LANES] = {
+       VCO_CODE,
+@@ -102,6 +98,23 @@ static DECLARE_DELAYED_WORK(mykmod_work,
+ static unsigned long onesec;
+ struct phy_device *inphi_phydev;
++static int mdio_wr(u32 regnum, u16 val)
++{
++      regnum = MII_ADDR_C45 | (MDIO_MMD_VEND1 << 16) | (regnum & 0xffff);
++
++      return mdiobus_write(inphi_phydev->mdio.bus, inphi_phydev->mdio.addr,
++                              regnum, val);
++}
++
++static int mdio_rd(u32 regnum)
++{
++      regnum = MII_ADDR_C45 | (MDIO_MMD_VEND1 << 16) | (regnum & 0xffff);
++
++      return mdiobus_read(inphi_phydev->mdio.bus, inphi_phydev->mdio.addr,
++                              regnum);
++}
++
++
+ int bit_test(int value, int bit_field)
+ {
+       int result;
+@@ -518,14 +531,17 @@ int inphi_probe(struct phy_device *phyde
+ {
+       int phy_id = 0, id_lsb = 0, id_msb = 0;
++      /* setup the inphi_phydev ptr for mdio_rd/mdio_wr APIs */
++      inphi_phydev = phydev;
++
+       /* Read device id from phy registers */
+-      id_lsb = phy_read_mmd(phydev, MDIO_MMD_VEND1, INPHI_S03_DEVICE_ID_MSB);
++      id_lsb = mdio_rd(INPHI_S03_DEVICE_ID_MSB);
+       if (id_lsb < 0)
+               return -ENXIO;
+       phy_id = id_lsb << 16;
+-      id_msb = phy_read_mmd(phydev, MDIO_MMD_VEND1, INPHI_S03_DEVICE_ID_LSB);
++      id_msb = mdio_rd(INPHI_S03_DEVICE_ID_LSB);
+       if (id_msb < 0)
+               return -ENXIO;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0330-net-phy-at803x-add-vddio-1v8-and-eee-disable-support.patch b/target/linux/layerscape/patches-5.4/701-net-0330-net-phy-at803x-add-vddio-1v8-and-eee-disable-support.patch
new file mode 100644 (file)
index 0000000..3233919
--- /dev/null
@@ -0,0 +1,140 @@
+From e54e051c0adbe86116ab81c09a208f3a62c84f92 Mon Sep 17 00:00:00 2001
+From: Fugang Duan <fugang.duan@nxp.com>
+Date: Wed, 5 Jun 2019 18:38:51 +0800
+Subject: [PATCH] net: phy: at803x: add vddio-1v8 and eee disable support
+
+Add new property "at803x,vddio-1p8v" and "at803x,eee-disabled"
+support.
+
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+[ Aisheng: fix small merge conflict ]
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/phy/at803x.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 64 insertions(+)
+
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -44,8 +44,13 @@
+ #define AT803X_LOC_MAC_ADDR_0_15_OFFSET               0x804C
+ #define AT803X_LOC_MAC_ADDR_16_31_OFFSET      0x804B
+ #define AT803X_LOC_MAC_ADDR_32_47_OFFSET      0x804A
++#define AT803X_SMARTEEE_CTL3_OFFSET           0x805D
++#define AT803X_MMD_ACCESS_CONTROL             0x0D
++#define AT803X_MMD_ACCESS_CONTROL_DATA                0x0E
++#define AT803X_FUNC_DATA                      0x4003
+ #define AT803X_REG_CHIP_CONFIG                        0x1f
+ #define AT803X_BT_BX_REG_SEL                  0x8000
++#define AT803X_SMARTEEE_DISABLED_VAL          0x1000
+ #define AT803X_SGMII_ANEG_EN                  0x1000
+ #define AT803X_DEBUG_ADDR                     0x1D
+@@ -65,6 +70,9 @@
+ #define AT803X_LPI_EN                         BIT(8)
++#define AT803X_DEBUG_REG_31                   0x1f
++#define AT803X_VDDIO_1P8V_EN                  0x8
++
+ #define ATH8030_PHY_ID 0x004dd076
+ #define ATH8031_PHY_ID 0x004dd074
+ #define ATH8032_PHY_ID 0x004dd023
+@@ -72,12 +80,16 @@
+ #define AT803X_PHY_ID_MASK                    0xffffffef
+ #define AT8032_PHY_ID_MASK                    0xffffffff
++#define AT803X_EEE_FEATURE_DISABLE            (1 << 1)
++#define AT803X_VDDIO_1P8V                     (1 << 2)
++
+ MODULE_DESCRIPTION("Atheros 803x PHY driver");
+ MODULE_AUTHOR("Matus Ujhelyi");
+ MODULE_LICENSE("GPL");
+ struct at803x_priv {
+       bool phy_reset:1;
++      u32 quirks;
+ };
+ struct at803x_context {
+@@ -141,6 +153,39 @@ static int at803x_disable_tx_delay(struc
+                                    AT803X_DEBUG_TX_CLK_DLY_EN, 0);
+ }
++static inline int at803x_set_vddio_1p8v(struct phy_device *phydev)
++{
++      return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_31, 0,
++                                      AT803X_VDDIO_1P8V_EN);
++}
++
++static int at803x_disable_eee(struct phy_device *phydev)
++{
++      int ret;
++
++      ret = phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
++                                AT803X_DEVICE_ADDR);
++      if (ret < 0)
++              return ret;
++
++      ret = phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
++                                AT803X_SMARTEEE_CTL3_OFFSET);
++      if (ret < 0)
++              return ret;
++
++      ret = phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
++                                AT803X_FUNC_DATA);
++      if (ret < 0)
++              return ret;
++
++      ret = phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
++                                AT803X_SMARTEEE_DISABLED_VAL);
++      if (ret < 0)
++              return ret;
++
++      return 0;
++}
++
+ /* save relevant PHY registers to private copy */
+ static void at803x_context_save(struct phy_device *phydev,
+                               struct at803x_context *context)
+@@ -254,6 +299,12 @@ static int at803x_probe(struct phy_devic
+       if (!priv)
+               return -ENOMEM;
++      if (of_property_read_bool(dev->of_node, "at803x,eee-disabled"))
++              priv->quirks |= AT803X_EEE_FEATURE_DISABLE;
++
++      if (of_property_read_bool(dev->of_node, "at803x,vddio-1p8v"))
++              priv->quirks |= AT803X_VDDIO_1P8V;
++
+       phydev->priv = priv;
+       return 0;
+@@ -275,6 +326,7 @@ static void at803x_enable_smart_eee(stru
+ static int at803x_config_init(struct phy_device *phydev)
+ {
+       int ret;
++      struct at803x_priv *priv = phydev->priv;
+       u32 v;
+       if (phydev->drv->phy_id == ATH8031_PHY_ID &&
+@@ -323,6 +375,18 @@ static int at803x_config_init(struct phy
+       else
+               ret = at803x_disable_tx_delay(phydev);
++      if (priv->quirks & AT803X_VDDIO_1P8V) {
++              ret = at803x_set_vddio_1p8v(phydev);
++              if (ret < 0)
++                      return ret;
++      }
++
++      if (priv->quirks & AT803X_EEE_FEATURE_DISABLE) {
++              ret = at803x_disable_eee(phydev);
++              if (ret < 0)
++                      return ret;
++      }
++
+       return ret;
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0331-drivers-net-phy-aquantia-enable-AQR112-and-AQR412.patch b/target/linux/layerscape/patches-5.4/701-net-0331-drivers-net-phy-aquantia-enable-AQR112-and-AQR412.patch
new file mode 100644 (file)
index 0000000..9140382
--- /dev/null
@@ -0,0 +1,140 @@
+From 5f62951fba63a9f9cfff564209426bdea5fcc371 Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Tue, 27 Aug 2019 15:16:56 +0300
+Subject: [PATCH] drivers: net: phy: aquantia: enable AQR112 and AQR412
+
+Adds support for AQR112 and AQR412 which is mostly based on existing code
+with the addition of code configuring the protocol on system side.
+This allows changing the system side protocol without having to deploy a
+different firmware on the PHY.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ drivers/net/phy/aquantia_main.c | 88 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 88 insertions(+)
+
+--- a/drivers/net/phy/aquantia_main.c
++++ b/drivers/net/phy/aquantia_main.c
+@@ -22,6 +22,8 @@
+ #define PHY_ID_AQR107 0x03a1b4e0
+ #define PHY_ID_AQCS109        0x03a1b5c2
+ #define PHY_ID_AQR405 0x03a1b4b0
++#define PHY_ID_AQR112 0x03a1b662
++#define PHY_ID_AQR412 0x03a1b712
+ #define MDIO_PHYXS_VEND_IF_STATUS             0xe812
+ #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK   GENMASK(7, 3)
+@@ -121,6 +123,29 @@
+ #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2    BIT(1)
+ #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3    BIT(0)
++/* registers in MDIO_MMD_VEND1 region */
++#define AQUANTIA_VND1_GLOBAL_SC                       0x000
++#define  AQUANTIA_VND1_GLOBAL_SC_LP           BIT(0xb)
++
++/* global start rate, the protocol associated with this speed is used by default
++ * on SI.
++ */
++#define AQUANTIA_VND1_GSTART_RATE             0x31a
++#define  AQUANTIA_VND1_GSTART_RATE_OFF                0
++#define  AQUANTIA_VND1_GSTART_RATE_100M               1
++#define  AQUANTIA_VND1_GSTART_RATE_1G         2
++#define  AQUANTIA_VND1_GSTART_RATE_10G                3
++#define  AQUANTIA_VND1_GSTART_RATE_2_5G               4
++#define  AQUANTIA_VND1_GSTART_RATE_5G         5
++
++/* SYSCFG registers for 100M, 1G, 2.5G, 5G, 10G */
++#define AQUANTIA_VND1_GSYSCFG_BASE            0x31b
++#define AQUANTIA_VND1_GSYSCFG_100M            0
++#define AQUANTIA_VND1_GSYSCFG_1G              1
++#define AQUANTIA_VND1_GSYSCFG_2_5G            2
++#define AQUANTIA_VND1_GSYSCFG_5G              3
++#define AQUANTIA_VND1_GSYSCFG_10G             4
++
+ struct aqr107_hw_stat {
+       const char *name;
+       int reg;
+@@ -241,6 +266,51 @@ static int aqr_config_aneg(struct phy_de
+       return genphy_c45_check_and_restart_aneg(phydev, changed);
+ }
++static struct {
++      u16 syscfg;
++      int cnt;
++      u16 start_rate;
++} aquantia_syscfg[PHY_INTERFACE_MODE_MAX] = {
++      [PHY_INTERFACE_MODE_SGMII] =      {0x04b, AQUANTIA_VND1_GSYSCFG_1G,
++                                         AQUANTIA_VND1_GSTART_RATE_1G},
++      [PHY_INTERFACE_MODE_2500BASEX] = {0x144, AQUANTIA_VND1_GSYSCFG_2_5G,
++                                         AQUANTIA_VND1_GSTART_RATE_2_5G},
++      [PHY_INTERFACE_MODE_XGMII] =      {0x100, AQUANTIA_VND1_GSYSCFG_10G,
++                                         AQUANTIA_VND1_GSTART_RATE_10G},
++      [PHY_INTERFACE_MODE_USXGMII] =    {0x080, AQUANTIA_VND1_GSYSCFG_10G,
++                                         AQUANTIA_VND1_GSTART_RATE_10G},
++};
++
++/* Sets up protocol on system side before calling aqr_config_aneg */
++static int aqr_config_aneg_set_prot(struct phy_device *phydev)
++{
++      int if_type = phydev->interface;
++      int i;
++
++      if (!aquantia_syscfg[if_type].cnt)
++              return 0;
++
++      /* set PHY in low power mode so we can configure protocols */
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC,
++                    AQUANTIA_VND1_GLOBAL_SC_LP);
++      mdelay(10);
++
++      /* set the default rate to enable the SI link */
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE,
++                    aquantia_syscfg[if_type].start_rate);
++
++      for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++)
++              phy_write_mmd(phydev, MDIO_MMD_VEND1,
++                            AQUANTIA_VND1_GSYSCFG_BASE + i,
++                            aquantia_syscfg[if_type].syscfg);
++
++      /* wake PHY back up */
++      phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0);
++      mdelay(10);
++
++      return aqr_config_aneg(phydev);
++}
++
+ static int aqr_config_intr(struct phy_device *phydev)
+ {
+       bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED;
+@@ -682,6 +752,22 @@ static struct phy_driver aqr_driver[] =
+       .ack_interrupt  = aqr_ack_interrupt,
+       .read_status    = aqr_read_status,
+ },
++{
++      PHY_ID_MATCH_MODEL(PHY_ID_AQR112),
++      .name           = "Aquantia AQR112",
++      .config_aneg    = aqr_config_aneg_set_prot,
++      .config_intr    = aqr_config_intr,
++      .ack_interrupt  = aqr_ack_interrupt,
++      .read_status    = aqr_read_status,
++},
++{
++      PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
++      .name           = "Aquantia AQR412",
++      .config_aneg    = aqr_config_aneg_set_prot,
++      .config_intr    = aqr_config_intr,
++      .ack_interrupt  = aqr_ack_interrupt,
++      .read_status    = aqr_read_status,
++},
+ };
+ module_phy_driver(aqr_driver);
+@@ -694,6 +780,8 @@ static struct mdio_device_id __maybe_unu
+       { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) },
+       { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) },
+       { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) },
++      { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) },
++      { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) },
+       { }
+ };
diff --git a/target/linux/layerscape/patches-5.4/701-net-0332-drivers-net-phy-aquantia-fix-system-side-protocol-mi.patch b/target/linux/layerscape/patches-5.4/701-net-0332-drivers-net-phy-aquantia-fix-system-side-protocol-mi.patch
new file mode 100644 (file)
index 0000000..2c75ec2
--- /dev/null
@@ -0,0 +1,34 @@
+From 5f008cb22f60da4e10375f22266c1a4e20b1252e Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Fri, 20 Sep 2019 18:22:52 +0300
+Subject: [PATCH] drivers: net: phy: aquantia: fix system side protocol
+ misconfiguration
+
+Do not set up protocols for speeds that are not supported by FW.  Enabling
+these protocols leads to link issues on system side.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ drivers/net/phy/aquantia_main.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/phy/aquantia_main.c
++++ b/drivers/net/phy/aquantia_main.c
+@@ -299,10 +299,16 @@ static int aqr_config_aneg_set_prot(stru
+       phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE,
+                     aquantia_syscfg[if_type].start_rate);
+-      for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++)
++      for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++) {
++              u16 reg = phy_read_mmd(phydev, MDIO_MMD_VEND1,
++                                     AQUANTIA_VND1_GSYSCFG_BASE + i);
++              if (!reg)
++                      continue;
++
+               phy_write_mmd(phydev, MDIO_MMD_VEND1,
+                             AQUANTIA_VND1_GSYSCFG_BASE + i,
+                             aquantia_syscfg[if_type].syscfg);
++      }
+       /* wake PHY back up */
+       phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0333-drivers-net-phy-aquantia-enable-USX-AN-for-USXGMII-p.patch b/target/linux/layerscape/patches-5.4/701-net-0333-drivers-net-phy-aquantia-enable-USX-AN-for-USXGMII-p.patch
new file mode 100644 (file)
index 0000000..472dce9
--- /dev/null
@@ -0,0 +1,37 @@
+From ca49d3e4820704bfc3d2b48f59238d26a584602d Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Fri, 20 Sep 2019 19:37:19 +0300
+Subject: [PATCH] drivers: net: phy: aquantia: enable USX AN for USXGMII
+ protocol
+
+Depending on FW defaults USX AN in AQR PHY must be explicitly enabled when
+using USXGMII.  Enable it based on interface type.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ drivers/net/phy/aquantia_main.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/net/phy/aquantia_main.c
++++ b/drivers/net/phy/aquantia_main.c
+@@ -33,6 +33,9 @@
+ #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII  6
+ #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII        10
++#define MDIO_PHYXS_VEND_PROV2                 0xC441
++#define MDIO_PHYXS_VEND_PROV2_USX_AN          BIT(3)
++
+ #define MDIO_AN_VEND_PROV                     0xc400
+ #define MDIO_AN_VEND_PROV_1000BASET_FULL      BIT(15)
+ #define MDIO_AN_VEND_PROV_1000BASET_HALF      BIT(14)
+@@ -310,6 +313,10 @@ static int aqr_config_aneg_set_prot(stru
+                             aquantia_syscfg[if_type].syscfg);
+       }
++      if (if_type == PHY_INTERFACE_MODE_USXGMII)
++              phy_write_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_VEND_PROV2,
++                            MDIO_PHYXS_VEND_PROV2_USX_AN);
++
+       /* wake PHY back up */
+       phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0);
+       mdelay(10);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0334-net-tsn-netlink-interface-for-APP-layer-to-config-TS.patch b/target/linux/layerscape/patches-5.4/701-net-0334-net-tsn-netlink-interface-for-APP-layer-to-config-TS.patch
new file mode 100644 (file)
index 0000000..33de677
--- /dev/null
@@ -0,0 +1,5113 @@
+From e478ab518612f1a821968e1bb5b08b01b10085b0 Mon Sep 17 00:00:00 2001
+From: Po Liu <Po.Liu@nxp.com>
+Date: Tue, 15 Oct 2019 16:11:40 +0800
+Subject: [PATCH] net:tsn: netlink interface for APP layer to config TSN
+ capability hardware ports
+
+This patch provids netlink method to configure the TSN protocols hardwares.
+TSN guaranteed packet transport with bounded low latency, low packet delay
+variation, and low packet loss by hardware and software methods.
+
+The three basic components of TSN are:
+
+1. Time synchronization: This was implement by 8021AS which base on the
+   IEEE1588 precision Time Protocol. This is configured by the other way
+   in kernel.
+   8021AS not included in this patch.
+
+2. Scheduling and traffic shaping and per-stream filter policing:
+   This patch support Qbv/Qci/Qbu/8021CB/Qav etc.
+
+3. Selection of communication paths:
+   This patch not support the pure software only TSN protocols(like Qcc)
+   but hardware related configuration.
+
+TSN Protocols supports by this patch: Qbv/Qci/Qbu/Credit-base Shaper(Qav).
+This patch verified on NXP ls1028ardb board.
+
+Signed-off-by: Po Liu <Po.Liu@nxp.com>
+---
+ include/net/tsn.h        |  114 ++
+ include/uapi/linux/tsn.h | 1207 +++++++++++++++
+ net/Kconfig              |    1 +
+ net/Makefile             |    3 +
+ net/tsn/Kconfig          |   15 +
+ net/tsn/Makefile         |    1 +
+ net/tsn/genl_tsn.c       | 3696 ++++++++++++++++++++++++++++++++++++++++++++++
+ 7 files changed, 5037 insertions(+)
+ create mode 100644 include/net/tsn.h
+ create mode 100644 include/uapi/linux/tsn.h
+ create mode 100644 net/tsn/Kconfig
+ create mode 100644 net/tsn/Makefile
+ create mode 100644 net/tsn/genl_tsn.c
+
+--- /dev/null
++++ b/include/net/tsn.h
+@@ -0,0 +1,114 @@
++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
++/* Copyright 2017-2019 NXP */
++
++#ifndef __TSN_H__
++#define __TSN_H__
++
++#include <linux/notifier.h>
++#include <uapi/linux/tsn.h>
++
++enum tsn_notifier_type {
++      TSN_QBV_CONFIGCHANGETIME_ARRIVE = 1,
++};
++
++struct tsn_notifier_info {
++      struct net_device *dev;
++      union {
++              struct tsn_qbv_conf qbv_notify;
++              struct tsn_qci_psfp_sgi_conf qci_notify;
++      } ntdata;
++};
++
++static inline struct net_device *
++tsn_notifier_info_to_dev(const struct tsn_notifier_info *info)
++{
++      return info->dev;
++}
++
++struct tsn_ops {
++      void (*device_init)(struct net_device *ndev);
++      void (*device_deinit)(struct net_device *ndev);
++      u32 (*get_capability)(struct net_device *ndev);
++      /* Qbv standard */
++      int (*qbv_set)(struct net_device *ndev, struct tsn_qbv_conf *qbvconf);
++      int (*qbv_get)(struct net_device *ndev, struct tsn_qbv_conf *qbvconf);
++      int (*qbv_get_status)(struct net_device *ndev,
++                              struct tsn_qbv_status *qbvstat);
++      int (*cb_streamid_set)(struct net_device *ndev, u32 index,
++                              bool enable, struct tsn_cb_streamid *sid);
++      int (*cb_streamid_get)(struct net_device *ndev, u32 index,
++                              struct tsn_cb_streamid *sid);
++      int (*cb_streamid_counters_get)(struct net_device *ndev, u32 index,
++                              struct tsn_cb_streamid_counters *sidcounter);
++      int (*qci_get_maxcap)(struct net_device *ndev,
++                              struct tsn_qci_psfp_stream_param *qcicapa);
++      int (*qci_sfi_set)(struct net_device *ndev, u32 index, bool enable,
++                              struct tsn_qci_psfp_sfi_conf *sficonf);
++      /* return: 0 stream filter instance not valid
++       * 1 stream filter instance valid
++       * -1 error happened
++       */
++      int (*qci_sfi_get)(struct net_device *ndev, u32 index,
++                              struct tsn_qci_psfp_sfi_conf *sficonf);
++      int (*qci_sfi_counters_get)(struct net_device *ndev, u32 index,
++                              struct tsn_qci_psfp_sfi_counters *sficounter);
++      int (*qci_sgi_set)(struct net_device *ndev, u32 index,
++                              struct tsn_qci_psfp_sgi_conf *sgiconf);
++      int (*qci_sgi_get)(struct net_device *ndev, u32 index,
++                              struct tsn_qci_psfp_sgi_conf *sgiconf);
++      int (*qci_sgi_status_get)(struct net_device *ndev, u16 index,
++                              struct tsn_psfp_sgi_status *sgistat);
++      int (*qci_fmi_set)(struct net_device *ndev, u32 index, bool enable,
++                              struct tsn_qci_psfp_fmi *fmi);
++      int (*qci_fmi_get)(struct net_device *ndev, u32 index,
++                              struct tsn_qci_psfp_fmi *fmi,
++                              struct tsn_qci_psfp_fmi_counters *counters);
++      int (*cbs_set)(struct net_device *ndev, u8 tc, u8 bw);
++      int (*cbs_get)(struct net_device *ndev, u8 tc);
++      /* To set a 8 bits vector shows 8 traffic classes
++       * preemtable(1) or express(0)
++       */
++      int (*qbu_set)(struct net_device *ndev, u8 ptvector);
++      /* To get port preemtion status */
++      int (*qbu_get)(struct net_device *ndev,
++                              struct tsn_preempt_status *preemptstat);
++      int (*tsd_set)(struct net_device *ndev, struct tsn_tsd *tsd);
++      int (*tsd_get)(struct net_device *ndev, struct tsn_tsd_status *stats);
++      int (*ct_set)(struct net_device *ndev, u8 cut_thru);
++      int (*cbgen_set)(struct net_device *ndev, u32 index,
++                       struct tsn_seq_gen_conf *seqgen);
++      int (*cbrec_set)(struct net_device *ndev, u32 index,
++                       struct tsn_seq_rec_conf *seqrec);
++      int (*cb_get)(struct net_device *ndev, u32 index,
++                    struct tsn_cb_status  *c);
++      int (*dscp_set)(struct net_device *ndev, bool enable,
++                      const u8 dscp_ix,
++                      struct tsn_qos_switch_dscp_conf *c);
++};
++
++enum ethdev_type {
++      TSN_SWITCH,
++      TSN_ENDPOINT,
++};
++
++#define GROUP_OFFSET_SWITCH 256
++
++struct tsn_port {
++      u16 groupid;
++      struct tsn_ops *tsnops;
++      struct net_device *netdev;
++      struct list_head list;
++      enum ethdev_type type;
++      u8 tc_nums;
++      struct tsn_notifier_info nd;
++};
++
++struct tsn_port *tsn_get_port(struct net_device *ndev);
++int register_tsn_notifier(struct notifier_block *nb);
++int unregister_tsn_notifier(struct notifier_block *nb);
++int call_tsn_notifiers(unsigned long val, struct net_device *dev,
++                           struct tsn_notifier_info *info);
++int tsn_port_register(struct net_device *netdev,
++                              struct tsn_ops *tsnops, u16 groupid);
++void tsn_port_unregister(struct net_device *netdev);
++#endif
+--- /dev/null
++++ b/include/uapi/linux/tsn.h
+@@ -0,0 +1,1207 @@
++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
++/* Copyright 2017-2019 NXP */
++
++#ifndef __UAPI_GENL_TSN_H
++#define __UAPI_GENL_TSN_H
++
++#define       TSN_GENL_NAME           "TSN_GEN_CTRL"
++#define       TSN_GENL_VERSION        0x1
++
++#define MAX_USER_SIZE 0
++#define MAX_ATTR_SIZE 3072
++#define MAX_TOTAL_MSG_SIZE  (MAX_USER_SIZE + MAX_ATTR_SIZE)
++#define MAX_ENTRY_SIZE 2048
++#define MAX_ENTRY_NUMBER 128
++#define MAX_IFNAME_COUNT 64
++
++#define TSN_MULTICAST_GROUP_QBV       "qbv"
++#define TSN_MULTICAST_GROUP_QCI       "qci"
++
++/* multicast groups */
++enum tsn_multicast_groups {
++      TSN_MCGRP_QBV,
++      TSN_MCGRP_QCI,
++      TSN_MCGRP_MAX
++};
++
++enum tsn_capability {
++      TSN_CAP_QBV = 0x1,
++      TSN_CAP_QCI = 0x2,
++      TSN_CAP_QBU = 0x4,
++      TSN_CAP_CBS = 0x8, /* Credit-based Shapter Qav */
++      TSN_CAP_CB  = 0x10, /* 8021CB redundancy and replication */
++      TSN_CAP_TBS = 0x20, /* Time Based schedule */
++      TSN_CAP_CTH = 0x40, /* cut through */
++};
++
++/*
++ * Commands sent from userspace
++ * Not versioned. New commands should only be inserted at the enum's end
++ * prior to __TSN_CMD_MAX
++ */
++
++enum {
++      TSN_CMD_UNSPEC = 0,     /* Reserved */
++      TSN_CMD_QBV_SET,
++      TSN_CMD_QBV_GET,
++      TSN_CMD_QBV_GET_STATUS,
++      TSN_CMD_CB_STREAMID_SET,
++      TSN_CMD_CB_STREAMID_GET,
++      TSN_CMD_CB_STREAMID_GET_COUNTS,
++      TSN_CMD_QCI_CAP_GET, /* Qci capability get length capability get */
++      TSN_CMD_QCI_SFI_SET,
++      TSN_CMD_QCI_SFI_GET,
++      TSN_CMD_QCI_SFI_GET_COUNTS,
++      TSN_CMD_QCI_SGI_SET,
++      TSN_CMD_QCI_SGI_GET,
++      TSN_CMD_QCI_SGI_GET_STATUS,
++      TSN_CMD_QCI_FMI_SET,
++      TSN_CMD_QCI_FMI_GET,
++      TSN_CMD_CBS_SET,
++      TSN_CMD_CBS_GET,
++      TSN_CMD_QBU_SET,
++      TSN_CMD_QBU_GET_STATUS,
++      TSN_CMD_QAV_SET_CBS,
++      TSN_CMD_QAV_GET_CBS,
++      TSN_CMD_TSD_SET,
++      TSN_CMD_TSD_GET,
++      TSN_CMD_CT_SET,
++      TSN_CMD_CBGEN_SET,
++      TSN_CMD_CBREC_SET,
++      TSN_CMD_CBSTAT_GET,
++      TSN_CMD_PCPMAP_SET_UNUSE,
++      TSN_CMD_DSCP_SET,
++      TSN_CMD_ECHO,                   /* user->kernel request/get-response */
++      TSN_CMD_REPLY,                  /* kernel->user event */
++      TSN_CMD_CAP_GET,
++      __TSN_CMD_MAX,
++};
++#define TSN_CMD_MAX (__TSN_CMD_MAX - 1)
++
++
++enum {
++      TSN_CMD_ATTR_UNSPEC = 0,
++      TSN_CMD_ATTR_MESG,              /* demo message  */
++      TSN_CMD_ATTR_DATA,              /* demo data */
++      TSN_ATTR_IFNAME,
++      TSN_ATTR_PORT_NUMBER,
++      TSN_ATTR_QBV,
++      TSN_ATTR_STREAM_IDENTIFY, /* stream identify */
++      TSN_ATTR_QCI_SP,                /* psfp port capbility parameters */
++      TSN_ATTR_QCI_SFI,               /* psfp stream filter instance */
++      TSN_ATTR_QCI_SGI,               /* psfp stream gate instance */
++      TSN_ATTR_QCI_FMI,               /* psfp flow meter instance */
++      TSN_ATTR_CBS,                   /* credit-based shaper */
++      TSN_ATTR_TSD,                   /* Time Specific Departure */
++      TSN_ATTR_QBU,                   /* preemption */
++      TSN_ATTR_CT,                    /* cut through */
++      TSN_ATTR_CBGEN,                 /* 802.1CB sequence generate */
++      TSN_ATTR_CBREC,                 /* 802.1CB sequence recover */
++      TSN_ATTR_CBSTAT,                 /* 802.1CB status */
++      TSN_ATTR_PCPMAP_UNUSE,
++      TSN_ATTR_DSCP,
++      TSN_ATTR_CAP,           /* TSN capbility */
++      __TSN_CMD_ATTR_MAX,
++};
++#define TSN_CMD_ATTR_MAX (__TSN_CMD_ATTR_MAX - 1)
++
++enum {
++      TSN_CAP_ATTR_UNSPEC,
++      TSN_CAP_ATTR_QBV,
++      TSN_CAP_ATTR_QCI,
++      TSN_CAP_ATTR_QBU,
++      TSN_CAP_ATTR_CBS,
++      TSN_CAP_ATTR_CB,
++      TSN_CAP_ATTR_TBS,
++      TSN_CAP_ATTR_CTH,
++      __TSN_CAP_ATTR_MAX,
++      TSN_CAP_ATTR_MAX = __TSN_CAP_ATTR_MAX - 1,
++};
++
++enum {
++      TSN_QBU_ATTR_UNSPEC,
++      TSN_QBU_ATTR_ADMIN_STATE,
++      TSN_QBU_ATTR_HOLD_ADVANCE,
++      TSN_QBU_ATTR_RELEASE_ADVANCE,
++      TSN_QBU_ATTR_ACTIVE,
++      TSN_QBU_ATTR_HOLD_REQUEST,
++      __TSN_QBU_ATTR_MAX,
++      TSN_QBU_ATTR_MAX = __TSN_QBU_ATTR_MAX - 1,
++};
++
++enum {
++      TSN_CBS_ATTR_UNSPEC,
++      TSN_CBS_ATTR_TC_INDEX,
++      TSN_CBS_ATTR_BW,
++      __TSN_CBS_ATTR_MAX,
++      TSN_CBS_ATTR_MAX = __TSN_CBS_ATTR_MAX - 1,
++};
++
++enum {
++      TSN_TSD_ATTR_UNSPEC,
++      TSN_TSD_ATTR_DISABLE,
++      TSN_TSD_ATTR_ENABLE,
++      TSN_TSD_ATTR_PERIOD,
++      TSN_TSD_ATTR_MAX_FRM_NUM,
++      TSN_TSD_ATTR_CYCLE_NUM,
++      TSN_TSD_ATTR_LOSS_STEPS,
++      TSN_TSD_ATTR_SYN_IMME,
++      __TSN_TSD_ATTR_MAX,
++      TSN_TSD_ATTR_MAX = __TSN_TSD_ATTR_MAX - 1,
++};
++
++enum {
++      TSN_STREAMID_ATTR_UNSPEC,
++      TSN_STREAMID_ATTR_INDEX,
++      TSN_STREAMID_ATTR_ENABLE,
++      TSN_STREAMID_ATTR_DISABLE,
++      TSN_STREAMID_ATTR_STREAM_HANDLE,
++      TSN_STREAMID_ATTR_IFOP,
++      TSN_STREAMID_ATTR_OFOP,
++      TSN_STREAMID_ATTR_IFIP,
++      TSN_STREAMID_ATTR_OFIP,
++      TSN_STREAMID_ATTR_TYPE,
++      TSN_STREAMID_ATTR_NDMAC,
++      TSN_STREAMID_ATTR_NTAGGED,
++      TSN_STREAMID_ATTR_NVID,
++      TSN_STREAMID_ATTR_SMAC,
++      TSN_STREAMID_ATTR_STAGGED,
++      TSN_STREAMID_ATTR_SVID,
++      TSN_STREAMID_ATTR_COUNTERS_PSI,
++      TSN_STREAMID_ATTR_COUNTERS_PSO,
++      TSN_STREAMID_ATTR_COUNTERS_PSPPI,
++      TSN_STREAMID_ATTR_COUNTERS_PSPPO,
++      __TSN_STREAMID_ATTR_MAX,
++      TSN_STREAMID_ATTR_MAX = __TSN_STREAMID_ATTR_MAX - 1,
++};
++
++enum {
++      TSN_QCI_STREAM_ATTR_UNSPEC = 0,
++      TSN_QCI_STREAM_ATTR_MAX_SFI,
++      TSN_QCI_STREAM_ATTR_MAX_SGI,
++      TSN_QCI_STREAM_ATTR_MAX_FMI,
++      TSN_QCI_STREAM_ATTR_SLM,
++      __TSN_QCI_STREAM_ATTR_MAX,
++      TSN_QCI_STREAM_ATTR_MAX = __TSN_QCI_STREAM_ATTR_MAX - 1,
++};
++
++enum {
++      TSN_QCI_SFI_ATTR_UNSPEC = 0,
++      TSN_QCI_SFI_ATTR_INDEX,
++      TSN_QCI_SFI_ATTR_ENABLE,
++      TSN_QCI_SFI_ATTR_DISABLE,
++      TSN_QCI_SFI_ATTR_STREAM_HANDLE,
++      TSN_QCI_SFI_ATTR_PRIO_SPEC,
++      TSN_QCI_SFI_ATTR_GATE_ID,
++      TSN_QCI_SFI_ATTR_FILTER_TYPE,
++      TSN_QCI_SFI_ATTR_FLOW_ID,
++      TSN_QCI_SFI_ATTR_MAXSDU,
++      TSN_QCI_SFI_ATTR_COUNTERS,
++      TSN_QCI_SFI_ATTR_OVERSIZE_ENABLE,
++      TSN_QCI_SFI_ATTR_OVERSIZE,
++      __TSN_QCI_SFI_ATTR_MAX,
++      TSN_QCI_SFI_ATTR_MAX = __TSN_QCI_SFI_ATTR_MAX - 1,
++};
++
++enum {
++      TSN_QCI_SFI_ATTR_COUNTERS_UNSPEC = 0,
++      TSN_QCI_SFI_ATTR_MATCH,
++      TSN_QCI_SFI_ATTR_PASS,
++      TSN_QCI_SFI_ATTR_DROP,
++      TSN_QCI_SFI_ATTR_SDU_DROP,
++      TSN_QCI_SFI_ATTR_SDU_PASS,
++      TSN_QCI_SFI_ATTR_RED,
++      __TSN_QCI_SFI_ATTR_COUNT_MAX,
++      TSN_QCI_SFI_ATTR_COUNT_MAX = __TSN_QCI_SFI_ATTR_COUNT_MAX - 1,
++};
++
++enum {
++      TSN_QCI_SGI_ATTR_UNSPEC = 0,
++      TSN_QCI_SGI_ATTR_INDEX,
++      TSN_QCI_SGI_ATTR_ENABLE,
++      TSN_QCI_SGI_ATTR_DISABLE,
++      TSN_QCI_SGI_ATTR_CONFCHANGE,
++      TSN_QCI_SGI_ATTR_IRXEN,         /* Invalid rx enable*/
++      TSN_QCI_SGI_ATTR_IRX,
++      TSN_QCI_SGI_ATTR_OEXEN,         /* Octet exceed enable */
++      TSN_QCI_SGI_ATTR_OEX,
++      TSN_QCI_SGI_ATTR_ADMINENTRY,
++      TSN_QCI_SGI_ATTR_OPERENTRY,
++      TSN_QCI_SGI_ATTR_CCTIME,        /* config change time */
++      TSN_QCI_SGI_ATTR_TICKG,
++      TSN_QCI_SGI_ATTR_CUTIME,
++      TSN_QCI_SGI_ATTR_CPENDING,
++      TSN_QCI_SGI_ATTR_CCERROR,
++      __TSN_QCI_SGI_ATTR_MAX,
++      TSN_QCI_SGI_ATTR_MAX = __TSN_QCI_SGI_ATTR_MAX - 1,
++};
++
++enum {
++      TSN_SGI_ATTR_CTRL_UNSPEC = 0,
++      TSN_SGI_ATTR_CTRL_INITSTATE,
++      TSN_SGI_ATTR_CTRL_LEN,
++      TSN_SGI_ATTR_CTRL_CYTIME,
++      TSN_SGI_ATTR_CTRL_CYTIMEEX,
++      TSN_SGI_ATTR_CTRL_BTIME,
++      TSN_SGI_ATTR_CTRL_INITIPV,
++      TSN_SGI_ATTR_CTRL_GCLENTRY,
++      __TSN_SGI_ATTR_CTRL_MAX,
++      TSN_SGI_ATTR_CTRL_MAX = __TSN_SGI_ATTR_CTRL_MAX - 1,
++};
++
++enum {
++      TSN_SGI_ATTR_GCL_UNSPEC = 0,
++      TSN_SGI_ATTR_GCL_GATESTATE,
++      TSN_SGI_ATTR_GCL_IPV,
++      TSN_SGI_ATTR_GCL_INTERVAL,
++      TSN_SGI_ATTR_GCL_OCTMAX,
++      __TSN_SGI_ATTR_GCL_MAX,
++      TSN_SGI_ATTR_GCL_MAX = __TSN_SGI_ATTR_GCL_MAX - 1,
++};
++
++enum {
++      TSN_QCI_FMI_ATTR_UNSPEC = 0,
++      TSN_QCI_FMI_ATTR_INDEX,
++      TSN_QCI_FMI_ATTR_ENABLE,
++      TSN_QCI_FMI_ATTR_DISABLE,
++      TSN_QCI_FMI_ATTR_CIR,
++      TSN_QCI_FMI_ATTR_CBS,
++      TSN_QCI_FMI_ATTR_EIR,
++      TSN_QCI_FMI_ATTR_EBS,
++      TSN_QCI_FMI_ATTR_CF,
++      TSN_QCI_FMI_ATTR_CM,
++      TSN_QCI_FMI_ATTR_DROPYL,
++      TSN_QCI_FMI_ATTR_MAREDEN,
++      TSN_QCI_FMI_ATTR_MARED,
++      TSN_QCI_FMI_ATTR_COUNTERS,
++      __TSN_QCI_FMI_ATTR_MAX,
++      TSN_QCI_FMI_ATTR_MAX = __TSN_QCI_FMI_ATTR_MAX - 1,
++};
++
++enum {
++      TSN_QBV_ATTR_UNSPEC,
++      TSN_QBV_ATTR_ENABLE,
++      TSN_QBV_ATTR_DISABLE,
++      TSN_QBV_ATTR_CONFIGCHANGE,
++      TSN_QBV_ATTR_CONFIGCHANGETIME,
++      TSN_QBV_ATTR_MAXSDU,
++      TSN_QBV_ATTR_GRANULARITY,
++      TSN_QBV_ATTR_CURRENTTIME,
++      TSN_QBV_ATTR_CONFIGPENDING,
++      TSN_QBV_ATTR_CONFIGCHANGEERROR,
++      TSN_QBV_ATTR_ADMINENTRY,
++      TSN_QBV_ATTR_OPERENTRY,
++      TSN_QBV_ATTR_LISTMAX,
++      __TSN_QBV_ATTR_MAX,
++      TSN_QBV_ATTR_MAX = __TSN_QBV_ATTR_MAX - 1,
++};
++
++enum {
++      TSN_QBV_ATTR_CTRL_UNSPEC,
++      TSN_QBV_ATTR_CTRL_LISTCOUNT,
++      TSN_QBV_ATTR_CTRL_GATESTATE,
++      TSN_QBV_ATTR_CTRL_CYCLETIME,
++      TSN_QBV_ATTR_CTRL_CYCLETIMEEXT,
++      TSN_QBV_ATTR_CTRL_BASETIME,
++      TSN_QBV_ATTR_CTRL_LISTENTRY,
++      __TSN_QBV_ATTR_CTRL_MAX,
++      TSN_QBV_ATTR_CTRL_MAX = __TSN_QBV_ATTR_CTRL_MAX - 1,
++};
++
++enum {
++      TSN_QBV_ATTR_ENTRY_UNSPEC,
++      TSN_QBV_ATTR_ENTRY_ID,
++      TSN_QBV_ATTR_ENTRY_GC,
++      TSN_QBV_ATTR_ENTRY_TM,
++      __TSN_QBV_ATTR_ENTRY_MAX,
++      TSN_QBV_ATTR_ENTRY_MAX = __TSN_QBV_ATTR_ENTRY_MAX - 1,
++};
++
++enum {
++      TSN_CT_ATTR_UNSPEC,
++      TSN_CT_ATTR_QUEUE_STATE,
++      __TSN_CT_ATTR_MAX,
++      TSN_CT_ATTR_MAX = __TSN_CT_ATTR_MAX - 1,
++};
++
++enum {
++      TSN_CBGEN_ATTR_UNSPEC,
++      TSN_CBGEN_ATTR_INDEX,
++      TSN_CBGEN_ATTR_PORT_MASK,
++      TSN_CBGEN_ATTR_SPLIT_MASK,
++      TSN_CBGEN_ATTR_SEQ_LEN,
++      TSN_CBGEN_ATTR_SEQ_NUM,
++      __TSN_CBGEN_ATTR_MAX,
++      TSN_CBGEN_ATTR_MAX = __TSN_CBGEN_ATTR_MAX - 1,
++};
++
++enum {
++      TSN_CBREC_ATTR_UNSPEC,
++      TSN_CBREC_ATTR_INDEX,
++      TSN_CBREC_ATTR_SEQ_LEN,
++      TSN_CBREC_ATTR_HIS_LEN,
++      TSN_CBREC_ATTR_TAG_POP_EN,
++      __TSN_CBREC_ATTR_MAX,
++      TSN_CBREC_ATTR_MAX = __TSN_CBREC_ATTR_MAX - 1,
++};
++
++enum {
++      TSN_CBSTAT_ATTR_UNSPEC,
++      TSN_CBSTAT_ATTR_INDEX,
++      TSN_CBSTAT_ATTR_GEN_REC,
++      TSN_CBSTAT_ATTR_ERR,
++      TSN_CBSTAT_ATTR_SEQ_NUM,
++      TSN_CBSTAT_ATTR_SEQ_LEN,
++      TSN_CBSTAT_ATTR_SPLIT_MASK,
++      TSN_CBSTAT_ATTR_PORT_MASK,
++      TSN_CBSTAT_ATTR_HIS_LEN,
++      TSN_CBSTAT_ATTR_SEQ_HIS,
++      __TSN_CBSTAT_ATTR_MAX,
++      TSN_CBSTAT_ATTR_MAX = __TSN_CBSTAT_ATTR_MAX - 1,
++};
++
++enum {
++      TSN_DSCP_ATTR_UNSPEC,
++      TSN_DSCP_ATTR_DISABLE,
++      TSN_DSCP_ATTR_INDEX,
++      TSN_DSCP_ATTR_COS,
++      TSN_DSCP_ATTR_DPL,
++      __TSN_DSCP_ATTR_MAX,
++      TSN_DSCP_ATTR_MAX = __TSN_DSCP_ATTR_MAX - 1,
++};
++
++#define ptptime_t __u64
++
++#define MAX_QUEUE_CNT 8
++
++struct tsn_preempt_status {
++      /* The value of admin_state shows a 8-bits vector value for showing
++       * the framePreemptionAdminStatus parameter and PreemptionPriority
++       * for the traffic class. Bit-7 is the highest priority traffic class
++       * and the bit-0 is the lowest priority traffic class.
++       * The bit is express (0) and is preemptible (1).
++       */
++      __u8 admin_state;
++      /* The value of the holdAdvance parameter for the port in nanoseconds.
++       * There is no default value; the holdAdvance is a property of the
++       * underlying MAC." This parameter corresponds to the holdAdvance
++       * parameter in 802.1Qbu.
++       */
++      __u32 hold_advance;
++
++      /* The value of the releaseAdvance parameter for the port in
++       * nanoseconds.  There is no default value; the releaseAdvance is a
++       * property of the underlying MAC." This parameter corresponds to the
++       * releaseAdvance parameter in 802.1Qbu.
++       */
++      __u32 release_advance;
++
++      /* The value is active (TRUE) when preemption is operationally active
++       * for the port, and idle (FALSE) otherwise.  This parameter corresponds
++       * to the preemptionActive parameter in 802.1Qbu.
++       */
++      __u8 preemption_active;
++
++      /* The value is hold (1) when the sequence of gate operations for
++       * the port has executed a Set-And-Hold-MAC operation, and release
++       * (2) when the sequence of gate operations has executed a
++       * Set-And-Release-MAC operation. The value of this object is release
++       * (FALSE) on system initialization.  This parameter corresponds to the
++       * holdRequest parameter in 802.1Qbu.
++       */
++      __u8 hold_request;
++};
++
++enum tsn_tx_mode  {
++      TX_MODE_STRICT,
++      TX_MODE_CBS,
++      TX_MODE_ETS,
++      TX_MODE_VENDOR_DEFINE = 255,
++};
++
++#define QUEUE_TX_MASK ((1 << TX_MODE_STRICT) | (1 << TX_MODE_CBS) \
++                      | (1 << TX_MODE_ETS) | (1 << TX_MODE_VENDOR_DEFINE))
++
++struct cbs_status {
++      __u8 delta_bw; /* percentage, 0~100 */
++      __u32 idleslope;
++      __s32 sendslope;
++      __u32 maxframesize;
++      __u32 hicredit;
++      __s32 locredit;
++      __u32 maxninference;
++};
++
++struct tx_queue {
++      /* tx_queue_capbility shows the queue's capability mask.
++       * refer the enum tsn_tx_mode
++       */
++      __u8 capability;
++
++      /* tx_queue_mode is current queue working mode */
++      __u8 mode;
++
++      /* prio is showing the queue priority */
++      __u8 prio;
++
++      /* mstat shows the status data of cbs or priority */
++      union {
++              struct cbs_status cbs;
++      };
++};
++
++struct port_status {
++      /* txqueue_cnt shows how many queues in this port */
++      __u8 queue_cnt;
++
++      /* max_rate(Mbit/s) is the port transmit rate current port is setting */
++      __u32 max_rate;
++
++      /* tsn_capability mask the tsn capability */
++      __u32 tsn_capability;
++};
++
++enum tsn_cb_streamid_type {
++      STREAMID_RESERVED = 0,
++      /* Null Stream identification */
++      STREAMID_NULL,
++      /* Source MAC and VLAN Stream identification */
++      STREAMID_SMAC_VLAN,
++      /* Active Destination MAC and VLAN stream identification */
++      STREAMID_DMAC_VLAN,
++      /* IP stream identification */
++      STREAMID_IP,
++};
++
++/* When instantiating an instance of the Null Stream identification function
++ * 8021CB(6.4) for a particular input Stream, the managed objects in the
++ * following subsections serve as the tsnStreamIdParameters managed object
++ * 8021CB claus(9.1.1.7).
++ */
++struct tsn_cb_null_streamid {
++      /* tsnCpeNullDownDestMac. Specifies the destination_address that
++       * identifies a packet in an Enhanced Internal Sublayer Service (EISS)
++       * indication primitive, to the Null Stream identification function.
++       */
++      __u64 dmac;
++
++      /* tsnCpeNullDownTagged. It can take the following values:
++       * 1 tagged: A frame must have a VLAN tag to be recognized as belonging
++       * to the Stream.
++       * 2 priority: A frame must be untagged, or have a VLAN tag with a VLAN
++       * ID = 0 to be recognized as belonging to the Stream.
++       * 3 all: A frame is recognized as belonging to the Stream whether
++       * tagged or not.
++       */
++      __u8 tagged;
++
++      /* tsnCpeNullDownVlan. Specifies the vlan_identifier parameter that
++       * identifies a packet in an EISS indication primitive to the Null
++       * Stream identification function. A value of 0 indicates that the vlan
++       * _identifier parameter is ignored on EISS indication primitives.
++       */
++      __u16 vid;
++};
++
++struct tsn_cb_source_streamid {
++      __u64 smac;
++      __u8 tagged;
++      __u16 vid;
++};
++
++struct tsn_cb_dest_streamid {
++      __u64 down_dmac;
++      __u8 down_tagged;
++      __u16 down_vid;
++      __u8 down_prio;
++      __u64 up_dmac;
++      __u8 up_tagged;
++      __u16 up_vid;
++      __u8 up_prio;
++};
++
++struct tsn_cb_ip_streamid {
++      __u64 dmac;
++      __u8 tagged;
++      __u16 vid;
++      __u64 siph;
++      __u64 sipl;
++      __u64 diph;
++      __u64 dipl;
++      __u8 dscp;
++      __u8 npt;
++      __u16 sport;
++      __u16 dport;
++};
++
++/* 802.1CB stream identify table clause 9.1 */
++struct tsn_cb_streamid {
++      /* The objects in a given entry of the Stream identity table are used
++       * to control packets whose stream_handle subparameter is equal to the
++       * entry tsnStreamIdHandle object.
++       */
++      __s32 handle;
++
++      /* The list of ports on which an in-facing Stream identification
++       * function in the output (towards the system forwarding function)
++       * direction Only Active Destination MAC and VLAN Stream identification
++       * (or nothing) can be configured.
++       */
++      __u32 ifac_oport;
++
++      /* The list of ports on which an out-facing Stream identification
++       * function in the output (towards the physical interface) direction.
++       * Only Active Destination MAC and VLAN Stream identification
++       * (or nothing) can be configured.
++       */
++      __u32 ofac_oport;
++
++      /* The list of ports on which an in-facing Stream identification
++       * function in the input (coming from the system forwarding function)
++       * direction
++       */
++      __u32 ifac_iport;
++
++      /* The list of ports on which an out-facing Stream identification
++       * function in the input (coming from the physical interface) direction
++       * .
++       */
++      __u32 ofac_iport;
++
++      /* An enumerated value indicating the method used to identify packets
++       * belonging to the Stream.
++       * The Organizationally Unique Identifier (OUI) or Company Identifier
++       * (CID) to identify the organization defining the enumerated type
++       * should be: 00-80-C2
++       * 1: null stream identification
++       * 2: source mac and vlan stream identification
++       * 3: activ destination mac and vlan stream identification
++       * 4: ip stream identifaciton
++       */
++      __u8 type;
++
++      /* tsnStreamIdParameters The number of controlling parameters for a
++       * Stream identification method, their types and values, are specific
++       * to the tsnStreamIdIdentificationType
++       */
++      union {
++              struct tsn_cb_null_streamid nid;
++              struct tsn_cb_source_streamid sid;
++              struct tsn_cb_dest_streamid did;
++              struct tsn_cb_ip_streamid iid;
++      } para;
++};
++
++/* Following counters are instantiated for each port on which the Stream
++ * identification function (6.2) is configured. The counters are indexed by
++ * port number, facing (in-facing or out-facing), and stream_handle value
++ * (tsnStreamIdHandle, 9.1.1.1).
++ */
++struct tsn_cb_streamid_counters {
++      struct {
++              __u64 input;
++              __u64 output;
++      } per_stream;
++
++      struct {
++              __u64 input;
++              __u64 output;
++      } per_streamport[32];
++};
++
++/* 802.1Qci Stream Parameter Table, read from port */
++struct tsn_qci_psfp_stream_param {
++      /* MaxStreamFilterInstances.
++       * The maximum number of Stream Filter instances supported by this
++       * Bridge component.
++       */
++      __s32 max_sf_instance;
++
++      /* MaxStreamGateInstances
++       * The maximum number of Stream Gate instances supported by this Bridge
++       * component.
++       */
++      __s32 max_sg_instance;
++
++      /* MaxFlowMeterInstances
++       * The maximum number of Flow Meter instances supported by this Bridge
++       * component.
++       */
++      __s32 max_fm_instance;
++
++      /* SupportedListMax
++       * The maximum value supported by this Bridge component of the
++       * AdminControlListLength and OperControlListLength parameters.
++       */
++      __s32 supported_list_max;
++};
++
++/* 802.1Qci Stream Filter Instance Table, counters part only. */
++struct tsn_qci_psfp_sfi_counters {
++      /* The MatchingFramesCount counter counts received frames that match
++       * this stream filter.
++       */
++      __u64 matching_frames_count;
++
++      /* The PassingFramesCount counter counts received frames that pass the
++       * gate associated with this stream filter.
++       */
++      __u64 passing_frames_count;
++
++      /* The NotPassingFramesCount counter counts received frames that do not
++       * pass the gate associated with this stream filter.
++       */
++      __u64 not_passing_frames_count;
++
++      /* The PassingSDUCount counter counts received frames that pass the SDU
++       * size filter specification associated with this stream filter.
++       */
++      __u64 passing_sdu_count;
++
++      /* The NotPassingSDUCount counter counts received frames that do not
++       * pass the SDU size filter specification associated with this stream
++       * filter.
++       */
++      __u64 not_passing_sdu_count;
++
++      /* The  REDFramesCount counter counts received random early detection
++       * (RED) frames associated with this stream filter.
++       */
++      __u64 red_frames_count;
++};
++
++/* 802.1Qci Stream Filter Instance Table, configuration part only. */
++struct tsn_qci_psfp_sfi_conf {
++
++      /* The StreamHandleSpec parameter contains a stream identifier
++       * specification value. A value of -1 denotes the wild card value; zero
++       * or positive values denote stream identifier values.
++       */
++      __s32 stream_handle_spec;
++
++      /* The PrioritySpec parameter contains a priority specification value.
++       * A value of -1 denotes the wild card value; zero or positive values
++       * denote priority values.
++       */
++      __s8 priority_spec;
++
++      /* The StreamGateInstanceID parameter contains the index of an entry in
++       * the Stream Gate Table.
++       */
++      __u32 stream_gate_instance_id;
++
++      /* The filter specifications. The actions specified in a filter
++       * specification can result in a frame passing or failing the specified
++       * filter. Frames that fail a filter are discarded.
++       */
++      struct {
++              /* The MaximumSDUSize parameter specifies the maximum allowed
++               * frame size for the stream. Any frame exceeding this value
++               * will be dropped.  A value of 0 denote that the MaximumSDUSize
++               * filter is disabled for this stream.
++               */
++              __u16 maximum_sdu_size;
++
++              /* The FlowMeterInstanceID parameter contains the index of an
++               * entry in the Flow Meter Table.  A value of -1 denotes that
++               * no flow meter is assigned; zero or positive values denote
++               * flow meter IDs.
++               */
++              __s32 flow_meter_instance_id;
++      } stream_filter;
++
++      /* The StreamBlockedDueToOversizeFrameEnable object contains a Boolean
++       * value that indicates whether the StreamBlockedDueToOversizeFrame
++       * function is enabled (TRUE) or disabled (FALSE).
++       */
++      __u8 block_oversize_enable;
++
++      /* The StreamBlockedDueToOversizeFrame object contains a Boolean value
++       * that indicates whether, if the StreamBlockedDueToOversizeFrame
++       * function is enabled, all frames are to be discarded (TRUE) or not
++       * (FALSE).
++       */
++      __u8 block_oversize;
++};
++
++/* 802.1Qci Stream Gate Control List Entry. */
++struct tsn_qci_psfp_gcl {
++      /* The GateState parameter specifies a desired state, open (true) or
++       * closed (false), for the stream gate.
++       */
++      __u8 gate_state;
++
++      /* An IPV is encoded as a signed integer.  A negative denotes the null
++       * value; zero or positive values denote internal priority values.
++       */
++      __s8 ipv;
++
++      /* A TimeInterval is encoded in 4 octets as a 32-bit unsigned integer,
++       * representing a number of nanoseconds.
++       */
++      __u32 time_interval;
++
++      /* The maximum number of octets that are permitted to pass the gate
++       * during the specified TimeInterval.  If zero, there is no maximum.
++       */
++      __u32 octet_max;
++
++};
++
++/* 802.1Qci Stream Gate Admin/Operation common list control parameters */
++struct tsn_qci_sg_control {
++      /* The administrative/operation value of the GateStates parameter
++       * for the stream gate.  A value of false indicates closed;
++       * a value of true indicates open.
++       */
++      __u8 gate_states;
++
++      /* The administrative/operation value of the ListMax parameter for the
++       * gate. The integer value indicates the number of entries (TLVs) in
++       * the AdminControlList/OperControlList.
++       */
++      __u8 control_list_length;
++
++      /* The administrative/operation value of the CycleTime parameter for
++       * the gate.  The value is an unsigned integer number of nanoseconds.
++       */
++      __u32 cycle_time;
++
++      /* The administrative/operation value of the CycleTimeExtension
++       * parameter for the gate.  The value is an unsigned integer number
++       * of nanoseconds.
++       */
++      __u32 cycle_time_extension;
++
++      /* The administrative/operation value of the BaseTime parameter for the
++       * gate.  The value is a representation of a PTPtime value, consisting
++       * of a 48-bit integer number of seconds and a 32-bit integer number of
++       * nanoseconds.
++       */
++      ptptime_t base_time;
++
++      /* The administrative/operation value of the IPV parameter for the gate.
++       * A value of -1 denotes the null value; zero or positive values denote
++       * internal priority values.
++       */
++      __s8 init_ipv;
++
++      /* control_list contend the gate control list of
++       * administrative/operation
++       */
++      struct tsn_qci_psfp_gcl *gcl;
++};
++
++/* 802.1Qci Stream Gate Instance Table, configuration part only. */
++struct tsn_qci_psfp_sgi_conf {
++      /* The GateEnabled parameter determines whether the stream gate is
++       * active (true) or inactive (false).
++       */
++      __u8 gate_enabled;
++
++      /* The ConfigChange parameter signals the start of a configuration
++       * change when it is set to TRUE. This should only be done when the
++       * various administrative parameters are all set to appropriate values.
++       */
++      __u8 config_change;
++
++      /* admin control parameters with admin control list */
++      struct tsn_qci_sg_control admin;
++
++      /* The GateClosedDueToInvalidRxEnable object contains a Boolean value
++       * that indicates whether the GateClosedDueToInvalidRx function is
++       * enabled (TRUE) or disabled (FALSE).
++       */
++      __u8 block_invalid_rx_enable;
++
++      /* The GateClosedDueToInvalidRx object contains a Boolean value that
++       * indicates whether, if the GateClosedDueToInvalidRx function is
++       * enabled, all frames are to be discarded (TRUE) or not (FALSE).
++       */
++      __u8 block_invalid_rx;
++
++      /* The GateClosedDueToOctetsExceededEnable object contains a Boolean
++       * value that indicates whether the GateClosedDueToOctetsExceeded
++       * function is enabled (TRUE) or disabled (FALSE).
++       */
++      __u8 block_octets_exceeded_enable;
++
++      /* The GateClosedDueToOctetsExceeded object contains a Boolean value
++       * that indicates whether, if the GateClosedDueToOctetsExceeded
++       * function is enabled, all frames are to be discarded (TRUE) or not
++       * (FALSE).
++       */
++      __u8 block_octets_exceeded;
++};
++
++/* 802.1Qci Stream Gate Instance Table, status part only. */
++struct tsn_psfp_sgi_status {
++
++      /* admin control parameters with admin control list */
++      struct tsn_qci_sg_control oper;
++
++      /* The PTPtime at which the next config change is scheduled to occur.
++       * The value is a representation of a PTPtime value, consisting of a
++       * 48-bit integer number of seconds and a 32-bit integer number of
++       * nanoseconds.
++       */
++      ptptime_t config_change_time;
++
++      /* The granularity of the cycle time clock, represented as an unsigned
++       * number of tenths of nanoseconds.
++       */
++      __u32 tick_granularity;
++
++      /* The current time, in PTPtime, as maintained by the local system.
++       * The value is a representation of a PTPtime value, consisting of a
++       * 48-bit integer number of seconds and a 32-bit integer number of
++       * nanoseconds.
++       */
++      ptptime_t current_time;
++
++      /* The value of the ConfigPending state machine variable.  The value is
++       * TRUE if a configuration change is in progress but has not yet
++       * completed.
++       */
++      __u8 config_pending;
++
++      /* A counter of the number of times that a re-configuration of the
++       * traffic schedule has been requested with the old schedule still
++       * running and the requested base time was in the past.
++       */
++      __u64 config_change_error;
++
++};
++
++/* 802.1Qci Flow Meter Instance Table. */
++struct tsn_qci_psfp_fmi {
++      /* The FlowMeterCIR parameter contains an integer value that represents
++       * the CIR value for the flow meter, in kbit/s.
++       */
++      __u32 cir;
++
++      /* The FlowMeterCBS parameter contains an integer value that represents
++       * the CBS value for the flow meter, in octets.
++       */
++      __u32 cbs;
++
++      /* The FlowMeterEIR parameter contains an integer value that represents
++       * the EIR value for the flow meter, in kbit/s.
++       */
++      __u32 eir;
++
++      /* The FlowMeterEBS parameter contains an integer value that represents
++       * the EBS value for the flow meter, in octets.
++       */
++      __u32 ebs;
++
++      /* The FlowMeterCF parameter contains a Boolean value that represents
++       * the CF value for the flow meter, as a Boolean value indicating no
++       * coupling (FALSE) or coupling (TRUE).
++       */
++      __u8 cf;
++
++      /* The FlowMeterCM parameter contains a Boolean value that represents
++       * the CM value for the flow meter, as a Boolean value indicating
++       * colorBlind (FALSE) or colorAware (TRUE).
++       */
++      __u8 cm;
++
++      /* The FlowMeterDropOnYellow parameter contains a Boolean value that
++       * indicates whether yellow frames are dropped (TRUE) or have
++       * drop_eligible set to TRUE (FALSE).
++       */
++      __u8 drop_on_yellow;
++
++      /* The FlowMeterMarkAllFramesRedEnable parameter contains a Boolean
++       * value that indicates whether the MarkAllFramesRed function
++       * is enabled (TRUE) or disabled (FALSE).
++       */
++      __u8 mark_red_enable;
++
++      /* The FlowMeterMarkAllFramesRed parameter contains a Boolean value
++       * that indicates whether, if the MarkAllFramesRed function is enabled,
++       * all frames are to be discarded (TRUE) or not (FALSE).
++       */
++      __u8 mark_red;
++};
++
++struct tsn_qci_psfp_fmi_counters {
++      __u64 bytecount;
++      __u64 drop;
++      __u64 dr0_green;
++      __u64 dr1_green;
++      __u64 dr2_yellow;
++      __u64 remark_yellow;
++      __u64 dr3_red;
++      __u64 remark_red;
++};
++
++/* 802.1cb */
++struct tsn_seq_gen_conf {
++
++      /* The InputPortMask parameter contains a port mask.
++       * If the packet is from input port belonging to this
++       * port mask then it's on known stream and sequence
++       * generation parameters can be applied.
++       */
++      __u8 iport_mask;
++
++      /* The SplitMask parameter contains a output port mask
++       * used to add redundant paths.
++       */
++      __u8 split_mask;
++
++      /* The SequenceSpaceLenLog parameter is a value to specifies
++       * number of bits to be used for sequence number.
++       */
++      __u8 seq_len;
++
++      /* The SequenceNumber parameter is a value to used for
++       * outgoing packet's sequence number generation.
++       */
++      __u32 seq_num;
++};
++
++struct tsn_seq_rec_conf {
++
++      /* The SequenceSpaceLenLog parameter is a value to specifies
++       * number of bits to be used for sequence number.
++       */
++      __u8 seq_len;
++
++      /* The HistorySpaceLenLog parameter is a value to specifies
++       * number of bits to be used for history register.
++       */
++      __u8 his_len;
++
++      /* The RTagPopEnable parameter contains a __u8 to enable removal
++       * of redundancy tag from the packet.
++       */
++      __u8 rtag_pop_en;
++};
++
++struct tsn_cb_status {
++
++      /* The GenRecover parameter contains a value specifies type
++       * of stream sequence parameters:
++       *      0: Stream sequence parameters are for generation.
++       *      1: Stream sequence parameters are for recovery.
++       */
++      __u8 gen_rec;
++
++      /* The ErrStatus parameter indicates stream's error status
++       * 1: This switch is expected to sequence the stream,
++       *    but the incoming packet has sequence number.
++       * 2: This switch is expected to recover the stream,
++       *    but the incoming packet is NONSEQ.
++       */
++      __u8 err;
++
++      /* The SequenceNumber parameter is a value to used for
++       * outgoing packet's sequence number generation.
++       */
++      __u32 seq_num;
++
++      /* The SequenceSpaceLenLog parameter is a value to specifies
++       * number of bits to be used for sequence number.
++       */
++      __u8 seq_len;
++
++      /* The SplitMask parameter contains a output port mask
++       * used to add redundant paths.
++       */
++      __u8 split_mask;
++
++      /* The InputPortMask parameter contains a port mask.
++       * If the packet is from input port belonging to this
++       * port mask then it's on known stream and sequence
++       * generation parameters can be applied.
++       */
++      __u8 iport_mask;
++
++      /* The HistorySpaceLenLog parameter is a value to specifies
++       * number of bits to be used for history register.
++       */
++      __u8 his_len;
++
++      /* The SequenceHistory parameter Maintains history of sequence
++       * numbers of received packets.
++       */
++      __u32 seq_his;
++};
++
++/* An entry for gate control list */
++struct tsn_qbv_entry {
++      /* Octet represent the gate states for the corresponding traffic
++       * classes.
++       * The MS bit corresponds to traffic class 7.
++       * The LS bit to traffic class 0.
++       * A bit value of 0 indicates closed;
++       * A bit value of 1 indicates open.
++       */
++      __u8 gate_state;
++
++      /* A TimeInterval is encoded in 4 octets as a 32-bit unsigned integer,
++       * representing a number of nanoseconds.
++       */
++      __u32 time_interval;
++};
++
++/* The administrative/operation time and gate list */
++struct tsn_qbv_basic {
++      /* The administrative/operation value of the GateStates parameter for
++       * the Port.
++       * The bits of the octet represent the gate states for the
++       * corresponding traffic classes; the MS bit corresponds to traffic
++       * class 7, the LS bit to traffic class 0. A bit value of 0 indicates
++       * closed; a bit value of 1 indicates open.
++       * The value of this object MUST be retained
++       * across reinitializations of the management system.
++       */
++      __u8 gate_states;
++
++      /* The administrative/operation value of the ListMax parameter for the
++       * port. The integer value indicates the number of entries (TLVs) in
++       * the AdminControlList. The value of this object MUST be retained
++       * across reinitializations of the management system.
++       */
++      __u32 control_list_length;
++
++      /* The administrative/operation value of the AdminCycleTime
++       * parameter for the Port. The numerator and denominator together
++       * represent the cycle time as a rational number of seconds.  The value
++       * of this object MUST be retained across reinitializations of the
++       * management system.
++       */
++      __u32 cycle_time;
++
++      /* The administrative/operation value of the CycleTimeExtension
++       * parameter for the Port. The value is an unsigned integer number of
++       * nanoseconds.
++       * The value of this object MUST be retained across reinitializations
++       * of the management system.
++       */
++
++      __u32 cycle_time_extension;
++
++      /* The administrative/operation value of the BaseTime parameter for the
++       * Port.  The value is a representation of a PTPtime value, consisting
++       * of a 48-bit integer number of seconds and a 32-bit integer number of
++       * nanoseconds.
++       * The value of this object MUST be retained across reinitializations of
++       * the management system.
++       */
++      ptptime_t base_time;
++
++      /* admin_control_list represent the AdminControlList/OperControlList.
++       * The administrative version of the gate control list for the Port.
++       */
++      struct tsn_qbv_entry *control_list;
++};
++
++struct tsn_qbv_conf {
++      /* The GateEnabled parameter determines whether traffic scheduling is
++       * active (true) or inactive (false).  The value of this object MUST be
++       * retained across reinitializations of the management system.
++       */
++      __u8 gate_enabled;
++
++      /* The maxsdu parameter denoting the maximum SDU size supported by the
++       * queue.
++       */
++      __u32 maxsdu;
++
++      /* The ConfigChange parameter signals the start of a configuration
++       * change when it is set to TRUE. This should only be done when the
++       * various administrative parameters are all set to appropriate values.
++       */
++      __u8 config_change;
++
++      /* The admin parameter signals the admin relate cycletime, basictime,
++       * gatelist paraters.
++       */
++      struct tsn_qbv_basic admin;
++};
++
++/* 802.1Qbv (Time Aware Shaper) port status */
++struct tsn_qbv_status {
++      /* The PTPtime at which the next config change is scheduled to occur.
++       * The value is a representation of a PTPtime value, consisting of a
++       * 48-bit integer number of seconds and a 32-bit integer number of
++       * nanoseconds.  The value of this object MUST be retained across
++       * reinitializations of the management system.
++       */
++      ptptime_t config_change_time;
++
++      /* The granularity of the cycle time clock, represented as an unsigned
++       * number of tenths of nanoseconds.  The value of this object MUST be
++       * retained across reinitializations of the management system.
++       */
++      __u32 tick_granularity;
++
++      /* The current time, in PTPtime, as maintained by the local system.
++       * The value is a representation of a PTPtime value, consisting of a
++       * 48-bit integer number of seconds and a 32-bit integer number of
++       * nanoseconds.
++       */
++      ptptime_t  current_time;
++
++      /* The value of the ConfigPending state machine variable.  The value is
++       * TRUE if a configuration change is in progress but has not yet
++       * completed.
++       */
++      __u8 config_pending;
++
++      /* A counter of the number of times that a re-configuration of the
++       * traffic schedule has been requested with the old schedule still
++       * running and the requested base time was in the past.
++       */
++      __u64 config_change_error;
++
++      /* The maximum value supported by this Port of the
++       * AdminControlListLength and OperControlListLength parameters.
++       */
++      __u32 supported_list_max;
++
++      /* Operation settings parameters and Oper gate list */
++      struct tsn_qbv_basic oper;
++};
++
++/* Time Specific Departure parameters */
++struct tsn_tsd {
++      __u8 enable;
++
++      /* The cycle time, in units of microsecond(us)*/
++      __u32 period;
++
++      /* The maximum number of frames which could be transmitted on one cycle
++       *  The exceeding frames will be transmitted on next cycle.
++       */
++      __u32 maxFrameNum;
++
++      /* Specify the time of the first cycle begins.
++       *      1:  begin when the queue get the first frame to transmit.
++       *      2:  begin immediately at the end of setting function.
++       */
++      __u32 syn_flag;
++};
++
++struct tsn_tsd_status {
++      __u8 enable;
++      __u32 period;
++      __u32 maxFrameNum;
++      __u32 flag;
++      __u32 cycleNum;
++      __u32 loss_steps;
++};
++
++struct tsn_qos_switch_dscp_conf {
++      __u8 trust;
++      __u8 cos;
++      __u8 dpl;
++      __u8 remark;
++      __u8 dscp; /* New ingress translated DSCP value */
++};
++
++#endif /* _UAPI_GENL_TSN_H */
+--- a/net/Kconfig
++++ b/net/Kconfig
+@@ -240,6 +240,7 @@ source "net/ieee802154/Kconfig"
+ source "net/mac802154/Kconfig"
+ source "net/sched/Kconfig"
+ source "net/dcb/Kconfig"
++source "net/tsn/Kconfig"
+ source "net/dns_resolver/Kconfig"
+ source "net/batman-adv/Kconfig"
+ source "net/openvswitch/Kconfig"
+--- a/net/Makefile
++++ b/net/Makefile
+@@ -59,6 +59,9 @@ obj-$(CONFIG_CAIF)           += caif/
+ ifneq ($(CONFIG_DCB),)
+ obj-y                         += dcb/
+ endif
++ifneq ($(CONFIG_TSN),)
++obj-y                                 += tsn/
++endif
+ obj-$(CONFIG_6LOWPAN)         += 6lowpan/
+ obj-$(CONFIG_IEEE802154)      += ieee802154/
+ obj-$(CONFIG_MAC802154)               += mac802154/
+--- /dev/null
++++ b/net/tsn/Kconfig
+@@ -0,0 +1,15 @@
++config TSN
++      bool "802.1 Time-Sensitive Networking support"
++      default n
++      depends on VLAN_8021Q && PTP_1588_CLOCK
++      help
++        This enables support for TSN(time sensitive networking)
++        TSN features include:
++              802.1Qav:
++              802.1Qbv:
++              802.1Qci:
++              802.1Qbu:
++              802.1AS:
++              802.1CB:
++
++        If unsure, say N.
+--- /dev/null
++++ b/net/tsn/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_TSN) += genl_tsn.o
+--- /dev/null
++++ b/net/tsn/genl_tsn.c
+@@ -0,0 +1,3696 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
++/* Copyright 2017-2019 NXP */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/netdevice.h>
++#include <linux/if_vlan.h>
++#include <net/genetlink.h>
++#include <net/netlink.h>
++#include <linux/version.h>
++#include <net/tsn.h>
++
++#define NLA_PARSE_NESTED(a, b, c, d) \
++      nla_parse_nested_deprecated(a, b, c, d, NULL)
++#define NLA_PUT_U64(a, b, c) nla_put_u64_64bit(a, b, c, NLA_U64)
++
++static struct genl_family tsn_family;
++
++LIST_HEAD(port_list);
++
++static const struct nla_policy tsn_cmd_policy[TSN_CMD_ATTR_MAX + 1] = {
++      [TSN_CMD_ATTR_MESG]             = { .type = NLA_STRING },
++      [TSN_CMD_ATTR_DATA]             = { .type = NLA_S32 },
++      [TSN_ATTR_IFNAME]               = { .type = NLA_STRING },
++      [TSN_ATTR_PORT_NUMBER]          = { .type = NLA_U8 },
++      [TSN_ATTR_CAP]                  = { .type = NLA_NESTED  },
++      [TSN_ATTR_QBV]                  = { .type = NLA_NESTED },
++      [TSN_ATTR_STREAM_IDENTIFY]      = { .type = NLA_NESTED },
++      [TSN_ATTR_QCI_SP]               = { .type = NLA_NESTED },
++      [TSN_ATTR_QCI_SFI]              = { .type = NLA_NESTED },
++      [TSN_ATTR_QCI_SGI]              = { .type = NLA_NESTED },
++      [TSN_ATTR_QCI_FMI]              = { .type = NLA_NESTED },
++      [TSN_ATTR_CBS]                  = { .type = NLA_NESTED },
++      [TSN_ATTR_TSD]                  = { .type = NLA_NESTED },
++      [TSN_ATTR_QBU]                  = { .type = NLA_NESTED },
++      [TSN_ATTR_CT]                   = { .type = NLA_NESTED },
++      [TSN_ATTR_CBGEN]                = { .type = NLA_NESTED },
++      [TSN_ATTR_CBREC]                = { .type = NLA_NESTED },
++      [TSN_ATTR_CBSTAT]               = { .type = NLA_NESTED },
++      [TSN_ATTR_DSCP]                 = { .type = NLA_NESTED },
++};
++
++static const struct nla_policy tsn_cap_policy[TSN_CAP_ATTR_MAX + 1] = {
++      [TSN_CAP_ATTR_QBV]              = { .type = NLA_FLAG },
++      [TSN_CAP_ATTR_QCI]              = { .type = NLA_FLAG },
++      [TSN_CAP_ATTR_QBU]              = { .type = NLA_FLAG },
++      [TSN_CAP_ATTR_CBS]              = { .type = NLA_FLAG },
++      [TSN_CAP_ATTR_CB]               = { .type = NLA_FLAG },
++      [TSN_CAP_ATTR_TBS]              = { .type = NLA_FLAG },
++      [TSN_CAP_ATTR_CTH]              = { .type = NLA_FLAG },
++};
++
++static const struct nla_policy qci_cap_policy[TSN_QCI_STREAM_ATTR_MAX + 1] = {
++      [TSN_QCI_STREAM_ATTR_MAX_SFI]   = { .type = NLA_U32 },
++      [TSN_QCI_STREAM_ATTR_MAX_SGI]   = { .type = NLA_U32 },
++      [TSN_QCI_STREAM_ATTR_MAX_FMI]   = { .type = NLA_U32 },
++      [TSN_QCI_STREAM_ATTR_SLM]       = { .type = NLA_U32 },
++};
++
++static const struct nla_policy ct_policy[TSN_CT_ATTR_MAX + 1] = {
++      [TSN_CT_ATTR_QUEUE_STATE]       = { .type = NLA_U8 }
++};
++
++static const struct nla_policy cbgen_policy[TSN_CBGEN_ATTR_MAX + 1] = {
++      [TSN_CBGEN_ATTR_INDEX]          = { .type = NLA_U32 },
++      [TSN_CBGEN_ATTR_PORT_MASK]      = { .type = NLA_U8 },
++      [TSN_CBGEN_ATTR_SPLIT_MASK]     = { .type = NLA_U8 },
++      [TSN_CBGEN_ATTR_SEQ_LEN]        = { .type = NLA_U8 },
++      [TSN_CBGEN_ATTR_SEQ_NUM]        = { .type = NLA_U32 },
++};
++
++static const struct nla_policy cbrec_policy[TSN_CBREC_ATTR_MAX + 1] = {
++      [TSN_CBREC_ATTR_INDEX]          = { .type = NLA_U32 },
++      [TSN_CBREC_ATTR_SEQ_LEN]        = { .type = NLA_U8 },
++      [TSN_CBREC_ATTR_HIS_LEN]        = { .type = NLA_U8 },
++      [TSN_CBREC_ATTR_TAG_POP_EN]     = { .type = NLA_FLAG },
++};
++
++static const struct nla_policy cbstat_policy[TSN_CBSTAT_ATTR_MAX + 1] = {
++      [TSN_CBSTAT_ATTR_INDEX]         = { .type = NLA_U32 },
++      [TSN_CBSTAT_ATTR_GEN_REC]       = { .type = NLA_U8 },
++      [TSN_CBSTAT_ATTR_ERR]           = { .type = NLA_U8 },
++      [TSN_CBSTAT_ATTR_SEQ_NUM]       = { .type = NLA_U32 },
++      [TSN_CBSTAT_ATTR_SEQ_LEN]       = { .type = NLA_U8 },
++      [TSN_CBSTAT_ATTR_SPLIT_MASK]    = { .type = NLA_U8 },
++      [TSN_CBSTAT_ATTR_PORT_MASK]     = { .type = NLA_U8 },
++      [TSN_CBSTAT_ATTR_HIS_LEN]       = { .type = NLA_U8 },
++      [TSN_CBSTAT_ATTR_SEQ_HIS]       = { .type = NLA_U32 },
++};
++
++static const struct nla_policy qbu_policy[TSN_QBU_ATTR_MAX + 1] = {
++      [TSN_QBU_ATTR_ADMIN_STATE]      = { .type = NLA_U8 },
++      [TSN_QBU_ATTR_HOLD_ADVANCE]     = { .type = NLA_U32},
++      [TSN_QBU_ATTR_RELEASE_ADVANCE]  = { .type = NLA_U32},
++      [TSN_QBU_ATTR_ACTIVE]           = { .type = NLA_FLAG},
++      [TSN_QBU_ATTR_HOLD_REQUEST]     = { .type = NLA_U8},
++};
++
++static const struct nla_policy cbs_policy[TSN_CBS_ATTR_MAX + 1] = {
++      [TSN_CBS_ATTR_TC_INDEX]         = { .type = NLA_U8},
++      [TSN_CBS_ATTR_BW]               = { .type = NLA_U8},
++};
++
++static const struct nla_policy tsd_policy[TSN_TSD_ATTR_MAX + 1] = {
++      [TSN_TSD_ATTR_ENABLE]                   = { .type = NLA_FLAG},
++      [TSN_TSD_ATTR_DISABLE]                  = { .type = NLA_FLAG},
++      [TSN_TSD_ATTR_PERIOD]                   = { .type = NLA_U32},
++      [TSN_TSD_ATTR_MAX_FRM_NUM]              = { .type = NLA_U32},
++      [TSN_TSD_ATTR_CYCLE_NUM]                = { .type = NLA_U32},
++      [TSN_TSD_ATTR_LOSS_STEPS]               = { .type = NLA_U32},
++      [TSN_TSD_ATTR_SYN_IMME]                 = { .type = NLA_FLAG},
++};
++
++static const struct nla_policy qbv_policy[TSN_QBV_ATTR_MAX + 1] = {
++      [TSN_QBV_ATTR_ADMINENTRY]       = {     .type = NLA_NESTED},
++      [TSN_QBV_ATTR_OPERENTRY]        = { .type = NLA_NESTED},
++      [TSN_QBV_ATTR_ENABLE]           = { .type = NLA_FLAG},
++      [TSN_QBV_ATTR_DISABLE]          = { .type = NLA_FLAG},
++      [TSN_QBV_ATTR_CONFIGCHANGE]     = { .type = NLA_FLAG},
++      [TSN_QBV_ATTR_CONFIGCHANGETIME] = { .type = NLA_U64},
++      [TSN_QBV_ATTR_MAXSDU]           = { .type = NLA_U32},
++      [TSN_QBV_ATTR_GRANULARITY]      = { .type = NLA_U32},
++      [TSN_QBV_ATTR_CURRENTTIME]      = { .type = NLA_U64},
++      [TSN_QBV_ATTR_CONFIGPENDING]    = {.type = NLA_FLAG},
++      [TSN_QBV_ATTR_CONFIGCHANGEERROR]        = { .type = NLA_U64},
++      [TSN_QBV_ATTR_LISTMAX]          = { .type = NLA_U32},
++};
++
++static const struct nla_policy qbv_ctrl_policy[TSN_QBV_ATTR_CTRL_MAX + 1] = {
++      [TSN_QBV_ATTR_CTRL_LISTCOUNT]           = { .type = NLA_U32},
++      [TSN_QBV_ATTR_CTRL_GATESTATE]           = { .type = NLA_U8},
++      [TSN_QBV_ATTR_CTRL_CYCLETIME]           = { .type = NLA_U32},
++      [TSN_QBV_ATTR_CTRL_CYCLETIMEEXT]        = { .type = NLA_U32},
++      [TSN_QBV_ATTR_CTRL_BASETIME]            = { .type = NLA_U64},
++      [TSN_QBV_ATTR_CTRL_LISTENTRY]           = { .type = NLA_NESTED},
++};
++
++static const struct nla_policy qbv_entry_policy[TSN_QBV_ATTR_ENTRY_MAX + 1] = {
++      [TSN_QBV_ATTR_ENTRY_ID] = { .type = NLA_U32},
++      [TSN_QBV_ATTR_ENTRY_GC] = { .type = NLA_U8},
++      [TSN_QBV_ATTR_ENTRY_TM] = { .type = NLA_U32},
++};
++
++static const struct nla_policy cb_streamid_policy[TSN_STREAMID_ATTR_MAX + 1] = {
++      [TSN_STREAMID_ATTR_INDEX]       = { .type = NLA_U32},
++      [TSN_STREAMID_ATTR_ENABLE]      = { .type = NLA_FLAG},
++      [TSN_STREAMID_ATTR_DISABLE]     = { .type = NLA_FLAG},
++      [TSN_STREAMID_ATTR_STREAM_HANDLE]       = { .type = NLA_S32},
++      [TSN_STREAMID_ATTR_IFOP]        = { .type = NLA_U32},
++      [TSN_STREAMID_ATTR_OFOP]        = { .type = NLA_U32},
++      [TSN_STREAMID_ATTR_IFIP]        = { .type = NLA_U32},
++      [TSN_STREAMID_ATTR_OFIP]        = { .type = NLA_U32},
++      [TSN_STREAMID_ATTR_TYPE]        = { .type = NLA_U8},
++      [TSN_STREAMID_ATTR_NDMAC]       = { .type = NLA_U64},
++      [TSN_STREAMID_ATTR_NTAGGED]     = { .type = NLA_U8},
++      [TSN_STREAMID_ATTR_NVID]        = { .type = NLA_U16},
++      [TSN_STREAMID_ATTR_SMAC]        = { .type = NLA_U64},
++      [TSN_STREAMID_ATTR_STAGGED]     = { .type = NLA_U8},
++      [TSN_STREAMID_ATTR_SVID]        = { .type = NLA_U16},
++      [TSN_STREAMID_ATTR_COUNTERS_PSI] = { .type = NLA_U64},
++      [TSN_STREAMID_ATTR_COUNTERS_PSO] = { .type = NLA_U64},
++      [TSN_STREAMID_ATTR_COUNTERS_PSPPI] = { .type = NLA_U64},
++      [TSN_STREAMID_ATTR_COUNTERS_PSPPO] = { .type = NLA_U64},
++};
++
++static const struct nla_policy qci_sfi_policy[TSN_QCI_SFI_ATTR_MAX + 1] = {
++      [TSN_QCI_SFI_ATTR_INDEX]                = { .type = NLA_U32},
++      [TSN_QCI_SFI_ATTR_ENABLE]               = { .type = NLA_FLAG},
++      [TSN_QCI_SFI_ATTR_DISABLE]              = { .type = NLA_FLAG},
++      [TSN_QCI_SFI_ATTR_STREAM_HANDLE]        = { .type = NLA_S32},
++      [TSN_QCI_SFI_ATTR_PRIO_SPEC]            = { .type = NLA_S8},
++      [TSN_QCI_SFI_ATTR_GATE_ID]              = { .type = NLA_U32},
++      [TSN_QCI_SFI_ATTR_FILTER_TYPE]          = { .type = NLA_U8},
++      [TSN_QCI_SFI_ATTR_FLOW_ID]              = { .type = NLA_S32},
++      [TSN_QCI_SFI_ATTR_MAXSDU]               = { .type = NLA_U16},
++      [TSN_QCI_SFI_ATTR_COUNTERS]             = {
++              .len = sizeof(struct tsn_qci_psfp_sfi_counters)},
++      [TSN_QCI_SFI_ATTR_OVERSIZE_ENABLE]      = { .type = NLA_FLAG},
++      [TSN_QCI_SFI_ATTR_OVERSIZE]             = { .type = NLA_FLAG},
++};
++
++static const struct nla_policy qci_sgi_policy[] = {
++      [TSN_QCI_SGI_ATTR_INDEX]                = { .type = NLA_U32},
++      [TSN_QCI_SGI_ATTR_ENABLE]               = { .type = NLA_FLAG},
++      [TSN_QCI_SGI_ATTR_DISABLE]              = { .type = NLA_FLAG},
++      [TSN_QCI_SGI_ATTR_CONFCHANGE]           = { .type = NLA_FLAG},
++      [TSN_QCI_SGI_ATTR_IRXEN]                = { .type = NLA_FLAG},
++      [TSN_QCI_SGI_ATTR_IRX]                  = { .type = NLA_FLAG},
++      [TSN_QCI_SGI_ATTR_OEXEN]                = { .type = NLA_FLAG},
++      [TSN_QCI_SGI_ATTR_OEX]                  = { .type = NLA_FLAG},
++      [TSN_QCI_SGI_ATTR_ADMINENTRY]           = { .type = NLA_NESTED},
++      [TSN_QCI_SGI_ATTR_OPERENTRY]            = { .type = NLA_NESTED},
++      [TSN_QCI_SGI_ATTR_CCTIME]               = { .type = NLA_U64},
++      [TSN_QCI_SGI_ATTR_TICKG]                = { .type = NLA_U32},
++      [TSN_QCI_SGI_ATTR_CUTIME]               = { .type = NLA_U64},
++      [TSN_QCI_SGI_ATTR_CPENDING]             = { .type = NLA_FLAG},
++      [TSN_QCI_SGI_ATTR_CCERROR]              = { .type = NLA_U64},
++};
++
++static const struct nla_policy qci_sgi_ctrl_policy[] = {
++      [TSN_SGI_ATTR_CTRL_INITSTATE]           = { .type = NLA_FLAG},
++      [TSN_SGI_ATTR_CTRL_LEN]                 = { .type = NLA_U8},
++      [TSN_SGI_ATTR_CTRL_CYTIME]              = { .type = NLA_U32},
++      [TSN_SGI_ATTR_CTRL_CYTIMEEX]            = { .type = NLA_U32},
++      [TSN_SGI_ATTR_CTRL_BTIME]               = { .type = NLA_U64},
++      [TSN_SGI_ATTR_CTRL_INITIPV]             = { .type = NLA_S8},
++      [TSN_SGI_ATTR_CTRL_GCLENTRY]            = { .type = NLA_NESTED},
++};
++
++static const struct nla_policy qci_sgi_gcl_policy[] = {
++      [TSN_SGI_ATTR_GCL_GATESTATE]            = { .type = NLA_FLAG},
++      [TSN_SGI_ATTR_GCL_IPV]                  = { .type = NLA_S8},
++      [TSN_SGI_ATTR_GCL_INTERVAL]             = { .type = NLA_U32},
++      [TSN_SGI_ATTR_GCL_OCTMAX]               = { .type = NLA_U32},
++};
++
++static const struct nla_policy qci_fmi_policy[] = {
++      [TSN_QCI_FMI_ATTR_INDEX]        = { .type = NLA_U32},
++      [TSN_QCI_FMI_ATTR_ENABLE]       = { .type = NLA_FLAG},
++      [TSN_QCI_FMI_ATTR_DISABLE]      = { .type = NLA_FLAG},
++      [TSN_QCI_FMI_ATTR_CIR]          = { .type = NLA_U32},
++      [TSN_QCI_FMI_ATTR_CBS]          = { .type = NLA_U32},
++      [TSN_QCI_FMI_ATTR_EIR]          = { .type = NLA_U32},
++      [TSN_QCI_FMI_ATTR_EBS]          = { .type = NLA_U32},
++      [TSN_QCI_FMI_ATTR_CF]           = { .type = NLA_FLAG},
++      [TSN_QCI_FMI_ATTR_CM]           = { .type = NLA_FLAG},
++      [TSN_QCI_FMI_ATTR_DROPYL]       = { .type = NLA_FLAG},
++      [TSN_QCI_FMI_ATTR_MAREDEN]      = { .type = NLA_FLAG},
++      [TSN_QCI_FMI_ATTR_MARED]        = { .type = NLA_FLAG},
++      [TSN_QCI_FMI_ATTR_COUNTERS]     = {
++              .len = sizeof(struct tsn_qci_psfp_fmi_counters)},
++};
++
++static const struct nla_policy dscp_policy[] = {
++      [TSN_DSCP_ATTR_INDEX]           = { .type = NLA_U32},
++      [TSN_DSCP_ATTR_DISABLE]         = { .type = NLA_FLAG},
++      [TSN_DSCP_ATTR_COS]             = { .type = NLA_U8},
++      [TSN_DSCP_ATTR_DPL]             = { .type = NLA_U8},
++};
++
++static ATOMIC_NOTIFIER_HEAD(tsn_notif_chain);
++
++/**
++ *    register_tsn_notifier - Register notifier
++ *    @nb: notifier_block
++ *
++ *    Register switch device notifier.
++ */
++int register_tsn_notifier(struct notifier_block *nb)
++{
++      return atomic_notifier_chain_register(&tsn_notif_chain, nb);
++}
++EXPORT_SYMBOL_GPL(register_tsn_notifier);
++
++/**
++ *    unregister_tsn_notifier - Unregister notifier
++ *    @nb: notifier_block
++ *
++ *    Unregister switch device notifier.
++ */
++int unregister_tsn_notifier(struct notifier_block *nb)
++{
++      return atomic_notifier_chain_unregister(&tsn_notif_chain, nb);
++}
++EXPORT_SYMBOL_GPL(unregister_tsn_notifier);
++
++/**
++ *    call_tsn_notifiers - Call notifiers
++ *    @val: value passed unmodified to notifier function
++ *    @dev: port device
++ *    @info: notifier information data
++ *
++ *    Call all network notifier blocks.
++ */
++int call_tsn_notifiers(unsigned long val, struct net_device *dev,
++                     struct tsn_notifier_info *info)
++{
++      info->dev = dev;
++      return atomic_notifier_call_chain(&tsn_notif_chain, val, info);
++}
++EXPORT_SYMBOL_GPL(call_tsn_notifiers);
++
++struct tsn_port *tsn_get_port(struct net_device *ndev)
++{
++      struct tsn_port *port;
++      bool tsn_found = false;
++
++      list_for_each_entry(port, &port_list, list) {
++              if (port->netdev == ndev) {
++                      tsn_found = true;
++                      break;
++              }
++      }
++
++      if (!tsn_found)
++              return NULL;
++
++      return port;
++}
++EXPORT_SYMBOL_GPL(tsn_get_port);
++
++static int tsn_prepare_reply(struct genl_info *info, u8 cmd,
++                           struct sk_buff **skbp, size_t size)
++{
++      struct sk_buff *skb;
++      void *reply;
++
++      /* If new attributes are added, please revisit this allocation
++       */
++      skb = genlmsg_new(size, GFP_KERNEL);
++      if (!skb)
++              return -ENOMEM;
++
++      if (!info) {
++              nlmsg_free(skb);
++              return -EINVAL;
++      }
++
++      reply = genlmsg_put_reply(skb, info, &tsn_family, 0, cmd);
++      if (!reply) {
++              nlmsg_free(skb);
++              return -EINVAL;
++      }
++
++      *skbp = skb;
++      return 0;
++}
++
++static int tsn_mk_reply(struct sk_buff *skb, int aggr, void *data, int len)
++{
++    /* add a netlink attribute to a socket buffer */
++      return nla_put(skb, aggr, len, data);
++}
++
++static int tsn_send_reply(struct sk_buff *skb, struct genl_info *info)
++{
++      struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
++      void *reply = genlmsg_data(genlhdr);
++
++      genlmsg_end(skb, reply);
++
++      return genlmsg_reply(skb, info);
++}
++
++static int cmd_attr_echo_message(struct genl_info *info)
++{
++      struct nlattr *na;
++      char *msg;
++      struct sk_buff *rep_skb;
++      size_t size;
++      int ret;
++
++      na = info->attrs[TSN_CMD_ATTR_MESG];
++      if (!na)
++              return -EINVAL;
++
++      msg = (char *)nla_data(na);
++      pr_info("tsn generic netlink receive echo mesg %s\n", msg);
++
++      size = nla_total_size(strlen(msg) + 1);
++
++      ret = tsn_prepare_reply(info, TSN_CMD_REPLY, &rep_skb,
++                              size + NLMSG_ALIGN(MAX_USER_SIZE));
++      if (ret < 0)
++              return ret;
++
++      ret = tsn_mk_reply(rep_skb, TSN_CMD_ATTR_MESG, msg, size);
++      if (ret < 0)
++              goto err;
++
++      return tsn_send_reply(rep_skb, info);
++
++err:
++      nlmsg_free(rep_skb);
++      return ret;
++}
++
++static int cmd_attr_echo_data(struct genl_info *info)
++{
++      struct nlattr *na;
++      s32     data;
++      struct sk_buff *rep_skb;
++      size_t size;
++      int ret;
++
++      /*read data */
++      na = info->attrs[TSN_CMD_ATTR_DATA];
++      if (!na)
++              return -EINVAL;
++
++      data = nla_get_s32(info->attrs[TSN_CMD_ATTR_DATA]);
++      pr_info("tsn generic netlink receive echo data %d\n", data);
++
++      /* send back */
++      size = nla_total_size(sizeof(s32));
++
++      ret = tsn_prepare_reply(info, TSN_CMD_REPLY, &rep_skb,
++                              size + NLMSG_ALIGN(MAX_USER_SIZE));
++      if (ret < 0)
++              return ret;
++
++      /* netlink lib func */
++      ret = nla_put_s32(rep_skb, TSN_CMD_ATTR_DATA, data);
++      if (ret < 0)
++              goto err;
++
++      return tsn_send_reply(rep_skb, info);
++
++err:
++      nlmsg_free(rep_skb);
++      return ret;
++}
++
++static int tsn_echo_cmd(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_CMD_ATTR_MESG])
++              return cmd_attr_echo_message(info);
++      else if (info->attrs[TSN_CMD_ATTR_DATA])
++              return cmd_attr_echo_data(info);
++
++      return -EINVAL;
++}
++
++static int tsn_simple_reply(struct genl_info *info, u32 cmd,
++                          char *portname, s32 retvalue)
++{
++      struct sk_buff *rep_skb;
++      size_t size;
++      int ret;
++
++      /* send back */
++      size = nla_total_size(strlen(portname) + 1);
++      size += nla_total_size(sizeof(s32));
++
++      ret = tsn_prepare_reply(info, cmd,
++                              &rep_skb, size + NLMSG_ALIGN(MAX_USER_SIZE));
++      if (ret < 0)
++              return ret;
++
++      /* netlink lib func */
++      ret = nla_put_string(rep_skb, TSN_ATTR_IFNAME, portname);
++      if (ret < 0)
++              return ret;
++
++      ret = nla_put_s32(rep_skb, TSN_CMD_ATTR_DATA, retvalue);
++      if (ret < 0)
++              return ret;
++
++      return tsn_send_reply(rep_skb, info);
++}
++
++struct tsn_port *tsn_init_check(struct genl_info *info,
++                              struct net_device **ndev)
++{
++      struct nlattr *na;
++      char *portname;
++      struct net_device *netdev;
++      struct tsn_port *port;
++      bool tsn_found = false;
++
++      if (!info->attrs[TSN_ATTR_IFNAME]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               "no portname", -EINVAL);
++              return NULL;
++      }
++
++      na = info->attrs[TSN_ATTR_IFNAME];
++
++      portname = (char *)nla_data(na);
++
++      netdev = __dev_get_by_name(genl_info_net(info), portname);
++      if (!netdev) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               "error device", -ENODEV);
++              return NULL;
++      }
++
++      list_for_each_entry(port, &port_list, list) {
++              if (port->netdev == netdev) {
++                      tsn_found = true;
++                      break;
++              }
++      }
++
++      if (!tsn_found) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -ENODEV);
++              return NULL;
++      }
++
++      *ndev = netdev;
++
++      return port;
++}
++
++static int tsn_cap_get(struct sk_buff *skb, struct genl_info *info)
++{
++      struct sk_buff *rep_skb;
++      struct nlattr *tsn_cap_attr;
++      int ret;
++      u32 cap = 0;
++      struct net_device *netdev;
++      struct genlmsghdr *genlhdr;
++      const struct tsn_ops *tsnops;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port) {
++              ret = -ENODEV;
++              goto out;
++      }
++
++      tsnops = port->tsnops;
++      genlhdr = info->genlhdr;
++      if (!tsnops->get_capability) {
++              ret = -EOPNOTSUPP;
++              goto out;
++      }
++
++      cap = tsnops->get_capability(netdev);
++      if (cap < 0) {
++              ret = cap;
++              goto out;
++      }
++
++      /* Pad netlink reply data */
++      ret = tsn_prepare_reply(info, genlhdr->cmd,
++                              &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
++      if (ret < 0)
++              goto out;
++
++      if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name)) {
++              ret = -EMSGSIZE;
++              goto err;
++      }
++
++      tsn_cap_attr = nla_nest_start_noflag(rep_skb, TSN_ATTR_CAP);
++      if (!tsn_cap_attr) {
++              ret = -EMSGSIZE;
++              goto err;
++      }
++
++      if (cap & TSN_CAP_QBV) {
++              if (nla_put_flag(rep_skb, TSN_CAP_ATTR_QBV))
++                      goto err;
++      }
++
++      if (cap & TSN_CAP_QCI) {
++              if (nla_put_flag(rep_skb, TSN_CAP_ATTR_QCI))
++                      goto err;
++      }
++
++      if (cap & TSN_CAP_QBU) {
++              if (nla_put_flag(rep_skb, TSN_CAP_ATTR_QBU))
++                      goto err;
++      }
++
++      if (cap & TSN_CAP_CBS) {
++              if (nla_put_flag(rep_skb, TSN_CAP_ATTR_CBS))
++                      goto err;
++      }
++
++      if (cap & TSN_CAP_CB) {
++              if (nla_put_flag(rep_skb, TSN_CAP_ATTR_CB))
++                      goto err;
++      }
++
++      if (cap & TSN_CAP_TBS) {
++              if (nla_put_flag(rep_skb, TSN_CAP_ATTR_TBS))
++                      goto err;
++      }
++
++      if (cap & TSN_CAP_CTH) {
++              if (nla_put_flag(rep_skb, TSN_CAP_ATTR_CTH))
++                      goto err;
++      }
++
++      nla_nest_end(rep_skb, tsn_cap_attr);
++
++      tsn_send_reply(rep_skb, info);
++      return 0;
++err:
++      nlmsg_free(rep_skb);
++out:
++      if (ret < 0)
++              tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
++      return ret;
++}
++
++static int cmd_cb_streamid_set(struct genl_info *info)
++{
++      struct nlattr *na, *sid[TSN_STREAMID_ATTR_MAX + 1];
++      u32 sid_index;
++      u8 iden_type = 1;
++      bool enable;
++      int ret;
++      struct net_device *netdev;
++      struct tsn_cb_streamid sidconf;
++      const struct tsn_ops *tsnops;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      memset(&sidconf, 0, sizeof(struct tsn_cb_streamid));
++
++      if (!info->attrs[TSN_ATTR_STREAM_IDENTIFY])
++              return -EINVAL;
++
++      na = info->attrs[TSN_ATTR_STREAM_IDENTIFY];
++
++      ret = NLA_PARSE_NESTED(sid, TSN_STREAMID_ATTR_MAX,
++                             na, cb_streamid_policy);
++      if (ret)
++              return -EINVAL;
++
++      if (!sid[TSN_STREAMID_ATTR_INDEX])
++              return -EINVAL;
++
++      sid_index = nla_get_u32(sid[TSN_STREAMID_ATTR_INDEX]);
++
++      if (sid[TSN_STREAMID_ATTR_ENABLE])
++              enable = true;
++      else if (sid[TSN_STREAMID_ATTR_DISABLE])
++              enable = false;
++      else
++              return -EINVAL;
++
++      if (!enable)
++              goto loaddev;
++
++      if (sid[TSN_STREAMID_ATTR_TYPE])
++              iden_type = nla_get_u8(sid[TSN_STREAMID_ATTR_TYPE]);
++      else
++              return -EINVAL;
++
++      sidconf.type = iden_type;
++      switch (iden_type) {
++      case STREAMID_NULL:
++              if (!sid[TSN_STREAMID_ATTR_NDMAC] ||
++                  !sid[TSN_STREAMID_ATTR_NTAGGED] ||
++                  !sid[TSN_STREAMID_ATTR_NVID]) {
++                      return -EINVAL;
++              }
++
++              sidconf.para.nid.dmac =
++                      nla_get_u64(sid[TSN_STREAMID_ATTR_NDMAC]);
++              sidconf.para.nid.tagged =
++                      nla_get_u8(sid[TSN_STREAMID_ATTR_NTAGGED]);
++              sidconf.para.nid.vid =
++                      nla_get_u16(sid[TSN_STREAMID_ATTR_NVID]);
++              break;
++      case STREAMID_SMAC_VLAN:
++              /* TODO: not supportted yet */
++              if (!sid[TSN_STREAMID_ATTR_SMAC] ||
++                  !sid[TSN_STREAMID_ATTR_STAGGED] ||
++                  !sid[TSN_STREAMID_ATTR_SVID]) {
++                      return -EINVAL;
++              }
++
++              sidconf.para.sid.smac =
++                      nla_get_u64(sid[TSN_STREAMID_ATTR_SMAC]);
++              sidconf.para.sid.tagged =
++                      nla_get_u8(sid[TSN_STREAMID_ATTR_STAGGED]);
++              sidconf.para.sid.vid =
++                      nla_get_u16(sid[TSN_STREAMID_ATTR_SVID]);
++              break;
++      case STREAMID_DMAC_VLAN:
++
++      case STREAMID_IP:
++
++      default:
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      if (sid[TSN_STREAMID_ATTR_STREAM_HANDLE])
++              sidconf.handle =
++                      nla_get_s32(sid[TSN_STREAMID_ATTR_STREAM_HANDLE]);
++
++      if (sid[TSN_STREAMID_ATTR_IFOP])
++              sidconf.ifac_oport = nla_get_u32(sid[TSN_STREAMID_ATTR_IFOP]);
++      if (sid[TSN_STREAMID_ATTR_OFOP])
++              sidconf.ofac_oport = nla_get_u32(sid[TSN_STREAMID_ATTR_OFOP]);
++      if (sid[TSN_STREAMID_ATTR_IFIP])
++              sidconf.ifac_iport = nla_get_u32(sid[TSN_STREAMID_ATTR_IFIP]);
++      if (sid[TSN_STREAMID_ATTR_OFIP])
++              sidconf.ofac_iport = nla_get_u32(sid[TSN_STREAMID_ATTR_OFIP]);
++
++loaddev:
++      if (!tsnops->cb_streamid_set) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -EOPNOTSUPP;
++      }
++
++      ret = tsnops->cb_streamid_set(netdev, sid_index, enable, &sidconf);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
++              return ret;
++      }
++
++      /* simple reply here. To be continue */
++      if (tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, 0))
++              return -1;
++
++      return 0;
++}
++
++static int tsn_cb_streamid_set(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME]) {
++              cmd_cb_streamid_set(info);
++              return 0;
++      }
++
++      return -1;
++}
++
++static int cmd_cb_streamid_get(struct genl_info *info)
++{
++      struct nlattr *na, *sidattr, *sid[TSN_STREAMID_ATTR_MAX + 1];
++      u32 sid_index;
++      struct genlmsghdr *genlhdr;
++      struct sk_buff *rep_skb;
++      int ret, i;
++      int valid;
++      struct net_device *netdev;
++      struct tsn_cb_streamid sidconf;
++      struct tsn_cb_streamid_counters sidcounts;
++      const struct tsn_ops *tsnops;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      memset(&sidconf, 0, sizeof(struct tsn_cb_streamid));
++      memset(&sidcounts, 0, sizeof(struct tsn_cb_streamid_counters));
++
++      if (!info->attrs[TSN_ATTR_STREAM_IDENTIFY])
++              return -EINVAL;
++
++      na = info->attrs[TSN_ATTR_STREAM_IDENTIFY];
++
++      ret = NLA_PARSE_NESTED(sid, TSN_STREAMID_ATTR_MAX,
++                             na, cb_streamid_policy);
++      if (ret)
++              return -EINVAL;
++
++      if (!sid[TSN_STREAMID_ATTR_INDEX])
++              return -EINVAL;
++
++      sid_index = nla_get_u32(sid[TSN_STREAMID_ATTR_INDEX]);
++
++      if (!tsnops->cb_streamid_get) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              ret = -EINVAL;
++              goto exit;
++      } else {
++              valid = tsnops->cb_streamid_get(netdev, sid_index, &sidconf);
++              if (valid < 0) {
++                      tsn_simple_reply(info, TSN_CMD_REPLY,
++                                       netdev->name, valid);
++                      return valid;
++              }
++      }
++
++      /* send back */
++      genlhdr = info->genlhdr;
++      ret = tsn_prepare_reply(info, genlhdr->cmd, &rep_skb,
++                              NLMSG_ALIGN(MAX_ATTR_SIZE));
++      if (ret < 0)
++              return ret;
++
++      /* input netlink the parameters */
++      sidattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_STREAM_IDENTIFY);
++      if (!sidattr) {
++              ret = -EINVAL;
++              goto err;
++      }
++
++      if (nla_put_u32(rep_skb, TSN_STREAMID_ATTR_INDEX, sid_index))
++              return -EMSGSIZE;
++
++      if (valid == 1) {
++              nla_put_flag(rep_skb, TSN_STREAMID_ATTR_ENABLE);
++      } else if (valid == 0) {
++              nla_put_flag(rep_skb, TSN_STREAMID_ATTR_DISABLE);
++      } else {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              goto err;
++      }
++
++      if (nla_put_s32(rep_skb,
++                      TSN_STREAMID_ATTR_STREAM_HANDLE, sidconf.handle) ||
++          nla_put_u32(rep_skb, TSN_STREAMID_ATTR_IFOP, sidconf.ifac_oport) ||
++          nla_put_u32(rep_skb, TSN_STREAMID_ATTR_OFOP, sidconf.ofac_oport) ||
++          nla_put_u32(rep_skb, TSN_STREAMID_ATTR_IFIP, sidconf.ifac_iport) ||
++          nla_put_u32(rep_skb, TSN_STREAMID_ATTR_OFIP, sidconf.ofac_iport) ||
++          nla_put_u8(rep_skb, TSN_STREAMID_ATTR_TYPE, sidconf.type))
++              return -EMSGSIZE;
++
++      switch (sidconf.type) {
++      case STREAMID_NULL:
++              if (NLA_PUT_U64(rep_skb, TSN_STREAMID_ATTR_NDMAC,
++                              sidconf.para.nid.dmac) ||
++                  nla_put_u16(rep_skb, TSN_STREAMID_ATTR_NVID,
++                              sidconf.para.nid.vid) ||
++                  nla_put_u8(rep_skb, TSN_STREAMID_ATTR_NTAGGED,
++                             sidconf.para.nid.tagged))
++                      return -EMSGSIZE;
++              break;
++      case STREAMID_SMAC_VLAN:
++              if (NLA_PUT_U64(rep_skb, TSN_STREAMID_ATTR_SMAC,
++                              sidconf.para.sid.smac) ||
++                  nla_put_u16(rep_skb, TSN_STREAMID_ATTR_SVID,
++                              sidconf.para.sid.vid) ||
++                  nla_put_u8(rep_skb, TSN_STREAMID_ATTR_STAGGED,
++                             sidconf.para.sid.tagged))
++                      return -EMSGSIZE;
++              break;
++      case STREAMID_DMAC_VLAN:
++      case STREAMID_IP:
++      default:
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              goto err;
++      }
++
++      if (!tsnops->cb_streamid_counters_get) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              goto err;
++      } else {
++              ret = tsnops->cb_streamid_counters_get(netdev,
++                                                      sid_index,
++                                                      &sidcounts);
++              if (ret < 0) {
++                      tsn_simple_reply(info, TSN_CMD_REPLY,
++                                       netdev->name, ret);
++                      goto err;
++              }
++      }
++
++      if (NLA_PUT_U64(rep_skb, TSN_STREAMID_ATTR_COUNTERS_PSI,
++                      sidcounts.per_stream.input) ||
++          NLA_PUT_U64(rep_skb, TSN_STREAMID_ATTR_COUNTERS_PSO,
++                      sidcounts.per_stream.output))
++              return -EMSGSIZE;
++
++      for (i = 0; i < 32; i++) {
++              if (NLA_PUT_U64(rep_skb, TSN_STREAMID_ATTR_COUNTERS_PSPPI,
++                              sidcounts.per_streamport[i].input) ||
++                  NLA_PUT_U64(rep_skb, TSN_STREAMID_ATTR_COUNTERS_PSPPO,
++                              sidcounts.per_streamport[i].output))
++                      return -EMSGSIZE;
++      }
++
++      nla_nest_end(rep_skb, sidattr);
++      /* end netlink input the parameters */
++
++      /* netlink lib func */
++      ret = nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name);
++      if (ret < 0)
++              goto err;
++
++      ret = nla_put_s32(rep_skb, TSN_CMD_ATTR_DATA, 0);
++      if (ret < 0)
++              goto err;
++
++      return tsn_send_reply(rep_skb, info);
++
++err:
++      nlmsg_free(rep_skb);
++exit:
++      return ret;
++}
++
++static int tsn_cb_streamid_get(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME]) {
++              cmd_cb_streamid_get(info);
++              return 0;
++      }
++
++      return -1;
++}
++
++static int cmb_cb_streamid_counters_get(struct genl_info *info)
++{
++      return 0;
++}
++
++static int tsn_cb_streamid_counters_get(struct sk_buff *skb,
++                                      struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME]) {
++              cmb_cb_streamid_counters_get(info);
++              return 0;
++      }
++
++      return -1;
++}
++
++static int tsn_qci_cap_get(struct sk_buff *skb, struct genl_info *info)
++{
++      struct nlattr *qci_cap;
++      struct sk_buff *rep_skb;
++      int ret;
++      struct net_device *netdev;
++      struct genlmsghdr *genlhdr;
++      struct tsn_qci_psfp_stream_param qci_cap_status;
++      const struct tsn_ops *tsnops;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port) {
++              ret = -EINVAL;
++              goto out;
++      }
++
++      tsnops = port->tsnops;
++
++      genlhdr = info->genlhdr;
++
++      memset(&qci_cap_status, 0, sizeof(qci_cap_status));
++
++      if (!tsnops->qci_get_maxcap) {
++              ret = -EOPNOTSUPP;
++              goto out;
++      }
++
++      ret = tsnops->qci_get_maxcap(netdev, &qci_cap_status);
++      if (ret < 0)
++              goto out;
++
++      /* Pad netlink reply data */
++      ret = tsn_prepare_reply(info, genlhdr->cmd,
++                              &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
++      if (ret < 0)
++              goto out;
++
++      if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name)) {
++              ret = -EMSGSIZE;
++              goto err;
++      }
++
++      qci_cap = nla_nest_start_noflag(rep_skb, TSN_ATTR_QCI_SP);
++      if (!qci_cap) {
++              ret = -EMSGSIZE;
++              goto err;
++      }
++
++      if (nla_put_u32(rep_skb, TSN_QCI_STREAM_ATTR_MAX_SFI,
++                      qci_cap_status.max_sf_instance) ||
++              nla_put_u32(rep_skb, TSN_QCI_STREAM_ATTR_MAX_SGI,
++                          qci_cap_status.max_sg_instance) ||
++              nla_put_u32(rep_skb, TSN_QCI_STREAM_ATTR_MAX_FMI,
++                          qci_cap_status.max_fm_instance) ||
++              nla_put_u32(rep_skb, TSN_QCI_STREAM_ATTR_SLM,
++                          qci_cap_status.supported_list_max)) {
++              ret = -EMSGSIZE;
++              goto err;
++      }
++
++      nla_nest_end(rep_skb, qci_cap);
++
++      tsn_send_reply(rep_skb, info);
++
++      return 0;
++err:
++      nlmsg_free(rep_skb);
++out:
++      if (ret < 0)
++              tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
++
++      return ret;
++}
++
++static int cmd_qci_sfi_set(struct genl_info *info)
++{
++      struct nlattr *na, *sfi[TSN_QCI_SFI_ATTR_MAX + 1];
++      u32 sfi_handle;
++      bool enable;
++      int ret;
++      struct net_device *netdev;
++      struct tsn_qci_psfp_sfi_conf sficonf;
++      const struct tsn_ops *tsnops;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      memset(&sficonf, 0, sizeof(struct tsn_qci_psfp_sfi_conf));
++
++      if (!info->attrs[TSN_ATTR_QCI_SFI])
++              return -EINVAL;
++
++      na = info->attrs[TSN_ATTR_QCI_SFI];
++
++      ret = NLA_PARSE_NESTED(sfi, TSN_QCI_SFI_ATTR_MAX, na, qci_sfi_policy);
++      if (ret) {
++              pr_info("tsn: parse value TSN_QCI_SFI_ATTR_MAX  error.");
++              return -EINVAL;
++      }
++
++      if (!sfi[TSN_QCI_SFI_ATTR_INDEX])
++              return -EINVAL;
++
++      sfi_handle = nla_get_u32(sfi[TSN_QCI_SFI_ATTR_INDEX]);
++
++      if (sfi[TSN_QCI_SFI_ATTR_ENABLE]) {
++              enable = true;
++      } else if (sfi[TSN_QCI_SFI_ATTR_DISABLE]) {
++              enable = false;
++              goto loaddrive;
++      } else {
++              pr_err("tsn: must provde ENABLE or DISABLE attribute.\n");
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      if (!sfi[TSN_QCI_SFI_ATTR_GATE_ID]) {
++              pr_err("tsn: must provide stream gate index\n");
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      if (!sfi[TSN_QCI_SFI_ATTR_STREAM_HANDLE])
++              sficonf.stream_handle_spec = -1;
++      else
++              sficonf.stream_handle_spec =
++                      nla_get_s32(sfi[TSN_QCI_SFI_ATTR_STREAM_HANDLE]);
++
++      if (!sfi[TSN_QCI_SFI_ATTR_PRIO_SPEC])
++              sficonf.priority_spec = -1;
++      else
++              sficonf.priority_spec =
++                      nla_get_s8(sfi[TSN_QCI_SFI_ATTR_PRIO_SPEC]);
++
++      sficonf.stream_gate_instance_id =
++                      nla_get_u32(sfi[TSN_QCI_SFI_ATTR_GATE_ID]);
++
++      if (sfi[TSN_QCI_SFI_ATTR_MAXSDU])
++              sficonf.stream_filter.maximum_sdu_size =
++                      nla_get_u16(sfi[TSN_QCI_SFI_ATTR_MAXSDU]);
++      else
++              sficonf.stream_filter.maximum_sdu_size = 0;
++
++      if (sfi[TSN_QCI_SFI_ATTR_FLOW_ID])
++              sficonf.stream_filter.flow_meter_instance_id =
++                      nla_get_s32(sfi[TSN_QCI_SFI_ATTR_FLOW_ID]);
++      else
++              sficonf.stream_filter.flow_meter_instance_id = -1;
++
++      if (sfi[TSN_QCI_SFI_ATTR_OVERSIZE_ENABLE])
++              sficonf.block_oversize_enable = true;
++
++      if (sfi[TSN_QCI_SFI_ATTR_OVERSIZE])
++              sficonf.block_oversize = true;
++
++loaddrive:
++      if (!tsnops->qci_sfi_set) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -EINVAL;
++      }
++
++      ret = tsnops->qci_sfi_set(netdev, sfi_handle, enable, &sficonf);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
++              return ret;
++      }
++
++      ret = tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, 0);
++
++      if (ret)
++              return ret;
++      return 0;
++}
++
++static int tsn_qci_sfi_set(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME]) {
++              cmd_qci_sfi_set(info);
++              return 0;
++      }
++
++      return -1;
++}
++
++static int cmd_qci_sfi_get(struct genl_info *info)
++{
++      struct nlattr *na, *sfiattr;
++      struct nlattr *sfi[TSN_QCI_SFI_ATTR_MAX + 1];
++      u32 sfi_handle;
++      struct sk_buff *rep_skb;
++      int ret, valid = 0;
++      struct net_device *netdev;
++      struct genlmsghdr *genlhdr;
++      struct tsn_qci_psfp_sfi_conf sficonf;
++      struct tsn_qci_psfp_sfi_counters sficount;
++      const struct tsn_ops *tsnops;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      genlhdr = info->genlhdr;
++
++      if (!info->attrs[TSN_ATTR_QCI_SFI])
++              return -EINVAL;
++
++      na = info->attrs[TSN_ATTR_QCI_SFI];
++
++      ret = NLA_PARSE_NESTED(sfi, TSN_QCI_SFI_ATTR_MAX,
++                             na, qci_sfi_policy);
++      if (ret)
++              return -EINVAL;
++
++      if (!sfi[TSN_QCI_SFI_ATTR_INDEX])
++              return -EINVAL;
++
++      sfi_handle = nla_get_u32(sfi[TSN_QCI_SFI_ATTR_INDEX]);
++
++      memset(&sficonf, 0, sizeof(struct tsn_qci_psfp_sfi_conf));
++      memset(&sficount, 0, sizeof(struct tsn_qci_psfp_sfi_counters));
++
++      if (!tsnops->qci_sfi_get || !tsnops->qci_sfi_counters_get) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              ret = -EINVAL;
++              goto exit;
++      } else {
++              valid = tsnops->qci_sfi_get(netdev, sfi_handle, &sficonf);
++              if (valid < 0) {
++                      tsn_simple_reply(info, TSN_CMD_REPLY,
++                                       netdev->name, valid);
++                      return valid;
++              }
++
++              valid = tsnops->qci_sfi_counters_get(netdev, sfi_handle,
++                                                   &sficount);
++              if (valid < 0) {
++                      tsn_simple_reply(info, TSN_CMD_REPLY,
++                                       netdev->name, valid);
++                      return valid;
++              }
++      }
++
++      ret = tsn_prepare_reply(info, genlhdr->cmd,
++                              &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
++      if (ret < 0)
++              return ret;
++
++      if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
++              goto err;
++
++      sfiattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_QCI_SFI);
++      if (!sfiattr) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              ret = -EINVAL;
++              goto err;
++      }
++
++      if (nla_put_u32(rep_skb, TSN_QCI_SFI_ATTR_INDEX, sfi_handle))
++              return -EMSGSIZE;
++
++      if (valid) {
++              if (nla_put_flag(rep_skb, TSN_QCI_SFI_ATTR_ENABLE))
++                      return -EMSGSIZE;
++      } else {
++              if (nla_put_flag(rep_skb, TSN_QCI_SFI_ATTR_DISABLE))
++                      return -EMSGSIZE;
++      }
++
++      if (nla_put_s32(rep_skb, TSN_QCI_SFI_ATTR_STREAM_HANDLE,
++                      sficonf.stream_handle_spec) ||
++          nla_put_s8(rep_skb, TSN_QCI_SFI_ATTR_PRIO_SPEC,
++                     sficonf.priority_spec) ||
++          nla_put_u32(rep_skb, TSN_QCI_SFI_ATTR_GATE_ID,
++                      sficonf.stream_gate_instance_id))
++              return -EMSGSIZE;
++
++      if (sficonf.stream_filter.maximum_sdu_size)
++              if (nla_put_u16(rep_skb, TSN_QCI_SFI_ATTR_MAXSDU,
++                              sficonf.stream_filter.maximum_sdu_size))
++                      return -EMSGSIZE;
++
++      if (sficonf.stream_filter.flow_meter_instance_id >= 0)
++              if (nla_put_s32(rep_skb, TSN_QCI_SFI_ATTR_FLOW_ID,
++                              sficonf.stream_filter.flow_meter_instance_id))
++                      return -EMSGSIZE;
++
++      if (sficonf.block_oversize_enable)
++              if (nla_put_flag(rep_skb, TSN_QCI_SFI_ATTR_OVERSIZE_ENABLE))
++                      return -EMSGSIZE;
++      if (sficonf.block_oversize)
++              if (nla_put_flag(rep_skb, TSN_QCI_SFI_ATTR_OVERSIZE))
++                      return -EMSGSIZE;
++
++      if (nla_put(rep_skb, TSN_QCI_SFI_ATTR_COUNTERS,
++                  sizeof(struct tsn_qci_psfp_sfi_counters), &sficount))
++              return -EMSGSIZE;
++
++      nla_nest_end(rep_skb, sfiattr);
++
++      return tsn_send_reply(rep_skb, info);
++err:
++      nlmsg_free(rep_skb);
++      tsn_simple_reply(info, TSN_CMD_REPLY,
++                       netdev->name, -EINVAL);
++exit:
++      return ret;
++}
++
++static int tsn_qci_sfi_get(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME]) {
++              cmd_qci_sfi_get(info);
++              return 0;
++      }
++
++      return -1;
++}
++
++static int cmd_qci_sfi_counters_get(struct genl_info *info)
++{
++      struct nlattr *na, *sfiattr;
++      struct nlattr *sfi[TSN_QCI_SFI_ATTR_MAX + 1];
++      u32 sfi_handle;
++      struct sk_buff *rep_skb;
++      int ret;
++      struct net_device *netdev;
++      struct genlmsghdr *genlhdr;
++      struct tsn_qci_psfp_sfi_counters sficount;
++      const struct tsn_ops *tsnops;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      genlhdr = info->genlhdr;
++
++      if (!info->attrs[TSN_ATTR_QCI_SFI])
++              return -EINVAL;
++
++      na = info->attrs[TSN_ATTR_QCI_SFI];
++
++      ret = NLA_PARSE_NESTED(sfi, TSN_QCI_SFI_ATTR_MAX,
++                             na, qci_sfi_policy);
++      if (ret)
++              return -EINVAL;
++
++      if (!sfi[TSN_QCI_SFI_ATTR_INDEX])
++              return -EINVAL;
++
++      sfi_handle = nla_get_u32(sfi[TSN_QCI_SFI_ATTR_INDEX]);
++
++      memset(&sficount, 0, sizeof(struct tsn_qci_psfp_sfi_counters));
++      if (!tsnops->qci_sfi_counters_get) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -1;
++      }
++
++      ret = tsnops->qci_sfi_counters_get(netdev, sfi_handle, &sficount);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++              return ret;
++      }
++
++      ret = tsn_prepare_reply(info, genlhdr->cmd, &rep_skb,
++                              NLMSG_ALIGN(MAX_ATTR_SIZE));
++      if (ret < 0)
++              return ret;
++
++      if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
++              goto err;
++
++      sfiattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_QCI_SFI);
++      if (!sfiattr) {
++              ret = -EINVAL;
++              goto err;
++      }
++
++      if (nla_put_u32(rep_skb, TSN_QCI_SFI_ATTR_INDEX, sfi_handle))
++              return -EMSGSIZE;
++
++      ret = tsnops->qci_sfi_counters_get(netdev, sfi_handle, &sficount);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
++              return ret;
++      }
++
++      if (nla_put(rep_skb, TSN_QCI_SFI_ATTR_COUNTERS,
++                  sizeof(struct tsn_qci_psfp_sfi_counters), &sficount))
++              return -EMSGSIZE;
++
++      nla_nest_end(rep_skb, sfiattr);
++
++      return tsn_send_reply(rep_skb, info);
++err:
++      nlmsg_free(rep_skb);
++      tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, -EINVAL);
++      return ret;
++}
++
++static int tsn_qci_sfi_counters_get(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME]) {
++              cmd_qci_sfi_counters_get(info);
++              return 0;
++      }
++
++      return -1;
++}
++
++static int cmd_qci_sgi_set(struct genl_info *info)
++{
++      struct nlattr *na;
++      struct nlattr *sgia[TSN_QCI_SGI_ATTR_MAX + 1];
++      struct nlattr *admin[TSN_SGI_ATTR_CTRL_MAX + 1];
++      int ret = 0;
++      struct net_device *netdev;
++      const struct tsn_ops *tsnops;
++      struct tsn_qci_psfp_sgi_conf sgi;
++      struct tsn_qci_psfp_gcl *gcl = NULL;
++      u16 sgi_handle = 0;
++      u16 listcount = 0;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      memset(&sgi, 0, sizeof(struct tsn_qci_psfp_sgi_conf));
++
++      if (!info->attrs[TSN_ATTR_QCI_SGI]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      na = info->attrs[TSN_ATTR_QCI_SGI];
++
++      ret = NLA_PARSE_NESTED(sgia, TSN_QCI_SGI_ATTR_MAX,
++                             na, qci_sgi_policy);
++      if (ret) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      if (sgia[TSN_QCI_SGI_ATTR_ENABLE] && sgia[TSN_QCI_SGI_ATTR_DISABLE]) {
++              pr_err("tsn: enable or disable?\n");
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -1;
++      }
++
++      if (sgia[TSN_QCI_SGI_ATTR_INDEX])
++              sgi_handle = nla_get_u32(sgia[TSN_QCI_SGI_ATTR_INDEX]);
++
++      if (sgia[TSN_QCI_SGI_ATTR_DISABLE]) {
++              sgi.gate_enabled = 0;
++              goto loaddev;
++      } else {
++              /* set default to be enable*/
++              sgi.gate_enabled = 1;
++      }
++
++      if (sgia[TSN_QCI_SGI_ATTR_CONFCHANGE])
++              sgi.config_change = 1;
++
++      if (sgia[TSN_QCI_SGI_ATTR_IRXEN])
++              sgi.block_invalid_rx_enable = 1;
++
++      if (sgia[TSN_QCI_SGI_ATTR_IRX])
++              sgi.block_invalid_rx = 1;
++
++      if (sgia[TSN_QCI_SGI_ATTR_OEXEN])
++              sgi.block_octets_exceeded_enable = 1;
++
++      if (sgia[TSN_QCI_SGI_ATTR_OEX])
++              sgi.block_octets_exceeded = 1;
++
++      if (sgia[TSN_QCI_SGI_ATTR_ADMINENTRY]) {
++              struct nlattr *entry;
++              int rem;
++              int count = 0;
++
++              na = sgia[TSN_QCI_SGI_ATTR_ADMINENTRY];
++              ret = NLA_PARSE_NESTED(admin, TSN_SGI_ATTR_CTRL_MAX,
++                                     na, qci_sgi_ctrl_policy);
++
++              /* Other parameters in admin control */
++              if (admin[TSN_SGI_ATTR_CTRL_INITSTATE])
++                      sgi.admin.gate_states = 1;
++
++              if (admin[TSN_SGI_ATTR_CTRL_CYTIME])
++                      sgi.admin.cycle_time =
++                              nla_get_u32(admin[TSN_SGI_ATTR_CTRL_CYTIME]);
++
++              if (admin[TSN_SGI_ATTR_CTRL_CYTIMEEX])
++                      sgi.admin.cycle_time_extension =
++                              nla_get_u32(admin[TSN_SGI_ATTR_CTRL_CYTIMEEX]);
++
++              if (admin[TSN_SGI_ATTR_CTRL_BTIME])
++                      sgi.admin.base_time =
++                              nla_get_u64(admin[TSN_SGI_ATTR_CTRL_BTIME]);
++
++              if (admin[TSN_SGI_ATTR_CTRL_INITIPV])
++                      sgi.admin.init_ipv =
++                              nla_get_s8(admin[TSN_SGI_ATTR_CTRL_INITIPV]);
++              else
++                      sgi.admin.init_ipv = -1;
++
++              if (admin[TSN_SGI_ATTR_CTRL_LEN]) {
++                      sgi.admin.control_list_length =
++                              nla_get_u8(admin[TSN_SGI_ATTR_CTRL_LEN]);
++                      listcount = sgi.admin.control_list_length;
++              }
++
++              if (!listcount)
++                      goto loaddev;
++
++              gcl = kmalloc_array(listcount, sizeof(*gcl), GFP_KERNEL);
++
++              memset(gcl, 0, listcount * sizeof(struct tsn_qci_psfp_gcl));
++
++              /* Check the whole admin attrs,
++               * checkout the TSN_SGI_ATTR_CTRL_GCLENTRY attributes
++               */
++              nla_for_each_nested(entry, na, rem) {
++                      struct nlattr *gcl_entry[TSN_SGI_ATTR_GCL_MAX + 1];
++                      struct nlattr *ti, *om;
++
++                      if (nla_type(entry) != TSN_SGI_ATTR_CTRL_GCLENTRY)
++                              continue;
++
++                      /* parse each TSN_SGI_ATTR_CTRL_GCLENTRY */
++                      ret = NLA_PARSE_NESTED(gcl_entry, TSN_SGI_ATTR_GCL_MAX,
++                                             entry, qci_sgi_gcl_policy);
++                      /* Parse gate control list */
++                      if (gcl_entry[TSN_SGI_ATTR_GCL_GATESTATE])
++                              (gcl + count)->gate_state = 1;
++
++                      if (gcl_entry[TSN_SGI_ATTR_GCL_IPV])
++                              (gcl + count)->ipv =
++                               nla_get_s8(gcl_entry[TSN_SGI_ATTR_GCL_IPV]);
++
++                      if (gcl_entry[TSN_SGI_ATTR_GCL_INTERVAL]) {
++                              ti = gcl_entry[TSN_SGI_ATTR_GCL_INTERVAL];
++                              (gcl + count)->time_interval = nla_get_u32(ti);
++                      }
++
++                      if (gcl_entry[TSN_SGI_ATTR_GCL_OCTMAX]) {
++                              om = gcl_entry[TSN_SGI_ATTR_GCL_OCTMAX];
++                              (gcl + count)->octet_max = nla_get_u32(om);
++                      }
++
++                      count++;
++
++                      if (count >= listcount)
++                              break;
++              }
++
++              if (count < listcount) {
++                      tsn_simple_reply(info, TSN_CMD_REPLY,
++                                       netdev->name, -EINVAL);
++                      pr_err("tsn: count less than TSN_SGI_ATTR_CTRL_LEN\n");
++                      kfree(gcl);
++                      return -EINVAL;
++              }
++
++      } else {
++              pr_info("tsn: no admin list parameters setting\n");
++      }
++
++loaddev:
++      if (!tsnops->qci_sgi_set) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              kfree(gcl);
++              return -EINVAL;
++      }
++
++      sgi.admin.gcl = gcl;
++
++      ret = tsnops->qci_sgi_set(netdev, sgi_handle, &sgi);
++      kfree(gcl);
++      if (!ret)
++              return tsn_simple_reply(info, TSN_CMD_REPLY,
++                                      netdev->name, 0);
++
++      tsn_simple_reply(info, TSN_CMD_REPLY,
++                       netdev->name, ret);
++      return ret;
++}
++
++static int tsn_qci_sgi_set(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME]) {
++              cmd_qci_sgi_set(info);
++              return 0;
++      }
++
++      return -1;
++}
++
++static int cmd_qci_sgi_get(struct genl_info *info)
++{
++      struct nlattr *na, *sgiattr, *adminattr, *sglattr;
++      struct nlattr *sgi[TSN_QCI_SGI_ATTR_MAX + 1];
++      struct sk_buff *rep_skb;
++      int ret;
++      struct net_device *netdev;
++      struct genlmsghdr *genlhdr;
++      struct tsn_qci_psfp_sgi_conf sgiadmin;
++      struct tsn_qci_psfp_gcl *gcl = NULL;
++      const struct tsn_ops *tsnops;
++      u16 sgi_handle;
++      u8 listcount, i;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      if (!info->attrs[TSN_ATTR_QCI_SGI]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              pr_err("tsn: no sgi handle input\n");
++              return -EINVAL;
++      }
++
++      na = info->attrs[TSN_ATTR_QCI_SGI];
++
++      ret = NLA_PARSE_NESTED(sgi, TSN_QCI_SGI_ATTR_MAX,
++                             na, qci_sgi_policy);
++      if (ret)
++              return -EINVAL;
++
++      if (!sgi[TSN_QCI_SGI_ATTR_INDEX]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              pr_err("tsn: no sgi handle input\n");
++              return -EINVAL;
++      }
++
++      sgi_handle = nla_get_u32(sgi[TSN_QCI_SGI_ATTR_INDEX]);
++
++      /* Get config data from device */
++      genlhdr = info->genlhdr;
++
++      memset(&sgiadmin, 0, sizeof(struct tsn_qci_psfp_sgi_conf));
++
++      if (!tsnops->qci_sgi_get) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -1;
++      }
++
++      ret = tsnops->qci_sgi_get(netdev, sgi_handle, &sgiadmin);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++              return ret;
++      }
++
++      /* Form netlink reply data */
++      ret = tsn_prepare_reply(info, genlhdr->cmd,
++                              &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
++      if (ret < 0)
++              return ret;
++
++      if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
++              return -EMSGSIZE;
++
++      sgiattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_QCI_SGI);
++      if (!sgiattr)
++              return -EMSGSIZE;
++
++      if (nla_put_u32(rep_skb, TSN_QCI_SGI_ATTR_INDEX, sgi_handle))
++              return -EMSGSIZE;
++
++      /* Gate enable? sgiadmin.gate_enabled */
++      if (sgiadmin.gate_enabled) {
++              if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_ENABLE))
++                      return -EMSGSIZE;
++      } else {
++              if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_DISABLE))
++                      return -EMSGSIZE;
++      }
++
++      if (sgiadmin.config_change)
++              if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_CONFCHANGE))
++                      return -EMSGSIZE;
++
++      if (sgiadmin.block_invalid_rx_enable)
++              if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_IRXEN))
++                      return -EMSGSIZE;
++
++      if (sgiadmin.block_invalid_rx)
++              if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_IRX))
++                      return -EMSGSIZE;
++
++      if (sgiadmin.block_octets_exceeded_enable)
++              if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_OEXEN))
++                      return -EMSGSIZE;
++
++      if (sgiadmin.block_octets_exceeded)
++              if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_OEX))
++                      return -EMSGSIZE;
++
++      /* Administration */
++      adminattr = nla_nest_start_noflag(rep_skb, TSN_QCI_SGI_ATTR_ADMINENTRY);
++      if (!adminattr)
++              return -EMSGSIZE;
++
++      if (sgiadmin.admin.gate_states)
++              if (nla_put_flag(rep_skb, TSN_SGI_ATTR_CTRL_INITSTATE))
++                      return -EMSGSIZE;
++
++      if (nla_put_u32(rep_skb, TSN_SGI_ATTR_CTRL_CYTIME,
++                      sgiadmin.admin.cycle_time) ||
++          nla_put_u32(rep_skb, TSN_SGI_ATTR_CTRL_CYTIMEEX,
++                      sgiadmin.admin.cycle_time_extension) ||
++          NLA_PUT_U64(rep_skb, TSN_SGI_ATTR_CTRL_BTIME,
++                      sgiadmin.admin.base_time) ||
++          nla_put_u8(rep_skb, TSN_SGI_ATTR_CTRL_INITIPV,
++                     sgiadmin.admin.init_ipv))
++              return -EMSGSIZE;
++
++      listcount = sgiadmin.admin.control_list_length;
++      if (!listcount)
++              goto out1;
++
++      if (!sgiadmin.admin.gcl) {
++              pr_err("error: no gate control list\n");
++              ret = -EINVAL;
++              goto err;
++      }
++
++      gcl = sgiadmin.admin.gcl;
++
++      /* loop list */
++      for (i = 0; i < listcount; i++) {
++              s8 ipv;
++              u32 ti, omax;
++
++              if (!(gcl + i)) {
++                      pr_err("error: list count too big\n");
++                      ret = -EINVAL;
++                      kfree(sgiadmin.admin.gcl);
++                      goto err;
++              }
++
++              /* Adminastration entry */
++              sglattr = nla_nest_start_noflag(rep_skb,
++                                              TSN_SGI_ATTR_CTRL_GCLENTRY);
++              if (!sglattr)
++                      return -EMSGSIZE;
++              ipv = (gcl + i)->ipv;
++              ti = (gcl + i)->time_interval;
++              omax = (gcl + i)->octet_max;
++
++              if ((gcl + i)->gate_state)
++                      if (nla_put_flag(rep_skb, TSN_SGI_ATTR_GCL_GATESTATE))
++                              return -EMSGSIZE;
++
++              if (nla_put_s8(rep_skb, TSN_SGI_ATTR_GCL_IPV, ipv) ||
++                  nla_put_u32(rep_skb, TSN_SGI_ATTR_GCL_INTERVAL, ti) ||
++                  nla_put_u32(rep_skb, TSN_SGI_ATTR_GCL_OCTMAX, omax))
++                      return -EMSGSIZE;
++
++              /* End administration entry */
++              nla_nest_end(rep_skb, sglattr);
++      }
++
++      kfree(sgiadmin.admin.gcl);
++      if (nla_put_u8(rep_skb, TSN_SGI_ATTR_CTRL_LEN, listcount))
++              return -EMSGSIZE;
++
++out1:
++      /* End adminastration */
++      nla_nest_end(rep_skb, adminattr);
++
++      nla_nest_end(rep_skb, sgiattr);
++
++      return tsn_send_reply(rep_skb, info);
++err:
++      nlmsg_free(rep_skb);
++      tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
++      return ret;
++}
++
++static int tsn_qci_sgi_get(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME]) {
++              cmd_qci_sgi_get(info);
++              return 0;
++      }
++
++      return -1;
++}
++
++static int cmd_qci_sgi_status_get(struct genl_info *info)
++{
++      struct nlattr *na, *sgiattr, *operattr, *sglattr;
++      struct nlattr *sgi[TSN_QCI_SGI_ATTR_MAX + 1];
++      struct sk_buff *rep_skb;
++      int ret;
++      struct net_device *netdev;
++      struct genlmsghdr *genlhdr;
++      struct tsn_psfp_sgi_status sgistat;
++      struct tsn_qci_psfp_gcl *gcl = NULL;
++      const struct tsn_ops *tsnops;
++      u16 sgi_handle;
++      u8 listcount;
++      int valid, i;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      if (!info->attrs[TSN_ATTR_QCI_SGI]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              pr_err("tsn: no sgi handle input\n");
++              return -EINVAL;
++      }
++
++      na = info->attrs[TSN_ATTR_QCI_SGI];
++
++      ret = NLA_PARSE_NESTED(sgi, TSN_QCI_SGI_ATTR_MAX,
++                             na, qci_sgi_policy);
++      if (ret)
++              return -EINVAL;
++
++      if (!sgi[TSN_QCI_SGI_ATTR_INDEX]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              pr_err("tsn: no sgi handle input\n");
++              return -EINVAL;
++      }
++
++      sgi_handle = nla_get_u32(sgi[TSN_QCI_SGI_ATTR_INDEX]);
++
++      /* Get status data from device */
++      genlhdr = info->genlhdr;
++
++      memset(&sgistat, 0, sizeof(struct tsn_psfp_sgi_status));
++
++      if (!tsnops->qci_sgi_status_get) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -1;
++      }
++
++      valid = tsnops->qci_sgi_status_get(netdev, sgi_handle, &sgistat);
++      if (valid < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, valid);
++              return valid;
++      }
++
++      /* Form netlink reply data */
++      ret = tsn_prepare_reply(info, genlhdr->cmd,
++                              &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
++      if (ret < 0)
++              return ret;
++
++      if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
++              return -EMSGSIZE;
++
++      /* Down one netlink attribute level */
++      sgiattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_QCI_SGI);
++      if (!sgiattr)
++              return -EMSGSIZE;
++
++      if (nla_put_u32(rep_skb, TSN_QCI_SGI_ATTR_INDEX, sgi_handle))
++              return -EMSGSIZE;
++
++      /* Gate enable */
++      if (valid == 1) {
++              if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_ENABLE))
++                      return -EMSGSIZE;
++      } else {
++              if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_DISABLE))
++                      return -EMSGSIZE;
++      }
++
++      if (nla_put_u32(rep_skb, TSN_QCI_SGI_ATTR_TICKG,
++                      sgistat.tick_granularity) ||
++          NLA_PUT_U64(rep_skb, TSN_QCI_SGI_ATTR_CCTIME,
++                      sgistat.config_change_time) ||
++          NLA_PUT_U64(rep_skb, TSN_QCI_SGI_ATTR_CUTIME,
++                      sgistat.current_time) ||
++          NLA_PUT_U64(rep_skb, TSN_QCI_SGI_ATTR_CCERROR,
++                      sgistat.config_change_error))
++              return -EMSGSIZE;
++
++      if (sgistat.config_pending)
++              if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_CPENDING))
++                      return -EMSGSIZE;
++
++      /* operation data */
++      operattr = nla_nest_start_noflag(rep_skb, TSN_QCI_SGI_ATTR_OPERENTRY);
++      if (!operattr)
++              return -EMSGSIZE;
++
++      if (sgistat.oper.gate_states)
++              if (nla_put_flag(rep_skb, TSN_SGI_ATTR_CTRL_INITSTATE))
++                      return -EMSGSIZE;
++
++      if (nla_put_u32(rep_skb, TSN_SGI_ATTR_CTRL_CYTIME,
++                      sgistat.oper.cycle_time) ||
++          nla_put_u32(rep_skb, TSN_SGI_ATTR_CTRL_CYTIMEEX,
++                      sgistat.oper.cycle_time_extension) ||
++          NLA_PUT_U64(rep_skb, TSN_SGI_ATTR_CTRL_BTIME,
++                      sgistat.oper.base_time) ||
++          nla_put_u8(rep_skb, TSN_SGI_ATTR_CTRL_INITIPV,
++                     sgistat.oper.init_ipv))
++              return -EMSGSIZE;
++
++      /* Loop list */
++      listcount = sgistat.oper.control_list_length;
++      if (!listcount)
++              goto out1;
++
++      if (!sgistat.oper.gcl) {
++              pr_err("error: list lenghth is not zero!\n");
++              ret = -EINVAL;
++              goto err;
++      }
++
++      gcl = sgistat.oper.gcl;
++
++      /* loop list */
++      for (i = 0; i < listcount; i++) {
++              s8 ipv;
++              u32 ti, omax;
++
++              if (!(gcl + i)) {
++                      pr_err("error: list count too big\n");
++                      ret = -EINVAL;
++                      kfree(sgistat.oper.gcl);
++                      goto err;
++              }
++
++              /* Operation entry */
++              sglattr = nla_nest_start_noflag(rep_skb,
++                                              TSN_SGI_ATTR_CTRL_GCLENTRY);
++              if (!sglattr)
++                      return -EMSGSIZE;
++              ipv = (gcl + i)->ipv;
++              ti = (gcl + i)->time_interval;
++              omax = (gcl + i)->octet_max;
++
++              if ((gcl + i)->gate_state)
++                      if (nla_put_flag(rep_skb, TSN_SGI_ATTR_GCL_GATESTATE))
++                              return -EMSGSIZE;
++
++              if (nla_put_s8(rep_skb, TSN_SGI_ATTR_GCL_IPV, ipv) ||
++                  nla_put_u32(rep_skb, TSN_SGI_ATTR_GCL_INTERVAL, ti) ||
++                  nla_put_u32(rep_skb, TSN_SGI_ATTR_GCL_OCTMAX, omax))
++                      return -EMSGSIZE;
++
++              /* End operation entry */
++              nla_nest_end(rep_skb, sglattr);
++      }
++
++      kfree(sgistat.oper.gcl);
++      if (nla_put_u8(rep_skb, TSN_SGI_ATTR_CTRL_LEN, listcount))
++              return -EMSGSIZE;
++out1:
++      /* End operation */
++      nla_nest_end(rep_skb, operattr);
++
++      nla_nest_end(rep_skb, sgiattr);
++
++      return tsn_send_reply(rep_skb, info);
++err:
++      nlmsg_free(rep_skb);
++      tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
++      return ret;
++}
++
++static int tsn_qci_sgi_status_get(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME]) {
++              cmd_qci_sgi_status_get(info);
++              return 0;
++      }
++
++      return -1;
++}
++
++static int cmd_qci_fmi_set(struct genl_info *info)
++{
++      struct nlattr *na, *fmi[TSN_QCI_FMI_ATTR_MAX + 1];
++      u32 index;
++      int ret;
++      struct net_device *netdev;
++      struct tsn_qci_psfp_fmi fmiconf;
++      const struct tsn_ops *tsnops;
++      bool enable = 0;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      memset(&fmiconf, 0, sizeof(struct tsn_qci_psfp_fmi));
++
++      if (!info->attrs[TSN_ATTR_QCI_FMI])
++              return -EINVAL;
++
++      na = info->attrs[TSN_ATTR_QCI_FMI];
++
++      ret = NLA_PARSE_NESTED(fmi, TSN_QCI_FMI_ATTR_MAX, na, qci_fmi_policy);
++      if (ret) {
++              pr_info("tsn: parse value TSN_QCI_FMI_ATTR_MAX  error.");
++              return -EINVAL;
++      }
++
++      if (!fmi[TSN_QCI_FMI_ATTR_INDEX])
++              return -EINVAL;
++
++      index = nla_get_u32(fmi[TSN_QCI_FMI_ATTR_INDEX]);
++
++      if (fmi[TSN_QCI_FMI_ATTR_DISABLE])
++              goto loaddev;
++
++      enable = 1;
++
++      if (fmi[TSN_QCI_FMI_ATTR_CIR])
++              fmiconf.cir = nla_get_u32(fmi[TSN_QCI_FMI_ATTR_CIR]);
++
++      if (fmi[TSN_QCI_FMI_ATTR_CBS])
++              fmiconf.cbs = nla_get_u32(fmi[TSN_QCI_FMI_ATTR_CBS]);
++
++      if (fmi[TSN_QCI_FMI_ATTR_EIR])
++              fmiconf.eir = nla_get_u32(fmi[TSN_QCI_FMI_ATTR_EIR]);
++
++      if (fmi[TSN_QCI_FMI_ATTR_EBS])
++              fmiconf.ebs = nla_get_u32(fmi[TSN_QCI_FMI_ATTR_EBS]);
++
++      if (fmi[TSN_QCI_FMI_ATTR_CF])
++              fmiconf.cf = 1;
++
++      if (fmi[TSN_QCI_FMI_ATTR_CM])
++              fmiconf.cm = 1;
++
++      if (fmi[TSN_QCI_FMI_ATTR_DROPYL])
++              fmiconf.drop_on_yellow = 1;
++
++      if (fmi[TSN_QCI_FMI_ATTR_MAREDEN])
++              fmiconf.mark_red_enable = 1;
++
++      if (fmi[TSN_QCI_FMI_ATTR_MARED])
++              fmiconf.mark_red = 1;
++
++loaddev:
++
++      if (!tsnops->qci_fmi_set) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -EINVAL;
++      }
++
++      ret = tsnops->qci_fmi_set(netdev, index, enable, &fmiconf);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
++              return ret;
++      }
++
++      ret = tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, 0);
++
++      if (ret)
++              return ret;
++      return 0;
++}
++
++static int tsn_qci_fmi_set(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME]) {
++              cmd_qci_fmi_set(info);
++              return 0;
++      }
++
++      return -1;
++}
++
++static int cmd_qci_fmi_get(struct genl_info *info)
++{
++      struct nlattr *na, *fmi[TSN_QCI_FMI_ATTR_MAX + 1], *fmiattr;
++      u32 index;
++      struct sk_buff *rep_skb;
++      int ret;
++      struct net_device *netdev;
++      struct tsn_qci_psfp_fmi fmiconf;
++      struct tsn_qci_psfp_fmi_counters counters;
++      const struct tsn_ops *tsnops;
++      struct genlmsghdr *genlhdr;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      if (!info->attrs[TSN_ATTR_QCI_FMI])
++              return -EINVAL;
++
++      na = info->attrs[TSN_ATTR_QCI_FMI];
++
++      ret = NLA_PARSE_NESTED(fmi, TSN_QCI_FMI_ATTR_MAX,
++                             na, qci_fmi_policy);
++      if (ret) {
++              pr_info("tsn: parse value TSN_QCI_FMI_ATTR_MAX  error.");
++              return -EINVAL;
++      }
++
++      if (!fmi[TSN_QCI_FMI_ATTR_INDEX])
++              return -EINVAL;
++
++      index = nla_get_u32(fmi[TSN_QCI_FMI_ATTR_INDEX]);
++
++      /* Get data from device */
++      memset(&fmiconf, 0, sizeof(struct tsn_qci_psfp_fmi));
++      memset(&counters, 0, sizeof(struct tsn_qci_psfp_fmi_counters));
++
++      if (!tsnops->qci_fmi_get) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -EINVAL;
++      }
++
++      ret = tsnops->qci_fmi_get(netdev, index, &fmiconf, &counters);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
++              return ret;
++      }
++
++      genlhdr = info->genlhdr;
++
++      /* Form netlink reply data */
++      ret = tsn_prepare_reply(info, genlhdr->cmd,
++                              &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
++      if (ret < 0)
++              return ret;
++
++      if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
++              return -EMSGSIZE;
++
++      fmiattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_QCI_FMI);
++      if (!fmiattr)
++              return -EMSGSIZE;
++
++      if (nla_put_u32(rep_skb, TSN_QCI_FMI_ATTR_INDEX, index) ||
++          nla_put_u32(rep_skb, TSN_QCI_FMI_ATTR_CIR, fmiconf.cir) ||
++          nla_put_u32(rep_skb, TSN_QCI_FMI_ATTR_CBS, fmiconf.cbs) ||
++          nla_put_u32(rep_skb, TSN_QCI_FMI_ATTR_EIR, fmiconf.eir) ||
++          nla_put_u32(rep_skb, TSN_QCI_FMI_ATTR_EBS, fmiconf.ebs))
++              return -EMSGSIZE;
++
++      if (fmiconf.cf)
++              if (nla_put_flag(rep_skb, TSN_QCI_FMI_ATTR_CF))
++                      return -EMSGSIZE;
++
++      if (fmiconf.cm)
++              if (nla_put_flag(rep_skb, TSN_QCI_FMI_ATTR_CM))
++                      return -EMSGSIZE;
++
++      if (fmiconf.drop_on_yellow)
++              if (nla_put_flag(rep_skb, TSN_QCI_FMI_ATTR_DROPYL))
++                      return -EMSGSIZE;
++
++      if (fmiconf.mark_red_enable)
++              if (nla_put_flag(rep_skb, TSN_QCI_FMI_ATTR_MAREDEN))
++                      return -EMSGSIZE;
++
++      if (fmiconf.mark_red)
++              if (nla_put_flag(rep_skb, TSN_QCI_FMI_ATTR_MAREDEN))
++                      return -EMSGSIZE;
++
++      if (nla_put(rep_skb, TSN_QCI_FMI_ATTR_COUNTERS,
++                  sizeof(struct tsn_qci_psfp_fmi_counters), &counters))
++              return -EMSGSIZE;
++
++      nla_nest_end(rep_skb, fmiattr);
++
++      tsn_send_reply(rep_skb, info);
++
++      return 0;
++}
++
++static int tsn_qci_fmi_get(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME]) {
++              cmd_qci_fmi_get(info);
++              return 0;
++      }
++
++      return -1;
++}
++
++static int cmd_qbv_set(struct genl_info *info)
++{
++      struct nlattr *na, *na1;
++      struct nlattr *qbv_table;
++      struct nlattr *qbv[TSN_QBV_ATTR_MAX + 1];
++      struct nlattr *qbvctrl[TSN_QBV_ATTR_CTRL_MAX + 1];
++      int rem;
++      int ret = 0;
++      struct net_device *netdev;
++      struct tsn_qbv_conf qbvconfig;
++      const struct tsn_ops *tsnops;
++      struct tsn_qbv_entry *gatelist = NULL;
++      int count = 0;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      memset(&qbvconfig, 0, sizeof(struct tsn_qbv_conf));
++
++      if (!info->attrs[TSN_ATTR_QBV])
++              return -EINVAL;
++
++      na = info->attrs[TSN_ATTR_QBV];
++
++      ret = NLA_PARSE_NESTED(qbv, TSN_QBV_ATTR_MAX, na, qbv_policy);
++      if (ret)
++              return -EINVAL;
++
++      if (qbv[TSN_QBV_ATTR_ENABLE])
++              qbvconfig.gate_enabled = 1;
++      else
++              goto setdrive;
++
++      if (qbv[TSN_QBV_ATTR_CONFIGCHANGE])
++              qbvconfig.config_change = 1;
++
++      if (!qbv[TSN_QBV_ATTR_ADMINENTRY]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -1;
++      }
++
++      na1 = qbv[TSN_QBV_ATTR_ADMINENTRY];
++      NLA_PARSE_NESTED(qbvctrl, TSN_QBV_ATTR_CTRL_MAX,
++                       na1, qbv_ctrl_policy);
++
++      if (qbvctrl[TSN_QBV_ATTR_CTRL_CYCLETIME]) {
++              qbvconfig.admin.cycle_time =
++                      nla_get_u32(qbvctrl[TSN_QBV_ATTR_CTRL_CYCLETIME]);
++      }
++
++      if (qbvctrl[TSN_QBV_ATTR_CTRL_CYCLETIMEEXT]) {
++              qbvconfig.admin.cycle_time_extension =
++                      nla_get_u32(qbvctrl[TSN_QBV_ATTR_CTRL_CYCLETIMEEXT]);
++      }
++
++      if (qbvctrl[TSN_QBV_ATTR_CTRL_BASETIME]) {
++              qbvconfig.admin.base_time =
++                      nla_get_u64(qbvctrl[TSN_QBV_ATTR_CTRL_BASETIME]);
++      }
++
++      if (qbvctrl[TSN_QBV_ATTR_CTRL_GATESTATE]) {
++              qbvconfig.admin.gate_states =
++                      nla_get_u8(qbvctrl[TSN_QBV_ATTR_CTRL_GATESTATE]);
++      }
++
++      if (qbvctrl[TSN_QBV_ATTR_CTRL_LISTCOUNT]) {
++              int listcount;
++
++              listcount = nla_get_u32(qbvctrl[TSN_QBV_ATTR_CTRL_LISTCOUNT]);
++
++              qbvconfig.admin.control_list_length = listcount;
++
++              gatelist = kmalloc_array(listcount,
++                                       sizeof(*gatelist),
++                                       GFP_KERNEL);
++
++              nla_for_each_nested(qbv_table, na1, rem) {
++                      struct nlattr *qbv_entry[TSN_QBV_ATTR_ENTRY_MAX + 1];
++
++                      if (nla_type(qbv_table) != TSN_QBV_ATTR_CTRL_LISTENTRY)
++                              continue;
++
++                      ret = NLA_PARSE_NESTED(qbv_entry,
++                                             TSN_QBV_ATTR_ENTRY_MAX,
++                                             qbv_table, qbv_entry_policy);
++                      if (ret)
++                              return -EINVAL;
++
++                      (gatelist + count)->gate_state =
++                              nla_get_u8(qbv_entry[TSN_QBV_ATTR_ENTRY_GC]);
++                      (gatelist + count)->time_interval =
++                              nla_get_u32(qbv_entry[TSN_QBV_ATTR_ENTRY_TM]);
++                      count++;
++                      if (count > listcount)
++                              break;
++              }
++      }
++
++      if (gatelist)
++              qbvconfig.admin.control_list = gatelist;
++
++setdrive:
++      if (!tsnops->qbv_set) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              goto err;
++      }
++
++      ret = tsnops->qbv_set(netdev, &qbvconfig);
++
++      /* send back */
++      if (ret < 0)
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++      else
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, 0);
++
++err:
++      kfree(gatelist);
++      return ret;
++}
++
++static int tsn_qbv_set(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME]) {
++              cmd_qbv_set(info);
++              return 0;
++      }
++
++      return -1;
++}
++
++static int cmd_qbv_get(struct genl_info *info)
++{
++      struct nlattr *qbv, *qbvadminattr;
++      struct sk_buff *rep_skb;
++      int ret;
++      int len = 0, i = 0;
++      struct net_device *netdev;
++      struct genlmsghdr *genlhdr;
++      struct tsn_qbv_conf qbvconf;
++      const struct tsn_ops *tsnops;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      genlhdr = info->genlhdr;
++
++      memset(&qbvconf, 0, sizeof(struct tsn_qbv_conf));
++
++      if (!tsnops->qbv_get) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -1;
++      }
++
++      ret = tsnops->qbv_get(netdev, &qbvconf);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++              return ret;
++      }
++
++      ret = tsn_prepare_reply(info, genlhdr->cmd,
++                              &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
++      if (ret < 0)
++              return ret;
++
++      if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
++              return -EMSGSIZE;
++
++      qbv = nla_nest_start_noflag(rep_skb, TSN_ATTR_QBV);
++      if (!qbv)
++              return -EMSGSIZE;
++
++      qbvadminattr = nla_nest_start_noflag(rep_skb, TSN_QBV_ATTR_ADMINENTRY);
++      if (!qbvadminattr)
++              return -EMSGSIZE;
++
++      if (qbvconf.admin.control_list) {
++              len = qbvconf.admin.control_list_length;
++              if (nla_put_u32(rep_skb, TSN_QBV_ATTR_CTRL_LISTCOUNT, len))
++                      return -EMSGSIZE;
++
++              for (i = 0; i < len; i++) {
++                      struct nlattr *qbv_table;
++                      u8 gs;
++                      u32 tp;
++                      int glisttype = TSN_QBV_ATTR_CTRL_LISTENTRY;
++
++                      gs = (qbvconf.admin.control_list + i)->gate_state;
++                      tp = (qbvconf.admin.control_list + i)->time_interval;
++
++                      qbv_table =
++                              nla_nest_start_noflag(rep_skb, glisttype);
++                      if (!qbv_table)
++                              return -EMSGSIZE;
++
++                      if (nla_put_u32(rep_skb, TSN_QBV_ATTR_ENTRY_ID, i) ||
++                          nla_put_u8(rep_skb, TSN_QBV_ATTR_ENTRY_GC, gs) ||
++                          nla_put_u32(rep_skb, TSN_QBV_ATTR_ENTRY_TM, tp))
++                              return -EMSGSIZE;
++                      nla_nest_end(rep_skb, qbv_table);
++              }
++
++              if (qbvconf.admin.gate_states)
++                      if (nla_put_u8(rep_skb, TSN_QBV_ATTR_CTRL_GATESTATE,
++                                     qbvconf.admin.gate_states))
++                              return -EMSGSIZE;
++
++              if (qbvconf.admin.cycle_time)
++                      if (nla_put_u32(rep_skb, TSN_QBV_ATTR_CTRL_CYCLETIME,
++                                      qbvconf.admin.cycle_time))
++                              return -EMSGSIZE;
++
++              if (qbvconf.admin.cycle_time_extension)
++                      if (nla_put_u32(rep_skb, TSN_QBV_ATTR_CTRL_CYCLETIMEEXT,
++                                      qbvconf.admin.cycle_time_extension))
++                              return -EMSGSIZE;
++
++              if (qbvconf.admin.base_time)
++                      if (NLA_PUT_U64(rep_skb, TSN_QBV_ATTR_CTRL_BASETIME,
++                                      qbvconf.admin.base_time))
++                              return -EMSGSIZE;
++
++              kfree(qbvconf.admin.control_list);
++
++      } else {
++              pr_info("tsn: error get administrator data.");
++      }
++
++      nla_nest_end(rep_skb, qbvadminattr);
++
++      if (qbvconf.gate_enabled) {
++              if (nla_put_flag(rep_skb, TSN_QBV_ATTR_ENABLE))
++                      return -EMSGSIZE;
++      } else {
++              if (nla_put_flag(rep_skb, TSN_QBV_ATTR_DISABLE))
++                      return -EMSGSIZE;
++      }
++
++      if (qbvconf.maxsdu)
++              if (nla_put_u32(rep_skb, TSN_QBV_ATTR_MAXSDU, qbvconf.maxsdu))
++                      return -EMSGSIZE;
++
++      if (qbvconf.config_change)
++              if (nla_put_flag(rep_skb, TSN_QBV_ATTR_CONFIGCHANGE))
++                      return -EMSGSIZE;
++
++      nla_nest_end(rep_skb, qbv);
++
++      tsn_send_reply(rep_skb, info);
++
++      return ret;
++}
++
++static int cmd_qbv_status_get(struct genl_info *info)
++{
++      struct nlattr *qbv, *qbvoperattr;
++      struct sk_buff *rep_skb;
++      int ret;
++      int len = 0, i = 0;
++      struct net_device *netdev;
++      struct genlmsghdr *genlhdr;
++      struct tsn_qbv_status qbvstatus;
++      const struct tsn_ops *tsnops;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      genlhdr = info->genlhdr;
++
++      memset(&qbvstatus, 0, sizeof(struct tsn_qbv_status));
++
++      if (!tsnops->qbv_get_status) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -1;
++      }
++
++      ret = tsnops->qbv_get_status(netdev, &qbvstatus);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++              return ret;
++      }
++
++      ret = tsn_prepare_reply(info, genlhdr->cmd,
++                              &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
++      if (ret < 0)
++              return ret;
++
++      if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
++              return -EMSGSIZE;
++
++      qbv = nla_nest_start_noflag(rep_skb, TSN_ATTR_QBV);
++      if (!qbv)
++              return -EMSGSIZE;
++
++      qbvoperattr = nla_nest_start_noflag(rep_skb, TSN_QBV_ATTR_OPERENTRY);
++      if (!qbvoperattr)
++              return -EMSGSIZE;
++
++      if (qbvstatus.oper.control_list) {
++              len = qbvstatus.oper.control_list_length;
++              if (nla_put_u32(rep_skb, TSN_QBV_ATTR_CTRL_LISTCOUNT, len)) {
++                      nla_nest_cancel(rep_skb, qbvoperattr);
++                      return -EMSGSIZE;
++              }
++
++              for (i = 0; i < len; i++) {
++                      struct nlattr *qbv_table;
++                      u8 gs;
++                      u32 tp;
++                      int glisttype = TSN_QBV_ATTR_CTRL_LISTENTRY;
++
++                      gs = (qbvstatus.oper.control_list + i)->gate_state;
++                      tp = (qbvstatus.oper.control_list + i)->time_interval;
++
++                      qbv_table = nla_nest_start_noflag(rep_skb, glisttype);
++                      if (!qbv_table)
++                              return -EMSGSIZE;
++
++                      if (nla_put_u32(rep_skb, TSN_QBV_ATTR_ENTRY_ID, i) ||
++                          nla_put_u8(rep_skb, TSN_QBV_ATTR_ENTRY_GC, gs) ||
++                          nla_put_u32(rep_skb, TSN_QBV_ATTR_ENTRY_TM, tp)) {
++                              nla_nest_cancel(rep_skb, qbv_table);
++                              return -EMSGSIZE;
++                      }
++
++                      nla_nest_end(rep_skb, qbv_table);
++              }
++
++              if (qbvstatus.oper.gate_states) {
++                      if (nla_put_u8(rep_skb, TSN_QBV_ATTR_CTRL_GATESTATE,
++                                     qbvstatus.oper.gate_states))
++                              return -EMSGSIZE;
++              }
++
++              if (qbvstatus.oper.cycle_time) {
++                      if (nla_put_u32(rep_skb, TSN_QBV_ATTR_CTRL_CYCLETIME,
++                                      qbvstatus.oper.cycle_time))
++                              return -EMSGSIZE;
++              }
++
++              if (qbvstatus.oper.cycle_time_extension) {
++                      if (nla_put_u32(rep_skb, TSN_QBV_ATTR_CTRL_CYCLETIMEEXT,
++                                      qbvstatus.oper.cycle_time_extension))
++                              return -EMSGSIZE;
++              }
++
++              if (qbvstatus.oper.base_time) {
++                      if (NLA_PUT_U64(rep_skb, TSN_QBV_ATTR_CTRL_BASETIME,
++                                      qbvstatus.oper.base_time))
++                              return -EMSGSIZE;
++              }
++
++              kfree(qbvstatus.oper.control_list);
++      } else {
++              pr_info("tsn: error get operation list data.");
++      }
++
++      nla_nest_end(rep_skb, qbvoperattr);
++
++      if (qbvstatus.config_change_time) {
++              if (NLA_PUT_U64(rep_skb, TSN_QBV_ATTR_CONFIGCHANGETIME,
++                              qbvstatus.config_change_time))
++                      return -EMSGSIZE;
++      }
++
++      if (qbvstatus.tick_granularity) {
++              if (nla_put_u32(rep_skb, TSN_QBV_ATTR_GRANULARITY,
++                              qbvstatus.tick_granularity))
++                      return -EMSGSIZE;
++      }
++
++      if (qbvstatus.current_time) {
++              if (NLA_PUT_U64(rep_skb, TSN_QBV_ATTR_CURRENTTIME,
++                              qbvstatus.current_time))
++                      return -EMSGSIZE;
++      }
++
++      if (qbvstatus.config_pending) {
++              if (nla_put_flag(rep_skb, TSN_QBV_ATTR_CONFIGPENDING))
++                      return -EMSGSIZE;
++      }
++
++      if (qbvstatus.config_change_error) {
++              if (NLA_PUT_U64(rep_skb, TSN_QBV_ATTR_CONFIGCHANGEERROR,
++                              qbvstatus.config_change_error))
++                      return -EMSGSIZE;
++      }
++
++      if (qbvstatus.supported_list_max) {
++              if (nla_put_u32(rep_skb, TSN_QBV_ATTR_LISTMAX,
++                              qbvstatus.supported_list_max))
++                      return -EMSGSIZE;
++      }
++
++      nla_nest_end(rep_skb, qbv);
++
++      tsn_send_reply(rep_skb, info);
++
++      return ret;
++}
++
++static int tsn_qbv_status_get(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME])
++              cmd_qbv_status_get(info);
++
++      return 0;
++}
++
++static int tsn_qbv_get(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME])
++              cmd_qbv_get(info);
++
++      return 0;
++}
++
++static int tsn_cbs_set(struct sk_buff *skb, struct genl_info *info)
++{
++      struct nlattr *na;
++      struct nlattr *cbsa[TSN_CBS_ATTR_MAX + 1];
++      struct net_device *netdev;
++      const struct tsn_ops *tsnops;
++      int ret;
++      u8 tc, bw;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      if (!info->attrs[TSN_ATTR_CBS]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      na = info->attrs[TSN_ATTR_CBS];
++
++      if (!tsnops->cbs_set) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -1;
++      }
++
++      ret = NLA_PARSE_NESTED(cbsa, TSN_CBS_ATTR_MAX, na, cbs_policy);
++      if (ret) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      if (!cbsa[TSN_CBS_ATTR_TC_INDEX]) {
++              pr_err("tsn: no TSN_CBS_ATTR_TC_INDEX input\n");
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++      tc = nla_get_u8(cbsa[TSN_CBS_ATTR_TC_INDEX]);
++
++      if (!cbsa[TSN_CBS_ATTR_BW]) {
++              pr_err("tsn: no TSN_CBS_ATTR_BW input\n");
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      bw = nla_get_u8(cbsa[TSN_CBS_ATTR_BW]);
++      if (bw > 100) {
++              pr_err("tsn: TSN_CBS_ATTR_BW isn't in the range of 0~100\n");
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      ret = tsnops->cbs_set(netdev, tc, bw);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++              return ret;
++      }
++
++      tsn_simple_reply(info, TSN_CMD_REPLY,
++                       netdev->name, 0);
++      return 0;
++}
++
++static int tsn_cbs_get(struct sk_buff *skb, struct genl_info *info)
++{
++      struct nlattr *na, *cbsattr;
++      struct nlattr *cbsa[TSN_CBS_ATTR_MAX + 1];
++      struct net_device *netdev;
++      const struct tsn_ops *tsnops;
++      struct sk_buff *rep_skb;
++      int ret;
++      struct genlmsghdr *genlhdr;
++      u8 tc;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      if (!info->attrs[TSN_ATTR_CBS]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      if (!tsnops->cbs_get) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -1;
++      }
++
++      na = info->attrs[TSN_ATTR_CBS];
++      ret = NLA_PARSE_NESTED(cbsa, TSN_CBS_ATTR_MAX, na, cbs_policy);
++      if (ret) {
++              pr_err("tsn: parse value TSN_CBS_ATTR_MAX error.");
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      /* Get status data from device */
++      genlhdr = info->genlhdr;
++
++      /* Form netlink reply data */
++      ret = tsn_prepare_reply(info, genlhdr->cmd, &rep_skb,
++                              NLMSG_ALIGN(MAX_ATTR_SIZE));
++      if (ret < 0)
++              return ret;
++
++      if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
++              return -EMSGSIZE;
++
++      cbsattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_CBS);
++      if (!cbsattr)
++              return -EMSGSIZE;
++
++      if (!cbsa[TSN_CBS_ATTR_TC_INDEX]) {
++              pr_err("tsn: must to specify the TSN_CBS_ATTR_TC_INDEX\n");
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++      tc = nla_get_u8(cbsa[TSN_CBS_ATTR_TC_INDEX]);
++
++      ret = tsnops->cbs_get(netdev, tc);
++      if (ret < 0) {
++              pr_err("tsn: cbs_get return error\n");
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++              return ret;
++      }
++
++      if (nla_put_u8(rep_skb, TSN_CBS_ATTR_BW, ret & 0XF))
++              return -EMSGSIZE;
++
++      nla_nest_end(rep_skb, cbsattr);
++      return tsn_send_reply(rep_skb, info);
++}
++
++static int cmd_qbu_set(struct genl_info *info)
++{
++      struct nlattr *na;
++      struct nlattr *qbua[TSN_QBU_ATTR_MAX + 1];
++      struct net_device *netdev;
++      const struct tsn_ops *tsnops;
++      int ret;
++      u8 preemptible = 0;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      if (!info->attrs[TSN_ATTR_QBU]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      na = info->attrs[TSN_ATTR_QBU];
++
++      ret = NLA_PARSE_NESTED(qbua, TSN_QBU_ATTR_MAX, na, qbu_policy);
++      if (ret) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      if (qbua[TSN_QBU_ATTR_ADMIN_STATE])
++              preemptible = nla_get_u8(qbua[TSN_QBU_ATTR_ADMIN_STATE]);
++      else
++              pr_info("No preemptible TSN_QBU_ATTR_ADMIN_STATE config!\n");
++
++      if (!tsnops->qbu_set) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -EINVAL;
++      }
++
++      ret = tsnops->qbu_set(netdev, preemptible);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++              return ret;
++      }
++
++      tsn_simple_reply(info, TSN_CMD_REPLY,
++                       netdev->name, 0);
++      return 0;
++}
++
++static int tsn_qbu_set(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME])
++              return cmd_qbu_set(info);
++
++      return -1;
++}
++
++static int cmd_qbu_get_status(struct genl_info *info)
++{
++      struct nlattr *qbuattr;
++      struct net_device *netdev;
++      const struct tsn_ops *tsnops;
++      struct sk_buff *rep_skb;
++      int ret;
++      struct genlmsghdr *genlhdr;
++      struct tsn_preempt_status pps;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      /* Get status data from device */
++      genlhdr = info->genlhdr;
++
++      memset(&pps, 0, sizeof(struct tsn_preempt_status));
++
++      if (!tsnops->qbu_get) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -1;
++      }
++
++      ret = tsnops->qbu_get(netdev, &pps);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++              return ret;
++      }
++
++      /* Form netlink reply data */
++      ret = tsn_prepare_reply(info, genlhdr->cmd,
++                              &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
++      if (ret < 0)
++              return ret;
++
++      if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
++              return -EMSGSIZE;
++
++      qbuattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_QBU);
++      if (!qbuattr)
++              return -EMSGSIZE;
++
++      if (nla_put_u8(rep_skb, TSN_QBU_ATTR_ADMIN_STATE, pps.admin_state) ||
++          nla_put_u32(rep_skb,
++                      TSN_QBU_ATTR_HOLD_ADVANCE, pps.hold_advance) ||
++          nla_put_u32(rep_skb,
++                      TSN_QBU_ATTR_RELEASE_ADVANCE, pps.release_advance))
++              return -EMSGSIZE;
++
++      if (pps.preemption_active) {
++              if (nla_put_flag(rep_skb, TSN_QBU_ATTR_ACTIVE))
++                      return -EMSGSIZE;
++      }
++
++      if (nla_put_u8(rep_skb, TSN_QBU_ATTR_HOLD_REQUEST, pps.hold_request))
++              return -EMSGSIZE;
++
++      nla_nest_end(rep_skb, qbuattr);
++
++      return tsn_send_reply(rep_skb, info);
++}
++
++static int tsn_qbu_get_status(struct sk_buff *skb, struct genl_info *info)
++{
++      if (info->attrs[TSN_ATTR_IFNAME])
++              return cmd_qbu_get_status(info);
++
++      return -1;
++}
++
++static int tsn_tsd_set(struct sk_buff *skb, struct genl_info *info)
++{
++      struct nlattr *na;
++      struct nlattr *ntsd[TSN_TSD_ATTR_MAX + 1];
++      struct net_device *netdev;
++      const struct tsn_ops *tsnops;
++      struct tsn_tsd tsd;
++      int ret;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      memset(&tsd, 0, sizeof(struct tsn_tsd));
++
++      if (!info->attrs[TSN_ATTR_TSD]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      na = info->attrs[TSN_ATTR_TSD];
++
++      ret = NLA_PARSE_NESTED(ntsd, TSN_TSD_ATTR_MAX, na, tsd_policy);
++      if (ret) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      if (!tsnops->tsd_set) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -EINVAL;
++      }
++
++      if (nla_get_flag(ntsd[TSN_TSD_ATTR_DISABLE])) {
++              tsd.enable = false;
++      } else {
++              if (ntsd[TSN_TSD_ATTR_PERIOD])
++                      tsd.period = nla_get_u32(ntsd[TSN_TSD_ATTR_PERIOD]);
++
++              if (!tsd.period) {
++                      tsn_simple_reply(info, TSN_CMD_REPLY,
++                                       netdev->name, -EINVAL);
++                      return -EINVAL;
++              }
++
++              if (ntsd[TSN_TSD_ATTR_MAX_FRM_NUM])
++                      tsd.maxFrameNum =
++                              nla_get_u32(ntsd[TSN_TSD_ATTR_MAX_FRM_NUM]);
++
++              if (ntsd[TSN_TSD_ATTR_SYN_IMME])
++                      tsd.syn_flag = 2;
++              else
++                      tsd.syn_flag = 1;
++
++              tsd.enable = true;
++      }
++
++      ret = tsnops->tsd_set(netdev, &tsd);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++              return ret;
++      }
++
++      tsn_simple_reply(info, TSN_CMD_REPLY,
++                       netdev->name, 0);
++      return 0;
++}
++
++static int tsn_tsd_get(struct sk_buff *skb, struct genl_info *info)
++{
++      struct nlattr *na, *tsdattr;
++      struct nlattr *tsda[TSN_TSD_ATTR_MAX + 1];
++      struct net_device *netdev;
++      const struct tsn_ops *tsnops;
++      struct sk_buff *rep_skb;
++      int ret;
++      struct genlmsghdr *genlhdr;
++      struct tsn_tsd_status tts;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      if (!info->attrs[TSN_ATTR_TSD]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      if (!tsnops->tsd_get) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -1;
++      }
++
++      ret = tsnops->tsd_get(netdev, &tts);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++              return ret;
++      }
++
++      na = info->attrs[TSN_ATTR_TSD];
++
++      ret = NLA_PARSE_NESTED(tsda, TSN_TSD_ATTR_MAX,
++                             na, tsd_policy);
++      if (ret) {
++              pr_err("tsn: parse value TSN_TSD_ATTR_MAX error.");
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      /* Get status data from device */
++      genlhdr = info->genlhdr;
++
++      /* Form netlink reply data */
++      ret = tsn_prepare_reply(info, genlhdr->cmd, &rep_skb,
++                              NLMSG_ALIGN(MAX_ATTR_SIZE));
++      if (ret < 0)
++              return ret;
++
++      if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
++              return -EMSGSIZE;
++
++      tsdattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_TSD);
++      if (!tsdattr)
++              return -EMSGSIZE;
++
++      if (nla_put_u32(rep_skb, TSN_TSD_ATTR_PERIOD, tts.period) ||
++          nla_put_u32(rep_skb, TSN_TSD_ATTR_MAX_FRM_NUM, tts.maxFrameNum) ||
++          nla_put_u32(rep_skb, TSN_TSD_ATTR_CYCLE_NUM, tts.cycleNum) ||
++          nla_put_u32(rep_skb, TSN_TSD_ATTR_LOSS_STEPS, tts.loss_steps) ||
++          nla_put_u32(rep_skb, TSN_TSD_ATTR_MAX_FRM_NUM, tts.maxFrameNum))
++              return -EMSGSIZE;
++
++      if (!tts.enable) {
++              if (nla_put_flag(rep_skb, TSN_TSD_ATTR_DISABLE))
++                      return -EMSGSIZE;
++      } else {
++              if (nla_put_flag(rep_skb, TSN_TSD_ATTR_ENABLE))
++                      return -EMSGSIZE;
++      }
++
++      if (tts.flag == 2)
++              if (nla_put_flag(rep_skb, TSN_TSD_ATTR_SYN_IMME))
++                      return -EMSGSIZE;
++
++      nla_nest_end(rep_skb, tsdattr);
++      return tsn_send_reply(rep_skb, info);
++}
++
++static int tsn_ct_set(struct sk_buff *skb, struct genl_info *info)
++{
++      struct nlattr *na;
++      struct nlattr *cta[TSN_CT_ATTR_MAX + 1];
++      struct net_device *netdev;
++      const struct tsn_ops *tsnops;
++      int ret;
++      u8 queue_stat;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      if (!info->attrs[TSN_ATTR_CT]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      na = info->attrs[TSN_ATTR_CT];
++
++      if (!tsnops->ct_set) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -1;
++      }
++
++      ret = NLA_PARSE_NESTED(cta, TSN_CT_ATTR_MAX,
++                             na, ct_policy);
++      if (ret) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      queue_stat = nla_get_u8(cta[TSN_CT_ATTR_QUEUE_STATE]);
++
++      ret = tsnops->ct_set(netdev, queue_stat);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++              return ret;
++      }
++
++      tsn_simple_reply(info, TSN_CMD_REPLY,
++                       netdev->name, 0);
++      return 0;
++}
++
++static int tsn_cbgen_set(struct sk_buff *skb, struct genl_info *info)
++{
++      struct nlattr *na;
++      struct nlattr *cbgena[TSN_CBGEN_ATTR_MAX + 1];
++      struct net_device *netdev;
++      const struct tsn_ops *tsnops;
++      int ret;
++      u32 index;
++      struct tsn_seq_gen_conf sg_conf;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      if (!info->attrs[TSN_ATTR_CBGEN]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      na = info->attrs[TSN_ATTR_CBGEN];
++
++      if (!tsnops->cbgen_set) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -1;
++      }
++
++      ret = NLA_PARSE_NESTED(cbgena, TSN_CBGEN_ATTR_MAX,
++                             na, cbgen_policy);
++      if (ret) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      index = nla_get_u32(cbgena[TSN_CBGEN_ATTR_INDEX]);
++
++      memset(&sg_conf, 0, sizeof(struct tsn_seq_gen_conf));
++      sg_conf.iport_mask = nla_get_u8(cbgena[TSN_CBGEN_ATTR_PORT_MASK]);
++      sg_conf.split_mask = nla_get_u8(cbgena[TSN_CBGEN_ATTR_SPLIT_MASK]);
++      sg_conf.seq_len = nla_get_u8(cbgena[TSN_CBGEN_ATTR_SEQ_LEN]);
++      sg_conf.seq_num = nla_get_u32(cbgena[TSN_CBGEN_ATTR_SEQ_NUM]);
++
++      ret = tsnops->cbgen_set(netdev, index, &sg_conf);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++              return ret;
++      }
++
++      tsn_simple_reply(info, TSN_CMD_REPLY,
++                       netdev->name, 0);
++      return 0;
++}
++
++static int tsn_cbrec_set(struct sk_buff *skb, struct genl_info *info)
++{
++      struct nlattr *na;
++      struct nlattr *cbreca[TSN_CBREC_ATTR_MAX + 1];
++      struct net_device *netdev;
++      const struct tsn_ops *tsnops;
++      int ret;
++      u32 index;
++      struct tsn_seq_rec_conf sr_conf;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      if (!info->attrs[TSN_ATTR_CBREC]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      na = info->attrs[TSN_ATTR_CBREC];
++
++      if (!tsnops->cbrec_set) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -1;
++      }
++
++      ret = NLA_PARSE_NESTED(cbreca, TSN_CBREC_ATTR_MAX,
++                             na, cbrec_policy);
++      if (ret) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      index = nla_get_u32(cbreca[TSN_CBREC_ATTR_INDEX]);
++
++      memset(&sr_conf, 0, sizeof(struct tsn_seq_rec_conf));
++      sr_conf.seq_len = nla_get_u8(cbreca[TSN_CBREC_ATTR_SEQ_LEN]);
++      sr_conf.his_len = nla_get_u8(cbreca[TSN_CBREC_ATTR_HIS_LEN]);
++      sr_conf.rtag_pop_en = nla_get_flag(cbreca[TSN_CBREC_ATTR_TAG_POP_EN]);
++
++      ret = tsnops->cbrec_set(netdev, index, &sr_conf);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++              return ret;
++      }
++
++      tsn_simple_reply(info, TSN_CMD_REPLY,
++                       netdev->name, 0);
++      return 0;
++}
++
++static int tsn_cbstatus_get(struct sk_buff *skb, struct genl_info *info)
++{
++      struct nlattr *na;
++      struct nlattr *cba[TSN_CBSTAT_ATTR_MAX + 1];
++      struct nlattr *cbattr;
++      struct net_device *netdev;
++      const struct tsn_ops *tsnops;
++      struct sk_buff *rep_skb;
++      int ret;
++      unsigned int index;
++      struct genlmsghdr *genlhdr;
++      struct tsn_cb_status cbstat;
++      struct tsn_port *port;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      /* Get status data from device */
++      genlhdr = info->genlhdr;
++
++      memset(&cbstat, 0, sizeof(struct tsn_cb_status));
++
++      if (!tsnops->cb_get) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -1;
++      }
++
++      na = info->attrs[TSN_ATTR_CBSTAT];
++      ret = NLA_PARSE_NESTED(cba, TSN_CBSTAT_ATTR_MAX,
++                             na, cbstat_policy);
++      if (ret) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      index = nla_get_u32(cba[TSN_CBSTAT_ATTR_INDEX]);
++
++      ret = tsnops->cb_get(netdev, index, &cbstat);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++              return ret;
++      }
++
++      /* Form netlink reply data */
++      ret = tsn_prepare_reply(info, genlhdr->cmd,
++                              &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
++      if (ret < 0)
++              return ret;
++
++      if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
++              return -EMSGSIZE;
++
++      cbattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_CBSTAT);
++      if (!cbattr)
++              return -EMSGSIZE;
++
++      if (nla_put_u8(rep_skb, TSN_CBSTAT_ATTR_GEN_REC, cbstat.gen_rec) ||
++          nla_put_u8(rep_skb, TSN_CBSTAT_ATTR_ERR, cbstat.err) ||
++          nla_put_u32(rep_skb, TSN_CBSTAT_ATTR_SEQ_NUM,
++                      cbstat.seq_num) ||
++          nla_put_u8(rep_skb, TSN_CBSTAT_ATTR_SEQ_LEN, cbstat.seq_len) ||
++          nla_put_u8(rep_skb, TSN_CBSTAT_ATTR_SPLIT_MASK,
++                     cbstat.split_mask) ||
++          nla_put_u8(rep_skb, TSN_CBSTAT_ATTR_PORT_MASK,
++                     cbstat.iport_mask) ||
++          nla_put_u8(rep_skb, TSN_CBSTAT_ATTR_HIS_LEN, cbstat.his_len) ||
++          nla_put_u32(rep_skb, TSN_CBSTAT_ATTR_SEQ_HIS,
++                      cbstat.seq_his))
++              return -EMSGSIZE;
++
++      nla_nest_end(rep_skb, cbattr);
++
++      return tsn_send_reply(rep_skb, info);
++}
++
++static int tsn_dscp_set(struct sk_buff *skb, struct genl_info *info)
++{
++      struct nlattr *na;
++      struct nlattr *dscpa[TSN_DSCP_ATTR_MAX + 1];
++      struct net_device *netdev;
++      const struct tsn_ops *tsnops;
++      int ret;
++      bool enable = 0;
++      struct tsn_port *port;
++      int dscp_ix;
++      struct tsn_qos_switch_dscp_conf dscp_conf;
++
++      port = tsn_init_check(info, &netdev);
++      if (!port)
++              return -ENODEV;
++
++      tsnops = port->tsnops;
++
++      if (!info->attrs[TSN_ATTR_DSCP]) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      na = info->attrs[TSN_ATTR_DSCP];
++
++      if (!tsnops->dscp_set) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EPERM);
++              return -1;
++      }
++
++      ret = NLA_PARSE_NESTED(dscpa, TSN_DSCP_ATTR_MAX,
++                             na, dscp_policy);
++      if (ret) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, -EINVAL);
++              return -EINVAL;
++      }
++
++      enable = 1;
++      if (dscpa[TSN_DSCP_ATTR_DISABLE])
++              enable = 0;
++      dscp_ix = nla_get_u32(dscpa[TSN_DSCP_ATTR_INDEX]);
++      dscp_conf.cos = nla_get_u32(dscpa[TSN_DSCP_ATTR_COS]);
++      dscp_conf.dpl = nla_get_u32(dscpa[TSN_DSCP_ATTR_DPL]);
++      ret = tsnops->dscp_set(netdev, enable, dscp_ix, &dscp_conf);
++      if (ret < 0) {
++              tsn_simple_reply(info, TSN_CMD_REPLY,
++                               netdev->name, ret);
++              return ret;
++      }
++
++      tsn_simple_reply(info, TSN_CMD_REPLY,
++                       netdev->name, 0);
++
++      return 0;
++}
++
++static const struct genl_ops tsnnl_ops[] = {
++      {
++              .cmd            = TSN_CMD_ECHO,
++              .doit           = tsn_echo_cmd,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_CAP_GET,
++              .doit           = tsn_cap_get,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_QBV_SET,
++              .doit           = tsn_qbv_set,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_QBV_GET,
++              .doit           = tsn_qbv_get,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_QBV_GET_STATUS,
++              .doit           = tsn_qbv_status_get,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_CB_STREAMID_SET,
++              .doit           = tsn_cb_streamid_set,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_CB_STREAMID_GET,
++              .doit           = tsn_cb_streamid_get,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_CB_STREAMID_GET_COUNTS,
++              .doit           = tsn_cb_streamid_counters_get,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_QCI_CAP_GET,
++              .doit           = tsn_qci_cap_get,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_QCI_SFI_SET,
++              .doit           = tsn_qci_sfi_set,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_QCI_SFI_GET,
++              .doit           = tsn_qci_sfi_get,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_QCI_SFI_GET_COUNTS,
++              .doit           = tsn_qci_sfi_counters_get,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_QCI_SGI_SET,
++              .doit           = tsn_qci_sgi_set,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_QCI_SGI_GET,
++              .doit           = tsn_qci_sgi_get,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_QCI_SGI_GET_STATUS,
++              .doit           = tsn_qci_sgi_status_get,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_QCI_FMI_SET,
++              .doit           = tsn_qci_fmi_set,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_QCI_FMI_GET,
++              .doit           = tsn_qci_fmi_get,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_CBS_SET,
++              .doit           = tsn_cbs_set,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_CBS_GET,
++              .doit           = tsn_cbs_get,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_QBU_SET,
++              .doit           = tsn_qbu_set,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_QBU_GET_STATUS,
++              .doit           = tsn_qbu_get_status,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_TSD_SET,
++              .doit           = tsn_tsd_set,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_TSD_GET,
++              .doit           = tsn_tsd_get,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_CT_SET,
++              .doit           = tsn_ct_set,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_CBGEN_SET,
++              .doit           = tsn_cbgen_set,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_CBREC_SET,
++              .doit           = tsn_cbrec_set,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_CBSTAT_GET,
++              .doit           = tsn_cbstatus_get,
++              .flags          = GENL_ADMIN_PERM,
++      },
++      {
++              .cmd            = TSN_CMD_DSCP_SET,
++              .doit           = tsn_dscp_set,
++              .flags          = GENL_ADMIN_PERM,
++      },
++};
++
++static const struct genl_multicast_group tsn_mcgrps[] = {
++      [TSN_MCGRP_QBV] = { .name = TSN_MULTICAST_GROUP_QBV},
++      [TSN_MCGRP_QCI] = { .name = TSN_MULTICAST_GROUP_QCI},
++};
++
++static struct genl_family tsn_family = {
++      .name           = TSN_GENL_NAME,
++      .version        = TSN_GENL_VERSION,
++      .maxattr        = TSN_CMD_ATTR_MAX,
++      .module         = THIS_MODULE,
++      .netnsok        = true,
++      .ops            = tsnnl_ops,
++      .n_ops          = ARRAY_SIZE(tsnnl_ops),
++      .mcgrps         = tsn_mcgrps,
++      .n_mcgrps       = ARRAY_SIZE(tsn_mcgrps),
++};
++
++int tsn_port_register(struct net_device *netdev,
++                    struct tsn_ops *tsnops, u16 groupid)
++{
++      struct tsn_port *port;
++
++      if (list_empty(&port_list)) {
++              INIT_LIST_HEAD(&port_list);
++      } else {
++              list_for_each_entry(port, &port_list, list) {
++                      if (port->netdev == netdev) {
++                              pr_info("TSN device already registered!\n");
++                              return -1;
++                      }
++              }
++      }
++
++      port = kzalloc(sizeof(*port), GFP_KERNEL);
++      if (!port)
++              return -1;
++
++      port->netdev = netdev;
++      port->groupid = groupid;
++      port->tsnops = tsnops;
++      port->nd.dev = netdev;
++
++      if (groupid < GROUP_OFFSET_SWITCH)
++              port->type = TSN_ENDPOINT;
++      else
++              port->type = TSN_SWITCH;
++
++      list_add_tail(&port->list, &port_list);
++
++      if (tsnops && tsnops->device_init)
++              port->tsnops->device_init(netdev);
++
++      return 0;
++}
++EXPORT_SYMBOL(tsn_port_register);
++
++void tsn_port_unregister(struct net_device *netdev)
++{
++      struct tsn_port *p;
++
++      list_for_each_entry(p, &port_list, list) {
++              if (!p || !p->netdev)
++                      continue;
++              if (p->netdev == netdev) {
++                      if (p->tsnops->device_deinit)
++                              p->tsnops->device_deinit(netdev);
++                      list_del(&p->list);
++                      kfree(p);
++                      break;
++              }
++      }
++}
++EXPORT_SYMBOL(tsn_port_unregister);
++
++static int tsn_multicast_to_user(unsigned long event,
++                               struct tsn_notifier_info *tsn_info)
++{
++      struct sk_buff *skb;
++      struct genlmsghdr *nlh;
++      int res;
++      struct tsn_qbv_conf *qbvdata;
++
++      /* If new attributes are added, please revisit this allocation */
++      skb = genlmsg_new(sizeof(*tsn_info), GFP_KERNEL);
++      if (!skb) {
++              pr_err("Allocation failure.\n");
++              return -ENOMEM;
++      }
++
++      switch (event) {
++      case TSN_QBV_CONFIGCHANGETIME_ARRIVE:
++              nlh = genlmsg_put(skb, 0, 1, &tsn_family,
++                                GFP_KERNEL, TSN_CMD_QBV_SET);
++              qbvdata = &tsn_info->ntdata.qbv_notify;
++              res = NLA_PUT_U64(skb, TSN_QBV_ATTR_CTRL_BASETIME,
++                                qbvdata->admin.base_time);
++
++              if (res) {
++                      pr_err("put data failure!\n");
++                      goto done;
++              }
++
++              res = nla_put_u32(skb, TSN_QBV_ATTR_CTRL_CYCLETIME,
++                                qbvdata->admin.cycle_time);
++              if (res) {
++                      pr_err("put data failure!\n");
++                      goto done;
++              }
++
++              if (qbvdata->gate_enabled)
++                      res = nla_put_flag(skb, TSN_QBV_ATTR_ENABLE +
++                                         TSN_QBV_ATTR_CTRL_MAX);
++              else
++                      res = nla_put_flag(skb, TSN_QBV_ATTR_DISABLE +
++                                         TSN_QBV_ATTR_CTRL_MAX);
++              if (res) {
++                      pr_err("put data failure!\n");
++                      goto done;
++              }
++
++              res = nla_put_u32(skb, TSN_QBV_ATTR_CTRL_UNSPEC,
++                                tsn_info->dev->ifindex);
++              if (res) {
++                      pr_err("put data failure!\n");
++                      goto done;
++              }
++
++              break;
++      default:
++              pr_info("event not supportted!\n");
++              break;
++      }
++
++      (void)genlmsg_end(skb, nlh);
++
++      res = genlmsg_multicast_allns(&tsn_family, skb, 0,
++                                    TSN_MCGRP_QBV, GFP_KERNEL);
++      skb = NULL;
++      if (res && res != -ESRCH) {
++              pr_err("genlmsg_multicast_allns error: %d\n", res);
++              goto done;
++      }
++
++      if (res == -ESRCH)
++              res = 0;
++
++done:
++      if (skb) {
++              nlmsg_free(skb);
++              skb = NULL;
++      }
++
++      return res;
++}
++
++/* called with RTNL or RCU */
++static int tsn_event(struct notifier_block *unused,
++                   unsigned long event, void *ptr)
++{
++      struct tsn_notifier_info *tsn_info;
++      int err = NOTIFY_DONE;
++
++      switch (event) {
++      case TSN_QBV_CONFIGCHANGETIME_ARRIVE:
++              tsn_info = ptr;
++              err = tsn_multicast_to_user(event, tsn_info);
++              if (err) {
++                      err = notifier_from_errno(err);
++                      break;
++              }
++              break;
++      default:
++              pr_info("event not supportted!\n");
++              break;
++      }
++
++      return err;
++}
++
++static struct notifier_block tsn_notifier = {
++      .notifier_call = tsn_event,
++};
++
++static int __init tsn_genetlink_init(void)
++{
++      int ret;
++
++      pr_info("tsn generic netlink module v%d init...\n", TSN_GENL_VERSION);
++
++      ret = genl_register_family(&tsn_family);
++
++      if (ret != 0) {
++              pr_info("failed to init tsn generic netlink example module\n");
++              return ret;
++      }
++
++      register_tsn_notifier(&tsn_notifier);
++
++      return 0;
++}
++
++static void __exit tsn_genetlink_exit(void)
++{
++      int ret;
++
++      ret = genl_unregister_family(&tsn_family);
++      if (ret != 0)
++              pr_info("failed to unregister family:%i\n", ret);
++
++      unregister_tsn_notifier(&tsn_notifier);
++}
++
++module_init(tsn_genetlink_init);
++module_exit(tsn_genetlink_exit);
++MODULE_LICENSE("GPL");
diff --git a/target/linux/layerscape/patches-5.4/701-net-0335-net-tsn-fix-headfile-voliates-the-new-rule.patch b/target/linux/layerscape/patches-5.4/701-net-0335-net-tsn-fix-headfile-voliates-the-new-rule.patch
new file mode 100644 (file)
index 0000000..e732f14
--- /dev/null
@@ -0,0 +1,22 @@
+From 6e9f130a3be14a92a16b2332f6c92f873ebb8af5 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Tue, 3 Sep 2019 15:57:49 +0800
+Subject: [PATCH] net: tsn: fix headfile voliates the new rule
+
+After commit
+622445541b75 ("kbuild: detect missing "WITH Linux-syscall-note" for uapi headers")
+the headfile must explicitly include "WITH Linux-syscall-note".
+
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ include/uapi/linux/tsn.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/include/uapi/linux/tsn.h
++++ b/include/uapi/linux/tsn.h
+@@ -1,4 +1,4 @@
+-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) WITH Linux-syscall-note */
+ /* Copyright 2017-2019 NXP */
+ #ifndef __UAPI_GENL_TSN_H
diff --git a/target/linux/layerscape/patches-5.4/701-net-0336-enetc-add-support-Credit-Based-Shaper-CBS-for-hardwa.patch b/target/linux/layerscape/patches-5.4/701-net-0336-enetc-add-support-Credit-Based-Shaper-CBS-for-hardwa.patch
new file mode 100644 (file)
index 0000000..fd89174
--- /dev/null
@@ -0,0 +1,231 @@
+From 3426e5e4339f124f00eef8815b56a80481364550 Mon Sep 17 00:00:00 2001
+From: Po Liu <po.liu@nxp.com>
+Date: Mon, 25 Nov 2019 05:56:56 +0000
+Subject: [PATCH] enetc: add support Credit Based Shaper(CBS) for hardware
+ offload
+
+The ENETC hardware support the Credit Based Shaper(CBS) which part
+of the IEEE-802.1Qav. The CBS driver was loaded by the sch_cbs
+interface when set in the QOS in the kernel.
+
+Here is an example command to set 20Mbits bandwidth in 1Gbits port
+for taffic class 7:
+
+tc qdisc add dev eth0 root handle 1: mqprio \
+          num_tc 8 map 0 1 2 3 4 5 6 7 hw 1
+
+tc qdisc replace dev eth0 parent 1:8 cbs \
+          locredit -1470 hicredit 30 \
+          sendslope -980000 idleslope 20000 offload 1
+
+Signed-off-by: Po Liu <Po.Liu@nxp.com>
+Reviewed-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/freescale/enetc/Kconfig     |   4 +-
+ drivers/net/ethernet/freescale/enetc/enetc.c     |   2 +
+ drivers/net/ethernet/freescale/enetc/enetc.h     |   2 +
+ drivers/net/ethernet/freescale/enetc/enetc_hw.h  |   4 +
+ drivers/net/ethernet/freescale/enetc/enetc_qos.c | 128 +++++++++++++++++++++++
+ 5 files changed, 138 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/Kconfig
++++ b/drivers/net/ethernet/freescale/enetc/Kconfig
+@@ -53,10 +53,10 @@ config FSL_ENETC_HW_TIMESTAMPING
+ config FSL_ENETC_QOS
+       bool "ENETC hardware Time-sensitive Network support"
+-      depends on (FSL_ENETC || FSL_ENETC_VF) && NET_SCH_TAPRIO
++      depends on (FSL_ENETC || FSL_ENETC_VF) && (NET_SCH_TAPRIO || NET_SCH_CBS)
+       help
+         There are Time-Sensitive Network(TSN) capabilities(802.1Qbv/802.1Qci
+         /802.1Qbu etc.) supported by ENETC. These TSN capabilities can be set
+         enable/disable from user space via Qos commands(tc). In the kernel
+         side, it can be loaded by Qos driver. Currently, it is only support
+-        taprio(802.1Qbv).
++        taprio(802.1Qbv) and Credit Based Shaper(802.1Qbu).
+--- a/drivers/net/ethernet/freescale/enetc/enetc.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc.c
+@@ -1524,6 +1524,8 @@ int enetc_setup_tc(struct net_device *nd
+               return enetc_setup_tc_mqprio(ndev, type_data);
+       case TC_SETUP_QDISC_TAPRIO:
+               return enetc_setup_tc_taprio(ndev, type_data);
++      case TC_SETUP_QDISC_CBS:
++              return enetc_setup_tc_cbs(ndev, type_data);
+       default:
+               return -EOPNOTSUPP;
+       }
+--- a/drivers/net/ethernet/freescale/enetc/enetc.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc.h
+@@ -255,7 +255,9 @@ int enetc_send_cmd(struct enetc_si *si,
+ #ifdef CONFIG_FSL_ENETC_QOS
+ int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
+ void enetc_sched_speed_set(struct net_device *ndev);
++int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data);
+ #else
+ #define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
+ #define enetc_sched_speed_set(ndev) (void)0
++#define enetc_setup_tc_cbs(ndev, type_data) -EOPNOTSUPP
+ #endif
+--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+@@ -185,6 +185,8 @@ enum enetc_bdr_type {TX, RX};
+ #define ENETC_PSICFGR0_SIVC(bmp)      (((bmp) & 0xff) << 24) /* VLAN_TYPE */
+ #define ENETC_PTCCBSR0(n)     (0x1110 + (n) * 8) /* n = 0 to 7*/
++#define ENETC_CBSE            BIT(31)
++#define ENETC_CBS_BW_MASK     GENMASK(6, 0)
+ #define ENETC_PTCCBSR1(n)     (0x1114 + (n) * 8) /* n = 0 to 7*/
+ #define ENETC_RSSHASH_KEY_SIZE        40
+ #define ENETC_PRSSK(n)                (0x1410 + (n) * 4) /* n = [0..9] */
+@@ -673,6 +675,8 @@ struct enetc_cbd {
+       u8 status_flags;
+ };
++#define ENETC_CLK  400000000ULL
++
+ /* port time gating control register */
+ #define ENETC_QBV_PTGCR_OFFSET                0x11a00
+ #define ENETC_QBV_TGE                 BIT(31)
+--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
+@@ -4,6 +4,7 @@
+ #include "enetc.h"
+ #include <net/pkt_sched.h>
++#include <linux/math64.h>
+ static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
+ {
+@@ -170,3 +171,130 @@ int enetc_setup_tc_taprio(struct net_dev
+       return err;
+ }
++
++static u32 enetc_get_cbs_enable(struct enetc_hw *hw, u8 tc)
++{
++      return enetc_port_rd(hw, ENETC_PTCCBSR0(tc)) & ENETC_CBSE;
++}
++
++static u8 enetc_get_cbs_bw(struct enetc_hw *hw, u8 tc)
++{
++      return enetc_port_rd(hw, ENETC_PTCCBSR0(tc)) & ENETC_CBS_BW_MASK;
++}
++
++int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data)
++{
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      struct tc_cbs_qopt_offload *cbs = type_data;
++      u32 port_transmit_rate = priv->speed;
++      u8 tc_nums = netdev_get_num_tc(ndev);
++      struct enetc_si *si = priv->si;
++      u32 hi_credit_bit, hi_credit_reg;
++      u32 max_interference_size;
++      u32 port_frame_max_size;
++      u32 tc_max_sized_frame;
++      u8 tc = cbs->queue;
++      u8 prio_top, prio_next;
++      int bw_sum = 0;
++      u8 bw;
++
++      prio_top = netdev_get_prio_tc_map(ndev, tc_nums - 1);
++      prio_next = netdev_get_prio_tc_map(ndev, tc_nums - 2);
++
++      /* Support highest prio and second prio tc in cbs mode */
++      if (tc != prio_top && tc != prio_next)
++              return -EOPNOTSUPP;
++
++      if (!cbs->enable) {
++              /* Make sure the other TC that are numerically
++               * lower than this TC have been disabled.
++               */
++              if (tc == prio_top &&
++                  enetc_get_cbs_enable(&si->hw, prio_next)) {
++                      dev_err(&ndev->dev,
++                              "Disable TC%d before disable TC%d\n",
++                              prio_next, tc);
++                      return -EINVAL;
++              }
++
++              enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), 0);
++              enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), 0);
++
++              return 0;
++      }
++
++      if (cbs->idleslope - cbs->sendslope != port_transmit_rate * 1000L ||
++          cbs->idleslope < 0 || cbs->sendslope > 0)
++              return -EOPNOTSUPP;
++
++      port_frame_max_size = ndev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
++
++      bw = cbs->idleslope / (port_transmit_rate * 10UL);
++
++      /* Make sure the other TC that are numerically
++       * higher than this TC have been enabled.
++       */
++      if (tc == prio_next) {
++              if (!enetc_get_cbs_enable(&si->hw, prio_top)) {
++                      dev_err(&ndev->dev,
++                              "Enable TC%d first before enable TC%d\n",
++                              prio_top, prio_next);
++                      return -EINVAL;
++              }
++              bw_sum += enetc_get_cbs_bw(&si->hw, prio_top);
++      }
++
++      if (bw_sum + bw >= 100) {
++              dev_err(&ndev->dev,
++                      "The sum of all CBS Bandwidth can't exceed 100\n");
++              return -EINVAL;
++      }
++
++      tc_max_sized_frame = enetc_port_rd(&si->hw, ENETC_PTCMSDUR(tc));
++
++      /* For top prio TC, the max_interfrence_size is maxSizedFrame.
++       *
++       * For next prio TC, the max_interfrence_size is calculated as below:
++       *
++       *      max_interference_size = M0 + Ma + Ra * M0 / (R0 - Ra)
++       *
++       *      - RA: idleSlope for AVB Class A
++       *      - R0: port transmit rate
++       *      - M0: maximum sized frame for the port
++       *      - MA: maximum sized frame for AVB Class A
++       */
++
++      if (tc == prio_top) {
++              max_interference_size = port_frame_max_size * 8;
++      } else {
++              u32 m0, ma, r0, ra;
++
++              m0 = port_frame_max_size * 8;
++              ma = enetc_port_rd(&si->hw, ENETC_PTCMSDUR(prio_top)) * 8;
++              ra = enetc_get_cbs_bw(&si->hw, prio_top) *
++                      port_transmit_rate * 10000ULL;
++              r0 = port_transmit_rate * 1000000ULL;
++              max_interference_size = m0 + ma +
++                      (u32)div_u64((u64)ra * m0, r0 - ra);
++      }
++
++      /* hiCredit bits calculate by:
++       *
++       * maxSizedFrame * (idleSlope/portTxRate)
++       */
++      hi_credit_bit = max_interference_size * bw / 100;
++
++      /* hiCredit bits to hiCredit register need to calculated as:
++       *
++       * (enetClockFrequency / portTransmitRate) * 100
++       */
++      hi_credit_reg = (u32)div_u64((ENETC_CLK * 100ULL) * hi_credit_bit,
++                                   port_transmit_rate * 1000000ULL);
++
++      enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), hi_credit_reg);
++
++      /* Set bw register and enable this traffic class */
++      enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), bw | ENETC_CBSE);
++
++      return 0;
++}
diff --git a/target/linux/layerscape/patches-5.4/701-net-0337-enetc-add-support-tsn-capabilities-qbv-qci-qbu-cbs.patch b/target/linux/layerscape/patches-5.4/701-net-0337-enetc-add-support-tsn-capabilities-qbv-qci-qbu-cbs.patch
new file mode 100644 (file)
index 0000000..6200bd8
--- /dev/null
@@ -0,0 +1,2911 @@
+From bf3f81f3773cc9f6b273d769aca96512780c6189 Mon Sep 17 00:00:00 2001
+From: Po Liu <Po.Liu@nxp.com>
+Date: Tue, 3 Dec 2019 16:52:57 +0800
+Subject: [PATCH] enetc: add support tsn capabilities qbv/qci/qbu/cbs
+
+Support Qbv/Qci/Qbu/Credit Base Shaper etc.
+This patch using the generic netlink adapt layer driver net/tsn/*
+and include/net/tsn.h interface load by user space. The user space
+refer the include/uapi/linux/tsn.h.
+
+Signed-off-by: Po Liu <Po.Liu@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/Kconfig       |   10 +
+ drivers/net/ethernet/freescale/enetc/Makefile      |    1 +
+ drivers/net/ethernet/freescale/enetc/enetc.c       |   13 +-
+ drivers/net/ethernet/freescale/enetc/enetc.h       |   38 +
+ .../net/ethernet/freescale/enetc/enetc_ethtool.c   |   59 +
+ drivers/net/ethernet/freescale/enetc/enetc_hw.h    |  438 ++++-
+ drivers/net/ethernet/freescale/enetc/enetc_pf.c    |   15 +-
+ drivers/net/ethernet/freescale/enetc/enetc_tsn.c   | 2049 ++++++++++++++++++++
+ 8 files changed, 2614 insertions(+), 9 deletions(-)
+ create mode 100644 drivers/net/ethernet/freescale/enetc/enetc_tsn.c
+
+--- a/drivers/net/ethernet/freescale/enetc/Kconfig
++++ b/drivers/net/ethernet/freescale/enetc/Kconfig
+@@ -60,3 +60,13 @@ config FSL_ENETC_QOS
+         enable/disable from user space via Qos commands(tc). In the kernel
+         side, it can be loaded by Qos driver. Currently, it is only support
+         taprio(802.1Qbv) and Credit Based Shaper(802.1Qbu).
++
++config ENETC_TSN
++      bool "TSN Support for NXP ENETC driver"
++      default n
++      depends on TSN && FSL_ENETC
++      help
++        This driver supports TSN on Freescale ENETC driver. Provide
++        interface to config the tsn capabilities of ENETC. The interface link
++        to the /net/tsn/* and include/net/tsn.h. User space refer the
++        include/uapi/linux/tsn.h.
+--- a/drivers/net/ethernet/freescale/enetc/Makefile
++++ b/drivers/net/ethernet/freescale/enetc/Makefile
+@@ -6,6 +6,7 @@ obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
+ fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs)
+ fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
+ fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
++fsl-enetc-$(CONFIG_ENETC_TSN) += enetc_tsn.o
+ obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
+ fsl-enetc-vf-y := enetc_vf.o $(common-objs)
+--- a/drivers/net/ethernet/freescale/enetc/enetc.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc.c
+@@ -145,7 +145,8 @@ static int enetc_map_tx_buffs(struct ene
+       do_tstamp = (active_offloads & ENETC_F_TX_TSTAMP) &&
+                   (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP);
+       tx_swbd->do_tstamp = do_tstamp;
+-      tx_swbd->check_wb = tx_swbd->do_tstamp;
++      tx_swbd->qbv_en = !!(active_offloads & ENETC_F_QBV);
++      tx_swbd->check_wb = tx_swbd->do_tstamp || tx_swbd->qbv_en;
+       if (do_vlan || do_tstamp)
+               flags |= ENETC_TXBD_FLAGS_EX;
+@@ -342,7 +343,7 @@ static void enetc_tstamp_tx(struct sk_bu
+ static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget)
+ {
+       struct net_device *ndev = tx_ring->ndev;
+-      int tx_frm_cnt = 0, tx_byte_cnt = 0;
++      int tx_frm_cnt = 0, tx_byte_cnt = 0, tx_win_drop = 0;
+       struct enetc_tx_swbd *tx_swbd;
+       int i, bds_to_clean;
+       bool do_tstamp;
+@@ -372,6 +373,10 @@ static bool enetc_clean_tx_ring(struct e
+                                                   &tstamp);
+                               do_tstamp = true;
+                       }
++
++                      if (tx_swbd->qbv_en &&
++                          txbd->wb.status & ENETC_TXBD_STATS_WIN)
++                              tx_win_drop++;
+               }
+               if (likely(tx_swbd->dma))
+@@ -415,6 +420,7 @@ static bool enetc_clean_tx_ring(struct e
+       tx_ring->next_to_clean = i;
+       tx_ring->stats.packets += tx_frm_cnt;
+       tx_ring->stats.bytes += tx_byte_cnt;
++      tx_ring->stats.win_drop += tx_win_drop;
+       if (unlikely(tx_frm_cnt && netif_carrier_ok(ndev) &&
+                    __netif_subqueue_stopped(ndev, tx_ring->index) &&
+@@ -778,6 +784,9 @@ void enetc_get_si_caps(struct enetc_si *
+       if (val & ENETC_SIPCAPR0_QBV)
+               si->hw_features |= ENETC_SI_F_QBV;
++
++      if (val & ENETC_SIPCAPR0_QBU)
++              si->hw_features |= ENETC_SI_F_QBU;
+ }
+ static int enetc_dma_alloc_bdr(struct enetc_bdr *r, size_t bd_size)
+--- a/drivers/net/ethernet/freescale/enetc/enetc.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc.h
+@@ -10,6 +10,7 @@
+ #include <linux/ethtool.h>
+ #include <linux/if_vlan.h>
+ #include <linux/phy.h>
++#include <net/tsn.h>
+ #include "enetc_hw.h"
+@@ -24,6 +25,7 @@ struct enetc_tx_swbd {
+       u8 is_dma_page:1;
+       u8 check_wb:1;
+       u8 do_tstamp:1;
++      u8 qbv_en:1;
+ };
+ #define ENETC_RX_MAXFRM_SIZE  ENETC_MAC_MAXFRM_SIZE
+@@ -42,6 +44,7 @@ struct enetc_ring_stats {
+       unsigned int packets;
+       unsigned int bytes;
+       unsigned int rx_alloc_errs;
++      unsigned int win_drop;
+ };
+ #define ENETC_BDR_DEFAULT_SIZE        1024
+@@ -111,6 +114,28 @@ struct enetc_msg_swbd {
+       int size;
+ };
++#ifdef CONFIG_ENETC_TSN
++/* Credit-Based Shaper parameters */
++struct cbs {
++      u8 tc;
++      bool enable;
++      u8 bw;
++      u32 hi_credit;
++      u32 lo_credit;
++      u32 idle_slope;
++      u32 send_slope;
++      u32 tc_max_sized_frame;
++      u32 max_interfrence_size;
++};
++
++struct enetc_cbs {
++      u32 port_transmit_rate;
++      u32 port_max_size_frame;
++      u8 tc_nums;
++      struct cbs cbs[0];
++};
++#endif
++
+ #define ENETC_REV1    0x1
+ enum enetc_errata {
+       ENETC_ERR_TXCSUM        = BIT(0),
+@@ -119,6 +144,7 @@ enum enetc_errata {
+ };
+ #define ENETC_SI_F_QBV BIT(0)
++#define ENETC_SI_F_QBU BIT(1)
+ /* PCI IEP device data */
+ struct enetc_si {
+@@ -136,6 +162,10 @@ struct enetc_si {
+       int num_rss; /* number of RSS buckets */
+       unsigned short pad;
+       int hw_features;
++#ifdef CONFIG_ENETC_TSN
++      struct enetc_cbs *ecbs;
++#endif
++
+ };
+ #define ENETC_SI_ALIGN        32
+@@ -177,6 +207,7 @@ enum enetc_active_offloads {
+       ENETC_F_RX_TSTAMP       = BIT(0),
+       ENETC_F_TX_TSTAMP       = BIT(1),
+       ENETC_F_QBV             = BIT(2),
++      ENETC_F_QBU             = BIT(3),
+ };
+ struct enetc_ndev_priv {
+@@ -261,3 +292,10 @@ int enetc_setup_tc_cbs(struct net_device
+ #define enetc_sched_speed_set(ndev) (void)0
+ #define enetc_setup_tc_cbs(ndev, type_data) -EOPNOTSUPP
+ #endif
++#ifdef CONFIG_ENETC_TSN
++void enetc_tsn_pf_init(struct net_device *netdev, struct pci_dev *pdev);
++void enetc_tsn_pf_deinit(struct net_device *netdev);
++#else
++#define enetc_tsn_pf_init(netdev, pdev) (void)0
++#define enetc_tsn_pf_deinit(netdev) (void)0
++#endif
+--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+@@ -183,6 +183,21 @@ static const struct {
+       { ENETC_PICDR(3),   "ICM DR3 discarded frames" },
+ };
++static const struct {
++      int reg;
++      char name[ETH_GSTRING_LEN];
++} enetc_pmac_counters[] = {
++      { ENETC_PM1_RFRM,   "PMAC rx frames" },
++      { ENETC_PM1_RPKT,   "PMAC rx packets" },
++      { ENETC_PM1_RDRP,   "PMAC rx dropped packets" },
++      { ENETC_PM1_RFRG,   "PMAC rx fragment packets" },
++      { ENETC_PM1_TFRM,   "PMAC tx frames" },
++      { ENETC_PM1_TERR,   "PMAC tx error frames" },
++      { ENETC_PM1_TPKT,   "PMAC tx packets" },
++      { ENETC_MAC_MERGE_MMFCRXR,   "MAC merge fragment rx counter" },
++      { ENETC_MAC_MERGE_MMFCTXR,   "MAC merge fragment tx counter"},
++};
++
+ static const char rx_ring_stats[][ETH_GSTRING_LEN] = {
+       "Rx ring %2d frames",
+       "Rx ring %2d alloc errors",
+@@ -192,6 +207,10 @@ static const char tx_ring_stats[][ETH_GS
+       "Tx ring %2d frames",
+ };
++static const char tx_windrop_stats[][ETH_GSTRING_LEN] = {
++      "Tx window drop %2d frames",
++};
++
+ static int enetc_get_sset_count(struct net_device *ndev, int sset)
+ {
+       struct enetc_ndev_priv *priv = netdev_priv(ndev);
+@@ -209,6 +228,12 @@ static int enetc_get_sset_count(struct n
+       len += ARRAY_SIZE(enetc_port_counters);
++      if (priv->active_offloads & ENETC_F_QBU)
++              len += ARRAY_SIZE(enetc_pmac_counters);
++
++      if (priv->active_offloads & ENETC_F_QBV)
++              len += ARRAY_SIZE(tx_windrop_stats) * priv->num_tx_rings;
++
+       return len;
+ }
+@@ -247,6 +272,28 @@ static void enetc_get_strings(struct net
+                               ETH_GSTRING_LEN);
+                       p += ETH_GSTRING_LEN;
+               }
++
++              if (!(priv->active_offloads & ENETC_F_QBU))
++                      break;
++
++              for (i = 0; i < ARRAY_SIZE(enetc_pmac_counters); i++) {
++                      strlcpy(p, enetc_pmac_counters[i].name,
++                              ETH_GSTRING_LEN);
++                      p += ETH_GSTRING_LEN;
++              }
++
++              if (!((priv->active_offloads & ENETC_F_QBV)))
++                      break;
++
++              for (i = 0; i < priv->num_tx_rings; i++) {
++                      for (j = 0; j < ARRAY_SIZE(tx_windrop_stats); j++) {
++                              snprintf(p, ETH_GSTRING_LEN,
++                                       tx_windrop_stats[j],
++                                       i);
++                              p += ETH_GSTRING_LEN;
++                      }
++              }
++
+               break;
+       }
+ }
+@@ -274,6 +321,18 @@ static void enetc_get_ethtool_stats(stru
+       for (i = 0; i < ARRAY_SIZE(enetc_port_counters); i++)
+               data[o++] = enetc_port_rd(hw, enetc_port_counters[i].reg);
++
++      if (!(priv->active_offloads & ENETC_F_QBU))
++              return;
++
++      for (i = 0; i < ARRAY_SIZE(enetc_pmac_counters); i++)
++              data[o++] = enetc_port_rd(hw, enetc_pmac_counters[i].reg);
++
++      if (!((priv->active_offloads & ENETC_F_QBV)))
++              return;
++
++      for (i = 0; i < priv->num_tx_rings; i++)
++              data[o++] = priv->tx_ring[i]->stats.win_drop;
+ }
+ #define ENETC_RSSHASH_L3 (RXH_L2DA | RXH_VLAN | RXH_L3_PROTO | RXH_IP_SRC | \
+--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+@@ -19,6 +19,7 @@
+ #define ENETC_SICTR1  0x1c
+ #define ENETC_SIPCAPR0        0x20
+ #define ENETC_SIPCAPR0_QBV    BIT(4)
++#define ENETC_SIPCAPR0_QBU    BIT(3)
+ #define ENETC_SIPCAPR0_RSS    BIT(8)
+ #define ENETC_SIPCAPR1        0x24
+ #define ENETC_SITGTGR 0x30
+@@ -241,10 +242,20 @@ enum enetc_bdr_type {TX, RX};
+ #define ENETC_PCS_IF_MODE_SGMII_AN    0x0003
+ #define ENETC_PM0_IF_MODE     0x8300
++#define ENETC_PM1_IF_MODE       0x9300
+ #define ENETC_PMO_IFM_RG      BIT(2)
+ #define ENETC_PM0_IFM_RLP     (BIT(5) | BIT(11))
+ #define ENETC_PM0_IFM_RGAUTO  (BIT(15) | ENETC_PMO_IFM_RG | BIT(1))
+ #define ENETC_PM0_IFM_XGMII   BIT(12)
++#define ENETC_PSIDCAPR                0x1b08
++#define ENETC_PSIDCAPR_MSK    GENMASK(15, 0)
++#define ENETC_PSFCAPR         0x1b18
++#define ENETC_PSFCAPR_MSK     GENMASK(15, 0)
++#define ENETC_PSGCAPR         0x1b28
++#define ENETC_PSGCAPR_GCL_MSK GENMASK(18, 16)
++#define ENETC_PSGCAPR_SGIT_MSK        GENMASK(15, 0)
++#define ENETC_PFMCAPR         0x1b38
++#define ENETC_PFMCAPR_MSK     GENMASK(15, 0)
+ /* MAC counters */
+ #define ENETC_PM0_REOCT               0x8100
+@@ -294,6 +305,15 @@ enum enetc_bdr_type {TX, RX};
+ #define ENETC_PM0_TSCOL               0x82E0
+ #define ENETC_PM0_TLCOL               0x82E8
+ #define ENETC_PM0_TECOL               0x82F0
++#define ENETC_PM1_RFRM                0x9120
++#define ENETC_PM1_RDRP                0x9158
++#define ENETC_PM1_RPKT                0x9160
++#define ENETC_PM1_RFRG                0x91B8
++#define ENETC_PM1_TFRM                0x9220
++#define ENETC_PM1_TERR                0x9238
++#define ENETC_PM1_TPKT                0x9260
++#define ENETC_MAC_MERGE_MMFCRXR       0x1f14
++#define ENETC_MAC_MERGE_MMFCTXR       0x1f18
+ /* Port counters */
+ #define ENETC_PICDR(n)                (0x0700 + (n) * 8) /* n = [0..3] */
+@@ -452,6 +472,7 @@ union enetc_tx_bd {
+ #define ENETC_TXBD_FLAGS_CSUM BIT(3)
+ #define ENETC_TXBD_FLAGS_EX   BIT(6)
+ #define ENETC_TXBD_FLAGS_F    BIT(7)
++#define ENETC_TXBD_STATS_WIN  BIT(7)
+ static inline void enetc_clear_tx_bd(union enetc_tx_bd *txbd)
+ {
+@@ -479,6 +500,8 @@ static inline __le16 enetc_txbd_l3_csoff
+ #define ENETC_TXBD_L4_UDP     BIT(5)
+ #define ENETC_TXBD_L4_TCP     BIT(6)
++#define enetc_tsn_is_enabled() IS_ENABLED(CONFIG_ENETC_TSN)
++
+ union enetc_rx_bd {
+       struct {
+               __le64 addr;
+@@ -625,21 +648,307 @@ enum bdcr_cmd_class {
+       BDCR_CMD_RFS,
+       BDCR_CMD_PORT_GCL,
+       BDCR_CMD_RECV_CLASSIFIER,
++      BDCR_CMD_STREAM_IDENTIFY,
++      BDCR_CMD_STREAM_FILTER,
++      BDCR_CMD_STREAM_GCL,
++      BDCR_CMD_FLOW_METER,
+       __BDCR_CMD_MAX_LEN,
+       BDCR_CMD_MAX_LEN = __BDCR_CMD_MAX_LEN - 1,
+ };
++/* class 7, command 0, Stream Identity Entry Configuration */
++struct streamid_conf {
++      __le32  stream_handle;  /* init gate value */
++      __le32  iports;
++              u8      id_type;
++              u8      oui[3];
++              u8      res[3];
++              u8      en;
++};
++
++#define ENETC_CBDR_SID_VID_MASK 0xfff
++#define ENETC_CBDR_SID_VIDM BIT(12)
++#define ENETC_CBDR_SID_TG_MASK 0xc000
++/* streamid_conf address point to this data space */
++struct null_streamid_data {
++      u8      dmac[6];
++      u16     vid_vidm_tg;
++};
++
++struct smac_streamid_data {
++      u8      smac[6];
++      u16     vid_vidm_tg;
++};
++
++/* class 7, command 1, query config , long format */
++/* No need structure define */
++
++#define ENETC_CDBR_SID_ENABLE BIT(7)
++/*  Stream ID Query Response Data Buffer */
++struct streamid_query_resp {
++      u32     stream_handle;
++      u32     input_ports;
++      u8      id_type;
++      u8      oui[3];
++      u8      mac[6];
++      u16     vid_vidm_tg;
++      u8      res[3];
++      u8  en;
++};
++
++/* class 7, command 2, qeury status count, Stream ID query long format */
++struct streamid_stat_query {
++      u8      res[12];
++      __le32 input_ports;
++};
++
++/* Stream Identity Statistics Query */
++struct streamid_stat_query_resp {
++      u32     psinl;
++      u32     psinh;
++      u64     pspi[32];
++};
++
++#define ENETC_CBDR_SFI_PRI_MASK 0x7
++#define ENETC_CBDR_SFI_PRIM           BIT(3)
++#define ENETC_CBDR_SFI_BLOV           BIT(4)
++#define ENETC_CBDR_SFI_BLEN           BIT(5)
++#define ENETC_CBDR_SFI_MSDUEN BIT(6)
++#define ENETC_CBDR_SFI_FMITEN BIT(7)
++#define ENETC_CBDR_SFI_ENABLE BIT(7)
++/* class 8, command 0, Stream Filter Instance, Short Format */
++struct sfi_conf {
++      __le32  stream_handle;
++              u8      multi;
++              u8      res[2];
++              u8      sthm;
++      /* Max Service Data Unit or Flow Meter Instance Table index.
++       * Depending on the value of FLT this represents either Max
++       * Service Data Unit (max frame size) allowed by the filter
++       * entry or is an index into the Flow Meter Instance table
++       * index identifying the policer which will be used to police
++       * it.
++       */
++      __le16  fm_inst_table_index;
++      __le16  msdu;
++      __le16  sg_inst_table_index;
++              u8      res1[2];
++      __le32  input_ports;
++              u8      res2[3];
++              u8      en;
++};
++
++/* class 8, command 1, Stream Filter Instance, write back, short Format */
++struct sfi_query {
++              u32     stream_handle;
++              u8      multi;
++              u8      res[2];
++              u8      sthm;
++              u16     fm_inst_table_index;
++              u16     msdu;
++              u16     sg_inst_table_index;
++              u8      res1[2];
++              u32     input_ports;
++              u8      res2[3];
++              u8      en;
++};
++
++/* class 8, command 2 stream Filter Instance status query short format
++ * command no need structure define
++ * Stream Filter Instance Query Statistics Response data
++ */
++struct sfi_counter_data {
++      u32 matchl;
++      u32 matchh;
++      u32 msdu_dropl;
++      u32 msdu_droph;
++      u32 stream_gate_dropl;
++      u32 stream_gate_droph;
++      u32 flow_meter_dropl;
++      u32 flow_meter_droph;
++};
++
++#define ENETC_CBDR_SGI_OIPV_MASK 0x7
++#define ENETC_CBDR_SGI_OIPV_EN        BIT(3)
++#define ENETC_CBDR_SGI_CGTST  BIT(6)
++#define ENETC_CBDR_SGI_OGTST  BIT(7)
++#define ENETC_CBDR_SGI_CFG_CHG  BIT(1)
++#define ENETC_CBDR_SGI_CFG_PND  BIT(2)
++#define ENETC_CBDR_SGI_OEX            BIT(4)
++#define ENETC_CBDR_SGI_OEXEN  BIT(5)
++#define ENETC_CBDR_SGI_IRX            BIT(6)
++#define ENETC_CBDR_SGI_IRXEN  BIT(7)
++#define ENETC_CBDR_SGI_ACLLEN_MASK 0x3
++#define ENETC_CBDR_SGI_OCLLEN_MASK 0xc
++#define       ENETC_CBDR_SGI_EN               BIT(7)
++/* class 9, command 0, Stream Gate Instance Table, Short Format
++ * class 9, command 2, Stream Gate Instance Table entry query write back
++ * Short Format
++ */
++struct sgi_table {
++      u8      res[8];
++      u8      oipv;
++      u8      res0[2];
++      u8      ocgtst;
++      u8      res1[7];
++      u8      gset;
++      u8      oacl_len;
++      u8      res2[2];
++      u8      en;
++};
++
++#define ENETC_CBDR_SGI_AIPV_MASK 0x7
++#define ENETC_CBDR_SGI_AIPV_EN        BIT(3)
++#define ENETC_CBDR_SGI_AGTST  BIT(7)
++
++/* class 9, command 1, Stream Gate Control List, Long Format */
++struct sgcl_conf {
++      u8      aipv;
++      u8      res[2];
++      u8      agtst;
++      u8      res1[4];
++      union {
++              struct {
++                      u8 res2[4];
++                      u8 acl_len;
++                      u8 res3[3];
++              };
++              u8 cct[8]; /* Config change time */
++      };
++};
++
++/* stream control list class 9 , cmd 1 data buffer */
++struct sgcl_data {
++      u32     btl;
++      u32 bth;
++      u32     ct;
++      u32     cte;
++      /*struct sgce   *sgcl;*/
++};
++
++/* class 9, command 2, stream gate instant table enery query, short format
++ * write back see struct sgi_table. Do not need define.
++ * class 9, command 3 Stream Gate Control List Query Descriptor - Long Format
++ * ocl_len or acl_len to be 0, oper or admin would not show in the data space
++ * true len will be write back in the space.
++ */
++struct sgcl_query {
++      u8 res[12];
++      u8 oacl_len;
++      u8 res1[3];
++};
++
++/* define for 'stat' */
++#define ENETC_CBDR_SGIQ_AIPV_MASK 0x7
++#define ENETC_CBDR_SGIQ_AIPV_EN       BIT(3)
++#define ENETC_CBDR_SGIQ_AGTST BIT(4)
++#define ENETC_CBDR_SGIQ_ACL_LEN_MASK 0x60
++#define ENETC_CBDR_SGIQ_OIPV_MASK 0x380
++#define ENETC_CBDR_SGIQ_OIPV_EN       BIT(10)
++#define ENETC_CBDR_SGIQ_OGTST BIT(11)
++#define ENETC_CBDR_SGIQ_OCL_LEN_MASK 0x3000
++/* class 9, command 3 data space */
++struct sgcl_query_resp {
++      u16 stat;
++      u16 res;
++      u32     abtl;
++      u32 abth;
++      u32     act;
++      u32     acte;
++      u32     cctl;
++      u32 ccth;
++      u32     obtl;
++      u32 obth;
++      u32     oct;
++      u32     octe;
++};
++
++/* class 9, command 4 Stream Gate Instance Table Query Statistics Response
++ * short command, write back, no command define
++ */
++struct sgi_query_stat_resp {
++      u32     pgcl;
++      u32 pgch;
++      u32 dgcl;
++      u32 dgch;
++      u16     msdu_avail;
++      u8 res[6];
++};
++
++#define ENETC_CBDR_FMI_MR     BIT(0)
++#define ENETC_CBDR_FMI_MREN BIT(1)
++#define ENETC_CBDR_FMI_DOY    BIT(2)
++#define       ENETC_CBDR_FMI_CM       BIT(3)
++#define ENETC_CBDR_FMI_CF     BIT(4)
++#define ENETC_CBDR_FMI_NDOR BIT(5)
++#define ENETC_CBDR_FMI_OALEN BIT(6)
++#define ENETC_CBDR_FMI_IRFPP_MASK 0x1f
++/* class 10: command 0/1, Flow Meter Instance Set, short Format */
++struct fmi_conf {
++      __le32  cir;
++      __le32  cbs;
++      __le32  eir;
++      __le32  ebs;
++              u8      conf;
++              u8      res1;
++              u8      ir_fpp;
++              u8      res2[4];
++              u8      en;
++};
++
++/* class:10, command:2, Flow Meter Instance Statistics Query Response */
++struct fmi_query_stat_resp {
++      u32     bcl;
++      u32 bch;
++      u32 dfl;
++      u32 dfh;
++      u32 d0gfl;
++      u32 d0gfh;
++      u32 d1gfl;
++      u32 d1gfh;
++      u32 dyfl;
++      u32 dyfh;
++      u32 ryfl;
++      u32 ryfh;
++      u32 drfl;
++      u32 drfh;
++      u32 rrfl;
++      u32 rrfh;
++      u32 lts;
++      u32 bci;
++      u32 bcf;
++      u32 bei;
++      u32 bef;
++};
++
+ /* class 5, command 0 */
+ struct tgs_gcl_conf {
+       u8      atc;    /* init gate value */
+       u8      res[7];
+-      struct {
+-              u8      res1[4];
+-              __le16  acl_len;
+-              u8      res2[2];
++      union {
++              struct {
++                      u8      res1[4];
++                      __le16  acl_len;
++                      u8      res2[2];
++              };
++              struct {
++                      u32 cctl;
++                      u32 ccth;
++              };
+       };
+ };
++#define ENETC_CBDR_SGL_IOMEN  BIT(0)
++#define ENETC_CBDR_SGL_IPVEN  BIT(3)
++#define ENETC_CBDR_SGL_GTST           BIT(4)
++#define ENETC_CBDR_SGL_IPV_MASK 0xe
++/* Stream Gate Control List Entry */
++struct sgce {
++      u32     interval;
++      u8      msdu[3];
++      u8      multi;
++};
++
+ /* gate control list entry */
+ struct gce {
+       __le32  period;
+@@ -656,13 +965,55 @@ struct tgs_gcl_data {
+       struct gce      entry[0];
+ };
++/* class 5, command 1 */
++struct tgs_gcl_query {
++              u8      res[12];
++              union {
++                      struct {
++                              __le16  acl_len; /* admin list length */
++                              __le16  ocl_len; /* operation list length */
++                      };
++                      struct {
++                              u16 admin_list_len;
++                              u16 oper_list_len;
++                      };
++              };
++
++};
++
++/* tgs_gcl_query command response data format */
++struct tgs_gcl_resp {
++      u32     abtl;   /* base time */
++      u32 abth;
++      u32     act;    /* cycle time */
++      u32     acte;   /* cycle time extend */
++      u32     cctl;   /* config change time */
++      u32 ccth;
++      u32 obtl;       /* operation base time */
++      u32 obth;
++      u32     oct;    /* operation cycle time */
++      u32     octe;   /* operation cycle time extend */
++      u32     ccel;   /* config change error */
++      u32 cceh;
++      /*struct gce    *gcl;*/
++};
++
+ struct enetc_cbd {
+       union{
++              struct sfi_conf sfi_conf;
++              struct sgi_table sgi_table;
++              struct sgi_query_stat_resp sgi_query_stat_resp;
++              struct fmi_conf fmi_conf;
+               struct {
+                       __le32  addr[2];
+                       union {
+                               __le32  opt[4];
+-                              struct tgs_gcl_conf     gcl_conf;
++                              struct tgs_gcl_conf             gcl_conf;
++                              struct tgs_gcl_query    gcl_query;
++                              struct streamid_conf            sid_set;
++                              struct streamid_stat_query      sid_stat;
++                              struct sgcl_conf                sgcl_conf;
++                              struct sgcl_query               sgcl_query;
+                       };
+               };      /* Long format */
+               __le32 data[6];
+@@ -677,11 +1028,88 @@ struct enetc_cbd {
+ #define ENETC_CLK  400000000ULL
++#define ENETC_PTCFPR(n)               (0x1910 + (n) * 4) /* n = [0 ..7] */
++#define ENETC_FPE             BIT(31)
++
++/* Port capability register 0 */
++#define ENETC_PCAPR0_PSFPM    BIT(10)
++#define ENETC_PCAPR0_PSFP     BIT(9)
++#define ENETC_PCAPR0_TSN      BIT(4)
++#define ENETC_PCAPR0_QBU      BIT(3)
++
+ /* port time gating control register */
+ #define ENETC_QBV_PTGCR_OFFSET                0x11a00
+ #define ENETC_QBV_TGE                 BIT(31)
+ #define ENETC_QBV_TGPE                        BIT(30)
++#define ENETC_QBV_TGDROP_DISABLE      BIT(29)
+ /* Port time gating capability register */
+ #define ENETC_QBV_PTGCAPR_OFFSET      0x11a08
+ #define ENETC_QBV_MAX_GCL_LEN_MASK    GENMASK(15, 0)
++
++/* Port time gating tick granularity register */
++#define ENETC_QBV_PTGTGR_OFFSET 0x11a0c
++#define ENETC_QBV_TICK_GRAN_MASK 0xffffffff
++
++/* Port time gating admin gate list status register */
++#define ENETC_QBV_PTGAGLSR_OFFSET 0x11a10
++
++#define ENETC_QBV_CFG_PEND_MASK 0x00000002
++
++/* Port time gating admin gate list length register */
++#define ENETC_QBV_PTGAGLLR_OFFSET 0x11a14
++#define ENETC_QBV_ADMIN_GATE_LIST_LENGTH_MASK 0xffff
++
++/* Port time gating operational gate list status register */
++#define ENETC_QBV_PTGOGLSR_OFFSET 0x11a18
++#define ENETC_QBV_HTA_POS_MASK 0xffff0000
++
++#define ENETC_QBV_CURR_POS_MASK 0x0000ffff
++
++/* Port time gating operational gate list length register */
++#define ENETC_QBV_PTGOGLLR_OFFSET 0x11a1c
++#define ENETC_QBV_OPER_GATE_LIST_LENGTH_MASK 0xffff
++
++/* Port time gating current time register */
++#define ENETC_QBV_PTGCTR_OFFSET 0x11a20
++#define ENETC_QBV_CURR_TIME_MASK 0xffffffffffffffff
++
++/* Port traffic class a time gating control register */
++#define ENETC_QBV_PTC0TGCR_OFFSET  0x11a40
++#define ENETC_QBV_PTC1TGCR_OFFSET  0x11a50
++#define ENETC_QBV_PTC2TGCR_OFFSET  0x11a60
++#define ENETC_QBV_PTC3TGCR_OFFSET  0x11a70
++#define ENETC_QBV_PTC4TGCR_OFFSET  0x11a80
++#define ENETC_QBV_PTC5TGCR_OFFSET  0x11a90
++#define ENETC_QBV_PTC6TGCR_OFFSET  0x11aa0
++#define ENETC_QBV_PTC7TGCR_OFFSET  0x11ab0
++
++/* Maximum Service Data Unit. */
++#define ENETC_PTC0MSDUR 0x12020
++#define ENETC_PTC1MSDUR 0x12024
++#define ENETC_PTC2MSDUR 0x12028
++#define ENETC_PTC3MSDUR 0x1202c
++#define ENETC_PTC4MSDUR 0x12030
++#define ENETC_PTC5MSDUR 0x12034
++#define ENETC_PTC6MSDUR 0x12038
++#define ENETC_PTC7MSDUR 0x1203c
++
++#define ENETC_QBV_MAXSDU_MASK 0xffff
++
++/* Port traffic class a time gating status register */
++#define ENETC_QBV_PTC0TGSR_OFFSET  0x11a44
++#define ENETC_QBV_HTA_STATE_MASK  0x10000
++#define ENETC_QBV_CURR_STATE_MASK 0x1
++
++/* Port traffic class a time gating transmission overrun counter register*/
++#define ENETC_QBV_PTC0TGTOCR_OFFSET 0x11a48
++#define ENETC_QBV_TX_OVERRUN_MASK 0xffffffffffffffff
++#define ENETC_TGLSTR 0xa200
++#define ENETC_TGS_MIN_DIS_MASK 0x80000000
++#define ENETC_MIN_LOOKAHEAD_MASK 0xffff
++
++#define ENETC_PPSFPMR 0x11b00
++#define ENETC_PPSFPMR_PSFPEN BIT(0)
++#define ENETC_PPSFPMR_VS BIT(1)
++#define ENETC_PPSFPMR_PVC BIT(2)
++#define ENETC_PPSFPMR_PVZC BIT(3)
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -525,12 +525,16 @@ static void enetc_configure_port_mac(str
+                     ENETC_PM0_TX_EN | ENETC_PM0_RX_EN);
+       /* set auto-speed for RGMII */
+       if (enetc_port_rd(hw, ENETC_PM0_IF_MODE) & ENETC_PMO_IFM_RG ||
+-          phy_mode == PHY_INTERFACE_MODE_RGMII)
++          phy_mode == PHY_INTERFACE_MODE_RGMII) {
+               enetc_port_wr(hw, ENETC_PM0_IF_MODE, ENETC_PM0_IFM_RGAUTO);
++              enetc_port_wr(hw, ENETC_PM1_IF_MODE, ENETC_PM0_IFM_RGAUTO);
++      }
+       if (phy_mode == PHY_INTERFACE_MODE_XGMII ||
+-          phy_mode == PHY_INTERFACE_MODE_USXGMII)
++          phy_mode == PHY_INTERFACE_MODE_USXGMII) {
+               enetc_port_wr(hw, ENETC_PM0_IF_MODE, ENETC_PM0_IFM_XGMII);
++              enetc_port_wr(hw, ENETC_PM1_IF_MODE, ENETC_PM0_IFM_XGMII);
++      }
+ }
+ static void enetc_configure_port_pmac(struct enetc_hw *hw)
+@@ -749,6 +753,9 @@ static void enetc_pf_netdev_setup(struct
+       if (si->hw_features & ENETC_SI_F_QBV)
+               priv->active_offloads |= ENETC_F_QBV;
++      if (enetc_tsn_is_enabled() && (si->hw_features & ENETC_SI_F_QBU))
++              priv->active_offloads |= ENETC_F_QBU;
++
+       /* pick up primary MAC address from SI */
+       enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr);
+ }
+@@ -942,6 +949,8 @@ static int enetc_pf_probe(struct pci_dev
+       netif_info(priv, probe, ndev, "%s v%s\n",
+                  enetc_drv_name, enetc_drv_ver);
++      enetc_tsn_pf_init(ndev, pdev);
++
+       return 0;
+ err_reg_netdev:
+@@ -973,6 +982,8 @@ static void enetc_pf_remove(struct pci_d
+       netif_info(priv, drv, si->ndev, "%s v%s remove\n",
+                  enetc_drv_name, enetc_drv_ver);
++      enetc_tsn_pf_deinit(si->ndev);
++
+       unregister_netdev(si->ndev);
+       enetc_mdio_remove(pf);
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/enetc/enetc_tsn.c
+@@ -0,0 +1,2049 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
++/* Copyright 2017-2019 NXP */
++
++#ifdef CONFIG_ENETC_TSN
++#include "enetc.h"
++
++#include <net/tsn.h>
++#include <linux/module.h>
++#include <linux/irqflags.h>
++#include <linux/preempt.h>
++
++static u32 get_ndev_speed(struct net_device *netdev);
++
++static int alloc_cbdr(struct enetc_si *si, struct enetc_cbd **curr_cbd)
++{
++      struct enetc_cbdr *ring = &si->cbd_ring;
++      int i;
++
++      i = ring->next_to_use;
++      *curr_cbd = ENETC_CBD(*ring, i);
++
++      memset(*curr_cbd, 0, sizeof(struct enetc_cbd));
++      return i;
++}
++
++/* Transmit the BD control ring by writing the pir register.
++ * Update the counters maintained by software.
++ */
++static int xmit_cbdr(struct enetc_si *si, int i)
++{
++      struct enetc_cbdr *ring = &si->cbd_ring;
++      struct enetc_cbd *dest_cbd;
++      int nc, timeout;
++
++      i = (i + 1) % ring->bd_count;
++
++      ring->next_to_use = i;
++      /* let H/W know BD ring has been updated */
++      enetc_wr_reg(ring->pir, i);
++
++      timeout = ENETC_CBDR_TIMEOUT;
++
++      do {
++              if (enetc_rd_reg(ring->cir) == i)
++                      break;
++              usleep_range(10, 20);
++              timeout -= 10;
++      } while (timeout);
++
++      if (!timeout)
++              return -EBUSY;
++
++      nc = ring->next_to_clean;
++
++      while (enetc_rd_reg(ring->cir) != nc) {
++              dest_cbd = ENETC_CBD(*ring, nc);
++              if (dest_cbd->status_flags & ENETC_CBD_STATUS_MASK)
++                      WARN_ON(1);
++
++              nc = (nc + 1) % ring->bd_count;
++      }
++
++      ring->next_to_clean = nc;
++
++      return 0;
++}
++
++static inline u64 get_current_time(struct enetc_si *si)
++{
++      u64 tmp = 0;
++
++      tmp = (u64)enetc_rd(&si->hw, ENETC_SICTR0);
++      return ((u64)enetc_rd(&si->hw, ENETC_SICTR1) << 32) + tmp;
++}
++
++/* Class 10: Flow Meter Instance Statistics Query Descriptor - Long Format */
++int enetc_qci_fmi_counters_get(struct net_device *ndev, u32 index,
++                             struct fmi_query_stat_resp *counters)
++{
++      struct enetc_cbd *cbdr;
++      struct fmi_query_stat_resp *fmi_data;
++      dma_addr_t dma;
++      u16 data_size, dma_size;
++      int curr_cbd;
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++
++      cbdr->index = cpu_to_le16((u16)index);
++      cbdr->cmd = 2;
++      cbdr->cls = BDCR_CMD_FLOW_METER;
++      cbdr->status_flags = 0;
++
++      data_size = sizeof(struct fmi_query_stat_resp);
++
++      fmi_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
++      if (!fmi_data)
++              return -ENOMEM;
++
++      dma_size = cpu_to_le16(data_size);
++      cbdr->length = dma_size;
++
++      dma = dma_map_single(&priv->si->pdev->dev, fmi_data,
++                           data_size, DMA_FROM_DEVICE);
++      if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
++              netdev_err(priv->si->ndev, "DMA mapping failed!\n");
++              kfree(fmi_data);
++              return -ENOMEM;
++      }
++      cbdr->addr[0] = lower_32_bits(dma);
++      cbdr->addr[1] = upper_32_bits(dma);
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      memcpy(counters, fmi_data, sizeof(struct fmi_query_stat_resp));
++
++      memset(cbdr, 0, sizeof(*cbdr));
++      kfree(fmi_data);
++      return 0;
++}
++
++u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
++{
++      return (enetc_rd(hw, ENETC_QBV_PTGCAPR_OFFSET)
++              & ENETC_QBV_MAX_GCL_LEN_MASK);
++}
++
++void enetc_pspeed_set(struct net_device *ndev)
++{
++      u32 speed, pspeed;
++      u32 difflag = 0;
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++
++      speed = get_ndev_speed(ndev);
++      pspeed = enetc_port_rd(&priv->si->hw, ENETC_PMR)
++              & ENETC_PMR_PSPEED_MASK;
++      switch (speed) {
++      case SPEED_1000:
++              if (pspeed != ENETC_PMR_PSPEED_1000M) {
++                      difflag = 1;
++                      pspeed = ENETC_PMR_PSPEED_1000M;
++              }
++              break;
++      case SPEED_2500:
++              if (pspeed != ENETC_PMR_PSPEED_2500M) {
++                      difflag = 1;
++                      pspeed = ENETC_PMR_PSPEED_2500M;
++              }
++
++              break;
++      case SPEED_100:
++              if (pspeed != ENETC_PMR_PSPEED_100M) {
++                      difflag = 1;
++                      pspeed = ENETC_PMR_PSPEED_100M;
++              }
++              break;
++      case SPEED_10:
++              if (pspeed != ENETC_PMR_PSPEED_10M) {
++                      difflag = 1;
++                      pspeed = ENETC_PMR_PSPEED_10M;
++              }
++              break;
++      default:
++              netdev_err(ndev, "not support speed\n");
++      }
++
++      if (difflag) {
++              enetc_port_wr(&priv->si->hw, ENETC_PMR,
++                            (enetc_port_rd(&priv->si->hw, ENETC_PMR)
++                            & (~ENETC_PMR_PSPEED_MASK))
++                            | pspeed);
++      }
++}
++
++/* CBD Class 5: Time Gated Scheduling Gate Control List configuration
++ * Descriptor - Long Format
++ */
++int enetc_qbv_set(struct net_device *ndev, struct tsn_qbv_conf *admin_conf)
++{
++      struct enetc_cbd *cbdr;
++      struct tgs_gcl_data *gcl_data;
++      struct tgs_gcl_conf *gcl_config;
++      struct gce *gce;
++      u16 gcl_len;
++      u16 data_size;
++      int i;
++      dma_addr_t dma;
++      int curr_cbd;
++      struct tsn_qbv_basic *admin_basic = &admin_conf->admin;
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      u32 temp;
++      u64 tempclock;
++      struct tsn_port *port;
++
++      port = tsn_get_port(ndev);
++      if (!port) {
++              netdev_err(priv->si->ndev, "TSN device not registered!\n");
++              return -ENODEV;
++      }
++
++      enetc_pspeed_set(ndev);
++
++      gcl_len = admin_basic->control_list_length;
++      if (gcl_len > enetc_get_max_gcl_len(&priv->si->hw))
++              return -EINVAL;
++
++      temp = enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET);
++      if (admin_conf->gate_enabled && !(temp & ENETC_QBV_TGE)) {
++              enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
++                       temp & (~ENETC_QBV_TGE));
++              usleep_range(10, 20);
++              enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
++                       temp | ENETC_QBV_TGE);
++      } else if (!admin_conf->gate_enabled) {
++              enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
++                       temp & (~ENETC_QBV_TGE));
++              memcpy(&port->nd.ntdata, admin_conf, sizeof(*admin_conf));
++              call_tsn_notifiers(TSN_QBV_CONFIGCHANGETIME_ARRIVE,
++                                 ndev, &port->nd);
++              return 0;
++      }
++
++      /* Set the maximum frame size for each traffic class index
++       * PTCaMSDUR[MAXSDU]. The maximum frame size cannot exceed
++       * 9,600 bytes (0x2580). Frames that exceed the limit are
++       * discarded.
++       */
++      if (admin_conf->maxsdu) {
++              enetc_wr(&priv->si->hw, ENETC_PTC0MSDUR, admin_conf->maxsdu);
++              enetc_wr(&priv->si->hw, ENETC_PTC1MSDUR, admin_conf->maxsdu);
++              enetc_wr(&priv->si->hw, ENETC_PTC2MSDUR, admin_conf->maxsdu);
++              enetc_wr(&priv->si->hw, ENETC_PTC3MSDUR, admin_conf->maxsdu);
++              enetc_wr(&priv->si->hw, ENETC_PTC4MSDUR, admin_conf->maxsdu);
++              enetc_wr(&priv->si->hw, ENETC_PTC5MSDUR, admin_conf->maxsdu);
++              enetc_wr(&priv->si->hw, ENETC_PTC6MSDUR, admin_conf->maxsdu);
++              enetc_wr(&priv->si->hw, ENETC_PTC7MSDUR, admin_conf->maxsdu);
++      }
++
++      /* Configure the (administrative) gate control list using the
++       * control BD descriptor.
++       */
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++
++      gcl_config = &cbdr->gcl_conf;
++
++      data_size = struct_size(gcl_data, entry, gcl_len);
++
++      gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
++      if (!gcl_data)
++              return -ENOMEM;
++
++      gce = &gcl_data->entry[0];
++
++      gcl_config->atc = admin_basic->gate_states;
++      gcl_config->acl_len = cpu_to_le16(gcl_len);
++
++      if (!admin_basic->base_time) {
++              gcl_data->btl =
++                      cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
++              gcl_data->bth =
++                      cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
++      } else {
++              gcl_data->btl =
++                      cpu_to_le32(lower_32_bits(admin_basic->base_time));
++              gcl_data->bth =
++                      cpu_to_le32(upper_32_bits(admin_basic->base_time));
++      }
++
++      gcl_data->ct = cpu_to_le32(admin_basic->cycle_time);
++      gcl_data->cte = cpu_to_le32(admin_basic->cycle_time_extension);
++
++      for (i = 0; i < gcl_len; i++) {
++              struct gce *temp_gce = gce + i;
++              struct tsn_qbv_entry *temp_entry;
++
++              temp_entry = admin_basic->control_list + i;
++
++              temp_gce->gate = temp_entry->gate_state;
++              temp_gce->period = cpu_to_le32(temp_entry->time_interval);
++      }
++
++      cbdr->length = cpu_to_le16(data_size);
++      cbdr->status_flags = 0;
++
++      dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
++                           data_size, DMA_TO_DEVICE);
++      if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
++              netdev_err(priv->si->ndev, "DMA mapping failed!\n");
++              kfree(gcl_data);
++              return -ENOMEM;
++      }
++
++      cbdr->addr[0] = lower_32_bits(dma);
++      cbdr->addr[1] = upper_32_bits(dma);
++      cbdr->cmd = 0;
++      cbdr->cls = BDCR_CMD_PORT_GCL;
++
++      /* Updated by ENETC on completion of the configuration
++       * command. A zero value indicates success.
++       */
++      cbdr->status_flags = 0;
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      memcpy(&port->nd.ntdata, admin_conf, sizeof(*admin_conf));
++
++      tempclock = ((u64)le32_to_cpu(gcl_config->ccth)) << 32;
++      port->nd.ntdata.qbv_notify.admin.base_time =
++              le32_to_cpu(gcl_config->cctl) + tempclock;
++
++      memset(cbdr, 0, sizeof(struct enetc_cbd));
++      dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE);
++      kfree(gcl_data);
++
++      call_tsn_notifiers(TSN_QBV_CONFIGCHANGETIME_ARRIVE,
++                         ndev, &port->nd);
++
++      return 0;
++}
++
++/* CBD Class 5: Time Gated Scheduling Gate Control List query
++ * Descriptor - Long Format
++ */
++int enetc_qbv_get(struct net_device *ndev, struct tsn_qbv_conf *admin_conf)
++{
++      struct enetc_cbd *cbdr;
++      struct tgs_gcl_resp *gcl_data;
++      struct tgs_gcl_query *gcl_query;
++      struct gce *gce;
++      struct tsn_qbv_basic *admin_basic = &admin_conf->admin;
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      dma_addr_t dma;
++      int curr_cbd;
++      u16 maxlen;
++      u16 data_size, dma_size;
++      u16 admin_len;
++      u16 oper_len;
++      u64 temp;
++      int i;
++
++      if (enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET) & ENETC_QBV_TGE) {
++              admin_conf->gate_enabled = true;
++      } else {
++              admin_conf->gate_enabled = false;
++              return 0;
++      }
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++
++      gcl_query =  &cbdr->gcl_query;
++
++      maxlen = enetc_get_max_gcl_len(&priv->si->hw);
++
++      data_size = sizeof(struct tgs_gcl_resp)
++                      + sizeof(struct gce) * 2 * maxlen;
++
++      gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
++      if (!gcl_data)
++              return -ENOMEM;
++
++      gce = (struct gce *)(gcl_data + 1);
++
++      gcl_query->acl_len = cpu_to_le16(maxlen);
++
++      dma_size = cpu_to_le16(data_size);
++      cbdr->length = dma_size;
++      cbdr->status_flags = 0;
++
++      dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
++                           data_size, DMA_FROM_DEVICE);
++      if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
++              netdev_err(priv->si->ndev, "DMA mapping failed!\n");
++              kfree(gcl_data);
++              return -ENOMEM;
++      }
++
++      cbdr->addr[0] = lower_32_bits(dma);
++      cbdr->addr[1] = upper_32_bits(dma);
++      cbdr->cmd = 1;
++      cbdr->cls = BDCR_CMD_PORT_GCL;
++      xmit_cbdr(priv->si, curr_cbd);
++      dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_FROM_DEVICE);
++
++      /* since cbdr already passed to free, below could be get wrong */
++      admin_len = le16_to_cpu(gcl_query->admin_list_len);
++      oper_len = le16_to_cpu(gcl_query->oper_list_len);
++
++      admin_basic->control_list_length = admin_len;
++
++      temp = ((u64)le32_to_cpu(gcl_data->abth)) << 32;
++      admin_basic->base_time = le32_to_cpu(gcl_data->abtl) + temp;
++
++      admin_basic->cycle_time = le32_to_cpu(gcl_data->act);
++      admin_basic->cycle_time_extension = le32_to_cpu(gcl_data->acte);
++
++      admin_basic->control_list = kcalloc(admin_len,
++                                          sizeof(admin_basic->control_list),
++                                          GFP_KERNEL);
++      if (!admin_basic->control_list) {
++              memset(cbdr, 0, sizeof(*cbdr));
++              kfree(gcl_data);
++              return -ENOMEM;
++      }
++
++      for (i = 0; i < admin_len; i++) {
++              struct gce *temp_gce = gce + i;
++              struct tsn_qbv_entry *temp_entry;
++
++              temp_entry = admin_basic->control_list + i;
++
++              temp_entry->gate_state = temp_gce->gate;
++              temp_entry->time_interval = le32_to_cpu(temp_gce->period);
++      }
++
++      /* Updated by ENETC on completion of the configuration
++       * command. A zero value indicates success.
++       */
++      admin_conf->config_change = true;
++
++      memset(cbdr, 0, sizeof(*cbdr));
++      kfree(gcl_data);
++
++      return 0;
++}
++
++int enetc_qbv_get_status(struct net_device *ndev,
++                       struct tsn_qbv_status *status)
++{
++      struct enetc_cbd *cbdr;
++      struct tgs_gcl_resp *gcl_data;
++      struct tgs_gcl_query *gcl_query;
++      struct gce *gce;
++      struct tsn_qbv_basic *oper_basic;
++      struct enetc_ndev_priv *priv;
++      dma_addr_t dma;
++      int curr_cbd;
++      u16 maxlen;
++      u16 data_size, dma_size;
++      u16 admin_len;
++      u16 oper_len;
++      u64 temp;
++      int i;
++
++      if (!ndev)
++              return -EINVAL;
++
++      if (!status)
++              return -EINVAL;
++
++      oper_basic = &status->oper;
++      priv = netdev_priv(ndev);
++
++      if (!(enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET) & ENETC_QBV_TGE))
++              return -EINVAL;
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++
++      gcl_query = &cbdr->gcl_query;
++
++      maxlen = enetc_get_max_gcl_len(&priv->si->hw);
++
++      data_size = sizeof(struct tgs_gcl_resp) +
++                      sizeof(struct gce) * 2 * maxlen;
++
++      gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
++      if (!gcl_data)
++              return -ENOMEM;
++
++      gce = (struct gce *)(gcl_data + 1);
++
++      gcl_query->acl_len = cpu_to_le16(maxlen);
++      gcl_query->ocl_len = cpu_to_le16(maxlen);
++
++      dma_size = cpu_to_le16(data_size);
++      cbdr->length = dma_size;
++      cbdr->status_flags = 0; /* long format command no ie */
++
++      dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
++                           data_size, DMA_FROM_DEVICE);
++      if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
++              netdev_err(priv->si->ndev, "DMA mapping failed!\n");
++              kfree(gcl_data);
++              return -ENOMEM;
++      }
++
++      cbdr->addr[0] = lower_32_bits(dma);
++      cbdr->addr[1] = upper_32_bits(dma);
++      cbdr->cmd = 1;
++      cbdr->cls = BDCR_CMD_PORT_GCL;
++      xmit_cbdr(priv->si, curr_cbd);
++      dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_FROM_DEVICE);
++
++      /* since cbdr already passed to free, below could be get wrong */
++      admin_len = le16_to_cpu(gcl_query->admin_list_len);
++      oper_len = le16_to_cpu(gcl_query->oper_list_len);
++
++      if (enetc_rd(&priv->si->hw, ENETC_QBV_PTGAGLSR_OFFSET) &
++                                              ENETC_QBV_CFG_PEND_MASK) {
++              status->config_pending = true;
++              goto exit;
++      }
++
++      /* The Oper and Admin timing fields exist in the response buffer even
++       * if no valid corresponding lists exists. These fields are considered
++       * invalid if the corresponding list does not exist.
++       */
++      status->config_pending = false;
++      temp = ((u64)le32_to_cpu(gcl_data->ccth)) << 32;
++      status->config_change_time = le32_to_cpu(gcl_data->cctl) + temp;
++
++      temp = ((u64)le32_to_cpu(gcl_data->cceh)) << 32;
++      status->config_change_error = le32_to_cpu(gcl_data->ccel) + temp;
++
++      /* changed to SITGTGR */
++      status->tick_granularity = enetc_rd(&priv->si->hw, ENETC_SITGTGR);
++
++      /* current time */
++      status->current_time = get_current_time(priv->si);
++
++      status->supported_list_max = maxlen;
++
++      /* status->oper.gate_states , no init oper/admin gate state */
++      status->oper.control_list_length = oper_len;
++      temp = ((u64)le32_to_cpu(gcl_data->obth)) << 32;
++      status->oper.base_time = le32_to_cpu(gcl_data->obtl) + temp;
++      status->oper.cycle_time = le32_to_cpu(gcl_data->oct);
++      status->oper.cycle_time_extension = le32_to_cpu(gcl_data->octe);
++
++      oper_basic->control_list =
++              kcalloc(oper_len, sizeof(oper_basic->control_list), GFP_KERNEL);
++      if (!oper_basic->control_list) {
++              memset(cbdr, 0, sizeof(*cbdr));
++              kfree(gcl_data);
++              return -ENOMEM;
++      }
++
++      for (i = 0; i < oper_len; i++) {
++              struct gce *temp_gce = gce + maxlen + i;
++              struct tsn_qbv_entry *temp_entry = oper_basic->control_list + i;
++
++              temp_entry->gate_state = temp_gce->gate;
++              temp_entry->time_interval = le32_to_cpu(temp_gce->period);
++      }
++
++exit:
++      memset(cbdr, 0, sizeof(*cbdr));
++      kfree(gcl_data);
++      return 0;
++}
++
++/* CBD Class 7: Stream Identity Entry Set Descriptor - Long Format */
++int enetc_cb_streamid_set(struct net_device *ndev, u32 index,
++                        bool en, struct tsn_cb_streamid *streamid)
++{
++      struct enetc_cbd *cbdr;
++      void *si_data;
++      struct null_streamid_data *si_data1;
++      struct smac_streamid_data *si_data2;
++      struct streamid_conf *si_conf;
++      struct enetc_ndev_priv *priv;
++      dma_addr_t dma;
++      u16 data_size, dma_size;
++      int curr_cbd;
++
++      if (!ndev)
++              return -EINVAL;
++
++      priv = netdev_priv(ndev);
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++
++      cbdr->index = cpu_to_le16((u16)index);
++      cbdr->cmd = 0;
++      cbdr->cls = BDCR_CMD_STREAM_IDENTIFY;
++      cbdr->status_flags = 0;
++
++      data_size = sizeof(struct null_streamid_data);
++      si_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
++      cbdr->length = cpu_to_le16(data_size);
++
++      dma = dma_map_single(&priv->si->pdev->dev, si_data,
++                           data_size, DMA_FROM_DEVICE);
++      if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
++              netdev_err(priv->si->ndev, "DMA mapping failed!\n");
++              kfree(si_data);
++              return -ENOMEM;
++      }
++
++      cbdr->addr[0] = lower_32_bits(dma);
++      cbdr->addr[1] = upper_32_bits(dma);
++      si_data1 = (struct null_streamid_data *)si_data;
++      si_data1->dmac[0] = 0xFF;
++      si_data1->dmac[1] = 0xFF;
++      si_data1->dmac[2] = 0xFF;
++      si_data1->dmac[3] = 0xFF;
++      si_data1->dmac[4] = 0xFF;
++      si_data1->dmac[5] = 0xFF;
++      si_data1->vid_vidm_tg =
++              cpu_to_le16(ENETC_CBDR_SID_VID_MASK
++                          + ((0x3 << 14) | ENETC_CBDR_SID_VIDM));
++
++      si_conf = &cbdr->sid_set;
++      /* Only one port supported for one entry, set itself */
++      si_conf->iports = 1 << (priv->si->pdev->devfn & 0x7);
++      si_conf->id_type = 1;
++      si_conf->oui[2] = 0x0;
++      si_conf->oui[1] = 0x80;
++      si_conf->oui[0] = 0xC2;
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      memset(cbdr, 0, sizeof(*cbdr));
++      kfree(si_data);
++
++      if (!en)
++              return 0;
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++
++      cbdr->index = cpu_to_le16((u16)index);
++      cbdr->cmd = 0;
++      cbdr->cls = BDCR_CMD_STREAM_IDENTIFY;
++      cbdr->status_flags = 0;
++
++      si_conf = &cbdr->sid_set;
++      si_conf->en = 0x80;
++      si_conf->stream_handle = cpu_to_le32(streamid->handle);
++      si_conf->iports = 1 << (priv->si->pdev->devfn & 0x7);
++      si_conf->id_type = streamid->type;
++      si_conf->oui[2] = 0x0;
++      si_conf->oui[1] = 0x80;
++      si_conf->oui[0] = 0xC2;
++
++      if (si_conf->id_type == 1) {
++              data_size = sizeof(struct null_streamid_data);
++              si_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
++      } else if (si_conf->id_type == 2) {
++              data_size = sizeof(struct smac_streamid_data);
++              si_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
++      } else {
++              return -EINVAL;
++      }
++
++      if (!si_data)
++              return -ENOMEM;
++
++      dma_size = cpu_to_le16(data_size);
++      cbdr->length = dma_size;
++      cbdr->status_flags = 0;
++
++      dma = dma_map_single(&priv->si->pdev->dev, si_data,
++                           data_size, DMA_FROM_DEVICE);
++      if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
++              netdev_err(priv->si->ndev, "DMA mapping failed!\n");
++              memset(cbdr, 0, sizeof(*cbdr));
++              kfree(si_data);
++              return -ENOMEM;
++      }
++      cbdr->addr[0] = lower_32_bits(dma);
++      cbdr->addr[1] = upper_32_bits(dma);
++
++      /* VIDM default to be 1.
++       * VID Match. If set (b1) then the VID must match, otherwise
++       * any VID is considered a match. VIDM setting is only used
++       * when TG is set to b01.
++       */
++      if (si_conf->id_type == 1) {
++              si_data1 = (struct null_streamid_data *)si_data;
++              si_data1->dmac[0] = streamid->para.nid.dmac & 0xFF;
++              si_data1->dmac[1] = (streamid->para.nid.dmac >> 8) & 0xFF;
++              si_data1->dmac[2] = (streamid->para.nid.dmac >> 16) & 0xFF;
++              si_data1->dmac[3] = (streamid->para.nid.dmac >> 24) & 0xFF;
++              si_data1->dmac[4] = (streamid->para.nid.dmac >> 32) & 0xFF;
++              si_data1->dmac[5] = (streamid->para.nid.dmac >> 40) & 0xFF;
++              si_data1->vid_vidm_tg =
++              cpu_to_le16((streamid->para.nid.vid & ENETC_CBDR_SID_VID_MASK) +
++                          ((((u16)(streamid->para.nid.tagged) & 0x3) << 14)
++                           | ENETC_CBDR_SID_VIDM));
++      } else if (si_conf->id_type == 2) {
++              si_data2 = (struct smac_streamid_data *)si_data;
++              si_data2->smac[0] = streamid->para.sid.smac & 0xFF;
++              si_data2->smac[1] = (streamid->para.sid.smac >> 8) & 0xFF;
++              si_data2->smac[2] = (streamid->para.sid.smac >> 16) & 0xFF;
++              si_data2->smac[3] = (streamid->para.sid.smac >> 24) & 0xFF;
++              si_data2->smac[4] = (streamid->para.sid.smac >> 32) & 0xFF;
++              si_data2->smac[5] = (streamid->para.sid.smac >> 40) & 0xFF;
++              si_data2->vid_vidm_tg =
++              cpu_to_le16((streamid->para.sid.vid & ENETC_CBDR_SID_VID_MASK) +
++                          ((((u16)(streamid->para.sid.tagged) & 0x3) << 14)
++                           | ENETC_CBDR_SID_VIDM));
++      }
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      memset(cbdr, 0, sizeof(*cbdr));
++      kfree(si_data);
++
++      return 0;
++}
++
++/* CBD Class 7: Stream Identity Entry Query Descriptor - Long Format */
++int enetc_cb_streamid_get(struct net_device *ndev, u32 index,
++                        struct tsn_cb_streamid *streamid)
++{
++      struct enetc_cbd *cbdr;
++      struct streamid_query_resp *si_data;
++      struct enetc_ndev_priv *priv;
++      dma_addr_t dma;
++      u16 data_size, dma_size;
++      int curr_cbd;
++      int valid;
++
++      if (!ndev)
++              return -EINVAL;
++
++      priv = netdev_priv(ndev);
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++
++      cbdr->index = cpu_to_le32(index);
++      cbdr->cmd = 1;
++      cbdr->cls = BDCR_CMD_STREAM_IDENTIFY;
++      cbdr->status_flags = 0;
++
++      data_size = sizeof(struct streamid_query_resp);
++      si_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
++      if (!si_data)
++              return -ENOMEM;
++
++      dma_size = cpu_to_le16(data_size);
++      cbdr->length = dma_size;
++      cbdr->status_flags = 0; /* long format command no ie */
++
++      dma = dma_map_single(&priv->si->pdev->dev, si_data,
++                           data_size, DMA_FROM_DEVICE);
++      if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
++              netdev_err(priv->si->ndev, "DMA mapping failed!\n");
++              kfree(si_data);
++              return -ENOMEM;
++      }
++      cbdr->addr[0] = lower_32_bits(dma);
++      cbdr->addr[1] = upper_32_bits(dma);
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      streamid->type = si_data->id_type;
++
++      if (streamid->type == 1) {
++              streamid->para.nid.dmac = si_data->mac[0]
++                      + ((u64)si_data->mac[1] << 8)
++                      + ((u64)si_data->mac[2] << 16)
++                      + ((u64)si_data->mac[3] << 24)
++                      + ((u64)si_data->mac[4] << 32)
++                      + ((u64)si_data->mac[5] << 40);
++              /* VID Match. If set (b1) then the VID must match, otherwise
++               * any VID is considered a match.
++               */
++              streamid->para.nid.vid =
++                              le16_to_cpu(si_data->vid_vidm_tg
++                                          & ENETC_CBDR_SID_VID_MASK);
++              streamid->para.nid.tagged =
++                              le16_to_cpu(si_data->vid_vidm_tg >> 14 & 0x3);
++      } else if (streamid->type == 2) {
++              streamid->para.sid.smac = si_data->mac[0]
++                      + ((u64)si_data->mac[1] << 8)
++                      + ((u64)si_data->mac[2] << 16)
++                      + ((u64)si_data->mac[3] << 24)
++                      + ((u64)si_data->mac[4] << 32)
++                      + ((u64)si_data->mac[5] << 40);
++              /* VID Match. If set (b1) then the VID must match, otherwise
++               * any VID is considered a match.
++               */
++              streamid->para.sid.vid =
++                              le16_to_cpu(si_data->vid_vidm_tg
++                                          & ENETC_CBDR_SID_VID_MASK);
++              streamid->para.sid.tagged =
++                              le16_to_cpu(si_data->vid_vidm_tg >> 14 & 0x3);
++      }
++
++      streamid->handle = le32_to_cpu(si_data->stream_handle);
++      streamid->ifac_iport = le32_to_cpu(si_data->input_ports);
++      valid = si_data->en ? 1 : 0;
++
++      memset(cbdr, 0, sizeof(*cbdr));
++      kfree(si_data);
++
++      return valid;
++}
++
++/*  CBD Class 7: Stream Identity Statistics Query Descriptor - Long Format */
++int enetc_cb_streamid_counters_get(struct net_device *ndev, u32 index,
++                                 struct tsn_cb_streamid_counters *counters)
++{
++      return 0;
++}
++
++void enetc_qci_enable(struct enetc_hw *hw)
++{
++      enetc_wr(hw, ENETC_PPSFPMR, enetc_rd(hw, ENETC_PPSFPMR)
++               | ENETC_PPSFPMR_PSFPEN | ENETC_PPSFPMR_VS
++               | ENETC_PPSFPMR_PVC | ENETC_PPSFPMR_PVZC);
++}
++
++void enetc_qci_disable(struct enetc_hw *hw)
++{
++      enetc_wr(hw, ENETC_PPSFPMR, enetc_rd(hw, ENETC_PPSFPMR)
++               & ~ENETC_PPSFPMR_PSFPEN & ~ENETC_PPSFPMR_VS
++               & ~ENETC_PPSFPMR_PVC & ~ENETC_PPSFPMR_PVZC);
++}
++
++/* CBD Class 8: Stream Filter Instance Set Descriptor - Short Format */
++int enetc_qci_sfi_set(struct net_device *ndev, u32 index, bool en,
++                    struct tsn_qci_psfp_sfi_conf *tsn_qci_sfi)
++{
++      struct enetc_cbd *cbdr;
++      struct sfi_conf *sfi_config;
++
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      int curr_cbd;
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++
++      cbdr->index = cpu_to_le16(index);
++      cbdr->cmd = 0;
++      cbdr->cls = BDCR_CMD_STREAM_FILTER;
++      cbdr->status_flags = 0x80;
++      cbdr->length = cpu_to_le16(1);
++
++      sfi_config = &cbdr->sfi_conf;
++      if (en)
++              sfi_config->en = 0x80;
++
++      if (tsn_qci_sfi->stream_handle_spec >= 0) {
++              sfi_config->stream_handle =
++                      cpu_to_le32(tsn_qci_sfi->stream_handle_spec);
++              sfi_config->sthm |= 0x80;
++      }
++
++      sfi_config->sg_inst_table_index =
++              cpu_to_le16(tsn_qci_sfi->stream_gate_instance_id);
++      sfi_config->input_ports = 1 << (priv->si->pdev->devfn & 0x7);
++
++      /* The priority value which may be matched against the
++       * frame’s priority value to determine a match for this entry.
++       */
++      if (tsn_qci_sfi->priority_spec >= 0)
++              sfi_config->multi |= (tsn_qci_sfi->priority_spec & 0x7) | 0x8;
++
++      /* Filter Type. Identifies the contents of the MSDU/FM_INST_INDEX
++       * field as being either an MSDU value or an index into the Flow
++       * Meter Instance table.
++       */
++      if (tsn_qci_sfi->stream_filter.maximum_sdu_size != 0) {
++              sfi_config->msdu =
++              cpu_to_le16(tsn_qci_sfi->stream_filter.maximum_sdu_size);
++              sfi_config->multi |= 0x40;
++      }
++
++      if (tsn_qci_sfi->stream_filter.flow_meter_instance_id >= 0) {
++              sfi_config->fm_inst_table_index =
++              cpu_to_le16(tsn_qci_sfi->stream_filter.flow_meter_instance_id);
++              sfi_config->multi |= 0x80;
++      }
++
++      /* Stream blocked due to oversized frame enable. TRUE or FALSE */
++      if (tsn_qci_sfi->block_oversize_enable)
++              sfi_config->multi |= 0x20;
++
++      /* Stream blocked due to oversized frame. TRUE or FALSE */
++      if (tsn_qci_sfi->block_oversize)
++              sfi_config->multi |= 0x10;
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      memset(cbdr, 0, sizeof(*cbdr));
++      return 0;
++}
++
++/* CBD Class 8: Stream Filter Instance Query Descriptor - Short Format */
++int enetc_qci_sfi_get(struct net_device *ndev, u32 index,
++                    struct tsn_qci_psfp_sfi_conf *tsn_qci_sfi)
++{
++      struct enetc_cbd *cbdr;
++      struct sfi_conf *sfi_config;
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      int curr_cbd;
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++
++      cbdr->index = cpu_to_le16(index);
++      cbdr->cmd = 1;
++      cbdr->cls = BDCR_CMD_STREAM_FILTER;
++      cbdr->status_flags = 0x80;
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      sfi_config = &cbdr->sfi_conf;
++      if (sfi_config->sthm & 0x80)
++              tsn_qci_sfi->stream_handle_spec =
++                      le32_to_cpu(sfi_config->stream_handle);
++      else
++              tsn_qci_sfi->stream_handle_spec = -1;
++
++      tsn_qci_sfi->stream_gate_instance_id =
++              le16_to_cpu(sfi_config->sg_inst_table_index);
++
++      if (sfi_config->multi & 0x8)
++              tsn_qci_sfi->priority_spec =
++                      le16_to_cpu(sfi_config->multi & 0x7);
++      else
++              tsn_qci_sfi->priority_spec = -1;
++
++      /* Filter Type. Identifies the contents of the MSDU/FM_INST_INDEX
++       * field as being either an MSDU value or an index into the Flow
++       * Meter Instance table.
++       */
++      if (sfi_config->multi & 0x80)
++              tsn_qci_sfi->stream_filter.flow_meter_instance_id =
++                      le16_to_cpu(sfi_config->fm_inst_table_index);
++      else
++              tsn_qci_sfi->stream_filter.flow_meter_instance_id = -1;
++
++      if (sfi_config->multi & 0x40)
++              tsn_qci_sfi->stream_filter.maximum_sdu_size =
++                      le16_to_cpu(sfi_config->msdu);
++
++      /* Stream blocked due to oversized frame enable. TRUE or FALSE */
++      if (sfi_config->multi & 0x20)
++              tsn_qci_sfi->block_oversize_enable = true;
++      /* Stream blocked due to oversized frame. TRUE or FALSE */
++      if (sfi_config->multi & 0x10)
++              tsn_qci_sfi->block_oversize = true;
++
++      if (sfi_config->en & 0x80) {
++              memset(cbdr, 0, sizeof(*cbdr));
++              return 1;
++      }
++
++      memset(cbdr, 0, sizeof(*cbdr));
++      return 0;
++}
++
++/* CBD Class 8: Stream Filter Instance Query Statistics
++ * Descriptor - Long Format
++ */
++int enetc_qci_sfi_counters_get(struct net_device *ndev, u32 index,
++                             struct tsn_qci_psfp_sfi_counters *counters)
++{
++      struct enetc_cbd *cbdr;
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      int curr_cbd;
++      struct sfi_counter_data *sfi_counter_data;
++      dma_addr_t dma;
++      u16 data_size, dma_size;
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++
++      cbdr->index = cpu_to_le16((u16)index);
++      cbdr->cmd = 2;
++      cbdr->cls = BDCR_CMD_STREAM_FILTER;
++      cbdr->status_flags = 0;
++
++      data_size = sizeof(struct sfi_counter_data);
++      sfi_counter_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
++      if (!sfi_counter_data)
++              return -ENOMEM;
++
++      dma = dma_map_single(&priv->si->pdev->dev, sfi_counter_data,
++                           data_size, DMA_FROM_DEVICE);
++      if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
++              netdev_err(priv->si->ndev, "DMA mapping failed!\n");
++              kfree(sfi_counter_data);
++              return -ENOMEM;
++      }
++      cbdr->addr[0] = lower_32_bits(dma);
++      cbdr->addr[1] = upper_32_bits(dma);
++
++      dma_size = cpu_to_le16(data_size);
++      cbdr->length = dma_size;
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      counters->matching_frames_count =
++                      ((u64)le32_to_cpu(sfi_counter_data->matchh) << 32)
++                      + sfi_counter_data->matchl;
++
++      counters->not_passing_sdu_count =
++                      ((u64)le32_to_cpu(sfi_counter_data->msdu_droph) << 32)
++                      + sfi_counter_data->msdu_dropl;
++
++      counters->passing_sdu_count = counters->matching_frames_count
++                              - counters->not_passing_sdu_count;
++
++      counters->not_passing_frames_count =
++              ((u64)le32_to_cpu(sfi_counter_data->stream_gate_droph) << 32)
++              + le32_to_cpu(sfi_counter_data->stream_gate_dropl);
++
++      counters->passing_frames_count = counters->matching_frames_count
++                              - counters->not_passing_sdu_count
++                              - counters->not_passing_frames_count;
++
++      counters->red_frames_count =
++              ((u64)le32_to_cpu(sfi_counter_data->flow_meter_droph) << 32)
++              + le32_to_cpu(sfi_counter_data->flow_meter_dropl);
++
++      memset(cbdr, 0, sizeof(*cbdr));
++      return 0;
++}
++
++/* CBD Class 9: Stream Gate Instance Table Entry Set
++ * Descriptor - Short Format
++ */
++int enetc_qci_sgi_set(struct net_device *ndev, u32 index,
++                    struct tsn_qci_psfp_sgi_conf *tsn_qci_sgi)
++{
++      struct enetc_cbd *cbdr, *cbdr_sgcl;
++      struct sgi_table *sgi_config;
++      struct sgcl_conf *sgcl_config;
++      struct sgcl_data *sgcl_data;
++      struct sgce *sgce;
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++
++      dma_addr_t dma;
++      u16 data_size, dma_size;
++      int curr_cbd, i;
++
++      /* disable first */
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++      memset(cbdr, 0, sizeof(*cbdr));
++
++      cbdr->index = cpu_to_le16(index);
++      cbdr->cmd = 0;
++      cbdr->cls = BDCR_CMD_STREAM_GCL;
++      cbdr->status_flags = 0x80;
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      if (!tsn_qci_sgi->gate_enabled) {
++              memset(cbdr, 0, sizeof(*cbdr));
++              return 0;
++      }
++
++      /* Re-enable */
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++      memset(cbdr, 0, sizeof(*cbdr));
++
++      cbdr->index = cpu_to_le16(index);
++      cbdr->cmd = 0;
++      cbdr->cls = BDCR_CMD_STREAM_GCL;
++      cbdr->status_flags = 0x80;
++
++      sgi_config = &cbdr->sgi_table;
++
++      sgi_config->ocgtst = tsn_qci_sgi->admin.control_list_length ?
++                      0x80 : (tsn_qci_sgi->admin.gate_states ? 0x80 : 0x0);
++
++      sgi_config->oipv =
++              tsn_qci_sgi->admin.control_list_length ?
++              0x0 : ((tsn_qci_sgi->admin.init_ipv < 0) ?
++                     0x0 : ((tsn_qci_sgi->admin.init_ipv & 0x7) | 0x8));
++
++      sgi_config->en = 0x80;
++
++      if (tsn_qci_sgi->block_invalid_rx_enable)
++              sgi_config->gset |= 0x80;
++      if (tsn_qci_sgi->block_invalid_rx)
++              sgi_config->gset |= 0x40;
++      if (tsn_qci_sgi->block_octets_exceeded)
++              sgi_config->gset |= 0x10;
++      if (tsn_qci_sgi->block_octets_exceeded_enable)
++              sgi_config->gset |= 0x20;
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      if (tsn_qci_sgi->admin.control_list_length == 0)
++              goto exit;
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr_sgcl);
++      memset(cbdr, 0, sizeof(*cbdr));
++
++      cbdr_sgcl->index = cpu_to_le16(index);
++      cbdr_sgcl->cmd = 1;
++      cbdr_sgcl->cls = BDCR_CMD_STREAM_GCL;
++      cbdr_sgcl->status_flags = 0;
++
++      sgcl_config = &cbdr_sgcl->sgcl_conf;
++
++      /* tsn_qci_sgi->admin.control_list_length is not zero now */
++      if (tsn_qci_sgi->admin.control_list_length > 4)
++              return -EINVAL;
++
++      sgcl_config->acl_len =
++              (tsn_qci_sgi->admin.control_list_length - 1) & 0x3;
++
++      data_size = sizeof(struct sgcl_data) +
++              (sgcl_config->acl_len + 1) * sizeof(struct sgce);
++
++      sgcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
++      if (!sgcl_data)
++              return -ENOMEM;
++
++      dma_size = cpu_to_le16(data_size);
++      cbdr_sgcl->length = dma_size;
++
++      dma = dma_map_single(&priv->si->pdev->dev,
++                           sgcl_data, data_size,
++                           DMA_FROM_DEVICE);
++      if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
++              netdev_err(priv->si->ndev, "DMA mapping failed!\n");
++              memset(cbdr, 0, sizeof(*cbdr));
++              memset(cbdr_sgcl, 0, sizeof(*cbdr_sgcl));
++              kfree(sgcl_data);
++              return -ENOMEM;
++      }
++      cbdr_sgcl->addr[0] = lower_32_bits(dma);
++      cbdr_sgcl->addr[1] = upper_32_bits(dma);
++
++      sgce = (struct sgce *)(sgcl_data + 1);
++
++      if (tsn_qci_sgi->admin.gate_states)
++              sgcl_config->agtst = 0x80;
++
++      sgcl_data->ct = cpu_to_le32(tsn_qci_sgi->admin.cycle_time);
++      sgcl_data->cte = cpu_to_le32(tsn_qci_sgi->admin.cycle_time_extension);
++
++      if (tsn_qci_sgi->admin.init_ipv >= 0)
++              sgcl_config->aipv = (tsn_qci_sgi->admin.init_ipv & 0x7) | 0x8;
++
++      for (i = 0; i < tsn_qci_sgi->admin.control_list_length; i++) {
++              struct tsn_qci_psfp_gcl *temp_sgcl = tsn_qci_sgi->admin.gcl + i;
++              struct sgce *temp_entry = (struct sgce *)(sgce + i);
++
++              if (temp_sgcl->gate_state)
++                      temp_entry->multi |= 0x10;
++
++              if (temp_sgcl->ipv >= 0)
++                      temp_entry->multi |= ((temp_sgcl->ipv & 0x7) << 5)
++                                              | 0x08;
++
++              if (temp_sgcl->octet_max)
++                      temp_entry->multi |= 0x01;
++
++              temp_entry->interval = cpu_to_le32(temp_sgcl->time_interval);
++              temp_entry->msdu[0] = temp_sgcl->octet_max & 0xFF;
++              temp_entry->msdu[1] = (temp_sgcl->octet_max >> 8) & 0xFF;
++              temp_entry->msdu[2] = (temp_sgcl->octet_max >> 16) & 0xFF;
++      }
++
++      if (!tsn_qci_sgi->admin.base_time) {
++              sgcl_data->btl =
++                      cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
++              sgcl_data->bth =
++                      cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
++      } else {
++              u32 tempu, templ;
++
++              tempu = upper_32_bits(tsn_qci_sgi->admin.base_time);
++              templ = lower_32_bits(tsn_qci_sgi->admin.base_time);
++              sgcl_data->bth = cpu_to_le32(tempu);
++              sgcl_data->btl = cpu_to_le32(templ);
++      }
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      memset(cbdr_sgcl, 0, sizeof(*cbdr_sgcl));
++      kfree(sgcl_data);
++
++exit:
++      memset(cbdr, 0, sizeof(*cbdr));
++      return 0;
++}
++
++/* CBD Class 9: Stream Gate Instance Table Entry Query
++ * Descriptor - Short Format
++ */
++int enetc_qci_sgi_get(struct net_device *ndev, u32 index,
++                    struct tsn_qci_psfp_sgi_conf *tsn_qci_sgi)
++{
++      struct enetc_cbd *cbdr, *cbdr_sgcl;
++      struct sgi_table *sgi_config;
++      struct sgcl_query *sgcl_query;
++      struct sgcl_query_resp *sgcl_data;
++      struct sgce *sgce;
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      dma_addr_t dma;
++      u16 data_size, dma_size, gcl_data_stat = 0;
++      u8 admin_len = 0;
++      int curr_cbd, i;
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++
++      cbdr->index = cpu_to_le16(index);
++      cbdr->cmd = 2;
++      cbdr->cls = BDCR_CMD_STREAM_GCL;
++      cbdr->status_flags = 0x80;
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      sgi_config = &cbdr->sgi_table;
++
++      tsn_qci_sgi->admin.gate_states = (sgi_config->ocgtst & 0x80) ?
++                                              true : false;
++      if (sgi_config->oipv & 0x08)
++              tsn_qci_sgi->admin.init_ipv = sgi_config->oipv & 0x7;
++      else
++              tsn_qci_sgi->admin.init_ipv = -1;
++
++      if (sgi_config->en & 0x80)
++              tsn_qci_sgi->gate_enabled = true;
++      if (sgi_config->gset & 0x80)
++              tsn_qci_sgi->block_invalid_rx_enable = true;
++      if (sgi_config->gset & 0x40)
++              tsn_qci_sgi->block_invalid_rx = true;
++      if (sgi_config->gset & 0x20)
++              tsn_qci_sgi->block_octets_exceeded_enable = true;
++      if (sgi_config->gset & 0x10)
++              tsn_qci_sgi->block_octets_exceeded = true;
++
++      /* Check gate list length is zero? */
++      if (!(sgi_config->oacl_len & 0x30)) {
++              tsn_qci_sgi->admin.control_list_length = 0;
++              goto exit;
++      }
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr_sgcl);
++
++      cbdr_sgcl->index = cpu_to_le16(index);
++      cbdr_sgcl->cmd = 3;
++      cbdr_sgcl->cls = BDCR_CMD_STREAM_GCL;
++      cbdr_sgcl->status_flags = 0;
++
++      data_size = sizeof(struct sgcl_query_resp) + 4 * sizeof(struct sgce);
++
++      sgcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
++      if (!sgcl_data)
++              return -ENOMEM;
++
++      dma_size = cpu_to_le16(data_size);
++      cbdr_sgcl->length = dma_size;
++      cbdr_sgcl->status_flags = 0;
++
++      sgcl_query = &cbdr_sgcl->sgcl_query;
++
++      sgcl_query->oacl_len = 0x10;
++
++      dma = dma_map_single(&priv->si->pdev->dev, sgcl_data,
++                           data_size, DMA_FROM_DEVICE);
++      if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
++              netdev_err(priv->si->ndev, "DMA mapping failed!\n");
++              memset(cbdr, 0, sizeof(*cbdr));
++              memset(cbdr_sgcl, 0, sizeof(*cbdr_sgcl));
++              kfree(sgcl_data);
++              return -ENOMEM;
++      }
++      cbdr_sgcl->addr[0] = lower_32_bits(dma);
++      cbdr_sgcl->addr[1] = upper_32_bits(dma);
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      sgce = (struct sgce *)(sgcl_data + 1);
++
++      gcl_data_stat = le16_to_cpu(sgcl_data->stat);
++      if (gcl_data_stat & 0x10)
++              tsn_qci_sgi->admin.gate_states = true;
++
++      if (gcl_data_stat & 0x80)
++              tsn_qci_sgi->admin.init_ipv = gcl_data_stat & 0x7;
++      else
++              tsn_qci_sgi->admin.init_ipv = -1;
++
++      /* admin_len can also get from gcl_data_stat bit 5,6
++       * OR sgi_config->oacl_len
++       */
++      admin_len = (sgcl_query->oacl_len & 0x3) + 1;
++      tsn_qci_sgi->admin.control_list_length = admin_len;
++      tsn_qci_sgi->admin.cycle_time = le32_to_cpu(sgcl_data->act);
++      tsn_qci_sgi->admin.cycle_time_extension = le32_to_cpu(sgcl_data->acte);
++      tsn_qci_sgi->admin.base_time = ((u64)(le32_to_cpu(sgcl_data->abth))
++                                            << 32)
++                                      + le32_to_cpu(sgcl_data->abtl);
++
++      tsn_qci_sgi->admin.gcl = kcalloc(admin_len,
++                                       sizeof(struct tsn_qci_psfp_gcl),
++                                       GFP_KERNEL);
++      if (!tsn_qci_sgi->admin.gcl) {
++              kfree(sgcl_data);
++              return -ENOMEM;
++      }
++
++      for (i = 0; i < admin_len; i++) {
++              struct tsn_qci_psfp_gcl *temp_sgcl = tsn_qci_sgi->admin.gcl + i;
++              struct sgce *temp_entry = (struct sgce *)(sgce + i);
++
++              if (temp_entry->multi & 0x10)
++                      temp_sgcl->gate_state = true;
++
++              if (temp_entry->multi & 0x08)
++                      temp_sgcl->ipv = temp_entry->multi >> 5;
++              else
++                      temp_sgcl->ipv = -1;
++
++              temp_sgcl->time_interval = le32_to_cpu(temp_entry->interval);
++
++              if (temp_entry->multi & 0x01)
++                      temp_sgcl->octet_max = (temp_entry->msdu[0] & 0xff)
++                              | (((u32)temp_entry->msdu[1] << 8) & 0xff00)
++                              | (((u32)temp_entry->msdu[1] << 16) & 0xff0000);
++              else
++                      temp_sgcl->octet_max = 0;
++      }
++
++      memset(cbdr_sgcl, 0, sizeof(*cbdr_sgcl));
++      kfree(sgcl_data);
++
++exit:
++      memset(cbdr, 0, sizeof(*cbdr));
++      return 0;
++}
++
++/* CBD Class 9: Stream Gate Instance Table Entry Query Descriptor
++ * CBD Class 9: Stream Gate Control List Query Descriptor
++ */
++int enetc_qci_sgi_status_get(struct net_device *ndev, u16 index,
++                           struct tsn_psfp_sgi_status *status)
++{
++      struct enetc_cbd *cbdr_sgi, *cbdr_sgcl;
++      struct sgi_table *sgi_config;
++      struct sgcl_query *sgcl_query;
++      struct sgcl_query_resp *sgcl_data;
++      struct sgce *sgce;
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      dma_addr_t dma;
++      u16 data_size, dma_size, gcl_data_stat = 0;
++      u8 oper_len = 0;
++      int curr_cbd, i;
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr_sgi);
++
++      cbdr_sgi->index = cpu_to_le16(index);
++      cbdr_sgi->cmd = 2;
++      cbdr_sgi->cls = BDCR_CMD_STREAM_GCL;
++      cbdr_sgi->status_flags = 0x80;
++
++      sgi_config = &cbdr_sgi->sgi_table;
++
++      if (sgi_config->gset & 0x4)
++              status->config_pending = true;
++
++      status->oper.gate_states = ((sgi_config->ocgtst & 0x80) ? true : false);
++
++      /* Check gate list length is zero */
++      if (!(sgi_config->oacl_len & 0x30)) {
++              status->oper.control_list_length = 0;
++              goto cmd2quit;
++      }
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr_sgcl);
++
++      cbdr_sgcl->index = cpu_to_le16(index);
++      cbdr_sgcl->cmd = 3;
++      cbdr_sgcl->cls = BDCR_CMD_STREAM_GCL;
++      cbdr_sgcl->status_flags = 0;
++
++      /* Max size */
++      data_size = sizeof(struct sgcl_query_resp) + 4 * sizeof(struct sgce);
++
++      sgcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
++      if (!sgcl_data)
++              return -ENOMEM;
++
++      dma_size = cpu_to_le16(data_size);
++      cbdr_sgcl->length = dma_size;
++      cbdr_sgcl->status_flags = 0;
++
++      sgcl_query = &cbdr_sgcl->sgcl_query;
++
++      sgcl_query->oacl_len = 0x20;
++
++      dma = dma_map_single(&priv->si->pdev->dev, sgcl_data,
++                           data_size, DMA_FROM_DEVICE);
++      if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
++              netdev_err(priv->si->ndev, "DMA mapping failed!\n");
++              memset(cbdr_sgi, 0, sizeof(*cbdr_sgi));
++              memset(cbdr_sgcl, 0, sizeof(*cbdr_sgcl));
++              kfree(sgcl_data);
++              return -ENOMEM;
++      }
++      cbdr_sgcl->addr[0] = lower_32_bits(dma);
++      cbdr_sgcl->addr[1] = upper_32_bits(dma);
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      sgce = (struct sgce *)(sgcl_data + 1);
++
++      /* oper_len can also get from gcl_data_stat bit 5,6
++       * OR sgi_config->oacl_len
++       */
++      oper_len = ((sgcl_query->oacl_len & 0x0c) >> 2) + 1;
++
++      /* Get Stream Gate Control List */
++      status->oper.cycle_time = le32_to_cpu(sgcl_data->oct);
++      status->oper.cycle_time_extension = le32_to_cpu(sgcl_data->octe);
++      status->oper.base_time = le32_to_cpu(sgcl_data->obtl)
++                              + ((u64)le32_to_cpu(sgcl_data->obth) << 32);
++      status->oper.control_list_length = oper_len;
++
++      gcl_data_stat = le16_to_cpu(sgcl_data->stat);
++      if (gcl_data_stat & 0x400)
++              status->oper.init_ipv = gcl_data_stat & 0x38 >> 7;
++      else
++              status->oper.init_ipv = -1;
++
++      if (gcl_data_stat & 0x800)
++              status->oper.gate_states = true;
++
++      status->oper.gcl = kcalloc(oper_len,
++                                 sizeof(struct tsn_qci_psfp_gcl),
++                                 GFP_KERNEL);
++      if (!status->oper.gcl) {
++              memset(cbdr_sgi, 0, sizeof(*cbdr_sgi));
++              memset(cbdr_sgcl, 0, sizeof(*cbdr_sgcl));
++              kfree(sgcl_data);
++              return -ENOMEM;
++      }
++
++      for (i = 0; i < oper_len; i++) {
++              struct tsn_qci_psfp_gcl *temp_sgcl = status->oper.gcl + i;
++              struct sgce *temp_entry = (struct sgce *)(sgce + i);
++
++              if (temp_entry->multi & 0x10)
++                      temp_sgcl->gate_state = true;
++
++              if (temp_entry->multi & 0x08)
++                      temp_sgcl->ipv = temp_entry->multi >> 5;
++              else
++                      temp_sgcl->ipv = -1;
++
++              temp_sgcl->time_interval = le32_to_cpu(temp_entry->interval);
++
++              if (temp_entry->multi & 0x01)
++                      temp_sgcl->octet_max = temp_entry->msdu[0]
++                                      | ((((u32)temp_entry->msdu[1]) << 8)
++                                         & 0xff00)
++                                      | ((((u32)temp_entry->msdu[2]) << 16)
++                                         & 0xff0000);
++              else
++                      temp_sgcl->octet_max = 0;
++      }
++
++      status->config_change_time = le32_to_cpu(sgcl_data->cctl)
++                              + ((u64)le32_to_cpu(sgcl_data->ccth) << 32);
++
++      memset(cbdr_sgcl, 0, sizeof(*cbdr_sgcl));
++      kfree(sgcl_data);
++
++cmd2quit:
++      /* changed to SITGTGR */
++      status->tick_granularity = enetc_rd(&priv->si->hw, ENETC_SITGTGR);
++
++      /* current time */
++      status->current_time = get_current_time(priv->si);
++
++      memset(cbdr_sgi, 0, sizeof(*cbdr_sgi));
++
++      return 0;
++}
++
++/* CBD Class 10: Flow Meter Instance Set Descriptor - Short Format */
++int enetc_qci_fmi_set(struct net_device *ndev, u32 index, bool enable,
++                    struct tsn_qci_psfp_fmi *tsn_qci_fmi)
++{
++      struct enetc_cbd *cbdr;
++      struct fmi_conf *fmi_config;
++
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      int curr_cbd;
++      u64 temp = 0;
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++
++      cbdr->index = cpu_to_le16((u16)index);
++      cbdr->cmd = 0;
++      cbdr->cls = BDCR_CMD_FLOW_METER;
++      cbdr->status_flags = 0x80;
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      if (!enable) {
++              memset(cbdr, 0, sizeof(*cbdr));
++              return 0;
++      }
++
++      /* Re-enable */
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++      memset(cbdr, 0, sizeof(*cbdr));
++      cbdr->index = cpu_to_le16((u16)index);
++      cbdr->cmd = 0;
++      cbdr->cls = BDCR_CMD_FLOW_METER;
++      cbdr->status_flags = 0x80;
++
++      fmi_config = &cbdr->fmi_conf;
++      fmi_config->en = 0x80;
++      if (tsn_qci_fmi->cir) {
++              temp = (u64)1000 * tsn_qci_fmi->cir;
++              temp = temp / 3725;
++      }
++      fmi_config->cir = cpu_to_le32((u32)temp);
++      fmi_config->cbs = cpu_to_le32(tsn_qci_fmi->cbs);
++      temp = 0;
++      if (tsn_qci_fmi->eir) {
++              temp = (u64)1000 * tsn_qci_fmi->eir;
++              temp = temp / 3725;
++      }
++      fmi_config->eir = cpu_to_le32((u32)temp);
++      fmi_config->ebs = cpu_to_le32(tsn_qci_fmi->ebs);
++
++      if (tsn_qci_fmi->mark_red)
++              fmi_config->conf |= 0x1;
++
++      if (tsn_qci_fmi->mark_red_enable)
++              fmi_config->conf |= 0x2;
++
++      if (tsn_qci_fmi->drop_on_yellow)
++              fmi_config->conf |= 0x4;
++
++      if (tsn_qci_fmi->cm)
++              fmi_config->conf |= 0x8;
++
++      if (tsn_qci_fmi->cf)
++              fmi_config->conf |= 0x10;
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      memset(cbdr, 0, sizeof(*cbdr));
++      return 0;
++}
++
++/* CBD Class 10: Flow Meter Instance Query Descriptor - Short Format */
++int enetc_qci_fmi_get(struct net_device *ndev, u32 index,
++                    struct tsn_qci_psfp_fmi *tsn_qci_fmi,
++                    struct tsn_qci_psfp_fmi_counters *counters)
++{
++      struct enetc_cbd *cbdr;
++      struct fmi_conf *fmi_config;
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      int curr_cbd;
++      u16 data_size, dma_size;
++      dma_addr_t dma;
++      struct fmi_query_stat_resp *fmi_counter_data;
++      u64 temp = 0;
++
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++
++      cbdr->index = cpu_to_le16(index);
++      cbdr->cmd = 1;
++      cbdr->cls = BDCR_CMD_FLOW_METER;
++      cbdr->status_flags = 0x80;
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      fmi_config = &cbdr->fmi_conf;
++      if (fmi_config->cir) {
++              temp = (u64)3725 * fmi_config->cir;
++              temp = temp / 1000;
++      }
++      tsn_qci_fmi->cir = le32_to_cpu((u32)temp);
++      tsn_qci_fmi->cbs = le32_to_cpu(fmi_config->cbs);
++      temp = 0;
++      if (fmi_config->eir) {
++              temp = (u64)3725 * fmi_config->eir;
++              temp = temp / 1000;
++      }
++      tsn_qci_fmi->eir = le32_to_cpu((u32)temp);
++      tsn_qci_fmi->ebs = le32_to_cpu(fmi_config->ebs);
++
++      if (fmi_config->conf & 0x1)
++              tsn_qci_fmi->mark_red = true;
++
++      if (fmi_config->conf & 0x2)
++              tsn_qci_fmi->mark_red_enable = true;
++
++      if (fmi_config->conf & 0x4)
++              tsn_qci_fmi->drop_on_yellow = true;
++
++      if (fmi_config->conf & 0x8)
++              tsn_qci_fmi->cm = true;
++
++      if (fmi_config->conf & 0x10)
++              tsn_qci_fmi->cf = true;
++
++      memset(cbdr, 0, sizeof(*cbdr));
++
++      /* Get counters */
++      curr_cbd = alloc_cbdr(priv->si, &cbdr);
++
++      cbdr->index = cpu_to_le16(index);
++      cbdr->cmd = 2;
++      cbdr->cls = BDCR_CMD_FLOW_METER;
++      cbdr->status_flags = 0x0;
++
++      data_size = sizeof(struct fmi_query_stat_resp);
++      fmi_counter_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
++      if (!fmi_counter_data)
++              return -ENOMEM;
++
++      dma = dma_map_single(&priv->si->pdev->dev, fmi_counter_data,
++                           data_size, DMA_FROM_DEVICE);
++      if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
++              netdev_err(priv->si->ndev, "DMA mapping failed!\n");
++              kfree(fmi_counter_data);
++              return -ENOMEM;
++      }
++      cbdr->addr[0] = lower_32_bits(dma);
++      cbdr->addr[1] = upper_32_bits(dma);
++
++      dma_size = cpu_to_le16(data_size);
++      cbdr->length = dma_size;
++
++      xmit_cbdr(priv->si, curr_cbd);
++
++      memcpy(counters, fmi_counter_data, sizeof(*counters));
++
++      return 0;
++}
++
++int enetc_qbu_set(struct net_device *ndev, u8 ptvector)
++{
++      u32 temp;
++      int i;
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++
++      temp = enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET);
++      if (temp & ENETC_QBV_TGE)
++              enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
++                       temp & (~ENETC_QBV_TGPE));
++
++      for (i = 0; i < 8; i++) {
++              /* 1 Enabled. Traffic is transmitted on the preemptive MAC. */
++              temp = enetc_port_rd(&priv->si->hw, ENETC_PTCFPR(i));
++
++              if ((ptvector >> i) & 0x1)
++                      enetc_port_wr(&priv->si->hw,
++                                    ENETC_PTCFPR(i),
++                                    temp | ENETC_FPE);
++              else
++                      enetc_port_wr(&priv->si->hw,
++                                    ENETC_PTCFPR(i),
++                                    temp & ~ENETC_FPE);
++      }
++
++      return 0;
++}
++
++int enetc_qbu_get(struct net_device *ndev,
++                struct tsn_preempt_status *preemptstat)
++{
++      int i;
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++
++      if (enetc_port_rd(&priv->si->hw, ENETC_PFPMR) & ENETC_PFPMR_PMACE) {
++              preemptstat->preemption_active = true;
++              if (enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET)
++                                                      & ENETC_QBV_TGE)
++                      preemptstat->hold_request = 1;
++              else
++                      preemptstat->hold_request = 2;
++      } else {
++              preemptstat->preemption_active = false;
++              return 0;
++      }
++
++      for (i = 0; i < 8; i++)
++              if (enetc_port_rd(&priv->si->hw, ENETC_PTCFPR(i)) & 0x80000000)
++                      preemptstat->admin_state |= 1 << i;
++
++      preemptstat->hold_advance =
++              enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET) & 0xFFFF;
++      preemptstat->release_advance =
++              enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET) & 0xFFFF;
++
++      return 0;
++}
++
++u32 __enetc_tsn_get_cap(struct enetc_si *si)
++{
++      u32 reg = 0;
++      u32 cap = 0;
++
++      reg = enetc_port_rd(&si->hw, ENETC_PCAPR0);
++
++      if (reg & ENETC_PCAPR0_PSFP)
++              cap |= TSN_CAP_QCI;
++
++      if (reg & ENETC_PCAPR0_TSN)
++              cap |= TSN_CAP_QBV;
++
++      if (reg & ENETC_PCAPR0_QBU)
++              cap |= TSN_CAP_QBU;
++
++      cap |= TSN_CAP_CBS;
++      cap |= TSN_CAP_TBS;
++
++      return cap;
++}
++
++u32 enetc_tsn_get_capability(struct net_device *ndev)
++{
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++
++      return __enetc_tsn_get_cap(priv->si);
++}
++
++static int  __enetc_get_max_cap(struct enetc_si *si,
++                              struct tsn_qci_psfp_stream_param *stream_para)
++{
++      u32 reg = 0;
++
++      /* Port stream filter capability */
++      reg = enetc_port_rd(&si->hw, ENETC_PSFCAPR);
++      stream_para->max_sf_instance = reg & ENETC_PSFCAPR_MSK;
++      /* Port stream filter capability */
++      reg = enetc_port_rd(&si->hw, ENETC_PSGCAPR);
++      stream_para->max_sg_instance = (reg & ENETC_PSGCAPR_SGIT_MSK);
++      stream_para->supported_list_max = (reg & ENETC_PSGCAPR_GCL_MSK) >> 16;
++      /* Port flow meter capability */
++      reg = enetc_port_rd(&si->hw, ENETC_PFMCAPR);
++      stream_para->max_fm_instance = reg & ENETC_PFMCAPR_MSK;
++
++      return 0;
++}
++
++int enetc_get_max_cap(struct net_device *ndev,
++                    struct tsn_qci_psfp_stream_param *stream_para)
++{
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++
++      return __enetc_get_max_cap(priv->si, stream_para);
++}
++
++static int enetc_set_cbs(struct net_device *ndev, u8 tc, u8 bw)
++{
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      struct enetc_si *si = priv->si;
++      struct enetc_cbs *ecbs = si->ecbs;
++      struct cbs *cbs;
++
++      int bw_sum = 0;
++      u32 port_transmit_rate;
++      u32 port_frame_max_size;
++      u8 tc_nums;
++      int i;
++
++      u32 max_interfrence_size;
++      u32 send_slope;
++      u32 hi_credit;
++
++      if (!ecbs)
++              return -ENOMEM;
++
++      port_transmit_rate = get_ndev_speed(si->ndev);
++      if (port_transmit_rate != ecbs->port_transmit_rate)
++              ecbs->port_transmit_rate = port_transmit_rate;
++      port_frame_max_size = ecbs->port_max_size_frame;
++      tc_nums = ecbs->tc_nums;
++      cbs = ecbs->cbs;
++
++      if (tc >= tc_nums) {
++              dev_err(&ndev->dev, "Make sure the TC less than %d\n", tc_nums);
++              return -EINVAL;
++      }
++
++      if (!bw) {
++              if (cbs[tc].enable) {
++                      /* Make sure the other TC that are numerically
++                       * lower than this TC have been disabled.
++                       */
++                      for (i = 0; i < tc; i++) {
++                              if (cbs[i].enable)
++                                      break;
++                      }
++                      if (i < tc) {
++                              dev_err(&ndev->dev,
++                                      "TC%d has been disabled first\n", i);
++                              return -EINVAL;
++                      }
++                      memset(&cbs[tc], 0, sizeof(*cbs));
++                      cbs[tc].enable = false;
++                      enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), 0);
++                      enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), 0);
++              }
++              return 0;
++      }
++
++      /* Make sure the other TC that are numerically
++       * higher than this TC have been enabled.
++       */
++      for (i = tc_nums - 1; i > tc; i--) {
++              if (!cbs[i].enable) {
++                      dev_err(&ndev->dev,
++                              "TC%d has been enabled first\n", i);
++                      return -EINVAL;
++              }
++              bw_sum += cbs[i].bw;
++      }
++
++      if (bw_sum + bw >= 100) {
++              dev_err(&ndev->dev,
++                      "The sum of all CBS Bandwidth cann't exceed 100\n");
++              return -EINVAL;
++      }
++
++      cbs[tc].bw = bw;
++      cbs[tc].tc_max_sized_frame = enetc_port_rd(&si->hw, ENETC_PTCMSDUR(tc));
++      cbs[tc].idle_slope = port_transmit_rate / 100 * bw;
++      cbs[tc].send_slope = port_transmit_rate - cbs[tc].idle_slope;
++
++      /* For TC7, the max_interfrence_size is ENETC_MAC_MAXFRM_SIZE.
++       * For TC6, the max_interfrence_size is calculated as below:
++       *
++       *      max_interfrence_size = (M0 + Ma + Ra * M0 / (R0 - Ra))
++       *
++       * For other traffic class, for example SR class Q:
++       *
++       *                            R0 * (M0 + Ma + ... + Mp)
++       *      max_interfrence_size =  ------------------------------
++       *                            (R0 - Ra) + ... + (R0 - Rp)
++       *
++       */
++
++      if (tc == tc_nums - 1) {
++              cbs[tc].max_interfrence_size = port_frame_max_size * 8;
++
++      } else if (tc == tc_nums - 2) {
++              cbs[tc].max_interfrence_size = (port_frame_max_size
++                              + cbs[tc + 1].tc_max_sized_frame
++                              + port_frame_max_size * (cbs[tc + 1].idle_slope
++                              / cbs[tc + 1].send_slope)) * 8;
++      } else {
++              max_interfrence_size = port_frame_max_size;
++              send_slope = 0;
++              for (i = tc + 1; i < tc_nums; i++) {
++                      send_slope += cbs[i].send_slope;
++                      max_interfrence_size += cbs[i].tc_max_sized_frame;
++              }
++              max_interfrence_size = ((u64)port_transmit_rate
++                              * max_interfrence_size) / send_slope;
++              cbs[tc].max_interfrence_size = max_interfrence_size * 8;
++      }
++
++      cbs[tc].hi_credit = cbs[tc].max_interfrence_size * cbs[tc].bw / 100;
++      cbs[tc].lo_credit = cbs[tc].tc_max_sized_frame * (cbs[tc].send_slope
++                      / port_transmit_rate);
++      cbs[tc].tc = tc;
++
++      hi_credit = (ENETC_CLK * 100L) * (u64)cbs[tc].hi_credit
++                      / port_transmit_rate;
++      enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), hi_credit);
++
++      /* Set bw register and enable this traffic class*/
++      enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc),
++                    (cbs[tc].bw & 0x7F) | (1 << 31));
++      cbs[tc].enable = true;
++
++      return 0;
++}
++
++static int enetc_get_cbs(struct net_device *ndev, u8 tc)
++{
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      struct enetc_si *si = priv->si;
++      struct enetc_cbs *ecbs = si->ecbs;
++      struct cbs *cbs;
++
++      if (!ecbs)
++              return -ENOMEM;
++      cbs = ecbs->cbs;
++      if (tc >= ecbs->tc_nums) {
++              dev_err(&ndev->dev, "The maximum of TC is %d\n", ecbs->tc_nums);
++              return -EINVAL;
++      }
++
++      return cbs[tc].bw;
++}
++
++static int enetc_set_tsd(struct net_device *ndev, struct tsn_tsd *ttsd)
++{
++      return 0;
++}
++
++static int enetc_get_tsd(struct net_device *ndev, struct tsn_tsd_status *tts)
++{
++      return 0;
++}
++
++static u32 get_ndev_speed(struct net_device *netdev)
++{
++      struct ethtool_link_ksettings ksettings;
++      int rc = -1;
++
++      if (netdev->ethtool_ops->get_link_ksettings) {
++              if (netdev->ethtool_ops->begin) {
++                      rc = netdev->ethtool_ops->begin(netdev);
++                      if (rc < 0)
++                              return 0;
++              }
++
++              memset(&ksettings, 0, sizeof(ksettings));
++
++              if (!netdev->ethtool_ops->get_link_ksettings)
++                      return 0;
++
++              rc = netdev->ethtool_ops->get_link_ksettings(netdev,
++                                                           &ksettings);
++
++              if (netdev->ethtool_ops->complete)
++                      netdev->ethtool_ops->complete(netdev);
++      }
++
++      return (rc < 0) ? 0 : ksettings.base.speed;
++}
++
++static void enetc_cbs_init(struct enetc_si *si)
++{
++      struct enetc_ndev_priv *priv = netdev_priv(si->ndev);
++      u8 tc_nums;
++
++      tc_nums = priv->num_tx_rings;
++      si->ecbs = kzalloc(sizeof(*si->ecbs) +
++                         sizeof(struct cbs) * tc_nums, GFP_KERNEL);
++      if (!si->ecbs)
++              return;
++
++      si->ecbs->port_max_size_frame = si->ndev->mtu + ETH_HLEN
++                                              + VLAN_HLEN + ETH_FCS_LEN;
++      si->ecbs->tc_nums = tc_nums;
++      si->ecbs->port_transmit_rate = get_ndev_speed(si->ndev);
++
++      /*This trick is used only for CFP*/
++      if (!si->ecbs->port_transmit_rate)
++              si->ecbs->port_transmit_rate = 1000000000;
++
++      if (!si->ecbs->port_transmit_rate) {
++              dev_err(&si->pdev->dev, "Failure to get port speed for CBS\n");
++              kfree(si->ecbs);
++              si->ecbs = NULL;
++      }
++}
++
++static void enetc_qbv_init(struct enetc_hw *hw)
++{
++      /* Set PSPEED to be 1Gbps */
++      enetc_port_wr(hw, ENETC_PMR,
++                    (enetc_port_rd(hw, ENETC_PMR)
++                    & (~ENETC_PMR_PSPEED_MASK))
++                    | ENETC_PMR_PSPEED_1000M);
++}
++
++void enetc_tsn_init(struct net_device *ndev)
++{
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      struct enetc_si *si = priv->si;
++      u32 capability = 0;
++
++      capability = __enetc_tsn_get_cap(si);
++
++      if (capability & TSN_CAP_CBS)
++              enetc_cbs_init(si);
++
++      if (capability & TSN_CAP_QBV)
++              enetc_qbv_init(&si->hw);
++
++      if (capability & TSN_CAP_QCI)
++              enetc_qci_enable(&si->hw);
++
++      dev_info(&si->pdev->dev, "%s: setup done\n", __func__);
++}
++
++void enetc_tsn_deinit(struct net_device *ndev)
++{
++      struct enetc_ndev_priv *priv = netdev_priv(ndev);
++      struct enetc_si *si = priv->si;
++
++      dev_info(&si->pdev->dev, "%s: release\n", __func__);
++}
++
++static struct tsn_ops enetc_tsn_ops_full = {
++      .device_init = enetc_tsn_init,
++      .device_deinit = enetc_tsn_deinit,
++      .get_capability = enetc_tsn_get_capability,
++      .qbv_set = enetc_qbv_set,
++      .qbv_get = enetc_qbv_get,
++      .qbv_get_status = enetc_qbv_get_status,
++      .cb_streamid_set = enetc_cb_streamid_set,
++      .cb_streamid_get = enetc_cb_streamid_get,
++      .cb_streamid_counters_get = enetc_cb_streamid_counters_get,
++      .qci_get_maxcap = enetc_get_max_cap,
++      .qci_sfi_set = enetc_qci_sfi_set,
++      .qci_sfi_get = enetc_qci_sfi_get,
++      .qci_sfi_counters_get = enetc_qci_sfi_counters_get,
++      .qci_sgi_set = enetc_qci_sgi_set,
++      .qci_sgi_get = enetc_qci_sgi_get,
++      .qci_sgi_status_get = enetc_qci_sgi_status_get,
++      .qci_fmi_set = enetc_qci_fmi_set,
++      .qci_fmi_get = enetc_qci_fmi_get,
++      .qbu_set = enetc_qbu_set,
++      .qbu_get = enetc_qbu_get,
++      .cbs_set = enetc_set_cbs,
++      .cbs_get = enetc_get_cbs,
++      .tsd_set = enetc_set_tsd,
++      .tsd_get = enetc_get_tsd,
++};
++
++static struct tsn_ops enetc_tsn_ops_part = {
++      .device_init = enetc_tsn_init,
++      .device_deinit = enetc_tsn_deinit,
++      .get_capability = enetc_tsn_get_capability,
++      .cb_streamid_set = enetc_cb_streamid_set,
++      .cb_streamid_get = enetc_cb_streamid_get,
++      .cb_streamid_counters_get = enetc_cb_streamid_counters_get,
++      .qci_get_maxcap = enetc_get_max_cap,
++      .qci_sfi_set = enetc_qci_sfi_set,
++      .qci_sfi_get = enetc_qci_sfi_get,
++      .qci_sfi_counters_get = enetc_qci_sfi_counters_get,
++      .qci_sgi_set = enetc_qci_sgi_set,
++      .qci_sgi_get = enetc_qci_sgi_get,
++      .qci_sgi_status_get = enetc_qci_sgi_status_get,
++      .qci_fmi_set = enetc_qci_fmi_set,
++      .qci_fmi_get = enetc_qci_fmi_get,
++};
++
++void enetc_tsn_pf_init(struct net_device *netdev, struct pci_dev *pdev)
++{
++      int port = pdev->devfn & 0x7;
++
++      if (port == 1 || port == 3)
++              tsn_port_register(netdev, &enetc_tsn_ops_part,
++                                (u16)pdev->bus->number);
++      else
++              tsn_port_register(netdev, &enetc_tsn_ops_full,
++                                (u16)pdev->bus->number);
++}
++
++void enetc_tsn_pf_deinit(struct net_device *netdev)
++{
++      tsn_port_unregister(netdev);
++}
++#endif        /* #if IS_ENABLED(CONFIG_ENETC_TSN) */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0338-net-dsa-felix-Fix-probing-allocation-and-cleanup-pat.patch b/target/linux/layerscape/patches-5.4/701-net-0338-net-dsa-felix-Fix-probing-allocation-and-cleanup-pat.patch
new file mode 100644 (file)
index 0000000..3e99861
--- /dev/null
@@ -0,0 +1,123 @@
+From 5ae4c4ac2d992afcf4087e5f33ad7e5f7d073fbf Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Wed, 4 Dec 2019 14:36:09 +0200
+Subject: [PATCH] net: dsa: felix: Fix probing allocation and cleanup path
+
+dsa_switch_alloc() uses managed (devm_alloc) allocation
+to alloc 'ds'.  kfree()-ing 'ds' results in memory corruption.
+kfree(ds) seems harmless on the error path, however for this
+particular device, dsa_register_swtich() deffers probing to
+allow the enetc driver to probe the master port first.
+This results in kfree(ds) being called during the first
+probing attempt of felix, followed by a NULL poiter access
+crash during enetc driver probing (when accessing its net_device).
+
+This patch fixes following crash (triggerred in the enetc driver by
+the probing routine of the felix driver):
+
+[    3.502254] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
+[    3.511073] Mem abort info:
+[    3.513874]   ESR = 0x96000044
+[    3.516936]   EC = 0x25: DABT (current EL), IL = 32 bits
+[    3.522266]   SET = 0, FnV = 0
+[    3.525327]   EA = 0, S1PTW = 0
+[    3.528476] Data abort info:
+[    3.531359]   ISV = 0, ISS = 0x00000044
+[    3.535205]   CM = 0, WnR = 1
+[    3.538182] user pgtable: 4k pages, 48-bit VAs, pgdp=00000020f612d000
+[    3.544645] [0000000000000000] pgd=0000000000000000
+[    3.549542] Internal error: Oops: 96000044 [#1] PREEMPT SMP
+[    3.555128] Modules linked in:
+[    3.558189] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.4.0-03552-gfa6e1cd69f80 #1
+[    3.565781] Hardware name: LS1028A RDB Board (DT)
+[    3.570496] pstate: a0000005 (NzCv daif -PAN -UAO)
+[    3.575303] pc : enetc_pf_probe+0x784/0xba8
+[    3.579495] lr : enetc_pf_probe+0x6e8/0xba8
+[    3.583686] sp : ffff80001002ba90
+[    3.587005] x29: ffff80001002ba90 x28: ffff002076130c08
+[    3.592331] x27: 0000000000000002 x26: ffff002076130c80
+[    3.597657] x25: ffff002076130c00 x24: ffff002076130c80
+[    3.602982] x23: ffffb3f2ab0ec000 x22: ffff0020760d7840
+[    3.608307] x21: ffff0020760d7000 x20: ffff002076130c00
+[    3.613632] x19: ffff800010850000 x18: ffffffffffffffff
+[    3.618957] x17: 000000007dee1586 x16: 00000000cb746ba4
+[    3.624282] x15: ffffb3f2abce9908 x14: 0000000000000000
+[    3.629608] x13: 0000000000000101 x12: 0000000000010000
+[    3.634933] x11: 00000000ffffffff x10: ffff4c2dd0136000
+[    3.640257] x9 : 0000000000000000 x8 : ffff002076122000
+[    3.645582] x7 : 0000000000000000 x6 : 000000000000003f
+[    3.650908] x5 : 0000000000000040 x4 : 0000000000000001
+[    3.656234] x3 : ffff800010850000 x2 : ffffb3f2ab0ed868
+[    3.661560] x1 : 0000000000000000 x0 : 00000000051ca556
+[    3.666886] Call trace:
+[    3.669333]  enetc_pf_probe+0x784/0xba8
+[    3.673178]  local_pci_probe+0x3c/0xa0
+[    3.676935]  pci_device_probe+0x128/0x1c0
+[    3.680954]  really_probe+0x108/0x348
+[    3.684623]  driver_probe_device+0x58/0x100
+[    3.688815]  device_driver_attach+0x6c/0x90
+[    3.693006]  __driver_attach+0x84/0xc8
+[    3.696762]  bus_for_each_dev+0x74/0xc8
+[    3.700605]  driver_attach+0x20/0x28
+[    3.704186]  bus_add_driver+0x148/0x1f0
+[    3.708029]  driver_register+0x60/0x110
+[    3.711872]  __pci_register_driver+0x40/0x48
+[    3.716153]  enetc_pf_driver_init+0x20/0x28
+[    3.720346]  do_one_initcall+0x5c/0x1b0
+[    3.724189]  kernel_init_freeable+0x1a4/0x24c
+[    3.728557]  kernel_init+0x10/0x108
+[    3.732052]  ret_from_fork+0x10/0x18
+[    3.735635] Code: f9400680 f9417ea1 91020000 b9400000 (b9000020)
+[    3.741749] ---[ end trace c8ab43e3d33fed3f ]---
+[    3.746396] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
+[    3.748522] ata1: SATA link down (SStatus 0 SControl 300)
+[    3.754077] SMP: stopping secondary CPUs
+[    3.754082] Kernel Offset: 0x33f299c00000 from 0xffff800010000000
+[    3.754083] PHYS_OFFSET: 0xfffff019c0000000
+[    3.754086] CPU features: 0x0002,21806008
+[    3.754088] Memory Limit: none
+[    3.780794] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]---
+
+As a result of the fix, struct felix allocation also needs to
+be converted to managed allocation (devm_alloc).
+
+Fixes: bb849431a970 ("net: dsa: ocelot: alloc memory for dsa switch instance")
+
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+---
+ drivers/net/dsa/ocelot/felix.c | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -530,7 +530,7 @@ static int felix_pci_probe(struct pci_de
+               }
+       }
+-      felix = kzalloc(sizeof(struct felix), GFP_KERNEL);
++      felix = devm_kzalloc(&pdev->dev, sizeof(*felix), GFP_KERNEL);
+       if (!felix) {
+               err = -ENOMEM;
+               dev_err(&pdev->dev, "Failed to allocate driver memory\n");
+@@ -577,11 +577,9 @@ static int felix_pci_probe(struct pci_de
+       return 0;
+ err_register_ds:
+-      kfree(ds);
+ err_alloc_ds:
+ err_alloc_irq:
+ err_alloc_felix:
+-      kfree(felix);
+ err_dma:
+       pci_disable_device(pdev);
+ err_pci_enable:
+@@ -596,9 +594,6 @@ static void felix_pci_remove(struct pci_
+       dsa_unregister_switch(felix->ds);
+-      kfree(felix->ds);
+-      kfree(felix);
+-
+       pci_disable_device(pdev);
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0339-LF-368-net-mscc-ocelot-hard-code-VCAP_PORT_CNT-for-F.patch b/target/linux/layerscape/patches-5.4/701-net-0339-LF-368-net-mscc-ocelot-hard-code-VCAP_PORT_CNT-for-F.patch
new file mode 100644 (file)
index 0000000..44d97ba
--- /dev/null
@@ -0,0 +1,26 @@
+From 17bde33ffe50be558520a063392dc73b319a7f20 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Thu, 28 Nov 2019 11:48:24 +0800
+Subject: [PATCH] LF-368 net: mscc: ocelot: hard code VCAP_PORT_CNT for Felix
+ temporarily
+
+The Felix switch supports different port number with Ocelot.
+This makes the bits mapping in TCAM entry and Action entry
+is different with Ocelot for VCAP function.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/mscc/ocelot_vcap.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot_vcap.h
++++ b/drivers/net/ethernet/mscc/ocelot_vcap.h
+@@ -25,7 +25,7 @@
+ #define VCAP_IS2_CNT 64
+ #define VCAP_IS2_ENTRY_WIDTH 376
+ #define VCAP_IS2_ACTION_WIDTH 99
+-#define VCAP_PORT_CNT 11
++#define VCAP_PORT_CNT 6
+ /* IS2 half key types */
+ #define IS2_TYPE_ETYPE 0
diff --git a/target/linux/layerscape/patches-5.4/701-net-0340-LF-368-net-mscc-ocelot-make-ocelot_ace_rule-support-.patch b/target/linux/layerscape/patches-5.4/701-net-0340-LF-368-net-mscc-ocelot-make-ocelot_ace_rule-support-.patch
new file mode 100644 (file)
index 0000000..6628de5
--- /dev/null
@@ -0,0 +1,123 @@
+From 79fbcc73dd52acfe8b7aa20a793ce8d60c8d3f7b Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Thu, 28 Nov 2019 12:10:44 -0600
+Subject: [PATCH] LF-368 net: mscc: ocelot: make ocelot_ace_rule support
+ multiple ports
+
+The ocelot_ace_rule is port specific now. Make it flexible to
+be able to support multiple ports too.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/mscc/ocelot_ace.c    | 14 +++++++-------
+ drivers/net/ethernet/mscc/ocelot_ace.h    |  4 ++--
+ drivers/net/ethernet/mscc/ocelot_flower.c |  8 ++++----
+ 3 files changed, 13 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot_ace.c
++++ b/drivers/net/ethernet/mscc/ocelot_ace.c
+@@ -352,7 +352,7 @@ static void is2_entry_set(struct ocelot
+       data.type = IS2_ACTION_TYPE_NORMAL;
+       VCAP_KEY_ANY_SET(PAG);
+-      VCAP_KEY_SET(IGR_PORT_MASK, 0, ~BIT(ace->chip_port));
++      VCAP_KEY_SET(IGR_PORT_MASK, 0, ~ace->ingress_port_mask);
+       VCAP_KEY_BIT_SET(FIRST, OCELOT_VCAP_BIT_1);
+       VCAP_KEY_BIT_SET(HOST_MATCH, OCELOT_VCAP_BIT_ANY);
+       VCAP_KEY_BIT_SET(L2_MC, ace->dmac_mc);
+@@ -576,7 +576,7 @@ static void is2_entry_set(struct ocelot
+ static void is2_entry_get(struct ocelot_ace_rule *rule, int ix)
+ {
+-      struct ocelot *op = rule->port->ocelot;
++      struct ocelot *op = rule->ocelot;
+       struct vcap_data data;
+       int row = (ix / 2);
+       u32 cnt;
+@@ -655,11 +655,11 @@ int ocelot_ace_rule_offload_add(struct o
+       /* Move down the rules to make place for the new rule */
+       for (i = acl_block->count - 1; i > index; i--) {
+               ace = ocelot_ace_rule_get_rule_index(acl_block, i);
+-              is2_entry_set(rule->port->ocelot, i, ace);
++              is2_entry_set(rule->ocelot, i, ace);
+       }
+       /* Now insert the new rule */
+-      is2_entry_set(rule->port->ocelot, index, rule);
++      is2_entry_set(rule->ocelot, index, rule);
+       return 0;
+ }
+@@ -697,11 +697,11 @@ int ocelot_ace_rule_offload_del(struct o
+       /* Move up all the blocks over the deleted rule */
+       for (i = index; i < acl_block->count; i++) {
+               ace = ocelot_ace_rule_get_rule_index(acl_block, i);
+-              is2_entry_set(rule->port->ocelot, i, ace);
++              is2_entry_set(rule->ocelot, i, ace);
+       }
+       /* Now delete the last rule, because it is duplicated */
+-      is2_entry_set(rule->port->ocelot, acl_block->count, &del_ace);
++      is2_entry_set(rule->ocelot, acl_block->count, &del_ace);
+       return 0;
+ }
+@@ -717,7 +717,7 @@ int ocelot_ace_rule_stats_update(struct
+       /* After we get the result we need to clear the counters */
+       tmp = ocelot_ace_rule_get_rule_index(acl_block, index);
+       tmp->stats.pkts = 0;
+-      is2_entry_set(rule->port->ocelot, index, tmp);
++      is2_entry_set(rule->ocelot, index, tmp);
+       return 0;
+ }
+--- a/drivers/net/ethernet/mscc/ocelot_ace.h
++++ b/drivers/net/ethernet/mscc/ocelot_ace.h
+@@ -186,14 +186,14 @@ struct ocelot_ace_stats {
+ struct ocelot_ace_rule {
+       struct list_head list;
+-      struct ocelot_port *port;
++      struct ocelot *ocelot;
+       u16 prio;
+       u32 id;
+       enum ocelot_ace_action action;
+       struct ocelot_ace_stats stats;
+-      int chip_port;
++      u16 ingress_port_mask;
+       enum ocelot_vcap_bit dmac_mc;
+       enum ocelot_vcap_bit dmac_bc;
+--- a/drivers/net/ethernet/mscc/ocelot_flower.c
++++ b/drivers/net/ethernet/mscc/ocelot_flower.c
+@@ -177,8 +177,8 @@ struct ocelot_ace_rule *ocelot_ace_rule_
+       if (!rule)
+               return NULL;
+-      rule->port = &block->priv->port;
+-      rule->chip_port = block->priv->chip_port;
++      rule->ocelot = block->priv->port.ocelot;
++      rule->ingress_port_mask = BIT(block->priv->chip_port);
+       return rule;
+ }
+@@ -213,7 +213,7 @@ static int ocelot_flower_destroy(struct
+       int ret;
+       rule.prio = f->common.prio;
+-      rule.port = &port_block->priv->port;
++      rule.ocelot = port_block->priv->port.ocelot;
+       rule.id = f->cookie;
+       ret = ocelot_ace_rule_offload_del(&rule);
+@@ -231,7 +231,7 @@ static int ocelot_flower_stats_update(st
+       int ret;
+       rule.prio = f->common.prio;
+-      rule.port = &port_block->priv->port;
++      rule.ocelot = port_block->priv->port.ocelot;
+       rule.id = f->cookie;
+       ret = ocelot_ace_rule_stats_update(&rule);
+       if (ret)
diff --git a/target/linux/layerscape/patches-5.4/701-net-0341-LF-368-net-mscc-ocelot-add-VCAP-IS2-rule-to-trap-PTP.patch b/target/linux/layerscape/patches-5.4/701-net-0341-LF-368-net-mscc-ocelot-add-VCAP-IS2-rule-to-trap-PTP.patch
new file mode 100644 (file)
index 0000000..af80b9f
--- /dev/null
@@ -0,0 +1,60 @@
+From 67ca04147efac6cac3f7490c61c817a84daada57 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Thu, 28 Nov 2019 14:42:44 +0800
+Subject: [PATCH] LF-368 net: mscc: ocelot: add VCAP IS2 rule to trap PTP
+ Ethernet frames
+
+All the PTP messages over Ethernet have etype 0x88f7 on them.
+Use etype as the key to trap PTP messages.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -2338,6 +2338,20 @@ void ocelot_set_cpu_port(struct ocelot *
+ }
+ EXPORT_SYMBOL(ocelot_set_cpu_port);
++/* Entry for PTP over Ethernet (etype 0x88f7)
++ * Action: trap to CPU port
++ */
++static struct ocelot_ace_rule ptp_rule = {
++      .prio           = 1,
++      .type           = OCELOT_ACE_TYPE_ETYPE,
++      .dmac_mc        = OCELOT_VCAP_BIT_1,
++      .action         = OCELOT_ACL_ACTION_TRAP,
++      .frame.etype.etype.value[0]     = 0x88,
++      .frame.etype.etype.value[1]     = 0xf7,
++      .frame.etype.etype.mask[0]      = 0xff,
++      .frame.etype.etype.mask[1]      = 0xff,
++};
++
+ int ocelot_init(struct ocelot *ocelot)
+ {
+       char queue_name[32];
+@@ -2475,6 +2489,13 @@ int ocelot_init(struct ocelot *ocelot)
+                               "Timestamp initialization failed\n");
+                       return ret;
+               }
++
++              /* Available on all ingress port except CPU port */
++              ptp_rule.ocelot = ocelot;
++              ptp_rule.ingress_port_mask =
++                      GENMASK(ocelot->num_phys_ports - 1, 0);
++              ptp_rule.ingress_port_mask &= ~BIT(ocelot->cpu);
++              ocelot_ace_rule_offload_add(&ptp_rule);
+       }
+       return 0;
+@@ -2489,6 +2510,8 @@ void ocelot_deinit(struct ocelot *ocelot
+       cancel_delayed_work(&ocelot->stats_work);
+       destroy_workqueue(ocelot->stats_queue);
+       mutex_destroy(&ocelot->stats_lock);
++      if (ocelot->ptp)
++              ocelot_ace_rule_offload_del(&ptp_rule);
+       ocelot_ace_deinit();
+       if (ocelot->ptp_clock)
+               ptp_clock_unregister(ocelot->ptp_clock);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0342-LF-376-enetc-disable-EEE-autoneg-by-default.patch b/target/linux/layerscape/patches-5.4/701-net-0342-LF-376-enetc-disable-EEE-autoneg-by-default.patch
new file mode 100644 (file)
index 0000000..18b4d77
--- /dev/null
@@ -0,0 +1,38 @@
+From cb87015e005f429bff6fc084a61281235ca83d51 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Fri, 6 Dec 2019 12:41:48 +0800
+Subject: [PATCH] LF-376 enetc: disable EEE autoneg by default
+
+The EEE support has not been enabled on ENETC, but it may connect
+to a PHY which supports EEE and advertises EEE by default, while
+its link partner also advertises EEE. If this happens, the PHY enters
+low power mode when the traffic rate is low and causes packet loss.
+This patch disables EEE advertisement by default for any PHY that
+ENETC connects to, to prevent the above unwanted outcome.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc.c
+@@ -1369,6 +1369,7 @@ static int enetc_phy_connect(struct net_
+ {
+       struct enetc_ndev_priv *priv = netdev_priv(ndev);
+       struct phy_device *phydev;
++      struct ethtool_eee edata;
+       if (!priv->phy_node)
+               return 0; /* phy-less mode */
+@@ -1382,6 +1383,10 @@ static int enetc_phy_connect(struct net_
+       phy_attached_info(phydev);
++      /* disable EEE autoneg, until ENETC driver supports it */
++      memset(&edata, 0, sizeof(struct ethtool_eee));
++      phy_ethtool_set_eee(phydev, &edata);
++
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0343-staging-dpaa2-ethsw-move-port-notifier-per-ethsw.patch b/target/linux/layerscape/patches-5.4/701-net-0343-staging-dpaa2-ethsw-move-port-notifier-per-ethsw.patch
new file mode 100644 (file)
index 0000000..5024e98
--- /dev/null
@@ -0,0 +1,80 @@
+From daaa4e77f9bc9e67fa3fd973d4455631d59fb898 Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Mon, 11 Nov 2019 18:50:55 +0200
+Subject: [PATCH] staging: dpaa2-ethsw: move port notifier per ethsw
+
+Register a different net_device notifier block per ethsw instance.
+When probing multiple dpaa2-ethsw instances, without this the register
+will fail.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+Link: https://lore.kernel.org/r/1573491058-24766-2-git-send-email-ioana.ciornei@nxp.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 13 ++++++-------
+ drivers/staging/fsl-dpaa2/ethsw/ethsw.h |  2 ++
+ 2 files changed, 8 insertions(+), 7 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
++++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+@@ -1174,10 +1174,6 @@ static int port_netdevice_event(struct n
+       return notifier_from_errno(err);
+ }
+-static struct notifier_block port_nb __read_mostly = {
+-      .notifier_call = port_netdevice_event,
+-};
+-
+ struct ethsw_switchdev_event_work {
+       struct work_struct work;
+       struct switchdev_notifier_fdb_info fdb_info;
+@@ -1328,9 +1324,11 @@ static struct notifier_block port_switch
+ static int ethsw_register_notifier(struct device *dev)
+ {
++      struct ethsw_core *ethsw = dev_get_drvdata(dev);
+       int err;
+-      err = register_netdevice_notifier(&port_nb);
++      ethsw->port_nb.notifier_call = port_netdevice_event;
++      err = register_netdevice_notifier(&ethsw->port_nb);
+       if (err) {
+               dev_err(dev, "Failed to register netdev notifier\n");
+               return err;
+@@ -1353,7 +1351,7 @@ static int ethsw_register_notifier(struc
+ err_switchdev_blocking_nb:
+       unregister_switchdev_notifier(&port_switchdev_nb);
+ err_switchdev_nb:
+-      unregister_netdevice_notifier(&port_nb);
++      unregister_netdevice_notifier(&ethsw->port_nb);
+       return err;
+ }
+@@ -1491,6 +1489,7 @@ static int ethsw_port_init(struct ethsw_
+ static void ethsw_unregister_notifier(struct device *dev)
+ {
++      struct ethsw_core *ethsw = dev_get_drvdata(dev);
+       struct notifier_block *nb;
+       int err;
+@@ -1505,7 +1504,7 @@ static void ethsw_unregister_notifier(st
+               dev_err(dev,
+                       "Failed to unregister switchdev notifier (%d)\n", err);
+-      err = unregister_netdevice_notifier(&port_nb);
++      err = unregister_netdevice_notifier(&ethsw->port_nb);
+       if (err)
+               dev_err(dev,
+                       "Failed to unregister netdev notifier (%d)\n", err);
+--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
++++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+@@ -66,6 +66,8 @@ struct ethsw_core {
+       u8                              vlans[VLAN_VID_MASK + 1];
+       bool                            learning;
++
++      struct notifier_block           port_nb;
+ };
+ #endif        /* __ETHSW_H */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0344-staging-dpaa2-ethsw-move-port-switchdev-notifier-per.patch b/target/linux/layerscape/patches-5.4/701-net-0344-staging-dpaa2-ethsw-move-port-switchdev-notifier-per.patch
new file mode 100644 (file)
index 0000000..459d145
--- /dev/null
@@ -0,0 +1,68 @@
+From e35e9d1a3dd2cc4f06f03ec4c3fae781bb0c5075 Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Mon, 11 Nov 2019 18:50:56 +0200
+Subject: [PATCH] staging: dpaa2-ethsw: move port switchdev notifier per ethsw
+
+Register a different switchdev notifier block per ethsw instance.
+When probing multiple dpaa2-ethsw instances, without this the register
+will fail.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+Link: https://lore.kernel.org/r/1573491058-24766-3-git-send-email-ioana.ciornei@nxp.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 11 ++++-------
+ drivers/staging/fsl-dpaa2/ethsw/ethsw.h |  1 +
+ 2 files changed, 5 insertions(+), 7 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
++++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+@@ -1314,10 +1314,6 @@ static int port_switchdev_blocking_event
+       return NOTIFY_DONE;
+ }
+-static struct notifier_block port_switchdev_nb = {
+-      .notifier_call = port_switchdev_event,
+-};
+-
+ static struct notifier_block port_switchdev_blocking_nb = {
+       .notifier_call = port_switchdev_blocking_event,
+ };
+@@ -1334,7 +1330,8 @@ static int ethsw_register_notifier(struc
+               return err;
+       }
+-      err = register_switchdev_notifier(&port_switchdev_nb);
++      ethsw->port_switchdev_nb.notifier_call = port_switchdev_event;
++      err = register_switchdev_notifier(&ethsw->port_switchdev_nb);
+       if (err) {
+               dev_err(dev, "Failed to register switchdev notifier\n");
+               goto err_switchdev_nb;
+@@ -1349,7 +1346,7 @@ static int ethsw_register_notifier(struc
+       return 0;
+ err_switchdev_blocking_nb:
+-      unregister_switchdev_notifier(&port_switchdev_nb);
++      unregister_switchdev_notifier(&ethsw->port_switchdev_nb);
+ err_switchdev_nb:
+       unregister_netdevice_notifier(&ethsw->port_nb);
+       return err;
+@@ -1499,7 +1496,7 @@ static void ethsw_unregister_notifier(st
+               dev_err(dev,
+                       "Failed to unregister switchdev blocking notifier (%d)\n", err);
+-      err = unregister_switchdev_notifier(&port_switchdev_nb);
++      err = unregister_switchdev_notifier(&ethsw->port_switchdev_nb);
+       if (err)
+               dev_err(dev,
+                       "Failed to unregister switchdev notifier (%d)\n", err);
+--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
++++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+@@ -68,6 +68,7 @@ struct ethsw_core {
+       bool                            learning;
+       struct notifier_block           port_nb;
++      struct notifier_block           port_switchdev_nb;
+ };
+ #endif        /* __ETHSW_H */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0345-staging-dpaa2-ethsw-move-port-switchdev-blocking-not.patch b/target/linux/layerscape/patches-5.4/701-net-0345-staging-dpaa2-ethsw-move-port-switchdev-blocking-not.patch
new file mode 100644 (file)
index 0000000..ace7012
--- /dev/null
@@ -0,0 +1,60 @@
+From e6987a7f7ebbde64eb679f10a6eb857b9e28d05d Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Mon, 11 Nov 2019 18:50:57 +0200
+Subject: [PATCH] staging: dpaa2-ethsw: move port switchdev blocking notifier
+ per ethsw
+
+Register a different switchdev blocking notifier block per ethsw
+instance.  When probing multiple dpaa2-ethsw instances, without this the
+register will fail.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+Link: https://lore.kernel.org/r/1573491058-24766-4-git-send-email-ioana.ciornei@nxp.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 9 +++------
+ drivers/staging/fsl-dpaa2/ethsw/ethsw.h | 1 +
+ 2 files changed, 4 insertions(+), 6 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
++++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+@@ -1314,10 +1314,6 @@ static int port_switchdev_blocking_event
+       return NOTIFY_DONE;
+ }
+-static struct notifier_block port_switchdev_blocking_nb = {
+-      .notifier_call = port_switchdev_blocking_event,
+-};
+-
+ static int ethsw_register_notifier(struct device *dev)
+ {
+       struct ethsw_core *ethsw = dev_get_drvdata(dev);
+@@ -1337,7 +1333,8 @@ static int ethsw_register_notifier(struc
+               goto err_switchdev_nb;
+       }
+-      err = register_switchdev_blocking_notifier(&port_switchdev_blocking_nb);
++      ethsw->port_switchdevb_nb.notifier_call = port_switchdev_blocking_event;
++      err = register_switchdev_blocking_notifier(&ethsw->port_switchdevb_nb);
+       if (err) {
+               dev_err(dev, "Failed to register switchdev blocking notifier\n");
+               goto err_switchdev_blocking_nb;
+@@ -1490,7 +1487,7 @@ static void ethsw_unregister_notifier(st
+       struct notifier_block *nb;
+       int err;
+-      nb = &port_switchdev_blocking_nb;
++      nb = &ethsw->port_switchdevb_nb;
+       err = unregister_switchdev_blocking_notifier(nb);
+       if (err)
+               dev_err(dev,
+--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
++++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+@@ -69,6 +69,7 @@ struct ethsw_core {
+       struct notifier_block           port_nb;
+       struct notifier_block           port_switchdev_nb;
++      struct notifier_block           port_switchdevb_nb;
+ };
+ #endif        /* __ETHSW_H */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0346-staging-dpaa2-ethsw-ordered-workqueue-should-be-per-.patch b/target/linux/layerscape/patches-5.4/701-net-0346-staging-dpaa2-ethsw-ordered-workqueue-should-be-per-.patch
new file mode 100644 (file)
index 0000000..e8ef629
--- /dev/null
@@ -0,0 +1,90 @@
+From 6e0b1cafcfc1bf343cf4957a93850178ba9ea165 Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Mon, 11 Nov 2019 18:50:58 +0200
+Subject: [PATCH] staging: dpaa2-ethsw: ordered workqueue should be per ethsw
+
+Create a different ordered workqueue per dpaa2-ethsw instance.  Without
+this change, we overwrite the global queue and leak memory when probing
+multiple instances of the driver.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+Link: https://lore.kernel.org/r/1573491058-24766-5-git-send-email-ioana.ciornei@nxp.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 17 +++++++++--------
+ drivers/staging/fsl-dpaa2/ethsw/ethsw.h |  1 +
+ 2 files changed, 10 insertions(+), 8 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
++++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+@@ -18,8 +18,6 @@
+ #include "ethsw.h"
+-static struct workqueue_struct *ethsw_owq;
+-
+ /* Minimal supported DPSW version */
+ #define DPSW_MIN_VER_MAJOR            8
+ #define DPSW_MIN_VER_MINOR            1
+@@ -1229,8 +1227,10 @@ static int port_switchdev_event(struct n
+                               unsigned long event, void *ptr)
+ {
+       struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
++      struct ethsw_port_priv *port_priv = netdev_priv(dev);
+       struct ethsw_switchdev_event_work *switchdev_work;
+       struct switchdev_notifier_fdb_info *fdb_info = ptr;
++      struct ethsw_core *ethsw = port_priv->ethsw_data;
+       if (!ethsw_port_dev_check(dev))
+               return NOTIFY_DONE;
+@@ -1266,7 +1266,7 @@ static int port_switchdev_event(struct n
+               return NOTIFY_DONE;
+       }
+-      queue_work(ethsw_owq, &switchdev_work->work);
++      queue_work(ethsw->workqueue, &switchdev_work->work);
+       return NOTIFY_DONE;
+@@ -1427,9 +1427,10 @@ static int ethsw_init(struct fsl_mc_devi
+               }
+       }
+-      ethsw_owq = alloc_ordered_workqueue("%s_ordered", WQ_MEM_RECLAIM,
+-                                          "ethsw");
+-      if (!ethsw_owq) {
++      ethsw->workqueue = alloc_ordered_workqueue("%s_%d_ordered",
++                                                 WQ_MEM_RECLAIM, "ethsw",
++                                                 ethsw->sw_attr.id);
++      if (!ethsw->workqueue) {
+               err = -ENOMEM;
+               goto err_close;
+       }
+@@ -1441,7 +1442,7 @@ static int ethsw_init(struct fsl_mc_devi
+       return 0;
+ err_destroy_ordered_workqueue:
+-      destroy_workqueue(ethsw_owq);
++      destroy_workqueue(ethsw->workqueue);
+ err_close:
+       dpsw_close(ethsw->mc_io, 0, ethsw->dpsw_handle);
+@@ -1529,7 +1530,7 @@ static int ethsw_remove(struct fsl_mc_de
+       ethsw_teardown_irqs(sw_dev);
+-      destroy_workqueue(ethsw_owq);
++      destroy_workqueue(ethsw->workqueue);
+       dpsw_disable(ethsw->mc_io, 0, ethsw->dpsw_handle);
+--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
++++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+@@ -70,6 +70,7 @@ struct ethsw_core {
+       struct notifier_block           port_nb;
+       struct notifier_block           port_switchdev_nb;
+       struct notifier_block           port_switchdevb_nb;
++      struct workqueue_struct         *workqueue;
+ };
+ #endif        /* __ETHSW_H */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0347-staging-fsl-dpaa2-mac-do-not-call-dpmac_set_link_sta.patch b/target/linux/layerscape/patches-5.4/701-net-0347-staging-fsl-dpaa2-mac-do-not-call-dpmac_set_link_sta.patch
new file mode 100644 (file)
index 0000000..6920237
--- /dev/null
@@ -0,0 +1,45 @@
+From 978b13baa79b68f3471cc2c5110a2e45aab9ca61 Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Tue, 10 Dec 2019 17:26:06 +0200
+Subject: [PATCH] staging: fsl-dpaa2/mac: do not call dpmac_set_link_state()
+ when nothing changed
+
+In case nothing changed in the link configuration do not call
+dpmac_set_link_state().
+This is needed in case of the following sequence of commands.
+
+$ ip link set dev eth1 up; ip link set dev eth2 down
+
+Phylib brings the link down when the aneg is started on the phy which
+translates in a link down from phy in MC and confuses the MC linkman.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -158,12 +158,16 @@ static void dpaa2_mac_link_changed(struc
+               netif_carrier_off(netdev);
+       }
+-      if (priv->old_state.up != state.up ||
+-          priv->old_state.rate != state.rate ||
+-          priv->old_state.options != state.options) {
+-              priv->old_state = state;
+-              phy_print_status(phydev);
+-      }
++      /* Call the dpmac_set_link_state() only if there is a change in the
++       * link configuration
++       */
++      if (priv->old_state.up == state.up &&
++          priv->old_state.rate == state.rate &&
++          priv->old_state.options == state.options)
++              return;
++
++      priv->old_state = state;
++      phy_print_status(phydev);
+       if (cmp_dpmac_ver(priv, DPMAC_LINK_AUTONEG_VER_MAJOR,
+                         DPMAC_LINK_AUTONEG_VER_MINOR) < 0) {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0348-staging-fsl-dpaa2-mac-reverse-order-of-handling-stop.patch b/target/linux/layerscape/patches-5.4/701-net-0348-staging-fsl-dpaa2-mac-reverse-order-of-handling-stop.patch
new file mode 100644 (file)
index 0000000..6788b84
--- /dev/null
@@ -0,0 +1,37 @@
+From c9db7ecdd08e38fb1af207c2a7e810b4bd0d1043 Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Wed, 11 Dec 2019 17:06:40 +0200
+Subject: [PATCH] staging: fsl-dpaa2/mac: reverse order of handling stop/start
+ IRQs
+
+Both the LINK_UP_REQ and the LINK_DOWN_REQ IRQs can be received in the
+same time when a reset is performed on the DPMAC's partner.
+Handle first the link down and then the link up so that we do not
+trigger a phylib WARNING like the following:
+
+[  446.272011] called from state NOLINK
+[  446.275604] WARNING: CPU: 0 PID: 473 at drivers/net/phy/phy.c:874
+phy_start+0x44/0xa8
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -482,12 +482,11 @@ static irqreturn_t dpaa2_mac_irq_handler
+               configure_link(priv, &link_cfg);
+       }
+-      if (status & DPMAC_IRQ_EVENT_LINK_UP_REQ)
+-              phy_start(ndev->phydev);
+-
+       if (status & DPMAC_IRQ_EVENT_LINK_DOWN_REQ)
+               phy_stop(ndev->phydev);
++      if (status & DPMAC_IRQ_EVENT_LINK_UP_REQ)
++              phy_start(ndev->phydev);
+ out:
+       dpmac_clear_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle,
+                              DPMAC_IRQ_INDEX, status);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0349-fsl_qbman-add-dummy-functions-for-probe-deferal-APIs.patch b/target/linux/layerscape/patches-5.4/701-net-0349-fsl_qbman-add-dummy-functions-for-probe-deferal-APIs.patch
new file mode 100644 (file)
index 0000000..7192ae7
--- /dev/null
@@ -0,0 +1,34 @@
+From d7050fa7b0b0e88217ebfc09666eb08632dfe436 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 12 Mar 2019 17:57:26 +0200
+Subject: [PATCH] fsl_qbman: add dummy functions for probe deferal APIs
+
+Add missing definitions for probe deferal APIs for drivers
+that use them with the SDK version of the qbman drivers.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Signed-off-by: Vlad Pelin <vlad.pelin@nxp.com>
+Acked-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ include/linux/fsl_qman.h | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/include/linux/fsl_qman.h
++++ b/include/linux/fsl_qman.h
+@@ -3893,6 +3893,16 @@ int qman_p_enqueue_orp(struct qman_porta
+ int qman_p_enqueue_precommit(struct qman_portal *p, struct qman_fq *fq,
+                               const struct qm_fd *fd, u32 flags,
+                               qman_cb_precommit cb, void *cb_arg);
++
++static inline int qman_is_probed(void) {
++      return 1;
++}
++
++
++static inline int qman_portals_probed(void) {
++      return 1;
++}
++
+ #ifdef __cplusplus
+ }
+ #endif
diff --git a/target/linux/layerscape/patches-5.4/701-net-0350-sdk_fman-fix-identation-causing-compilation-warnings.patch b/target/linux/layerscape/patches-5.4/701-net-0350-sdk_fman-fix-identation-causing-compilation-warnings.patch
new file mode 100644 (file)
index 0000000..64eb72d
--- /dev/null
@@ -0,0 +1,34 @@
+From 2152a79d81c23f21bedd9ea5934c6df266642f36 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@oss.nxp.com>
+Date: Thu, 19 Dec 2019 14:33:11 +0200
+Subject: [PATCH] sdk_fman: fix identation causing compilation warnings
+
+Signed-off-by: Madalin Bucur <madalin.bucur@oss.nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c
+@@ -460,8 +460,8 @@ uint8_t fman_get_num_of_tasks(struct fma
+ {
+       uint32_t tmp;
+-    if ((port_id > 63) || (port_id < 1))
+-        return 0;
++      if ((port_id > 63) || (port_id < 1))
++              return 0;
+       tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
+       return (uint8_t)(((tmp & BMI_NUM_OF_TASKS_MASK) >>
+@@ -472,8 +472,8 @@ uint8_t fman_get_num_extra_tasks(struct
+ {
+       uint32_t tmp;
+-    if ((port_id > 63) || (port_id < 1))
+-        return 0;
++      if ((port_id > 63) || (port_id < 1))
++              return 0;
+       tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
+       return (uint8_t)((tmp & BMI_NUM_OF_EXTRA_TASKS_MASK) >>
diff --git a/target/linux/layerscape/patches-5.4/701-net-0351-sdk_fman-address-compilation-warning.patch b/target/linux/layerscape/patches-5.4/701-net-0351-sdk_fman-address-compilation-warning.patch
new file mode 100644 (file)
index 0000000..efcaccc
--- /dev/null
@@ -0,0 +1,32 @@
+From dd20e6f1e67e50bfa557b3b4597dd76dc1589644 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@oss.nxp.com>
+Date: Thu, 19 Dec 2019 14:41:09 +0200
+Subject: [PATCH] sdk_fman: address compilation warning
+
+Signed-off-by: Madalin Bucur <madalin.bucur@oss.nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c
+@@ -642,6 +642,8 @@ t_Error FmHcPcdKgSetClsPlan(t_Handle h_F
+     t_DpaaFD                fmFd;
+     uint8_t                 i, idx;
+     uint32_t                seqNum;
++    const void *src;
++    void *dest;
+     t_Error                 err = E_OK;
+     ASSERT_COND(p_FmHc);
+@@ -659,7 +661,9 @@ t_Error FmHcPcdKgSetClsPlan(t_Handle h_F
+         idx = (uint8_t)(i - p_Set->baseEntry);
+         ASSERT_COND(idx < FM_PCD_MAX_NUM_OF_CLS_PLANS);
+-        memcpy(&p_HcFrame->hcSpecificData.clsPlanEntries, &p_Set->vectors[idx], CLS_PLAN_NUM_PER_GRP*sizeof(uint32_t));
++      dest = (void *)&p_HcFrame->hcSpecificData.clsPlanEntries; 
++      src = &p_Set->vectors[idx];
++        memcpy(dest, src, CLS_PLAN_NUM_PER_GRP*sizeof(uint32_t));
+         p_HcFrame->commandSequence = seqNum;
+         BUILD_FD(sizeof(t_HcFrame));
diff --git a/target/linux/layerscape/patches-5.4/701-net-0352-soc-fsl-dpio-Enable-ACP-port-in-Linux-QMAN-driver.patch b/target/linux/layerscape/patches-5.4/701-net-0352-soc-fsl-dpio-Enable-ACP-port-in-Linux-QMAN-driver.patch
new file mode 100644 (file)
index 0000000..ed1978b
--- /dev/null
@@ -0,0 +1,37 @@
+From 462a65a13cff2e04122df6a770d91ef1e301b359 Mon Sep 17 00:00:00 2001
+From: Youri Querry <youri.querry_1@nxp.com>
+Date: Thu, 19 Dec 2019 09:44:33 -0500
+Subject: [PATCH] soc: fsl: dpio: Enable ACP port in Linux QMAN driver
+
+Setting the software portal configuration DE(dequeue stashing
+enable) bit. This should enable the ACP (Accelerator Coherency
+Port).
+
+During test this improved performance on the LS2088a slightly. No
+effect on the LX2160a.
+
+Signed-off-by: Youri Querry <youri.querry_1@nxp.com>
+---
+ drivers/soc/fsl/dpio/qbman-portal.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/soc/fsl/dpio/qbman-portal.c
++++ b/drivers/soc/fsl/dpio/qbman-portal.c
+@@ -299,7 +299,7 @@ struct qbman_swp *qbman_swp_init(const s
+                       1, /* mem stashing priority enable */
+                       1, /* mem stashing enable */
+                       1, /* dequeue stashing priority enable */
+-                      0, /* dequeue stashing enable enable */
++                      1, /* dequeue stashing enable enable */
+                       0); /* EQCR_CI stashing priority enable */
+       } else {
+               memset(p->addr_cena, 0, 64 * 1024);
+@@ -313,7 +313,7 @@ struct qbman_swp *qbman_swp_init(const s
+                       1, /* mem stashing priority enable */
+                       1, /* mem stashing enable */
+                       1, /* dequeue stashing priority enable */
+-                      0, /* dequeue stashing enable */
++                      1, /* dequeue stashing enable */
+                       0); /* EQCR_CI stashing priority enable */
+               reg |= 1 << SWP_CFG_CPBS_SHIFT | /* memory-backed mode */
+                      1 << SWP_CFG_VPM_SHIFT |  /* VDQCR read triggered mode */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0353-staging-fsl-dpaa2-mac-do-not-stop-MAC-when-the-net_d.patch b/target/linux/layerscape/patches-5.4/701-net-0353-staging-fsl-dpaa2-mac-do-not-stop-MAC-when-the-net_d.patch
new file mode 100644 (file)
index 0000000..80bb697
--- /dev/null
@@ -0,0 +1,65 @@
+From aae18d4ce3055e459855cc8661cf8f2a5e2cbe73 Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Fri, 13 Dec 2019 13:24:01 +0200
+Subject: [PATCH] staging: fsl-dpaa2/mac: do not stop MAC when the net_dev is
+ not up
+
+In case the net_device is not up, there is no need to call
+dpmac_mac_stop(). Guard the call by checking the IFF_UP flag.
+This patch will also solve the following warning generated by removing a
+dpmac that is not up.
+
+[   40.942937] called from state READY
+[   40.946442] WARNING: CPU: 0 PID: 755 at drivers/net/phy/phy.c:838
+phy_stop+0x6c/0x78
+[   40.954171] Modules linked in:
+[   40.957214] CPU: 0 PID: 755 Comm: bash Tainted: G        W
+5.4.0-03629-gfd7102c32b2c-dirty #911
+[   40.966592] Hardware name: NXP Layerscape LX2160ARDB (DT)
+[   40.971978] pstate: 40000005 (nZcv daif -PAN -UAO)
+[   40.976756] pc : phy_stop+0x6c/0x78
+[   40.980232] lr : phy_stop+0x6c/0x78
+(..)
+[   41.066487] Call trace:
+[   41.068922]  phy_stop+0x6c/0x78
+[   41.072052]  dpaa2_mac_stop.part.4+0x34/0x5c
+[   41.076309]  dpaa2_mac_remove+0x9c/0xa8
+
+Also, remove the IFF_UP flag from the mac netdev since the PHY is not
+anymore started at probe time but is rather started/stopped on ifconfig
+up/down.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+---
+ drivers/staging/fsl-dpaa2/mac/mac.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+--- a/drivers/staging/fsl-dpaa2/mac/mac.c
++++ b/drivers/staging/fsl-dpaa2/mac/mac.c
+@@ -1,5 +1,5 @@
+ /* Copyright 2015 Freescale Semiconductor Inc.
+- * Copyright 2018 NXP
++ * Copyright 2018-2019 NXP
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions are met:
+@@ -664,9 +664,6 @@ static int dpaa2_mac_probe(struct fsl_mc
+       netdev->netdev_ops = &dpaa2_mac_ndo_ops;
+       netdev->ethtool_ops = &dpaa2_mac_ethtool_ops;
+-      /* phy starts up enabled so netdev should be up too */
+-      netdev->flags |= IFF_UP;
+-
+       err = register_netdev(priv->netdev);
+       if (err < 0) {
+               dev_err(dev, "register_netdev error %d\n", err);
+@@ -775,7 +772,8 @@ static int dpaa2_mac_remove(struct fsl_m
+       struct dpaa2_mac_priv   *priv = dev_get_drvdata(dev);
+       struct net_device       *netdev = priv->netdev;
+-      dpaa2_mac_stop(netdev);
++      if (netdev->flags & IFF_UP)
++              dpaa2_mac_stop(netdev);
+       if (phy_is_pseudo_fixed_link(netdev->phydev))
+               fixed_phy_unregister(netdev->phydev);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0354-bus-fsl-mc-add-the-dpdbg-device-type.patch b/target/linux/layerscape/patches-5.4/701-net-0354-bus-fsl-mc-add-the-dpdbg-device-type.patch
new file mode 100644 (file)
index 0000000..6a20704
--- /dev/null
@@ -0,0 +1,35 @@
+From 6f506965930f06a3c82ba46c5f095e7b1b6368af Mon Sep 17 00:00:00 2001
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+Date: Fri, 20 Dec 2019 14:35:52 +0200
+Subject: [PATCH] bus: fsl-mc: add the dpdbg device type
+
+A new object type was recently added in MC.  This has to be added in the
+fsl-mc bus device type list so that it can be properly listed.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+Reviewed-by: Madalin Bucur <madalin.bucur@nxp.com>
+---
+ drivers/bus/fsl-mc/fsl-mc-bus.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
+@@ -369,6 +369,10 @@ struct device_type fsl_mc_bus_dpdmai_typ
+       .name = "fsl_mc_bus_dpdmai"
+ };
++struct device_type fsl_mc_bus_dpdbg_type = {
++      .name = "fsl_mc_bus_dpdbg"
++};
++
+ static struct device_type *fsl_mc_get_device_type(const char *type)
+ {
+       static const struct {
+@@ -390,6 +394,7 @@ static struct device_type *fsl_mc_get_de
+               { &fsl_mc_bus_dpaiop_type, "dpaiop" },
+               { &fsl_mc_bus_dpci_type, "dpci" },
+               { &fsl_mc_bus_dpdmai_type, "dpdmai" },
++              { &fsl_mc_bus_dpdbg_type, "dpdbg" },
+               { NULL, NULL }
+       };
+       int i;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0355-sdk_fman-decrease-log-severity-levels.patch b/target/linux/layerscape/patches-5.4/701-net-0355-sdk_fman-decrease-log-severity-levels.patch
new file mode 100644 (file)
index 0000000..5bb3d7b
--- /dev/null
@@ -0,0 +1,41 @@
+From 1cbcd6a80eb6bbea5747a5a8edc450d8fc48e976 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Thu, 19 Dec 2019 11:38:33 +0200
+Subject: [PATCH] sdk_fman: decrease log severity levels
+
+Decrease the severity of log messages from critical to appropriate
+levels (warning and info).
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c      | 2 +-
+ drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
+@@ -2896,7 +2896,7 @@ static int __init __cold fm_load (void)
+         return -ENODEV;
+     }
+-      printk(KERN_CRIT "Freescale FM module," \
++      printk(KERN_INFO "Freescale FM module," \
+               " FMD API version %d.%d.%d\n",
+               FMD_API_VERSION_MAJOR,
+               FMD_API_VERSION_MINOR,
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c
+@@ -1494,11 +1494,11 @@ void LNXWRP_FM_Port_Free(void)
+ static int __init __cold fm_port_load(void)
+ {
+       if (LNXWRP_FM_Port_Init() != E_OK) {
+-              printk(KERN_CRIT "Failed to init FM Ports wrapper!\n");
++              printk(KERN_ERR "Failed to init FM Ports wrapper!\n");
+               return -ENODEV;
+       }
+-      printk(KERN_CRIT "Freescale FM Ports module\n");
++      printk(KERN_INFO "Freescale FM Ports module\n");
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0356-sdk_dpaa-ethtool-drop-unused-variable.patch b/target/linux/layerscape/patches-5.4/701-net-0356-sdk_dpaa-ethtool-drop-unused-variable.patch
new file mode 100644 (file)
index 0000000..7d59d55
--- /dev/null
@@ -0,0 +1,31 @@
+From 77d8734e1870f842d1e62addec82e5c05c1a6630 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 29 Oct 2019 16:07:57 +0200
+Subject: [PATCH] sdk_dpaa: ethtool: drop unused variable
+
+Remove unused variable that was missed in past code refactorings.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c
+@@ -90,7 +90,6 @@ static char dpa_stats_global[][ETH_GSTRI
+ static int __cold dpa_get_ksettings(struct net_device *net_dev,
+               struct ethtool_link_ksettings *cmd)
+ {
+-      int                      _errno;
+       struct dpa_priv_s       *priv;
+       priv = netdev_priv(net_dev);
+@@ -106,7 +105,7 @@ static int __cold dpa_get_ksettings(stru
+       phy_ethtool_ksettings_get(priv->mac_dev->phy_dev, cmd);
+-      return _errno;
++      return 0;
+ }
+ static int __cold dpa_set_ksettings(struct net_device *net_dev,
diff --git a/target/linux/layerscape/patches-5.4/701-net-0357-sdk_dpaa-ls1043a-errata-memory-related-fixes.patch b/target/linux/layerscape/patches-5.4/701-net-0357-sdk_dpaa-ls1043a-errata-memory-related-fixes.patch
new file mode 100644 (file)
index 0000000..6daee46
--- /dev/null
@@ -0,0 +1,107 @@
+From 26d3cc476c26832e1e05db182ac27906f6c81f2d Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 29 Oct 2019 16:12:18 +0200
+Subject: [PATCH] sdk_dpaa: ls1043a errata: memory related fixes
+
+Avoid a crash by verifying the allocation return status.
+
+Use the standard API for determining the page order needed for
+allocating Jumbo sized skbs.
+
+Explicitly remove the old skb outside the w/a, for both successful and
+unsuccessful realignments. Make sure the old skb's memory isn't leaked.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c  | 30 ++++++++++++++--------
+ 1 file changed, 19 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -809,8 +809,8 @@ static struct sk_buff *a010022_realign_s
+ {
+       int trans_offset = skb_transport_offset(skb);
+       int net_offset = skb_network_offset(skb);
+-      int nsize, headroom, npage_order;
+       struct sk_buff *nskb = NULL;
++      int nsize, headroom;
+       struct page *npage;
+       void *npage_addr;
+@@ -825,8 +825,7 @@ static struct sk_buff *a010022_realign_s
+               SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+       /* Reserve enough memory to accommodate Jumbo frames */
+-      npage_order = (nsize - 1) / PAGE_SIZE;
+-      npage = alloc_pages(GFP_ATOMIC | __GFP_COMP, npage_order);
++      npage = alloc_pages(GFP_ATOMIC | __GFP_COMP, get_order(nsize));
+       if (unlikely(!npage)) {
+               WARN_ONCE(1, "Memory allocation failure\n");
+               return NULL;
+@@ -869,7 +868,6 @@ static struct sk_buff *a010022_realign_s
+       /* We don't want the buffer to be recycled so we mark it accordingly */
+       nskb->mark = NONREC_MARK;
+-      dev_kfree_skb(skb);
+       return nskb;
+ err:
+@@ -911,8 +909,13 @@ int __hot skb_to_sg_fd(struct dpa_priv_s
+        * is in place and we need to avoid crossing a 4k boundary.
+        */
+ #ifndef CONFIG_PPC
+-      if (unlikely(dpaa_errata_a010022))
+-              sgt_buf = page_address(alloc_page(GFP_ATOMIC));
++      if (unlikely(dpaa_errata_a010022)) {
++              struct page *new_page = alloc_page(GFP_ATOMIC);
++
++              if (unlikely(!new_page))
++                      return -ENOMEM;
++              sgt_buf = page_address(new_page);
++      }
+       else
+ #endif
+               sgt_buf = netdev_alloc_frag(priv->tx_headroom + sgt_size);
+@@ -1061,6 +1064,7 @@ int __hot dpa_tx_extended(struct sk_buff
+       int err = 0;
+       bool nonlinear;
+       int *countptr, offset = 0;
++      struct sk_buff *nskb;
+       priv = netdev_priv(net_dev);
+       /* Non-migratable context, safe to use raw_cpu_ptr */
+@@ -1072,9 +1076,11 @@ int __hot dpa_tx_extended(struct sk_buff
+ #ifndef CONFIG_PPC
+       if (unlikely(dpaa_errata_a010022) && a010022_check_skb(skb, priv)) {
+-              skb = a010022_realign_skb(skb, priv);
+-              if (!skb)
++              nskb = a010022_realign_skb(skb, priv);
++              if (!nskb)
+                       goto skb_to_fd_failed;
++              dev_kfree_skb(skb);
++              skb = nskb;
+       }
+ #endif
+@@ -1130,15 +1136,17 @@ int __hot dpa_tx_extended(struct sk_buff
+               /* Code borrowed from skb_unshare(). */
+               if (skb_cloned(skb)) {
+-                      struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);
++                      nskb = skb_copy(skb, GFP_ATOMIC);
+                       kfree_skb(skb);
+                       skb = nskb;
+ #ifndef CONFIG_PPC
+                       if (unlikely(dpaa_errata_a010022) &&
+                           a010022_check_skb(skb, priv)) {
+-                              skb = a010022_realign_skb(skb, priv);
+-                              if (!skb)
++                              nskb = a010022_realign_skb(skb, priv);
++                              if (!nskb)
+                                       goto skb_to_fd_failed;
++                              dev_kfree_skb(skb);
++                              skb = nskb;
+                       }
+ #endif
+                       /* skb_copy() has now linearized the skbuff. */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0358-sdk_dpaa-ls1043a-errata-update-and-optimize-the-rest.patch b/target/linux/layerscape/patches-5.4/701-net-0358-sdk_dpaa-ls1043a-errata-update-and-optimize-the-rest.patch
new file mode 100644 (file)
index 0000000..684d04b
--- /dev/null
@@ -0,0 +1,252 @@
+From e89db675171a7a12f19b6ec0089a9cc62807cdf1 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 29 Oct 2019 16:34:08 +0200
+Subject: [PATCH] sdk_dpaa: ls1043a errata: update and optimize the
+ restrictions
+
+An skb is in no danger of triggering the errata under the following
+conditions:
+- the paged data doesn't cross a 4K page boundary OR the linear data
+is aligned to 256 bytes when crossing a 4K page boundary
+- the linear and the paged data are 16 byte aligned
+- the paged data is a multiple of 16 bytes in size
+
+Optimize the detection for each skb that might trigger the errata. Parse
+the skb twice, at most, and realign it only once.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h |   2 +-
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c  | 147 +++++++++++++++------
+ 2 files changed, 111 insertions(+), 38 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
+@@ -662,7 +662,7 @@ static inline void _dpa_bp_free_pf(void
+ #ifndef CONFIG_PPC
+ extern bool dpaa_errata_a010022; /* SoC affected by A010022 errata */
+ #define NONREC_MARK   0x01
+-#define HAS_DMA_ISSUE(start, size) \
++#define CROSS_4K(start, size) \
+       (((uintptr_t)(start) + (size)) > \
+        (((uintptr_t)(start) + 0x1000) & ~0xFFF))
+ /* The headroom needs to accommodate our private data (64 bytes) but
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -771,32 +771,73 @@ int __hot skb_to_contig_fd(struct dpa_pr
+ EXPORT_SYMBOL(skb_to_contig_fd);
+ #ifndef CONFIG_PPC
+-/* Verify the conditions that trigger the A010022 errata: data unaligned to
+- * 16 bytes, 4K memory address crossings and S/G fragments.
++/* Verify the conditions that trigger the A010022 errata:
++ * - 4K memory address boundary crossings when the data/SG fragments aren't
++ *   aligned to 256 bytes
++ * - data and SG fragments that aren't aligned to 16 bytes
++ * - SG fragments that aren't mod 16 bytes in size (except for the last
++ *   fragment)
+  */
+ static bool a010022_check_skb(struct sk_buff *skb, struct dpa_priv_s *priv)
+ {
+-      /* Check if the headroom is aligned */
+-      if (((uintptr_t)skb->data - priv->tx_headroom) %
+-          priv->buf_layout[TX].data_align != 0)
+-              return true;
++      skb_frag_t *frag;
++      int i, nr_frags;
+-      /* Check for paged data in the skb. We do not support S/G fragments */
+-      if (skb_is_nonlinear(skb))
++      nr_frags = skb_shinfo(skb)->nr_frags;
++
++      /* Check if the linear data is 16 byte aligned */
++      if ((uintptr_t)skb->data % 16)
+               return true;
+-      /* Check if the headroom crosses a boundary */
+-      if (HAS_DMA_ISSUE(skb->head, skb_headroom(skb)))
++      /* Check if the needed headroom crosses a 4K address boundary without
++       * being 256 byte aligned
++       */
++      if (CROSS_4K(skb->data - priv->tx_headroom, priv->tx_headroom) &&
++          (((uintptr_t)skb->data - priv->tx_headroom) % 256))
+               return true;
+-      /* Check if the non-paged data crosses a boundary */
+-      if (HAS_DMA_ISSUE(skb->data, skb_headlen(skb)))
++      /* Check if the linear data crosses a 4K address boundary without
++       * being 256 byte aligned
++       */
++      if (CROSS_4K(skb->data, skb_headlen(skb)) &&
++          ((uintptr_t)skb->data % 256))
+               return true;
+-      /* Check if the entire linear skb crosses a boundary */
+-      if (HAS_DMA_ISSUE(skb->head, skb_end_offset(skb)))
++      /* When using Scatter/Gather, the linear data becomes the first
++       * fragment in the list and must follow the same restrictions as the
++       * other fragments.
++       *
++       * Check if the linear data is mod 16 bytes in size.
++       */
++      if (nr_frags && (skb_headlen(skb) % 16))
+               return true;
++      /* Check the SG fragments. They must follow the same rules as the
++       * linear data with and additional restriction: they must be multiple
++       * of 16 bytes in size to account for the hardware carryover effect.
++       */
++      for (i = 0; i < nr_frags; i++) {
++              frag = &skb_shinfo(skb)->frags[i];
++
++              /* Check if the fragment is a multiple of 16 bytes in size.
++               * The last fragment is exempt from this restriction.
++               */
++              if ((i != (nr_frags - 1)) && (skb_frag_size(frag) % 16))
++                      return true;
++
++              /* Check if the fragment is 16 byte aligned */
++              if (skb_frag_off(frag) % 16)
++                      return true;
++
++              /* Check if the fragment crosses a 4K address boundary. Since
++               * the alignment of previous fragments can influence the
++               * current fragment, checking for the 256 byte alignment
++               * isn't relevant.
++               */
++              if (CROSS_4K(skb_frag_off(frag), skb_frag_size(frag)))
++                      return true;
++      }
++
+       return false;
+ }
+@@ -1062,10 +1103,24 @@ int __hot dpa_tx_extended(struct sk_buff
+       struct dpa_percpu_priv_s *percpu_priv;
+       struct rtnl_link_stats64 *percpu_stats;
+       int err = 0;
+-      bool nonlinear;
++      bool nonlinear, skb_changed, skb_need_wa;
+       int *countptr, offset = 0;
+       struct sk_buff *nskb;
++      /* Flags to help optimize the A010022 errata restriction checks.
++       *
++       * First flag marks if the skb changed between the first A010022 check
++       * and the moment it's converted to an FD.
++       *
++       * The second flag marks if the skb needs to be realigned in order to
++       * avoid the errata.
++       *
++       * The flags should have minimal impact on platforms not impacted by
++       * the errata.
++       */
++      skb_changed = false;
++      skb_need_wa = false;
++
+       priv = netdev_priv(net_dev);
+       /* Non-migratable context, safe to use raw_cpu_ptr */
+       percpu_priv = raw_cpu_ptr(priv->percpu_priv);
+@@ -1075,13 +1130,8 @@ int __hot dpa_tx_extended(struct sk_buff
+       clear_fd(&fd);
+ #ifndef CONFIG_PPC
+-      if (unlikely(dpaa_errata_a010022) && a010022_check_skb(skb, priv)) {
+-              nskb = a010022_realign_skb(skb, priv);
+-              if (!nskb)
+-                      goto skb_to_fd_failed;
+-              dev_kfree_skb(skb);
+-              skb = nskb;
+-      }
++      if (unlikely(dpaa_errata_a010022) && a010022_check_skb(skb, priv))
++              skb_need_wa = true;
+ #endif
+       nonlinear = skb_is_nonlinear(skb);
+@@ -1102,8 +1152,8 @@ int __hot dpa_tx_extended(struct sk_buff
+        * Btw, we're using the first sgt entry to store the linear part of
+        * the skb, so we're one extra frag short.
+        */
+-      if (nonlinear &&
+-              likely(skb_shinfo(skb)->nr_frags < DPA_SGT_MAX_ENTRIES)) {
++      if (nonlinear && !skb_need_wa &&
++          likely(skb_shinfo(skb)->nr_frags < DPA_SGT_MAX_ENTRIES)) {
+               /* Just create a S/G fd based on the skb */
+               err = skb_to_sg_fd(priv, skb, &fd);
+               percpu_priv->tx_frag_skbuffs++;
+@@ -1128,39 +1178,62 @@ int __hot dpa_tx_extended(struct sk_buff
+                       dev_kfree_skb(skb);
+                       skb = skb_new;
++                      skb_changed = true;
+               }
+               /* We're going to store the skb backpointer at the beginning
+                * of the data buffer, so we need a privately owned skb
++               *
++               * Under the A010022 errata, we are going to have a privately
++               * owned skb after realigning the current one, so no point in
++               * copying it here in that case.
+                */
+               /* Code borrowed from skb_unshare(). */
+-              if (skb_cloned(skb)) {
++              if (skb_cloned(skb) && !skb_need_wa) {
+                       nskb = skb_copy(skb, GFP_ATOMIC);
+                       kfree_skb(skb);
+                       skb = nskb;
+-#ifndef CONFIG_PPC
+-                      if (unlikely(dpaa_errata_a010022) &&
+-                          a010022_check_skb(skb, priv)) {
+-                              nskb = a010022_realign_skb(skb, priv);
+-                              if (!nskb)
+-                                      goto skb_to_fd_failed;
+-                              dev_kfree_skb(skb);
+-                              skb = nskb;
+-                      }
+-#endif
++                      skb_changed = true;
++
+                       /* skb_copy() has now linearized the skbuff. */
+-              } else if (unlikely(nonlinear)) {
++              } else if (unlikely(nonlinear) && !skb_need_wa) {
+                       /* We are here because the egress skb contains
+                        * more fragments than we support. In this case,
+                        * we have no choice but to linearize it ourselves.
+                        */
+-                      err = __skb_linearize(skb);
++#ifndef CONFIG_PPC
++                      /* No point in linearizing the skb now if we are going
++                       * to realign and linearize it again further down due
++                       * to the A010022 errata
++                       */
++                      if (unlikely(dpaa_errata_a010022))
++                              skb_need_wa = true;
++                      else
++#endif
++                              err = __skb_linearize(skb);
+               }
+               if (unlikely(!skb || err < 0))
+                       /* Common out-of-memory error path */
+                       goto enomem;
++#ifndef CONFIG_PPC
++              /* Verify the skb a second time if it has been updated since
++               * the previous check
++               */
++              if (unlikely(dpaa_errata_a010022) && skb_changed &&
++                  a010022_check_skb(skb, priv))
++                      skb_need_wa = true;
++
++              if (unlikely(dpaa_errata_a010022) && skb_need_wa) {
++                      nskb = a010022_realign_skb(skb, priv);
++                      if (!nskb)
++                              goto skb_to_fd_failed;
++                      dev_kfree_skb(skb);
++                      skb = nskb;
++              }
++#endif
++
+               err = skb_to_contig_fd(priv, skb, &fd, countptr, &offset);
+       }
+       if (unlikely(err < 0))
diff --git a/target/linux/layerscape/patches-5.4/701-net-0359-sdk_dpaa-ls1043a-errata-re-enable-SG-support-and-rec.patch b/target/linux/layerscape/patches-5.4/701-net-0359-sdk_dpaa-ls1043a-errata-re-enable-SG-support-and-rec.patch
new file mode 100644 (file)
index 0000000..d6bb4c4
--- /dev/null
@@ -0,0 +1,71 @@
+From fc7824df7022869a403c8a5122a55fe73a193466 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Tue, 29 Oct 2019 16:50:34 +0200
+Subject: [PATCH] sdk_dpaa: ls1043a errata: re-enable SG support and recycling
+
+With certain limitation, SG frames can be used safely without triggering
+the errata.
+
+Buffers can be recycled, even after realigning the data.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c    | 10 ----------
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h    |  1 -
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c |  9 ---------
+ 3 files changed, 20 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
+@@ -778,16 +778,6 @@ static int dpa_private_netdev_init(struc
+       /* Advertise NETIF_F_HW_ACCEL_MQ to avoid Tx timeout warnings */
+       net_dev->features |= NETIF_F_HW_ACCEL_MQ;
+-#ifndef CONFIG_PPC
+-      /* Due to the A010022 FMan errata, we can not use S/G frames. We need
+-       * to stop advertising S/G and GSO support.
+-       */
+-      if (unlikely(dpaa_errata_a010022)) {
+-              net_dev->hw_features &= ~NETIF_F_SG;
+-              net_dev->features &= ~NETIF_F_GSO;
+-      }
+-#endif
+-
+       return dpa_netdev_init(net_dev, mac_addr, tx_timeout);
+ }
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
+@@ -661,7 +661,6 @@ static inline void _dpa_bp_free_pf(void
+ #ifndef CONFIG_PPC
+ extern bool dpaa_errata_a010022; /* SoC affected by A010022 errata */
+-#define NONREC_MARK   0x01
+ #define CROSS_4K(start, size) \
+       (((uintptr_t)(start) + (size)) > \
+        (((uintptr_t)(start) + 0x1000) & ~0xFFF))
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -327,12 +327,6 @@ EXPORT_SYMBOL(_dpa_cleanup_tx_fd);
+ #ifndef CONFIG_FSL_DPAA_TS
+ bool dpa_skb_is_recyclable(struct sk_buff *skb)
+ {
+-#ifndef CONFIG_PPC
+-      /* Do no recycle skbs realigned by the errata workaround */
+-      if (unlikely(dpaa_errata_a010022) && skb->mark == NONREC_MARK)
+-              return false;
+-#endif
+-
+       /* No recycling possible if skb buffer is kmalloc'ed  */
+       if (skb->head_frag == 0)
+               return false;
+@@ -906,9 +900,6 @@ static struct sk_buff *a010022_realign_s
+       skb_set_network_header(nskb, net_offset);
+       skb_set_transport_header(nskb, trans_offset);
+-      /* We don't want the buffer to be recycled so we mark it accordingly */
+-      nskb->mark = NONREC_MARK;
+-
+       return nskb;
+ err:
diff --git a/target/linux/layerscape/patches-5.4/701-net-0360-sdk_dpaa-sdk_fman-ls1043a-errata-detect-based-on-DTB.patch b/target/linux/layerscape/patches-5.4/701-net-0360-sdk_dpaa-sdk_fman-ls1043a-errata-detect-based-on-DTB.patch
new file mode 100644 (file)
index 0000000..e9e5ae0
--- /dev/null
@@ -0,0 +1,297 @@
+From 6dbf409f09fd85d738652c7867a5822f682d5682 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Thu, 12 Dec 2019 14:15:05 +0200
+Subject: [PATCH] sdk_dpaa: sdk_fman: ls1043a errata: detect based on DTB
+ property
+
+Detect if the platform is vulnerable to the A010022 erratum based on device
+tree properties instead of the SoC family.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c | 31 +---------------------
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h | 14 +++++-----
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c  | 25 ++++++++---------
+ .../inc/integrations/LS1043/dpaa_integration_ext.h |  3 +++
+ .../sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h     | 10 +++++++
+ .../freescale/sdk_fman/src/wrapper/lnxwrp_fm.c     | 17 ++++++++++++
+ 6 files changed, 51 insertions(+), 49 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
+@@ -1,4 +1,5 @@
+ /* Copyright 2008-2013 Freescale Semiconductor Inc.
++ * Copyright 2019 NXP
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions are met:
+@@ -105,11 +106,6 @@ static const char rtx[][3] = {
+       [TX] = "TX"
+ };
+-#ifndef CONFIG_PPC
+-bool dpaa_errata_a010022;
+-EXPORT_SYMBOL(dpaa_errata_a010022);
+-#endif
+-
+ /* BM */
+ #define DPAA_ETH_MAX_PAD (L1_CACHE_BYTES * 8)
+@@ -1133,26 +1129,6 @@ static struct platform_driver dpa_driver
+       .remove         = dpa_remove
+ };
+-#ifndef CONFIG_PPC
+-static bool __init __cold soc_has_errata_a010022(void)
+-{
+-#ifdef CONFIG_SOC_BUS
+-      const struct soc_device_attribute soc_msi_matches[] = {
+-              { .family = "QorIQ LS1043A",
+-                .data = NULL },
+-              { },
+-      };
+-
+-      if (soc_device_match(soc_msi_matches))
+-              return true;
+-
+-      return false;
+-#else
+-      return true; /* cannot identify SoC */
+-#endif
+-}
+-#endif
+-
+ static int __init __cold dpa_load(void)
+ {
+       int      _errno;
+@@ -1168,11 +1144,6 @@ static int __init __cold dpa_load(void)
+       dpa_max_frm = fm_get_max_frm();
+       dpa_num_cpus = num_possible_cpus();
+-#ifndef CONFIG_PPC
+-      /* Detect if the current SoC requires the 4K alignment workaround */
+-      dpaa_errata_a010022 = soc_has_errata_a010022();
+-#endif
+-
+ #ifdef CONFIG_FSL_DPAA_DBG_LOOP
+       memset(dpa_loop_netdevs, 0, sizeof(dpa_loop_netdevs));
+ #endif
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
+@@ -1,4 +1,5 @@
+ /* Copyright 2008-2012 Freescale Semiconductor Inc.
++ * Copyright 2019 NXP
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions are met:
+@@ -98,15 +99,15 @@ struct dpa_buffer_layout_s {
+  * space to account for further alignments.
+  */
+ #define DPA_MAX_FRM_SIZE      9600
+-#ifdef CONFIG_PPC
++#ifndef FM_ERRATUM_A010022
+ #define DPA_BP_RAW_SIZE \
+       ((DPA_MAX_FRM_SIZE + DPA_MAX_FD_OFFSET + \
+         sizeof(struct skb_shared_info) + 128) & ~(SMP_CACHE_BYTES - 1))
+-#else /* CONFIG_PPC */
+-#define DPA_BP_RAW_SIZE ((unlikely(dpaa_errata_a010022)) ? 2048 : \
++#else /* FM_ERRATUM_A010022 */
++#define DPA_BP_RAW_SIZE ((unlikely(fm_has_errata_a010022())) ? 2048 : \
+       ((DPA_MAX_FRM_SIZE + DPA_MAX_FD_OFFSET + \
+         sizeof(struct skb_shared_info) + 128) & ~(SMP_CACHE_BYTES - 1)))
+-#endif /* CONFIG_PPC */
++#endif /* FM_ERRATUM_A010022 */
+ #endif /* CONFIG_FSL_DPAA_ETH_JUMBO_FRAME */
+ /* This is what FMan is ever allowed to use.
+@@ -659,8 +660,7 @@ static inline void _dpa_bp_free_pf(void
+  * on egress.
+  */
+-#ifndef CONFIG_PPC
+-extern bool dpaa_errata_a010022; /* SoC affected by A010022 errata */
++#ifdef FM_ERRATUM_A010022
+ #define CROSS_4K(start, size) \
+       (((uintptr_t)(start) + (size)) > \
+        (((uintptr_t)(start) + 0x1000) & ~0xFFF))
+@@ -668,6 +668,6 @@ extern bool dpaa_errata_a010022; /* SoC
+  * we reserve 256 bytes instead to guarantee 256 data alignment.
+  */
+ #define DPAA_A010022_HEADROOM 256
+-#endif  /* !CONFIG_PPC */
++#endif  /* FM_ERRATUM_A010022 */
+ #endif        /* __DPA_H */
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -1,4 +1,5 @@
+ /* Copyright 2012 Freescale Semiconductor Inc.
++ * Copyright 2019 NXP
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions are met:
+@@ -100,8 +101,8 @@ static int _dpa_bp_add_8_bufs(const stru
+                * We only need enough space to store a pointer, but allocate
+                * an entire cacheline for performance reasons.
+                */
+-#ifndef CONFIG_PPC
+-              if (unlikely(dpaa_errata_a010022)) {
++#ifdef FM_ERRATUM_A010022
++              if (unlikely(fm_has_errata_a010022())) {
+                       struct page *new_page = alloc_page(GFP_ATOMIC);
+                       if (unlikely(!new_page))
+                               goto netdev_alloc_failed;
+@@ -764,7 +765,7 @@ int __hot skb_to_contig_fd(struct dpa_pr
+ }
+ EXPORT_SYMBOL(skb_to_contig_fd);
+-#ifndef CONFIG_PPC
++#ifdef FM_ERRATUM_A010022
+ /* Verify the conditions that trigger the A010022 errata:
+  * - 4K memory address boundary crossings when the data/SG fragments aren't
+  *   aligned to 256 bytes
+@@ -940,8 +941,8 @@ int __hot skb_to_sg_fd(struct dpa_priv_s
+       /* Get a page frag to store the SGTable, or a full page if the errata
+        * is in place and we need to avoid crossing a 4k boundary.
+        */
+-#ifndef CONFIG_PPC
+-      if (unlikely(dpaa_errata_a010022)) {
++#ifdef FM_ERRATUM_A010022
++      if (unlikely(fm_has_errata_a010022())) {
+               struct page *new_page = alloc_page(GFP_ATOMIC);
+               if (unlikely(!new_page))
+@@ -1120,8 +1121,8 @@ int __hot dpa_tx_extended(struct sk_buff
+       clear_fd(&fd);
+-#ifndef CONFIG_PPC
+-      if (unlikely(dpaa_errata_a010022) && a010022_check_skb(skb, priv))
++#ifdef FM_ERRATUM_A010022
++      if (unlikely(fm_has_errata_a010022()) && a010022_check_skb(skb, priv))
+               skb_need_wa = true;
+ #endif
+@@ -1193,12 +1194,12 @@ int __hot dpa_tx_extended(struct sk_buff
+                        * more fragments than we support. In this case,
+                        * we have no choice but to linearize it ourselves.
+                        */
+-#ifndef CONFIG_PPC
++#ifdef FM_ERRATUM_A010022
+                       /* No point in linearizing the skb now if we are going
+                        * to realign and linearize it again further down due
+                        * to the A010022 errata
+                        */
+-                      if (unlikely(dpaa_errata_a010022))
++                      if (unlikely(fm_has_errata_a010022()))
+                               skb_need_wa = true;
+                       else
+ #endif
+@@ -1208,15 +1209,15 @@ int __hot dpa_tx_extended(struct sk_buff
+                       /* Common out-of-memory error path */
+                       goto enomem;
+-#ifndef CONFIG_PPC
++#ifdef FM_ERRATUM_A010022
+               /* Verify the skb a second time if it has been updated since
+                * the previous check
+                */
+-              if (unlikely(dpaa_errata_a010022) && skb_changed &&
++              if (unlikely(fm_has_errata_a010022()) && skb_changed &&
+                   a010022_check_skb(skb, priv))
+                       skb_need_wa = true;
+-              if (unlikely(dpaa_errata_a010022) && skb_need_wa) {
++              if (unlikely(fm_has_errata_a010022()) && skb_need_wa) {
+                       nskb = a010022_realign_skb(skb, priv);
+                       if (!nskb)
+                               goto skb_to_fd_failed;
+--- a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/dpaa_integration_ext.h
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/dpaa_integration_ext.h
+@@ -1,5 +1,6 @@
+ /*
+  * Copyright 2012 Freescale Semiconductor Inc.
++ * Copyright 2019 NXP
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions are met:
+@@ -270,6 +271,8 @@ typedef enum
+ #define FM_AID_MODE_NO_TNUM_SW005 /* refer to pdm TKT068794 - only support of port_id on aid */
+ #define FM_ERROR_VSP_NO_MATCH_SW006 /* refer to pdm TKT174304 - no match between errorQ and VSP */
++#define FM_ERRATUM_A010022
++
+ /*****************************************************************************
+  RMan INTEGRATION-SPECIFIC DEFINITIONS
+ ******************************************************************************/
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h
+@@ -1,5 +1,6 @@
+ /*
+  * Copyright 2008-2012 Freescale Semiconductor Inc.
++ * Copyright 2019 NXP
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions are met:
+@@ -489,6 +490,15 @@ int fm_get_max_frm(void);
+ int fm_get_rx_extra_headroom(void);
+ /**************************************************************************//**
++ @Function    fm_has_errata_a010022
++
++ @Description   Detect if the SoC is vulnerable to the A010022 errata
++*//***************************************************************************/
++#ifdef FM_ERRATUM_A010022
++bool fm_has_errata_a010022(void);
++#endif
++
++/**************************************************************************//**
+ @Function     fm_port_set_rate_limit
+ @Description  Configure Shaper parameter on FM-port device (Tx port).
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
+@@ -1,5 +1,6 @@
+ /*
+  * Copyright 2008-2012 Freescale Semiconductor Inc.
++ * Copyright 2019 NXP
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions are met:
+@@ -155,6 +156,10 @@ static int fsl_fm_pfc_quanta[] = {
+ static t_LnxWrpFm   lnxWrpFm;
++#ifdef FM_ERRATUM_A010022
++static bool fm_has_err_a010022;
++#endif
++
+ int fm_get_max_frm()
+ {
+       return fsl_fm_max_frm;
+@@ -167,6 +172,14 @@ int fm_get_rx_extra_headroom()
+ }
+ EXPORT_SYMBOL(fm_get_rx_extra_headroom);
++#ifdef FM_ERRATUM_A010022
++bool fm_has_errata_a010022(void)
++{
++      return fm_has_err_a010022;
++}
++EXPORT_SYMBOL(fm_has_errata_a010022);
++#endif
++
+ static int __init fm_set_max_frm(char *str)
+ {
+       int ret = 0;
+@@ -749,6 +762,10 @@ static t_LnxWrpFmDev * ReadFmDevTreeNode
+             p_LnxWrpFmDev->defPcd = e_NO_PCD;
+     }
++#ifdef FM_ERRATUM_A010022
++    fm_has_err_a010022 = of_property_read_bool(fm_node, "fsl,erratum-a010022");
++#endif
++
+     of_node_put(fm_node);
+     p_LnxWrpFmDev->hcCh =
diff --git a/target/linux/layerscape/patches-5.4/701-net-0361-sdk_dpaa-sdk_fman-ls1034a-errata-update-number-to-A0.patch b/target/linux/layerscape/patches-5.4/701-net-0361-sdk_dpaa-sdk_fman-ls1034a-errata-update-number-to-A0.patch
new file mode 100644 (file)
index 0000000..f9b0c70
--- /dev/null
@@ -0,0 +1,259 @@
+From 512bb2bd0555a8e78713dfdc109d87723a9da5c1 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Fri, 13 Dec 2019 14:49:16 +0200
+Subject: [PATCH] sdk_dpaa: sdk_fman: ls1034a errata: update number to A050385
+
+The A050385 erratum extends the A010022 erratum by defining additional
+FMan lock-up conditions and suggests new w/a restrictions.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h | 14 +++----
+ .../net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c  | 44 +++++++++++-----------
+ .../inc/integrations/LS1043/dpaa_integration_ext.h |  2 +-
+ .../sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h     |  8 ++--
+ .../freescale/sdk_fman/src/wrapper/lnxwrp_fm.c     | 16 ++++----
+ 5 files changed, 42 insertions(+), 42 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
+@@ -99,15 +99,15 @@ struct dpa_buffer_layout_s {
+  * space to account for further alignments.
+  */
+ #define DPA_MAX_FRM_SIZE      9600
+-#ifndef FM_ERRATUM_A010022
++#ifndef FM_ERRATUM_A050385
+ #define DPA_BP_RAW_SIZE \
+       ((DPA_MAX_FRM_SIZE + DPA_MAX_FD_OFFSET + \
+         sizeof(struct skb_shared_info) + 128) & ~(SMP_CACHE_BYTES - 1))
+-#else /* FM_ERRATUM_A010022 */
+-#define DPA_BP_RAW_SIZE ((unlikely(fm_has_errata_a010022())) ? 2048 : \
++#else /* FM_ERRATUM_A050385 */
++#define DPA_BP_RAW_SIZE ((unlikely(fm_has_errata_a050385())) ? 2048 : \
+       ((DPA_MAX_FRM_SIZE + DPA_MAX_FD_OFFSET + \
+         sizeof(struct skb_shared_info) + 128) & ~(SMP_CACHE_BYTES - 1)))
+-#endif /* FM_ERRATUM_A010022 */
++#endif /* FM_ERRATUM_A050385 */
+ #endif /* CONFIG_FSL_DPAA_ETH_JUMBO_FRAME */
+ /* This is what FMan is ever allowed to use.
+@@ -660,14 +660,14 @@ static inline void _dpa_bp_free_pf(void
+  * on egress.
+  */
+-#ifdef FM_ERRATUM_A010022
++#ifdef FM_ERRATUM_A050385
+ #define CROSS_4K(start, size) \
+       (((uintptr_t)(start) + (size)) > \
+        (((uintptr_t)(start) + 0x1000) & ~0xFFF))
+ /* The headroom needs to accommodate our private data (64 bytes) but
+  * we reserve 256 bytes instead to guarantee 256 data alignment.
+  */
+-#define DPAA_A010022_HEADROOM 256
+-#endif  /* FM_ERRATUM_A010022 */
++#define DPAA_A050385_HEADROOM 256
++#endif  /* FM_ERRATUM_A050385 */
+ #endif        /* __DPA_H */
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
+@@ -101,8 +101,8 @@ static int _dpa_bp_add_8_bufs(const stru
+                * We only need enough space to store a pointer, but allocate
+                * an entire cacheline for performance reasons.
+                */
+-#ifdef FM_ERRATUM_A010022
+-              if (unlikely(fm_has_errata_a010022())) {
++#ifdef FM_ERRATUM_A050385
++              if (unlikely(fm_has_errata_a050385())) {
+                       struct page *new_page = alloc_page(GFP_ATOMIC);
+                       if (unlikely(!new_page))
+                               goto netdev_alloc_failed;
+@@ -765,15 +765,15 @@ int __hot skb_to_contig_fd(struct dpa_pr
+ }
+ EXPORT_SYMBOL(skb_to_contig_fd);
+-#ifdef FM_ERRATUM_A010022
+-/* Verify the conditions that trigger the A010022 errata:
++#ifdef FM_ERRATUM_A050385
++/* Verify the conditions that trigger the A050385 errata:
+  * - 4K memory address boundary crossings when the data/SG fragments aren't
+  *   aligned to 256 bytes
+  * - data and SG fragments that aren't aligned to 16 bytes
+  * - SG fragments that aren't mod 16 bytes in size (except for the last
+  *   fragment)
+  */
+-static bool a010022_check_skb(struct sk_buff *skb, struct dpa_priv_s *priv)
++static bool a050385_check_skb(struct sk_buff *skb, struct dpa_priv_s *priv)
+ {
+       skb_frag_t *frag;
+       int i, nr_frags;
+@@ -840,7 +840,7 @@ static bool a010022_check_skb(struct sk_
+  * page. Build a new skb around the new buffer and release the old one.
+  * A performance drop should be expected.
+  */
+-static struct sk_buff *a010022_realign_skb(struct sk_buff *skb,
++static struct sk_buff *a050385_realign_skb(struct sk_buff *skb,
+                                          struct dpa_priv_s *priv)
+ {
+       int trans_offset = skb_transport_offset(skb);
+@@ -850,7 +850,7 @@ static struct sk_buff *a010022_realign_s
+       struct page *npage;
+       void *npage_addr;
+-      headroom = DPAA_A010022_HEADROOM;
++      headroom = DPAA_A050385_HEADROOM;
+       /* For the new skb we only need the old one's data (both non-paged and
+        * paged). We can skip the old tailroom.
+@@ -941,8 +941,8 @@ int __hot skb_to_sg_fd(struct dpa_priv_s
+       /* Get a page frag to store the SGTable, or a full page if the errata
+        * is in place and we need to avoid crossing a 4k boundary.
+        */
+-#ifdef FM_ERRATUM_A010022
+-      if (unlikely(fm_has_errata_a010022())) {
++#ifdef FM_ERRATUM_A050385
++      if (unlikely(fm_has_errata_a050385())) {
+               struct page *new_page = alloc_page(GFP_ATOMIC);
+               if (unlikely(!new_page))
+@@ -1099,9 +1099,9 @@ int __hot dpa_tx_extended(struct sk_buff
+       int *countptr, offset = 0;
+       struct sk_buff *nskb;
+-      /* Flags to help optimize the A010022 errata restriction checks.
++      /* Flags to help optimize the A050385 errata restriction checks.
+        *
+-       * First flag marks if the skb changed between the first A010022 check
++       * First flag marks if the skb changed between the first A050385 check
+        * and the moment it's converted to an FD.
+        *
+        * The second flag marks if the skb needs to be realigned in order to
+@@ -1121,8 +1121,8 @@ int __hot dpa_tx_extended(struct sk_buff
+       clear_fd(&fd);
+-#ifdef FM_ERRATUM_A010022
+-      if (unlikely(fm_has_errata_a010022()) && a010022_check_skb(skb, priv))
++#ifdef FM_ERRATUM_A050385
++      if (unlikely(fm_has_errata_a050385()) && a050385_check_skb(skb, priv))
+               skb_need_wa = true;
+ #endif
+@@ -1176,7 +1176,7 @@ int __hot dpa_tx_extended(struct sk_buff
+               /* We're going to store the skb backpointer at the beginning
+                * of the data buffer, so we need a privately owned skb
+                *
+-               * Under the A010022 errata, we are going to have a privately
++               * Under the A050385 errata, we are going to have a privately
+                * owned skb after realigning the current one, so no point in
+                * copying it here in that case.
+                */
+@@ -1194,12 +1194,12 @@ int __hot dpa_tx_extended(struct sk_buff
+                        * more fragments than we support. In this case,
+                        * we have no choice but to linearize it ourselves.
+                        */
+-#ifdef FM_ERRATUM_A010022
++#ifdef FM_ERRATUM_A050385
+                       /* No point in linearizing the skb now if we are going
+                        * to realign and linearize it again further down due
+-                       * to the A010022 errata
++                       * to the A050385 errata
+                        */
+-                      if (unlikely(fm_has_errata_a010022()))
++                      if (unlikely(fm_has_errata_a050385()))
+                               skb_need_wa = true;
+                       else
+ #endif
+@@ -1209,16 +1209,16 @@ int __hot dpa_tx_extended(struct sk_buff
+                       /* Common out-of-memory error path */
+                       goto enomem;
+-#ifdef FM_ERRATUM_A010022
++#ifdef FM_ERRATUM_A050385
+               /* Verify the skb a second time if it has been updated since
+                * the previous check
+                */
+-              if (unlikely(fm_has_errata_a010022()) && skb_changed &&
+-                  a010022_check_skb(skb, priv))
++              if (unlikely(fm_has_errata_a050385()) && skb_changed &&
++                  a050385_check_skb(skb, priv))
+                       skb_need_wa = true;
+-              if (unlikely(fm_has_errata_a010022()) && skb_need_wa) {
+-                      nskb = a010022_realign_skb(skb, priv);
++              if (unlikely(fm_has_errata_a050385()) && skb_need_wa) {
++                      nskb = a050385_realign_skb(skb, priv);
+                       if (!nskb)
+                               goto skb_to_fd_failed;
+                       dev_kfree_skb(skb);
+--- a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/dpaa_integration_ext.h
++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/dpaa_integration_ext.h
+@@ -271,7 +271,7 @@ typedef enum
+ #define FM_AID_MODE_NO_TNUM_SW005 /* refer to pdm TKT068794 - only support of port_id on aid */
+ #define FM_ERROR_VSP_NO_MATCH_SW006 /* refer to pdm TKT174304 - no match between errorQ and VSP */
+-#define FM_ERRATUM_A010022
++#define FM_ERRATUM_A050385
+ /*****************************************************************************
+  RMan INTEGRATION-SPECIFIC DEFINITIONS
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h
+@@ -490,12 +490,12 @@ int fm_get_max_frm(void);
+ int fm_get_rx_extra_headroom(void);
+ /**************************************************************************//**
+- @Function    fm_has_errata_a010022
++ @Function    fm_has_errata_a050385
+- @Description   Detect if the SoC is vulnerable to the A010022 errata
++ @Description   Detect if the SoC is vulnerable to the A050385 errata
+ *//***************************************************************************/
+-#ifdef FM_ERRATUM_A010022
+-bool fm_has_errata_a010022(void);
++#ifdef FM_ERRATUM_A050385
++bool fm_has_errata_a050385(void);
+ #endif
+ /**************************************************************************//**
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
+@@ -156,8 +156,8 @@ static int fsl_fm_pfc_quanta[] = {
+ static t_LnxWrpFm   lnxWrpFm;
+-#ifdef FM_ERRATUM_A010022
+-static bool fm_has_err_a010022;
++#ifdef FM_ERRATUM_A050385
++static bool fm_has_err_a050385;
+ #endif
+ int fm_get_max_frm()
+@@ -172,12 +172,12 @@ int fm_get_rx_extra_headroom()
+ }
+ EXPORT_SYMBOL(fm_get_rx_extra_headroom);
+-#ifdef FM_ERRATUM_A010022
+-bool fm_has_errata_a010022(void)
++#ifdef FM_ERRATUM_A050385
++bool fm_has_errata_a050385(void)
+ {
+-      return fm_has_err_a010022;
++      return fm_has_err_a050385;
+ }
+-EXPORT_SYMBOL(fm_has_errata_a010022);
++EXPORT_SYMBOL(fm_has_errata_a050385);
+ #endif
+ static int __init fm_set_max_frm(char *str)
+@@ -762,8 +762,8 @@ static t_LnxWrpFmDev * ReadFmDevTreeNode
+             p_LnxWrpFmDev->defPcd = e_NO_PCD;
+     }
+-#ifdef FM_ERRATUM_A010022
+-    fm_has_err_a010022 = of_property_read_bool(fm_node, "fsl,erratum-a010022");
++#ifdef FM_ERRATUM_A050385
++    fm_has_err_a050385 = of_property_read_bool(fm_node, "fsl,erratum-a050385");
+ #endif
+     of_node_put(fm_node);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0362-sdk_dpaa-ceetm-remove-references-to-qdisc_lookup.patch b/target/linux/layerscape/patches-5.4/701-net-0362-sdk_dpaa-ceetm-remove-references-to-qdisc_lookup.patch
new file mode 100644 (file)
index 0000000..652ab89
--- /dev/null
@@ -0,0 +1,111 @@
+From d6fc3dc5591ca4f0b2a5a77b210c622d8b709362 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Fri, 20 Dec 2019 15:56:53 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: remove references to qdisc_lookup
+
+In order to enable building the driver as a module, remove the
+references to the undefined qdisc_lookup symbol.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 49 ++++++++++++++++------
+ 1 file changed, 36 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -812,8 +812,8 @@ static int ceetm_init_prio(struct Qdisc
+       int err;
+       unsigned int i;
+       struct ceetm_class *parent_cl, *child_cl;
+-      struct Qdisc *parent_qdisc;
+       struct net_device *dev = qdisc_dev(sch);
++      struct Qdisc *root_qdisc = dev->qdisc;
+       pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+@@ -822,14 +822,18 @@ static int ceetm_init_prio(struct Qdisc
+               return -EINVAL;
+       }
+-      parent_qdisc = qdisc_lookup(dev, TC_H_MAJ(sch->parent));
+-      if (strcmp(parent_qdisc->ops->id, ceetm_qdisc_ops.id)) {
++      if (TC_H_MAJ(sch->parent) != TC_H_MAJ(root_qdisc->handle)) {
++              pr_err("CEETM: a prio ceetm qdiscs can be added only under a root ceetm class\n");
++              return -EINVAL;
++      }
++
++      if (strcmp(root_qdisc->ops->id, ceetm_qdisc_ops.id)) {
+               pr_err("CEETM: a ceetm qdisc can not be attached to other qdisc/class types\n");
+               return -EINVAL;
+       }
+       /* Obtain the parent root ceetm_class */
+-      parent_cl = ceetm_find(sch->parent, parent_qdisc);
++      parent_cl = ceetm_find(sch->parent, root_qdisc);
+       if (!parent_cl || parent_cl->type != CEETM_ROOT) {
+               pr_err("CEETM: a prio ceetm qdiscs can be added only under a root ceetm class\n");
+@@ -902,9 +906,9 @@ static int ceetm_init_wbfs(struct Qdisc
+ {
+       int err, group_b, small_group;
+       unsigned int i, id, prio_a, prio_b;
+-      struct ceetm_class *parent_cl, *child_cl, *root_cl;
+-      struct Qdisc *parent_qdisc;
+-      struct ceetm_qdisc *parent_priv;
++      struct ceetm_class *parent_cl, *child_cl, *tmp_cl, *root_cl = NULL;
++      struct Qdisc *root_qdisc, *parent_qdisc = NULL;
++      struct ceetm_qdisc *root_priv;
+       struct net_device *dev = qdisc_dev(sch);
+       pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+@@ -915,16 +919,37 @@ static int ceetm_init_wbfs(struct Qdisc
+               return -EINVAL;
+       }
+-      /* Obtain the parent prio ceetm qdisc */
+-      parent_qdisc = qdisc_lookup(dev, TC_H_MAJ(sch->parent));
+-      if (strcmp(parent_qdisc->ops->id, ceetm_qdisc_ops.id)) {
++      root_qdisc = dev->qdisc;
++
++      if (strcmp(root_qdisc->ops->id, ceetm_qdisc_ops.id)) {
+               pr_err("CEETM: a ceetm qdisc can not be attached to other qdisc/class types\n");
+               return -EINVAL;
+       }
++      root_priv = qdisc_priv(root_qdisc);
++
++      /* Obtain the root ceetm class and the parent prio ceetm qdisc */
++      for (i = 0; i < root_priv->clhash.hashsize; i++) {
++              hlist_for_each_entry(tmp_cl, &root_priv->clhash.hash[i],
++                                   common.hnode) {
++                      if (tmp_cl->root.child &&
++                          (TC_H_MAJ(tmp_cl->root.child->handle) ==
++                          TC_H_MAJ(sch->parent))) {
++                              parent_qdisc = tmp_cl->root.child;
++                              root_cl = tmp_cl;
++                              break;
++                      }
++              }
++      }
++
++      if (!parent_qdisc ||
++          strcmp(parent_qdisc->ops->id, ceetm_qdisc_ops.id)) {
++              pr_err("CEETM: a wbfs ceetm qdiscs can be added only under a prio ceetm class\n");
++              return -EINVAL;
++      }
++
+       /* Obtain the parent prio ceetm class */
+       parent_cl = ceetm_find(sch->parent, parent_qdisc);
+-      parent_priv = qdisc_priv(parent_qdisc);
+       if (!parent_cl || parent_cl->type != CEETM_PRIO) {
+               pr_err("CEETM: a wbfs ceetm qdiscs can be added only under a prio ceetm class\n");
+@@ -948,8 +973,6 @@ static int ceetm_init_wbfs(struct Qdisc
+               return -EINVAL;
+       }
+-      /* Obtain the parent root ceetm class */
+-      root_cl = parent_priv->prio.parent;
+       if ((root_cl->root.wbfs_grp_a && root_cl->root.wbfs_grp_b) ||
+           root_cl->root.wbfs_grp_large) {
+               pr_err("CEETM: no more wbfs classes are available\n");
diff --git a/target/linux/layerscape/patches-5.4/701-net-0363-sdk_dpaa-ceetm-export-the-ceetm_tx-symbol.patch b/target/linux/layerscape/patches-5.4/701-net-0363-sdk_dpaa-ceetm-export-the-ceetm_tx-symbol.patch
new file mode 100644 (file)
index 0000000..0d82df4
--- /dev/null
@@ -0,0 +1,23 @@
+From c741a131f2fb267b5b3bb333aca2453a07536535 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Fri, 20 Dec 2019 16:00:07 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: export the ceetm_tx symbol
+
+In order to enable building the driver as a module, export the ceetm_tx
+symbol for the DPAA Ethernet driver to use.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -2077,6 +2077,7 @@ drop:
+       dev_kfree_skb_any(skb);
+       return NET_XMIT_SUCCESS;
+ }
++EXPORT_SYMBOL(ceetm_tx);
+ static int __init ceetm_register(void)
+ {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0364-sdk_dpaa-ceetm-enable-building-as-a-module.patch b/target/linux/layerscape/patches-5.4/701-net-0364-sdk_dpaa-ceetm-enable-building-as-a-module.patch
new file mode 100644 (file)
index 0000000..a1bc652
--- /dev/null
@@ -0,0 +1,40 @@
+From 047bb6ca46d7cd8b2400bfbf062469ff84cec3d3 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Fri, 20 Dec 2019 16:01:23 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: enable building as a module
+
+Enable building the driver as a module by adding the required module
+macros and creating the fsl_ceetm object file.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/Makefile         | 4 +++-
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 2 ++
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/Makefile
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/Makefile
+@@ -17,9 +17,11 @@ endif
+ ifeq ($(CONFIG_FSL_DPAA_1588),y)
+ fsl_dpa-objs += dpaa_1588.o
+ endif
++
+ ifeq ($(CONFIG_FSL_DPAA_CEETM),y)
+ ccflags-y += -I$(srctree)/drivers/net/ethernet/freescale/sdk_fman/src/wrapper
+-fsl_dpa-objs += dpaa_eth_ceetm.o
++obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_ceetm.o
++fsl_ceetm-objs += dpaa_eth_ceetm.o
+ endif
+ fsl_mac-objs += mac.o mac-api.o
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -33,6 +33,8 @@
+ #include "dpaa_eth_ceetm.h"
+ #define DPA_CEETM_DESCRIPTION "FSL DPAA CEETM qdisc"
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_DESCRIPTION(DPA_CEETM_DESCRIPTION);
+ const struct nla_policy ceetm_policy[TCA_CEETM_MAX + 1] = {
+       [TCA_CEETM_COPT] = { .len = sizeof(struct tc_ceetm_copt) },
diff --git a/target/linux/layerscape/patches-5.4/701-net-0365-sdk_dpaa-ceetm-coding-style-cleanup.patch b/target/linux/layerscape/patches-5.4/701-net-0365-sdk_dpaa-ceetm-coding-style-cleanup.patch
new file mode 100644 (file)
index 0000000..13ae5e5
--- /dev/null
@@ -0,0 +1,431 @@
+From fec484580477d93cd69e5355be68e6f5bf1a1e54 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Mon, 9 Dec 2019 18:20:05 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: coding style cleanup
+
+Fix checkpatch warnings and use reverse Christmas tree variable ordering
+throughout the driver.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 145 +++++++++++----------
+ 1 file changed, 76 insertions(+), 69 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -1,4 +1,5 @@
+ /* Copyright 2008-2016 Freescale Semiconductor Inc.
++ * Copyright 2019 NXP
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions are met:
+@@ -47,10 +48,10 @@ struct Qdisc_ops ceetm_qdisc_ops;
+ static void get_dcp_and_sp(struct net_device *dev, enum qm_dc_portal *dcp_id,
+                          unsigned int *sp_id)
+ {
+-      uint32_t channel;
+-      t_LnxWrpFmPortDev *port_dev;
+       struct dpa_priv_s *dpa_priv = netdev_priv(dev);
+       struct mac_device *mac_dev = dpa_priv->mac_dev;
++      t_LnxWrpFmPortDev *port_dev;
++      uint32_t channel;
+       port_dev = (t_LnxWrpFmPortDev *)mac_dev->port_dev[TX];
+       channel = port_dev->txCh;
+@@ -75,7 +76,7 @@ static void dpaa_drain_fqs(struct net_de
+       struct qman_fq *fq;
+       int ret, i;
+-      for (i = 0; i < DPAA_ETH_TX_QUEUES; i ++) {
++      for (i = 0; i < DPAA_ETH_TX_QUEUES; i++) {
+               fq = priv->egress_fqs[i];
+               while (true) {
+                       ret = qman_query_fq_np(fq, &np);
+@@ -96,7 +97,7 @@ static void dpaa_drain_fqs(struct net_de
+ static void ceetm_drain_class(struct ceetm_class *cl)
+ {
+       struct qm_mcr_ceetm_cq_query cq_query;
+-      struct qm_ceetm_cq *cq;
++      struct qm_ceetm_cq *cq = NULL;
+       unsigned int idx;
+       int ret;
+@@ -108,10 +109,10 @@ static void ceetm_drain_class(struct cee
+               /* The ROOT classes aren't directly linked to CEETM CQs */
+               return;
+       case CEETM_PRIO:
+-              cq = (struct qm_ceetm_cq*)cl->prio.cq;
++              cq = (struct qm_ceetm_cq *)cl->prio.cq;
+               break;
+       case CEETM_WBFS:
+-              cq = (struct qm_ceetm_cq*)cl->wbfs.cq;
++              cq = (struct qm_ceetm_cq *)cl->wbfs.cq;
+               break;
+       }
+@@ -190,10 +191,14 @@ static void ceetm_ern(struct qman_portal
+ /* Congestion State Change Notification callback */
+ static void ceetm_cscn(struct qm_ceetm_ccg *ccg, void *cb_ctx, int congested)
+ {
+-      struct ceetm_fq *ceetm_fq = (struct ceetm_fq *)cb_ctx;
+-      struct dpa_priv_s *dpa_priv = netdev_priv(ceetm_fq->net_dev);
+-      struct ceetm_class *cls = ceetm_fq->ceetm_cls;
+       struct ceetm_class_stats *cstats = NULL;
++      struct dpa_priv_s *dpa_priv;
++      struct ceetm_fq *ceetm_fq;
++      struct ceetm_class *cls;
++
++      ceetm_fq = (struct ceetm_fq *)cb_ctx;
++      dpa_priv = netdev_priv(ceetm_fq->net_dev);
++      cls = ceetm_fq->ceetm_cls;
+       switch (cls->type) {
+       case CEETM_PRIO:
+@@ -236,10 +241,10 @@ static int ceetm_config_ccg(struct qm_ce
+                           struct qm_ceetm_channel *channel, unsigned int id,
+                           struct ceetm_fq *fq, struct dpa_priv_s *dpa_priv)
+ {
+-      int err;
+-      u32 cs_th;
+-      u16 ccg_mask;
+       struct qm_ceetm_ccg_params ccg_params;
++      u16 ccg_mask;
++      u32 cs_th;
++      int err;
+       err = qman_ceetm_ccg_claim(ccg, channel, id, ceetm_cscn, fq);
+       if (err)
+@@ -284,9 +289,9 @@ static int ceetm_config_ccg(struct qm_ce
+ static int ceetm_config_lfq(struct qm_ceetm_cq *cq, struct ceetm_fq *fq,
+                           struct qm_ceetm_lfq **lfq)
+ {
+-      int err;
+       u64 context_a;
+       u32 context_b;
++      int err;
+       err = qman_ceetm_lfq_claim(lfq, cq);
+       if (err)
+@@ -316,8 +321,8 @@ static int ceetm_config_prio_cls(struct
+                                struct net_device *dev,
+                                unsigned int id)
+ {
+-      int err;
+       struct dpa_priv_s *dpa_priv = netdev_priv(dev);
++      int err;
+       err = ceetm_alloc_fq(&cls->prio.fq, dev, cls);
+       if (err)
+@@ -357,8 +362,8 @@ static int ceetm_config_wbfs_cls(struct
+                                struct net_device *dev,
+                                unsigned int id, int type)
+ {
+-      int err;
+       struct dpa_priv_s *dpa_priv = netdev_priv(dev);
++      int err;
+       err = ceetm_alloc_fq(&cls->wbfs.fq, dev, cls);
+       if (err)
+@@ -517,11 +522,11 @@ static void ceetm_cls_destroy(struct Qdi
+ /* Destroy a ceetm qdisc */
+ static void ceetm_destroy(struct Qdisc *sch)
+ {
+-      unsigned int ntx, i;
+-      struct hlist_node *next;
+-      struct ceetm_class *cl;
+       struct ceetm_qdisc *priv = qdisc_priv(sch);
+       struct net_device *dev = qdisc_dev(sch);
++      struct hlist_node *next;
++      struct ceetm_class *cl;
++      unsigned int ntx, i;
+       pr_debug(KBUILD_BASENAME " : %s : destroy qdisc %X\n",
+                __func__, sch->handle);
+@@ -592,13 +597,13 @@ static void ceetm_destroy(struct Qdisc *
+ static int ceetm_dump(struct Qdisc *sch, struct sk_buff *skb)
+ {
++      struct ceetm_qdisc *priv = qdisc_priv(sch);
++      struct net_device *dev = qdisc_dev(sch);
++      struct ceetm_qdisc_stats *qstats;
++      struct tc_ceetm_qopt qopt;
+       struct Qdisc *qdisc;
+       unsigned int ntx, i;
+       struct nlattr *nest;
+-      struct tc_ceetm_qopt qopt;
+-      struct ceetm_qdisc_stats *qstats;
+-      struct net_device *dev = qdisc_dev(sch);
+-      struct ceetm_qdisc *priv = qdisc_priv(sch);
+       pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+@@ -673,17 +678,20 @@ static int ceetm_init_root(struct Qdisc
+                          struct tc_ceetm_qopt *qopt,
+                          struct netlink_ext_ack *extack)
+ {
++      struct net_device *dev = qdisc_dev(sch);
++      unsigned int i, sp_id, parent_id;
+       struct netdev_queue *dev_queue;
+-      struct Qdisc *qdisc;
++      struct dpa_priv_s *dpa_priv;
++      struct mac_device *mac_dev;
+       enum qm_dc_portal dcp_id;
+-      unsigned int i, sp_id, parent_id;
++      struct qm_ceetm_lni *lni;
++      struct qm_ceetm_sp *sp;
++      struct Qdisc *qdisc;
+       int err;
+       u64 bps;
+-      struct qm_ceetm_sp *sp;
+-      struct qm_ceetm_lni *lni;
+-      struct net_device *dev = qdisc_dev(sch);
+-      struct dpa_priv_s *dpa_priv = netdev_priv(dev);
+-      struct mac_device *mac_dev = dpa_priv->mac_dev;
++
++      dpa_priv = netdev_priv(dev);
++      mac_dev = dpa_priv->mac_dev;
+       pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+@@ -711,9 +719,8 @@ static int ceetm_init_root(struct Qdisc
+       priv->root.qdiscs = kcalloc(dev->num_tx_queues,
+                                   sizeof(priv->root.qdiscs[0]),
+                                   GFP_KERNEL);
+-      if (!priv->root.qdiscs) {
++      if (!priv->root.qdiscs)
+               return -ENOMEM;
+-      }
+       for (i = 0; i < dev->num_tx_queues; i++) {
+               dev_queue = netdev_get_tx_queue(dev, i);
+@@ -811,11 +818,11 @@ static int ceetm_init_root(struct Qdisc
+ static int ceetm_init_prio(struct Qdisc *sch, struct ceetm_qdisc *priv,
+                          struct tc_ceetm_qopt *qopt)
+ {
+-      int err;
+-      unsigned int i;
+       struct ceetm_class *parent_cl, *child_cl;
+       struct net_device *dev = qdisc_dev(sch);
+       struct Qdisc *root_qdisc = dev->qdisc;
++      unsigned int i;
++      int err;
+       pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+@@ -852,11 +859,8 @@ static int ceetm_init_prio(struct Qdisc
+       /* Create and configure qcount child classes */
+       for (i = 0; i < priv->prio.qcount; i++) {
+               child_cl = kzalloc(sizeof(*child_cl), GFP_KERNEL);
+-              if (!child_cl) {
+-                      pr_err(KBUILD_BASENAME " : %s : kzalloc() failed\n",
+-                             __func__);
++              if (!child_cl)
+                       return -ENOMEM;
+-              }
+               child_cl->prio.cstats = alloc_percpu(struct ceetm_class_stats);
+               if (!child_cl->prio.cstats) {
+@@ -906,12 +910,12 @@ err_init_prio_cls:
+ static int ceetm_init_wbfs(struct Qdisc *sch, struct ceetm_qdisc *priv,
+                          struct tc_ceetm_qopt *qopt)
+ {
+-      int err, group_b, small_group;
+-      unsigned int i, id, prio_a, prio_b;
+       struct ceetm_class *parent_cl, *child_cl, *tmp_cl, *root_cl = NULL;
+       struct Qdisc *root_qdisc, *parent_qdisc = NULL;
+-      struct ceetm_qdisc *root_priv;
+       struct net_device *dev = qdisc_dev(sch);
++      unsigned int i, id, prio_a, prio_b;
++      int err, group_b, small_group;
++      struct ceetm_qdisc *root_priv;
+       pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+@@ -1070,11 +1074,8 @@ static int ceetm_init_wbfs(struct Qdisc
+       /* Create qcount child classes */
+       for (i = 0; i < priv->wbfs.qcount; i++) {
+               child_cl = kzalloc(sizeof(*child_cl), GFP_KERNEL);
+-              if (!child_cl) {
+-                      pr_err(KBUILD_BASENAME " : %s : kzalloc() failed\n",
+-                             __func__);
++              if (!child_cl)
+                       return -ENOMEM;
+-              }
+               child_cl->wbfs.cstats = alloc_percpu(struct ceetm_class_stats);
+               if (!child_cl->wbfs.cstats) {
+@@ -1138,11 +1139,11 @@ err_init_wbfs_cls:
+ static int ceetm_init(struct Qdisc *sch, struct nlattr *opt,
+                     struct netlink_ext_ack *extack)
+ {
+-      struct tc_ceetm_qopt *qopt;
+-      struct nlattr *tb[TCA_CEETM_QOPS + 1];
+-      int ret;
+       struct ceetm_qdisc *priv = qdisc_priv(sch);
+       struct net_device *dev = qdisc_dev(sch);
++      struct nlattr *tb[TCA_CEETM_QOPS + 1];
++      struct tc_ceetm_qopt *qopt;
++      int ret;
+       pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+@@ -1158,7 +1159,8 @@ static int ceetm_init(struct Qdisc *sch,
+       if (ret)
+               return ret;
+-      ret = nla_parse_nested_deprecated(tb, TCA_CEETM_QOPS, opt, ceetm_policy, NULL);
++      ret = nla_parse_nested_deprecated(tb, TCA_CEETM_QOPS, opt,
++                                        ceetm_policy, NULL);
+       if (ret < 0) {
+               pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+               return ret;
+@@ -1265,8 +1267,8 @@ change_err:
+ static int ceetm_change_wbfs(struct Qdisc *sch, struct ceetm_qdisc *priv,
+                            struct tc_ceetm_qopt *qopt)
+ {
+-      int err;
+       bool group_b;
++      int err;
+       if (qopt->qcount) {
+               pr_err("CEETM: the qcount can not be modified\n");
+@@ -1324,15 +1326,16 @@ change_err:
+ static int ceetm_change(struct Qdisc *sch, struct nlattr *opt,
+                       struct netlink_ext_ack *extack)
+ {
+-      struct tc_ceetm_qopt *qopt;
+-      struct nlattr *tb[TCA_CEETM_QOPS + 1];
+-      int ret;
+       struct ceetm_qdisc *priv = qdisc_priv(sch);
+       struct net_device *dev = qdisc_dev(sch);
++      struct nlattr *tb[TCA_CEETM_QOPS + 1];
++      struct tc_ceetm_qopt *qopt;
++      int ret;
+       pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+-      ret = nla_parse_nested_deprecated(tb, TCA_CEETM_QOPS, opt, ceetm_policy, NULL);
++      ret = nla_parse_nested_deprecated(tb, TCA_CEETM_QOPS, opt,
++                                        ceetm_policy, NULL);
+       if (ret < 0) {
+               pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+               return ret;
+@@ -1381,8 +1384,8 @@ static int ceetm_change(struct Qdisc *sc
+  */
+ static void ceetm_attach(struct Qdisc *sch)
+ {
+-      struct net_device *dev = qdisc_dev(sch);
+       struct ceetm_qdisc *priv = qdisc_priv(sch);
++      struct net_device *dev = qdisc_dev(sch);
+       struct Qdisc *qdisc, *old_qdisc;
+       unsigned int i;
+@@ -1461,8 +1464,8 @@ static int ceetm_cls_change_prio(struct
+       }
+       if (cl->prio.cr != (bool)copt->cr) {
+-              err = qman_ceetm_channel_set_cq_cr_eligibility(
+-                                              cl->prio.cq->parent,
++              err = qman_ceetm_channel_set_cq_cr_eligibility
++                                              (cl->prio.cq->parent,
+                                               cl->prio.cq->idx,
+                                               copt->cr);
+               if (err)
+@@ -1471,8 +1474,8 @@ static int ceetm_cls_change_prio(struct
+       }
+       if (cl->prio.er != (bool)copt->er) {
+-              err = qman_ceetm_channel_set_cq_er_eligibility(
+-                                              cl->prio.cq->parent,
++              err = qman_ceetm_channel_set_cq_er_eligibility
++                                              (cl->prio.cq->parent,
+                                               cl->prio.cq->idx,
+                                               copt->er);
+               if (err)
+@@ -1517,15 +1520,15 @@ static int ceetm_cls_change(struct Qdisc
+                           struct nlattr **tca, unsigned long *arg,
+                           struct netlink_ext_ack *extack)
+ {
+-      int err;
+-      u64 bps;
+-      struct ceetm_qdisc *priv;
+       struct ceetm_class *cl = (struct ceetm_class *)*arg;
++      struct net_device *dev = qdisc_dev(sch);
+       struct nlattr *opt = tca[TCA_OPTIONS];
+       struct nlattr *tb[__TCA_CEETM_MAX];
+-      struct tc_ceetm_copt *copt;
+       struct qm_ceetm_channel *channel;
+-      struct net_device *dev = qdisc_dev(sch);
++      struct tc_ceetm_copt *copt;
++      struct ceetm_qdisc *priv;
++      int err;
++      u64 bps;
+       pr_debug(KBUILD_BASENAME " : %s : classid %X under qdisc %X\n",
+                __func__, classid, sch->handle);
+@@ -1552,7 +1555,8 @@ static int ceetm_cls_change(struct Qdisc
+               return -EINVAL;
+       }
+-      err = nla_parse_nested_deprecated(tb, TCA_CEETM_COPT, opt, ceetm_policy, NULL);
++      err = nla_parse_nested_deprecated(tb, TCA_CEETM_COPT, opt,
++                                        ceetm_policy, NULL);
+       if (err < 0) {
+               pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+               return -EINVAL;
+@@ -1714,8 +1718,8 @@ static int ceetm_cls_dump(struct Qdisc *
+                         struct sk_buff *skb, struct tcmsg *tcm)
+ {
+       struct ceetm_class *cl = (struct ceetm_class *)arg;
+-      struct nlattr *nest;
+       struct tc_ceetm_copt copt;
++      struct nlattr *nest;
+       pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
+                __func__, cl->common.classid, sch->handle);
+@@ -1770,8 +1774,8 @@ nla_put_failure:
+ static int ceetm_cls_delete(struct Qdisc *sch, unsigned long arg)
+ {
+-      struct ceetm_qdisc *priv = qdisc_priv(sch);
+       struct ceetm_class *cl = (struct ceetm_class *)arg;
++      struct ceetm_qdisc *priv = qdisc_priv(sch);
+       pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
+                __func__, cl->common.classid, sch->handle);
+@@ -1818,12 +1822,12 @@ static int ceetm_cls_graft(struct Qdisc
+ static int ceetm_cls_dump_stats(struct Qdisc *sch, unsigned long arg,
+                               struct gnet_dump *d)
+ {
+-      unsigned int i;
+       struct ceetm_class *cl = (struct ceetm_class *)arg;
+       struct gnet_stats_basic_packed tmp_bstats;
+       struct ceetm_class_stats *cstats = NULL;
+       struct qm_ceetm_cq *cq = NULL;
+       struct tc_ceetm_xstats xstats;
++      unsigned int i;
+       memset(&xstats, 0, sizeof(xstats));
+       memset(&tmp_bstats, 0, sizeof(tmp_bstats));
+@@ -1872,9 +1876,11 @@ static int ceetm_cls_dump_stats(struct Q
+ static struct tcf_block *ceetm_tcf_block(struct Qdisc *sch, unsigned long arg,
+                                        struct netlink_ext_ack *extack)
+ {
+-      struct ceetm_qdisc *priv = qdisc_priv(sch);
+       struct ceetm_class *cl = (struct ceetm_class *)arg;
+-      struct tcf_block *block = cl ? cl->block : priv->block;
++      struct ceetm_qdisc *priv = qdisc_priv(sch);
++      struct tcf_block *block;
++
++      block = cl ? cl->block : priv->block;
+       pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
+                cl ? cl->common.classid : 0, sch->handle);
+@@ -1945,6 +1951,7 @@ static struct ceetm_class *ceetm_classif
+               case TC_ACT_STOLEN:
+               case TC_ACT_TRAP:
+                       *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
++                      /* fall through */
+               case TC_ACT_SHOT:
+                       /* No valid class found due to action */
+                       *act_drop = true;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0366-LF-697-net-ethernet-freescale-sdk_fman-fix-the-build.patch b/target/linux/layerscape/patches-5.4/701-net-0366-LF-697-net-ethernet-freescale-sdk_fman-fix-the-build.patch
new file mode 100644 (file)
index 0000000..9c38b48
--- /dev/null
@@ -0,0 +1,280 @@
+From 43be5f0f6c36e23d6f51c1f1f55ebcec920cc453 Mon Sep 17 00:00:00 2001
+From: Jason Liu <jason.hui.liu@nxp.com>
+Date: Thu, 2 Jan 2020 12:46:37 +0800
+Subject: [PATCH] LF-697 net: ethernet: freescale: sdk_fman: fix the build
+ warnings
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The patch fixes the build warnings by adding the comments 'fall through' to avoid the build warnings
+The patch also initializes the value pgid_val to avoid the warning: ‘pgid_val’ may be used uninitialized
+The patch should not and will not have any function impact.
+
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c: In function ‘ValidateNextEngineParams’:
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c:1681:51: warning: this statement may fall through [-Wimplicit-fallthrough=]
+In file included from drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c:40:
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c: In function ‘GetGenHdrCode’:
+drivers/net/ethernet/freescale/sdk_fman/inc/error_ext.h:446:12: warning: this statement may fall through [-Wimplicit-fallthrough=]
+In file included from drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c:40:
+drivers/net/ethernet/freescale/sdk_fman/inc/error_ext.h:446:12: warning: this statement may fall through [-Wimplicit-fallthrough=]
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c:255:13: note: here
+  255 |             case (HEADER_TYPE_ETH):
+      |             ^~~~
+In file included from drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c:40:
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c:278:13: note: here
+  278 |             case (HEADER_TYPE_MINENCAP):
+      |             ^~~~
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c: In function ‘BuildHmct’:
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c:673:32: warning: this statement may fall through [-Wimplicit-fallthrough=]
+  673 |                         tmpReg = HMCD_INSRT_UDP_LITE;
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c:674:21: note: here
+  674 |                     case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP):
+      |                     ^~~~
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c: In function ‘FM_PORT_Config’:
+arch/arm64/include/asm/io.h:36:22: warning: this statement may fall through [-Wimplicit-fallthrough=]
+   36 | #define __raw_writel __raw_writel
+drivers/net/ethernet/freescale/sdk_fman/src/inc/types_linux.h:99:25: note: in expansion of macro ‘__raw_writel’
+   99 | #define out_be32(a, v)  __raw_writel(__cpu_to_be32(v), a)
+      |                         ^~~~~~~~~~~~
+drivers/net/ethernet/freescale/sdk_fman/src/inc/types_linux.h:121:37: note: in expansion of macro ‘out_be32’
+  121 | #define WRITE_UINT32(arg, data)     out_be32(&(arg), data)//*(volatile unsigned int *)(&(arg)) = (data)
+      |                                     ^~~~~~~~
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c:2404:13: note: in expansion of macro ‘WRITE_UINT32’
+ 2404 |             WRITE_UINT32( p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfp,
+      |             ^~~~~~~~~~~~
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c:2407:9: note: here
+ 2407 |         case (e_FM_PORT_TYPE_TX_10G):
+      |         ^~~~
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c:2435:60: warning: this statement may fall through [-Wimplicit-fallthrough=]
+ 2435 |             p_FmPort->p_FmPortDriverParam->noScatherGather =
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c:2438:9: note: here
+ 2438 |         case (e_FM_PORT_TYPE_OH_HOST_COMMAND):
+      |         ^~~~
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c: In function ‘FM_PORT_ModifyCounter’:
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c:4268:16: warning: this statement may fall through [-Wimplicit-fallthrough=]
+ 4268 |             if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
+      |                ^
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c:4273:9: note: here
+ 4273 |         case (e_FM_PORT_COUNTERS_ENQ_TOTAL):
+      |         ^~~~
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c: In function ‘SetPcd’:
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c:1396:24: warning: this statement may fall through [-Wimplicit-fallthrough=]
+ 1396 |                 tmpReg = NIA_KG_CC_EN;
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c:1397:13: note: here
+ 1397 |             case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG):
+      |             ^~~~
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c: In function ‘FM_GetCounter’:
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c:4804:16: warning: this statement may fall through [-Wimplicit-fallthrough=]
+ 4804 |             if ((p_Fm->p_FmStateStruct->revInfo.majorRev == 4) ||
+      |                ^
+drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c:4810:9: note: here
+ 4810 |         case (e_FM_COUNTERS_ENQ_TOTAL_FRAME):
+      |         ^~~~
+drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c: In function ‘fm_get_counter’:
+drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c:1803:6: warning: this statement may fall through [-Wimplicit-fallthrough=]
+ 1803 |   if (p_fm->p_FmStateStruct->revInfo.majorRev >= 6)
+      |      ^
+drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c:1806:2: note: here
+ 1806 |  case (e_FM_COUNTERS_ENQ_TOTAL_FRAME):
+      |  ^~~~
+drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c: In function ‘compat_copy_fm_pcd_cc_next_engine’:
+drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c:378:33: warning: this statement may fall through [-Wimplicit-fallthrough=]
+  378 |                 param->manip_id = compat_pcd_id2ptr(compat_param->manip_id);
+      |                 ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c:379:13: note: here
+  379 |             default:
+      |             ^~~~~~~
+drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c:405:40: warning: this statement may fall through [-Wimplicit-fallthrough=]
+  405 |                 compat_param->manip_id = compat_pcd_ptr2id(param->manip_id);
+      |                 ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c:406:13: note: here
+  406 |             default:
+      |             ^~~~~~~
+In file included from drivers/net/ethernet/mscc/ocelot.h:21,
+                 from drivers/net/ethernet/mscc/ocelot_tsn.c:12:
+drivers/net/ethernet/mscc/ocelot_tsn.c: In function ‘ocelot_seq_gen_set’:
+include/soc/mscc/ocelot.h:499:48: warning: ‘pgid_val’ may be used uninitialized in this function [-Wmaybe-uninitialized]
+  499 | #define ocelot_write_rix(ocelot, val, reg, ri) __ocelot_write_ix(ocelot, val, reg, reg##_RSZ * (ri))
+      |                                                ^~~~~~~~~~~~~~~~~
+drivers/net/ethernet/mscc/ocelot_tsn.c:755:5: note: ‘pgid_val’ was declared here
+  755 |  u8 pgid_val, fwdport;
+
+Signed-off-by: Jason Liu <jason.hui.liu@nxp.com>
+Cc: Madalin Bucur <madalin.bucur@nxp.com>
+Reviewed-by: Fugang Duan <fugang.duan@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c   | 1 +
+ drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c   | 4 ++++
+ .../net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c    | 1 +
+ .../net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c    | 5 +++++
+ drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c          | 3 +++
+ .../freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c         | 2 ++
+ .../net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c    | 3 +++
+ drivers/net/ethernet/mscc/ocelot_tsn.c                               | 2 +-
+ 8 files changed, 20 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c
+@@ -1679,6 +1679,7 @@ t_Error ValidateNextEngineParams(
+         case (e_FM_PCD_HASH):
+             p_FmPcdCcNextEngineParams->nextEngine = e_FM_PCD_CC;
++            /* fall through */
+         case (e_FM_PCD_CC):
+             if (!p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode)
+                 RETURN_ERROR(MAJOR, E_NULL_POINTER,
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c
+@@ -198,6 +198,7 @@ static uint8_t GetGenHdrCode(e_NetHeader
+         {
+             case (HEADER_TYPE_NONE):
+                 ASSERT_COND(FALSE);
++              /* Else fall through */
+             case (HEADER_TYPE_ETH):
+                 return KG_SCH_GEN_ETH;
+             case (HEADER_TYPE_LLC_SNAP):
+@@ -252,6 +253,7 @@ static uint8_t GetGenHdrCode(e_NetHeader
+         {
+             case (HEADER_TYPE_NONE):
+                 ASSERT_COND(FALSE);
++              /* Else fall through */
+             case (HEADER_TYPE_ETH):
+                 return KG_SCH_GEN_ETH_NO_V;
+             case (HEADER_TYPE_LLC_SNAP):
+@@ -269,12 +271,14 @@ static uint8_t GetGenHdrCode(e_NetHeader
+                     REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS header index"));
+                 return 0;
+             case (HEADER_TYPE_IPv4):
++              /* fall through */
+             case (HEADER_TYPE_IPv6):
+                 if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
+                     return KG_SCH_GEN_L3_NO_V;
+                 if ((hdrIndex == e_FM_PCD_HDR_INDEX_2) || (hdrIndex == e_FM_PCD_HDR_INDEX_LAST))
+                     return KG_SCH_GEN_IP2_NO_V;
+                 REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP header index"));
++              /* fall through */
+             case (HEADER_TYPE_MINENCAP):
+                 return KG_SCH_GEN_IP2_NO_V;
+             case (HEADER_TYPE_USER_DEFINED_L3):
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c
+@@ -671,6 +671,7 @@ static t_Error BuildHmct(t_FmPcdManip *p
+                         break;
+                     case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE):
+                         tmpReg = HMCD_INSRT_UDP_LITE;
++                      /* fall through */
+                     case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP):
+                         tmpReg |= (uint32_t)(HMCD_OPCODE_UDP_INSRT)
+                                 << HMCD_OC_SHIFT;
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c
+@@ -1394,6 +1394,7 @@ static t_Error SetPcd(t_FmPort *p_FmPort
+             case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC):
+             case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR):
+                 tmpReg = NIA_KG_CC_EN;
++                /* fall through */
+             case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG):
+             case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR):
+                 if (p_PcdParams->p_KgParams->directScheme)
+@@ -2404,6 +2405,8 @@ t_Handle FM_PORT_Config(t_FmPortParams *
+             WRITE_UINT32( p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfp,
+                          tmpReg);
+ #endif /* FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 */
++
++            /* fall through */
+         case (e_FM_PORT_TYPE_TX_10G):
+                 tmpReg =
+                         GET_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfp);
+@@ -2435,6 +2438,7 @@ t_Handle FM_PORT_Config(t_FmPortParams *
+             p_FmPort->p_FmPortDriverParam->noScatherGather =
+                     DEFAULT_PORT_noScatherGather;
+ #endif /* (DPAA_VERSION >= 11) */
++            /* fall through */
+         case (e_FM_PORT_TYPE_OH_HOST_COMMAND):
+             p_FmPort->p_FmPortDriverParam->deqPrefetchOption =
+                     DEFAULT_PORT_deqPrefetchOption_HC;
+@@ -4270,6 +4274,7 @@ t_Error FM_PORT_ModifyCounter(t_Handle h
+                 RETURN_ERROR(
+                         MINOR, E_INVALID_STATE,
+                         ("Requested counter is not available for Rx ports"));
++            /* fall through */
+         case (e_FM_PORT_COUNTERS_ENQ_TOTAL):
+             bmiCounter = FALSE;
+             break;
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c
+@@ -4800,6 +4800,7 @@ uint32_t FM_GetCounter(t_Handle h_Fm, e_
+     {
+         case (e_FM_COUNTERS_DEQ_1):
+         case (e_FM_COUNTERS_DEQ_2):
++            /* fall through */
+         case (e_FM_COUNTERS_DEQ_3):
+             if ((p_Fm->p_FmStateStruct->revInfo.majorRev == 4) ||
+                 (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6))
+@@ -4807,12 +4808,14 @@ uint32_t FM_GetCounter(t_Handle h_Fm, e_
+                 REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Requested counter not supported"));
+                 return 0;
+             }
++            /* fall through */
+         case (e_FM_COUNTERS_ENQ_TOTAL_FRAME):
+         case (e_FM_COUNTERS_DEQ_TOTAL_FRAME):
+         case (e_FM_COUNTERS_DEQ_0):
+         case (e_FM_COUNTERS_DEQ_FROM_DEFAULT):
+         case (e_FM_COUNTERS_DEQ_FROM_CONTEXT):
+         case (e_FM_COUNTERS_DEQ_FROM_FD):
++            /* fall through */
+         case (e_FM_COUNTERS_DEQ_CONFIRM):
+             if (!(GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_gc) & QMI_CFG_EN_COUNTERS))
+             {
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c
+@@ -376,6 +376,7 @@ static inline void compat_copy_fm_pcd_cc
+             case e_IOC_FM_PCD_DONE:
+             case e_IOC_FM_PCD_PLCR:
+                 param->manip_id = compat_pcd_id2ptr(compat_param->manip_id);
++              /* fall through */
+             default:
+                 memcpy(&param->params, &compat_param->params, sizeof(param->params));
+         }
+@@ -403,6 +404,7 @@ static inline void compat_copy_fm_pcd_cc
+             case e_IOC_FM_PCD_DONE:
+             case e_IOC_FM_PCD_PLCR:
+                 compat_param->manip_id = compat_pcd_ptr2id(param->manip_id);
++              /* fall through */
+             default:
+                 memcpy(&compat_param->params, &param->params, sizeof(compat_param->params));
+         }
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c
+@@ -1799,16 +1799,19 @@ int fm_get_counter(void *h_fm, e_FmCount
+       switch (cnt_e) {
+       case (e_FM_COUNTERS_DEQ_1):
+       case (e_FM_COUNTERS_DEQ_2):
++              /* fall through */
+       case (e_FM_COUNTERS_DEQ_3):
+               if (p_fm->p_FmStateStruct->revInfo.majorRev >= 6)
+                       return -EINVAL; /* counter not available */
++              /* Else fall through */
+       case (e_FM_COUNTERS_ENQ_TOTAL_FRAME):
+       case (e_FM_COUNTERS_DEQ_TOTAL_FRAME):
+       case (e_FM_COUNTERS_DEQ_0):
+       case (e_FM_COUNTERS_DEQ_FROM_DEFAULT):
+       case (e_FM_COUNTERS_DEQ_FROM_CONTEXT):
+       case (e_FM_COUNTERS_DEQ_FROM_FD):
++              /* fall through */
+       case (e_FM_COUNTERS_DEQ_CONFIRM):
+               if (!(ioread32be(&p_fm->p_FmQmiRegs->fmqm_gc) &
+                       QMI_CFG_EN_COUNTERS))
+--- a/drivers/net/ethernet/mscc/ocelot_tsn.c
++++ b/drivers/net/ethernet/mscc/ocelot_tsn.c
+@@ -752,7 +752,7 @@ static int streamid_multi_forward_set(st
+       u32 bucket;
+       u32 val;
+       int m, n, i;
+-      u8 pgid_val, fwdport;
++      u8 pgid_val = 0, fwdport;
+       u32 dst_idx;
+       m_index = index / 4;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0367-net-mscc-ocelot-Workaround-to-allow-traffic-to-CPU-i.patch b/target/linux/layerscape/patches-5.4/701-net-0367-net-mscc-ocelot-Workaround-to-allow-traffic-to-CPU-i.patch
new file mode 100644 (file)
index 0000000..069c518
--- /dev/null
@@ -0,0 +1,149 @@
+From 937bf9496489cb4b491e75fe4436348bf3454dcd Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Sat, 21 Dec 2019 23:19:20 +0200
+Subject: [PATCH] net: mscc: ocelot: Workaround to allow traffic to CPU in
+ standalone mode
+
+The Ocelot switches have what is, in my opinion, a design flaw: their
+DSA header is in front of the Ethernet header, which means that they
+subvert the DSA master's RX filter, which for all practical purposes,
+either needs to be in promiscuous mode, or the OCELOT_TAG_PREFIX_LONG
+needs to be used for extraction, which makes the switch add a fake DMAC
+of ff:ff:ff:ff:ff:ff so that the DSA master accepts the frame.
+
+The issue with this design, of course, is that the CPU will be spammed
+with frames that it doesn't want to respond to, and there isn't any
+hardware offload in place by default to drop them.
+
+What is being done in the VSC7514 Ocelot driver is a process of
+selective whitelisting. The "MAC address" of each Ocelot switch net
+device, with all VLANs installed on that port, is being added as a FDB
+entry towards PGID_CPU.
+
+Some background first: Port Group IDs (PGIDs) are masks of destination
+ports. The switch performs 3 lookups in the PGID table for each frame,
+and forwards the frame to the ports that are present in the logical AND
+of all 3 PGIDs (for the most part, see below).
+
+The first PGID lookup is for the destination masks and the PGID table is
+indexed by the DEST_IDX field from the MAC table (FDB).
+The PGID can be an unicast set: PGIDs 0-11 are the per-port PGIDs, and
+by convention PGID i has only BIT(i) set, aka only this port is set in
+the destination mask.
+Or the PGID can be a multicast set: PGIDs 12-63 can (again, still by
+convention) hold a richer destination mask comprised of multiple ports.
+
+[ Ignoring the second PGID lookup, for aggregation, since it doesn't
+  interfere. ]
+
+The third PGID lookup is for source masks: PGID entries 80-91 answer the
+question: is port i allowed to forward traffic to port j? If yes, then
+BIT(j) of PGID 80+i will be found set.
+
+What is interesting about the CPU port in this whole story is that, in
+the way the driver sets up the PGIDs, its bit isn't set in any source
+mask PGID of any other port (therefore, the third lookup would always
+decide to exclude the CPU port from this list). So frames are never
+_forwarded_ to the CPU.
+
+There is a loophole in this PGID mechanism which is described in the
+VSC7514 manual:
+
+       If an entry is found in the MAC table entry of ENTRY_TYPE 0 or 1
+       and the CPU port is set in the PGID pointed to by the MAC table
+       entry, CPU extraction queue PGID.DST_PGID is added to the CPUQ.
+
+In other words, the CPU port is special, and frames are "copied" to the
+CPU, disregarding the source masks (third PGID lookup), if BIT(cpu) is
+found to be set in the destination masks (first PGID lookup).
+
+Now back to the story: what is PGID_CPU? It is a multicast set
+containing only BIT(cpu). I don't know why it was chosen to be a
+multicast PGID (59) and not simply the unicast one of this port, but it
+doesn't matter.
+
+The point is that frames that match the FDB will go to PGID_CPU by
+virtue of the DEST_IDX from the respective MAC table entry, and frames
+that don't will go to PGID_UC or PGID_MC, by virtue of the FLD_UNICAST,
+FLD_BROADCAST etc settings for flooding. And that is where the
+distinction is made: flooded frames will be subject to the third PGID
+lookup, while frames that are whitelisted to the PGID_CPU by the MAC
+table aren't.
+
+So we can use this mechanism to simulate an RX filter, given that we are
+subverting the DSA master's implicit one, as mentioned in the first
+paragraph. But this has some limitations:
+
+- In Ocelot each net device has its own MAC address. When simulating
+  this with MAC table entries, it will practically result in having N
+  MAC addresses for each of the N front-panel ports (because FDB entries
+  are not per source port). A bit strange, I think.
+
+- In DSA we don't have the infrastructure in place to support this
+  whitelisting mechanism. Calling .port_fdb_add on the CPU port for each
+  slave net device dev_addr isn't, in itself, hard. The problem is with
+  the VLANs that this port is part of. We would need to keep a duplicate
+  list of the VLANs from the bridge, plus the ones added from 8021q, for
+  each port. And we would need reference counting on each MAC address,
+  such that when a front-panel port changes its MAC address and we need
+  to delete the old FDB entry, we don't actually delete it if the other
+  front-panel ports are still using it. Not to mention that this FDB
+  entry would have to be added on the whole net of upstream DSA switches.
+
+So... it's complicated. What this patch does is to simply allow frames
+to be flooded to the CPU, which is anyway what the Ocelot driver is
+doing after removing the bridge from the net devices, see this snippet
+from ocelot_bridge_stp_state_set:
+
+       /* Apply FWD mask. The loop is needed to add/remove the current port as
+        * a source for the other ports.
+        */
+       for (p = 0; p < ocelot->num_phys_ports; p++) {
+               if (p == ocelot->cpu || (ocelot->bridge_fwd_mask & BIT(p))) {
+                       (...)
+               } else {
+                       /* Only the CPU port, this is compatible with link
+                        * aggregation.
+                        */
+                       ocelot_write_rix(ocelot,
+                                        BIT(ocelot->cpu),
+                                        ANA_PGID_PGID, PGID_SRC + p);
+               }
+
+Otherwise said, the ocelot driver itself is already not self-coherent,
+since immediately after probe time, and immediately after removal from a
+bridge, it behaves in different ways, although the front panel ports are
+standalone in both cases.
+
+While standalone traffic _does_ work for the Felix DSA wrapper after
+enslaving and removing the ports from a bridge, this patch makes
+standalone traffic work at probe time too, with the caveat that even
+irrelevant frames will get processed by software, making it more
+susceptible to denial of service.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -2292,6 +2292,18 @@ void ocelot_set_cpu_port(struct ocelot *
+                        enum ocelot_tag_prefix injection,
+                        enum ocelot_tag_prefix extraction)
+ {
++      int port;
++
++      for (port = 0; port < ocelot->num_phys_ports; port++) {
++              /* Disable old CPU port and enable new one */
++              ocelot_rmw_rix(ocelot, 0, BIT(ocelot->cpu),
++                             ANA_PGID_PGID, PGID_SRC + port);
++              if (port == cpu)
++                      continue;
++              ocelot_rmw_rix(ocelot, BIT(cpu), BIT(cpu),
++                             ANA_PGID_PGID, PGID_SRC + port);
++      }
++
+       /* Configure and enable the CPU port. */
+       ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu);
+       ocelot_write_rix(ocelot, BIT(cpu), ANA_PGID_PGID, PGID_CPU);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0368-Revert-net-dsa-felix-Add-PCS-operations-for-PHYLINK.patch b/target/linux/layerscape/patches-5.4/701-net-0368-Revert-net-dsa-felix-Add-PCS-operations-for-PHYLINK.patch
new file mode 100644 (file)
index 0000000..ea01a8b
--- /dev/null
@@ -0,0 +1,440 @@
+From 9ee918eb911853c7b46cd84779d857988366e845 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 6 Jan 2020 14:30:24 +0200
+Subject: [PATCH] Revert "net: dsa: felix: Add PCS operations for PHYLINK"
+
+This reverts commit 1082a3ef9e832cc52c4b0053c7c52453376f4830.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/dsa/ocelot/felix.c         |  23 +--
+ drivers/net/dsa/ocelot/felix.h         |   7 +-
+ drivers/net/dsa/ocelot/felix_vsc9959.c | 292 +--------------------------------
+ 3 files changed, 8 insertions(+), 314 deletions(-)
+
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -265,7 +265,7 @@ static int felix_get_ts_info(struct dsa_
+ static int felix_init_structs(struct felix *felix, int num_phys_ports)
+ {
+       struct ocelot *ocelot = &felix->ocelot;
+-      resource_size_t switch_base;
++      resource_size_t base;
+       int port, i, err;
+       ocelot->num_phys_ports = num_phys_ports;
+@@ -281,8 +281,7 @@ static int felix_init_structs(struct fel
+       ocelot->ops             = felix->info->ops;
+       ocelot->quirks          = felix->info->quirks;
+-      switch_base = pci_resource_start(felix->pdev,
+-                                       felix->info->switch_pci_bar);
++      base = pci_resource_start(felix->pdev, felix->info->pci_bar);
+       for (i = 0; i < TARGET_MAX; i++) {
+               struct regmap *target;
+@@ -293,8 +292,8 @@ static int felix_init_structs(struct fel
+               res = &felix->info->target_io_res[i];
+               res->flags = IORESOURCE_MEM;
+-              res->start += switch_base;
+-              res->end += switch_base;
++              res->start += base;
++              res->end += base;
+               target = ocelot_regmap_init(ocelot, res);
+               if (IS_ERR(target)) {
+@@ -328,8 +327,8 @@ static int felix_init_structs(struct fel
+               res = &felix->info->port_io_res[port];
+               res->flags = IORESOURCE_MEM;
+-              res->start += switch_base;
+-              res->end += switch_base;
++              res->start += base;
++              res->end += base;
+               port_regs = devm_ioremap_resource(ocelot->dev, res);
+               if (IS_ERR(port_regs)) {
+@@ -343,12 +342,6 @@ static int felix_init_structs(struct fel
+               ocelot->ports[port] = ocelot_port;
+       }
+-      if (felix->info->mdio_bus_alloc) {
+-              err = felix->info->mdio_bus_alloc(ocelot);
+-              if (err < 0)
+-                      return err;
+-      }
+-
+       return 0;
+ }
+@@ -384,10 +377,6 @@ static int felix_setup(struct dsa_switch
+ static void felix_teardown(struct dsa_switch *ds)
+ {
+       struct ocelot *ocelot = ds->priv;
+-      struct felix *felix = ocelot_to_felix(ocelot);
+-
+-      if (felix->imdio)
+-              mdiobus_unregister(felix->imdio);
+       /* stop workqueue thread */
+       ocelot_deinit(ocelot);
+--- a/drivers/net/dsa/ocelot/felix.h
++++ b/drivers/net/dsa/ocelot/felix.h
+@@ -10,7 +10,6 @@
+ struct felix_info {
+       struct resource                 *target_io_res;
+       struct resource                 *port_io_res;
+-      struct resource                 *imdio_res;
+       const struct reg_field          *regfields;
+       const u32 *const                *map;
+       const struct ocelot_ops         *ops;
+@@ -18,10 +17,8 @@ struct felix_info {
+       const struct ocelot_stat_layout *stats_layout;
+       unsigned int                    num_stats;
+       int                             num_ports;
+-      int                             switch_pci_bar;
+-      int                             imdio_pci_bar;
++      int                             pci_bar;
+       unsigned long                   quirks;
+-      int (*mdio_bus_alloc)(struct ocelot *ocelot);
+ };
+ extern struct felix_info              felix_info_vsc9959;
+@@ -36,8 +33,6 @@ struct felix {
+       struct pci_dev                  *pdev;
+       struct felix_info               *info;
+       struct ocelot                   ocelot;
+-      struct mii_bus                  *imdio;
+-      struct phy_device               **pcs;
+ };
+ #endif
+--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
+@@ -2,7 +2,6 @@
+ /* Copyright 2017 Microsemi Corporation
+  * Copyright 2018-2019 NXP Semiconductors
+  */
+-#include <linux/fsl/enetc_mdio.h>
+ #include <soc/mscc/ocelot_sys.h>
+ #include <soc/mscc/ocelot.h>
+ #include <linux/iopoll.h>
+@@ -391,15 +390,6 @@ static struct resource vsc9959_port_io_r
+       },
+ };
+-/* Port MAC 0 Internal MDIO bus through which the SerDes acting as an
+- * SGMII/QSGMII MAC PCS can be found.
+- */
+-static struct resource vsc9959_imdio_res = {
+-      .start          = 0x8030,
+-      .end            = 0x8040,
+-      .name           = "imdio",
+-};
+-
+ static const struct reg_field vsc9959_regfields[] = {
+       [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6),
+       [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 5),
+@@ -579,291 +569,13 @@ static int vsc9959_reset(struct ocelot *
+       return 0;
+ }
+-void vsc9959_pcs_validate(struct ocelot *ocelot, int port,
+-                        unsigned long *supported,
+-                        struct phylink_link_state *state)
+-{
+-      __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+-
+-      if (state->interface != PHY_INTERFACE_MODE_NA &&
+-          state->interface != PHY_INTERFACE_MODE_GMII &&
+-          state->interface != PHY_INTERFACE_MODE_SGMII &&
+-          state->interface != PHY_INTERFACE_MODE_QSGMII &&
+-          state->interface != PHY_INTERFACE_MODE_USXGMII) {
+-              bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+-              return;
+-      }
+-
+-      /* No half-duplex. */
+-      phylink_set_port_modes(mask);
+-      phylink_set(mask, Autoneg);
+-      phylink_set(mask, Pause);
+-      phylink_set(mask, Asym_Pause);
+-      phylink_set(mask, 10baseT_Full);
+-      phylink_set(mask, 100baseT_Full);
+-      phylink_set(mask, 1000baseT_Full);
+-      phylink_set(mask, 1000baseX_Full);
+-      phylink_set(mask, 2500baseT_Full);
+-      phylink_set(mask, 2500baseX_Full);
+-      phylink_set(mask, 1000baseKX_Full);
+-
+-      bitmap_and(supported, supported, mask,
+-                 __ETHTOOL_LINK_MODE_MASK_NBITS);
+-      bitmap_and(state->advertising, state->advertising, mask,
+-                 __ETHTOOL_LINK_MODE_MASK_NBITS);
+-}
+-
+-static void vsc9959_pcs_an_restart(struct ocelot *ocelot, int port)
+-{
+-      struct felix *felix = ocelot_to_felix(ocelot);
+-      struct phy_device *pcs = felix->pcs[port];
+-
+-      if (!pcs)
+-              return;
+-
+-      phy_set_bits(pcs, MII_BMCR, BMCR_ANRESTART);
+-}
+-
+-static void vsc9959_pcs_init_sgmii(struct phy_device *pcs,
+-                                 unsigned int link_an_mode,
+-                                 const struct phylink_link_state *state)
+-{
+-      /* SGMII spec requires tx_config_Reg[15:0] to be exactly 0x4001
+-       * for the MAC PCS in order to acknowledge the AN.
+-       */
+-      phy_write(pcs, MII_ADVERTISE, ADVERTISE_SGMII | ADVERTISE_LPACK);
+-
+-      /* Set to SGMII mode, use AN */
+-      phy_write(pcs, ENETC_PCS_IF_MODE, ENETC_PCS_IF_MODE_SGMII_AN);
+-
+-      /* Adjust link timer for SGMII */
+-      phy_write(pcs, ENETC_PCS_LINK_TIMER1, ENETC_PCS_LINK_TIMER1_VAL);
+-      phy_write(pcs, ENETC_PCS_LINK_TIMER2, ENETC_PCS_LINK_TIMER2_VAL);
+-
+-      phy_write(pcs, MII_BMCR, BMCR_SPEED1000 |
+-                               BMCR_FULLDPLX |
+-                               BMCR_ANENABLE);
+-}
+-
+-#define ADVERTISE_USXGMII_FDX         BIT(12)
+-
+-static void vsc9959_pcs_init_sxgmii(struct phy_device *pcs,
+-                                  unsigned int link_an_mode,
+-                                  const struct phylink_link_state *state)
+-{
+-      /* Configure device ability for the USXGMII Replicator */
+-      phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_ADVERTISE,
+-                    ADVERTISE_SGMII |
+-                    ADVERTISE_LPACK |
+-                    ADVERTISE_USXGMII_FDX);
+-}
+-
+-static void vsc9959_pcs_init(struct ocelot *ocelot, int port,
+-                           unsigned int link_an_mode,
+-                           const struct phylink_link_state *state)
+-{
+-      struct felix *felix = ocelot_to_felix(ocelot);
+-      struct phy_device *pcs = felix->pcs[port];
+-
+-      if (!pcs)
+-              return;
+-
+-      if (link_an_mode == MLO_AN_FIXED) {
+-              phydev_err(pcs, "Fixed modes are not yet supported.\n");
+-              return;
+-      }
+-
+-      pcs->interface = state->interface;
+-      if (pcs->interface == PHY_INTERFACE_MODE_USXGMII)
+-              pcs->is_c45 = true;
+-      else
+-              pcs->is_c45 = false;
+-
+-      /* The PCS does not implement the BMSR register fully, so capability
+-       * detection via genphy_read_abilities does not work. Since we can get
+-       * the PHY config word from the LPA register though, there is still
+-       * value in using the generic phy_resolve_aneg_linkmode function. So
+-       * populate the supported and advertising link modes manually here.
+-       */
+-      linkmode_set_bit_array(phy_basic_ports_array,
+-                             ARRAY_SIZE(phy_basic_ports_array),
+-                             pcs->supported);
+-      linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, pcs->supported);
+-      linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, pcs->supported);
+-      linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pcs->supported);
+-      linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, pcs->supported);
+-      phy_advertise_supported(pcs);
+-
+-      switch (pcs->interface) {
+-      case PHY_INTERFACE_MODE_SGMII:
+-      case PHY_INTERFACE_MODE_QSGMII:
+-              vsc9959_pcs_init_sgmii(pcs, link_an_mode, state);
+-              break;
+-      case PHY_INTERFACE_MODE_USXGMII:
+-              vsc9959_pcs_init_sxgmii(pcs, link_an_mode, state);
+-              break;
+-      default:
+-              dev_err(ocelot->dev, "Unsupported link mode %s\n",
+-                      phy_modes(pcs->interface));
+-      }
+-}
+-
+-static void vsc9959_pcs_link_state(struct ocelot *ocelot, int port,
+-                                 struct phylink_link_state *state)
+-{
+-      struct felix *felix = ocelot_to_felix(ocelot);
+-      struct phy_device *pcs = felix->pcs[port];
+-      int err;
+-
+-      if (!pcs)
+-              return;
+-
+-      /* Reading PCS status not yet supported for USXGMII */
+-      if (pcs->is_c45) {
+-              state->link = 1;
+-              return;
+-      }
+-
+-      pcs->speed = SPEED_UNKNOWN;
+-      pcs->duplex = DUPLEX_UNKNOWN;
+-      pcs->pause = 0;
+-      pcs->asym_pause = 0;
+-
+-      err = genphy_update_link(pcs);
+-      if (err < 0)
+-              return;
+-
+-      if (pcs->autoneg_complete) {
+-              u16 lpa = phy_read(pcs, MII_LPA);
+-
+-              switch (state->interface) {
+-              case PHY_INTERFACE_MODE_SGMII:
+-              case PHY_INTERFACE_MODE_QSGMII:
+-                      mii_lpa_to_linkmode_lpa_sgmii(pcs->lp_advertising, lpa);
+-                      break;
+-              default:
+-                      return;
+-              }
+-
+-              phy_resolve_aneg_linkmode(pcs);
+-      }
+-
+-      state->an_complete = pcs->autoneg_complete;
+-      state->an_enabled = pcs->autoneg;
+-      state->link = pcs->link;
+-      state->duplex = pcs->duplex;
+-      state->speed = pcs->speed;
+-      /* SGMII AN does not negotiate flow control, but that's ok,
+-       * since phylink already knows that, and does:
+-       *      link_state.pause |= pl->phy_state.pause;
+-       */
+-      state->pause = pcs->pause;
+-
+-      dev_dbg(ocelot->dev,
+-              "%s: mode=%s/%s/%s adv=%*pb lpa=%*pb link=%u an_enabled=%u an_complete=%u\n",
+-              __func__,
+-              phy_modes(state->interface),
+-              phy_speed_to_str(state->speed),
+-              phy_duplex_to_str(state->duplex),
+-              __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising,
+-              __ETHTOOL_LINK_MODE_MASK_NBITS, state->lp_advertising,
+-              state->link, state->an_enabled, state->an_complete);
+-}
+-
+ static const struct ocelot_ops vsc9959_ops = {
+       .reset                  = vsc9959_reset,
+-      .pcs_init               = vsc9959_pcs_init,
+-      .pcs_an_restart         = vsc9959_pcs_an_restart,
+-      .pcs_link_state         = vsc9959_pcs_link_state,
+-      .pcs_validate           = vsc9959_pcs_validate,
+ };
+-static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
+-{
+-      struct felix *felix = ocelot_to_felix(ocelot);
+-      struct enetc_mdio_priv *mdio_priv;
+-      struct device *dev = ocelot->dev;
+-      resource_size_t imdio_base;
+-      void __iomem *imdio_regs;
+-      struct resource *res;
+-      struct enetc_hw *hw;
+-      struct mii_bus *bus;
+-      int port;
+-      int rc;
+-
+-      felix->pcs = devm_kcalloc(dev, felix->info->num_ports,
+-                                sizeof(struct phy_device),
+-                                GFP_KERNEL);
+-      if (!felix->pcs) {
+-              dev_err(dev, "failed to allocate array for PCS PHYs\n");
+-              return -ENOMEM;
+-      }
+-
+-      imdio_base = pci_resource_start(felix->pdev,
+-                                      felix->info->imdio_pci_bar);
+-
+-      res = felix->info->imdio_res;
+-      res->flags = IORESOURCE_MEM;
+-      res->start += imdio_base;
+-      res->end += imdio_base;
+-
+-      imdio_regs = devm_ioremap_resource(dev, res);
+-      if (IS_ERR(imdio_regs)) {
+-              dev_err(dev, "failed to map internal MDIO registers\n");
+-              return PTR_ERR(imdio_regs);
+-      }
+-
+-      hw = enetc_hw_alloc(dev, imdio_regs);
+-      if (IS_ERR(hw)) {
+-              dev_err(dev, "failed to allocate ENETC HW structure\n");
+-              return PTR_ERR(hw);
+-      }
+-
+-      bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
+-      if (!bus)
+-              return -ENOMEM;
+-
+-      bus->name = "VSC9959 internal MDIO bus";
+-      bus->read = enetc_mdio_read;
+-      bus->write = enetc_mdio_write;
+-      bus->parent = dev;
+-      mdio_priv = bus->priv;
+-      mdio_priv->hw = hw;
+-      /* This gets added to imdio_regs, which already maps addresses
+-       * starting with the proper offset.
+-       */
+-      mdio_priv->mdio_base = 0;
+-      snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
+-
+-      /* Needed in order to initialize the bus mutex lock */
+-      rc = mdiobus_register(bus);
+-      if (rc < 0) {
+-              dev_err(dev, "failed to register MDIO bus\n");
+-              return rc;
+-      }
+-
+-      felix->imdio = bus;
+-
+-      for (port = 0; port < felix->info->num_ports; port++) {
+-              struct phy_device *pcs;
+-              bool is_c45 = false;
+-
+-              pcs = get_phy_device(felix->imdio, port, is_c45);
+-              if (IS_ERR(pcs))
+-                      continue;
+-
+-              felix->pcs[port] = pcs;
+-
+-              dev_info(dev, "Found PCS at internal MDIO address %d\n", port);
+-      }
+-
+-      return 0;
+-}
+-
+ struct felix_info felix_info_vsc9959 = {
+       .target_io_res          = vsc9959_target_io_res,
+       .port_io_res            = vsc9959_port_io_res,
+-      .imdio_res              = &vsc9959_imdio_res,
+       .regfields              = vsc9959_regfields,
+       .map                    = vsc9959_regmap,
+       .ops                    = &vsc9959_ops,
+@@ -871,8 +583,6 @@ struct felix_info felix_info_vsc9959 = {
+       .num_stats              = ARRAY_SIZE(vsc9959_stats_layout),
+       .shared_queue_sz        = 128 * 1024,
+       .num_ports              = 6,
+-      .switch_pci_bar         = 4,
+-      .imdio_pci_bar          = 0,
++      .pci_bar                = 4,
+       .quirks                 = OCELOT_PCS_PERFORMS_RATE_ADAPTATION,
+-      .mdio_bus_alloc         = vsc9959_mdio_bus_alloc,
+ };
diff --git a/target/linux/layerscape/patches-5.4/701-net-0369-Revert-net-mscc-ocelot-introduce-more-focused-PCS-op.patch b/target/linux/layerscape/patches-5.4/701-net-0369-Revert-net-mscc-ocelot-introduce-more-focused-PCS-op.patch
new file mode 100644 (file)
index 0000000..9ba2030
--- /dev/null
@@ -0,0 +1,164 @@
+From e1aa2a770cc5f4d46693bb491ed2ca7f066c3585 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 6 Jan 2020 14:30:41 +0200
+Subject: [PATCH] Revert "net: mscc: ocelot: introduce more focused PCS ops for
+ PHYLINK"
+
+This reverts commit 423c8b04007c85907f8f514de459ebc8541f0a54.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/ethernet/mscc/ocelot.c       | 36 ++++++++++++++++++++++++--------
+ drivers/net/ethernet/mscc/ocelot_board.c | 35 +------------------------------
+ include/soc/mscc/ocelot.h                | 12 +++--------
+ 3 files changed, 31 insertions(+), 52 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -410,25 +410,43 @@ void ocelot_phylink_validate(struct ocel
+                            unsigned long *supported,
+                            struct phylink_link_state *state)
+ {
+-      if (ocelot->ops->pcs_validate)
+-              ocelot->ops->pcs_validate(ocelot, port, supported, state);
++      __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
++
++      if (state->interface != PHY_INTERFACE_MODE_NA &&
++          state->interface != PHY_INTERFACE_MODE_GMII &&
++          state->interface != PHY_INTERFACE_MODE_SGMII &&
++          state->interface != PHY_INTERFACE_MODE_QSGMII) {
++              bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
++              return;
++      }
++
++      /* No half-duplex. */
++      phylink_set_port_modes(mask);
++      phylink_set(mask, Autoneg);
++      phylink_set(mask, Pause);
++      phylink_set(mask, Asym_Pause);
++      phylink_set(mask, 10baseT_Full);
++      phylink_set(mask, 100baseT_Full);
++      phylink_set(mask, 1000baseT_Full);
++      phylink_set(mask, 2500baseT_Full);
++
++      bitmap_and(supported, supported, mask,
++                 __ETHTOOL_LINK_MODE_MASK_NBITS);
++      bitmap_and(state->advertising, state->advertising, mask,
++                 __ETHTOOL_LINK_MODE_MASK_NBITS);
+ }
+ EXPORT_SYMBOL(ocelot_phylink_validate);
+ void ocelot_phylink_mac_pcs_get_state(struct ocelot *ocelot, int port,
+                                     struct phylink_link_state *state)
+ {
+-      if (ocelot->ops->pcs_link_state)
+-              ocelot->ops->pcs_link_state(ocelot, port, state);
+-      else
+-              state->link = 1;
++      state->link = 1;
+ }
+ EXPORT_SYMBOL(ocelot_phylink_mac_pcs_get_state);
+ void ocelot_phylink_mac_an_restart(struct ocelot *ocelot, int port)
+ {
+-      if (ocelot->ops->pcs_an_restart)
+-              ocelot->ops->pcs_an_restart(ocelot, port);
++      /* Not supported */
+ }
+ EXPORT_SYMBOL(ocelot_phylink_mac_an_restart);
+@@ -472,7 +490,7 @@ void ocelot_phylink_mac_config(struct oc
+       ocelot_port_writel(ocelot_port, mac_mode, DEV_MAC_MODE_CFG);
+       if (ocelot->ops->pcs_init)
+-              ocelot->ops->pcs_init(ocelot, port, link_an_mode, state);
++              ocelot->ops->pcs_init(ocelot, port);
+       /* Enable MAC module */
+       ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA |
+--- a/drivers/net/ethernet/mscc/ocelot_board.c
++++ b/drivers/net/ethernet/mscc/ocelot_board.c
+@@ -212,9 +212,7 @@ static const struct of_device_id mscc_oc
+ };
+ MODULE_DEVICE_TABLE(of, mscc_ocelot_match);
+-static void ocelot_port_pcs_init(struct ocelot *ocelot, int port,
+-                               unsigned int link_an_mode,
+-                               const struct phylink_link_state *state)
++static void ocelot_port_pcs_init(struct ocelot *ocelot, int port)
+ {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+@@ -237,36 +235,6 @@ static void ocelot_port_pcs_init(struct
+       ocelot_port_writel(ocelot_port, 0, PCS1G_LB_CFG);
+ }
+-void ocelot_port_pcs_validate(struct ocelot *ocelot, int port,
+-                            unsigned long *supported,
+-                            struct phylink_link_state *state)
+-{
+-      __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+-
+-      if (state->interface != PHY_INTERFACE_MODE_NA &&
+-          state->interface != PHY_INTERFACE_MODE_GMII &&
+-          state->interface != PHY_INTERFACE_MODE_SGMII &&
+-          state->interface != PHY_INTERFACE_MODE_QSGMII) {
+-              bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+-              return;
+-      }
+-
+-      /* No half-duplex. */
+-      phylink_set_port_modes(mask);
+-      phylink_set(mask, Autoneg);
+-      phylink_set(mask, Pause);
+-      phylink_set(mask, Asym_Pause);
+-      phylink_set(mask, 10baseT_Full);
+-      phylink_set(mask, 100baseT_Full);
+-      phylink_set(mask, 1000baseT_Full);
+-      phylink_set(mask, 2500baseT_Full);
+-
+-      bitmap_and(supported, supported, mask,
+-                 __ETHTOOL_LINK_MODE_MASK_NBITS);
+-      bitmap_and(state->advertising, state->advertising, mask,
+-                 __ETHTOOL_LINK_MODE_MASK_NBITS);
+-}
+-
+ static int ocelot_reset(struct ocelot *ocelot)
+ {
+       int retries = 100;
+@@ -292,7 +260,6 @@ static int ocelot_reset(struct ocelot *o
+ static const struct ocelot_ops ocelot_ops = {
+       .pcs_init               = ocelot_port_pcs_init,
+-      .pcs_validate           = ocelot_port_pcs_validate,
+       .reset                  = ocelot_reset,
+ };
+--- a/include/soc/mscc/ocelot.h
++++ b/include/soc/mscc/ocelot.h
+@@ -412,15 +412,7 @@ enum {
+ struct ocelot;
+ struct ocelot_ops {
+-      void (*pcs_init)(struct ocelot *ocelot, int port,
+-                       unsigned int link_an_mode,
+-                       const struct phylink_link_state *state);
+-      void (*pcs_an_restart)(struct ocelot *ocelot, int port);
+-      void (*pcs_link_state)(struct ocelot *ocelot, int port,
+-                             struct phylink_link_state *state);
+-      void (*pcs_validate)(struct ocelot *ocelot, int port,
+-                           unsigned long *supported,
+-                           struct phylink_link_state *state);
++      void (*pcs_init)(struct ocelot *ocelot, int port);
+       int (*reset)(struct ocelot *ocelot);
+ };
+@@ -487,6 +479,8 @@ struct ocelot {
+       struct mutex                    ptp_lock;
+       /* Protects the PTP clock */
+       spinlock_t                      ptp_clock_lock;
++
++      void (*port_pcs_init)(struct ocelot_port *port);
+ };
+ #define ocelot_read_ix(ocelot, reg, gi, ri) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
diff --git a/target/linux/layerscape/patches-5.4/701-net-0370-Revert-net-mscc-ocelot-convert-to-PHYLINK.patch b/target/linux/layerscape/patches-5.4/701-net-0370-Revert-net-mscc-ocelot-convert-to-PHYLINK.patch
new file mode 100644 (file)
index 0000000..1423104
--- /dev/null
@@ -0,0 +1,653 @@
+From 74e550d54d7c8142aefc06d1f00c506cd9039b6d Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 6 Jan 2020 14:30:48 +0200
+Subject: [PATCH] Revert "net: mscc: ocelot: convert to PHYLINK"
+
+This reverts commit e51cc023c37902e10d1e0109ff0c6ddcce3d5c03.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/dsa/ocelot/felix.c           |  65 ++++---------
+ drivers/net/ethernet/mscc/Kconfig        |   2 +-
+ drivers/net/ethernet/mscc/ocelot.c       | 150 ++++++++++++++----------------
+ drivers/net/ethernet/mscc/ocelot.h       |  13 ++-
+ drivers/net/ethernet/mscc/ocelot_board.c | 154 ++++---------------------------
+ include/soc/mscc/ocelot.h                |  22 +----
+ 6 files changed, 117 insertions(+), 289 deletions(-)
+
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -58,6 +58,14 @@ static int felix_set_ageing_time(struct
+       return 0;
+ }
++static void felix_adjust_link(struct dsa_switch *ds, int port,
++                            struct phy_device *phydev)
++{
++      struct ocelot *ocelot = ds->priv;
++
++      ocelot_adjust_link(ocelot, port, phydev);
++}
++
+ static int felix_fdb_dump(struct dsa_switch *ds, int port,
+                         dsa_fdb_dump_cb_t *cb, void *data)
+ {
+@@ -177,59 +185,21 @@ static int felix_tsn_enable(struct dsa_p
+ }
+ #endif
+-static void felix_phylink_validate(struct dsa_switch *ds, int port,
+-                                 unsigned long *supported,
+-                                 struct phylink_link_state *state)
++static int felix_port_enable(struct dsa_switch *ds, int port,
++                           struct phy_device *phy)
+ {
+       struct ocelot *ocelot = ds->priv;
+-      ocelot_phylink_validate(ocelot, port, supported, state);
+-}
+-
+-static int felix_phylink_mac_pcs_get_state(struct dsa_switch *ds, int port,
+-                                         struct phylink_link_state *state)
+-{
+-      struct ocelot *ocelot = ds->priv;
+-
+-      ocelot_phylink_mac_pcs_get_state(ocelot, port, state);
++      ocelot_port_enable(ocelot, port, phy);
+       return 0;
+ }
+-static void felix_phylink_mac_config(struct dsa_switch *ds, int port,
+-                                   unsigned int link_an_mode,
+-                                   const struct phylink_link_state *state)
+-{
+-      struct ocelot *ocelot = ds->priv;
+-
+-      ocelot_phylink_mac_config(ocelot, port, link_an_mode, state);
+-}
+-
+-static void felix_phylink_mac_an_restart(struct dsa_switch *ds, int port)
+-{
+-      struct ocelot *ocelot = ds->priv;
+-
+-      ocelot_phylink_mac_an_restart(ocelot, port);
+-}
+-
+-static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port,
+-                                      unsigned int link_an_mode,
+-                                      phy_interface_t interface)
+-{
+-      struct ocelot *ocelot = ds->priv;
+-
+-      ocelot_phylink_mac_link_down(ocelot, port, link_an_mode, interface);
+-}
+-
+-static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
+-                                    unsigned int link_an_mode,
+-                                    phy_interface_t interface,
+-                                    struct phy_device *phydev)
++static void felix_port_disable(struct dsa_switch *ds, int port)
+ {
+       struct ocelot *ocelot = ds->priv;
+-      ocelot_phylink_mac_link_up(ocelot, port, link_an_mode, interface,
+-                                 phydev);
++      return ocelot_port_disable(ocelot, port);
+ }
+ static void felix_get_strings(struct dsa_switch *ds, int port,
+@@ -447,12 +417,9 @@ static const struct dsa_switch_ops felix
+       .get_ethtool_stats      = felix_get_ethtool_stats,
+       .get_sset_count         = felix_get_sset_count,
+       .get_ts_info            = felix_get_ts_info,
+-      .phylink_validate       = felix_phylink_validate,
+-      .phylink_mac_link_state = felix_phylink_mac_pcs_get_state,
+-      .phylink_mac_config     = felix_phylink_mac_config,
+-      .phylink_mac_an_restart = felix_phylink_mac_an_restart,
+-      .phylink_mac_link_down  = felix_phylink_mac_link_down,
+-      .phylink_mac_link_up    = felix_phylink_mac_link_up,
++      .adjust_link            = felix_adjust_link,
++      .port_enable            = felix_port_enable,
++      .port_disable           = felix_port_disable,
+       .port_fdb_dump          = felix_fdb_dump,
+       .port_fdb_add           = felix_fdb_add,
+       .port_fdb_del           = felix_fdb_del,
+--- a/drivers/net/ethernet/mscc/Kconfig
++++ b/drivers/net/ethernet/mscc/Kconfig
+@@ -15,7 +15,7 @@ config MSCC_OCELOT_SWITCH
+       tristate "Ocelot switch driver"
+       depends on NET_SWITCHDEV
+       depends on HAS_IOMEM
+-      select PHYLINK
++      select PHYLIB
+       select REGMAP_MMIO
+       help
+         This driver supports the Ocelot network switch device.
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -13,7 +13,7 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/netdevice.h>
+-#include <linux/phylink.h>
++#include <linux/phy.h>
+ #include <linux/ptp_clock_kernel.h>
+ #include <linux/skbuff.h>
+ #include <linux/iopoll.h>
+@@ -406,66 +406,18 @@ static u16 ocelot_wm_enc(u16 value)
+       return value;
+ }
+-void ocelot_phylink_validate(struct ocelot *ocelot, int port,
+-                           unsigned long *supported,
+-                           struct phylink_link_state *state)
+-{
+-      __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+-
+-      if (state->interface != PHY_INTERFACE_MODE_NA &&
+-          state->interface != PHY_INTERFACE_MODE_GMII &&
+-          state->interface != PHY_INTERFACE_MODE_SGMII &&
+-          state->interface != PHY_INTERFACE_MODE_QSGMII) {
+-              bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+-              return;
+-      }
+-
+-      /* No half-duplex. */
+-      phylink_set_port_modes(mask);
+-      phylink_set(mask, Autoneg);
+-      phylink_set(mask, Pause);
+-      phylink_set(mask, Asym_Pause);
+-      phylink_set(mask, 10baseT_Full);
+-      phylink_set(mask, 100baseT_Full);
+-      phylink_set(mask, 1000baseT_Full);
+-      phylink_set(mask, 2500baseT_Full);
+-
+-      bitmap_and(supported, supported, mask,
+-                 __ETHTOOL_LINK_MODE_MASK_NBITS);
+-      bitmap_and(state->advertising, state->advertising, mask,
+-                 __ETHTOOL_LINK_MODE_MASK_NBITS);
+-}
+-EXPORT_SYMBOL(ocelot_phylink_validate);
+-
+-void ocelot_phylink_mac_pcs_get_state(struct ocelot *ocelot, int port,
+-                                    struct phylink_link_state *state)
+-{
+-      state->link = 1;
+-}
+-EXPORT_SYMBOL(ocelot_phylink_mac_pcs_get_state);
+-
+-void ocelot_phylink_mac_an_restart(struct ocelot *ocelot, int port)
+-{
+-      /* Not supported */
+-}
+-EXPORT_SYMBOL(ocelot_phylink_mac_an_restart);
+-
+-void ocelot_phylink_mac_config(struct ocelot *ocelot, int port,
+-                             unsigned int link_an_mode,
+-                             const struct phylink_link_state *state)
++void ocelot_adjust_link(struct ocelot *ocelot, int port,
++                      struct phy_device *phydev)
+ {
+       int speed, mac_speed, mac_mode = DEV_MAC_MODE_CFG_FDX_ENA;
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+-      u32 mac_fc_cfg;
+       if (ocelot->quirks & OCELOT_PCS_PERFORMS_RATE_ADAPTATION)
+               speed = SPEED_1000;
+       else
+-              speed = state->speed;
++              speed = phydev->speed;
+       switch (speed) {
+-      case SPEED_UNKNOWN:
+-              return;
+       case SPEED_10:
+               mac_speed = OCELOT_SPEED_10;
+               break;
+@@ -481,11 +433,16 @@ void ocelot_phylink_mac_config(struct oc
+               mac_mode |= DEV_MAC_MODE_CFG_GIGA_MODE_ENA;
+               break;
+       default:
+-              dev_err(ocelot->dev, "Unsupported speed on port %d: %d\n",
++              dev_err(ocelot->dev, "Unsupported PHY speed on port %d: %d\n",
+                       port, speed);
+               return;
+       }
++      phy_print_status(phydev);
++
++      if (!phydev->link)
++              return;
++
+       /* Only full duplex supported for now */
+       ocelot_port_writel(ocelot_port, mac_mode, DEV_MAC_MODE_CFG);
+@@ -512,36 +469,27 @@ void ocelot_phylink_mac_config(struct oc
+                        QSYS_SWITCH_PORT_MODE, port);
+       /* Flow control */
+-      mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(mac_speed);
+-      if (state->pause & MLO_PAUSE_RX)
+-              mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA;
+-      if (state->pause & MLO_PAUSE_TX)
+-              mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA |
+-                            SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) |
+-                            SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) |
+-                            SYS_MAC_FC_CFG_ZERO_PAUSE_ENA;
+-      ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port);
+-
++      ocelot_write_rix(ocelot, SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) |
++                       SYS_MAC_FC_CFG_RX_FC_ENA | SYS_MAC_FC_CFG_TX_FC_ENA |
++                       SYS_MAC_FC_CFG_ZERO_PAUSE_ENA |
++                       SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) |
++                       SYS_MAC_FC_CFG_FC_LINK_SPEED(mac_speed),
++                       SYS_MAC_FC_CFG, port);
+       ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port);
+ }
+-EXPORT_SYMBOL(ocelot_phylink_mac_config);
++EXPORT_SYMBOL(ocelot_adjust_link);
+-void ocelot_phylink_mac_link_down(struct ocelot *ocelot, int port,
+-                                unsigned int link_an_mode,
+-                                phy_interface_t interface)
++static void ocelot_port_adjust_link(struct net_device *dev)
+ {
+-      struct ocelot_port *ocelot_port = ocelot->ports[port];
++      struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
+-      ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG);
+-      ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA,
+-                     QSYS_SWITCH_PORT_MODE, port);
++      ocelot_adjust_link(ocelot, port, dev->phydev);
+ }
+-EXPORT_SYMBOL(ocelot_phylink_mac_link_down);
+-void ocelot_phylink_mac_link_up(struct ocelot *ocelot, int port,
+-                              unsigned int link_an_mode,
+-                              phy_interface_t interface,
+-                              struct phy_device *phy)
++void ocelot_port_enable(struct ocelot *ocelot, int port,
++                      struct phy_device *phy)
+ {
+       /* Enable receiving frames on the port, and activate auto-learning of
+        * MAC addresses.
+@@ -551,22 +499,62 @@ void ocelot_phylink_mac_link_up(struct o
+                        ANA_PORT_PORT_CFG_PORTID_VAL(port),
+                        ANA_PORT_PORT_CFG, port);
+ }
+-EXPORT_SYMBOL(ocelot_phylink_mac_link_up);
++EXPORT_SYMBOL(ocelot_port_enable);
+ static int ocelot_port_open(struct net_device *dev)
+ {
+       struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
++      int err;
++
++      if (priv->serdes) {
++              err = phy_set_mode_ext(priv->serdes, PHY_MODE_ETHERNET,
++                                     priv->phy_mode);
++              if (err) {
++                      netdev_err(dev, "Could not set mode of SerDes\n");
++                      return err;
++              }
++      }
++
++      err = phy_connect_direct(dev, priv->phy, &ocelot_port_adjust_link,
++                               priv->phy_mode);
++      if (err) {
++              netdev_err(dev, "Could not attach to PHY\n");
++              return err;
++      }
+-      phylink_start(priv->phylink);
++      dev->phydev = priv->phy;
++
++      phy_attached_info(priv->phy);
++      phy_start(priv->phy);
++
++      ocelot_port_enable(ocelot, port, priv->phy);
+       return 0;
+ }
++void ocelot_port_disable(struct ocelot *ocelot, int port)
++{
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++
++      ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG);
++      ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA,
++                     QSYS_SWITCH_PORT_MODE, port);
++}
++EXPORT_SYMBOL(ocelot_port_disable);
++
+ static int ocelot_port_stop(struct net_device *dev)
+ {
+       struct ocelot_port_private *priv = netdev_priv(dev);
++      struct ocelot *ocelot = priv->port.ocelot;
++      int port = priv->chip_port;
++
++      phy_disconnect(priv->phy);
++
++      dev->phydev = NULL;
+-      phylink_stop(priv->phylink);
++      ocelot_port_disable(ocelot, port);
+       return 0;
+ }
+@@ -2263,7 +2251,8 @@ void ocelot_init_port(struct ocelot *oce
+ EXPORT_SYMBOL(ocelot_init_port);
+ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
+-                    void __iomem *regs)
++                    void __iomem *regs,
++                    struct phy_device *phy)
+ {
+       struct ocelot_port_private *priv;
+       struct ocelot_port *ocelot_port;
+@@ -2276,6 +2265,7 @@ int ocelot_probe_port(struct ocelot *oce
+       SET_NETDEV_DEV(dev, ocelot->dev);
+       priv = netdev_priv(dev);
+       priv->dev = dev;
++      priv->phy = phy;
+       priv->chip_port = port;
+       ocelot_port = &priv->port;
+       ocelot_port->ocelot = ocelot;
+--- a/drivers/net/ethernet/mscc/ocelot.h
++++ b/drivers/net/ethernet/mscc/ocelot.h
+@@ -12,7 +12,8 @@
+ #include <linux/etherdevice.h>
+ #include <linux/if_vlan.h>
+ #include <linux/net_tstamp.h>
+-#include <linux/phylink.h>
++#include <linux/phy.h>
++#include <linux/phy/phy.h>
+ #include <linux/platform_device.h>
+ #include <linux/ptp_clock_kernel.h>
+ #include <linux/regmap.h>
+@@ -64,12 +65,14 @@ struct ocelot_multicast {
+ struct ocelot_port_private {
+       struct ocelot_port port;
+       struct net_device *dev;
+-      struct phylink *phylink;
+-      struct phylink_config phylink_config;
++      struct phy_device *phy;
+       u8 chip_port;
+       u8 vlan_aware;
++      phy_interface_t phy_mode;
++      struct phy *serdes;
++
+       struct ocelot_port_tc tc;
+ };
+@@ -80,7 +83,9 @@ void ocelot_port_writel(struct ocelot_po
+ #define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val))
+ int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops);
+-int ocelot_probe_port(struct ocelot *ocelot, u8 port, void __iomem *regs);
++int ocelot_probe_port(struct ocelot *ocelot, u8 port,
++                    void __iomem *regs,
++                    struct phy_device *phy);
+ void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu,
+                        enum ocelot_tag_prefix injection,
+--- a/drivers/net/ethernet/mscc/ocelot_board.c
++++ b/drivers/net/ethernet/mscc/ocelot_board.c
+@@ -13,7 +13,6 @@
+ #include <linux/mfd/syscon.h>
+ #include <linux/skbuff.h>
+ #include <net/switchdev.h>
+-#include <linux/phy/phy.h>
+ #include "ocelot.h"
+@@ -263,91 +262,6 @@ static const struct ocelot_ops ocelot_op
+       .reset                  = ocelot_reset,
+ };
+-static void ocelot_port_phylink_validate(struct phylink_config *config,
+-                                       unsigned long *supported,
+-                                       struct phylink_link_state *state)
+-{
+-      struct net_device *ndev = to_net_dev(config->dev);
+-      struct ocelot_port_private *priv = netdev_priv(ndev);
+-      struct ocelot *ocelot = priv->port.ocelot;
+-      int port = priv->chip_port;
+-
+-      ocelot_phylink_validate(ocelot, port, supported, state);
+-}
+-
+-static int
+-ocelot_port_phylink_mac_pcs_get_state(struct phylink_config *config,
+-                                    struct phylink_link_state *state)
+-{
+-      struct net_device *ndev = to_net_dev(config->dev);
+-      struct ocelot_port_private *priv = netdev_priv(ndev);
+-      struct ocelot *ocelot = priv->port.ocelot;
+-      int port = priv->chip_port;
+-
+-      ocelot_phylink_mac_pcs_get_state(ocelot, port, state);
+-
+-      return 0;
+-}
+-
+-static void ocelot_port_phylink_mac_an_restart(struct phylink_config *config)
+-{
+-      struct net_device *ndev = to_net_dev(config->dev);
+-      struct ocelot_port_private *priv = netdev_priv(ndev);
+-      struct ocelot *ocelot = priv->port.ocelot;
+-      int port = priv->chip_port;
+-
+-      ocelot_phylink_mac_an_restart(ocelot, port);
+-}
+-
+-static void
+-ocelot_port_phylink_mac_config(struct phylink_config *config,
+-                             unsigned int link_an_mode,
+-                             const struct phylink_link_state *state)
+-{
+-      struct net_device *ndev = to_net_dev(config->dev);
+-      struct ocelot_port_private *priv = netdev_priv(ndev);
+-      struct ocelot *ocelot = priv->port.ocelot;
+-      int port = priv->chip_port;
+-
+-      ocelot_phylink_mac_config(ocelot, port, link_an_mode, state);
+-}
+-
+-static void ocelot_port_phylink_mac_link_down(struct phylink_config *config,
+-                                            unsigned int link_an_mode,
+-                                            phy_interface_t interface)
+-{
+-      struct net_device *ndev = to_net_dev(config->dev);
+-      struct ocelot_port_private *priv = netdev_priv(ndev);
+-      struct ocelot *ocelot = priv->port.ocelot;
+-      int port = priv->chip_port;
+-
+-      return ocelot_phylink_mac_link_down(ocelot, port, link_an_mode,
+-                                          interface);
+-}
+-
+-static void ocelot_port_phylink_mac_link_up(struct phylink_config *config,
+-                                          unsigned int link_an_mode,
+-                                          phy_interface_t interface,
+-                                          struct phy_device *phy)
+-{
+-      struct net_device *ndev = to_net_dev(config->dev);
+-      struct ocelot_port_private *priv = netdev_priv(ndev);
+-      struct ocelot *ocelot = priv->port.ocelot;
+-      int port = priv->chip_port;
+-
+-      return ocelot_phylink_mac_link_up(ocelot, port, link_an_mode,
+-                                        interface, phy);
+-}
+-
+-static const struct phylink_mac_ops ocelot_phylink_ops = {
+-      .validate               = ocelot_port_phylink_validate,
+-      .mac_link_state         = ocelot_port_phylink_mac_pcs_get_state,
+-      .mac_an_restart         = ocelot_port_phylink_mac_an_restart,
+-      .mac_config             = ocelot_port_phylink_mac_config,
+-      .mac_link_down          = ocelot_port_phylink_mac_link_down,
+-      .mac_link_up            = ocelot_port_phylink_mac_link_up,
+-};
+-
+ static int mscc_ocelot_probe(struct platform_device *pdev)
+ {
+       struct device_node *np = pdev->dev.of_node;
+@@ -455,6 +369,8 @@ static int mscc_ocelot_probe(struct plat
+       for_each_available_child_of_node(ports, portnp) {
+               struct ocelot_port_private *priv;
+               struct ocelot_port *ocelot_port;
++              struct device_node *phy_node;
++              struct phy_device *phy;
+               struct resource *res;
+               struct phy *serdes;
+               void __iomem *regs;
+@@ -473,7 +389,16 @@ static int mscc_ocelot_probe(struct plat
+               if (IS_ERR(regs))
+                       continue;
+-              err = ocelot_probe_port(ocelot, port, regs);
++              phy_node = of_parse_phandle(portnp, "phy-handle", 0);
++              if (!phy_node)
++                      continue;
++
++              phy = of_phy_find_device(phy_node);
++              of_node_put(phy_node);
++              if (!phy)
++                      continue;
++
++              err = ocelot_probe_port(ocelot, port, regs, phy);
+               if (err) {
+                       of_node_put(portnp);
+                       goto out_put_ports;
+@@ -487,7 +412,9 @@ static int mscc_ocelot_probe(struct plat
+               if (phy_mode < 0)
+                       phy_mode = PHY_INTERFACE_MODE_NA;
+-              switch (phy_mode) {
++              priv->phy_mode = phy_mode;
++
++              switch (priv->phy_mode) {
+               case PHY_INTERFACE_MODE_NA:
+                       continue;
+               case PHY_INTERFACE_MODE_SGMII:
+@@ -524,41 +451,7 @@ static int mscc_ocelot_probe(struct plat
+                       goto out_put_ports;
+               }
+-              if (serdes) {
+-                      err = phy_set_mode_ext(serdes, PHY_MODE_ETHERNET,
+-                                             phy_mode);
+-                      if (err) {
+-                              dev_err(ocelot->dev,
+-                                      "Could not set mode of SerDes\n");
+-                              of_node_put(portnp);
+-                              goto out_put_ports;
+-                      }
+-              }
+-
+-              priv->phylink_config.dev = &priv->dev->dev;
+-              priv->phylink_config.type = PHYLINK_NETDEV;
+-
+-              priv->phylink = phylink_create(&priv->phylink_config,
+-                                             of_fwnode_handle(portnp),
+-                                             phy_mode, &ocelot_phylink_ops);
+-              if (IS_ERR(priv->phylink)) {
+-                      dev_err(ocelot->dev,
+-                              "Could not create a phylink instance (%ld)\n",
+-                              PTR_ERR(priv->phylink));
+-                      err = PTR_ERR(priv->phylink);
+-                      priv->phylink = NULL;
+-                      of_node_put(portnp);
+-                      goto out_put_ports;
+-              }
+-
+-              err = phylink_of_phy_connect(priv->phylink, portnp, 0);
+-              if (err) {
+-                      dev_err(ocelot->dev, "Could not connect to PHY: %d\n",
+-                              err);
+-                      phylink_destroy(priv->phylink);
+-                      of_node_put(portnp);
+-                      goto out_put_ports;
+-              }
++              priv->serdes = serdes;
+       }
+       register_netdevice_notifier(&ocelot_netdevice_nb);
+@@ -575,27 +468,12 @@ out_put_ports:
+ static int mscc_ocelot_remove(struct platform_device *pdev)
+ {
+       struct ocelot *ocelot = platform_get_drvdata(pdev);
+-      int port;
+       ocelot_deinit(ocelot);
+       unregister_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);
+       unregister_switchdev_notifier(&ocelot_switchdev_nb);
+       unregister_netdevice_notifier(&ocelot_netdevice_nb);
+-      for (port = 0; port < ocelot->num_phys_ports; port++) {
+-              struct ocelot_port_private *priv;
+-
+-              priv = container_of(ocelot->ports[port],
+-                                  struct ocelot_port_private,
+-                                  port);
+-
+-              if (priv->phylink) {
+-                      rtnl_lock();
+-                      phylink_destroy(priv->phylink);
+-                      rtnl_unlock();
+-              }
+-      }
+-
+       return 0;
+ }
+--- a/include/soc/mscc/ocelot.h
++++ b/include/soc/mscc/ocelot.h
+@@ -518,12 +518,17 @@ void ocelot_deinit(struct ocelot *ocelot
+ void ocelot_init_port(struct ocelot *ocelot, int port);
+ /* DSA callbacks */
++void ocelot_port_enable(struct ocelot *ocelot, int port,
++                      struct phy_device *phy);
++void ocelot_port_disable(struct ocelot *ocelot, int port);
+ void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data);
+ void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data);
+ int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset);
+ int ocelot_get_ts_info(struct ocelot *ocelot, int port,
+                      struct ethtool_ts_info *info);
+ void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs);
++void ocelot_adjust_link(struct ocelot *ocelot, int port,
++                      struct phy_device *phydev);
+ void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
+                               bool vlan_aware);
+ void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state);
+@@ -592,21 +597,4 @@ int ocelot_rtag_parse_enable(struct ocel
+ int ocelot_dscp_set(struct ocelot *ocelot, int port,
+                   bool enable, const u8 dscp_ix,
+                   struct tsn_qos_switch_dscp_conf *c);
+-void ocelot_phylink_validate(struct ocelot *ocelot, int port,
+-                           unsigned long *supported,
+-                           struct phylink_link_state *state);
+-void ocelot_phylink_mac_pcs_get_state(struct ocelot *ocelot, int port,
+-                                    struct phylink_link_state *state);
+-void ocelot_phylink_mac_an_restart(struct ocelot *ocelot, int port);
+-void ocelot_phylink_mac_config(struct ocelot *ocelot, int port,
+-                             unsigned int link_an_mode,
+-                             const struct phylink_link_state *state);
+-void ocelot_phylink_mac_link_down(struct ocelot *ocelot, int port,
+-                                unsigned int link_an_mode,
+-                                phy_interface_t interface);
+-void ocelot_phylink_mac_link_up(struct ocelot *ocelot, int port,
+-                              unsigned int link_an_mode,
+-                              phy_interface_t interface,
+-                              struct phy_device *phy);
+-
+ #endif
diff --git a/target/linux/layerscape/patches-5.4/701-net-0371-Revert-net-mscc-ocelot-do-not-force-Felix-MACs-at-lo.patch b/target/linux/layerscape/patches-5.4/701-net-0371-Revert-net-mscc-ocelot-do-not-force-Felix-MACs-at-lo.patch
new file mode 100644 (file)
index 0000000..4859d17
--- /dev/null
@@ -0,0 +1,145 @@
+From 6864e50946bf92f96b8452d1e47765230a276bb0 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 6 Jan 2020 14:30:58 +0200
+Subject: [PATCH] Revert "net: mscc: ocelot: do not force Felix MACs at lower
+ speeds than gigabit"
+
+This reverts commit f3ebad1269aad8a04710e84dc1cd5de485e5fec4.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/dsa/ocelot/felix.c         |  1 -
+ drivers/net/dsa/ocelot/felix.h         |  1 -
+ drivers/net/dsa/ocelot/felix_vsc9959.c |  1 -
+ drivers/net/ethernet/mscc/ocelot.c     | 32 ++++++++++++++------------------
+ include/soc/mscc/ocelot.h              |  7 -------
+ 5 files changed, 14 insertions(+), 28 deletions(-)
+
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -249,7 +249,6 @@ static int felix_init_structs(struct fel
+       ocelot->num_stats       = felix->info->num_stats;
+       ocelot->shared_queue_sz = felix->info->shared_queue_sz;
+       ocelot->ops             = felix->info->ops;
+-      ocelot->quirks          = felix->info->quirks;
+       base = pci_resource_start(felix->pdev, felix->info->pci_bar);
+--- a/drivers/net/dsa/ocelot/felix.h
++++ b/drivers/net/dsa/ocelot/felix.h
+@@ -18,7 +18,6 @@ struct felix_info {
+       unsigned int                    num_stats;
+       int                             num_ports;
+       int                             pci_bar;
+-      unsigned long                   quirks;
+ };
+ extern struct felix_info              felix_info_vsc9959;
+--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
+@@ -584,5 +584,4 @@ struct felix_info felix_info_vsc9959 = {
+       .shared_queue_sz        = 128 * 1024,
+       .num_ports              = 6,
+       .pci_bar                = 4,
+-      .quirks                 = OCELOT_PCS_PERFORMS_RATE_ADAPTATION,
+ };
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -409,32 +409,27 @@ static u16 ocelot_wm_enc(u16 value)
+ void ocelot_adjust_link(struct ocelot *ocelot, int port,
+                       struct phy_device *phydev)
+ {
+-      int speed, mac_speed, mac_mode = DEV_MAC_MODE_CFG_FDX_ENA;
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
++      int speed, mode = 0;
+-      if (ocelot->quirks & OCELOT_PCS_PERFORMS_RATE_ADAPTATION)
+-              speed = SPEED_1000;
+-      else
+-              speed = phydev->speed;
+-
+-      switch (speed) {
++      switch (phydev->speed) {
+       case SPEED_10:
+-              mac_speed = OCELOT_SPEED_10;
++              speed = OCELOT_SPEED_10;
+               break;
+       case SPEED_100:
+-              mac_speed = OCELOT_SPEED_100;
++              speed = OCELOT_SPEED_100;
+               break;
+       case SPEED_1000:
+-              mac_speed = OCELOT_SPEED_1000;
+-              mac_mode |= DEV_MAC_MODE_CFG_GIGA_MODE_ENA;
++              speed = OCELOT_SPEED_1000;
++              mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA;
+               break;
+       case SPEED_2500:
+-              mac_speed = OCELOT_SPEED_2500;
+-              mac_mode |= DEV_MAC_MODE_CFG_GIGA_MODE_ENA;
++              speed = OCELOT_SPEED_2500;
++              mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA;
+               break;
+       default:
+               dev_err(ocelot->dev, "Unsupported PHY speed on port %d: %d\n",
+-                      port, speed);
++                      port, phydev->speed);
+               return;
+       }
+@@ -444,7 +439,8 @@ void ocelot_adjust_link(struct ocelot *o
+               return;
+       /* Only full duplex supported for now */
+-      ocelot_port_writel(ocelot_port, mac_mode, DEV_MAC_MODE_CFG);
++      ocelot_port_writel(ocelot_port, DEV_MAC_MODE_CFG_FDX_ENA |
++                         mode, DEV_MAC_MODE_CFG);
+       if (ocelot->ops->pcs_init)
+               ocelot->ops->pcs_init(ocelot, port);
+@@ -455,11 +451,11 @@ void ocelot_adjust_link(struct ocelot *o
+       /* Take MAC, Port, Phy (intern) and PCS (SGMII/Serdes) clock out of
+        * reset */
+-      ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(mac_speed),
++      ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(speed),
+                          DEV_CLOCK_CFG);
+       /* No PFC */
+-      ocelot_write_gix(ocelot, ANA_PFC_PFC_CFG_FC_LINK_SPEED(mac_speed),
++      ocelot_write_gix(ocelot, ANA_PFC_PFC_CFG_FC_LINK_SPEED(speed),
+                        ANA_PFC_PFC_CFG, port);
+       /* Core: Enable port for frame transfer */
+@@ -473,7 +469,7 @@ void ocelot_adjust_link(struct ocelot *o
+                        SYS_MAC_FC_CFG_RX_FC_ENA | SYS_MAC_FC_CFG_TX_FC_ENA |
+                        SYS_MAC_FC_CFG_ZERO_PAUSE_ENA |
+                        SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) |
+-                       SYS_MAC_FC_CFG_FC_LINK_SPEED(mac_speed),
++                       SYS_MAC_FC_CFG_FC_LINK_SPEED(speed),
+                        SYS_MAC_FC_CFG, port);
+       ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port);
+ }
+--- a/include/soc/mscc/ocelot.h
++++ b/include/soc/mscc/ocelot.h
+@@ -404,11 +404,6 @@ enum ocelot_tag_prefix {
+       OCELOT_TAG_PREFIX_LONG,
+ };
+-/* Hardware quirks (differences between switch instantiations) */
+-enum {
+-      OCELOT_PCS_PERFORMS_RATE_ADAPTATION     = BIT(0),
+-};
+-
+ struct ocelot;
+ struct ocelot_ops {
+@@ -469,8 +464,6 @@ struct ocelot {
+       struct delayed_work             stats_work;
+       struct workqueue_struct         *stats_queue;
+-      unsigned long                   quirks;
+-
+       u8                              ptp:1;
+       struct ptp_clock                *ptp_clock;
+       struct ptp_clock_info           ptp_info;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0372-Revert-enetc-Set-MDIO_CFG_HOLD-to-the-recommended-va.patch b/target/linux/layerscape/patches-5.4/701-net-0372-Revert-enetc-Set-MDIO_CFG_HOLD-to-the-recommended-va.patch
new file mode 100644 (file)
index 0000000..fda777b
--- /dev/null
@@ -0,0 +1,55 @@
+From d93ca8d9c8365cf533f88582c57c83cb50fe598a Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 6 Jan 2020 14:31:13 +0200
+Subject: [PATCH] Revert "enetc: Set MDIO_CFG_HOLD to the recommended value of
+ 2"
+
+This reverts commit 3f643e4af035886cd2ca4bf79967098cfe55b40b.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_mdio.c | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
+@@ -31,19 +31,15 @@ static inline void _enetc_mdio_wr(struct
+       _enetc_mdio_wr(mdio_priv, ENETC_##off, val)
+ #define enetc_mdio_rd_reg(off)        enetc_mdio_rd(mdio_priv, off)
++#define ENETC_MDC_DIV         258
++
+ #define MDIO_CFG_CLKDIV(x)    ((((x) >> 1) & 0xff) << 8)
+ #define MDIO_CFG_BSY          BIT(0)
+ #define MDIO_CFG_RD_ER                BIT(1)
+-#define MDIO_CFG_HOLD(x)      (((x) << 2) & GENMASK(4, 2))
+ #define MDIO_CFG_ENC45                BIT(6)
+  /* external MDIO only - driven on neg MDC edge */
+ #define MDIO_CFG_NEG          BIT(23)
+-#define ENETC_EMDIO_CFG \
+-      (MDIO_CFG_HOLD(2) | \
+-       MDIO_CFG_CLKDIV(258) | \
+-       MDIO_CFG_NEG)
+-
+ #define MDIO_CTL_DEV_ADDR(x)  ((x) & 0x1f)
+ #define MDIO_CTL_PORT_ADDR(x) (((x) & 0x1f) << 5)
+ #define MDIO_CTL_READ         BIT(15)
+@@ -65,7 +61,7 @@ int enetc_mdio_write(struct mii_bus *bus
+       u16 dev_addr;
+       int ret;
+-      mdio_cfg = ENETC_EMDIO_CFG;
++      mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
+       if (regnum & MII_ADDR_C45) {
+               dev_addr = (regnum >> 16) & 0x1f;
+               mdio_cfg |= MDIO_CFG_ENC45;
+@@ -112,7 +108,7 @@ int enetc_mdio_read(struct mii_bus *bus,
+       u16 dev_addr, value;
+       int ret;
+-      mdio_cfg = ENETC_EMDIO_CFG;
++      mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
+       if (regnum & MII_ADDR_C45) {
+               dev_addr = (regnum >> 16) & 0x1f;
+               mdio_cfg |= MDIO_CFG_ENC45;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0373-Revert-enetc-export-enetc_mdio-definitionns-to-inclu.patch b/target/linux/layerscape/patches-5.4/701-net-0373-Revert-enetc-export-enetc_mdio-definitionns-to-inclu.patch
new file mode 100644 (file)
index 0000000..5e934c6
--- /dev/null
@@ -0,0 +1,192 @@
+From 78378454e7978ea3b4128822880677e6efa9ddef Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 6 Jan 2020 14:31:22 +0200
+Subject: [PATCH] Revert "enetc: export enetc_mdio definitionns to
+ include/linux/fsl"
+
+This reverts commit f8d80c003b76f397696bf887ebbd37a78781c050.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_mdio.c  | 18 +---------
+ drivers/net/ethernet/freescale/enetc/enetc_mdio.h  | 12 +++++++
+ .../net/ethernet/freescale/enetc/enetc_pci_mdio.c  | 41 +++++++++-------------
+ include/linux/fsl/enetc_mdio.h                     | 21 -----------
+ 4 files changed, 30 insertions(+), 62 deletions(-)
+ create mode 100644 drivers/net/ethernet/freescale/enetc/enetc_mdio.h
+ delete mode 100644 include/linux/fsl/enetc_mdio.h
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
+@@ -1,13 +1,13 @@
+ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+ /* Copyright 2019 NXP */
+-#include <linux/fsl/enetc_mdio.h>
+ #include <linux/mdio.h>
+ #include <linux/of_mdio.h>
+ #include <linux/iopoll.h>
+ #include <linux/of.h>
+ #include "enetc_pf.h"
++#include "enetc_mdio.h"
+ #define       ENETC_MDIO_CFG  0x0     /* MDIO configuration and status */
+ #define       ENETC_MDIO_CTL  0x4     /* MDIO control */
+@@ -99,7 +99,6 @@ int enetc_mdio_write(struct mii_bus *bus
+       return 0;
+ }
+-EXPORT_SYMBOL_GPL(enetc_mdio_write);
+ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
+ {
+@@ -155,21 +154,6 @@ int enetc_mdio_read(struct mii_bus *bus,
+       return value;
+ }
+-EXPORT_SYMBOL_GPL(enetc_mdio_read);
+-
+-struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
+-{
+-      struct enetc_hw *hw;
+-
+-      hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
+-      if (!hw)
+-              return ERR_PTR(-ENOMEM);
+-
+-      hw->port = port_regs;
+-
+-      return hw;
+-}
+-EXPORT_SYMBOL_GPL(enetc_hw_alloc);
+ int enetc_mdio_probe(struct enetc_pf *pf)
+ {
+--- /dev/null
++++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.h
+@@ -0,0 +1,12 @@
++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
++/* Copyright 2019 NXP */
++
++#include <linux/phy.h>
++
++struct enetc_mdio_priv {
++      struct enetc_hw *hw;
++      int mdio_base;
++};
++
++int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value);
++int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum);
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
+@@ -1,8 +1,8 @@
+ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+ /* Copyright 2019 NXP */
+-#include <linux/fsl/enetc_mdio.h>
+ #include <linux/of_mdio.h>
+ #include "enetc_pf.h"
++#include "enetc_mdio.h"
+ #define ENETC_MDIO_DEV_ID     0xee01
+ #define ENETC_MDIO_DEV_NAME   "FSL PCIe IE Central MDIO"
+@@ -14,29 +14,17 @@ static int enetc_pci_mdio_probe(struct p
+ {
+       struct enetc_mdio_priv *mdio_priv;
+       struct device *dev = &pdev->dev;
+-      void __iomem *port_regs;
+       struct enetc_hw *hw;
+       struct mii_bus *bus;
+       int err;
+-      port_regs = pci_iomap(pdev, 0, 0);
+-      if (!port_regs) {
+-              dev_err(dev, "iomap failed\n");
+-              err = -ENXIO;
+-              goto err_ioremap;
+-      }
+-
+-      hw = enetc_hw_alloc(dev, port_regs);
+-      if (IS_ERR(enetc_hw_alloc)) {
+-              err = PTR_ERR(hw);
+-              goto err_hw_alloc;
+-      }
++      hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
++      if (!hw)
++              return -ENOMEM;
+       bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
+-      if (!bus) {
+-              err = -ENOMEM;
+-              goto err_mdiobus_alloc;
+-      }
++      if (!bus)
++              return -ENOMEM;
+       bus->name = ENETC_MDIO_BUS_NAME;
+       bus->read = enetc_mdio_read;
+@@ -51,7 +39,7 @@ static int enetc_pci_mdio_probe(struct p
+       err = pci_enable_device_mem(pdev);
+       if (err) {
+               dev_err(dev, "device enable failed\n");
+-              goto err_pci_enable;
++              return err;
+       }
+       err = pci_request_region(pdev, 0, KBUILD_MODNAME);
+@@ -60,6 +48,13 @@ static int enetc_pci_mdio_probe(struct p
+               goto err_pci_mem_reg;
+       }
++      hw->port = pci_iomap(pdev, 0, 0);
++      if (!hw->port) {
++              err = -ENXIO;
++              dev_err(dev, "iomap failed\n");
++              goto err_ioremap;
++      }
++
+       err = of_mdiobus_register(bus, dev->of_node);
+       if (err)
+               goto err_mdiobus_reg;
+@@ -69,14 +64,12 @@ static int enetc_pci_mdio_probe(struct p
+       return 0;
+ err_mdiobus_reg:
++      iounmap(mdio_priv->hw->port);
++err_ioremap:
+       pci_release_mem_regions(pdev);
+ err_pci_mem_reg:
+       pci_disable_device(pdev);
+-err_pci_enable:
+-err_mdiobus_alloc:
+-      iounmap(port_regs);
+-err_hw_alloc:
+-err_ioremap:
++
+       return err;
+ }
+--- a/include/linux/fsl/enetc_mdio.h
++++ /dev/null
+@@ -1,21 +0,0 @@
+-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+-/* Copyright 2019 NXP */
+-
+-#include <linux/phy.h>
+-
+-/* PCS registers */
+-#define ENETC_PCS_LINK_TIMER1         0x12
+-#define ENETC_PCS_LINK_TIMER1_VAL     0x06a0
+-#define ENETC_PCS_LINK_TIMER2         0x13
+-#define ENETC_PCS_LINK_TIMER2_VAL     0x0003
+-#define ENETC_PCS_IF_MODE             0x14
+-#define ENETC_PCS_IF_MODE_SGMII_AN    0x0003
+-
+-struct enetc_mdio_priv {
+-      struct enetc_hw *hw;
+-      int mdio_base;
+-};
+-
+-int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value);
+-int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum);
+-struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0374-Revert-net-phylink-call-mac_an_restart-for-SGMII-QSG.patch b/target/linux/layerscape/patches-5.4/701-net-0374-Revert-net-phylink-call-mac_an_restart-for-SGMII-QSG.patch
new file mode 100644 (file)
index 0000000..4b2cee6
--- /dev/null
@@ -0,0 +1,26 @@
+From d3a532021976d98bfc9e3dac18a17abccf6eb567 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 6 Jan 2020 14:31:42 +0200
+Subject: [PATCH] Revert "net: phylink: call mac_an_restart for SGMII/QSGMII
+ inband interfaces too"
+
+This reverts commit 57fe15baac62dad00817e3359cefc123e24f10a2.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/phy/phylink.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -360,9 +360,7 @@ static void phylink_mac_config_up(struct
+ static void phylink_mac_an_restart(struct phylink *pl)
+ {
+       if (pl->link_config.an_enabled &&
+-          (phy_interface_mode_is_8023z(pl->link_config.interface) ||
+-           pl->link_config.interface == PHY_INTERFACE_MODE_SGMII ||
+-           pl->link_config.interface == PHY_INTERFACE_MODE_QSGMII))
++          phy_interface_mode_is_8023z(pl->link_config.interface))
+               pl->ops->mac_an_restart(pl->config);
+ }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0375-Revert-net-phylink-make-QSGMII-a-valid-PHY-mode-for-.patch b/target/linux/layerscape/patches-5.4/701-net-0375-Revert-net-phylink-make-QSGMII-a-valid-PHY-mode-for-.patch
new file mode 100644 (file)
index 0000000..e2bce2f
--- /dev/null
@@ -0,0 +1,23 @@
+From e53b64cab45ea4d01226840efd963a6bec8ad2f9 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 6 Jan 2020 14:31:58 +0200
+Subject: [PATCH] Revert "net: phylink: make QSGMII a valid PHY mode for
+ in-band AN"
+
+This reverts commit fe7fd9f6afce50c0fc09fd3d56cd59eda44d8dd0.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/phy/phylink.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -283,7 +283,6 @@ static int phylink_parse_mode(struct phy
+               switch (pl->link_config.interface) {
+               case PHY_INTERFACE_MODE_SGMII:
+-              case PHY_INTERFACE_MODE_QSGMII:
+                       phylink_set(pl->supported, 10baseT_Half);
+                       phylink_set(pl->supported, 10baseT_Full);
+                       phylink_set(pl->supported, 100baseT_Half);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0376-Revert-mii-Add-helpers-for-parsing-SGMII-auto-negoti.patch b/target/linux/layerscape/patches-5.4/701-net-0376-Revert-mii-Add-helpers-for-parsing-SGMII-auto-negoti.patch
new file mode 100644 (file)
index 0000000..3831cac
--- /dev/null
@@ -0,0 +1,110 @@
+From c6f9fb78b7534392d3be307e566d10c8525c7c9a Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 6 Jan 2020 14:32:06 +0200
+Subject: [PATCH] Revert "mii: Add helpers for parsing SGMII auto-negotiation"
+
+This reverts commit de81e3c1ccbf27eda7584e23c713705a221a57da.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ include/linux/mii.h      | 50 ------------------------------------------------
+ include/uapi/linux/mii.h | 10 ----------
+ 2 files changed, 60 deletions(-)
+
+--- a/include/linux/mii.h
++++ b/include/linux/mii.h
+@@ -373,56 +373,6 @@ static inline u32 mii_lpa_to_ethtool_lpa
+ }
+ /**
+- * mii_lpa_mod_linkmode_adv_sgmii
+- * @lp_advertising: pointer to destination link mode.
+- * @lpa: value of the MII_LPA register
+- *
+- * A small helper function that translates MII_LPA bits to
+- * linkmode advertisement settings for SGMII.
+- * Leaves other bits unchanged.
+- */
+-static inline void
+-mii_lpa_mod_linkmode_lpa_sgmii(unsigned long *lp_advertising, u32 lpa)
+-{
+-      u32 speed_duplex = lpa & LPA_SGMII_DPX_SPD_MASK;
+-
+-      linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, lp_advertising,
+-                       speed_duplex == LPA_SGMII_1000HALF);
+-
+-      linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, lp_advertising,
+-                       speed_duplex == LPA_SGMII_1000FULL);
+-
+-      linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, lp_advertising,
+-                       speed_duplex == LPA_SGMII_100HALF);
+-
+-      linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, lp_advertising,
+-                       speed_duplex == LPA_SGMII_100FULL);
+-
+-      linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, lp_advertising,
+-                       speed_duplex == LPA_SGMII_10HALF);
+-
+-      linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, lp_advertising,
+-                       speed_duplex == LPA_SGMII_10FULL);
+-}
+-
+-/**
+- * mii_lpa_to_linkmode_adv_sgmii
+- * @advertising: pointer to destination link mode.
+- * @lpa: value of the MII_LPA register
+- *
+- * A small helper function that translates MII_ADVERTISE bits
+- * to linkmode advertisement settings when in SGMII mode.
+- * Clears the old value of advertising.
+- */
+-static inline void mii_lpa_to_linkmode_lpa_sgmii(unsigned long *lp_advertising,
+-                                               u32 lpa)
+-{
+-      linkmode_zero(lp_advertising);
+-
+-      mii_lpa_mod_linkmode_lpa_sgmii(lp_advertising, lpa);
+-}
+-
+-/**
+  * mii_adv_mod_linkmode_adv_t
+  * @advertising:pointer to destination link mode.
+  * @adv: value of the MII_ADVERTISE register
+--- a/include/uapi/linux/mii.h
++++ b/include/uapi/linux/mii.h
+@@ -71,7 +71,6 @@
+ /* Advertisement control register. */
+ #define ADVERTISE_SLCT                0x001f  /* Selector bits               */
+ #define ADVERTISE_CSMA                0x0001  /* Only selector supported     */
+-#define ADVERTISE_SGMII               0x0001  /* Can do SGMII                */
+ #define ADVERTISE_10HALF      0x0020  /* Try for 10mbps half-duplex  */
+ #define ADVERTISE_1000XFULL   0x0020  /* Try for 1000BASE-X full-duplex */
+ #define ADVERTISE_10FULL      0x0040  /* Try for 10mbps full-duplex  */
+@@ -95,7 +94,6 @@
+ /* Link partner ability register. */
+ #define LPA_SLCT              0x001f  /* Same as advertise selector  */
+-#define LPA_SGMII             0x0001  /* Can do SGMII                */
+ #define LPA_10HALF            0x0020  /* Can do 10mbps half-duplex   */
+ #define LPA_1000XFULL         0x0020  /* Can do 1000BASE-X full-duplex */
+ #define LPA_10FULL            0x0040  /* Can do 10mbps full-duplex   */
+@@ -106,19 +104,11 @@
+ #define LPA_1000XPAUSE_ASYM   0x0100  /* Can do 1000BASE-X pause asym*/
+ #define LPA_100BASE4          0x0200  /* Can do 100mbps 4k packets   */
+ #define LPA_PAUSE_CAP         0x0400  /* Can pause                   */
+-#define LPA_SGMII_DPX_SPD_MASK        0x1C00  /* SGMII duplex and speed bits */
+-#define LPA_SGMII_10HALF      0x0000  /* Can do SGMII 10mbps half-duplex */
+-#define LPA_SGMII_10FULL      0x1000  /* Can do SGMII 10mbps full-duplex */
+-#define LPA_SGMII_100HALF     0x0400  /* Can do SGMII 100mbps half-duplex */
+-#define LPA_SGMII_100FULL     0x1400  /* Can do SGMII 100mbps full-duplex */
+ #define LPA_PAUSE_ASYM                0x0800  /* Can pause asymetrically     */
+-#define LPA_SGMII_1000HALF    0x0800  /* Can do SGMII 1000mbps half-duplex */
+-#define LPA_SGMII_1000FULL    0x1800  /* Can do SGMII 1000mbps full-duplex */
+ #define LPA_RESV              0x1000  /* Unused...                   */
+ #define LPA_RFAULT            0x2000  /* Link partner faulted        */
+ #define LPA_LPACK             0x4000  /* Link partner acked us       */
+ #define LPA_NPAGE             0x8000  /* Next page bit               */
+-#define LPA_SGMII_LINK                0x8000  /* Link partner has link       */
+ #define LPA_DUPLEX            (LPA_10FULL | LPA_100FULL)
+ #define LPA_100                       (LPA_100FULL | LPA_100HALF | LPA_100BASE4)
diff --git a/target/linux/layerscape/patches-5.4/701-net-0377-net-dsa-ocelot-add-NET_VENDOR_MICROSEMI-dependency.patch b/target/linux/layerscape/patches-5.4/701-net-0377-net-dsa-ocelot-add-NET_VENDOR_MICROSEMI-dependency.patch
new file mode 100644 (file)
index 0000000..81db669
--- /dev/null
@@ -0,0 +1,41 @@
+From ac2fb1a9879204825467eed7a138a3d77c1ecfe8 Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Mon, 16 Dec 2019 00:12:14 +0200
+Subject: [PATCH] net: dsa: ocelot: add NET_VENDOR_MICROSEMI dependency
+
+Selecting MSCC_OCELOT_SWITCH is not possible when NET_VENDOR_MICROSEMI
+is disabled:
+
+WARNING: unmet direct dependencies detected for MSCC_OCELOT_SWITCH
+  Depends on [n]: NETDEVICES [=y] && ETHERNET [=n] && NET_VENDOR_MICROSEMI [=n] && NET_SWITCHDEV [=y] && HAS_IOMEM [=y]
+  Selected by [m]:
+  - NET_DSA_MSCC_FELIX [=m] && NETDEVICES [=y] && HAVE_NET_DSA [=y] && NET_DSA [=y] && PCI [=y]
+
+Add a Kconfig dependency on NET_VENDOR_MICROSEMI, which also implies
+CONFIG_NETDEVICES.
+
+Depending on a vendor config violates menuconfig locality for the DSA
+driver, but is the smallest compromise since all other solutions are
+much more complicated (see [0]).
+
+https://www.spinics.net/lists/netdev/msg618808.html
+
+Fixes: 56051948773e ("net: dsa: ocelot: add driver for Felix switch family")
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Mao Wenan <maowenan@huawei.com>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/ocelot/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/dsa/ocelot/Kconfig
++++ b/drivers/net/dsa/ocelot/Kconfig
+@@ -2,6 +2,7 @@
+ config NET_DSA_MSCC_FELIX
+       tristate "Ocelot / Felix Ethernet switch support"
+       depends on NET_DSA && PCI
++      depends on NET_VENDOR_MICROSEMI
+       select MSCC_OCELOT_SWITCH
+       select NET_DSA_TAG_OCELOT
+       help
diff --git a/target/linux/layerscape/patches-5.4/701-net-0378-mii-Add-helpers-for-parsing-SGMII-auto-negotiation.patch b/target/linux/layerscape/patches-5.4/701-net-0378-mii-Add-helpers-for-parsing-SGMII-auto-negotiation.patch
new file mode 100644 (file)
index 0000000..3aeda2a
--- /dev/null
@@ -0,0 +1,105 @@
+From 4f3ba90c37ec5aedd2227beb013bab59035fbb57 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 30 Sep 2019 19:20:26 +0300
+Subject: [PATCH] mii: Add helpers for parsing SGMII auto-negotiation
+
+Typically a MAC PCS auto-configures itself after it receives the
+negotiated copper-side link settings from the PHY, but some MAC devices
+are more special and need manual interpretation of the SGMII AN result.
+
+In other cases, the PCS exposes the entire tx_config_reg base page as it
+is transmitted on the wire during auto-negotiation, so it makes sense to
+be able to decode the equivalent lp_advertised bit mask from the raw u16
+(of course, "lp" considering the PCS to be the local PHY).
+
+Therefore, add the bit definitions for the SGMII registers 4 and 5
+(local device ability, link partner ability), as well as a link_mode
+conversion helper that can be used to feed the AN results into
+phy_resolve_aneg_linkmode.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ include/linux/mii.h      | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
+ include/uapi/linux/mii.h | 12 ++++++++++++
+ 2 files changed, 62 insertions(+)
+
+--- a/include/linux/mii.h
++++ b/include/linux/mii.h
+@@ -373,6 +373,56 @@ static inline u32 mii_lpa_to_ethtool_lpa
+ }
+ /**
++ * mii_lpa_mod_linkmode_adv_sgmii
++ * @lp_advertising: pointer to destination link mode.
++ * @lpa: value of the MII_LPA register
++ *
++ * A small helper function that translates MII_LPA bits to
++ * linkmode advertisement settings for SGMII.
++ * Leaves other bits unchanged.
++ */
++static inline void
++mii_lpa_mod_linkmode_lpa_sgmii(unsigned long *lp_advertising, u32 lpa)
++{
++      u32 speed_duplex = lpa & LPA_SGMII_DPX_SPD_MASK;
++
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, lp_advertising,
++                       speed_duplex == LPA_SGMII_1000HALF);
++
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, lp_advertising,
++                       speed_duplex == LPA_SGMII_1000FULL);
++
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, lp_advertising,
++                       speed_duplex == LPA_SGMII_100HALF);
++
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, lp_advertising,
++                       speed_duplex == LPA_SGMII_100FULL);
++
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, lp_advertising,
++                       speed_duplex == LPA_SGMII_10HALF);
++
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, lp_advertising,
++                       speed_duplex == LPA_SGMII_10FULL);
++}
++
++/**
++ * mii_lpa_to_linkmode_adv_sgmii
++ * @advertising: pointer to destination link mode.
++ * @lpa: value of the MII_LPA register
++ *
++ * A small helper function that translates MII_ADVERTISE bits
++ * to linkmode advertisement settings when in SGMII mode.
++ * Clears the old value of advertising.
++ */
++static inline void mii_lpa_to_linkmode_lpa_sgmii(unsigned long *lp_advertising,
++                                               u32 lpa)
++{
++      linkmode_zero(lp_advertising);
++
++      mii_lpa_mod_linkmode_lpa_sgmii(lp_advertising, lpa);
++}
++
++/**
+  * mii_adv_mod_linkmode_adv_t
+  * @advertising:pointer to destination link mode.
+  * @adv: value of the MII_ADVERTISE register
+--- a/include/uapi/linux/mii.h
++++ b/include/uapi/linux/mii.h
+@@ -131,6 +131,18 @@
+ #define NWAYTEST_LOOPBACK     0x0100  /* Enable loopback for N-way   */
+ #define NWAYTEST_RESV2                0xfe00  /* Unused...                   */
++/* MAC and PHY tx_config_Reg[15:0] for SGMII in-band auto-negotiation.*/
++#define ADVERTISE_SGMII               0x0001  /* MAC can do SGMII            */
++#define LPA_SGMII             0x0001  /* PHY can do SGMII            */
++#define LPA_SGMII_DPX_SPD_MASK        0x1C00  /* SGMII duplex and speed bits */
++#define LPA_SGMII_10HALF      0x0000  /* Can do 10mbps half-duplex   */
++#define LPA_SGMII_10FULL      0x1000  /* Can do 10mbps full-duplex   */
++#define LPA_SGMII_100HALF     0x0400  /* Can do 100mbps half-duplex  */
++#define LPA_SGMII_100FULL     0x1400  /* Can do 100mbps full-duplex  */
++#define LPA_SGMII_1000HALF    0x0800  /* Can do 1000mbps half-duplex */
++#define LPA_SGMII_1000FULL    0x1800  /* Can do 1000mbps full-duplex */
++#define LPA_SGMII_LINK                0x8000  /* PHY link with copper-side partner */
++
+ /* 1000BASE-T Control register */
+ #define ADVERTISE_1000FULL    0x0200  /* Advertise 1000BASE-T full duplex */
+ #define ADVERTISE_1000HALF    0x0100  /* Advertise 1000BASE-T half duplex */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0379-net-phylink-make-QSGMII-a-valid-PHY-mode-for-in-band.patch b/target/linux/layerscape/patches-5.4/701-net-0379-net-phylink-make-QSGMII-a-valid-PHY-mode-for-in-band.patch
new file mode 100644 (file)
index 0000000..44c9a86
--- /dev/null
@@ -0,0 +1,30 @@
+From 5fdc065751ee25688f99da501123f7e7d4020751 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 22 Nov 2019 13:46:46 +0200
+Subject: [PATCH] net: phylink: make QSGMII a valid PHY mode for in-band AN
+
+QSGMII is a SerDes protocol clocked at 5 Gbaud (4 times higher than
+SGMII which is clocked at 1.25 Gbaud), with the same 8b/10b encoding and
+some extra symbols for synchronization. Logically it offers 4 SGMII
+interfaces multiplexed onto the same physical lanes. Each MAC PCS has
+its own in-band AN process with the system side of the QSGMII PHY, which
+is identical to the regular SGMII AN process.
+
+So allow QSGMII as a valid in-band AN mode, since it is no different
+from software perspective from regular SGMII.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/phy/phylink.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -283,6 +283,7 @@ static int phylink_parse_mode(struct phy
+               switch (pl->link_config.interface) {
+               case PHY_INTERFACE_MODE_SGMII:
++              case PHY_INTERFACE_MODE_QSGMII:
+                       phylink_set(pl->supported, 10baseT_Half);
+                       phylink_set(pl->supported, 10baseT_Full);
+                       phylink_set(pl->supported, 100baseT_Half);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0380-net-phylink-add-support-for-polling-MAC-PCS.patch b/target/linux/layerscape/patches-5.4/701-net-0380-net-phylink-add-support-for-polling-MAC-PCS.patch
new file mode 100644 (file)
index 0000000..f9b97b3
--- /dev/null
@@ -0,0 +1,74 @@
+From c12db737cf62ca262c01ec6d4ba942b34db35d8b Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 27 Dec 2019 19:45:22 +0200
+Subject: [PATCH] net: phylink: add support for polling MAC PCS
+
+Some MAC PCS blocks are unable to provide interrupts when their status
+changes. As we already have support in phylink for polling status, use
+this to provide a hook for MACs to enable polling mode.
+
+The patch idea was picked up from Russell King's suggestion on the macb
+phylink patch thread here [0] but the implementation was changed.
+Instead of introducing a new phylink_start_poll() function, which would
+make the implementation cumbersome for common PHYLINK implementations
+for multiple types of devices, like DSA, just add a boolean property to
+the phylink_config structure, which is just as backwards-compatible.
+
+https://lkml.org/lkml/2019/12/16/603
+
+Suggested-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+
+Conflicts:
+       drivers/net/phy/phylink.c
+
+with upstream commit 24cf0e693bb5 ("net: phylink: split link_an_mode
+configured and current settings") submitted for net-next and merged
+during v5.5-rc1.
+---
+ Documentation/networking/sfp-phylink.rst | 3 ++-
+ drivers/net/phy/phylink.c                | 3 ++-
+ include/linux/phylink.h                  | 2 ++
+ 3 files changed, 6 insertions(+), 2 deletions(-)
+
+--- a/Documentation/networking/sfp-phylink.rst
++++ b/Documentation/networking/sfp-phylink.rst
+@@ -251,7 +251,8 @@ this documentation.
+       phylink_mac_change(priv->phylink, link_is_up);
+     where ``link_is_up`` is true if the link is currently up or false
+-    otherwise.
++    otherwise. If a MAC is unable to provide these interrupts, then
++    it should set ``priv->phylink_config.pcs_poll = true;`` in step 9.
+ 11. Verify that the driver does not call::
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1008,7 +1008,8 @@ void phylink_start(struct phylink *pl)
+               if (irq <= 0)
+                       mod_timer(&pl->link_poll, jiffies + HZ);
+       }
+-      if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->get_fixed_state)
++      if ((pl->cfg_link_an_mode == MLO_AN_FIXED && pl->get_fixed_state) ||
++          pl->config->pcs_poll)
+               mod_timer(&pl->link_poll, jiffies + HZ);
+       if (pl->phydev)
+               phy_start(pl->phydev);
+--- a/include/linux/phylink.h
++++ b/include/linux/phylink.h
+@@ -63,10 +63,12 @@ enum phylink_op_type {
+  * struct phylink_config - PHYLINK configuration structure
+  * @dev: a pointer to a struct device associated with the MAC
+  * @type: operation type of PHYLINK instance
++ * @pcs_poll: MAC PCS cannot provide link change interrupt
+  */
+ struct phylink_config {
+       struct device *dev;
+       enum phylink_op_type type;
++      bool pcs_poll;
+ };
+ /**
diff --git a/target/linux/layerscape/patches-5.4/701-net-0381-net-dsa-Pass-pcs_poll-flag-from-driver-to-PHYLINK.patch b/target/linux/layerscape/patches-5.4/701-net-0381-net-dsa-Pass-pcs_poll-flag-from-driver-to-PHYLINK.patch
new file mode 100644 (file)
index 0000000..40d22f4
--- /dev/null
@@ -0,0 +1,48 @@
+From 3f911800613a3417101563b488c51a9b310ba7fa Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 27 Dec 2019 20:14:57 +0200
+Subject: [PATCH] net: dsa: Pass pcs_poll flag from driver to PHYLINK
+
+The DSA drivers that implement .phylink_mac_link_state should normally
+register an interrupt for the PCS, from which they should call
+phylink_mac_change(). However not all switches implement this, and those
+who don't should set this flag in dsa_switch in the .setup callback, so
+that PHYLINK will poll for a few ms until the in-band AN link timer
+expires and the PCS state settles.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+Conflicts:
+       include/net/dsa.h
+
+trivially with upstream commit 05f294a85235 ("net: dsa: allocate ports
+on touch") which was merged in v5.4-rc3.
+---
+ include/net/dsa.h | 5 +++++
+ net/dsa/port.c    | 1 +
+ 2 files changed, 6 insertions(+)
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -277,6 +277,11 @@ struct dsa_switch {
+        */
+       bool                    vlan_filtering;
++      /* MAC PCS does not provide link state change interrupt, and requires
++       * polling. Flag passed on to PHYLINK.
++       */
++      bool                    pcs_poll;
++
+       /* Dynamically allocated ports, keep last */
+       size_t num_ports;
+       struct dsa_port ports[];
+--- a/net/dsa/port.c
++++ b/net/dsa/port.c
+@@ -625,6 +625,7 @@ static int dsa_port_phylink_register(str
+       dp->pl_config.dev = ds->dev;
+       dp->pl_config.type = PHYLINK_DEV;
++      dp->pl_config.pcs_poll = ds->pcs_poll;
+       dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn),
+                               mode, &dsa_port_phylink_mac_ops);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0382-enetc-Make-MDIO-accessors-more-generic-and-export-to.patch b/target/linux/layerscape/patches-5.4/701-net-0382-enetc-Make-MDIO-accessors-more-generic-and-export-to.patch
new file mode 100644 (file)
index 0000000..6a1e647
--- /dev/null
@@ -0,0 +1,446 @@
+From 126e6f022c749ac1bf3a607269a106ccd87d0594 Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Mon, 12 Aug 2019 20:26:42 +0300
+Subject: [PATCH] enetc: Make MDIO accessors more generic and export to
+ include/linux/fsl
+
+Within the LS1028A SoC, the register map for the ENETC MDIO controller
+is instantiated a few times: for the central (external) MDIO controller,
+for the internal bus of each standalone ENETC port, and for the internal
+bus of the Felix switch.
+
+Refactoring is needed to support multiple MDIO buses from multiple
+drivers. The enetc_hw structure is made an opaque type and a smaller
+enetc_mdio_priv is created.
+
+'mdio_base' - MDIO registers base address - is being parameterized, to
+be able to work with different MDIO register bases.
+
+The ENETC MDIO bus operations are exported from the fsl-enetc-mdio
+kernel object, the same that registers the central MDIO controller (the
+dedicated PF). The ENETC main driver has been changed to select it, and
+use its exported helpers to further register its private MDIO bus. The
+DSA Felix driver will do the same.
+
+Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+Conflicts:
+       drivers/net/ethernet/freescale/enetc/enetc_mdio.c
+       drivers/net/ethernet/freescale/enetc/enetc_mdio.h
+       drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
+       drivers/net/ethernet/freescale/enetc/enetc_pf.c
+       drivers/net/ethernet/freescale/enetc/enetc_pf.h
+
+mostly with the previous (downstream version of this commit) patch
+572ee5d842da ("enetc: Make mdio accessors more generic"), which couldn't
+be reverted cleanly due to the existing downstream workaround for the
+MDIO erratum.
+---
+ drivers/net/ethernet/freescale/enetc/Kconfig       |  1 +
+ drivers/net/ethernet/freescale/enetc/Makefile      |  2 +-
+ drivers/net/ethernet/freescale/enetc/enetc_mdio.c  | 76 ++++------------------
+ drivers/net/ethernet/freescale/enetc/enetc_mdio.h  | 12 ----
+ .../net/ethernet/freescale/enetc/enetc_pci_mdio.c  | 41 +++++++-----
+ drivers/net/ethernet/freescale/enetc/enetc_pf.c    | 71 ++++++++++++++++++++
+ drivers/net/ethernet/freescale/enetc/enetc_pf.h    |  5 --
+ include/linux/fsl/enetc_mdio.h                     | 55 ++++++++++++++++
+ 8 files changed, 163 insertions(+), 100 deletions(-)
+ delete mode 100644 drivers/net/ethernet/freescale/enetc/enetc_mdio.h
+ create mode 100644 include/linux/fsl/enetc_mdio.h
+
+--- a/drivers/net/ethernet/freescale/enetc/Kconfig
++++ b/drivers/net/ethernet/freescale/enetc/Kconfig
+@@ -2,6 +2,7 @@
+ config FSL_ENETC
+       tristate "ENETC PF driver"
+       depends on PCI && PCI_MSI && (ARCH_LAYERSCAPE || COMPILE_TEST)
++      select FSL_ENETC_MDIO
+       select PHYLIB
+       help
+         This driver supports NXP ENETC gigabit ethernet controller PCIe
+--- a/drivers/net/ethernet/freescale/enetc/Makefile
++++ b/drivers/net/ethernet/freescale/enetc/Makefile
+@@ -3,7 +3,7 @@
+ common-objs := enetc.o enetc_cbdr.o enetc_ethtool.o
+ obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
+-fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs)
++fsl-enetc-y := enetc_pf.o $(common-objs)
+ fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
+ fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
+ fsl-enetc-$(CONFIG_ENETC_TSN) += enetc_tsn.o
+--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
+@@ -1,13 +1,13 @@
+ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+ /* Copyright 2019 NXP */
++#include <linux/fsl/enetc_mdio.h>
+ #include <linux/mdio.h>
+ #include <linux/of_mdio.h>
+ #include <linux/iopoll.h>
+ #include <linux/of.h>
+ #include "enetc_pf.h"
+-#include "enetc_mdio.h"
+ #define       ENETC_MDIO_CFG  0x0     /* MDIO configuration and status */
+ #define       ENETC_MDIO_CTL  0x4     /* MDIO control */
+@@ -99,6 +99,7 @@ int enetc_mdio_write(struct mii_bus *bus
+       return 0;
+ }
++EXPORT_SYMBOL_GPL(enetc_mdio_write);
+ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
+ {
+@@ -154,73 +155,18 @@ int enetc_mdio_read(struct mii_bus *bus,
+       return value;
+ }
++EXPORT_SYMBOL_GPL(enetc_mdio_read);
+-int enetc_mdio_probe(struct enetc_pf *pf)
++struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
+ {
+-      struct device *dev = &pf->si->pdev->dev;
+-      struct enetc_mdio_priv *mdio_priv;
+-      struct device_node *np;
+-      struct mii_bus *bus;
+-      int err;
+-
+-      bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
+-      if (!bus)
+-              return -ENOMEM;
+-
+-      bus->name = "Freescale ENETC MDIO Bus";
+-      bus->read = enetc_mdio_read;
+-      bus->write = enetc_mdio_write;
+-      bus->parent = dev;
+-      mdio_priv = bus->priv;
+-      mdio_priv->hw = &pf->si->hw;
+-      mdio_priv->mdio_base = ENETC_EMDIO_BASE;
+-      snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
+-
+-      np = of_get_child_by_name(dev->of_node, "mdio");
+-      if (!np) {
+-              dev_err(dev, "MDIO node missing\n");
+-              return -EINVAL;
+-      }
+-
+-      err = of_mdiobus_register(bus, np);
+-      if (err) {
+-              of_node_put(np);
+-              dev_err(dev, "cannot register MDIO bus\n");
+-              return err;
+-      }
+-
+-      of_node_put(np);
+-      pf->mdio = bus;
+-
+-      return 0;
+-}
++      struct enetc_hw *hw;
+-void enetc_mdio_remove(struct enetc_pf *pf)
+-{
+-      if (pf->mdio)
+-              mdiobus_unregister(pf->mdio);
+-}
+-
+-int enetc_imdio_init(struct enetc_pf *pf)
+-{
+-      struct device *dev = &pf->si->pdev->dev;
+-      struct enetc_mdio_priv *mdio_priv;
+-      struct mii_bus *bus;
++      hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
++      if (!hw)
++              return ERR_PTR(-ENOMEM);
+-      bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
+-      if (!bus)
+-              return -ENOMEM;
++      hw->port = port_regs;
+-      bus->name = "FSL ENETC internal MDIO Bus";
+-      bus->read = enetc_mdio_read;
+-      bus->write = enetc_mdio_write;
+-      bus->parent = dev;
+-      mdio_priv = bus->priv;
+-      mdio_priv->hw = &pf->si->hw;
+-      mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
+-      snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
+-
+-      pf->imdio = bus;
+-
+-      return 0;
++      return hw;
+ }
++EXPORT_SYMBOL_GPL(enetc_hw_alloc);
+--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.h
++++ /dev/null
+@@ -1,12 +0,0 @@
+-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+-/* Copyright 2019 NXP */
+-
+-#include <linux/phy.h>
+-
+-struct enetc_mdio_priv {
+-      struct enetc_hw *hw;
+-      int mdio_base;
+-};
+-
+-int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value);
+-int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum);
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
+@@ -1,8 +1,8 @@
+ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+ /* Copyright 2019 NXP */
++#include <linux/fsl/enetc_mdio.h>
+ #include <linux/of_mdio.h>
+ #include "enetc_pf.h"
+-#include "enetc_mdio.h"
+ #define ENETC_MDIO_DEV_ID     0xee01
+ #define ENETC_MDIO_DEV_NAME   "FSL PCIe IE Central MDIO"
+@@ -14,17 +14,29 @@ static int enetc_pci_mdio_probe(struct p
+ {
+       struct enetc_mdio_priv *mdio_priv;
+       struct device *dev = &pdev->dev;
++      void __iomem *port_regs;
+       struct enetc_hw *hw;
+       struct mii_bus *bus;
+       int err;
+-      hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
+-      if (!hw)
+-              return -ENOMEM;
++      port_regs = pci_iomap(pdev, 0, 0);
++      if (!port_regs) {
++              dev_err(dev, "iomap failed\n");
++              err = -ENXIO;
++              goto err_ioremap;
++      }
++
++      hw = enetc_hw_alloc(dev, port_regs);
++      if (IS_ERR(enetc_hw_alloc)) {
++              err = PTR_ERR(hw);
++              goto err_hw_alloc;
++      }
+       bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
+-      if (!bus)
+-              return -ENOMEM;
++      if (!bus) {
++              err = -ENOMEM;
++              goto err_mdiobus_alloc;
++      }
+       bus->name = ENETC_MDIO_BUS_NAME;
+       bus->read = enetc_mdio_read;
+@@ -39,7 +51,7 @@ static int enetc_pci_mdio_probe(struct p
+       err = pci_enable_device_mem(pdev);
+       if (err) {
+               dev_err(dev, "device enable failed\n");
+-              return err;
++              goto err_pci_enable;
+       }
+       err = pci_request_region(pdev, 0, KBUILD_MODNAME);
+@@ -48,13 +60,6 @@ static int enetc_pci_mdio_probe(struct p
+               goto err_pci_mem_reg;
+       }
+-      hw->port = pci_iomap(pdev, 0, 0);
+-      if (!hw->port) {
+-              err = -ENXIO;
+-              dev_err(dev, "iomap failed\n");
+-              goto err_ioremap;
+-      }
+-
+       err = of_mdiobus_register(bus, dev->of_node);
+       if (err)
+               goto err_mdiobus_reg;
+@@ -64,12 +69,14 @@ static int enetc_pci_mdio_probe(struct p
+       return 0;
+ err_mdiobus_reg:
+-      iounmap(mdio_priv->hw->port);
+-err_ioremap:
+       pci_release_mem_regions(pdev);
+ err_pci_mem_reg:
+       pci_disable_device(pdev);
+-
++err_pci_enable:
++err_mdiobus_alloc:
++      iounmap(port_regs);
++err_hw_alloc:
++err_ioremap:
+       return err;
+ }
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -2,6 +2,7 @@
+ /* Copyright 2017-2019 NXP */
+ #include <linux/module.h>
++#include <linux/fsl/enetc_mdio.h>
+ #include <linux/of_mdio.h>
+ #include <linux/of_net.h>
+ #include "enetc_pf.h"
+@@ -760,6 +761,52 @@ static void enetc_pf_netdev_setup(struct
+       enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr);
+ }
++static int enetc_mdio_probe(struct enetc_pf *pf)
++{
++      struct device *dev = &pf->si->pdev->dev;
++      struct enetc_mdio_priv *mdio_priv;
++      struct device_node *np;
++      struct mii_bus *bus;
++      int err;
++
++      bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
++      if (!bus)
++              return -ENOMEM;
++
++      bus->name = "Freescale ENETC MDIO Bus";
++      bus->read = enetc_mdio_read;
++      bus->write = enetc_mdio_write;
++      bus->parent = dev;
++      mdio_priv = bus->priv;
++      mdio_priv->hw = &pf->si->hw;
++      mdio_priv->mdio_base = ENETC_EMDIO_BASE;
++      snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
++
++      np = of_get_child_by_name(dev->of_node, "mdio");
++      if (!np) {
++              dev_err(dev, "MDIO node missing\n");
++              return -EINVAL;
++      }
++
++      err = of_mdiobus_register(bus, np);
++      if (err) {
++              of_node_put(np);
++              dev_err(dev, "cannot register MDIO bus\n");
++              return err;
++      }
++
++      of_node_put(np);
++      pf->mdio = bus;
++
++      return 0;
++}
++
++static void enetc_mdio_remove(struct enetc_pf *pf)
++{
++      if (pf->mdio)
++              mdiobus_unregister(pf->mdio);
++}
++
+ static int enetc_of_get_phy(struct enetc_pf *pf)
+ {
+       struct device *dev = &pf->si->pdev->dev;
+@@ -846,6 +893,30 @@ static void enetc_configure_sxgmii(struc
+                    ENETC_PCS_CR_LANE_RESET | ENETC_PCS_CR_RESET_AN);
+ }
++static int enetc_imdio_init(struct enetc_pf *pf)
++{
++      struct device *dev = &pf->si->pdev->dev;
++      struct enetc_mdio_priv *mdio_priv;
++      struct mii_bus *bus;
++
++      bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
++      if (!bus)
++              return -ENOMEM;
++
++      bus->name = "FSL ENETC internal MDIO Bus";
++      bus->read = enetc_mdio_read;
++      bus->write = enetc_mdio_write;
++      bus->parent = dev;
++      mdio_priv = bus->priv;
++      mdio_priv->hw = &pf->si->hw;
++      mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
++      snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
++
++      pf->imdio = bus;
++
++      return 0;
++}
++
+ static int enetc_configure_serdes(struct enetc_ndev_priv *priv)
+ {
+       struct enetc_pf *pf = enetc_si_priv(priv->si);
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+@@ -53,8 +53,3 @@ struct enetc_pf {
+ int enetc_msg_psi_init(struct enetc_pf *pf);
+ void enetc_msg_psi_free(struct enetc_pf *pf);
+ void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int mbox_id, u16 *status);
+-
+-/* MDIO */
+-int enetc_mdio_probe(struct enetc_pf *pf);
+-void enetc_mdio_remove(struct enetc_pf *pf);
+-int enetc_imdio_init(struct enetc_pf *pf);
+--- /dev/null
++++ b/include/linux/fsl/enetc_mdio.h
+@@ -0,0 +1,55 @@
++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
++/* Copyright 2019 NXP */
++
++#ifndef _FSL_ENETC_MDIO_H_
++#define _FSL_ENETC_MDIO_H_
++
++#include <linux/phy.h>
++
++/* PCS registers */
++#define ENETC_PCS_LINK_TIMER1                 0x12
++#define ENETC_PCS_LINK_TIMER1_VAL             0x06a0
++#define ENETC_PCS_LINK_TIMER2                 0x13
++#define ENETC_PCS_LINK_TIMER2_VAL             0x0003
++#define ENETC_PCS_IF_MODE                     0x14
++#define ENETC_PCS_IF_MODE_SGMII_EN            BIT(0)
++#define ENETC_PCS_IF_MODE_USE_SGMII_AN                BIT(1)
++#define ENETC_PCS_IF_MODE_SGMII_SPEED(x)      (((x) << 2) & GENMASK(3, 2))
++
++/* Not a mistake, the SerDes PLL needs to be set at 3.125 GHz by Reset
++ * Configuration Word (RCW, outside Linux control) for 2.5G SGMII mode. The PCS
++ * still thinks it's at gigabit.
++ */
++enum enetc_pcs_speed {
++      ENETC_PCS_SPEED_10      = 0,
++      ENETC_PCS_SPEED_100     = 1,
++      ENETC_PCS_SPEED_1000    = 2,
++      ENETC_PCS_SPEED_2500    = 2,
++};
++
++struct enetc_hw;
++
++struct enetc_mdio_priv {
++      struct enetc_hw *hw;
++      int mdio_base;
++};
++
++#if IS_REACHABLE(CONFIG_FSL_ENETC_MDIO)
++
++int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum);
++int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value);
++struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs);
++
++#else
++
++static inline int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
++{ return -EINVAL; }
++static inline int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum,
++                                 u16 value)
++{ return -EINVAL; }
++struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
++{ return ERR_PTR(-EINVAL); }
++
++#endif
++
++#endif
diff --git a/target/linux/layerscape/patches-5.4/701-net-0383-enetc-Set-MDIO_CFG_HOLD-to-the-recommended-value-of-.patch b/target/linux/layerscape/patches-5.4/701-net-0383-enetc-Set-MDIO_CFG_HOLD-to-the-recommended-value-of-.patch
new file mode 100644 (file)
index 0000000..50b3452
--- /dev/null
@@ -0,0 +1,58 @@
+From c0308743202449028d2b839d9b01d3d5ed2b210a Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Wed, 27 Nov 2019 19:21:13 +0200
+Subject: [PATCH] enetc: Set MDIO_CFG_HOLD to the recommended value of 2
+
+This increases the MDIO hold time to 5 enet_clk cycles from the previous
+value of 0. This is actually the out-of-reset value, that the driver was
+previously overwriting with 0. Zero worked for the external MDIO, but
+breaks communication with the internal MDIO buses on which the PCS of
+ENETC SI's and Felix switch are found.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_mdio.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
+@@ -31,15 +31,19 @@ static inline void _enetc_mdio_wr(struct
+       _enetc_mdio_wr(mdio_priv, ENETC_##off, val)
+ #define enetc_mdio_rd_reg(off)        enetc_mdio_rd(mdio_priv, off)
+-#define ENETC_MDC_DIV         258
+-
+ #define MDIO_CFG_CLKDIV(x)    ((((x) >> 1) & 0xff) << 8)
+ #define MDIO_CFG_BSY          BIT(0)
+ #define MDIO_CFG_RD_ER                BIT(1)
++#define MDIO_CFG_HOLD(x)      (((x) << 2) & GENMASK(4, 2))
+ #define MDIO_CFG_ENC45                BIT(6)
+  /* external MDIO only - driven on neg MDC edge */
+ #define MDIO_CFG_NEG          BIT(23)
++#define ENETC_EMDIO_CFG \
++      (MDIO_CFG_HOLD(2) | \
++       MDIO_CFG_CLKDIV(258) | \
++       MDIO_CFG_NEG)
++
+ #define MDIO_CTL_DEV_ADDR(x)  ((x) & 0x1f)
+ #define MDIO_CTL_PORT_ADDR(x) (((x) & 0x1f) << 5)
+ #define MDIO_CTL_READ         BIT(15)
+@@ -61,7 +65,7 @@ int enetc_mdio_write(struct mii_bus *bus
+       u16 dev_addr;
+       int ret;
+-      mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
++      mdio_cfg = ENETC_EMDIO_CFG;
+       if (regnum & MII_ADDR_C45) {
+               dev_addr = (regnum >> 16) & 0x1f;
+               mdio_cfg |= MDIO_CFG_ENC45;
+@@ -108,7 +112,7 @@ int enetc_mdio_read(struct mii_bus *bus,
+       u16 dev_addr, value;
+       int ret;
+-      mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
++      mdio_cfg = ENETC_EMDIO_CFG;
+       if (regnum & MII_ADDR_C45) {
+               dev_addr = (regnum >> 16) & 0x1f;
+               mdio_cfg |= MDIO_CFG_ENC45;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0384-net-mscc-ocelot-make-phy_mode-a-member-of-the-common.patch b/target/linux/layerscape/patches-5.4/701-net-0384-net-mscc-ocelot-make-phy_mode-a-member-of-the-common.patch
new file mode 100644 (file)
index 0000000..662ad10
--- /dev/null
@@ -0,0 +1,85 @@
+From 1737de8045838dcf3c7713c940eb1582810a319f Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 16 Dec 2019 15:07:20 +0200
+Subject: [PATCH] net: mscc: ocelot: make phy_mode a member of the common
+ struct ocelot_port
+
+The Ocelot switchdev driver and the Felix DSA one need it for different
+reasons. Felix (or at least the VSC9959 instantiation in NXP LS1028A) is
+integrated with the traditional NXP Layerscape PCS design which does not
+support runtime configuration of SerDes protocol. So it needs to
+pre-validate the phy-mode from the device tree and prevent PHYLINK from
+attempting to change it. For this, it needs to cache it in a private
+variable.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/ethernet/mscc/ocelot.c       | 7 ++++---
+ drivers/net/ethernet/mscc/ocelot.h       | 1 -
+ drivers/net/ethernet/mscc/ocelot_board.c | 4 ++--
+ include/soc/mscc/ocelot.h                | 2 ++
+ 4 files changed, 8 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -500,13 +500,14 @@ EXPORT_SYMBOL(ocelot_port_enable);
+ static int ocelot_port_open(struct net_device *dev)
+ {
+       struct ocelot_port_private *priv = netdev_priv(dev);
+-      struct ocelot *ocelot = priv->port.ocelot;
++      struct ocelot_port *ocelot_port = &priv->port;
++      struct ocelot *ocelot = ocelot_port->ocelot;
+       int port = priv->chip_port;
+       int err;
+       if (priv->serdes) {
+               err = phy_set_mode_ext(priv->serdes, PHY_MODE_ETHERNET,
+-                                     priv->phy_mode);
++                                     ocelot_port->phy_mode);
+               if (err) {
+                       netdev_err(dev, "Could not set mode of SerDes\n");
+                       return err;
+@@ -514,7 +515,7 @@ static int ocelot_port_open(struct net_d
+       }
+       err = phy_connect_direct(dev, priv->phy, &ocelot_port_adjust_link,
+-                               priv->phy_mode);
++                               ocelot_port->phy_mode);
+       if (err) {
+               netdev_err(dev, "Could not attach to PHY\n");
+               return err;
+--- a/drivers/net/ethernet/mscc/ocelot.h
++++ b/drivers/net/ethernet/mscc/ocelot.h
+@@ -70,7 +70,6 @@ struct ocelot_port_private {
+       u8 vlan_aware;
+-      phy_interface_t phy_mode;
+       struct phy *serdes;
+       struct ocelot_port_tc tc;
+--- a/drivers/net/ethernet/mscc/ocelot_board.c
++++ b/drivers/net/ethernet/mscc/ocelot_board.c
+@@ -412,9 +412,9 @@ static int mscc_ocelot_probe(struct plat
+               if (phy_mode < 0)
+                       phy_mode = PHY_INTERFACE_MODE_NA;
+-              priv->phy_mode = phy_mode;
++              ocelot_port->phy_mode = phy_mode;
+-              switch (priv->phy_mode) {
++              switch (ocelot_port->phy_mode) {
+               case PHY_INTERFACE_MODE_NA:
+                       continue;
+               case PHY_INTERFACE_MODE_SGMII:
+--- a/include/soc/mscc/ocelot.h
++++ b/include/soc/mscc/ocelot.h
+@@ -425,6 +425,8 @@ struct ocelot_port {
+       u8                              ptp_cmd;
+       struct sk_buff_head             tx_skbs;
+       u8                              ts_id;
++
++      phy_interface_t                 phy_mode;
+ };
+ struct ocelot {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0385-net-mscc-ocelot-export-ANA-DEV-and-QSYS-registers-to.patch b/target/linux/layerscape/patches-5.4/701-net-0385-net-mscc-ocelot-export-ANA-DEV-and-QSYS-registers-to.patch
new file mode 100644 (file)
index 0000000..b300ba9
--- /dev/null
@@ -0,0 +1,2457 @@
+From 518d779810c0e4185f2d8a71fc112232df5be62e Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 16 Dec 2019 15:09:49 +0200
+Subject: [PATCH] net: mscc: ocelot: export ANA, DEV and QSYS registers to
+ include/soc/mscc
+
+Since the Felix DSA driver is implementing its own PHYLINK instance due
+to SoC differences, it needs access to the few registers that are
+common, mainly for flow control.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+Conflicts:
+       drivers/net/ethernet/mscc/ocelot_tsn.c
+
+which has been added in downstream patch b5c05e3404a5 ("net: mscc:
+ocelot: tsn configuration support") and also needs to be adapted to the
+new location of the header files.
+---
+ drivers/net/ethernet/mscc/ocelot.h      |   6 +-
+ drivers/net/ethernet/mscc/ocelot_ana.h  | 642 --------------------------------
+ drivers/net/ethernet/mscc/ocelot_dev.h  | 275 --------------
+ drivers/net/ethernet/mscc/ocelot_qsys.h | 270 --------------
+ drivers/net/ethernet/mscc/ocelot_tsn.c  |   4 +-
+ include/soc/mscc/ocelot_ana.h           | 642 ++++++++++++++++++++++++++++++++
+ include/soc/mscc/ocelot_dev.h           | 275 ++++++++++++++
+ include/soc/mscc/ocelot_qsys.h          | 270 ++++++++++++++
+ 8 files changed, 1192 insertions(+), 1192 deletions(-)
+ delete mode 100644 drivers/net/ethernet/mscc/ocelot_ana.h
+ delete mode 100644 drivers/net/ethernet/mscc/ocelot_dev.h
+ delete mode 100644 drivers/net/ethernet/mscc/ocelot_qsys.h
+ create mode 100644 include/soc/mscc/ocelot_ana.h
+ create mode 100644 include/soc/mscc/ocelot_dev.h
+ create mode 100644 include/soc/mscc/ocelot_qsys.h
+
+--- a/drivers/net/ethernet/mscc/ocelot.h
++++ b/drivers/net/ethernet/mscc/ocelot.h
+@@ -18,11 +18,11 @@
+ #include <linux/ptp_clock_kernel.h>
+ #include <linux/regmap.h>
++#include <soc/mscc/ocelot_qsys.h>
+ #include <soc/mscc/ocelot_sys.h>
++#include <soc/mscc/ocelot_dev.h>
++#include <soc/mscc/ocelot_ana.h>
+ #include <soc/mscc/ocelot.h>
+-#include "ocelot_ana.h"
+-#include "ocelot_dev.h"
+-#include "ocelot_qsys.h"
+ #include "ocelot_rew.h"
+ #include "ocelot_qs.h"
+ #include "ocelot_tc.h"
+--- a/drivers/net/ethernet/mscc/ocelot_ana.h
++++ /dev/null
+@@ -1,642 +0,0 @@
+-/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+-/*
+- * Microsemi Ocelot Switch driver
+- *
+- * Copyright (c) 2017 Microsemi Corporation
+- */
+-
+-#ifndef _MSCC_OCELOT_ANA_H_
+-#define _MSCC_OCELOT_ANA_H_
+-
+-#define ANA_ANAGEFIL_B_DOM_EN                             BIT(22)
+-#define ANA_ANAGEFIL_B_DOM_VAL                            BIT(21)
+-#define ANA_ANAGEFIL_AGE_LOCKED                           BIT(20)
+-#define ANA_ANAGEFIL_PID_EN                               BIT(19)
+-#define ANA_ANAGEFIL_PID_VAL(x)                           (((x) << 14) & GENMASK(18, 14))
+-#define ANA_ANAGEFIL_PID_VAL_M                            GENMASK(18, 14)
+-#define ANA_ANAGEFIL_PID_VAL_X(x)                         (((x) & GENMASK(18, 14)) >> 14)
+-#define ANA_ANAGEFIL_VID_EN                               BIT(13)
+-#define ANA_ANAGEFIL_VID_VAL(x)                           ((x) & GENMASK(12, 0))
+-#define ANA_ANAGEFIL_VID_VAL_M                            GENMASK(12, 0)
+-
+-#define ANA_STORMLIMIT_CFG_RSZ                            0x4
+-
+-#define ANA_STORMLIMIT_CFG_STORM_RATE(x)                  (((x) << 3) & GENMASK(6, 3))
+-#define ANA_STORMLIMIT_CFG_STORM_RATE_M                   GENMASK(6, 3)
+-#define ANA_STORMLIMIT_CFG_STORM_RATE_X(x)                (((x) & GENMASK(6, 3)) >> 3)
+-#define ANA_STORMLIMIT_CFG_STORM_UNIT                     BIT(2)
+-#define ANA_STORMLIMIT_CFG_STORM_MODE(x)                  ((x) & GENMASK(1, 0))
+-#define ANA_STORMLIMIT_CFG_STORM_MODE_M                   GENMASK(1, 0)
+-
+-#define ANA_AUTOAGE_AGE_FAST                              BIT(21)
+-#define ANA_AUTOAGE_AGE_PERIOD(x)                         (((x) << 1) & GENMASK(20, 1))
+-#define ANA_AUTOAGE_AGE_PERIOD_M                          GENMASK(20, 1)
+-#define ANA_AUTOAGE_AGE_PERIOD_X(x)                       (((x) & GENMASK(20, 1)) >> 1)
+-#define ANA_AUTOAGE_AUTOAGE_LOCKED                        BIT(0)
+-
+-#define ANA_MACTOPTIONS_REDUCED_TABLE                     BIT(1)
+-#define ANA_MACTOPTIONS_SHADOW                            BIT(0)
+-
+-#define ANA_AGENCTRL_FID_MASK(x)                          (((x) << 12) & GENMASK(23, 12))
+-#define ANA_AGENCTRL_FID_MASK_M                           GENMASK(23, 12)
+-#define ANA_AGENCTRL_FID_MASK_X(x)                        (((x) & GENMASK(23, 12)) >> 12)
+-#define ANA_AGENCTRL_IGNORE_DMAC_FLAGS                    BIT(11)
+-#define ANA_AGENCTRL_IGNORE_SMAC_FLAGS                    BIT(10)
+-#define ANA_AGENCTRL_FLOOD_SPECIAL                        BIT(9)
+-#define ANA_AGENCTRL_FLOOD_IGNORE_VLAN                    BIT(8)
+-#define ANA_AGENCTRL_MIRROR_CPU                           BIT(7)
+-#define ANA_AGENCTRL_LEARN_CPU_COPY                       BIT(6)
+-#define ANA_AGENCTRL_LEARN_FWD_KILL                       BIT(5)
+-#define ANA_AGENCTRL_LEARN_IGNORE_VLAN                    BIT(4)
+-#define ANA_AGENCTRL_CPU_CPU_KILL_ENA                     BIT(3)
+-#define ANA_AGENCTRL_GREEN_COUNT_MODE                     BIT(2)
+-#define ANA_AGENCTRL_YELLOW_COUNT_MODE                    BIT(1)
+-#define ANA_AGENCTRL_RED_COUNT_MODE                       BIT(0)
+-
+-#define ANA_FLOODING_RSZ                                  0x4
+-
+-#define ANA_FLOODING_FLD_UNICAST(x)                       (((x) << 12) & GENMASK(17, 12))
+-#define ANA_FLOODING_FLD_UNICAST_M                        GENMASK(17, 12)
+-#define ANA_FLOODING_FLD_UNICAST_X(x)                     (((x) & GENMASK(17, 12)) >> 12)
+-#define ANA_FLOODING_FLD_BROADCAST(x)                     (((x) << 6) & GENMASK(11, 6))
+-#define ANA_FLOODING_FLD_BROADCAST_M                      GENMASK(11, 6)
+-#define ANA_FLOODING_FLD_BROADCAST_X(x)                   (((x) & GENMASK(11, 6)) >> 6)
+-#define ANA_FLOODING_FLD_MULTICAST(x)                     ((x) & GENMASK(5, 0))
+-#define ANA_FLOODING_FLD_MULTICAST_M                      GENMASK(5, 0)
+-
+-#define ANA_FLOODING_IPMC_FLD_MC4_CTRL(x)                 (((x) << 18) & GENMASK(23, 18))
+-#define ANA_FLOODING_IPMC_FLD_MC4_CTRL_M                  GENMASK(23, 18)
+-#define ANA_FLOODING_IPMC_FLD_MC4_CTRL_X(x)               (((x) & GENMASK(23, 18)) >> 18)
+-#define ANA_FLOODING_IPMC_FLD_MC4_DATA(x)                 (((x) << 12) & GENMASK(17, 12))
+-#define ANA_FLOODING_IPMC_FLD_MC4_DATA_M                  GENMASK(17, 12)
+-#define ANA_FLOODING_IPMC_FLD_MC4_DATA_X(x)               (((x) & GENMASK(17, 12)) >> 12)
+-#define ANA_FLOODING_IPMC_FLD_MC6_CTRL(x)                 (((x) << 6) & GENMASK(11, 6))
+-#define ANA_FLOODING_IPMC_FLD_MC6_CTRL_M                  GENMASK(11, 6)
+-#define ANA_FLOODING_IPMC_FLD_MC6_CTRL_X(x)               (((x) & GENMASK(11, 6)) >> 6)
+-#define ANA_FLOODING_IPMC_FLD_MC6_DATA(x)                 ((x) & GENMASK(5, 0))
+-#define ANA_FLOODING_IPMC_FLD_MC6_DATA_M                  GENMASK(5, 0)
+-
+-#define ANA_SFLOW_CFG_RSZ                                 0x4
+-
+-#define ANA_SFLOW_CFG_SF_RATE(x)                          (((x) << 2) & GENMASK(13, 2))
+-#define ANA_SFLOW_CFG_SF_RATE_M                           GENMASK(13, 2)
+-#define ANA_SFLOW_CFG_SF_RATE_X(x)                        (((x) & GENMASK(13, 2)) >> 2)
+-#define ANA_SFLOW_CFG_SF_SAMPLE_RX                        BIT(1)
+-#define ANA_SFLOW_CFG_SF_SAMPLE_TX                        BIT(0)
+-
+-#define ANA_PORT_MODE_RSZ                                 0x4
+-
+-#define ANA_PORT_MODE_REDTAG_PARSE_CFG                    BIT(3)
+-#define ANA_PORT_MODE_VLAN_PARSE_CFG(x)                   (((x) << 1) & GENMASK(2, 1))
+-#define ANA_PORT_MODE_VLAN_PARSE_CFG_M                    GENMASK(2, 1)
+-#define ANA_PORT_MODE_VLAN_PARSE_CFG_X(x)                 (((x) & GENMASK(2, 1)) >> 1)
+-#define ANA_PORT_MODE_L3_PARSE_CFG                        BIT(0)
+-
+-#define ANA_CUT_THRU_CFG_RSZ                              0x4
+-
+-#define ANA_PGID_PGID_RSZ                                 0x4
+-
+-#define ANA_PGID_PGID_PGID(x)                             ((x) & GENMASK(11, 0))
+-#define ANA_PGID_PGID_PGID_M                              GENMASK(11, 0)
+-#define ANA_PGID_PGID_CPUQ_DST_PGID(x)                    (((x) << 27) & GENMASK(29, 27))
+-#define ANA_PGID_PGID_CPUQ_DST_PGID_M                     GENMASK(29, 27)
+-#define ANA_PGID_PGID_CPUQ_DST_PGID_X(x)                  (((x) & GENMASK(29, 27)) >> 27)
+-
+-#define ANA_TABLES_MACHDATA_VID(x)                        (((x) << 16) & GENMASK(28, 16))
+-#define ANA_TABLES_MACHDATA_VID_M                         GENMASK(28, 16)
+-#define ANA_TABLES_MACHDATA_VID_X(x)                      (((x) & GENMASK(28, 16)) >> 16)
+-#define ANA_TABLES_MACHDATA_MACHDATA(x)                   ((x) & GENMASK(15, 0))
+-#define ANA_TABLES_MACHDATA_MACHDATA_M                    GENMASK(15, 0)
+-
+-#define ANA_TABLES_STREAMDATA_SSID_VALID                  BIT(16)
+-#define ANA_TABLES_STREAMDATA_SSID(x)                     (((x) << 9) & GENMASK(15, 9))
+-#define ANA_TABLES_STREAMDATA_SSID_M                      GENMASK(15, 9)
+-#define ANA_TABLES_STREAMDATA_SSID_X(x)                   (((x) & GENMASK(15, 9)) >> 9)
+-#define ANA_TABLES_STREAMDATA_SFID_VALID                  BIT(8)
+-#define ANA_TABLES_STREAMDATA_SFID(x)                     ((x) & GENMASK(7, 0))
+-#define ANA_TABLES_STREAMDATA_SFID_M                      GENMASK(7, 0)
+-
+-#define ANA_TABLES_MACACCESS_MAC_CPU_COPY                 BIT(15)
+-#define ANA_TABLES_MACACCESS_SRC_KILL                     BIT(14)
+-#define ANA_TABLES_MACACCESS_IGNORE_VLAN                  BIT(13)
+-#define ANA_TABLES_MACACCESS_AGED_FLAG                    BIT(12)
+-#define ANA_TABLES_MACACCESS_VALID                        BIT(11)
+-#define ANA_TABLES_MACACCESS_ENTRYTYPE(x)                 (((x) << 9) & GENMASK(10, 9))
+-#define ANA_TABLES_MACACCESS_ENTRYTYPE_M                  GENMASK(10, 9)
+-#define ANA_TABLES_MACACCESS_ENTRYTYPE_X(x)               (((x) & GENMASK(10, 9)) >> 9)
+-#define ANA_TABLES_MACACCESS_DEST_IDX(x)                  (((x) << 3) & GENMASK(8, 3))
+-#define ANA_TABLES_MACACCESS_DEST_IDX_M                   GENMASK(8, 3)
+-#define ANA_TABLES_MACACCESS_DEST_IDX_X(x)                (((x) & GENMASK(8, 3)) >> 3)
+-#define ANA_TABLES_MACACCESS_MAC_TABLE_CMD(x)             ((x) & GENMASK(2, 0))
+-#define ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M              GENMASK(2, 0)
+-#define MACACCESS_CMD_IDLE                     0
+-#define MACACCESS_CMD_LEARN                    1
+-#define MACACCESS_CMD_FORGET                   2
+-#define MACACCESS_CMD_AGE                      3
+-#define MACACCESS_CMD_GET_NEXT                 4
+-#define MACACCESS_CMD_INIT                     5
+-#define MACACCESS_CMD_READ                     6
+-#define MACACCESS_CMD_WRITE                    7
+-
+-#define ANA_TABLES_VLANACCESS_VLAN_PORT_MASK(x)           (((x) << 2) & GENMASK(13, 2))
+-#define ANA_TABLES_VLANACCESS_VLAN_PORT_MASK_M            GENMASK(13, 2)
+-#define ANA_TABLES_VLANACCESS_VLAN_PORT_MASK_X(x)         (((x) & GENMASK(13, 2)) >> 2)
+-#define ANA_TABLES_VLANACCESS_VLAN_TBL_CMD(x)             ((x) & GENMASK(1, 0))
+-#define ANA_TABLES_VLANACCESS_VLAN_TBL_CMD_M              GENMASK(1, 0)
+-#define ANA_TABLES_VLANACCESS_CMD_IDLE                    0x0
+-#define ANA_TABLES_VLANACCESS_CMD_WRITE                   0x2
+-#define ANA_TABLES_VLANACCESS_CMD_INIT                    0x3
+-
+-#define ANA_TABLES_VLANTIDX_VLAN_SEC_FWD_ENA              BIT(17)
+-#define ANA_TABLES_VLANTIDX_VLAN_FLOOD_DIS                BIT(16)
+-#define ANA_TABLES_VLANTIDX_VLAN_PRIV_VLAN                BIT(15)
+-#define ANA_TABLES_VLANTIDX_VLAN_LEARN_DISABLED           BIT(14)
+-#define ANA_TABLES_VLANTIDX_VLAN_MIRROR                   BIT(13)
+-#define ANA_TABLES_VLANTIDX_VLAN_SRC_CHK                  BIT(12)
+-#define ANA_TABLES_VLANTIDX_V_INDEX(x)                    ((x) & GENMASK(11, 0))
+-#define ANA_TABLES_VLANTIDX_V_INDEX_M                     GENMASK(11, 0)
+-
+-#define ANA_TABLES_ISDXACCESS_ISDX_PORT_MASK(x)           (((x) << 2) & GENMASK(8, 2))
+-#define ANA_TABLES_ISDXACCESS_ISDX_PORT_MASK_M            GENMASK(8, 2)
+-#define ANA_TABLES_ISDXACCESS_ISDX_PORT_MASK_X(x)         (((x) & GENMASK(8, 2)) >> 2)
+-#define ANA_TABLES_ISDXACCESS_ISDX_TBL_CMD(x)             ((x) & GENMASK(1, 0))
+-#define ANA_TABLES_ISDXACCESS_ISDX_TBL_CMD_M              GENMASK(1, 0)
+-
+-#define ANA_TABLES_ISDXTIDX_ISDX_SDLBI(x)                 (((x) << 21) & GENMASK(28, 21))
+-#define ANA_TABLES_ISDXTIDX_ISDX_SDLBI_M                  GENMASK(28, 21)
+-#define ANA_TABLES_ISDXTIDX_ISDX_SDLBI_X(x)               (((x) & GENMASK(28, 21)) >> 21)
+-#define ANA_TABLES_ISDXTIDX_ISDX_MSTI(x)                  (((x) << 15) & GENMASK(20, 15))
+-#define ANA_TABLES_ISDXTIDX_ISDX_MSTI_M                   GENMASK(20, 15)
+-#define ANA_TABLES_ISDXTIDX_ISDX_MSTI_X(x)                (((x) & GENMASK(20, 15)) >> 15)
+-#define ANA_TABLES_ISDXTIDX_ISDX_ES0_KEY_ENA              BIT(14)
+-#define ANA_TABLES_ISDXTIDX_ISDX_FORCE_ENA                BIT(10)
+-#define ANA_TABLES_ISDXTIDX_ISDX_INDEX(x)                 ((x) & GENMASK(7, 0))
+-#define ANA_TABLES_ISDXTIDX_ISDX_INDEX_M                  GENMASK(7, 0)
+-
+-#define ANA_TABLES_ENTRYLIM_RSZ                           0x4
+-
+-#define ANA_TABLES_ENTRYLIM_ENTRYLIM(x)                   (((x) << 14) & GENMASK(17, 14))
+-#define ANA_TABLES_ENTRYLIM_ENTRYLIM_M                    GENMASK(17, 14)
+-#define ANA_TABLES_ENTRYLIM_ENTRYLIM_X(x)                 (((x) & GENMASK(17, 14)) >> 14)
+-#define ANA_TABLES_ENTRYLIM_ENTRYSTAT(x)                  ((x) & GENMASK(13, 0))
+-#define ANA_TABLES_ENTRYLIM_ENTRYSTAT_M                   GENMASK(13, 0)
+-
+-#define ANA_TABLES_STREAMACCESS_GEN_REC_SEQ_NUM(x)        (((x) << 4) & GENMASK(31, 4))
+-#define ANA_TABLES_STREAMACCESS_GEN_REC_SEQ_NUM_M         GENMASK(31, 4)
+-#define ANA_TABLES_STREAMACCESS_GEN_REC_SEQ_NUM_X(x)      (((x) & GENMASK(31, 4)) >> 4)
+-#define ANA_TABLES_STREAMACCESS_SEQ_GEN_REC_ENA           BIT(3)
+-#define ANA_TABLES_STREAMACCESS_GEN_REC_TYPE              BIT(2)
+-#define ANA_TABLES_STREAMACCESS_STREAM_TBL_CMD(x)         ((x) & GENMASK(1, 0))
+-#define ANA_TABLES_STREAMACCESS_STREAM_TBL_CMD_M          GENMASK(1, 0)
+-
+-#define ANA_TABLES_STREAMTIDX_SEQ_GEN_ERR_STATUS(x)       (((x) << 30) & GENMASK(31, 30))
+-#define ANA_TABLES_STREAMTIDX_SEQ_GEN_ERR_STATUS_M        GENMASK(31, 30)
+-#define ANA_TABLES_STREAMTIDX_SEQ_GEN_ERR_STATUS_X(x)     (((x) & GENMASK(31, 30)) >> 30)
+-#define ANA_TABLES_STREAMTIDX_S_INDEX(x)                  (((x) << 16) & GENMASK(22, 16))
+-#define ANA_TABLES_STREAMTIDX_S_INDEX_M                   GENMASK(22, 16)
+-#define ANA_TABLES_STREAMTIDX_S_INDEX_X(x)                (((x) & GENMASK(22, 16)) >> 16)
+-#define ANA_TABLES_STREAMTIDX_FORCE_SF_BEHAVIOUR          BIT(14)
+-#define ANA_TABLES_STREAMTIDX_SEQ_HISTORY_LEN(x)          (((x) << 8) & GENMASK(13, 8))
+-#define ANA_TABLES_STREAMTIDX_SEQ_HISTORY_LEN_M           GENMASK(13, 8)
+-#define ANA_TABLES_STREAMTIDX_SEQ_HISTORY_LEN_X(x)        (((x) & GENMASK(13, 8)) >> 8)
+-#define ANA_TABLES_STREAMTIDX_RESET_ON_ROGUE              BIT(7)
+-#define ANA_TABLES_STREAMTIDX_REDTAG_POP                  BIT(6)
+-#define ANA_TABLES_STREAMTIDX_STREAM_SPLIT                BIT(5)
+-#define ANA_TABLES_STREAMTIDX_SEQ_SPACE_LOG2(x)           ((x) & GENMASK(4, 0))
+-#define ANA_TABLES_STREAMTIDX_SEQ_SPACE_LOG2_M            GENMASK(4, 0)
+-
+-#define ANA_TABLES_SEQ_MASK_SPLIT_MASK(x)                 (((x) << 16) & GENMASK(22, 16))
+-#define ANA_TABLES_SEQ_MASK_SPLIT_MASK_M                  GENMASK(22, 16)
+-#define ANA_TABLES_SEQ_MASK_SPLIT_MASK_X(x)               (((x) & GENMASK(22, 16)) >> 16)
+-#define ANA_TABLES_SEQ_MASK_INPUT_PORT_MASK(x)            ((x) & GENMASK(6, 0))
+-#define ANA_TABLES_SEQ_MASK_INPUT_PORT_MASK_M             GENMASK(6, 0)
+-
+-#define ANA_TABLES_SFID_MASK_IGR_PORT_MASK(x)             (((x) << 1) & GENMASK(7, 1))
+-#define ANA_TABLES_SFID_MASK_IGR_PORT_MASK_M              GENMASK(7, 1)
+-#define ANA_TABLES_SFID_MASK_IGR_PORT_MASK_X(x)           (((x) & GENMASK(7, 1)) >> 1)
+-#define ANA_TABLES_SFID_MASK_IGR_SRCPORT_MATCH_ENA        BIT(0)
+-
+-#define ANA_TABLES_SFIDACCESS_IGR_PRIO_MATCH_ENA          BIT(22)
+-#define ANA_TABLES_SFIDACCESS_IGR_PRIO(x)                 (((x) << 19) & GENMASK(21, 19))
+-#define ANA_TABLES_SFIDACCESS_IGR_PRIO_M                  GENMASK(21, 19)
+-#define ANA_TABLES_SFIDACCESS_IGR_PRIO_X(x)               (((x) & GENMASK(21, 19)) >> 19)
+-#define ANA_TABLES_SFIDACCESS_FORCE_BLOCK                 BIT(18)
+-#define ANA_TABLES_SFIDACCESS_MAX_SDU_LEN(x)              (((x) << 2) & GENMASK(17, 2))
+-#define ANA_TABLES_SFIDACCESS_MAX_SDU_LEN_M               GENMASK(17, 2)
+-#define ANA_TABLES_SFIDACCESS_MAX_SDU_LEN_X(x)            (((x) & GENMASK(17, 2)) >> 2)
+-#define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(x)             ((x) & GENMASK(1, 0))
+-#define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD_M              GENMASK(1, 0)
+-
+-#define SFIDACCESS_CMD_IDLE                             0
+-#define SFIDACCESS_CMD_READ                             1
+-#define SFIDACCESS_CMD_WRITE                            2
+-#define SFIDACCESS_CMD_INIT                           3
+-
+-#define ANA_TABLES_SFIDTIDX_SGID_VALID                    BIT(26)
+-#define ANA_TABLES_SFIDTIDX_SGID(x)                       (((x) << 18) & GENMASK(25, 18))
+-#define ANA_TABLES_SFIDTIDX_SGID_M                        GENMASK(25, 18)
+-#define ANA_TABLES_SFIDTIDX_SGID_X(x)                     (((x) & GENMASK(25, 18)) >> 18)
+-#define ANA_TABLES_SFIDTIDX_POL_ENA                       BIT(17)
+-#define ANA_TABLES_SFIDTIDX_POL_IDX(x)                    (((x) << 8) & GENMASK(16, 8))
+-#define ANA_TABLES_SFIDTIDX_POL_IDX_M                     GENMASK(16, 8)
+-#define ANA_TABLES_SFIDTIDX_POL_IDX_X(x)                  (((x) & GENMASK(16, 8)) >> 8)
+-#define ANA_TABLES_SFIDTIDX_SFID_INDEX(x)                 ((x) & GENMASK(7, 0))
+-#define ANA_TABLES_SFIDTIDX_SFID_INDEX_M                  GENMASK(7, 0)
+-
+-#define ANA_MSTI_STATE_RSZ                                0x4
+-
+-#define ANA_OAM_UPM_LM_CNT_RSZ                            0x4
+-
+-#define ANA_SG_ACCESS_CTRL_SGID(x)                        ((x) & GENMASK(7, 0))
+-#define ANA_SG_ACCESS_CTRL_SGID_M                         GENMASK(7, 0)
+-#define ANA_SG_ACCESS_CTRL_CONFIG_CHANGE                  BIT(28)
+-
+-#define ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB(x)          ((x) & GENMASK(15, 0))
+-#define ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB_M           GENMASK(15, 0)
+-#define ANA_SG_CONFIG_REG_3_LIST_LENGTH(x)                (((x) << 16) & GENMASK(18, 16))
+-#define ANA_SG_CONFIG_REG_3_LIST_LENGTH_M                 GENMASK(18, 16)
+-#define ANA_SG_CONFIG_REG_3_LIST_LENGTH_X(x)              (((x) & GENMASK(18, 16)) >> 16)
+-#define ANA_SG_CONFIG_REG_3_GATE_ENABLE                   BIT(20)
+-#define ANA_SG_CONFIG_REG_3_INIT_IPS(x)                   (((x) << 21) & GENMASK(24, 21))
+-#define ANA_SG_CONFIG_REG_3_INIT_IPS_M                    GENMASK(24, 21)
+-#define ANA_SG_CONFIG_REG_3_INIT_IPS_X(x)                 (((x) & GENMASK(24, 21)) >> 21)
+-#define ANA_SG_CONFIG_REG_3_IPV_VALID                     BIT(24)
+-#define ANA_SG_CONFIG_REG_3_IPV_INVALID(x)              (((x) << 24) & GENMASK(24, 24))
+-#define ANA_SG_CONFIG_REG_3_INIT_IPV(x)                   (((x) << 21) & GENMASK(23, 21))
+-#define ANA_SG_CONFIG_REG_3_INIT_IPV_M                    GENMASK(23, 21)
+-#define ANA_SG_CONFIG_REG_3_INIT_IPV_X(x)                 (((x) & GENMASK(23, 21)) >> 21)
+-#define ANA_SG_CONFIG_REG_3_INIT_GATE_STATE               BIT(25)
+-
+-#define ANA_SG_GCL_GS_CONFIG_RSZ                          0x4
+-
+-#define ANA_SG_GCL_GS_CONFIG_IPS(x)                       ((x) & GENMASK(3, 0))
+-#define ANA_SG_GCL_GS_CONFIG_IPS_M                        GENMASK(3, 0)
+-#define ANA_SG_GCL_GS_CONFIG_IPV_VALID                    BIT(3)
+-#define ANA_SG_GCL_GS_CONFIG_IPV(x)                       ((x) & GENMASK(2, 0))
+-#define ANA_SG_GCL_GS_CONFIG_IPV_M                        GENMASK(2, 0)
+-#define ANA_SG_GCL_GS_CONFIG_GATE_STATE                   BIT(4)
+-
+-#define ANA_SG_GCL_TI_CONFIG_RSZ                          0x4
+-
+-#define ANA_SG_STATUS_REG_3_CFG_CHG_TIME_SEC_MSB(x)       ((x) & GENMASK(15, 0))
+-#define ANA_SG_STATUS_REG_3_CFG_CHG_TIME_SEC_MSB_M        GENMASK(15, 0)
+-#define ANA_SG_STATUS_REG_3_GATE_STATE                    BIT(16)
+-#define ANA_SG_STATUS_REG_3_IPS(x)                        (((x) << 20) & GENMASK(23, 20))
+-#define ANA_SG_STATUS_REG_3_IPS_M                         GENMASK(23, 20)
+-#define ANA_SG_STATUS_REG_3_IPS_X(x)                      (((x) & GENMASK(23, 20)) >> 20)
+-#define ANA_SG_STATUS_REG_3_IPV_VALID                     BIT(23)
+-#define ANA_SG_STATUS_REG_3_IPV(x)                        (((x) << 20) & GENMASK(22, 20))
+-#define ANA_SG_STATUS_REG_3_IPV_M                         GENMASK(22, 20)
+-#define ANA_SG_STATUS_REG_3_IPV_X(x)                      (((x) & GENMASK(22, 20)) >> 20)
+-#define ANA_SG_STATUS_REG_3_CONFIG_PENDING                BIT(24)
+-
+-#define ANA_PORT_VLAN_CFG_GSZ                             0x100
+-
+-#define ANA_PORT_VLAN_CFG_VLAN_VID_AS_ISDX                BIT(21)
+-#define ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA                  BIT(20)
+-#define ANA_PORT_VLAN_CFG_VLAN_POP_CNT(x)                 (((x) << 18) & GENMASK(19, 18))
+-#define ANA_PORT_VLAN_CFG_VLAN_POP_CNT_M                  GENMASK(19, 18)
+-#define ANA_PORT_VLAN_CFG_VLAN_POP_CNT_X(x)               (((x) & GENMASK(19, 18)) >> 18)
+-#define ANA_PORT_VLAN_CFG_VLAN_INNER_TAG_ENA              BIT(17)
+-#define ANA_PORT_VLAN_CFG_VLAN_TAG_TYPE                   BIT(16)
+-#define ANA_PORT_VLAN_CFG_VLAN_DEI                        BIT(15)
+-#define ANA_PORT_VLAN_CFG_VLAN_PCP(x)                     (((x) << 12) & GENMASK(14, 12))
+-#define ANA_PORT_VLAN_CFG_VLAN_PCP_M                      GENMASK(14, 12)
+-#define ANA_PORT_VLAN_CFG_VLAN_PCP_X(x)                   (((x) & GENMASK(14, 12)) >> 12)
+-#define ANA_PORT_VLAN_CFG_VLAN_VID(x)                     ((x) & GENMASK(11, 0))
+-#define ANA_PORT_VLAN_CFG_VLAN_VID_M                      GENMASK(11, 0)
+-
+-#define ANA_PORT_DROP_CFG_GSZ                             0x100
+-
+-#define ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA               BIT(6)
+-#define ANA_PORT_DROP_CFG_DROP_S_TAGGED_ENA               BIT(5)
+-#define ANA_PORT_DROP_CFG_DROP_C_TAGGED_ENA               BIT(4)
+-#define ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA          BIT(3)
+-#define ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA          BIT(2)
+-#define ANA_PORT_DROP_CFG_DROP_NULL_MAC_ENA               BIT(1)
+-#define ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA                BIT(0)
+-
+-#define ANA_PORT_QOS_CFG_GSZ                              0x100
+-
+-#define ANA_PORT_QOS_CFG_DP_DEFAULT_VAL                   BIT(8)
+-#define ANA_PORT_QOS_CFG_QOS_DEFAULT_VAL(x)               (((x) << 5) & GENMASK(7, 5))
+-#define ANA_PORT_QOS_CFG_QOS_DEFAULT_VAL_M                GENMASK(7, 5)
+-#define ANA_PORT_QOS_CFG_QOS_DEFAULT_VAL_X(x)             (((x) & GENMASK(7, 5)) >> 5)
+-#define ANA_PORT_QOS_CFG_QOS_DSCP_ENA                     BIT(4)
+-#define ANA_PORT_QOS_CFG_QOS_PCP_ENA                      BIT(3)
+-#define ANA_PORT_QOS_CFG_DSCP_TRANSLATE_ENA               BIT(2)
+-#define ANA_PORT_QOS_CFG_DSCP_REWR_CFG(x)                 ((x) & GENMASK(1, 0))
+-#define ANA_PORT_QOS_CFG_DSCP_REWR_CFG_M                  GENMASK(1, 0)
+-
+-#define ANA_PORT_VCAP_CFG_GSZ                             0x100
+-
+-#define ANA_PORT_VCAP_CFG_S1_ENA                          BIT(14)
+-#define ANA_PORT_VCAP_CFG_S1_DMAC_DIP_ENA(x)              (((x) << 11) & GENMASK(13, 11))
+-#define ANA_PORT_VCAP_CFG_S1_DMAC_DIP_ENA_M               GENMASK(13, 11)
+-#define ANA_PORT_VCAP_CFG_S1_DMAC_DIP_ENA_X(x)            (((x) & GENMASK(13, 11)) >> 11)
+-#define ANA_PORT_VCAP_CFG_S1_VLAN_INNER_TAG_ENA(x)        (((x) << 8) & GENMASK(10, 8))
+-#define ANA_PORT_VCAP_CFG_S1_VLAN_INNER_TAG_ENA_M         GENMASK(10, 8)
+-#define ANA_PORT_VCAP_CFG_S1_VLAN_INNER_TAG_ENA_X(x)      (((x) & GENMASK(10, 8)) >> 8)
+-#define ANA_PORT_VCAP_CFG_PAG_VAL(x)                      ((x) & GENMASK(7, 0))
+-#define ANA_PORT_VCAP_CFG_PAG_VAL_M                       GENMASK(7, 0)
+-
+-#define ANA_PORT_VCAP_S1_KEY_CFG_GSZ                      0x100
+-#define ANA_PORT_VCAP_S1_KEY_CFG_RSZ                      0x4
+-
+-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP6_CFG(x)        (((x) << 4) & GENMASK(6, 4))
+-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP6_CFG_M         GENMASK(6, 4)
+-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP6_CFG_X(x)      (((x) & GENMASK(6, 4)) >> 4)
+-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP4_CFG(x)        (((x) << 2) & GENMASK(3, 2))
+-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP4_CFG_M         GENMASK(3, 2)
+-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP4_CFG_X(x)      (((x) & GENMASK(3, 2)) >> 2)
+-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_OTHER_CFG(x)      ((x) & GENMASK(1, 0))
+-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_OTHER_CFG_M       GENMASK(1, 0)
+-
+-#define ANA_PORT_VCAP_S2_CFG_GSZ                          0x100
+-
+-#define ANA_PORT_VCAP_S2_CFG_S2_UDP_PAYLOAD_ENA(x)        (((x) << 17) & GENMASK(18, 17))
+-#define ANA_PORT_VCAP_S2_CFG_S2_UDP_PAYLOAD_ENA_M         GENMASK(18, 17)
+-#define ANA_PORT_VCAP_S2_CFG_S2_UDP_PAYLOAD_ENA_X(x)      (((x) & GENMASK(18, 17)) >> 17)
+-#define ANA_PORT_VCAP_S2_CFG_S2_ETYPE_PAYLOAD_ENA(x)      (((x) << 15) & GENMASK(16, 15))
+-#define ANA_PORT_VCAP_S2_CFG_S2_ETYPE_PAYLOAD_ENA_M       GENMASK(16, 15)
+-#define ANA_PORT_VCAP_S2_CFG_S2_ETYPE_PAYLOAD_ENA_X(x)    (((x) & GENMASK(16, 15)) >> 15)
+-#define ANA_PORT_VCAP_S2_CFG_S2_ENA                       BIT(14)
+-#define ANA_PORT_VCAP_S2_CFG_S2_SNAP_DIS(x)               (((x) << 12) & GENMASK(13, 12))
+-#define ANA_PORT_VCAP_S2_CFG_S2_SNAP_DIS_M                GENMASK(13, 12)
+-#define ANA_PORT_VCAP_S2_CFG_S2_SNAP_DIS_X(x)             (((x) & GENMASK(13, 12)) >> 12)
+-#define ANA_PORT_VCAP_S2_CFG_S2_ARP_DIS(x)                (((x) << 10) & GENMASK(11, 10))
+-#define ANA_PORT_VCAP_S2_CFG_S2_ARP_DIS_M                 GENMASK(11, 10)
+-#define ANA_PORT_VCAP_S2_CFG_S2_ARP_DIS_X(x)              (((x) & GENMASK(11, 10)) >> 10)
+-#define ANA_PORT_VCAP_S2_CFG_S2_IP_TCPUDP_DIS(x)          (((x) << 8) & GENMASK(9, 8))
+-#define ANA_PORT_VCAP_S2_CFG_S2_IP_TCPUDP_DIS_M           GENMASK(9, 8)
+-#define ANA_PORT_VCAP_S2_CFG_S2_IP_TCPUDP_DIS_X(x)        (((x) & GENMASK(9, 8)) >> 8)
+-#define ANA_PORT_VCAP_S2_CFG_S2_IP_OTHER_DIS(x)           (((x) << 6) & GENMASK(7, 6))
+-#define ANA_PORT_VCAP_S2_CFG_S2_IP_OTHER_DIS_M            GENMASK(7, 6)
+-#define ANA_PORT_VCAP_S2_CFG_S2_IP_OTHER_DIS_X(x)         (((x) & GENMASK(7, 6)) >> 6)
+-#define ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG(x)                (((x) << 2) & GENMASK(5, 2))
+-#define ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG_M                 GENMASK(5, 2)
+-#define ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG_X(x)              (((x) & GENMASK(5, 2)) >> 2)
+-#define ANA_PORT_VCAP_S2_CFG_S2_OAM_DIS(x)                ((x) & GENMASK(1, 0))
+-#define ANA_PORT_VCAP_S2_CFG_S2_OAM_DIS_M                 GENMASK(1, 0)
+-
+-#define ANA_PORT_PCP_DEI_MAP_GSZ                          0x100
+-#define ANA_PORT_PCP_DEI_MAP_RSZ                          0x4
+-
+-#define ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL               BIT(3)
+-#define ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(x)           ((x) & GENMASK(2, 0))
+-#define ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL_M            GENMASK(2, 0)
+-
+-#define ANA_PORT_CPU_FWD_CFG_GSZ                          0x100
+-
+-#define ANA_PORT_CPU_FWD_CFG_CPU_VRAP_REDIR_ENA           BIT(7)
+-#define ANA_PORT_CPU_FWD_CFG_CPU_MLD_REDIR_ENA            BIT(6)
+-#define ANA_PORT_CPU_FWD_CFG_CPU_IGMP_REDIR_ENA           BIT(5)
+-#define ANA_PORT_CPU_FWD_CFG_CPU_IPMC_CTRL_COPY_ENA       BIT(4)
+-#define ANA_PORT_CPU_FWD_CFG_CPU_SRC_COPY_ENA             BIT(3)
+-#define ANA_PORT_CPU_FWD_CFG_CPU_ALLBRIDGE_DROP_ENA       BIT(2)
+-#define ANA_PORT_CPU_FWD_CFG_CPU_ALLBRIDGE_REDIR_ENA      BIT(1)
+-#define ANA_PORT_CPU_FWD_CFG_CPU_OAM_ENA                  BIT(0)
+-
+-#define ANA_PORT_CPU_FWD_BPDU_CFG_GSZ                     0x100
+-
+-#define ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA(x)        (((x) << 16) & GENMASK(31, 16))
+-#define ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA_M         GENMASK(31, 16)
+-#define ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA_X(x)      (((x) & GENMASK(31, 16)) >> 16)
+-#define ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(x)       ((x) & GENMASK(15, 0))
+-#define ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA_M        GENMASK(15, 0)
+-
+-#define ANA_PORT_CPU_FWD_GARP_CFG_GSZ                     0x100
+-
+-#define ANA_PORT_CPU_FWD_GARP_CFG_GARP_DROP_ENA(x)        (((x) << 16) & GENMASK(31, 16))
+-#define ANA_PORT_CPU_FWD_GARP_CFG_GARP_DROP_ENA_M         GENMASK(31, 16)
+-#define ANA_PORT_CPU_FWD_GARP_CFG_GARP_DROP_ENA_X(x)      (((x) & GENMASK(31, 16)) >> 16)
+-#define ANA_PORT_CPU_FWD_GARP_CFG_GARP_REDIR_ENA(x)       ((x) & GENMASK(15, 0))
+-#define ANA_PORT_CPU_FWD_GARP_CFG_GARP_REDIR_ENA_M        GENMASK(15, 0)
+-
+-#define ANA_PORT_CPU_FWD_CCM_CFG_GSZ                      0x100
+-
+-#define ANA_PORT_CPU_FWD_CCM_CFG_CCM_DROP_ENA(x)          (((x) << 16) & GENMASK(31, 16))
+-#define ANA_PORT_CPU_FWD_CCM_CFG_CCM_DROP_ENA_M           GENMASK(31, 16)
+-#define ANA_PORT_CPU_FWD_CCM_CFG_CCM_DROP_ENA_X(x)        (((x) & GENMASK(31, 16)) >> 16)
+-#define ANA_PORT_CPU_FWD_CCM_CFG_CCM_REDIR_ENA(x)         ((x) & GENMASK(15, 0))
+-#define ANA_PORT_CPU_FWD_CCM_CFG_CCM_REDIR_ENA_M          GENMASK(15, 0)
+-
+-#define ANA_PORT_PORT_CFG_GSZ                             0x100
+-
+-#define ANA_PORT_PORT_CFG_SRC_MIRROR_ENA                  BIT(15)
+-#define ANA_PORT_PORT_CFG_LIMIT_DROP                      BIT(14)
+-#define ANA_PORT_PORT_CFG_LIMIT_CPU                       BIT(13)
+-#define ANA_PORT_PORT_CFG_LOCKED_PORTMOVE_DROP            BIT(12)
+-#define ANA_PORT_PORT_CFG_LOCKED_PORTMOVE_CPU             BIT(11)
+-#define ANA_PORT_PORT_CFG_LEARNDROP                       BIT(10)
+-#define ANA_PORT_PORT_CFG_LEARNCPU                        BIT(9)
+-#define ANA_PORT_PORT_CFG_LEARNAUTO                       BIT(8)
+-#define ANA_PORT_PORT_CFG_LEARN_ENA                       BIT(7)
+-#define ANA_PORT_PORT_CFG_RECV_ENA                        BIT(6)
+-#define ANA_PORT_PORT_CFG_PORTID_VAL(x)                   (((x) << 2) & GENMASK(5, 2))
+-#define ANA_PORT_PORT_CFG_PORTID_VAL_M                    GENMASK(5, 2)
+-#define ANA_PORT_PORT_CFG_PORTID_VAL_X(x)                 (((x) & GENMASK(5, 2)) >> 2)
+-#define ANA_PORT_PORT_CFG_USE_B_DOM_TBL                   BIT(1)
+-#define ANA_PORT_PORT_CFG_LSR_MODE                        BIT(0)
+-
+-#define ANA_PORT_POL_CFG_GSZ                              0x100
+-
+-#define ANA_PORT_POL_CFG_POL_CPU_REDIR_8021               BIT(19)
+-#define ANA_PORT_POL_CFG_POL_CPU_REDIR_IP                 BIT(18)
+-#define ANA_PORT_POL_CFG_PORT_POL_ENA                     BIT(17)
+-#define ANA_PORT_POL_CFG_QUEUE_POL_ENA(x)                 (((x) << 9) & GENMASK(16, 9))
+-#define ANA_PORT_POL_CFG_QUEUE_POL_ENA_M                  GENMASK(16, 9)
+-#define ANA_PORT_POL_CFG_QUEUE_POL_ENA_X(x)               (((x) & GENMASK(16, 9)) >> 9)
+-#define ANA_PORT_POL_CFG_POL_ORDER(x)                     ((x) & GENMASK(8, 0))
+-#define ANA_PORT_POL_CFG_POL_ORDER_M                      GENMASK(8, 0)
+-
+-#define ANA_PORT_PTP_CFG_GSZ                              0x100
+-
+-#define ANA_PORT_PTP_CFG_PTP_BACKPLANE_MODE               BIT(0)
+-
+-#define ANA_PORT_PTP_DLY1_CFG_GSZ                         0x100
+-
+-#define ANA_PORT_PTP_DLY2_CFG_GSZ                         0x100
+-
+-#define ANA_PORT_SFID_CFG_GSZ                             0x100
+-#define ANA_PORT_SFID_CFG_RSZ                             0x4
+-
+-#define ANA_PORT_SFID_CFG_SFID_VALID                      BIT(8)
+-#define ANA_PORT_SFID_CFG_SFID(x)                         ((x) & GENMASK(7, 0))
+-#define ANA_PORT_SFID_CFG_SFID_M                          GENMASK(7, 0)
+-
+-#define ANA_PFC_PFC_CFG_GSZ                               0x40
+-
+-#define ANA_PFC_PFC_CFG_RX_PFC_ENA(x)                     (((x) << 2) & GENMASK(9, 2))
+-#define ANA_PFC_PFC_CFG_RX_PFC_ENA_M                      GENMASK(9, 2)
+-#define ANA_PFC_PFC_CFG_RX_PFC_ENA_X(x)                   (((x) & GENMASK(9, 2)) >> 2)
+-#define ANA_PFC_PFC_CFG_FC_LINK_SPEED(x)                  ((x) & GENMASK(1, 0))
+-#define ANA_PFC_PFC_CFG_FC_LINK_SPEED_M                   GENMASK(1, 0)
+-
+-#define ANA_PFC_PFC_TIMER_GSZ                             0x40
+-#define ANA_PFC_PFC_TIMER_RSZ                             0x4
+-
+-#define ANA_IPT_OAM_MEP_CFG_GSZ                           0x8
+-
+-#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_P(x)                  (((x) << 6) & GENMASK(10, 6))
+-#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_P_M                   GENMASK(10, 6)
+-#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_P_X(x)                (((x) & GENMASK(10, 6)) >> 6)
+-#define ANA_IPT_OAM_MEP_CFG_MEP_IDX(x)                    (((x) << 1) & GENMASK(5, 1))
+-#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_M                     GENMASK(5, 1)
+-#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_X(x)                  (((x) & GENMASK(5, 1)) >> 1)
+-#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_ENA                   BIT(0)
+-
+-#define ANA_IPT_IPT_GSZ                                   0x8
+-
+-#define ANA_IPT_IPT_IPT_CFG(x)                            (((x) << 15) & GENMASK(16, 15))
+-#define ANA_IPT_IPT_IPT_CFG_M                             GENMASK(16, 15)
+-#define ANA_IPT_IPT_IPT_CFG_X(x)                          (((x) & GENMASK(16, 15)) >> 15)
+-#define ANA_IPT_IPT_ISDX_P(x)                             (((x) << 7) & GENMASK(14, 7))
+-#define ANA_IPT_IPT_ISDX_P_M                              GENMASK(14, 7)
+-#define ANA_IPT_IPT_ISDX_P_X(x)                           (((x) & GENMASK(14, 7)) >> 7)
+-#define ANA_IPT_IPT_PPT_IDX(x)                            ((x) & GENMASK(6, 0))
+-#define ANA_IPT_IPT_PPT_IDX_M                             GENMASK(6, 0)
+-
+-#define ANA_PPT_PPT_RSZ                                   0x4
+-
+-#define ANA_FID_MAP_FID_MAP_RSZ                           0x4
+-
+-#define ANA_FID_MAP_FID_MAP_FID_C_VAL(x)                  (((x) << 6) & GENMASK(11, 6))
+-#define ANA_FID_MAP_FID_MAP_FID_C_VAL_M                   GENMASK(11, 6)
+-#define ANA_FID_MAP_FID_MAP_FID_C_VAL_X(x)                (((x) & GENMASK(11, 6)) >> 6)
+-#define ANA_FID_MAP_FID_MAP_FID_B_VAL(x)                  ((x) & GENMASK(5, 0))
+-#define ANA_FID_MAP_FID_MAP_FID_B_VAL_M                   GENMASK(5, 0)
+-
+-#define ANA_AGGR_CFG_AC_RND_ENA                           BIT(7)
+-#define ANA_AGGR_CFG_AC_DMAC_ENA                          BIT(6)
+-#define ANA_AGGR_CFG_AC_SMAC_ENA                          BIT(5)
+-#define ANA_AGGR_CFG_AC_IP6_FLOW_LBL_ENA                  BIT(4)
+-#define ANA_AGGR_CFG_AC_IP6_TCPUDP_ENA                    BIT(3)
+-#define ANA_AGGR_CFG_AC_IP4_SIPDIP_ENA                    BIT(2)
+-#define ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA                    BIT(1)
+-#define ANA_AGGR_CFG_AC_ISDX_ENA                          BIT(0)
+-
+-#define ANA_CPUQ_CFG_CPUQ_MLD(x)                          (((x) << 27) & GENMASK(29, 27))
+-#define ANA_CPUQ_CFG_CPUQ_MLD_M                           GENMASK(29, 27)
+-#define ANA_CPUQ_CFG_CPUQ_MLD_X(x)                        (((x) & GENMASK(29, 27)) >> 27)
+-#define ANA_CPUQ_CFG_CPUQ_IGMP(x)                         (((x) << 24) & GENMASK(26, 24))
+-#define ANA_CPUQ_CFG_CPUQ_IGMP_M                          GENMASK(26, 24)
+-#define ANA_CPUQ_CFG_CPUQ_IGMP_X(x)                       (((x) & GENMASK(26, 24)) >> 24)
+-#define ANA_CPUQ_CFG_CPUQ_IPMC_CTRL(x)                    (((x) << 21) & GENMASK(23, 21))
+-#define ANA_CPUQ_CFG_CPUQ_IPMC_CTRL_M                     GENMASK(23, 21)
+-#define ANA_CPUQ_CFG_CPUQ_IPMC_CTRL_X(x)                  (((x) & GENMASK(23, 21)) >> 21)
+-#define ANA_CPUQ_CFG_CPUQ_ALLBRIDGE(x)                    (((x) << 18) & GENMASK(20, 18))
+-#define ANA_CPUQ_CFG_CPUQ_ALLBRIDGE_M                     GENMASK(20, 18)
+-#define ANA_CPUQ_CFG_CPUQ_ALLBRIDGE_X(x)                  (((x) & GENMASK(20, 18)) >> 18)
+-#define ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE(x)              (((x) << 15) & GENMASK(17, 15))
+-#define ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE_M               GENMASK(17, 15)
+-#define ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE_X(x)            (((x) & GENMASK(17, 15)) >> 15)
+-#define ANA_CPUQ_CFG_CPUQ_SRC_COPY(x)                     (((x) << 12) & GENMASK(14, 12))
+-#define ANA_CPUQ_CFG_CPUQ_SRC_COPY_M                      GENMASK(14, 12)
+-#define ANA_CPUQ_CFG_CPUQ_SRC_COPY_X(x)                   (((x) & GENMASK(14, 12)) >> 12)
+-#define ANA_CPUQ_CFG_CPUQ_MAC_COPY(x)                     (((x) << 9) & GENMASK(11, 9))
+-#define ANA_CPUQ_CFG_CPUQ_MAC_COPY_M                      GENMASK(11, 9)
+-#define ANA_CPUQ_CFG_CPUQ_MAC_COPY_X(x)                   (((x) & GENMASK(11, 9)) >> 9)
+-#define ANA_CPUQ_CFG_CPUQ_LRN(x)                          (((x) << 6) & GENMASK(8, 6))
+-#define ANA_CPUQ_CFG_CPUQ_LRN_M                           GENMASK(8, 6)
+-#define ANA_CPUQ_CFG_CPUQ_LRN_X(x)                        (((x) & GENMASK(8, 6)) >> 6)
+-#define ANA_CPUQ_CFG_CPUQ_MIRROR(x)                       (((x) << 3) & GENMASK(5, 3))
+-#define ANA_CPUQ_CFG_CPUQ_MIRROR_M                        GENMASK(5, 3)
+-#define ANA_CPUQ_CFG_CPUQ_MIRROR_X(x)                     (((x) & GENMASK(5, 3)) >> 3)
+-#define ANA_CPUQ_CFG_CPUQ_SFLOW(x)                        ((x) & GENMASK(2, 0))
+-#define ANA_CPUQ_CFG_CPUQ_SFLOW_M                         GENMASK(2, 0)
+-
+-#define ANA_CPUQ_8021_CFG_RSZ                             0x4
+-
+-#define ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL(x)                (((x) << 6) & GENMASK(8, 6))
+-#define ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL_M                 GENMASK(8, 6)
+-#define ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL_X(x)              (((x) & GENMASK(8, 6)) >> 6)
+-#define ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL(x)                (((x) << 3) & GENMASK(5, 3))
+-#define ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL_M                 GENMASK(5, 3)
+-#define ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL_X(x)              (((x) & GENMASK(5, 3)) >> 3)
+-#define ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL(x)                 ((x) & GENMASK(2, 0))
+-#define ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL_M                  GENMASK(2, 0)
+-
+-#define ANA_DSCP_CFG_RSZ                                  0x4
+-
+-#define ANA_DSCP_CFG_DP_DSCP_VAL                          BIT(11)
+-#define ANA_DSCP_CFG_QOS_DSCP_VAL(x)                      (((x) << 8) & GENMASK(10, 8))
+-#define ANA_DSCP_CFG_QOS_DSCP_VAL_M                       GENMASK(10, 8)
+-#define ANA_DSCP_CFG_QOS_DSCP_VAL_X(x)                    (((x) & GENMASK(10, 8)) >> 8)
+-#define ANA_DSCP_CFG_DSCP_TRANSLATE_VAL(x)                (((x) << 2) & GENMASK(7, 2))
+-#define ANA_DSCP_CFG_DSCP_TRANSLATE_VAL_M                 GENMASK(7, 2)
+-#define ANA_DSCP_CFG_DSCP_TRANSLATE_VAL_X(x)              (((x) & GENMASK(7, 2)) >> 2)
+-#define ANA_DSCP_CFG_DSCP_TRUST_ENA                       BIT(1)
+-#define ANA_DSCP_CFG_DSCP_REWR_ENA                        BIT(0)
+-
+-#define ANA_DSCP_REWR_CFG_RSZ                             0x4
+-
+-#define ANA_VCAP_RNG_TYPE_CFG_RSZ                         0x4
+-
+-#define ANA_VCAP_RNG_VAL_CFG_RSZ                          0x4
+-
+-#define ANA_VCAP_RNG_VAL_CFG_VCAP_RNG_MIN_VAL(x)          (((x) << 16) & GENMASK(31, 16))
+-#define ANA_VCAP_RNG_VAL_CFG_VCAP_RNG_MIN_VAL_M           GENMASK(31, 16)
+-#define ANA_VCAP_RNG_VAL_CFG_VCAP_RNG_MIN_VAL_X(x)        (((x) & GENMASK(31, 16)) >> 16)
+-#define ANA_VCAP_RNG_VAL_CFG_VCAP_RNG_MAX_VAL(x)          ((x) & GENMASK(15, 0))
+-#define ANA_VCAP_RNG_VAL_CFG_VCAP_RNG_MAX_VAL_M           GENMASK(15, 0)
+-
+-#define ANA_VRAP_CFG_VRAP_VLAN_AWARE_ENA                  BIT(12)
+-#define ANA_VRAP_CFG_VRAP_VID(x)                          ((x) & GENMASK(11, 0))
+-#define ANA_VRAP_CFG_VRAP_VID_M                           GENMASK(11, 0)
+-
+-#define ANA_DISCARD_CFG_DROP_TAGGING_ISDX0                BIT(3)
+-#define ANA_DISCARD_CFG_DROP_CTRLPROT_ISDX0               BIT(2)
+-#define ANA_DISCARD_CFG_DROP_TAGGING_S2_ENA               BIT(1)
+-#define ANA_DISCARD_CFG_DROP_CTRLPROT_S2_ENA              BIT(0)
+-
+-#define ANA_FID_CFG_VID_MC_ENA                            BIT(0)
+-
+-#define ANA_POL_PIR_CFG_GSZ                               0x20
+-
+-#define ANA_POL_PIR_CFG_PIR_RATE(x)                       (((x) << 6) & GENMASK(20, 6))
+-#define ANA_POL_PIR_CFG_PIR_RATE_M                        GENMASK(20, 6)
+-#define ANA_POL_PIR_CFG_PIR_RATE_X(x)                     (((x) & GENMASK(20, 6)) >> 6)
+-#define ANA_POL_PIR_CFG_PIR_BURST(x)                      ((x) & GENMASK(5, 0))
+-#define ANA_POL_PIR_CFG_PIR_BURST_M                       GENMASK(5, 0)
+-
+-#define ANA_POL_CIR_CFG_GSZ                               0x20
+-
+-#define ANA_POL_CIR_CFG_CIR_RATE(x)                       (((x) << 6) & GENMASK(20, 6))
+-#define ANA_POL_CIR_CFG_CIR_RATE_M                        GENMASK(20, 6)
+-#define ANA_POL_CIR_CFG_CIR_RATE_X(x)                     (((x) & GENMASK(20, 6)) >> 6)
+-#define ANA_POL_CIR_CFG_CIR_BURST(x)                      ((x) & GENMASK(5, 0))
+-#define ANA_POL_CIR_CFG_CIR_BURST_M                       GENMASK(5, 0)
+-
+-#define ANA_POL_MODE_CFG_GSZ                              0x20
+-
+-#define ANA_POL_MODE_CFG_IPG_SIZE(x)                      (((x) << 5) & GENMASK(9, 5))
+-#define ANA_POL_MODE_CFG_IPG_SIZE_M                       GENMASK(9, 5)
+-#define ANA_POL_MODE_CFG_IPG_SIZE_X(x)                    (((x) & GENMASK(9, 5)) >> 5)
+-#define ANA_POL_MODE_CFG_FRM_MODE(x)                      (((x) << 3) & GENMASK(4, 3))
+-#define ANA_POL_MODE_CFG_FRM_MODE_M                       GENMASK(4, 3)
+-#define ANA_POL_MODE_CFG_FRM_MODE_X(x)                    (((x) & GENMASK(4, 3)) >> 3)
+-#define ANA_POL_MODE_CFG_DLB_COUPLED                      BIT(2)
+-#define ANA_POL_MODE_CFG_CIR_ENA                          BIT(1)
+-#define ANA_POL_MODE_CFG_OVERSHOOT_ENA                    BIT(0)
+-
+-#define ANA_POL_PIR_STATE_GSZ                             0x20
+-
+-#define ANA_POL_CIR_STATE_GSZ                             0x20
+-
+-#define ANA_POL_STATE_GSZ                                 0x20
+-
+-#define ANA_POL_FLOWC_RSZ                                 0x4
+-
+-#define ANA_POL_FLOWC_POL_FLOWC                           BIT(0)
+-
+-#define ANA_POL_HYST_POL_FC_HYST(x)                       (((x) << 4) & GENMASK(9, 4))
+-#define ANA_POL_HYST_POL_FC_HYST_M                        GENMASK(9, 4)
+-#define ANA_POL_HYST_POL_FC_HYST_X(x)                     (((x) & GENMASK(9, 4)) >> 4)
+-#define ANA_POL_HYST_POL_STOP_HYST(x)                     ((x) & GENMASK(3, 0))
+-#define ANA_POL_HYST_POL_STOP_HYST_M                      GENMASK(3, 0)
+-
+-#define ANA_POL_MISC_CFG_POL_CLOSE_ALL                    BIT(1)
+-#define ANA_POL_MISC_CFG_POL_LEAK_DIS                     BIT(0)
+-
+-#endif
+--- a/drivers/net/ethernet/mscc/ocelot_dev.h
++++ /dev/null
+@@ -1,275 +0,0 @@
+-/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+-/*
+- * Microsemi Ocelot Switch driver
+- *
+- * Copyright (c) 2017 Microsemi Corporation
+- */
+-
+-#ifndef _MSCC_OCELOT_DEV_H_
+-#define _MSCC_OCELOT_DEV_H_
+-
+-#define DEV_CLOCK_CFG                                     0x0
+-
+-#define DEV_CLOCK_CFG_MAC_TX_RST                          BIT(7)
+-#define DEV_CLOCK_CFG_MAC_RX_RST                          BIT(6)
+-#define DEV_CLOCK_CFG_PCS_TX_RST                          BIT(5)
+-#define DEV_CLOCK_CFG_PCS_RX_RST                          BIT(4)
+-#define DEV_CLOCK_CFG_PORT_RST                            BIT(3)
+-#define DEV_CLOCK_CFG_PHY_RST                             BIT(2)
+-#define DEV_CLOCK_CFG_LINK_SPEED(x)                       ((x) & GENMASK(1, 0))
+-#define DEV_CLOCK_CFG_LINK_SPEED_M                        GENMASK(1, 0)
+-
+-#define DEV_PORT_MISC                                     0x4
+-
+-#define DEV_PORT_MISC_FWD_ERROR_ENA                       BIT(4)
+-#define DEV_PORT_MISC_FWD_PAUSE_ENA                       BIT(3)
+-#define DEV_PORT_MISC_FWD_CTRL_ENA                        BIT(2)
+-#define DEV_PORT_MISC_DEV_LOOP_ENA                        BIT(1)
+-#define DEV_PORT_MISC_HDX_FAST_DIS                        BIT(0)
+-
+-#define DEV_EVENTS                                        0x8
+-
+-#define DEV_EEE_CFG                                       0xc
+-
+-#define DEV_EEE_CFG_EEE_ENA                               BIT(22)
+-#define DEV_EEE_CFG_EEE_TIMER_AGE(x)                      (((x) << 15) & GENMASK(21, 15))
+-#define DEV_EEE_CFG_EEE_TIMER_AGE_M                       GENMASK(21, 15)
+-#define DEV_EEE_CFG_EEE_TIMER_AGE_X(x)                    (((x) & GENMASK(21, 15)) >> 15)
+-#define DEV_EEE_CFG_EEE_TIMER_WAKEUP(x)                   (((x) << 8) & GENMASK(14, 8))
+-#define DEV_EEE_CFG_EEE_TIMER_WAKEUP_M                    GENMASK(14, 8)
+-#define DEV_EEE_CFG_EEE_TIMER_WAKEUP_X(x)                 (((x) & GENMASK(14, 8)) >> 8)
+-#define DEV_EEE_CFG_EEE_TIMER_HOLDOFF(x)                  (((x) << 1) & GENMASK(7, 1))
+-#define DEV_EEE_CFG_EEE_TIMER_HOLDOFF_M                   GENMASK(7, 1)
+-#define DEV_EEE_CFG_EEE_TIMER_HOLDOFF_X(x)                (((x) & GENMASK(7, 1)) >> 1)
+-#define DEV_EEE_CFG_PORT_LPI                              BIT(0)
+-
+-#define DEV_RX_PATH_DELAY                                 0x10
+-
+-#define DEV_TX_PATH_DELAY                                 0x14
+-
+-#define DEV_PTP_PREDICT_CFG                               0x18
+-
+-#define DEV_PTP_PREDICT_CFG_PTP_PHY_PREDICT_CFG(x)        (((x) << 4) & GENMASK(11, 4))
+-#define DEV_PTP_PREDICT_CFG_PTP_PHY_PREDICT_CFG_M         GENMASK(11, 4)
+-#define DEV_PTP_PREDICT_CFG_PTP_PHY_PREDICT_CFG_X(x)      (((x) & GENMASK(11, 4)) >> 4)
+-#define DEV_PTP_PREDICT_CFG_PTP_PHASE_PREDICT_CFG(x)      ((x) & GENMASK(3, 0))
+-#define DEV_PTP_PREDICT_CFG_PTP_PHASE_PREDICT_CFG_M       GENMASK(3, 0)
+-
+-#define DEV_MAC_ENA_CFG                                   0x1c
+-
+-#define DEV_MAC_ENA_CFG_RX_ENA                            BIT(4)
+-#define DEV_MAC_ENA_CFG_TX_ENA                            BIT(0)
+-
+-#define DEV_MAC_MODE_CFG                                  0x20
+-
+-#define DEV_MAC_MODE_CFG_FC_WORD_SYNC_ENA                 BIT(8)
+-#define DEV_MAC_MODE_CFG_GIGA_MODE_ENA                    BIT(4)
+-#define DEV_MAC_MODE_CFG_FDX_ENA                          BIT(0)
+-
+-#define DEV_MAC_MAXLEN_CFG                                0x24
+-
+-#define DEV_MAC_TAGS_CFG                                  0x28
+-
+-#define DEV_MAC_TAGS_CFG_TAG_ID(x)                        (((x) << 16) & GENMASK(31, 16))
+-#define DEV_MAC_TAGS_CFG_TAG_ID_M                         GENMASK(31, 16)
+-#define DEV_MAC_TAGS_CFG_TAG_ID_X(x)                      (((x) & GENMASK(31, 16)) >> 16)
+-#define DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA                 BIT(2)
+-#define DEV_MAC_TAGS_CFG_PB_ENA                           BIT(1)
+-#define DEV_MAC_TAGS_CFG_VLAN_AWR_ENA                     BIT(0)
+-
+-#define DEV_MAC_ADV_CHK_CFG                               0x2c
+-
+-#define DEV_MAC_ADV_CHK_CFG_LEN_DROP_ENA                  BIT(0)
+-
+-#define DEV_MAC_IFG_CFG                                   0x30
+-
+-#define DEV_MAC_IFG_CFG_RESTORE_OLD_IPG_CHECK             BIT(17)
+-#define DEV_MAC_IFG_CFG_REDUCED_TX_IFG                    BIT(16)
+-#define DEV_MAC_IFG_CFG_TX_IFG(x)                         (((x) << 8) & GENMASK(12, 8))
+-#define DEV_MAC_IFG_CFG_TX_IFG_M                          GENMASK(12, 8)
+-#define DEV_MAC_IFG_CFG_TX_IFG_X(x)                       (((x) & GENMASK(12, 8)) >> 8)
+-#define DEV_MAC_IFG_CFG_RX_IFG2(x)                        (((x) << 4) & GENMASK(7, 4))
+-#define DEV_MAC_IFG_CFG_RX_IFG2_M                         GENMASK(7, 4)
+-#define DEV_MAC_IFG_CFG_RX_IFG2_X(x)                      (((x) & GENMASK(7, 4)) >> 4)
+-#define DEV_MAC_IFG_CFG_RX_IFG1(x)                        ((x) & GENMASK(3, 0))
+-#define DEV_MAC_IFG_CFG_RX_IFG1_M                         GENMASK(3, 0)
+-
+-#define DEV_MAC_HDX_CFG                                   0x34
+-
+-#define DEV_MAC_HDX_CFG_BYPASS_COL_SYNC                   BIT(26)
+-#define DEV_MAC_HDX_CFG_OB_ENA                            BIT(25)
+-#define DEV_MAC_HDX_CFG_WEXC_DIS                          BIT(24)
+-#define DEV_MAC_HDX_CFG_SEED(x)                           (((x) << 16) & GENMASK(23, 16))
+-#define DEV_MAC_HDX_CFG_SEED_M                            GENMASK(23, 16)
+-#define DEV_MAC_HDX_CFG_SEED_X(x)                         (((x) & GENMASK(23, 16)) >> 16)
+-#define DEV_MAC_HDX_CFG_SEED_LOAD                         BIT(12)
+-#define DEV_MAC_HDX_CFG_RETRY_AFTER_EXC_COL_ENA           BIT(8)
+-#define DEV_MAC_HDX_CFG_LATE_COL_POS(x)                   ((x) & GENMASK(6, 0))
+-#define DEV_MAC_HDX_CFG_LATE_COL_POS_M                    GENMASK(6, 0)
+-
+-#define DEV_MAC_DBG_CFG                                   0x38
+-
+-#define DEV_MAC_DBG_CFG_TBI_MODE                          BIT(4)
+-#define DEV_MAC_DBG_CFG_IFG_CRS_EXT_CHK_ENA               BIT(0)
+-
+-#define DEV_MAC_FC_MAC_LOW_CFG                            0x3c
+-
+-#define DEV_MAC_FC_MAC_HIGH_CFG                           0x40
+-
+-#define DEV_MAC_STICKY                                    0x44
+-
+-#define DEV_MAC_STICKY_RX_IPG_SHRINK_STICKY               BIT(9)
+-#define DEV_MAC_STICKY_RX_PREAM_SHRINK_STICKY             BIT(8)
+-#define DEV_MAC_STICKY_RX_CARRIER_EXT_STICKY              BIT(7)
+-#define DEV_MAC_STICKY_RX_CARRIER_EXT_ERR_STICKY          BIT(6)
+-#define DEV_MAC_STICKY_RX_JUNK_STICKY                     BIT(5)
+-#define DEV_MAC_STICKY_TX_RETRANSMIT_STICKY               BIT(4)
+-#define DEV_MAC_STICKY_TX_JAM_STICKY                      BIT(3)
+-#define DEV_MAC_STICKY_TX_FIFO_OFLW_STICKY                BIT(2)
+-#define DEV_MAC_STICKY_TX_FRM_LEN_OVR_STICKY              BIT(1)
+-#define DEV_MAC_STICKY_TX_ABORT_STICKY                    BIT(0)
+-
+-#define PCS1G_CFG                                         0x48
+-
+-#define PCS1G_CFG_LINK_STATUS_TYPE                        BIT(4)
+-#define PCS1G_CFG_AN_LINK_CTRL_ENA                        BIT(1)
+-#define PCS1G_CFG_PCS_ENA                                 BIT(0)
+-
+-#define PCS1G_MODE_CFG                                    0x4c
+-
+-#define PCS1G_MODE_CFG_UNIDIR_MODE_ENA                    BIT(4)
+-#define PCS1G_MODE_CFG_SGMII_MODE_ENA                     BIT(0)
+-
+-#define PCS1G_SD_CFG                                      0x50
+-
+-#define PCS1G_SD_CFG_SD_SEL                               BIT(8)
+-#define PCS1G_SD_CFG_SD_POL                               BIT(4)
+-#define PCS1G_SD_CFG_SD_ENA                               BIT(0)
+-
+-#define PCS1G_ANEG_CFG                                    0x54
+-
+-#define PCS1G_ANEG_CFG_ADV_ABILITY(x)                     (((x) << 16) & GENMASK(31, 16))
+-#define PCS1G_ANEG_CFG_ADV_ABILITY_M                      GENMASK(31, 16)
+-#define PCS1G_ANEG_CFG_ADV_ABILITY_X(x)                   (((x) & GENMASK(31, 16)) >> 16)
+-#define PCS1G_ANEG_CFG_SW_RESOLVE_ENA                     BIT(8)
+-#define PCS1G_ANEG_CFG_ANEG_RESTART_ONE_SHOT              BIT(1)
+-#define PCS1G_ANEG_CFG_ANEG_ENA                           BIT(0)
+-
+-#define PCS1G_ANEG_NP_CFG                                 0x58
+-
+-#define PCS1G_ANEG_NP_CFG_NP_TX(x)                        (((x) << 16) & GENMASK(31, 16))
+-#define PCS1G_ANEG_NP_CFG_NP_TX_M                         GENMASK(31, 16)
+-#define PCS1G_ANEG_NP_CFG_NP_TX_X(x)                      (((x) & GENMASK(31, 16)) >> 16)
+-#define PCS1G_ANEG_NP_CFG_NP_LOADED_ONE_SHOT              BIT(0)
+-
+-#define PCS1G_LB_CFG                                      0x5c
+-
+-#define PCS1G_LB_CFG_RA_ENA                               BIT(4)
+-#define PCS1G_LB_CFG_GMII_PHY_LB_ENA                      BIT(1)
+-#define PCS1G_LB_CFG_TBI_HOST_LB_ENA                      BIT(0)
+-
+-#define PCS1G_DBG_CFG                                     0x60
+-
+-#define PCS1G_DBG_CFG_UDLT                                BIT(0)
+-
+-#define PCS1G_CDET_CFG                                    0x64
+-
+-#define PCS1G_CDET_CFG_CDET_ENA                           BIT(0)
+-
+-#define PCS1G_ANEG_STATUS                                 0x68
+-
+-#define PCS1G_ANEG_STATUS_LP_ADV_ABILITY(x)               (((x) << 16) & GENMASK(31, 16))
+-#define PCS1G_ANEG_STATUS_LP_ADV_ABILITY_M                GENMASK(31, 16)
+-#define PCS1G_ANEG_STATUS_LP_ADV_ABILITY_X(x)             (((x) & GENMASK(31, 16)) >> 16)
+-#define PCS1G_ANEG_STATUS_PR                              BIT(4)
+-#define PCS1G_ANEG_STATUS_PAGE_RX_STICKY                  BIT(3)
+-#define PCS1G_ANEG_STATUS_ANEG_COMPLETE                   BIT(0)
+-
+-#define PCS1G_ANEG_NP_STATUS                              0x6c
+-
+-#define PCS1G_LINK_STATUS                                 0x70
+-
+-#define PCS1G_LINK_STATUS_DELAY_VAR(x)                    (((x) << 12) & GENMASK(15, 12))
+-#define PCS1G_LINK_STATUS_DELAY_VAR_M                     GENMASK(15, 12)
+-#define PCS1G_LINK_STATUS_DELAY_VAR_X(x)                  (((x) & GENMASK(15, 12)) >> 12)
+-#define PCS1G_LINK_STATUS_SIGNAL_DETECT                   BIT(8)
+-#define PCS1G_LINK_STATUS_LINK_STATUS                     BIT(4)
+-#define PCS1G_LINK_STATUS_SYNC_STATUS                     BIT(0)
+-
+-#define PCS1G_LINK_DOWN_CNT                               0x74
+-
+-#define PCS1G_STICKY                                      0x78
+-
+-#define PCS1G_STICKY_LINK_DOWN_STICKY                     BIT(4)
+-#define PCS1G_STICKY_OUT_OF_SYNC_STICKY                   BIT(0)
+-
+-#define PCS1G_DEBUG_STATUS                                0x7c
+-
+-#define PCS1G_LPI_CFG                                     0x80
+-
+-#define PCS1G_LPI_CFG_QSGMII_MS_SEL                       BIT(20)
+-#define PCS1G_LPI_CFG_RX_LPI_OUT_DIS                      BIT(17)
+-#define PCS1G_LPI_CFG_LPI_TESTMODE                        BIT(16)
+-#define PCS1G_LPI_CFG_LPI_RX_WTIM(x)                      (((x) << 4) & GENMASK(5, 4))
+-#define PCS1G_LPI_CFG_LPI_RX_WTIM_M                       GENMASK(5, 4)
+-#define PCS1G_LPI_CFG_LPI_RX_WTIM_X(x)                    (((x) & GENMASK(5, 4)) >> 4)
+-#define PCS1G_LPI_CFG_TX_ASSERT_LPIDLE                    BIT(0)
+-
+-#define PCS1G_LPI_WAKE_ERROR_CNT                          0x84
+-
+-#define PCS1G_LPI_STATUS                                  0x88
+-
+-#define PCS1G_LPI_STATUS_RX_LPI_FAIL                      BIT(16)
+-#define PCS1G_LPI_STATUS_RX_LPI_EVENT_STICKY              BIT(12)
+-#define PCS1G_LPI_STATUS_RX_QUIET                         BIT(9)
+-#define PCS1G_LPI_STATUS_RX_LPI_MODE                      BIT(8)
+-#define PCS1G_LPI_STATUS_TX_LPI_EVENT_STICKY              BIT(4)
+-#define PCS1G_LPI_STATUS_TX_QUIET                         BIT(1)
+-#define PCS1G_LPI_STATUS_TX_LPI_MODE                      BIT(0)
+-
+-#define PCS1G_TSTPAT_MODE_CFG                             0x8c
+-
+-#define PCS1G_TSTPAT_STATUS                               0x90
+-
+-#define PCS1G_TSTPAT_STATUS_JTP_ERR_CNT(x)                (((x) << 8) & GENMASK(15, 8))
+-#define PCS1G_TSTPAT_STATUS_JTP_ERR_CNT_M                 GENMASK(15, 8)
+-#define PCS1G_TSTPAT_STATUS_JTP_ERR_CNT_X(x)              (((x) & GENMASK(15, 8)) >> 8)
+-#define PCS1G_TSTPAT_STATUS_JTP_ERR                       BIT(4)
+-#define PCS1G_TSTPAT_STATUS_JTP_LOCK                      BIT(0)
+-
+-#define DEV_PCS_FX100_CFG                                 0x94
+-
+-#define DEV_PCS_FX100_CFG_SD_SEL                          BIT(26)
+-#define DEV_PCS_FX100_CFG_SD_POL                          BIT(25)
+-#define DEV_PCS_FX100_CFG_SD_ENA                          BIT(24)
+-#define DEV_PCS_FX100_CFG_LOOPBACK_ENA                    BIT(20)
+-#define DEV_PCS_FX100_CFG_SWAP_MII_ENA                    BIT(16)
+-#define DEV_PCS_FX100_CFG_RXBITSEL(x)                     (((x) << 12) & GENMASK(15, 12))
+-#define DEV_PCS_FX100_CFG_RXBITSEL_M                      GENMASK(15, 12)
+-#define DEV_PCS_FX100_CFG_RXBITSEL_X(x)                   (((x) & GENMASK(15, 12)) >> 12)
+-#define DEV_PCS_FX100_CFG_SIGDET_CFG(x)                   (((x) << 9) & GENMASK(10, 9))
+-#define DEV_PCS_FX100_CFG_SIGDET_CFG_M                    GENMASK(10, 9)
+-#define DEV_PCS_FX100_CFG_SIGDET_CFG_X(x)                 (((x) & GENMASK(10, 9)) >> 9)
+-#define DEV_PCS_FX100_CFG_LINKHYST_TM_ENA                 BIT(8)
+-#define DEV_PCS_FX100_CFG_LINKHYSTTIMER(x)                (((x) << 4) & GENMASK(7, 4))
+-#define DEV_PCS_FX100_CFG_LINKHYSTTIMER_M                 GENMASK(7, 4)
+-#define DEV_PCS_FX100_CFG_LINKHYSTTIMER_X(x)              (((x) & GENMASK(7, 4)) >> 4)
+-#define DEV_PCS_FX100_CFG_UNIDIR_MODE_ENA                 BIT(3)
+-#define DEV_PCS_FX100_CFG_FEFCHK_ENA                      BIT(2)
+-#define DEV_PCS_FX100_CFG_FEFGEN_ENA                      BIT(1)
+-#define DEV_PCS_FX100_CFG_PCS_ENA                         BIT(0)
+-
+-#define DEV_PCS_FX100_STATUS                              0x98
+-
+-#define DEV_PCS_FX100_STATUS_EDGE_POS_PTP(x)              (((x) << 8) & GENMASK(11, 8))
+-#define DEV_PCS_FX100_STATUS_EDGE_POS_PTP_M               GENMASK(11, 8)
+-#define DEV_PCS_FX100_STATUS_EDGE_POS_PTP_X(x)            (((x) & GENMASK(11, 8)) >> 8)
+-#define DEV_PCS_FX100_STATUS_PCS_ERROR_STICKY             BIT(7)
+-#define DEV_PCS_FX100_STATUS_FEF_FOUND_STICKY             BIT(6)
+-#define DEV_PCS_FX100_STATUS_SSD_ERROR_STICKY             BIT(5)
+-#define DEV_PCS_FX100_STATUS_SYNC_LOST_STICKY             BIT(4)
+-#define DEV_PCS_FX100_STATUS_FEF_STATUS                   BIT(2)
+-#define DEV_PCS_FX100_STATUS_SIGNAL_DETECT                BIT(1)
+-#define DEV_PCS_FX100_STATUS_SYNC_STATUS                  BIT(0)
+-
+-#endif
+--- a/drivers/net/ethernet/mscc/ocelot_qsys.h
++++ /dev/null
+@@ -1,270 +0,0 @@
+-/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+-/*
+- * Microsemi Ocelot Switch driver
+- *
+- * Copyright (c) 2017 Microsemi Corporation
+- */
+-
+-#ifndef _MSCC_OCELOT_QSYS_H_
+-#define _MSCC_OCELOT_QSYS_H_
+-
+-#define QSYS_PORT_MODE_RSZ                                0x4
+-
+-#define QSYS_PORT_MODE_DEQUEUE_DIS                        BIT(1)
+-#define QSYS_PORT_MODE_DEQUEUE_LATE                       BIT(0)
+-
+-#define QSYS_SWITCH_PORT_MODE_RSZ                         0x4
+-
+-#define QSYS_SWITCH_PORT_MODE_PORT_ENA                    BIT(14)
+-#define QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(x)             (((x) << 11) & GENMASK(13, 11))
+-#define QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG_M              GENMASK(13, 11)
+-#define QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG_X(x)           (((x) & GENMASK(13, 11)) >> 11)
+-#define QSYS_SWITCH_PORT_MODE_YEL_RSRVD                   BIT(10)
+-#define QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE           BIT(9)
+-#define QSYS_SWITCH_PORT_MODE_TX_PFC_ENA(x)               (((x) << 1) & GENMASK(8, 1))
+-#define QSYS_SWITCH_PORT_MODE_TX_PFC_ENA_M                GENMASK(8, 1)
+-#define QSYS_SWITCH_PORT_MODE_TX_PFC_ENA_X(x)             (((x) & GENMASK(8, 1)) >> 1)
+-#define QSYS_SWITCH_PORT_MODE_TX_PFC_MODE                 BIT(0)
+-
+-#define QSYS_STAT_CNT_CFG_TX_GREEN_CNT_MODE               BIT(5)
+-#define QSYS_STAT_CNT_CFG_TX_YELLOW_CNT_MODE              BIT(4)
+-#define QSYS_STAT_CNT_CFG_DROP_GREEN_CNT_MODE             BIT(3)
+-#define QSYS_STAT_CNT_CFG_DROP_YELLOW_CNT_MODE            BIT(2)
+-#define QSYS_STAT_CNT_CFG_DROP_COUNT_ONCE                 BIT(1)
+-#define QSYS_STAT_CNT_CFG_DROP_COUNT_EGRESS               BIT(0)
+-
+-#define QSYS_EEE_CFG_RSZ                                  0x4
+-
+-#define QSYS_EEE_THRES_EEE_HIGH_BYTES(x)                  (((x) << 8) & GENMASK(15, 8))
+-#define QSYS_EEE_THRES_EEE_HIGH_BYTES_M                   GENMASK(15, 8)
+-#define QSYS_EEE_THRES_EEE_HIGH_BYTES_X(x)                (((x) & GENMASK(15, 8)) >> 8)
+-#define QSYS_EEE_THRES_EEE_HIGH_FRAMES(x)                 ((x) & GENMASK(7, 0))
+-#define QSYS_EEE_THRES_EEE_HIGH_FRAMES_M                  GENMASK(7, 0)
+-
+-#define QSYS_SW_STATUS_RSZ                                0x4
+-
+-#define QSYS_EXT_CPU_CFG_EXT_CPU_PORT(x)                  (((x) << 8) & GENMASK(12, 8))
+-#define QSYS_EXT_CPU_CFG_EXT_CPU_PORT_M                   GENMASK(12, 8)
+-#define QSYS_EXT_CPU_CFG_EXT_CPU_PORT_X(x)                (((x) & GENMASK(12, 8)) >> 8)
+-#define QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK(x)                  ((x) & GENMASK(7, 0))
+-#define QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M                   GENMASK(7, 0)
+-
+-#define QSYS_QMAP_GSZ                                     0x4
+-
+-#define QSYS_QMAP_SE_BASE(x)                              (((x) << 5) & GENMASK(12, 5))
+-#define QSYS_QMAP_SE_BASE_M                               GENMASK(12, 5)
+-#define QSYS_QMAP_SE_BASE_X(x)                            (((x) & GENMASK(12, 5)) >> 5)
+-#define QSYS_QMAP_SE_IDX_SEL(x)                           (((x) << 2) & GENMASK(4, 2))
+-#define QSYS_QMAP_SE_IDX_SEL_M                            GENMASK(4, 2)
+-#define QSYS_QMAP_SE_IDX_SEL_X(x)                         (((x) & GENMASK(4, 2)) >> 2)
+-#define QSYS_QMAP_SE_INP_SEL(x)                           ((x) & GENMASK(1, 0))
+-#define QSYS_QMAP_SE_INP_SEL_M                            GENMASK(1, 0)
+-
+-#define QSYS_ISDX_SGRP_GSZ                                0x4
+-
+-#define QSYS_TIMED_FRAME_ENTRY_GSZ                        0x4
+-
+-#define QSYS_TFRM_MISC_TIMED_CANCEL_SLOT(x)               (((x) << 9) & GENMASK(18, 9))
+-#define QSYS_TFRM_MISC_TIMED_CANCEL_SLOT_M                GENMASK(18, 9)
+-#define QSYS_TFRM_MISC_TIMED_CANCEL_SLOT_X(x)             (((x) & GENMASK(18, 9)) >> 9)
+-#define QSYS_TFRM_MISC_TIMED_CANCEL_1SHOT                 BIT(8)
+-#define QSYS_TFRM_MISC_TIMED_SLOT_MODE_MC                 BIT(7)
+-#define QSYS_TFRM_MISC_TIMED_ENTRY_FAST_CNT(x)            ((x) & GENMASK(6, 0))
+-#define QSYS_TFRM_MISC_TIMED_ENTRY_FAST_CNT_M             GENMASK(6, 0)
+-
+-#define QSYS_RED_PROFILE_RSZ                              0x4
+-
+-#define QSYS_RED_PROFILE_WM_RED_LOW(x)                    (((x) << 8) & GENMASK(15, 8))
+-#define QSYS_RED_PROFILE_WM_RED_LOW_M                     GENMASK(15, 8)
+-#define QSYS_RED_PROFILE_WM_RED_LOW_X(x)                  (((x) & GENMASK(15, 8)) >> 8)
+-#define QSYS_RED_PROFILE_WM_RED_HIGH(x)                   ((x) & GENMASK(7, 0))
+-#define QSYS_RED_PROFILE_WM_RED_HIGH_M                    GENMASK(7, 0)
+-
+-#define QSYS_RES_CFG_GSZ                                  0x8
+-
+-#define QSYS_RES_STAT_GSZ                                 0x8
+-
+-#define QSYS_RES_STAT_INUSE(x)                            (((x) << 12) & GENMASK(23, 12))
+-#define QSYS_RES_STAT_INUSE_M                             GENMASK(23, 12)
+-#define QSYS_RES_STAT_INUSE_X(x)                          (((x) & GENMASK(23, 12)) >> 12)
+-#define QSYS_RES_STAT_MAXUSE(x)                           ((x) & GENMASK(11, 0))
+-#define QSYS_RES_STAT_MAXUSE_M                            GENMASK(11, 0)
+-
+-#define QSYS_EVENTS_CORE_EV_FDC(x)                        (((x) << 2) & GENMASK(4, 2))
+-#define QSYS_EVENTS_CORE_EV_FDC_M                         GENMASK(4, 2)
+-#define QSYS_EVENTS_CORE_EV_FDC_X(x)                      (((x) & GENMASK(4, 2)) >> 2)
+-#define QSYS_EVENTS_CORE_EV_FRD(x)                        ((x) & GENMASK(1, 0))
+-#define QSYS_EVENTS_CORE_EV_FRD_M                         GENMASK(1, 0)
+-
+-#define QSYS_QMAXSDU_CFG_0_RSZ                            0x4
+-
+-#define QSYS_QMAXSDU_CFG_1_RSZ                            0x4
+-
+-#define QSYS_QMAXSDU_CFG_2_RSZ                            0x4
+-
+-#define QSYS_QMAXSDU_CFG_3_RSZ                            0x4
+-
+-#define QSYS_QMAXSDU_CFG_4_RSZ                            0x4
+-
+-#define QSYS_QMAXSDU_CFG_5_RSZ                            0x4
+-
+-#define QSYS_QMAXSDU_CFG_6_RSZ                            0x4
+-
+-#define QSYS_QMAXSDU_CFG_7_RSZ                            0x4
+-
+-#define QSYS_PREEMPTION_CFG_RSZ                           0x4
+-
+-#define QSYS_PREEMPTION_CFG_P_QUEUES(x)                   ((x) & GENMASK(7, 0))
+-#define QSYS_PREEMPTION_CFG_P_QUEUES_M                    GENMASK(7, 0)
+-#define QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE(x)           (((x) << 8) & GENMASK(9, 8))
+-#define QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_M            GENMASK(9, 8)
+-#define QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_X(x)         (((x) & GENMASK(9, 8)) >> 8)
+-#define QSYS_PREEMPTION_CFG_STRICT_IPG(x)                 (((x) << 12) & GENMASK(13, 12))
+-#define QSYS_PREEMPTION_CFG_STRICT_IPG_M                  GENMASK(13, 12)
+-#define QSYS_PREEMPTION_CFG_STRICT_IPG_X(x)               (((x) & GENMASK(13, 12)) >> 12)
+-#define QSYS_PREEMPTION_CFG_HOLD_ADVANCE(x)               (((x) << 16) & GENMASK(31, 16))
+-#define QSYS_PREEMPTION_CFG_HOLD_ADVANCE_M                GENMASK(31, 16)
+-#define QSYS_PREEMPTION_CFG_HOLD_ADVANCE_X(x)             (((x) & GENMASK(31, 16)) >> 16)
+-
+-#define QSYS_CIR_CFG_GSZ                                  0x80
+-
+-#define QSYS_CIR_CFG_CIR_RATE(x)                          (((x) << 6) & GENMASK(20, 6))
+-#define QSYS_CIR_CFG_CIR_RATE_M                           GENMASK(20, 6)
+-#define QSYS_CIR_CFG_CIR_RATE_X(x)                        (((x) & GENMASK(20, 6)) >> 6)
+-#define QSYS_CIR_CFG_CIR_BURST(x)                         ((x) & GENMASK(5, 0))
+-#define QSYS_CIR_CFG_CIR_BURST_M                          GENMASK(5, 0)
+-
+-#define QSYS_EIR_CFG_GSZ                                  0x80
+-
+-#define QSYS_EIR_CFG_EIR_RATE(x)                          (((x) << 7) & GENMASK(21, 7))
+-#define QSYS_EIR_CFG_EIR_RATE_M                           GENMASK(21, 7)
+-#define QSYS_EIR_CFG_EIR_RATE_X(x)                        (((x) & GENMASK(21, 7)) >> 7)
+-#define QSYS_EIR_CFG_EIR_BURST(x)                         (((x) << 1) & GENMASK(6, 1))
+-#define QSYS_EIR_CFG_EIR_BURST_M                          GENMASK(6, 1)
+-#define QSYS_EIR_CFG_EIR_BURST_X(x)                       (((x) & GENMASK(6, 1)) >> 1)
+-#define QSYS_EIR_CFG_EIR_MARK_ENA                         BIT(0)
+-
+-#define QSYS_SE_CFG_GSZ                                   0x80
+-
+-#define QSYS_SE_CFG_SE_DWRR_CNT(x)                        (((x) << 6) & GENMASK(9, 6))
+-#define QSYS_SE_CFG_SE_DWRR_CNT_M                         GENMASK(9, 6)
+-#define QSYS_SE_CFG_SE_DWRR_CNT_X(x)                      (((x) & GENMASK(9, 6)) >> 6)
+-#define QSYS_SE_CFG_SE_RR_ENA                             BIT(5)
+-#define QSYS_SE_CFG_SE_AVB_ENA                            BIT(4)
+-#define QSYS_SE_CFG_SE_FRM_MODE(x)                        (((x) << 2) & GENMASK(3, 2))
+-#define QSYS_SE_CFG_SE_FRM_MODE_M                         GENMASK(3, 2)
+-#define QSYS_SE_CFG_SE_FRM_MODE_X(x)                      (((x) & GENMASK(3, 2)) >> 2)
+-#define QSYS_SE_CFG_SE_EXC_ENA                            BIT(1)
+-#define QSYS_SE_CFG_SE_EXC_FWD                            BIT(0)
+-
+-#define QSYS_SE_DWRR_CFG_GSZ                              0x80
+-#define QSYS_SE_DWRR_CFG_RSZ                              0x4
+-
+-#define QSYS_SE_CONNECT_GSZ                               0x80
+-
+-#define QSYS_SE_CONNECT_SE_OUTP_IDX(x)                    (((x) << 17) & GENMASK(24, 17))
+-#define QSYS_SE_CONNECT_SE_OUTP_IDX_M                     GENMASK(24, 17)
+-#define QSYS_SE_CONNECT_SE_OUTP_IDX_X(x)                  (((x) & GENMASK(24, 17)) >> 17)
+-#define QSYS_SE_CONNECT_SE_INP_IDX(x)                     (((x) << 9) & GENMASK(16, 9))
+-#define QSYS_SE_CONNECT_SE_INP_IDX_M                      GENMASK(16, 9)
+-#define QSYS_SE_CONNECT_SE_INP_IDX_X(x)                   (((x) & GENMASK(16, 9)) >> 9)
+-#define QSYS_SE_CONNECT_SE_OUTP_CON(x)                    (((x) << 5) & GENMASK(8, 5))
+-#define QSYS_SE_CONNECT_SE_OUTP_CON_M                     GENMASK(8, 5)
+-#define QSYS_SE_CONNECT_SE_OUTP_CON_X(x)                  (((x) & GENMASK(8, 5)) >> 5)
+-#define QSYS_SE_CONNECT_SE_INP_CNT(x)                     (((x) << 1) & GENMASK(4, 1))
+-#define QSYS_SE_CONNECT_SE_INP_CNT_M                      GENMASK(4, 1)
+-#define QSYS_SE_CONNECT_SE_INP_CNT_X(x)                   (((x) & GENMASK(4, 1)) >> 1)
+-#define QSYS_SE_CONNECT_SE_TERMINAL                       BIT(0)
+-
+-#define QSYS_SE_DLB_SENSE_GSZ                             0x80
+-
+-#define QSYS_SE_DLB_SENSE_SE_DLB_PRIO(x)                  (((x) << 11) & GENMASK(13, 11))
+-#define QSYS_SE_DLB_SENSE_SE_DLB_PRIO_M                   GENMASK(13, 11)
+-#define QSYS_SE_DLB_SENSE_SE_DLB_PRIO_X(x)                (((x) & GENMASK(13, 11)) >> 11)
+-#define QSYS_SE_DLB_SENSE_SE_DLB_SPORT(x)                 (((x) << 7) & GENMASK(10, 7))
+-#define QSYS_SE_DLB_SENSE_SE_DLB_SPORT_M                  GENMASK(10, 7)
+-#define QSYS_SE_DLB_SENSE_SE_DLB_SPORT_X(x)               (((x) & GENMASK(10, 7)) >> 7)
+-#define QSYS_SE_DLB_SENSE_SE_DLB_DPORT(x)                 (((x) << 3) & GENMASK(6, 3))
+-#define QSYS_SE_DLB_SENSE_SE_DLB_DPORT_M                  GENMASK(6, 3)
+-#define QSYS_SE_DLB_SENSE_SE_DLB_DPORT_X(x)               (((x) & GENMASK(6, 3)) >> 3)
+-#define QSYS_SE_DLB_SENSE_SE_DLB_PRIO_ENA                 BIT(2)
+-#define QSYS_SE_DLB_SENSE_SE_DLB_SPORT_ENA                BIT(1)
+-#define QSYS_SE_DLB_SENSE_SE_DLB_DPORT_ENA                BIT(0)
+-
+-#define QSYS_CIR_STATE_GSZ                                0x80
+-
+-#define QSYS_CIR_STATE_CIR_LVL(x)                         (((x) << 4) & GENMASK(25, 4))
+-#define QSYS_CIR_STATE_CIR_LVL_M                          GENMASK(25, 4)
+-#define QSYS_CIR_STATE_CIR_LVL_X(x)                       (((x) & GENMASK(25, 4)) >> 4)
+-#define QSYS_CIR_STATE_SHP_TIME(x)                        ((x) & GENMASK(3, 0))
+-#define QSYS_CIR_STATE_SHP_TIME_M                         GENMASK(3, 0)
+-
+-#define QSYS_EIR_STATE_GSZ                                0x80
+-
+-#define QSYS_SE_STATE_GSZ                                 0x80
+-
+-#define QSYS_SE_STATE_SE_OUTP_LVL(x)                      (((x) << 1) & GENMASK(2, 1))
+-#define QSYS_SE_STATE_SE_OUTP_LVL_M                       GENMASK(2, 1)
+-#define QSYS_SE_STATE_SE_OUTP_LVL_X(x)                    (((x) & GENMASK(2, 1)) >> 1)
+-#define QSYS_SE_STATE_SE_WAS_YEL                          BIT(0)
+-
+-#define QSYS_HSCH_MISC_CFG_SE_CONNECT_VLD                 BIT(8)
+-#define QSYS_HSCH_MISC_CFG_FRM_ADJ(x)                     (((x) << 3) & GENMASK(7, 3))
+-#define QSYS_HSCH_MISC_CFG_FRM_ADJ_M                      GENMASK(7, 3)
+-#define QSYS_HSCH_MISC_CFG_FRM_ADJ_X(x)                   (((x) & GENMASK(7, 3)) >> 3)
+-#define QSYS_HSCH_MISC_CFG_LEAK_DIS                       BIT(2)
+-#define QSYS_HSCH_MISC_CFG_QSHP_EXC_ENA                   BIT(1)
+-#define QSYS_HSCH_MISC_CFG_PFC_BYP_UPD                    BIT(0)
+-
+-#define QSYS_TAG_CONFIG_RSZ                               0x4
+-
+-#define QSYS_TAG_CONFIG_ENABLE                            BIT(0)
+-#define QSYS_TAG_CONFIG_LINK_SPEED(x)                     (((x) << 4) & GENMASK(5, 4))
+-#define QSYS_TAG_CONFIG_LINK_SPEED_M                      GENMASK(5, 4)
+-#define QSYS_TAG_CONFIG_LINK_SPEED_X(x)                   (((x) & GENMASK(5, 4)) >> 4)
+-#define QSYS_TAG_CONFIG_INIT_GATE_STATE(x)                (((x) << 8) & GENMASK(15, 8))
+-#define QSYS_TAG_CONFIG_INIT_GATE_STATE_M                 GENMASK(15, 8)
+-#define QSYS_TAG_CONFIG_INIT_GATE_STATE_X(x)              (((x) & GENMASK(15, 8)) >> 8)
+-#define QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES(x)             (((x) << 16) & GENMASK(23, 16))
+-#define QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_M              GENMASK(23, 16)
+-#define QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_X(x)           (((x) & GENMASK(23, 16)) >> 16)
+-
+-#define QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(x)               ((x) & GENMASK(7, 0))
+-#define QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M                GENMASK(7, 0)
+-#define QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q   BIT(8)
+-#define QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE             BIT(16)
+-
+-#define QSYS_PORT_MAX_SDU_RSZ                             0x4
+-
+-#define QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(x)         ((x) & GENMASK(15, 0))
+-#define QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB_M          GENMASK(15, 0)
+-#define QSYS_PARAM_CFG_REG_3_LIST_LENGTH(x)               (((x) << 16) & GENMASK(31, 16))
+-#define QSYS_PARAM_CFG_REG_3_LIST_LENGTH_M                GENMASK(31, 16)
+-#define QSYS_PARAM_CFG_REG_3_LIST_LENGTH_X(x)             (((x) & GENMASK(31, 16)) >> 16)
+-
+-#define QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM(x)               ((x) & GENMASK(5, 0))
+-#define QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM_M                GENMASK(5, 0)
+-#define QSYS_GCL_CFG_REG_1_GATE_STATE(x)                  (((x) << 8) & GENMASK(15, 8))
+-#define QSYS_GCL_CFG_REG_1_GATE_STATE_M                   GENMASK(15, 8)
+-#define QSYS_GCL_CFG_REG_1_GATE_STATE_X(x)                (((x) & GENMASK(15, 8)) >> 8)
+-
+-#define QSYS_PARAM_STATUS_REG_3_BASE_TIME_SEC_MSB(x)      ((x) & GENMASK(15, 0))
+-#define QSYS_PARAM_STATUS_REG_3_BASE_TIME_SEC_MSB_M       GENMASK(15, 0)
+-#define QSYS_PARAM_STATUS_REG_3_LIST_LENGTH(x)            (((x) << 16) & GENMASK(31, 16))
+-#define QSYS_PARAM_STATUS_REG_3_LIST_LENGTH_M             GENMASK(31, 16)
+-#define QSYS_PARAM_STATUS_REG_3_LIST_LENGTH_X(x)          (((x) & GENMASK(31, 16)) >> 16)
+-
+-#define QSYS_PARAM_STATUS_REG_8_CFG_CHG_TIME_SEC_MSB(x)   ((x) & GENMASK(15, 0))
+-#define QSYS_PARAM_STATUS_REG_8_CFG_CHG_TIME_SEC_MSB_M    GENMASK(15, 0)
+-#define QSYS_PARAM_STATUS_REG_8_OPER_GATE_STATE(x)        (((x) << 16) & GENMASK(23, 16))
+-#define QSYS_PARAM_STATUS_REG_8_OPER_GATE_STATE_M         GENMASK(23, 16)
+-#define QSYS_PARAM_STATUS_REG_8_OPER_GATE_STATE_X(x)      (((x) & GENMASK(23, 16)) >> 16)
+-#define QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING            BIT(24)
+-
+-#define QSYS_GCL_STATUS_REG_1_GCL_ENTRY_NUM(x)            ((x) & GENMASK(5, 0))
+-#define QSYS_GCL_STATUS_REG_1_GCL_ENTRY_NUM_M             GENMASK(5, 0)
+-#define QSYS_GCL_STATUS_REG_1_GATE_STATE(x)               (((x) << 8) & GENMASK(15, 8))
+-#define QSYS_GCL_STATUS_REG_1_GATE_STATE_M                GENMASK(15, 8)
+-#define QSYS_GCL_STATUS_REG_1_GATE_STATE_X(x)             (((x) & GENMASK(15, 8)) >> 8)
+-
+-#endif
+--- a/drivers/net/ethernet/mscc/ocelot_tsn.c
++++ b/drivers/net/ethernet/mscc/ocelot_tsn.c
+@@ -11,8 +11,8 @@
+ #include <linux/iopoll.h>
+ #include "ocelot.h"
+ #include <soc/mscc/ocelot_sys.h>
+-#include "ocelot_ana.h"
+-#include "ocelot_qsys.h"
++#include <soc/mscc/ocelot_ana.h>
++#include <soc/mscc/ocelot_qsys.h>
+ #include "ocelot_rew.h"
+ #include "ocelot_dev_gmii.h"
+ #include "ocelot_tsn.h"
+--- /dev/null
++++ b/include/soc/mscc/ocelot_ana.h
+@@ -0,0 +1,642 @@
++/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
++/*
++ * Microsemi Ocelot Switch driver
++ *
++ * Copyright (c) 2017 Microsemi Corporation
++ */
++
++#ifndef _MSCC_OCELOT_ANA_H_
++#define _MSCC_OCELOT_ANA_H_
++
++#define ANA_ANAGEFIL_B_DOM_EN                             BIT(22)
++#define ANA_ANAGEFIL_B_DOM_VAL                            BIT(21)
++#define ANA_ANAGEFIL_AGE_LOCKED                           BIT(20)
++#define ANA_ANAGEFIL_PID_EN                               BIT(19)
++#define ANA_ANAGEFIL_PID_VAL(x)                           (((x) << 14) & GENMASK(18, 14))
++#define ANA_ANAGEFIL_PID_VAL_M                            GENMASK(18, 14)
++#define ANA_ANAGEFIL_PID_VAL_X(x)                         (((x) & GENMASK(18, 14)) >> 14)
++#define ANA_ANAGEFIL_VID_EN                               BIT(13)
++#define ANA_ANAGEFIL_VID_VAL(x)                           ((x) & GENMASK(12, 0))
++#define ANA_ANAGEFIL_VID_VAL_M                            GENMASK(12, 0)
++
++#define ANA_STORMLIMIT_CFG_RSZ                            0x4
++
++#define ANA_STORMLIMIT_CFG_STORM_RATE(x)                  (((x) << 3) & GENMASK(6, 3))
++#define ANA_STORMLIMIT_CFG_STORM_RATE_M                   GENMASK(6, 3)
++#define ANA_STORMLIMIT_CFG_STORM_RATE_X(x)                (((x) & GENMASK(6, 3)) >> 3)
++#define ANA_STORMLIMIT_CFG_STORM_UNIT                     BIT(2)
++#define ANA_STORMLIMIT_CFG_STORM_MODE(x)                  ((x) & GENMASK(1, 0))
++#define ANA_STORMLIMIT_CFG_STORM_MODE_M                   GENMASK(1, 0)
++
++#define ANA_AUTOAGE_AGE_FAST                              BIT(21)
++#define ANA_AUTOAGE_AGE_PERIOD(x)                         (((x) << 1) & GENMASK(20, 1))
++#define ANA_AUTOAGE_AGE_PERIOD_M                          GENMASK(20, 1)
++#define ANA_AUTOAGE_AGE_PERIOD_X(x)                       (((x) & GENMASK(20, 1)) >> 1)
++#define ANA_AUTOAGE_AUTOAGE_LOCKED                        BIT(0)
++
++#define ANA_MACTOPTIONS_REDUCED_TABLE                     BIT(1)
++#define ANA_MACTOPTIONS_SHADOW                            BIT(0)
++
++#define ANA_AGENCTRL_FID_MASK(x)                          (((x) << 12) & GENMASK(23, 12))
++#define ANA_AGENCTRL_FID_MASK_M                           GENMASK(23, 12)
++#define ANA_AGENCTRL_FID_MASK_X(x)                        (((x) & GENMASK(23, 12)) >> 12)
++#define ANA_AGENCTRL_IGNORE_DMAC_FLAGS                    BIT(11)
++#define ANA_AGENCTRL_IGNORE_SMAC_FLAGS                    BIT(10)
++#define ANA_AGENCTRL_FLOOD_SPECIAL                        BIT(9)
++#define ANA_AGENCTRL_FLOOD_IGNORE_VLAN                    BIT(8)
++#define ANA_AGENCTRL_MIRROR_CPU                           BIT(7)
++#define ANA_AGENCTRL_LEARN_CPU_COPY                       BIT(6)
++#define ANA_AGENCTRL_LEARN_FWD_KILL                       BIT(5)
++#define ANA_AGENCTRL_LEARN_IGNORE_VLAN                    BIT(4)
++#define ANA_AGENCTRL_CPU_CPU_KILL_ENA                     BIT(3)
++#define ANA_AGENCTRL_GREEN_COUNT_MODE                     BIT(2)
++#define ANA_AGENCTRL_YELLOW_COUNT_MODE                    BIT(1)
++#define ANA_AGENCTRL_RED_COUNT_MODE                       BIT(0)
++
++#define ANA_FLOODING_RSZ                                  0x4
++
++#define ANA_FLOODING_FLD_UNICAST(x)                       (((x) << 12) & GENMASK(17, 12))
++#define ANA_FLOODING_FLD_UNICAST_M                        GENMASK(17, 12)
++#define ANA_FLOODING_FLD_UNICAST_X(x)                     (((x) & GENMASK(17, 12)) >> 12)
++#define ANA_FLOODING_FLD_BROADCAST(x)                     (((x) << 6) & GENMASK(11, 6))
++#define ANA_FLOODING_FLD_BROADCAST_M                      GENMASK(11, 6)
++#define ANA_FLOODING_FLD_BROADCAST_X(x)                   (((x) & GENMASK(11, 6)) >> 6)
++#define ANA_FLOODING_FLD_MULTICAST(x)                     ((x) & GENMASK(5, 0))
++#define ANA_FLOODING_FLD_MULTICAST_M                      GENMASK(5, 0)
++
++#define ANA_FLOODING_IPMC_FLD_MC4_CTRL(x)                 (((x) << 18) & GENMASK(23, 18))
++#define ANA_FLOODING_IPMC_FLD_MC4_CTRL_M                  GENMASK(23, 18)
++#define ANA_FLOODING_IPMC_FLD_MC4_CTRL_X(x)               (((x) & GENMASK(23, 18)) >> 18)
++#define ANA_FLOODING_IPMC_FLD_MC4_DATA(x)                 (((x) << 12) & GENMASK(17, 12))
++#define ANA_FLOODING_IPMC_FLD_MC4_DATA_M                  GENMASK(17, 12)
++#define ANA_FLOODING_IPMC_FLD_MC4_DATA_X(x)               (((x) & GENMASK(17, 12)) >> 12)
++#define ANA_FLOODING_IPMC_FLD_MC6_CTRL(x)                 (((x) << 6) & GENMASK(11, 6))
++#define ANA_FLOODING_IPMC_FLD_MC6_CTRL_M                  GENMASK(11, 6)
++#define ANA_FLOODING_IPMC_FLD_MC6_CTRL_X(x)               (((x) & GENMASK(11, 6)) >> 6)
++#define ANA_FLOODING_IPMC_FLD_MC6_DATA(x)                 ((x) & GENMASK(5, 0))
++#define ANA_FLOODING_IPMC_FLD_MC6_DATA_M                  GENMASK(5, 0)
++
++#define ANA_SFLOW_CFG_RSZ                                 0x4
++
++#define ANA_SFLOW_CFG_SF_RATE(x)                          (((x) << 2) & GENMASK(13, 2))
++#define ANA_SFLOW_CFG_SF_RATE_M                           GENMASK(13, 2)
++#define ANA_SFLOW_CFG_SF_RATE_X(x)                        (((x) & GENMASK(13, 2)) >> 2)
++#define ANA_SFLOW_CFG_SF_SAMPLE_RX                        BIT(1)
++#define ANA_SFLOW_CFG_SF_SAMPLE_TX                        BIT(0)
++
++#define ANA_PORT_MODE_RSZ                                 0x4
++
++#define ANA_PORT_MODE_REDTAG_PARSE_CFG                    BIT(3)
++#define ANA_PORT_MODE_VLAN_PARSE_CFG(x)                   (((x) << 1) & GENMASK(2, 1))
++#define ANA_PORT_MODE_VLAN_PARSE_CFG_M                    GENMASK(2, 1)
++#define ANA_PORT_MODE_VLAN_PARSE_CFG_X(x)                 (((x) & GENMASK(2, 1)) >> 1)
++#define ANA_PORT_MODE_L3_PARSE_CFG                        BIT(0)
++
++#define ANA_CUT_THRU_CFG_RSZ                              0x4
++
++#define ANA_PGID_PGID_RSZ                                 0x4
++
++#define ANA_PGID_PGID_PGID(x)                             ((x) & GENMASK(11, 0))
++#define ANA_PGID_PGID_PGID_M                              GENMASK(11, 0)
++#define ANA_PGID_PGID_CPUQ_DST_PGID(x)                    (((x) << 27) & GENMASK(29, 27))
++#define ANA_PGID_PGID_CPUQ_DST_PGID_M                     GENMASK(29, 27)
++#define ANA_PGID_PGID_CPUQ_DST_PGID_X(x)                  (((x) & GENMASK(29, 27)) >> 27)
++
++#define ANA_TABLES_MACHDATA_VID(x)                        (((x) << 16) & GENMASK(28, 16))
++#define ANA_TABLES_MACHDATA_VID_M                         GENMASK(28, 16)
++#define ANA_TABLES_MACHDATA_VID_X(x)                      (((x) & GENMASK(28, 16)) >> 16)
++#define ANA_TABLES_MACHDATA_MACHDATA(x)                   ((x) & GENMASK(15, 0))
++#define ANA_TABLES_MACHDATA_MACHDATA_M                    GENMASK(15, 0)
++
++#define ANA_TABLES_STREAMDATA_SSID_VALID                  BIT(16)
++#define ANA_TABLES_STREAMDATA_SSID(x)                     (((x) << 9) & GENMASK(15, 9))
++#define ANA_TABLES_STREAMDATA_SSID_M                      GENMASK(15, 9)
++#define ANA_TABLES_STREAMDATA_SSID_X(x)                   (((x) & GENMASK(15, 9)) >> 9)
++#define ANA_TABLES_STREAMDATA_SFID_VALID                  BIT(8)
++#define ANA_TABLES_STREAMDATA_SFID(x)                     ((x) & GENMASK(7, 0))
++#define ANA_TABLES_STREAMDATA_SFID_M                      GENMASK(7, 0)
++
++#define ANA_TABLES_MACACCESS_MAC_CPU_COPY                 BIT(15)
++#define ANA_TABLES_MACACCESS_SRC_KILL                     BIT(14)
++#define ANA_TABLES_MACACCESS_IGNORE_VLAN                  BIT(13)
++#define ANA_TABLES_MACACCESS_AGED_FLAG                    BIT(12)
++#define ANA_TABLES_MACACCESS_VALID                        BIT(11)
++#define ANA_TABLES_MACACCESS_ENTRYTYPE(x)                 (((x) << 9) & GENMASK(10, 9))
++#define ANA_TABLES_MACACCESS_ENTRYTYPE_M                  GENMASK(10, 9)
++#define ANA_TABLES_MACACCESS_ENTRYTYPE_X(x)               (((x) & GENMASK(10, 9)) >> 9)
++#define ANA_TABLES_MACACCESS_DEST_IDX(x)                  (((x) << 3) & GENMASK(8, 3))
++#define ANA_TABLES_MACACCESS_DEST_IDX_M                   GENMASK(8, 3)
++#define ANA_TABLES_MACACCESS_DEST_IDX_X(x)                (((x) & GENMASK(8, 3)) >> 3)
++#define ANA_TABLES_MACACCESS_MAC_TABLE_CMD(x)             ((x) & GENMASK(2, 0))
++#define ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M              GENMASK(2, 0)
++#define MACACCESS_CMD_IDLE                     0
++#define MACACCESS_CMD_LEARN                    1
++#define MACACCESS_CMD_FORGET                   2
++#define MACACCESS_CMD_AGE                      3
++#define MACACCESS_CMD_GET_NEXT                 4
++#define MACACCESS_CMD_INIT                     5
++#define MACACCESS_CMD_READ                     6
++#define MACACCESS_CMD_WRITE                    7
++
++#define ANA_TABLES_VLANACCESS_VLAN_PORT_MASK(x)           (((x) << 2) & GENMASK(13, 2))
++#define ANA_TABLES_VLANACCESS_VLAN_PORT_MASK_M            GENMASK(13, 2)
++#define ANA_TABLES_VLANACCESS_VLAN_PORT_MASK_X(x)         (((x) & GENMASK(13, 2)) >> 2)
++#define ANA_TABLES_VLANACCESS_VLAN_TBL_CMD(x)             ((x) & GENMASK(1, 0))
++#define ANA_TABLES_VLANACCESS_VLAN_TBL_CMD_M              GENMASK(1, 0)
++#define ANA_TABLES_VLANACCESS_CMD_IDLE                    0x0
++#define ANA_TABLES_VLANACCESS_CMD_WRITE                   0x2
++#define ANA_TABLES_VLANACCESS_CMD_INIT                    0x3
++
++#define ANA_TABLES_VLANTIDX_VLAN_SEC_FWD_ENA              BIT(17)
++#define ANA_TABLES_VLANTIDX_VLAN_FLOOD_DIS                BIT(16)
++#define ANA_TABLES_VLANTIDX_VLAN_PRIV_VLAN                BIT(15)
++#define ANA_TABLES_VLANTIDX_VLAN_LEARN_DISABLED           BIT(14)
++#define ANA_TABLES_VLANTIDX_VLAN_MIRROR                   BIT(13)
++#define ANA_TABLES_VLANTIDX_VLAN_SRC_CHK                  BIT(12)
++#define ANA_TABLES_VLANTIDX_V_INDEX(x)                    ((x) & GENMASK(11, 0))
++#define ANA_TABLES_VLANTIDX_V_INDEX_M                     GENMASK(11, 0)
++
++#define ANA_TABLES_ISDXACCESS_ISDX_PORT_MASK(x)           (((x) << 2) & GENMASK(8, 2))
++#define ANA_TABLES_ISDXACCESS_ISDX_PORT_MASK_M            GENMASK(8, 2)
++#define ANA_TABLES_ISDXACCESS_ISDX_PORT_MASK_X(x)         (((x) & GENMASK(8, 2)) >> 2)
++#define ANA_TABLES_ISDXACCESS_ISDX_TBL_CMD(x)             ((x) & GENMASK(1, 0))
++#define ANA_TABLES_ISDXACCESS_ISDX_TBL_CMD_M              GENMASK(1, 0)
++
++#define ANA_TABLES_ISDXTIDX_ISDX_SDLBI(x)                 (((x) << 21) & GENMASK(28, 21))
++#define ANA_TABLES_ISDXTIDX_ISDX_SDLBI_M                  GENMASK(28, 21)
++#define ANA_TABLES_ISDXTIDX_ISDX_SDLBI_X(x)               (((x) & GENMASK(28, 21)) >> 21)
++#define ANA_TABLES_ISDXTIDX_ISDX_MSTI(x)                  (((x) << 15) & GENMASK(20, 15))
++#define ANA_TABLES_ISDXTIDX_ISDX_MSTI_M                   GENMASK(20, 15)
++#define ANA_TABLES_ISDXTIDX_ISDX_MSTI_X(x)                (((x) & GENMASK(20, 15)) >> 15)
++#define ANA_TABLES_ISDXTIDX_ISDX_ES0_KEY_ENA              BIT(14)
++#define ANA_TABLES_ISDXTIDX_ISDX_FORCE_ENA                BIT(10)
++#define ANA_TABLES_ISDXTIDX_ISDX_INDEX(x)                 ((x) & GENMASK(7, 0))
++#define ANA_TABLES_ISDXTIDX_ISDX_INDEX_M                  GENMASK(7, 0)
++
++#define ANA_TABLES_ENTRYLIM_RSZ                           0x4
++
++#define ANA_TABLES_ENTRYLIM_ENTRYLIM(x)                   (((x) << 14) & GENMASK(17, 14))
++#define ANA_TABLES_ENTRYLIM_ENTRYLIM_M                    GENMASK(17, 14)
++#define ANA_TABLES_ENTRYLIM_ENTRYLIM_X(x)                 (((x) & GENMASK(17, 14)) >> 14)
++#define ANA_TABLES_ENTRYLIM_ENTRYSTAT(x)                  ((x) & GENMASK(13, 0))
++#define ANA_TABLES_ENTRYLIM_ENTRYSTAT_M                   GENMASK(13, 0)
++
++#define ANA_TABLES_STREAMACCESS_GEN_REC_SEQ_NUM(x)        (((x) << 4) & GENMASK(31, 4))
++#define ANA_TABLES_STREAMACCESS_GEN_REC_SEQ_NUM_M         GENMASK(31, 4)
++#define ANA_TABLES_STREAMACCESS_GEN_REC_SEQ_NUM_X(x)      (((x) & GENMASK(31, 4)) >> 4)
++#define ANA_TABLES_STREAMACCESS_SEQ_GEN_REC_ENA           BIT(3)
++#define ANA_TABLES_STREAMACCESS_GEN_REC_TYPE              BIT(2)
++#define ANA_TABLES_STREAMACCESS_STREAM_TBL_CMD(x)         ((x) & GENMASK(1, 0))
++#define ANA_TABLES_STREAMACCESS_STREAM_TBL_CMD_M          GENMASK(1, 0)
++
++#define ANA_TABLES_STREAMTIDX_SEQ_GEN_ERR_STATUS(x)       (((x) << 30) & GENMASK(31, 30))
++#define ANA_TABLES_STREAMTIDX_SEQ_GEN_ERR_STATUS_M        GENMASK(31, 30)
++#define ANA_TABLES_STREAMTIDX_SEQ_GEN_ERR_STATUS_X(x)     (((x) & GENMASK(31, 30)) >> 30)
++#define ANA_TABLES_STREAMTIDX_S_INDEX(x)                  (((x) << 16) & GENMASK(22, 16))
++#define ANA_TABLES_STREAMTIDX_S_INDEX_M                   GENMASK(22, 16)
++#define ANA_TABLES_STREAMTIDX_S_INDEX_X(x)                (((x) & GENMASK(22, 16)) >> 16)
++#define ANA_TABLES_STREAMTIDX_FORCE_SF_BEHAVIOUR          BIT(14)
++#define ANA_TABLES_STREAMTIDX_SEQ_HISTORY_LEN(x)          (((x) << 8) & GENMASK(13, 8))
++#define ANA_TABLES_STREAMTIDX_SEQ_HISTORY_LEN_M           GENMASK(13, 8)
++#define ANA_TABLES_STREAMTIDX_SEQ_HISTORY_LEN_X(x)        (((x) & GENMASK(13, 8)) >> 8)
++#define ANA_TABLES_STREAMTIDX_RESET_ON_ROGUE              BIT(7)
++#define ANA_TABLES_STREAMTIDX_REDTAG_POP                  BIT(6)
++#define ANA_TABLES_STREAMTIDX_STREAM_SPLIT                BIT(5)
++#define ANA_TABLES_STREAMTIDX_SEQ_SPACE_LOG2(x)           ((x) & GENMASK(4, 0))
++#define ANA_TABLES_STREAMTIDX_SEQ_SPACE_LOG2_M            GENMASK(4, 0)
++
++#define ANA_TABLES_SEQ_MASK_SPLIT_MASK(x)                 (((x) << 16) & GENMASK(22, 16))
++#define ANA_TABLES_SEQ_MASK_SPLIT_MASK_M                  GENMASK(22, 16)
++#define ANA_TABLES_SEQ_MASK_SPLIT_MASK_X(x)               (((x) & GENMASK(22, 16)) >> 16)
++#define ANA_TABLES_SEQ_MASK_INPUT_PORT_MASK(x)            ((x) & GENMASK(6, 0))
++#define ANA_TABLES_SEQ_MASK_INPUT_PORT_MASK_M             GENMASK(6, 0)
++
++#define ANA_TABLES_SFID_MASK_IGR_PORT_MASK(x)             (((x) << 1) & GENMASK(7, 1))
++#define ANA_TABLES_SFID_MASK_IGR_PORT_MASK_M              GENMASK(7, 1)
++#define ANA_TABLES_SFID_MASK_IGR_PORT_MASK_X(x)           (((x) & GENMASK(7, 1)) >> 1)
++#define ANA_TABLES_SFID_MASK_IGR_SRCPORT_MATCH_ENA        BIT(0)
++
++#define ANA_TABLES_SFIDACCESS_IGR_PRIO_MATCH_ENA          BIT(22)
++#define ANA_TABLES_SFIDACCESS_IGR_PRIO(x)                 (((x) << 19) & GENMASK(21, 19))
++#define ANA_TABLES_SFIDACCESS_IGR_PRIO_M                  GENMASK(21, 19)
++#define ANA_TABLES_SFIDACCESS_IGR_PRIO_X(x)               (((x) & GENMASK(21, 19)) >> 19)
++#define ANA_TABLES_SFIDACCESS_FORCE_BLOCK                 BIT(18)
++#define ANA_TABLES_SFIDACCESS_MAX_SDU_LEN(x)              (((x) << 2) & GENMASK(17, 2))
++#define ANA_TABLES_SFIDACCESS_MAX_SDU_LEN_M               GENMASK(17, 2)
++#define ANA_TABLES_SFIDACCESS_MAX_SDU_LEN_X(x)            (((x) & GENMASK(17, 2)) >> 2)
++#define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(x)             ((x) & GENMASK(1, 0))
++#define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD_M              GENMASK(1, 0)
++
++#define SFIDACCESS_CMD_IDLE                             0
++#define SFIDACCESS_CMD_READ                             1
++#define SFIDACCESS_CMD_WRITE                            2
++#define SFIDACCESS_CMD_INIT                           3
++
++#define ANA_TABLES_SFIDTIDX_SGID_VALID                    BIT(26)
++#define ANA_TABLES_SFIDTIDX_SGID(x)                       (((x) << 18) & GENMASK(25, 18))
++#define ANA_TABLES_SFIDTIDX_SGID_M                        GENMASK(25, 18)
++#define ANA_TABLES_SFIDTIDX_SGID_X(x)                     (((x) & GENMASK(25, 18)) >> 18)
++#define ANA_TABLES_SFIDTIDX_POL_ENA                       BIT(17)
++#define ANA_TABLES_SFIDTIDX_POL_IDX(x)                    (((x) << 8) & GENMASK(16, 8))
++#define ANA_TABLES_SFIDTIDX_POL_IDX_M                     GENMASK(16, 8)
++#define ANA_TABLES_SFIDTIDX_POL_IDX_X(x)                  (((x) & GENMASK(16, 8)) >> 8)
++#define ANA_TABLES_SFIDTIDX_SFID_INDEX(x)                 ((x) & GENMASK(7, 0))
++#define ANA_TABLES_SFIDTIDX_SFID_INDEX_M                  GENMASK(7, 0)
++
++#define ANA_MSTI_STATE_RSZ                                0x4
++
++#define ANA_OAM_UPM_LM_CNT_RSZ                            0x4
++
++#define ANA_SG_ACCESS_CTRL_SGID(x)                        ((x) & GENMASK(7, 0))
++#define ANA_SG_ACCESS_CTRL_SGID_M                         GENMASK(7, 0)
++#define ANA_SG_ACCESS_CTRL_CONFIG_CHANGE                  BIT(28)
++
++#define ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB(x)          ((x) & GENMASK(15, 0))
++#define ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB_M           GENMASK(15, 0)
++#define ANA_SG_CONFIG_REG_3_LIST_LENGTH(x)                (((x) << 16) & GENMASK(18, 16))
++#define ANA_SG_CONFIG_REG_3_LIST_LENGTH_M                 GENMASK(18, 16)
++#define ANA_SG_CONFIG_REG_3_LIST_LENGTH_X(x)              (((x) & GENMASK(18, 16)) >> 16)
++#define ANA_SG_CONFIG_REG_3_GATE_ENABLE                   BIT(20)
++#define ANA_SG_CONFIG_REG_3_INIT_IPS(x)                   (((x) << 21) & GENMASK(24, 21))
++#define ANA_SG_CONFIG_REG_3_INIT_IPS_M                    GENMASK(24, 21)
++#define ANA_SG_CONFIG_REG_3_INIT_IPS_X(x)                 (((x) & GENMASK(24, 21)) >> 21)
++#define ANA_SG_CONFIG_REG_3_IPV_VALID                     BIT(24)
++#define ANA_SG_CONFIG_REG_3_IPV_INVALID(x)              (((x) << 24) & GENMASK(24, 24))
++#define ANA_SG_CONFIG_REG_3_INIT_IPV(x)                   (((x) << 21) & GENMASK(23, 21))
++#define ANA_SG_CONFIG_REG_3_INIT_IPV_M                    GENMASK(23, 21)
++#define ANA_SG_CONFIG_REG_3_INIT_IPV_X(x)                 (((x) & GENMASK(23, 21)) >> 21)
++#define ANA_SG_CONFIG_REG_3_INIT_GATE_STATE               BIT(25)
++
++#define ANA_SG_GCL_GS_CONFIG_RSZ                          0x4
++
++#define ANA_SG_GCL_GS_CONFIG_IPS(x)                       ((x) & GENMASK(3, 0))
++#define ANA_SG_GCL_GS_CONFIG_IPS_M                        GENMASK(3, 0)
++#define ANA_SG_GCL_GS_CONFIG_IPV_VALID                    BIT(3)
++#define ANA_SG_GCL_GS_CONFIG_IPV(x)                       ((x) & GENMASK(2, 0))
++#define ANA_SG_GCL_GS_CONFIG_IPV_M                        GENMASK(2, 0)
++#define ANA_SG_GCL_GS_CONFIG_GATE_STATE                   BIT(4)
++
++#define ANA_SG_GCL_TI_CONFIG_RSZ                          0x4
++
++#define ANA_SG_STATUS_REG_3_CFG_CHG_TIME_SEC_MSB(x)       ((x) & GENMASK(15, 0))
++#define ANA_SG_STATUS_REG_3_CFG_CHG_TIME_SEC_MSB_M        GENMASK(15, 0)
++#define ANA_SG_STATUS_REG_3_GATE_STATE                    BIT(16)
++#define ANA_SG_STATUS_REG_3_IPS(x)                        (((x) << 20) & GENMASK(23, 20))
++#define ANA_SG_STATUS_REG_3_IPS_M                         GENMASK(23, 20)
++#define ANA_SG_STATUS_REG_3_IPS_X(x)                      (((x) & GENMASK(23, 20)) >> 20)
++#define ANA_SG_STATUS_REG_3_IPV_VALID                     BIT(23)
++#define ANA_SG_STATUS_REG_3_IPV(x)                        (((x) << 20) & GENMASK(22, 20))
++#define ANA_SG_STATUS_REG_3_IPV_M                         GENMASK(22, 20)
++#define ANA_SG_STATUS_REG_3_IPV_X(x)                      (((x) & GENMASK(22, 20)) >> 20)
++#define ANA_SG_STATUS_REG_3_CONFIG_PENDING                BIT(24)
++
++#define ANA_PORT_VLAN_CFG_GSZ                             0x100
++
++#define ANA_PORT_VLAN_CFG_VLAN_VID_AS_ISDX                BIT(21)
++#define ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA                  BIT(20)
++#define ANA_PORT_VLAN_CFG_VLAN_POP_CNT(x)                 (((x) << 18) & GENMASK(19, 18))
++#define ANA_PORT_VLAN_CFG_VLAN_POP_CNT_M                  GENMASK(19, 18)
++#define ANA_PORT_VLAN_CFG_VLAN_POP_CNT_X(x)               (((x) & GENMASK(19, 18)) >> 18)
++#define ANA_PORT_VLAN_CFG_VLAN_INNER_TAG_ENA              BIT(17)
++#define ANA_PORT_VLAN_CFG_VLAN_TAG_TYPE                   BIT(16)
++#define ANA_PORT_VLAN_CFG_VLAN_DEI                        BIT(15)
++#define ANA_PORT_VLAN_CFG_VLAN_PCP(x)                     (((x) << 12) & GENMASK(14, 12))
++#define ANA_PORT_VLAN_CFG_VLAN_PCP_M                      GENMASK(14, 12)
++#define ANA_PORT_VLAN_CFG_VLAN_PCP_X(x)                   (((x) & GENMASK(14, 12)) >> 12)
++#define ANA_PORT_VLAN_CFG_VLAN_VID(x)                     ((x) & GENMASK(11, 0))
++#define ANA_PORT_VLAN_CFG_VLAN_VID_M                      GENMASK(11, 0)
++
++#define ANA_PORT_DROP_CFG_GSZ                             0x100
++
++#define ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA               BIT(6)
++#define ANA_PORT_DROP_CFG_DROP_S_TAGGED_ENA               BIT(5)
++#define ANA_PORT_DROP_CFG_DROP_C_TAGGED_ENA               BIT(4)
++#define ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA          BIT(3)
++#define ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA          BIT(2)
++#define ANA_PORT_DROP_CFG_DROP_NULL_MAC_ENA               BIT(1)
++#define ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA                BIT(0)
++
++#define ANA_PORT_QOS_CFG_GSZ                              0x100
++
++#define ANA_PORT_QOS_CFG_DP_DEFAULT_VAL                   BIT(8)
++#define ANA_PORT_QOS_CFG_QOS_DEFAULT_VAL(x)               (((x) << 5) & GENMASK(7, 5))
++#define ANA_PORT_QOS_CFG_QOS_DEFAULT_VAL_M                GENMASK(7, 5)
++#define ANA_PORT_QOS_CFG_QOS_DEFAULT_VAL_X(x)             (((x) & GENMASK(7, 5)) >> 5)
++#define ANA_PORT_QOS_CFG_QOS_DSCP_ENA                     BIT(4)
++#define ANA_PORT_QOS_CFG_QOS_PCP_ENA                      BIT(3)
++#define ANA_PORT_QOS_CFG_DSCP_TRANSLATE_ENA               BIT(2)
++#define ANA_PORT_QOS_CFG_DSCP_REWR_CFG(x)                 ((x) & GENMASK(1, 0))
++#define ANA_PORT_QOS_CFG_DSCP_REWR_CFG_M                  GENMASK(1, 0)
++
++#define ANA_PORT_VCAP_CFG_GSZ                             0x100
++
++#define ANA_PORT_VCAP_CFG_S1_ENA                          BIT(14)
++#define ANA_PORT_VCAP_CFG_S1_DMAC_DIP_ENA(x)              (((x) << 11) & GENMASK(13, 11))
++#define ANA_PORT_VCAP_CFG_S1_DMAC_DIP_ENA_M               GENMASK(13, 11)
++#define ANA_PORT_VCAP_CFG_S1_DMAC_DIP_ENA_X(x)            (((x) & GENMASK(13, 11)) >> 11)
++#define ANA_PORT_VCAP_CFG_S1_VLAN_INNER_TAG_ENA(x)        (((x) << 8) & GENMASK(10, 8))
++#define ANA_PORT_VCAP_CFG_S1_VLAN_INNER_TAG_ENA_M         GENMASK(10, 8)
++#define ANA_PORT_VCAP_CFG_S1_VLAN_INNER_TAG_ENA_X(x)      (((x) & GENMASK(10, 8)) >> 8)
++#define ANA_PORT_VCAP_CFG_PAG_VAL(x)                      ((x) & GENMASK(7, 0))
++#define ANA_PORT_VCAP_CFG_PAG_VAL_M                       GENMASK(7, 0)
++
++#define ANA_PORT_VCAP_S1_KEY_CFG_GSZ                      0x100
++#define ANA_PORT_VCAP_S1_KEY_CFG_RSZ                      0x4
++
++#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP6_CFG(x)        (((x) << 4) & GENMASK(6, 4))
++#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP6_CFG_M         GENMASK(6, 4)
++#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP6_CFG_X(x)      (((x) & GENMASK(6, 4)) >> 4)
++#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP4_CFG(x)        (((x) << 2) & GENMASK(3, 2))
++#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP4_CFG_M         GENMASK(3, 2)
++#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP4_CFG_X(x)      (((x) & GENMASK(3, 2)) >> 2)
++#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_OTHER_CFG(x)      ((x) & GENMASK(1, 0))
++#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_OTHER_CFG_M       GENMASK(1, 0)
++
++#define ANA_PORT_VCAP_S2_CFG_GSZ                          0x100
++
++#define ANA_PORT_VCAP_S2_CFG_S2_UDP_PAYLOAD_ENA(x)        (((x) << 17) & GENMASK(18, 17))
++#define ANA_PORT_VCAP_S2_CFG_S2_UDP_PAYLOAD_ENA_M         GENMASK(18, 17)
++#define ANA_PORT_VCAP_S2_CFG_S2_UDP_PAYLOAD_ENA_X(x)      (((x) & GENMASK(18, 17)) >> 17)
++#define ANA_PORT_VCAP_S2_CFG_S2_ETYPE_PAYLOAD_ENA(x)      (((x) << 15) & GENMASK(16, 15))
++#define ANA_PORT_VCAP_S2_CFG_S2_ETYPE_PAYLOAD_ENA_M       GENMASK(16, 15)
++#define ANA_PORT_VCAP_S2_CFG_S2_ETYPE_PAYLOAD_ENA_X(x)    (((x) & GENMASK(16, 15)) >> 15)
++#define ANA_PORT_VCAP_S2_CFG_S2_ENA                       BIT(14)
++#define ANA_PORT_VCAP_S2_CFG_S2_SNAP_DIS(x)               (((x) << 12) & GENMASK(13, 12))
++#define ANA_PORT_VCAP_S2_CFG_S2_SNAP_DIS_M                GENMASK(13, 12)
++#define ANA_PORT_VCAP_S2_CFG_S2_SNAP_DIS_X(x)             (((x) & GENMASK(13, 12)) >> 12)
++#define ANA_PORT_VCAP_S2_CFG_S2_ARP_DIS(x)                (((x) << 10) & GENMASK(11, 10))
++#define ANA_PORT_VCAP_S2_CFG_S2_ARP_DIS_M                 GENMASK(11, 10)
++#define ANA_PORT_VCAP_S2_CFG_S2_ARP_DIS_X(x)              (((x) & GENMASK(11, 10)) >> 10)
++#define ANA_PORT_VCAP_S2_CFG_S2_IP_TCPUDP_DIS(x)          (((x) << 8) & GENMASK(9, 8))
++#define ANA_PORT_VCAP_S2_CFG_S2_IP_TCPUDP_DIS_M           GENMASK(9, 8)
++#define ANA_PORT_VCAP_S2_CFG_S2_IP_TCPUDP_DIS_X(x)        (((x) & GENMASK(9, 8)) >> 8)
++#define ANA_PORT_VCAP_S2_CFG_S2_IP_OTHER_DIS(x)           (((x) << 6) & GENMASK(7, 6))
++#define ANA_PORT_VCAP_S2_CFG_S2_IP_OTHER_DIS_M            GENMASK(7, 6)
++#define ANA_PORT_VCAP_S2_CFG_S2_IP_OTHER_DIS_X(x)         (((x) & GENMASK(7, 6)) >> 6)
++#define ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG(x)                (((x) << 2) & GENMASK(5, 2))
++#define ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG_M                 GENMASK(5, 2)
++#define ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG_X(x)              (((x) & GENMASK(5, 2)) >> 2)
++#define ANA_PORT_VCAP_S2_CFG_S2_OAM_DIS(x)                ((x) & GENMASK(1, 0))
++#define ANA_PORT_VCAP_S2_CFG_S2_OAM_DIS_M                 GENMASK(1, 0)
++
++#define ANA_PORT_PCP_DEI_MAP_GSZ                          0x100
++#define ANA_PORT_PCP_DEI_MAP_RSZ                          0x4
++
++#define ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL               BIT(3)
++#define ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(x)           ((x) & GENMASK(2, 0))
++#define ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL_M            GENMASK(2, 0)
++
++#define ANA_PORT_CPU_FWD_CFG_GSZ                          0x100
++
++#define ANA_PORT_CPU_FWD_CFG_CPU_VRAP_REDIR_ENA           BIT(7)
++#define ANA_PORT_CPU_FWD_CFG_CPU_MLD_REDIR_ENA            BIT(6)
++#define ANA_PORT_CPU_FWD_CFG_CPU_IGMP_REDIR_ENA           BIT(5)
++#define ANA_PORT_CPU_FWD_CFG_CPU_IPMC_CTRL_COPY_ENA       BIT(4)
++#define ANA_PORT_CPU_FWD_CFG_CPU_SRC_COPY_ENA             BIT(3)
++#define ANA_PORT_CPU_FWD_CFG_CPU_ALLBRIDGE_DROP_ENA       BIT(2)
++#define ANA_PORT_CPU_FWD_CFG_CPU_ALLBRIDGE_REDIR_ENA      BIT(1)
++#define ANA_PORT_CPU_FWD_CFG_CPU_OAM_ENA                  BIT(0)
++
++#define ANA_PORT_CPU_FWD_BPDU_CFG_GSZ                     0x100
++
++#define ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA(x)        (((x) << 16) & GENMASK(31, 16))
++#define ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA_M         GENMASK(31, 16)
++#define ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA_X(x)      (((x) & GENMASK(31, 16)) >> 16)
++#define ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(x)       ((x) & GENMASK(15, 0))
++#define ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA_M        GENMASK(15, 0)
++
++#define ANA_PORT_CPU_FWD_GARP_CFG_GSZ                     0x100
++
++#define ANA_PORT_CPU_FWD_GARP_CFG_GARP_DROP_ENA(x)        (((x) << 16) & GENMASK(31, 16))
++#define ANA_PORT_CPU_FWD_GARP_CFG_GARP_DROP_ENA_M         GENMASK(31, 16)
++#define ANA_PORT_CPU_FWD_GARP_CFG_GARP_DROP_ENA_X(x)      (((x) & GENMASK(31, 16)) >> 16)
++#define ANA_PORT_CPU_FWD_GARP_CFG_GARP_REDIR_ENA(x)       ((x) & GENMASK(15, 0))
++#define ANA_PORT_CPU_FWD_GARP_CFG_GARP_REDIR_ENA_M        GENMASK(15, 0)
++
++#define ANA_PORT_CPU_FWD_CCM_CFG_GSZ                      0x100
++
++#define ANA_PORT_CPU_FWD_CCM_CFG_CCM_DROP_ENA(x)          (((x) << 16) & GENMASK(31, 16))
++#define ANA_PORT_CPU_FWD_CCM_CFG_CCM_DROP_ENA_M           GENMASK(31, 16)
++#define ANA_PORT_CPU_FWD_CCM_CFG_CCM_DROP_ENA_X(x)        (((x) & GENMASK(31, 16)) >> 16)
++#define ANA_PORT_CPU_FWD_CCM_CFG_CCM_REDIR_ENA(x)         ((x) & GENMASK(15, 0))
++#define ANA_PORT_CPU_FWD_CCM_CFG_CCM_REDIR_ENA_M          GENMASK(15, 0)
++
++#define ANA_PORT_PORT_CFG_GSZ                             0x100
++
++#define ANA_PORT_PORT_CFG_SRC_MIRROR_ENA                  BIT(15)
++#define ANA_PORT_PORT_CFG_LIMIT_DROP                      BIT(14)
++#define ANA_PORT_PORT_CFG_LIMIT_CPU                       BIT(13)
++#define ANA_PORT_PORT_CFG_LOCKED_PORTMOVE_DROP            BIT(12)
++#define ANA_PORT_PORT_CFG_LOCKED_PORTMOVE_CPU             BIT(11)
++#define ANA_PORT_PORT_CFG_LEARNDROP                       BIT(10)
++#define ANA_PORT_PORT_CFG_LEARNCPU                        BIT(9)
++#define ANA_PORT_PORT_CFG_LEARNAUTO                       BIT(8)
++#define ANA_PORT_PORT_CFG_LEARN_ENA                       BIT(7)
++#define ANA_PORT_PORT_CFG_RECV_ENA                        BIT(6)
++#define ANA_PORT_PORT_CFG_PORTID_VAL(x)                   (((x) << 2) & GENMASK(5, 2))
++#define ANA_PORT_PORT_CFG_PORTID_VAL_M                    GENMASK(5, 2)
++#define ANA_PORT_PORT_CFG_PORTID_VAL_X(x)                 (((x) & GENMASK(5, 2)) >> 2)
++#define ANA_PORT_PORT_CFG_USE_B_DOM_TBL                   BIT(1)
++#define ANA_PORT_PORT_CFG_LSR_MODE                        BIT(0)
++
++#define ANA_PORT_POL_CFG_GSZ                              0x100
++
++#define ANA_PORT_POL_CFG_POL_CPU_REDIR_8021               BIT(19)
++#define ANA_PORT_POL_CFG_POL_CPU_REDIR_IP                 BIT(18)
++#define ANA_PORT_POL_CFG_PORT_POL_ENA                     BIT(17)
++#define ANA_PORT_POL_CFG_QUEUE_POL_ENA(x)                 (((x) << 9) & GENMASK(16, 9))
++#define ANA_PORT_POL_CFG_QUEUE_POL_ENA_M                  GENMASK(16, 9)
++#define ANA_PORT_POL_CFG_QUEUE_POL_ENA_X(x)               (((x) & GENMASK(16, 9)) >> 9)
++#define ANA_PORT_POL_CFG_POL_ORDER(x)                     ((x) & GENMASK(8, 0))
++#define ANA_PORT_POL_CFG_POL_ORDER_M                      GENMASK(8, 0)
++
++#define ANA_PORT_PTP_CFG_GSZ                              0x100
++
++#define ANA_PORT_PTP_CFG_PTP_BACKPLANE_MODE               BIT(0)
++
++#define ANA_PORT_PTP_DLY1_CFG_GSZ                         0x100
++
++#define ANA_PORT_PTP_DLY2_CFG_GSZ                         0x100
++
++#define ANA_PORT_SFID_CFG_GSZ                             0x100
++#define ANA_PORT_SFID_CFG_RSZ                             0x4
++
++#define ANA_PORT_SFID_CFG_SFID_VALID                      BIT(8)
++#define ANA_PORT_SFID_CFG_SFID(x)                         ((x) & GENMASK(7, 0))
++#define ANA_PORT_SFID_CFG_SFID_M                          GENMASK(7, 0)
++
++#define ANA_PFC_PFC_CFG_GSZ                               0x40
++
++#define ANA_PFC_PFC_CFG_RX_PFC_ENA(x)                     (((x) << 2) & GENMASK(9, 2))
++#define ANA_PFC_PFC_CFG_RX_PFC_ENA_M                      GENMASK(9, 2)
++#define ANA_PFC_PFC_CFG_RX_PFC_ENA_X(x)                   (((x) & GENMASK(9, 2)) >> 2)
++#define ANA_PFC_PFC_CFG_FC_LINK_SPEED(x)                  ((x) & GENMASK(1, 0))
++#define ANA_PFC_PFC_CFG_FC_LINK_SPEED_M                   GENMASK(1, 0)
++
++#define ANA_PFC_PFC_TIMER_GSZ                             0x40
++#define ANA_PFC_PFC_TIMER_RSZ                             0x4
++
++#define ANA_IPT_OAM_MEP_CFG_GSZ                           0x8
++
++#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_P(x)                  (((x) << 6) & GENMASK(10, 6))
++#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_P_M                   GENMASK(10, 6)
++#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_P_X(x)                (((x) & GENMASK(10, 6)) >> 6)
++#define ANA_IPT_OAM_MEP_CFG_MEP_IDX(x)                    (((x) << 1) & GENMASK(5, 1))
++#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_M                     GENMASK(5, 1)
++#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_X(x)                  (((x) & GENMASK(5, 1)) >> 1)
++#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_ENA                   BIT(0)
++
++#define ANA_IPT_IPT_GSZ                                   0x8
++
++#define ANA_IPT_IPT_IPT_CFG(x)                            (((x) << 15) & GENMASK(16, 15))
++#define ANA_IPT_IPT_IPT_CFG_M                             GENMASK(16, 15)
++#define ANA_IPT_IPT_IPT_CFG_X(x)                          (((x) & GENMASK(16, 15)) >> 15)
++#define ANA_IPT_IPT_ISDX_P(x)                             (((x) << 7) & GENMASK(14, 7))
++#define ANA_IPT_IPT_ISDX_P_M                              GENMASK(14, 7)
++#define ANA_IPT_IPT_ISDX_P_X(x)                           (((x) & GENMASK(14, 7)) >> 7)
++#define ANA_IPT_IPT_PPT_IDX(x)                            ((x) & GENMASK(6, 0))
++#define ANA_IPT_IPT_PPT_IDX_M                             GENMASK(6, 0)
++
++#define ANA_PPT_PPT_RSZ                                   0x4
++
++#define ANA_FID_MAP_FID_MAP_RSZ                           0x4
++
++#define ANA_FID_MAP_FID_MAP_FID_C_VAL(x)                  (((x) << 6) & GENMASK(11, 6))
++#define ANA_FID_MAP_FID_MAP_FID_C_VAL_M                   GENMASK(11, 6)
++#define ANA_FID_MAP_FID_MAP_FID_C_VAL_X(x)                (((x) & GENMASK(11, 6)) >> 6)
++#define ANA_FID_MAP_FID_MAP_FID_B_VAL(x)                  ((x) & GENMASK(5, 0))
++#define ANA_FID_MAP_FID_MAP_FID_B_VAL_M                   GENMASK(5, 0)
++
++#define ANA_AGGR_CFG_AC_RND_ENA                           BIT(7)
++#define ANA_AGGR_CFG_AC_DMAC_ENA                          BIT(6)
++#define ANA_AGGR_CFG_AC_SMAC_ENA                          BIT(5)
++#define ANA_AGGR_CFG_AC_IP6_FLOW_LBL_ENA                  BIT(4)
++#define ANA_AGGR_CFG_AC_IP6_TCPUDP_ENA                    BIT(3)
++#define ANA_AGGR_CFG_AC_IP4_SIPDIP_ENA                    BIT(2)
++#define ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA                    BIT(1)
++#define ANA_AGGR_CFG_AC_ISDX_ENA                          BIT(0)
++
++#define ANA_CPUQ_CFG_CPUQ_MLD(x)                          (((x) << 27) & GENMASK(29, 27))
++#define ANA_CPUQ_CFG_CPUQ_MLD_M                           GENMASK(29, 27)
++#define ANA_CPUQ_CFG_CPUQ_MLD_X(x)                        (((x) & GENMASK(29, 27)) >> 27)
++#define ANA_CPUQ_CFG_CPUQ_IGMP(x)                         (((x) << 24) & GENMASK(26, 24))
++#define ANA_CPUQ_CFG_CPUQ_IGMP_M                          GENMASK(26, 24)
++#define ANA_CPUQ_CFG_CPUQ_IGMP_X(x)                       (((x) & GENMASK(26, 24)) >> 24)
++#define ANA_CPUQ_CFG_CPUQ_IPMC_CTRL(x)                    (((x) << 21) & GENMASK(23, 21))
++#define ANA_CPUQ_CFG_CPUQ_IPMC_CTRL_M                     GENMASK(23, 21)
++#define ANA_CPUQ_CFG_CPUQ_IPMC_CTRL_X(x)                  (((x) & GENMASK(23, 21)) >> 21)
++#define ANA_CPUQ_CFG_CPUQ_ALLBRIDGE(x)                    (((x) << 18) & GENMASK(20, 18))
++#define ANA_CPUQ_CFG_CPUQ_ALLBRIDGE_M                     GENMASK(20, 18)
++#define ANA_CPUQ_CFG_CPUQ_ALLBRIDGE_X(x)                  (((x) & GENMASK(20, 18)) >> 18)
++#define ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE(x)              (((x) << 15) & GENMASK(17, 15))
++#define ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE_M               GENMASK(17, 15)
++#define ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE_X(x)            (((x) & GENMASK(17, 15)) >> 15)
++#define ANA_CPUQ_CFG_CPUQ_SRC_COPY(x)                     (((x) << 12) & GENMASK(14, 12))
++#define ANA_CPUQ_CFG_CPUQ_SRC_COPY_M                      GENMASK(14, 12)
++#define ANA_CPUQ_CFG_CPUQ_SRC_COPY_X(x)                   (((x) & GENMASK(14, 12)) >> 12)
++#define ANA_CPUQ_CFG_CPUQ_MAC_COPY(x)                     (((x) << 9) & GENMASK(11, 9))
++#define ANA_CPUQ_CFG_CPUQ_MAC_COPY_M                      GENMASK(11, 9)
++#define ANA_CPUQ_CFG_CPUQ_MAC_COPY_X(x)                   (((x) & GENMASK(11, 9)) >> 9)
++#define ANA_CPUQ_CFG_CPUQ_LRN(x)                          (((x) << 6) & GENMASK(8, 6))
++#define ANA_CPUQ_CFG_CPUQ_LRN_M                           GENMASK(8, 6)
++#define ANA_CPUQ_CFG_CPUQ_LRN_X(x)                        (((x) & GENMASK(8, 6)) >> 6)
++#define ANA_CPUQ_CFG_CPUQ_MIRROR(x)                       (((x) << 3) & GENMASK(5, 3))
++#define ANA_CPUQ_CFG_CPUQ_MIRROR_M                        GENMASK(5, 3)
++#define ANA_CPUQ_CFG_CPUQ_MIRROR_X(x)                     (((x) & GENMASK(5, 3)) >> 3)
++#define ANA_CPUQ_CFG_CPUQ_SFLOW(x)                        ((x) & GENMASK(2, 0))
++#define ANA_CPUQ_CFG_CPUQ_SFLOW_M                         GENMASK(2, 0)
++
++#define ANA_CPUQ_8021_CFG_RSZ                             0x4
++
++#define ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL(x)                (((x) << 6) & GENMASK(8, 6))
++#define ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL_M                 GENMASK(8, 6)
++#define ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL_X(x)              (((x) & GENMASK(8, 6)) >> 6)
++#define ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL(x)                (((x) << 3) & GENMASK(5, 3))
++#define ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL_M                 GENMASK(5, 3)
++#define ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL_X(x)              (((x) & GENMASK(5, 3)) >> 3)
++#define ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL(x)                 ((x) & GENMASK(2, 0))
++#define ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL_M                  GENMASK(2, 0)
++
++#define ANA_DSCP_CFG_RSZ                                  0x4
++
++#define ANA_DSCP_CFG_DP_DSCP_VAL                          BIT(11)
++#define ANA_DSCP_CFG_QOS_DSCP_VAL(x)                      (((x) << 8) & GENMASK(10, 8))
++#define ANA_DSCP_CFG_QOS_DSCP_VAL_M                       GENMASK(10, 8)
++#define ANA_DSCP_CFG_QOS_DSCP_VAL_X(x)                    (((x) & GENMASK(10, 8)) >> 8)
++#define ANA_DSCP_CFG_DSCP_TRANSLATE_VAL(x)                (((x) << 2) & GENMASK(7, 2))
++#define ANA_DSCP_CFG_DSCP_TRANSLATE_VAL_M                 GENMASK(7, 2)
++#define ANA_DSCP_CFG_DSCP_TRANSLATE_VAL_X(x)              (((x) & GENMASK(7, 2)) >> 2)
++#define ANA_DSCP_CFG_DSCP_TRUST_ENA                       BIT(1)
++#define ANA_DSCP_CFG_DSCP_REWR_ENA                        BIT(0)
++
++#define ANA_DSCP_REWR_CFG_RSZ                             0x4
++
++#define ANA_VCAP_RNG_TYPE_CFG_RSZ                         0x4
++
++#define ANA_VCAP_RNG_VAL_CFG_RSZ                          0x4
++
++#define ANA_VCAP_RNG_VAL_CFG_VCAP_RNG_MIN_VAL(x)          (((x) << 16) & GENMASK(31, 16))
++#define ANA_VCAP_RNG_VAL_CFG_VCAP_RNG_MIN_VAL_M           GENMASK(31, 16)
++#define ANA_VCAP_RNG_VAL_CFG_VCAP_RNG_MIN_VAL_X(x)        (((x) & GENMASK(31, 16)) >> 16)
++#define ANA_VCAP_RNG_VAL_CFG_VCAP_RNG_MAX_VAL(x)          ((x) & GENMASK(15, 0))
++#define ANA_VCAP_RNG_VAL_CFG_VCAP_RNG_MAX_VAL_M           GENMASK(15, 0)
++
++#define ANA_VRAP_CFG_VRAP_VLAN_AWARE_ENA                  BIT(12)
++#define ANA_VRAP_CFG_VRAP_VID(x)                          ((x) & GENMASK(11, 0))
++#define ANA_VRAP_CFG_VRAP_VID_M                           GENMASK(11, 0)
++
++#define ANA_DISCARD_CFG_DROP_TAGGING_ISDX0                BIT(3)
++#define ANA_DISCARD_CFG_DROP_CTRLPROT_ISDX0               BIT(2)
++#define ANA_DISCARD_CFG_DROP_TAGGING_S2_ENA               BIT(1)
++#define ANA_DISCARD_CFG_DROP_CTRLPROT_S2_ENA              BIT(0)
++
++#define ANA_FID_CFG_VID_MC_ENA                            BIT(0)
++
++#define ANA_POL_PIR_CFG_GSZ                               0x20
++
++#define ANA_POL_PIR_CFG_PIR_RATE(x)                       (((x) << 6) & GENMASK(20, 6))
++#define ANA_POL_PIR_CFG_PIR_RATE_M                        GENMASK(20, 6)
++#define ANA_POL_PIR_CFG_PIR_RATE_X(x)                     (((x) & GENMASK(20, 6)) >> 6)
++#define ANA_POL_PIR_CFG_PIR_BURST(x)                      ((x) & GENMASK(5, 0))
++#define ANA_POL_PIR_CFG_PIR_BURST_M                       GENMASK(5, 0)
++
++#define ANA_POL_CIR_CFG_GSZ                               0x20
++
++#define ANA_POL_CIR_CFG_CIR_RATE(x)                       (((x) << 6) & GENMASK(20, 6))
++#define ANA_POL_CIR_CFG_CIR_RATE_M                        GENMASK(20, 6)
++#define ANA_POL_CIR_CFG_CIR_RATE_X(x)                     (((x) & GENMASK(20, 6)) >> 6)
++#define ANA_POL_CIR_CFG_CIR_BURST(x)                      ((x) & GENMASK(5, 0))
++#define ANA_POL_CIR_CFG_CIR_BURST_M                       GENMASK(5, 0)
++
++#define ANA_POL_MODE_CFG_GSZ                              0x20
++
++#define ANA_POL_MODE_CFG_IPG_SIZE(x)                      (((x) << 5) & GENMASK(9, 5))
++#define ANA_POL_MODE_CFG_IPG_SIZE_M                       GENMASK(9, 5)
++#define ANA_POL_MODE_CFG_IPG_SIZE_X(x)                    (((x) & GENMASK(9, 5)) >> 5)
++#define ANA_POL_MODE_CFG_FRM_MODE(x)                      (((x) << 3) & GENMASK(4, 3))
++#define ANA_POL_MODE_CFG_FRM_MODE_M                       GENMASK(4, 3)
++#define ANA_POL_MODE_CFG_FRM_MODE_X(x)                    (((x) & GENMASK(4, 3)) >> 3)
++#define ANA_POL_MODE_CFG_DLB_COUPLED                      BIT(2)
++#define ANA_POL_MODE_CFG_CIR_ENA                          BIT(1)
++#define ANA_POL_MODE_CFG_OVERSHOOT_ENA                    BIT(0)
++
++#define ANA_POL_PIR_STATE_GSZ                             0x20
++
++#define ANA_POL_CIR_STATE_GSZ                             0x20
++
++#define ANA_POL_STATE_GSZ                                 0x20
++
++#define ANA_POL_FLOWC_RSZ                                 0x4
++
++#define ANA_POL_FLOWC_POL_FLOWC                           BIT(0)
++
++#define ANA_POL_HYST_POL_FC_HYST(x)                       (((x) << 4) & GENMASK(9, 4))
++#define ANA_POL_HYST_POL_FC_HYST_M                        GENMASK(9, 4)
++#define ANA_POL_HYST_POL_FC_HYST_X(x)                     (((x) & GENMASK(9, 4)) >> 4)
++#define ANA_POL_HYST_POL_STOP_HYST(x)                     ((x) & GENMASK(3, 0))
++#define ANA_POL_HYST_POL_STOP_HYST_M                      GENMASK(3, 0)
++
++#define ANA_POL_MISC_CFG_POL_CLOSE_ALL                    BIT(1)
++#define ANA_POL_MISC_CFG_POL_LEAK_DIS                     BIT(0)
++
++#endif
+--- /dev/null
++++ b/include/soc/mscc/ocelot_dev.h
+@@ -0,0 +1,275 @@
++/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
++/*
++ * Microsemi Ocelot Switch driver
++ *
++ * Copyright (c) 2017 Microsemi Corporation
++ */
++
++#ifndef _MSCC_OCELOT_DEV_H_
++#define _MSCC_OCELOT_DEV_H_
++
++#define DEV_CLOCK_CFG                                     0x0
++
++#define DEV_CLOCK_CFG_MAC_TX_RST                          BIT(7)
++#define DEV_CLOCK_CFG_MAC_RX_RST                          BIT(6)
++#define DEV_CLOCK_CFG_PCS_TX_RST                          BIT(5)
++#define DEV_CLOCK_CFG_PCS_RX_RST                          BIT(4)
++#define DEV_CLOCK_CFG_PORT_RST                            BIT(3)
++#define DEV_CLOCK_CFG_PHY_RST                             BIT(2)
++#define DEV_CLOCK_CFG_LINK_SPEED(x)                       ((x) & GENMASK(1, 0))
++#define DEV_CLOCK_CFG_LINK_SPEED_M                        GENMASK(1, 0)
++
++#define DEV_PORT_MISC                                     0x4
++
++#define DEV_PORT_MISC_FWD_ERROR_ENA                       BIT(4)
++#define DEV_PORT_MISC_FWD_PAUSE_ENA                       BIT(3)
++#define DEV_PORT_MISC_FWD_CTRL_ENA                        BIT(2)
++#define DEV_PORT_MISC_DEV_LOOP_ENA                        BIT(1)
++#define DEV_PORT_MISC_HDX_FAST_DIS                        BIT(0)
++
++#define DEV_EVENTS                                        0x8
++
++#define DEV_EEE_CFG                                       0xc
++
++#define DEV_EEE_CFG_EEE_ENA                               BIT(22)
++#define DEV_EEE_CFG_EEE_TIMER_AGE(x)                      (((x) << 15) & GENMASK(21, 15))
++#define DEV_EEE_CFG_EEE_TIMER_AGE_M                       GENMASK(21, 15)
++#define DEV_EEE_CFG_EEE_TIMER_AGE_X(x)                    (((x) & GENMASK(21, 15)) >> 15)
++#define DEV_EEE_CFG_EEE_TIMER_WAKEUP(x)                   (((x) << 8) & GENMASK(14, 8))
++#define DEV_EEE_CFG_EEE_TIMER_WAKEUP_M                    GENMASK(14, 8)
++#define DEV_EEE_CFG_EEE_TIMER_WAKEUP_X(x)                 (((x) & GENMASK(14, 8)) >> 8)
++#define DEV_EEE_CFG_EEE_TIMER_HOLDOFF(x)                  (((x) << 1) & GENMASK(7, 1))
++#define DEV_EEE_CFG_EEE_TIMER_HOLDOFF_M                   GENMASK(7, 1)
++#define DEV_EEE_CFG_EEE_TIMER_HOLDOFF_X(x)                (((x) & GENMASK(7, 1)) >> 1)
++#define DEV_EEE_CFG_PORT_LPI                              BIT(0)
++
++#define DEV_RX_PATH_DELAY                                 0x10
++
++#define DEV_TX_PATH_DELAY                                 0x14
++
++#define DEV_PTP_PREDICT_CFG                               0x18
++
++#define DEV_PTP_PREDICT_CFG_PTP_PHY_PREDICT_CFG(x)        (((x) << 4) & GENMASK(11, 4))
++#define DEV_PTP_PREDICT_CFG_PTP_PHY_PREDICT_CFG_M         GENMASK(11, 4)
++#define DEV_PTP_PREDICT_CFG_PTP_PHY_PREDICT_CFG_X(x)      (((x) & GENMASK(11, 4)) >> 4)
++#define DEV_PTP_PREDICT_CFG_PTP_PHASE_PREDICT_CFG(x)      ((x) & GENMASK(3, 0))
++#define DEV_PTP_PREDICT_CFG_PTP_PHASE_PREDICT_CFG_M       GENMASK(3, 0)
++
++#define DEV_MAC_ENA_CFG                                   0x1c
++
++#define DEV_MAC_ENA_CFG_RX_ENA                            BIT(4)
++#define DEV_MAC_ENA_CFG_TX_ENA                            BIT(0)
++
++#define DEV_MAC_MODE_CFG                                  0x20
++
++#define DEV_MAC_MODE_CFG_FC_WORD_SYNC_ENA                 BIT(8)
++#define DEV_MAC_MODE_CFG_GIGA_MODE_ENA                    BIT(4)
++#define DEV_MAC_MODE_CFG_FDX_ENA                          BIT(0)
++
++#define DEV_MAC_MAXLEN_CFG                                0x24
++
++#define DEV_MAC_TAGS_CFG                                  0x28
++
++#define DEV_MAC_TAGS_CFG_TAG_ID(x)                        (((x) << 16) & GENMASK(31, 16))
++#define DEV_MAC_TAGS_CFG_TAG_ID_M                         GENMASK(31, 16)
++#define DEV_MAC_TAGS_CFG_TAG_ID_X(x)                      (((x) & GENMASK(31, 16)) >> 16)
++#define DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA                 BIT(2)
++#define DEV_MAC_TAGS_CFG_PB_ENA                           BIT(1)
++#define DEV_MAC_TAGS_CFG_VLAN_AWR_ENA                     BIT(0)
++
++#define DEV_MAC_ADV_CHK_CFG                               0x2c
++
++#define DEV_MAC_ADV_CHK_CFG_LEN_DROP_ENA                  BIT(0)
++
++#define DEV_MAC_IFG_CFG                                   0x30
++
++#define DEV_MAC_IFG_CFG_RESTORE_OLD_IPG_CHECK             BIT(17)
++#define DEV_MAC_IFG_CFG_REDUCED_TX_IFG                    BIT(16)
++#define DEV_MAC_IFG_CFG_TX_IFG(x)                         (((x) << 8) & GENMASK(12, 8))
++#define DEV_MAC_IFG_CFG_TX_IFG_M                          GENMASK(12, 8)
++#define DEV_MAC_IFG_CFG_TX_IFG_X(x)                       (((x) & GENMASK(12, 8)) >> 8)
++#define DEV_MAC_IFG_CFG_RX_IFG2(x)                        (((x) << 4) & GENMASK(7, 4))
++#define DEV_MAC_IFG_CFG_RX_IFG2_M                         GENMASK(7, 4)
++#define DEV_MAC_IFG_CFG_RX_IFG2_X(x)                      (((x) & GENMASK(7, 4)) >> 4)
++#define DEV_MAC_IFG_CFG_RX_IFG1(x)                        ((x) & GENMASK(3, 0))
++#define DEV_MAC_IFG_CFG_RX_IFG1_M                         GENMASK(3, 0)
++
++#define DEV_MAC_HDX_CFG                                   0x34
++
++#define DEV_MAC_HDX_CFG_BYPASS_COL_SYNC                   BIT(26)
++#define DEV_MAC_HDX_CFG_OB_ENA                            BIT(25)
++#define DEV_MAC_HDX_CFG_WEXC_DIS                          BIT(24)
++#define DEV_MAC_HDX_CFG_SEED(x)                           (((x) << 16) & GENMASK(23, 16))
++#define DEV_MAC_HDX_CFG_SEED_M                            GENMASK(23, 16)
++#define DEV_MAC_HDX_CFG_SEED_X(x)                         (((x) & GENMASK(23, 16)) >> 16)
++#define DEV_MAC_HDX_CFG_SEED_LOAD                         BIT(12)
++#define DEV_MAC_HDX_CFG_RETRY_AFTER_EXC_COL_ENA           BIT(8)
++#define DEV_MAC_HDX_CFG_LATE_COL_POS(x)                   ((x) & GENMASK(6, 0))
++#define DEV_MAC_HDX_CFG_LATE_COL_POS_M                    GENMASK(6, 0)
++
++#define DEV_MAC_DBG_CFG                                   0x38
++
++#define DEV_MAC_DBG_CFG_TBI_MODE                          BIT(4)
++#define DEV_MAC_DBG_CFG_IFG_CRS_EXT_CHK_ENA               BIT(0)
++
++#define DEV_MAC_FC_MAC_LOW_CFG                            0x3c
++
++#define DEV_MAC_FC_MAC_HIGH_CFG                           0x40
++
++#define DEV_MAC_STICKY                                    0x44
++
++#define DEV_MAC_STICKY_RX_IPG_SHRINK_STICKY               BIT(9)
++#define DEV_MAC_STICKY_RX_PREAM_SHRINK_STICKY             BIT(8)
++#define DEV_MAC_STICKY_RX_CARRIER_EXT_STICKY              BIT(7)
++#define DEV_MAC_STICKY_RX_CARRIER_EXT_ERR_STICKY          BIT(6)
++#define DEV_MAC_STICKY_RX_JUNK_STICKY                     BIT(5)
++#define DEV_MAC_STICKY_TX_RETRANSMIT_STICKY               BIT(4)
++#define DEV_MAC_STICKY_TX_JAM_STICKY                      BIT(3)
++#define DEV_MAC_STICKY_TX_FIFO_OFLW_STICKY                BIT(2)
++#define DEV_MAC_STICKY_TX_FRM_LEN_OVR_STICKY              BIT(1)
++#define DEV_MAC_STICKY_TX_ABORT_STICKY                    BIT(0)
++
++#define PCS1G_CFG                                         0x48
++
++#define PCS1G_CFG_LINK_STATUS_TYPE                        BIT(4)
++#define PCS1G_CFG_AN_LINK_CTRL_ENA                        BIT(1)
++#define PCS1G_CFG_PCS_ENA                                 BIT(0)
++
++#define PCS1G_MODE_CFG                                    0x4c
++
++#define PCS1G_MODE_CFG_UNIDIR_MODE_ENA                    BIT(4)
++#define PCS1G_MODE_CFG_SGMII_MODE_ENA                     BIT(0)
++
++#define PCS1G_SD_CFG                                      0x50
++
++#define PCS1G_SD_CFG_SD_SEL                               BIT(8)
++#define PCS1G_SD_CFG_SD_POL                               BIT(4)
++#define PCS1G_SD_CFG_SD_ENA                               BIT(0)
++
++#define PCS1G_ANEG_CFG                                    0x54
++
++#define PCS1G_ANEG_CFG_ADV_ABILITY(x)                     (((x) << 16) & GENMASK(31, 16))
++#define PCS1G_ANEG_CFG_ADV_ABILITY_M                      GENMASK(31, 16)
++#define PCS1G_ANEG_CFG_ADV_ABILITY_X(x)                   (((x) & GENMASK(31, 16)) >> 16)
++#define PCS1G_ANEG_CFG_SW_RESOLVE_ENA                     BIT(8)
++#define PCS1G_ANEG_CFG_ANEG_RESTART_ONE_SHOT              BIT(1)
++#define PCS1G_ANEG_CFG_ANEG_ENA                           BIT(0)
++
++#define PCS1G_ANEG_NP_CFG                                 0x58
++
++#define PCS1G_ANEG_NP_CFG_NP_TX(x)                        (((x) << 16) & GENMASK(31, 16))
++#define PCS1G_ANEG_NP_CFG_NP_TX_M                         GENMASK(31, 16)
++#define PCS1G_ANEG_NP_CFG_NP_TX_X(x)                      (((x) & GENMASK(31, 16)) >> 16)
++#define PCS1G_ANEG_NP_CFG_NP_LOADED_ONE_SHOT              BIT(0)
++
++#define PCS1G_LB_CFG                                      0x5c
++
++#define PCS1G_LB_CFG_RA_ENA                               BIT(4)
++#define PCS1G_LB_CFG_GMII_PHY_LB_ENA                      BIT(1)
++#define PCS1G_LB_CFG_TBI_HOST_LB_ENA                      BIT(0)
++
++#define PCS1G_DBG_CFG                                     0x60
++
++#define PCS1G_DBG_CFG_UDLT                                BIT(0)
++
++#define PCS1G_CDET_CFG                                    0x64
++
++#define PCS1G_CDET_CFG_CDET_ENA                           BIT(0)
++
++#define PCS1G_ANEG_STATUS                                 0x68
++
++#define PCS1G_ANEG_STATUS_LP_ADV_ABILITY(x)               (((x) << 16) & GENMASK(31, 16))
++#define PCS1G_ANEG_STATUS_LP_ADV_ABILITY_M                GENMASK(31, 16)
++#define PCS1G_ANEG_STATUS_LP_ADV_ABILITY_X(x)             (((x) & GENMASK(31, 16)) >> 16)
++#define PCS1G_ANEG_STATUS_PR                              BIT(4)
++#define PCS1G_ANEG_STATUS_PAGE_RX_STICKY                  BIT(3)
++#define PCS1G_ANEG_STATUS_ANEG_COMPLETE                   BIT(0)
++
++#define PCS1G_ANEG_NP_STATUS                              0x6c
++
++#define PCS1G_LINK_STATUS                                 0x70
++
++#define PCS1G_LINK_STATUS_DELAY_VAR(x)                    (((x) << 12) & GENMASK(15, 12))
++#define PCS1G_LINK_STATUS_DELAY_VAR_M                     GENMASK(15, 12)
++#define PCS1G_LINK_STATUS_DELAY_VAR_X(x)                  (((x) & GENMASK(15, 12)) >> 12)
++#define PCS1G_LINK_STATUS_SIGNAL_DETECT                   BIT(8)
++#define PCS1G_LINK_STATUS_LINK_STATUS                     BIT(4)
++#define PCS1G_LINK_STATUS_SYNC_STATUS                     BIT(0)
++
++#define PCS1G_LINK_DOWN_CNT                               0x74
++
++#define PCS1G_STICKY                                      0x78
++
++#define PCS1G_STICKY_LINK_DOWN_STICKY                     BIT(4)
++#define PCS1G_STICKY_OUT_OF_SYNC_STICKY                   BIT(0)
++
++#define PCS1G_DEBUG_STATUS                                0x7c
++
++#define PCS1G_LPI_CFG                                     0x80
++
++#define PCS1G_LPI_CFG_QSGMII_MS_SEL                       BIT(20)
++#define PCS1G_LPI_CFG_RX_LPI_OUT_DIS                      BIT(17)
++#define PCS1G_LPI_CFG_LPI_TESTMODE                        BIT(16)
++#define PCS1G_LPI_CFG_LPI_RX_WTIM(x)                      (((x) << 4) & GENMASK(5, 4))
++#define PCS1G_LPI_CFG_LPI_RX_WTIM_M                       GENMASK(5, 4)
++#define PCS1G_LPI_CFG_LPI_RX_WTIM_X(x)                    (((x) & GENMASK(5, 4)) >> 4)
++#define PCS1G_LPI_CFG_TX_ASSERT_LPIDLE                    BIT(0)
++
++#define PCS1G_LPI_WAKE_ERROR_CNT                          0x84
++
++#define PCS1G_LPI_STATUS                                  0x88
++
++#define PCS1G_LPI_STATUS_RX_LPI_FAIL                      BIT(16)
++#define PCS1G_LPI_STATUS_RX_LPI_EVENT_STICKY              BIT(12)
++#define PCS1G_LPI_STATUS_RX_QUIET                         BIT(9)
++#define PCS1G_LPI_STATUS_RX_LPI_MODE                      BIT(8)
++#define PCS1G_LPI_STATUS_TX_LPI_EVENT_STICKY              BIT(4)
++#define PCS1G_LPI_STATUS_TX_QUIET                         BIT(1)
++#define PCS1G_LPI_STATUS_TX_LPI_MODE                      BIT(0)
++
++#define PCS1G_TSTPAT_MODE_CFG                             0x8c
++
++#define PCS1G_TSTPAT_STATUS                               0x90
++
++#define PCS1G_TSTPAT_STATUS_JTP_ERR_CNT(x)                (((x) << 8) & GENMASK(15, 8))
++#define PCS1G_TSTPAT_STATUS_JTP_ERR_CNT_M                 GENMASK(15, 8)
++#define PCS1G_TSTPAT_STATUS_JTP_ERR_CNT_X(x)              (((x) & GENMASK(15, 8)) >> 8)
++#define PCS1G_TSTPAT_STATUS_JTP_ERR                       BIT(4)
++#define PCS1G_TSTPAT_STATUS_JTP_LOCK                      BIT(0)
++
++#define DEV_PCS_FX100_CFG                                 0x94
++
++#define DEV_PCS_FX100_CFG_SD_SEL                          BIT(26)
++#define DEV_PCS_FX100_CFG_SD_POL                          BIT(25)
++#define DEV_PCS_FX100_CFG_SD_ENA                          BIT(24)
++#define DEV_PCS_FX100_CFG_LOOPBACK_ENA                    BIT(20)
++#define DEV_PCS_FX100_CFG_SWAP_MII_ENA                    BIT(16)
++#define DEV_PCS_FX100_CFG_RXBITSEL(x)                     (((x) << 12) & GENMASK(15, 12))
++#define DEV_PCS_FX100_CFG_RXBITSEL_M                      GENMASK(15, 12)
++#define DEV_PCS_FX100_CFG_RXBITSEL_X(x)                   (((x) & GENMASK(15, 12)) >> 12)
++#define DEV_PCS_FX100_CFG_SIGDET_CFG(x)                   (((x) << 9) & GENMASK(10, 9))
++#define DEV_PCS_FX100_CFG_SIGDET_CFG_M                    GENMASK(10, 9)
++#define DEV_PCS_FX100_CFG_SIGDET_CFG_X(x)                 (((x) & GENMASK(10, 9)) >> 9)
++#define DEV_PCS_FX100_CFG_LINKHYST_TM_ENA                 BIT(8)
++#define DEV_PCS_FX100_CFG_LINKHYSTTIMER(x)                (((x) << 4) & GENMASK(7, 4))
++#define DEV_PCS_FX100_CFG_LINKHYSTTIMER_M                 GENMASK(7, 4)
++#define DEV_PCS_FX100_CFG_LINKHYSTTIMER_X(x)              (((x) & GENMASK(7, 4)) >> 4)
++#define DEV_PCS_FX100_CFG_UNIDIR_MODE_ENA                 BIT(3)
++#define DEV_PCS_FX100_CFG_FEFCHK_ENA                      BIT(2)
++#define DEV_PCS_FX100_CFG_FEFGEN_ENA                      BIT(1)
++#define DEV_PCS_FX100_CFG_PCS_ENA                         BIT(0)
++
++#define DEV_PCS_FX100_STATUS                              0x98
++
++#define DEV_PCS_FX100_STATUS_EDGE_POS_PTP(x)              (((x) << 8) & GENMASK(11, 8))
++#define DEV_PCS_FX100_STATUS_EDGE_POS_PTP_M               GENMASK(11, 8)
++#define DEV_PCS_FX100_STATUS_EDGE_POS_PTP_X(x)            (((x) & GENMASK(11, 8)) >> 8)
++#define DEV_PCS_FX100_STATUS_PCS_ERROR_STICKY             BIT(7)
++#define DEV_PCS_FX100_STATUS_FEF_FOUND_STICKY             BIT(6)
++#define DEV_PCS_FX100_STATUS_SSD_ERROR_STICKY             BIT(5)
++#define DEV_PCS_FX100_STATUS_SYNC_LOST_STICKY             BIT(4)
++#define DEV_PCS_FX100_STATUS_FEF_STATUS                   BIT(2)
++#define DEV_PCS_FX100_STATUS_SIGNAL_DETECT                BIT(1)
++#define DEV_PCS_FX100_STATUS_SYNC_STATUS                  BIT(0)
++
++#endif
+--- /dev/null
++++ b/include/soc/mscc/ocelot_qsys.h
+@@ -0,0 +1,270 @@
++/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
++/*
++ * Microsemi Ocelot Switch driver
++ *
++ * Copyright (c) 2017 Microsemi Corporation
++ */
++
++#ifndef _MSCC_OCELOT_QSYS_H_
++#define _MSCC_OCELOT_QSYS_H_
++
++#define QSYS_PORT_MODE_RSZ                                0x4
++
++#define QSYS_PORT_MODE_DEQUEUE_DIS                        BIT(1)
++#define QSYS_PORT_MODE_DEQUEUE_LATE                       BIT(0)
++
++#define QSYS_SWITCH_PORT_MODE_RSZ                         0x4
++
++#define QSYS_SWITCH_PORT_MODE_PORT_ENA                    BIT(14)
++#define QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(x)             (((x) << 11) & GENMASK(13, 11))
++#define QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG_M              GENMASK(13, 11)
++#define QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG_X(x)           (((x) & GENMASK(13, 11)) >> 11)
++#define QSYS_SWITCH_PORT_MODE_YEL_RSRVD                   BIT(10)
++#define QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE           BIT(9)
++#define QSYS_SWITCH_PORT_MODE_TX_PFC_ENA(x)               (((x) << 1) & GENMASK(8, 1))
++#define QSYS_SWITCH_PORT_MODE_TX_PFC_ENA_M                GENMASK(8, 1)
++#define QSYS_SWITCH_PORT_MODE_TX_PFC_ENA_X(x)             (((x) & GENMASK(8, 1)) >> 1)
++#define QSYS_SWITCH_PORT_MODE_TX_PFC_MODE                 BIT(0)
++
++#define QSYS_STAT_CNT_CFG_TX_GREEN_CNT_MODE               BIT(5)
++#define QSYS_STAT_CNT_CFG_TX_YELLOW_CNT_MODE              BIT(4)
++#define QSYS_STAT_CNT_CFG_DROP_GREEN_CNT_MODE             BIT(3)
++#define QSYS_STAT_CNT_CFG_DROP_YELLOW_CNT_MODE            BIT(2)
++#define QSYS_STAT_CNT_CFG_DROP_COUNT_ONCE                 BIT(1)
++#define QSYS_STAT_CNT_CFG_DROP_COUNT_EGRESS               BIT(0)
++
++#define QSYS_EEE_CFG_RSZ                                  0x4
++
++#define QSYS_EEE_THRES_EEE_HIGH_BYTES(x)                  (((x) << 8) & GENMASK(15, 8))
++#define QSYS_EEE_THRES_EEE_HIGH_BYTES_M                   GENMASK(15, 8)
++#define QSYS_EEE_THRES_EEE_HIGH_BYTES_X(x)                (((x) & GENMASK(15, 8)) >> 8)
++#define QSYS_EEE_THRES_EEE_HIGH_FRAMES(x)                 ((x) & GENMASK(7, 0))
++#define QSYS_EEE_THRES_EEE_HIGH_FRAMES_M                  GENMASK(7, 0)
++
++#define QSYS_SW_STATUS_RSZ                                0x4
++
++#define QSYS_EXT_CPU_CFG_EXT_CPU_PORT(x)                  (((x) << 8) & GENMASK(12, 8))
++#define QSYS_EXT_CPU_CFG_EXT_CPU_PORT_M                   GENMASK(12, 8)
++#define QSYS_EXT_CPU_CFG_EXT_CPU_PORT_X(x)                (((x) & GENMASK(12, 8)) >> 8)
++#define QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK(x)                  ((x) & GENMASK(7, 0))
++#define QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M                   GENMASK(7, 0)
++
++#define QSYS_QMAP_GSZ                                     0x4
++
++#define QSYS_QMAP_SE_BASE(x)                              (((x) << 5) & GENMASK(12, 5))
++#define QSYS_QMAP_SE_BASE_M                               GENMASK(12, 5)
++#define QSYS_QMAP_SE_BASE_X(x)                            (((x) & GENMASK(12, 5)) >> 5)
++#define QSYS_QMAP_SE_IDX_SEL(x)                           (((x) << 2) & GENMASK(4, 2))
++#define QSYS_QMAP_SE_IDX_SEL_M                            GENMASK(4, 2)
++#define QSYS_QMAP_SE_IDX_SEL_X(x)                         (((x) & GENMASK(4, 2)) >> 2)
++#define QSYS_QMAP_SE_INP_SEL(x)                           ((x) & GENMASK(1, 0))
++#define QSYS_QMAP_SE_INP_SEL_M                            GENMASK(1, 0)
++
++#define QSYS_ISDX_SGRP_GSZ                                0x4
++
++#define QSYS_TIMED_FRAME_ENTRY_GSZ                        0x4
++
++#define QSYS_TFRM_MISC_TIMED_CANCEL_SLOT(x)               (((x) << 9) & GENMASK(18, 9))
++#define QSYS_TFRM_MISC_TIMED_CANCEL_SLOT_M                GENMASK(18, 9)
++#define QSYS_TFRM_MISC_TIMED_CANCEL_SLOT_X(x)             (((x) & GENMASK(18, 9)) >> 9)
++#define QSYS_TFRM_MISC_TIMED_CANCEL_1SHOT                 BIT(8)
++#define QSYS_TFRM_MISC_TIMED_SLOT_MODE_MC                 BIT(7)
++#define QSYS_TFRM_MISC_TIMED_ENTRY_FAST_CNT(x)            ((x) & GENMASK(6, 0))
++#define QSYS_TFRM_MISC_TIMED_ENTRY_FAST_CNT_M             GENMASK(6, 0)
++
++#define QSYS_RED_PROFILE_RSZ                              0x4
++
++#define QSYS_RED_PROFILE_WM_RED_LOW(x)                    (((x) << 8) & GENMASK(15, 8))
++#define QSYS_RED_PROFILE_WM_RED_LOW_M                     GENMASK(15, 8)
++#define QSYS_RED_PROFILE_WM_RED_LOW_X(x)                  (((x) & GENMASK(15, 8)) >> 8)
++#define QSYS_RED_PROFILE_WM_RED_HIGH(x)                   ((x) & GENMASK(7, 0))
++#define QSYS_RED_PROFILE_WM_RED_HIGH_M                    GENMASK(7, 0)
++
++#define QSYS_RES_CFG_GSZ                                  0x8
++
++#define QSYS_RES_STAT_GSZ                                 0x8
++
++#define QSYS_RES_STAT_INUSE(x)                            (((x) << 12) & GENMASK(23, 12))
++#define QSYS_RES_STAT_INUSE_M                             GENMASK(23, 12)
++#define QSYS_RES_STAT_INUSE_X(x)                          (((x) & GENMASK(23, 12)) >> 12)
++#define QSYS_RES_STAT_MAXUSE(x)                           ((x) & GENMASK(11, 0))
++#define QSYS_RES_STAT_MAXUSE_M                            GENMASK(11, 0)
++
++#define QSYS_EVENTS_CORE_EV_FDC(x)                        (((x) << 2) & GENMASK(4, 2))
++#define QSYS_EVENTS_CORE_EV_FDC_M                         GENMASK(4, 2)
++#define QSYS_EVENTS_CORE_EV_FDC_X(x)                      (((x) & GENMASK(4, 2)) >> 2)
++#define QSYS_EVENTS_CORE_EV_FRD(x)                        ((x) & GENMASK(1, 0))
++#define QSYS_EVENTS_CORE_EV_FRD_M                         GENMASK(1, 0)
++
++#define QSYS_QMAXSDU_CFG_0_RSZ                            0x4
++
++#define QSYS_QMAXSDU_CFG_1_RSZ                            0x4
++
++#define QSYS_QMAXSDU_CFG_2_RSZ                            0x4
++
++#define QSYS_QMAXSDU_CFG_3_RSZ                            0x4
++
++#define QSYS_QMAXSDU_CFG_4_RSZ                            0x4
++
++#define QSYS_QMAXSDU_CFG_5_RSZ                            0x4
++
++#define QSYS_QMAXSDU_CFG_6_RSZ                            0x4
++
++#define QSYS_QMAXSDU_CFG_7_RSZ                            0x4
++
++#define QSYS_PREEMPTION_CFG_RSZ                           0x4
++
++#define QSYS_PREEMPTION_CFG_P_QUEUES(x)                   ((x) & GENMASK(7, 0))
++#define QSYS_PREEMPTION_CFG_P_QUEUES_M                    GENMASK(7, 0)
++#define QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE(x)           (((x) << 8) & GENMASK(9, 8))
++#define QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_M            GENMASK(9, 8)
++#define QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_X(x)         (((x) & GENMASK(9, 8)) >> 8)
++#define QSYS_PREEMPTION_CFG_STRICT_IPG(x)                 (((x) << 12) & GENMASK(13, 12))
++#define QSYS_PREEMPTION_CFG_STRICT_IPG_M                  GENMASK(13, 12)
++#define QSYS_PREEMPTION_CFG_STRICT_IPG_X(x)               (((x) & GENMASK(13, 12)) >> 12)
++#define QSYS_PREEMPTION_CFG_HOLD_ADVANCE(x)               (((x) << 16) & GENMASK(31, 16))
++#define QSYS_PREEMPTION_CFG_HOLD_ADVANCE_M                GENMASK(31, 16)
++#define QSYS_PREEMPTION_CFG_HOLD_ADVANCE_X(x)             (((x) & GENMASK(31, 16)) >> 16)
++
++#define QSYS_CIR_CFG_GSZ                                  0x80
++
++#define QSYS_CIR_CFG_CIR_RATE(x)                          (((x) << 6) & GENMASK(20, 6))
++#define QSYS_CIR_CFG_CIR_RATE_M                           GENMASK(20, 6)
++#define QSYS_CIR_CFG_CIR_RATE_X(x)                        (((x) & GENMASK(20, 6)) >> 6)
++#define QSYS_CIR_CFG_CIR_BURST(x)                         ((x) & GENMASK(5, 0))
++#define QSYS_CIR_CFG_CIR_BURST_M                          GENMASK(5, 0)
++
++#define QSYS_EIR_CFG_GSZ                                  0x80
++
++#define QSYS_EIR_CFG_EIR_RATE(x)                          (((x) << 7) & GENMASK(21, 7))
++#define QSYS_EIR_CFG_EIR_RATE_M                           GENMASK(21, 7)
++#define QSYS_EIR_CFG_EIR_RATE_X(x)                        (((x) & GENMASK(21, 7)) >> 7)
++#define QSYS_EIR_CFG_EIR_BURST(x)                         (((x) << 1) & GENMASK(6, 1))
++#define QSYS_EIR_CFG_EIR_BURST_M                          GENMASK(6, 1)
++#define QSYS_EIR_CFG_EIR_BURST_X(x)                       (((x) & GENMASK(6, 1)) >> 1)
++#define QSYS_EIR_CFG_EIR_MARK_ENA                         BIT(0)
++
++#define QSYS_SE_CFG_GSZ                                   0x80
++
++#define QSYS_SE_CFG_SE_DWRR_CNT(x)                        (((x) << 6) & GENMASK(9, 6))
++#define QSYS_SE_CFG_SE_DWRR_CNT_M                         GENMASK(9, 6)
++#define QSYS_SE_CFG_SE_DWRR_CNT_X(x)                      (((x) & GENMASK(9, 6)) >> 6)
++#define QSYS_SE_CFG_SE_RR_ENA                             BIT(5)
++#define QSYS_SE_CFG_SE_AVB_ENA                            BIT(4)
++#define QSYS_SE_CFG_SE_FRM_MODE(x)                        (((x) << 2) & GENMASK(3, 2))
++#define QSYS_SE_CFG_SE_FRM_MODE_M                         GENMASK(3, 2)
++#define QSYS_SE_CFG_SE_FRM_MODE_X(x)                      (((x) & GENMASK(3, 2)) >> 2)
++#define QSYS_SE_CFG_SE_EXC_ENA                            BIT(1)
++#define QSYS_SE_CFG_SE_EXC_FWD                            BIT(0)
++
++#define QSYS_SE_DWRR_CFG_GSZ                              0x80
++#define QSYS_SE_DWRR_CFG_RSZ                              0x4
++
++#define QSYS_SE_CONNECT_GSZ                               0x80
++
++#define QSYS_SE_CONNECT_SE_OUTP_IDX(x)                    (((x) << 17) & GENMASK(24, 17))
++#define QSYS_SE_CONNECT_SE_OUTP_IDX_M                     GENMASK(24, 17)
++#define QSYS_SE_CONNECT_SE_OUTP_IDX_X(x)                  (((x) & GENMASK(24, 17)) >> 17)
++#define QSYS_SE_CONNECT_SE_INP_IDX(x)                     (((x) << 9) & GENMASK(16, 9))
++#define QSYS_SE_CONNECT_SE_INP_IDX_M                      GENMASK(16, 9)
++#define QSYS_SE_CONNECT_SE_INP_IDX_X(x)                   (((x) & GENMASK(16, 9)) >> 9)
++#define QSYS_SE_CONNECT_SE_OUTP_CON(x)                    (((x) << 5) & GENMASK(8, 5))
++#define QSYS_SE_CONNECT_SE_OUTP_CON_M                     GENMASK(8, 5)
++#define QSYS_SE_CONNECT_SE_OUTP_CON_X(x)                  (((x) & GENMASK(8, 5)) >> 5)
++#define QSYS_SE_CONNECT_SE_INP_CNT(x)                     (((x) << 1) & GENMASK(4, 1))
++#define QSYS_SE_CONNECT_SE_INP_CNT_M                      GENMASK(4, 1)
++#define QSYS_SE_CONNECT_SE_INP_CNT_X(x)                   (((x) & GENMASK(4, 1)) >> 1)
++#define QSYS_SE_CONNECT_SE_TERMINAL                       BIT(0)
++
++#define QSYS_SE_DLB_SENSE_GSZ                             0x80
++
++#define QSYS_SE_DLB_SENSE_SE_DLB_PRIO(x)                  (((x) << 11) & GENMASK(13, 11))
++#define QSYS_SE_DLB_SENSE_SE_DLB_PRIO_M                   GENMASK(13, 11)
++#define QSYS_SE_DLB_SENSE_SE_DLB_PRIO_X(x)                (((x) & GENMASK(13, 11)) >> 11)
++#define QSYS_SE_DLB_SENSE_SE_DLB_SPORT(x)                 (((x) << 7) & GENMASK(10, 7))
++#define QSYS_SE_DLB_SENSE_SE_DLB_SPORT_M                  GENMASK(10, 7)
++#define QSYS_SE_DLB_SENSE_SE_DLB_SPORT_X(x)               (((x) & GENMASK(10, 7)) >> 7)
++#define QSYS_SE_DLB_SENSE_SE_DLB_DPORT(x)                 (((x) << 3) & GENMASK(6, 3))
++#define QSYS_SE_DLB_SENSE_SE_DLB_DPORT_M                  GENMASK(6, 3)
++#define QSYS_SE_DLB_SENSE_SE_DLB_DPORT_X(x)               (((x) & GENMASK(6, 3)) >> 3)
++#define QSYS_SE_DLB_SENSE_SE_DLB_PRIO_ENA                 BIT(2)
++#define QSYS_SE_DLB_SENSE_SE_DLB_SPORT_ENA                BIT(1)
++#define QSYS_SE_DLB_SENSE_SE_DLB_DPORT_ENA                BIT(0)
++
++#define QSYS_CIR_STATE_GSZ                                0x80
++
++#define QSYS_CIR_STATE_CIR_LVL(x)                         (((x) << 4) & GENMASK(25, 4))
++#define QSYS_CIR_STATE_CIR_LVL_M                          GENMASK(25, 4)
++#define QSYS_CIR_STATE_CIR_LVL_X(x)                       (((x) & GENMASK(25, 4)) >> 4)
++#define QSYS_CIR_STATE_SHP_TIME(x)                        ((x) & GENMASK(3, 0))
++#define QSYS_CIR_STATE_SHP_TIME_M                         GENMASK(3, 0)
++
++#define QSYS_EIR_STATE_GSZ                                0x80
++
++#define QSYS_SE_STATE_GSZ                                 0x80
++
++#define QSYS_SE_STATE_SE_OUTP_LVL(x)                      (((x) << 1) & GENMASK(2, 1))
++#define QSYS_SE_STATE_SE_OUTP_LVL_M                       GENMASK(2, 1)
++#define QSYS_SE_STATE_SE_OUTP_LVL_X(x)                    (((x) & GENMASK(2, 1)) >> 1)
++#define QSYS_SE_STATE_SE_WAS_YEL                          BIT(0)
++
++#define QSYS_HSCH_MISC_CFG_SE_CONNECT_VLD                 BIT(8)
++#define QSYS_HSCH_MISC_CFG_FRM_ADJ(x)                     (((x) << 3) & GENMASK(7, 3))
++#define QSYS_HSCH_MISC_CFG_FRM_ADJ_M                      GENMASK(7, 3)
++#define QSYS_HSCH_MISC_CFG_FRM_ADJ_X(x)                   (((x) & GENMASK(7, 3)) >> 3)
++#define QSYS_HSCH_MISC_CFG_LEAK_DIS                       BIT(2)
++#define QSYS_HSCH_MISC_CFG_QSHP_EXC_ENA                   BIT(1)
++#define QSYS_HSCH_MISC_CFG_PFC_BYP_UPD                    BIT(0)
++
++#define QSYS_TAG_CONFIG_RSZ                               0x4
++
++#define QSYS_TAG_CONFIG_ENABLE                            BIT(0)
++#define QSYS_TAG_CONFIG_LINK_SPEED(x)                     (((x) << 4) & GENMASK(5, 4))
++#define QSYS_TAG_CONFIG_LINK_SPEED_M                      GENMASK(5, 4)
++#define QSYS_TAG_CONFIG_LINK_SPEED_X(x)                   (((x) & GENMASK(5, 4)) >> 4)
++#define QSYS_TAG_CONFIG_INIT_GATE_STATE(x)                (((x) << 8) & GENMASK(15, 8))
++#define QSYS_TAG_CONFIG_INIT_GATE_STATE_M                 GENMASK(15, 8)
++#define QSYS_TAG_CONFIG_INIT_GATE_STATE_X(x)              (((x) & GENMASK(15, 8)) >> 8)
++#define QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES(x)             (((x) << 16) & GENMASK(23, 16))
++#define QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_M              GENMASK(23, 16)
++#define QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_X(x)           (((x) & GENMASK(23, 16)) >> 16)
++
++#define QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(x)               ((x) & GENMASK(7, 0))
++#define QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M                GENMASK(7, 0)
++#define QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q   BIT(8)
++#define QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE             BIT(16)
++
++#define QSYS_PORT_MAX_SDU_RSZ                             0x4
++
++#define QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(x)         ((x) & GENMASK(15, 0))
++#define QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB_M          GENMASK(15, 0)
++#define QSYS_PARAM_CFG_REG_3_LIST_LENGTH(x)               (((x) << 16) & GENMASK(31, 16))
++#define QSYS_PARAM_CFG_REG_3_LIST_LENGTH_M                GENMASK(31, 16)
++#define QSYS_PARAM_CFG_REG_3_LIST_LENGTH_X(x)             (((x) & GENMASK(31, 16)) >> 16)
++
++#define QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM(x)               ((x) & GENMASK(5, 0))
++#define QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM_M                GENMASK(5, 0)
++#define QSYS_GCL_CFG_REG_1_GATE_STATE(x)                  (((x) << 8) & GENMASK(15, 8))
++#define QSYS_GCL_CFG_REG_1_GATE_STATE_M                   GENMASK(15, 8)
++#define QSYS_GCL_CFG_REG_1_GATE_STATE_X(x)                (((x) & GENMASK(15, 8)) >> 8)
++
++#define QSYS_PARAM_STATUS_REG_3_BASE_TIME_SEC_MSB(x)      ((x) & GENMASK(15, 0))
++#define QSYS_PARAM_STATUS_REG_3_BASE_TIME_SEC_MSB_M       GENMASK(15, 0)
++#define QSYS_PARAM_STATUS_REG_3_LIST_LENGTH(x)            (((x) << 16) & GENMASK(31, 16))
++#define QSYS_PARAM_STATUS_REG_3_LIST_LENGTH_M             GENMASK(31, 16)
++#define QSYS_PARAM_STATUS_REG_3_LIST_LENGTH_X(x)          (((x) & GENMASK(31, 16)) >> 16)
++
++#define QSYS_PARAM_STATUS_REG_8_CFG_CHG_TIME_SEC_MSB(x)   ((x) & GENMASK(15, 0))
++#define QSYS_PARAM_STATUS_REG_8_CFG_CHG_TIME_SEC_MSB_M    GENMASK(15, 0)
++#define QSYS_PARAM_STATUS_REG_8_OPER_GATE_STATE(x)        (((x) << 16) & GENMASK(23, 16))
++#define QSYS_PARAM_STATUS_REG_8_OPER_GATE_STATE_M         GENMASK(23, 16)
++#define QSYS_PARAM_STATUS_REG_8_OPER_GATE_STATE_X(x)      (((x) & GENMASK(23, 16)) >> 16)
++#define QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING            BIT(24)
++
++#define QSYS_GCL_STATUS_REG_1_GCL_ENTRY_NUM(x)            ((x) & GENMASK(5, 0))
++#define QSYS_GCL_STATUS_REG_1_GCL_ENTRY_NUM_M             GENMASK(5, 0)
++#define QSYS_GCL_STATUS_REG_1_GATE_STATE(x)               (((x) << 8) & GENMASK(15, 8))
++#define QSYS_GCL_STATUS_REG_1_GATE_STATE_M                GENMASK(15, 8)
++#define QSYS_GCL_STATUS_REG_1_GATE_STATE_X(x)             (((x) & GENMASK(15, 8)) >> 8)
++
++#endif
diff --git a/target/linux/layerscape/patches-5.4/701-net-0386-net-dsa-felix-Add-PCS-operations-for-PHYLINK.patch b/target/linux/layerscape/patches-5.4/701-net-0386-net-dsa-felix-Add-PCS-operations-for-PHYLINK.patch
new file mode 100644 (file)
index 0000000..4286c3b
--- /dev/null
@@ -0,0 +1,1087 @@
+From 78d77114e35a491232c50e054f43c980bbf9d434 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Mon, 6 Jan 2020 03:34:17 +0200
+Subject: [PATCH] net: dsa: felix: Add PCS operations for PHYLINK
+
+Layerscape SoCs traditionally expose the SerDes configuration/status for
+Ethernet protocols (PCS for SGMII/USXGMII/10GBase-R etc etc) in a register
+format that is compatible with clause 22 or clause 45 (depending on
+SerDes protocol). Each MAC has its own internal MDIO bus on which there
+is one or more of these PCS's, responding to commands at a configurable
+PHY address. The per-port internal MDIO bus (which is just for PCSs) is
+totally separate and has nothing to do with the dedicated external MDIO
+controller (which is just for PHYs), but the register map for the MDIO
+controller is the same.
+
+The VSC9959 (Felix) switch instantiated in the LS1028A is integrated
+in hardware with the ENETC PCS of its DSA master, and reuses its MDIO
+controller driver, so Felix has been made to depend on it in Kconfig.
+
+ +------------------------------------------------------------------------+
+ |                   +--------+ GMII (typically disabled via RCW)         |
+ | ENETC PCI         |  ENETC |--------------------------+                |
+ | Root Complex      | port 3 |-----------------------+  |                |
+ | Integrated        +--------+                       |  |                |
+ | Endpoint                                           |  |                |
+ |                   +--------+ 2.5G GMII             |  |                |
+ |                   |  ENETC |--------------+        |  |                |
+ |                   | port 2 |-----------+  |        |  |                |
+ |                   +--------+           |  |        |  |                |
+ |                                     +--------+  +--------+             |
+ |                                     |  Felix |  |  Felix |             |
+ |                                     | port 4 |  | port 5 |             |
+ |                                     +--------+  +--------+             |
+ |                                                                        |
+ | +--------+  +--------+  +--------+  +--------+  +--------+  +--------+ |
+ | |  ENETC |  |  ENETC |  |  Felix |  |  Felix |  |  Felix |  |  Felix | |
+ | | port 0 |  | port 1 |  | port 0 |  | port 1 |  | port 2 |  | port 3 | |
+ +------------------------------------------------------------------------+
+ |    ||||  SerDes |          ||||        ||||        ||||        ||||    |
+ | +--------+block |       +--------------------------------------------+ |
+ | |  ENETC |      |       |       ENETC port 2 internal MDIO bus       | |
+ | | port 0 |      |       |  PCS         PCS          PCS        PCS   | |
+ | |   PCS  |      |       |   0           1            2          3    | |
+ +-----------------|------------------------------------------------------+
+        v          v           v           v            v          v
+     SGMII/      RGMII    QSGMII/QSXGMII/4xSGMII/4x1000Base-X/4x2500Base-X
+    USXGMII/   (bypasses
+  1000Base-X/   SerDes)
+  2500Base-X
+
+In the LS1028A SoC described above, the VSC9959 Felix switch is PF5 of
+the ENETC root complex, and has 2 BARs:
+- BAR 4: the switch's effective registers
+- BAR 0: the MDIO controller register map lended from ENETC port 2
+         (PF2), for accessing its associated PCS's.
+
+This explanation is necessary because the patch does some renaming
+"pci_bar" -> "switch_pci_bar" for clarity, which would otherwise appear
+a bit obtuse.
+
+The fact that the internal MDIO bus is "borrowed" is relevant because
+the register map is found in PF5 (the switch) but it triggers an access
+fault if PF2 (the ENETC DSA master) is not enabled. This is not treated
+in any way (and I don't think it can be treated).
+
+All of this is so SoC-specific, that it was contained as much as
+possible in the platform-integration file felix_vsc9959.c.
+
+We need to parse and pre-validate the device tree because of 2 reasons:
+- The PHY mode (SerDes protocol) cannot change at runtime due to SoC
+  design.
+- There is a circular dependency in that we need to know what clause the
+  PCS speaks in order to find it on the internal MDIO bus. But the
+  clause of the PCS depends on what phy-mode it is configured for.
+
+The goal of this patch is to make steps towards removing the bootloader
+dependency for SGMII PCS pre-configuration, as well as to add support
+for monitoring the in-band SGMII AN between the PCS and the system-side
+link partner (PHY or other MAC).
+
+In practice the bootloader dependency is not completely removed. U-Boot
+pre-programs the PHY address at which each PCS can be found on the
+internal MDIO bus (MDEV_PORT). This is needed because the PCS of each
+port has the same out-of-reset PHY address of zero. The SerDes register
+for changing MDEV_PORT is pretty deep in the SoC (outside the addresses
+of the ENETC PCI BARs) and therefore inaccessible to us from here.
+
+Felix VSC9959 and Ocelot VSC7514 are integrated very differently in
+their respective SoCs, and for that reason Felix does not use the Ocelot
+core library for PHYLINK. On one hand we don't want to impose the
+fixed phy-mode limitation to Ocelot, and on the other hand Felix doesn't
+need to force the MAC link speed the way Ocelot does, since the MAC is
+connected to the PCS through a fixed GMII, and the PCS is the one who
+does the rate adaptation at lower link speeds, which the MAC does not
+even need to know about. In fact changing the GMII speed for Felix
+irrecoverably breaks transmission through that port until a reset.
+
+The pair with ENETC port 3 and Felix port 5 is optional and doesn't
+support tagging. When we enable it, swp5 is a regular slave port, albeit
+an internal one. The trouble is that it doesn't work, and that is
+because the DSA PHYLIB adaptation layer doesn't treat fixed-link slave
+ports. So that is yet another reason for wanting to convert Felix to the
+native PHYLINK API.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+Conflicts:
+       drivers/net/dsa/ocelot/felix.c
+
+with the upstream API change for of_get_phy_mode() introduced in
+0c65b2b90d13 ("net: of_get_phy_mode: Change API to solve int/unit
+warnings") and merged in v5.4-rc5.
+---
+ drivers/net/dsa/ocelot/Kconfig         |   2 +
+ drivers/net/dsa/ocelot/felix.c         | 267 +++++++++++++++++-
+ drivers/net/dsa/ocelot/felix.h         |  16 +-
+ drivers/net/dsa/ocelot/felix_vsc9959.c | 501 ++++++++++++++++++++++++++++++++-
+ 4 files changed, 769 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/dsa/ocelot/Kconfig
++++ b/drivers/net/dsa/ocelot/Kconfig
+@@ -3,8 +3,10 @@ config NET_DSA_MSCC_FELIX
+       tristate "Ocelot / Felix Ethernet switch support"
+       depends on NET_DSA && PCI
+       depends on NET_VENDOR_MICROSEMI
++      depends on NET_VENDOR_FREESCALE
+       select MSCC_OCELOT_SWITCH
+       select NET_DSA_TAG_OCELOT
++      select FSL_ENETC_MDIO
+       help
+         This driver supports the VSC9959 network switch, which is a member of
+         the Vitesse / Microsemi / Microchip Ocelot family of switching cores.
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -2,9 +2,14 @@
+ /* Copyright 2019 NXP Semiconductors
+  */
+ #include <uapi/linux/if_bridge.h>
++#include <soc/mscc/ocelot_qsys.h>
++#include <soc/mscc/ocelot_sys.h>
++#include <soc/mscc/ocelot_dev.h>
++#include <soc/mscc/ocelot_ana.h>
+ #include <soc/mscc/ocelot.h>
+ #include <linux/packing.h>
+ #include <linux/module.h>
++#include <linux/of_net.h>
+ #include <linux/pci.h>
+ #include <linux/of.h>
+ #include <net/dsa.h>
+@@ -58,14 +63,6 @@ static int felix_set_ageing_time(struct
+       return 0;
+ }
+-static void felix_adjust_link(struct dsa_switch *ds, int port,
+-                            struct phy_device *phydev)
+-{
+-      struct ocelot *ocelot = ds->priv;
+-
+-      ocelot_adjust_link(ocelot, port, phydev);
+-}
+-
+ static int felix_fdb_dump(struct dsa_switch *ds, int port,
+                         dsa_fdb_dump_cb_t *cb, void *data)
+ {
+@@ -202,6 +199,138 @@ static void felix_port_disable(struct ds
+       return ocelot_port_disable(ocelot, port);
+ }
++static void felix_phylink_validate(struct dsa_switch *ds, int port,
++                                 unsigned long *supported,
++                                 struct phylink_link_state *state)
++{
++      struct ocelot *ocelot = ds->priv;
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++      __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
++
++      if (state->interface != PHY_INTERFACE_MODE_NA &&
++          state->interface != ocelot_port->phy_mode) {
++              bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
++              return;
++      }
++
++      /* No half-duplex. */
++      phylink_set_port_modes(mask);
++      phylink_set(mask, Autoneg);
++      phylink_set(mask, Pause);
++      phylink_set(mask, Asym_Pause);
++      if (state->interface != PHY_INTERFACE_MODE_2500BASEX) {
++              phylink_set(mask, 10baseT_Full);
++              phylink_set(mask, 100baseT_Full);
++              phylink_set(mask, 1000baseT_Full);
++      }
++      /* The internal ports that run at 2.5G are overclocked GMII */
++      if (state->interface == PHY_INTERFACE_MODE_GMII ||
++          state->interface == PHY_INTERFACE_MODE_2500BASEX ||
++          state->interface == PHY_INTERFACE_MODE_USXGMII) {
++              phylink_set(mask, 2500baseT_Full);
++              phylink_set(mask, 2500baseX_Full);
++      }
++
++      bitmap_and(supported, supported, mask,
++                 __ETHTOOL_LINK_MODE_MASK_NBITS);
++      bitmap_and(state->advertising, state->advertising, mask,
++                 __ETHTOOL_LINK_MODE_MASK_NBITS);
++}
++
++static int felix_phylink_mac_pcs_get_state(struct dsa_switch *ds, int port,
++                                         struct phylink_link_state *state)
++{
++      struct ocelot *ocelot = ds->priv;
++      struct felix *felix = ocelot_to_felix(ocelot);
++
++      if (felix->info->pcs_link_state)
++              felix->info->pcs_link_state(ocelot, port, state);
++
++      return 0;
++}
++
++static void felix_phylink_mac_config(struct dsa_switch *ds, int port,
++                                   unsigned int link_an_mode,
++                                   const struct phylink_link_state *state)
++{
++      struct ocelot *ocelot = ds->priv;
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++      struct felix *felix = ocelot_to_felix(ocelot);
++      u32 mac_fc_cfg;
++
++      /* Take port out of reset by clearing the MAC_TX_RST, MAC_RX_RST and
++       * PORT_RST bits in CLOCK_CFG
++       */
++      ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(state->speed),
++                         DEV_CLOCK_CFG);
++
++      /* Flow control. Link speed is only used here to evaluate the time
++       * specification in incoming pause frames.
++       */
++      mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(state->speed);
++      if (state->pause & MLO_PAUSE_RX)
++              mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA;
++      if (state->pause & MLO_PAUSE_TX)
++              mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA |
++                            SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) |
++                            SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) |
++                            SYS_MAC_FC_CFG_ZERO_PAUSE_ENA;
++      ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port);
++
++      ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port);
++
++      if (felix->info->pcs_init)
++              felix->info->pcs_init(ocelot, port, link_an_mode, state);
++}
++
++static void felix_phylink_mac_an_restart(struct dsa_switch *ds, int port)
++{
++      struct ocelot *ocelot = ds->priv;
++      struct felix *felix = ocelot_to_felix(ocelot);
++
++      if (felix->info->pcs_an_restart)
++              felix->info->pcs_an_restart(ocelot, port);
++}
++
++static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port,
++                                      unsigned int link_an_mode,
++                                      phy_interface_t interface)
++{
++      struct ocelot *ocelot = ds->priv;
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++
++      ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG);
++      ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA,
++                     QSYS_SWITCH_PORT_MODE, port);
++}
++
++static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
++                                    unsigned int link_an_mode,
++                                    phy_interface_t interface,
++                                    struct phy_device *phydev)
++{
++      struct ocelot *ocelot = ds->priv;
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++
++      /* Enable MAC module */
++      ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA |
++                         DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG);
++
++      /* Enable receiving frames on the port, and activate auto-learning of
++       * MAC addresses.
++       */
++      ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO |
++                       ANA_PORT_PORT_CFG_RECV_ENA |
++                       ANA_PORT_PORT_CFG_PORTID_VAL(port),
++                       ANA_PORT_PORT_CFG, port);
++
++      /* Core: Enable port for frame transfer */
++      ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE |
++                       QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) |
++                       QSYS_SWITCH_PORT_MODE_PORT_ENA,
++                       QSYS_SWITCH_PORT_MODE, port);
++}
++
+ static void felix_get_strings(struct dsa_switch *ds, int port,
+                             u32 stringset, u8 *data)
+ {
+@@ -232,10 +361,78 @@ static int felix_get_ts_info(struct dsa_
+       return ocelot_get_ts_info(ocelot, port, info);
+ }
++static int felix_parse_ports_node(struct felix *felix,
++                                struct device_node *ports_node,
++                                phy_interface_t *port_phy_modes)
++{
++      struct ocelot *ocelot = &felix->ocelot;
++      struct device *dev = felix->ocelot.dev;
++      struct device_node *child;
++
++      for_each_child_of_node(ports_node, child) {
++              phy_interface_t phy_mode;
++              u32 port;
++              int err;
++
++              /* Get switch port number from DT */
++              if (of_property_read_u32(child, "reg", &port) < 0) {
++                      dev_err(dev, "Port number not defined in device tree "
++                              "(property \"reg\")\n");
++                      of_node_put(child);
++                      return -ENODEV;
++              }
++
++              /* Get PHY mode from DT */
++              err = of_get_phy_mode(child);
++              if (err < 0) {
++                      dev_err(dev, "Failed to read phy-mode or "
++                              "phy-interface-type property for port %d\n",
++                              port);
++                      of_node_put(child);
++                      return -ENODEV;
++              }
++
++              phy_mode = err;
++
++              err = felix->info->prevalidate_phy_mode(ocelot, port, phy_mode);
++              if (err < 0) {
++                      dev_err(dev, "Unsupported PHY mode %s on port %d\n",
++                              phy_modes(phy_mode), port);
++                      return err;
++              }
++
++              port_phy_modes[port] = phy_mode;
++      }
++
++      return 0;
++}
++
++static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes)
++{
++      struct device *dev = felix->ocelot.dev;
++      struct device_node *switch_node;
++      struct device_node *ports_node;
++      int err;
++
++      switch_node = dev->of_node;
++
++      ports_node = of_get_child_by_name(switch_node, "ports");
++      if (!ports_node) {
++              dev_err(dev, "Incorrect bindings: absent \"ports\" node\n");
++              return -ENODEV;
++      }
++
++      err = felix_parse_ports_node(felix, ports_node, port_phy_modes);
++      of_node_put(ports_node);
++
++      return err;
++}
++
+ static int felix_init_structs(struct felix *felix, int num_phys_ports)
+ {
+       struct ocelot *ocelot = &felix->ocelot;
+-      resource_size_t base;
++      phy_interface_t *port_phy_modes;
++      resource_size_t switch_base;
+       int port, i, err;
+       ocelot->num_phys_ports = num_phys_ports;
+@@ -250,7 +447,19 @@ static int felix_init_structs(struct fel
+       ocelot->shared_queue_sz = felix->info->shared_queue_sz;
+       ocelot->ops             = felix->info->ops;
+-      base = pci_resource_start(felix->pdev, felix->info->pci_bar);
++      port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t),
++                               GFP_KERNEL);
++      if (!port_phy_modes)
++              return -ENOMEM;
++
++      err = felix_parse_dt(felix, port_phy_modes);
++      if (err) {
++              kfree(port_phy_modes);
++              return err;
++      }
++
++      switch_base = pci_resource_start(felix->pdev,
++                                       felix->info->switch_pci_bar);
+       for (i = 0; i < TARGET_MAX; i++) {
+               struct regmap *target;
+@@ -261,13 +470,14 @@ static int felix_init_structs(struct fel
+               res = &felix->info->target_io_res[i];
+               res->flags = IORESOURCE_MEM;
+-              res->start += base;
+-              res->end += base;
++              res->start += switch_base;
++              res->end += switch_base;
+               target = ocelot_regmap_init(ocelot, res);
+               if (IS_ERR(target)) {
+                       dev_err(ocelot->dev,
+                               "Failed to map device memory space\n");
++                      kfree(port_phy_modes);
+                       return PTR_ERR(target);
+               }
+@@ -277,6 +487,7 @@ static int felix_init_structs(struct fel
+       err = ocelot_regfields_init(ocelot, felix->info->regfields);
+       if (err) {
+               dev_err(ocelot->dev, "failed to init reg fields map\n");
++              kfree(port_phy_modes);
+               return err;
+       }
+@@ -291,26 +502,37 @@ static int felix_init_structs(struct fel
+               if (!ocelot_port) {
+                       dev_err(ocelot->dev,
+                               "failed to allocate port memory\n");
++                      kfree(port_phy_modes);
+                       return -ENOMEM;
+               }
+               res = &felix->info->port_io_res[port];
+               res->flags = IORESOURCE_MEM;
+-              res->start += base;
+-              res->end += base;
++              res->start += switch_base;
++              res->end += switch_base;
+               port_regs = devm_ioremap_resource(ocelot->dev, res);
+               if (IS_ERR(port_regs)) {
+                       dev_err(ocelot->dev,
+                               "failed to map registers for port %d\n", port);
++                      kfree(port_phy_modes);
+                       return PTR_ERR(port_regs);
+               }
++              ocelot_port->phy_mode = port_phy_modes[port];
+               ocelot_port->ocelot = ocelot;
+               ocelot_port->regs = port_regs;
+               ocelot->ports[port] = ocelot_port;
+       }
++      kfree(port_phy_modes);
++
++      if (felix->info->mdio_bus_alloc) {
++              err = felix->info->mdio_bus_alloc(ocelot);
++              if (err < 0)
++                      return err;
++      }
++
+       return 0;
+ }
+@@ -340,12 +562,22 @@ static int felix_setup(struct dsa_switch
+                                           OCELOT_TAG_PREFIX_LONG);
+       }
++      /* It looks like the MAC/PCS interrupt register - PM0_IEVENT (0x8040)
++       * isn't instantiated for the Felix PF.
++       * In-band AN may take a few ms to complete, so we need to poll.
++       */
++      ds->pcs_poll = true;
++
+       return 0;
+ }
+ static void felix_teardown(struct dsa_switch *ds)
+ {
+       struct ocelot *ocelot = ds->priv;
++      struct felix *felix = ocelot_to_felix(ocelot);
++
++      if (felix->info->mdio_bus_free)
++              felix->info->mdio_bus_free(ocelot);
+       /* stop workqueue thread */
+       ocelot_deinit(ocelot);
+@@ -416,7 +648,12 @@ static const struct dsa_switch_ops felix
+       .get_ethtool_stats      = felix_get_ethtool_stats,
+       .get_sset_count         = felix_get_sset_count,
+       .get_ts_info            = felix_get_ts_info,
+-      .adjust_link            = felix_adjust_link,
++      .phylink_validate       = felix_phylink_validate,
++      .phylink_mac_link_state = felix_phylink_mac_pcs_get_state,
++      .phylink_mac_config     = felix_phylink_mac_config,
++      .phylink_mac_an_restart = felix_phylink_mac_an_restart,
++      .phylink_mac_link_down  = felix_phylink_mac_link_down,
++      .phylink_mac_link_up    = felix_phylink_mac_link_up,
+       .port_enable            = felix_port_enable,
+       .port_disable           = felix_port_disable,
+       .port_fdb_dump          = felix_fdb_dump,
+--- a/drivers/net/dsa/ocelot/felix.h
++++ b/drivers/net/dsa/ocelot/felix.h
+@@ -10,6 +10,7 @@
+ struct felix_info {
+       struct resource                 *target_io_res;
+       struct resource                 *port_io_res;
++      struct resource                 *imdio_res;
+       const struct reg_field          *regfields;
+       const u32 *const                *map;
+       const struct ocelot_ops         *ops;
+@@ -17,7 +18,18 @@ struct felix_info {
+       const struct ocelot_stat_layout *stats_layout;
+       unsigned int                    num_stats;
+       int                             num_ports;
+-      int                             pci_bar;
++      int                             switch_pci_bar;
++      int                             imdio_pci_bar;
++      int     (*mdio_bus_alloc)(struct ocelot *ocelot);
++      void    (*mdio_bus_free)(struct ocelot *ocelot);
++      void    (*pcs_init)(struct ocelot *ocelot, int port,
++                          unsigned int link_an_mode,
++                          const struct phylink_link_state *state);
++      void    (*pcs_an_restart)(struct ocelot *ocelot, int port);
++      void    (*pcs_link_state)(struct ocelot *ocelot, int port,
++                                struct phylink_link_state *state);
++      int     (*prevalidate_phy_mode)(struct ocelot *ocelot, int port,
++                                      phy_interface_t phy_mode);
+ };
+ extern struct felix_info              felix_info_vsc9959;
+@@ -32,6 +44,8 @@ struct felix {
+       struct pci_dev                  *pdev;
+       struct felix_info               *info;
+       struct ocelot                   ocelot;
++      struct mii_bus                  *imdio;
++      struct phy_device               **pcs;
+ };
+ #endif
+--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
+@@ -2,12 +2,33 @@
+ /* Copyright 2017 Microsemi Corporation
+  * Copyright 2018-2019 NXP Semiconductors
+  */
++#include <linux/fsl/enetc_mdio.h>
+ #include <soc/mscc/ocelot_sys.h>
+ #include <soc/mscc/ocelot.h>
+ #include <linux/iopoll.h>
+ #include <linux/pci.h>
+ #include "felix.h"
++/* TODO: should find a better place for these */
++#define USXGMII_BMCR_RESET            BIT(15)
++#define USXGMII_BMCR_AN_EN            BIT(12)
++#define USXGMII_BMCR_RST_AN           BIT(9)
++#define USXGMII_BMSR_LNKS(status)     (((status) & GENMASK(2, 2)) >> 2)
++#define USXGMII_BMSR_AN_CMPL(status)  (((status) & GENMASK(5, 5)) >> 5)
++#define USXGMII_ADVERTISE_LNKS(x)     (((x) << 15) & BIT(15))
++#define USXGMII_ADVERTISE_FDX         BIT(12)
++#define USXGMII_ADVERTISE_SPEED(x)    (((x) << 9) & GENMASK(11, 9))
++#define USXGMII_LPA_LNKS(lpa)         ((lpa) >> 15)
++#define USXGMII_LPA_DUPLEX(lpa)               (((lpa) & GENMASK(12, 12)) >> 12)
++#define USXGMII_LPA_SPEED(lpa)                (((lpa) & GENMASK(11, 9)) >> 9)
++
++enum usxgmii_speed {
++      USXGMII_SPEED_10        = 0,
++      USXGMII_SPEED_100       = 1,
++      USXGMII_SPEED_1000      = 2,
++      USXGMII_SPEED_2500      = 4,
++};
++
+ static const u32 vsc9959_ana_regmap[] = {
+       REG(ANA_ADVLEARN,                       0x0089a0),
+       REG(ANA_VLANMASK,                       0x0089a4),
+@@ -390,6 +411,15 @@ static struct resource vsc9959_port_io_r
+       },
+ };
++/* Port MAC 0 Internal MDIO bus through which the SerDes acting as an
++ * SGMII/QSGMII MAC PCS can be found.
++ */
++static struct resource vsc9959_imdio_res = {
++      .start          = 0x8030,
++      .end            = 0x8040,
++      .name           = "imdio",
++};
++
+ static const struct reg_field vsc9959_regfields[] = {
+       [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6),
+       [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 5),
+@@ -569,13 +599,475 @@ static int vsc9959_reset(struct ocelot *
+       return 0;
+ }
++static void vsc9959_pcs_an_restart_sgmii(struct phy_device *pcs)
++{
++      phy_set_bits(pcs, MII_BMCR, BMCR_ANRESTART);
++}
++
++static void vsc9959_pcs_an_restart_usxgmii(struct phy_device *pcs)
++{
++      phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_BMCR,
++                    USXGMII_BMCR_RESET |
++                    USXGMII_BMCR_AN_EN |
++                    USXGMII_BMCR_RST_AN);
++}
++
++static void vsc9959_pcs_an_restart(struct ocelot *ocelot, int port)
++{
++      struct felix *felix = ocelot_to_felix(ocelot);
++      struct phy_device *pcs = felix->pcs[port];
++
++      if (!pcs)
++              return;
++
++      switch (pcs->interface) {
++      case PHY_INTERFACE_MODE_SGMII:
++      case PHY_INTERFACE_MODE_QSGMII:
++              vsc9959_pcs_an_restart_sgmii(pcs);
++              break;
++      case PHY_INTERFACE_MODE_USXGMII:
++              vsc9959_pcs_an_restart_usxgmii(pcs);
++              break;
++      default:
++              dev_err(ocelot->dev, "Invalid PCS interface type %s\n",
++                      phy_modes(pcs->interface));
++              break;
++      }
++}
++
++/* We enable SGMII AN only when the PHY has managed = "in-band-status" in the
++ * device tree. If we are in MLO_AN_PHY mode, we program directly state->speed
++ * into the PCS, which is retrieved out-of-band over MDIO. This also has the
++ * benefit of working with SGMII fixed-links, like downstream switches, where
++ * both link partners attempt to operate as AN slaves and therefore AN never
++ * completes.  But it also has the disadvantage that some PHY chips don't pass
++ * traffic if SGMII AN is enabled but not completed (acknowledged by us), so
++ * setting MLO_AN_INBAND is actually required for those.
++ */
++static void vsc9959_pcs_init_sgmii(struct phy_device *pcs,
++                                 unsigned int link_an_mode,
++                                 const struct phylink_link_state *state)
++{
++      if (link_an_mode == MLO_AN_INBAND) {
++              /* SGMII spec requires tx_config_Reg[15:0] to be exactly 0x4001
++               * for the MAC PCS in order to acknowledge the AN.
++               */
++              phy_write(pcs, MII_ADVERTISE, ADVERTISE_SGMII |
++                                            ADVERTISE_LPACK);
++
++              phy_write(pcs, ENETC_PCS_IF_MODE,
++                        ENETC_PCS_IF_MODE_SGMII_EN |
++                        ENETC_PCS_IF_MODE_USE_SGMII_AN);
++
++              /* Adjust link timer for SGMII */
++              phy_write(pcs, ENETC_PCS_LINK_TIMER1,
++                        ENETC_PCS_LINK_TIMER1_VAL);
++              phy_write(pcs, ENETC_PCS_LINK_TIMER2,
++                        ENETC_PCS_LINK_TIMER2_VAL);
++
++              phy_write(pcs, MII_BMCR, BMCR_ANRESTART | BMCR_ANENABLE);
++      } else {
++              int speed;
++
++              if (state->duplex == DUPLEX_HALF) {
++                      phydev_err(pcs, "Half duplex not supported\n");
++                      return;
++              }
++              switch (state->speed) {
++              case SPEED_1000:
++                      speed = ENETC_PCS_SPEED_1000;
++                      break;
++              case SPEED_100:
++                      speed = ENETC_PCS_SPEED_100;
++                      break;
++              case SPEED_10:
++                      speed = ENETC_PCS_SPEED_10;
++                      break;
++              case SPEED_UNKNOWN:
++                      /* Silently don't do anything */
++                      return;
++              default:
++                      phydev_err(pcs, "Invalid PCS speed %d\n", state->speed);
++                      return;
++              }
++
++              phy_write(pcs, ENETC_PCS_IF_MODE,
++                        ENETC_PCS_IF_MODE_SGMII_EN |
++                        ENETC_PCS_IF_MODE_SGMII_SPEED(speed));
++
++              /* Yes, not a mistake: speed is given by IF_MODE. */
++              phy_write(pcs, MII_BMCR, BMCR_RESET |
++                                       BMCR_SPEED1000 |
++                                       BMCR_FULLDPLX);
++      }
++}
++
++/* 2500Base-X is SerDes protocol 7 on Felix and 6 on ENETC. It is a SerDes lane
++ * clocked at 3.125 GHz which encodes symbols with 8b/10b and does not have
++ * auto-negotiation of any link parameters. Electrically it is compatible with
++ * a single lane of XAUI.
++ * The hardware reference manual wants to call this mode SGMII, but it isn't
++ * really, since the fundamental features of SGMII:
++ * - Downgrading the link speed by duplicating symbols
++ * - Auto-negotiation
++ * are not there.
++ * The speed is configured at 1000 in the IF_MODE and BMCR MDIO registers
++ * because the clock frequency is actually given by a PLL configured in the
++ * Reset Configuration Word (RCW).
++ * Since there is no difference between fixed speed SGMII w/o AN and 802.3z w/o
++ * AN, we call this PHY interface type 2500Base-X. In case a PHY negotiates a
++ * lower link speed on line side, the system-side interface remains fixed at
++ * 2500 Mbps and we do rate adaptation through pause frames.
++ */
++static void vsc9959_pcs_init_2500basex(struct phy_device *pcs,
++                                     unsigned int link_an_mode,
++                                     const struct phylink_link_state *state)
++{
++      if (link_an_mode == MLO_AN_INBAND) {
++              phydev_err(pcs, "AN not supported on 3.125GHz SerDes lane\n");
++              return;
++      }
++
++      phy_write(pcs, ENETC_PCS_IF_MODE,
++                ENETC_PCS_IF_MODE_SGMII_EN |
++                ENETC_PCS_IF_MODE_SGMII_SPEED(ENETC_PCS_SPEED_2500));
++
++      phy_write(pcs, MII_BMCR, BMCR_SPEED1000 |
++                               BMCR_FULLDPLX |
++                               BMCR_RESET);
++}
++
++static void vsc9959_pcs_init_usxgmii(struct phy_device *pcs,
++                                   unsigned int link_an_mode,
++                                   const struct phylink_link_state *state)
++{
++      if (link_an_mode != MLO_AN_INBAND) {
++              phydev_err(pcs, "USXGMII only supports in-band AN for now\n");
++              return;
++      }
++
++      /* Configure device ability for the USXGMII Replicator */
++      phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_ADVERTISE,
++                    USXGMII_ADVERTISE_SPEED(USXGMII_SPEED_2500) |
++                    USXGMII_ADVERTISE_LNKS(1) |
++                    ADVERTISE_SGMII |
++                    ADVERTISE_LPACK |
++                    USXGMII_ADVERTISE_FDX);
++}
++
++static void vsc9959_pcs_init(struct ocelot *ocelot, int port,
++                           unsigned int link_an_mode,
++                           const struct phylink_link_state *state)
++{
++      struct felix *felix = ocelot_to_felix(ocelot);
++      struct phy_device *pcs = felix->pcs[port];
++
++      if (!pcs)
++              return;
++
++      /* The PCS does not implement the BMSR register fully, so capability
++       * detection via genphy_read_abilities does not work. Since we can get
++       * the PHY config word from the LPA register though, there is still
++       * value in using the generic phy_resolve_aneg_linkmode function. So
++       * populate the supported and advertising link modes manually here.
++       */
++      linkmode_set_bit_array(phy_basic_ports_array,
++                             ARRAY_SIZE(phy_basic_ports_array),
++                             pcs->supported);
++      linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, pcs->supported);
++      linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pcs->supported);
++      linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, pcs->supported);
++      if (pcs->interface == PHY_INTERFACE_MODE_2500BASEX ||
++          pcs->interface == PHY_INTERFACE_MODE_USXGMII)
++              linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
++                               pcs->supported);
++      if (pcs->interface != PHY_INTERFACE_MODE_2500BASEX)
++              linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
++                               pcs->supported);
++      phy_advertise_supported(pcs);
++
++      switch (pcs->interface) {
++      case PHY_INTERFACE_MODE_SGMII:
++      case PHY_INTERFACE_MODE_QSGMII:
++              vsc9959_pcs_init_sgmii(pcs, link_an_mode, state);
++              break;
++      case PHY_INTERFACE_MODE_2500BASEX:
++              vsc9959_pcs_init_2500basex(pcs, link_an_mode, state);
++              break;
++      case PHY_INTERFACE_MODE_USXGMII:
++              vsc9959_pcs_init_usxgmii(pcs, link_an_mode, state);
++              break;
++      default:
++              dev_err(ocelot->dev, "Unsupported link mode %s\n",
++                      phy_modes(pcs->interface));
++      }
++}
++
++static void vsc9959_pcs_link_state_resolve(struct phy_device *pcs,
++                                         struct phylink_link_state *state)
++{
++      state->an_complete = pcs->autoneg_complete;
++      state->an_enabled = pcs->autoneg;
++      state->link = pcs->link;
++      state->duplex = pcs->duplex;
++      state->speed = pcs->speed;
++      /* SGMII AN does not negotiate flow control, but that's ok,
++       * since phylink already knows that, and does:
++       *      link_state.pause |= pl->phy_state.pause;
++       */
++      state->pause = MLO_PAUSE_NONE;
++
++      phydev_dbg(pcs,
++                 "mode=%s/%s/%s adv=%*pb lpa=%*pb link=%u an_enabled=%u an_complete=%u\n",
++                 phy_modes(pcs->interface),
++                 phy_speed_to_str(pcs->speed),
++                 phy_duplex_to_str(pcs->duplex),
++                 __ETHTOOL_LINK_MODE_MASK_NBITS, pcs->advertising,
++                 __ETHTOOL_LINK_MODE_MASK_NBITS, pcs->lp_advertising,
++                 pcs->link, pcs->autoneg, pcs->autoneg_complete);
++}
++
++static void vsc9959_pcs_link_state_sgmii(struct phy_device *pcs,
++                                       struct phylink_link_state *state)
++{
++      int err;
++
++      err = genphy_update_link(pcs);
++      if (err < 0)
++              return;
++
++      if (pcs->autoneg_complete) {
++              u16 lpa = phy_read(pcs, MII_LPA);
++
++              mii_lpa_to_linkmode_lpa_sgmii(pcs->lp_advertising, lpa);
++
++              phy_resolve_aneg_linkmode(pcs);
++      }
++}
++
++static void vsc9959_pcs_link_state_2500basex(struct phy_device *pcs,
++                                           struct phylink_link_state *state)
++{
++      int err;
++
++      err = genphy_update_link(pcs);
++      if (err < 0)
++              return;
++
++      pcs->speed = SPEED_2500;
++      pcs->asym_pause = true;
++      pcs->pause = true;
++}
++
++static void vsc9959_pcs_link_state_usxgmii(struct phy_device *pcs,
++                                         struct phylink_link_state *state)
++{
++      int status, lpa;
++
++      status = phy_read_mmd(pcs, MDIO_MMD_VEND2, MII_BMSR);
++      if (status < 0)
++              return;
++
++      pcs->autoneg = true;
++      pcs->autoneg_complete = USXGMII_BMSR_AN_CMPL(status);
++      pcs->link = USXGMII_BMSR_LNKS(status);
++
++      if (!pcs->link || !pcs->autoneg_complete)
++              return;
++
++      lpa = phy_read_mmd(pcs, MDIO_MMD_VEND2, MII_LPA);
++      if (lpa < 0)
++              return;
++
++      switch (USXGMII_LPA_SPEED(lpa)) {
++      case USXGMII_SPEED_10:
++              pcs->speed = SPEED_10;
++              break;
++      case USXGMII_SPEED_100:
++              pcs->speed = SPEED_100;
++              break;
++      case USXGMII_SPEED_1000:
++              pcs->speed = SPEED_1000;
++              break;
++      case USXGMII_SPEED_2500:
++              pcs->speed = SPEED_2500;
++              break;
++      default:
++              break;
++      }
++
++      pcs->link = USXGMII_LPA_LNKS(lpa);
++      if (USXGMII_LPA_DUPLEX(lpa))
++              pcs->duplex = DUPLEX_FULL;
++      else
++              pcs->duplex = DUPLEX_HALF;
++}
++
++static void vsc9959_pcs_link_state(struct ocelot *ocelot, int port,
++                                 struct phylink_link_state *state)
++{
++      struct felix *felix = ocelot_to_felix(ocelot);
++      struct phy_device *pcs = felix->pcs[port];
++
++      if (!pcs)
++              return;
++
++      pcs->speed = SPEED_UNKNOWN;
++      pcs->duplex = DUPLEX_UNKNOWN;
++      pcs->pause = 0;
++      pcs->asym_pause = 0;
++
++      switch (pcs->interface) {
++      case PHY_INTERFACE_MODE_SGMII:
++      case PHY_INTERFACE_MODE_QSGMII:
++              vsc9959_pcs_link_state_sgmii(pcs, state);
++              break;
++      case PHY_INTERFACE_MODE_2500BASEX:
++              vsc9959_pcs_link_state_2500basex(pcs, state);
++              break;
++      case PHY_INTERFACE_MODE_USXGMII:
++              vsc9959_pcs_link_state_usxgmii(pcs, state);
++              break;
++      default:
++              return;
++      }
++
++      vsc9959_pcs_link_state_resolve(pcs, state);
++}
++
++static int vsc9959_prevalidate_phy_mode(struct ocelot *ocelot, int port,
++                                      phy_interface_t phy_mode)
++{
++      switch (phy_mode) {
++      case PHY_INTERFACE_MODE_GMII:
++              /* Only supported on internal to-CPU ports */
++              if (port != 4 && port != 5)
++                      return -ENOTSUPP;
++              return 0;
++      case PHY_INTERFACE_MODE_SGMII:
++      case PHY_INTERFACE_MODE_QSGMII:
++      case PHY_INTERFACE_MODE_USXGMII:
++      case PHY_INTERFACE_MODE_2500BASEX:
++              /* Not supported on internal to-CPU ports */
++              if (port == 4 || port == 5)
++                      return -ENOTSUPP;
++              return 0;
++      default:
++              return -ENOTSUPP;
++      }
++}
++
+ static const struct ocelot_ops vsc9959_ops = {
+       .reset                  = vsc9959_reset,
+ };
++static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
++{
++      struct felix *felix = ocelot_to_felix(ocelot);
++      struct enetc_mdio_priv *mdio_priv;
++      struct device *dev = ocelot->dev;
++      resource_size_t imdio_base;
++      void __iomem *imdio_regs;
++      struct resource *res;
++      struct enetc_hw *hw;
++      struct mii_bus *bus;
++      int port;
++      int rc;
++
++      felix->pcs = devm_kcalloc(dev, felix->info->num_ports,
++                                sizeof(struct phy_device *),
++                                GFP_KERNEL);
++      if (!felix->pcs) {
++              dev_err(dev, "failed to allocate array for PCS PHYs\n");
++              return -ENOMEM;
++      }
++
++      imdio_base = pci_resource_start(felix->pdev,
++                                      felix->info->imdio_pci_bar);
++
++      res = felix->info->imdio_res;
++      res->flags = IORESOURCE_MEM;
++      res->start += imdio_base;
++      res->end += imdio_base;
++
++      imdio_regs = devm_ioremap_resource(dev, res);
++      if (IS_ERR(imdio_regs)) {
++              dev_err(dev, "failed to map internal MDIO registers\n");
++              return PTR_ERR(imdio_regs);
++      }
++
++      hw = enetc_hw_alloc(dev, imdio_regs);
++      if (IS_ERR(hw)) {
++              dev_err(dev, "failed to allocate ENETC HW structure\n");
++              return PTR_ERR(hw);
++      }
++
++      bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
++      if (!bus)
++              return -ENOMEM;
++
++      bus->name = "VSC9959 internal MDIO bus";
++      bus->read = enetc_mdio_read;
++      bus->write = enetc_mdio_write;
++      bus->parent = dev;
++      mdio_priv = bus->priv;
++      mdio_priv->hw = hw;
++      /* This gets added to imdio_regs, which already maps addresses
++       * starting with the proper offset.
++       */
++      mdio_priv->mdio_base = 0;
++      snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
++
++      /* Needed in order to initialize the bus mutex lock */
++      rc = mdiobus_register(bus);
++      if (rc < 0) {
++              dev_err(dev, "failed to register MDIO bus\n");
++              return rc;
++      }
++
++      felix->imdio = bus;
++
++      for (port = 0; port < felix->info->num_ports; port++) {
++              struct ocelot_port *ocelot_port = ocelot->ports[port];
++              struct phy_device *pcs;
++              bool is_c45 = false;
++
++              if (ocelot_port->phy_mode == PHY_INTERFACE_MODE_USXGMII)
++                      is_c45 = true;
++
++              pcs = get_phy_device(felix->imdio, port, is_c45);
++              if (IS_ERR(pcs))
++                      continue;
++
++              pcs->interface = ocelot_port->phy_mode;
++              felix->pcs[port] = pcs;
++
++              dev_info(dev, "Found PCS at internal MDIO address %d\n", port);
++      }
++
++      return 0;
++}
++
++static void vsc9959_mdio_bus_free(struct ocelot *ocelot)
++{
++      struct felix *felix = ocelot_to_felix(ocelot);
++      int port;
++
++      for (port = 0; port < ocelot->num_phys_ports; port++) {
++              struct phy_device *pcs = felix->pcs[port];
++
++              if (!pcs)
++                      continue;
++
++              put_device(&pcs->mdio.dev);
++      }
++      mdiobus_unregister(felix->imdio);
++}
++
+ struct felix_info felix_info_vsc9959 = {
+       .target_io_res          = vsc9959_target_io_res,
+       .port_io_res            = vsc9959_port_io_res,
++      .imdio_res              = &vsc9959_imdio_res,
+       .regfields              = vsc9959_regfields,
+       .map                    = vsc9959_regmap,
+       .ops                    = &vsc9959_ops,
+@@ -583,5 +1075,12 @@ struct felix_info felix_info_vsc9959 = {
+       .num_stats              = ARRAY_SIZE(vsc9959_stats_layout),
+       .shared_queue_sz        = 128 * 1024,
+       .num_ports              = 6,
+-      .pci_bar                = 4,
++      .switch_pci_bar         = 4,
++      .imdio_pci_bar          = 0,
++      .mdio_bus_alloc         = vsc9959_mdio_bus_alloc,
++      .mdio_bus_free          = vsc9959_mdio_bus_free,
++      .pcs_init               = vsc9959_pcs_init,
++      .pcs_an_restart         = vsc9959_pcs_an_restart,
++      .pcs_link_state         = vsc9959_pcs_link_state,
++      .prevalidate_phy_mode   = vsc9959_prevalidate_phy_mode,
+ };
diff --git a/target/linux/layerscape/patches-5.4/701-net-0387-net-phy-vsc8514-enable-in-band-SGMII-auto-negotiatio.patch b/target/linux/layerscape/patches-5.4/701-net-0387-net-phy-vsc8514-enable-in-band-SGMII-auto-negotiatio.patch
new file mode 100644 (file)
index 0000000..8aaafe5
--- /dev/null
@@ -0,0 +1,56 @@
+From ebfedac745f6d747df2214e11a89ba44742b3def Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Fri, 27 Dec 2019 21:44:46 +0200
+Subject: [PATCH] net: phy: vsc8514: enable in-band SGMII auto-negotiation
+ setting
+
+The default in-band AN setting for the VSC8514 PHY is not very reliable:
+its out-of-reset state is with SerDes AN disabled, but certain boot
+firmware (such as U-Boot) enables it during the boot process.
+
+So its final state as seen by Linux depends on whether the U-Boot PHY
+driver has run or not.
+
+If SGMII auto-negotiation is enabled but not acknowledged by the MAC,
+the PHY does not pass traffic.
+
+But otherwise, it is able to pass traffic both with AN disabled, and
+with AN enabled.
+
+We would like to make this explicitly configurable rather than hardcoded
+as "on" as we are doing right now, but we'd rather hardcode it in LSDK
+and wait until a solution lands upstream, than invent a solution for
+this here.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+---
+ drivers/net/phy/mscc.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/net/phy/mscc.c
++++ b/drivers/net/phy/mscc.c
+@@ -176,6 +176,8 @@ enum rgmii_rx_clock_delay {
+ #define SECURE_ON_PASSWD_LEN_4                  0x4000
+ /* Extended Page 3 Registers */
++#define MSCC_PHY_SERDES_CON             16
++#define MSCC_PHY_SERDES_ANEG            BIT(7)
+ #define MSCC_PHY_SERDES_TX_VALID_CNT    21
+ #define MSCC_PHY_SERDES_TX_CRC_ERR_CNT          22
+ #define MSCC_PHY_SERDES_RX_VALID_CNT    28
+@@ -2131,6 +2133,14 @@ static int vsc8514_config_init(struct ph
+       mutex_unlock(&phydev->mdio.bus->mdio_lock);
++      ret = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_3);
++      if (ret)
++              return ret;
++
++      ret = phy_set_bits(phydev, MSCC_PHY_SERDES_CON, MSCC_PHY_SERDES_ANEG);
++      if (ret)
++              return ret;
++
+       ret = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+       if (ret)
diff --git a/target/linux/layerscape/patches-5.4/701-net-0388-drivers-net-phy-aquantia-Add-XFI-counters.patch b/target/linux/layerscape/patches-5.4/701-net-0388-drivers-net-phy-aquantia-Add-XFI-counters.patch
new file mode 100644 (file)
index 0000000..8c65e3a
--- /dev/null
@@ -0,0 +1,96 @@
+From 30da8769107ce2112f3dc356fd06f0fa5bed7742 Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Mon, 6 Jan 2020 17:57:10 +0200
+Subject: [PATCH] drivers: net: phy: aquantia: Add XFI counters
+
+Adds XFI counters and enables counters for AQR112/412.  These are gen 3
+PHYs, the register map is compatible with AQR107 which is gen 2.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ drivers/net/phy/aquantia_main.c | 27 ++++++++++++++++++++++++---
+ 1 file changed, 24 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/phy/aquantia_main.c
++++ b/drivers/net/phy/aquantia_main.c
+@@ -25,6 +25,12 @@
+ #define PHY_ID_AQR112 0x03a1b662
+ #define PHY_ID_AQR412 0x03a1b712
++/* PCS counters */
++#define MDIO_C45_PCS_STAT_XFI_TX_GOOD_FRAMES  0xc860
++#define MDIO_C45_PCS_STAT_XFI_TX_BAD_FRAMES   0xc862
++#define MDIO_C45_PCS_STAT_XFI_RX_GOOD_FRAMES  0xe860
++#define MDIO_C45_PCS_STAT_XFI_RX_BAD_FRAMES   0xe862
++
+ #define MDIO_PHYXS_VEND_IF_STATUS             0xe812
+ #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK   GENMASK(7, 3)
+ #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR     0
+@@ -153,9 +159,12 @@ struct aqr107_hw_stat {
+       const char *name;
+       int reg;
+       int size;
++      int devad;
+ };
+-#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s }
++#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s, \
++                            MDIO_MMD_C22EXT}
++#define C45_PCS_STAT(n, r, s) { n, MDIO_C45_PCS_STAT_ ## r, s, MDIO_MMD_PCS }
+ static const struct aqr107_hw_stat aqr107_hw_stats[] = {
+       SGMII_STAT("sgmii_rx_good_frames",          RX_GOOD_FRAMES,     26),
+       SGMII_STAT("sgmii_rx_bad_frames",           RX_BAD_FRAMES,      26),
+@@ -167,6 +176,10 @@ static const struct aqr107_hw_stat aqr10
+       SGMII_STAT("sgmii_tx_line_collisions",      TX_LINE_COLLISIONS,  8),
+       SGMII_STAT("sgmii_tx_frame_alignment_err",  TX_FRAME_ALIGN_ERR, 16),
+       SGMII_STAT("sgmii_tx_runt_frames",          TX_RUNT_FRAMES,     22),
++      C45_PCS_STAT("xfi_rx_good_frames",          XFI_RX_GOOD_FRAMES, 26),
++      C45_PCS_STAT("xfi_rx_bad_frames",           XFI_RX_BAD_FRAMES,  26),
++      C45_PCS_STAT("xfi_tx_good_frames",          XFI_TX_GOOD_FRAMES, 26),
++      C45_PCS_STAT("xfi_tx_bad_frames",           XFI_TX_BAD_FRAMES,  26),
+ };
+ #define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats)
+@@ -196,13 +209,13 @@ static u64 aqr107_get_stat(struct phy_de
+       u64 ret;
+       int val;
+-      val = phy_read_mmd(phydev, MDIO_MMD_C22EXT, stat->reg);
++      val = phy_read_mmd(phydev, stat->devad, stat->reg);
+       if (val < 0)
+               return U64_MAX;
+       ret = val & GENMASK(len_l - 1, 0);
+       if (len_h) {
+-              val = phy_read_mmd(phydev, MDIO_MMD_C22EXT, stat->reg + 1);
++              val = phy_read_mmd(phydev, stat->devad, stat->reg + 1);
+               if (val < 0)
+                       return U64_MAX;
+@@ -768,18 +781,26 @@ static struct phy_driver aqr_driver[] =
+ {
+       PHY_ID_MATCH_MODEL(PHY_ID_AQR112),
+       .name           = "Aquantia AQR112",
++      .probe          = aqr107_probe,
+       .config_aneg    = aqr_config_aneg_set_prot,
+       .config_intr    = aqr_config_intr,
+       .ack_interrupt  = aqr_ack_interrupt,
+       .read_status    = aqr_read_status,
++      .get_sset_count = aqr107_get_sset_count,
++      .get_strings    = aqr107_get_strings,
++      .get_stats      = aqr107_get_stats,
+ },
+ {
+       PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
+       .name           = "Aquantia AQR412",
++      .probe          = aqr107_probe,
+       .config_aneg    = aqr_config_aneg_set_prot,
+       .config_intr    = aqr_config_intr,
+       .ack_interrupt  = aqr_ack_interrupt,
+       .read_status    = aqr_read_status,
++      .get_sset_count = aqr107_get_sset_count,
++      .get_strings    = aqr107_get_strings,
++      .get_stats      = aqr107_get_stats,
+ },
+ };
diff --git a/target/linux/layerscape/patches-5.4/701-net-0389-drivers-net-felix-set-link-based-on-BMSR-not-LPA.patch b/target/linux/layerscape/patches-5.4/701-net-0389-drivers-net-felix-set-link-based-on-BMSR-not-LPA.patch
new file mode 100644 (file)
index 0000000..1d8f1f4
--- /dev/null
@@ -0,0 +1,23 @@
+From a40da00390f47fa698ef9ef9a2c82d427f6f8aa6 Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Tue, 7 Jan 2020 16:44:20 +0200
+Subject: [PATCH] drivers: net: felix: set link based on BMSR, not LPA
+
+At least some PHYs don't advertise link up during system side AN, rely on
+local indication from internal PHYs for link state.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ drivers/net/dsa/ocelot/felix_vsc9959.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
+@@ -896,7 +896,6 @@ static void vsc9959_pcs_link_state_usxgm
+               break;
+       }
+-      pcs->link = USXGMII_LPA_LNKS(lpa);
+       if (USXGMII_LPA_DUPLEX(lpa))
+               pcs->duplex = DUPLEX_FULL;
+       else
diff --git a/target/linux/layerscape/patches-5.4/701-net-0390-drivers-net-phylink-in-band-AN-for-USXGMII.patch b/target/linux/layerscape/patches-5.4/701-net-0390-drivers-net-phylink-in-band-AN-for-USXGMII.patch
new file mode 100644 (file)
index 0000000..a805c35
--- /dev/null
@@ -0,0 +1,35 @@
+From a1d37fce23d69a51a299b848d0a5700d64e6db4e Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Tue, 7 Jan 2020 16:48:05 +0200
+Subject: [PATCH] drivers: net: phylink: in-band AN for USXGMII
+
+USXGMII supports passing link information in-band between PHY and MAC PCS,
+add it to the list of protocls that support in-band AN mode.
+
+TODO:
+Add 2500baseT, 5GbaseT, 10GbaseT.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ drivers/net/phy/phylink.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -300,6 +300,16 @@ static int phylink_parse_mode(struct phy
+                       phylink_set(pl->supported, 2500baseX_Full);
+                       break;
++              case PHY_INTERFACE_MODE_USXGMII:
++                      phylink_set(pl->supported, 10baseT_Half);
++                      phylink_set(pl->supported, 10baseT_Full);
++                      phylink_set(pl->supported, 100baseT_Half);
++                      phylink_set(pl->supported, 100baseT_Full);
++                      phylink_set(pl->supported, 1000baseT_Half);
++                      phylink_set(pl->supported, 1000baseT_Full);
++                      phylink_set(pl->supported, 2500baseX_Full);
++                      break;
++
+               case PHY_INTERFACE_MODE_10GKR:
+                       phylink_set(pl->supported, 10baseT_Half);
+                       phylink_set(pl->supported, 10baseT_Full);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0391-drivers-net-phy-don-t-crash-in-phy_read-_write_mmd-w.patch b/target/linux/layerscape/patches-5.4/701-net-0391-drivers-net-phy-don-t-crash-in-phy_read-_write_mmd-w.patch
new file mode 100644 (file)
index 0000000..532715d
--- /dev/null
@@ -0,0 +1,35 @@
+From 8e515a39805c013229698e1a142e16701f07edf9 Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Tue, 7 Jan 2020 16:50:31 +0200
+Subject: [PATCH] drivers: net: phy: don't crash in phy_read/_write_mmd without
+ a PHY driver
+
+The APIs can be used by Ethernet drivers to configure internal PHYs
+without actually loading a PHY driver.  Check that drv is not NULL before
+reading from it.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ drivers/net/phy/phy-core.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/phy/phy-core.c
++++ b/drivers/net/phy/phy-core.c
+@@ -379,7 +379,7 @@ int __phy_read_mmd(struct phy_device *ph
+       if (regnum > (u16)~0 || devad > 32)
+               return -EINVAL;
+-      if (phydev->drv->read_mmd) {
++      if (phydev->drv && phydev->drv->read_mmd) {
+               val = phydev->drv->read_mmd(phydev, devad, regnum);
+       } else if (phydev->is_c45) {
+               u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
+@@ -436,7 +436,7 @@ int __phy_write_mmd(struct phy_device *p
+       if (regnum > (u16)~0 || devad > 32)
+               return -EINVAL;
+-      if (phydev->drv->write_mmd) {
++      if (phydev->drv && phydev->drv->write_mmd) {
+               ret = phydev->drv->write_mmd(phydev, devad, regnum, val);
+       } else if (phydev->is_c45) {
+               u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0392-drivers-net-dsa-felix-Allow-PHY-to-AN-10-100-1000-wi.patch b/target/linux/layerscape/patches-5.4/701-net-0392-drivers-net-dsa-felix-Allow-PHY-to-AN-10-100-1000-wi.patch
new file mode 100644 (file)
index 0000000..68c21a2
--- /dev/null
@@ -0,0 +1,34 @@
+From b3841e7de0be51ddb4e0d17ab0561a12c6db2753 Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Wed, 8 Jan 2020 12:34:33 +0200
+Subject: [PATCH] drivers: net: dsa: felix: Allow PHY to AN 10/100/1000 with
+ 2500 serdes link
+
+If the serdes link is set to 2500 using interfce type 2500base-X, lower
+link speeds over on the line side should still be supported.
+Rate adaptation is done out of band, in our case using AQR PHYs this is
+done using flow control.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ drivers/net/dsa/ocelot/felix.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -218,11 +218,10 @@ static void felix_phylink_validate(struc
+       phylink_set(mask, Autoneg);
+       phylink_set(mask, Pause);
+       phylink_set(mask, Asym_Pause);
+-      if (state->interface != PHY_INTERFACE_MODE_2500BASEX) {
+-              phylink_set(mask, 10baseT_Full);
+-              phylink_set(mask, 100baseT_Full);
+-              phylink_set(mask, 1000baseT_Full);
+-      }
++      phylink_set(mask, 10baseT_Full);
++      phylink_set(mask, 100baseT_Full);
++      phylink_set(mask, 1000baseT_Full);
++
+       /* The internal ports that run at 2.5G are overclocked GMII */
+       if (state->interface == PHY_INTERFACE_MODE_GMII ||
+           state->interface == PHY_INTERFACE_MODE_2500BASEX ||
diff --git a/target/linux/layerscape/patches-5.4/701-net-0393-drivers-net-dsa-felix-Handle-PAUSE-Rx-regardless-of-.patch b/target/linux/layerscape/patches-5.4/701-net-0393-drivers-net-dsa-felix-Handle-PAUSE-Rx-regardless-of-.patch
new file mode 100644 (file)
index 0000000..887ca36
--- /dev/null
@@ -0,0 +1,35 @@
+From 774408ea6a55b9d40b7bdc4ff4e33f1464c605c9 Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Wed, 8 Jan 2020 13:15:07 +0200
+Subject: [PATCH] drivers: net: dsa: felix: Handle PAUSE Rx regardless of AN
+ result
+
+Flow control is used with 2500Base-X and AQR PHYs to do rate adapation
+between line side 100/1000 links and MAC running at 2.5G.  This is
+independent of the flow control configuration settled on line side though
+AN.  In general allowing MAC to handle flow control even though AN did
+not enable it explicitly should not be a problem, so the patch enables
+it in all cases.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ drivers/net/dsa/ocelot/felix.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -267,8 +267,12 @@ static void felix_phylink_mac_config(str
+        * specification in incoming pause frames.
+        */
+       mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(state->speed);
+-      if (state->pause & MLO_PAUSE_RX)
+-              mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA;
++
++      /* handle Rx pause in all cases, with 2500base-X this is used for rate
++       * adaptation.
++       */
++      mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA;
++
+       if (state->pause & MLO_PAUSE_TX)
+               mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA |
+                             SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) |
diff --git a/target/linux/layerscape/patches-5.4/701-net-0394-drivers-net-mscc_ocelot-don-t-flood-unicast-traffic-.patch b/target/linux/layerscape/patches-5.4/701-net-0394-drivers-net-mscc_ocelot-don-t-flood-unicast-traffic-.patch
new file mode 100644 (file)
index 0000000..12a03b0
--- /dev/null
@@ -0,0 +1,39 @@
+From 714e8c634821b340c191a157e8c4e0b1afd53dfc Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Wed, 8 Jan 2020 15:21:53 +0200
+Subject: [PATCH] drivers: net: mscc_ocelot: don't flood unicast traffic to cpu
+
+Switch cpu port doesn't learn MAC addresses and the local bridge dev_addr
+must be explicitly added to the bridge.
+This is done whenever a port is added to a bridge, ports following the
+1st one will just overwrite the same entry.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ drivers/net/ethernet/mscc/ocelot.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -1680,6 +1680,8 @@ static int ocelot_port_obj_del(struct ne
+ int ocelot_port_bridge_join(struct ocelot *ocelot, int port,
+                           struct net_device *bridge)
+ {
++      struct ocelot_port *ocelot_port = ocelot->ports[port];
++
+       if (!ocelot->bridge_mask) {
+               ocelot->hw_bridge_dev = bridge;
+       } else {
+@@ -1691,6 +1693,12 @@ int ocelot_port_bridge_join(struct ocelo
+       ocelot->bridge_mask |= BIT(port);
++      /* Direct CPU traffic to PCU port, this should override any existing
++       * entries
++       */
++      ocelot_mact_learn(ocelot, PGID_CPU, bridge->dev_addr, ocelot_port->pvid,
++                        ENTRYTYPE_LOCKED);
++
+       return 0;
+ }
+ EXPORT_SYMBOL(ocelot_port_bridge_join);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0395-LF-183-sdk_fman-add-an-option-for-RTC-1588-timer-ini.patch b/target/linux/layerscape/patches-5.4/701-net-0395-LF-183-sdk_fman-add-an-option-for-RTC-1588-timer-ini.patch
new file mode 100644 (file)
index 0000000..138d2b6
--- /dev/null
@@ -0,0 +1,215 @@
+From f7ed64503d5e27571833b76acee721d00448fdec Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Mon, 2 Sep 2019 15:33:16 +0800
+Subject: [PATCH] LF-183 sdk_fman: add an option for RTC (1588 timer)
+ initialization and APIs
+
+The RTC (1588 timer) could be managed by either ptp_qoriq driver
+or sdk_fman RTC driver. So add an option for sdk_fman RTC
+(1588 timer) initialization and APIs, so that user could select
+it or not.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_fman/Kconfig    |  9 +++++++++
+ .../freescale/sdk_fman/Peripherals/FM/Makefile     |  3 ++-
+ .../freescale/sdk_fman/Peripherals/FM/fm.c         |  4 ++++
+ .../sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h     | 22 ++++++++++++++++++++++
+ .../freescale/sdk_fman/src/wrapper/lnxwrp_fm.c     | 18 +++++++++++++-----
+ 5 files changed, 50 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_fman/Kconfig
++++ b/drivers/net/ethernet/freescale/sdk_fman/Kconfig
+@@ -49,6 +49,15 @@ config FMAN_V3L
+ endchoice
+ endmenu
++config FSL_SDK_FMAN_RTC_API
++      bool "FMan RTC (1588 timer) APIs"
++      default n
++      help
++              This option enables RTC (1588 timer) initialization and
++              APIs support. The ptp_qoriq driver is not available if
++              it is selected for RTC (1588 timer). Neither of them
++              were not able to be used together.
++
+ config FMAN_MIB_CNT_OVF_IRQ_EN
+       bool "Enable the dTSEC MIB counters overflow interrupt"
+       default n
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Makefile
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Makefile
+@@ -19,5 +19,6 @@ obj-y                += Pcd/
+ obj-y         += SP/
+ obj-y         += Port/
+ obj-y         += HC/
+-obj-y         += Rtc/
+ obj-y         += MACSEC/
++
++obj-$(CONFIG_FSL_SDK_FMAN_RTC_API)    += Rtc/
+--- a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c
+@@ -602,8 +602,10 @@ do {
+         FM_G_CALL_10G_MAC_ISR(0);
+     if (pending & INTR_EN_10G_MAC1)
+         FM_G_CALL_10G_MAC_ISR(1);
++#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+     if (pending & INTR_EN_TMR)
+         p_Fm->intrMng[e_FM_EV_TMR].f_Isr(p_Fm->intrMng[e_FM_EV_TMR].h_SrcHandle);
++#endif
+ }
+ #if (DPAA_VERSION >= 11)
+@@ -4318,8 +4320,10 @@ void FM_EventIsr(t_Handle h_Fm)
+         p_Fm->intrMng[e_FM_EV_PRS].f_Isr(p_Fm->intrMng[e_FM_EV_PRS].h_SrcHandle);
+     if (pending & INTR_EN_PLCR)
+         p_Fm->intrMng[e_FM_EV_PLCR].f_Isr(p_Fm->intrMng[e_FM_EV_PLCR].h_SrcHandle);
++#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+     if (pending & INTR_EN_TMR)
+             p_Fm->intrMng[e_FM_EV_TMR].f_Isr(p_Fm->intrMng[e_FM_EV_TMR].h_SrcHandle);
++#endif
+     /* MAC events may belong to different partitions */
+     if (pending & INTR_EN_1G_MAC0)
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h
+@@ -802,6 +802,7 @@ int fm_mac_set_rx_pause_frames(
+ int fm_mac_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev,
+                                            bool en);
++#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+ int fm_rtc_enable(struct fm *fm_dev);
+ int fm_rtc_disable(struct fm *fm_dev);
+@@ -819,6 +820,27 @@ int fm_rtc_set_alarm(struct fm *fm_dev,
+ int fm_rtc_set_fiper(struct fm *fm_dev, uint32_t id,
+               uint64_t fiper);
++#else
++static inline int fm_rtc_enable(struct fm *fm_dev) { return 0; }
++
++static inline int fm_rtc_disable(struct fm *fm_dev) { return 0; }
++
++static inline int fm_rtc_get_cnt(struct fm *fm_dev, uint64_t *ts) { return 0; }
++
++static inline int fm_rtc_set_cnt(struct fm *fm_dev, uint64_t ts) { return 0; }
++
++static inline int fm_rtc_get_drift(struct fm *fm_dev, uint32_t *drift)
++{ return 0; }
++
++static inline int fm_rtc_set_drift(struct fm *fm_dev, uint32_t drift)
++{ return 0; }
++
++static inline int fm_rtc_set_alarm(struct fm *fm_dev, uint32_t id,
++                                 uint64_t time) { return 0; }
++
++static inline int fm_rtc_set_fiper(struct fm *fm_dev, uint32_t id,
++                                 uint64_t fiper) { return 0; }
++#endif
+ int fm_mac_set_wol(struct fm_port *port, struct fm_mac_dev *fm_mac_dev,
+                       bool en);
+--- a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
+@@ -695,11 +695,7 @@ static t_LnxWrpFmDev * ReadFmDevTreeNode
+         }
+     }
+-/* DPAA PTP timer was managed by ptp_qoriq driver in drivers/ptp/.
+- * We will no longer manage it in sdk_fman driver and use related
+- * APIs.
+- */
+-#if 0
++#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+     /* Get the RTC base address and size */
+     memset(ids, 0, sizeof(ids));
+     if (WARN_ON(strlen("ptp-timer") >= sizeof(ids[0].name)))
+@@ -941,6 +937,7 @@ static t_Error ConfigureFmDev(t_LnxWrpFm
+     if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmMuramBaseAddr, (uint64_t)p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize) != E_OK)
+         RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM MURAM memory map"));
++#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+     if (p_LnxWrpFmDev->fmRtcPhysBaseAddr)
+     {
+         dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize, "fman-ptp-timer");
+@@ -954,6 +951,7 @@ static t_Error ConfigureFmDev(t_LnxWrpFm
+         if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmRtcBaseAddr, (uint64_t)p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize) != E_OK)
+             RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC memory map"));
+     }
++#endif
+ #if (DPAA_VERSION >= 11)
+     if (p_LnxWrpFmDev->fmVspPhysBaseAddr) {
+@@ -1187,6 +1185,7 @@ static t_Error InitFmDev(t_LnxWrpFmDev
+          * FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_MURAM_ECC,FALSE);*/
+     }
++#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+     if (p_LnxWrpFmDev->fmRtcBaseAddr)
+     {
+         t_FmRtcParams   fmRtcParam;
+@@ -1205,6 +1204,7 @@ static t_Error InitFmDev(t_LnxWrpFmDev
+         if (FM_RTC_Init(p_LnxWrpFmDev->h_RtcDev) != E_OK)
+             RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC"));
+     }
++#endif
+     return E_OK;
+ }
+@@ -1219,8 +1219,10 @@ static void FreeFmDev(t_LnxWrpFmDev  *p_
+     FreeFmPcdDev(p_LnxWrpFmDev);
++#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+     if (p_LnxWrpFmDev->h_RtcDev)
+       FM_RTC_Free(p_LnxWrpFmDev->h_RtcDev);
++#endif
+     if (p_LnxWrpFmDev->h_Dev)
+         FM_Free(p_LnxWrpFmDev->h_Dev);
+@@ -1228,12 +1230,14 @@ static void FreeFmDev(t_LnxWrpFmDev  *p_
+     if (p_LnxWrpFmDev->h_MuramDev)
+         FM_MURAM_Free(p_LnxWrpFmDev->h_MuramDev);
++#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+     if (p_LnxWrpFmDev->fmRtcBaseAddr)
+     {
+         SYS_UnregisterIoMap(p_LnxWrpFmDev->fmRtcBaseAddr);
+         devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmRtcBaseAddr));
+         __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize);
+     }
++#endif
+     SYS_UnregisterIoMap(p_LnxWrpFmDev->fmMuramBaseAddr);
+     devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmMuramBaseAddr));
+     __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize);
+@@ -1463,6 +1467,7 @@ void * fm_get_handle(struct fm *fm)
+ }
+ EXPORT_SYMBOL(fm_get_handle);
++#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+ void * fm_get_rtc_handle(struct fm *fm)
+ {
+     t_LnxWrpFmDev       *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm;
+@@ -1470,6 +1475,7 @@ void * fm_get_rtc_handle(struct fm *fm)
+     return (void *)p_LnxWrpFmDev->h_RtcDev;
+ }
+ EXPORT_SYMBOL(fm_get_rtc_handle);
++#endif
+ struct fm_port * fm_port_bind (struct device *fm_port_dev)
+ {
+@@ -2053,6 +2059,7 @@ int fm_mac_set_tx_pause_frames(struct fm
+ #endif
+ EXPORT_SYMBOL(fm_mac_set_tx_pause_frames);
++#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+ int fm_rtc_enable(struct fm *fm_dev)
+ {
+       int                      _errno;
+@@ -2209,6 +2216,7 @@ int fm_rtc_disable_interrupt(struct fm *
+ }
+ EXPORT_SYMBOL(fm_rtc_disable_interrupt);
+ #endif
++#endif /* CONFIG_FSL_SDK_FMAN_RTC_API */
+ int fm_mac_set_wol(struct fm_port *port, struct fm_mac_dev *fm_mac_dev, bool en)
+ {
diff --git a/target/linux/layerscape/patches-5.4/701-net-0396-LF-183-ptp-depend-on-FSL_SDK_FMAN_RTC_API-for-ptp_qo.patch b/target/linux/layerscape/patches-5.4/701-net-0396-LF-183-ptp-depend-on-FSL_SDK_FMAN_RTC_API-for-ptp_qo.patch
new file mode 100644 (file)
index 0000000..09021db
--- /dev/null
@@ -0,0 +1,27 @@
+From 9dad88f61f7400939a4076b641b6cd80904358cf Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Thu, 5 Dec 2019 15:03:05 +0800
+Subject: [PATCH] LF-183 ptp: depend on !FSL_SDK_FMAN_RTC_API for ptp_qoriq
+
+When kernel uses SDK version DPAA/FMan drivers, user could
+select to use ptp_qoriq driver, or FMan RTC driver to manage
+1588 timer. But neither should not be enabled together.
+This patch is to add dependency !FSL_SDK_FMAN_RTC_API for
+ptp_qoriq driver.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/ptp/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/ptp/Kconfig
++++ b/drivers/ptp/Kconfig
+@@ -44,7 +44,7 @@ config PTP_1588_CLOCK_DTE
+ config PTP_1588_CLOCK_QORIQ
+       tristate "Freescale QorIQ 1588 timer as PTP clock"
+-      depends on GIANFAR || FSL_DPAA_ETH || FSL_SDK_DPAA_ETH || FSL_DPAA2_ETH || FSL_ENETC || FSL_ENETC_VF || COMPILE_TEST
++      depends on !FSL_SDK_FMAN_RTC_API && (GIANFAR || FSL_DPAA_ETH || FSL_SDK_DPAA_ETH || FSL_DPAA2_ETH || FSL_ENETC || FSL_ENETC_VF) || COMPILE_TEST
+       depends on PTP_1588_CLOCK
+       default y
+       help
diff --git a/target/linux/layerscape/patches-5.4/701-net-0397-sdk_dpaa-ceetm-fix-recursive-dependencies.patch b/target/linux/layerscape/patches-5.4/701-net-0397-sdk_dpaa-ceetm-fix-recursive-dependencies.patch
new file mode 100644 (file)
index 0000000..dff27a4
--- /dev/null
@@ -0,0 +1,132 @@
+From 03117a1e7db4cd3d745c663c697e446695ebb8e1 Mon Sep 17 00:00:00 2001
+From: Camelia Groza <camelia.groza@nxp.com>
+Date: Wed, 8 Jan 2020 18:41:33 +0200
+Subject: [PATCH] sdk_dpaa: ceetm: fix recursive dependencies
+
+Due to dependencies between the fsl_ceetm and fsl_dpa modules, remove
+the module support for the ceetm driver and integrate it into the main
+DPAA Ethernet driver.
+
+The registration of the CEETM Qdisc was the only operation done at
+module init. Pass the management of the Qdisc register and unregister
+operations to the loading and unloading of the DPAA driver.
+
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+---
+ drivers/net/ethernet/freescale/sdk_dpaa/Makefile   |  3 +-
+ drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c | 19 +++++++++++++
+ .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 32 +---------------------
+ 3 files changed, 21 insertions(+), 33 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/Makefile
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/Makefile
+@@ -20,8 +20,7 @@ endif
+ ifeq ($(CONFIG_FSL_DPAA_CEETM),y)
+ ccflags-y += -I$(srctree)/drivers/net/ethernet/freescale/sdk_fman/src/wrapper
+-obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_ceetm.o
+-fsl_ceetm-objs += dpaa_eth_ceetm.o
++fsl_dpa-objs += dpaa_eth_ceetm.o
+ endif
+ fsl_mac-objs += mac.o mac-api.o
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
+@@ -72,6 +72,9 @@
+ #ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ #include "dpaa_debugfs.h"
+ #endif /* CONFIG_FSL_DPAA_DBG_LOOP */
++#ifdef CONFIG_FSL_DPAA_CEETM
++#include "dpaa_eth_ceetm.h"
++#endif
+ /* CREATE_TRACE_POINTS only needs to be defined once. Other dpa files
+  * using trace events only need to #include <trace/events/sched.h>
+@@ -116,6 +119,10 @@ static uint8_t dpa_priv_common_bpid;
+ struct net_device *dpa_loop_netdevs[20];
+ #endif
++#ifdef CONFIG_FSL_DPAA_CEETM
++extern struct Qdisc_ops ceetm_qdisc_ops;
++#endif
++
+ #ifdef CONFIG_PM
+ static int dpaa_suspend(struct device *dev)
+@@ -1158,6 +1165,14 @@ static int __init __cold dpa_load(void)
+       pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
+               KBUILD_BASENAME".c", __func__);
++#ifdef CONFIG_FSL_DPAA_CEETM
++      _errno = register_qdisc(&ceetm_qdisc_ops);
++      if (unlikely(_errno))
++              pr_err(KBUILD_MODNAME
++                     ": %s:%hu:%s(): register_qdisc() = %d\n",
++                     KBUILD_BASENAME ".c", __LINE__, __func__, _errno);
++#endif
++
+       return _errno;
+ }
+ module_init(dpa_load);
+@@ -1167,6 +1182,10 @@ static void __exit __cold dpa_unload(voi
+       pr_debug(KBUILD_MODNAME ": -> %s:%s()\n",
+               KBUILD_BASENAME".c", __func__);
++#ifdef CONFIG_FSL_DPAA_CEETM
++      unregister_qdisc(&ceetm_qdisc_ops);
++#endif
++
+       platform_driver_unregister(&dpa_driver);
+ #ifdef CONFIG_FSL_DPAA_DBG_LOOP
+--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+@@ -33,16 +33,13 @@
+ #include <linux/init.h>
+ #include "dpaa_eth_ceetm.h"
+-#define DPA_CEETM_DESCRIPTION "FSL DPAA CEETM qdisc"
+-MODULE_LICENSE("Dual BSD/GPL");
+-MODULE_DESCRIPTION(DPA_CEETM_DESCRIPTION);
+-
+ const struct nla_policy ceetm_policy[TCA_CEETM_MAX + 1] = {
+       [TCA_CEETM_COPT] = { .len = sizeof(struct tc_ceetm_copt) },
+       [TCA_CEETM_QOPS] = { .len = sizeof(struct tc_ceetm_qopt) },
+ };
+ struct Qdisc_ops ceetm_qdisc_ops;
++EXPORT_SYMBOL(ceetm_qdisc_ops);
+ /* Obtain the DCP and the SP ids from the FMan port */
+ static void get_dcp_and_sp(struct net_device *dev, enum qm_dc_portal *dcp_id,
+@@ -2086,30 +2083,3 @@ drop:
+       dev_kfree_skb_any(skb);
+       return NET_XMIT_SUCCESS;
+ }
+-EXPORT_SYMBOL(ceetm_tx);
+-
+-static int __init ceetm_register(void)
+-{
+-      int _errno = 0;
+-
+-      pr_info(KBUILD_MODNAME ": " DPA_CEETM_DESCRIPTION "\n");
+-
+-      _errno = register_qdisc(&ceetm_qdisc_ops);
+-      if (unlikely(_errno))
+-              pr_err(KBUILD_MODNAME
+-                     ": %s:%hu:%s(): register_qdisc() = %d\n",
+-                     KBUILD_BASENAME ".c", __LINE__, __func__, _errno);
+-
+-      return _errno;
+-}
+-
+-static void __exit ceetm_unregister(void)
+-{
+-      pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
+-               KBUILD_BASENAME ".c", __func__);
+-
+-      unregister_qdisc(&ceetm_qdisc_ops);
+-}
+-
+-module_init(ceetm_register);
+-module_exit(ceetm_unregister);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0398-enetc-add-ioctl-support-for-PHY-related-ops.patch b/target/linux/layerscape/patches-5.4/701-net-0398-enetc-add-ioctl-support-for-PHY-related-ops.patch
new file mode 100644 (file)
index 0000000..bb3f926
--- /dev/null
@@ -0,0 +1,30 @@
+From d3fe9bfb9c854ce3acb7db099d9c9476e4fe2ea7 Mon Sep 17 00:00:00 2001
+From: Michael Walle <michael@walle.cc>
+Date: Thu, 7 Nov 2019 09:39:37 +0100
+Subject: [PATCH] enetc: add ioctl() support for PHY-related ops
+
+If there is an attached PHY try to handle the requested ioctl with its
+handler, which allows the userspace to access PHY registers, for
+example. This will make mii-diag and similar tools work.
+
+Signed-off-by: Michael Walle <michael@walle.cc>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/freescale/enetc/enetc.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc.c
+@@ -1661,7 +1661,10 @@ int enetc_ioctl(struct net_device *ndev,
+       if (cmd == SIOCGHWTSTAMP)
+               return enetc_hwtstamp_get(ndev, rq);
+ #endif
+-      return -EINVAL;
++
++      if (!ndev->phydev)
++              return -EINVAL;
++      return phy_mii_ioctl(ndev->phydev, rq, cmd);
+ }
+ int enetc_alloc_msix(struct enetc_ndev_priv *priv)
diff --git a/target/linux/layerscape/patches-5.4/701-net-0399-staging-fsl_ppfe-eth-Enhance-error-checking-in-platf.patch b/target/linux/layerscape/patches-5.4/701-net-0399-staging-fsl_ppfe-eth-Enhance-error-checking-in-platf.patch
new file mode 100644 (file)
index 0000000..a42e9aa
--- /dev/null
@@ -0,0 +1,38 @@
+From 1ccc18ca96d8a824f2af45d1046d23ccdb90f3df Mon Sep 17 00:00:00 2001
+From: Anji Jagarlmudi <anji.jagarlmudi@nxp.com>
+Date: Wed, 8 Jan 2020 12:18:40 +0530
+Subject: [PATCH] staging: fsl_ppfe/eth: Enhance error checking in platform
+ probe
+
+Fix the kernel crash when MAC addr is not passed in dtb.
+
+Signed-off-by: Anji Jagarlmudi <anji.jagarlmudi@nxp.com>
+---
+ drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
++++ b/drivers/staging/fsl_ppfe/pfe_ls1012a_platform.c
+@@ -29,15 +29,19 @@ static int pfe_get_gemac_if_properties(s
+       int size;
+       int phy_id = 0;
+       const u32 *addr;
+-      const void *mac_addr;
++      const u8 *mac_addr;
+       addr = of_get_property(gem, "reg", &size);
+-      port = be32_to_cpup(addr);
++      if (addr)
++              port = be32_to_cpup(addr);
++      else
++              goto err;
++
+       pdata->ls1012a_eth_pdata[port].gem_id = port;
+       mac_addr = of_get_mac_address(gem);
+-      if (mac_addr) {
++      if (!IS_ERR_OR_NULL(mac_addr)) {
+               memcpy(pdata->ls1012a_eth_pdata[port].mac_addr, mac_addr,
+                      ETH_ALEN);
+       }
diff --git a/target/linux/layerscape/patches-5.4/701-net-0400-drivers-staging-fsl_qbman-Disable-Portal-Channel-IRQ.patch b/target/linux/layerscape/patches-5.4/701-net-0400-drivers-staging-fsl_qbman-Disable-Portal-Channel-IRQ.patch
new file mode 100644 (file)
index 0000000..d9e4b43
--- /dev/null
@@ -0,0 +1,31 @@
+From 09269e71bfe9ff445ba42e2b88b17d323e434896 Mon Sep 17 00:00:00 2001
+From: Roy Pledge <roy.pledge@nxp.com>
+Date: Mon, 16 Dec 2019 16:59:32 -0500
+Subject: [PATCH] drivers/staging/fsl_qbman: Disable Portal Channel IRQs
+
+Disable portal channel IRQs to avoid them stopping QBMan from
+entering idle mode. Since push mode is used in this driver these
+interrupts are not needed/used.
+
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+(cherry picked from commit 977cf95ef173bf22b1816e7dbafcbb0f8a151133)
+---
+ drivers/staging/fsl_qbman/qman_high.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl_qbman/qman_high.c
++++ b/drivers/staging/fsl_qbman/qman_high.c
+@@ -737,7 +737,12 @@ struct qman_portal *qman_create_portal(
+       }
+       /* Success */
+       portal->config = config;
+-      qm_isr_disable_write(__p, 0);
++      /*
++       * Undisable all the IRQs except the dequeue available bits.
++       * If left enabled they cause problems with sleep mode. Since
++       * they are not used in push mode we can safely turn them off
++       */
++      qm_isr_disable_write(__p, QM_DQAVAIL_MASK);
+       qm_isr_uninhibit(__p);
+       /* Write a sane SDQCR */
+       qm_dqrr_sdqcr_set(__p, portal->sdqcr);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0401-fsl_qbman-Framework-for-enabling-Link-status-notific.patch b/target/linux/layerscape/patches-5.4/701-net-0401-fsl_qbman-Framework-for-enabling-Link-status-notific.patch
new file mode 100644 (file)
index 0000000..b476751
--- /dev/null
@@ -0,0 +1,385 @@
+From 136d46d2fa27815cc4cc3a57d5e3d54523028768 Mon Sep 17 00:00:00 2001
+From: Sachin Saxena <sachin.saxena@nxp.com>
+Date: Thu, 19 Dec 2019 12:57:35 +0530
+Subject: [PATCH] fsl_qbman: Framework for enabling Link status notification
+
+ -  This will enable link update event notification for
+    user space USDPAA application.
+
+Signed-off-by: Sachin Saxena <sachin.saxena@nxp.com>
+DPDK-2128
+(cherry picked from commit fb53c813a779cc3fc28c8ed3fc8bc0dde24db0ea)
+---
+ drivers/staging/fsl_qbman/Makefile     |   4 +
+ drivers/staging/fsl_qbman/fsl_usdpaa.c | 278 ++++++++++++++++++++++++++++++++-
+ include/linux/fsl_usdpaa.h             |  32 ++++
+ 3 files changed, 313 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/fsl_qbman/Makefile
++++ b/drivers/staging/fsl_qbman/Makefile
+@@ -1,5 +1,9 @@
+ subdir-ccflags-y := -Werror
++# Include netcomm SW specific definitions
++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
++ccflags-y += -I$(NET_DPA)
++
+ # Common
+ obj-$(CONFIG_FSL_SDK_DPA)             += dpa_alloc.o
+ obj-$(CONFIG_FSL_SDK_DPA)     += qbman_driver.o
+--- a/drivers/staging/fsl_qbman/fsl_usdpaa.c
++++ b/drivers/staging/fsl_qbman/fsl_usdpaa.c
+@@ -18,6 +18,8 @@
+ #include <linux/slab.h>
+ #include <linux/mman.h>
+ #include <linux/of_reserved_mem.h>
++#include <linux/eventfd.h>
++#include <linux/fdtable.h>
+ #if !(defined(CONFIG_ARM) || defined(CONFIG_ARM64))
+ #include <mm/mmu_decl.h>
+@@ -27,6 +29,26 @@
+ #include <linux/fsl_usdpaa.h>
+ #include "bman_low.h"
+ #include "qman_low.h"
++/* Headers requires for
++ * Link status support
++ */
++#include <linux/device.h>
++#include <linux/of_mdio.h>
++#include "mac.h"
++#include "dpaa_eth_common.h"
++
++/* Private data for Proxy Interface */
++struct dpa_proxy_priv_s {
++      struct mac_device       *mac_dev;
++      struct eventfd_ctx      *efd_ctx;
++};
++/* Interface Helpers */
++static inline struct device *get_dev_ptr(char *if_name);
++static void phy_link_updates(struct net_device *net_dev);
++/* IOCTL handlers */
++static inline int ioctl_usdpaa_get_link_status(char *if_name);
++static int ioctl_en_if_link_status(struct usdpaa_ioctl_link_status *args);
++static int ioctl_disable_if_link_status(char *if_name);
+ /* Physical address range of the memory reservation, exported for mm/mem.c */
+ static u64 phys_start;
+@@ -556,7 +578,6 @@ static bool check_portal_channel(void *c
+-
+ static int usdpaa_release(struct inode *inode, struct file *filp)
+ {
+       int err = 0;
+@@ -1656,6 +1677,220 @@ found:
+       return 0;
+ }
++
++static inline struct device *get_dev_ptr(char *if_name)
++{
++      struct device *dev;
++      char node[NODE_NAME_LEN];
++
++      sprintf(node, "soc:fsl,dpaa:%s",if_name);
++      dev = bus_find_device_by_name(&platform_bus_type, NULL, node);
++      if (dev == NULL) {
++              pr_err(KBUILD_MODNAME "IF %s not found\n", if_name);
++              return NULL;
++      }
++      pr_debug("%s: found dev 0x%lX  for If %s ,dev->platform_data %p\n",
++                        __func__, (unsigned long)dev,
++                        if_name, dev->platform_data);
++
++      return dev;
++}
++
++/* This function will return Current link status of the device
++ * '1' if Link is UP, '0' otherwise.
++ *
++ * Input parameter:
++ * if_name: Interface node name
++ *
++ */
++static inline int ioctl_usdpaa_get_link_status(char *if_name)
++{
++      struct net_device *net_dev = NULL;
++      struct device *dev;
++
++      dev = get_dev_ptr(if_name);
++      if (dev == NULL)
++              return -ENODEV;
++      net_dev = dev->platform_data;
++      if (net_dev == NULL)
++              return -ENODEV;
++
++      if (test_bit(__LINK_STATE_NOCARRIER, &net_dev->state))
++              return 0; /* Link is DOWN */
++      else
++              return 1; /* Link is UP */
++}
++
++
++/* Link Status Callback Function
++ * This function will be resgitered to PHY framework to get
++ * Link update notifications and should be responsible for waking up
++ * user space task when there is a link update notification.
++ */
++static void phy_link_updates(struct net_device *net_dev)
++{
++      struct dpa_proxy_priv_s *priv = NULL;
++
++      pr_debug("%s: Link '%s': Speed '%d-Mbps': Autoneg '%d': Duplex '%d'\n",
++              net_dev->name,
++              ioctl_usdpaa_get_link_status(net_dev->name)?"UP":"DOWN",
++              net_dev->phydev->speed,
++              net_dev->phydev->autoneg,
++              net_dev->phydev->duplex);
++
++      /* Wake up the user space context to notify PHY update */
++      priv = netdev_priv(net_dev);
++      eventfd_signal(priv->efd_ctx, 1);
++}
++
++
++/* IOCTL handler for enabling Link status request for a given interface
++ * Input parameters:
++ * args->if_name:     This the network interface node name as defind in
++ *                    device tree file. Currently, it has format of
++ *                    "ethernet@x" type for each interface.
++ * args->efd:         The eventfd value which should be waked up when
++ *                    there is any link update received.
++ */
++static int ioctl_en_if_link_status(struct usdpaa_ioctl_link_status *args)
++{
++      struct net_device *net_dev = NULL;
++      struct dpa_proxy_priv_s *priv = NULL;
++      struct device *dev;
++      struct mac_device *mac_dev;
++      struct proxy_device *proxy_dev;
++      struct task_struct *userspace_task = NULL;
++      struct file *efd_file = NULL;
++
++      dev = get_dev_ptr(args->if_name);
++      if (dev == NULL)
++              return -ENODEV;
++      /* Utilize dev->platform_data to save netdevice
++         pointer as it will not be registered */
++      if (dev->platform_data) {
++              pr_debug("%s: IF %s already initialized\n",
++                      __func__, args->if_name);
++              /* This will happen when application is not able to initiate
++               * cleanup in last run. We still need to save the new
++               * eventfd context.
++               */
++              net_dev = dev->platform_data;
++              priv = netdev_priv(net_dev);
++
++              /* Get current task context from which IOCTL was called */
++              userspace_task = current;
++
++              rcu_read_lock();
++              efd_file = fcheck_files(userspace_task->files, args->efd);
++              rcu_read_unlock();
++
++              priv->efd_ctx = eventfd_ctx_fileget(efd_file);
++              if (!priv->efd_ctx) {
++                      pr_err(KBUILD_MODNAME "get eventfd context failed\n");
++                      /* Free the allocated memory for net device */
++                      dev->platform_data = NULL;
++                      free_netdev(net_dev);
++                      return -EINVAL;
++              }
++              /* Since there will be NO PHY update as link is already setup,
++               * wake user context once so that current PHY status can
++               * be fetched.
++               */
++              phy_link_updates(net_dev);
++              return 0;
++      }
++
++      proxy_dev = dev_get_drvdata(dev);
++      mac_dev =  proxy_dev->mac_dev;
++      /* Allocate an dummy net device for proxy interface */
++      net_dev = alloc_etherdev(sizeof(*priv));
++      if (!net_dev) {
++              pr_err(KBUILD_MODNAME "alloc_etherdev failed\n");
++              return -ENOMEM;
++      } else {
++              SET_NETDEV_DEV(net_dev, dev);
++              priv = netdev_priv(net_dev);
++              priv->mac_dev = mac_dev;
++              /* Get current task context from which IOCTL was called */
++              userspace_task = current;
++
++              rcu_read_lock();
++              efd_file = fcheck_files(userspace_task->files, args->efd);
++              rcu_read_unlock();
++
++              priv->efd_ctx = eventfd_ctx_fileget(efd_file);
++
++              if (!priv->efd_ctx) {
++                      pr_err(KBUILD_MODNAME "get eventfd context failed\n");
++                      /* Free the allocated memory for net device */
++                      free_netdev(net_dev);
++                      return -EINVAL;
++              }
++              strncpy(net_dev->name, args->if_name, IF_NAME_MAX_LEN);
++              dev->platform_data = net_dev;
++      }
++
++      pr_debug("%s: mac_dev %p cell_index %d\n",
++              __func__, mac_dev, mac_dev->cell_index);
++      mac_dev->phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
++                               phy_link_updates, 0, mac_dev->phy_if);
++      if (unlikely(mac_dev->phy_dev == NULL) || IS_ERR(mac_dev->phy_dev)) {
++              pr_err("%s: --------Error in PHY Connect\n", __func__);
++              /* Free the allocated memory for net device */
++              free_netdev(net_dev);
++              return -ENODEV;
++      }
++      net_dev->phydev = mac_dev->phy_dev;
++      mac_dev->start(mac_dev);
++      pr_debug("%s: --- PHY connected for %s\n", __func__, args->if_name);
++
++      return 0;
++}
++
++/* IOCTL handler for disabling Link status for a given interface
++ * Input parameters:
++ * if_name:   This the network interface node name as defind in
++ *            device tree file. Currently, it has format of
++ *            "ethernet@x" type for each interface.
++ */
++static int ioctl_disable_if_link_status(char *if_name)
++{
++      struct net_device *net_dev = NULL;
++      struct device *dev;
++      struct mac_device *mac_dev;
++      struct proxy_device *proxy_dev;
++      struct dpa_proxy_priv_s *priv = NULL;
++
++      dev = get_dev_ptr(if_name);
++      if (dev == NULL)
++              return -ENODEV;
++      /* Utilize dev->platform_data to save netdevice
++         pointer as it will not be registered */
++      if (!dev->platform_data) {
++              pr_debug("%s: IF %s already Disabled for Link status\n",
++                      __func__, if_name);
++              return 0;
++      }
++
++      net_dev = dev->platform_data;
++      proxy_dev = dev_get_drvdata(dev);
++      mac_dev =  proxy_dev->mac_dev;
++      mac_dev->stop(mac_dev);
++
++      priv = netdev_priv(net_dev);
++      eventfd_ctx_put(priv->efd_ctx);
++
++      /* This will also deregister the call back */
++      phy_disconnect(mac_dev->phy_dev);
++      phy_resume(mac_dev->phy_dev);
++
++      free_netdev(net_dev);
++      dev->platform_data = NULL;
++
++      pr_debug("%s: Link status Disabled for %s\n", __func__, if_name);
++      return 0;
++}
++
+ static long usdpaa_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+ {
+       struct ctx *ctx = fp->private_data;
+@@ -1722,6 +1957,47 @@ static long usdpaa_ioctl(struct file *fp
+                       return -EFAULT;
+               return ioctl_free_raw_portal(fp, ctx, &input);
+       }
++      case USDPAA_IOCTL_ENABLE_LINK_STATUS_INTERRUPT:
++      {
++              struct usdpaa_ioctl_link_status input;
++              int ret;
++
++              if (copy_from_user(&input, a, sizeof(input)))
++                      return -EFAULT;
++              ret = ioctl_en_if_link_status(&input);
++              if (ret)
++                      pr_err("Error(%d) enable link interrupt:IF: %s\n",
++                              ret, input.if_name);
++              return ret;
++      }
++      case USDPAA_IOCTL_DISABLE_LINK_STATUS_INTERRUPT:
++      {
++              char *input;
++              int ret;
++
++              if (copy_from_user(&input, a, sizeof(input)))
++                      return -EFAULT;
++              ret = ioctl_disable_if_link_status(input);
++              if (ret)
++                      pr_err("Error(%d) Disabling link interrupt:IF: %s\n",
++                              ret, input);
++              return ret;
++      }
++      case USDPAA_IOCTL_GET_LINK_STATUS:
++      {
++              struct usdpaa_ioctl_link_status_args input;
++
++              if (copy_from_user(&input, a, sizeof(input)))
++                      return -EFAULT;
++
++              input.link_status = ioctl_usdpaa_get_link_status(input.if_name);
++              if (input.link_status < 0)
++                      return input.link_status;
++              if (copy_to_user(a, &input, sizeof(input)))
++                      return -EFAULT;
++
++              return 0;
++      }
+       }
+       return -EINVAL;
+ }
+--- a/include/linux/fsl_usdpaa.h
++++ b/include/linux/fsl_usdpaa.h
+@@ -365,6 +365,38 @@ int dpa_alloc_pop(struct dpa_alloc *allo
+ int dpa_alloc_check(struct dpa_alloc *list, u32 id);
+ #endif /* __KERNEL__ */
++
++/************************************
++ * Link Status support for user space
++ * interface
++ ************************************/
++#define IF_NAME_MAX_LEN 16
++#define NODE_NAME_LEN 32
++
++struct usdpaa_ioctl_link_status {
++      /* network device node name */
++      char            if_name[IF_NAME_MAX_LEN];
++      /* Eventfd value */
++      uint32_t        efd;
++};
++
++#define USDPAA_IOCTL_ENABLE_LINK_STATUS_INTERRUPT \
++      _IOW(USDPAA_IOCTL_MAGIC, 0x0E, struct usdpaa_ioctl_link_status)
++
++#define USDPAA_IOCTL_DISABLE_LINK_STATUS_INTERRUPT \
++      _IOW(USDPAA_IOCTL_MAGIC, 0x0F, char *)
++
++struct usdpaa_ioctl_link_status_args {
++      /* network device node name */
++      char    if_name[IF_NAME_MAX_LEN];
++      /* link status(UP/DOWN) */
++      int     link_status;
++};
++
++#define USDPAA_IOCTL_GET_LINK_STATUS \
++      _IOWR(USDPAA_IOCTL_MAGIC, 0x10, struct usdpaa_ioctl_link_status_args)
++
++
+ #ifdef __cplusplus
+ }
+ #endif
diff --git a/target/linux/layerscape/patches-5.4/701-net-0402-drivers-net-dsa-felix-don-t-restart-PCS-SGMII-AN-if-.patch b/target/linux/layerscape/patches-5.4/701-net-0402-drivers-net-dsa-felix-don-t-restart-PCS-SGMII-AN-if-.patch
new file mode 100644 (file)
index 0000000..5008ca5
--- /dev/null
@@ -0,0 +1,41 @@
+From 2a2ccfa44e56c45dfd1230f6efb3ec0a4a677f0a Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Wed, 15 Jan 2020 15:49:11 +0200
+Subject: [PATCH] drivers: net: dsa: felix: don't restart PCS SGMII AN if not
+ needed
+
+Some PHYs like VSC8234 don't like it when AN restarts on their system side
+and they restart line side AN too, going into an endless link up/down loop.
+Don't restart PCS AN if link is up already.
+
+Suggested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+---
+ drivers/net/dsa/ocelot/felix_vsc9959.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
+@@ -648,7 +648,22 @@ static void vsc9959_pcs_init_sgmii(struc
+                                  unsigned int link_an_mode,
+                                  const struct phylink_link_state *state)
+ {
++      int bmsr, bmcr;
++
+       if (link_an_mode == MLO_AN_INBAND) {
++              /* Some PHYs like VSC8234 don't like it when AN restarts on
++               * their system  side and they restart line side AN too, going
++               * into an endless link up/down loop.  Don't restart PCS AN if
++               * link is up already.
++               * We do check that AN is enabled just in case this is the 1st
++               * call, PCS detects a carrier but AN is disabled from power on
++               * or by boot loader.
++               */
++              bmcr = phy_read(pcs, MII_BMCR);
++              bmsr = phy_read(pcs, MII_BMSR);
++              if ((bmcr & BMCR_ANENABLE) && (bmsr & BMSR_LSTATUS))
++                      return;
++
+               /* SGMII spec requires tx_config_Reg[15:0] to be exactly 0x4001
+                * for the MAC PCS in order to acknowledge the AN.
+                */
diff --git a/target/linux/layerscape/patches-5.4/701-net-0403-net-dsa-felix-Don-t-error-out-on-disabled-ports-with.patch b/target/linux/layerscape/patches-5.4/701-net-0403-net-dsa-felix-Don-t-error-out-on-disabled-ports-with.patch
new file mode 100644 (file)
index 0000000..febb557
--- /dev/null
@@ -0,0 +1,31 @@
+From 921af144d0022ae6036024ae4981e774711949a7 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Thu, 16 Jan 2020 20:41:53 +0200
+Subject: [PATCH] net: dsa: felix: Don't error out on disabled ports with no
+ phy-mode
+
+The felix_parse_ports_node function was tested only on device trees
+where all ports were enabled. Fix this check so that the driver
+continues to probe only with the ports where status is not "disabled",
+as expected.
+
+Fixes: bdeced75b13f ("net: dsa: felix: Add PCS operations for PHYLINK")
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/ocelot/felix.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -372,7 +372,7 @@ static int felix_parse_ports_node(struct
+       struct device *dev = felix->ocelot.dev;
+       struct device_node *child;
+-      for_each_child_of_node(ports_node, child) {
++      for_each_available_child_of_node(ports_node, child) {
+               phy_interface_t phy_mode;
+               u32 port;
+               int err;
diff --git a/target/linux/layerscape/patches-5.4/701-net-0404-LF-457-ocelot-tsn-clean-preempt-interrupt-status.patch b/target/linux/layerscape/patches-5.4/701-net-0404-LF-457-ocelot-tsn-clean-preempt-interrupt-status.patch
new file mode 100644 (file)
index 0000000..96897b5
--- /dev/null
@@ -0,0 +1,61 @@
+From 5d246e343440ee4915109dac66543d02d71ca900 Mon Sep 17 00:00:00 2001
+From: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
+Date: Tue, 11 Feb 2020 15:33:46 +0800
+Subject: [PATCH] LF-457: ocelot: tsn: clean preempt interrupt status
+
+The INTB interrupt is used both for 1588 interrupt and preemption status
+change interrupt on each port. So clean preempt status interrupt in IRQ
+handle function. Without handling it, driver may get interrupt storm.
+
+Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
+Reviewed-by: Po Liu <Po.Liu@nxp.com>
+---
+ drivers/net/dsa/ocelot/felix.c         |  5 +----
+ drivers/net/ethernet/mscc/ocelot_tsn.c | 14 ++++++++++++++
+ include/soc/mscc/ocelot.h              |  1 +
+ 3 files changed, 16 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -688,12 +688,9 @@ static irqreturn_t felix_irq_handler(int
+       /* The INTB interrupt is used for both PTP TX timestamp interrupt
+        * and preemption status change interrupt on each port.
+-       *
+-       * - Get txtstamp if have
+-       * - TODO: handle preemption. Without handling it, driver may get
+-       *   interrupt storm.
+        */
++      ocelot_preempt_irq_clean(ocelot);
+       ocelot_get_txtstamp(ocelot);
+       return IRQ_HANDLED;
+--- a/drivers/net/ethernet/mscc/ocelot_tsn.c
++++ b/drivers/net/ethernet/mscc/ocelot_tsn.c
+@@ -1570,3 +1570,17 @@ int ocelot_dscp_set(struct ocelot *ocelo
+       return 0;
+ }
++
++void ocelot_preempt_irq_clean(struct ocelot *ocelot)
++{
++      struct ocelot_port *ocelot_port;
++      int port;
++      u32 val;
++
++      val = DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STICKY;
++      for (port = 0; port < ocelot->num_phys_ports; port++) {
++              ocelot_port = ocelot->ports[port];
++              ocelot_port_rmwl(ocelot_port, val, val,
++                               DEV_GMII_MM_STATISTICS_MM_STATUS);
++      }
++}
+--- a/include/soc/mscc/ocelot.h
++++ b/include/soc/mscc/ocelot.h
+@@ -592,4 +592,5 @@ int ocelot_rtag_parse_enable(struct ocel
+ int ocelot_dscp_set(struct ocelot *ocelot, int port,
+                   bool enable, const u8 dscp_ix,
+                   struct tsn_qos_switch_dscp_conf *c);
++void ocelot_preempt_irq_clean(struct ocelot *ocelot);
+ #endif
diff --git a/target/linux/layerscape/patches-5.4/701-net-0406-sdk_qbman-Only-create-debugfs-entries-when-QBMan-is-.patch b/target/linux/layerscape/patches-5.4/701-net-0406-sdk_qbman-Only-create-debugfs-entries-when-QBMan-is-.patch
new file mode 100644 (file)
index 0000000..889aecc
--- /dev/null
@@ -0,0 +1,69 @@
+From f34c01773d5dbd2db04200079bb4d32ecb0cd847 Mon Sep 17 00:00:00 2001
+From: Roy Pledge <roy.pledge@nxp.com>
+Date: Tue, 18 Feb 2020 14:02:21 -0500
+Subject: [PATCH] sdk_qbman: Only create debugfs entries when QBMan is part of
+ device tree
+
+Only create debugfs entries if the QBMan nodes exist in the device
+tree.
+
+Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
+Acked-by: Madalin Bucur <madalin.bucur@nxp.com>
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ drivers/staging/fsl_qbman/bman_debugfs.c |  8 +++++++-
+ drivers/staging/fsl_qbman/qman_debugfs.c | 17 ++++++++++-------
+ 2 files changed, 17 insertions(+), 8 deletions(-)
+
+--- a/drivers/staging/fsl_qbman/bman_debugfs.c
++++ b/drivers/staging/fsl_qbman/bman_debugfs.c
+@@ -33,6 +33,7 @@
+ #include <linux/debugfs.h>
+ #include <linux/seq_file.h>
+ #include <linux/uaccess.h>
++#include <linux/of.h>
+ static struct dentry *dfs_root; /* debugfs root directory */
+@@ -83,9 +84,14 @@ static int __init bman_debugfs_module_in
+ {
+       int ret = 0;
+       struct dentry *d;
++      struct device_node *dn;
++      dn = of_find_compatible_node(NULL, NULL, "fsl,bman");
++      if (!dn) {
++              pr_debug("No fsl,bman node\n");
++              return 0;
++      }
+       dfs_root = debugfs_create_dir("bman", NULL);
+-
+       if (dfs_root == NULL) {
+               ret = -ENOMEM;
+               pr_err("Cannot create bman debugfs dir\n");
+--- a/drivers/staging/fsl_qbman/qman_debugfs.c
++++ b/drivers/staging/fsl_qbman/qman_debugfs.c
+@@ -1457,13 +1457,16 @@ static int __init qman_debugfs_module_in
+       fqid_max = 0;
+       init_ccsrmempeek();
+-      if (qman_ccsr_start) {
+-              if (!qman_ccsrmempeek(&reg, QM_FQD_AR)) {
+-                      /* extract the size of the FQD window */
+-                      reg = reg & 0x3f;
+-                      /* calculate valid frame queue descriptor range */
+-                      fqid_max = (1 << (reg + 1)) / QM_FQD_BLOCK_SIZE;
+-              }
++      if (!qman_ccsr_start) {
++              /* No QMan node found in device tree */
++              return 0;
++      }
++
++      if (!qman_ccsrmempeek(&reg, QM_FQD_AR)) {
++              /* extract the size of the FQD window */
++              reg = reg & 0x3f;
++              /* calculate valid frame queue descriptor range */
++              fqid_max = (1 << (reg + 1)) / QM_FQD_BLOCK_SIZE;
+       }
+       dfs_root = debugfs_create_dir("qman", NULL);
+       fqd_root = debugfs_create_dir("fqd", dfs_root);
diff --git a/target/linux/layerscape/patches-5.4/701-net-0407-LF-924-net-enetc-Set-MAC-Rx-FIFO-to-recommended-valu.patch b/target/linux/layerscape/patches-5.4/701-net-0407-LF-924-net-enetc-Set-MAC-Rx-FIFO-to-recommended-valu.patch
new file mode 100644 (file)
index 0000000..a288938
--- /dev/null
@@ -0,0 +1,43 @@
+From 9507f517ac4080627515c31c937f45a4a58ccbe4 Mon Sep 17 00:00:00 2001
+From: Alex Marginean <alexandru.marginean@nxp.com>
+Date: Fri, 14 Feb 2020 17:28:26 +0000
+Subject: [PATCH] LF-924: net/enetc: Set MAC Rx FIFO to recommended value
+
+On LS1028A the MAC Rx FIFO defaults to value 2, which is too high and may
+lead to Rx lock-up under traffic.  Set it to 1 instead, as recommended by
+the hardware team.
+
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+Reviewed-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Acked-by: Jason Liu <jason.hui.liu@nxp.com>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_hw.h | 2 ++
+ drivers/net/ethernet/freescale/enetc/enetc_pf.c | 6 ++++++
+ 2 files changed, 8 insertions(+)
+
+--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+@@ -224,6 +224,8 @@ enum enetc_bdr_type {TX, RX};
+ #define ENETC_PM0_MAXFRM      0x8014
+ #define ENETC_SET_TX_MTU(val) ((val) << 16)
+ #define ENETC_SET_MAXFRM(val) ((val) & 0xffff)
++#define ENETC_PM0_RX_FIFO     0x801c
++#define ENETC_PM0_RX_FIFO_VAL 1
+ #define ENETC_PM_IMDIO_BASE   0x8030
+ /* PCS registers */
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -536,6 +536,12 @@ static void enetc_configure_port_mac(str
+               enetc_port_wr(hw, ENETC_PM0_IF_MODE, ENETC_PM0_IFM_XGMII);
+               enetc_port_wr(hw, ENETC_PM1_IF_MODE, ENETC_PM0_IFM_XGMII);
+       }
++
++      /* on LS1028A the MAC Rx FIFO defaults to value 2, which is too high and
++       * may lead to Rx lock-up under traffic.  Set it to 1 instead, as
++       * recommended by the hardware team.
++       */
++      enetc_port_wr(hw, ENETC_PM0_RX_FIFO, ENETC_PM0_RX_FIFO_VAL);
+ }
+ static void enetc_configure_port_pmac(struct enetc_hw *hw)
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0001-Revert-ASoC-fsl_sai-Fix-noise-when-using-EDMA.patch b/target/linux/layerscape/patches-5.4/801-audio-0001-Revert-ASoC-fsl_sai-Fix-noise-when-using-EDMA.patch
new file mode 100644 (file)
index 0000000..e88d0fb
--- /dev/null
@@ -0,0 +1,76 @@
+From cf07127ea019b78f7ea5e009d494e2bd0bd475fa Mon Sep 17 00:00:00 2001
+From: Leonard Crestez <leonard.crestez@nxp.com>
+Date: Thu, 3 Oct 2019 20:44:56 +0300
+Subject: [PATCH] Revert "ASoC: fsl_sai: Fix noise when using EDMA"
+
+This reverts commit e75f4940e8ad0dd76527302a10c06b58bf7eb590.
+---
+ sound/soc/fsl/fsl_sai.c | 15 ---------------
+ sound/soc/fsl/fsl_sai.h |  1 -
+ 2 files changed, 16 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -628,16 +628,6 @@ static int fsl_sai_startup(struct snd_pc
+                          FSL_SAI_CR3_TRCE_MASK,
+                          FSL_SAI_CR3_TRCE);
+-      /*
+-       * EDMA controller needs period size to be a multiple of
+-       * tx/rx maxburst
+-       */
+-      if (sai->soc_data->use_edma)
+-              snd_pcm_hw_constraint_step(substream->runtime, 0,
+-                                         SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+-                                         tx ? sai->dma_params_tx.maxburst :
+-                                         sai->dma_params_rx.maxburst);
+-
+       ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &fsl_sai_rate_constraints);
+@@ -1048,35 +1038,30 @@ static int fsl_sai_remove(struct platfor
+ static const struct fsl_sai_soc_data fsl_sai_vf610_data = {
+       .use_imx_pcm = false,
+-      .use_edma = false,
+       .fifo_depth = 32,
+       .reg_offset = 0,
+ };
+ static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = {
+       .use_imx_pcm = true,
+-      .use_edma = false,
+       .fifo_depth = 32,
+       .reg_offset = 0,
+ };
+ static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = {
+       .use_imx_pcm = true,
+-      .use_edma = false,
+       .fifo_depth = 16,
+       .reg_offset = 8,
+ };
+ static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = {
+       .use_imx_pcm = true,
+-      .use_edma = false,
+       .fifo_depth = 128,
+       .reg_offset = 8,
+ };
+ static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = {
+       .use_imx_pcm = true,
+-      .use_edma = true,
+       .fifo_depth = 64,
+       .reg_offset = 0,
+ };
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -157,7 +157,6 @@
+ struct fsl_sai_soc_data {
+       bool use_imx_pcm;
+-      bool use_edma;
+       unsigned int fifo_depth;
+       unsigned int reg_offset;
+ };
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0002-Revert-ASoC-fsl_sai-Implement-set_bclk_ratio.patch b/target/linux/layerscape/patches-5.4/801-audio-0002-Revert-ASoC-fsl_sai-Implement-set_bclk_ratio.patch
new file mode 100644 (file)
index 0000000..a8aeca7
--- /dev/null
@@ -0,0 +1,65 @@
+From aff2edb9c66a1188ed6554643e3cf76595c56846 Mon Sep 17 00:00:00 2001
+From: Leonard Crestez <leonard.crestez@nxp.com>
+Date: Thu, 3 Oct 2019 20:44:59 +0300
+Subject: [PATCH] Revert "ASoC: fsl_sai: Implement set_bclk_ratio"
+
+This reverts commit 63d1a3488ff58e094a7f517cf93c0250f0a3f6be.
+---
+ sound/soc/fsl/fsl_sai.c | 21 ++-------------------
+ sound/soc/fsl/fsl_sai.h |  1 -
+ 2 files changed, 2 insertions(+), 20 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -137,16 +137,6 @@ static int fsl_sai_set_dai_tdm_slot(stru
+       return 0;
+ }
+-static int fsl_sai_set_dai_bclk_ratio(struct snd_soc_dai *dai,
+-                                    unsigned int ratio)
+-{
+-      struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
+-
+-      sai->bclk_ratio = ratio;
+-
+-      return 0;
+-}
+-
+ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
+               int clk_id, unsigned int freq, int fsl_dir)
+ {
+@@ -433,14 +423,8 @@ static int fsl_sai_hw_params(struct snd_
+               slot_width = sai->slot_width;
+       if (!sai->is_slave_mode) {
+-              if (sai->bclk_ratio)
+-                      ret = fsl_sai_set_bclk(cpu_dai, tx,
+-                                             sai->bclk_ratio *
+-                                             params_rate(params));
+-              else
+-                      ret = fsl_sai_set_bclk(cpu_dai, tx,
+-                                             slots * slot_width *
+-                                             params_rate(params));
++              ret = fsl_sai_set_bclk(cpu_dai, tx,
++                              slots * slot_width * params_rate(params));
+               if (ret)
+                       return ret;
+@@ -646,7 +630,6 @@ static void fsl_sai_shutdown(struct snd_
+ }
+ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
+-      .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio,
+       .set_sysclk     = fsl_sai_set_dai_sysclk,
+       .set_fmt        = fsl_sai_set_dai_fmt,
+       .set_tdm_slot   = fsl_sai_set_dai_tdm_slot,
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -176,7 +176,6 @@ struct fsl_sai {
+       unsigned int mclk_streams;
+       unsigned int slots;
+       unsigned int slot_width;
+-      unsigned int bclk_ratio;
+       const struct fsl_sai_soc_data *soc_data;
+       struct snd_dmaengine_dai_dma_data dma_params_rx;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0003-Revert-ASoC-fsl_sai-Add-support-for-imx8qm.patch b/target/linux/layerscape/patches-5.4/801-audio-0003-Revert-ASoC-fsl_sai-Add-support-for-imx8qm.patch
new file mode 100644 (file)
index 0000000..ba3eb4d
--- /dev/null
@@ -0,0 +1,32 @@
+From 841e80ea4dcfa52f6883ad5330aa7d2ab7d6229e Mon Sep 17 00:00:00 2001
+From: Leonard Crestez <leonard.crestez@nxp.com>
+Date: Thu, 3 Oct 2019 20:45:02 +0300
+Subject: [PATCH] Revert "ASoC: fsl_sai: Add support for imx8qm"
+
+This reverts commit 6eeb60be5ebb73b2e5911e26fb1aed02940b7d09.
+---
+ sound/soc/fsl/fsl_sai.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -1043,19 +1043,12 @@ static const struct fsl_sai_soc_data fsl
+       .reg_offset = 8,
+ };
+-static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = {
+-      .use_imx_pcm = true,
+-      .fifo_depth = 64,
+-      .reg_offset = 0,
+-};
+-
+ static const struct of_device_id fsl_sai_ids[] = {
+       { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data },
+       { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data },
+       { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6sx_data },
+       { .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp_data },
+       { .compatible = "fsl,imx8mq-sai", .data = &fsl_sai_imx8mq_data },
+-      { .compatible = "fsl,imx8qm-sai", .data = &fsl_sai_imx8qm_data },
+       { /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, fsl_sai_ids);
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0004-Revert-ASoC-fsl_sai-Add-support-for-imx7ulp-imx8mq.patch b/target/linux/layerscape/patches-5.4/801-audio-0004-Revert-ASoC-fsl_sai-Add-support-for-imx7ulp-imx8mq.patch
new file mode 100644 (file)
index 0000000..4735cce
--- /dev/null
@@ -0,0 +1,37 @@
+From 6357cf1832f46d29f9756a34887af7fd96d48f18 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Fri, 16 Aug 2019 18:01:12 +0800
+Subject: [PATCH] Revert "ASoC: fsl_sai: Add support for imx7ulp/imx8mq"
+
+This reverts commit a860fac420971c5a90d4f78959b44ead793aee4f.
+---
+ sound/soc/fsl/fsl_sai.c | 14 --------------
+ 1 file changed, 14 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -1031,24 +1031,10 @@ static const struct fsl_sai_soc_data fsl
+       .reg_offset = 0,
+ };
+-static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = {
+-      .use_imx_pcm = true,
+-      .fifo_depth = 16,
+-      .reg_offset = 8,
+-};
+-
+-static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = {
+-      .use_imx_pcm = true,
+-      .fifo_depth = 128,
+-      .reg_offset = 8,
+-};
+-
+ static const struct of_device_id fsl_sai_ids[] = {
+       { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data },
+       { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data },
+       { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6sx_data },
+-      { .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp_data },
+-      { .compatible = "fsl,imx8mq-sai", .data = &fsl_sai_imx8mq_data },
+       { /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, fsl_sai_ids);
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0005-Revert-ASoC-fsl_sai-Add-support-for-SAI-new-version.patch b/target/linux/layerscape/patches-5.4/801-audio-0005-Revert-ASoC-fsl_sai-Add-support-for-SAI-new-version.patch
new file mode 100644 (file)
index 0000000..85dec5c
--- /dev/null
@@ -0,0 +1,606 @@
+From 2d6dfbd200d8de9bef8fb30bec90594acea9a145 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Fri, 16 Aug 2019 18:01:26 +0800
+Subject: [PATCH] Revert "ASoC: fsl_sai: Add support for SAI new version"
+
+This reverts commit 4f7a0728b5305e2d865f543fbcffd617e03c7674.
+---
+ sound/soc/fsl/fsl_sai.c | 228 ++++++++++++++++++++----------------------------
+ sound/soc/fsl/fsl_sai.h |  41 +++++----
+ 2 files changed, 113 insertions(+), 156 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -40,7 +40,6 @@ static const struct snd_pcm_hw_constrain
+ static irqreturn_t fsl_sai_isr(int irq, void *devid)
+ {
+       struct fsl_sai *sai = (struct fsl_sai *)devid;
+-      unsigned int ofs = sai->soc_data->reg_offset;
+       struct device *dev = &sai->pdev->dev;
+       u32 flags, xcsr, mask;
+       bool irq_none = true;
+@@ -53,7 +52,7 @@ static irqreturn_t fsl_sai_isr(int irq,
+       mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT;
+       /* Tx IRQ */
+-      regmap_read(sai->regmap, FSL_SAI_TCSR(ofs), &xcsr);
++      regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr);
+       flags = xcsr & mask;
+       if (flags)
+@@ -83,11 +82,11 @@ static irqreturn_t fsl_sai_isr(int irq,
+       xcsr &= ~FSL_SAI_CSR_xF_MASK;
+       if (flags)
+-              regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), flags | xcsr);
++              regmap_write(sai->regmap, FSL_SAI_TCSR, flags | xcsr);
+ irq_rx:
+       /* Rx IRQ */
+-      regmap_read(sai->regmap, FSL_SAI_RCSR(ofs), &xcsr);
++      regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr);
+       flags = xcsr & mask;
+       if (flags)
+@@ -117,7 +116,7 @@ irq_rx:
+       xcsr &= ~FSL_SAI_CSR_xF_MASK;
+       if (flags)
+-              regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), flags | xcsr);
++              regmap_write(sai->regmap, FSL_SAI_RCSR, flags | xcsr);
+ out:
+       if (irq_none)
+@@ -141,7 +140,6 @@ static int fsl_sai_set_dai_sysclk_tr(str
+               int clk_id, unsigned int freq, int fsl_dir)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+-      unsigned int ofs = sai->soc_data->reg_offset;
+       bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
+       u32 val_cr2 = 0;
+@@ -162,7 +160,7 @@ static int fsl_sai_set_dai_sysclk_tr(str
+               return -EINVAL;
+       }
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx),
+                          FSL_SAI_CR2_MSEL_MASK, val_cr2);
+       return 0;
+@@ -195,7 +193,6 @@ static int fsl_sai_set_dai_fmt_tr(struct
+                               unsigned int fmt, int fsl_dir)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+-      unsigned int ofs = sai->soc_data->reg_offset;
+       bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
+       u32 val_cr2 = 0, val_cr4 = 0;
+@@ -290,9 +287,9 @@ static int fsl_sai_set_dai_fmt_tr(struct
+               return -EINVAL;
+       }
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx),
+                          FSL_SAI_CR2_BCP | FSL_SAI_CR2_BCD_MSTR, val_cr2);
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
+                          FSL_SAI_CR4_MF | FSL_SAI_CR4_FSE |
+                          FSL_SAI_CR4_FSP | FSL_SAI_CR4_FSD_MSTR, val_cr4);
+@@ -319,7 +316,6 @@ static int fsl_sai_set_dai_fmt(struct sn
+ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
+-      unsigned int ofs = sai->soc_data->reg_offset;
+       unsigned long clk_rate;
+       u32 savediv = 0, ratio, savesub = freq;
+       u32 id;
+@@ -382,17 +378,17 @@ static int fsl_sai_set_bclk(struct snd_s
+        */
+       if ((sai->synchronous[TX] && !sai->synchronous[RX]) ||
+           (!tx && !sai->synchronous[RX])) {
+-              regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs),
++              regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
+                                  FSL_SAI_CR2_MSEL_MASK,
+                                  FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
+-              regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs),
++              regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
+                                  FSL_SAI_CR2_DIV_MASK, savediv - 1);
+       } else if ((sai->synchronous[RX] && !sai->synchronous[TX]) ||
+                  (tx && !sai->synchronous[TX])) {
+-              regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs),
++              regmap_update_bits(sai->regmap, FSL_SAI_TCR2,
+                                  FSL_SAI_CR2_MSEL_MASK,
+                                  FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
+-              regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs),
++              regmap_update_bits(sai->regmap, FSL_SAI_TCR2,
+                                  FSL_SAI_CR2_DIV_MASK, savediv - 1);
+       }
+@@ -407,7 +403,6 @@ static int fsl_sai_hw_params(struct snd_
+               struct snd_soc_dai *cpu_dai)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+-      unsigned int ofs = sai->soc_data->reg_offset;
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       unsigned int channels = params_channels(params);
+       u32 word_width = params_width(params);
+@@ -460,19 +455,19 @@ static int fsl_sai_hw_params(struct snd_
+       if (!sai->is_slave_mode) {
+               if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
+-                      regmap_update_bits(sai->regmap, FSL_SAI_TCR4(ofs),
++                      regmap_update_bits(sai->regmap, FSL_SAI_TCR4,
+                               FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+                               val_cr4);
+-                      regmap_update_bits(sai->regmap, FSL_SAI_TCR5(ofs),
++                      regmap_update_bits(sai->regmap, FSL_SAI_TCR5,
+                               FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+                               FSL_SAI_CR5_FBT_MASK, val_cr5);
+                       regmap_write(sai->regmap, FSL_SAI_TMR,
+                               ~0UL - ((1 << channels) - 1));
+               } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
+-                      regmap_update_bits(sai->regmap, FSL_SAI_RCR4(ofs),
++                      regmap_update_bits(sai->regmap, FSL_SAI_RCR4,
+                               FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+                               val_cr4);
+-                      regmap_update_bits(sai->regmap, FSL_SAI_RCR5(ofs),
++                      regmap_update_bits(sai->regmap, FSL_SAI_RCR5,
+                               FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+                               FSL_SAI_CR5_FBT_MASK, val_cr5);
+                       regmap_write(sai->regmap, FSL_SAI_RMR,
+@@ -480,10 +475,10 @@ static int fsl_sai_hw_params(struct snd_
+               }
+       }
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
+                          FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+                          val_cr4);
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, ofs),
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx),
+                          FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+                          FSL_SAI_CR5_FBT_MASK, val_cr5);
+       regmap_write(sai->regmap, FSL_SAI_xMR(tx), ~0UL - ((1 << channels) - 1));
+@@ -511,8 +506,6 @@ static int fsl_sai_trigger(struct snd_pc
+               struct snd_soc_dai *cpu_dai)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+-      unsigned int ofs = sai->soc_data->reg_offset;
+-
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       u32 xcsr, count = 100;
+@@ -521,9 +514,9 @@ static int fsl_sai_trigger(struct snd_pc
+        * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
+        * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx.
+        */
+-      regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs), FSL_SAI_CR2_SYNC,
+-                         sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0);
+-      regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs), FSL_SAI_CR2_SYNC,
++      regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC,
++                         sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0);
++      regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
+                          sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0);
+       /*
+@@ -534,44 +527,43 @@ static int fsl_sai_trigger(struct snd_pc
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
++              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+                                  FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
+-              regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs),
++              regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
+                                  FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+-              regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs),
++              regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
+                                  FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
++              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+                                  FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
++              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+                                  FSL_SAI_CSR_FRDE, 0);
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
++              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+                                  FSL_SAI_CSR_xIE_MASK, 0);
+               /* Check if the opposite FRDE is also disabled */
+-              regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, ofs), &xcsr);
++              regmap_read(sai->regmap, FSL_SAI_xCSR(!tx), &xcsr);
+               if (!(xcsr & FSL_SAI_CSR_FRDE)) {
+                       /* Disable both directions and reset their FIFOs */
+-                      regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs),
++                      regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
+                                          FSL_SAI_CSR_TERE, 0);
+-                      regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs),
++                      regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
+                                          FSL_SAI_CSR_TERE, 0);
+                       /* TERE will remain set till the end of current frame */
+                       do {
+                               udelay(10);
+-                              regmap_read(sai->regmap,
+-                                          FSL_SAI_xCSR(tx, ofs), &xcsr);
++                              regmap_read(sai->regmap, FSL_SAI_xCSR(tx), &xcsr);
+                       } while (--count && xcsr & FSL_SAI_CSR_TERE);
+-                      regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs),
++                      regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
+                                          FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
+-                      regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs),
++                      regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
+                                          FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
+                       /*
+@@ -583,13 +575,13 @@ static int fsl_sai_trigger(struct snd_pc
+                        */
+                       if (!sai->is_slave_mode) {
+                               /* Software Reset for both Tx and Rx */
+-                              regmap_write(sai->regmap, FSL_SAI_TCSR(ofs),
+-                                           FSL_SAI_CSR_SR);
+-                              regmap_write(sai->regmap, FSL_SAI_RCSR(ofs),
+-                                           FSL_SAI_CSR_SR);
++                              regmap_write(sai->regmap,
++                                           FSL_SAI_TCSR, FSL_SAI_CSR_SR);
++                              regmap_write(sai->regmap,
++                                           FSL_SAI_RCSR, FSL_SAI_CSR_SR);
+                               /* Clear SR bit to finish the reset */
+-                              regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0);
+-                              regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0);
++                              regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
++                              regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
+                       }
+               }
+               break;
+@@ -604,11 +596,10 @@ static int fsl_sai_startup(struct snd_pc
+               struct snd_soc_dai *cpu_dai)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+-      unsigned int ofs = sai->soc_data->reg_offset;
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       int ret;
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx),
+                          FSL_SAI_CR3_TRCE_MASK,
+                          FSL_SAI_CR3_TRCE);
+@@ -622,10 +613,9 @@ static void fsl_sai_shutdown(struct snd_
+               struct snd_soc_dai *cpu_dai)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+-      unsigned int ofs = sai->soc_data->reg_offset;
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx),
+                          FSL_SAI_CR3_TRCE_MASK, 0);
+ }
+@@ -643,20 +633,18 @@ static const struct snd_soc_dai_ops fsl_
+ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
+ {
+       struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
+-      unsigned int ofs = sai->soc_data->reg_offset;
+       /* Software Reset for both Tx and Rx */
+-      regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR);
+-      regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR);
++      regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR);
++      regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR);
+       /* Clear SR bit to finish the reset */
+-      regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0);
+-      regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0);
++      regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
++      regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
+-      regmap_update_bits(sai->regmap, FSL_SAI_TCR1(ofs),
+-                         FSL_SAI_CR1_RFW_MASK,
++      regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
+                          sai->soc_data->fifo_depth - FSL_SAI_MAXBURST_TX);
+-      regmap_update_bits(sai->regmap, FSL_SAI_RCR1(ofs),
+-                         FSL_SAI_CR1_RFW_MASK, FSL_SAI_MAXBURST_RX - 1);
++      regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
++                         FSL_SAI_MAXBURST_RX - 1);
+       snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
+                               &sai->dma_params_rx);
+@@ -693,12 +681,12 @@ static const struct snd_soc_component_dr
+       .name           = "fsl-sai",
+ };
+-static struct reg_default fsl_sai_reg_defaults_ofs0[] = {
+-      {FSL_SAI_TCR1(0), 0},
+-      {FSL_SAI_TCR2(0), 0},
+-      {FSL_SAI_TCR3(0), 0},
+-      {FSL_SAI_TCR4(0), 0},
+-      {FSL_SAI_TCR5(0), 0},
++static struct reg_default fsl_sai_reg_defaults[] = {
++      {FSL_SAI_TCR1, 0},
++      {FSL_SAI_TCR2, 0},
++      {FSL_SAI_TCR3, 0},
++      {FSL_SAI_TCR4, 0},
++      {FSL_SAI_TCR5, 0},
+       {FSL_SAI_TDR0, 0},
+       {FSL_SAI_TDR1, 0},
+       {FSL_SAI_TDR2, 0},
+@@ -707,50 +695,24 @@ static struct reg_default fsl_sai_reg_de
+       {FSL_SAI_TDR5, 0},
+       {FSL_SAI_TDR6, 0},
+       {FSL_SAI_TDR7, 0},
+-      {FSL_SAI_TMR, 0},
+-      {FSL_SAI_RCR1(0), 0},
+-      {FSL_SAI_RCR2(0), 0},
+-      {FSL_SAI_RCR3(0), 0},
+-      {FSL_SAI_RCR4(0), 0},
+-      {FSL_SAI_RCR5(0), 0},
+-      {FSL_SAI_RMR, 0},
+-};
+-
+-static struct reg_default fsl_sai_reg_defaults_ofs8[] = {
+-      {FSL_SAI_TCR1(8), 0},
+-      {FSL_SAI_TCR2(8), 0},
+-      {FSL_SAI_TCR3(8), 0},
+-      {FSL_SAI_TCR4(8), 0},
+-      {FSL_SAI_TCR5(8), 0},
+-      {FSL_SAI_TDR0, 0},
+-      {FSL_SAI_TDR1, 0},
+-      {FSL_SAI_TDR2, 0},
+-      {FSL_SAI_TDR3, 0},
+-      {FSL_SAI_TDR4, 0},
+-      {FSL_SAI_TDR5, 0},
+-      {FSL_SAI_TDR6, 0},
+-      {FSL_SAI_TDR7, 0},
+-      {FSL_SAI_TMR, 0},
+-      {FSL_SAI_RCR1(8), 0},
+-      {FSL_SAI_RCR2(8), 0},
+-      {FSL_SAI_RCR3(8), 0},
+-      {FSL_SAI_RCR4(8), 0},
+-      {FSL_SAI_RCR5(8), 0},
+-      {FSL_SAI_RMR, 0},
++      {FSL_SAI_TMR,  0},
++      {FSL_SAI_RCR1, 0},
++      {FSL_SAI_RCR2, 0},
++      {FSL_SAI_RCR3, 0},
++      {FSL_SAI_RCR4, 0},
++      {FSL_SAI_RCR5, 0},
++      {FSL_SAI_RMR,  0},
+ };
+ static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
+ {
+-      struct fsl_sai *sai = dev_get_drvdata(dev);
+-      unsigned int ofs = sai->soc_data->reg_offset;
+-
+-      if (reg >= FSL_SAI_TCSR(ofs) && reg <= FSL_SAI_TCR5(ofs))
+-              return true;
+-
+-      if (reg >= FSL_SAI_RCSR(ofs) && reg <= FSL_SAI_RCR5(ofs))
+-              return true;
+-
+       switch (reg) {
++      case FSL_SAI_TCSR:
++      case FSL_SAI_TCR1:
++      case FSL_SAI_TCR2:
++      case FSL_SAI_TCR3:
++      case FSL_SAI_TCR4:
++      case FSL_SAI_TCR5:
+       case FSL_SAI_TFR0:
+       case FSL_SAI_TFR1:
+       case FSL_SAI_TFR2:
+@@ -760,6 +722,12 @@ static bool fsl_sai_readable_reg(struct
+       case FSL_SAI_TFR6:
+       case FSL_SAI_TFR7:
+       case FSL_SAI_TMR:
++      case FSL_SAI_RCSR:
++      case FSL_SAI_RCR1:
++      case FSL_SAI_RCR2:
++      case FSL_SAI_RCR3:
++      case FSL_SAI_RCR4:
++      case FSL_SAI_RCR5:
+       case FSL_SAI_RDR0:
+       case FSL_SAI_RDR1:
+       case FSL_SAI_RDR2:
+@@ -785,13 +753,9 @@ static bool fsl_sai_readable_reg(struct
+ static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
+ {
+-      struct fsl_sai *sai = dev_get_drvdata(dev);
+-      unsigned int ofs = sai->soc_data->reg_offset;
+-
+-      if (reg == FSL_SAI_TCSR(ofs) || reg == FSL_SAI_RCSR(ofs))
+-              return true;
+-
+       switch (reg) {
++      case FSL_SAI_TCSR:
++      case FSL_SAI_RCSR:
+       case FSL_SAI_TFR0:
+       case FSL_SAI_TFR1:
+       case FSL_SAI_TFR2:
+@@ -824,16 +788,13 @@ static bool fsl_sai_volatile_reg(struct
+ static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
+ {
+-      struct fsl_sai *sai = dev_get_drvdata(dev);
+-      unsigned int ofs = sai->soc_data->reg_offset;
+-
+-      if (reg >= FSL_SAI_TCSR(ofs) && reg <= FSL_SAI_TCR5(ofs))
+-              return true;
+-
+-      if (reg >= FSL_SAI_RCSR(ofs) && reg <= FSL_SAI_RCR5(ofs))
+-              return true;
+-
+       switch (reg) {
++      case FSL_SAI_TCSR:
++      case FSL_SAI_TCR1:
++      case FSL_SAI_TCR2:
++      case FSL_SAI_TCR3:
++      case FSL_SAI_TCR4:
++      case FSL_SAI_TCR5:
+       case FSL_SAI_TDR0:
+       case FSL_SAI_TDR1:
+       case FSL_SAI_TDR2:
+@@ -843,6 +804,12 @@ static bool fsl_sai_writeable_reg(struct
+       case FSL_SAI_TDR6:
+       case FSL_SAI_TDR7:
+       case FSL_SAI_TMR:
++      case FSL_SAI_RCSR:
++      case FSL_SAI_RCR1:
++      case FSL_SAI_RCR2:
++      case FSL_SAI_RCR3:
++      case FSL_SAI_RCR4:
++      case FSL_SAI_RCR5:
+       case FSL_SAI_RMR:
+               return true;
+       default:
+@@ -850,15 +817,15 @@ static bool fsl_sai_writeable_reg(struct
+       }
+ }
+-static struct regmap_config fsl_sai_regmap_config = {
++static const struct regmap_config fsl_sai_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .fast_io = true,
+       .max_register = FSL_SAI_RMR,
+-      .reg_defaults = fsl_sai_reg_defaults_ofs0,
+-      .num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults_ofs0),
++      .reg_defaults = fsl_sai_reg_defaults,
++      .num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults),
+       .readable_reg = fsl_sai_readable_reg,
+       .volatile_reg = fsl_sai_volatile_reg,
+       .writeable_reg = fsl_sai_writeable_reg,
+@@ -890,12 +857,6 @@ static int fsl_sai_probe(struct platform
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+-      if (sai->soc_data->reg_offset == 8) {
+-              fsl_sai_regmap_config.reg_defaults = fsl_sai_reg_defaults_ofs8;
+-              fsl_sai_regmap_config.num_reg_defaults =
+-                      ARRAY_SIZE(fsl_sai_reg_defaults_ofs8);
+-      }
+-
+       sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+                       "bus", base, &fsl_sai_regmap_config);
+@@ -1022,13 +983,11 @@ static int fsl_sai_remove(struct platfor
+ static const struct fsl_sai_soc_data fsl_sai_vf610_data = {
+       .use_imx_pcm = false,
+       .fifo_depth = 32,
+-      .reg_offset = 0,
+ };
+ static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = {
+       .use_imx_pcm = true,
+       .fifo_depth = 32,
+-      .reg_offset = 0,
+ };
+ static const struct of_device_id fsl_sai_ids[] = {
+@@ -1061,7 +1020,6 @@ static int fsl_sai_runtime_suspend(struc
+ static int fsl_sai_runtime_resume(struct device *dev)
+ {
+       struct fsl_sai *sai = dev_get_drvdata(dev);
+-      unsigned int ofs = sai->soc_data->reg_offset;
+       int ret;
+       ret = clk_prepare_enable(sai->bus_clk);
+@@ -1083,11 +1041,11 @@ static int fsl_sai_runtime_resume(struct
+       }
+       regcache_cache_only(sai->regmap, false);
+-      regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR);
+-      regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR);
++      regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR);
++      regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR);
+       usleep_range(1000, 2000);
+-      regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0);
+-      regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0);
++      regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
++      regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
+       ret = regcache_sync(sai->regmap);
+       if (ret)
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -14,12 +14,12 @@
+                        SNDRV_PCM_FMTBIT_S32_LE)
+ /* SAI Register Map Register */
+-#define FSL_SAI_TCSR(ofs)     (0x00 + ofs) /* SAI Transmit Control */
+-#define FSL_SAI_TCR1(ofs)     (0x04 + ofs) /* SAI Transmit Configuration 1 */
+-#define FSL_SAI_TCR2(ofs)     (0x08 + ofs) /* SAI Transmit Configuration 2 */
+-#define FSL_SAI_TCR3(ofs)     (0x0c + ofs) /* SAI Transmit Configuration 3 */
+-#define FSL_SAI_TCR4(ofs)     (0x10 + ofs) /* SAI Transmit Configuration 4 */
+-#define FSL_SAI_TCR5(ofs)     (0x14 + ofs) /* SAI Transmit Configuration 5 */
++#define FSL_SAI_TCSR  0x00 /* SAI Transmit Control */
++#define FSL_SAI_TCR1  0x04 /* SAI Transmit Configuration 1 */
++#define FSL_SAI_TCR2  0x08 /* SAI Transmit Configuration 2 */
++#define FSL_SAI_TCR3  0x0c /* SAI Transmit Configuration 3 */
++#define FSL_SAI_TCR4  0x10 /* SAI Transmit Configuration 4 */
++#define FSL_SAI_TCR5  0x14 /* SAI Transmit Configuration 5 */
+ #define FSL_SAI_TDR0  0x20 /* SAI Transmit Data 0 */
+ #define FSL_SAI_TDR1  0x24 /* SAI Transmit Data 1 */
+ #define FSL_SAI_TDR2  0x28 /* SAI Transmit Data 2 */
+@@ -37,12 +37,12 @@
+ #define FSL_SAI_TFR6  0x58 /* SAI Transmit FIFO 6 */
+ #define FSL_SAI_TFR7  0x5C /* SAI Transmit FIFO 7 */
+ #define FSL_SAI_TMR   0x60 /* SAI Transmit Mask */
+-#define FSL_SAI_RCSR(ofs)     (0x80 + ofs) /* SAI Receive Control */
+-#define FSL_SAI_RCR1(ofs)     (0x84 + ofs)/* SAI Receive Configuration 1 */
+-#define FSL_SAI_RCR2(ofs)     (0x88 + ofs) /* SAI Receive Configuration 2 */
+-#define FSL_SAI_RCR3(ofs)     (0x8c + ofs) /* SAI Receive Configuration 3 */
+-#define FSL_SAI_RCR4(ofs)     (0x90 + ofs) /* SAI Receive Configuration 4 */
+-#define FSL_SAI_RCR5(ofs)     (0x94 + ofs) /* SAI Receive Configuration 5 */
++#define FSL_SAI_RCSR  0x80 /* SAI Receive Control */
++#define FSL_SAI_RCR1  0x84 /* SAI Receive Configuration 1 */
++#define FSL_SAI_RCR2  0x88 /* SAI Receive Configuration 2 */
++#define FSL_SAI_RCR3  0x8c /* SAI Receive Configuration 3 */
++#define FSL_SAI_RCR4  0x90 /* SAI Receive Configuration 4 */
++#define FSL_SAI_RCR5  0x94 /* SAI Receive Configuration 5 */
+ #define FSL_SAI_RDR0  0xa0 /* SAI Receive Data 0 */
+ #define FSL_SAI_RDR1  0xa4 /* SAI Receive Data 1 */
+ #define FSL_SAI_RDR2  0xa8 /* SAI Receive Data 2 */
+@@ -61,14 +61,14 @@
+ #define FSL_SAI_RFR7  0xdc /* SAI Receive FIFO 7 */
+ #define FSL_SAI_RMR   0xe0 /* SAI Receive Mask */
+-#define FSL_SAI_xCSR(tx, ofs) (tx ? FSL_SAI_TCSR(ofs) : FSL_SAI_RCSR(ofs))
+-#define FSL_SAI_xCR1(tx, ofs) (tx ? FSL_SAI_TCR1(ofs) : FSL_SAI_RCR1(ofs))
+-#define FSL_SAI_xCR2(tx, ofs) (tx ? FSL_SAI_TCR2(ofs) : FSL_SAI_RCR2(ofs))
+-#define FSL_SAI_xCR3(tx, ofs) (tx ? FSL_SAI_TCR3(ofs) : FSL_SAI_RCR3(ofs))
+-#define FSL_SAI_xCR4(tx, ofs) (tx ? FSL_SAI_TCR4(ofs) : FSL_SAI_RCR4(ofs))
+-#define FSL_SAI_xCR5(tx, ofs) (tx ? FSL_SAI_TCR5(ofs) : FSL_SAI_RCR5(ofs))
+-#define FSL_SAI_xDR(tx, ofs)  (tx ? FSL_SAI_TDR(ofs) : FSL_SAI_RDR(ofs))
+-#define FSL_SAI_xFR(tx, ofs)  (tx ? FSL_SAI_TFR(ofs) : FSL_SAI_RFR(ofs))
++#define FSL_SAI_xCSR(tx)      (tx ? FSL_SAI_TCSR : FSL_SAI_RCSR)
++#define FSL_SAI_xCR1(tx)      (tx ? FSL_SAI_TCR1 : FSL_SAI_RCR1)
++#define FSL_SAI_xCR2(tx)      (tx ? FSL_SAI_TCR2 : FSL_SAI_RCR2)
++#define FSL_SAI_xCR3(tx)      (tx ? FSL_SAI_TCR3 : FSL_SAI_RCR3)
++#define FSL_SAI_xCR4(tx)      (tx ? FSL_SAI_TCR4 : FSL_SAI_RCR4)
++#define FSL_SAI_xCR5(tx)      (tx ? FSL_SAI_TCR5 : FSL_SAI_RCR5)
++#define FSL_SAI_xDR(tx)               (tx ? FSL_SAI_TDR : FSL_SAI_RDR)
++#define FSL_SAI_xFR(tx)               (tx ? FSL_SAI_TFR : FSL_SAI_RFR)
+ #define FSL_SAI_xMR(tx)               (tx ? FSL_SAI_TMR : FSL_SAI_RMR)
+ /* SAI Transmit/Receive Control Register */
+@@ -158,7 +158,6 @@
+ struct fsl_sai_soc_data {
+       bool use_imx_pcm;
+       unsigned int fifo_depth;
+-      unsigned int reg_offset;
+ };
+ struct fsl_sai {
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0006-Revert-ASoC-fsl_sai-Update-Tx-Rx-channel-enable-mask.patch b/target/linux/layerscape/patches-5.4/801-audio-0006-Revert-ASoC-fsl_sai-Update-Tx-Rx-channel-enable-mask.patch
new file mode 100644 (file)
index 0000000..e116389
--- /dev/null
@@ -0,0 +1,43 @@
+From 480565647b43c25ae86c635f88ae99f036f4e63a Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Fri, 16 Aug 2019 18:01:33 +0800
+Subject: [PATCH] Revert "ASoC: fsl_sai: Update Tx/Rx channel enable mask"
+
+This reverts commit b84f50b0fcb497a62068926fca793d2d213c7dbd.
+---
+ sound/soc/fsl/fsl_sai.c | 6 ++----
+ sound/soc/fsl/fsl_sai.h | 1 -
+ 2 files changed, 2 insertions(+), 5 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -599,8 +599,7 @@ static int fsl_sai_startup(struct snd_pc
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       int ret;
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx),
+-                         FSL_SAI_CR3_TRCE_MASK,
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE,
+                          FSL_SAI_CR3_TRCE);
+       ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
+@@ -615,8 +614,7 @@ static void fsl_sai_shutdown(struct snd_
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx),
+-                         FSL_SAI_CR3_TRCE_MASK, 0);
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
+ }
+ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -110,7 +110,6 @@
+ /* SAI Transmit and Receive Configuration 3 Register */
+ #define FSL_SAI_CR3_TRCE      BIT(16)
+-#define FSL_SAI_CR3_TRCE_MASK GENMASK(23, 16)
+ #define FSL_SAI_CR3_WDFL(x)   (x)
+ #define FSL_SAI_CR3_WDFL_MASK 0x1f
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0007-Revert-ASoC-fsl_sai-Add-registers-definition-for-mul.patch b/target/linux/layerscape/patches-5.4/801-audio-0007-Revert-ASoC-fsl_sai-Add-registers-definition-for-mul.patch
new file mode 100644 (file)
index 0000000..0cca97f
--- /dev/null
@@ -0,0 +1,184 @@
+From 56d254c9b7abf3e5632dd1b257927e23b4449019 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Fri, 16 Aug 2019 18:01:43 +0800
+Subject: [PATCH] Revert "ASoC: fsl_sai: Add registers definition for multiple
+ datalines"
+
+This reverts commit 5f0ac20ed6db1d6da2eea8b862cf3d54fdfb5830.
+---
+ sound/soc/fsl/fsl_sai.c | 76 +++++++------------------------------------------
+ sound/soc/fsl/fsl_sai.h | 36 +++--------------------
+ 2 files changed, 14 insertions(+), 98 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -685,14 +685,7 @@ static struct reg_default fsl_sai_reg_de
+       {FSL_SAI_TCR3, 0},
+       {FSL_SAI_TCR4, 0},
+       {FSL_SAI_TCR5, 0},
+-      {FSL_SAI_TDR0, 0},
+-      {FSL_SAI_TDR1, 0},
+-      {FSL_SAI_TDR2, 0},
+-      {FSL_SAI_TDR3, 0},
+-      {FSL_SAI_TDR4, 0},
+-      {FSL_SAI_TDR5, 0},
+-      {FSL_SAI_TDR6, 0},
+-      {FSL_SAI_TDR7, 0},
++      {FSL_SAI_TDR,  0},
+       {FSL_SAI_TMR,  0},
+       {FSL_SAI_RCR1, 0},
+       {FSL_SAI_RCR2, 0},
+@@ -711,14 +704,7 @@ static bool fsl_sai_readable_reg(struct
+       case FSL_SAI_TCR3:
+       case FSL_SAI_TCR4:
+       case FSL_SAI_TCR5:
+-      case FSL_SAI_TFR0:
+-      case FSL_SAI_TFR1:
+-      case FSL_SAI_TFR2:
+-      case FSL_SAI_TFR3:
+-      case FSL_SAI_TFR4:
+-      case FSL_SAI_TFR5:
+-      case FSL_SAI_TFR6:
+-      case FSL_SAI_TFR7:
++      case FSL_SAI_TFR:
+       case FSL_SAI_TMR:
+       case FSL_SAI_RCSR:
+       case FSL_SAI_RCR1:
+@@ -726,22 +712,8 @@ static bool fsl_sai_readable_reg(struct
+       case FSL_SAI_RCR3:
+       case FSL_SAI_RCR4:
+       case FSL_SAI_RCR5:
+-      case FSL_SAI_RDR0:
+-      case FSL_SAI_RDR1:
+-      case FSL_SAI_RDR2:
+-      case FSL_SAI_RDR3:
+-      case FSL_SAI_RDR4:
+-      case FSL_SAI_RDR5:
+-      case FSL_SAI_RDR6:
+-      case FSL_SAI_RDR7:
+-      case FSL_SAI_RFR0:
+-      case FSL_SAI_RFR1:
+-      case FSL_SAI_RFR2:
+-      case FSL_SAI_RFR3:
+-      case FSL_SAI_RFR4:
+-      case FSL_SAI_RFR5:
+-      case FSL_SAI_RFR6:
+-      case FSL_SAI_RFR7:
++      case FSL_SAI_RDR:
++      case FSL_SAI_RFR:
+       case FSL_SAI_RMR:
+               return true;
+       default:
+@@ -754,30 +726,9 @@ static bool fsl_sai_volatile_reg(struct
+       switch (reg) {
+       case FSL_SAI_TCSR:
+       case FSL_SAI_RCSR:
+-      case FSL_SAI_TFR0:
+-      case FSL_SAI_TFR1:
+-      case FSL_SAI_TFR2:
+-      case FSL_SAI_TFR3:
+-      case FSL_SAI_TFR4:
+-      case FSL_SAI_TFR5:
+-      case FSL_SAI_TFR6:
+-      case FSL_SAI_TFR7:
+-      case FSL_SAI_RFR0:
+-      case FSL_SAI_RFR1:
+-      case FSL_SAI_RFR2:
+-      case FSL_SAI_RFR3:
+-      case FSL_SAI_RFR4:
+-      case FSL_SAI_RFR5:
+-      case FSL_SAI_RFR6:
+-      case FSL_SAI_RFR7:
+-      case FSL_SAI_RDR0:
+-      case FSL_SAI_RDR1:
+-      case FSL_SAI_RDR2:
+-      case FSL_SAI_RDR3:
+-      case FSL_SAI_RDR4:
+-      case FSL_SAI_RDR5:
+-      case FSL_SAI_RDR6:
+-      case FSL_SAI_RDR7:
++      case FSL_SAI_TFR:
++      case FSL_SAI_RFR:
++      case FSL_SAI_RDR:
+               return true;
+       default:
+               return false;
+@@ -793,14 +744,7 @@ static bool fsl_sai_writeable_reg(struct
+       case FSL_SAI_TCR3:
+       case FSL_SAI_TCR4:
+       case FSL_SAI_TCR5:
+-      case FSL_SAI_TDR0:
+-      case FSL_SAI_TDR1:
+-      case FSL_SAI_TDR2:
+-      case FSL_SAI_TDR3:
+-      case FSL_SAI_TDR4:
+-      case FSL_SAI_TDR5:
+-      case FSL_SAI_TDR6:
+-      case FSL_SAI_TDR7:
++      case FSL_SAI_TDR:
+       case FSL_SAI_TMR:
+       case FSL_SAI_RCSR:
+       case FSL_SAI_RCR1:
+@@ -939,8 +883,8 @@ static int fsl_sai_probe(struct platform
+                                  MCLK_DIR(index));
+       }
+-      sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0;
+-      sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0;
++      sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
++      sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
+       sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
+       sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -20,22 +20,8 @@
+ #define FSL_SAI_TCR3  0x0c /* SAI Transmit Configuration 3 */
+ #define FSL_SAI_TCR4  0x10 /* SAI Transmit Configuration 4 */
+ #define FSL_SAI_TCR5  0x14 /* SAI Transmit Configuration 5 */
+-#define FSL_SAI_TDR0  0x20 /* SAI Transmit Data 0 */
+-#define FSL_SAI_TDR1  0x24 /* SAI Transmit Data 1 */
+-#define FSL_SAI_TDR2  0x28 /* SAI Transmit Data 2 */
+-#define FSL_SAI_TDR3  0x2C /* SAI Transmit Data 3 */
+-#define FSL_SAI_TDR4  0x30 /* SAI Transmit Data 4 */
+-#define FSL_SAI_TDR5  0x34 /* SAI Transmit Data 5 */
+-#define FSL_SAI_TDR6  0x38 /* SAI Transmit Data 6 */
+-#define FSL_SAI_TDR7  0x3C /* SAI Transmit Data 7 */
+-#define FSL_SAI_TFR0  0x40 /* SAI Transmit FIFO 0 */
+-#define FSL_SAI_TFR1  0x44 /* SAI Transmit FIFO 1 */
+-#define FSL_SAI_TFR2  0x48 /* SAI Transmit FIFO 2 */
+-#define FSL_SAI_TFR3  0x4C /* SAI Transmit FIFO 3 */
+-#define FSL_SAI_TFR4  0x50 /* SAI Transmit FIFO 4 */
+-#define FSL_SAI_TFR5  0x54 /* SAI Transmit FIFO 5 */
+-#define FSL_SAI_TFR6  0x58 /* SAI Transmit FIFO 6 */
+-#define FSL_SAI_TFR7  0x5C /* SAI Transmit FIFO 7 */
++#define FSL_SAI_TDR   0x20 /* SAI Transmit Data */
++#define FSL_SAI_TFR   0x40 /* SAI Transmit FIFO */
+ #define FSL_SAI_TMR   0x60 /* SAI Transmit Mask */
+ #define FSL_SAI_RCSR  0x80 /* SAI Receive Control */
+ #define FSL_SAI_RCR1  0x84 /* SAI Receive Configuration 1 */
+@@ -43,22 +29,8 @@
+ #define FSL_SAI_RCR3  0x8c /* SAI Receive Configuration 3 */
+ #define FSL_SAI_RCR4  0x90 /* SAI Receive Configuration 4 */
+ #define FSL_SAI_RCR5  0x94 /* SAI Receive Configuration 5 */
+-#define FSL_SAI_RDR0  0xa0 /* SAI Receive Data 0 */
+-#define FSL_SAI_RDR1  0xa4 /* SAI Receive Data 1 */
+-#define FSL_SAI_RDR2  0xa8 /* SAI Receive Data 2 */
+-#define FSL_SAI_RDR3  0xac /* SAI Receive Data 3 */
+-#define FSL_SAI_RDR4  0xb0 /* SAI Receive Data 4 */
+-#define FSL_SAI_RDR5  0xb4 /* SAI Receive Data 5 */
+-#define FSL_SAI_RDR6  0xb8 /* SAI Receive Data 6 */
+-#define FSL_SAI_RDR7  0xbc /* SAI Receive Data 7 */
+-#define FSL_SAI_RFR0  0xc0 /* SAI Receive FIFO 0 */
+-#define FSL_SAI_RFR1  0xc4 /* SAI Receive FIFO 1 */
+-#define FSL_SAI_RFR2  0xc8 /* SAI Receive FIFO 2 */
+-#define FSL_SAI_RFR3  0xcc /* SAI Receive FIFO 3 */
+-#define FSL_SAI_RFR4  0xd0 /* SAI Receive FIFO 4 */
+-#define FSL_SAI_RFR5  0xd4 /* SAI Receive FIFO 5 */
+-#define FSL_SAI_RFR6  0xd8 /* SAI Receive FIFO 6 */
+-#define FSL_SAI_RFR7  0xdc /* SAI Receive FIFO 7 */
++#define FSL_SAI_RDR   0xa0 /* SAI Receive Data */
++#define FSL_SAI_RFR   0xc0 /* SAI Receive FIFO */
+ #define FSL_SAI_RMR   0xe0 /* SAI Receive Mask */
+ #define FSL_SAI_xCSR(tx)      (tx ? FSL_SAI_TCSR : FSL_SAI_RCSR)
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0008-Revert-ASoC-Remove-dev_err-usage-after-platform_get_.patch b/target/linux/layerscape/patches-5.4/801-audio-0008-Revert-ASoC-Remove-dev_err-usage-after-platform_get_.patch
new file mode 100644 (file)
index 0000000..4b61c0e
--- /dev/null
@@ -0,0 +1,467 @@
+From b3aa9fe657c5e96659d64e6b008e025b433616ad Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Fri, 16 Aug 2019 18:01:53 +0800
+Subject: [PATCH] Revert "ASoC: Remove dev_err() usage after
+ platform_get_irq()"
+
+This reverts commit cf9441adb1a35506d7606866c382b9d8614169b5.
+---
+ sound/soc/atmel/atmel-classd.c             |  7 +++++--
+ sound/soc/atmel/atmel-pdmic.c              |  7 +++++--
+ sound/soc/bcm/cygnus-ssp.c                 |  7 +++++--
+ sound/soc/codecs/msm8916-wcd-analog.c      | 12 +++++++++---
+ sound/soc/codecs/twl6040.c                 |  4 +++-
+ sound/soc/fsl/fsl_asrc.c                   |  4 +++-
+ sound/soc/fsl/fsl_esai.c                   |  4 +++-
+ sound/soc/fsl/fsl_sai.c                    |  4 +++-
+ sound/soc/fsl/fsl_spdif.c                  |  4 +++-
+ sound/soc/fsl/fsl_ssi.c                    |  4 +++-
+ sound/soc/fsl/imx-ssi.c                    |  4 +++-
+ sound/soc/kirkwood/kirkwood-i2s.c          |  4 +++-
+ sound/soc/mediatek/common/mtk-btcvsd.c     |  4 +++-
+ sound/soc/mediatek/mt2701/mt2701-afe-pcm.c |  4 +++-
+ sound/soc/mediatek/mt8173/mt8173-afe-pcm.c |  4 +++-
+ sound/soc/mxs/mxs-saif.c                   |  8 ++++++--
+ sound/soc/qcom/lpass-platform.c            |  5 ++++-
+ sound/soc/sof/intel/bdw.c                  |  5 ++++-
+ sound/soc/sof/intel/byt.c                  |  5 ++++-
+ sound/soc/sprd/sprd-mcdt.c                 |  4 +++-
+ sound/soc/sti/sti_uniperif.c               |  4 +++-
+ sound/soc/stm/stm32_i2s.c                  |  5 ++++-
+ sound/soc/stm/stm32_sai.c                  |  4 +++-
+ sound/soc/stm/stm32_spdifrx.c              |  4 +++-
+ sound/soc/sunxi/sun4i-i2s.c                |  4 +++-
+ sound/soc/uniphier/aio-dma.c               |  4 +++-
+ sound/soc/xilinx/xlnx_formatter_pcm.c      |  2 ++
+ sound/soc/xtensa/xtfpga-i2s.c              |  1 +
+ 28 files changed, 100 insertions(+), 32 deletions(-)
+
+--- a/sound/soc/atmel/atmel-classd.c
++++ b/sound/soc/atmel/atmel-classd.c
+@@ -571,8 +571,11 @@ static int atmel_classd_probe(struct pla
+       dd->pdata = pdata;
+       dd->irq = platform_get_irq(pdev, 0);
+-      if (dd->irq < 0)
+-              return dd->irq;
++      if (dd->irq < 0) {
++              ret = dd->irq;
++              dev_err(dev, "failed to could not get irq: %d\n", ret);
++              return ret;
++      }
+       dd->pclk = devm_clk_get(dev, "pclk");
+       if (IS_ERR(dd->pclk)) {
+--- a/sound/soc/atmel/atmel-pdmic.c
++++ b/sound/soc/atmel/atmel-pdmic.c
+@@ -612,8 +612,11 @@ static int atmel_pdmic_probe(struct plat
+       dd->dev = dev;
+       dd->irq = platform_get_irq(pdev, 0);
+-      if (dd->irq < 0)
+-              return dd->irq;
++      if (dd->irq < 0) {
++              ret = dd->irq;
++              dev_err(dev, "failed to get irq: %d\n", ret);
++              return ret;
++      }
+       dd->pclk = devm_clk_get(dev, "pclk");
+       if (IS_ERR(dd->pclk)) {
+--- a/sound/soc/bcm/cygnus-ssp.c
++++ b/sound/soc/bcm/cygnus-ssp.c
+@@ -1342,8 +1342,11 @@ static int cygnus_ssp_probe(struct platf
+       }
+       cygaud->irq_num = platform_get_irq(pdev, 0);
+-      if (cygaud->irq_num <= 0)
+-              return cygaud->irq_num;
++      if (cygaud->irq_num <= 0) {
++              dev_err(dev, "platform_get_irq failed\n");
++              err = cygaud->irq_num;
++              return err;
++      }
+       err = audio_clk_init(pdev, cygaud);
+       if (err) {
+--- a/sound/soc/codecs/msm8916-wcd-analog.c
++++ b/sound/soc/codecs/msm8916-wcd-analog.c
+@@ -1195,8 +1195,10 @@ static int pm8916_wcd_analog_spmi_probe(
+       }
+       irq = platform_get_irq_byname(pdev, "mbhc_switch_int");
+-      if (irq < 0)
++      if (irq < 0) {
++              dev_err(dev, "failed to get mbhc switch irq\n");
+               return irq;
++      }
+       ret = devm_request_threaded_irq(dev, irq, NULL,
+                              pm8916_mbhc_switch_irq_handler,
+@@ -1208,8 +1210,10 @@ static int pm8916_wcd_analog_spmi_probe(
+       if (priv->mbhc_btn_enabled) {
+               irq = platform_get_irq_byname(pdev, "mbhc_but_press_det");
+-              if (irq < 0)
++              if (irq < 0) {
++                      dev_err(dev, "failed to get button press irq\n");
+                       return irq;
++              }
+               ret = devm_request_threaded_irq(dev, irq, NULL,
+                                      mbhc_btn_press_irq_handler,
+@@ -1220,8 +1224,10 @@ static int pm8916_wcd_analog_spmi_probe(
+                       dev_err(dev, "cannot request mbhc button press irq\n");
+               irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det");
+-              if (irq < 0)
++              if (irq < 0) {
++                      dev_err(dev, "failed to get button release irq\n");
+                       return irq;
++              }
+               ret = devm_request_threaded_irq(dev, irq, NULL,
+                                      mbhc_btn_release_irq_handler,
+--- a/sound/soc/codecs/twl6040.c
++++ b/sound/soc/codecs/twl6040.c
+@@ -1108,8 +1108,10 @@ static int twl6040_probe(struct snd_soc_
+       priv->component = component;
+       priv->plug_irq = platform_get_irq(pdev, 0);
+-      if (priv->plug_irq < 0)
++      if (priv->plug_irq < 0) {
++              dev_err(component->dev, "invalid irq: %d\n", priv->plug_irq);
+               return priv->plug_irq;
++      }
+       INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work);
+--- a/sound/soc/fsl/fsl_asrc.c
++++ b/sound/soc/fsl/fsl_asrc.c
+@@ -885,8 +885,10 @@ static int fsl_asrc_probe(struct platfor
+       }
+       irq = platform_get_irq(pdev, 0);
+-      if (irq < 0)
++      if (irq < 0) {
++              dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+               return irq;
++      }
+       ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0,
+                              dev_name(&pdev->dev), asrc_priv);
+--- a/sound/soc/fsl/fsl_esai.c
++++ b/sound/soc/fsl/fsl_esai.c
+@@ -973,8 +973,10 @@ static int fsl_esai_probe(struct platfor
+                               PTR_ERR(esai_priv->spbaclk));
+       irq = platform_get_irq(pdev, 0);
+-      if (irq < 0)
++      if (irq < 0) {
++              dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+               return irq;
++      }
+       ret = devm_request_irq(&pdev->dev, irq, esai_isr, 0,
+                              esai_priv->name, esai_priv);
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -831,8 +831,10 @@ static int fsl_sai_probe(struct platform
+       }
+       irq = platform_get_irq(pdev, 0);
+-      if (irq < 0)
++      if (irq < 0) {
++              dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+               return irq;
++      }
+       ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, 0, np->name, sai);
+       if (ret) {
+--- a/sound/soc/fsl/fsl_spdif.c
++++ b/sound/soc/fsl/fsl_spdif.c
+@@ -1248,8 +1248,10 @@ static int fsl_spdif_probe(struct platfo
+       }
+       irq = platform_get_irq(pdev, 0);
+-      if (irq < 0)
++      if (irq < 0) {
++              dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+               return irq;
++      }
+       ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
+                              dev_name(&pdev->dev), spdif_priv);
+--- a/sound/soc/fsl/fsl_ssi.c
++++ b/sound/soc/fsl/fsl_ssi.c
+@@ -1510,8 +1510,10 @@ static int fsl_ssi_probe(struct platform
+       }
+       ssi->irq = platform_get_irq(pdev, 0);
+-      if (ssi->irq < 0)
++      if (ssi->irq < 0) {
++              dev_err(dev, "no irq for node %s\n", pdev->name);
+               return ssi->irq;
++      }
+       /* Set software limitations for synchronous mode except AC97 */
+       if (ssi->synchronous && !fsl_ssi_is_ac97(ssi)) {
+--- a/sound/soc/fsl/imx-ssi.c
++++ b/sound/soc/fsl/imx-ssi.c
+@@ -520,8 +520,10 @@ static int imx_ssi_probe(struct platform
+       }
+       ssi->irq = platform_get_irq(pdev, 0);
+-      if (ssi->irq < 0)
++      if (ssi->irq < 0) {
++              dev_err(&pdev->dev, "Failed to get IRQ: %d\n", ssi->irq);
+               return ssi->irq;
++      }
+       ssi->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(ssi->clk)) {
+--- a/sound/soc/kirkwood/kirkwood-i2s.c
++++ b/sound/soc/kirkwood/kirkwood-i2s.c
+@@ -537,8 +537,10 @@ static int kirkwood_i2s_dev_probe(struct
+               return PTR_ERR(priv->io);
+       priv->irq = platform_get_irq(pdev, 0);
+-      if (priv->irq < 0)
++      if (priv->irq < 0) {
++              dev_err(&pdev->dev, "platform_get_irq failed: %d\n", priv->irq);
+               return priv->irq;
++      }
+       if (np) {
+               priv->burst = 128;              /* might be 32 or 128 */
+--- a/sound/soc/mediatek/common/mtk-btcvsd.c
++++ b/sound/soc/mediatek/common/mtk-btcvsd.c
+@@ -1335,8 +1335,10 @@ static int mtk_btcvsd_snd_probe(struct p
+       /* irq */
+       irq_id = platform_get_irq(pdev, 0);
+-      if (irq_id <= 0)
++      if (irq_id <= 0) {
++              dev_err(dev, "%pOFn no irq found\n", dev->of_node);
+               return irq_id < 0 ? irq_id : -ENXIO;
++      }
+       ret = devm_request_irq(dev, irq_id, mtk_btcvsd_snd_irq_handler,
+                              IRQF_TRIGGER_LOW, "BTCVSD_ISR_Handle",
+--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
++++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+@@ -1350,8 +1350,10 @@ static int mt2701_afe_pcm_dev_probe(stru
+               return -ENOMEM;
+       irq_id = platform_get_irq_byname(pdev, "asys");
+-      if (irq_id < 0)
++      if (irq_id < 0) {
++              dev_err(dev, "unable to get ASYS IRQ\n");
+               return irq_id;
++      }
+       ret = devm_request_irq(dev, irq_id, mt2701_asys_isr,
+                              IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
+--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
++++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
+@@ -1074,8 +1074,10 @@ static int mt8173_afe_pcm_dev_probe(stru
+       afe->dev = &pdev->dev;
+       irq_id = platform_get_irq(pdev, 0);
+-      if (irq_id <= 0)
++      if (irq_id <= 0) {
++              dev_err(afe->dev, "np %pOFn no irq\n", afe->dev->of_node);
+               return irq_id < 0 ? irq_id : -ENXIO;
++      }
+       ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler,
+                              0, "Afe_ISR_Handle", (void *)afe);
+       if (ret) {
+--- a/sound/soc/mxs/mxs-saif.c
++++ b/sound/soc/mxs/mxs-saif.c
+@@ -790,8 +790,12 @@ static int mxs_saif_probe(struct platfor
+               return PTR_ERR(saif->base);
+       irq = platform_get_irq(pdev, 0);
+-      if (irq < 0)
+-              return irq;
++      if (irq < 0) {
++              ret = irq;
++              dev_err(&pdev->dev, "failed to get irq resource: %d\n",
++                      ret);
++              return ret;
++      }
+       saif->dev = &pdev->dev;
+       ret = devm_request_irq(&pdev->dev, irq, mxs_saif_irq, 0,
+--- a/sound/soc/qcom/lpass-platform.c
++++ b/sound/soc/qcom/lpass-platform.c
+@@ -564,8 +564,11 @@ int asoc_qcom_lpass_platform_register(st
+       int ret;
+       drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
+-      if (drvdata->lpaif_irq < 0)
++      if (drvdata->lpaif_irq < 0) {
++              dev_err(&pdev->dev, "error getting irq handle: %d\n",
++                      drvdata->lpaif_irq);
+               return -ENODEV;
++      }
+       /* ensure audio hardware is disabled */
+       ret = regmap_write(drvdata->lpaif_map,
+--- a/sound/soc/sof/intel/bdw.c
++++ b/sound/soc/sof/intel/bdw.c
+@@ -483,8 +483,11 @@ static int bdw_probe(struct snd_sof_dev
+       /* register our IRQ */
+       sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
+-      if (sdev->ipc_irq < 0)
++      if (sdev->ipc_irq < 0) {
++              dev_err(sdev->dev, "error: failed to get IRQ at index %d\n",
++                      desc->irqindex_host_ipc);
+               return sdev->ipc_irq;
++      }
+       dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq);
+       ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq,
+--- a/sound/soc/sof/intel/byt.c
++++ b/sound/soc/sof/intel/byt.c
+@@ -600,8 +600,11 @@ static int byt_acpi_probe(struct snd_sof
+ irq:
+       /* register our IRQ */
+       sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
+-      if (sdev->ipc_irq < 0)
++      if (sdev->ipc_irq < 0) {
++              dev_err(sdev->dev, "error: failed to get IRQ at index %d\n",
++                      desc->irqindex_host_ipc);
+               return sdev->ipc_irq;
++      }
+       dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq);
+       ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq,
+--- a/sound/soc/sprd/sprd-mcdt.c
++++ b/sound/soc/sprd/sprd-mcdt.c
+@@ -959,8 +959,10 @@ static int sprd_mcdt_probe(struct platfo
+       platform_set_drvdata(pdev, mcdt);
+       irq = platform_get_irq(pdev, 0);
+-      if (irq < 0)
++      if (irq < 0) {
++              dev_err(&pdev->dev, "Failed to get MCDT interrupt\n");
+               return irq;
++      }
+       ret = devm_request_irq(&pdev->dev, irq, sprd_mcdt_irq_handler,
+                              0, "sprd-mcdt", mcdt);
+--- a/sound/soc/sti/sti_uniperif.c
++++ b/sound/soc/sti/sti_uniperif.c
+@@ -426,8 +426,10 @@ static int sti_uniperiph_cpu_dai_of(stru
+                                    UNIPERIF_FIFO_DATA_OFFSET(uni);
+       uni->irq = platform_get_irq(priv->pdev, 0);
+-      if (uni->irq < 0)
++      if (uni->irq < 0) {
++              dev_err(dev, "Failed to get IRQ resource\n");
+               return -ENXIO;
++      }
+       uni->type = dev_data->type;
+--- a/sound/soc/stm/stm32_i2s.c
++++ b/sound/soc/stm/stm32_i2s.c
+@@ -855,8 +855,11 @@ static int stm32_i2s_parse_dt(struct pla
+       /* Get irqs */
+       irq = platform_get_irq(pdev, 0);
+-      if (irq < 0)
++      if (irq < 0) {
++              if (irq != -EPROBE_DEFER)
++                      dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+               return irq;
++      }
+       ret = devm_request_irq(&pdev->dev, irq, stm32_i2s_isr, IRQF_ONESHOT,
+                              dev_name(&pdev->dev), i2s);
+--- a/sound/soc/stm/stm32_sai.c
++++ b/sound/soc/stm/stm32_sai.c
+@@ -193,8 +193,10 @@ static int stm32_sai_probe(struct platfo
+       /* init irqs */
+       sai->irq = platform_get_irq(pdev, 0);
+-      if (sai->irq < 0)
++      if (sai->irq < 0) {
++              dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+               return sai->irq;
++      }
+       /* reset */
+       rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+--- a/sound/soc/stm/stm32_spdifrx.c
++++ b/sound/soc/stm/stm32_spdifrx.c
+@@ -920,8 +920,10 @@ static int stm32_spdifrx_parse_of(struct
+       }
+       spdifrx->irq = platform_get_irq(pdev, 0);
+-      if (spdifrx->irq < 0)
++      if (spdifrx->irq < 0) {
++              dev_err(&pdev->dev, "No irq for node %s\n", pdev->name);
+               return spdifrx->irq;
++      }
+       return 0;
+ }
+--- a/sound/soc/sunxi/sun4i-i2s.c
++++ b/sound/soc/sunxi/sun4i-i2s.c
+@@ -1198,8 +1198,10 @@ static int sun4i_i2s_probe(struct platfo
+               return PTR_ERR(regs);
+       irq = platform_get_irq(pdev, 0);
+-      if (irq < 0)
++      if (irq < 0) {
++              dev_err(&pdev->dev, "Can't retrieve our interrupt\n");
+               return irq;
++      }
+       i2s->variant = of_device_get_match_data(&pdev->dev);
+       if (!i2s->variant) {
+--- a/sound/soc/uniphier/aio-dma.c
++++ b/sound/soc/uniphier/aio-dma.c
+@@ -289,8 +289,10 @@ int uniphier_aiodma_soc_register_platfor
+               return PTR_ERR(chip->regmap);
+       irq = platform_get_irq(pdev, 0);
+-      if (irq < 0)
++      if (irq < 0) {
++              dev_err(dev, "Could not get irq.\n");
+               return irq;
++      }
+       ret = devm_request_irq(dev, irq, aiodma_irq,
+                              IRQF_SHARED, dev_name(dev), pdev);
+--- a/sound/soc/xilinx/xlnx_formatter_pcm.c
++++ b/sound/soc/xilinx/xlnx_formatter_pcm.c
+@@ -613,6 +613,7 @@ static int xlnx_formatter_pcm_probe(stru
+               aud_drv_data->mm2s_irq = platform_get_irq_byname(pdev,
+                                                                "irq_mm2s");
+               if (aud_drv_data->mm2s_irq < 0) {
++                      dev_err(dev, "xlnx audio mm2s irq resource failed\n");
+                       ret = aud_drv_data->mm2s_irq;
+                       goto clk_err;
+               }
+@@ -639,6 +640,7 @@ static int xlnx_formatter_pcm_probe(stru
+               aud_drv_data->s2mm_irq = platform_get_irq_byname(pdev,
+                                                                "irq_s2mm");
+               if (aud_drv_data->s2mm_irq < 0) {
++                      dev_err(dev, "xlnx audio s2mm irq resource failed\n");
+                       ret = aud_drv_data->s2mm_irq;
+                       goto clk_err;
+               }
+--- a/sound/soc/xtensa/xtfpga-i2s.c
++++ b/sound/soc/xtensa/xtfpga-i2s.c
+@@ -570,6 +570,7 @@ static int xtfpga_i2s_probe(struct platf
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
++              dev_err(&pdev->dev, "No IRQ resource\n");
+               err = irq;
+               goto err;
+       }
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0009-Revert-ASoC-fsl_sai-mark-regmap-as-fast_io.patch b/target/linux/layerscape/patches-5.4/801-audio-0009-Revert-ASoC-fsl_sai-mark-regmap-as-fast_io.patch
new file mode 100644 (file)
index 0000000..454bfd5
--- /dev/null
@@ -0,0 +1,20 @@
+From 6efe2223fa2de658d9017e2abd0ab4849430ef9c Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Wed, 31 Jul 2019 17:11:24 +0800
+Subject: [PATCH] Revert "ASoC: fsl_sai: mark regmap as fast_io"
+
+This reverts commit 6d19d8a3cec74a9680947ecb6abdeda38583110e.
+---
+ sound/soc/fsl/fsl_sai.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -763,7 +763,6 @@ static const struct regmap_config fsl_sa
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+-      .fast_io = true,
+       .max_register = FSL_SAI_RMR,
+       .reg_defaults = fsl_sai_reg_defaults,
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0010-Revert-ASoC-fsl_sai-derive-TX-FIFO-watermark-from-FI.patch b/target/linux/layerscape/patches-5.4/801-audio-0010-Revert-ASoC-fsl_sai-derive-TX-FIFO-watermark-from-FI.patch
new file mode 100644 (file)
index 0000000..33e6c7d
--- /dev/null
@@ -0,0 +1,46 @@
+From 33c1f03b9eca0c192708c9df295d2a30073cd121 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Wed, 31 Jul 2019 17:11:32 +0800
+Subject: [PATCH] Revert "ASoC: fsl_sai: derive TX FIFO watermark from FIFO
+ depth"
+
+This reverts commit bd517707d85f19a7339ea8b882fcbf0fd9976bd6.
+---
+ sound/soc/fsl/fsl_sai.c | 4 +---
+ sound/soc/fsl/fsl_sai.h | 1 -
+ 2 files changed, 1 insertion(+), 4 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -640,7 +640,7 @@ static int fsl_sai_dai_probe(struct snd_
+       regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
+       regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
+-                         sai->soc_data->fifo_depth - FSL_SAI_MAXBURST_TX);
++                         FSL_SAI_MAXBURST_TX * 2);
+       regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
+                          FSL_SAI_MAXBURST_RX - 1);
+@@ -925,12 +925,10 @@ static int fsl_sai_remove(struct platfor
+ static const struct fsl_sai_soc_data fsl_sai_vf610_data = {
+       .use_imx_pcm = false,
+-      .fifo_depth = 32,
+ };
+ static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = {
+       .use_imx_pcm = true,
+-      .fifo_depth = 32,
+ };
+ static const struct of_device_id fsl_sai_ids[] = {
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -128,7 +128,6 @@
+ struct fsl_sai_soc_data {
+       bool use_imx_pcm;
+-      unsigned int fifo_depth;
+ };
+ struct fsl_sai {
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0011-Revert-ASoC-fsl_sai-add-of_match-data.patch b/target/linux/layerscape/patches-5.4/801-audio-0011-Revert-ASoC-fsl_sai-add-of_match-data.patch
new file mode 100644 (file)
index 0000000..465c331
--- /dev/null
@@ -0,0 +1,96 @@
+From 6e0abca40338d5078be0e5947c7f9723b40bc7e7 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Mon, 30 Mar 2020 16:17:52 +0800
+Subject: [PATCH] Revert "ASoC: fsl_sai: add of_match data"
+
+This reverts commit 89c9679f699d88986ce552738dc7c5c500c8fc67.
+
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 22 ++++++++--------------
+ sound/soc/fsl/fsl_sai.h |  6 +-----
+ 2 files changed, 9 insertions(+), 19 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -9,7 +9,6 @@
+ #include <linux/dmaengine.h>
+ #include <linux/module.h>
+ #include <linux/of_address.h>
+-#include <linux/of_device.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/regmap.h>
+ #include <linux/slab.h>
+@@ -789,7 +788,10 @@ static int fsl_sai_probe(struct platform
+               return -ENOMEM;
+       sai->pdev = pdev;
+-      sai->soc_data = of_device_get_match_data(&pdev->dev);
++
++      if (of_device_is_compatible(np, "fsl,imx6sx-sai") ||
++          of_device_is_compatible(np, "fsl,imx6ul-sai"))
++              sai->sai_on_imx = true;
+       sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
+@@ -898,7 +900,7 @@ static int fsl_sai_probe(struct platform
+       if (ret)
+               goto err_pm_disable;
+-      if (sai->soc_data->use_imx_pcm) {
++      if (sai->sai_on_imx)
+               ret = imx_pcm_dma_init(pdev, IMX_SAI_DMABUF_SIZE);
+               if (ret)
+                       goto err_pm_disable;
+@@ -923,18 +925,10 @@ static int fsl_sai_remove(struct platfor
+       return 0;
+ }
+-static const struct fsl_sai_soc_data fsl_sai_vf610_data = {
+-      .use_imx_pcm = false,
+-};
+-
+-static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = {
+-      .use_imx_pcm = true,
+-};
+-
+ static const struct of_device_id fsl_sai_ids[] = {
+-      { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data },
+-      { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data },
+-      { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6sx_data },
++      { .compatible = "fsl,vf610-sai", },
++      { .compatible = "fsl,imx6sx-sai", },
++      { .compatible = "fsl,imx6ul-sai", },
+       { /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, fsl_sai_ids);
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -126,10 +126,6 @@
+ #define FSL_SAI_MAXBURST_TX 6
+ #define FSL_SAI_MAXBURST_RX 6
+-struct fsl_sai_soc_data {
+-      bool use_imx_pcm;
+-};
+-
+ struct fsl_sai {
+       struct platform_device *pdev;
+       struct regmap *regmap;
+@@ -139,6 +135,7 @@ struct fsl_sai {
+       bool is_slave_mode;
+       bool is_lsb_first;
+       bool is_dsp_mode;
++      bool sai_on_imx;
+       bool synchronous[2];
+       unsigned int mclk_id[2];
+@@ -146,7 +143,6 @@ struct fsl_sai {
+       unsigned int slots;
+       unsigned int slot_width;
+-      const struct fsl_sai_soc_data *soc_data;
+       struct snd_dmaengine_dai_dma_data dma_params_rx;
+       struct snd_dmaengine_dai_dma_data dma_params_tx;
+ };
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0012-MLK-9974-ASoC-fsl_sai-There-is-underrun-detected-in-.patch b/target/linux/layerscape/patches-5.4/801-audio-0012-MLK-9974-ASoC-fsl_sai-There-is-underrun-detected-in-.patch
new file mode 100644 (file)
index 0000000..3b7de3c
--- /dev/null
@@ -0,0 +1,39 @@
+From 2a7fa96feddb63d36d64336a994dc4132e8a5cd4 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@freescale.com>
+Date: Mon, 29 Dec 2014 13:40:08 +0800
+Subject: [PATCH] MLK-9974: ASoC: fsl_sai: There is underrun detected in the
+ beginning sometimes
+
+Write initial words to SAI FIFO to reduce underrun error
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
+(cherry picked from commit 7ba8ae883d84540fac5ed4147d124399537bc0b3)
+(cherry picked from commit f4435f35aa2a97551d2c4a12ca316c354a880f85)
+---
+ sound/soc/fsl/fsl_sai.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -506,7 +506,9 @@ static int fsl_sai_trigger(struct snd_pc
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
++      u8 channels = substream->runtime->channels;
+       u32 xcsr, count = 100;
++      int i;
+       /*
+        * Asynchronous mode: Clear SYNC for both Tx and Rx.
+@@ -529,6 +531,11 @@ static int fsl_sai_trigger(struct snd_pc
+               regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+                                  FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
++              for (i = 0; tx && i < channels; i++)
++                      regmap_write(sai->regmap, FSL_SAI_TDR, 0x0);
++              if (tx)
++                      udelay(10);
++
+               regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
+                                  FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+               regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0013-MLK-10611-1-ASoC-fsl-sai-Just-one-device-can-playbac.patch b/target/linux/layerscape/patches-5.4/801-audio-0013-MLK-10611-1-ASoC-fsl-sai-Just-one-device-can-playbac.patch
new file mode 100644 (file)
index 0000000..faff978
--- /dev/null
@@ -0,0 +1,51 @@
+From 0ab3461b68ccc1d4ffb37dbc7f2e57adc8aed0fb Mon Sep 17 00:00:00 2001
+From: Zidan Wang <zidan.wang@freescale.com>
+Date: Fri, 10 Apr 2015 09:52:36 +0800
+Subject: [PATCH] MLK-10611-1 ASoC: fsl-sai: Just one device can
+ playback(captrue) when using the same SAI
+
+Just one device can playback(captrue) when using the same SAI.
+
+Signed-off-by: Zidan Wang <zidan.wang@freescale.com>
+(cherry picked from commit 7981a488c4da440db21f0544b519b44636a0cabb)
+---
+ sound/soc/fsl/fsl_sai.c | 10 ++++++++++
+ sound/soc/fsl/fsl_sai.h |  1 +
+ 2 files changed, 11 insertions(+)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -605,6 +605,11 @@ static int fsl_sai_startup(struct snd_pc
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       int ret;
++      if (sai->is_stream_opened[tx])
++              return -EBUSY;
++      else
++              sai->is_stream_opened[tx] = true;
++
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE,
+                          FSL_SAI_CR3_TRCE);
+@@ -621,6 +626,11 @@ static void fsl_sai_shutdown(struct snd_
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
++
++      if (sai->is_stream_opened[tx]) {
++              regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
++              sai->is_stream_opened[tx] = false;
++      }
+ }
+ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -137,6 +137,7 @@ struct fsl_sai {
+       bool is_dsp_mode;
+       bool sai_on_imx;
+       bool synchronous[2];
++      bool is_stream_opened[2];
+       unsigned int mclk_id[2];
+       unsigned int mclk_streams;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0014-MLK-11628-ASoC-fsl_sai-add-initial-value-for-is_slav.patch b/target/linux/layerscape/patches-5.4/801-audio-0014-MLK-11628-ASoC-fsl_sai-add-initial-value-for-is_slav.patch
new file mode 100644 (file)
index 0000000..0fe2245
--- /dev/null
@@ -0,0 +1,25 @@
+From b40561fa263f3f9b06be0dd9b9e1665478d1def6 Mon Sep 17 00:00:00 2001
+From: Zidan Wang <zidan.wang@freescale.com>
+Date: Fri, 25 Sep 2015 14:27:00 +0800
+Subject: [PATCH] MLK-11628 ASoC: fsl_sai: add initial value for is_slave_mode
+
+After playback audio with sai<->wm8960 sound card, is_slave_mode
+will be set, but it will not be cleared. So playback audio with
+sai<->sii902x sound card will have no voice.
+
+Signed-off-by: Zidan Wang <zidan.wang@freescale.com>
+---
+ sound/soc/fsl/fsl_sai.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -264,6 +264,8 @@ static int fsl_sai_set_dai_fmt_tr(struct
+               return -EINVAL;
+       }
++      sai->is_slave_mode = false;
++
+       /* DAI clock master masks */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0015-ASoC-fsl-sai-set-xCR4-xCR5-xMR-for-SAI-master-mode.patch b/target/linux/layerscape/patches-5.4/801-audio-0015-ASoC-fsl-sai-set-xCR4-xCR5-xMR-for-SAI-master-mode.patch
new file mode 100644 (file)
index 0000000..8dbc6d1
--- /dev/null
@@ -0,0 +1,56 @@
+From 0b33246dfb59df34b2b834eb00f7aea75cbd4366 Mon Sep 17 00:00:00 2001
+From: Zidan Wang <zidan.wang@freescale.com>
+Date: Mon, 9 Nov 2015 19:03:13 +0800
+Subject: [PATCH] ASoC: fsl-sai: set xCR4/xCR5/xMR for SAI master mode
+
+For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will
+generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4),
+RCR5(TCR5) and RMR(TMR) for playback(capture), or there will be sync
+error sometimes.
+
+Signed-off-by: Zidan Wang <zidan.wang@freescale.com>
+Acked-by: Nicolin Chen <nicoleotsuka@gmail.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+(cherry picked from commit 51659ca069ce5bdf20675a7967a39ef8419e87f2)
+---
+ sound/soc/fsl/fsl_sai.c | 29 +++++++++++++++++++++++++++++
+ 1 file changed, 29 insertions(+)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -476,6 +476,35 @@ static int fsl_sai_hw_params(struct snd_
+               }
+       }
++      /*
++       * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will
++       * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4),
++       * RCR5(TCR5) and RMR(TMR) for playback(capture), or there will be sync
++       * error.
++       */
++
++      if (!sai->is_slave_mode) {
++              if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
++                      regmap_update_bits(sai->regmap, FSL_SAI_TCR4,
++                              FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
++                              val_cr4);
++                      regmap_update_bits(sai->regmap, FSL_SAI_TCR5,
++                              FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
++                              FSL_SAI_CR5_FBT_MASK, val_cr5);
++                      regmap_write(sai->regmap, FSL_SAI_TMR,
++                              ~0UL - ((1 << channels) - 1));
++              } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
++                      regmap_update_bits(sai->regmap, FSL_SAI_RCR4,
++                              FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
++                              val_cr4);
++                      regmap_update_bits(sai->regmap, FSL_SAI_RCR5,
++                              FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
++                              FSL_SAI_CR5_FBT_MASK, val_cr5);
++                      regmap_write(sai->regmap, FSL_SAI_RMR,
++                              ~0UL - ((1 << channels) - 1));
++              }
++      }
++
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
+                          FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+                          val_cr4);
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0016-MLK-12374-ASoC-fsl_sai-Change-the-dev_warn-to-dev_db.patch b/target/linux/layerscape/patches-5.4/801-audio-0016-MLK-12374-ASoC-fsl_sai-Change-the-dev_warn-to-dev_db.patch
new file mode 100644 (file)
index 0000000..9772d7d
--- /dev/null
@@ -0,0 +1,27 @@
+From 81b0102ac649207dff14b265311e6b3d2724adc4 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@freescale.com>
+Date: Thu, 4 Feb 2016 15:07:57 +0800
+Subject: [PATCH] MLK-12374: ASoC: fsl_sai: Change the dev_warn to dev_dbg
+
+When audio stop, it will first stop dma, then stop cpu_dai.
+If there is delay between dma stop and cpu dai stop, there
+will be underrun error, the print will cost time, then will
+cause another underrun error, it is a infinite loop.
+Which will cause the cpu dai can't stop.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
+---
+ sound/soc/fsl/fsl_sai.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -2,7 +2,7 @@
+ //
+ // Freescale ALSA SoC Digital Audio Interface (SAI) driver.
+ //
+-// Copyright 2012-2015 Freescale Semiconductor, Inc.
++// Copyright 2012-2016 Freescale Semiconductor, Inc.
+ #include <linux/clk.h>
+ #include <linux/delay.h>
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0017-MLK-12786-2-ASoC-fsl_sai-correct-the-clock-source-fo.patch b/target/linux/layerscape/patches-5.4/801-audio-0017-MLK-12786-2-ASoC-fsl_sai-correct-the-clock-source-fo.patch
new file mode 100644 (file)
index 0000000..470b1d0
--- /dev/null
@@ -0,0 +1,25 @@
+From ee6adaada426e3f04925f93b4372fa3534889775 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@freescale.com>
+Date: Thu, 12 May 2016 17:54:08 +0800
+Subject: [PATCH] MLK-12786-2: ASoC: fsl_sai: correct the clock source for
+ mclk0
+
+mclk0 is assigned through the device tree.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
+---
+ sound/soc/fsl/fsl_sai.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -868,8 +868,7 @@ static int fsl_sai_probe(struct platform
+               sai->bus_clk = NULL;
+       }
+-      sai->mclk_clk[0] = sai->bus_clk;
+-      for (i = 1; i < FSL_SAI_MCLK_MAX; i++) {
++      for (i = 0; i < FSL_SAI_MCLK_MAX; i++) {
+               sprintf(tmp, "mclk%d", i);
+               sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
+               if (IS_ERR(sai->mclk_clk[i])) {
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0018-MLK-13574-2-ASoC-fsl_sai-refine-driver-for-ip-upgrad.patch b/target/linux/layerscape/patches-5.4/801-audio-0018-MLK-13574-2-ASoC-fsl_sai-refine-driver-for-ip-upgrad.patch
new file mode 100644 (file)
index 0000000..2d770d0
--- /dev/null
@@ -0,0 +1,423 @@
+From c516c261c49d0ce9509d6b9623dec6a4e9f919c3 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@freescale.com>
+Date: Mon, 30 Mar 2020 16:21:00 +0800
+Subject: [PATCH] MLK-13574-2: ASoC: fsl_sai: refine driver for ip upgrade
+
+In imx7ulp1, the sai can support two TX channel and two RX
+channels, So the usage need to be updated.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 145 ++++++++++++++++++++++++++++++++++++++++--------
+ sound/soc/fsl/fsl_sai.h |  37 ++++++++++--
+ 2 files changed, 156 insertions(+), 26 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -8,16 +8,19 @@
+ #include <linux/delay.h>
+ #include <linux/dmaengine.h>
+ #include <linux/module.h>
++#include <linux/of_device.h>
+ #include <linux/of_address.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/regmap.h>
+ #include <linux/slab.h>
+ #include <linux/time.h>
++#include <linux/pm_qos.h>
+ #include <sound/core.h>
+ #include <sound/dmaengine_pcm.h>
+ #include <sound/pcm_params.h>
+ #include <linux/mfd/syscon.h>
+ #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
++#include <linux/pm_runtime.h>
+ #include "fsl_sai.h"
+ #include "imx-pcm.h"
+@@ -25,6 +28,39 @@
+ #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
+                      FSL_SAI_CSR_FEIE)
++static struct fsl_sai_soc_data fsl_sai_vf610 = {
++      .imx = false,
++      /*dataline is mask, not index*/
++      .dataline = 0x1,
++      .fifos = 1,
++      .fifo_depth = 32,
++      .flags = 0,
++};
++
++static struct fsl_sai_soc_data fsl_sai_imx6sx = {
++      .imx = true,
++      .dataline = 0x1,
++      .fifos = 1,
++      .fifo_depth = 32,
++      .flags = 0,
++};
++
++static struct fsl_sai_soc_data fsl_sai_imx6ul = {
++      .imx = true,
++      .dataline = 0x1,
++      .fifos = 1,
++      .fifo_depth = 32,
++      .flags = 0,
++};
++
++static struct fsl_sai_soc_data fsl_sai_imx7ulp = {
++      .imx = true,
++      .dataline = 0x3,
++      .fifos = 2,
++      .fifo_depth = 16,
++      .flags = SAI_FLAG_PMQOS,
++};
++
+ static const unsigned int fsl_sai_rates[] = {
+       8000, 11025, 12000, 16000, 22050,
+       24000, 32000, 44100, 48000, 64000,
+@@ -505,6 +541,29 @@ static int fsl_sai_hw_params(struct snd_
+               }
+       }
++      if (sai->soc->dataline != 0x1) {
++              switch (sai->dataline[tx]) {
++              case 0x0:
++                      break;
++              case 0x1:
++                      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
++                              FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT, 0);
++                      break;
++              case 0x2:
++                      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
++                              FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT,
++                              FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT);
++                      break;
++              case 0x3:
++                      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
++                              FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT,
++                              FSL_SAI_CR4_FCOMB_SOFT);
++                      break;
++              default:
++                      break;
++              }
++      }
++
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
+                          FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+                          val_cr4);
+@@ -563,14 +622,16 @@ static int fsl_sai_trigger(struct snd_pc
+                                  FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
+               for (i = 0; tx && i < channels; i++)
+-                      regmap_write(sai->regmap, FSL_SAI_TDR, 0x0);
++                      regmap_write(sai->regmap, FSL_SAI_TDR0, 0x0);
+               if (tx)
+                       udelay(10);
+-              regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
+-                                 FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+               regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
+                                  FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
++              regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
++                                 FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
++              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
++                                 FSL_SAI_CSR_SE, FSL_SAI_CSR_SE);
+               regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+                                  FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS);
+@@ -641,8 +702,8 @@ static int fsl_sai_startup(struct snd_pc
+       else
+               sai->is_stream_opened[tx] = true;
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE,
+-                         FSL_SAI_CR3_TRCE);
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE0|FSL_SAI_CR3_TRCE1,
++                         FSL_SAI_CR3_TRCE(sai->dataline[tx]));
+       ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &fsl_sai_rate_constraints);
+@@ -659,7 +720,7 @@ static void fsl_sai_shutdown(struct snd_
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
+       if (sai->is_stream_opened[tx]) {
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
++              regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE0 | FSL_SAI_CR3_TRCE1, 0);
+               sai->is_stream_opened[tx] = false;
+       }
+ }
+@@ -687,7 +748,7 @@ static int fsl_sai_dai_probe(struct snd_
+       regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
+       regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
+-                         FSL_SAI_MAXBURST_TX * 2);
++                         sai->soc->fifo_depth - FSL_SAI_MAXBURST_TX);
+       regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
+                          FSL_SAI_MAXBURST_RX - 1);
+@@ -732,7 +793,8 @@ static struct reg_default fsl_sai_reg_de
+       {FSL_SAI_TCR3, 0},
+       {FSL_SAI_TCR4, 0},
+       {FSL_SAI_TCR5, 0},
+-      {FSL_SAI_TDR,  0},
++      {FSL_SAI_TDR0, 0},
++      {FSL_SAI_TDR1, 0},
+       {FSL_SAI_TMR,  0},
+       {FSL_SAI_RCR1, 0},
+       {FSL_SAI_RCR2, 0},
+@@ -751,7 +813,8 @@ static bool fsl_sai_readable_reg(struct
+       case FSL_SAI_TCR3:
+       case FSL_SAI_TCR4:
+       case FSL_SAI_TCR5:
+-      case FSL_SAI_TFR:
++      case FSL_SAI_TFR0:
++      case FSL_SAI_TFR1:
+       case FSL_SAI_TMR:
+       case FSL_SAI_RCSR:
+       case FSL_SAI_RCR1:
+@@ -759,8 +822,10 @@ static bool fsl_sai_readable_reg(struct
+       case FSL_SAI_RCR3:
+       case FSL_SAI_RCR4:
+       case FSL_SAI_RCR5:
+-      case FSL_SAI_RDR:
+-      case FSL_SAI_RFR:
++      case FSL_SAI_RDR0:
++      case FSL_SAI_RDR1:
++      case FSL_SAI_RFR0:
++      case FSL_SAI_RFR1:
+       case FSL_SAI_RMR:
+               return true;
+       default:
+@@ -773,9 +838,12 @@ static bool fsl_sai_volatile_reg(struct
+       switch (reg) {
+       case FSL_SAI_TCSR:
+       case FSL_SAI_RCSR:
+-      case FSL_SAI_TFR:
+-      case FSL_SAI_RFR:
+-      case FSL_SAI_RDR:
++      case FSL_SAI_TFR0:
++      case FSL_SAI_TFR1:
++      case FSL_SAI_RFR0:
++      case FSL_SAI_RFR1:
++      case FSL_SAI_RDR0:
++      case FSL_SAI_RDR1:
+               return true;
+       default:
+               return false;
+@@ -791,7 +859,8 @@ static bool fsl_sai_writeable_reg(struct
+       case FSL_SAI_TCR3:
+       case FSL_SAI_TCR4:
+       case FSL_SAI_TCR5:
+-      case FSL_SAI_TDR:
++      case FSL_SAI_TDR0:
++      case FSL_SAI_TDR1:
+       case FSL_SAI_TMR:
+       case FSL_SAI_RCSR:
+       case FSL_SAI_RCR1:
+@@ -820,9 +889,19 @@ static const struct regmap_config fsl_sa
+       .cache_type = REGCACHE_FLAT,
+ };
++static const struct of_device_id fsl_sai_ids[] = {
++      { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610 },
++      { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx },
++      { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6ul },
++      { .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp },
++      { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, fsl_sai_ids);
++
+ static int fsl_sai_probe(struct platform_device *pdev)
+ {
+       struct device_node *np = pdev->dev.of_node;
++      const struct of_device_id *of_id;
+       struct fsl_sai *sai;
+       struct regmap *gpr;
+       struct resource *res;
+@@ -837,11 +916,12 @@ static int fsl_sai_probe(struct platform
+       sai->pdev = pdev;
+-      if (of_device_is_compatible(np, "fsl,imx6sx-sai") ||
+-          of_device_is_compatible(np, "fsl,imx6ul-sai"))
+-              sai->sai_on_imx = true;
++      of_id = of_match_device(fsl_sai_ids, &pdev->dev);
++      if (!of_id || !of_id->data)
++              return -EINVAL;
+       sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
++      sai->soc = of_id->data;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, res);
+@@ -873,11 +953,25 @@ static int fsl_sai_probe(struct platform
+               sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
+               if (IS_ERR(sai->mclk_clk[i])) {
+                       dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n",
+-                                      i + 1, PTR_ERR(sai->mclk_clk[i]));
++                                      i, PTR_ERR(sai->mclk_clk[i]));
+                       sai->mclk_clk[i] = NULL;
+               }
+       }
++      /*dataline mask for rx and tx*/
++      ret = of_property_read_u32_index(np, "fsl,dataline", 0, &sai->dataline[0]);
++      if (ret)
++              sai->dataline[0] = 1;
++
++      ret = of_property_read_u32_index(np, "fsl,dataline", 1, &sai->dataline[1]);
++      if (ret)
++              sai->dataline[1] = 1;
++
++      if ((sai->dataline[0] & (~sai->soc->dataline)) || sai->dataline[1] & (~sai->soc->dataline)) {
++              dev_err(&pdev->dev, "dataline setting error, Mask is 0x%x\n", sai->soc->dataline);
++              return -EINVAL;
++      }
++
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+@@ -933,8 +1027,8 @@ static int fsl_sai_probe(struct platform
+                                  MCLK_DIR(index));
+       }
+-      sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
+-      sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
++      sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0;
++      sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0;
+       sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
+       sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
+@@ -947,7 +1041,7 @@ static int fsl_sai_probe(struct platform
+       if (ret)
+               goto err_pm_disable;
+-      if (sai->sai_on_imx)
++      if (sai->soc->imx)
+               ret = imx_pcm_dma_init(pdev, IMX_SAI_DMABUF_SIZE);
+               if (ret)
+                       goto err_pm_disable;
+@@ -993,6 +1087,9 @@ static int fsl_sai_runtime_suspend(struc
+       clk_disable_unprepare(sai->bus_clk);
++      if (sai->soc->flags & SAI_FLAG_PMQOS)
++              pm_qos_remove_request(&sai->pm_qos_req);
++
+       regcache_cache_only(sai->regmap, true);
+       regcache_mark_dirty(sai->regmap);
+@@ -1022,6 +1119,10 @@ static int fsl_sai_runtime_resume(struct
+                       goto disable_tx_clk;
+       }
++      if (sai->soc->flags & SAI_FLAG_PMQOS)
++              pm_qos_add_request(&sai->pm_qos_req,
++                              PM_QOS_CPU_DMA_LATENCY, 0);
++
+       regcache_cache_only(sai->regmap, false);
+       regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR);
+       regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR);
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -1,11 +1,12 @@
+ /* SPDX-License-Identifier: GPL-2.0 */
+ /*
+- * Copyright 2012-2013 Freescale Semiconductor, Inc.
++ * Copyright 2012-2016 Freescale Semiconductor, Inc.
+  */
+ #ifndef __FSL_SAI_H
+ #define __FSL_SAI_H
++#include <linux/pm_qos.h>
+ #include <sound/dmaengine_pcm.h>
+ #define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+@@ -20,7 +21,10 @@
+ #define FSL_SAI_TCR3  0x0c /* SAI Transmit Configuration 3 */
+ #define FSL_SAI_TCR4  0x10 /* SAI Transmit Configuration 4 */
+ #define FSL_SAI_TCR5  0x14 /* SAI Transmit Configuration 5 */
+-#define FSL_SAI_TDR   0x20 /* SAI Transmit Data */
++#define FSL_SAI_TDR0    0x20 /* SAI Transmit Data */
++#define FSL_SAI_TDR1    0x24 /* SAI Transmit Data */
++#define FSL_SAI_TFR0    0x40 /* SAI Transmit FIFO */
++#define FSL_SAI_TFR1    0x44 /* SAI Transmit FIFO */
+ #define FSL_SAI_TFR   0x40 /* SAI Transmit FIFO */
+ #define FSL_SAI_TMR   0x60 /* SAI Transmit Mask */
+ #define FSL_SAI_RCSR  0x80 /* SAI Receive Control */
+@@ -29,7 +33,10 @@
+ #define FSL_SAI_RCR3  0x8c /* SAI Receive Configuration 3 */
+ #define FSL_SAI_RCR4  0x90 /* SAI Receive Configuration 4 */
+ #define FSL_SAI_RCR5  0x94 /* SAI Receive Configuration 5 */
+-#define FSL_SAI_RDR   0xa0 /* SAI Receive Data */
++#define FSL_SAI_RDR0    0xa0 /* SAI Receive Data */
++#define FSL_SAI_RDR1    0xa4 /* SAI Receive Data */
++#define FSL_SAI_RFR0    0xc0 /* SAI Receive FIFO */
++#define FSL_SAI_RFR1    0xc4 /* SAI Receive FIFO */
+ #define FSL_SAI_RFR   0xc0 /* SAI Receive FIFO */
+ #define FSL_SAI_RMR   0xe0 /* SAI Receive Mask */
+@@ -45,6 +52,7 @@
+ /* SAI Transmit/Receive Control Register */
+ #define FSL_SAI_CSR_TERE      BIT(31)
++#define FSL_SAI_CSR_SE                BIT(30)
+ #define FSL_SAI_CSR_FR                BIT(25)
+ #define FSL_SAI_CSR_SR                BIT(24)
+ #define FSL_SAI_CSR_xF_SHIFT  16
+@@ -81,11 +89,19 @@
+ #define FSL_SAI_CR2_DIV_MASK  0xff
+ /* SAI Transmit and Receive Configuration 3 Register */
+-#define FSL_SAI_CR3_TRCE      BIT(16)
++#define FSL_SAI_CR3_TRCE0     BIT(16)
++#define FSL_SAI_CR3_TRCE1     BIT(17)
++#define FSL_SAI_CR3_TRCE(x)   (x << 16)
+ #define FSL_SAI_CR3_WDFL(x)   (x)
+ #define FSL_SAI_CR3_WDFL_MASK 0x1f
+ /* SAI Transmit and Receive Configuration 4 Register */
++
++#define FSL_SAI_CR4_FCONT     BIT(28)
++#define FSL_SAI_CR4_FCOMB_SHIFT BIT(26)
++#define FSL_SAI_CR4_FCOMB_SOFT  BIT(27)
++#define FSL_SAI_CR4_FPACK_8     (0x2 << 24)
++#define FSL_SAI_CR4_FPACK_16    (0x3 << 24)
+ #define FSL_SAI_CR4_FRSZ(x)   (((x) - 1) << 16)
+ #define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16)
+ #define FSL_SAI_CR4_SYWD(x)   (((x) - 1) << 8)
+@@ -126,6 +142,16 @@
+ #define FSL_SAI_MAXBURST_TX 6
+ #define FSL_SAI_MAXBURST_RX 6
++#define SAI_FLAG_PMQOS   BIT(0)
++
++struct fsl_sai_soc_data {
++      unsigned int fifo_depth;
++      unsigned int fifos;
++      unsigned int dataline;
++      unsigned int flags;
++      bool imx;
++};
++
+ struct fsl_sai {
+       struct platform_device *pdev;
+       struct regmap *regmap;
+@@ -138,6 +164,7 @@ struct fsl_sai {
+       bool sai_on_imx;
+       bool synchronous[2];
+       bool is_stream_opened[2];
++      unsigned int dataline[2];
+       unsigned int mclk_id[2];
+       unsigned int mclk_streams;
+@@ -146,6 +173,8 @@ struct fsl_sai {
+       struct snd_dmaengine_dai_dma_data dma_params_rx;
+       struct snd_dmaengine_dai_dma_data dma_params_tx;
++      const struct fsl_sai_soc_data *soc;
++      struct pm_qos_request pm_qos_req;
+ };
+ #define TX 1
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0019-MLK-13609-ASoC-fsl_sai-fix-for-synchronize-mode.patch b/target/linux/layerscape/patches-5.4/801-audio-0019-MLK-13609-ASoC-fsl_sai-fix-for-synchronize-mode.patch
new file mode 100644 (file)
index 0000000..2d78327
--- /dev/null
@@ -0,0 +1,56 @@
+From 7b5c62dc6c1de58ee1d527059ae69152ed1380f2 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@freescale.com>
+Date: Mon, 12 Dec 2016 11:52:24 +0800
+Subject: [PATCH] MLK-13609: ASoC: fsl_sai: fix for synchronize mode
+
+TX synchronous with receiver: the RMR should not be changed and
+the RCSR.RE should be set in playback.
+RX synchronous with transmitter: the TMR should not be changed and
+the TCSR.TE should be set in recording.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
+---
+ sound/soc/fsl/fsl_sai.c | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -527,8 +527,6 @@ static int fsl_sai_hw_params(struct snd_
+                       regmap_update_bits(sai->regmap, FSL_SAI_TCR5,
+                               FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+                               FSL_SAI_CR5_FBT_MASK, val_cr5);
+-                      regmap_write(sai->regmap, FSL_SAI_TMR,
+-                              ~0UL - ((1 << channels) - 1));
+               } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
+                       regmap_update_bits(sai->regmap, FSL_SAI_RCR4,
+                               FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+@@ -536,8 +534,6 @@ static int fsl_sai_hw_params(struct snd_
+                       regmap_update_bits(sai->regmap, FSL_SAI_RCR5,
+                               FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+                               FSL_SAI_CR5_FBT_MASK, val_cr5);
+-                      regmap_write(sai->regmap, FSL_SAI_RMR,
+-                              ~0UL - ((1 << channels) - 1));
+               }
+       }
+@@ -626,12 +622,17 @@ static int fsl_sai_trigger(struct snd_pc
+               if (tx)
+                       udelay(10);
+-              regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
+-                                 FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+-              regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
++              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+                                  FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+               regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+                                  FSL_SAI_CSR_SE, FSL_SAI_CSR_SE);
++              if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
++                      regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx)),
++                                 FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
++              } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
++                      regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx)),
++                                 FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
++              }
+               regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+                                  FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS);
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0020-ASoC-fsl_-e-sai-introduce-shared-interrupt-DT-flag-p.patch b/target/linux/layerscape/patches-5.4/801-audio-0020-ASoC-fsl_-e-sai-introduce-shared-interrupt-DT-flag-p.patch
new file mode 100644 (file)
index 0000000..1184bce
--- /dev/null
@@ -0,0 +1,42 @@
+From a22b10e2c273308f547c5ad96e3820f312058ae7 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Sun, 30 Apr 2017 12:41:33 +0300
+Subject: [PATCH] ASoC: fsl_(e)sai: introduce "shared-interrupt" DT flag (part
+ 2)
+
+SAI & ESAI interfaces may share the same interrupt with EDMA,
+so that we need a flag to trigger proper shared interrupt
+handling. For compatibility the same DT flag, "shared-interrupt",
+is introduced as the one used in drivers/dma/fsl-edma-v3.c.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+[ Aisheng: split easi changes ]
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -910,6 +910,7 @@ static int fsl_sai_probe(struct platform
+       char tmp[8];
+       int irq, ret, i;
+       int index;
++      unsigned long irqflag = 0;
+       sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
+       if (!sai)
+@@ -979,7 +980,12 @@ static int fsl_sai_probe(struct platform
+               return irq;
+       }
+-      ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, 0, np->name, sai);
++      /* SAI shared interrupt */
++      if (of_property_read_bool(np, "shared-interrupt"))
++              irqflag = IRQF_SHARED;
++
++      ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, irqflag,
++                              np->name, sai);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
+               return ret;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0021-ASoC-fsl_sai-handle-slave-mode-per-TX-RX-direction.patch b/target/linux/layerscape/patches-5.4/801-audio-0021-ASoC-fsl_sai-handle-slave-mode-per-TX-RX-direction.patch
new file mode 100644 (file)
index 0000000..2fb5789
--- /dev/null
@@ -0,0 +1,118 @@
+From 06d8069b308a1655e0c248b6bd556e63d9b38099 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Wed, 3 May 2017 10:16:02 +0300
+Subject: [PATCH] ASoC: fsl_sai: handle slave mode per TX/RX direction
+
+The SAI interface can be a clock supplier or consummer
+as function of stream direction, ie when interacting
+with I2S XTOR. Removed FSL_SAI_RFR define as it is now
+referred as FSL_SAI_RFR0.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 18 +++++++++---------
+ sound/soc/fsl/fsl_sai.h |  3 +--
+ 2 files changed, 10 insertions(+), 11 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -300,7 +300,7 @@ static int fsl_sai_set_dai_fmt_tr(struct
+               return -EINVAL;
+       }
+-      sai->is_slave_mode = false;
++      sai->slave_mode[tx] = false;
+       /* DAI clock master masks */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+@@ -310,7 +310,7 @@ static int fsl_sai_set_dai_fmt_tr(struct
+               sai->is_slave_mode = false;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+-              sai->is_slave_mode = true;
++              sai->slave_mode[tx] = true;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
+@@ -318,7 +318,7 @@ static int fsl_sai_set_dai_fmt_tr(struct
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
+-              sai->is_slave_mode = true;
++              sai->slave_mode[tx] = true;
+               break;
+       default:
+               return -EINVAL;
+@@ -359,7 +359,7 @@ static int fsl_sai_set_bclk(struct snd_s
+       int ret = 0;
+       /* Don't apply to slave mode */
+-      if (sai->is_slave_mode)
++      if (sai->slave_mode[tx])
+               return 0;
+       for (id = 0; id < FSL_SAI_MCLK_MAX; id++) {
+@@ -454,7 +454,7 @@ static int fsl_sai_hw_params(struct snd_
+       if (sai->slot_width)
+               slot_width = sai->slot_width;
+-      if (!sai->is_slave_mode) {
++      if (!sai->slave_mode[tx]) {
+               ret = fsl_sai_set_bclk(cpu_dai, tx,
+                               slots * slot_width * params_rate(params));
+               if (ret)
+@@ -490,7 +490,7 @@ static int fsl_sai_hw_params(struct snd_
+        * error.
+        */
+-      if (!sai->is_slave_mode) {
++      if (!sai->slave_mode[tx]) {
+               if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
+                       regmap_update_bits(sai->regmap, FSL_SAI_TCR4,
+                               FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+@@ -519,7 +519,7 @@ static int fsl_sai_hw_params(struct snd_
+        * error.
+        */
+-      if (!sai->is_slave_mode) {
++      if (!sai->slave_mode[tx]) {
+               if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
+                       regmap_update_bits(sai->regmap, FSL_SAI_TCR4,
+                               FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+@@ -577,7 +577,7 @@ static int fsl_sai_hw_free(struct snd_pc
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+-      if (!sai->is_slave_mode &&
++      if (!sai->slave_mode[tx] &&
+                       sai->mclk_streams & BIT(substream->stream)) {
+               clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]);
+               sai->mclk_streams &= ~BIT(substream->stream);
+@@ -672,7 +672,7 @@ static int fsl_sai_trigger(struct snd_pc
+                        * This is a hardware bug, and will be fix in the
+                        * next sai version.
+                        */
+-                      if (!sai->is_slave_mode) {
++                      if (!sai->slave_mode[tx]) {
+                               /* Software Reset for both Tx and Rx */
+                               regmap_write(sai->regmap,
+                                            FSL_SAI_TCSR, FSL_SAI_CSR_SR);
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -37,7 +37,6 @@
+ #define FSL_SAI_RDR1    0xa4 /* SAI Receive Data */
+ #define FSL_SAI_RFR0    0xc0 /* SAI Receive FIFO */
+ #define FSL_SAI_RFR1    0xc4 /* SAI Receive FIFO */
+-#define FSL_SAI_RFR   0xc0 /* SAI Receive FIFO */
+ #define FSL_SAI_RMR   0xe0 /* SAI Receive Mask */
+ #define FSL_SAI_xCSR(tx)      (tx ? FSL_SAI_TCSR : FSL_SAI_RCSR)
+@@ -158,7 +157,7 @@ struct fsl_sai {
+       struct clk *bus_clk;
+       struct clk *mclk_clk[FSL_SAI_MCLK_MAX];
+-      bool is_slave_mode;
++      bool slave_mode[2];
+       bool is_lsb_first;
+       bool is_dsp_mode;
+       bool sai_on_imx;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0022-ASoC-fsl_sai-set-specific-fmt-for-I2S-XTOR.patch b/target/linux/layerscape/patches-5.4/801-audio-0022-ASoC-fsl_sai-set-specific-fmt-for-I2S-XTOR.patch
new file mode 100644 (file)
index 0000000..84bf81a
--- /dev/null
@@ -0,0 +1,62 @@
+From 307e37122cc14b5b305639c18ea575ebe623da2f Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Sun, 30 Apr 2017 17:05:52 +0300
+Subject: [PATCH] ASoC: fsl_sai: set specific fmt for I2S XTOR
+
+Set specific fmt, for i2s xtor receiver is
+in slave mode and i2s xtor transmitter is in master mode.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 12 ++++++++++++
+ sound/soc/fsl/fsl_sai.h |  2 +-
+ 2 files changed, 13 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -335,14 +335,23 @@ static int fsl_sai_set_dai_fmt_tr(struct
+ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+ {
++      struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret;
++      if (sai->i2s_xtor)
++              fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++                    SND_SOC_DAIFMT_CBS_CFS;
++
+       ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
+       if (ret) {
+               dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret);
+               return ret;
+       }
++      if (sai->i2s_xtor)
++              fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++                    SND_SOC_DAIFMT_CBM_CFM;
++
+       ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
+       if (ret)
+               dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret);
+@@ -974,6 +983,9 @@ static int fsl_sai_probe(struct platform
+               return -EINVAL;
+       }
++      /* I2S XTOR mode */
++      sai->i2s_xtor = (of_find_property(np, "fsl,i2s-xtor", NULL) != NULL);
++
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -160,7 +160,7 @@ struct fsl_sai {
+       bool slave_mode[2];
+       bool is_lsb_first;
+       bool is_dsp_mode;
+-      bool sai_on_imx;
++      bool i2s_xtor;
+       bool synchronous[2];
+       bool is_stream_opened[2];
+       unsigned int dataline[2];
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0023-ASoC-fsl-add-imx-pcm-dma-v2-platform-driver-part-2.patch b/target/linux/layerscape/patches-5.4/801-audio-0023-ASoC-fsl-add-imx-pcm-dma-v2-platform-driver-part-2.patch
new file mode 100644 (file)
index 0000000..d09dd9b
--- /dev/null
@@ -0,0 +1,38 @@
+From 5d816f1a5cac458a7fff9ecf896c85eb351a7352 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Mon, 30 Mar 2020 16:24:59 +0800
+Subject: [PATCH] ASoC: fsl: add imx-pcm-dma v2 platform driver (part 2)
+
+which don't request the dma channel in the probe, but request
+dma channel when needed. for the dma channel of cpu dai in BE
+can be reused by the FE.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+[ Aisheng: split PCM changes ]
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -1046,6 +1046,8 @@ static int fsl_sai_probe(struct platform
+                                  MCLK_DIR(index));
+       }
++      sai->dma_params_rx.filter_data = "rx";
++      sai->dma_params_tx.filter_data = "tx";
+       sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0;
+       sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0;
+       sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
+@@ -1061,7 +1063,7 @@ static int fsl_sai_probe(struct platform
+               goto err_pm_disable;
+       if (sai->soc->imx)
+-              ret = imx_pcm_dma_init(pdev, IMX_SAI_DMABUF_SIZE);
++              ret = imx_pcm_platform_register(&pdev->dev);
+               if (ret)
+                       goto err_pm_disable;
+       } else {
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0024-MLK-14847-Revert-ASoC-fsl-sai-set-xCR4-xCR5-xMR-for-.patch b/target/linux/layerscape/patches-5.4/801-audio-0024-MLK-14847-Revert-ASoC-fsl-sai-set-xCR4-xCR5-xMR-for-.patch
new file mode 100644 (file)
index 0000000..1edd4a3
--- /dev/null
@@ -0,0 +1,59 @@
+From 060265cd3cec354804c0c944e42de83cec9f2f2a Mon Sep 17 00:00:00 2001
+From: Mihai Serban <mihai.serban@nxp.com>
+Date: Fri, 21 Apr 2017 15:57:58 +0300
+Subject: [PATCH] MLK-14847: Revert "ASoC: fsl-sai: set xCR4/xCR5/xMR for SAI
+ master mode"
+
+This reverts commit c768ed336bba ("ASoC: fsl-sai: set xCR4/xCR5/xMR for
+SAI master mode")
+
+This change was already introduced by commit 51659ca069ce ("ASoC: fsl-sai:
+set xCR4/xCR5/xMR for SAI master mode") from upstream.
+
+Manually adjust the code to match the changes introduced by subsequent
+commit b2936555bb38 ("MLK-13609: ASoC: fsl_sai: fix for synchronize mode")
+by removing updates to FSL_SAI_TMR/FSL_SAI_RMR registers.
+
+Signed-off-by: Mihai Serban <mihai.serban@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 29 -----------------------------
+ 1 file changed, 29 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -507,35 +507,6 @@ static int fsl_sai_hw_params(struct snd_
+                       regmap_update_bits(sai->regmap, FSL_SAI_TCR5,
+                               FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+                               FSL_SAI_CR5_FBT_MASK, val_cr5);
+-                      regmap_write(sai->regmap, FSL_SAI_TMR,
+-                              ~0UL - ((1 << channels) - 1));
+-              } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
+-                      regmap_update_bits(sai->regmap, FSL_SAI_RCR4,
+-                              FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+-                              val_cr4);
+-                      regmap_update_bits(sai->regmap, FSL_SAI_RCR5,
+-                              FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+-                              FSL_SAI_CR5_FBT_MASK, val_cr5);
+-                      regmap_write(sai->regmap, FSL_SAI_RMR,
+-                              ~0UL - ((1 << channels) - 1));
+-              }
+-      }
+-
+-      /*
+-       * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will
+-       * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4),
+-       * RCR5(TCR5) and RMR(TMR) for playback(capture), or there will be sync
+-       * error.
+-       */
+-
+-      if (!sai->slave_mode[tx]) {
+-              if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
+-                      regmap_update_bits(sai->regmap, FSL_SAI_TCR4,
+-                              FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+-                              val_cr4);
+-                      regmap_update_bits(sai->regmap, FSL_SAI_TCR5,
+-                              FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+-                              FSL_SAI_CR5_FBT_MASK, val_cr5);
+               } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
+                       regmap_update_bits(sai->regmap, FSL_SAI_RCR4,
+                               FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0025-MLK-14870-ASoC-fsl_sai-Remove-support-for-S20_3LE.patch b/target/linux/layerscape/patches-5.4/801-audio-0025-MLK-14870-ASoC-fsl_sai-Remove-support-for-S20_3LE.patch
new file mode 100644 (file)
index 0000000..e497705
--- /dev/null
@@ -0,0 +1,30 @@
+From 1a3b5fa78e710771c44450735439d5f5fd156141 Mon Sep 17 00:00:00 2001
+From: Daniel Baluta <daniel.baluta@nxp.com>
+Date: Wed, 10 May 2017 14:21:40 +0300
+Subject: [PATCH] MLK-14870: ASoC: fsl_sai: Remove support for S20_3LE
+
+With current clock configuration we cannot derive bitclk for S20_3LE
+format in SAI master mode. There was an attempt to fix this in commit
+65e6b5f1b4a7 ("MLK-14536: ASoC: wm8960: Fix playback in CPU DAI master mode")
+but this broke codec-master mode, thus the patch was partially reverted in
+96f0d36e420 ("MLK-14798: arm: dts: imx6ul: Fix wm8960 codec master mode")
+
+So, remove S20_3LE support for SAI master mode. Clients using this
+feature should use codec master mode, which is the default one in the
+dts anyway.
+
+Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.h | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -10,7 +10,6 @@
+ #include <sound/dmaengine_pcm.h>
+ #define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+-                       SNDRV_PCM_FMTBIT_S20_3LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE |\
+                        SNDRV_PCM_FMTBIT_S32_LE)
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0026-MLK-14935-ASoC-fsl_sai-Fix-mixing-initialization-dat.patch b/target/linux/layerscape/patches-5.4/801-audio-0026-MLK-14935-ASoC-fsl_sai-Fix-mixing-initialization-dat.patch
new file mode 100644 (file)
index 0000000..a68985f
--- /dev/null
@@ -0,0 +1,36 @@
+From 96412158397ca0e41db1eb7cec4f51a2280d1bf1 Mon Sep 17 00:00:00 2001
+From: Mihai Serban <mihai.serban@nxp.com>
+Date: Thu, 27 Apr 2017 18:47:42 +0300
+Subject: [PATCH] MLK-14935: ASoC: fsl_sai: Fix mixing initialization data with
+ actual audio samples
+
+When starting a playback the initialization data used to reduce underruns
+was send to the transmit data register after the DMA requests were enabled.
+This patch moves the initialization phase before enabling the DMA so the
+data is transmitted in correct order.
+
+Signed-off-by: Mihai Serban <mihai.serban@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -594,15 +594,14 @@ static int fsl_sai_trigger(struct snd_pc
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+-                                 FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
+-
+               for (i = 0; tx && i < channels; i++)
+                       regmap_write(sai->regmap, FSL_SAI_TDR0, 0x0);
+               if (tx)
+                       udelay(10);
+               regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
++                                 FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
++              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+                                  FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+               regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+                                  FSL_SAI_CSR_SE, FSL_SAI_CSR_SE);
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0027-MLK-15140-1-ASoC-fsl_sai-support-latest-sai-module.patch b/target/linux/layerscape/patches-5.4/801-audio-0027-MLK-15140-1-ASoC-fsl_sai-support-latest-sai-module.patch
new file mode 100644 (file)
index 0000000..38d3041
--- /dev/null
@@ -0,0 +1,701 @@
+From 21cf15cd000ba45bc02b8bfcf59df1e13bfdb803 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@freescale.com>
+Date: Thu, 22 Jun 2017 15:39:24 +0800
+Subject: [PATCH] MLK-15140-1: ASoC: fsl_sai: support latest sai module
+
+The version of sai is upgrate in imx8mq, which add two register
+in beginning, there is VERID and PARAM. the driver need to be
+update
+
+Signed-off-by: Mihai Serban <mihai.serban@nxp.com>
+Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
+---
+ sound/soc/fsl/fsl_sai.c | 273 ++++++++++++++++++++++++++++--------------------
+ sound/soc/fsl/fsl_sai.h |  43 ++++----
+ 2 files changed, 180 insertions(+), 136 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -43,6 +43,7 @@ static struct fsl_sai_soc_data fsl_sai_i
+       .fifos = 1,
+       .fifo_depth = 32,
+       .flags = 0,
++      .reg_offset = 0,
+ };
+ static struct fsl_sai_soc_data fsl_sai_imx6ul = {
+@@ -51,6 +52,7 @@ static struct fsl_sai_soc_data fsl_sai_i
+       .fifos = 1,
+       .fifo_depth = 32,
+       .flags = 0,
++      .reg_offset = 0,
+ };
+ static struct fsl_sai_soc_data fsl_sai_imx7ulp = {
+@@ -59,6 +61,16 @@ static struct fsl_sai_soc_data fsl_sai_i
+       .fifos = 2,
+       .fifo_depth = 16,
+       .flags = SAI_FLAG_PMQOS,
++      .reg_offset = 0,
++};
++
++static struct fsl_sai_soc_data fsl_sai_imx8mq = {
++      .imx = true,
++      .dataline = 0xff,
++      .fifos = 8,
++      .fifo_depth = 32,
++      .flags = 0,
++      .reg_offset = 8,
+ };
+ static const unsigned int fsl_sai_rates[] = {
+@@ -75,6 +87,7 @@ static const struct snd_pcm_hw_constrain
+ static irqreturn_t fsl_sai_isr(int irq, void *devid)
+ {
+       struct fsl_sai *sai = (struct fsl_sai *)devid;
++      unsigned char offset = sai->soc->reg_offset;
+       struct device *dev = &sai->pdev->dev;
+       u32 flags, xcsr, mask;
+       bool irq_none = true;
+@@ -87,7 +100,7 @@ static irqreturn_t fsl_sai_isr(int irq,
+       mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT;
+       /* Tx IRQ */
+-      regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr);
++      regmap_read(sai->regmap, FSL_SAI_TCSR(offset), &xcsr);
+       flags = xcsr & mask;
+       if (flags)
+@@ -117,11 +130,11 @@ static irqreturn_t fsl_sai_isr(int irq,
+       xcsr &= ~FSL_SAI_CSR_xF_MASK;
+       if (flags)
+-              regmap_write(sai->regmap, FSL_SAI_TCSR, flags | xcsr);
++              regmap_write(sai->regmap, FSL_SAI_TCSR(offset), flags | xcsr);
+ irq_rx:
+       /* Rx IRQ */
+-      regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr);
++      regmap_read(sai->regmap, FSL_SAI_RCSR(offset), &xcsr);
+       flags = xcsr & mask;
+       if (flags)
+@@ -151,7 +164,7 @@ irq_rx:
+       xcsr &= ~FSL_SAI_CSR_xF_MASK;
+       if (flags)
+-              regmap_write(sai->regmap, FSL_SAI_RCSR, flags | xcsr);
++              regmap_write(sai->regmap, FSL_SAI_RCSR(offset), flags | xcsr);
+ out:
+       if (irq_none)
+@@ -175,6 +188,7 @@ static int fsl_sai_set_dai_sysclk_tr(str
+               int clk_id, unsigned int freq, int fsl_dir)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
++      unsigned char offset = sai->soc->reg_offset;
+       bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
+       u32 val_cr2 = 0;
+@@ -195,7 +209,7 @@ static int fsl_sai_set_dai_sysclk_tr(str
+               return -EINVAL;
+       }
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx),
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, offset),
+                          FSL_SAI_CR2_MSEL_MASK, val_cr2);
+       return 0;
+@@ -228,6 +242,7 @@ static int fsl_sai_set_dai_fmt_tr(struct
+                               unsigned int fmt, int fsl_dir)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
++      unsigned char offset = sai->soc->reg_offset;
+       bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
+       u32 val_cr2 = 0, val_cr4 = 0;
+@@ -324,9 +339,9 @@ static int fsl_sai_set_dai_fmt_tr(struct
+               return -EINVAL;
+       }
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx),
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, offset),
+                          FSL_SAI_CR2_BCP | FSL_SAI_CR2_BCD_MSTR, val_cr2);
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
+                          FSL_SAI_CR4_MF | FSL_SAI_CR4_FSE |
+                          FSL_SAI_CR4_FSP | FSL_SAI_CR4_FSD_MSTR, val_cr4);
+@@ -362,6 +377,7 @@ static int fsl_sai_set_dai_fmt(struct sn
+ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
++      unsigned char offset = sai->soc->reg_offset;
+       unsigned long clk_rate;
+       u32 savediv = 0, ratio, savesub = freq;
+       u32 id;
+@@ -424,17 +440,17 @@ static int fsl_sai_set_bclk(struct snd_s
+        */
+       if ((sai->synchronous[TX] && !sai->synchronous[RX]) ||
+           (!tx && !sai->synchronous[RX])) {
+-              regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
++              regmap_update_bits(sai->regmap, FSL_SAI_RCR2(offset),
+                                  FSL_SAI_CR2_MSEL_MASK,
+                                  FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
+-              regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
++              regmap_update_bits(sai->regmap, FSL_SAI_RCR2(offset),
+                                  FSL_SAI_CR2_DIV_MASK, savediv - 1);
+       } else if ((sai->synchronous[RX] && !sai->synchronous[TX]) ||
+                  (tx && !sai->synchronous[TX])) {
+-              regmap_update_bits(sai->regmap, FSL_SAI_TCR2,
++              regmap_update_bits(sai->regmap, FSL_SAI_TCR2(offset),
+                                  FSL_SAI_CR2_MSEL_MASK,
+                                  FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
+-              regmap_update_bits(sai->regmap, FSL_SAI_TCR2,
++              regmap_update_bits(sai->regmap, FSL_SAI_TCR2(offset),
+                                  FSL_SAI_CR2_DIV_MASK, savediv - 1);
+       }
+@@ -449,6 +465,7 @@ static int fsl_sai_hw_params(struct snd_
+               struct snd_soc_dai *cpu_dai)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
++      unsigned char offset = sai->soc->reg_offset;
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       unsigned int channels = params_channels(params);
+       u32 word_width = params_width(params);
+@@ -501,49 +518,35 @@ static int fsl_sai_hw_params(struct snd_
+       if (!sai->slave_mode[tx]) {
+               if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
+-                      regmap_update_bits(sai->regmap, FSL_SAI_TCR4,
++                      regmap_update_bits(sai->regmap, FSL_SAI_TCR4(offset),
+                               FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+                               val_cr4);
+-                      regmap_update_bits(sai->regmap, FSL_SAI_TCR5,
++                      regmap_update_bits(sai->regmap, FSL_SAI_TCR5(offset),
+                               FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+                               FSL_SAI_CR5_FBT_MASK, val_cr5);
+               } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
+-                      regmap_update_bits(sai->regmap, FSL_SAI_RCR4,
++                      regmap_update_bits(sai->regmap, FSL_SAI_RCR4(offset),
+                               FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+                               val_cr4);
+-                      regmap_update_bits(sai->regmap, FSL_SAI_RCR5,
++                      regmap_update_bits(sai->regmap, FSL_SAI_RCR5(offset),
+                               FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+                               FSL_SAI_CR5_FBT_MASK, val_cr5);
+               }
+       }
+       if (sai->soc->dataline != 0x1) {
+-              switch (sai->dataline[tx]) {
+-              case 0x0:
+-                      break;
+-              case 0x1:
+-                      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
+-                              FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT, 0);
+-                      break;
+-              case 0x2:
+-                      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
+-                              FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT,
+-                              FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT);
+-                      break;
+-              case 0x3:
+-                      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
+-                              FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT,
+-                              FSL_SAI_CR4_FCOMB_SOFT);
+-                      break;
+-              default:
+-                      break;
+-              }
++              if (sai->dataline[tx] <= 1)
++                      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
++                              FSL_SAI_CR4_FCOMB_MASK, 0);
++              else
++                      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
++                              FSL_SAI_CR4_FCOMB_MASK, FSL_SAI_CR4_FCOMB_SOFT);
+       }
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
+                          FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+                          val_cr4);
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx),
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, offset),
+                          FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+                          FSL_SAI_CR5_FBT_MASK, val_cr5);
+       regmap_write(sai->regmap, FSL_SAI_xMR(tx), ~0UL - ((1 << channels) - 1));
+@@ -571,6 +574,7 @@ static int fsl_sai_trigger(struct snd_pc
+               struct snd_soc_dai *cpu_dai)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
++      unsigned char offset = sai->soc->reg_offset;
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       u8 channels = substream->runtime->channels;
+       u32 xcsr, count = 100;
+@@ -581,9 +585,9 @@ static int fsl_sai_trigger(struct snd_pc
+        * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
+        * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx.
+        */
+-      regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC,
++      regmap_update_bits(sai->regmap, FSL_SAI_TCR2(offset), FSL_SAI_CR2_SYNC,
+                          sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0);
+-      regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
++      regmap_update_bits(sai->regmap, FSL_SAI_RCR2(offset), FSL_SAI_CR2_SYNC,
+                          sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0);
+       /*
+@@ -599,49 +603,50 @@ static int fsl_sai_trigger(struct snd_pc
+               if (tx)
+                       udelay(10);
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
++              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
+                                  FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
++
++              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
+                                  FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
++              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
+                                  FSL_SAI_CSR_SE, FSL_SAI_CSR_SE);
+               if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
+-                      regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx)),
++                      regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx), offset),
+                                  FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+               } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
+-                      regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx)),
++                      regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx), offset),
+                                  FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+               }
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
++              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
+                                  FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
++              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
+                                  FSL_SAI_CSR_FRDE, 0);
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
++              regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
+                                  FSL_SAI_CSR_xIE_MASK, 0);
+               /* Check if the opposite FRDE is also disabled */
+-              regmap_read(sai->regmap, FSL_SAI_xCSR(!tx), &xcsr);
++              regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, offset), &xcsr);
+               if (!(xcsr & FSL_SAI_CSR_FRDE)) {
+                       /* Disable both directions and reset their FIFOs */
+-                      regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
++                      regmap_update_bits(sai->regmap, FSL_SAI_TCSR(offset),
+                                          FSL_SAI_CSR_TERE, 0);
+-                      regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
++                      regmap_update_bits(sai->regmap, FSL_SAI_RCSR(offset),
+                                          FSL_SAI_CSR_TERE, 0);
+                       /* TERE will remain set till the end of current frame */
+                       do {
+                               udelay(10);
+-                              regmap_read(sai->regmap, FSL_SAI_xCSR(tx), &xcsr);
++                              regmap_read(sai->regmap, FSL_SAI_xCSR(tx, offset), &xcsr);
+                       } while (--count && xcsr & FSL_SAI_CSR_TERE);
+-                      regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
++                      regmap_update_bits(sai->regmap, FSL_SAI_TCSR(offset),
+                                          FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
+-                      regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
++                      regmap_update_bits(sai->regmap, FSL_SAI_RCSR(offset),
+                                          FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
+                       /*
+@@ -654,12 +659,12 @@ static int fsl_sai_trigger(struct snd_pc
+                       if (!sai->slave_mode[tx]) {
+                               /* Software Reset for both Tx and Rx */
+                               regmap_write(sai->regmap,
+-                                           FSL_SAI_TCSR, FSL_SAI_CSR_SR);
++                                           FSL_SAI_TCSR(offset), FSL_SAI_CSR_SR);
+                               regmap_write(sai->regmap,
+-                                           FSL_SAI_RCSR, FSL_SAI_CSR_SR);
++                                           FSL_SAI_RCSR(offset), FSL_SAI_CSR_SR);
+                               /* Clear SR bit to finish the reset */
+-                              regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
+-                              regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
++                              regmap_write(sai->regmap, FSL_SAI_TCSR(offset), 0);
++                              regmap_write(sai->regmap, FSL_SAI_RCSR(offset), 0);
+                       }
+               }
+               break;
+@@ -674,6 +679,7 @@ static int fsl_sai_startup(struct snd_pc
+               struct snd_soc_dai *cpu_dai)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
++      unsigned char offset = sai->soc->reg_offset;
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       int ret;
+@@ -682,7 +688,8 @@ static int fsl_sai_startup(struct snd_pc
+       else
+               sai->is_stream_opened[tx] = true;
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE0|FSL_SAI_CR3_TRCE1,
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
++                         FSL_SAI_CR3_TRCE_MASK,
+                          FSL_SAI_CR3_TRCE(sai->dataline[tx]));
+       ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
+@@ -695,12 +702,14 @@ static void fsl_sai_shutdown(struct snd_
+               struct snd_soc_dai *cpu_dai)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
++      unsigned char offset = sai->soc->reg_offset;
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
+       if (sai->is_stream_opened[tx]) {
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE0 | FSL_SAI_CR3_TRCE1, 0);
++              regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
++                                 FSL_SAI_CR3_TRCE_MASK, 0);
+               sai->is_stream_opened[tx] = false;
+       }
+ }
+@@ -719,17 +728,18 @@ static const struct snd_soc_dai_ops fsl_
+ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
+ {
+       struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
++      unsigned char offset = sai->soc->reg_offset;
+       /* Software Reset for both Tx and Rx */
+-      regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR);
+-      regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR);
++      regmap_write(sai->regmap, FSL_SAI_TCSR(offset), FSL_SAI_CSR_SR);
++      regmap_write(sai->regmap, FSL_SAI_RCSR(offset), FSL_SAI_CSR_SR);
+       /* Clear SR bit to finish the reset */
+-      regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
+-      regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
++      regmap_write(sai->regmap, FSL_SAI_TCSR(offset), 0);
++      regmap_write(sai->regmap, FSL_SAI_RCSR(offset), 0);
+-      regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
++      regmap_update_bits(sai->regmap, FSL_SAI_TCR1(offset), FSL_SAI_CR1_RFW_MASK,
+                          sai->soc->fifo_depth - FSL_SAI_MAXBURST_TX);
+-      regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
++      regmap_update_bits(sai->regmap, FSL_SAI_RCR1(offset), FSL_SAI_CR1_RFW_MASK,
+                          FSL_SAI_MAXBURST_RX - 1);
+       snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
+@@ -767,41 +777,55 @@ static const struct snd_soc_component_dr
+       .name           = "fsl-sai",
+ };
+-static struct reg_default fsl_sai_reg_defaults[] = {
+-      {FSL_SAI_TCR1, 0},
+-      {FSL_SAI_TCR2, 0},
+-      {FSL_SAI_TCR3, 0},
+-      {FSL_SAI_TCR4, 0},
+-      {FSL_SAI_TCR5, 0},
++static struct reg_default fsl_sai_v2_reg_defaults[] = {
++      {FSL_SAI_TCR1(0), 0},
++      {FSL_SAI_TCR2(0), 0},
++      {FSL_SAI_TCR3(0), 0},
++      {FSL_SAI_TCR4(0), 0},
++      {FSL_SAI_TCR5(0), 0},
++      {FSL_SAI_TDR0, 0},
++      {FSL_SAI_TDR1, 0},
++      {FSL_SAI_TMR,  0},
++      {FSL_SAI_RCR1(0), 0},
++      {FSL_SAI_RCR2(0), 0},
++      {FSL_SAI_RCR3(0), 0},
++      {FSL_SAI_RCR4(0), 0},
++      {FSL_SAI_RCR5(0), 0},
++      {FSL_SAI_RMR,  0},
++};
++
++static struct reg_default fsl_sai_v3_reg_defaults[] = {
++      {FSL_SAI_TCR1(8), 0},
++      {FSL_SAI_TCR2(8), 0},
++      {FSL_SAI_TCR3(8), 0},
++      {FSL_SAI_TCR4(8), 0},
++      {FSL_SAI_TCR5(8), 0},
+       {FSL_SAI_TDR0, 0},
+       {FSL_SAI_TDR1, 0},
+       {FSL_SAI_TMR,  0},
+-      {FSL_SAI_RCR1, 0},
+-      {FSL_SAI_RCR2, 0},
+-      {FSL_SAI_RCR3, 0},
+-      {FSL_SAI_RCR4, 0},
+-      {FSL_SAI_RCR5, 0},
++      {FSL_SAI_RCR1(8), 0},
++      {FSL_SAI_RCR2(8), 0},
++      {FSL_SAI_RCR3(8), 0},
++      {FSL_SAI_RCR4(8), 0},
++      {FSL_SAI_RCR5(8), 0},
+       {FSL_SAI_RMR,  0},
+ };
+ static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
+ {
++      struct fsl_sai *sai = dev_get_drvdata(dev);
++      unsigned char offset = sai->soc->reg_offset;
++
++      if (reg >= FSL_SAI_TCSR(offset) && reg <= FSL_SAI_TCR5(offset))
++              return true;
++
++      if (reg >= FSL_SAI_RCSR(offset) && reg <= FSL_SAI_RCR5(offset))
++              return true;
++
+       switch (reg) {
+-      case FSL_SAI_TCSR:
+-      case FSL_SAI_TCR1:
+-      case FSL_SAI_TCR2:
+-      case FSL_SAI_TCR3:
+-      case FSL_SAI_TCR4:
+-      case FSL_SAI_TCR5:
+       case FSL_SAI_TFR0:
+       case FSL_SAI_TFR1:
+       case FSL_SAI_TMR:
+-      case FSL_SAI_RCSR:
+-      case FSL_SAI_RCR1:
+-      case FSL_SAI_RCR2:
+-      case FSL_SAI_RCR3:
+-      case FSL_SAI_RCR4:
+-      case FSL_SAI_RCR5:
+       case FSL_SAI_RDR0:
+       case FSL_SAI_RDR1:
+       case FSL_SAI_RFR0:
+@@ -815,9 +839,13 @@ static bool fsl_sai_readable_reg(struct
+ static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
+ {
++      struct fsl_sai *sai = dev_get_drvdata(dev);
++      unsigned char offset = sai->soc->reg_offset;
++
++      if (reg == FSL_SAI_TCSR(offset) || reg == FSL_SAI_RCSR(offset))
++              return true;
++
+       switch (reg) {
+-      case FSL_SAI_TCSR:
+-      case FSL_SAI_RCSR:
+       case FSL_SAI_TFR0:
+       case FSL_SAI_TFR1:
+       case FSL_SAI_RFR0:
+@@ -832,22 +860,19 @@ static bool fsl_sai_volatile_reg(struct
+ static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
+ {
++      struct fsl_sai *sai = dev_get_drvdata(dev);
++      unsigned char offset = sai->soc->reg_offset;
++
++      if (reg >= FSL_SAI_TCSR(offset) && reg <= FSL_SAI_TCR5(offset))
++              return true;
++
++      if (reg >= FSL_SAI_RCSR(offset) && reg <= FSL_SAI_RCR5(offset))
++              return true;
++
+       switch (reg) {
+-      case FSL_SAI_TCSR:
+-      case FSL_SAI_TCR1:
+-      case FSL_SAI_TCR2:
+-      case FSL_SAI_TCR3:
+-      case FSL_SAI_TCR4:
+-      case FSL_SAI_TCR5:
+       case FSL_SAI_TDR0:
+       case FSL_SAI_TDR1:
+       case FSL_SAI_TMR:
+-      case FSL_SAI_RCSR:
+-      case FSL_SAI_RCR1:
+-      case FSL_SAI_RCR2:
+-      case FSL_SAI_RCR3:
+-      case FSL_SAI_RCR4:
+-      case FSL_SAI_RCR5:
+       case FSL_SAI_RMR:
+               return true;
+       default:
+@@ -855,14 +880,28 @@ static bool fsl_sai_writeable_reg(struct
+       }
+ }
+-static const struct regmap_config fsl_sai_regmap_config = {
++static const struct regmap_config fsl_sai_v2_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = FSL_SAI_RMR,
+-      .reg_defaults = fsl_sai_reg_defaults,
+-      .num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults),
++      .reg_defaults = fsl_sai_v2_reg_defaults,
++      .num_reg_defaults = ARRAY_SIZE(fsl_sai_v2_reg_defaults),
++      .readable_reg = fsl_sai_readable_reg,
++      .volatile_reg = fsl_sai_volatile_reg,
++      .writeable_reg = fsl_sai_writeable_reg,
++      .cache_type = REGCACHE_FLAT,
++};
++
++static const struct regmap_config fsl_sai_v3_regmap_config = {
++      .reg_bits = 32,
++      .reg_stride = 4,
++      .val_bits = 32,
++
++      .max_register = FSL_SAI_RMR,
++      .reg_defaults = fsl_sai_v3_reg_defaults,
++      .num_reg_defaults = ARRAY_SIZE(fsl_sai_v3_reg_defaults),
+       .readable_reg = fsl_sai_readable_reg,
+       .volatile_reg = fsl_sai_volatile_reg,
+       .writeable_reg = fsl_sai_writeable_reg,
+@@ -874,6 +913,7 @@ static const struct of_device_id fsl_sai
+       { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx },
+       { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6ul },
+       { .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp },
++      { .compatible = "fsl,imx8mq-sai", .data = &fsl_sai_imx8mq },
+       { /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, fsl_sai_ids);
+@@ -889,7 +929,8 @@ static int fsl_sai_probe(struct platform
+       char tmp[8];
+       int irq, ret, i;
+       int index;
+-      unsigned long irqflag = 0;
++      struct regmap_config fsl_sai_regmap_config = fsl_sai_v2_regmap_config;
++      unsigned long irqflags = 0;
+       sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
+       if (!sai)
+@@ -909,6 +950,9 @@ static int fsl_sai_probe(struct platform
+       if (IS_ERR(base))
+               return PTR_ERR(base);
++      if (sai->soc->reg_offset == 8)
++              fsl_sai_regmap_config = fsl_sai_v3_regmap_config;
++
+       sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+                       "bus", base, &fsl_sai_regmap_config);
+@@ -963,11 +1007,11 @@ static int fsl_sai_probe(struct platform
+       }
+       /* SAI shared interrupt */
+-      if (of_property_read_bool(np, "shared-interrupt"))
+-              irqflag = IRQF_SHARED;
++      if (of_property_read_bool(np, "fsl,shared-interrupt"))
++              irqflags = IRQF_SHARED;
+-      ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, irqflag,
+-                              np->name, sai);
++      ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, irqflags, np->name,
++                             sai);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
+               return ret;
+@@ -1090,6 +1134,7 @@ static int fsl_sai_runtime_suspend(struc
+ static int fsl_sai_runtime_resume(struct device *dev)
+ {
+       struct fsl_sai *sai = dev_get_drvdata(dev);
++      unsigned char offset = sai->soc->reg_offset;
+       int ret;
+       ret = clk_prepare_enable(sai->bus_clk);
+@@ -1115,11 +1160,11 @@ static int fsl_sai_runtime_resume(struct
+                               PM_QOS_CPU_DMA_LATENCY, 0);
+       regcache_cache_only(sai->regmap, false);
+-      regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR);
+-      regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR);
++      regmap_write(sai->regmap, FSL_SAI_TCSR(offset), FSL_SAI_CSR_SR);
++      regmap_write(sai->regmap, FSL_SAI_RCSR(offset), FSL_SAI_CSR_SR);
+       usleep_range(1000, 2000);
+-      regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
+-      regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
++      regmap_write(sai->regmap, FSL_SAI_TCSR(offset), 0);
++      regmap_write(sai->regmap, FSL_SAI_RCSR(offset), 0);
+       ret = regcache_sync(sai->regmap);
+       if (ret)
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -14,38 +14,36 @@
+                        SNDRV_PCM_FMTBIT_S32_LE)
+ /* SAI Register Map Register */
+-#define FSL_SAI_TCSR  0x00 /* SAI Transmit Control */
+-#define FSL_SAI_TCR1  0x04 /* SAI Transmit Configuration 1 */
+-#define FSL_SAI_TCR2  0x08 /* SAI Transmit Configuration 2 */
+-#define FSL_SAI_TCR3  0x0c /* SAI Transmit Configuration 3 */
+-#define FSL_SAI_TCR4  0x10 /* SAI Transmit Configuration 4 */
+-#define FSL_SAI_TCR5  0x14 /* SAI Transmit Configuration 5 */
++#define FSL_SAI_TCSR(offset) (0x00 + offset) /* SAI Transmit Control */
++#define FSL_SAI_TCR1(offset) (0x04 + offset) /* SAI Transmit Configuration 1 */
++#define FSL_SAI_TCR2(offset) (0x08 + offset) /* SAI Transmit Configuration 2 */
++#define FSL_SAI_TCR3(offset) (0x0c + offset) /* SAI Transmit Configuration 3 */
++#define FSL_SAI_TCR4(offset) (0x10 + offset) /* SAI Transmit Configuration 4 */
++#define FSL_SAI_TCR5(offset) (0x14 + offset) /* SAI Transmit Configuration 5 */
+ #define FSL_SAI_TDR0    0x20 /* SAI Transmit Data */
+ #define FSL_SAI_TDR1    0x24 /* SAI Transmit Data */
+ #define FSL_SAI_TFR0    0x40 /* SAI Transmit FIFO */
+ #define FSL_SAI_TFR1    0x44 /* SAI Transmit FIFO */
+ #define FSL_SAI_TFR   0x40 /* SAI Transmit FIFO */
+ #define FSL_SAI_TMR   0x60 /* SAI Transmit Mask */
+-#define FSL_SAI_RCSR  0x80 /* SAI Receive Control */
+-#define FSL_SAI_RCR1  0x84 /* SAI Receive Configuration 1 */
+-#define FSL_SAI_RCR2  0x88 /* SAI Receive Configuration 2 */
+-#define FSL_SAI_RCR3  0x8c /* SAI Receive Configuration 3 */
+-#define FSL_SAI_RCR4  0x90 /* SAI Receive Configuration 4 */
+-#define FSL_SAI_RCR5  0x94 /* SAI Receive Configuration 5 */
++#define FSL_SAI_RCSR(offset) (0x80 + offset) /* SAI Receive Control */
++#define FSL_SAI_RCR1(offset) (0x84 + offset) /* SAI Receive Configuration 1 */
++#define FSL_SAI_RCR2(offset) (0x88 + offset) /* SAI Receive Configuration 2 */
++#define FSL_SAI_RCR3(offset) (0x8c + offset) /* SAI Receive Configuration 3 */
++#define FSL_SAI_RCR4(offset) (0x90 + offset) /* SAI Receive Configuration 4 */
++#define FSL_SAI_RCR5(offset) (0x94 + offset) /* SAI Receive Configuration 5 */
+ #define FSL_SAI_RDR0    0xa0 /* SAI Receive Data */
+ #define FSL_SAI_RDR1    0xa4 /* SAI Receive Data */
+ #define FSL_SAI_RFR0    0xc0 /* SAI Receive FIFO */
+ #define FSL_SAI_RFR1    0xc4 /* SAI Receive FIFO */
+ #define FSL_SAI_RMR   0xe0 /* SAI Receive Mask */
+-#define FSL_SAI_xCSR(tx)      (tx ? FSL_SAI_TCSR : FSL_SAI_RCSR)
+-#define FSL_SAI_xCR1(tx)      (tx ? FSL_SAI_TCR1 : FSL_SAI_RCR1)
+-#define FSL_SAI_xCR2(tx)      (tx ? FSL_SAI_TCR2 : FSL_SAI_RCR2)
+-#define FSL_SAI_xCR3(tx)      (tx ? FSL_SAI_TCR3 : FSL_SAI_RCR3)
+-#define FSL_SAI_xCR4(tx)      (tx ? FSL_SAI_TCR4 : FSL_SAI_RCR4)
+-#define FSL_SAI_xCR5(tx)      (tx ? FSL_SAI_TCR5 : FSL_SAI_RCR5)
+-#define FSL_SAI_xDR(tx)               (tx ? FSL_SAI_TDR : FSL_SAI_RDR)
+-#define FSL_SAI_xFR(tx)               (tx ? FSL_SAI_TFR : FSL_SAI_RFR)
++#define FSL_SAI_xCSR(tx, off) (tx ? FSL_SAI_TCSR(off) : FSL_SAI_RCSR(off))
++#define FSL_SAI_xCR1(tx, off) (tx ? FSL_SAI_TCR1(off) : FSL_SAI_RCR1(off))
++#define FSL_SAI_xCR2(tx, off) (tx ? FSL_SAI_TCR2(off) : FSL_SAI_RCR2(off))
++#define FSL_SAI_xCR3(tx, off) (tx ? FSL_SAI_TCR3(off) : FSL_SAI_RCR3(off))
++#define FSL_SAI_xCR4(tx, off) (tx ? FSL_SAI_TCR4(off) : FSL_SAI_RCR4(off))
++#define FSL_SAI_xCR5(tx, off) (tx ? FSL_SAI_TCR5(off) : FSL_SAI_RCR5(off))
+ #define FSL_SAI_xMR(tx)               (tx ? FSL_SAI_TMR : FSL_SAI_RMR)
+ /* SAI Transmit/Receive Control Register */
+@@ -87,8 +85,7 @@
+ #define FSL_SAI_CR2_DIV_MASK  0xff
+ /* SAI Transmit and Receive Configuration 3 Register */
+-#define FSL_SAI_CR3_TRCE0     BIT(16)
+-#define FSL_SAI_CR3_TRCE1     BIT(17)
++#define FSL_SAI_CR3_TRCE_MASK (0xff << 16)
+ #define FSL_SAI_CR3_TRCE(x)   (x << 16)
+ #define FSL_SAI_CR3_WDFL(x)   (x)
+ #define FSL_SAI_CR3_WDFL_MASK 0x1f
+@@ -98,6 +95,7 @@
+ #define FSL_SAI_CR4_FCONT     BIT(28)
+ #define FSL_SAI_CR4_FCOMB_SHIFT BIT(26)
+ #define FSL_SAI_CR4_FCOMB_SOFT  BIT(27)
++#define FSL_SAI_CR4_FCOMB_MASK  (0x3 << 26)
+ #define FSL_SAI_CR4_FPACK_8     (0x2 << 24)
+ #define FSL_SAI_CR4_FPACK_16    (0x3 << 24)
+ #define FSL_SAI_CR4_FRSZ(x)   (((x) - 1) << 16)
+@@ -147,6 +145,7 @@ struct fsl_sai_soc_data {
+       unsigned int fifos;
+       unsigned int dataline;
+       unsigned int flags;
++      unsigned char reg_offset;
+       bool imx;
+ };
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0028-MLK-15927-1-ASoC-fsl_sai-Fix-noise-when-using-EDMA.patch b/target/linux/layerscape/patches-5.4/801-audio-0028-MLK-15927-1-ASoC-fsl_sai-Fix-noise-when-using-EDMA.patch
new file mode 100644 (file)
index 0000000..71554d2
--- /dev/null
@@ -0,0 +1,107 @@
+From 3b671c297cff1ba5f5c3e089ffa82523eca3c598 Mon Sep 17 00:00:00 2001
+From: Mihai Serban <mihai.serban@nxp.com>
+Date: Fri, 7 Jul 2017 15:09:51 +0300
+Subject: [PATCH] MLK-15927-1: ASoC: fsl_sai: Fix noise when using EDMA
+
+EDMA requires the period size to be multiple of maxburst. Otherwise the
+remaining bytes are not transferred and thus noise is produced.
+
+We can handle this issue by adding a constraint on
+SNDRV_PCM_HW_PARAM_PERIOD_SIZE to be multiple of tx/rx maxburst value.
+
+This is based on a similar patch we have for ESAI:
+commit bd3f3eb2a37c
+("MLK-15109-2: ASoC: fsl_esai: add constrain_period_size")
+
+Signed-off-by: Mihai Serban <mihai.serban@nxp.com>
+Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 23 +++++++++++++++++++++++
+ sound/soc/fsl/fsl_sai.h |  2 ++
+ 2 files changed, 25 insertions(+)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -35,6 +35,7 @@ static struct fsl_sai_soc_data fsl_sai_v
+       .fifos = 1,
+       .fifo_depth = 32,
+       .flags = 0,
++      .constrain_period_size = false,
+ };
+ static struct fsl_sai_soc_data fsl_sai_imx6sx = {
+@@ -44,6 +45,7 @@ static struct fsl_sai_soc_data fsl_sai_i
+       .fifo_depth = 32,
+       .flags = 0,
+       .reg_offset = 0,
++      .constrain_period_size = false,
+ };
+ static struct fsl_sai_soc_data fsl_sai_imx6ul = {
+@@ -53,6 +55,7 @@ static struct fsl_sai_soc_data fsl_sai_i
+       .fifo_depth = 32,
+       .flags = 0,
+       .reg_offset = 0,
++      .constrain_period_size = false,
+ };
+ static struct fsl_sai_soc_data fsl_sai_imx7ulp = {
+@@ -62,6 +65,7 @@ static struct fsl_sai_soc_data fsl_sai_i
+       .fifo_depth = 16,
+       .flags = SAI_FLAG_PMQOS,
+       .reg_offset = 0,
++      .constrain_period_size = false,
+ };
+ static struct fsl_sai_soc_data fsl_sai_imx8mq = {
+@@ -71,6 +75,17 @@ static struct fsl_sai_soc_data fsl_sai_i
+       .fifo_depth = 32,
+       .flags = 0,
+       .reg_offset = 8,
++      .constrain_period_size = false,
++};
++
++static struct fsl_sai_soc_data fsl_sai_imx8qm = {
++      .imx = true,
++      .dataline = 0x3,
++      .fifos = 1,
++      .fifo_depth = 32,
++      .flags = 0,
++      .reg_offset = 0,
++      .constrain_period_size = true,
+ };
+ static const unsigned int fsl_sai_rates[] = {
+@@ -692,6 +707,13 @@ static int fsl_sai_startup(struct snd_pc
+                          FSL_SAI_CR3_TRCE_MASK,
+                          FSL_SAI_CR3_TRCE(sai->dataline[tx]));
++      /* EDMA engine needs periods of size multiple of tx/rx maxburst */
++      if (sai->soc->constrain_period_size)
++              snd_pcm_hw_constraint_step(substream->runtime, 0,
++                                         SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
++                                         tx ? sai->dma_params_tx.maxburst :
++                                         sai->dma_params_rx.maxburst);
++
+       ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &fsl_sai_rate_constraints);
+@@ -914,6 +936,7 @@ static const struct of_device_id fsl_sai
+       { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6ul },
+       { .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp },
+       { .compatible = "fsl,imx8mq-sai", .data = &fsl_sai_imx8mq },
++      { .compatible = "fsl,imx8qm-sai", .data = &fsl_sai_imx8qm },
+       { /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, fsl_sai_ids);
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -147,6 +147,8 @@ struct fsl_sai_soc_data {
+       unsigned int flags;
+       unsigned char reg_offset;
+       bool imx;
++      /* True for EDMA because it needs period size multiple of maxburst */
++      bool constrain_period_size;
+ };
+ struct fsl_sai {
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0029-MLK-15960-1-ASoC-fsl_sai-update-fifo_depth-for-diffe.patch b/target/linux/layerscape/patches-5.4/801-audio-0029-MLK-15960-1-ASoC-fsl_sai-update-fifo_depth-for-diffe.patch
new file mode 100644 (file)
index 0000000..d2a7955
--- /dev/null
@@ -0,0 +1,51 @@
+From 1640daf71d5230997e9b75a550d3800bede298db Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@freescale.com>
+Date: Wed, 12 Jul 2017 18:19:25 +0800
+Subject: [PATCH] MLK-15960-1: ASoC: fsl_sai: update fifo_depth for different
+ platform
+
+The fifo_depth is changed to 64 in imx8qm/imx8qxp, in imx8mq, the
+fifo_depth is 128. which is mentioned in their ADD.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
+---
+ sound/soc/fsl/fsl_sai.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -72,7 +72,7 @@ static struct fsl_sai_soc_data fsl_sai_i
+       .imx = true,
+       .dataline = 0xff,
+       .fifos = 8,
+-      .fifo_depth = 32,
++      .fifo_depth = 128,
+       .flags = 0,
+       .reg_offset = 8,
+       .constrain_period_size = false,
+@@ -82,7 +82,7 @@ static struct fsl_sai_soc_data fsl_sai_i
+       .imx = true,
+       .dataline = 0x3,
+       .fifos = 1,
+-      .fifo_depth = 32,
++      .fifo_depth = 64,
+       .flags = 0,
+       .reg_offset = 0,
+       .constrain_period_size = true,
+@@ -759,10 +759,12 @@ static int fsl_sai_dai_probe(struct snd_
+       regmap_write(sai->regmap, FSL_SAI_TCSR(offset), 0);
+       regmap_write(sai->regmap, FSL_SAI_RCSR(offset), 0);
+-      regmap_update_bits(sai->regmap, FSL_SAI_TCR1(offset), FSL_SAI_CR1_RFW_MASK,
+-                         sai->soc->fifo_depth - FSL_SAI_MAXBURST_TX);
+-      regmap_update_bits(sai->regmap, FSL_SAI_RCR1(offset), FSL_SAI_CR1_RFW_MASK,
+-                         FSL_SAI_MAXBURST_RX - 1);
++      regmap_update_bits(sai->regmap, FSL_SAI_TCR1(offset),
++                              sai->soc->fifo_depth - 1,
++                              sai->soc->fifo_depth - FSL_SAI_MAXBURST_TX);
++      regmap_update_bits(sai->regmap, FSL_SAI_RCR1(offset),
++                              sai->soc->fifo_depth - 1,
++                              FSL_SAI_MAXBURST_RX - 1);
+       snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
+                               &sai->dma_params_rx);
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0030-MLK-15960-2-ASoC-fsl_sai-refine-the-pm-runtime-funct.patch b/target/linux/layerscape/patches-5.4/801-audio-0030-MLK-15960-2-ASoC-fsl_sai-refine-the-pm-runtime-funct.patch
new file mode 100644 (file)
index 0000000..5232a69
--- /dev/null
@@ -0,0 +1,36 @@
+From 136762e82a9c4974c15b0525245092d11a825cee Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@freescale.com>
+Date: Wed, 12 Jul 2017 18:00:58 +0800
+Subject: [PATCH] MLK-15960-2: ASoC: fsl_sai: refine the pm runtime function
+
+In imx8qm/imx8qxp, the power domain of IP is enabled when
+pm_runtime_get_sync() is called, and disabled when pm_runtime
+_put_sync() is called. when power domain is disabled, the value
+of registers will lost, so we need to use the regcache_sync()
+to restore the registers in fsl_sai_runtime_resume.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
+---
+ sound/soc/fsl/fsl_sai.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -1096,6 +1096,8 @@ static int fsl_sai_probe(struct platform
+       pm_runtime_enable(&pdev->dev);
++      regcache_cache_only(sai->regmap, true);
++
+       ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
+                       &fsl_sai_dai, 1);
+       if (ret)
+@@ -1139,6 +1141,8 @@ static int fsl_sai_runtime_suspend(struc
+ {
+       struct fsl_sai *sai = dev_get_drvdata(dev);
++      regcache_cache_only(sai->regmap, true);
++
+       if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE))
+               clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]);
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0031-MLK-13975-ASoC-fsl_sai-Refine-master-flag-handling.patch b/target/linux/layerscape/patches-5.4/801-audio-0031-MLK-13975-ASoC-fsl_sai-Refine-master-flag-handling.patch
new file mode 100644 (file)
index 0000000..cc60638
--- /dev/null
@@ -0,0 +1,80 @@
+From 45ef8360c3ce459342994cdcfbf140e876b5490b Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Tue, 11 Jul 2017 08:26:44 +0300
+Subject: [PATCH] MLK-13975: ASoC: fsl_sai: Refine master flag handling
+
+The patch introduces the master flag handling
+as function of direction and the option to provide
+the flag value from DTS.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 27 +++++++++++++++++++--------
+ sound/soc/fsl/fsl_sai.h |  2 +-
+ 2 files changed, 20 insertions(+), 9 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -368,9 +368,9 @@ static int fsl_sai_set_dai_fmt(struct sn
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret;
+-      if (sai->i2s_xtor)
+-              fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+-                    SND_SOC_DAIFMT_CBS_CFS;
++      if (sai->masterflag[FSL_FMT_TRANSMITTER])
++              fmt = (fmt & (~SND_SOC_DAIFMT_MASTER_MASK)) |
++                              sai->masterflag[FSL_FMT_TRANSMITTER];
+       ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
+       if (ret) {
+@@ -378,9 +378,9 @@ static int fsl_sai_set_dai_fmt(struct sn
+               return ret;
+       }
+-      if (sai->i2s_xtor)
+-              fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+-                    SND_SOC_DAIFMT_CBM_CFM;
++      if (sai->masterflag[FSL_FMT_RECEIVER])
++              fmt = (fmt & (~SND_SOC_DAIFMT_MASTER_MASK)) |
++                              sai->masterflag[FSL_FMT_RECEIVER];
+       ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
+       if (ret)
+@@ -1022,8 +1022,19 @@ static int fsl_sai_probe(struct platform
+               return -EINVAL;
+       }
+-      /* I2S XTOR mode */
+-      sai->i2s_xtor = (of_find_property(np, "fsl,i2s-xtor", NULL) != NULL);
++      if ((of_find_property(np, "fsl,i2s-xtor", NULL) != NULL) ||
++          (of_find_property(np, "fsl,txm-rxs", NULL) != NULL))
++      {
++              sai->masterflag[FSL_FMT_TRANSMITTER] = SND_SOC_DAIFMT_CBS_CFS;
++              sai->masterflag[FSL_FMT_RECEIVER] = SND_SOC_DAIFMT_CBM_CFM;
++      } else {
++              if (!of_property_read_u32(np, "fsl,txmasterflag",
++                      &sai->masterflag[FSL_FMT_TRANSMITTER]))
++                      sai->masterflag[FSL_FMT_TRANSMITTER] <<= 12;
++              if (!of_property_read_u32(np, "fsl,rxmasterflag",
++                      &sai->masterflag[FSL_FMT_RECEIVER]))
++                      sai->masterflag[FSL_FMT_RECEIVER] <<= 12;
++      }
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -160,10 +160,10 @@ struct fsl_sai {
+       bool slave_mode[2];
+       bool is_lsb_first;
+       bool is_dsp_mode;
+-      bool i2s_xtor;
+       bool synchronous[2];
+       bool is_stream_opened[2];
+       unsigned int dataline[2];
++      unsigned int masterflag[2];
+       unsigned int mclk_id[2];
+       unsigned int mclk_streams;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0032-MLK-16130-1-ASoC-fsl_sai-enable-TCE-RCE-according-to.patch b/target/linux/layerscape/patches-5.4/801-audio-0032-MLK-16130-1-ASoC-fsl_sai-enable-TCE-RCE-according-to.patch
new file mode 100644 (file)
index 0000000..25275a2
--- /dev/null
@@ -0,0 +1,72 @@
+From 1b4638a9fa32d8a786e71a2a8813b2e1a3c15830 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@freescale.com>
+Date: Tue, 1 Aug 2017 16:10:38 +0800
+Subject: [PATCH] MLK-16130-1: ASoC: fsl_sai: enable TCE/RCE according to input
+ channels
+
+If there is only two channels input and slots is 2, then enable one
+port is enough for data transfer. so enable the TCE/RCE according to
+the input channels and slots configuration.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
+---
+ sound/soc/fsl/fsl_sai.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -487,11 +487,14 @@ static int fsl_sai_hw_params(struct snd_
+       u32 val_cr4 = 0, val_cr5 = 0;
+       u32 slots = (channels == 1) ? 2 : channels;
+       u32 slot_width = word_width;
++      u32 pins;
+       int ret;
+       if (sai->slots)
+               slots = sai->slots;
++      pins = DIV_ROUND_UP(channels, slots);
++
+       if (sai->slot_width)
+               slot_width = sai->slot_width;
+@@ -558,6 +561,10 @@ static int fsl_sai_hw_params(struct snd_
+                               FSL_SAI_CR4_FCOMB_MASK, FSL_SAI_CR4_FCOMB_SOFT);
+       }
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
++                         FSL_SAI_CR3_TRCE_MASK,
++                         FSL_SAI_CR3_TRCE((sai->dataline[tx] & ((1 << pins) - 1))));
++
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
+                          FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+                          val_cr4);
+@@ -573,8 +580,12 @@ static int fsl_sai_hw_free(struct snd_pc
+               struct snd_soc_dai *cpu_dai)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
++      unsigned char offset = sai->soc->reg_offset;
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
++                                 FSL_SAI_CR3_TRCE_MASK, 0);
++
+       if (!sai->slave_mode[tx] &&
+                       sai->mclk_streams & BIT(substream->stream)) {
+               clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]);
+@@ -694,7 +705,6 @@ static int fsl_sai_startup(struct snd_pc
+               struct snd_soc_dai *cpu_dai)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+-      unsigned char offset = sai->soc->reg_offset;
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       int ret;
+@@ -724,7 +734,6 @@ static void fsl_sai_shutdown(struct snd_
+               struct snd_soc_dai *cpu_dai)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+-      unsigned char offset = sai->soc->reg_offset;
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0033-MLK-13946-3-ASoC-fsl_sai-fix-the-xMR-setting.patch b/target/linux/layerscape/patches-5.4/801-audio-0033-MLK-13946-3-ASoC-fsl_sai-fix-the-xMR-setting.patch
new file mode 100644 (file)
index 0000000..c353ba4
--- /dev/null
@@ -0,0 +1,108 @@
+From 9d00118e0ac420d3bf6e266a0fbfd28135cbadb8 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Thu, 12 Oct 2017 14:01:19 +0800
+Subject: [PATCH] MLK-13946-3: ASoC: fsl_sai: fix the xMR setting
+
+When there is multi data line enabled, the xMR setting is
+wrong if according to the channel number. which should
+according to the slot number
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 28 ++++++++++++++++++++++++++--
+ sound/soc/fsl/fsl_sai.h | 12 ++++++++++++
+ 2 files changed, 38 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -80,7 +80,7 @@ static struct fsl_sai_soc_data fsl_sai_i
+ static struct fsl_sai_soc_data fsl_sai_imx8qm = {
+       .imx = true,
+-      .dataline = 0x3,
++      .dataline = 0xf,
+       .fifos = 1,
+       .fifo_depth = 64,
+       .flags = 0,
+@@ -571,7 +571,7 @@ static int fsl_sai_hw_params(struct snd_
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, offset),
+                          FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+                          FSL_SAI_CR5_FBT_MASK, val_cr5);
+-      regmap_write(sai->regmap, FSL_SAI_xMR(tx), ~0UL - ((1 << channels) - 1));
++      regmap_write(sai->regmap, FSL_SAI_xMR(tx), ~0UL - ((1 << slots) - 1));
+       return 0;
+ }
+@@ -858,11 +858,23 @@ static bool fsl_sai_readable_reg(struct
+       switch (reg) {
+       case FSL_SAI_TFR0:
+       case FSL_SAI_TFR1:
++      case FSL_SAI_TFR2:
++      case FSL_SAI_TFR3:
++      case FSL_SAI_TFR4:
++      case FSL_SAI_TFR5:
++      case FSL_SAI_TFR6:
++      case FSL_SAI_TFR7:
+       case FSL_SAI_TMR:
+       case FSL_SAI_RDR0:
+       case FSL_SAI_RDR1:
+       case FSL_SAI_RFR0:
+       case FSL_SAI_RFR1:
++      case FSL_SAI_RFR2:
++      case FSL_SAI_RFR3:
++      case FSL_SAI_RFR4:
++      case FSL_SAI_RFR5:
++      case FSL_SAI_RFR6:
++      case FSL_SAI_RFR7:
+       case FSL_SAI_RMR:
+               return true;
+       default:
+@@ -881,8 +893,20 @@ static bool fsl_sai_volatile_reg(struct
+       switch (reg) {
+       case FSL_SAI_TFR0:
+       case FSL_SAI_TFR1:
++      case FSL_SAI_TFR2:
++      case FSL_SAI_TFR3:
++      case FSL_SAI_TFR4:
++      case FSL_SAI_TFR5:
++      case FSL_SAI_TFR6:
++      case FSL_SAI_TFR7:
+       case FSL_SAI_RFR0:
+       case FSL_SAI_RFR1:
++      case FSL_SAI_RFR2:
++      case FSL_SAI_RFR3:
++      case FSL_SAI_RFR4:
++      case FSL_SAI_RFR5:
++      case FSL_SAI_RFR6:
++      case FSL_SAI_RFR7:
+       case FSL_SAI_RDR0:
+       case FSL_SAI_RDR1:
+               return true;
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -24,6 +24,12 @@
+ #define FSL_SAI_TDR1    0x24 /* SAI Transmit Data */
+ #define FSL_SAI_TFR0    0x40 /* SAI Transmit FIFO */
+ #define FSL_SAI_TFR1    0x44 /* SAI Transmit FIFO */
++#define FSL_SAI_TFR2    0x48 /* SAI Transmit FIFO */
++#define FSL_SAI_TFR3    0x4C /* SAI Transmit FIFO */
++#define FSL_SAI_TFR4    0x50 /* SAI Transmit FIFO */
++#define FSL_SAI_TFR5    0x54 /* SAI Transmit FIFO */
++#define FSL_SAI_TFR6    0x58 /* SAI Transmit FIFO */
++#define FSL_SAI_TFR7    0x5C /* SAI Transmit FIFO */
+ #define FSL_SAI_TFR   0x40 /* SAI Transmit FIFO */
+ #define FSL_SAI_TMR   0x60 /* SAI Transmit Mask */
+ #define FSL_SAI_RCSR(offset) (0x80 + offset) /* SAI Receive Control */
+@@ -36,6 +42,12 @@
+ #define FSL_SAI_RDR1    0xa4 /* SAI Receive Data */
+ #define FSL_SAI_RFR0    0xc0 /* SAI Receive FIFO */
+ #define FSL_SAI_RFR1    0xc4 /* SAI Receive FIFO */
++#define FSL_SAI_RFR2    0xc8 /* SAI Receive FIFO */
++#define FSL_SAI_RFR3    0xcc /* SAI Receive FIFO */
++#define FSL_SAI_RFR4    0xd0 /* SAI Receive FIFO */
++#define FSL_SAI_RFR5    0xd4 /* SAI Receive FIFO */
++#define FSL_SAI_RFR6    0xd8 /* SAI Receive FIFO */
++#define FSL_SAI_RFR7    0xdc /* SAI Receive FIFO */
+ #define FSL_SAI_RMR   0xe0 /* SAI Receive Mask */
+ #define FSL_SAI_xCSR(tx, off) (tx ? FSL_SAI_TCSR(off) : FSL_SAI_RCSR(off))
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0034-MLK-13946-8-ASoC-fsl_sai-use-min-channels-slots-for-.patch b/target/linux/layerscape/patches-5.4/801-audio-0034-MLK-13946-8-ASoC-fsl_sai-use-min-channels-slots-for-.patch
new file mode 100644 (file)
index 0000000..ab89291
--- /dev/null
@@ -0,0 +1,28 @@
+From 283d3a9e253d2cefd915ee7f891c24edc3e6d6d0 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Tue, 24 Oct 2017 13:09:27 +0300
+Subject: [PATCH] MLK-13946-8: ASoC: fsl_sai: use min(channels,slots) for xMR
+ setting
+
+xMR setting must be set as min(channels,slots) since
+both "channels < slots" and "channels > slots" scenarios
+are possible.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -571,8 +571,8 @@ static int fsl_sai_hw_params(struct snd_
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, offset),
+                          FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+                          FSL_SAI_CR5_FBT_MASK, val_cr5);
+-      regmap_write(sai->regmap, FSL_SAI_xMR(tx), ~0UL - ((1 << slots) - 1));
+-
++      regmap_write(sai->regmap, FSL_SAI_xMR(tx),
++                      ~0UL - ((1 << min(channels, slots)) - 1));
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0035-MLK-16929-1-ASoC-fsl_sai-add-bitclk_freq.patch b/target/linux/layerscape/patches-5.4/801-audio-0035-MLK-16929-1-ASoC-fsl_sai-add-bitclk_freq.patch
new file mode 100644 (file)
index 0000000..72078d9
--- /dev/null
@@ -0,0 +1,55 @@
+From d40566a2e9aa3c40be313b1fba9d5435c58ffd79 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Thu, 23 Nov 2017 13:32:13 +0800
+Subject: [PATCH] MLK-16929-1: ASoC: fsl_sai: add bitclk_freq
+
+Allow set SAI bit clock frequency trough snd_soc_dai_set_sysclk
+function call on machine sound drivers.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+Signed-off-by: Adrian Alonso <adrian.alonso@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 9 ++++++++-
+ sound/soc/fsl/fsl_sai.h | 1 +
+ 2 files changed, 9 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -233,11 +233,14 @@ static int fsl_sai_set_dai_sysclk_tr(str
+ static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+               int clk_id, unsigned int freq, int dir)
+ {
++      struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret;
+       if (dir == SND_SOC_CLOCK_IN)
+               return 0;
++      sai->bitclk_freq = freq;
++
+       ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
+                                       FSL_FMT_TRANSMITTER);
+       if (ret) {
+@@ -499,7 +502,11 @@ static int fsl_sai_hw_params(struct snd_
+               slot_width = sai->slot_width;
+       if (!sai->slave_mode[tx]) {
+-              ret = fsl_sai_set_bclk(cpu_dai, tx,
++              if (sai->bitclk_freq)
++                      ret = fsl_sai_set_bclk(cpu_dai, tx,
++                                      sai->bitclk_freq);
++              else
++                      ret = fsl_sai_set_bclk(cpu_dai, tx,
+                               slots * slot_width * params_rate(params));
+               if (ret)
+                       return ret;
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -181,6 +181,7 @@ struct fsl_sai {
+       unsigned int mclk_streams;
+       unsigned int slots;
+       unsigned int slot_width;
++      unsigned int bitclk_freq;
+       struct snd_dmaengine_dai_dma_data dma_params_rx;
+       struct snd_dmaengine_dai_dma_data dma_params_tx;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0036-MLK-17442-ASoC-fsl-fix-wrong-usage-of-filter_data-pa.patch b/target/linux/layerscape/patches-5.4/801-audio-0036-MLK-17442-ASoC-fsl-fix-wrong-usage-of-filter_data-pa.patch
new file mode 100644 (file)
index 0000000..5cc4274
--- /dev/null
@@ -0,0 +1,30 @@
+From 8d4837f146cd14cf7041050ddec77b2a5c3f2f27 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Tue, 23 Jan 2018 13:25:40 +0800
+Subject: [PATCH] MLK-17442: ASoC: fsl: fix wrong usage of filter_data (part 1)
+
+The filter_data should be used for dma_filter_fn function,
+but we used the filter_data wrongly for dma channel name.
+This patch is to fix the issue.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+Reviwed-by: Daniel Baluta <daniel.baluta@nxp.com>
+[ Aisheng: split out esai and pcm changes ]
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -1136,8 +1136,8 @@ static int fsl_sai_probe(struct platform
+                                  MCLK_DIR(index));
+       }
+-      sai->dma_params_rx.filter_data = "rx";
+-      sai->dma_params_tx.filter_data = "tx";
++      sai->dma_params_rx.chan_name = "rx";
++      sai->dma_params_tx.chan_name = "tx";
+       sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0;
+       sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0;
+       sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0037-MLK-16224-4-ASoC-fsl_sai-support-multi-fifo-and-DSD.patch b/target/linux/layerscape/patches-5.4/801-audio-0037-MLK-16224-4-ASoC-fsl_sai-support-multi-fifo-and-DSD.patch
new file mode 100644 (file)
index 0000000..033ab0d
--- /dev/null
@@ -0,0 +1,326 @@
+From 87f734fa8214b4ddbfdac9b7ac5dc75a3d86badb Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Tue, 23 Jan 2018 13:26:37 +0800
+Subject: [PATCH] MLK-16224-4: ASoC: fsl_sai: support multi fifo and DSD
+
+The codec always mux the LRCLK pin to DSD data line, so when
+we want to support DSD, the pinmux is different. For two channel
+DSD, the DSDL is mapped to TX0, but the DSDR is mapped to TX4,
+there is address offset for the fifo address of TX0 and TX4, TX4's
+fifo is not adjacent to TX0's.
+
+Usually, if mapping is TX0 and TX1, that will be easy for SAI
+and SDMA to handle, that SAI can use the FIFO combine mode, SDMA
+can use the normal script.
+
+so for DSD:
+1. The SDMA should use the multi-fifo script, and SAI can't
+use the FIFO combine mode.
+2. driver should to check the dts configuration(fsl,dataline) for
+which dataline is used corrently
+3. maxburst is the multiply of datalines
+4. each channel of DSD occupy one data lane
+5. according to data lane, set TRCE bits
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+Reviewed-by: Viorel Suman <viorel.suman@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 162 +++++++++++++++++++++++++++++++++++++++++++++---
+ sound/soc/fsl/fsl_sai.h |  12 +++-
+ 2 files changed, 164 insertions(+), 10 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -267,6 +267,7 @@ static int fsl_sai_set_dai_fmt_tr(struct
+       if (!sai->is_lsb_first)
+               val_cr4 |= FSL_SAI_CR4_MF;
++      sai->is_dsp_mode = false;
+       /* DAI mode */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+@@ -305,6 +306,11 @@ static int fsl_sai_set_dai_fmt_tr(struct
+               val_cr2 |= FSL_SAI_CR2_BCP;
+               sai->is_dsp_mode = true;
+               break;
++      case SND_SOC_DAIFMT_PDM:
++              val_cr2 |= FSL_SAI_CR2_BCP;
++              val_cr4 &= ~FSL_SAI_CR4_MF;
++              sai->is_dsp_mode = true;
++              break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               /* To be done */
+       default:
+@@ -492,12 +498,38 @@ static int fsl_sai_hw_params(struct snd_
+       u32 slot_width = word_width;
+       u32 pins;
+       int ret;
++      int i;
++      int trce_mask = 0;
++      snd_pcm_format_t format = params_format(params);
+       if (sai->slots)
+               slots = sai->slots;
+       pins = DIV_ROUND_UP(channels, slots);
++      if (format == SNDRV_PCM_FORMAT_DSD_U8 ||
++              format == SNDRV_PCM_FORMAT_DSD_U16_LE ||
++              format == SNDRV_PCM_FORMAT_DSD_U16_BE ||
++              format == SNDRV_PCM_FORMAT_DSD_U32_LE ||
++              format == SNDRV_PCM_FORMAT_DSD_U32_BE) {
++              sai->is_dsd = true;
++
++              if (!IS_ERR_OR_NULL(sai->pins_dsd)) {
++                      ret = pinctrl_select_state(sai->pinctrl, sai->pins_dsd);
++                      if (ret) {
++                              dev_err(cpu_dai->dev,
++                                      "failed to set proper pins state: %d\n", ret);
++                              return ret;
++                      }
++              }
++      } else {
++              pinctrl_pm_select_default_state(cpu_dai->dev);
++              sai->is_dsd = false;
++      }
++
++      if (sai->is_dsd)
++              pins = channels;
++
+       if (sai->slot_width)
+               slot_width = sai->slot_width;
+@@ -527,7 +559,7 @@ static int fsl_sai_hw_params(struct snd_
+       val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
+       val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
+-      if (sai->is_lsb_first)
++      if (sai->is_lsb_first || sai->is_dsd)
+               val_cr5 |= FSL_SAI_CR5_FBT(0);
+       else
+               val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
+@@ -560,17 +592,71 @@ static int fsl_sai_hw_params(struct snd_
+       }
+       if (sai->soc->dataline != 0x1) {
+-              if (sai->dataline[tx] <= 1)
++
++              if (sai->dataline[tx] <= 1 || sai->is_multi_lane)
+                       regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
+                               FSL_SAI_CR4_FCOMB_MASK, 0);
+               else
+                       regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
+                               FSL_SAI_CR4_FCOMB_MASK, FSL_SAI_CR4_FCOMB_SOFT);
++
++              if (sai->is_multi_lane) {
++                      if (tx) {
++                              sai->dma_params_tx.maxburst =
++                                              FSL_SAI_MAXBURST_TX * pins;
++                              if (sai->is_dsd)
++                                      sai->dma_params_tx.fifo_num = pins +
++                                         (sai->dataline_off_dsd[tx] << 8);
++                              else
++                                      sai->dma_params_tx.fifo_num = pins +
++                                              (sai->dataline_off[tx] << 8);
++                      } else {
++                              sai->dma_params_rx.maxburst =
++                                      FSL_SAI_MAXBURST_RX * pins;
++                              if (sai->is_dsd)
++                                      sai->dma_params_rx.fifo_num = pins +
++                                        (sai->dataline_off_dsd[tx] << 8);
++                              else
++                                      sai->dma_params_rx.fifo_num = pins +
++                                              (sai->dataline_off[tx] << 8);
++                      }
++              }
++
++              snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
++                              &sai->dma_params_rx);
+       }
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
++      if (sai->is_dsd) {
++              if (__sw_hweight8(sai->dataline_dsd[tx] & 0xFF) < pins) {
++                      dev_err(cpu_dai->dev, "channel not supported\n");
++                      return -EINVAL;
++              }
++              /*find a proper tcre setting*/
++              for (i = 0; i < 8; i++) {
++                      trce_mask = (1 << (i + 1)) - 1;
++                      if (__sw_hweight8(sai->dataline_dsd[tx] & trce_mask) == pins)
++                              break;
++              }
++
++              regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
+                          FSL_SAI_CR3_TRCE_MASK,
+-                         FSL_SAI_CR3_TRCE((sai->dataline[tx] & ((1 << pins) - 1))));
++                         FSL_SAI_CR3_TRCE((sai->dataline_dsd[tx] & trce_mask)));
++      } else {
++              if (__sw_hweight8(sai->dataline[tx] & 0xFF) < pins) {
++                      dev_err(cpu_dai->dev, "channel not supported\n");
++                      return -EINVAL;
++              }
++              /*find a proper tcre setting*/
++              for (i = 0; i < 8; i++) {
++                      trce_mask = (1 << (i + 1)) - 1;
++                      if (__sw_hweight8(sai->dataline[tx] & trce_mask) == pins)
++                              break;
++              }
++
++              regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
++                         FSL_SAI_CR3_TRCE_MASK,
++                         FSL_SAI_CR3_TRCE((sai->dataline[tx] & trce_mask)));
++      }
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
+                          FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+@@ -610,9 +696,18 @@ static int fsl_sai_trigger(struct snd_pc
+       unsigned char offset = sai->soc->reg_offset;
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       u8 channels = substream->runtime->channels;
++      u32 slots = (channels == 1) ? 2 : channels;
+       u32 xcsr, count = 100;
+-      int i;
++      u32 pins;
++      int i = 0, j = 0, k = 0;
++
++      if (sai->slots)
++              slots = sai->slots;
++
++      pins = DIV_ROUND_UP(channels, slots);
++      if (sai->is_dsd)
++              pins = channels;
+       /*
+        * Asynchronous mode: Clear SYNC for both Tx and Rx.
+        * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
+@@ -631,10 +726,19 @@ static int fsl_sai_trigger(struct snd_pc
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+-              for (i = 0; tx && i < channels; i++)
+-                      regmap_write(sai->regmap, FSL_SAI_TDR0, 0x0);
+-              if (tx)
+-                      udelay(10);
++
++              for (i = 0; tx && i < channels; i++) {
++              while (tx && i < channels)
++                      if (sai->dataline[tx] & (1 << j)) {
++                              regmap_write(sai->regmap, FSL_SAI_TDR0 + j * 0x4, 0x0);
++                              i++;
++                              k++;
++                      }
++                      j++;
++
++                      if (k%pins == 0)
++                              j = 0;
++              }
+               regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
+                                  FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
+@@ -994,6 +1098,7 @@ static int fsl_sai_probe(struct platform
+       char tmp[8];
+       int irq, ret, i;
+       int index;
++      int firstbitidx, nextbitidx;
+       struct regmap_config fsl_sai_regmap_config = fsl_sai_v2_regmap_config;
+       unsigned long irqflags = 0;
+@@ -1048,6 +1153,9 @@ static int fsl_sai_probe(struct platform
+               }
+       }
++      if (of_find_property(np, "fsl,sai-multi-lane", NULL))
++              sai->is_multi_lane = true;
++
+       /*dataline mask for rx and tx*/
+       ret = of_property_read_u32_index(np, "fsl,dataline", 0, &sai->dataline[0]);
+       if (ret)
+@@ -1062,6 +1170,37 @@ static int fsl_sai_probe(struct platform
+               return -EINVAL;
+       }
++      for (i = 0; i < 2; i++) {
++              firstbitidx = find_first_bit((const unsigned long *)&sai->dataline[i], 8);
++              nextbitidx = find_next_bit((const unsigned long *)&sai->dataline[i], 8, firstbitidx+1);
++              sai->dataline_off[i] = nextbitidx - firstbitidx - 1;
++
++              if (sai->dataline_off[i] < 0 || sai->dataline_off[i] >= 7)
++                      sai->dataline_off[i] = 0;
++      }
++
++      ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 0, &sai->dataline_dsd[0]);
++      if (ret)
++              sai->dataline_dsd[0] = 1;
++
++      ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 1, &sai->dataline_dsd[1]);
++      if (ret)
++              sai->dataline_dsd[1] = 1;
++
++      if ((sai->dataline_dsd[0] & (~sai->soc->dataline)) || sai->dataline_dsd[1] & (~sai->soc->dataline)) {
++              dev_err(&pdev->dev, "dataline setting error, Mask is 0x%x\n", sai->soc->dataline);
++              return -EINVAL;
++      }
++
++      for (i = 0; i < 2; i++) {
++              firstbitidx = find_first_bit((const unsigned long *)&sai->dataline_dsd[i], 8);
++              nextbitidx = find_next_bit((const unsigned long *)&sai->dataline_dsd[i], 8, firstbitidx+1);
++              sai->dataline_off_dsd[i] = nextbitidx - firstbitidx - 1;
++
++              if (sai->dataline_off_dsd[i] < 0 || sai->dataline_off_dsd[i] >= 7)
++                      sai->dataline_off_dsd[i] = 0;
++      }
++
+       if ((of_find_property(np, "fsl,i2s-xtor", NULL) != NULL) ||
+           (of_find_property(np, "fsl,txm-rxs", NULL) != NULL))
+       {
+@@ -1143,6 +1282,11 @@ static int fsl_sai_probe(struct platform
+       sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
+       sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
++      sai->pinctrl  = devm_pinctrl_get(&pdev->dev);
++
++      if (!IS_ERR_OR_NULL(sai->pinctrl))
++              sai->pins_dsd = pinctrl_lookup_state(sai->pinctrl, "dsd");
++
+       platform_set_drvdata(pdev, sai);
+       pm_runtime_enable(&pdev->dev);
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -11,7 +11,10 @@
+ #define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE |\
+-                       SNDRV_PCM_FMTBIT_S32_LE)
++                       SNDRV_PCM_FMTBIT_S32_LE |\
++                       SNDRV_PCM_FMTBIT_DSD_U8 |\
++                       SNDRV_PCM_FMTBIT_DSD_U16_LE |\
++                       SNDRV_PCM_FMTBIT_DSD_U32_LE)
+ /* SAI Register Map Register */
+ #define FSL_SAI_TCSR(offset) (0x00 + offset) /* SAI Transmit Control */
+@@ -172,9 +175,14 @@ struct fsl_sai {
+       bool slave_mode[2];
+       bool is_lsb_first;
+       bool is_dsp_mode;
++      bool is_multi_lane;
+       bool synchronous[2];
+       bool is_stream_opened[2];
++      bool is_dsd;
+       unsigned int dataline[2];
++      unsigned int dataline_dsd[2];
++      unsigned int dataline_off[2];
++      unsigned int dataline_off_dsd[2];
+       unsigned int masterflag[2];
+       unsigned int mclk_id[2];
+@@ -187,6 +195,8 @@ struct fsl_sai {
+       struct snd_dmaengine_dai_dma_data dma_params_tx;
+       const struct fsl_sai_soc_data *soc;
+       struct pm_qos_request pm_qos_req;
++      struct pinctrl *pinctrl;
++      struct pinctrl_state *pins_dsd;
+ };
+ #define TX 1
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0038-MLK-17467-ASoC-fsl_sai-fix-typo-for-fsl_sai.patch b/target/linux/layerscape/patches-5.4/801-audio-0038-MLK-17467-ASoC-fsl_sai-fix-typo-for-fsl_sai.patch
new file mode 100644 (file)
index 0000000..9499b54
--- /dev/null
@@ -0,0 +1,36 @@
+From b22f55e1f41ebe218604f12c127d299a2c302393 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Fri, 26 Jan 2018 16:44:19 +0800
+Subject: [PATCH] MLK-17467: ASoC: fsl_sai: fix typo for fsl_sai
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Fix build warning
+
+sound/soc/fsl/fsl_sai.c: In function ‘fsl_sai_trigger’:
+sound/soc/fsl/fsl_sai.c:736:3: warning: this ‘while’ clause does not guard... [-Wmisleading-indentation]
+   while (tx && i < channels)
+   ^~~~~
+sound/soc/fsl/fsl_sai.c:742:4: note: ...this statement, but the latter is misleadingly indented as if it is guarded by the ‘while’
+    j++;
+    ^
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -727,9 +727,8 @@ static int fsl_sai_trigger(struct snd_pc
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+-              for (i = 0; tx && i < channels; i++) {
+-              while (tx && i < channels)
+-                      if (sai->dataline[tx] & (1 << j)) {
++              while (tx && i < channels) {
++                      if ((sai->is_dsd ? sai->dataline_dsd[tx] : sai->dataline[tx]) & (1 << j)) {
+                               regmap_write(sai->regmap, FSL_SAI_TDR0 + j * 0x4, 0x0);
+                               i++;
+                               k++;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0039-MLK-16224-6-ASoC-fsl_sai-fix-DSD-suspend-resume.patch b/target/linux/layerscape/patches-5.4/801-audio-0039-MLK-16224-6-ASoC-fsl_sai-fix-DSD-suspend-resume.patch
new file mode 100644 (file)
index 0000000..8ca538c
--- /dev/null
@@ -0,0 +1,49 @@
+From a115bf34468398647e7a8f380058bd597e44e1b3 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Mon, 29 Jan 2018 16:04:44 +0200
+Subject: [PATCH] MLK-16224-6: ASoC: fsl_sai: fix DSD suspend/resume
+
+With the existing implementation the SAI pinctrl state is restored to
+default after resume - this breaks DSD playback after resume.
+Restore DSD pinctrl state in snd_soc_dai_driver resume callback.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -893,6 +893,23 @@ static int fsl_sai_dai_probe(struct snd_
+       return 0;
+ }
++static int fsl_sai_dai_resume(struct snd_soc_dai *cpu_dai)
++{
++      struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
++      int ret;
++
++      if (sai->is_dsd && !IS_ERR_OR_NULL(sai->pins_dsd)) {
++              ret = pinctrl_select_state(sai->pinctrl, sai->pins_dsd);
++              if (ret) {
++                      dev_err(cpu_dai->dev,
++                              "failed to set proper pins state: %d\n", ret);
++                      return ret;
++              }
++      }
++
++      return 0;
++}
++
+ static struct snd_soc_dai_driver fsl_sai_dai = {
+       .probe = fsl_sai_dai_probe,
+       .playback = {
+@@ -913,6 +930,7 @@ static struct snd_soc_dai_driver fsl_sai
+               .rates = SNDRV_PCM_RATE_KNOT,
+               .formats = FSL_SAI_FORMATS,
+       },
++      .resume  = fsl_sai_dai_resume,
+       .ops = &fsl_sai_pcm_dai_ops,
+ };
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0040-MLK-17428-8-ASoC-fsl_sai-support-768KHz-sample-rate.patch b/target/linux/layerscape/patches-5.4/801-audio-0040-MLK-17428-8-ASoC-fsl_sai-support-768KHz-sample-rate.patch
new file mode 100644 (file)
index 0000000..63b38b6
--- /dev/null
@@ -0,0 +1,42 @@
+From 2bc81e99f261aa6eafa900453b477dd46d568d73 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Fri, 19 Jan 2018 15:45:21 +0800
+Subject: [PATCH] MLK-17428-8: ASoC: fsl_sai: support 768KHz sample rate
+
+support 768Hz sample rate and 2.8MHz for DSD
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -91,7 +91,8 @@ static struct fsl_sai_soc_data fsl_sai_i
+ static const unsigned int fsl_sai_rates[] = {
+       8000, 11025, 12000, 16000, 22050,
+       24000, 32000, 44100, 48000, 64000,
+-      88200, 96000, 176400, 192000
++      88200, 96000, 176400, 192000, 352800,
++      384000, 705600, 768000, 1411200, 2822400,
+ };
+ static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = {
+@@ -916,8 +917,6 @@ static struct snd_soc_dai_driver fsl_sai
+               .stream_name = "CPU-Playback",
+               .channels_min = 1,
+               .channels_max = 32,
+-              .rate_min = 8000,
+-              .rate_max = 192000,
+               .rates = SNDRV_PCM_RATE_KNOT,
+               .formats = FSL_SAI_FORMATS,
+       },
+@@ -925,8 +924,6 @@ static struct snd_soc_dai_driver fsl_sai
+               .stream_name = "CPU-Capture",
+               .channels_min = 1,
+               .channels_max = 32,
+-              .rate_min = 8000,
+-              .rate_max = 192000,
+               .rates = SNDRV_PCM_RATE_KNOT,
+               .formats = FSL_SAI_FORMATS,
+       },
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0041-MLK-17485-ASoC-fsl_sai-Specify-supported-rate_min-an.patch b/target/linux/layerscape/patches-5.4/801-audio-0041-MLK-17485-ASoC-fsl_sai-Specify-supported-rate_min-an.patch
new file mode 100644 (file)
index 0000000..9358833
--- /dev/null
@@ -0,0 +1,38 @@
+From 4859edfca7fb2408b8b9f90bf03c62e484dadc79 Mon Sep 17 00:00:00 2001
+From: Daniel Baluta <daniel.baluta@nxp.com>
+Date: Fri, 2 Feb 2018 11:02:27 +0200
+Subject: [PATCH] MLK-17485: ASoC: fsl_sai: Specify supported rate_min and
+ rate_max
+
+Because fsl_sai_dai rates doesn't have a specific set of
+rate values (.rates = SNDRV_PCM_RATE_KNOT) we need to provide
+rate_min and rate_max otherwise functions trying to get
+supported parameters will get confused and return an error.
+
+Fixes:  1b6f0496e013 ("MLK-17428-8: ASoC: fsl_sai: support 768KHz sample rate")
+Reviewed-by: Viorel Suman <viorel.suman@nxp.com>
+Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -917,6 +917,8 @@ static struct snd_soc_dai_driver fsl_sai
+               .stream_name = "CPU-Playback",
+               .channels_min = 1,
+               .channels_max = 32,
++              .rate_min = 8000,
++              .rate_max = 2822400,
+               .rates = SNDRV_PCM_RATE_KNOT,
+               .formats = FSL_SAI_FORMATS,
+       },
+@@ -924,6 +926,8 @@ static struct snd_soc_dai_driver fsl_sai
+               .stream_name = "CPU-Capture",
+               .channels_min = 1,
+               .channels_max = 32,
++              .rate_min = 8000,
++              .rate_max = 2822400,
+               .rates = SNDRV_PCM_RATE_KNOT,
+               .formats = FSL_SAI_FORMATS,
+       },
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0042-MLK-17566-ASoC-fsl_sai-fix-register-definition.patch b/target/linux/layerscape/patches-5.4/801-audio-0042-MLK-17566-ASoC-fsl_sai-fix-register-definition.patch
new file mode 100644 (file)
index 0000000..bd6488a
--- /dev/null
@@ -0,0 +1,97 @@
+From 8e28947dacb52352807fed71d70355a18bf416c5 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Thu, 8 Feb 2018 14:38:35 +0800
+Subject: [PATCH] MLK-17566: ASoC: fsl_sai: fix register definition
+
+The register definition is not completed for SAI support
+8 transmit data register and 8 receive data register.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+Reviewed-by: Daniel Baluta <daniel.baluta@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 24 ++++++++++++++++++++++++
+ sound/soc/fsl/fsl_sai.h | 12 ++++++++++++
+ 2 files changed, 36 insertions(+)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -964,6 +964,12 @@ static struct reg_default fsl_sai_v3_reg
+       {FSL_SAI_TCR5(8), 0},
+       {FSL_SAI_TDR0, 0},
+       {FSL_SAI_TDR1, 0},
++      {FSL_SAI_TDR2, 0},
++      {FSL_SAI_TDR3, 0},
++      {FSL_SAI_TDR4, 0},
++      {FSL_SAI_TDR5, 0},
++      {FSL_SAI_TDR6, 0},
++      {FSL_SAI_TDR7, 0},
+       {FSL_SAI_TMR,  0},
+       {FSL_SAI_RCR1(8), 0},
+       {FSL_SAI_RCR2(8), 0},
+@@ -996,6 +1002,12 @@ static bool fsl_sai_readable_reg(struct
+       case FSL_SAI_TMR:
+       case FSL_SAI_RDR0:
+       case FSL_SAI_RDR1:
++      case FSL_SAI_RDR2:
++      case FSL_SAI_RDR3:
++      case FSL_SAI_RDR4:
++      case FSL_SAI_RDR5:
++      case FSL_SAI_RDR6:
++      case FSL_SAI_RDR7:
+       case FSL_SAI_RFR0:
+       case FSL_SAI_RFR1:
+       case FSL_SAI_RFR2:
+@@ -1038,6 +1050,12 @@ static bool fsl_sai_volatile_reg(struct
+       case FSL_SAI_RFR7:
+       case FSL_SAI_RDR0:
+       case FSL_SAI_RDR1:
++      case FSL_SAI_RDR2:
++      case FSL_SAI_RDR3:
++      case FSL_SAI_RDR4:
++      case FSL_SAI_RDR5:
++      case FSL_SAI_RDR6:
++      case FSL_SAI_RDR7:
+               return true;
+       default:
+               return false;
+@@ -1058,6 +1076,12 @@ static bool fsl_sai_writeable_reg(struct
+       switch (reg) {
+       case FSL_SAI_TDR0:
+       case FSL_SAI_TDR1:
++      case FSL_SAI_TDR2:
++      case FSL_SAI_TDR3:
++      case FSL_SAI_TDR4:
++      case FSL_SAI_TDR5:
++      case FSL_SAI_TDR6:
++      case FSL_SAI_TDR7:
+       case FSL_SAI_TMR:
+       case FSL_SAI_RMR:
+               return true;
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -25,6 +25,12 @@
+ #define FSL_SAI_TCR5(offset) (0x14 + offset) /* SAI Transmit Configuration 5 */
+ #define FSL_SAI_TDR0    0x20 /* SAI Transmit Data */
+ #define FSL_SAI_TDR1    0x24 /* SAI Transmit Data */
++#define FSL_SAI_TDR2    0x28 /* SAI Transmit Data */
++#define FSL_SAI_TDR3    0x2C /* SAI Transmit Data */
++#define FSL_SAI_TDR4    0x30 /* SAI Transmit Data */
++#define FSL_SAI_TDR5    0x34 /* SAI Transmit Data */
++#define FSL_SAI_TDR6    0x38 /* SAI Transmit Data */
++#define FSL_SAI_TDR7    0x3C /* SAI Transmit Data */
+ #define FSL_SAI_TFR0    0x40 /* SAI Transmit FIFO */
+ #define FSL_SAI_TFR1    0x44 /* SAI Transmit FIFO */
+ #define FSL_SAI_TFR2    0x48 /* SAI Transmit FIFO */
+@@ -43,6 +49,12 @@
+ #define FSL_SAI_RCR5(offset) (0x94 + offset) /* SAI Receive Configuration 5 */
+ #define FSL_SAI_RDR0    0xa0 /* SAI Receive Data */
+ #define FSL_SAI_RDR1    0xa4 /* SAI Receive Data */
++#define FSL_SAI_RDR2    0xa8 /* SAI Receive Data */
++#define FSL_SAI_RDR3    0xac /* SAI Receive Data */
++#define FSL_SAI_RDR4    0xb0 /* SAI Receive Data */
++#define FSL_SAI_RDR5    0xb4 /* SAI Receive Data */
++#define FSL_SAI_RDR6    0xb8 /* SAI Receive Data */
++#define FSL_SAI_RDR7    0xbc /* SAI Receive Data */
+ #define FSL_SAI_RFR0    0xc0 /* SAI Receive FIFO */
+ #define FSL_SAI_RFR1    0xc4 /* SAI Receive FIFO */
+ #define FSL_SAI_RFR2    0xc8 /* SAI Receive FIFO */
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0043-MLK-17528-1-ASoC-fsl_sai-Introduce-FSL_SAI_CLK_BIT-c.patch b/target/linux/layerscape/patches-5.4/801-audio-0043-MLK-17528-1-ASoC-fsl_sai-Introduce-FSL_SAI_CLK_BIT-c.patch
new file mode 100644 (file)
index 0000000..a6ff55b
--- /dev/null
@@ -0,0 +1,42 @@
+From 8eb2c08d504ac0697285b08084487fd3869ea7b6 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Thu, 8 Feb 2018 12:47:24 +0200
+Subject: [PATCH] MLK-17528-1: ASoC: fsl_sai: Introduce FSL_SAI_CLK_BIT clock
+ id
+
+Introduce FSL_SAI_CLK_BIT clock id in order to distinguish
+the bit clock and master clocks in "set_sysclk" API.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+Suggested-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+Reviewed-by: Daniel Baluta <daniel.baluta@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 5 ++++-
+ sound/soc/fsl/fsl_sai.h | 1 +
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -240,7 +240,10 @@ static int fsl_sai_set_dai_sysclk(struct
+       if (dir == SND_SOC_CLOCK_IN)
+               return 0;
+-      sai->bitclk_freq = freq;
++      if (clk_id == FSL_SAI_CLK_BIT) {
++              sai->bitclk_freq = freq;
++              return 0;
++      }
+       ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
+                                       FSL_FMT_TRANSMITTER);
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -160,6 +160,7 @@
+ #define FSL_SAI_CLK_MAST3     3
+ #define FSL_SAI_MCLK_MAX      4
++#define FSL_SAI_CLK_BIT               5
+ /* SAI data transfer numbers per DMA request */
+ #define FSL_SAI_MAXBURST_TX 6
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0044-MLK-17528-3-ASoC-fsl_sai-Set-clock-rate-in-set_syscl.patch b/target/linux/layerscape/patches-5.4/801-audio-0044-MLK-17528-3-ASoC-fsl_sai-Set-clock-rate-in-set_syscl.patch
new file mode 100644 (file)
index 0000000..da3ec8d
--- /dev/null
@@ -0,0 +1,44 @@
+From 0d9bc2f22dc418c4573ded86278e55f97d029dca Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Fri, 9 Feb 2018 11:39:58 +0200
+Subject: [PATCH] MLK-17528-3: ASoC: fsl_sai: Set clock rate in "set_sysclk"
+ API
+
+Set the requested clock rate in "set_sysclk" for specified clock id.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+Suggested-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+Reviewed-by: Daniel Baluta <daniel.baluta@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -245,6 +245,25 @@ static int fsl_sai_set_dai_sysclk(struct
+               return 0;
+       }
++      if (freq > 0) {
++              if (clk_id < 0 || clk_id >= FSL_SAI_MCLK_MAX) {
++                      dev_err(cpu_dai->dev, "Unknown clock id: %d\n", clk_id);
++                      return -EINVAL;
++              }
++
++              if (IS_ERR_OR_NULL(sai->mclk_clk[clk_id])) {
++                      dev_err(cpu_dai->dev, "Unassigned clock: %d\n", clk_id);
++                      return -EINVAL;
++              }
++
++              ret = clk_set_rate(sai->mclk_clk[clk_id], freq);
++              if (ret < 0) {
++                      dev_err(cpu_dai->dev, "failed to set clock rate (%u): %d\n",
++                                      freq, ret);
++                      return ret;
++              }
++      }
++
+       ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
+                                       FSL_FMT_TRANSMITTER);
+       if (ret) {
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0045-MLK-17156-1-ASoC-fsl_sai-update-register-offset-for-.patch b/target/linux/layerscape/patches-5.4/801-audio-0045-MLK-17156-1-ASoC-fsl_sai-update-register-offset-for-.patch
new file mode 100644 (file)
index 0000000..8189ec2
--- /dev/null
@@ -0,0 +1,26 @@
+From bed63eea982ba6d59995288a5deab94510a51994 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Tue, 6 Mar 2018 11:45:30 +0800
+Subject: [PATCH] MLK-17156-1: ASoC: fsl_sai: update register offset for ULP B0
+
+ULP B0 integrate the latest SAI IP, there is version id and
+parameter id register in the beginning, so update the offset
+for ULP B0
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+Reviewed-by: Daniel Baluta <daniel.baluta@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -64,7 +64,7 @@ static struct fsl_sai_soc_data fsl_sai_i
+       .fifos = 2,
+       .fifo_depth = 16,
+       .flags = SAI_FLAG_PMQOS,
+-      .reg_offset = 0,
++      .reg_offset = 8,
+       .constrain_period_size = false,
+ };
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0046-Sound-Soc-fsl-Set-SAI-Channel-Mode-to-Output-Mode.patch b/target/linux/layerscape/patches-5.4/801-audio-0046-Sound-Soc-fsl-Set-SAI-Channel-Mode-to-Output-Mode.patch
new file mode 100644 (file)
index 0000000..0d8fc16
--- /dev/null
@@ -0,0 +1,72 @@
+From 494c1f9c5c86396d2974c6072f728e2325b72703 Mon Sep 17 00:00:00 2001
+From: Cosmin-Gabriel Samoila <cosmin.samoila@nxp.com>
+Date: Wed, 7 Mar 2018 11:35:07 +0200
+Subject: [PATCH] Sound: Soc: fsl: Set SAI Channel Mode to Output Mode
+
+Transmit data pins will output zero when slots are masked or channels
+are disabled. In CHMOD TDM mode, transmit data pins are tri-stated when
+slots are masked or channels are disabled. When data pins are tri-stated,
+there is noise on some channels when FS clock value is high and data is
+read while fsclk is transitioning from high to low.
+
+Signed-off-by: Cosmin-Gabriel Samoila <cosmin.samoila@nxp.com>
+Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 14 +++++++++++---
+ sound/soc/fsl/fsl_sai.h |  2 ++
+ 2 files changed, 13 insertions(+), 3 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -589,6 +589,11 @@ static int fsl_sai_hw_params(struct snd_
+       val_cr4 |= FSL_SAI_CR4_FRSZ(slots);
++      /* Output Mode - data pins transmit 0 when slots are masked
++       * or channels are disabled
++       */
++      val_cr4 |= FSL_SAI_CR4_CHMOD;
++
+       /*
+        * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will
+        * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4),
+@@ -599,14 +604,16 @@ static int fsl_sai_hw_params(struct snd_
+       if (!sai->slave_mode[tx]) {
+               if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
+                       regmap_update_bits(sai->regmap, FSL_SAI_TCR4(offset),
+-                              FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
++                              FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
++                              FSL_SAI_CR4_CHMOD_MASK,
+                               val_cr4);
+                       regmap_update_bits(sai->regmap, FSL_SAI_TCR5(offset),
+                               FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+                               FSL_SAI_CR5_FBT_MASK, val_cr5);
+               } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
+                       regmap_update_bits(sai->regmap, FSL_SAI_RCR4(offset),
+-                              FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
++                              FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
++                              FSL_SAI_CR4_CHMOD_MASK,
+                               val_cr4);
+                       regmap_update_bits(sai->regmap, FSL_SAI_RCR5(offset),
+                               FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+@@ -682,7 +689,8 @@ static int fsl_sai_hw_params(struct snd_
+       }
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
+-                         FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
++                         FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
++                         FSL_SAI_CR4_CHMOD_MASK,
+                          val_cr4);
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, offset),
+                          FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -129,6 +129,8 @@
+ #define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16)
+ #define FSL_SAI_CR4_SYWD(x)   (((x) - 1) << 8)
+ #define FSL_SAI_CR4_SYWD_MASK (0x1f << 8)
++#define FSL_SAI_CR4_CHMOD     (1 << 5)
++#define FSL_SAI_CR4_CHMOD_MASK        (1 << 5)
+ #define FSL_SAI_CR4_MF                BIT(4)
+ #define FSL_SAI_CR4_FSE               BIT(3)
+ #define FSL_SAI_CR4_FSP               BIT(1)
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0047-MLK-17580-ASoC-fsl-dsd-Add-DSD-utilities-helper.patch b/target/linux/layerscape/patches-5.4/801-audio-0047-MLK-17580-ASoC-fsl-dsd-Add-DSD-utilities-helper.patch
new file mode 100644 (file)
index 0000000..9290b3b
--- /dev/null
@@ -0,0 +1,76 @@
+From e28e3e0d01c0fcb628e841977b51c45189b43f47 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Thu, 8 Mar 2018 14:37:30 +0200
+Subject: [PATCH] MLK-17580: ASoC: fsl: dsd: Add DSD utilities helper
+
+Add DSD utilities helper.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com
+---
+ sound/soc/fsl/fsl_dsd.h | 59 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 59 insertions(+)
+ create mode 100644 sound/soc/fsl/fsl_dsd.h
+
+--- /dev/null
++++ b/sound/soc/fsl/fsl_dsd.h
+@@ -0,0 +1,59 @@
++/*
++ * Copyright 2018 NXP
++ *
++ * 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.
++ */
++
++#ifndef __FSL_DSD_H
++#define __FSL_DSD_H
++
++#include <linux/pinctrl/consumer.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++
++static bool fsl_is_dsd(struct snd_pcm_hw_params *params)
++{
++      snd_pcm_format_t format = params_format(params);
++
++      switch (format) {
++      case SNDRV_PCM_FORMAT_DSD_U8:
++      case SNDRV_PCM_FORMAT_DSD_U16_LE:
++      case SNDRV_PCM_FORMAT_DSD_U16_BE:
++      case SNDRV_PCM_FORMAT_DSD_U32_LE:
++      case SNDRV_PCM_FORMAT_DSD_U32_BE:
++              return true;
++      default:
++              return false;
++      }
++}
++
++static struct pinctrl_state *fsl_get_pins_state(struct pinctrl *pinctrl,
++      struct snd_pcm_hw_params *params)
++{
++      int dsd_bclk;
++      struct pinctrl_state *state = 0;
++
++      if (fsl_is_dsd(params)) {
++              dsd_bclk = params_rate(params) * params_physical_width(params);
++
++              switch (dsd_bclk) {
++              case 22579200: /* DSD512 */
++                      state = pinctrl_lookup_state(pinctrl, "dsd512");
++                      break;
++              }
++
++              /* Get default DSD state */
++              if (IS_ERR_OR_NULL(state))
++                      state = pinctrl_lookup_state(pinctrl, "dsd");
++      }
++
++      /* Get default state */
++      if (IS_ERR_OR_NULL(state))
++              state = pinctrl_lookup_state(pinctrl, "default");
++
++      return state;
++}
++
++#endif /* __FSL_DSD_H */
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0048-MLK-17580-ASoC-fsl-sai-Use-DSD-helper.patch b/target/linux/layerscape/patches-5.4/801-audio-0048-MLK-17580-ASoC-fsl-sai-Use-DSD-helper.patch
new file mode 100644 (file)
index 0000000..ffd74f8
--- /dev/null
@@ -0,0 +1,96 @@
+From 0a71cfbd55ba50414bfcb4ecccf656a580930790 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Thu, 8 Mar 2018 14:43:34 +0200
+Subject: [PATCH] MLK-17580: ASoC: fsl: sai: Use DSD helper
+
+Replace DSD related code with calls to DSD helper functions.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com
+---
+ sound/soc/fsl/fsl_sai.c | 34 +++++++++++-----------------------
+ sound/soc/fsl/fsl_sai.h |  2 +-
+ 2 files changed, 12 insertions(+), 24 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -22,6 +22,7 @@
+ #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+ #include <linux/pm_runtime.h>
++#include "fsl_dsd.h"
+ #include "fsl_sai.h"
+ #include "imx-pcm.h"
+@@ -523,31 +524,21 @@ static int fsl_sai_hw_params(struct snd_
+       int ret;
+       int i;
+       int trce_mask = 0;
+-      snd_pcm_format_t format = params_format(params);
+       if (sai->slots)
+               slots = sai->slots;
+       pins = DIV_ROUND_UP(channels, slots);
++      sai->is_dsd = fsl_is_dsd(params);
++      sai->pins_state = fsl_get_pins_state(sai->pinctrl, params);
+-      if (format == SNDRV_PCM_FORMAT_DSD_U8 ||
+-              format == SNDRV_PCM_FORMAT_DSD_U16_LE ||
+-              format == SNDRV_PCM_FORMAT_DSD_U16_BE ||
+-              format == SNDRV_PCM_FORMAT_DSD_U32_LE ||
+-              format == SNDRV_PCM_FORMAT_DSD_U32_BE) {
+-              sai->is_dsd = true;
+-
+-              if (!IS_ERR_OR_NULL(sai->pins_dsd)) {
+-                      ret = pinctrl_select_state(sai->pinctrl, sai->pins_dsd);
+-                      if (ret) {
+-                              dev_err(cpu_dai->dev,
+-                                      "failed to set proper pins state: %d\n", ret);
+-                              return ret;
+-                      }
++      if (!IS_ERR_OR_NULL(sai->pins_state)) {
++              ret = pinctrl_select_state(sai->pinctrl, sai->pins_state);
++              if (ret) {
++                      dev_err(cpu_dai->dev,
++                              "failed to set proper pins state: %d\n", ret);
++                      return ret;
+               }
+-      } else {
+-              pinctrl_pm_select_default_state(cpu_dai->dev);
+-              sai->is_dsd = false;
+       }
+       if (sai->is_dsd)
+@@ -929,8 +920,8 @@ static int fsl_sai_dai_resume(struct snd
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret;
+-      if (sai->is_dsd && !IS_ERR_OR_NULL(sai->pins_dsd)) {
+-              ret = pinctrl_select_state(sai->pinctrl, sai->pins_dsd);
++      if (!IS_ERR_OR_NULL(sai->pins_state)) {
++              ret = pinctrl_select_state(sai->pinctrl, sai->pins_state);
+               if (ret) {
+                       dev_err(cpu_dai->dev,
+                               "failed to set proper pins state: %d\n", ret);
+@@ -1356,9 +1347,6 @@ static int fsl_sai_probe(struct platform
+       sai->pinctrl  = devm_pinctrl_get(&pdev->dev);
+-      if (!IS_ERR_OR_NULL(sai->pinctrl))
+-              sai->pins_dsd = pinctrl_lookup_state(sai->pinctrl, "dsd");
+-
+       platform_set_drvdata(pdev, sai);
+       pm_runtime_enable(&pdev->dev);
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -211,7 +211,7 @@ struct fsl_sai {
+       const struct fsl_sai_soc_data *soc;
+       struct pm_qos_request pm_qos_req;
+       struct pinctrl *pinctrl;
+-      struct pinctrl_state *pins_dsd;
++      struct pinctrl_state *pins_state;
+ };
+ #define TX 1
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0049-MLK-17580-ASoC-fsl-sai-check-for-pinctrl-status.patch b/target/linux/layerscape/patches-5.4/801-audio-0049-MLK-17580-ASoC-fsl-sai-check-for-pinctrl-status.patch
new file mode 100644 (file)
index 0000000..5f69c1d
--- /dev/null
@@ -0,0 +1,60 @@
+From 12b887445779c33285dac5279fc02fd80e0800d8 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Fri, 9 Mar 2018 12:41:42 +0200
+Subject: [PATCH] MLK-17580: ASoC: fsl: sai: check for pinctrl status
+
+For some cases (like AMIX) pinctrl may be null - this
+breaks SAI functionality. Enforce pinctrl null pointer
+checking prior calling any function which involves
+pins state changes.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 21 ++++++++++++---------
+ 1 file changed, 12 insertions(+), 9 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -530,14 +530,17 @@ static int fsl_sai_hw_params(struct snd_
+       pins = DIV_ROUND_UP(channels, slots);
+       sai->is_dsd = fsl_is_dsd(params);
+-      sai->pins_state = fsl_get_pins_state(sai->pinctrl, params);
+-      if (!IS_ERR_OR_NULL(sai->pins_state)) {
+-              ret = pinctrl_select_state(sai->pinctrl, sai->pins_state);
+-              if (ret) {
+-                      dev_err(cpu_dai->dev,
+-                              "failed to set proper pins state: %d\n", ret);
+-                      return ret;
++      if (!IS_ERR_OR_NULL(sai->pinctrl)) {
++              sai->pins_state = fsl_get_pins_state(sai->pinctrl, params);
++
++              if (!IS_ERR_OR_NULL(sai->pins_state)) {
++                      ret = pinctrl_select_state(sai->pinctrl, sai->pins_state);
++                      if (ret) {
++                              dev_err(cpu_dai->dev,
++                                      "failed to set proper pins state: %d\n", ret);
++                              return ret;
++                      }
+               }
+       }
+@@ -920,7 +923,7 @@ static int fsl_sai_dai_resume(struct snd
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret;
+-      if (!IS_ERR_OR_NULL(sai->pins_state)) {
++      if (!IS_ERR_OR_NULL(sai->pinctrl) && !IS_ERR_OR_NULL(sai->pins_state)) {
+               ret = pinctrl_select_state(sai->pinctrl, sai->pins_state);
+               if (ret) {
+                       dev_err(cpu_dai->dev,
+@@ -1345,7 +1348,7 @@ static int fsl_sai_probe(struct platform
+       sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
+       sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
+-      sai->pinctrl  = devm_pinctrl_get(&pdev->dev);
++      sai->pinctrl = devm_pinctrl_get(&pdev->dev);
+       platform_set_drvdata(pdev, sai);
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0050-MLK-17531-1-ASoC-fsl-sai-add-support-for-SAI-v3.01.patch b/target/linux/layerscape/patches-5.4/801-audio-0050-MLK-17531-1-ASoC-fsl-sai-add-support-for-SAI-v3.01.patch
new file mode 100644 (file)
index 0000000..d2ce7e2
--- /dev/null
@@ -0,0 +1,250 @@
+From 63b81694ef7736849dcf7f7daf0becc6ebc02844 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Mon, 14 May 2018 16:28:48 +0300
+Subject: [PATCH] MLK-17531-1: ASoC: fsl: sai: add support for SAI v3.01
+
+a) Add support for new SAI (VERID, PARAM, MCTL, MDIV) registers
+   available in i.MX 850d (SAI v3.00) and i.MX 845s (SAI v3.01).
+b) Handle SAI MCLK register as function of SAI IP version.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+Reviewed-by: Daniel Baluta <daniel.baluta@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ sound/soc/fsl/fsl_sai.h | 59 +++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 122 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -29,6 +29,8 @@
+ #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
+                      FSL_SAI_CSR_FEIE)
++#define FSL_SAI_VERID_0301    0x0301
++
+ static struct fsl_sai_soc_data fsl_sai_vf610 = {
+       .imx = false,
+       /*dataline is mask, not index*/
+@@ -422,6 +424,48 @@ static int fsl_sai_set_dai_fmt(struct sn
+       return ret;
+ }
++static int fsl_sai_check_ver(struct snd_soc_dai *cpu_dai)
++{
++      struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
++      unsigned char offset = sai->soc->reg_offset;
++      unsigned int val;
++
++      if (FSL_SAI_TCSR(offset) == FSL_SAI_VERID)
++              return 0;
++
++      if (sai->verid.loaded)
++              return 0;
++
++      sai->verid.loaded = true;
++      regmap_read(sai->regmap, FSL_SAI_VERID, &val);
++      dev_dbg(cpu_dai->dev, "VERID: 0x%016X\n", val);
++
++      sai->verid.id = (val & FSL_SAI_VER_ID_MASK) >> FSL_SAI_VER_ID_SHIFT;
++      sai->verid.extfifo_en = (val & FSL_SAI_VER_EFIFO_EN);
++      sai->verid.timestamp_en = (val & FSL_SAI_VER_TSTMP_EN);
++
++      regmap_read(sai->regmap, FSL_SAI_PARAM, &val);
++      dev_dbg(cpu_dai->dev, "PARAM: 0x%016X\n", val);
++
++      /* max slots per frame, power of 2 */
++      sai->param.spf = 1 <<
++              ((val & FSL_SAI_PAR_SPF_MASK) >> FSL_SAI_PAR_SPF_SHIFT);
++
++      /* words per fifo, power of 2 */
++      sai->param.wpf = 1 <<
++              ((val & FSL_SAI_PAR_WPF_MASK) >> FSL_SAI_PAR_WPF_SHIFT);
++
++      /* number of datalines implemented */
++      sai->param.dln = val & FSL_SAI_PAR_DLN_MASK;
++
++      dev_dbg(cpu_dai->dev,
++              "Version: 0x%08X, SPF: %u, WPF: %u, DLN: %u\n",
++              sai->verid.id, sai->param.spf, sai->param.wpf, sai->param.dln
++      );
++
++      return 0;
++}
++
+ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
+@@ -502,6 +546,15 @@ static int fsl_sai_set_bclk(struct snd_s
+                                  FSL_SAI_CR2_DIV_MASK, savediv - 1);
+       }
++      fsl_sai_check_ver(dai);
++      switch (sai->verid.id) {
++      case FSL_SAI_VERID_0301:
++              /* SAI is in master mode at this point, so enable MCLK */
++              regmap_update_bits(sai->regmap, FSL_SAI_MCTL,
++                              FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN);
++              break;
++      }
++
+       dev_dbg(dai->dev, "best fit: clock id=%d, div=%d, deviation =%d\n",
+                       sai->mclk_id[tx], savediv, savesub);
+@@ -1001,6 +1054,8 @@ static struct reg_default fsl_sai_v3_reg
+       {FSL_SAI_RCR4(8), 0},
+       {FSL_SAI_RCR5(8), 0},
+       {FSL_SAI_RMR,  0},
++      {FSL_SAI_MCTL, 0},
++      {FSL_SAI_MDIV, 0},
+ };
+ static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
+@@ -1041,6 +1096,10 @@ static bool fsl_sai_readable_reg(struct
+       case FSL_SAI_RFR6:
+       case FSL_SAI_RFR7:
+       case FSL_SAI_RMR:
++      case FSL_SAI_MCTL:
++      case FSL_SAI_MDIV:
++      case FSL_SAI_VERID:
++      case FSL_SAI_PARAM:
+               return true;
+       default:
+               return false;
+@@ -1056,6 +1115,8 @@ static bool fsl_sai_volatile_reg(struct
+               return true;
+       switch (reg) {
++      case FSL_SAI_VERID:
++      case FSL_SAI_PARAM:
+       case FSL_SAI_TFR0:
+       case FSL_SAI_TFR1:
+       case FSL_SAI_TFR2:
+@@ -1108,6 +1169,8 @@ static bool fsl_sai_writeable_reg(struct
+       case FSL_SAI_TDR7:
+       case FSL_SAI_TMR:
+       case FSL_SAI_RMR:
++      case FSL_SAI_MCTL:
++      case FSL_SAI_MDIV:
+               return true;
+       default:
+               return false;
+@@ -1133,7 +1196,7 @@ static const struct regmap_config fsl_sa
+       .reg_stride = 4,
+       .val_bits = 32,
+-      .max_register = FSL_SAI_RMR,
++      .max_register = FSL_SAI_MDIV,
+       .reg_defaults = fsl_sai_v3_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(fsl_sai_v3_reg_defaults),
+       .readable_reg = fsl_sai_readable_reg,
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -17,6 +17,8 @@
+                        SNDRV_PCM_FMTBIT_DSD_U32_LE)
+ /* SAI Register Map Register */
++#define FSL_SAI_VERID 0x00 /* SAI Version ID Register */
++#define FSL_SAI_PARAM 0x04 /* SAI Parameter Register */
+ #define FSL_SAI_TCSR(offset) (0x00 + offset) /* SAI Transmit Control */
+ #define FSL_SAI_TCR1(offset) (0x04 + offset) /* SAI Transmit Configuration 1 */
+ #define FSL_SAI_TCR2(offset) (0x08 + offset) /* SAI Transmit Configuration 2 */
+@@ -39,8 +41,12 @@
+ #define FSL_SAI_TFR5    0x54 /* SAI Transmit FIFO */
+ #define FSL_SAI_TFR6    0x58 /* SAI Transmit FIFO */
+ #define FSL_SAI_TFR7    0x5C /* SAI Transmit FIFO */
+-#define FSL_SAI_TFR   0x40 /* SAI Transmit FIFO */
+ #define FSL_SAI_TMR   0x60 /* SAI Transmit Mask */
++#define FSL_SAI_TTCTL 0x70 /* SAI Transmit Timestamp Control Register */
++#define FSL_SAI_TTCTN 0x74 /* SAI Transmit Timestamp Counter Register */
++#define FSL_SAI_TBCTN 0x78 /* SAI Transmit Bit Counter Register */
++#define FSL_SAI_TTCAP 0x7C /* SAI Transmit Timestamp Capture */
++
+ #define FSL_SAI_RCSR(offset) (0x80 + offset) /* SAI Receive Control */
+ #define FSL_SAI_RCR1(offset) (0x84 + offset) /* SAI Receive Configuration 1 */
+ #define FSL_SAI_RCR2(offset) (0x88 + offset) /* SAI Receive Configuration 2 */
+@@ -64,6 +70,13 @@
+ #define FSL_SAI_RFR6    0xd8 /* SAI Receive FIFO */
+ #define FSL_SAI_RFR7    0xdc /* SAI Receive FIFO */
+ #define FSL_SAI_RMR   0xe0 /* SAI Receive Mask */
++#define FSL_SAI_RTCTL 0xf0 /* SAI Receive Timestamp Control Register */
++#define FSL_SAI_RTCTN 0xf4 /* SAI Receive Timestamp Counter Register */
++#define FSL_SAI_RBCTN 0xf8 /* SAI Receive Bit Counter Register */
++#define FSL_SAI_RTCAP 0xfc /* SAI Receive Timestamp Capture */
++
++#define FSL_SAI_MCTL  0x100 /* SAI MCLK Control Register */
++#define FSL_SAI_MDIV  0x104 /* SAI MCLK Divide Register */
+ #define FSL_SAI_xCSR(tx, off) (tx ? FSL_SAI_TCSR(off) : FSL_SAI_RCSR(off))
+ #define FSL_SAI_xCR1(tx, off) (tx ? FSL_SAI_TCR1(off) : FSL_SAI_RCR1(off))
+@@ -109,6 +122,7 @@
+ #define FSL_SAI_CR2_MSEL(ID)  ((ID) << 26)
+ #define FSL_SAI_CR2_BCP               BIT(25)
+ #define FSL_SAI_CR2_BCD_MSTR  BIT(24)
++#define FSL_SAI_CR2_BCBP      BIT(23) /* BCLK bypass */
+ #define FSL_SAI_CR2_DIV_MASK  0xff
+ /* SAI Transmit and Receive Configuration 3 Register */
+@@ -144,6 +158,33 @@
+ #define FSL_SAI_CR5_FBT(x)    ((x) << 8)
+ #define FSL_SAI_CR5_FBT_MASK  (0x1f << 8)
++/* SAI MCLK Control Register */
++#define FSL_SAI_MCTL_MCLK_EN  BIT(30) /* MCLK Enable */
++#define FSL_SAI_MCTL_MSEL_MASK        (0x3 << 24)
++#define FSL_SAI_MCTL_MSEL(ID)   ((ID) << 24)
++#define FSL_SAI_MCTL_MSEL_BUS 0
++#define FSL_SAI_MCTL_MSEL_MCLK1       BIT(24)
++#define FSL_SAI_MCTL_MSEL_MCLK2       BIT(25)
++#define FSL_SAI_MCTL_MSEL_MCLK3       (BIT(24) | BIT(25))
++#define FSL_SAI_MCTL_DIV_EN   BIT(23)
++#define FSL_SAI_MCTL_DIV_MASK 0xFF
++
++/* SAI VERID Register */
++#define FSL_SAI_VER_ID_SHIFT  16
++#define FSL_SAI_VER_ID_MASK   (0xFFFF << FSL_SAI_VER_ID_SHIFT)
++#define FSL_SAI_VER_EFIFO_EN  BIT(0)
++#define FSL_SAI_VER_TSTMP_EN  BIT(1)
++
++/* SAI PARAM Register */
++#define FSL_SAI_PAR_SPF_SHIFT 16
++#define FSL_SAI_PAR_SPF_MASK  (0x0F << FSL_SAI_PAR_SPF_SHIFT)
++#define FSL_SAI_PAR_WPF_SHIFT 8
++#define FSL_SAI_PAR_WPF_MASK  (0x0F << FSL_SAI_PAR_WPF_SHIFT)
++#define FSL_SAI_PAR_DLN_MASK  (0x0F)
++
++/* SAI MCLK Divide Register */
++#define FSL_SAI_MDIV_MASK     0xFFFFF
++
+ /* SAI type */
+ #define FSL_SAI_DMA           BIT(0)
+ #define FSL_SAI_USE_AC97      BIT(1)
+@@ -181,6 +222,19 @@ struct fsl_sai_soc_data {
+       bool constrain_period_size;
+ };
++struct fsl_sai_verid {
++      u32 id;
++      bool timestamp_en;
++      bool extfifo_en;
++      bool loaded;
++};
++
++struct fsl_sai_param {
++      u32 spf; /* max slots per frame */
++      u32 wpf; /* words in fifo */
++      u32 dln; /* number of datalines implemented */
++};
++
+ struct fsl_sai {
+       struct platform_device *pdev;
+       struct regmap *regmap;
+@@ -212,6 +266,9 @@ struct fsl_sai {
+       struct pm_qos_request pm_qos_req;
+       struct pinctrl *pinctrl;
+       struct pinctrl_state *pins_state;
++
++      struct fsl_sai_verid verid;
++      struct fsl_sai_param param;
+ };
+ #define TX 1
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0051-MLK-18534-1-ASoC-fsl-sai-introduce-1-1-bclk-mclk-rat.patch b/target/linux/layerscape/patches-5.4/801-audio-0051-MLK-18534-1-ASoC-fsl-sai-introduce-1-1-bclk-mclk-rat.patch
new file mode 100644 (file)
index 0000000..3103300
--- /dev/null
@@ -0,0 +1,135 @@
+From 2e891d3d62f5fd51e33ae6e614198ce0b3b48e95 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Wed, 6 Jun 2018 13:36:20 +0300
+Subject: [PATCH] MLK-18534-1: ASoC: fsl: sai: introduce 1:1 bclk:mclk ratio
+ support
+
+Since IP version 3.01 (845s) SAI has support for 1:1
+bclk:mclk ratio.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 69 +++++++++++++++++++++++++------------------------
+ sound/soc/fsl/fsl_sai.h |  2 +-
+ 2 files changed, 36 insertions(+), 35 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -471,7 +471,8 @@ static int fsl_sai_set_bclk(struct snd_s
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
+       unsigned char offset = sai->soc->reg_offset;
+       unsigned long clk_rate;
+-      u32 savediv = 0, ratio, savesub = freq;
++      unsigned int reg = 0;
++      u32 ratio, savesub = freq, saveratio = 0, savediv = 0;
+       u32 id;
+       int ret = 0;
+@@ -479,6 +480,8 @@ static int fsl_sai_set_bclk(struct snd_s
+       if (sai->slave_mode[tx])
+               return 0;
++      fsl_sai_check_ver(dai);
++
+       for (id = 0; id < FSL_SAI_MCLK_MAX; id++) {
+               clk_rate = clk_get_rate(sai->mclk_clk[id]);
+               if (!clk_rate)
+@@ -499,22 +502,21 @@ static int fsl_sai_set_bclk(struct snd_s
+                       "ratio %d for freq %dHz based on clock %ldHz\n",
+                       ratio, freq, clk_rate);
+-              if (ratio % 2 == 0 && ratio >= 2 && ratio <= 512)
+-                      ratio /= 2;
+-              else
+-                      continue;
++              if ((ratio % 2 == 0 && ratio >= 2 && ratio <= 512) ||
++                  (ratio == 1 && sai->verid.id >= FSL_SAI_VERID_0301)) {
+-              if (ret < savesub) {
+-                      savediv = ratio;
+-                      sai->mclk_id[tx] = id;
+-                      savesub = ret;
+-              }
++                      if (ret < savesub) {
++                              saveratio = ratio;
++                              sai->mclk_id[tx] = id;
++                              savesub = ret;
++                      }
+-              if (ret == 0)
+-                      break;
++                      if (ret == 0)
++                              break;
++              }
+       }
+-      if (savediv == 0) {
++      if (saveratio == 0) {
+               dev_err(dai->dev, "failed to derive required %cx rate: %d\n",
+                               tx ? 'T' : 'R', freq);
+               return -EINVAL;
+@@ -530,33 +532,32 @@ static int fsl_sai_set_bclk(struct snd_s
+        * 4) For Tx and Rx are both Synchronous with another SAI, we just
+        *    ignore it.
+        */
+-      if ((sai->synchronous[TX] && !sai->synchronous[RX]) ||
+-          (!tx && !sai->synchronous[RX])) {
+-              regmap_update_bits(sai->regmap, FSL_SAI_RCR2(offset),
+-                                 FSL_SAI_CR2_MSEL_MASK,
+-                                 FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
+-              regmap_update_bits(sai->regmap, FSL_SAI_RCR2(offset),
+-                                 FSL_SAI_CR2_DIV_MASK, savediv - 1);
+-      } else if ((sai->synchronous[RX] && !sai->synchronous[TX]) ||
+-                 (tx && !sai->synchronous[TX])) {
+-              regmap_update_bits(sai->regmap, FSL_SAI_TCR2(offset),
+-                                 FSL_SAI_CR2_MSEL_MASK,
+-                                 FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
+-              regmap_update_bits(sai->regmap, FSL_SAI_TCR2(offset),
+-                                 FSL_SAI_CR2_DIV_MASK, savediv - 1);
++      if ((!tx || sai->synchronous[TX]) && !sai->synchronous[RX])
++              reg = FSL_SAI_RCR2(offset);
++      else if ((tx || sai->synchronous[RX]) && !sai->synchronous[TX])
++              reg = FSL_SAI_TCR2(offset);
++
++      if (reg) {
++              regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_MSEL_MASK,
++                         FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
++
++              savediv = (saveratio == 1 ? 0 : (saveratio >> 1) - 1);
++              regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_DIV_MASK, savediv);
++
++              if (sai->verid.id >= FSL_SAI_VERID_0301) {
++                      regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_BYP,
++                                 (saveratio == 1 ? FSL_SAI_CR2_BYP : 0));
++              }
+       }
+-      fsl_sai_check_ver(dai);
+-      switch (sai->verid.id) {
+-      case FSL_SAI_VERID_0301:
++      if (sai->verid.id >= FSL_SAI_VERID_0301) {
+               /* SAI is in master mode at this point, so enable MCLK */
+               regmap_update_bits(sai->regmap, FSL_SAI_MCTL,
+-                              FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN);
+-              break;
++                      FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN);
+       }
+-      dev_dbg(dai->dev, "best fit: clock id=%d, div=%d, deviation =%d\n",
+-                      sai->mclk_id[tx], savediv, savesub);
++      dev_dbg(dai->dev, "best fit: clock id=%d, ratio=%d, deviation=%d\n",
++                      sai->mclk_id[tx], saveratio, savesub);
+       return 0;
+ }
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -122,7 +122,7 @@
+ #define FSL_SAI_CR2_MSEL(ID)  ((ID) << 26)
+ #define FSL_SAI_CR2_BCP               BIT(25)
+ #define FSL_SAI_CR2_BCD_MSTR  BIT(24)
+-#define FSL_SAI_CR2_BCBP      BIT(23) /* BCLK bypass */
++#define FSL_SAI_CR2_BYP               BIT(23) /* BCLK bypass */
+ #define FSL_SAI_CR2_DIV_MASK  0xff
+ /* SAI Transmit and Receive Configuration 3 Register */
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0052-MLK-18682-1-ASoC-fsl-sai-use-set_bclk_ratio-to-calcu.patch b/target/linux/layerscape/patches-5.4/801-audio-0052-MLK-18682-1-ASoC-fsl-sai-use-set_bclk_ratio-to-calcu.patch
new file mode 100644 (file)
index 0000000..7c3685f
--- /dev/null
@@ -0,0 +1,98 @@
+From fc4146698489c4725c9ac86ea3e0484914d5285b Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Wed, 27 Jun 2018 10:31:02 +0300
+Subject: [PATCH] MLK-18682-1: ASoC: fsl: sai: use set_bclk_ratio to calculate
+ BCLK freq (part 1)
+
+ALSA API has a standard way to configure DAI BCLK by calling
+"snd_soc_dai_set_bclk_ratio" function. So use it to set BCLK ratio
+and calculate SAI BCLK frequency.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+[ Aisheng: split machine imx-pdm changes ]
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 21 +++++++++++++--------
+ sound/soc/fsl/fsl_sai.h |  3 +--
+ 2 files changed, 14 insertions(+), 10 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -234,6 +234,14 @@ static int fsl_sai_set_dai_sysclk_tr(str
+       return 0;
+ }
++static int fsl_sai_set_dai_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
++{
++      struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
++
++      sai->bitclk_ratio = ratio;
++      return 0;
++}
++
+ static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+               int clk_id, unsigned int freq, int dir)
+ {
+@@ -243,11 +251,6 @@ static int fsl_sai_set_dai_sysclk(struct
+       if (dir == SND_SOC_CLOCK_IN)
+               return 0;
+-      if (clk_id == FSL_SAI_CLK_BIT) {
+-              sai->bitclk_freq = freq;
+-              return 0;
+-      }
+-
+       if (freq > 0) {
+               if (clk_id < 0 || clk_id >= FSL_SAI_MCLK_MAX) {
+                       dev_err(cpu_dai->dev, "Unknown clock id: %d\n", clk_id);
+@@ -571,6 +574,7 @@ static int fsl_sai_hw_params(struct snd_
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       unsigned int channels = params_channels(params);
+       u32 word_width = params_width(params);
++      u32 rate = params_rate(params);
+       u32 val_cr4 = 0, val_cr5 = 0;
+       u32 slots = (channels == 1) ? 2 : channels;
+       u32 slot_width = word_width;
+@@ -605,12 +609,12 @@ static int fsl_sai_hw_params(struct snd_
+               slot_width = sai->slot_width;
+       if (!sai->slave_mode[tx]) {
+-              if (sai->bitclk_freq)
++              if (sai->bitclk_ratio)
+                       ret = fsl_sai_set_bclk(cpu_dai, tx,
+-                                      sai->bitclk_freq);
++                                      rate * sai->bitclk_ratio);
+               else
+                       ret = fsl_sai_set_bclk(cpu_dai, tx,
+-                              slots * slot_width * params_rate(params));
++                                      rate * slots * slot_width);
+               if (ret)
+                       return ret;
+@@ -935,6 +939,7 @@ static void fsl_sai_shutdown(struct snd_
+ }
+ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
++      .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio,
+       .set_sysclk     = fsl_sai_set_dai_sysclk,
+       .set_fmt        = fsl_sai_set_dai_fmt,
+       .set_tdm_slot   = fsl_sai_set_dai_tdm_slot,
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -203,7 +203,6 @@
+ #define FSL_SAI_CLK_MAST3     3
+ #define FSL_SAI_MCLK_MAX      4
+-#define FSL_SAI_CLK_BIT               5
+ /* SAI data transfer numbers per DMA request */
+ #define FSL_SAI_MAXBURST_TX 6
+@@ -258,7 +257,7 @@ struct fsl_sai {
+       unsigned int mclk_streams;
+       unsigned int slots;
+       unsigned int slot_width;
+-      unsigned int bitclk_freq;
++      unsigned int bitclk_ratio;
+       struct snd_dmaengine_dai_dma_data dma_params_rx;
+       struct snd_dmaengine_dai_dma_data dma_params_tx;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0053-MLK-18682-2-ASoC-fsl-sai-allow-dynamic-pll-switching.patch b/target/linux/layerscape/patches-5.4/801-audio-0053-MLK-18682-2-ASoC-fsl-sai-allow-dynamic-pll-switching.patch
new file mode 100644 (file)
index 0000000..373305d
--- /dev/null
@@ -0,0 +1,121 @@
+From b2dd96ec88b7eb4288ca39a1fc78176872c0683b Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Wed, 27 Jun 2018 10:59:12 +0300
+Subject: [PATCH] MLK-18682-2: ASoC: fsl: sai: allow dynamic pll switching
+
+Currently SAI master clock derives from an audio pll that cannot be
+changed at runtime. iMX8 SoC has 2 audio plls usually configured to support
+either 8000Hz (8k,16k,32k,48k,etc) or 11025Hz (11k,22k,44.1k,88.2k,etc)
+ranges of rates - thus at runtime a SAI interface is able to play only one
+range of rates. The patch allows dynamic SAI master clock reparenting to
+the appropriate audio pll as function of the audio stream rate to be
+played/recorded.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 60 ++++++++++++++++++++++++++++++++++++++++++++-----
+ sound/soc/fsl/fsl_sai.h |  2 ++
+ 2 files changed, 57 insertions(+), 5 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -5,6 +5,7 @@
+ // Copyright 2012-2016 Freescale Semiconductor, Inc.
+ #include <linux/clk.h>
++#include <linux/clk-provider.h>
+ #include <linux/delay.h>
+ #include <linux/dmaengine.h>
+ #include <linux/module.h>
+@@ -234,6 +235,50 @@ static int fsl_sai_set_dai_sysclk_tr(str
+       return 0;
+ }
++static int fsl_sai_set_mclk_rate(struct snd_soc_dai *dai, int clk_id,
++              unsigned int freq)
++{
++      struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
++      struct clk *p = sai->mclk_clk[clk_id], *pll = 0, *npll = 0;
++      u64 ratio = freq;
++      int ret;
++
++      while (p && sai->pll8k_clk && sai->pll11k_clk) {
++              struct clk *pp = clk_get_parent(p);
++
++              if (clk_is_match(pp, sai->pll8k_clk) ||
++                  clk_is_match(pp, sai->pll11k_clk)) {
++                      pll = pp;
++                      break;
++              }
++              p = pp;
++      }
++
++      if (pll) {
++              npll = (do_div(ratio, 8000) ? sai->pll11k_clk : sai->pll8k_clk);
++              if (!clk_is_match(pll, npll)) {
++                      if (sai->mclk_streams == 0) {
++                              ret = clk_set_parent(p, npll);
++                              if (ret < 0)
++                                      dev_warn(dai->dev,
++                                              "failed to set parent %s: %d\n",
++                                              __clk_get_name(npll), ret);
++                      } else {
++                              dev_err(dai->dev,
++                                      "PLL %s is in use by a running stream.\n",
++                                      __clk_get_name(pll));
++                              return -EINVAL;
++                      }
++              }
++      }
++
++      ret = clk_set_rate(sai->mclk_clk[clk_id], freq);
++      if (ret < 0)
++              dev_err(dai->dev, "failed to set clock rate (%u): %d\n",
++                              freq, ret);
++      return ret;
++}
++
+ static int fsl_sai_set_dai_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+ {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
+@@ -262,12 +307,9 @@ static int fsl_sai_set_dai_sysclk(struct
+                       return -EINVAL;
+               }
+-              ret = clk_set_rate(sai->mclk_clk[clk_id], freq);
+-              if (ret < 0) {
+-                      dev_err(cpu_dai->dev, "failed to set clock rate (%u): %d\n",
+-                                      freq, ret);
++              ret = fsl_sai_set_mclk_rate(cpu_dai, clk_id, freq);
++              if (ret < 0)
+                       return ret;
+-              }
+       }
+       ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
+@@ -1288,6 +1330,14 @@ static int fsl_sai_probe(struct platform
+               }
+       }
++      sai->pll8k_clk = devm_clk_get(&pdev->dev, "pll8k");
++      if (IS_ERR(sai->pll8k_clk))
++              sai->pll8k_clk = NULL;
++
++      sai->pll11k_clk = devm_clk_get(&pdev->dev, "pll11k");
++      if (IS_ERR(sai->pll11k_clk))
++              sai->pll11k_clk = NULL;
++
+       if (of_find_property(np, "fsl,sai-multi-lane", NULL))
+               sai->is_multi_lane = true;
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -239,6 +239,8 @@ struct fsl_sai {
+       struct regmap *regmap;
+       struct clk *bus_clk;
+       struct clk *mclk_clk[FSL_SAI_MCLK_MAX];
++      struct clk *pll8k_clk;
++      struct clk *pll11k_clk;
+       bool slave_mode[2];
+       bool is_lsb_first;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0054-MLK-18947-ASoC-fsl_sai-fix-volatile-function.patch b/target/linux/layerscape/patches-5.4/801-audio-0054-MLK-18947-ASoC-fsl_sai-fix-volatile-function.patch
new file mode 100644 (file)
index 0000000..7004219
--- /dev/null
@@ -0,0 +1,30 @@
+From 84b1defe99a15b96d32f4c2fecb2c8e9149f696c Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Wed, 15 Aug 2018 09:53:07 +0800
+Subject: [PATCH] MLK-18947: ASoC: fsl_sai: fix volatile function
+
+The FSL_SAI_VERID and FSL_SAI_PARAM only available
+when reg_offset is 8
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+(cherry picked from commit 0a0695672dc7ecf07a7642ff6f99f0b9d3a26b32)
+---
+ sound/soc/fsl/fsl_sai.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -1162,9 +1162,11 @@ static bool fsl_sai_volatile_reg(struct
+       if (reg == FSL_SAI_TCSR(offset) || reg == FSL_SAI_RCSR(offset))
+               return true;
++      if (sai->soc->reg_offset == 8 && (reg == FSL_SAI_VERID ||
++                              reg == FSL_SAI_PARAM))
++              return true;
++
+       switch (reg) {
+-      case FSL_SAI_VERID:
+-      case FSL_SAI_PARAM:
+       case FSL_SAI_TFR0:
+       case FSL_SAI_TFR1:
+       case FSL_SAI_TFR2:
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0055-MLK-18898-1-ASoC-fsl_sai-select-pinctrl-state-as-fun.patch b/target/linux/layerscape/patches-5.4/801-audio-0055-MLK-18898-1-ASoC-fsl_sai-select-pinctrl-state-as-fun.patch
new file mode 100644 (file)
index 0000000..2912d76
--- /dev/null
@@ -0,0 +1,100 @@
+From 001937cc21a05165530c0775c4646bd04e797658 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Mon, 27 Aug 2018 13:50:17 +0300
+Subject: [PATCH] MLK-18898-1: ASoC: fsl_sai: select pinctrl state as function
+ of bitclock rate
+
+Similar to DSD512 case we need a PCM pinctrl state option to map SAI BCLK
+to codec MCLK pin. Given that bitclock rate is function of slots number and
+slot width - pass bclk rate as parameter value from SAI driver.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+(cherry picked from commit 826caeae32713cff7ad50de8ebc9915de975edd9)
+---
+ sound/soc/fsl/fsl_dsd.h | 15 +++++++--------
+ sound/soc/fsl/fsl_sai.c | 24 ++++++++++--------------
+ 2 files changed, 17 insertions(+), 22 deletions(-)
+
+--- a/sound/soc/fsl/fsl_dsd.h
++++ b/sound/soc/fsl/fsl_dsd.h
+@@ -30,23 +30,22 @@ static bool fsl_is_dsd(struct snd_pcm_hw
+ }
+ static struct pinctrl_state *fsl_get_pins_state(struct pinctrl *pinctrl,
+-      struct snd_pcm_hw_params *params)
++      struct snd_pcm_hw_params *params, u32 bclk)
+ {
+-      int dsd_bclk;
+       struct pinctrl_state *state = 0;
+       if (fsl_is_dsd(params)) {
+-              dsd_bclk = params_rate(params) * params_physical_width(params);
+-
+-              switch (dsd_bclk) {
+-              case 22579200: /* DSD512 */
++              /* DSD512@44.1kHz, DSD512@48kHz */
++              if (bclk >= 22579200)
+                       state = pinctrl_lookup_state(pinctrl, "dsd512");
+-                      break;
+-              }
+               /* Get default DSD state */
+               if (IS_ERR_OR_NULL(state))
+                       state = pinctrl_lookup_state(pinctrl, "dsd");
++      } else {
++              /* 706k32b2c, 768k32b2c, etc */
++              if (bclk >= 45158400)
++                      state = pinctrl_lookup_state(pinctrl, "pcm_b2m");
+       }
+       /* Get default state */
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -620,7 +620,7 @@ static int fsl_sai_hw_params(struct snd_
+       u32 val_cr4 = 0, val_cr5 = 0;
+       u32 slots = (channels == 1) ? 2 : channels;
+       u32 slot_width = word_width;
+-      u32 pins;
++      u32 pins, bclk;
+       int ret;
+       int i;
+       int trce_mask = 0;
+@@ -630,9 +630,16 @@ static int fsl_sai_hw_params(struct snd_
+       pins = DIV_ROUND_UP(channels, slots);
+       sai->is_dsd = fsl_is_dsd(params);
++      if (sai->is_dsd)
++              pins = channels;
++
++      if (sai->slot_width)
++              slot_width = sai->slot_width;
++
++      bclk = rate*(sai->bitclk_ratio ? sai->bitclk_ratio : slots * slot_width);
+       if (!IS_ERR_OR_NULL(sai->pinctrl)) {
+-              sai->pins_state = fsl_get_pins_state(sai->pinctrl, params);
++              sai->pins_state = fsl_get_pins_state(sai->pinctrl, params, bclk);
+               if (!IS_ERR_OR_NULL(sai->pins_state)) {
+                       ret = pinctrl_select_state(sai->pinctrl, sai->pins_state);
+@@ -644,19 +651,8 @@ static int fsl_sai_hw_params(struct snd_
+               }
+       }
+-      if (sai->is_dsd)
+-              pins = channels;
+-
+-      if (sai->slot_width)
+-              slot_width = sai->slot_width;
+-
+       if (!sai->slave_mode[tx]) {
+-              if (sai->bitclk_ratio)
+-                      ret = fsl_sai_set_bclk(cpu_dai, tx,
+-                                      rate * sai->bitclk_ratio);
+-              else
+-                      ret = fsl_sai_set_bclk(cpu_dai, tx,
+-                                      rate * slots * slot_width);
++              ret = fsl_sai_set_bclk(cpu_dai, tx, bclk);
+               if (ret)
+                       return ret;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0056-MLK-19573-1-ASoC-fsl-dsd-make-fsl_get_pins_state-inl.patch b/target/linux/layerscape/patches-5.4/801-audio-0056-MLK-19573-1-ASoC-fsl-dsd-make-fsl_get_pins_state-inl.patch
new file mode 100644 (file)
index 0000000..aa40533
--- /dev/null
@@ -0,0 +1,24 @@
+From 7d66ca1081c0626f03aa8f419ca253e88a10018e Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Mon, 17 Sep 2018 09:31:24 +0300
+Subject: [PATCH] MLK-19573-1: ASoC: fsl: dsd: make fsl_get_pins_state inline
+
+Make fsl_get_pins_state function inline.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+(cherry picked from commit badcb97ebd8c0aae89f76e979bcc801be35c7400)
+---
+ sound/soc/fsl/fsl_dsd.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/soc/fsl/fsl_dsd.h
++++ b/sound/soc/fsl/fsl_dsd.h
+@@ -29,7 +29,7 @@ static bool fsl_is_dsd(struct snd_pcm_hw
+       }
+ }
+-static struct pinctrl_state *fsl_get_pins_state(struct pinctrl *pinctrl,
++static inline struct pinctrl_state *fsl_get_pins_state(struct pinctrl *pinctrl,
+       struct snd_pcm_hw_params *params, u32 bclk)
+ {
+       struct pinctrl_state *state = 0;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0057-MLK-15975-3-ASoC-fsl_sai-The-offset-of-fifo_off-is-c.patch b/target/linux/layerscape/patches-5.4/801-audio-0057-MLK-15975-3-ASoC-fsl_sai-The-offset-of-fifo_off-is-c.patch
new file mode 100644 (file)
index 0000000..8a01eaf
--- /dev/null
@@ -0,0 +1,41 @@
+From af52be88c689521364e06924e26c8989a075e0e3 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Fri, 28 Sep 2018 15:33:34 +0800
+Subject: [PATCH] MLK-15975-3: ASoC: fsl_sai: The offset of fifo_off is changed
+
+Commit 786c8bd56324 ("MLK-19734-3: dmaengine: imx-sdma: change
+fifo offset of fifo_num") change the offset of fifo_off, so
+the sai driver need to be updated.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+(cherry picked from commit c94ce8776e01f1f40a866d4da89603ab042dde0f)
+---
+ sound/soc/fsl/fsl_sai.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -726,19 +726,19 @@ static int fsl_sai_hw_params(struct snd_
+                                               FSL_SAI_MAXBURST_TX * pins;
+                               if (sai->is_dsd)
+                                       sai->dma_params_tx.fifo_num = pins +
+-                                         (sai->dataline_off_dsd[tx] << 8);
++                                         (sai->dataline_off_dsd[tx] << 4);
+                               else
+                                       sai->dma_params_tx.fifo_num = pins +
+-                                              (sai->dataline_off[tx] << 8);
++                                              (sai->dataline_off[tx] << 4);
+                       } else {
+                               sai->dma_params_rx.maxburst =
+                                       FSL_SAI_MAXBURST_RX * pins;
+                               if (sai->is_dsd)
+                                       sai->dma_params_rx.fifo_num = pins +
+-                                        (sai->dataline_off_dsd[tx] << 8);
++                                        (sai->dataline_off_dsd[tx] << 4);
+                               else
+                                       sai->dma_params_rx.fifo_num = pins +
+-                                              (sai->dataline_off[tx] << 8);
++                                              (sai->dataline_off[tx] << 4);
+                       }
+               }
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0058-MLK-20189-8-ASoC-fsl_sai-use-signed-offset-variable.patch b/target/linux/layerscape/patches-5.4/801-audio-0058-MLK-20189-8-ASoC-fsl_sai-use-signed-offset-variable.patch
new file mode 100644 (file)
index 0000000..97f4cb0
--- /dev/null
@@ -0,0 +1,53 @@
+From d8802def525b4f74f66fca02afe9c17a729a3201 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Tue, 13 Nov 2018 11:36:29 +0200
+Subject: [PATCH] MLK-20189-8: ASoC: fsl_sai: use signed offset variable
+
+Both dataline_off and dataline_off_dsd fields are unsigned,
+thus checking negative values make no sense. Use a signed
+variable to calculate offset instead.
+
+This fixes Coverity issue: CID1899299
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 14 +++++---------
+ 1 file changed, 5 insertions(+), 9 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -1273,7 +1273,7 @@ static int fsl_sai_probe(struct platform
+       char tmp[8];
+       int irq, ret, i;
+       int index;
+-      int firstbitidx, nextbitidx;
++      int firstbitidx, nextbitidx, offset;
+       struct regmap_config fsl_sai_regmap_config = fsl_sai_v2_regmap_config;
+       unsigned long irqflags = 0;
+@@ -1356,10 +1356,8 @@ static int fsl_sai_probe(struct platform
+       for (i = 0; i < 2; i++) {
+               firstbitidx = find_first_bit((const unsigned long *)&sai->dataline[i], 8);
+               nextbitidx = find_next_bit((const unsigned long *)&sai->dataline[i], 8, firstbitidx+1);
+-              sai->dataline_off[i] = nextbitidx - firstbitidx - 1;
+-
+-              if (sai->dataline_off[i] < 0 || sai->dataline_off[i] >= 7)
+-                      sai->dataline_off[i] = 0;
++              offset = nextbitidx - firstbitidx - 1;
++              sai->dataline_off[i] = (offset < 0 || offset >= 7 ? 0 : offset);
+       }
+       ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 0, &sai->dataline_dsd[0]);
+@@ -1378,10 +1376,8 @@ static int fsl_sai_probe(struct platform
+       for (i = 0; i < 2; i++) {
+               firstbitidx = find_first_bit((const unsigned long *)&sai->dataline_dsd[i], 8);
+               nextbitidx = find_next_bit((const unsigned long *)&sai->dataline_dsd[i], 8, firstbitidx+1);
+-              sai->dataline_off_dsd[i] = nextbitidx - firstbitidx - 1;
+-
+-              if (sai->dataline_off_dsd[i] < 0 || sai->dataline_off_dsd[i] >= 7)
+-                      sai->dataline_off_dsd[i] = 0;
++              offset = nextbitidx - firstbitidx - 1;
++              sai->dataline_off_dsd[i] = (offset < 0 || offset >= 7 ? 0 : offset);
+       }
+       if ((of_find_property(np, "fsl,i2s-xtor", NULL) != NULL) ||
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0059-MLK-20328-1-ASoC-fsl_sai-map-number-of-pins-to-datal.patch b/target/linux/layerscape/patches-5.4/801-audio-0059-MLK-20328-1-ASoC-fsl_sai-map-number-of-pins-to-datal.patch
new file mode 100644 (file)
index 0000000..4f1bcea
--- /dev/null
@@ -0,0 +1,373 @@
+From e62741891f6901b5219eacdf60835cac9beb7bae Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Wed, 21 Nov 2018 16:09:44 +0200
+Subject: [PATCH] MLK-20328-1: ASoC: fsl_sai: map number of pins to dataline
+ masks
+
+The patch enable mapping the number of pins required to play or record
+a specific number of channels to a specific dataline mask.
+
+Three consequent elements in "fsl,dataline" and "fsl,dataline,dsd" defines a
+particular mapping, for instance for: fsl,dataline = "0 0xff 0xff 2 0x11 0x11"
+there are two mappings defined:
+
+default (0 pins) "rx" and "tx" dataline masks: 0 0xff 0xff
+         2 pins  "rx" and "tx" dataline masks: 2 0x11 0x11
+
+In case if property is missing, then default value "0 0x1 0x1" is considered.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 227 ++++++++++++++++++++++++++++++------------------
+ sound/soc/fsl/fsl_sai.h |  16 +++-
+ 2 files changed, 153 insertions(+), 90 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -621,17 +621,35 @@ static int fsl_sai_hw_params(struct snd_
+       u32 slots = (channels == 1) ? 2 : channels;
+       u32 slot_width = word_width;
+       u32 pins, bclk;
+-      int ret;
+-      int i;
+-      int trce_mask = 0;
++      int ret, i, trce_mask = 0, dl_cfg_cnt, dl_cfg_idx = 0;
++      struct fsl_sai_dl_cfg *dl_cfg;
+       if (sai->slots)
+               slots = sai->slots;
+       pins = DIV_ROUND_UP(channels, slots);
+       sai->is_dsd = fsl_is_dsd(params);
+-      if (sai->is_dsd)
++      if (sai->is_dsd) {
+               pins = channels;
++              dl_cfg = sai->dsd_dl_cfg;
++              dl_cfg_cnt = sai->dsd_dl_cfg_cnt;
++      } else {
++              dl_cfg = sai->pcm_dl_cfg;
++              dl_cfg_cnt = sai->pcm_dl_cfg_cnt;
++      }
++
++      for (i = 0; i < dl_cfg_cnt; i++) {
++              if (dl_cfg[i].pins == pins) {
++                      dl_cfg_idx = i;
++                      break;
++              }
++      }
++
++      if (dl_cfg_idx >= dl_cfg_cnt) {
++              dev_err(cpu_dai->dev, "fsl,dataline%s invalid or not provided.\n",
++                      sai->is_dsd ? ",dsd" : "");
++              return -EINVAL;
++      }
+       if (sai->slot_width)
+               slot_width = sai->slot_width;
+@@ -713,7 +731,7 @@ static int fsl_sai_hw_params(struct snd_
+       if (sai->soc->dataline != 0x1) {
+-              if (sai->dataline[tx] <= 1 || sai->is_multi_lane)
++              if (dl_cfg[dl_cfg_idx].mask[tx] <= 1 || sai->is_multi_lane)
+                       regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
+                               FSL_SAI_CR4_FCOMB_MASK, 0);
+               else
+@@ -724,21 +742,13 @@ static int fsl_sai_hw_params(struct snd_
+                       if (tx) {
+                               sai->dma_params_tx.maxburst =
+                                               FSL_SAI_MAXBURST_TX * pins;
+-                              if (sai->is_dsd)
+-                                      sai->dma_params_tx.fifo_num = pins +
+-                                         (sai->dataline_off_dsd[tx] << 4);
+-                              else
+-                                      sai->dma_params_tx.fifo_num = pins +
+-                                              (sai->dataline_off[tx] << 4);
++                              sai->dma_params_tx.fifo_num = pins +
++                                         (dl_cfg[dl_cfg_idx].offset[tx] << 4);
+                       } else {
+                               sai->dma_params_rx.maxburst =
+                                       FSL_SAI_MAXBURST_RX * pins;
+-                              if (sai->is_dsd)
+-                                      sai->dma_params_rx.fifo_num = pins +
+-                                        (sai->dataline_off_dsd[tx] << 4);
+-                              else
+-                                      sai->dma_params_rx.fifo_num = pins +
+-                                              (sai->dataline_off[tx] << 4);
++                              sai->dma_params_rx.fifo_num = pins +
++                                        (dl_cfg[dl_cfg_idx].offset[tx] << 4);
+                       }
+               }
+@@ -746,38 +756,22 @@ static int fsl_sai_hw_params(struct snd_
+                               &sai->dma_params_rx);
+       }
+-      if (sai->is_dsd) {
+-              if (__sw_hweight8(sai->dataline_dsd[tx] & 0xFF) < pins) {
+-                      dev_err(cpu_dai->dev, "channel not supported\n");
+-                      return -EINVAL;
+-              }
+-              /*find a proper tcre setting*/
+-              for (i = 0; i < 8; i++) {
+-                      trce_mask = (1 << (i + 1)) - 1;
+-                      if (__sw_hweight8(sai->dataline_dsd[tx] & trce_mask) == pins)
+-                              break;
+-              }
+-
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
+-                         FSL_SAI_CR3_TRCE_MASK,
+-                         FSL_SAI_CR3_TRCE((sai->dataline_dsd[tx] & trce_mask)));
+-      } else {
+-              if (__sw_hweight8(sai->dataline[tx] & 0xFF) < pins) {
+-                      dev_err(cpu_dai->dev, "channel not supported\n");
+-                      return -EINVAL;
+-              }
+-              /*find a proper tcre setting*/
+-              for (i = 0; i < 8; i++) {
+-                      trce_mask = (1 << (i + 1)) - 1;
+-                      if (__sw_hweight8(sai->dataline[tx] & trce_mask) == pins)
+-                              break;
+-              }
++      if (__sw_hweight8(dl_cfg[dl_cfg_idx].mask[tx] & 0xFF) < pins) {
++              dev_err(cpu_dai->dev, "channel not supported\n");
++              return -EINVAL;
++      }
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
+-                         FSL_SAI_CR3_TRCE_MASK,
+-                         FSL_SAI_CR3_TRCE((sai->dataline[tx] & trce_mask)));
++      /*find a proper tcre setting*/
++      for (i = 0; i < 8; i++) {
++              trce_mask = (1 << (i + 1)) - 1;
++              if (__sw_hweight8(dl_cfg[dl_cfg_idx].mask[tx] & trce_mask) == pins)
++                      break;
+       }
++      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
++                 FSL_SAI_CR3_TRCE_MASK,
++                 FSL_SAI_CR3_TRCE((dl_cfg[dl_cfg_idx].mask[tx] & trce_mask)));
++
+       regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
+                          FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
+                          FSL_SAI_CR4_CHMOD_MASK,
+@@ -820,15 +814,32 @@ static int fsl_sai_trigger(struct snd_pc
+       u32 slots = (channels == 1) ? 2 : channels;
+       u32 xcsr, count = 100;
+       u32 pins;
+-      int i = 0, j = 0, k = 0;
++      int i = 0, j = 0, k = 0, dl_cfg_cnt, dl_cfg_idx = 0;
++      struct fsl_sai_dl_cfg *dl_cfg;
+       if (sai->slots)
+               slots = sai->slots;
+       pins = DIV_ROUND_UP(channels, slots);
+-      if (sai->is_dsd)
++      if (sai->is_dsd) {
+               pins = channels;
++              dl_cfg = sai->dsd_dl_cfg;
++              dl_cfg_cnt = sai->dsd_dl_cfg_cnt;
++      } else {
++              dl_cfg = sai->pcm_dl_cfg;
++              dl_cfg_cnt = sai->pcm_dl_cfg_cnt;
++      }
++
++      for (i = 0; i < dl_cfg_cnt; i++) {
++              if (dl_cfg[i].pins == pins) {
++                      dl_cfg_idx = i;
++                      break;
++              }
++      }
++
++      i = 0;
++
+       /*
+        * Asynchronous mode: Clear SYNC for both Tx and Rx.
+        * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
+@@ -849,7 +860,7 @@ static int fsl_sai_trigger(struct snd_pc
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               while (tx && i < channels) {
+-                      if ((sai->is_dsd ? sai->dataline_dsd[tx] : sai->dataline[tx]) & (1 << j)) {
++                      if (dl_cfg[dl_cfg_idx].mask[tx] & (1 << j)) {
+                               regmap_write(sai->regmap, FSL_SAI_TDR0 + j * 0x4, 0x0);
+                               i++;
+                               k++;
+@@ -1262,6 +1273,77 @@ static const struct of_device_id fsl_sai
+ };
+ MODULE_DEVICE_TABLE(of, fsl_sai_ids);
++static unsigned int fsl_sai_calc_dl_off(unsigned int* dl_mask)
++{
++      int fbidx, nbidx, offset;
++
++      fbidx = find_first_bit((const unsigned long *)dl_mask, 8);
++      nbidx = find_next_bit((const unsigned long *)dl_mask, 8, fbidx+1);
++      offset = nbidx - fbidx - 1;
++
++      return (offset < 0 || offset >= 7 ? 0 : offset);
++}
++
++static int fsl_sai_read_dlcfg(struct platform_device *pdev, char *pn,
++      struct fsl_sai_dl_cfg **rcfg, unsigned int soc_dl)
++{
++      int ret, elems, i, index, num_cfg;
++      struct device_node *np = pdev->dev.of_node;
++      struct fsl_sai_dl_cfg *cfg;
++      u32 rx, tx, pins;
++
++      *rcfg = NULL;
++
++      elems = of_property_count_u32_elems(np, pn);
++
++      /* consider default value "0 0x1 0x1" if property is missing */
++      if (elems <= 0)
++              elems = 3;
++
++      if (elems % 3) {
++              dev_err(&pdev->dev,
++                      "Number of elements in %s must be divisible to 3.\n", pn);
++              return -EINVAL;
++      }
++
++      num_cfg = elems / 3;
++      cfg = devm_kzalloc(&pdev->dev, num_cfg * sizeof(*cfg), GFP_KERNEL);
++      if (cfg == NULL) {
++              dev_err(&pdev->dev, "Cannot allocate memory for %s.\n", pn);
++              return -ENOMEM;
++      }
++
++      for (i = 0, index = 0; i < num_cfg; i++) {
++              ret = of_property_read_u32_index(np, pn, index++, &pins);
++              if (ret)
++                      pins = 0;
++
++              ret = of_property_read_u32_index(np, pn, index++, &rx);
++              if (ret)
++                      rx = 1;
++
++              ret = of_property_read_u32_index(np, pn, index++, &tx);
++              if (ret)
++                      tx = 1;
++
++              if ((rx & ~soc_dl) || (tx & ~soc_dl)) {
++                      dev_err(&pdev->dev,
++                              "%s: dataline cfg[%d] setting error, mask is 0x%x\n",
++                               pn, i, soc_dl);
++                      return -EINVAL;
++              }
++
++              cfg[i].pins = pins;
++              cfg[i].mask[0] = rx;
++              cfg[i].offset[0] = fsl_sai_calc_dl_off(&rx);
++              cfg[i].mask[1] = tx;
++              cfg[i].offset[1] = fsl_sai_calc_dl_off(&tx);
++      }
++
++      *rcfg = cfg;
++      return num_cfg;
++}
++
+ static int fsl_sai_probe(struct platform_device *pdev)
+ {
+       struct device_node *np = pdev->dev.of_node;
+@@ -1273,7 +1355,6 @@ static int fsl_sai_probe(struct platform
+       char tmp[8];
+       int irq, ret, i;
+       int index;
+-      int firstbitidx, nextbitidx, offset;
+       struct regmap_config fsl_sai_regmap_config = fsl_sai_v2_regmap_config;
+       unsigned long irqflags = 0;
+@@ -1340,45 +1421,19 @@ static int fsl_sai_probe(struct platform
+               sai->is_multi_lane = true;
+       /*dataline mask for rx and tx*/
+-      ret = of_property_read_u32_index(np, "fsl,dataline", 0, &sai->dataline[0]);
+-      if (ret)
+-              sai->dataline[0] = 1;
+-
+-      ret = of_property_read_u32_index(np, "fsl,dataline", 1, &sai->dataline[1]);
+-      if (ret)
+-              sai->dataline[1] = 1;
+-
+-      if ((sai->dataline[0] & (~sai->soc->dataline)) || sai->dataline[1] & (~sai->soc->dataline)) {
+-              dev_err(&pdev->dev, "dataline setting error, Mask is 0x%x\n", sai->soc->dataline);
+-              return -EINVAL;
+-      }
+-
+-      for (i = 0; i < 2; i++) {
+-              firstbitidx = find_first_bit((const unsigned long *)&sai->dataline[i], 8);
+-              nextbitidx = find_next_bit((const unsigned long *)&sai->dataline[i], 8, firstbitidx+1);
+-              offset = nextbitidx - firstbitidx - 1;
+-              sai->dataline_off[i] = (offset < 0 || offset >= 7 ? 0 : offset);
+-      }
+-
+-      ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 0, &sai->dataline_dsd[0]);
+-      if (ret)
+-              sai->dataline_dsd[0] = 1;
+-
+-      ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 1, &sai->dataline_dsd[1]);
+-      if (ret)
+-              sai->dataline_dsd[1] = 1;
++      ret = fsl_sai_read_dlcfg(pdev, "fsl,dataline", &sai->pcm_dl_cfg,
++                                      sai->soc->dataline);
++      if (ret < 0)
++              return ret;
++
++      sai->pcm_dl_cfg_cnt = ret;
++
++      ret = fsl_sai_read_dlcfg(pdev, "fsl,dataline,dsd", &sai->dsd_dl_cfg,
++                                      sai->soc->dataline);
++      if (ret < 0)
++              return ret;
+-      if ((sai->dataline_dsd[0] & (~sai->soc->dataline)) || sai->dataline_dsd[1] & (~sai->soc->dataline)) {
+-              dev_err(&pdev->dev, "dataline setting error, Mask is 0x%x\n", sai->soc->dataline);
+-              return -EINVAL;
+-      }
+-
+-      for (i = 0; i < 2; i++) {
+-              firstbitidx = find_first_bit((const unsigned long *)&sai->dataline_dsd[i], 8);
+-              nextbitidx = find_next_bit((const unsigned long *)&sai->dataline_dsd[i], 8, firstbitidx+1);
+-              offset = nextbitidx - firstbitidx - 1;
+-              sai->dataline_off_dsd[i] = (offset < 0 || offset >= 7 ? 0 : offset);
+-      }
++      sai->dsd_dl_cfg_cnt = ret;
+       if ((of_find_property(np, "fsl,i2s-xtor", NULL) != NULL) ||
+           (of_find_property(np, "fsl,txm-rxs", NULL) != NULL))
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -234,6 +234,12 @@ struct fsl_sai_param {
+       u32 dln; /* number of datalines implemented */
+ };
++struct fsl_sai_dl_cfg {
++      unsigned int pins;
++      unsigned int mask[2];
++      unsigned int offset[2];
++};
++
+ struct fsl_sai {
+       struct platform_device *pdev;
+       struct regmap *regmap;
+@@ -249,10 +255,12 @@ struct fsl_sai {
+       bool synchronous[2];
+       bool is_stream_opened[2];
+       bool is_dsd;
+-      unsigned int dataline[2];
+-      unsigned int dataline_dsd[2];
+-      unsigned int dataline_off[2];
+-      unsigned int dataline_off_dsd[2];
++
++      int pcm_dl_cfg_cnt;
++      int dsd_dl_cfg_cnt;
++      struct fsl_sai_dl_cfg *pcm_dl_cfg;
++      struct fsl_sai_dl_cfg *dsd_dl_cfg;
++
+       unsigned int masterflag[2];
+       unsigned int mclk_id[2];
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0060-ASoC-fsl_sai-Support-EPROBE_DEFER.patch b/target/linux/layerscape/patches-5.4/801-audio-0060-ASoC-fsl_sai-Support-EPROBE_DEFER.patch
new file mode 100644 (file)
index 0000000..56d259a
--- /dev/null
@@ -0,0 +1,23 @@
+From 906ed2027fe62acf79be975c06fc297e77331191 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Tue, 29 Jan 2019 14:41:39 +0800
+Subject: [PATCH] ASoC: fsl_sai: Support -EPROBE_DEFER
+
+Support -EPROBE_DEFER for the resource is not ready in time
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -1383,7 +1383,7 @@ static int fsl_sai_probe(struct platform
+                       "bus", base, &fsl_sai_regmap_config);
+       /* Compatible with old DTB cases */
+-      if (IS_ERR(sai->regmap))
++      if (IS_ERR(sai->regmap) && PTR_ERR(sai->regmap) != -EPROBE_DEFER)
+               sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+                               "sai", base, &fsl_sai_regmap_config);
+       if (IS_ERR(sai->regmap)) {
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0061-ASoC-fsl_sai-support-multi-power-domain.patch b/target/linux/layerscape/patches-5.4/801-audio-0061-ASoC-fsl_sai-support-multi-power-domain.patch
new file mode 100644 (file)
index 0000000..63c77db
--- /dev/null
@@ -0,0 +1,55 @@
+From f11933205182a3da44e7f99d899dd27adafcb6d5 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Tue, 29 Jan 2019 14:51:24 +0800
+Subject: [PATCH] ASoC: fsl_sai: support multi power domain
+
+support multi power domain
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -16,6 +16,7 @@
+ #include <linux/slab.h>
+ #include <linux/time.h>
+ #include <linux/pm_qos.h>
++#include <linux/pm_domain.h>
+ #include <sound/core.h>
+ #include <sound/dmaengine_pcm.h>
+ #include <sound/pcm_params.h>
+@@ -1357,6 +1358,7 @@ static int fsl_sai_probe(struct platform
+       int index;
+       struct regmap_config fsl_sai_regmap_config = fsl_sai_v2_regmap_config;
+       unsigned long irqflags = 0;
++      int num_domains = 0;
+       sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
+       if (!sai)
+@@ -1409,6 +1411,24 @@ static int fsl_sai_probe(struct platform
+               }
+       }
++      num_domains = of_count_phandle_with_args(np, "power-domains",
++                                               "#power-domain-cells");
++      for (i = 0; i < num_domains; i++) {
++              struct device *pd_dev;
++              struct device_link *link;
++
++              pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, i);
++              if (IS_ERR(pd_dev))
++                      return PTR_ERR(pd_dev);
++
++              link = device_link_add(&pdev->dev, pd_dev,
++                      DL_FLAG_STATELESS |
++                      DL_FLAG_PM_RUNTIME |
++                      DL_FLAG_RPM_ACTIVE);
++              if (IS_ERR(link))
++                      return PTR_ERR(link);
++      }
++
+       sai->pll8k_clk = devm_clk_get(&pdev->dev, "pll8k");
+       if (IS_ERR(sai->pll8k_clk))
+               sai->pll8k_clk = NULL;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0062-ASoC-fsl-sai-fix-build-failture-due-to-5.1-RC7-upgra.patch b/target/linux/layerscape/patches-5.4/801-audio-0062-ASoC-fsl-sai-fix-build-failture-due-to-5.1-RC7-upgra.patch
new file mode 100644 (file)
index 0000000..7cce9d4
--- /dev/null
@@ -0,0 +1,42 @@
+From 0e4fe4adfd9a9cd36220b79a8eecce4d24a9fd02 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Tue, 7 May 2019 11:01:08 +0800
+Subject: [PATCH] ASoC: fsl: sai: fix build failture due to 5.1 RC7 upgrade
+
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -418,14 +418,12 @@ static int fsl_sai_set_dai_fmt_tr(struct
+       case SND_SOC_DAIFMT_CBS_CFS:
+               val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
+               val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
+-              sai->is_slave_mode = false;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               sai->slave_mode[tx] = true;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
+-              sai->is_slave_mode = false;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
+@@ -1574,14 +1572,6 @@ static int fsl_sai_remove(struct platfor
+       return 0;
+ }
+-static const struct of_device_id fsl_sai_ids[] = {
+-      { .compatible = "fsl,vf610-sai", },
+-      { .compatible = "fsl,imx6sx-sai", },
+-      { .compatible = "fsl,imx6ul-sai", },
+-      { /* sentinel */ }
+-};
+-MODULE_DEVICE_TABLE(of, fsl_sai_ids);
+-
+ #ifdef CONFIG_PM
+ static int fsl_sai_runtime_suspend(struct device *dev)
+ {
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0063-MLK-21876-4-ASoC-fsl-sai-fix-build-for-next-20190524.patch b/target/linux/layerscape/patches-5.4/801-audio-0063-MLK-21876-4-ASoC-fsl-sai-fix-build-for-next-20190524.patch
new file mode 100644 (file)
index 0000000..8ceb8bf
--- /dev/null
@@ -0,0 +1,68 @@
+From 23212c6c5fcee8c1a317b5beb73c89374751de7b Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Mon, 27 May 2019 17:00:54 +0800
+Subject: [PATCH] MLK-21876-4 ASoC: fsl: sai: fix build for next-20190524
+ upgrade
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+In file included from ../sound/soc/fsl/fsl_sai.c:15:0:
+../sound/soc/fsl/fsl_sai.c: In function ‘fsl_sai_startup’:
+../sound/soc/fsl/fsl_sai.c:957:51: error: ‘offset’ undeclared (first use in this function)
+  regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
+                                                   ^
+../include/linux/regmap.h:77:31: note: in definition of macro ‘regmap_update_bits’
+  regmap_update_bits_base(map, reg, mask, val, NULL, false, false)
+                               ^
+../sound/soc/fsl/fsl_sai.h:84:37: note: in expansion of macro ‘FSL_SAI_TCR3’
+ #define FSL_SAI_xCR3(tx, off) (tx ? FSL_SAI_TCR3(off) : FSL_SAI_RCR3(off))
+                                     ^
+../sound/soc/fsl/fsl_sai.c:957:34: note: in expansion of macro ‘FSL_SAI_xCR3’
+  regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
+                                  ^
+../sound/soc/fsl/fsl_sai.c:957:51: note: each undeclared identifier is reported only once for each function it appears in
+  regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
+                                                   ^
+../include/linux/regmap.h:77:31: note: in definition of macro ‘regmap_update_bits’
+  regmap_update_bits_base(map, reg, mask, val, NULL, false, false)
+                               ^
+../sound/soc/fsl/fsl_sai.h:84:37: note: in expansion of macro ‘FSL_SAI_TCR3’
+ #define FSL_SAI_xCR3(tx, off) (tx ? FSL_SAI_TCR3(off) : FSL_SAI_RCR3(off))
+                                     ^
+../sound/soc/fsl/fsl_sai.c:957:34: note: in expansion of macro ‘FSL_SAI_xCR3’
+  regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
+
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 11 +----------
+ 1 file changed, 1 insertion(+), 10 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -954,10 +954,6 @@ static int fsl_sai_startup(struct snd_pc
+       else
+               sai->is_stream_opened[tx] = true;
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
+-                         FSL_SAI_CR3_TRCE_MASK,
+-                         FSL_SAI_CR3_TRCE(sai->dataline[tx]));
+-
+       /* EDMA engine needs periods of size multiple of tx/rx maxburst */
+       if (sai->soc->constrain_period_size)
+               snd_pcm_hw_constraint_step(substream->runtime, 0,
+@@ -977,13 +973,8 @@ static void fsl_sai_shutdown(struct snd_
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+-      regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
+-
+-      if (sai->is_stream_opened[tx]) {
+-              regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
+-                                 FSL_SAI_CR3_TRCE_MASK, 0);
++      if (sai->is_stream_opened[tx])
+               sai->is_stream_opened[tx] = false;
+-      }
+ }
+ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0064-ASoC-fsl_sai-Mark-cache-dirty-at-resume.patch b/target/linux/layerscape/patches-5.4/801-audio-0064-ASoC-fsl_sai-Mark-cache-dirty-at-resume.patch
new file mode 100644 (file)
index 0000000..1f74ff2
--- /dev/null
@@ -0,0 +1,28 @@
+From e89355ed8ddefc68e33a754fe8be067cee54ce62 Mon Sep 17 00:00:00 2001
+From: Daniel Baluta <daniel.baluta@nxp.com>
+Date: Wed, 19 Jun 2019 19:50:31 +0300
+Subject: [PATCH] ASoC: fsl_sai: Mark cache dirty at resume
+
+This is needed so that at resume will restore the
+correct SAI registers.
+
+Looks like the call to regcache_mark_dirty was missed when
+porting commit 760bd6187413e37c8 ("MLK-15960-2: ASoC: fsl_sai: refine
+the pm runtime function")
+
+Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -1616,6 +1616,8 @@ static int fsl_sai_runtime_resume(struct
+                               PM_QOS_CPU_DMA_LATENCY, 0);
+       regcache_cache_only(sai->regmap, false);
++      regcache_mark_dirty(sai->regmap);
++
+       regmap_write(sai->regmap, FSL_SAI_TCSR(offset), FSL_SAI_CSR_SR);
+       regmap_write(sai->regmap, FSL_SAI_RCSR(offset), FSL_SAI_CSR_SR);
+       usleep_range(1000, 2000);
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0065-LF-106-ASoC-fsl_sai-request-BUS_FREQ_AUDIO.patch b/target/linux/layerscape/patches-5.4/801-audio-0065-LF-106-ASoC-fsl_sai-request-BUS_FREQ_AUDIO.patch
new file mode 100644 (file)
index 0000000..25c65f1
--- /dev/null
@@ -0,0 +1,40 @@
+From 702f662e21b9246348987a119e2a3ca16a31acb7 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Fri, 22 Nov 2019 15:36:31 +0800
+Subject: [PATCH] LF-106: ASoC: fsl_sai: request BUS_FREQ_AUDIO
+
+request BUS_FREQ_AUDIO
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -23,6 +23,7 @@
+ #include <linux/mfd/syscon.h>
+ #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+ #include <linux/pm_runtime.h>
++#include <linux/busfreq-imx.h>
+ #include "fsl_dsd.h"
+ #include "fsl_sai.h"
+@@ -1570,6 +1571,8 @@ static int fsl_sai_runtime_suspend(struc
+       regcache_cache_only(sai->regmap, true);
++      release_bus_freq(BUS_FREQ_AUDIO);
++
+       if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE))
+               clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]);
+@@ -1611,6 +1614,8 @@ static int fsl_sai_runtime_resume(struct
+                       goto disable_tx_clk;
+       }
++      request_bus_freq(BUS_FREQ_AUDIO);
++
+       if (sai->soc->flags & SAI_FLAG_PMQOS)
+               pm_qos_add_request(&sai->pm_qos_req,
+                               PM_QOS_CPU_DMA_LATENCY, 0);
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0066-MLK-16224-2-ASoC-dmaengine_pcm-add-fifo_num-to-snd_d.patch b/target/linux/layerscape/patches-5.4/801-audio-0066-MLK-16224-2-ASoC-dmaengine_pcm-add-fifo_num-to-snd_d.patch
new file mode 100644 (file)
index 0000000..6f4997f
--- /dev/null
@@ -0,0 +1,28 @@
+From fd343b5141e1128ab893f5370d2a05e4f09830b1 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Tue, 23 Jan 2018 13:27:10 +0800
+Subject: [PATCH] MLK-16224-2: ASoC: dmaengine_pcm: add fifo_num to
+ snd_dmaengine_dai_dma_data
+
+In order to support multi-fifo sdma script, the audio driver need to send
+the fifo number to dma driver through dma_slave_config, and the cpu_dai
+driver should config fifo_num for the audio platform driver, then platform
+driver can config fifo_num to dma.
+So add new variable fifo_num for struct snd_dmaengine_dai_dma_data.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+Reviewed-by: Robin Gong<yibin.gong@nxp.com>
+---
+ include/sound/dmaengine_pcm.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/include/sound/dmaengine_pcm.h
++++ b/include/sound/dmaengine_pcm.h
+@@ -76,6 +76,7 @@ struct snd_dmaengine_dai_dma_data {
+       const char *chan_name;
+       unsigned int fifo_size;
+       unsigned int flags;
++      unsigned int fifo_num;
+ };
+ void snd_dmaengine_pcm_set_config_from_dai_data(
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0067-Revert-MLK-17442-ASoC-fsl-fix-wrong-usage-of-filter_.patch b/target/linux/layerscape/patches-5.4/801-audio-0067-Revert-MLK-17442-ASoC-fsl-fix-wrong-usage-of-filter_.patch
new file mode 100644 (file)
index 0000000..d36101e
--- /dev/null
@@ -0,0 +1,24 @@
+From 912323e5d1290cbee651270f65de338663012c9b Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Mon, 30 Mar 2020 16:30:03 +0800
+Subject: [PATCH] Revert "MLK-17442: ASoC: fsl: fix wrong usage of filter_data
+ (part 1)"
+
+This reverts commit 8d4837f146cd14cf7041050ddec77b2a5c3f2f27.
+---
+ sound/soc/fsl/fsl_sai.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -1519,8 +1519,8 @@ static int fsl_sai_probe(struct platform
+                                  MCLK_DIR(index));
+       }
+-      sai->dma_params_rx.chan_name = "rx";
+-      sai->dma_params_tx.chan_name = "tx";
++      sai->dma_params_rx.filter_data = "rx";
++      sai->dma_params_tx.filter_data = "tx";
+       sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0;
+       sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0;
+       sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0068-Revert-ASoC-fsl-add-imx-pcm-dma-v2-platform-driver-p.patch b/target/linux/layerscape/patches-5.4/801-audio-0068-Revert-ASoC-fsl-add-imx-pcm-dma-v2-platform-driver-p.patch
new file mode 100644 (file)
index 0000000..1045b90
--- /dev/null
@@ -0,0 +1,31 @@
+From d8715f02b84c1a210b6fd84badc41eced6272424 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Mon, 30 Mar 2020 16:30:26 +0800
+Subject: [PATCH] Revert "ASoC: fsl: add imx-pcm-dma v2 platform driver (part
+ 2)"
+
+This reverts commit 5d816f1a5cac458a7fff9ecf896c85eb351a7352.
+---
+ sound/soc/fsl/fsl_sai.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -1519,8 +1519,6 @@ static int fsl_sai_probe(struct platform
+                                  MCLK_DIR(index));
+       }
+-      sai->dma_params_rx.filter_data = "rx";
+-      sai->dma_params_tx.filter_data = "tx";
+       sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0;
+       sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0;
+       sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
+@@ -1540,7 +1538,7 @@ static int fsl_sai_probe(struct platform
+               goto err_pm_disable;
+       if (sai->soc->imx)
+-              ret = imx_pcm_platform_register(&pdev->dev);
++              ret = imx_pcm_dma_init(pdev, IMX_SAI_DMABUF_SIZE);
+               if (ret)
+                       goto err_pm_disable;
+       } else {
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0069-MLK-21484-4-ASoC-fsl_sai-ensure-clk-not-in-use-prior.patch b/target/linux/layerscape/patches-5.4/801-audio-0069-MLK-21484-4-ASoC-fsl_sai-ensure-clk-not-in-use-prior.patch
new file mode 100644 (file)
index 0000000..87ecb07
--- /dev/null
@@ -0,0 +1,79 @@
+From 5c4835e943dd31265770e7ca3c03307d5c725db6 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Thu, 25 Apr 2019 15:03:56 +0300
+Subject: [PATCH] MLK-21484-4: ASoC: fsl_sai: ensure clk not in use prior
+ set_mclk_rate
+
+On recent kernels clks which are marked with CLK_SET_RATE_GATE are
+"protected" against further changes at clk_prepare time, including clk
+set_parent and set_rate. See commit 9461f7b33d11 ("clk: fix
+CLK_SET_RATE_GATE with clock rate protection"). The current fsl_sai
+implementation ensures the clock is not in use prior set_parent,
+extend this for set_rate also by moving if (sai->mclk_streams == 0)
+outside fsl_sai_set_mclk_rate(). Aside of this avoid changing rate and
+parent for BUS clk.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 30 +++++++++++++-----------------
+ 1 file changed, 13 insertions(+), 17 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -259,25 +259,19 @@ static int fsl_sai_set_mclk_rate(struct
+       if (pll) {
+               npll = (do_div(ratio, 8000) ? sai->pll11k_clk : sai->pll8k_clk);
+               if (!clk_is_match(pll, npll)) {
+-                      if (sai->mclk_streams == 0) {
+-                              ret = clk_set_parent(p, npll);
+-                              if (ret < 0)
+-                                      dev_warn(dai->dev,
+-                                              "failed to set parent %s: %d\n",
+-                                              __clk_get_name(npll), ret);
+-                      } else {
+-                              dev_err(dai->dev,
+-                                      "PLL %s is in use by a running stream.\n",
+-                                      __clk_get_name(pll));
+-                              return -EINVAL;
+-                      }
++                      ret = clk_set_parent(p, npll);
++                      if (ret < 0)
++                              dev_warn(dai->dev,
++                                       "failed to set parent %s: %d\n",
++                                       __clk_get_name(npll), ret);
+               }
+       }
+       ret = clk_set_rate(sai->mclk_clk[clk_id], freq);
+       if (ret < 0)
+               dev_err(dai->dev, "failed to set clock rate (%u): %d\n",
+-                              freq, ret);
++                      freq, ret);
++
+       return ret;
+ }
+@@ -298,7 +292,7 @@ static int fsl_sai_set_dai_sysclk(struct
+       if (dir == SND_SOC_CLOCK_IN)
+               return 0;
+-      if (freq > 0) {
++      if (freq > 0 && clk_id != FSL_SAI_CLK_BUS) {
+               if (clk_id < 0 || clk_id >= FSL_SAI_MCLK_MAX) {
+                       dev_err(cpu_dai->dev, "Unknown clock id: %d\n", clk_id);
+                       return -EINVAL;
+@@ -309,9 +303,11 @@ static int fsl_sai_set_dai_sysclk(struct
+                       return -EINVAL;
+               }
+-              ret = fsl_sai_set_mclk_rate(cpu_dai, clk_id, freq);
+-              if (ret < 0)
+-                      return ret;
++              if (sai->mclk_streams == 0) {
++                      ret = fsl_sai_set_mclk_rate(cpu_dai, clk_id, freq);
++                      if (ret < 0)
++                              return ret;
++              }
+       }
+       ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0070-MLK-21957-1-ASoC-fsl_sai-remove-reset-code-from-dai_.patch b/target/linux/layerscape/patches-5.4/801-audio-0070-MLK-21957-1-ASoC-fsl_sai-remove-reset-code-from-dai_.patch
new file mode 100644 (file)
index 0000000..e4c7fa0
--- /dev/null
@@ -0,0 +1,30 @@
+From 9bd468920e23649e1244c5d243215c04ff3e72e6 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Tue, 18 Jun 2019 16:16:19 +0300
+Subject: [PATCH] MLK-21957-1: ASoC: fsl_sai: remove reset code from dai_probe
+
+SAI software reset is done in runtime resume,
+there is no need to do it in fsl_sai_dai_probe.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -991,13 +991,6 @@ static int fsl_sai_dai_probe(struct snd_
+       struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
+       unsigned char offset = sai->soc->reg_offset;
+-      /* Software Reset for both Tx and Rx */
+-      regmap_write(sai->regmap, FSL_SAI_TCSR(offset), FSL_SAI_CSR_SR);
+-      regmap_write(sai->regmap, FSL_SAI_RCSR(offset), FSL_SAI_CSR_SR);
+-      /* Clear SR bit to finish the reset */
+-      regmap_write(sai->regmap, FSL_SAI_TCSR(offset), 0);
+-      regmap_write(sai->regmap, FSL_SAI_RCSR(offset), 0);
+-
+       regmap_update_bits(sai->regmap, FSL_SAI_TCR1(offset),
+                               sai->soc->fifo_depth - 1,
+                               sai->soc->fifo_depth - FSL_SAI_MAXBURST_TX);
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0071-MLK-21957-2-ASoC-fsl_sai-read-SAI-version-and-params.patch b/target/linux/layerscape/patches-5.4/801-audio-0071-MLK-21957-2-ASoC-fsl_sai-read-SAI-version-and-params.patch
new file mode 100644 (file)
index 0000000..005f4b5
--- /dev/null
@@ -0,0 +1,92 @@
+From 34a1cd97a2ef6f68a12ff2f2fd813548e867f72f Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Thu, 20 Jun 2019 13:25:15 +0300
+Subject: [PATCH] MLK-21957-2: ASoC: fsl_sai: read SAI version and params in
+ probe
+
+Read SAI IP version and parameters in probe function.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 30 ++++++++++++++++++++----------
+ 1 file changed, 20 insertions(+), 10 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -465,11 +465,12 @@ static int fsl_sai_set_dai_fmt(struct sn
+       return ret;
+ }
+-static int fsl_sai_check_ver(struct snd_soc_dai *cpu_dai)
++static int fsl_sai_check_ver(struct device *dev)
+ {
+-      struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
++      struct fsl_sai *sai = dev_get_drvdata(dev);
+       unsigned char offset = sai->soc->reg_offset;
+       unsigned int val;
++      int ret;
+       if (FSL_SAI_TCSR(offset) == FSL_SAI_VERID)
+               return 0;
+@@ -477,16 +478,21 @@ static int fsl_sai_check_ver(struct snd_
+       if (sai->verid.loaded)
+               return 0;
+-      sai->verid.loaded = true;
+-      regmap_read(sai->regmap, FSL_SAI_VERID, &val);
+-      dev_dbg(cpu_dai->dev, "VERID: 0x%016X\n", val);
++      ret = regmap_read(sai->regmap, FSL_SAI_VERID, &val);
++      if (ret < 0)
++              return ret;
++
++      dev_dbg(dev, "VERID: 0x%016X\n", val);
+       sai->verid.id = (val & FSL_SAI_VER_ID_MASK) >> FSL_SAI_VER_ID_SHIFT;
+       sai->verid.extfifo_en = (val & FSL_SAI_VER_EFIFO_EN);
+       sai->verid.timestamp_en = (val & FSL_SAI_VER_TSTMP_EN);
+-      regmap_read(sai->regmap, FSL_SAI_PARAM, &val);
+-      dev_dbg(cpu_dai->dev, "PARAM: 0x%016X\n", val);
++      ret = regmap_read(sai->regmap, FSL_SAI_PARAM, &val);
++      if (ret < 0)
++              return ret;
++
++      dev_dbg(dev, "PARAM: 0x%016X\n", val);
+       /* max slots per frame, power of 2 */
+       sai->param.spf = 1 <<
+@@ -499,11 +505,13 @@ static int fsl_sai_check_ver(struct snd_
+       /* number of datalines implemented */
+       sai->param.dln = val & FSL_SAI_PAR_DLN_MASK;
+-      dev_dbg(cpu_dai->dev,
++      dev_dbg(dev,
+               "Version: 0x%08X, SPF: %u, WPF: %u, DLN: %u\n",
+               sai->verid.id, sai->param.spf, sai->param.wpf, sai->param.dln
+       );
++      sai->verid.loaded = true;
++
+       return 0;
+ }
+@@ -521,8 +529,6 @@ static int fsl_sai_set_bclk(struct snd_s
+       if (sai->slave_mode[tx])
+               return 0;
+-      fsl_sai_check_ver(dai);
+-
+       for (id = 0; id < FSL_SAI_MCLK_MAX; id++) {
+               clk_rate = clk_get_rate(sai->mclk_clk[id]);
+               if (!clk_rate)
+@@ -1517,6 +1523,10 @@ static int fsl_sai_probe(struct platform
+       platform_set_drvdata(pdev, sai);
++      ret = fsl_sai_check_ver(&pdev->dev);
++      if (ret < 0)
++              dev_warn(&pdev->dev, "Error reading SAI version: %d\n", ret);
++
+       pm_runtime_enable(&pdev->dev);
+       regcache_cache_only(sai->regmap, true);
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0072-MLK-22522-ASoC-fsl_sai-fix-stack-out-of-bounds-KASAN.patch b/target/linux/layerscape/patches-5.4/801-audio-0072-MLK-22522-ASoC-fsl_sai-fix-stack-out-of-bounds-KASAN.patch
new file mode 100644 (file)
index 0000000..2fc52b8
--- /dev/null
@@ -0,0 +1,78 @@
+From 5d4e9c8371a2343c66123078dbde15438450b9a4 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Thu, 29 Aug 2019 13:17:33 +0300
+Subject: [PATCH] MLK-22522: ASoC: fsl_sai: fix stack-out-of-bounds KASAN
+ complain
+
+Fix the following KASAN reported issue:
+==================================================================
+[   11.580278] BUG: KASAN: stack-out-of-bounds in find_next_bit+0x3c/0xc0
+[   11.586815] Read of size 8 at addr ffffffc8c8d4f760 by task swapper/0/1
+[   11.593440]
+[   11.594943] CPU: 4 PID: 1 Comm: swapper/0 Tainted: G W 4.19.35-05042-g. #157
+[   11.604259] Hardware name: Freescale i.MX8QM MEK (DT)
+[   11.609323] Call trace:
+[   11.611785]  dump_backtrace+0x0/0x230
+[   11.615458]  show_stack+0x14/0x20
+[   11.618787]  dump_stack+0xbc/0xf4
+[   11.622118]  print_address_description+0x60/0x270
+[   11.626830]  kasan_report+0x230/0x360
+[   11.630505]  __asan_load8+0x84/0xa8
+[   11.634005]  find_next_bit+0x3c/0xc0
+[   11.637595]  fsl_sai_calc_dl_off+0x1c/0x50
+[   11.641703]  fsl_sai_read_dlcfg+0x184/0x368
+[   11.645898]  fsl_sai_probe+0x3ec/0xb48
+[   11.649663]  platform_drv_probe+0x70/0xd8
+[   11.653683]  really_probe+0x24c/0x370
+[   11.657358]  driver_probe_device+0x70/0x138
+[   11.661554]  __driver_attach+0x124/0x128
+[   11.665489]  bus_for_each_dev+0xe8/0x158
+[   11.669425]  driver_attach+0x30/0x40
+[   11.673012]  bus_add_driver+0x290/0x308
+[   11.676861]  driver_register+0xbc/0x1d0
+[   11.680711]  __platform_driver_register+0x7c/0x88
+[   11.685431]  fsl_sai_driver_init+0x18/0x20
+[   11.689537]  do_one_initcall+0xe8/0x5a8
+[   11.693387]  kernel_init_freeable+0x6b0/0x760
+[   11.697759]  kernel_init+0x10/0x120
+[   11.701255]  ret_from_fork+0x10/0x18
+....
+==================================================================
+[   11.800186] Disabling lock debugging due to kernel taint
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -1259,12 +1259,12 @@ static const struct of_device_id fsl_sai
+ };
+ MODULE_DEVICE_TABLE(of, fsl_sai_ids);
+-static unsigned int fsl_sai_calc_dl_off(unsigned int* dl_mask)
++static unsigned int fsl_sai_calc_dl_off(unsigned long dl_mask)
+ {
+       int fbidx, nbidx, offset;
+-      fbidx = find_first_bit((const unsigned long *)dl_mask, 8);
+-      nbidx = find_next_bit((const unsigned long *)dl_mask, 8, fbidx+1);
++      fbidx = find_first_bit(&dl_mask, 8);
++      nbidx = find_next_bit(&dl_mask, 8, fbidx + 1);
+       offset = nbidx - fbidx - 1;
+       return (offset < 0 || offset >= 7 ? 0 : offset);
+@@ -1321,9 +1321,9 @@ static int fsl_sai_read_dlcfg(struct pla
+               cfg[i].pins = pins;
+               cfg[i].mask[0] = rx;
+-              cfg[i].offset[0] = fsl_sai_calc_dl_off(&rx);
++              cfg[i].offset[0] = fsl_sai_calc_dl_off(rx);
+               cfg[i].mask[1] = tx;
+-              cfg[i].offset[1] = fsl_sai_calc_dl_off(&tx);
++              cfg[i].offset[1] = fsl_sai_calc_dl_off(tx);
+       }
+       *rcfg = cfg;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0073-MLK-21957-3-ASoC-fsl_sai-add-bitcount-and-timestamp-.patch b/target/linux/layerscape/patches-5.4/801-audio-0073-MLK-21957-3-ASoC-fsl_sai-add-bitcount-and-timestamp-.patch
new file mode 100644 (file)
index 0000000..0bee583
--- /dev/null
@@ -0,0 +1,164 @@
+From 599235bd9d22c8cad90b0a7621b46d70cca94d31 Mon Sep 17 00:00:00 2001
+From: Viorel Suman <viorel.suman@nxp.com>
+Date: Wed, 5 Jun 2019 13:46:32 +0000
+Subject: [PATCH] MLK-21957-3: ASoC: fsl_sai: add bitcount and timestamp
+ controls
+
+Bitcount and timestamp support added in SAI IP recently.
+Add the related controls in SAI driver.
+
+Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ sound/soc/fsl/fsl_sai.h |  6 +++
+ 2 files changed, 102 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -992,6 +992,90 @@ static const struct snd_soc_dai_ops fsl_
+       .shutdown       = fsl_sai_shutdown,
+ };
++static const char
++      *en_sl[] = { "Disabled", "Enabled", },
++      *inc_sl[] = { "On enabled and bitcount increment", "On enabled", };
++
++static const struct soc_enum tstmp_enum[] = {
++SOC_ENUM_SINGLE(FSL_SAI_TTCTL, 0, ARRAY_SIZE(en_sl), en_sl),
++SOC_ENUM_SINGLE(FSL_SAI_RTCTL, 0, ARRAY_SIZE(en_sl), en_sl),
++SOC_ENUM_SINGLE(FSL_SAI_TTCTL, 1, ARRAY_SIZE(inc_sl), inc_sl),
++SOC_ENUM_SINGLE(FSL_SAI_RTCTL, 1, ARRAY_SIZE(inc_sl), inc_sl),
++};
++
++int fsl_sai_get_reg(struct snd_kcontrol *kcontrol,
++                  struct snd_ctl_elem_value *ucontrol)
++{
++      struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
++      struct soc_mreg_control *mc =
++              (struct soc_mreg_control *)kcontrol->private_value;
++      bool pm_active = pm_runtime_active(component->dev);
++      unsigned int regval;
++      int ret;
++
++      if (pm_active)
++              regcache_cache_bypass(component->regmap, true);
++
++      ret = snd_soc_component_read(component, mc->regbase, &regval);
++
++      if (pm_active)
++              regcache_cache_bypass(component->regmap, false);
++
++      if (ret < 0)
++              return ret;
++
++      ucontrol->value.integer.value[0] = regval;
++
++      return 0;
++}
++
++#define SOC_SINGLE_REG_RO(xname, xreg) \
++{     .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \
++      .access = SNDRV_CTL_ELEM_ACCESS_READ | \
++                SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
++      .info = snd_soc_info_xr_sx, .get = fsl_sai_get_reg, \
++      .private_value = (unsigned long)&(struct soc_mreg_control) \
++              { .regbase = xreg, .regcount = 1, .nbits = 32, \
++                .invert = 0, .min = 0, .max = 0xffffffff, } }
++
++static const struct snd_kcontrol_new fsl_sai_pb_ctrls[] = {
++      SOC_ENUM("Playback Timestamp Control", tstmp_enum[0]),
++      SOC_ENUM("Playback Timestamp Increment", tstmp_enum[2]),
++      SOC_SINGLE("Playback Timestamp Reset", FSL_SAI_TTCTL, 8, 1, 0),
++      SOC_SINGLE("Playback Bit Counter Reset", FSL_SAI_TTCTL, 9, 1, 0),
++      SOC_SINGLE_REG_RO("Playback Timestamp Counter", FSL_SAI_TTCTN),
++      SOC_SINGLE_REG_RO("Playback Bit Counter", FSL_SAI_TBCTN),
++      SOC_SINGLE_REG_RO("Playback Latched Timestamp Counter", FSL_SAI_TTCAP),
++};
++
++static const struct snd_kcontrol_new fsl_sai_cp_ctrls[] = {
++      SOC_ENUM("Capture Timestamp Control", tstmp_enum[1]),
++      SOC_ENUM("Capture Timestamp Increment", tstmp_enum[3]),
++      SOC_SINGLE("Capture Timestamp Reset", FSL_SAI_RTCTL, 8, 1, 0),
++      SOC_SINGLE("Capture Bit Counter Reset", FSL_SAI_RTCTL, 9, 1, 0),
++      SOC_SINGLE_REG_RO("Capture Timestamp Counter", FSL_SAI_RTCTN),
++      SOC_SINGLE_REG_RO("Capture Bit Counter", FSL_SAI_RBCTN),
++      SOC_SINGLE_REG_RO("Capture Latched Timestamp Counter", FSL_SAI_RTCAP),
++};
++
++static int fsl_sai_pcm_new(struct snd_soc_pcm_runtime *rtd,
++                         struct snd_soc_dai *dai)
++{
++      struct fsl_sai *sai = dev_get_drvdata(dai->dev);
++      struct snd_pcm *pcm = rtd->pcm;
++      bool ts_enabled = sai->verid.timestamp_en;
++      struct snd_soc_component *comp = dai->component;
++
++      if (ts_enabled && pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
++              snd_soc_add_component_controls(comp, fsl_sai_pb_ctrls,
++                                             ARRAY_SIZE(fsl_sai_pb_ctrls));
++
++      if (ts_enabled && pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream)
++              snd_soc_add_component_controls(comp, fsl_sai_cp_ctrls,
++                                             ARRAY_SIZE(fsl_sai_cp_ctrls));
++      return 0;
++}
++
+ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
+ {
+       struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
+@@ -1030,6 +1114,7 @@ static int fsl_sai_dai_resume(struct snd
+ }
+ static struct snd_soc_dai_driver fsl_sai_dai = {
++      .pcm_new = fsl_sai_pcm_new,
+       .probe = fsl_sai_dai_probe,
+       .playback = {
+               .stream_name = "CPU-Playback",
+@@ -1054,7 +1139,7 @@ static struct snd_soc_dai_driver fsl_sai
+ };
+ static const struct snd_soc_component_driver fsl_component = {
+-      .name           = "fsl-sai",
++      .name   = "fsl-sai",
+ };
+ static struct reg_default fsl_sai_v2_reg_defaults[] = {
+@@ -1141,6 +1226,14 @@ static bool fsl_sai_readable_reg(struct
+       case FSL_SAI_MDIV:
+       case FSL_SAI_VERID:
+       case FSL_SAI_PARAM:
++      case FSL_SAI_TTCTN:
++      case FSL_SAI_RTCTN:
++      case FSL_SAI_TTCTL:
++      case FSL_SAI_TBCTN:
++      case FSL_SAI_TTCAP:
++      case FSL_SAI_RTCTL:
++      case FSL_SAI_RBCTN:
++      case FSL_SAI_RTCAP:
+               return true;
+       default:
+               return false;
+@@ -1214,6 +1307,8 @@ static bool fsl_sai_writeable_reg(struct
+       case FSL_SAI_RMR:
+       case FSL_SAI_MCTL:
+       case FSL_SAI_MDIV:
++      case FSL_SAI_TTCTL:
++      case FSL_SAI_RTCTL:
+               return true;
+       default:
+               return false;
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -210,6 +210,12 @@
+ #define SAI_FLAG_PMQOS   BIT(0)
++/* SAI timestamp and bitcounter */
++#define FSL_SAI_xTCTL_TSEN BIT(0)
++#define FSL_SAI_xTCTL_TSINC BIT(1)
++#define FSL_SAI_xTCTL_RTSC BIT(8)
++#define FSL_SAI_xTCTL_RBC BIT(9)
++
+ struct fsl_sai_soc_data {
+       unsigned int fifo_depth;
+       unsigned int fifos;
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0074-ASoC-fsl_sai-fix-build-issue-of-incomplete-parenthes.patch b/target/linux/layerscape/patches-5.4/801-audio-0074-ASoC-fsl_sai-fix-build-issue-of-incomplete-parenthes.patch
new file mode 100644 (file)
index 0000000..a511504
--- /dev/null
@@ -0,0 +1,24 @@
+From 0524e0b15966f8cbb010d430ec3fdcf9faf876f4 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Wed, 1 Apr 2020 15:49:50 +0800
+Subject: [PATCH] ASoC: fsl_sai: fix build issue of incomplete parentheses
+
+Fix build issue of incomplete parentheses.
+
+Fixes: c516c26 (MLK-13574-2: ASoC: fsl_sai: refine driver for ip upgrade)
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -1631,7 +1631,7 @@ static int fsl_sai_probe(struct platform
+       if (ret)
+               goto err_pm_disable;
+-      if (sai->soc->imx)
++      if (sai->soc->imx) {
+               ret = imx_pcm_dma_init(pdev, IMX_SAI_DMABUF_SIZE);
+               if (ret)
+                       goto err_pm_disable;
diff --git a/target/linux/layerscape/patches-5.4/802-can-0001-imx-busfreq-Add-API-header-file.patch b/target/linux/layerscape/patches-5.4/802-can-0001-imx-busfreq-Add-API-header-file.patch
new file mode 100644 (file)
index 0000000..e7a31c5
--- /dev/null
@@ -0,0 +1,95 @@
+From c8055614385c90accdea4e7a046c5560bccc84cf Mon Sep 17 00:00:00 2001
+From: Leonard Crestez <leonard.crestez@nxp.com>
+Date: Mon, 13 May 2019 15:06:37 +0300
+Subject: [PATCH] imx busfreq: Add API header file
+
+Add sufficient enough definitions so that drivers which call
+request_bus_freq and release_bus_freq can compile even if
+CONFIG_HAVE_IMX_BUSFREQ is missing.
+
+Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
+---
+ include/linux/busfreq-imx.h | 77 +++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 77 insertions(+)
+ create mode 100644 include/linux/busfreq-imx.h
+
+--- /dev/null
++++ b/include/linux/busfreq-imx.h
+@@ -0,0 +1,77 @@
++/*
++ * Copyright 2012-2016 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ * 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.
++ */
++
++#ifndef __ASM_ARCH_MXC_BUSFREQ_H__
++#define __ASM_ARCH_MXC_BUSFREQ_H__
++
++#include <linux/notifier.h>
++#include <linux/regulator/consumer.h>
++
++/*
++ * This enumerates busfreq low power mode entry and exit.
++ */
++enum busfreq_event {
++      LOW_BUSFREQ_ENTER,
++      LOW_BUSFREQ_EXIT,
++};
++
++/*
++ * This enumerates the system bus and ddr frequencies in various modes.
++ * BUS_FREQ_HIGH - DDR @ 528MHz, AHB @ 132MHz.
++ * BUS_FREQ_MED - DDR @ 400MHz, AHB @ 132MHz
++ * BUS_FREQ_AUDIO - DDR @ 50MHz/100MHz, AHB @ 24MHz.
++ * BUS_FREQ_LOW  - DDR @ 24MHz, AHB @ 24MHz.
++ * BUS_FREQ_ULTRA_LOW - DDR @ 1MHz, AHB - 3MHz.
++ *
++ * Drivers need to request/release the bus/ddr frequencies based on
++ * their performance requirements. Drivers cannot request/release
++ * BUS_FREQ_ULTRA_LOW mode as this mode is automatically entered from
++ * either BUS_FREQ_AUDIO or BUS_FREQ_LOW
++ * modes.
++ */
++enum bus_freq_mode {
++      BUS_FREQ_HIGH,
++      BUS_FREQ_MED,
++      BUS_FREQ_AUDIO,
++      BUS_FREQ_LOW,
++      BUS_FREQ_ULTRA_LOW,
++};
++
++#if defined(CONFIG_HAVE_IMX_BUSFREQ) && !defined(CONFIG_ARM64)
++extern struct regulator *arm_reg;
++extern struct regulator *soc_reg;
++void request_bus_freq(enum bus_freq_mode mode);
++void release_bus_freq(enum bus_freq_mode mode);
++int register_busfreq_notifier(struct notifier_block *nb);
++int unregister_busfreq_notifier(struct notifier_block *nb);
++int get_bus_freq_mode(void);
++#elif defined(CONFIG_HAVE_IMX_BUSFREQ)
++void request_bus_freq(enum bus_freq_mode mode);
++void release_bus_freq(enum bus_freq_mode mode);
++int get_bus_freq_mode(void);
++#else
++static inline void request_bus_freq(enum bus_freq_mode mode)
++{
++}
++static inline void release_bus_freq(enum bus_freq_mode mode)
++{
++}
++static inline int register_busfreq_notifier(struct notifier_block *nb)
++{
++      return 0;
++}
++static inline int unregister_busfreq_notifier(struct notifier_block *nb)
++{
++      return 0;
++}
++static inline int get_bus_freq_mode(void)
++{
++      return BUS_FREQ_HIGH;
++}
++#endif
++#endif
diff --git a/target/linux/layerscape/patches-5.4/802-can-0002-can-rx-offload-fix-long-lines.patch b/target/linux/layerscape/patches-5.4/802-can-0002-can-rx-offload-fix-long-lines.patch
new file mode 100644 (file)
index 0000000..88692a2
--- /dev/null
@@ -0,0 +1,120 @@
+From 47058e3bd5c13b9db796a81083c049cb1d0b7883 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Mon, 7 Oct 2019 09:59:49 +0200
+Subject: [PATCH] can: rx-offload: fix long lines
+
+This patch fixes the checkpatch warnings about too long lines.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/rx-offload.c | 39 ++++++++++++++++++++++++++-------------
+ 1 file changed, 26 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/can/rx-offload.c
++++ b/drivers/net/can/rx-offload.c
+@@ -1,7 +1,8 @@
+ // SPDX-License-Identifier: GPL-2.0-only
+-/*
+- * Copyright (c) 2014 David Jander, Protonic Holland
+- * Copyright (C) 2014-2017 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de>
++/* Copyright (c) 2014      Protonic Holland,
++ *                         David Jander
++ * Copyright (C) 2014-2017 Pengutronix,
++ *                         Marc Kleine-Budde <kernel@pengutronix.de>
+  */
+ #include <linux/can/dev.h>
+@@ -11,14 +12,17 @@ struct can_rx_offload_cb {
+       u32 timestamp;
+ };
+-static inline struct can_rx_offload_cb *can_rx_offload_get_cb(struct sk_buff *skb)
++static inline struct can_rx_offload_cb *
++can_rx_offload_get_cb(struct sk_buff *skb)
+ {
+       BUILD_BUG_ON(sizeof(struct can_rx_offload_cb) > sizeof(skb->cb));
+       return (struct can_rx_offload_cb *)skb->cb;
+ }
+-static inline bool can_rx_offload_le(struct can_rx_offload *offload, unsigned int a, unsigned int b)
++static inline bool
++can_rx_offload_le(struct can_rx_offload *offload,
++                unsigned int a, unsigned int b)
+ {
+       if (offload->inc)
+               return a <= b;
+@@ -26,7 +30,8 @@ static inline bool can_rx_offload_le(str
+               return a >= b;
+ }
+-static inline unsigned int can_rx_offload_inc(struct can_rx_offload *offload, unsigned int *val)
++static inline unsigned int
++can_rx_offload_inc(struct can_rx_offload *offload, unsigned int *val)
+ {
+       if (offload->inc)
+               return (*val)++;
+@@ -36,7 +41,9 @@ static inline unsigned int can_rx_offloa
+ static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota)
+ {
+-      struct can_rx_offload *offload = container_of(napi, struct can_rx_offload, napi);
++      struct can_rx_offload *offload = container_of(napi,
++                                                    struct can_rx_offload,
++                                                    napi);
+       struct net_device *dev = offload->dev;
+       struct net_device_stats *stats = &dev->stats;
+       struct sk_buff *skb;
+@@ -65,8 +72,9 @@ static int can_rx_offload_napi_poll(stru
+       return work_done;
+ }
+-static inline void __skb_queue_add_sort(struct sk_buff_head *head, struct sk_buff *new,
+-                                      int (*compare)(struct sk_buff *a, struct sk_buff *b))
++static inline void
++__skb_queue_add_sort(struct sk_buff_head *head, struct sk_buff *new,
++                   int (*compare)(struct sk_buff *a, struct sk_buff *b))
+ {
+       struct sk_buff *pos, *insert = NULL;
+@@ -199,7 +207,8 @@ can_rx_offload_offload_one(struct can_rx
+       return skb;
+ }
+-int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload, u64 pending)
++int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload,
++                                       u64 pending)
+ {
+       struct sk_buff_head skb_queue;
+       unsigned int i;
+@@ -328,7 +337,9 @@ int can_rx_offload_queue_tail(struct can
+ }
+ EXPORT_SYMBOL_GPL(can_rx_offload_queue_tail);
+-static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offload *offload, unsigned int weight)
++static int can_rx_offload_init_queue(struct net_device *dev,
++                                   struct can_rx_offload *offload,
++                                   unsigned int weight)
+ {
+       offload->dev = dev;
+@@ -346,7 +357,8 @@ static int can_rx_offload_init_queue(str
+       return 0;
+ }
+-int can_rx_offload_add_timestamp(struct net_device *dev, struct can_rx_offload *offload)
++int can_rx_offload_add_timestamp(struct net_device *dev,
++                               struct can_rx_offload *offload)
+ {
+       unsigned int weight;
+@@ -366,7 +378,8 @@ int can_rx_offload_add_timestamp(struct
+ }
+ EXPORT_SYMBOL_GPL(can_rx_offload_add_timestamp);
+-int can_rx_offload_add_fifo(struct net_device *dev, struct can_rx_offload *offload, unsigned int weight)
++int can_rx_offload_add_fifo(struct net_device *dev,
++                          struct can_rx_offload *offload, unsigned int weight)
+ {
+       if (!offload->mailbox_read)
+               return -EINVAL;
diff --git a/target/linux/layerscape/patches-5.4/802-can-0003-can-rx-offload-can_rx_offload_compare-fix-typo.patch b/target/linux/layerscape/patches-5.4/802-can-0003-can-rx-offload-can_rx_offload_compare-fix-typo.patch
new file mode 100644 (file)
index 0000000..26d4a90
--- /dev/null
@@ -0,0 +1,23 @@
+From e1a24fd01ca938096aebe397a547aa2409368ab5 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Mon, 7 Oct 2019 10:00:25 +0200
+Subject: [PATCH] can: rx-offload: can_rx_offload_compare(): fix typo
+
+This patch fixes a typo found by checkpatch.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/rx-offload.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/can/rx-offload.c
++++ b/drivers/net/can/rx-offload.c
+@@ -109,7 +109,7 @@ static int can_rx_offload_compare(struct
+       cb_a = can_rx_offload_get_cb(a);
+       cb_b = can_rx_offload_get_cb(b);
+-      /* Substract two u32 and return result as int, to keep
++      /* Subtract two u32 and return result as int, to keep
+        * difference steady around the u32 overflow.
+        */
+       return cb_b->timestamp - cb_a->timestamp;
diff --git a/target/linux/layerscape/patches-5.4/802-can-0004-can-rx-offload-can_rx_offload_irq_offload_timestamp-.patch b/target/linux/layerscape/patches-5.4/802-can-0004-can-rx-offload-can_rx_offload_irq_offload_timestamp-.patch
new file mode 100644 (file)
index 0000000..77cc9f8
--- /dev/null
@@ -0,0 +1,26 @@
+From b95cae85e913fb13f4c8f1241be85725e4dffeed Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Mon, 7 Oct 2019 10:00:52 +0200
+Subject: [PATCH] can: rx-offload: can_rx_offload_irq_offload_timestamp():
+ don't use assignment in if condition
+
+This patch moves the assignment of queue_len out of the if condition.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/rx-offload.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/can/rx-offload.c
++++ b/drivers/net/can/rx-offload.c
+@@ -238,8 +238,8 @@ int can_rx_offload_irq_offload_timestamp
+               skb_queue_splice_tail(&skb_queue, &offload->skb_queue);
+               spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
+-              if ((queue_len = skb_queue_len(&offload->skb_queue)) >
+-                  (offload->skb_queue_len_max / 8))
++              queue_len = skb_queue_len(&offload->skb_queue);
++              if (queue_len > offload->skb_queue_len_max / 8)
+                       netdev_dbg(offload->dev, "%s: queue_len=%d\n",
+                                  __func__, queue_len);
diff --git a/target/linux/layerscape/patches-5.4/802-can-0005-can-rx-offload-can_rx_offload_reset-remove-no-op-fun.patch b/target/linux/layerscape/patches-5.4/802-can-0005-can-rx-offload-can_rx_offload_reset-remove-no-op-fun.patch
new file mode 100644 (file)
index 0000000..45a20c4
--- /dev/null
@@ -0,0 +1,52 @@
+From 88b21e30646ba263df647469c3af8c09e43a99d6 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Mon, 7 Oct 2019 13:36:58 +0200
+Subject: [PATCH] can: rx-offload: can_rx_offload_reset(): remove no-op
+ function
+
+This patch removes the function can_rx_offload_reset(), as it does
+nothing. If we ever need this function, add it back again.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/rx-offload.c   | 7 -------
+ include/linux/can/rx-offload.h | 1 -
+ 2 files changed, 8 deletions(-)
+
+--- a/drivers/net/can/rx-offload.c
++++ b/drivers/net/can/rx-offload.c
+@@ -348,7 +348,6 @@ static int can_rx_offload_init_queue(str
+       offload->skb_queue_len_max *= 4;
+       skb_queue_head_init(&offload->skb_queue);
+-      can_rx_offload_reset(offload);
+       netif_napi_add(dev, &offload->napi, can_rx_offload_napi_poll, weight);
+       dev_dbg(dev->dev.parent, "%s: skb_queue_len_max=%d\n",
+@@ -390,7 +389,6 @@ EXPORT_SYMBOL_GPL(can_rx_offload_add_fif
+ void can_rx_offload_enable(struct can_rx_offload *offload)
+ {
+-      can_rx_offload_reset(offload);
+       napi_enable(&offload->napi);
+ }
+ EXPORT_SYMBOL_GPL(can_rx_offload_enable);
+@@ -401,8 +399,3 @@ void can_rx_offload_del(struct can_rx_of
+       skb_queue_purge(&offload->skb_queue);
+ }
+ EXPORT_SYMBOL_GPL(can_rx_offload_del);
+-
+-void can_rx_offload_reset(struct can_rx_offload *offload)
+-{
+-}
+-EXPORT_SYMBOL_GPL(can_rx_offload_reset);
+--- a/include/linux/can/rx-offload.h
++++ b/include/linux/can/rx-offload.h
+@@ -44,7 +44,6 @@ unsigned int can_rx_offload_get_echo_skb
+                                        unsigned int idx, u32 timestamp);
+ int can_rx_offload_queue_tail(struct can_rx_offload *offload,
+                             struct sk_buff *skb);
+-void can_rx_offload_reset(struct can_rx_offload *offload);
+ void can_rx_offload_del(struct can_rx_offload *offload);
+ void can_rx_offload_enable(struct can_rx_offload *offload);
diff --git a/target/linux/layerscape/patches-5.4/802-can-0006-can-rx-offload-Prepare-for-CAN-FD-support.patch b/target/linux/layerscape/patches-5.4/802-can-0006-can-rx-offload-Prepare-for-CAN-FD-support.patch
new file mode 100644 (file)
index 0000000..30b9e4b
--- /dev/null
@@ -0,0 +1,206 @@
+From 42abc4a8a97a87734c759c02c5ba255ed5124a2c Mon Sep 17 00:00:00 2001
+From: Joakim Zhang <qiangqing.zhang@nxp.com>
+Date: Fri, 12 Jul 2019 08:02:38 +0000
+Subject: [PATCH] can: rx-offload: Prepare for CAN FD support
+
+The skbs for classic CAN and CAN FD frames are allocated with seperate
+functions: alloc_can_skb() and alloc_canfd_skb().
+
+In order to support CAN FD frames via the rx-offload helper, the driver
+itself has to allocate the skb (depending whether it received a classic
+CAN or CAN FD frame), as the rx-offload helper cannot know which kind of
+CAN frame the driver has received.
+
+This patch moves the allocation of the skb into the struct
+can_rx_offload::mailbox_read callbacks of the the flexcan and ti_hecc
+driver and adjusts the rx-offload helper accordingly.
+
+Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c      | 27 +++++++++++-----
+ drivers/net/can/rx-offload.c   | 70 ++++++++++--------------------------------
+ include/linux/can/rx-offload.h |  6 ++--
+ 3 files changed, 40 insertions(+), 63 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -784,16 +784,23 @@ static inline struct flexcan_priv *rx_of
+       return container_of(offload, struct flexcan_priv, offload);
+ }
+-static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
+-                                       struct can_frame *cf,
+-                                       u32 *timestamp, unsigned int n)
++static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload,
++                                          unsigned int n, u32 *timestamp,
++                                          bool drop)
+ {
+       struct flexcan_priv *priv = rx_offload_to_priv(offload);
+       struct flexcan_regs __iomem *regs = priv->regs;
+       struct flexcan_mb __iomem *mb;
++      struct sk_buff *skb;
++      struct can_frame *cf;
+       u32 reg_ctrl, reg_id, reg_iflag1;
+       int i;
++      if (unlikely(drop)) {
++              skb = ERR_PTR(-ENOBUFS);
++              goto mark_as_read;
++      }
++
+       mb = flexcan_get_mb(priv, n);
+       if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
+@@ -807,7 +814,7 @@ static unsigned int flexcan_mailbox_read
+               code = reg_ctrl & FLEXCAN_MB_CODE_MASK;
+               if ((code != FLEXCAN_MB_CODE_RX_FULL) &&
+                   (code != FLEXCAN_MB_CODE_RX_OVERRUN))
+-                      return 0;
++                      return NULL;
+               if (code == FLEXCAN_MB_CODE_RX_OVERRUN) {
+                       /* This MB was overrun, we lost data */
+@@ -817,11 +824,17 @@ static unsigned int flexcan_mailbox_read
+       } else {
+               reg_iflag1 = priv->read(&regs->iflag1);
+               if (!(reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE))
+-                      return 0;
++                      return NULL;
+               reg_ctrl = priv->read(&mb->can_ctrl);
+       }
++      skb = alloc_can_skb(offload->dev, &cf);
++      if (!skb) {
++              skb = ERR_PTR(-ENOMEM);
++              goto mark_as_read;
++      }
++
+       /* increase timstamp to full 32 bit */
+       *timestamp = reg_ctrl << 16;
+@@ -840,7 +853,7 @@ static unsigned int flexcan_mailbox_read
+               *(__be32 *)(cf->data + i) = data;
+       }
+-      /* mark as read */
++ mark_as_read:
+       if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
+               /* Clear IRQ */
+               if (n < 32)
+@@ -857,7 +870,7 @@ static unsigned int flexcan_mailbox_read
+        */
+       priv->read(&regs->timer);
+-      return 1;
++      return skb;
+ }
+--- a/drivers/net/can/rx-offload.c
++++ b/drivers/net/can/rx-offload.c
+@@ -139,71 +139,35 @@ static int can_rx_offload_compare(struct
+ static struct sk_buff *
+ can_rx_offload_offload_one(struct can_rx_offload *offload, unsigned int n)
+ {
+-      struct sk_buff *skb = NULL, *skb_error = NULL;
++      struct sk_buff *skb;
+       struct can_rx_offload_cb *cb;
+-      struct can_frame *cf;
+-      int ret;
++      bool drop = false;
++      u32 timestamp;
+-      if (likely(skb_queue_len(&offload->skb_queue) <
+-                 offload->skb_queue_len_max)) {
+-              skb = alloc_can_skb(offload->dev, &cf);
+-              if (unlikely(!skb))
+-                      skb_error = ERR_PTR(-ENOMEM);   /* skb alloc failed */
+-      } else {
+-              skb_error = ERR_PTR(-ENOBUFS);          /* skb_queue is full */
+-      }
+-
+-      /* If queue is full or skb not available, drop by reading into
+-       * overflow buffer.
+-       */
+-      if (unlikely(skb_error)) {
+-              struct can_frame cf_overflow;
+-              u32 timestamp;
+-
+-              ret = offload->mailbox_read(offload, &cf_overflow,
+-                                          &timestamp, n);
+-
+-              /* Mailbox was empty. */
+-              if (unlikely(!ret))
+-                      return NULL;
+-
+-              /* Mailbox has been read and we're dropping it or
+-               * there was a problem reading the mailbox.
+-               *
+-               * Increment error counters in any case.
+-               */
+-              offload->dev->stats.rx_dropped++;
+-              offload->dev->stats.rx_fifo_errors++;
+-
+-              /* There was a problem reading the mailbox, propagate
+-               * error value.
+-               */
+-              if (unlikely(ret < 0))
+-                      return ERR_PTR(ret);
+-
+-              return skb_error;
+-      }
+-
+-      cb = can_rx_offload_get_cb(skb);
+-      ret = offload->mailbox_read(offload, cf, &cb->timestamp, n);
++      /* If queue is full drop frame */
++      if (unlikely(skb_queue_len(&offload->skb_queue) >
++                   offload->skb_queue_len_max))
++              drop = true;
++      skb = offload->mailbox_read(offload, n, &timestamp, drop);
+       /* Mailbox was empty. */
+-      if (unlikely(!ret)) {
+-              kfree_skb(skb);
++      if (unlikely(!skb))
+               return NULL;
+-      }
+-
+-      /* There was a problem reading the mailbox, propagate error value. */
+-      if (unlikely(ret < 0)) {
+-              kfree_skb(skb);
++      /* There was a problem reading the mailbox, propagate
++       * error value.
++       */
++      if (unlikely(IS_ERR(skb))) {
+               offload->dev->stats.rx_dropped++;
+               offload->dev->stats.rx_fifo_errors++;
+-              return ERR_PTR(ret);
++              return skb;
+       }
+       /* Mailbox was read. */
++      cb = can_rx_offload_get_cb(skb);
++      cb->timestamp = timestamp;
++
+       return skb;
+ }
+--- a/include/linux/can/rx-offload.h
++++ b/include/linux/can/rx-offload.h
+@@ -15,9 +15,9 @@
+ struct can_rx_offload {
+       struct net_device *dev;
+-      unsigned int (*mailbox_read)(struct can_rx_offload *offload,
+-                                   struct can_frame *cf,
+-                                   u32 *timestamp, unsigned int mb);
++      struct sk_buff *(*mailbox_read)(struct can_rx_offload *offload,
++                                      unsigned int mb, u32 *timestamp,
++                                      bool drop);
+       struct sk_buff_head skb_queue;
+       u32 skb_queue_len_max;
diff --git a/target/linux/layerscape/patches-5.4/802-can-0007-can-flexcan-use-devm_platform_ioremap_resource-to-si.patch b/target/linux/layerscape/patches-5.4/802-can-0007-can-flexcan-use-devm_platform_ioremap_resource-to-si.patch
new file mode 100644 (file)
index 0000000..5d88a58
--- /dev/null
@@ -0,0 +1,41 @@
+From 9198f241a7205bd85b89bda08fce5c2446a12e23 Mon Sep 17 00:00:00 2001
+From: Joakim Zhang <qiangqing.zhang@nxp.com>
+Date: Sun, 29 Sep 2019 08:32:09 +0000
+Subject: [PATCH] can: flexcan: use devm_platform_ioremap_resource() to
+ simplify code
+
+Use the new helper devm_platform_ioremap_resource() which wraps the
+platform_get_resource() and devm_ioremap_resource() together to simplify
+the code.
+
+Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
+Reviewed-by: Sean Nyekjaer <sean@geanix.com>
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -1548,7 +1548,6 @@ static int flexcan_probe(struct platform
+       struct net_device *dev;
+       struct flexcan_priv *priv;
+       struct regulator *reg_xceiver;
+-      struct resource *mem;
+       struct clk *clk_ipg = NULL, *clk_per = NULL;
+       struct flexcan_regs __iomem *regs;
+       int err, irq;
+@@ -1583,12 +1582,11 @@ static int flexcan_probe(struct platform
+               clock_freq = clk_get_rate(clk_per);
+       }
+-      mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0)
+               return -ENODEV;
+-      regs = devm_ioremap_resource(&pdev->dev, mem);
++      regs = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
diff --git a/target/linux/layerscape/patches-5.4/802-can-0008-can-flexcan-flexcan_irq_state-only-read-timestamp-if.patch b/target/linux/layerscape/patches-5.4/802-can-0008-can-flexcan-flexcan_irq_state-only-read-timestamp-if.patch
new file mode 100644 (file)
index 0000000..bc84f5f
--- /dev/null
@@ -0,0 +1,38 @@
+From 1a92e5a9109963e2491eec111b84b35b4e2adc8f Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Wed, 9 Oct 2019 15:15:37 +0200
+Subject: [PATCH] can: flexcan: flexcan_irq_state(): only read timestamp if
+ needed
+
+The function flexcan_irq_state() checks the controller for CAN state
+changes and pushes a skb with the new state and a timestamp into the
+rx-offload framework.
+
+This patch optimizes the function by only reading the timestamp, if a
+state change is detected.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -744,8 +744,6 @@ static void flexcan_irq_state(struct net
+       u32 timestamp;
+       int err;
+-      timestamp = priv->read(&regs->timer) << 16;
+-
+       flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK;
+       if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) {
+               tx_state = unlikely(reg_esr & FLEXCAN_ESR_TX_WRN) ?
+@@ -765,6 +763,8 @@ static void flexcan_irq_state(struct net
+       if (likely(new_state == priv->can.state))
+               return;
++      timestamp = priv->read(&regs->timer) << 16;
++
+       skb = alloc_can_err_skb(dev, &cf);
+       if (unlikely(!skb))
+               return;
diff --git a/target/linux/layerscape/patches-5.4/802-can-0009-can-flexcan-rename-macro-FLEXCAN_IFLAG_MB-FLEXCAN_IF.patch b/target/linux/layerscape/patches-5.4/802-can-0009-can-flexcan-rename-macro-FLEXCAN_IFLAG_MB-FLEXCAN_IF.patch
new file mode 100644 (file)
index 0000000..d67fc9c
--- /dev/null
@@ -0,0 +1,61 @@
+From 86608c5578b7a276e0edcedc976c604e283fd177 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Fri, 1 Mar 2019 11:12:13 +0100
+Subject: [PATCH] can: flexcan: rename macro FLEXCAN_IFLAG_MB() ->
+ FLEXCAN_IFLAG2_MB()
+
+The macro FLEXCAN_IFLAG_MB() is always used for the iflag2 register, so
+rename it to FLEXCAN_IFLAG2_MB()
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -142,7 +142,7 @@
+ #define FLEXCAN_TX_MB_RESERVED_OFF_FIFO               8
+ #define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP  0
+ #define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST     (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1)
+-#define FLEXCAN_IFLAG_MB(x)           BIT((x) & 0x1f)
++#define FLEXCAN_IFLAG2_MB(x)          BIT((x) & 0x1f)
+ #define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW        BIT(7)
+ #define FLEXCAN_IFLAG_RX_FIFO_WARN    BIT(6)
+ #define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE       BIT(5)
+@@ -880,7 +880,7 @@ static inline u64 flexcan_read_reg_iflag
+       u32 iflag1, iflag2;
+       iflag2 = priv->read(&regs->iflag2) & priv->reg_imask2_default &
+-              ~FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
++              ~FLEXCAN_IFLAG2_MB(priv->tx_mb_idx);
+       iflag1 = priv->read(&regs->iflag1) & priv->reg_imask1_default;
+       return (u64)iflag2 << 32 | iflag1;
+@@ -930,7 +930,7 @@ static irqreturn_t flexcan_irq(int irq,
+       reg_iflag2 = priv->read(&regs->iflag2);
+       /* transmission complete interrupt */
+-      if (reg_iflag2 & FLEXCAN_IFLAG_MB(priv->tx_mb_idx)) {
++      if (reg_iflag2 & FLEXCAN_IFLAG2_MB(priv->tx_mb_idx)) {
+               u32 reg_ctrl = priv->read(&priv->tx_mb->can_ctrl);
+               handled = IRQ_HANDLED;
+@@ -942,7 +942,7 @@ static irqreturn_t flexcan_irq(int irq,
+               /* after sending a RTR frame MB is in RX mode */
+               priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
+                           &priv->tx_mb->can_ctrl);
+-              priv->write(FLEXCAN_IFLAG_MB(priv->tx_mb_idx), &regs->iflag2);
++              priv->write(FLEXCAN_IFLAG2_MB(priv->tx_mb_idx), &regs->iflag2);
+               netif_wake_queue(dev);
+       }
+@@ -1299,7 +1299,7 @@ static int flexcan_open(struct net_devic
+       priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx);
+       priv->reg_imask1_default = 0;
+-      priv->reg_imask2_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
++      priv->reg_imask2_default = FLEXCAN_IFLAG2_MB(priv->tx_mb_idx);
+       priv->offload.mailbox_read = flexcan_mailbox_read;
diff --git a/target/linux/layerscape/patches-5.4/802-can-0010-can-flexcan-flexcan_irq-rename-variable-reg_iflag-re.patch b/target/linux/layerscape/patches-5.4/802-can-0010-can-flexcan-flexcan_irq-rename-variable-reg_iflag-re.patch
new file mode 100644 (file)
index 0000000..e2086b7
--- /dev/null
@@ -0,0 +1,35 @@
+From f7f3c7abdef9fb6c9668a3945ec791fb206b4ee8 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Fri, 1 Mar 2019 16:29:47 +0100
+Subject: [PATCH] can: flexcan: flexcan_irq(): rename variable reg_iflag ->
+ reg_iflag_rx
+
+This patch renames the variable reg_iflag in the flexcan_irq() function
+to reg_iflag_rx. This better reflects the contents of the varibale. It
+does not hold the unmodified iflag registers, instead all non RX
+interrupts have been masked.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -898,13 +898,13 @@ static irqreturn_t flexcan_irq(int irq,
+       /* reception interrupt */
+       if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
+-              u64 reg_iflag;
++              u64 reg_iflag_rx;
+               int ret;
+-              while ((reg_iflag = flexcan_read_reg_iflag_rx(priv))) {
++              while ((reg_iflag_rx = flexcan_read_reg_iflag_rx(priv))) {
+                       handled = IRQ_HANDLED;
+                       ret = can_rx_offload_irq_offload_timestamp(&priv->offload,
+-                                                                 reg_iflag);
++                                                                 reg_iflag_rx);
+                       if (!ret)
+                               break;
+               }
diff --git a/target/linux/layerscape/patches-5.4/802-can-0011-can-flexcan-rename-struct-flexcan_priv-reg_imask-1-2.patch b/target/linux/layerscape/patches-5.4/802-can-0011-can-flexcan-rename-struct-flexcan_priv-reg_imask-1-2.patch
new file mode 100644 (file)
index 0000000..12030a2
--- /dev/null
@@ -0,0 +1,101 @@
+From a1126887f068def0bc11f5260e55e25b9c03e3ea Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Fri, 1 Mar 2019 09:18:54 +0100
+Subject: [PATCH] can: flexcan: rename struct
+ flexcan_priv::reg_imask{1,2}_default to rx_mask{1,2}
+
+The flexcan IP core has up to 64 mailboxes, each one has a corresponding
+interrupt bit in the iflag1 or iflag2 registers and a mask bit in the
+imask1 or imask2 registers.
+
+In the timestamp (i.e. non FIFO) mode the driver needs to mask out all
+non RX interrupt sources and uses the precomputed values
+reg_imask1_default and reg_imask2_default of struct flexcan_priv for
+this.
+
+However in the current driver the reg_imask{1,2}_default cannot be used
+directly to get the pending RX interrupts. The TX interrupt is part of
+these variables, so it needs to be masked out, too.
+
+This is a preparation patch to clean up calculation of the pending RX
+interrupts, it only renames the variables from
+
+    reg_imask{1,2}_default
+
+to
+
+    rx_mask{1,2}
+
+To better reflect their meaning after the complete conversion. This
+change is done with the following sed command:
+
+    sed -i -e "s/reg_imask\(1\|2\)_default/rx_mask\1/" drivers/net/can/flexcan.c
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 22 +++++++++++-----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -278,8 +278,8 @@ struct flexcan_priv {
+       u8 clk_src;     /* clock source of CAN Protocol Engine */
+       u32 reg_ctrl_default;
+-      u32 reg_imask1_default;
+-      u32 reg_imask2_default;
++      u32 rx_mask1;
++      u32 rx_mask2;
+       struct clk *clk_ipg;
+       struct clk *clk_per;
+@@ -879,9 +879,9 @@ static inline u64 flexcan_read_reg_iflag
+       struct flexcan_regs __iomem *regs = priv->regs;
+       u32 iflag1, iflag2;
+-      iflag2 = priv->read(&regs->iflag2) & priv->reg_imask2_default &
++      iflag2 = priv->read(&regs->iflag2) & priv->rx_mask2 &
+               ~FLEXCAN_IFLAG2_MB(priv->tx_mb_idx);
+-      iflag1 = priv->read(&regs->iflag1) & priv->reg_imask1_default;
++      iflag1 = priv->read(&regs->iflag1) & priv->rx_mask1;
+       return (u64)iflag2 << 32 | iflag1;
+ }
+@@ -1228,8 +1228,8 @@ static int flexcan_chip_start(struct net
+       /* enable interrupts atomically */
+       disable_irq(dev->irq);
+       priv->write(priv->reg_ctrl_default, &regs->ctrl);
+-      priv->write(priv->reg_imask1_default, &regs->imask1);
+-      priv->write(priv->reg_imask2_default, &regs->imask2);
++      priv->write(priv->rx_mask1, &regs->imask1);
++      priv->write(priv->rx_mask2, &regs->imask2);
+       enable_irq(dev->irq);
+       /* print chip status */
+@@ -1298,8 +1298,8 @@ static int flexcan_open(struct net_devic
+       priv->tx_mb_idx = priv->mb_count - 1;
+       priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx);
+-      priv->reg_imask1_default = 0;
+-      priv->reg_imask2_default = FLEXCAN_IFLAG2_MB(priv->tx_mb_idx);
++      priv->rx_mask1 = 0;
++      priv->rx_mask2 = FLEXCAN_IFLAG2_MB(priv->tx_mb_idx);
+       priv->offload.mailbox_read = flexcan_mailbox_read;
+@@ -1311,12 +1311,12 @@ static int flexcan_open(struct net_devic
+               imask = GENMASK_ULL(priv->offload.mb_last,
+                                   priv->offload.mb_first);
+-              priv->reg_imask1_default |= imask;
+-              priv->reg_imask2_default |= imask >> 32;
++              priv->rx_mask1 |= imask;
++              priv->rx_mask2 |= imask >> 32;
+               err = can_rx_offload_add_timestamp(dev, &priv->offload);
+       } else {
+-              priv->reg_imask1_default |= FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
++              priv->rx_mask1 |= FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
+                       FLEXCAN_IFLAG_RX_FIFO_AVAILABLE;
+               err = can_rx_offload_add_fifo(dev, &priv->offload,
+                                             FLEXCAN_NAPI_WEIGHT);
diff --git a/target/linux/layerscape/patches-5.4/802-can-0012-can-flexcan-remove-TX-mailbox-bit-from-struct-flexca.patch b/target/linux/layerscape/patches-5.4/802-can-0012-can-flexcan-remove-TX-mailbox-bit-from-struct-flexca.patch
new file mode 100644 (file)
index 0000000..a066764
--- /dev/null
@@ -0,0 +1,71 @@
+From 916df9ddac295df428a304fd03ed492ad10e900c Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Fri, 1 Mar 2019 10:22:26 +0100
+Subject: [PATCH] can: flexcan: remove TX mailbox bit from struct
+ flexcan_priv::rx_mask{1,2}
+
+The flexcan IP core has up to 64 mailboxes, each one has a corresponding
+interrupt bit in the iflag1 or iflag2 registers and a mask bit in the
+imask1 or imask2 registers.
+
+In the timestamp (i.e. non FIFO) mode the driver needs to mask out all
+non RX interrupt sources and uses the precomputed values rx_mask1 and
+rx_mask2 of struct flexcan_priv for this.
+
+Currently these values cannot be used directly, as they contain the TX
+mailbox flag. This patch removes the TX flag from flexcan_priv::rx_mask1
+and flexcan_priv::rx_mask2, and sets the TX flag directly when writing
+the regs->iflag1 and regs->iflag2 into the hardware.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 14 +++++---------
+ 1 file changed, 5 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -879,8 +879,7 @@ static inline u64 flexcan_read_reg_iflag
+       struct flexcan_regs __iomem *regs = priv->regs;
+       u32 iflag1, iflag2;
+-      iflag2 = priv->read(&regs->iflag2) & priv->rx_mask2 &
+-              ~FLEXCAN_IFLAG2_MB(priv->tx_mb_idx);
++      iflag2 = priv->read(&regs->iflag2) & priv->rx_mask2;
+       iflag1 = priv->read(&regs->iflag1) & priv->rx_mask1;
+       return (u64)iflag2 << 32 | iflag1;
+@@ -1229,7 +1228,7 @@ static int flexcan_chip_start(struct net
+       disable_irq(dev->irq);
+       priv->write(priv->reg_ctrl_default, &regs->ctrl);
+       priv->write(priv->rx_mask1, &regs->imask1);
+-      priv->write(priv->rx_mask2, &regs->imask2);
++      priv->write(priv->rx_mask2 | FLEXCAN_IFLAG2_MB(priv->tx_mb_idx), &regs->imask2);
+       enable_irq(dev->irq);
+       /* print chip status */
+@@ -1298,9 +1297,6 @@ static int flexcan_open(struct net_devic
+       priv->tx_mb_idx = priv->mb_count - 1;
+       priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx);
+-      priv->rx_mask1 = 0;
+-      priv->rx_mask2 = FLEXCAN_IFLAG2_MB(priv->tx_mb_idx);
+-
+       priv->offload.mailbox_read = flexcan_mailbox_read;
+       if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
+@@ -1311,12 +1307,12 @@ static int flexcan_open(struct net_devic
+               imask = GENMASK_ULL(priv->offload.mb_last,
+                                   priv->offload.mb_first);
+-              priv->rx_mask1 |= imask;
+-              priv->rx_mask2 |= imask >> 32;
++              priv->rx_mask1 = imask;
++              priv->rx_mask2 = imask >> 32;
+               err = can_rx_offload_add_timestamp(dev, &priv->offload);
+       } else {
+-              priv->rx_mask1 |= FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
++              priv->rx_mask1 = FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
+                       FLEXCAN_IFLAG_RX_FIFO_AVAILABLE;
+               err = can_rx_offload_add_fifo(dev, &priv->offload,
+                                             FLEXCAN_NAPI_WEIGHT);
diff --git a/target/linux/layerscape/patches-5.4/802-can-0013-can-flexcan-convert-struct-flexcan_priv-rx_mask-1-2-.patch b/target/linux/layerscape/patches-5.4/802-can-0013-can-flexcan-convert-struct-flexcan_priv-rx_mask-1-2-.patch
new file mode 100644 (file)
index 0000000..8cf6215
--- /dev/null
@@ -0,0 +1,107 @@
+From 6adf87956ee1043e6bf0ef83fa0eec1e755c0d48 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Fri, 1 Mar 2019 12:17:30 +0100
+Subject: [PATCH] can: flexcan: convert struct flexcan_priv::rx_mask{1,2} to
+ rx_mask
+
+The flexcan IP core has up to 64 mailboxes, each one has a corresponding
+interrupt bit in the iflag1 or iflag2 registers and a mask bit in the
+imask1 or imask2 registers.
+
+In the timestamp (i.e. non FIFO) mode the driver needs to mask out all non RX
+interrupt sources and uses the precomputed values rx_mask1 and rx_mask2 of
+struct flexcan_priv for this.
+
+This patch merges the two u32 rx_mask1 and rx_mask2 to a single u64 rx_mask
+variable, which simplifies the code a bit.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 30 +++++++++++++-----------------
+ 1 file changed, 13 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -142,6 +142,7 @@
+ #define FLEXCAN_TX_MB_RESERVED_OFF_FIFO               8
+ #define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP  0
+ #define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST     (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1)
++#define FLEXCAN_IFLAG_MB(x)           BIT_ULL(x)
+ #define FLEXCAN_IFLAG2_MB(x)          BIT((x) & 0x1f)
+ #define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW        BIT(7)
+ #define FLEXCAN_IFLAG_RX_FIFO_WARN    BIT(6)
+@@ -277,9 +278,8 @@ struct flexcan_priv {
+       u8 mb_size;
+       u8 clk_src;     /* clock source of CAN Protocol Engine */
++      u64 rx_mask;
+       u32 reg_ctrl_default;
+-      u32 rx_mask1;
+-      u32 rx_mask2;
+       struct clk *clk_ipg;
+       struct clk *clk_per;
+@@ -873,16 +873,15 @@ static struct sk_buff *flexcan_mailbox_r
+       return skb;
+ }
+-
+ static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv)
+ {
+       struct flexcan_regs __iomem *regs = priv->regs;
+-      u32 iflag1, iflag2;
++      u64 iflag;
+-      iflag2 = priv->read(&regs->iflag2) & priv->rx_mask2;
+-      iflag1 = priv->read(&regs->iflag1) & priv->rx_mask1;
++      iflag = (u64)priv->read(&regs->iflag2) << 32 |
++              priv->read(&regs->iflag1);
+-      return (u64)iflag2 << 32 | iflag1;
++      return iflag & priv->rx_mask;
+ }
+ static irqreturn_t flexcan_irq(int irq, void *dev_id)
+@@ -1053,6 +1052,7 @@ static int flexcan_chip_start(struct net
+       struct flexcan_priv *priv = netdev_priv(dev);
+       struct flexcan_regs __iomem *regs = priv->regs;
+       u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr;
++      u64 reg_imask;
+       int err, i;
+       struct flexcan_mb __iomem *mb;
+@@ -1227,8 +1227,9 @@ static int flexcan_chip_start(struct net
+       /* enable interrupts atomically */
+       disable_irq(dev->irq);
+       priv->write(priv->reg_ctrl_default, &regs->ctrl);
+-      priv->write(priv->rx_mask1, &regs->imask1);
+-      priv->write(priv->rx_mask2 | FLEXCAN_IFLAG2_MB(priv->tx_mb_idx), &regs->imask2);
++      reg_imask = priv->rx_mask | FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
++      priv->write(upper_32_bits(reg_imask), &regs->imask2);
++      priv->write(lower_32_bits(reg_imask), &regs->imask1);
+       enable_irq(dev->irq);
+       /* print chip status */
+@@ -1300,19 +1301,14 @@ static int flexcan_open(struct net_devic
+       priv->offload.mailbox_read = flexcan_mailbox_read;
+       if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
+-              u64 imask;
+-
+               priv->offload.mb_first = FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST;
+               priv->offload.mb_last = priv->mb_count - 2;
+-              imask = GENMASK_ULL(priv->offload.mb_last,
+-                                  priv->offload.mb_first);
+-              priv->rx_mask1 = imask;
+-              priv->rx_mask2 = imask >> 32;
+-
++              priv->rx_mask = GENMASK_ULL(priv->offload.mb_last,
++                                          priv->offload.mb_first);
+               err = can_rx_offload_add_timestamp(dev, &priv->offload);
+       } else {
+-              priv->rx_mask1 = FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
++              priv->rx_mask = FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
+                       FLEXCAN_IFLAG_RX_FIFO_AVAILABLE;
+               err = can_rx_offload_add_fifo(dev, &priv->offload,
+                                             FLEXCAN_NAPI_WEIGHT);
diff --git a/target/linux/layerscape/patches-5.4/802-can-0014-can-flexcan-introduce-struct-flexcan_priv-tx_mask-an.patch b/target/linux/layerscape/patches-5.4/802-can-0014-can-flexcan-introduce-struct-flexcan_priv-tx_mask-an.patch
new file mode 100644 (file)
index 0000000..3df5afd
--- /dev/null
@@ -0,0 +1,90 @@
+From 1693e5693b77f0d172aac8adcfaa4888d64f8996 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Fri, 1 Mar 2019 13:54:19 +0100
+Subject: [PATCH] can: flexcan: introduce struct flexcan_priv::tx_mask and make
+ use of it
+
+The current driver uses FLEXCAN_IFLAG2_MB() to generate the mask to check for
+the TX complete interrupt. This works well, as the driver will always use the
+last mailbox for TX, which falls into the iflag2 register.
+
+To support CANFD the payload size has to increase to 64 bytes and the
+number of mailboxes will decrease so much that the TX mailbox will be
+handled in the iflag1 register.
+
+This patch introduces a tx_mask in the struct flexcan_priv (similar to rx_mask)
+and makes use of it. The actual support to handle the TX mailbox in iflag1 will
+be added in the next patches.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -143,7 +143,6 @@
+ #define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP  0
+ #define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST     (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1)
+ #define FLEXCAN_IFLAG_MB(x)           BIT_ULL(x)
+-#define FLEXCAN_IFLAG2_MB(x)          BIT((x) & 0x1f)
+ #define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW        BIT(7)
+ #define FLEXCAN_IFLAG_RX_FIFO_WARN    BIT(6)
+ #define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE       BIT(5)
+@@ -279,6 +278,7 @@ struct flexcan_priv {
+       u8 clk_src;     /* clock source of CAN Protocol Engine */
+       u64 rx_mask;
++      u64 tx_mask;
+       u32 reg_ctrl_default;
+       struct clk *clk_ipg;
+@@ -891,7 +891,8 @@ static irqreturn_t flexcan_irq(int irq,
+       struct flexcan_priv *priv = netdev_priv(dev);
+       struct flexcan_regs __iomem *regs = priv->regs;
+       irqreturn_t handled = IRQ_NONE;
+-      u32 reg_iflag2, reg_esr;
++      u64 reg_iflag_tx;
++      u32 reg_esr;
+       enum can_state last_state = priv->can.state;
+       /* reception interrupt */
+@@ -925,10 +926,10 @@ static irqreturn_t flexcan_irq(int irq,
+               }
+       }
+-      reg_iflag2 = priv->read(&regs->iflag2);
++      reg_iflag_tx = (u64)priv->read(&regs->iflag2) << 32;
+       /* transmission complete interrupt */
+-      if (reg_iflag2 & FLEXCAN_IFLAG2_MB(priv->tx_mb_idx)) {
++      if (reg_iflag_tx & priv->tx_mask) {
+               u32 reg_ctrl = priv->read(&priv->tx_mb->can_ctrl);
+               handled = IRQ_HANDLED;
+@@ -940,7 +941,7 @@ static irqreturn_t flexcan_irq(int irq,
+               /* after sending a RTR frame MB is in RX mode */
+               priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
+                           &priv->tx_mb->can_ctrl);
+-              priv->write(FLEXCAN_IFLAG2_MB(priv->tx_mb_idx), &regs->iflag2);
++              priv->write(priv->tx_mask >> 32, &regs->iflag2);
+               netif_wake_queue(dev);
+       }
+@@ -1227,7 +1228,7 @@ static int flexcan_chip_start(struct net
+       /* enable interrupts atomically */
+       disable_irq(dev->irq);
+       priv->write(priv->reg_ctrl_default, &regs->ctrl);
+-      reg_imask = priv->rx_mask | FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
++      reg_imask = priv->rx_mask | priv->tx_mask;
+       priv->write(upper_32_bits(reg_imask), &regs->imask2);
+       priv->write(lower_32_bits(reg_imask), &regs->imask1);
+       enable_irq(dev->irq);
+@@ -1297,6 +1298,7 @@ static int flexcan_open(struct net_devic
+                       flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_FIFO);
+       priv->tx_mb_idx = priv->mb_count - 1;
+       priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx);
++      priv->tx_mask = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
+       priv->offload.mailbox_read = flexcan_mailbox_read;
diff --git a/target/linux/layerscape/patches-5.4/802-can-0015-can-flexcan-flexcan_read_reg_iflag_rx-optimize-readi.patch b/target/linux/layerscape/patches-5.4/802-can-0015-can-flexcan-flexcan_read_reg_iflag_rx-optimize-readi.patch
new file mode 100644 (file)
index 0000000..cf7a6fd
--- /dev/null
@@ -0,0 +1,68 @@
+From 74920ba156136a58dd3411c02d429d4f31497dc0 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Fri, 1 Mar 2019 15:38:05 +0100
+Subject: [PATCH] can: flexcan: flexcan_read_reg_iflag_rx(): optimize reading
+
+The flexcan IP core has up to 64 mailboxes, each one has a corresponding
+interrupt bit in the iflag1 or iflag2 registers and a mask bit in the
+imask1 or imask2 registers.
+
+In the timestamp (i.e. non FIFO) mode the driver needs to mask all non RX
+interrupt sources, it uses the precomputed value rx_mask of struct flexcan_priv
+for this.
+
+In certain use cases, for example the CANFD mode, the contents of the iflag2
+register is completely masked.
+
+This patch optimizes the flexcan_read_reg_iflag_rx() function by not reading
+the iflag1 or iflag2 register if the contents is masked.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 28 +++++++++++++++++-----------
+ 1 file changed, 17 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -779,6 +779,23 @@ static void flexcan_irq_state(struct net
+               dev->stats.rx_fifo_errors++;
+ }
++static inline u64 flexcan_read64_mask(struct flexcan_priv *priv, void __iomem *addr, u64 mask)
++{
++      u64 reg = 0;
++
++      if (upper_32_bits(mask))
++              reg = (u64)priv->read(addr - 4) << 32;
++      if (lower_32_bits(mask))
++              reg |= priv->read(addr);
++
++      return reg & mask;
++}
++
++static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv)
++{
++      return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->rx_mask);
++}
++
+ static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *offload)
+ {
+       return container_of(offload, struct flexcan_priv, offload);
+@@ -873,17 +890,6 @@ static struct sk_buff *flexcan_mailbox_r
+       return skb;
+ }
+-static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv)
+-{
+-      struct flexcan_regs __iomem *regs = priv->regs;
+-      u64 iflag;
+-
+-      iflag = (u64)priv->read(&regs->iflag2) << 32 |
+-              priv->read(&regs->iflag1);
+-
+-      return iflag & priv->rx_mask;
+-}
+-
+ static irqreturn_t flexcan_irq(int irq, void *dev_id)
+ {
+       struct net_device *dev = dev_id;
diff --git a/target/linux/layerscape/patches-5.4/802-can-0016-can-flexcan-flexcan_irq-add-support-for-TX-mailbox-i.patch b/target/linux/layerscape/patches-5.4/802-can-0016-can-flexcan-flexcan_irq-add-support-for-TX-mailbox-i.patch
new file mode 100644 (file)
index 0000000..5fb96f4
--- /dev/null
@@ -0,0 +1,73 @@
+From 57d3edbdcfee9b677452744bba5c4f08b476872a Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Fri, 1 Mar 2019 15:38:05 +0100
+Subject: [PATCH] can: flexcan: flexcan_irq(): add support for TX mailbox in
+ iflag1
+
+The flexcan IP core has up to 64 mailboxes, each one has a corresponding
+interrupt bit in the iflag1 or iflag2 registers and a mask bit in the
+imask1 or imask2 registers.
+
+The driver will always use the last mailbox for TX, which falls into the iflag2
+register.
+
+To support CANFD the payload size has to increase to 64 bytes and the number of
+mailboxes will decrease so much that the TX mailbox will be handled in the
+iflag1 register.
+
+This patch add support to handle the TX mailbox independent whether it's
+in iflag1 or iflag2 by introducing th flexcan_read_reg_iflag_tx()
+function, similar to flexcan_read_reg_iflag_rx(), for the read path.
+
+For the write path the function flexcan_write64() is added.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 17 +++++++++++++++--
+ 1 file changed, 15 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -791,11 +791,24 @@ static inline u64 flexcan_read64_mask(st
+       return reg & mask;
+ }
++static inline void flexcan_write64(struct flexcan_priv *priv, u64 val, void __iomem *addr)
++{
++      if (upper_32_bits(val))
++              priv->write(upper_32_bits(val), addr - 4);
++      if (lower_32_bits(val))
++              priv->write(lower_32_bits(val), addr);
++}
++
+ static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv)
+ {
+       return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->rx_mask);
+ }
++static inline u64 flexcan_read_reg_iflag_tx(struct flexcan_priv *priv)
++{
++      return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->tx_mask);
++}
++
+ static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *offload)
+ {
+       return container_of(offload, struct flexcan_priv, offload);
+@@ -932,7 +945,7 @@ static irqreturn_t flexcan_irq(int irq,
+               }
+       }
+-      reg_iflag_tx = (u64)priv->read(&regs->iflag2) << 32;
++      reg_iflag_tx = flexcan_read_reg_iflag_tx(priv);
+       /* transmission complete interrupt */
+       if (reg_iflag_tx & priv->tx_mask) {
+@@ -947,7 +960,7 @@ static irqreturn_t flexcan_irq(int irq,
+               /* after sending a RTR frame MB is in RX mode */
+               priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
+                           &priv->tx_mb->can_ctrl);
+-              priv->write(priv->tx_mask >> 32, &regs->iflag2);
++              flexcan_write64(priv, priv->tx_mask, &regs->iflag1);
+               netif_wake_queue(dev);
+       }
diff --git a/target/linux/layerscape/patches-5.4/802-can-0017-can-flexcan-flexcan_mailbox_read-make-use-of-flexcan.patch b/target/linux/layerscape/patches-5.4/802-can-0017-can-flexcan-flexcan_mailbox_read-make-use-of-flexcan.patch
new file mode 100644 (file)
index 0000000..37c2ed3
--- /dev/null
@@ -0,0 +1,37 @@
+From 6340760d0671e92b15ff92b7eda41bbdd9702437 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Fri, 1 Mar 2019 16:27:59 +0100
+Subject: [PATCH] can: flexcan: flexcan_mailbox_read() make use of
+ flexcan_write64() to mark the mailbox as read
+
+In the previous patch the function flexcan_write64() was introduced.
+
+This patch replaces the open coded variant in flexcan_mailbox_read()
+that marks a mailbox as read, by a single call to flexcan_write64().
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 11 +++--------
+ 1 file changed, 3 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -884,15 +884,10 @@ static struct sk_buff *flexcan_mailbox_r
+       }
+  mark_as_read:
+-      if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
+-              /* Clear IRQ */
+-              if (n < 32)
+-                      priv->write(BIT(n), &regs->iflag1);
+-              else
+-                      priv->write(BIT(n - 32), &regs->iflag2);
+-      } else {
++      if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)
++              flexcan_write64(priv, FLEXCAN_IFLAG_MB(n), &regs->iflag1);
++      else
+               priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->iflag1);
+-      }
+       /* Read the Free Running Timer. It is optional but recommended
+        * to unlock Mailbox as soon as possible and make it available
diff --git a/target/linux/layerscape/patches-5.4/802-can-0018-can-flexcan-use-struct-canfd_frame-for-CAN-classic-f.patch b/target/linux/layerscape/patches-5.4/802-can-0018-can-flexcan-use-struct-canfd_frame-for-CAN-classic-f.patch
new file mode 100644 (file)
index 0000000..968bc11
--- /dev/null
@@ -0,0 +1,115 @@
+From 03374d551c7fbb1b1ecc115df4f374bc5027b1f9 Mon Sep 17 00:00:00 2001
+From: Joakim Zhang <qiangqing.zhang@nxp.com>
+Date: Fri, 12 Jul 2019 08:02:41 +0000
+Subject: [PATCH] can: flexcan: use struct canfd_frame for CAN classic frame
+
+This patch prepares for CAN FD mode, using struct canfd_frame can both
+for classic format frame and fd format frame.
+
+Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c    | 34 +++++++++++++++++-----------------
+ drivers/net/can/rx-offload.c |  4 ++--
+ 2 files changed, 19 insertions(+), 19 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -628,10 +628,10 @@ static int flexcan_get_berr_counter(cons
+ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+       const struct flexcan_priv *priv = netdev_priv(dev);
+-      struct can_frame *cf = (struct can_frame *)skb->data;
++      struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+       u32 can_id;
+       u32 data;
+-      u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16);
++      u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cfd->len << 16);
+       int i;
+       if (can_dropped_invalid_skb(dev, skb))
+@@ -639,18 +639,18 @@ static netdev_tx_t flexcan_start_xmit(st
+       netif_stop_queue(dev);
+-      if (cf->can_id & CAN_EFF_FLAG) {
+-              can_id = cf->can_id & CAN_EFF_MASK;
++      if (cfd->can_id & CAN_EFF_FLAG) {
++              can_id = cfd->can_id & CAN_EFF_MASK;
+               ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR;
+       } else {
+-              can_id = (cf->can_id & CAN_SFF_MASK) << 18;
++              can_id = (cfd->can_id & CAN_SFF_MASK) << 18;
+       }
+-      if (cf->can_id & CAN_RTR_FLAG)
++      if (cfd->can_id & CAN_RTR_FLAG)
+               ctrl |= FLEXCAN_MB_CNT_RTR;
+-      for (i = 0; i < cf->can_dlc; i += sizeof(u32)) {
+-              data = be32_to_cpup((__be32 *)&cf->data[i]);
++      for (i = 0; i < cfd->len; i += sizeof(u32)) {
++              data = be32_to_cpup((__be32 *)&cfd->data[i]);
+               priv->write(data, &priv->tx_mb->data[i / sizeof(u32)]);
+       }
+@@ -822,7 +822,7 @@ static struct sk_buff *flexcan_mailbox_r
+       struct flexcan_regs __iomem *regs = priv->regs;
+       struct flexcan_mb __iomem *mb;
+       struct sk_buff *skb;
+-      struct can_frame *cf;
++      struct canfd_frame *cfd;
+       u32 reg_ctrl, reg_id, reg_iflag1;
+       int i;
+@@ -859,8 +859,8 @@ static struct sk_buff *flexcan_mailbox_r
+               reg_ctrl = priv->read(&mb->can_ctrl);
+       }
+-      skb = alloc_can_skb(offload->dev, &cf);
+-      if (!skb) {
++      skb = alloc_can_skb(offload->dev, (struct can_frame **)&cfd);
++      if (unlikely(!skb)) {
+               skb = ERR_PTR(-ENOMEM);
+               goto mark_as_read;
+       }
+@@ -870,17 +870,17 @@ static struct sk_buff *flexcan_mailbox_r
+       reg_id = priv->read(&mb->can_id);
+       if (reg_ctrl & FLEXCAN_MB_CNT_IDE)
+-              cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
++              cfd->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
+       else
+-              cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
++              cfd->can_id = (reg_id >> 18) & CAN_SFF_MASK;
+       if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
+-              cf->can_id |= CAN_RTR_FLAG;
+-      cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
++              cfd->can_id |= CAN_RTR_FLAG;
++      cfd->len = get_can_dlc((reg_ctrl >> 16) & 0xf);
+-      for (i = 0; i < cf->can_dlc; i += sizeof(u32)) {
++      for (i = 0; i < cfd->len; i += sizeof(u32)) {
+               __be32 data = cpu_to_be32(priv->read(&mb->data[i / sizeof(u32)]));
+-              *(__be32 *)(cf->data + i) = data;
++              *(__be32 *)(cfd->data + i) = data;
+       }
+  mark_as_read:
+--- a/drivers/net/can/rx-offload.c
++++ b/drivers/net/can/rx-offload.c
+@@ -51,11 +51,11 @@ static int can_rx_offload_napi_poll(stru
+       while ((work_done < quota) &&
+              (skb = skb_dequeue(&offload->skb_queue))) {
+-              struct can_frame *cf = (struct can_frame *)skb->data;
++              struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+               work_done++;
+               stats->rx_packets++;
+-              stats->rx_bytes += cf->can_dlc;
++              stats->rx_bytes += cfd->len;
+               netif_receive_skb(skb);
+       }
diff --git a/target/linux/layerscape/patches-5.4/802-can-0019-can-flexcan-add-CAN-FD-mode-support.patch b/target/linux/layerscape/patches-5.4/802-can-0019-can-flexcan-add-CAN-FD-mode-support.patch
new file mode 100644 (file)
index 0000000..f762ed6
--- /dev/null
@@ -0,0 +1,397 @@
+From 2aea13a107090d05e968d7d2aa3f72380a3f1b4c Mon Sep 17 00:00:00 2001
+From: Joakim Zhang <qiangqing.zhang@nxp.com>
+Date: Fri, 12 Jul 2019 08:02:44 +0000
+Subject: [PATCH] can: flexcan: add CAN FD mode support
+
+This patch intends to add CAN FD mode support in driver, it means that
+payload size can extend up to 64 bytes.
+
+Bit timing always set in CBT register other than CTRL1 register when
+CANFD supports BRS, it will extend the range of all CAN bit timing
+variables (PRESDIV, PROPSEG, PSEG1, PSEG2 and RJW), which will improve
+the bit timing accuracy.
+
+Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 247 ++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 218 insertions(+), 29 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -52,6 +52,7 @@
+ #define FLEXCAN_MCR_IRMQ              BIT(16)
+ #define FLEXCAN_MCR_LPRIO_EN          BIT(13)
+ #define FLEXCAN_MCR_AEN                       BIT(12)
++#define FLEXCAN_MCR_FDEN              BIT(11)
+ /* MCR_MAXMB: maximum used MBs is MAXMB + 1 */
+ #define FLEXCAN_MCR_MAXMB(x)          ((x) & 0x7f)
+ #define FLEXCAN_MCR_IDAM_A            (0x0 << 8)
+@@ -137,6 +138,26 @@
+        FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT | \
+        FLEXCAN_ESR_WAK_INT)
++/* FLEXCAN Bit Timing register (CBT) bits */
++#define FLEXCAN_CBT_BTF                       BIT(31)
++#define FLEXCAN_CBT_EPRESDIV(x)               (((x) & 0x3ff) << 21)
++#define FLEXCAN_CBT_ERJW(x)           (((x) & 0x0f) << 16)
++#define FLEXCAN_CBT_EPROPSEG(x)               (((x) & 0x3f) << 10)
++#define FLEXCAN_CBT_EPSEG1(x)         (((x) & 0x1f) << 5)
++#define FLEXCAN_CBT_EPSEG2(x)         ((x) & 0x1f)
++
++/* FLEXCAN FD control register (FDCTRL) bits */
++#define FLEXCAN_FDCTRL_FDRATE         BIT(31)
++#define FLEXCAN_FDCTRL_MBDSR1(x)      (((x) & 0x3) << 19)
++#define FLEXCAN_FDCTRL_MBDSR0(x)      (((x) & 0x3) << 16)
++
++/* FLEXCAN FD Bit Timing register (FDCBT) bits */
++#define FLEXCAN_FDCBT_FPRESDIV(x)     (((x) & 0x3ff) << 20)
++#define FLEXCAN_FDCBT_FRJW(x)         (((x) & 0x07) << 16)
++#define FLEXCAN_FDCBT_FPROPSEG(x)     (((x) & 0x1f) << 10)
++#define FLEXCAN_FDCBT_FPSEG1(x)               (((x) & 0x07) << 5)
++#define FLEXCAN_FDCBT_FPSEG2(x)               ((x) & 0x07)
++
+ /* FLEXCAN interrupt flag register (IFLAG) bits */
+ /* Errata ERR005829 step7: Reserve first valid MB */
+ #define FLEXCAN_TX_MB_RESERVED_OFF_FIFO               8
+@@ -161,6 +182,9 @@
+ #define FLEXCAN_MB_CODE_TX_DATA               (0xc << 24)
+ #define FLEXCAN_MB_CODE_TX_TANSWER    (0xe << 24)
++#define FLEXCAN_MB_CNT_EDL            BIT(31)
++#define FLEXCAN_MB_CNT_BRS            BIT(30)
++#define FLEXCAN_MB_CNT_ESI            BIT(29)
+ #define FLEXCAN_MB_CNT_SRR            BIT(22)
+ #define FLEXCAN_MB_CNT_IDE            BIT(21)
+ #define FLEXCAN_MB_CNT_RTR            BIT(20)
+@@ -192,6 +216,7 @@
+ #define FLEXCAN_QUIRK_BROKEN_PERR_STATE       BIT(6) /* No interrupt for error passive */
+ #define FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN      BIT(7) /* default to BE register access */
+ #define FLEXCAN_QUIRK_SETUP_STOP_MODE         BIT(8) /* Setup stop mode to support wakeup */
++#define FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD    BIT(9) /* Use timestamp then support can fd mode */
+ /* Structure of the message buffer */
+ struct flexcan_mb {
+@@ -225,7 +250,8 @@ struct flexcan_regs {
+       u32 crcr;               /* 0x44 */
+       u32 rxfgmask;           /* 0x48 */
+       u32 rxfir;              /* 0x4c */
+-      u32 _reserved3[12];     /* 0x50 */
++      u32 cbt;                /* 0x50 */
++      u32 _reserved3[11];     /* 0x54 */
+       u8 mb[2][512];          /* 0x80 */
+       /* FIFO-mode:
+        *                      MB
+@@ -250,6 +276,10 @@ struct flexcan_regs {
+       u32 rerrdr;             /* 0xaf4 */
+       u32 rerrsynr;           /* 0xaf8 */
+       u32 errsr;              /* 0xafc */
++      u32 _reserved7[64];     /* 0xb00 */
++      u32 fdctrl;             /* 0xc00 */
++      u32 fdcbt;              /* 0xc04 */
++      u32 fdcrc;              /* 0xc08 */
+ };
+ struct flexcan_devtype_data {
+@@ -337,6 +367,30 @@ static const struct can_bittiming_const
+       .brp_inc = 1,
+ };
++static const struct can_bittiming_const flexcan_fd_bittiming_const = {
++      .name = DRV_NAME,
++      .tseg1_min = 2,
++      .tseg1_max = 96,
++      .tseg2_min = 2,
++      .tseg2_max = 32,
++      .sjw_max = 16,
++      .brp_min = 1,
++      .brp_max = 1024,
++      .brp_inc = 1,
++};
++
++static const struct can_bittiming_const flexcan_fd_data_bittiming_const = {
++      .name = DRV_NAME,
++      .tseg1_min = 2,
++      .tseg1_max = 39,
++      .tseg2_min = 2,
++      .tseg2_max = 8,
++      .sjw_max = 4,
++      .brp_min = 1,
++      .brp_max = 1024,
++      .brp_inc = 1,
++};
++
+ /* FlexCAN module is essentially modelled as a little-endian IP in most
+  * SoCs, i.e the registers as well as the message buffer areas are
+  * implemented in a little-endian fashion.
+@@ -631,7 +685,7 @@ static netdev_tx_t flexcan_start_xmit(st
+       struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+       u32 can_id;
+       u32 data;
+-      u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cfd->len << 16);
++      u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | ((can_len2dlc(cfd->len)) << 16);
+       int i;
+       if (can_dropped_invalid_skb(dev, skb))
+@@ -649,6 +703,9 @@ static netdev_tx_t flexcan_start_xmit(st
+       if (cfd->can_id & CAN_RTR_FLAG)
+               ctrl |= FLEXCAN_MB_CNT_RTR;
++      if (can_is_canfd_skb(skb))
++              ctrl |= FLEXCAN_MB_CNT_EDL;
++
+       for (i = 0; i < cfd->len; i += sizeof(u32)) {
+               data = be32_to_cpup((__be32 *)&cfd->data[i]);
+               priv->write(data, &priv->tx_mb->data[i / sizeof(u32)]);
+@@ -859,7 +916,10 @@ static struct sk_buff *flexcan_mailbox_r
+               reg_ctrl = priv->read(&mb->can_ctrl);
+       }
+-      skb = alloc_can_skb(offload->dev, (struct can_frame **)&cfd);
++      if (reg_ctrl & FLEXCAN_MB_CNT_EDL)
++              skb = alloc_canfd_skb(offload->dev, &cfd);
++      else
++              skb = alloc_can_skb(offload->dev, (struct can_frame **)&cfd);
+       if (unlikely(!skb)) {
+               skb = ERR_PTR(-ENOMEM);
+               goto mark_as_read;
+@@ -874,9 +934,17 @@ static struct sk_buff *flexcan_mailbox_r
+       else
+               cfd->can_id = (reg_id >> 18) & CAN_SFF_MASK;
+-      if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
+-              cfd->can_id |= CAN_RTR_FLAG;
+-      cfd->len = get_can_dlc((reg_ctrl >> 16) & 0xf);
++      if (reg_ctrl & FLEXCAN_MB_CNT_EDL) {
++              cfd->len = can_dlc2len(get_canfd_dlc((reg_ctrl >> 16) & 0xf));
++      } else {
++              cfd->len = get_can_dlc((reg_ctrl >> 16) & 0xf);
++
++              if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
++                      cfd->can_id |= CAN_RTR_FLAG;
++      }
++
++      if (reg_ctrl & FLEXCAN_MB_CNT_ESI)
++              cfd->flags |= CANFD_ESI;
+       for (i = 0; i < cfd->len; i += sizeof(u32)) {
+               __be32 data = cpu_to_be32(priv->read(&mb->data[i / sizeof(u32)]));
+@@ -1021,27 +1089,14 @@ static irqreturn_t flexcan_irq(int irq,
+ static void flexcan_set_bittiming(struct net_device *dev)
+ {
+-      const struct flexcan_priv *priv = netdev_priv(dev);
+-      const struct can_bittiming *bt = &priv->can.bittiming;
++      struct flexcan_priv *priv = netdev_priv(dev);
++      struct can_bittiming *bt = &priv->can.bittiming;
++      struct can_bittiming *dbt = &priv->can.data_bittiming;
+       struct flexcan_regs __iomem *regs = priv->regs;
+-      u32 reg;
++      u32 reg, reg_cbt, reg_fdcbt;
+       reg = priv->read(&regs->ctrl);
+-      reg &= ~(FLEXCAN_CTRL_PRESDIV(0xff) |
+-               FLEXCAN_CTRL_RJW(0x3) |
+-               FLEXCAN_CTRL_PSEG1(0x7) |
+-               FLEXCAN_CTRL_PSEG2(0x7) |
+-               FLEXCAN_CTRL_PROPSEG(0x7) |
+-               FLEXCAN_CTRL_LPB |
+-               FLEXCAN_CTRL_SMP |
+-               FLEXCAN_CTRL_LOM);
+-
+-      reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) |
+-              FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) |
+-              FLEXCAN_CTRL_PSEG2(bt->phase_seg2 - 1) |
+-              FLEXCAN_CTRL_RJW(bt->sjw - 1) |
+-              FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1);
+-
++      reg &= ~(FLEXCAN_CTRL_LPB | FLEXCAN_CTRL_SMP | FLEXCAN_CTRL_LOM);
+       if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
+               reg |= FLEXCAN_CTRL_LPB;
+       if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+@@ -1052,9 +1107,102 @@ static void flexcan_set_bittiming(struct
+       netdev_dbg(dev, "writing ctrl=0x%08x\n", reg);
+       priv->write(reg, &regs->ctrl);
+-      /* print chip status */
+-      netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
+-                 priv->read(&regs->mcr), priv->read(&regs->ctrl));
++      if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
++              reg_cbt = priv->read(&regs->cbt);
++              reg_cbt &= ~(FLEXCAN_CBT_EPRESDIV(0x3ff) |
++                           FLEXCAN_CBT_EPSEG1(0x1f) |
++                           FLEXCAN_CBT_EPSEG2(0x1f) |
++                           FLEXCAN_CBT_ERJW(0x1f) |
++                           FLEXCAN_CBT_EPROPSEG(0x3f) |
++                           FLEXCAN_CBT_BTF);
++
++              /* CBT[EPSEG1] is 5 bit long and CBT[EPROPSEG] is 6 bit long.
++               * The can_calc_bittiming tries to divide the tseg1 equally
++               * between phase_seg1 and prop_seg, which may not fit in CBT
++               * register. Therefore, if phase_seg1 is more than possible
++               * value, increase prop_seg and decrease phase_seg1
++               */
++              if (bt->phase_seg1 > 0x20) {
++                      bt->prop_seg += (bt->phase_seg1 - 0x20);
++                      bt->phase_seg1 = 0x20;
++              }
++
++              reg_cbt = FLEXCAN_CBT_EPRESDIV(bt->brp - 1) |
++                              FLEXCAN_CBT_EPSEG1(bt->phase_seg1 - 1) |
++                              FLEXCAN_CBT_EPSEG2(bt->phase_seg2 - 1) |
++                              FLEXCAN_CBT_ERJW(bt->sjw - 1) |
++                              FLEXCAN_CBT_EPROPSEG(bt->prop_seg - 1) |
++                              FLEXCAN_CBT_BTF;
++              priv->write(reg_cbt, &regs->cbt);
++
++              netdev_dbg(dev, "bt: prediv %d seg1 %d seg2 %d rjw %d propseg %d\n",
++                         bt->brp - 1, bt->phase_seg1 - 1, bt->phase_seg2 - 1,
++                         bt->sjw - 1, bt->prop_seg - 1);
++
++              if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
++                      reg_fdcbt = priv->read(&regs->fdcbt);
++                      reg_fdcbt &= ~(FLEXCAN_FDCBT_FPRESDIV(0x3ff) |
++                                     FLEXCAN_FDCBT_FPSEG1(0x07) |
++                                     FLEXCAN_FDCBT_FPSEG2(0x07) |
++                                     FLEXCAN_FDCBT_FRJW(0x07) |
++                                     FLEXCAN_FDCBT_FPROPSEG(0x1f));
++
++                      /* FDCBT[FPSEG1] is 3 bit long and FDCBT[FPROPSEG] is 5 bit long.
++                       * The can_calc_bittiming tries to divide the tseg1 equally
++                       * between phase_seg1 and prop_seg, which may not fit in FDCBT
++                       * register. Therefore, if phase_seg1 is more than possible
++                       * value, increase prop_seg and decrease phase_seg1
++                       */
++                      if (dbt->phase_seg1 > 0x8) {
++                              dbt->prop_seg += (dbt->phase_seg1 - 0x8);
++                              dbt->phase_seg1 = 0x8;
++                      }
++
++                      reg_fdcbt = FLEXCAN_FDCBT_FPRESDIV(dbt->brp - 1) |
++                                      FLEXCAN_FDCBT_FPSEG1(dbt->phase_seg1 - 1) |
++                                      FLEXCAN_FDCBT_FPSEG2(dbt->phase_seg2 - 1) |
++                                      FLEXCAN_FDCBT_FRJW(dbt->sjw - 1) |
++                                      FLEXCAN_FDCBT_FPROPSEG(dbt->prop_seg);
++                      priv->write(reg_fdcbt, &regs->fdcbt);
++
++                      if (bt->brp != dbt->brp)
++                              netdev_warn(dev, "Warning!! data brp = %d and brp = %d don't match.\n"
++                                          "flexcan may not work. consider using different bitrate or data bitrate\n",
++                                          dbt->brp, bt->brp);
++
++                      netdev_dbg(dev, "fdbt: prediv %d seg1 %d seg2 %d rjw %d propseg %d\n",
++                                 dbt->brp - 1, dbt->phase_seg1 - 1, dbt->phase_seg2 - 1,
++                                 dbt->sjw - 1, dbt->prop_seg);
++
++                      netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x cbt=0x%08x fdcbt=0x%08x\n",
++                                 __func__, priv->read(&regs->mcr),
++                                 priv->read(&regs->ctrl),
++                                 priv->read(&regs->cbt),
++                                 priv->read(&regs->fdcbt));
++              }
++      } else {
++              reg = priv->read(&regs->ctrl);
++              reg &= ~(FLEXCAN_CTRL_PRESDIV(0xff) |
++                       FLEXCAN_CTRL_RJW(0x3) |
++                       FLEXCAN_CTRL_PSEG1(0x7) |
++                       FLEXCAN_CTRL_PSEG2(0x7) |
++                       FLEXCAN_CTRL_PROPSEG(0x7));
++
++              reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) |
++                      FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) |
++                      FLEXCAN_CTRL_PSEG2(bt->phase_seg2 - 1) |
++                      FLEXCAN_CTRL_RJW(bt->sjw - 1) |
++                      FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1);
++              priv->write(reg, &regs->ctrl);
++
++              netdev_dbg(dev, "bt: prediv %d seg1 %d seg2 %d rjw %d propseg %d\n",
++                         bt->brp - 1, bt->phase_seg1 - 1, bt->phase_seg2 - 1,
++                         bt->sjw - 1, bt->prop_seg - 1);
++
++              /* print chip status */
++              netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
++                         priv->read(&regs->mcr), priv->read(&regs->ctrl));
++      }
+ }
+ /* flexcan_chip_start
+@@ -1066,7 +1214,7 @@ static int flexcan_chip_start(struct net
+ {
+       struct flexcan_priv *priv = netdev_priv(dev);
+       struct flexcan_regs __iomem *regs = priv->regs;
+-      u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr;
++      u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr, reg_fdctrl;
+       u64 reg_imask;
+       int err, i;
+       struct flexcan_mb __iomem *mb;
+@@ -1163,6 +1311,26 @@ static int flexcan_chip_start(struct net
+       netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl);
+       priv->write(reg_ctrl, &regs->ctrl);
++      /* FDCTRL */
++      if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
++              reg_fdctrl = priv->read(&regs->fdctrl) & ~FLEXCAN_FDCTRL_FDRATE;
++              reg_fdctrl &= ~(FLEXCAN_FDCTRL_MBDSR1(0x3) | FLEXCAN_FDCTRL_MBDSR0(0x3));
++              reg_mcr = priv->read(&regs->mcr) & ~FLEXCAN_MCR_FDEN;
++
++              /* support BRS when set CAN FD mode
++               * 64 bytes payload per MB and 7 MBs per RAM block by default
++               * enable CAN FD mode
++               */
++              if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
++                      reg_fdctrl |= FLEXCAN_FDCTRL_FDRATE;
++                      reg_fdctrl |= FLEXCAN_FDCTRL_MBDSR1(0x3) | FLEXCAN_FDCTRL_MBDSR0(0x3);
++                      reg_mcr |= FLEXCAN_MCR_FDEN;
++              }
++
++              priv->write(reg_fdctrl, &regs->fdctrl);
++              priv->write(reg_mcr, &regs->mcr);
++      }
++
+       if ((priv->devtype_data->quirks & FLEXCAN_QUIRK_ENABLE_EACEN_RRS)) {
+               reg_ctrl2 = priv->read(&regs->ctrl2);
+               reg_ctrl2 |= FLEXCAN_CTRL2_EACEN | FLEXCAN_CTRL2_RRS;
+@@ -1288,6 +1456,12 @@ static int flexcan_open(struct net_devic
+       struct flexcan_priv *priv = netdev_priv(dev);
+       int err;
++      if ((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) &&
++          (priv->can.ctrlmode & CAN_CTRLMODE_FD)) {
++              netdev_err(dev, "three samples mode and fd mode can't be used together\n");
++              return -EINVAL;
++      }
++
+       err = pm_runtime_get_sync(priv->dev);
+       if (err < 0)
+               return err;
+@@ -1300,7 +1474,10 @@ static int flexcan_open(struct net_devic
+       if (err)
+               goto out_close;
+-      priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN;
++      if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
++              priv->mb_size = sizeof(struct flexcan_mb) + CANFD_MAX_DLEN;
++      else
++              priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN;
+       priv->mb_count = (sizeof(priv->regs->mb[0]) / priv->mb_size) +
+                        (sizeof(priv->regs->mb[1]) / priv->mb_size);
+@@ -1645,6 +1822,18 @@ static int flexcan_probe(struct platform
+       priv->devtype_data = devtype_data;
+       priv->reg_xceiver = reg_xceiver;
++      if (priv->devtype_data->quirks & FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD) {
++              if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
++                      priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
++                      priv->can.bittiming_const = &flexcan_fd_bittiming_const;
++                      priv->can.data_bittiming_const = &flexcan_fd_data_bittiming_const;
++              } else {
++                      dev_err(&pdev->dev, "can fd mode can't work on fifo mode\n");
++                      err = -EINVAL;
++                      goto failed_register;
++              }
++      }
++
+       pm_runtime_get_noresume(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
diff --git a/target/linux/layerscape/patches-5.4/802-can-0020-can-flexcan-add-CAN-FD-BRS-support.patch b/target/linux/layerscape/patches-5.4/802-can-0020-can-flexcan-add-CAN-FD-BRS-support.patch
new file mode 100644 (file)
index 0000000..d569c7f
--- /dev/null
@@ -0,0 +1,40 @@
+From 4c26434ac773e37f30ee5a8fa6f7275fe7dabac2 Mon Sep 17 00:00:00 2001
+From: Joakim Zhang <qiangqing.zhang@nxp.com>
+Date: Fri, 12 Jul 2019 08:02:47 +0000
+Subject: [PATCH] can: flexcan: add CAN FD BRS support
+
+This patch adds CAN FD BitRate Switch (BRS) support to driver.
+
+Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -703,9 +703,13 @@ static netdev_tx_t flexcan_start_xmit(st
+       if (cfd->can_id & CAN_RTR_FLAG)
+               ctrl |= FLEXCAN_MB_CNT_RTR;
+-      if (can_is_canfd_skb(skb))
++      if (can_is_canfd_skb(skb)) {
+               ctrl |= FLEXCAN_MB_CNT_EDL;
++              if (cfd->flags & CANFD_BRS)
++                      ctrl |= FLEXCAN_MB_CNT_BRS;
++      }
++
+       for (i = 0; i < cfd->len; i += sizeof(u32)) {
+               data = be32_to_cpup((__be32 *)&cfd->data[i]);
+               priv->write(data, &priv->tx_mb->data[i / sizeof(u32)]);
+@@ -936,6 +940,9 @@ static struct sk_buff *flexcan_mailbox_r
+       if (reg_ctrl & FLEXCAN_MB_CNT_EDL) {
+               cfd->len = can_dlc2len(get_canfd_dlc((reg_ctrl >> 16) & 0xf));
++
++              if (reg_ctrl & FLEXCAN_MB_CNT_BRS)
++                      cfd->flags |= CANFD_BRS;
+       } else {
+               cfd->len = get_can_dlc((reg_ctrl >> 16) & 0xf);
diff --git a/target/linux/layerscape/patches-5.4/802-can-0021-can-flexcan-add-ISO-CAN-FD-feature-support.patch b/target/linux/layerscape/patches-5.4/802-can-0021-can-flexcan-add-ISO-CAN-FD-feature-support.patch
new file mode 100644 (file)
index 0000000..df95f05
--- /dev/null
@@ -0,0 +1,65 @@
+From 094a648bc2217a9624f35224059c3eac86196143 Mon Sep 17 00:00:00 2001
+From: Joakim Zhang <qiangqing.zhang@nxp.com>
+Date: Fri, 12 Jul 2019 08:02:51 +0000
+Subject: [PATCH] can: flexcan: add ISO CAN FD feature support
+
+ISO CAN FD is introduced to increase the failture detection capability
+than non-ISO CAN FD. The non-ISO CAN FD is still supported by FlexCAN so
+that it can be used mainly during an intermediate phase, for evaluation
+and development purposes.
+
+Therefore, it is strongly recommended to configure FlexCAN to the ISO
+CAN FD protocol by setting the ISOCANFDEN field in the CTRL2 register.
+
+NOTE: If you only set "fd on", driver will use ISO FD mode by default.
+You should set "fd-non-iso on" after setting "fd on" if you want to use
+NON ISO FD mode.
+
+Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -92,6 +92,7 @@
+ #define FLEXCAN_CTRL2_MRP             BIT(18)
+ #define FLEXCAN_CTRL2_RRS             BIT(17)
+ #define FLEXCAN_CTRL2_EACEN           BIT(16)
++#define FLEXCAN_CTRL2_ISOCANFDEN      BIT(12)
+ /* FLEXCAN memory error control register (MECR) bits */
+ #define FLEXCAN_MECR_ECRWRDIS         BIT(31)
+@@ -1323,6 +1324,7 @@ static int flexcan_chip_start(struct net
+               reg_fdctrl = priv->read(&regs->fdctrl) & ~FLEXCAN_FDCTRL_FDRATE;
+               reg_fdctrl &= ~(FLEXCAN_FDCTRL_MBDSR1(0x3) | FLEXCAN_FDCTRL_MBDSR0(0x3));
+               reg_mcr = priv->read(&regs->mcr) & ~FLEXCAN_MCR_FDEN;
++              reg_ctrl2 = priv->read(&regs->ctrl2) & ~FLEXCAN_CTRL2_ISOCANFDEN;
+               /* support BRS when set CAN FD mode
+                * 64 bytes payload per MB and 7 MBs per RAM block by default
+@@ -1332,10 +1334,14 @@ static int flexcan_chip_start(struct net
+                       reg_fdctrl |= FLEXCAN_FDCTRL_FDRATE;
+                       reg_fdctrl |= FLEXCAN_FDCTRL_MBDSR1(0x3) | FLEXCAN_FDCTRL_MBDSR0(0x3);
+                       reg_mcr |= FLEXCAN_MCR_FDEN;
++
++                      if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO))
++                              reg_ctrl2 |= FLEXCAN_CTRL2_ISOCANFDEN;
+               }
+               priv->write(reg_fdctrl, &regs->fdctrl);
+               priv->write(reg_mcr, &regs->mcr);
++              priv->write(reg_ctrl2, &regs->ctrl2);
+       }
+       if ((priv->devtype_data->quirks & FLEXCAN_QUIRK_ENABLE_EACEN_RRS)) {
+@@ -1831,7 +1837,7 @@ static int flexcan_probe(struct platform
+       if (priv->devtype_data->quirks & FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD) {
+               if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
+-                      priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
++                      priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO;
+                       priv->can.bittiming_const = &flexcan_fd_bittiming_const;
+                       priv->can.data_bittiming_const = &flexcan_fd_data_bittiming_const;
+               } else {
diff --git a/target/linux/layerscape/patches-5.4/802-can-0022-can-flexcan-add-Transceiver-Delay-Compensation-suopp.patch b/target/linux/layerscape/patches-5.4/802-can-0022-can-flexcan-add-Transceiver-Delay-Compensation-suopp.patch
new file mode 100644 (file)
index 0000000..ee00ddb
--- /dev/null
@@ -0,0 +1,70 @@
+From 7b294e0cd2f7fbfb548a17b8d68d161da19e6592 Mon Sep 17 00:00:00 2001
+From: Joakim Zhang <qiangqing.zhang@nxp.com>
+Date: Fri, 12 Jul 2019 08:02:56 +0000
+Subject: [PATCH] can: flexcan: add Transceiver Delay Compensation suopport
+
+The CAN FD protocol allows the transmission and reception of data at a higher
+bit rate than the nominal rate used in the arbitration phase when the message's
+BRS bit is set.
+
+The TDC mechanism is effective only during the data phase of FD frames
+having BRS bit set. It has no effect either on non-FD frames, or on FD
+frames transmitted at normal bit rate.
+
+Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 19 ++++++++++++++++++-
+ 1 file changed, 18 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -149,8 +149,11 @@
+ /* FLEXCAN FD control register (FDCTRL) bits */
+ #define FLEXCAN_FDCTRL_FDRATE         BIT(31)
++#define FLEXCAN_FDCTRL_TDCEN          BIT(15)
++#define FLEXCAN_FDCTRL_TDCFAIL                BIT(14)
+ #define FLEXCAN_FDCTRL_MBDSR1(x)      (((x) & 0x3) << 19)
+ #define FLEXCAN_FDCTRL_MBDSR0(x)      (((x) & 0x3) << 16)
++#define FLEXCAN_FDCTRL_TDCOFF(x)      (((x) & 0x1f) << 8)
+ /* FLEXCAN FD Bit Timing register (FDCBT) bits */
+ #define FLEXCAN_FDCBT_FPRESDIV(x)     (((x) & 0x3ff) << 20)
+@@ -1101,7 +1104,7 @@ static void flexcan_set_bittiming(struct
+       struct can_bittiming *bt = &priv->can.bittiming;
+       struct can_bittiming *dbt = &priv->can.data_bittiming;
+       struct flexcan_regs __iomem *regs = priv->regs;
+-      u32 reg, reg_cbt, reg_fdcbt;
++      u32 reg, reg_cbt, reg_fdcbt, reg_fdctrl;
+       reg = priv->read(&regs->ctrl);
+       reg &= ~(FLEXCAN_CTRL_LPB | FLEXCAN_CTRL_SMP | FLEXCAN_CTRL_LOM);
+@@ -1173,6 +1176,19 @@ static void flexcan_set_bittiming(struct
+                                       FLEXCAN_FDCBT_FPROPSEG(dbt->prop_seg);
+                       priv->write(reg_fdcbt, &regs->fdcbt);
++                      /* enable transceiver delay compensation(TDC) for fd frame.
++                       * TDC must be disabled when Loop Back mode is enabled.
++                       */
++                      reg_fdctrl = priv->read(&regs->fdctrl);
++                      if (!(reg & FLEXCAN_CTRL_LPB)) {
++                              reg_fdctrl |= FLEXCAN_FDCTRL_TDCEN;
++                              reg_fdctrl &= ~FLEXCAN_FDCTRL_TDCOFF(0x1f);
++                              /* for the TDC to work reliably, the offset has to use optimal settings */
++                              reg_fdctrl |= FLEXCAN_FDCTRL_TDCOFF(((dbt->phase_seg1 - 1) + dbt->prop_seg + 2) *
++                                                                  ((dbt->brp -1) + 1));
++                      }
++                      priv->write(reg_fdctrl, &regs->fdctrl);
++
+                       if (bt->brp != dbt->brp)
+                               netdev_warn(dev, "Warning!! data brp = %d and brp = %d don't match.\n"
+                                           "flexcan may not work. consider using different bitrate or data bitrate\n",
+@@ -1322,6 +1338,7 @@ static int flexcan_chip_start(struct net
+       /* FDCTRL */
+       if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
+               reg_fdctrl = priv->read(&regs->fdctrl) & ~FLEXCAN_FDCTRL_FDRATE;
++              reg_fdctrl &= ~FLEXCAN_FDCTRL_TDCEN;
+               reg_fdctrl &= ~(FLEXCAN_FDCTRL_MBDSR1(0x3) | FLEXCAN_FDCTRL_MBDSR0(0x3));
+               reg_mcr = priv->read(&regs->mcr) & ~FLEXCAN_MCR_FDEN;
+               reg_ctrl2 = priv->read(&regs->ctrl2) & ~FLEXCAN_CTRL2_ISOCANFDEN;
diff --git a/target/linux/layerscape/patches-5.4/802-can-0023-can-flexcan-add-imx8qm-support.patch b/target/linux/layerscape/patches-5.4/802-can-0023-can-flexcan-add-imx8qm-support.patch
new file mode 100644 (file)
index 0000000..5690263
--- /dev/null
@@ -0,0 +1,62 @@
+From 7ff112c7b144fb084f28f944d7021cd04acabecd Mon Sep 17 00:00:00 2001
+From: Joakim Zhang <qiangqing.zhang@nxp.com>
+Date: Fri, 12 Jul 2019 08:02:59 +0000
+Subject: [PATCH] can: flexcan: add imx8qm support
+
+The Flexcan on i.MX8QM supports CAN FD protocol.
+
+Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 26 +++++++++++++++++---------
+ 1 file changed, 17 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -200,15 +200,16 @@
+ /* FLEXCAN hardware feature flags
+  *
+  * Below is some version info we got:
+- *    SOC   Version   IP-Version  Glitch- [TR]WRN_INT IRQ Err Memory err RTR re-
+- *                                Filter? connected?  Passive detection  ception in MB
+- *   MX25  FlexCAN2  03.00.00.00     no        no        no       no        no
+- *   MX28  FlexCAN2  03.00.04.00    yes       yes        no       no        no
+- *   MX35  FlexCAN2  03.00.00.00     no        no        no       no        no
+- *   MX53  FlexCAN2  03.00.00.00    yes        no        no       no        no
+- *   MX6s  FlexCAN3  10.00.12.00    yes       yes        no       no       yes
+- *   VF610 FlexCAN3  ?               no       yes        no      yes       yes?
+- * LS1021A FlexCAN2  03.00.04.00     no       yes        no       no       yes
++ *    SOC   Version   IP-Version  Glitch- [TR]WRN_INT IRQ Err Memory err RTR rece-   FD Mode
++ *                                Filter? connected?  Passive detection  ption in MB Supported?
++ *   MX25  FlexCAN2  03.00.00.00     no        no        no       no        no           no
++ *   MX28  FlexCAN2  03.00.04.00    yes       yes        no       no        no           no
++ *   MX35  FlexCAN2  03.00.00.00     no        no        no       no        no           no
++ *   MX53  FlexCAN2  03.00.00.00    yes        no        no       no        no           no
++ *   MX6s  FlexCAN3  10.00.12.00    yes       yes        no       no       yes           no
++ *  MX8QM  FlexCAN3  03.00.23.00    yes       yes        no       no       yes          yes
++ *   VF610 FlexCAN3  ?               no       yes        no      yes       yes?          no
++ * LS1021A FlexCAN2  03.00.04.00     no       yes        no       no       yes           no
+  *
+  * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected.
+  */
+@@ -347,6 +348,12 @@ static const struct flexcan_devtype_data
+               FLEXCAN_QUIRK_SETUP_STOP_MODE,
+ };
++static struct flexcan_devtype_data fsl_imx8qm_devtype_data = {
++      .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
++              FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
++              FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD,
++};
++
+ static const struct flexcan_devtype_data fsl_vf610_devtype_data = {
+       .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
+               FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP |
+@@ -1738,6 +1745,7 @@ out_put_node:
+ }
+ static const struct of_device_id flexcan_of_match[] = {
++      { .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, },
+       { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, },
+       { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, },
+       { .compatible = "fsl,imx53-flexcan", .data = &fsl_imx25_devtype_data, },
diff --git a/target/linux/layerscape/patches-5.4/802-can-0024-can-flexcan-add-lx2160ar1-support.patch b/target/linux/layerscape/patches-5.4/802-can-0024-can-flexcan-add-lx2160ar1-support.patch
new file mode 100644 (file)
index 0000000..aeb6a1c
--- /dev/null
@@ -0,0 +1,45 @@
+From 3e13fca177e84f94ce691fb90f36086812972eff Mon Sep 17 00:00:00 2001
+From: Pankaj Bansal <pankaj.bansal@nxp.com>
+Date: Fri, 12 Jul 2019 08:03:01 +0000
+Subject: [PATCH] can: flexcan: add lx2160ar1 support
+
+The Flexcan on lx2160ar1 supports CAN FD protocol.
+
+signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com>
+Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/flexcan.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -210,6 +210,7 @@
+  *  MX8QM  FlexCAN3  03.00.23.00    yes       yes        no       no       yes          yes
+  *   VF610 FlexCAN3  ?               no       yes        no      yes       yes?          no
+  * LS1021A FlexCAN2  03.00.04.00     no       yes        no       no       yes           no
++ * LX2160A FlexCAN3  03.00.23.00     no       yes        no       no       yes          yes
+  *
+  * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected.
+  */
+@@ -360,6 +361,12 @@ static const struct flexcan_devtype_data
+               FLEXCAN_QUIRK_BROKEN_PERR_STATE,
+ };
++static const struct flexcan_devtype_data fsl_lx2160a_r1_devtype_data = {
++      .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
++              FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
++              FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD,
++};
++
+ static const struct flexcan_devtype_data fsl_ls1021a_r2_devtype_data = {
+       .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
+               FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
+@@ -1754,6 +1761,7 @@ static const struct of_device_id flexcan
+       { .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, },
+       { .compatible = "fsl,vf610-flexcan", .data = &fsl_vf610_devtype_data, },
+       { .compatible = "fsl,ls1021ar2-flexcan", .data = &fsl_ls1021a_r2_devtype_data, },
++      { .compatible = "fsl,lx2160ar1-flexcan", .data = &fsl_lx2160a_r1_devtype_data, },
+       { /* sentinel */ },
+ };
+ MODULE_DEVICE_TABLE(of, flexcan_of_match);
diff --git a/target/linux/layerscape/patches-5.4/802-can-0025-can-flexcan-add-LPSR-mode-support-for-i.MX7D.patch b/target/linux/layerscape/patches-5.4/802-can-0025-can-flexcan-add-LPSR-mode-support-for-i.MX7D.patch
new file mode 100644 (file)
index 0000000..afb5557
--- /dev/null
@@ -0,0 +1,93 @@
+From 211c20a459a0fd4868ed22ecfc2b2186d9df6da0 Mon Sep 17 00:00:00 2001
+From: Joakim Zhang <qiangqing.zhang@nxp.com>
+Date: Tue, 30 Jul 2019 14:43:25 +0800
+Subject: [PATCH] can: flexcan: add LPSR mode support for i.MX7D
+
+For i.MX7D LPSR mode, the controller will lost power and got the
+configuration state lost after system resume back.
+So we need to set pinctrl state again and re-start chip to do
+re-configuration after resume.
+
+For wakeup case, it should not set pinctrl to sleep state by
+pinctrl_pm_select_sleep_state.
+For interface is not up before suspend case, we don't need
+re-configure as it will be configured by user later by interface up.
+
+Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
+---
+ drivers/net/can/flexcan.c | 21 ++++++++++++++-------
+ 1 file changed, 14 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -26,6 +26,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/regulator/consumer.h>
++#include <linux/pinctrl/consumer.h>
+ #include <linux/regmap.h>
+ #define DRV_NAME                      "flexcan"
+@@ -1920,7 +1921,7 @@ static int __maybe_unused flexcan_suspen
+ {
+       struct net_device *dev = dev_get_drvdata(device);
+       struct flexcan_priv *priv = netdev_priv(dev);
+-      int err = 0;
++      int err;
+       if (netif_running(dev)) {
+               /* if wakeup is enabled, enter stop mode
+@@ -1932,25 +1933,27 @@ static int __maybe_unused flexcan_suspen
+                       if (err)
+                               return err;
+               } else {
+-                      err = flexcan_chip_disable(priv);
++                      flexcan_chip_stop(dev);
++
++                      err = pm_runtime_force_suspend(device);
+                       if (err)
+                               return err;
+-                      err = pm_runtime_force_suspend(device);
++                      pinctrl_pm_select_sleep_state(device);
+               }
+               netif_stop_queue(dev);
+               netif_device_detach(dev);
+       }
+       priv->can.state = CAN_STATE_SLEEPING;
+-      return err;
++      return 0;
+ }
+ static int __maybe_unused flexcan_resume(struct device *device)
+ {
+       struct net_device *dev = dev_get_drvdata(device);
+       struct flexcan_priv *priv = netdev_priv(dev);
+-      int err = 0;
++      int err;
+       priv->can.state = CAN_STATE_ERROR_ACTIVE;
+       if (netif_running(dev)) {
+@@ -1962,15 +1965,19 @@ static int __maybe_unused flexcan_resume
+                       if (err)
+                               return err;
+               } else {
++                      pinctrl_pm_select_default_state(device);
++
+                       err = pm_runtime_force_resume(device);
+                       if (err)
+                               return err;
+-                      err = flexcan_chip_enable(priv);
++                      err = flexcan_chip_start(dev);
++                      if (err)
++                              return err;
+               }
+       }
+-      return err;
++      return 0;
+ }
+ static int __maybe_unused flexcan_runtime_suspend(struct device *device)
diff --git a/target/linux/layerscape/patches-5.4/802-can-0026-can-flexcan-fix-deadlock-when-using-self-wakeup.patch b/target/linux/layerscape/patches-5.4/802-can-0026-can-flexcan-fix-deadlock-when-using-self-wakeup.patch
new file mode 100644 (file)
index 0000000..a771395
--- /dev/null
@@ -0,0 +1,62 @@
+From 59876225748221d7ebbdb9c892a2086420ddd80d Mon Sep 17 00:00:00 2001
+From: Sean Nyekjaer <sean@geanix.com>
+Date: Thu, 14 Nov 2019 19:56:28 +0800
+Subject: [PATCH] can: flexcan: fix deadlock when using self wakeup
+
+When suspending, when there is still can traffic on the interfaces the
+flexcan immediately wakes the platform again. As it should :-). But it
+throws this error msg:
+[ 3169.378661] PM: noirq suspend of devices failed
+
+On the way down to suspend the interface that throws the error message does
+call flexcan_suspend but fails to call flexcan_noirq_suspend. That means the
+flexcan_enter_stop_mode is called, but on the way out of suspend the driver
+only calls flexcan_resume and skips flexcan_noirq_resume, thus it doesn't call
+flexcan_exit_stop_mode. This leaves the flexcan in stop mode, and with the
+current driver it can't recover from this even with a soft reboot, it requires
+a hard reboot.
+
+This patch can fix deadlock when using self wakeup, it happenes to be
+able to fix another issue that frames out-of-order in first IRQ handler
+run after wakeup.
+
+In wakeup case, after system resume, frames received out-of-order,the
+problem is wakeup latency from frame reception to IRQ handler is much
+bigger than the counter overflow. This means it's impossible to sort the
+CAN frames by timestamp. The reason is that controller exits stop mode
+during noirq resume, then it can receive the frame immediately. If
+noirq reusme stage consumes much time, it will extend interrupt response
+time.
+
+Fixes: de3578c198c6 ("can: flexcan: add self wakeup support")
+Signed-off-by: Sean Nyekjaer <sean@geanix.com>
+Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
+---
+ drivers/net/can/flexcan.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -137,8 +137,7 @@
+       (FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE)
+ #define FLEXCAN_ESR_ALL_INT \
+       (FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | \
+-       FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT | \
+-       FLEXCAN_ESR_WAK_INT)
++       FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT)
+ /* FLEXCAN Bit Timing register (CBT) bits */
+ #define FLEXCAN_CBT_BTF                       BIT(31)
+@@ -1055,6 +1054,12 @@ static irqreturn_t flexcan_irq(int irq,
+       reg_esr = priv->read(&regs->esr);
++      /* ACK wakeup interrupt */
++      if (reg_esr & FLEXCAN_ESR_WAK_INT) {
++              handled = IRQ_HANDLED;
++              priv->write(reg_esr & FLEXCAN_ESR_WAK_INT, &regs->esr);
++      }
++
+       /* ACK all bus error and state change IRQ sources */
+       if (reg_esr & FLEXCAN_ESR_ALL_INT) {
+               handled = IRQ_HANDLED;
diff --git a/target/linux/layerscape/patches-5.4/802-can-0027-can-flexcan-add-CAN-wakeup-function-for-i.MX8.patch b/target/linux/layerscape/patches-5.4/802-can-0027-can-flexcan-add-CAN-wakeup-function-for-i.MX8.patch
new file mode 100644 (file)
index 0000000..bf0eac4
--- /dev/null
@@ -0,0 +1,193 @@
+From 140de383d9d26e8be300b7ba86d56b47898cd8c9 Mon Sep 17 00:00:00 2001
+From: Joakim Zhang <qiangqing.zhang@nxp.com>
+Date: Tue, 30 Jul 2019 18:01:11 +0800
+Subject: [PATCH] can: flexcan: add CAN wakeup function for i.MX8
+
+The System Controller Firmware (SCFW) is a low-level system function
+which runs on a dedicated Cortex-M core to provide power, clock, and
+resource management. It exists on some i.MX8 processors. e.g. i.MX8QM
+(QM, QP), and i.MX8QX (QXP, DX).
+
+SCU driver manages the IPC interface between host CPU and the
+SCU firmware running on M4.
+
+For i.MX8, stop mode request is controlled by System Controller Unit(SCU)
+firmware.
+
+Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
+---
+ drivers/net/can/flexcan.c | 99 ++++++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 86 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -29,6 +29,11 @@
+ #include <linux/pinctrl/consumer.h>
+ #include <linux/regmap.h>
++#ifdef CONFIG_IMX_SCU_SOC
++#include <linux/firmware/imx/sci.h>
++#include <dt-bindings/firmware/imx/rsrc.h>
++#endif
++
+ #define DRV_NAME                      "flexcan"
+ /* 8 for RX fifo and 2 error handling */
+@@ -223,6 +228,7 @@
+ #define FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN      BIT(7) /* default to BE register access */
+ #define FLEXCAN_QUIRK_SETUP_STOP_MODE         BIT(8) /* Setup stop mode to support wakeup */
+ #define FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD    BIT(9) /* Use timestamp then support can fd mode */
++#define FLEXCAN_QUIRK_USE_SCFW                        BIT(10) /* Use System Controller Firmware */
+ /* Structure of the message buffer */
+ struct flexcan_mb {
+@@ -323,6 +329,11 @@ struct flexcan_priv {
+       struct regulator *reg_xceiver;
+       struct flexcan_stop_mode stm;
++#ifdef CONFIG_IMX_SCU_SOC
++      /* IPC handle when enable stop mode by System Controller firmware(scfw) */
++      struct imx_sc_ipc *sc_ipc_handle;
++#endif
++
+       /* Read and Write APIs */
+       u32 (*read)(void __iomem *addr);
+       void (*write)(u32 val, void __iomem *addr);
+@@ -352,7 +363,8 @@ static const struct flexcan_devtype_data
+ static struct flexcan_devtype_data fsl_imx8qm_devtype_data = {
+       .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
+               FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
+-              FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD,
++              FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD | FLEXCAN_QUIRK_SETUP_STOP_MODE |
++              FLEXCAN_QUIRK_USE_SCFW,
+ };
+ static const struct flexcan_devtype_data fsl_vf610_devtype_data = {
+@@ -504,6 +516,32 @@ static void flexcan_enable_wakeup_irq(st
+       priv->write(reg_mcr, &regs->mcr);
+ }
++#ifdef CONFIG_IMX_SCU_SOC
++static void flexcan_stop_mode_enable_scfw(struct flexcan_priv *priv, bool enabled)
++{
++      struct device_node *np = priv->dev->of_node;
++      u32 rsrc_id, val;
++      int idx;
++
++      idx = of_alias_get_id(np, "can");
++      if (idx == 0)
++              rsrc_id = IMX_SC_R_CAN_0;
++      else if (idx == 1)
++              rsrc_id = IMX_SC_R_CAN_1;
++      else
++              rsrc_id = IMX_SC_R_CAN_2;
++
++      val = enabled ? 1 : 0;
++      /* stop mode request */
++      imx_sc_misc_set_control(priv->sc_ipc_handle, rsrc_id, IMX_SC_C_IPG_STOP, val);
++}
++#else
++static int flexcan_stop_mode_enable_scfw(struct flexcan_priv *priv, bool enabled)
++{
++      return 0;
++}
++#endif
++
+ static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv)
+ {
+       struct flexcan_regs __iomem *regs = priv->regs;
+@@ -513,9 +551,12 @@ static inline int flexcan_enter_stop_mod
+       reg_mcr |= FLEXCAN_MCR_SLF_WAK;
+       priv->write(reg_mcr, &regs->mcr);
+-      /* enable stop request */
+-      regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
+-                         1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
++       /* enable stop request */
++      if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_SCFW)
++              flexcan_stop_mode_enable_scfw(priv, true);
++      else
++              regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
++                                 1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
+       return flexcan_low_power_enter_ack(priv);
+ }
+@@ -526,8 +567,11 @@ static inline int flexcan_exit_stop_mode
+       u32 reg_mcr;
+       /* remove stop request */
+-      regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
+-                         1 << priv->stm.req_bit, 0);
++      if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_SCFW)
++              flexcan_stop_mode_enable_scfw(priv, false);
++      else
++              regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
++                                 1 << priv->stm.req_bit, 0);
+       reg_mcr = priv->read(&regs->mcr);
+@@ -1745,11 +1789,6 @@ static int flexcan_setup_stop_mode(struc
+               gpr_np->full_name, priv->stm.req_gpr, priv->stm.req_bit,
+               priv->stm.ack_gpr, priv->stm.ack_bit);
+-      device_set_wakeup_capable(&pdev->dev, true);
+-
+-      if (of_property_read_bool(np, "wakeup-source"))
+-              device_set_wakeup_enable(&pdev->dev, true);
+-
+       return 0;
+ out_put_node:
+@@ -1757,6 +1796,30 @@ out_put_node:
+       return ret;
+ }
++#ifdef CONFIG_IMX_SCU_SOC
++static int flexcan_setup_stop_mode_scfw(struct platform_device *pdev)
++{
++      struct net_device *dev = platform_get_drvdata(pdev);
++      struct flexcan_priv *priv;
++      int ret;
++
++      priv = netdev_priv(dev);
++
++      ret = imx_scu_get_handle(&(priv->sc_ipc_handle));
++      if (ret < 0) {
++              dev_err(&pdev->dev, "get ipc handle used by SCU failed\n");
++              return ret;
++      }
++
++      return 0;
++}
++#else
++static int flexcan_setup_stop_mode_scfw(struct platform_device *pdev)
++{
++      return 0;
++}
++#endif
++
+ static const struct of_device_id flexcan_of_match[] = {
+       { .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, },
+       { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, },
+@@ -1899,9 +1962,19 @@ static int flexcan_probe(struct platform
+       devm_can_led_init(dev);
+       if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE) {
+-              err = flexcan_setup_stop_mode(pdev);
+-              if (err)
++              if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_SCFW)
++                      err = flexcan_setup_stop_mode_scfw(pdev);
++              else
++                      err = flexcan_setup_stop_mode(pdev);
++
++              if (err) {
+                       dev_dbg(&pdev->dev, "failed to setup stop-mode\n");
++              } else {
++                      device_set_wakeup_capable(&pdev->dev, true);
++
++                      if (of_property_read_bool(pdev->dev.of_node, "wakeup-source"))
++                              device_set_wakeup_enable(&pdev->dev, true);
++              }
+       }
+       return 0;
diff --git a/target/linux/layerscape/patches-5.4/802-can-0028-can-flexcan-Add-S32V234-support-to-FlexCAN-driver.patch b/target/linux/layerscape/patches-5.4/802-can-0028-can-flexcan-Add-S32V234-support-to-FlexCAN-driver.patch
new file mode 100644 (file)
index 0000000..0474969
--- /dev/null
@@ -0,0 +1,47 @@
+From 6a892e9147ff5b6a21a752326841869427068f01 Mon Sep 17 00:00:00 2001
+From: Chircu-Mare Bogdan-Petru <Bogdan.Chircu@freescale.com>
+Date: Tue, 3 Nov 2015 17:25:46 +0200
+Subject: [PATCH] can: flexcan: Add S32V234 support to FlexCAN driver
+
+The FlexCAN driver is compatible with the modules on S32V234 chips.
+
+Signed-off-by: Chircu-Mare Bogdan-Petru <Bogdan.Chircu@freescale.com>
+Signed-off-by: Dan Nica <dan.nica@nxp.com>
+Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
+Reviewed-by: Li Yang <leoyang.li@nxp.com>
+Reviewed-by: Joakim Zhang <qiangqing.zhang@nxp.com>
+Reviewed-by: Leonard Crestez <leonard.crestez@nxp.com>
+---
+ drivers/net/can/flexcan.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/net/can/flexcan.c
++++ b/drivers/net/can/flexcan.c
+@@ -6,6 +6,7 @@
+ // Copyright (c) 2009 Sascha Hauer, Pengutronix
+ // Copyright (c) 2010-2017 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de>
+ // Copyright (c) 2014 David Jander, Protonic Holland
++// Copyright 2015, 2018 NXP
+ //
+ // Based on code originally by Andrey Volkov <avolkov@varma-el.com>
+@@ -385,6 +386,10 @@ static const struct flexcan_devtype_data
+               FLEXCAN_QUIRK_USE_OFF_TIMESTAMP,
+ };
++static struct flexcan_devtype_data fsl_s32v234_devtype_data = {
++      .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_DISABLE_MECR,
++};
++
+ static const struct can_bittiming_const flexcan_bittiming_const = {
+       .name = DRV_NAME,
+       .tseg1_min = 4,
+@@ -1831,6 +1836,8 @@ static const struct of_device_id flexcan
+       { .compatible = "fsl,vf610-flexcan", .data = &fsl_vf610_devtype_data, },
+       { .compatible = "fsl,ls1021ar2-flexcan", .data = &fsl_ls1021a_r2_devtype_data, },
+       { .compatible = "fsl,lx2160ar1-flexcan", .data = &fsl_lx2160a_r1_devtype_data, },
++      { .compatible = "fsl,s32v234-flexcan",
++        .data = &fsl_s32v234_devtype_data, },
+       { /* sentinel */ },
+ };
+ MODULE_DEVICE_TABLE(of, flexcan_of_match);
diff --git a/target/linux/layerscape/patches-5.4/803-clock-0001-clk-ls1028a-Add-clock-driver-for-Display-output-inte.patch b/target/linux/layerscape/patches-5.4/803-clock-0001-clk-ls1028a-Add-clock-driver-for-Display-output-inte.patch
new file mode 100644 (file)
index 0000000..9d548d5
--- /dev/null
@@ -0,0 +1,351 @@
+From e9e60d44268e2cfba73efeb7c3e68c355940f2c3 Mon Sep 17 00:00:00 2001
+From: Wen He <wen.he_1@nxp.com>
+Date: Wed, 27 Nov 2019 11:19:26 +0800
+Subject: [PATCH] clk: ls1028a: Add clock driver for Display output interface
+
+Add clock driver for QorIQ LS1028A Display output interfaces(LCD, DPHY),
+as implemented in TSMC CLN28HPM PLL, this PLL supports the programmable
+integer division and range of the display output pixel clock's 27-594MHz.
+
+Signed-off-by: Wen He <wen.he_1@nxp.com>
+Signed-off-by: Michael Walle <michael@walle.cc>
+---
+ drivers/clk/Kconfig      |  10 ++
+ drivers/clk/Makefile     |   1 +
+ drivers/clk/clk-plldig.c | 301 +++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 312 insertions(+)
+ create mode 100644 drivers/clk/clk-plldig.c
+
+--- a/drivers/clk/Kconfig
++++ b/drivers/clk/Kconfig
+@@ -218,6 +218,16 @@ config CLK_QORIQ
+         This adds the clock driver support for Freescale QorIQ platforms
+         using common clock framework.
++config CLK_LS1028A_PLLDIG
++        tristate "Clock driver for LS1028A Display output"
++        depends on ARCH_LAYERSCAPE || COMPILE_TEST
++        default ARCH_LAYERSCAPE
++        help
++          This driver support the Display output interfaces(LCD, DPHY) pixel clocks
++          of the QorIQ Layerscape LS1028A, as implemented TSMC CLN28HPM PLL. Not all
++          features of the PLL are currently supported by the driver. By default,
++          configured bypass mode with this PLL.
++
+ config COMMON_CLK_XGENE
+       bool "Clock driver for APM XGene SoC"
+       default ARCH_XGENE
+--- a/drivers/clk/Makefile
++++ b/drivers/clk/Makefile
+@@ -43,6 +43,7 @@ obj-$(CONFIG_ARCH_NPCM7XX)           += clk-n
+ obj-$(CONFIG_ARCH_NSPIRE)             += clk-nspire.o
+ obj-$(CONFIG_COMMON_CLK_OXNAS)                += clk-oxnas.o
+ obj-$(CONFIG_COMMON_CLK_PALMAS)               += clk-palmas.o
++obj-$(CONFIG_CLK_LS1028A_PLLDIG)      += clk-plldig.o
+ obj-$(CONFIG_COMMON_CLK_PWM)          += clk-pwm.o
+ obj-$(CONFIG_CLK_QORIQ)                       += clk-qoriq.o
+ obj-$(CONFIG_COMMON_CLK_RK808)                += clk-rk808.o
+--- /dev/null
++++ b/drivers/clk/clk-plldig.c
+@@ -0,0 +1,301 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright 2019 NXP
++ *
++ * Clock driver for LS1028A Display output interfaces(LCD, DPHY).
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/iopoll.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/bitfield.h>
++
++/* PLLDIG register offsets and bit masks */
++#define PLLDIG_REG_PLLSR            0x24
++#define PLLDIG_LOCK_MASK            BIT(2)
++#define PLLDIG_REG_PLLDV            0x28
++#define PLLDIG_MFD_MASK             GENMASK(7, 0)
++#define PLLDIG_RFDPHI1_MASK         GENMASK(30, 25)
++#define PLLDIG_REG_PLLFM            0x2c
++#define PLLDIG_SSCGBYP_ENABLE       BIT(30)
++#define PLLDIG_REG_PLLFD            0x30
++#define PLLDIG_FDEN                 BIT(30)
++#define PLLDIG_FRAC_MASK            GENMASK(15, 0)
++#define PLLDIG_DTH_MASK             GENMASK(17, 16)
++#define PLLDIG_DTH_DISABLE          3
++#define PLLDIG_REG_PLLCAL1          0x38
++#define PLLDIG_REG_PLLCAL2          0x3c
++
++/* Range of the VCO frequencies, in Hz */
++#define PLLDIG_MIN_VCO_FREQ         650000000
++#define PLLDIG_MAX_VCO_FREQ         1300000000
++
++/* Range of the output frequencies, in Hz */
++#define PHI1_MIN_FREQ               27000000
++#define PHI1_MAX_FREQ               600000000
++
++/* Maximum value of the reduced frequency divider */
++#define MAX_RFDPHI1          63UL
++
++/* Best value of multiplication factor divider */
++#define PLLDIG_DEFAULT_MFD   44
++
++/*
++ * Denominator part of the fractional part of the
++ * loop multiplication factor.
++ */
++#define MFDEN          20480
++
++static const struct clk_parent_data parent_data[] = {
++      {.index = 0},
++};
++
++struct clk_plldig {
++      struct clk_hw hw;
++      void __iomem *regs;
++      unsigned int vco_freq;
++};
++
++#define to_clk_plldig(_hw)    container_of(_hw, struct clk_plldig, hw)
++
++static int plldig_enable(struct clk_hw *hw)
++{
++      struct clk_plldig *data = to_clk_plldig(hw);
++      u32 val;
++
++      val = readl(data->regs + PLLDIG_REG_PLLFM);
++      /*
++       * Use Bypass mode with PLL off by default, the frequency overshoot
++       * detector output was disable. SSCG Bypass mode should be enable.
++       */
++      val |= PLLDIG_SSCGBYP_ENABLE;
++      writel(val, data->regs + PLLDIG_REG_PLLFM);
++
++      return 0;
++}
++
++static void plldig_disable(struct clk_hw *hw)
++{
++      struct clk_plldig *data = to_clk_plldig(hw);
++      u32 val;
++
++      val = readl(data->regs + PLLDIG_REG_PLLFM);
++
++      val &= ~PLLDIG_SSCGBYP_ENABLE;
++      val |= FIELD_PREP(PLLDIG_SSCGBYP_ENABLE, 0x0);
++
++      writel(val, data->regs + PLLDIG_REG_PLLFM);
++}
++
++static int plldig_is_enabled(struct clk_hw *hw)
++{
++      struct clk_plldig *data = to_clk_plldig(hw);
++
++      return (readl(data->regs + PLLDIG_REG_PLLFM) &
++                            PLLDIG_SSCGBYP_ENABLE);
++}
++
++static unsigned long plldig_recalc_rate(struct clk_hw *hw,
++                                      unsigned long parent_rate)
++{
++      struct clk_plldig *data = to_clk_plldig(hw);
++      u32 val, rfdphi1;
++
++      val = readl(data->regs + PLLDIG_REG_PLLDV);
++
++      /* Check if PLL is bypassed */
++      if (val & PLLDIG_SSCGBYP_ENABLE)
++              return parent_rate;
++
++      rfdphi1 = FIELD_GET(PLLDIG_RFDPHI1_MASK, val);
++
++      /*
++       * If RFDPHI1 has a value of 1 the VCO frequency is also divided by
++       * one.
++       */
++      if (!rfdphi1)
++              rfdphi1 = 1;
++
++      return DIV_ROUND_UP(data->vco_freq, rfdphi1);
++}
++
++static unsigned long plldig_calc_target_div(unsigned long vco_freq,
++                                          unsigned long target_rate)
++{
++      unsigned long div;
++
++      div = DIV_ROUND_CLOSEST(vco_freq, target_rate);
++      div = max(1UL, div);
++      div = min(div, MAX_RFDPHI1);
++
++      return div;
++}
++
++static int plldig_determine_rate(struct clk_hw *hw,
++                               struct clk_rate_request *req)
++{
++      struct clk_plldig *data = to_clk_plldig(hw);
++      unsigned int div;
++
++      if (req->rate < PHI1_MIN_FREQ)
++              req->rate = PHI1_MIN_FREQ;
++      if (req->rate > PHI1_MAX_FREQ)
++              req->rate = PHI1_MAX_FREQ;
++
++      div = plldig_calc_target_div(data->vco_freq, req->rate);
++      req->rate = DIV_ROUND_UP(data->vco_freq, div);
++
++      return 0;
++}
++
++static int plldig_set_rate(struct clk_hw *hw, unsigned long rate,
++              unsigned long parent_rate)
++{
++      struct clk_plldig *data = to_clk_plldig(hw);
++      unsigned int val, cond;
++      unsigned int rfdphi1;
++
++      if (rate < PHI1_MIN_FREQ)
++              rate = PHI1_MIN_FREQ;
++      if (rate > PHI1_MAX_FREQ)
++              rate = PHI1_MAX_FREQ;
++
++      rfdphi1 = plldig_calc_target_div(data->vco_freq, rate);
++
++      /* update the divider value */
++      val = readl(data->regs + PLLDIG_REG_PLLDV);
++      val &= ~PLLDIG_RFDPHI1_MASK;
++      val |= FIELD_PREP(PLLDIG_RFDPHI1_MASK, rfdphi1);
++      writel(val, data->regs + PLLDIG_REG_PLLDV);
++
++      /* delay 200us make sure that old lock state is cleared */
++      udelay(200);
++
++      /* Wait until PLL is locked or timeout (maximum 1000 usecs) */
++      return readl_poll_timeout_atomic(data->regs + PLLDIG_REG_PLLSR, cond,
++                                       cond & PLLDIG_LOCK_MASK, 0,
++                                       USEC_PER_MSEC);
++}
++
++static const struct clk_ops plldig_clk_ops = {
++      .enable = plldig_enable,
++      .disable = plldig_disable,
++      .is_enabled = plldig_is_enabled,
++      .recalc_rate = plldig_recalc_rate,
++      .determine_rate = plldig_determine_rate,
++      .set_rate = plldig_set_rate,
++};
++
++static int plldig_init(struct clk_hw *hw)
++{
++      struct clk_plldig *data = to_clk_plldig(hw);
++      struct clk_hw *parent = clk_hw_get_parent(hw);
++      unsigned long parent_rate = clk_hw_get_rate(parent);
++      unsigned long val;
++      unsigned long long lltmp;
++      unsigned int mfd, fracdiv = 0;
++
++      if (!parent)
++              return -EINVAL;
++
++      if (data->vco_freq) {
++              mfd = data->vco_freq / parent_rate;
++              lltmp = data->vco_freq % parent_rate;
++              lltmp *= MFDEN;
++              do_div(lltmp, parent_rate);
++              fracdiv = lltmp;
++      } else {
++              mfd = PLLDIG_DEFAULT_MFD;
++              data->vco_freq = parent_rate * mfd;
++      }
++
++      val = FIELD_PREP(PLLDIG_MFD_MASK, mfd);
++      writel(val, data->regs + PLLDIG_REG_PLLDV);
++
++      if (fracdiv) {
++              val = FIELD_PREP(PLLDIG_FRAC_MASK, fracdiv);
++              /* Enable fractional divider */
++              val |= PLLDIG_FDEN;
++              /* Disable dither */
++              val |= FIELD_PREP(PLLDIG_DTH_MASK, PLLDIG_DTH_DISABLE);
++              writel(val, data->regs + PLLDIG_REG_PLLFD);
++      }
++
++      return 0;
++}
++
++static int plldig_clk_probe(struct platform_device *pdev)
++{
++      struct clk_plldig *data;
++      struct resource *mem;
++      struct device *dev = &pdev->dev;
++      int ret;
++
++      data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
++      if (!data)
++              return -ENOMEM;
++
++      mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      data->regs = devm_ioremap_resource(dev, mem);
++      if (IS_ERR(data->regs))
++              return PTR_ERR(data->regs);
++
++      data->hw.init = CLK_HW_INIT_PARENTS_DATA("dpclk",
++                                               parent_data,
++                                               &plldig_clk_ops,
++                                               0);
++
++      ret = devm_clk_hw_register(dev, &data->hw);
++      if (ret) {
++              dev_err(dev, "failed to register %s clock\n",
++                                              dev->of_node->name);
++              return ret;
++      }
++
++      ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
++                                        &data->hw);
++      if (ret) {
++              dev_err(dev, "unable to add clk provider\n");
++              return ret;
++      }
++
++      /*
++       * The frequency of the VCO cannot be changed during runtime.
++       * Therefore, let the user specify a desired frequency.
++       */
++      if (!of_property_read_u32(dev->of_node, "vco-frequency",
++                                &data->vco_freq)) {
++              if (data->vco_freq < PLLDIG_MIN_VCO_FREQ ||
++                  data->vco_freq > PLLDIG_MAX_VCO_FREQ)
++                      return -EINVAL;
++      }
++
++      return plldig_init(&data->hw);
++}
++
++static const struct of_device_id plldig_clk_id[] = {
++      { .compatible = "fsl,ls1028a-plldig"},
++      { }
++};
++MODULE_DEVICE_TABLE(of, plldig_clk_id);
++
++static struct platform_driver plldig_clk_driver = {
++      .driver = {
++              .name = "plldig-clock",
++              .of_match_table = plldig_clk_id,
++      },
++      .probe = plldig_clk_probe,
++};
++module_platform_driver(plldig_clk_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Wen He <wen.he_1@nxp.com>");
++MODULE_DESCRIPTION("LS1028A Display output interface pixel clock driver");
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0001-crypto-add-support-for-TLS-1.0-record-encryption.patch b/target/linux/layerscape/patches-5.4/804-crypto-0001-crypto-add-support-for-TLS-1.0-record-encryption.patch
new file mode 100644 (file)
index 0000000..ad557fa
--- /dev/null
@@ -0,0 +1,1205 @@
+From 223db480c54de8ec47b3b0b4c6066b58342a5ad4 Mon Sep 17 00:00:00 2001
+From: Radu Alexe <radu.alexe@nxp.com>
+Date: Wed, 3 May 2017 16:17:13 +0300
+Subject: [PATCH] crypto: add support for TLS 1.0 record encryption
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch adds kernel support for encryption/decryption of TLS 1.0
+records using block ciphers. Implementation is similar to authenc in the
+sense that the base algorithms (AES, SHA1) are combined in a template to
+produce TLS encapsulation frames. The composite algorithm will be called
+"tls10(hmac(<digest>),cbc(<cipher>))". The cipher and hmac keys are
+wrapped in the same format used by authenc.c.
+
+Signed-off-by: Radu Alexe <radu.alexe@nxp.com>
+Signed-off-by: Cristian Stoica <cristian.stoica@nxp.com>
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ crypto/Kconfig   |  20 ++
+ crypto/Makefile  |   1 +
+ crypto/tcrypt.c  |   3 +
+ crypto/testmgr.c | 238 ++++++++++++++++++++++
+ crypto/testmgr.h | 224 ++++++++++++++++++++
+ crypto/tls.c     | 607 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 6 files changed, 1093 insertions(+)
+ create mode 100644 crypto/tls.c
+
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -342,6 +342,26 @@ config CRYPTO_ECHAINIV
+         a sequence number xored with a salt.  This is the default
+         algorithm for CBC.
++config CRYPTO_TLS
++      tristate "TLS support"
++      select CRYPTO_AEAD
++      select CRYPTO_BLKCIPHER
++      select CRYPTO_MANAGER
++      select CRYPTO_HASH
++      select CRYPTO_NULL
++      select CRYPTO_AUTHENC
++      help
++        Support for TLS 1.0 record encryption and decryption
++
++        This module adds support for encryption/decryption of TLS 1.0 frames
++        using blockcipher algorithms. The name of the resulting algorithm is
++        "tls10(hmac(<digest>),cbc(<cipher>))". By default, the generic base
++        algorithms are used (e.g. aes-generic, sha1-generic), but hardware
++        accelerated versions will be used automatically if available.
++
++        User-space applications (OpenSSL, GnuTLS) can offload TLS 1.0
++        operations through AF_ALG or cryptodev interfaces
++
+ comment "Block modes"
+ config CRYPTO_CBC
+--- a/crypto/Makefile
++++ b/crypto/Makefile
+@@ -143,6 +143,7 @@ obj-$(CONFIG_CRYPTO_CRC32) += crc32_gene
+ obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_common.o crct10dif_generic.o
+ obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o
+ obj-$(CONFIG_CRYPTO_LZO) += lzo.o lzo-rle.o
++obj-$(CONFIG_CRYPTO_TLS) += tls.o
+ obj-$(CONFIG_CRYPTO_LZ4) += lz4.o
+ obj-$(CONFIG_CRYPTO_LZ4HC) += lz4hc.o
+ obj-$(CONFIG_CRYPTO_XXHASH) += xxhash_generic.o
+--- a/crypto/tcrypt.c
++++ b/crypto/tcrypt.c
+@@ -2049,6 +2049,9 @@ static int do_test(const char *alg, u32
+               ret += tcrypt_test("cbc(sm4)");
+               ret += tcrypt_test("ctr(sm4)");
+               break;
++      case 192:
++              ret += tcrypt_test("tls10(hmac(sha1),cbc(aes))");
++              break;
+       case 200:
+               test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
+                               speed_template_16_24_32);
+--- a/crypto/testmgr.c
++++ b/crypto/testmgr.c
+@@ -111,6 +111,13 @@ struct drbg_test_suite {
+       unsigned int count;
+ };
++struct tls_test_suite {
++      struct {
++              struct tls_testvec *vecs;
++              unsigned int count;
++      } enc, dec;
++};
++
+ struct akcipher_test_suite {
+       const struct akcipher_testvec *vecs;
+       unsigned int count;
+@@ -135,6 +142,7 @@ struct alg_test_desc {
+               struct hash_test_suite hash;
+               struct cprng_test_suite cprng;
+               struct drbg_test_suite drbg;
++              struct tls_test_suite tls;
+               struct akcipher_test_suite akcipher;
+               struct kpp_test_suite kpp;
+       } suite;
+@@ -2294,6 +2302,227 @@ static int test_aead(const char *driver,
+       return 0;
+ }
++static int __test_tls(struct crypto_aead *tfm, int enc,
++                    struct tls_testvec *template, unsigned int tcount,
++                    const bool diff_dst)
++{
++      const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm));
++      unsigned int i, k, authsize;
++      char *q;
++      struct aead_request *req;
++      struct scatterlist *sg;
++      struct scatterlist *sgout;
++      const char *e, *d;
++      struct crypto_wait wait;
++      void *input;
++      void *output;
++      void *assoc;
++      char *iv;
++      char *key;
++      char *xbuf[XBUFSIZE];
++      char *xoutbuf[XBUFSIZE];
++      char *axbuf[XBUFSIZE];
++      int ret = -ENOMEM;
++
++      if (testmgr_alloc_buf(xbuf))
++              goto out_noxbuf;
++
++      if (diff_dst && testmgr_alloc_buf(xoutbuf))
++              goto out_nooutbuf;
++
++      if (testmgr_alloc_buf(axbuf))
++              goto out_noaxbuf;
++
++      iv = kzalloc(MAX_IVLEN, GFP_KERNEL);
++      if (!iv)
++              goto out_noiv;
++
++      key = kzalloc(MAX_KEYLEN, GFP_KERNEL);
++      if (!key)
++              goto out_nokey;
++
++      sg = kmalloc(sizeof(*sg) * 8 * (diff_dst ? 2 : 1), GFP_KERNEL);
++      if (!sg)
++              goto out_nosg;
++
++      sgout = sg + 8;
++
++      d = diff_dst ? "-ddst" : "";
++      e = enc ? "encryption" : "decryption";
++
++      crypto_init_wait(&wait);
++
++      req = aead_request_alloc(tfm, GFP_KERNEL);
++      if (!req) {
++              pr_err("alg: tls%s: Failed to allocate request for %s\n",
++                     d, algo);
++              goto out;
++      }
++
++      aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
++                                crypto_req_done, &wait);
++
++      for (i = 0; i < tcount; i++) {
++              input = xbuf[0];
++              assoc = axbuf[0];
++
++              ret = -EINVAL;
++              if (WARN_ON(template[i].ilen > PAGE_SIZE ||
++                          template[i].alen > PAGE_SIZE))
++                      goto out;
++
++              memcpy(assoc, template[i].assoc, template[i].alen);
++              memcpy(input, template[i].input, template[i].ilen);
++
++              if (template[i].iv)
++                      memcpy(iv, template[i].iv, MAX_IVLEN);
++              else
++                      memset(iv, 0, MAX_IVLEN);
++
++              crypto_aead_clear_flags(tfm, ~0);
++
++              if (template[i].klen > MAX_KEYLEN) {
++                      pr_err("alg: aead%s: setkey failed on test %d for %s: key size %d > %d\n",
++                             d, i, algo, template[i].klen, MAX_KEYLEN);
++                      ret = -EINVAL;
++                      goto out;
++              }
++              memcpy(key, template[i].key, template[i].klen);
++
++              ret = crypto_aead_setkey(tfm, key, template[i].klen);
++              if (!ret == template[i].fail) {
++                      pr_err("alg: tls%s: setkey failed on test %d for %s: flags=%x\n",
++                             d, i, algo, crypto_aead_get_flags(tfm));
++                      goto out;
++              } else if (ret)
++                      continue;
++
++              authsize = 20;
++              ret = crypto_aead_setauthsize(tfm, authsize);
++              if (ret) {
++                      pr_err("alg: aead%s: Failed to set authsize to %u on test %d for %s\n",
++                             d, authsize, i, algo);
++                      goto out;
++              }
++
++              k = !!template[i].alen;
++              sg_init_table(sg, k + 1);
++              sg_set_buf(&sg[0], assoc, template[i].alen);
++              sg_set_buf(&sg[k], input, (enc ? template[i].rlen :
++                                         template[i].ilen));
++              output = input;
++
++              if (diff_dst) {
++                      sg_init_table(sgout, k + 1);
++                      sg_set_buf(&sgout[0], assoc, template[i].alen);
++
++                      output = xoutbuf[0];
++                      sg_set_buf(&sgout[k], output,
++                                 (enc ? template[i].rlen : template[i].ilen));
++              }
++
++              aead_request_set_crypt(req, sg, (diff_dst) ? sgout : sg,
++                                     template[i].ilen, iv);
++
++              aead_request_set_ad(req, template[i].alen);
++
++              ret = crypto_wait_req(enc ? crypto_aead_encrypt(req)
++                                    : crypto_aead_decrypt(req), &wait);
++
++              switch (ret) {
++              case 0:
++                      if (template[i].novrfy) {
++                              /* verification was supposed to fail */
++                              pr_err("alg: tls%s: %s failed on test %d for %s: ret was 0, expected -EBADMSG\n",
++                                     d, e, i, algo);
++                              /* so really, we got a bad message */
++                              ret = -EBADMSG;
++                              goto out;
++                      }
++                      break;
++              case -EBADMSG:
++                      /* verification failure was expected */
++                      if (template[i].novrfy)
++                              continue;
++                      /* fall through */
++              default:
++                      pr_err("alg: tls%s: %s failed on test %d for %s: ret=%d\n",
++                             d, e, i, algo, -ret);
++                      goto out;
++              }
++
++              q = output;
++              if (memcmp(q, template[i].result, template[i].rlen)) {
++                      pr_err("alg: tls%s: Test %d failed on %s for %s\n",
++                             d, i, e, algo);
++                      hexdump(q, template[i].rlen);
++                      pr_err("should be:\n");
++                      hexdump(template[i].result, template[i].rlen);
++                      ret = -EINVAL;
++                      goto out;
++              }
++      }
++
++out:
++      aead_request_free(req);
++
++      kfree(sg);
++out_nosg:
++      kfree(key);
++out_nokey:
++      kfree(iv);
++out_noiv:
++      testmgr_free_buf(axbuf);
++out_noaxbuf:
++      if (diff_dst)
++              testmgr_free_buf(xoutbuf);
++out_nooutbuf:
++      testmgr_free_buf(xbuf);
++out_noxbuf:
++      return ret;
++}
++
++static int test_tls(struct crypto_aead *tfm, int enc,
++                  struct tls_testvec *template, unsigned int tcount)
++{
++      int ret;
++      /* test 'dst == src' case */
++      ret = __test_tls(tfm, enc, template, tcount, false);
++      if (ret)
++              return ret;
++      /* test 'dst != src' case */
++      return __test_tls(tfm, enc, template, tcount, true);
++}
++
++static int alg_test_tls(const struct alg_test_desc *desc, const char *driver,
++                      u32 type, u32 mask)
++{
++      struct crypto_aead *tfm;
++      int err = 0;
++
++      tfm = crypto_alloc_aead(driver, type, mask);
++      if (IS_ERR(tfm)) {
++              pr_err("alg: aead: Failed to load transform for %s: %ld\n",
++                      driver, PTR_ERR(tfm));
++              return PTR_ERR(tfm);
++      }
++
++      if (desc->suite.tls.enc.vecs) {
++              err = test_tls(tfm, ENCRYPT, desc->suite.tls.enc.vecs,
++                              desc->suite.tls.enc.count);
++              if (err)
++                      goto out;
++      }
++
++      if (!err && desc->suite.tls.dec.vecs)
++              err = test_tls(tfm, DECRYPT, desc->suite.tls.dec.vecs,
++                             desc->suite.tls.dec.count);
++
++out:
++      crypto_free_aead(tfm);
++      return err;
++}
++
+ static int alg_test_aead(const struct alg_test_desc *desc, const char *driver,
+                        u32 type, u32 mask)
+ {
+@@ -5012,6 +5241,15 @@ static const struct alg_test_desc alg_te
+                       .hash = __VECS(tgr192_tv_template)
+               }
+       }, {
++              .alg = "tls10(hmac(sha1),cbc(aes))",
++              .test = alg_test_tls,
++              .suite = {
++                      .tls = {
++                              .enc = __VECS(tls_enc_tv_template),
++                              .dec = __VECS(tls_dec_tv_template)
++                      }
++              }
++      }, {
+               .alg = "vmac64(aes)",
+               .test = alg_test_hash,
+               .suite = {
+--- a/crypto/testmgr.h
++++ b/crypto/testmgr.h
+@@ -21,7 +21,12 @@
+ #define _CRYPTO_TESTMGR_H
+ #include <linux/oid_registry.h>
++#include <linux/netlink.h>
++#define MAX_DIGEST_SIZE               64
++#define MAX_TAP                       8
++
++#define MAX_KEYLEN            160
+ #define MAX_IVLEN             32
+ /*
+@@ -140,6 +145,20 @@ struct drbg_testvec {
+       size_t expectedlen;
+ };
++struct tls_testvec {
++      char *key;      /* wrapped keys for encryption and authentication */
++      char *iv;       /* initialization vector */
++      char *input;    /* input data */
++      char *assoc;    /* associated data: seq num, type, version, input len */
++      char *result;   /* result data */
++      unsigned char fail;     /* the test failure is expected */
++      unsigned char novrfy;   /* dec verification failure expected */
++      unsigned char klen;     /* key length */
++      unsigned short ilen;    /* input data length */
++      unsigned short alen;    /* associated data length */
++      unsigned short rlen;    /* result length */
++};
++
+ struct akcipher_testvec {
+       const unsigned char *key;
+       const unsigned char *params;
+@@ -171,6 +190,211 @@ struct kpp_testvec {
+ static const char zeroed_string[48];
+ /*
++ * TLS1.0 synthetic test vectors
++ */
++static struct tls_testvec tls_enc_tv_template[] = {
++      {
++#ifdef __LITTLE_ENDIAN
++              .key    = "\x08\x00"            /* rta length */
++                      "\x01\x00"              /* rta type */
++#else
++              .key    = "\x00\x08"            /* rta length */
++                      "\x00\x01"              /* rta type */
++#endif
++                      "\x00\x00\x00\x10"      /* enc key length */
++                      "authenticationkey20benckeyis16_bytes",
++              .klen   = 8 + 20 + 16,
++              .iv     = "iv0123456789abcd",
++              .input  = "Single block msg",
++              .ilen   = 16,
++              .assoc  = "\x00\x01\x02\x03\x04\x05\x06\x07"
++                      "\x00\x03\x01\x00\x10",
++              .alen   = 13,
++              .result = "\xd5\xac\xb\xd2\xac\xad\x3f\xb1"
++                      "\x59\x79\x1e\x91\x5f\x52\x14\x9c"
++                      "\xc0\x75\xd8\x4c\x97\x0f\x07\x73"
++                      "\xdc\x89\x47\x49\x49\xcb\x30\x6b"
++                      "\x1b\x45\x23\xa1\xd0\x51\xcf\x02"
++                      "\x2e\xa8\x5d\xa0\xfe\xca\x82\x61",
++              .rlen   = 16 + 20 + 12,
++      }, {
++#ifdef __LITTLE_ENDIAN
++              .key    = "\x08\x00"            /* rta length */
++                      "\x01\x00"              /* rta type */
++#else
++              .key    = "\x00\x08"            /* rta length */
++                      "\x00\x01"              /* rta type */
++#endif
++                      "\x00\x00\x00\x10"      /* enc key length */
++                      "authenticationkey20benckeyis16_bytes",
++              .klen   = 8 + 20 + 16,
++              .iv     = "iv0123456789abcd",
++              .input  = "",
++              .ilen   = 0,
++              .assoc  = "\x00\x01\x02\x03\x04\x05\x06\x07"
++                      "\x00\x03\x01\x00\x00",
++              .alen   = 13,
++              .result = "\x58\x2a\x11\xc\x86\x8e\x4b\x67"
++                      "\x2d\x16\x26\x1a\xac\x4b\xe2\x1a"
++                      "\xe9\x6a\xcc\x4d\x6f\x79\x8a\x45"
++                      "\x1f\x4e\x27\xf2\xa7\x59\xb4\x5a",
++              .rlen   = 20 + 12,
++      }, {
++#ifdef __LITTLE_ENDIAN
++              .key    = "\x08\x00"            /* rta length */
++                      "\x01\x00"              /* rta type */
++#else
++              .key    = "\x00\x08"            /* rta length */
++                      "\x00\x01"              /* rta type */
++#endif
++                      "\x00\x00\x00\x10"      /* enc key length */
++                      "authenticationkey20benckeyis16_bytes",
++              .klen   = 8 + 20 + 16,
++              .iv     = "iv0123456789abcd",
++              .input  = "285 bytes plaintext285 bytes plaintext285 bytes"
++                      " plaintext285 bytes plaintext285 bytes plaintext285"
++                      " bytes plaintext285 bytes plaintext285 bytes"
++                      " plaintext285 bytes plaintext285 bytes plaintext285"
++                      " bytes plaintext285 bytes plaintext285 bytes"
++                      " plaintext285 bytes plaintext285 bytes plaintext285"
++                      " bytes plaintext285 bytes plaintext",
++              .ilen   = 285,
++              .assoc  = "\x00\x01\x02\x03\x04\x05\x06\x07"
++                      "\x00\x03\x01\x01\x1d",
++              .alen   = 13,
++              .result = "\x80\x23\x82\x44\x14\x2a\x1d\x94\xc\xc2\x1d\xd"
++                      "\x3a\x32\x89\x4c\x57\x30\xa8\x89\x76\x46\xcc\x90"
++                      "\x1d\x88\xb8\xa6\x1a\x58\xe\x2d\xeb\x2c\xc7\x3a"
++                      "\x52\x4e\xdb\xb3\x1e\x83\x11\xf5\x3c\xce\x6e\x94"
++                      "\xd3\x26\x6a\x9a\xd\xbd\xc7\x98\xb9\xb3\x3a\x51"
++                      "\x1e\x4\x84\x8a\x8f\x54\x9a\x51\x69\x9c\xce\x31"
++                      "\x8d\x5d\x8b\xee\x5f\x70\xc\xc9\xb8\x50\x54\xf8"
++                      "\xb2\x4a\x7a\xcd\xeb\x7a\x82\x81\xc6\x41\xc8\x50"
++                      "\x91\x8d\xc8\xed\xcd\x40\x8f\x55\xd1\xec\xc9\xac"
++                      "\x15\x18\xf9\x20\xa0\xed\x18\xa1\xe3\x56\xe3\x14"
++                      "\xe5\xe8\x66\x63\x20\xed\xe4\x62\x9d\xa3\xa4\x1d"
++                      "\x81\x89\x18\xf2\x36\xae\xc8\x8a\x2b\xbc\xc3\xb8"
++                      "\x80\xf\x97\x21\x36\x39\x8\x84\x23\x18\x9e\x9c"
++                      "\x72\x32\x75\x2d\x2e\xf9\x60\xb\xe8\xcc\xd9\x74"
++                      "\x4\x1b\x8e\x99\xc1\x94\xee\xd0\xac\x4e\xfc\x7e"
++                      "\xf1\x96\xb3\xe7\x14\xb8\xf2\xc\x25\x97\x82\x6b"
++                      "\xbd\x0\x65\xab\x5c\xe3\x16\xfb\x68\xef\xea\x9d"
++                      "\xff\x44\x1d\x2a\x44\xf5\xc8\x56\x77\xb7\xbf\x13"
++                      "\xc8\x54\xdb\x92\xfe\x16\x4c\xbe\x18\xe9\xb\x8d"
++                      "\xb\xd4\x43\x58\x43\xaa\xf4\x3\x80\x97\x62\xd5"
++                      "\xdf\x3c\x28\xaa\xee\x48\x4b\x55\x41\x1b\x31\x2"
++                      "\xbe\xa0\x1c\xbd\xb7\x22\x2a\xe5\x53\x72\x73\x20"
++                      "\x44\x4f\xe6\x1\x2b\x34\x33\x11\x7d\xfb\x10\xc1"
++                      "\x66\x7c\xa6\xf4\x48\x36\x5e\x2\xda\x41\x4b\x3e"
++                      "\xe7\x80\x17\x17\xce\xf1\x3e\x6a\x8e\x26\xf3\xb7"
++                      "\x2b\x85\xd\x31\x8d\xba\x6c\x22\xb4\x28\x55\x7e"
++                      "\x2a\x9e\x26\xf1\x3d\x21\xac\x65",
++              .rlen   = 285 + 20 + 15,
++      }
++};
++
++static struct tls_testvec tls_dec_tv_template[] = {
++      {
++#ifdef __LITTLE_ENDIAN
++              .key    = "\x08\x00"            /* rta length */
++                      "\x01\x00"              /* rta type */
++#else
++              .key    = "\x00\x08"            /* rta length */
++                      "\x00\x01"              /* rta type */
++#endif
++                      "\x00\x00\x00\x10"      /* enc key length */
++                      "authenticationkey20benckeyis16_bytes",
++              .klen   = 8 + 20 + 16,
++              .iv     = "iv0123456789abcd",
++              .input  = "\xd5\xac\xb\xd2\xac\xad\x3f\xb1"
++                      "\x59\x79\x1e\x91\x5f\x52\x14\x9c"
++                      "\xc0\x75\xd8\x4c\x97\x0f\x07\x73"
++                      "\xdc\x89\x47\x49\x49\xcb\x30\x6b"
++                      "\x1b\x45\x23\xa1\xd0\x51\xcf\x02"
++                      "\x2e\xa8\x5d\xa0\xfe\xca\x82\x61",
++              .ilen   = 16 + 20 + 12,
++              .assoc  = "\x00\x01\x02\x03\x04\x05\x06\x07"
++                      "\x00\x03\x01\x00\x30",
++              .alen   = 13,
++              .result = "Single block msg",
++              .rlen   = 16,
++      }, {
++#ifdef __LITTLE_ENDIAN
++              .key    = "\x08\x00"            /* rta length */
++                      "\x01\x00"              /* rta type */
++#else
++              .key    = "\x00\x08"            /* rta length */
++                      "\x00\x01"              /* rta type */
++#endif
++                      "\x00\x00\x00\x10"      /* enc key length */
++                      "authenticationkey20benckeyis16_bytes",
++              .klen   = 8 + 20 + 16,
++              .iv     = "iv0123456789abcd",
++              .input = "\x58\x2a\x11\xc\x86\x8e\x4b\x67"
++                      "\x2d\x16\x26\x1a\xac\x4b\xe2\x1a"
++                      "\xe9\x6a\xcc\x4d\x6f\x79\x8a\x45"
++                      "\x1f\x4e\x27\xf2\xa7\x59\xb4\x5a",
++              .ilen   = 20 + 12,
++              .assoc  = "\x00\x01\x02\x03\x04\x05\x06\x07"
++                      "\x00\x03\x01\x00\x20",
++              .alen   = 13,
++              .result = "",
++              .rlen   = 0,
++      }, {
++#ifdef __LITTLE_ENDIAN
++              .key    = "\x08\x00"            /* rta length */
++                      "\x01\x00"              /* rta type */
++#else
++              .key    = "\x00\x08"            /* rta length */
++                      "\x00\x01"              /* rta type */
++#endif
++                      "\x00\x00\x00\x10"      /* enc key length */
++                      "authenticationkey20benckeyis16_bytes",
++              .klen   = 8 + 20 + 16,
++              .iv     = "iv0123456789abcd",
++              .input = "\x80\x23\x82\x44\x14\x2a\x1d\x94\xc\xc2\x1d\xd"
++                      "\x3a\x32\x89\x4c\x57\x30\xa8\x89\x76\x46\xcc\x90"
++                      "\x1d\x88\xb8\xa6\x1a\x58\xe\x2d\xeb\x2c\xc7\x3a"
++                      "\x52\x4e\xdb\xb3\x1e\x83\x11\xf5\x3c\xce\x6e\x94"
++                      "\xd3\x26\x6a\x9a\xd\xbd\xc7\x98\xb9\xb3\x3a\x51"
++                      "\x1e\x4\x84\x8a\x8f\x54\x9a\x51\x69\x9c\xce\x31"
++                      "\x8d\x5d\x8b\xee\x5f\x70\xc\xc9\xb8\x50\x54\xf8"
++                      "\xb2\x4a\x7a\xcd\xeb\x7a\x82\x81\xc6\x41\xc8\x50"
++                      "\x91\x8d\xc8\xed\xcd\x40\x8f\x55\xd1\xec\xc9\xac"
++                      "\x15\x18\xf9\x20\xa0\xed\x18\xa1\xe3\x56\xe3\x14"
++                      "\xe5\xe8\x66\x63\x20\xed\xe4\x62\x9d\xa3\xa4\x1d"
++                      "\x81\x89\x18\xf2\x36\xae\xc8\x8a\x2b\xbc\xc3\xb8"
++                      "\x80\xf\x97\x21\x36\x39\x8\x84\x23\x18\x9e\x9c"
++                      "\x72\x32\x75\x2d\x2e\xf9\x60\xb\xe8\xcc\xd9\x74"
++                      "\x4\x1b\x8e\x99\xc1\x94\xee\xd0\xac\x4e\xfc\x7e"
++                      "\xf1\x96\xb3\xe7\x14\xb8\xf2\xc\x25\x97\x82\x6b"
++                      "\xbd\x0\x65\xab\x5c\xe3\x16\xfb\x68\xef\xea\x9d"
++                      "\xff\x44\x1d\x2a\x44\xf5\xc8\x56\x77\xb7\xbf\x13"
++                      "\xc8\x54\xdb\x92\xfe\x16\x4c\xbe\x18\xe9\xb\x8d"
++                      "\xb\xd4\x43\x58\x43\xaa\xf4\x3\x80\x97\x62\xd5"
++                      "\xdf\x3c\x28\xaa\xee\x48\x4b\x55\x41\x1b\x31\x2"
++                      "\xbe\xa0\x1c\xbd\xb7\x22\x2a\xe5\x53\x72\x73\x20"
++                      "\x44\x4f\xe6\x1\x2b\x34\x33\x11\x7d\xfb\x10\xc1"
++                      "\x66\x7c\xa6\xf4\x48\x36\x5e\x2\xda\x41\x4b\x3e"
++                      "\xe7\x80\x17\x17\xce\xf1\x3e\x6a\x8e\x26\xf3\xb7"
++                      "\x2b\x85\xd\x31\x8d\xba\x6c\x22\xb4\x28\x55\x7e"
++                      "\x2a\x9e\x26\xf1\x3d\x21\xac\x65",
++
++              .ilen   = 285 + 20 + 15,
++              .assoc  = "\x00\x01\x02\x03\x04\x05\x06\x07"
++                      "\x00\x03\x01\x01\x40",
++              .alen   = 13,
++              .result = "285 bytes plaintext285 bytes plaintext285 bytes"
++                      " plaintext285 bytes plaintext285 bytes plaintext285"
++                      " bytes plaintext285 bytes plaintext285 bytes"
++                      " plaintext285 bytes plaintext285 bytes plaintext285"
++                      " bytes plaintext285 bytes plaintext285 bytes"
++                      " plaintext285 bytes plaintext285 bytes plaintext",
++              .rlen   = 285,
++      }
++};
++
++/*
+  * RSA test vectors. Borrowed from openSSL.
+  */
+ static const struct akcipher_testvec rsa_tv_template[] = {
+--- /dev/null
++++ b/crypto/tls.c
+@@ -0,0 +1,607 @@
++/*
++ * Copyright 2013 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP Semiconductor, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the Free
++ * Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ *
++ */
++
++#include <crypto/internal/aead.h>
++#include <crypto/internal/hash.h>
++#include <crypto/internal/skcipher.h>
++#include <crypto/authenc.h>
++#include <crypto/null.h>
++#include <crypto/scatterwalk.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/rtnetlink.h>
++
++struct tls_instance_ctx {
++      struct crypto_ahash_spawn auth;
++      struct crypto_skcipher_spawn enc;
++};
++
++struct crypto_tls_ctx {
++      unsigned int reqoff;
++      struct crypto_ahash *auth;
++      struct crypto_skcipher *enc;
++      struct crypto_sync_skcipher *null;
++};
++
++struct tls_request_ctx {
++      /*
++       * cryptlen holds the payload length in the case of encryption or
++       * payload_len + icv_len + padding_len in case of decryption
++       */
++      unsigned int cryptlen;
++      /* working space for partial results */
++      struct scatterlist tmp[2];
++      struct scatterlist cipher[2];
++      struct scatterlist dst[2];
++      char tail[];
++};
++
++struct async_op {
++      struct completion completion;
++      int err;
++};
++
++static void tls_async_op_done(struct crypto_async_request *req, int err)
++{
++      struct async_op *areq = req->data;
++
++      if (err == -EINPROGRESS)
++              return;
++
++      areq->err = err;
++      complete(&areq->completion);
++}
++
++static int crypto_tls_setkey(struct crypto_aead *tls, const u8 *key,
++                           unsigned int keylen)
++{
++      struct crypto_tls_ctx *ctx = crypto_aead_ctx(tls);
++      struct crypto_ahash *auth = ctx->auth;
++      struct crypto_skcipher *enc = ctx->enc;
++      struct crypto_authenc_keys keys;
++      int err = -EINVAL;
++
++      if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
++              goto badkey;
++
++      crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
++      crypto_ahash_set_flags(auth, crypto_aead_get_flags(tls) &
++                                  CRYPTO_TFM_REQ_MASK);
++      err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen);
++      crypto_aead_set_flags(tls, crypto_ahash_get_flags(auth) &
++                                     CRYPTO_TFM_RES_MASK);
++
++      if (err)
++              goto out;
++
++      crypto_skcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
++      crypto_skcipher_set_flags(enc, crypto_aead_get_flags(tls) &
++                                       CRYPTO_TFM_REQ_MASK);
++      err = crypto_skcipher_setkey(enc, keys.enckey, keys.enckeylen);
++      crypto_aead_set_flags(tls, crypto_skcipher_get_flags(enc) &
++                                     CRYPTO_TFM_RES_MASK);
++
++out:
++      return err;
++
++badkey:
++      crypto_aead_set_flags(tls, CRYPTO_TFM_RES_BAD_KEY_LEN);
++      goto out;
++}
++
++/**
++ * crypto_tls_genicv - Calculate hmac digest for a TLS record
++ * @hash:     (output) buffer to save the digest into
++ * @src:      (input) scatterlist with the assoc and payload data
++ * @srclen:   (input) size of the source buffer (assoclen + cryptlen)
++ * @req:      (input) aead request
++ **/
++static int crypto_tls_genicv(u8 *hash, struct scatterlist *src,
++                           unsigned int srclen, struct aead_request *req)
++{
++      struct crypto_aead *tls = crypto_aead_reqtfm(req);
++      struct crypto_tls_ctx *ctx = crypto_aead_ctx(tls);
++      struct tls_request_ctx *treq_ctx = aead_request_ctx(req);
++      struct async_op ahash_op;
++      struct ahash_request *ahreq = (void *)(treq_ctx->tail + ctx->reqoff);
++      unsigned int flags = CRYPTO_TFM_REQ_MAY_SLEEP;
++      int err = -EBADMSG;
++
++       /* Bail out if the request assoc len is 0 */
++      if (!req->assoclen)
++              return err;
++
++      init_completion(&ahash_op.completion);
++
++      /* the hash transform to be executed comes from the original request */
++      ahash_request_set_tfm(ahreq, ctx->auth);
++      /* prepare the hash request with input data and result pointer */
++      ahash_request_set_crypt(ahreq, src, hash, srclen);
++      /* set the notifier for when the async hash function returns */
++      ahash_request_set_callback(ahreq, aead_request_flags(req) & flags,
++                                 tls_async_op_done, &ahash_op);
++
++      /* Calculate the digest on the given data. The result is put in hash */
++      err = crypto_ahash_digest(ahreq);
++      if (err == -EINPROGRESS) {
++              err = wait_for_completion_interruptible(&ahash_op.completion);
++              if (!err)
++                      err = ahash_op.err;
++      }
++
++      return err;
++}
++
++/**
++ * crypto_tls_gen_padicv - Calculate and pad hmac digest for a TLS record
++ * @hash:     (output) buffer to save the digest and padding into
++ * @phashlen: (output) the size of digest + padding
++ * @req:      (input) aead request
++ **/
++static int crypto_tls_gen_padicv(u8 *hash, unsigned int *phashlen,
++                               struct aead_request *req)
++{
++      struct crypto_aead *tls = crypto_aead_reqtfm(req);
++      unsigned int hash_size = crypto_aead_authsize(tls);
++      unsigned int block_size = crypto_aead_blocksize(tls);
++      unsigned int srclen = req->cryptlen + hash_size;
++      unsigned int icvlen = req->cryptlen + req->assoclen;
++      unsigned int padlen;
++      int err;
++
++      err = crypto_tls_genicv(hash, req->src, icvlen, req);
++      if (err)
++              goto out;
++
++      /* add padding after digest */
++      padlen = block_size - (srclen % block_size);
++      memset(hash + hash_size, padlen - 1, padlen);
++
++      *phashlen = hash_size + padlen;
++out:
++      return err;
++}
++
++static int crypto_tls_copy_data(struct aead_request *req,
++                              struct scatterlist *src,
++                              struct scatterlist *dst,
++                              unsigned int len)
++{
++      struct crypto_aead *tls = crypto_aead_reqtfm(req);
++      struct crypto_tls_ctx *ctx = crypto_aead_ctx(tls);
++      SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
++
++      skcipher_request_set_sync_tfm(skreq, ctx->null);
++      skcipher_request_set_callback(skreq, aead_request_flags(req),
++                                    NULL, NULL);
++      skcipher_request_set_crypt(skreq, src, dst, len, NULL);
++
++      return crypto_skcipher_encrypt(skreq);
++}
++
++static int crypto_tls_encrypt(struct aead_request *req)
++{
++      struct crypto_aead *tls = crypto_aead_reqtfm(req);
++      struct crypto_tls_ctx *ctx = crypto_aead_ctx(tls);
++      struct tls_request_ctx *treq_ctx = aead_request_ctx(req);
++      struct skcipher_request *skreq;
++      struct scatterlist *cipher = treq_ctx->cipher;
++      struct scatterlist *tmp = treq_ctx->tmp;
++      struct scatterlist *sg, *src, *dst;
++      unsigned int cryptlen, phashlen;
++      u8 *hash = treq_ctx->tail;
++      int err;
++
++      /*
++       * The hash result is saved at the beginning of the tls request ctx
++       * and is aligned as required by the hash transform. Enough space was
++       * allocated in crypto_tls_init_tfm to accommodate the difference. The
++       * requests themselves start later at treq_ctx->tail + ctx->reqoff so
++       * the result is not overwritten by the second (cipher) request.
++       */
++      hash = (u8 *)ALIGN((unsigned long)hash +
++                         crypto_ahash_alignmask(ctx->auth),
++                         crypto_ahash_alignmask(ctx->auth) + 1);
++
++      /*
++       * STEP 1: create ICV together with necessary padding
++       */
++      err = crypto_tls_gen_padicv(hash, &phashlen, req);
++      if (err)
++              return err;
++
++      /*
++       * STEP 2: Hash and padding are combined with the payload
++       * depending on the form it arrives. Scatter tables must have at least
++       * one page of data before chaining with another table and can't have
++       * an empty data page. The following code addresses these requirements.
++       *
++       * If the payload is empty, only the hash is encrypted, otherwise the
++       * payload scatterlist is merged with the hash. A special merging case
++       * is when the payload has only one page of data. In that case the
++       * payload page is moved to another scatterlist and prepared there for
++       * encryption.
++       */
++      if (req->cryptlen) {
++              src = scatterwalk_ffwd(tmp, req->src, req->assoclen);
++
++              sg_init_table(cipher, 2);
++              sg_set_buf(cipher + 1, hash, phashlen);
++
++              if (sg_is_last(src)) {
++                      sg_set_page(cipher, sg_page(src), req->cryptlen,
++                                  src->offset);
++                      src = cipher;
++              } else {
++                      unsigned int rem_len = req->cryptlen;
++
++                      for (sg = src; rem_len > sg->length; sg = sg_next(sg))
++                              rem_len -= min(rem_len, sg->length);
++
++                      sg_set_page(cipher, sg_page(sg), rem_len, sg->offset);
++                      sg_chain(sg, 1, cipher);
++              }
++      } else {
++              sg_init_one(cipher, hash, phashlen);
++              src = cipher;
++      }
++
++      /**
++       * If src != dst copy the associated data from source to destination.
++       * In both cases fast-forward passed the associated data in the dest.
++       */
++      if (req->src != req->dst) {
++              err = crypto_tls_copy_data(req, req->src, req->dst,
++                                         req->assoclen);
++              if (err)
++                      return err;
++      }
++      dst = scatterwalk_ffwd(treq_ctx->dst, req->dst, req->assoclen);
++
++      /*
++       * STEP 3: encrypt the frame and return the result
++       */
++      cryptlen = req->cryptlen + phashlen;
++
++      /*
++       * The hash and the cipher are applied at different times and their
++       * requests can use the same memory space without interference
++       */
++      skreq = (void *)(treq_ctx->tail + ctx->reqoff);
++      skcipher_request_set_tfm(skreq, ctx->enc);
++      skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv);
++      skcipher_request_set_callback(skreq, aead_request_flags(req),
++                                    req->base.complete, req->base.data);
++      /*
++       * Apply the cipher transform. The result will be in req->dst when the
++       * asynchronuous call terminates
++       */
++      err = crypto_skcipher_encrypt(skreq);
++
++      return err;
++}
++
++static int crypto_tls_decrypt(struct aead_request *req)
++{
++      struct crypto_aead *tls = crypto_aead_reqtfm(req);
++      struct crypto_tls_ctx *ctx = crypto_aead_ctx(tls);
++      struct tls_request_ctx *treq_ctx = aead_request_ctx(req);
++      unsigned int cryptlen = req->cryptlen;
++      unsigned int hash_size = crypto_aead_authsize(tls);
++      unsigned int block_size = crypto_aead_blocksize(tls);
++      struct skcipher_request *skreq = (void *)(treq_ctx->tail + ctx->reqoff);
++      struct scatterlist *tmp = treq_ctx->tmp;
++      struct scatterlist *src, *dst;
++
++      u8 padding[255]; /* padding can be 0-255 bytes */
++      u8 pad_size;
++      u16 *len_field;
++      u8 *ihash, *hash = treq_ctx->tail;
++
++      int paderr = 0;
++      int err = -EINVAL;
++      int i;
++      struct async_op ciph_op;
++
++      /*
++       * Rule out bad packets. The input packet length must be at least one
++       * byte more than the hash_size
++       */
++      if (cryptlen <= hash_size || cryptlen % block_size)
++              goto out;
++
++      /*
++       * Step 1 - Decrypt the source. Fast-forward past the associated data
++       * to the encrypted data. The result will be overwritten in place so
++       * that the decrypted data will be adjacent to the associated data. The
++       * last step (computing the hash) will have it's input data already
++       * prepared and ready to be accessed at req->src.
++       */
++      src = scatterwalk_ffwd(tmp, req->src, req->assoclen);
++      dst = src;
++
++      init_completion(&ciph_op.completion);
++      skcipher_request_set_tfm(skreq, ctx->enc);
++      skcipher_request_set_callback(skreq, aead_request_flags(req),
++                                    tls_async_op_done, &ciph_op);
++      skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv);
++      err = crypto_skcipher_decrypt(skreq);
++      if (err == -EINPROGRESS) {
++              err = wait_for_completion_interruptible(&ciph_op.completion);
++              if (!err)
++                      err = ciph_op.err;
++      }
++      if (err)
++              goto out;
++
++      /*
++       * Step 2 - Verify padding
++       * Retrieve the last byte of the payload; this is the padding size.
++       */
++      cryptlen -= 1;
++      scatterwalk_map_and_copy(&pad_size, dst, cryptlen, 1, 0);
++
++      /* RFC recommendation for invalid padding size. */
++      if (cryptlen < pad_size + hash_size) {
++              pad_size = 0;
++              paderr = -EBADMSG;
++      }
++      cryptlen -= pad_size;
++      scatterwalk_map_and_copy(padding, dst, cryptlen, pad_size, 0);
++
++      /* Padding content must be equal with pad_size. We verify it all */
++      for (i = 0; i < pad_size; i++)
++              if (padding[i] != pad_size)
++                      paderr = -EBADMSG;
++
++      /*
++       * Step 3 - Verify hash
++       * Align the digest result as required by the hash transform. Enough
++       * space was allocated in crypto_tls_init_tfm
++       */
++      hash = (u8 *)ALIGN((unsigned long)hash +
++                         crypto_ahash_alignmask(ctx->auth),
++                         crypto_ahash_alignmask(ctx->auth) + 1);
++      /*
++       * Two bytes at the end of the associated data make the length field.
++       * It must be updated with the length of the cleartext message before
++       * the hash is calculated.
++       */
++      len_field = sg_virt(req->src) + req->assoclen - 2;
++      cryptlen -= hash_size;
++      *len_field = htons(cryptlen);
++
++      /* This is the hash from the decrypted packet. Save it for later */
++      ihash = hash + hash_size;
++      scatterwalk_map_and_copy(ihash, dst, cryptlen, hash_size, 0);
++
++      /* Now compute and compare our ICV with the one from the packet */
++      err = crypto_tls_genicv(hash, req->src, cryptlen + req->assoclen, req);
++      if (!err)
++              err = memcmp(hash, ihash, hash_size) ? -EBADMSG : 0;
++
++      if (req->src != req->dst) {
++              err = crypto_tls_copy_data(req, req->src, req->dst, cryptlen +
++                                         req->assoclen);
++              if (err)
++                      goto out;
++      }
++
++      /* return the first found error */
++      if (paderr)
++              err = paderr;
++
++out:
++      aead_request_complete(req, err);
++      return err;
++}
++
++static int crypto_tls_init_tfm(struct crypto_aead *tfm)
++{
++      struct aead_instance *inst = aead_alg_instance(tfm);
++      struct tls_instance_ctx *ictx = aead_instance_ctx(inst);
++      struct crypto_tls_ctx *ctx = crypto_aead_ctx(tfm);
++      struct crypto_ahash *auth;
++      struct crypto_skcipher *enc;
++      struct crypto_sync_skcipher *null;
++      int err;
++
++      auth = crypto_spawn_ahash(&ictx->auth);
++      if (IS_ERR(auth))
++              return PTR_ERR(auth);
++
++      enc = crypto_spawn_skcipher(&ictx->enc);
++      err = PTR_ERR(enc);
++      if (IS_ERR(enc))
++              goto err_free_ahash;
++
++      null = crypto_get_default_null_skcipher();
++      err = PTR_ERR(null);
++      if (IS_ERR(null))
++              goto err_free_skcipher;
++
++      ctx->auth = auth;
++      ctx->enc = enc;
++      ctx->null = null;
++
++      /*
++       * Allow enough space for two digests. The two digests will be compared
++       * during the decryption phase. One will come from the decrypted packet
++       * and the other will be calculated. For encryption, one digest is
++       * padded (up to a cipher blocksize) and chained with the payload
++       */
++      ctx->reqoff = ALIGN(crypto_ahash_digestsize(auth) +
++                          crypto_ahash_alignmask(auth),
++                          crypto_ahash_alignmask(auth) + 1) +
++                          max(crypto_ahash_digestsize(auth),
++                              crypto_skcipher_blocksize(enc));
++
++      crypto_aead_set_reqsize(tfm,
++                              sizeof(struct tls_request_ctx) +
++                              ctx->reqoff +
++                              max_t(unsigned int,
++                                    crypto_ahash_reqsize(auth) +
++                                    sizeof(struct ahash_request),
++                                    crypto_skcipher_reqsize(enc) +
++                                    sizeof(struct skcipher_request)));
++
++      return 0;
++
++err_free_skcipher:
++      crypto_free_skcipher(enc);
++err_free_ahash:
++      crypto_free_ahash(auth);
++      return err;
++}
++
++static void crypto_tls_exit_tfm(struct crypto_aead *tfm)
++{
++      struct crypto_tls_ctx *ctx = crypto_aead_ctx(tfm);
++
++      crypto_free_ahash(ctx->auth);
++      crypto_free_skcipher(ctx->enc);
++      crypto_put_default_null_skcipher();
++}
++
++static void crypto_tls_free(struct aead_instance *inst)
++{
++      struct tls_instance_ctx *ctx = aead_instance_ctx(inst);
++
++      crypto_drop_skcipher(&ctx->enc);
++      crypto_drop_ahash(&ctx->auth);
++      kfree(inst);
++}
++
++static int crypto_tls_create(struct crypto_template *tmpl, struct rtattr **tb)
++{
++      struct crypto_attr_type *algt;
++      struct aead_instance *inst;
++      struct hash_alg_common *auth;
++      struct crypto_alg *auth_base;
++      struct skcipher_alg *enc;
++      struct tls_instance_ctx *ctx;
++      const char *enc_name;
++      int err;
++
++      algt = crypto_get_attr_type(tb);
++      if (IS_ERR(algt))
++              return PTR_ERR(algt);
++
++      if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
++              return -EINVAL;
++
++      auth = ahash_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH,
++                            CRYPTO_ALG_TYPE_AHASH_MASK |
++                            crypto_requires_sync(algt->type, algt->mask));
++      if (IS_ERR(auth))
++              return PTR_ERR(auth);
++
++      auth_base = &auth->base;
++
++      enc_name = crypto_attr_alg_name(tb[2]);
++      err = PTR_ERR(enc_name);
++      if (IS_ERR(enc_name))
++              goto out_put_auth;
++
++      inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
++      err = -ENOMEM;
++      if (!inst)
++              goto out_put_auth;
++
++      ctx = aead_instance_ctx(inst);
++
++      err = crypto_init_ahash_spawn(&ctx->auth, auth,
++                                    aead_crypto_instance(inst));
++      if (err)
++              goto err_free_inst;
++
++      crypto_set_skcipher_spawn(&ctx->enc, aead_crypto_instance(inst));
++      err = crypto_grab_skcipher(&ctx->enc, enc_name, 0,
++                                 crypto_requires_sync(algt->type,
++                                                      algt->mask));
++      if (err)
++              goto err_drop_auth;
++
++      enc = crypto_spawn_skcipher_alg(&ctx->enc);
++
++      err = -ENAMETOOLONG;
++      if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
++                   "tls10(%s,%s)", auth_base->cra_name,
++                   enc->base.cra_name) >= CRYPTO_MAX_ALG_NAME)
++              goto err_drop_enc;
++
++      if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
++                   "tls10(%s,%s)", auth_base->cra_driver_name,
++                   enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
++              goto err_drop_enc;
++
++      inst->alg.base.cra_flags = (auth_base->cra_flags |
++                                      enc->base.cra_flags) & CRYPTO_ALG_ASYNC;
++      inst->alg.base.cra_priority = enc->base.cra_priority * 10 +
++                                      auth_base->cra_priority;
++      inst->alg.base.cra_blocksize = enc->base.cra_blocksize;
++      inst->alg.base.cra_alignmask = auth_base->cra_alignmask |
++                                      enc->base.cra_alignmask;
++      inst->alg.base.cra_ctxsize = sizeof(struct crypto_tls_ctx);
++
++      inst->alg.ivsize = crypto_skcipher_alg_ivsize(enc);
++      inst->alg.chunksize = crypto_skcipher_alg_chunksize(enc);
++      inst->alg.maxauthsize = auth->digestsize;
++
++      inst->alg.init = crypto_tls_init_tfm;
++      inst->alg.exit = crypto_tls_exit_tfm;
++
++      inst->alg.setkey = crypto_tls_setkey;
++      inst->alg.encrypt = crypto_tls_encrypt;
++      inst->alg.decrypt = crypto_tls_decrypt;
++
++      inst->free = crypto_tls_free;
++
++      err = aead_register_instance(tmpl, inst);
++      if (err)
++              goto err_drop_enc;
++
++out:
++      crypto_mod_put(auth_base);
++      return err;
++
++err_drop_enc:
++      crypto_drop_skcipher(&ctx->enc);
++err_drop_auth:
++      crypto_drop_ahash(&ctx->auth);
++err_free_inst:
++      kfree(inst);
++out_put_auth:
++      goto out;
++}
++
++static struct crypto_template crypto_tls_tmpl = {
++      .name = "tls10",
++      .create = crypto_tls_create,
++      .module = THIS_MODULE,
++};
++
++static int __init crypto_tls_module_init(void)
++{
++      return crypto_register_template(&crypto_tls_tmpl);
++}
++
++static void __exit crypto_tls_module_exit(void)
++{
++      crypto_unregister_template(&crypto_tls_tmpl);
++}
++
++module_init(crypto_tls_module_init);
++module_exit(crypto_tls_module_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("TLS 1.0 record encryption");
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0002-crypto-tcrypt-include-rsa-test.patch b/target/linux/layerscape/patches-5.4/804-crypto-0002-crypto-tcrypt-include-rsa-test.patch
new file mode 100644 (file)
index 0000000..5be1e05
--- /dev/null
@@ -0,0 +1,36 @@
+From c579c23d57c0ef7c832cf0844c86c7be42c197d3 Mon Sep 17 00:00:00 2001
+From: Radu Alexe <radu.alexe@nxp.com>
+Date: Thu, 13 Apr 2017 09:36:32 +0300
+Subject: [PATCH] crypto: tcrypt - include rsa test
+
+Signed-off-by: Radu Alexe <radu.alexe@nxp.com>
+Signed-off-by: Tudor Ambarus <tudor-dan.ambarus@nxp.com>
+---
+ crypto/tcrypt.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+--- a/crypto/tcrypt.c
++++ b/crypto/tcrypt.c
+@@ -71,9 +71,8 @@ static char *check[] = {
+       "cast6", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
+       "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta",  "fcrypt",
+       "camellia", "seed", "salsa20", "rmd128", "rmd160", "rmd256", "rmd320",
+-      "lzo", "lzo-rle", "cts", "sha3-224", "sha3-256", "sha3-384",
+-      "sha3-512", "streebog256", "streebog512",
+-      NULL
++      "lzo", "lzo-rle", "cts", "zlib", "sha3-224", "sha3-256", "sha3-384",
++      "sha3-512", "streebog256", "streebog512", "rsa", NULL
+ };
+ static u32 block_sizes[] = { 16, 64, 256, 1024, 1472, 8192, 0 };
+@@ -1983,6 +1982,10 @@ static int do_test(const char *alg, u32
+               ret += tcrypt_test("hmac(streebog512)");
+               break;
++      case 117:
++              ret += tcrypt_test("rsa");
++              break;
++
+       case 150:
+               ret += tcrypt_test("ansi_cprng");
+               break;
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0003-crypto-caam-use-mapped_-src-dst-_nents-for-descripto.patch b/target/linux/layerscape/patches-5.4/804-crypto-0003-crypto-caam-use-mapped_-src-dst-_nents-for-descripto.patch
new file mode 100644 (file)
index 0000000..4e1efc8
--- /dev/null
@@ -0,0 +1,227 @@
+From e640f4bcfa0088ff696bc5da6063a1ea8d782189 Mon Sep 17 00:00:00 2001
+From: Iuliana Prodan <iuliana.prodan@nxp.com>
+Date: Thu, 26 Sep 2019 15:26:29 +0300
+Subject: [PATCH] crypto: caam - use mapped_{src,dst}_nents for descriptor
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The mapped_{src,dst}_nents _returned_ from the dma_map_sg
+call (which could be less than src/dst_nents) have to be
+used to generate the job descriptors.
+
+Signed-off-by: Iuliana Prodan <iuliana.prodan@nxp.com>
+Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+(cherry picked from commit eff9771d51529acf7f6f58a60b2923b98da28f0e)
+---
+ drivers/crypto/caam/caampkc.c | 72 +++++++++++++++++++++++--------------------
+ drivers/crypto/caam/caampkc.h |  8 +++--
+ 2 files changed, 45 insertions(+), 35 deletions(-)
+
+--- a/drivers/crypto/caam/caampkc.c
++++ b/drivers/crypto/caam/caampkc.c
+@@ -252,9 +252,9 @@ static struct rsa_edesc *rsa_edesc_alloc
+       gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+                      GFP_KERNEL : GFP_ATOMIC;
+       int sg_flags = (flags == GFP_ATOMIC) ? SG_MITER_ATOMIC : 0;
+-      int sgc;
+       int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes;
+       int src_nents, dst_nents;
++      int mapped_src_nents, mapped_dst_nents;
+       unsigned int diff_size = 0;
+       int lzeros;
+@@ -285,13 +285,27 @@ static struct rsa_edesc *rsa_edesc_alloc
+                                    req_ctx->fixup_src_len);
+       dst_nents = sg_nents_for_len(req->dst, req->dst_len);
+-      if (!diff_size && src_nents == 1)
++      mapped_src_nents = dma_map_sg(dev, req_ctx->fixup_src, src_nents,
++                                    DMA_TO_DEVICE);
++      if (unlikely(!mapped_src_nents)) {
++              dev_err(dev, "unable to map source\n");
++              return ERR_PTR(-ENOMEM);
++      }
++      mapped_dst_nents = dma_map_sg(dev, req->dst, dst_nents,
++                                    DMA_FROM_DEVICE);
++      if (unlikely(!mapped_dst_nents)) {
++              dev_err(dev, "unable to map destination\n");
++              goto src_fail;
++      }
++
++      if (!diff_size && mapped_src_nents == 1)
+               sec4_sg_len = 0; /* no need for an input hw s/g table */
+       else
+-              sec4_sg_len = src_nents + !!diff_size;
++              sec4_sg_len = mapped_src_nents + !!diff_size;
+       sec4_sg_index = sec4_sg_len;
+-      if (dst_nents > 1)
+-              sec4_sg_len += pad_sg_nents(dst_nents);
++
++      if (mapped_dst_nents > 1)
++              sec4_sg_len += pad_sg_nents(mapped_dst_nents);
+       else
+               sec4_sg_len = pad_sg_nents(sec4_sg_len);
+@@ -301,19 +315,7 @@ static struct rsa_edesc *rsa_edesc_alloc
+       edesc = kzalloc(sizeof(*edesc) + desclen + sec4_sg_bytes,
+                       GFP_DMA | flags);
+       if (!edesc)
+-              return ERR_PTR(-ENOMEM);
+-
+-      sgc = dma_map_sg(dev, req_ctx->fixup_src, src_nents, DMA_TO_DEVICE);
+-      if (unlikely(!sgc)) {
+-              dev_err(dev, "unable to map source\n");
+-              goto src_fail;
+-      }
+-
+-      sgc = dma_map_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE);
+-      if (unlikely(!sgc)) {
+-              dev_err(dev, "unable to map destination\n");
+               goto dst_fail;
+-      }
+       edesc->sec4_sg = (void *)edesc + sizeof(*edesc) + desclen;
+       if (diff_size)
+@@ -324,7 +326,7 @@ static struct rsa_edesc *rsa_edesc_alloc
+               sg_to_sec4_sg_last(req_ctx->fixup_src, req_ctx->fixup_src_len,
+                                  edesc->sec4_sg + !!diff_size, 0);
+-      if (dst_nents > 1)
++      if (mapped_dst_nents > 1)
+               sg_to_sec4_sg_last(req->dst, req->dst_len,
+                                  edesc->sec4_sg + sec4_sg_index, 0);
+@@ -335,6 +337,9 @@ static struct rsa_edesc *rsa_edesc_alloc
+       if (!sec4_sg_bytes)
+               return edesc;
++      edesc->mapped_src_nents = mapped_src_nents;
++      edesc->mapped_dst_nents = mapped_dst_nents;
++
+       edesc->sec4_sg_dma = dma_map_single(dev, edesc->sec4_sg,
+                                           sec4_sg_bytes, DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, edesc->sec4_sg_dma)) {
+@@ -351,11 +356,11 @@ static struct rsa_edesc *rsa_edesc_alloc
+       return edesc;
+ sec4_sg_fail:
+-      dma_unmap_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE);
++      kfree(edesc);
+ dst_fail:
+-      dma_unmap_sg(dev, req_ctx->fixup_src, src_nents, DMA_TO_DEVICE);
++      dma_unmap_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE);
+ src_fail:
+-      kfree(edesc);
++      dma_unmap_sg(dev, req_ctx->fixup_src, src_nents, DMA_TO_DEVICE);
+       return ERR_PTR(-ENOMEM);
+ }
+@@ -383,15 +388,15 @@ static int set_rsa_pub_pdb(struct akciph
+               return -ENOMEM;
+       }
+-      if (edesc->src_nents > 1) {
++      if (edesc->mapped_src_nents > 1) {
+               pdb->sgf |= RSA_PDB_SGF_F;
+               pdb->f_dma = edesc->sec4_sg_dma;
+-              sec4_sg_index += edesc->src_nents;
++              sec4_sg_index += edesc->mapped_src_nents;
+       } else {
+               pdb->f_dma = sg_dma_address(req_ctx->fixup_src);
+       }
+-      if (edesc->dst_nents > 1) {
++      if (edesc->mapped_dst_nents > 1) {
+               pdb->sgf |= RSA_PDB_SGF_G;
+               pdb->g_dma = edesc->sec4_sg_dma +
+                            sec4_sg_index * sizeof(struct sec4_sg_entry);
+@@ -428,17 +433,18 @@ static int set_rsa_priv_f1_pdb(struct ak
+               return -ENOMEM;
+       }
+-      if (edesc->src_nents > 1) {
++      if (edesc->mapped_src_nents > 1) {
+               pdb->sgf |= RSA_PRIV_PDB_SGF_G;
+               pdb->g_dma = edesc->sec4_sg_dma;
+-              sec4_sg_index += edesc->src_nents;
++              sec4_sg_index += edesc->mapped_src_nents;
++
+       } else {
+               struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req);
+               pdb->g_dma = sg_dma_address(req_ctx->fixup_src);
+       }
+-      if (edesc->dst_nents > 1) {
++      if (edesc->mapped_dst_nents > 1) {
+               pdb->sgf |= RSA_PRIV_PDB_SGF_F;
+               pdb->f_dma = edesc->sec4_sg_dma +
+                            sec4_sg_index * sizeof(struct sec4_sg_entry);
+@@ -493,17 +499,17 @@ static int set_rsa_priv_f2_pdb(struct ak
+               goto unmap_tmp1;
+       }
+-      if (edesc->src_nents > 1) {
++      if (edesc->mapped_src_nents > 1) {
+               pdb->sgf |= RSA_PRIV_PDB_SGF_G;
+               pdb->g_dma = edesc->sec4_sg_dma;
+-              sec4_sg_index += edesc->src_nents;
++              sec4_sg_index += edesc->mapped_src_nents;
+       } else {
+               struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req);
+               pdb->g_dma = sg_dma_address(req_ctx->fixup_src);
+       }
+-      if (edesc->dst_nents > 1) {
++      if (edesc->mapped_dst_nents > 1) {
+               pdb->sgf |= RSA_PRIV_PDB_SGF_F;
+               pdb->f_dma = edesc->sec4_sg_dma +
+                            sec4_sg_index * sizeof(struct sec4_sg_entry);
+@@ -582,17 +588,17 @@ static int set_rsa_priv_f3_pdb(struct ak
+               goto unmap_tmp1;
+       }
+-      if (edesc->src_nents > 1) {
++      if (edesc->mapped_src_nents > 1) {
+               pdb->sgf |= RSA_PRIV_PDB_SGF_G;
+               pdb->g_dma = edesc->sec4_sg_dma;
+-              sec4_sg_index += edesc->src_nents;
++              sec4_sg_index += edesc->mapped_src_nents;
+       } else {
+               struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req);
+               pdb->g_dma = sg_dma_address(req_ctx->fixup_src);
+       }
+-      if (edesc->dst_nents > 1) {
++      if (edesc->mapped_dst_nents > 1) {
+               pdb->sgf |= RSA_PRIV_PDB_SGF_F;
+               pdb->f_dma = edesc->sec4_sg_dma +
+                            sec4_sg_index * sizeof(struct sec4_sg_entry);
+--- a/drivers/crypto/caam/caampkc.h
++++ b/drivers/crypto/caam/caampkc.h
+@@ -112,8 +112,10 @@ struct caam_rsa_req_ctx {
+ /**
+  * rsa_edesc - s/w-extended rsa descriptor
+- * @src_nents     : number of segments in input scatterlist
+- * @dst_nents     : number of segments in output scatterlist
++ * @src_nents     : number of segments in input s/w scatterlist
++ * @dst_nents     : number of segments in output s/w scatterlist
++ * @mapped_src_nents: number of segments in input h/w link table
++ * @mapped_dst_nents: number of segments in output h/w link table
+  * @sec4_sg_bytes : length of h/w link table
+  * @sec4_sg_dma   : dma address of h/w link table
+  * @sec4_sg       : pointer to h/w link table
+@@ -123,6 +125,8 @@ struct caam_rsa_req_ctx {
+ struct rsa_edesc {
+       int src_nents;
+       int dst_nents;
++      int mapped_src_nents;
++      int mapped_dst_nents;
+       int sec4_sg_bytes;
+       dma_addr_t sec4_sg_dma;
+       struct sec4_sg_entry *sec4_sg;
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0004-crypto-caam-use-devres-to-unmap-memory.patch b/target/linux/layerscape/patches-5.4/804-crypto-0004-crypto-caam-use-devres-to-unmap-memory.patch
new file mode 100644 (file)
index 0000000..d85280c
--- /dev/null
@@ -0,0 +1,109 @@
+From 76087c548649ea0fae04a0538f9de12546c5c680 Mon Sep 17 00:00:00 2001
+From: Andrey Smirnov <andrew.smirnov@gmail.com>
+Date: Tue, 22 Oct 2019 08:30:08 -0700
+Subject: [PATCH] crypto: caam - use devres to unmap memory
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Use devres to unmap memory and drop corresponding iounmap() call.
+
+Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
+Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
+Cc: Chris Healy <cphealy@gmail.com>
+Cc: Lucas Stach <l.stach@pengutronix.de>
+Cc: Horia Geantă <horia.geanta@nxp.com>
+Cc: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: Iuliana Prodan <iuliana.prodan@nxp.com>
+Cc: linux-crypto@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+(cherry picked from commit 66e93b28075d3cae568ed97ef78789afa5a6eb36)
+---
+ drivers/crypto/caam/ctrl.c | 28 +++++++++-------------------
+ 1 file changed, 9 insertions(+), 19 deletions(-)
+
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -308,11 +308,9 @@ static int caam_remove(struct platform_d
+ {
+       struct device *ctrldev;
+       struct caam_drv_private *ctrlpriv;
+-      struct caam_ctrl __iomem *ctrl;
+       ctrldev = &pdev->dev;
+       ctrlpriv = dev_get_drvdata(ctrldev);
+-      ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl;
+       /* Remove platform devices under the crypto node */
+       of_platform_depopulate(ctrldev);
+@@ -334,9 +332,6 @@ static int caam_remove(struct platform_d
+       debugfs_remove_recursive(ctrlpriv->dfs_root);
+ #endif
+-      /* Unmap controller region */
+-      iounmap(ctrl);
+-
+       return 0;
+ }
+@@ -611,10 +606,11 @@ static int caam_probe(struct platform_de
+       /* Get configuration properties from device tree */
+       /* First, get register page */
+-      ctrl = of_iomap(nprop, 0);
+-      if (!ctrl) {
++      ctrl = devm_of_iomap(dev, nprop, 0, NULL);
++      ret = PTR_ERR_OR_ZERO(ctrl);
++      if (ret) {
+               dev_err(dev, "caam: of_iomap() failed\n");
+-              return -ENOMEM;
++              return ret;
+       }
+       caam_little_end = !(bool)(rd_reg32(&ctrl->perfmon.status) &
+@@ -632,22 +628,18 @@ static int caam_probe(struct platform_de
+       if (ctrlpriv->qi_present && !caam_dpaa2) {
+               ret = qman_is_probed();
+               if (!ret) {
+-                      ret = -EPROBE_DEFER;
+-                      goto iounmap_ctrl;
++                      return -EPROBE_DEFER;
+               } else if (ret < 0) {
+                       dev_err(dev, "failing probe due to qman probe error\n");
+-                      ret = -ENODEV;
+-                      goto iounmap_ctrl;
++                      return -ENODEV;
+               }
+               ret = qman_portals_probed();
+               if (!ret) {
+-                      ret = -EPROBE_DEFER;
+-                      goto iounmap_ctrl;
++                      return -EPROBE_DEFER;
+               } else if (ret < 0) {
+                       dev_err(dev, "failing probe due to qman portals probe error\n");
+-                      ret = -ENODEV;
+-                      goto iounmap_ctrl;
++                      return -ENODEV;
+               }
+       }
+ #endif
+@@ -720,7 +712,7 @@ static int caam_probe(struct platform_de
+       ret = dma_set_mask_and_coherent(dev, caam_get_dma_mask(dev));
+       if (ret) {
+               dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret);
+-              goto iounmap_ctrl;
++              return ret;
+       }
+       ctrlpriv->era = caam_get_era(ctrl);
+@@ -925,8 +917,6 @@ shutdown_qi:
+       if (ctrlpriv->qi_init)
+               caam_qi_shutdown(dev);
+ #endif
+-iounmap_ctrl:
+-      iounmap(ctrl);
+       return ret;
+ }
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0005-crypto-caam-use-devres-to-remove-debugfs.patch b/target/linux/layerscape/patches-5.4/804-crypto-0005-crypto-caam-use-devres-to-remove-debugfs.patch
new file mode 100644 (file)
index 0000000..ff15d95
--- /dev/null
@@ -0,0 +1,88 @@
+From 93fbe7c21a64d22ac057fc9e8eed5967f5d0bd88 Mon Sep 17 00:00:00 2001
+From: Andrey Smirnov <andrew.smirnov@gmail.com>
+Date: Tue, 22 Oct 2019 08:30:09 -0700
+Subject: [PATCH] crypto: caam - use devres to remove debugfs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Use devres to remove debugfs and drop corresponding
+debugfs_remove_recursive() call.
+
+Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
+Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
+Cc: Chris Healy <cphealy@gmail.com>
+Cc: Lucas Stach <l.stach@pengutronix.de>
+Cc: Horia Geantă <horia.geanta@nxp.com>
+Cc: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: Iuliana Prodan <iuliana.prodan@nxp.com>
+Cc: linux-crypto@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+(cherry picked from commit eceb5daf9ebaa564a65eb2d9d5a4682a33747300)
+---
+ drivers/crypto/caam/ctrl.c   | 21 ++++++++++++++-------
+ drivers/crypto/caam/intern.h |  1 -
+ 2 files changed, 14 insertions(+), 8 deletions(-)
+
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -327,11 +327,6 @@ static int caam_remove(struct platform_d
+       if (!ctrlpriv->mc_en && ctrlpriv->rng4_sh_init)
+               deinstantiate_rng(ctrldev, ctrlpriv->rng4_sh_init);
+-      /* Shut down debug views */
+-#ifdef CONFIG_DEBUG_FS
+-      debugfs_remove_recursive(ctrlpriv->dfs_root);
+-#endif
+-
+       return 0;
+ }
+@@ -563,6 +558,13 @@ static int init_clocks(struct device *de
+       return devm_add_action_or_reset(dev, disable_clocks, ctrlpriv);
+ }
++#ifdef CONFIG_DEBUG_FS
++static void caam_remove_debugfs(void *root)
++{
++      debugfs_remove_recursive(root);
++}
++#endif
++
+ /* Probe routine for CAAM top (controller) level */
+ static int caam_probe(struct platform_device *pdev)
+ {
+@@ -575,6 +577,7 @@ static int caam_probe(struct platform_de
+       struct caam_drv_private *ctrlpriv;
+ #ifdef CONFIG_DEBUG_FS
+       struct caam_perfmon *perfmon;
++      struct dentry *dfs_root;
+ #endif
+       u32 scfgr, comp_params;
+       u8 rng_vid;
+@@ -726,8 +729,12 @@ static int caam_probe(struct platform_de
+        */
+       perfmon = (struct caam_perfmon __force *)&ctrl->perfmon;
+-      ctrlpriv->dfs_root = debugfs_create_dir(dev_name(dev), NULL);
+-      ctrlpriv->ctl = debugfs_create_dir("ctl", ctrlpriv->dfs_root);
++      dfs_root = debugfs_create_dir(dev_name(dev), NULL);
++      ret = devm_add_action_or_reset(dev, caam_remove_debugfs, dfs_root);
++      if (ret)
++              return ret;
++
++      ctrlpriv->ctl = debugfs_create_dir("ctl", dfs_root);
+ #endif
+       /* Check to see if (DPAA 1.x) QI present. If so, enable */
+--- a/drivers/crypto/caam/intern.h
++++ b/drivers/crypto/caam/intern.h
+@@ -102,7 +102,6 @@ struct caam_drv_private {
+        * variables at runtime.
+        */
+ #ifdef CONFIG_DEBUG_FS
+-      struct dentry *dfs_root;
+       struct dentry *ctl; /* controller dir */
+       struct debugfs_blob_wrapper ctl_kek_wrap, ctl_tkek_wrap, ctl_tdsk_wrap;
+ #endif
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0006-crypto-caam-use-devres-to-de-initialize-the-RNG.patch b/target/linux/layerscape/patches-5.4/804-crypto-0006-crypto-caam-use-devres-to-de-initialize-the-RNG.patch
new file mode 100644 (file)
index 0000000..6e3cd24
--- /dev/null
@@ -0,0 +1,179 @@
+From 4719469bf1e6d5bac8bb0426be4dd6a124471b69 Mon Sep 17 00:00:00 2001
+From: Andrey Smirnov <andrew.smirnov@gmail.com>
+Date: Tue, 22 Oct 2019 08:30:10 -0700
+Subject: [PATCH] crypto: caam - use devres to de-initialize the RNG
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Use devres to de-initialize the RNG and drop explicit de-initialization
+code in caam_remove().
+
+Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
+Cc: Chris Healy <cphealy@gmail.com>
+Cc: Lucas Stach <l.stach@pengutronix.de>
+Cc: Horia Geantă <horia.geanta@nxp.com>
+Cc: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: Iuliana Prodan <iuliana.prodan@nxp.com>
+Cc: linux-crypto@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org
+Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+(cherry picked from commit e57acaf0dfe0c8f63411d43cf7c689e43f6810c0)
+---
+ drivers/crypto/caam/ctrl.c | 130 ++++++++++++++++++++++++---------------------
+ 1 file changed, 70 insertions(+), 60 deletions(-)
+
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -176,6 +176,73 @@ static inline int run_descriptor_deco0(s
+ }
+ /*
++ * deinstantiate_rng - builds and executes a descriptor on DECO0,
++ *                   which deinitializes the RNG block.
++ * @ctrldev - pointer to device
++ * @state_handle_mask - bitmask containing the instantiation status
++ *                    for the RNG4 state handles which exist in
++ *                    the RNG4 block: 1 if it's been instantiated
++ *
++ * Return: - 0 if no error occurred
++ *       - -ENOMEM if there isn't enough memory to allocate the descriptor
++ *       - -ENODEV if DECO0 couldn't be acquired
++ *       - -EAGAIN if an error occurred when executing the descriptor
++ */
++static int deinstantiate_rng(struct device *ctrldev, int state_handle_mask)
++{
++      u32 *desc, status;
++      int sh_idx, ret = 0;
++
++      desc = kmalloc(CAAM_CMD_SZ * 3, GFP_KERNEL);
++      if (!desc)
++              return -ENOMEM;
++
++      for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) {
++              /*
++               * If the corresponding bit is set, then it means the state
++               * handle was initialized by us, and thus it needs to be
++               * deinitialized as well
++               */
++              if ((1 << sh_idx) & state_handle_mask) {
++                      /*
++                       * Create the descriptor for deinstantating this state
++                       * handle
++                       */
++                      build_deinstantiation_desc(desc, sh_idx);
++
++                      /* Try to run it through DECO0 */
++                      ret = run_descriptor_deco0(ctrldev, desc, &status);
++
++                      if (ret ||
++                          (status && status != JRSTA_SSRC_JUMP_HALT_CC)) {
++                              dev_err(ctrldev,
++                                      "Failed to deinstantiate RNG4 SH%d\n",
++                                      sh_idx);
++                              break;
++                      }
++                      dev_info(ctrldev, "Deinstantiated RNG4 SH%d\n", sh_idx);
++              }
++      }
++
++      kfree(desc);
++
++      return ret;
++}
++
++static void devm_deinstantiate_rng(void *data)
++{
++      struct device *ctrldev = data;
++      struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
++
++      /*
++       * De-initialize RNG state handles initialized by this driver.
++       * In case of SoCs with Management Complex, RNG is managed by MC f/w.
++       */
++      if (ctrlpriv->rng4_sh_init)
++              deinstantiate_rng(ctrldev, ctrlpriv->rng4_sh_init);
++}
++
++/*
+  * instantiate_rng - builds and executes a descriptor on DECO0,
+  *                 which initializes the RNG block.
+  * @ctrldev - pointer to device
+@@ -247,59 +314,9 @@ static int instantiate_rng(struct device
+       kfree(desc);
+-      return ret;
+-}
+-
+-/*
+- * deinstantiate_rng - builds and executes a descriptor on DECO0,
+- *                   which deinitializes the RNG block.
+- * @ctrldev - pointer to device
+- * @state_handle_mask - bitmask containing the instantiation status
+- *                    for the RNG4 state handles which exist in
+- *                    the RNG4 block: 1 if it's been instantiated
+- *
+- * Return: - 0 if no error occurred
+- *       - -ENOMEM if there isn't enough memory to allocate the descriptor
+- *       - -ENODEV if DECO0 couldn't be acquired
+- *       - -EAGAIN if an error occurred when executing the descriptor
+- */
+-static int deinstantiate_rng(struct device *ctrldev, int state_handle_mask)
+-{
+-      u32 *desc, status;
+-      int sh_idx, ret = 0;
+-
+-      desc = kmalloc(CAAM_CMD_SZ * 3, GFP_KERNEL);
+-      if (!desc)
+-              return -ENOMEM;
+-
+-      for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) {
+-              /*
+-               * If the corresponding bit is set, then it means the state
+-               * handle was initialized by us, and thus it needs to be
+-               * deinitialized as well
+-               */
+-              if ((1 << sh_idx) & state_handle_mask) {
+-                      /*
+-                       * Create the descriptor for deinstantating this state
+-                       * handle
+-                       */
+-                      build_deinstantiation_desc(desc, sh_idx);
+-
+-                      /* Try to run it through DECO0 */
+-                      ret = run_descriptor_deco0(ctrldev, desc, &status);
+-
+-                      if (ret ||
+-                          (status && status != JRSTA_SSRC_JUMP_HALT_CC)) {
+-                              dev_err(ctrldev,
+-                                      "Failed to deinstantiate RNG4 SH%d\n",
+-                                      sh_idx);
+-                              break;
+-                      }
+-                      dev_info(ctrldev, "Deinstantiated RNG4 SH%d\n", sh_idx);
+-              }
+-      }
+-
+-      kfree(desc);
++      if (!ret)
++              ret = devm_add_action_or_reset(ctrldev, devm_deinstantiate_rng,
++                                             ctrldev);
+       return ret;
+ }
+@@ -320,13 +337,6 @@ static int caam_remove(struct platform_d
+               caam_qi_shutdown(ctrldev);
+ #endif
+-      /*
+-       * De-initialize RNG state handles initialized by this driver.
+-       * In case of SoCs with Management Complex, RNG is managed by MC f/w.
+-       */
+-      if (!ctrlpriv->mc_en && ctrlpriv->rng4_sh_init)
+-              deinstantiate_rng(ctrldev, ctrlpriv->rng4_sh_init);
+-
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0007-crypto-caam-use-devres-to-de-initialize-QI.patch b/target/linux/layerscape/patches-5.4/804-crypto-0007-crypto-caam-use-devres-to-de-initialize-QI.patch
new file mode 100644 (file)
index 0000000..f9e7940
--- /dev/null
@@ -0,0 +1,114 @@
+From 5a359d189f9938d30046aedfc94c9cd7fe383e34 Mon Sep 17 00:00:00 2001
+From: Andrey Smirnov <andrew.smirnov@gmail.com>
+Date: Tue, 22 Oct 2019 08:30:11 -0700
+Subject: [PATCH] crypto: caam - use devres to de-initialize QI
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Use devres to de-initialize the QI and drop explicit de-initialization
+code in caam_remove().
+
+Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
+Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
+Cc: Chris Healy <cphealy@gmail.com>
+Cc: Lucas Stach <l.stach@pengutronix.de>
+Cc: Horia Geantă <horia.geanta@nxp.com>
+Cc: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: Iuliana Prodan <iuliana.prodan@nxp.com>
+Cc: linux-crypto@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+(cherry picked from commit f414de2e2fffd89c8a4e5b5e06b0eba5f9d8b1eb)
+---
+ drivers/crypto/caam/ctrl.c   | 14 +-------------
+ drivers/crypto/caam/intern.h |  3 ---
+ drivers/crypto/caam/qi.c     |  8 ++++++--
+ drivers/crypto/caam/qi.h     |  1 -
+ 4 files changed, 7 insertions(+), 19 deletions(-)
+
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -332,11 +332,6 @@ static int caam_remove(struct platform_d
+       /* Remove platform devices under the crypto node */
+       of_platform_depopulate(ctrldev);
+-#ifdef CONFIG_CAAM_QI
+-      if (ctrlpriv->qi_init)
+-              caam_qi_shutdown(ctrldev);
+-#endif
+-
+       return 0;
+ }
+@@ -767,7 +762,7 @@ static int caam_probe(struct platform_de
+       ret = of_platform_populate(nprop, caam_match, NULL, dev);
+       if (ret) {
+               dev_err(dev, "JR platform devices creation error\n");
+-              goto shutdown_qi;
++              return ret;
+       }
+       ring = 0;
+@@ -928,13 +923,6 @@ static int caam_probe(struct platform_de
+ caam_remove:
+       caam_remove(pdev);
+       return ret;
+-
+-shutdown_qi:
+-#ifdef CONFIG_CAAM_QI
+-      if (ctrlpriv->qi_init)
+-              caam_qi_shutdown(dev);
+-#endif
+-      return ret;
+ }
+ static struct platform_driver caam_driver = {
+--- a/drivers/crypto/caam/intern.h
++++ b/drivers/crypto/caam/intern.h
+@@ -81,9 +81,6 @@ struct caam_drv_private {
+        */
+       u8 total_jobrs;         /* Total Job Rings in device */
+       u8 qi_present;          /* Nonzero if QI present in device */
+-#ifdef CONFIG_CAAM_QI
+-      u8 qi_init;             /* Nonzero if QI has been initialized */
+-#endif
+       u8 mc_en;               /* Nonzero if MC f/w is active */
+       int secvio_irq;         /* Security violation interrupt number */
+       int virt_en;            /* Virtualization enabled in CAAM */
+--- a/drivers/crypto/caam/qi.c
++++ b/drivers/crypto/caam/qi.c
+@@ -500,9 +500,10 @@ void caam_drv_ctx_rel(struct caam_drv_ct
+ }
+ EXPORT_SYMBOL(caam_drv_ctx_rel);
+-void caam_qi_shutdown(struct device *qidev)
++static void caam_qi_shutdown(void *data)
+ {
+       int i;
++      struct device *qidev = data;
+       struct caam_qi_priv *priv = &qipriv;
+       const cpumask_t *cpus = qman_affine_cpus();
+@@ -761,7 +762,10 @@ int caam_qi_init(struct platform_device
+                           &times_congested, &caam_fops_u64_ro);
+ #endif
+-      ctrlpriv->qi_init = 1;
++      err = devm_add_action_or_reset(qidev, caam_qi_shutdown, ctrlpriv);
++      if (err)
++              return err;
++
+       dev_info(qidev, "Linux CAAM Queue I/F driver initialised\n");
+       return 0;
+ }
+--- a/drivers/crypto/caam/qi.h
++++ b/drivers/crypto/caam/qi.h
+@@ -147,7 +147,6 @@ int caam_drv_ctx_update(struct caam_drv_
+ void caam_drv_ctx_rel(struct caam_drv_ctx *drv_ctx);
+ int caam_qi_init(struct platform_device *pdev);
+-void caam_qi_shutdown(struct device *dev);
+ /**
+  * qi_cache_alloc - Allocate buffers from CAAM-QI cache
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0008-crypto-caam-use-devres-to-populate-platform-devices.patch b/target/linux/layerscape/patches-5.4/804-crypto-0008-crypto-caam-use-devres-to-populate-platform-devices.patch
new file mode 100644 (file)
index 0000000..c3a8ba2
--- /dev/null
@@ -0,0 +1,96 @@
+From 7200bc3a88315a59e7094bf111c7816f0298923f Mon Sep 17 00:00:00 2001
+From: Andrey Smirnov <andrew.smirnov@gmail.com>
+Date: Tue, 22 Oct 2019 08:30:12 -0700
+Subject: [PATCH] crypto: caam - use devres to populate platform devices
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Use devres to de-initialize the RNG and drop explicit de-initialization
+code in caam_remove().
+
+Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
+Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
+Cc: Chris Healy <cphealy@gmail.com>
+Cc: Lucas Stach <l.stach@pengutronix.de>
+Cc: Horia Geantă <horia.geanta@nxp.com>
+Cc: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: Iuliana Prodan <iuliana.prodan@nxp.com>
+Cc: linux-crypto@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+(cherry picked from commit 1a1c4f004444ebb962a02b7fc6d534e0f2ed9acb)
+---
+ drivers/crypto/caam/ctrl.c | 26 +++-----------------------
+ 1 file changed, 3 insertions(+), 23 deletions(-)
+
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -321,20 +321,6 @@ static int instantiate_rng(struct device
+       return ret;
+ }
+-static int caam_remove(struct platform_device *pdev)
+-{
+-      struct device *ctrldev;
+-      struct caam_drv_private *ctrlpriv;
+-
+-      ctrldev = &pdev->dev;
+-      ctrlpriv = dev_get_drvdata(ctrldev);
+-
+-      /* Remove platform devices under the crypto node */
+-      of_platform_depopulate(ctrldev);
+-
+-      return 0;
+-}
+-
+ /*
+  * kick_trng - sets the various parameters for enabling the initialization
+  *           of the RNG4 block in CAAM
+@@ -759,7 +745,7 @@ static int caam_probe(struct platform_de
+ #endif
+       }
+-      ret = of_platform_populate(nprop, caam_match, NULL, dev);
++      ret = devm_of_platform_populate(dev);
+       if (ret) {
+               dev_err(dev, "JR platform devices creation error\n");
+               return ret;
+@@ -781,8 +767,7 @@ static int caam_probe(struct platform_de
+       /* If no QI and no rings specified, quit and go home */
+       if ((!ctrlpriv->qi_present) && (!ctrlpriv->total_jobrs)) {
+               dev_err(dev, "no queues configured, terminating\n");
+-              ret = -ENOMEM;
+-              goto caam_remove;
++              return -ENOMEM;
+       }
+       if (ctrlpriv->era < 10)
+@@ -845,7 +830,7 @@ static int caam_probe(struct platform_de
+               } while ((ret == -EAGAIN) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
+               if (ret) {
+                       dev_err(dev, "failed to instantiate RNG");
+-                      goto caam_remove;
++                      return ret;
+               }
+               /*
+                * Set handles init'ed by this module as the complement of the
+@@ -919,10 +904,6 @@ static int caam_probe(struct platform_de
+                           &ctrlpriv->ctl_tdsk_wrap);
+ #endif
+       return 0;
+-
+-caam_remove:
+-      caam_remove(pdev);
+-      return ret;
+ }
+ static struct platform_driver caam_driver = {
+@@ -931,7 +912,6 @@ static struct platform_driver caam_drive
+               .of_match_table = caam_match,
+       },
+       .probe       = caam_probe,
+-      .remove      = caam_remove,
+ };
+ module_platform_driver(caam_driver);
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0009-crypto-caam-populate-platform-devices-last.patch b/target/linux/layerscape/patches-5.4/804-crypto-0009-crypto-caam-populate-platform-devices-last.patch
new file mode 100644 (file)
index 0000000..8ab1199
--- /dev/null
@@ -0,0 +1,56 @@
+From 6d186bceac74dd7fcabac860295cfb7b893168cd Mon Sep 17 00:00:00 2001
+From: Andrey Smirnov <andrew.smirnov@gmail.com>
+Date: Tue, 22 Oct 2019 08:30:13 -0700
+Subject: [PATCH] crypto: caam - populate platform devices last
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Move the call to devm_of_platform_populate() at the end of
+caam_probe(), so we won't try to add any child devices until all of
+the initialization is finished successfully.
+
+Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
+Cc: Chris Healy <cphealy@gmail.com>
+Cc: Lucas Stach <l.stach@pengutronix.de>
+Cc: Horia Geantă <horia.geanta@nxp.com>
+Cc: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: Iuliana Prodan <iuliana.prodan@nxp.com>
+Cc: linux-crypto@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org
+Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+(cherry picked from commit 51d13aaf59779ff4d13f1def2c72ae102a1aad40)
+---
+ drivers/crypto/caam/ctrl.c | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -745,12 +745,6 @@ static int caam_probe(struct platform_de
+ #endif
+       }
+-      ret = devm_of_platform_populate(dev);
+-      if (ret) {
+-              dev_err(dev, "JR platform devices creation error\n");
+-              return ret;
+-      }
+-
+       ring = 0;
+       for_each_available_child_of_node(nprop, np)
+               if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
+@@ -903,7 +897,12 @@ static int caam_probe(struct platform_de
+       debugfs_create_blob("tdsk", S_IRUSR | S_IRGRP | S_IROTH, ctrlpriv->ctl,
+                           &ctrlpriv->ctl_tdsk_wrap);
+ #endif
+-      return 0;
++
++      ret = devm_of_platform_populate(dev);
++      if (ret)
++              dev_err(dev, "JR platform devices creation error\n");
++
++      return ret;
+ }
+ static struct platform_driver caam_driver = {
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0010-MLK-9769-1-crypto-caam-jr-remove-incorrect-comment-f.patch b/target/linux/layerscape/patches-5.4/804-crypto-0010-MLK-9769-1-crypto-caam-jr-remove-incorrect-comment-f.patch
new file mode 100644 (file)
index 0000000..a9221cc
--- /dev/null
@@ -0,0 +1,39 @@
+From 7bf33e375e1b260d2ef3c414852a2131ce11d113 Mon Sep 17 00:00:00 2001
+From: Victoria Milhoan <vicki.milhoan@freescale.com>
+Date: Wed, 29 Oct 2014 11:23:05 -0700
+Subject: [PATCH] MLK-9769-1 crypto: caam/jr - remove incorrect comment from
+ job ring module
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+caam_jr_register() function is no longer part of the driver since
+commit 6dad41158db6 ("crypto: caam - Remove unused functions from Job Ring")
+
+This patch removes a comment referencing the function.
+
+Signed-off-by: Victoria Milhoan <vicki.milhoan@freescale.com>
+Signed-off-by: Dan Douglass <dan.douglass@freescale.com>
+Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
+(cherry picked from commit 96c125b8962ba5bcbb625b0b162644c16fb33685)
+
+-changed commit headline prefix
+-added details about commit removing caam_jr_register()
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/jr.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/crypto/caam/jr.c
++++ b/drivers/crypto/caam/jr.c
+@@ -327,8 +327,7 @@ EXPORT_SYMBOL(caam_jr_free);
+  * caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK,
+  * -EBUSY if the queue is full, -EIO if it cannot map the caller's
+  * descriptor.
+- * @dev:  device of the job ring to be used. This device should have
+- *        been assigned prior by caam_jr_register().
++ * @dev:  struct device of the job ring to be used
+  * @desc: points to a job descriptor that execute our request. All
+  *        descriptors (and all referenced data) must be in a DMAable
+  *        region, and all data references must be physical addresses
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0011-MLK-20204-crypto-caam-remove-deadcode-on-32-bit-plat.patch b/target/linux/layerscape/patches-5.4/804-crypto-0011-MLK-20204-crypto-caam-remove-deadcode-on-32-bit-plat.patch
new file mode 100644 (file)
index 0000000..1adf634
--- /dev/null
@@ -0,0 +1,42 @@
+From 4269eb560ac34c5974559fe256811c1ac5d764ed Mon Sep 17 00:00:00 2001
+From: Franck LENORMAND <franck.lenormand@nxp.com>
+Date: Fri, 23 Nov 2018 16:06:45 +0100
+Subject: [PATCH] MLK-20204 crypto: caam - remove deadcode on 32-bit platforms
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When building on a platform with a 32bit DMA address, taking the
+upper 32 bits makes no sense.
+
+Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
+(cherry picked from commit d3346aaa3fbfaf9b7f827d8554f076e3fc82c35b)
+
+-replace ifdeffery with IS_ENABLED() macro
+-change commit headline prefix
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/regs.h | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/drivers/crypto/caam/regs.h
++++ b/drivers/crypto/caam/regs.h
+@@ -173,9 +173,14 @@ static inline u64 rd_reg64(void __iomem
+ static inline u64 cpu_to_caam_dma64(dma_addr_t value)
+ {
+-      if (caam_imx)
+-              return (((u64)cpu_to_caam32(lower_32_bits(value)) << 32) |
+-                       (u64)cpu_to_caam32(upper_32_bits(value)));
++      if (caam_imx) {
++              u64 ret_val = (u64)cpu_to_caam32(lower_32_bits(value)) << 32;
++
++              if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT))
++                      ret_val |= (u64)cpu_to_caam32(upper_32_bits(value));
++
++              return ret_val;
++      }
+       return cpu_to_caam64(value);
+ }
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0012-MLK-19053-crypto-caam-RNG4-TRNG-errata.patch b/target/linux/layerscape/patches-5.4/804-crypto-0012-MLK-19053-crypto-caam-RNG4-TRNG-errata.patch
new file mode 100644 (file)
index 0000000..52d15b7
--- /dev/null
@@ -0,0 +1,63 @@
+From e1a89cdf6fa6b04806eb24b939738bb89ab62914 Mon Sep 17 00:00:00 2001
+From: Aymen Sghaier <aymen.sghaier@nxp.com>
+Date: Thu, 13 Sep 2018 16:41:03 +0200
+Subject: [PATCH] MLK-19053 crypto: caam - RNG4 TRNG errata
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+ The TRNG as used in RNG4, used in CAAM has a documentation issue. The
+effect is that it is possible that the entropy used to instantiate the
+DRBG may be old entropy, rather than newly generated entropy. There is
+proper programming guidance, but it is not in the documentation.
+
+Signed-off-by: Aymen Sghaier <aymen.sghaier@nxp.com>
+Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
+(cherry picked from commit ea2b30c8171acf7624e3d44276737c3878ca900d)
+
+-ported to RNG initialization in ctrl.c
+-changed commit headline
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/ctrl.c | 9 +++++++--
+ drivers/crypto/caam/regs.h | 3 ++-
+ 2 files changed, 9 insertions(+), 3 deletions(-)
+
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -339,7 +339,11 @@ static void kick_trng(struct platform_de
+       r4tst = &ctrl->r4tst[0];
+       /* put RNG4 into program mode */
+-      clrsetbits_32(&r4tst->rtmctl, 0, RTMCTL_PRGM);
++      /* Setting both RTMCTL:PRGM and RTMCTL:TRNG_ACC causes TRNG to
++       * properly invalidate the entropy in the entropy register and
++       * force re-generation.
++       */
++      clrsetbits_32(&r4tst->rtmctl, 0, RTMCTL_PRGM | RTMCTL_ACC);
+       /*
+        * Performance-wise, it does not make sense to
+@@ -369,7 +373,8 @@ start_rng:
+        * select raw sampling in both entropy shifter
+        * and statistical checker; ; put RNG4 into run mode
+        */
+-      clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM, RTMCTL_SAMP_MODE_RAW_ES_SC);
++      clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM | RTMCTL_ACC,
++                    RTMCTL_SAMP_MODE_RAW_ES_SC);
+ }
+ static int caam_get_era_from_hw(struct caam_ctrl __iomem *ctrl)
+--- a/drivers/crypto/caam/regs.h
++++ b/drivers/crypto/caam/regs.h
+@@ -492,7 +492,8 @@ struct rngtst {
+ /* RNG4 TRNG test registers */
+ struct rng4tst {
+-#define RTMCTL_PRGM   0x00010000      /* 1 -> program mode, 0 -> run mode */
++#define RTMCTL_ACC  BIT(5)  /* TRNG access mode */
++#define RTMCTL_PRGM BIT(16) /* 1 -> program mode, 0 -> run mode */
+ #define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_SC    0 /* use von Neumann data in
+                                                    both entropy shifter and
+                                                    statistical checker */
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0013-MLK-9769-9-crypto-caam-adjust-RNG-timing-to-support-.patch b/target/linux/layerscape/patches-5.4/804-crypto-0013-MLK-9769-9-crypto-caam-adjust-RNG-timing-to-support-.patch
new file mode 100644 (file)
index 0000000..5c30e1d
--- /dev/null
@@ -0,0 +1,36 @@
+From 5bc830089553a445952d69a73e0a9f5fdf9d0f19 Mon Sep 17 00:00:00 2001
+From: Victoria Milhoan <vicki.milhoan@freescale.com>
+Date: Wed, 12 Nov 2014 09:58:24 -0700
+Subject: [PATCH] MLK-9769-9 crypto: caam - adjust RNG timing to support more
+ devices
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Adjust RNG timing parameters to support more i.MX6 devices.
+
+Signed-off-by: Victoria Milhoan <vicki.milhoan@freescale.com>
+Signed-off-by: Dan Douglass <dan.douglass@freescale.com>
+Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
+(cherry picked from commit 57eabb638430ec68490d192738640b95a3507b1d)
+
+Changed commit headline prefix.
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/ctrl.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -364,8 +364,8 @@ static void kick_trng(struct platform_de
+       wr_reg32(&r4tst->rtsdctl, val);
+       /* min. freq. count, equal to 1/4 of the entropy sample length */
+       wr_reg32(&r4tst->rtfrqmin, ent_delay >> 2);
+-      /* disable maximum frequency count */
+-      wr_reg32(&r4tst->rtfrqmax, RTFRQMAX_DISABLE);
++      /* max. freq. count, equal to 16 times the entropy sample length */
++      wr_reg32(&r4tst->rtfrqmax, ent_delay << 4);
+       /* read the control register */
+       val = rd_reg32(&r4tst->rtmctl);
+ start_rng:
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0014-MLK-9769-8-crypto-caam-add-a-test-for-the-RNG.patch b/target/linux/layerscape/patches-5.4/804-crypto-0014-MLK-9769-8-crypto-caam-add-a-test-for-the-RNG.patch
new file mode 100644 (file)
index 0000000..b5a4bf1
--- /dev/null
@@ -0,0 +1,108 @@
+From 387a26c56933fbfd0fa211ad5347d48d08695ea0 Mon Sep 17 00:00:00 2001
+From: "Victoria Milhoan (b42089)" <vicki.milhoan@freescale.com>
+Date: Fri, 17 Oct 2014 16:30:56 -0700
+Subject: [PATCH] MLK-9769-8 crypto: caam - add a test for the RNG
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Freescale's CAAM includes a Random Number Generator.  This change adds
+a kernel configuration option to test the RNG's capabilities via the
+hw_random framework.
+
+Signed-off-by: Victoria Milhoan <vicki.milhoan@freescale.com>
+Signed-off-by: Dan Douglass <dan.douglass@freescale.com>
+Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
+(cherry picked from commit 05fba1bb857d5329fdcf79e736643fce0944a86d)
+
+-fixed compilation warning:
+drivers/crypto/caam/caamrng.c:271:2: warning: format '%d' expects argument of type 'int', but argument 2 has type 'size_t' [-Wformat=]
+
+-changed commit headline
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/Kconfig   |  8 ++++++++
+ drivers/crypto/caam/caamrng.c | 47 +++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 55 insertions(+)
+
+--- a/drivers/crypto/caam/Kconfig
++++ b/drivers/crypto/caam/Kconfig
+@@ -147,6 +147,14 @@ config CRYPTO_DEV_FSL_CAAM_RNG_API
+         Selecting this will register the SEC4 hardware rng to
+         the hw_random API for suppying the kernel entropy pool.
++config CRYPTO_DEV_FSL_CAAM_RNG_TEST
++      bool "Test caam rng"
++      depends on CRYPTO_DEV_FSL_CAAM_RNG_API
++      help
++        Selecting this will enable a self-test to run for the
++        caam RNG. This test is several minutes long and executes
++        just before the RNG is registered with the hw_random API.
++
+ endif # CRYPTO_DEV_FSL_CAAM_JR
+ endif # CRYPTO_DEV_FSL_CAAM
+--- a/drivers/crypto/caam/caamrng.c
++++ b/drivers/crypto/caam/caamrng.c
+@@ -258,6 +258,49 @@ static void caam_cleanup(struct hwrng *r
+       rng_unmap_ctx(rng_ctx);
+ }
++#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST
++static inline void test_len(struct hwrng *rng, size_t len, bool wait)
++{
++      u8 *buf;
++      int real_len;
++
++      buf = kzalloc(sizeof(u8) * len, GFP_KERNEL);
++      real_len = rng->read(rng, buf, len, wait);
++      if (real_len == 0 && wait)
++              pr_err("WAITING FAILED\n");
++      pr_info("wanted %zu bytes, got %d\n", len, real_len);
++      print_hex_dump(KERN_INFO, "random bytes@: ", DUMP_PREFIX_ADDRESS,
++                     16, 4, buf, real_len, 1);
++      kfree(buf);
++}
++
++static inline void test_mode_once(struct hwrng *rng, bool wait)
++{
++#define TEST_CHUNK (RN_BUF_SIZE / 4)
++
++      test_len(rng, TEST_CHUNK, wait);
++      test_len(rng, RN_BUF_SIZE * 2, wait);
++      test_len(rng, RN_BUF_SIZE * 2 - TEST_CHUNK, wait);
++}
++
++static inline void test_mode(struct hwrng *rng, bool wait)
++{
++#define TEST_PASS 1
++      int i;
++
++      for (i = 0; i < TEST_PASS; i++)
++              test_mode_once(rng, wait);
++}
++
++static void self_test(struct hwrng *rng)
++{
++      pr_info("testing without waiting\n");
++      test_mode(rng, false);
++      pr_info("testing with waiting\n");
++      test_mode(rng, true);
++}
++#endif
++
+ static int caam_init_buf(struct caam_rng_ctx *ctx, int buf_id)
+ {
+       struct buf_data *bd = &ctx->bufs[buf_id];
+@@ -342,6 +385,10 @@ int caam_rng_init(struct device *ctrldev
+       if (err)
+               goto free_rng_ctx;
++#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST
++      self_test(&caam_rng);
++#endif
++
+       dev_info(dev, "registering rng-caam\n");
+       err = hwrng_register(&caam_rng);
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0015-MLKU-123-1-crypto-caam-add-support-for-i.mx8mm-mn.patch b/target/linux/layerscape/patches-5.4/804-crypto-0015-MLKU-123-1-crypto-caam-add-support-for-i.mx8mm-mn.patch
new file mode 100644 (file)
index 0000000..def910a
--- /dev/null
@@ -0,0 +1,47 @@
+From 866aab825ad10675b1e98004aec19127ec16b2b3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Horia=20Geant=C4=83?= <horia.geanta@nxp.com>
+Date: Mon, 23 Sep 2019 14:28:42 +0300
+Subject: [PATCH] MLKU-123-1 crypto: caam - add support for i.mx8mm, mn
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+TODO:
+
+1. clarify logic wrt. virtualization and DECORSR - see e-mail thread:
+"Register-based interface - DECORSR with virtualization disabled"
+
+2. check whether the clocks are identical for all mScale parts,
+and if they do use a single "i.MX8M*" entry in clocks array.
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/ctrl.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -99,10 +99,12 @@ static inline int run_descriptor_deco0(s
+       if (ctrlpriv->virt_en == 1 ||
+           /*
+-           * Apparently on i.MX8MQ it doesn't matter if virt_en == 1
++           * Apparently on i.MX8MQ, 8MM, 8MN it doesn't matter if virt_en == 1
+            * and the following steps should be performed regardless
+            */
+-          of_machine_is_compatible("fsl,imx8mq")) {
++          of_machine_is_compatible("fsl,imx8mq") ||
++          of_machine_is_compatible("fsl,imx8mm") ||
++          of_machine_is_compatible("fsl,imx8mn")) {
+               clrsetbits_32(&ctrl->deco_rsr, 0, DECORSR_JR0);
+               while (!(rd_reg32(&ctrl->deco_rsr) & DECORSR_VALID) &&
+@@ -514,6 +516,8 @@ static const struct soc_device_attribute
+       { .soc_id = "i.MX6*",  .data = &caam_imx6_data },
+       { .soc_id = "i.MX7*",  .data = &caam_imx7_data },
+       { .soc_id = "i.MX8MQ", .data = &caam_imx7_data },
++      { .soc_id = "i.MX8MM", .data = &caam_imx7_data },
++      { .soc_id = "i.MX8MN", .data = &caam_imx7_data },
+       { .family = "Freescale i.MX" },
+       { /* sentinel */ }
+ };
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0016-MLKU-114-1-crypto-caam-reduce-page-0-regs-access-to-.patch b/target/linux/layerscape/patches-5.4/804-crypto-0016-MLKU-114-1-crypto-caam-reduce-page-0-regs-access-to-.patch
new file mode 100644 (file)
index 0000000..23839a3
--- /dev/null
@@ -0,0 +1,296 @@
+From 3d21ebe0b870b9b65b3be0c1473e7148256c4d16 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Horia=20Geant=C4=83?= <horia.geanta@nxp.com>
+Date: Tue, 24 Sep 2019 14:56:48 +0300
+Subject: [PATCH] MLKU-114-1 crypto: caam - reduce page 0 regs access to
+ minimum
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+TODO:
+
+1. if of_property_read_u32_index(,,index=0,) is to be used,
+DT bindings (fsl-sec4.txt) should be updated to mandate for
+-checked that all existing DTs are configured like this
+-this might create problems in the future, if DTs are needed where
+JR DT nodes would exist without the controller DT node
+(directly on simple bus etc.)
+
+2. MCFGR (ctrl->mcr)
+How to determine caam_ptr_sz if MCFGR is not accesible?
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/caamalg.c  | 21 ++++++------
+ drivers/crypto/caam/caamhash.c |  8 +++--
+ drivers/crypto/caam/caampkc.c  |  4 +--
+ drivers/crypto/caam/caamrng.c  |  4 +--
+ drivers/crypto/caam/ctrl.c     | 78 ++++++++++++++++++++++++++----------------
+ 5 files changed, 68 insertions(+), 47 deletions(-)
+
+--- a/drivers/crypto/caam/caamalg.c
++++ b/drivers/crypto/caam/caamalg.c
+@@ -3542,13 +3542,14 @@ int caam_algapi_init(struct device *ctrl
+        * First, detect presence and attributes of DES, AES, and MD blocks.
+        */
+       if (priv->era < 10) {
++              struct caam_perfmon __iomem *perfmon = &priv->jr[0]->perfmon;
+               u32 cha_vid, cha_inst, aes_rn;
+-              cha_vid = rd_reg32(&priv->ctrl->perfmon.cha_id_ls);
++              cha_vid = rd_reg32(&perfmon->cha_id_ls);
+               aes_vid = cha_vid & CHA_ID_LS_AES_MASK;
+               md_vid = (cha_vid & CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT;
+-              cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls);
++              cha_inst = rd_reg32(&perfmon->cha_num_ls);
+               des_inst = (cha_inst & CHA_ID_LS_DES_MASK) >>
+                          CHA_ID_LS_DES_SHIFT;
+               aes_inst = cha_inst & CHA_ID_LS_AES_MASK;
+@@ -3558,24 +3559,24 @@ int caam_algapi_init(struct device *ctrl
+               ccha_inst = 0;
+               ptha_inst = 0;
+-              aes_rn = rd_reg32(&priv->ctrl->perfmon.cha_rev_ls) &
+-                       CHA_ID_LS_AES_MASK;
++              aes_rn = rd_reg32(&perfmon->cha_rev_ls) & CHA_ID_LS_AES_MASK;
+               gcm_support = !(aes_vid == CHA_VER_VID_AES_LP && aes_rn < 8);
+       } else {
++              struct version_regs __iomem *vreg = &priv->jr[0]->vreg;
+               u32 aesa, mdha;
+-              aesa = rd_reg32(&priv->ctrl->vreg.aesa);
+-              mdha = rd_reg32(&priv->ctrl->vreg.mdha);
++              aesa = rd_reg32(&vreg->aesa);
++              mdha = rd_reg32(&vreg->mdha);
+               aes_vid = (aesa & CHA_VER_VID_MASK) >> CHA_VER_VID_SHIFT;
+               md_vid = (mdha & CHA_VER_VID_MASK) >> CHA_VER_VID_SHIFT;
+-              des_inst = rd_reg32(&priv->ctrl->vreg.desa) & CHA_VER_NUM_MASK;
++              des_inst = rd_reg32(&vreg->desa) & CHA_VER_NUM_MASK;
+               aes_inst = aesa & CHA_VER_NUM_MASK;
+               md_inst = mdha & CHA_VER_NUM_MASK;
+-              ccha_inst = rd_reg32(&priv->ctrl->vreg.ccha) & CHA_VER_NUM_MASK;
+-              ptha_inst = rd_reg32(&priv->ctrl->vreg.ptha) & CHA_VER_NUM_MASK;
+-              arc4_inst = rd_reg32(&priv->ctrl->vreg.afha) & CHA_VER_NUM_MASK;
++              ccha_inst = rd_reg32(&vreg->ccha) & CHA_VER_NUM_MASK;
++              ptha_inst = rd_reg32(&vreg->ptha) & CHA_VER_NUM_MASK;
++              arc4_inst = rd_reg32(&vreg->afha) & CHA_VER_NUM_MASK;
+               gcm_support = aesa & CHA_VER_MISC_AES_GCM;
+       }
+--- a/drivers/crypto/caam/caamhash.c
++++ b/drivers/crypto/caam/caamhash.c
+@@ -1991,12 +1991,14 @@ int caam_algapi_hash_init(struct device
+        * presence and attributes of MD block.
+        */
+       if (priv->era < 10) {
+-              md_vid = (rd_reg32(&priv->ctrl->perfmon.cha_id_ls) &
++              struct caam_perfmon __iomem *perfmon = &priv->jr[0]->perfmon;
++
++              md_vid = (rd_reg32(&perfmon->cha_id_ls) &
+                         CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT;
+-              md_inst = (rd_reg32(&priv->ctrl->perfmon.cha_num_ls) &
++              md_inst = (rd_reg32(&perfmon->cha_num_ls) &
+                          CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT;
+       } else {
+-              u32 mdha = rd_reg32(&priv->ctrl->vreg.mdha);
++              u32 mdha = rd_reg32(&priv->jr[0]->vreg.mdha);
+               md_vid = (mdha & CHA_VER_VID_MASK) >> CHA_VER_VID_SHIFT;
+               md_inst = mdha & CHA_VER_NUM_MASK;
+--- a/drivers/crypto/caam/caampkc.c
++++ b/drivers/crypto/caam/caampkc.c
+@@ -1099,10 +1099,10 @@ int caam_pkc_init(struct device *ctrldev
+       /* Determine public key hardware accelerator presence. */
+       if (priv->era < 10)
+-              pk_inst = (rd_reg32(&priv->ctrl->perfmon.cha_num_ls) &
++              pk_inst = (rd_reg32(&priv->jr[0]->perfmon.cha_num_ls) &
+                          CHA_ID_LS_PK_MASK) >> CHA_ID_LS_PK_SHIFT;
+       else
+-              pk_inst = rd_reg32(&priv->ctrl->vreg.pkha) & CHA_VER_NUM_MASK;
++              pk_inst = rd_reg32(&priv->jr[0]->vreg.pkha) & CHA_VER_NUM_MASK;
+       /* Do not register algorithms if PKHA is not present. */
+       if (!pk_inst)
+--- a/drivers/crypto/caam/caamrng.c
++++ b/drivers/crypto/caam/caamrng.c
+@@ -363,10 +363,10 @@ int caam_rng_init(struct device *ctrldev
+       /* Check for an instantiated RNG before registration */
+       if (priv->era < 10)
+-              rng_inst = (rd_reg32(&priv->ctrl->perfmon.cha_num_ls) &
++              rng_inst = (rd_reg32(&priv->jr[0]->perfmon.cha_num_ls) &
+                           CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT;
+       else
+-              rng_inst = rd_reg32(&priv->ctrl->vreg.rng) & CHA_VER_NUM_MASK;
++              rng_inst = rd_reg32(&priv->jr[0]->vreg.rng) & CHA_VER_NUM_MASK;
+       if (!rng_inst)
+               return 0;
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -379,7 +379,7 @@ start_rng:
+                     RTMCTL_SAMP_MODE_RAW_ES_SC);
+ }
+-static int caam_get_era_from_hw(struct caam_ctrl __iomem *ctrl)
++static int caam_get_era_from_hw(struct caam_perfmon __iomem *perfmon)
+ {
+       static const struct {
+               u16 ip_id;
+@@ -405,12 +405,12 @@ static int caam_get_era_from_hw(struct c
+       u16 ip_id;
+       int i;
+-      ccbvid = rd_reg32(&ctrl->perfmon.ccb_id);
++      ccbvid = rd_reg32(&perfmon->ccb_id);
+       era = (ccbvid & CCBVID_ERA_MASK) >> CCBVID_ERA_SHIFT;
+       if (era)        /* This is '0' prior to CAAM ERA-6 */
+               return era;
+-      id_ms = rd_reg32(&ctrl->perfmon.caam_id_ms);
++      id_ms = rd_reg32(&perfmon->caam_id_ms);
+       ip_id = (id_ms & SECVID_MS_IPID_MASK) >> SECVID_MS_IPID_SHIFT;
+       maj_rev = (id_ms & SECVID_MS_MAJ_REV_MASK) >> SECVID_MS_MAJ_REV_SHIFT;
+@@ -428,7 +428,7 @@ static int caam_get_era_from_hw(struct c
+  * In case this property is not passed an attempt to retrieve the CAAM
+  * era via register reads will be made.
+  **/
+-static int caam_get_era(struct caam_ctrl __iomem *ctrl)
++static int caam_get_era(struct caam_perfmon __iomem *perfmon)
+ {
+       struct device_node *caam_node;
+       int ret;
+@@ -441,7 +441,7 @@ static int caam_get_era(struct caam_ctrl
+       if (!ret)
+               return prop;
+       else
+-              return caam_get_era_from_hw(ctrl);
++              return caam_get_era_from_hw(perfmon);
+ }
+ /*
+@@ -575,8 +575,8 @@ static int caam_probe(struct platform_de
+       struct device_node *nprop, *np;
+       struct caam_ctrl __iomem *ctrl;
+       struct caam_drv_private *ctrlpriv;
++      struct caam_perfmon __iomem *perfmon;
+ #ifdef CONFIG_DEBUG_FS
+-      struct caam_perfmon *perfmon;
+       struct dentry *dfs_root;
+ #endif
+       u32 scfgr, comp_params;
+@@ -616,9 +616,36 @@ static int caam_probe(struct platform_de
+               return ret;
+       }
+-      caam_little_end = !(bool)(rd_reg32(&ctrl->perfmon.status) &
++      ring = 0;
++      for_each_available_child_of_node(nprop, np)
++              if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
++                  of_device_is_compatible(np, "fsl,sec4.0-job-ring")) {
++                      u32 reg;
++
++                      if (of_property_read_u32_index(np, "reg", 0, &reg)) {
++                              dev_err(dev, "%s read reg property error\n",
++                                      np->full_name);
++                              continue;
++                      }
++
++                      ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *)
++                                           ((__force uint8_t *)ctrl + reg);
++
++                      ctrlpriv->total_jobrs++;
++                      ring++;
++              }
++
++      /*
++       * Wherever possible, instead of accessing registers from the global page,
++       * use the alias registers in the first (cf. DT nodes order)
++       * job ring's page.
++       */
++      perfmon = ring ? (struct caam_perfmon *)&ctrlpriv->jr[0]->perfmon :
++                       (struct caam_perfmon *)&ctrl->perfmon;
++
++      caam_little_end = !(bool)(rd_reg32(&perfmon->status) &
+                                 (CSTA_PLEND | CSTA_ALT_PLEND));
+-      comp_params = rd_reg32(&ctrl->perfmon.comp_parms_ms);
++      comp_params = rd_reg32(&perfmon->comp_parms_ms);
+       if (comp_params & CTPR_MS_PS && rd_reg32(&ctrl->mcr) & MCFGR_LONG_PTR)
+               caam_ptr_sz = sizeof(u64);
+       else
+@@ -718,7 +745,7 @@ static int caam_probe(struct platform_de
+               return ret;
+       }
+-      ctrlpriv->era = caam_get_era(ctrl);
++      ctrlpriv->era = caam_get_era(perfmon);
+       ctrlpriv->domain = iommu_get_domain_for_dev(dev);
+ #ifdef CONFIG_DEBUG_FS
+@@ -727,8 +754,6 @@ static int caam_probe(struct platform_de
+        * "caam" and nprop->full_name. The OF name isn't distinctive,
+        * but does separate instances
+        */
+-      perfmon = (struct caam_perfmon __force *)&ctrl->perfmon;
+-
+       dfs_root = debugfs_create_dir(dev_name(dev), NULL);
+       ret = devm_add_action_or_reset(dev, caam_remove_debugfs, dfs_root);
+       if (ret)
+@@ -754,31 +779,24 @@ static int caam_probe(struct platform_de
+ #endif
+       }
+-      ring = 0;
+-      for_each_available_child_of_node(nprop, np)
+-              if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
+-                  of_device_is_compatible(np, "fsl,sec4.0-job-ring")) {
+-                      ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *)
+-                                           ((__force uint8_t *)ctrl +
+-                                           (ring + JR_BLOCK_NUMBER) *
+-                                            BLOCK_OFFSET
+-                                           );
+-                      ctrlpriv->total_jobrs++;
+-                      ring++;
+-              }
+-
+       /* If no QI and no rings specified, quit and go home */
+       if ((!ctrlpriv->qi_present) && (!ctrlpriv->total_jobrs)) {
+               dev_err(dev, "no queues configured, terminating\n");
+               return -ENOMEM;
+       }
+-      if (ctrlpriv->era < 10)
+-              rng_vid = (rd_reg32(&ctrl->perfmon.cha_id_ls) &
++      if (ctrlpriv->era < 10) {
++              rng_vid = (rd_reg32(&perfmon->cha_id_ls) &
+                          CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT;
+-      else
+-              rng_vid = (rd_reg32(&ctrl->vreg.rng) & CHA_VER_VID_MASK) >>
++      } else {
++              struct version_regs __iomem *vreg;
++
++              vreg = ring ? (struct version_regs *)&ctrlpriv->jr[0]->vreg :
++                            (struct version_regs *)&ctrl->vreg;
++
++              rng_vid = (rd_reg32(&vreg->rng) & CHA_VER_VID_MASK) >>
+                          CHA_VER_VID_SHIFT;
++      }
+       /*
+        * If SEC has RNG version >= 4 and RNG state handle has not been
+@@ -847,8 +865,8 @@ static int caam_probe(struct platform_de
+       /* NOTE: RTIC detection ought to go here, around Si time */
+-      caam_id = (u64)rd_reg32(&ctrl->perfmon.caam_id_ms) << 32 |
+-                (u64)rd_reg32(&ctrl->perfmon.caam_id_ls);
++      caam_id = (u64)rd_reg32(&perfmon->caam_id_ms) << 32 |
++                (u64)rd_reg32(&perfmon->caam_id_ls);
+       /* Report "alive" for developer to see */
+       dev_info(dev, "device ID = 0x%016llx (Era %d)\n", caam_id,
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0017-MLKU-114-2-crypto-caam-SCU-firmware-support.patch b/target/linux/layerscape/patches-5.4/804-crypto-0017-MLKU-114-2-crypto-caam-SCU-firmware-support.patch
new file mode 100644 (file)
index 0000000..9ff30d8
--- /dev/null
@@ -0,0 +1,137 @@
+From b752c8ed4ab83d47a585c363056d64fb978ef481 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Horia=20Geant=C4=83?= <horia.geanta@nxp.com>
+Date: Fri, 27 Sep 2019 20:05:26 +0300
+Subject: [PATCH] MLKU-114-2 crypto: caam - SCU firmware support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Some i.MX8 processors, e.g. i.MX8QM (QM, QP), i.MX8QX (QXP, DX) have a
+System Controller Firmware (SCFW) running on a dedicated Cortex-M core
+that provides power, clock, and resource management.
+
+caam driver needs to be aware of SCU f/w presence, since some things
+are done differently:
+
+1. clocks are under SCU f/w control and are turned on automatically
+
+2. there is no access to controller's register page (note however that
+some registers are aliased in job rings' register pages)
+
+It's worth mentioning that due to this, MCFGR[PS] cannot be read
+and driver assumes MCFGR[PS] = b'0 - engine using 32-bit address pointers.
+This is in sync with the limitation imposed by the
+SECO (Security Controller) ROM and f/w running on a dedicated Cortex-M.
+
+3. as a consequence of "2.", part of the initialization is moved in
+other f/w (SCU, TF-A etc.), e.g. RNG initialization
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/ctrl.c   | 28 ++++++++++++++++++++++++++--
+ drivers/crypto/caam/intern.h |  1 +
+ 2 files changed, 27 insertions(+), 2 deletions(-)
+
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -596,6 +596,17 @@ static int caam_probe(struct platform_de
+       caam_imx = (bool)imx_soc_match;
+       if (imx_soc_match) {
++              np = of_find_compatible_node(NULL, NULL, "fsl,imx-scu");
++              ctrlpriv->scu_en = !!np;
++              of_node_put(np);
++
++              /*
++               * CAAM clocks cannot be controlled from kernel.
++               * They are automatically turned on by SCU f/w.
++               */
++              if (ctrlpriv->scu_en)
++                      goto iomap_ctrl;
++
+               if (!imx_soc_match->data) {
+                       dev_err(dev, "No clock data provided for i.MX SoC");
+                       return -EINVAL;
+@@ -606,7 +617,7 @@ static int caam_probe(struct platform_de
+                       return ret;
+       }
+-
++iomap_ctrl:
+       /* Get configuration properties from device tree */
+       /* First, get register page */
+       ctrl = devm_of_iomap(dev, nprop, 0, NULL);
+@@ -646,7 +657,8 @@ static int caam_probe(struct platform_de
+       caam_little_end = !(bool)(rd_reg32(&perfmon->status) &
+                                 (CSTA_PLEND | CSTA_ALT_PLEND));
+       comp_params = rd_reg32(&perfmon->comp_parms_ms);
+-      if (comp_params & CTPR_MS_PS && rd_reg32(&ctrl->mcr) & MCFGR_LONG_PTR)
++      if (!ctrlpriv->scu_en && comp_params & CTPR_MS_PS &&
++          rd_reg32(&ctrl->mcr) & MCFGR_LONG_PTR)
+               caam_ptr_sz = sizeof(u64);
+       else
+               caam_ptr_sz = sizeof(u32);
+@@ -696,6 +708,9 @@ static int caam_probe(struct platform_de
+       /* Get the IRQ of the controller (for security violations only) */
+       ctrlpriv->secvio_irq = irq_of_parse_and_map(nprop, 0);
++      if (ctrlpriv->scu_en)
++              goto set_dma_mask;
++
+       /*
+        * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel,
+        * long pointers in master configuration register.
+@@ -739,6 +754,7 @@ static int caam_probe(struct platform_de
+                             JRSTART_JR1_START | JRSTART_JR2_START |
+                             JRSTART_JR3_START);
++set_dma_mask:
+       ret = dma_set_mask_and_coherent(dev, caam_get_dma_mask(dev));
+       if (ret) {
+               dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret);
+@@ -785,6 +801,9 @@ static int caam_probe(struct platform_de
+               return -ENOMEM;
+       }
++      if (ctrlpriv->scu_en)
++              goto report_live;
++
+       if (ctrlpriv->era < 10) {
+               rng_vid = (rd_reg32(&perfmon->cha_id_ls) &
+                          CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT;
+@@ -865,6 +884,7 @@ static int caam_probe(struct platform_de
+       /* NOTE: RTIC detection ought to go here, around Si time */
++report_live:
+       caam_id = (u64)rd_reg32(&perfmon->caam_id_ms) << 32 |
+                 (u64)rd_reg32(&perfmon->caam_id_ls);
+@@ -908,6 +928,9 @@ static int caam_probe(struct platform_de
+                           ctrlpriv->ctl, &perfmon->status,
+                           &caam_fops_u32_ro);
++      if (ctrlpriv->scu_en)
++              goto probe_jrs;
++
+       /* Internal covering keys (useful in non-secure mode only) */
+       ctrlpriv->ctl_kek_wrap.data = (__force void *)&ctrlpriv->ctrl->kek[0];
+       ctrlpriv->ctl_kek_wrap.size = KEK_KEY_SIZE * sizeof(u32);
+@@ -925,6 +948,7 @@ static int caam_probe(struct platform_de
+                           &ctrlpriv->ctl_tdsk_wrap);
+ #endif
++probe_jrs:
+       ret = devm_of_platform_populate(dev);
+       if (ret)
+               dev_err(dev, "JR platform devices creation error\n");
+--- a/drivers/crypto/caam/intern.h
++++ b/drivers/crypto/caam/intern.h
+@@ -82,6 +82,7 @@ struct caam_drv_private {
+       u8 total_jobrs;         /* Total Job Rings in device */
+       u8 qi_present;          /* Nonzero if QI present in device */
+       u8 mc_en;               /* Nonzero if MC f/w is active */
++      u8 scu_en;              /* Nonzero if SCU f/w is active */
+       int secvio_irq;         /* Security violation interrupt number */
+       int virt_en;            /* Virtualization enabled in CAAM */
+       int era;                /* CAAM Era (internal HW revision) */
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0018-MLKU-114-3-crypto-caam-OP-TEE-firmware-support.patch b/target/linux/layerscape/patches-5.4/804-crypto-0018-MLKU-114-3-crypto-caam-OP-TEE-firmware-support.patch
new file mode 100644 (file)
index 0000000..7e71fdc
--- /dev/null
@@ -0,0 +1,117 @@
+From 8a0bf079f870379a1e392819ac1116d74500ec01 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Horia=20Geant=C4=83?= <horia.geanta@nxp.com>
+Date: Fri, 4 Oct 2019 15:07:41 +0300
+Subject: [PATCH] MLKU-114-3 crypto: caam - OP-TEE firmware support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+caam driver needs to be aware of OP-TEE f/w presence, since some things
+are done differently:
+
+1. there is no access to controller's register page (note however that
+some registers are aliased in job rings' register pages)
+
+It's worth mentioning that due to this, MCFGR[PS] cannot be read
+and driver assumes MCFGR[PS] = b'0 - engine using 32-bit address pointers.
+
+This is in sync with the fact that:
+-all i.MX SoCs currently use MCFGR[PS] = b'0
+-only i.MX OP-TEE use cases don't allow access to controller register page
+
+Note: When DN OP-TEE will start enforcing the same policy,
+this solution will stop working and information about caam configuration
+will have to deduced in some other way.
+
+2. as a consequence of "1.", part of the initialization is moved in
+other f/w (TF-A etc.), e.g. RNG initialization
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/ctrl.c   | 22 ++++++++++++++++++----
+ drivers/crypto/caam/intern.h |  1 +
+ 2 files changed, 19 insertions(+), 4 deletions(-)
+
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -583,6 +583,7 @@ static int caam_probe(struct platform_de
+       u8 rng_vid;
+       int pg_size;
+       int BLOCK_OFFSET = 0;
++      bool reg_access = true;
+       ctrlpriv = devm_kzalloc(&pdev->dev, sizeof(*ctrlpriv), GFP_KERNEL);
+       if (!ctrlpriv)
+@@ -600,6 +601,8 @@ static int caam_probe(struct platform_de
+               ctrlpriv->scu_en = !!np;
+               of_node_put(np);
++              reg_access = !ctrlpriv->scu_en;
++
+               /*
+                * CAAM clocks cannot be controlled from kernel.
+                * They are automatically turned on by SCU f/w.
+@@ -607,6 +610,17 @@ static int caam_probe(struct platform_de
+               if (ctrlpriv->scu_en)
+                       goto iomap_ctrl;
++              /*
++               * Until Layerscape and i.MX OP-TEE get in sync,
++               * only i.MX OP-TEE use cases disallow access to
++               * caam page 0 (controller) registers.
++               */
++              np = of_find_compatible_node(NULL, NULL, "linaro,optee-tz");
++              ctrlpriv->optee_en = !!np;
++              of_node_put(np);
++
++              reg_access = reg_access && !ctrlpriv->optee_en;
++
+               if (!imx_soc_match->data) {
+                       dev_err(dev, "No clock data provided for i.MX SoC");
+                       return -EINVAL;
+@@ -657,7 +671,7 @@ iomap_ctrl:
+       caam_little_end = !(bool)(rd_reg32(&perfmon->status) &
+                                 (CSTA_PLEND | CSTA_ALT_PLEND));
+       comp_params = rd_reg32(&perfmon->comp_parms_ms);
+-      if (!ctrlpriv->scu_en && comp_params & CTPR_MS_PS &&
++      if (reg_access && comp_params & CTPR_MS_PS &&
+           rd_reg32(&ctrl->mcr) & MCFGR_LONG_PTR)
+               caam_ptr_sz = sizeof(u64);
+       else
+@@ -708,7 +722,7 @@ iomap_ctrl:
+       /* Get the IRQ of the controller (for security violations only) */
+       ctrlpriv->secvio_irq = irq_of_parse_and_map(nprop, 0);
+-      if (ctrlpriv->scu_en)
++      if (!reg_access)
+               goto set_dma_mask;
+       /*
+@@ -801,7 +815,7 @@ set_dma_mask:
+               return -ENOMEM;
+       }
+-      if (ctrlpriv->scu_en)
++      if (!reg_access)
+               goto report_live;
+       if (ctrlpriv->era < 10) {
+@@ -928,7 +942,7 @@ report_live:
+                           ctrlpriv->ctl, &perfmon->status,
+                           &caam_fops_u32_ro);
+-      if (ctrlpriv->scu_en)
++      if (!reg_access)
+               goto probe_jrs;
+       /* Internal covering keys (useful in non-secure mode only) */
+--- a/drivers/crypto/caam/intern.h
++++ b/drivers/crypto/caam/intern.h
+@@ -83,6 +83,7 @@ struct caam_drv_private {
+       u8 qi_present;          /* Nonzero if QI present in device */
+       u8 mc_en;               /* Nonzero if MC f/w is active */
+       u8 scu_en;              /* Nonzero if SCU f/w is active */
+++     u8 optee_en;            /* Nonzero if OP-TEE f/w is active */
+       int secvio_irq;         /* Security violation interrupt number */
+       int virt_en;            /* Virtualization enabled in CAAM */
+       int era;                /* CAAM Era (internal HW revision) */
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0019-MLKU-38-3-crypto-caam-add-SNVS-SECVIO-support.patch b/target/linux/layerscape/patches-5.4/804-crypto-0019-MLKU-38-3-crypto-caam-add-SNVS-SECVIO-support.patch
new file mode 100644 (file)
index 0000000..4ad7a7e
--- /dev/null
@@ -0,0 +1,784 @@
+From 03ec635be0eb1c1b63b1f631938d41b379dad637 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Horia=20Geant=C4=83?= <horia.geanta@nxp.com>
+Date: Mon, 30 Sep 2019 00:22:09 +0300
+Subject: [PATCH] MLKU-38-3 crypto: caam - add SNVS / SECVIO support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This is a squash of the following i.MX BSP commits
+(rel_imx_4.19.35_1.1.0_rc2)
+
+1. 8f6a17b41917 ("ENGR00289885 [iMX6Q] Add Secure Memory and SECVIO support.")
+2. 8433c811e97a ("MLK-9710-18 snvs - make SECVIO module device tree correct")
+3. 35bbc34e996b ("MLK-9769-23 Replace SECVIO of_irq_to_resource() with irq_of_parse_and_map()")
+4. 3ac6edcd92d4 ("MLK-11360-01 crypto: caam_snvs: add snvs clock management")
+5. 9d9ca7a03e3b ("MLK-11922 i.mx6: Linux 3.14.28 CAAM & SNVS enabled by default. JTAG, DS-5 attachment causes exceptions")
+6. fcdaabf1bba2 ("MLK-17412-01: Fix secvio driver to have same driver name as DTS")
+
+Signed-off-by: Dan Douglass <dan.douglass@nxp.com>
+Signed-off-by: Victoria Milhoan <vicki.milhoan@freescale.com>
+Signed-off-by: Steve Cornelius <steve.cornelius@nxp.com>
+Signed-off-by: Fugang Duan <andy.duan@nxp.com>
+Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
+
+that have been reworked:
+
+1.
+-make SM depend on JR
+-enable SM, SECVIO only on i.MX SoCs
+-fix resource leak - add off_node_put() where needed
+
+Split commit in three:
+- SNVS/SECVIO driver
+- Secure Memory driver
+- DT changes
+
+3.
+JR changes dropped - no longer needed, already upstream in
+commit 549077d7d86a1 ("crypto: caam - check irq_of_parse_and_map for errors")
+
+4.
+Split the patch in two:
+-DT bindings changes
+-driver changes
+
+5.
+Fixed conflicts in imx7d.dtsi - added caam_sm and irq_sec_vio nodes.
+
+Split commit in 3:
+-SECVIO/SNVS driver changes
+-SECVIO/SNVS DT changes
+-Secure Memory DT changes
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/Kconfig    |   7 +
+ drivers/crypto/caam/Makefile   |   1 +
+ drivers/crypto/caam/ctrl.c     |   3 -
+ drivers/crypto/caam/intern.h   |   4 +-
+ drivers/crypto/caam/secvio.c   | 342 +++++++++++++++++++++++++++++++++++++++++
+ drivers/crypto/caam/secvio.h   |  69 +++++++++
+ drivers/crypto/caam/snvsregs.h | 239 ++++++++++++++++++++++++++++
+ 7 files changed, 660 insertions(+), 5 deletions(-)
+ create mode 100644 drivers/crypto/caam/secvio.c
+ create mode 100644 drivers/crypto/caam/secvio.h
+ create mode 100644 drivers/crypto/caam/snvsregs.h
+
+--- a/drivers/crypto/caam/Kconfig
++++ b/drivers/crypto/caam/Kconfig
+@@ -155,6 +155,13 @@ config CRYPTO_DEV_FSL_CAAM_RNG_TEST
+         caam RNG. This test is several minutes long and executes
+         just before the RNG is registered with the hw_random API.
++config CRYPTO_DEV_FSL_CAAM_SECVIO
++      tristate "CAAM/SNVS Security Violation Handler (EXPERIMENTAL)"
++      help
++        Enables installation of an interrupt handler with registrable
++          handler functions which can be specified to act on the consequences
++          of a security violation.
++
+ endif # CRYPTO_DEV_FSL_CAAM_JR
+ endif # CRYPTO_DEV_FSL_CAAM
+--- a/drivers/crypto/caam/Makefile
++++ b/drivers/crypto/caam/Makefile
+@@ -21,6 +21,7 @@ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRY
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caampkc.o pkc_desc.o
++caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO) += secvio.o
+ caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += qi.o
+ ifneq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI),)
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -719,9 +719,6 @@ iomap_ctrl:
+                        BLOCK_OFFSET * DECO_BLOCK_NUMBER
+                        );
+-      /* Get the IRQ of the controller (for security violations only) */
+-      ctrlpriv->secvio_irq = irq_of_parse_and_map(nprop, 0);
+-
+       if (!reg_access)
+               goto set_dma_mask;
+--- a/drivers/crypto/caam/intern.h
++++ b/drivers/crypto/caam/intern.h
+@@ -66,6 +66,7 @@ struct caam_drv_private_jr {
+  * Driver-private storage for a single CAAM block instance
+  */
+ struct caam_drv_private {
++
+       /* Physical-presence section */
+       struct caam_ctrl __iomem *ctrl; /* controller region */
+       struct caam_deco __iomem *deco; /* DECO/CCB views */
+@@ -83,8 +84,7 @@ struct caam_drv_private {
+       u8 qi_present;          /* Nonzero if QI present in device */
+       u8 mc_en;               /* Nonzero if MC f/w is active */
+       u8 scu_en;              /* Nonzero if SCU f/w is active */
+-+     u8 optee_en;            /* Nonzero if OP-TEE f/w is active */
+-      int secvio_irq;         /* Security violation interrupt number */
++      u8 optee_en;            /* Nonzero if OP-TEE f/w is active */
+       int virt_en;            /* Virtualization enabled in CAAM */
+       int era;                /* CAAM Era (internal HW revision) */
+--- /dev/null
++++ b/drivers/crypto/caam/secvio.c
+@@ -0,0 +1,342 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
++/*
++ * SNVS Security Violation Handler
++ *
++ * Copyright 2012-2016 Freescale Semiconductor, Inc.
++ * Copyright 2017-2019 NXP
++ */
++
++#include "compat.h"
++#include "secvio.h"
++#include "regs.h"
++#include "intern.h"
++#include <linux/of.h>
++#include <linux/of_irq.h>
++#include <linux/of_address.h>
++
++/* The driver is matched with node caam_snvs to get regmap
++ * It will then retrieve interruption and tamper alarm configuration from
++ * node caam-secvio searching for the compat string "fsl,imx6q-caam-secvio"
++ */
++#define DRIVER_NAME "caam-snvs"
++
++/*
++ * These names are associated with each violation handler.
++ * The source names were taken from MX6, and are based on recommendations
++ * for most common SoCs.
++ */
++static const u8 *violation_src_name[] = {
++      "CAAM Internal Security Violation",
++      "JTAG Alarm",
++      "Watchdog",
++      "(reserved)",
++      "External Boot",
++      "External Tamper Detect",
++};
++
++/* These names help describe security monitor state for the console */
++static const u8 *snvs_ssm_state_name[] = {
++      "init",
++      "hard fail",
++      "(undef:2)",
++      "soft fail",
++      "(undef:4)",
++      "(undef:5)",
++      "(undef:6)",
++      "(undef:7)",
++      "transition",
++      "check",
++      "(undef:10)",
++      "non-secure",
++      "(undef:12)",
++      "trusted",
++      "(undef:14)",
++      "secure",
++};
++
++/* Top-level security violation interrupt */
++static irqreturn_t snvs_secvio_interrupt(int irq, void *snvsdev)
++{
++      struct device *dev = snvsdev;
++      struct snvs_secvio_drv_private *svpriv = dev_get_drvdata(dev);
++
++      clk_enable(svpriv->clk);
++      /* Check the HP secvio status register */
++      svpriv->irqcause = rd_reg32(&svpriv->svregs->hp.secvio_status) &
++                                  HP_SECVIOST_SECVIOMASK;
++
++      if (!svpriv->irqcause) {
++              clk_disable(svpriv->clk);
++              return IRQ_NONE;
++      }
++
++      /* Now ACK cause */
++      clrsetbits_32(&svpriv->svregs->hp.secvio_status, 0, svpriv->irqcause);
++
++      /* And run deferred service */
++      preempt_disable();
++      tasklet_schedule(&svpriv->irqtask[smp_processor_id()]);
++      preempt_enable();
++
++      clk_disable(svpriv->clk);
++
++      return IRQ_HANDLED;
++}
++
++/* Deferred service handler. Tasklet arg is simply the SNVS dev */
++static void snvs_secvio_dispatch(unsigned long indev)
++{
++      struct device *dev = (struct device *)indev;
++      struct snvs_secvio_drv_private *svpriv = dev_get_drvdata(dev);
++      unsigned long flags;
++      int i;
++
++
++      /* Look through stored causes, call each handler if exists */
++      for (i = 0; i < MAX_SECVIO_SOURCES; i++)
++              if (svpriv->irqcause & (1 << i)) {
++                      spin_lock_irqsave(&svpriv->svlock, flags);
++                      svpriv->intsrc[i].handler(dev, i,
++                                                svpriv->intsrc[i].ext);
++                      spin_unlock_irqrestore(&svpriv->svlock, flags);
++              };
++
++      /* Re-enable now-serviced interrupts */
++      clrsetbits_32(&svpriv->svregs->hp.secvio_intcfg, 0, svpriv->irqcause);
++}
++
++/*
++ * Default cause handler, used in lieu of an application-defined handler.
++ * All it does at this time is print a console message. It could force a halt.
++ */
++static void snvs_secvio_default(struct device *dev, u32 cause, void *ext)
++{
++      struct snvs_secvio_drv_private *svpriv = dev_get_drvdata(dev);
++
++      dev_err(dev, "Unhandled Security Violation Interrupt %d = %s\n",
++              cause, svpriv->intsrc[cause].intname);
++}
++
++/*
++ * Install an application-defined handler for a specified cause
++ * Arguments:
++ * - dev        points to SNVS-owning device
++ * - cause      interrupt source cause
++ * - handler    application-defined handler, gets called with dev
++ *              source cause, and locally-defined handler argument
++ * - cause_description   points to a string to override the default cause
++ *                       name, this can be used as an alternate for error
++ *                       messages and such. If left NULL, the default
++ *                       description string is used.
++ * - ext        pointer to any extra data needed by the handler.
++ */
++int snvs_secvio_install_handler(struct device *dev, enum secvio_cause cause,
++                              void (*handler)(struct device *dev, u32 cause,
++                                              void *ext),
++                              u8 *cause_description, void *ext)
++{
++      unsigned long flags;
++      struct snvs_secvio_drv_private *svpriv;
++
++      svpriv = dev_get_drvdata(dev);
++
++      if ((handler == NULL) || (cause > SECVIO_CAUSE_SOURCE_5))
++              return -EINVAL;
++
++      spin_lock_irqsave(&svpriv->svlock, flags);
++      svpriv->intsrc[cause].handler = handler;
++      if (cause_description != NULL)
++              svpriv->intsrc[cause].intname = cause_description;
++      if (ext != NULL)
++              svpriv->intsrc[cause].ext = ext;
++      spin_unlock_irqrestore(&svpriv->svlock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL(snvs_secvio_install_handler);
++
++/*
++ * Remove an application-defined handler for a specified cause (and, by
++ * implication, restore the "default".
++ * Arguments:
++ * - dev      points to SNVS-owning device
++ * - cause    interrupt source cause
++ */
++int snvs_secvio_remove_handler(struct device *dev, enum secvio_cause cause)
++{
++      unsigned long flags;
++      struct snvs_secvio_drv_private *svpriv;
++
++      svpriv = dev_get_drvdata(dev);
++
++      if (cause > SECVIO_CAUSE_SOURCE_5)
++              return -EINVAL;
++
++      spin_lock_irqsave(&svpriv->svlock, flags);
++      svpriv->intsrc[cause].intname = violation_src_name[cause];
++      svpriv->intsrc[cause].handler = snvs_secvio_default;
++      svpriv->intsrc[cause].ext = NULL;
++      spin_unlock_irqrestore(&svpriv->svlock, flags);
++      return 0;
++}
++EXPORT_SYMBOL(snvs_secvio_remove_handler);
++
++static int snvs_secvio_remove(struct platform_device *pdev)
++{
++      struct device *svdev;
++      struct snvs_secvio_drv_private *svpriv;
++      int i;
++
++      svdev = &pdev->dev;
++      svpriv = dev_get_drvdata(svdev);
++
++      clk_enable(svpriv->clk);
++      /* Set all sources to nonfatal */
++      wr_reg32(&svpriv->svregs->hp.secvio_intcfg, 0);
++
++      /* Remove tasklets and release interrupt */
++      for_each_possible_cpu(i)
++              tasklet_kill(&svpriv->irqtask[i]);
++
++      clk_disable_unprepare(svpriv->clk);
++      free_irq(svpriv->irq, svdev);
++      iounmap(svpriv->svregs);
++      kfree(svpriv);
++
++      return 0;
++}
++
++static int snvs_secvio_probe(struct platform_device *pdev)
++{
++      struct device *svdev;
++      struct snvs_secvio_drv_private *svpriv;
++      struct device_node *np, *npirq;
++      struct snvs_full __iomem *snvsregs;
++      int i, error;
++      u32 hpstate;
++      const void *jtd, *wtd, *itd, *etd;
++      u32 td_en;
++
++      svpriv = kzalloc(sizeof(struct snvs_secvio_drv_private), GFP_KERNEL);
++      if (!svpriv)
++              return -ENOMEM;
++
++      svdev = &pdev->dev;
++      dev_set_drvdata(svdev, svpriv);
++      svpriv->pdev = pdev;
++      np = pdev->dev.of_node;
++
++      npirq = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-secvio");
++      if (!npirq) {
++              dev_err(svdev, "can't find secvio node\n");
++              kfree(svpriv);
++              return -EINVAL;
++      }
++      svpriv->irq = irq_of_parse_and_map(npirq, 0);
++      if (svpriv->irq <= 0) {
++              dev_err(svdev, "can't identify secvio interrupt\n");
++              kfree(svpriv);
++              return -EINVAL;
++      }
++
++      jtd = of_get_property(npirq, "jtag-tamper", NULL);
++      wtd = of_get_property(npirq, "watchdog-tamper", NULL);
++      itd = of_get_property(npirq, "internal-boot-tamper", NULL);
++      etd = of_get_property(npirq, "external-pin-tamper", NULL);
++      if (!jtd | !wtd | !itd | !etd ) {
++              dev_err(svdev, "can't identify all tamper alarm configuration\n");
++              kfree(svpriv);
++              return -EINVAL;
++      }
++
++      /*
++       * Configure all sources  according to device tree property.
++       * If the property is enabled then the source is ser as
++       * fatal violations except LP section,
++       * source #5 (typically used as an external tamper detect), and
++       * source #3 (typically unused). Whenever the transition to
++       * secure mode has occurred, these will now be "fatal" violations
++       */
++      td_en = HP_SECVIO_INTEN_SRC0;
++      if (!strcmp(jtd, "enabled"))
++              td_en |= HP_SECVIO_INTEN_SRC1;
++      if (!strcmp(wtd, "enabled"))
++              td_en |= HP_SECVIO_INTEN_SRC2;
++      if (!strcmp(itd, "enabled"))
++              td_en |= HP_SECVIO_INTEN_SRC4;
++      if (!strcmp(etd, "enabled"))
++              td_en |= HP_SECVIO_INTEN_SRC5;
++
++      snvsregs = of_iomap(np, 0);
++      if (!snvsregs) {
++              dev_err(svdev, "register mapping failed\n");
++              return -ENOMEM;
++      }
++      svpriv->svregs = (struct snvs_full __force *)snvsregs;
++
++      svpriv->clk = devm_clk_get(&pdev->dev, NULL);
++      if (IS_ERR(svpriv->clk)) {
++              dev_err(&pdev->dev, "can't get snvs clock\n");
++              svpriv->clk = NULL;
++      }
++
++      /* Write the Secvio Enable Config the SVCR */
++      wr_reg32(&svpriv->svregs->hp.secvio_ctl, td_en);
++      wr_reg32(&svpriv->svregs->hp.secvio_intcfg, td_en);
++
++       /* Device data set up. Now init interrupt source descriptions */
++      for (i = 0; i < MAX_SECVIO_SOURCES; i++) {
++              svpriv->intsrc[i].intname = violation_src_name[i];
++              svpriv->intsrc[i].handler = snvs_secvio_default;
++      }
++      /* Connect main handler */
++      for_each_possible_cpu(i)
++              tasklet_init(&svpriv->irqtask[i], snvs_secvio_dispatch,
++                           (unsigned long)svdev);
++
++      error = request_irq(svpriv->irq, snvs_secvio_interrupt,
++                          IRQF_SHARED, DRIVER_NAME, svdev);
++      if (error) {
++              dev_err(svdev, "can't connect secvio interrupt\n");
++              irq_dispose_mapping(svpriv->irq);
++              svpriv->irq = 0;
++              iounmap(svpriv->svregs);
++              kfree(svpriv);
++              return -EINVAL;
++      }
++
++      clk_prepare_enable(svpriv->clk);
++
++      hpstate = (rd_reg32(&svpriv->svregs->hp.status) &
++                          HP_STATUS_SSM_ST_MASK) >> HP_STATUS_SSM_ST_SHIFT;
++      dev_info(svdev, "violation handlers armed - %s state\n",
++               snvs_ssm_state_name[hpstate]);
++
++      clk_disable(svpriv->clk);
++
++      return 0;
++}
++
++static struct of_device_id snvs_secvio_match[] = {
++      {
++              .compatible = "fsl,imx6q-caam-snvs",
++      },
++      {},
++};
++MODULE_DEVICE_TABLE(of, snvs_secvio_match);
++
++static struct platform_driver snvs_secvio_driver = {
++      .driver = {
++              .name = DRIVER_NAME,
++              .owner = THIS_MODULE,
++              .of_match_table = snvs_secvio_match,
++      },
++      .probe       = snvs_secvio_probe,
++      .remove      = snvs_secvio_remove,
++};
++
++module_platform_driver(snvs_secvio_driver);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_DESCRIPTION("FSL SNVS Security Violation Handler");
++MODULE_AUTHOR("Freescale Semiconductor - MCU");
+--- /dev/null
++++ b/drivers/crypto/caam/secvio.h
+@@ -0,0 +1,69 @@
++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
++/*
++ * CAAM Security Violation Handler
++ *
++ * Copyright 2012-2015 Freescale Semiconductor, Inc.
++ * Copyright 2016-2019 NXP
++ */
++
++#ifndef SECVIO_H
++#define SECVIO_H
++
++#include "snvsregs.h"
++
++
++/*
++ * Defines the published interfaces to install/remove application-specified
++ * handlers for catching violations
++ */
++
++#define MAX_SECVIO_SOURCES 6
++
++/* these are the untranslated causes */
++enum secvio_cause {
++      SECVIO_CAUSE_SOURCE_0,
++      SECVIO_CAUSE_SOURCE_1,
++      SECVIO_CAUSE_SOURCE_2,
++      SECVIO_CAUSE_SOURCE_3,
++      SECVIO_CAUSE_SOURCE_4,
++      SECVIO_CAUSE_SOURCE_5
++};
++
++/* These are common "recommended" cause definitions for most devices */
++#define SECVIO_CAUSE_CAAM_VIOLATION   SECVIO_CAUSE_SOURCE_0
++#define SECVIO_CAUSE_JTAG_ALARM               SECVIO_CAUSE_SOURCE_1
++#define SECVIO_CAUSE_WATCHDOG         SECVIO_CAUSE_SOURCE_2
++#define SECVIO_CAUSE_EXTERNAL_BOOT    SECVIO_CAUSE_SOURCE_4
++#define SECVIO_CAUSE_TAMPER_DETECT    SECVIO_CAUSE_SOURCE_5
++
++int snvs_secvio_install_handler(struct device *dev, enum secvio_cause cause,
++                              void (*handler)(struct device *dev, u32 cause,
++                                              void *ext),
++                              u8 *cause_description, void *ext);
++int snvs_secvio_remove_handler(struct device *dev, enum  secvio_cause cause);
++
++/*
++ * Private data definitions for the secvio "driver"
++ */
++
++struct secvio_int_src {
++      const u8 *intname;      /* Points to a descriptive name for source */
++      void *ext;              /* Extended data to pass to the handler */
++      void (*handler)(struct device *dev, u32 cause, void *ext);
++};
++
++struct snvs_secvio_drv_private {
++      struct platform_device *pdev;
++      spinlock_t svlock ____cacheline_aligned;
++      struct tasklet_struct irqtask[NR_CPUS];
++      struct snvs_full __iomem *svregs;       /* both HP and LP domains */
++      struct clk *clk;
++      int irq;
++      u32 irqcause; /* stashed cause of violation interrupt */
++
++      /* Registered handlers for each violation */
++      struct secvio_int_src intsrc[MAX_SECVIO_SOURCES];
++
++};
++
++#endif /* SECVIO_H */
+--- /dev/null
++++ b/drivers/crypto/caam/snvsregs.h
+@@ -0,0 +1,239 @@
++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
++/*
++ * SNVS hardware register-level view
++ *
++ * Copyright 2012-2015 Freescale Semiconductor, Inc.
++ * Copyright 2016-2019 NXP
++ */
++
++#ifndef SNVSREGS_H
++#define SNVSREGS_H
++
++#include <linux/types.h>
++#include <linux/io.h>
++
++/*
++ * SNVS High Power Domain
++ * Includes security violations, HA counter, RTC, alarm
++ */
++struct snvs_hp {
++      u32 lock;               /* HPLR - HP Lock */
++      u32 cmd;                /* HPCOMR - HP Command */
++      u32 ctl;                /* HPCR - HP Control */
++      u32 secvio_intcfg;      /* HPSICR - Security Violation Int Config */
++      u32 secvio_ctl;         /* HPSVCR - Security Violation Control */
++      u32 status;             /* HPSR - HP Status */
++      u32 secvio_status;      /* HPSVSR - Security Violation Status */
++      u32 ha_counteriv;       /* High Assurance Counter IV */
++      u32 ha_counter;         /* High Assurance Counter */
++      u32 rtc_msb;            /* Real Time Clock/Counter MSB */
++      u32 rtc_lsb;            /* Real Time Counter LSB */
++      u32 time_alarm_msb;     /* Time Alarm MSB */
++      u32 time_alarm_lsb;     /* Time Alarm LSB */
++};
++
++#define HP_LOCK_HAC_LCK               0x00040000
++#define HP_LOCK_HPSICR_LCK    0x00020000
++#define HP_LOCK_HPSVCR_LCK    0x00010000
++#define HP_LOCK_MKEYSEL_LCK   0x00000200
++#define HP_LOCK_TAMPCFG_LCK   0x00000100
++#define HP_LOCK_TAMPFLT_LCK   0x00000080
++#define HP_LOCK_SECVIO_LCK    0x00000040
++#define HP_LOCK_GENP_LCK      0x00000020
++#define HP_LOCK_MONOCTR_LCK   0x00000010
++#define HP_LOCK_CALIB_LCK     0x00000008
++#define HP_LOCK_SRTC_LCK      0x00000004
++#define HP_LOCK_ZMK_RD_LCK    0x00000002
++#define HP_LOCK_ZMK_WT_LCK    0x00000001
++
++#define HP_CMD_NONPRIV_AXS    0x80000000
++#define HP_CMD_HAC_STOP               0x00080000
++#define HP_CMD_HAC_CLEAR      0x00040000
++#define HP_CMD_HAC_LOAD               0x00020000
++#define HP_CMD_HAC_CFG_EN     0x00010000
++#define HP_CMD_SNVS_MSTR_KEY  0x00002000
++#define HP_CMD_PROG_ZMK               0x00001000
++#define HP_CMD_SW_LPSV                0x00000400
++#define HP_CMD_SW_FSV         0x00000200
++#define HP_CMD_SW_SV          0x00000100
++#define HP_CMD_LP_SWR_DIS     0x00000020
++#define HP_CMD_LP_SWR         0x00000010
++#define HP_CMD_SSM_SFNS_DIS   0x00000004
++#define HP_CMD_SSM_ST_DIS     0x00000002
++#define HP_CMD_SMM_ST         0x00000001
++
++#define HP_CTL_TIME_SYNC      0x00010000
++#define HP_CTL_CAL_VAL_SHIFT  10
++#define HP_CTL_CAL_VAL_MASK   (0x1f << HP_CTL_CALIB_SHIFT)
++#define HP_CTL_CALIB_EN               0x00000100
++#define HP_CTL_PI_FREQ_SHIFT  4
++#define HP_CTL_PI_FREQ_MASK   (0xf << HP_CTL_PI_FREQ_SHIFT)
++#define HP_CTL_PI_EN          0x00000008
++#define HP_CTL_TIMEALARM_EN   0x00000002
++#define HP_CTL_RTC_EN         0x00000001
++
++#define HP_SECVIO_INTEN_EN    0x10000000
++#define HP_SECVIO_INTEN_SRC5  0x00000020
++#define HP_SECVIO_INTEN_SRC4  0x00000010
++#define HP_SECVIO_INTEN_SRC3  0x00000008
++#define HP_SECVIO_INTEN_SRC2  0x00000004
++#define HP_SECVIO_INTEN_SRC1  0x00000002
++#define HP_SECVIO_INTEN_SRC0  0x00000001
++#define HP_SECVIO_INTEN_ALL   0x8000003f
++
++#define HP_SECVIO_ICTL_CFG_SHIFT      30
++#define HP_SECVIO_ICTL_CFG_MASK               (0x3 << HP_SECVIO_ICTL_CFG_SHIFT)
++#define HP_SECVIO_ICTL_CFG5_SHIFT     5
++#define HP_SECVIO_ICTL_CFG5_MASK      (0x3 << HP_SECVIO_ICTL_CFG5_SHIFT)
++#define HP_SECVIO_ICTL_CFG_DISABLE    0
++#define HP_SECVIO_ICTL_CFG_NONFATAL   1
++#define HP_SECVIO_ICTL_CFG_FATAL      2
++#define HP_SECVIO_ICTL_CFG4_FATAL     0x00000010
++#define HP_SECVIO_ICTL_CFG3_FATAL     0x00000008
++#define HP_SECVIO_ICTL_CFG2_FATAL     0x00000004
++#define HP_SECVIO_ICTL_CFG1_FATAL     0x00000002
++#define HP_SECVIO_ICTL_CFG0_FATAL     0x00000001
++
++#define HP_STATUS_ZMK_ZERO            0x80000000
++#define HP_STATUS_OTPMK_ZERO          0x08000000
++#define HP_STATUS_OTPMK_SYN_SHIFT     16
++#define HP_STATUS_OTPMK_SYN_MASK      (0x1ff << HP_STATUS_OTPMK_SYN_SHIFT)
++#define HP_STATUS_SSM_ST_SHIFT                8
++#define HP_STATUS_SSM_ST_MASK         (0xf << HP_STATUS_SSM_ST_SHIFT)
++#define HP_STATUS_SSM_ST_INIT         0
++#define HP_STATUS_SSM_ST_HARDFAIL     1
++#define HP_STATUS_SSM_ST_SOFTFAIL     3
++#define HP_STATUS_SSM_ST_INITINT      8
++#define HP_STATUS_SSM_ST_CHECK                9
++#define HP_STATUS_SSM_ST_NONSECURE    11
++#define HP_STATUS_SSM_ST_TRUSTED      13
++#define HP_STATUS_SSM_ST_SECURE               15
++
++#define HP_SECVIOST_ZMK_ECC_FAIL      0x08000000      /* write to clear */
++#define HP_SECVIOST_ZMK_SYN_SHIFT     16
++#define HP_SECVIOST_ZMK_SYN_MASK      (0x1ff << HP_SECVIOST_ZMK_SYN_SHIFT)
++#define HP_SECVIOST_SECVIO5           0x00000020
++#define HP_SECVIOST_SECVIO4           0x00000010
++#define HP_SECVIOST_SECVIO3           0x00000008
++#define HP_SECVIOST_SECVIO2           0x00000004
++#define HP_SECVIOST_SECVIO1           0x00000002
++#define HP_SECVIOST_SECVIO0           0x00000001
++#define HP_SECVIOST_SECVIOMASK                0x0000003f
++
++/*
++ * SNVS Low Power Domain
++ * Includes glitch detector, SRTC, alarm, monotonic counter, ZMK
++ */
++struct snvs_lp {
++      u32 lock;
++      u32 ctl;
++      u32 mstr_key_ctl;       /* Master Key Control */
++      u32 secvio_ctl;         /* Security Violation Control */
++      u32 tamper_filt_cfg;    /* Tamper Glitch Filters Configuration */
++      u32 tamper_det_cfg;     /* Tamper Detectors Configuration */
++      u32 status;
++      u32 srtc_msb;           /* Secure Real Time Clock/Counter MSB */
++      u32 srtc_lsb;           /* Secure Real Time Clock/Counter LSB */
++      u32 time_alarm;         /* Time Alarm */
++      u32 smc_msb;            /* Secure Monotonic Counter MSB */
++      u32 smc_lsb;            /* Secure Monotonic Counter LSB */
++      u32 pwr_glitch_det;     /* Power Glitch Detector */
++      u32 gen_purpose;
++      u32 zmk[8];             /* Zeroizable Master Key */
++};
++
++#define LP_LOCK_MKEYSEL_LCK   0x00000200
++#define LP_LOCK_TAMPDET_LCK   0x00000100
++#define LP_LOCK_TAMPFLT_LCK   0x00000080
++#define LP_LOCK_SECVIO_LCK    0x00000040
++#define LP_LOCK_GENP_LCK      0x00000020
++#define LP_LOCK_MONOCTR_LCK   0x00000010
++#define LP_LOCK_CALIB_LCK     0x00000008
++#define LP_LOCK_SRTC_LCK      0x00000004
++#define LP_LOCK_ZMK_RD_LCK    0x00000002
++#define LP_LOCK_ZMK_WT_LCK    0x00000001
++
++#define LP_CTL_CAL_VAL_SHIFT  10
++#define LP_CTL_CAL_VAL_MASK   (0x1f << LP_CTL_CAL_VAL_SHIFT)
++#define LP_CTL_CALIB_EN               0x00000100
++#define LP_CTL_SRTC_INVAL_EN  0x00000010
++#define LP_CTL_WAKE_INT_EN    0x00000008
++#define LP_CTL_MONOCTR_EN     0x00000004
++#define LP_CTL_TIMEALARM_EN   0x00000002
++#define LP_CTL_SRTC_EN                0x00000001
++
++#define LP_MKEYCTL_ZMKECC_SHIFT       8
++#define LP_MKEYCTL_ZMKECC_MASK        (0xff << LP_MKEYCTL_ZMKECC_SHIFT)
++#define LP_MKEYCTL_ZMKECC_EN  0x00000010
++#define LP_MKEYCTL_ZMKECC_VAL 0x00000008
++#define LP_MKEYCTL_ZMKECC_PROG        0x00000004
++#define LP_MKEYCTL_MKSEL_SHIFT        0
++#define LP_MKEYCTL_MKSEL_MASK (3 << LP_MKEYCTL_MKSEL_SHIFT)
++#define LP_MKEYCTL_MK_OTP     0
++#define LP_MKEYCTL_MK_ZMK     2
++#define LP_MKEYCTL_MK_COMB    3
++
++#define LP_SECVIO_CTL_SRC5    0x20
++#define LP_SECVIO_CTL_SRC4    0x10
++#define LP_SECVIO_CTL_SRC3    0x08
++#define LP_SECVIO_CTL_SRC2    0x04
++#define LP_SECVIO_CTL_SRC1    0x02
++#define LP_SECVIO_CTL_SRC0    0x01
++
++#define LP_TAMPFILT_EXT2_EN   0x80000000
++#define LP_TAMPFILT_EXT2_SHIFT        24
++#define LP_TAMPFILT_EXT2_MASK (0x1f << LP_TAMPFILT_EXT2_SHIFT)
++#define LP_TAMPFILT_EXT1_EN   0x00800000
++#define LP_TAMPFILT_EXT1_SHIFT        16
++#define LP_TAMPFILT_EXT1_MASK (0x1f << LP_TAMPFILT_EXT1_SHIFT)
++#define LP_TAMPFILT_WM_EN     0x00000080
++#define LP_TAMPFILT_WM_SHIFT  0
++#define LP_TAMPFILT_WM_MASK   (0x1f << LP_TAMPFILT_WM_SHIFT)
++
++#define LP_TAMPDET_OSC_BPS    0x10000000
++#define LP_TAMPDET_VRC_SHIFT  24
++#define LP_TAMPDET_VRC_MASK   (3 << LP_TAMPFILT_VRC_SHIFT)
++#define LP_TAMPDET_HTDC_SHIFT 20
++#define LP_TAMPDET_HTDC_MASK  (3 << LP_TAMPFILT_HTDC_SHIFT)
++#define LP_TAMPDET_LTDC_SHIFT 16
++#define LP_TAMPDET_LTDC_MASK  (3 << LP_TAMPFILT_LTDC_SHIFT)
++#define LP_TAMPDET_POR_OBS    0x00008000
++#define LP_TAMPDET_PFD_OBS    0x00004000
++#define LP_TAMPDET_ET2_EN     0x00000400
++#define LP_TAMPDET_ET1_EN     0x00000200
++#define LP_TAMPDET_WMT2_EN    0x00000100
++#define LP_TAMPDET_WMT1_EN    0x00000080
++#define LP_TAMPDET_VT_EN      0x00000040
++#define LP_TAMPDET_TT_EN      0x00000020
++#define LP_TAMPDET_CT_EN      0x00000010
++#define LP_TAMPDET_MCR_EN     0x00000004
++#define LP_TAMPDET_SRTCR_EN   0x00000002
++
++#define LP_STATUS_SECURE
++#define LP_STATUS_NONSECURE
++#define LP_STATUS_SCANEXIT    0x00100000      /* all write 1 clear here on */
++#define LP_STATUS_EXT_SECVIO  0x00010000
++#define LP_STATUS_ET2         0x00000400
++#define LP_STATUS_ET1         0x00000200
++#define LP_STATUS_WMT2                0x00000100
++#define LP_STATUS_WMT1                0x00000080
++#define LP_STATUS_VTD         0x00000040
++#define LP_STATUS_TTD         0x00000020
++#define LP_STATUS_CTD         0x00000010
++#define LP_STATUS_PGD         0x00000008
++#define LP_STATUS_MCR         0x00000004
++#define LP_STATUS_SRTCR               0x00000002
++#define LP_STATUS_LPTA                0x00000001
++
++/* Full SNVS register page, including version/options */
++struct snvs_full {
++      struct snvs_hp hp;
++      struct snvs_lp lp;
++      u32 rsvd[731];          /* deadspace 0x08c-0xbf7 */
++
++      /* Version / Revision / Option ID space - end of register page */
++      u32 vid;                /* 0xbf8 HP Version ID (VID 1) */
++      u32 opt_rev;            /* 0xbfc HP Options / Revision (VID 2) */
++};
++
++#endif /* SNVSREGS_H */
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0020-MLKU-25-3-crypto-caam-add-Secure-Memory-support.patch b/target/linux/layerscape/patches-5.4/804-crypto-0020-MLKU-25-3-crypto-caam-add-Secure-Memory-support.patch
new file mode 100644 (file)
index 0000000..697f24b
--- /dev/null
@@ -0,0 +1,2503 @@
+From 32221046a302245a63d5e00d16cf3008b5b31255 Mon Sep 17 00:00:00 2001
+From: Steve Cornelius <steve.cornelius@freescale.com>
+Date: Tue, 23 Jul 2013 20:47:32 -0700
+Subject: [PATCH] MLKU-25-3 crypto: caam - add Secure Memory support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This is a squash of the following i.MX BSP commits
+(rel_imx_4.19.35_1.1.0_rc2)
+
+1.  ae8175a3f1be ("MLK-9710-10 Add CCM defs for FIFO_STORE instruction")
+2.  9512280d066b ("MLK-9769-11 Add SM register defs, and expanded driver-private storage.")
+3.  a9dc44de8150 ("MLK-9769-10 Add Blob command bitdefs.")
+4.  8f6a17b41917 ("ENGR00289885 [iMX6Q] Add Secure Memory and SECVIO support.")
+5.  c7d4f9db1077 ("MLK-9710-11 Add internal key cover and external blob export/import to prototype SM-API")
+6.  568e449edfca ("MLK-9710-12 Adapt sm_test as a black-key handling example")
+7.  f42f12d9cb19 ("MLK-9710-13 Correct size in BLOB_OVERHEAD definition")
+8.  022fc2b33f57 ("MLK-9710-14 Un-pad cache sizes for blob export/import")
+9.  8d3e8c3c4dc1 ("MLK-9710-15 Correct size of padded key buffers")
+10. 997fb2ff88ec ("MLK-9710-5 Unregister Secure Memory platform device upon shutdown")
+11. 5316249198ee ("MLK-10897-1 ARM: imx7d: Add CAAM support for i.mx7d")
+12. 07566f42a4ec ("MLK-11103 Missing register in Secure memory configuration v1")
+13. 3004636304e1 ("MLK-12302 caam: Secure Memory platform device creation crashes")
+14. 0e6ed5a819f7 ("MLK-13779 crypto: caam - initialize kslock spinlock")
+15. b1254b6b5f52 ("Add missing NULL checks in CAAM sm")
+16. 61f57509bc9a ("MLK-17992: caam: sm: Fix compilation warnings")
+17. 41cf3d4c580c ("MLK-15473-1: crypto: caam: Add CAAM driver support for iMX8 soc family")
+18. bb8742481209 ("MLK-17253-1: crypto: caam: Fix computation of SM pages addresses")
+19. 308796dfae3b ("MLK-17253-2: crypto: caam: Use correct memory function for Secure Memory")
+20. ba2cb6b5fb10 ("MLK-17732-2: SM store: Support iMX8QX and iMX8QM")
+21. de710d376af6 ("MLK-17674-1: sm_store remove CONFIG_OF")
+22. cfcae647434e ("MLK-17674-2: CAAM SM : get base address from device tree")
+23. f49ebbd5eefa ("MLK-17992: caam: sm: Fix compilation warnings")
+24. 345ead4338b9 ("MLK-17841: crypto: caam: Correct bugs in Secure Memory")
+25. c17811f3fffc ("MLK-18082: crypto: caam: sm: Fix encap/decap function to handle errors")
+26. 41bcba1d4c9b ("MLK-18082: crypto: caam: sm: Fix descriptor running functions")
+27. b7385ab94784 ("MLK-20204: drivers: crypto: caam: sm: Remove deadcode")
+28. 1d749430cb63 ("MLK-20204: drivers: crypto: caam: sm: test: Dealloc keyslot properly")
+29. 6a5c2d9d358f ("crypto: caam - lower SM test verbosity")
+30. 1a6bc92c0c87 ("MLK-21617: crypto: caam - update SM test error handling")
+
+Signed-off-by: Dan Douglass <dan.douglass@nxp.com>
+Signed-off-by: Victoria Milhoan <vicki.milhoan@freescale.com>
+Signed-off-by: Steve Cornelius <steve.cornelius@nxp.com>
+Signed-off-by: Octavian Purdila <octavian.purdila@nxp.com>
+Signed-off-by: Radu Solea <radu.solea@nxp.com>
+Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
+Signed-off-by: Aymen Sghaier <aymen.sghaier@nxp.com>
+Signed-off-by: Silvano di Ninno <silvano.dininno@nxp.com>
+
+that have been reworked:
+
+4.
+-make SM depend on JR
+-enable SM, SECVIO only on i.MX SoCs
+-fix resource leak - add off_node_put() where needed
+
+Split commit in three:
+1 - SNVS/SECVIO driver
+2 - Secure Memory driver
+3 - DT changes
+
+11.
+Clock handling dropped - logic already upstream.
+
+17.
+Keep only Secure Memory related changes.
+Changes related to page 0 registers have been added previously.
+Other changes are dropped.
+
+21.
+Always use first jr in ctrlpriv->jr[] array to access registers
+in page 0 (aliased in jr page), irrespective of SCU presence.
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/Kconfig    |   30 +
+ drivers/crypto/caam/Makefile   |    2 +
+ drivers/crypto/caam/ctrl.c     |   37 ++
+ drivers/crypto/caam/desc.h     |   21 +
+ drivers/crypto/caam/intern.h   |    4 +
+ drivers/crypto/caam/regs.h     |  158 ++++-
+ drivers/crypto/caam/sm.h       |  127 ++++
+ drivers/crypto/caam/sm_store.c | 1332 ++++++++++++++++++++++++++++++++++++++++
+ drivers/crypto/caam/sm_test.c  |  571 +++++++++++++++++
+ 9 files changed, 2279 insertions(+), 3 deletions(-)
+ create mode 100644 drivers/crypto/caam/sm.h
+ create mode 100644 drivers/crypto/caam/sm_store.c
+ create mode 100644 drivers/crypto/caam/sm_test.c
+
+--- a/drivers/crypto/caam/Kconfig
++++ b/drivers/crypto/caam/Kconfig
+@@ -155,6 +155,36 @@ config CRYPTO_DEV_FSL_CAAM_RNG_TEST
+         caam RNG. This test is several minutes long and executes
+         just before the RNG is registered with the hw_random API.
++config CRYPTO_DEV_FSL_CAAM_SM
++      tristate "CAAM Secure Memory / Keystore API (EXPERIMENTAL)"
++      help
++        Enables use of a prototype kernel-level Keystore API with CAAM
++        Secure Memory for insertion/extraction of bus-protected secrets.
++
++config CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE
++      int "Size of each keystore slot in Secure Memory"
++      depends on CRYPTO_DEV_FSL_CAAM_SM
++      range 5 9
++      default 7
++      help
++        Select size of allocation units to divide Secure Memory pages into
++        (the size of a "slot" as referenced inside the API code).
++        Established as powers of two.
++        Examples:
++              5 => 32 bytes
++              6 => 64 bytes
++              7 => 128 bytes
++              8 => 256 bytes
++              9 => 512 bytes
++
++config CRYPTO_DEV_FSL_CAAM_SM_TEST
++      tristate "CAAM Secure Memory - Keystore Test/Example (EXPERIMENTAL)"
++      depends on CRYPTO_DEV_FSL_CAAM_SM
++      help
++        Example thread to exercise the Keystore API and to verify that
++        stored and recovered secrets can be used for general purpose
++        encryption/decryption.
++
+ config CRYPTO_DEV_FSL_CAAM_SECVIO
+       tristate "CAAM/SNVS Security Violation Handler (EXPERIMENTAL)"
+       help
+--- a/drivers/crypto/caam/Makefile
++++ b/drivers/crypto/caam/Makefile
+@@ -21,6 +21,8 @@ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRY
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caampkc.o pkc_desc.o
++caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM) += sm_store.o
++caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST) += sm_test.o
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO) += secvio.o
+ caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += qi.o
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -17,6 +17,7 @@
+ #include "jr.h"
+ #include "desc_constr.h"
+ #include "ctrl.h"
++#include "sm.h"
+ bool caam_dpaa2;
+ EXPORT_SYMBOL(caam_dpaa2);
+@@ -573,6 +574,7 @@ static int caam_probe(struct platform_de
+       const struct soc_device_attribute *imx_soc_match;
+       struct device *dev;
+       struct device_node *nprop, *np;
++      struct resource res_regs;
+       struct caam_ctrl __iomem *ctrl;
+       struct caam_drv_private *ctrlpriv;
+       struct caam_perfmon __iomem *perfmon;
+@@ -719,9 +721,44 @@ iomap_ctrl:
+                        BLOCK_OFFSET * DECO_BLOCK_NUMBER
+                        );
++      /* Only i.MX SoCs have sm */
++      if (!imx_soc_match)
++              goto mc_fw;
++
++      /* Get CAAM-SM node and of_iomap() and save */
++      np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-sm");
++      if (!np)
++              return -ENODEV;
++
++      /* Get CAAM SM registers base address from device tree */
++      ret = of_address_to_resource(np, 0, &res_regs);
++      if (ret) {
++              dev_err(dev, "failed to retrieve registers base from device tree\n");
++              of_node_put(np);
++              return -ENODEV;
++      }
++
++      ctrlpriv->sm_phy = res_regs.start;
++      ctrlpriv->sm_base = devm_ioremap_resource(dev, &res_regs);
++      if (IS_ERR(ctrlpriv->sm_base)) {
++              of_node_put(np);
++              return PTR_ERR(ctrlpriv->sm_base);
++      }
++
++      if (!of_machine_is_compatible("fsl,imx8mn") &&
++          !of_machine_is_compatible("fsl,imx8mm") &&
++          !of_machine_is_compatible("fsl,imx8mq") &&
++          !of_machine_is_compatible("fsl,imx8qm") &&
++          !of_machine_is_compatible("fsl,imx8qxp"))
++              ctrlpriv->sm_size = resource_size(&res_regs);
++      else
++              ctrlpriv->sm_size = PG_SIZE_64K;
++      of_node_put(np);
++
+       if (!reg_access)
+               goto set_dma_mask;
++mc_fw:
+       /*
+        * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel,
+        * long pointers in master configuration register.
+--- a/drivers/crypto/caam/desc.h
++++ b/drivers/crypto/caam/desc.h
+@@ -403,6 +403,10 @@
+ #define FIFOST_TYPE_PKHA_N     (0x08 << FIFOST_TYPE_SHIFT)
+ #define FIFOST_TYPE_PKHA_A     (0x0c << FIFOST_TYPE_SHIFT)
+ #define FIFOST_TYPE_PKHA_B     (0x0d << FIFOST_TYPE_SHIFT)
++#define FIFOST_TYPE_AF_SBOX_CCM_JKEK  (0x10 << FIFOST_TYPE_SHIFT)
++#define FIFOST_TYPE_AF_SBOX_CCM_TKEK  (0x11 << FIFOST_TYPE_SHIFT)
++#define FIFOST_TYPE_KEY_CCM_JKEK      (0x14 << FIFOST_TYPE_SHIFT)
++#define FIFOST_TYPE_KEY_CCM_TKEK      (0x15 << FIFOST_TYPE_SHIFT)
+ #define FIFOST_TYPE_AF_SBOX_JKEK (0x20 << FIFOST_TYPE_SHIFT)
+ #define FIFOST_TYPE_AF_SBOX_TKEK (0x21 << FIFOST_TYPE_SHIFT)
+ #define FIFOST_TYPE_PKHA_E_JKEK        (0x22 << FIFOST_TYPE_SHIFT)
+@@ -1136,6 +1140,23 @@
+ #define OP_PCL_PKPROT_ECC                      0x0002
+ #define OP_PCL_PKPROT_F2M                      0x0001
++/* Blob protocol protinfo bits */
++#define OP_PCL_BLOB_TK                        0x0200
++#define OP_PCL_BLOB_EKT                       0x0100
++
++#define OP_PCL_BLOB_K2KR_MEM          0x0000
++#define OP_PCL_BLOB_K2KR_C1KR         0x0010
++#define OP_PCL_BLOB_K2KR_C2KR         0x0030
++#define OP_PCL_BLOB_K2KR_AFHAS                0x0050
++#define OP_PCL_BLOB_K2KR_C2KR_SPLIT   0x0070
++
++#define OP_PCL_BLOB_PTXT_SECMEM               0x0008
++#define OP_PCL_BLOB_BLACK             0x0004
++
++#define OP_PCL_BLOB_FMT_NORMAL                0x0000
++#define OP_PCL_BLOB_FMT_MSTR          0x0002
++#define OP_PCL_BLOB_FMT_TEST          0x0003
++
+ /* For non-protocol/alg-only op commands */
+ #define OP_ALG_TYPE_SHIFT     24
+ #define OP_ALG_TYPE_MASK      (0x7 << OP_ALG_TYPE_SHIFT)
+--- a/drivers/crypto/caam/intern.h
++++ b/drivers/crypto/caam/intern.h
+@@ -66,6 +66,7 @@ struct caam_drv_private_jr {
+  * Driver-private storage for a single CAAM block instance
+  */
+ struct caam_drv_private {
++      struct device *smdev;
+       /* Physical-presence section */
+       struct caam_ctrl __iomem *ctrl; /* controller region */
+@@ -73,6 +74,9 @@ struct caam_drv_private {
+       struct caam_assurance __iomem *assure;
+       struct caam_queue_if __iomem *qi; /* QI control region */
+       struct caam_job_ring __iomem *jr[4];    /* JobR's register space */
++      dma_addr_t __iomem *sm_base;    /* Secure memory storage base */
++      phys_addr_t sm_phy;             /* Secure memory storage physical */
++      u32 sm_size;
+       struct iommu_domain *domain;
+--- a/drivers/crypto/caam/regs.h
++++ b/drivers/crypto/caam/regs.h
+@@ -382,6 +382,12 @@ struct version_regs {
+ #define CHA_VER_VID_MD_LP512  0x1ull
+ #define CHA_VER_VID_MD_HP     0x2ull
++/*
++ * caam_perfmon - Performance Monitor/Secure Memory Status/
++ *                CAAM Global Status/Component Version IDs
++ *
++ * Spans f00-fff wherever instantiated
++ */
+ struct sec_vid {
+       u16 ip_id;
+       u8 maj_rev;
+@@ -412,17 +418,22 @@ struct caam_perfmon {
+ #define CTPR_MS_PG_SZ_SHIFT   4
+       u32 comp_parms_ms;      /* CTPR - Compile Parameters Register   */
+       u32 comp_parms_ls;      /* CTPR - Compile Parameters Register   */
+-      u64 rsvd1[2];
++      /* Secure Memory State Visibility */
++      u32 rsvd1;
++      u32 smstatus;   /* Secure memory status */
++      u32 rsvd2;
++      u32 smpartown;  /* Secure memory partition owner */
+       /* CAAM Global Status                                   fc0-fdf */
+       u64 faultaddr;  /* FAR  - Fault Address         */
+       u32 faultliodn; /* FALR - Fault Address LIODN   */
+       u32 faultdetail;        /* FADR - Fault Addr Detail     */
+-      u32 rsvd2;
+ #define CSTA_PLEND            BIT(10)
+ #define CSTA_ALT_PLEND                BIT(18)
++      u32 rsvd3;
+       u32 status;             /* CSTA - CAAM Status */
+-      u64 rsvd3;
++      u32 smpart;             /* Secure Memory Partition Parameters */
++      u32 smvid;              /* Secure Memory Version ID */
+       /* Component Instantiation Parameters                   fe0-fff */
+       u32 rtic_id;            /* RVID - RTIC Version ID       */
+@@ -441,6 +452,62 @@ struct caam_perfmon {
+       u32 caam_id_ls;         /* CAAMVID - CAAM Version ID LS */
+ };
++#define SMSTATUS_PART_SHIFT   28
++#define SMSTATUS_PART_MASK    (0xf << SMSTATUS_PART_SHIFT)
++#define SMSTATUS_PAGE_SHIFT   16
++#define SMSTATUS_PAGE_MASK    (0x7ff << SMSTATUS_PAGE_SHIFT)
++#define SMSTATUS_MID_SHIFT    8
++#define SMSTATUS_MID_MASK     (0x3f << SMSTATUS_MID_SHIFT)
++#define SMSTATUS_ACCERR_SHIFT 4
++#define SMSTATUS_ACCERR_MASK  (0xf << SMSTATUS_ACCERR_SHIFT)
++#define SMSTATUS_ACCERR_NONE  0
++#define SMSTATUS_ACCERR_ALLOC 1       /* Page not allocated */
++#define SMSTATUS_ACCESS_ID    2       /* Not granted by ID */
++#define SMSTATUS_ACCESS_WRITE 3       /* Writes not allowed */
++#define SMSTATUS_ACCESS_READ  4       /* Reads not allowed */
++#define SMSTATUS_ACCESS_NONKEY        6       /* Non-key reads not allowed */
++#define SMSTATUS_ACCESS_BLOB  9       /* Blob access not allowed */
++#define SMSTATUS_ACCESS_DESCB 10      /* Descriptor Blob access spans pages */
++#define SMSTATUS_ACCESS_NON_SM        11      /* Outside Secure Memory range */
++#define SMSTATUS_ACCESS_XPAGE 12      /* Access crosses pages */
++#define SMSTATUS_ACCESS_INITPG        13      /* Page still initializing */
++#define SMSTATUS_STATE_SHIFT  0
++#define SMSTATUS_STATE_MASK   (0xf << SMSTATUS_STATE_SHIFT)
++#define SMSTATUS_STATE_RESET  0
++#define SMSTATUS_STATE_INIT   1
++#define SMSTATUS_STATE_NORMAL 2
++#define SMSTATUS_STATE_FAIL   3
++
++/* up to 15 rings, 2 bits shifted by ring number */
++#define SMPARTOWN_RING_SHIFT  2
++#define SMPARTOWN_RING_MASK   3
++#define SMPARTOWN_AVAILABLE   0
++#define SMPARTOWN_NOEXIST     1
++#define SMPARTOWN_UNAVAILABLE 2
++#define SMPARTOWN_OURS                3
++
++/* Maximum number of pages possible */
++#define SMPART_MAX_NUMPG_SHIFT        16
++#define SMPART_MAX_NUMPG_MASK (0x3f << SMPART_MAX_NUMPG_SHIFT)
++
++/* Maximum partition number */
++#define SMPART_MAX_PNUM_SHIFT 12
++#define SMPART_MAX_PNUM_MASK  (0xf << SMPART_MAX_PNUM_SHIFT)
++
++/* Highest possible page number */
++#define SMPART_MAX_PG_SHIFT   0
++#define SMPART_MAX_PG_MASK    (0x3f << SMPART_MAX_PG_SHIFT)
++
++/* Max size of a page */
++#define SMVID_PG_SIZE_SHIFT   16
++#define SMVID_PG_SIZE_MASK    (0x7 << SMVID_PG_SIZE_SHIFT)
++
++/* Major/Minor Version ID */
++#define SMVID_MAJ_VERS_SHIFT  8
++#define SMVID_MAJ_VERS                (0xf << SMVID_MAJ_VERS_SHIFT)
++#define SMVID_MIN_VERS_SHIFT  0
++#define SMVID_MIN_VERS                (0xf << SMVID_MIN_VERS_SHIFT)
++
+ /* LIODN programming for DMA configuration */
+ #define MSTRID_LOCK_LIODN     0x80000000
+ #define MSTRID_LOCK_MAKETRUSTED       0x00010000      /* only for JR masterid */
+@@ -645,6 +712,35 @@ struct caam_ctrl {
+ #define JRSTART_JR2_START       0x00000004 /* Start Job ring 2 */
+ #define JRSTART_JR3_START       0x00000008 /* Start Job ring 3 */
++/* Secure Memory Configuration - if you have it */
++/* Secure Memory Register Offset from JR Base Reg*/
++#define SM_V1_OFFSET 0x0f4
++#define SM_V2_OFFSET 0xa00
++
++/* Minimum SM Version ID requiring v2 SM register mapping */
++#define SMVID_V2 0x20105
++
++struct caam_secure_mem_v1 {
++      u32 sm_cmd;     /* SMCJRx - Secure memory command */
++      u32 rsvd1;
++      u32 sm_status;  /* SMCSJRx - Secure memory status */
++      u32 rsvd2;
++
++      u32 sm_perm;    /* SMAPJRx - Secure memory access perms */
++      u32 sm_group2;  /* SMAP2JRx - Secure memory access group 2 */
++      u32 sm_group1;  /* SMAP1JRx - Secure memory access group 1 */
++};
++
++struct caam_secure_mem_v2 {
++      u32 sm_perm;    /* SMAPJRx - Secure memory access perms */
++      u32 sm_group2;  /* SMAP2JRx - Secure memory access group 2 */
++      u32 sm_group1;  /* SMAP1JRx - Secure memory access group 1 */
++      u32 rsvd1[118];
++      u32 sm_cmd;     /* SMCJRx - Secure memory command */
++      u32 rsvd2;
++      u32 sm_status;  /* SMCSJRx - Secure memory status */
++};
++
+ /*
+  * caam_job_ring - direct job ring setup
+  * 1-4 possible per instantiation, base + 1000/2000/3000/4000
+@@ -815,6 +911,62 @@ struct caam_job_ring {
+ #define JRCR_RESET                  0x01
++/* secure memory command */
++#define SMC_PAGE_SHIFT        16
++#define SMC_PAGE_MASK (0xffff << SMC_PAGE_SHIFT)
++#define SMC_PART_SHIFT        8
++#define SMC_PART_MASK (0x0f << SMC_PART_SHIFT)
++#define SMC_CMD_SHIFT 0
++#define SMC_CMD_MASK  (0x0f << SMC_CMD_SHIFT)
++
++#define SMC_CMD_ALLOC_PAGE    0x01    /* allocate page to this partition */
++#define SMC_CMD_DEALLOC_PAGE  0x02    /* deallocate page from partition */
++#define SMC_CMD_DEALLOC_PART  0x03    /* deallocate partition */
++#define SMC_CMD_PAGE_INQUIRY  0x05    /* find partition associate with page */
++
++/* secure memory (command) status */
++#define SMCS_PAGE_SHIFT               16
++#define SMCS_PAGE_MASK                (0x0fff << SMCS_PAGE_SHIFT)
++#define SMCS_CMDERR_SHIFT     14
++#define SMCS_CMDERR_MASK      (3 << SMCS_CMDERR_SHIFT)
++#define SMCS_ALCERR_SHIFT     12
++#define SMCS_ALCERR_MASK      (3 << SMCS_ALCERR_SHIFT)
++#define SMCS_PGOWN_SHIFT      6
++#define SMCS_PGWON_MASK               (3 << SMCS_PGOWN_SHIFT)
++#define SMCS_PART_SHIFT               0
++#define SMCS_PART_MASK                (0xf << SMCS_PART_SHIFT)
++
++#define SMCS_CMDERR_NONE      0
++#define SMCS_CMDERR_INCOMP    1       /* Command not yet complete */
++#define SMCS_CMDERR_SECFAIL   2       /* Security failure occurred */
++#define SMCS_CMDERR_OVERFLOW  3       /* Command overflow */
++
++#define SMCS_ALCERR_NONE      0
++#define SMCS_ALCERR_PSPERR    1       /* Partion marked PSP (dealloc only) */
++#define SMCS_ALCERR_PAGEAVAIL 2       /* Page not available */
++#define SMCS_ALCERR_PARTOWN   3       /* Partition ownership error */
++
++#define SMCS_PGOWN_AVAIL      0       /* Page is available */
++#define SMCS_PGOWN_NOEXIST    1       /* Page initializing or nonexistent */
++#define SMCS_PGOWN_NOOWN      2       /* Page owned by another processor */
++#define SMCS_PGOWN_OWNED      3       /* Page belongs to this processor */
++
++/* secure memory access permissions */
++#define SMCS_PERM_KEYMOD_SHIFT        16
++#define SMCA_PERM_KEYMOD_MASK (0xff << SMCS_PERM_KEYMOD_SHIFT)
++#define SMCA_PERM_CSP_ZERO    0x8000  /* Zero when deallocated or released */
++#define SMCA_PERM_PSP_LOCK    0x4000  /* Part./pages can't be deallocated */
++#define SMCA_PERM_PERM_LOCK   0x2000  /* Lock permissions */
++#define SMCA_PERM_GRP_LOCK    0x1000  /* Lock access groups */
++#define SMCA_PERM_RINGID_SHIFT        10
++#define SMCA_PERM_RINGID_MASK (3 << SMCA_PERM_RINGID_SHIFT)
++#define SMCA_PERM_G2_BLOB     0x0080  /* Group 2 blob import/export */
++#define SMCA_PERM_G2_WRITE    0x0020  /* Group 2 write */
++#define SMCA_PERM_G2_READ     0x0010  /* Group 2 read */
++#define SMCA_PERM_G1_BLOB     0x0008  /* Group 1... */
++#define SMCA_PERM_G1_WRITE    0x0002
++#define SMCA_PERM_G1_READ     0x0001
++
+ /*
+  * caam_assurance - Assurance Controller View
+  * base + 0x6000 padded out to 0x1000
+--- /dev/null
++++ b/drivers/crypto/caam/sm.h
+@@ -0,0 +1,127 @@
++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
++/*
++ * CAAM Secure Memory/Keywrap API Definitions
++ *
++ * Copyright 2008-2015 Freescale Semiconductor, Inc.
++ * Copyright 2016-2019 NXP
++ */
++
++#ifndef SM_H
++#define SM_H
++
++
++/* Storage access permissions */
++#define SM_PERM_READ 0x01
++#define SM_PERM_WRITE 0x02
++#define SM_PERM_BLOB 0x03
++
++/* Define treatment of secure memory vs. general memory blobs */
++#define SM_SECMEM 0
++#define SM_GENMEM 1
++
++/* Define treatment of red/black keys */
++#define RED_KEY 0
++#define BLACK_KEY 1
++
++/* Define key encryption/covering options */
++#define KEY_COVER_ECB 0       /* cover key in AES-ECB */
++#define KEY_COVER_CCM 1 /* cover key with AES-CCM */
++
++/*
++ * Round a key size up to an AES blocksize boundary so to allow for
++ * padding out to a full block
++ */
++#define AES_BLOCK_PAD(x) ((x % 16) ? ((x >> 4) + 1) << 4 : x)
++
++/* Define space required for BKEK + MAC tag storage in any blob */
++#define BLOB_OVERHEAD (32 + 16)
++
++/* Keystore maintenance functions */
++void sm_init_keystore(struct device *dev);
++u32 sm_detect_keystore_units(struct device *dev);
++int sm_establish_keystore(struct device *dev, u32 unit);
++void sm_release_keystore(struct device *dev, u32 unit);
++void caam_sm_shutdown(struct platform_device *pdev);
++int caam_sm_example_init(struct platform_device *pdev);
++
++/* Keystore accessor functions */
++extern int sm_keystore_slot_alloc(struct device *dev, u32 unit, u32 size,
++                                u32 *slot);
++extern int sm_keystore_slot_dealloc(struct device *dev, u32 unit, u32 slot);
++extern int sm_keystore_slot_load(struct device *dev, u32 unit, u32 slot,
++                               const u8 *key_data, u32 key_length);
++extern int sm_keystore_slot_read(struct device *dev, u32 unit, u32 slot,
++                               u32 key_length, u8 *key_data);
++extern int sm_keystore_cover_key(struct device *dev, u32 unit, u32 slot,
++                               u16 key_length, u8 keyauth);
++extern int sm_keystore_slot_export(struct device *dev, u32 unit, u32 slot,
++                                 u8 keycolor, u8 keyauth, u8 *outbuf,
++                                 u16 keylen, u8 *keymod);
++extern int sm_keystore_slot_import(struct device *dev, u32 unit, u32 slot,
++                                 u8 keycolor, u8 keyauth, u8 *inbuf,
++                                 u16 keylen, u8 *keymod);
++
++/* Prior functions from legacy API, deprecated */
++extern int sm_keystore_slot_encapsulate(struct device *dev, u32 unit,
++                                      u32 inslot, u32 outslot, u16 secretlen,
++                                      u8 *keymod, u16 keymodlen);
++extern int sm_keystore_slot_decapsulate(struct device *dev, u32 unit,
++                                      u32 inslot, u32 outslot, u16 secretlen,
++                                      u8 *keymod, u16 keymodlen);
++
++/* Data structure to hold per-slot information */
++struct keystore_data_slot_info {
++      u8      allocated;      /* Track slot assignments */
++      u32     key_length;     /* Size of the key */
++};
++
++/* Data structure to hold keystore information */
++struct keystore_data {
++      void    *base_address;  /* Virtual base of secure memory pages */
++      void    *phys_address;  /* Physical base of secure memory pages */
++      u32     slot_count;     /* Number of slots in the keystore */
++      struct keystore_data_slot_info *slot; /* Per-slot information */
++};
++
++/* store the detected attributes of a secure memory page */
++struct sm_page_descriptor {
++      u16 phys_pagenum;       /* may be discontiguous */
++      u16 own_part;           /* Owning partition */
++      void *pg_base;          /* Calculated virtual address */
++      void *pg_phys;          /* Calculated physical address */
++      struct keystore_data *ksdata;
++};
++
++struct caam_drv_private_sm {
++      struct device *parentdev;       /* this ends up as the controller */
++      struct device *smringdev;       /* ring that owns this instance */
++      struct platform_device *sm_pdev;  /* Secure Memory platform device */
++      spinlock_t kslock ____cacheline_aligned;
++
++      /* SM Register offset from JR base address */
++      u32 sm_reg_offset;
++
++      /* Default parameters for geometry */
++      u32 max_pages;          /* maximum pages this instance can support */
++      u32 top_partition;      /* highest partition number in this instance */
++      u32 top_page;           /* highest page number in this instance */
++      u32 page_size;          /* page size */
++      u32 slot_size;          /* selected size of each storage block */
++
++      /* Partition/Page Allocation Map */
++      u32 localpages;         /* Number of pages we can access */
++      struct sm_page_descriptor *pagedesc;    /* Allocated per-page */
++
++      /* Installed handlers for keystore access */
++      int (*data_init)(struct device *dev, u32 unit);
++      void (*data_cleanup)(struct device *dev, u32 unit);
++      int (*slot_alloc)(struct device *dev, u32 unit, u32 size, u32 *slot);
++      int (*slot_dealloc)(struct device *dev, u32 unit, u32 slot);
++      void *(*slot_get_address)(struct device *dev, u32 unit, u32 handle);
++      void *(*slot_get_physical)(struct device *dev, u32 unit, u32 handle);
++      u32 (*slot_get_base)(struct device *dev, u32 unit, u32 handle);
++      u32 (*slot_get_offset)(struct device *dev, u32 unit, u32 handle);
++      u32 (*slot_get_slot_size)(struct device *dev, u32 unit, u32 handle);
++};
++
++#endif /* SM_H */
+--- /dev/null
++++ b/drivers/crypto/caam/sm_store.c
+@@ -0,0 +1,1332 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
++/*
++ * CAAM Secure Memory Storage Interface
++ *
++ * Copyright 2008-2015 Freescale Semiconductor, Inc.
++ * Copyright 2016-2019 NXP
++ *
++ * Loosely based on the SHW Keystore API for SCC/SCC2
++ * Experimental implementation and NOT intended for upstream use. Expect
++ * this interface to be amended significantly in the future once it becomes
++ * integrated into live applications.
++ *
++ * Known issues:
++ *
++ * - Executes one instance of an secure memory "driver". This is tied to the
++ *   fact that job rings can't run as standalone instances in the present
++ *   configuration.
++ *
++ * - It does not expose a userspace interface. The value of a userspace
++ *   interface for access to secrets is a point for further architectural
++ *   discussion.
++ *
++ * - Partition/permission management is not part of this interface. It
++ *   depends on some level of "knowledge" agreed upon between bootloader,
++ *   provisioning applications, and OS-hosted software (which uses this
++ *   driver).
++ *
++ * - No means of identifying the location or purpose of secrets managed by
++ *   this interface exists; "slot location" and format of a given secret
++ *   needs to be agreed upon between bootloader, provisioner, and OS-hosted
++ *   application.
++ */
++
++#include "compat.h"
++#include "regs.h"
++#include "jr.h"
++#include "desc.h"
++#include "intern.h"
++#include "error.h"
++#include "sm.h"
++#include <linux/of_address.h>
++
++#define SECMEM_KEYMOD_LEN 8
++#define GENMEM_KEYMOD_LEN 16
++
++#ifdef SM_DEBUG_CONT
++void sm_show_page(struct device *dev, struct sm_page_descriptor *pgdesc)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      u32 i, *smdata;
++
++      dev_info(dev, "physical page %d content at 0x%08x\n",
++               pgdesc->phys_pagenum, pgdesc->pg_base);
++      smdata = pgdesc->pg_base;
++      for (i = 0; i < (smpriv->page_size / sizeof(u32)); i += 4)
++              dev_info(dev, "[0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
++                       (u32)&smdata[i], smdata[i], smdata[i+1], smdata[i+2],
++                       smdata[i+3]);
++}
++#endif
++
++#define INITIAL_DESCSZ 16     /* size of tmp buffer for descriptor const. */
++
++static __always_inline u32 sm_send_cmd(struct caam_drv_private_sm *smpriv,
++                                           struct caam_drv_private_jr *jrpriv,
++                                           u32 cmd, u32 *status)
++{
++      void __iomem *write_address;
++      void __iomem *read_address;
++
++      if (smpriv->sm_reg_offset == SM_V1_OFFSET) {
++              struct caam_secure_mem_v1 *sm_regs_v1;
++
++              sm_regs_v1 = (struct caam_secure_mem_v1 *)
++                      ((void *)jrpriv->rregs + SM_V1_OFFSET);
++              write_address = &sm_regs_v1->sm_cmd;
++              read_address = &sm_regs_v1->sm_status;
++
++      } else if (smpriv->sm_reg_offset == SM_V2_OFFSET) {
++              struct caam_secure_mem_v2 *sm_regs_v2;
++
++              sm_regs_v2 = (struct caam_secure_mem_v2 *)
++                      ((void *)jrpriv->rregs + SM_V2_OFFSET);
++              write_address = &sm_regs_v2->sm_cmd;
++              read_address = &sm_regs_v2->sm_status;
++
++      } else {
++              return -EINVAL;
++      }
++
++      wr_reg32(write_address, cmd);
++
++      udelay(10);
++
++      /* Read until the command has terminated and the status is correct */
++      do {
++              *status = rd_reg32(read_address);
++      } while (((*status & SMCS_CMDERR_MASK) >>  SMCS_CMDERR_SHIFT)
++                                 == SMCS_CMDERR_INCOMP);
++
++      return 0;
++}
++
++/*
++ * Construct a black key conversion job descriptor
++ *
++ * This function constructs a job descriptor capable of performing
++ * a key blackening operation on a plaintext secure memory resident object.
++ *
++ * - desc     pointer to a pointer to the descriptor generated by this
++ *            function. Caller will be responsible to kfree() this
++ *            descriptor after execution.
++ * - key      physical pointer to the plaintext, which will also hold
++ *            the result. Since encryption occurs in place, caller must
++ *              ensure that the space is large enough to accommodate the
++ *              blackened key
++ * - keysz    size of the plaintext
++ * - auth     if a CCM-covered key is required, use KEY_COVER_CCM, else
++ *            use KEY_COVER_ECB.
++ *
++ * KEY to key1 from @key_addr LENGTH 16 BYTES;
++ * FIFO STORE from key1[ecb] TO @key_addr LENGTH 16 BYTES;
++ *
++ * Note that this variant uses the JDKEK only; it does not accommodate the
++ * trusted key encryption key at this time.
++ *
++ */
++static int blacken_key_jobdesc(u32 **desc, void *key, u16 keysz, bool auth)
++{
++      u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
++      u16 dsize, idx;
++
++      memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32));
++      idx = 1;
++
++      /* Load key to class 1 key register */
++      tmpdesc[idx++] = CMD_KEY | CLASS_1 | (keysz & KEY_LENGTH_MASK);
++      tmpdesc[idx++] = (uintptr_t)key;
++
++      /* ...and write back out via FIFO store*/
++      tmpdesc[idx] = CMD_FIFO_STORE | CLASS_1 | (keysz & KEY_LENGTH_MASK);
++
++      /* plus account for ECB/CCM option in FIFO_STORE */
++      if (auth == KEY_COVER_ECB)
++              tmpdesc[idx] |= FIFOST_TYPE_KEY_KEK;
++      else
++              tmpdesc[idx] |= FIFOST_TYPE_KEY_CCM_JKEK;
++
++      idx++;
++      tmpdesc[idx++] = (uintptr_t)key;
++
++      /* finish off the job header */
++      tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
++      dsize = idx * sizeof(u32);
++
++      /* now allocate execution buffer and coat it with executable */
++      tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA);
++      if (tdesc == NULL)
++              return 0;
++
++      memcpy(tdesc, tmpdesc, dsize);
++      *desc = tdesc;
++
++      return dsize;
++}
++
++/*
++ * Construct a blob encapsulation job descriptor
++ *
++ * This function dynamically constructs a blob encapsulation job descriptor
++ * from the following arguments:
++ *
++ * - desc     pointer to a pointer to the descriptor generated by this
++ *            function. Caller will be responsible to kfree() this
++ *            descriptor after execution.
++ * - keymod   Physical pointer to a key modifier, which must reside in a
++ *            contiguous piece of memory. Modifier will be assumed to be
++ *            8 bytes long for a blob of type SM_SECMEM, or 16 bytes long
++ *            for a blob of type SM_GENMEM (see blobtype argument).
++ * - secretbuf        Physical pointer to a secret, normally a black or red key,
++ *            possibly residing within an accessible secure memory page,
++ *            of the secret to be encapsulated to an output blob.
++ * - outbuf   Physical pointer to the destination buffer to receive the
++ *            encapsulated output. This buffer will need to be 48 bytes
++ *            larger than the input because of the added encapsulation data.
++ *            The generated descriptor will account for the increase in size,
++ *            but the caller must also account for this increase in the
++ *            buffer allocator.
++ * - secretsz Size of input secret, in bytes. This is limited to 65536
++ *            less the size of blob overhead, since the length embeds into
++ *            DECO pointer in/out instructions.
++ * - keycolor   Determines if the source data is covered (black key) or
++ *            plaintext (red key). RED_KEY or BLACK_KEY are defined in
++ *            for this purpose.
++ * - blobtype Determine if encapsulated blob should be a secure memory
++ *            blob (SM_SECMEM), with partition data embedded with key
++ *            material, or a general memory blob (SM_GENMEM).
++ * - auth     If BLACK_KEY source is covered via AES-CCM, specify
++ *            KEY_COVER_CCM, else uses AES-ECB (KEY_COVER_ECB).
++ *
++ * Upon completion, desc points to a buffer containing a CAAM job
++ * descriptor which encapsulates data into an externally-storable blob
++ * suitable for use across power cycles.
++ *
++ * This is an example of a black key encapsulation job into a general memory
++ * blob. Notice the 16-byte key modifier in the LOAD instruction. Also note
++ * the output 48 bytes longer than the input:
++ *
++ * [00] B0800008       jobhdr: stidx=0 len=8
++ * [01] 14400010           ld: ccb2-key len=16 offs=0
++ * [02] 08144891               ptr->@0x08144891
++ * [03] F800003A    seqoutptr: len=58
++ * [04] 01000000               out_ptr->@0x01000000
++ * [05] F000000A     seqinptr: len=10
++ * [06] 09745090               in_ptr->@0x09745090
++ * [07] 870D0004    operation: encap blob  reg=memory, black, format=normal
++ *
++ * This is an example of a red key encapsulation job for storing a red key
++ * into a secure memory blob. Note the 8 byte modifier on the 12 byte offset
++ * in the LOAD instruction; this accounts for blob permission storage:
++ *
++ * [00] B0800008       jobhdr: stidx=0 len=8
++ * [01] 14400C08           ld: ccb2-key len=8 offs=12
++ * [02] 087D0784               ptr->@0x087d0784
++ * [03] F8000050    seqoutptr: len=80
++ * [04] 09251BB2               out_ptr->@0x09251bb2
++ * [05] F0000020     seqinptr: len=32
++ * [06] 40000F31               in_ptr->@0x40000f31
++ * [07] 870D0008    operation: encap blob  reg=memory, red, sec_mem,
++ *                             format=normal
++ *
++ * Note: this function only generates 32-bit pointers at present, and should
++ * be refactored using a scheme that allows both 32 and 64 bit addressing
++ */
++
++static int blob_encap_jobdesc(u32 **desc, dma_addr_t keymod,
++                            void *secretbuf, dma_addr_t outbuf,
++                            u16 secretsz, u8 keycolor, u8 blobtype, u8 auth)
++{
++      u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
++      u16 dsize, idx;
++
++      memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32));
++      idx = 1;
++
++      /*
++       * Key modifier works differently for secure/general memory blobs
++       * This accounts for the permission/protection data encapsulated
++       * within the blob if a secure memory blob is requested
++       */
++      if (blobtype == SM_SECMEM)
++              tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
++                               LDST_SRCDST_BYTE_KEY |
++                               ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK)
++                               | (8 & LDST_LEN_MASK);
++      else /* is general memory blob */
++              tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
++                               LDST_SRCDST_BYTE_KEY | (16 & LDST_LEN_MASK);
++
++      tmpdesc[idx++] = (u32)keymod;
++
++      /*
++       * Encapsulation output must include space for blob key encryption
++       * key and MAC tag
++       */
++      tmpdesc[idx++] = CMD_SEQ_OUT_PTR | (secretsz + BLOB_OVERHEAD);
++      tmpdesc[idx++] = (u32)outbuf;
++
++      /* Input data, should be somewhere in secure memory */
++      tmpdesc[idx++] = CMD_SEQ_IN_PTR | secretsz;
++      tmpdesc[idx++] = (uintptr_t)secretbuf;
++
++      /* Set blob encap, then color */
++      tmpdesc[idx] = CMD_OPERATION | OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB;
++
++      if (blobtype == SM_SECMEM)
++              tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM;
++
++      if (auth == KEY_COVER_CCM)
++              tmpdesc[idx] |= OP_PCL_BLOB_EKT;
++
++      if (keycolor == BLACK_KEY)
++              tmpdesc[idx] |= OP_PCL_BLOB_BLACK;
++
++      idx++;
++      tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
++      dsize = idx * sizeof(u32);
++
++      tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA);
++      if (tdesc == NULL)
++              return 0;
++
++      memcpy(tdesc, tmpdesc, dsize);
++      *desc = tdesc;
++      return dsize;
++}
++
++/*
++ * Construct a blob decapsulation job descriptor
++ *
++ * This function dynamically constructs a blob decapsulation job descriptor
++ * from the following arguments:
++ *
++ * - desc     pointer to a pointer to the descriptor generated by this
++ *            function. Caller will be responsible to kfree() this
++ *            descriptor after execution.
++ * - keymod   Physical pointer to a key modifier, which must reside in a
++ *            contiguous piece of memory. Modifier will be assumed to be
++ *            8 bytes long for a blob of type SM_SECMEM, or 16 bytes long
++ *            for a blob of type SM_GENMEM (see blobtype argument).
++ * - blobbuf  Physical pointer (into external memory) of the blob to
++ *            be decapsulated. Blob must reside in a contiguous memory
++ *            segment.
++ * - outbuf   Physical pointer of the decapsulated output, possibly into
++ *            a location within a secure memory page. Must be contiguous.
++ * - secretsz Size of encapsulated secret in bytes (not the size of the
++ *            input blob).
++ * - keycolor   Determines if decapsulated content is encrypted (BLACK_KEY)
++ *            or left as plaintext (RED_KEY).
++ * - blobtype Determine if encapsulated blob should be a secure memory
++ *            blob (SM_SECMEM), with partition data embedded with key
++ *            material, or a general memory blob (SM_GENMEM).
++ * - auth     If decapsulation path is specified by BLACK_KEY, then if
++ *            AES-CCM is requested for key covering use KEY_COVER_CCM, else
++ *            use AES-ECB (KEY_COVER_ECB).
++ *
++ * Upon completion, desc points to a buffer containing a CAAM job descriptor
++ * that decapsulates a key blob from external memory into a black (encrypted)
++ * key or red (plaintext) content.
++ *
++ * This is an example of a black key decapsulation job from a general memory
++ * blob. Notice the 16-byte key modifier in the LOAD instruction.
++ *
++ * [00] B0800008       jobhdr: stidx=0 len=8
++ * [01] 14400010           ld: ccb2-key len=16 offs=0
++ * [02] 08A63B7F               ptr->@0x08a63b7f
++ * [03] F8000010    seqoutptr: len=16
++ * [04] 01000000               out_ptr->@0x01000000
++ * [05] F000003A     seqinptr: len=58
++ * [06] 01000010               in_ptr->@0x01000010
++ * [07] 860D0004    operation: decap blob  reg=memory, black, format=normal
++ *
++ * This is an example of a red key decapsulation job for restoring a red key
++ * from a secure memory blob. Note the 8 byte modifier on the 12 byte offset
++ * in the LOAD instruction:
++ *
++ * [00] B0800008       jobhdr: stidx=0 len=8
++ * [01] 14400C08           ld: ccb2-key len=8 offs=12
++ * [02] 01000000               ptr->@0x01000000
++ * [03] F8000020    seqoutptr: len=32
++ * [04] 400000E6               out_ptr->@0x400000e6
++ * [05] F0000050     seqinptr: len=80
++ * [06] 08F0C0EA               in_ptr->@0x08f0c0ea
++ * [07] 860D0008    operation: decap blob  reg=memory, red, sec_mem,
++ *                           format=normal
++ *
++ * Note: this function only generates 32-bit pointers at present, and should
++ * be refactored using a scheme that allows both 32 and 64 bit addressing
++ */
++
++static int blob_decap_jobdesc(u32 **desc, dma_addr_t keymod, dma_addr_t blobbuf,
++                            u8 *outbuf, u16 secretsz, u8 keycolor,
++                            u8 blobtype, u8 auth)
++{
++      u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
++      u16 dsize, idx;
++
++      memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32));
++      idx = 1;
++
++      /* Load key modifier */
++      if (blobtype == SM_SECMEM)
++              tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
++                               LDST_SRCDST_BYTE_KEY |
++                               ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK)
++                               | (8 & LDST_LEN_MASK);
++      else /* is general memory blob */
++              tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
++                               LDST_SRCDST_BYTE_KEY | (16 & LDST_LEN_MASK);
++
++      tmpdesc[idx++] = (u32)keymod;
++
++      /* Compensate BKEK + MAC tag over size of encapsulated secret */
++      tmpdesc[idx++] = CMD_SEQ_IN_PTR | (secretsz + BLOB_OVERHEAD);
++      tmpdesc[idx++] = (u32)blobbuf;
++      tmpdesc[idx++] = CMD_SEQ_OUT_PTR | secretsz;
++      tmpdesc[idx++] = (uintptr_t)outbuf;
++
++      /* Decapsulate from secure memory partition to black blob */
++      tmpdesc[idx] = CMD_OPERATION | OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB;
++
++      if (blobtype == SM_SECMEM)
++              tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM;
++
++      if (auth == KEY_COVER_CCM)
++              tmpdesc[idx] |= OP_PCL_BLOB_EKT;
++
++      if (keycolor == BLACK_KEY)
++              tmpdesc[idx] |= OP_PCL_BLOB_BLACK;
++
++      idx++;
++      tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
++      dsize = idx * sizeof(u32);
++
++      tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA);
++      if (tdesc == NULL)
++              return 0;
++
++      memcpy(tdesc, tmpdesc, dsize);
++      *desc = tdesc;
++      return dsize;
++}
++
++/*
++ * Pseudo-synchronous ring access functions for carrying out key
++ * encapsulation and decapsulation
++ */
++
++struct sm_key_job_result {
++      int error;
++      struct completion completion;
++};
++
++void sm_key_job_done(struct device *dev, u32 *desc, u32 err, void *context)
++{
++      struct sm_key_job_result *res = context;
++
++      if (err)
++              caam_jr_strstatus(dev, err);
++
++      res->error = err;       /* save off the error for postprocessing */
++
++      complete(&res->completion);     /* mark us complete */
++}
++
++static int sm_key_job(struct device *ksdev, u32 *jobdesc)
++{
++      struct sm_key_job_result testres = {0};
++      struct caam_drv_private_sm *kspriv;
++      int rtn = 0;
++
++      kspriv = dev_get_drvdata(ksdev);
++
++      init_completion(&testres.completion);
++
++      rtn = caam_jr_enqueue(kspriv->smringdev, jobdesc, sm_key_job_done,
++                            &testres);
++      if (rtn)
++              goto exit;
++
++      wait_for_completion_interruptible(&testres.completion);
++      rtn = testres.error;
++
++exit:
++      return rtn;
++}
++
++/*
++ * Following section establishes the default methods for keystore access
++ * They are NOT intended for use external to this module
++ *
++ * In the present version, these are the only means for the higher-level
++ * interface to deal with the mechanics of accessing the phyiscal keystore
++ */
++
++
++int slot_alloc(struct device *dev, u32 unit, u32 size, u32 *slot)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
++      u32 i;
++#ifdef SM_DEBUG
++      dev_info(dev, "slot_alloc(): requesting slot for %d bytes\n", size);
++#endif
++
++      if (size > smpriv->slot_size)
++              return -EKEYREJECTED;
++
++      for (i = 0; i < ksdata->slot_count; i++) {
++              if (ksdata->slot[i].allocated == 0) {
++                      ksdata->slot[i].allocated = 1;
++                      (*slot) = i;
++#ifdef SM_DEBUG
++                      dev_info(dev, "slot_alloc(): new slot %d allocated\n",
++                               *slot);
++#endif
++                      return 0;
++              }
++      }
++
++      return -ENOSPC;
++}
++EXPORT_SYMBOL(slot_alloc);
++
++int slot_dealloc(struct device *dev, u32 unit, u32 slot)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
++      u8 __iomem *slotdata;
++
++#ifdef SM_DEBUG
++      dev_info(dev, "slot_dealloc(): releasing slot %d\n", slot);
++#endif
++      if (slot >= ksdata->slot_count)
++              return -EINVAL;
++      slotdata = ksdata->base_address + slot * smpriv->slot_size;
++
++      if (ksdata->slot[slot].allocated == 1) {
++              /* Forcibly overwrite the data from the keystore */
++              memset_io(ksdata->base_address + slot * smpriv->slot_size, 0,
++                     smpriv->slot_size);
++
++              ksdata->slot[slot].allocated = 0;
++#ifdef SM_DEBUG
++              dev_info(dev, "slot_dealloc(): slot %d released\n", slot);
++#endif
++              return 0;
++      }
++
++      return -EINVAL;
++}
++EXPORT_SYMBOL(slot_dealloc);
++
++void *slot_get_address(struct device *dev, u32 unit, u32 slot)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
++
++      if (slot >= ksdata->slot_count)
++              return NULL;
++
++#ifdef SM_DEBUG
++      dev_info(dev, "slot_get_address(): slot %d is 0x%08x\n", slot,
++               (u32)ksdata->base_address + slot * smpriv->slot_size);
++#endif
++
++      return ksdata->base_address + slot * smpriv->slot_size;
++}
++
++void *slot_get_physical(struct device *dev, u32 unit, u32 slot)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
++
++      if (slot >= ksdata->slot_count)
++              return NULL;
++
++#ifdef SM_DEBUG
++      dev_info(dev, "%s: slot %d is 0x%08x\n", __func__, slot,
++               (u32)ksdata->phys_address + slot * smpriv->slot_size);
++#endif
++
++      return ksdata->phys_address + slot * smpriv->slot_size;
++}
++
++u32 slot_get_base(struct device *dev, u32 unit, u32 slot)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
++
++      /*
++       * There could potentially be more than one secure partition object
++       * associated with this keystore.  For now, there is just one.
++       */
++
++      (void)slot;
++
++#ifdef SM_DEBUG
++      dev_info(dev, "slot_get_base(): slot %d = 0x%08x\n",
++              slot, (u32)ksdata->base_address);
++#endif
++
++      return (uintptr_t)(ksdata->base_address);
++}
++
++u32 slot_get_offset(struct device *dev, u32 unit, u32 slot)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
++
++      if (slot >= ksdata->slot_count)
++              return -EINVAL;
++
++#ifdef SM_DEBUG
++      dev_info(dev, "slot_get_offset(): slot %d = %d\n", slot,
++              slot * smpriv->slot_size);
++#endif
++
++      return slot * smpriv->slot_size;
++}
++
++u32 slot_get_slot_size(struct device *dev, u32 unit, u32 slot)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++
++
++#ifdef SM_DEBUG
++      dev_info(dev, "slot_get_slot_size(): slot %d = %d\n", slot,
++               smpriv->slot_size);
++#endif
++      /* All slots are the same size in the default implementation */
++      return smpriv->slot_size;
++}
++
++
++
++int kso_init_data(struct device *dev, u32 unit)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      struct keystore_data *keystore_data = NULL;
++      u32 slot_count;
++      u32 keystore_data_size;
++
++      /*
++       * Calculate the required size of the keystore data structure, based
++       * on the number of keys that can fit in the partition.
++       */
++      slot_count = smpriv->page_size / smpriv->slot_size;
++#ifdef SM_DEBUG
++      dev_info(dev, "kso_init_data: %d slots initializing\n", slot_count);
++#endif
++
++      keystore_data_size = sizeof(struct keystore_data) +
++                              slot_count *
++                              sizeof(struct keystore_data_slot_info);
++
++      keystore_data = kzalloc(keystore_data_size, GFP_KERNEL);
++
++      if (!keystore_data)
++              return -ENOMEM;
++
++#ifdef SM_DEBUG
++      dev_info(dev, "kso_init_data: keystore data size = %d\n",
++               keystore_data_size);
++#endif
++
++      /*
++       * Place the slot information structure directly after the keystore data
++       * structure.
++       */
++      keystore_data->slot = (struct keystore_data_slot_info *)
++                            (keystore_data + 1);
++      keystore_data->slot_count = slot_count;
++
++      smpriv->pagedesc[unit].ksdata = keystore_data;
++      smpriv->pagedesc[unit].ksdata->base_address =
++              smpriv->pagedesc[unit].pg_base;
++      smpriv->pagedesc[unit].ksdata->phys_address =
++              smpriv->pagedesc[unit].pg_phys;
++
++      return 0;
++}
++
++void kso_cleanup_data(struct device *dev, u32 unit)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      struct keystore_data *keystore_data = NULL;
++
++      if (smpriv->pagedesc[unit].ksdata != NULL)
++              keystore_data = smpriv->pagedesc[unit].ksdata;
++
++      /* Release the allocated keystore management data */
++      kfree(smpriv->pagedesc[unit].ksdata);
++
++      return;
++}
++
++
++
++/*
++ * Keystore management section
++ */
++
++void sm_init_keystore(struct device *dev)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++
++      smpriv->data_init = kso_init_data;
++      smpriv->data_cleanup = kso_cleanup_data;
++      smpriv->slot_alloc = slot_alloc;
++      smpriv->slot_dealloc = slot_dealloc;
++      smpriv->slot_get_address = slot_get_address;
++      smpriv->slot_get_physical = slot_get_physical;
++      smpriv->slot_get_base = slot_get_base;
++      smpriv->slot_get_offset = slot_get_offset;
++      smpriv->slot_get_slot_size = slot_get_slot_size;
++#ifdef SM_DEBUG
++      dev_info(dev, "sm_init_keystore(): handlers installed\n");
++#endif
++}
++EXPORT_SYMBOL(sm_init_keystore);
++
++/* Return available pages/units */
++u32 sm_detect_keystore_units(struct device *dev)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++
++      return smpriv->localpages;
++}
++EXPORT_SYMBOL(sm_detect_keystore_units);
++
++/*
++ * Do any keystore specific initializations
++ */
++int sm_establish_keystore(struct device *dev, u32 unit)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++
++#ifdef SM_DEBUG
++      dev_info(dev, "sm_establish_keystore(): unit %d initializing\n", unit);
++#endif
++
++      if (smpriv->data_init == NULL)
++              return -EINVAL;
++
++      /* Call the data_init function for any user setup */
++      return smpriv->data_init(dev, unit);
++}
++EXPORT_SYMBOL(sm_establish_keystore);
++
++void sm_release_keystore(struct device *dev, u32 unit)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++
++#ifdef SM_DEBUG
++      dev_info(dev, "sm_establish_keystore(): unit %d releasing\n", unit);
++#endif
++      if ((smpriv != NULL) && (smpriv->data_cleanup != NULL))
++              smpriv->data_cleanup(dev, unit);
++
++      return;
++}
++EXPORT_SYMBOL(sm_release_keystore);
++
++/*
++ * Subsequent interfacce (sm_keystore_*) forms the accessor interfacce to
++ * the keystore
++ */
++int sm_keystore_slot_alloc(struct device *dev, u32 unit, u32 size, u32 *slot)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      int retval = -EINVAL;
++
++      spin_lock(&smpriv->kslock);
++
++      if ((smpriv->slot_alloc == NULL) ||
++          (smpriv->pagedesc[unit].ksdata == NULL))
++              goto out;
++
++      retval =  smpriv->slot_alloc(dev, unit, size, slot);
++
++out:
++      spin_unlock(&smpriv->kslock);
++      return retval;
++}
++EXPORT_SYMBOL(sm_keystore_slot_alloc);
++
++int sm_keystore_slot_dealloc(struct device *dev, u32 unit, u32 slot)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      int retval = -EINVAL;
++
++      spin_lock(&smpriv->kslock);
++
++      if ((smpriv->slot_alloc == NULL) ||
++          (smpriv->pagedesc[unit].ksdata == NULL))
++              goto out;
++
++      retval = smpriv->slot_dealloc(dev, unit, slot);
++out:
++      spin_unlock(&smpriv->kslock);
++      return retval;
++}
++EXPORT_SYMBOL(sm_keystore_slot_dealloc);
++
++int sm_keystore_slot_load(struct device *dev, u32 unit, u32 slot,
++                        const u8 *key_data, u32 key_length)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      int retval = -EINVAL;
++      u32 slot_size;
++      u8 __iomem *slot_location;
++
++      spin_lock(&smpriv->kslock);
++
++      slot_size = smpriv->slot_get_slot_size(dev, unit, slot);
++
++      if (key_length > slot_size) {
++              retval = -EFBIG;
++              goto out;
++      }
++
++      slot_location = smpriv->slot_get_address(dev, unit, slot);
++
++      memcpy_toio(slot_location, key_data, key_length);
++
++      retval = 0;
++
++out:
++      spin_unlock(&smpriv->kslock);
++      return retval;
++}
++EXPORT_SYMBOL(sm_keystore_slot_load);
++
++int sm_keystore_slot_read(struct device *dev, u32 unit, u32 slot,
++                        u32 key_length, u8 *key_data)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      int retval = -EINVAL;
++      u8 __iomem *slot_addr;
++      u32 slot_size;
++
++      spin_lock(&smpriv->kslock);
++
++      slot_addr = smpriv->slot_get_address(dev, unit, slot);
++      slot_size = smpriv->slot_get_slot_size(dev, unit, slot);
++
++      if (key_length > slot_size) {
++              retval = -EKEYREJECTED;
++              goto out;
++      }
++
++      memcpy_fromio(key_data, slot_addr, key_length);
++      retval = 0;
++
++out:
++      spin_unlock(&smpriv->kslock);
++      return retval;
++}
++EXPORT_SYMBOL(sm_keystore_slot_read);
++
++/*
++ * Blacken a clear key in a slot. Operates "in place".
++ * Limited to class 1 keys at the present time
++ */
++int sm_keystore_cover_key(struct device *dev, u32 unit, u32 slot,
++                        u16 key_length, u8 keyauth)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      int retval = 0;
++      u8 __iomem *slotaddr;
++      void *slotphys;
++      u32 dsize, jstat;
++      u32 __iomem *coverdesc = NULL;
++
++      /* Get the address of the object in the slot */
++      slotaddr = (u8 *)smpriv->slot_get_address(dev, unit, slot);
++      slotphys = (u8 *)smpriv->slot_get_physical(dev, unit, slot);
++
++      dsize = blacken_key_jobdesc(&coverdesc, slotphys, key_length, keyauth);
++      if (!dsize)
++              return -ENOMEM;
++      jstat = sm_key_job(dev, coverdesc);
++      if (jstat)
++              retval = -EIO;
++
++      kfree(coverdesc);
++      return retval;
++}
++EXPORT_SYMBOL(sm_keystore_cover_key);
++
++/* Export a black/red key to a blob in external memory */
++int sm_keystore_slot_export(struct device *dev, u32 unit, u32 slot, u8 keycolor,
++                          u8 keyauth, u8 *outbuf, u16 keylen, u8 *keymod)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      int retval = 0;
++      u8 __iomem *slotaddr, *lkeymod;
++      u8 __iomem *slotphys;
++      dma_addr_t keymod_dma, outbuf_dma;
++      u32 dsize, jstat;
++      u32 __iomem *encapdesc = NULL;
++      struct device *dev_for_dma_op;
++
++      /* Use the ring as device for DMA operations */
++      dev_for_dma_op = smpriv->smringdev;
++
++      /* Get the base address(es) of the specified slot */
++      slotaddr = (u8 *)smpriv->slot_get_address(dev, unit, slot);
++      slotphys = smpriv->slot_get_physical(dev, unit, slot);
++
++      /* Allocate memory for key modifier compatible with DMA */
++      lkeymod = kmalloc(SECMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA);
++      if (!lkeymod) {
++              retval = (-ENOMEM);
++              goto exit;
++      }
++
++      /* Get DMA address for the key modifier */
++      keymod_dma = dma_map_single(dev_for_dma_op, lkeymod,
++                                      SECMEM_KEYMOD_LEN, DMA_TO_DEVICE);
++      if (dma_mapping_error(dev_for_dma_op, keymod_dma)) {
++              dev_err(dev, "unable to map keymod: %p\n", lkeymod);
++              retval = (-ENOMEM);
++              goto free_keymod;
++      }
++
++      /* Copy the keymod and synchronize the DMA */
++      memcpy(lkeymod, keymod, SECMEM_KEYMOD_LEN);
++      dma_sync_single_for_device(dev_for_dma_op, keymod_dma,
++                                      SECMEM_KEYMOD_LEN, DMA_TO_DEVICE);
++
++      /* Get DMA address for the destination */
++      outbuf_dma = dma_map_single(dev_for_dma_op, outbuf,
++                              keylen + BLOB_OVERHEAD, DMA_FROM_DEVICE);
++      if (dma_mapping_error(dev_for_dma_op, outbuf_dma)) {
++              dev_err(dev, "unable to map outbuf: %p\n", outbuf);
++              retval = (-ENOMEM);
++              goto unmap_keymod;
++      }
++
++      /* Build the encapsulation job descriptor */
++      dsize = blob_encap_jobdesc(&encapdesc, keymod_dma, slotphys, outbuf_dma,
++                                 keylen, keycolor, SM_SECMEM, keyauth);
++      if (!dsize) {
++              dev_err(dev, "can't alloc an encapsulation descriptor\n");
++              retval = -ENOMEM;
++              goto unmap_outbuf;
++      }
++
++      /* Run the job */
++      jstat = sm_key_job(dev, encapdesc);
++      if (jstat) {
++              retval = (-EIO);
++              goto free_desc;
++      }
++
++      /* Synchronize the data received */
++      dma_sync_single_for_cpu(dev_for_dma_op, outbuf_dma,
++                      keylen + BLOB_OVERHEAD, DMA_FROM_DEVICE);
++
++free_desc:
++      kfree(encapdesc);
++
++unmap_outbuf:
++      dma_unmap_single(dev_for_dma_op, outbuf_dma, keylen + BLOB_OVERHEAD,
++                      DMA_FROM_DEVICE);
++
++unmap_keymod:
++      dma_unmap_single(dev_for_dma_op, keymod_dma, SECMEM_KEYMOD_LEN,
++                      DMA_TO_DEVICE);
++
++free_keymod:
++      kfree(lkeymod);
++
++exit:
++      return retval;
++}
++EXPORT_SYMBOL(sm_keystore_slot_export);
++
++/* Import a black/red key from a blob residing in external memory */
++int sm_keystore_slot_import(struct device *dev, u32 unit, u32 slot, u8 keycolor,
++                          u8 keyauth, u8 *inbuf, u16 keylen, u8 *keymod)
++{
++      struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
++      int retval = 0;
++      u8 __iomem *slotaddr, *lkeymod;
++      u8 __iomem *slotphys;
++      dma_addr_t keymod_dma, inbuf_dma;
++      u32 dsize, jstat;
++      u32 __iomem *decapdesc = NULL;
++      struct device *dev_for_dma_op;
++
++      /* Use the ring as device for DMA operations */
++      dev_for_dma_op = smpriv->smringdev;
++
++      /* Get the base address(es) of the specified slot */
++      slotaddr = (u8 *)smpriv->slot_get_address(dev, unit, slot);
++      slotphys = smpriv->slot_get_physical(dev, unit, slot);
++
++      /* Allocate memory for key modifier compatible with DMA */
++      lkeymod = kmalloc(SECMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA);
++      if (!lkeymod) {
++              retval = (-ENOMEM);
++              goto exit;
++      }
++
++      /* Get DMA address for the key modifier */
++      keymod_dma = dma_map_single(dev_for_dma_op, lkeymod,
++                                      SECMEM_KEYMOD_LEN, DMA_TO_DEVICE);
++      if (dma_mapping_error(dev_for_dma_op, keymod_dma)) {
++              dev_err(dev, "unable to map keymod: %p\n", lkeymod);
++              retval = (-ENOMEM);
++              goto free_keymod;
++      }
++
++      /* Copy the keymod and synchronize the DMA */
++      memcpy(lkeymod, keymod, SECMEM_KEYMOD_LEN);
++      dma_sync_single_for_device(dev_for_dma_op, keymod_dma,
++                                      SECMEM_KEYMOD_LEN, DMA_TO_DEVICE);
++
++      /* Get DMA address for the input */
++      inbuf_dma = dma_map_single(dev_for_dma_op, inbuf,
++                                      keylen + BLOB_OVERHEAD, DMA_TO_DEVICE);
++      if (dma_mapping_error(dev_for_dma_op, inbuf_dma)) {
++              dev_err(dev, "unable to map inbuf: %p\n", (void *)inbuf_dma);
++              retval = (-ENOMEM);
++              goto unmap_keymod;
++      }
++
++      /* synchronize the DMA */
++      dma_sync_single_for_device(dev_for_dma_op, inbuf_dma,
++                                      keylen + BLOB_OVERHEAD, DMA_TO_DEVICE);
++
++      /* Build the encapsulation job descriptor */
++      dsize = blob_decap_jobdesc(&decapdesc, keymod_dma, inbuf_dma, slotphys,
++                                 keylen, keycolor, SM_SECMEM, keyauth);
++      if (!dsize) {
++              dev_err(dev, "can't alloc a decapsulation descriptor\n");
++              retval = -ENOMEM;
++              goto unmap_inbuf;
++      }
++
++      /* Run the job */
++      jstat = sm_key_job(dev, decapdesc);
++
++      /*
++       * May want to expand upon error meanings a bit. Any CAAM status
++       * is reported as EIO, but we might want to look for something more
++       * meaningful for something like an ICV error on restore, otherwise
++       * the caller is left guessing.
++       */
++      if (jstat) {
++              retval = (-EIO);
++              goto free_desc;
++      }
++
++free_desc:
++      kfree(decapdesc);
++
++unmap_inbuf:
++      dma_unmap_single(dev_for_dma_op, inbuf_dma, keylen + BLOB_OVERHEAD,
++                      DMA_TO_DEVICE);
++
++unmap_keymod:
++      dma_unmap_single(dev_for_dma_op, keymod_dma, SECMEM_KEYMOD_LEN,
++                      DMA_TO_DEVICE);
++
++free_keymod:
++      kfree(lkeymod);
++
++exit:
++      return retval;
++}
++EXPORT_SYMBOL(sm_keystore_slot_import);
++
++/*
++ * Initialization/shutdown subsystem
++ * Assumes statically-invoked startup/shutdown from the controller driver
++ * for the present time, to be reworked when a device tree becomes
++ * available. This code will not modularize in present form.
++ *
++ * Also, simply uses ring 0 for execution at the present
++ */
++
++int caam_sm_startup(struct platform_device *pdev)
++{
++      struct device *ctrldev, *smdev;
++      struct caam_drv_private *ctrlpriv;
++      struct caam_drv_private_sm *smpriv;
++      struct caam_drv_private_jr *jrpriv;     /* need this for reg page */
++      struct platform_device *sm_pdev;
++      struct sm_page_descriptor *lpagedesc;
++      u32 page, pgstat, lpagect, detectedpage, smvid, smpart;
++      int ret = 0;
++
++      struct device_node *np;
++      ctrldev = &pdev->dev;
++      ctrlpriv = dev_get_drvdata(ctrldev);
++
++      /*
++       * If ctrlpriv is NULL, it's probably because the caam driver wasn't
++       * properly initialized (e.g. RNG4 init failed). Thus, bail out here.
++       */
++      if (!ctrlpriv) {
++              ret = -ENODEV;
++              goto exit;
++      }
++
++      /*
++       * Set up the private block for secure memory
++       * Only one instance is possible
++       */
++      smpriv = kzalloc(sizeof(struct caam_drv_private_sm), GFP_KERNEL);
++      if (smpriv == NULL) {
++              dev_err(ctrldev, "can't alloc private mem for secure memory\n");
++              ret = -ENOMEM;
++              goto exit;
++      }
++      smpriv->parentdev = ctrldev; /* copy of parent dev is handy */
++      spin_lock_init(&smpriv->kslock);
++
++      /* Create the dev */
++      np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-sm");
++      if (np)
++              of_node_clear_flag(np, OF_POPULATED);
++      sm_pdev = of_platform_device_create(np, "caam_sm", ctrldev);
++
++      if (sm_pdev == NULL) {
++              ret = -EINVAL;
++              goto free_smpriv;
++      }
++
++      /* Save a pointer to the platform device for Secure Memory */
++      smpriv->sm_pdev = sm_pdev;
++      smdev = &sm_pdev->dev;
++      dev_set_drvdata(smdev, smpriv);
++      ctrlpriv->smdev = smdev;
++
++      /* Set the Secure Memory Register Map Version */
++      smvid = rd_reg32(&ctrlpriv->jr[0]->perfmon.smvid);
++      smpart = rd_reg32(&ctrlpriv->jr[0]->perfmon.smpart);
++
++      if (smvid < SMVID_V2)
++              smpriv->sm_reg_offset = SM_V1_OFFSET;
++      else
++              smpriv->sm_reg_offset = SM_V2_OFFSET;
++
++      /*
++       * Collect configuration limit data for reference
++       * This batch comes from the partition data/vid registers in perfmon
++       */
++      smpriv->max_pages = ((smpart & SMPART_MAX_NUMPG_MASK) >>
++                          SMPART_MAX_NUMPG_SHIFT) + 1;
++      smpriv->top_partition = ((smpart & SMPART_MAX_PNUM_MASK) >>
++                              SMPART_MAX_PNUM_SHIFT) + 1;
++      smpriv->top_page =  ((smpart & SMPART_MAX_PG_MASK) >>
++                              SMPART_MAX_PG_SHIFT) + 1;
++      smpriv->page_size = 1024 << ((smvid & SMVID_PG_SIZE_MASK) >>
++                              SMVID_PG_SIZE_SHIFT);
++      smpriv->slot_size = 1 << CONFIG_CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE;
++
++#ifdef SM_DEBUG
++      dev_info(smdev, "max pages = %d, top partition = %d\n",
++                      smpriv->max_pages, smpriv->top_partition);
++      dev_info(smdev, "top page = %d, page size = %d (total = %d)\n",
++                      smpriv->top_page, smpriv->page_size,
++                      smpriv->top_page * smpriv->page_size);
++      dev_info(smdev, "selected slot size = %d\n", smpriv->slot_size);
++#endif
++
++      /*
++       * Now probe for partitions/pages to which we have access. Note that
++       * these have likely been set up by a bootloader or platform
++       * provisioning application, so we have to assume that we "inherit"
++       * a configuration and work within the constraints of what it might be.
++       *
++       * Assume use of the zeroth ring in the present iteration (until
++       * we can divorce the controller and ring drivers, and then assign
++       * an SM instance to any ring instance).
++       */
++      smpriv->smringdev = caam_jr_alloc();
++      if (!smpriv->smringdev) {
++              dev_err(smdev, "Device for job ring not created\n");
++              ret = -ENODEV;
++              goto unregister_smpdev;
++      }
++
++      jrpriv = dev_get_drvdata(smpriv->smringdev);
++      lpagect = 0;
++      pgstat = 0;
++      lpagedesc = kzalloc(sizeof(struct sm_page_descriptor)
++                          * smpriv->max_pages, GFP_KERNEL);
++      if (lpagedesc == NULL) {
++              ret = -ENOMEM;
++              goto free_smringdev;
++      }
++
++      for (page = 0; page < smpriv->max_pages; page++) {
++              u32 page_ownership;
++
++              if (sm_send_cmd(smpriv, jrpriv,
++                              ((page << SMC_PAGE_SHIFT) & SMC_PAGE_MASK) |
++                              (SMC_CMD_PAGE_INQUIRY & SMC_CMD_MASK),
++                              &pgstat)) {
++                      ret = -EINVAL;
++                      goto free_lpagedesc;
++              }
++
++              page_ownership = (pgstat & SMCS_PGWON_MASK) >> SMCS_PGOWN_SHIFT;
++              if ((page_ownership == SMCS_PGOWN_OWNED)
++                      || (page_ownership == SMCS_PGOWN_NOOWN)) {
++                      /* page allocated */
++                      lpagedesc[page].phys_pagenum =
++                              (pgstat & SMCS_PAGE_MASK) >> SMCS_PAGE_SHIFT;
++                      lpagedesc[page].own_part =
++                              (pgstat & SMCS_PART_SHIFT) >> SMCS_PART_MASK;
++                      lpagedesc[page].pg_base = (u8 *)ctrlpriv->sm_base +
++                              (smpriv->page_size * page);
++                      if (ctrlpriv->scu_en) {
++/* FIXME: get different addresses viewed by CPU and CAAM from
++ * platform property
++ */
++                              lpagedesc[page].pg_phys = (u8 *)0x20800000 +
++                                      (smpriv->page_size * page);
++                      } else {
++                              lpagedesc[page].pg_phys =
++                                      (u8 *) ctrlpriv->sm_phy +
++                                      (smpriv->page_size * page);
++                      }
++                      lpagect++;
++#ifdef SM_DEBUG
++                      dev_info(smdev,
++                              "physical page %d, owning partition = %d\n",
++                              lpagedesc[page].phys_pagenum,
++                              lpagedesc[page].own_part);
++#endif
++              }
++      }
++
++      smpriv->pagedesc = kzalloc(sizeof(struct sm_page_descriptor) * lpagect,
++                                 GFP_KERNEL);
++      if (smpriv->pagedesc == NULL) {
++              ret = -ENOMEM;
++              goto free_lpagedesc;
++      }
++      smpriv->localpages = lpagect;
++
++      detectedpage = 0;
++      for (page = 0; page < smpriv->max_pages; page++) {
++              if (lpagedesc[page].pg_base != NULL) {  /* e.g. live entry */
++                      memcpy(&smpriv->pagedesc[detectedpage],
++                             &lpagedesc[page],
++                             sizeof(struct sm_page_descriptor));
++#ifdef SM_DEBUG_CONT
++                      sm_show_page(smdev, &smpriv->pagedesc[detectedpage]);
++#endif
++                      detectedpage++;
++              }
++      }
++
++      kfree(lpagedesc);
++
++      sm_init_keystore(smdev);
++
++      goto exit;
++
++free_lpagedesc:
++      kfree(lpagedesc);
++free_smringdev:
++      caam_jr_free(smpriv->smringdev);
++unregister_smpdev:
++      of_device_unregister(smpriv->sm_pdev);
++free_smpriv:
++      kfree(smpriv);
++
++exit:
++      return ret;
++}
++
++void caam_sm_shutdown(struct platform_device *pdev)
++{
++      struct device *ctrldev, *smdev;
++      struct caam_drv_private *priv;
++      struct caam_drv_private_sm *smpriv;
++
++      ctrldev = &pdev->dev;
++      priv = dev_get_drvdata(ctrldev);
++      smdev = priv->smdev;
++
++      /* Return if resource not initialized by startup */
++      if (smdev == NULL)
++              return;
++
++      smpriv = dev_get_drvdata(smdev);
++
++      caam_jr_free(smpriv->smringdev);
++
++      /* Remove Secure Memory Platform Device */
++      of_device_unregister(smpriv->sm_pdev);
++
++      kfree(smpriv->pagedesc);
++      kfree(smpriv);
++}
++EXPORT_SYMBOL(caam_sm_shutdown);
++
++static void  __exit caam_sm_exit(void)
++{
++      struct device_node *dev_node;
++      struct platform_device *pdev;
++
++      dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
++      if (!dev_node) {
++              dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
++              if (!dev_node)
++                      return;
++      }
++
++      pdev = of_find_device_by_node(dev_node);
++      if (!pdev)
++              return;
++
++      of_node_put(dev_node);
++
++      caam_sm_shutdown(pdev);
++
++      return;
++}
++
++static int __init caam_sm_init(void)
++{
++      struct device_node *dev_node;
++      struct platform_device *pdev;
++
++      /*
++       * Do of_find_compatible_node() then of_find_device_by_node()
++       * once a functional device tree is available
++       */
++      dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
++      if (!dev_node) {
++              dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
++              if (!dev_node)
++                      return -ENODEV;
++      }
++
++      pdev = of_find_device_by_node(dev_node);
++      if (!pdev)
++              return -ENODEV;
++
++      of_node_get(dev_node);
++
++      caam_sm_startup(pdev);
++
++      return 0;
++}
++
++module_init(caam_sm_init);
++module_exit(caam_sm_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_DESCRIPTION("FSL CAAM Secure Memory / Keystore");
++MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD");
+--- /dev/null
++++ b/drivers/crypto/caam/sm_test.c
+@@ -0,0 +1,571 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
++/*
++ * Secure Memory / Keystore Exemplification Module
++ *
++ * Copyright 2012-2015 Freescale Semiconductor, Inc.
++ * Copyright 2016-2019 NXP
++ *
++ * This module has been overloaded as an example to show:
++ * - Secure memory subsystem initialization/shutdown
++ * - Allocation/deallocation of "slots" in a secure memory page
++ * - Loading and unloading of key material into slots
++ * - Covering of secure memory objects into "black keys" (ECB only at present)
++ * - Verification of key covering (by differentiation only)
++ * - Exportation of keys into secure memory blobs (with display of result)
++ * - Importation of keys from secure memory blobs (with display of result)
++ * - Verification of re-imported keys where possible.
++ *
++ * The module does not show the use of key objects as working key register
++ * source material at this time.
++ *
++ * This module can use a substantial amount of refactoring, which may occur
++ * after the API gets some mileage. Furthermore, expect this module to
++ * eventually disappear once the API is integrated into "real" software.
++ */
++
++#include "compat.h"
++#include "regs.h"
++#include "intern.h"
++#include "desc.h"
++#include "error.h"
++#include "jr.h"
++#include "sm.h"
++
++/* Fixed known pattern for a key modifier */
++static u8 skeymod[] = {
++      0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
++      0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
++};
++
++/* Fixed known pattern for a key */
++static u8 clrkey[] = {
++      0x00, 0x01, 0x02, 0x03, 0x04, 0x0f, 0x06, 0x07,
++      0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
++      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
++      0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
++      0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
++      0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
++      0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
++      0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
++      0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
++      0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
++      0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
++      0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
++      0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
++      0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
++      0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
++      0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
++      0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++      0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++      0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++      0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
++      0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
++      0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
++      0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
++      0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
++      0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
++      0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
++      0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
++      0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
++      0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
++      0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
++      0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
++      0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
++};
++
++static void key_display(struct device *dev, const char *label, u16 size,
++                      u8 *key)
++{
++      unsigned i;
++
++      dev_dbg(dev, "%s", label);
++      for (i = 0; i < size; i += 8)
++              dev_dbg(dev,
++                      "[%04d] %02x %02x %02x %02x %02x %02x %02x %02x\n",
++                      i, key[i], key[i + 1], key[i + 2], key[i + 3],
++                      key[i + 4], key[i + 5], key[i + 6], key[i + 7]);
++}
++
++int caam_sm_example_init(struct platform_device *pdev)
++{
++      struct device *ctrldev, *ksdev;
++      struct caam_drv_private *ctrlpriv;
++      struct caam_drv_private_sm *kspriv;
++      u32 unit, units;
++      int rtnval;
++      u8 clrkey8[8], clrkey16[16], clrkey24[24], clrkey32[32];
++      u8 blkkey8[AES_BLOCK_PAD(8)], blkkey16[AES_BLOCK_PAD(16)];
++      u8 blkkey24[AES_BLOCK_PAD(24)], blkkey32[AES_BLOCK_PAD(32)];
++      u8 rstkey8[AES_BLOCK_PAD(8)], rstkey16[AES_BLOCK_PAD(16)];
++      u8 rstkey24[AES_BLOCK_PAD(24)], rstkey32[AES_BLOCK_PAD(32)];
++      u8 __iomem *blob8, *blob16, *blob24, *blob32;
++      u32 keyslot8, keyslot16, keyslot24, keyslot32 = 0;
++
++      blob8 = blob16 = blob24 = blob32 = NULL;
++
++      /*
++       * 3.5.x and later revs for MX6 should be able to ditch this
++       * and detect via dts property
++       */
++      ctrldev = &pdev->dev;
++      ctrlpriv = dev_get_drvdata(ctrldev);
++
++      /*
++       * If ctrlpriv is NULL, it's probably because the caam driver wasn't
++       * properly initialized (e.g. RNG4 init failed). Thus, bail out here.
++       */
++      if (!ctrlpriv)
++              return -ENODEV;
++
++      ksdev = ctrlpriv->smdev;
++      kspriv = dev_get_drvdata(ksdev);
++      if (kspriv == NULL)
++              return -ENODEV;
++
++      /* What keystores are available ? */
++      units = sm_detect_keystore_units(ksdev);
++      if (!units)
++              dev_err(ksdev, "blkkey_ex: no keystore units available\n");
++
++      /*
++       * MX6 bootloader stores some stuff in unit 0, so let's
++       * use 1 or above
++       */
++      if (units < 2) {
++              dev_err(ksdev, "blkkey_ex: insufficient keystore units\n");
++              return -ENODEV;
++      }
++      unit = 1;
++
++      dev_info(ksdev, "blkkey_ex: %d keystore units available\n", units);
++
++      /* Initialize/Establish Keystore */
++      sm_establish_keystore(ksdev, unit);     /* Initalize store in #1 */
++
++      /*
++       * Now let's set up buffers for blobs in DMA-able memory. All are
++       * larger than need to be so that blob size can be seen.
++       */
++      blob8 = kzalloc(128, GFP_KERNEL | GFP_DMA);
++      blob16 = kzalloc(128, GFP_KERNEL | GFP_DMA);
++      blob24 = kzalloc(128, GFP_KERNEL | GFP_DMA);
++      blob32 = kzalloc(128, GFP_KERNEL | GFP_DMA);
++
++      if ((blob8 == NULL) || (blob16 == NULL) || (blob24 == NULL) ||
++          (blob32 == NULL)) {
++              rtnval = -ENOMEM;
++              dev_err(ksdev, "blkkey_ex: can't get blob buffers\n");
++              goto freemem;
++      }
++
++      /* Initialize clear keys with a known and recognizable pattern */
++      memcpy(clrkey8, clrkey, 8);
++      memcpy(clrkey16, clrkey, 16);
++      memcpy(clrkey24, clrkey, 24);
++      memcpy(clrkey32, clrkey, 32);
++
++      memset(blkkey8, 0, AES_BLOCK_PAD(8));
++      memset(blkkey16, 0, AES_BLOCK_PAD(16));
++      memset(blkkey24, 0, AES_BLOCK_PAD(24));
++      memset(blkkey32, 0, AES_BLOCK_PAD(32));
++
++      memset(rstkey8, 0, AES_BLOCK_PAD(8));
++      memset(rstkey16, 0, AES_BLOCK_PAD(16));
++      memset(rstkey24, 0, AES_BLOCK_PAD(24));
++      memset(rstkey32, 0, AES_BLOCK_PAD(32));
++
++      /*
++       * Allocate keyslots. Since we're going to blacken keys in-place,
++       * we want slots big enough to pad out to the next larger AES blocksize
++       * so pad them out.
++       */
++      rtnval = sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(8),
++                                      &keyslot8);
++      if (rtnval)
++              goto freemem;
++
++      rtnval = sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(16),
++                                      &keyslot16);
++      if (rtnval)
++              goto dealloc_slot8;
++
++      rtnval = sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(24),
++                                      &keyslot24);
++      if (rtnval)
++              goto dealloc_slot16;
++
++      rtnval = sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(32),
++                                      &keyslot32);
++      if (rtnval)
++              goto dealloc_slot24;
++
++
++      /* Now load clear key data into the newly allocated slots */
++      rtnval = sm_keystore_slot_load(ksdev, unit, keyslot8, clrkey8, 8);
++      if (rtnval)
++              goto dealloc;
++
++      rtnval = sm_keystore_slot_load(ksdev, unit, keyslot16, clrkey16, 16);
++      if (rtnval)
++              goto dealloc;
++
++      rtnval = sm_keystore_slot_load(ksdev, unit, keyslot24, clrkey24, 24);
++      if (rtnval)
++              goto dealloc;
++
++      rtnval = sm_keystore_slot_load(ksdev, unit, keyslot32, clrkey32, 32);
++      if (rtnval)
++              goto dealloc;
++
++      /*
++       * All cleartext keys are loaded into slots (in an unprotected
++       * partition at this time)
++       *
++       * Cover keys in-place
++       */
++      rtnval = sm_keystore_cover_key(ksdev, unit, keyslot8, 8, KEY_COVER_ECB);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't cover 64-bit key\n");
++              goto dealloc;
++      }
++
++      rtnval = sm_keystore_cover_key(ksdev, unit, keyslot16, 16,
++                                     KEY_COVER_ECB);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't cover 128-bit key\n");
++              goto dealloc;
++      }
++
++      rtnval = sm_keystore_cover_key(ksdev, unit, keyslot24, 24,
++                                     KEY_COVER_ECB);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't cover 192-bit key\n");
++              goto dealloc;
++      }
++
++      rtnval = sm_keystore_cover_key(ksdev, unit, keyslot32, 32,
++                                     KEY_COVER_ECB);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't cover 256-bit key\n");
++              goto dealloc;
++      }
++
++      /*
++       * Keys should be covered and appear sufficiently "random"
++       * as a result of the covering (blackening) process. Assuming
++       * non-secure mode, read them back out for examination; they should
++       * appear as random data, completely differing from the clear
++       * inputs. So, this will read them back from secure memory and
++       * compare them. If they match the clear key, then the covering
++       * operation didn't occur.
++       */
++
++      rtnval = sm_keystore_slot_read(ksdev, unit, keyslot8, AES_BLOCK_PAD(8),
++                                     blkkey8);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't read 64-bit black key\n");
++              goto dealloc;
++      }
++
++      rtnval = sm_keystore_slot_read(ksdev, unit, keyslot16,
++                                     AES_BLOCK_PAD(16), blkkey16);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't read 128-bit black key\n");
++              goto dealloc;
++      }
++
++      rtnval = sm_keystore_slot_read(ksdev, unit, keyslot24,
++                                     AES_BLOCK_PAD(24), blkkey24);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't read 192-bit black key\n");
++              goto dealloc;
++      }
++
++      rtnval = sm_keystore_slot_read(ksdev, unit, keyslot32,
++                                     AES_BLOCK_PAD(32), blkkey32);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't read 256-bit black key\n");
++              goto dealloc;
++      }
++
++      rtnval = -EINVAL;
++      if (!memcmp(blkkey8, clrkey8, 8)) {
++              dev_err(ksdev, "blkkey_ex: 64-bit key cover failed\n");
++              goto dealloc;
++      }
++
++      if (!memcmp(blkkey16, clrkey16, 16)) {
++              dev_err(ksdev, "blkkey_ex: 128-bit key cover failed\n");
++              goto dealloc;
++      }
++
++      if (!memcmp(blkkey24, clrkey24, 24)) {
++              dev_err(ksdev, "blkkey_ex: 192-bit key cover failed\n");
++              goto dealloc;
++      }
++
++      if (!memcmp(blkkey32, clrkey32, 32)) {
++              dev_err(ksdev, "blkkey_ex: 256-bit key cover failed\n");
++              goto dealloc;
++      }
++
++
++      key_display(ksdev, "64-bit clear key:", 8, clrkey8);
++      key_display(ksdev, "64-bit black key:", AES_BLOCK_PAD(8), blkkey8);
++
++      key_display(ksdev, "128-bit clear key:", 16, clrkey16);
++      key_display(ksdev, "128-bit black key:", AES_BLOCK_PAD(16), blkkey16);
++
++      key_display(ksdev, "192-bit clear key:", 24, clrkey24);
++      key_display(ksdev, "192-bit black key:", AES_BLOCK_PAD(24), blkkey24);
++
++      key_display(ksdev, "256-bit clear key:", 32, clrkey32);
++      key_display(ksdev, "256-bit black key:", AES_BLOCK_PAD(32), blkkey32);
++
++      /*
++       * Now encapsulate all keys as SM blobs out to external memory
++       * Blobs will appear as random-looking blocks of data different
++       * from the original source key, and 48 bytes longer than the
++       * original key, to account for the extra data encapsulated within.
++       */
++      key_display(ksdev, "64-bit unwritten blob:", 96, blob8);
++      key_display(ksdev, "128-bit unwritten blob:", 96, blob16);
++      key_display(ksdev, "196-bit unwritten blob:", 96, blob24);
++      key_display(ksdev, "256-bit unwritten blob:", 96, blob32);
++
++      rtnval = sm_keystore_slot_export(ksdev, unit, keyslot8, BLACK_KEY,
++                                       KEY_COVER_ECB, blob8, 8, skeymod);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't encapsulate 64-bit key\n");
++              goto dealloc;
++      }
++
++      rtnval = sm_keystore_slot_export(ksdev, unit, keyslot16, BLACK_KEY,
++                                       KEY_COVER_ECB, blob16, 16, skeymod);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't encapsulate 128-bit key\n");
++              goto dealloc;
++      }
++
++      rtnval = sm_keystore_slot_export(ksdev, unit, keyslot24, BLACK_KEY,
++                                       KEY_COVER_ECB, blob24, 24, skeymod);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't encapsulate 192-bit key\n");
++              goto dealloc;
++      }
++
++      rtnval = sm_keystore_slot_export(ksdev, unit, keyslot32, BLACK_KEY,
++                                       KEY_COVER_ECB, blob32, 32, skeymod);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't encapsulate 256-bit key\n");
++              goto dealloc;
++      }
++
++      key_display(ksdev, "64-bit black key in blob:", 96, blob8);
++      key_display(ksdev, "128-bit black key in blob:", 96, blob16);
++      key_display(ksdev, "192-bit black key in blob:", 96, blob24);
++      key_display(ksdev, "256-bit black key in blob:", 96, blob32);
++
++      /*
++       * Now re-import black keys from secure-memory blobs stored
++       * in general memory from the previous operation. Since we are
++       * working with black keys, and since power has not cycled, the
++       * restored black keys should match the original blackened keys
++       * (this would not be true if the blobs were save in some non-volatile
++       * store, and power was cycled between the save and restore)
++       */
++      rtnval = sm_keystore_slot_import(ksdev, unit, keyslot8, BLACK_KEY,
++                                       KEY_COVER_ECB, blob8, 8, skeymod);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't decapsulate 64-bit blob\n");
++              goto dealloc;
++      }
++
++      rtnval = sm_keystore_slot_import(ksdev, unit, keyslot16, BLACK_KEY,
++                                       KEY_COVER_ECB, blob16, 16, skeymod);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't decapsulate 128-bit blob\n");
++              goto dealloc;
++      }
++
++      rtnval = sm_keystore_slot_import(ksdev, unit, keyslot24, BLACK_KEY,
++                                       KEY_COVER_ECB, blob24, 24, skeymod);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't decapsulate 196-bit blob\n");
++              goto dealloc;
++      }
++
++      rtnval = sm_keystore_slot_import(ksdev, unit, keyslot32, BLACK_KEY,
++                                       KEY_COVER_ECB, blob32, 32, skeymod);
++      if (rtnval) {
++              dev_err(ksdev, "blkkey_ex: can't decapsulate 256-bit blob\n");
++              goto dealloc;
++      }
++
++
++      /*
++       * Blobs are now restored as black keys. Read those black keys back
++       * for a comparison with the original black key, they should match
++       */
++      rtnval = sm_keystore_slot_read(ksdev, unit, keyslot8, AES_BLOCK_PAD(8),
++                                     rstkey8);
++      if (rtnval) {
++              dev_err(ksdev,
++                      "blkkey_ex: can't read restored 64-bit black key\n");
++              goto dealloc;
++      }
++
++      rtnval = sm_keystore_slot_read(ksdev, unit, keyslot16,
++                                     AES_BLOCK_PAD(16), rstkey16);
++      if (rtnval) {
++              dev_err(ksdev,
++                      "blkkey_ex: can't read restored 128-bit black key\n");
++              goto dealloc;
++      }
++
++      rtnval = sm_keystore_slot_read(ksdev, unit, keyslot24,
++                                     AES_BLOCK_PAD(24), rstkey24);
++      if (rtnval) {
++              dev_err(ksdev,
++                      "blkkey_ex: can't read restored 196-bit black key\n");
++              goto dealloc;
++      }
++
++      rtnval = sm_keystore_slot_read(ksdev, unit, keyslot32,
++                                     AES_BLOCK_PAD(32), rstkey32);
++      if (rtnval) {
++              dev_err(ksdev,
++                      "blkkey_ex: can't read restored 256-bit black key\n");
++              goto dealloc;
++      }
++
++      key_display(ksdev, "restored 64-bit black key:", AES_BLOCK_PAD(8),
++                  rstkey8);
++      key_display(ksdev, "restored 128-bit black key:", AES_BLOCK_PAD(16),
++                  rstkey16);
++      key_display(ksdev, "restored 192-bit black key:", AES_BLOCK_PAD(24),
++                  rstkey24);
++      key_display(ksdev, "restored 256-bit black key:", AES_BLOCK_PAD(32),
++                  rstkey32);
++
++      /*
++       * Compare the restored black keys with the original blackened keys
++       * As long as we're operating within the same power cycle, a black key
++       * restored from a blob should match the original black key IF the
++       * key happens to be of a size that matches a multiple of the AES
++       * blocksize. Any key that is padded to fill the block size will not
++       * match, excepting a key that exceeds a block; only the first full
++       * blocks will match (assuming ECB).
++       *
++       * Therefore, compare the 16 and 32 bit keys, they should match.
++       * The 24 bit key can only match within the first 16 byte block.
++       */
++
++      if (memcmp(rstkey16, blkkey16, AES_BLOCK_PAD(16))) {
++              dev_err(ksdev, "blkkey_ex: 128-bit restored key mismatch\n");
++              rtnval = -EINVAL;
++      }
++
++      /* Only first AES block will match, remainder subject to padding */
++      if (memcmp(rstkey24, blkkey24, 16)) {
++              dev_err(ksdev, "blkkey_ex: 192-bit restored key mismatch\n");
++              rtnval = -EINVAL;
++      }
++
++      if (memcmp(rstkey32, blkkey32, AES_BLOCK_PAD(32))) {
++              dev_err(ksdev, "blkkey_ex: 256-bit restored key mismatch\n");
++              rtnval = -EINVAL;
++      }
++
++
++      /* Remove keys from keystore */
++dealloc:
++      sm_keystore_slot_dealloc(ksdev, unit, keyslot32);
++dealloc_slot24:
++      sm_keystore_slot_dealloc(ksdev, unit, keyslot24);
++dealloc_slot16:
++      sm_keystore_slot_dealloc(ksdev, unit, keyslot16);
++dealloc_slot8:
++      sm_keystore_slot_dealloc(ksdev, unit, keyslot8);
++
++      /* Free resources */
++freemem:
++      kfree(blob8);
++      kfree(blob16);
++      kfree(blob24);
++      kfree(blob32);
++
++      /* Disconnect from keystore and leave */
++      sm_release_keystore(ksdev, unit);
++
++      return rtnval;
++}
++EXPORT_SYMBOL(caam_sm_example_init);
++
++void caam_sm_example_shutdown(void)
++{
++      /* unused in present version */
++      struct device_node *dev_node;
++      struct platform_device *pdev;
++
++      /*
++       * Do of_find_compatible_node() then of_find_device_by_node()
++       * once a functional device tree is available
++       */
++      dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
++      if (!dev_node) {
++              dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
++              if (!dev_node)
++                      return;
++      }
++
++      pdev = of_find_device_by_node(dev_node);
++      if (!pdev)
++              return;
++
++      of_node_get(dev_node);
++
++}
++
++static int __init caam_sm_test_init(void)
++{
++      struct device_node *dev_node;
++      struct platform_device *pdev;
++      int ret;
++
++      /*
++       * Do of_find_compatible_node() then of_find_device_by_node()
++       * once a functional device tree is available
++       */
++      dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
++      if (!dev_node) {
++              dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
++              if (!dev_node)
++                      return -ENODEV;
++      }
++
++      pdev = of_find_device_by_node(dev_node);
++      if (!pdev)
++              return -ENODEV;
++
++      of_node_put(dev_node);
++
++      ret = caam_sm_example_init(pdev);
++      if (ret)
++              dev_err(&pdev->dev, "SM test failed: %d\n", ret);
++      else
++              dev_info(&pdev->dev, "SM test passed\n");
++
++      return ret;
++}
++
++
++/* Module-based initialization needs to wait for dev tree */
++#ifdef CONFIG_OF
++module_init(caam_sm_test_init);
++module_exit(caam_sm_example_shutdown);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_DESCRIPTION("FSL CAAM Black Key Usage Example");
++MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD");
++#endif
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0021-MLK-19801-1-crypto-caam-add-tag-functionality.patch b/target/linux/layerscape/patches-5.4/804-crypto-0021-MLK-19801-1-crypto-caam-add-tag-functionality.patch
new file mode 100644 (file)
index 0000000..cb2477c
--- /dev/null
@@ -0,0 +1,439 @@
+From b2fb5441c4613465e0c8f9203cdec4f8083d2fdd Mon Sep 17 00:00:00 2001
+From: Franck LENORMAND <franck.lenormand@nxp.com>
+Date: Fri, 5 Oct 2018 16:08:25 +0200
+Subject: [PATCH] MLK-19801-1 crypto: caam - add tag functionality
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add functions to tag an object with metadata(configuration).
+
+It is possible to:
+ - create metadata:
+       - init_tag_object_header
+       - init_blackey_conf
+       - set_tag_object_conf
+ - retrieve metadata:
+       - get_tag_object_conf
+       - get_blackey_conf
+
+The API expects an object to be a space a memory
+with an address and a size.
+
+The implementation of the tag is currently exposed
+but users shouldn't access it directly, they should
+use the functions provided.
+
+Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
+(cherry picked from commit ebbb132da8e7f9de7f3d375eff8d87f684feb1eb)
+Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
+(cherry picked from commit 8b6f6b4474be33ee271dfe2cce79f9f6335733aa)
+
+-make tag functionality depend on JR
+-change commit headline prefix
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/Kconfig      |  10 ++
+ drivers/crypto/caam/Makefile     |   1 +
+ drivers/crypto/caam/tag_object.c | 260 +++++++++++++++++++++++++++++++++++++++
+ drivers/crypto/caam/tag_object.h | 100 +++++++++++++++
+ 4 files changed, 371 insertions(+)
+ create mode 100644 drivers/crypto/caam/tag_object.c
+ create mode 100644 drivers/crypto/caam/tag_object.h
+
+--- a/drivers/crypto/caam/Kconfig
++++ b/drivers/crypto/caam/Kconfig
+@@ -147,6 +147,16 @@ config CRYPTO_DEV_FSL_CAAM_RNG_API
+         Selecting this will register the SEC4 hardware rng to
+         the hw_random API for suppying the kernel entropy pool.
++config CRYPTO_DEV_FSL_CAAM_TK_API
++      bool "Register tagged key cryptography implementations with Crypto API"
++      depends on CRYPTO_DEV_FSL_CAAM_CRYPTO_API
++      help
++        Selecting this will register algorithms supporting tagged
++        key.
++
++        Tagged key are keys that contains metadata indicating what
++        they are and how to handle them.
++
+ config CRYPTO_DEV_FSL_CAAM_RNG_TEST
+       bool "Test caam rng"
+       depends on CRYPTO_DEV_FSL_CAAM_RNG_API
+--- a/drivers/crypto/caam/Makefile
++++ b/drivers/crypto/caam/Makefile
+@@ -24,6 +24,7 @@ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM) += sm_store.o
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST) += sm_test.o
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO) += secvio.o
++caam-jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API) += tag_object.o
+ caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += qi.o
+ ifneq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI),)
+--- /dev/null
++++ b/drivers/crypto/caam/tag_object.c
+@@ -0,0 +1,260 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
++/*
++ * Copyright 2018-2019 NXP
++ */
++
++#include <linux/export.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++
++#include "tag_object.h"
++#include "desc.h"
++
++/*
++ * Magic number to clearly identify the structure is for us
++ * 0x54 = 'T'
++ * 0x61 = 'a'
++ * 0x67 = 'g'
++ * 0x4f = 'O'
++ */
++#define TAG_OBJECT_MAGIC 0x5461674f
++
++/**
++ * struct tagged_object - Structure representing a tagged object
++ * @tag : The configuration of the data
++ * @object : The object
++ */
++struct tagged_object {
++      struct tag_object_conf tag;
++      char object;
++};
++
++/**
++ * is_bk_type() - Determines if black key type.
++ * @type: The type
++ *
++ * Return: True if black key type, False otherwise.
++ */
++static bool is_bk_type(enum tag_type type)
++{
++      return (type == TAG_TYPE_BLACK_KEY_ECB) ||
++              (type == TAG_TYPE_BLACK_KEY_ECB_TRUSTED) ||
++              (type == TAG_TYPE_BLACK_KEY_CCM) ||
++              (type == TAG_TYPE_BLACK_KEY_CCM_TRUSTED);
++}
++
++/**
++ * is_bk_conf() - Determines if black key conf.
++ * @tag_obj_conf : The tag object conf
++ *
++ * Return: True if black key conf, False otherwise.
++ */
++bool is_bk_conf(const struct tag_object_conf *tag_obj_conf)
++{
++      return is_bk_type(tag_obj_conf->header.type);
++}
++EXPORT_SYMBOL(is_bk_conf);
++
++/**
++ * get_bk_conf() - Gets the block conf.
++ * @tag_obj_conf : The tag object conf
++ *
++ * Return: The block conf.
++ */
++const struct blackey_conf *get_bk_conf(const struct tag_object_conf *tag_obj_conf)
++{
++      return &tag_obj_conf->conf.bk_conf;
++}
++
++/**
++ * get_tag_object_overhead() - Gets the tag object overhead.
++ *
++ * Return: The tag object overhead.
++ */
++size_t get_tag_object_overhead(void)
++{
++      return TAG_OVERHEAD;
++}
++EXPORT_SYMBOL(get_tag_object_overhead);
++
++/**
++ * is_valid_type() - Determines if valid type.
++ * @type : The type
++ *
++ * Return: True if valid type, False otherwise.
++ */
++bool is_valid_type(enum tag_type type)
++{
++      return (type > TAG_TYPE_NOT_SUPPORTED) && (type < NB_TAG_TYPE);
++}
++EXPORT_SYMBOL(is_valid_type);
++
++/**
++ * is_valid_header() - Determines if valid header.
++ * @header : The header
++ *
++ * Return: True if valid tag object conf, False otherwise.
++ */
++static bool is_valid_header(const struct conf_header *header)
++{
++      bool valid = header->_magic_number == TAG_OBJECT_MAGIC;
++
++      valid = valid && is_valid_type(header->type);
++
++      return valid;
++}
++
++/**
++ * is_valid_tag_object_conf() - Determines if valid tag object conf.
++ * @tag_obj_conf : The tag object conf
++ *
++ * Return: True if valid header, False otherwise.
++ */
++bool is_valid_tag_object_conf(const struct tag_object_conf *tag_obj_conf)
++{
++      bool valid = true;
++
++      valid = is_valid_header(&tag_obj_conf->header);
++
++      return valid;
++}
++EXPORT_SYMBOL(is_valid_tag_object_conf);
++
++/**
++ * get_tag_object_conf() - Gets a pointer on the tag object conf.
++ * @tag_obj_conf : The tag object conf
++ * @buffer : The buffer
++ * @size : The size
++ *
++ * Return: 0 if success, else error code
++ */
++int get_tag_object_conf(void *buffer, size_t size,
++                      struct tag_object_conf **tag_obj_conf)
++{
++      bool is_valid;
++      struct tagged_object *tago = (struct tagged_object *)buffer;
++      size_t conf_size = get_tag_object_overhead();
++
++      /* Check we can retrieve the conf */
++      if (size < conf_size)
++              return -EINVAL;
++
++      is_valid = is_valid_tag_object_conf(&tago->tag);
++
++      *tag_obj_conf = &tago->tag;
++
++      return (is_valid) ? 0 : -EINVAL;
++}
++EXPORT_SYMBOL(get_tag_object_conf);
++
++/**
++ * init_tag_object_header() - Initialize the tag object header
++ * @conf_header : The configuration header
++ * @type : The type
++ *
++ * It initialize the header structure
++ */
++void init_tag_object_header(struct conf_header *conf_header,
++                          enum tag_type type)
++{
++      conf_header->_magic_number = TAG_OBJECT_MAGIC;
++      conf_header->type = type;
++}
++EXPORT_SYMBOL(init_tag_object_header);
++
++/**
++ * set_tag_object_conf() - Sets the tag object conf.
++ * @tag_obj_conf : The tag object conf
++ * @buffer : The buffer
++ * @obj_size : The object size
++ * @to_size : The tagged object size
++ *
++ * Return: 0 if success, else error code
++ */
++int set_tag_object_conf(const struct tag_object_conf *tag_obj_conf,
++                      void *buffer, size_t obj_size, u32 *to_size)
++{
++      struct tagged_object *tago = buffer;
++      size_t conf_size = get_tag_object_overhead();
++      size_t req_size = obj_size + conf_size;
++
++      /* Check we can set the conf */
++      if (*to_size < req_size) {
++              *to_size = req_size;
++              return -EINVAL;
++      }
++
++      /* Move the object */
++      memmove(&tago->object, buffer, obj_size);
++
++      /* Copy the tag */
++      memcpy(&tago->tag, tag_obj_conf, conf_size);
++
++      *to_size = req_size;
++
++      return 0;
++}
++EXPORT_SYMBOL(set_tag_object_conf);
++
++/**
++ * init_blackey_conf() - Initialize the black key configuration
++ * @blackey_conf : The blackey conf
++ * @len : The length
++ * @ccm : The ccm
++ * @tk : The trusted key
++ *
++ * It initialize the black key configuration structure
++ */
++void init_blackey_conf(struct blackey_conf *blackey_conf,
++                     size_t len, bool ccm, bool tk)
++{
++      blackey_conf->real_len = len;
++      blackey_conf->load = KEY_ENC
++                              | ((ccm) ? KEY_EKT : 0)
++                              | ((tk) ? KEY_TK : 0);
++}
++EXPORT_SYMBOL(init_blackey_conf);
++
++/**
++ * get_blackey_conf() - Get the black key configuration
++ * @blackey_conf : The blackey conf
++ * @real_len : The real length
++ * @load_param : The load parameter
++ *
++ * It retrieve the black key configuration
++ */
++void get_blackey_conf(const struct blackey_conf *blackey_conf,
++                    u32 *real_len, u32 *load_param)
++{
++      *real_len = blackey_conf->real_len;
++      *load_param = blackey_conf->load;
++}
++EXPORT_SYMBOL(get_blackey_conf);
++
++/**
++ * get_tagged_data() - Get a pointer on the data and the size
++ * @tagged_object : Pointer on the tagged object
++ * @tagged_object_size : tagged object size in bytes
++ * @data : Pointer on the data
++ * @data_size : data size in bytes
++ *
++ * Return: 0 if success, else error code
++ */
++int get_tagged_data(void *tagged_object, size_t tagged_object_size,
++                  void **data, u32 *data_size)
++{
++      struct tagged_object *tago =
++              (struct tagged_object *)tagged_object;
++      size_t conf_size = get_tag_object_overhead();
++
++      /* Check we can retrieve the object */
++      if (tagged_object_size < conf_size)
++              return -EINVAL;
++
++      /* Retrieve the object */
++      *data = &tago->object;
++      *data_size = tagged_object_size - conf_size;
++
++      return 0;
++}
++EXPORT_SYMBOL(get_tagged_data);
+--- /dev/null
++++ b/drivers/crypto/caam/tag_object.h
+@@ -0,0 +1,100 @@
++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
++/*
++ * Copyright 2018-2019 NXP
++ */
++
++#ifndef _TAG_OBJECT_H_
++#define _TAG_OBJECT_H_
++
++#include <linux/types.h>
++
++#define TAG_MIN_SIZE (2 * sizeof(struct conf_header))
++#define TAG_OVERHEAD sizeof(struct tag_object_conf)
++
++/**
++ * enum tag_type - Type of data represented by the tag
++ */
++enum tag_type {
++      /** @TAG_TYPE_NOT_SUPPORTED: The type is not supported */
++      TAG_TYPE_NOT_SUPPORTED = 0,
++
++      /* Type that passes is_tag_type_valid() */
++      /** @TAG_TYPE_BLACK_KEY_ECB: Black key encrypted with ECB */
++      TAG_TYPE_BLACK_KEY_ECB,
++      /**
++       * @TAG_TYPE_BLACK_KEY_ECB_TRUSTED: ECB Black key created by trusted
++       * descriptor
++       */
++      TAG_TYPE_BLACK_KEY_ECB_TRUSTED,
++      /** @TAG_TYPE_BLACK_KEY_CCM: Black key encrypted with CCM */
++      TAG_TYPE_BLACK_KEY_CCM,
++      /**
++       * @TAG_TYPE_BLACK_KEY_CCM_TRUSTED: CCM Black key created by trusted
++       * descriptor
++       */
++      TAG_TYPE_BLACK_KEY_CCM_TRUSTED,
++
++      /** @NB_TAG_TYPE: Number of type of tag */
++      NB_TAG_TYPE,
++};
++
++/**
++ * struct conf_header - Common struture holding the type of data and the magic
++ * number
++ * @_magic_number : A magic number to identify the structure
++ * @type : The type of data contained
++ */
++struct conf_header {
++      u32 _magic_number;
++      u32 type;
++};
++
++/**
++ * struct blackey_conf - Configuration for a black key
++ * @load : Load parameter for CAAM
++ * @real_len : Length of the key before encryption
++ */
++struct blackey_conf {
++      u32 load;
++      u32 real_len;
++};
++
++/**
++ * struct tag_object_conf - Common structure which is the tag applied to data
++ * @header : Part of the data initialized with common function
++ * :c:func:`init_tag_object_header`
++ * @conf : Configuration data about the object tagged, initialized with
++ * specific function
++ */
++struct tag_object_conf {
++      struct conf_header header;
++      union {
++              struct blackey_conf bk_conf;
++      } conf;
++};
++
++bool is_bk_conf(const struct tag_object_conf *tag_obj_conf);
++
++bool is_valid_tag_object_conf(const struct tag_object_conf *tag_obj_conf);
++
++void init_tag_object_header(struct conf_header *conf_header,
++                          enum tag_type type);
++
++int get_tag_object_conf(void *buffer, size_t buffer_size,
++                      struct tag_object_conf **tag_obj_conf);
++
++int set_tag_object_conf(const struct tag_object_conf *tag_obj_conf,
++                      void *buffer, size_t obj_size, u32 *to_size);
++
++size_t get_tag_object_overhead(void);
++
++void get_blackey_conf(const struct blackey_conf *blackey_conf,
++                    u32 *real_len, u32 *load_param);
++
++void init_blackey_conf(struct blackey_conf *blackey_conf,
++                     size_t len, bool ccm, bool tk);
++
++int get_tagged_data(void *buffer, size_t buffer_size,
++                  void **data, u32 *data_size);
++
++#endif /* _TAG_OBJECT_H_ */
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0022-MLK-19801-2-crypto-caam-add-support-of-tagged-keys-i.patch b/target/linux/layerscape/patches-5.4/804-crypto-0022-MLK-19801-2-crypto-caam-add-support-of-tagged-keys-i.patch
new file mode 100644 (file)
index 0000000..915a2cd
--- /dev/null
@@ -0,0 +1,304 @@
+From df1b397d7c5e79052fa56d1b256ededcd301a27a Mon Sep 17 00:00:00 2001
+From: Franck LENORMAND <franck.lenormand@nxp.com>
+Date: Fri, 5 Oct 2018 16:41:54 +0200
+Subject: [PATCH] MLK-19801-2 crypto: caam - add support of tagged keys in
+ caamalg
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+A tagged key is a key which has been tagged with metadata
+using tag_object.h API.
+
+We add the support for these keys to caamalg.
+
+For each algo of caamalg which supports tagged keys , it is done by:
+ - Creating a modified version of the algo
+ - Registering the modified version
+ - When the modified transform is used, it gets
+   the load parameter of the key.
+
+Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
+(cherry picked from commit 88dee97d985890dbf37cafa7934c476d0ecfd0b3)
+(Vipul: Fixed merge conflicts)
+Conflicts:
+       drivers/crypto/caam/caamalg.c
+Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
+(cherry picked from commit 5adebac40a7a8065c074f4a69f4ad760c67233f5)
+
+-port from ablkcipher to current skcipher implementation
+-since in linux-imx true key_inline was always true: a. simplify
+the descriptors and b. use key_cmd_opt to differentiate b/w tk and non-tk
+cases
+-change commit headline prefix
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/Makefile       |  3 +-
+ drivers/crypto/caam/caamalg.c      | 91 +++++++++++++++++++++++++++++++++++++-
+ drivers/crypto/caam/caamalg_desc.c | 20 +++++++--
+ drivers/crypto/caam/desc_constr.h  |  4 ++
+ drivers/crypto/caam/tag_object.c   |  6 +--
+ drivers/crypto/caam/tag_object.h   |  6 +--
+ 6 files changed, 118 insertions(+), 12 deletions(-)
+
+--- a/drivers/crypto/caam/Makefile
++++ b/drivers/crypto/caam/Makefile
+@@ -15,6 +15,7 @@ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_
+ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC) += caamhash_desc.o
+ caam-y := ctrl.o
++caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API) += tag_object.o
+ caam_jr-y := jr.o key_gen.o
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o
+@@ -24,7 +25,7 @@ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM) += sm_store.o
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST) += sm_test.o
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO) += secvio.o
+-caam-jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API) += tag_object.o
++#caam-jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API) += tag_object.o
+ caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += qi.o
+ ifneq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI),)
+--- a/drivers/crypto/caam/caamalg.c
++++ b/drivers/crypto/caam/caamalg.c
+@@ -57,6 +57,10 @@
+ #include "key_gen.h"
+ #include "caamalg_desc.h"
++#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API
++#include "tag_object.h"
++#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API */
++
+ /*
+  * crypto alg
+  */
+@@ -83,6 +87,7 @@ struct caam_alg_entry {
+       bool rfc3686;
+       bool geniv;
+       bool nodkp;
++      bool support_tagged_key;
+ };
+ struct caam_aead_alg {
+@@ -739,6 +744,44 @@ static int skcipher_setkey(struct crypto
+       ctx->cdata.key_virt = key;
+       ctx->cdata.key_inline = true;
++#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API
++      /*
++       * Check if the key is not in plaintext format
++       */
++      if (alg->caam.support_tagged_key) {
++              struct tag_object_conf *tagged_key_conf;
++              int ret;
++
++              /* Get the configuration */
++              ret = get_tag_object_conf(ctx->cdata.key_virt,
++                                        ctx->cdata.keylen, &tagged_key_conf);
++              if (ret) {
++                      dev_err(jrdev,
++                              "caam algorithms can't process tagged key\n");
++                      return ret;
++              }
++
++              /* Only support black key */
++              if (!is_bk_conf(tagged_key_conf)) {
++                      dev_err(jrdev,
++                              "The tagged key provided is not a black key\n");
++                      return -EINVAL;
++              }
++
++              get_blackey_conf(&tagged_key_conf->conf.bk_conf,
++                               &ctx->cdata.key_real_len,
++                               &ctx->cdata.key_cmd_opt);
++
++              ret = get_tagged_data(ctx->cdata.key_virt, ctx->cdata.keylen,
++                                    &ctx->cdata.key_virt, &ctx->cdata.keylen);
++              if (ret) {
++                      dev_err(jrdev,
++                              "caam algorithms wrong data from tagged key\n");
++                      return ret;
++              }
++      }
++#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API */
++
+       /* skcipher_encrypt shared descriptor */
+       desc = ctx->sh_desc_enc;
+       cnstr_shdsc_skcipher_encap(desc, &ctx->cdata, ivsize, is_rfc3686,
+@@ -824,6 +867,14 @@ static int arc4_skcipher_setkey(struct c
+       return skcipher_setkey(skcipher, key, keylen, 0);
+ }
++#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API
++static int tk_skcipher_setkey(struct crypto_skcipher *skcipher,
++                              const u8 *key, unsigned int keylen)
++{
++      return skcipher_setkey(skcipher, key, keylen, 0);
++}
++#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API */
++
+ static int des_skcipher_setkey(struct crypto_skcipher *skcipher,
+                              const u8 *key, unsigned int keylen)
+ {
+@@ -1924,6 +1975,25 @@ static struct caam_skcipher_alg driver_a
+               },
+               .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+       },
++#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API
++      {
++              .skcipher = {
++                      .base = {
++                              .cra_name = "tk(cbc(aes))",
++                              .cra_driver_name = "tk-cbc-aes-caam",
++                              .cra_blocksize = AES_BLOCK_SIZE,
++                      },
++                      .setkey = tk_skcipher_setkey,
++                      .encrypt = skcipher_encrypt,
++                      .decrypt = skcipher_decrypt,
++                      .min_keysize = TAG_MIN_SIZE,
++                      .max_keysize = CAAM_MAX_KEY_SIZE,
++                      .ivsize = AES_BLOCK_SIZE,
++              },
++              .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++              .caam.support_tagged_key = true,
++      },
++#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API */
+       {
+               .skcipher = {
+                       .base = {
+@@ -2043,6 +2113,24 @@ static struct caam_skcipher_alg driver_a
+               },
+               .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_ECB,
+       },
++#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API
++      {
++              .skcipher = {
++                      .base = {
++                              .cra_name = "tk(ecb(aes))",
++                              .cra_driver_name = "tk-ecb-aes-caam",
++                              .cra_blocksize = AES_BLOCK_SIZE,
++                      },
++                      .setkey = tk_skcipher_setkey,
++                      .encrypt = skcipher_encrypt,
++                      .decrypt = skcipher_decrypt,
++                      .min_keysize = TAG_MIN_SIZE,
++                      .max_keysize = CAAM_MAX_KEY_SIZE,
++              },
++              .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_ECB,
++              .caam.support_tagged_key = true,
++      },
++#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API */
+       {
+               .skcipher = {
+                       .base = {
+@@ -3507,7 +3595,8 @@ static void caam_skcipher_alg_init(struc
+       struct skcipher_alg *alg = &t_alg->skcipher;
+       alg->base.cra_module = THIS_MODULE;
+-      alg->base.cra_priority = CAAM_CRA_PRIORITY;
++      alg->base.cra_priority =
++              t_alg->caam.support_tagged_key ? 1 : CAAM_CRA_PRIORITY;
+       alg->base.cra_ctxsize = sizeof(struct caam_ctx);
+       alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY;
+--- a/drivers/crypto/caam/caamalg_desc.c
++++ b/drivers/crypto/caam/caamalg_desc.c
+@@ -1386,8 +1386,14 @@ void cnstr_shdsc_skcipher_encap(u32 * co
+                                  JUMP_COND_SHRD);
+       /* Load class1 key only */
+-      append_key_as_imm(desc, cdata->key_virt, cdata->keylen,
+-                        cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG);
++      if (IS_ENABLED(CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API) &&
++          cdata->key_cmd_opt)
++              append_key_as_imm(desc, cdata->key_virt, cdata->keylen,
++                                cdata->key_real_len, CLASS_1 |
++                                KEY_DEST_CLASS_REG | cdata->key_cmd_opt);
++      else
++              append_key_as_imm(desc, cdata->key_virt, cdata->keylen,
++                                cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG);
+       /* Load nonce into CONTEXT1 reg */
+       if (is_rfc3686) {
+@@ -1458,8 +1464,14 @@ void cnstr_shdsc_skcipher_decap(u32 * co
+                                  JUMP_COND_SHRD);
+       /* Load class1 key only */
+-      append_key_as_imm(desc, cdata->key_virt, cdata->keylen,
+-                        cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG);
++      if (IS_ENABLED(CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API) &&
++          cdata->key_cmd_opt)
++              append_key_as_imm(desc, cdata->key_virt, cdata->keylen,
++                                cdata->key_real_len, CLASS_1 |
++                                KEY_DEST_CLASS_REG | cdata->key_cmd_opt);
++      else
++              append_key_as_imm(desc, cdata->key_virt, cdata->keylen,
++                                cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG);
+       /* Load nonce into CONTEXT1 reg */
+       if (is_rfc3686) {
+--- a/drivers/crypto/caam/desc_constr.h
++++ b/drivers/crypto/caam/desc_constr.h
+@@ -500,6 +500,8 @@ do { \
+  * @key_virt: virtual address where algorithm key resides
+  * @key_inline: true - key can be inlined in the descriptor; false - key is
+  *              referenced by the descriptor
++ * @key_real_len: size of the key to be loaded by the CAAM
++ * @key_cmd_opt: optional parameters for KEY command
+  */
+ struct alginfo {
+       u32 algtype;
+@@ -508,6 +510,8 @@ struct alginfo {
+       dma_addr_t key_dma;
+       const void *key_virt;
+       bool key_inline;
++      u32 key_real_len;
++      u32 key_cmd_opt;
+ };
+ /**
+--- a/drivers/crypto/caam/tag_object.c
++++ b/drivers/crypto/caam/tag_object.c
+@@ -128,7 +128,7 @@ EXPORT_SYMBOL(is_valid_tag_object_conf);
+  *
+  * Return: 0 if success, else error code
+  */
+-int get_tag_object_conf(void *buffer, size_t size,
++int get_tag_object_conf(const void *buffer, size_t size,
+                       struct tag_object_conf **tag_obj_conf)
+ {
+       bool is_valid;
+@@ -240,8 +240,8 @@ EXPORT_SYMBOL(get_blackey_conf);
+  *
+  * Return: 0 if success, else error code
+  */
+-int get_tagged_data(void *tagged_object, size_t tagged_object_size,
+-                  void **data, u32 *data_size)
++int get_tagged_data(const void *tagged_object, size_t tagged_object_size,
++                  const void **data, u32 *data_size)
+ {
+       struct tagged_object *tago =
+               (struct tagged_object *)tagged_object;
+--- a/drivers/crypto/caam/tag_object.h
++++ b/drivers/crypto/caam/tag_object.h
+@@ -80,7 +80,7 @@ bool is_valid_tag_object_conf(const stru
+ void init_tag_object_header(struct conf_header *conf_header,
+                           enum tag_type type);
+-int get_tag_object_conf(void *buffer, size_t buffer_size,
++int get_tag_object_conf(const void *buffer, size_t buffer_size,
+                       struct tag_object_conf **tag_obj_conf);
+ int set_tag_object_conf(const struct tag_object_conf *tag_obj_conf,
+@@ -94,7 +94,7 @@ void get_blackey_conf(const struct black
+ void init_blackey_conf(struct blackey_conf *blackey_conf,
+                      size_t len, bool ccm, bool tk);
+-int get_tagged_data(void *buffer, size_t buffer_size,
+-                  void **data, u32 *data_size);
++int get_tagged_data(const void *buffer, size_t buffer_size,
++                  const void **data, u32 *data_size);
+ #endif /* _TAG_OBJECT_H_ */
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0023-MLK-10036-crypto-caam-add-support-for-DSM-with-Mega-.patch b/target/linux/layerscape/patches-5.4/804-crypto-0023-MLK-10036-crypto-caam-add-support-for-DSM-with-Mega-.patch
new file mode 100644 (file)
index 0000000..883cd42
--- /dev/null
@@ -0,0 +1,81 @@
+From 1ffdfbcd42dbb87f2841e45c0719a3fbcb2fe926 Mon Sep 17 00:00:00 2001
+From: Victoria Milhoan <vicki.milhoan@freescale.com>
+Date: Thu, 18 Dec 2014 14:06:50 -0700
+Subject: [PATCH] MLK-10036 crypto: caam - add support for DSM with Mega/Fast
+ mix on
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch allows CAAM to be enabled as a wakeup source for the
+Mega/Fast mix domain. If CAAM is enabled as a wakeup source, it
+will continue to be powered on across Deep Sleep Mode (DSM). This
+allows CAAM to be functional after the system resumes from DSM.
+
+Signed-off-by: Victoria Milhoan <vicki.milhoan@freescale.com>
+(cherry picked from commit 290744e3b40a563319324e234fa5a65b49fd4d82)
+Signed-off-by: Dan Douglass <dan.douglass@freescale.com>
+Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
+(cherry picked from commit 0bf9c6f84f1d74d9e6d9384c4b11bbdf9301c94e)
+
+Changed commit headline prefix.
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/jr.c | 33 +++++++++++++++++++++++++++++++++
+ 1 file changed, 33 insertions(+)
+
+--- a/drivers/crypto/caam/jr.c
++++ b/drivers/crypto/caam/jr.c
+@@ -561,11 +561,41 @@ static int caam_jr_probe(struct platform
+       atomic_set(&jrpriv->tfm_count, 0);
++      device_init_wakeup(&pdev->dev, 1);
++      device_set_wakeup_enable(&pdev->dev, false);
++
+       register_algs(jrdev->parent);
+       return 0;
+ }
++#ifdef CONFIG_PM
++static int caam_jr_suspend(struct device *dev)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++      struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
++
++      if (device_may_wakeup(&pdev->dev))
++              enable_irq_wake(jrpriv->irq);
++
++      return 0;
++}
++
++static int caam_jr_resume(struct device *dev)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++      struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
++
++      if (device_may_wakeup(&pdev->dev))
++              disable_irq_wake(jrpriv->irq);
++
++      return 0;
++}
++
++static SIMPLE_DEV_PM_OPS(caam_jr_pm_ops, caam_jr_suspend,
++                       caam_jr_resume);
++#endif
++
+ static const struct of_device_id caam_jr_match[] = {
+       {
+               .compatible = "fsl,sec-v4.0-job-ring",
+@@ -581,6 +611,9 @@ static struct platform_driver caam_jr_dr
+       .driver = {
+               .name = "caam_jr",
+               .of_match_table = caam_jr_match,
++#ifdef CONFIG_PM
++              .pm = &caam_jr_pm_ops,
++#endif
+       },
+       .probe       = caam_jr_probe,
+       .remove      = caam_jr_remove,
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0024-MLK-19449-crypto-caam-Change-structure-type-represen.patch b/target/linux/layerscape/patches-5.4/804-crypto-0024-MLK-19449-crypto-caam-Change-structure-type-represen.patch
new file mode 100644 (file)
index 0000000..0fb3847
--- /dev/null
@@ -0,0 +1,45 @@
+From 18c56f8bced33c4d3d18dd10d2648def4291e6ea Mon Sep 17 00:00:00 2001
+From: Franck LENORMAND <franck.lenormand@nxp.com>
+Date: Tue, 5 Mar 2019 14:20:34 +0100
+Subject: [PATCH] MLK-19449 crypto: caam - Change structure type representing
+ DECO MID
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The structure partid is not suitable to represent the DECO MID register.
+
+This patch replace partid by masterid which is more appropriate.
+
+Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
+(cherry picked from commit 2d8dab735757dae8efb35bb0371970a7d27e98be)
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/regs.h | 8 +-------
+ 1 file changed, 1 insertion(+), 7 deletions(-)
+
+--- a/drivers/crypto/caam/regs.h
++++ b/drivers/crypto/caam/regs.h
+@@ -518,12 +518,6 @@ struct masterid {
+       u32 liodn_ls;   /* LIODN for non-sequence and seq access */
+ };
+-/* Partition ID for DMA configuration */
+-struct partid {
+-      u32 rsvd1;
+-      u32 pidr;       /* partition ID, DECO */
+-};
+-
+ /* RNGB test mode (replicated twice in some configurations) */
+ /* Padded out to 0x100 */
+ struct rngtst {
+@@ -637,7 +631,7 @@ struct caam_ctrl {
+       u32 deco_rsr;                   /* DECORSR - Deco Request Source */
+       u32 rsvd11;
+       u32 deco_rq;                    /* DECORR - DECO Request */
+-      struct partid deco_mid[5];      /* DECOxLIODNR - 1 per DECO */
++      struct masterid deco_mid[5];    /* DECOxLIODNR - 1 per DECO */
+       u32 rsvd5[22];
+       /* DECO Availability/Reset Section                      120-3ff */
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0025-crypto-caam-qi2-add-unused-dpseci-API.patch b/target/linux/layerscape/patches-5.4/804-crypto-0025-crypto-caam-qi2-add-unused-dpseci-API.patch
new file mode 100644 (file)
index 0000000..269d723
--- /dev/null
@@ -0,0 +1,561 @@
+From f79915995e8fe4f2d11043fe4cab4b579e5cf1de Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Horia=20Geant=C4=83?= <horia.geanta@nxp.com>
+Date: Wed, 10 Oct 2018 16:06:11 +0300
+Subject: [PATCH] crypto: caam/qi2 - add (unused) dpseci API
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+During driver upstreaming all unused dpseci API was trimmed down.
+Add the API back to be in sync with files provided by MC f/w release.
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/dpseci.c     | 330 ++++++++++++++++++++++++++++++++++++++-
+ drivers/crypto/caam/dpseci.h     |  50 ++++++
+ drivers/crypto/caam/dpseci_cmd.h |  59 +++++++
+ 3 files changed, 437 insertions(+), 2 deletions(-)
+
+--- a/drivers/crypto/caam/dpseci.c
++++ b/drivers/crypto/caam/dpseci.c
+@@ -16,8 +16,8 @@
+  * @token:    Returned token; use in subsequent API calls
+  *
+  * This function can be used to open a control session for an already created
+- * object; an object may have been declared statically in the DPL
+- * or created dynamically.
++ * object; an object may have been declared in the DPL or by calling the
++ * dpseci_create() function.
+  * This function returns a unique authentication token, associated with the
+  * specific object ID and the specific MC portal; this token must be used in all
+  * subsequent commands for this specific object.
+@@ -67,6 +67,85 @@ int dpseci_close(struct fsl_mc_io *mc_io
+ }
+ /**
++ * dpseci_create() - Create the DPSECI object
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @dprc_token:       Parent container token; '0' for default container
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @cfg:      Configuration structure
++ * @obj_id:   returned object id
++ *
++ * Create the DPSECI object, allocate required resources and perform required
++ * initialization.
++ *
++ * The object can be created either by declaring it in the DPL file, or by
++ * calling this function.
++ *
++ * The function accepts an authentication token of a parent container that this
++ * object should be assigned to. The token can be '0' so the object will be
++ * assigned to the default container.
++ * The newly created object can be opened with the returned object id and using
++ * the container's associated tokens and MC portals.
++ *
++ * Return:    '0' on success, error code otherwise
++ */
++int dpseci_create(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags,
++                const struct dpseci_cfg *cfg, u32 *obj_id)
++{
++      struct fsl_mc_command cmd = { 0 };
++      struct dpseci_cmd_create *cmd_params;
++      int i, err;
++
++      cmd.header = mc_encode_cmd_header(DPSECI_CMDID_CREATE,
++                                        cmd_flags,
++                                        dprc_token);
++      cmd_params = (struct dpseci_cmd_create *)cmd.params;
++      for (i = 0; i < 8; i++)
++              cmd_params->priorities[i] = cfg->priorities[i];
++      for (i = 0; i < 8; i++)
++              cmd_params->priorities2[i] = cfg->priorities[8 + i];
++      cmd_params->num_tx_queues = cfg->num_tx_queues;
++      cmd_params->num_rx_queues = cfg->num_rx_queues;
++      cmd_params->options = cpu_to_le32(cfg->options);
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      *obj_id = mc_cmd_read_object_id(&cmd);
++
++      return 0;
++}
++
++/**
++ * dpseci_destroy() - Destroy the DPSECI object and release all its resources
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @dprc_token: Parent container token; '0' for default container
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @object_id:        The object id; it must be a valid id within the container that
++ *            created this object
++ *
++ * The function accepts the authentication token of the parent container that
++ * created the object (not the one that currently owns the object). The object
++ * is searched within parent using the provided 'object_id'.
++ * All tokens to the object must be closed before calling destroy.
++ *
++ * Return:    '0' on success, error code otherwise
++ */
++int dpseci_destroy(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags,
++                 u32 object_id)
++{
++      struct fsl_mc_command cmd = { 0 };
++      struct dpseci_cmd_destroy *cmd_params;
++
++      cmd.header = mc_encode_cmd_header(DPSECI_CMDID_DESTROY,
++                                        cmd_flags,
++                                        dprc_token);
++      cmd_params = (struct dpseci_cmd_destroy *)cmd.params;
++      cmd_params->object_id = cpu_to_le32(object_id);
++
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
+  * dpseci_enable() - Enable the DPSECI, allow sending and receiving frames
+  * @mc_io:    Pointer to MC portal's I/O object
+  * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
+@@ -133,6 +212,217 @@ int dpseci_is_enabled(struct fsl_mc_io *
+ }
+ /**
++ * dpseci_reset() - Reset the DPSECI, returns the object to initial state.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPSECI object
++ *
++ * Return:    '0' on success, error code otherwise
++ */
++int dpseci_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
++{
++      struct fsl_mc_command cmd = { 0 };
++
++      cmd.header = mc_encode_cmd_header(DPSECI_CMDID_RESET,
++                                        cmd_flags,
++                                        token);
++
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpseci_get_irq_enable() - Get overall interrupt state
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPSECI object
++ * @irq_index:        The interrupt index to configure
++ * @en:               Returned Interrupt state - enable = 1, disable = 0
++ *
++ * Return:    '0' on success, error code otherwise
++ */
++int dpseci_get_irq_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                        u8 irq_index, u8 *en)
++{
++      struct fsl_mc_command cmd = { 0 };
++      struct dpseci_cmd_irq_enable *cmd_params;
++      struct dpseci_rsp_get_irq_enable *rsp_params;
++      int err;
++
++      cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_IRQ_ENABLE,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpseci_cmd_irq_enable *)cmd.params;
++      cmd_params->irq_index = irq_index;
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      rsp_params = (struct dpseci_rsp_get_irq_enable *)cmd.params;
++      *en = rsp_params->enable_state;
++
++      return 0;
++}
++
++/**
++ * dpseci_set_irq_enable() - Set overall interrupt state.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPSECI object
++ * @irq_index:        The interrupt index to configure
++ * @en:               Interrupt state - enable = 1, disable = 0
++ *
++ * Allows GPP software to control when interrupts are generated.
++ * Each interrupt can have up to 32 causes. The enable/disable control's the
++ * overall interrupt state. If the interrupt is disabled no causes will cause
++ * an interrupt.
++ *
++ * Return:    '0' on success, error code otherwise
++ */
++int dpseci_set_irq_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                        u8 irq_index, u8 en)
++{
++      struct fsl_mc_command cmd = { 0 };
++      struct dpseci_cmd_irq_enable *cmd_params;
++
++      cmd.header = mc_encode_cmd_header(DPSECI_CMDID_SET_IRQ_ENABLE,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpseci_cmd_irq_enable *)cmd.params;
++      cmd_params->irq_index = irq_index;
++      cmd_params->enable_state = en;
++
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpseci_get_irq_mask() - Get interrupt mask.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPSECI object
++ * @irq_index:        The interrupt index to configure
++ * @mask:     Returned event mask to trigger interrupt
++ *
++ * Every interrupt can have up to 32 causes and the interrupt model supports
++ * masking/unmasking each cause independently.
++ *
++ * Return:    '0' on success, error code otherwise
++ */
++int dpseci_get_irq_mask(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                      u8 irq_index, u32 *mask)
++{
++      struct fsl_mc_command cmd = { 0 };
++      struct dpseci_cmd_irq_mask *cmd_params;
++      int err;
++
++      cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_IRQ_MASK,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpseci_cmd_irq_mask *)cmd.params;
++      cmd_params->irq_index = irq_index;
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      *mask = le32_to_cpu(cmd_params->mask);
++
++      return 0;
++}
++
++/**
++ * dpseci_set_irq_mask() - Set interrupt mask.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPSECI object
++ * @irq_index:        The interrupt index to configure
++ * @mask:     event mask to trigger interrupt;
++ *            each bit:
++ *                    0 = ignore event
++ *                    1 = consider event for asserting IRQ
++ *
++ * Every interrupt can have up to 32 causes and the interrupt model supports
++ * masking/unmasking each cause independently
++ *
++ * Return:    '0' on success, error code otherwise
++ */
++int dpseci_set_irq_mask(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                      u8 irq_index, u32 mask)
++{
++      struct fsl_mc_command cmd = { 0 };
++      struct dpseci_cmd_irq_mask *cmd_params;
++
++      cmd.header = mc_encode_cmd_header(DPSECI_CMDID_SET_IRQ_MASK,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpseci_cmd_irq_mask *)cmd.params;
++      cmd_params->mask = cpu_to_le32(mask);
++      cmd_params->irq_index = irq_index;
++
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpseci_get_irq_status() - Get the current status of any pending interrupts
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPSECI object
++ * @irq_index:        The interrupt index to configure
++ * @status:   Returned interrupts status - one bit per cause:
++ *                    0 = no interrupt pending
++ *                    1 = interrupt pending
++ *
++ * Return:    '0' on success, error code otherwise
++ */
++int dpseci_get_irq_status(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                        u8 irq_index, u32 *status)
++{
++      struct fsl_mc_command cmd = { 0 };
++      struct dpseci_cmd_irq_status *cmd_params;
++      int err;
++
++      cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_IRQ_STATUS,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpseci_cmd_irq_status *)cmd.params;
++      cmd_params->status = cpu_to_le32(*status);
++      cmd_params->irq_index = irq_index;
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      *status = le32_to_cpu(cmd_params->status);
++
++      return 0;
++}
++
++/**
++ * dpseci_clear_irq_status() - Clear a pending interrupt's status
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPSECI object
++ * @irq_index:        The interrupt index to configure
++ * @status:   bits to clear (W1C) - one bit per cause:
++ *                    0 = don't change
++ *                    1 = clear status bit
++ *
++ * Return:    '0' on success, error code otherwise
++ */
++int dpseci_clear_irq_status(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                          u8 irq_index, u32 status)
++{
++      struct fsl_mc_command cmd = { 0 };
++      struct dpseci_cmd_irq_status *cmd_params;
++
++      cmd.header = mc_encode_cmd_header(DPSECI_CMDID_CLEAR_IRQ_STATUS,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpseci_cmd_irq_status *)cmd.params;
++      cmd_params->status = cpu_to_le32(status);
++      cmd_params->irq_index = irq_index;
++
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
+  * dpseci_get_attributes() - Retrieve DPSECI attributes
+  * @mc_io:    Pointer to MC portal's I/O object
+  * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
+@@ -320,6 +610,42 @@ int dpseci_get_sec_attr(struct fsl_mc_io
+       return 0;
+ }
++
++/**
++ * dpseci_get_sec_counters() - Retrieve SEC accelerator counters
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPSECI object
++ * @counters: Returned SEC counters
++ *
++ * Return:    '0' on success, error code otherwise
++ */
++int dpseci_get_sec_counters(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                          struct dpseci_sec_counters *counters)
++{
++      struct fsl_mc_command cmd = { 0 };
++      struct dpseci_rsp_get_sec_counters *rsp_params;
++      int err;
++
++      cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_SEC_COUNTERS,
++                                        cmd_flags,
++                                        token);
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      rsp_params = (struct dpseci_rsp_get_sec_counters *)cmd.params;
++      counters->dequeued_requests =
++              le64_to_cpu(rsp_params->dequeued_requests);
++      counters->ob_enc_requests = le64_to_cpu(rsp_params->ob_enc_requests);
++      counters->ib_dec_requests = le64_to_cpu(rsp_params->ib_dec_requests);
++      counters->ob_enc_bytes = le64_to_cpu(rsp_params->ob_enc_bytes);
++      counters->ob_prot_bytes = le64_to_cpu(rsp_params->ob_prot_bytes);
++      counters->ib_dec_bytes = le64_to_cpu(rsp_params->ib_dec_bytes);
++      counters->ib_valid_bytes = le64_to_cpu(rsp_params->ib_valid_bytes);
++
++      return 0;
++}
+ /**
+  * dpseci_get_api_version() - Get Data Path SEC Interface API version
+--- a/drivers/crypto/caam/dpseci.h
++++ b/drivers/crypto/caam/dpseci.h
+@@ -55,6 +55,12 @@ struct dpseci_cfg {
+       u8 priorities[DPSECI_MAX_QUEUE_NUM];
+ };
++int dpseci_create(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags,
++                const struct dpseci_cfg *cfg, u32 *obj_id);
++
++int dpseci_destroy(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags,
++                 u32 object_id);
++
+ int dpseci_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
+ int dpseci_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
+@@ -62,6 +68,26 @@ int dpseci_disable(struct fsl_mc_io *mc_
+ int dpseci_is_enabled(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+                     int *en);
++int dpseci_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
++
++int dpseci_get_irq_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                        u8 irq_index, u8 *en);
++
++int dpseci_set_irq_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                        u8 irq_index, u8 en);
++
++int dpseci_get_irq_mask(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                      u8 irq_index, u32 *mask);
++
++int dpseci_set_irq_mask(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                      u8 irq_index, u32 mask);
++
++int dpseci_get_irq_status(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                        u8 irq_index, u32 *status);
++
++int dpseci_clear_irq_status(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                          u8 irq_index, u32 status);
++
+ /**
+  * struct dpseci_attr - Structure representing DPSECI attributes
+  * @id: DPSECI object ID
+@@ -248,6 +274,30 @@ struct dpseci_sec_attr {
+ int dpseci_get_sec_attr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+                       struct dpseci_sec_attr *attr);
++/**
++ * struct dpseci_sec_counters - Structure representing global SEC counters and
++ *                            not per dpseci counters
++ * @dequeued_requests:        Number of Requests Dequeued
++ * @ob_enc_requests:  Number of Outbound Encrypt Requests
++ * @ib_dec_requests:  Number of Inbound Decrypt Requests
++ * @ob_enc_bytes:     Number of Outbound Bytes Encrypted
++ * @ob_prot_bytes:    Number of Outbound Bytes Protected
++ * @ib_dec_bytes:     Number of Inbound Bytes Decrypted
++ * @ib_valid_bytes:   Number of Inbound Bytes Validated
++ */
++struct dpseci_sec_counters {
++      u64 dequeued_requests;
++      u64 ob_enc_requests;
++      u64 ib_dec_requests;
++      u64 ob_enc_bytes;
++      u64 ob_prot_bytes;
++      u64 ib_dec_bytes;
++      u64 ib_valid_bytes;
++};
++
++int dpseci_get_sec_counters(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                          struct dpseci_sec_counters *counters);
++
+ int dpseci_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags,
+                          u16 *major_ver, u16 *minor_ver);
+--- a/drivers/crypto/caam/dpseci_cmd.h
++++ b/drivers/crypto/caam/dpseci_cmd.h
+@@ -17,6 +17,7 @@
+ /* Command versioning */
+ #define DPSECI_CMD_BASE_VERSION               1
+ #define DPSECI_CMD_BASE_VERSION_V2    2
++#define DPSECI_CMD_BASE_VERSION_V3    3
+ #define DPSECI_CMD_ID_OFFSET          4
+ #define DPSECI_CMD_V1(id)     (((id) << DPSECI_CMD_ID_OFFSET) | \
+@@ -25,20 +26,34 @@
+ #define DPSECI_CMD_V2(id)     (((id) << DPSECI_CMD_ID_OFFSET) | \
+                                DPSECI_CMD_BASE_VERSION_V2)
++#define DPSECI_CMD_V3(id)     (((id) << DPSECI_CMD_ID_OFFSET) | \
++                               DPSECI_CMD_BASE_VERSION_V3)
++
+ /* Command IDs */
+ #define DPSECI_CMDID_CLOSE                            DPSECI_CMD_V1(0x800)
+ #define DPSECI_CMDID_OPEN                             DPSECI_CMD_V1(0x809)
++#define DPSECI_CMDID_CREATE                           DPSECI_CMD_V3(0x909)
++#define DPSECI_CMDID_DESTROY                          DPSECI_CMD_V1(0x989)
+ #define DPSECI_CMDID_GET_API_VERSION                  DPSECI_CMD_V1(0xa09)
+ #define DPSECI_CMDID_ENABLE                           DPSECI_CMD_V1(0x002)
+ #define DPSECI_CMDID_DISABLE                          DPSECI_CMD_V1(0x003)
+ #define DPSECI_CMDID_GET_ATTR                         DPSECI_CMD_V1(0x004)
++#define DPSECI_CMDID_RESET                            DPSECI_CMD_V1(0x005)
+ #define DPSECI_CMDID_IS_ENABLED                               DPSECI_CMD_V1(0x006)
++#define DPSECI_CMDID_SET_IRQ_ENABLE                   DPSECI_CMD_V1(0x012)
++#define DPSECI_CMDID_GET_IRQ_ENABLE                   DPSECI_CMD_V1(0x013)
++#define DPSECI_CMDID_SET_IRQ_MASK                     DPSECI_CMD_V1(0x014)
++#define DPSECI_CMDID_GET_IRQ_MASK                     DPSECI_CMD_V1(0x015)
++#define DPSECI_CMDID_GET_IRQ_STATUS                   DPSECI_CMD_V1(0x016)
++#define DPSECI_CMDID_CLEAR_IRQ_STATUS                 DPSECI_CMD_V1(0x017)
++
+ #define DPSECI_CMDID_SET_RX_QUEUE                     DPSECI_CMD_V1(0x194)
+ #define DPSECI_CMDID_GET_RX_QUEUE                     DPSECI_CMD_V1(0x196)
+ #define DPSECI_CMDID_GET_TX_QUEUE                     DPSECI_CMD_V1(0x197)
+ #define DPSECI_CMDID_GET_SEC_ATTR                     DPSECI_CMD_V2(0x198)
++#define DPSECI_CMDID_GET_SEC_COUNTERS                 DPSECI_CMD_V1(0x199)
+ #define DPSECI_CMDID_SET_CONGESTION_NOTIFICATION      DPSECI_CMD_V1(0x170)
+ #define DPSECI_CMDID_GET_CONGESTION_NOTIFICATION      DPSECI_CMD_V1(0x171)
+@@ -57,6 +72,20 @@ struct dpseci_cmd_open {
+       __le32 dpseci_id;
+ };
++struct dpseci_cmd_create {
++      u8 priorities[8];
++      u8 num_tx_queues;
++      u8 num_rx_queues;
++      u8 pad0[6];
++      __le32 options;
++      __le32 pad1;
++      u8 priorities2[8];
++};
++
++struct dpseci_cmd_destroy {
++      __le32 object_id;
++};
++
+ #define DPSECI_ENABLE_SHIFT   0
+ #define DPSECI_ENABLE_SIZE    1
+@@ -64,6 +93,26 @@ struct dpseci_rsp_is_enabled {
+       u8 is_enabled;
+ };
++struct dpseci_cmd_irq_enable {
++      u8 enable_state;
++      u8 pad[3];
++      u8 irq_index;
++};
++
++struct dpseci_rsp_get_irq_enable {
++      u8 enable_state;
++};
++
++struct dpseci_cmd_irq_mask {
++      __le32 mask;
++      u8 irq_index;
++};
++
++struct dpseci_cmd_irq_status {
++      __le32 status;
++      u8 irq_index;
++};
++
+ struct dpseci_rsp_get_attributes {
+       __le32 id;
+       __le32 pad0;
+@@ -125,6 +174,16 @@ struct dpseci_rsp_get_sec_attr {
+       u8 ptha_acc_num;
+ };
++struct dpseci_rsp_get_sec_counters {
++      __le64 dequeued_requests;
++      __le64 ob_enc_requests;
++      __le64 ib_dec_requests;
++      __le64 ob_enc_bytes;
++      __le64 ob_prot_bytes;
++      __le64 ib_dec_bytes;
++      __le64 ib_valid_bytes;
++};
++
+ struct dpseci_rsp_get_api_version {
+       __le16 major;
+       __le16 minor;
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0026-crypto-caam-qi2-add-OPR-Order-Preservation-support.patch b/target/linux/layerscape/patches-5.4/804-crypto-0026-crypto-caam-qi2-add-OPR-Order-Preservation-support.patch
new file mode 100644 (file)
index 0000000..c6975ad
--- /dev/null
@@ -0,0 +1,246 @@
+From 70eb620ed6d38e171e5619313e99d31688d25010 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Horia=20Geant=C4=83?= <horia.geanta@nxp.com>
+Date: Wed, 10 Oct 2018 16:07:50 +0300
+Subject: [PATCH] crypto: caam/qi2 - add OPR (Order Preservation) support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+During driver upstreaming OPR was removed due to lacking users.
+Add OPR back, since in LSDK / LSDK-based ADKs there is at least
+one user (ASF / VortiQa IPsec).
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/dpseci.c     | 85 ++++++++++++++++++++++++++++++++++++++++
+ drivers/crypto/caam/dpseci.h     | 26 +++++++++++-
+ drivers/crypto/caam/dpseci_cmd.h | 51 ++++++++++++++++++++++++
+ 3 files changed, 160 insertions(+), 2 deletions(-)
+
+--- a/drivers/crypto/caam/dpseci.c
++++ b/drivers/crypto/caam/dpseci.c
+@@ -5,6 +5,7 @@
+  */
+ #include <linux/fsl/mc.h>
++#include <soc/fsl/dpaa2-io.h>
+ #include "dpseci.h"
+ #include "dpseci_cmd.h"
+@@ -675,6 +676,90 @@ int dpseci_get_api_version(struct fsl_mc
+       return 0;
+ }
++
++/**
++ * dpseci_set_opr() - Set Order Restoration configuration
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPSECI object
++ * @index:    The queue index
++ * @options:  Configuration mode options; can be OPR_OPT_CREATE or
++ *            OPR_OPT_RETIRE
++ * @cfg:      Configuration options for the OPR
++ *
++ * Return:    '0' on success, error code otherwise
++ */
++int dpseci_set_opr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u8 index,
++                 u8 options, struct opr_cfg *cfg)
++{
++      struct fsl_mc_command cmd = { 0 };
++      struct dpseci_cmd_opr *cmd_params;
++
++      cmd.header = mc_encode_cmd_header(
++                      DPSECI_CMDID_SET_OPR,
++                      cmd_flags,
++                      token);
++      cmd_params = (struct dpseci_cmd_opr *)cmd.params;
++      cmd_params->index = index;
++      cmd_params->options = options;
++      cmd_params->oloe = cfg->oloe;
++      cmd_params->oeane = cfg->oeane;
++      cmd_params->olws = cfg->olws;
++      cmd_params->oa = cfg->oa;
++      cmd_params->oprrws = cfg->oprrws;
++
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpseci_get_opr() - Retrieve Order Restoration config and query
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPSECI object
++ * @index:    The queue index
++ * @cfg:      Returned OPR configuration
++ * @qry:      Returned OPR query
++ *
++ * Return:    '0' on success, error code otherwise
++ */
++int dpseci_get_opr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u8 index,
++                 struct opr_cfg *cfg, struct opr_qry *qry)
++{
++      struct fsl_mc_command cmd = { 0 };
++      struct dpseci_cmd_opr *cmd_params;
++      struct dpseci_rsp_get_opr *rsp_params;
++      int err;
++
++      cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_OPR,
++                                        cmd_flags,
++                                        token);
++      cmd_params = (struct dpseci_cmd_opr *)cmd.params;
++      cmd_params->index = index;
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      rsp_params = (struct dpseci_rsp_get_opr *)cmd.params;
++      qry->rip = dpseci_get_field(rsp_params->flags, OPR_RIP);
++      qry->enable = dpseci_get_field(rsp_params->flags, OPR_ENABLE);
++      cfg->oloe = rsp_params->oloe;
++      cfg->oeane = rsp_params->oeane;
++      cfg->olws = rsp_params->olws;
++      cfg->oa = rsp_params->oa;
++      cfg->oprrws = rsp_params->oprrws;
++      qry->nesn = le16_to_cpu(rsp_params->nesn);
++      qry->ndsn = le16_to_cpu(rsp_params->ndsn);
++      qry->ea_tseq = le16_to_cpu(rsp_params->ea_tseq);
++      qry->tseq_nlis = dpseci_get_field(rsp_params->tseq_nlis, OPR_TSEQ_NLIS);
++      qry->ea_hseq = le16_to_cpu(rsp_params->ea_hseq);
++      qry->hseq_nlis = dpseci_get_field(rsp_params->hseq_nlis, OPR_HSEQ_NLIS);
++      qry->ea_hptr = le16_to_cpu(rsp_params->ea_hptr);
++      qry->ea_tptr = le16_to_cpu(rsp_params->ea_tptr);
++      qry->opr_vid = le16_to_cpu(rsp_params->opr_vid);
++      qry->opr_id = le16_to_cpu(rsp_params->opr_id);
++
++      return 0;
++}
+ /**
+  * dpseci_set_congestion_notification() - Set congestion group
+--- a/drivers/crypto/caam/dpseci.h
++++ b/drivers/crypto/caam/dpseci.h
+@@ -12,6 +12,8 @@
+  */
+ struct fsl_mc_io;
++struct opr_cfg;
++struct opr_qry;
+ /**
+  * General DPSECI macros
+@@ -38,9 +40,21 @@ int dpseci_close(struct fsl_mc_io *mc_io
+ #define DPSECI_OPT_HAS_CG             0x000020
+ /**
++ * Enable the Order Restoration support
++ */
++#define DPSECI_OPT_HAS_OPR            0x000040
++
++/**
++ * Order Point Records are shared for the entire DPSECI
++ */
++#define DPSECI_OPT_OPR_SHARED         0x000080
++
++/**
+  * struct dpseci_cfg - Structure representing DPSECI configuration
+- * @options: Any combination of the following flags:
++ * @options: Any combination of the following options:
+  *            DPSECI_OPT_HAS_CG
++ *            DPSECI_OPT_HAS_OPR
++ *            DPSECI_OPT_OPR_SHARED
+  * @num_tx_queues: num of queues towards the SEC
+  * @num_rx_queues: num of queues back from the SEC
+  * @priorities: Priorities for the SEC hardware processing;
+@@ -93,8 +107,10 @@ int dpseci_clear_irq_status(struct fsl_m
+  * @id: DPSECI object ID
+  * @num_tx_queues: number of queues towards the SEC
+  * @num_rx_queues: number of queues back from the SEC
+- * @options: any combination of the following flags:
++ * @options: any combination of the following options:
+  *            DPSECI_OPT_HAS_CG
++ *            DPSECI_OPT_HAS_OPR
++ *            DPSECI_OPT_OPR_SHARED
+  */
+ struct dpseci_attr {
+       int id;
+@@ -301,6 +317,12 @@ int dpseci_get_sec_counters(struct fsl_m
+ int dpseci_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags,
+                          u16 *major_ver, u16 *minor_ver);
++int dpseci_set_opr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u8 index,
++                 u8 options, struct opr_cfg *cfg);
++
++int dpseci_get_opr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u8 index,
++                 struct opr_cfg *cfg, struct opr_qry *qry);
++
+ /**
+  * enum dpseci_congestion_unit - DPSECI congestion units
+  * @DPSECI_CONGESTION_UNIT_BYTES: bytes units
+--- a/drivers/crypto/caam/dpseci_cmd.h
++++ b/drivers/crypto/caam/dpseci_cmd.h
+@@ -54,6 +54,8 @@
+ #define DPSECI_CMDID_GET_TX_QUEUE                     DPSECI_CMD_V1(0x197)
+ #define DPSECI_CMDID_GET_SEC_ATTR                     DPSECI_CMD_V2(0x198)
+ #define DPSECI_CMDID_GET_SEC_COUNTERS                 DPSECI_CMD_V1(0x199)
++#define DPSECI_CMDID_SET_OPR                          DPSECI_CMD_V1(0x19A)
++#define DPSECI_CMDID_GET_OPR                          DPSECI_CMD_V1(0x19B)
+ #define DPSECI_CMDID_SET_CONGESTION_NOTIFICATION      DPSECI_CMD_V1(0x170)
+ #define DPSECI_CMDID_GET_CONGESTION_NOTIFICATION      DPSECI_CMD_V1(0x171)
+@@ -189,6 +191,55 @@ struct dpseci_rsp_get_api_version {
+       __le16 minor;
+ };
++struct dpseci_cmd_opr {
++      __le16 pad;
++      u8 index;
++      u8 options;
++      u8 pad1[7];
++      u8 oloe;
++      u8 oeane;
++      u8 olws;
++      u8 oa;
++      u8 oprrws;
++};
++
++#define DPSECI_OPR_RIP_SHIFT          0
++#define DPSECI_OPR_RIP_SIZE           1
++#define DPSECI_OPR_ENABLE_SHIFT               1
++#define DPSECI_OPR_ENABLE_SIZE                1
++#define DPSECI_OPR_TSEQ_NLIS_SHIFT    0
++#define DPSECI_OPR_TSEQ_NLIS_SIZE     1
++#define DPSECI_OPR_HSEQ_NLIS_SHIFT    0
++#define DPSECI_OPR_HSEQ_NLIS_SIZE     1
++
++struct dpseci_rsp_get_opr {
++      __le64 pad;
++      u8 flags;
++      u8 pad0[2];
++      u8 oloe;
++      u8 oeane;
++      u8 olws;
++      u8 oa;
++      u8 oprrws;
++      __le16 nesn;
++      __le16 pad1;
++      __le16 ndsn;
++      __le16 pad2;
++      __le16 ea_tseq;
++      u8 tseq_nlis;
++      u8 pad3;
++      __le16 ea_hseq;
++      u8 hseq_nlis;
++      u8 pad4;
++      __le16 ea_hptr;
++      __le16 pad5;
++      __le16 ea_tptr;
++      __le16 pad6;
++      __le16 opr_vid;
++      __le16 pad7;
++      __le16 opr_id;
++};
++
+ #define DPSECI_CGN_DEST_TYPE_SHIFT    0
+ #define DPSECI_CGN_DEST_TYPE_SIZE     4
+ #define DPSECI_CGN_UNITS_SHIFT                4
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0027-crypto-caam-add-support-for-MOVEB-command.patch b/target/linux/layerscape/patches-5.4/804-crypto-0027-crypto-caam-add-support-for-MOVEB-command.patch
new file mode 100644 (file)
index 0000000..551be94
--- /dev/null
@@ -0,0 +1,38 @@
+From fafd87f0b6bc388b811e342ff83c88212041b119 Mon Sep 17 00:00:00 2001
+From: Radu Alexe <radu.alexe@nxp.com>
+Date: Tue, 6 Jun 2017 12:23:56 +0300
+Subject: [PATCH] crypto: caam - add support for MOVEB command
+
+CHAs of SEC work natively in BE mode. When moving
+data to the alignment blocks, swapping is needed
+for LE platforms. This is done by means of the MOVEB
+command. This patch adds support
+to DCL for this command.
+
+Signed-off-by: Alex Porosanu <alexandru.porosanu@freescale.com>
+Signed-off-by: Radu Alexe <radu.alexe@nxp.com>
+---
+ drivers/crypto/caam/desc.h        | 1 +
+ drivers/crypto/caam/desc_constr.h | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/drivers/crypto/caam/desc.h
++++ b/drivers/crypto/caam/desc.h
+@@ -43,6 +43,7 @@
+ #define CMD_SEQ_LOAD          (0x03 << CMD_SHIFT)
+ #define CMD_FIFO_LOAD         (0x04 << CMD_SHIFT)
+ #define CMD_SEQ_FIFO_LOAD     (0x05 << CMD_SHIFT)
++#define CMD_MOVEB             (0x07 << CMD_SHIFT)
+ #define CMD_STORE             (0x0a << CMD_SHIFT)
+ #define CMD_SEQ_STORE         (0x0b << CMD_SHIFT)
+ #define CMD_FIFO_STORE                (0x0c << CMD_SHIFT)
+--- a/drivers/crypto/caam/desc_constr.h
++++ b/drivers/crypto/caam/desc_constr.h
+@@ -240,6 +240,7 @@ static inline u32 *append_##cmd(u32 * co
+ APPEND_CMD_RET(jump, JUMP)
+ APPEND_CMD_RET(move, MOVE)
+ APPEND_CMD_RET(move_len, MOVE_LEN)
++APPEND_CMD_RET(moveb, MOVEB)
+ static inline void set_jump_tgt_here(u32 * const desc, u32 *jump_cmd)
+ {
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0028-crypto-caam-qi-add-support-for-TLS-1.0-record.patch b/target/linux/layerscape/patches-5.4/804-crypto-0028-crypto-caam-qi-add-support-for-TLS-1.0-record.patch
new file mode 100644 (file)
index 0000000..162f89a
--- /dev/null
@@ -0,0 +1,1048 @@
+From 47824cc9417946b49b80e88c74ab5ee69eacc2a7 Mon Sep 17 00:00:00 2001
+From: Radu Alexe <radu.alexe@nxp.com>
+Date: Thu, 25 May 2017 15:51:50 +0300
+Subject: [PATCH] crypto: caam/qi - add support for TLS 1.0 record
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+TLS 1.0 descriptors run on SEC 4.x or higher.
+For now, only tls10(hmac(sha1),cbc(aes)) algorithm
+is registered by the driver.
+
+Known limitations:
+ - when src == dst - there should be no element in the src scatterlist array
+   that contains both associated data and message data.
+ - when src != dst - associated data is not copied from source into
+   destination.
+ - for decryption when src != dst the size of the destination should be
+   large enough so that the buffer may contain the decrypted authenc and
+   padded data.
+
+Signed-off-by: Tudor Ambarus <tudor-dan.ambarus@nxp.com>
+Signed-off-by: Cristian Stoica <cristian.stoica@nxp.com>
+Signed-off-by: Alex Porosanu <alexandru.porosanu@nxp.com>
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Radu Alexe <radu.alexe@nxp.com>
+---
+ drivers/crypto/caam/caamalg_desc.c | 414 ++++++++++++++++++++++++++++++++
+ drivers/crypto/caam/caamalg_desc.h |  13 +
+ drivers/crypto/caam/caamalg_qi.c   | 478 +++++++++++++++++++++++++++++++++++++
+ drivers/crypto/caam/desc.h         |  27 +++
+ 4 files changed, 932 insertions(+)
+
+--- a/drivers/crypto/caam/caamalg_desc.c
++++ b/drivers/crypto/caam/caamalg_desc.c
+@@ -622,6 +622,420 @@ copy_iv:
+ EXPORT_SYMBOL(cnstr_shdsc_aead_givencap);
+ /**
++ * cnstr_shdsc_tls_encap - tls encapsulation shared descriptor
++ * @desc: pointer to buffer used for descriptor construction
++ * @cdata: pointer to block cipher transform definitions
++ *         Valid algorithm values - one of OP_ALG_ALGSEL_AES ANDed
++ *         with OP_ALG_AAI_CBC
++ * @adata: pointer to authentication transform definitions.
++ *         A split key is required for SEC Era < 6; the size of the split key
++ *         is specified in this case. Valid algorithm values OP_ALG_ALGSEL_SHA1
++ *         ANDed with OP_ALG_AAI_HMAC_PRECOMP.
++ * @assoclen: associated data length
++ * @ivsize: initialization vector size
++ * @authsize: authentication data size
++ * @blocksize: block cipher size
++ * @era: SEC Era
++ */
++void cnstr_shdsc_tls_encap(u32 * const desc, struct alginfo *cdata,
++                         struct alginfo *adata, unsigned int assoclen,
++                         unsigned int ivsize, unsigned int authsize,
++                         unsigned int blocksize, int era)
++{
++      u32 *key_jump_cmd, *zero_payload_jump_cmd;
++      u32 genpad, idx_ld_datasz, idx_ld_pad, stidx;
++
++      /*
++       * Compute the index (in bytes) for the LOAD with destination of
++       * Class 1 Data Size Register and for the LOAD that generates padding
++       */
++      if (adata->key_inline) {
++              idx_ld_datasz = DESC_TLS10_ENC_LEN + adata->keylen_pad +
++                              cdata->keylen - 4 * CAAM_CMD_SZ;
++              idx_ld_pad = DESC_TLS10_ENC_LEN + adata->keylen_pad +
++                           cdata->keylen - 2 * CAAM_CMD_SZ;
++      } else {
++              idx_ld_datasz = DESC_TLS10_ENC_LEN + 2 * CAAM_PTR_SZ -
++                              4 * CAAM_CMD_SZ;
++              idx_ld_pad = DESC_TLS10_ENC_LEN + 2 * CAAM_PTR_SZ -
++                           2 * CAAM_CMD_SZ;
++      }
++
++      stidx = 1 << HDR_START_IDX_SHIFT;
++      init_sh_desc(desc, HDR_SHARE_SERIAL | stidx);
++
++      /* skip key loading if they are loaded due to sharing */
++      key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
++                                 JUMP_COND_SHRD);
++
++      if (era < 6) {
++              if (adata->key_inline)
++                      append_key_as_imm(desc, adata->key_virt,
++                                        adata->keylen_pad, adata->keylen,
++                                        CLASS_2 | KEY_DEST_MDHA_SPLIT |
++                                        KEY_ENC);
++              else
++                      append_key(desc, adata->key_dma, adata->keylen,
++                                 CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC);
++      } else {
++              append_proto_dkp(desc, adata);
++      }
++
++      if (cdata->key_inline)
++              append_key_as_imm(desc, cdata->key_virt, cdata->keylen,
++                                cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG);
++      else
++              append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 |
++                         KEY_DEST_CLASS_REG);
++
++      set_jump_tgt_here(desc, key_jump_cmd);
++
++      /* class 2 operation */
++      append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL |
++                       OP_ALG_ENCRYPT);
++      /* class 1 operation */
++      append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
++                       OP_ALG_ENCRYPT);
++
++      /* payloadlen = input data length - (assoclen + ivlen) */
++      append_math_sub_imm_u32(desc, REG0, SEQINLEN, IMM, assoclen + ivsize);
++
++      /* math1 = payloadlen + icvlen */
++      append_math_add_imm_u32(desc, REG1, REG0, IMM, authsize);
++
++      /* padlen = block_size - math1 % block_size */
++      append_math_and_imm_u32(desc, REG3, REG1, IMM, blocksize - 1);
++      append_math_sub_imm_u32(desc, REG2, IMM, REG3, blocksize);
++
++      /* cryptlen = payloadlen + icvlen + padlen */
++      append_math_add(desc, VARSEQOUTLEN, REG1, REG2, 4);
++
++      /*
++       * update immediate data with the padding length value
++       * for the LOAD in the class 1 data size register.
++       */
++      append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH2 |
++                      (idx_ld_datasz << MOVE_OFFSET_SHIFT) | 7);
++      append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH2 | MOVE_DEST_DESCBUF |
++                      (idx_ld_datasz << MOVE_OFFSET_SHIFT) | 8);
++
++      /* overwrite PL field for the padding iNFO FIFO entry  */
++      append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH2 |
++                      (idx_ld_pad << MOVE_OFFSET_SHIFT) | 7);
++      append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH2 | MOVE_DEST_DESCBUF |
++                      (idx_ld_pad << MOVE_OFFSET_SHIFT) | 8);
++
++      /* store encrypted payload, icv and padding */
++      append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | LDST_VLF);
++
++      /* if payload length is zero, jump to zero-payload commands */
++      append_math_add(desc, VARSEQINLEN, ZERO, REG0, 4);
++      zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL |
++                                          JUMP_COND_MATH_Z);
++
++      /* load iv in context1 */
++      append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_WORD_CLASS_CTX |
++                 LDST_CLASS_1_CCB | ivsize);
++
++      /* read assoc for authentication */
++      append_seq_fifo_load(desc, assoclen, FIFOLD_CLASS_CLASS2 |
++                           FIFOLD_TYPE_MSG);
++      /* insnoop payload */
++      append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | FIFOLD_TYPE_MSG |
++                           FIFOLD_TYPE_LAST2 | FIFOLDST_VLF);
++
++      /* jump the zero-payload commands */
++      append_jump(desc, JUMP_TEST_ALL | 3);
++
++      /* zero-payload commands */
++      set_jump_tgt_here(desc, zero_payload_jump_cmd);
++
++      /* load iv in context1 */
++      append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_WORD_CLASS_CTX |
++                 LDST_CLASS_1_CCB | ivsize);
++
++      /* assoc data is the only data for authentication */
++      append_seq_fifo_load(desc, assoclen, FIFOLD_CLASS_CLASS2 |
++                           FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST2);
++
++      /* send icv to encryption */
++      append_move(desc, MOVE_SRC_CLASS2CTX | MOVE_DEST_CLASS1INFIFO |
++                  authsize);
++
++      /* update class 1 data size register with padding length */
++      append_load_imm_u32(desc, 0, LDST_CLASS_1_CCB |
++                          LDST_SRCDST_WORD_DATASZ_REG | LDST_IMM);
++
++      /* generate padding and send it to encryption */
++      genpad = NFIFOENTRY_DEST_CLASS1 | NFIFOENTRY_LC1 | NFIFOENTRY_FC1 |
++            NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_PTYPE_N;
++      append_load_imm_u32(desc, genpad, LDST_CLASS_IND_CCB |
++                          LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM);
++
++#ifdef DEBUG
++      print_hex_dump(KERN_ERR, "tls enc shdesc@" __stringify(__LINE__) ": ",
++                     DUMP_PREFIX_ADDRESS, 16, 4, desc,
++                     desc_bytes(desc), 1);
++#endif
++}
++EXPORT_SYMBOL(cnstr_shdsc_tls_encap);
++
++/**
++ * cnstr_shdsc_tls_decap - tls decapsulation shared descriptor
++ * @desc: pointer to buffer used for descriptor construction
++ * @cdata: pointer to block cipher transform definitions
++ *         Valid algorithm values - one of OP_ALG_ALGSEL_AES ANDed
++ *         with OP_ALG_AAI_CBC
++ * @adata: pointer to authentication transform definitions.
++ *         A split key is required for SEC Era < 6; the size of the split key
++ *         is specified in this case. Valid algorithm values OP_ALG_ALGSEL_SHA1
++ *         ANDed with OP_ALG_AAI_HMAC_PRECOMP.
++ * @assoclen: associated data length
++ * @ivsize: initialization vector size
++ * @authsize: authentication data size
++ * @blocksize: block cipher size
++ * @era: SEC Era
++ */
++void cnstr_shdsc_tls_decap(u32 * const desc, struct alginfo *cdata,
++                         struct alginfo *adata, unsigned int assoclen,
++                         unsigned int ivsize, unsigned int authsize,
++                         unsigned int blocksize, int era)
++{
++      u32 stidx, jumpback;
++      u32 *key_jump_cmd, *zero_payload_jump_cmd, *skip_zero_jump_cmd;
++      /*
++       * Pointer Size bool determines the size of address pointers.
++       * false - Pointers fit in one 32-bit word.
++       * true - Pointers fit in two 32-bit words.
++       */
++      bool ps = (CAAM_PTR_SZ != CAAM_CMD_SZ);
++
++      stidx = 1 << HDR_START_IDX_SHIFT;
++      init_sh_desc(desc, HDR_SHARE_SERIAL | stidx);
++
++      /* skip key loading if they are loaded due to sharing */
++      key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
++                                 JUMP_COND_SHRD);
++
++      if (era < 6)
++              append_key(desc, adata->key_dma, adata->keylen, CLASS_2 |
++                         KEY_DEST_MDHA_SPLIT | KEY_ENC);
++      else
++              append_proto_dkp(desc, adata);
++
++      append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 |
++                 KEY_DEST_CLASS_REG);
++
++      set_jump_tgt_here(desc, key_jump_cmd);
++
++      /* class 2 operation */
++      append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL |
++                       OP_ALG_DECRYPT | OP_ALG_ICV_ON);
++      /* class 1 operation */
++      append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
++                       OP_ALG_DECRYPT);
++
++      /* VSIL = input data length - 2 * block_size */
++      append_math_sub_imm_u32(desc, VARSEQINLEN, SEQINLEN, IMM, 2 *
++                              blocksize);
++
++      /*
++       * payloadlen + icvlen + padlen = input data length - (assoclen +
++       * ivsize)
++       */
++      append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM, assoclen + ivsize);
++
++      /* skip data to the last but one cipher block */
++      append_seq_fifo_load(desc, 0, FIFOLD_CLASS_SKIP | LDST_VLF);
++
++      /* load iv for the last cipher block */
++      append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_WORD_CLASS_CTX |
++                 LDST_CLASS_1_CCB | ivsize);
++
++      /* read last cipher block */
++      append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG |
++                           FIFOLD_TYPE_LAST1 | blocksize);
++
++      /* move decrypted block into math0 and math1 */
++      append_move(desc, MOVE_WAITCOMP | MOVE_SRC_OUTFIFO | MOVE_DEST_MATH0 |
++                  blocksize);
++
++      /* reset AES CHA */
++      append_load_imm_u32(desc, CCTRL_RESET_CHA_AESA, LDST_CLASS_IND_CCB |
++                          LDST_SRCDST_WORD_CHACTRL | LDST_IMM);
++
++      /* rewind input sequence */
++      append_seq_in_ptr_intlen(desc, 0, 65535, SQIN_RTO);
++
++      /* key1 is in decryption form */
++      append_operation(desc, cdata->algtype | OP_ALG_AAI_DK |
++                       OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT);
++
++      /* load iv in context1 */
++      append_cmd(desc, CMD_SEQ_LOAD | LDST_CLASS_1_CCB |
++                 LDST_SRCDST_WORD_CLASS_CTX | ivsize);
++
++      /* read sequence number */
++      append_seq_fifo_load(desc, 8, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG);
++      /* load Type, Version and Len fields in math0 */
++      append_cmd(desc, CMD_SEQ_LOAD | LDST_CLASS_DECO |
++                 LDST_SRCDST_WORD_DECO_MATH0 | (3 << LDST_OFFSET_SHIFT) | 5);
++
++      /* compute (padlen - 1) */
++      append_math_and_imm_u64(desc, REG1, REG1, IMM, 255);
++
++      /* math2 = icvlen + (padlen - 1) + 1 */
++      append_math_add_imm_u32(desc, REG2, REG1, IMM, authsize + 1);
++
++      append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | 1);
++
++      /* VSOL = payloadlen + icvlen + padlen */
++      append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, 4);
++
++      if (caam_little_end)
++              append_moveb(desc, MOVE_WAITCOMP |
++                           MOVE_SRC_MATH0 | MOVE_DEST_MATH0 | 8);
++
++      /* update Len field */
++      append_math_sub(desc, REG0, REG0, REG2, 8);
++
++      /* store decrypted payload, icv and padding */
++      append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | LDST_VLF);
++
++      /* VSIL = (payloadlen + icvlen + padlen) - (icvlen + padlen)*/
++      append_math_sub(desc, VARSEQINLEN, REG3, REG2, 4);
++
++      zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL |
++                                          JUMP_COND_MATH_Z);
++
++      /* send Type, Version and Len(pre ICV) fields to authentication */
++      append_move(desc, MOVE_WAITCOMP |
++                  MOVE_SRC_MATH0 | MOVE_DEST_CLASS2INFIFO |
++                  (3 << MOVE_OFFSET_SHIFT) | 5);
++
++      /* outsnooping payload */
++      append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH |
++                           FIFOLD_TYPE_MSG1OUT2 | FIFOLD_TYPE_LAST2 |
++                           FIFOLDST_VLF);
++      skip_zero_jump_cmd = append_jump(desc, JUMP_TEST_ALL | 2);
++
++      set_jump_tgt_here(desc, zero_payload_jump_cmd);
++      /* send Type, Version and Len(pre ICV) fields to authentication */
++      append_move(desc, MOVE_WAITCOMP | MOVE_AUX_LS |
++                  MOVE_SRC_MATH0 | MOVE_DEST_CLASS2INFIFO |
++                  (3 << MOVE_OFFSET_SHIFT) | 5);
++
++      set_jump_tgt_here(desc, skip_zero_jump_cmd);
++      append_math_add(desc, VARSEQINLEN, ZERO, REG2, 4);
++
++      /* load icvlen and padlen */
++      append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG |
++                           FIFOLD_TYPE_LAST1 | FIFOLDST_VLF);
++
++      /* VSIL = (payloadlen + icvlen + padlen) - icvlen + padlen */
++      append_math_sub(desc, VARSEQINLEN, REG3, REG2, 4);
++
++      /*
++       * Start a new input sequence using the SEQ OUT PTR command options,
++       * pointer and length used when the current output sequence was defined.
++       */
++      if (ps) {
++              /*
++               * Move the lower 32 bits of Shared Descriptor address, the
++               * SEQ OUT PTR command, Output Pointer (2 words) and
++               * Output Length into math registers.
++               */
++              if (caam_little_end)
++                      append_move(desc, MOVE_WAITCOMP | MOVE_SRC_DESCBUF |
++                                  MOVE_DEST_MATH0 |
++                                  (55 * 4 << MOVE_OFFSET_SHIFT) | 20);
++              else
++                      append_move(desc, MOVE_WAITCOMP | MOVE_SRC_DESCBUF |
++                                  MOVE_DEST_MATH0 |
++                                  (54 * 4 << MOVE_OFFSET_SHIFT) | 20);
++
++              /* Transform SEQ OUT PTR command in SEQ IN PTR command */
++              append_math_and_imm_u32(desc, REG0, REG0, IMM,
++                                      ~(CMD_SEQ_IN_PTR ^ CMD_SEQ_OUT_PTR));
++              /* Append a JUMP command after the copied fields */
++              jumpback = CMD_JUMP | (char)-9;
++              append_load_imm_u32(desc, jumpback, LDST_CLASS_DECO | LDST_IMM |
++                                  LDST_SRCDST_WORD_DECO_MATH2 |
++                                  (4 << LDST_OFFSET_SHIFT));
++              append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | 1);
++              /* Move the updated fields back to the Job Descriptor */
++              if (caam_little_end)
++                      append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH0 |
++                                  MOVE_DEST_DESCBUF |
++                                  (55 * 4 << MOVE_OFFSET_SHIFT) | 24);
++              else
++                      append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH0 |
++                                  MOVE_DEST_DESCBUF |
++                                  (54 * 4 << MOVE_OFFSET_SHIFT) | 24);
++
++              /*
++               * Read the new SEQ IN PTR command, Input Pointer, Input Length
++               * and then jump back to the next command from the
++               * Shared Descriptor.
++               */
++              append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | 6);
++      } else {
++              /*
++               * Move the SEQ OUT PTR command, Output Pointer (1 word) and
++               * Output Length into math registers.
++               */
++              if (caam_little_end)
++                      append_move(desc, MOVE_WAITCOMP | MOVE_SRC_DESCBUF |
++                                  MOVE_DEST_MATH0 |
++                                  (54 * 4 << MOVE_OFFSET_SHIFT) | 12);
++              else
++                      append_move(desc, MOVE_WAITCOMP | MOVE_SRC_DESCBUF |
++                                  MOVE_DEST_MATH0 |
++                                  (53 * 4 << MOVE_OFFSET_SHIFT) | 12);
++
++              /* Transform SEQ OUT PTR command in SEQ IN PTR command */
++              append_math_and_imm_u64(desc, REG0, REG0, IMM,
++                                      ~(((u64)(CMD_SEQ_IN_PTR ^
++                                               CMD_SEQ_OUT_PTR)) << 32));
++              /* Append a JUMP command after the copied fields */
++              jumpback = CMD_JUMP | (char)-7;
++              append_load_imm_u32(desc, jumpback, LDST_CLASS_DECO | LDST_IMM |
++                                  LDST_SRCDST_WORD_DECO_MATH1 |
++                                  (4 << LDST_OFFSET_SHIFT));
++              append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | 1);
++              /* Move the updated fields back to the Job Descriptor */
++              if (caam_little_end)
++                      append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH0 |
++                                  MOVE_DEST_DESCBUF |
++                                  (54 * 4 << MOVE_OFFSET_SHIFT) | 16);
++              else
++                      append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH0 |
++                                  MOVE_DEST_DESCBUF |
++                                  (53 * 4 << MOVE_OFFSET_SHIFT) | 16);
++
++              /*
++               * Read the new SEQ IN PTR command, Input Pointer, Input Length
++               * and then jump back to the next command from the
++               * Shared Descriptor.
++               */
++               append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | 5);
++      }
++
++      /* skip payload */
++      append_seq_fifo_load(desc, 0, FIFOLD_CLASS_SKIP | FIFOLDST_VLF);
++      /* check icv */
++      append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_ICV |
++                           FIFOLD_TYPE_LAST2 | authsize);
++
++#ifdef DEBUG
++      print_hex_dump(KERN_ERR, "tls dec shdesc@" __stringify(__LINE__) ": ",
++                     DUMP_PREFIX_ADDRESS, 16, 4, desc,
++                     desc_bytes(desc), 1);
++#endif
++}
++EXPORT_SYMBOL(cnstr_shdsc_tls_decap);
++
++/**
+  * cnstr_shdsc_gcm_encap - gcm encapsulation shared descriptor
+  * @desc: pointer to buffer used for descriptor construction
+  * @cdata: pointer to block cipher transform definitions
+--- a/drivers/crypto/caam/caamalg_desc.h
++++ b/drivers/crypto/caam/caamalg_desc.h
+@@ -17,6 +17,9 @@
+ #define DESC_QI_AEAD_DEC_LEN          (DESC_AEAD_DEC_LEN + 3 * CAAM_CMD_SZ)
+ #define DESC_QI_AEAD_GIVENC_LEN               (DESC_AEAD_GIVENC_LEN + 3 * CAAM_CMD_SZ)
++#define DESC_TLS_BASE                 (4 * CAAM_CMD_SZ)
++#define DESC_TLS10_ENC_LEN            (DESC_TLS_BASE + 29 * CAAM_CMD_SZ)
++
+ /* Note: Nonce is counted in cdata.keylen */
+ #define DESC_AEAD_CTR_RFC3686_LEN     (4 * CAAM_CMD_SZ)
+@@ -72,6 +75,16 @@ void cnstr_shdsc_aead_givencap(u32 * con
+                              u32 *nonce, const u32 ctx1_iv_off,
+                              const bool is_qi, int era);
++void cnstr_shdsc_tls_encap(u32 *const desc, struct alginfo *cdata,
++                         struct alginfo *adata, unsigned int assoclen,
++                         unsigned int ivsize, unsigned int authsize,
++                         unsigned int blocksize, int era);
++
++void cnstr_shdsc_tls_decap(u32 *const desc, struct alginfo *cdata,
++                         struct alginfo *adata, unsigned int assoclen,
++                         unsigned int ivsize, unsigned int authsize,
++                         unsigned int blocksize, int era);
++
+ void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata,
+                          unsigned int ivsize, unsigned int icvsize,
+                          const bool is_qi);
+--- a/drivers/crypto/caam/caamalg_qi.c
++++ b/drivers/crypto/caam/caamalg_qi.c
+@@ -290,6 +290,167 @@ static int des3_aead_setkey(struct crypt
+       return err;
+ }
++static int tls_set_sh_desc(struct crypto_aead *tls)
++{
++      struct caam_ctx *ctx = crypto_aead_ctx(tls);
++      unsigned int ivsize = crypto_aead_ivsize(tls);
++      unsigned int blocksize = crypto_aead_blocksize(tls);
++      unsigned int assoclen = 13; /* always 13 bytes for TLS */
++      unsigned int data_len[2];
++      u32 inl_mask;
++      struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctx->jrdev->parent);
++
++      if (!ctx->cdata.keylen || !ctx->authsize)
++              return 0;
++
++      /*
++       * TLS 1.0 encrypt shared descriptor
++       * Job Descriptor and Shared Descriptor
++       * must fit into the 64-word Descriptor h/w Buffer
++       */
++      data_len[0] = ctx->adata.keylen_pad;
++      data_len[1] = ctx->cdata.keylen;
++
++      if (desc_inline_query(DESC_TLS10_ENC_LEN, DESC_JOB_IO_LEN, data_len,
++                            &inl_mask, ARRAY_SIZE(data_len)) < 0)
++              return -EINVAL;
++
++      if (inl_mask & 1)
++              ctx->adata.key_virt = ctx->key;
++      else
++              ctx->adata.key_dma = ctx->key_dma;
++
++      if (inl_mask & 2)
++              ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad;
++      else
++              ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad;
++
++      ctx->adata.key_inline = !!(inl_mask & 1);
++      ctx->cdata.key_inline = !!(inl_mask & 2);
++
++      cnstr_shdsc_tls_encap(ctx->sh_desc_enc, &ctx->cdata, &ctx->adata,
++                            assoclen, ivsize, ctx->authsize, blocksize,
++                            ctrlpriv->era);
++
++      /*
++       * TLS 1.0 decrypt shared descriptor
++       * Keys do not fit inline, regardless of algorithms used
++       */
++      ctx->adata.key_inline = false;
++      ctx->adata.key_dma = ctx->key_dma;
++      ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad;
++
++      cnstr_shdsc_tls_decap(ctx->sh_desc_dec, &ctx->cdata, &ctx->adata,
++                            assoclen, ivsize, ctx->authsize, blocksize,
++                            ctrlpriv->era);
++
++      return 0;
++}
++
++static int tls_setauthsize(struct crypto_aead *tls, unsigned int authsize)
++{
++      struct caam_ctx *ctx = crypto_aead_ctx(tls);
++
++      ctx->authsize = authsize;
++      tls_set_sh_desc(tls);
++
++      return 0;
++}
++
++static int tls_setkey(struct crypto_aead *tls, const u8 *key,
++                    unsigned int keylen)
++{
++      struct caam_ctx *ctx = crypto_aead_ctx(tls);
++      struct device *jrdev = ctx->jrdev;
++      struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent);
++      struct crypto_authenc_keys keys;
++      int ret = 0;
++
++      if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
++              goto badkey;
++
++#ifdef DEBUG
++      dev_err(jrdev, "keylen %d enckeylen %d authkeylen %d\n",
++              keys.authkeylen + keys.enckeylen, keys.enckeylen,
++              keys.authkeylen);
++      print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
++                     DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
++#endif
++
++      /*
++       * If DKP is supported, use it in the shared descriptor to generate
++       * the split key.
++       */
++      if (ctrlpriv->era >= 6) {
++              ctx->adata.keylen = keys.authkeylen;
++              ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype &
++                                                    OP_ALG_ALGSEL_MASK);
++
++              if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE)
++                      goto badkey;
++
++              memcpy(ctx->key, keys.authkey, keys.authkeylen);
++              memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey,
++                     keys.enckeylen);
++              dma_sync_single_for_device(jrdev, ctx->key_dma,
++                                         ctx->adata.keylen_pad +
++                                         keys.enckeylen, ctx->dir);
++              goto skip_split_key;
++      }
++
++      ret = gen_split_key(jrdev, ctx->key, &ctx->adata, keys.authkey,
++                          keys.authkeylen, CAAM_MAX_KEY_SIZE -
++                          keys.enckeylen);
++      if (ret)
++              goto badkey;
++
++      /* postpend encryption key to auth split key */
++      memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen);
++      dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad +
++                                 keys.enckeylen, ctx->dir);
++
++#ifdef DEBUG
++      dev_err(jrdev, "split keylen %d split keylen padded %d\n",
++              ctx->adata.keylen, ctx->adata.keylen_pad);
++      print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ",
++                     DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
++                     ctx->adata.keylen_pad + keys.enckeylen, 1);
++#endif
++
++skip_split_key:
++      ctx->cdata.keylen = keys.enckeylen;
++
++      ret = tls_set_sh_desc(tls);
++      if (ret)
++              goto badkey;
++
++      /* Now update the driver contexts with the new shared descriptor */
++      if (ctx->drv_ctx[ENCRYPT]) {
++              ret = caam_drv_ctx_update(ctx->drv_ctx[ENCRYPT],
++                                        ctx->sh_desc_enc);
++              if (ret) {
++                      dev_err(jrdev, "driver enc context update failed\n");
++                      goto badkey;
++              }
++      }
++
++      if (ctx->drv_ctx[DECRYPT]) {
++              ret = caam_drv_ctx_update(ctx->drv_ctx[DECRYPT],
++                                        ctx->sh_desc_dec);
++              if (ret) {
++                      dev_err(jrdev, "driver dec context update failed\n");
++                      goto badkey;
++              }
++      }
++
++      memzero_explicit(&keys, sizeof(keys));
++      return ret;
++badkey:
++      crypto_aead_set_flags(tls, CRYPTO_TFM_RES_BAD_KEY_LEN);
++      memzero_explicit(&keys, sizeof(keys));
++      return -EINVAL;
++}
++
+ static int gcm_set_sh_desc(struct crypto_aead *aead)
+ {
+       struct caam_ctx *ctx = crypto_aead_ctx(aead);
+@@ -809,6 +970,29 @@ struct aead_edesc {
+ };
+ /*
++ * tls_edesc - s/w-extended tls descriptor
++ * @src_nents: number of segments in input scatterlist
++ * @dst_nents: number of segments in output scatterlist
++ * @iv_dma: dma address of iv for checking continuity and link table
++ * @qm_sg_bytes: length of dma mapped h/w link table
++ * @tmp: array of scatterlists used by 'scatterwalk_ffwd'
++ * @qm_sg_dma: bus physical mapped address of h/w link table
++ * @drv_req: driver-specific request structure
++ * @sgt: the h/w link table, followed by IV
++ */
++struct tls_edesc {
++      int src_nents;
++      int dst_nents;
++      dma_addr_t iv_dma;
++      int qm_sg_bytes;
++      dma_addr_t qm_sg_dma;
++      struct scatterlist tmp[2];
++      struct scatterlist *dst;
++      struct caam_drv_req drv_req;
++      struct qm_sg_entry sgt[0];
++};
++
++/*
+  * skcipher_edesc - s/w-extended skcipher descriptor
+  * @src_nents: number of segments in input scatterlist
+  * @dst_nents: number of segments in output scatterlist
+@@ -900,6 +1084,18 @@ static void aead_unmap(struct device *de
+       dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE);
+ }
++static void tls_unmap(struct device *dev,
++                    struct tls_edesc *edesc,
++                    struct aead_request *req)
++{
++      struct crypto_aead *aead = crypto_aead_reqtfm(req);
++      int ivsize = crypto_aead_ivsize(aead);
++
++      caam_unmap(dev, req->src, edesc->dst, edesc->src_nents,
++                 edesc->dst_nents, edesc->iv_dma, ivsize, DMA_TO_DEVICE,
++                 edesc->qm_sg_dma, edesc->qm_sg_bytes);
++}
++
+ static void skcipher_unmap(struct device *dev, struct skcipher_edesc *edesc,
+                          struct skcipher_request *req)
+ {
+@@ -1192,6 +1388,243 @@ static int aead_decrypt(struct aead_requ
+       return aead_crypt(req, false);
+ }
++static void tls_done(struct caam_drv_req *drv_req, u32 status)
++{
++      struct device *qidev;
++      struct tls_edesc *edesc;
++      struct aead_request *aead_req = drv_req->app_ctx;
++      struct crypto_aead *aead = crypto_aead_reqtfm(aead_req);
++      struct caam_ctx *caam_ctx = crypto_aead_ctx(aead);
++      int ecode = 0;
++
++      qidev = caam_ctx->qidev;
++
++      if (unlikely(status)) {
++              caam_jr_strstatus(qidev, status);
++              ecode = -EIO;
++      }
++
++      edesc = container_of(drv_req, typeof(*edesc), drv_req);
++      tls_unmap(qidev, edesc, aead_req);
++
++      aead_request_complete(aead_req, ecode);
++      qi_cache_free(edesc);
++}
++
++/*
++ * allocate and map the tls extended descriptor
++ */
++static struct tls_edesc *tls_edesc_alloc(struct aead_request *req, bool encrypt)
++{
++      struct crypto_aead *aead = crypto_aead_reqtfm(req);
++      struct caam_ctx *ctx = crypto_aead_ctx(aead);
++      unsigned int blocksize = crypto_aead_blocksize(aead);
++      unsigned int padsize, authsize;
++      struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead),
++                                               typeof(*alg), aead);
++      struct device *qidev = ctx->qidev;
++      gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
++                    GFP_KERNEL : GFP_ATOMIC;
++      int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0;
++      struct tls_edesc *edesc;
++      dma_addr_t qm_sg_dma, iv_dma = 0;
++      int ivsize = 0;
++      u8 *iv;
++      int qm_sg_index, qm_sg_ents = 0, qm_sg_bytes;
++      int in_len, out_len;
++      struct qm_sg_entry *sg_table, *fd_sgt;
++      struct caam_drv_ctx *drv_ctx;
++      struct scatterlist *dst;
++
++      if (encrypt) {
++              padsize = blocksize - ((req->cryptlen + ctx->authsize) %
++                                      blocksize);
++              authsize = ctx->authsize + padsize;
++      } else {
++              authsize = ctx->authsize;
++      }
++
++      drv_ctx = get_drv_ctx(ctx, encrypt ? ENCRYPT : DECRYPT);
++      if (unlikely(IS_ERR_OR_NULL(drv_ctx)))
++              return (struct tls_edesc *)drv_ctx;
++
++      /* allocate space for base edesc, link tables and IV */
++      edesc = qi_cache_alloc(GFP_DMA | flags);
++      if (unlikely(!edesc)) {
++              dev_err(qidev, "could not allocate extended descriptor\n");
++              return ERR_PTR(-ENOMEM);
++      }
++
++      if (likely(req->src == req->dst)) {
++              src_nents = sg_nents_for_len(req->src, req->assoclen +
++                                           req->cryptlen +
++                                           (encrypt ? authsize : 0));
++              if (unlikely(src_nents < 0)) {
++                      dev_err(qidev, "Insufficient bytes (%d) in src S/G\n",
++                              req->assoclen + req->cryptlen +
++                              (encrypt ? authsize : 0));
++                      qi_cache_free(edesc);
++                      return ERR_PTR(src_nents);
++              }
++
++              mapped_src_nents = dma_map_sg(qidev, req->src, src_nents,
++                                            DMA_BIDIRECTIONAL);
++              if (unlikely(!mapped_src_nents)) {
++                      dev_err(qidev, "unable to map source\n");
++                      qi_cache_free(edesc);
++                      return ERR_PTR(-ENOMEM);
++              }
++              dst = req->dst;
++      } else {
++              src_nents = sg_nents_for_len(req->src, req->assoclen +
++                                           req->cryptlen);
++              if (unlikely(src_nents < 0)) {
++                      dev_err(qidev, "Insufficient bytes (%d) in src S/G\n",
++                              req->assoclen + req->cryptlen);
++                      qi_cache_free(edesc);
++                      return ERR_PTR(src_nents);
++              }
++
++              dst = scatterwalk_ffwd(edesc->tmp, req->dst, req->assoclen);
++              dst_nents = sg_nents_for_len(dst, req->cryptlen +
++                                           (encrypt ? authsize : 0));
++              if (unlikely(dst_nents < 0)) {
++                      dev_err(qidev, "Insufficient bytes (%d) in dst S/G\n",
++                              req->cryptlen +
++                              (encrypt ? authsize : 0));
++                      qi_cache_free(edesc);
++                      return ERR_PTR(dst_nents);
++              }
++
++              if (src_nents) {
++                      mapped_src_nents = dma_map_sg(qidev, req->src,
++                                                    src_nents, DMA_TO_DEVICE);
++                      if (unlikely(!mapped_src_nents)) {
++                              dev_err(qidev, "unable to map source\n");
++                              qi_cache_free(edesc);
++                              return ERR_PTR(-ENOMEM);
++                      }
++              } else {
++                      mapped_src_nents = 0;
++              }
++
++              mapped_dst_nents = dma_map_sg(qidev, dst, dst_nents,
++                                            DMA_FROM_DEVICE);
++              if (unlikely(!mapped_dst_nents)) {
++                      dev_err(qidev, "unable to map destination\n");
++                      dma_unmap_sg(qidev, req->src, src_nents, DMA_TO_DEVICE);
++                      qi_cache_free(edesc);
++                      return ERR_PTR(-ENOMEM);
++              }
++      }
++
++      /*
++       * Create S/G table: IV, src, dst.
++       * Input is not contiguous.
++       */
++      qm_sg_ents = 1 + mapped_src_nents +
++                   (mapped_dst_nents > 1 ? mapped_dst_nents : 0);
++      sg_table = &edesc->sgt[0];
++      qm_sg_bytes = qm_sg_ents * sizeof(*sg_table);
++
++      ivsize = crypto_aead_ivsize(aead);
++      iv = (u8 *)(sg_table + qm_sg_ents);
++      /* Make sure IV is located in a DMAable area */
++      memcpy(iv, req->iv, ivsize);
++      iv_dma = dma_map_single(qidev, iv, ivsize, DMA_TO_DEVICE);
++      if (dma_mapping_error(qidev, iv_dma)) {
++              dev_err(qidev, "unable to map IV\n");
++              caam_unmap(qidev, req->src, dst, src_nents, dst_nents, 0, 0,
++                         DMA_NONE, 0, 0);
++              qi_cache_free(edesc);
++              return ERR_PTR(-ENOMEM);
++      }
++
++      edesc->src_nents = src_nents;
++      edesc->dst_nents = dst_nents;
++      edesc->dst = dst;
++      edesc->iv_dma = iv_dma;
++      edesc->drv_req.app_ctx = req;
++      edesc->drv_req.cbk = tls_done;
++      edesc->drv_req.drv_ctx = drv_ctx;
++
++      dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0);
++      qm_sg_index = 1;
++
++      sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + qm_sg_index, 0);
++      qm_sg_index += mapped_src_nents;
++
++      if (mapped_dst_nents > 1)
++              sg_to_qm_sg_last(dst, mapped_dst_nents, sg_table +
++                               qm_sg_index, 0);
++
++      qm_sg_dma = dma_map_single(qidev, sg_table, qm_sg_bytes, DMA_TO_DEVICE);
++      if (dma_mapping_error(qidev, qm_sg_dma)) {
++              dev_err(qidev, "unable to map S/G table\n");
++              caam_unmap(qidev, req->src, dst, src_nents, dst_nents, iv_dma,
++                         ivsize, DMA_TO_DEVICE, 0, 0);
++              qi_cache_free(edesc);
++              return ERR_PTR(-ENOMEM);
++      }
++
++      edesc->qm_sg_dma = qm_sg_dma;
++      edesc->qm_sg_bytes = qm_sg_bytes;
++
++      out_len = req->cryptlen + (encrypt ? authsize : 0);
++      in_len = ivsize + req->assoclen + req->cryptlen;
++
++      fd_sgt = &edesc->drv_req.fd_sgt[0];
++
++      dma_to_qm_sg_one_last_ext(&fd_sgt[1], qm_sg_dma, in_len, 0);
++
++      if (req->dst == req->src)
++              dma_to_qm_sg_one_ext(&fd_sgt[0], qm_sg_dma +
++                                  (sg_nents_for_len(req->src, req->assoclen) +
++                                   1) * sizeof(*sg_table), out_len, 0);
++      else if (mapped_dst_nents == 1)
++              dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(dst), out_len, 0);
++      else
++              dma_to_qm_sg_one_ext(&fd_sgt[0], qm_sg_dma + sizeof(*sg_table) *
++                                   qm_sg_index, out_len, 0);
++
++      return edesc;
++}
++
++static int tls_crypt(struct aead_request *req, bool encrypt)
++{
++      struct tls_edesc *edesc;
++      struct crypto_aead *aead = crypto_aead_reqtfm(req);
++      struct caam_ctx *ctx = crypto_aead_ctx(aead);
++      int ret;
++
++      if (unlikely(caam_congested))
++              return -EAGAIN;
++
++      edesc = tls_edesc_alloc(req, encrypt);
++      if (IS_ERR_OR_NULL(edesc))
++              return PTR_ERR(edesc);
++
++      ret = caam_qi_enqueue(ctx->qidev, &edesc->drv_req);
++      if (!ret) {
++              ret = -EINPROGRESS;
++      } else {
++              tls_unmap(ctx->qidev, edesc, req);
++              qi_cache_free(edesc);
++      }
++
++      return ret;
++}
++
++static int tls_encrypt(struct aead_request *req)
++{
++      return tls_crypt(req, true);
++}
++
++static int tls_decrypt(struct aead_request *req)
++{
++      return tls_crypt(req, false);
++}
++
+ static int ipsec_gcm_encrypt(struct aead_request *req)
+ {
+       return crypto_ipsec_check_assoclen(req->assoclen) ? : aead_crypt(req,
+@@ -2411,6 +2844,26 @@ static struct caam_aead_alg driver_aeads
+                       .geniv = true,
+               }
+       },
++      {
++              .aead = {
++                      .base = {
++                              .cra_name = "tls10(hmac(sha1),cbc(aes))",
++                              .cra_driver_name = "tls10-hmac-sha1-cbc-aes-caam-qi",
++                              .cra_blocksize = AES_BLOCK_SIZE,
++                      },
++                      .setkey = tls_setkey,
++                      .setauthsize = tls_setauthsize,
++                      .encrypt = tls_encrypt,
++                      .decrypt = tls_decrypt,
++                      .ivsize = AES_BLOCK_SIZE,
++                      .maxauthsize = SHA1_DIGEST_SIZE,
++              },
++              .caam = {
++                      .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++                      .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
++                                         OP_ALG_AAI_HMAC_PRECOMP,
++              }
++      }
+ };
+ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam,
+@@ -2418,6 +2871,16 @@ static int caam_init_common(struct caam_
+ {
+       struct caam_drv_private *priv;
+       struct device *dev;
++      /* Digest sizes for MD5, SHA1, SHA-224, SHA-256, SHA-384, SHA-512 */
++      static const u8 digest_size[] = {
++              MD5_DIGEST_SIZE,
++              SHA1_DIGEST_SIZE,
++              SHA224_DIGEST_SIZE,
++              SHA256_DIGEST_SIZE,
++              SHA384_DIGEST_SIZE,
++              SHA512_DIGEST_SIZE
++      };
++      u8 op_id;
+       /*
+        * distribute tfms across job rings to ensure in-order
+@@ -2449,6 +2912,21 @@ static int caam_init_common(struct caam_
+       ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam->class2_alg_type;
+       ctx->qidev = dev;
++      if (ctx->adata.algtype) {
++              op_id = (ctx->adata.algtype & OP_ALG_ALGSEL_SUBMASK)
++                              >> OP_ALG_ALGSEL_SHIFT;
++              if (op_id < ARRAY_SIZE(digest_size)) {
++                      ctx->authsize = digest_size[op_id];
++              } else {
++                      dev_err(ctx->jrdev,
++                              "incorrect op_id %d; must be less than %zu\n",
++                              op_id, ARRAY_SIZE(digest_size));
++                      caam_jr_free(ctx->jrdev);
++                      return -EINVAL;
++              }
++      } else {
++              ctx->authsize = 0;
++      }
+       spin_lock_init(&ctx->lock);
+       ctx->drv_ctx[ENCRYPT] = NULL;
+--- a/drivers/crypto/caam/desc.h
++++ b/drivers/crypto/caam/desc.h
+@@ -1704,4 +1704,31 @@
+ /* Frame Descriptor Command for Replacement Job Descriptor */
+ #define FD_CMD_REPLACE_JOB_DESC                               0x20000000
++/* CHA Control Register bits */
++#define CCTRL_RESET_CHA_ALL          0x1
++#define CCTRL_RESET_CHA_AESA         0x2
++#define CCTRL_RESET_CHA_DESA         0x4
++#define CCTRL_RESET_CHA_AFHA         0x8
++#define CCTRL_RESET_CHA_KFHA         0x10
++#define CCTRL_RESET_CHA_SF8A         0x20
++#define CCTRL_RESET_CHA_PKHA         0x40
++#define CCTRL_RESET_CHA_MDHA         0x80
++#define CCTRL_RESET_CHA_CRCA         0x100
++#define CCTRL_RESET_CHA_RNG          0x200
++#define CCTRL_RESET_CHA_SF9A         0x400
++#define CCTRL_RESET_CHA_ZUCE         0x800
++#define CCTRL_RESET_CHA_ZUCA         0x1000
++#define CCTRL_UNLOAD_PK_A0           0x10000
++#define CCTRL_UNLOAD_PK_A1           0x20000
++#define CCTRL_UNLOAD_PK_A2           0x40000
++#define CCTRL_UNLOAD_PK_A3           0x80000
++#define CCTRL_UNLOAD_PK_B0           0x100000
++#define CCTRL_UNLOAD_PK_B1           0x200000
++#define CCTRL_UNLOAD_PK_B2           0x400000
++#define CCTRL_UNLOAD_PK_B3           0x800000
++#define CCTRL_UNLOAD_PK_N            0x1000000
++#define CCTRL_UNLOAD_PK_A            0x4000000
++#define CCTRL_UNLOAD_PK_B            0x8000000
++#define CCTRL_UNLOAD_SBOX            0x10000000
++
+ #endif /* DESC_H */
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0029-crypto-caam-qi2-add-support-for-TLS-1.0-record.patch b/target/linux/layerscape/patches-5.4/804-crypto-0029-crypto-caam-qi2-add-support-for-TLS-1.0-record.patch
new file mode 100644 (file)
index 0000000..034c623
--- /dev/null
@@ -0,0 +1,545 @@
+From a97159ba48984bfec10abcea3a0215cf3deff153 Mon Sep 17 00:00:00 2001
+From: Radu Alexe <radu.alexe@nxp.com>
+Date: Fri, 9 Jun 2017 14:49:17 +0300
+Subject: [PATCH] crypto: caam/qi2 - add support for TLS 1.0 record
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+TLS 1.0 descriptors run on SEC 4.x or higher. For now, only
+tls10(hmac(sha1),cbc(aes)) algorithm is registered by the driver.
+
+Known limitations:
+ - when src == dst - there should be no element in the src scatterlist
+   array that contains both associated data and message data.
+ - when src != dst - associated data is not copied from source into
+   destination.
+ - for decryption when src != dst the size of the destination should be
+   large enough so that the buffer may contain the decrypted authenc and
+padded data.
+
+Signed-off-by: Radu Alexe <radu.alexe@nxp.com>
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/caamalg_qi2.c | 450 ++++++++++++++++++++++++++++++++++++++
+ drivers/crypto/caam/caamalg_qi2.h |  22 ++
+ 2 files changed, 472 insertions(+)
+
+--- a/drivers/crypto/caam/caamalg_qi2.c
++++ b/drivers/crypto/caam/caamalg_qi2.c
+@@ -583,6 +583,257 @@ skip_out_fle:
+       return edesc;
+ }
++static struct tls_edesc *tls_edesc_alloc(struct aead_request *req,
++                                       bool encrypt)
++{
++      struct crypto_aead *tls = crypto_aead_reqtfm(req);
++      unsigned int blocksize = crypto_aead_blocksize(tls);
++      unsigned int padsize, authsize;
++      struct caam_request *req_ctx = aead_request_ctx(req);
++      struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
++      struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
++      struct caam_ctx *ctx = crypto_aead_ctx(tls);
++      struct caam_aead_alg *alg = container_of(crypto_aead_alg(tls),
++                                               typeof(*alg), aead);
++      struct device *dev = ctx->dev;
++      gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
++                    GFP_KERNEL : GFP_ATOMIC;
++      int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0;
++      struct tls_edesc *edesc;
++      dma_addr_t qm_sg_dma, iv_dma = 0;
++      int ivsize = 0;
++      u8 *iv;
++      int qm_sg_index, qm_sg_ents = 0, qm_sg_bytes;
++      int in_len, out_len;
++      struct dpaa2_sg_entry *sg_table;
++      struct scatterlist *dst;
++
++      if (encrypt) {
++              padsize = blocksize - ((req->cryptlen + ctx->authsize) %
++                                      blocksize);
++              authsize = ctx->authsize + padsize;
++      } else {
++              authsize = ctx->authsize;
++      }
++
++      /* allocate space for base edesc, link tables and IV */
++      edesc = qi_cache_zalloc(GFP_DMA | flags);
++      if (unlikely(!edesc)) {
++              dev_err(dev, "could not allocate extended descriptor\n");
++              return ERR_PTR(-ENOMEM);
++      }
++
++      if (likely(req->src == req->dst)) {
++              src_nents = sg_nents_for_len(req->src, req->assoclen +
++                                           req->cryptlen +
++                                           (encrypt ? authsize : 0));
++              if (unlikely(src_nents < 0)) {
++                      dev_err(dev, "Insufficient bytes (%d) in src S/G\n",
++                              req->assoclen + req->cryptlen +
++                              (encrypt ? authsize : 0));
++                      qi_cache_free(edesc);
++                      return ERR_PTR(src_nents);
++              }
++
++              mapped_src_nents = dma_map_sg(dev, req->src, src_nents,
++                                            DMA_BIDIRECTIONAL);
++              if (unlikely(!mapped_src_nents)) {
++                      dev_err(dev, "unable to map source\n");
++                      qi_cache_free(edesc);
++                      return ERR_PTR(-ENOMEM);
++              }
++              dst = req->dst;
++      } else {
++              src_nents = sg_nents_for_len(req->src, req->assoclen +
++                                           req->cryptlen);
++              if (unlikely(src_nents < 0)) {
++                      dev_err(dev, "Insufficient bytes (%d) in src S/G\n",
++                              req->assoclen + req->cryptlen);
++                      qi_cache_free(edesc);
++                      return ERR_PTR(src_nents);
++              }
++
++              dst = scatterwalk_ffwd(edesc->tmp, req->dst, req->assoclen);
++              dst_nents = sg_nents_for_len(dst, req->cryptlen +
++                                           (encrypt ? authsize : 0));
++              if (unlikely(dst_nents < 0)) {
++                      dev_err(dev, "Insufficient bytes (%d) in dst S/G\n",
++                              req->cryptlen +
++                              (encrypt ? authsize : 0));
++                      qi_cache_free(edesc);
++                      return ERR_PTR(dst_nents);
++              }
++
++              if (src_nents) {
++                      mapped_src_nents = dma_map_sg(dev, req->src,
++                                                    src_nents, DMA_TO_DEVICE);
++                      if (unlikely(!mapped_src_nents)) {
++                              dev_err(dev, "unable to map source\n");
++                              qi_cache_free(edesc);
++                              return ERR_PTR(-ENOMEM);
++                      }
++              } else {
++                      mapped_src_nents = 0;
++              }
++
++              mapped_dst_nents = dma_map_sg(dev, dst, dst_nents,
++                                            DMA_FROM_DEVICE);
++              if (unlikely(!mapped_dst_nents)) {
++                      dev_err(dev, "unable to map destination\n");
++                      dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE);
++                      qi_cache_free(edesc);
++                      return ERR_PTR(-ENOMEM);
++              }
++      }
++
++      /*
++       * Create S/G table: IV, src, dst.
++       * Input is not contiguous.
++       */
++      qm_sg_ents = 1 + mapped_src_nents +
++                   (mapped_dst_nents > 1 ? mapped_dst_nents : 0);
++      sg_table = &edesc->sgt[0];
++      qm_sg_bytes = qm_sg_ents * sizeof(*sg_table);
++
++      ivsize = crypto_aead_ivsize(tls);
++      iv = (u8 *)(sg_table + qm_sg_ents);
++      /* Make sure IV is located in a DMAable area */
++      memcpy(iv, req->iv, ivsize);
++      iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE);
++      if (dma_mapping_error(dev, iv_dma)) {
++              dev_err(dev, "unable to map IV\n");
++              caam_unmap(dev, req->src, dst, src_nents, dst_nents, 0, 0,
++              DMA_NONE, 0, 0);
++              qi_cache_free(edesc);
++              return ERR_PTR(-ENOMEM);
++      }
++
++      edesc->src_nents = src_nents;
++      edesc->dst_nents = dst_nents;
++      edesc->dst = dst;
++      edesc->iv_dma = iv_dma;
++
++      dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0);
++      qm_sg_index = 1;
++
++      sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + qm_sg_index, 0);
++      qm_sg_index += mapped_src_nents;
++
++      if (mapped_dst_nents > 1)
++              sg_to_qm_sg_last(dst, mapped_dst_nents, sg_table +
++                               qm_sg_index, 0);
++
++      qm_sg_dma = dma_map_single(dev, sg_table, qm_sg_bytes, DMA_TO_DEVICE);
++      if (dma_mapping_error(dev, qm_sg_dma)) {
++              dev_err(dev, "unable to map S/G table\n");
++              caam_unmap(dev, req->src, dst, src_nents, dst_nents, iv_dma,
++                         ivsize, DMA_TO_DEVICE, 0, 0);
++              qi_cache_free(edesc);
++              return ERR_PTR(-ENOMEM);
++      }
++
++      edesc->qm_sg_dma = qm_sg_dma;
++      edesc->qm_sg_bytes = qm_sg_bytes;
++
++      out_len = req->cryptlen + (encrypt ? authsize : 0);
++      in_len = ivsize + req->assoclen + req->cryptlen;
++
++      memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
++      dpaa2_fl_set_final(in_fle, true);
++      dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
++      dpaa2_fl_set_addr(in_fle, qm_sg_dma);
++      dpaa2_fl_set_len(in_fle, in_len);
++
++      if (req->dst == req->src) {
++              dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
++              dpaa2_fl_set_addr(out_fle, qm_sg_dma +
++                                (sg_nents_for_len(req->src, req->assoclen) +
++                                 1) * sizeof(*sg_table));
++      } else if (mapped_dst_nents == 1) {
++              dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
++              dpaa2_fl_set_addr(out_fle, sg_dma_address(dst));
++      } else {
++              dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
++              dpaa2_fl_set_addr(out_fle, qm_sg_dma + qm_sg_index *
++                                sizeof(*sg_table));
++      }
++
++      dpaa2_fl_set_len(out_fle, out_len);
++
++      return edesc;
++}
++
++static int tls_set_sh_desc(struct crypto_aead *tls)
++{
++      struct caam_ctx *ctx = crypto_aead_ctx(tls);
++      unsigned int ivsize = crypto_aead_ivsize(tls);
++      unsigned int blocksize = crypto_aead_blocksize(tls);
++      struct device *dev = ctx->dev;
++      struct dpaa2_caam_priv *priv = dev_get_drvdata(dev);
++      struct caam_flc *flc;
++      u32 *desc;
++      unsigned int assoclen = 13; /* always 13 bytes for TLS */
++      unsigned int data_len[2];
++      u32 inl_mask;
++
++      if (!ctx->cdata.keylen || !ctx->authsize)
++              return 0;
++
++      /*
++       * TLS 1.0 encrypt shared descriptor
++       * Job Descriptor and Shared Descriptor
++       * must fit into the 64-word Descriptor h/w Buffer
++       */
++      data_len[0] = ctx->adata.keylen_pad;
++      data_len[1] = ctx->cdata.keylen;
++
++      if (desc_inline_query(DESC_TLS10_ENC_LEN, DESC_JOB_IO_LEN, data_len,
++                            &inl_mask, ARRAY_SIZE(data_len)) < 0)
++              return -EINVAL;
++
++      if (inl_mask & 1)
++              ctx->adata.key_virt = ctx->key;
++      else
++              ctx->adata.key_dma = ctx->key_dma;
++
++      if (inl_mask & 2)
++              ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad;
++      else
++              ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad;
++
++      ctx->adata.key_inline = !!(inl_mask & 1);
++      ctx->cdata.key_inline = !!(inl_mask & 2);
++
++      flc = &ctx->flc[ENCRYPT];
++      desc = flc->sh_desc;
++      cnstr_shdsc_tls_encap(desc, &ctx->cdata, &ctx->adata,
++                            assoclen, ivsize, ctx->authsize, blocksize,
++                            priv->sec_attr.era);
++      flc->flc[1] = cpu_to_caam32(desc_len(desc));
++      dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
++                                 sizeof(flc->flc) + desc_bytes(desc),
++                                 ctx->dir);
++
++      /*
++       * TLS 1.0 decrypt shared descriptor
++       * Keys do not fit inline, regardless of algorithms used
++       */
++      ctx->adata.key_inline = false;
++      ctx->adata.key_dma = ctx->key_dma;
++      ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad;
++
++      flc = &ctx->flc[DECRYPT];
++      desc = flc->sh_desc;
++      cnstr_shdsc_tls_decap(desc, &ctx->cdata, &ctx->adata, assoclen, ivsize,
++                            ctx->authsize, blocksize, priv->sec_attr.era);
++      flc->flc[1] = cpu_to_caam32(desc_len(desc));
++      dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
++                                 sizeof(flc->flc) + desc_bytes(desc),
++                                 ctx->dir);
++
++      return 0;
++}
++
+ static int chachapoly_set_sh_desc(struct crypto_aead *aead)
+ {
+       struct caam_ctx *ctx = crypto_aead_ctx(aead);
+@@ -627,6 +878,61 @@ static int chachapoly_setauthsize(struct
+       return chachapoly_set_sh_desc(aead);
+ }
++static int tls_setkey(struct crypto_aead *tls, const u8 *key,
++                    unsigned int keylen)
++{
++      struct caam_ctx *ctx = crypto_aead_ctx(tls);
++      struct device *dev = ctx->dev;
++      struct crypto_authenc_keys keys;
++
++      if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
++              goto badkey;
++
++#ifdef DEBUG
++      dev_err(dev, "keylen %d enckeylen %d authkeylen %d\n",
++              keys.authkeylen + keys.enckeylen, keys.enckeylen,
++              keys.authkeylen);
++      print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
++                     DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
++#endif
++
++      ctx->adata.keylen = keys.authkeylen;
++      ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype &
++                                            OP_ALG_ALGSEL_MASK);
++
++      if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE)
++              goto badkey;
++
++      memcpy(ctx->key, keys.authkey, keys.authkeylen);
++      memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen);
++      dma_sync_single_for_device(dev, ctx->key_dma, ctx->adata.keylen_pad +
++                                 keys.enckeylen, ctx->dir);
++#ifdef DEBUG
++      print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ",
++                     DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
++                     ctx->adata.keylen_pad + keys.enckeylen, 1);
++#endif
++
++      ctx->cdata.keylen = keys.enckeylen;
++
++      memzero_explicit(&keys, sizeof(keys));
++      return tls_set_sh_desc(tls);
++badkey:
++      crypto_aead_set_flags(tls, CRYPTO_TFM_RES_BAD_KEY_LEN);
++      memzero_explicit(&keys, sizeof(keys));
++      return -EINVAL;
++}
++
++static int tls_setauthsize(struct crypto_aead *tls, unsigned int authsize)
++{
++      struct caam_ctx *ctx = crypto_aead_ctx(tls);
++
++      ctx->authsize = authsize;
++      tls_set_sh_desc(tls);
++
++      return 0;
++}
++
+ static int chachapoly_setkey(struct crypto_aead *aead, const u8 *key,
+                            unsigned int keylen)
+ {
+@@ -1274,6 +1580,17 @@ static void aead_unmap(struct device *de
+       dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE);
+ }
++static void tls_unmap(struct device *dev, struct tls_edesc *edesc,
++                    struct aead_request *req)
++{
++      struct crypto_aead *tls = crypto_aead_reqtfm(req);
++      int ivsize = crypto_aead_ivsize(tls);
++
++      caam_unmap(dev, req->src, edesc->dst, edesc->src_nents,
++                 edesc->dst_nents, edesc->iv_dma, ivsize, DMA_TO_DEVICE,
++                 edesc->qm_sg_dma, edesc->qm_sg_bytes);
++}
++
+ static void skcipher_unmap(struct device *dev, struct skcipher_edesc *edesc,
+                          struct skcipher_request *req)
+ {
+@@ -1383,6 +1700,119 @@ static int aead_decrypt(struct aead_requ
+       return ret;
+ }
++static void tls_encrypt_done(void *cbk_ctx, u32 status)
++{
++      struct crypto_async_request *areq = cbk_ctx;
++      struct aead_request *req = container_of(areq, struct aead_request,
++                                              base);
++      struct caam_request *req_ctx = to_caam_req(areq);
++      struct tls_edesc *edesc = req_ctx->edesc;
++      struct crypto_aead *tls = crypto_aead_reqtfm(req);
++      struct caam_ctx *ctx = crypto_aead_ctx(tls);
++      int ecode = 0;
++
++#ifdef DEBUG
++      dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
++#endif
++
++      if (unlikely(status)) {
++              caam_qi2_strstatus(ctx->dev, status);
++              ecode = -EIO;
++      }
++
++      tls_unmap(ctx->dev, edesc, req);
++      qi_cache_free(edesc);
++      aead_request_complete(req, ecode);
++}
++
++static void tls_decrypt_done(void *cbk_ctx, u32 status)
++{
++      struct crypto_async_request *areq = cbk_ctx;
++      struct aead_request *req = container_of(areq, struct aead_request,
++                                              base);
++      struct caam_request *req_ctx = to_caam_req(areq);
++      struct tls_edesc *edesc = req_ctx->edesc;
++      struct crypto_aead *tls = crypto_aead_reqtfm(req);
++      struct caam_ctx *ctx = crypto_aead_ctx(tls);
++      int ecode = 0;
++
++#ifdef DEBUG
++      dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
++#endif
++
++      if (unlikely(status)) {
++              caam_qi2_strstatus(ctx->dev, status);
++              /*
++               * verify hw auth check passed else return -EBADMSG
++               */
++              if ((status & JRSTA_CCBERR_ERRID_MASK) ==
++                   JRSTA_CCBERR_ERRID_ICVCHK)
++                      ecode = -EBADMSG;
++              else
++                      ecode = -EIO;
++      }
++
++      tls_unmap(ctx->dev, edesc, req);
++      qi_cache_free(edesc);
++      aead_request_complete(req, ecode);
++}
++
++static int tls_encrypt(struct aead_request *req)
++{
++      struct tls_edesc *edesc;
++      struct crypto_aead *tls = crypto_aead_reqtfm(req);
++      struct caam_ctx *ctx = crypto_aead_ctx(tls);
++      struct caam_request *caam_req = aead_request_ctx(req);
++      int ret;
++
++      /* allocate extended descriptor */
++      edesc = tls_edesc_alloc(req, true);
++      if (IS_ERR(edesc))
++              return PTR_ERR(edesc);
++
++      caam_req->flc = &ctx->flc[ENCRYPT];
++      caam_req->flc_dma = ctx->flc_dma[ENCRYPT];
++      caam_req->cbk = tls_encrypt_done;
++      caam_req->ctx = &req->base;
++      caam_req->edesc = edesc;
++      ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
++      if (ret != -EINPROGRESS &&
++          !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
++              tls_unmap(ctx->dev, edesc, req);
++              qi_cache_free(edesc);
++      }
++
++      return ret;
++}
++
++static int tls_decrypt(struct aead_request *req)
++{
++      struct tls_edesc *edesc;
++      struct crypto_aead *tls = crypto_aead_reqtfm(req);
++      struct caam_ctx *ctx = crypto_aead_ctx(tls);
++      struct caam_request *caam_req = aead_request_ctx(req);
++      int ret;
++
++      /* allocate extended descriptor */
++      edesc = tls_edesc_alloc(req, false);
++      if (IS_ERR(edesc))
++              return PTR_ERR(edesc);
++
++      caam_req->flc = &ctx->flc[DECRYPT];
++      caam_req->flc_dma = ctx->flc_dma[DECRYPT];
++      caam_req->cbk = tls_decrypt_done;
++      caam_req->ctx = &req->base;
++      caam_req->edesc = edesc;
++      ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
++      if (ret != -EINPROGRESS &&
++          !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
++              tls_unmap(ctx->dev, edesc, req);
++              qi_cache_free(edesc);
++      }
++
++      return ret;
++}
++
+ static int ipsec_gcm_encrypt(struct aead_request *req)
+ {
+       return crypto_ipsec_check_assoclen(req->assoclen) ? : aead_encrypt(req);
+@@ -2929,6 +3359,26 @@ static struct caam_aead_alg driver_aeads
+                       .geniv = true,
+               },
+       },
++      {
++              .aead = {
++                      .base = {
++                              .cra_name = "tls10(hmac(sha1),cbc(aes))",
++                              .cra_driver_name = "tls10-hmac-sha1-cbc-aes-caam-qi2",
++                              .cra_blocksize = AES_BLOCK_SIZE,
++                      },
++                      .setkey = tls_setkey,
++                      .setauthsize = tls_setauthsize,
++                      .encrypt = tls_encrypt,
++                      .decrypt = tls_decrypt,
++                      .ivsize = AES_BLOCK_SIZE,
++                      .maxauthsize = SHA1_DIGEST_SIZE,
++              },
++              .caam = {
++                      .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++                      .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
++                                         OP_ALG_AAI_HMAC_PRECOMP,
++              },
++      },
+ };
+ static void caam_skcipher_alg_init(struct caam_skcipher_alg *t_alg)
+--- a/drivers/crypto/caam/caamalg_qi2.h
++++ b/drivers/crypto/caam/caamalg_qi2.h
+@@ -118,6 +118,28 @@ struct aead_edesc {
+ };
+ /*
++ * tls_edesc - s/w-extended tls descriptor
++ * @src_nents: number of segments in input scatterlist
++ * @dst_nents: number of segments in output scatterlist
++ * @iv_dma: dma address of iv for checking continuity and link table
++ * @qm_sg_bytes: length of dma mapped h/w link table
++ * @qm_sg_dma: bus physical mapped address of h/w link table
++ * @tmp: array of scatterlists used by 'scatterwalk_ffwd'
++ * @dst: pointer to output scatterlist, usefull for unmapping
++ * @sgt: the h/w link table, followed by IV
++ */
++struct tls_edesc {
++      int src_nents;
++      int dst_nents;
++      dma_addr_t iv_dma;
++      int qm_sg_bytes;
++      dma_addr_t qm_sg_dma;
++      struct scatterlist tmp[2];
++      struct scatterlist *dst;
++      struct dpaa2_sg_entry sgt[0];
++};
++
++/*
+  * skcipher_edesc - s/w-extended skcipher descriptor
+  * @src_nents: number of segments in input scatterlist
+  * @dst_nents: number of segments in output scatterlist
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0030-crypto-caam-add-functionality-used-by-the-caam_dma-d.patch b/target/linux/layerscape/patches-5.4/804-crypto-0030-crypto-caam-add-functionality-used-by-the-caam_dma-d.patch
new file mode 100644 (file)
index 0000000..6e43239
--- /dev/null
@@ -0,0 +1,122 @@
+From 20f552cafd7dda6f5d25128bbc04ea2c91d9f5d1 Mon Sep 17 00:00:00 2001
+From: Radu Alexe <radu.alexe@nxp.com>
+Date: Thu, 26 Oct 2017 10:45:14 +0300
+Subject: [PATCH] crypto: caam - add functionality used by the caam_dma driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The caam_dma is a memcpy DMA driver based on the DMA functionality of
+the CAAM hardware block. It creates a DMA channel for each JR of the
+CAAM. This patch adds functionality that is used by the caam_dma that is
+not yet part of the JR driver.
+
+Signed-off-by: Radu Alexe <radu.alexe@nxp.com>
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/desc.h |  2 ++
+ drivers/crypto/caam/jr.c   | 41 +++++++++++++++++++++++++++++++++++++++++
+ drivers/crypto/caam/jr.h   |  2 ++
+ 3 files changed, 45 insertions(+)
+
+--- a/drivers/crypto/caam/desc.h
++++ b/drivers/crypto/caam/desc.h
+@@ -364,6 +364,7 @@
+ #define FIFOLD_TYPE_PK_N      (0x08 << FIFOLD_TYPE_SHIFT)
+ #define FIFOLD_TYPE_PK_A      (0x0c << FIFOLD_TYPE_SHIFT)
+ #define FIFOLD_TYPE_PK_B      (0x0d << FIFOLD_TYPE_SHIFT)
++#define FIFOLD_TYPE_IFIFO     (0x0f << FIFOLD_TYPE_SHIFT)
+ /* Other types. Need to OR in last/flush bits as desired */
+ #define FIFOLD_TYPE_MSG_MASK  (0x38 << FIFOLD_TYPE_SHIFT)
+@@ -1522,6 +1523,7 @@
+ #define MATH_SRC1_INFIFO      (0x0a << MATH_SRC1_SHIFT)
+ #define MATH_SRC1_OUTFIFO     (0x0b << MATH_SRC1_SHIFT)
+ #define MATH_SRC1_ONE         (0x0c << MATH_SRC1_SHIFT)
++#define MATH_SRC1_ZERO                (0x0f << MATH_SRC1_SHIFT)
+ /* Destination selectors */
+ #define MATH_DEST_SHIFT               8
+--- a/drivers/crypto/caam/jr.c
++++ b/drivers/crypto/caam/jr.c
+@@ -62,6 +62,14 @@ algs_unlock:
+       mutex_unlock(&algs_lock);
+ }
++static int jr_driver_probed;
++
++int caam_jr_driver_probed(void)
++{
++      return jr_driver_probed;
++}
++EXPORT_SYMBOL(caam_jr_driver_probed);
++
+ static int caam_reset_hw_jr(struct device *dev)
+ {
+       struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+@@ -147,6 +155,8 @@ static int caam_jr_remove(struct platfor
+       if (ret)
+               dev_err(jrdev, "Failed to shut down job ring\n");
++      jr_driver_probed--;
++
+       return ret;
+ }
+@@ -311,6 +321,36 @@ struct device *caam_jr_alloc(void)
+ EXPORT_SYMBOL(caam_jr_alloc);
+ /**
++ * caam_jridx_alloc() - Alloc a specific job ring based on its index.
++ *
++ * returns :  pointer to the newly allocated physical
++ *          JobR dev can be written to if successful.
++ **/
++struct device *caam_jridx_alloc(int idx)
++{
++      struct caam_drv_private_jr *jrpriv;
++      struct device *dev = ERR_PTR(-ENODEV);
++
++      spin_lock(&driver_data.jr_alloc_lock);
++
++      if (list_empty(&driver_data.jr_list))
++              goto end;
++
++      list_for_each_entry(jrpriv, &driver_data.jr_list, list_node) {
++              if (jrpriv->ridx == idx) {
++                      atomic_inc(&jrpriv->tfm_count);
++                      dev = jrpriv->dev;
++                      break;
++              }
++      }
++
++end:
++      spin_unlock(&driver_data.jr_alloc_lock);
++      return dev;
++}
++EXPORT_SYMBOL(caam_jridx_alloc);
++
++/**
+  * caam_jr_free() - Free the Job Ring
+  * @rdev     - points to the dev that identifies the Job ring to
+  *             be released.
+@@ -565,6 +605,7 @@ static int caam_jr_probe(struct platform
+       device_set_wakeup_enable(&pdev->dev, false);
+       register_algs(jrdev->parent);
++      jr_driver_probed++;
+       return 0;
+ }
+--- a/drivers/crypto/caam/jr.h
++++ b/drivers/crypto/caam/jr.h
+@@ -9,7 +9,9 @@
+ #define JR_H
+ /* Prototypes for backend-level services exposed to APIs */
++int caam_jr_driver_probed(void);
+ struct device *caam_jr_alloc(void);
++struct device *caam_jridx_alloc(int idx);
+ void caam_jr_free(struct device *rdev);
+ int caam_jr_enqueue(struct device *dev, u32 *desc,
+                   void (*cbk)(struct device *dev, u32 *desc, u32 status,
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0031-crypto-caam-add-caam_dma-device-on-caam_probe.patch b/target/linux/layerscape/patches-5.4/804-crypto-0031-crypto-caam-add-caam_dma-device-on-caam_probe.patch
new file mode 100644 (file)
index 0000000..1dca71c
--- /dev/null
@@ -0,0 +1,67 @@
+From 0547020c73ab7a457f3e1601ef822b61f0b963b9 Mon Sep 17 00:00:00 2001
+From: Radu Alexe <radu.alexe@nxp.com>
+Date: Wed, 8 Nov 2017 17:22:12 +0200
+Subject: [PATCH] crypto: caam - add caam_dma device on caam_probe
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Dynamically create a platform device for the caam_dma driver
+at caam_probe() time.
+
+Signed-off-by: Radu Alexe <radu.alexe@nxp.com>
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+
+Use devres for caam_dma platform device unregistering.
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/ctrl.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -566,12 +566,22 @@ static void caam_remove_debugfs(void *ro
+ }
+ #endif
++static void caam_dma_dev_unregister(void *data)
++{
++      platform_device_unregister(data);
++}
++
+ /* Probe routine for CAAM top (controller) level */
+ static int caam_probe(struct platform_device *pdev)
+ {
+       int ret, ring, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN;
+       u64 caam_id;
+       const struct soc_device_attribute *imx_soc_match;
++      static struct platform_device_info caam_dma_pdev_info = {
++              .name = "caam-dma",
++              .id = PLATFORM_DEVID_NONE
++      };
++      static struct platform_device *caam_dma_dev;
+       struct device *dev;
+       struct device_node *nprop, *np;
+       struct resource res_regs;
+@@ -849,6 +859,20 @@ set_dma_mask:
+               return -ENOMEM;
+       }
++      caam_dma_pdev_info.parent = dev;
++      caam_dma_pdev_info.dma_mask = dma_get_mask(dev);
++      caam_dma_dev = platform_device_register_full(&caam_dma_pdev_info);
++      if (IS_ERR(caam_dma_dev)) {
++              dev_err(dev, "Unable to create and register caam-dma dev\n");
++              return PTR_ERR(caam_dma_dev);
++      } else {
++              set_dma_ops(&caam_dma_dev->dev, get_dma_ops(dev));
++              ret = devm_add_action_or_reset(dev, caam_dma_dev_unregister,
++                                             caam_dma_dev);
++              if (ret)
++                      return ret;
++      }
++
+       if (!reg_access)
+               goto report_live;
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0032-crypto-caam-add-CAAM-job-ring-UIO-support.patch b/target/linux/layerscape/patches-5.4/804-crypto-0032-crypto-caam-add-CAAM-job-ring-UIO-support.patch
new file mode 100644 (file)
index 0000000..469fb2e
--- /dev/null
@@ -0,0 +1,337 @@
+From 8b60a441202cb5c6b5264dbee633fcb24414bab4 Mon Sep 17 00:00:00 2001
+From: Sandeep Malik <Sandeep.Malik@nxp.com>
+Date: Wed, 15 Nov 2017 17:16:13 +0530
+Subject: [PATCH] crypto: caam - add CAAM job ring UIO support
+
+This patch add the support for job ring UIO so
+that userspace drivers can have access to the
+caam job rings
+
+Signed-off-by: Sandeep Malik <Sandeep.Malik@nxp.com>
+Signed-off-by: Gagandeep Singh <g.singh@nxp.com>
+---
+ drivers/crypto/caam/Kconfig      |  11 ++
+ drivers/crypto/caam/Makefile     |   1 +
+ drivers/crypto/caam/fsl_jr_uio.c | 256 +++++++++++++++++++++++++++++++++++++++
+ drivers/crypto/caam/fsl_jr_uio.h |  25 ++++
+ 4 files changed, 293 insertions(+)
+ create mode 100644 drivers/crypto/caam/fsl_jr_uio.c
+ create mode 100644 drivers/crypto/caam/fsl_jr_uio.h
+
+--- a/drivers/crypto/caam/Kconfig
++++ b/drivers/crypto/caam/Kconfig
+@@ -202,6 +202,17 @@ config CRYPTO_DEV_FSL_CAAM_SECVIO
+           handler functions which can be specified to act on the consequences
+           of a security violation.
++config CRYPTO_DEV_FSL_CAAM_JR_UIO
++      tristate "Freescale Job Ring UIO support"
++      depends on UIO
++      default y
++      help
++        Selecting this will allow job ring UIO support for
++        Userspace drivers
++
++        To compile this as a module, choose M here: the module
++        will be called fsl_jr_uio.
++
+ endif # CRYPTO_DEV_FSL_CAAM_JR
+ endif # CRYPTO_DEV_FSL_CAAM
+--- a/drivers/crypto/caam/Makefile
++++ b/drivers/crypto/caam/Makefile
+@@ -13,6 +13,7 @@ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caa
+ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR) += caam_jr.o
+ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC) += caamalg_desc.o
+ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC) += caamhash_desc.o
++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR_UIO) += fsl_jr_uio.o
+ caam-y := ctrl.o
+ caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API) += tag_object.o
+--- /dev/null
++++ b/drivers/crypto/caam/fsl_jr_uio.c
+@@ -0,0 +1,256 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright 2013 Freescale Semiconductor, Inc.
++ * Copyright 2018 NXP
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/of_platform.h>
++#include <linux/io.h>
++#include <linux/uio_driver.h>
++#include <linux/slab.h>
++#include <linux/list.h>
++#include "regs.h"
++#include "fsl_jr_uio.h"
++
++static const char jr_uio_version[] = "fsl JR UIO driver v1.0";
++
++#define NAME_LENGTH 30
++#define JR_INDEX_OFFSET 12
++
++static const char uio_device_name[] = "fsl-jr";
++static LIST_HEAD(jr_list);
++
++struct jr_uio_info {
++      atomic_t ref; /* exclusive, only one open() at a time */
++      struct uio_info uio;
++      char name[NAME_LENGTH];
++};
++
++struct jr_dev {
++      u32 revision;
++      u32 index;
++      u32 irq;
++      struct caam_job_ring __iomem *global_regs;
++      struct device *dev;
++      struct resource *res;
++      struct jr_uio_info info;
++      struct list_head node;
++      struct list_head jr_list;
++};
++
++static int jr_uio_open(struct uio_info *info, struct inode *inode)
++{
++      struct jr_uio_info *uio_info = container_of(info,
++                                      struct jr_uio_info, uio);
++
++      if (!atomic_dec_and_test(&uio_info->ref)) {
++              pr_err("%s: failing non-exclusive open()\n", uio_info->name);
++              atomic_inc(&uio_info->ref);
++              return -EBUSY;
++      }
++
++      return 0;
++}
++
++static int jr_uio_release(struct uio_info *info, struct inode *inode)
++{
++      struct jr_uio_info *uio_info = container_of(info,
++                                      struct jr_uio_info, uio);
++      atomic_inc(&uio_info->ref);
++
++      return 0;
++}
++
++static irqreturn_t jr_uio_irq_handler(int irq, struct uio_info *dev_info)
++{
++      struct jr_dev *jrdev = dev_info->priv;
++      u32 irqstate;
++
++      irqstate = rd_reg32(&jrdev->global_regs->jrintstatus);
++
++      if (!irqstate)
++              return IRQ_NONE;
++
++      if (irqstate & JRINT_JR_ERROR)
++              dev_info(jrdev->dev, "uio job ring error - irqstate: %08x\n",
++                       irqstate);
++
++      /*mask valid interrupts */
++      clrsetbits_32(&jrdev->global_regs->rconfig_lo, 0, JRCFG_IMSK);
++
++      /* Have valid interrupt at this point, just ACK and trigger */
++      wr_reg32(&jrdev->global_regs->jrintstatus, irqstate);
++
++      return IRQ_HANDLED;
++}
++
++static int jr_uio_irqcontrol(struct uio_info *dev_info, int irqon)
++{
++      struct jr_dev *jrdev = dev_info->priv;
++
++      switch (irqon) {
++      case SEC_UIO_SIMULATE_IRQ_CMD:
++              uio_event_notify(dev_info);
++              break;
++      case SEC_UIO_ENABLE_IRQ_CMD:
++              /* Enable Job Ring interrupt */
++              clrsetbits_32(&jrdev->global_regs->rconfig_lo, JRCFG_IMSK, 0);
++              break;
++      case SEC_UIO_DISABLE_IRQ_CMD:
++              /* Disable Job Ring interrupt */
++              clrsetbits_32(&jrdev->global_regs->rconfig_lo, 0, JRCFG_IMSK);
++              break;
++      default:
++              break;
++      }
++      return 0;
++}
++
++static int __init jr_uio_init(struct jr_dev *uio_dev)
++{
++      int ret;
++      struct jr_uio_info *info;
++
++      info = &uio_dev->info;
++      atomic_set(&info->ref, 1);
++      info->uio.version = jr_uio_version;
++      info->uio.name = uio_dev->info.name;
++      info->uio.mem[0].name = "JR config space";
++      info->uio.mem[0].addr = uio_dev->res->start;
++      info->uio.mem[0].size = uio_dev->res->end - uio_dev->res->start + 1;
++      info->uio.mem[0].internal_addr = uio_dev->global_regs;
++      info->uio.mem[0].memtype = UIO_MEM_PHYS;
++      info->uio.irq = uio_dev->irq;
++      info->uio.irq_flags = IRQF_SHARED;
++      info->uio.handler = jr_uio_irq_handler;
++      info->uio.irqcontrol = jr_uio_irqcontrol;
++      info->uio.open = jr_uio_open;
++      info->uio.release = jr_uio_release;
++      info->uio.priv = uio_dev;
++
++      ret = uio_register_device(uio_dev->dev, &info->uio);
++      if (ret) {
++              dev_err(uio_dev->dev, "jr_uio: UIO registration failed\n");
++              return ret;
++      }
++
++      return 0;
++}
++
++static const struct of_device_id jr_ids[] = {
++      { .compatible = "fsl,sec-v4.0-job-ring", },
++      { .compatible = "fsl,sec-v4.4-job-ring", },
++      { .compatible = "fsl,sec-v5.0-job-ring", },
++      { .compatible = "fsl,sec-v6.0-job-ring", },
++      {},
++};
++
++static int fsl_jr_probe(struct platform_device *dev)
++{
++      struct resource regs;
++      struct jr_dev *jr_dev;
++      struct device_node *jr_node;
++      int ret, count = 0;
++      struct list_head *p;
++
++      jr_node = dev->dev.of_node;
++      if (!jr_node) {
++              dev_err(&dev->dev, "Device OF-Node is NULL\n");
++              return -EFAULT;
++      }
++
++      jr_dev = devm_kzalloc(&dev->dev, sizeof(*jr_dev), GFP_KERNEL);
++      if (!jr_dev)
++              return -ENOMEM;
++
++      /* Creat name and index */
++      list_for_each(p, &jr_list) {
++              count++;
++      }
++      jr_dev->index = count;
++
++      snprintf(jr_dev->info.name, sizeof(jr_dev->info.name) - 1,
++               "%s%d", uio_device_name, jr_dev->index);
++
++      jr_dev->dev = &dev->dev;
++      platform_set_drvdata(dev, jr_dev);
++
++      /* Get the resource from dtb node */
++      ret = of_address_to_resource(jr_node, 0, &regs);
++      if (unlikely(ret < 0)) {
++              dev_err(&dev->dev, "OF-Address-to-resource Failed\n");
++              ret = -EFAULT;
++              goto abort;
++      }
++
++      jr_dev->res = devm_request_mem_region(&dev->dev, regs.start,
++                                            regs.end - regs.start + 1,
++                                            jr_dev->info.name);
++      if (unlikely(!jr_dev->res)) {
++              dev_err(jr_dev->dev, "devm_request_mem_region failed\n");
++              ret = -ENOMEM;
++              goto abort;
++      }
++
++      jr_dev->global_regs =
++              devm_ioremap(&dev->dev, jr_dev->res->start,
++                           jr_dev->res->end - jr_dev->res->start + 1);
++      if (unlikely(jr_dev->global_regs == 0)) {
++              dev_err(jr_dev->dev, "devm_ioremap failed\n");
++              ret = -EIO;
++              goto abort;
++      }
++      jr_dev->irq = irq_of_parse_and_map(jr_node, 0);
++      dev_dbg(jr_dev->dev, "errirq: %d\n", jr_dev->irq);
++
++      /* Register UIO */
++      ret = jr_uio_init(jr_dev);
++      if (ret) {
++              dev_err(&dev->dev, "UIO init Failed\n");
++              goto abort;
++      }
++
++      list_add_tail(&jr_dev->node, &jr_list);
++
++      dev_info(jr_dev->dev, "UIO device full name %s initialized\n",
++               jr_dev->info.name);
++
++      return 0;
++
++abort:
++      return ret;
++}
++
++static int fsl_jr_remove(struct platform_device *dev)
++{
++      struct jr_dev *jr_dev = platform_get_drvdata(dev);
++
++      if (!jr_dev)
++              return 0;
++
++      list_del(&jr_dev->node);
++      uio_unregister_device(&jr_dev->info.uio);
++
++      return 0;
++}
++
++MODULE_DEVICE_TABLE(of, jr_ids);
++
++static struct platform_driver fsl_jr_driver = {
++      .driver = {
++              .name = "fsl-jr-uio",
++              .of_match_table = jr_ids,
++      },
++      .probe = fsl_jr_probe,
++      .remove = fsl_jr_remove,
++};
++
++module_platform_driver(fsl_jr_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("NXP");
++MODULE_DESCRIPTION("FSL SEC UIO Driver");
+--- /dev/null
++++ b/drivers/crypto/caam/fsl_jr_uio.h
+@@ -0,0 +1,25 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * CAAM Job RING UIO support header file
++ *
++ * Copyright 2013 Freescale Semiconductor, Inc
++ * Copyright 2018 NXP
++ */
++
++#ifndef FSL_JR_UIO_H
++#define FSL_JR_UIO_H
++
++/** UIO command used by user-space driver to request
++ *  disabling IRQs on a certain job ring
++ */
++#define SEC_UIO_DISABLE_IRQ_CMD         0
++/** UIO command used by user-space driver to request
++ *  enabling IRQs on a certain job ring
++ */
++#define SEC_UIO_ENABLE_IRQ_CMD          1
++/** UIO command used by user-space driver to request SEC kernel driver
++ *  to simulate that an IRQ is generated on a certain job ring
++ */
++#define SEC_UIO_SIMULATE_IRQ_CMD        2
++
++#endif
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0033-LFV-26-crypto-caam-fix-Secure-Memory-driver-init.patch b/target/linux/layerscape/patches-5.4/804-crypto-0033-LFV-26-crypto-caam-fix-Secure-Memory-driver-init.patch
new file mode 100644 (file)
index 0000000..8bece63
--- /dev/null
@@ -0,0 +1,274 @@
+From 1286c9b10f76b122ad1b328cc1bec17ac4d5908e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Horia=20Geant=C4=83?= <horia.geanta@nxp.com>
+Date: Wed, 13 Nov 2019 09:42:34 +0200
+Subject: [PATCH] LFV-26 crypto: caam - fix Secure Memory driver init
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+SM driver is buggy, since it runs irrespective of the presence of
+the caam-sm DT node.
+This causes issues on SoCs that have caam HW, but without support
+for secure memory.
+
+Let's transform the module in a library, in the same way (and for
+the same reasons) we did for the other job ring-dependent drivers
+(caamalg, caamhash etc.) in
+commit 1b46c90c8e00 ("crypto: caam - convert top level drivers to libraries")
+
+SM test module is also updated, to run only when needed.
+
+Fixes: 54e3fcf89f97 ("MLKU-25-3 crypto: caam - add Secure Memory support")
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+Reviewed-by: Iuliana Prodan <iuliana.prodan@nxp.com>
+---
+ drivers/crypto/caam/Kconfig    |  2 +-
+ drivers/crypto/caam/ctrl.c     |  2 ++
+ drivers/crypto/caam/intern.h   | 19 ++++++++++
+ drivers/crypto/caam/jr.c       |  6 ++--
+ drivers/crypto/caam/sm.h       |  1 -
+ drivers/crypto/caam/sm_store.c | 80 +++++-------------------------------------
+ drivers/crypto/caam/sm_test.c  |  7 ++++
+ 7 files changed, 42 insertions(+), 75 deletions(-)
+
+--- a/drivers/crypto/caam/Kconfig
++++ b/drivers/crypto/caam/Kconfig
+@@ -166,7 +166,7 @@ config CRYPTO_DEV_FSL_CAAM_RNG_TEST
+         just before the RNG is registered with the hw_random API.
+ config CRYPTO_DEV_FSL_CAAM_SM
+-      tristate "CAAM Secure Memory / Keystore API (EXPERIMENTAL)"
++      bool "CAAM Secure Memory / Keystore API (EXPERIMENTAL)"
+       help
+         Enables use of a prototype kernel-level Keystore API with CAAM
+         Secure Memory for insertion/extraction of bus-protected secrets.
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -763,6 +763,8 @@ iomap_ctrl:
+               ctrlpriv->sm_size = resource_size(&res_regs);
+       else
+               ctrlpriv->sm_size = PG_SIZE_64K;
++
++      ctrlpriv->sm_present = 1;
+       of_node_put(np);
+       if (!reg_access)
+--- a/drivers/crypto/caam/intern.h
++++ b/drivers/crypto/caam/intern.h
+@@ -86,6 +86,7 @@ struct caam_drv_private {
+        */
+       u8 total_jobrs;         /* Total Job Rings in device */
+       u8 qi_present;          /* Nonzero if QI present in device */
++      u8 sm_present;          /* Nonzero if Secure Memory is supported */
+       u8 mc_en;               /* Nonzero if MC f/w is active */
+       u8 scu_en;              /* Nonzero if SCU f/w is active */
+       u8 optee_en;            /* Nonzero if OP-TEE f/w is active */
+@@ -200,6 +201,24 @@ static inline void caam_qi_algapi_exit(v
+ #endif /* CONFIG_CAAM_QI */
++#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_SM
++
++int caam_sm_startup(struct device *dev);
++void caam_sm_shutdown(struct device *dev);
++
++#else
++
++static inline int caam_sm_startup(struct device *dev)
++{
++      return 0;
++}
++
++static inline void caam_sm_shutdown(struct device *dev)
++{
++}
++
++#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_SM */
++
+ #ifdef CONFIG_DEBUG_FS
+ static int caam_debugfs_u64_get(void *data, u64 *val)
+ {
+--- a/drivers/crypto/caam/jr.c
++++ b/drivers/crypto/caam/jr.c
+@@ -34,6 +34,7 @@ static void register_algs(struct device
+       if (++active_devs != 1)
+               goto algs_unlock;
++      caam_sm_startup(dev);
+       caam_algapi_init(dev);
+       caam_algapi_hash_init(dev);
+       caam_pkc_init(dev);
+@@ -44,7 +45,7 @@ algs_unlock:
+       mutex_unlock(&algs_lock);
+ }
+-static void unregister_algs(void)
++static void unregister_algs(struct device *dev)
+ {
+       mutex_lock(&algs_lock);
+@@ -57,6 +58,7 @@ static void unregister_algs(void)
+       caam_pkc_exit();
+       caam_algapi_hash_exit();
+       caam_algapi_exit();
++      caam_sm_shutdown(dev);
+ algs_unlock:
+       mutex_unlock(&algs_lock);
+@@ -143,7 +145,7 @@ static int caam_jr_remove(struct platfor
+       }
+       /* Unregister JR-based RNG & crypto algorithms */
+-      unregister_algs();
++      unregister_algs(jrdev->parent);
+       /* Remove the node from Physical JobR list maintained by driver */
+       spin_lock(&driver_data.jr_alloc_lock);
+--- a/drivers/crypto/caam/sm.h
++++ b/drivers/crypto/caam/sm.h
+@@ -41,7 +41,6 @@ void sm_init_keystore(struct device *dev
+ u32 sm_detect_keystore_units(struct device *dev);
+ int sm_establish_keystore(struct device *dev, u32 unit);
+ void sm_release_keystore(struct device *dev, u32 unit);
+-void caam_sm_shutdown(struct platform_device *pdev);
+ int caam_sm_example_init(struct platform_device *pdev);
+ /* Keystore accessor functions */
+--- a/drivers/crypto/caam/sm_store.c
++++ b/drivers/crypto/caam/sm_store.c
+@@ -1053,9 +1053,9 @@ EXPORT_SYMBOL(sm_keystore_slot_import);
+  * Also, simply uses ring 0 for execution at the present
+  */
+-int caam_sm_startup(struct platform_device *pdev)
++int caam_sm_startup(struct device *ctrldev)
+ {
+-      struct device *ctrldev, *smdev;
++      struct device *smdev;
+       struct caam_drv_private *ctrlpriv;
+       struct caam_drv_private_sm *smpriv;
+       struct caam_drv_private_jr *jrpriv;     /* need this for reg page */
+@@ -1065,17 +1065,10 @@ int caam_sm_startup(struct platform_devi
+       int ret = 0;
+       struct device_node *np;
+-      ctrldev = &pdev->dev;
+       ctrlpriv = dev_get_drvdata(ctrldev);
+-      /*
+-       * If ctrlpriv is NULL, it's probably because the caam driver wasn't
+-       * properly initialized (e.g. RNG4 init failed). Thus, bail out here.
+-       */
+-      if (!ctrlpriv) {
+-              ret = -ENODEV;
+-              goto exit;
+-      }
++      if (!ctrlpriv->sm_present)
++              return 0;
+       /*
+        * Set up the private block for secure memory
+@@ -1248,14 +1241,16 @@ exit:
+       return ret;
+ }
+-void caam_sm_shutdown(struct platform_device *pdev)
++void caam_sm_shutdown(struct device *ctrldev)
+ {
+-      struct device *ctrldev, *smdev;
++      struct device *smdev;
+       struct caam_drv_private *priv;
+       struct caam_drv_private_sm *smpriv;
+-      ctrldev = &pdev->dev;
+       priv = dev_get_drvdata(ctrldev);
++      if (!priv->sm_present)
++              return;
++
+       smdev = priv->smdev;
+       /* Return if resource not initialized by startup */
+@@ -1273,60 +1268,3 @@ void caam_sm_shutdown(struct platform_de
+       kfree(smpriv);
+ }
+ EXPORT_SYMBOL(caam_sm_shutdown);
+-
+-static void  __exit caam_sm_exit(void)
+-{
+-      struct device_node *dev_node;
+-      struct platform_device *pdev;
+-
+-      dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+-      if (!dev_node) {
+-              dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+-              if (!dev_node)
+-                      return;
+-      }
+-
+-      pdev = of_find_device_by_node(dev_node);
+-      if (!pdev)
+-              return;
+-
+-      of_node_put(dev_node);
+-
+-      caam_sm_shutdown(pdev);
+-
+-      return;
+-}
+-
+-static int __init caam_sm_init(void)
+-{
+-      struct device_node *dev_node;
+-      struct platform_device *pdev;
+-
+-      /*
+-       * Do of_find_compatible_node() then of_find_device_by_node()
+-       * once a functional device tree is available
+-       */
+-      dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+-      if (!dev_node) {
+-              dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+-              if (!dev_node)
+-                      return -ENODEV;
+-      }
+-
+-      pdev = of_find_device_by_node(dev_node);
+-      if (!pdev)
+-              return -ENODEV;
+-
+-      of_node_get(dev_node);
+-
+-      caam_sm_startup(pdev);
+-
+-      return 0;
+-}
+-
+-module_init(caam_sm_init);
+-module_exit(caam_sm_exit);
+-
+-MODULE_LICENSE("Dual BSD/GPL");
+-MODULE_DESCRIPTION("FSL CAAM Secure Memory / Keystore");
+-MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD");
+--- a/drivers/crypto/caam/sm_test.c
++++ b/drivers/crypto/caam/sm_test.c
+@@ -531,6 +531,7 @@ static int __init caam_sm_test_init(void
+ {
+       struct device_node *dev_node;
+       struct platform_device *pdev;
++      struct caam_drv_private *priv;
+       int ret;
+       /*
+@@ -550,6 +551,12 @@ static int __init caam_sm_test_init(void
+       of_node_put(dev_node);
++      priv = dev_get_drvdata(&pdev->dev);
++      if (!priv->sm_present) {
++              dev_info(&pdev->dev, "No SM support, skipping tests\n");
++              return -ENODEV;
++      }
++
+       ret = caam_sm_example_init(pdev);
+       if (ret)
+               dev_err(&pdev->dev, "SM test failed: %d\n", ret);
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0034-LF-63-1-crypto-caam-fix-SM-test-init.patch b/target/linux/layerscape/patches-5.4/804-crypto-0034-LF-63-1-crypto-caam-fix-SM-test-init.patch
new file mode 100644 (file)
index 0000000..04c14ca
--- /dev/null
@@ -0,0 +1,80 @@
+From 79aa6ebf9d0b982c859a0c1bec1d879ff3d9ad29 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Horia=20Geant=C4=83?= <horia.geanta@nxp.com>
+Date: Wed, 27 Nov 2019 12:30:41 +0200
+Subject: [PATCH] LF-63-1 crypto: caam - fix SM test init
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Commit 77debf316c44 ("LFV-26 crypto: caam - fix Secure Memory driver init")
+addressed SM driver initialization and also update SM test.
+
+However, the fix for SM test is insufficient.
+There are cases when SM test runs before SM driver, causing a crash
+due to uninitialized "priv" pointer being dereferenced.
+
+The fix consists in the following:
+
+1. Since SM test is a "bare" device driver (doesn't sit on any bus),
+there is no deferred probing support.
+Thus we have no choice (*) but to abort SM tests with a notification.
+
+(*) We don't want to force SM driver running first by means of
+init levels etc. Just KISS.
+
+2. SM test driver forced to being built only as a module
+Since SM test driver's only goal is to run SM tests, it doesn't make
+any sense to be built-in.
+Building the driver as a module allows for running the tests
+several times if needed (multiple modprobe & rmmod cycles).
+
+Note: from the perspective of wanting to test repetitively, it would
+make sense to force module unloading by returning an error code
+in the module_init function.
+However, this might affect test scripts (due to error code and/or
+message output by unsuccessful module loading), so we postpone
+this change for now.
+
+Fixes: d02fe599d7d5 ("MLKU-25-3 crypto: caam - add Secure Memory support")
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+Acked-by: Leonard Crestez <leonard.crestez@nxp.com>
+---
+ drivers/crypto/caam/Kconfig   | 1 +
+ drivers/crypto/caam/Makefile  | 2 +-
+ drivers/crypto/caam/sm_test.c | 4 ++++
+ 3 files changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/crypto/caam/Kconfig
++++ b/drivers/crypto/caam/Kconfig
+@@ -190,6 +190,7 @@ config CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE
+ config CRYPTO_DEV_FSL_CAAM_SM_TEST
+       tristate "CAAM Secure Memory - Keystore Test/Example (EXPERIMENTAL)"
+       depends on CRYPTO_DEV_FSL_CAAM_SM
++      depends on m
+       help
+         Example thread to exercise the Keystore API and to verify that
+         stored and recovered secrets can be used for general purpose
+--- a/drivers/crypto/caam/Makefile
++++ b/drivers/crypto/caam/Makefile
+@@ -24,7 +24,7 @@ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHA
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caampkc.o pkc_desc.o
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM) += sm_store.o
+-caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST) += sm_test.o
++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST) += sm_test.o
+ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO) += secvio.o
+ #caam-jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API) += tag_object.o
+--- a/drivers/crypto/caam/sm_test.c
++++ b/drivers/crypto/caam/sm_test.c
+@@ -552,6 +552,10 @@ static int __init caam_sm_test_init(void
+       of_node_put(dev_node);
+       priv = dev_get_drvdata(&pdev->dev);
++      if (!priv) {
++              dev_info(&pdev->dev, "SM driver not ready, aborting tests\n");
++              return -ENODEV;
++      }
+       if (!priv->sm_present) {
+               dev_info(&pdev->dev, "No SM support, skipping tests\n");
+               return -ENODEV;
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0035-crypto-caam-qi-use-QBMan-NXP-SDK-driver.patch b/target/linux/layerscape/patches-5.4/804-crypto-0035-crypto-caam-qi-use-QBMan-NXP-SDK-driver.patch
new file mode 100644 (file)
index 0000000..524ac40
--- /dev/null
@@ -0,0 +1,342 @@
+From 28ef279c55a914372bf41587f6264e8e3e61e7d5 Mon Sep 17 00:00:00 2001
+From: Horia Geanta <horia.geanta@nxp.com>
+Date: Mon, 12 Jun 2017 19:42:34 +0300
+Subject: [PATCH] crypto: caam/qi - use QBMan (NXP) SDK driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Update caam/qi to work with QBMan from NXP SDK.
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+
+Squashed "crypto: caam/qi - fix FD congestion weight" fix.
+
+Solved rebase conflicts:
+
+drivers/crypto/caam/qi.c:579
+    kept call to dev_err_ratelimited, but changed to fd->status
+drivers/crypto/caam/sg_sw_qm.h:96
+    kept changes from patch, but changed sg_count to len
+
+Signed-off-by: Vlad Pelin <vlad.pelin@nxp.com>
+Acked-by: Horia Geanta <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/Kconfig    |  2 +-
+ drivers/crypto/caam/qi.c       | 82 +++++++++++++++++++++---------------------
+ drivers/crypto/caam/qi.h       |  2 +-
+ drivers/crypto/caam/sg_sw_qm.h | 46 ++++++++++++++++--------
+ 4 files changed, 74 insertions(+), 58 deletions(-)
+
+--- a/drivers/crypto/caam/Kconfig
++++ b/drivers/crypto/caam/Kconfig
+@@ -106,7 +106,7 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API
+ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI
+       bool "Queue Interface as Crypto API backend"
+-      depends on FSL_DPAA && NET
++      depends on FSL_SDK_DPA && NET
+       default y
+       select CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC
+       select CRYPTO_AUTHENC
+--- a/drivers/crypto/caam/qi.c
++++ b/drivers/crypto/caam/qi.c
+@@ -9,7 +9,7 @@
+ #include <linux/cpumask.h>
+ #include <linux/kthread.h>
+-#include <soc/fsl/qman.h>
++#include <linux/fsl_qman.h>
+ #include "regs.h"
+ #include "qi.h"
+@@ -107,23 +107,21 @@ static void *caam_iova_to_virt(struct io
+ int caam_qi_enqueue(struct device *qidev, struct caam_drv_req *req)
+ {
+       struct qm_fd fd;
+-      dma_addr_t addr;
+       int ret;
+       int num_retries = 0;
+-      qm_fd_clear_fd(&fd);
+-      qm_fd_set_compound(&fd, qm_sg_entry_get_len(&req->fd_sgt[1]));
+-
+-      addr = dma_map_single(qidev, req->fd_sgt, sizeof(req->fd_sgt),
++      fd.cmd = 0;
++      fd.format = qm_fd_compound;
++      fd.cong_weight = caam32_to_cpu(req->fd_sgt[1].length);
++      fd.addr = dma_map_single(qidev, req->fd_sgt, sizeof(req->fd_sgt),
+                             DMA_BIDIRECTIONAL);
+-      if (dma_mapping_error(qidev, addr)) {
++      if (dma_mapping_error(qidev, fd.addr)) {
+               dev_err(qidev, "DMA mapping error for QI enqueue request\n");
+               return -EIO;
+       }
+-      qm_fd_addr_set64(&fd, addr);
+       do {
+-              ret = qman_enqueue(req->drv_ctx->req_fq, &fd);
++              ret = qman_enqueue(req->drv_ctx->req_fq, &fd, 0);
+               if (likely(!ret))
+                       return 0;
+@@ -139,7 +137,7 @@ int caam_qi_enqueue(struct device *qidev
+ EXPORT_SYMBOL(caam_qi_enqueue);
+ static void caam_fq_ern_cb(struct qman_portal *qm, struct qman_fq *fq,
+-                         const union qm_mr_entry *msg)
++                         const struct qm_mr_entry *msg)
+ {
+       const struct qm_fd *fd;
+       struct caam_drv_req *drv_req;
+@@ -148,7 +146,7 @@ static void caam_fq_ern_cb(struct qman_p
+       fd = &msg->ern.fd;
+-      if (qm_fd_get_format(fd) != qm_fd_compound) {
++      if (fd->format != qm_fd_compound) {
+               dev_err(qidev, "Non-compound FD from CAAM\n");
+               return;
+       }
+@@ -186,20 +184,22 @@ static struct qman_fq *create_caam_req_f
+       req_fq->cb.fqs = NULL;
+       ret = qman_create_fq(0, QMAN_FQ_FLAG_DYNAMIC_FQID |
+-                              QMAN_FQ_FLAG_TO_DCPORTAL, req_fq);
++                              QMAN_FQ_FLAG_TO_DCPORTAL | QMAN_FQ_FLAG_LOCKED,
++                           req_fq);
+       if (ret) {
+               dev_err(qidev, "Failed to create session req FQ\n");
+               goto create_req_fq_fail;
+       }
+-      memset(&opts, 0, sizeof(opts));
+-      opts.we_mask = cpu_to_be16(QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_DESTWQ |
+-                                 QM_INITFQ_WE_CONTEXTB |
+-                                 QM_INITFQ_WE_CONTEXTA | QM_INITFQ_WE_CGID);
+-      opts.fqd.fq_ctrl = cpu_to_be16(QM_FQCTRL_CPCSTASH | QM_FQCTRL_CGE);
+-      qm_fqd_set_destwq(&opts.fqd, qm_channel_caam, 2);
+-      opts.fqd.context_b = cpu_to_be32(qman_fq_fqid(rsp_fq));
+-      qm_fqd_context_a_set64(&opts.fqd, hwdesc);
++      opts.we_mask = QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_DESTWQ |
++                     QM_INITFQ_WE_CONTEXTB | QM_INITFQ_WE_CONTEXTA |
++                     QM_INITFQ_WE_CGID;
++      opts.fqd.fq_ctrl = QM_FQCTRL_CPCSTASH | QM_FQCTRL_CGE;
++      opts.fqd.dest.channel = qm_channel_caam;
++      opts.fqd.dest.wq = 2;
++      opts.fqd.context_b = qman_fq_fqid(rsp_fq);
++      opts.fqd.context_a.hi = upper_32_bits(hwdesc);
++      opts.fqd.context_a.lo = lower_32_bits(hwdesc);
+       opts.fqd.cgid = qipriv.cgr.cgrid;
+       ret = qman_init_fq(req_fq, fq_sched_flag, &opts);
+@@ -213,7 +213,7 @@ static struct qman_fq *create_caam_req_f
+       return req_fq;
+ init_req_fq_fail:
+-      qman_destroy_fq(req_fq);
++      qman_destroy_fq(req_fq, 0);
+ create_req_fq_fail:
+       kfree(req_fq);
+       return ERR_PTR(ret);
+@@ -281,7 +281,7 @@ empty_fq:
+       if (ret)
+               dev_err(qidev, "OOS of FQID: %u failed\n", fq->fqid);
+-      qman_destroy_fq(fq);
++      qman_destroy_fq(fq, 0);
+       kfree(fq);
+       return ret;
+@@ -298,7 +298,7 @@ static int empty_caam_fq(struct qman_fq
+               if (ret)
+                       return ret;
+-              if (!qm_mcr_np_get(&np, frm_cnt))
++              if (!np.frm_cnt)
+                       break;
+               msleep(20);
+@@ -565,30 +565,28 @@ static enum qman_cb_dqrr_result caam_rsp
+       const struct qm_fd *fd;
+       struct device *qidev = &(raw_cpu_ptr(&pcpu_qipriv)->net_dev.dev);
+       struct caam_drv_private *priv = dev_get_drvdata(qidev);
+-      u32 status;
+       if (caam_qi_napi_schedule(p, caam_napi))
+               return qman_cb_dqrr_stop;
+       fd = &dqrr->fd;
+-      status = be32_to_cpu(fd->status);
+-      if (unlikely(status)) {
+-              u32 ssrc = status & JRSTA_SSRC_MASK;
+-              u8 err_id = status & JRSTA_CCBERR_ERRID_MASK;
++      if (unlikely(fd->status)) {
++              u32 ssrc = fd->status & JRSTA_SSRC_MASK;
++              u8 err_id = fd->status & JRSTA_CCBERR_ERRID_MASK;
+               if (ssrc != JRSTA_SSRC_CCB_ERROR ||
+                   err_id != JRSTA_CCBERR_ERRID_ICVCHK)
+                       dev_err_ratelimited(qidev,
+                                           "Error: %#x in CAAM response FD\n",
+-                                          status);
++                                          fd->status);
+       }
+-      if (unlikely(qm_fd_get_format(fd) != qm_fd_compound)) {
++      if (unlikely(fd->format != qm_fd_compound)) {
+               dev_err(qidev, "Non-compound FD from CAAM\n");
+               return qman_cb_dqrr_consume;
+       }
+-      drv_req = caam_iova_to_virt(priv->domain, qm_fd_addr_get64(fd));
++      drv_req = caam_iova_to_virt(priv->domain, fd->addr);
+       if (unlikely(!drv_req)) {
+               dev_err(qidev,
+                       "Can't find original request for caam response\n");
+@@ -598,7 +596,7 @@ static enum qman_cb_dqrr_result caam_rsp
+       dma_unmap_single(drv_req->drv_ctx->qidev, qm_fd_addr(fd),
+                        sizeof(drv_req->fd_sgt), DMA_BIDIRECTIONAL);
+-      drv_req->cbk(drv_req, status);
++      drv_req->cbk(drv_req, fd->status);
+       return qman_cb_dqrr_consume;
+ }
+@@ -622,17 +620,18 @@ static int alloc_rsp_fq_cpu(struct devic
+               return -ENODEV;
+       }
+-      memset(&opts, 0, sizeof(opts));
+-      opts.we_mask = cpu_to_be16(QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_DESTWQ |
+-                                 QM_INITFQ_WE_CONTEXTB |
+-                                 QM_INITFQ_WE_CONTEXTA | QM_INITFQ_WE_CGID);
+-      opts.fqd.fq_ctrl = cpu_to_be16(QM_FQCTRL_CTXASTASHING |
+-                                     QM_FQCTRL_CPCSTASH | QM_FQCTRL_CGE);
+-      qm_fqd_set_destwq(&opts.fqd, qman_affine_channel(cpu), 3);
++      opts.we_mask = QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_DESTWQ |
++              QM_INITFQ_WE_CONTEXTB | QM_INITFQ_WE_CONTEXTA |
++              QM_INITFQ_WE_CGID;
++      opts.fqd.fq_ctrl = QM_FQCTRL_CTXASTASHING | QM_FQCTRL_CPCSTASH |
++                         QM_FQCTRL_CGE;
++      opts.fqd.dest.channel = qman_affine_channel(cpu);
++      opts.fqd.dest.wq = 3;
+       opts.fqd.cgid = qipriv.cgr.cgrid;
+       opts.fqd.context_a.stashing.exclusive = QM_STASHING_EXCL_CTX |
+                                               QM_STASHING_EXCL_DATA;
+-      qm_fqd_set_stashing(&opts.fqd, 0, 1, 1);
++      opts.fqd.context_a.stashing.data_cl = 1;
++      opts.fqd.context_a.stashing.context_cl = 1;
+       ret = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &opts);
+       if (ret) {
+@@ -662,8 +661,7 @@ static int init_cgr(struct device *qidev
+       qipriv.cgr.cb = cgr_cb;
+       memset(&opts, 0, sizeof(opts));
+-      opts.we_mask = cpu_to_be16(QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES |
+-                                 QM_CGR_WE_MODE);
++      opts.we_mask = QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES | QM_CGR_WE_MODE;
+       opts.cgr.cscn_en = QM_CGR_EN;
+       opts.cgr.mode = QMAN_CGR_MODE_FRAME;
+       qm_cgr_cs_thres_set64(&opts.cgr.cs_thres, val, 1);
+--- a/drivers/crypto/caam/qi.h
++++ b/drivers/crypto/caam/qi.h
+@@ -9,7 +9,7 @@
+ #ifndef __QI_H__
+ #define __QI_H__
+-#include <soc/fsl/qman.h>
++#include <linux/fsl_qman.h>
+ #include "compat.h"
+ #include "desc.h"
+ #include "desc_constr.h"
+--- a/drivers/crypto/caam/sg_sw_qm.h
++++ b/drivers/crypto/caam/sg_sw_qm.h
+@@ -7,46 +7,61 @@
+ #ifndef __SG_SW_QM_H
+ #define __SG_SW_QM_H
+-#include <soc/fsl/qman.h>
++#include <linux/fsl_qman.h>
+ #include "regs.h"
++static inline void cpu_to_hw_sg(struct qm_sg_entry *qm_sg_ptr)
++{
++      dma_addr_t addr = qm_sg_ptr->opaque;
++
++      qm_sg_ptr->opaque = cpu_to_caam64(addr);
++      qm_sg_ptr->sgt_efl = cpu_to_caam32(qm_sg_ptr->sgt_efl);
++}
++
+ static inline void __dma_to_qm_sg(struct qm_sg_entry *qm_sg_ptr, dma_addr_t dma,
+-                                u16 offset)
++                                u32 len, u16 offset)
+ {
+-      qm_sg_entry_set64(qm_sg_ptr, dma);
++      qm_sg_ptr->addr = dma;
++      qm_sg_ptr->length = len;
+       qm_sg_ptr->__reserved2 = 0;
+       qm_sg_ptr->bpid = 0;
+-      qm_sg_ptr->offset = cpu_to_be16(offset & QM_SG_OFF_MASK);
++      qm_sg_ptr->__reserved3 = 0;
++      qm_sg_ptr->offset = offset & QM_SG_OFFSET_MASK;
++
++      cpu_to_hw_sg(qm_sg_ptr);
+ }
+ static inline void dma_to_qm_sg_one(struct qm_sg_entry *qm_sg_ptr,
+                                   dma_addr_t dma, u32 len, u16 offset)
+ {
+-      __dma_to_qm_sg(qm_sg_ptr, dma, offset);
+-      qm_sg_entry_set_len(qm_sg_ptr, len);
++      qm_sg_ptr->extension = 0;
++      qm_sg_ptr->final = 0;
++      __dma_to_qm_sg(qm_sg_ptr, dma, len, offset);
+ }
+ static inline void dma_to_qm_sg_one_last(struct qm_sg_entry *qm_sg_ptr,
+                                        dma_addr_t dma, u32 len, u16 offset)
+ {
+-      __dma_to_qm_sg(qm_sg_ptr, dma, offset);
+-      qm_sg_entry_set_f(qm_sg_ptr, len);
++      qm_sg_ptr->extension = 0;
++      qm_sg_ptr->final = 1;
++      __dma_to_qm_sg(qm_sg_ptr, dma, len, offset);
+ }
+ static inline void dma_to_qm_sg_one_ext(struct qm_sg_entry *qm_sg_ptr,
+                                       dma_addr_t dma, u32 len, u16 offset)
+ {
+-      __dma_to_qm_sg(qm_sg_ptr, dma, offset);
+-      qm_sg_ptr->cfg = cpu_to_be32(QM_SG_EXT | (len & QM_SG_LEN_MASK));
++      qm_sg_ptr->extension = 1;
++      qm_sg_ptr->final = 0;
++      __dma_to_qm_sg(qm_sg_ptr, dma, len, offset);
+ }
+ static inline void dma_to_qm_sg_one_last_ext(struct qm_sg_entry *qm_sg_ptr,
+                                            dma_addr_t dma, u32 len,
+                                            u16 offset)
+ {
+-      __dma_to_qm_sg(qm_sg_ptr, dma, offset);
+-      qm_sg_ptr->cfg = cpu_to_be32(QM_SG_EXT | QM_SG_FIN |
+-                                   (len & QM_SG_LEN_MASK));
++      qm_sg_ptr->extension = 1;
++      qm_sg_ptr->final = 1;
++      __dma_to_qm_sg(qm_sg_ptr, dma, len, offset);
+ }
+ /*
+@@ -79,7 +94,10 @@ static inline void sg_to_qm_sg_last(stru
+                                   struct qm_sg_entry *qm_sg_ptr, u16 offset)
+ {
+       qm_sg_ptr = sg_to_qm_sg(sg, len, qm_sg_ptr, offset);
+-      qm_sg_entry_set_f(qm_sg_ptr, qm_sg_entry_get_len(qm_sg_ptr));
++
++      qm_sg_ptr->sgt_efl = caam32_to_cpu(qm_sg_ptr->sgt_efl);
++      qm_sg_ptr->final = 1;
++      qm_sg_ptr->sgt_efl = cpu_to_caam32(qm_sg_ptr->sgt_efl);
+ }
+ #endif /* __SG_SW_QM_H */
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0036-LF-933-crypto-caam-fix-iosource-busy-issue.patch b/target/linux/layerscape/patches-5.4/804-crypto-0036-LF-933-crypto-caam-fix-iosource-busy-issue.patch
new file mode 100644 (file)
index 0000000..f142a67
--- /dev/null
@@ -0,0 +1,38 @@
+From 4f59ceff69a20d28881848140ef5fc2888042e62 Mon Sep 17 00:00:00 2001
+From: Gagandeep Singh <g.singh@nxp.com>
+Date: Mon, 17 Feb 2020 16:41:01 +0000
+Subject: [PATCH] LF-933: crypto: caam: fix iosource busy issue
+
+The caam controller driver claims the ownership of the
+whole caam register space due to which while binding the
+Job Ring to fsl-jr-uio driver, it returns IOSOURCE_BUSY
+error.
+
+This patch replaces devm_request_mem_region() API with
+platform_get_resource() to avoid this issue.
+
+Fixes: eb5e94d4624a ("crypto: caam - use devres to unmap memory")
+
+Signed-off-by: Gagandeep Singh <g.singh@nxp.com>
+Acked-by: Horia Geanta <horia.geanta@nxp.com>
+---
+ drivers/crypto/caam/fsl_jr_uio.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+--- a/drivers/crypto/caam/fsl_jr_uio.c
++++ b/drivers/crypto/caam/fsl_jr_uio.c
+@@ -187,11 +187,10 @@ static int fsl_jr_probe(struct platform_
+               goto abort;
+       }
+-      jr_dev->res = devm_request_mem_region(&dev->dev, regs.start,
+-                                            regs.end - regs.start + 1,
+-                                            jr_dev->info.name);
++
++      jr_dev->res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (unlikely(!jr_dev->res)) {
+-              dev_err(jr_dev->dev, "devm_request_mem_region failed\n");
++              dev_err(jr_dev->dev, "platform_get_resource() failed\n");
+               ret = -ENOMEM;
+               goto abort;
+       }
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0038-LF-838-crypto-caam-increase-the-domain-of-write-memo.patch b/target/linux/layerscape/patches-5.4/804-crypto-0038-LF-838-crypto-caam-increase-the-domain-of-write-memo.patch
new file mode 100644 (file)
index 0000000..7cc8c5f
--- /dev/null
@@ -0,0 +1,44 @@
+From ada13fea4dcc8419e0523614b108635d8f689000 Mon Sep 17 00:00:00 2001
+From: Iuliana Prodan <iuliana.prodan@nxp.com>
+Date: Mon, 17 Feb 2020 03:05:10 +0200
+Subject: [PATCH] LF-838: crypto: caam - increase the domain of write memory
+ barrier to full system
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+In caam_jr_enqueue, under heavy DDR load, smp_wmb() or dma_wmb()
+fail to make the input ring be updated before the CAAM starts
+reading it. So, CAAM will process, again, an old descriptor address
+and will put it in the output ring. This will make caam_jr_dequeue()
+to fail, since this old descriptor is not in the software ring.
+To fix this, use wmb() which works on the full system instead of
+inner/outer shareable domains.
+
+Signed-off-by: Iuliana Prodan <iuliana.prodan@nxp.com>
+Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
+---
+ drivers/crypto/caam/jr.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/drivers/crypto/caam/jr.c
++++ b/drivers/crypto/caam/jr.c
+@@ -434,8 +434,16 @@ int caam_jr_enqueue(struct device *dev,
+        * Guarantee that the descriptor's DMA address has been written to
+        * the next slot in the ring before the write index is updated, since
+        * other cores may update this index independently.
++       *
++       * Under heavy DDR load, smp_wmb() or dma_wmb() fail to make the input
++       * ring be updated before the CAAM starts reading it. So, CAAM will
++       * process, again, an old descriptor address and will put it in the
++       * output ring. This will make caam_jr_dequeue() to fail, since this
++       * old descriptor is not in the software ring.
++       * To fix this, use wmb() which works on the full system instead of
++       * inner/outer shareable domains.
+        */
+-      smp_wmb();
++      wmb();
+       jrp->head = (head + 1) & (JOBR_DEPTH - 1);
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0040-LF-292-1-crypto-caam-refactor-RNG-initialization.patch b/target/linux/layerscape/patches-5.4/804-crypto-0040-LF-292-1-crypto-caam-refactor-RNG-initialization.patch
new file mode 100644 (file)
index 0000000..c4c22a1
--- /dev/null
@@ -0,0 +1,248 @@
+From 43f8f404e2e8cd81baa4d89706e40901c466c7bb Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Horia=20Geant=C4=83?= <horia.geanta@nxp.com>
+Date: Fri, 21 Feb 2020 11:48:39 +0100
+Subject: [PATCH] LF-292-1 crypto: caam - refactor RNG initialization
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+RNG (re-)initialization will be needed on pm resume path,
+thus refactor the corresponding code out of the probe callback.
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+Reviewed-by: Valentin Ciocoi Radulescu <valentin.ciocoi@nxp.com>
+Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
+Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ drivers/crypto/caam/ctrl.c | 189 ++++++++++++++++++++++++---------------------
+ 1 file changed, 102 insertions(+), 87 deletions(-)
+
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -327,13 +327,12 @@ static int instantiate_rng(struct device
+ /*
+  * kick_trng - sets the various parameters for enabling the initialization
+  *           of the RNG4 block in CAAM
+- * @pdev - pointer to the platform device
++ * @dev - pointer to the controller device
+  * @ent_delay - Defines the length (in system clocks) of each entropy sample.
+  */
+-static void kick_trng(struct platform_device *pdev, int ent_delay)
++static void kick_trng(struct device *dev, int ent_delay)
+ {
+-      struct device *ctrldev = &pdev->dev;
+-      struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
++      struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
+       struct caam_ctrl __iomem *ctrl;
+       struct rng4tst __iomem *r4tst;
+       u32 val;
+@@ -571,10 +570,105 @@ static void caam_dma_dev_unregister(void
+       platform_device_unregister(data);
+ }
++static int caam_ctrl_rng_init(struct device *dev)
++{
++      struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
++      struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl;
++      int ret, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN;
++      u8 rng_vid;
++
++      if (ctrlpriv->era < 10) {
++              struct caam_perfmon __iomem *perfmon;
++
++              perfmon = ctrlpriv->total_jobrs ?
++                        (struct caam_perfmon *)&ctrlpriv->jr[0]->perfmon :
++                        (struct caam_perfmon *)&ctrl->perfmon;
++
++              rng_vid = (rd_reg32(&perfmon->cha_id_ls) &
++                         CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT;
++      } else {
++              struct version_regs __iomem *vreg;
++
++              vreg = ctrlpriv->total_jobrs ?
++                      (struct version_regs *)&ctrlpriv->jr[0]->vreg :
++                      (struct version_regs *)&ctrl->vreg;
++
++              rng_vid = (rd_reg32(&vreg->rng) & CHA_VER_VID_MASK) >>
++                        CHA_VER_VID_SHIFT;
++      }
++
++      /*
++       * If SEC has RNG version >= 4 and RNG state handle has not been
++       * already instantiated, do RNG instantiation
++       * In case of SoCs with Management Complex, RNG is managed by MC f/w.
++       */
++      if (!ctrlpriv->mc_en && rng_vid >= 4) {
++              ctrlpriv->rng4_sh_init =
++                      rd_reg32(&ctrl->r4tst[0].rdsta);
++              /*
++               * If the secure keys (TDKEK, JDKEK, TDSK), were already
++               * generated, signal this to the function that is instantiating
++               * the state handles. An error would occur if RNG4 attempts
++               * to regenerate these keys before the next POR.
++               */
++              gen_sk = ctrlpriv->rng4_sh_init & RDSTA_SKVN ? 0 : 1;
++              ctrlpriv->rng4_sh_init &= RDSTA_IFMASK;
++              do {
++                      int inst_handles =
++                              rd_reg32(&ctrl->r4tst[0].rdsta) &
++                                                              RDSTA_IFMASK;
++                      /*
++                       * If either SH were instantiated by somebody else
++                       * (e.g. u-boot) then it is assumed that the entropy
++                       * parameters are properly set and thus the function
++                       * setting these (kick_trng(...)) is skipped.
++                       * Also, if a handle was instantiated, do not change
++                       * the TRNG parameters.
++                       */
++                      if (!(ctrlpriv->rng4_sh_init || inst_handles)) {
++                              dev_info(dev,
++                                       "Entropy delay = %u\n",
++                                       ent_delay);
++                              kick_trng(dev, ent_delay);
++                              ent_delay += 400;
++                      }
++                      /*
++                       * if instantiate_rng(...) fails, the loop will rerun
++                       * and the kick_trng(...) function will modify the
++                       * upper and lower limits of the entropy sampling
++                       * interval, leading to a sucessful initialization of
++                       * the RNG.
++                       */
++                      ret = instantiate_rng(dev, inst_handles,
++                                            gen_sk);
++                      if (ret == -EAGAIN)
++                              /*
++                               * if here, the loop will rerun,
++                               * so don't hog the CPU
++                               */
++                              cpu_relax();
++              } while ((ret == -EAGAIN) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
++              if (ret) {
++                      dev_err(dev, "failed to instantiate RNG");
++                      return ret;
++              }
++              /*
++               * Set handles init'ed by this module as the complement of the
++               * already initialized ones
++               */
++              ctrlpriv->rng4_sh_init = ~ctrlpriv->rng4_sh_init & RDSTA_IFMASK;
++
++              /* Enable RDB bit so that RNG works faster */
++              clrsetbits_32(&ctrl->scfgr, 0, SCFGR_RDBENABLE);
++      }
++
++      return 0;
++}
++
+ /* Probe routine for CAAM top (controller) level */
+ static int caam_probe(struct platform_device *pdev)
+ {
+-      int ret, ring, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN;
++      int ret, ring;
+       u64 caam_id;
+       const struct soc_device_attribute *imx_soc_match;
+       static struct platform_device_info caam_dma_pdev_info = {
+@@ -592,7 +686,6 @@ static int caam_probe(struct platform_de
+       struct dentry *dfs_root;
+ #endif
+       u32 scfgr, comp_params;
+-      u8 rng_vid;
+       int pg_size;
+       int BLOCK_OFFSET = 0;
+       bool reg_access = true;
+@@ -875,90 +968,12 @@ set_dma_mask:
+                       return ret;
+       }
+-      if (!reg_access)
+-              goto report_live;
+-
+-      if (ctrlpriv->era < 10) {
+-              rng_vid = (rd_reg32(&perfmon->cha_id_ls) &
+-                         CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT;
+-      } else {
+-              struct version_regs __iomem *vreg;
+-
+-              vreg = ring ? (struct version_regs *)&ctrlpriv->jr[0]->vreg :
+-                            (struct version_regs *)&ctrl->vreg;
+-
+-              rng_vid = (rd_reg32(&vreg->rng) & CHA_VER_VID_MASK) >>
+-                         CHA_VER_VID_SHIFT;
+-      }
+-
+-      /*
+-       * If SEC has RNG version >= 4 and RNG state handle has not been
+-       * already instantiated, do RNG instantiation
+-       * In case of SoCs with Management Complex, RNG is managed by MC f/w.
+-       */
+-      if (!ctrlpriv->mc_en && rng_vid >= 4) {
+-              ctrlpriv->rng4_sh_init =
+-                      rd_reg32(&ctrl->r4tst[0].rdsta);
+-              /*
+-               * If the secure keys (TDKEK, JDKEK, TDSK), were already
+-               * generated, signal this to the function that is instantiating
+-               * the state handles. An error would occur if RNG4 attempts
+-               * to regenerate these keys before the next POR.
+-               */
+-              gen_sk = ctrlpriv->rng4_sh_init & RDSTA_SKVN ? 0 : 1;
+-              ctrlpriv->rng4_sh_init &= RDSTA_IFMASK;
+-              do {
+-                      int inst_handles =
+-                              rd_reg32(&ctrl->r4tst[0].rdsta) &
+-                                                              RDSTA_IFMASK;
+-                      /*
+-                       * If either SH were instantiated by somebody else
+-                       * (e.g. u-boot) then it is assumed that the entropy
+-                       * parameters are properly set and thus the function
+-                       * setting these (kick_trng(...)) is skipped.
+-                       * Also, if a handle was instantiated, do not change
+-                       * the TRNG parameters.
+-                       */
+-                      if (!(ctrlpriv->rng4_sh_init || inst_handles)) {
+-                              dev_info(dev,
+-                                       "Entropy delay = %u\n",
+-                                       ent_delay);
+-                              kick_trng(pdev, ent_delay);
+-                              ent_delay += 400;
+-                      }
+-                      /*
+-                       * if instantiate_rng(...) fails, the loop will rerun
+-                       * and the kick_trng(...) function will modfiy the
+-                       * upper and lower limits of the entropy sampling
+-                       * interval, leading to a sucessful initialization of
+-                       * the RNG.
+-                       */
+-                      ret = instantiate_rng(dev, inst_handles,
+-                                            gen_sk);
+-                      if (ret == -EAGAIN)
+-                              /*
+-                               * if here, the loop will rerun,
+-                               * so don't hog the CPU
+-                               */
+-                              cpu_relax();
+-              } while ((ret == -EAGAIN) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
+-              if (ret) {
+-                      dev_err(dev, "failed to instantiate RNG");
++      if (reg_access) {
++              ret = caam_ctrl_rng_init(dev);
++              if (ret)
+                       return ret;
+-              }
+-              /*
+-               * Set handles init'ed by this module as the complement of the
+-               * already initialized ones
+-               */
+-              ctrlpriv->rng4_sh_init = ~ctrlpriv->rng4_sh_init & RDSTA_IFMASK;
+-
+-              /* Enable RDB bit so that RNG works faster */
+-              clrsetbits_32(&ctrl->scfgr, 0, SCFGR_RDBENABLE);
+       }
+-      /* NOTE: RTIC detection ought to go here, around Si time */
+-
+-report_live:
+       caam_id = (u64)rd_reg32(&perfmon->caam_id_ms) << 32 |
+                 (u64)rd_reg32(&perfmon->caam_id_ls);
diff --git a/target/linux/layerscape/patches-5.4/804-crypto-0041-LF-292-2-crypto-caam-add-power-management.patch b/target/linux/layerscape/patches-5.4/804-crypto-0041-LF-292-2-crypto-caam-add-power-management.patch
new file mode 100644 (file)
index 0000000..f3ebbcc
--- /dev/null
@@ -0,0 +1,570 @@
+From e8aeb8bbd925b50555c70ad4be86cf7d8e8767a6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Horia=20Geant=C4=83?= <horia.geanta@nxp.com>
+Date: Fri, 21 Feb 2020 11:48:40 +0100
+Subject: [PATCH] LF-292-2 crypto: caam - add power management
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add support for suspend and resume operation for PM in CAAM driver.
+
+When the CAAM goes in suspend, the hardware is considered to do nothing.
+
+On some platforms, the power of the CAAM is not turned off so it keeps
+its configuration.
+
+On other platforms, it doesn't so it is necessary to save the state of
+the CAAM:
+ - JRs MID
+ - Address of input and output rings
+
+Limitation:
+When the CAAM is powered OFF, it is resetted so the JDKEK and TDKEK
+changes. This impacts crypto transforms using MDHA split-keys
+which are kept over suspend as they are encrypted with the JDKEK:
+ - hmac(*) from caamhash.c
+ - authenc(hmac(*),*) from caamalg.c
+ - echainiv(authenc(hmac(*),*)) from caamalg.c
+The issue was already present in current code so this patch does not
+add a regression in this regard.
+
+Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
+(cherry picked from commit c151af80cfda82eae533a80fb2bb0158dffe556d)
+
+Differences vs. i.MX BSP:
+-RNG re-initialization done in ctrl, not in jr
+
+The fix for MLK-22518 (drivers: crypto: caam: jr: Allow quiesce when quiesced)
+is integrated in this patch.
+
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
+Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ drivers/crypto/caam/ctrl.c   | 116 +++++++++++++++++++++++
+ drivers/crypto/caam/intern.h |  31 ++++++
+ drivers/crypto/caam/jr.c     | 219 ++++++++++++++++++++++++++++++++++++-------
+ drivers/crypto/caam/regs.h   |   3 +-
+ 4 files changed, 333 insertions(+), 36 deletions(-)
+
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -665,6 +665,115 @@ static int caam_ctrl_rng_init(struct dev
+       return 0;
+ }
++#ifdef CONFIG_PM_SLEEP
++
++/* Indicate if the internal state of the CAAM is lost during PM */
++static int caam_off_during_pm(void)
++{
++      bool not_off_during_pm = of_machine_is_compatible("fsl,imx6q") ||
++                               of_machine_is_compatible("fsl,imx6qp") ||
++                               of_machine_is_compatible("fsl,imx6dl");
++
++      return not_off_during_pm ? 0 : 1;
++}
++
++static void caam_state_save(struct device *dev)
++{
++      struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
++      struct caam_ctl_state *state = &ctrlpriv->state;
++      struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl;
++      u32 deco_inst, jr_inst;
++      int i;
++
++      state->mcr = rd_reg32(&ctrl->mcr);
++      state->scfgr = rd_reg32(&ctrl->scfgr);
++
++      deco_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) &
++                   CHA_ID_MS_DECO_MASK) >> CHA_ID_MS_DECO_SHIFT;
++      for (i = 0; i < deco_inst; i++) {
++              state->deco_mid[i].liodn_ms =
++                      rd_reg32(&ctrl->deco_mid[i].liodn_ms);
++              state->deco_mid[i].liodn_ls =
++                      rd_reg32(&ctrl->deco_mid[i].liodn_ls);
++      }
++
++      jr_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) &
++                 CHA_ID_MS_JR_MASK) >> CHA_ID_MS_JR_SHIFT;
++      for (i = 0; i < jr_inst; i++) {
++              state->jr_mid[i].liodn_ms =
++                      rd_reg32(&ctrl->jr_mid[i].liodn_ms);
++              state->jr_mid[i].liodn_ls =
++                      rd_reg32(&ctrl->jr_mid[i].liodn_ls);
++      }
++}
++
++static void caam_state_restore(const struct device *dev)
++{
++      const struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
++      const struct caam_ctl_state *state = &ctrlpriv->state;
++      struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl;
++      u32 deco_inst, jr_inst;
++      int i;
++
++      wr_reg32(&ctrl->mcr, state->mcr);
++      wr_reg32(&ctrl->scfgr, state->scfgr);
++
++      deco_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) &
++                   CHA_ID_MS_DECO_MASK) >> CHA_ID_MS_DECO_SHIFT;
++      for (i = 0; i < deco_inst; i++) {
++              wr_reg32(&ctrl->deco_mid[i].liodn_ms,
++                       state->deco_mid[i].liodn_ms);
++              wr_reg32(&ctrl->deco_mid[i].liodn_ls,
++                       state->deco_mid[i].liodn_ls);
++      }
++
++      jr_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) &
++                 CHA_ID_MS_JR_MASK) >> CHA_ID_MS_JR_SHIFT;
++      for (i = 0; i < ctrlpriv->total_jobrs; i++) {
++              wr_reg32(&ctrl->jr_mid[i].liodn_ms,
++                       state->jr_mid[i].liodn_ms);
++              wr_reg32(&ctrl->jr_mid[i].liodn_ls,
++                       state->jr_mid[i].liodn_ls);
++      }
++
++      if (ctrlpriv->virt_en == 1)
++              clrsetbits_32(&ctrl->jrstart, 0, JRSTART_JR0_START |
++                            JRSTART_JR1_START | JRSTART_JR2_START |
++                            JRSTART_JR3_START);
++}
++
++static int caam_ctrl_suspend(struct device *dev)
++{
++      const struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
++
++      if (ctrlpriv->caam_off_during_pm && !ctrlpriv->scu_en &&
++          !ctrlpriv->optee_en)
++              caam_state_save(dev);
++
++      return 0;
++}
++
++static int caam_ctrl_resume(struct device *dev)
++{
++      struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
++      int ret = 0;
++
++      if (ctrlpriv->caam_off_during_pm && !ctrlpriv->scu_en &&
++          !ctrlpriv->optee_en) {
++              caam_state_restore(dev);
++
++              /* HW and rng will be reset so deinstantiation can be removed */
++              devm_remove_action(dev, devm_deinstantiate_rng, dev);
++              ret = caam_ctrl_rng_init(dev);
++      }
++
++      return ret;
++}
++
++SIMPLE_DEV_PM_OPS(caam_ctrl_pm_ops, caam_ctrl_suspend, caam_ctrl_resume);
++
++#endif /* CONFIG_PM_SLEEP */
++
+ /* Probe routine for CAAM top (controller) level */
+ static int caam_probe(struct platform_device *pdev)
+ {
+@@ -701,6 +810,10 @@ static int caam_probe(struct platform_de
+       imx_soc_match = soc_device_match(caam_imx_soc_table);
+       caam_imx = (bool)imx_soc_match;
++#ifdef CONFIG_PM_SLEEP
++      ctrlpriv->caam_off_during_pm = caam_imx && caam_off_during_pm();
++#endif
++
+       if (imx_soc_match) {
+               np = of_find_compatible_node(NULL, NULL, "fsl,imx-scu");
+               ctrlpriv->scu_en = !!np;
+@@ -1049,6 +1162,9 @@ static struct platform_driver caam_drive
+       .driver = {
+               .name = "caam",
+               .of_match_table = caam_match,
++#ifdef CONFIG_PM_SLEEP
++              .pm = &caam_ctrl_pm_ops,
++#endif
+       },
+       .probe       = caam_probe,
+ };
+--- a/drivers/crypto/caam/intern.h
++++ b/drivers/crypto/caam/intern.h
+@@ -38,6 +38,18 @@ struct caam_jrentry_info {
+       u32 desc_size;  /* Stored size for postprocessing, header derived */
+ };
++#ifdef CONFIG_PM_SLEEP
++struct caam_jr_state {
++      dma_addr_t inpbusaddr;
++      dma_addr_t outbusaddr;
++};
++#endif
++
++struct caam_jr_dequeue_params {
++      struct device *dev;
++      int enable_itr;
++};
++
+ /* Private sub-storage for a single JobR */
+ struct caam_drv_private_jr {
+       struct list_head        list_node;      /* Job Ring device list */
+@@ -45,6 +57,7 @@ struct caam_drv_private_jr {
+       int ridx;
+       struct caam_job_ring __iomem *rregs;    /* JobR's register space */
+       struct tasklet_struct irqtask;
++      struct caam_jr_dequeue_params tasklet_params;
+       int irq;                        /* One per queue */
+       /* Number of scatterlist crypt transforms active on the JobR */
+@@ -60,7 +73,20 @@ struct caam_drv_private_jr {
+       int out_ring_read_index;        /* Output index "tail" */
+       int tail;                       /* entinfo (s/w ring) tail index */
+       void *outring;                  /* Base of output ring, DMA-safe */
++
++#ifdef CONFIG_PM_SLEEP
++      struct caam_jr_state state;     /* State of the JR during PM */
++#endif
++};
++
++#ifdef CONFIG_PM_SLEEP
++struct caam_ctl_state {
++      struct masterid deco_mid[16];
++      struct masterid jr_mid[4];
++      u32 mcr;
++      u32 scfgr;
+ };
++#endif
+ /*
+  * Driver-private storage for a single CAAM block instance
+@@ -109,6 +135,11 @@ struct caam_drv_private {
+       struct dentry *ctl; /* controller dir */
+       struct debugfs_blob_wrapper ctl_kek_wrap, ctl_tkek_wrap, ctl_tdsk_wrap;
+ #endif
++
++#ifdef CONFIG_PM_SLEEP
++      int caam_off_during_pm;         /* If the CAAM is reset after suspend */
++      struct caam_ctl_state state;    /* State of the CTL during PM */
++#endif
+ };
+ #ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API
+--- a/drivers/crypto/caam/jr.c
++++ b/drivers/crypto/caam/jr.c
+@@ -72,19 +72,27 @@ int caam_jr_driver_probed(void)
+ }
+ EXPORT_SYMBOL(caam_jr_driver_probed);
+-static int caam_reset_hw_jr(struct device *dev)
++/*
++ * Put the CAAM in quiesce, ie stop
++ *
++ * Must be called with itr disabled
++ */
++static int caam_jr_stop_processing(struct device *dev, u32 jrcr_bits)
+ {
+       struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+       unsigned int timeout = 100000;
+-      /*
+-       * mask interrupts since we are going to poll
+-       * for reset completion status
+-       */
+-      clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JRCFG_IMSK);
++      /* Check the current status */
++      if (rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_INPROGRESS)
++              goto wait_quiesce_completion;
+-      /* initiate flush (required prior to reset) */
+-      wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET);
++      /* Reset the field */
++      clrsetbits_32(&jrp->rregs->jrintstatus, JRINT_ERR_HALT_MASK, 0);
++
++      /* initiate flush / park (required prior to reset) */
++      wr_reg32(&jrp->rregs->jrcommand, jrcr_bits);
++
++wait_quiesce_completion:
+       while (((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) ==
+               JRINT_ERR_HALT_INPROGRESS) && --timeout)
+               cpu_relax();
+@@ -95,8 +103,56 @@ static int caam_reset_hw_jr(struct devic
+               return -EIO;
+       }
++      return 0;
++}
++
++/*
++ * Flush the job ring, so the jobs running will be stopped, jobs queued will be
++ * invalidated and the CAAM will no longer fetch fron input ring.
++ *
++ * Must be called with itr disabled
++ */
++static int caam_jr_flush(struct device *dev)
++{
++      return caam_jr_stop_processing(dev, JRCR_RESET);
++}
++
++#ifdef CONFIG_PM_SLEEP
++/* The resume can be used after a park or a flush if CAAM has not been reset */
++static int caam_jr_restart_processing(struct device *dev)
++{
++      struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
++      u32 halt_status = rd_reg32(&jrp->rregs->jrintstatus) &
++                        JRINT_ERR_HALT_MASK;
++
++      /* Check that the flush/park is completed */
++      if (halt_status != JRINT_ERR_HALT_COMPLETE)
++              return -1;
++
++      /* Resume processing of jobs */
++      clrsetbits_32(&jrp->rregs->jrintstatus, 0, JRINT_ERR_HALT_COMPLETE);
++
++      return 0;
++}
++#endif /* CONFIG_PM_SLEEP */
++
++static int caam_reset_hw_jr(struct device *dev)
++{
++      struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
++      unsigned int timeout = 100000;
++      int err;
++
++      /*
++       * mask interrupts since we are going to poll
++       * for reset completion status
++       */
++      clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JRCFG_IMSK);
++
++      err = caam_jr_flush(dev);
++      if (err)
++              return err;
++
+       /* initiate reset */
+-      timeout = 100000;
+       wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET);
+       while ((rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET) && --timeout)
+               cpu_relax();
+@@ -204,7 +260,8 @@ static irqreturn_t caam_jr_interrupt(int
+ static void caam_jr_dequeue(unsigned long devarg)
+ {
+       int hw_idx, sw_idx, i, head, tail;
+-      struct device *dev = (struct device *)devarg;
++      struct caam_jr_dequeue_params *params = (void *)devarg;
++      struct device *dev = params->dev;
+       struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+       void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg);
+       u32 *userdesc, userstatus;
+@@ -278,8 +335,9 @@ static void caam_jr_dequeue(unsigned lon
+               outring_used--;
+       }
+-      /* reenable / unmask IRQs */
+-      clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
++      if (params->enable_itr)
++              /* reenable / unmask IRQs */
++              clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
+ }
+ /**
+@@ -467,6 +525,29 @@ int caam_jr_enqueue(struct device *dev,
+ }
+ EXPORT_SYMBOL(caam_jr_enqueue);
++static void caam_jr_init_hw(struct device *dev, dma_addr_t inpbusaddr,
++                          dma_addr_t outbusaddr)
++{
++      struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
++
++      wr_reg64(&jrp->rregs->inpring_base, inpbusaddr);
++      wr_reg64(&jrp->rregs->outring_base, outbusaddr);
++      wr_reg32(&jrp->rregs->inpring_size, JOBR_DEPTH);
++      wr_reg32(&jrp->rregs->outring_size, JOBR_DEPTH);
++
++      /* Select interrupt coalescing parameters */
++      clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JOBR_INTC |
++                    (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) |
++                    (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
++}
++
++static void caam_jr_reset_index(struct caam_drv_private_jr *jrp)
++{
++      jrp->out_ring_read_index = 0;
++      jrp->head = 0;
++      jrp->tail = 0;
++}
++
+ /*
+  * Init JobR independent of platform property detection
+  */
+@@ -503,25 +584,16 @@ static int caam_jr_init(struct device *d
+               jrp->entinfo[i].desc_addr_dma = !0;
+       /* Setup rings */
+-      jrp->out_ring_read_index = 0;
+-      jrp->head = 0;
+-      jrp->tail = 0;
+-
+-      wr_reg64(&jrp->rregs->inpring_base, inpbusaddr);
+-      wr_reg64(&jrp->rregs->outring_base, outbusaddr);
+-      wr_reg32(&jrp->rregs->inpring_size, JOBR_DEPTH);
+-      wr_reg32(&jrp->rregs->outring_size, JOBR_DEPTH);
+-
++      caam_jr_reset_index(jrp);
+       jrp->inpring_avail = JOBR_DEPTH;
++      caam_jr_init_hw(dev, inpbusaddr, outbusaddr);
+       spin_lock_init(&jrp->inplock);
+-      /* Select interrupt coalescing parameters */
+-      clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JOBR_INTC |
+-                    (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) |
+-                    (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
+-
+-      tasklet_init(&jrp->irqtask, caam_jr_dequeue, (unsigned long)dev);
++      jrp->tasklet_params.dev = dev;
++      jrp->tasklet_params.enable_itr = 1;
++      tasklet_init(&jrp->irqtask, caam_jr_dequeue,
++                   (unsigned long)&jrp->tasklet_params);
+       /* Connect job ring interrupt handler. */
+       error = devm_request_irq(dev, jrp->irq, caam_jr_interrupt, IRQF_SHARED,
+@@ -620,14 +692,48 @@ static int caam_jr_probe(struct platform
+       return 0;
+ }
+-#ifdef CONFIG_PM
++#ifdef CONFIG_PM_SLEEP
++static void caam_jr_get_hw_state(struct device *dev)
++{
++      struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
++
++      jrp->state.inpbusaddr = rd_reg64(&jrp->rregs->inpring_base);
++      jrp->state.outbusaddr = rd_reg64(&jrp->rregs->outring_base);
++}
++
+ static int caam_jr_suspend(struct device *dev)
+ {
+       struct platform_device *pdev = to_platform_device(dev);
+       struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
++      struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev->parent);
++      struct caam_jr_dequeue_params suspend_params = {
++              .dev = dev,
++              .enable_itr = 0,
++      };
++
++      if (ctrlpriv->caam_off_during_pm) {
++              int err;
++
++              tasklet_disable(&jrpriv->irqtask);
++
++              /* mask itr to call flush */
++              clrsetbits_32(&jrpriv->rregs->rconfig_lo, 0, JRCFG_IMSK);
++
++              /* Invalid job in process */
++              err = caam_jr_flush(dev);
++              if (err) {
++                      dev_err(dev, "Failed to flush\n");
++                      return err;
++              }
++
++              /* Dequeing jobs flushed */
++              caam_jr_dequeue((unsigned long)&suspend_params);
+-      if (device_may_wakeup(&pdev->dev))
++              /* Save state */
++              caam_jr_get_hw_state(dev);
++      } else if (device_may_wakeup(&pdev->dev)) {
+               enable_irq_wake(jrpriv->irq);
++      }
+       return 0;
+ }
+@@ -636,16 +742,61 @@ static int caam_jr_resume(struct device
+ {
+       struct platform_device *pdev = to_platform_device(dev);
+       struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
++      struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev->parent);
+-      if (device_may_wakeup(&pdev->dev))
++      if (ctrlpriv->caam_off_during_pm) {
++              u64 inp_addr;
++              int err;
++
++              /*
++               * Check if the CAAM has been resetted checking the address of
++               * the input ring
++               */
++              inp_addr = rd_reg64(&jrpriv->rregs->inpring_base);
++              if (inp_addr != 0) {
++                      /* JR still has some configuration */
++                      if (inp_addr == jrpriv->state.inpbusaddr) {
++                              /* JR has not been resetted */
++                              err = caam_jr_restart_processing(dev);
++                              if (err) {
++                                      dev_err(dev,
++                                              "Restart processing failed\n");
++                                      return err;
++                              }
++
++                              tasklet_enable(&jrpriv->irqtask);
++
++                              clrsetbits_32(&jrpriv->rregs->rconfig_lo,
++                                            JRCFG_IMSK, 0);
++
++                              return 0;
++                      } else if (ctrlpriv->optee_en) {
++                              /* JR has been used by OPTEE, reset it */
++                              err = caam_reset_hw_jr(dev);
++                              if (err) {
++                                      dev_err(dev, "Failed to reset JR\n");
++                                      return err;
++                              }
++                      } else {
++                              /* No explanation, return error */
++                              return -EIO;
++                      }
++              }
++
++              caam_jr_reset_index(jrpriv);
++              caam_jr_init_hw(dev, jrpriv->state.inpbusaddr,
++                              jrpriv->state.outbusaddr);
++
++              tasklet_enable(&jrpriv->irqtask);
++      } else if (device_may_wakeup(&pdev->dev)) {
+               disable_irq_wake(jrpriv->irq);
++      }
+       return 0;
+ }
+-static SIMPLE_DEV_PM_OPS(caam_jr_pm_ops, caam_jr_suspend,
+-                       caam_jr_resume);
+-#endif
++SIMPLE_DEV_PM_OPS(caam_jr_pm_ops, caam_jr_suspend, caam_jr_resume);
++#endif /* CONFIG_PM_SLEEP */
+ static const struct of_device_id caam_jr_match[] = {
+       {
+@@ -662,7 +813,7 @@ static struct platform_driver caam_jr_dr
+       .driver = {
+               .name = "caam_jr",
+               .of_match_table = caam_jr_match,
+-#ifdef CONFIG_PM
++#ifdef CONFIG_PM_SLEEP
+               .pm = &caam_jr_pm_ops,
+ #endif
+       },
+--- a/drivers/crypto/caam/regs.h
++++ b/drivers/crypto/caam/regs.h
+@@ -631,8 +631,7 @@ struct caam_ctrl {
+       u32 deco_rsr;                   /* DECORSR - Deco Request Source */
+       u32 rsvd11;
+       u32 deco_rq;                    /* DECORR - DECO Request */
+-      struct masterid deco_mid[5];    /* DECOxLIODNR - 1 per DECO */
+-      u32 rsvd5[22];
++      struct masterid deco_mid[16];   /* DECOxLIODNR - 1 per DECO */
+       /* DECO Availability/Reset Section                      120-3ff */
+       u32 deco_avail;         /* DAR - DECO availability */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0001-drm-arm-mali-dp-Add-display-QoS-interface-configurat.patch b/target/linux/layerscape/patches-5.4/805-display-0001-drm-arm-mali-dp-Add-display-QoS-interface-configurat.patch
new file mode 100644 (file)
index 0000000..c27e34f
--- /dev/null
@@ -0,0 +1,85 @@
+From dae2475df84cd77c6f7245984869897c0eb0f84e Mon Sep 17 00:00:00 2001
+From: Wen He <wen.he_1@nxp.com>
+Date: Tue, 10 Sep 2019 15:01:00 +0800
+Subject: [PATCH] drm/arm/mali-dp: Add display QoS interface configuration for
+ Mali DP500
+
+Configure the display Quality of service (QoS) levels priority if the
+optional property node "arm,malidp-aqros-value" is defined in DTS file.
+
+QoS signaling using AQROS and AWQOS AXI interface signals, the AQROS is
+driven from the "RQOS" register, so needed to program the RQOS register
+to avoid the high resolutions flicker issue on the LS1028A platform.
+
+Signed-off-by: Wen He <wen.he_1@nxp.com>
+---
+ drivers/gpu/drm/arm/malidp_drv.c  |  6 ++++++
+ drivers/gpu/drm/arm/malidp_hw.c   |  9 +++++++++
+ drivers/gpu/drm/arm/malidp_hw.h   |  3 +++
+ drivers/gpu/drm/arm/malidp_regs.h | 10 ++++++++++
+ 4 files changed, 28 insertions(+)
+
+--- a/drivers/gpu/drm/arm/malidp_drv.c
++++ b/drivers/gpu/drm/arm/malidp_drv.c
+@@ -817,6 +817,12 @@ static int malidp_bind(struct device *de
+       malidp->core_id = version;
++      ret = of_property_read_u32(dev->of_node,
++                                      "arm,malidp-arqos-value",
++                                      &hwdev->arqos_value);
++      if (ret)
++              hwdev->arqos_value = 0x0;
++
+       /* set the number of lines used for output of RGB data */
+       ret = of_property_read_u8_array(dev->of_node,
+                                       "arm,malidp-output-port-lines",
+--- a/drivers/gpu/drm/arm/malidp_hw.c
++++ b/drivers/gpu/drm/arm/malidp_hw.c
+@@ -379,6 +379,15 @@ static void malidp500_modeset(struct mal
+               malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
+       else
+               malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
++
++      /*
++       * Program the RQoS register to avoid high resolutions flicker
++       * issue on the LS1028A.
++       */
++      if (hwdev->arqos_value) {
++              val = hwdev->arqos_value;
++              malidp_hw_setbits(hwdev, val, MALIDP500_RQOS_QUALITY);
++      }
+ }
+ int malidp_format_get_bpp(u32 fmt)
+--- a/drivers/gpu/drm/arm/malidp_hw.h
++++ b/drivers/gpu/drm/arm/malidp_hw.h
+@@ -251,6 +251,9 @@ struct malidp_hw_device {
+       /* size of memory used for rotating layers, up to two banks available */
+       u32 rotation_memory[2];
++
++      /* priority level of RQOS register used for driven the ARQOS signal */
++      u32 arqos_value;
+ };
+ static inline u32 malidp_hw_read(struct malidp_hw_device *hwdev, u32 reg)
+--- a/drivers/gpu/drm/arm/malidp_regs.h
++++ b/drivers/gpu/drm/arm/malidp_regs.h
+@@ -210,6 +210,16 @@
+ #define MALIDP500_CONFIG_VALID                0x00f00
+ #define MALIDP500_CONFIG_ID           0x00fd4
++/*
++ * The quality of service (QoS) register on the DP500. RQOS register values
++ * are driven by the ARQOS signal, using AXI transacations, dependent on the
++ * FIFO input level.
++ * The RQOS register can also set QoS levels for:
++ *    - RED_ARQOS   @ A 4-bit signal value for close to underflow conditions
++ *    - GREEN_ARQOS @ A 4-bit signal value for normal conditions
++ */
++#define MALIDP500_RQOS_QUALITY          0x00500
++
+ /* register offsets and bits specific to DP550/DP650 */
+ #define MALIDP550_ADDR_SPACE_SIZE     0x10000
+ #define MALIDP550_DE_CONTROL          0x00010
diff --git a/target/linux/layerscape/patches-5.4/805-display-0002-drm-rockchip-prepare-common-code-for-cdns-and-rk-dpi.patch b/target/linux/layerscape/patches-5.4/805-display-0002-drm-rockchip-prepare-common-code-for-cdns-and-rk-dpi.patch
new file mode 100644 (file)
index 0000000..aff5359
--- /dev/null
@@ -0,0 +1,1943 @@
+From 2a77bbf7f6494d4d618fc6ff70b1a21f04cb8a22 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Wed, 10 Jul 2019 10:50:25 +0800
+Subject: [PATCH] drm/rockchip: prepare common code for cdns and rk dpi/dp
+ driver
+
+- Extracted common fields from cdn_dp_device to a new cdns_mhdp_device
+  structure which will be used by two separate drivers later on.
+- Moved some datatypes (audio_format, audio_info,
+  vic_pxl_encoding_format, video_info) from cdn-dp-core.c to cdn-dp-reg.h.
+- Changed prefixes from cdn_dp to cdns_mhdp cdn -> cdns to match the other Cadence's drivers
+  dp -> mhdp to distinguish it from a "just a DP" as the IP underneath this registers map can be a HDMI (which is
+  internally different, but the interface for commands, events is pretty much the same).
+- Modified cdn-dp-core.c to use the new driver structure and new function names.
+
+Signed-off-by: Damian Kos<dkos@cadence.com>
+Reviewed-by: Andrzej Hajda<a.hajda@samsung.com>
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/rockchip/cdn-dp-core.c | 220 +++++++++--------
+ drivers/gpu/drm/rockchip/cdn-dp-core.h |  40 +---
+ drivers/gpu/drm/rockchip/cdn-dp-reg.c  | 415 +++++++++++++++++----------------
+ drivers/gpu/drm/rockchip/cdn-dp-reg.h  | 114 +++++++--
+ 4 files changed, 423 insertions(+), 366 deletions(-)
+
+--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
++++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
+@@ -22,11 +22,10 @@
+ #include <drm/drm_probe_helper.h>
+ #include "cdn-dp-core.h"
+-#include "cdn-dp-reg.h"
+ #include "rockchip_drm_vop.h"
+ #define connector_to_dp(c) \
+-              container_of(c, struct cdn_dp_device, connector)
++              container_of(c, struct cdn_dp_device, mhdp.connector)
+ #define encoder_to_dp(c) \
+               container_of(c, struct cdn_dp_device, encoder)
+@@ -61,17 +60,18 @@ MODULE_DEVICE_TABLE(of, cdn_dp_dt_ids);
+ static int cdn_dp_grf_write(struct cdn_dp_device *dp,
+                           unsigned int reg, unsigned int val)
+ {
++      struct device *dev = dp->mhdp.dev;
+       int ret;
+       ret = clk_prepare_enable(dp->grf_clk);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "Failed to prepare_enable grf clock\n");
++              DRM_DEV_ERROR(dev, "Failed to prepare_enable grf clock\n");
+               return ret;
+       }
+       ret = regmap_write(dp->grf, reg, val);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret);
++              DRM_DEV_ERROR(dev, "Could not write to GRF: %d\n", ret);
+               return ret;
+       }
+@@ -82,24 +82,25 @@ static int cdn_dp_grf_write(struct cdn_d
+ static int cdn_dp_clk_enable(struct cdn_dp_device *dp)
+ {
++      struct device *dev = dp->mhdp.dev;
+       int ret;
+       unsigned long rate;
+       ret = clk_prepare_enable(dp->pclk);
+       if (ret < 0) {
+-              DRM_DEV_ERROR(dp->dev, "cannot enable dp pclk %d\n", ret);
++              DRM_DEV_ERROR(dev, "cannot enable dp pclk %d\n", ret);
+               goto err_pclk;
+       }
+       ret = clk_prepare_enable(dp->core_clk);
+       if (ret < 0) {
+-              DRM_DEV_ERROR(dp->dev, "cannot enable core_clk %d\n", ret);
++              DRM_DEV_ERROR(dev, "cannot enable core_clk %d\n", ret);
+               goto err_core_clk;
+       }
+-      ret = pm_runtime_get_sync(dp->dev);
++      ret = pm_runtime_get_sync(dev);
+       if (ret < 0) {
+-              DRM_DEV_ERROR(dp->dev, "cannot get pm runtime %d\n", ret);
++              DRM_DEV_ERROR(dev, "cannot get pm runtime %d\n", ret);
+               goto err_pm_runtime_get;
+       }
+@@ -112,18 +113,18 @@ static int cdn_dp_clk_enable(struct cdn_
+       rate = clk_get_rate(dp->core_clk);
+       if (!rate) {
+-              DRM_DEV_ERROR(dp->dev, "get clk rate failed\n");
++              DRM_DEV_ERROR(dev, "get clk rate failed\n");
+               ret = -EINVAL;
+               goto err_set_rate;
+       }
+-      cdn_dp_set_fw_clk(dp, rate);
+-      cdn_dp_clock_reset(dp);
++      cdns_mhdp_set_fw_clk(&dp->mhdp, rate);
++      cdns_mhdp_clock_reset(&dp->mhdp);
+       return 0;
+ err_set_rate:
+-      pm_runtime_put(dp->dev);
++      pm_runtime_put(dev);
+ err_pm_runtime_get:
+       clk_disable_unprepare(dp->core_clk);
+ err_core_clk:
+@@ -134,7 +135,7 @@ err_pclk:
+ static void cdn_dp_clk_disable(struct cdn_dp_device *dp)
+ {
+-      pm_runtime_put_sync(dp->dev);
++      pm_runtime_put_sync(dp->mhdp.dev);
+       clk_disable_unprepare(dp->pclk);
+       clk_disable_unprepare(dp->core_clk);
+ }
+@@ -167,7 +168,7 @@ static int cdn_dp_get_sink_count(struct
+       u8 value;
+       *sink_count = 0;
+-      ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, &value, 1);
++      ret = cdns_mhdp_dpcd_read(&dp->mhdp, DP_SINK_COUNT, &value, 1);
+       if (ret)
+               return ret;
+@@ -191,12 +192,13 @@ static struct cdn_dp_port *cdn_dp_connec
+ static bool cdn_dp_check_sink_connection(struct cdn_dp_device *dp)
+ {
++      struct device *dev = dp->mhdp.dev;
+       unsigned long timeout = jiffies + msecs_to_jiffies(CDN_DPCD_TIMEOUT_MS);
+       struct cdn_dp_port *port;
+       u8 sink_count = 0;
+       if (dp->active_port < 0 || dp->active_port >= dp->ports) {
+-              DRM_DEV_ERROR(dp->dev, "active_port is wrong!\n");
++              DRM_DEV_ERROR(dev, "active_port is wrong!\n");
+               return false;
+       }
+@@ -218,7 +220,7 @@ static bool cdn_dp_check_sink_connection
+               usleep_range(5000, 10000);
+       }
+-      DRM_DEV_ERROR(dp->dev, "Get sink capability timed out\n");
++      DRM_DEV_ERROR(dev, "Get sink capability timed out\n");
+       return false;
+ }
+@@ -260,7 +262,8 @@ static int cdn_dp_connector_get_modes(st
+       mutex_lock(&dp->lock);
+       edid = dp->edid;
+       if (edid) {
+-              DRM_DEV_DEBUG_KMS(dp->dev, "got edid: width[%d] x height[%d]\n",
++              DRM_DEV_DEBUG_KMS(dp->mhdp.dev,
++                                "got edid: width[%d] x height[%d]\n",
+                                 edid->width_cm, edid->height_cm);
+               dp->sink_has_audio = drm_detect_monitor_audio(edid);
+@@ -278,7 +281,8 @@ static int cdn_dp_connector_mode_valid(s
+                                      struct drm_display_mode *mode)
+ {
+       struct cdn_dp_device *dp = connector_to_dp(connector);
+-      struct drm_display_info *display_info = &dp->connector.display_info;
++      struct drm_display_info *display_info =
++              &dp->mhdp.connector.display_info;
+       u32 requested, actual, rate, sink_max, source_max = 0;
+       u8 lanes, bpc;
+@@ -304,7 +308,7 @@ static int cdn_dp_connector_mode_valid(s
+       sink_max = drm_dp_max_lane_count(dp->dpcd);
+       lanes = min(source_max, sink_max);
+-      source_max = drm_dp_bw_code_to_link_rate(CDN_DP_MAX_LINK_RATE);
++      source_max = drm_dp_bw_code_to_link_rate(CDNS_DP_MAX_LINK_RATE);
+       sink_max = drm_dp_max_link_rate(dp->dpcd);
+       rate = min(source_max, sink_max);
+@@ -314,7 +318,7 @@ static int cdn_dp_connector_mode_valid(s
+       actual = actual * 8 / 10;
+       if (requested > actual) {
+-              DRM_DEV_DEBUG_KMS(dp->dev,
++              DRM_DEV_DEBUG_KMS(dp->mhdp.dev,
+                                 "requested=%d, actual=%d, clock=%d\n",
+                                 requested, actual, mode->clock);
+               return MODE_CLOCK_HIGH;
+@@ -334,28 +338,29 @@ static int cdn_dp_firmware_init(struct c
+       const u32 *iram_data, *dram_data;
+       const struct firmware *fw = dp->fw;
+       const struct cdn_firmware_header *hdr;
++      struct device *dev = dp->mhdp.dev;
+       hdr = (struct cdn_firmware_header *)fw->data;
+       if (fw->size != le32_to_cpu(hdr->size_bytes)) {
+-              DRM_DEV_ERROR(dp->dev, "firmware is invalid\n");
++              DRM_DEV_ERROR(dev, "firmware is invalid\n");
+               return -EINVAL;
+       }
+       iram_data = (const u32 *)(fw->data + hdr->header_size);
+       dram_data = (const u32 *)(fw->data + hdr->header_size + hdr->iram_size);
+-      ret = cdn_dp_load_firmware(dp, iram_data, hdr->iram_size,
+-                                 dram_data, hdr->dram_size);
++      ret = cdns_mhdp_load_firmware(&dp->mhdp, iram_data, hdr->iram_size,
++                                    dram_data, hdr->dram_size);
+       if (ret)
+               return ret;
+-      ret = cdn_dp_set_firmware_active(dp, true);
++      ret = cdns_mhdp_set_firmware_active(&dp->mhdp, true);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "active ucpu failed: %d\n", ret);
++              DRM_DEV_ERROR(dev, "active ucpu failed: %d\n", ret);
+               return ret;
+       }
+-      return cdn_dp_event_config(dp);
++      return cdns_mhdp_event_config(&dp->mhdp);
+ }
+ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp)
+@@ -365,28 +370,29 @@ static int cdn_dp_get_sink_capability(st
+       if (!cdn_dp_check_sink_connection(dp))
+               return -ENODEV;
+-      ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd,
+-                             DP_RECEIVER_CAP_SIZE);
++      ret = cdns_mhdp_dpcd_read(&dp->mhdp, DP_DPCD_REV, dp->dpcd,
++                                DP_RECEIVER_CAP_SIZE);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret);
++              DRM_DEV_ERROR(dp->mhdp.dev, "Failed to get caps %d\n", ret);
+               return ret;
+       }
+       kfree(dp->edid);
+-      dp->edid = drm_do_get_edid(&dp->connector,
+-                                 cdn_dp_get_edid_block, dp);
++      dp->edid = drm_do_get_edid(&dp->mhdp.connector,
++                                 cdns_mhdp_get_edid_block, &dp->mhdp);
+       return 0;
+ }
+ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
+ {
++      struct device *dev = dp->mhdp.dev;
+       union extcon_property_value property;
+       int ret;
+       if (!port->phy_enabled) {
+               ret = phy_power_on(port->phy);
+               if (ret) {
+-                      DRM_DEV_ERROR(dp->dev, "phy power on failed: %d\n",
++                      DRM_DEV_ERROR(dev, "phy power on failed: %d\n",
+                                     ret);
+                       goto err_phy;
+               }
+@@ -396,28 +402,28 @@ static int cdn_dp_enable_phy(struct cdn_
+       ret = cdn_dp_grf_write(dp, GRF_SOC_CON26,
+                              DPTX_HPD_SEL_MASK | DPTX_HPD_SEL);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "Failed to write HPD_SEL %d\n", ret);
++              DRM_DEV_ERROR(dev, "Failed to write HPD_SEL %d\n", ret);
+               goto err_power_on;
+       }
+-      ret = cdn_dp_get_hpd_status(dp);
++      ret = cdns_mhdp_get_hpd_status(&dp->mhdp);
+       if (ret <= 0) {
+               if (!ret)
+-                      DRM_DEV_ERROR(dp->dev, "hpd does not exist\n");
++                      DRM_DEV_ERROR(dev, "hpd does not exist\n");
+               goto err_power_on;
+       }
+       ret = extcon_get_property(port->extcon, EXTCON_DISP_DP,
+                                 EXTCON_PROP_USB_TYPEC_POLARITY, &property);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "get property failed\n");
++              DRM_DEV_ERROR(dev, "get property failed\n");
+               goto err_power_on;
+       }
+       port->lanes = cdn_dp_get_port_lanes(port);
+-      ret = cdn_dp_set_host_cap(dp, port->lanes, property.intval);
++      ret = cdns_mhdp_set_host_cap(&dp->mhdp, port->lanes, property.intval);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "set host capabilities failed: %d\n",
++              DRM_DEV_ERROR(dev, "set host capabilities failed: %d\n",
+                             ret);
+               goto err_power_on;
+       }
+@@ -427,7 +433,7 @@ static int cdn_dp_enable_phy(struct cdn_
+ err_power_on:
+       if (phy_power_off(port->phy))
+-              DRM_DEV_ERROR(dp->dev, "phy power off failed: %d", ret);
++              DRM_DEV_ERROR(dev, "phy power off failed: %d", ret);
+       else
+               port->phy_enabled = false;
+@@ -445,7 +451,8 @@ static int cdn_dp_disable_phy(struct cdn
+       if (port->phy_enabled) {
+               ret = phy_power_off(port->phy);
+               if (ret) {
+-                      DRM_DEV_ERROR(dp->dev, "phy power off failed: %d", ret);
++                      DRM_DEV_ERROR(dp->mhdp.dev,
++                                    "phy power off failed: %d", ret);
+                       return ret;
+               }
+       }
+@@ -469,16 +476,16 @@ static int cdn_dp_disable(struct cdn_dp_
+       ret = cdn_dp_grf_write(dp, GRF_SOC_CON26,
+                              DPTX_HPD_SEL_MASK | DPTX_HPD_DEL);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "Failed to clear hpd sel %d\n",
++              DRM_DEV_ERROR(dp->mhdp.dev, "Failed to clear hpd sel %d\n",
+                             ret);
+               return ret;
+       }
+-      cdn_dp_set_firmware_active(dp, false);
++      cdns_mhdp_set_firmware_active(&dp->mhdp, false);
+       cdn_dp_clk_disable(dp);
+       dp->active = false;
+-      dp->link.rate = 0;
+-      dp->link.num_lanes = 0;
++      dp->mhdp.link.rate = 0;
++      dp->mhdp.link.num_lanes = 0;
+       if (!dp->connected) {
+               kfree(dp->edid);
+               dp->edid = NULL;
+@@ -491,11 +498,11 @@ static int cdn_dp_enable(struct cdn_dp_d
+ {
+       int ret, i, lanes;
+       struct cdn_dp_port *port;
++      struct device *dev = dp->mhdp.dev;
+       port = cdn_dp_connected_port(dp);
+       if (!port) {
+-              DRM_DEV_ERROR(dp->dev,
+-                            "Can't enable without connection\n");
++              DRM_DEV_ERROR(dev, "Can't enable without connection\n");
+               return -ENODEV;
+       }
+@@ -508,7 +515,7 @@ static int cdn_dp_enable(struct cdn_dp_d
+       ret = cdn_dp_firmware_init(dp);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "firmware init failed: %d", ret);
++              DRM_DEV_ERROR(dp->mhdp.dev, "firmware init failed: %d", ret);
+               goto err_clk_disable;
+       }
+@@ -542,8 +549,9 @@ static void cdn_dp_encoder_mode_set(stru
+                                   struct drm_display_mode *adjusted)
+ {
+       struct cdn_dp_device *dp = encoder_to_dp(encoder);
+-      struct drm_display_info *display_info = &dp->connector.display_info;
+-      struct video_info *video = &dp->video_info;
++      struct drm_display_info *display_info =
++              &dp->mhdp.connector.display_info;
++      struct video_info *video = &dp->mhdp.video_info;
+       switch (display_info->bpc) {
+       case 10:
+@@ -561,7 +569,7 @@ static void cdn_dp_encoder_mode_set(stru
+       video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
+       video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
+-      memcpy(&dp->mode, adjusted, sizeof(*mode));
++      memcpy(&dp->mhdp.mode, adjusted, sizeof(*mode));
+ }
+ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp)
+@@ -570,11 +578,11 @@ static bool cdn_dp_check_link_status(str
+       struct cdn_dp_port *port = cdn_dp_connected_port(dp);
+       u8 sink_lanes = drm_dp_max_lane_count(dp->dpcd);
+-      if (!port || !dp->link.rate || !dp->link.num_lanes)
++      if (!port || !dp->mhdp.link.rate || !dp->mhdp.link.num_lanes)
+               return false;
+-      if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status,
+-                           DP_LINK_STATUS_SIZE)) {
++      if (cdns_mhdp_dpcd_read(&dp->mhdp, DP_LANE0_1_STATUS, link_status,
++                              DP_LINK_STATUS_SIZE)) {
+               DRM_ERROR("Failed to get link status\n");
+               return false;
+       }
+@@ -586,15 +594,16 @@ static bool cdn_dp_check_link_status(str
+ static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
+ {
+       struct cdn_dp_device *dp = encoder_to_dp(encoder);
++      struct device *dev = dp->mhdp.dev;
+       int ret, val;
+-      ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
++      ret = drm_of_encoder_active_endpoint_id(dev->of_node, encoder);
+       if (ret < 0) {
+-              DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret);
++              DRM_DEV_ERROR(dev, "Could not get vop id, %d", ret);
+               return;
+       }
+-      DRM_DEV_DEBUG_KMS(dp->dev, "vop %s output to cdn-dp\n",
++      DRM_DEV_DEBUG_KMS(dev, "vop %s output to cdn-dp\n",
+                         (ret) ? "LIT" : "BIG");
+       if (ret)
+               val = DP_SEL_VOP_LIT | (DP_SEL_VOP_LIT << 16);
+@@ -609,33 +618,33 @@ static void cdn_dp_encoder_enable(struct
+       ret = cdn_dp_enable(dp);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "Failed to enable encoder %d\n",
++              DRM_DEV_ERROR(dev, "Failed to enable encoder %d\n",
+                             ret);
+               goto out;
+       }
+       if (!cdn_dp_check_link_status(dp)) {
+-              ret = cdn_dp_train_link(dp);
++              ret = cdns_mhdp_train_link(&dp->mhdp);
+               if (ret) {
+-                      DRM_DEV_ERROR(dp->dev, "Failed link train %d\n", ret);
++                      DRM_DEV_ERROR(dev, "Failed link train %d\n", ret);
+                       goto out;
+               }
+       }
+-      ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE);
++      ret = cdns_mhdp_set_video_status(&dp->mhdp, CONTROL_VIDEO_IDLE);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret);
++              DRM_DEV_ERROR(dev, "Failed to idle video %d\n", ret);
+               goto out;
+       }
+-      ret = cdn_dp_config_video(dp);
++      ret = cdns_mhdp_config_video(&dp->mhdp);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "Failed to config video %d\n", ret);
++              DRM_DEV_ERROR(dev, "Failed to config video %d\n", ret);
+               goto out;
+       }
+-      ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID);
++      ret = cdns_mhdp_set_video_status(&dp->mhdp, CONTROL_VIDEO_VALID);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret);
++              DRM_DEV_ERROR(dev, "Failed to valid video %d\n", ret);
+               goto out;
+       }
+ out:
+@@ -651,7 +660,8 @@ static void cdn_dp_encoder_disable(struc
+       if (dp->active) {
+               ret = cdn_dp_disable(dp);
+               if (ret) {
+-                      DRM_DEV_ERROR(dp->dev, "Failed to disable encoder %d\n",
++                      DRM_DEV_ERROR(dp->mhdp.dev,
++                                    "Failed to disable encoder %d\n",
+                                     ret);
+               }
+       }
+@@ -695,7 +705,7 @@ static const struct drm_encoder_funcs cd
+ static int cdn_dp_parse_dt(struct cdn_dp_device *dp)
+ {
+-      struct device *dev = dp->dev;
++      struct device *dev = dp->mhdp.dev;
+       struct device_node *np = dev->of_node;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct resource *res;
+@@ -707,10 +717,10 @@ static int cdn_dp_parse_dt(struct cdn_dp
+       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-      dp->regs = devm_ioremap_resource(dev, res);
+-      if (IS_ERR(dp->regs)) {
++      dp->mhdp.regs = devm_ioremap_resource(dev, res);
++      if (IS_ERR(dp->mhdp.regs)) {
+               DRM_DEV_ERROR(dev, "ioremap reg failed\n");
+-              return PTR_ERR(dp->regs);
++              return PTR_ERR(dp->mhdp.regs);
+       }
+       dp->core_clk = devm_clk_get(dev, "core-clk");
+@@ -725,10 +735,10 @@ static int cdn_dp_parse_dt(struct cdn_dp
+               return PTR_ERR(dp->pclk);
+       }
+-      dp->spdif_clk = devm_clk_get(dev, "spdif");
+-      if (IS_ERR(dp->spdif_clk)) {
++      dp->mhdp.spdif_clk = devm_clk_get(dev, "spdif");
++      if (IS_ERR(dp->mhdp.spdif_clk)) {
+               DRM_DEV_ERROR(dev, "cannot get spdif_clk\n");
+-              return PTR_ERR(dp->spdif_clk);
++              return PTR_ERR(dp->mhdp.spdif_clk);
+       }
+       dp->grf_clk = devm_clk_get(dev, "grf");
+@@ -737,10 +747,10 @@ static int cdn_dp_parse_dt(struct cdn_dp
+               return PTR_ERR(dp->grf_clk);
+       }
+-      dp->spdif_rst = devm_reset_control_get(dev, "spdif");
+-      if (IS_ERR(dp->spdif_rst)) {
++      dp->mhdp.spdif_rst = devm_reset_control_get(dev, "spdif");
++      if (IS_ERR(dp->mhdp.spdif_rst)) {
+               DRM_DEV_ERROR(dev, "no spdif reset control found\n");
+-              return PTR_ERR(dp->spdif_rst);
++              return PTR_ERR(dp->mhdp.spdif_rst);
+       }
+       dp->dptx_rst = devm_reset_control_get(dev, "dptx");
+@@ -795,7 +805,7 @@ static int cdn_dp_audio_hw_params(struct
+               goto out;
+       }
+-      ret = cdn_dp_audio_config(dp, &audio);
++      ret = cdns_mhdp_audio_config(&dp->mhdp, &audio);
+       if (!ret)
+               dp->audio_info = audio;
+@@ -813,7 +823,7 @@ static void cdn_dp_audio_shutdown(struct
+       if (!dp->active)
+               goto out;
+-      ret = cdn_dp_audio_stop(dp, &dp->audio_info);
++      ret = cdns_mhdp_audio_stop(&dp->mhdp, &dp->audio_info);
+       if (!ret)
+               dp->audio_info.format = AFMT_UNUSED;
+ out:
+@@ -832,7 +842,7 @@ static int cdn_dp_audio_digital_mute(str
+               goto out;
+       }
+-      ret = cdn_dp_audio_mute(dp, enable);
++      ret = cdns_mhdp_audio_mute(&dp->mhdp, enable);
+ out:
+       mutex_unlock(&dp->lock);
+@@ -844,7 +854,8 @@ static int cdn_dp_audio_get_eld(struct d
+ {
+       struct cdn_dp_device *dp = dev_get_drvdata(dev);
+-      memcpy(buf, dp->connector.eld, min(sizeof(dp->connector.eld), len));
++      memcpy(buf, dp->mhdp.connector.eld,
++             min(sizeof(dp->mhdp.connector.eld), len));
+       return 0;
+ }
+@@ -878,6 +889,7 @@ static int cdn_dp_request_firmware(struc
+       int ret;
+       unsigned long timeout = jiffies + msecs_to_jiffies(CDN_FW_TIMEOUT_MS);
+       unsigned long sleep = 1000;
++      struct device *dev = dp->mhdp.dev;
+       WARN_ON(!mutex_is_locked(&dp->lock));
+@@ -888,13 +900,13 @@ static int cdn_dp_request_firmware(struc
+       mutex_unlock(&dp->lock);
+       while (time_before(jiffies, timeout)) {
+-              ret = request_firmware(&dp->fw, CDN_DP_FIRMWARE, dp->dev);
++              ret = request_firmware(&dp->fw, CDN_DP_FIRMWARE, dev);
+               if (ret == -ENOENT) {
+                       msleep(sleep);
+                       sleep *= 2;
+                       continue;
+               } else if (ret) {
+-                      DRM_DEV_ERROR(dp->dev,
++                      DRM_DEV_ERROR(dev,
+                                     "failed to request firmware: %d\n", ret);
+                       goto out;
+               }
+@@ -904,7 +916,7 @@ static int cdn_dp_request_firmware(struc
+               goto out;
+       }
+-      DRM_DEV_ERROR(dp->dev, "Timed out trying to load firmware\n");
++      DRM_DEV_ERROR(dev, "Timed out trying to load firmware\n");
+       ret = -ETIMEDOUT;
+ out:
+       mutex_lock(&dp->lock);
+@@ -915,8 +927,9 @@ static void cdn_dp_pd_event_work(struct
+ {
+       struct cdn_dp_device *dp = container_of(work, struct cdn_dp_device,
+                                               event_work);
+-      struct drm_connector *connector = &dp->connector;
++      struct drm_connector *connector = &dp->mhdp.connector;
+       enum drm_connector_status old_status;
++      struct device *dev = dp->mhdp.dev;
+       int ret;
+@@ -933,44 +946,45 @@ static void cdn_dp_pd_event_work(struct
+       /* Not connected, notify userspace to disable the block */
+       if (!cdn_dp_connected_port(dp)) {
+-              DRM_DEV_INFO(dp->dev, "Not connected. Disabling cdn\n");
++              DRM_DEV_INFO(dev, "Not connected. Disabling cdn\n");
+               dp->connected = false;
+       /* Connected but not enabled, enable the block */
+       } else if (!dp->active) {
+-              DRM_DEV_INFO(dp->dev, "Connected, not enabled. Enabling cdn\n");
++              DRM_DEV_INFO(dev, "Connected, not enabled. Enabling cdn\n");
+               ret = cdn_dp_enable(dp);
+               if (ret) {
+-                      DRM_DEV_ERROR(dp->dev, "Enable dp failed %d\n", ret);
++                      DRM_DEV_ERROR(dev, "Enable dp failed %d\n", ret);
+                       dp->connected = false;
+               }
+       /* Enabled and connected to a dongle without a sink, notify userspace */
+       } else if (!cdn_dp_check_sink_connection(dp)) {
+-              DRM_DEV_INFO(dp->dev, "Connected without sink. Assert hpd\n");
++              DRM_DEV_INFO(dev, "Connected without sink. Assert hpd\n");
+               dp->connected = false;
+       /* Enabled and connected with a sink, re-train if requested */
+       } else if (!cdn_dp_check_link_status(dp)) {
+-              unsigned int rate = dp->link.rate;
+-              unsigned int lanes = dp->link.num_lanes;
+-              struct drm_display_mode *mode = &dp->mode;
++              unsigned int rate = dp->mhdp.link.rate;
++              unsigned int lanes = dp->mhdp.link.num_lanes;
++              struct drm_display_mode *mode = &dp->mhdp.mode;
+-              DRM_DEV_INFO(dp->dev, "Connected with sink. Re-train link\n");
+-              ret = cdn_dp_train_link(dp);
++              DRM_DEV_INFO(dev, "Connected with sink. Re-train link\n");
++              ret = cdns_mhdp_train_link(&dp->mhdp);
+               if (ret) {
+                       dp->connected = false;
+-                      DRM_DEV_ERROR(dp->dev, "Train link failed %d\n", ret);
++                      DRM_DEV_ERROR(dev, "Train link failed %d\n", ret);
+                       goto out;
+               }
+               /* If training result is changed, update the video config */
+               if (mode->clock &&
+-                  (rate != dp->link.rate || lanes != dp->link.num_lanes)) {
+-                      ret = cdn_dp_config_video(dp);
++                  (rate != dp->mhdp.link.rate ||
++                   lanes != dp->mhdp.link.num_lanes)) {
++                      ret = cdns_mhdp_config_video(&dp->mhdp);
+                       if (ret) {
+                               dp->connected = false;
+-                              DRM_DEV_ERROR(dp->dev,
++                              DRM_DEV_ERROR(dev,
+                                             "Failed to config video %d\n",
+                                             ret);
+                       }
+@@ -1039,7 +1053,7 @@ static int cdn_dp_bind(struct device *de
+       drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs);
+-      connector = &dp->connector;
++      connector = &dp->mhdp.connector;
+       connector->polled = DRM_CONNECTOR_POLL_HPD;
+       connector->dpms = DRM_MODE_DPMS_OFF;
+@@ -1063,7 +1077,7 @@ static int cdn_dp_bind(struct device *de
+               port = dp->port[i];
+               port->event_nb.notifier_call = cdn_dp_pd_event;
+-              ret = devm_extcon_register_notifier(dp->dev, port->extcon,
++              ret = devm_extcon_register_notifier(dp->mhdp.dev, port->extcon,
+                                                   EXTCON_DISP_DP,
+                                                   &port->event_nb);
+               if (ret) {
+@@ -1090,7 +1104,7 @@ static void cdn_dp_unbind(struct device
+ {
+       struct cdn_dp_device *dp = dev_get_drvdata(dev);
+       struct drm_encoder *encoder = &dp->encoder;
+-      struct drm_connector *connector = &dp->connector;
++      struct drm_connector *connector = &dp->mhdp.connector;
+       cancel_work_sync(&dp->event_work);
+       cdn_dp_encoder_disable(encoder);
+@@ -1150,7 +1164,7 @@ static int cdn_dp_probe(struct platform_
+       dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
+       if (!dp)
+               return -ENOMEM;
+-      dp->dev = dev;
++      dp->mhdp.dev = dev;
+       match = of_match_node(cdn_dp_dt_ids, pdev->dev.of_node);
+       dp_data = (struct cdn_dp_data *)match->data;
+@@ -1195,7 +1209,7 @@ static int cdn_dp_remove(struct platform
+       struct cdn_dp_device *dp = platform_get_drvdata(pdev);
+       platform_device_unregister(dp->audio_pdev);
+-      cdn_dp_suspend(dp->dev);
++      cdn_dp_suspend(dp->mhdp.dev);
+       component_del(&pdev->dev, &cdn_dp_component_ops);
+       return 0;
+@@ -1205,7 +1219,7 @@ static void cdn_dp_shutdown(struct platf
+ {
+       struct cdn_dp_device *dp = platform_get_drvdata(pdev);
+-      cdn_dp_suspend(dp->dev);
++      cdn_dp_suspend(dp->mhdp.dev);
+ }
+ static const struct dev_pm_ops cdn_dp_pm_ops = {
+--- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
++++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
+@@ -12,38 +12,10 @@
+ #include <drm/drm_probe_helper.h>
+ #include "rockchip_drm_drv.h"
++#include "cdn-dp-reg.h"
+ #define MAX_PHY               2
+-enum audio_format {
+-      AFMT_I2S = 0,
+-      AFMT_SPDIF = 1,
+-      AFMT_UNUSED,
+-};
+-
+-struct audio_info {
+-      enum audio_format format;
+-      int sample_rate;
+-      int channels;
+-      int sample_width;
+-};
+-
+-enum vic_pxl_encoding_format {
+-      PXL_RGB = 0x1,
+-      YCBCR_4_4_4 = 0x2,
+-      YCBCR_4_2_2 = 0x4,
+-      YCBCR_4_2_0 = 0x8,
+-      Y_ONLY = 0x10,
+-};
+-
+-struct video_info {
+-      bool h_sync_polarity;
+-      bool v_sync_polarity;
+-      bool interlaced;
+-      int color_depth;
+-      enum vic_pxl_encoding_format color_fmt;
+-};
+-
+ struct cdn_firmware_header {
+       u32 size_bytes; /* size of the entire header+image(s) in bytes */
+       u32 header_size; /* size of just the header in bytes */
+@@ -62,11 +34,9 @@ struct cdn_dp_port {
+ };
+ struct cdn_dp_device {
+-      struct device *dev;
++      struct cdns_mhdp_device mhdp;
+       struct drm_device *drm_dev;
+-      struct drm_connector connector;
+       struct drm_encoder encoder;
+-      struct drm_display_mode mode;
+       struct platform_device *audio_pdev;
+       struct work_struct event_work;
+       struct edid *edid;
+@@ -77,22 +47,16 @@ struct cdn_dp_device {
+       bool suspended;
+       const struct firmware *fw;      /* cdn dp firmware */
+-      unsigned int fw_version;        /* cdn fw version */
+       bool fw_loaded;
+-      void __iomem *regs;
+       struct regmap *grf;
+       struct clk *core_clk;
+       struct clk *pclk;
+-      struct clk *spdif_clk;
+       struct clk *grf_clk;
+-      struct reset_control *spdif_rst;
+       struct reset_control *dptx_rst;
+       struct reset_control *apb_rst;
+       struct reset_control *core_rst;
+       struct audio_info audio_info;
+-      struct video_info video_info;
+-      struct drm_dp_link link;
+       struct cdn_dp_port *port[MAX_PHY];
+       u8 ports;
+       u8 lanes;
+--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c
++++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
+@@ -14,19 +14,19 @@
+ #include "cdn-dp-core.h"
+ #include "cdn-dp-reg.h"
+-#define CDN_DP_SPDIF_CLK              200000000
++#define CDNS_DP_SPDIF_CLK             200000000
+ #define FW_ALIVE_TIMEOUT_US           1000000
+ #define MAILBOX_RETRY_US              1000
+ #define MAILBOX_TIMEOUT_US            5000000
+ #define LINK_TRAINING_RETRY_MS                20
+ #define LINK_TRAINING_TIMEOUT_MS      500
+-void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, unsigned long clk)
++void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk)
+ {
+-      writel(clk / 1000000, dp->regs + SW_CLK_H);
++      writel(clk / 1000000, mhdp->regs + SW_CLK_H);
+ }
+-void cdn_dp_clock_reset(struct cdn_dp_device *dp)
++void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp)
+ {
+       u32 val;
+@@ -42,16 +42,16 @@ void cdn_dp_clock_reset(struct cdn_dp_de
+             DPTX_SYS_CLK_EN |
+             CFG_DPTX_VIF_CLK_RSTN_EN |
+             CFG_DPTX_VIF_CLK_EN;
+-      writel(val, dp->regs + SOURCE_DPTX_CAR);
++      writel(val, mhdp->regs + SOURCE_DPTX_CAR);
+       val = SOURCE_PHY_RSTN_EN | SOURCE_PHY_CLK_EN;
+-      writel(val, dp->regs + SOURCE_PHY_CAR);
++      writel(val, mhdp->regs + SOURCE_PHY_CAR);
+       val = SOURCE_PKT_SYS_RSTN_EN |
+             SOURCE_PKT_SYS_CLK_EN |
+             SOURCE_PKT_DATA_RSTN_EN |
+             SOURCE_PKT_DATA_CLK_EN;
+-      writel(val, dp->regs + SOURCE_PKT_CAR);
++      writel(val, mhdp->regs + SOURCE_PKT_CAR);
+       val = SPDIF_CDR_CLK_RSTN_EN |
+             SPDIF_CDR_CLK_EN |
+@@ -59,53 +59,53 @@ void cdn_dp_clock_reset(struct cdn_dp_de
+             SOURCE_AIF_SYS_CLK_EN |
+             SOURCE_AIF_CLK_RSTN_EN |
+             SOURCE_AIF_CLK_EN;
+-      writel(val, dp->regs + SOURCE_AIF_CAR);
++      writel(val, mhdp->regs + SOURCE_AIF_CAR);
+       val = SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN |
+             SOURCE_CIPHER_SYS_CLK_EN |
+             SOURCE_CIPHER_CHAR_CLK_RSTN_EN |
+             SOURCE_CIPHER_CHAR_CLK_EN;
+-      writel(val, dp->regs + SOURCE_CIPHER_CAR);
++      writel(val, mhdp->regs + SOURCE_CIPHER_CAR);
+       val = SOURCE_CRYPTO_SYS_CLK_RSTN_EN |
+             SOURCE_CRYPTO_SYS_CLK_EN;
+-      writel(val, dp->regs + SOURCE_CRYPTO_CAR);
++      writel(val, mhdp->regs + SOURCE_CRYPTO_CAR);
+       /* enable Mailbox and PIF interrupt */
+-      writel(0, dp->regs + APB_INT_MASK);
++      writel(0, mhdp->regs + APB_INT_MASK);
+ }
+-static int cdn_dp_mailbox_read(struct cdn_dp_device *dp)
++static int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)
+ {
+       int val, ret;
+-      ret = readx_poll_timeout(readl, dp->regs + MAILBOX_EMPTY_ADDR,
++      ret = readx_poll_timeout(readl, mhdp->regs + MAILBOX_EMPTY_ADDR,
+                                val, !val, MAILBOX_RETRY_US,
+                                MAILBOX_TIMEOUT_US);
+       if (ret < 0)
+               return ret;
+-      return readl(dp->regs + MAILBOX0_RD_DATA) & 0xff;
++      return readl(mhdp->regs + MAILBOX0_RD_DATA) & 0xff;
+ }
+-static int cdp_dp_mailbox_write(struct cdn_dp_device *dp, u8 val)
++static int cdp_dp_mailbox_write(struct cdns_mhdp_device *mhdp, u8 val)
+ {
+       int ret, full;
+-      ret = readx_poll_timeout(readl, dp->regs + MAILBOX_FULL_ADDR,
++      ret = readx_poll_timeout(readl, mhdp->regs + MAILBOX_FULL_ADDR,
+                                full, !full, MAILBOX_RETRY_US,
+                                MAILBOX_TIMEOUT_US);
+       if (ret < 0)
+               return ret;
+-      writel(val, dp->regs + MAILBOX0_WR_DATA);
++      writel(val, mhdp->regs + MAILBOX0_WR_DATA);
+       return 0;
+ }
+-static int cdn_dp_mailbox_validate_receive(struct cdn_dp_device *dp,
+-                                         u8 module_id, u8 opcode,
+-                                         u16 req_size)
++static int cdns_mhdp_mailbox_validate_receive(struct cdns_mhdp_device *mhdp,
++                                            u8 module_id, u8 opcode,
++                                            u16 req_size)
+ {
+       u32 mbox_size, i;
+       u8 header[4];
+@@ -113,7 +113,7 @@ static int cdn_dp_mailbox_validate_recei
+       /* read the header of the message */
+       for (i = 0; i < 4; i++) {
+-              ret = cdn_dp_mailbox_read(dp);
++              ret = cdns_mhdp_mailbox_read(mhdp);
+               if (ret < 0)
+                       return ret;
+@@ -129,7 +129,7 @@ static int cdn_dp_mailbox_validate_recei
+                * clear the mailbox by reading its contents.
+                */
+               for (i = 0; i < mbox_size; i++)
+-                      if (cdn_dp_mailbox_read(dp) < 0)
++                      if (cdns_mhdp_mailbox_read(mhdp) < 0)
+                               break;
+               return -EINVAL;
+@@ -138,14 +138,14 @@ static int cdn_dp_mailbox_validate_recei
+       return 0;
+ }
+-static int cdn_dp_mailbox_read_receive(struct cdn_dp_device *dp,
+-                                     u8 *buff, u16 buff_size)
++static int cdns_mhdp_mailbox_read_receive(struct cdns_mhdp_device *mhdp,
++                                        u8 *buff, u16 buff_size)
+ {
+       u32 i;
+       int ret;
+       for (i = 0; i < buff_size; i++) {
+-              ret = cdn_dp_mailbox_read(dp);
++              ret = cdns_mhdp_mailbox_read(mhdp);
+               if (ret < 0)
+                       return ret;
+@@ -155,8 +155,8 @@ static int cdn_dp_mailbox_read_receive(s
+       return 0;
+ }
+-static int cdn_dp_mailbox_send(struct cdn_dp_device *dp, u8 module_id,
+-                             u8 opcode, u16 size, u8 *message)
++static int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id,
++                                u8 opcode, u16 size, u8 *message)
+ {
+       u8 header[4];
+       int ret, i;
+@@ -167,13 +167,13 @@ static int cdn_dp_mailbox_send(struct cd
+       header[3] = size & 0xff;
+       for (i = 0; i < 4; i++) {
+-              ret = cdp_dp_mailbox_write(dp, header[i]);
++              ret = cdp_dp_mailbox_write(mhdp, header[i]);
+               if (ret)
+                       return ret;
+       }
+       for (i = 0; i < size; i++) {
+-              ret = cdp_dp_mailbox_write(dp, message[i]);
++              ret = cdp_dp_mailbox_write(mhdp, message[i]);
+               if (ret)
+                       return ret;
+       }
+@@ -181,7 +181,7 @@ static int cdn_dp_mailbox_send(struct cd
+       return 0;
+ }
+-static int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val)
++static int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u16 addr, u32 val)
+ {
+       u8 msg[6];
+@@ -191,12 +191,12 @@ static int cdn_dp_reg_write(struct cdn_d
+       msg[3] = (val >> 16) & 0xff;
+       msg[4] = (val >> 8) & 0xff;
+       msg[5] = val & 0xff;
+-      return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_REGISTER,
+-                                 sizeof(msg), msg);
++      return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                    DPTX_WRITE_REGISTER, sizeof(msg), msg);
+ }
+-static int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr,
+-                              u8 start_bit, u8 bits_no, u32 val)
++static int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
++                                 u8 start_bit, u8 bits_no, u32 val)
+ {
+       u8 field[8];
+@@ -209,11 +209,12 @@ static int cdn_dp_reg_write_bit(struct c
+       field[6] = (val >> 8) & 0xff;
+       field[7] = val & 0xff;
+-      return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_FIELD,
+-                                 sizeof(field), field);
++      return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                    DPTX_WRITE_FIELD, sizeof(field), field);
+ }
+-int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len)
++int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,
++                      u32 addr, u8 *data, u16 len)
+ {
+       u8 msg[5], reg[5];
+       int ret;
+@@ -223,28 +224,28 @@ int cdn_dp_dpcd_read(struct cdn_dp_devic
+       msg[2] = (addr >> 16) & 0xff;
+       msg[3] = (addr >> 8) & 0xff;
+       msg[4] = addr & 0xff;
+-      ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_DPCD,
+-                                sizeof(msg), msg);
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                   DPTX_READ_DPCD, sizeof(msg), msg);
+       if (ret)
+               goto err_dpcd_read;
+-      ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX,
+-                                            DPTX_READ_DPCD,
+-                                            sizeof(reg) + len);
++      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
++                                               DPTX_READ_DPCD,
++                                               sizeof(reg) + len);
+       if (ret)
+               goto err_dpcd_read;
+-      ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg));
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+       if (ret)
+               goto err_dpcd_read;
+-      ret = cdn_dp_mailbox_read_receive(dp, data, len);
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, data, len);
+ err_dpcd_read:
+       return ret;
+ }
+-int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value)
++int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value)
+ {
+       u8 msg[6], reg[5];
+       int ret;
+@@ -255,17 +256,17 @@ int cdn_dp_dpcd_write(struct cdn_dp_devi
+       msg[3] = (addr >> 8) & 0xff;
+       msg[4] = addr & 0xff;
+       msg[5] = value;
+-      ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_DPCD,
+-                                sizeof(msg), msg);
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                   DPTX_WRITE_DPCD, sizeof(msg), msg);
+       if (ret)
+               goto err_dpcd_write;
+-      ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX,
+-                                            DPTX_WRITE_DPCD, sizeof(reg));
++      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
++                                               DPTX_WRITE_DPCD, sizeof(reg));
+       if (ret)
+               goto err_dpcd_write;
+-      ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg));
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+       if (ret)
+               goto err_dpcd_write;
+@@ -274,53 +275,53 @@ int cdn_dp_dpcd_write(struct cdn_dp_devi
+ err_dpcd_write:
+       if (ret)
+-              DRM_DEV_ERROR(dp->dev, "dpcd write failed: %d\n", ret);
++              DRM_DEV_ERROR(mhdp->dev, "dpcd write failed: %d\n", ret);
+       return ret;
+ }
+-int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem,
+-                       u32 i_size, const u32 *d_mem, u32 d_size)
++int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
++                          u32 i_size, const u32 *d_mem, u32 d_size)
+ {
+       u32 reg;
+       int i, ret;
+       /* reset ucpu before load firmware*/
+       writel(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET,
+-             dp->regs + APB_CTRL);
++             mhdp->regs + APB_CTRL);
+       for (i = 0; i < i_size; i += 4)
+-              writel(*i_mem++, dp->regs + ADDR_IMEM + i);
++              writel(*i_mem++, mhdp->regs + ADDR_IMEM + i);
+       for (i = 0; i < d_size; i += 4)
+-              writel(*d_mem++, dp->regs + ADDR_DMEM + i);
++              writel(*d_mem++, mhdp->regs + ADDR_DMEM + i);
+       /* un-reset ucpu */
+-      writel(0, dp->regs + APB_CTRL);
++      writel(0, mhdp->regs + APB_CTRL);
+       /* check the keep alive register to make sure fw working */
+-      ret = readx_poll_timeout(readl, dp->regs + KEEP_ALIVE,
++      ret = readx_poll_timeout(readl, mhdp->regs + KEEP_ALIVE,
+                                reg, reg, 2000, FW_ALIVE_TIMEOUT_US);
+       if (ret < 0) {
+-              DRM_DEV_ERROR(dp->dev, "failed to loaded the FW reg = %x\n",
++              DRM_DEV_ERROR(mhdp->dev, "failed to loaded the FW reg = %x\n",
+                             reg);
+               return -EINVAL;
+       }
+-      reg = readl(dp->regs + VER_L) & 0xff;
+-      dp->fw_version = reg;
+-      reg = readl(dp->regs + VER_H) & 0xff;
+-      dp->fw_version |= reg << 8;
+-      reg = readl(dp->regs + VER_LIB_L_ADDR) & 0xff;
+-      dp->fw_version |= reg << 16;
+-      reg = readl(dp->regs + VER_LIB_H_ADDR) & 0xff;
+-      dp->fw_version |= reg << 24;
++      reg = readl(mhdp->regs + VER_L) & 0xff;
++      mhdp->fw_version = reg;
++      reg = readl(mhdp->regs + VER_H) & 0xff;
++      mhdp->fw_version |= reg << 8;
++      reg = readl(mhdp->regs + VER_LIB_L_ADDR) & 0xff;
++      mhdp->fw_version |= reg << 16;
++      reg = readl(mhdp->regs + VER_LIB_H_ADDR) & 0xff;
++      mhdp->fw_version |= reg << 24;
+-      DRM_DEV_DEBUG(dp->dev, "firmware version: %x\n", dp->fw_version);
++      DRM_DEV_DEBUG(mhdp->dev, "firmware version: %x\n", mhdp->fw_version);
+       return 0;
+ }
+-int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable)
++int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable)
+ {
+       u8 msg[5];
+       int ret, i;
+@@ -332,14 +333,14 @@ int cdn_dp_set_firmware_active(struct cd
+       msg[4] = enable ? FW_ACTIVE : FW_STANDBY;
+       for (i = 0; i < sizeof(msg); i++) {
+-              ret = cdp_dp_mailbox_write(dp, msg[i]);
++              ret = cdp_dp_mailbox_write(mhdp, msg[i]);
+               if (ret)
+                       goto err_set_firmware_active;
+       }
+       /* read the firmware state */
+       for (i = 0; i < sizeof(msg); i++)  {
+-              ret = cdn_dp_mailbox_read(dp);
++              ret = cdns_mhdp_mailbox_read(mhdp);
+               if (ret < 0)
+                       goto err_set_firmware_active;
+@@ -350,16 +351,16 @@ int cdn_dp_set_firmware_active(struct cd
+ err_set_firmware_active:
+       if (ret < 0)
+-              DRM_DEV_ERROR(dp->dev, "set firmware active failed\n");
++              DRM_DEV_ERROR(mhdp->dev, "set firmware active failed\n");
+       return ret;
+ }
+-int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip)
++int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, u8 lanes, bool flip)
+ {
+       u8 msg[8];
+       int ret;
+-      msg[0] = CDN_DP_MAX_LINK_RATE;
++      msg[0] = CDNS_DP_MAX_LINK_RATE;
+       msg[1] = lanes | SCRAMBLER_EN;
+       msg[2] = VOLTAGE_LEVEL_2;
+       msg[3] = PRE_EMPHASIS_LEVEL_3;
+@@ -368,22 +369,22 @@ int cdn_dp_set_host_cap(struct cdn_dp_de
+       msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL;
+       msg[7] = ENHANCED;
+-      ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX,
+-                                DPTX_SET_HOST_CAPABILITIES,
+-                                sizeof(msg), msg);
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                   DPTX_SET_HOST_CAPABILITIES,
++                                   sizeof(msg), msg);
+       if (ret)
+               goto err_set_host_cap;
+-      ret = cdn_dp_reg_write(dp, DP_AUX_SWAP_INVERSION_CONTROL,
+-                             AUX_HOST_INVERT);
++      ret = cdns_mhdp_reg_write(mhdp, DP_AUX_SWAP_INVERSION_CONTROL,
++                                AUX_HOST_INVERT);
+ err_set_host_cap:
+       if (ret)
+-              DRM_DEV_ERROR(dp->dev, "set host cap failed: %d\n", ret);
++              DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret);
+       return ret;
+ }
+-int cdn_dp_event_config(struct cdn_dp_device *dp)
++int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp)
+ {
+       u8 msg[5];
+       int ret;
+@@ -392,49 +393,50 @@ int cdn_dp_event_config(struct cdn_dp_de
+       msg[0] = DPTX_EVENT_ENABLE_HPD | DPTX_EVENT_ENABLE_TRAINING;
+-      ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_ENABLE_EVENT,
+-                                sizeof(msg), msg);
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                   DPTX_ENABLE_EVENT, sizeof(msg), msg);
+       if (ret)
+-              DRM_DEV_ERROR(dp->dev, "set event config failed: %d\n", ret);
++              DRM_DEV_ERROR(mhdp->dev, "set event config failed: %d\n", ret);
+       return ret;
+ }
+-u32 cdn_dp_get_event(struct cdn_dp_device *dp)
++u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp)
+ {
+-      return readl(dp->regs + SW_EVENTS0);
++      return readl(mhdp->regs + SW_EVENTS0);
+ }
+-int cdn_dp_get_hpd_status(struct cdn_dp_device *dp)
++int cdns_mhdp_get_hpd_status(struct cdns_mhdp_device *mhdp)
+ {
+       u8 status;
+       int ret;
+-      ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_HPD_STATE,
+-                                0, NULL);
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                   DPTX_HPD_STATE, 0, NULL);
+       if (ret)
+               goto err_get_hpd;
+-      ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX,
+-                                            DPTX_HPD_STATE, sizeof(status));
++      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
++                                               DPTX_HPD_STATE,
++                                               sizeof(status));
+       if (ret)
+               goto err_get_hpd;
+-      ret = cdn_dp_mailbox_read_receive(dp, &status, sizeof(status));
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, &status, sizeof(status));
+       if (ret)
+               goto err_get_hpd;
+       return status;
+ err_get_hpd:
+-      DRM_DEV_ERROR(dp->dev, "get hpd status failed: %d\n", ret);
++      DRM_DEV_ERROR(mhdp->dev, "get hpd status failed: %d\n", ret);
+       return ret;
+ }
+-int cdn_dp_get_edid_block(void *data, u8 *edid,
++int cdns_mhdp_get_edid_block(void *data, u8 *edid,
+                         unsigned int block, size_t length)
+ {
+-      struct cdn_dp_device *dp = data;
++      struct cdns_mhdp_device *mhdp = data;
+       u8 msg[2], reg[2], i;
+       int ret;
+@@ -442,22 +444,23 @@ int cdn_dp_get_edid_block(void *data, u8
+               msg[0] = block / 2;
+               msg[1] = block % 2;
+-              ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_GET_EDID,
+-                                        sizeof(msg), msg);
++              ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                           DPTX_GET_EDID, sizeof(msg), msg);
+               if (ret)
+                       continue;
+-              ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX,
+-                                                    DPTX_GET_EDID,
+-                                                    sizeof(reg) + length);
++              ret = cdns_mhdp_mailbox_validate_receive(mhdp,
++                                                       MB_MODULE_ID_DP_TX,
++                                                       DPTX_GET_EDID,
++                                                       sizeof(reg) + length);
+               if (ret)
+                       continue;
+-              ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg));
++              ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+               if (ret)
+                       continue;
+-              ret = cdn_dp_mailbox_read_receive(dp, edid, length);
++              ret = cdns_mhdp_mailbox_read_receive(mhdp, edid, length);
+               if (ret)
+                       continue;
+@@ -466,13 +469,13 @@ int cdn_dp_get_edid_block(void *data, u8
+       }
+       if (ret)
+-              DRM_DEV_ERROR(dp->dev, "get block[%d] edid failed: %d\n", block,
+-                            ret);
++              DRM_DEV_ERROR(mhdp->dev, "get block[%d] edid failed: %d\n",
++                            block, ret);
+       return ret;
+ }
+-static int cdn_dp_training_start(struct cdn_dp_device *dp)
++static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp)
+ {
+       unsigned long timeout;
+       u8 msg, event[2];
+@@ -481,26 +484,28 @@ static int cdn_dp_training_start(struct
+       msg = LINK_TRAINING_RUN;
+       /* start training */
+-      ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_TRAINING_CONTROL,
+-                                sizeof(msg), &msg);
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                   DPTX_TRAINING_CONTROL, sizeof(msg), &msg);
+       if (ret)
+               goto err_training_start;
+       timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS);
+       while (time_before(jiffies, timeout)) {
+               msleep(LINK_TRAINING_RETRY_MS);
+-              ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX,
+-                                        DPTX_READ_EVENT, 0, NULL);
++              ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                           DPTX_READ_EVENT, 0, NULL);
+               if (ret)
+                       goto err_training_start;
+-              ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX,
+-                                                    DPTX_READ_EVENT,
+-                                                    sizeof(event));
++              ret = cdns_mhdp_mailbox_validate_receive(mhdp,
++                                                       MB_MODULE_ID_DP_TX,
++                                                       DPTX_READ_EVENT,
++                                                       sizeof(event));
+               if (ret)
+                       goto err_training_start;
+-              ret = cdn_dp_mailbox_read_receive(dp, event, sizeof(event));
++              ret = cdns_mhdp_mailbox_read_receive(mhdp, event,
++                                                   sizeof(event));
+               if (ret)
+                       goto err_training_start;
+@@ -511,76 +516,76 @@ static int cdn_dp_training_start(struct
+       ret = -ETIMEDOUT;
+ err_training_start:
+-      DRM_DEV_ERROR(dp->dev, "training failed: %d\n", ret);
++      DRM_DEV_ERROR(mhdp->dev, "training failed: %d\n", ret);
+       return ret;
+ }
+-static int cdn_dp_get_training_status(struct cdn_dp_device *dp)
++static int cdns_mhdp_get_training_status(struct cdns_mhdp_device *mhdp)
+ {
+       u8 status[10];
+       int ret;
+-      ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_LINK_STAT,
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, DPTX_READ_LINK_STAT,
+                                 0, NULL);
+       if (ret)
+               goto err_get_training_status;
+-      ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX,
++      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+                                             DPTX_READ_LINK_STAT,
+                                             sizeof(status));
+       if (ret)
+               goto err_get_training_status;
+-      ret = cdn_dp_mailbox_read_receive(dp, status, sizeof(status));
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, status, sizeof(status));
+       if (ret)
+               goto err_get_training_status;
+-      dp->link.rate = drm_dp_bw_code_to_link_rate(status[0]);
+-      dp->link.num_lanes = status[1];
++      mhdp->link.rate = drm_dp_bw_code_to_link_rate(status[0]);
++      mhdp->link.num_lanes = status[1];
+ err_get_training_status:
+       if (ret)
+-              DRM_DEV_ERROR(dp->dev, "get training status failed: %d\n", ret);
++              DRM_DEV_ERROR(mhdp->dev, "get training status failed: %d\n", ret);
+       return ret;
+ }
+-int cdn_dp_train_link(struct cdn_dp_device *dp)
++int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp)
+ {
+       int ret;
+-      ret = cdn_dp_training_start(dp);
++      ret = cdns_mhdp_training_start(mhdp);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "Failed to start training %d\n", ret);
++              DRM_DEV_ERROR(mhdp->dev, "Failed to start training %d\n", ret);
+               return ret;
+       }
+-      ret = cdn_dp_get_training_status(dp);
++      ret = cdns_mhdp_get_training_status(mhdp);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "Failed to get training stat %d\n", ret);
++              DRM_DEV_ERROR(mhdp->dev, "Failed to get training stat %d\n", ret);
+               return ret;
+       }
+-      DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->link.rate,
+-                        dp->link.num_lanes);
++      DRM_DEV_DEBUG_KMS(mhdp->dev, "rate:0x%x, lanes:%d\n", mhdp->link.rate,
++                        mhdp->link.num_lanes);
+       return ret;
+ }
+-int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active)
++int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active)
+ {
+       u8 msg;
+       int ret;
+       msg = !!active;
+-      ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_SET_VIDEO,
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, DPTX_SET_VIDEO,
+                                 sizeof(msg), &msg);
+       if (ret)
+-              DRM_DEV_ERROR(dp->dev, "set video status failed: %d\n", ret);
++              DRM_DEV_ERROR(mhdp->dev, "set video status failed: %d\n", ret);
+       return ret;
+ }
+-static int cdn_dp_get_msa_misc(struct video_info *video,
++static int cdns_mhdp_get_msa_misc(struct video_info *video,
+                              struct drm_display_mode *mode)
+ {
+       u32 msa_misc;
+@@ -627,10 +632,10 @@ static int cdn_dp_get_msa_misc(struct vi
+       return msa_misc;
+ }
+-int cdn_dp_config_video(struct cdn_dp_device *dp)
++int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp)
+ {
+-      struct video_info *video = &dp->video_info;
+-      struct drm_display_mode *mode = &dp->mode;
++      struct video_info *video = &mhdp->video_info;
++      struct drm_display_mode *mode = &mhdp->mode;
+       u64 symbol;
+       u32 val, link_rate, rem;
+       u8 bit_per_pix, tu_size_reg = TU_SIZE;
+@@ -639,13 +644,13 @@ int cdn_dp_config_video(struct cdn_dp_de
+       bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ?
+                     (video->color_depth * 2) : (video->color_depth * 3);
+-      link_rate = dp->link.rate / 1000;
++      link_rate = mhdp->link.rate / 1000;
+-      ret = cdn_dp_reg_write(dp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE);
++      ret = cdns_mhdp_reg_write(mhdp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE);
+       if (ret)
+               goto err_config_video;
+-      ret = cdn_dp_reg_write(dp, HSYNC2VSYNC_POL_CTRL, 0);
++      ret = cdns_mhdp_reg_write(mhdp, HSYNC2VSYNC_POL_CTRL, 0);
+       if (ret)
+               goto err_config_video;
+@@ -659,13 +664,13 @@ int cdn_dp_config_video(struct cdn_dp_de
+       do {
+               tu_size_reg += 2;
+               symbol = tu_size_reg * mode->clock * bit_per_pix;
+-              do_div(symbol, dp->link.num_lanes * link_rate * 8);
++              do_div(symbol, mhdp->link.num_lanes * link_rate * 8);
+               rem = do_div(symbol, 1000);
+               if (tu_size_reg > 64) {
+                       ret = -EINVAL;
+-                      DRM_DEV_ERROR(dp->dev,
++                      DRM_DEV_ERROR(mhdp->dev,
+                                     "tu error, clk:%d, lanes:%d, rate:%d\n",
+-                                    mode->clock, dp->link.num_lanes,
++                                    mode->clock, mhdp->link.num_lanes,
+                                     link_rate);
+                       goto err_config_video;
+               }
+@@ -674,16 +679,16 @@ int cdn_dp_config_video(struct cdn_dp_de
+       val = symbol + (tu_size_reg << 8);
+       val |= TU_CNT_RST_EN;
+-      ret = cdn_dp_reg_write(dp, DP_FRAMER_TU, val);
++      ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_TU, val);
+       if (ret)
+               goto err_config_video;
+       /* set the FIFO Buffer size */
+       val = div_u64(mode->clock * (symbol + 1), 1000) + link_rate;
+-      val /= (dp->link.num_lanes * link_rate);
++      val /= (mhdp->link.num_lanes * link_rate);
+       val = div_u64(8 * (symbol + 1), bit_per_pix) - val;
+       val += 2;
+-      ret = cdn_dp_reg_write(dp, DP_VC_TABLE(15), val);
++      ret = cdns_mhdp_reg_write(mhdp, DP_VC_TABLE(15), val);
+       switch (video->color_depth) {
+       case 6:
+@@ -704,136 +709,137 @@ int cdn_dp_config_video(struct cdn_dp_de
+       };
+       val += video->color_fmt << 8;
+-      ret = cdn_dp_reg_write(dp, DP_FRAMER_PXL_REPR, val);
++      ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_PXL_REPR, val);
+       if (ret)
+               goto err_config_video;
+       val = video->h_sync_polarity ? DP_FRAMER_SP_HSP : 0;
+       val |= video->v_sync_polarity ? DP_FRAMER_SP_VSP : 0;
+-      ret = cdn_dp_reg_write(dp, DP_FRAMER_SP, val);
++      ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_SP, val);
+       if (ret)
+               goto err_config_video;
+       val = (mode->hsync_start - mode->hdisplay) << 16;
+       val |= mode->htotal - mode->hsync_end;
+-      ret = cdn_dp_reg_write(dp, DP_FRONT_BACK_PORCH, val);
++      ret = cdns_mhdp_reg_write(mhdp, DP_FRONT_BACK_PORCH, val);
+       if (ret)
+               goto err_config_video;
+       val = mode->hdisplay * bit_per_pix / 8;
+-      ret = cdn_dp_reg_write(dp, DP_BYTE_COUNT, val);
++      ret = cdns_mhdp_reg_write(mhdp, DP_BYTE_COUNT, val);
+       if (ret)
+               goto err_config_video;
+       val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16);
+-      ret = cdn_dp_reg_write(dp, MSA_HORIZONTAL_0, val);
++      ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_0, val);
+       if (ret)
+               goto err_config_video;
+       val = mode->hsync_end - mode->hsync_start;
+       val |= (mode->hdisplay << 16) | (video->h_sync_polarity << 15);
+-      ret = cdn_dp_reg_write(dp, MSA_HORIZONTAL_1, val);
++      ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_1, val);
+       if (ret)
+               goto err_config_video;
+       val = mode->vtotal;
+       val |= (mode->vtotal - mode->vsync_start) << 16;
+-      ret = cdn_dp_reg_write(dp, MSA_VERTICAL_0, val);
++      ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_0, val);
+       if (ret)
+               goto err_config_video;
+       val = mode->vsync_end - mode->vsync_start;
+       val |= (mode->vdisplay << 16) | (video->v_sync_polarity << 15);
+-      ret = cdn_dp_reg_write(dp, MSA_VERTICAL_1, val);
++      ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_1, val);
+       if (ret)
+               goto err_config_video;
+-      val = cdn_dp_get_msa_misc(video, mode);
+-      ret = cdn_dp_reg_write(dp, MSA_MISC, val);
++      val = cdns_mhdp_get_msa_misc(video, mode);
++      ret = cdns_mhdp_reg_write(mhdp, MSA_MISC, val);
+       if (ret)
+               goto err_config_video;
+-      ret = cdn_dp_reg_write(dp, STREAM_CONFIG, 1);
++      ret = cdns_mhdp_reg_write(mhdp, STREAM_CONFIG, 1);
+       if (ret)
+               goto err_config_video;
+       val = mode->hsync_end - mode->hsync_start;
+       val |= mode->hdisplay << 16;
+-      ret = cdn_dp_reg_write(dp, DP_HORIZONTAL, val);
++      ret = cdns_mhdp_reg_write(mhdp, DP_HORIZONTAL, val);
+       if (ret)
+               goto err_config_video;
+       val = mode->vdisplay;
+       val |= (mode->vtotal - mode->vsync_start) << 16;
+-      ret = cdn_dp_reg_write(dp, DP_VERTICAL_0, val);
++      ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_0, val);
+       if (ret)
+               goto err_config_video;
+       val = mode->vtotal;
+-      ret = cdn_dp_reg_write(dp, DP_VERTICAL_1, val);
++      ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_1, val);
+       if (ret)
+               goto err_config_video;
+-      ret = cdn_dp_reg_write_bit(dp, DP_VB_ID, 2, 1, 0);
++      ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 2, 1, 0);
+ err_config_video:
+       if (ret)
+-              DRM_DEV_ERROR(dp->dev, "config video failed: %d\n", ret);
++              DRM_DEV_ERROR(mhdp->dev, "config video failed: %d\n", ret);
+       return ret;
+ }
+-int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio)
++int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
++                       struct audio_info *audio)
+ {
+       int ret;
+-      ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, 0);
++      ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, 0);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->dev, "audio stop failed: %d\n", ret);
++              DRM_DEV_ERROR(mhdp->dev, "audio stop failed: %d\n", ret);
+               return ret;
+       }
+-      writel(0, dp->regs + SPDIF_CTRL_ADDR);
++      writel(0, mhdp->regs + SPDIF_CTRL_ADDR);
+       /* clearn the audio config and reset */
+-      writel(0, dp->regs + AUDIO_SRC_CNTL);
+-      writel(0, dp->regs + AUDIO_SRC_CNFG);
+-      writel(AUDIO_SW_RST, dp->regs + AUDIO_SRC_CNTL);
+-      writel(0, dp->regs + AUDIO_SRC_CNTL);
++      writel(0, mhdp->regs + AUDIO_SRC_CNTL);
++      writel(0, mhdp->regs + AUDIO_SRC_CNFG);
++      writel(AUDIO_SW_RST, mhdp->regs + AUDIO_SRC_CNTL);
++      writel(0, mhdp->regs + AUDIO_SRC_CNTL);
+       /* reset smpl2pckt component  */
+-      writel(0, dp->regs + SMPL2PKT_CNTL);
+-      writel(AUDIO_SW_RST, dp->regs + SMPL2PKT_CNTL);
+-      writel(0, dp->regs + SMPL2PKT_CNTL);
++      writel(0, mhdp->regs + SMPL2PKT_CNTL);
++      writel(AUDIO_SW_RST, mhdp->regs + SMPL2PKT_CNTL);
++      writel(0, mhdp->regs + SMPL2PKT_CNTL);
+       /* reset FIFO */
+-      writel(AUDIO_SW_RST, dp->regs + FIFO_CNTL);
+-      writel(0, dp->regs + FIFO_CNTL);
++      writel(AUDIO_SW_RST, mhdp->regs + FIFO_CNTL);
++      writel(0, mhdp->regs + FIFO_CNTL);
+       if (audio->format == AFMT_SPDIF)
+-              clk_disable_unprepare(dp->spdif_clk);
++              clk_disable_unprepare(mhdp->spdif_clk);
+       return 0;
+ }
+-int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable)
++int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable)
+ {
+       int ret;
+-      ret = cdn_dp_reg_write_bit(dp, DP_VB_ID, 4, 1, enable);
++      ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 4, 1, enable);
+       if (ret)
+-              DRM_DEV_ERROR(dp->dev, "audio mute failed: %d\n", ret);
++              DRM_DEV_ERROR(mhdp->dev, "audio mute failed: %d\n", ret);
+       return ret;
+ }
+-static void cdn_dp_audio_config_i2s(struct cdn_dp_device *dp,
+-                                  struct audio_info *audio)
++static void cdns_mhdp_audio_config_i2s(struct cdns_mhdp_device *mhdp,
++                                     struct audio_info *audio)
+ {
+       int sub_pckt_num = 1, i2s_port_en_val = 0xf, i;
+       u32 val;
+       if (audio->channels == 2) {
+-              if (dp->link.num_lanes == 1)
++              if (mhdp->link.num_lanes == 1)
+                       sub_pckt_num = 2;
+               else
+                       sub_pckt_num = 4;
+@@ -843,15 +849,15 @@ static void cdn_dp_audio_config_i2s(stru
+               i2s_port_en_val = 3;
+       }
+-      writel(0x0, dp->regs + SPDIF_CTRL_ADDR);
++      writel(0x0, mhdp->regs + SPDIF_CTRL_ADDR);
+-      writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL);
++      writel(SYNC_WR_TO_CH_ZERO, mhdp->regs + FIFO_CNTL);
+       val = MAX_NUM_CH(audio->channels);
+       val |= NUM_OF_I2S_PORTS(audio->channels);
+       val |= AUDIO_TYPE_LPCM;
+       val |= CFG_SUB_PCKT_NUM(sub_pckt_num);
+-      writel(val, dp->regs + SMPL2PKT_CNFG);
++      writel(val, mhdp->regs + SMPL2PKT_CNFG);
+       if (audio->sample_width == 16)
+               val = 0;
+@@ -863,7 +869,7 @@ static void cdn_dp_audio_config_i2s(stru
+       val |= AUDIO_CH_NUM(audio->channels);
+       val |= I2S_DEC_PORT_EN(i2s_port_en_val);
+       val |= TRANS_SMPL_WIDTH_32;
+-      writel(val, dp->regs + AUDIO_SRC_CNFG);
++      writel(val, mhdp->regs + AUDIO_SRC_CNFG);
+       for (i = 0; i < (audio->channels + 1) / 2; i++) {
+               if (audio->sample_width == 16)
+@@ -872,7 +878,7 @@ static void cdn_dp_audio_config_i2s(stru
+                       val = (0x0b << 8) | (0x0b << 20);
+               val |= ((2 * i) << 4) | ((2 * i + 1) << 16);
+-              writel(val, dp->regs + STTS_BIT_CH(i));
++              writel(val, mhdp->regs + STTS_BIT_CH(i));
+       }
+       switch (audio->sample_rate) {
+@@ -906,56 +912,57 @@ static void cdn_dp_audio_config_i2s(stru
+               break;
+       }
+       val |= 4;
+-      writel(val, dp->regs + COM_CH_STTS_BITS);
++      writel(val, mhdp->regs + COM_CH_STTS_BITS);
+-      writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL);
+-      writel(I2S_DEC_START, dp->regs + AUDIO_SRC_CNTL);
++      writel(SMPL2PKT_EN, mhdp->regs + SMPL2PKT_CNTL);
++      writel(I2S_DEC_START, mhdp->regs + AUDIO_SRC_CNTL);
+ }
+-static void cdn_dp_audio_config_spdif(struct cdn_dp_device *dp)
++static void cdns_mhdp_audio_config_spdif(struct cdns_mhdp_device *mhdp)
+ {
+       u32 val;
+-      writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL);
++      writel(SYNC_WR_TO_CH_ZERO, mhdp->regs + FIFO_CNTL);
+       val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4);
+-      writel(val, dp->regs + SMPL2PKT_CNFG);
+-      writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL);
++      writel(val, mhdp->regs + SMPL2PKT_CNFG);
++      writel(SMPL2PKT_EN, mhdp->regs + SMPL2PKT_CNTL);
+       val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS;
+-      writel(val, dp->regs + SPDIF_CTRL_ADDR);
++      writel(val, mhdp->regs + SPDIF_CTRL_ADDR);
+-      clk_prepare_enable(dp->spdif_clk);
+-      clk_set_rate(dp->spdif_clk, CDN_DP_SPDIF_CLK);
++      clk_prepare_enable(mhdp->spdif_clk);
++      clk_set_rate(mhdp->spdif_clk, CDNS_DP_SPDIF_CLK);
+ }
+-int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio)
++int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
++                         struct audio_info *audio)
+ {
+       int ret;
+       /* reset the spdif clk before config */
+       if (audio->format == AFMT_SPDIF) {
+-              reset_control_assert(dp->spdif_rst);
+-              reset_control_deassert(dp->spdif_rst);
++              reset_control_assert(mhdp->spdif_rst);
++              reset_control_deassert(mhdp->spdif_rst);
+       }
+-      ret = cdn_dp_reg_write(dp, CM_LANE_CTRL, LANE_REF_CYC);
++      ret = cdns_mhdp_reg_write(mhdp, CM_LANE_CTRL, LANE_REF_CYC);
+       if (ret)
+               goto err_audio_config;
+-      ret = cdn_dp_reg_write(dp, CM_CTRL, 0);
++      ret = cdns_mhdp_reg_write(mhdp, CM_CTRL, 0);
+       if (ret)
+               goto err_audio_config;
+       if (audio->format == AFMT_I2S)
+-              cdn_dp_audio_config_i2s(dp, audio);
++              cdns_mhdp_audio_config_i2s(mhdp, audio);
+       else if (audio->format == AFMT_SPDIF)
+-              cdn_dp_audio_config_spdif(dp);
++              cdns_mhdp_audio_config_spdif(mhdp);
+-      ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN);
++      ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN);
+ err_audio_config:
+       if (ret)
+-              DRM_DEV_ERROR(dp->dev, "audio config failed: %d\n", ret);
++              DRM_DEV_ERROR(mhdp->dev, "audio config failed: %d\n", ret);
+       return ret;
+ }
+--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h
++++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
+@@ -387,7 +387,7 @@
+ #define HDCP_TX_IS_RECEIVER_ID_VALID_EVENT    BIT(7)
+ #define TU_SIZE                                       30
+-#define CDN_DP_MAX_LINK_RATE                  DP_LINK_BW_5_4
++#define CDNS_DP_MAX_LINK_RATE                 DP_LINK_BW_5_4
+ /* audio */
+ #define AUDIO_PACK_EN                         BIT(8)
+@@ -451,24 +451,96 @@ enum vic_bt_type {
+       BT_709 = 0x1,
+ };
+-void cdn_dp_clock_reset(struct cdn_dp_device *dp);
++enum audio_format {
++      AFMT_I2S = 0,
++      AFMT_SPDIF = 1,
++      AFMT_UNUSED,
++};
++
++struct audio_info {
++      enum audio_format format;
++      int sample_rate;
++      int channels;
++      int sample_width;
++};
++
++enum vic_pxl_encoding_format {
++      PXL_RGB = 0x1,
++      YCBCR_4_4_4 = 0x2,
++      YCBCR_4_2_2 = 0x4,
++      YCBCR_4_2_0 = 0x8,
++      Y_ONLY = 0x10,
++};
++
++struct video_info {
++      bool h_sync_polarity;
++      bool v_sync_polarity;
++      bool interlaced;
++      int color_depth;
++      enum vic_pxl_encoding_format color_fmt;
++};
++
++struct cdns_mhdp_host {
++      unsigned int    link_rate;
++      u8      lanes_cnt;
++      u8      volt_swing;
++      u8      pre_emphasis;
++      u8      pattern_supp;
++      u8      fast_link;
++      u8      lane_mapping;
++      u8      enhanced;
++};
++
++struct cdns_mhdp_sink {
++      unsigned int    link_rate;
++      u8      lanes_cnt;
++      u8      pattern_supp;
++      u8      fast_link;
++      u8      enhanced;
++};
++
++struct cdns_mhdp_device {
++      void __iomem            *regs;
++
++      struct device           *dev;
++
++      struct drm_dp_link      link;
++      struct drm_connector    connector;
++      struct clk              *spdif_clk;
++      struct reset_control    *spdif_rst;
++
++      struct drm_dp_aux       aux;
++      struct cdns_mhdp_host   host;
++      struct cdns_mhdp_sink   sink;
++      struct drm_bridge       bridge;
++      struct phy              *phy;
++      void __iomem            *dbg_regs;
++
++      struct video_info       video_info;
++      struct drm_display_mode mode;
++      unsigned int            fw_version;
++};
+-void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, unsigned long clk);
+-int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem,
+-                       u32 i_size, const u32 *d_mem, u32 d_size);
+-int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable);
+-int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip);
+-int cdn_dp_event_config(struct cdn_dp_device *dp);
+-u32 cdn_dp_get_event(struct cdn_dp_device *dp);
+-int cdn_dp_get_hpd_status(struct cdn_dp_device *dp);
+-int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value);
+-int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len);
+-int cdn_dp_get_edid_block(void *dp, u8 *edid,
+-                        unsigned int block, size_t length);
+-int cdn_dp_train_link(struct cdn_dp_device *dp);
+-int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active);
+-int cdn_dp_config_video(struct cdn_dp_device *dp);
+-int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio);
+-int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable);
+-int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio);
++void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp);
++void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk);
++int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
++                          u32 i_size, const u32 *d_mem, u32 d_size);
++int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable);
++int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, u8 lanes, bool flip);
++int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp);
++u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp);
++int cdns_mhdp_get_hpd_status(struct cdns_mhdp_device *mhdp);
++int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value);
++int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,
++                      u32 addr, u8 *data, u16 len);
++int cdns_mhdp_get_edid_block(void *mhdp, u8 *edid,
++                           unsigned int block, size_t length);
++int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp);
++int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active);
++int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp);
++int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
++                       struct audio_info *audio);
++int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable);
++int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
++                         struct audio_info *audio);
+ #endif /* _CDN_DP_REG_H */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0003-drm-bridge-add-Cadence-MHDP-HDMI-DP-API.patch b/target/linux/layerscape/patches-5.4/805-display-0003-drm-bridge-add-Cadence-MHDP-HDMI-DP-API.patch
new file mode 100644 (file)
index 0000000..19e7626
--- /dev/null
@@ -0,0 +1,4241 @@
+From d94a1a8c31cab273b3409c9c380a8089a794f592 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Wed, 10 Jul 2019 14:22:12 +0800
+Subject: [PATCH] drm: bridge: add Cadence MHDP HDMI/DP API
+
+Changes made in the low level driver (cdn-dp-reg.*):
+- moved it to from drivers/gpu/drm/rockchip to
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c and
+ include/drm/bridge/cdns-mhdp-common.h
+- functions for sending/receiving commands are now public
+- added functions for reading registers and link training adjustment
+
+Changes made in RK's driver (cdn-dp-core.*):
+- Moved audio_info and audio_pdev fields from cdn_dp_device to
+  cdns_mhdp_device structure.
+
+Signed-off-by: Quentin Schulz<quentin.schulz@free-electrons.com>
+Signed-off-by: Piotr Sroka <piotrs@cadence.com>
+Signed-off-by: Damian Kos <dkos@cadence.com>
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/Kconfig                    |    2 +
+ drivers/gpu/drm/bridge/Makefile                   |    1 +
+ drivers/gpu/drm/bridge/cadence/Kconfig            |    7 +
+ drivers/gpu/drm/bridge/cadence/Makefile           |    3 +
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c | 1165 +++++++++++++++++++++
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c   |  296 ++++++
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp.h        |  209 ++++
+ drivers/gpu/drm/rockchip/Kconfig                  |    4 +-
+ drivers/gpu/drm/rockchip/Makefile                 |    2 +-
+ drivers/gpu/drm/rockchip/cdn-dp-core.c            |   48 +-
+ drivers/gpu/drm/rockchip/cdn-dp-core.h            |    5 +-
+ drivers/gpu/drm/rockchip/cdn-dp-reg.c             |  968 -----------------
+ drivers/gpu/drm/rockchip/cdn-dp-reg.h             |  546 ----------
+ include/drm/bridge/cdns-mhdp-cbs.h                |   29 +
+ include/drm/bridge/cdns-mhdp-common.h             |  704 +++++++++++++
+ 15 files changed, 2446 insertions(+), 1543 deletions(-)
+ create mode 100644 drivers/gpu/drm/bridge/cadence/Kconfig
+ create mode 100644 drivers/gpu/drm/bridge/cadence/Makefile
+ create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
+ create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
+ create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp.h
+ delete mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.c
+ delete mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.h
+ create mode 100644 include/drm/bridge/cdns-mhdp-cbs.h
+ create mode 100644 include/drm/bridge/cdns-mhdp-common.h
+
+--- a/drivers/gpu/drm/bridge/Kconfig
++++ b/drivers/gpu/drm/bridge/Kconfig
+@@ -154,6 +154,8 @@ source "drivers/gpu/drm/bridge/analogix/
+ source "drivers/gpu/drm/bridge/adv7511/Kconfig"
++source "drivers/gpu/drm/bridge/cadence/Kconfig"
++
+ source "drivers/gpu/drm/bridge/synopsys/Kconfig"
+ endmenu
+--- a/drivers/gpu/drm/bridge/Makefile
++++ b/drivers/gpu/drm/bridge/Makefile
+@@ -16,4 +16,5 @@ obj-$(CONFIG_DRM_ANALOGIX_DP) += analogi
+ obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
+ obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o
+ obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
++obj-y += cadence/
+ obj-y += synopsys/
+--- /dev/null
++++ b/drivers/gpu/drm/bridge/cadence/Kconfig
+@@ -0,0 +1,7 @@
++config DRM_CDNS_MHDP
++      tristate "Cadence MHDP COMMON API driver"
++      select DRM_KMS_HELPER
++      select DRM_PANEL_BRIDGE
++      depends on OF
++      help
++        Support Cadence MHDP API library.
+--- /dev/null
++++ b/drivers/gpu/drm/bridge/cadence/Makefile
+@@ -0,0 +1,3 @@
++#ccflags-y := -Iinclude/drm
++
++obj-$(CONFIG_DRM_CDNS_MHDP) += cdns-mhdp-common.o cdns-mhdp-hdmi.o
+--- /dev/null
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
+@@ -0,0 +1,1165 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
++ * Author: Chris Zhong <zyw@rock-chips.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/iopoll.h>
++#include <linux/reset.h>
++
++#include <asm/unaligned.h>
++
++#include <drm/bridge/cdns-mhdp-common.h>
++#include <drm/drm_modes.h>
++#include <drm/drm_print.h>
++
++#define CDNS_DP_SPDIF_CLK             200000000
++#define FW_ALIVE_TIMEOUT_US           1000000
++#define MAILBOX_RETRY_US              1000
++#define MAILBOX_TIMEOUT_US            5000000
++#define LINK_TRAINING_RETRY_MS                20
++#define LINK_TRAINING_TIMEOUT_MS      500
++
++static inline u32 get_unaligned_be24(const void *p)
++{
++      const u8 *_p = p;
++
++      return _p[0] << 16 | _p[1] << 8 | _p[2];
++}
++
++static inline void put_unaligned_be24(u32 val, void *p)
++{
++      u8 *_p = p;
++
++      _p[0] = val >> 16;
++      _p[1] = val >> 8;
++      _p[2] = val;
++}
++
++void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk)
++{
++      writel(clk / 1000000, mhdp->regs + SW_CLK_H);
++}
++EXPORT_SYMBOL(cdns_mhdp_set_fw_clk);
++
++void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp)
++{
++      u32 val;
++
++      val = DPTX_FRMR_DATA_CLK_RSTN_EN |
++            DPTX_FRMR_DATA_CLK_EN |
++            DPTX_PHY_DATA_RSTN_EN |
++            DPTX_PHY_DATA_CLK_EN |
++            DPTX_PHY_CHAR_RSTN_EN |
++            DPTX_PHY_CHAR_CLK_EN |
++            SOURCE_AUX_SYS_CLK_RSTN_EN |
++            SOURCE_AUX_SYS_CLK_EN |
++            DPTX_SYS_CLK_RSTN_EN |
++            DPTX_SYS_CLK_EN |
++            CFG_DPTX_VIF_CLK_RSTN_EN |
++            CFG_DPTX_VIF_CLK_EN;
++      writel(val, mhdp->regs + SOURCE_DPTX_CAR);
++
++      val = SOURCE_PHY_RSTN_EN | SOURCE_PHY_CLK_EN;
++      writel(val, mhdp->regs + SOURCE_PHY_CAR);
++
++      val = SOURCE_PKT_SYS_RSTN_EN |
++            SOURCE_PKT_SYS_CLK_EN |
++            SOURCE_PKT_DATA_RSTN_EN |
++            SOURCE_PKT_DATA_CLK_EN;
++      writel(val, mhdp->regs + SOURCE_PKT_CAR);
++
++      val = SPDIF_CDR_CLK_RSTN_EN |
++            SPDIF_CDR_CLK_EN |
++            SOURCE_AIF_SYS_RSTN_EN |
++            SOURCE_AIF_SYS_CLK_EN |
++            SOURCE_AIF_CLK_RSTN_EN |
++            SOURCE_AIF_CLK_EN;
++      writel(val, mhdp->regs + SOURCE_AIF_CAR);
++
++      val = SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN |
++            SOURCE_CIPHER_SYS_CLK_EN |
++            SOURCE_CIPHER_CHAR_CLK_RSTN_EN |
++            SOURCE_CIPHER_CHAR_CLK_EN;
++      writel(val, mhdp->regs + SOURCE_CIPHER_CAR);
++
++      val = SOURCE_CRYPTO_SYS_CLK_RSTN_EN |
++            SOURCE_CRYPTO_SYS_CLK_EN;
++      writel(val, mhdp->regs + SOURCE_CRYPTO_CAR);
++
++      /* enable Mailbox and PIF interrupt */
++      writel(0, mhdp->regs + APB_INT_MASK);
++}
++EXPORT_SYMBOL(cdns_mhdp_clock_reset);
++
++int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)
++{
++      int val, ret;
++
++      ret = readx_poll_timeout(readl, mhdp->regs + MAILBOX_EMPTY_ADDR,
++                               val, !val, MAILBOX_RETRY_US,
++                               MAILBOX_TIMEOUT_US);
++      if (ret < 0)
++              return ret;
++
++      return readl(mhdp->regs + MAILBOX0_RD_DATA) & 0xff;
++}
++EXPORT_SYMBOL(cdns_mhdp_mailbox_read);
++
++static int cdp_dp_mailbox_write(struct cdns_mhdp_device *mhdp, u8 val)
++{
++      int ret, full;
++
++      ret = readx_poll_timeout(readl, mhdp->regs + MAILBOX_FULL_ADDR,
++                               full, !full, MAILBOX_RETRY_US,
++                               MAILBOX_TIMEOUT_US);
++      if (ret < 0)
++              return ret;
++
++      writel(val, mhdp->regs + MAILBOX0_WR_DATA);
++
++      return 0;
++}
++
++int cdns_mhdp_mailbox_validate_receive(struct cdns_mhdp_device *mhdp,
++                                            u8 module_id, u8 opcode,
++                                            u16 req_size)
++{
++      u32 mbox_size, i;
++      u8 header[4];
++      int ret;
++
++      /* read the header of the message */
++      for (i = 0; i < 4; i++) {
++              ret = cdns_mhdp_mailbox_read(mhdp);
++              if (ret < 0)
++                      return ret;
++
++              header[i] = ret;
++      }
++
++      mbox_size = get_unaligned_be16(header + 2);
++
++      if (opcode != header[0] || module_id != header[1] ||
++          req_size != mbox_size) {
++              /*
++               * If the message in mailbox is not what we want, we need to
++               * clear the mailbox by reading its contents.
++               */
++              for (i = 0; i < mbox_size; i++)
++                      if (cdns_mhdp_mailbox_read(mhdp) < 0)
++                              break;
++
++              return -EINVAL;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(cdns_mhdp_mailbox_validate_receive);
++
++int cdns_mhdp_mailbox_read_receive(struct cdns_mhdp_device *mhdp,
++                                        u8 *buff, u16 buff_size)
++{
++      u32 i;
++      int ret;
++
++      for (i = 0; i < buff_size; i++) {
++              ret = cdns_mhdp_mailbox_read(mhdp);
++              if (ret < 0)
++                      return ret;
++
++              buff[i] = ret;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(cdns_mhdp_mailbox_read_receive);
++
++int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id,
++                                u8 opcode, u16 size, u8 *message)
++{
++      u8 header[4];
++      int ret, i;
++
++      header[0] = opcode;
++      header[1] = module_id;
++      put_unaligned_be16(size, header + 2);
++
++      for (i = 0; i < 4; i++) {
++              ret = cdp_dp_mailbox_write(mhdp, header[i]);
++              if (ret)
++                      return ret;
++      }
++
++      for (i = 0; i < size; i++) {
++              ret = cdp_dp_mailbox_write(mhdp, message[i]);
++              if (ret)
++                      return ret;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(cdns_mhdp_mailbox_send);
++
++int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr)
++{
++      u8 msg[4], resp[8];
++      u32 val;
++      int ret;
++
++      if (addr == 0) {
++              ret = -EINVAL;
++              goto err_reg_read;
++      }
++
++      put_unaligned_be32(addr, msg);
++
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL,
++                                   GENERAL_READ_REGISTER,
++                                   sizeof(msg), msg);
++      if (ret)
++              goto err_reg_read;
++
++      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_GENERAL,
++                                               GENERAL_READ_REGISTER,
++                                               sizeof(resp));
++      if (ret)
++              goto err_reg_read;
++
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, resp, sizeof(resp));
++      if (ret)
++              goto err_reg_read;
++
++      /* Returned address value should be the same as requested */
++      if (memcmp(msg, resp, sizeof(msg))) {
++              ret = -EINVAL;
++              goto err_reg_read;
++      }
++
++      val = get_unaligned_be32(resp + 4);
++
++      return val;
++err_reg_read:
++      DRM_DEV_ERROR(mhdp->dev, "Failed to read register.\n");
++
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_reg_read);
++
++int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val)
++{
++      u8 msg[8];
++
++      put_unaligned_be32(addr, msg);
++      put_unaligned_be32(val, msg + 4);
++
++      return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL,
++                                    GENERAL_WRITE_REGISTER, sizeof(msg), msg);
++}
++EXPORT_SYMBOL(cdns_mhdp_reg_write);
++
++int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
++                                 u8 start_bit, u8 bits_no, u32 val)
++{
++      u8 field[8];
++
++      put_unaligned_be16(addr, field);
++      field[2] = start_bit;
++      field[3] = bits_no;
++      put_unaligned_be32(val, field + 4);
++
++      return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                    DPTX_WRITE_FIELD, sizeof(field), field);
++}
++EXPORT_SYMBOL(cdns_mhdp_reg_write_bit);
++
++int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,
++                      u32 addr, u8 *data, u16 len)
++{
++      u8 msg[5], reg[5];
++      int ret;
++
++      put_unaligned_be16(len, msg);
++      put_unaligned_be24(addr, msg + 2);
++
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                   DPTX_READ_DPCD, sizeof(msg), msg);
++      if (ret)
++              goto err_dpcd_read;
++
++      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
++                                               DPTX_READ_DPCD,
++                                               sizeof(reg) + len);
++      if (ret)
++              goto err_dpcd_read;
++
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
++      if (ret)
++              goto err_dpcd_read;
++
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, data, len);
++
++err_dpcd_read:
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_dpcd_read);
++
++int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value)
++{
++      u8 msg[6], reg[5];
++      int ret;
++
++      put_unaligned_be16(1, msg);
++      put_unaligned_be24(addr, msg + 2);
++      msg[5] = value;
++
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                   DPTX_WRITE_DPCD, sizeof(msg), msg);
++      if (ret)
++              goto err_dpcd_write;
++
++      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
++                                               DPTX_WRITE_DPCD, sizeof(reg));
++      if (ret)
++              goto err_dpcd_write;
++
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
++      if (ret)
++              goto err_dpcd_write;
++
++      if (addr != get_unaligned_be24(reg + 2))
++              ret = -EINVAL;
++
++err_dpcd_write:
++      if (ret)
++              DRM_DEV_ERROR(mhdp->dev, "dpcd write failed: %d\n", ret);
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_dpcd_write);
++
++int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
++                          u32 i_size, const u32 *d_mem, u32 d_size)
++{
++      u32 reg;
++      int i, ret;
++
++      /* reset ucpu before load firmware*/
++      writel(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET,
++             mhdp->regs + APB_CTRL);
++
++      for (i = 0; i < i_size; i += 4)
++              writel(*i_mem++, mhdp->regs + ADDR_IMEM + i);
++
++      for (i = 0; i < d_size; i += 4)
++              writel(*d_mem++, mhdp->regs + ADDR_DMEM + i);
++
++      /* un-reset ucpu */
++      writel(0, mhdp->regs + APB_CTRL);
++
++      /* check the keep alive register to make sure fw working */
++      ret = readx_poll_timeout(readl, mhdp->regs + KEEP_ALIVE,
++                               reg, reg, 2000, FW_ALIVE_TIMEOUT_US);
++      if (ret < 0) {
++              DRM_DEV_ERROR(mhdp->dev, "failed to loaded the FW reg = %x\n",
++                            reg);
++              return -EINVAL;
++      }
++
++      reg = readl(mhdp->regs + VER_L) & 0xff;
++      mhdp->fw_version = reg;
++      reg = readl(mhdp->regs + VER_H) & 0xff;
++      mhdp->fw_version |= reg << 8;
++      reg = readl(mhdp->regs + VER_LIB_L_ADDR) & 0xff;
++      mhdp->fw_version |= reg << 16;
++      reg = readl(mhdp->regs + VER_LIB_H_ADDR) & 0xff;
++      mhdp->fw_version |= reg << 24;
++
++      DRM_DEV_DEBUG(mhdp->dev, "firmware version: %x\n", mhdp->fw_version);
++
++      return 0;
++}
++EXPORT_SYMBOL(cdns_mhdp_load_firmware);
++
++int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable)
++{
++      u8 msg[5];
++      int ret, i;
++
++      msg[0] = GENERAL_MAIN_CONTROL;
++      msg[1] = MB_MODULE_ID_GENERAL;
++      msg[2] = 0;
++      msg[3] = 1;
++      msg[4] = enable ? FW_ACTIVE : FW_STANDBY;
++
++      for (i = 0; i < sizeof(msg); i++) {
++              ret = cdp_dp_mailbox_write(mhdp, msg[i]);
++              if (ret)
++                      goto err_set_firmware_active;
++      }
++
++      /* read the firmware state */
++      for (i = 0; i < sizeof(msg); i++)  {
++              ret = cdns_mhdp_mailbox_read(mhdp);
++              if (ret < 0)
++                      goto err_set_firmware_active;
++
++              msg[i] = ret;
++      }
++
++      ret = 0;
++
++err_set_firmware_active:
++      if (ret < 0)
++              DRM_DEV_ERROR(mhdp->dev, "set firmware active failed\n");
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_set_firmware_active);
++
++int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, u8 lanes, bool flip)
++{
++      u8 msg[8];
++      int ret;
++
++      msg[0] = CDNS_DP_MAX_LINK_RATE;
++      msg[1] = lanes | SCRAMBLER_EN;
++      msg[2] = VOLTAGE_LEVEL_2;
++      msg[3] = PRE_EMPHASIS_LEVEL_3;
++      msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
++      msg[5] = FAST_LT_NOT_SUPPORT;
++      msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL;
++      msg[7] = ENHANCED;
++
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                   DPTX_SET_HOST_CAPABILITIES,
++                                   sizeof(msg), msg);
++      if (ret)
++              goto err_set_host_cap;
++
++/* TODO Sandor */
++//    ret = cdns_mhdp_reg_write(mhdp, DP_AUX_SWAP_INVERSION_CONTROL,
++//                              AUX_HOST_INVERT);
++
++err_set_host_cap:
++      if (ret)
++              DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret);
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_set_host_cap);
++
++int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp)
++{
++      u8 msg[5];
++      int ret;
++
++      memset(msg, 0, sizeof(msg));
++
++      msg[0] = DPTX_EVENT_ENABLE_HPD | DPTX_EVENT_ENABLE_TRAINING;
++
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                   DPTX_ENABLE_EVENT, sizeof(msg), msg);
++      if (ret)
++              DRM_DEV_ERROR(mhdp->dev, "set event config failed: %d\n", ret);
++
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_event_config);
++
++u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp)
++{
++      return readl(mhdp->regs + SW_EVENTS0);
++}
++EXPORT_SYMBOL(cdns_mhdp_get_event);
++
++int cdns_mhdp_get_hpd_status(struct cdns_mhdp_device *mhdp)
++{
++      u8 status;
++      int ret;
++
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                   DPTX_HPD_STATE, 0, NULL);
++      if (ret)
++              goto err_get_hpd;
++
++      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
++                                               DPTX_HPD_STATE,
++                                               sizeof(status));
++      if (ret)
++              goto err_get_hpd;
++
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, &status, sizeof(status));
++      if (ret)
++              goto err_get_hpd;
++
++      return status;
++
++err_get_hpd:
++      DRM_DEV_ERROR(mhdp->dev, "get hpd status failed: %d\n", ret);
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_get_hpd_status);
++
++int cdns_mhdp_get_edid_block(void *data, u8 *edid,
++                        unsigned int block, size_t length)
++{
++      struct cdns_mhdp_device *mhdp = data;
++      u8 msg[2], reg[2], i;
++      int ret;
++
++      for (i = 0; i < 4; i++) {
++              msg[0] = block / 2;
++              msg[1] = block % 2;
++
++              ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                           DPTX_GET_EDID, sizeof(msg), msg);
++              if (ret)
++                      continue;
++
++              ret = cdns_mhdp_mailbox_validate_receive(mhdp,
++                                                       MB_MODULE_ID_DP_TX,
++                                                       DPTX_GET_EDID,
++                                                       sizeof(reg) + length);
++              if (ret)
++                      continue;
++
++              ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
++              if (ret)
++                      continue;
++
++              ret = cdns_mhdp_mailbox_read_receive(mhdp, edid, length);
++              if (ret)
++                      continue;
++
++              if (reg[0] == length && reg[1] == block / 2)
++                      break;
++      }
++
++      if (ret)
++              DRM_DEV_ERROR(mhdp->dev, "get block[%d] edid failed: %d\n",
++                            block, ret);
++
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_get_edid_block);
++
++static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp)
++{
++      unsigned long timeout;
++      u8 msg, event[2];
++      int ret;
++
++      msg = LINK_TRAINING_RUN;
++
++      /* start training */
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                   DPTX_TRAINING_CONTROL, sizeof(msg), &msg);
++      if (ret)
++              goto err_training_start;
++
++      timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS);
++      while (time_before(jiffies, timeout)) {
++              msleep(LINK_TRAINING_RETRY_MS);
++              ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                           DPTX_READ_EVENT, 0, NULL);
++              if (ret)
++                      goto err_training_start;
++
++              ret = cdns_mhdp_mailbox_validate_receive(mhdp,
++                                                       MB_MODULE_ID_DP_TX,
++                                                       DPTX_READ_EVENT,
++                                                       sizeof(event));
++              if (ret)
++                      goto err_training_start;
++
++              ret = cdns_mhdp_mailbox_read_receive(mhdp, event,
++                                                   sizeof(event));
++              if (ret)
++                      goto err_training_start;
++
++              if (event[1] & EQ_PHASE_FINISHED)
++                      return 0;
++      }
++
++      ret = -ETIMEDOUT;
++
++err_training_start:
++      DRM_DEV_ERROR(mhdp->dev, "training failed: %d\n", ret);
++      return ret;
++}
++
++static int cdns_mhdp_get_training_status(struct cdns_mhdp_device *mhdp)
++{
++      u8 status[10];
++      int ret;
++
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                   DPTX_READ_LINK_STAT, 0, NULL);
++      if (ret)
++              goto err_get_training_status;
++
++      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
++                                               DPTX_READ_LINK_STAT,
++                                               sizeof(status));
++      if (ret)
++              goto err_get_training_status;
++
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, status, sizeof(status));
++      if (ret)
++              goto err_get_training_status;
++
++      mhdp->dp.link.rate = drm_dp_bw_code_to_link_rate(status[0]); 
++      mhdp->dp.link.num_lanes = status[1];
++
++err_get_training_status:
++      if (ret)
++              DRM_DEV_ERROR(mhdp->dev, "get training status failed: %d\n",
++                            ret);
++      return ret;
++}
++
++int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp)
++{
++      int ret;
++
++      ret = cdns_mhdp_training_start(mhdp);
++      if (ret) {
++              DRM_DEV_ERROR(mhdp->dev, "Failed to start training %d\n",
++                            ret);
++              return ret;
++      }
++
++      ret = cdns_mhdp_get_training_status(mhdp);
++      if (ret) {
++              DRM_DEV_ERROR(mhdp->dev, "Failed to get training stat %d\n",
++                            ret);
++              return ret;
++      }
++
++      DRM_DEV_DEBUG_KMS(mhdp->dev, "rate:0x%x, lanes:%d\n", mhdp->dp.link.rate,
++                        mhdp->dp.link.num_lanes);
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_train_link);
++
++int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active)
++{
++      u8 msg;
++      int ret;
++
++      msg = !!active;
++
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                   DPTX_SET_VIDEO, sizeof(msg), &msg);
++      if (ret)
++              DRM_DEV_ERROR(mhdp->dev, "set video status failed: %d\n", ret);
++
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_set_video_status);
++
++static int cdns_mhdp_get_msa_misc(struct video_info *video,
++                                struct drm_display_mode *mode)
++{
++      u32 msa_misc;
++      u8 val[2] = {0};
++
++      switch (video->color_fmt) {
++      case PXL_RGB:
++      case Y_ONLY:
++              val[0] = 0;
++              break;
++      /* set YUV default color space conversion to BT601 */
++      case YCBCR_4_4_4:
++              val[0] = 6 + BT_601 * 8;
++              break;
++      case YCBCR_4_2_2:
++              val[0] = 5 + BT_601 * 8;
++              break;
++      case YCBCR_4_2_0:
++              val[0] = 5;
++              break;
++      };
++
++      switch (video->color_depth) {
++      case 6:
++              val[1] = 0;
++              break;
++      case 8:
++              val[1] = 1;
++              break;
++      case 10:
++              val[1] = 2;
++              break;
++      case 12:
++              val[1] = 3;
++              break;
++      case 16:
++              val[1] = 4;
++              break;
++      };
++
++      msa_misc = 2 * val[0] + 32 * val[1] +
++                 ((video->color_fmt == Y_ONLY) ? (1 << 14) : 0);
++
++      return msa_misc;
++}
++
++int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp)
++{
++      struct video_info *video = &mhdp->video_info;
++      struct drm_display_mode *mode = &mhdp->mode;
++      u64 symbol;
++      u32 val, link_rate, rem;
++      u8 bit_per_pix, tu_size_reg = TU_SIZE;
++      int ret;
++
++      bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ?
++                    (video->color_depth * 2) : (video->color_depth * 3);
++
++      link_rate = mhdp->dp.link.rate / 1000;
++
++      ret = cdns_mhdp_reg_write(mhdp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE);
++      if (ret)
++              goto err_config_video;
++
++      ret = cdns_mhdp_reg_write(mhdp, HSYNC2VSYNC_POL_CTRL, 0);
++      if (ret)
++              goto err_config_video;
++
++      /*
++       * get a best tu_size and valid symbol:
++       * 1. chose Lclk freq(162Mhz, 270Mhz, 540Mhz), set TU to 32
++       * 2. calculate VS(valid symbol) = TU * Pclk * Bpp / (Lclk * Lanes)
++       * 3. if VS > *.85 or VS < *.1 or VS < 2 or TU < VS + 4, then set
++       *    TU += 2 and repeat 2nd step.
++       */
++      do {
++              tu_size_reg += 2;
++              symbol = tu_size_reg * mode->clock * bit_per_pix;
++              do_div(symbol, mhdp->dp.link.num_lanes * link_rate * 8);
++              rem = do_div(symbol, 1000);
++              if (tu_size_reg > 64) {
++                      ret = -EINVAL;
++                      DRM_DEV_ERROR(mhdp->dev,
++                                    "tu error, clk:%d, lanes:%d, rate:%d\n",
++                                    mode->clock, mhdp->dp.link.num_lanes,
++                                    link_rate);
++                      goto err_config_video;
++              }
++      } while ((symbol <= 1) || (tu_size_reg - symbol < 4) ||
++               (rem > 850) || (rem < 100));
++
++      val = symbol + (tu_size_reg << 8);
++      val |= TU_CNT_RST_EN;
++      ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_TU, val);
++      if (ret)
++              goto err_config_video;
++
++      /* set the FIFO Buffer size */
++      val = div_u64(mode->clock * (symbol + 1), 1000) + link_rate;
++      val /= (mhdp->dp.link.num_lanes * link_rate);
++      val = div_u64(8 * (symbol + 1), bit_per_pix) - val;
++      val += 2;
++      ret = cdns_mhdp_reg_write(mhdp, DP_VC_TABLE(15), val);
++
++      switch (video->color_depth) {
++      case 6:
++              val = BCS_6;
++              break;
++      case 8:
++              val = BCS_8;
++              break;
++      case 10:
++              val = BCS_10;
++              break;
++      case 12:
++              val = BCS_12;
++              break;
++      case 16:
++              val = BCS_16;
++              break;
++      };
++
++      val += video->color_fmt << 8;
++      ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_PXL_REPR, val);
++      if (ret)
++              goto err_config_video;
++
++      val = video->h_sync_polarity ? DP_FRAMER_SP_HSP : 0;
++      val |= video->v_sync_polarity ? DP_FRAMER_SP_VSP : 0;
++      ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_SP, val);
++      if (ret)
++              goto err_config_video;
++
++      val = (mode->hsync_start - mode->hdisplay) << 16;
++      val |= mode->htotal - mode->hsync_end;
++      ret = cdns_mhdp_reg_write(mhdp, DP_FRONT_BACK_PORCH, val);
++      if (ret)
++              goto err_config_video;
++
++      val = mode->hdisplay * bit_per_pix / 8;
++      ret = cdns_mhdp_reg_write(mhdp, DP_BYTE_COUNT, val);
++      if (ret)
++              goto err_config_video;
++
++      val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16);
++      ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_0, val);
++      if (ret)
++              goto err_config_video;
++
++      val = mode->hsync_end - mode->hsync_start;
++      val |= (mode->hdisplay << 16) | (video->h_sync_polarity << 15);
++      ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_1, val);
++      if (ret)
++              goto err_config_video;
++
++      val = mode->vtotal;
++      val |= (mode->vtotal - mode->vsync_start) << 16;
++      ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_0, val);
++      if (ret)
++              goto err_config_video;
++
++      val = mode->vsync_end - mode->vsync_start;
++      val |= (mode->vdisplay << 16) | (video->v_sync_polarity << 15);
++      ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_1, val);
++      if (ret)
++              goto err_config_video;
++
++      val = cdns_mhdp_get_msa_misc(video, mode);
++      ret = cdns_mhdp_reg_write(mhdp, MSA_MISC, val);
++      if (ret)
++              goto err_config_video;
++
++      ret = cdns_mhdp_reg_write(mhdp, STREAM_CONFIG, 1);
++      if (ret)
++              goto err_config_video;
++
++      val = mode->hsync_end - mode->hsync_start;
++      val |= mode->hdisplay << 16;
++      ret = cdns_mhdp_reg_write(mhdp, DP_HORIZONTAL, val);
++      if (ret)
++              goto err_config_video;
++
++      val = mode->vdisplay;
++      val |= (mode->vtotal - mode->vsync_start) << 16;
++      ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_0, val);
++      if (ret)
++              goto err_config_video;
++
++      val = mode->vtotal;
++      ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_1, val);
++      if (ret)
++              goto err_config_video;
++
++      ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 2, 1, 0);
++
++err_config_video:
++      if (ret)
++              DRM_DEV_ERROR(mhdp->dev, "config video failed: %d\n", ret);
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_config_video);
++
++int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
++                       struct audio_info *audio)
++{
++      int ret;
++
++      ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, 0);
++      if (ret) {
++              DRM_DEV_ERROR(mhdp->dev, "audio stop failed: %d\n", ret);
++              return ret;
++      }
++
++      writel(0, mhdp->regs + SPDIF_CTRL_ADDR);
++
++      /* clearn the audio config and reset */
++      writel(0, mhdp->regs + AUDIO_SRC_CNTL);
++      writel(0, mhdp->regs + AUDIO_SRC_CNFG);
++      writel(AUDIO_SW_RST, mhdp->regs + AUDIO_SRC_CNTL);
++      writel(0, mhdp->regs + AUDIO_SRC_CNTL);
++
++      /* reset smpl2pckt component  */
++      writel(0, mhdp->regs + SMPL2PKT_CNTL);
++      writel(AUDIO_SW_RST, mhdp->regs + SMPL2PKT_CNTL);
++      writel(0, mhdp->regs + SMPL2PKT_CNTL);
++
++      /* reset FIFO */
++      writel(AUDIO_SW_RST, mhdp->regs + FIFO_CNTL);
++      writel(0, mhdp->regs + FIFO_CNTL);
++
++      if (audio->format == AFMT_SPDIF)
++              clk_disable_unprepare(mhdp->spdif_clk);
++
++      return 0;
++}
++EXPORT_SYMBOL(cdns_mhdp_audio_stop);
++
++int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable)
++{
++      int ret;
++
++      ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 4, 1, enable);
++      if (ret)
++              DRM_DEV_ERROR(mhdp->dev, "audio mute failed: %d\n", ret);
++
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_audio_mute);
++
++static void cdns_mhdp_audio_config_i2s(struct cdns_mhdp_device *mhdp,
++                                     struct audio_info *audio)
++{
++      int sub_pckt_num = 1, i2s_port_en_val = 0xf, i;
++      u32 val;
++
++      if (audio->channels == 2) {
++              if (mhdp->dp.link.num_lanes == 1)
++                      sub_pckt_num = 2;
++              else
++                      sub_pckt_num = 4;
++
++              i2s_port_en_val = 1;
++      } else if (audio->channels == 4) {
++              i2s_port_en_val = 3;
++      }
++
++      writel(0x0, mhdp->regs + SPDIF_CTRL_ADDR);
++
++      writel(SYNC_WR_TO_CH_ZERO, mhdp->regs + FIFO_CNTL);
++
++      val = MAX_NUM_CH(audio->channels);
++      val |= NUM_OF_I2S_PORTS(audio->channels);
++      val |= AUDIO_TYPE_LPCM;
++      val |= CFG_SUB_PCKT_NUM(sub_pckt_num);
++      writel(val, mhdp->regs + SMPL2PKT_CNFG);
++
++      if (audio->sample_width == 16)
++              val = 0;
++      else if (audio->sample_width == 24)
++              val = 1 << 9;
++      else
++              val = 2 << 9;
++
++      val |= AUDIO_CH_NUM(audio->channels);
++      val |= I2S_DEC_PORT_EN(i2s_port_en_val);
++      val |= TRANS_SMPL_WIDTH_32;
++      writel(val, mhdp->regs + AUDIO_SRC_CNFG);
++
++      for (i = 0; i < (audio->channels + 1) / 2; i++) {
++              if (audio->sample_width == 16)
++                      val = (0x02 << 8) | (0x02 << 20);
++              else if (audio->sample_width == 24)
++                      val = (0x0b << 8) | (0x0b << 20);
++
++              val |= ((2 * i) << 4) | ((2 * i + 1) << 16);
++              writel(val, mhdp->regs + STTS_BIT_CH(i));
++      }
++
++      switch (audio->sample_rate) {
++      case 32000:
++              val = SAMPLING_FREQ(3) |
++                    ORIGINAL_SAMP_FREQ(0xc);
++              break;
++      case 44100:
++              val = SAMPLING_FREQ(0) |
++                    ORIGINAL_SAMP_FREQ(0xf);
++              break;
++      case 48000:
++              val = SAMPLING_FREQ(2) |
++                    ORIGINAL_SAMP_FREQ(0xd);
++              break;
++      case 88200:
++              val = SAMPLING_FREQ(8) |
++                    ORIGINAL_SAMP_FREQ(0x7);
++              break;
++      case 96000:
++              val = SAMPLING_FREQ(0xa) |
++                    ORIGINAL_SAMP_FREQ(5);
++              break;
++      case 176400:
++              val = SAMPLING_FREQ(0xc) |
++                    ORIGINAL_SAMP_FREQ(3);
++              break;
++      case 192000:
++              val = SAMPLING_FREQ(0xe) |
++                    ORIGINAL_SAMP_FREQ(1);
++              break;
++      }
++      val |= 4;
++      writel(val, mhdp->regs + COM_CH_STTS_BITS);
++
++      writel(SMPL2PKT_EN, mhdp->regs + SMPL2PKT_CNTL);
++      writel(I2S_DEC_START, mhdp->regs + AUDIO_SRC_CNTL);
++}
++
++static void cdns_mhdp_audio_config_spdif(struct cdns_mhdp_device *mhdp)
++{
++      u32 val;
++
++      writel(SYNC_WR_TO_CH_ZERO, mhdp->regs + FIFO_CNTL);
++
++      val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4);
++      writel(val, mhdp->regs + SMPL2PKT_CNFG);
++      writel(SMPL2PKT_EN, mhdp->regs + SMPL2PKT_CNTL);
++
++      val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS;
++      writel(val, mhdp->regs + SPDIF_CTRL_ADDR);
++
++      clk_prepare_enable(mhdp->spdif_clk);
++      clk_set_rate(mhdp->spdif_clk, CDNS_DP_SPDIF_CLK);
++}
++
++int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
++                         struct audio_info *audio)
++{
++      int ret;
++
++      /* reset the spdif clk before config */
++      if (audio->format == AFMT_SPDIF) {
++              reset_control_assert(mhdp->spdif_rst);
++              reset_control_deassert(mhdp->spdif_rst);
++      }
++
++      ret = cdns_mhdp_reg_write(mhdp, CM_LANE_CTRL, LANE_REF_CYC);
++      if (ret)
++              goto err_audio_config;
++
++      ret = cdns_mhdp_reg_write(mhdp, CM_CTRL, 0);
++      if (ret)
++              goto err_audio_config;
++
++      if (audio->format == AFMT_I2S)
++              cdns_mhdp_audio_config_i2s(mhdp, audio);
++      else if (audio->format == AFMT_SPDIF)
++              cdns_mhdp_audio_config_spdif(mhdp);
++
++      ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN);
++
++err_audio_config:
++      if (ret)
++              DRM_DEV_ERROR(mhdp->dev, "audio config failed: %d\n", ret);
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_audio_config);
++
++int cdns_mhdp_adjust_lt(struct cdns_mhdp_device *mhdp,
++                      u8 nlanes, u16 udelay, u8 *lanes_data, u8 *dpcd)
++{
++      u8 payload[7];
++      u8 hdr[5]; /* For DPCD read response header */
++      u32 addr;
++      u8 const nregs = 6; /* Registers 0x202-0x207 */
++      int ret;
++
++      if (nlanes != 4 && nlanes != 2 && nlanes != 1) {
++              DRM_DEV_ERROR(mhdp->dev, "invalid number of lanes: %d\n",
++                            nlanes);
++              ret = -EINVAL;
++              goto err_adjust_lt;
++      }
++
++      payload[0] = nlanes;
++      put_unaligned_be16(udelay, payload + 1);
++      memcpy(payload + 3, lanes_data, nlanes);
++
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
++                                   DPTX_ADJUST_LT,
++                                   sizeof(payload), payload);
++      if (ret)
++              goto err_adjust_lt;
++
++      /* Yes, read the DPCD read command response */
++      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
++                                               DPTX_READ_DPCD,
++                                               sizeof(hdr) + nregs);
++      if (ret)
++              goto err_adjust_lt;
++
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, hdr, sizeof(hdr));
++      if (ret)
++              goto err_adjust_lt;
++
++      addr = get_unaligned_be24(hdr + 2);
++      if (addr != DP_LANE0_1_STATUS)
++              goto err_adjust_lt;
++
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, dpcd, nregs);
++
++err_adjust_lt:
++      if (ret)
++              DRM_DEV_ERROR(mhdp->dev, "Failed to adjust Link Training.\n");
++
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_adjust_lt);
++
++int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val)
++{
++      return cdns_mhdp_reg_write(mhdp, ADDR_PHY_AFE + (addr << 2), val);
++}
++EXPORT_SYMBOL(cdns_phy_reg_write);
++
++u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr)
++{
++      return cdns_mhdp_reg_read(mhdp, ADDR_PHY_AFE + (addr << 2));
++}
++EXPORT_SYMBOL(cdns_phy_reg_read);
++
++int cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp)
++{
++      u8 status;
++      int ret;
++
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL, GENERAL_GET_HPD_STATE,
++                                0, NULL);
++      if (ret)
++              goto err_get_hpd;
++
++      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_GENERAL,
++                                                      GENERAL_GET_HPD_STATE, sizeof(status));
++      if (ret)
++              goto err_get_hpd;
++
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, &status, sizeof(status));
++      if (ret)
++              goto err_get_hpd;
++
++      return status;
++
++err_get_hpd:
++      DRM_ERROR("read hpd  failed: %d\n", ret);
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_read_hpd);
++
++bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp)
++{
++      u32  alive, newalive;
++      u8 retries_left = 10;
++
++      alive = readl(mhdp->regs + KEEP_ALIVE);
++
++      while (retries_left--) {
++              udelay(2);
++
++              newalive = readl(mhdp->regs + KEEP_ALIVE);
++              if (alive == newalive)
++                      continue;
++              return true;
++      }
++      return false;
++}
++EXPORT_SYMBOL(cdns_mhdp_check_alive);
+--- /dev/null
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
+@@ -0,0 +1,296 @@
++/*
++ * Copyright (C) 2019 NXP Semiconductor, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <drm/drmP.h>
++#include <linux/io.h>
++#include <drm/bridge/cdns-mhdp-common.h>
++
++int cdns_hdmi_get_edid_block(void *data, u8 *edid,
++                        u32 block, size_t length)
++{
++      struct cdns_mhdp_device *mhdp = data;
++      u8 msg[2], reg[5], i;
++      int ret;
++
++      for (i = 0; i < 4; i++) {
++              msg[0] = block / 2;
++              msg[1] = block % 2;
++
++              ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX, HDMI_TX_EDID,
++                                        sizeof(msg), msg);
++              if (ret)
++                      continue;
++
++              ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDMI_TX,
++                                                    HDMI_TX_EDID, sizeof(reg) + length);
++              if (ret)
++                      continue;
++
++              ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
++              if (ret)
++                      continue;
++
++              ret = cdns_mhdp_mailbox_read_receive(mhdp, edid, length);
++              if (ret)
++                      continue;
++
++              if ((reg[3] << 8 | reg[4]) == length)
++                      break;
++      }
++
++      if (ret)
++              DRM_ERROR("get block[%d] edid failed: %d\n", block, ret);
++      return ret;
++}
++
++int cdns_hdmi_scdc_read(struct cdns_mhdp_device *mhdp, u8 addr, u8 *data)
++{
++      u8 msg[4], reg[6];
++      int ret;
++
++      msg[0] = 0x54;
++      msg[1] = addr;
++      msg[2] = 0;
++      msg[3] = 1;
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX, HDMI_TX_READ,
++                                sizeof(msg), msg);
++      if (ret)
++              goto err_scdc_read;
++
++      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDMI_TX,
++                                            HDMI_TX_READ, sizeof(reg));
++      if (ret)
++              goto err_scdc_read;
++
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
++      if (ret)
++              goto err_scdc_read;
++
++      *data = reg[5];
++
++err_scdc_read:
++      if (ret)
++              DRM_ERROR("scdc read failed: %d\n", ret);
++      return ret;
++}
++
++int cdns_hdmi_scdc_write(struct cdns_mhdp_device *mhdp, u8 addr, u8 value)
++{
++      u8 msg[5], reg[5];
++      int ret;
++
++      msg[0] = 0x54;
++      msg[1] = addr;
++      msg[2] = 0;
++      msg[3] = 1;
++      msg[4] = value;
++      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX, HDMI_TX_WRITE,
++                                sizeof(msg), msg);
++      if (ret)
++              goto err_scdc_write;
++
++      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDMI_TX,
++                                            HDMI_TX_WRITE, sizeof(reg));
++      if (ret)
++              goto err_scdc_write;
++
++      ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
++      if (ret)
++              goto err_scdc_write;
++
++      if (reg[0] != 0)
++              ret = -EINVAL;
++
++err_scdc_write:
++      if (ret)
++              DRM_ERROR("scdc write failed: %d\n", ret);
++      return ret;
++}
++
++int cdns_hdmi_ctrl_init(struct cdns_mhdp_device *mhdp,
++                               int protocol,
++                               u32 char_rate)
++{
++      u32 reg0;
++      u32 reg1;
++      u32 val;
++      int ret;
++
++      /* Set PHY to HDMI data */
++      ret = cdns_mhdp_reg_write(mhdp, PHY_DATA_SEL, F_SOURCE_PHY_MHDP_SEL(1));
++      if (ret < 0)
++              return ret;
++
++      ret = cdns_mhdp_reg_write(mhdp, HDTX_HPD,
++                                      F_HPD_VALID_WIDTH(4) | F_HPD_GLITCH_WIDTH(0));
++      if (ret < 0)
++              return ret;
++
++      /* open CARS */
++      ret = cdns_mhdp_reg_write(mhdp, SOURCE_PHY_CAR, 0xF);
++      if (ret < 0)
++              return ret;
++      ret = cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, 0xFF);
++      if (ret < 0)
++              return ret;
++      ret = cdns_mhdp_reg_write(mhdp, SOURCE_PKT_CAR, 0xF);
++      if (ret < 0)
++              return ret;
++      ret = cdns_mhdp_reg_write(mhdp, SOURCE_AIF_CAR, 0xF);
++      if (ret < 0)
++              return ret;
++      ret = cdns_mhdp_reg_write(mhdp, SOURCE_CIPHER_CAR, 0xF);
++      if (ret < 0)
++              return ret;
++      ret = cdns_mhdp_reg_write(mhdp, SOURCE_CRYPTO_CAR, 0xF);
++      if (ret < 0)
++              return ret;
++      ret = cdns_mhdp_reg_write(mhdp, SOURCE_CEC_CAR, 3);
++      if (ret < 0)
++              return ret;
++
++      reg0 = reg1 = 0x7c1f;
++      if (protocol == MODE_HDMI_2_0 && char_rate >= 340000) {
++              reg0 = 0;
++              reg1 = 0xFFFFF;
++      }
++      ret = cdns_mhdp_reg_write(mhdp, HDTX_CLOCK_REG_0, reg0);
++      if (ret < 0)
++              return ret;
++      ret = cdns_mhdp_reg_write(mhdp, HDTX_CLOCK_REG_1, reg1);
++      if (ret < 0)
++              return ret;
++
++      /* set hdmi mode and preemble mode data enable */
++      val = F_HDMI_MODE(protocol) | F_HDMI2_PREAMBLE_EN(1) |  F_DATA_EN(1) |
++                      F_HDMI2_CTRL_IL_MODE(1) | F_BCH_EN(1) | F_PIC_3D(0XF);
++      ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
++
++      return ret;
++}
++
++int cdns_hdmi_mode_config(struct cdns_mhdp_device *mhdp,
++                                            struct drm_display_mode *mode,
++                                                struct video_info *video_info)
++{
++      int ret;
++      u32 val;
++      u32 vsync_lines = mode->vsync_end - mode->vsync_start;
++      u32 eof_lines = mode->vsync_start - mode->vdisplay;
++      u32 sof_lines = mode->vtotal - mode->vsync_end;
++      u32 hblank = mode->htotal - mode->hdisplay;
++      u32 hactive = mode->hdisplay;
++      u32 vblank = mode->vtotal - mode->vdisplay;
++      u32 vactive = mode->vdisplay;
++      u32 hfront = mode->hsync_start - mode->hdisplay;
++      u32 hback = mode->htotal - mode->hsync_end;
++      u32 vfront = eof_lines;
++      u32 hsync = hblank - hfront - hback;
++      u32 vsync = vsync_lines;
++      u32 vback = sof_lines;
++      u32 v_h_polarity = ((mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1) +
++                                              ((mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : 2);
++
++      ret = cdns_mhdp_reg_write(mhdp, SCHEDULER_H_SIZE, (hactive << 16) + hblank);
++      if (ret < 0)
++              return ret;
++
++      ret = cdns_mhdp_reg_write(mhdp, SCHEDULER_V_SIZE, (vactive << 16) + vblank);
++      if (ret < 0)
++              return ret;
++
++      ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_FRONT_WIDTH, (vfront << 16) + hfront);
++      if (ret < 0)
++              return ret;
++
++      ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_SYNC_WIDTH, (vsync << 16) + hsync);
++      if (ret < 0)
++              return ret;
++
++      ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_BACK_WIDTH, (vback << 16) + hback);
++      if (ret < 0)
++              return ret;
++
++      ret = cdns_mhdp_reg_write(mhdp, HSYNC2VSYNC_POL_CTRL, v_h_polarity);
++      if (ret < 0)
++              return ret;
++
++      /* Reset Data Enable */
++      val = cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER);
++      val &= ~F_DATA_EN(1);
++      ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
++      if (ret < 0)
++              return ret;
++
++      /* Set bpc */
++      val &= ~F_VIF_DATA_WIDTH(3);
++      switch (video_info->color_depth) {
++      case 10:
++              val |= F_VIF_DATA_WIDTH(1);
++              break;
++      case 12:
++              val |= F_VIF_DATA_WIDTH(2);
++              break;
++      case 16:
++              val |= F_VIF_DATA_WIDTH(3);
++              break;
++      case 8:
++      default:
++              val |= F_VIF_DATA_WIDTH(0);
++              break;
++      }
++
++      /* select color encoding */
++      val &= ~F_HDMI_ENCODING(3);
++      switch (video_info->color_fmt) {
++      case YCBCR_4_4_4:
++              val |= F_HDMI_ENCODING(2);
++              break;
++      case YCBCR_4_2_2:
++              val |= F_HDMI_ENCODING(1);
++              break;
++      case YCBCR_4_2_0:
++              val |= F_HDMI_ENCODING(3);
++              break;
++      case PXL_RGB:
++      default:
++              val |= F_HDMI_ENCODING(0);
++              break;
++      }
++
++      ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
++      if (ret < 0)
++              return ret;
++
++      /* set data enable */
++      val |= F_DATA_EN(1);
++      ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
++
++      return ret;
++}
++
++int cdns_hdmi_disable_gcp(struct cdns_mhdp_device *mhdp)
++{
++      u32 val;
++
++      val = cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER);
++      val &= ~F_GCP_EN(1);
++
++      return cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
++}
++
++int cdns_hdmi_enable_gcp(struct cdns_mhdp_device *mhdp)
++{
++      u32 val;
++
++      val = cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER);
++      val |= F_GCP_EN(1);
++
++      return cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
++}
+--- /dev/null
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp.h
+@@ -0,0 +1,209 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Cadence MHDP DP MST bridge driver.
++ *
++ * Copyright: 2018 Cadence Design Systems, Inc.
++ *
++ * Author: Quentin Schulz <quentin.schulz@free-electrons.com>
++ */
++
++
++#ifndef CDNS_MHDP_H
++#define CDNS_MHDP_H
++
++#include <drm/drm_dp_mst_helper.h>
++
++#define CDNS_APB_CFG                          0x00000
++#define CDNS_APB_CTRL                         (CDNS_APB_CFG + 0x00)
++#define CDNS_MAILBOX_FULL                     (CDNS_APB_CFG + 0x08)
++#define CDNS_MAILBOX_EMPTY                    (CDNS_APB_CFG + 0x0c)
++#define CDNS_MAILBOX_TX_DATA                  (CDNS_APB_CFG + 0x10)
++#define CDNS_MAILBOX_RX_DATA                  (CDNS_APB_CFG + 0x14)
++#define CDNS_KEEP_ALIVE                               (CDNS_APB_CFG + 0x18)
++#define CDNS_KEEP_ALIVE_MASK                  GENMASK(7, 0)
++
++#define CDNS_MB_INT_MASK                      (CDNS_APB_CFG + 0x34)
++
++#define CDNS_SW_CLK_L                         (CDNS_APB_CFG + 0x3c)
++#define CDNS_SW_CLK_H                         (CDNS_APB_CFG + 0x40)
++#define CDNS_SW_EVENT0                                (CDNS_APB_CFG + 0x44)
++#define CDNS_DPTX_HPD                         BIT(0)
++
++#define CDNS_SW_EVENT1                                (CDNS_APB_CFG + 0x48)
++#define CDNS_SW_EVENT2                                (CDNS_APB_CFG + 0x4c)
++#define CDNS_SW_EVENT3                                (CDNS_APB_CFG + 0x50)
++
++#define CDNS_APB_INT_MASK                     (CDNS_APB_CFG + 0x6C)
++#define CDNS_APB_INT_MASK_MAILBOX_INT         BIT(0)
++#define CDNS_APB_INT_MASK_SW_EVENT_INT                BIT(1)
++
++#define CDNS_DPTX_CAR                         (CDNS_APB_CFG + 0x904)
++#define CDNS_VIF_CLK_EN                               BIT(0)
++#define CDNS_VIF_CLK_RSTN                     BIT(1)
++
++#define CDNS_SOURCE_VIDEO_IF(s)                       (0x00b00 + (s * 0x20))
++#define CDNS_BND_HSYNC2VSYNC(s)                       (CDNS_SOURCE_VIDEO_IF(s) + \
++                                               0x00)
++#define CDNS_IP_DTCT_WIN                      GENMASK(11, 0)
++#define CDNS_IP_DET_INTERLACE_FORMAT          BIT(12)
++#define CDNS_IP_BYPASS_V_INTERFACE            BIT(13)
++
++#define CDNS_HSYNC2VSYNC_POL_CTRL(s)          (CDNS_SOURCE_VIDEO_IF(s) + \
++                                               0x10)
++#define CDNS_H2V_HSYNC_POL_ACTIVE_LOW         BIT(1)
++#define CDNS_H2V_VSYNC_POL_ACTIVE_LOW         BIT(2)
++
++#define CDNS_DPTX_PHY_CONFIG                  0x02000
++#define CDNS_PHY_TRAINING_EN                  BIT(0)
++#define CDNS_PHY_TRAINING_TYPE(x)             (((x) & GENMASK(3, 0)) << 1)
++#define CDNS_PHY_SCRAMBLER_BYPASS             BIT(5)
++#define CDNS_PHY_ENCODER_BYPASS                       BIT(6)
++#define CDNS_PHY_SKEW_BYPASS                  BIT(7)
++#define CDNS_PHY_TRAINING_AUTO                        BIT(8)
++#define CDNS_PHY_LANE0_SKEW(x)                        (((x) & GENMASK(2, 0)) << 9)
++#define CDNS_PHY_LANE1_SKEW(x)                        (((x) & GENMASK(2, 0)) << 12)
++#define CDNS_PHY_LANE2_SKEW(x)                        (((x) & GENMASK(2, 0)) << 15)
++#define CDNS_PHY_LANE3_SKEW(x)                        (((x) & GENMASK(2, 0)) << 18)
++#define CDNS_PHY_COMMON_CONFIG                        (CDNS_PHY_LANE1_SKEW(1) | \
++                                              CDNS_PHY_LANE2_SKEW(2) |  \
++                                              CDNS_PHY_LANE3_SKEW(3))
++#define CDNS_PHY_10BIT_EN                     BIT(21)
++
++#define CDNS_DPTX_FRAMER                      0x02200
++#define CDNS_DP_FRAMER_GLOBAL_CONFIG          (CDNS_DPTX_FRAMER + 0x00)
++#define CDNS_DP_NUM_LANES(x)                  (x - 1)
++#define CDNS_DP_MST_EN                                BIT(2)
++#define CDNS_DP_FRAMER_EN                     BIT(3)
++#define CDNS_DP_RATE_GOVERNOR_EN              BIT(4)
++#define CDNS_DP_NO_VIDEO_MODE                 BIT(5)
++#define CDNS_DP_DISABLE_PHY_RST                       BIT(6)
++#define CDNS_DP_WR_FAILING_EDGE_VSYNC         BIT(7)
++
++#define CDNS_DP_SW_RESET                      (CDNS_DPTX_FRAMER + 0x04)
++#define CDNS_DP_FRAMER_TU                     (CDNS_DPTX_FRAMER + 0x08)
++#define CDNS_DP_FRAMER_TU_SIZE(x)             (((x) & GENMASK(6, 0)) << 8)
++#define CDNS_DP_FRAMER_TU_VS(x)                       ((x) & GENMASK(5, 0))
++#define CDNS_DP_FRAMER_TU_CNT_RST_EN          BIT(15)
++
++#define CDNS_DPTX_STREAM(s)                   (0x03000 + s * 0x80)
++#define CDNS_DP_MSA_HORIZONTAL_0(s)           (CDNS_DPTX_STREAM(s) + 0x00)
++#define CDNS_DP_MSAH0_H_TOTAL(x)              (x)
++#define CDNS_DP_MSAH0_HSYNC_START(x)          ((x) << 16)
++
++#define CDNS_DP_MSA_HORIZONTAL_1(s)           (CDNS_DPTX_STREAM(s) + 0x04)
++#define CDNS_DP_MSAH1_HSYNC_WIDTH(x)          (x)
++#define CDNS_DP_MSAH1_HSYNC_POL_LOW           BIT(15)
++#define CDNS_DP_MSAH1_HDISP_WIDTH(x)          ((x) << 16)
++
++#define CDNS_DP_MSA_VERTICAL_0(s)             (CDNS_DPTX_STREAM(s) + 0x08)
++#define CDNS_DP_MSAV0_V_TOTAL(x)              (x)
++#define CDNS_DP_MSAV0_VSYNC_START(x)          ((x) << 16)
++
++#define CDNS_DP_MSA_VERTICAL_1(s)             (CDNS_DPTX_STREAM(s) + 0x0c)
++#define CDNS_DP_MSAV1_VSYNC_WIDTH(x)          (x)
++#define CDNS_DP_MSAV1_VSYNC_POL_LOW           BIT(15)
++#define CDNS_DP_MSAV1_VDISP_WIDTH(x)          ((x) << 16)
++
++#define CDNS_DP_MSA_MISC(s)                   (CDNS_DPTX_STREAM(s) + 0x10)
++#define CDNS_DP_STREAM_CONFIGs(s)             (CDNS_DPTX_STREAM(s) + 0x14)
++#define CDNS_DP_STREAM_CONFIG_2(s)            (CDNS_DPTX_STREAM(s) + 0x2c)
++#define CDNS_DP_SC2_TU_VS_DIFF(x)             ((x) << 8)
++
++#define CDNS_DP_HORIZONTAL(s)                 (CDNS_DPTX_STREAM(s) + 0x30)
++#define CDNS_DP_H_HSYNC_WIDTH(x)              (x)
++#define CDNS_DP_H_H_TOTAL(x)                  ((x) << 16)
++
++#define CDNS_DP_VERTICAL_0(s)                 (CDNS_DPTX_STREAM(s) + 0x34)
++#define CDNS_DP_V0_VHEIGHT(x)                 (x)
++#define CDNS_DP_V0_VSTART(x)                  ((x) << 16)
++
++#define CDNS_DP_VERTICAL_1(s)                 (CDNS_DPTX_STREAM(s) + 0x38)
++#define CDNS_DP_V1_VTOTAL(x)                  (x)
++#define CDNS_DP_V1_VTOTAL_EVEN                        BIT(16)
++
++#define CDNS_DP_FRAMER_PXL_REPR(s)            (CDNS_DPTX_STREAM(s) + 0x4c)
++#define CDNS_DP_FRAMER_6_BPC                  BIT(0)
++#define CDNS_DP_FRAMER_8_BPC                  BIT(1)
++#define CDNS_DP_FRAMER_10_BPC                 BIT(2)
++#define CDNS_DP_FRAMER_12_BPC                 BIT(3)
++#define CDNS_DP_FRAMER_16_BPC                 BIT(4)
++#define CDNS_DP_FRAMER_PXL_FORMAT             0x8
++#define CDNS_DP_FRAMER_RGB                    BIT(0)
++#define CDNS_DP_FRAMER_YCBCR444                       BIT(1)
++#define CDNS_DP_FRAMER_YCBCR422                       BIT(2)
++#define CDNS_DP_FRAMER_YCBCR420                       BIT(3)
++#define CDNS_DP_FRAMER_Y_ONLY                 BIT(4)
++
++#define CDNS_DP_FRAMER_SP(s)                  (CDNS_DPTX_STREAM(s) + 0x10)
++#define CDNS_DP_FRAMER_VSYNC_POL_LOW          BIT(0)
++#define CDNS_DP_FRAMER_HSYNC_POL_LOW          BIT(1)
++#define CDNS_DP_FRAMER_INTERLACE              BIT(2)
++
++#define CDNS_DP_LINE_THRESH(s)                        (CDNS_DPTX_STREAM(s) + 0x64)
++#define CDNS_DP_ACTIVE_LINE_THRESH(x)         (x)
++
++#define CDNS_DP_VB_ID(s)                      (CDNS_DPTX_STREAM(s) + 0x68)
++#define CDNS_DP_VB_ID_INTERLACED              BIT(2)
++#define CDNS_DP_VB_ID_COMPRESSED              BIT(6)
++
++#define CDNS_DP_FRONT_BACK_PORCH(s)           (CDNS_DPTX_STREAM(s) + 0x78)
++#define CDNS_DP_BACK_PORCH(x)                 (x)
++#define CDNS_DP_FRONT_PORCH(x)                        ((x) << 16)
++
++#define CDNS_DP_BYTE_COUNT(s)                 (CDNS_DPTX_STREAM(s) + 0x7c)
++#define CDNS_DP_BYTE_COUNT_BYTES_IN_CHUNK_SHIFT       16
++
++#define CDNS_DP_MST_STREAM_CONFIG(s)          (CDNS_DPTX_STREAM(s) + 0x14)
++#define CDNS_DP_MST_STRM_CFG_STREAM_EN                BIT(0)
++#define CDNS_DP_MST_STRM_CFG_NO_VIDEO         BIT(1)
++
++#define CDNS_DP_MST_SLOT_ALLOCATE(s)          (CDNS_DPTX_STREAM(s) + 0x44)
++#define CDNS_DP_S_ALLOC_START_SLOT(x)         (x)
++#define CDNS_DP_S_ALLOC_END_SLOT(x)           ((x) << 8)
++
++#define CDNS_DP_RATE_GOVERNING(s)             (CDNS_DPTX_STREAM(s) + 0x48)
++#define CDNS_DP_RG_TARG_AV_SLOTS_Y(x)         (x)
++#define CDNS_DP_RG_TARG_AV_SLOTS_X(x)         (x << 4)
++#define CDNS_DP_RG_ENABLE                     BIT(10)
++
++#define CDNS_DP_MTPH_CONTROL                  0x2264
++#define CDNS_DP_MTPH_ECF_EN                   BIT(0)
++#define CDNS_DP_MTPH_ACT_EN                   BIT(1)
++#define CDNS_DP_MTPH_LVP_EN                   BIT(2)
++
++#define CDNS_DP_MTPH_STATUS                   0x226C
++#define CDNS_DP_MTPH_ACT_STATUS                       BIT(0)
++
++
++#define CDNS_DPTX_GLOBAL                      0x02300
++#define CDNS_DP_LANE_EN                               (CDNS_DPTX_GLOBAL + 0x00)
++#define CDNS_DP_LANE_EN_LANES(x)              GENMASK(x - 1, 0)
++#define CDNS_DP_ENHNCD                                (CDNS_DPTX_GLOBAL + 0x04)
++
++
++#define to_mhdp_connector(x) container_of(x, struct cdns_mhdp_connector, base)
++#define to_mhdp_bridge(x) container_of(x, struct cdns_mhdp_bridge, base)
++#define mgr_to_mhdp(x) container_of(x, struct cdns_mhdp_device, mst_mgr)
++
++#define CDNS_MHDP_MAX_STREAMS   4
++
++enum pixel_format {
++      PIXEL_FORMAT_RGB = 1,
++      PIXEL_FORMAT_YCBCR_444 = 2,
++      PIXEL_FORMAT_YCBCR_422 = 4,
++      PIXEL_FORMAT_YCBCR_420 = 8,
++      PIXEL_FORMAT_Y_ONLY = 16,
++};
++
++
++int cdns_mhdp_mst_init(struct cdns_mhdp_device *mhdp);
++void cdns_mhdp_mst_deinit(struct cdns_mhdp_device *mhdp);
++bool cdns_mhdp_mst_probe(struct cdns_mhdp_device *mhdp);
++enum pixel_format cdns_mhdp_get_pxlfmt(u32 color_formats);
++u32 cdns_mhdp_get_bpp(u32 bpc, u32 color_formats);
++void cdns_mhdp_configure_video(struct drm_bridge *bridge);
++void cdns_mhdp_mst_enable(struct drm_bridge *bridge);
++void cdns_mhdp_mst_disable(struct drm_bridge *bridge);
++void cdns_mhdp_enable(struct drm_bridge *bridge);
++
++#endif
+--- a/drivers/gpu/drm/rockchip/Kconfig
++++ b/drivers/gpu/drm/rockchip/Kconfig
+@@ -29,7 +29,9 @@ config ROCKCHIP_ANALOGIX_DP
+ config ROCKCHIP_CDN_DP
+         bool "Rockchip cdn DP"
+-      depends on EXTCON=y || (EXTCON=m && DRM_ROCKCHIP=m)
++      depends on DRM_ROCKCHIP
++      select EXTCON
++      select DRM_CDNS_MHDP
+         help
+         This selects support for Rockchip SoC specific extensions
+         for the cdn DP driver. If you want to enable Dp on
+--- a/drivers/gpu/drm/rockchip/Makefile
++++ b/drivers/gpu/drm/rockchip/Makefile
+@@ -8,7 +8,7 @@ rockchipdrm-y := rockchip_drm_drv.o rock
+ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
+ rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
+-rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
++rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o
+ rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
+ rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o
+ rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
+--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
++++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
+@@ -25,7 +25,7 @@
+ #include "rockchip_drm_vop.h"
+ #define connector_to_dp(c) \
+-              container_of(c, struct cdn_dp_device, mhdp.connector)
++              container_of(c, struct cdn_dp_device, mhdp.connector.base)
+ #define encoder_to_dp(c) \
+               container_of(c, struct cdn_dp_device, encoder)
+@@ -282,7 +282,7 @@ static int cdn_dp_connector_mode_valid(s
+ {
+       struct cdn_dp_device *dp = connector_to_dp(connector);
+       struct drm_display_info *display_info =
+-              &dp->mhdp.connector.display_info;
++              &dp->mhdp.connector.base.display_info;
+       u32 requested, actual, rate, sink_max, source_max = 0;
+       u8 lanes, bpc;
+@@ -378,7 +378,7 @@ static int cdn_dp_get_sink_capability(st
+       }
+       kfree(dp->edid);
+-      dp->edid = drm_do_get_edid(&dp->mhdp.connector,
++      dp->edid = drm_do_get_edid(&dp->mhdp.connector.base,
+                                  cdns_mhdp_get_edid_block, &dp->mhdp);
+       return 0;
+ }
+@@ -484,8 +484,8 @@ static int cdn_dp_disable(struct cdn_dp_
+       cdns_mhdp_set_firmware_active(&dp->mhdp, false);
+       cdn_dp_clk_disable(dp);
+       dp->active = false;
+-      dp->mhdp.link.rate = 0;
+-      dp->mhdp.link.num_lanes = 0;
++      dp->mhdp.dp.link.rate = 0;
++      dp->mhdp.dp.link.num_lanes = 0;
+       if (!dp->connected) {
+               kfree(dp->edid);
+               dp->edid = NULL;
+@@ -550,7 +550,7 @@ static void cdn_dp_encoder_mode_set(stru
+ {
+       struct cdn_dp_device *dp = encoder_to_dp(encoder);
+       struct drm_display_info *display_info =
+-              &dp->mhdp.connector.display_info;
++              &dp->mhdp.connector.base.display_info;
+       struct video_info *video = &dp->mhdp.video_info;
+       switch (display_info->bpc) {
+@@ -578,7 +578,7 @@ static bool cdn_dp_check_link_status(str
+       struct cdn_dp_port *port = cdn_dp_connected_port(dp);
+       u8 sink_lanes = drm_dp_max_lane_count(dp->dpcd);
+-      if (!port || !dp->mhdp.link.rate || !dp->mhdp.link.num_lanes)
++      if (!port || !dp->mhdp.dp.link.rate || !dp->mhdp.dp.link.num_lanes)
+               return false;
+       if (cdns_mhdp_dpcd_read(&dp->mhdp, DP_LANE0_1_STATUS, link_status,
+@@ -807,7 +807,7 @@ static int cdn_dp_audio_hw_params(struct
+       ret = cdns_mhdp_audio_config(&dp->mhdp, &audio);
+       if (!ret)
+-              dp->audio_info = audio;
++              dp->mhdp.audio_info = audio;
+ out:
+       mutex_unlock(&dp->lock);
+@@ -823,9 +823,9 @@ static void cdn_dp_audio_shutdown(struct
+       if (!dp->active)
+               goto out;
+-      ret = cdns_mhdp_audio_stop(&dp->mhdp, &dp->audio_info);
++      ret = cdns_mhdp_audio_stop(&dp->mhdp, &dp->mhdp.audio_info);
+       if (!ret)
+-              dp->audio_info.format = AFMT_UNUSED;
++              dp->mhdp.audio_info.format = AFMT_UNUSED;
+ out:
+       mutex_unlock(&dp->lock);
+ }
+@@ -854,8 +854,8 @@ static int cdn_dp_audio_get_eld(struct d
+ {
+       struct cdn_dp_device *dp = dev_get_drvdata(dev);
+-      memcpy(buf, dp->mhdp.connector.eld,
+-             min(sizeof(dp->mhdp.connector.eld), len));
++      memcpy(buf, dp->mhdp.connector.base.eld,
++             min(sizeof(dp->mhdp.connector.base.eld), len));
+       return 0;
+ }
+@@ -877,11 +877,11 @@ static int cdn_dp_audio_codec_init(struc
+               .max_i2s_channels = 8,
+       };
+-      dp->audio_pdev = platform_device_register_data(
+-                       dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO,
+-                       &codec_data, sizeof(codec_data));
++      dp->mhdp.audio_pdev = platform_device_register_data(
++                            dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO,
++                            &codec_data, sizeof(codec_data));
+-      return PTR_ERR_OR_ZERO(dp->audio_pdev);
++      return PTR_ERR_OR_ZERO(dp->mhdp.audio_pdev);
+ }
+ static int cdn_dp_request_firmware(struct cdn_dp_device *dp)
+@@ -927,7 +927,7 @@ static void cdn_dp_pd_event_work(struct
+ {
+       struct cdn_dp_device *dp = container_of(work, struct cdn_dp_device,
+                                               event_work);
+-      struct drm_connector *connector = &dp->mhdp.connector;
++      struct drm_connector *connector = &dp->mhdp.connector.base;
+       enum drm_connector_status old_status;
+       struct device *dev = dp->mhdp.dev;
+@@ -965,8 +965,8 @@ static void cdn_dp_pd_event_work(struct
+       /* Enabled and connected with a sink, re-train if requested */
+       } else if (!cdn_dp_check_link_status(dp)) {
+-              unsigned int rate = dp->mhdp.link.rate;
+-              unsigned int lanes = dp->mhdp.link.num_lanes;
++              unsigned int rate = dp->mhdp.dp.link.rate;
++              unsigned int lanes = dp->mhdp.dp.link.num_lanes;
+               struct drm_display_mode *mode = &dp->mhdp.mode;
+               DRM_DEV_INFO(dev, "Connected with sink. Re-train link\n");
+@@ -979,8 +979,8 @@ static void cdn_dp_pd_event_work(struct
+               /* If training result is changed, update the video config */
+               if (mode->clock &&
+-                  (rate != dp->mhdp.link.rate ||
+-                   lanes != dp->mhdp.link.num_lanes)) {
++                  (rate != dp->mhdp.dp.link.rate ||
++                   lanes != dp->mhdp.dp.link.num_lanes)) {
+                       ret = cdns_mhdp_config_video(&dp->mhdp);
+                       if (ret) {
+                               dp->connected = false;
+@@ -1053,7 +1053,7 @@ static int cdn_dp_bind(struct device *de
+       drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs);
+-      connector = &dp->mhdp.connector;
++      connector = &dp->mhdp.connector.base;
+       connector->polled = DRM_CONNECTOR_POLL_HPD;
+       connector->dpms = DRM_MODE_DPMS_OFF;
+@@ -1104,7 +1104,7 @@ static void cdn_dp_unbind(struct device
+ {
+       struct cdn_dp_device *dp = dev_get_drvdata(dev);
+       struct drm_encoder *encoder = &dp->encoder;
+-      struct drm_connector *connector = &dp->mhdp.connector;
++      struct drm_connector *connector = &dp->mhdp.connector.base;
+       cancel_work_sync(&dp->event_work);
+       cdn_dp_encoder_disable(encoder);
+@@ -1208,7 +1208,7 @@ static int cdn_dp_remove(struct platform
+ {
+       struct cdn_dp_device *dp = platform_get_drvdata(pdev);
+-      platform_device_unregister(dp->audio_pdev);
++      platform_device_unregister(dp->mhdp.audio_pdev);
+       cdn_dp_suspend(dp->mhdp.dev);
+       component_del(&pdev->dev, &cdn_dp_component_ops);
+--- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
++++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
+@@ -7,12 +7,13 @@
+ #ifndef _CDN_DP_CORE_H
+ #define _CDN_DP_CORE_H
++#include <drm/bridge/cdns-mhdp-common.h>
++#include <drm/drmP.h>
+ #include <drm/drm_dp_helper.h>
+ #include <drm/drm_panel.h>
+ #include <drm/drm_probe_helper.h>
+ #include "rockchip_drm_drv.h"
+-#include "cdn-dp-reg.h"
+ #define MAX_PHY               2
+@@ -37,7 +38,6 @@ struct cdn_dp_device {
+       struct cdns_mhdp_device mhdp;
+       struct drm_device *drm_dev;
+       struct drm_encoder encoder;
+-      struct platform_device *audio_pdev;
+       struct work_struct event_work;
+       struct edid *edid;
+@@ -56,7 +56,6 @@ struct cdn_dp_device {
+       struct reset_control *dptx_rst;
+       struct reset_control *apb_rst;
+       struct reset_control *core_rst;
+-      struct audio_info audio_info;
+       struct cdn_dp_port *port[MAX_PHY];
+       u8 ports;
+       u8 lanes;
+--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c
++++ /dev/null
+@@ -1,968 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-only
+-/*
+- * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+- * Author: Chris Zhong <zyw@rock-chips.com>
+- */
+-
+-#include <linux/clk.h>
+-#include <linux/device.h>
+-#include <linux/delay.h>
+-#include <linux/io.h>
+-#include <linux/iopoll.h>
+-#include <linux/reset.h>
+-
+-#include "cdn-dp-core.h"
+-#include "cdn-dp-reg.h"
+-
+-#define CDNS_DP_SPDIF_CLK             200000000
+-#define FW_ALIVE_TIMEOUT_US           1000000
+-#define MAILBOX_RETRY_US              1000
+-#define MAILBOX_TIMEOUT_US            5000000
+-#define LINK_TRAINING_RETRY_MS                20
+-#define LINK_TRAINING_TIMEOUT_MS      500
+-
+-void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk)
+-{
+-      writel(clk / 1000000, mhdp->regs + SW_CLK_H);
+-}
+-
+-void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp)
+-{
+-      u32 val;
+-
+-      val = DPTX_FRMR_DATA_CLK_RSTN_EN |
+-            DPTX_FRMR_DATA_CLK_EN |
+-            DPTX_PHY_DATA_RSTN_EN |
+-            DPTX_PHY_DATA_CLK_EN |
+-            DPTX_PHY_CHAR_RSTN_EN |
+-            DPTX_PHY_CHAR_CLK_EN |
+-            SOURCE_AUX_SYS_CLK_RSTN_EN |
+-            SOURCE_AUX_SYS_CLK_EN |
+-            DPTX_SYS_CLK_RSTN_EN |
+-            DPTX_SYS_CLK_EN |
+-            CFG_DPTX_VIF_CLK_RSTN_EN |
+-            CFG_DPTX_VIF_CLK_EN;
+-      writel(val, mhdp->regs + SOURCE_DPTX_CAR);
+-
+-      val = SOURCE_PHY_RSTN_EN | SOURCE_PHY_CLK_EN;
+-      writel(val, mhdp->regs + SOURCE_PHY_CAR);
+-
+-      val = SOURCE_PKT_SYS_RSTN_EN |
+-            SOURCE_PKT_SYS_CLK_EN |
+-            SOURCE_PKT_DATA_RSTN_EN |
+-            SOURCE_PKT_DATA_CLK_EN;
+-      writel(val, mhdp->regs + SOURCE_PKT_CAR);
+-
+-      val = SPDIF_CDR_CLK_RSTN_EN |
+-            SPDIF_CDR_CLK_EN |
+-            SOURCE_AIF_SYS_RSTN_EN |
+-            SOURCE_AIF_SYS_CLK_EN |
+-            SOURCE_AIF_CLK_RSTN_EN |
+-            SOURCE_AIF_CLK_EN;
+-      writel(val, mhdp->regs + SOURCE_AIF_CAR);
+-
+-      val = SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN |
+-            SOURCE_CIPHER_SYS_CLK_EN |
+-            SOURCE_CIPHER_CHAR_CLK_RSTN_EN |
+-            SOURCE_CIPHER_CHAR_CLK_EN;
+-      writel(val, mhdp->regs + SOURCE_CIPHER_CAR);
+-
+-      val = SOURCE_CRYPTO_SYS_CLK_RSTN_EN |
+-            SOURCE_CRYPTO_SYS_CLK_EN;
+-      writel(val, mhdp->regs + SOURCE_CRYPTO_CAR);
+-
+-      /* enable Mailbox and PIF interrupt */
+-      writel(0, mhdp->regs + APB_INT_MASK);
+-}
+-
+-static int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)
+-{
+-      int val, ret;
+-
+-      ret = readx_poll_timeout(readl, mhdp->regs + MAILBOX_EMPTY_ADDR,
+-                               val, !val, MAILBOX_RETRY_US,
+-                               MAILBOX_TIMEOUT_US);
+-      if (ret < 0)
+-              return ret;
+-
+-      return readl(mhdp->regs + MAILBOX0_RD_DATA) & 0xff;
+-}
+-
+-static int cdp_dp_mailbox_write(struct cdns_mhdp_device *mhdp, u8 val)
+-{
+-      int ret, full;
+-
+-      ret = readx_poll_timeout(readl, mhdp->regs + MAILBOX_FULL_ADDR,
+-                               full, !full, MAILBOX_RETRY_US,
+-                               MAILBOX_TIMEOUT_US);
+-      if (ret < 0)
+-              return ret;
+-
+-      writel(val, mhdp->regs + MAILBOX0_WR_DATA);
+-
+-      return 0;
+-}
+-
+-static int cdns_mhdp_mailbox_validate_receive(struct cdns_mhdp_device *mhdp,
+-                                            u8 module_id, u8 opcode,
+-                                            u16 req_size)
+-{
+-      u32 mbox_size, i;
+-      u8 header[4];
+-      int ret;
+-
+-      /* read the header of the message */
+-      for (i = 0; i < 4; i++) {
+-              ret = cdns_mhdp_mailbox_read(mhdp);
+-              if (ret < 0)
+-                      return ret;
+-
+-              header[i] = ret;
+-      }
+-
+-      mbox_size = (header[2] << 8) | header[3];
+-
+-      if (opcode != header[0] || module_id != header[1] ||
+-          req_size != mbox_size) {
+-              /*
+-               * If the message in mailbox is not what we want, we need to
+-               * clear the mailbox by reading its contents.
+-               */
+-              for (i = 0; i < mbox_size; i++)
+-                      if (cdns_mhdp_mailbox_read(mhdp) < 0)
+-                              break;
+-
+-              return -EINVAL;
+-      }
+-
+-      return 0;
+-}
+-
+-static int cdns_mhdp_mailbox_read_receive(struct cdns_mhdp_device *mhdp,
+-                                        u8 *buff, u16 buff_size)
+-{
+-      u32 i;
+-      int ret;
+-
+-      for (i = 0; i < buff_size; i++) {
+-              ret = cdns_mhdp_mailbox_read(mhdp);
+-              if (ret < 0)
+-                      return ret;
+-
+-              buff[i] = ret;
+-      }
+-
+-      return 0;
+-}
+-
+-static int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id,
+-                                u8 opcode, u16 size, u8 *message)
+-{
+-      u8 header[4];
+-      int ret, i;
+-
+-      header[0] = opcode;
+-      header[1] = module_id;
+-      header[2] = (size >> 8) & 0xff;
+-      header[3] = size & 0xff;
+-
+-      for (i = 0; i < 4; i++) {
+-              ret = cdp_dp_mailbox_write(mhdp, header[i]);
+-              if (ret)
+-                      return ret;
+-      }
+-
+-      for (i = 0; i < size; i++) {
+-              ret = cdp_dp_mailbox_write(mhdp, message[i]);
+-              if (ret)
+-                      return ret;
+-      }
+-
+-      return 0;
+-}
+-
+-static int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u16 addr, u32 val)
+-{
+-      u8 msg[6];
+-
+-      msg[0] = (addr >> 8) & 0xff;
+-      msg[1] = addr & 0xff;
+-      msg[2] = (val >> 24) & 0xff;
+-      msg[3] = (val >> 16) & 0xff;
+-      msg[4] = (val >> 8) & 0xff;
+-      msg[5] = val & 0xff;
+-      return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+-                                    DPTX_WRITE_REGISTER, sizeof(msg), msg);
+-}
+-
+-static int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
+-                                 u8 start_bit, u8 bits_no, u32 val)
+-{
+-      u8 field[8];
+-
+-      field[0] = (addr >> 8) & 0xff;
+-      field[1] = addr & 0xff;
+-      field[2] = start_bit;
+-      field[3] = bits_no;
+-      field[4] = (val >> 24) & 0xff;
+-      field[5] = (val >> 16) & 0xff;
+-      field[6] = (val >> 8) & 0xff;
+-      field[7] = val & 0xff;
+-
+-      return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+-                                    DPTX_WRITE_FIELD, sizeof(field), field);
+-}
+-
+-int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,
+-                      u32 addr, u8 *data, u16 len)
+-{
+-      u8 msg[5], reg[5];
+-      int ret;
+-
+-      msg[0] = (len >> 8) & 0xff;
+-      msg[1] = len & 0xff;
+-      msg[2] = (addr >> 16) & 0xff;
+-      msg[3] = (addr >> 8) & 0xff;
+-      msg[4] = addr & 0xff;
+-      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+-                                   DPTX_READ_DPCD, sizeof(msg), msg);
+-      if (ret)
+-              goto err_dpcd_read;
+-
+-      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+-                                               DPTX_READ_DPCD,
+-                                               sizeof(reg) + len);
+-      if (ret)
+-              goto err_dpcd_read;
+-
+-      ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+-      if (ret)
+-              goto err_dpcd_read;
+-
+-      ret = cdns_mhdp_mailbox_read_receive(mhdp, data, len);
+-
+-err_dpcd_read:
+-      return ret;
+-}
+-
+-int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value)
+-{
+-      u8 msg[6], reg[5];
+-      int ret;
+-
+-      msg[0] = 0;
+-      msg[1] = 1;
+-      msg[2] = (addr >> 16) & 0xff;
+-      msg[3] = (addr >> 8) & 0xff;
+-      msg[4] = addr & 0xff;
+-      msg[5] = value;
+-      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+-                                   DPTX_WRITE_DPCD, sizeof(msg), msg);
+-      if (ret)
+-              goto err_dpcd_write;
+-
+-      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+-                                               DPTX_WRITE_DPCD, sizeof(reg));
+-      if (ret)
+-              goto err_dpcd_write;
+-
+-      ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+-      if (ret)
+-              goto err_dpcd_write;
+-
+-      if (addr != (reg[2] << 16 | reg[3] << 8 | reg[4]))
+-              ret = -EINVAL;
+-
+-err_dpcd_write:
+-      if (ret)
+-              DRM_DEV_ERROR(mhdp->dev, "dpcd write failed: %d\n", ret);
+-      return ret;
+-}
+-
+-int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
+-                          u32 i_size, const u32 *d_mem, u32 d_size)
+-{
+-      u32 reg;
+-      int i, ret;
+-
+-      /* reset ucpu before load firmware*/
+-      writel(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET,
+-             mhdp->regs + APB_CTRL);
+-
+-      for (i = 0; i < i_size; i += 4)
+-              writel(*i_mem++, mhdp->regs + ADDR_IMEM + i);
+-
+-      for (i = 0; i < d_size; i += 4)
+-              writel(*d_mem++, mhdp->regs + ADDR_DMEM + i);
+-
+-      /* un-reset ucpu */
+-      writel(0, mhdp->regs + APB_CTRL);
+-
+-      /* check the keep alive register to make sure fw working */
+-      ret = readx_poll_timeout(readl, mhdp->regs + KEEP_ALIVE,
+-                               reg, reg, 2000, FW_ALIVE_TIMEOUT_US);
+-      if (ret < 0) {
+-              DRM_DEV_ERROR(mhdp->dev, "failed to loaded the FW reg = %x\n",
+-                            reg);
+-              return -EINVAL;
+-      }
+-
+-      reg = readl(mhdp->regs + VER_L) & 0xff;
+-      mhdp->fw_version = reg;
+-      reg = readl(mhdp->regs + VER_H) & 0xff;
+-      mhdp->fw_version |= reg << 8;
+-      reg = readl(mhdp->regs + VER_LIB_L_ADDR) & 0xff;
+-      mhdp->fw_version |= reg << 16;
+-      reg = readl(mhdp->regs + VER_LIB_H_ADDR) & 0xff;
+-      mhdp->fw_version |= reg << 24;
+-
+-      DRM_DEV_DEBUG(mhdp->dev, "firmware version: %x\n", mhdp->fw_version);
+-
+-      return 0;
+-}
+-
+-int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable)
+-{
+-      u8 msg[5];
+-      int ret, i;
+-
+-      msg[0] = GENERAL_MAIN_CONTROL;
+-      msg[1] = MB_MODULE_ID_GENERAL;
+-      msg[2] = 0;
+-      msg[3] = 1;
+-      msg[4] = enable ? FW_ACTIVE : FW_STANDBY;
+-
+-      for (i = 0; i < sizeof(msg); i++) {
+-              ret = cdp_dp_mailbox_write(mhdp, msg[i]);
+-              if (ret)
+-                      goto err_set_firmware_active;
+-      }
+-
+-      /* read the firmware state */
+-      for (i = 0; i < sizeof(msg); i++)  {
+-              ret = cdns_mhdp_mailbox_read(mhdp);
+-              if (ret < 0)
+-                      goto err_set_firmware_active;
+-
+-              msg[i] = ret;
+-      }
+-
+-      ret = 0;
+-
+-err_set_firmware_active:
+-      if (ret < 0)
+-              DRM_DEV_ERROR(mhdp->dev, "set firmware active failed\n");
+-      return ret;
+-}
+-
+-int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, u8 lanes, bool flip)
+-{
+-      u8 msg[8];
+-      int ret;
+-
+-      msg[0] = CDNS_DP_MAX_LINK_RATE;
+-      msg[1] = lanes | SCRAMBLER_EN;
+-      msg[2] = VOLTAGE_LEVEL_2;
+-      msg[3] = PRE_EMPHASIS_LEVEL_3;
+-      msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
+-      msg[5] = FAST_LT_NOT_SUPPORT;
+-      msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL;
+-      msg[7] = ENHANCED;
+-
+-      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+-                                   DPTX_SET_HOST_CAPABILITIES,
+-                                   sizeof(msg), msg);
+-      if (ret)
+-              goto err_set_host_cap;
+-
+-      ret = cdns_mhdp_reg_write(mhdp, DP_AUX_SWAP_INVERSION_CONTROL,
+-                                AUX_HOST_INVERT);
+-
+-err_set_host_cap:
+-      if (ret)
+-              DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret);
+-      return ret;
+-}
+-
+-int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp)
+-{
+-      u8 msg[5];
+-      int ret;
+-
+-      memset(msg, 0, sizeof(msg));
+-
+-      msg[0] = DPTX_EVENT_ENABLE_HPD | DPTX_EVENT_ENABLE_TRAINING;
+-
+-      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+-                                   DPTX_ENABLE_EVENT, sizeof(msg), msg);
+-      if (ret)
+-              DRM_DEV_ERROR(mhdp->dev, "set event config failed: %d\n", ret);
+-
+-      return ret;
+-}
+-
+-u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp)
+-{
+-      return readl(mhdp->regs + SW_EVENTS0);
+-}
+-
+-int cdns_mhdp_get_hpd_status(struct cdns_mhdp_device *mhdp)
+-{
+-      u8 status;
+-      int ret;
+-
+-      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+-                                   DPTX_HPD_STATE, 0, NULL);
+-      if (ret)
+-              goto err_get_hpd;
+-
+-      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+-                                               DPTX_HPD_STATE,
+-                                               sizeof(status));
+-      if (ret)
+-              goto err_get_hpd;
+-
+-      ret = cdns_mhdp_mailbox_read_receive(mhdp, &status, sizeof(status));
+-      if (ret)
+-              goto err_get_hpd;
+-
+-      return status;
+-
+-err_get_hpd:
+-      DRM_DEV_ERROR(mhdp->dev, "get hpd status failed: %d\n", ret);
+-      return ret;
+-}
+-
+-int cdns_mhdp_get_edid_block(void *data, u8 *edid,
+-                        unsigned int block, size_t length)
+-{
+-      struct cdns_mhdp_device *mhdp = data;
+-      u8 msg[2], reg[2], i;
+-      int ret;
+-
+-      for (i = 0; i < 4; i++) {
+-              msg[0] = block / 2;
+-              msg[1] = block % 2;
+-
+-              ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+-                                           DPTX_GET_EDID, sizeof(msg), msg);
+-              if (ret)
+-                      continue;
+-
+-              ret = cdns_mhdp_mailbox_validate_receive(mhdp,
+-                                                       MB_MODULE_ID_DP_TX,
+-                                                       DPTX_GET_EDID,
+-                                                       sizeof(reg) + length);
+-              if (ret)
+-                      continue;
+-
+-              ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+-              if (ret)
+-                      continue;
+-
+-              ret = cdns_mhdp_mailbox_read_receive(mhdp, edid, length);
+-              if (ret)
+-                      continue;
+-
+-              if (reg[0] == length && reg[1] == block / 2)
+-                      break;
+-      }
+-
+-      if (ret)
+-              DRM_DEV_ERROR(mhdp->dev, "get block[%d] edid failed: %d\n",
+-                            block, ret);
+-
+-      return ret;
+-}
+-
+-static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp)
+-{
+-      unsigned long timeout;
+-      u8 msg, event[2];
+-      int ret;
+-
+-      msg = LINK_TRAINING_RUN;
+-
+-      /* start training */
+-      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+-                                   DPTX_TRAINING_CONTROL, sizeof(msg), &msg);
+-      if (ret)
+-              goto err_training_start;
+-
+-      timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS);
+-      while (time_before(jiffies, timeout)) {
+-              msleep(LINK_TRAINING_RETRY_MS);
+-              ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+-                                           DPTX_READ_EVENT, 0, NULL);
+-              if (ret)
+-                      goto err_training_start;
+-
+-              ret = cdns_mhdp_mailbox_validate_receive(mhdp,
+-                                                       MB_MODULE_ID_DP_TX,
+-                                                       DPTX_READ_EVENT,
+-                                                       sizeof(event));
+-              if (ret)
+-                      goto err_training_start;
+-
+-              ret = cdns_mhdp_mailbox_read_receive(mhdp, event,
+-                                                   sizeof(event));
+-              if (ret)
+-                      goto err_training_start;
+-
+-              if (event[1] & EQ_PHASE_FINISHED)
+-                      return 0;
+-      }
+-
+-      ret = -ETIMEDOUT;
+-
+-err_training_start:
+-      DRM_DEV_ERROR(mhdp->dev, "training failed: %d\n", ret);
+-      return ret;
+-}
+-
+-static int cdns_mhdp_get_training_status(struct cdns_mhdp_device *mhdp)
+-{
+-      u8 status[10];
+-      int ret;
+-
+-      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, DPTX_READ_LINK_STAT,
+-                                0, NULL);
+-      if (ret)
+-              goto err_get_training_status;
+-
+-      ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+-                                            DPTX_READ_LINK_STAT,
+-                                            sizeof(status));
+-      if (ret)
+-              goto err_get_training_status;
+-
+-      ret = cdns_mhdp_mailbox_read_receive(mhdp, status, sizeof(status));
+-      if (ret)
+-              goto err_get_training_status;
+-
+-      mhdp->link.rate = drm_dp_bw_code_to_link_rate(status[0]);
+-      mhdp->link.num_lanes = status[1];
+-
+-err_get_training_status:
+-      if (ret)
+-              DRM_DEV_ERROR(mhdp->dev, "get training status failed: %d\n", ret);
+-      return ret;
+-}
+-
+-int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp)
+-{
+-      int ret;
+-
+-      ret = cdns_mhdp_training_start(mhdp);
+-      if (ret) {
+-              DRM_DEV_ERROR(mhdp->dev, "Failed to start training %d\n", ret);
+-              return ret;
+-      }
+-
+-      ret = cdns_mhdp_get_training_status(mhdp);
+-      if (ret) {
+-              DRM_DEV_ERROR(mhdp->dev, "Failed to get training stat %d\n", ret);
+-              return ret;
+-      }
+-
+-      DRM_DEV_DEBUG_KMS(mhdp->dev, "rate:0x%x, lanes:%d\n", mhdp->link.rate,
+-                        mhdp->link.num_lanes);
+-      return ret;
+-}
+-
+-int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active)
+-{
+-      u8 msg;
+-      int ret;
+-
+-      msg = !!active;
+-
+-      ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, DPTX_SET_VIDEO,
+-                                sizeof(msg), &msg);
+-      if (ret)
+-              DRM_DEV_ERROR(mhdp->dev, "set video status failed: %d\n", ret);
+-
+-      return ret;
+-}
+-
+-static int cdns_mhdp_get_msa_misc(struct video_info *video,
+-                             struct drm_display_mode *mode)
+-{
+-      u32 msa_misc;
+-      u8 val[2] = {0};
+-
+-      switch (video->color_fmt) {
+-      case PXL_RGB:
+-      case Y_ONLY:
+-              val[0] = 0;
+-              break;
+-      /* set YUV default color space conversion to BT601 */
+-      case YCBCR_4_4_4:
+-              val[0] = 6 + BT_601 * 8;
+-              break;
+-      case YCBCR_4_2_2:
+-              val[0] = 5 + BT_601 * 8;
+-              break;
+-      case YCBCR_4_2_0:
+-              val[0] = 5;
+-              break;
+-      };
+-
+-      switch (video->color_depth) {
+-      case 6:
+-              val[1] = 0;
+-              break;
+-      case 8:
+-              val[1] = 1;
+-              break;
+-      case 10:
+-              val[1] = 2;
+-              break;
+-      case 12:
+-              val[1] = 3;
+-              break;
+-      case 16:
+-              val[1] = 4;
+-              break;
+-      };
+-
+-      msa_misc = 2 * val[0] + 32 * val[1] +
+-                 ((video->color_fmt == Y_ONLY) ? (1 << 14) : 0);
+-
+-      return msa_misc;
+-}
+-
+-int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp)
+-{
+-      struct video_info *video = &mhdp->video_info;
+-      struct drm_display_mode *mode = &mhdp->mode;
+-      u64 symbol;
+-      u32 val, link_rate, rem;
+-      u8 bit_per_pix, tu_size_reg = TU_SIZE;
+-      int ret;
+-
+-      bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ?
+-                    (video->color_depth * 2) : (video->color_depth * 3);
+-
+-      link_rate = mhdp->link.rate / 1000;
+-
+-      ret = cdns_mhdp_reg_write(mhdp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE);
+-      if (ret)
+-              goto err_config_video;
+-
+-      ret = cdns_mhdp_reg_write(mhdp, HSYNC2VSYNC_POL_CTRL, 0);
+-      if (ret)
+-              goto err_config_video;
+-
+-      /*
+-       * get a best tu_size and valid symbol:
+-       * 1. chose Lclk freq(162Mhz, 270Mhz, 540Mhz), set TU to 32
+-       * 2. calculate VS(valid symbol) = TU * Pclk * Bpp / (Lclk * Lanes)
+-       * 3. if VS > *.85 or VS < *.1 or VS < 2 or TU < VS + 4, then set
+-       *    TU += 2 and repeat 2nd step.
+-       */
+-      do {
+-              tu_size_reg += 2;
+-              symbol = tu_size_reg * mode->clock * bit_per_pix;
+-              do_div(symbol, mhdp->link.num_lanes * link_rate * 8);
+-              rem = do_div(symbol, 1000);
+-              if (tu_size_reg > 64) {
+-                      ret = -EINVAL;
+-                      DRM_DEV_ERROR(mhdp->dev,
+-                                    "tu error, clk:%d, lanes:%d, rate:%d\n",
+-                                    mode->clock, mhdp->link.num_lanes,
+-                                    link_rate);
+-                      goto err_config_video;
+-              }
+-      } while ((symbol <= 1) || (tu_size_reg - symbol < 4) ||
+-               (rem > 850) || (rem < 100));
+-
+-      val = symbol + (tu_size_reg << 8);
+-      val |= TU_CNT_RST_EN;
+-      ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_TU, val);
+-      if (ret)
+-              goto err_config_video;
+-
+-      /* set the FIFO Buffer size */
+-      val = div_u64(mode->clock * (symbol + 1), 1000) + link_rate;
+-      val /= (mhdp->link.num_lanes * link_rate);
+-      val = div_u64(8 * (symbol + 1), bit_per_pix) - val;
+-      val += 2;
+-      ret = cdns_mhdp_reg_write(mhdp, DP_VC_TABLE(15), val);
+-
+-      switch (video->color_depth) {
+-      case 6:
+-              val = BCS_6;
+-              break;
+-      case 8:
+-              val = BCS_8;
+-              break;
+-      case 10:
+-              val = BCS_10;
+-              break;
+-      case 12:
+-              val = BCS_12;
+-              break;
+-      case 16:
+-              val = BCS_16;
+-              break;
+-      };
+-
+-      val += video->color_fmt << 8;
+-      ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_PXL_REPR, val);
+-      if (ret)
+-              goto err_config_video;
+-
+-      val = video->h_sync_polarity ? DP_FRAMER_SP_HSP : 0;
+-      val |= video->v_sync_polarity ? DP_FRAMER_SP_VSP : 0;
+-      ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_SP, val);
+-      if (ret)
+-              goto err_config_video;
+-
+-      val = (mode->hsync_start - mode->hdisplay) << 16;
+-      val |= mode->htotal - mode->hsync_end;
+-      ret = cdns_mhdp_reg_write(mhdp, DP_FRONT_BACK_PORCH, val);
+-      if (ret)
+-              goto err_config_video;
+-
+-      val = mode->hdisplay * bit_per_pix / 8;
+-      ret = cdns_mhdp_reg_write(mhdp, DP_BYTE_COUNT, val);
+-      if (ret)
+-              goto err_config_video;
+-
+-      val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16);
+-      ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_0, val);
+-      if (ret)
+-              goto err_config_video;
+-
+-      val = mode->hsync_end - mode->hsync_start;
+-      val |= (mode->hdisplay << 16) | (video->h_sync_polarity << 15);
+-      ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_1, val);
+-      if (ret)
+-              goto err_config_video;
+-
+-      val = mode->vtotal;
+-      val |= (mode->vtotal - mode->vsync_start) << 16;
+-      ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_0, val);
+-      if (ret)
+-              goto err_config_video;
+-
+-      val = mode->vsync_end - mode->vsync_start;
+-      val |= (mode->vdisplay << 16) | (video->v_sync_polarity << 15);
+-      ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_1, val);
+-      if (ret)
+-              goto err_config_video;
+-
+-      val = cdns_mhdp_get_msa_misc(video, mode);
+-      ret = cdns_mhdp_reg_write(mhdp, MSA_MISC, val);
+-      if (ret)
+-              goto err_config_video;
+-
+-      ret = cdns_mhdp_reg_write(mhdp, STREAM_CONFIG, 1);
+-      if (ret)
+-              goto err_config_video;
+-
+-      val = mode->hsync_end - mode->hsync_start;
+-      val |= mode->hdisplay << 16;
+-      ret = cdns_mhdp_reg_write(mhdp, DP_HORIZONTAL, val);
+-      if (ret)
+-              goto err_config_video;
+-
+-      val = mode->vdisplay;
+-      val |= (mode->vtotal - mode->vsync_start) << 16;
+-      ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_0, val);
+-      if (ret)
+-              goto err_config_video;
+-
+-      val = mode->vtotal;
+-      ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_1, val);
+-      if (ret)
+-              goto err_config_video;
+-
+-      ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 2, 1, 0);
+-
+-err_config_video:
+-      if (ret)
+-              DRM_DEV_ERROR(mhdp->dev, "config video failed: %d\n", ret);
+-      return ret;
+-}
+-
+-int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
+-                       struct audio_info *audio)
+-{
+-      int ret;
+-
+-      ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, 0);
+-      if (ret) {
+-              DRM_DEV_ERROR(mhdp->dev, "audio stop failed: %d\n", ret);
+-              return ret;
+-      }
+-
+-      writel(0, mhdp->regs + SPDIF_CTRL_ADDR);
+-
+-      /* clearn the audio config and reset */
+-      writel(0, mhdp->regs + AUDIO_SRC_CNTL);
+-      writel(0, mhdp->regs + AUDIO_SRC_CNFG);
+-      writel(AUDIO_SW_RST, mhdp->regs + AUDIO_SRC_CNTL);
+-      writel(0, mhdp->regs + AUDIO_SRC_CNTL);
+-
+-      /* reset smpl2pckt component  */
+-      writel(0, mhdp->regs + SMPL2PKT_CNTL);
+-      writel(AUDIO_SW_RST, mhdp->regs + SMPL2PKT_CNTL);
+-      writel(0, mhdp->regs + SMPL2PKT_CNTL);
+-
+-      /* reset FIFO */
+-      writel(AUDIO_SW_RST, mhdp->regs + FIFO_CNTL);
+-      writel(0, mhdp->regs + FIFO_CNTL);
+-
+-      if (audio->format == AFMT_SPDIF)
+-              clk_disable_unprepare(mhdp->spdif_clk);
+-
+-      return 0;
+-}
+-
+-int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable)
+-{
+-      int ret;
+-
+-      ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 4, 1, enable);
+-      if (ret)
+-              DRM_DEV_ERROR(mhdp->dev, "audio mute failed: %d\n", ret);
+-
+-      return ret;
+-}
+-
+-static void cdns_mhdp_audio_config_i2s(struct cdns_mhdp_device *mhdp,
+-                                     struct audio_info *audio)
+-{
+-      int sub_pckt_num = 1, i2s_port_en_val = 0xf, i;
+-      u32 val;
+-
+-      if (audio->channels == 2) {
+-              if (mhdp->link.num_lanes == 1)
+-                      sub_pckt_num = 2;
+-              else
+-                      sub_pckt_num = 4;
+-
+-              i2s_port_en_val = 1;
+-      } else if (audio->channels == 4) {
+-              i2s_port_en_val = 3;
+-      }
+-
+-      writel(0x0, mhdp->regs + SPDIF_CTRL_ADDR);
+-
+-      writel(SYNC_WR_TO_CH_ZERO, mhdp->regs + FIFO_CNTL);
+-
+-      val = MAX_NUM_CH(audio->channels);
+-      val |= NUM_OF_I2S_PORTS(audio->channels);
+-      val |= AUDIO_TYPE_LPCM;
+-      val |= CFG_SUB_PCKT_NUM(sub_pckt_num);
+-      writel(val, mhdp->regs + SMPL2PKT_CNFG);
+-
+-      if (audio->sample_width == 16)
+-              val = 0;
+-      else if (audio->sample_width == 24)
+-              val = 1 << 9;
+-      else
+-              val = 2 << 9;
+-
+-      val |= AUDIO_CH_NUM(audio->channels);
+-      val |= I2S_DEC_PORT_EN(i2s_port_en_val);
+-      val |= TRANS_SMPL_WIDTH_32;
+-      writel(val, mhdp->regs + AUDIO_SRC_CNFG);
+-
+-      for (i = 0; i < (audio->channels + 1) / 2; i++) {
+-              if (audio->sample_width == 16)
+-                      val = (0x02 << 8) | (0x02 << 20);
+-              else if (audio->sample_width == 24)
+-                      val = (0x0b << 8) | (0x0b << 20);
+-
+-              val |= ((2 * i) << 4) | ((2 * i + 1) << 16);
+-              writel(val, mhdp->regs + STTS_BIT_CH(i));
+-      }
+-
+-      switch (audio->sample_rate) {
+-      case 32000:
+-              val = SAMPLING_FREQ(3) |
+-                    ORIGINAL_SAMP_FREQ(0xc);
+-              break;
+-      case 44100:
+-              val = SAMPLING_FREQ(0) |
+-                    ORIGINAL_SAMP_FREQ(0xf);
+-              break;
+-      case 48000:
+-              val = SAMPLING_FREQ(2) |
+-                    ORIGINAL_SAMP_FREQ(0xd);
+-              break;
+-      case 88200:
+-              val = SAMPLING_FREQ(8) |
+-                    ORIGINAL_SAMP_FREQ(0x7);
+-              break;
+-      case 96000:
+-              val = SAMPLING_FREQ(0xa) |
+-                    ORIGINAL_SAMP_FREQ(5);
+-              break;
+-      case 176400:
+-              val = SAMPLING_FREQ(0xc) |
+-                    ORIGINAL_SAMP_FREQ(3);
+-              break;
+-      case 192000:
+-              val = SAMPLING_FREQ(0xe) |
+-                    ORIGINAL_SAMP_FREQ(1);
+-              break;
+-      }
+-      val |= 4;
+-      writel(val, mhdp->regs + COM_CH_STTS_BITS);
+-
+-      writel(SMPL2PKT_EN, mhdp->regs + SMPL2PKT_CNTL);
+-      writel(I2S_DEC_START, mhdp->regs + AUDIO_SRC_CNTL);
+-}
+-
+-static void cdns_mhdp_audio_config_spdif(struct cdns_mhdp_device *mhdp)
+-{
+-      u32 val;
+-
+-      writel(SYNC_WR_TO_CH_ZERO, mhdp->regs + FIFO_CNTL);
+-
+-      val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4);
+-      writel(val, mhdp->regs + SMPL2PKT_CNFG);
+-      writel(SMPL2PKT_EN, mhdp->regs + SMPL2PKT_CNTL);
+-
+-      val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS;
+-      writel(val, mhdp->regs + SPDIF_CTRL_ADDR);
+-
+-      clk_prepare_enable(mhdp->spdif_clk);
+-      clk_set_rate(mhdp->spdif_clk, CDNS_DP_SPDIF_CLK);
+-}
+-
+-int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
+-                         struct audio_info *audio)
+-{
+-      int ret;
+-
+-      /* reset the spdif clk before config */
+-      if (audio->format == AFMT_SPDIF) {
+-              reset_control_assert(mhdp->spdif_rst);
+-              reset_control_deassert(mhdp->spdif_rst);
+-      }
+-
+-      ret = cdns_mhdp_reg_write(mhdp, CM_LANE_CTRL, LANE_REF_CYC);
+-      if (ret)
+-              goto err_audio_config;
+-
+-      ret = cdns_mhdp_reg_write(mhdp, CM_CTRL, 0);
+-      if (ret)
+-              goto err_audio_config;
+-
+-      if (audio->format == AFMT_I2S)
+-              cdns_mhdp_audio_config_i2s(mhdp, audio);
+-      else if (audio->format == AFMT_SPDIF)
+-              cdns_mhdp_audio_config_spdif(mhdp);
+-
+-      ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN);
+-
+-err_audio_config:
+-      if (ret)
+-              DRM_DEV_ERROR(mhdp->dev, "audio config failed: %d\n", ret);
+-      return ret;
+-}
+--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h
++++ /dev/null
+@@ -1,546 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0-only */
+-/*
+- * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+- * Author: Chris Zhong <zyw@rock-chips.com>
+- */
+-
+-#ifndef _CDN_DP_REG_H
+-#define _CDN_DP_REG_H
+-
+-#include <linux/bitops.h>
+-
+-#define ADDR_IMEM             0x10000
+-#define ADDR_DMEM             0x20000
+-
+-/* APB CFG addr */
+-#define APB_CTRL                      0
+-#define XT_INT_CTRL                   0x04
+-#define MAILBOX_FULL_ADDR             0x08
+-#define MAILBOX_EMPTY_ADDR            0x0c
+-#define MAILBOX0_WR_DATA              0x10
+-#define MAILBOX0_RD_DATA              0x14
+-#define KEEP_ALIVE                    0x18
+-#define VER_L                         0x1c
+-#define VER_H                         0x20
+-#define VER_LIB_L_ADDR                        0x24
+-#define VER_LIB_H_ADDR                        0x28
+-#define SW_DEBUG_L                    0x2c
+-#define SW_DEBUG_H                    0x30
+-#define MAILBOX_INT_MASK              0x34
+-#define MAILBOX_INT_STATUS            0x38
+-#define SW_CLK_L                      0x3c
+-#define SW_CLK_H                      0x40
+-#define SW_EVENTS0                    0x44
+-#define SW_EVENTS1                    0x48
+-#define SW_EVENTS2                    0x4c
+-#define SW_EVENTS3                    0x50
+-#define XT_OCD_CTRL                   0x60
+-#define APB_INT_MASK                  0x6c
+-#define APB_STATUS_MASK                       0x70
+-
+-/* audio decoder addr */
+-#define AUDIO_SRC_CNTL                        0x30000
+-#define AUDIO_SRC_CNFG                        0x30004
+-#define COM_CH_STTS_BITS              0x30008
+-#define STTS_BIT_CH(x)                        (0x3000c + ((x) << 2))
+-#define SPDIF_CTRL_ADDR                       0x3004c
+-#define SPDIF_CH1_CS_3100_ADDR                0x30050
+-#define SPDIF_CH1_CS_6332_ADDR                0x30054
+-#define SPDIF_CH1_CS_9564_ADDR                0x30058
+-#define SPDIF_CH1_CS_12796_ADDR               0x3005c
+-#define SPDIF_CH1_CS_159128_ADDR      0x30060
+-#define SPDIF_CH1_CS_191160_ADDR      0x30064
+-#define SPDIF_CH2_CS_3100_ADDR                0x30068
+-#define SPDIF_CH2_CS_6332_ADDR                0x3006c
+-#define SPDIF_CH2_CS_9564_ADDR                0x30070
+-#define SPDIF_CH2_CS_12796_ADDR               0x30074
+-#define SPDIF_CH2_CS_159128_ADDR      0x30078
+-#define SPDIF_CH2_CS_191160_ADDR      0x3007c
+-#define SMPL2PKT_CNTL                 0x30080
+-#define SMPL2PKT_CNFG                 0x30084
+-#define FIFO_CNTL                     0x30088
+-#define FIFO_STTS                     0x3008c
+-
+-/* source pif addr */
+-#define SOURCE_PIF_WR_ADDR            0x30800
+-#define SOURCE_PIF_WR_REQ             0x30804
+-#define SOURCE_PIF_RD_ADDR            0x30808
+-#define SOURCE_PIF_RD_REQ             0x3080c
+-#define SOURCE_PIF_DATA_WR            0x30810
+-#define SOURCE_PIF_DATA_RD            0x30814
+-#define SOURCE_PIF_FIFO1_FLUSH                0x30818
+-#define SOURCE_PIF_FIFO2_FLUSH                0x3081c
+-#define SOURCE_PIF_STATUS             0x30820
+-#define SOURCE_PIF_INTERRUPT_SOURCE   0x30824
+-#define SOURCE_PIF_INTERRUPT_MASK     0x30828
+-#define SOURCE_PIF_PKT_ALLOC_REG      0x3082c
+-#define SOURCE_PIF_PKT_ALLOC_WR_EN    0x30830
+-#define SOURCE_PIF_SW_RESET           0x30834
+-
+-/* bellow registers need access by mailbox */
+-/* source car addr */
+-#define SOURCE_HDTX_CAR                       0x0900
+-#define SOURCE_DPTX_CAR                       0x0904
+-#define SOURCE_PHY_CAR                        0x0908
+-#define SOURCE_CEC_CAR                        0x090c
+-#define SOURCE_CBUS_CAR                       0x0910
+-#define SOURCE_PKT_CAR                        0x0918
+-#define SOURCE_AIF_CAR                        0x091c
+-#define SOURCE_CIPHER_CAR             0x0920
+-#define SOURCE_CRYPTO_CAR             0x0924
+-
+-/* clock meters addr */
+-#define CM_CTRL                               0x0a00
+-#define CM_I2S_CTRL                   0x0a04
+-#define CM_SPDIF_CTRL                 0x0a08
+-#define CM_VID_CTRL                   0x0a0c
+-#define CM_LANE_CTRL                  0x0a10
+-#define I2S_NM_STABLE                 0x0a14
+-#define I2S_NCTS_STABLE                       0x0a18
+-#define SPDIF_NM_STABLE                       0x0a1c
+-#define SPDIF_NCTS_STABLE             0x0a20
+-#define NMVID_MEAS_STABLE             0x0a24
+-#define I2S_MEAS                      0x0a40
+-#define SPDIF_MEAS                    0x0a80
+-#define NMVID_MEAS                    0x0ac0
+-
+-/* source vif addr */
+-#define BND_HSYNC2VSYNC                       0x0b00
+-#define HSYNC2VSYNC_F1_L1             0x0b04
+-#define HSYNC2VSYNC_F2_L1             0x0b08
+-#define HSYNC2VSYNC_STATUS            0x0b0c
+-#define HSYNC2VSYNC_POL_CTRL          0x0b10
+-
+-/* dptx phy addr */
+-#define DP_TX_PHY_CONFIG_REG          0x2000
+-#define DP_TX_PHY_SW_RESET            0x2004
+-#define DP_TX_PHY_SCRAMBLER_SEED      0x2008
+-#define DP_TX_PHY_TRAINING_01_04      0x200c
+-#define DP_TX_PHY_TRAINING_05_08      0x2010
+-#define DP_TX_PHY_TRAINING_09_10      0x2014
+-#define TEST_COR                      0x23fc
+-
+-/* dptx hpd addr */
+-#define HPD_IRQ_DET_MIN_TIMER         0x2100
+-#define HPD_IRQ_DET_MAX_TIMER         0x2104
+-#define HPD_UNPLGED_DET_MIN_TIMER     0x2108
+-#define HPD_STABLE_TIMER              0x210c
+-#define HPD_FILTER_TIMER              0x2110
+-#define HPD_EVENT_MASK                        0x211c
+-#define HPD_EVENT_DET                 0x2120
+-
+-/* dpyx framer addr */
+-#define DP_FRAMER_GLOBAL_CONFIG               0x2200
+-#define DP_SW_RESET                   0x2204
+-#define DP_FRAMER_TU                  0x2208
+-#define DP_FRAMER_PXL_REPR            0x220c
+-#define DP_FRAMER_SP                  0x2210
+-#define AUDIO_PACK_CONTROL            0x2214
+-#define DP_VC_TABLE(x)                        (0x2218 + ((x) << 2))
+-#define DP_VB_ID                      0x2258
+-#define DP_MTPH_LVP_CONTROL           0x225c
+-#define DP_MTPH_SYMBOL_VALUES         0x2260
+-#define DP_MTPH_ECF_CONTROL           0x2264
+-#define DP_MTPH_ACT_CONTROL           0x2268
+-#define DP_MTPH_STATUS                        0x226c
+-#define DP_INTERRUPT_SOURCE           0x2270
+-#define DP_INTERRUPT_MASK             0x2274
+-#define DP_FRONT_BACK_PORCH           0x2278
+-#define DP_BYTE_COUNT                 0x227c
+-
+-/* dptx stream addr */
+-#define MSA_HORIZONTAL_0              0x2280
+-#define MSA_HORIZONTAL_1              0x2284
+-#define MSA_VERTICAL_0                        0x2288
+-#define MSA_VERTICAL_1                        0x228c
+-#define MSA_MISC                      0x2290
+-#define STREAM_CONFIG                 0x2294
+-#define AUDIO_PACK_STATUS             0x2298
+-#define VIF_STATUS                    0x229c
+-#define PCK_STUFF_STATUS_0            0x22a0
+-#define PCK_STUFF_STATUS_1            0x22a4
+-#define INFO_PACK_STATUS              0x22a8
+-#define RATE_GOVERNOR_STATUS          0x22ac
+-#define DP_HORIZONTAL                 0x22b0
+-#define DP_VERTICAL_0                 0x22b4
+-#define DP_VERTICAL_1                 0x22b8
+-#define DP_BLOCK_SDP                  0x22bc
+-
+-/* dptx glbl addr */
+-#define DPTX_LANE_EN                  0x2300
+-#define DPTX_ENHNCD                   0x2304
+-#define DPTX_INT_MASK                 0x2308
+-#define DPTX_INT_STATUS                       0x230c
+-
+-/* dp aux addr */
+-#define DP_AUX_HOST_CONTROL           0x2800
+-#define DP_AUX_INTERRUPT_SOURCE               0x2804
+-#define DP_AUX_INTERRUPT_MASK         0x2808
+-#define DP_AUX_SWAP_INVERSION_CONTROL 0x280c
+-#define DP_AUX_SEND_NACK_TRANSACTION  0x2810
+-#define DP_AUX_CLEAR_RX                       0x2814
+-#define DP_AUX_CLEAR_TX                       0x2818
+-#define DP_AUX_TIMER_STOP             0x281c
+-#define DP_AUX_TIMER_CLEAR            0x2820
+-#define DP_AUX_RESET_SW                       0x2824
+-#define DP_AUX_DIVIDE_2M              0x2828
+-#define DP_AUX_TX_PREACHARGE_LENGTH   0x282c
+-#define DP_AUX_FREQUENCY_1M_MAX               0x2830
+-#define DP_AUX_FREQUENCY_1M_MIN               0x2834
+-#define DP_AUX_RX_PRE_MIN             0x2838
+-#define DP_AUX_RX_PRE_MAX             0x283c
+-#define DP_AUX_TIMER_PRESET           0x2840
+-#define DP_AUX_NACK_FORMAT            0x2844
+-#define DP_AUX_TX_DATA                        0x2848
+-#define DP_AUX_RX_DATA                        0x284c
+-#define DP_AUX_TX_STATUS              0x2850
+-#define DP_AUX_RX_STATUS              0x2854
+-#define DP_AUX_RX_CYCLE_COUNTER               0x2858
+-#define DP_AUX_MAIN_STATES            0x285c
+-#define DP_AUX_MAIN_TIMER             0x2860
+-#define DP_AUX_AFE_OUT                        0x2864
+-
+-/* crypto addr */
+-#define CRYPTO_HDCP_REVISION          0x5800
+-#define HDCP_CRYPTO_CONFIG            0x5804
+-#define CRYPTO_INTERRUPT_SOURCE               0x5808
+-#define CRYPTO_INTERRUPT_MASK         0x580c
+-#define CRYPTO22_CONFIG                       0x5818
+-#define CRYPTO22_STATUS                       0x581c
+-#define SHA_256_DATA_IN                       0x583c
+-#define SHA_256_DATA_OUT_(x)          (0x5850 + ((x) << 2))
+-#define AES_32_KEY_(x)                        (0x5870 + ((x) << 2))
+-#define AES_32_DATA_IN                        0x5880
+-#define AES_32_DATA_OUT_(x)           (0x5884 + ((x) << 2))
+-#define CRYPTO14_CONFIG                       0x58a0
+-#define CRYPTO14_STATUS                       0x58a4
+-#define CRYPTO14_PRNM_OUT             0x58a8
+-#define CRYPTO14_KM_0                 0x58ac
+-#define CRYPTO14_KM_1                 0x58b0
+-#define CRYPTO14_AN_0                 0x58b4
+-#define CRYPTO14_AN_1                 0x58b8
+-#define CRYPTO14_YOUR_KSV_0           0x58bc
+-#define CRYPTO14_YOUR_KSV_1           0x58c0
+-#define CRYPTO14_MI_0                 0x58c4
+-#define CRYPTO14_MI_1                 0x58c8
+-#define CRYPTO14_TI_0                 0x58cc
+-#define CRYPTO14_KI_0                 0x58d0
+-#define CRYPTO14_KI_1                 0x58d4
+-#define CRYPTO14_BLOCKS_NUM           0x58d8
+-#define CRYPTO14_KEY_MEM_DATA_0               0x58dc
+-#define CRYPTO14_KEY_MEM_DATA_1               0x58e0
+-#define CRYPTO14_SHA1_MSG_DATA                0x58e4
+-#define CRYPTO14_SHA1_V_VALUE_(x)     (0x58e8 + ((x) << 2))
+-#define TRNG_CTRL                     0x58fc
+-#define TRNG_DATA_RDY                 0x5900
+-#define TRNG_DATA                     0x5904
+-
+-/* cipher addr */
+-#define HDCP_REVISION                 0x60000
+-#define INTERRUPT_SOURCE              0x60004
+-#define INTERRUPT_MASK                        0x60008
+-#define HDCP_CIPHER_CONFIG            0x6000c
+-#define AES_128_KEY_0                 0x60010
+-#define AES_128_KEY_1                 0x60014
+-#define AES_128_KEY_2                 0x60018
+-#define AES_128_KEY_3                 0x6001c
+-#define AES_128_RANDOM_0              0x60020
+-#define AES_128_RANDOM_1              0x60024
+-#define CIPHER14_KM_0                 0x60028
+-#define CIPHER14_KM_1                 0x6002c
+-#define CIPHER14_STATUS                       0x60030
+-#define CIPHER14_RI_PJ_STATUS         0x60034
+-#define CIPHER_MODE                   0x60038
+-#define CIPHER14_AN_0                 0x6003c
+-#define CIPHER14_AN_1                 0x60040
+-#define CIPHER22_AUTH                 0x60044
+-#define CIPHER14_R0_DP_STATUS         0x60048
+-#define CIPHER14_BOOTSTRAP            0x6004c
+-
+-#define DPTX_FRMR_DATA_CLK_RSTN_EN    BIT(11)
+-#define DPTX_FRMR_DATA_CLK_EN         BIT(10)
+-#define DPTX_PHY_DATA_RSTN_EN         BIT(9)
+-#define DPTX_PHY_DATA_CLK_EN          BIT(8)
+-#define DPTX_PHY_CHAR_RSTN_EN         BIT(7)
+-#define DPTX_PHY_CHAR_CLK_EN          BIT(6)
+-#define SOURCE_AUX_SYS_CLK_RSTN_EN    BIT(5)
+-#define SOURCE_AUX_SYS_CLK_EN         BIT(4)
+-#define DPTX_SYS_CLK_RSTN_EN          BIT(3)
+-#define DPTX_SYS_CLK_EN                       BIT(2)
+-#define CFG_DPTX_VIF_CLK_RSTN_EN      BIT(1)
+-#define CFG_DPTX_VIF_CLK_EN           BIT(0)
+-
+-#define SOURCE_PHY_RSTN_EN            BIT(1)
+-#define SOURCE_PHY_CLK_EN             BIT(0)
+-
+-#define SOURCE_PKT_SYS_RSTN_EN                BIT(3)
+-#define SOURCE_PKT_SYS_CLK_EN         BIT(2)
+-#define SOURCE_PKT_DATA_RSTN_EN               BIT(1)
+-#define SOURCE_PKT_DATA_CLK_EN                BIT(0)
+-
+-#define SPDIF_CDR_CLK_RSTN_EN         BIT(5)
+-#define SPDIF_CDR_CLK_EN              BIT(4)
+-#define SOURCE_AIF_SYS_RSTN_EN                BIT(3)
+-#define SOURCE_AIF_SYS_CLK_EN         BIT(2)
+-#define SOURCE_AIF_CLK_RSTN_EN                BIT(1)
+-#define SOURCE_AIF_CLK_EN             BIT(0)
+-
+-#define SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN      BIT(3)
+-#define SOURCE_CIPHER_SYS_CLK_EN              BIT(2)
+-#define SOURCE_CIPHER_CHAR_CLK_RSTN_EN                BIT(1)
+-#define SOURCE_CIPHER_CHAR_CLK_EN             BIT(0)
+-
+-#define SOURCE_CRYPTO_SYS_CLK_RSTN_EN BIT(1)
+-#define SOURCE_CRYPTO_SYS_CLK_EN      BIT(0)
+-
+-#define APB_IRAM_PATH                 BIT(2)
+-#define APB_DRAM_PATH                 BIT(1)
+-#define APB_XT_RESET                  BIT(0)
+-
+-#define MAILBOX_INT_MASK_BIT          BIT(1)
+-#define PIF_INT_MASK_BIT              BIT(0)
+-#define ALL_INT_MASK                  3
+-
+-/* mailbox */
+-#define MB_OPCODE_ID                  0
+-#define MB_MODULE_ID                  1
+-#define MB_SIZE_MSB_ID                        2
+-#define MB_SIZE_LSB_ID                        3
+-#define MB_DATA_ID                    4
+-
+-#define MB_MODULE_ID_DP_TX            0x01
+-#define MB_MODULE_ID_HDCP_TX          0x07
+-#define MB_MODULE_ID_HDCP_RX          0x08
+-#define MB_MODULE_ID_HDCP_GENERAL     0x09
+-#define MB_MODULE_ID_GENERAL          0x0a
+-
+-/* general opcode */
+-#define GENERAL_MAIN_CONTROL            0x01
+-#define GENERAL_TEST_ECHO               0x02
+-#define GENERAL_BUS_SETTINGS            0x03
+-#define GENERAL_TEST_ACCESS             0x04
+-
+-#define DPTX_SET_POWER_MNG                    0x00
+-#define DPTX_SET_HOST_CAPABILITIES            0x01
+-#define DPTX_GET_EDID                         0x02
+-#define DPTX_READ_DPCD                                0x03
+-#define DPTX_WRITE_DPCD                               0x04
+-#define DPTX_ENABLE_EVENT                     0x05
+-#define DPTX_WRITE_REGISTER                   0x06
+-#define DPTX_READ_REGISTER                    0x07
+-#define DPTX_WRITE_FIELD                      0x08
+-#define DPTX_TRAINING_CONTROL                 0x09
+-#define DPTX_READ_EVENT                               0x0a
+-#define DPTX_READ_LINK_STAT                   0x0b
+-#define DPTX_SET_VIDEO                                0x0c
+-#define DPTX_SET_AUDIO                                0x0d
+-#define DPTX_GET_LAST_AUX_STAUS                       0x0e
+-#define DPTX_SET_LINK_BREAK_POINT             0x0f
+-#define DPTX_FORCE_LANES                      0x10
+-#define DPTX_HPD_STATE                                0x11
+-
+-#define FW_STANDBY                            0
+-#define FW_ACTIVE                             1
+-
+-#define DPTX_EVENT_ENABLE_HPD                 BIT(0)
+-#define DPTX_EVENT_ENABLE_TRAINING            BIT(1)
+-
+-#define LINK_TRAINING_NOT_ACTIVE              0
+-#define LINK_TRAINING_RUN                     1
+-#define LINK_TRAINING_RESTART                 2
+-
+-#define CONTROL_VIDEO_IDLE                    0
+-#define CONTROL_VIDEO_VALID                   1
+-
+-#define TU_CNT_RST_EN                         BIT(15)
+-#define VIF_BYPASS_INTERLACE                  BIT(13)
+-#define INTERLACE_FMT_DET                     BIT(12)
+-#define INTERLACE_DTCT_WIN                    0x20
+-
+-#define DP_FRAMER_SP_INTERLACE_EN             BIT(2)
+-#define DP_FRAMER_SP_HSP                      BIT(1)
+-#define DP_FRAMER_SP_VSP                      BIT(0)
+-
+-/* capability */
+-#define AUX_HOST_INVERT                               3
+-#define       FAST_LT_SUPPORT                         1
+-#define FAST_LT_NOT_SUPPORT                   0
+-#define LANE_MAPPING_NORMAL                   0x1b
+-#define LANE_MAPPING_FLIPPED                  0xe4
+-#define ENHANCED                              1
+-#define SCRAMBLER_EN                          BIT(4)
+-
+-#define       FULL_LT_STARTED                         BIT(0)
+-#define FASE_LT_STARTED                               BIT(1)
+-#define CLK_RECOVERY_FINISHED                 BIT(2)
+-#define EQ_PHASE_FINISHED                     BIT(3)
+-#define FASE_LT_START_FINISHED                        BIT(4)
+-#define CLK_RECOVERY_FAILED                   BIT(5)
+-#define EQ_PHASE_FAILED                               BIT(6)
+-#define FASE_LT_FAILED                                BIT(7)
+-
+-#define DPTX_HPD_EVENT                                BIT(0)
+-#define DPTX_TRAINING_EVENT                   BIT(1)
+-#define HDCP_TX_STATUS_EVENT                  BIT(4)
+-#define HDCP2_TX_IS_KM_STORED_EVENT           BIT(5)
+-#define HDCP2_TX_STORE_KM_EVENT                       BIT(6)
+-#define HDCP_TX_IS_RECEIVER_ID_VALID_EVENT    BIT(7)
+-
+-#define TU_SIZE                                       30
+-#define CDNS_DP_MAX_LINK_RATE                 DP_LINK_BW_5_4
+-
+-/* audio */
+-#define AUDIO_PACK_EN                         BIT(8)
+-#define SAMPLING_FREQ(x)                      (((x) & 0xf) << 16)
+-#define ORIGINAL_SAMP_FREQ(x)                 (((x) & 0xf) << 24)
+-#define SYNC_WR_TO_CH_ZERO                    BIT(1)
+-#define I2S_DEC_START                         BIT(1)
+-#define AUDIO_SW_RST                          BIT(0)
+-#define SMPL2PKT_EN                           BIT(1)
+-#define MAX_NUM_CH(x)                         (((x) & 0x1f) - 1)
+-#define NUM_OF_I2S_PORTS(x)                   ((((x) / 2 - 1) & 0x3) << 5)
+-#define AUDIO_TYPE_LPCM                               (2 << 7)
+-#define CFG_SUB_PCKT_NUM(x)                   ((((x) - 1) & 0x7) << 11)
+-#define AUDIO_CH_NUM(x)                               ((((x) - 1) & 0x1f) << 2)
+-#define TRANS_SMPL_WIDTH_16                   0
+-#define TRANS_SMPL_WIDTH_24                   BIT(11)
+-#define TRANS_SMPL_WIDTH_32                   (2 << 11)
+-#define I2S_DEC_PORT_EN(x)                    (((x) & 0xf) << 17)
+-#define SPDIF_ENABLE                          BIT(21)
+-#define SPDIF_AVG_SEL                         BIT(20)
+-#define SPDIF_JITTER_BYPASS                   BIT(19)
+-#define SPDIF_FIFO_MID_RANGE(x)                       (((x) & 0xff) << 11)
+-#define SPDIF_JITTER_THRSH(x)                 (((x) & 0xff) << 3)
+-#define SPDIF_JITTER_AVG_WIN(x)                       ((x) & 0x7)
+-
+-/* Reference cycles when using lane clock as reference */
+-#define LANE_REF_CYC                          0x8000
+-
+-enum voltage_swing_level {
+-      VOLTAGE_LEVEL_0,
+-      VOLTAGE_LEVEL_1,
+-      VOLTAGE_LEVEL_2,
+-      VOLTAGE_LEVEL_3,
+-};
+-
+-enum pre_emphasis_level {
+-      PRE_EMPHASIS_LEVEL_0,
+-      PRE_EMPHASIS_LEVEL_1,
+-      PRE_EMPHASIS_LEVEL_2,
+-      PRE_EMPHASIS_LEVEL_3,
+-};
+-
+-enum pattern_set {
+-      PTS1            = BIT(0),
+-      PTS2            = BIT(1),
+-      PTS3            = BIT(2),
+-      PTS4            = BIT(3),
+-      DP_NONE         = BIT(4)
+-};
+-
+-enum vic_color_depth {
+-      BCS_6 = 0x1,
+-      BCS_8 = 0x2,
+-      BCS_10 = 0x4,
+-      BCS_12 = 0x8,
+-      BCS_16 = 0x10,
+-};
+-
+-enum vic_bt_type {
+-      BT_601 = 0x0,
+-      BT_709 = 0x1,
+-};
+-
+-enum audio_format {
+-      AFMT_I2S = 0,
+-      AFMT_SPDIF = 1,
+-      AFMT_UNUSED,
+-};
+-
+-struct audio_info {
+-      enum audio_format format;
+-      int sample_rate;
+-      int channels;
+-      int sample_width;
+-};
+-
+-enum vic_pxl_encoding_format {
+-      PXL_RGB = 0x1,
+-      YCBCR_4_4_4 = 0x2,
+-      YCBCR_4_2_2 = 0x4,
+-      YCBCR_4_2_0 = 0x8,
+-      Y_ONLY = 0x10,
+-};
+-
+-struct video_info {
+-      bool h_sync_polarity;
+-      bool v_sync_polarity;
+-      bool interlaced;
+-      int color_depth;
+-      enum vic_pxl_encoding_format color_fmt;
+-};
+-
+-struct cdns_mhdp_host {
+-      unsigned int    link_rate;
+-      u8      lanes_cnt;
+-      u8      volt_swing;
+-      u8      pre_emphasis;
+-      u8      pattern_supp;
+-      u8      fast_link;
+-      u8      lane_mapping;
+-      u8      enhanced;
+-};
+-
+-struct cdns_mhdp_sink {
+-      unsigned int    link_rate;
+-      u8      lanes_cnt;
+-      u8      pattern_supp;
+-      u8      fast_link;
+-      u8      enhanced;
+-};
+-
+-struct cdns_mhdp_device {
+-      void __iomem            *regs;
+-
+-      struct device           *dev;
+-
+-      struct drm_dp_link      link;
+-      struct drm_connector    connector;
+-      struct clk              *spdif_clk;
+-      struct reset_control    *spdif_rst;
+-
+-      struct drm_dp_aux       aux;
+-      struct cdns_mhdp_host   host;
+-      struct cdns_mhdp_sink   sink;
+-      struct drm_bridge       bridge;
+-      struct phy              *phy;
+-      void __iomem            *dbg_regs;
+-
+-      struct video_info       video_info;
+-      struct drm_display_mode mode;
+-      unsigned int            fw_version;
+-};
+-
+-void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp);
+-void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk);
+-int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
+-                          u32 i_size, const u32 *d_mem, u32 d_size);
+-int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable);
+-int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, u8 lanes, bool flip);
+-int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp);
+-u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp);
+-int cdns_mhdp_get_hpd_status(struct cdns_mhdp_device *mhdp);
+-int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value);
+-int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,
+-                      u32 addr, u8 *data, u16 len);
+-int cdns_mhdp_get_edid_block(void *mhdp, u8 *edid,
+-                           unsigned int block, size_t length);
+-int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp);
+-int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active);
+-int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp);
+-int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
+-                       struct audio_info *audio);
+-int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable);
+-int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
+-                         struct audio_info *audio);
+-#endif /* _CDN_DP_REG_H */
+--- /dev/null
++++ b/include/drm/bridge/cdns-mhdp-cbs.h
+@@ -0,0 +1,29 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Cadence MHDP DP bridge callbacks.
++ *
++ * Copyright: 2018 Cadence Design Systems, Inc.
++ *
++ * Author: Piotr Sroka <piotrs@cadence.com>
++ */
++
++#ifndef CDNS_MHDP_CBS_H
++#define CDNS_MHDP_CBS_H
++
++#include <drm/drm_bridge.h>
++
++struct cdns_mhdp_mst_cbs_funcs {
++      struct drm_encoder *(*create_mst_encoder)(void *priv_data,
++                                                struct drm_bridge *bridge);
++      void (*destroy_mst_encoder)(void *priv_data, struct drm_bridge *bridge);
++};
++
++struct cdns_mhdp_mst_cbs {
++      struct cdns_mhdp_mst_cbs_funcs funcs;
++      void *priv_data;
++};
++
++int mhdp_bridge_attach_mst_cbs(struct drm_bridge *bridge,
++                             struct cdns_mhdp_mst_cbs *cbs);
++
++#endif
+--- /dev/null
++++ b/include/drm/bridge/cdns-mhdp-common.h
+@@ -0,0 +1,704 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
++ * Author: Chris Zhong <zyw@rock-chips.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef CDNS_MHDP_COMMON_H_
++#define CDNS_MHDP_COMMON_H_
++
++#include <drm/bridge/cdns-mhdp-cbs.h>
++#include <drm/drm_bridge.h>
++#include <drm/drm_connector.h>
++#include <drm/drm_dp_helper.h>
++#include <drm/drm_dp_mst_helper.h>
++
++#include <linux/bitops.h>
++
++#define ADDR_IMEM             0x10000
++#define ADDR_DMEM             0x20000
++#define ADDR_PHY_AFE  0x80000
++
++/* APB CFG addr */
++#define APB_CTRL                      0
++#define XT_INT_CTRL                   0x04
++#define MAILBOX_FULL_ADDR             0x08
++#define MAILBOX_EMPTY_ADDR            0x0c
++#define MAILBOX0_WR_DATA              0x10
++#define MAILBOX0_RD_DATA              0x14
++#define KEEP_ALIVE                    0x18
++#define VER_L                         0x1c
++#define VER_H                         0x20
++#define VER_LIB_L_ADDR                        0x24
++#define VER_LIB_H_ADDR                        0x28
++#define SW_DEBUG_L                    0x2c
++#define SW_DEBUG_H                    0x30
++#define MAILBOX_INT_MASK              0x34
++#define MAILBOX_INT_STATUS            0x38
++#define SW_CLK_L                      0x3c
++#define SW_CLK_H                      0x40
++#define SW_EVENTS0                    0x44
++#define SW_EVENTS1                    0x48
++#define SW_EVENTS2                    0x4c
++#define SW_EVENTS3                    0x50
++#define XT_OCD_CTRL                   0x60
++#define APB_INT_MASK                  0x6c
++#define APB_STATUS_MASK                       0x70
++
++/* audio decoder addr */
++#define AUDIO_SRC_CNTL                        0x30000
++#define AUDIO_SRC_CNFG                        0x30004
++#define COM_CH_STTS_BITS              0x30008
++#define STTS_BIT_CH(x)                        (0x3000c + ((x) << 2))
++#define SPDIF_CTRL_ADDR                       0x3004c
++#define SPDIF_CH1_CS_3100_ADDR                0x30050
++#define SPDIF_CH1_CS_6332_ADDR                0x30054
++#define SPDIF_CH1_CS_9564_ADDR                0x30058
++#define SPDIF_CH1_CS_12796_ADDR               0x3005c
++#define SPDIF_CH1_CS_159128_ADDR      0x30060
++#define SPDIF_CH1_CS_191160_ADDR      0x30064
++#define SPDIF_CH2_CS_3100_ADDR                0x30068
++#define SPDIF_CH2_CS_6332_ADDR                0x3006c
++#define SPDIF_CH2_CS_9564_ADDR                0x30070
++#define SPDIF_CH2_CS_12796_ADDR               0x30074
++#define SPDIF_CH2_CS_159128_ADDR      0x30078
++#define SPDIF_CH2_CS_191160_ADDR      0x3007c
++#define SMPL2PKT_CNTL                 0x30080
++#define SMPL2PKT_CNFG                 0x30084
++#define FIFO_CNTL                     0x30088
++#define FIFO_STTS                     0x3008c
++
++/* source pif addr */
++#define SOURCE_PIF_WR_ADDR            0x30800
++#define SOURCE_PIF_WR_REQ             0x30804
++#define SOURCE_PIF_RD_ADDR            0x30808
++#define SOURCE_PIF_RD_REQ             0x3080c
++#define SOURCE_PIF_DATA_WR            0x30810
++#define SOURCE_PIF_DATA_RD            0x30814
++#define SOURCE_PIF_FIFO1_FLUSH                0x30818
++#define SOURCE_PIF_FIFO2_FLUSH                0x3081c
++#define SOURCE_PIF_STATUS             0x30820
++#define SOURCE_PIF_INTERRUPT_SOURCE   0x30824
++#define SOURCE_PIF_INTERRUPT_MASK     0x30828
++#define SOURCE_PIF_PKT_ALLOC_REG      0x3082c
++#define SOURCE_PIF_PKT_ALLOC_WR_EN    0x30830
++#define SOURCE_PIF_SW_RESET           0x30834
++
++/* bellow registers need access by mailbox */
++/* source phy comp */
++#define PHY_DATA_SEL                  0x0818
++#define LANES_CONFIG                  0x0814
++
++/* source car addr */
++#define SOURCE_HDTX_CAR                       0x0900
++#define SOURCE_DPTX_CAR                       0x0904
++#define SOURCE_PHY_CAR                        0x0908
++#define SOURCE_CEC_CAR                        0x090c
++#define SOURCE_CBUS_CAR                       0x0910
++#define SOURCE_PKT_CAR                        0x0918
++#define SOURCE_AIF_CAR                        0x091c
++#define SOURCE_CIPHER_CAR             0x0920
++#define SOURCE_CRYPTO_CAR             0x0924
++
++/* mhdp tx_top_comp */
++#define SCHEDULER_H_SIZE              0x1000
++#define SCHEDULER_V_SIZE              0x1004
++#define HDTX_SIGNAL_FRONT_WIDTH       0x100c
++#define HDTX_SIGNAL_SYNC_WIDTH        0x1010
++#define HDTX_SIGNAL_BACK_WIDTH        0x1014
++#define HDTX_CONTROLLER                       0x1018
++#define HDTX_HPD                              0x1020
++#define HDTX_CLOCK_REG_0              0x1024
++#define HDTX_CLOCK_REG_1              0x1028
++
++/* clock meters addr */
++#define CM_CTRL                               0x0a00
++#define CM_I2S_CTRL                   0x0a04
++#define CM_SPDIF_CTRL                 0x0a08
++#define CM_VID_CTRL                   0x0a0c
++#define CM_LANE_CTRL                  0x0a10
++#define I2S_NM_STABLE                 0x0a14
++#define I2S_NCTS_STABLE                       0x0a18
++#define SPDIF_NM_STABLE                       0x0a1c
++#define SPDIF_NCTS_STABLE             0x0a20
++#define NMVID_MEAS_STABLE             0x0a24
++#define I2S_MEAS                      0x0a40
++#define SPDIF_MEAS                    0x0a80
++#define NMVID_MEAS                    0x0ac0
++
++/* source vif addr */
++#define BND_HSYNC2VSYNC                       0x0b00
++#define HSYNC2VSYNC_F1_L1             0x0b04
++#define HSYNC2VSYNC_F2_L1             0x0b08
++#define HSYNC2VSYNC_STATUS            0x0b0c
++#define HSYNC2VSYNC_POL_CTRL          0x0b10
++
++/* dptx phy addr */
++#define DP_TX_PHY_CONFIG_REG          0x2000
++#define DP_TX_PHY_SW_RESET            0x2004
++#define DP_TX_PHY_SCRAMBLER_SEED      0x2008
++#define DP_TX_PHY_TRAINING_01_04      0x200c
++#define DP_TX_PHY_TRAINING_05_08      0x2010
++#define DP_TX_PHY_TRAINING_09_10      0x2014
++#define TEST_COR                      0x23fc
++
++/* dptx hpd addr */
++#define HPD_IRQ_DET_MIN_TIMER         0x2100
++#define HPD_IRQ_DET_MAX_TIMER         0x2104
++#define HPD_UNPLGED_DET_MIN_TIMER     0x2108
++#define HPD_STABLE_TIMER              0x210c
++#define HPD_FILTER_TIMER              0x2110
++#define HPD_EVENT_MASK                        0x211c
++#define HPD_EVENT_DET                 0x2120
++
++/* dpyx framer addr */
++#define DP_FRAMER_GLOBAL_CONFIG               0x2200
++#define DP_SW_RESET                   0x2204
++#define DP_FRAMER_TU                  0x2208
++#define DP_FRAMER_PXL_REPR            0x220c
++#define DP_FRAMER_SP                  0x2210
++#define AUDIO_PACK_CONTROL            0x2214
++#define DP_VC_TABLE(x)                        (0x2218 + ((x) << 2))
++#define DP_VB_ID                      0x2258
++#define DP_MTPH_LVP_CONTROL           0x225c
++#define DP_MTPH_SYMBOL_VALUES         0x2260
++#define DP_MTPH_ECF_CONTROL           0x2264
++#define DP_MTPH_ACT_CONTROL           0x2268
++#define DP_MTPH_STATUS                        0x226c
++#define DP_INTERRUPT_SOURCE           0x2270
++#define DP_INTERRUPT_MASK             0x2274
++#define DP_FRONT_BACK_PORCH           0x2278
++#define DP_BYTE_COUNT                 0x227c
++
++/* dptx stream addr */
++#define MSA_HORIZONTAL_0              0x2280
++#define MSA_HORIZONTAL_1              0x2284
++#define MSA_VERTICAL_0                        0x2288
++#define MSA_VERTICAL_1                        0x228c
++#define MSA_MISC                      0x2290
++#define STREAM_CONFIG                 0x2294
++#define AUDIO_PACK_STATUS             0x2298
++#define VIF_STATUS                    0x229c
++#define PCK_STUFF_STATUS_0            0x22a0
++#define PCK_STUFF_STATUS_1            0x22a4
++#define INFO_PACK_STATUS              0x22a8
++#define RATE_GOVERNOR_STATUS          0x22ac
++#define DP_HORIZONTAL                 0x22b0
++#define DP_VERTICAL_0                 0x22b4
++#define DP_VERTICAL_1                 0x22b8
++#define DP_BLOCK_SDP                  0x22bc
++
++/* dptx glbl addr */
++#define DPTX_LANE_EN                  0x2300
++#define DPTX_ENHNCD                   0x2304
++#define DPTX_INT_MASK                 0x2308
++#define DPTX_INT_STATUS                       0x230c
++
++/* dp aux addr */
++#define DP_AUX_HOST_CONTROL           0x2800
++#define DP_AUX_INTERRUPT_SOURCE               0x2804
++#define DP_AUX_INTERRUPT_MASK         0x2808
++#define DP_AUX_SWAP_INVERSION_CONTROL 0x280c
++#define DP_AUX_SEND_NACK_TRANSACTION  0x2810
++#define DP_AUX_CLEAR_RX                       0x2814
++#define DP_AUX_CLEAR_TX                       0x2818
++#define DP_AUX_TIMER_STOP             0x281c
++#define DP_AUX_TIMER_CLEAR            0x2820
++#define DP_AUX_RESET_SW                       0x2824
++#define DP_AUX_DIVIDE_2M              0x2828
++#define DP_AUX_TX_PREACHARGE_LENGTH   0x282c
++#define DP_AUX_FREQUENCY_1M_MAX               0x2830
++#define DP_AUX_FREQUENCY_1M_MIN               0x2834
++#define DP_AUX_RX_PRE_MIN             0x2838
++#define DP_AUX_RX_PRE_MAX             0x283c
++#define DP_AUX_TIMER_PRESET           0x2840
++#define DP_AUX_NACK_FORMAT            0x2844
++#define DP_AUX_TX_DATA                        0x2848
++#define DP_AUX_RX_DATA                        0x284c
++#define DP_AUX_TX_STATUS              0x2850
++#define DP_AUX_RX_STATUS              0x2854
++#define DP_AUX_RX_CYCLE_COUNTER               0x2858
++#define DP_AUX_MAIN_STATES            0x285c
++#define DP_AUX_MAIN_TIMER             0x2860
++#define DP_AUX_AFE_OUT                        0x2864
++
++/* crypto addr */
++#define CRYPTO_HDCP_REVISION          0x5800
++#define HDCP_CRYPTO_CONFIG            0x5804
++#define CRYPTO_INTERRUPT_SOURCE               0x5808
++#define CRYPTO_INTERRUPT_MASK         0x580c
++#define CRYPTO22_CONFIG                       0x5818
++#define CRYPTO22_STATUS                       0x581c
++#define SHA_256_DATA_IN                       0x583c
++#define SHA_256_DATA_OUT_(x)          (0x5850 + ((x) << 2))
++#define AES_32_KEY_(x)                        (0x5870 + ((x) << 2))
++#define AES_32_DATA_IN                        0x5880
++#define AES_32_DATA_OUT_(x)           (0x5884 + ((x) << 2))
++#define CRYPTO14_CONFIG                       0x58a0
++#define CRYPTO14_STATUS                       0x58a4
++#define CRYPTO14_PRNM_OUT             0x58a8
++#define CRYPTO14_KM_0                 0x58ac
++#define CRYPTO14_KM_1                 0x58b0
++#define CRYPTO14_AN_0                 0x58b4
++#define CRYPTO14_AN_1                 0x58b8
++#define CRYPTO14_YOUR_KSV_0           0x58bc
++#define CRYPTO14_YOUR_KSV_1           0x58c0
++#define CRYPTO14_MI_0                 0x58c4
++#define CRYPTO14_MI_1                 0x58c8
++#define CRYPTO14_TI_0                 0x58cc
++#define CRYPTO14_KI_0                 0x58d0
++#define CRYPTO14_KI_1                 0x58d4
++#define CRYPTO14_BLOCKS_NUM           0x58d8
++#define CRYPTO14_KEY_MEM_DATA_0               0x58dc
++#define CRYPTO14_KEY_MEM_DATA_1               0x58e0
++#define CRYPTO14_SHA1_MSG_DATA                0x58e4
++#define CRYPTO14_SHA1_V_VALUE_(x)     (0x58e8 + ((x) << 2))
++#define TRNG_CTRL                     0x58fc
++#define TRNG_DATA_RDY                 0x5900
++#define TRNG_DATA                     0x5904
++
++/* cipher addr */
++#define HDCP_REVISION                 0x60000
++#define INTERRUPT_SOURCE              0x60004
++#define INTERRUPT_MASK                        0x60008
++#define HDCP_CIPHER_CONFIG            0x6000c
++#define AES_128_KEY_0                 0x60010
++#define AES_128_KEY_1                 0x60014
++#define AES_128_KEY_2                 0x60018
++#define AES_128_KEY_3                 0x6001c
++#define AES_128_RANDOM_0              0x60020
++#define AES_128_RANDOM_1              0x60024
++#define CIPHER14_KM_0                 0x60028
++#define CIPHER14_KM_1                 0x6002c
++#define CIPHER14_STATUS                       0x60030
++#define CIPHER14_RI_PJ_STATUS         0x60034
++#define CIPHER_MODE                   0x60038
++#define CIPHER14_AN_0                 0x6003c
++#define CIPHER14_AN_1                 0x60040
++#define CIPHER22_AUTH                 0x60044
++#define CIPHER14_R0_DP_STATUS         0x60048
++#define CIPHER14_BOOTSTRAP            0x6004c
++
++#define DPTX_FRMR_DATA_CLK_RSTN_EN    BIT(11)
++#define DPTX_FRMR_DATA_CLK_EN         BIT(10)
++#define DPTX_PHY_DATA_RSTN_EN         BIT(9)
++#define DPTX_PHY_DATA_CLK_EN          BIT(8)
++#define DPTX_PHY_CHAR_RSTN_EN         BIT(7)
++#define DPTX_PHY_CHAR_CLK_EN          BIT(6)
++#define SOURCE_AUX_SYS_CLK_RSTN_EN    BIT(5)
++#define SOURCE_AUX_SYS_CLK_EN         BIT(4)
++#define DPTX_SYS_CLK_RSTN_EN          BIT(3)
++#define DPTX_SYS_CLK_EN                       BIT(2)
++#define CFG_DPTX_VIF_CLK_RSTN_EN      BIT(1)
++#define CFG_DPTX_VIF_CLK_EN           BIT(0)
++
++#define SOURCE_PHY_RSTN_EN            BIT(1)
++#define SOURCE_PHY_CLK_EN             BIT(0)
++
++#define SOURCE_PKT_SYS_RSTN_EN                BIT(3)
++#define SOURCE_PKT_SYS_CLK_EN         BIT(2)
++#define SOURCE_PKT_DATA_RSTN_EN               BIT(1)
++#define SOURCE_PKT_DATA_CLK_EN                BIT(0)
++
++#define SPDIF_CDR_CLK_RSTN_EN         BIT(5)
++#define SPDIF_CDR_CLK_EN              BIT(4)
++#define SOURCE_AIF_SYS_RSTN_EN                BIT(3)
++#define SOURCE_AIF_SYS_CLK_EN         BIT(2)
++#define SOURCE_AIF_CLK_RSTN_EN                BIT(1)
++#define SOURCE_AIF_CLK_EN             BIT(0)
++
++#define SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN      BIT(3)
++#define SOURCE_CIPHER_SYS_CLK_EN              BIT(2)
++#define SOURCE_CIPHER_CHAR_CLK_RSTN_EN                BIT(1)
++#define SOURCE_CIPHER_CHAR_CLK_EN             BIT(0)
++
++#define SOURCE_CRYPTO_SYS_CLK_RSTN_EN BIT(1)
++#define SOURCE_CRYPTO_SYS_CLK_EN      BIT(0)
++
++#define APB_IRAM_PATH                 BIT(2)
++#define APB_DRAM_PATH                 BIT(1)
++#define APB_XT_RESET                  BIT(0)
++
++#define MAILBOX_INT_MASK_BIT          BIT(1)
++#define PIF_INT_MASK_BIT              BIT(0)
++#define ALL_INT_MASK                  3
++
++/* mailbox */
++#define MB_OPCODE_ID                  0
++#define MB_MODULE_ID                  1
++#define MB_SIZE_MSB_ID                        2
++#define MB_SIZE_LSB_ID                        3
++#define MB_DATA_ID                    4
++
++#define MB_MODULE_ID_DP_TX                    0x01
++#define MB_MODULE_ID_HDMI_TX          0x03
++#define MB_MODULE_ID_HDCP_TX          0x07
++#define MB_MODULE_ID_HDCP_RX          0x08
++#define MB_MODULE_ID_HDCP_GENERAL     0x09
++#define MB_MODULE_ID_GENERAL          0x0A
++
++/* general opcode */
++#define GENERAL_MAIN_CONTROL            0x01
++#define GENERAL_TEST_ECHO               0x02
++#define GENERAL_BUS_SETTINGS            0x03
++#define GENERAL_TEST_ACCESS             0x04
++#define GENERAL_WRITE_REGISTER          0x05
++#define GENERAL_WRITE_FIELD             0x06
++#define GENERAL_READ_REGISTER           0x07
++#define GENERAL_GET_HPD_STATE           0x11
++
++/* DPTX opcode */
++#define DPTX_SET_POWER_MNG                    0x00
++#define DPTX_SET_HOST_CAPABILITIES            0x01
++#define DPTX_GET_EDID                         0x02
++#define DPTX_READ_DPCD                                0x03
++#define DPTX_WRITE_DPCD                               0x04
++#define DPTX_ENABLE_EVENT                     0x05
++#define DPTX_WRITE_REGISTER                   0x06
++#define DPTX_READ_REGISTER                    0x07
++#define DPTX_WRITE_FIELD                      0x08
++#define DPTX_TRAINING_CONTROL                 0x09
++#define DPTX_READ_EVENT                               0x0a
++#define DPTX_READ_LINK_STAT                   0x0b
++#define DPTX_SET_VIDEO                                0x0c
++#define DPTX_SET_AUDIO                                0x0d
++#define DPTX_GET_LAST_AUX_STAUS                       0x0e
++#define DPTX_SET_LINK_BREAK_POINT             0x0f
++#define DPTX_FORCE_LANES                      0x10
++#define DPTX_HPD_STATE                                0x11
++#define DPTX_ADJUST_LT                                0x12
++
++/* HDMI TX opcode */
++#define HDMI_TX_READ                          0x00
++#define HDMI_TX_WRITE                         0x01
++#define HDMI_TX_UPDATE_READ                   0x02
++#define HDMI_TX_EDID                          0x03
++#define HDMI_TX_EVENTS                                0x04
++#define HDMI_TX_HPD_STATUS                    0x05
++#define HDMI_TX_DEBUG_ECHO                    0xAA
++#define HDMI_TX_TEST                          0xBB
++#define HDMI_TX_EDID_INTERNAL         0xF0
++
++#define FW_STANDBY                            0
++#define FW_ACTIVE                             1
++
++#define DPTX_EVENT_ENABLE_HPD                 BIT(0)
++#define DPTX_EVENT_ENABLE_TRAINING            BIT(1)
++
++#define LINK_TRAINING_NOT_ACTIVE              0
++#define LINK_TRAINING_RUN                     1
++#define LINK_TRAINING_RESTART                 2
++
++#define CONTROL_VIDEO_IDLE                    0
++#define CONTROL_VIDEO_VALID                   1
++
++#define TU_CNT_RST_EN                         BIT(15)
++#define VIF_BYPASS_INTERLACE                  BIT(13)
++#define INTERLACE_FMT_DET                     BIT(12)
++#define INTERLACE_DTCT_WIN                    0x20
++
++#define DP_FRAMER_SP_INTERLACE_EN             BIT(2)
++#define DP_FRAMER_SP_HSP                      BIT(1)
++#define DP_FRAMER_SP_VSP                      BIT(0)
++
++/* capability */
++#define AUX_HOST_INVERT                               3
++#define       FAST_LT_SUPPORT                         1
++#define FAST_LT_NOT_SUPPORT                   0
++#define LANE_MAPPING_NORMAL                   0x1b
++#define LANE_MAPPING_FLIPPED                  0xe4
++#define ENHANCED                              1
++#define SCRAMBLER_EN                          BIT(4)
++
++#define       FULL_LT_STARTED                         BIT(0)
++#define FASE_LT_STARTED                               BIT(1)
++#define CLK_RECOVERY_FINISHED                 BIT(2)
++#define EQ_PHASE_FINISHED                     BIT(3)
++#define FASE_LT_START_FINISHED                        BIT(4)
++#define CLK_RECOVERY_FAILED                   BIT(5)
++#define EQ_PHASE_FAILED                               BIT(6)
++#define FASE_LT_FAILED                                BIT(7)
++
++#define DPTX_HPD_EVENT                                BIT(0)
++#define DPTX_TRAINING_EVENT                   BIT(1)
++#define HDCP_TX_STATUS_EVENT                  BIT(4)
++#define HDCP2_TX_IS_KM_STORED_EVENT           BIT(5)
++#define HDCP2_TX_STORE_KM_EVENT                       BIT(6)
++#define HDCP_TX_IS_RECEIVER_ID_VALID_EVENT    BIT(7)
++
++#define TU_SIZE                                       30
++#define CDNS_DP_MAX_LINK_RATE                 DP_LINK_BW_5_4
++
++#define F_HDMI_ENCODING(x) (((x) & ((1 << 2) - 1)) << 16)
++#define F_VIF_DATA_WIDTH(x) (((x) & ((1 << 2) - 1)) << 2)
++#define F_HDMI_MODE(x) (((x) & ((1 << 2) - 1)) << 0)
++#define F_GCP_EN(x) (((x) & ((1 << 1) - 1)) << 12)
++#define F_DATA_EN(x) (((x) & ((1 << 1) - 1)) << 15)
++#define F_HDMI2_PREAMBLE_EN(x) (((x) & ((1 << 1) - 1)) << 18)
++#define F_PIC_3D(x) (((x) & ((1 << 4) - 1)) << 7)
++#define F_BCH_EN(x) (((x) & ((1 << 1) - 1)) << 11)
++#define F_SOURCE_PHY_MHDP_SEL(x) (((x) & ((1 << 2) - 1)) << 3)
++#define F_HPD_VALID_WIDTH(x) (((x) & ((1 << 12) - 1)) << 0)
++#define F_HPD_GLITCH_WIDTH(x) (((x) & ((1 << 8) - 1)) << 12)
++#define F_HDMI2_CTRL_IL_MODE(x) (((x) & ((1 << 1) - 1)) << 19)
++#define F_SOURCE_PHY_LANE0_SWAP(x) (((x) & ((1 << 2) - 1)) << 0)
++#define F_SOURCE_PHY_LANE1_SWAP(x) (((x) & ((1 << 2) - 1)) << 2)
++#define F_SOURCE_PHY_LANE2_SWAP(x) (((x) & ((1 << 2) - 1)) << 4)
++#define F_SOURCE_PHY_LANE3_SWAP(x) (((x) & ((1 << 2) - 1)) << 6)
++#define F_SOURCE_PHY_COMB_BYPASS(x) (((x) & ((1 << 1) - 1)) << 21)
++#define F_SOURCE_PHY_20_10(x) (((x) & ((1 << 1) - 1)) << 22)
++#define F_PKT_ALLOC_ADDRESS(x) (((x) & ((1 << 4) - 1)) << 0)
++#define F_ACTIVE_IDLE_TYPE(x) (((x) & ((1 << 1) - 1)) << 17)
++#define F_FIFO1_FLUSH(x) (((x) & ((1 << 1) - 1)) << 0)
++#define F_PKT_ALLOC_WR_EN(x) (((x) & ((1 << 1) - 1)) << 0)
++#define F_DATA_WR(x) (x)
++#define F_WR_ADDR(x) (((x) & ((1 << 4) - 1)) << 0)
++#define F_HOST_WR(x) (((x) & ((1 << 1) - 1)) << 0)
++#define F_TYPE_VALID(x) (((x) & ((1 << 1) - 1)) << 16)
++#define F_PACKET_TYPE(x) (((x) & ((1 << 8) - 1)) << 8)
++
++/* audio */
++#define AUDIO_PACK_EN                         BIT(8)
++#define SAMPLING_FREQ(x)                      (((x) & 0xf) << 16)
++#define ORIGINAL_SAMP_FREQ(x)                 (((x) & 0xf) << 24)
++#define SYNC_WR_TO_CH_ZERO                    BIT(1)
++#define I2S_DEC_START                         BIT(1)
++#define AUDIO_SW_RST                          BIT(0)
++#define SMPL2PKT_EN                           BIT(1)
++#define MAX_NUM_CH(x)                         (((x) & 0x1f) - 1)
++#define NUM_OF_I2S_PORTS(x)                   ((((x) / 2 - 1) & 0x3) << 5)
++#define AUDIO_TYPE_LPCM                               (2 << 7)
++#define CFG_SUB_PCKT_NUM(x)                   ((((x) - 1) & 0x7) << 11)
++#define AUDIO_CH_NUM(x)                               ((((x) - 1) & 0x1f) << 2)
++#define TRANS_SMPL_WIDTH_16                   0
++#define TRANS_SMPL_WIDTH_24                   BIT(11)
++#define TRANS_SMPL_WIDTH_32                   (2 << 11)
++#define I2S_DEC_PORT_EN(x)                    (((x) & 0xf) << 17)
++#define SPDIF_ENABLE                          BIT(21)
++#define SPDIF_AVG_SEL                         BIT(20)
++#define SPDIF_JITTER_BYPASS                   BIT(19)
++#define SPDIF_FIFO_MID_RANGE(x)                       (((x) & 0xff) << 11)
++#define SPDIF_JITTER_THRSH(x)                 (((x) & 0xff) << 3)
++#define SPDIF_JITTER_AVG_WIN(x)                       ((x) & 0x7)
++
++/* Reference cycles when using lane clock as reference */
++#define LANE_REF_CYC                          0x8000
++
++#define HOTPLUG_DEBOUNCE_MS           200
++
++enum voltage_swing_level {
++      VOLTAGE_LEVEL_0,
++      VOLTAGE_LEVEL_1,
++      VOLTAGE_LEVEL_2,
++      VOLTAGE_LEVEL_3,
++};
++
++enum pre_emphasis_level {
++      PRE_EMPHASIS_LEVEL_0,
++      PRE_EMPHASIS_LEVEL_1,
++      PRE_EMPHASIS_LEVEL_2,
++      PRE_EMPHASIS_LEVEL_3,
++};
++
++enum pattern_set {
++      PTS1            = BIT(0),
++      PTS2            = BIT(1),
++      PTS3            = BIT(2),
++      PTS4            = BIT(3),
++      DP_NONE         = BIT(4)
++};
++
++enum vic_color_depth {
++      BCS_6 = 0x1,
++      BCS_8 = 0x2,
++      BCS_10 = 0x4,
++      BCS_12 = 0x8,
++      BCS_16 = 0x10,
++};
++
++enum vic_bt_type {
++      BT_601 = 0x0,
++      BT_709 = 0x1,
++};
++
++enum audio_format {
++      AFMT_I2S = 0,
++      AFMT_SPDIF = 1,
++      AFMT_UNUSED,
++};
++
++enum {
++      MODE_DVI,
++      MODE_HDMI_1_4,
++      MODE_HDMI_2_0,
++};
++
++struct audio_info {
++      enum audio_format format;
++      int sample_rate;
++      int channels;
++      int sample_width;
++};
++
++enum vic_pxl_encoding_format {
++      PXL_RGB = 0x1,
++      YCBCR_4_4_4 = 0x2,
++      YCBCR_4_2_2 = 0x4,
++      YCBCR_4_2_0 = 0x8,
++      Y_ONLY = 0x10,
++};
++
++struct video_info {
++      bool h_sync_polarity;
++      bool v_sync_polarity;
++      bool interlaced;
++      int color_depth;
++      enum vic_pxl_encoding_format color_fmt;
++};
++
++struct cdns_mhdp_host {
++      unsigned int    link_rate;
++      u8      lanes_cnt;
++      u8      volt_swing;
++      u8      pre_emphasis;
++      u8      pattern_supp;
++      u8      fast_link;
++      u8      lane_mapping;
++      u8      enhanced;
++};
++
++struct cdns_mhdp_sink {
++      unsigned int    link_rate;
++      u8      lanes_cnt;
++      u8      pattern_supp;
++      u8      fast_link;
++      u8      enhanced;
++};
++
++struct cdns_mhdp_bridge;
++struct cdns_mhdp_connector;
++
++struct cdns_mhdp_bridge {
++      struct cdns_mhdp_device *mhdp;
++      struct drm_bridge base;
++      int pbn;
++      int8_t stream_id;
++      struct cdns_mhdp_connector *connector;
++      bool is_active;
++};
++
++struct cdns_mhdp_connector {
++      struct drm_connector base;
++      bool is_mst_connector;
++      struct drm_dp_mst_port *port;
++      struct cdns_mhdp_bridge *bridge;
++};
++
++struct cdns_mhdp_device {
++      void __iomem            *regs;
++
++      struct device           *dev;
++
++      struct cdns_mhdp_connector  connector;
++      struct clk              *spdif_clk;
++      struct reset_control    *spdif_rst;
++
++      struct platform_device  *audio_pdev;
++      struct audio_info       audio_info;
++
++      struct cdns_mhdp_bridge bridge;
++      struct phy              *phy;
++
++      struct video_info       video_info;
++      struct drm_display_mode mode;
++      unsigned int            fw_version;
++
++      struct drm_dp_mst_topology_mgr mst_mgr;
++      struct delayed_work hotplug_work;
++
++      bool link_up;
++      bool power_up;
++      bool plugged;
++
++      union {
++              struct _dp_data {
++                      struct drm_dp_link      link;
++                      struct drm_dp_aux       aux;
++                      struct cdns_mhdp_host   host;
++                      struct cdns_mhdp_sink   sink;
++                      struct cdns_mhdp_mst_cbs cbs;
++                      bool is_mst;
++                      bool can_mst;
++                      u32 lane_mapping;
++                      u32 link_rate;
++                      u32 num_lanes;
++              } dp;
++              struct _hdmi_data {
++                      u32 char_rate;
++                      u32 hdmi_type;
++              } hdmi;
++      };
++};
++
++void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp);
++void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk);
++int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
++                          u32 i_size, const u32 *d_mem, u32 d_size);
++int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable);
++int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, u8 lanes, bool flip);
++int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp);
++u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp);
++int cdns_mhdp_get_hpd_status(struct cdns_mhdp_device *mhdp);
++int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value);
++int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,
++                      u32 addr, u8 *data, u16 len);
++int cdns_mhdp_get_edid_block(void *mhdp, u8 *edid,
++                           unsigned int block, size_t length);
++int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp);
++int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active);
++int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp);
++int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
++                       struct audio_info *audio);
++int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable);
++int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
++                         struct audio_info *audio);
++int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
++int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val);
++int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
++                          u8 start_bit, u8 bits_no, u32 val);
++int cdns_mhdp_adjust_lt(struct cdns_mhdp_device *mhdp, u8 nlanes,
++                      u16 udelay, u8 *lanes_data,
++                      u8 *dpcd);
++
++int cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp);
++u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
++int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val);
++int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id,
++                                u8 opcode, u16 size, u8 *message);
++int cdns_mhdp_mailbox_read_receive(struct cdns_mhdp_device *mhdp,
++                                        u8 *buff, u16 buff_size);
++int cdns_mhdp_mailbox_validate_receive(struct cdns_mhdp_device *mhdp,
++                                            u8 module_id, u8 opcode,
++                                            u16 req_size);
++int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp);
++
++int cdns_hdmi_get_edid_block(void *data, u8 *edid, u32 block, size_t length);
++int cdns_hdmi_scdc_read(struct cdns_mhdp_device *mhdp, u8 addr, u8 *data);
++int cdns_hdmi_scdc_write(struct cdns_mhdp_device *mhdp, u8 addr, u8 value);
++int cdns_hdmi_ctrl_init(struct cdns_mhdp_device *mhdp, int protocol, u32 char_rate);
++int cdns_hdmi_mode_config(struct cdns_mhdp_device *mhdp, struct drm_display_mode *mode,
++                              struct video_info *video_info);
++int cdns_hdmi_disable_gcp(struct cdns_mhdp_device *mhdp);
++int cdns_hdmi_enable_gcp(struct cdns_mhdp_device *mhdp);
++
++bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp);
++#endif /* CDNS_MHDP_COMMON_H_ */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0004-drm-bridge-Add-Cadence-DP-HDMI-core-driver.patch b/target/linux/layerscape/patches-5.4/805-display-0004-drm-bridge-Add-Cadence-DP-HDMI-core-driver.patch
new file mode 100644 (file)
index 0000000..3c0daf7
--- /dev/null
@@ -0,0 +1,1417 @@
+From 9d6e1670f14a77c092ce32b559de52d7ddea3748 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Fri, 23 Aug 2019 13:57:49 +0800
+Subject: [PATCH] drm: bridge: Add Cadence DP/HDMI core driver
+
+Add HDMI and DP core driver.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/Kconfig          |   6 +
+ drivers/gpu/drm/bridge/cadence/Makefile         |   2 +
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c   | 605 ++++++++++++++++++++++
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 643 ++++++++++++++++++++++++
+ include/drm/bridge/cdns-mhdp-imx.h              | 121 +++++
+ 5 files changed, 1377 insertions(+)
+ create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+ create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+ create mode 100644 include/drm/bridge/cdns-mhdp-imx.h
+
+--- a/drivers/gpu/drm/bridge/cadence/Kconfig
++++ b/drivers/gpu/drm/bridge/cadence/Kconfig
+@@ -5,3 +5,9 @@ config DRM_CDNS_MHDP
+       depends on OF
+       help
+         Support Cadence MHDP API library.
++
++config DRM_CDNS_HDMI
++      tristate "Cadence HDMI DRM driver"
++
++config DRM_CDNS_DP
++      tristate "Cadence DP DRM driver"
+--- a/drivers/gpu/drm/bridge/cadence/Makefile
++++ b/drivers/gpu/drm/bridge/cadence/Makefile
+@@ -1,3 +1,5 @@
+ #ccflags-y := -Iinclude/drm
+ obj-$(CONFIG_DRM_CDNS_MHDP) += cdns-mhdp-common.o cdns-mhdp-hdmi.o
++obj-$(CONFIG_DRM_CDNS_HDMI) += cdns-hdmi-core.o
++obj-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
+--- /dev/null
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -0,0 +1,605 @@
++/*
++ * Cadence Display Port Interface (DP) driver
++ *
++ * Copyright (C) 2019 NXP Semiconductor, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++
++#include <drm/bridge/cdns-mhdp-imx.h>
++#include <drm/drm_atomic_helper.h>
++#include <drm/drm_crtc_helper.h>
++#include <drm/drm_edid.h>
++#include <drm/drm_encoder_slave.h>
++#include <drm/drm_of.h>
++#include <drm/drm_probe_helper.h>
++#include <drm/drmP.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/irq.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/of_device.h>
++
++#define aux_to_hdp(x) container_of(x, struct imx_mhdp_device, aux)
++
++/*
++ * This function only implements native DPDC reads and writes
++ */
++static ssize_t dp_aux_transfer(struct drm_dp_aux *aux,
++              struct drm_dp_aux_msg *msg)
++{
++      struct cdns_mhdp_device *mhdp = dev_get_drvdata(aux->dev);
++      bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
++      int ret;
++
++      /* Ignore address only message */
++      if ((msg->size == 0) || (msg->buffer == NULL)) {
++              msg->reply = native ?
++                      DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
++              return msg->size;
++      }
++
++      if (!native) {
++              dev_err(mhdp->dev, "%s: only native messages supported\n", __func__);
++              return -EINVAL;
++      }
++
++      /* msg sanity check */
++      if (msg->size > DP_AUX_MAX_PAYLOAD_BYTES) {
++              dev_err(mhdp->dev, "%s: invalid msg: size(%zu), request(%x)\n",
++                                              __func__, msg->size, (unsigned int)msg->request);
++              return -EINVAL;
++      }
++
++      if (msg->request == DP_AUX_NATIVE_WRITE) {
++              const u8 *buf = msg->buffer;
++              int i;
++              for (i = 0; i < msg->size; ++i) {
++                      ret = cdns_mhdp_dpcd_write(mhdp,
++                                                 msg->address + i, buf[i]);
++                      if (!ret)
++                              continue;
++
++                      DRM_DEV_ERROR(mhdp->dev, "Failed to write DPCD\n");
++
++                      return ret;
++              }
++      }
++
++      if (msg->request == DP_AUX_NATIVE_READ) {
++              ret = cdns_mhdp_dpcd_read(mhdp, msg->address, msg->buffer, msg->size);
++              if (ret < 0)
++                      return -EIO;
++              msg->reply = DP_AUX_NATIVE_REPLY_ACK;
++              return msg->size;
++      }
++      return 0;
++}
++
++static int dp_aux_init(struct cdns_mhdp_device *mhdp,
++                struct device *dev)
++{
++      int ret;
++
++      mhdp->dp.aux.name = "imx_dp_aux";
++      mhdp->dp.aux.dev = dev;
++      mhdp->dp.aux.transfer = dp_aux_transfer;
++
++      ret = drm_dp_aux_register(&mhdp->dp.aux);
++
++      return ret;
++}
++
++static int dp_aux_destroy(struct cdns_mhdp_device *mhdp)
++{
++      drm_dp_aux_unregister(&mhdp->dp.aux);
++      return 0;
++}
++
++static void dp_pixel_clk_reset(struct cdns_mhdp_device *mhdp)
++{
++      u32 val;
++
++      /* reset pixel clk */
++      val = cdns_mhdp_reg_read(mhdp, SOURCE_HDTX_CAR);
++      cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val & 0xFD);
++      cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val);
++}
++
++static void cdns_dp_mode_set(struct imx_mhdp_device *dp,
++                      const struct drm_display_mode *mode)
++{
++      struct drm_dp_link link;
++      struct cdns_mhdp_device *mhdp = &dp->mhdp;
++      u32 lane_mapping = mhdp->dp.lane_mapping;
++      int ret;
++      char linkid[6];
++
++      memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
++
++      dp->dual_mode = video_is_dual_mode(mode);
++
++      dp_pixel_clk_reset(mhdp);
++
++      hdp_plat_call(dp, pclock_change);
++
++      hdp_plat_call(dp, phy_init);
++
++      ret = drm_dp_downstream_id(&mhdp->dp.aux, linkid);
++      if (ret < 0) {
++              DRM_INFO("Failed to Get DP link ID: %d\n", ret);
++              return;
++      }
++      DRM_INFO("DP link id: %s, 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
++               linkid, linkid[0], linkid[1], linkid[2], linkid[3], linkid[4],
++               linkid[5]);
++
++      /* Check dp link */
++      ret = drm_dp_link_probe(&mhdp->dp.aux, &link);
++      if (ret < 0) {
++              DRM_INFO("Failed to probe DP link: %d\n", ret);
++              return;
++      }
++      DRM_INFO("DP revision: 0x%x\n", link.revision);
++      DRM_INFO("DP rate: %d Mbps\n", link.rate);
++      DRM_INFO("DP number of lanes: %d\n", link.num_lanes);
++      DRM_INFO("DP capabilities: 0x%lx\n", link.capabilities);
++
++      drm_dp_link_power_up(&mhdp->dp.aux, &mhdp->dp.link);
++      if (ret < 0) {
++              DRM_INFO("Failed to power DP link: %d\n", ret);
++              return;
++      }
++
++      /* always use the number of lanes from the display*/
++      mhdp->dp.link.num_lanes = link.num_lanes;
++
++      /* Use the lower link rate */
++      if (mhdp->dp.link_rate != 0) {
++              mhdp->dp.link.rate = min(mhdp->dp.link_rate, (u32)link.rate);
++              DRM_DEBUG("DP actual link rate:  0x%x\n", link.rate);
++      }
++
++      /* initialize phy if lanes or link rate differnt */
++      if (mhdp->dp.link.num_lanes != mhdp->dp.num_lanes ||
++                      mhdp->dp.link.rate != mhdp->dp.link_rate)
++              hdp_plat_call(dp, phy_init);
++
++      /* Video off */
++      ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
++      if (ret) {
++              DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
++              return;
++      }
++
++      /* Line swaping */
++      cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | lane_mapping);
++
++      /* Set DP host capability */
++      ret = cdns_mhdp_set_host_cap(mhdp, mhdp->dp.link.num_lanes, false);
++      if (ret) {
++              DRM_DEV_ERROR(mhdp->dev, "Failed to set host cap %d\n", ret);
++              return;
++      }
++
++      ret = cdns_mhdp_config_video(mhdp);
++      if (ret) {
++              DRM_DEV_ERROR(mhdp->dev, "Failed to config video %d\n", ret);
++              return;
++      }
++
++      /* Link trainning */
++      ret = cdns_mhdp_train_link(mhdp);
++      if (ret) {
++              DRM_DEV_ERROR(mhdp->dev, "Failed link train %d\n", ret);
++              return;
++      }
++
++      ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_VALID);
++      if (ret) {
++              DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
++              return;
++      }
++
++      return;
++}
++
++/* -----------------------------------------------------------------------------
++ * dp TX Setup
++ */
++static enum drm_connector_status
++cdns_dp_connector_detect(struct drm_connector *connector, bool force)
++{
++      struct imx_mhdp_device *dp = container_of(connector,
++                                      struct imx_mhdp_device, mhdp.connector.base);
++      u8 hpd = 0xf;
++
++      hpd = cdns_mhdp_read_hpd(&dp->mhdp);
++      if (hpd == 1)
++              /* Cable Connected */
++              return connector_status_connected;
++      else if (hpd == 0)
++              /* Cable Disconnedted */
++              return connector_status_disconnected;
++      else {
++              /* Cable status unknown */
++              DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
++              return connector_status_unknown;
++      }
++}
++
++static int cdns_dp_connector_get_modes(struct drm_connector *connector)
++{
++      struct imx_mhdp_device *dp = container_of(connector,
++                                              struct imx_mhdp_device, mhdp.connector.base);
++      int num_modes = 0;
++      struct edid *edid;
++
++      edid = drm_do_get_edid(&dp->mhdp.connector.base,
++                                 cdns_mhdp_get_edid_block, &dp->mhdp);
++      if (edid) {
++              dev_info(dp->mhdp.dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
++                       edid->header[0], edid->header[1],
++                       edid->header[2], edid->header[3],
++                       edid->header[4], edid->header[5],
++                       edid->header[6], edid->header[7]);
++              drm_connector_update_edid_property(connector, edid);
++              num_modes = drm_add_edid_modes(connector, edid);
++              kfree(edid);
++      }
++
++      if (num_modes == 0)
++              DRM_ERROR("Invalid edid\n");
++      return num_modes;
++}
++
++static const struct drm_connector_funcs cdns_dp_connector_funcs = {
++      .fill_modes = drm_helper_probe_single_connector_modes,
++      .detect = cdns_dp_connector_detect,
++      .destroy = drm_connector_cleanup,
++      .reset = drm_atomic_helper_connector_reset,
++      .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
++      .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
++};
++
++static const struct drm_connector_helper_funcs cdns_dp_connector_helper_funcs = {
++      .get_modes = cdns_dp_connector_get_modes,
++};
++
++static int cdns_dp_bridge_attach(struct drm_bridge *bridge)
++{
++      struct imx_mhdp_device *dp = bridge->driver_private;
++      struct drm_encoder *encoder = bridge->encoder;
++      struct drm_connector *connector = &dp->mhdp.connector.base;
++
++      connector->interlace_allowed = 1;
++      connector->polled = DRM_CONNECTOR_POLL_HPD;
++
++      drm_connector_helper_add(connector, &cdns_dp_connector_helper_funcs);
++
++      drm_connector_init(bridge->dev, connector, &cdns_dp_connector_funcs,
++                         DRM_MODE_CONNECTOR_DisplayPort);
++
++      drm_connector_attach_encoder(connector, encoder);
++
++      return 0;
++}
++
++static enum drm_mode_status
++cdns_dp_bridge_mode_valid(struct drm_bridge *bridge,
++                        const struct drm_display_mode *mode)
++{
++      enum drm_mode_status mode_status = MODE_OK;
++
++      /* We don't support double-clocked modes */
++      if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
++                      mode->flags & DRM_MODE_FLAG_INTERLACE)
++              return MODE_BAD;
++
++      /* MAX support pixel clock rate 594MHz */
++      if (mode->clock > 594000)
++              return MODE_CLOCK_HIGH;
++
++      /* 4096x2160 is not supported now */
++      if (mode->hdisplay > 3840)
++              return MODE_BAD_HVALUE;
++
++      if (mode->vdisplay > 2160)
++              return MODE_BAD_VVALUE;
++
++      return mode_status;
++}
++
++static void cdns_dp_bridge_mode_set(struct drm_bridge *bridge,
++                                  const struct drm_display_mode *orig_mode,
++                                  const struct drm_display_mode *mode)
++{
++      struct imx_mhdp_device *dp = bridge->driver_private;
++      struct drm_display_info *display_info = &dp->mhdp.connector.base.display_info;
++      struct video_info *video = &dp->mhdp.video_info;
++
++      switch (display_info->bpc) {
++      case 10:
++              video->color_depth = 10;
++              break;
++      case 6:
++              video->color_depth = 6;
++              break;
++      default:
++              video->color_depth = 8;
++              break;
++      }
++
++      video->color_fmt = PXL_RGB;
++      video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
++      video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
++
++      DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); 
++
++      mutex_lock(&dp->lock);
++
++      cdns_dp_mode_set(dp, mode);
++
++      mutex_unlock(&dp->lock);
++}
++
++static void cdn_hdp_bridge_enable(struct drm_bridge *bridge)
++{
++}
++
++static void cdn_hdp_bridge_disable(struct drm_bridge *bridge)
++{     
++      struct imx_mhdp_device *dp = bridge->driver_private;
++      struct cdns_mhdp_device *mhdp = &dp->mhdp;
++
++      cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
++      drm_dp_link_power_down(&mhdp->dp.aux, &mhdp->dp.link);
++}
++
++static const struct drm_bridge_funcs cdns_dp_bridge_funcs = {
++      .attach = cdns_dp_bridge_attach,
++      .enable = cdn_hdp_bridge_enable,
++      .disable = cdn_hdp_bridge_disable,
++      .mode_set = cdns_dp_bridge_mode_set,
++      .mode_valid = cdns_dp_bridge_mode_valid,
++};
++
++static void hotplug_work_func(struct work_struct *work)
++{
++      struct imx_mhdp_device *dp = container_of(work,
++                                         struct imx_mhdp_device, hotplug_work.work);
++      struct drm_connector *connector = &dp->mhdp.connector.base;
++
++      drm_helper_hpd_irq_event(connector->dev);
++
++      if (connector->status == connector_status_connected) {
++              DRM_INFO("HDMI/DP Cable Plug In\n");
++              enable_irq(dp->irq[IRQ_OUT]);
++      } else if (connector->status == connector_status_disconnected) {
++              /* Cable Disconnedted  */
++              DRM_INFO("HDMI/DP Cable Plug Out\n");
++              enable_irq(dp->irq[IRQ_IN]);
++      }
++}
++
++static irqreturn_t cdns_dp_irq_thread(int irq, void *data)
++{
++      struct imx_mhdp_device *dp = data;
++
++      disable_irq_nosync(irq);
++
++      mod_delayed_work(system_wq, &dp->hotplug_work,
++                      msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
++
++      return IRQ_HANDLED;
++}
++
++static void cdns_dp_parse_dt(struct cdns_mhdp_device *mhdp)
++{
++      struct device_node *of_node = mhdp->dev->of_node;
++      int ret;
++
++      ret = of_property_read_u32(of_node, "lane-mapping",
++                                              &mhdp->dp.lane_mapping);
++      if (ret) {
++              mhdp->dp.lane_mapping = 0xc6;
++              dev_warn(mhdp->dev, "Failed to get lane_mapping - using default 0xc6\n");
++      }
++      dev_info(mhdp->dev, "lane-mapping 0x%02x\n", mhdp->dp.lane_mapping);
++
++      ret = of_property_read_u32(of_node, "link-rate", &mhdp->dp.link_rate);
++      if (ret) {
++              mhdp->dp.link_rate = 162000 ;
++              dev_warn(mhdp->dev, "Failed to get link-rate, use default 1620MHz\n");
++      }
++      dev_info(mhdp->dev, "link-rate %d\n", mhdp->dp.link_rate);
++      
++      ret = of_property_read_u32(of_node, "num-lanes", &mhdp->dp.num_lanes);
++      if (ret) {
++              mhdp->dp.num_lanes = 4;
++              dev_warn(mhdp->dev, "Failed to get num_lanes - using default\n");
++      }
++      dev_info(mhdp->dev, "dp_num_lanes 0x%02x\n", mhdp->dp.num_lanes);
++
++      mhdp->dp.link.num_lanes = mhdp->dp.num_lanes;
++      mhdp->dp.link.rate= mhdp->dp.link_rate;
++}
++
++static struct imx_mhdp_device *
++__cdns_dp_probe(struct platform_device *pdev,
++              const struct cdn_plat_data *plat_data)
++{
++      struct device *dev = &pdev->dev;
++      struct imx_mhdp_device *dp;
++      struct resource *iores = NULL;
++      int ret;
++
++      dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
++      if (!dp)
++              return ERR_PTR(-ENOMEM);
++
++      dp->plat_data = plat_data;
++      dp->mhdp.dev = dev;
++
++      mutex_init(&dp->lock);
++      mutex_init(&dp->audio_mutex);
++      spin_lock_init(&dp->audio_lock);
++
++      INIT_DELAYED_WORK(&dp->hotplug_work, hotplug_work_func);
++
++      iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      dp->mhdp.regs = devm_ioremap(dev, iores->start, resource_size(iores));
++      if (IS_ERR(dp->mhdp.regs)) {
++              ret = PTR_ERR(dp->mhdp.regs);
++              goto err_out;
++      }
++
++#if 0
++      iores = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++      dp->regs_ss = devm_ioremap(dev, iores->start, resource_size(iores));
++      if (IS_ERR(dp->regs_ss)) {
++              ret = PTR_ERR(dp->regs_ss);
++              goto err_out;
++      }
++#endif
++
++      dp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
++      if (dp->irq[IRQ_IN] < 0)
++              dev_info(&pdev->dev, "No plug_in irq number\n");
++
++      dp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
++      if (dp->irq[IRQ_OUT] < 0)
++              dev_info(&pdev->dev, "No plug_out irq number\n");
++
++      cdns_dp_parse_dt(&dp->mhdp);
++
++      dp->dual_mode = false;
++      hdp_plat_call(dp, fw_init);
++
++      /* DP FW alive check */
++      ret = cdns_mhdp_check_alive(&dp->mhdp);
++      if (ret == false) {
++              DRM_ERROR("NO dp FW running\n");
++              return ERR_PTR(-ENXIO);
++      }
++
++      /* DP PHY init before AUX init */
++      hdp_plat_call(dp, phy_init);
++
++      /* Enable Hotplug Detect IRQ thread */
++      irq_set_status_flags(dp->irq[IRQ_IN], IRQ_NOAUTOEN);
++      ret = devm_request_threaded_irq(dev, dp->irq[IRQ_IN],
++                                      NULL, cdns_dp_irq_thread,
++                                      IRQF_ONESHOT, dev_name(dev),
++                                      dp);
++      if (ret) {
++              dev_err(&pdev->dev, "can't claim irq %d\n",
++                                              dp->irq[IRQ_IN]);
++              goto err_out;
++      }
++      
++      irq_set_status_flags(dp->irq[IRQ_OUT], IRQ_NOAUTOEN);
++      ret = devm_request_threaded_irq(dev, dp->irq[IRQ_OUT],
++                                      NULL, cdns_dp_irq_thread,
++                                      IRQF_ONESHOT, dev_name(dev),
++                                      dp);
++      if (ret) {
++              dev_err(&pdev->dev, "can't claim irq %d\n",
++                                              dp->irq[IRQ_OUT]);
++              goto err_out;
++      }
++      if (cdns_mhdp_read_hpd(&dp->mhdp))
++              enable_irq(dp->irq[IRQ_OUT]);
++      else
++              enable_irq(dp->irq[IRQ_IN]);
++
++      dp->mhdp.bridge.base.driver_private = dp;
++      dp->mhdp.bridge.base.funcs = &cdns_dp_bridge_funcs;
++#ifdef CONFIG_OF
++      dp->mhdp.bridge.base.of_node = pdev->dev.of_node;
++#endif
++
++      platform_set_drvdata(pdev, dp);
++      
++      dp_aux_init(&dp->mhdp, dev);
++
++      return dp;
++
++err_out:
++      return ERR_PTR(ret);
++}
++
++static void __cdns_dp_remove(struct imx_mhdp_device *dp)
++{
++      dp_aux_destroy(&dp->mhdp);
++}
++
++/* -----------------------------------------------------------------------------
++ * Probe/remove API, used from platforms based on the DRM bridge API.
++ */
++int cdns_dp_probe(struct platform_device *pdev,
++                const struct cdn_plat_data *plat_data)
++{
++      struct imx_mhdp_device *dp;
++
++      dp = __cdns_dp_probe(pdev, plat_data);
++      if (IS_ERR(dp))
++              return PTR_ERR(dp);
++
++      drm_bridge_add(&dp->mhdp.bridge.base);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(cdns_dp_probe);
++
++void cdns_dp_remove(struct platform_device *pdev)
++{
++      struct imx_mhdp_device *dp = platform_get_drvdata(pdev);
++
++      drm_bridge_remove(&dp->mhdp.bridge.base);
++
++      __cdns_dp_remove(dp);
++}
++EXPORT_SYMBOL_GPL(cdns_dp_remove);
++
++/* -----------------------------------------------------------------------------
++ * Bind/unbind API, used from platforms based on the component framework.
++ */
++int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
++               const struct cdn_plat_data *plat_data)
++{
++      struct imx_mhdp_device *dp;
++      int ret;
++
++      dp = __cdns_dp_probe(pdev, plat_data);
++      if (IS_ERR(dp))
++              return PTR_ERR(dp);
++
++      ret = drm_bridge_attach(encoder, &dp->mhdp.bridge.base, NULL);
++      if (ret) {
++              cdns_dp_remove(pdev);
++              DRM_ERROR("Failed to initialize bridge with drm\n");
++              return ret;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(cdns_dp_bind);
++
++void cdns_dp_unbind(struct device *dev)
++{
++      struct imx_mhdp_device *dp = dev_get_drvdata(dev);
++
++      __cdns_dp_remove(dp);
++}
++EXPORT_SYMBOL_GPL(cdns_dp_unbind);
++
++MODULE_AUTHOR("Sandor Yu <sandor.yu@nxp.com>");
++MODULE_DESCRIPTION("Cadence Display Port transmitter driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:cdn-dp");
+--- /dev/null
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -0,0 +1,643 @@
++/*
++ * Cadence High-Definition Multimedia Interface (HDMI) driver
++ *
++ * Copyright (C) 2019 NXP Semiconductor, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++
++#include <drm/bridge/cdns-mhdp-imx.h>
++#include <drm/drm_atomic_helper.h>
++#include <drm/drm_crtc_helper.h>
++#include <drm/drm_edid.h>
++#include <drm/drm_encoder_slave.h>
++#include <drm/drm_of.h>
++#include <drm/drm_probe_helper.h>
++#include <drm/drmP.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/hdmi.h>
++#include <linux/irq.h>
++#include <linux/module.h>
++#include <linux/mfd/syscon.h>
++#include <linux/mutex.h>
++#include <linux/regmap.h>
++#include <linux/of_device.h>
++
++static void hdmi_writel(struct cdns_mhdp_device *mhdp, u32 val, u32 offset)
++{
++      struct imx_mhdp_device *hdmi = container_of(mhdp, struct imx_mhdp_device, mhdp);
++
++      /* TODO */
++      if (offset >= 0x1000 && hdmi->regmap_csr) {
++              /* Remap address to low 4K memory */
++              regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, offset >> 12);
++              writel(val, (offset & 0xfff) + mhdp->regs);
++              /* Restore address mapping */
++              regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, 0);
++
++      } else
++              writel(val, mhdp->regs + offset);
++}
++
++static int hdmi_sink_config(struct cdns_mhdp_device *mhdp)
++{
++      struct drm_scdc *scdc = &mhdp->connector.base.display_info.hdmi.scdc;
++      u8 buff;
++      int ret;
++
++      if (mhdp->hdmi.char_rate > 340000) {
++              /*
++               * TMDS Character Rate above 340MHz should working in HDMI2.0
++               * Enable scrambling and TMDS_Bit_Clock_Ratio
++               */
++              buff = 3;
++              mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
++      } else  if (scdc->scrambling.low_rates) {
++              /*
++               * Enable scrambling and HDMI2.0 when scrambling capability of sink
++               * be indicated in the HF-VSDB LTE_340Mcsc_scramble bit
++               */
++              buff = 1;
++              mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
++      } else {
++              /* Default work in HDMI1.4 */
++              buff = 0;
++              mhdp->hdmi.hdmi_type = MODE_HDMI_1_4;
++       }
++
++      /* TMDS config */
++      ret = cdns_hdmi_scdc_write(mhdp, 0x20, buff);
++      return ret;
++}
++
++static int hdmi_lanes_config(struct cdns_mhdp_device *mhdp)
++{
++      int ret;
++
++      /* TODO */
++      /* Set the lane swapping */
++//    if (cpu_is_imx8qm())
++              ret = cdns_mhdp_reg_write(mhdp, LANES_CONFIG,
++                                                  F_SOURCE_PHY_LANE0_SWAP(3) |
++                                                  F_SOURCE_PHY_LANE1_SWAP(0) |
++                                                  F_SOURCE_PHY_LANE2_SWAP(1) |
++                                                  F_SOURCE_PHY_LANE3_SWAP(2) |
++                                                  F_SOURCE_PHY_COMB_BYPASS(0) |
++                                                      F_SOURCE_PHY_20_10(1));
++#if 0
++      else
++              ret = cdns_mhdp_reg_write(mhdp, LANES_CONFIG,
++                                                  F_SOURCE_PHY_LANE0_SWAP(0) |
++                                                  F_SOURCE_PHY_LANE1_SWAP(1) |
++                                                  F_SOURCE_PHY_LANE2_SWAP(2) |
++                                                  F_SOURCE_PHY_LANE3_SWAP(3) |
++                                                  F_SOURCE_PHY_COMB_BYPASS(0) |
++                                                      F_SOURCE_PHY_20_10(1));
++#endif
++      return ret;
++}
++
++static void hdmi_info_frame_set(struct cdns_mhdp_device *mhdp,
++                                      u8 entry_id, u8 packet_len, u8 *packet, u8 packet_type)
++{
++      u32 *packet32, len32;
++      u32 val, i;
++
++      /* invalidate entry */
++      val = F_ACTIVE_IDLE_TYPE(1) | F_PKT_ALLOC_ADDRESS(entry_id);
++      hdmi_writel(mhdp, val, SOURCE_PIF_PKT_ALLOC_REG);
++      hdmi_writel(mhdp, F_PKT_ALLOC_WR_EN(1), SOURCE_PIF_PKT_ALLOC_WR_EN);
++
++      /* flush fifo 1 */
++      hdmi_writel(mhdp, F_FIFO1_FLUSH(1), SOURCE_PIF_FIFO1_FLUSH);
++
++      /* write packet into memory */
++      packet32 = (u32 *)packet;
++      len32 = packet_len / 4;
++      for (i = 0; i < len32; i++)
++              hdmi_writel(mhdp, F_DATA_WR(packet32[i]), SOURCE_PIF_DATA_WR);
++
++      /* write entry id */
++      hdmi_writel(mhdp, F_WR_ADDR(entry_id), SOURCE_PIF_WR_ADDR);
++
++      /* write request */
++      hdmi_writel(mhdp, F_HOST_WR(1), SOURCE_PIF_WR_REQ);
++
++      /* update entry */
++      val =  F_ACTIVE_IDLE_TYPE(1) | F_TYPE_VALID(1) |
++                      F_PACKET_TYPE(packet_type) | F_PKT_ALLOC_ADDRESS(entry_id);
++      hdmi_writel(mhdp, val, SOURCE_PIF_PKT_ALLOC_REG);
++
++      hdmi_writel(mhdp, F_PKT_ALLOC_WR_EN(1), SOURCE_PIF_PKT_ALLOC_WR_EN);
++}
++
++#define RGB_ALLOWED_COLORIMETRY (BIT(HDMI_EXTENDED_COLORIMETRY_BT2020) |\
++                               BIT(HDMI_EXTENDED_COLORIMETRY_OPRGB))
++#define YCC_ALLOWED_COLORIMETRY (BIT(HDMI_EXTENDED_COLORIMETRY_BT2020) |\
++                               BIT(HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM) |\
++                               BIT(HDMI_EXTENDED_COLORIMETRY_OPYCC_601) |\
++                               BIT(HDMI_EXTENDED_COLORIMETRY_S_YCC_601) |\
++                               BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_709) |\
++                               BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_601))
++static int hdmi_avi_info_set(struct cdns_mhdp_device *mhdp,
++                              struct drm_display_mode *mode)
++{
++      struct hdmi_avi_infoframe frame;
++//    struct drm_display_info *di = &mhdp->connector.base.display_info;
++//    enum hdmi_extended_colorimetry ext_col;
++//    u32 sink_col, allowed_col;
++      int format = mhdp->video_info.color_fmt;
++      u8 buf[32];
++      int ret;
++
++      /* Initialise info frame from DRM mode */
++      drm_hdmi_avi_infoframe_from_display_mode(&frame, &mhdp->connector.base, mode);
++
++#if 0 //TODO to DCSS
++      /* Set up colorimetry */
++      allowed_col = format == PXL_RGB ? RGB_ALLOWED_COLORIMETRY :
++                                                YCC_ALLOWED_COLORIMETRY;
++
++      sink_col = di->hdmi.colorimetry & allowed_col;
++
++      if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_BT2020))
++              ext_col = HDMI_EXTENDED_COLORIMETRY_BT2020;
++      else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM))
++              ext_col = HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM;
++      else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_OPRGB))
++              ext_col = HDMI_EXTENDED_COLORIMETRY_OPRGB;
++      else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_709))
++              ext_col = HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
++      else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_OPYCC_601))
++              ext_col = HDMI_EXTENDED_COLORIMETRY_OPYCC_601;
++      else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_S_YCC_601))
++              ext_col = HDMI_EXTENDED_COLORIMETRY_S_YCC_601;
++      else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_601))
++              ext_col = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
++      else
++              ext_col = 0;
++
++      frame.colorimetry = sink_col ? HDMI_COLORIMETRY_EXTENDED :
++                                        HDMI_COLORIMETRY_NONE;
++      frame.extended_colorimetry = ext_col;
++#endif
++
++      switch (format) {
++      case YCBCR_4_4_4:
++              frame.colorspace = HDMI_COLORSPACE_YUV444;
++              break;
++      case YCBCR_4_2_2:
++              frame.colorspace = HDMI_COLORSPACE_YUV422;
++              break;
++      case YCBCR_4_2_0:
++              frame.colorspace = HDMI_COLORSPACE_YUV420;
++              break;
++      default:
++              frame.colorspace = HDMI_COLORSPACE_RGB;
++              break;
++      }
++
++      ret = hdmi_avi_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
++      if (ret < 0) {
++              DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
++              return -1;
++      }
++
++      buf[0] = 0;
++      hdmi_info_frame_set(mhdp, 0, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_AVI);
++      return 0;
++}
++
++static int hdmi_vendor_info_set(struct cdns_mhdp_device *mhdp,
++                              struct drm_display_mode *mode)
++{
++      struct hdmi_vendor_infoframe frame;
++      u8 buf[32];
++      int ret;
++
++      /* Initialise vendor frame from DRM mode */
++      ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame, &mhdp->connector.base, mode);
++      if (ret < 0) {
++              DRM_WARN("Unable to init vendor infoframe: %d\n", ret);
++              return -1;
++      }
++
++      ret = hdmi_vendor_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
++      if (ret < 0) {
++              DRM_WARN("Unable to pack vendor infoframe: %d\n", ret);
++              return -1;
++      }
++
++      buf[0] = 0;
++      hdmi_info_frame_set(mhdp, 3, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_VENDOR);
++      return 0;
++}
++
++void cdns_hdmi_mode_set(struct cdns_mhdp_device *mhdp)
++{
++      struct drm_display_mode *mode = &mhdp->mode;
++      int ret;
++
++      ret = hdmi_sink_config(mhdp);
++      if (ret < 0) {
++              DRM_ERROR("%s failed\n", __func__);
++              return;
++      }
++
++      ret = cdns_hdmi_ctrl_init(mhdp, mhdp->hdmi.hdmi_type, mhdp->hdmi.char_rate);
++      if (ret < 0) {
++              DRM_ERROR("%s, ret = %d\n", __func__, ret);
++              return;
++      }
++
++      /* Config GCP */
++      if (mhdp->video_info.color_depth == 8)
++              cdns_hdmi_disable_gcp(mhdp);
++      else
++              cdns_hdmi_enable_gcp(mhdp);
++
++      ret = hdmi_avi_info_set(mhdp, mode);
++      if (ret < 0) {
++              DRM_ERROR("%s ret = %d\n", __func__, ret);
++              return;
++      }
++
++      /* vendor info frame is enable only  when HDMI1.4 4K mode */
++      ret = hdmi_vendor_info_set(mhdp, mode);
++      if (ret < 0)
++              DRM_WARN("Unable to configure Vendor infoframe\n");
++
++      ret = cdns_hdmi_mode_config(mhdp, mode, &mhdp->video_info);
++      if (ret < 0) {
++              DRM_ERROR("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret);
++              return;
++      }
++
++      /* wait HDMI PHY pixel clock stable */
++      msleep(50);
++}
++
++static enum drm_connector_status
++cdns_hdmi_connector_detect(struct drm_connector *connector, bool force)
++{
++      struct imx_mhdp_device *hdmi =
++                              container_of(connector, struct imx_mhdp_device, mhdp.connector.base);
++
++      u8 hpd = 0xf;
++
++      hpd = cdns_mhdp_read_hpd(&hdmi->mhdp);
++
++      if (hpd == 1)
++              /* Cable Connected */
++              return connector_status_connected;
++      else if (hpd == 0)
++              /* Cable Disconnedted */
++              return connector_status_disconnected;
++      else {
++              /* Cable status unknown */
++              DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
++              return connector_status_unknown;
++      }
++}
++
++static int cdns_hdmi_connector_get_modes(struct drm_connector *connector)
++{
++      struct imx_mhdp_device *hdmi = container_of(connector, struct imx_mhdp_device,
++                                           mhdp.connector.base);
++      int num_modes = 0;
++      struct edid *edid;
++
++      edid = drm_do_get_edid(&hdmi->mhdp.connector.base,
++                                 cdns_hdmi_get_edid_block, &hdmi->mhdp);
++      if (edid) {
++              dev_info(hdmi->mhdp.dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
++                       edid->header[0], edid->header[1],
++                       edid->header[2], edid->header[3],
++                       edid->header[4], edid->header[5],
++                       edid->header[6], edid->header[7]);
++              drm_connector_update_edid_property(connector, edid);
++              num_modes = drm_add_edid_modes(connector, edid);
++              kfree(edid);
++      }
++
++      if (num_modes == 0)
++              DRM_ERROR("Invalid edid\n");
++      return num_modes;
++}
++
++static const struct drm_connector_funcs cdns_hdmi_connector_funcs = {
++      .fill_modes = drm_helper_probe_single_connector_modes,
++      .detect = cdns_hdmi_connector_detect,
++      .destroy = drm_connector_cleanup,
++      .reset = drm_atomic_helper_connector_reset,
++      .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
++      .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
++};
++
++static const struct drm_connector_helper_funcs cdns_hdmi_connector_helper_funcs = {
++      .get_modes = cdns_hdmi_connector_get_modes,
++};
++
++static int cdns_hdmi_bridge_attach(struct drm_bridge *bridge)
++{
++      struct imx_mhdp_device *hdmi = bridge->driver_private;
++      struct drm_encoder *encoder = bridge->encoder;
++      struct drm_connector *connector = &hdmi->mhdp.connector.base;
++
++      connector->interlace_allowed = 1;
++      connector->polled = DRM_CONNECTOR_POLL_HPD;
++
++      drm_connector_helper_add(connector, &cdns_hdmi_connector_helper_funcs);
++
++      drm_connector_init(bridge->dev, connector, &cdns_hdmi_connector_funcs,
++                         DRM_MODE_CONNECTOR_HDMIA);
++
++      drm_connector_attach_encoder(connector, encoder);
++
++      return 0;
++}
++
++static enum drm_mode_status
++cdns_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
++                        const struct drm_display_mode *mode)
++{
++      enum drm_mode_status mode_status = MODE_OK;
++
++      /* We don't support double-clocked and Interlaced modes */
++      if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
++                      mode->flags & DRM_MODE_FLAG_INTERLACE)
++              return MODE_BAD;
++
++      /* MAX support pixel clock rate 148.5MHz */
++      if (mode->clock > 148500)
++              return MODE_CLOCK_HIGH;
++
++      /* 4096x2160 is not supported */
++      if (mode->hdisplay > 3840 || mode->vdisplay > 2160)
++              return MODE_BAD_HVALUE;
++
++      return mode_status;
++}
++
++static void cdns_hdmi_bridge_mode_set(struct drm_bridge *bridge,
++                                  const struct drm_display_mode *orig_mode,
++                                  const struct drm_display_mode *mode)
++{
++      struct imx_mhdp_device *hdmi = bridge->driver_private;
++      struct drm_display_info *display_info = &hdmi->mhdp.connector.base.display_info;
++      struct video_info *video = &hdmi->mhdp.video_info;
++
++      switch (display_info->bpc) {
++      case 10:
++              video->color_depth = 10;
++              break;
++      case 6:
++              video->color_depth = 6;
++              break;
++      default:
++              video->color_depth = 8;
++              break;
++      }
++
++      video->color_fmt = PXL_RGB;
++      video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
++      video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
++
++      mutex_lock(&hdmi->lock);
++
++      DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); 
++
++      memcpy(&hdmi->mhdp.mode, mode, sizeof(struct drm_display_mode));
++
++      hdmi->dual_mode = video_is_dual_mode(mode);
++
++      hdmi_lanes_config(&hdmi->mhdp);
++
++      hdp_plat_call(hdmi, pclock_change);
++
++      hdp_plat_call(hdmi, phy_init);
++
++      cdns_hdmi_mode_set(&hdmi->mhdp);
++
++      mutex_unlock(&hdmi->lock);
++}
++
++static const struct drm_bridge_funcs cdns_hdmi_bridge_funcs = {
++      .attach = cdns_hdmi_bridge_attach,
++      .mode_set = cdns_hdmi_bridge_mode_set,
++      .mode_valid = cdns_hdmi_bridge_mode_valid,
++};
++
++static void hotplug_work_func(struct work_struct *work)
++{
++      struct imx_mhdp_device *hdmi = container_of(work,
++                                         struct imx_mhdp_device, hotplug_work.work);
++      struct drm_connector *connector = &hdmi->mhdp.connector.base;
++
++      drm_helper_hpd_irq_event(connector->dev);
++
++      if (connector->status == connector_status_connected) {
++              /* Cable Connected */
++              DRM_INFO("HDMI Cable Plug In\n");
++              enable_irq(hdmi->irq[IRQ_OUT]);
++      } else if (connector->status == connector_status_disconnected) {
++              /* Cable Disconnedted  */
++              DRM_INFO("HDMI Cable Plug Out\n");
++              enable_irq(hdmi->irq[IRQ_IN]);
++      }
++}
++
++static irqreturn_t cdns_hdmi_irq_thread(int irq, void *data)
++{
++      struct imx_mhdp_device *hdmi = data;
++
++      disable_irq_nosync(irq);
++
++      mod_delayed_work(system_wq, &hdmi->hotplug_work,
++                      msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
++
++      return IRQ_HANDLED;
++}
++
++static struct imx_mhdp_device *
++__cdns_hdmi_probe(struct platform_device *pdev,
++                      const struct cdn_plat_data *plat_data)
++{
++      struct device *dev = &pdev->dev;
++      struct device_node *np = dev->of_node;
++      struct platform_device_info pdevinfo;
++      struct imx_mhdp_device *hdmi;
++      struct resource *iores = NULL;
++      int ret;
++
++      hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
++      if (!hdmi)
++              return ERR_PTR(-ENOMEM);
++
++      hdmi->plat_data = plat_data;
++      hdmi->mhdp.dev = dev;
++
++      mutex_init(&hdmi->lock);
++      mutex_init(&hdmi->audio_mutex);
++      spin_lock_init(&hdmi->audio_lock);
++
++      INIT_DELAYED_WORK(&hdmi->hotplug_work, hotplug_work_func);
++
++      iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      hdmi->mhdp.regs = devm_ioremap(dev, iores->start, resource_size(iores));
++      if (IS_ERR(hdmi->mhdp.regs)) {
++              ret = PTR_ERR(hdmi->mhdp.regs);
++              goto err_out;
++      }
++
++      /* csr register base */
++      hdmi->regmap_csr = syscon_regmap_lookup_by_phandle(np, "csr");
++      if (IS_ERR(hdmi->regmap_csr)) {
++              dev_info(dev, "No csr regmap\n");
++      }
++
++      hdmi->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
++      if (hdmi->irq[IRQ_IN] < 0) {
++              dev_info(&pdev->dev, "No plug_in irq number\n");
++              return ERR_PTR(-EPROBE_DEFER);
++      }
++
++      hdmi->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
++      if (hdmi->irq[IRQ_OUT] < 0) {
++              dev_info(&pdev->dev, "No plug_out irq number\n");
++              return ERR_PTR(-EPROBE_DEFER);
++      }
++
++      /* Initialize dual_mode to false */
++      hdmi->dual_mode = false;
++
++      /* Initialize FW */
++      hdp_plat_call(hdmi, fw_init);
++
++      /* HDMI FW alive check */
++      ret = cdns_mhdp_check_alive(&hdmi->mhdp);
++      if (ret == false) {
++              DRM_ERROR("NO HDMI FW running\n");
++              return ERR_PTR(-ENXIO);
++      }
++
++      /* Enable Hotplug Detect thread */
++      irq_set_status_flags(hdmi->irq[IRQ_IN], IRQ_NOAUTOEN);
++      ret = devm_request_threaded_irq(dev, hdmi->irq[IRQ_IN],
++                                      NULL, cdns_hdmi_irq_thread,
++                                      IRQF_ONESHOT, dev_name(dev),
++                                      hdmi);
++      if (ret) {
++              dev_err(&pdev->dev, "can't claim irq %d\n",
++                                              hdmi->irq[IRQ_IN]);
++              goto err_out;
++      }
++      
++      irq_set_status_flags(hdmi->irq[IRQ_OUT], IRQ_NOAUTOEN);
++      ret = devm_request_threaded_irq(dev, hdmi->irq[IRQ_OUT],
++                                      NULL, cdns_hdmi_irq_thread,
++                                      IRQF_ONESHOT, dev_name(dev),
++                                      hdmi);
++      if (ret) {
++              dev_err(&pdev->dev, "can't claim irq %d\n",
++                                              hdmi->irq[IRQ_OUT]);
++              goto err_out;
++      }
++
++      if (cdns_mhdp_read_hpd(&hdmi->mhdp))
++              enable_irq(hdmi->irq[IRQ_OUT]);
++      else
++              enable_irq(hdmi->irq[IRQ_IN]);
++
++      hdmi->mhdp.bridge.base.driver_private = hdmi;
++      hdmi->mhdp.bridge.base.funcs = &cdns_hdmi_bridge_funcs;
++#ifdef CONFIG_OF
++      hdmi->mhdp.bridge.base.of_node = pdev->dev.of_node;
++#endif
++
++      memset(&pdevinfo, 0, sizeof(pdevinfo));
++      pdevinfo.parent = dev;
++      pdevinfo.id = PLATFORM_DEVID_AUTO;
++
++      platform_set_drvdata(pdev, hdmi);
++
++      return hdmi;
++
++err_out:
++
++      return ERR_PTR(ret);
++}
++
++static void __cdns_hdmi_remove(struct imx_mhdp_device *hdmi)
++{
++}
++
++/* -----------------------------------------------------------------------------
++ * Probe/remove API, used from platforms based on the DRM bridge API.
++ */
++int cdns_hdmi_probe(struct platform_device *pdev,
++                const struct cdn_plat_data *plat_data)
++{
++      struct imx_mhdp_device *hdmi;
++
++      hdmi = __cdns_hdmi_probe(pdev, plat_data);
++      if (IS_ERR(hdmi))
++              return PTR_ERR(hdmi);
++
++      drm_bridge_add(&hdmi->mhdp.bridge.base);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(cdns_hdmi_probe);
++
++void cdns_hdmi_remove(struct platform_device *pdev)
++{
++      struct imx_mhdp_device *hdmi = platform_get_drvdata(pdev);
++
++      drm_bridge_remove(&hdmi->mhdp.bridge.base);
++
++      __cdns_hdmi_remove(hdmi);
++}
++EXPORT_SYMBOL_GPL(cdns_hdmi_remove);
++
++/* -----------------------------------------------------------------------------
++ * Bind/unbind API, used from platforms based on the component framework.
++ */
++int cdns_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
++               const struct cdn_plat_data *plat_data)
++{
++      struct imx_mhdp_device *hdmi;
++      int ret;
++
++      hdmi = __cdns_hdmi_probe(pdev, plat_data);
++      if (IS_ERR(hdmi))
++              return PTR_ERR(hdmi);
++
++      ret = drm_bridge_attach(encoder, &hdmi->mhdp.bridge.base, NULL);
++      if (ret) {
++              cdns_hdmi_remove(pdev);
++              DRM_ERROR("Failed to initialize bridge with drm\n");
++              return ret;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(cdns_hdmi_bind);
++
++void cdns_hdmi_unbind(struct device *dev)
++{
++      struct imx_mhdp_device *hdmi = dev_get_drvdata(dev);
++
++      __cdns_hdmi_remove(hdmi);
++}
++EXPORT_SYMBOL_GPL(cdns_hdmi_unbind);
++
++MODULE_AUTHOR("Sandor Yu <sandor.yu@nxp.com>");
++MODULE_DESCRIPTION("Cadence HDMI transmitter driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:cdn-hdmi");
+--- /dev/null
++++ b/include/drm/bridge/cdns-mhdp-imx.h
+@@ -0,0 +1,121 @@
++/*
++ * Cadence High-Definition Multimedia Interface (HDMI) driver
++ *
++ * Copyright (C) 2019 NXP Semiconductor, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++#ifndef CDNS_MHDP_IMX_H_
++#define CDNS_MHDP_IMX_H_
++
++#include <drm/bridge/cdns-mhdp-common.h>
++
++#define IRQ_IN    0
++#define IRQ_OUT   1
++#define IRQ_NUM   2
++
++#define hdp_plat_call(hdp, operation)                 \
++      (!(hdp) ? -ENODEV : (((hdp)->plat_data && (hdp)->plat_data->operation) ?        \
++       (hdp)->plat_data->operation(hdp) : ENOIOCTLCMD))
++
++#define HDP_DUAL_MODE_MIN_PCLK_RATE   300000  /* KHz */
++#define HDP_SINGLE_MODE_MAX_WIDTH     1920
++
++static inline bool video_is_dual_mode(const struct drm_display_mode *mode)
++{
++      return (mode->clock > HDP_DUAL_MODE_MIN_PCLK_RATE ||
++              mode->hdisplay > HDP_SINGLE_MODE_MAX_WIDTH) ? true : false;
++}
++
++struct imx_mhdp_device;
++
++struct imx_hdp_clks {
++      struct clk *av_pll;
++      struct clk *dig_pll;
++      struct clk *clk_ipg;
++      struct clk *clk_core;
++      struct clk *clk_pxl;
++      struct clk *clk_pxl_mux;
++      struct clk *clk_pxl_link;
++
++      struct clk *lpcg_hdp;
++      struct clk *lpcg_msi;
++      struct clk *lpcg_pxl;
++      struct clk *lpcg_vif;
++      struct clk *lpcg_lis;
++      struct clk *lpcg_apb;
++      struct clk *lpcg_apb_csr;
++      struct clk *lpcg_apb_ctrl;
++
++      struct clk *lpcg_i2s;
++      struct clk *clk_i2s_bypass;
++};
++
++struct cdn_plat_data {
++      /* Vendor PHY support */
++      int (*phy_init)(struct imx_mhdp_device *hdmi);
++      int (*bind)(struct platform_device *pdev,
++                      struct drm_encoder *encoder,
++                      const struct cdn_plat_data *plat_data);
++      void (*unbind)(struct device *dev);
++      int (*fw_init)(struct imx_mhdp_device *hdp);
++      void (*pclock_change)(struct imx_mhdp_device *hdp);
++      char is_dp;
++};
++
++struct imx_mhdp_device {
++      struct cdns_mhdp_device mhdp;
++
++      struct mutex lock;
++      struct mutex audio_mutex;
++      spinlock_t audio_lock;
++      bool connected;
++      bool active;
++      bool suspended;
++      struct imx_hdp_clks clks;
++
++      const struct cdn_plat_data *plat_data;
++
++      int irq[IRQ_NUM];
++      struct delayed_work hotplug_work;
++      //void __iomem *regmap_csr;
++      struct regmap *regmap_csr;
++      u32 csr_pxl_mux_reg;
++      u32 csr_ctrl0_reg;
++      u32 csr_ctrl0_sec;
++
++      struct audio_info audio_info;
++      bool sink_has_audio;
++      u32 dual_mode;
++
++      struct device           *pd_mhdp_dev;
++      struct device           *pd_pll0_dev;
++      struct device           *pd_pll1_dev;
++      struct device_link      *pd_mhdp_link;
++      struct device_link      *pd_pll0_link;
++      struct device_link      *pd_pll1_link;
++
++      u32 phy_init;
++};
++
++int cdns_hdmi_probe(struct platform_device *pdev,
++                const struct cdn_plat_data *plat_data);
++void cdns_hdmi_remove(struct platform_device *pdev);
++void cdns_hdmi_unbind(struct device *dev);
++int cdns_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
++               const struct cdn_plat_data *plat_data);
++void cdns_hdmi_set_sample_rate(struct imx_mhdp_device *hdmi, unsigned int rate);
++void cdns_hdmi_audio_enable(struct imx_mhdp_device *hdmi);
++void cdns_hdmi_audio_disable(struct imx_mhdp_device *hdmi);
++int cdns_dp_probe(struct platform_device *pdev,
++                const struct cdn_plat_data *plat_data);
++void cdns_dp_remove(struct platform_device *pdev);
++void cdns_dp_unbind(struct device *dev);
++int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
++               const struct cdn_plat_data *plat_data);
++
++#endif /* CDNS_MHDP_IMX_H_ */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0005-gpu-drm-Add-imx8qm-mq-DP-HDMI-driver.patch b/target/linux/layerscape/patches-5.4/805-display-0005-gpu-drm-Add-imx8qm-mq-DP-HDMI-driver.patch
new file mode 100644 (file)
index 0000000..f4e428b
--- /dev/null
@@ -0,0 +1,2307 @@
+From 1433ad0f114ec80b524768af8ec96e09a5bba9b2 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Fri, 23 Aug 2019 14:05:16 +0800
+Subject: [PATCH] gpu: drm: Add imx8qm/mq DP/HDMI driver
+
+Add imx8qm/mq DP/hdmi driver
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/imx/Kconfig             |   9 +
+ drivers/gpu/drm/imx/Makefile            |   1 +
+ drivers/gpu/drm/imx/cdn-mhdp-dp-phy.c   | 533 ++++++++++++++++++++++++
+ drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c | 684 ++++++++++++++++++++++++++++++
+ drivers/gpu/drm/imx/cdn-mhdp-imx8mq.c   | 163 ++++++++
+ drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c   | 714 ++++++++++++++++++++++++++++++++
+ drivers/gpu/drm/imx/cdn-mhdp-phy.h      | 153 +++++++
+ 7 files changed, 2257 insertions(+)
+ create mode 100644 drivers/gpu/drm/imx/cdn-mhdp-dp-phy.c
+ create mode 100644 drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c
+ create mode 100644 drivers/gpu/drm/imx/cdn-mhdp-imx8mq.c
+ create mode 100644 drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
+ create mode 100644 drivers/gpu/drm/imx/cdn-mhdp-phy.h
+
+--- a/drivers/gpu/drm/imx/Kconfig
++++ b/drivers/gpu/drm/imx/Kconfig
+@@ -39,3 +39,12 @@ config DRM_IMX_HDMI
+       depends on DRM_IMX
+       help
+         Choose this if you want to use HDMI on i.MX6.
++
++config DRM_IMX_CDNS_MHDP
++      tristate "NXP i.MX MX8 DRM HDMI/DP"
++      select DRM_CDNS_MHDP
++      select DRM_CDNS_DP
++      select DRM_CDNS_HDMI
++      depends on DRM_IMX
++      help
++        Choose this if you want to use HDMI on i.MX8.
+--- a/drivers/gpu/drm/imx/Makefile
++++ b/drivers/gpu/drm/imx/Makefile
+@@ -9,3 +9,4 @@ obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
+ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
+ obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
++obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdn-mhdp-imx8qm.o cdn-mhdp-imx8mq.o cdn-mhdp-dp-phy.o cdn-mhdp-hdmi-phy.o
+--- /dev/null
++++ b/drivers/gpu/drm/imx/cdn-mhdp-dp-phy.c
+@@ -0,0 +1,533 @@
++/*
++ * Cadence Display Port Interface (DP) PHY driver
++ *
++ * Copyright (C) 2019 NXP Semiconductor, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++#include <linux/clk.h>
++#include <linux/kernel.h>
++#include <drm/drm_dp_helper.h>
++
++#include <drm/bridge/cdns-mhdp-common.h>
++#include "cdn-mhdp-phy.h"
++
++enum dp_link_rate {
++      RATE_1_6 = 162000,
++      RATE_2_1 = 216000,
++      RATE_2_4 = 243000,
++      RATE_2_7 = 270000,
++      RATE_3_2 = 324000,
++      RATE_4_3 = 432000,
++      RATE_5_4 = 540000,
++      RATE_8_1 = 810000,
++};
++
++struct phy_pll_reg {
++      u16 val[7];
++      u32 addr;
++};
++
++static const struct phy_pll_reg phy_pll_27m_cfg[] = {
++      /*  1.62    2.16    2.43    2.7     3.24    4.32    5.4      register address */
++      {{ 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E }, CMN_PLL0_VCOCAL_INIT_TMR },
++      {{ 0x001B, 0x001B, 0x001B, 0x001B, 0x001B, 0x001B, 0x001B }, CMN_PLL0_VCOCAL_ITER_TMR },
++      {{ 0x30B9, 0x3087, 0x3096, 0x30B4, 0x30B9, 0x3087, 0x30B4 }, CMN_PLL0_VCOCAL_START },
++      {{ 0x0077, 0x009F, 0x00B3, 0x00C7, 0x0077, 0x009F, 0x00C7 }, CMN_PLL0_INTDIV },
++      {{ 0xF9DA, 0xF7CD, 0xF6C7, 0xF5C1, 0xF9DA, 0xF7CD, 0xF5C1 }, CMN_PLL0_FRACDIV },
++      {{ 0x001E, 0x0028, 0x002D, 0x0032, 0x001E, 0x0028, 0x0032 }, CMN_PLL0_HIGH_THR },
++      {{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_PLL0_DSM_DIAG },
++      {{ 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x1000 }, CMN_PLLSM0_USER_DEF_CTRL },
++      {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_OVRD },
++      {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBH_OVRD },
++      {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBL_OVRD },
++      {{ 0x0006, 0x0007, 0x0007, 0x0007, 0x0006, 0x0007, 0x0007 }, CMN_DIAG_PLL0_V2I_TUNE },
++      {{ 0x0043, 0x0043, 0x0043, 0x0042, 0x0043, 0x0043, 0x0042 }, CMN_DIAG_PLL0_CP_TUNE },
++      {{ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008 }, CMN_DIAG_PLL0_LF_PROG },
++      {{ 0x0100, 0x0001, 0x0001, 0x0001, 0x0100, 0x0001, 0x0001 }, CMN_DIAG_PLL0_PTATIS_TUNE1 },
++      {{ 0x0007, 0x0001, 0x0001, 0x0001, 0x0007, 0x0001, 0x0001 }, CMN_DIAG_PLL0_PTATIS_TUNE2 },
++      {{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_DIAG_PLL0_TEST_MODE},
++      {{ 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016 }, CMN_PSM_CLK_CTRL }
++};
++
++static const struct phy_pll_reg phy_pll_24m_cfg[] = {
++      /*  1.62    2.16    2.43    2.7     3.24    4.32    5.4      register address */
++      {{ 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0 }, CMN_PLL0_VCOCAL_INIT_TMR },
++      {{ 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018 }, CMN_PLL0_VCOCAL_ITER_TMR },
++      {{ 0x3061, 0x3092, 0x30B3, 0x30D0, 0x3061, 0x3092, 0x30D0 }, CMN_PLL0_VCOCAL_START },
++      {{ 0x0086, 0x00B3, 0x00CA, 0x00E0, 0x0086, 0x00B3, 0x00E0 }, CMN_PLL0_INTDIV },
++      {{ 0xF917, 0xF6C7, 0x75A1, 0xF479, 0xF917, 0xF6C7, 0xF479 }, CMN_PLL0_FRACDIV },
++      {{ 0x0022, 0x002D, 0x0033, 0x0038, 0x0022, 0x002D, 0x0038 }, CMN_PLL0_HIGH_THR },
++      {{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_PLL0_DSM_DIAG },
++      {{ 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x1000 }, CMN_PLLSM0_USER_DEF_CTRL },
++      {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_OVRD },
++      {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBH_OVRD },
++      {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBL_OVRD },
++      {{ 0x0006, 0x0007, 0x0007, 0x0007, 0x0006, 0x0007, 0x0007 }, CMN_DIAG_PLL0_V2I_TUNE },
++      {{ 0x0026, 0x0029, 0x0029, 0x0029, 0x0026, 0x0029, 0x0029 }, CMN_DIAG_PLL0_CP_TUNE },
++      {{ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008 }, CMN_DIAG_PLL0_LF_PROG },
++      {{ 0x008C, 0x008C, 0x008C, 0x008C, 0x008C, 0x008C, 0x008C }, CMN_DIAG_PLL0_PTATIS_TUNE1 },
++      {{ 0x002E, 0x002E, 0x002E, 0x002E, 0x002E, 0x002E, 0x002E }, CMN_DIAG_PLL0_PTATIS_TUNE2 },
++      {{ 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022 }, CMN_DIAG_PLL0_TEST_MODE},
++      {{ 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016 }, CMN_PSM_CLK_CTRL }
++};
++
++static int link_rate_index(u32 rate)
++{
++      switch (rate) {
++      case RATE_1_6:
++              return 0;
++      case RATE_2_1:
++              return 1;
++      case RATE_2_4:
++              return 2;
++      case RATE_2_7:
++              return 3;
++      case RATE_3_2:
++              return 4;
++      case RATE_4_3:
++              return 5;
++      case RATE_5_4:
++              return 6;
++      default:
++              return -1;
++      }
++}
++
++static void dp_aux_cfg(struct cdns_mhdp_device *mhdp)
++{
++      /* Power up Aux */
++      cdns_phy_reg_write(mhdp, TXDA_CYA_AUXDA_CYA, 1);
++
++      cdns_phy_reg_write(mhdp, TX_DIG_CTRL_REG_2, 36);
++      ndelay(150);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0100);
++      ndelay(150);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0300);
++      ndelay(150);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_3, 0x0000);
++      ndelay(150);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2008);
++      ndelay(150);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2018);
++      ndelay(150);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA018);
++      ndelay(150);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030C);
++      ndelay(150);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_5, 0x0000);
++      ndelay(150);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_4, 0x1001);
++      ndelay(150);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA098);
++      ndelay(150);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA198);
++      ndelay(150);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030d);
++      ndelay(150);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030f);
++}
++
++/* PMA common configuration for 24MHz */
++static void dp_phy_pma_cmn_cfg_24mhz(struct cdns_mhdp_device *mhdp)
++{
++      int k;
++      u32 num_lanes = mhdp->dp.link.num_lanes;
++      u16 val;
++
++      val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
++      val &= 0xFFF7;
++      val |= 0x0008;
++      cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
++
++      for (k = 0; k < num_lanes; k++) {
++              /* Transceiver control and diagnostic registers */
++              cdns_phy_reg_write(mhdp, XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9), 0x0090);
++              /* Transmitter receiver detect registers */
++              cdns_phy_reg_write(mhdp, TX_RCVDET_EN_TMR | (k << 9), 0x0960);
++              cdns_phy_reg_write(mhdp, TX_RCVDET_ST_TMR | (k << 9), 0x0030);
++      }
++}
++
++/* Valid for 24 MHz only */
++static void dp_phy_pma_cmn_pll0_24mhz(struct cdns_mhdp_device *mhdp)
++{
++      u32 num_lanes = mhdp->dp.link.num_lanes;
++      u32 link_rate = mhdp->dp.link.rate;
++      u16 val;
++      int index, i, k;
++
++      /*
++       * PLL reference clock source select
++       * for single ended reference clock val |= 0x0030;
++       * for differential clock  val |= 0x0000;
++       */
++      val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
++      val = val & 0xFF8F;
++      val = val | 0x0030;
++      cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
++
++      /* DP PLL data rate 0/1 clock divider value */
++      val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
++      val &= 0x00FF;
++      if (link_rate <= RATE_2_7)
++              val |= 0x2400;
++      else
++              val |= 0x1200;
++      cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
++
++      /* High speed clock 0/1 div */
++      val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL);
++      val &= 0xFFCC;
++      if (link_rate <= RATE_2_7)
++              val |= 0x0011;
++      cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val);
++
++      for (k = 0; k < num_lanes; k = k + 1) {
++              val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
++              val &= 0xCFFF;
++              if (link_rate <= RATE_2_7)
++                      val |= 0x1000;
++              cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val);
++      }
++
++      /* DP PHY PLL 24MHz configuration */
++      index = link_rate_index(link_rate);
++      for (i = 0; i < ARRAY_SIZE(phy_pll_24m_cfg); i++)
++              cdns_phy_reg_write(mhdp, phy_pll_24m_cfg[i].addr, phy_pll_24m_cfg[i].val[index]);
++
++      /* Transceiver control and diagnostic registers */
++      for (k = 0; k < num_lanes; k = k + 1) {
++              val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
++              val &= 0x8FFF;
++              if (link_rate <= RATE_2_7)
++                      val |= 0x2000;
++              else
++                      val |= 0x1000;
++              cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
++      }
++
++      for (k = 0; k < num_lanes; k = k + 1) {
++              cdns_phy_reg_write(mhdp, (XCVR_PSM_RCTRL | (k << 9)), 0xBEFC);
++              cdns_phy_reg_write(mhdp, (TX_PSC_A0 | (k << 9)), 0x6799);
++              cdns_phy_reg_write(mhdp, (TX_PSC_A1 | (k << 9)), 0x6798);
++              cdns_phy_reg_write(mhdp, (TX_PSC_A2 | (k << 9)), 0x0098);
++              cdns_phy_reg_write(mhdp, (TX_PSC_A3 | (k << 9)), 0x0098);
++      }
++}
++
++/* PMA common configuration for 27MHz */
++static void dp_phy_pma_cmn_cfg_27mhz(struct cdns_mhdp_device *mhdp)
++{
++      u32 num_lanes = mhdp->dp.link.num_lanes;
++      u16 val;
++      int k;
++
++      val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
++      val &= 0xFFF7;
++      val |= 0x0008;
++      cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
++
++      /* Startup state machine registers */
++      cdns_phy_reg_write(mhdp, CMN_SSM_BIAS_TMR, 0x0087);
++      cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLEN_TMR, 0x001B);
++      cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLPRE_TMR, 0x0036);
++      cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLVREF_TMR, 0x001B);
++      cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLLOCK_TMR, 0x006C);
++
++      /* Current calibration registers */
++      cdns_phy_reg_write(mhdp, CMN_ICAL_INIT_TMR, 0x0044);
++      cdns_phy_reg_write(mhdp, CMN_ICAL_ITER_TMR, 0x0006);
++      cdns_phy_reg_write(mhdp, CMN_ICAL_ADJ_INIT_TMR, 0x0022);
++      cdns_phy_reg_write(mhdp, CMN_ICAL_ADJ_ITER_TMR, 0x0006);
++
++      /* Resistor calibration registers */
++      cdns_phy_reg_write(mhdp, CMN_TXPUCAL_INIT_TMR, 0x0022);
++      cdns_phy_reg_write(mhdp, CMN_TXPUCAL_ITER_TMR, 0x0006);
++      cdns_phy_reg_write(mhdp, CMN_TXPU_ADJ_INIT_TMR, 0x0022);
++      cdns_phy_reg_write(mhdp, CMN_TXPU_ADJ_ITER_TMR, 0x0006);
++      cdns_phy_reg_write(mhdp, CMN_TXPDCAL_INIT_TMR, 0x0022);
++      cdns_phy_reg_write(mhdp, CMN_TXPDCAL_ITER_TMR, 0x0006);
++      cdns_phy_reg_write(mhdp, CMN_TXPD_ADJ_INIT_TMR, 0x0022);
++      cdns_phy_reg_write(mhdp, CMN_TXPD_ADJ_ITER_TMR, 0x0006);
++      cdns_phy_reg_write(mhdp, CMN_RXCAL_INIT_TMR, 0x0022);
++      cdns_phy_reg_write(mhdp, CMN_RXCAL_ITER_TMR, 0x0006);
++      cdns_phy_reg_write(mhdp, CMN_RX_ADJ_INIT_TMR, 0x0022);
++      cdns_phy_reg_write(mhdp, CMN_RX_ADJ_ITER_TMR, 0x0006);
++
++      for (k = 0; k < num_lanes; k = k + 1) {
++              /* Power state machine registers */
++              cdns_phy_reg_write(mhdp, XCVR_PSM_CAL_TMR  | (k << 9), 0x016D);
++              cdns_phy_reg_write(mhdp, XCVR_PSM_A0IN_TMR | (k << 9), 0x016D);
++              /* Transceiver control and diagnostic registers */
++              cdns_phy_reg_write(mhdp, XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9), 0x00A2);
++              cdns_phy_reg_write(mhdp, TX_DIAG_BGREF_PREDRV_DELAY    | (k << 9), 0x0097);
++              /* Transmitter receiver detect registers */
++              cdns_phy_reg_write(mhdp, TX_RCVDET_EN_TMR | (k << 9), 0x0A8C);
++              cdns_phy_reg_write(mhdp, TX_RCVDET_ST_TMR | (k << 9), 0x0036);
++      }
++}
++
++static void dp_phy_pma_cmn_pll0_27mhz(struct cdns_mhdp_device *mhdp)
++{
++      u32 num_lanes = mhdp->dp.link.num_lanes;
++      u32 link_rate = mhdp->dp.link.rate;
++      u16 val;
++      int index, i, k;
++
++      /*
++       * PLL reference clock source select
++       * for single ended reference clock val |= 0x0030;
++       * for differential clock  val |= 0x0000;
++       */
++      val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
++      val &= 0xFF8F;
++      cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
++
++      /* for differential clock on the refclk_p and refclk_m off chip pins:
++       * CMN_DIAG_ACYA[8]=1'b1
++       */
++      cdns_phy_reg_write(mhdp, CMN_DIAG_ACYA, 0x0100);
++
++      /* DP PLL data rate 0/1 clock divider value */
++      val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
++      val &= 0x00FF;
++      if (link_rate <= RATE_2_7)
++              val |= 0x2400;
++      else
++              val |= 0x1200;
++      cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
++
++      /* High speed clock 0/1 div */
++      val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL);
++      val &= 0xFFCC;
++      if (link_rate <= RATE_2_7)
++              val |= 0x0011;
++      cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val);
++
++      for (k = 0; k < num_lanes; k++) {
++              val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
++              val = val & 0xCFFF;
++              if (link_rate <= RATE_2_7)
++                      val |= 0x1000;
++              cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val);
++      }
++
++      /* DP PHY PLL 27MHz configuration */
++      index = link_rate_index(link_rate);
++      for (i = 0; i < ARRAY_SIZE(phy_pll_27m_cfg); i++)
++              cdns_phy_reg_write(mhdp, phy_pll_27m_cfg[i].addr, phy_pll_27m_cfg[i].val[index]);
++
++      /* Transceiver control and diagnostic registers */
++      for (k = 0; k < num_lanes; k++) {
++              val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
++              val = val & 0x8FFF;
++              if (link_rate <= RATE_2_7)
++                      val |= 0x2000;
++              else
++                      val |= 0x1000;
++              cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
++      }
++
++      for (k = 0; k < num_lanes; k = k + 1) {
++              /* Power state machine registers */
++              cdns_phy_reg_write(mhdp, (XCVR_PSM_RCTRL | (k << 9)),  0xBEFC);
++              cdns_phy_reg_write(mhdp, (TX_PSC_A0 | (k << 9)), 0x6799);
++              cdns_phy_reg_write(mhdp, (TX_PSC_A1 | (k << 9)), 0x6798);
++              cdns_phy_reg_write(mhdp, (TX_PSC_A2 | (k << 9)), 0x0098);
++              cdns_phy_reg_write(mhdp, (TX_PSC_A3 | (k << 9)), 0x0098);
++              /* Receiver calibration power state definition register */
++              val = cdns_phy_reg_read(mhdp, RX_PSC_CAL | (k << 9));
++              val &= 0xFFBB;
++              cdns_phy_reg_write(mhdp, (RX_PSC_CAL | (k << 9)), val);
++              val = cdns_phy_reg_read(mhdp, RX_PSC_A0  | (k << 9));
++              val &= 0xFFBB;
++              cdns_phy_reg_write(mhdp, (RX_PSC_A0  | (k << 9)), val);
++      }
++}
++
++static void dp_phy_power_down(struct cdns_mhdp_device *mhdp)
++{
++      u16 val;
++      int i;
++
++      if (!mhdp->power_up)
++              return;
++
++      /* Place the PHY lanes in the A3 power state. */
++      cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x8);
++      /* Wait for Power State A3 Ack */
++      for (i = 0; i < 10; i++) {
++              val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
++              if (val & (1 << 7))
++                      break;
++              msleep(20);
++      }
++      if (i == 10) {
++              dev_err(mhdp->dev, "Wait A3 Ack failed\n");
++              return;
++      }
++
++      /* Disable HDP PLL’s data rate and full rate clocks out of PMA. */
++      val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
++      val &= ~(1 << 2);
++      cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
++      /* Wait for PLL clock gate ACK */
++      for (i = 0; i < 10; i++) {
++              val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
++              if (!(val & (1 << 3)))
++                      break;
++              msleep(20);
++      }
++      if (i == 10) {
++              dev_err(mhdp->dev, "Wait PLL clock gate Ack failed\n");
++              return;
++      }
++
++      /* Disable HDP PLL’s for high speed clocks */
++      val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
++      val &= ~(1 << 0);
++      cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
++      /* Wait for PLL disable ACK */
++      for (i = 0; i < 10; i++) {
++              val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
++              if (!(val & (1 << 1)))
++                      break;
++              msleep(20);
++      }
++      if (i == 10) {
++              dev_err(mhdp->dev, "Wait PLL disable Ack failed\n");
++              return;
++      }
++}
++
++static int dp_phy_power_up(struct cdns_mhdp_device *mhdp)
++{
++      u32 val, i;
++
++      /* Enable HDP PLL’s for high speed clocks */
++      val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
++      val |= (1 << 0);
++      cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
++      /* Wait for PLL ready ACK */
++      for (i = 0; i < 10; i++) {
++              val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
++              if (val & (1 << 1))
++                      break;
++              msleep(20);
++      }
++      if (i == 10) {
++              dev_err(mhdp->dev, "Wait PLL Ack failed\n");
++              return -1;
++      }
++
++      /* Enable HDP PLL’s data rate and full rate clocks out of PMA. */
++      val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
++      val |= (1 << 2);
++      cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
++      /* Wait for PLL clock enable ACK */
++      for (i = 0; i < 10; i++) {
++              val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
++              if (val & (1 << 3))
++                      break;
++              msleep(20);
++      }
++      if (i == 10) {
++              dev_err(mhdp->dev, "Wait PLL clock enable ACk failed\n");
++              return -1;
++      }
++
++      /* Configure PHY in A2 Mode */
++      cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0004);
++      /* Wait for Power State A2 Ack */
++      for (i = 0; i < 10; i++) {
++              val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
++              if (val & (1 << 6))
++                      break;
++              msleep(20);
++      }
++      if (i == 10) {
++              dev_err(mhdp->dev, "Wait A2 Ack failed\n");
++              return -1;
++      }
++
++      /* Configure PHY in A0 mode (PHY must be in the A0 power
++       * state in order to transmit data)
++       */
++      cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0101);
++
++      /* Wait for Power State A0 Ack */
++      for (i = 0; i < 10; i++) {
++              val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
++              if (val & (1 << 4))
++                      break;
++              msleep(20);
++      }
++      if (i == 10) {
++              dev_err(mhdp->dev, "Wait A0 Ack failed\n");
++              return -1;
++      }
++
++      mhdp->power_up = true;
++
++      return 0;
++}
++
++int cdns_dp_phy_init_imx8mq(struct imx_mhdp_device *hdp)
++{
++      struct cdns_mhdp_device *mhdp = &hdp->mhdp;
++      int ret;
++
++      /* Disable phy clock if PHY in power up state */
++      dp_phy_power_down(mhdp);
++
++      dp_phy_pma_cmn_cfg_27mhz(mhdp);
++
++      dp_phy_pma_cmn_pll0_27mhz(mhdp);
++
++      cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_0, 1);
++      cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_1, 1);
++      cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_2, 1);
++      cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_3, 1);
++
++      /* PHY power up */
++      ret = dp_phy_power_up(mhdp);
++      if (ret < 0)
++              return ret;
++
++      dp_aux_cfg(mhdp);
++
++      return ret;
++}
++
++
++int cdns_dp_phy_init_imx8qm(struct imx_mhdp_device *hdp)
++{
++      struct cdns_mhdp_device *mhdp = &hdp->mhdp;
++      int ret;
++
++      /* Disable phy clock if PHY in power up state */
++      dp_phy_power_down(mhdp);
++
++      dp_phy_pma_cmn_cfg_24mhz(mhdp);
++
++      dp_phy_pma_cmn_pll0_24mhz(mhdp);
++
++      cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_0, 1);
++      cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_1, 1);
++      cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_2, 1);
++      cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_3, 1);
++
++      /* PHY power up */
++      ret = dp_phy_power_up(mhdp);
++      if (ret < 0)
++              return ret;
++
++      dp_aux_cfg(mhdp);
++
++      return true;
++}
+--- /dev/null
++++ b/drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c
+@@ -0,0 +1,684 @@
++/*
++ * Cadence High-Definition Multimedia Interface (HDMI) driver
++ *
++ * Copyright (C) 2019 NXP Semiconductor, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++#include <drm/drm_of.h>
++#include <drm/drmP.h>
++#include <drm/drm_crtc_helper.h>
++#include <linux/io.h>
++#include <drm/drm_edid.h>
++#include <drm/drm_encoder_slave.h>
++#include <drm/drm_atomic.h>
++#include <linux/io.h>
++
++#include <drm/bridge/cdns-mhdp-common.h>
++#include "cdn-mhdp-phy.h"
++
++/* HDMI TX clock control settings */
++struct hdmi_ctrl {
++      u32 pixel_clk_freq_min;
++      u32 pixel_clk_freq_max;
++      u32 feedback_factor;
++      u32 data_range_kbps_min;
++      u32 data_range_kbps_max;
++      u32 cmnda_pll0_ip_div;
++      u32 cmn_ref_clk_dig_div;
++      u32 ref_clk_divider_scaler;
++      u32 pll_fb_div_total;
++      u32 cmnda_pll0_fb_div_low;
++      u32 cmnda_pll0_fb_div_high;
++      u32 pixel_div_total;
++      u32 cmnda_pll0_pxdiv_low;
++      u32 cmnda_pll0_pxdiv_high;
++      u32 vco_freq_min;
++      u32 vco_freq_max;
++      u32 vco_ring_select;
++      u32 cmnda_hs_clk_0_sel;
++      u32 cmnda_hs_clk_1_sel;
++      u32 hsclk_div_at_xcvr;
++      u32 hsclk_div_tx_sub_rate;
++      u32 cmnda_pll0_hs_sym_div_sel;
++      u32 cmnda_pll0_clk_freq_min;
++      u32 cmnda_pll0_clk_freq_max;
++};
++
++/* HDMI TX clock control settings, pixel clock is output */
++static const struct hdmi_ctrl imx8mq_ctrl_table[] = {
++/*Minclk  Maxclk Fdbak  DR_min   DR_max  ip_d  dig  DS    Totl */
++{ 27000,  27000, 1000,  270000,  270000, 0x03, 0x1, 0x1,  240, 0x0BC, 0x030,  80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x3,  27000,  27000},
++{ 27000,  27000, 1250,  337500,  337500, 0x03, 0x1, 0x1,  300, 0x0EC, 0x03C, 100, 0x030, 0x030, 2700000, 2700000, 0, 2, 2, 2, 4, 0x3,  33750,  33750},
++{ 27000,  27000, 1500,  405000,  405000, 0x03, 0x1, 0x1,  360, 0x11C, 0x048, 120, 0x03A, 0x03A, 3240000, 3240000, 0, 2, 2, 2, 4, 0x3,  40500,  40500},
++{ 27000,  27000, 2000,  540000,  540000, 0x03, 0x1, 0x1,  240, 0x0BC, 0x030,  80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x2,  54000,  54000},
++{ 54000,  54000, 1000,  540000,  540000, 0x03, 0x1, 0x1,  480, 0x17C, 0x060,  80, 0x026, 0x026, 4320000, 4320000, 1, 2, 2, 2, 4, 0x3,  54000,  54000},
++{ 54000,  54000, 1250,  675000,  675000, 0x04, 0x1, 0x1,  400, 0x13C, 0x050,  50, 0x017, 0x017, 2700000, 2700000, 0, 1, 1, 2, 4, 0x2,  67500,  67500},
++{ 54000,  54000, 1500,  810000,  810000, 0x04, 0x1, 0x1,  480, 0x17C, 0x060,  60, 0x01C, 0x01C, 3240000, 3240000, 0, 2, 2, 2, 2, 0x2,  81000,  81000},
++{ 54000,  54000, 2000, 1080000, 1080000, 0x03, 0x1, 0x1,  240, 0x0BC, 0x030,  40, 0x012, 0x012, 2160000, 2160000, 0, 2, 2, 2, 1, 0x1, 108000, 108000},
++{ 74250,  74250, 1000,  742500,  742500, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  80, 0x026, 0x026, 5940000, 5940000, 1, 2, 2, 2, 4, 0x3,  74250,  74250},
++{ 74250,  74250, 1250,  928125,  928125, 0x04, 0x1, 0x1,  550, 0x1B4, 0x06E,  50, 0x017, 0x017, 3712500, 3712500, 1, 1, 1, 2, 4, 0x2,  92812,  92812},
++{ 74250,  74250, 1500, 1113750, 1113750, 0x04, 0x1, 0x1,  660, 0x20C, 0x084,  60, 0x01C, 0x01C, 4455000, 4455000, 1, 2, 2, 2, 2, 0x2, 111375, 111375},
++{ 74250,  74250, 2000, 1485000, 1485000, 0x03, 0x1, 0x1,  330, 0x104, 0x042,  40, 0x012, 0x012, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500, 148500},
++{ 99000,  99000, 1000,  990000,  990000, 0x03, 0x1, 0x1,  440, 0x15C, 0x058,  40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 2, 0x2,  99000,  99000},
++{ 99000,  99000, 1250, 1237500, 1237500, 0x03, 0x1, 0x1,  275, 0x0D8, 0x037,  25, 0x00B, 0x00A, 2475000, 2475000, 0, 1, 1, 2, 2, 0x1, 123750, 123750},
++{ 99000,  99000, 1500, 1485000, 1485000, 0x03, 0x1, 0x1,  330, 0x104, 0x042,  30, 0x00D, 0x00D, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500, 148500},
++{ 99000,  99000, 2000, 1980000, 1980000, 0x03, 0x1, 0x1,  440, 0x15C, 0x058,  40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 1, 0x1, 198000, 198000},
++{148500, 148500, 1000, 1485000, 1485000, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 2, 0x2, 148500, 148500},
++{148500, 148500, 1250, 1856250, 1856250, 0x04, 0x1, 0x1,  550, 0x1B4, 0x06E,  25, 0x00B, 0x00A, 3712500, 3712500, 1, 1, 1, 2, 2, 0x1, 185625, 185625},
++{148500, 148500, 1500, 2227500, 2227500, 0x03, 0x1, 0x1,  495, 0x188, 0x063,  30, 0x00D, 0x00D, 4455000, 4455000, 1, 1, 1, 2, 2, 0x1, 222750, 222750},
++{148500, 148500, 2000, 2970000, 2970000, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 1, 0x1, 297000, 297000},
++{198000, 198000, 1000, 1980000, 1980000, 0x03, 0x1, 0x1,  220, 0x0AC, 0x02C,  10, 0x003, 0x003, 1980000, 1980000, 0, 1, 1, 2, 1, 0x0, 198000, 198000},
++{198000, 198000, 1250, 2475000, 2475000, 0x03, 0x1, 0x1,  550, 0x1B4, 0x06E,  25, 0x00B, 0x00A, 4950000, 4950000, 1, 1, 1, 2, 2, 0x1, 247500, 247500},
++{198000, 198000, 1500, 2970000, 2970000, 0x03, 0x1, 0x1,  330, 0x104, 0x042,  15, 0x006, 0x005, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000, 297000},
++{198000, 198000, 2000, 3960000, 3960000, 0x03, 0x1, 0x1,  440, 0x15C, 0x058,  20, 0x008, 0x008, 3960000, 3960000, 1, 1, 1, 2, 1, 0x0, 396000, 396000},
++{297000, 297000, 1000, 2970000, 2970000, 0x03, 0x1, 0x1,  330, 0x104, 0x042,  10, 0x003, 0x003, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000, 297000},
++{297000, 297000, 1500, 4455000, 4455000, 0x03, 0x1, 0x1,  495, 0x188, 0x063,  15, 0x006, 0x005, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500, 445500},
++{297000, 297000, 2000, 5940000, 5940000, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  20, 0x008, 0x008, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000, 594000},
++{594000, 594000, 1000, 5940000, 5940000, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000, 594000},
++{594000, 594000,  750, 4455000, 4455000, 0x03, 0x1, 0x1,  495, 0x188, 0x063,  10, 0x003, 0x003, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500, 445500},
++{594000, 594000,  625, 3712500, 3712500, 0x04, 0x1, 0x1,  550, 0x1B4, 0x06E,  10, 0x003, 0x003, 3712500, 3712500, 1, 1, 1, 2, 1, 0x0, 371250, 371250},
++{594000, 594000,  500, 2970000, 2970000, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 2, 0x1, 297000, 297000},
++};
++
++/* HDMI TX clock control settings, pixel clock is input */
++static const struct hdmi_ctrl imx8qm_ctrl_table[] = {
++/*pclk_l  pclk_h  fd    DRR_L    DRR_H   PLLD */
++{ 25000,  42500, 1000,  250000,  425000, 0x05, 0x01, 0x01, 400, 0x182, 0x00A, 0, 0, 0, 2000000, 3400000, 0, 2, 2, 2, 4, 0x03,  25000,  42500},
++{ 42500,  85000, 1000,  425000,  850000, 0x08, 0x03, 0x01, 320, 0x132, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 4, 0x02,  42500,  85000},
++{ 85000, 170000, 1000,  850000, 1700000, 0x11, 0x00, 0x07, 340, 0x146, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 2, 0x01,  85000, 170000},
++{170000, 340000, 1000, 1700000, 3400000, 0x22, 0x01, 0x07, 340, 0x146, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 1, 0x00, 170000, 340000},
++{340000, 600000, 1000, 3400000, 6000000, 0x3C, 0x03, 0x06, 600, 0x24A, 0x00A, 0, 0, 0, 3400000, 6000000, 1, 1, 1, 2, 1, 0x00, 340000, 600000},
++{ 25000,  34000, 1205,  312500,  425000, 0x04, 0x01, 0x01, 400, 0x182, 0x00A, 0, 0, 0, 2500000, 3400000, 0, 2, 2, 2, 4, 0x03,  31250,  42500},
++{ 34000,  68000, 1205,  425000,  850000, 0x06, 0x02, 0x01, 300, 0x11E, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 4, 0x02,  42500,  85000},
++{ 68000, 136000, 1205,  850000, 1700000, 0x0D, 0x02, 0x02, 325, 0x137, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 2, 0x01,  85000, 170000},
++{136000, 272000, 1205, 1700000, 3400000, 0x1A, 0x02, 0x04, 325, 0x137, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 1, 0x00, 170000, 340000},
++{272000, 480000, 1205, 3400000, 6000000, 0x30, 0x03, 0x05, 600, 0x24A, 0x00A, 0, 0, 0, 3400000, 6000000, 1, 1, 1, 2, 1, 0x00, 340000, 600000},
++{ 25000,  28000, 1500,  375000,  420000, 0x03, 0x01, 0x01, 360, 0x15A, 0x00A, 0, 0, 0, 3000000, 3360000, 0, 2, 2, 2, 4, 0x03,  37500,  42000},
++{ 28000,  56000, 1500,  420000,  840000, 0x06, 0x02, 0x01, 360, 0x15A, 0x00A, 0, 0, 0, 1680000, 3360000, 0, 1, 1, 2, 4, 0x02,  42000,  84000},
++{ 56000, 113000, 1500,  840000, 1695000, 0x0B, 0x00, 0x05, 330, 0x13C, 0x00A, 0, 0, 0, 1680000, 3390000, 0, 1, 1, 2, 2, 0x01,  84000, 169500},
++{113000, 226000, 1500, 1695000, 3390000, 0x16, 0x01, 0x05, 330, 0x13C, 0x00A, 0, 0, 0, 1695000, 3390000, 0, 1, 1, 2, 1, 0x00, 169500, 339000},
++{226000, 400000, 1500, 3390000, 6000000, 0x28, 0x03, 0x04, 600, 0x24A, 0x00A, 0, 0, 0, 3390000, 6000000, 1, 1, 1, 2, 1, 0x00, 339000, 600000},
++{ 25000,  42500, 2000,  500000,  850000, 0x05, 0x01, 0x01, 400, 0x182, 0x00A, 0, 0, 0, 2000000, 3400000, 0, 1, 1, 2, 4, 0x02,  50000,  85000},
++{ 42500,  85000, 2000,  850000, 1700000, 0x08, 0x03, 0x01, 320, 0x132, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 2, 0x01,  85000, 170000},
++{ 85000, 170000, 2000, 1700000, 3400000, 0x11, 0x00, 0x07, 340, 0x146, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 1, 0x00, 170000, 340000},
++{170000, 300000, 2000, 3400000, 6000000, 0x22, 0x01, 0x06, 680, 0x29A, 0x00A, 0, 0, 0, 3400000, 6000000, 1, 1, 1, 2, 1, 0x00, 340000, 600000},
++{594000, 594000, 5000, 2970000, 2970000, 0x3C, 0x03, 0x06, 600, 0x24A, 0x00A, 0, 0, 0, 5940000, 5940000, 1, 1, 1, 2, 2, 0x01, 297000, 297000},
++{594000, 594000, 6250, 3712500, 3712500, 0x3C, 0x03, 0x06, 375, 0x169, 0x00A, 0, 0, 0, 3712500, 3712500, 1, 1, 1, 2, 1, 0x00, 371250, 371250},
++{594000, 594000, 7500, 4455000, 4455000, 0x3C, 0x03, 0x06, 450, 0x1B4, 0x00A, 0, 0, 0, 4455000, 4455000, 1, 1, 1, 2, 1, 0x00, 445500, 445500},
++};
++
++/* HDMI TX PLL tuning settings */
++struct hdmi_pll_tuning {
++      u32 vco_freq_bin;
++      u32 vco_freq_min;
++      u32 vco_freq_max;
++      u32 volt_to_current_coarse;
++      u32 volt_to_current;
++      u32 ndac_ctrl;
++      u32 pmos_ctrl;
++      u32 ptat_ndac_ctrl;
++      u32 feedback_div_total;
++      u32 charge_pump_gain;
++      u32 coarse_code;
++      u32 v2i_code;
++      u32 vco_cal_code;
++};
++
++/* HDMI TX PLL tuning settings, pixel clock is output */
++static const struct hdmi_pll_tuning imx8mq_pll_table[] = {
++/*    bin VCO_freq min/max  coar  cod NDAC  PMOS PTAT div-T P-Gain Coa V2I CAL */
++    {  1, 1980000, 1980000, 0x4, 0x3, 0x0, 0x09, 0x09, 220, 0x42, 160, 5, 183 },
++    {  2, 2160000, 2160000, 0x4, 0x3, 0x0, 0x09, 0x09, 240, 0x42, 166, 6, 208 },
++    {  3, 2475000, 2475000, 0x5, 0x3, 0x1, 0x00, 0x07, 275, 0x42, 167, 6, 209 },
++    {  4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 300, 0x42, 188, 6, 230 },
++    {  4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 400, 0x4C, 188, 6, 230 },
++    {  5, 2970000, 2970000, 0x6, 0x3, 0x1, 0x00, 0x07, 330, 0x42, 183, 6, 225 },
++    {  6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 360, 0x42, 203, 7, 256 },
++    {  6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 480, 0x4C, 203, 7, 256 },
++    {  7, 3712500, 3712500, 0x4, 0x3, 0x0, 0x07, 0x0F, 550, 0x4C, 212, 7, 257 },
++    {  8, 3960000, 3960000, 0x5, 0x3, 0x0, 0x07, 0x0F, 440, 0x42, 184, 6, 226 },
++    {  9, 4320000, 4320000, 0x5, 0x3, 0x1, 0x07, 0x0F, 480, 0x42, 205, 7, 258 },
++    { 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 495, 0x42, 219, 7, 272 },
++    { 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 660, 0x4C, 219, 7, 272 },
++    { 11, 4950000, 4950000, 0x6, 0x3, 0x1, 0x00, 0x07, 550, 0x42, 213, 7, 258 },
++    { 12, 5940000, 5940000, 0x7, 0x3, 0x1, 0x00, 0x07, 660, 0x42, 244, 8, 292 },
++};
++
++/* HDMI TX PLL tuning settings, pixel clock is input */
++static const struct hdmi_pll_tuning imx8qm_pll_table[] = {
++/*  bin VCO_freq min/max  coar  cod NDAC  PMOS PTAT div-T P-Gain  pad only */
++      { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 300, 0x08D, 0, 0, 0 },
++      { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 320, 0x08E, 0, 0, 0 },
++      { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 325, 0x08E, 0, 0, 0 },
++      { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 330, 0x08E, 0, 0, 0 },
++      { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 340, 0x08F, 0, 0, 0 },
++      { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 360, 0x0A7, 0, 0, 0 },
++      { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 400, 0x0C5, 0, 0, 0 },
++      { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 300, 0x086, 0, 0, 0 },
++      { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 320, 0x087, 0, 0, 0 },
++      { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 325, 0x087, 0, 0, 0 },
++      { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 330, 0x104, 0, 0, 0 },
++      { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 340, 0x08B, 0, 0, 0 },
++      { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 360, 0x08D, 0, 0, 0 },
++      { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 400, 0x0A6, 0, 0, 0 },
++      { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 300, 0x04E, 0, 0, 0 },
++      { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 320, 0x04F, 0, 0, 0 },
++      { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 325, 0x04F, 0, 0, 0 },
++      { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 330, 0x085, 0, 0, 0 },
++      { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 340, 0x085, 0, 0, 0 },
++      { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 360, 0x086, 0, 0, 0 },
++      { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 400, 0x08B, 0, 0, 0 },
++      { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 300, 0x047, 0, 0, 0 },
++      { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 320, 0x04B, 0, 0, 0 },
++      { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 325, 0x04B, 0, 0, 0 },
++      { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 330, 0x04B, 0, 0, 0 },
++      { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 340, 0x04D, 0, 0, 0 },
++      { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 360, 0x04E, 0, 0, 0 },
++      { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 400, 0x085, 0, 0, 0 },
++      { 4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 375, 0x041, 0, 0, 0 },
++      { 4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 600, 0x08D, 0, 0, 0 },
++      { 4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 680, 0x0A6, 0, 0, 0 },
++      { 5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 450, 0x041, 0, 0, 0 },
++      { 5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 600, 0x087, 0, 0, 0 },
++      { 5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 680, 0x0A4, 0, 0, 0 },
++      { 6, 4500000, 5200000, 0x7, 0x1, 0x0, 0x04, 0x0D, 600, 0x04F, 0, 0, 0 },
++      { 6, 4500000, 5200000, 0x7, 0x1, 0x0, 0x04, 0x0D, 680, 0x086, 0, 0, 0 },
++      { 7, 5200000, 6000000, 0x7, 0x1, 0x0, 0x04, 0x0D, 600, 0x04D, 0, 0, 0 },
++      { 7, 5200000, 6000000, 0x7, 0x1, 0x0, 0x04, 0x0D, 680, 0x04F, 0, 0, 0 }
++};
++
++static void hdmi_phy_set_vswing(struct cdns_mhdp_device *mhdp)
++{
++      const u32 num_lanes = 4;
++      u32 k;
++
++      for (k = 0; k < num_lanes; k++) {
++              cdns_phy_reg_write(mhdp, (TX_DIAG_TX_DRV | (k << 9)), 0x7c0);
++              cdns_phy_reg_write(mhdp, (TX_TXCC_CPOST_MULT_00_0 | (k << 9)), 0x0);
++              cdns_phy_reg_write(mhdp, (TX_TXCC_CAL_SCLR_MULT_0 | (k << 9)), 0x120);
++      }
++}
++
++static int hdmi_feedback_factor(struct cdns_mhdp_device *mhdp)
++{
++      u32 feedback_factor;
++
++      switch (mhdp->video_info.color_fmt) {
++      case YCBCR_4_2_2:
++              feedback_factor = 1000;
++              break;
++      case YCBCR_4_2_0:
++              switch (mhdp->video_info.color_depth) {
++              case 8:
++                      feedback_factor = 500;
++                      break;
++              case 10:
++                      feedback_factor = 625;
++                      break;
++              case 12:
++                      feedback_factor = 750;
++                      break;
++              case 16:
++                      feedback_factor = 1000;
++                      break;
++              default:
++                      DRM_ERROR("Invalid ColorDepth\n");
++                      return 0;
++              }
++              break;
++      default:
++              /* Assume RGB/YUV444 */
++              switch (mhdp->video_info.color_depth) {
++              case 10:
++                      feedback_factor = 1250;
++                      break;
++              case 12:
++                      feedback_factor = 1500;
++                      break;
++              case 16:
++                      feedback_factor = 2000;
++                      break;
++              default:
++                      feedback_factor = 1000;
++              }
++      }
++      return feedback_factor;
++}
++
++static int hdmi_phy_config(struct cdns_mhdp_device *mhdp,
++                                      const struct hdmi_ctrl *p_ctrl_table,
++                                      const struct hdmi_pll_tuning *p_pll_table,
++                                      char pclk_in)
++{
++      const u32 num_lanes = 4;
++      u32 val, i, k;
++
++      /* enable PHY isolation mode only for CMN */
++      cdns_phy_reg_write(mhdp, PHY_PMA_ISOLATION_CTRL, 0xD000);
++
++      /* set cmn_pll0_clk_datart1_div/cmn_pll0_clk_datart0_div dividers */
++      val = cdns_phy_reg_read(mhdp, PHY_PMA_ISO_PLL_CTRL1);
++      val &= 0xFF00;
++      val |= 0x0012;
++      cdns_phy_reg_write(mhdp, PHY_PMA_ISO_PLL_CTRL1, val);
++
++      /* assert PHY reset from isolation register */
++      cdns_phy_reg_write(mhdp, PHY_ISO_CMN_CTRL, 0x0000);
++      /* assert PMA CMN reset */
++      cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0000);
++
++      /* register XCVR_DIAG_BIDI_CTRL */
++      for (k = 0; k < num_lanes; k++)
++              cdns_phy_reg_write(mhdp, XCVR_DIAG_BIDI_CTRL | (k << 9), 0x00FF);
++
++      /* Describing Task phy_cfg_hdp */
++
++      val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
++      val &= 0xFFF7;
++      val |= 0x0008;
++      cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
++
++      /* PHY Registers */
++      val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
++      val &= 0xCFFF;
++      val |= p_ctrl_table->cmn_ref_clk_dig_div << 12;
++      cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
++
++      val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
++      val &= 0x00FF;
++      val |= 0x1200;
++      cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
++
++      /* Common control module control and diagnostic registers */
++      val = cdns_phy_reg_read(mhdp, CMN_CDIAG_REFCLK_CTRL);
++      val &= 0x8FFF;
++      val |= p_ctrl_table->ref_clk_divider_scaler << 12;
++      val |= 0x00C0;
++      cdns_phy_reg_write(mhdp, CMN_CDIAG_REFCLK_CTRL, val);
++
++      /* High speed clock used */
++      val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL);
++      val &= 0xFF00;
++      val |= (p_ctrl_table->cmnda_hs_clk_0_sel >> 1) << 0;
++      val |= (p_ctrl_table->cmnda_hs_clk_1_sel >> 1) << 4;
++      cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val);
++
++      for (k = 0; k < num_lanes; k++) {
++              val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
++              val &= 0xCFFF;
++              val |= (p_ctrl_table->cmnda_hs_clk_0_sel >> 1) << 12;
++              cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val);
++      }
++
++      /* PLL 0 control state machine registers */
++      val = p_ctrl_table->vco_ring_select << 12;
++      cdns_phy_reg_write(mhdp, CMN_PLLSM0_USER_DEF_CTRL, val);
++
++      if (pclk_in == true)
++              val = 0x30A0;
++      else {
++              val = cdns_phy_reg_read(mhdp, CMN_PLL0_VCOCAL_START);
++              val &= 0xFE00;
++              val |= p_pll_table->vco_cal_code;
++      }
++      cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_START, val);
++
++      cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_INIT_TMR, 0x0064);
++      cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_ITER_TMR, 0x000A);
++
++      /* Common functions control and diagnostics registers */
++      val = p_ctrl_table->cmnda_pll0_hs_sym_div_sel << 8;
++      val |= p_ctrl_table->cmnda_pll0_ip_div;
++      cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_INCLK_CTRL, val);
++
++      cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_OVRD, 0x0000);
++
++      val = p_ctrl_table->cmnda_pll0_fb_div_high;
++      val |= (1 << 15);
++      cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_FBH_OVRD, val);
++
++      val = p_ctrl_table->cmnda_pll0_fb_div_low;
++      val |= (1 << 15);
++      cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_FBL_OVRD, val);
++
++      if (pclk_in == false) {
++              val = p_ctrl_table->cmnda_pll0_pxdiv_low;
++              cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PXL_DIVL, val);
++
++              val = p_ctrl_table->cmnda_pll0_pxdiv_high;
++              val |= (1 << 15);
++              cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PXL_DIVH, val);
++      }
++
++      val = p_pll_table->volt_to_current_coarse;
++      val |= (p_pll_table->volt_to_current) << 4;
++      cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_V2I_TUNE, val);
++
++      val = p_pll_table->charge_pump_gain;
++      cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_CP_TUNE, val);
++
++      cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_LF_PROG, 0x0008);
++
++      val = p_pll_table->pmos_ctrl;
++      val |= (p_pll_table->ndac_ctrl) << 8;
++      cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PTATIS_TUNE1, val);
++
++      val = p_pll_table->ptat_ndac_ctrl;
++      cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PTATIS_TUNE2, val);
++
++      if (pclk_in == true)
++      cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_TEST_MODE, 0x0022);
++      else
++      cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_TEST_MODE, 0x0020);
++      cdns_phy_reg_write(mhdp, CMN_PSM_CLK_CTRL, 0x0016);
++
++      /* Transceiver control and diagnostic registers */
++      for (k = 0; k < num_lanes; k++) {
++              val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
++              val &= 0xBFFF;
++              cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
++      }
++
++      for (k = 0; k < num_lanes; k++) {
++              val = cdns_phy_reg_read(mhdp, (TX_DIAG_TX_CTRL | (k << 9)));
++              val &= 0xFF3F;
++              val |= (p_ctrl_table->hsclk_div_tx_sub_rate >> 1) << 6;
++              cdns_phy_reg_write(mhdp, (TX_DIAG_TX_CTRL | (k << 9)), val);
++      }
++
++      /*
++       * for single ended reference clock val |= 0x0030;
++       * for differential clock  val |= 0x0000;
++       */
++      val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
++      val &= 0xFF8F;
++      if (pclk_in == true)
++              val |= 0x0030;
++      cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
++
++      /* for differential clock on the refclk_p and
++       * refclk_m off chip pins: CMN_DIAG_ACYA[8]=1'b1 */
++      cdns_phy_reg_write(mhdp, CMN_DIAG_ACYA, 0x0100);
++
++      /* Deassert PHY reset */
++      cdns_phy_reg_write(mhdp, PHY_ISO_CMN_CTRL, 0x0001);
++      cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0003);
++
++      /* Power state machine registers */
++      for (k = 0; k < num_lanes; k++)
++              cdns_phy_reg_write(mhdp, XCVR_PSM_RCTRL | (k << 9), 0xFEFC);
++
++      /* Assert cmn_macro_pwr_en */
++      cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0013);
++
++      /* wait for cmn_macro_pwr_en_ack */
++      for (i = 0; i < 10; i++) {
++              val = cdns_phy_reg_read(mhdp, PHY_PMA_ISO_CMN_CTRL);
++              if (val & (1 << 5))
++                      break;
++              msleep(20);
++      }
++      if (i == 10) {
++              DRM_ERROR("PMA ouput macro power up failed\n");
++              return false;
++      }
++
++      /* wait for cmn_ready */
++      for (i = 0; i < 10; i++) {
++              val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
++              if (val & (1 << 0))
++                      break;
++              msleep(20);
++      }
++      if (i == 10) {
++              DRM_ERROR("PMA output ready failed\n");
++              return false;
++      }
++
++      for (k = 0; k < num_lanes; k++) {
++              cdns_phy_reg_write(mhdp, TX_PSC_A0 | (k << 9), 0x6791);
++              cdns_phy_reg_write(mhdp, TX_PSC_A1 | (k << 9), 0x6790);
++              cdns_phy_reg_write(mhdp, TX_PSC_A2 | (k << 9), 0x0090);
++              cdns_phy_reg_write(mhdp, TX_PSC_A3 | (k << 9), 0x0090);
++
++              val = cdns_phy_reg_read(mhdp, RX_PSC_CAL | (k << 9));
++              val &= 0xFFBB;
++              cdns_phy_reg_write(mhdp, RX_PSC_CAL | (k << 9), val);
++
++              val = cdns_phy_reg_read(mhdp, RX_PSC_A0 | (k << 9));
++              val &= 0xFFBB;
++              cdns_phy_reg_write(mhdp, RX_PSC_A0 | (k << 9), val);
++      }
++      return true;
++}
++
++static int hdmi_phy_cfg_t28hpc(struct cdns_mhdp_device *mhdp,
++                              struct drm_display_mode *mode)
++{
++      const struct hdmi_ctrl *p_ctrl_table;
++      const struct hdmi_pll_tuning *p_pll_table;
++      const u32 refclk_freq_khz = 27000;
++      const u8 pclk_in = false;
++      u32 pixel_freq = mode->clock;
++      u32 vco_freq, char_freq;
++      u32 div_total, feedback_factor;
++      u32 i, ret;
++
++      feedback_factor = hdmi_feedback_factor(mhdp);
++
++      char_freq = pixel_freq * feedback_factor / 1000;
++
++      DRM_INFO("Pixel clock: %d KHz, character clock: %d, bpc is %0d-bit.\n",
++           pixel_freq, char_freq, mhdp->video_info.color_depth);
++
++      /* Get right row from the ctrl_table table.
++       * Check if 'pixel_freq_khz' value matches the PIXEL_CLK_FREQ column.
++       * Consider only the rows with FEEDBACK_FACTOR column matching feedback_factor. */
++      for (i = 0; i < ARRAY_SIZE(imx8mq_ctrl_table); i++) {
++              if (feedback_factor == imx8mq_ctrl_table[i].feedback_factor &&
++                              pixel_freq == imx8mq_ctrl_table[i].pixel_clk_freq_min) {
++                      p_ctrl_table = &imx8mq_ctrl_table[i];
++                      break;
++              }
++      }
++      if (i == ARRAY_SIZE(imx8mq_ctrl_table)) {
++              DRM_WARN("Pixel clk (%d KHz) not supported, color depth (%0d-bit)\n",
++                   pixel_freq, mhdp->video_info.color_depth);
++              return 0;
++      }
++
++      div_total = p_ctrl_table->pll_fb_div_total;
++      vco_freq = refclk_freq_khz * div_total / p_ctrl_table->cmnda_pll0_ip_div;
++
++      /* Get right row from the imx8mq_pll_table table.
++       * Check if vco_freq_khz and feedback_div_total
++       * column matching with imx8mq_pll_table. */
++      for (i = 0; i < ARRAY_SIZE(imx8mq_pll_table); i++) {
++              if (vco_freq == imx8mq_pll_table[i].vco_freq_min &&
++                              div_total == imx8mq_pll_table[i].feedback_div_total) {
++                      p_pll_table = &imx8mq_pll_table[i];
++                      break;
++              }
++      }
++      if (i == ARRAY_SIZE(imx8mq_pll_table)) {
++              DRM_WARN("VCO (%d KHz) not supported\n", vco_freq);
++              return 0;
++      }
++      DRM_INFO("VCO frequency is %d KHz\n", vco_freq);
++
++      ret = hdmi_phy_config(mhdp, p_ctrl_table, p_pll_table, pclk_in);
++      if (ret == false)
++              return 0;
++
++      return char_freq;
++}
++
++static int hdmi_phy_cfg_ss28fdsoi(struct cdns_mhdp_device *mhdp,
++                              struct drm_display_mode *mode)
++{
++      const struct hdmi_ctrl *p_ctrl_table;
++      const struct hdmi_pll_tuning *p_pll_table;
++      const u8 pclk_in = true;
++      u32 pixel_freq = mode->clock;
++      u32 vco_freq, char_freq;
++      u32 div_total, feedback_factor;
++      u32 ret, i;
++
++      feedback_factor = hdmi_feedback_factor(mhdp);
++
++      char_freq = pixel_freq * feedback_factor / 1000;
++
++      DRM_INFO("Pixel clock: %d KHz, character clock: %d, bpc is %0d-bit.\n",
++           pixel_freq, char_freq, mhdp->video_info.color_depth);
++
++      /* Get right row from the ctrl_table table.
++       * Check if 'pixel_freq_khz' value matches the PIXEL_CLK_FREQ column.
++       * Consider only the rows with FEEDBACK_FACTOR column matching feedback_factor. */
++      for (i = 0; i < ARRAY_SIZE(imx8qm_ctrl_table); i++) {
++              if (feedback_factor == imx8qm_ctrl_table[i].feedback_factor &&
++                              pixel_freq >= imx8qm_ctrl_table[i].pixel_clk_freq_min &&
++                              pixel_freq <= imx8qm_ctrl_table[i].pixel_clk_freq_max) {
++                      p_ctrl_table = &imx8qm_ctrl_table[i];
++                      break;
++              }
++      }
++      if (i == ARRAY_SIZE(imx8qm_ctrl_table)) {
++              DRM_WARN("Pixel clk (%d KHz) not supported, color depth (%0d-bit)\n",
++                   pixel_freq, mhdp->video_info.color_depth);
++              return 0;
++      }
++
++      div_total = p_ctrl_table->pll_fb_div_total;
++      vco_freq = pixel_freq * div_total / p_ctrl_table->cmnda_pll0_ip_div;
++
++      /* Get right row from the imx8mq_pll_table table.
++       * Check if vco_freq_khz and feedback_div_total
++       * column matching with imx8mq_pll_table. */
++      for (i = 0; i < ARRAY_SIZE(imx8qm_pll_table); i++) {
++              if (vco_freq >= imx8qm_pll_table[i].vco_freq_min &&
++                              vco_freq < imx8qm_pll_table[i].vco_freq_max &&
++                              div_total == imx8qm_pll_table[i].feedback_div_total) {
++                      p_pll_table = &imx8qm_pll_table[i];
++                      break;
++              }
++      }
++      if (i == ARRAY_SIZE(imx8qm_pll_table)) {
++              DRM_WARN("VCO (%d KHz) not supported\n", vco_freq);
++              return 0;
++      }
++      DRM_INFO("VCO frequency is %d KHz\n", vco_freq);
++
++      ret = hdmi_phy_config(mhdp, p_ctrl_table, p_pll_table, pclk_in);
++      if (ret == false)
++              return 0;
++
++      return char_freq;
++}
++
++static int hdmi_phy_power_up(struct cdns_mhdp_device *mhdp)
++{
++      u32 val, i;
++
++      /* set Power State to A2 */
++      cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0004);
++
++      cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_0, 1);
++      cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_1, 1);
++      cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_2, 1);
++      cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_3, 1);
++
++      /* Wait for Power State A2 Ack */
++      for (i = 0; i < 10; i++) {
++              val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
++              if (val & (1 << 6))
++                      break;
++              msleep(20);
++      }
++      if (i == 10) {
++              dev_err(mhdp->dev, "Wait A2 Ack failed\n");
++              return -1;
++      }
++
++      /* Configure PHY in A0 mode (PHY must be in the A0 power
++       * state in order to transmit data)
++       */
++      //cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0101); //imx8mq
++      cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0001);
++
++      /* Wait for Power State A0 Ack */
++      for (i = 0; i < 10; i++) {
++              val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
++              if (val & (1 << 4))
++                      break;
++              msleep(20);
++      }
++      if (i == 10) {
++              dev_err(mhdp->dev, "Wait A0 Ack failed\n");
++              return -1;
++      }
++      return 0;
++}
++
++int cdns_hdmi_phy_set_imx8mq(struct imx_mhdp_device *hdp)
++{
++      struct cdns_mhdp_device *mhdp = &hdp->mhdp;
++      struct drm_display_mode *mode = &mhdp->mode;
++      int ret;
++
++      /* Check HDMI FW alive before HDMI PHY init */
++      ret = cdns_mhdp_check_alive(mhdp);
++      if (ret == false) {
++              DRM_ERROR("NO HDMI FW running\n");
++              return -ENXIO;
++      }
++
++      /* Configure PHY */
++      mhdp->hdmi.char_rate = hdmi_phy_cfg_t28hpc(mhdp, mode);
++      if (mhdp->hdmi.char_rate == 0) {
++              DRM_ERROR("failed to set phy pclock\n");
++              return -EINVAL;
++      }
++
++      ret = hdmi_phy_power_up(mhdp);
++      if (ret < 0)
++              return ret;
++
++      hdmi_phy_set_vswing(mhdp);
++
++      return true;
++}
++
++int cdns_hdmi_phy_set_imx8qm(struct imx_mhdp_device *hdp)
++{
++      struct cdns_mhdp_device *mhdp = &hdp->mhdp;
++      struct drm_display_mode *mode = &mhdp->mode;
++      int ret;
++
++      /* Check HDMI FW alive before HDMI PHY init */
++      ret = cdns_mhdp_check_alive(mhdp);
++      if (ret == false) {
++              DRM_ERROR("NO HDMI FW running\n");
++              return -ENXIO;
++      }
++
++      /* Configure PHY */
++      mhdp->hdmi.char_rate = hdmi_phy_cfg_ss28fdsoi(mhdp, mode);
++      if (mhdp->hdmi.char_rate == 0) {
++              DRM_ERROR("failed to set phy pclock\n");
++              return -EINVAL;
++      }
++
++      ret = hdmi_phy_power_up(mhdp);
++      if (ret < 0)
++              return ret;
++
++      hdmi_phy_set_vswing(mhdp);
++
++      return true;
++}
++
+--- /dev/null
++++ b/drivers/gpu/drm/imx/cdn-mhdp-imx8mq.c
+@@ -0,0 +1,163 @@
++/*
++ * Copyright (C) 2019 NXP Semiconductor, 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/platform_device.h>
++#include <linux/component.h>
++#include <linux/mfd/syscon.h>
++#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
++#include <drm/drm_of.h>
++#include <drm/drmP.h>
++#include <drm/drm_crtc_helper.h>
++#include <drm/drm_edid.h>
++#include <drm/drm_encoder_slave.h>
++
++#include <drm/bridge/cdns-mhdp-imx.h>
++#include "cdn-mhdp-phy.h"
++#include "imx-drm.h"
++
++struct imx_hdmi {
++      struct device *dev;
++      struct drm_encoder encoder;
++};
++
++static void cdns_hdmi_imx_encoder_disable(struct drm_encoder *encoder)
++{
++}
++
++static void cdns_hdmi_imx_encoder_enable(struct drm_encoder *encoder)
++{
++}
++
++static int cdns_hdmi_imx_atomic_check(struct drm_encoder *encoder,
++                                  struct drm_crtc_state *crtc_state,
++                                  struct drm_connector_state *conn_state)
++{
++      return 0;
++}
++
++static const struct drm_encoder_helper_funcs cdns_hdmi_imx_encoder_helper_funcs = {
++      .enable     = cdns_hdmi_imx_encoder_enable,
++      .disable    = cdns_hdmi_imx_encoder_disable,
++      .atomic_check = cdns_hdmi_imx_atomic_check,
++};
++
++static const struct drm_encoder_funcs cdns_hdmi_imx_encoder_funcs = {
++      .destroy = drm_encoder_cleanup,
++};
++
++static struct cdn_plat_data imx8mq_hdmi_drv_data = {
++      .bind   = cdns_hdmi_bind,
++      .unbind = cdns_hdmi_unbind,
++      .phy_init = cdns_hdmi_phy_set_imx8mq,
++};
++
++static struct cdn_plat_data imx8mq_dp_drv_data = {
++      .bind   = cdns_dp_bind,
++      .unbind = cdns_dp_unbind,
++      .phy_init = cdns_dp_phy_init_imx8mq,
++};
++
++static const struct of_device_id cdns_hdmi_imx_dt_ids[] = {
++      { .compatible = "cdn,imx8mq-hdmi",
++        .data = &imx8mq_hdmi_drv_data
++      },
++      { .compatible = "cdn,imx8mq-dp",
++        .data = &imx8mq_dp_drv_data
++      },
++      {},
++};
++MODULE_DEVICE_TABLE(of, cdns_hdmi_imx_dt_ids);
++
++static int cdns_hdmi_imx_bind(struct device *dev, struct device *master,
++                          void *data)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++      const struct cdn_plat_data *plat_data;
++      const struct of_device_id *match;
++      struct drm_device *drm = data;
++      struct drm_encoder *encoder;
++      struct imx_hdmi *hdmi;
++      int ret;
++
++      if (!pdev->dev.of_node)
++              return -ENODEV;
++
++      hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
++      if (!hdmi)
++              return -ENOMEM;
++
++      match = of_match_node(cdns_hdmi_imx_dt_ids, pdev->dev.of_node);
++      plat_data = match->data;
++      hdmi->dev = &pdev->dev;
++      encoder = &hdmi->encoder;
++
++      encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
++      /*
++       * If we failed to find the CRTC(s) which this encoder is
++       * supposed to be connected to, it's because the CRTC has
++       * not been registered yet.  Defer probing, and hope that
++       * the required CRTC is added later.
++       */
++      if (encoder->possible_crtcs == 0)
++              return -EPROBE_DEFER;
++
++      drm_encoder_helper_add(encoder, &cdns_hdmi_imx_encoder_helper_funcs);
++      drm_encoder_init(drm, encoder, &cdns_hdmi_imx_encoder_funcs,
++                       DRM_MODE_ENCODER_TMDS, NULL);
++
++      ret = plat_data->bind(pdev, encoder, plat_data);
++
++      /*
++       * If cdns_hdmi_bind() fails we'll never call cdns_hdmi_unbind(),
++       * which would have called the encoder cleanup.  Do it manually.
++       */
++      if (ret)
++              drm_encoder_cleanup(encoder);
++
++      return ret;
++}
++
++static void cdns_hdmi_imx_unbind(struct device *dev, struct device *master,
++                             void *data)
++{
++      struct imx_mhdp_device *hdp = dev_get_drvdata(dev);
++
++      hdp->plat_data->unbind(dev);
++}
++
++static const struct component_ops cdns_hdmi_imx_ops = {
++      .bind   = cdns_hdmi_imx_bind,
++      .unbind = cdns_hdmi_imx_unbind,
++};
++
++static int cdns_hdmi_imx_probe(struct platform_device *pdev)
++{
++      return component_add(&pdev->dev, &cdns_hdmi_imx_ops);
++}
++
++static int cdns_hdmi_imx_remove(struct platform_device *pdev)
++{
++      component_del(&pdev->dev, &cdns_hdmi_imx_ops);
++
++      return 0;
++}
++
++static struct platform_driver cdns_hdmi_imx_platform_driver = {
++      .probe  = cdns_hdmi_imx_probe,
++      .remove = cdns_hdmi_imx_remove,
++      .driver = {
++              .name = "cdn-hdp-imx8mq",
++              .of_match_table = cdns_hdmi_imx_dt_ids,
++      },
++};
++
++module_platform_driver(cdns_hdmi_imx_platform_driver);
++
++MODULE_AUTHOR("Sandor YU <sandor.yu@nxp.com>");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:cdnhdmi-imx");
+--- /dev/null
++++ b/drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
+@@ -0,0 +1,714 @@
++/*
++ * Copyright (C) 2019 NXP Semiconductor, 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 <dt-bindings/firmware/imx/rsrc.h>
++#include <linux/clk.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/component.h>
++#include <drm/drm_of.h>
++#include <drm/drmP.h>
++#include <drm/drm_crtc_helper.h>
++#include <drm/drm_encoder_slave.h>
++#include <linux/firmware/imx/sci.h>
++#include <linux/regmap.h>
++#include <linux/pm_domain.h>
++
++#include <drm/bridge/cdns-mhdp-imx.h>
++#include "cdn-mhdp-phy.h"
++#include "imx-drm.h"
++
++#define CSR_PIXEL_LINK_MUX_CTL                0x00
++#define PL_MUX_CTL_VCP_OFFSET         5
++#define PL_MUX_CTL_HCP_OFFSET         4
++
++#define PLL_800MHZ (800000000)
++
++struct imx_hdmi {
++      struct device *dev;
++      struct drm_encoder encoder;
++};
++
++static void imx8qm_pixel_link_mux(struct imx_mhdp_device *hdp)
++{
++      struct drm_display_mode *mode = &hdp->mhdp.mode;
++      u32 val;
++
++      val = 0x4;      /* RGB */
++      if (hdp->dual_mode)
++              val |= 0x2;     /* pixel link 0 and 1 are active */
++      if (mode->flags & DRM_MODE_FLAG_PVSYNC)
++              val |= 1 << PL_MUX_CTL_VCP_OFFSET;
++      if (mode->flags & DRM_MODE_FLAG_PHSYNC)
++              val |= 1 << PL_MUX_CTL_HCP_OFFSET;
++      if (mode->flags & DRM_MODE_FLAG_INTERLACE)
++              val |= 0x2;
++
++      regmap_write(hdp->regmap_csr, hdp->csr_pxl_mux_reg, val);
++}
++
++static void imx8qm_pixel_link_valid(u32 dual_mode)
++{
++      struct imx_sc_ipc *handle;
++
++      imx_scu_get_handle(&handle);
++
++      imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST1_VLD, 1);
++      if (dual_mode)
++              imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST2_VLD, 1);
++}
++
++static void imx8qm_pixel_link_invalid(u32 dual_mode)
++{
++      struct imx_sc_ipc *handle;
++
++      imx_scu_get_handle(&handle);
++
++      imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST1_VLD, 0);
++      if (dual_mode)
++              imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST2_VLD, 0);
++}
++
++static void imx8qm_pixel_link_sync_enable(u32 dual_mode)
++{
++      struct imx_sc_ipc *handle;
++
++      imx_scu_get_handle(&handle);
++
++      if (dual_mode)
++              imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL, 3);
++      else
++              imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL0, 1);
++}
++
++static void imx8qm_pixel_link_sync_disable(u32 dual_mode)
++{
++      struct imx_sc_ipc *handle;
++
++      imx_scu_get_handle(&handle);
++
++      if (dual_mode)
++              imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL, 0);
++      else
++              imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL0, 0);
++}
++
++static void imx8qm_phy_reset(u8 reset)
++{
++      struct imx_sc_ipc *handle;
++
++      imx_scu_get_handle(&handle);
++
++      /* set the pixel link mode and pixel type */
++      imx_sc_misc_set_control(handle, IMX_SC_R_HDMI, IMX_SC_C_PHY_RESET, reset);
++}
++
++static void imx8qm_clk_mux(u8 is_dp)
++{
++      struct imx_sc_ipc *handle;
++
++      imx_scu_get_handle(&handle);
++
++      if (is_dp)
++              /* Enable the 24MHz for HDP PHY */
++              imx_sc_misc_set_control(handle, IMX_SC_R_HDMI, IMX_SC_C_MODE, 1);
++      else
++              imx_sc_misc_set_control(handle, IMX_SC_R_HDMI, IMX_SC_C_MODE, 0);
++}
++
++int imx8qm_clocks_init(struct imx_mhdp_device *hdp)
++{
++      struct device *dev = hdp->mhdp.dev;
++      struct imx_hdp_clks *clks = &hdp->clks;
++
++      clks->dig_pll = devm_clk_get(dev, "dig_pll");
++      if (IS_ERR(clks->dig_pll)) {
++              dev_warn(dev, "failed to get dig pll clk\n");
++              return PTR_ERR(clks->dig_pll);
++      }
++
++      clks->av_pll = devm_clk_get(dev, "av_pll");
++      if (IS_ERR(clks->av_pll)) {
++              dev_warn(dev, "failed to get av pll clk\n");
++              return PTR_ERR(clks->av_pll);
++      }
++
++      clks->clk_ipg = devm_clk_get(dev, "clk_ipg");
++      if (IS_ERR(clks->clk_ipg)) {
++              dev_warn(dev, "failed to get dp ipg clk\n");
++              return PTR_ERR(clks->clk_ipg);
++      }
++
++      clks->clk_core = devm_clk_get(dev, "clk_core");
++      if (IS_ERR(clks->clk_core)) {
++              dev_warn(dev, "failed to get hdp core clk\n");
++              return PTR_ERR(clks->clk_core);
++      }
++
++      clks->clk_pxl = devm_clk_get(dev, "clk_pxl");
++      if (IS_ERR(clks->clk_pxl)) {
++              dev_warn(dev, "failed to get pxl clk\n");
++              return PTR_ERR(clks->clk_pxl);
++      }
++
++      clks->clk_pxl_mux = devm_clk_get(dev, "clk_pxl_mux");
++      if (IS_ERR(clks->clk_pxl_mux)) {
++              dev_warn(dev, "failed to get pxl mux clk\n");
++              return PTR_ERR(clks->clk_pxl_mux);
++      }
++
++      clks->clk_pxl_link = devm_clk_get(dev, "clk_pxl_link");
++      if (IS_ERR(clks->clk_pxl_mux)) {
++              dev_warn(dev, "failed to get pxl link clk\n");
++              return PTR_ERR(clks->clk_pxl_link);
++      }
++
++      clks->lpcg_hdp = devm_clk_get(dev, "lpcg_hdp");
++      if (IS_ERR(clks->lpcg_hdp)) {
++              dev_warn(dev, "failed to get lpcg hdp clk\n");
++              return PTR_ERR(clks->lpcg_hdp);
++      }
++
++      clks->lpcg_msi = devm_clk_get(dev, "lpcg_msi");
++      if (IS_ERR(clks->lpcg_msi)) {
++              dev_warn(dev, "failed to get lpcg msi clk\n");
++              return PTR_ERR(clks->lpcg_msi);
++      }
++
++      clks->lpcg_pxl = devm_clk_get(dev, "lpcg_pxl");
++      if (IS_ERR(clks->lpcg_pxl)) {
++              dev_warn(dev, "failed to get lpcg pxl clk\n");
++              return PTR_ERR(clks->lpcg_pxl);
++      }
++
++      clks->lpcg_vif = devm_clk_get(dev, "lpcg_vif");
++      if (IS_ERR(clks->lpcg_vif)) {
++              dev_warn(dev, "failed to get lpcg vif clk\n");
++              return PTR_ERR(clks->lpcg_vif);
++      }
++
++      clks->lpcg_lis = devm_clk_get(dev, "lpcg_lis");
++      if (IS_ERR(clks->lpcg_lis)) {
++              dev_warn(dev, "failed to get lpcg lis clk\n");
++              return PTR_ERR(clks->lpcg_lis);
++      }
++
++      clks->lpcg_apb = devm_clk_get(dev, "lpcg_apb");
++      if (IS_ERR(clks->lpcg_apb)) {
++              dev_warn(dev, "failed to get lpcg apb clk\n");
++              return PTR_ERR(clks->lpcg_apb);
++      }
++
++      clks->lpcg_apb_csr = devm_clk_get(dev, "lpcg_apb_csr");
++      if (IS_ERR(clks->lpcg_apb_csr)) {
++              dev_warn(dev, "failed to get apb csr clk\n");
++              return PTR_ERR(clks->lpcg_apb_csr);
++      }
++
++      clks->lpcg_apb_ctrl = devm_clk_get(dev, "lpcg_apb_ctrl");
++      if (IS_ERR(clks->lpcg_apb_ctrl)) {
++              dev_warn(dev, "failed to get lpcg apb ctrl clk\n");
++              return PTR_ERR(clks->lpcg_apb_ctrl);
++      }
++
++      clks->clk_i2s_bypass = devm_clk_get(dev, "clk_i2s_bypass");
++      if (IS_ERR(clks->clk_i2s_bypass)) {
++              dev_err(dev, "failed to get i2s bypass clk\n");
++              return PTR_ERR(clks->clk_i2s_bypass);
++      }
++
++      clks->lpcg_i2s = devm_clk_get(dev, "lpcg_i2s");
++      if (IS_ERR(clks->lpcg_i2s)) {
++              dev_err(dev, "failed to get lpcg i2s clk\n");
++              return PTR_ERR(clks->lpcg_i2s);
++      }
++      return true;
++}
++
++static int imx8qm_pixel_clk_enable(struct imx_mhdp_device *hdp)
++{
++      struct imx_hdp_clks *clks = &hdp->clks;
++      struct device *dev = hdp->mhdp.dev;
++      int ret;
++
++      ret = clk_prepare_enable(clks->av_pll);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre av pll  error\n", __func__);
++              return ret;
++      }
++
++      ret = clk_prepare_enable(clks->clk_pxl);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre clk pxl error\n", __func__);
++              return ret;
++      }
++      ret = clk_prepare_enable(clks->clk_pxl_mux);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre clk pxl mux error\n", __func__);
++              return ret;
++      }
++
++      ret = clk_prepare_enable(clks->clk_pxl_link);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre clk pxl link error\n", __func__);
++              return ret;
++      }
++      ret = clk_prepare_enable(clks->lpcg_vif);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre clk vif error\n", __func__);
++              return ret;
++      }
++      ret = clk_prepare_enable(clks->lpcg_pxl);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre lpcg pxl error\n", __func__);
++              return ret;
++      }
++      ret = clk_prepare_enable(clks->lpcg_hdp);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre lpcg hdp error\n", __func__);
++              return ret;
++      }
++      return ret;
++
++}
++
++static void imx8qm_pixel_clk_disable(struct imx_mhdp_device *hdp)
++{
++      struct imx_hdp_clks *clks = &hdp->clks;
++
++      clk_disable_unprepare(clks->lpcg_pxl);
++      clk_disable_unprepare(clks->lpcg_hdp);
++      clk_disable_unprepare(clks->lpcg_vif);
++      clk_disable_unprepare(clks->clk_pxl);
++      clk_disable_unprepare(clks->clk_pxl_link);
++      clk_disable_unprepare(clks->clk_pxl_mux);
++      clk_disable_unprepare(clks->av_pll);
++}
++
++static void imx8qm_pixel_clk_set_rate(struct imx_mhdp_device *hdp, u32 pclock)
++{
++      struct imx_hdp_clks *clks = &hdp->clks;
++
++      /* pixel clock for HDMI */
++      clk_set_rate(clks->av_pll, pclock);
++
++      if (hdp->dual_mode == true) {
++              clk_set_rate(clks->clk_pxl, pclock/2);
++              clk_set_rate(clks->clk_pxl_link, pclock/2);
++      } else {
++              clk_set_rate(clks->clk_pxl_link, pclock);
++              clk_set_rate(clks->clk_pxl, pclock);
++      }
++      clk_set_rate(clks->clk_pxl_mux, pclock);
++}
++
++static void imx8qm_pixel_clk_rate_change(struct imx_mhdp_device *hdp)
++{
++      /* set pixel clock before video mode setup */
++      imx8qm_pixel_clk_disable(hdp);
++
++      imx8qm_pixel_clk_set_rate(hdp, hdp->mhdp.mode.clock * 1000);
++
++      imx8qm_pixel_clk_enable(hdp);
++
++      /* Config pixel link mux */
++      imx8qm_pixel_link_mux(hdp);
++}
++
++static int imx8qm_ipg_clk_enable(struct imx_mhdp_device *hdp)
++{
++      int ret;
++      struct imx_hdp_clks *clks = &hdp->clks;
++      struct device *dev = hdp->mhdp.dev;
++
++      ret = clk_prepare_enable(clks->dig_pll);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre dig pll error\n", __func__);
++              return ret;
++      }
++
++      ret = clk_prepare_enable(clks->clk_ipg);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre clk_ipg error\n", __func__);
++              return ret;
++      }
++
++      ret = clk_prepare_enable(clks->clk_core);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre clk core error\n", __func__);
++              return ret;
++      }
++
++      ret = clk_prepare_enable(clks->lpcg_apb);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre clk apb error\n", __func__);
++              return ret;
++      }
++      ret = clk_prepare_enable(clks->lpcg_lis);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre clk lis error\n", __func__);
++              return ret;
++      }
++      ret = clk_prepare_enable(clks->lpcg_msi);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre clk msierror\n", __func__);
++              return ret;
++      }
++      ret = clk_prepare_enable(clks->lpcg_apb_csr);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre clk apb csr error\n", __func__);
++              return ret;
++      }
++      ret = clk_prepare_enable(clks->lpcg_apb_ctrl);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre clk apb ctrl error\n", __func__);
++              return ret;
++      }
++      ret = clk_prepare_enable(clks->lpcg_i2s);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre clk i2s error\n", __func__);
++              return ret;
++      }
++      ret = clk_prepare_enable(clks->clk_i2s_bypass);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre clk i2s bypass error\n", __func__);
++              return ret;
++      }
++      return ret;
++}
++
++static void imx8qm_ipg_clk_disable(struct imx_mhdp_device *hdp)
++{
++      struct imx_hdp_clks *clks = &hdp->clks;
++
++      clk_disable_unprepare(clks->clk_i2s_bypass);
++      clk_disable_unprepare(clks->lpcg_i2s);
++      clk_disable_unprepare(clks->lpcg_apb_ctrl);
++      clk_disable_unprepare(clks->lpcg_apb_csr);
++      clk_disable_unprepare(clks->lpcg_msi);
++      clk_disable_unprepare(clks->lpcg_lis);
++      clk_disable_unprepare(clks->lpcg_apb);
++      clk_disable_unprepare(clks->clk_core);
++      clk_disable_unprepare(clks->clk_ipg);
++      clk_disable_unprepare(clks->dig_pll);
++}
++
++static void imx8qm_ipg_clk_set_rate(struct imx_mhdp_device *hdp)
++{
++      struct imx_hdp_clks *clks = &hdp->clks;
++
++      /* ipg/core clock */
++      clk_set_rate(clks->dig_pll,  PLL_800MHZ);
++      clk_set_rate(clks->clk_core, PLL_800MHZ/4);
++      clk_set_rate(clks->clk_ipg,  PLL_800MHZ/8);
++}
++
++static void imx8qm_detach_pm_domains(struct imx_mhdp_device *hdp)
++{
++      if (hdp->pd_pll1_link && !IS_ERR(hdp->pd_pll1_link))
++              device_link_del(hdp->pd_pll1_link);
++      if (hdp->pd_pll1_dev && !IS_ERR(hdp->pd_pll1_dev))
++              dev_pm_domain_detach(hdp->pd_pll1_dev, true);
++
++      if (hdp->pd_pll0_link && !IS_ERR(hdp->pd_pll0_link))
++              device_link_del(hdp->pd_pll0_link);
++      if (hdp->pd_pll0_dev && !IS_ERR(hdp->pd_pll0_dev))
++              dev_pm_domain_detach(hdp->pd_pll0_dev, true);
++
++      if (hdp->pd_mhdp_link && !IS_ERR(hdp->pd_mhdp_link))
++              device_link_del(hdp->pd_mhdp_link);
++      if (hdp->pd_mhdp_dev && !IS_ERR(hdp->pd_mhdp_dev))
++              dev_pm_domain_detach(hdp->pd_mhdp_dev, true);
++
++      hdp->pd_mhdp_dev = NULL;
++      hdp->pd_mhdp_link = NULL;
++      hdp->pd_pll0_dev = NULL;
++      hdp->pd_pll0_link = NULL;
++      hdp->pd_pll1_dev = NULL;
++      hdp->pd_pll1_link = NULL;
++}
++
++static int imx8qm_attach_pm_domains(struct imx_mhdp_device *hdp)
++{
++      struct device *dev = hdp->mhdp.dev;
++      u32 flags = DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE;
++      int ret = 0;
++
++      hdp->pd_mhdp_dev = dev_pm_domain_attach_by_name(dev, "hdmi");
++      if (IS_ERR(hdp->pd_mhdp_dev)) {
++              ret = PTR_ERR(hdp->pd_mhdp_dev);
++              dev_err(dev, "Failed to attach dc pd dev: %d\n", ret);
++              goto fail;
++      }
++      hdp->pd_mhdp_link = device_link_add(dev, hdp->pd_mhdp_dev, flags);
++      if (IS_ERR(hdp->pd_mhdp_link)) {
++              ret = PTR_ERR(hdp->pd_mhdp_link);
++              dev_err(dev, "Failed to add device link to dc pd dev: %d\n",
++                      ret);
++              goto fail;
++      }
++
++      hdp->pd_pll0_dev = dev_pm_domain_attach_by_name(dev, "pll0");
++      if (IS_ERR(hdp->pd_pll0_dev)) {
++              ret = PTR_ERR(hdp->pd_pll0_dev);
++              dev_err(dev, "Failed to attach pll0 pd dev: %d\n", ret);
++              goto fail;
++      }
++      hdp->pd_pll0_link = device_link_add(dev, hdp->pd_pll0_dev, flags);
++      if (IS_ERR(hdp->pd_pll0_link)) {
++              ret = PTR_ERR(hdp->pd_pll0_link);
++              dev_err(dev, "Failed to add device link to pll0 pd dev: %d\n",
++                      ret);
++              goto fail;
++      }
++
++      hdp->pd_pll1_dev = dev_pm_domain_attach_by_name(dev, "pll1");
++      if (IS_ERR(hdp->pd_pll1_dev)) {
++              ret = PTR_ERR(hdp->pd_pll1_dev);
++              dev_err(dev, "Failed to attach pll0 pd dev: %d\n", ret);
++              goto fail;
++      }
++      hdp->pd_pll1_link = device_link_add(dev, hdp->pd_pll1_dev, flags);
++      if (IS_ERR(hdp->pd_pll1_link)) {
++              ret = PTR_ERR(hdp->pd_pll1_link);
++              dev_err(dev, "Failed to add device link to pll1 pd dev: %d\n",
++                      ret);
++              goto fail;
++      }
++fail:
++      imx8qm_detach_pm_domains(hdp);
++      return ret;
++}
++
++static int imx8qm_firmware_init(struct imx_mhdp_device *hdp)
++{
++      u32 rate;
++      int ret;
++
++      /* Power on PM Domains */
++      imx8qm_attach_pm_domains(hdp);
++
++      /* clock init and  rate set */
++      imx8qm_clocks_init(hdp);
++
++      imx8qm_ipg_clk_set_rate(hdp);
++
++      /* Init pixel clock with 148.5MHz before FW init */
++      imx8qm_pixel_clk_set_rate(hdp, 148500000);
++
++      imx8qm_ipg_clk_enable(hdp);
++
++      imx8qm_clk_mux(hdp->plat_data->is_dp);
++
++      imx8qm_pixel_clk_enable(hdp);
++
++      imx8qm_phy_reset(1);
++
++      hdp->csr_pxl_mux_reg = 0;
++      hdp->csr_ctrl0_reg = 0x8;
++      hdp->csr_ctrl0_sec = 0xc;
++      /* iMX8QM HDP register, Remap HPD memory address to low 4K */
++      regmap_write(hdp->regmap_csr, hdp->csr_ctrl0_reg, 0);
++
++      /* configure HDMI/DP core clock */
++      rate = clk_get_rate(hdp->clks.clk_core);
++      cdns_mhdp_set_fw_clk(&hdp->mhdp, rate);
++
++      /* un-reset ucpu */
++      writel(0,  (APB_CTRL << 2) + hdp->mhdp.regs);
++      DRM_INFO("Started firmware!\n");
++
++      ret = cdns_mhdp_check_alive(&hdp->mhdp);
++      if (ret == false) {
++              DRM_ERROR("NO HDMI FW running\n");
++              return -ENXIO;
++      }
++
++      /* turn on IP activity */
++      cdns_mhdp_set_firmware_active(&hdp->mhdp, 1);
++
++      DRM_INFO("HDP FW Version - ver %d verlib %d\n",
++                      __raw_readb(VER_L + hdp->mhdp.regs) + (__raw_readb(VER_H + hdp->mhdp.regs) << 8),
++      __raw_readb(VER_LIB_L_ADDR + hdp->mhdp.regs) + (__raw_readb(VER_LIB_H_ADDR + hdp->mhdp.regs) << 8));
++
++      return 0;
++}
++
++static void cdns_hdmi_imx_encoder_disable(struct drm_encoder *encoder)
++{
++      struct imx_mhdp_device *hdp = encoder->bridge->driver_private;
++
++      imx8qm_pixel_link_sync_disable(hdp->dual_mode);
++      imx8qm_pixel_link_invalid(hdp->dual_mode);
++}
++
++static void cdns_hdmi_imx_encoder_enable(struct drm_encoder *encoder)
++{
++      struct imx_mhdp_device *hdp = encoder->bridge->driver_private;
++
++      imx8qm_pixel_link_valid(hdp->dual_mode);
++      imx8qm_pixel_link_sync_enable(hdp->dual_mode);
++}
++
++static int cdns_hdmi_imx_encoder_atomic_check(struct drm_encoder *encoder,
++                                  struct drm_crtc_state *crtc_state,
++                                  struct drm_connector_state *conn_state)
++{
++      struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
++
++      imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB101010_1X30;
++      return 0;
++}
++
++static const struct drm_encoder_helper_funcs cdns_hdmi_imx_encoder_helper_funcs = {
++      .enable     = cdns_hdmi_imx_encoder_enable,
++      .disable    = cdns_hdmi_imx_encoder_disable,
++      .atomic_check = cdns_hdmi_imx_encoder_atomic_check,
++};
++
++static const struct drm_encoder_funcs cdns_hdmi_imx_encoder_funcs = {
++      .destroy = drm_encoder_cleanup,
++};
++
++#if 0
++static struct cdn_plat_data imx8mq_hdmi_drv_data = {
++      .bind   = cdns_hdmi_bind,
++      .unbind = cdns_hdmi_unbind,
++      .phy_init = cdns_hdmi_phy_set_imx8mq,
++};
++
++static struct cdn_plat_data imx8mq_dp_drv_data = {
++      .bind   = cdns_dp_bind,
++      .unbind = cdns_dp_unbind,
++      .phy_init = cdns_dp_phy_init_imx8mq,
++};
++#endif
++
++static struct cdn_plat_data imx8qm_hdmi_drv_data = {
++      .bind   = cdns_hdmi_bind,
++      .unbind = cdns_hdmi_unbind,
++      .phy_init = cdns_hdmi_phy_set_imx8qm,
++      .fw_init = imx8qm_firmware_init,
++      .pclock_change = imx8qm_pixel_clk_rate_change,
++};
++
++static struct cdn_plat_data imx8qm_dp_drv_data = {
++      .bind   = cdns_dp_bind,
++      .unbind = cdns_dp_unbind,
++      .phy_init = cdns_dp_phy_init_imx8qm,
++      .fw_init = imx8qm_firmware_init,
++      .pclock_change = imx8qm_pixel_clk_rate_change,
++      .is_dp = true,
++};
++
++static const struct of_device_id cdns_hdmi_imx_dt_ids[] = {
++#if 0
++      { .compatible = "cdn,imx8mq-hdmi",
++        .data = &imx8mq_hdmi_drv_data
++      },
++      { .compatible = "cdn,imx8mq-dp",
++        .data = &imx8mq_dp_drv_data
++      },
++#endif
++      { .compatible = "cdn,imx8qm-hdmi",
++        .data = &imx8qm_hdmi_drv_data
++      },
++      { .compatible = "cdn,imx8qm-dp",
++        .data = &imx8qm_dp_drv_data
++      },
++      {},
++};
++MODULE_DEVICE_TABLE(of, cdns_hdmi_imx_dt_ids);
++
++static int cdns_hdmi_imx_bind(struct device *dev, struct device *master,
++                          void *data)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++      const struct cdn_plat_data *plat_data;
++      const struct of_device_id *match;
++      struct drm_device *drm = data;
++      struct drm_encoder *encoder;
++      struct imx_hdmi *hdmi;
++      int ret;
++
++      if (!pdev->dev.of_node)
++              return -ENODEV;
++
++      hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
++      if (!hdmi)
++              return -ENOMEM;
++
++      match = of_match_node(cdns_hdmi_imx_dt_ids, pdev->dev.of_node);
++      plat_data = match->data;
++      hdmi->dev = &pdev->dev;
++      encoder = &hdmi->encoder;
++
++      encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
++      /*
++       * If we failed to find the CRTC(s) which this encoder is
++       * supposed to be connected to, it's because the CRTC has
++       * not been registered yet.  Defer probing, and hope that
++       * the required CRTC is added later.
++       */
++      if (encoder->possible_crtcs == 0)
++              return -EPROBE_DEFER;
++
++      drm_encoder_helper_add(encoder, &cdns_hdmi_imx_encoder_helper_funcs);
++      drm_encoder_init(drm, encoder, &cdns_hdmi_imx_encoder_funcs,
++                       DRM_MODE_ENCODER_TMDS, NULL);
++
++      ret = plat_data->bind(pdev, encoder, plat_data);
++
++      /*
++       * If cdns_hdmi_bind() fails we'll never call cdns_hdmi_unbind(),
++       * which would have called the encoder cleanup.  Do it manually.
++       */
++      if (ret)
++              drm_encoder_cleanup(encoder);
++
++      return ret;
++}
++
++static void cdns_hdmi_imx_unbind(struct device *dev, struct device *master,
++                             void *data)
++{
++      struct imx_mhdp_device *hdp = dev_get_drvdata(dev);
++
++      hdp->plat_data->unbind(dev);
++}
++
++static const struct component_ops cdns_hdmi_imx8qm_ops = {
++      .bind   = cdns_hdmi_imx_bind,
++      .unbind = cdns_hdmi_imx_unbind,
++};
++
++static int cdns_hdmi_imx_probe(struct platform_device *pdev)
++{
++      return component_add(&pdev->dev, &cdns_hdmi_imx8qm_ops);
++}
++
++static int cdns_hdmi_imx_remove(struct platform_device *pdev)
++{
++      component_del(&pdev->dev, &cdns_hdmi_imx8qm_ops);
++
++      return 0;
++}
++
++static struct platform_driver cdns_hdmi_imx_platform_driver = {
++      .probe  = cdns_hdmi_imx_probe,
++      .remove = cdns_hdmi_imx_remove,
++      .driver = {
++              .name = "cdn-hdp-imx8qm",
++              .of_match_table = cdns_hdmi_imx_dt_ids,
++      },
++};
++
++module_platform_driver(cdns_hdmi_imx_platform_driver);
++
++MODULE_AUTHOR("Sandor YU <sandor.yu@nxp.com>");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:cdnhdmi-imx");
+--- /dev/null
++++ b/drivers/gpu/drm/imx/cdn-mhdp-phy.h
+@@ -0,0 +1,153 @@
++/*
++ * Copyright (C) 2019 NXP Semiconductor, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#ifndef _CDN_DP_PHY_H
++#define _CDN_DP_PHY_H
++
++#include <drm/bridge/cdns-mhdp-imx.h>
++
++#define CMN_SSM_BIAS_TMR                0x0022
++#define CMN_PLLSM0_PLLEN_TMR            0x0029
++#define CMN_PLLSM0_PLLPRE_TMR           0x002A
++#define CMN_PLLSM0_PLLVREF_TMR          0x002B
++#define CMN_PLLSM0_PLLLOCK_TMR          0x002C
++#define CMN_PLLSM0_USER_DEF_CTRL        0x002F
++#define CMN_PSM_CLK_CTRL                0x0061
++#define CMN_CDIAG_REFCLK_CTRL           0x0062
++#define CMN_PLL0_VCOCAL_START           0x0081
++#define CMN_PLL0_VCOCAL_INIT_TMR        0x0084
++#define CMN_PLL0_VCOCAL_ITER_TMR        0x0085
++#define CMN_PLL0_INTDIV                 0x0094
++#define CMN_PLL0_FRACDIV                0x0095
++#define CMN_PLL0_HIGH_THR               0x0096
++#define CMN_PLL0_DSM_DIAG               0x0097
++#define CMN_PLL0_SS_CTRL1               0x0098
++#define CMN_PLL0_SS_CTRL2               0x0099
++#define CMN_ICAL_INIT_TMR               0x00C4
++#define CMN_ICAL_ITER_TMR               0x00C5
++#define CMN_RXCAL_INIT_TMR              0x00D4
++#define CMN_RXCAL_ITER_TMR              0x00D5
++#define CMN_TXPUCAL_CTRL                0x00E0
++#define CMN_TXPUCAL_INIT_TMR            0x00E4
++#define CMN_TXPUCAL_ITER_TMR            0x00E5
++#define CMN_TXPDCAL_CTRL                0x00F0
++#define CMN_TXPDCAL_INIT_TMR            0x00F4
++#define CMN_TXPDCAL_ITER_TMR            0x00F5
++#define CMN_ICAL_ADJ_INIT_TMR           0x0102
++#define CMN_ICAL_ADJ_ITER_TMR           0x0103
++#define CMN_RX_ADJ_INIT_TMR             0x0106
++#define CMN_RX_ADJ_ITER_TMR             0x0107
++#define CMN_TXPU_ADJ_CTRL               0x0108
++#define CMN_TXPU_ADJ_INIT_TMR           0x010A
++#define CMN_TXPU_ADJ_ITER_TMR           0x010B
++#define CMN_TXPD_ADJ_CTRL               0x010c
++#define CMN_TXPD_ADJ_INIT_TMR           0x010E
++#define CMN_TXPD_ADJ_ITER_TMR           0x010F
++#define CMN_DIAG_PLL0_FBH_OVRD          0x01C0
++#define CMN_DIAG_PLL0_FBL_OVRD          0x01C1
++#define CMN_DIAG_PLL0_OVRD              0x01C2
++#define CMN_DIAG_PLL0_TEST_MODE         0x01C4
++#define CMN_DIAG_PLL0_V2I_TUNE          0x01C5
++#define CMN_DIAG_PLL0_CP_TUNE           0x01C6
++#define CMN_DIAG_PLL0_LF_PROG           0x01C7
++#define CMN_DIAG_PLL0_PTATIS_TUNE1      0x01C8
++#define CMN_DIAG_PLL0_PTATIS_TUNE2      0x01C9
++#define CMN_DIAG_PLL0_INCLK_CTRL        0x01CA
++#define CMN_DIAG_PLL0_PXL_DIVH          0x01CB
++#define CMN_DIAG_PLL0_PXL_DIVL          0x01CC
++#define CMN_DIAG_HSCLK_SEL              0x01E0
++#define CMN_DIAG_PER_CAL_ADJ            0x01EC
++#define CMN_DIAG_CAL_CTRL               0x01ED
++#define CMN_DIAG_ACYA                   0x01FF
++#define XCVR_PSM_RCTRL                  0x4001
++#define XCVR_PSM_CAL_TMR                0x4002
++#define XCVR_PSM_A0IN_TMR               0x4003
++#define TX_TXCC_CAL_SCLR_MULT_0         0x4047
++#define TX_TXCC_CPOST_MULT_00_0         0x404C
++#define TX_TXCC_MGNFS_MULT_000_0        0x4050
++#define XCVR_DIAG_PLLDRC_CTRL           0x40E0
++#define XCVR_DIAG_PLLDRC_CTRL           0x40E0
++#define XCVR_DIAG_HSCLK_SEL             0x40E1
++#define XCVR_DIAG_BIDI_CTRL             0x40E8
++#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR   0x40F2
++#define XCVR_DIAG_LANE_FCM_EN_MGN       0x40F2
++#define TX_PSC_A0                       0x4100
++#define TX_PSC_A1                       0x4101
++#define TX_PSC_A2                       0x4102
++#define TX_PSC_A3                       0x4103
++#define TX_RCVDET_CTRL                  0x4120
++#define TX_RCVDET_EN_TMR                0x4122
++#define TX_RCVDET_EN_TMR                0x4122
++#define TX_RCVDET_ST_TMR                0x4123
++#define TX_RCVDET_ST_TMR                0x4123
++#define TX_BIST_CTRL                    0x4140
++#define TX_BIST_UDDWR                   0x4141
++#define TX_DIAG_TX_CTRL                 0x41E0
++#define TX_DIAG_TX_DRV                  0x41E1
++#define TX_DIAG_BGREF_PREDRV_DELAY      0x41E7
++#define TX_DIAG_BGREF_PREDRV_DELAY      0x41E7
++#define XCVR_PSM_RCTRL_1                0x4201
++#define TX_TXCC_CAL_SCLR_MULT_1         0x4247
++#define TX_TXCC_CPOST_MULT_00_1         0x424C
++#define TX_TXCC_MGNFS_MULT_000_1        0x4250
++#define XCVR_DIAG_PLLDRC_CTRL_1         0x42E0
++#define XCVR_DIAG_HSCLK_SEL_1           0x42E1
++#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_1 0x42F2
++#define TX_RCVDET_EN_TMR_1              0x4322
++#define TX_RCVDET_ST_TMR_1              0x4323
++#define TX_DIAG_ACYA_0                  0x41FF
++#define TX_DIAG_ACYA_1                  0x43FF
++#define TX_DIAG_ACYA_2                  0x45FF
++#define TX_DIAG_ACYA_3                  0x47FF
++#define TX_ANA_CTRL_REG_1               0x5020
++#define TX_ANA_CTRL_REG_2               0x5021
++#define TXDA_COEFF_CALC                 0x5022
++#define TX_DIG_CTRL_REG_1               0x5023
++#define TX_DIG_CTRL_REG_2               0x5024
++#define TXDA_CYA_AUXDA_CYA              0x5025
++#define TX_ANA_CTRL_REG_3               0x5026
++#define TX_ANA_CTRL_REG_4               0x5027
++#define TX_ANA_CTRL_REG_5               0x5029
++#define RX_PSC_A0                       0x8000
++#define RX_PSC_CAL                      0x8006
++#define PMA_LANE_CFG                    0xC000
++#define PIPE_CMN_CTRL1                  0xC001
++#define PIPE_CMN_CTRL2                  0xC002
++#define PIPE_COM_LOCK_CFG1              0xC003
++#define PIPE_COM_LOCK_CFG2              0xC004
++#define PIPE_RCV_DET_INH                0xC005
++#define PHY_HDP_MODE_CTRL               0xC008
++#define PHY_HDP_CLK_CTL                 0xC009
++#define STS                             0xC00F
++#define PHY_ISO_CMN_CTRL                0xC010
++#define PHY_ISO_CMN_CTRL                0xC010
++#define PHY_HDP_TX_CTL_L0               0xC408
++#define PHY_DP_TX_CTL                   0xC408
++#define PHY_HDP_TX_CTL_L1               0xC448
++#define PHY_HDP_TX_CTL_L2               0xC488
++#define PHY_HDP_TX_CTL_L3               0xC4C8
++#define PHY_PMA_CMN_CTRL1               0xC800
++#define PMA_CMN_CTRL1                   0xC800
++#define PHY_PMA_ISO_CMN_CTRL            0xC810
++#define PHY_PMA_ISO_PLL_CTRL1           0xC812
++#define PHY_PMA_ISOLATION_CTRL          0xC81F
++#define PHY_ISOLATION_CTRL              0xC81F
++#define PHY_PMA_ISO_XCVR_CTRL           0xCC11
++#define PHY_PMA_ISO_LINK_MODE           0xCC12
++#define PHY_PMA_ISO_PWRST_CTRL          0xCC13
++#define PHY_PMA_ISO_TX_DATA_LO          0xCC14
++#define PHY_PMA_ISO_TX_DATA_HI          0xCC15
++#define PHY_PMA_ISO_RX_DATA_LO          0xCC16
++#define PHY_PMA_ISO_RX_DATA_HI          0xCC17
++
++int cdns_dp_phy_init_imx8mq(struct imx_mhdp_device *hdp);
++int cdns_dp_phy_init_imx8qm(struct imx_mhdp_device *hdp);
++int cdns_hdmi_phy_set_imx8mq(struct imx_mhdp_device *hdp);
++int cdns_hdmi_phy_set_imx8qm(struct imx_mhdp_device *hdp);
++#endif /* _CDN_DP_PHY_H */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0006-drm-bridge-cadence-Add-new-api-functions.patch b/target/linux/layerscape/patches-5.4/805-display-0006-drm-bridge-cadence-Add-new-api-functions.patch
new file mode 100644 (file)
index 0000000..d41acfe
--- /dev/null
@@ -0,0 +1,864 @@
+From ae4d4a1aa913eaafe72b252cfe93f6fad68b39f2 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Fri, 30 Aug 2019 15:02:13 +0800
+Subject: [PATCH] drm: bridge: cadence: Add new api functions
+
+Add variable lane_mapping for hdmi.
+Add new API function cdns_mhdp_bus_read/cdns_mhdp_bus_write,
+cdns_mhdp_get_fw_clk and cdns_mhdp_infoframe_set.
+Adjust some API function interface.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c     |  34 ++---
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c   | 131 +++++------------
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c | 167 +++++++++++++++-------
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c   |  36 +++++
+ include/drm/bridge/cdns-mhdp-common.h             |  16 ++-
+ 5 files changed, 219 insertions(+), 165 deletions(-)
+ mode change 100644 => 100755 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+ mode change 100644 => 100755 drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+ mode change 100644 => 100755 drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
+ mode change 100644 => 100755 drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
+ mode change 100644 => 100755 include/drm/bridge/cdns-mhdp-common.h
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -116,7 +116,7 @@ static void cdns_dp_mode_set(struct imx_
+ {
+       struct drm_dp_link link;
+       struct cdns_mhdp_device *mhdp = &dp->mhdp;
+-      u32 lane_mapping = mhdp->dp.lane_mapping;
++      u32 lane_mapping = mhdp->lane_mapping;
+       int ret;
+       char linkid[6];
+@@ -405,12 +405,12 @@ static void cdns_dp_parse_dt(struct cdns
+       int ret;
+       ret = of_property_read_u32(of_node, "lane-mapping",
+-                                              &mhdp->dp.lane_mapping);
++                                              &mhdp->lane_mapping);
+       if (ret) {
+-              mhdp->dp.lane_mapping = 0xc6;
++              mhdp->lane_mapping = 0xc6;
+               dev_warn(mhdp->dev, "Failed to get lane_mapping - using default 0xc6\n");
+       }
+-      dev_info(mhdp->dev, "lane-mapping 0x%02x\n", mhdp->dp.lane_mapping);
++      dev_info(mhdp->dev, "lane-mapping 0x%02x\n", mhdp->lane_mapping);
+       ret = of_property_read_u32(of_node, "link-rate", &mhdp->dp.link_rate);
+       if (ret) {
+@@ -470,11 +470,11 @@ __cdns_dp_probe(struct platform_device *
+       dp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
+       if (dp->irq[IRQ_IN] < 0)
+-              dev_info(&pdev->dev, "No plug_in irq number\n");
++              dev_info(dev, "No plug_in irq number\n");
+       dp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
+       if (dp->irq[IRQ_OUT] < 0)
+-              dev_info(&pdev->dev, "No plug_out irq number\n");
++              dev_info(dev, "No plug_out irq number\n");
+       cdns_dp_parse_dt(&dp->mhdp);
+@@ -498,7 +498,7 @@ __cdns_dp_probe(struct platform_device *
+                                       IRQF_ONESHOT, dev_name(dev),
+                                       dp);
+       if (ret) {
+-              dev_err(&pdev->dev, "can't claim irq %d\n",
++              dev_err(dev, "can't claim irq %d\n",
+                                               dp->irq[IRQ_IN]);
+               goto err_out;
+       }
+@@ -509,7 +509,7 @@ __cdns_dp_probe(struct platform_device *
+                                       IRQF_ONESHOT, dev_name(dev),
+                                       dp);
+       if (ret) {
+-              dev_err(&pdev->dev, "can't claim irq %d\n",
++              dev_err(dev, "can't claim irq %d\n",
+                                               dp->irq[IRQ_OUT]);
+               goto err_out;
+       }
+@@ -521,10 +521,10 @@ __cdns_dp_probe(struct platform_device *
+       dp->mhdp.bridge.base.driver_private = dp;
+       dp->mhdp.bridge.base.funcs = &cdns_dp_bridge_funcs;
+ #ifdef CONFIG_OF
+-      dp->mhdp.bridge.base.of_node = pdev->dev.of_node;
++      dp->mhdp.bridge.base.of_node = dev->of_node;
+ #endif
+-      platform_set_drvdata(pdev, dp);
++      dev_set_drvdata(dev, &dp->mhdp);
+       
+       dp_aux_init(&dp->mhdp, dev);
+@@ -534,9 +534,9 @@ err_out:
+       return ERR_PTR(ret);
+ }
+-static void __cdns_dp_remove(struct imx_mhdp_device *dp)
++static void __cdns_dp_remove(struct cdns_mhdp_device *mhdp)
+ {
+-      dp_aux_destroy(&dp->mhdp);
++      dp_aux_destroy(mhdp);
+ }
+ /* -----------------------------------------------------------------------------
+@@ -559,11 +559,11 @@ EXPORT_SYMBOL_GPL(cdns_dp_probe);
+ void cdns_dp_remove(struct platform_device *pdev)
+ {
+-      struct imx_mhdp_device *dp = platform_get_drvdata(pdev);
++      struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev);
+-      drm_bridge_remove(&dp->mhdp.bridge.base);
++      drm_bridge_remove(&mhdp->bridge.base);
+-      __cdns_dp_remove(dp);
++      __cdns_dp_remove(mhdp);
+ }
+ EXPORT_SYMBOL_GPL(cdns_dp_remove);
+@@ -593,9 +593,9 @@ EXPORT_SYMBOL_GPL(cdns_dp_bind);
+ void cdns_dp_unbind(struct device *dev)
+ {
+-      struct imx_mhdp_device *dp = dev_get_drvdata(dev);
++      struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+-      __cdns_dp_remove(dp);
++      __cdns_dp_remove(mhdp);
+ }
+ EXPORT_SYMBOL_GPL(cdns_dp_unbind);
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -25,25 +25,8 @@
+ #include <linux/module.h>
+ #include <linux/mfd/syscon.h>
+ #include <linux/mutex.h>
+-#include <linux/regmap.h>
+ #include <linux/of_device.h>
+-static void hdmi_writel(struct cdns_mhdp_device *mhdp, u32 val, u32 offset)
+-{
+-      struct imx_mhdp_device *hdmi = container_of(mhdp, struct imx_mhdp_device, mhdp);
+-
+-      /* TODO */
+-      if (offset >= 0x1000 && hdmi->regmap_csr) {
+-              /* Remap address to low 4K memory */
+-              regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, offset >> 12);
+-              writel(val, (offset & 0xfff) + mhdp->regs);
+-              /* Restore address mapping */
+-              regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, 0);
+-
+-      } else
+-              writel(val, mhdp->regs + offset);
+-}
+-
+ static int hdmi_sink_config(struct cdns_mhdp_device *mhdp)
+ {
+       struct drm_scdc *scdc = &mhdp->connector.base.display_info.hdmi.scdc;
+@@ -75,65 +58,12 @@ static int hdmi_sink_config(struct cdns_
+       return ret;
+ }
+-static int hdmi_lanes_config(struct cdns_mhdp_device *mhdp)
+-{
+-      int ret;
+-
+-      /* TODO */
+-      /* Set the lane swapping */
+-//    if (cpu_is_imx8qm())
+-              ret = cdns_mhdp_reg_write(mhdp, LANES_CONFIG,
+-                                                  F_SOURCE_PHY_LANE0_SWAP(3) |
+-                                                  F_SOURCE_PHY_LANE1_SWAP(0) |
+-                                                  F_SOURCE_PHY_LANE2_SWAP(1) |
+-                                                  F_SOURCE_PHY_LANE3_SWAP(2) |
+-                                                  F_SOURCE_PHY_COMB_BYPASS(0) |
+-                                                      F_SOURCE_PHY_20_10(1));
+-#if 0
+-      else
+-              ret = cdns_mhdp_reg_write(mhdp, LANES_CONFIG,
+-                                                  F_SOURCE_PHY_LANE0_SWAP(0) |
+-                                                  F_SOURCE_PHY_LANE1_SWAP(1) |
+-                                                  F_SOURCE_PHY_LANE2_SWAP(2) |
+-                                                  F_SOURCE_PHY_LANE3_SWAP(3) |
+-                                                  F_SOURCE_PHY_COMB_BYPASS(0) |
+-                                                      F_SOURCE_PHY_20_10(1));
+-#endif
+-      return ret;
+-}
+-
+-static void hdmi_info_frame_set(struct cdns_mhdp_device *mhdp,
+-                                      u8 entry_id, u8 packet_len, u8 *packet, u8 packet_type)
++static void hdmi_lanes_config(struct cdns_mhdp_device *mhdp)
+ {
+-      u32 *packet32, len32;
+-      u32 val, i;
+-
+-      /* invalidate entry */
+-      val = F_ACTIVE_IDLE_TYPE(1) | F_PKT_ALLOC_ADDRESS(entry_id);
+-      hdmi_writel(mhdp, val, SOURCE_PIF_PKT_ALLOC_REG);
+-      hdmi_writel(mhdp, F_PKT_ALLOC_WR_EN(1), SOURCE_PIF_PKT_ALLOC_WR_EN);
+-
+-      /* flush fifo 1 */
+-      hdmi_writel(mhdp, F_FIFO1_FLUSH(1), SOURCE_PIF_FIFO1_FLUSH);
+-
+-      /* write packet into memory */
+-      packet32 = (u32 *)packet;
+-      len32 = packet_len / 4;
+-      for (i = 0; i < len32; i++)
+-              hdmi_writel(mhdp, F_DATA_WR(packet32[i]), SOURCE_PIF_DATA_WR);
+-
+-      /* write entry id */
+-      hdmi_writel(mhdp, F_WR_ADDR(entry_id), SOURCE_PIF_WR_ADDR);
+-
+-      /* write request */
+-      hdmi_writel(mhdp, F_HOST_WR(1), SOURCE_PIF_WR_REQ);
+-
+-      /* update entry */
+-      val =  F_ACTIVE_IDLE_TYPE(1) | F_TYPE_VALID(1) |
+-                      F_PACKET_TYPE(packet_type) | F_PKT_ALLOC_ADDRESS(entry_id);
+-      hdmi_writel(mhdp, val, SOURCE_PIF_PKT_ALLOC_REG);
+-
+-      hdmi_writel(mhdp, F_PKT_ALLOC_WR_EN(1), SOURCE_PIF_PKT_ALLOC_WR_EN);
++      /* Line swaping */
++      /* For imx8qm lane_mapping = 0x93
++       * For imx8mq lane_mapping = 0xe4*/
++      cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | mhdp->lane_mapping);
+ }
+ #define RGB_ALLOWED_COLORIMETRY (BIT(HDMI_EXTENDED_COLORIMETRY_BT2020) |\
+@@ -148,9 +78,11 @@ static int hdmi_avi_info_set(struct cdns
+                               struct drm_display_mode *mode)
+ {
+       struct hdmi_avi_infoframe frame;
+-//    struct drm_display_info *di = &mhdp->connector.base.display_info;
+-//    enum hdmi_extended_colorimetry ext_col;
+-//    u32 sink_col, allowed_col;
++#if 0
++      struct drm_display_info *di = &mhdp->connector.base.display_info;
++      enum hdmi_extended_colorimetry ext_col;
++      u32 sink_col, allowed_col;
++#endif
+       int format = mhdp->video_info.color_fmt;
+       u8 buf[32];
+       int ret;
+@@ -209,7 +141,7 @@ static int hdmi_avi_info_set(struct cdns
+       }
+       buf[0] = 0;
+-      hdmi_info_frame_set(mhdp, 0, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_AVI);
++      cdns_mhdp_infoframe_set(mhdp, 0, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_AVI);
+       return 0;
+ }
+@@ -234,7 +166,7 @@ static int hdmi_vendor_info_set(struct c
+       }
+       buf[0] = 0;
+-      hdmi_info_frame_set(mhdp, 3, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_VENDOR);
++      cdns_mhdp_infoframe_set(mhdp, 3, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_VENDOR);
+       return 0;
+ }
+@@ -464,6 +396,19 @@ static irqreturn_t cdns_hdmi_irq_thread(
+       return IRQ_HANDLED;
+ }
++static void cdns_hdmi_parse_dt(struct cdns_mhdp_device *mhdp)
++{
++      struct device_node *of_node = mhdp->dev->of_node;
++      int ret;
++
++      ret = of_property_read_u32(of_node, "lane-mapping", &mhdp->lane_mapping);
++      if (ret) {
++              mhdp->lane_mapping = 0xc6;
++              dev_warn(mhdp->dev, "Failed to get lane_mapping - using default 0xc6\n");
++      }
++      dev_info(mhdp->dev, "lane-mapping 0x%02x\n", mhdp->lane_mapping);
++}
++
+ static struct imx_mhdp_device *
+ __cdns_hdmi_probe(struct platform_device *pdev,
+                       const struct cdn_plat_data *plat_data)
+@@ -503,13 +448,13 @@ __cdns_hdmi_probe(struct platform_device
+       hdmi->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
+       if (hdmi->irq[IRQ_IN] < 0) {
+-              dev_info(&pdev->dev, "No plug_in irq number\n");
++              dev_info(dev, "No plug_in irq number\n");
+               return ERR_PTR(-EPROBE_DEFER);
+       }
+       hdmi->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
+       if (hdmi->irq[IRQ_OUT] < 0) {
+-              dev_info(&pdev->dev, "No plug_out irq number\n");
++              dev_info(dev, "No plug_out irq number\n");
+               return ERR_PTR(-EPROBE_DEFER);
+       }
+@@ -533,7 +478,7 @@ __cdns_hdmi_probe(struct platform_device
+                                       IRQF_ONESHOT, dev_name(dev),
+                                       hdmi);
+       if (ret) {
+-              dev_err(&pdev->dev, "can't claim irq %d\n",
++              dev_err(dev, "can't claim irq %d\n",
+                                               hdmi->irq[IRQ_IN]);
+               goto err_out;
+       }
+@@ -544,11 +489,13 @@ __cdns_hdmi_probe(struct platform_device
+                                       IRQF_ONESHOT, dev_name(dev),
+                                       hdmi);
+       if (ret) {
+-              dev_err(&pdev->dev, "can't claim irq %d\n",
++              dev_err(dev, "can't claim irq %d\n",
+                                               hdmi->irq[IRQ_OUT]);
+               goto err_out;
+       }
++      cdns_hdmi_parse_dt(&hdmi->mhdp);
++
+       if (cdns_mhdp_read_hpd(&hdmi->mhdp))
+               enable_irq(hdmi->irq[IRQ_OUT]);
+       else
+@@ -557,14 +504,14 @@ __cdns_hdmi_probe(struct platform_device
+       hdmi->mhdp.bridge.base.driver_private = hdmi;
+       hdmi->mhdp.bridge.base.funcs = &cdns_hdmi_bridge_funcs;
+ #ifdef CONFIG_OF
+-      hdmi->mhdp.bridge.base.of_node = pdev->dev.of_node;
++      hdmi->mhdp.bridge.base.of_node = dev->of_node;
+ #endif
+       memset(&pdevinfo, 0, sizeof(pdevinfo));
+       pdevinfo.parent = dev;
+       pdevinfo.id = PLATFORM_DEVID_AUTO;
+-      platform_set_drvdata(pdev, hdmi);
++      dev_set_drvdata(dev, &hdmi->mhdp);
+       return hdmi;
+@@ -573,7 +520,7 @@ err_out:
+       return ERR_PTR(ret);
+ }
+-static void __cdns_hdmi_remove(struct imx_mhdp_device *hdmi)
++static void __cdns_hdmi_remove(struct cdns_mhdp_device *mhdp)
+ {
+ }
+@@ -597,11 +544,11 @@ EXPORT_SYMBOL_GPL(cdns_hdmi_probe);
+ void cdns_hdmi_remove(struct platform_device *pdev)
+ {
+-      struct imx_mhdp_device *hdmi = platform_get_drvdata(pdev);
++      struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev);
+-      drm_bridge_remove(&hdmi->mhdp.bridge.base);
++      drm_bridge_remove(&mhdp->bridge.base);
+-      __cdns_hdmi_remove(hdmi);
++      __cdns_hdmi_remove(mhdp);
+ }
+ EXPORT_SYMBOL_GPL(cdns_hdmi_remove);
+@@ -631,9 +578,9 @@ EXPORT_SYMBOL_GPL(cdns_hdmi_bind);
+ void cdns_hdmi_unbind(struct device *dev)
+ {
+-      struct imx_mhdp_device *hdmi = dev_get_drvdata(dev);
++      struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+-      __cdns_hdmi_remove(hdmi);
++      __cdns_hdmi_remove(mhdp);
+ }
+ EXPORT_SYMBOL_GPL(cdns_hdmi_unbind);
+--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
+@@ -23,8 +23,10 @@
+ #include <asm/unaligned.h>
+ #include <drm/bridge/cdns-mhdp-common.h>
++#include <drm/bridge/cdns-mhdp-imx.h>
+ #include <drm/drm_modes.h>
+ #include <drm/drm_print.h>
++#include <linux/regmap.h>
+ #define CDNS_DP_SPDIF_CLK             200000000
+ #define FW_ALIVE_TIMEOUT_US           1000000
+@@ -33,6 +35,27 @@
+ #define LINK_TRAINING_RETRY_MS                20
+ #define LINK_TRAINING_TIMEOUT_MS      500
++#define mhdp_readx_poll_timeout(op, addr, offset, val, cond, sleep_us, timeout_us)    \
++({ \
++      u64 __timeout_us = (timeout_us); \
++      unsigned long __sleep_us = (sleep_us); \
++      ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \
++      might_sleep_if((__sleep_us) != 0); \
++      for (;;) { \
++              (val) = op(addr, offset); \
++              if (cond) \
++                      break; \
++              if (__timeout_us && \
++                  ktime_compare(ktime_get(), __timeout) > 0) { \
++                      (val) = op(addr, offset); \
++                      break; \
++              } \
++              if (__sleep_us) \
++                      usleep_range((__sleep_us >> 2) + 1, __sleep_us); \
++      } \
++      (cond) ? 0 : -ETIMEDOUT; \
++})
++
+ static inline u32 get_unaligned_be24(const void *p)
+ {
+       const u8 *_p = p;
+@@ -49,9 +72,51 @@ static inline void put_unaligned_be24(u3
+       _p[2] = val;
+ }
++u32 cdns_mhdp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset)
++{
++      struct imx_mhdp_device *hdmi = container_of(mhdp, struct imx_mhdp_device, mhdp);
++      u32 val;
++
++      /* TODO */
++      if (offset >= 0x1000 && hdmi->regmap_csr) {
++              /* Remap address to low 4K memory */
++              regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, offset >> 12);
++              val = readl((offset & 0xfff) + mhdp->regs);
++              /* Restore address mapping */
++              regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, 0);
++      } else
++              val = readl(mhdp->regs + offset);
++
++      return val;
++}
++EXPORT_SYMBOL(cdns_mhdp_bus_read);
++
++void cdns_mhdp_bus_write(u32 val, struct cdns_mhdp_device *mhdp, u32 offset)
++{
++      struct imx_mhdp_device *hdmi = container_of(mhdp, struct imx_mhdp_device, mhdp);
++
++      /* TODO */
++      if (offset >= 0x1000 && hdmi->regmap_csr) {
++              /* Remap address to low 4K memory */
++              regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, offset >> 12);
++              writel(val, (offset & 0xfff) + mhdp->regs);
++              /* Restore address mapping */
++              regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, 0);
++
++      } else
++              writel(val, mhdp->regs + offset);
++}
++EXPORT_SYMBOL(cdns_mhdp_bus_write);
++
++u32 cdns_mhdp_get_fw_clk(struct cdns_mhdp_device *mhdp)
++{
++      return cdns_mhdp_bus_read(mhdp, SW_CLK_H);
++}
++EXPORT_SYMBOL(cdns_mhdp_get_fw_clk);
++
+ void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk)
+ {
+-      writel(clk / 1000000, mhdp->regs + SW_CLK_H);
++      cdns_mhdp_bus_write(clk / 1000000, mhdp, SW_CLK_H);
+ }
+ EXPORT_SYMBOL(cdns_mhdp_set_fw_clk);
+@@ -71,16 +136,16 @@ void cdns_mhdp_clock_reset(struct cdns_m
+             DPTX_SYS_CLK_EN |
+             CFG_DPTX_VIF_CLK_RSTN_EN |
+             CFG_DPTX_VIF_CLK_EN;
+-      writel(val, mhdp->regs + SOURCE_DPTX_CAR);
++      cdns_mhdp_bus_write(val, mhdp, SOURCE_DPTX_CAR);
+       val = SOURCE_PHY_RSTN_EN | SOURCE_PHY_CLK_EN;
+-      writel(val, mhdp->regs + SOURCE_PHY_CAR);
++      cdns_mhdp_bus_write(val, mhdp, SOURCE_PHY_CAR);
+       val = SOURCE_PKT_SYS_RSTN_EN |
+             SOURCE_PKT_SYS_CLK_EN |
+             SOURCE_PKT_DATA_RSTN_EN |
+             SOURCE_PKT_DATA_CLK_EN;
+-      writel(val, mhdp->regs + SOURCE_PKT_CAR);
++      cdns_mhdp_bus_write(val, mhdp, SOURCE_PKT_CAR);
+       val = SPDIF_CDR_CLK_RSTN_EN |
+             SPDIF_CDR_CLK_EN |
+@@ -88,20 +153,20 @@ void cdns_mhdp_clock_reset(struct cdns_m
+             SOURCE_AIF_SYS_CLK_EN |
+             SOURCE_AIF_CLK_RSTN_EN |
+             SOURCE_AIF_CLK_EN;
+-      writel(val, mhdp->regs + SOURCE_AIF_CAR);
++      cdns_mhdp_bus_write(val, mhdp, SOURCE_AIF_CAR);
+       val = SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN |
+             SOURCE_CIPHER_SYS_CLK_EN |
+             SOURCE_CIPHER_CHAR_CLK_RSTN_EN |
+             SOURCE_CIPHER_CHAR_CLK_EN;
+-      writel(val, mhdp->regs + SOURCE_CIPHER_CAR);
++      cdns_mhdp_bus_write(val, mhdp, SOURCE_CIPHER_CAR);
+       val = SOURCE_CRYPTO_SYS_CLK_RSTN_EN |
+             SOURCE_CRYPTO_SYS_CLK_EN;
+-      writel(val, mhdp->regs + SOURCE_CRYPTO_CAR);
++      cdns_mhdp_bus_write(val, mhdp, SOURCE_CRYPTO_CAR);
+       /* enable Mailbox and PIF interrupt */
+-      writel(0, mhdp->regs + APB_INT_MASK);
++      cdns_mhdp_bus_write(0, mhdp, APB_INT_MASK);
+ }
+ EXPORT_SYMBOL(cdns_mhdp_clock_reset);
+@@ -109,13 +174,13 @@ int cdns_mhdp_mailbox_read(struct cdns_m
+ {
+       int val, ret;
+-      ret = readx_poll_timeout(readl, mhdp->regs + MAILBOX_EMPTY_ADDR,
++      ret = mhdp_readx_poll_timeout(cdns_mhdp_bus_read, mhdp, MAILBOX_EMPTY_ADDR,
+                                val, !val, MAILBOX_RETRY_US,
+                                MAILBOX_TIMEOUT_US);
+       if (ret < 0)
+               return ret;
+-      return readl(mhdp->regs + MAILBOX0_RD_DATA) & 0xff;
++      return cdns_mhdp_bus_read(mhdp, MAILBOX0_RD_DATA) & 0xff;
+ }
+ EXPORT_SYMBOL(cdns_mhdp_mailbox_read);
+@@ -123,13 +188,13 @@ static int cdp_dp_mailbox_write(struct c
+ {
+       int ret, full;
+-      ret = readx_poll_timeout(readl, mhdp->regs + MAILBOX_FULL_ADDR,
++      ret = mhdp_readx_poll_timeout(cdns_mhdp_bus_read, mhdp, MAILBOX_FULL_ADDR,
+                                full, !full, MAILBOX_RETRY_US,
+                                MAILBOX_TIMEOUT_US);
+       if (ret < 0)
+               return ret;
+-      writel(val, mhdp->regs + MAILBOX0_WR_DATA);
++      cdns_mhdp_bus_write(val, mhdp, MAILBOX0_WR_DATA);
+       return 0;
+ }
+@@ -357,20 +422,20 @@ int cdns_mhdp_load_firmware(struct cdns_
+       int i, ret;
+       /* reset ucpu before load firmware*/
+-      writel(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET,
+-             mhdp->regs + APB_CTRL);
++      cdns_mhdp_bus_write(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET,
++             mhdp, APB_CTRL);
+       for (i = 0; i < i_size; i += 4)
+-              writel(*i_mem++, mhdp->regs + ADDR_IMEM + i);
++              cdns_mhdp_bus_write(*i_mem++, mhdp, ADDR_IMEM + i);
+       for (i = 0; i < d_size; i += 4)
+-              writel(*d_mem++, mhdp->regs + ADDR_DMEM + i);
++              cdns_mhdp_bus_write(*d_mem++, mhdp, ADDR_DMEM + i);
+       /* un-reset ucpu */
+-      writel(0, mhdp->regs + APB_CTRL);
++      cdns_mhdp_bus_write(0, mhdp, APB_CTRL);
+       /* check the keep alive register to make sure fw working */
+-      ret = readx_poll_timeout(readl, mhdp->regs + KEEP_ALIVE,
++      ret = mhdp_readx_poll_timeout(cdns_mhdp_bus_read, mhdp, KEEP_ALIVE,
+                                reg, reg, 2000, FW_ALIVE_TIMEOUT_US);
+       if (ret < 0) {
+               DRM_DEV_ERROR(mhdp->dev, "failed to loaded the FW reg = %x\n",
+@@ -378,13 +443,13 @@ int cdns_mhdp_load_firmware(struct cdns_
+               return -EINVAL;
+       }
+-      reg = readl(mhdp->regs + VER_L) & 0xff;
++      reg = cdns_mhdp_bus_read(mhdp, VER_L) & 0xff;
+       mhdp->fw_version = reg;
+-      reg = readl(mhdp->regs + VER_H) & 0xff;
++      reg = cdns_mhdp_bus_read(mhdp, VER_H) & 0xff;
+       mhdp->fw_version |= reg << 8;
+-      reg = readl(mhdp->regs + VER_LIB_L_ADDR) & 0xff;
++      reg = cdns_mhdp_bus_read(mhdp, VER_LIB_L_ADDR) & 0xff;
+       mhdp->fw_version |= reg << 16;
+-      reg = readl(mhdp->regs + VER_LIB_H_ADDR) & 0xff;
++      reg = cdns_mhdp_bus_read(mhdp, VER_LIB_H_ADDR) & 0xff;
+       mhdp->fw_version |= reg << 24;
+       DRM_DEV_DEBUG(mhdp->dev, "firmware version: %x\n", mhdp->fw_version);
+@@ -466,7 +531,7 @@ int cdns_mhdp_event_config(struct cdns_m
+       memset(msg, 0, sizeof(msg));
+-      msg[0] = DPTX_EVENT_ENABLE_HPD | DPTX_EVENT_ENABLE_TRAINING;
++      msg[0] = MHDP_EVENT_ENABLE_HPD | MHDP_EVENT_ENABLE_TRAINING;
+       ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+                                    DPTX_ENABLE_EVENT, sizeof(msg), msg);
+@@ -479,7 +544,7 @@ EXPORT_SYMBOL(cdns_mhdp_event_config);
+ u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp)
+ {
+-      return readl(mhdp->regs + SW_EVENTS0);
++      return cdns_mhdp_bus_read(mhdp, SW_EVENTS0);
+ }
+ EXPORT_SYMBOL(cdns_mhdp_get_event);
+@@ -883,24 +948,24 @@ int cdns_mhdp_audio_stop(struct cdns_mhd
+               return ret;
+       }
+-      writel(0, mhdp->regs + SPDIF_CTRL_ADDR);
++      cdns_mhdp_bus_write(0, mhdp, SPDIF_CTRL_ADDR);
+       /* clearn the audio config and reset */
+-      writel(0, mhdp->regs + AUDIO_SRC_CNTL);
+-      writel(0, mhdp->regs + AUDIO_SRC_CNFG);
+-      writel(AUDIO_SW_RST, mhdp->regs + AUDIO_SRC_CNTL);
+-      writel(0, mhdp->regs + AUDIO_SRC_CNTL);
++      cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL);
++      cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNFG);
++      cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, AUDIO_SRC_CNTL);
++      cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL);
+       /* reset smpl2pckt component  */
+-      writel(0, mhdp->regs + SMPL2PKT_CNTL);
+-      writel(AUDIO_SW_RST, mhdp->regs + SMPL2PKT_CNTL);
+-      writel(0, mhdp->regs + SMPL2PKT_CNTL);
++      cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL);
++      cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, SMPL2PKT_CNTL);
++      cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL);
+       /* reset FIFO */
+-      writel(AUDIO_SW_RST, mhdp->regs + FIFO_CNTL);
+-      writel(0, mhdp->regs + FIFO_CNTL);
++      cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, FIFO_CNTL);
++      cdns_mhdp_bus_write(0, mhdp, FIFO_CNTL);
+-      if (audio->format == AFMT_SPDIF)
++      if (audio->format == AFMT_SPDIF_INT)
+               clk_disable_unprepare(mhdp->spdif_clk);
+       return 0;
+@@ -936,15 +1001,15 @@ static void cdns_mhdp_audio_config_i2s(s
+               i2s_port_en_val = 3;
+       }
+-      writel(0x0, mhdp->regs + SPDIF_CTRL_ADDR);
++      cdns_mhdp_bus_write(0x0, mhdp, SPDIF_CTRL_ADDR);
+-      writel(SYNC_WR_TO_CH_ZERO, mhdp->regs + FIFO_CNTL);
++      cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL);
+       val = MAX_NUM_CH(audio->channels);
+       val |= NUM_OF_I2S_PORTS(audio->channels);
+       val |= AUDIO_TYPE_LPCM;
+       val |= CFG_SUB_PCKT_NUM(sub_pckt_num);
+-      writel(val, mhdp->regs + SMPL2PKT_CNFG);
++      cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG);
+       if (audio->sample_width == 16)
+               val = 0;
+@@ -956,7 +1021,7 @@ static void cdns_mhdp_audio_config_i2s(s
+       val |= AUDIO_CH_NUM(audio->channels);
+       val |= I2S_DEC_PORT_EN(i2s_port_en_val);
+       val |= TRANS_SMPL_WIDTH_32;
+-      writel(val, mhdp->regs + AUDIO_SRC_CNFG);
++      cdns_mhdp_bus_write(val, mhdp, AUDIO_SRC_CNFG);
+       for (i = 0; i < (audio->channels + 1) / 2; i++) {
+               if (audio->sample_width == 16)
+@@ -965,7 +1030,7 @@ static void cdns_mhdp_audio_config_i2s(s
+                       val = (0x0b << 8) | (0x0b << 20);
+               val |= ((2 * i) << 4) | ((2 * i + 1) << 16);
+-              writel(val, mhdp->regs + STTS_BIT_CH(i));
++              cdns_mhdp_bus_write(val, mhdp, STTS_BIT_CH(i));
+       }
+       switch (audio->sample_rate) {
+@@ -999,24 +1064,24 @@ static void cdns_mhdp_audio_config_i2s(s
+               break;
+       }
+       val |= 4;
+-      writel(val, mhdp->regs + COM_CH_STTS_BITS);
++      cdns_mhdp_bus_write(val, mhdp, COM_CH_STTS_BITS);
+-      writel(SMPL2PKT_EN, mhdp->regs + SMPL2PKT_CNTL);
+-      writel(I2S_DEC_START, mhdp->regs + AUDIO_SRC_CNTL);
++      cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL);
++      cdns_mhdp_bus_write(I2S_DEC_START, mhdp, AUDIO_SRC_CNTL);
+ }
+ static void cdns_mhdp_audio_config_spdif(struct cdns_mhdp_device *mhdp)
+ {
+       u32 val;
+-      writel(SYNC_WR_TO_CH_ZERO, mhdp->regs + FIFO_CNTL);
++      cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL);
+       val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4);
+-      writel(val, mhdp->regs + SMPL2PKT_CNFG);
+-      writel(SMPL2PKT_EN, mhdp->regs + SMPL2PKT_CNTL);
++      cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG);
++      cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL);
+       val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS;
+-      writel(val, mhdp->regs + SPDIF_CTRL_ADDR);
++      cdns_mhdp_bus_write(val, mhdp, SPDIF_CTRL_ADDR);
+       clk_prepare_enable(mhdp->spdif_clk);
+       clk_set_rate(mhdp->spdif_clk, CDNS_DP_SPDIF_CLK);
+@@ -1028,7 +1093,7 @@ int cdns_mhdp_audio_config(struct cdns_m
+       int ret;
+       /* reset the spdif clk before config */
+-      if (audio->format == AFMT_SPDIF) {
++      if (audio->format == AFMT_SPDIF_INT) {
+               reset_control_assert(mhdp->spdif_rst);
+               reset_control_deassert(mhdp->spdif_rst);
+       }
+@@ -1043,7 +1108,7 @@ int cdns_mhdp_audio_config(struct cdns_m
+       if (audio->format == AFMT_I2S)
+               cdns_mhdp_audio_config_i2s(mhdp, audio);
+-      else if (audio->format == AFMT_SPDIF)
++      else if (audio->format == AFMT_SPDIF_INT)
+               cdns_mhdp_audio_config_spdif(mhdp);
+       ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN);
+@@ -1150,12 +1215,12 @@ bool cdns_mhdp_check_alive(struct cdns_m
+       u32  alive, newalive;
+       u8 retries_left = 10;
+-      alive = readl(mhdp->regs + KEEP_ALIVE);
++      alive = cdns_mhdp_bus_read(mhdp, KEEP_ALIVE);
+       while (retries_left--) {
+               udelay(2);
+-              newalive = readl(mhdp->regs + KEEP_ALIVE);
++              newalive = cdns_mhdp_bus_read(mhdp, KEEP_ALIVE);
+               if (alive == newalive)
+                       continue;
+               return true;
+--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
+@@ -10,6 +10,42 @@
+ #include <drm/drmP.h>
+ #include <linux/io.h>
+ #include <drm/bridge/cdns-mhdp-common.h>
++#include <drm/bridge/cdns-mhdp-imx.h>
++#include <linux/regmap.h>
++
++void cdns_mhdp_infoframe_set(struct cdns_mhdp_device *mhdp,
++                                      u8 entry_id, u8 packet_len, u8 *packet, u8 packet_type)
++{
++      u32 *packet32, len32;
++      u32 val, i;
++
++      /* invalidate entry */
++      val = F_ACTIVE_IDLE_TYPE(1) | F_PKT_ALLOC_ADDRESS(entry_id);
++      cdns_mhdp_bus_write(val, mhdp, SOURCE_PIF_PKT_ALLOC_REG);
++      cdns_mhdp_bus_write(F_PKT_ALLOC_WR_EN(1), mhdp, SOURCE_PIF_PKT_ALLOC_WR_EN);
++
++      /* flush fifo 1 */
++      cdns_mhdp_bus_write(F_FIFO1_FLUSH(1), mhdp, SOURCE_PIF_FIFO1_FLUSH);
++
++      /* write packet into memory */
++      packet32 = (u32 *)packet;
++      len32 = packet_len / 4;
++      for (i = 0; i < len32; i++)
++              cdns_mhdp_bus_write(F_DATA_WR(packet32[i]), mhdp, SOURCE_PIF_DATA_WR);
++
++      /* write entry id */
++      cdns_mhdp_bus_write(F_WR_ADDR(entry_id), mhdp, SOURCE_PIF_WR_ADDR);
++
++      /* write request */
++      cdns_mhdp_bus_write(F_HOST_WR(1), mhdp, SOURCE_PIF_WR_REQ);
++
++      /* update entry */
++      val =  F_ACTIVE_IDLE_TYPE(1) | F_TYPE_VALID(1) |
++                      F_PACKET_TYPE(packet_type) | F_PKT_ALLOC_ADDRESS(entry_id);
++      cdns_mhdp_bus_write(val, mhdp, SOURCE_PIF_PKT_ALLOC_REG);
++
++      cdns_mhdp_bus_write(F_PKT_ALLOC_WR_EN(1), mhdp, SOURCE_PIF_PKT_ALLOC_WR_EN);
++}
+ int cdns_hdmi_get_edid_block(void *data, u8 *edid,
+                         u32 block, size_t length)
+--- a/include/drm/bridge/cdns-mhdp-common.h
++++ b/include/drm/bridge/cdns-mhdp-common.h
+@@ -391,8 +391,8 @@
+ #define FW_STANDBY                            0
+ #define FW_ACTIVE                             1
+-#define DPTX_EVENT_ENABLE_HPD                 BIT(0)
+-#define DPTX_EVENT_ENABLE_TRAINING            BIT(1)
++#define MHDP_EVENT_ENABLE_HPD                 BIT(0)
++#define MHDP_EVENT_ENABLE_TRAINING            BIT(1)
+ #define LINK_TRAINING_NOT_ACTIVE              0
+ #define LINK_TRAINING_RUN                     1
+@@ -532,7 +532,8 @@ enum vic_bt_type {
+ enum audio_format {
+       AFMT_I2S = 0,
+-      AFMT_SPDIF = 1,
++      AFMT_SPDIF_INT = 1,
++      AFMT_SPDIF_EXT = 2,
+       AFMT_UNUSED,
+ };
+@@ -625,12 +626,13 @@ struct cdns_mhdp_device {
+       struct drm_dp_mst_topology_mgr mst_mgr;
+       struct delayed_work hotplug_work;
++      u32 lane_mapping;
+       bool link_up;
+       bool power_up;
+       bool plugged;
+       union {
+-              struct _dp_data {
++              struct cdn_dp_data {
+                       struct drm_dp_link      link;
+                       struct drm_dp_aux       aux;
+                       struct cdns_mhdp_host   host;
+@@ -638,7 +640,6 @@ struct cdns_mhdp_device {
+                       struct cdns_mhdp_mst_cbs cbs;
+                       bool is_mst;
+                       bool can_mst;
+-                      u32 lane_mapping;
+                       u32 link_rate;
+                       u32 num_lanes;
+               } dp;
+@@ -649,8 +650,11 @@ struct cdns_mhdp_device {
+       };
+ };
++u32 cdns_mhdp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset);
++void cdns_mhdp_bus_write(u32 val, struct cdns_mhdp_device *mhdp, u32 offset);
+ void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp);
+ void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk);
++u32 cdns_mhdp_get_fw_clk(struct cdns_mhdp_device *mhdp);
+ int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
+                           u32 i_size, const u32 *d_mem, u32 d_size);
+ int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable);
+@@ -691,6 +695,8 @@ int cdns_mhdp_mailbox_validate_receive(s
+                                             u16 req_size);
+ int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp);
++void cdns_mhdp_infoframe_set(struct cdns_mhdp_device *mhdp,
++                                      u8 entry_id, u8 packet_len, u8 *packet, u8 packet_type);
+ int cdns_hdmi_get_edid_block(void *data, u8 *edid, u32 block, size_t length);
+ int cdns_hdmi_scdc_read(struct cdns_mhdp_device *mhdp, u8 addr, u8 *data);
+ int cdns_hdmi_scdc_write(struct cdns_mhdp_device *mhdp, u8 addr, u8 value);
diff --git a/target/linux/layerscape/patches-5.4/805-display-0007-drm-bridge-cadence-Add-mhdp-audio-driver.patch b/target/linux/layerscape/patches-5.4/805-display-0007-drm-bridge-cadence-Add-mhdp-audio-driver.patch
new file mode 100644 (file)
index 0000000..f0a1414
--- /dev/null
@@ -0,0 +1,715 @@
+From 3cd4b3cfc651c4d54897c72fbbaa9cd583ee6208 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Fri, 30 Aug 2019 17:51:43 +0800
+Subject: [PATCH] drm: bridge: cadence: Add mhdp audio driver
+
+Move mhdp audio driver to cadence folder.
+Add audio info-frame set function for hdmi tx audio.
+The driver suppoer both HDMI and DP audio.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/Kconfig            |   3 +
+ drivers/gpu/drm/bridge/cadence/Makefile           |   3 +-
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c     |   4 +
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c   |   5 +-
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c  | 395 ++++++++++++++++++++++
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c | 183 ----------
+ drivers/gpu/drm/imx/Kconfig                       |   1 +
+ include/drm/bridge/cdns-mhdp-common.h             |   6 +
+ 8 files changed, 414 insertions(+), 186 deletions(-)
+ create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
+
+--- a/drivers/gpu/drm/bridge/cadence/Kconfig
++++ b/drivers/gpu/drm/bridge/cadence/Kconfig
+@@ -11,3 +11,6 @@ config DRM_CDNS_HDMI
+ config DRM_CDNS_DP
+       tristate "Cadence DP DRM driver"
++
++config DRM_CDNS_AUDIO
++      tristate "Cadence MHDP Audio driver"
+--- a/drivers/gpu/drm/bridge/cadence/Makefile
++++ b/drivers/gpu/drm/bridge/cadence/Makefile
+@@ -1,5 +1,4 @@
+-#ccflags-y := -Iinclude/drm
+-
+ obj-$(CONFIG_DRM_CDNS_MHDP) += cdns-mhdp-common.o cdns-mhdp-hdmi.o
+ obj-$(CONFIG_DRM_CDNS_HDMI) += cdns-hdmi-core.o
+ obj-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
++obj-$(CONFIG_DRM_CDNS_AUDIO) += cdns-mhdp-audio.o
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -526,6 +526,9 @@ __cdns_dp_probe(struct platform_device *
+       dev_set_drvdata(dev, &dp->mhdp);
+       
++      /* register audio driver */
++      cdns_mhdp_register_audio_driver(dev);
++
+       dp_aux_init(&dp->mhdp, dev);
+       return dp;
+@@ -537,6 +540,7 @@ err_out:
+ static void __cdns_dp_remove(struct cdns_mhdp_device *mhdp)
+ {
+       dp_aux_destroy(mhdp);
++      cdns_mhdp_unregister_audio_driver(mhdp->dev);
+ }
+ /* -----------------------------------------------------------------------------
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -9,7 +9,6 @@
+  * (at your option) any later version.
+  *
+  */
+-
+ #include <drm/bridge/cdns-mhdp-imx.h>
+ #include <drm/drm_atomic_helper.h>
+ #include <drm/drm_crtc_helper.h>
+@@ -513,6 +512,9 @@ __cdns_hdmi_probe(struct platform_device
+       dev_set_drvdata(dev, &hdmi->mhdp);
++      /* register audio driver */
++      cdns_mhdp_register_audio_driver(dev);
++
+       return hdmi;
+ err_out:
+@@ -522,6 +524,7 @@ err_out:
+ static void __cdns_hdmi_remove(struct cdns_mhdp_device *mhdp)
+ {
++      cdns_mhdp_unregister_audio_driver(mhdp->dev);
+ }
+ /* -----------------------------------------------------------------------------
+--- /dev/null
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
+@@ -0,0 +1,395 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
++ * Author: Chris Zhong <zyw@rock-chips.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++#include <linux/clk.h>
++#include <linux/reset.h>
++#include <drm/bridge/cdns-mhdp-common.h>
++#include <sound/hdmi-codec.h>
++#include <drm/bridge/cdns-mhdp-imx.h>
++#include <drm/drm_of.h>
++#include <drm/drmP.h>
++
++#define CDNS_DP_SPDIF_CLK             200000000
++
++static u32 TMDS_rate_table[7] = {
++      25200, 27000, 54000, 74250, 148500, 297000, 594000,
++};
++
++static u32 N_table_32k[7] = {
++/* 25200/27000/54000/74250/148500/297000/594000 */
++      4096, 4096, 4096, 4096, 4096, 3072, 3072,
++};
++
++static u32 N_table_44k[7] = {
++      6272, 6272, 6272, 6272, 6272, 4704, 9408,
++};
++
++static u32 N_table_48k[7] = {
++      6144, 6144, 6144, 6144, 6144, 5120, 6144,
++};
++
++static int select_N_index(u32 pclk)
++{
++      int num = sizeof(TMDS_rate_table)/sizeof(int);
++      int i = 0;
++
++      for (i = 0; i < num ; i++)
++              if (pclk == TMDS_rate_table[i])
++                      break;
++
++      if (i == num) {
++              DRM_WARN("pclkc %d is not supported!\n", pclk);
++              return num-1;
++      }
++
++      return i;
++}
++
++static void hdmi_audio_avi_set(struct cdns_mhdp_device *mhdp,
++                                              u32 channels)
++{
++      struct hdmi_audio_infoframe frame;
++      u8 buf[32];
++      int ret;
++
++      hdmi_audio_infoframe_init(&frame);
++
++      frame.channels = channels;
++      frame.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
++
++      if (channels == 2)
++              frame.channel_allocation = 0;
++      else if (channels == 4)
++              frame.channel_allocation = 0x3;
++      else if (channels == 8)
++              frame.channel_allocation = 0x13;
++
++      ret = hdmi_audio_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
++      if (ret < 0) {
++              DRM_ERROR("failed to pack audio infoframe: %d\n", ret);
++              return;
++      }
++
++      buf[0] = 0;
++
++      cdns_mhdp_infoframe_set(mhdp, 1, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_AUDIO);
++}
++
++int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
++                       struct audio_info *audio)
++{
++      int ret;
++
++      if (audio->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
++              ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, 0);
++              if (ret) {
++                      DRM_DEV_ERROR(mhdp->dev, "audio stop failed: %d\n", ret);
++                      return ret;
++              }
++      }
++
++      cdns_mhdp_bus_write(0, mhdp, SPDIF_CTRL_ADDR);
++
++      /* clearn the audio config and reset */
++      cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL);
++      cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNFG);
++      cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, AUDIO_SRC_CNTL);
++      cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL);
++
++      /* reset smpl2pckt component  */
++      cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL);
++      cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, SMPL2PKT_CNTL);
++      cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL);
++
++      /* reset FIFO */
++      cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, FIFO_CNTL);
++      cdns_mhdp_bus_write(0, mhdp, FIFO_CNTL);
++
++      if (audio->format == AFMT_SPDIF_INT)
++              clk_disable_unprepare(mhdp->spdif_clk);
++
++      return 0;
++}
++EXPORT_SYMBOL(cdns_mhdp_audio_stop);
++
++int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable)
++{
++      struct audio_info *audio = &mhdp->audio_info;
++      int ret = true;
++
++      if (audio->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
++              ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 4, 1, enable);
++              if (ret)
++                      DRM_DEV_ERROR(mhdp->dev, "audio mute failed: %d\n", ret);
++      }
++
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_audio_mute);
++
++static void cdns_mhdp_audio_config_i2s(struct cdns_mhdp_device *mhdp,
++                                     struct audio_info *audio)
++{
++      int sub_pckt_num = 1, i2s_port_en_val = 0xf, i;
++      int idx = select_N_index(mhdp->mode.clock);
++      u32 val, ncts;
++
++      if (audio->channels == 2) {
++              if (mhdp->dp.link.num_lanes == 1)
++                      sub_pckt_num = 2;
++              else
++                      sub_pckt_num = 4;
++
++              i2s_port_en_val = 1;
++      } else if (audio->channels == 4) {
++              i2s_port_en_val = 3;
++      }
++
++      cdns_mhdp_bus_write(0x0, mhdp, SPDIF_CTRL_ADDR);
++
++      cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL);
++
++      val = MAX_NUM_CH(audio->channels);
++      val |= NUM_OF_I2S_PORTS(audio->channels);
++      val |= AUDIO_TYPE_LPCM;
++      val |= CFG_SUB_PCKT_NUM(sub_pckt_num);
++      cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG);
++
++      if (audio->sample_width == 16)
++              val = 0;
++      else if (audio->sample_width == 24)
++              val = 1 << 9;
++      else
++              val = 2 << 9;
++
++      val |= AUDIO_CH_NUM(audio->channels);
++      val |= I2S_DEC_PORT_EN(i2s_port_en_val);
++      val |= TRANS_SMPL_WIDTH_32;
++      cdns_mhdp_bus_write(val, mhdp, AUDIO_SRC_CNFG);
++
++      for (i = 0; i < (audio->channels + 1) / 2; i++) {
++              if (audio->sample_width == 16)
++                      val = (0x02 << 8) | (0x02 << 20);
++              else if (audio->sample_width == 24)
++                      val = (0x0b << 8) | (0x0b << 20);
++
++              val |= ((2 * i) << 4) | ((2 * i + 1) << 16);
++              cdns_mhdp_bus_write(val, mhdp, STTS_BIT_CH(i));
++      }
++
++      switch (audio->sample_rate) {
++      case 32000:
++              val = SAMPLING_FREQ(3) |
++                    ORIGINAL_SAMP_FREQ(0xc);
++              ncts = N_table_32k[idx];
++              break;
++      case 44100:
++              val = SAMPLING_FREQ(0) |
++                    ORIGINAL_SAMP_FREQ(0xf);
++              ncts = N_table_44k[idx];
++              break;
++      case 48000:
++              val = SAMPLING_FREQ(2) |
++                    ORIGINAL_SAMP_FREQ(0xd);
++              ncts = N_table_48k[idx];
++              break;
++      case 88200:
++              val = SAMPLING_FREQ(8) |
++                    ORIGINAL_SAMP_FREQ(0x7);
++              ncts = N_table_44k[idx] * 2;
++              break;
++      case 96000:
++              val = SAMPLING_FREQ(0xa) |
++                    ORIGINAL_SAMP_FREQ(5);
++              ncts = N_table_48k[idx] * 2;
++              break;
++      case 176400:
++              val = SAMPLING_FREQ(0xc) |
++                    ORIGINAL_SAMP_FREQ(3);
++              ncts = N_table_44k[idx] * 4;
++              break;
++      case 192000:
++      default:
++              val = SAMPLING_FREQ(0xe) |
++                    ORIGINAL_SAMP_FREQ(1);
++              ncts = N_table_48k[idx] * 4;
++              break;
++      }
++      val |= 4;
++      cdns_mhdp_bus_write(val, mhdp, COM_CH_STTS_BITS);
++
++      if (audio->connector_type == DRM_MODE_CONNECTOR_HDMIA)
++              cdns_mhdp_reg_write(mhdp, CM_I2S_CTRL, ncts | 0x4000000);
++
++      cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL);
++      cdns_mhdp_bus_write(I2S_DEC_START, mhdp, AUDIO_SRC_CNTL);
++}
++
++static void cdns_mhdp_audio_config_spdif(struct cdns_mhdp_device *mhdp)
++{
++      u32 val;
++
++      cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL);
++
++      val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4);
++      cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG);
++      cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL);
++
++      val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS;
++      cdns_mhdp_bus_write(val, mhdp, SPDIF_CTRL_ADDR);
++
++      clk_prepare_enable(mhdp->spdif_clk);
++      clk_set_rate(mhdp->spdif_clk, CDNS_DP_SPDIF_CLK);
++}
++
++int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
++                         struct audio_info *audio)
++{
++      int ret;
++
++      /* reset the spdif clk before config */
++      if (audio->format == AFMT_SPDIF_INT) {
++              reset_control_assert(mhdp->spdif_rst);
++              reset_control_deassert(mhdp->spdif_rst);
++      }
++
++      if (audio->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
++              ret = cdns_mhdp_reg_write(mhdp, CM_LANE_CTRL, LANE_REF_CYC);
++              if (ret)
++                      goto err_audio_config;
++
++              ret = cdns_mhdp_reg_write(mhdp, CM_CTRL, 0);
++              if (ret)
++                      goto err_audio_config;
++      } else {
++              /* HDMI Mode */
++              ret = cdns_mhdp_reg_write(mhdp, CM_CTRL, 8);
++              if (ret)
++                      goto err_audio_config;
++      }
++
++      if (audio->format == AFMT_I2S)
++              cdns_mhdp_audio_config_i2s(mhdp, audio);
++      else if (audio->format == AFMT_SPDIF_INT)
++              cdns_mhdp_audio_config_spdif(mhdp);
++
++      if (audio->connector_type == DRM_MODE_CONNECTOR_DisplayPort)
++              ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN);
++
++      if (audio->connector_type == DRM_MODE_CONNECTOR_HDMIA)
++              hdmi_audio_avi_set(mhdp, audio->channels);
++
++err_audio_config:
++      if (ret)
++              DRM_DEV_ERROR(mhdp->dev, "audio config failed: %d\n", ret);
++      return ret;
++}
++EXPORT_SYMBOL(cdns_mhdp_audio_config);
++
++static int audio_hw_params(struct device *dev,  void *data,
++                                struct hdmi_codec_daifmt *daifmt,
++                                struct hdmi_codec_params *params)
++{
++      struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
++      struct audio_info audio = {
++              .sample_width = params->sample_width,
++              .sample_rate = params->sample_rate,
++              .channels = params->channels,
++              .connector_type = mhdp->connector.base.connector_type,
++      };
++      int ret;
++
++      switch (daifmt->fmt) {
++      case HDMI_I2S:
++              audio.format = AFMT_I2S;
++              break;
++      case HDMI_SPDIF:
++              audio.format = AFMT_SPDIF_EXT;
++              break;
++      default:
++              DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt);
++              ret = -EINVAL;
++              goto out;
++      }
++
++      ret = cdns_mhdp_audio_config(mhdp, &audio);
++      if (!ret)
++              mhdp->audio_info = audio;
++
++out:
++      return ret;
++}
++
++static void audio_shutdown(struct device *dev, void *data)
++{
++      struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
++      int ret;
++
++      ret = cdns_mhdp_audio_stop(mhdp, &mhdp->audio_info);
++      if (!ret)
++              mhdp->audio_info.format = AFMT_UNUSED;
++}
++
++static int audio_digital_mute(struct device *dev, void *data,
++                                   bool enable)
++{
++      struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
++      int ret;
++
++      ret = cdns_mhdp_audio_mute(mhdp, enable);
++
++      return ret;
++}
++
++static int audio_get_eld(struct device *dev, void *data,
++                              u8 *buf, size_t len)
++{
++      struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
++
++      memcpy(buf, mhdp->connector.base.eld,
++             min(sizeof(mhdp->connector.base.eld), len));
++
++      return 0;
++}
++
++static const struct hdmi_codec_ops audio_codec_ops = {
++      .hw_params = audio_hw_params,
++      .audio_shutdown = audio_shutdown,
++      .digital_mute = audio_digital_mute,
++      .get_eld = audio_get_eld,
++};
++
++int cdns_mhdp_register_audio_driver(struct device *dev)
++{
++      struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
++      struct hdmi_codec_pdata codec_data = {
++              .i2s = 1,
++              .spdif = 1,
++              .ops = &audio_codec_ops,
++              .max_i2s_channels = 8,
++      };
++
++      mhdp->audio_pdev = platform_device_register_data(
++                            dev, HDMI_CODEC_DRV_NAME, 1,
++                            &codec_data, sizeof(codec_data));
++
++      return PTR_ERR_OR_ZERO(mhdp->audio_pdev);
++}
++
++void cdns_mhdp_unregister_audio_driver(struct device *dev)
++{
++      struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
++
++      platform_device_unregister(mhdp->audio_pdev);
++}
+--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
+@@ -937,189 +937,6 @@ err_config_video:
+ }
+ EXPORT_SYMBOL(cdns_mhdp_config_video);
+-int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
+-                       struct audio_info *audio)
+-{
+-      int ret;
+-
+-      ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, 0);
+-      if (ret) {
+-              DRM_DEV_ERROR(mhdp->dev, "audio stop failed: %d\n", ret);
+-              return ret;
+-      }
+-
+-      cdns_mhdp_bus_write(0, mhdp, SPDIF_CTRL_ADDR);
+-
+-      /* clearn the audio config and reset */
+-      cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL);
+-      cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNFG);
+-      cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, AUDIO_SRC_CNTL);
+-      cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL);
+-
+-      /* reset smpl2pckt component  */
+-      cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL);
+-      cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, SMPL2PKT_CNTL);
+-      cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL);
+-
+-      /* reset FIFO */
+-      cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, FIFO_CNTL);
+-      cdns_mhdp_bus_write(0, mhdp, FIFO_CNTL);
+-
+-      if (audio->format == AFMT_SPDIF_INT)
+-              clk_disable_unprepare(mhdp->spdif_clk);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL(cdns_mhdp_audio_stop);
+-
+-int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable)
+-{
+-      int ret;
+-
+-      ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 4, 1, enable);
+-      if (ret)
+-              DRM_DEV_ERROR(mhdp->dev, "audio mute failed: %d\n", ret);
+-
+-      return ret;
+-}
+-EXPORT_SYMBOL(cdns_mhdp_audio_mute);
+-
+-static void cdns_mhdp_audio_config_i2s(struct cdns_mhdp_device *mhdp,
+-                                     struct audio_info *audio)
+-{
+-      int sub_pckt_num = 1, i2s_port_en_val = 0xf, i;
+-      u32 val;
+-
+-      if (audio->channels == 2) {
+-              if (mhdp->dp.link.num_lanes == 1)
+-                      sub_pckt_num = 2;
+-              else
+-                      sub_pckt_num = 4;
+-
+-              i2s_port_en_val = 1;
+-      } else if (audio->channels == 4) {
+-              i2s_port_en_val = 3;
+-      }
+-
+-      cdns_mhdp_bus_write(0x0, mhdp, SPDIF_CTRL_ADDR);
+-
+-      cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL);
+-
+-      val = MAX_NUM_CH(audio->channels);
+-      val |= NUM_OF_I2S_PORTS(audio->channels);
+-      val |= AUDIO_TYPE_LPCM;
+-      val |= CFG_SUB_PCKT_NUM(sub_pckt_num);
+-      cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG);
+-
+-      if (audio->sample_width == 16)
+-              val = 0;
+-      else if (audio->sample_width == 24)
+-              val = 1 << 9;
+-      else
+-              val = 2 << 9;
+-
+-      val |= AUDIO_CH_NUM(audio->channels);
+-      val |= I2S_DEC_PORT_EN(i2s_port_en_val);
+-      val |= TRANS_SMPL_WIDTH_32;
+-      cdns_mhdp_bus_write(val, mhdp, AUDIO_SRC_CNFG);
+-
+-      for (i = 0; i < (audio->channels + 1) / 2; i++) {
+-              if (audio->sample_width == 16)
+-                      val = (0x02 << 8) | (0x02 << 20);
+-              else if (audio->sample_width == 24)
+-                      val = (0x0b << 8) | (0x0b << 20);
+-
+-              val |= ((2 * i) << 4) | ((2 * i + 1) << 16);
+-              cdns_mhdp_bus_write(val, mhdp, STTS_BIT_CH(i));
+-      }
+-
+-      switch (audio->sample_rate) {
+-      case 32000:
+-              val = SAMPLING_FREQ(3) |
+-                    ORIGINAL_SAMP_FREQ(0xc);
+-              break;
+-      case 44100:
+-              val = SAMPLING_FREQ(0) |
+-                    ORIGINAL_SAMP_FREQ(0xf);
+-              break;
+-      case 48000:
+-              val = SAMPLING_FREQ(2) |
+-                    ORIGINAL_SAMP_FREQ(0xd);
+-              break;
+-      case 88200:
+-              val = SAMPLING_FREQ(8) |
+-                    ORIGINAL_SAMP_FREQ(0x7);
+-              break;
+-      case 96000:
+-              val = SAMPLING_FREQ(0xa) |
+-                    ORIGINAL_SAMP_FREQ(5);
+-              break;
+-      case 176400:
+-              val = SAMPLING_FREQ(0xc) |
+-                    ORIGINAL_SAMP_FREQ(3);
+-              break;
+-      case 192000:
+-              val = SAMPLING_FREQ(0xe) |
+-                    ORIGINAL_SAMP_FREQ(1);
+-              break;
+-      }
+-      val |= 4;
+-      cdns_mhdp_bus_write(val, mhdp, COM_CH_STTS_BITS);
+-
+-      cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL);
+-      cdns_mhdp_bus_write(I2S_DEC_START, mhdp, AUDIO_SRC_CNTL);
+-}
+-
+-static void cdns_mhdp_audio_config_spdif(struct cdns_mhdp_device *mhdp)
+-{
+-      u32 val;
+-
+-      cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL);
+-
+-      val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4);
+-      cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG);
+-      cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL);
+-
+-      val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS;
+-      cdns_mhdp_bus_write(val, mhdp, SPDIF_CTRL_ADDR);
+-
+-      clk_prepare_enable(mhdp->spdif_clk);
+-      clk_set_rate(mhdp->spdif_clk, CDNS_DP_SPDIF_CLK);
+-}
+-
+-int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
+-                         struct audio_info *audio)
+-{
+-      int ret;
+-
+-      /* reset the spdif clk before config */
+-      if (audio->format == AFMT_SPDIF_INT) {
+-              reset_control_assert(mhdp->spdif_rst);
+-              reset_control_deassert(mhdp->spdif_rst);
+-      }
+-
+-      ret = cdns_mhdp_reg_write(mhdp, CM_LANE_CTRL, LANE_REF_CYC);
+-      if (ret)
+-              goto err_audio_config;
+-
+-      ret = cdns_mhdp_reg_write(mhdp, CM_CTRL, 0);
+-      if (ret)
+-              goto err_audio_config;
+-
+-      if (audio->format == AFMT_I2S)
+-              cdns_mhdp_audio_config_i2s(mhdp, audio);
+-      else if (audio->format == AFMT_SPDIF_INT)
+-              cdns_mhdp_audio_config_spdif(mhdp);
+-
+-      ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN);
+-
+-err_audio_config:
+-      if (ret)
+-              DRM_DEV_ERROR(mhdp->dev, "audio config failed: %d\n", ret);
+-      return ret;
+-}
+-EXPORT_SYMBOL(cdns_mhdp_audio_config);
+-
+ int cdns_mhdp_adjust_lt(struct cdns_mhdp_device *mhdp,
+                       u8 nlanes, u16 udelay, u8 *lanes_data, u8 *dpcd)
+ {
+--- a/drivers/gpu/drm/imx/Kconfig
++++ b/drivers/gpu/drm/imx/Kconfig
+@@ -45,6 +45,7 @@ config DRM_IMX_CDNS_MHDP
+       select DRM_CDNS_MHDP
+       select DRM_CDNS_DP
+       select DRM_CDNS_HDMI
++      select DRM_CDNS_AUDIO
+       depends on DRM_IMX
+       help
+         Choose this if you want to use HDMI on i.MX8.
+--- a/include/drm/bridge/cdns-mhdp-common.h
++++ b/include/drm/bridge/cdns-mhdp-common.h
+@@ -548,6 +548,7 @@ struct audio_info {
+       int sample_rate;
+       int channels;
+       int sample_width;
++      int connector_type;
+ };
+ enum vic_pxl_encoding_format {
+@@ -670,11 +671,16 @@ int cdns_mhdp_get_edid_block(void *mhdp,
+ int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp);
+ int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active);
+ int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp);
++
++/* Audio */
+ int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
+                        struct audio_info *audio);
+ int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable);
+ int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
+                          struct audio_info *audio);
++int cdns_mhdp_register_audio_driver(struct device *dev);
++void cdns_mhdp_unregister_audio_driver(struct device *dev);
++
+ int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
+ int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val);
+ int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
diff --git a/target/linux/layerscape/patches-5.4/805-display-0008-drm-bridge-cadence-Add-CEC-driver-for-cdns-mhdp-hdmi.patch b/target/linux/layerscape/patches-5.4/805-display-0008-drm-bridge-cadence-Add-CEC-driver-for-cdns-mhdp-hdmi.patch
new file mode 100644 (file)
index 0000000..742928e
--- /dev/null
@@ -0,0 +1,474 @@
+From ed9e7a6b3346b186a7bd22d9b62072e55ff7b9c5 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Mon, 2 Sep 2019 14:57:05 +0800
+Subject: [PATCH] drm: bridge: cadence: Add CEC driver for cdns mhdp hdmi
+
+Add cec driver for cdns mhdp hdmi.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/Kconfig            |   3 +
+ drivers/gpu/drm/bridge/cadence/Makefile           |   1 +
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c     |   0
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c   |   9 +
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c    | 347 ++++++++++++++++++++++
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c |   0
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c   |   0
+ include/drm/bridge/cdns-mhdp-common.h             |  24 +-
+ 8 files changed, 382 insertions(+), 2 deletions(-)
+ mode change 100755 => 100644 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+ mode change 100755 => 100644 drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+ create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c
+ mode change 100755 => 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
+ mode change 100755 => 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
+
+--- a/drivers/gpu/drm/bridge/cadence/Kconfig
++++ b/drivers/gpu/drm/bridge/cadence/Kconfig
+@@ -14,3 +14,6 @@ config DRM_CDNS_DP
+ config DRM_CDNS_AUDIO
+       tristate "Cadence MHDP Audio driver"
++
++config DRM_CDNS_HDMI_CEC
++      tristate "Cadence MHDP HDMI CEC driver"
+--- a/drivers/gpu/drm/bridge/cadence/Makefile
++++ b/drivers/gpu/drm/bridge/cadence/Makefile
+@@ -2,3 +2,4 @@ obj-$(CONFIG_DRM_CDNS_MHDP) += cdns-mhdp
+ obj-$(CONFIG_DRM_CDNS_HDMI) += cdns-hdmi-core.o
+ obj-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
+ obj-$(CONFIG_DRM_CDNS_AUDIO) += cdns-mhdp-audio.o
++obj-$(CONFIG_DRM_CDNS_HDMI_CEC) += cdns-mhdp-cec.o
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -515,6 +515,11 @@ __cdns_hdmi_probe(struct platform_device
+       /* register audio driver */
+       cdns_mhdp_register_audio_driver(dev);
++      /* register cec driver */
++#ifdef CONFIG_DRM_CDNS_HDMI_CEC
++      cdns_mhdp_register_cec_driver(dev);
++#endif
++
+       return hdmi;
+ err_out:
+@@ -524,6 +529,10 @@ err_out:
+ static void __cdns_hdmi_remove(struct cdns_mhdp_device *mhdp)
+ {
++      /* unregister cec driver */
++#ifdef CONFIG_DRM_CDNS_HDMI_CEC
++      cdns_mhdp_unregister_cec_driver(mhdp->dev);
++#endif
+       cdns_mhdp_unregister_audio_driver(mhdp->dev);
+ }
+--- /dev/null
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c
+@@ -0,0 +1,347 @@
++/*
++ * Copyright 2019 NXP
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++#include <linux/module.h>
++#include <linux/workqueue.h>
++#include <linux/kthread.h>
++#include <linux/freezer.h>
++#include <drm/bridge/cdns-mhdp-common.h>
++
++#define CEC_NAME      "cdns-mhdp-cec"
++
++#define REG_ADDR_OFF 4
++#define MAX_LA_IDX 4
++#define MAX_LA_VAL 15
++
++/* regsiter define */
++#define TX_MSG_HEADER 0x33800
++#define TX_MSG_LENGTH 0x33840
++#define TX_MSG_CMD 0x33844
++#define RX_MSG_CMD 0x33850
++#define RX_CLEAR_BUF 0x33854
++#define LOGICAL_ADDRESS_LA0 0x33858
++
++#define CLK_DIV_MSB 0x3386c
++#define CLK_DIV_LSB 0x33870
++#define RX_MSG_DATA1 0x33900
++#define RX_MSG_LENGTH 0x33940
++#define RX_MSG_STATUS 0x33944
++#define NUM_OF_MSG_RX_BUF 0x33948
++#define TX_MSG_STATUS 0x3394c
++#define DB_L_TIMER 0x33980
++
++/**
++ * CEC Transceiver operation.
++ */
++enum {
++      CEC_TX_STOP,
++      CEC_TX_TRANSMIT,
++      CEC_TX_ABORT,
++      CEC_TX_ABORT_AND_TRANSMIT
++};
++
++/**
++ * CEC Transceiver status.
++ */
++enum {
++      CEC_STS_IDLE,
++      CEC_STS_BUSY,
++      CEC_STS_SUCCESS,
++      CEC_STS_ERROR
++};
++
++/**
++ * CEC Receiver operation.
++ */
++enum {
++      CEC_RX_STOP,
++      CEC_RX_READ,
++      CEC_RX_DISABLE,
++      CEC_RX_ABORT_AND_CLR_FIFO
++};
++/**
++ * Maximum number of Messages in the RX Buffers.
++ */
++#define CEC_MAX_RX_MSGS 2
++
++static u32 mhdp_cec_read(struct cdns_mhdp_cec *cec, u32 offset)
++{
++      struct cdns_mhdp_device *mhdp =
++                      container_of(cec, struct cdns_mhdp_device, hdmi.cec);
++      return cdns_mhdp_bus_read(mhdp, offset);
++}
++
++static void mhdp_cec_write(struct cdns_mhdp_cec *cec, u32 offset, u32 val)
++{
++      struct cdns_mhdp_device *mhdp =
++                      container_of(cec, struct cdns_mhdp_device, hdmi.cec);
++      cdns_mhdp_bus_write(val, mhdp, offset);
++}
++
++static void mhdp_cec_clear_rx_buffer(struct cdns_mhdp_cec *cec)
++{
++      mhdp_cec_write(cec, RX_CLEAR_BUF, 1);
++      mhdp_cec_write(cec, RX_CLEAR_BUF, 0);
++}
++
++static void mhdp_cec_set_divider(struct cdns_mhdp_cec *cec)
++{
++      struct cdns_mhdp_device *mhdp =
++                      container_of(cec, struct cdns_mhdp_device, hdmi.cec);
++      u32 clk_div;
++
++      /* Set clock divider */
++      clk_div = cdns_mhdp_get_fw_clk(mhdp) * 10;
++
++      mhdp_cec_write(cec, CLK_DIV_MSB,
++                        (clk_div >> 8) & 0xFF);
++      mhdp_cec_write(cec, CLK_DIV_LSB, clk_div & 0xFF);
++}
++
++static u32 mhdp_cec_read_message(struct cdns_mhdp_cec *cec)
++{
++      struct cec_msg *msg = &cec->msg;
++      int len;
++      int i;
++
++      mhdp_cec_write(cec, RX_MSG_CMD, CEC_RX_READ);
++
++      len = mhdp_cec_read(cec, RX_MSG_LENGTH);
++      msg->len = len + 1;
++      dev_dbg(cec->dev, "RX MSG len =%d\n", len);
++
++      /* Read RX MSG bytes */
++      for (i = 0; i < msg->len; ++i) {
++              msg->msg[i] = (u8) mhdp_cec_read(cec, RX_MSG_DATA1 + (i * REG_ADDR_OFF));
++              dev_dbg(cec->dev, "RX MSG[%d]=0x%x\n", i, msg->msg[i]);
++      }
++
++      mhdp_cec_write(cec, RX_MSG_CMD, CEC_RX_STOP);
++
++      return true;
++}
++
++static u32 mhdp_cec_write_message(struct cdns_mhdp_cec *cec, struct cec_msg *msg)
++{
++      u8 i;
++
++      mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
++
++      if (msg->len > CEC_MAX_MSG_SIZE) {
++              dev_err(cec->dev, "Invalid MSG size!\n");
++              return -EINVAL;
++      }
++
++      for (i = 0; i < msg->len; ++i)
++              printk("msg[%d]=0x%x\n",i, msg->msg[i]);
++
++      /* Write Message to register */
++      for (i = 0; i < msg->len; ++i) {
++              mhdp_cec_write(cec, TX_MSG_HEADER + (i * REG_ADDR_OFF),
++                        msg->msg[i]);
++      }
++      /* Write Message Length (payload + opcode) */
++      mhdp_cec_write(cec, TX_MSG_LENGTH, msg->len - 1);
++
++      mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_TRANSMIT);
++
++      return true;
++}
++
++//static void cec_abort_tx_transfer(struct cdns_mhdp_cec *cec)
++//{
++//    cec_write(cec, TX_MSG_CMD, CEC_TX_ABORT);
++//    cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
++//}
++
++static int mhdp_cec_set_logical_addr(struct cdns_mhdp_cec *cec, u32 la)
++{
++      u8 i;
++      u8 la_reg;
++
++      if (la >= MAX_LA_VAL) {
++              dev_err(cec->dev, "Error logical Addr\n");
++              return -EINVAL;
++      }
++
++      for (i = 0; i < MAX_LA_IDX; ++i) {
++              la_reg =
++                  mhdp_cec_read(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF));
++
++              if (la_reg & 0x10)
++                      continue;
++
++              if ((la_reg & 0xF) == la) {
++                      dev_warn(cec->dev, "Warning. LA already in use.\n");
++                      return true;
++              }
++
++              la = (la & 0xF) | (1 << 4);
++
++              mhdp_cec_write(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF), la);
++              return true;
++      }
++
++      dev_warn(cec->dev, "All LA in use\n");
++
++      return false;
++}
++
++static int mhdp_cec_poll_worker(void *_cec)
++{
++      struct cdns_mhdp_cec *cec = (struct cdns_mhdp_cec *)_cec;
++      int num_rx_msgs, i;
++      int sts;
++
++      set_freezable();
++
++      for (;;) {
++              if (kthread_freezable_should_stop(NULL))
++                      break;
++
++              /* Check TX State */
++              sts = mhdp_cec_read(cec, TX_MSG_STATUS);
++              switch (sts) {
++              case CEC_STS_SUCCESS:
++                      cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0,
++                                        0);
++                      mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
++                      break;
++              case CEC_STS_ERROR:
++                      mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
++                      cec_transmit_done(cec->adap,
++                                        CEC_TX_STATUS_MAX_RETRIES |
++                                        CEC_TX_STATUS_NACK, 0, 1, 0, 0);
++                      break;
++              case CEC_STS_BUSY:
++              default:
++                      break;
++              }
++
++              /* Check RX State */
++              sts = mhdp_cec_read(cec, RX_MSG_STATUS);
++              num_rx_msgs = mhdp_cec_read(cec, NUM_OF_MSG_RX_BUF);
++              switch (sts) {
++              case CEC_STS_SUCCESS:
++                      if (num_rx_msgs == 0xf)
++                              num_rx_msgs = CEC_MAX_RX_MSGS;
++
++                      if (num_rx_msgs > CEC_MAX_RX_MSGS) {
++                              dev_err(cec->dev, "Error rx msg num %d\n",
++                                      num_rx_msgs);
++                              mhdp_cec_clear_rx_buffer(cec);
++                              break;
++                      }
++
++                      /* Rx FIFO Depth 2 RX MSG */
++                      for (i = 0; i < num_rx_msgs; i++) {
++                              mhdp_cec_read_message(cec);
++                              cec->msg.rx_status = CEC_RX_STATUS_OK;
++                              cec_received_msg(cec->adap, &cec->msg);
++                      }
++                      break;
++              default:
++                      break;
++              }
++
++              if (!kthread_should_stop())
++                      schedule_timeout_idle(20);
++      }
++
++      return 0;
++}
++
++static int mhdp_cec_adap_enable(struct cec_adapter *adap, bool enable)
++{
++      struct cdns_mhdp_cec *cec = adap->priv;
++
++      if (enable) {
++              mhdp_cec_write(cec, DB_L_TIMER, 0x10);
++              mhdp_cec_set_divider(cec);
++      } else
++              mhdp_cec_set_divider(cec);
++
++      return 0;
++}
++
++static int mhdp_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
++{
++      struct cdns_mhdp_cec *cec = adap->priv;
++
++      return mhdp_cec_set_logical_addr(cec, addr);
++}
++
++static int mhdp_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
++                               u32 signal_free_time, struct cec_msg *msg)
++{
++      struct cdns_mhdp_cec *cec = adap->priv;
++
++      mhdp_cec_write_message(cec, msg);
++
++      return 0;
++}
++
++static const struct cec_adap_ops cdns_mhdp_cec_adap_ops = {
++      .adap_enable = mhdp_cec_adap_enable,
++      .adap_log_addr = mhdp_cec_adap_log_addr,
++      .adap_transmit = mhdp_cec_adap_transmit,
++};
++
++int cdns_mhdp_register_cec_driver(struct device *dev)
++{
++      struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
++      struct cdns_mhdp_cec *cec = &mhdp->hdmi.cec;
++      int ret;
++
++      cec->adap = cec_allocate_adapter(&cdns_mhdp_cec_adap_ops, cec,
++                                       CEC_NAME,
++                                       CEC_CAP_PHYS_ADDR | CEC_CAP_LOG_ADDRS |
++                                       CEC_CAP_TRANSMIT | CEC_CAP_PASSTHROUGH
++                                       | CEC_CAP_RC, 1);
++      ret = PTR_ERR_OR_ZERO(cec->adap);
++      if (ret)
++              return ret;
++      ret = cec_register_adapter(cec->adap, dev);
++      if (ret) {
++              cec_delete_adapter(cec->adap);
++              return ret;
++      }
++
++      cec->dev = dev;
++
++      cec->cec_worker = kthread_create(mhdp_cec_poll_worker, cec, "cdns-mhdp-cec");
++      if (IS_ERR(cec->cec_worker))
++              dev_err(cec->dev, "failed  create hdp cec thread\n");
++
++      wake_up_process(cec->cec_worker);
++
++      dev_dbg(dev, "CEC successfuly probed\n");
++      return 0;
++}
++
++int cdns_mhdp_unregister_cec_driver(struct device *dev)
++{
++      struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
++      struct cdns_mhdp_cec *cec = &mhdp->hdmi.cec;
++
++      if (cec->cec_worker) {
++              kthread_stop(cec->cec_worker);
++              cec->cec_worker = NULL;
++      }
++      cec_unregister_adapter(cec->adap);
++      return 0;
++}
++
++MODULE_AUTHOR("Sandor.Yu@NXP.com");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("NXP CDNS MHDP CEC driver");
+--- a/include/drm/bridge/cdns-mhdp-common.h
++++ b/include/drm/bridge/cdns-mhdp-common.h
+@@ -21,7 +21,7 @@
+ #include <drm/drm_connector.h>
+ #include <drm/drm_dp_helper.h>
+ #include <drm/drm_dp_mst_helper.h>
+-
++#include <media/cec.h>
+ #include <linux/bitops.h>
+ #define ADDR_IMEM             0x10000
+@@ -605,6 +605,17 @@ struct cdns_mhdp_connector {
+       struct cdns_mhdp_bridge *bridge;
+ };
++#ifdef CONFIG_DRM_CDNS_HDMI_CEC
++struct cdns_mhdp_cec {
++       struct cec_adapter *adap;
++       struct device *dev;
++       struct mutex lock;
++
++       struct cec_msg msg;
++       struct task_struct *cec_worker;
++};
++#endif
++
+ struct cdns_mhdp_device {
+       void __iomem            *regs;
+@@ -633,7 +644,7 @@ struct cdns_mhdp_device {
+       bool plugged;
+       union {
+-              struct cdn_dp_data {
++              struct _dp_data {
+                       struct drm_dp_link      link;
+                       struct drm_dp_aux       aux;
+                       struct cdns_mhdp_host   host;
+@@ -645,6 +656,9 @@ struct cdns_mhdp_device {
+                       u32 num_lanes;
+               } dp;
+               struct _hdmi_data {
++#ifdef CONFIG_DRM_CDNS_HDMI_CEC
++                      struct cdns_mhdp_cec cec;
++#endif
+                       u32 char_rate;
+                       u32 hdmi_type;
+               } hdmi;
+@@ -713,4 +727,10 @@ int cdns_hdmi_disable_gcp(struct cdns_mh
+ int cdns_hdmi_enable_gcp(struct cdns_mhdp_device *mhdp);
+ bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp);
++/* CEC */
++#ifdef CONFIG_DRM_CDNS_HDMI_CEC
++int cdns_mhdp_register_cec_driver(struct device *dev);
++int cdns_mhdp_unregister_cec_driver(struct device *dev);
++#endif
++
+ #endif /* CDNS_MHDP_COMMON_H_ */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0009-drm-rockchip-Fix-build-failed-issue.patch b/target/linux/layerscape/patches-5.4/805-display-0009-drm-rockchip-Fix-build-failed-issue.patch
new file mode 100644 (file)
index 0000000..106c1f7
--- /dev/null
@@ -0,0 +1,24 @@
+From 9ab73f9efe983f2f9b6887150a2e7a48d7a57ded Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Mon, 2 Sep 2019 15:58:34 +0800
+Subject: [PATCH] drm: rockchip: Fix build failed issue
+
+Macro variable AFMT_SPDIF have renamed to AFMT_SPDIF_INT in headfile.
+use the correct variable to fix build issue.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/rockchip/cdn-dp-core.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
++++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
+@@ -797,7 +797,7 @@ static int cdn_dp_audio_hw_params(struct
+               audio.format = AFMT_I2S;
+               break;
+       case HDMI_SPDIF:
+-              audio.format = AFMT_SPDIF;
++              audio.format = AFMT_SPDIF_INT;
+               break;
+       default:
+               DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt);
diff --git a/target/linux/layerscape/patches-5.4/805-display-0010-drm-bridge-cadence-move-struct-imx_mhdp_device-to-dr.patch b/target/linux/layerscape/patches-5.4/805-display-0010-drm-bridge-cadence-move-struct-imx_mhdp_device-to-dr.patch
new file mode 100644 (file)
index 0000000..74e5a58
--- /dev/null
@@ -0,0 +1,1096 @@
+From fe1824851dd6f7d3ee6d5411edba4102dacea873 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Wed, 11 Sep 2019 17:16:47 +0800
+Subject: [PATCH] drm: bridge: cadence: move struct imx_mhdp_device to drm/imx
+
+move struct imx_mhdp_device to drm/imx folder.
+change the base address name from regs to regs_base.
+add mhdp bus access function.
+uniform variable name.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c     | 188 ++++++++++-----------
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c   | 190 ++++++++++------------
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c  |   1 -
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c    |   2 +-
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c |  43 ++---
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c   |   1 -
+ include/drm/bridge/cdns-mhdp-common.h             |  67 +++++++-
+ include/drm/bridge/cdns-mhdp-imx.h                | 121 --------------
+ 8 files changed, 258 insertions(+), 355 deletions(-)
+ delete mode 100644 include/drm/bridge/cdns-mhdp-imx.h
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -9,8 +9,7 @@
+  * (at your option) any later version.
+  *
+  */
+-
+-#include <drm/bridge/cdns-mhdp-imx.h>
++#include <drm/bridge/cdns-mhdp-common.h>
+ #include <drm/drm_atomic_helper.h>
+ #include <drm/drm_crtc_helper.h>
+ #include <drm/drm_edid.h>
+@@ -25,8 +24,6 @@
+ #include <linux/mutex.h>
+ #include <linux/of_device.h>
+-#define aux_to_hdp(x) container_of(x, struct imx_mhdp_device, aux)
+-
+ /*
+  * This function only implements native DPDC reads and writes
+  */
+@@ -111,24 +108,24 @@ static void dp_pixel_clk_reset(struct cd
+       cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val);
+ }
+-static void cdns_dp_mode_set(struct imx_mhdp_device *dp,
++static void cdns_dp_mode_set(struct cdns_mhdp_device *mhdp,
+                       const struct drm_display_mode *mode)
+ {
+       struct drm_dp_link link;
+-      struct cdns_mhdp_device *mhdp = &dp->mhdp;
+       u32 lane_mapping = mhdp->lane_mapping;
+       int ret;
+       char linkid[6];
+       memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
+-      dp->dual_mode = video_is_dual_mode(mode);
++      //Sandor TODO
++//    mhdp->dual_mode = video_is_dual_mode(mode);
+       dp_pixel_clk_reset(mhdp);
+-      hdp_plat_call(dp, pclock_change);
++      cdns_mhdp_plat_call(mhdp, pclk_rate);
+-      hdp_plat_call(dp, phy_init);
++      cdns_mhdp_plat_call(mhdp, phy_set);
+       ret = drm_dp_downstream_id(&mhdp->dp.aux, linkid);
+       if (ret < 0) {
+@@ -168,7 +165,7 @@ static void cdns_dp_mode_set(struct imx_
+       /* initialize phy if lanes or link rate differnt */
+       if (mhdp->dp.link.num_lanes != mhdp->dp.num_lanes ||
+                       mhdp->dp.link.rate != mhdp->dp.link_rate)
+-              hdp_plat_call(dp, phy_init);
++              cdns_mhdp_plat_call(mhdp, phy_set);
+       /* Video off */
+       ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
+@@ -215,11 +212,11 @@ static void cdns_dp_mode_set(struct imx_
+ static enum drm_connector_status
+ cdns_dp_connector_detect(struct drm_connector *connector, bool force)
+ {
+-      struct imx_mhdp_device *dp = container_of(connector,
+-                                      struct imx_mhdp_device, mhdp.connector.base);
++      struct cdns_mhdp_device *mhdp = container_of(connector,
++                                      struct cdns_mhdp_device, connector.base);
+       u8 hpd = 0xf;
+-      hpd = cdns_mhdp_read_hpd(&dp->mhdp);
++      hpd = cdns_mhdp_read_hpd(mhdp);
+       if (hpd == 1)
+               /* Cable Connected */
+               return connector_status_connected;
+@@ -235,15 +232,15 @@ cdns_dp_connector_detect(struct drm_conn
+ static int cdns_dp_connector_get_modes(struct drm_connector *connector)
+ {
+-      struct imx_mhdp_device *dp = container_of(connector,
+-                                              struct imx_mhdp_device, mhdp.connector.base);
++      struct cdns_mhdp_device *mhdp = container_of(connector,
++                                      struct cdns_mhdp_device, connector.base);
+       int num_modes = 0;
+       struct edid *edid;
+-      edid = drm_do_get_edid(&dp->mhdp.connector.base,
+-                                 cdns_mhdp_get_edid_block, &dp->mhdp);
++      edid = drm_do_get_edid(&mhdp->connector.base,
++                                 cdns_mhdp_get_edid_block, mhdp);
+       if (edid) {
+-              dev_info(dp->mhdp.dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
++              dev_info(mhdp->dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
+                        edid->header[0], edid->header[1],
+                        edid->header[2], edid->header[3],
+                        edid->header[4], edid->header[5],
+@@ -273,9 +270,9 @@ static const struct drm_connector_helper
+ static int cdns_dp_bridge_attach(struct drm_bridge *bridge)
+ {
+-      struct imx_mhdp_device *dp = bridge->driver_private;
++      struct cdns_mhdp_device *mhdp = bridge->driver_private;
+       struct drm_encoder *encoder = bridge->encoder;
+-      struct drm_connector *connector = &dp->mhdp.connector.base;
++      struct drm_connector *connector = &mhdp->connector.base;
+       connector->interlace_allowed = 1;
+       connector->polled = DRM_CONNECTOR_POLL_HPD;
+@@ -319,9 +316,9 @@ static void cdns_dp_bridge_mode_set(stru
+                                   const struct drm_display_mode *orig_mode,
+                                   const struct drm_display_mode *mode)
+ {
+-      struct imx_mhdp_device *dp = bridge->driver_private;
+-      struct drm_display_info *display_info = &dp->mhdp.connector.base.display_info;
+-      struct video_info *video = &dp->mhdp.video_info;
++      struct cdns_mhdp_device *mhdp = bridge->driver_private;
++      struct drm_display_info *display_info = &mhdp->connector.base.display_info;
++      struct video_info *video = &mhdp->video_info;
+       switch (display_info->bpc) {
+       case 10:
+@@ -341,11 +338,11 @@ static void cdns_dp_bridge_mode_set(stru
+       DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); 
+-      mutex_lock(&dp->lock);
++      mutex_lock(&mhdp->lock);
+-      cdns_dp_mode_set(dp, mode);
++      cdns_dp_mode_set(mhdp, mode);
+-      mutex_unlock(&dp->lock);
++      mutex_unlock(&mhdp->lock);
+ }
+ static void cdn_hdp_bridge_enable(struct drm_bridge *bridge)
+@@ -354,8 +351,7 @@ static void cdn_hdp_bridge_enable(struct
+ static void cdn_hdp_bridge_disable(struct drm_bridge *bridge)
+ {     
+-      struct imx_mhdp_device *dp = bridge->driver_private;
+-      struct cdns_mhdp_device *mhdp = &dp->mhdp;
++      struct cdns_mhdp_device *mhdp = bridge->driver_private;
+       cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
+       drm_dp_link_power_down(&mhdp->dp.aux, &mhdp->dp.link);
+@@ -371,29 +367,29 @@ static const struct drm_bridge_funcs cdn
+ static void hotplug_work_func(struct work_struct *work)
+ {
+-      struct imx_mhdp_device *dp = container_of(work,
+-                                         struct imx_mhdp_device, hotplug_work.work);
+-      struct drm_connector *connector = &dp->mhdp.connector.base;
++      struct cdns_mhdp_device *mhdp = container_of(work,
++                                         struct cdns_mhdp_device, hotplug_work.work);
++      struct drm_connector *connector = &mhdp->connector.base;
+       drm_helper_hpd_irq_event(connector->dev);
+       if (connector->status == connector_status_connected) {
+               DRM_INFO("HDMI/DP Cable Plug In\n");
+-              enable_irq(dp->irq[IRQ_OUT]);
++              enable_irq(mhdp->irq[IRQ_OUT]);
+       } else if (connector->status == connector_status_disconnected) {
+               /* Cable Disconnedted  */
+               DRM_INFO("HDMI/DP Cable Plug Out\n");
+-              enable_irq(dp->irq[IRQ_IN]);
++              enable_irq(mhdp->irq[IRQ_IN]);
+       }
+ }
+ static irqreturn_t cdns_dp_irq_thread(int irq, void *data)
+ {
+-      struct imx_mhdp_device *dp = data;
++      struct cdns_mhdp_device *mhdp = data;
+       disable_irq_nosync(irq);
+-      mod_delayed_work(system_wq, &dp->hotplug_work,
++      mod_delayed_work(system_wq, &mhdp->hotplug_work,
+                       msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
+       return IRQ_HANDLED;
+@@ -430,111 +426,92 @@ static void cdns_dp_parse_dt(struct cdns
+       mhdp->dp.link.rate= mhdp->dp.link_rate;
+ }
+-static struct imx_mhdp_device *
+-__cdns_dp_probe(struct platform_device *pdev,
+-              const struct cdn_plat_data *plat_data)
++static int __cdns_dp_probe(struct platform_device *pdev,
++              struct cdns_mhdp_device *mhdp)
+ {
+       struct device *dev = &pdev->dev;
+-      struct imx_mhdp_device *dp;
+       struct resource *iores = NULL;
+       int ret;
+-      dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
+-      if (!dp)
+-              return ERR_PTR(-ENOMEM);
+-
+-      dp->plat_data = plat_data;
+-      dp->mhdp.dev = dev;
+-
+-      mutex_init(&dp->lock);
+-      mutex_init(&dp->audio_mutex);
+-      spin_lock_init(&dp->audio_lock);
++      mutex_init(&mhdp->lock);
+-      INIT_DELAYED_WORK(&dp->hotplug_work, hotplug_work_func);
++      INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func);
+       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-      dp->mhdp.regs = devm_ioremap(dev, iores->start, resource_size(iores));
+-      if (IS_ERR(dp->mhdp.regs)) {
+-              ret = PTR_ERR(dp->mhdp.regs);
+-              goto err_out;
+-      }
++      mhdp->regs_base = devm_ioremap(dev, iores->start, resource_size(iores));
++      if (IS_ERR(mhdp->regs_base))
++              return -ENOMEM;
+-#if 0
+       iores = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+-      dp->regs_ss = devm_ioremap(dev, iores->start, resource_size(iores));
+-      if (IS_ERR(dp->regs_ss)) {
+-              ret = PTR_ERR(dp->regs_ss);
+-              goto err_out;
+-      }
+-#endif
++      mhdp->regs_sec = devm_ioremap(dev, iores->start, resource_size(iores));
++      if (IS_ERR(mhdp->regs_sec))
++              return -ENOMEM;
+-      dp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
+-      if (dp->irq[IRQ_IN] < 0)
++      mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
++      if (mhdp->irq[IRQ_IN] < 0)
+               dev_info(dev, "No plug_in irq number\n");
+-      dp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
+-      if (dp->irq[IRQ_OUT] < 0)
++      mhdp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
++      if (mhdp->irq[IRQ_OUT] < 0)
+               dev_info(dev, "No plug_out irq number\n");
+-      cdns_dp_parse_dt(&dp->mhdp);
++      cdns_dp_parse_dt(mhdp);
+-      dp->dual_mode = false;
+-      hdp_plat_call(dp, fw_init);
++//    mhdp->dual_mode = false;
++      cdns_mhdp_plat_call(mhdp, firmware_init);
+       /* DP FW alive check */
+-      ret = cdns_mhdp_check_alive(&dp->mhdp);
++      ret = cdns_mhdp_check_alive(mhdp);
+       if (ret == false) {
+               DRM_ERROR("NO dp FW running\n");
+-              return ERR_PTR(-ENXIO);
++              return -ENXIO;
+       }
+       /* DP PHY init before AUX init */
+-      hdp_plat_call(dp, phy_init);
++      cdns_mhdp_plat_call(mhdp, phy_set);
+       /* Enable Hotplug Detect IRQ thread */
+-      irq_set_status_flags(dp->irq[IRQ_IN], IRQ_NOAUTOEN);
+-      ret = devm_request_threaded_irq(dev, dp->irq[IRQ_IN],
++      irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN);
++      ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN],
+                                       NULL, cdns_dp_irq_thread,
+                                       IRQF_ONESHOT, dev_name(dev),
+-                                      dp);
++                                      mhdp);
+       if (ret) {
+               dev_err(dev, "can't claim irq %d\n",
+-                                              dp->irq[IRQ_IN]);
+-              goto err_out;
++                                              mhdp->irq[IRQ_IN]);
++              return -EINVAL;
+       }
+       
+-      irq_set_status_flags(dp->irq[IRQ_OUT], IRQ_NOAUTOEN);
+-      ret = devm_request_threaded_irq(dev, dp->irq[IRQ_OUT],
++      irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN);
++      ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT],
+                                       NULL, cdns_dp_irq_thread,
+                                       IRQF_ONESHOT, dev_name(dev),
+-                                      dp);
++                                      mhdp);
+       if (ret) {
+               dev_err(dev, "can't claim irq %d\n",
+-                                              dp->irq[IRQ_OUT]);
+-              goto err_out;
++                                              mhdp->irq[IRQ_OUT]);
++              return -EINVAL;
+       }
+-      if (cdns_mhdp_read_hpd(&dp->mhdp))
+-              enable_irq(dp->irq[IRQ_OUT]);
++
++      if (cdns_mhdp_read_hpd(mhdp))
++              enable_irq(mhdp->irq[IRQ_OUT]);
+       else
+-              enable_irq(dp->irq[IRQ_IN]);
++              enable_irq(mhdp->irq[IRQ_IN]);
+-      dp->mhdp.bridge.base.driver_private = dp;
+-      dp->mhdp.bridge.base.funcs = &cdns_dp_bridge_funcs;
++      mhdp->bridge.base.driver_private = mhdp;
++      mhdp->bridge.base.funcs = &cdns_dp_bridge_funcs;
+ #ifdef CONFIG_OF
+-      dp->mhdp.bridge.base.of_node = dev->of_node;
++      mhdp->bridge.base.of_node = dev->of_node;
+ #endif
+-      dev_set_drvdata(dev, &dp->mhdp);
++      dev_set_drvdata(dev, mhdp);
+       
+       /* register audio driver */
+       cdns_mhdp_register_audio_driver(dev);
+-      dp_aux_init(&dp->mhdp, dev);
+-
+-      return dp;
++      dp_aux_init(mhdp, dev);
+-err_out:
+-      return ERR_PTR(ret);
++      return 0;
+ }
+ static void __cdns_dp_remove(struct cdns_mhdp_device *mhdp)
+@@ -547,15 +524,15 @@ static void __cdns_dp_remove(struct cdns
+  * Probe/remove API, used from platforms based on the DRM bridge API.
+  */
+ int cdns_dp_probe(struct platform_device *pdev,
+-                const struct cdn_plat_data *plat_data)
++                struct cdns_mhdp_device *mhdp)
+ {
+-      struct imx_mhdp_device *dp;
++      int ret;
+-      dp = __cdns_dp_probe(pdev, plat_data);
+-      if (IS_ERR(dp))
+-              return PTR_ERR(dp);
++      ret = __cdns_dp_probe(pdev, mhdp);
++      if (ret)
++              return ret;
+-      drm_bridge_add(&dp->mhdp.bridge.base);
++      drm_bridge_add(&mhdp->bridge.base);
+       return 0;
+ }
+@@ -575,16 +552,15 @@ EXPORT_SYMBOL_GPL(cdns_dp_remove);
+  * Bind/unbind API, used from platforms based on the component framework.
+  */
+ int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
+-               const struct cdn_plat_data *plat_data)
++              struct cdns_mhdp_device *mhdp)
+ {
+-      struct imx_mhdp_device *dp;
+       int ret;
+-      dp = __cdns_dp_probe(pdev, plat_data);
+-      if (IS_ERR(dp))
+-              return PTR_ERR(dp);
++      ret = __cdns_dp_probe(pdev, mhdp);
++      if (ret < 0)
++              return ret;
+-      ret = drm_bridge_attach(encoder, &dp->mhdp.bridge.base, NULL);
++      ret = drm_bridge_attach(encoder, &mhdp->bridge.base, NULL);
+       if (ret) {
+               cdns_dp_remove(pdev);
+               DRM_ERROR("Failed to initialize bridge with drm\n");
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -9,7 +9,7 @@
+  * (at your option) any later version.
+  *
+  */
+-#include <drm/bridge/cdns-mhdp-imx.h>
++#include <drm/bridge/cdns-mhdp-common.h>
+ #include <drm/drm_atomic_helper.h>
+ #include <drm/drm_crtc_helper.h>
+ #include <drm/drm_edid.h>
+@@ -60,8 +60,6 @@ static int hdmi_sink_config(struct cdns_
+ static void hdmi_lanes_config(struct cdns_mhdp_device *mhdp)
+ {
+       /* Line swaping */
+-      /* For imx8qm lane_mapping = 0x93
+-       * For imx8mq lane_mapping = 0xe4*/
+       cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | mhdp->lane_mapping);
+ }
+@@ -216,12 +214,12 @@ void cdns_hdmi_mode_set(struct cdns_mhdp
+ static enum drm_connector_status
+ cdns_hdmi_connector_detect(struct drm_connector *connector, bool force)
+ {
+-      struct imx_mhdp_device *hdmi =
+-                              container_of(connector, struct imx_mhdp_device, mhdp.connector.base);
++      struct cdns_mhdp_device *mhdp =
++                              container_of(connector, struct cdns_mhdp_device, connector.base);
+       u8 hpd = 0xf;
+-      hpd = cdns_mhdp_read_hpd(&hdmi->mhdp);
++      hpd = cdns_mhdp_read_hpd(mhdp);
+       if (hpd == 1)
+               /* Cable Connected */
+@@ -238,15 +236,15 @@ cdns_hdmi_connector_detect(struct drm_co
+ static int cdns_hdmi_connector_get_modes(struct drm_connector *connector)
+ {
+-      struct imx_mhdp_device *hdmi = container_of(connector, struct imx_mhdp_device,
+-                                           mhdp.connector.base);
++      struct cdns_mhdp_device *mhdp =
++                              container_of(connector, struct cdns_mhdp_device, connector.base);
+       int num_modes = 0;
+       struct edid *edid;
+-      edid = drm_do_get_edid(&hdmi->mhdp.connector.base,
+-                                 cdns_hdmi_get_edid_block, &hdmi->mhdp);
++      edid = drm_do_get_edid(&mhdp->connector.base,
++                                 cdns_hdmi_get_edid_block, mhdp);
+       if (edid) {
+-              dev_info(hdmi->mhdp.dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
++              dev_info(mhdp->dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
+                        edid->header[0], edid->header[1],
+                        edid->header[2], edid->header[3],
+                        edid->header[4], edid->header[5],
+@@ -276,9 +274,9 @@ static const struct drm_connector_helper
+ static int cdns_hdmi_bridge_attach(struct drm_bridge *bridge)
+ {
+-      struct imx_mhdp_device *hdmi = bridge->driver_private;
++      struct cdns_mhdp_device *mhdp = bridge->driver_private;
+       struct drm_encoder *encoder = bridge->encoder;
+-      struct drm_connector *connector = &hdmi->mhdp.connector.base;
++      struct drm_connector *connector = &mhdp->connector.base;
+       connector->interlace_allowed = 1;
+       connector->polled = DRM_CONNECTOR_POLL_HPD;
+@@ -319,9 +317,9 @@ static void cdns_hdmi_bridge_mode_set(st
+                                   const struct drm_display_mode *orig_mode,
+                                   const struct drm_display_mode *mode)
+ {
+-      struct imx_mhdp_device *hdmi = bridge->driver_private;
+-      struct drm_display_info *display_info = &hdmi->mhdp.connector.base.display_info;
+-      struct video_info *video = &hdmi->mhdp.video_info;
++      struct cdns_mhdp_device *mhdp = bridge->driver_private;
++      struct drm_display_info *display_info = &mhdp->connector.base.display_info;
++      struct video_info *video = &mhdp->video_info;
+       switch (display_info->bpc) {
+       case 10:
+@@ -339,23 +337,24 @@ static void cdns_hdmi_bridge_mode_set(st
+       video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
+       video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
+-      mutex_lock(&hdmi->lock);
++      mutex_lock(&mhdp->lock);
+       DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); 
+-      memcpy(&hdmi->mhdp.mode, mode, sizeof(struct drm_display_mode));
++      memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
+-      hdmi->dual_mode = video_is_dual_mode(mode);
++      //Sandor TODO
++//    hdmi->dual_mode = video_is_dual_mode(mode);
+-      hdmi_lanes_config(&hdmi->mhdp);
++      hdmi_lanes_config(mhdp);
+-      hdp_plat_call(hdmi, pclock_change);
++      cdns_mhdp_plat_call(mhdp, pclk_rate);
+-      hdp_plat_call(hdmi, phy_init);
++      cdns_mhdp_plat_call(mhdp, phy_set);
+-      cdns_hdmi_mode_set(&hdmi->mhdp);
++      cdns_hdmi_mode_set(mhdp);
+-      mutex_unlock(&hdmi->lock);
++      mutex_unlock(&mhdp->lock);
+ }
+ static const struct drm_bridge_funcs cdns_hdmi_bridge_funcs = {
+@@ -366,30 +365,30 @@ static const struct drm_bridge_funcs cdn
+ static void hotplug_work_func(struct work_struct *work)
+ {
+-      struct imx_mhdp_device *hdmi = container_of(work,
+-                                         struct imx_mhdp_device, hotplug_work.work);
+-      struct drm_connector *connector = &hdmi->mhdp.connector.base;
++      struct cdns_mhdp_device *mhdp = container_of(work,
++                                         struct cdns_mhdp_device, hotplug_work.work);
++      struct drm_connector *connector = &mhdp->connector.base;
+       drm_helper_hpd_irq_event(connector->dev);
+       if (connector->status == connector_status_connected) {
+               /* Cable Connected */
+               DRM_INFO("HDMI Cable Plug In\n");
+-              enable_irq(hdmi->irq[IRQ_OUT]);
++              enable_irq(mhdp->irq[IRQ_OUT]);
+       } else if (connector->status == connector_status_disconnected) {
+               /* Cable Disconnedted  */
+               DRM_INFO("HDMI Cable Plug Out\n");
+-              enable_irq(hdmi->irq[IRQ_IN]);
++              enable_irq(mhdp->irq[IRQ_IN]);
+       }
+ }
+ static irqreturn_t cdns_hdmi_irq_thread(int irq, void *data)
+ {
+-      struct imx_mhdp_device *hdmi = data;
++      struct cdns_mhdp_device *mhdp = data;
+       disable_irq_nosync(irq);
+-      mod_delayed_work(system_wq, &hdmi->hotplug_work,
++      mod_delayed_work(system_wq, &mhdp->hotplug_work,
+                       msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
+       return IRQ_HANDLED;
+@@ -408,109 +407,99 @@ static void cdns_hdmi_parse_dt(struct cd
+       dev_info(mhdp->dev, "lane-mapping 0x%02x\n", mhdp->lane_mapping);
+ }
+-static struct imx_mhdp_device *
+-__cdns_hdmi_probe(struct platform_device *pdev,
+-                      const struct cdn_plat_data *plat_data)
++static int __cdns_hdmi_probe(struct platform_device *pdev,
++                struct cdns_mhdp_device *mhdp)
+ {
+       struct device *dev = &pdev->dev;
+-      struct device_node *np = dev->of_node;
+       struct platform_device_info pdevinfo;
+-      struct imx_mhdp_device *hdmi;
+       struct resource *iores = NULL;
+       int ret;
+-      hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
+-      if (!hdmi)
+-              return ERR_PTR(-ENOMEM);
+-
+-      hdmi->plat_data = plat_data;
+-      hdmi->mhdp.dev = dev;
+-
+-      mutex_init(&hdmi->lock);
+-      mutex_init(&hdmi->audio_mutex);
+-      spin_lock_init(&hdmi->audio_lock);
++      mutex_init(&mhdp->lock);
+-      INIT_DELAYED_WORK(&hdmi->hotplug_work, hotplug_work_func);
++      INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func);
+       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-      hdmi->mhdp.regs = devm_ioremap(dev, iores->start, resource_size(iores));
+-      if (IS_ERR(hdmi->mhdp.regs)) {
+-              ret = PTR_ERR(hdmi->mhdp.regs);
+-              goto err_out;
++      mhdp->regs_base = devm_ioremap(dev, iores->start, resource_size(iores));
++      if (IS_ERR(mhdp->regs_base)) {
++              dev_err(dev, "No regs_base memory\n");
++              return -ENOMEM;
++      }
++
++      /* sec register base */
++      iores = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++      mhdp->regs_sec = devm_ioremap(dev, iores->start, resource_size(iores));
++      if (IS_ERR(mhdp->regs_sec)) {
++              dev_err(dev, "No regs_sec memory\n");
++              return -ENOMEM;
+       }
+-      /* csr register base */
+-      hdmi->regmap_csr = syscon_regmap_lookup_by_phandle(np, "csr");
+-      if (IS_ERR(hdmi->regmap_csr)) {
+-              dev_info(dev, "No csr regmap\n");
+-      }
+-
+-      hdmi->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
+-      if (hdmi->irq[IRQ_IN] < 0) {
++      mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
++      if (mhdp->irq[IRQ_IN] < 0) {
+               dev_info(dev, "No plug_in irq number\n");
+-              return ERR_PTR(-EPROBE_DEFER);
++              return -EPROBE_DEFER;
+       }
+-      hdmi->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
+-      if (hdmi->irq[IRQ_OUT] < 0) {
++      mhdp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
++      if (mhdp->irq[IRQ_OUT] < 0) {
+               dev_info(dev, "No plug_out irq number\n");
+-              return ERR_PTR(-EPROBE_DEFER);
++              return -EPROBE_DEFER;
+       }
+       /* Initialize dual_mode to false */
+-      hdmi->dual_mode = false;
++//    hdmi->dual_mode = false;
+       /* Initialize FW */
+-      hdp_plat_call(hdmi, fw_init);
++      cdns_mhdp_plat_call(mhdp, firmware_init);
+       /* HDMI FW alive check */
+-      ret = cdns_mhdp_check_alive(&hdmi->mhdp);
++      ret = cdns_mhdp_check_alive(mhdp);
+       if (ret == false) {
+-              DRM_ERROR("NO HDMI FW running\n");
+-              return ERR_PTR(-ENXIO);
++              dev_err(dev, "NO HDMI FW running\n");
++              return -ENXIO;
+       }
+       /* Enable Hotplug Detect thread */
+-      irq_set_status_flags(hdmi->irq[IRQ_IN], IRQ_NOAUTOEN);
+-      ret = devm_request_threaded_irq(dev, hdmi->irq[IRQ_IN],
++      irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN);
++      ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN],
+                                       NULL, cdns_hdmi_irq_thread,
+                                       IRQF_ONESHOT, dev_name(dev),
+-                                      hdmi);
+-      if (ret) {
++                                      mhdp);
++      if (ret < 0) {
+               dev_err(dev, "can't claim irq %d\n",
+-                                              hdmi->irq[IRQ_IN]);
+-              goto err_out;
++                                              mhdp->irq[IRQ_IN]);
++              return -EINVAL;
+       }
+       
+-      irq_set_status_flags(hdmi->irq[IRQ_OUT], IRQ_NOAUTOEN);
+-      ret = devm_request_threaded_irq(dev, hdmi->irq[IRQ_OUT],
++      irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN);
++      ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT],
+                                       NULL, cdns_hdmi_irq_thread,
+                                       IRQF_ONESHOT, dev_name(dev),
+-                                      hdmi);
+-      if (ret) {
++                                      mhdp);
++      if (ret < 0) {
+               dev_err(dev, "can't claim irq %d\n",
+-                                              hdmi->irq[IRQ_OUT]);
+-              goto err_out;
++                                              mhdp->irq[IRQ_OUT]);
++              return -EINVAL;
+       }
+-      cdns_hdmi_parse_dt(&hdmi->mhdp);
++      cdns_hdmi_parse_dt(mhdp);
+-      if (cdns_mhdp_read_hpd(&hdmi->mhdp))
+-              enable_irq(hdmi->irq[IRQ_OUT]);
++      if (cdns_mhdp_read_hpd(mhdp))
++              enable_irq(mhdp->irq[IRQ_OUT]);
+       else
+-              enable_irq(hdmi->irq[IRQ_IN]);
++              enable_irq(mhdp->irq[IRQ_IN]);
+-      hdmi->mhdp.bridge.base.driver_private = hdmi;
+-      hdmi->mhdp.bridge.base.funcs = &cdns_hdmi_bridge_funcs;
++      mhdp->bridge.base.driver_private = mhdp;
++      mhdp->bridge.base.funcs = &cdns_hdmi_bridge_funcs;
+ #ifdef CONFIG_OF
+-      hdmi->mhdp.bridge.base.of_node = dev->of_node;
++      mhdp->bridge.base.of_node = dev->of_node;
+ #endif
+       memset(&pdevinfo, 0, sizeof(pdevinfo));
+       pdevinfo.parent = dev;
+       pdevinfo.id = PLATFORM_DEVID_AUTO;
+-      dev_set_drvdata(dev, &hdmi->mhdp);
++      dev_set_drvdata(dev, mhdp);
+       /* register audio driver */
+       cdns_mhdp_register_audio_driver(dev);
+@@ -520,11 +509,7 @@ __cdns_hdmi_probe(struct platform_device
+       cdns_mhdp_register_cec_driver(dev);
+ #endif
+-      return hdmi;
+-
+-err_out:
+-
+-      return ERR_PTR(ret);
++      return 0;
+ }
+ static void __cdns_hdmi_remove(struct cdns_mhdp_device *mhdp)
+@@ -540,15 +525,15 @@ static void __cdns_hdmi_remove(struct cd
+  * Probe/remove API, used from platforms based on the DRM bridge API.
+  */
+ int cdns_hdmi_probe(struct platform_device *pdev,
+-                const struct cdn_plat_data *plat_data)
++              struct cdns_mhdp_device *mhdp)
+ {
+-      struct imx_mhdp_device *hdmi;
++      int ret;
+-      hdmi = __cdns_hdmi_probe(pdev, plat_data);
+-      if (IS_ERR(hdmi))
+-              return PTR_ERR(hdmi);
++      ret  = __cdns_hdmi_probe(pdev, mhdp);
++      if (ret < 0)
++              return ret;
+-      drm_bridge_add(&hdmi->mhdp.bridge.base);
++      drm_bridge_add(&mhdp->bridge.base);
+       return 0;
+ }
+@@ -568,16 +553,15 @@ EXPORT_SYMBOL_GPL(cdns_hdmi_remove);
+  * Bind/unbind API, used from platforms based on the component framework.
+  */
+ int cdns_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
+-               const struct cdn_plat_data *plat_data)
++                      struct cdns_mhdp_device *mhdp)
+ {
+-      struct imx_mhdp_device *hdmi;
+       int ret;
+-      hdmi = __cdns_hdmi_probe(pdev, plat_data);
+-      if (IS_ERR(hdmi))
+-              return PTR_ERR(hdmi);
++      ret = __cdns_hdmi_probe(pdev, mhdp);
++      if (ret)
++              return ret;
+-      ret = drm_bridge_attach(encoder, &hdmi->mhdp.bridge.base, NULL);
++      ret = drm_bridge_attach(encoder, &mhdp->bridge.base, NULL);
+       if (ret) {
+               cdns_hdmi_remove(pdev);
+               DRM_ERROR("Failed to initialize bridge with drm\n");
+--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
+@@ -16,7 +16,6 @@
+ #include <linux/reset.h>
+ #include <drm/bridge/cdns-mhdp-common.h>
+ #include <sound/hdmi-codec.h>
+-#include <drm/bridge/cdns-mhdp-imx.h>
+ #include <drm/drm_of.h>
+ #include <drm/drmP.h>
+--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c
+@@ -344,4 +344,4 @@ int cdns_mhdp_unregister_cec_driver(stru
+ MODULE_AUTHOR("Sandor.Yu@NXP.com");
+ MODULE_LICENSE("GPL");
+-MODULE_DESCRIPTION("NXP CDNS MHDP CEC driver");
++MODULE_DESCRIPTION("NXP CDNS MHDP HDMI CEC driver");
+--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
+@@ -23,7 +23,6 @@
+ #include <asm/unaligned.h>
+ #include <drm/bridge/cdns-mhdp-common.h>
+-#include <drm/bridge/cdns-mhdp-imx.h>
+ #include <drm/drm_modes.h>
+ #include <drm/drm_print.h>
+ #include <linux/regmap.h>
+@@ -74,18 +73,20 @@ static inline void put_unaligned_be24(u3
+ u32 cdns_mhdp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset)
+ {
+-      struct imx_mhdp_device *hdmi = container_of(mhdp, struct imx_mhdp_device, mhdp);
+       u32 val;
+-      /* TODO */
+-      if (offset >= 0x1000 && hdmi->regmap_csr) {
++      if (mhdp->bus_type == BUS_TYPE_LOW4K_SAPB) {
++              /* Remap address to low 4K SAPB bus */
++              writel(offset >> 12, mhdp->regs_sec + 0xc);
++              val = readl((offset & 0xfff) + mhdp->regs_base);
++      } else if (mhdp->bus_type == BUS_TYPE_LOW4K_APB) {
+               /* Remap address to low 4K memory */
+-              regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, offset >> 12);
+-              val = readl((offset & 0xfff) + mhdp->regs);
+-              /* Restore address mapping */
+-              regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, 0);
+-      } else
+-              val = readl(mhdp->regs + offset);
++              writel(offset >> 12, mhdp->regs_sec + 8);
++              val = readl((offset & 0xfff) + mhdp->regs_base);
++      } else if (mhdp->bus_type == BUS_TYPE_NORMAL_SAPB)
++              val = readl(mhdp->regs_sec + offset);
++      else
++              val = readl(mhdp->regs_base + offset);
+       return val;
+ }
+@@ -93,18 +94,18 @@ EXPORT_SYMBOL(cdns_mhdp_bus_read);
+ void cdns_mhdp_bus_write(u32 val, struct cdns_mhdp_device *mhdp, u32 offset)
+ {
+-      struct imx_mhdp_device *hdmi = container_of(mhdp, struct imx_mhdp_device, mhdp);
+-
+-      /* TODO */
+-      if (offset >= 0x1000 && hdmi->regmap_csr) {
++      if (mhdp->bus_type == BUS_TYPE_LOW4K_SAPB) {
++              /* Remap address to low 4K SAPB bus */
++              writel(offset >> 12, mhdp->regs_sec + 0xc);
++              writel(val, (offset & 0xfff) + mhdp->regs_base);
++      } else if (mhdp->bus_type == BUS_TYPE_LOW4K_APB) {
+               /* Remap address to low 4K memory */
+-              regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, offset >> 12);
+-              writel(val, (offset & 0xfff) + mhdp->regs);
+-              /* Restore address mapping */
+-              regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, 0);
+-
+-      } else
+-              writel(val, mhdp->regs + offset);
++              writel(offset >> 12, mhdp->regs_sec + 8);
++              writel(val, (offset & 0xfff) + mhdp->regs_base);
++      } else if (mhdp->bus_type == BUS_TYPE_NORMAL_SAPB)
++              writel(val, mhdp->regs_sec + offset);
++      else
++              writel(val, mhdp->regs_base + offset);
+ }
+ EXPORT_SYMBOL(cdns_mhdp_bus_write);
+--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
+@@ -10,7 +10,6 @@
+ #include <drm/drmP.h>
+ #include <linux/io.h>
+ #include <drm/bridge/cdns-mhdp-common.h>
+-#include <drm/bridge/cdns-mhdp-imx.h>
+ #include <linux/regmap.h>
+ void cdns_mhdp_infoframe_set(struct cdns_mhdp_device *mhdp,
+--- a/include/drm/bridge/cdns-mhdp-common.h
++++ b/include/drm/bridge/cdns-mhdp-common.h
+@@ -495,6 +495,22 @@
+ #define HOTPLUG_DEBOUNCE_MS           200
++#define IRQ_IN    0
++#define IRQ_OUT   1
++#define IRQ_NUM   2
++
++#define cdns_mhdp_plat_call(mhdp, operation)                  \
++      (!(mhdp) ? -ENODEV : (((mhdp)->plat_data && (mhdp)->plat_data->operation) ?     \
++       (mhdp)->plat_data->operation(mhdp) : ENOIOCTLCMD))
++
++/* bus access type */
++enum {
++      BUS_TYPE_NORMAL_APB = 0,
++      BUS_TYPE_NORMAL_SAPB = 1,
++      BUS_TYPE_LOW4K_APB = 2,
++      BUS_TYPE_LOW4K_SAPB = 3,
++};
++
+ enum voltage_swing_level {
+       VOLTAGE_LEVEL_0,
+       VOLTAGE_LEVEL_1,
+@@ -616,8 +632,33 @@ struct cdns_mhdp_cec {
+ };
+ #endif
++struct cdns_plat_data {
++      /* Vendor PHY support */
++      int (*bind)(struct platform_device *pdev,
++                      struct drm_encoder *encoder,
++                      struct cdns_mhdp_device *mhdp);
++      void (*unbind)(struct device *dev);
++
++      void (*plat_init)(struct cdns_mhdp_device *mhdp);
++      void (*plat_deinit)(struct cdns_mhdp_device *mhdp);
++
++      int (*phy_set)(struct cdns_mhdp_device *mhdp);
++      int (*firmware_init)(struct cdns_mhdp_device *mhdp);
++      void (*pclk_rate)(struct cdns_mhdp_device *mhdp);
++
++      int (*power_on)(struct cdns_mhdp_device *mhdp);
++      int (*power_off)(struct cdns_mhdp_device *mhdp);
++
++      int bus_type;
++      int video_format;
++      char is_dp;
++};
++
+ struct cdns_mhdp_device {
+-      void __iomem            *regs;
++      void __iomem            *regs_base;
++      void __iomem            *regs_sec;
++
++      int bus_type;
+       struct device           *dev;
+@@ -642,6 +683,9 @@ struct cdns_mhdp_device {
+       bool link_up;
+       bool power_up;
+       bool plugged;
++      struct mutex lock;
++
++      int irq[IRQ_NUM];
+       union {
+               struct _dp_data {
+@@ -663,6 +707,8 @@ struct cdns_mhdp_device {
+                       u32 hdmi_type;
+               } hdmi;
+       };
++      const struct cdns_plat_data *plat_data;
++
+ };
+ u32 cdns_mhdp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset);
+@@ -727,6 +773,25 @@ int cdns_hdmi_disable_gcp(struct cdns_mh
+ int cdns_hdmi_enable_gcp(struct cdns_mhdp_device *mhdp);
+ bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp);
++
++/* HDMI */
++int cdns_hdmi_probe(struct platform_device *pdev,
++               struct cdns_mhdp_device *mhdp);
++void cdns_hdmi_remove(struct platform_device *pdev);
++void cdns_hdmi_unbind(struct device *dev);
++int cdns_hdmi_bind(struct platform_device *pdev,
++                      struct drm_encoder *encoder, struct cdns_mhdp_device *mhdp);
++void cdns_hdmi_set_sample_rate(struct cdns_mhdp_device *mhdp, unsigned int rate);
++void cdns_hdmi_audio_enable(struct cdns_mhdp_device *mhdp);
++void cdns_hdmi_audio_disable(struct cdns_mhdp_device *mhdp);
++/* DP  */
++int cdns_dp_probe(struct platform_device *pdev,
++               struct cdns_mhdp_device *mhdp);
++void cdns_dp_remove(struct platform_device *pdev);
++void cdns_dp_unbind(struct device *dev);
++int cdns_dp_bind(struct platform_device *pdev,
++                      struct drm_encoder *encoder, struct cdns_mhdp_device *mhdp);
++
+ /* CEC */
+ #ifdef CONFIG_DRM_CDNS_HDMI_CEC
+ int cdns_mhdp_register_cec_driver(struct device *dev);
+--- a/include/drm/bridge/cdns-mhdp-imx.h
++++ /dev/null
+@@ -1,121 +0,0 @@
+-/*
+- * Cadence High-Definition Multimedia Interface (HDMI) driver
+- *
+- * Copyright (C) 2019 NXP Semiconductor, Inc.
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- */
+-#ifndef CDNS_MHDP_IMX_H_
+-#define CDNS_MHDP_IMX_H_
+-
+-#include <drm/bridge/cdns-mhdp-common.h>
+-
+-#define IRQ_IN    0
+-#define IRQ_OUT   1
+-#define IRQ_NUM   2
+-
+-#define hdp_plat_call(hdp, operation)                 \
+-      (!(hdp) ? -ENODEV : (((hdp)->plat_data && (hdp)->plat_data->operation) ?        \
+-       (hdp)->plat_data->operation(hdp) : ENOIOCTLCMD))
+-
+-#define HDP_DUAL_MODE_MIN_PCLK_RATE   300000  /* KHz */
+-#define HDP_SINGLE_MODE_MAX_WIDTH     1920
+-
+-static inline bool video_is_dual_mode(const struct drm_display_mode *mode)
+-{
+-      return (mode->clock > HDP_DUAL_MODE_MIN_PCLK_RATE ||
+-              mode->hdisplay > HDP_SINGLE_MODE_MAX_WIDTH) ? true : false;
+-}
+-
+-struct imx_mhdp_device;
+-
+-struct imx_hdp_clks {
+-      struct clk *av_pll;
+-      struct clk *dig_pll;
+-      struct clk *clk_ipg;
+-      struct clk *clk_core;
+-      struct clk *clk_pxl;
+-      struct clk *clk_pxl_mux;
+-      struct clk *clk_pxl_link;
+-
+-      struct clk *lpcg_hdp;
+-      struct clk *lpcg_msi;
+-      struct clk *lpcg_pxl;
+-      struct clk *lpcg_vif;
+-      struct clk *lpcg_lis;
+-      struct clk *lpcg_apb;
+-      struct clk *lpcg_apb_csr;
+-      struct clk *lpcg_apb_ctrl;
+-
+-      struct clk *lpcg_i2s;
+-      struct clk *clk_i2s_bypass;
+-};
+-
+-struct cdn_plat_data {
+-      /* Vendor PHY support */
+-      int (*phy_init)(struct imx_mhdp_device *hdmi);
+-      int (*bind)(struct platform_device *pdev,
+-                      struct drm_encoder *encoder,
+-                      const struct cdn_plat_data *plat_data);
+-      void (*unbind)(struct device *dev);
+-      int (*fw_init)(struct imx_mhdp_device *hdp);
+-      void (*pclock_change)(struct imx_mhdp_device *hdp);
+-      char is_dp;
+-};
+-
+-struct imx_mhdp_device {
+-      struct cdns_mhdp_device mhdp;
+-
+-      struct mutex lock;
+-      struct mutex audio_mutex;
+-      spinlock_t audio_lock;
+-      bool connected;
+-      bool active;
+-      bool suspended;
+-      struct imx_hdp_clks clks;
+-
+-      const struct cdn_plat_data *plat_data;
+-
+-      int irq[IRQ_NUM];
+-      struct delayed_work hotplug_work;
+-      //void __iomem *regmap_csr;
+-      struct regmap *regmap_csr;
+-      u32 csr_pxl_mux_reg;
+-      u32 csr_ctrl0_reg;
+-      u32 csr_ctrl0_sec;
+-
+-      struct audio_info audio_info;
+-      bool sink_has_audio;
+-      u32 dual_mode;
+-
+-      struct device           *pd_mhdp_dev;
+-      struct device           *pd_pll0_dev;
+-      struct device           *pd_pll1_dev;
+-      struct device_link      *pd_mhdp_link;
+-      struct device_link      *pd_pll0_link;
+-      struct device_link      *pd_pll1_link;
+-
+-      u32 phy_init;
+-};
+-
+-int cdns_hdmi_probe(struct platform_device *pdev,
+-                const struct cdn_plat_data *plat_data);
+-void cdns_hdmi_remove(struct platform_device *pdev);
+-void cdns_hdmi_unbind(struct device *dev);
+-int cdns_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
+-               const struct cdn_plat_data *plat_data);
+-void cdns_hdmi_set_sample_rate(struct imx_mhdp_device *hdmi, unsigned int rate);
+-void cdns_hdmi_audio_enable(struct imx_mhdp_device *hdmi);
+-void cdns_hdmi_audio_disable(struct imx_mhdp_device *hdmi);
+-int cdns_dp_probe(struct platform_device *pdev,
+-                const struct cdn_plat_data *plat_data);
+-void cdns_dp_remove(struct platform_device *pdev);
+-void cdns_dp_unbind(struct device *dev);
+-int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
+-               const struct cdn_plat_data *plat_data);
+-
+-#endif /* CDNS_MHDP_IMX_H_ */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0011-drm-imx-add-imx8mq-hdmi-support.patch b/target/linux/layerscape/patches-5.4/805-display-0011-drm-imx-add-imx8mq-hdmi-support.patch
new file mode 100644 (file)
index 0000000..8a6f5dd
--- /dev/null
@@ -0,0 +1,1169 @@
+From 7095b3b3b28031708ab74a65c32e84e231bc9d27 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Wed, 11 Sep 2019 17:18:29 +0800
+Subject: [PATCH] drm: imx: add imx8mq hdmi support
+
+add struct imx_mhdp_device for imx specific.
+add imx8mq hdmi support.
+move imx8qm specific functions to plat_data
+uniform variable name.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/imx/Makefile            |   2 +-
+ drivers/gpu/drm/imx/cdn-mhdp-dp-phy.c   |   8 +-
+ drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c |   7 +-
+ drivers/gpu/drm/imx/cdn-mhdp-imx8mq.c   | 163 ------------
+ drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c   | 437 ++++++++++----------------------
+ drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c   | 202 +++++++++++++++
+ drivers/gpu/drm/imx/cdn-mhdp-phy.h      |  12 +-
+ drivers/gpu/drm/imx/cdns-mhdp-imx.h     |  80 ++++++
+ 8 files changed, 421 insertions(+), 490 deletions(-)
+ delete mode 100644 drivers/gpu/drm/imx/cdn-mhdp-imx8mq.c
+ create mode 100644 drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
+ create mode 100644 drivers/gpu/drm/imx/cdns-mhdp-imx.h
+
+--- a/drivers/gpu/drm/imx/Makefile
++++ b/drivers/gpu/drm/imx/Makefile
+@@ -9,4 +9,4 @@ obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
+ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
+ obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
+-obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdn-mhdp-imx8qm.o cdn-mhdp-imx8mq.o cdn-mhdp-dp-phy.o cdn-mhdp-hdmi-phy.o
++obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdn-mhdp-imxdrv.o cdn-mhdp-dp-phy.o cdn-mhdp-hdmi-phy.o cdn-mhdp-imx8qm.o
+--- a/drivers/gpu/drm/imx/cdn-mhdp-dp-phy.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-dp-phy.c
+@@ -12,7 +12,6 @@
+ #include <linux/clk.h>
+ #include <linux/kernel.h>
+ #include <drm/drm_dp_helper.h>
+-
+ #include <drm/bridge/cdns-mhdp-common.h>
+ #include "cdn-mhdp-phy.h"
+@@ -477,9 +476,8 @@ static int dp_phy_power_up(struct cdns_m
+       return 0;
+ }
+-int cdns_dp_phy_init_imx8mq(struct imx_mhdp_device *hdp)
++int cdns_dp_phy_set_imx8mq(struct cdns_mhdp_device *mhdp)
+ {
+-      struct cdns_mhdp_device *mhdp = &hdp->mhdp;
+       int ret;
+       /* Disable phy clock if PHY in power up state */
+@@ -504,10 +502,8 @@ int cdns_dp_phy_init_imx8mq(struct imx_m
+       return ret;
+ }
+-
+-int cdns_dp_phy_init_imx8qm(struct imx_mhdp_device *hdp)
++int cdns_dp_phy_set_imx8qm(struct cdns_mhdp_device *mhdp)
+ {
+-      struct cdns_mhdp_device *mhdp = &hdp->mhdp;
+       int ret;
+       /* Disable phy clock if PHY in power up state */
+--- a/drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c
+@@ -624,9 +624,8 @@ static int hdmi_phy_power_up(struct cdns
+       return 0;
+ }
+-int cdns_hdmi_phy_set_imx8mq(struct imx_mhdp_device *hdp)
++int cdns_hdmi_phy_set_imx8mq(struct cdns_mhdp_device *mhdp)
+ {
+-      struct cdns_mhdp_device *mhdp = &hdp->mhdp;
+       struct drm_display_mode *mode = &mhdp->mode;
+       int ret;
+@@ -653,9 +652,8 @@ int cdns_hdmi_phy_set_imx8mq(struct imx_
+       return true;
+ }
+-int cdns_hdmi_phy_set_imx8qm(struct imx_mhdp_device *hdp)
++int cdns_hdmi_phy_set_imx8qm(struct cdns_mhdp_device *mhdp)
+ {
+-      struct cdns_mhdp_device *mhdp = &hdp->mhdp;
+       struct drm_display_mode *mode = &mhdp->mode;
+       int ret;
+@@ -681,4 +679,3 @@ int cdns_hdmi_phy_set_imx8qm(struct imx_
+       return true;
+ }
+-
+--- a/drivers/gpu/drm/imx/cdn-mhdp-imx8mq.c
++++ /dev/null
+@@ -1,163 +0,0 @@
+-/*
+- * Copyright (C) 2019 NXP Semiconductor, 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/platform_device.h>
+-#include <linux/component.h>
+-#include <linux/mfd/syscon.h>
+-#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+-#include <drm/drm_of.h>
+-#include <drm/drmP.h>
+-#include <drm/drm_crtc_helper.h>
+-#include <drm/drm_edid.h>
+-#include <drm/drm_encoder_slave.h>
+-
+-#include <drm/bridge/cdns-mhdp-imx.h>
+-#include "cdn-mhdp-phy.h"
+-#include "imx-drm.h"
+-
+-struct imx_hdmi {
+-      struct device *dev;
+-      struct drm_encoder encoder;
+-};
+-
+-static void cdns_hdmi_imx_encoder_disable(struct drm_encoder *encoder)
+-{
+-}
+-
+-static void cdns_hdmi_imx_encoder_enable(struct drm_encoder *encoder)
+-{
+-}
+-
+-static int cdns_hdmi_imx_atomic_check(struct drm_encoder *encoder,
+-                                  struct drm_crtc_state *crtc_state,
+-                                  struct drm_connector_state *conn_state)
+-{
+-      return 0;
+-}
+-
+-static const struct drm_encoder_helper_funcs cdns_hdmi_imx_encoder_helper_funcs = {
+-      .enable     = cdns_hdmi_imx_encoder_enable,
+-      .disable    = cdns_hdmi_imx_encoder_disable,
+-      .atomic_check = cdns_hdmi_imx_atomic_check,
+-};
+-
+-static const struct drm_encoder_funcs cdns_hdmi_imx_encoder_funcs = {
+-      .destroy = drm_encoder_cleanup,
+-};
+-
+-static struct cdn_plat_data imx8mq_hdmi_drv_data = {
+-      .bind   = cdns_hdmi_bind,
+-      .unbind = cdns_hdmi_unbind,
+-      .phy_init = cdns_hdmi_phy_set_imx8mq,
+-};
+-
+-static struct cdn_plat_data imx8mq_dp_drv_data = {
+-      .bind   = cdns_dp_bind,
+-      .unbind = cdns_dp_unbind,
+-      .phy_init = cdns_dp_phy_init_imx8mq,
+-};
+-
+-static const struct of_device_id cdns_hdmi_imx_dt_ids[] = {
+-      { .compatible = "cdn,imx8mq-hdmi",
+-        .data = &imx8mq_hdmi_drv_data
+-      },
+-      { .compatible = "cdn,imx8mq-dp",
+-        .data = &imx8mq_dp_drv_data
+-      },
+-      {},
+-};
+-MODULE_DEVICE_TABLE(of, cdns_hdmi_imx_dt_ids);
+-
+-static int cdns_hdmi_imx_bind(struct device *dev, struct device *master,
+-                          void *data)
+-{
+-      struct platform_device *pdev = to_platform_device(dev);
+-      const struct cdn_plat_data *plat_data;
+-      const struct of_device_id *match;
+-      struct drm_device *drm = data;
+-      struct drm_encoder *encoder;
+-      struct imx_hdmi *hdmi;
+-      int ret;
+-
+-      if (!pdev->dev.of_node)
+-              return -ENODEV;
+-
+-      hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+-      if (!hdmi)
+-              return -ENOMEM;
+-
+-      match = of_match_node(cdns_hdmi_imx_dt_ids, pdev->dev.of_node);
+-      plat_data = match->data;
+-      hdmi->dev = &pdev->dev;
+-      encoder = &hdmi->encoder;
+-
+-      encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+-      /*
+-       * If we failed to find the CRTC(s) which this encoder is
+-       * supposed to be connected to, it's because the CRTC has
+-       * not been registered yet.  Defer probing, and hope that
+-       * the required CRTC is added later.
+-       */
+-      if (encoder->possible_crtcs == 0)
+-              return -EPROBE_DEFER;
+-
+-      drm_encoder_helper_add(encoder, &cdns_hdmi_imx_encoder_helper_funcs);
+-      drm_encoder_init(drm, encoder, &cdns_hdmi_imx_encoder_funcs,
+-                       DRM_MODE_ENCODER_TMDS, NULL);
+-
+-      ret = plat_data->bind(pdev, encoder, plat_data);
+-
+-      /*
+-       * If cdns_hdmi_bind() fails we'll never call cdns_hdmi_unbind(),
+-       * which would have called the encoder cleanup.  Do it manually.
+-       */
+-      if (ret)
+-              drm_encoder_cleanup(encoder);
+-
+-      return ret;
+-}
+-
+-static void cdns_hdmi_imx_unbind(struct device *dev, struct device *master,
+-                             void *data)
+-{
+-      struct imx_mhdp_device *hdp = dev_get_drvdata(dev);
+-
+-      hdp->plat_data->unbind(dev);
+-}
+-
+-static const struct component_ops cdns_hdmi_imx_ops = {
+-      .bind   = cdns_hdmi_imx_bind,
+-      .unbind = cdns_hdmi_imx_unbind,
+-};
+-
+-static int cdns_hdmi_imx_probe(struct platform_device *pdev)
+-{
+-      return component_add(&pdev->dev, &cdns_hdmi_imx_ops);
+-}
+-
+-static int cdns_hdmi_imx_remove(struct platform_device *pdev)
+-{
+-      component_del(&pdev->dev, &cdns_hdmi_imx_ops);
+-
+-      return 0;
+-}
+-
+-static struct platform_driver cdns_hdmi_imx_platform_driver = {
+-      .probe  = cdns_hdmi_imx_probe,
+-      .remove = cdns_hdmi_imx_remove,
+-      .driver = {
+-              .name = "cdn-hdp-imx8mq",
+-              .of_match_table = cdns_hdmi_imx_dt_ids,
+-      },
+-};
+-
+-module_platform_driver(cdns_hdmi_imx_platform_driver);
+-
+-MODULE_AUTHOR("Sandor YU <sandor.yu@nxp.com>");
+-MODULE_LICENSE("GPL");
+-MODULE_ALIAS("platform:cdnhdmi-imx");
+--- a/drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
+@@ -1,54 +1,40 @@
+ /*
+- * Copyright (C) 2019 NXP Semiconductor, Inc.
++ * copyright (c) 2019 nxp semiconductor, 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.
++ * 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 <dt-bindings/firmware/imx/rsrc.h>
+-#include <linux/clk.h>
+-#include <linux/module.h>
+-#include <linux/platform_device.h>
+-#include <linux/component.h>
+-#include <drm/drm_of.h>
+-#include <drm/drmP.h>
+-#include <drm/drm_crtc_helper.h>
+-#include <drm/drm_encoder_slave.h>
+ #include <linux/firmware/imx/sci.h>
+-#include <linux/regmap.h>
+ #include <linux/pm_domain.h>
++#include <linux/clk.h>
++#include <drm/drmP.h>
+-#include <drm/bridge/cdns-mhdp-imx.h>
+-#include "cdn-mhdp-phy.h"
+-#include "imx-drm.h"
++#include "cdns-mhdp-imx.h"
+ #define CSR_PIXEL_LINK_MUX_CTL                0x00
+-#define PL_MUX_CTL_VCP_OFFSET         5
+-#define PL_MUX_CTL_HCP_OFFSET         4
++#define CSR_PIXEL_LINK_MUX_VCP_OFFSET         5
++#define CSR_PIXEL_LINK_MUX_HCP_OFFSET         4
+ #define PLL_800MHZ (800000000)
+-struct imx_hdmi {
+-      struct device *dev;
+-      struct drm_encoder encoder;
+-};
+-
+-static void imx8qm_pixel_link_mux(struct imx_mhdp_device *hdp)
++static void imx8qm_pixel_link_mux(struct imx_mhdp_device *imx_mhdp)
+ {
+-      struct drm_display_mode *mode = &hdp->mhdp.mode;
++      struct drm_display_mode *mode = &imx_mhdp->mhdp.mode;
+       u32 val;
+       val = 0x4;      /* RGB */
+-      if (hdp->dual_mode)
++      if (imx_mhdp->dual_mode)
+               val |= 0x2;     /* pixel link 0 and 1 are active */
+       if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+-              val |= 1 << PL_MUX_CTL_VCP_OFFSET;
++              val |= 1 << CSR_PIXEL_LINK_MUX_VCP_OFFSET;
+       if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+-              val |= 1 << PL_MUX_CTL_HCP_OFFSET;
++              val |= 1 << CSR_PIXEL_LINK_MUX_HCP_OFFSET;
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+               val |= 0x2;
+-      regmap_write(hdp->regmap_csr, hdp->csr_pxl_mux_reg, val);
++      writel(val, imx_mhdp->mhdp.regs_sec);
+ }
+ static void imx8qm_pixel_link_valid(u32 dual_mode)
+@@ -120,10 +106,10 @@ static void imx8qm_clk_mux(u8 is_dp)
+               imx_sc_misc_set_control(handle, IMX_SC_R_HDMI, IMX_SC_C_MODE, 0);
+ }
+-int imx8qm_clocks_init(struct imx_mhdp_device *hdp)
++int imx8qm_clocks_init(struct imx_mhdp_device *imx_mhdp)
+ {
+-      struct device *dev = hdp->mhdp.dev;
+-      struct imx_hdp_clks *clks = &hdp->clks;
++      struct device *dev = imx_mhdp->mhdp.dev;
++      struct imx_hdp_clks *clks = &imx_mhdp->clks;
+       clks->dig_pll = devm_clk_get(dev, "dig_pll");
+       if (IS_ERR(clks->dig_pll)) {
+@@ -229,10 +215,10 @@ int imx8qm_clocks_init(struct imx_mhdp_d
+       return true;
+ }
+-static int imx8qm_pixel_clk_enable(struct imx_mhdp_device *hdp)
++static int imx8qm_pixel_clk_enable(struct imx_mhdp_device *imx_mhdp)
+ {
+-      struct imx_hdp_clks *clks = &hdp->clks;
+-      struct device *dev = hdp->mhdp.dev;
++      struct imx_hdp_clks *clks = &imx_mhdp->clks;
++      struct device *dev = imx_mhdp->mhdp.dev;
+       int ret;
+       ret = clk_prepare_enable(clks->av_pll);
+@@ -273,12 +259,11 @@ static int imx8qm_pixel_clk_enable(struc
+               return ret;
+       }
+       return ret;
+-
+ }
+-static void imx8qm_pixel_clk_disable(struct imx_mhdp_device *hdp)
++static void imx8qm_pixel_clk_disable(struct imx_mhdp_device *imx_mhdp)
+ {
+-      struct imx_hdp_clks *clks = &hdp->clks;
++      struct imx_hdp_clks *clks = &imx_mhdp->clks;
+       clk_disable_unprepare(clks->lpcg_pxl);
+       clk_disable_unprepare(clks->lpcg_hdp);
+@@ -289,14 +274,14 @@ static void imx8qm_pixel_clk_disable(str
+       clk_disable_unprepare(clks->av_pll);
+ }
+-static void imx8qm_pixel_clk_set_rate(struct imx_mhdp_device *hdp, u32 pclock)
++static void imx8qm_pixel_clk_set_rate(struct imx_mhdp_device *imx_mhdp, u32 pclock)
+ {
+-      struct imx_hdp_clks *clks = &hdp->clks;
++      struct imx_hdp_clks *clks = &imx_mhdp->clks;
+       /* pixel clock for HDMI */
+       clk_set_rate(clks->av_pll, pclock);
+-      if (hdp->dual_mode == true) {
++      if (imx_mhdp->dual_mode == true) {
+               clk_set_rate(clks->clk_pxl, pclock/2);
+               clk_set_rate(clks->clk_pxl_link, pclock/2);
+       } else {
+@@ -306,24 +291,11 @@ static void imx8qm_pixel_clk_set_rate(st
+       clk_set_rate(clks->clk_pxl_mux, pclock);
+ }
+-static void imx8qm_pixel_clk_rate_change(struct imx_mhdp_device *hdp)
+-{
+-      /* set pixel clock before video mode setup */
+-      imx8qm_pixel_clk_disable(hdp);
+-
+-      imx8qm_pixel_clk_set_rate(hdp, hdp->mhdp.mode.clock * 1000);
+-
+-      imx8qm_pixel_clk_enable(hdp);
+-
+-      /* Config pixel link mux */
+-      imx8qm_pixel_link_mux(hdp);
+-}
+-
+-static int imx8qm_ipg_clk_enable(struct imx_mhdp_device *hdp)
++static int imx8qm_ipg_clk_enable(struct imx_mhdp_device *imx_mhdp)
+ {
+       int ret;
+-      struct imx_hdp_clks *clks = &hdp->clks;
+-      struct device *dev = hdp->mhdp.dev;
++      struct imx_hdp_clks *clks = &imx_mhdp->clks;
++      struct device *dev = imx_mhdp->mhdp.dev;
+       ret = clk_prepare_enable(clks->dig_pll);
+       if (ret < 0) {
+@@ -381,25 +353,9 @@ static int imx8qm_ipg_clk_enable(struct
+       return ret;
+ }
+-static void imx8qm_ipg_clk_disable(struct imx_mhdp_device *hdp)
+-{
+-      struct imx_hdp_clks *clks = &hdp->clks;
+-
+-      clk_disable_unprepare(clks->clk_i2s_bypass);
+-      clk_disable_unprepare(clks->lpcg_i2s);
+-      clk_disable_unprepare(clks->lpcg_apb_ctrl);
+-      clk_disable_unprepare(clks->lpcg_apb_csr);
+-      clk_disable_unprepare(clks->lpcg_msi);
+-      clk_disable_unprepare(clks->lpcg_lis);
+-      clk_disable_unprepare(clks->lpcg_apb);
+-      clk_disable_unprepare(clks->clk_core);
+-      clk_disable_unprepare(clks->clk_ipg);
+-      clk_disable_unprepare(clks->dig_pll);
+-}
+-
+-static void imx8qm_ipg_clk_set_rate(struct imx_mhdp_device *hdp)
++static void imx8qm_ipg_clk_set_rate(struct imx_mhdp_device *imx_mhdp)
+ {
+-      struct imx_hdp_clks *clks = &hdp->clks;
++      struct imx_hdp_clks *clks = &imx_mhdp->clks;
+       /* ipg/core clock */
+       clk_set_rate(clks->dig_pll,  PLL_800MHZ);
+@@ -407,308 +363,171 @@ static void imx8qm_ipg_clk_set_rate(stru
+       clk_set_rate(clks->clk_ipg,  PLL_800MHZ/8);
+ }
+-static void imx8qm_detach_pm_domains(struct imx_mhdp_device *hdp)
++static void imx8qm_detach_pm_domains(struct imx_mhdp_device *imx_mhdp)
+ {
+-      if (hdp->pd_pll1_link && !IS_ERR(hdp->pd_pll1_link))
+-              device_link_del(hdp->pd_pll1_link);
+-      if (hdp->pd_pll1_dev && !IS_ERR(hdp->pd_pll1_dev))
+-              dev_pm_domain_detach(hdp->pd_pll1_dev, true);
+-
+-      if (hdp->pd_pll0_link && !IS_ERR(hdp->pd_pll0_link))
+-              device_link_del(hdp->pd_pll0_link);
+-      if (hdp->pd_pll0_dev && !IS_ERR(hdp->pd_pll0_dev))
+-              dev_pm_domain_detach(hdp->pd_pll0_dev, true);
+-
+-      if (hdp->pd_mhdp_link && !IS_ERR(hdp->pd_mhdp_link))
+-              device_link_del(hdp->pd_mhdp_link);
+-      if (hdp->pd_mhdp_dev && !IS_ERR(hdp->pd_mhdp_dev))
+-              dev_pm_domain_detach(hdp->pd_mhdp_dev, true);
+-
+-      hdp->pd_mhdp_dev = NULL;
+-      hdp->pd_mhdp_link = NULL;
+-      hdp->pd_pll0_dev = NULL;
+-      hdp->pd_pll0_link = NULL;
+-      hdp->pd_pll1_dev = NULL;
+-      hdp->pd_pll1_link = NULL;
++      if (imx_mhdp->pd_pll1_link && !IS_ERR(imx_mhdp->pd_pll1_link))
++              device_link_del(imx_mhdp->pd_pll1_link);
++      if (imx_mhdp->pd_pll1_dev && !IS_ERR(imx_mhdp->pd_pll1_dev))
++              dev_pm_domain_detach(imx_mhdp->pd_pll1_dev, true);
++
++      if (imx_mhdp->pd_pll0_link && !IS_ERR(imx_mhdp->pd_pll0_link))
++              device_link_del(imx_mhdp->pd_pll0_link);
++      if (imx_mhdp->pd_pll0_dev && !IS_ERR(imx_mhdp->pd_pll0_dev))
++              dev_pm_domain_detach(imx_mhdp->pd_pll0_dev, true);
++
++      if (imx_mhdp->pd_mhdp_link && !IS_ERR(imx_mhdp->pd_mhdp_link))
++              device_link_del(imx_mhdp->pd_mhdp_link);
++      if (imx_mhdp->pd_mhdp_dev && !IS_ERR(imx_mhdp->pd_mhdp_dev))
++              dev_pm_domain_detach(imx_mhdp->pd_mhdp_dev, true);
++
++      imx_mhdp->pd_mhdp_dev = NULL;
++      imx_mhdp->pd_mhdp_link = NULL;
++      imx_mhdp->pd_pll0_dev = NULL;
++      imx_mhdp->pd_pll0_link = NULL;
++      imx_mhdp->pd_pll1_dev = NULL;
++      imx_mhdp->pd_pll1_link = NULL;
+ }
+-static int imx8qm_attach_pm_domains(struct imx_mhdp_device *hdp)
++static int imx8qm_attach_pm_domains(struct imx_mhdp_device *imx_mhdp)
+ {
+-      struct device *dev = hdp->mhdp.dev;
++      struct device *dev = imx_mhdp->mhdp.dev;
+       u32 flags = DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE;
+       int ret = 0;
+-      hdp->pd_mhdp_dev = dev_pm_domain_attach_by_name(dev, "hdmi");
+-      if (IS_ERR(hdp->pd_mhdp_dev)) {
+-              ret = PTR_ERR(hdp->pd_mhdp_dev);
++      imx_mhdp->pd_mhdp_dev = dev_pm_domain_attach_by_name(dev, "hdmi");
++      if (IS_ERR(imx_mhdp->pd_mhdp_dev)) {
++              ret = PTR_ERR(imx_mhdp->pd_mhdp_dev);
+               dev_err(dev, "Failed to attach dc pd dev: %d\n", ret);
+               goto fail;
+       }
+-      hdp->pd_mhdp_link = device_link_add(dev, hdp->pd_mhdp_dev, flags);
+-      if (IS_ERR(hdp->pd_mhdp_link)) {
+-              ret = PTR_ERR(hdp->pd_mhdp_link);
++      imx_mhdp->pd_mhdp_link = device_link_add(dev, imx_mhdp->pd_mhdp_dev, flags);
++      if (IS_ERR(imx_mhdp->pd_mhdp_link)) {
++              ret = PTR_ERR(imx_mhdp->pd_mhdp_link);
+               dev_err(dev, "Failed to add device link to dc pd dev: %d\n",
+                       ret);
+               goto fail;
+       }
+-      hdp->pd_pll0_dev = dev_pm_domain_attach_by_name(dev, "pll0");
+-      if (IS_ERR(hdp->pd_pll0_dev)) {
+-              ret = PTR_ERR(hdp->pd_pll0_dev);
++      imx_mhdp->pd_pll0_dev = dev_pm_domain_attach_by_name(dev, "pll0");
++      if (IS_ERR(imx_mhdp->pd_pll0_dev)) {
++              ret = PTR_ERR(imx_mhdp->pd_pll0_dev);
+               dev_err(dev, "Failed to attach pll0 pd dev: %d\n", ret);
+               goto fail;
+       }
+-      hdp->pd_pll0_link = device_link_add(dev, hdp->pd_pll0_dev, flags);
+-      if (IS_ERR(hdp->pd_pll0_link)) {
+-              ret = PTR_ERR(hdp->pd_pll0_link);
++      imx_mhdp->pd_pll0_link = device_link_add(dev, imx_mhdp->pd_pll0_dev, flags);
++      if (IS_ERR(imx_mhdp->pd_pll0_link)) {
++              ret = PTR_ERR(imx_mhdp->pd_pll0_link);
+               dev_err(dev, "Failed to add device link to pll0 pd dev: %d\n",
+                       ret);
+               goto fail;
+       }
+-      hdp->pd_pll1_dev = dev_pm_domain_attach_by_name(dev, "pll1");
+-      if (IS_ERR(hdp->pd_pll1_dev)) {
+-              ret = PTR_ERR(hdp->pd_pll1_dev);
++      imx_mhdp->pd_pll1_dev = dev_pm_domain_attach_by_name(dev, "pll1");
++      if (IS_ERR(imx_mhdp->pd_pll1_dev)) {
++              ret = PTR_ERR(imx_mhdp->pd_pll1_dev);
+               dev_err(dev, "Failed to attach pll0 pd dev: %d\n", ret);
+               goto fail;
+       }
+-      hdp->pd_pll1_link = device_link_add(dev, hdp->pd_pll1_dev, flags);
+-      if (IS_ERR(hdp->pd_pll1_link)) {
+-              ret = PTR_ERR(hdp->pd_pll1_link);
++      imx_mhdp->pd_pll1_link = device_link_add(dev, imx_mhdp->pd_pll1_dev, flags);
++      if (IS_ERR(imx_mhdp->pd_pll1_link)) {
++              ret = PTR_ERR(imx_mhdp->pd_pll1_link);
+               dev_err(dev, "Failed to add device link to pll1 pd dev: %d\n",
+                       ret);
+               goto fail;
+       }
+ fail:
+-      imx8qm_detach_pm_domains(hdp);
++      imx8qm_detach_pm_domains(imx_mhdp);
+       return ret;
+ }
+-static int imx8qm_firmware_init(struct imx_mhdp_device *hdp)
++static void imx8qm_mhdp_power_on(struct cdns_mhdp_device *mhdp)
+ {
+-      u32 rate;
+-      int ret;
+-
++      struct imx_mhdp_device *imx_mhdp =
++                              container_of(mhdp, struct imx_mhdp_device, mhdp);
+       /* Power on PM Domains */
+-      imx8qm_attach_pm_domains(hdp);
++
++      imx8qm_attach_pm_domains(imx_mhdp);
+       /* clock init and  rate set */
+-      imx8qm_clocks_init(hdp);
++      imx8qm_clocks_init(imx_mhdp);
+-      imx8qm_ipg_clk_set_rate(hdp);
++      imx8qm_ipg_clk_set_rate(imx_mhdp);
+       /* Init pixel clock with 148.5MHz before FW init */
+-      imx8qm_pixel_clk_set_rate(hdp, 148500000);
++      imx8qm_pixel_clk_set_rate(imx_mhdp, 148500000);
+-      imx8qm_ipg_clk_enable(hdp);
++      imx8qm_ipg_clk_enable(imx_mhdp);
+-      imx8qm_clk_mux(hdp->plat_data->is_dp);
++      imx8qm_clk_mux(imx_mhdp->mhdp.plat_data->is_dp);
+-      imx8qm_pixel_clk_enable(hdp);
++      imx8qm_pixel_clk_enable(imx_mhdp);
+       imx8qm_phy_reset(1);
+-
+-      hdp->csr_pxl_mux_reg = 0;
+-      hdp->csr_ctrl0_reg = 0x8;
+-      hdp->csr_ctrl0_sec = 0xc;
+-      /* iMX8QM HDP register, Remap HPD memory address to low 4K */
+-      regmap_write(hdp->regmap_csr, hdp->csr_ctrl0_reg, 0);
+-
+-      /* configure HDMI/DP core clock */
+-      rate = clk_get_rate(hdp->clks.clk_core);
+-      cdns_mhdp_set_fw_clk(&hdp->mhdp, rate);
+-
+-      /* un-reset ucpu */
+-      writel(0,  (APB_CTRL << 2) + hdp->mhdp.regs);
+-      DRM_INFO("Started firmware!\n");
+-
+-      ret = cdns_mhdp_check_alive(&hdp->mhdp);
+-      if (ret == false) {
+-              DRM_ERROR("NO HDMI FW running\n");
+-              return -ENXIO;
+-      }
+-
+-      /* turn on IP activity */
+-      cdns_mhdp_set_firmware_active(&hdp->mhdp, 1);
+-
+-      DRM_INFO("HDP FW Version - ver %d verlib %d\n",
+-                      __raw_readb(VER_L + hdp->mhdp.regs) + (__raw_readb(VER_H + hdp->mhdp.regs) << 8),
+-      __raw_readb(VER_LIB_L_ADDR + hdp->mhdp.regs) + (__raw_readb(VER_LIB_H_ADDR + hdp->mhdp.regs) << 8));
+-
+-      return 0;
+ }
+-static void cdns_hdmi_imx_encoder_disable(struct drm_encoder *encoder)
++void cdns_mhdp_plat_init_imx8qm(struct cdns_mhdp_device *mhdp)
+ {
+-      struct imx_mhdp_device *hdp = encoder->bridge->driver_private;
++      struct imx_mhdp_device *imx_mhdp =
++                              container_of(mhdp, struct imx_mhdp_device, mhdp);
+-      imx8qm_pixel_link_sync_disable(hdp->dual_mode);
+-      imx8qm_pixel_link_invalid(hdp->dual_mode);
++      imx8qm_pixel_link_sync_disable(imx_mhdp->dual_mode);
++      imx8qm_pixel_link_invalid(imx_mhdp->dual_mode);
+ }
+-static void cdns_hdmi_imx_encoder_enable(struct drm_encoder *encoder)
++void cdns_mhdp_plat_deinit_imx8qm(struct cdns_mhdp_device *mhdp)
+ {
+-      struct imx_mhdp_device *hdp = encoder->bridge->driver_private;
++      struct imx_mhdp_device *imx_mhdp =
++                              container_of(mhdp, struct imx_mhdp_device, mhdp);
+-      imx8qm_pixel_link_valid(hdp->dual_mode);
+-      imx8qm_pixel_link_sync_enable(hdp->dual_mode);
++      imx8qm_pixel_link_valid(imx_mhdp->dual_mode);
++      imx8qm_pixel_link_sync_enable(imx_mhdp->dual_mode);
+ }
+-static int cdns_hdmi_imx_encoder_atomic_check(struct drm_encoder *encoder,
+-                                  struct drm_crtc_state *crtc_state,
+-                                  struct drm_connector_state *conn_state)
++void cdns_mhdp_pclk_rate_imx8qm(struct cdns_mhdp_device *mhdp)
+ {
+-      struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
+-
+-      imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB101010_1X30;
+-      return 0;
+-}
++      struct imx_mhdp_device *imx_mhdp =
++                              container_of(mhdp, struct imx_mhdp_device, mhdp);
+-static const struct drm_encoder_helper_funcs cdns_hdmi_imx_encoder_helper_funcs = {
+-      .enable     = cdns_hdmi_imx_encoder_enable,
+-      .disable    = cdns_hdmi_imx_encoder_disable,
+-      .atomic_check = cdns_hdmi_imx_encoder_atomic_check,
+-};
+-
+-static const struct drm_encoder_funcs cdns_hdmi_imx_encoder_funcs = {
+-      .destroy = drm_encoder_cleanup,
+-};
+-
+-#if 0
+-static struct cdn_plat_data imx8mq_hdmi_drv_data = {
+-      .bind   = cdns_hdmi_bind,
+-      .unbind = cdns_hdmi_unbind,
+-      .phy_init = cdns_hdmi_phy_set_imx8mq,
+-};
+-
+-static struct cdn_plat_data imx8mq_dp_drv_data = {
+-      .bind   = cdns_dp_bind,
+-      .unbind = cdns_dp_unbind,
+-      .phy_init = cdns_dp_phy_init_imx8mq,
+-};
+-#endif
+-
+-static struct cdn_plat_data imx8qm_hdmi_drv_data = {
+-      .bind   = cdns_hdmi_bind,
+-      .unbind = cdns_hdmi_unbind,
+-      .phy_init = cdns_hdmi_phy_set_imx8qm,
+-      .fw_init = imx8qm_firmware_init,
+-      .pclock_change = imx8qm_pixel_clk_rate_change,
+-};
+-
+-static struct cdn_plat_data imx8qm_dp_drv_data = {
+-      .bind   = cdns_dp_bind,
+-      .unbind = cdns_dp_unbind,
+-      .phy_init = cdns_dp_phy_init_imx8qm,
+-      .fw_init = imx8qm_firmware_init,
+-      .pclock_change = imx8qm_pixel_clk_rate_change,
+-      .is_dp = true,
+-};
+-
+-static const struct of_device_id cdns_hdmi_imx_dt_ids[] = {
+-#if 0
+-      { .compatible = "cdn,imx8mq-hdmi",
+-        .data = &imx8mq_hdmi_drv_data
+-      },
+-      { .compatible = "cdn,imx8mq-dp",
+-        .data = &imx8mq_dp_drv_data
+-      },
+-#endif
+-      { .compatible = "cdn,imx8qm-hdmi",
+-        .data = &imx8qm_hdmi_drv_data
+-      },
+-      { .compatible = "cdn,imx8qm-dp",
+-        .data = &imx8qm_dp_drv_data
+-      },
+-      {},
+-};
+-MODULE_DEVICE_TABLE(of, cdns_hdmi_imx_dt_ids);
+-
+-static int cdns_hdmi_imx_bind(struct device *dev, struct device *master,
+-                          void *data)
+-{
+-      struct platform_device *pdev = to_platform_device(dev);
+-      const struct cdn_plat_data *plat_data;
+-      const struct of_device_id *match;
+-      struct drm_device *drm = data;
+-      struct drm_encoder *encoder;
+-      struct imx_hdmi *hdmi;
+-      int ret;
++      /* set pixel clock before video mode setup */
++      imx8qm_pixel_clk_disable(imx_mhdp);
+-      if (!pdev->dev.of_node)
+-              return -ENODEV;
++      imx8qm_pixel_clk_set_rate(imx_mhdp, imx_mhdp->mhdp.mode.clock * 1000);
+-      hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+-      if (!hdmi)
+-              return -ENOMEM;
+-
+-      match = of_match_node(cdns_hdmi_imx_dt_ids, pdev->dev.of_node);
+-      plat_data = match->data;
+-      hdmi->dev = &pdev->dev;
+-      encoder = &hdmi->encoder;
+-
+-      encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+-      /*
+-       * If we failed to find the CRTC(s) which this encoder is
+-       * supposed to be connected to, it's because the CRTC has
+-       * not been registered yet.  Defer probing, and hope that
+-       * the required CRTC is added later.
+-       */
+-      if (encoder->possible_crtcs == 0)
+-              return -EPROBE_DEFER;
+-
+-      drm_encoder_helper_add(encoder, &cdns_hdmi_imx_encoder_helper_funcs);
+-      drm_encoder_init(drm, encoder, &cdns_hdmi_imx_encoder_funcs,
+-                       DRM_MODE_ENCODER_TMDS, NULL);
+-
+-      ret = plat_data->bind(pdev, encoder, plat_data);
+-
+-      /*
+-       * If cdns_hdmi_bind() fails we'll never call cdns_hdmi_unbind(),
+-       * which would have called the encoder cleanup.  Do it manually.
+-       */
+-      if (ret)
+-              drm_encoder_cleanup(encoder);
++      imx8qm_pixel_clk_enable(imx_mhdp);
+-      return ret;
++      /* Config pixel link mux */
++      imx8qm_pixel_link_mux(imx_mhdp);
+ }
+-static void cdns_hdmi_imx_unbind(struct device *dev, struct device *master,
+-                             void *data)
++int cdns_mhdp_firmware_init_imx8qm(struct cdns_mhdp_device *mhdp)
+ {
+-      struct imx_mhdp_device *hdp = dev_get_drvdata(dev);
++      struct imx_mhdp_device *imx_mhdp =
++                              container_of(mhdp, struct imx_mhdp_device, mhdp);
++      u32 rate;
++      int ret;
+-      hdp->plat_data->unbind(dev);
+-}
++      imx8qm_mhdp_power_on(mhdp);
+-static const struct component_ops cdns_hdmi_imx8qm_ops = {
+-      .bind   = cdns_hdmi_imx_bind,
+-      .unbind = cdns_hdmi_imx_unbind,
+-};
++      /* configure HDMI/DP core clock */
++      rate = clk_get_rate(imx_mhdp->clks.clk_core);
++      cdns_mhdp_set_fw_clk(&imx_mhdp->mhdp, rate);
+-static int cdns_hdmi_imx_probe(struct platform_device *pdev)
+-{
+-      return component_add(&pdev->dev, &cdns_hdmi_imx8qm_ops);
+-}
++      /* un-reset ucpu */
++      cdns_mhdp_bus_write(0, &imx_mhdp->mhdp, APB_CTRL);
++      DRM_INFO("Started firmware!\n");
+-static int cdns_hdmi_imx_remove(struct platform_device *pdev)
+-{
+-      component_del(&pdev->dev, &cdns_hdmi_imx8qm_ops);
++      ret = cdns_mhdp_check_alive(&imx_mhdp->mhdp);
++      if (ret == false) {
++              DRM_ERROR("NO HDMI FW running\n");
++              return -ENXIO;
++      }
++
++      /* turn on IP activity */
++      cdns_mhdp_set_firmware_active(&imx_mhdp->mhdp, 1);
++
++      DRM_INFO("HDP FW Version - ver %d verlib %d\n",
++                      cdns_mhdp_bus_read(mhdp, VER_L) + (cdns_mhdp_bus_read(mhdp, VER_H) << 8),
++                      cdns_mhdp_bus_read(mhdp, VER_LIB_H_ADDR) + (cdns_mhdp_bus_read(mhdp, VER_LIB_H_ADDR) << 8));
+       return 0;
+ }
+-
+-static struct platform_driver cdns_hdmi_imx_platform_driver = {
+-      .probe  = cdns_hdmi_imx_probe,
+-      .remove = cdns_hdmi_imx_remove,
+-      .driver = {
+-              .name = "cdn-hdp-imx8qm",
+-              .of_match_table = cdns_hdmi_imx_dt_ids,
+-      },
+-};
+-
+-module_platform_driver(cdns_hdmi_imx_platform_driver);
+-
+-MODULE_AUTHOR("Sandor YU <sandor.yu@nxp.com>");
+-MODULE_LICENSE("GPL");
+-MODULE_ALIAS("platform:cdnhdmi-imx");
+--- /dev/null
++++ b/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
+@@ -0,0 +1,202 @@
++/*
++ * copyright (c) 2019 nxp semiconductor, 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/platform_device.h>
++#include <linux/component.h>
++#include <drm/drm_of.h>
++#include <drm/drmP.h>
++#include <drm/drm_crtc_helper.h>
++#include <drm/drm_encoder_slave.h>
++
++#include "cdns-mhdp-imx.h"
++#include "cdn-mhdp-phy.h"
++#include "imx-drm.h"
++
++static void cdns_mhdp_imx_encoder_disable(struct drm_encoder *encoder)
++{
++      struct cdns_mhdp_device *mhdp = encoder->bridge->driver_private;
++
++      cdns_mhdp_plat_call(mhdp, plat_init);
++}
++
++static void cdns_mhdp_imx_encoder_enable(struct drm_encoder *encoder)
++{
++      struct cdns_mhdp_device *mhdp = encoder->bridge->driver_private;
++
++      cdns_mhdp_plat_call(mhdp, plat_deinit);
++}
++
++static int cdns_mhdp_imx_encoder_atomic_check(struct drm_encoder *encoder,
++                                  struct drm_crtc_state *crtc_state,
++                                  struct drm_connector_state *conn_state)
++{
++      struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
++      struct cdns_mhdp_device *mhdp = encoder->bridge->driver_private;
++
++      if (mhdp->plat_data->video_format != 0)
++              imx_crtc_state->bus_format = mhdp->plat_data->video_format;
++      return 0;
++}
++
++static const struct drm_encoder_helper_funcs cdns_mhdp_imx_encoder_helper_funcs = {
++      .enable     = cdns_mhdp_imx_encoder_enable,
++      .disable    = cdns_mhdp_imx_encoder_disable,
++      .atomic_check = cdns_mhdp_imx_encoder_atomic_check,
++};
++
++static const struct drm_encoder_funcs cdns_mhdp_imx_encoder_funcs = {
++      .destroy = drm_encoder_cleanup,
++};
++
++static struct cdns_plat_data imx8mq_hdmi_drv_data = {
++      .bind   = cdns_hdmi_bind,
++      .unbind = cdns_hdmi_unbind,
++      .phy_set = cdns_hdmi_phy_set_imx8mq,
++      .bus_type = BUS_TYPE_NORMAL_APB,
++};
++
++static struct cdns_plat_data imx8mq_dp_drv_data = {
++      .bind   = cdns_dp_bind,
++      .unbind = cdns_dp_unbind,
++      .phy_set = cdns_dp_phy_set_imx8mq,
++      .bus_type = BUS_TYPE_NORMAL_APB,
++};
++
++static struct cdns_plat_data imx8qm_hdmi_drv_data = {
++      .bind   = cdns_hdmi_bind,
++      .unbind = cdns_hdmi_unbind,
++      .phy_set = cdns_hdmi_phy_set_imx8qm,
++      .firmware_init = cdns_mhdp_firmware_init_imx8qm,
++      .pclk_rate = cdns_mhdp_pclk_rate_imx8qm,
++      .plat_init = cdns_mhdp_plat_init_imx8qm,
++      .plat_deinit = cdns_mhdp_plat_deinit_imx8qm,
++      .bus_type = BUS_TYPE_LOW4K_APB,
++      .video_format =  MEDIA_BUS_FMT_RGB101010_1X30,
++};
++
++static struct cdns_plat_data imx8qm_dp_drv_data = {
++      .bind   = cdns_dp_bind,
++      .unbind = cdns_dp_unbind,
++      .phy_set = cdns_dp_phy_set_imx8qm,
++      .firmware_init = cdns_mhdp_firmware_init_imx8qm,
++      .pclk_rate = cdns_mhdp_pclk_rate_imx8qm,
++      .plat_init = cdns_mhdp_plat_init_imx8qm,
++      .plat_deinit = cdns_mhdp_plat_deinit_imx8qm,
++      .bus_type = BUS_TYPE_LOW4K_APB,
++      .video_format =  MEDIA_BUS_FMT_RGB101010_1X30,
++      .is_dp = true,
++};
++
++static const struct of_device_id cdns_mhdp_imx_dt_ids[] = {
++      { .compatible = "cdn,imx8mq-hdmi",
++        .data = &imx8mq_hdmi_drv_data
++      },
++      { .compatible = "cdn,imx8mq-dp",
++        .data = &imx8mq_dp_drv_data
++      },
++      { .compatible = "cdn,imx8qm-hdmi",
++        .data = &imx8qm_hdmi_drv_data
++      },
++      { .compatible = "cdn,imx8qm-dp",
++        .data = &imx8qm_dp_drv_data
++      },
++      {},
++};
++MODULE_DEVICE_TABLE(of, cdns_mhdp_imx_dt_ids);
++
++static int cdns_mhdp_imx_bind(struct device *dev, struct device *master,
++                          void *data)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++      const struct cdns_plat_data *plat_data;
++      const struct of_device_id *match;
++      struct drm_device *drm = data;
++      struct drm_encoder *encoder;
++      struct imx_mhdp_device *imx_mhdp;
++      int ret;
++
++      if (!pdev->dev.of_node)
++              return -ENODEV;
++
++      imx_mhdp = devm_kzalloc(&pdev->dev, sizeof(*imx_mhdp), GFP_KERNEL);
++      if (!imx_mhdp)
++              return -ENOMEM;
++
++      match = of_match_node(cdns_mhdp_imx_dt_ids, pdev->dev.of_node);
++      plat_data = match->data;
++      encoder = &imx_mhdp->encoder;
++
++      encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
++      /*
++       * If we failed to find the CRTC(s) which this encoder is
++       * supposed to be connected to, it's because the CRTC has
++       * not been registered yet.  Defer probing, and hope that
++       * the required CRTC is added later.
++       */
++      if (encoder->possible_crtcs == 0)
++              return -EPROBE_DEFER;
++
++      drm_encoder_helper_add(encoder, &cdns_mhdp_imx_encoder_helper_funcs);
++      drm_encoder_init(drm, encoder, &cdns_mhdp_imx_encoder_funcs,
++                       DRM_MODE_ENCODER_TMDS, NULL);
++
++
++      imx_mhdp->mhdp.plat_data = plat_data;
++      imx_mhdp->mhdp.dev = dev;
++      imx_mhdp->mhdp.bus_type = plat_data->bus_type;
++      ret = plat_data->bind(pdev, encoder, &imx_mhdp->mhdp);
++      /*
++       * If cdns_mhdp_bind() fails we'll never call cdns_mhdp_unbind(),
++       * which would have called the encoder cleanup.  Do it manually.
++       */
++      if (ret < 0)
++              drm_encoder_cleanup(encoder);
++
++      imx_mhdp->dual_mode = false;
++      return ret;
++}
++
++static void cdns_mhdp_imx_unbind(struct device *dev, struct device *master,
++                             void *data)
++{
++      struct imx_mhdp_device *imx_mhdp = dev_get_drvdata(dev);
++
++      imx_mhdp->mhdp.plat_data->unbind(dev);
++}
++
++static const struct component_ops cdns_mhdp_imx_ops = {
++      .bind   = cdns_mhdp_imx_bind,
++      .unbind = cdns_mhdp_imx_unbind,
++};
++
++static int cdns_mhdp_imx_probe(struct platform_device *pdev)
++{
++      return component_add(&pdev->dev, &cdns_mhdp_imx_ops);
++}
++
++static int cdns_mhdp_imx_remove(struct platform_device *pdev)
++{
++      component_del(&pdev->dev, &cdns_mhdp_imx_ops);
++
++      return 0;
++}
++
++static struct platform_driver cdns_mhdp_imx_platform_driver = {
++      .probe  = cdns_mhdp_imx_probe,
++      .remove = cdns_mhdp_imx_remove,
++      .driver = {
++              .name = "cdn-hdp-imx8qm",
++              .of_match_table = cdns_mhdp_imx_dt_ids,
++      },
++};
++
++module_platform_driver(cdns_mhdp_imx_platform_driver);
++
++MODULE_AUTHOR("Sandor YU <sandor.yu@nxp.com>");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:cdnhdmi-imx");
+--- a/drivers/gpu/drm/imx/cdn-mhdp-phy.h
++++ b/drivers/gpu/drm/imx/cdn-mhdp-phy.h
+@@ -10,7 +10,7 @@
+ #ifndef _CDN_DP_PHY_H
+ #define _CDN_DP_PHY_H
+-#include <drm/bridge/cdns-mhdp-imx.h>
++#include <drm/bridge/cdns-mhdp-common.h>
+ #define CMN_SSM_BIAS_TMR                0x0022
+ #define CMN_PLLSM0_PLLEN_TMR            0x0029
+@@ -146,8 +146,8 @@
+ #define PHY_PMA_ISO_RX_DATA_LO          0xCC16
+ #define PHY_PMA_ISO_RX_DATA_HI          0xCC17
+-int cdns_dp_phy_init_imx8mq(struct imx_mhdp_device *hdp);
+-int cdns_dp_phy_init_imx8qm(struct imx_mhdp_device *hdp);
+-int cdns_hdmi_phy_set_imx8mq(struct imx_mhdp_device *hdp);
+-int cdns_hdmi_phy_set_imx8qm(struct imx_mhdp_device *hdp);
+-#endif /* _CDN_DP_PHY_H */
++int cdns_dp_phy_set_imx8mq(struct cdns_mhdp_device *hdp);
++int cdns_dp_phy_set_imx8qm(struct cdns_mhdp_device *hdp);
++int cdns_hdmi_phy_set_imx8mq(struct cdns_mhdp_device *hdp);
++int cdns_hdmi_phy_set_imx8qm(struct cdns_mhdp_device *hdp);
++#endif /* _CDNS_MHDP_PHY_H */
+--- /dev/null
++++ b/drivers/gpu/drm/imx/cdns-mhdp-imx.h
+@@ -0,0 +1,80 @@
++/*
++ * Cadence High-Definition Multimedia Interface (HDMI) driver
++ *
++ * Copyright (C) 2019 NXP Semiconductor, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++#ifndef CDNS_MHDP_IMX_H_
++#define CDNS_MHDP_IMX_H_
++
++#include <drm/bridge/cdns-mhdp-common.h>
++#include <drm/drm_encoder_slave.h>
++
++
++#define HDP_DUAL_MODE_MIN_PCLK_RATE   300000  /* KHz */
++#define HDP_SINGLE_MODE_MAX_WIDTH     1920
++
++static inline bool video_is_dual_mode(const struct drm_display_mode *mode)
++{
++      return (mode->clock > HDP_DUAL_MODE_MIN_PCLK_RATE ||
++              mode->hdisplay > HDP_SINGLE_MODE_MAX_WIDTH) ? true : false;
++}
++
++struct imx_mhdp_device;
++
++struct imx_hdp_clks {
++      struct clk *av_pll;
++      struct clk *dig_pll;
++      struct clk *clk_ipg;
++      struct clk *clk_core;
++      struct clk *clk_pxl;
++      struct clk *clk_pxl_mux;
++      struct clk *clk_pxl_link;
++
++      struct clk *lpcg_hdp;
++      struct clk *lpcg_msi;
++      struct clk *lpcg_pxl;
++      struct clk *lpcg_vif;
++      struct clk *lpcg_lis;
++      struct clk *lpcg_apb;
++      struct clk *lpcg_apb_csr;
++      struct clk *lpcg_apb_ctrl;
++
++      struct clk *lpcg_i2s;
++      struct clk *clk_i2s_bypass;
++};
++
++struct imx_mhdp_device {
++      struct cdns_mhdp_device mhdp;
++      struct drm_encoder encoder;
++
++      struct mutex audio_mutex;
++      spinlock_t audio_lock;
++      bool connected;
++      bool active;
++      bool suspended;
++      struct imx_hdp_clks clks;
++
++      int bus_type;
++
++      u32 dual_mode;
++
++      struct device           *pd_mhdp_dev;
++      struct device           *pd_pll0_dev;
++      struct device           *pd_pll1_dev;
++      struct device_link      *pd_mhdp_link;
++      struct device_link      *pd_pll0_link;
++      struct device_link      *pd_pll1_link;
++
++//    u32 phy_init;
++};
++void cdns_mhdp_plat_init_imx8qm(struct cdns_mhdp_device *mhdp);
++void cdns_mhdp_plat_deinit_imx8qm(struct cdns_mhdp_device *mhdp);
++void cdns_mhdp_pclk_rate_imx8qm(struct cdns_mhdp_device *mhdp);
++int cdns_mhdp_firmware_init_imx8qm(struct cdns_mhdp_device *mhdp);
++#endif /* CDNS_MHDP_IMX_H_ */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0012-drm-rockchip-change-base-address-name-from-regs-to-r.patch b/target/linux/layerscape/patches-5.4/805-display-0012-drm-rockchip-change-base-address-name-from-regs-to-r.patch
new file mode 100644 (file)
index 0000000..2ba9990
--- /dev/null
@@ -0,0 +1,29 @@
+From ef19c896ef02d33d5236ef70a53e5ca1ad06b9c9 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Wed, 11 Sep 2019 17:36:25 +0800
+Subject: [PATCH] drm: rockchip: change base address name from regs to
+ regs_base
+
+change the regs name to regs_base according the bridge druver.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/rockchip/cdn-dp-core.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
++++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
+@@ -717,10 +717,10 @@ static int cdn_dp_parse_dt(struct cdn_dp
+       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-      dp->mhdp.regs = devm_ioremap_resource(dev, res);
+-      if (IS_ERR(dp->mhdp.regs)) {
++      dp->mhdp.regs_base = devm_ioremap_resource(dev, res);
++      if (IS_ERR(dp->mhdp.regs_base)) {
+               DRM_DEV_ERROR(dev, "ioremap reg failed\n");
+-              return PTR_ERR(dp->mhdp.regs);
++              return PTR_ERR(dp->mhdp.regs_base);
+       }
+       dp->core_clk = devm_clk_get(dev, "core-clk");
diff --git a/target/linux/layerscape/patches-5.4/805-display-0013-drm-bridge-cadence-Add-power_on-to-__cdns_dp_probe.patch b/target/linux/layerscape/patches-5.4/805-display-0013-drm-bridge-cadence-Add-power_on-to-__cdns_dp_probe.patch
new file mode 100644 (file)
index 0000000..a58e75c
--- /dev/null
@@ -0,0 +1,94 @@
+From 9737dd813b872f5671d40685d2174a928da809a3 Mon Sep 17 00:00:00 2001
+From: Wen He <wen.he_1@nxp.com>
+Date: Tue, 17 Sep 2019 15:23:51 +0800
+Subject: [PATCH] drm: bridge: cadence: Add power_on to __cdns_dp_probe
+
+Add power_on of the cnds_plat_data to __cdns_dp_probe as to update
+Board related configuration initalization.
+
+Signed-off-by: Wen He <wen.he_1@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c   | 2 ++
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 2 ++
+ drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c           | 6 +++---
+ drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c           | 2 ++
+ drivers/gpu/drm/imx/cdns-mhdp-imx.h             | 1 +
+ 5 files changed, 10 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -457,6 +457,8 @@ static int __cdns_dp_probe(struct platfo
+       cdns_dp_parse_dt(mhdp);
++      cdns_mhdp_plat_call(mhdp, power_on);
++
+ //    mhdp->dual_mode = false;
+       cdns_mhdp_plat_call(mhdp, firmware_init);
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -449,6 +449,8 @@ static int __cdns_hdmi_probe(struct plat
+       /* Initialize dual_mode to false */
+ //    hdmi->dual_mode = false;
++      cdns_mhdp_plat_call(mhdp, power_on);
++
+       /* Initialize FW */
+       cdns_mhdp_plat_call(mhdp, firmware_init);
+--- a/drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
+@@ -440,7 +440,7 @@ fail:
+       return ret;
+ }
+-static void imx8qm_mhdp_power_on(struct cdns_mhdp_device *mhdp)
++int cdns_mhdp_power_on_imx8qm(struct cdns_mhdp_device *mhdp)
+ {
+       struct imx_mhdp_device *imx_mhdp =
+                               container_of(mhdp, struct imx_mhdp_device, mhdp);
+@@ -463,6 +463,8 @@ static void imx8qm_mhdp_power_on(struct
+       imx8qm_pixel_clk_enable(imx_mhdp);
+       imx8qm_phy_reset(1);
++
++      return 0;
+ }
+ void cdns_mhdp_plat_init_imx8qm(struct cdns_mhdp_device *mhdp)
+@@ -506,8 +508,6 @@ int cdns_mhdp_firmware_init_imx8qm(struc
+       u32 rate;
+       int ret;
+-      imx8qm_mhdp_power_on(mhdp);
+-
+       /* configure HDMI/DP core clock */
+       rate = clk_get_rate(imx_mhdp->clks.clk_core);
+       cdns_mhdp_set_fw_clk(&imx_mhdp->mhdp, rate);
+--- a/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
+@@ -71,6 +71,7 @@ static struct cdns_plat_data imx8qm_hdmi
+       .bind   = cdns_hdmi_bind,
+       .unbind = cdns_hdmi_unbind,
+       .phy_set = cdns_hdmi_phy_set_imx8qm,
++      .power_on = cdns_mhdp_power_on_imx8qm,
+       .firmware_init = cdns_mhdp_firmware_init_imx8qm,
+       .pclk_rate = cdns_mhdp_pclk_rate_imx8qm,
+       .plat_init = cdns_mhdp_plat_init_imx8qm,
+@@ -83,6 +84,7 @@ static struct cdns_plat_data imx8qm_dp_d
+       .bind   = cdns_dp_bind,
+       .unbind = cdns_dp_unbind,
+       .phy_set = cdns_dp_phy_set_imx8qm,
++      .power_on = cdns_mhdp_power_on_imx8qm,
+       .firmware_init = cdns_mhdp_firmware_init_imx8qm,
+       .pclk_rate = cdns_mhdp_pclk_rate_imx8qm,
+       .plat_init = cdns_mhdp_plat_init_imx8qm,
+--- a/drivers/gpu/drm/imx/cdns-mhdp-imx.h
++++ b/drivers/gpu/drm/imx/cdns-mhdp-imx.h
+@@ -77,4 +77,5 @@ void cdns_mhdp_plat_init_imx8qm(struct c
+ void cdns_mhdp_plat_deinit_imx8qm(struct cdns_mhdp_device *mhdp);
+ void cdns_mhdp_pclk_rate_imx8qm(struct cdns_mhdp_device *mhdp);
+ int cdns_mhdp_firmware_init_imx8qm(struct cdns_mhdp_device *mhdp);
++int cdns_mhdp_power_on_imx8qm(struct cdns_mhdp_device *mhdp);
+ #endif /* CDNS_MHDP_IMX_H_ */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0014-drm-ls1028a-Add-DP-driver-support-for-LS1028A.patch b/target/linux/layerscape/patches-5.4/805-display-0014-drm-ls1028a-Add-DP-driver-support-for-LS1028A.patch
new file mode 100644 (file)
index 0000000..c84b119
--- /dev/null
@@ -0,0 +1,186 @@
+From 06e912bd821b21d9360a75cde2d78b03f17a5872 Mon Sep 17 00:00:00 2001
+From: Wen He <wen.he_1@nxp.com>
+Date: Tue, 17 Sep 2019 15:35:52 +0800
+Subject: [PATCH] drm: ls1028a: Add DP driver support for LS1028A
+
+Add Display Port driver support for NXP Layerscape LS1028A platform.
+
+Signed-off-by: Wen He <wen.he_1@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c |   1 +
+ drivers/gpu/drm/imx/Makefile                  |   2 +-
+ drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c         |  13 +++
+ drivers/gpu/drm/imx/cdn-mhdp-ls1028a.c        | 110 ++++++++++++++++++++++++++
+ drivers/gpu/drm/imx/cdns-mhdp-imx.h           |   2 +
+ 5 files changed, 127 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/gpu/drm/imx/cdn-mhdp-ls1028a.c
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -275,6 +275,7 @@ static int cdns_dp_bridge_attach(struct
+       struct drm_connector *connector = &mhdp->connector.base;
+       connector->interlace_allowed = 1;
++
+       connector->polled = DRM_CONNECTOR_POLL_HPD;
+       drm_connector_helper_add(connector, &cdns_dp_connector_helper_funcs);
+--- a/drivers/gpu/drm/imx/Makefile
++++ b/drivers/gpu/drm/imx/Makefile
+@@ -9,4 +9,4 @@ obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
+ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
+ obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
+-obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdn-mhdp-imxdrv.o cdn-mhdp-dp-phy.o cdn-mhdp-hdmi-phy.o cdn-mhdp-imx8qm.o
++obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdn-mhdp-imxdrv.o cdn-mhdp-dp-phy.o cdn-mhdp-hdmi-phy.o cdn-mhdp-imx8qm.o cdn-mhdp-ls1028a.o
+--- a/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
+@@ -94,6 +94,16 @@ static struct cdns_plat_data imx8qm_dp_d
+       .is_dp = true,
+ };
++static struct cdns_plat_data ls1028a_dp_drv_data = {
++      .bind = cdns_dp_bind,
++      .unbind = cdns_dp_unbind,
++      .phy_set = cdns_dp_phy_set_imx8mq,
++      .power_on = cdns_mhdp_power_on_ls1028a,
++      .firmware_init = cdns_mhdp_firmware_init_imx8qm,
++      .pclk_rate = cdns_mhdp_pclk_rate_ls1028a,
++      .bus_type = BUS_TYPE_NORMAL_APB,
++};
++
+ static const struct of_device_id cdns_mhdp_imx_dt_ids[] = {
+       { .compatible = "cdn,imx8mq-hdmi",
+         .data = &imx8mq_hdmi_drv_data
+@@ -107,6 +117,9 @@ static const struct of_device_id cdns_mh
+       { .compatible = "cdn,imx8qm-dp",
+         .data = &imx8qm_dp_drv_data
+       },
++      { .compatible = "cdn,ls1028a-dp",
++        .data = &ls1028a_dp_drv_data
++      },
+       {},
+ };
+ MODULE_DEVICE_TABLE(of, cdns_mhdp_imx_dt_ids);
+--- /dev/null
++++ b/drivers/gpu/drm/imx/cdn-mhdp-ls1028a.c
+@@ -0,0 +1,110 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright 2019 NXP
++ *
++ */
++#include <linux/clk.h>
++#include <drm/drmP.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++
++#include "cdns-mhdp-imx.h"
++
++static const struct of_device_id scfg_device_ids[] = {
++      { .compatible = "fsl,ls1028a-scfg", },
++      {}
++};
++
++static void ls1028a_phy_reset(u8 reset)
++{
++      struct device_node *scfg_node;
++      void __iomem *scfg_base = NULL;
++
++      scfg_node = of_find_matching_node(NULL, scfg_device_ids);
++      if (scfg_node)
++              scfg_base = of_iomap(scfg_node, 0);
++
++      iowrite32(reset, scfg_base + 0x230);
++}
++
++int ls1028a_clocks_init(struct imx_mhdp_device *imx_mhdp)
++{
++      struct device *dev = imx_mhdp->mhdp.dev;
++      struct imx_hdp_clks *clks = &imx_mhdp->clks;
++
++      clks->clk_core = devm_clk_get(dev, "clk_core");
++      if (IS_ERR(clks->clk_core)) {
++              dev_warn(dev, "failed to get hdp core clk\n");
++              return PTR_ERR(clks->clk_core);
++      }
++
++      clks->clk_pxl = devm_clk_get(dev, "clk_pxl");
++      if (IS_ERR(clks->clk_pxl)) {
++              dev_warn(dev, "failed to get pxl clk\n");
++              return PTR_ERR(clks->clk_pxl);
++      }
++
++      return true;
++}
++
++static int ls1028a_pixel_clk_enable(struct imx_mhdp_device *imx_mhdp)
++{
++      struct imx_hdp_clks *clks = &imx_mhdp->clks;
++      struct device *dev = imx_mhdp->mhdp.dev;
++      int ret;
++
++      ret = clk_prepare_enable(clks->clk_pxl);
++      if (ret < 0) {
++              dev_err(dev, "%s, pre clk pxl error\n", __func__);
++              return ret;
++      }
++
++      return ret;
++}
++
++static void ls1028a_pixel_clk_disable(struct imx_mhdp_device *imx_mhdp)
++{
++      struct imx_hdp_clks *clks = &imx_mhdp->clks;
++
++      clk_disable_unprepare(clks->clk_pxl);
++}
++
++static void ls1028a_pixel_clk_set_rate(struct imx_mhdp_device *imx_mhdp,
++                                     u32 pclock)
++{
++      struct imx_hdp_clks *clks = &imx_mhdp->clks;
++
++      clk_set_rate(clks->clk_pxl, pclock);
++}
++
++int cdns_mhdp_power_on_ls1028a(struct cdns_mhdp_device *mhdp)
++{
++      struct imx_mhdp_device *imx_mhdp = container_of
++                              (mhdp, struct imx_mhdp_device, mhdp);
++
++      /* clock init and  rate set */
++      ls1028a_clocks_init(imx_mhdp);
++
++      ls1028a_pixel_clk_enable(imx_mhdp);
++
++      /* Init pixel clock with 148.5MHz before FW init */
++      ls1028a_pixel_clk_set_rate(imx_mhdp, 148500000);
++
++      ls1028a_phy_reset(1);
++
++      return 0;
++}
++
++void cdns_mhdp_pclk_rate_ls1028a(struct cdns_mhdp_device *mhdp)
++{
++      struct imx_mhdp_device *imx_mhdp = container_of
++                              (mhdp, struct imx_mhdp_device, mhdp);
++
++      /* set pixel clock before video mode setup */
++      ls1028a_pixel_clk_disable(imx_mhdp);
++
++      ls1028a_pixel_clk_set_rate(imx_mhdp, imx_mhdp->mhdp.mode.clock * 1000);
++
++      ls1028a_pixel_clk_enable(imx_mhdp);
++}
+--- a/drivers/gpu/drm/imx/cdns-mhdp-imx.h
++++ b/drivers/gpu/drm/imx/cdns-mhdp-imx.h
+@@ -78,4 +78,6 @@ void cdns_mhdp_plat_deinit_imx8qm(struct
+ void cdns_mhdp_pclk_rate_imx8qm(struct cdns_mhdp_device *mhdp);
+ int cdns_mhdp_firmware_init_imx8qm(struct cdns_mhdp_device *mhdp);
+ int cdns_mhdp_power_on_imx8qm(struct cdns_mhdp_device *mhdp);
++int cdns_mhdp_power_on_ls1028a(struct cdns_mhdp_device *mhdp);
++void cdns_mhdp_pclk_rate_ls1028a(struct cdns_mhdp_device *mhdp);
+ #endif /* CDNS_MHDP_IMX_H_ */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0015-drm-bridge-cadence-Add-support-for-periodically-poll.patch b/target/linux/layerscape/patches-5.4/805-display-0015-drm-bridge-cadence-Add-support-for-periodically-poll.patch
new file mode 100644 (file)
index 0000000..80dc0cc
--- /dev/null
@@ -0,0 +1,148 @@
+From 35e2ec234646f04eb0e17e4c3a4cf21faed3655a Mon Sep 17 00:00:00 2001
+From: Wen He <wen.he_1@nxp.com>
+Date: Wed, 18 Sep 2019 11:05:31 +0800
+Subject: [PATCH] drm: bridge: cadence: Add support for periodically poll the
+ connector
+
+Normally, DP/HDMI PHY use HPD_IRQ to monitor the connector connection
+status, but LS1028A doesn't support HPD_IRQ signals response.
+
+This patch allows periodically poll the connector for connection and
+disconnection.
+
+Signed-off-by: Wen He <wen.he_1@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 86 +++++++++++++++++----------
+ include/drm/bridge/cdns-mhdp-common.h         |  1 +
+ 2 files changed, 54 insertions(+), 33 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -276,7 +276,11 @@ static int cdns_dp_bridge_attach(struct
+       connector->interlace_allowed = 1;
+-      connector->polled = DRM_CONNECTOR_POLL_HPD;
++      if (mhdp->is_hpd)
++              connector->polled = DRM_CONNECTOR_POLL_HPD;
++      else
++              connector->polled = DRM_CONNECTOR_POLL_CONNECT |
++              DRM_CONNECTOR_POLL_DISCONNECT;
+       drm_connector_helper_add(connector, &cdns_dp_connector_helper_funcs);
+@@ -439,22 +443,34 @@ static int __cdns_dp_probe(struct platfo
+       INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func);
+       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-      mhdp->regs_base = devm_ioremap(dev, iores->start, resource_size(iores));
+-      if (IS_ERR(mhdp->regs_base))
+-              return -ENOMEM;
++      if (iores) {
++              mhdp->regs_base = devm_ioremap(dev, iores->start,
++                                             resource_size(iores));
++              if (IS_ERR(mhdp->regs_base))
++                      return -ENOMEM;
++      }
+       iores = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+-      mhdp->regs_sec = devm_ioremap(dev, iores->start, resource_size(iores));
+-      if (IS_ERR(mhdp->regs_sec))
+-              return -ENOMEM;
++      if (iores) {
++              mhdp->regs_sec = devm_ioremap(dev, iores->start,
++                                            resource_size(iores));
++              if (IS_ERR(mhdp->regs_sec))
++                      return -ENOMEM;
++      }
++
++      mhdp->is_hpd = true;
+       mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
+-      if (mhdp->irq[IRQ_IN] < 0)
++      if (mhdp->irq[IRQ_IN] < 0) {
++              mhdp->is_hpd = false;
+               dev_info(dev, "No plug_in irq number\n");
++      }
+       mhdp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
+-      if (mhdp->irq[IRQ_OUT] < 0)
++      if (mhdp->irq[IRQ_OUT] < 0) {
++              mhdp->is_hpd = false;
+               dev_info(dev, "No plug_out irq number\n");
++      }
+       cdns_dp_parse_dt(mhdp);
+@@ -474,33 +490,37 @@ static int __cdns_dp_probe(struct platfo
+       cdns_mhdp_plat_call(mhdp, phy_set);
+       /* Enable Hotplug Detect IRQ thread */
+-      irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN);
+-      ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN],
+-                                      NULL, cdns_dp_irq_thread,
+-                                      IRQF_ONESHOT, dev_name(dev),
+-                                      mhdp);
+-      if (ret) {
+-              dev_err(dev, "can't claim irq %d\n",
+-                                              mhdp->irq[IRQ_IN]);
+-              return -EINVAL;
+-      }
++      if (mhdp->is_hpd) {
++              irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN);
++              ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN],
++                                              NULL, cdns_dp_irq_thread,
++                                              IRQF_ONESHOT, dev_name(dev),
++                                              mhdp);
+       
+-      irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN);
+-      ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT],
+-                                      NULL, cdns_dp_irq_thread,
+-                                      IRQF_ONESHOT, dev_name(dev),
+-                                      mhdp);
+-      if (ret) {
+-              dev_err(dev, "can't claim irq %d\n",
+-                                              mhdp->irq[IRQ_OUT]);
+-              return -EINVAL;
++              if (ret) {
++                      dev_err(dev, "can't claim irq %d\n",
++                                      mhdp->irq[IRQ_IN]);
++                      return -EINVAL;
++              }
++
++              irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN);
++              ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT],
++                                              NULL, cdns_dp_irq_thread,
++                                              IRQF_ONESHOT, dev_name(dev),
++                                              mhdp);
++
++              if (ret) {
++                      dev_err(dev, "can't claim irq %d\n",
++                                      mhdp->irq[IRQ_OUT]);
++                      return -EINVAL;
++              }
++
++              if (cdns_mhdp_read_hpd(mhdp))
++                      enable_irq(mhdp->irq[IRQ_OUT]);
++              else
++                      enable_irq(mhdp->irq[IRQ_IN]);
+       }
+-      if (cdns_mhdp_read_hpd(mhdp))
+-              enable_irq(mhdp->irq[IRQ_OUT]);
+-      else
+-              enable_irq(mhdp->irq[IRQ_IN]);
+-
+       mhdp->bridge.base.driver_private = mhdp;
+       mhdp->bridge.base.funcs = &cdns_dp_bridge_funcs;
+ #ifdef CONFIG_OF
+--- a/include/drm/bridge/cdns-mhdp-common.h
++++ b/include/drm/bridge/cdns-mhdp-common.h
+@@ -683,6 +683,7 @@ struct cdns_mhdp_device {
+       bool link_up;
+       bool power_up;
+       bool plugged;
++      bool is_hpd;
+       struct mutex lock;
+       int irq[IRQ_NUM];
diff --git a/target/linux/layerscape/patches-5.4/805-display-0016-drm-imx-hdmi-support-arc-function.patch b/target/linux/layerscape/patches-5.4/805-display-0016-drm-imx-hdmi-support-arc-function.patch
new file mode 100644 (file)
index 0000000..a8876d0
--- /dev/null
@@ -0,0 +1,87 @@
+From a10d0b8516bc3f48f0c1005f8e69efce12cea8f9 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Mon, 23 Sep 2019 09:09:38 +0800
+Subject: [PATCH] drm: imx: hdmi: support arc function
+
+Add HDMI ARC configurate function.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c | 59 +++++++++++++++++++++++++++++++++
+ 1 file changed, 59 insertions(+)
+
+--- a/drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c
+@@ -192,6 +192,62 @@ static const struct hdmi_pll_tuning imx8
+       { 7, 5200000, 6000000, 0x7, 0x1, 0x0, 0x04, 0x0D, 680, 0x04F, 0, 0, 0 }
+ };
++static void hdmi_arc_config(struct cdns_mhdp_device *mhdp)
++{
++      u16 txpu_calib_code;
++      u16 txpd_calib_code;
++      u16 txpu_adj_calib_code;
++      u16 txpd_adj_calib_code;
++      u16 prev_calib_code;
++      u16 new_calib_code;
++      u16 rdata;
++
++      /* Power ARC */
++      cdns_phy_reg_write(mhdp, TXDA_CYA_AUXDA_CYA, 0x0001);
++
++      prev_calib_code = cdns_phy_reg_read(mhdp, TX_DIG_CTRL_REG_2);
++      txpu_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPUCAL_CTRL);
++      txpd_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPDCAL_CTRL);
++      txpu_adj_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPU_ADJ_CTRL);
++      txpd_adj_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPD_ADJ_CTRL);
++
++      new_calib_code = ((txpu_calib_code + txpd_calib_code) / 2)
++              + txpu_adj_calib_code + txpd_adj_calib_code;
++
++      if (new_calib_code != prev_calib_code) {
++              rdata = cdns_phy_reg_read(mhdp, TX_ANA_CTRL_REG_1);
++              rdata &= 0xDFFF;
++              cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, rdata);
++              cdns_phy_reg_write(mhdp, TX_DIG_CTRL_REG_2, new_calib_code);
++              mdelay(10);
++              rdata |= 0x2000;
++              cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, rdata);
++              udelay(150);
++      }
++
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0100);
++      udelay(100);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0300);
++      udelay(100);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_3, 0x0000);
++      udelay(100);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2008);
++      udelay(100);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2018);
++      udelay(100);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2098);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030C);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_5, 0x0010);
++      udelay(100);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_4, 0x4001);
++      mdelay(5);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2198);
++      mdelay(5);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030D);
++      udelay(100);
++      cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030F);
++}
++
+ static void hdmi_phy_set_vswing(struct cdns_mhdp_device *mhdp)
+ {
+       const u32 num_lanes = 4;
+@@ -604,6 +660,9 @@ static int hdmi_phy_power_up(struct cdns
+               return -1;
+       }
++      /* Power up ARC */
++      hdmi_arc_config(mhdp);
++
+       /* Configure PHY in A0 mode (PHY must be in the A0 power
+        * state in order to transmit data)
+        */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0017-drm-bridge-cadence-Fix-return-value-for-set-log-addr.patch b/target/linux/layerscape/patches-5.4/805-display-0017-drm-bridge-cadence-Fix-return-value-for-set-log-addr.patch
new file mode 100644 (file)
index 0000000..19e14bd
--- /dev/null
@@ -0,0 +1,36 @@
+From ce1e8ad4a303526026e56822a105ed45a19e6572 Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Thu, 26 Sep 2019 17:46:04 +0800
+Subject: [PATCH] drm: bridge: cadence: Fix return value for set log addr
+
+Fix return value for set log addr with cec
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c
+@@ -183,18 +183,18 @@ static int mhdp_cec_set_logical_addr(str
+               if ((la_reg & 0xF) == la) {
+                       dev_warn(cec->dev, "Warning. LA already in use.\n");
+-                      return true;
++                      return 0;
+               }
+               la = (la & 0xF) | (1 << 4);
+               mhdp_cec_write(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF), la);
+-              return true;
++              return 0;
+       }
+       dev_warn(cec->dev, "All LA in use\n");
+-      return false;
++      return -EINVAL;
+ }
+ static int mhdp_cec_poll_worker(void *_cec)
diff --git a/target/linux/layerscape/patches-5.4/805-display-0018-drm-bridge-cdns-dp-Remove-link-rate-lanes-set-by-dev.patch b/target/linux/layerscape/patches-5.4/805-display-0018-drm-bridge-cdns-dp-Remove-link-rate-lanes-set-by-dev.patch
new file mode 100644 (file)
index 0000000..58df9b9
--- /dev/null
@@ -0,0 +1,251 @@
+From 79d32025a54899fe7d82c88906c1e3ad911c498d Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Thu, 26 Sep 2019 15:46:43 +0800
+Subject: [PATCH] drm: bridge: cdns dp: Remove link rate/lanes set by device
+ tree
+
+Get the link rate and lanes from sink device.
+Remove user specific set by device tree.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c     | 56 ++++++-----------------
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c |  6 +--
+ drivers/gpu/drm/rockchip/cdn-dp-core.c            | 27 ++++++-----
+ drivers/gpu/drm/rockchip/cdn-dp-core.h            |  1 -
+ include/drm/bridge/cdns-mhdp-common.h             |  6 +--
+ 5 files changed, 35 insertions(+), 61 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -111,10 +111,10 @@ static void dp_pixel_clk_reset(struct cd
+ static void cdns_dp_mode_set(struct cdns_mhdp_device *mhdp,
+                       const struct drm_display_mode *mode)
+ {
+-      struct drm_dp_link link;
+       u32 lane_mapping = mhdp->lane_mapping;
+-      int ret;
++      struct drm_dp_link *link = &mhdp->dp.link;
+       char linkid[6];
++      int ret;
+       memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
+@@ -125,8 +125,6 @@ static void cdns_dp_mode_set(struct cdns
+       cdns_mhdp_plat_call(mhdp, pclk_rate);
+-      cdns_mhdp_plat_call(mhdp, phy_set);
+-
+       ret = drm_dp_downstream_id(&mhdp->dp.aux, linkid);
+       if (ret < 0) {
+               DRM_INFO("Failed to Get DP link ID: %d\n", ret);
+@@ -137,35 +135,28 @@ static void cdns_dp_mode_set(struct cdns
+                linkid[5]);
+       /* Check dp link */
+-      ret = drm_dp_link_probe(&mhdp->dp.aux, &link);
++      ret = drm_dp_link_probe(&mhdp->dp.aux, link);
+       if (ret < 0) {
+               DRM_INFO("Failed to probe DP link: %d\n", ret);
+               return;
+       }
+-      DRM_INFO("DP revision: 0x%x\n", link.revision);
+-      DRM_INFO("DP rate: %d Mbps\n", link.rate);
+-      DRM_INFO("DP number of lanes: %d\n", link.num_lanes);
+-      DRM_INFO("DP capabilities: 0x%lx\n", link.capabilities);
++      DRM_INFO("DP revision: 0x%x\n", link->revision);
++      DRM_INFO("DP rate: %d Mbps\n", link->rate);
++      DRM_INFO("DP number of lanes: %d\n", link->num_lanes);
++      DRM_INFO("DP capabilities: 0x%lx\n", link->capabilities);
++
++      /* check the max link rate */
++      if (link->rate > CDNS_DP_MAX_LINK_RATE)
++              link->rate = CDNS_DP_MAX_LINK_RATE;
+-      drm_dp_link_power_up(&mhdp->dp.aux, &mhdp->dp.link);
++      drm_dp_link_power_up(&mhdp->dp.aux, link);
+       if (ret < 0) {
+               DRM_INFO("Failed to power DP link: %d\n", ret);
+               return;
+       }
+-      /* always use the number of lanes from the display*/
+-      mhdp->dp.link.num_lanes = link.num_lanes;
+-
+-      /* Use the lower link rate */
+-      if (mhdp->dp.link_rate != 0) {
+-              mhdp->dp.link.rate = min(mhdp->dp.link_rate, (u32)link.rate);
+-              DRM_DEBUG("DP actual link rate:  0x%x\n", link.rate);
+-      }
+-
+-      /* initialize phy if lanes or link rate differnt */
+-      if (mhdp->dp.link.num_lanes != mhdp->dp.num_lanes ||
+-                      mhdp->dp.link.rate != mhdp->dp.link_rate)
+-              cdns_mhdp_plat_call(mhdp, phy_set);
++      /* Initialize link rate/num_lanes as panel max link rate/max_num_lanes */
++      cdns_mhdp_plat_call(mhdp, phy_set);
+       /* Video off */
+       ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
+@@ -178,7 +169,7 @@ static void cdns_dp_mode_set(struct cdns
+       cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | lane_mapping);
+       /* Set DP host capability */
+-      ret = cdns_mhdp_set_host_cap(mhdp, mhdp->dp.link.num_lanes, false);
++      ret = cdns_mhdp_set_host_cap(mhdp, false);
+       if (ret) {
+               DRM_DEV_ERROR(mhdp->dev, "Failed to set host cap %d\n", ret);
+               return;
+@@ -412,23 +403,6 @@ static void cdns_dp_parse_dt(struct cdns
+               dev_warn(mhdp->dev, "Failed to get lane_mapping - using default 0xc6\n");
+       }
+       dev_info(mhdp->dev, "lane-mapping 0x%02x\n", mhdp->lane_mapping);
+-
+-      ret = of_property_read_u32(of_node, "link-rate", &mhdp->dp.link_rate);
+-      if (ret) {
+-              mhdp->dp.link_rate = 162000 ;
+-              dev_warn(mhdp->dev, "Failed to get link-rate, use default 1620MHz\n");
+-      }
+-      dev_info(mhdp->dev, "link-rate %d\n", mhdp->dp.link_rate);
+-      
+-      ret = of_property_read_u32(of_node, "num-lanes", &mhdp->dp.num_lanes);
+-      if (ret) {
+-              mhdp->dp.num_lanes = 4;
+-              dev_warn(mhdp->dev, "Failed to get num_lanes - using default\n");
+-      }
+-      dev_info(mhdp->dev, "dp_num_lanes 0x%02x\n", mhdp->dp.num_lanes);
+-
+-      mhdp->dp.link.num_lanes = mhdp->dp.num_lanes;
+-      mhdp->dp.link.rate= mhdp->dp.link_rate;
+ }
+ static int __cdns_dp_probe(struct platform_device *pdev,
+--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
+@@ -494,13 +494,13 @@ err_set_firmware_active:
+ }
+ EXPORT_SYMBOL(cdns_mhdp_set_firmware_active);
+-int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, u8 lanes, bool flip)
++int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip)
+ {
+       u8 msg[8];
+       int ret;
+-      msg[0] = CDNS_DP_MAX_LINK_RATE;
+-      msg[1] = lanes | SCRAMBLER_EN;
++      msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.link.rate);
++      msg[1] = mhdp->dp.link.num_lanes | SCRAMBLER_EN;
+       msg[2] = VOLTAGE_LEVEL_2;
+       msg[3] = PRE_EMPHASIS_LEVEL_3;
+       msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
+--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
++++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
+@@ -305,12 +305,10 @@ static int cdn_dp_connector_mode_valid(s
+       requested = mode->clock * bpc * 3 / 1000;
+       source_max = dp->lanes;
+-      sink_max = drm_dp_max_lane_count(dp->dpcd);
++      sink_max = dp->mhdp.dp.link.num_lanes;
+       lanes = min(source_max, sink_max);
+-      source_max = drm_dp_bw_code_to_link_rate(CDNS_DP_MAX_LINK_RATE);
+-      sink_max = drm_dp_max_link_rate(dp->dpcd);
+-      rate = min(source_max, sink_max);
++      rate = dp->mhdp.dp.link.rate;
+       actual = rate * lanes / 100;
+@@ -365,21 +363,25 @@ static int cdn_dp_firmware_init(struct c
+ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp)
+ {
++      struct cdns_mhdp_device *mhdp = &dp->mhdp;
++      struct drm_dp_link *link = &mhdp->dp.link;
+       int ret;
+       if (!cdn_dp_check_sink_connection(dp))
+               return -ENODEV;
+-      ret = cdns_mhdp_dpcd_read(&dp->mhdp, DP_DPCD_REV, dp->dpcd,
+-                                DP_RECEIVER_CAP_SIZE);
++      ret = drm_dp_link_probe(&mhdp->dp.aux, link);
+       if (ret) {
+-              DRM_DEV_ERROR(dp->mhdp.dev, "Failed to get caps %d\n", ret);
++              DRM_DEV_ERROR(mhdp->dev, "Failed to get caps %d\n", ret);
+               return ret;
+       }
++      if (link->rate > CDNS_DP_MAX_LINK_RATE)
++              link->rate = CDNS_DP_MAX_LINK_RATE;
++
+       kfree(dp->edid);
+-      dp->edid = drm_do_get_edid(&dp->mhdp.connector.base,
+-                                 cdns_mhdp_get_edid_block, &dp->mhdp);
++      dp->edid = drm_do_get_edid(&mhdp->connector.base,
++                                 cdns_mhdp_get_edid_block, mhdp);
+       return 0;
+ }
+@@ -421,7 +423,8 @@ static int cdn_dp_enable_phy(struct cdn_
+       }
+       port->lanes = cdn_dp_get_port_lanes(port);
+-      ret = cdns_mhdp_set_host_cap(&dp->mhdp, port->lanes, property.intval);
++      dp->mhdp.dp.link.num_lanes = port->lanes;
++      ret = cdns_mhdp_set_host_cap(&dp->mhdp, property.intval);
+       if (ret) {
+               DRM_DEV_ERROR(dev, "set host capabilities failed: %d\n",
+                             ret);
+@@ -576,9 +579,9 @@ static bool cdn_dp_check_link_status(str
+ {
+       u8 link_status[DP_LINK_STATUS_SIZE];
+       struct cdn_dp_port *port = cdn_dp_connected_port(dp);
+-      u8 sink_lanes = drm_dp_max_lane_count(dp->dpcd);
++      u8 sink_lanes = dp->mhdp.dp.link.num_lanes;
+-      if (!port || !dp->mhdp.dp.link.rate || !dp->mhdp.dp.link.num_lanes)
++      if (!port || !dp->mhdp.dp.link.rate || !sink_lanes)
+               return false;
+       if (cdns_mhdp_dpcd_read(&dp->mhdp, DP_LANE0_1_STATUS, link_status,
+--- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
++++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
+@@ -61,7 +61,6 @@ struct cdn_dp_device {
+       u8 lanes;
+       int active_port;
+-      u8 dpcd[DP_RECEIVER_CAP_SIZE];
+       bool sink_has_audio;
+ };
+ #endif  /* _CDN_DP_CORE_H */
+--- a/include/drm/bridge/cdns-mhdp-common.h
++++ b/include/drm/bridge/cdns-mhdp-common.h
+@@ -436,7 +436,7 @@
+ #define HDCP_TX_IS_RECEIVER_ID_VALID_EVENT    BIT(7)
+ #define TU_SIZE                                       30
+-#define CDNS_DP_MAX_LINK_RATE                 DP_LINK_BW_5_4
++#define CDNS_DP_MAX_LINK_RATE 540000
+ #define F_HDMI_ENCODING(x) (((x) & ((1 << 2) - 1)) << 16)
+ #define F_VIF_DATA_WIDTH(x) (((x) & ((1 << 2) - 1)) << 2)
+@@ -697,8 +697,6 @@ struct cdns_mhdp_device {
+                       struct cdns_mhdp_mst_cbs cbs;
+                       bool is_mst;
+                       bool can_mst;
+-                      u32 link_rate;
+-                      u32 num_lanes;
+               } dp;
+               struct _hdmi_data {
+ #ifdef CONFIG_DRM_CDNS_HDMI_CEC
+@@ -720,7 +718,7 @@ u32 cdns_mhdp_get_fw_clk(struct cdns_mhd
+ int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
+                           u32 i_size, const u32 *d_mem, u32 d_size);
+ int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable);
+-int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, u8 lanes, bool flip);
++int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip);
+ int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp);
+ u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp);
+ int cdns_mhdp_get_hpd_status(struct cdns_mhdp_device *mhdp);
diff --git a/target/linux/layerscape/patches-5.4/805-display-0019-drm-imx-mhdp-add-dual-mode-support-for-imx8qm.patch b/target/linux/layerscape/patches-5.4/805-display-0019-drm-imx-mhdp-add-dual-mode-support-for-imx8qm.patch
new file mode 100644 (file)
index 0000000..689e573
--- /dev/null
@@ -0,0 +1,192 @@
+From 8e4cbfc8b1b86479a4bc64d6034449096d0af3a1 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Thu, 26 Sep 2019 17:00:26 +0800
+Subject: [PATCH] drm: imx: mhdp: add dual mode support for imx8qm
+
+Add dual mode support for imx8qm.
+imx8qm hdmi/dp driver are ready to support 4K.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c   |  4 ----
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c |  6 -----
+ drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c           | 30 +++++++++++++++++++------
+ drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c           |  3 +--
+ drivers/gpu/drm/imx/cdns-mhdp-imx.h             | 14 +-----------
+ 5 files changed, 25 insertions(+), 32 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -118,9 +118,6 @@ static void cdns_dp_mode_set(struct cdns
+       memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
+-      //Sandor TODO
+-//    mhdp->dual_mode = video_is_dual_mode(mode);
+-
+       dp_pixel_clk_reset(mhdp);
+       cdns_mhdp_plat_call(mhdp, pclk_rate);
+@@ -450,7 +447,6 @@ static int __cdns_dp_probe(struct platfo
+       cdns_mhdp_plat_call(mhdp, power_on);
+-//    mhdp->dual_mode = false;
+       cdns_mhdp_plat_call(mhdp, firmware_init);
+       /* DP FW alive check */
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -343,9 +343,6 @@ static void cdns_hdmi_bridge_mode_set(st
+       memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
+-      //Sandor TODO
+-//    hdmi->dual_mode = video_is_dual_mode(mode);
+-
+       hdmi_lanes_config(mhdp);
+       cdns_mhdp_plat_call(mhdp, pclk_rate);
+@@ -446,9 +443,6 @@ static int __cdns_hdmi_probe(struct plat
+               return -EPROBE_DEFER;
+       }
+-      /* Initialize dual_mode to false */
+-//    hdmi->dual_mode = false;
+-
+       cdns_mhdp_plat_call(mhdp, power_on);
+       /* Initialize FW */
+--- a/drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
+@@ -13,19 +13,32 @@
+ #include "cdns-mhdp-imx.h"
++#define PLL_800MHZ (800000000)
++
++#define HDP_DUAL_MODE_MIN_PCLK_RATE   300000  /* KHz */
++#define HDP_SINGLE_MODE_MAX_WIDTH     1920
++
+ #define CSR_PIXEL_LINK_MUX_CTL                0x00
+ #define CSR_PIXEL_LINK_MUX_VCP_OFFSET         5
+ #define CSR_PIXEL_LINK_MUX_HCP_OFFSET         4
+-#define PLL_800MHZ (800000000)
++static bool imx8qm_video_dual_mode(struct cdns_mhdp_device *mhdp)
++{
++      struct drm_display_mode *mode = &mhdp->mode;
++      return (mode->clock > HDP_DUAL_MODE_MIN_PCLK_RATE ||
++              mode->hdisplay > HDP_SINGLE_MODE_MAX_WIDTH) ? true : false;
++}
+ static void imx8qm_pixel_link_mux(struct imx_mhdp_device *imx_mhdp)
+ {
+       struct drm_display_mode *mode = &imx_mhdp->mhdp.mode;
++      bool dual_mode;
+       u32 val;
++      dual_mode = imx8qm_video_dual_mode(&imx_mhdp->mhdp);
++
+       val = 0x4;      /* RGB */
+-      if (imx_mhdp->dual_mode)
++      if (dual_mode)
+               val |= 0x2;     /* pixel link 0 and 1 are active */
+       if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+               val |= 1 << CSR_PIXEL_LINK_MUX_VCP_OFFSET;
+@@ -276,12 +289,13 @@ static void imx8qm_pixel_clk_disable(str
+ static void imx8qm_pixel_clk_set_rate(struct imx_mhdp_device *imx_mhdp, u32 pclock)
+ {
++      bool dual_mode = imx8qm_video_dual_mode(&imx_mhdp->mhdp);
+       struct imx_hdp_clks *clks = &imx_mhdp->clks;
+       /* pixel clock for HDMI */
+       clk_set_rate(clks->av_pll, pclock);
+-      if (imx_mhdp->dual_mode == true) {
++      if (dual_mode == true) {
+               clk_set_rate(clks->clk_pxl, pclock/2);
+               clk_set_rate(clks->clk_pxl_link, pclock/2);
+       } else {
+@@ -471,18 +485,20 @@ void cdns_mhdp_plat_init_imx8qm(struct c
+ {
+       struct imx_mhdp_device *imx_mhdp =
+                               container_of(mhdp, struct imx_mhdp_device, mhdp);
++      bool dual_mode = imx8qm_video_dual_mode(&imx_mhdp->mhdp);
+-      imx8qm_pixel_link_sync_disable(imx_mhdp->dual_mode);
+-      imx8qm_pixel_link_invalid(imx_mhdp->dual_mode);
++      imx8qm_pixel_link_sync_disable(dual_mode);
++      imx8qm_pixel_link_invalid(dual_mode);
+ }
+ void cdns_mhdp_plat_deinit_imx8qm(struct cdns_mhdp_device *mhdp)
+ {
+       struct imx_mhdp_device *imx_mhdp =
+                               container_of(mhdp, struct imx_mhdp_device, mhdp);
++      bool dual_mode = imx8qm_video_dual_mode(&imx_mhdp->mhdp);
+-      imx8qm_pixel_link_valid(imx_mhdp->dual_mode);
+-      imx8qm_pixel_link_sync_enable(imx_mhdp->dual_mode);
++      imx8qm_pixel_link_valid(dual_mode);
++      imx8qm_pixel_link_sync_enable(dual_mode);
+ }
+ void cdns_mhdp_pclk_rate_imx8qm(struct cdns_mhdp_device *mhdp)
+--- a/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
+@@ -172,7 +172,6 @@ static int cdns_mhdp_imx_bind(struct dev
+       if (ret < 0)
+               drm_encoder_cleanup(encoder);
+-      imx_mhdp->dual_mode = false;
+       return ret;
+ }
+@@ -205,7 +204,7 @@ static struct platform_driver cdns_mhdp_
+       .probe  = cdns_mhdp_imx_probe,
+       .remove = cdns_mhdp_imx_remove,
+       .driver = {
+-              .name = "cdn-hdp-imx8qm",
++              .name = "cdns-mhdp-imx",
+               .of_match_table = cdns_mhdp_imx_dt_ids,
+       },
+ };
+--- a/drivers/gpu/drm/imx/cdns-mhdp-imx.h
++++ b/drivers/gpu/drm/imx/cdns-mhdp-imx.h
+@@ -16,15 +16,6 @@
+ #include <drm/drm_encoder_slave.h>
+-#define HDP_DUAL_MODE_MIN_PCLK_RATE   300000  /* KHz */
+-#define HDP_SINGLE_MODE_MAX_WIDTH     1920
+-
+-static inline bool video_is_dual_mode(const struct drm_display_mode *mode)
+-{
+-      return (mode->clock > HDP_DUAL_MODE_MIN_PCLK_RATE ||
+-              mode->hdisplay > HDP_SINGLE_MODE_MAX_WIDTH) ? true : false;
+-}
+-
+ struct imx_mhdp_device;
+ struct imx_hdp_clks {
+@@ -62,17 +53,14 @@ struct imx_mhdp_device {
+       int bus_type;
+-      u32 dual_mode;
+-
+       struct device           *pd_mhdp_dev;
+       struct device           *pd_pll0_dev;
+       struct device           *pd_pll1_dev;
+       struct device_link      *pd_mhdp_link;
+       struct device_link      *pd_pll0_link;
+       struct device_link      *pd_pll1_link;
+-
+-//    u32 phy_init;
+ };
++
+ void cdns_mhdp_plat_init_imx8qm(struct cdns_mhdp_device *mhdp);
+ void cdns_mhdp_plat_deinit_imx8qm(struct cdns_mhdp_device *mhdp);
+ void cdns_mhdp_pclk_rate_imx8qm(struct cdns_mhdp_device *mhdp);
diff --git a/target/linux/layerscape/patches-5.4/805-display-0020-drm-bridge-cdns-cec-fix-LA-failed-set-issue.patch b/target/linux/layerscape/patches-5.4/805-display-0020-drm-bridge-cdns-cec-fix-LA-failed-set-issue.patch
new file mode 100644 (file)
index 0000000..ec36c57
--- /dev/null
@@ -0,0 +1,129 @@
+From 4e8d26c363c6e4b8b89d21feeb8c6dc57085b27d Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Fri, 27 Sep 2019 17:15:34 +0800
+Subject: [PATCH] drm: bridge: cdns cec: fix LA failed set issue
+
+improved function set_logical_addr() function.
+Fix LA set failed issue in some case.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/Kconfig         |  6 ++++
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c | 38 +++++++++++---------------
+ 2 files changed, 22 insertions(+), 22 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/Kconfig
++++ b/drivers/gpu/drm/bridge/cadence/Kconfig
+@@ -8,12 +8,18 @@ config DRM_CDNS_MHDP
+ config DRM_CDNS_HDMI
+       tristate "Cadence HDMI DRM driver"
++      depends on DRM_CDNS_MHDP
+ config DRM_CDNS_DP
+       tristate "Cadence DP DRM driver"
++      depends on DRM_CDNS_MHDP
+ config DRM_CDNS_AUDIO
+       tristate "Cadence MHDP Audio driver"
++      depends on DRM_CDNS_MHDP
+ config DRM_CDNS_HDMI_CEC
+       tristate "Cadence MHDP HDMI CEC driver"
++      depends on DRM_CDNS_HDMI
++      select CEC_CORE
++      select CEC_NOTIFIER
+--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c
+@@ -20,8 +20,6 @@
+ #define CEC_NAME      "cdns-mhdp-cec"
+ #define REG_ADDR_OFF 4
+-#define MAX_LA_IDX 4
+-#define MAX_LA_VAL 15
+ /* regsiter define */
+ #define TX_MSG_HEADER 0x33800
+@@ -158,26 +156,22 @@ static u32 mhdp_cec_write_message(struct
+       return true;
+ }
+-//static void cec_abort_tx_transfer(struct cdns_mhdp_cec *cec)
+-//{
+-//    cec_write(cec, TX_MSG_CMD, CEC_TX_ABORT);
+-//    cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
+-//}
+-
+ static int mhdp_cec_set_logical_addr(struct cdns_mhdp_cec *cec, u32 la)
+ {
+-      u8 i;
+       u8 la_reg;
++      u8 i;
+-      if (la >= MAX_LA_VAL) {
+-              dev_err(cec->dev, "Error logical Addr\n");
+-              return -EINVAL;
+-      }
+-
+-      for (i = 0; i < MAX_LA_IDX; ++i) {
+-              la_reg =
+-                  mhdp_cec_read(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF));
++      if (la == CEC_LOG_ADDR_INVALID)
++              /* invalid all LA address */
++              for (i = 0; i < CEC_MAX_LOG_ADDRS; ++i) {
++                      mhdp_cec_write(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF), 0);
++                      return 0;
++              }
++      /* In fact cdns mhdp cec could support max 5 La address */
++      for (i = 0; i < CEC_MAX_LOG_ADDRS; ++i) {
++              la_reg = mhdp_cec_read(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF));
++              /* Check LA already used */
+               if (la_reg & 0x10)
+                       continue;
+@@ -194,7 +188,7 @@ static int mhdp_cec_set_logical_addr(str
+       dev_warn(cec->dev, "All LA in use\n");
+-      return -EINVAL;
++      return -ENXIO;
+ }
+ static int mhdp_cec_poll_worker(void *_cec)
+@@ -263,7 +257,7 @@ static int mhdp_cec_poll_worker(void *_c
+ static int mhdp_cec_adap_enable(struct cec_adapter *adap, bool enable)
+ {
+-      struct cdns_mhdp_cec *cec = adap->priv;
++      struct cdns_mhdp_cec *cec = cec_get_drvdata(adap);
+       if (enable) {
+               mhdp_cec_write(cec, DB_L_TIMER, 0x10);
+@@ -276,7 +270,7 @@ static int mhdp_cec_adap_enable(struct c
+ static int mhdp_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
+ {
+-      struct cdns_mhdp_cec *cec = adap->priv;
++      struct cdns_mhdp_cec *cec = cec_get_drvdata(adap);
+       return mhdp_cec_set_logical_addr(cec, addr);
+ }
+@@ -284,7 +278,7 @@ static int mhdp_cec_adap_log_addr(struct
+ static int mhdp_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
+                                u32 signal_free_time, struct cec_msg *msg)
+ {
+-      struct cdns_mhdp_cec *cec = adap->priv;
++      struct cdns_mhdp_cec *cec = cec_get_drvdata(adap);
+       mhdp_cec_write_message(cec, msg);
+@@ -307,7 +301,7 @@ int cdns_mhdp_register_cec_driver(struct
+                                        CEC_NAME,
+                                        CEC_CAP_PHYS_ADDR | CEC_CAP_LOG_ADDRS |
+                                        CEC_CAP_TRANSMIT | CEC_CAP_PASSTHROUGH
+-                                       | CEC_CAP_RC, 1);
++                                       | CEC_CAP_RC, CEC_MAX_LOG_ADDRS);
+       ret = PTR_ERR_OR_ZERO(cec->adap);
+       if (ret)
+               return ret;
diff --git a/target/linux/layerscape/patches-5.4/805-display-0021-DRM-mhdp-HDMI-skip-scdc-write-return-check.patch b/target/linux/layerscape/patches-5.4/805-display-0021-DRM-mhdp-HDMI-skip-scdc-write-return-check.patch
new file mode 100644 (file)
index 0000000..a41beea
--- /dev/null
@@ -0,0 +1,29 @@
+From 74c383e7da3e20c201e3b0c847a3d2f6fa0dbdc6 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Sun, 29 Sep 2019 14:48:28 +0800
+Subject: [PATCH] DRM: mhdp: HDMI: skip scdc write return check
+
+HDMI sink that only support HDMI1.4 is not support
+SCDC read/write. Skip the SCDC write check and continue
+HDMI initialize process.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -173,10 +173,8 @@ void cdns_hdmi_mode_set(struct cdns_mhdp
+       int ret;
+       ret = hdmi_sink_config(mhdp);
+-      if (ret < 0) {
+-              DRM_ERROR("%s failed\n", __func__);
+-              return;
+-      }
++      if (ret < 0)
++              DRM_DEBUG("%s failed\n", __func__);
+       ret = cdns_hdmi_ctrl_init(mhdp, mhdp->hdmi.hdmi_type, mhdp->hdmi.char_rate);
+       if (ret < 0) {
diff --git a/target/linux/layerscape/patches-5.4/805-display-0022-drm-mhdp-add-mutex-lock-to-mhdp-register-access-func.patch b/target/linux/layerscape/patches-5.4/805-display-0022-drm-mhdp-add-mutex-lock-to-mhdp-register-access-func.patch
new file mode 100644 (file)
index 0000000..0fc3d13
--- /dev/null
@@ -0,0 +1,83 @@
+From ef8be75663178c0720d0944d9305f624776fc91c Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Thu, 17 Oct 2019 16:29:49 +0800
+Subject: [PATCH] drm: mhdp: add mutex lock to mhdp register access function
+
+Add muxtex lock to mhdp registers access functions
+that could avoid race condition between cec thread and hdmi video.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c     | 1 +
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c   | 1 +
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c | 8 ++++++++
+ include/drm/bridge/cdns-mhdp-common.h             | 1 +
+ 4 files changed, 11 insertions(+)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -410,6 +410,7 @@ static int __cdns_dp_probe(struct platfo
+       int ret;
+       mutex_init(&mhdp->lock);
++      mutex_init(&mhdp->iolock);
+       INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func);
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -411,6 +411,7 @@ static int __cdns_hdmi_probe(struct plat
+       int ret;
+       mutex_init(&mhdp->lock);
++      mutex_init(&mhdp->iolock);
+       INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func);
+--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
+@@ -75,6 +75,8 @@ u32 cdns_mhdp_bus_read(struct cdns_mhdp_
+ {
+       u32 val;
++      mutex_lock(&mhdp->iolock);
++
+       if (mhdp->bus_type == BUS_TYPE_LOW4K_SAPB) {
+               /* Remap address to low 4K SAPB bus */
+               writel(offset >> 12, mhdp->regs_sec + 0xc);
+@@ -88,12 +90,16 @@ u32 cdns_mhdp_bus_read(struct cdns_mhdp_
+       else
+               val = readl(mhdp->regs_base + offset);
++      mutex_unlock(&mhdp->iolock);
++
+       return val;
+ }
+ EXPORT_SYMBOL(cdns_mhdp_bus_read);
+ void cdns_mhdp_bus_write(u32 val, struct cdns_mhdp_device *mhdp, u32 offset)
+ {
++      mutex_lock(&mhdp->iolock);
++
+       if (mhdp->bus_type == BUS_TYPE_LOW4K_SAPB) {
+               /* Remap address to low 4K SAPB bus */
+               writel(offset >> 12, mhdp->regs_sec + 0xc);
+@@ -106,6 +112,8 @@ void cdns_mhdp_bus_write(u32 val, struct
+               writel(val, mhdp->regs_sec + offset);
+       else
+               writel(val, mhdp->regs_base + offset);
++
++      mutex_unlock(&mhdp->iolock);
+ }
+ EXPORT_SYMBOL(cdns_mhdp_bus_write);
+--- a/include/drm/bridge/cdns-mhdp-common.h
++++ b/include/drm/bridge/cdns-mhdp-common.h
+@@ -685,6 +685,7 @@ struct cdns_mhdp_device {
+       bool plugged;
+       bool is_hpd;
+       struct mutex lock;
++      struct mutex iolock;
+       int irq[IRQ_NUM];
diff --git a/target/linux/layerscape/patches-5.4/805-display-0023-drm-mhdp-reset-video-mode-after-hdmi-dp-cable-plugin.patch b/target/linux/layerscape/patches-5.4/805-display-0023-drm-mhdp-reset-video-mode-after-hdmi-dp-cable-plugin.patch
new file mode 100644 (file)
index 0000000..9e90f7d
--- /dev/null
@@ -0,0 +1,236 @@
+From 9ff3c9d6063c6464e243b85bbbbd03e2096a57c0 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Mon, 28 Oct 2019 17:07:06 +0800
+Subject: [PATCH] drm: mhdp: reset video mode after hdmi/dp cable plugin
+
+DP need setup link training, and HDMI need reset hdmi sink SCDC
+status after cable reconnected.
+Add video mode_set function when cable plugin.
+Add 20ms/50ms delay for hdmi/dp to waite FW stable.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c   | 20 ++++----
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 63 ++++++++++++-------------
+ 2 files changed, 43 insertions(+), 40 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -108,19 +108,19 @@ static void dp_pixel_clk_reset(struct cd
+       cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val);
+ }
+-static void cdns_dp_mode_set(struct cdns_mhdp_device *mhdp,
+-                      const struct drm_display_mode *mode)
++static void cdns_dp_mode_set(struct cdns_mhdp_device *mhdp)
+ {
+       u32 lane_mapping = mhdp->lane_mapping;
+       struct drm_dp_link *link = &mhdp->dp.link;
+       char linkid[6];
+       int ret;
+-      memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
++      cdns_mhdp_plat_call(mhdp, pclk_rate);
+-      dp_pixel_clk_reset(mhdp);
++      /* delay for DP FW stable after pixel clock relock */
++      msleep(50);
+-      cdns_mhdp_plat_call(mhdp, pclk_rate);
++      dp_pixel_clk_reset(mhdp);
+       ret = drm_dp_downstream_id(&mhdp->dp.aux, linkid);
+       if (ret < 0) {
+@@ -330,11 +330,10 @@ static void cdns_dp_bridge_mode_set(stru
+       video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
+       DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); 
++      memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
+       mutex_lock(&mhdp->lock);
+-
+-      cdns_dp_mode_set(mhdp, mode);
+-
++      cdns_dp_mode_set(mhdp);
+       mutex_unlock(&mhdp->lock);
+ }
+@@ -367,6 +366,11 @@ static void hotplug_work_func(struct wor
+       drm_helper_hpd_irq_event(connector->dev);
+       if (connector->status == connector_status_connected) {
++              /* reset video mode after cable plugin */
++              mutex_lock(&mhdp->lock);
++              cdns_dp_mode_set(mhdp);
++              mutex_unlock(&mhdp->lock);
++
+               DRM_INFO("HDMI/DP Cable Plug In\n");
+               enable_irq(mhdp->irq[IRQ_OUT]);
+       } else if (connector->status == connector_status_disconnected) {
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -11,11 +11,11 @@
+  */
+ #include <drm/bridge/cdns-mhdp-common.h>
+ #include <drm/drm_atomic_helper.h>
+-#include <drm/drm_crtc_helper.h>
+ #include <drm/drm_edid.h>
+ #include <drm/drm_encoder_slave.h>
+ #include <drm/drm_of.h>
+ #include <drm/drm_probe_helper.h>
++#include <drm/drm_scdc_helper.h>
+ #include <drm/drmP.h>
+ #include <linux/delay.h>
+ #include <linux/err.h>
+@@ -26,25 +26,30 @@
+ #include <linux/mutex.h>
+ #include <linux/of_device.h>
+-static int hdmi_sink_config(struct cdns_mhdp_device *mhdp)
++static void hdmi_sink_config(struct cdns_mhdp_device *mhdp)
+ {
+       struct drm_scdc *scdc = &mhdp->connector.base.display_info.hdmi.scdc;
+       u8 buff;
+-      int ret;
++
++      /* check sink support SCDC or not */
++      if (scdc->supported != true) {
++              DRM_INFO("Sink Not Support SCDC\n");
++              return;
++      }
+       if (mhdp->hdmi.char_rate > 340000) {
+               /*
+                * TMDS Character Rate above 340MHz should working in HDMI2.0
+                * Enable scrambling and TMDS_Bit_Clock_Ratio
+                */
+-              buff = 3;
++              buff = SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE;
+               mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
+       } else  if (scdc->scrambling.low_rates) {
+               /*
+                * Enable scrambling and HDMI2.0 when scrambling capability of sink
+                * be indicated in the HF-VSDB LTE_340Mcsc_scramble bit
+                */
+-              buff = 1;
++              buff = SCDC_SCRAMBLING_ENABLE;
+               mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
+       } else {
+               /* Default work in HDMI1.4 */
+@@ -53,8 +58,7 @@ static int hdmi_sink_config(struct cdns_
+        }
+       /* TMDS config */
+-      ret = cdns_hdmi_scdc_write(mhdp, 0x20, buff);
+-      return ret;
++      cdns_hdmi_scdc_write(mhdp, 0x20, buff);
+ }
+ static void hdmi_lanes_config(struct cdns_mhdp_device *mhdp)
+@@ -142,7 +146,7 @@ static int hdmi_avi_info_set(struct cdns
+       return 0;
+ }
+-static int hdmi_vendor_info_set(struct cdns_mhdp_device *mhdp,
++static void hdmi_vendor_info_set(struct cdns_mhdp_device *mhdp,
+                               struct drm_display_mode *mode)
+ {
+       struct hdmi_vendor_infoframe frame;
+@@ -152,19 +156,18 @@ static int hdmi_vendor_info_set(struct c
+       /* Initialise vendor frame from DRM mode */
+       ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame, &mhdp->connector.base, mode);
+       if (ret < 0) {
+-              DRM_WARN("Unable to init vendor infoframe: %d\n", ret);
+-              return -1;
++              DRM_INFO("No vendor infoframe\n");
++              return;
+       }
+       ret = hdmi_vendor_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
+       if (ret < 0) {
+               DRM_WARN("Unable to pack vendor infoframe: %d\n", ret);
+-              return -1;
++              return;
+       }
+       buf[0] = 0;
+       cdns_mhdp_infoframe_set(mhdp, 3, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_VENDOR);
+-      return 0;
+ }
+ void cdns_hdmi_mode_set(struct cdns_mhdp_device *mhdp)
+@@ -172,9 +175,16 @@ void cdns_hdmi_mode_set(struct cdns_mhdp
+       struct drm_display_mode *mode = &mhdp->mode;
+       int ret;
+-      ret = hdmi_sink_config(mhdp);
+-      if (ret < 0)
+-              DRM_DEBUG("%s failed\n", __func__);
++      hdmi_lanes_config(mhdp);
++
++      cdns_mhdp_plat_call(mhdp, pclk_rate);
++
++      /* delay for HDMI FW stable after pixel clock relock */
++      msleep(20);
++
++      cdns_mhdp_plat_call(mhdp, phy_set);
++
++      hdmi_sink_config(mhdp);
+       ret = cdns_hdmi_ctrl_init(mhdp, mhdp->hdmi.hdmi_type, mhdp->hdmi.char_rate);
+       if (ret < 0) {
+@@ -195,18 +205,13 @@ void cdns_hdmi_mode_set(struct cdns_mhdp
+       }
+       /* vendor info frame is enable only  when HDMI1.4 4K mode */
+-      ret = hdmi_vendor_info_set(mhdp, mode);
+-      if (ret < 0)
+-              DRM_WARN("Unable to configure Vendor infoframe\n");
++      hdmi_vendor_info_set(mhdp, mode);
+       ret = cdns_hdmi_mode_config(mhdp, mode, &mhdp->video_info);
+       if (ret < 0) {
+               DRM_ERROR("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret);
+               return;
+       }
+-
+-      /* wait HDMI PHY pixel clock stable */
+-      msleep(50);
+ }
+ static enum drm_connector_status
+@@ -335,20 +340,11 @@ static void cdns_hdmi_bridge_mode_set(st
+       video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
+       video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
+-      mutex_lock(&mhdp->lock);
+-
+       DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); 
+-
+       memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
+-      hdmi_lanes_config(mhdp);
+-
+-      cdns_mhdp_plat_call(mhdp, pclk_rate);
+-
+-      cdns_mhdp_plat_call(mhdp, phy_set);
+-
++      mutex_lock(&mhdp->lock);
+       cdns_hdmi_mode_set(mhdp);
+-
+       mutex_unlock(&mhdp->lock);
+ }
+@@ -367,8 +363,11 @@ static void hotplug_work_func(struct wor
+       drm_helper_hpd_irq_event(connector->dev);
+       if (connector->status == connector_status_connected) {
+-              /* Cable Connected */
+               DRM_INFO("HDMI Cable Plug In\n");
++              /* reset video mode after cable plugin */
++              mutex_lock(&mhdp->lock);
++              cdns_hdmi_mode_set(mhdp);
++              mutex_unlock(&mhdp->lock);
+               enable_irq(mhdp->irq[IRQ_OUT]);
+       } else if (connector->status == connector_status_disconnected) {
+               /* Cable Disconnedted  */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0024-drm-bridge-cadence-hdmi-remove-video-mode-limition.patch b/target/linux/layerscape/patches-5.4/805-display-0024-drm-bridge-cadence-hdmi-remove-video-mode-limition.patch
new file mode 100644 (file)
index 0000000..1e06680
--- /dev/null
@@ -0,0 +1,27 @@
+From e3ebc237397387251828e52f4c21509d977e7797 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Wed, 13 Nov 2019 16:47:47 +0800
+Subject: [PATCH] drm: bridge: cadence: hdmi: remove video mode limition
+
+combine mode is supported by imx8qm DPU.
+imx8qm HDMI could support full feature.
+Remove the 1080p60 limition.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -305,8 +305,8 @@ cdns_hdmi_bridge_mode_valid(struct drm_b
+                       mode->flags & DRM_MODE_FLAG_INTERLACE)
+               return MODE_BAD;
+-      /* MAX support pixel clock rate 148.5MHz */
+-      if (mode->clock > 148500)
++      /* MAX support pixel clock rate 594MHz */
++      if (mode->clock > 594000)
+               return MODE_CLOCK_HIGH;
+       /* 4096x2160 is not supported */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0025-drm-imx-hdp-add-hdr10-metadata-property.patch b/target/linux/layerscape/patches-5.4/805-display-0025-drm-imx-hdp-add-hdr10-metadata-property.patch
new file mode 100644 (file)
index 0000000..6ce4263
--- /dev/null
@@ -0,0 +1,173 @@
+From 7c5c4f891ce4746b52d95d9340c7cae063a48350 Mon Sep 17 00:00:00 2001
+From: Laurentiu Palcu <laurentiu.palcu@nxp.com>
+Date: Mon, 4 Nov 2019 13:18:48 +0200
+Subject: [PATCH] drm/imx/hdp: add hdr10 metadata property
+
+The HDR_OUTPUT_METADATA property is needed in order for userspace to instruct
+the sink to switch to HDR10 mode.
+
+Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 72 +++++++++++++++++++++++++
+ drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c           |  4 ++
+ include/drm/bridge/cdns-mhdp-common.h           |  1 +
+ 3 files changed, 77 insertions(+)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -170,6 +170,35 @@ static void hdmi_vendor_info_set(struct
+       cdns_mhdp_infoframe_set(mhdp, 3, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_VENDOR);
+ }
++static void hdmi_drm_info_set(struct cdns_mhdp_device *mhdp)
++{
++      struct drm_connector_state *conn_state;
++      struct hdmi_drm_infoframe frame;
++      u8 buf[32];
++      int ret;
++
++      conn_state = mhdp->connector.base.state;
++
++      if (!conn_state->hdr_output_metadata)
++              return;
++
++      ret = drm_hdmi_infoframe_set_hdr_metadata(&frame, conn_state);
++      if (ret < 0) {
++              DRM_DEBUG_KMS("couldn't set HDR metadata in infoframe\n");
++              return;
++      }
++
++      ret = hdmi_drm_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
++      if (ret < 0) {
++              DRM_DEBUG_KMS("couldn't pack HDR infoframe\n");
++              return;
++      }
++
++      buf[0] = 0;
++      cdns_mhdp_infoframe_set(mhdp, 3, sizeof(buf),
++                              buf, HDMI_INFOFRAME_TYPE_DRM);
++}
++
+ void cdns_hdmi_mode_set(struct cdns_mhdp_device *mhdp)
+ {
+       struct drm_display_mode *mode = &mhdp->mode;
+@@ -207,6 +236,8 @@ void cdns_hdmi_mode_set(struct cdns_mhdp
+       /* vendor info frame is enable only  when HDMI1.4 4K mode */
+       hdmi_vendor_info_set(mhdp, mode);
++      hdmi_drm_info_set(mhdp);
++
+       ret = cdns_hdmi_mode_config(mhdp, mode, &mhdp->video_info);
+       if (ret < 0) {
+               DRM_ERROR("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret);
+@@ -262,6 +293,40 @@ static int cdns_hdmi_connector_get_modes
+       return num_modes;
+ }
++static bool blob_equal(const struct drm_property_blob *a,
++                     const struct drm_property_blob *b)
++{
++      if (a && b)
++              return a->length == b->length &&
++                      !memcmp(a->data, b->data, a->length);
++
++      return !a == !b;
++}
++
++static int cdns_hdmi_connector_atomic_check(struct drm_connector *connector,
++                                          struct drm_atomic_state *state)
++{
++      struct drm_connector_state *new_con_state =
++              drm_atomic_get_new_connector_state(state, connector);
++      struct drm_connector_state *old_con_state =
++              drm_atomic_get_old_connector_state(state, connector);
++      struct drm_crtc *crtc = new_con_state->crtc;
++      struct drm_crtc_state *new_crtc_state;
++
++      if (!blob_equal(new_con_state->hdr_output_metadata,
++                      old_con_state->hdr_output_metadata)) {
++              new_crtc_state = drm_atomic_get_crtc_state(state, crtc);
++              if (IS_ERR(new_crtc_state))
++                      return PTR_ERR(new_crtc_state);
++
++              new_crtc_state->mode_changed =
++                      !new_con_state->hdr_output_metadata ||
++                      !old_con_state->hdr_output_metadata;
++      }
++
++      return 0;
++}
++
+ static const struct drm_connector_funcs cdns_hdmi_connector_funcs = {
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .detect = cdns_hdmi_connector_detect,
+@@ -273,11 +338,13 @@ static const struct drm_connector_funcs
+ static const struct drm_connector_helper_funcs cdns_hdmi_connector_helper_funcs = {
+       .get_modes = cdns_hdmi_connector_get_modes,
++      .atomic_check = cdns_hdmi_connector_atomic_check,
+ };
+ static int cdns_hdmi_bridge_attach(struct drm_bridge *bridge)
+ {
+       struct cdns_mhdp_device *mhdp = bridge->driver_private;
++      struct drm_mode_config *config = &bridge->dev->mode_config;
+       struct drm_encoder *encoder = bridge->encoder;
+       struct drm_connector *connector = &mhdp->connector.base;
+@@ -289,6 +356,11 @@ static int cdns_hdmi_bridge_attach(struc
+       drm_connector_init(bridge->dev, connector, &cdns_hdmi_connector_funcs,
+                          DRM_MODE_CONNECTOR_HDMIA);
++      if (!strncmp("imx8mq-hdmi", mhdp->plat_data->plat_name, 11))
++              drm_object_attach_property(&connector->base,
++                                         config->hdr_output_metadata_property,
++                                         0);
++
+       drm_connector_attach_encoder(connector, encoder);
+       return 0;
+--- a/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
+@@ -54,6 +54,7 @@ static const struct drm_encoder_funcs cd
+ };
+ static struct cdns_plat_data imx8mq_hdmi_drv_data = {
++      .plat_name = "imx8mq-hdmi",
+       .bind   = cdns_hdmi_bind,
+       .unbind = cdns_hdmi_unbind,
+       .phy_set = cdns_hdmi_phy_set_imx8mq,
+@@ -61,6 +62,7 @@ static struct cdns_plat_data imx8mq_hdmi
+ };
+ static struct cdns_plat_data imx8mq_dp_drv_data = {
++      .plat_name = "imx8mq-dp",
+       .bind   = cdns_dp_bind,
+       .unbind = cdns_dp_unbind,
+       .phy_set = cdns_dp_phy_set_imx8mq,
+@@ -68,6 +70,7 @@ static struct cdns_plat_data imx8mq_dp_d
+ };
+ static struct cdns_plat_data imx8qm_hdmi_drv_data = {
++      .plat_name = "imx8qm-hdmi",
+       .bind   = cdns_hdmi_bind,
+       .unbind = cdns_hdmi_unbind,
+       .phy_set = cdns_hdmi_phy_set_imx8qm,
+@@ -81,6 +84,7 @@ static struct cdns_plat_data imx8qm_hdmi
+ };
+ static struct cdns_plat_data imx8qm_dp_drv_data = {
++      .plat_name = "imx8qm-dp",
+       .bind   = cdns_dp_bind,
+       .unbind = cdns_dp_unbind,
+       .phy_set = cdns_dp_phy_set_imx8qm,
+--- a/include/drm/bridge/cdns-mhdp-common.h
++++ b/include/drm/bridge/cdns-mhdp-common.h
+@@ -652,6 +652,7 @@ struct cdns_plat_data {
+       int bus_type;
+       int video_format;
+       char is_dp;
++      char *plat_name;
+ };
+ struct cdns_mhdp_device {
diff --git a/target/linux/layerscape/patches-5.4/805-display-0026-drm-imx-hdp-add-colorspace-property.patch b/target/linux/layerscape/patches-5.4/805-display-0026-drm-imx-hdp-add-colorspace-property.patch
new file mode 100644 (file)
index 0000000..40d956c
--- /dev/null
@@ -0,0 +1,39 @@
+From 55ebf12c54a53319d6a890eb499b68565242c3c4 Mon Sep 17 00:00:00 2001
+From: Laurentiu Palcu <laurentiu.palcu@nxp.com>
+Date: Thu, 7 Nov 2019 15:09:11 +0200
+Subject: [PATCH] drm/imx/hdp: add colorspace property
+
+iMX8MQ has the ability to adjust the DCSS output pipe gamut and nonlinearity
+depending on the HDMI connector capability. Userspace can explicitly set this
+property if it decides, based on EDID parsing, that the sink supports REC.2020
+and it wants to switch when it plays HDR10 content.
+
+Otherwise, the kernel will use the default settings specified in the HDMI
+specifications.
+
+Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -356,11 +356,17 @@ static int cdns_hdmi_bridge_attach(struc
+       drm_connector_init(bridge->dev, connector, &cdns_hdmi_connector_funcs,
+                          DRM_MODE_CONNECTOR_HDMIA);
+-      if (!strncmp("imx8mq-hdmi", mhdp->plat_data->plat_name, 11))
++      if (!strncmp("imx8mq-hdmi", mhdp->plat_data->plat_name, 11)) {
+               drm_object_attach_property(&connector->base,
+                                          config->hdr_output_metadata_property,
+                                          0);
++              if (!drm_mode_create_colorspace_property(connector))
++                      drm_object_attach_property(&connector->base,
++                                              connector->colorspace_property,
++                                              0);
++      }
++
+       drm_connector_attach_encoder(connector, encoder);
+       return 0;
diff --git a/target/linux/layerscape/patches-5.4/805-display-0027-drm-imx-hdp-force-a-mode-set-when-colorspace-is-chan.patch b/target/linux/layerscape/patches-5.4/805-display-0027-drm-imx-hdp-force-a-mode-set-when-colorspace-is-chan.patch
new file mode 100644 (file)
index 0000000..c63ae91
--- /dev/null
@@ -0,0 +1,34 @@
+From da02a33c186db04986166659caafb0c2da5bf7f0 Mon Sep 17 00:00:00 2001
+From: Laurentiu Palcu <laurentiu.palcu@nxp.com>
+Date: Fri, 15 Nov 2019 10:00:55 +0200
+Subject: [PATCH] drm/imx/hdp: force a mode set when colorspace is changed
+
+If the userspace changes the connector Colorspace property, we need to force a
+modeset, so that the entire pipeline is properly configured.
+
+Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -314,14 +314,16 @@ static int cdns_hdmi_connector_atomic_ch
+       struct drm_crtc_state *new_crtc_state;
+       if (!blob_equal(new_con_state->hdr_output_metadata,
+-                      old_con_state->hdr_output_metadata)) {
++                      old_con_state->hdr_output_metadata) ||
++          new_con_state->colorspace != old_con_state->colorspace) {
+               new_crtc_state = drm_atomic_get_crtc_state(state, crtc);
+               if (IS_ERR(new_crtc_state))
+                       return PTR_ERR(new_crtc_state);
+               new_crtc_state->mode_changed =
+                       !new_con_state->hdr_output_metadata ||
+-                      !old_con_state->hdr_output_metadata;
++                      !old_con_state->hdr_output_metadata ||
++                      new_con_state->colorspace != old_con_state->colorspace;
+       }
+       return 0;
diff --git a/target/linux/layerscape/patches-5.4/805-display-0028-drm-imx-hdp-handle-the-various-deep-color-settings.patch b/target/linux/layerscape/patches-5.4/805-display-0028-drm-imx-hdp-handle-the-various-deep-color-settings.patch
new file mode 100644 (file)
index 0000000..14c9557
--- /dev/null
@@ -0,0 +1,187 @@
+From 1a8c7e6db6898ea62820bdd4fc9ef70b04ea528a Mon Sep 17 00:00:00 2001
+From: Laurentiu Palcu <laurentiu.palcu@nxp.com>
+Date: Thu, 7 Nov 2019 15:23:41 +0200
+Subject: [PATCH] drm/imx/hdp: handle the various deep-color settings
+
+iMX8MQ has the ability to handle color depths up to 12bpc. This patch adds
+support for higher color depths for various modes.
+
+Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 132 ++++++++++++++----------
+ 1 file changed, 75 insertions(+), 57 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -67,58 +67,20 @@ static void hdmi_lanes_config(struct cdn
+       cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | mhdp->lane_mapping);
+ }
+-#define RGB_ALLOWED_COLORIMETRY (BIT(HDMI_EXTENDED_COLORIMETRY_BT2020) |\
+-                               BIT(HDMI_EXTENDED_COLORIMETRY_OPRGB))
+-#define YCC_ALLOWED_COLORIMETRY (BIT(HDMI_EXTENDED_COLORIMETRY_BT2020) |\
+-                               BIT(HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM) |\
+-                               BIT(HDMI_EXTENDED_COLORIMETRY_OPYCC_601) |\
+-                               BIT(HDMI_EXTENDED_COLORIMETRY_S_YCC_601) |\
+-                               BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_709) |\
+-                               BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_601))
+ static int hdmi_avi_info_set(struct cdns_mhdp_device *mhdp,
+-                              struct drm_display_mode *mode)
++                           struct drm_display_mode *mode)
+ {
+       struct hdmi_avi_infoframe frame;
+-#if 0
+-      struct drm_display_info *di = &mhdp->connector.base.display_info;
+-      enum hdmi_extended_colorimetry ext_col;
+-      u32 sink_col, allowed_col;
+-#endif
+       int format = mhdp->video_info.color_fmt;
++      struct drm_connector_state *conn_state = mhdp->connector.base.state;
++      struct drm_display_mode *adj_mode;
++      enum hdmi_quantization_range qr;
+       u8 buf[32];
+       int ret;
+       /* Initialise info frame from DRM mode */
+-      drm_hdmi_avi_infoframe_from_display_mode(&frame, &mhdp->connector.base, mode);
+-
+-#if 0 //TODO to DCSS
+-      /* Set up colorimetry */
+-      allowed_col = format == PXL_RGB ? RGB_ALLOWED_COLORIMETRY :
+-                                                YCC_ALLOWED_COLORIMETRY;
+-
+-      sink_col = di->hdmi.colorimetry & allowed_col;
+-
+-      if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_BT2020))
+-              ext_col = HDMI_EXTENDED_COLORIMETRY_BT2020;
+-      else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM))
+-              ext_col = HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM;
+-      else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_OPRGB))
+-              ext_col = HDMI_EXTENDED_COLORIMETRY_OPRGB;
+-      else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_709))
+-              ext_col = HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
+-      else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_OPYCC_601))
+-              ext_col = HDMI_EXTENDED_COLORIMETRY_OPYCC_601;
+-      else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_S_YCC_601))
+-              ext_col = HDMI_EXTENDED_COLORIMETRY_S_YCC_601;
+-      else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_601))
+-              ext_col = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
+-      else
+-              ext_col = 0;
+-
+-      frame.colorimetry = sink_col ? HDMI_COLORIMETRY_EXTENDED :
+-                                        HDMI_COLORIMETRY_NONE;
+-      frame.extended_colorimetry = ext_col;
+-#endif
++      drm_hdmi_avi_infoframe_from_display_mode(&frame, &mhdp->connector.base,
++                                               mode);
+       switch (format) {
+       case YCBCR_4_4_4:
+@@ -135,6 +97,19 @@ static int hdmi_avi_info_set(struct cdns
+               break;
+       }
++      drm_hdmi_avi_infoframe_colorspace(&frame, conn_state);
++
++      adj_mode = &mhdp->bridge.base.encoder->crtc->state->adjusted_mode;
++
++      qr = drm_default_rgb_quant_range(adj_mode);
++
++      drm_hdmi_avi_infoframe_quant_range(&frame, &mhdp->connector.base,
++                                         adj_mode, qr);
++
++      ret = hdmi_avi_infoframe_check(&frame);
++      if (WARN_ON(ret))
++              return false;
++
+       ret = hdmi_avi_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
+       if (ret < 0) {
+               DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
+@@ -404,19 +379,6 @@ static void cdns_hdmi_bridge_mode_set(st
+       struct drm_display_info *display_info = &mhdp->connector.base.display_info;
+       struct video_info *video = &mhdp->video_info;
+-      switch (display_info->bpc) {
+-      case 10:
+-              video->color_depth = 10;
+-              break;
+-      case 6:
+-              video->color_depth = 6;
+-              break;
+-      default:
+-              video->color_depth = 8;
+-              break;
+-      }
+-
+-      video->color_fmt = PXL_RGB;
+       video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
+       video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
+@@ -428,10 +390,66 @@ static void cdns_hdmi_bridge_mode_set(st
+       mutex_unlock(&mhdp->lock);
+ }
++bool cdns_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
++                               const struct drm_display_mode *mode,
++                               struct drm_display_mode *adjusted_mode)
++{
++      struct cdns_mhdp_device *mhdp = bridge->driver_private;
++      struct drm_display_info *di = &mhdp->connector.base.display_info;
++      struct video_info *video = &mhdp->video_info;
++      int vic = drm_match_cea_mode(mode);
++
++      video->color_depth = 8;
++      video->color_fmt = PXL_RGB;
++
++      /* for all other platforms, other than imx8mq */
++      if (strncmp("imx8mq-hdmi", mhdp->plat_data->plat_name, 11)) {
++              if (di->bpc == 10 || di->bpc == 6)
++                      video->color_depth = di->bpc;
++
++              return true;
++      }
++
++      /* imx8mq */
++      if (vic == 97 || vic == 96) {
++              if (di->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36)
++                      video->color_depth = 12;
++              else if (di->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)
++                      video->color_depth = 10;
++
++              if (drm_mode_is_420_only(di, mode) ||
++                  (drm_mode_is_420_also(di, mode) &&
++                   video->color_depth > 8)) {
++                      video->color_fmt = YCBCR_4_2_0;
++
++                      adjusted_mode->private_flags = 1;
++                      return true;
++              }
++
++              video->color_depth = 8;
++              return true;
++      }
++
++      /* Any defined maximum tmds clock limit we must not exceed*/
++      if ((di->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36) &&
++          (mode->clock * 3 / 2 <= di->max_tmds_clock))
++              video->color_depth = 12;
++      else if ((di->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) &&
++               (mode->clock * 5 / 4 <= di->max_tmds_clock))
++              video->color_depth = 10;
++
++      /* 10-bit color depth for the following modes is not supported */
++      if ((vic == 95 || vic == 94 || vic == 93) && video->color_depth == 10)
++              video->color_depth = 8;
++
++      return true;
++}
++
+ static const struct drm_bridge_funcs cdns_hdmi_bridge_funcs = {
+       .attach = cdns_hdmi_bridge_attach,
+       .mode_set = cdns_hdmi_bridge_mode_set,
+       .mode_valid = cdns_hdmi_bridge_mode_valid,
++      .mode_fixup = cdns_hdmi_bridge_mode_fixup,
+ };
+ static void hotplug_work_func(struct work_struct *work)
diff --git a/target/linux/layerscape/patches-5.4/805-display-0029-drm-imx-mhdp-Adjustment-core-rate-of-DP-TX-CTRL-for-.patch b/target/linux/layerscape/patches-5.4/805-display-0029-drm-imx-mhdp-Adjustment-core-rate-of-DP-TX-CTRL-for-.patch
new file mode 100644 (file)
index 0000000..443351f
--- /dev/null
@@ -0,0 +1,59 @@
+From 4d5ce89b5a6faa347464221e4b674be46b951245 Mon Sep 17 00:00:00 2001
+From: Wen He <wen.he_1@nxp.com>
+Date: Wed, 27 Nov 2019 18:24:11 +0800
+Subject: [PATCH] drm: imx: mhdp: Adjustment core rate of DP TX CTRL for
+ LS1028A
+
+This Display TX CTRL clock should be ACLK/4, update it to align with
+the specification.
+
+Signed-off-by: Wen He <wen.he_1@nxp.com>
+Reviewed-by: Sandor Yu <sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 4 ++++
+ drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c         | 3 +++
+ include/drm/bridge/cdns-mhdp-common.h         | 1 +
+ 3 files changed, 8 insertions(+)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -435,6 +435,7 @@ static int __cdns_dp_probe(struct platfo
+       }
+       mhdp->is_hpd = true;
++      mhdp->is_ls1028a = false;
+       mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
+       if (mhdp->irq[IRQ_IN] < 0) {
+@@ -450,6 +451,9 @@ static int __cdns_dp_probe(struct platfo
+       cdns_dp_parse_dt(mhdp);
++      if (of_device_is_compatible(dev->of_node, "cdn,ls1028a-dp"))
++              mhdp->is_ls1028a = true;
++
+       cdns_mhdp_plat_call(mhdp, power_on);
+       cdns_mhdp_plat_call(mhdp, firmware_init);
+--- a/drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
+@@ -526,6 +526,9 @@ int cdns_mhdp_firmware_init_imx8qm(struc
+       /* configure HDMI/DP core clock */
+       rate = clk_get_rate(imx_mhdp->clks.clk_core);
++      if (mhdp->is_ls1028a)
++              rate = rate / 4;
++
+       cdns_mhdp_set_fw_clk(&imx_mhdp->mhdp, rate);
+       /* un-reset ucpu */
+--- a/include/drm/bridge/cdns-mhdp-common.h
++++ b/include/drm/bridge/cdns-mhdp-common.h
+@@ -685,6 +685,7 @@ struct cdns_mhdp_device {
+       bool power_up;
+       bool plugged;
+       bool is_hpd;
++      bool is_ls1028a;
+       struct mutex lock;
+       struct mutex iolock;
diff --git a/target/linux/layerscape/patches-5.4/805-display-0030-drm-imx-hdp-fix-issue-with-non-SCDC-HDMI-sinks.patch b/target/linux/layerscape/patches-5.4/805-display-0030-drm-imx-hdp-fix-issue-with-non-SCDC-HDMI-sinks.patch
new file mode 100644 (file)
index 0000000..be72d1f
--- /dev/null
@@ -0,0 +1,60 @@
+From d9440f7cb8fa5853b9dcc6e2b165725ac3e8b70c Mon Sep 17 00:00:00 2001
+From: Laurentiu Palcu <laurentiu.palcu@nxp.com>
+Date: Wed, 27 Nov 2019 13:34:51 +0200
+Subject: [PATCH] drm/imx/hdp: fix issue with non-SCDC HDMI sinks
+
+Currently, if sink does not support SCDC, even if the sink is HDMI 1.4 or 2.0,
+the hdmi_type is left to default value (MODE_DVI). Hence the HDMI controler is
+not properly initialized when cdns_hdmi_ctrl_init() is called.
+
+Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
+Reported-by: Jared Hu <jared.hu@nxp.com>
+Reviewed-by: Sandor Yu <sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -29,11 +29,17 @@
+ static void hdmi_sink_config(struct cdns_mhdp_device *mhdp)
+ {
+       struct drm_scdc *scdc = &mhdp->connector.base.display_info.hdmi.scdc;
+-      u8 buff;
++      struct drm_display_info *di = &mhdp->connector.base.display_info;
++      u8 buff = 0;
++
++      if (scdc->supported || di->color_formats & DRM_COLOR_FORMAT_YCRCB420)
++              mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
++      else
++              mhdp->hdmi.hdmi_type = MODE_HDMI_1_4;
+       /* check sink support SCDC or not */
+-      if (scdc->supported != true) {
+-              DRM_INFO("Sink Not Support SCDC\n");
++      if (!scdc->supported) {
++              DRM_INFO("Sink does not support SCDC\n");
+               return;
+       }
+@@ -43,19 +49,13 @@ static void hdmi_sink_config(struct cdns
+                * Enable scrambling and TMDS_Bit_Clock_Ratio
+                */
+               buff = SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE;
+-              mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
+       } else  if (scdc->scrambling.low_rates) {
+               /*
+                * Enable scrambling and HDMI2.0 when scrambling capability of sink
+                * be indicated in the HF-VSDB LTE_340Mcsc_scramble bit
+                */
+               buff = SCDC_SCRAMBLING_ENABLE;
+-              mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
+-      } else {
+-              /* Default work in HDMI1.4 */
+-              buff = 0;
+-              mhdp->hdmi.hdmi_type = MODE_HDMI_1_4;
+-       }
++      }
+       /* TMDS config */
+       cdns_hdmi_scdc_write(mhdp, 0x20, buff);
diff --git a/target/linux/layerscape/patches-5.4/805-display-0031-Revert-drm-imx-hdp-fix-issue-with-non-SCDC-HDMI-sink.patch b/target/linux/layerscape/patches-5.4/805-display-0031-Revert-drm-imx-hdp-fix-issue-with-non-SCDC-HDMI-sink.patch
new file mode 100644 (file)
index 0000000..e906be4
--- /dev/null
@@ -0,0 +1,63 @@
+From 575fc16e92287349f0ffd8399dd9d7e408954cd4 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Fri, 29 Nov 2019 15:05:03 +0800
+Subject: [PATCH] Revert "drm/imx/hdp: fix issue with non-SCDC HDMI sinks"
+
+For HDMI sinks that support HDMI2.0, those video modes have
+listed in hdmi1.4 specification should work in hdmi 1.4.
+Remove the patch, make sure all video modes can work well
+in HDMI2.0 sinks.
+For non-SCDC HDMI sinks issue,
+it will be fixed with another patch.
+
+This reverts commit 4b6617643f9e3a6f61d42eae39034ddc8d4825af.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -29,17 +29,11 @@
+ static void hdmi_sink_config(struct cdns_mhdp_device *mhdp)
+ {
+       struct drm_scdc *scdc = &mhdp->connector.base.display_info.hdmi.scdc;
+-      struct drm_display_info *di = &mhdp->connector.base.display_info;
+-      u8 buff = 0;
+-
+-      if (scdc->supported || di->color_formats & DRM_COLOR_FORMAT_YCRCB420)
+-              mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
+-      else
+-              mhdp->hdmi.hdmi_type = MODE_HDMI_1_4;
++      u8 buff;
+       /* check sink support SCDC or not */
+-      if (!scdc->supported) {
+-              DRM_INFO("Sink does not support SCDC\n");
++      if (scdc->supported != true) {
++              DRM_INFO("Sink Not Support SCDC\n");
+               return;
+       }
+@@ -49,13 +43,19 @@ static void hdmi_sink_config(struct cdns
+                * Enable scrambling and TMDS_Bit_Clock_Ratio
+                */
+               buff = SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE;
++              mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
+       } else  if (scdc->scrambling.low_rates) {
+               /*
+                * Enable scrambling and HDMI2.0 when scrambling capability of sink
+                * be indicated in the HF-VSDB LTE_340Mcsc_scramble bit
+                */
+               buff = SCDC_SCRAMBLING_ENABLE;
+-      }
++              mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
++      } else {
++              /* Default work in HDMI1.4 */
++              buff = 0;
++              mhdp->hdmi.hdmi_type = MODE_HDMI_1_4;
++       }
+       /* TMDS config */
+       cdns_hdmi_scdc_write(mhdp, 0x20, buff);
diff --git a/target/linux/layerscape/patches-5.4/805-display-0032-drm-hdmi-imx8-fix-wrong-hdmi-type-with-non-SCDC-HDMI.patch b/target/linux/layerscape/patches-5.4/805-display-0032-drm-hdmi-imx8-fix-wrong-hdmi-type-with-non-SCDC-HDMI.patch
new file mode 100644 (file)
index 0000000..43b590d
--- /dev/null
@@ -0,0 +1,41 @@
+From 94f34486d678f01378f539dee843a74eb476320e Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Fri, 29 Nov 2019 15:00:59 +0800
+Subject: [PATCH] drm: hdmi: imx8: fix wrong hdmi type with non-SCDC HDMI sinks
+
+hdmi type is uninitialized with non-SCDC HDMI sinks.
+And hdmi ctrl will work in DVI mode that is not ecpected.
+Set hdmi type to HDMI1.4 before SCDC support check to fix it.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -29,7 +29,10 @@
+ static void hdmi_sink_config(struct cdns_mhdp_device *mhdp)
+ {
+       struct drm_scdc *scdc = &mhdp->connector.base.display_info.hdmi.scdc;
+-      u8 buff;
++      u8 buff = 0;
++
++      /* Default work in HDMI1.4 */
++      mhdp->hdmi.hdmi_type = MODE_HDMI_1_4;
+       /* check sink support SCDC or not */
+       if (scdc->supported != true) {
+@@ -51,11 +54,7 @@ static void hdmi_sink_config(struct cdns
+                */
+               buff = SCDC_SCRAMBLING_ENABLE;
+               mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
+-      } else {
+-              /* Default work in HDMI1.4 */
+-              buff = 0;
+-              mhdp->hdmi.hdmi_type = MODE_HDMI_1_4;
+-       }
++      }
+       /* TMDS config */
+       cdns_hdmi_scdc_write(mhdp, 0x20, buff);
diff --git a/target/linux/layerscape/patches-5.4/805-display-0033-LF-94-drm-hdmi-imx-Add-hdmi-phy-video-mode-valid-fun.patch b/target/linux/layerscape/patches-5.4/805-display-0033-LF-94-drm-hdmi-imx-Add-hdmi-phy-video-mode-valid-fun.patch
new file mode 100644 (file)
index 0000000..e3e555e
--- /dev/null
@@ -0,0 +1,135 @@
+From 6f23cfed09dc50e532a5d6a535bb992102d03cab Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Wed, 27 Nov 2019 19:08:42 +0800
+Subject: [PATCH] LF-94: drm: hdmi: imx: Add hdmi phy video mode valid function
+
+Add hdmi phy video mode valid function to filter the video modes.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+Reviewed-by: Robby Cai <robby.cai@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c |  8 +++++++-
+ drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c         | 23 +++++++++++++++++++++++
+ drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c           |  2 ++
+ drivers/gpu/drm/imx/cdn-mhdp-phy.h              |  2 ++
+ include/drm/bridge/cdns-mhdp-common.h           |  2 ++
+ 5 files changed, 36 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -352,7 +352,9 @@ static enum drm_mode_status
+ cdns_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
+                         const struct drm_display_mode *mode)
+ {
++      struct cdns_mhdp_device *mhdp = bridge->driver_private;
+       enum drm_mode_status mode_status = MODE_OK;
++      int ret;
+       /* We don't support double-clocked and Interlaced modes */
+       if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
+@@ -367,6 +369,11 @@ cdns_hdmi_bridge_mode_valid(struct drm_b
+       if (mode->hdisplay > 3840 || mode->vdisplay > 2160)
+               return MODE_BAD_HVALUE;
++      mhdp->valid_mode = mode;
++      ret = cdns_mhdp_plat_call(mhdp, phy_video_valid);
++      if (ret == false)
++              return MODE_CLOCK_RANGE;
++
+       return mode_status;
+ }
+@@ -375,7 +382,6 @@ static void cdns_hdmi_bridge_mode_set(st
+                                   const struct drm_display_mode *mode)
+ {
+       struct cdns_mhdp_device *mhdp = bridge->driver_private;
+-      struct drm_display_info *display_info = &mhdp->connector.base.display_info;
+       struct video_info *video = &mhdp->video_info;
+       video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
+--- a/drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c
+@@ -683,6 +683,17 @@ static int hdmi_phy_power_up(struct cdns
+       return 0;
+ }
++bool cdns_hdmi_phy_video_valid_imx8mq(struct cdns_mhdp_device *mhdp)
++{
++      u32 rate = mhdp->valid_mode->clock;
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(imx8mq_ctrl_table); i++)
++                      if(rate == imx8mq_ctrl_table[i].pixel_clk_freq_min)
++                              return true;
++      return false;
++}
++
+ int cdns_hdmi_phy_set_imx8mq(struct cdns_mhdp_device *mhdp)
+ {
+       struct drm_display_mode *mode = &mhdp->mode;
+@@ -711,6 +722,18 @@ int cdns_hdmi_phy_set_imx8mq(struct cdns
+       return true;
+ }
++bool cdns_hdmi_phy_video_valid_imx8qm(struct cdns_mhdp_device *mhdp)
++{
++      u32 rate = mhdp->valid_mode->clock;
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(imx8qm_ctrl_table); i++)
++                      if(rate >= imx8qm_ctrl_table[i].pixel_clk_freq_min &&
++                              rate <= imx8qm_ctrl_table[i].pixel_clk_freq_max)
++                              return true;
++      return false;
++}
++
+ int cdns_hdmi_phy_set_imx8qm(struct cdns_mhdp_device *mhdp)
+ {
+       struct drm_display_mode *mode = &mhdp->mode;
+--- a/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
+@@ -58,6 +58,7 @@ static struct cdns_plat_data imx8mq_hdmi
+       .bind   = cdns_hdmi_bind,
+       .unbind = cdns_hdmi_unbind,
+       .phy_set = cdns_hdmi_phy_set_imx8mq,
++      .phy_video_valid = cdns_hdmi_phy_video_valid_imx8mq,
+       .bus_type = BUS_TYPE_NORMAL_APB,
+ };
+@@ -74,6 +75,7 @@ static struct cdns_plat_data imx8qm_hdmi
+       .bind   = cdns_hdmi_bind,
+       .unbind = cdns_hdmi_unbind,
+       .phy_set = cdns_hdmi_phy_set_imx8qm,
++      .phy_video_valid = cdns_hdmi_phy_video_valid_imx8qm,
+       .power_on = cdns_mhdp_power_on_imx8qm,
+       .firmware_init = cdns_mhdp_firmware_init_imx8qm,
+       .pclk_rate = cdns_mhdp_pclk_rate_imx8qm,
+--- a/drivers/gpu/drm/imx/cdn-mhdp-phy.h
++++ b/drivers/gpu/drm/imx/cdn-mhdp-phy.h
+@@ -148,6 +148,8 @@
+ int cdns_dp_phy_set_imx8mq(struct cdns_mhdp_device *hdp);
+ int cdns_dp_phy_set_imx8qm(struct cdns_mhdp_device *hdp);
++bool cdns_hdmi_phy_video_valid_imx8mq(struct cdns_mhdp_device *hdp);
++bool cdns_hdmi_phy_video_valid_imx8qm(struct cdns_mhdp_device *hdp);
+ int cdns_hdmi_phy_set_imx8mq(struct cdns_mhdp_device *hdp);
+ int cdns_hdmi_phy_set_imx8qm(struct cdns_mhdp_device *hdp);
+ #endif /* _CDNS_MHDP_PHY_H */
+--- a/include/drm/bridge/cdns-mhdp-common.h
++++ b/include/drm/bridge/cdns-mhdp-common.h
+@@ -643,6 +643,7 @@ struct cdns_plat_data {
+       void (*plat_deinit)(struct cdns_mhdp_device *mhdp);
+       int (*phy_set)(struct cdns_mhdp_device *mhdp);
++      bool (*phy_video_valid)(struct cdns_mhdp_device *mhdp);
+       int (*firmware_init)(struct cdns_mhdp_device *mhdp);
+       void (*pclk_rate)(struct cdns_mhdp_device *mhdp);
+@@ -675,6 +676,7 @@ struct cdns_mhdp_device {
+       struct video_info       video_info;
+       struct drm_display_mode mode;
++      const struct drm_display_mode   *valid_mode;
+       unsigned int            fw_version;
+       struct drm_dp_mst_topology_mgr mst_mgr;
diff --git a/target/linux/layerscape/patches-5.4/805-display-0034-media-bus-format-Add-RGB888_1X30_PADLO-support.patch b/target/linux/layerscape/patches-5.4/805-display-0034-media-bus-format-Add-RGB888_1X30_PADLO-support.patch
new file mode 100644 (file)
index 0000000..1bdcaed
--- /dev/null
@@ -0,0 +1,22 @@
+From 5df87202c0b8524a5eed58b86842219df42d6013 Mon Sep 17 00:00:00 2001
+From: Liu Ying <victor.liu@nxp.com>
+Date: Tue, 9 May 2017 17:16:27 +0800
+Subject: [PATCH] media: bus format: Add RGB888_1X30_PADLO support
+
+This patch adds 30bit RGB888 with low padding support.
+
+Signed-off-by: Liu Ying <victor.liu@nxp.com>
+---
+ include/uapi/linux/media-bus-format.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/include/uapi/linux/media-bus-format.h
++++ b/include/uapi/linux/media-bus-format.h
+@@ -63,6 +63,7 @@
+ #define MEDIA_BUS_FMT_RGB101010_1X30          0x1018
+ #define MEDIA_BUS_FMT_RGB121212_1X36          0x1019
+ #define MEDIA_BUS_FMT_RGB161616_1X48          0x101a
++#define MEDIA_BUS_FMT_RGB888_1X30_PADLO               0x101b
+ /* YUV (including grey) - next is     0x202d */
+ #define MEDIA_BUS_FMT_Y8_1X8                  0x2001
diff --git a/target/linux/layerscape/patches-5.4/805-display-0035-media-bus-format-Add-RGB666_1X30_PADLO-support.patch b/target/linux/layerscape/patches-5.4/805-display-0035-media-bus-format-Add-RGB666_1X30_PADLO-support.patch
new file mode 100644 (file)
index 0000000..0e821ec
--- /dev/null
@@ -0,0 +1,22 @@
+From 0792ee462890fa96cf84dce7ca05634316b64c49 Mon Sep 17 00:00:00 2001
+From: Liu Ying <victor.liu@nxp.com>
+Date: Tue, 9 May 2017 17:38:37 +0800
+Subject: [PATCH] media: bus format: Add RGB666_1X30_PADLO support
+
+This patch adds 30bit RGB666 with low padding support.
+
+Signed-off-by: Liu Ying <victor.liu@nxp.com>
+---
+ include/uapi/linux/media-bus-format.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/include/uapi/linux/media-bus-format.h
++++ b/include/uapi/linux/media-bus-format.h
+@@ -64,6 +64,7 @@
+ #define MEDIA_BUS_FMT_RGB121212_1X36          0x1019
+ #define MEDIA_BUS_FMT_RGB161616_1X48          0x101a
+ #define MEDIA_BUS_FMT_RGB888_1X30_PADLO               0x101b
++#define MEDIA_BUS_FMT_RGB666_1X30_PADLO               0x101c
+ /* YUV (including grey) - next is     0x202d */
+ #define MEDIA_BUS_FMT_Y8_1X8                  0x2001
diff --git a/target/linux/layerscape/patches-5.4/805-display-0036-media-bus-format-Add-RGB101010_1X7X5_SPWG-JEIDA-supp.patch b/target/linux/layerscape/patches-5.4/805-display-0036-media-bus-format-Add-RGB101010_1X7X5_SPWG-JEIDA-supp.patch
new file mode 100644 (file)
index 0000000..2d07206
--- /dev/null
@@ -0,0 +1,34 @@
+From 5cc582f5609f947d9692eef5489388c61cfbcc88 Mon Sep 17 00:00:00 2001
+From: Liu Ying <victor.liu@nxp.com>
+Date: Tue, 9 May 2017 17:39:41 +0800
+Subject: [PATCH] media: bus format: Add RGB101010_1X7X5_SPWG/JEIDA support
+
+This patch adds 30bit RGB101010 LVDS pixel formats support for
+the SPWG and JEIDA LVDS mapping standards.  Each pixel is transferred
+on 5 lanes with 7bit respectively.
+
+Signed-off-by: Liu Ying <victor.liu@nxp.com>
+---
+ include/uapi/linux/media-bus-format.h | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/include/uapi/linux/media-bus-format.h
++++ b/include/uapi/linux/media-bus-format.h
+@@ -34,7 +34,7 @@
+ #define MEDIA_BUS_FMT_FIXED                   0x0001
+-/* RGB - next is      0x101d */
++/* RGB - next is      0x101f */
+ #define MEDIA_BUS_FMT_RGB444_1X12             0x1016
+ #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE     0x1001
+ #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE     0x1002
+@@ -65,6 +65,8 @@
+ #define MEDIA_BUS_FMT_RGB161616_1X48          0x101a
+ #define MEDIA_BUS_FMT_RGB888_1X30_PADLO               0x101b
+ #define MEDIA_BUS_FMT_RGB666_1X30_PADLO               0x101c
++#define MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG    0x101d
++#define MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA   0x101e
+ /* YUV (including grey) - next is     0x202d */
+ #define MEDIA_BUS_FMT_Y8_1X8                  0x2001
diff --git a/target/linux/layerscape/patches-5.4/805-display-0037-MLK-15110-1-drm-fourcc-Add-Amphion-tiled-layout-form.patch b/target/linux/layerscape/patches-5.4/805-display-0037-MLK-15110-1-drm-fourcc-Add-Amphion-tiled-layout-form.patch
new file mode 100644 (file)
index 0000000..5edec54
--- /dev/null
@@ -0,0 +1,44 @@
+From 57a12a90496eb310d56ab45f105819d6103b472e Mon Sep 17 00:00:00 2001
+From: Liu Ying <victor.liu@nxp.com>
+Date: Thu, 3 Aug 2017 16:00:46 +0800
+Subject: [PATCH] MLK-15110-1 drm/fourcc: Add Amphion tiled layout format
+ modifier
+
+Amphion VPU has a tiled layout using 8x128 pixel vertical strips,
+where each strip contains 1x16 groups of 8x8 pixels in a row-major layout.
+
+Signed-off-by: Song Bing <bing.song@nxp.com>
+Signed-off-by: Liu Ying <victor.liu@nxp.com>
+[ Aisheng : AMPHION changed to 0xf1 ]
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ include/uapi/drm/drm_fourcc.h | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/include/uapi/drm/drm_fourcc.h
++++ b/include/uapi/drm/drm_fourcc.h
+@@ -309,6 +309,7 @@ extern "C" {
+ #define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07
+ #define DRM_FORMAT_MOD_VENDOR_ARM     0x08
+ #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09
++#define DRM_FORMAT_MOD_VENDOR_AMPHION 0xf0
+ /* add more to the end as needed */
+@@ -756,6 +757,16 @@ extern "C" {
+  */
+ #define DRM_FORMAT_MOD_ALLWINNER_TILED fourcc_mod_code(ALLWINNER, 1)
++/* Amphion tiled layout */
++
++/*
++ * Amphion 8x128 tiling layout
++ *
++ * This is a tiled layout using 8x128 pixel vertical strips, where each strip
++ * contains 1x16 groups of 8x8 pixels in a row-major layout.
++ */
++#define DRM_FORMAT_MOD_AMPHION_TILED fourcc_mod_code(AMPHION, 1)
++
+ #if defined(__cplusplus)
+ }
+ #endif
diff --git a/target/linux/layerscape/patches-5.4/805-display-0038-MLK-16290-drm-Add-drm_of_component_probe_with_match-.patch b/target/linux/layerscape/patches-5.4/805-display-0038-MLK-16290-drm-Add-drm_of_component_probe_with_match-.patch
new file mode 100644 (file)
index 0000000..4097733
--- /dev/null
@@ -0,0 +1,114 @@
+From 43265ca8cc62395e1750686daa8b7007b617e53b Mon Sep 17 00:00:00 2001
+From: Liu Ying <victor.liu@nxp.com>
+Date: Tue, 29 Aug 2017 16:58:58 +0800
+Subject: [PATCH] MLK-16290 drm: Add drm_of_component_probe_with_match() helper
+
+A component master may have both OF based and non-OF based components to be
+bound with.  This patch adds a helper drm_of_component_probe_with_match()
+similar to drm_of_component_probe() so that the new helper may get an
+additional provided match pointer(contains match entries for non-OF based
+components) to support this case.
+
+Tested-by: Meng Mingming <mingming.meng@nxp.com>
+Signed-off-by: Liu Ying <victor.liu@nxp.com>
+(cherry picked from commit c3cad7223488638ab56c20b2c29345487857bc5f)
+---
+ drivers/gpu/drm/drm_of.c | 31 ++++++++++++++++++++++++++++---
+ include/drm/drm_of.h     | 13 +++++++++++++
+ 2 files changed, 41 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/drm_of.c
++++ b/drivers/gpu/drm/drm_of.c
+@@ -100,8 +100,10 @@ void drm_of_component_match_add(struct d
+ EXPORT_SYMBOL_GPL(drm_of_component_match_add);
+ /**
+- * drm_of_component_probe - Generic probe function for a component based master
++ * drm_of_component_probe_with_match - Generic probe function with match
++ *                                     entries for a component based master
+  * @dev: master device containing the OF node
++ * @match: component match pointer provided to store matches
+  * @compare_of: compare function used for matching components
+  * @m_ops: component master ops to be used
+  *
+@@ -112,12 +114,12 @@ EXPORT_SYMBOL_GPL(drm_of_component_match
+  *
+  * Returns zero if successful, or one of the standard error codes if it fails.
+  */
+-int drm_of_component_probe(struct device *dev,
++int drm_of_component_probe_with_match(struct device *dev,
++                         struct component_match *match,
+                          int (*compare_of)(struct device *, void *),
+                          const struct component_master_ops *m_ops)
+ {
+       struct device_node *ep, *port, *remote;
+-      struct component_match *match = NULL;
+       int i;
+       if (!dev->of_node)
+@@ -183,6 +185,29 @@ int drm_of_component_probe(struct device
+       return component_master_add_with_match(dev, m_ops, match);
+ }
++EXPORT_SYMBOL(drm_of_component_probe_with_match);
++
++/**
++ * drm_of_component_probe - Generic probe function for a component based master
++ * @dev: master device containing the OF node
++ * @compare_of: compare function used for matching components
++ * @master_ops: component master ops to be used
++ *
++ * Parse the platform device OF node and bind all the components associated
++ * with the master. Interface ports are added before the encoders in order to
++ * satisfy their .bind requirements
++ * See Documentation/devicetree/bindings/graph.txt for the bindings.
++ *
++ * Returns zero if successful, or one of the standard error codes if it fails.
++ */
++int drm_of_component_probe(struct device *dev,
++                         int (*compare_of)(struct device *, void *),
++                         const struct component_master_ops *m_ops)
++{
++      struct component_match *match = NULL;
++
++      return drm_of_component_probe_with_match(dev, match, compare_of, m_ops);
++}
+ EXPORT_SYMBOL(drm_of_component_probe);
+ /*
+--- a/include/drm/drm_of.h
++++ b/include/drm/drm_of.h
+@@ -7,6 +7,7 @@
+ #include <drm/drm_bridge.h>
+ #endif
++struct component_match;
+ struct component_master_ops;
+ struct component_match;
+ struct device;
+@@ -25,6 +26,10 @@ void drm_of_component_match_add(struct d
+                               struct component_match **matchptr,
+                               int (*compare)(struct device *, void *),
+                               struct device_node *node);
++extern int drm_of_component_probe_with_match(struct device *dev,
++                         struct component_match *match,
++                         int (*compare_of)(struct device *, void *),
++                         const struct component_master_ops *m_ops);
+ int drm_of_component_probe(struct device *dev,
+                          int (*compare_of)(struct device *, void *),
+                          const struct component_master_ops *m_ops);
+@@ -56,6 +61,14 @@ drm_of_component_match_add(struct device
+ {
+ }
++static int drm_of_component_probe_with_match(struct device *dev,
++                         struct component_match *match,
++                         int (*compare_of)(struct device *, void *),
++                         const struct component_master_ops *m_ops)
++{
++      return -EINVAL;
++}
++
+ static inline int
+ drm_of_component_probe(struct device *dev,
+                      int (*compare_of)(struct device *, void *),
diff --git a/target/linux/layerscape/patches-5.4/805-display-0039-MLK-17368-1-drm-add-fourcc-codes-for-Verisilicon-til.patch b/target/linux/layerscape/patches-5.4/805-display-0039-MLK-17368-1-drm-add-fourcc-codes-for-Verisilicon-til.patch
new file mode 100644 (file)
index 0000000..842ca64
--- /dev/null
@@ -0,0 +1,58 @@
+From 7d11e6c1669b9134b11a48cdf47e5b7ab1b2396c Mon Sep 17 00:00:00 2001
+From: Bing Song <bing.song@nxp.com>
+Date: Fri, 5 Jan 2018 08:33:51 +0200
+Subject: [PATCH] MLK-17368-1 drm: add fourcc codes for Verisilicon tiled
+ formats
+
+These formats will be used by VPU and DCSS.
+
+Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
+[ Aisheng : VENDOR_VSI changed to 0xf1 ]
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ include/uapi/drm/drm_fourcc.h | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+--- a/include/uapi/drm/drm_fourcc.h
++++ b/include/uapi/drm/drm_fourcc.h
+@@ -310,6 +310,7 @@ extern "C" {
+ #define DRM_FORMAT_MOD_VENDOR_ARM     0x08
+ #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09
+ #define DRM_FORMAT_MOD_VENDOR_AMPHION 0xf0
++#define DRM_FORMAT_MOD_VENDOR_VSI     0xf1
+ /* add more to the end as needed */
+@@ -767,6 +768,32 @@ extern "C" {
+  */
+ #define DRM_FORMAT_MOD_AMPHION_TILED fourcc_mod_code(AMPHION, 1)
++/* Verisilicon framebuffer modifiers */
++
++/*
++ * Verisilicon 8x4 tiling layout
++ *
++ * This is G1 VPU tiled layout using tiles of 8x4 pixels in a row-major
++ * layout.
++ */
++#define DRM_FORMAT_MOD_VSI_G1_TILED fourcc_mod_code(VSI, 1)
++
++/*
++ * Verisilicon 4x4 tiling layout
++ *
++ * This is G2 VPU tiled layout using tiles of 4x4 pixels in a row-major
++ * layout.
++ */
++#define DRM_FORMAT_MOD_VSI_G2_TILED fourcc_mod_code(VSI, 2)
++
++/*
++ * Verisilicon 4x4 tiling with compression layout
++ *
++ * This is G2 VPU tiled layout using tiles of 4x4 pixels in a row-major
++ * layout with compression.
++ */
++#define DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED fourcc_mod_code(VSI, 3)
++
+ #if defined(__cplusplus)
+ }
+ #endif
diff --git a/target/linux/layerscape/patches-5.4/805-display-0040-drm-fourcc-add-modifier-for-vivante-compressed-tiled.patch b/target/linux/layerscape/patches-5.4/805-display-0040-drm-fourcc-add-modifier-for-vivante-compressed-tiled.patch
new file mode 100644 (file)
index 0000000..b4eae5c
--- /dev/null
@@ -0,0 +1,33 @@
+From 8894f4411bee347f7f392823805e77391dcaf305 Mon Sep 17 00:00:00 2001
+From: Fancy Fang <chen.fang@nxp.com>
+Date: Thu, 10 Oct 2019 17:06:15 +0300
+Subject: [PATCH] drm/fourcc: add modifier for vivante compressed tiled layout
+
+Add a new fb modifier for Vivante compressed and tiled
+pixle layout which can be decompressed by DEC400D module
+in DCSS.
+
+Signed-off-by: Fancy Fang <chen.fang@nxp.com>
+Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
+---
+ include/uapi/drm/drm_fourcc.h | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/include/uapi/drm/drm_fourcc.h
++++ b/include/uapi/drm/drm_fourcc.h
+@@ -489,6 +489,15 @@ extern "C" {
+  */
+ #define DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED fourcc_mod_code(VIVANTE, 4)
++      /*
++ * Vivante 64x64 super-tiling with compression layout
++ *
++ * This is a tiled layout using 64x64 pixel super-tiles, where each super-tile
++ * contains 8x4 groups of 2x4 tiles of 4x4 pixels each, all in row-major layout
++ * with compression.
++ */
++#define DRM_FORMAT_MOD_VIVANTE_SUPER_TILED_FC fourcc_mod_code(VIVANTE, 5)
++
+ /* NVIDIA frame buffer modifiers */
+ /*
diff --git a/target/linux/layerscape/patches-5.4/805-display-0041-drm-fourcc-add-a-10bits-fully-packed-variant-of-NV12.patch b/target/linux/layerscape/patches-5.4/805-display-0041-drm-fourcc-add-a-10bits-fully-packed-variant-of-NV12.patch
new file mode 100644 (file)
index 0000000..3bccbbd
--- /dev/null
@@ -0,0 +1,45 @@
+From 3ef66853a02133244bde79b165d8e5063def5ef4 Mon Sep 17 00:00:00 2001
+From: Randy Li <ayaka@soulik.info>
+Date: Thu, 10 Jan 2019 03:57:10 +0800
+Subject: [PATCH] drm/fourcc: add a 10bits fully packed variant of NV12
+
+This pixel format is a fully packed and 10bits variant of NV12.
+A luma pixel would take 10bits in memory, without any
+filled bits between pixels in a stride.
+
+Signed-off-by: Randy Li <ayaka@soulik.info>
+Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
+---
+ drivers/gpu/drm/drm_fourcc.c  | 3 +++
+ include/uapi/drm/drm_fourcc.h | 8 ++++++++
+ 2 files changed, 11 insertions(+)
+
+--- a/drivers/gpu/drm/drm_fourcc.c
++++ b/drivers/gpu/drm/drm_fourcc.c
+@@ -261,6 +261,9 @@ const struct drm_format_info *__drm_form
+               { .format = DRM_FORMAT_P016,            .depth = 0,  .num_planes = 2,
+                 .char_per_block = { 2, 4, 0 }, .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 },
+                 .hsub = 2, .vsub = 2, .is_yuv = true},
++              { .format = DRM_FORMAT_NV12_10LE40,     .depth = 0,  .num_planes = 2,
++                .char_per_block = { 5, 5, 0 }, .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 },
++                .hsub = 2, .vsub = 2, .is_yuv = true },
+               { .format = DRM_FORMAT_P210,            .depth = 0,
+                 .num_planes = 2, .char_per_block = { 2, 4, 0 },
+                 .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 }, .hsub = 2,
+--- a/include/uapi/drm/drm_fourcc.h
++++ b/include/uapi/drm/drm_fourcc.h
+@@ -236,6 +236,14 @@ extern "C" {
+ #define DRM_FORMAT_NV61               fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */
+ #define DRM_FORMAT_NV24               fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */
+ #define DRM_FORMAT_NV42               fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */
++/*
++ * A fully packed  2 plane YCbCr
++ * Y1 0-9, Y2 10-19, Y3 20-29, Y4 20-39
++ * ....
++ * U1V1: 0-19, U2V2: 20-39
++ */
++#define DRM_FORMAT_NV12_10LE40        fourcc_code('R', 'K', '2', '0') /* 2x2 subsampled Cr:Cb plane */
++
+ /*
+  * 2 plane YCbCr MSB aligned
diff --git a/target/linux/layerscape/patches-5.4/805-display-0042-drm-imx-Revert-a-patch-which-merges-imx-drm-core-and.patch b/target/linux/layerscape/patches-5.4/805-display-0042-drm-imx-Revert-a-patch-which-merges-imx-drm-core-and.patch
new file mode 100644 (file)
index 0000000..017f0e3
--- /dev/null
@@ -0,0 +1,116 @@
+From d27d7c25c946776c015a39f1a9eb0c6d4e724a70 Mon Sep 17 00:00:00 2001
+From: Liu Ying <victor.liu@nxp.com>
+Date: Fri, 25 Jan 2019 11:23:39 +0800
+Subject: [PATCH] drm/imx: Revert a patch which merges imx-drm-core and
+ ipuv3-crtc in one module
+
+DPU CRTC found in i.MX8qm/qxp SoCs can be hooked into imx-drm.
+Thus, move ipuv3-crtc out of imx-drm-core.
+
+Revert "drm/imx: merge imx-drm-core and ipuv3-crtc in one module"
+
+This reverts commit 3d1df96ad46856ce850be5ac112eab919cbe1cab.
+
+Signed-off-by: Liu Ying <victor.liu@nxp.com>
+[ Aisheng: fix conflicts ]
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ drivers/gpu/drm/imx/Kconfig        |  7 +++++++
+ drivers/gpu/drm/imx/Makefile       |  4 +++-
+ drivers/gpu/drm/imx/imx-drm-core.c | 18 +-----------------
+ drivers/gpu/drm/imx/imx-drm.h      |  2 --
+ drivers/gpu/drm/imx/ipuv3-crtc.c   |  8 +++++++-
+ 5 files changed, 18 insertions(+), 21 deletions(-)
+
+--- a/drivers/gpu/drm/imx/Kconfig
++++ b/drivers/gpu/drm/imx/Kconfig
+@@ -33,6 +33,13 @@ config DRM_IMX_LDB
+         Choose this to enable the internal LVDS Display Bridge (LDB)
+         found on i.MX53 and i.MX6 processors.
++config DRM_IMX_IPUV3
++      tristate
++      depends on DRM_IMX
++      depends on IMX_IPUV3_CORE
++      default y if DRM_IMX=y
++      default m if DRM_IMX=m
++
+ config DRM_IMX_HDMI
+       tristate "Freescale i.MX DRM HDMI"
+       select DRM_DW_HDMI
+--- a/drivers/gpu/drm/imx/Makefile
++++ b/drivers/gpu/drm/imx/Makefile
+@@ -1,6 +1,6 @@
+ # SPDX-License-Identifier: GPL-2.0
+-imxdrm-objs := imx-drm-core.o ipuv3-crtc.o ipuv3-plane.o
++imxdrm-objs := imx-drm-core.o
+ obj-$(CONFIG_DRM_IMX) += imxdrm.o
+@@ -8,5 +8,7 @@ obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) +
+ obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
+ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
++imx-ipuv3-crtc-objs  := ipuv3-crtc.o ipuv3-plane.o
++obj-$(CONFIG_DRM_IMX_IPUV3)   += imx-ipuv3-crtc.o
+ obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
+ obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdn-mhdp-imxdrv.o cdn-mhdp-dp-phy.o cdn-mhdp-hdmi-phy.o cdn-mhdp-imx8qm.o cdn-mhdp-ls1028a.o
+--- a/drivers/gpu/drm/imx/imx-drm-core.c
++++ b/drivers/gpu/drm/imx/imx-drm-core.c
+@@ -343,23 +343,7 @@ static struct platform_driver imx_drm_pd
+               .of_match_table = imx_drm_dt_ids,
+       },
+ };
+-
+-static struct platform_driver * const drivers[] = {
+-      &imx_drm_pdrv,
+-      &ipu_drm_driver,
+-};
+-
+-static int __init imx_drm_init(void)
+-{
+-      return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
+-}
+-module_init(imx_drm_init);
+-
+-static void __exit imx_drm_exit(void)
+-{
+-      platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
+-}
+-module_exit(imx_drm_exit);
++module_platform_driver(imx_drm_pdrv);
+ MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+ MODULE_DESCRIPTION("i.MX drm driver core");
+--- a/drivers/gpu/drm/imx/imx-drm.h
++++ b/drivers/gpu/drm/imx/imx-drm.h
+@@ -28,8 +28,6 @@ int imx_drm_init_drm(struct platform_dev
+               int preferred_bpp);
+ int imx_drm_exit_drm(void);
+-extern struct platform_driver ipu_drm_driver;
+-
+ void imx_drm_mode_config_init(struct drm_device *drm);
+ struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
+--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
++++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
+@@ -492,10 +492,16 @@ static int ipu_drm_remove(struct platfor
+       return 0;
+ }
+-struct platform_driver ipu_drm_driver = {
++static struct platform_driver ipu_drm_driver = {
+       .driver = {
+               .name = "imx-ipuv3-crtc",
+       },
+       .probe = ipu_drm_probe,
+       .remove = ipu_drm_remove,
+ };
++module_platform_driver(ipu_drm_driver);
++
++MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:imx-ipuv3-crtc");
diff --git a/target/linux/layerscape/patches-5.4/805-display-0043-gpu-Move-ipu-v3-to-imx-folder.patch b/target/linux/layerscape/patches-5.4/805-display-0043-gpu-Move-ipu-v3-to-imx-folder.patch
new file mode 100644 (file)
index 0000000..6deb30f
--- /dev/null
@@ -0,0 +1,19995 @@
+From a7782c6e5e37b2b406221827b177c2bfcc8825cd Mon Sep 17 00:00:00 2001
+From: Liu Ying <victor.liu@nxp.com>
+Date: Tue, 22 Jan 2019 17:08:01 +0800
+Subject: [PATCH] gpu: Move ipu-v3 to imx folder
+
+The new imx folder may contain ipu-v3 and dpu common drivers.
+
+Signed-off-by: Liu Ying <victor.liu@nxp.com>
+[ Aisheng: fix source path ]
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ drivers/gpu/Makefile                       |    2 +-
+ drivers/gpu/imx/Kconfig                    |    1 +
+ drivers/gpu/imx/Makefile                   |    1 +
+ drivers/gpu/imx/ipu-v3/Kconfig             |   11 +
+ drivers/gpu/imx/ipu-v3/Makefile            |   10 +
+ drivers/gpu/imx/ipu-v3/ipu-common.c        | 1565 ++++++++++++++++++
+ drivers/gpu/imx/ipu-v3/ipu-cpmem.c         |  976 +++++++++++
+ drivers/gpu/imx/ipu-v3/ipu-csi.c           |  821 +++++++++
+ drivers/gpu/imx/ipu-v3/ipu-dc.c            |  420 +++++
+ drivers/gpu/imx/ipu-v3/ipu-di.c            |  745 +++++++++
+ drivers/gpu/imx/ipu-v3/ipu-dmfc.c          |  214 +++
+ drivers/gpu/imx/ipu-v3/ipu-dp.c            |  357 ++++
+ drivers/gpu/imx/ipu-v3/ipu-ic.c            |  761 +++++++++
+ drivers/gpu/imx/ipu-v3/ipu-image-convert.c | 2475 ++++++++++++++++++++++++++++
+ drivers/gpu/imx/ipu-v3/ipu-pre.c           |  346 ++++
+ drivers/gpu/imx/ipu-v3/ipu-prg.c           |  483 ++++++
+ drivers/gpu/imx/ipu-v3/ipu-prv.h           |  274 +++
+ drivers/gpu/imx/ipu-v3/ipu-smfc.c          |  202 +++
+ drivers/gpu/imx/ipu-v3/ipu-vdi.c           |  234 +++
+ drivers/gpu/ipu-v3/Kconfig                 |   11 -
+ drivers/gpu/ipu-v3/Makefile                |   10 -
+ drivers/gpu/ipu-v3/ipu-common.c            | 1565 ------------------
+ drivers/gpu/ipu-v3/ipu-cpmem.c             |  976 -----------
+ drivers/gpu/ipu-v3/ipu-csi.c               |  821 ---------
+ drivers/gpu/ipu-v3/ipu-dc.c                |  420 -----
+ drivers/gpu/ipu-v3/ipu-di.c                |  745 ---------
+ drivers/gpu/ipu-v3/ipu-dmfc.c              |  214 ---
+ drivers/gpu/ipu-v3/ipu-dp.c                |  357 ----
+ drivers/gpu/ipu-v3/ipu-ic.c                |  761 ---------
+ drivers/gpu/ipu-v3/ipu-image-convert.c     | 2475 ----------------------------
+ drivers/gpu/ipu-v3/ipu-pre.c               |  346 ----
+ drivers/gpu/ipu-v3/ipu-prg.c               |  483 ------
+ drivers/gpu/ipu-v3/ipu-prv.h               |  274 ---
+ drivers/gpu/ipu-v3/ipu-smfc.c              |  202 ---
+ drivers/gpu/ipu-v3/ipu-vdi.c               |  234 ---
+ drivers/video/Kconfig                      |    2 +-
+ 36 files changed, 9898 insertions(+), 9896 deletions(-)
+ create mode 100644 drivers/gpu/imx/Kconfig
+ create mode 100644 drivers/gpu/imx/Makefile
+ create mode 100644 drivers/gpu/imx/ipu-v3/Kconfig
+ create mode 100644 drivers/gpu/imx/ipu-v3/Makefile
+ create mode 100644 drivers/gpu/imx/ipu-v3/ipu-common.c
+ create mode 100644 drivers/gpu/imx/ipu-v3/ipu-cpmem.c
+ create mode 100644 drivers/gpu/imx/ipu-v3/ipu-csi.c
+ create mode 100644 drivers/gpu/imx/ipu-v3/ipu-dc.c
+ create mode 100644 drivers/gpu/imx/ipu-v3/ipu-di.c
+ create mode 100644 drivers/gpu/imx/ipu-v3/ipu-dmfc.c
+ create mode 100644 drivers/gpu/imx/ipu-v3/ipu-dp.c
+ create mode 100644 drivers/gpu/imx/ipu-v3/ipu-ic.c
+ create mode 100644 drivers/gpu/imx/ipu-v3/ipu-image-convert.c
+ create mode 100644 drivers/gpu/imx/ipu-v3/ipu-pre.c
+ create mode 100644 drivers/gpu/imx/ipu-v3/ipu-prg.c
+ create mode 100644 drivers/gpu/imx/ipu-v3/ipu-prv.h
+ create mode 100644 drivers/gpu/imx/ipu-v3/ipu-smfc.c
+ create mode 100644 drivers/gpu/imx/ipu-v3/ipu-vdi.c
+ delete mode 100644 drivers/gpu/ipu-v3/Kconfig
+ delete mode 100644 drivers/gpu/ipu-v3/Makefile
+ delete mode 100644 drivers/gpu/ipu-v3/ipu-common.c
+ delete mode 100644 drivers/gpu/ipu-v3/ipu-cpmem.c
+ delete mode 100644 drivers/gpu/ipu-v3/ipu-csi.c
+ delete mode 100644 drivers/gpu/ipu-v3/ipu-dc.c
+ delete mode 100644 drivers/gpu/ipu-v3/ipu-di.c
+ delete mode 100644 drivers/gpu/ipu-v3/ipu-dmfc.c
+ delete mode 100644 drivers/gpu/ipu-v3/ipu-dp.c
+ delete mode 100644 drivers/gpu/ipu-v3/ipu-ic.c
+ delete mode 100644 drivers/gpu/ipu-v3/ipu-image-convert.c
+ delete mode 100644 drivers/gpu/ipu-v3/ipu-pre.c
+ delete mode 100644 drivers/gpu/ipu-v3/ipu-prg.c
+ delete mode 100644 drivers/gpu/ipu-v3/ipu-prv.h
+ delete mode 100644 drivers/gpu/ipu-v3/ipu-smfc.c
+ delete mode 100644 drivers/gpu/ipu-v3/ipu-vdi.c
+
+--- a/drivers/gpu/Makefile
++++ b/drivers/gpu/Makefile
+@@ -3,5 +3,5 @@
+ # taken to initialize them in the correct order. Link order is the only way
+ # to ensure this currently.
+ obj-$(CONFIG_TEGRA_HOST1X)    += host1x/
++obj-y                 += imx/
+ obj-y                 += drm/ vga/
+-obj-$(CONFIG_IMX_IPUV3_CORE)  += ipu-v3/
+--- /dev/null
++++ b/drivers/gpu/imx/Kconfig
+@@ -0,0 +1 @@
++source "drivers/gpu/imx/ipu-v3/Kconfig"
+--- /dev/null
++++ b/drivers/gpu/imx/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_IMX_IPUV3_CORE)  += ipu-v3/
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/Kconfig
+@@ -0,0 +1,11 @@
++# SPDX-License-Identifier: GPL-2.0-only
++config IMX_IPUV3_CORE
++      tristate "IPUv3 core support"
++      depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM || COMPILE_TEST
++      depends on DRM || !DRM # if DRM=m, this can't be 'y'
++      select BITREVERSE
++      select GENERIC_ALLOCATOR if DRM
++      select GENERIC_IRQ_CHIP
++      help
++        Choose this if you have a i.MX5/6 system and want to use the Image
++        Processing Unit. This option only enables IPU base support.
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/Makefile
+@@ -0,0 +1,10 @@
++# SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
++
++imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
++              ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-ic-csc.o \
++              ipu-image-convert.o ipu-smfc.o ipu-vdi.o
++
++ifdef CONFIG_DRM
++      imx-ipu-v3-objs += ipu-pre.o ipu-prg.o
++endif
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/ipu-common.c
+@@ -0,0 +1,1565 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++#include <linux/module.h>
++#include <linux/export.h>
++#include <linux/types.h>
++#include <linux/reset.h>
++#include <linux/platform_device.h>
++#include <linux/err.h>
++#include <linux/spinlock.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/clk.h>
++#include <linux/list.h>
++#include <linux/irq.h>
++#include <linux/irqchip/chained_irq.h>
++#include <linux/irqdomain.h>
++#include <linux/of_device.h>
++#include <linux/of_graph.h>
++
++#include <drm/drm_fourcc.h>
++
++#include <video/imx-ipu-v3.h>
++#include "ipu-prv.h"
++
++static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
++{
++      return readl(ipu->cm_reg + offset);
++}
++
++static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
++{
++      writel(value, ipu->cm_reg + offset);
++}
++
++int ipu_get_num(struct ipu_soc *ipu)
++{
++      return ipu->id;
++}
++EXPORT_SYMBOL_GPL(ipu_get_num);
++
++void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync)
++{
++      u32 val;
++
++      val = ipu_cm_read(ipu, IPU_SRM_PRI2);
++      val &= ~DP_S_SRM_MODE_MASK;
++      val |= sync ? DP_S_SRM_MODE_NEXT_FRAME :
++                    DP_S_SRM_MODE_NOW;
++      ipu_cm_write(ipu, val, IPU_SRM_PRI2);
++}
++EXPORT_SYMBOL_GPL(ipu_srm_dp_update);
++
++enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
++{
++      switch (drm_fourcc) {
++      case DRM_FORMAT_ARGB1555:
++      case DRM_FORMAT_ABGR1555:
++      case DRM_FORMAT_RGBA5551:
++      case DRM_FORMAT_BGRA5551:
++      case DRM_FORMAT_RGB565:
++      case DRM_FORMAT_BGR565:
++      case DRM_FORMAT_RGB888:
++      case DRM_FORMAT_BGR888:
++      case DRM_FORMAT_ARGB4444:
++      case DRM_FORMAT_XRGB8888:
++      case DRM_FORMAT_XBGR8888:
++      case DRM_FORMAT_RGBX8888:
++      case DRM_FORMAT_BGRX8888:
++      case DRM_FORMAT_ARGB8888:
++      case DRM_FORMAT_ABGR8888:
++      case DRM_FORMAT_RGBA8888:
++      case DRM_FORMAT_BGRA8888:
++      case DRM_FORMAT_RGB565_A8:
++      case DRM_FORMAT_BGR565_A8:
++      case DRM_FORMAT_RGB888_A8:
++      case DRM_FORMAT_BGR888_A8:
++      case DRM_FORMAT_RGBX8888_A8:
++      case DRM_FORMAT_BGRX8888_A8:
++              return IPUV3_COLORSPACE_RGB;
++      case DRM_FORMAT_YUYV:
++      case DRM_FORMAT_UYVY:
++      case DRM_FORMAT_YUV420:
++      case DRM_FORMAT_YVU420:
++      case DRM_FORMAT_YUV422:
++      case DRM_FORMAT_YVU422:
++      case DRM_FORMAT_YUV444:
++      case DRM_FORMAT_YVU444:
++      case DRM_FORMAT_NV12:
++      case DRM_FORMAT_NV21:
++      case DRM_FORMAT_NV16:
++      case DRM_FORMAT_NV61:
++              return IPUV3_COLORSPACE_YUV;
++      default:
++              return IPUV3_COLORSPACE_UNKNOWN;
++      }
++}
++EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace);
++
++enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
++{
++      switch (pixelformat) {
++      case V4L2_PIX_FMT_YUV420:
++      case V4L2_PIX_FMT_YVU420:
++      case V4L2_PIX_FMT_YUV422P:
++      case V4L2_PIX_FMT_UYVY:
++      case V4L2_PIX_FMT_YUYV:
++      case V4L2_PIX_FMT_NV12:
++      case V4L2_PIX_FMT_NV21:
++      case V4L2_PIX_FMT_NV16:
++      case V4L2_PIX_FMT_NV61:
++              return IPUV3_COLORSPACE_YUV;
++      case V4L2_PIX_FMT_RGB565:
++      case V4L2_PIX_FMT_BGR24:
++      case V4L2_PIX_FMT_RGB24:
++      case V4L2_PIX_FMT_ABGR32:
++      case V4L2_PIX_FMT_XBGR32:
++      case V4L2_PIX_FMT_BGRA32:
++      case V4L2_PIX_FMT_BGRX32:
++      case V4L2_PIX_FMT_RGBA32:
++      case V4L2_PIX_FMT_RGBX32:
++      case V4L2_PIX_FMT_ARGB32:
++      case V4L2_PIX_FMT_XRGB32:
++              return IPUV3_COLORSPACE_RGB;
++      default:
++              return IPUV3_COLORSPACE_UNKNOWN;
++      }
++}
++EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
++
++bool ipu_pixelformat_is_planar(u32 pixelformat)
++{
++      switch (pixelformat) {
++      case V4L2_PIX_FMT_YUV420:
++      case V4L2_PIX_FMT_YVU420:
++      case V4L2_PIX_FMT_YUV422P:
++      case V4L2_PIX_FMT_NV12:
++      case V4L2_PIX_FMT_NV21:
++      case V4L2_PIX_FMT_NV16:
++      case V4L2_PIX_FMT_NV61:
++              return true;
++      }
++
++      return false;
++}
++EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar);
++
++enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
++{
++      switch (mbus_code & 0xf000) {
++      case 0x1000:
++              return IPUV3_COLORSPACE_RGB;
++      case 0x2000:
++              return IPUV3_COLORSPACE_YUV;
++      default:
++              return IPUV3_COLORSPACE_UNKNOWN;
++      }
++}
++EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
++
++int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat)
++{
++      switch (pixelformat) {
++      case V4L2_PIX_FMT_YUV420:
++      case V4L2_PIX_FMT_YVU420:
++      case V4L2_PIX_FMT_YUV422P:
++      case V4L2_PIX_FMT_NV12:
++      case V4L2_PIX_FMT_NV21:
++      case V4L2_PIX_FMT_NV16:
++      case V4L2_PIX_FMT_NV61:
++              /*
++               * for the planar YUV formats, the stride passed to
++               * cpmem must be the stride in bytes of the Y plane.
++               * And all the planar YUV formats have an 8-bit
++               * Y component.
++               */
++              return (8 * pixel_stride) >> 3;
++      case V4L2_PIX_FMT_RGB565:
++      case V4L2_PIX_FMT_YUYV:
++      case V4L2_PIX_FMT_UYVY:
++              return (16 * pixel_stride) >> 3;
++      case V4L2_PIX_FMT_BGR24:
++      case V4L2_PIX_FMT_RGB24:
++              return (24 * pixel_stride) >> 3;
++      case V4L2_PIX_FMT_BGR32:
++      case V4L2_PIX_FMT_RGB32:
++      case V4L2_PIX_FMT_XBGR32:
++      case V4L2_PIX_FMT_XRGB32:
++              return (32 * pixel_stride) >> 3;
++      default:
++              break;
++      }
++
++      return -EINVAL;
++}
++EXPORT_SYMBOL_GPL(ipu_stride_to_bytes);
++
++int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
++                          bool hflip, bool vflip)
++{
++      u32 r90, vf, hf;
++
++      switch (degrees) {
++      case 0:
++              vf = hf = r90 = 0;
++              break;
++      case 90:
++              vf = hf = 0;
++              r90 = 1;
++              break;
++      case 180:
++              vf = hf = 1;
++              r90 = 0;
++              break;
++      case 270:
++              vf = hf = r90 = 1;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      hf ^= (u32)hflip;
++      vf ^= (u32)vflip;
++
++      *mode = (enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf);
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode);
++
++int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
++                          bool hflip, bool vflip)
++{
++      u32 r90, vf, hf;
++
++      r90 = ((u32)mode >> 2) & 0x1;
++      hf = ((u32)mode >> 1) & 0x1;
++      vf = ((u32)mode >> 0) & 0x1;
++      hf ^= (u32)hflip;
++      vf ^= (u32)vflip;
++
++      switch ((enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf)) {
++      case IPU_ROTATE_NONE:
++              *degrees = 0;
++              break;
++      case IPU_ROTATE_90_RIGHT:
++              *degrees = 90;
++              break;
++      case IPU_ROTATE_180:
++              *degrees = 180;
++              break;
++      case IPU_ROTATE_90_LEFT:
++              *degrees = 270;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees);
++
++struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
++{
++      struct ipuv3_channel *channel;
++
++      dev_dbg(ipu->dev, "%s %d\n", __func__, num);
++
++      if (num > 63)
++              return ERR_PTR(-ENODEV);
++
++      mutex_lock(&ipu->channel_lock);
++
++      list_for_each_entry(channel, &ipu->channels, list) {
++              if (channel->num == num) {
++                      channel = ERR_PTR(-EBUSY);
++                      goto out;
++              }
++      }
++
++      channel = kzalloc(sizeof(*channel), GFP_KERNEL);
++      if (!channel) {
++              channel = ERR_PTR(-ENOMEM);
++              goto out;
++      }
++
++      channel->num = num;
++      channel->ipu = ipu;
++      list_add(&channel->list, &ipu->channels);
++
++out:
++      mutex_unlock(&ipu->channel_lock);
++
++      return channel;
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_get);
++
++void ipu_idmac_put(struct ipuv3_channel *channel)
++{
++      struct ipu_soc *ipu = channel->ipu;
++
++      dev_dbg(ipu->dev, "%s %d\n", __func__, channel->num);
++
++      mutex_lock(&ipu->channel_lock);
++
++      list_del(&channel->list);
++      kfree(channel);
++
++      mutex_unlock(&ipu->channel_lock);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_put);
++
++#define idma_mask(ch)                 (1 << ((ch) & 0x1f))
++
++/*
++ * This is an undocumented feature, a write one to a channel bit in
++ * IPU_CHA_CUR_BUF and IPU_CHA_TRIPLE_CUR_BUF will reset the channel's
++ * internal current buffer pointer so that transfers start from buffer
++ * 0 on the next channel enable (that's the theory anyway, the imx6 TRM
++ * only says these are read-only registers). This operation is required
++ * for channel linking to work correctly, for instance video capture
++ * pipelines that carry out image rotations will fail after the first
++ * streaming unless this function is called for each channel before
++ * re-enabling the channels.
++ */
++static void __ipu_idmac_reset_current_buffer(struct ipuv3_channel *channel)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned int chno = channel->num;
++
++      ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_CUR_BUF(chno));
++}
++
++void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
++              bool doublebuffer)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned long flags;
++      u32 reg;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
++      if (doublebuffer)
++              reg |= idma_mask(channel->num);
++      else
++              reg &= ~idma_mask(channel->num);
++      ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
++
++      __ipu_idmac_reset_current_buffer(channel);
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
++
++static const struct {
++      int chnum;
++      u32 reg;
++      int shift;
++} idmac_lock_en_info[] = {
++      { .chnum =  5, .reg = IDMAC_CH_LOCK_EN_1, .shift =  0, },
++      { .chnum = 11, .reg = IDMAC_CH_LOCK_EN_1, .shift =  2, },
++      { .chnum = 12, .reg = IDMAC_CH_LOCK_EN_1, .shift =  4, },
++      { .chnum = 14, .reg = IDMAC_CH_LOCK_EN_1, .shift =  6, },
++      { .chnum = 15, .reg = IDMAC_CH_LOCK_EN_1, .shift =  8, },
++      { .chnum = 20, .reg = IDMAC_CH_LOCK_EN_1, .shift = 10, },
++      { .chnum = 21, .reg = IDMAC_CH_LOCK_EN_1, .shift = 12, },
++      { .chnum = 22, .reg = IDMAC_CH_LOCK_EN_1, .shift = 14, },
++      { .chnum = 23, .reg = IDMAC_CH_LOCK_EN_1, .shift = 16, },
++      { .chnum = 27, .reg = IDMAC_CH_LOCK_EN_1, .shift = 18, },
++      { .chnum = 28, .reg = IDMAC_CH_LOCK_EN_1, .shift = 20, },
++      { .chnum = 45, .reg = IDMAC_CH_LOCK_EN_2, .shift =  0, },
++      { .chnum = 46, .reg = IDMAC_CH_LOCK_EN_2, .shift =  2, },
++      { .chnum = 47, .reg = IDMAC_CH_LOCK_EN_2, .shift =  4, },
++      { .chnum = 48, .reg = IDMAC_CH_LOCK_EN_2, .shift =  6, },
++      { .chnum = 49, .reg = IDMAC_CH_LOCK_EN_2, .shift =  8, },
++      { .chnum = 50, .reg = IDMAC_CH_LOCK_EN_2, .shift = 10, },
++};
++
++int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned long flags;
++      u32 bursts, regval;
++      int i;
++
++      switch (num_bursts) {
++      case 0:
++      case 1:
++              bursts = 0x00; /* locking disabled */
++              break;
++      case 2:
++              bursts = 0x01;
++              break;
++      case 4:
++              bursts = 0x02;
++              break;
++      case 8:
++              bursts = 0x03;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      /*
++       * IPUv3EX / i.MX51 has a different register layout, and on IPUv3M /
++       * i.MX53 channel arbitration locking doesn't seem to work properly.
++       * Allow enabling the lock feature on IPUv3H / i.MX6 only.
++       */
++      if (bursts && ipu->ipu_type != IPUV3H)
++              return -EINVAL;
++
++      for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) {
++              if (channel->num == idmac_lock_en_info[i].chnum)
++                      break;
++      }
++      if (i >= ARRAY_SIZE(idmac_lock_en_info))
++              return -EINVAL;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      regval = ipu_idmac_read(ipu, idmac_lock_en_info[i].reg);
++      regval &= ~(0x03 << idmac_lock_en_info[i].shift);
++      regval |= (bursts << idmac_lock_en_info[i].shift);
++      ipu_idmac_write(ipu, regval, idmac_lock_en_info[i].reg);
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_lock_enable);
++
++int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
++{
++      unsigned long lock_flags;
++      u32 val;
++
++      spin_lock_irqsave(&ipu->lock, lock_flags);
++
++      val = ipu_cm_read(ipu, IPU_DISP_GEN);
++
++      if (mask & IPU_CONF_DI0_EN)
++              val |= IPU_DI0_COUNTER_RELEASE;
++      if (mask & IPU_CONF_DI1_EN)
++              val |= IPU_DI1_COUNTER_RELEASE;
++
++      ipu_cm_write(ipu, val, IPU_DISP_GEN);
++
++      val = ipu_cm_read(ipu, IPU_CONF);
++      val |= mask;
++      ipu_cm_write(ipu, val, IPU_CONF);
++
++      spin_unlock_irqrestore(&ipu->lock, lock_flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_module_enable);
++
++int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
++{
++      unsigned long lock_flags;
++      u32 val;
++
++      spin_lock_irqsave(&ipu->lock, lock_flags);
++
++      val = ipu_cm_read(ipu, IPU_CONF);
++      val &= ~mask;
++      ipu_cm_write(ipu, val, IPU_CONF);
++
++      val = ipu_cm_read(ipu, IPU_DISP_GEN);
++
++      if (mask & IPU_CONF_DI0_EN)
++              val &= ~IPU_DI0_COUNTER_RELEASE;
++      if (mask & IPU_CONF_DI1_EN)
++              val &= ~IPU_DI1_COUNTER_RELEASE;
++
++      ipu_cm_write(ipu, val, IPU_DISP_GEN);
++
++      spin_unlock_irqrestore(&ipu->lock, lock_flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_module_disable);
++
++int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned int chno = channel->num;
++
++      return (ipu_cm_read(ipu, IPU_CHA_CUR_BUF(chno)) & idma_mask(chno)) ? 1 : 0;
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer);
++
++bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned long flags;
++      u32 reg = 0;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++      switch (buf_num) {
++      case 0:
++              reg = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num));
++              break;
++      case 1:
++              reg = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num));
++              break;
++      case 2:
++              reg = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(channel->num));
++              break;
++      }
++      spin_unlock_irqrestore(&ipu->lock, flags);
++
++      return ((reg & idma_mask(channel->num)) != 0);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_buffer_is_ready);
++
++void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned int chno = channel->num;
++      unsigned long flags;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      /* Mark buffer as ready. */
++      if (buf_num == 0)
++              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
++      else
++              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
++
++void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned int chno = channel->num;
++      unsigned long flags;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */
++      switch (buf_num) {
++      case 0:
++              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
++              break;
++      case 1:
++              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
++              break;
++      case 2:
++              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF2_RDY(chno));
++              break;
++      default:
++              break;
++      }
++      ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer);
++
++int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      u32 val;
++      unsigned long flags;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
++      val |= idma_mask(channel->num);
++      ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
++
++bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno)
++{
++      return (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(chno)) & idma_mask(chno));
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_channel_busy);
++
++int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned long timeout;
++
++      timeout = jiffies + msecs_to_jiffies(ms);
++      while (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(channel->num)) &
++                      idma_mask(channel->num)) {
++              if (time_after(jiffies, timeout))
++                      return -ETIMEDOUT;
++              cpu_relax();
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy);
++
++int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      u32 val;
++      unsigned long flags;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      /* Disable DMA channel(s) */
++      val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
++      val &= ~idma_mask(channel->num);
++      ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
++
++      __ipu_idmac_reset_current_buffer(channel);
++
++      /* Set channel buffers NOT to be ready */
++      ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
++
++      if (ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num)) &
++                      idma_mask(channel->num)) {
++              ipu_cm_write(ipu, idma_mask(channel->num),
++                           IPU_CHA_BUF0_RDY(channel->num));
++      }
++
++      if (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num)) &
++                      idma_mask(channel->num)) {
++              ipu_cm_write(ipu, idma_mask(channel->num),
++                           IPU_CHA_BUF1_RDY(channel->num));
++      }
++
++      ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
++
++      /* Reset the double buffer */
++      val = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
++      val &= ~idma_mask(channel->num);
++      ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num));
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
++
++/*
++ * The imx6 rev. D TRM says that enabling the WM feature will increase
++ * a channel's priority. Refer to Table 36-8 Calculated priority value.
++ * The sub-module that is the sink or source for the channel must enable
++ * watermark signal for this to take effect (SMFC_WM for instance).
++ */
++void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned long flags;
++      u32 val;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      val = ipu_idmac_read(ipu, IDMAC_WM_EN(channel->num));
++      if (enable)
++              val |= 1 << (channel->num % 32);
++      else
++              val &= ~(1 << (channel->num % 32));
++      ipu_idmac_write(ipu, val, IDMAC_WM_EN(channel->num));
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_enable_watermark);
++
++static int ipu_memory_reset(struct ipu_soc *ipu)
++{
++      unsigned long timeout;
++
++      ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST);
++
++      timeout = jiffies + msecs_to_jiffies(1000);
++      while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) {
++              if (time_after(jiffies, timeout))
++                      return -ETIME;
++              cpu_relax();
++      }
++
++      return 0;
++}
++
++/*
++ * Set the source mux for the given CSI. Selects either parallel or
++ * MIPI CSI2 sources.
++ */
++void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2)
++{
++      unsigned long flags;
++      u32 val, mask;
++
++      mask = (csi_id == 1) ? IPU_CONF_CSI1_DATA_SOURCE :
++              IPU_CONF_CSI0_DATA_SOURCE;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      val = ipu_cm_read(ipu, IPU_CONF);
++      if (mipi_csi2)
++              val |= mask;
++      else
++              val &= ~mask;
++      ipu_cm_write(ipu, val, IPU_CONF);
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_set_csi_src_mux);
++
++/*
++ * Set the source mux for the IC. Selects either CSI[01] or the VDI.
++ */
++void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi)
++{
++      unsigned long flags;
++      u32 val;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      val = ipu_cm_read(ipu, IPU_CONF);
++      if (vdi)
++              val |= IPU_CONF_IC_INPUT;
++      else
++              val &= ~IPU_CONF_IC_INPUT;
++
++      if (csi_id == 1)
++              val |= IPU_CONF_CSI_SEL;
++      else
++              val &= ~IPU_CONF_CSI_SEL;
++
++      ipu_cm_write(ipu, val, IPU_CONF);
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux);
++
++
++/* Frame Synchronization Unit Channel Linking */
++
++struct fsu_link_reg_info {
++      int chno;
++      u32 reg;
++      u32 mask;
++      u32 val;
++};
++
++struct fsu_link_info {
++      struct fsu_link_reg_info src;
++      struct fsu_link_reg_info sink;
++};
++
++static const struct fsu_link_info fsu_link_info[] = {
++      {
++              .src  = { IPUV3_CHANNEL_IC_PRP_ENC_MEM, IPU_FS_PROC_FLOW2,
++                        FS_PRP_ENC_DEST_SEL_MASK, FS_PRP_ENC_DEST_SEL_IRT_ENC },
++              .sink = { IPUV3_CHANNEL_MEM_ROT_ENC, IPU_FS_PROC_FLOW1,
++                        FS_PRPENC_ROT_SRC_SEL_MASK, FS_PRPENC_ROT_SRC_SEL_ENC },
++      }, {
++              .src =  { IPUV3_CHANNEL_IC_PRP_VF_MEM, IPU_FS_PROC_FLOW2,
++                        FS_PRPVF_DEST_SEL_MASK, FS_PRPVF_DEST_SEL_IRT_VF },
++              .sink = { IPUV3_CHANNEL_MEM_ROT_VF, IPU_FS_PROC_FLOW1,
++                        FS_PRPVF_ROT_SRC_SEL_MASK, FS_PRPVF_ROT_SRC_SEL_VF },
++      }, {
++              .src =  { IPUV3_CHANNEL_IC_PP_MEM, IPU_FS_PROC_FLOW2,
++                        FS_PP_DEST_SEL_MASK, FS_PP_DEST_SEL_IRT_PP },
++              .sink = { IPUV3_CHANNEL_MEM_ROT_PP, IPU_FS_PROC_FLOW1,
++                        FS_PP_ROT_SRC_SEL_MASK, FS_PP_ROT_SRC_SEL_PP },
++      }, {
++              .src =  { IPUV3_CHANNEL_CSI_DIRECT, 0 },
++              .sink = { IPUV3_CHANNEL_CSI_VDI_PREV, IPU_FS_PROC_FLOW1,
++                        FS_VDI_SRC_SEL_MASK, FS_VDI_SRC_SEL_CSI_DIRECT },
++      },
++};
++
++static const struct fsu_link_info *find_fsu_link_info(int src, int sink)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(fsu_link_info); i++) {
++              if (src == fsu_link_info[i].src.chno &&
++                  sink == fsu_link_info[i].sink.chno)
++                      return &fsu_link_info[i];
++      }
++
++      return NULL;
++}
++
++/*
++ * Links a source channel to a sink channel in the FSU.
++ */
++int ipu_fsu_link(struct ipu_soc *ipu, int src_ch, int sink_ch)
++{
++      const struct fsu_link_info *link;
++      u32 src_reg, sink_reg;
++      unsigned long flags;
++
++      link = find_fsu_link_info(src_ch, sink_ch);
++      if (!link)
++              return -EINVAL;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      if (link->src.mask) {
++              src_reg = ipu_cm_read(ipu, link->src.reg);
++              src_reg &= ~link->src.mask;
++              src_reg |= link->src.val;
++              ipu_cm_write(ipu, src_reg, link->src.reg);
++      }
++
++      if (link->sink.mask) {
++              sink_reg = ipu_cm_read(ipu, link->sink.reg);
++              sink_reg &= ~link->sink.mask;
++              sink_reg |= link->sink.val;
++              ipu_cm_write(ipu, sink_reg, link->sink.reg);
++      }
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_fsu_link);
++
++/*
++ * Unlinks source and sink channels in the FSU.
++ */
++int ipu_fsu_unlink(struct ipu_soc *ipu, int src_ch, int sink_ch)
++{
++      const struct fsu_link_info *link;
++      u32 src_reg, sink_reg;
++      unsigned long flags;
++
++      link = find_fsu_link_info(src_ch, sink_ch);
++      if (!link)
++              return -EINVAL;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      if (link->src.mask) {
++              src_reg = ipu_cm_read(ipu, link->src.reg);
++              src_reg &= ~link->src.mask;
++              ipu_cm_write(ipu, src_reg, link->src.reg);
++      }
++
++      if (link->sink.mask) {
++              sink_reg = ipu_cm_read(ipu, link->sink.reg);
++              sink_reg &= ~link->sink.mask;
++              ipu_cm_write(ipu, sink_reg, link->sink.reg);
++      }
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_fsu_unlink);
++
++/* Link IDMAC channels in the FSU */
++int ipu_idmac_link(struct ipuv3_channel *src, struct ipuv3_channel *sink)
++{
++      return ipu_fsu_link(src->ipu, src->num, sink->num);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_link);
++
++/* Unlink IDMAC channels in the FSU */
++int ipu_idmac_unlink(struct ipuv3_channel *src, struct ipuv3_channel *sink)
++{
++      return ipu_fsu_unlink(src->ipu, src->num, sink->num);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_unlink);
++
++struct ipu_devtype {
++      const char *name;
++      unsigned long cm_ofs;
++      unsigned long cpmem_ofs;
++      unsigned long srm_ofs;
++      unsigned long tpm_ofs;
++      unsigned long csi0_ofs;
++      unsigned long csi1_ofs;
++      unsigned long ic_ofs;
++      unsigned long disp0_ofs;
++      unsigned long disp1_ofs;
++      unsigned long dc_tmpl_ofs;
++      unsigned long vdi_ofs;
++      enum ipuv3_type type;
++};
++
++static struct ipu_devtype ipu_type_imx51 = {
++      .name = "IPUv3EX",
++      .cm_ofs = 0x1e000000,
++      .cpmem_ofs = 0x1f000000,
++      .srm_ofs = 0x1f040000,
++      .tpm_ofs = 0x1f060000,
++      .csi0_ofs = 0x1e030000,
++      .csi1_ofs = 0x1e038000,
++      .ic_ofs = 0x1e020000,
++      .disp0_ofs = 0x1e040000,
++      .disp1_ofs = 0x1e048000,
++      .dc_tmpl_ofs = 0x1f080000,
++      .vdi_ofs = 0x1e068000,
++      .type = IPUV3EX,
++};
++
++static struct ipu_devtype ipu_type_imx53 = {
++      .name = "IPUv3M",
++      .cm_ofs = 0x06000000,
++      .cpmem_ofs = 0x07000000,
++      .srm_ofs = 0x07040000,
++      .tpm_ofs = 0x07060000,
++      .csi0_ofs = 0x06030000,
++      .csi1_ofs = 0x06038000,
++      .ic_ofs = 0x06020000,
++      .disp0_ofs = 0x06040000,
++      .disp1_ofs = 0x06048000,
++      .dc_tmpl_ofs = 0x07080000,
++      .vdi_ofs = 0x06068000,
++      .type = IPUV3M,
++};
++
++static struct ipu_devtype ipu_type_imx6q = {
++      .name = "IPUv3H",
++      .cm_ofs = 0x00200000,
++      .cpmem_ofs = 0x00300000,
++      .srm_ofs = 0x00340000,
++      .tpm_ofs = 0x00360000,
++      .csi0_ofs = 0x00230000,
++      .csi1_ofs = 0x00238000,
++      .ic_ofs = 0x00220000,
++      .disp0_ofs = 0x00240000,
++      .disp1_ofs = 0x00248000,
++      .dc_tmpl_ofs = 0x00380000,
++      .vdi_ofs = 0x00268000,
++      .type = IPUV3H,
++};
++
++static const struct of_device_id imx_ipu_dt_ids[] = {
++      { .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
++      { .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
++      { .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
++      { .compatible = "fsl,imx6qp-ipu", .data = &ipu_type_imx6q, },
++      { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, imx_ipu_dt_ids);
++
++static int ipu_submodules_init(struct ipu_soc *ipu,
++              struct platform_device *pdev, unsigned long ipu_base,
++              struct clk *ipu_clk)
++{
++      char *unit;
++      int ret;
++      struct device *dev = &pdev->dev;
++      const struct ipu_devtype *devtype = ipu->devtype;
++
++      ret = ipu_cpmem_init(ipu, dev, ipu_base + devtype->cpmem_ofs);
++      if (ret) {
++              unit = "cpmem";
++              goto err_cpmem;
++      }
++
++      ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs,
++                         IPU_CONF_CSI0_EN, ipu_clk);
++      if (ret) {
++              unit = "csi0";
++              goto err_csi_0;
++      }
++
++      ret = ipu_csi_init(ipu, dev, 1, ipu_base + devtype->csi1_ofs,
++                         IPU_CONF_CSI1_EN, ipu_clk);
++      if (ret) {
++              unit = "csi1";
++              goto err_csi_1;
++      }
++
++      ret = ipu_ic_init(ipu, dev,
++                        ipu_base + devtype->ic_ofs,
++                        ipu_base + devtype->tpm_ofs);
++      if (ret) {
++              unit = "ic";
++              goto err_ic;
++      }
++
++      ret = ipu_vdi_init(ipu, dev, ipu_base + devtype->vdi_ofs,
++                         IPU_CONF_VDI_EN | IPU_CONF_ISP_EN |
++                         IPU_CONF_IC_INPUT);
++      if (ret) {
++              unit = "vdi";
++              goto err_vdi;
++      }
++
++      ret = ipu_image_convert_init(ipu, dev);
++      if (ret) {
++              unit = "image_convert";
++              goto err_image_convert;
++      }
++
++      ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
++                        IPU_CONF_DI0_EN, ipu_clk);
++      if (ret) {
++              unit = "di0";
++              goto err_di_0;
++      }
++
++      ret = ipu_di_init(ipu, dev, 1, ipu_base + devtype->disp1_ofs,
++                      IPU_CONF_DI1_EN, ipu_clk);
++      if (ret) {
++              unit = "di1";
++              goto err_di_1;
++      }
++
++      ret = ipu_dc_init(ipu, dev, ipu_base + devtype->cm_ofs +
++                      IPU_CM_DC_REG_OFS, ipu_base + devtype->dc_tmpl_ofs);
++      if (ret) {
++              unit = "dc_template";
++              goto err_dc;
++      }
++
++      ret = ipu_dmfc_init(ipu, dev, ipu_base +
++                      devtype->cm_ofs + IPU_CM_DMFC_REG_OFS, ipu_clk);
++      if (ret) {
++              unit = "dmfc";
++              goto err_dmfc;
++      }
++
++      ret = ipu_dp_init(ipu, dev, ipu_base + devtype->srm_ofs);
++      if (ret) {
++              unit = "dp";
++              goto err_dp;
++      }
++
++      ret = ipu_smfc_init(ipu, dev, ipu_base +
++                      devtype->cm_ofs + IPU_CM_SMFC_REG_OFS);
++      if (ret) {
++              unit = "smfc";
++              goto err_smfc;
++      }
++
++      return 0;
++
++err_smfc:
++      ipu_dp_exit(ipu);
++err_dp:
++      ipu_dmfc_exit(ipu);
++err_dmfc:
++      ipu_dc_exit(ipu);
++err_dc:
++      ipu_di_exit(ipu, 1);
++err_di_1:
++      ipu_di_exit(ipu, 0);
++err_di_0:
++      ipu_image_convert_exit(ipu);
++err_image_convert:
++      ipu_vdi_exit(ipu);
++err_vdi:
++      ipu_ic_exit(ipu);
++err_ic:
++      ipu_csi_exit(ipu, 1);
++err_csi_1:
++      ipu_csi_exit(ipu, 0);
++err_csi_0:
++      ipu_cpmem_exit(ipu);
++err_cpmem:
++      dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
++      return ret;
++}
++
++static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs)
++{
++      unsigned long status;
++      int i, bit, irq;
++
++      for (i = 0; i < num_regs; i++) {
++
++              status = ipu_cm_read(ipu, IPU_INT_STAT(regs[i]));
++              status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i]));
++
++              for_each_set_bit(bit, &status, 32) {
++                      irq = irq_linear_revmap(ipu->domain,
++                                              regs[i] * 32 + bit);
++                      if (irq)
++                              generic_handle_irq(irq);
++              }
++      }
++}
++
++static void ipu_irq_handler(struct irq_desc *desc)
++{
++      struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
++      struct irq_chip *chip = irq_desc_get_chip(desc);
++      static const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
++
++      chained_irq_enter(chip, desc);
++
++      ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
++
++      chained_irq_exit(chip, desc);
++}
++
++static void ipu_err_irq_handler(struct irq_desc *desc)
++{
++      struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
++      struct irq_chip *chip = irq_desc_get_chip(desc);
++      static const int int_reg[] = { 4, 5, 8, 9};
++
++      chained_irq_enter(chip, desc);
++
++      ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
++
++      chained_irq_exit(chip, desc);
++}
++
++int ipu_map_irq(struct ipu_soc *ipu, int irq)
++{
++      int virq;
++
++      virq = irq_linear_revmap(ipu->domain, irq);
++      if (!virq)
++              virq = irq_create_mapping(ipu->domain, irq);
++
++      return virq;
++}
++EXPORT_SYMBOL_GPL(ipu_map_irq);
++
++int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
++              enum ipu_channel_irq irq_type)
++{
++      return ipu_map_irq(ipu, irq_type + channel->num);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq);
++
++static void ipu_submodules_exit(struct ipu_soc *ipu)
++{
++      ipu_smfc_exit(ipu);
++      ipu_dp_exit(ipu);
++      ipu_dmfc_exit(ipu);
++      ipu_dc_exit(ipu);
++      ipu_di_exit(ipu, 1);
++      ipu_di_exit(ipu, 0);
++      ipu_image_convert_exit(ipu);
++      ipu_vdi_exit(ipu);
++      ipu_ic_exit(ipu);
++      ipu_csi_exit(ipu, 1);
++      ipu_csi_exit(ipu, 0);
++      ipu_cpmem_exit(ipu);
++}
++
++static int platform_remove_devices_fn(struct device *dev, void *unused)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++
++      platform_device_unregister(pdev);
++
++      return 0;
++}
++
++static void platform_device_unregister_children(struct platform_device *pdev)
++{
++      device_for_each_child(&pdev->dev, NULL, platform_remove_devices_fn);
++}
++
++struct ipu_platform_reg {
++      struct ipu_client_platformdata pdata;
++      const char *name;
++};
++
++/* These must be in the order of the corresponding device tree port nodes */
++static struct ipu_platform_reg client_reg[] = {
++      {
++              .pdata = {
++                      .csi = 0,
++                      .dma[0] = IPUV3_CHANNEL_CSI0,
++                      .dma[1] = -EINVAL,
++              },
++              .name = "imx-ipuv3-csi",
++      }, {
++              .pdata = {
++                      .csi = 1,
++                      .dma[0] = IPUV3_CHANNEL_CSI1,
++                      .dma[1] = -EINVAL,
++              },
++              .name = "imx-ipuv3-csi",
++      }, {
++              .pdata = {
++                      .di = 0,
++                      .dc = 5,
++                      .dp = IPU_DP_FLOW_SYNC_BG,
++                      .dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC,
++                      .dma[1] = IPUV3_CHANNEL_MEM_FG_SYNC,
++              },
++              .name = "imx-ipuv3-crtc",
++      }, {
++              .pdata = {
++                      .di = 1,
++                      .dc = 1,
++                      .dp = -EINVAL,
++                      .dma[0] = IPUV3_CHANNEL_MEM_DC_SYNC,
++                      .dma[1] = -EINVAL,
++              },
++              .name = "imx-ipuv3-crtc",
++      },
++};
++
++static DEFINE_MUTEX(ipu_client_id_mutex);
++static int ipu_client_id;
++
++static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
++{
++      struct device *dev = ipu->dev;
++      unsigned i;
++      int id, ret;
++
++      mutex_lock(&ipu_client_id_mutex);
++      id = ipu_client_id;
++      ipu_client_id += ARRAY_SIZE(client_reg);
++      mutex_unlock(&ipu_client_id_mutex);
++
++      for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
++              struct ipu_platform_reg *reg = &client_reg[i];
++              struct platform_device *pdev;
++              struct device_node *of_node;
++
++              /* Associate subdevice with the corresponding port node */
++              of_node = of_graph_get_port_by_id(dev->of_node, i);
++              if (!of_node) {
++                      dev_info(dev,
++                               "no port@%d node in %pOF, not using %s%d\n",
++                               i, dev->of_node,
++                               (i / 2) ? "DI" : "CSI", i % 2);
++                      continue;
++              }
++
++              pdev = platform_device_alloc(reg->name, id++);
++              if (!pdev) {
++                      ret = -ENOMEM;
++                      goto err_register;
++              }
++
++              pdev->dev.parent = dev;
++
++              reg->pdata.of_node = of_node;
++              ret = platform_device_add_data(pdev, &reg->pdata,
++                                             sizeof(reg->pdata));
++              if (!ret)
++                      ret = platform_device_add(pdev);
++              if (ret) {
++                      platform_device_put(pdev);
++                      goto err_register;
++              }
++      }
++
++      return 0;
++
++err_register:
++      platform_device_unregister_children(to_platform_device(dev));
++
++      return ret;
++}
++
++
++static int ipu_irq_init(struct ipu_soc *ipu)
++{
++      struct irq_chip_generic *gc;
++      struct irq_chip_type *ct;
++      unsigned long unused[IPU_NUM_IRQS / 32] = {
++              0x400100d0, 0xffe000fd,
++              0x400100d0, 0xffe000fd,
++              0x400100d0, 0xffe000fd,
++              0x4077ffff, 0xffe7e1fd,
++              0x23fffffe, 0x8880fff0,
++              0xf98fe7d0, 0xfff81fff,
++              0x400100d0, 0xffe000fd,
++              0x00000000,
++      };
++      int ret, i;
++
++      ipu->domain = irq_domain_add_linear(ipu->dev->of_node, IPU_NUM_IRQS,
++                                          &irq_generic_chip_ops, ipu);
++      if (!ipu->domain) {
++              dev_err(ipu->dev, "failed to add irq domain\n");
++              return -ENODEV;
++      }
++
++      ret = irq_alloc_domain_generic_chips(ipu->domain, 32, 1, "IPU",
++                                           handle_level_irq, 0, 0, 0);
++      if (ret < 0) {
++              dev_err(ipu->dev, "failed to alloc generic irq chips\n");
++              irq_domain_remove(ipu->domain);
++              return ret;
++      }
++
++      /* Mask and clear all interrupts */
++      for (i = 0; i < IPU_NUM_IRQS; i += 32) {
++              ipu_cm_write(ipu, 0, IPU_INT_CTRL(i / 32));
++              ipu_cm_write(ipu, ~unused[i / 32], IPU_INT_STAT(i / 32));
++      }
++
++      for (i = 0; i < IPU_NUM_IRQS; i += 32) {
++              gc = irq_get_domain_generic_chip(ipu->domain, i);
++              gc->reg_base = ipu->cm_reg;
++              gc->unused = unused[i / 32];
++              ct = gc->chip_types;
++              ct->chip.irq_ack = irq_gc_ack_set_bit;
++              ct->chip.irq_mask = irq_gc_mask_clr_bit;
++              ct->chip.irq_unmask = irq_gc_mask_set_bit;
++              ct->regs.ack = IPU_INT_STAT(i / 32);
++              ct->regs.mask = IPU_INT_CTRL(i / 32);
++      }
++
++      irq_set_chained_handler_and_data(ipu->irq_sync, ipu_irq_handler, ipu);
++      irq_set_chained_handler_and_data(ipu->irq_err, ipu_err_irq_handler,
++                                       ipu);
++
++      return 0;
++}
++
++static void ipu_irq_exit(struct ipu_soc *ipu)
++{
++      int i, irq;
++
++      irq_set_chained_handler_and_data(ipu->irq_err, NULL, NULL);
++      irq_set_chained_handler_and_data(ipu->irq_sync, NULL, NULL);
++
++      /* TODO: remove irq_domain_generic_chips */
++
++      for (i = 0; i < IPU_NUM_IRQS; i++) {
++              irq = irq_linear_revmap(ipu->domain, i);
++              if (irq)
++                      irq_dispose_mapping(irq);
++      }
++
++      irq_domain_remove(ipu->domain);
++}
++
++void ipu_dump(struct ipu_soc *ipu)
++{
++      int i;
++
++      dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n",
++              ipu_cm_read(ipu, IPU_CONF));
++      dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n",
++              ipu_idmac_read(ipu, IDMAC_CONF));
++      dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n",
++              ipu_idmac_read(ipu, IDMAC_CHA_EN(0)));
++      dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n",
++              ipu_idmac_read(ipu, IDMAC_CHA_EN(32)));
++      dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n",
++              ipu_idmac_read(ipu, IDMAC_CHA_PRI(0)));
++      dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n",
++              ipu_idmac_read(ipu, IDMAC_CHA_PRI(32)));
++      dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n",
++              ipu_idmac_read(ipu, IDMAC_BAND_EN(0)));
++      dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n",
++              ipu_idmac_read(ipu, IDMAC_BAND_EN(32)));
++      dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
++              ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0)));
++      dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
++              ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32)));
++      dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n",
++              ipu_cm_read(ipu, IPU_FS_PROC_FLOW1));
++      dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n",
++              ipu_cm_read(ipu, IPU_FS_PROC_FLOW2));
++      dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n",
++              ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
++      dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
++              ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
++      for (i = 0; i < 15; i++)
++              dev_dbg(ipu->dev, "IPU_INT_CTRL(%d) = \t%08X\n", i,
++                      ipu_cm_read(ipu, IPU_INT_CTRL(i)));
++}
++EXPORT_SYMBOL_GPL(ipu_dump);
++
++static int ipu_probe(struct platform_device *pdev)
++{
++      struct device_node *np = pdev->dev.of_node;
++      struct ipu_soc *ipu;
++      struct resource *res;
++      unsigned long ipu_base;
++      int ret, irq_sync, irq_err;
++      const struct ipu_devtype *devtype;
++
++      devtype = of_device_get_match_data(&pdev->dev);
++      if (!devtype)
++              return -EINVAL;
++
++      irq_sync = platform_get_irq(pdev, 0);
++      irq_err = platform_get_irq(pdev, 1);
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++
++      dev_dbg(&pdev->dev, "irq_sync: %d irq_err: %d\n",
++                      irq_sync, irq_err);
++
++      if (!res || irq_sync < 0 || irq_err < 0)
++              return -ENODEV;
++
++      ipu_base = res->start;
++
++      ipu = devm_kzalloc(&pdev->dev, sizeof(*ipu), GFP_KERNEL);
++      if (!ipu)
++              return -ENODEV;
++
++      ipu->id = of_alias_get_id(np, "ipu");
++      if (ipu->id < 0)
++              ipu->id = 0;
++
++      if (of_device_is_compatible(np, "fsl,imx6qp-ipu") &&
++          IS_ENABLED(CONFIG_DRM)) {
++              ipu->prg_priv = ipu_prg_lookup_by_phandle(&pdev->dev,
++                                                        "fsl,prg", ipu->id);
++              if (!ipu->prg_priv)
++                      return -EPROBE_DEFER;
++      }
++
++      ipu->devtype = devtype;
++      ipu->ipu_type = devtype->type;
++
++      spin_lock_init(&ipu->lock);
++      mutex_init(&ipu->channel_lock);
++      INIT_LIST_HEAD(&ipu->channels);
++
++      dev_dbg(&pdev->dev, "cm_reg:   0x%08lx\n",
++                      ipu_base + devtype->cm_ofs);
++      dev_dbg(&pdev->dev, "idmac:    0x%08lx\n",
++                      ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS);
++      dev_dbg(&pdev->dev, "cpmem:    0x%08lx\n",
++                      ipu_base + devtype->cpmem_ofs);
++      dev_dbg(&pdev->dev, "csi0:    0x%08lx\n",
++                      ipu_base + devtype->csi0_ofs);
++      dev_dbg(&pdev->dev, "csi1:    0x%08lx\n",
++                      ipu_base + devtype->csi1_ofs);
++      dev_dbg(&pdev->dev, "ic:      0x%08lx\n",
++                      ipu_base + devtype->ic_ofs);
++      dev_dbg(&pdev->dev, "disp0:    0x%08lx\n",
++                      ipu_base + devtype->disp0_ofs);
++      dev_dbg(&pdev->dev, "disp1:    0x%08lx\n",
++                      ipu_base + devtype->disp1_ofs);
++      dev_dbg(&pdev->dev, "srm:      0x%08lx\n",
++                      ipu_base + devtype->srm_ofs);
++      dev_dbg(&pdev->dev, "tpm:      0x%08lx\n",
++                      ipu_base + devtype->tpm_ofs);
++      dev_dbg(&pdev->dev, "dc:       0x%08lx\n",
++                      ipu_base + devtype->cm_ofs + IPU_CM_DC_REG_OFS);
++      dev_dbg(&pdev->dev, "ic:       0x%08lx\n",
++                      ipu_base + devtype->cm_ofs + IPU_CM_IC_REG_OFS);
++      dev_dbg(&pdev->dev, "dmfc:     0x%08lx\n",
++                      ipu_base + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS);
++      dev_dbg(&pdev->dev, "vdi:      0x%08lx\n",
++                      ipu_base + devtype->vdi_ofs);
++
++      ipu->cm_reg = devm_ioremap(&pdev->dev,
++                      ipu_base + devtype->cm_ofs, PAGE_SIZE);
++      ipu->idmac_reg = devm_ioremap(&pdev->dev,
++                      ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS,
++                      PAGE_SIZE);
++
++      if (!ipu->cm_reg || !ipu->idmac_reg)
++              return -ENOMEM;
++
++      ipu->clk = devm_clk_get(&pdev->dev, "bus");
++      if (IS_ERR(ipu->clk)) {
++              ret = PTR_ERR(ipu->clk);
++              dev_err(&pdev->dev, "clk_get failed with %d", ret);
++              return ret;
++      }
++
++      platform_set_drvdata(pdev, ipu);
++
++      ret = clk_prepare_enable(ipu->clk);
++      if (ret) {
++              dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
++              return ret;
++      }
++
++      ipu->dev = &pdev->dev;
++      ipu->irq_sync = irq_sync;
++      ipu->irq_err = irq_err;
++
++      ret = device_reset(&pdev->dev);
++      if (ret) {
++              dev_err(&pdev->dev, "failed to reset: %d\n", ret);
++              goto out_failed_reset;
++      }
++      ret = ipu_memory_reset(ipu);
++      if (ret)
++              goto out_failed_reset;
++
++      ret = ipu_irq_init(ipu);
++      if (ret)
++              goto out_failed_irq;
++
++      /* Set MCU_T to divide MCU access window into 2 */
++      ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
++                      IPU_DISP_GEN);
++
++      ret = ipu_submodules_init(ipu, pdev, ipu_base, ipu->clk);
++      if (ret)
++              goto failed_submodules_init;
++
++      ret = ipu_add_client_devices(ipu, ipu_base);
++      if (ret) {
++              dev_err(&pdev->dev, "adding client devices failed with %d\n",
++                              ret);
++              goto failed_add_clients;
++      }
++
++      dev_info(&pdev->dev, "%s probed\n", devtype->name);
++
++      return 0;
++
++failed_add_clients:
++      ipu_submodules_exit(ipu);
++failed_submodules_init:
++      ipu_irq_exit(ipu);
++out_failed_irq:
++out_failed_reset:
++      clk_disable_unprepare(ipu->clk);
++      return ret;
++}
++
++static int ipu_remove(struct platform_device *pdev)
++{
++      struct ipu_soc *ipu = platform_get_drvdata(pdev);
++
++      platform_device_unregister_children(pdev);
++      ipu_submodules_exit(ipu);
++      ipu_irq_exit(ipu);
++
++      clk_disable_unprepare(ipu->clk);
++
++      return 0;
++}
++
++static struct platform_driver imx_ipu_driver = {
++      .driver = {
++              .name = "imx-ipuv3",
++              .of_match_table = imx_ipu_dt_ids,
++      },
++      .probe = ipu_probe,
++      .remove = ipu_remove,
++};
++
++static struct platform_driver * const drivers[] = {
++#if IS_ENABLED(CONFIG_DRM)
++      &ipu_pre_drv,
++      &ipu_prg_drv,
++#endif
++      &imx_ipu_driver,
++};
++
++static int __init imx_ipu_init(void)
++{
++      return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
++}
++module_init(imx_ipu_init);
++
++static void __exit imx_ipu_exit(void)
++{
++      platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
++}
++module_exit(imx_ipu_exit);
++
++MODULE_ALIAS("platform:imx-ipuv3");
++MODULE_DESCRIPTION("i.MX IPU v3 driver");
++MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/ipu-cpmem.c
+@@ -0,0 +1,976 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (C) 2012 Mentor Graphics Inc.
++ * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++#include <linux/types.h>
++#include <linux/bitrev.h>
++#include <linux/io.h>
++#include <linux/sizes.h>
++#include <drm/drm_fourcc.h>
++#include "ipu-prv.h"
++
++struct ipu_cpmem_word {
++      u32 data[5];
++      u32 res[3];
++};
++
++struct ipu_ch_param {
++      struct ipu_cpmem_word word[2];
++};
++
++struct ipu_cpmem {
++      struct ipu_ch_param __iomem *base;
++      u32 module;
++      spinlock_t lock;
++      int use_count;
++      struct ipu_soc *ipu;
++};
++
++#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
++
++#define IPU_FIELD_UBO         IPU_CPMEM_WORD(0, 46, 22)
++#define IPU_FIELD_VBO         IPU_CPMEM_WORD(0, 68, 22)
++#define IPU_FIELD_IOX         IPU_CPMEM_WORD(0, 90, 4)
++#define IPU_FIELD_RDRW                IPU_CPMEM_WORD(0, 94, 1)
++#define IPU_FIELD_SO          IPU_CPMEM_WORD(0, 113, 1)
++#define IPU_FIELD_SLY         IPU_CPMEM_WORD(1, 102, 14)
++#define IPU_FIELD_SLUV                IPU_CPMEM_WORD(1, 128, 14)
++
++#define IPU_FIELD_XV          IPU_CPMEM_WORD(0, 0, 10)
++#define IPU_FIELD_YV          IPU_CPMEM_WORD(0, 10, 9)
++#define IPU_FIELD_XB          IPU_CPMEM_WORD(0, 19, 13)
++#define IPU_FIELD_YB          IPU_CPMEM_WORD(0, 32, 12)
++#define IPU_FIELD_NSB_B               IPU_CPMEM_WORD(0, 44, 1)
++#define IPU_FIELD_CF          IPU_CPMEM_WORD(0, 45, 1)
++#define IPU_FIELD_SX          IPU_CPMEM_WORD(0, 46, 12)
++#define IPU_FIELD_SY          IPU_CPMEM_WORD(0, 58, 11)
++#define IPU_FIELD_NS          IPU_CPMEM_WORD(0, 69, 10)
++#define IPU_FIELD_SDX         IPU_CPMEM_WORD(0, 79, 7)
++#define IPU_FIELD_SM          IPU_CPMEM_WORD(0, 86, 10)
++#define IPU_FIELD_SCC         IPU_CPMEM_WORD(0, 96, 1)
++#define IPU_FIELD_SCE         IPU_CPMEM_WORD(0, 97, 1)
++#define IPU_FIELD_SDY         IPU_CPMEM_WORD(0, 98, 7)
++#define IPU_FIELD_SDRX                IPU_CPMEM_WORD(0, 105, 1)
++#define IPU_FIELD_SDRY                IPU_CPMEM_WORD(0, 106, 1)
++#define IPU_FIELD_BPP         IPU_CPMEM_WORD(0, 107, 3)
++#define IPU_FIELD_DEC_SEL     IPU_CPMEM_WORD(0, 110, 2)
++#define IPU_FIELD_DIM         IPU_CPMEM_WORD(0, 112, 1)
++#define IPU_FIELD_BNDM                IPU_CPMEM_WORD(0, 114, 3)
++#define IPU_FIELD_BM          IPU_CPMEM_WORD(0, 117, 2)
++#define IPU_FIELD_ROT         IPU_CPMEM_WORD(0, 119, 1)
++#define IPU_FIELD_ROT_HF_VF   IPU_CPMEM_WORD(0, 119, 3)
++#define IPU_FIELD_HF          IPU_CPMEM_WORD(0, 120, 1)
++#define IPU_FIELD_VF          IPU_CPMEM_WORD(0, 121, 1)
++#define IPU_FIELD_THE         IPU_CPMEM_WORD(0, 122, 1)
++#define IPU_FIELD_CAP         IPU_CPMEM_WORD(0, 123, 1)
++#define IPU_FIELD_CAE         IPU_CPMEM_WORD(0, 124, 1)
++#define IPU_FIELD_FW          IPU_CPMEM_WORD(0, 125, 13)
++#define IPU_FIELD_FH          IPU_CPMEM_WORD(0, 138, 12)
++#define IPU_FIELD_EBA0                IPU_CPMEM_WORD(1, 0, 29)
++#define IPU_FIELD_EBA1                IPU_CPMEM_WORD(1, 29, 29)
++#define IPU_FIELD_ILO         IPU_CPMEM_WORD(1, 58, 20)
++#define IPU_FIELD_NPB         IPU_CPMEM_WORD(1, 78, 7)
++#define IPU_FIELD_PFS         IPU_CPMEM_WORD(1, 85, 4)
++#define IPU_FIELD_ALU         IPU_CPMEM_WORD(1, 89, 1)
++#define IPU_FIELD_ALBM                IPU_CPMEM_WORD(1, 90, 3)
++#define IPU_FIELD_ID          IPU_CPMEM_WORD(1, 93, 2)
++#define IPU_FIELD_TH          IPU_CPMEM_WORD(1, 95, 7)
++#define IPU_FIELD_SL          IPU_CPMEM_WORD(1, 102, 14)
++#define IPU_FIELD_WID0                IPU_CPMEM_WORD(1, 116, 3)
++#define IPU_FIELD_WID1                IPU_CPMEM_WORD(1, 119, 3)
++#define IPU_FIELD_WID2                IPU_CPMEM_WORD(1, 122, 3)
++#define IPU_FIELD_WID3                IPU_CPMEM_WORD(1, 125, 3)
++#define IPU_FIELD_OFS0                IPU_CPMEM_WORD(1, 128, 5)
++#define IPU_FIELD_OFS1                IPU_CPMEM_WORD(1, 133, 5)
++#define IPU_FIELD_OFS2                IPU_CPMEM_WORD(1, 138, 5)
++#define IPU_FIELD_OFS3                IPU_CPMEM_WORD(1, 143, 5)
++#define IPU_FIELD_SXYS                IPU_CPMEM_WORD(1, 148, 1)
++#define IPU_FIELD_CRE         IPU_CPMEM_WORD(1, 149, 1)
++#define IPU_FIELD_DEC_SEL2    IPU_CPMEM_WORD(1, 150, 1)
++
++static inline struct ipu_ch_param __iomem *
++ipu_get_cpmem(struct ipuv3_channel *ch)
++{
++      struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv;
++
++      return cpmem->base + ch->num;
++}
++
++static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v)
++{
++      struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
++      u32 bit = (wbs >> 8) % 160;
++      u32 size = wbs & 0xff;
++      u32 word = (wbs >> 8) / 160;
++      u32 i = bit / 32;
++      u32 ofs = bit % 32;
++      u32 mask = (1 << size) - 1;
++      u32 val;
++
++      pr_debug("%s %d %d %d\n", __func__, word, bit , size);
++
++      val = readl(&base->word[word].data[i]);
++      val &= ~(mask << ofs);
++      val |= v << ofs;
++      writel(val, &base->word[word].data[i]);
++
++      if ((bit + size - 1) / 32 > i) {
++              val = readl(&base->word[word].data[i + 1]);
++              val &= ~(mask >> (ofs ? (32 - ofs) : 0));
++              val |= v >> (ofs ? (32 - ofs) : 0);
++              writel(val, &base->word[word].data[i + 1]);
++      }
++}
++
++static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs)
++{
++      struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
++      u32 bit = (wbs >> 8) % 160;
++      u32 size = wbs & 0xff;
++      u32 word = (wbs >> 8) / 160;
++      u32 i = bit / 32;
++      u32 ofs = bit % 32;
++      u32 mask = (1 << size) - 1;
++      u32 val = 0;
++
++      pr_debug("%s %d %d %d\n", __func__, word, bit , size);
++
++      val = (readl(&base->word[word].data[i]) >> ofs) & mask;
++
++      if ((bit + size - 1) / 32 > i) {
++              u32 tmp;
++
++              tmp = readl(&base->word[word].data[i + 1]);
++              tmp &= mask >> (ofs ? (32 - ofs) : 0);
++              val |= tmp << (ofs ? (32 - ofs) : 0);
++      }
++
++      return val;
++}
++
++/*
++ * The V4L2 spec defines packed RGB formats in memory byte order, which from
++ * point of view of the IPU corresponds to little-endian words with the first
++ * component in the least significant bits.
++ * The DRM pixel formats and IPU internal representation are ordered the other
++ * way around, with the first named component ordered at the most significant
++ * bits. Further, V4L2 formats are not well defined:
++ *     https://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
++ * We choose the interpretation which matches GStreamer behavior.
++ */
++static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
++{
++      switch (pixelformat) {
++      case V4L2_PIX_FMT_RGB565:
++              /*
++               * Here we choose the 'corrected' interpretation of RGBP, a
++               * little-endian 16-bit word with the red component at the most
++               * significant bits:
++               * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
++               */
++              return DRM_FORMAT_RGB565;
++      case V4L2_PIX_FMT_BGR24:
++              /* B G R <=> [24:0] R:G:B */
++              return DRM_FORMAT_RGB888;
++      case V4L2_PIX_FMT_RGB24:
++              /* R G B <=> [24:0] B:G:R */
++              return DRM_FORMAT_BGR888;
++      case V4L2_PIX_FMT_BGR32:
++              /* B G R A <=> [32:0] A:B:G:R */
++              return DRM_FORMAT_XRGB8888;
++      case V4L2_PIX_FMT_RGB32:
++              /* R G B A <=> [32:0] A:B:G:R */
++              return DRM_FORMAT_XBGR8888;
++      case V4L2_PIX_FMT_ABGR32:
++              /* B G R A <=> [32:0] A:R:G:B */
++              return DRM_FORMAT_ARGB8888;
++      case V4L2_PIX_FMT_XBGR32:
++              /* B G R X <=> [32:0] X:R:G:B */
++              return DRM_FORMAT_XRGB8888;
++      case V4L2_PIX_FMT_BGRA32:
++              /* A B G R <=> [32:0] R:G:B:A */
++              return DRM_FORMAT_RGBA8888;
++      case V4L2_PIX_FMT_BGRX32:
++              /* X B G R <=> [32:0] R:G:B:X */
++              return DRM_FORMAT_RGBX8888;
++      case V4L2_PIX_FMT_RGBA32:
++              /* R G B A <=> [32:0] A:B:G:R */
++              return DRM_FORMAT_ABGR8888;
++      case V4L2_PIX_FMT_RGBX32:
++              /* R G B X <=> [32:0] X:B:G:R */
++              return DRM_FORMAT_XBGR8888;
++      case V4L2_PIX_FMT_ARGB32:
++              /* A R G B <=> [32:0] B:G:R:A */
++              return DRM_FORMAT_BGRA8888;
++      case V4L2_PIX_FMT_XRGB32:
++              /* X R G B <=> [32:0] B:G:R:X */
++              return DRM_FORMAT_BGRX8888;
++      case V4L2_PIX_FMT_UYVY:
++              return DRM_FORMAT_UYVY;
++      case V4L2_PIX_FMT_YUYV:
++              return DRM_FORMAT_YUYV;
++      case V4L2_PIX_FMT_YUV420:
++              return DRM_FORMAT_YUV420;
++      case V4L2_PIX_FMT_YUV422P:
++              return DRM_FORMAT_YUV422;
++      case V4L2_PIX_FMT_YVU420:
++              return DRM_FORMAT_YVU420;
++      case V4L2_PIX_FMT_NV12:
++              return DRM_FORMAT_NV12;
++      case V4L2_PIX_FMT_NV16:
++              return DRM_FORMAT_NV16;
++      }
++
++      return -EINVAL;
++}
++
++void ipu_cpmem_zero(struct ipuv3_channel *ch)
++{
++      struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
++      void __iomem *base = p;
++      int i;
++
++      for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
++              writel(0, base + i * sizeof(u32));
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
++
++void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres)
++{
++      ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1);
++      ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
++
++void ipu_cpmem_skip_odd_chroma_rows(struct ipuv3_channel *ch)
++{
++      ipu_ch_param_write_field(ch, IPU_FIELD_RDRW, 1);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_skip_odd_chroma_rows);
++
++void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
++{
++      ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
++
++void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch)
++{
++      struct ipu_soc *ipu = ch->ipu;
++      u32 val;
++
++      if (ipu->ipu_type == IPUV3EX)
++              ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1);
++
++      val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num));
++      val |= 1 << (ch->num % 32);
++      ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num));
++};
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
++
++void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
++{
++      WARN_ON_ONCE(buf & 0x7);
++
++      if (bufnum)
++              ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
++      else
++              ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
++
++void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
++{
++      WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7));
++
++      ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
++      ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
++
++void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
++                             u32 pixelformat)
++{
++      u32 ilo, sly, sluv;
++
++      if (stride < 0) {
++              stride = -stride;
++              ilo = 0x100000 - (stride / 8);
++      } else {
++              ilo = stride / 8;
++      }
++
++      sly = (stride * 2) - 1;
++
++      switch (pixelformat) {
++      case V4L2_PIX_FMT_YUV420:
++      case V4L2_PIX_FMT_YVU420:
++              sluv = stride / 2 - 1;
++              break;
++      case V4L2_PIX_FMT_NV12:
++              sluv = stride - 1;
++              break;
++      case V4L2_PIX_FMT_YUV422P:
++              sluv = stride - 1;
++              break;
++      case V4L2_PIX_FMT_NV16:
++              sluv = stride * 2 - 1;
++              break;
++      default:
++              sluv = 0;
++              break;
++      }
++
++      ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
++      ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
++      ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
++      if (sluv)
++              ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
++};
++EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
++
++void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
++{
++      id &= 0x3;
++      ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
++
++int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
++{
++      return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
++
++void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
++{
++      ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
++};
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
++
++void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
++{
++      ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
++
++void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
++                          enum ipu_rotate_mode rot)
++{
++      u32 temp_rot = bitrev8(rot) >> 5;
++
++      ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
++
++int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
++                           const struct ipu_rgb *rgb)
++{
++      int bpp = 0, npb = 0, ro, go, bo, to;
++
++      ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
++      go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
++      bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
++      to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
++
++      ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1);
++      ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro);
++      ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1);
++      ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go);
++      ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1);
++      ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo);
++
++      if (rgb->transp.length) {
++              ipu_ch_param_write_field(ch, IPU_FIELD_WID3,
++                              rgb->transp.length - 1);
++              ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to);
++      } else {
++              ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
++              ipu_ch_param_write_field(ch, IPU_FIELD_OFS3,
++                              rgb->bits_per_pixel);
++      }
++
++      switch (rgb->bits_per_pixel) {
++      case 32:
++              bpp = 0;
++              npb = 15;
++              break;
++      case 24:
++              bpp = 1;
++              npb = 19;
++              break;
++      case 16:
++              bpp = 3;
++              npb = 31;
++              break;
++      case 8:
++              bpp = 5;
++              npb = 63;
++              break;
++      default:
++              return -EINVAL;
++      }
++      ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
++      ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
++      ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
++
++int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width)
++{
++      int bpp = 0, npb = 0;
++
++      switch (width) {
++      case 32:
++              bpp = 0;
++              npb = 15;
++              break;
++      case 24:
++              bpp = 1;
++              npb = 19;
++              break;
++      case 16:
++              bpp = 3;
++              npb = 31;
++              break;
++      case 8:
++              bpp = 5;
++              npb = 63;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
++      ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
++      ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
++
++void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format)
++{
++      switch (pixel_format) {
++      case V4L2_PIX_FMT_UYVY:
++              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
++              break;
++      case V4L2_PIX_FMT_YUYV:
++              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
++              break;
++      }
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
++
++void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
++                                 unsigned int uv_stride,
++                                 unsigned int u_offset, unsigned int v_offset)
++{
++      WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7));
++
++      ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1);
++      ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
++      ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
++
++static const struct ipu_rgb def_xrgb_32 = {
++      .red    = { .offset = 16, .length = 8, },
++      .green  = { .offset =  8, .length = 8, },
++      .blue   = { .offset =  0, .length = 8, },
++      .transp = { .offset = 24, .length = 8, },
++      .bits_per_pixel = 32,
++};
++
++static const struct ipu_rgb def_xbgr_32 = {
++      .red    = { .offset =  0, .length = 8, },
++      .green  = { .offset =  8, .length = 8, },
++      .blue   = { .offset = 16, .length = 8, },
++      .transp = { .offset = 24, .length = 8, },
++      .bits_per_pixel = 32,
++};
++
++static const struct ipu_rgb def_rgbx_32 = {
++      .red    = { .offset = 24, .length = 8, },
++      .green  = { .offset = 16, .length = 8, },
++      .blue   = { .offset =  8, .length = 8, },
++      .transp = { .offset =  0, .length = 8, },
++      .bits_per_pixel = 32,
++};
++
++static const struct ipu_rgb def_bgrx_32 = {
++      .red    = { .offset =  8, .length = 8, },
++      .green  = { .offset = 16, .length = 8, },
++      .blue   = { .offset = 24, .length = 8, },
++      .transp = { .offset =  0, .length = 8, },
++      .bits_per_pixel = 32,
++};
++
++static const struct ipu_rgb def_rgb_24 = {
++      .red    = { .offset = 16, .length = 8, },
++      .green  = { .offset =  8, .length = 8, },
++      .blue   = { .offset =  0, .length = 8, },
++      .transp = { .offset =  0, .length = 0, },
++      .bits_per_pixel = 24,
++};
++
++static const struct ipu_rgb def_bgr_24 = {
++      .red    = { .offset =  0, .length = 8, },
++      .green  = { .offset =  8, .length = 8, },
++      .blue   = { .offset = 16, .length = 8, },
++      .transp = { .offset =  0, .length = 0, },
++      .bits_per_pixel = 24,
++};
++
++static const struct ipu_rgb def_rgb_16 = {
++      .red    = { .offset = 11, .length = 5, },
++      .green  = { .offset =  5, .length = 6, },
++      .blue   = { .offset =  0, .length = 5, },
++      .transp = { .offset =  0, .length = 0, },
++      .bits_per_pixel = 16,
++};
++
++static const struct ipu_rgb def_bgr_16 = {
++      .red    = { .offset =  0, .length = 5, },
++      .green  = { .offset =  5, .length = 6, },
++      .blue   = { .offset = 11, .length = 5, },
++      .transp = { .offset =  0, .length = 0, },
++      .bits_per_pixel = 16,
++};
++
++static const struct ipu_rgb def_argb_16 = {
++      .red    = { .offset = 10, .length = 5, },
++      .green  = { .offset =  5, .length = 5, },
++      .blue   = { .offset =  0, .length = 5, },
++      .transp = { .offset = 15, .length = 1, },
++      .bits_per_pixel = 16,
++};
++
++static const struct ipu_rgb def_argb_16_4444 = {
++      .red    = { .offset =  8, .length = 4, },
++      .green  = { .offset =  4, .length = 4, },
++      .blue   = { .offset =  0, .length = 4, },
++      .transp = { .offset = 12, .length = 4, },
++      .bits_per_pixel = 16,
++};
++
++static const struct ipu_rgb def_abgr_16 = {
++      .red    = { .offset =  0, .length = 5, },
++      .green  = { .offset =  5, .length = 5, },
++      .blue   = { .offset = 10, .length = 5, },
++      .transp = { .offset = 15, .length = 1, },
++      .bits_per_pixel = 16,
++};
++
++static const struct ipu_rgb def_rgba_16 = {
++      .red    = { .offset = 11, .length = 5, },
++      .green  = { .offset =  6, .length = 5, },
++      .blue   = { .offset =  1, .length = 5, },
++      .transp = { .offset =  0, .length = 1, },
++      .bits_per_pixel = 16,
++};
++
++static const struct ipu_rgb def_bgra_16 = {
++      .red    = { .offset =  1, .length = 5, },
++      .green  = { .offset =  6, .length = 5, },
++      .blue   = { .offset = 11, .length = 5, },
++      .transp = { .offset =  0, .length = 1, },
++      .bits_per_pixel = 16,
++};
++
++#define Y_OFFSET(pix, x, y)   ((x) + pix->width * (y))
++#define U_OFFSET(pix, x, y)   ((pix->width * pix->height) +           \
++                               (pix->width * ((y) / 2) / 2) + (x) / 2)
++#define V_OFFSET(pix, x, y)   ((pix->width * pix->height) +           \
++                               (pix->width * pix->height / 4) +       \
++                               (pix->width * ((y) / 2) / 2) + (x) / 2)
++#define U2_OFFSET(pix, x, y)  ((pix->width * pix->height) +           \
++                               (pix->width * (y) / 2) + (x) / 2)
++#define V2_OFFSET(pix, x, y)  ((pix->width * pix->height) +           \
++                               (pix->width * pix->height / 2) +       \
++                               (pix->width * (y) / 2) + (x) / 2)
++#define UV_OFFSET(pix, x, y)  ((pix->width * pix->height) +   \
++                               (pix->width * ((y) / 2)) + (x))
++#define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) +   \
++                               (pix->width * y) + (x))
++
++#define NUM_ALPHA_CHANNELS    7
++
++/* See Table 37-12. Alpha channels mapping. */
++static int ipu_channel_albm(int ch_num)
++{
++      switch (ch_num) {
++      case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:     return 0;
++      case IPUV3_CHANNEL_G_MEM_IC_PP:         return 1;
++      case IPUV3_CHANNEL_MEM_FG_SYNC:         return 2;
++      case IPUV3_CHANNEL_MEM_FG_ASYNC:        return 3;
++      case IPUV3_CHANNEL_MEM_BG_SYNC:         return 4;
++      case IPUV3_CHANNEL_MEM_BG_ASYNC:        return 5;
++      case IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB: return 6;
++      default:
++              return -EINVAL;
++      }
++}
++
++static void ipu_cpmem_set_separate_alpha(struct ipuv3_channel *ch)
++{
++      struct ipu_soc *ipu = ch->ipu;
++      int albm;
++      u32 val;
++
++      albm = ipu_channel_albm(ch->num);
++      if (albm < 0)
++              return;
++
++      ipu_ch_param_write_field(ch, IPU_FIELD_ALU, 1);
++      ipu_ch_param_write_field(ch, IPU_FIELD_ALBM, albm);
++      ipu_ch_param_write_field(ch, IPU_FIELD_CRE, 1);
++
++      val = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
++      val |= BIT(ch->num);
++      ipu_idmac_write(ipu, val, IDMAC_SEP_ALPHA);
++}
++
++int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
++{
++      switch (drm_fourcc) {
++      case DRM_FORMAT_YUV420:
++      case DRM_FORMAT_YVU420:
++              /* pix format */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
++              /* burst size */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
++              break;
++      case DRM_FORMAT_YUV422:
++      case DRM_FORMAT_YVU422:
++              /* pix format */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
++              /* burst size */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
++              break;
++      case DRM_FORMAT_YUV444:
++      case DRM_FORMAT_YVU444:
++              /* pix format */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0);
++              /* burst size */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
++              break;
++      case DRM_FORMAT_NV12:
++              /* pix format */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
++              /* burst size */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
++              break;
++      case DRM_FORMAT_NV16:
++              /* pix format */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
++              /* burst size */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
++              break;
++      case DRM_FORMAT_UYVY:
++              /* bits/pixel */
++              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
++              /* pix format */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
++              /* burst size */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
++              break;
++      case DRM_FORMAT_YUYV:
++              /* bits/pixel */
++              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
++              /* pix format */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
++              /* burst size */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
++              break;
++      case DRM_FORMAT_ABGR8888:
++      case DRM_FORMAT_XBGR8888:
++              ipu_cpmem_set_format_rgb(ch, &def_xbgr_32);
++              break;
++      case DRM_FORMAT_ARGB8888:
++      case DRM_FORMAT_XRGB8888:
++              ipu_cpmem_set_format_rgb(ch, &def_xrgb_32);
++              break;
++      case DRM_FORMAT_RGBA8888:
++      case DRM_FORMAT_RGBX8888:
++      case DRM_FORMAT_RGBX8888_A8:
++              ipu_cpmem_set_format_rgb(ch, &def_rgbx_32);
++              break;
++      case DRM_FORMAT_BGRA8888:
++      case DRM_FORMAT_BGRX8888:
++      case DRM_FORMAT_BGRX8888_A8:
++              ipu_cpmem_set_format_rgb(ch, &def_bgrx_32);
++              break;
++      case DRM_FORMAT_BGR888:
++      case DRM_FORMAT_BGR888_A8:
++              ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
++              break;
++      case DRM_FORMAT_RGB888:
++      case DRM_FORMAT_RGB888_A8:
++              ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
++              break;
++      case DRM_FORMAT_RGB565:
++      case DRM_FORMAT_RGB565_A8:
++              ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
++              break;
++      case DRM_FORMAT_BGR565:
++      case DRM_FORMAT_BGR565_A8:
++              ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
++              break;
++      case DRM_FORMAT_ARGB1555:
++              ipu_cpmem_set_format_rgb(ch, &def_argb_16);
++              break;
++      case DRM_FORMAT_ABGR1555:
++              ipu_cpmem_set_format_rgb(ch, &def_abgr_16);
++              break;
++      case DRM_FORMAT_RGBA5551:
++              ipu_cpmem_set_format_rgb(ch, &def_rgba_16);
++              break;
++      case DRM_FORMAT_BGRA5551:
++              ipu_cpmem_set_format_rgb(ch, &def_bgra_16);
++              break;
++      case DRM_FORMAT_ARGB4444:
++              ipu_cpmem_set_format_rgb(ch, &def_argb_16_4444);
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      switch (drm_fourcc) {
++      case DRM_FORMAT_RGB565_A8:
++      case DRM_FORMAT_BGR565_A8:
++      case DRM_FORMAT_RGB888_A8:
++      case DRM_FORMAT_BGR888_A8:
++      case DRM_FORMAT_RGBX8888_A8:
++      case DRM_FORMAT_BGRX8888_A8:
++              ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
++              ipu_cpmem_set_separate_alpha(ch);
++              break;
++      default:
++              break;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
++
++int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
++{
++      struct v4l2_pix_format *pix = &image->pix;
++      int offset, u_offset, v_offset;
++      int ret = 0;
++
++      pr_debug("%s: resolution: %dx%d stride: %d\n",
++               __func__, pix->width, pix->height,
++               pix->bytesperline);
++
++      ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
++      ipu_cpmem_set_stride(ch, pix->bytesperline);
++
++      ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
++
++      switch (pix->pixelformat) {
++      case V4L2_PIX_FMT_YUV420:
++              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
++              u_offset = image->u_offset ?
++                      image->u_offset : U_OFFSET(pix, image->rect.left,
++                                                 image->rect.top) - offset;
++              v_offset = image->v_offset ?
++                      image->v_offset : V_OFFSET(pix, image->rect.left,
++                                                 image->rect.top) - offset;
++
++              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
++                                            u_offset, v_offset);
++              break;
++      case V4L2_PIX_FMT_YVU420:
++              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
++              u_offset = image->u_offset ?
++                      image->u_offset : V_OFFSET(pix, image->rect.left,
++                                                 image->rect.top) - offset;
++              v_offset = image->v_offset ?
++                      image->v_offset : U_OFFSET(pix, image->rect.left,
++                                                 image->rect.top) - offset;
++
++              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
++                                            u_offset, v_offset);
++              break;
++      case V4L2_PIX_FMT_YUV422P:
++              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
++              u_offset = image->u_offset ?
++                      image->u_offset : U2_OFFSET(pix, image->rect.left,
++                                                  image->rect.top) - offset;
++              v_offset = image->v_offset ?
++                      image->v_offset : V2_OFFSET(pix, image->rect.left,
++                                                  image->rect.top) - offset;
++
++              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
++                                            u_offset, v_offset);
++              break;
++      case V4L2_PIX_FMT_NV12:
++              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
++              u_offset = image->u_offset ?
++                      image->u_offset : UV_OFFSET(pix, image->rect.left,
++                                                  image->rect.top) - offset;
++              v_offset = image->v_offset ? image->v_offset : 0;
++
++              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
++                                            u_offset, v_offset);
++              break;
++      case V4L2_PIX_FMT_NV16:
++              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
++              u_offset = image->u_offset ?
++                      image->u_offset : UV2_OFFSET(pix, image->rect.left,
++                                                   image->rect.top) - offset;
++              v_offset = image->v_offset ? image->v_offset : 0;
++
++              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
++                                            u_offset, v_offset);
++              break;
++      case V4L2_PIX_FMT_UYVY:
++      case V4L2_PIX_FMT_YUYV:
++      case V4L2_PIX_FMT_RGB565:
++              offset = image->rect.left * 2 +
++                      image->rect.top * pix->bytesperline;
++              break;
++      case V4L2_PIX_FMT_RGB32:
++      case V4L2_PIX_FMT_BGR32:
++      case V4L2_PIX_FMT_ABGR32:
++      case V4L2_PIX_FMT_XBGR32:
++      case V4L2_PIX_FMT_BGRA32:
++      case V4L2_PIX_FMT_BGRX32:
++      case V4L2_PIX_FMT_RGBA32:
++      case V4L2_PIX_FMT_RGBX32:
++      case V4L2_PIX_FMT_ARGB32:
++      case V4L2_PIX_FMT_XRGB32:
++              offset = image->rect.left * 4 +
++                      image->rect.top * pix->bytesperline;
++              break;
++      case V4L2_PIX_FMT_RGB24:
++      case V4L2_PIX_FMT_BGR24:
++              offset = image->rect.left * 3 +
++                      image->rect.top * pix->bytesperline;
++              break;
++      case V4L2_PIX_FMT_SBGGR8:
++      case V4L2_PIX_FMT_SGBRG8:
++      case V4L2_PIX_FMT_SGRBG8:
++      case V4L2_PIX_FMT_SRGGB8:
++      case V4L2_PIX_FMT_GREY:
++              offset = image->rect.left + image->rect.top * pix->bytesperline;
++              break;
++      case V4L2_PIX_FMT_SBGGR16:
++      case V4L2_PIX_FMT_SGBRG16:
++      case V4L2_PIX_FMT_SGRBG16:
++      case V4L2_PIX_FMT_SRGGB16:
++      case V4L2_PIX_FMT_Y16:
++              offset = image->rect.left * 2 +
++                       image->rect.top * pix->bytesperline;
++              break;
++      default:
++              /* This should not happen */
++              WARN_ON(1);
++              offset = 0;
++              ret = -EINVAL;
++      }
++
++      ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
++      ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
++
++void ipu_cpmem_dump(struct ipuv3_channel *ch)
++{
++      struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
++      struct ipu_soc *ipu = ch->ipu;
++      int chno = ch->num;
++
++      dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
++              readl(&p->word[0].data[0]),
++              readl(&p->word[0].data[1]),
++              readl(&p->word[0].data[2]),
++              readl(&p->word[0].data[3]),
++              readl(&p->word[0].data[4]));
++      dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
++              readl(&p->word[1].data[0]),
++              readl(&p->word[1].data[1]),
++              readl(&p->word[1].data[2]),
++              readl(&p->word[1].data[3]),
++              readl(&p->word[1].data[4]));
++      dev_dbg(ipu->dev, "PFS 0x%x, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
++      dev_dbg(ipu->dev, "BPP 0x%x, ",
++              ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
++      dev_dbg(ipu->dev, "NPB 0x%x\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
++
++      dev_dbg(ipu->dev, "FW %d, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_FW));
++      dev_dbg(ipu->dev, "FH %d, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_FH));
++      dev_dbg(ipu->dev, "EBA0 0x%x\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
++      dev_dbg(ipu->dev, "EBA1 0x%x\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
++      dev_dbg(ipu->dev, "Stride %d\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_SL));
++      dev_dbg(ipu->dev, "scan_order %d\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_SO));
++      dev_dbg(ipu->dev, "uv_stride %d\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
++      dev_dbg(ipu->dev, "u_offset 0x%x\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
++      dev_dbg(ipu->dev, "v_offset 0x%x\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
++
++      dev_dbg(ipu->dev, "Width0 %d+1, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
++      dev_dbg(ipu->dev, "Width1 %d+1, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
++      dev_dbg(ipu->dev, "Width2 %d+1, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
++      dev_dbg(ipu->dev, "Width3 %d+1, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
++      dev_dbg(ipu->dev, "Offset0 %d, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
++      dev_dbg(ipu->dev, "Offset1 %d, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
++      dev_dbg(ipu->dev, "Offset2 %d, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
++      dev_dbg(ipu->dev, "Offset3 %d\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
++
++int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
++{
++      struct ipu_cpmem *cpmem;
++
++      cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
++      if (!cpmem)
++              return -ENOMEM;
++
++      ipu->cpmem_priv = cpmem;
++
++      spin_lock_init(&cpmem->lock);
++      cpmem->base = devm_ioremap(dev, base, SZ_128K);
++      if (!cpmem->base)
++              return -ENOMEM;
++
++      dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
++              base, cpmem->base);
++      cpmem->ipu = ipu;
++
++      return 0;
++}
++
++void ipu_cpmem_exit(struct ipu_soc *ipu)
++{
++}
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/ipu-csi.c
+@@ -0,0 +1,821 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (C) 2012-2014 Mentor Graphics Inc.
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++#include <linux/export.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/videodev2.h>
++#include <uapi/linux/v4l2-mediabus.h>
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++#include <linux/clkdev.h>
++
++#include "ipu-prv.h"
++
++struct ipu_csi {
++      void __iomem *base;
++      int id;
++      u32 module;
++      struct clk *clk_ipu;    /* IPU bus clock */
++      spinlock_t lock;
++      bool inuse;
++      struct ipu_soc *ipu;
++};
++
++/* CSI Register Offsets */
++#define CSI_SENS_CONF         0x0000
++#define CSI_SENS_FRM_SIZE     0x0004
++#define CSI_ACT_FRM_SIZE      0x0008
++#define CSI_OUT_FRM_CTRL      0x000c
++#define CSI_TST_CTRL          0x0010
++#define CSI_CCIR_CODE_1               0x0014
++#define CSI_CCIR_CODE_2               0x0018
++#define CSI_CCIR_CODE_3               0x001c
++#define CSI_MIPI_DI           0x0020
++#define CSI_SKIP              0x0024
++#define CSI_CPD_CTRL          0x0028
++#define CSI_CPD_RC(n)         (0x002c + ((n)*4))
++#define CSI_CPD_RS(n)         (0x004c + ((n)*4))
++#define CSI_CPD_GRC(n)                (0x005c + ((n)*4))
++#define CSI_CPD_GRS(n)                (0x007c + ((n)*4))
++#define CSI_CPD_GBC(n)                (0x008c + ((n)*4))
++#define CSI_CPD_GBS(n)                (0x00Ac + ((n)*4))
++#define CSI_CPD_BC(n)         (0x00Bc + ((n)*4))
++#define CSI_CPD_BS(n)         (0x00Dc + ((n)*4))
++#define CSI_CPD_OFFSET1               0x00ec
++#define CSI_CPD_OFFSET2               0x00f0
++
++/* CSI Register Fields */
++#define CSI_SENS_CONF_DATA_FMT_SHIFT          8
++#define CSI_SENS_CONF_DATA_FMT_MASK           0x00000700
++#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444     0L
++#define CSI_SENS_CONF_DATA_FMT_YUV422_YUYV    1L
++#define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY    2L
++#define CSI_SENS_CONF_DATA_FMT_BAYER          3L
++#define CSI_SENS_CONF_DATA_FMT_RGB565         4L
++#define CSI_SENS_CONF_DATA_FMT_RGB555         5L
++#define CSI_SENS_CONF_DATA_FMT_RGB444         6L
++#define CSI_SENS_CONF_DATA_FMT_JPEG           7L
++
++#define CSI_SENS_CONF_VSYNC_POL_SHIFT         0
++#define CSI_SENS_CONF_HSYNC_POL_SHIFT         1
++#define CSI_SENS_CONF_DATA_POL_SHIFT          2
++#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT               3
++#define CSI_SENS_CONF_SENS_PRTCL_MASK         0x00000070
++#define CSI_SENS_CONF_SENS_PRTCL_SHIFT                4
++#define CSI_SENS_CONF_PACK_TIGHT_SHIFT                7
++#define CSI_SENS_CONF_DATA_WIDTH_SHIFT                11
++#define CSI_SENS_CONF_EXT_VSYNC_SHIFT         15
++#define CSI_SENS_CONF_DIVRATIO_SHIFT          16
++
++#define CSI_SENS_CONF_DIVRATIO_MASK           0x00ff0000
++#define CSI_SENS_CONF_DATA_DEST_SHIFT         24
++#define CSI_SENS_CONF_DATA_DEST_MASK          0x07000000
++#define CSI_SENS_CONF_JPEG8_EN_SHIFT          27
++#define CSI_SENS_CONF_JPEG_EN_SHIFT           28
++#define CSI_SENS_CONF_FORCE_EOF_SHIFT         29
++#define CSI_SENS_CONF_DATA_EN_POL_SHIFT               31
++
++#define CSI_DATA_DEST_IC                      2
++#define CSI_DATA_DEST_IDMAC                   4
++
++#define CSI_CCIR_ERR_DET_EN                   0x01000000
++#define CSI_HORI_DOWNSIZE_EN                  0x80000000
++#define CSI_VERT_DOWNSIZE_EN                  0x40000000
++#define CSI_TEST_GEN_MODE_EN                  0x01000000
++
++#define CSI_HSC_MASK                          0x1fff0000
++#define CSI_HSC_SHIFT                         16
++#define CSI_VSC_MASK                          0x00000fff
++#define CSI_VSC_SHIFT                         0
++
++#define CSI_TEST_GEN_R_MASK                   0x000000ff
++#define CSI_TEST_GEN_R_SHIFT                  0
++#define CSI_TEST_GEN_G_MASK                   0x0000ff00
++#define CSI_TEST_GEN_G_SHIFT                  8
++#define CSI_TEST_GEN_B_MASK                   0x00ff0000
++#define CSI_TEST_GEN_B_SHIFT                  16
++
++#define CSI_MAX_RATIO_SKIP_SMFC_MASK          0x00000007
++#define CSI_MAX_RATIO_SKIP_SMFC_SHIFT         0
++#define CSI_SKIP_SMFC_MASK                    0x000000f8
++#define CSI_SKIP_SMFC_SHIFT                   3
++#define CSI_ID_2_SKIP_MASK                    0x00000300
++#define CSI_ID_2_SKIP_SHIFT                   8
++
++#define CSI_COLOR_FIRST_ROW_MASK              0x00000002
++#define CSI_COLOR_FIRST_COMP_MASK             0x00000001
++
++/* MIPI CSI-2 data types */
++#define MIPI_DT_YUV420                0x18 /* YYY.../UYVY.... */
++#define MIPI_DT_YUV420_LEGACY 0x1a /* UYY.../VYY...   */
++#define MIPI_DT_YUV422                0x1e /* UYVY...         */
++#define MIPI_DT_RGB444                0x20
++#define MIPI_DT_RGB555                0x21
++#define MIPI_DT_RGB565                0x22
++#define MIPI_DT_RGB666                0x23
++#define MIPI_DT_RGB888                0x24
++#define MIPI_DT_RAW6          0x28
++#define MIPI_DT_RAW7          0x29
++#define MIPI_DT_RAW8          0x2a
++#define MIPI_DT_RAW10         0x2b
++#define MIPI_DT_RAW12         0x2c
++#define MIPI_DT_RAW14         0x2d
++
++/*
++ * Bitfield of CSI bus signal polarities and modes.
++ */
++struct ipu_csi_bus_config {
++      unsigned data_width:4;
++      unsigned clk_mode:3;
++      unsigned ext_vsync:1;
++      unsigned vsync_pol:1;
++      unsigned hsync_pol:1;
++      unsigned pixclk_pol:1;
++      unsigned data_pol:1;
++      unsigned sens_clksrc:1;
++      unsigned pack_tight:1;
++      unsigned force_eof:1;
++      unsigned data_en_pol:1;
++
++      unsigned data_fmt;
++      unsigned mipi_dt;
++};
++
++/*
++ * Enumeration of CSI data bus widths.
++ */
++enum ipu_csi_data_width {
++      IPU_CSI_DATA_WIDTH_4   = 0,
++      IPU_CSI_DATA_WIDTH_8   = 1,
++      IPU_CSI_DATA_WIDTH_10  = 3,
++      IPU_CSI_DATA_WIDTH_12  = 5,
++      IPU_CSI_DATA_WIDTH_16  = 9,
++};
++
++/*
++ * Enumeration of CSI clock modes.
++ */
++enum ipu_csi_clk_mode {
++      IPU_CSI_CLK_MODE_GATED_CLK,
++      IPU_CSI_CLK_MODE_NONGATED_CLK,
++      IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
++      IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
++      IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
++      IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
++      IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
++      IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
++};
++
++static inline u32 ipu_csi_read(struct ipu_csi *csi, unsigned offset)
++{
++      return readl(csi->base + offset);
++}
++
++static inline void ipu_csi_write(struct ipu_csi *csi, u32 value,
++                               unsigned offset)
++{
++      writel(value, csi->base + offset);
++}
++
++/*
++ * Set mclk division ratio for generating test mode mclk. Only used
++ * for test generator.
++ */
++static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk,
++                                      u32 ipu_clk)
++{
++      u32 temp;
++      int div_ratio;
++
++      div_ratio = (ipu_clk / pixel_clk) - 1;
++
++      if (div_ratio > 0xFF || div_ratio < 0) {
++              dev_err(csi->ipu->dev,
++                      "value of pixel_clk extends normal range\n");
++              return -EINVAL;
++      }
++
++      temp = ipu_csi_read(csi, CSI_SENS_CONF);
++      temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
++      ipu_csi_write(csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
++                        CSI_SENS_CONF);
++
++      return 0;
++}
++
++/*
++ * Find the CSI data format and data width for the given V4L2 media
++ * bus pixel format code.
++ */
++static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code,
++                              enum v4l2_mbus_type mbus_type)
++{
++      switch (mbus_code) {
++      case MEDIA_BUS_FMT_BGR565_2X8_BE:
++      case MEDIA_BUS_FMT_BGR565_2X8_LE:
++      case MEDIA_BUS_FMT_RGB565_2X8_BE:
++      case MEDIA_BUS_FMT_RGB565_2X8_LE:
++              if (mbus_type == V4L2_MBUS_CSI2_DPHY)
++                      cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
++              else
++                      cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
++              cfg->mipi_dt = MIPI_DT_RGB565;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE:
++      case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444;
++              cfg->mipi_dt = MIPI_DT_RGB444;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
++      case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
++              cfg->mipi_dt = MIPI_DT_RGB555;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_RGB888_1X24:
++      case MEDIA_BUS_FMT_BGR888_1X24:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
++              cfg->mipi_dt = MIPI_DT_RGB888;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_UYVY8_2X8:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
++              cfg->mipi_dt = MIPI_DT_YUV422;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_YUYV8_2X8:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
++              cfg->mipi_dt = MIPI_DT_YUV422;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_UYVY8_1X16:
++      case MEDIA_BUS_FMT_YUYV8_1X16:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
++              cfg->mipi_dt = MIPI_DT_YUV422;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_16;
++              break;
++      case MEDIA_BUS_FMT_SBGGR8_1X8:
++      case MEDIA_BUS_FMT_SGBRG8_1X8:
++      case MEDIA_BUS_FMT_SGRBG8_1X8:
++      case MEDIA_BUS_FMT_SRGGB8_1X8:
++      case MEDIA_BUS_FMT_Y8_1X8:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
++              cfg->mipi_dt = MIPI_DT_RAW8;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8:
++      case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
++      case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
++      case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8:
++      case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE:
++      case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE:
++      case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE:
++      case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
++              cfg->mipi_dt = MIPI_DT_RAW10;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_SBGGR10_1X10:
++      case MEDIA_BUS_FMT_SGBRG10_1X10:
++      case MEDIA_BUS_FMT_SGRBG10_1X10:
++      case MEDIA_BUS_FMT_SRGGB10_1X10:
++      case MEDIA_BUS_FMT_Y10_1X10:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
++              cfg->mipi_dt = MIPI_DT_RAW10;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_10;
++              break;
++      case MEDIA_BUS_FMT_SBGGR12_1X12:
++      case MEDIA_BUS_FMT_SGBRG12_1X12:
++      case MEDIA_BUS_FMT_SGRBG12_1X12:
++      case MEDIA_BUS_FMT_SRGGB12_1X12:
++      case MEDIA_BUS_FMT_Y12_1X12:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
++              cfg->mipi_dt = MIPI_DT_RAW12;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_12;
++              break;
++      case MEDIA_BUS_FMT_JPEG_1X8:
++              /* TODO */
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG;
++              cfg->mipi_dt = MIPI_DT_RAW8;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++/* translate alternate field mode based on given standard */
++static inline enum v4l2_field
++ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
++{
++      return (field != V4L2_FIELD_ALTERNATE) ? field :
++              ((std & V4L2_STD_525_60) ?
++               V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
++}
++
++/*
++ * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
++ */
++static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
++                          const struct v4l2_mbus_config *mbus_cfg,
++                          const struct v4l2_mbus_framefmt *mbus_fmt)
++{
++      int ret;
++
++      memset(csicfg, 0, sizeof(*csicfg));
++
++      ret = mbus_code_to_bus_cfg(csicfg, mbus_fmt->code, mbus_cfg->type);
++      if (ret < 0)
++              return ret;
++
++      switch (mbus_cfg->type) {
++      case V4L2_MBUS_PARALLEL:
++              csicfg->ext_vsync = 1;
++              csicfg->vsync_pol = (mbus_cfg->flags &
++                                   V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0;
++              csicfg->hsync_pol = (mbus_cfg->flags &
++                                   V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0;
++              csicfg->pixclk_pol = (mbus_cfg->flags &
++                                    V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0;
++              csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
++              break;
++      case V4L2_MBUS_BT656:
++              csicfg->ext_vsync = 0;
++              if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field) ||
++                  mbus_fmt->field == V4L2_FIELD_ALTERNATE)
++                      csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
++              else
++                      csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
++              break;
++      case V4L2_MBUS_CSI2_DPHY:
++              /*
++               * MIPI CSI-2 requires non gated clock mode, all other
++               * parameters are not applicable for MIPI CSI-2 bus.
++               */
++              csicfg->clk_mode = IPU_CSI_CLK_MODE_NONGATED_CLK;
++              break;
++      default:
++              /* will never get here, keep compiler quiet */
++              break;
++      }
++
++      return 0;
++}
++
++static int
++ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
++                              const struct v4l2_mbus_framefmt *infmt,
++                              const struct v4l2_mbus_framefmt *outfmt,
++                              v4l2_std_id std)
++{
++      enum v4l2_field infield, outfield;
++      bool swap_fields;
++
++      /* get translated field type of input and output */
++      infield = ipu_csi_translate_field(infmt->field, std);
++      outfield = ipu_csi_translate_field(outfmt->field, std);
++
++      /*
++       * Write the H-V-F codes the CSI will match against the
++       * incoming data for start/end of active and blanking
++       * field intervals. If input and output field types are
++       * sequential but not the same (one is SEQ_BT and the other
++       * is SEQ_TB), swap the F-bit so that the CSI will capture
++       * field 1 lines before field 0 lines.
++       */
++      swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
++                     V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
++                     infield != outfield);
++
++      if (!swap_fields) {
++              /*
++               * Field0BlankEnd  = 110, Field0BlankStart  = 010
++               * Field0ActiveEnd = 100, Field0ActiveStart = 000
++               * Field1BlankEnd  = 111, Field1BlankStart  = 011
++               * Field1ActiveEnd = 101, Field1ActiveStart = 001
++               */
++              ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
++                            CSI_CCIR_CODE_1);
++              ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
++      } else {
++              dev_dbg(csi->ipu->dev, "capture field swap\n");
++
++              /* same as above but with F-bit inverted */
++              ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
++                            CSI_CCIR_CODE_1);
++              ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
++      }
++
++      ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
++
++      return 0;
++}
++
++
++int ipu_csi_init_interface(struct ipu_csi *csi,
++                         const struct v4l2_mbus_config *mbus_cfg,
++                         const struct v4l2_mbus_framefmt *infmt,
++                         const struct v4l2_mbus_framefmt *outfmt)
++{
++      struct ipu_csi_bus_config cfg;
++      unsigned long flags;
++      u32 width, height, data = 0;
++      v4l2_std_id std;
++      int ret;
++
++      ret = fill_csi_bus_cfg(&cfg, mbus_cfg, infmt);
++      if (ret < 0)
++              return ret;
++
++      /* set default sensor frame width and height */
++      width = infmt->width;
++      height = infmt->height;
++      if (infmt->field == V4L2_FIELD_ALTERNATE)
++              height *= 2;
++
++      /* Set the CSI_SENS_CONF register remaining fields */
++      data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
++              cfg.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
++              cfg.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
++              cfg.vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
++              cfg.hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
++              cfg.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
++              cfg.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
++              cfg.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
++              cfg.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
++              cfg.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
++              cfg.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      ipu_csi_write(csi, data, CSI_SENS_CONF);
++
++      /* Set CCIR registers */
++
++      switch (cfg.clk_mode) {
++      case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
++              ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
++              ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
++              break;
++      case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
++              if (width == 720 && height == 480) {
++                      std = V4L2_STD_NTSC;
++                      height = 525;
++              } else if (width == 720 && height == 576) {
++                      std = V4L2_STD_PAL;
++                      height = 625;
++              } else {
++                      dev_err(csi->ipu->dev,
++                              "Unsupported interlaced video mode\n");
++                      ret = -EINVAL;
++                      goto out_unlock;
++              }
++
++              ret = ipu_csi_set_bt_interlaced_codes(csi, infmt, outfmt, std);
++              if (ret)
++                      goto out_unlock;
++              break;
++      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
++      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
++      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
++      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
++              ipu_csi_write(csi, 0x40030 | CSI_CCIR_ERR_DET_EN,
++                                 CSI_CCIR_CODE_1);
++              ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
++              break;
++      case IPU_CSI_CLK_MODE_GATED_CLK:
++      case IPU_CSI_CLK_MODE_NONGATED_CLK:
++              ipu_csi_write(csi, 0, CSI_CCIR_CODE_1);
++              break;
++      }
++
++      /* Setup sensor frame size */
++      ipu_csi_write(csi, (width - 1) | ((height - 1) << 16),
++                    CSI_SENS_FRM_SIZE);
++
++      dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
++              ipu_csi_read(csi, CSI_SENS_CONF));
++      dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
++              ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
++
++out_unlock:
++      spin_unlock_irqrestore(&csi->lock, flags);
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_csi_init_interface);
++
++bool ipu_csi_is_interlaced(struct ipu_csi *csi)
++{
++      unsigned long flags;
++      u32 sensor_protocol;
++
++      spin_lock_irqsave(&csi->lock, flags);
++      sensor_protocol =
++              (ipu_csi_read(csi, CSI_SENS_CONF) &
++               CSI_SENS_CONF_SENS_PRTCL_MASK) >>
++              CSI_SENS_CONF_SENS_PRTCL_SHIFT;
++      spin_unlock_irqrestore(&csi->lock, flags);
++
++      switch (sensor_protocol) {
++      case IPU_CSI_CLK_MODE_GATED_CLK:
++      case IPU_CSI_CLK_MODE_NONGATED_CLK:
++      case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
++      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
++      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
++              return false;
++      case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
++      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
++      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
++              return true;
++      default:
++              dev_err(csi->ipu->dev,
++                      "CSI %d sensor protocol unsupported\n", csi->id);
++              return false;
++      }
++}
++EXPORT_SYMBOL_GPL(ipu_csi_is_interlaced);
++
++void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w)
++{
++      unsigned long flags;
++      u32 reg;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE);
++      w->width = (reg & 0xFFFF) + 1;
++      w->height = (reg >> 16 & 0xFFFF) + 1;
++
++      reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
++      w->left = (reg & CSI_HSC_MASK) >> CSI_HSC_SHIFT;
++      w->top = (reg & CSI_VSC_MASK) >> CSI_VSC_SHIFT;
++
++      spin_unlock_irqrestore(&csi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_csi_get_window);
++
++void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w)
++{
++      unsigned long flags;
++      u32 reg;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      ipu_csi_write(csi, (w->width - 1) | ((w->height - 1) << 16),
++                        CSI_ACT_FRM_SIZE);
++
++      reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
++      reg &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
++      reg |= ((w->top << CSI_VSC_SHIFT) | (w->left << CSI_HSC_SHIFT));
++      ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
++
++      spin_unlock_irqrestore(&csi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_csi_set_window);
++
++void ipu_csi_set_downsize(struct ipu_csi *csi, bool horiz, bool vert)
++{
++      unsigned long flags;
++      u32 reg;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
++      reg &= ~(CSI_HORI_DOWNSIZE_EN | CSI_VERT_DOWNSIZE_EN);
++      reg |= (horiz ? CSI_HORI_DOWNSIZE_EN : 0) |
++             (vert ? CSI_VERT_DOWNSIZE_EN : 0);
++      ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
++
++      spin_unlock_irqrestore(&csi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_csi_set_downsize);
++
++void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
++                              u32 r_value, u32 g_value, u32 b_value,
++                              u32 pix_clk)
++{
++      unsigned long flags;
++      u32 ipu_clk = clk_get_rate(csi->clk_ipu);
++      u32 temp;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      temp = ipu_csi_read(csi, CSI_TST_CTRL);
++
++      if (!active) {
++              temp &= ~CSI_TEST_GEN_MODE_EN;
++              ipu_csi_write(csi, temp, CSI_TST_CTRL);
++      } else {
++              /* Set sensb_mclk div_ratio */
++              ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk);
++
++              temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
++                        CSI_TEST_GEN_B_MASK);
++              temp |= CSI_TEST_GEN_MODE_EN;
++              temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
++                      (g_value << CSI_TEST_GEN_G_SHIFT) |
++                      (b_value << CSI_TEST_GEN_B_SHIFT);
++              ipu_csi_write(csi, temp, CSI_TST_CTRL);
++      }
++
++      spin_unlock_irqrestore(&csi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator);
++
++int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
++                            struct v4l2_mbus_framefmt *mbus_fmt)
++{
++      struct ipu_csi_bus_config cfg;
++      unsigned long flags;
++      u32 temp;
++      int ret;
++
++      if (vc > 3)
++              return -EINVAL;
++
++      ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code, V4L2_MBUS_CSI2_DPHY);
++      if (ret < 0)
++              return ret;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      temp = ipu_csi_read(csi, CSI_MIPI_DI);
++      temp &= ~(0xff << (vc * 8));
++      temp |= (cfg.mipi_dt << (vc * 8));
++      ipu_csi_write(csi, temp, CSI_MIPI_DI);
++
++      spin_unlock_irqrestore(&csi->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype);
++
++int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
++                        u32 max_ratio, u32 id)
++{
++      unsigned long flags;
++      u32 temp;
++
++      if (max_ratio > 5 || id > 3)
++              return -EINVAL;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      temp = ipu_csi_read(csi, CSI_SKIP);
++      temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
++                CSI_SKIP_SMFC_MASK);
++      temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
++              (id << CSI_ID_2_SKIP_SHIFT) |
++              (skip << CSI_SKIP_SMFC_SHIFT);
++      ipu_csi_write(csi, temp, CSI_SKIP);
++
++      spin_unlock_irqrestore(&csi->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc);
++
++int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest)
++{
++      unsigned long flags;
++      u32 csi_sens_conf, dest;
++
++      if (csi_dest == IPU_CSI_DEST_IDMAC)
++              dest = CSI_DATA_DEST_IDMAC;
++      else
++              dest = CSI_DATA_DEST_IC; /* IC or VDIC */
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF);
++      csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
++      csi_sens_conf |= (dest << CSI_SENS_CONF_DATA_DEST_SHIFT);
++      ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF);
++
++      spin_unlock_irqrestore(&csi->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_csi_set_dest);
++
++int ipu_csi_enable(struct ipu_csi *csi)
++{
++      ipu_module_enable(csi->ipu, csi->module);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_csi_enable);
++
++int ipu_csi_disable(struct ipu_csi *csi)
++{
++      ipu_module_disable(csi->ipu, csi->module);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_csi_disable);
++
++struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id)
++{
++      unsigned long flags;
++      struct ipu_csi *csi, *ret;
++
++      if (id > 1)
++              return ERR_PTR(-EINVAL);
++
++      csi = ipu->csi_priv[id];
++      ret = csi;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      if (csi->inuse) {
++              ret = ERR_PTR(-EBUSY);
++              goto unlock;
++      }
++
++      csi->inuse = true;
++unlock:
++      spin_unlock_irqrestore(&csi->lock, flags);
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_csi_get);
++
++void ipu_csi_put(struct ipu_csi *csi)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&csi->lock, flags);
++      csi->inuse = false;
++      spin_unlock_irqrestore(&csi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_csi_put);
++
++int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
++               unsigned long base, u32 module, struct clk *clk_ipu)
++{
++      struct ipu_csi *csi;
++
++      if (id > 1)
++              return -ENODEV;
++
++      csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL);
++      if (!csi)
++              return -ENOMEM;
++
++      ipu->csi_priv[id] = csi;
++
++      spin_lock_init(&csi->lock);
++      csi->module = module;
++      csi->id = id;
++      csi->clk_ipu = clk_ipu;
++      csi->base = devm_ioremap(dev, base, PAGE_SIZE);
++      if (!csi->base)
++              return -ENOMEM;
++
++      dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n",
++              id, base, csi->base);
++      csi->ipu = ipu;
++
++      return 0;
++}
++
++void ipu_csi_exit(struct ipu_soc *ipu, int id)
++{
++}
++
++void ipu_csi_dump(struct ipu_csi *csi)
++{
++      dev_dbg(csi->ipu->dev, "CSI_SENS_CONF:     %08x\n",
++              ipu_csi_read(csi, CSI_SENS_CONF));
++      dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n",
++              ipu_csi_read(csi, CSI_SENS_FRM_SIZE));
++      dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE:  %08x\n",
++              ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
++      dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL:  %08x\n",
++              ipu_csi_read(csi, CSI_OUT_FRM_CTRL));
++      dev_dbg(csi->ipu->dev, "CSI_TST_CTRL:      %08x\n",
++              ipu_csi_read(csi, CSI_TST_CTRL));
++      dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1:   %08x\n",
++              ipu_csi_read(csi, CSI_CCIR_CODE_1));
++      dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2:   %08x\n",
++              ipu_csi_read(csi, CSI_CCIR_CODE_2));
++      dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3:   %08x\n",
++              ipu_csi_read(csi, CSI_CCIR_CODE_3));
++      dev_dbg(csi->ipu->dev, "CSI_MIPI_DI:       %08x\n",
++              ipu_csi_read(csi, CSI_MIPI_DI));
++      dev_dbg(csi->ipu->dev, "CSI_SKIP:          %08x\n",
++              ipu_csi_read(csi, CSI_SKIP));
++}
++EXPORT_SYMBOL_GPL(ipu_csi_dump);
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/ipu-dc.c
+@@ -0,0 +1,420 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++
++#include <linux/export.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++
++#include <video/imx-ipu-v3.h>
++#include "ipu-prv.h"
++
++#define DC_MAP_CONF_PTR(n)    (0x108 + ((n) & ~0x1) * 2)
++#define DC_MAP_CONF_VAL(n)    (0x144 + ((n) & ~0x1) * 2)
++
++#define DC_EVT_NF             0
++#define DC_EVT_NL             1
++#define DC_EVT_EOF            2
++#define DC_EVT_NFIELD         3
++#define DC_EVT_EOL            4
++#define DC_EVT_EOFIELD                5
++#define DC_EVT_NEW_ADDR               6
++#define DC_EVT_NEW_CHAN               7
++#define DC_EVT_NEW_DATA               8
++
++#define DC_EVT_NEW_ADDR_W_0   0
++#define DC_EVT_NEW_ADDR_W_1   1
++#define DC_EVT_NEW_CHAN_W_0   2
++#define DC_EVT_NEW_CHAN_W_1   3
++#define DC_EVT_NEW_DATA_W_0   4
++#define DC_EVT_NEW_DATA_W_1   5
++#define DC_EVT_NEW_ADDR_R_0   6
++#define DC_EVT_NEW_ADDR_R_1   7
++#define DC_EVT_NEW_CHAN_R_0   8
++#define DC_EVT_NEW_CHAN_R_1   9
++#define DC_EVT_NEW_DATA_R_0   10
++#define DC_EVT_NEW_DATA_R_1   11
++
++#define DC_WR_CH_CONF         0x0
++#define DC_WR_CH_ADDR         0x4
++#define DC_RL_CH(evt)         (8 + ((evt) & ~0x1) * 2)
++
++#define DC_GEN                        0xd4
++#define DC_DISP_CONF1(disp)   (0xd8 + (disp) * 4)
++#define DC_DISP_CONF2(disp)   (0xe8 + (disp) * 4)
++#define DC_STAT                       0x1c8
++
++#define WROD(lf)              (0x18 | ((lf) << 1))
++#define WRG                   0x01
++#define WCLK                  0xc9
++
++#define SYNC_WAVE 0
++#define NULL_WAVE (-1)
++
++#define DC_GEN_SYNC_1_6_SYNC  (2 << 1)
++#define DC_GEN_SYNC_PRIORITY_1        (1 << 7)
++
++#define DC_WR_CH_CONF_WORD_SIZE_8             (0 << 0)
++#define DC_WR_CH_CONF_WORD_SIZE_16            (1 << 0)
++#define DC_WR_CH_CONF_WORD_SIZE_24            (2 << 0)
++#define DC_WR_CH_CONF_WORD_SIZE_32            (3 << 0)
++#define DC_WR_CH_CONF_DISP_ID_PARALLEL(i)     (((i) & 0x1) << 3)
++#define DC_WR_CH_CONF_DISP_ID_SERIAL          (2 << 3)
++#define DC_WR_CH_CONF_DISP_ID_ASYNC           (3 << 4)
++#define DC_WR_CH_CONF_FIELD_MODE              (1 << 9)
++#define DC_WR_CH_CONF_PROG_TYPE_NORMAL                (4 << 5)
++#define DC_WR_CH_CONF_PROG_TYPE_MASK          (7 << 5)
++#define DC_WR_CH_CONF_PROG_DI_ID              (1 << 2)
++#define DC_WR_CH_CONF_PROG_DISP_ID(i)         (((i) & 0x1) << 3)
++
++#define IPU_DC_NUM_CHANNELS   10
++
++struct ipu_dc_priv;
++
++enum ipu_dc_map {
++      IPU_DC_MAP_RGB24,
++      IPU_DC_MAP_RGB565,
++      IPU_DC_MAP_GBR24, /* TVEv2 */
++      IPU_DC_MAP_BGR666,
++      IPU_DC_MAP_LVDS666,
++      IPU_DC_MAP_BGR24,
++};
++
++struct ipu_dc {
++      /* The display interface number assigned to this dc channel */
++      unsigned int            di;
++      void __iomem            *base;
++      struct ipu_dc_priv      *priv;
++      int                     chno;
++      bool                    in_use;
++};
++
++struct ipu_dc_priv {
++      void __iomem            *dc_reg;
++      void __iomem            *dc_tmpl_reg;
++      struct ipu_soc          *ipu;
++      struct device           *dev;
++      struct ipu_dc           channels[IPU_DC_NUM_CHANNELS];
++      struct mutex            mutex;
++      struct completion       comp;
++      int                     use_count;
++};
++
++static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
++{
++      u32 reg;
++
++      reg = readl(dc->base + DC_RL_CH(event));
++      reg &= ~(0xffff << (16 * (event & 0x1)));
++      reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
++      writel(reg, dc->base + DC_RL_CH(event));
++}
++
++static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
++              int map, int wave, int glue, int sync, int stop)
++{
++      struct ipu_dc_priv *priv = dc->priv;
++      u32 reg1, reg2;
++
++      if (opcode == WCLK) {
++              reg1 = (operand << 20) & 0xfff00000;
++              reg2 = operand >> 12 | opcode << 1 | stop << 9;
++      } else if (opcode == WRG) {
++              reg1 = sync | glue << 4 | ++wave << 11 | ((operand << 15) & 0xffff8000);
++              reg2 = operand >> 17 | opcode << 7 | stop << 9;
++      } else {
++              reg1 = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000);
++              reg2 = operand >> 12 | opcode << 4 | stop << 9;
++      }
++      writel(reg1, priv->dc_tmpl_reg + word * 8);
++      writel(reg2, priv->dc_tmpl_reg + word * 8 + 4);
++}
++
++static int ipu_bus_format_to_map(u32 fmt)
++{
++      switch (fmt) {
++      default:
++              WARN_ON(1);
++              /* fall-through */
++      case MEDIA_BUS_FMT_RGB888_1X24:
++              return IPU_DC_MAP_RGB24;
++      case MEDIA_BUS_FMT_RGB565_1X16:
++              return IPU_DC_MAP_RGB565;
++      case MEDIA_BUS_FMT_GBR888_1X24:
++              return IPU_DC_MAP_GBR24;
++      case MEDIA_BUS_FMT_RGB666_1X18:
++              return IPU_DC_MAP_BGR666;
++      case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
++              return IPU_DC_MAP_LVDS666;
++      case MEDIA_BUS_FMT_BGR888_1X24:
++              return IPU_DC_MAP_BGR24;
++      }
++}
++
++int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
++              u32 bus_format, u32 width)
++{
++      struct ipu_dc_priv *priv = dc->priv;
++      int addr, sync;
++      u32 reg = 0;
++      int map;
++
++      dc->di = ipu_di_get_num(di);
++
++      map = ipu_bus_format_to_map(bus_format);
++
++      /*
++       * In interlaced mode we need more counters to create the asymmetric
++       * per-field VSYNC signals. The pixel active signal synchronising DC
++       * to DI moves to signal generator #6 (see ipu-di.c). In progressive
++       * mode counter #5 is used.
++       */
++      sync = interlaced ? 6 : 5;
++
++      /* Reserve 5 microcode template words for each DI */
++      if (dc->di)
++              addr = 5;
++      else
++              addr = 0;
++
++      if (interlaced) {
++              dc_link_event(dc, DC_EVT_NL, addr, 3);
++              dc_link_event(dc, DC_EVT_EOL, addr, 2);
++              dc_link_event(dc, DC_EVT_NEW_DATA, addr, 1);
++
++              /* Init template microcode */
++              dc_write_tmpl(dc, addr, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
++      } else {
++              dc_link_event(dc, DC_EVT_NL, addr + 2, 3);
++              dc_link_event(dc, DC_EVT_EOL, addr + 3, 2);
++              dc_link_event(dc, DC_EVT_NEW_DATA, addr + 1, 1);
++
++              /* Init template microcode */
++              dc_write_tmpl(dc, addr + 2, WROD(0), 0, map, SYNC_WAVE, 8, sync, 1);
++              dc_write_tmpl(dc, addr + 3, WROD(0), 0, map, SYNC_WAVE, 4, sync, 0);
++              dc_write_tmpl(dc, addr + 4, WRG, 0, map, NULL_WAVE, 0, 0, 1);
++              dc_write_tmpl(dc, addr + 1, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
++      }
++
++      dc_link_event(dc, DC_EVT_NF, 0, 0);
++      dc_link_event(dc, DC_EVT_NFIELD, 0, 0);
++      dc_link_event(dc, DC_EVT_EOF, 0, 0);
++      dc_link_event(dc, DC_EVT_EOFIELD, 0, 0);
++      dc_link_event(dc, DC_EVT_NEW_CHAN, 0, 0);
++      dc_link_event(dc, DC_EVT_NEW_ADDR, 0, 0);
++
++      reg = readl(dc->base + DC_WR_CH_CONF);
++      if (interlaced)
++              reg |= DC_WR_CH_CONF_FIELD_MODE;
++      else
++              reg &= ~DC_WR_CH_CONF_FIELD_MODE;
++      writel(reg, dc->base + DC_WR_CH_CONF);
++
++      writel(0x0, dc->base + DC_WR_CH_ADDR);
++      writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
++
++void ipu_dc_enable(struct ipu_soc *ipu)
++{
++      struct ipu_dc_priv *priv = ipu->dc_priv;
++
++      mutex_lock(&priv->mutex);
++
++      if (!priv->use_count)
++              ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
++
++      priv->use_count++;
++
++      mutex_unlock(&priv->mutex);
++}
++EXPORT_SYMBOL_GPL(ipu_dc_enable);
++
++void ipu_dc_enable_channel(struct ipu_dc *dc)
++{
++      u32 reg;
++
++      reg = readl(dc->base + DC_WR_CH_CONF);
++      reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL;
++      writel(reg, dc->base + DC_WR_CH_CONF);
++}
++EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
++
++void ipu_dc_disable_channel(struct ipu_dc *dc)
++{
++      u32 val;
++
++      val = readl(dc->base + DC_WR_CH_CONF);
++      val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
++      writel(val, dc->base + DC_WR_CH_CONF);
++}
++EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
++
++void ipu_dc_disable(struct ipu_soc *ipu)
++{
++      struct ipu_dc_priv *priv = ipu->dc_priv;
++
++      mutex_lock(&priv->mutex);
++
++      priv->use_count--;
++      if (!priv->use_count)
++              ipu_module_disable(priv->ipu, IPU_CONF_DC_EN);
++
++      if (priv->use_count < 0)
++              priv->use_count = 0;
++
++      mutex_unlock(&priv->mutex);
++}
++EXPORT_SYMBOL_GPL(ipu_dc_disable);
++
++static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
++              int byte_num, int offset, int mask)
++{
++      int ptr = map * 3 + byte_num;
++      u32 reg;
++
++      reg = readl(priv->dc_reg + DC_MAP_CONF_VAL(ptr));
++      reg &= ~(0xffff << (16 * (ptr & 0x1)));
++      reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
++      writel(reg, priv->dc_reg + DC_MAP_CONF_VAL(ptr));
++
++      reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
++      reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
++      reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
++      writel(reg, priv->dc_reg + DC_MAP_CONF_PTR(map));
++}
++
++static void ipu_dc_map_clear(struct ipu_dc_priv *priv, int map)
++{
++      u32 reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
++
++      writel(reg & ~(0xffff << (16 * (map & 0x1))),
++                   priv->dc_reg + DC_MAP_CONF_PTR(map));
++}
++
++struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel)
++{
++      struct ipu_dc_priv *priv = ipu->dc_priv;
++      struct ipu_dc *dc;
++
++      if (channel >= IPU_DC_NUM_CHANNELS)
++              return ERR_PTR(-ENODEV);
++
++      dc = &priv->channels[channel];
++
++      mutex_lock(&priv->mutex);
++
++      if (dc->in_use) {
++              mutex_unlock(&priv->mutex);
++              return ERR_PTR(-EBUSY);
++      }
++
++      dc->in_use = true;
++
++      mutex_unlock(&priv->mutex);
++
++      return dc;
++}
++EXPORT_SYMBOL_GPL(ipu_dc_get);
++
++void ipu_dc_put(struct ipu_dc *dc)
++{
++      struct ipu_dc_priv *priv = dc->priv;
++
++      mutex_lock(&priv->mutex);
++      dc->in_use = false;
++      mutex_unlock(&priv->mutex);
++}
++EXPORT_SYMBOL_GPL(ipu_dc_put);
++
++int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
++              unsigned long base, unsigned long template_base)
++{
++      struct ipu_dc_priv *priv;
++      static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
++              0x78, 0, 0x94, 0xb4};
++      int i;
++
++      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++
++      mutex_init(&priv->mutex);
++
++      priv->dev = dev;
++      priv->ipu = ipu;
++      priv->dc_reg = devm_ioremap(dev, base, PAGE_SIZE);
++      priv->dc_tmpl_reg = devm_ioremap(dev, template_base, PAGE_SIZE);
++      if (!priv->dc_reg || !priv->dc_tmpl_reg)
++              return -ENOMEM;
++
++      for (i = 0; i < IPU_DC_NUM_CHANNELS; i++) {
++              priv->channels[i].chno = i;
++              priv->channels[i].priv = priv;
++              priv->channels[i].base = priv->dc_reg + channel_offsets[i];
++      }
++
++      writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
++                      DC_WR_CH_CONF_PROG_DI_ID,
++                      priv->channels[1].base + DC_WR_CH_CONF);
++      writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0),
++                      priv->channels[5].base + DC_WR_CH_CONF);
++
++      writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1,
++              priv->dc_reg + DC_GEN);
++
++      ipu->dc_priv = priv;
++
++      dev_dbg(dev, "DC base: 0x%08lx template base: 0x%08lx\n",
++                      base, template_base);
++
++      /* rgb24 */
++      ipu_dc_map_clear(priv, IPU_DC_MAP_RGB24);
++      ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 0, 7, 0xff); /* blue */
++      ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 1, 15, 0xff); /* green */
++      ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 2, 23, 0xff); /* red */
++
++      /* rgb565 */
++      ipu_dc_map_clear(priv, IPU_DC_MAP_RGB565);
++      ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 0, 4, 0xf8); /* blue */
++      ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc); /* green */
++      ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8); /* red */
++
++      /* gbr24 */
++      ipu_dc_map_clear(priv, IPU_DC_MAP_GBR24);
++      ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 2, 15, 0xff); /* green */
++      ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 1, 7, 0xff); /* blue */
++      ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 0, 23, 0xff); /* red */
++
++      /* bgr666 */
++      ipu_dc_map_clear(priv, IPU_DC_MAP_BGR666);
++      ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 0, 5, 0xfc); /* blue */
++      ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc); /* green */
++      ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc); /* red */
++
++      /* lvds666 */
++      ipu_dc_map_clear(priv, IPU_DC_MAP_LVDS666);
++      ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 0, 5, 0xfc); /* blue */
++      ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 1, 13, 0xfc); /* green */
++      ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 2, 21, 0xfc); /* red */
++
++      /* bgr24 */
++      ipu_dc_map_clear(priv, IPU_DC_MAP_BGR24);
++      ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 2, 7, 0xff); /* red */
++      ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */
++      ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */
++
++      return 0;
++}
++
++void ipu_dc_exit(struct ipu_soc *ipu)
++{
++}
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/ipu-di.c
+@@ -0,0 +1,745 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++#include <linux/export.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++
++#include <video/imx-ipu-v3.h>
++#include "ipu-prv.h"
++
++struct ipu_di {
++      void __iomem *base;
++      int id;
++      u32 module;
++      struct clk *clk_di;     /* display input clock */
++      struct clk *clk_ipu;    /* IPU bus clock */
++      struct clk *clk_di_pixel; /* resulting pixel clock */
++      bool inuse;
++      struct ipu_soc *ipu;
++};
++
++static DEFINE_MUTEX(di_mutex);
++
++struct di_sync_config {
++      int run_count;
++      int run_src;
++      int offset_count;
++      int offset_src;
++      int repeat_count;
++      int cnt_clr_src;
++      int cnt_polarity_gen_en;
++      int cnt_polarity_clr_src;
++      int cnt_polarity_trigger_src;
++      int cnt_up;
++      int cnt_down;
++};
++
++enum di_pins {
++      DI_PIN11 = 0,
++      DI_PIN12 = 1,
++      DI_PIN13 = 2,
++      DI_PIN14 = 3,
++      DI_PIN15 = 4,
++      DI_PIN16 = 5,
++      DI_PIN17 = 6,
++      DI_PIN_CS = 7,
++
++      DI_PIN_SER_CLK = 0,
++      DI_PIN_SER_RS = 1,
++};
++
++enum di_sync_wave {
++      DI_SYNC_NONE = 0,
++      DI_SYNC_CLK = 1,
++      DI_SYNC_INT_HSYNC = 2,
++      DI_SYNC_HSYNC = 3,
++      DI_SYNC_VSYNC = 4,
++      DI_SYNC_DE = 6,
++
++      DI_SYNC_CNT1 = 2,       /* counter >= 2 only */
++      DI_SYNC_CNT4 = 5,       /* counter >= 5 only */
++      DI_SYNC_CNT5 = 6,       /* counter >= 6 only */
++};
++
++#define SYNC_WAVE 0
++
++#define DI_GENERAL            0x0000
++#define DI_BS_CLKGEN0         0x0004
++#define DI_BS_CLKGEN1         0x0008
++#define DI_SW_GEN0(gen)               (0x000c + 4 * ((gen) - 1))
++#define DI_SW_GEN1(gen)               (0x0030 + 4 * ((gen) - 1))
++#define DI_STP_REP(gen)               (0x0148 + 4 * (((gen) - 1)/2))
++#define DI_SYNC_AS_GEN                0x0054
++#define DI_DW_GEN(gen)                (0x0058 + 4 * (gen))
++#define DI_DW_SET(gen, set)   (0x0088 + 4 * ((gen) + 0xc * (set)))
++#define DI_SER_CONF           0x015c
++#define DI_SSC                        0x0160
++#define DI_POL                        0x0164
++#define DI_AW0                        0x0168
++#define DI_AW1                        0x016c
++#define DI_SCR_CONF           0x0170
++#define DI_STAT                       0x0174
++
++#define DI_SW_GEN0_RUN_COUNT(x)                       ((x) << 19)
++#define DI_SW_GEN0_RUN_SRC(x)                 ((x) << 16)
++#define DI_SW_GEN0_OFFSET_COUNT(x)            ((x) << 3)
++#define DI_SW_GEN0_OFFSET_SRC(x)              ((x) << 0)
++
++#define DI_SW_GEN1_CNT_POL_GEN_EN(x)          ((x) << 29)
++#define DI_SW_GEN1_CNT_CLR_SRC(x)             ((x) << 25)
++#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x)     ((x) << 12)
++#define DI_SW_GEN1_CNT_POL_CLR_SRC(x)         ((x) << 9)
++#define DI_SW_GEN1_CNT_DOWN(x)                        ((x) << 16)
++#define DI_SW_GEN1_CNT_UP(x)                  (x)
++#define DI_SW_GEN1_AUTO_RELOAD                        (0x10000000)
++
++#define DI_DW_GEN_ACCESS_SIZE_OFFSET          24
++#define DI_DW_GEN_COMPONENT_SIZE_OFFSET               16
++
++#define DI_GEN_POLARITY_1                     (1 << 0)
++#define DI_GEN_POLARITY_2                     (1 << 1)
++#define DI_GEN_POLARITY_3                     (1 << 2)
++#define DI_GEN_POLARITY_4                     (1 << 3)
++#define DI_GEN_POLARITY_5                     (1 << 4)
++#define DI_GEN_POLARITY_6                     (1 << 5)
++#define DI_GEN_POLARITY_7                     (1 << 6)
++#define DI_GEN_POLARITY_8                     (1 << 7)
++#define DI_GEN_POLARITY_DISP_CLK              (1 << 17)
++#define DI_GEN_DI_CLK_EXT                     (1 << 20)
++#define DI_GEN_DI_VSYNC_EXT                   (1 << 21)
++
++#define DI_POL_DRDY_DATA_POLARITY             (1 << 7)
++#define DI_POL_DRDY_POLARITY_15                       (1 << 4)
++
++#define DI_VSYNC_SEL_OFFSET                   13
++
++static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
++{
++      return readl(di->base + offset);
++}
++
++static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
++{
++      writel(value, di->base + offset);
++}
++
++static void ipu_di_data_wave_config(struct ipu_di *di,
++                                   int wave_gen,
++                                   int access_size, int component_size)
++{
++      u32 reg;
++      reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
++          (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
++      ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
++}
++
++static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin,
++              int set, int up, int down)
++{
++      u32 reg;
++
++      reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
++      reg &= ~(0x3 << (di_pin * 2));
++      reg |= set << (di_pin * 2);
++      ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
++
++      ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
++}
++
++static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config,
++              int start, int count)
++{
++      u32 reg;
++      int i;
++
++      for (i = 0; i < count; i++) {
++              struct di_sync_config *c = &config[i];
++              int wave_gen = start + i + 1;
++
++              if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) ||
++                              (c->repeat_count >= 0x1000) ||
++                              (c->cnt_up >= 0x400) ||
++                              (c->cnt_down >= 0x400)) {
++                      dev_err(di->ipu->dev, "DI%d counters out of range.\n",
++                                      di->id);
++                      return;
++              }
++
++              reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
++                      DI_SW_GEN0_RUN_SRC(c->run_src) |
++                      DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
++                      DI_SW_GEN0_OFFSET_SRC(c->offset_src);
++              ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
++
++              reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
++                      DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
++                      DI_SW_GEN1_CNT_POL_TRIGGER_SRC(
++                                      c->cnt_polarity_trigger_src) |
++                      DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
++                      DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
++                      DI_SW_GEN1_CNT_UP(c->cnt_up);
++
++              /* Enable auto reload */
++              if (c->repeat_count == 0)
++                      reg |= DI_SW_GEN1_AUTO_RELOAD;
++
++              ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
++
++              reg = ipu_di_read(di, DI_STP_REP(wave_gen));
++              reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
++              reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
++              ipu_di_write(di, reg, DI_STP_REP(wave_gen));
++      }
++}
++
++static void ipu_di_sync_config_interlaced(struct ipu_di *di,
++              struct ipu_di_signal_cfg *sig)
++{
++      u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
++              sig->mode.hback_porch + sig->mode.hfront_porch;
++      u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
++              sig->mode.vback_porch + sig->mode.vfront_porch;
++      struct di_sync_config cfg[] = {
++              {
++                      /* 1: internal VSYNC for each frame */
++                      .run_count = v_total * 2 - 1,
++                      .run_src = 3,                   /* == counter 7 */
++              }, {
++                      /* PIN2: HSYNC waveform */
++                      .run_count = h_total - 1,
++                      .run_src = DI_SYNC_CLK,
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
++                      .cnt_down = sig->mode.hsync_len * 2,
++              }, {
++                      /* PIN3: VSYNC waveform */
++                      .run_count = v_total - 1,
++                      .run_src = 4,                   /* == counter 7 */
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = 4,  /* == counter 7 */
++                      .cnt_down = sig->mode.vsync_len * 2,
++                      .cnt_clr_src = DI_SYNC_CNT1,
++              }, {
++                      /* 4: Field */
++                      .run_count = v_total / 2,
++                      .run_src = DI_SYNC_HSYNC,
++                      .offset_count = h_total / 2,
++                      .offset_src = DI_SYNC_CLK,
++                      .repeat_count = 2,
++                      .cnt_clr_src = DI_SYNC_CNT1,
++              }, {
++                      /* 5: Active lines */
++                      .run_src = DI_SYNC_HSYNC,
++                      .offset_count = (sig->mode.vsync_len +
++                                       sig->mode.vback_porch) / 2,
++                      .offset_src = DI_SYNC_HSYNC,
++                      .repeat_count = sig->mode.vactive / 2,
++                      .cnt_clr_src = DI_SYNC_CNT4,
++              }, {
++                      /* 6: Active pixel, referenced by DC */
++                      .run_src = DI_SYNC_CLK,
++                      .offset_count = sig->mode.hsync_len +
++                                      sig->mode.hback_porch,
++                      .offset_src = DI_SYNC_CLK,
++                      .repeat_count = sig->mode.hactive,
++                      .cnt_clr_src = DI_SYNC_CNT5,
++              }, {
++                      /* 7: Half line HSYNC */
++                      .run_count = h_total / 2 - 1,
++                      .run_src = DI_SYNC_CLK,
++              }
++      };
++
++      ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
++
++      ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
++}
++
++static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
++              struct ipu_di_signal_cfg *sig, int div)
++{
++      u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
++              sig->mode.hback_porch + sig->mode.hfront_porch;
++      u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
++              sig->mode.vback_porch + sig->mode.vfront_porch;
++      struct di_sync_config cfg[] = {
++              {
++                      /* 1: INT_HSYNC */
++                      .run_count = h_total - 1,
++                      .run_src = DI_SYNC_CLK,
++              } , {
++                      /* PIN2: HSYNC */
++                      .run_count = h_total - 1,
++                      .run_src = DI_SYNC_CLK,
++                      .offset_count = div * sig->v_to_h_sync,
++                      .offset_src = DI_SYNC_CLK,
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
++                      .cnt_down = sig->mode.hsync_len * 2,
++              } , {
++                      /* PIN3: VSYNC */
++                      .run_count = v_total - 1,
++                      .run_src = DI_SYNC_INT_HSYNC,
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
++                      .cnt_down = sig->mode.vsync_len * 2,
++              } , {
++                      /* 4: Line Active */
++                      .run_src = DI_SYNC_HSYNC,
++                      .offset_count = sig->mode.vsync_len +
++                                      sig->mode.vback_porch,
++                      .offset_src = DI_SYNC_HSYNC,
++                      .repeat_count = sig->mode.vactive,
++                      .cnt_clr_src = DI_SYNC_VSYNC,
++              } , {
++                      /* 5: Pixel Active, referenced by DC */
++                      .run_src = DI_SYNC_CLK,
++                      .offset_count = sig->mode.hsync_len +
++                                      sig->mode.hback_porch,
++                      .offset_src = DI_SYNC_CLK,
++                      .repeat_count = sig->mode.hactive,
++                      .cnt_clr_src = 5, /* Line Active */
++              } , {
++                      /* unused */
++              } , {
++                      /* unused */
++              } , {
++                      /* unused */
++              } , {
++                      /* unused */
++              },
++      };
++      /* can't use #7 and #8 for line active and pixel active counters */
++      struct di_sync_config cfg_vga[] = {
++              {
++                      /* 1: INT_HSYNC */
++                      .run_count = h_total - 1,
++                      .run_src = DI_SYNC_CLK,
++              } , {
++                      /* 2: VSYNC */
++                      .run_count = v_total - 1,
++                      .run_src = DI_SYNC_INT_HSYNC,
++              } , {
++                      /* 3: Line Active */
++                      .run_src = DI_SYNC_INT_HSYNC,
++                      .offset_count = sig->mode.vsync_len +
++                                      sig->mode.vback_porch,
++                      .offset_src = DI_SYNC_INT_HSYNC,
++                      .repeat_count = sig->mode.vactive,
++                      .cnt_clr_src = 3 /* VSYNC */,
++              } , {
++                      /* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
++                      .run_count = h_total - 1,
++                      .run_src = DI_SYNC_CLK,
++                      .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
++                      .offset_src = DI_SYNC_CLK,
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
++                      .cnt_down = sig->mode.hsync_len * 2,
++              } , {
++                      /* 5: Pixel Active signal to DC */
++                      .run_src = DI_SYNC_CLK,
++                      .offset_count = sig->mode.hsync_len +
++                                      sig->mode.hback_porch,
++                      .offset_src = DI_SYNC_CLK,
++                      .repeat_count = sig->mode.hactive,
++                      .cnt_clr_src = 4, /* Line Active */
++              } , {
++                      /* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
++                      .run_count = v_total - 1,
++                      .run_src = DI_SYNC_INT_HSYNC,
++                      .offset_count = 1, /* magic value from Freescale TVE driver */
++                      .offset_src = DI_SYNC_INT_HSYNC,
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
++                      .cnt_down = sig->mode.vsync_len * 2,
++              } , {
++                      /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
++                      .run_count = h_total - 1,
++                      .run_src = DI_SYNC_CLK,
++                      .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
++                      .offset_src = DI_SYNC_CLK,
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
++                      .cnt_down = sig->mode.hsync_len * 2,
++              } , {
++                      /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
++                      .run_count = v_total - 1,
++                      .run_src = DI_SYNC_INT_HSYNC,
++                      .offset_count = 1, /* magic value from Freescale TVE driver */
++                      .offset_src = DI_SYNC_INT_HSYNC,
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
++                      .cnt_down = sig->mode.vsync_len * 2,
++              } , {
++                      /* unused */
++              },
++      };
++
++      ipu_di_write(di, v_total - 1, DI_SCR_CONF);
++      if (sig->hsync_pin == 2 && sig->vsync_pin == 3)
++              ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
++      else
++              ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
++}
++
++static void ipu_di_config_clock(struct ipu_di *di,
++      const struct ipu_di_signal_cfg *sig)
++{
++      struct clk *clk;
++      unsigned clkgen0;
++      uint32_t val;
++
++      if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
++              /*
++               * CLKMODE_EXT means we must use the DI clock: this is
++               * needed for things like LVDS which needs to feed the
++               * DI and LDB with the same pixel clock.
++               */
++              clk = di->clk_di;
++
++              if (sig->clkflags & IPU_DI_CLKMODE_SYNC) {
++                      /*
++                       * CLKMODE_SYNC means that we want the DI to be
++                       * clocked at the same rate as the parent clock.
++                       * This is needed (eg) for LDB which needs to be
++                       * fed with the same pixel clock.  We assume that
++                       * the LDB clock has already been set correctly.
++                       */
++                      clkgen0 = 1 << 4;
++              } else {
++                      /*
++                       * We can use the divider.  We should really have
++                       * a flag here indicating whether the bridge can
++                       * cope with a fractional divider or not.  For the
++                       * time being, let's go for simplicitly and
++                       * reliability.
++                       */
++                      unsigned long in_rate;
++                      unsigned div;
++
++                      clk_set_rate(clk, sig->mode.pixelclock);
++
++                      in_rate = clk_get_rate(clk);
++                      div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
++                      div = clamp(div, 1U, 255U);
++
++                      clkgen0 = div << 4;
++              }
++      } else {
++              /*
++               * For other interfaces, we can arbitarily select between
++               * the DI specific clock and the internal IPU clock.  See
++               * DI_GENERAL bit 20.  We select the IPU clock if it can
++               * give us a clock rate within 1% of the requested frequency,
++               * otherwise we use the DI clock.
++               */
++              unsigned long rate, clkrate;
++              unsigned div, error;
++
++              clkrate = clk_get_rate(di->clk_ipu);
++              div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
++              div = clamp(div, 1U, 255U);
++              rate = clkrate / div;
++
++              error = rate / (sig->mode.pixelclock / 1000);
++
++              dev_dbg(di->ipu->dev, "  IPU clock can give %lu with divider %u, error %d.%u%%\n",
++                      rate, div, (signed)(error - 1000) / 10, error % 10);
++
++              /* Allow a 1% error */
++              if (error < 1010 && error >= 990) {
++                      clk = di->clk_ipu;
++
++                      clkgen0 = div << 4;
++              } else {
++                      unsigned long in_rate;
++                      unsigned div;
++
++                      clk = di->clk_di;
++
++                      clk_set_rate(clk, sig->mode.pixelclock);
++
++                      in_rate = clk_get_rate(clk);
++                      div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
++                      div = clamp(div, 1U, 255U);
++
++                      clkgen0 = div << 4;
++              }
++      }
++
++      di->clk_di_pixel = clk;
++
++      /* Set the divider */
++      ipu_di_write(di, clkgen0, DI_BS_CLKGEN0);
++
++      /*
++       * Set the high/low periods.  Bits 24:16 give us the falling edge,
++       * and bits 8:0 give the rising edge.  LSB is fraction, and is
++       * based on the divider above.  We want a 50% duty cycle, so set
++       * the falling edge to be half the divider.
++       */
++      ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1);
++
++      /* Finally select the input clock */
++      val = ipu_di_read(di, DI_GENERAL) & ~DI_GEN_DI_CLK_EXT;
++      if (clk == di->clk_di)
++              val |= DI_GEN_DI_CLK_EXT;
++      ipu_di_write(di, val, DI_GENERAL);
++
++      dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
++              sig->mode.pixelclock,
++              clk_get_rate(di->clk_ipu),
++              clk_get_rate(di->clk_di),
++              clk == di->clk_di ? "DI" : "IPU",
++              clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
++}
++
++/*
++ * This function is called to adjust a video mode to IPU restrictions.
++ * It is meant to be called from drm crtc mode_fixup() methods.
++ */
++int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode)
++{
++      u32 diff;
++
++      if (mode->vfront_porch >= 2)
++              return 0;
++
++      diff = 2 - mode->vfront_porch;
++
++      if (mode->vback_porch >= diff) {
++              mode->vfront_porch = 2;
++              mode->vback_porch -= diff;
++      } else if (mode->vsync_len > diff) {
++              mode->vfront_porch = 2;
++              mode->vsync_len = mode->vsync_len - diff;
++      } else {
++              dev_warn(di->ipu->dev, "failed to adjust videomode\n");
++              return -EINVAL;
++      }
++
++      dev_dbg(di->ipu->dev, "videomode adapted for IPU restrictions\n");
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode);
++
++static u32 ipu_di_gen_polarity(int pin)
++{
++      switch (pin) {
++      case 1:
++              return DI_GEN_POLARITY_1;
++      case 2:
++              return DI_GEN_POLARITY_2;
++      case 3:
++              return DI_GEN_POLARITY_3;
++      case 4:
++              return DI_GEN_POLARITY_4;
++      case 5:
++              return DI_GEN_POLARITY_5;
++      case 6:
++              return DI_GEN_POLARITY_6;
++      case 7:
++              return DI_GEN_POLARITY_7;
++      case 8:
++              return DI_GEN_POLARITY_8;
++      }
++      return 0;
++}
++
++int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
++{
++      u32 reg;
++      u32 di_gen, vsync_cnt;
++      u32 div;
++
++      dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
++              di->id, sig->mode.hactive, sig->mode.vactive);
++
++      dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
++              clk_get_rate(di->clk_ipu),
++              clk_get_rate(di->clk_di),
++              sig->mode.pixelclock);
++
++      mutex_lock(&di_mutex);
++
++      ipu_di_config_clock(di, sig);
++
++      div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
++      div = div / 16;         /* Now divider is integer portion */
++
++      /* Setup pixel clock timing */
++      /* Down time is half of period */
++      ipu_di_write(di, (div << 16), DI_BS_CLKGEN1);
++
++      ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1);
++      ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
++
++      di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
++      di_gen |= DI_GEN_DI_VSYNC_EXT;
++
++      if (sig->mode.flags & DISPLAY_FLAGS_INTERLACED) {
++              ipu_di_sync_config_interlaced(di, sig);
++
++              /* set y_sel = 1 */
++              di_gen |= 0x10000000;
++
++              vsync_cnt = 3;
++      } else {
++              ipu_di_sync_config_noninterlaced(di, sig, div);
++
++              vsync_cnt = 3;
++              if (di->id == 1)
++                      /*
++                       * TODO: change only for TVEv2, parallel display
++                       * uses pin 2 / 3
++                       */
++                      if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3))
++                              vsync_cnt = 6;
++      }
++
++      if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH)
++              di_gen |= ipu_di_gen_polarity(sig->hsync_pin);
++      if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH)
++              di_gen |= ipu_di_gen_polarity(sig->vsync_pin);
++
++      if (sig->clk_pol)
++              di_gen |= DI_GEN_POLARITY_DISP_CLK;
++
++      ipu_di_write(di, di_gen, DI_GENERAL);
++
++      ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
++                   DI_SYNC_AS_GEN);
++
++      reg = ipu_di_read(di, DI_POL);
++      reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
++
++      if (sig->enable_pol)
++              reg |= DI_POL_DRDY_POLARITY_15;
++      if (sig->data_pol)
++              reg |= DI_POL_DRDY_DATA_POLARITY;
++
++      ipu_di_write(di, reg, DI_POL);
++
++      mutex_unlock(&di_mutex);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
++
++int ipu_di_enable(struct ipu_di *di)
++{
++      int ret;
++
++      WARN_ON(IS_ERR(di->clk_di_pixel));
++
++      ret = clk_prepare_enable(di->clk_di_pixel);
++      if (ret)
++              return ret;
++
++      ipu_module_enable(di->ipu, di->module);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_di_enable);
++
++int ipu_di_disable(struct ipu_di *di)
++{
++      WARN_ON(IS_ERR(di->clk_di_pixel));
++
++      ipu_module_disable(di->ipu, di->module);
++
++      clk_disable_unprepare(di->clk_di_pixel);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_di_disable);
++
++int ipu_di_get_num(struct ipu_di *di)
++{
++      return di->id;
++}
++EXPORT_SYMBOL_GPL(ipu_di_get_num);
++
++static DEFINE_MUTEX(ipu_di_lock);
++
++struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp)
++{
++      struct ipu_di *di;
++
++      if (disp > 1)
++              return ERR_PTR(-EINVAL);
++
++      di = ipu->di_priv[disp];
++
++      mutex_lock(&ipu_di_lock);
++
++      if (di->inuse) {
++              di = ERR_PTR(-EBUSY);
++              goto out;
++      }
++
++      di->inuse = true;
++out:
++      mutex_unlock(&ipu_di_lock);
++
++      return di;
++}
++EXPORT_SYMBOL_GPL(ipu_di_get);
++
++void ipu_di_put(struct ipu_di *di)
++{
++      mutex_lock(&ipu_di_lock);
++
++      di->inuse = false;
++
++      mutex_unlock(&ipu_di_lock);
++}
++EXPORT_SYMBOL_GPL(ipu_di_put);
++
++int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
++              unsigned long base,
++              u32 module, struct clk *clk_ipu)
++{
++      struct ipu_di *di;
++
++      if (id > 1)
++              return -ENODEV;
++
++      di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
++      if (!di)
++              return -ENOMEM;
++
++      ipu->di_priv[id] = di;
++
++      di->clk_di = devm_clk_get(dev, id ? "di1" : "di0");
++      if (IS_ERR(di->clk_di))
++              return PTR_ERR(di->clk_di);
++
++      di->module = module;
++      di->id = id;
++      di->clk_ipu = clk_ipu;
++      di->base = devm_ioremap(dev, base, PAGE_SIZE);
++      if (!di->base)
++              return -ENOMEM;
++
++      ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
++
++      dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n",
++                      id, base, di->base);
++      di->inuse = false;
++      di->ipu = ipu;
++
++      return 0;
++}
++
++void ipu_di_exit(struct ipu_soc *ipu, int id)
++{
++}
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/ipu-dmfc.c
+@@ -0,0 +1,214 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++#include <linux/export.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/io.h>
++
++#include <video/imx-ipu-v3.h>
++#include "ipu-prv.h"
++
++#define DMFC_RD_CHAN          0x0000
++#define DMFC_WR_CHAN          0x0004
++#define DMFC_WR_CHAN_DEF      0x0008
++#define DMFC_DP_CHAN          0x000c
++#define DMFC_DP_CHAN_DEF      0x0010
++#define DMFC_GENERAL1         0x0014
++#define DMFC_GENERAL2         0x0018
++#define DMFC_IC_CTRL          0x001c
++#define DMFC_WR_CHAN_ALT      0x0020
++#define DMFC_WR_CHAN_DEF_ALT  0x0024
++#define DMFC_DP_CHAN_ALT      0x0028
++#define DMFC_DP_CHAN_DEF_ALT  0x002c
++#define DMFC_GENERAL1_ALT     0x0030
++#define DMFC_STAT             0x0034
++
++#define DMFC_WR_CHAN_1_28             0
++#define DMFC_WR_CHAN_2_41             8
++#define DMFC_WR_CHAN_1C_42            16
++#define DMFC_WR_CHAN_2C_43            24
++
++#define DMFC_DP_CHAN_5B_23            0
++#define DMFC_DP_CHAN_5F_27            8
++#define DMFC_DP_CHAN_6B_24            16
++#define DMFC_DP_CHAN_6F_29            24
++
++struct dmfc_channel_data {
++      int             ipu_channel;
++      unsigned long   channel_reg;
++      unsigned long   shift;
++      unsigned        eot_shift;
++      unsigned        max_fifo_lines;
++};
++
++static const struct dmfc_channel_data dmfcdata[] = {
++      {
++              .ipu_channel    = IPUV3_CHANNEL_MEM_BG_SYNC,
++              .channel_reg    = DMFC_DP_CHAN,
++              .shift          = DMFC_DP_CHAN_5B_23,
++              .eot_shift      = 20,
++              .max_fifo_lines = 3,
++      }, {
++              .ipu_channel    = 24,
++              .channel_reg    = DMFC_DP_CHAN,
++              .shift          = DMFC_DP_CHAN_6B_24,
++              .eot_shift      = 22,
++              .max_fifo_lines = 1,
++      }, {
++              .ipu_channel    = IPUV3_CHANNEL_MEM_FG_SYNC,
++              .channel_reg    = DMFC_DP_CHAN,
++              .shift          = DMFC_DP_CHAN_5F_27,
++              .eot_shift      = 21,
++              .max_fifo_lines = 2,
++      }, {
++              .ipu_channel    = IPUV3_CHANNEL_MEM_DC_SYNC,
++              .channel_reg    = DMFC_WR_CHAN,
++              .shift          = DMFC_WR_CHAN_1_28,
++              .eot_shift      = 16,
++              .max_fifo_lines = 2,
++      }, {
++              .ipu_channel    = 29,
++              .channel_reg    = DMFC_DP_CHAN,
++              .shift          = DMFC_DP_CHAN_6F_29,
++              .eot_shift      = 23,
++              .max_fifo_lines = 1,
++      },
++};
++
++#define DMFC_NUM_CHANNELS     ARRAY_SIZE(dmfcdata)
++
++struct ipu_dmfc_priv;
++
++struct dmfc_channel {
++      unsigned                        slots;
++      struct ipu_soc                  *ipu;
++      struct ipu_dmfc_priv            *priv;
++      const struct dmfc_channel_data  *data;
++};
++
++struct ipu_dmfc_priv {
++      struct ipu_soc *ipu;
++      struct device *dev;
++      struct dmfc_channel channels[DMFC_NUM_CHANNELS];
++      struct mutex mutex;
++      void __iomem *base;
++      int use_count;
++};
++
++int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
++{
++      struct ipu_dmfc_priv *priv = dmfc->priv;
++      mutex_lock(&priv->mutex);
++
++      if (!priv->use_count)
++              ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
++
++      priv->use_count++;
++
++      mutex_unlock(&priv->mutex);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
++
++void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
++{
++      struct ipu_dmfc_priv *priv = dmfc->priv;
++
++      mutex_lock(&priv->mutex);
++
++      priv->use_count--;
++
++      if (!priv->use_count)
++              ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
++
++      if (priv->use_count < 0)
++              priv->use_count = 0;
++
++      mutex_unlock(&priv->mutex);
++}
++EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
++
++void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width)
++{
++      struct ipu_dmfc_priv *priv = dmfc->priv;
++      u32 dmfc_gen1;
++
++      mutex_lock(&priv->mutex);
++
++      dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
++
++      if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
++              dmfc_gen1 |= 1 << dmfc->data->eot_shift;
++      else
++              dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
++
++      writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
++
++      mutex_unlock(&priv->mutex);
++}
++EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
++
++struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
++{
++      struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
++      int i;
++
++      for (i = 0; i < DMFC_NUM_CHANNELS; i++)
++              if (dmfcdata[i].ipu_channel == ipu_channel)
++                      return &priv->channels[i];
++      return ERR_PTR(-ENODEV);
++}
++EXPORT_SYMBOL_GPL(ipu_dmfc_get);
++
++void ipu_dmfc_put(struct dmfc_channel *dmfc)
++{
++}
++EXPORT_SYMBOL_GPL(ipu_dmfc_put);
++
++int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
++              struct clk *ipu_clk)
++{
++      struct ipu_dmfc_priv *priv;
++      int i;
++
++      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++
++      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
++      if (!priv->base)
++              return -ENOMEM;
++
++      priv->dev = dev;
++      priv->ipu = ipu;
++      mutex_init(&priv->mutex);
++
++      ipu->dmfc_priv = priv;
++
++      for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
++              priv->channels[i].priv = priv;
++              priv->channels[i].ipu = ipu;
++              priv->channels[i].data = &dmfcdata[i];
++
++              if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC ||
++                  dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC ||
++                  dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC)
++                      priv->channels[i].slots = 2;
++      }
++
++      writel(0x00000050, priv->base + DMFC_WR_CHAN);
++      writel(0x00005654, priv->base + DMFC_DP_CHAN);
++      writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
++      writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
++      writel(0x00000003, priv->base + DMFC_GENERAL1);
++
++      return 0;
++}
++
++void ipu_dmfc_exit(struct ipu_soc *ipu)
++{
++}
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/ipu-dp.c
+@@ -0,0 +1,357 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++#include <linux/export.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/io.h>
++#include <linux/err.h>
++
++#include <video/imx-ipu-v3.h>
++#include "ipu-prv.h"
++
++#define DP_SYNC 0
++#define DP_ASYNC0 0x60
++#define DP_ASYNC1 0xBC
++
++#define DP_COM_CONF           0x0
++#define DP_GRAPH_WIND_CTRL    0x0004
++#define DP_FG_POS             0x0008
++#define DP_CSC_A_0            0x0044
++#define DP_CSC_A_1            0x0048
++#define DP_CSC_A_2            0x004C
++#define DP_CSC_A_3            0x0050
++#define DP_CSC_0              0x0054
++#define DP_CSC_1              0x0058
++
++#define DP_COM_CONF_FG_EN             (1 << 0)
++#define DP_COM_CONF_GWSEL             (1 << 1)
++#define DP_COM_CONF_GWAM              (1 << 2)
++#define DP_COM_CONF_GWCKE             (1 << 3)
++#define DP_COM_CONF_CSC_DEF_MASK      (3 << 8)
++#define DP_COM_CONF_CSC_DEF_OFFSET    8
++#define DP_COM_CONF_CSC_DEF_FG                (3 << 8)
++#define DP_COM_CONF_CSC_DEF_BG                (2 << 8)
++#define DP_COM_CONF_CSC_DEF_BOTH      (1 << 8)
++
++#define IPUV3_NUM_FLOWS               3
++
++struct ipu_dp_priv;
++
++struct ipu_dp {
++      u32 flow;
++      bool in_use;
++      bool foreground;
++      enum ipu_color_space in_cs;
++};
++
++struct ipu_flow {
++      struct ipu_dp foreground;
++      struct ipu_dp background;
++      enum ipu_color_space out_cs;
++      void __iomem *base;
++      struct ipu_dp_priv *priv;
++};
++
++struct ipu_dp_priv {
++      struct ipu_soc *ipu;
++      struct device *dev;
++      void __iomem *base;
++      struct ipu_flow flow[IPUV3_NUM_FLOWS];
++      struct mutex mutex;
++      int use_count;
++};
++
++static u32 ipu_dp_flow_base[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1};
++
++static inline struct ipu_flow *to_flow(struct ipu_dp *dp)
++{
++      if (dp->foreground)
++              return container_of(dp, struct ipu_flow, foreground);
++      else
++              return container_of(dp, struct ipu_flow, background);
++}
++
++int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable,
++              u8 alpha, bool bg_chan)
++{
++      struct ipu_flow *flow = to_flow(dp);
++      struct ipu_dp_priv *priv = flow->priv;
++      u32 reg;
++
++      mutex_lock(&priv->mutex);
++
++      reg = readl(flow->base + DP_COM_CONF);
++      if (bg_chan)
++              reg &= ~DP_COM_CONF_GWSEL;
++      else
++              reg |= DP_COM_CONF_GWSEL;
++      writel(reg, flow->base + DP_COM_CONF);
++
++      if (enable) {
++              reg = readl(flow->base + DP_GRAPH_WIND_CTRL) & 0x00FFFFFFL;
++              writel(reg | ((u32) alpha << 24),
++                           flow->base + DP_GRAPH_WIND_CTRL);
++
++              reg = readl(flow->base + DP_COM_CONF);
++              writel(reg | DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
++      } else {
++              reg = readl(flow->base + DP_COM_CONF);
++              writel(reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
++      }
++
++      ipu_srm_dp_update(priv->ipu, true);
++
++      mutex_unlock(&priv->mutex);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha);
++
++int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
++{
++      struct ipu_flow *flow = to_flow(dp);
++      struct ipu_dp_priv *priv = flow->priv;
++
++      writel((x_pos << 16) | y_pos, flow->base + DP_FG_POS);
++
++      ipu_srm_dp_update(priv->ipu, true);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos);
++
++static void ipu_dp_csc_init(struct ipu_flow *flow,
++              enum ipu_color_space in,
++              enum ipu_color_space out,
++              u32 place)
++{
++      u32 reg;
++
++      reg = readl(flow->base + DP_COM_CONF);
++      reg &= ~DP_COM_CONF_CSC_DEF_MASK;
++
++      if (in == out) {
++              writel(reg, flow->base + DP_COM_CONF);
++              return;
++      }
++
++      if (in == IPUV3_COLORSPACE_RGB && out == IPUV3_COLORSPACE_YUV) {
++              writel(0x099 | (0x12d << 16), flow->base + DP_CSC_A_0);
++              writel(0x03a | (0x3a9 << 16), flow->base + DP_CSC_A_1);
++              writel(0x356 | (0x100 << 16), flow->base + DP_CSC_A_2);
++              writel(0x100 | (0x329 << 16), flow->base + DP_CSC_A_3);
++              writel(0x3d6 | (0x0000 << 16) | (2 << 30),
++                              flow->base + DP_CSC_0);
++              writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30),
++                              flow->base + DP_CSC_1);
++      } else {
++              writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0);
++              writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1);
++              writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2);
++              writel(0x095 | (0x0ff << 16), flow->base + DP_CSC_A_3);
++              writel(0x000 | (0x3e42 << 16) | (1 << 30),
++                              flow->base + DP_CSC_0);
++              writel(0x10a | (1 << 14) | (0x3dd6 << 16) | (1 << 30),
++                              flow->base + DP_CSC_1);
++      }
++
++      reg |= place;
++
++      writel(reg, flow->base + DP_COM_CONF);
++}
++
++int ipu_dp_setup_channel(struct ipu_dp *dp,
++              enum ipu_color_space in,
++              enum ipu_color_space out)
++{
++      struct ipu_flow *flow = to_flow(dp);
++      struct ipu_dp_priv *priv = flow->priv;
++
++      mutex_lock(&priv->mutex);
++
++      dp->in_cs = in;
++
++      if (!dp->foreground)
++              flow->out_cs = out;
++
++      if (flow->foreground.in_cs == flow->background.in_cs) {
++              /*
++               * foreground and background are of same colorspace, put
++               * colorspace converter after combining unit.
++               */
++              ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs,
++                              DP_COM_CONF_CSC_DEF_BOTH);
++      } else {
++              if (flow->foreground.in_cs == IPUV3_COLORSPACE_UNKNOWN ||
++                  flow->foreground.in_cs == flow->out_cs)
++                      /*
++                       * foreground identical to output, apply color
++                       * conversion on background
++                       */
++                      ipu_dp_csc_init(flow, flow->background.in_cs,
++                                      flow->out_cs, DP_COM_CONF_CSC_DEF_BG);
++              else
++                      ipu_dp_csc_init(flow, flow->foreground.in_cs,
++                                      flow->out_cs, DP_COM_CONF_CSC_DEF_FG);
++      }
++
++      ipu_srm_dp_update(priv->ipu, true);
++
++      mutex_unlock(&priv->mutex);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
++
++int ipu_dp_enable(struct ipu_soc *ipu)
++{
++      struct ipu_dp_priv *priv = ipu->dp_priv;
++
++      mutex_lock(&priv->mutex);
++
++      if (!priv->use_count)
++              ipu_module_enable(priv->ipu, IPU_CONF_DP_EN);
++
++      priv->use_count++;
++
++      mutex_unlock(&priv->mutex);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_dp_enable);
++
++int ipu_dp_enable_channel(struct ipu_dp *dp)
++{
++      struct ipu_flow *flow = to_flow(dp);
++      struct ipu_dp_priv *priv = flow->priv;
++      u32 reg;
++
++      if (!dp->foreground)
++              return 0;
++
++      mutex_lock(&priv->mutex);
++
++      reg = readl(flow->base + DP_COM_CONF);
++      reg |= DP_COM_CONF_FG_EN;
++      writel(reg, flow->base + DP_COM_CONF);
++
++      ipu_srm_dp_update(priv->ipu, true);
++
++      mutex_unlock(&priv->mutex);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
++
++void ipu_dp_disable_channel(struct ipu_dp *dp, bool sync)
++{
++      struct ipu_flow *flow = to_flow(dp);
++      struct ipu_dp_priv *priv = flow->priv;
++      u32 reg, csc;
++
++      dp->in_cs = IPUV3_COLORSPACE_UNKNOWN;
++
++      if (!dp->foreground)
++              return;
++
++      mutex_lock(&priv->mutex);
++
++      reg = readl(flow->base + DP_COM_CONF);
++      csc = reg & DP_COM_CONF_CSC_DEF_MASK;
++      reg &= ~DP_COM_CONF_CSC_DEF_MASK;
++      if (csc == DP_COM_CONF_CSC_DEF_BOTH || csc == DP_COM_CONF_CSC_DEF_BG)
++              reg |= DP_COM_CONF_CSC_DEF_BG;
++
++      reg &= ~DP_COM_CONF_FG_EN;
++      writel(reg, flow->base + DP_COM_CONF);
++
++      writel(0, flow->base + DP_FG_POS);
++      ipu_srm_dp_update(priv->ipu, sync);
++
++      mutex_unlock(&priv->mutex);
++}
++EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
++
++void ipu_dp_disable(struct ipu_soc *ipu)
++{
++      struct ipu_dp_priv *priv = ipu->dp_priv;
++
++      mutex_lock(&priv->mutex);
++
++      priv->use_count--;
++
++      if (!priv->use_count)
++              ipu_module_disable(priv->ipu, IPU_CONF_DP_EN);
++
++      if (priv->use_count < 0)
++              priv->use_count = 0;
++
++      mutex_unlock(&priv->mutex);
++}
++EXPORT_SYMBOL_GPL(ipu_dp_disable);
++
++struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
++{
++      struct ipu_dp_priv *priv = ipu->dp_priv;
++      struct ipu_dp *dp;
++
++      if ((flow >> 1) >= IPUV3_NUM_FLOWS)
++              return ERR_PTR(-EINVAL);
++
++      if (flow & 1)
++              dp = &priv->flow[flow >> 1].foreground;
++      else
++              dp = &priv->flow[flow >> 1].background;
++
++      if (dp->in_use)
++              return ERR_PTR(-EBUSY);
++
++      dp->in_use = true;
++
++      return dp;
++}
++EXPORT_SYMBOL_GPL(ipu_dp_get);
++
++void ipu_dp_put(struct ipu_dp *dp)
++{
++      dp->in_use = false;
++}
++EXPORT_SYMBOL_GPL(ipu_dp_put);
++
++int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
++{
++      struct ipu_dp_priv *priv;
++      int i;
++
++      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++      priv->dev = dev;
++      priv->ipu = ipu;
++
++      ipu->dp_priv = priv;
++
++      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
++      if (!priv->base)
++              return -ENOMEM;
++
++      mutex_init(&priv->mutex);
++
++      for (i = 0; i < IPUV3_NUM_FLOWS; i++) {
++              priv->flow[i].background.in_cs = IPUV3_COLORSPACE_UNKNOWN;
++              priv->flow[i].foreground.in_cs = IPUV3_COLORSPACE_UNKNOWN;
++              priv->flow[i].foreground.foreground = true;
++              priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
++              priv->flow[i].priv = priv;
++      }
++
++      return 0;
++}
++
++void ipu_dp_exit(struct ipu_soc *ipu)
++{
++}
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/ipu-ic.c
+@@ -0,0 +1,761 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (C) 2012-2014 Mentor Graphics Inc.
++ * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/spinlock.h>
++#include <linux/bitrev.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/sizes.h>
++#include "ipu-prv.h"
++
++/* IC Register Offsets */
++#define IC_CONF                 0x0000
++#define IC_PRP_ENC_RSC          0x0004
++#define IC_PRP_VF_RSC           0x0008
++#define IC_PP_RSC               0x000C
++#define IC_CMBP_1               0x0010
++#define IC_CMBP_2               0x0014
++#define IC_IDMAC_1              0x0018
++#define IC_IDMAC_2              0x001C
++#define IC_IDMAC_3              0x0020
++#define IC_IDMAC_4              0x0024
++
++/* IC Register Fields */
++#define IC_CONF_PRPENC_EN       (1 << 0)
++#define IC_CONF_PRPENC_CSC1     (1 << 1)
++#define IC_CONF_PRPENC_ROT_EN   (1 << 2)
++#define IC_CONF_PRPVF_EN        (1 << 8)
++#define IC_CONF_PRPVF_CSC1      (1 << 9)
++#define IC_CONF_PRPVF_CSC2      (1 << 10)
++#define IC_CONF_PRPVF_CMB       (1 << 11)
++#define IC_CONF_PRPVF_ROT_EN    (1 << 12)
++#define IC_CONF_PP_EN           (1 << 16)
++#define IC_CONF_PP_CSC1         (1 << 17)
++#define IC_CONF_PP_CSC2         (1 << 18)
++#define IC_CONF_PP_CMB          (1 << 19)
++#define IC_CONF_PP_ROT_EN       (1 << 20)
++#define IC_CONF_IC_GLB_LOC_A    (1 << 28)
++#define IC_CONF_KEY_COLOR_EN    (1 << 29)
++#define IC_CONF_RWS_EN          (1 << 30)
++#define IC_CONF_CSI_MEM_WR_EN   (1 << 31)
++
++#define IC_IDMAC_1_CB0_BURST_16         (1 << 0)
++#define IC_IDMAC_1_CB1_BURST_16         (1 << 1)
++#define IC_IDMAC_1_CB2_BURST_16         (1 << 2)
++#define IC_IDMAC_1_CB3_BURST_16         (1 << 3)
++#define IC_IDMAC_1_CB4_BURST_16         (1 << 4)
++#define IC_IDMAC_1_CB5_BURST_16         (1 << 5)
++#define IC_IDMAC_1_CB6_BURST_16         (1 << 6)
++#define IC_IDMAC_1_CB7_BURST_16         (1 << 7)
++#define IC_IDMAC_1_PRPENC_ROT_MASK      (0x7 << 11)
++#define IC_IDMAC_1_PRPENC_ROT_OFFSET    11
++#define IC_IDMAC_1_PRPVF_ROT_MASK       (0x7 << 14)
++#define IC_IDMAC_1_PRPVF_ROT_OFFSET     14
++#define IC_IDMAC_1_PP_ROT_MASK          (0x7 << 17)
++#define IC_IDMAC_1_PP_ROT_OFFSET        17
++#define IC_IDMAC_1_PP_FLIP_RS           (1 << 22)
++#define IC_IDMAC_1_PRPVF_FLIP_RS        (1 << 21)
++#define IC_IDMAC_1_PRPENC_FLIP_RS       (1 << 20)
++
++#define IC_IDMAC_2_PRPENC_HEIGHT_MASK   (0x3ff << 0)
++#define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0
++#define IC_IDMAC_2_PRPVF_HEIGHT_MASK    (0x3ff << 10)
++#define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET  10
++#define IC_IDMAC_2_PP_HEIGHT_MASK       (0x3ff << 20)
++#define IC_IDMAC_2_PP_HEIGHT_OFFSET     20
++
++#define IC_IDMAC_3_PRPENC_WIDTH_MASK    (0x3ff << 0)
++#define IC_IDMAC_3_PRPENC_WIDTH_OFFSET  0
++#define IC_IDMAC_3_PRPVF_WIDTH_MASK     (0x3ff << 10)
++#define IC_IDMAC_3_PRPVF_WIDTH_OFFSET   10
++#define IC_IDMAC_3_PP_WIDTH_MASK        (0x3ff << 20)
++#define IC_IDMAC_3_PP_WIDTH_OFFSET      20
++
++struct ic_task_regoffs {
++      u32 rsc;
++      u32 tpmem_csc[2];
++};
++
++struct ic_task_bitfields {
++      u32 ic_conf_en;
++      u32 ic_conf_rot_en;
++      u32 ic_conf_cmb_en;
++      u32 ic_conf_csc1_en;
++      u32 ic_conf_csc2_en;
++      u32 ic_cmb_galpha_bit;
++};
++
++static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
++      [IC_TASK_ENCODER] = {
++              .rsc = IC_PRP_ENC_RSC,
++              .tpmem_csc = {0x2008, 0},
++      },
++      [IC_TASK_VIEWFINDER] = {
++              .rsc = IC_PRP_VF_RSC,
++              .tpmem_csc = {0x4028, 0x4040},
++      },
++      [IC_TASK_POST_PROCESSOR] = {
++              .rsc = IC_PP_RSC,
++              .tpmem_csc = {0x6060, 0x6078},
++      },
++};
++
++static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = {
++      [IC_TASK_ENCODER] = {
++              .ic_conf_en = IC_CONF_PRPENC_EN,
++              .ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN,
++              .ic_conf_cmb_en = 0,    /* NA */
++              .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
++              .ic_conf_csc2_en = 0,   /* NA */
++              .ic_cmb_galpha_bit = 0, /* NA */
++      },
++      [IC_TASK_VIEWFINDER] = {
++              .ic_conf_en = IC_CONF_PRPVF_EN,
++              .ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN,
++              .ic_conf_cmb_en = IC_CONF_PRPVF_CMB,
++              .ic_conf_csc1_en = IC_CONF_PRPVF_CSC1,
++              .ic_conf_csc2_en = IC_CONF_PRPVF_CSC2,
++              .ic_cmb_galpha_bit = 0,
++      },
++      [IC_TASK_POST_PROCESSOR] = {
++              .ic_conf_en = IC_CONF_PP_EN,
++              .ic_conf_rot_en = IC_CONF_PP_ROT_EN,
++              .ic_conf_cmb_en = IC_CONF_PP_CMB,
++              .ic_conf_csc1_en = IC_CONF_PP_CSC1,
++              .ic_conf_csc2_en = IC_CONF_PP_CSC2,
++              .ic_cmb_galpha_bit = 8,
++      },
++};
++
++struct ipu_ic_priv;
++
++struct ipu_ic {
++      enum ipu_ic_task task;
++      const struct ic_task_regoffs *reg;
++      const struct ic_task_bitfields *bit;
++
++      struct ipu_ic_colorspace in_cs;
++      struct ipu_ic_colorspace g_in_cs;
++      struct ipu_ic_colorspace out_cs;
++
++      bool graphics;
++      bool rotation;
++      bool in_use;
++
++      struct ipu_ic_priv *priv;
++};
++
++struct ipu_ic_priv {
++      void __iomem *base;
++      void __iomem *tpmem_base;
++      spinlock_t lock;
++      struct ipu_soc *ipu;
++      int use_count;
++      int irt_use_count;
++      struct ipu_ic task[IC_NUM_TASKS];
++};
++
++static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset)
++{
++      return readl(ic->priv->base + offset);
++}
++
++static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset)
++{
++      writel(value, ic->priv->base + offset);
++}
++
++static int init_csc(struct ipu_ic *ic,
++                  const struct ipu_ic_csc *csc,
++                  int csc_index)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      u32 __iomem *base;
++      const u16 (*c)[3];
++      const u16 *a;
++      u32 param;
++
++      base = (u32 __iomem *)
++              (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
++
++      /* Cast to unsigned */
++      c = (const u16 (*)[3])csc->params.coeff;
++      a = (const u16 *)csc->params.offset;
++
++      param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) |
++              ((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff);
++      writel(param, base++);
++
++      param = ((a[0] & 0x1fe0) >> 5) | (csc->params.scale << 8) |
++              (csc->params.sat << 10);
++      writel(param, base++);
++
++      param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
++              ((c[1][0] & 0x1ff) << 9) | (c[2][0] & 0x1ff);
++      writel(param, base++);
++
++      param = ((a[1] & 0x1fe0) >> 5);
++      writel(param, base++);
++
++      param = ((a[2] & 0x1f) << 27) | ((c[0][2] & 0x1ff) << 18) |
++              ((c[1][2] & 0x1ff) << 9) | (c[2][1] & 0x1ff);
++      writel(param, base++);
++
++      param = ((a[2] & 0x1fe0) >> 5);
++      writel(param, base++);
++
++      return 0;
++}
++
++static int calc_resize_coeffs(struct ipu_ic *ic,
++                            u32 in_size, u32 out_size,
++                            u32 *resize_coeff,
++                            u32 *downsize_coeff)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      struct ipu_soc *ipu = priv->ipu;
++      u32 temp_size, temp_downsize;
++
++      /*
++       * Input size cannot be more than 4096, and output size cannot
++       * be more than 1024
++       */
++      if (in_size > 4096) {
++              dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
++              return -EINVAL;
++      }
++      if (out_size > 1024) {
++              dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
++              return -EINVAL;
++      }
++
++      /* Cannot downsize more than 4:1 */
++      if ((out_size << 2) < in_size) {
++              dev_err(ipu->dev, "Unsupported downsize\n");
++              return -EINVAL;
++      }
++
++      /* Compute downsizing coefficient */
++      temp_downsize = 0;
++      temp_size = in_size;
++      while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
++             (temp_downsize < 2)) {
++              temp_size >>= 1;
++              temp_downsize++;
++      }
++      *downsize_coeff = temp_downsize;
++
++      /*
++       * compute resizing coefficient using the following equation:
++       * resize_coeff = M * (SI - 1) / (SO - 1)
++       * where M = 2^13, SI = input size, SO = output size
++       */
++      *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
++      if (*resize_coeff >= 16384L) {
++              dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
++              *resize_coeff = 0x3FFF;
++      }
++
++      return 0;
++}
++
++void ipu_ic_task_enable(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      unsigned long flags;
++      u32 ic_conf;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      ic_conf = ipu_ic_read(ic, IC_CONF);
++
++      ic_conf |= ic->bit->ic_conf_en;
++
++      if (ic->rotation)
++              ic_conf |= ic->bit->ic_conf_rot_en;
++
++      if (ic->in_cs.cs != ic->out_cs.cs)
++              ic_conf |= ic->bit->ic_conf_csc1_en;
++
++      if (ic->graphics) {
++              ic_conf |= ic->bit->ic_conf_cmb_en;
++              ic_conf |= ic->bit->ic_conf_csc1_en;
++
++              if (ic->g_in_cs.cs != ic->out_cs.cs)
++                      ic_conf |= ic->bit->ic_conf_csc2_en;
++      }
++
++      ipu_ic_write(ic, ic_conf, IC_CONF);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_ic_task_enable);
++
++void ipu_ic_task_disable(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      unsigned long flags;
++      u32 ic_conf;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      ic_conf = ipu_ic_read(ic, IC_CONF);
++
++      ic_conf &= ~(ic->bit->ic_conf_en |
++                   ic->bit->ic_conf_csc1_en |
++                   ic->bit->ic_conf_rot_en);
++      if (ic->bit->ic_conf_csc2_en)
++              ic_conf &= ~ic->bit->ic_conf_csc2_en;
++      if (ic->bit->ic_conf_cmb_en)
++              ic_conf &= ~ic->bit->ic_conf_cmb_en;
++
++      ipu_ic_write(ic, ic_conf, IC_CONF);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
++
++int ipu_ic_task_graphics_init(struct ipu_ic *ic,
++                            const struct ipu_ic_colorspace *g_in_cs,
++                            bool galpha_en, u32 galpha,
++                            bool colorkey_en, u32 colorkey)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      struct ipu_ic_csc csc2;
++      unsigned long flags;
++      u32 reg, ic_conf;
++      int ret = 0;
++
++      if (ic->task == IC_TASK_ENCODER)
++              return -EINVAL;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      ic_conf = ipu_ic_read(ic, IC_CONF);
++
++      if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
++              struct ipu_ic_csc csc1;
++
++              ret = ipu_ic_calc_csc(&csc1,
++                                    V4L2_YCBCR_ENC_601,
++                                    V4L2_QUANTIZATION_FULL_RANGE,
++                                    IPUV3_COLORSPACE_RGB,
++                                    V4L2_YCBCR_ENC_601,
++                                    V4L2_QUANTIZATION_FULL_RANGE,
++                                    IPUV3_COLORSPACE_RGB);
++              if (ret)
++                      goto unlock;
++
++              /* need transparent CSC1 conversion */
++              ret = init_csc(ic, &csc1, 0);
++              if (ret)
++                      goto unlock;
++      }
++
++      ic->g_in_cs = *g_in_cs;
++      csc2.in_cs = ic->g_in_cs;
++      csc2.out_cs = ic->out_cs;
++
++      ret = __ipu_ic_calc_csc(&csc2);
++      if (ret)
++              goto unlock;
++
++      ret = init_csc(ic, &csc2, 1);
++      if (ret)
++              goto unlock;
++
++      if (galpha_en) {
++              ic_conf |= IC_CONF_IC_GLB_LOC_A;
++              reg = ipu_ic_read(ic, IC_CMBP_1);
++              reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit);
++              reg |= (galpha << ic->bit->ic_cmb_galpha_bit);
++              ipu_ic_write(ic, reg, IC_CMBP_1);
++      } else
++              ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
++
++      if (colorkey_en) {
++              ic_conf |= IC_CONF_KEY_COLOR_EN;
++              ipu_ic_write(ic, colorkey, IC_CMBP_2);
++      } else
++              ic_conf &= ~IC_CONF_KEY_COLOR_EN;
++
++      ipu_ic_write(ic, ic_conf, IC_CONF);
++
++      ic->graphics = true;
++unlock:
++      spin_unlock_irqrestore(&priv->lock, flags);
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
++
++int ipu_ic_task_init_rsc(struct ipu_ic *ic,
++                       const struct ipu_ic_csc *csc,
++                       int in_width, int in_height,
++                       int out_width, int out_height,
++                       u32 rsc)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      u32 downsize_coeff, resize_coeff;
++      unsigned long flags;
++      int ret = 0;
++
++      if (!rsc) {
++              /* Setup vertical resizing */
++
++              ret = calc_resize_coeffs(ic, in_height, out_height,
++                                       &resize_coeff, &downsize_coeff);
++              if (ret)
++                      return ret;
++
++              rsc = (downsize_coeff << 30) | (resize_coeff << 16);
++
++              /* Setup horizontal resizing */
++              ret = calc_resize_coeffs(ic, in_width, out_width,
++                                       &resize_coeff, &downsize_coeff);
++              if (ret)
++                      return ret;
++
++              rsc |= (downsize_coeff << 14) | resize_coeff;
++      }
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      ipu_ic_write(ic, rsc, ic->reg->rsc);
++
++      /* Setup color space conversion */
++      ic->in_cs = csc->in_cs;
++      ic->out_cs = csc->out_cs;
++
++      ret = init_csc(ic, csc, 0);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++      return ret;
++}
++
++int ipu_ic_task_init(struct ipu_ic *ic,
++                   const struct ipu_ic_csc *csc,
++                   int in_width, int in_height,
++                   int out_width, int out_height)
++{
++      return ipu_ic_task_init_rsc(ic, csc,
++                                  in_width, in_height,
++                                  out_width, out_height, 0);
++}
++EXPORT_SYMBOL_GPL(ipu_ic_task_init);
++
++int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
++                        u32 width, u32 height, int burst_size,
++                        enum ipu_rotate_mode rot)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      struct ipu_soc *ipu = priv->ipu;
++      u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
++      u32 temp_rot = bitrev8(rot) >> 5;
++      bool need_hor_flip = false;
++      unsigned long flags;
++      int ret = 0;
++
++      if ((burst_size != 8) && (burst_size != 16)) {
++              dev_err(ipu->dev, "Illegal burst length for IC\n");
++              return -EINVAL;
++      }
++
++      width--;
++      height--;
++
++      if (temp_rot & 0x2)     /* Need horizontal flip */
++              need_hor_flip = true;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1);
++      ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2);
++      ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3);
++
++      switch (channel->num) {
++      case IPUV3_CHANNEL_IC_PP_MEM:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
++
++              if (need_hor_flip)
++                      ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
++
++              ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
++              ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
++
++              ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
++              ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
++              break;
++      case IPUV3_CHANNEL_MEM_IC_PP:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
++              break;
++      case IPUV3_CHANNEL_MEM_ROT_PP:
++              ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
++              ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
++              break;
++      case IPUV3_CHANNEL_MEM_IC_PRP_VF:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
++              break;
++      case IPUV3_CHANNEL_IC_PRP_ENC_MEM:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
++
++              if (need_hor_flip)
++                      ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
++
++              ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
++              ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
++
++              ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
++              ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
++              break;
++      case IPUV3_CHANNEL_MEM_ROT_ENC:
++              ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
++              ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
++              break;
++      case IPUV3_CHANNEL_IC_PRP_VF_MEM:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
++
++              if (need_hor_flip)
++                      ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
++
++              ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
++              ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
++
++              ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
++              ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
++              break;
++      case IPUV3_CHANNEL_MEM_ROT_VF:
++              ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
++              ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
++              break;
++      case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
++              break;
++      case IPUV3_CHANNEL_G_MEM_IC_PP:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
++              break;
++      case IPUV3_CHANNEL_VDI_MEM_IC_VF:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
++              break;
++      default:
++              goto unlock;
++      }
++
++      ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1);
++      ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
++      ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
++
++      if (ipu_rot_mode_is_irt(rot))
++              ic->rotation = true;
++
++unlock:
++      spin_unlock_irqrestore(&priv->lock, flags);
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
++
++static void ipu_irt_enable(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++
++      if (!priv->irt_use_count)
++              ipu_module_enable(priv->ipu, IPU_CONF_ROT_EN);
++
++      priv->irt_use_count++;
++}
++
++static void ipu_irt_disable(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++
++      if (priv->irt_use_count) {
++              if (!--priv->irt_use_count)
++                      ipu_module_disable(priv->ipu, IPU_CONF_ROT_EN);
++      }
++}
++
++int ipu_ic_enable(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      unsigned long flags;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      if (!priv->use_count)
++              ipu_module_enable(priv->ipu, IPU_CONF_IC_EN);
++
++      priv->use_count++;
++
++      if (ic->rotation)
++              ipu_irt_enable(ic);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_ic_enable);
++
++int ipu_ic_disable(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      unsigned long flags;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      priv->use_count--;
++
++      if (!priv->use_count)
++              ipu_module_disable(priv->ipu, IPU_CONF_IC_EN);
++
++      if (priv->use_count < 0)
++              priv->use_count = 0;
++
++      if (ic->rotation)
++              ipu_irt_disable(ic);
++
++      ic->rotation = ic->graphics = false;
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_ic_disable);
++
++struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
++{
++      struct ipu_ic_priv *priv = ipu->ic_priv;
++      unsigned long flags;
++      struct ipu_ic *ic, *ret;
++
++      if (task >= IC_NUM_TASKS)
++              return ERR_PTR(-EINVAL);
++
++      ic = &priv->task[task];
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      if (ic->in_use) {
++              ret = ERR_PTR(-EBUSY);
++              goto unlock;
++      }
++
++      ic->in_use = true;
++      ret = ic;
++
++unlock:
++      spin_unlock_irqrestore(&priv->lock, flags);
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_ic_get);
++
++void ipu_ic_put(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      unsigned long flags;
++
++      spin_lock_irqsave(&priv->lock, flags);
++      ic->in_use = false;
++      spin_unlock_irqrestore(&priv->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_ic_put);
++
++int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
++              unsigned long base, unsigned long tpmem_base)
++{
++      struct ipu_ic_priv *priv;
++      int i;
++
++      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++
++      ipu->ic_priv = priv;
++
++      spin_lock_init(&priv->lock);
++      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
++      if (!priv->base)
++              return -ENOMEM;
++      priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K);
++      if (!priv->tpmem_base)
++              return -ENOMEM;
++
++      dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base);
++
++      priv->ipu = ipu;
++
++      for (i = 0; i < IC_NUM_TASKS; i++) {
++              priv->task[i].task = i;
++              priv->task[i].priv = priv;
++              priv->task[i].reg = &ic_task_reg[i];
++              priv->task[i].bit = &ic_task_bit[i];
++      }
++
++      return 0;
++}
++
++void ipu_ic_exit(struct ipu_soc *ipu)
++{
++}
++
++void ipu_ic_dump(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      struct ipu_soc *ipu = priv->ipu;
++
++      dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n",
++              ipu_ic_read(ic, IC_CONF));
++      dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n",
++              ipu_ic_read(ic, IC_PRP_ENC_RSC));
++      dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n",
++              ipu_ic_read(ic, IC_PRP_VF_RSC));
++      dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n",
++              ipu_ic_read(ic, IC_PP_RSC));
++      dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n",
++              ipu_ic_read(ic, IC_CMBP_1));
++      dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n",
++              ipu_ic_read(ic, IC_CMBP_2));
++      dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n",
++              ipu_ic_read(ic, IC_IDMAC_1));
++      dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n",
++              ipu_ic_read(ic, IC_IDMAC_2));
++      dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n",
++              ipu_ic_read(ic, IC_IDMAC_3));
++      dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n",
++              ipu_ic_read(ic, IC_IDMAC_4));
++}
++EXPORT_SYMBOL_GPL(ipu_ic_dump);
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/ipu-image-convert.c
+@@ -0,0 +1,2475 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (C) 2012-2016 Mentor Graphics Inc.
++ *
++ * Queued image conversion support, with tiling and rotation.
++ */
++
++#include <linux/interrupt.h>
++#include <linux/dma-mapping.h>
++#include <video/imx-ipu-image-convert.h>
++#include "ipu-prv.h"
++
++/*
++ * The IC Resizer has a restriction that the output frame from the
++ * resizer must be 1024 or less in both width (pixels) and height
++ * (lines).
++ *
++ * The image converter attempts to split up a conversion when
++ * the desired output (converted) frame resolution exceeds the
++ * IC resizer limit of 1024 in either dimension.
++ *
++ * If either dimension of the output frame exceeds the limit, the
++ * dimension is split into 1, 2, or 4 equal stripes, for a maximum
++ * of 4*4 or 16 tiles. A conversion is then carried out for each
++ * tile (but taking care to pass the full frame stride length to
++ * the DMA channel's parameter memory!). IDMA double-buffering is used
++ * to convert each tile back-to-back when possible (see note below
++ * when double_buffering boolean is set).
++ *
++ * Note that the input frame must be split up into the same number
++ * of tiles as the output frame:
++ *
++ *                       +---------+-----+
++ *   +-----+---+         |  A      | B   |
++ *   | A   | B |         |         |     |
++ *   +-----+---+   -->   +---------+-----+
++ *   | C   | D |         |  C      | D   |
++ *   +-----+---+         |         |     |
++ *                       +---------+-----+
++ *
++ * Clockwise 90° rotations are handled by first rescaling into a
++ * reusable temporary tile buffer and then rotating with the 8x8
++ * block rotator, writing to the correct destination:
++ *
++ *                                         +-----+-----+
++ *                                         |     |     |
++ *   +-----+---+         +---------+       | C   | A   |
++ *   | A   | B |         | A,B, |  |       |     |     |
++ *   +-----+---+   -->   | C,D  |  |  -->  |     |     |
++ *   | C   | D |         +---------+       +-----+-----+
++ *   +-----+---+                           | D   | B   |
++ *                                         |     |     |
++ *                                         +-----+-----+
++ *
++ * If the 8x8 block rotator is used, horizontal or vertical flipping
++ * is done during the rotation step, otherwise flipping is done
++ * during the scaling step.
++ * With rotation or flipping, tile order changes between input and
++ * output image. Tiles are numbered row major from top left to bottom
++ * right for both input and output image.
++ */
++
++#define MAX_STRIPES_W    4
++#define MAX_STRIPES_H    4
++#define MAX_TILES (MAX_STRIPES_W * MAX_STRIPES_H)
++
++#define MIN_W     16
++#define MIN_H     8
++#define MAX_W     4096
++#define MAX_H     4096
++
++enum ipu_image_convert_type {
++      IMAGE_CONVERT_IN = 0,
++      IMAGE_CONVERT_OUT,
++};
++
++struct ipu_image_convert_dma_buf {
++      void          *virt;
++      dma_addr_t    phys;
++      unsigned long len;
++};
++
++struct ipu_image_convert_dma_chan {
++      int in;
++      int out;
++      int rot_in;
++      int rot_out;
++      int vdi_in_p;
++      int vdi_in;
++      int vdi_in_n;
++};
++
++/* dimensions of one tile */
++struct ipu_image_tile {
++      u32 width;
++      u32 height;
++      u32 left;
++      u32 top;
++      /* size and strides are in bytes */
++      u32 size;
++      u32 stride;
++      u32 rot_stride;
++      /* start Y or packed offset of this tile */
++      u32 offset;
++      /* offset from start to tile in U plane, for planar formats */
++      u32 u_off;
++      /* offset from start to tile in V plane, for planar formats */
++      u32 v_off;
++};
++
++struct ipu_image_convert_image {
++      struct ipu_image base;
++      enum ipu_image_convert_type type;
++
++      const struct ipu_image_pixfmt *fmt;
++      unsigned int stride;
++
++      /* # of rows (horizontal stripes) if dest height is > 1024 */
++      unsigned int num_rows;
++      /* # of columns (vertical stripes) if dest width is > 1024 */
++      unsigned int num_cols;
++
++      struct ipu_image_tile tile[MAX_TILES];
++};
++
++struct ipu_image_pixfmt {
++      u32     fourcc;        /* V4L2 fourcc */
++      int     bpp;           /* total bpp */
++      int     uv_width_dec;  /* decimation in width for U/V planes */
++      int     uv_height_dec; /* decimation in height for U/V planes */
++      bool    planar;        /* planar format */
++      bool    uv_swapped;    /* U and V planes are swapped */
++      bool    uv_packed;     /* partial planar (U and V in same plane) */
++};
++
++struct ipu_image_convert_ctx;
++struct ipu_image_convert_chan;
++struct ipu_image_convert_priv;
++
++struct ipu_image_convert_ctx {
++      struct ipu_image_convert_chan *chan;
++
++      ipu_image_convert_cb_t complete;
++      void *complete_context;
++
++      /* Source/destination image data and rotation mode */
++      struct ipu_image_convert_image in;
++      struct ipu_image_convert_image out;
++      struct ipu_ic_csc csc;
++      enum ipu_rotate_mode rot_mode;
++      u32 downsize_coeff_h;
++      u32 downsize_coeff_v;
++      u32 image_resize_coeff_h;
++      u32 image_resize_coeff_v;
++      u32 resize_coeffs_h[MAX_STRIPES_W];
++      u32 resize_coeffs_v[MAX_STRIPES_H];
++
++      /* intermediate buffer for rotation */
++      struct ipu_image_convert_dma_buf rot_intermediate[2];
++
++      /* current buffer number for double buffering */
++      int cur_buf_num;
++
++      bool aborting;
++      struct completion aborted;
++
++      /* can we use double-buffering for this conversion operation? */
++      bool double_buffering;
++      /* num_rows * num_cols */
++      unsigned int num_tiles;
++      /* next tile to process */
++      unsigned int next_tile;
++      /* where to place converted tile in dest image */
++      unsigned int out_tile_map[MAX_TILES];
++
++      struct list_head list;
++};
++
++struct ipu_image_convert_chan {
++      struct ipu_image_convert_priv *priv;
++
++      enum ipu_ic_task ic_task;
++      const struct ipu_image_convert_dma_chan *dma_ch;
++
++      struct ipu_ic *ic;
++      struct ipuv3_channel *in_chan;
++      struct ipuv3_channel *out_chan;
++      struct ipuv3_channel *rotation_in_chan;
++      struct ipuv3_channel *rotation_out_chan;
++
++      /* the IPU end-of-frame irqs */
++      int out_eof_irq;
++      int rot_out_eof_irq;
++
++      spinlock_t irqlock;
++
++      /* list of convert contexts */
++      struct list_head ctx_list;
++      /* queue of conversion runs */
++      struct list_head pending_q;
++      /* queue of completed runs */
++      struct list_head done_q;
++
++      /* the current conversion run */
++      struct ipu_image_convert_run *current_run;
++};
++
++struct ipu_image_convert_priv {
++      struct ipu_image_convert_chan chan[IC_NUM_TASKS];
++      struct ipu_soc *ipu;
++};
++
++static const struct ipu_image_convert_dma_chan
++image_convert_dma_chan[IC_NUM_TASKS] = {
++      [IC_TASK_VIEWFINDER] = {
++              .in = IPUV3_CHANNEL_MEM_IC_PRP_VF,
++              .out = IPUV3_CHANNEL_IC_PRP_VF_MEM,
++              .rot_in = IPUV3_CHANNEL_MEM_ROT_VF,
++              .rot_out = IPUV3_CHANNEL_ROT_VF_MEM,
++              .vdi_in_p = IPUV3_CHANNEL_MEM_VDI_PREV,
++              .vdi_in = IPUV3_CHANNEL_MEM_VDI_CUR,
++              .vdi_in_n = IPUV3_CHANNEL_MEM_VDI_NEXT,
++      },
++      [IC_TASK_POST_PROCESSOR] = {
++              .in = IPUV3_CHANNEL_MEM_IC_PP,
++              .out = IPUV3_CHANNEL_IC_PP_MEM,
++              .rot_in = IPUV3_CHANNEL_MEM_ROT_PP,
++              .rot_out = IPUV3_CHANNEL_ROT_PP_MEM,
++      },
++};
++
++static const struct ipu_image_pixfmt image_convert_formats[] = {
++      {
++              .fourcc = V4L2_PIX_FMT_RGB565,
++              .bpp    = 16,
++      }, {
++              .fourcc = V4L2_PIX_FMT_RGB24,
++              .bpp    = 24,
++      }, {
++              .fourcc = V4L2_PIX_FMT_BGR24,
++              .bpp    = 24,
++      }, {
++              .fourcc = V4L2_PIX_FMT_RGB32,
++              .bpp    = 32,
++      }, {
++              .fourcc = V4L2_PIX_FMT_BGR32,
++              .bpp    = 32,
++      }, {
++              .fourcc = V4L2_PIX_FMT_XRGB32,
++              .bpp    = 32,
++      }, {
++              .fourcc = V4L2_PIX_FMT_XBGR32,
++              .bpp    = 32,
++      }, {
++              .fourcc = V4L2_PIX_FMT_BGRX32,
++              .bpp    = 32,
++      }, {
++              .fourcc = V4L2_PIX_FMT_RGBX32,
++              .bpp    = 32,
++      }, {
++              .fourcc = V4L2_PIX_FMT_YUYV,
++              .bpp    = 16,
++              .uv_width_dec = 2,
++              .uv_height_dec = 1,
++      }, {
++              .fourcc = V4L2_PIX_FMT_UYVY,
++              .bpp    = 16,
++              .uv_width_dec = 2,
++              .uv_height_dec = 1,
++      }, {
++              .fourcc = V4L2_PIX_FMT_YUV420,
++              .bpp    = 12,
++              .planar = true,
++              .uv_width_dec = 2,
++              .uv_height_dec = 2,
++      }, {
++              .fourcc = V4L2_PIX_FMT_YVU420,
++              .bpp    = 12,
++              .planar = true,
++              .uv_width_dec = 2,
++              .uv_height_dec = 2,
++              .uv_swapped = true,
++      }, {
++              .fourcc = V4L2_PIX_FMT_NV12,
++              .bpp    = 12,
++              .planar = true,
++              .uv_width_dec = 2,
++              .uv_height_dec = 2,
++              .uv_packed = true,
++      }, {
++              .fourcc = V4L2_PIX_FMT_YUV422P,
++              .bpp    = 16,
++              .planar = true,
++              .uv_width_dec = 2,
++              .uv_height_dec = 1,
++      }, {
++              .fourcc = V4L2_PIX_FMT_NV16,
++              .bpp    = 16,
++              .planar = true,
++              .uv_width_dec = 2,
++              .uv_height_dec = 1,
++              .uv_packed = true,
++      },
++};
++
++static const struct ipu_image_pixfmt *get_format(u32 fourcc)
++{
++      const struct ipu_image_pixfmt *ret = NULL;
++      unsigned int i;
++
++      for (i = 0; i < ARRAY_SIZE(image_convert_formats); i++) {
++              if (image_convert_formats[i].fourcc == fourcc) {
++                      ret = &image_convert_formats[i];
++                      break;
++              }
++      }
++
++      return ret;
++}
++
++static void dump_format(struct ipu_image_convert_ctx *ctx,
++                      struct ipu_image_convert_image *ic_image)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++
++      dev_dbg(priv->ipu->dev,
++              "task %u: ctx %p: %s format: %dx%d (%dx%d tiles), %c%c%c%c\n",
++              chan->ic_task, ctx,
++              ic_image->type == IMAGE_CONVERT_OUT ? "Output" : "Input",
++              ic_image->base.pix.width, ic_image->base.pix.height,
++              ic_image->num_cols, ic_image->num_rows,
++              ic_image->fmt->fourcc & 0xff,
++              (ic_image->fmt->fourcc >> 8) & 0xff,
++              (ic_image->fmt->fourcc >> 16) & 0xff,
++              (ic_image->fmt->fourcc >> 24) & 0xff);
++}
++
++int ipu_image_convert_enum_format(int index, u32 *fourcc)
++{
++      const struct ipu_image_pixfmt *fmt;
++
++      if (index >= (int)ARRAY_SIZE(image_convert_formats))
++              return -EINVAL;
++
++      /* Format found */
++      fmt = &image_convert_formats[index];
++      *fourcc = fmt->fourcc;
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_enum_format);
++
++static void free_dma_buf(struct ipu_image_convert_priv *priv,
++                       struct ipu_image_convert_dma_buf *buf)
++{
++      if (buf->virt)
++              dma_free_coherent(priv->ipu->dev,
++                                buf->len, buf->virt, buf->phys);
++      buf->virt = NULL;
++      buf->phys = 0;
++}
++
++static int alloc_dma_buf(struct ipu_image_convert_priv *priv,
++                       struct ipu_image_convert_dma_buf *buf,
++                       int size)
++{
++      buf->len = PAGE_ALIGN(size);
++      buf->virt = dma_alloc_coherent(priv->ipu->dev, buf->len, &buf->phys,
++                                     GFP_DMA | GFP_KERNEL);
++      if (!buf->virt) {
++              dev_err(priv->ipu->dev, "failed to alloc dma buffer\n");
++              return -ENOMEM;
++      }
++
++      return 0;
++}
++
++static inline int num_stripes(int dim)
++{
++      return (dim - 1) / 1024 + 1;
++}
++
++/*
++ * Calculate downsizing coefficients, which are the same for all tiles,
++ * and initial bilinear resizing coefficients, which are used to find the
++ * best seam positions.
++ * Also determine the number of tiles necessary to guarantee that no tile
++ * is larger than 1024 pixels in either dimension at the output and between
++ * IC downsizing and main processing sections.
++ */
++static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
++                                        struct ipu_image *in,
++                                        struct ipu_image *out)
++{
++      u32 downsized_width = in->rect.width;
++      u32 downsized_height = in->rect.height;
++      u32 downsize_coeff_v = 0;
++      u32 downsize_coeff_h = 0;
++      u32 resized_width = out->rect.width;
++      u32 resized_height = out->rect.height;
++      u32 resize_coeff_h;
++      u32 resize_coeff_v;
++      u32 cols;
++      u32 rows;
++
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              resized_width = out->rect.height;
++              resized_height = out->rect.width;
++      }
++
++      /* Do not let invalid input lead to an endless loop below */
++      if (WARN_ON(resized_width == 0 || resized_height == 0))
++              return -EINVAL;
++
++      while (downsized_width >= resized_width * 2) {
++              downsized_width >>= 1;
++              downsize_coeff_h++;
++      }
++
++      while (downsized_height >= resized_height * 2) {
++              downsized_height >>= 1;
++              downsize_coeff_v++;
++      }
++
++      /*
++       * Calculate the bilinear resizing coefficients that could be used if
++       * we were converting with a single tile. The bottom right output pixel
++       * should sample as close as possible to the bottom right input pixel
++       * out of the decimator, but not overshoot it:
++       */
++      resize_coeff_h = 8192 * (downsized_width - 1) / (resized_width - 1);
++      resize_coeff_v = 8192 * (downsized_height - 1) / (resized_height - 1);
++
++      /*
++       * Both the output of the IC downsizing section before being passed to
++       * the IC main processing section and the final output of the IC main
++       * processing section must be <= 1024 pixels in both dimensions.
++       */
++      cols = num_stripes(max_t(u32, downsized_width, resized_width));
++      rows = num_stripes(max_t(u32, downsized_height, resized_height));
++
++      dev_dbg(ctx->chan->priv->ipu->dev,
++              "%s: hscale: >>%u, *8192/%u vscale: >>%u, *8192/%u, %ux%u tiles\n",
++              __func__, downsize_coeff_h, resize_coeff_h, downsize_coeff_v,
++              resize_coeff_v, cols, rows);
++
++      if (downsize_coeff_h > 2 || downsize_coeff_v  > 2 ||
++          resize_coeff_h > 0x3fff || resize_coeff_v > 0x3fff)
++              return -EINVAL;
++
++      ctx->downsize_coeff_h = downsize_coeff_h;
++      ctx->downsize_coeff_v = downsize_coeff_v;
++      ctx->image_resize_coeff_h = resize_coeff_h;
++      ctx->image_resize_coeff_v = resize_coeff_v;
++      ctx->in.num_cols = cols;
++      ctx->in.num_rows = rows;
++
++      return 0;
++}
++
++#define round_closest(x, y) round_down((x) + (y)/2, (y))
++
++/*
++ * Find the best aligned seam position for the given column / row index.
++ * Rotation and image offsets are out of scope.
++ *
++ * @index: column / row index, used to calculate valid interval
++ * @in_edge: input right / bottom edge
++ * @out_edge: output right / bottom edge
++ * @in_align: input alignment, either horizontal 8-byte line start address
++ *            alignment, or pixel alignment due to image format
++ * @out_align: output alignment, either horizontal 8-byte line start address
++ *             alignment, or pixel alignment due to image format or rotator
++ *             block size
++ * @in_burst: horizontal input burst size in case of horizontal flip
++ * @out_burst: horizontal output burst size or rotator block size
++ * @downsize_coeff: downsizing section coefficient
++ * @resize_coeff: main processing section resizing coefficient
++ * @_in_seam: aligned input seam position return value
++ * @_out_seam: aligned output seam position return value
++ */
++static void find_best_seam(struct ipu_image_convert_ctx *ctx,
++                         unsigned int index,
++                         unsigned int in_edge,
++                         unsigned int out_edge,
++                         unsigned int in_align,
++                         unsigned int out_align,
++                         unsigned int in_burst,
++                         unsigned int out_burst,
++                         unsigned int downsize_coeff,
++                         unsigned int resize_coeff,
++                         u32 *_in_seam,
++                         u32 *_out_seam)
++{
++      struct device *dev = ctx->chan->priv->ipu->dev;
++      unsigned int out_pos;
++      /* Input / output seam position candidates */
++      unsigned int out_seam = 0;
++      unsigned int in_seam = 0;
++      unsigned int min_diff = UINT_MAX;
++      unsigned int out_start;
++      unsigned int out_end;
++      unsigned int in_start;
++      unsigned int in_end;
++
++      /* Start within 1024 pixels of the right / bottom edge */
++      out_start = max_t(int, index * out_align, out_edge - 1024);
++      /* End before having to add more columns to the left / rows above */
++      out_end = min_t(unsigned int, out_edge, index * 1024 + 1);
++
++      /*
++       * Limit input seam position to make sure that the downsized input tile
++       * to the right or bottom does not exceed 1024 pixels.
++       */
++      in_start = max_t(int, index * in_align,
++                       in_edge - (1024 << downsize_coeff));
++      in_end = min_t(unsigned int, in_edge,
++                     index * (1024 << downsize_coeff) + 1);
++
++      /*
++       * Output tiles must start at a multiple of 8 bytes horizontally and
++       * possibly at an even line horizontally depending on the pixel format.
++       * Only consider output aligned positions for the seam.
++       */
++      out_start = round_up(out_start, out_align);
++      for (out_pos = out_start; out_pos < out_end; out_pos += out_align) {
++              unsigned int in_pos;
++              unsigned int in_pos_aligned;
++              unsigned int in_pos_rounded;
++              unsigned int abs_diff;
++
++              /*
++               * Tiles in the right row / bottom column may not be allowed to
++               * overshoot horizontally / vertically. out_burst may be the
++               * actual DMA burst size, or the rotator block size.
++               */
++              if ((out_burst > 1) && (out_edge - out_pos) % out_burst)
++                      continue;
++
++              /*
++               * Input sample position, corresponding to out_pos, 19.13 fixed
++               * point.
++               */
++              in_pos = (out_pos * resize_coeff) << downsize_coeff;
++              /*
++               * The closest input sample position that we could actually
++               * start the input tile at, 19.13 fixed point.
++               */
++              in_pos_aligned = round_closest(in_pos, 8192U * in_align);
++              /* Convert 19.13 fixed point to integer */
++              in_pos_rounded = in_pos_aligned / 8192U;
++
++              if (in_pos_rounded < in_start)
++                      continue;
++              if (in_pos_rounded >= in_end)
++                      break;
++
++              if ((in_burst > 1) &&
++                  (in_edge - in_pos_rounded) % in_burst)
++                      continue;
++
++              if (in_pos < in_pos_aligned)
++                      abs_diff = in_pos_aligned - in_pos;
++              else
++                      abs_diff = in_pos - in_pos_aligned;
++
++              if (abs_diff < min_diff) {
++                      in_seam = in_pos_rounded;
++                      out_seam = out_pos;
++                      min_diff = abs_diff;
++              }
++      }
++
++      *_out_seam = out_seam;
++      *_in_seam = in_seam;
++
++      dev_dbg(dev, "%s: out_seam %u(%u) in [%u, %u], in_seam %u(%u) in [%u, %u] diff %u.%03u\n",
++              __func__, out_seam, out_align, out_start, out_end,
++              in_seam, in_align, in_start, in_end, min_diff / 8192,
++              DIV_ROUND_CLOSEST(min_diff % 8192 * 1000, 8192));
++}
++
++/*
++ * Tile left edges are required to be aligned to multiples of 8 bytes
++ * by the IDMAC.
++ */
++static inline u32 tile_left_align(const struct ipu_image_pixfmt *fmt)
++{
++      if (fmt->planar)
++              return fmt->uv_packed ? 8 : 8 * fmt->uv_width_dec;
++      else
++              return fmt->bpp == 32 ? 2 : fmt->bpp == 16 ? 4 : 8;
++}
++
++/*
++ * Tile top edge alignment is only limited by chroma subsampling.
++ */
++static inline u32 tile_top_align(const struct ipu_image_pixfmt *fmt)
++{
++      return fmt->uv_height_dec > 1 ? 2 : 1;
++}
++
++static inline u32 tile_width_align(enum ipu_image_convert_type type,
++                                 const struct ipu_image_pixfmt *fmt,
++                                 enum ipu_rotate_mode rot_mode)
++{
++      if (type == IMAGE_CONVERT_IN) {
++              /*
++               * The IC burst reads 8 pixels at a time. Reading beyond the
++               * end of the line is usually acceptable. Those pixels are
++               * ignored, unless the IC has to write the scaled line in
++               * reverse.
++               */
++              return (!ipu_rot_mode_is_irt(rot_mode) &&
++                      (rot_mode & IPU_ROT_BIT_HFLIP)) ? 8 : 2;
++      }
++
++      /*
++       * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
++       * formats to guarantee 8-byte aligned line start addresses in the
++       * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
++       * for all other formats.
++       */
++      return (ipu_rot_mode_is_irt(rot_mode) &&
++              fmt->planar && !fmt->uv_packed) ?
++              8 * fmt->uv_width_dec : 8;
++}
++
++static inline u32 tile_height_align(enum ipu_image_convert_type type,
++                                  const struct ipu_image_pixfmt *fmt,
++                                  enum ipu_rotate_mode rot_mode)
++{
++      if (type == IMAGE_CONVERT_IN || !ipu_rot_mode_is_irt(rot_mode))
++              return 2;
++
++      /*
++       * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
++       * formats to guarantee 8-byte aligned line start addresses in the
++       * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
++       * for all other formats.
++       */
++      return (fmt->planar && !fmt->uv_packed) ? 8 * fmt->uv_width_dec : 8;
++}
++
++/*
++ * Fill in left position and width and for all tiles in an input column, and
++ * for all corresponding output tiles. If the 90° rotator is used, the output
++ * tiles are in a row, and output tile top position and height are set.
++ */
++static void fill_tile_column(struct ipu_image_convert_ctx *ctx,
++                           unsigned int col,
++                           struct ipu_image_convert_image *in,
++                           unsigned int in_left, unsigned int in_width,
++                           struct ipu_image_convert_image *out,
++                           unsigned int out_left, unsigned int out_width)
++{
++      unsigned int row, tile_idx;
++      struct ipu_image_tile *in_tile, *out_tile;
++
++      for (row = 0; row < in->num_rows; row++) {
++              tile_idx = in->num_cols * row + col;
++              in_tile = &in->tile[tile_idx];
++              out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
++
++              in_tile->left = in_left;
++              in_tile->width = in_width;
++
++              if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++                      out_tile->top = out_left;
++                      out_tile->height = out_width;
++              } else {
++                      out_tile->left = out_left;
++                      out_tile->width = out_width;
++              }
++      }
++}
++
++/*
++ * Fill in top position and height and for all tiles in an input row, and
++ * for all corresponding output tiles. If the 90° rotator is used, the output
++ * tiles are in a column, and output tile left position and width are set.
++ */
++static void fill_tile_row(struct ipu_image_convert_ctx *ctx, unsigned int row,
++                        struct ipu_image_convert_image *in,
++                        unsigned int in_top, unsigned int in_height,
++                        struct ipu_image_convert_image *out,
++                        unsigned int out_top, unsigned int out_height)
++{
++      unsigned int col, tile_idx;
++      struct ipu_image_tile *in_tile, *out_tile;
++
++      for (col = 0; col < in->num_cols; col++) {
++              tile_idx = in->num_cols * row + col;
++              in_tile = &in->tile[tile_idx];
++              out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
++
++              in_tile->top = in_top;
++              in_tile->height = in_height;
++
++              if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++                      out_tile->left = out_top;
++                      out_tile->width = out_height;
++              } else {
++                      out_tile->top = out_top;
++                      out_tile->height = out_height;
++              }
++      }
++}
++
++/*
++ * Find the best horizontal and vertical seam positions to split into tiles.
++ * Minimize the fractional part of the input sampling position for the
++ * top / left pixels of each tile.
++ */
++static void find_seams(struct ipu_image_convert_ctx *ctx,
++                     struct ipu_image_convert_image *in,
++                     struct ipu_image_convert_image *out)
++{
++      struct device *dev = ctx->chan->priv->ipu->dev;
++      unsigned int resized_width = out->base.rect.width;
++      unsigned int resized_height = out->base.rect.height;
++      unsigned int col;
++      unsigned int row;
++      unsigned int in_left_align = tile_left_align(in->fmt);
++      unsigned int in_top_align = tile_top_align(in->fmt);
++      unsigned int out_left_align = tile_left_align(out->fmt);
++      unsigned int out_top_align = tile_top_align(out->fmt);
++      unsigned int out_width_align = tile_width_align(out->type, out->fmt,
++                                                      ctx->rot_mode);
++      unsigned int out_height_align = tile_height_align(out->type, out->fmt,
++                                                        ctx->rot_mode);
++      unsigned int in_right = in->base.rect.width;
++      unsigned int in_bottom = in->base.rect.height;
++      unsigned int out_right = out->base.rect.width;
++      unsigned int out_bottom = out->base.rect.height;
++      unsigned int flipped_out_left;
++      unsigned int flipped_out_top;
++
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              /* Switch width/height and align top left to IRT block size */
++              resized_width = out->base.rect.height;
++              resized_height = out->base.rect.width;
++              out_left_align = out_height_align;
++              out_top_align = out_width_align;
++              out_width_align = out_left_align;
++              out_height_align = out_top_align;
++              out_right = out->base.rect.height;
++              out_bottom = out->base.rect.width;
++      }
++
++      for (col = in->num_cols - 1; col > 0; col--) {
++              bool allow_in_overshoot = ipu_rot_mode_is_irt(ctx->rot_mode) ||
++                                        !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
++              bool allow_out_overshoot = (col < in->num_cols - 1) &&
++                                         !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
++              unsigned int in_left;
++              unsigned int out_left;
++
++              /*
++               * Align input width to burst length if the scaling step flips
++               * horizontally.
++               */
++
++              find_best_seam(ctx, col,
++                             in_right, out_right,
++                             in_left_align, out_left_align,
++                             allow_in_overshoot ? 1 : 8 /* burst length */,
++                             allow_out_overshoot ? 1 : out_width_align,
++                             ctx->downsize_coeff_h, ctx->image_resize_coeff_h,
++                             &in_left, &out_left);
++
++              if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
++                      flipped_out_left = resized_width - out_right;
++              else
++                      flipped_out_left = out_left;
++
++              fill_tile_column(ctx, col, in, in_left, in_right - in_left,
++                               out, flipped_out_left, out_right - out_left);
++
++              dev_dbg(dev, "%s: col %u: %u, %u -> %u, %u\n", __func__, col,
++                      in_left, in_right - in_left,
++                      flipped_out_left, out_right - out_left);
++
++              in_right = in_left;
++              out_right = out_left;
++      }
++
++      flipped_out_left = (ctx->rot_mode & IPU_ROT_BIT_HFLIP) ?
++                         resized_width - out_right : 0;
++
++      fill_tile_column(ctx, 0, in, 0, in_right,
++                       out, flipped_out_left, out_right);
++
++      dev_dbg(dev, "%s: col 0: 0, %u -> %u, %u\n", __func__,
++              in_right, flipped_out_left, out_right);
++
++      for (row = in->num_rows - 1; row > 0; row--) {
++              bool allow_overshoot = row < in->num_rows - 1;
++              unsigned int in_top;
++              unsigned int out_top;
++
++              find_best_seam(ctx, row,
++                             in_bottom, out_bottom,
++                             in_top_align, out_top_align,
++                             1, allow_overshoot ? 1 : out_height_align,
++                             ctx->downsize_coeff_v, ctx->image_resize_coeff_v,
++                             &in_top, &out_top);
++
++              if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
++                  ipu_rot_mode_is_irt(ctx->rot_mode))
++                      flipped_out_top = resized_height - out_bottom;
++              else
++                      flipped_out_top = out_top;
++
++              fill_tile_row(ctx, row, in, in_top, in_bottom - in_top,
++                            out, flipped_out_top, out_bottom - out_top);
++
++              dev_dbg(dev, "%s: row %u: %u, %u -> %u, %u\n", __func__, row,
++                      in_top, in_bottom - in_top,
++                      flipped_out_top, out_bottom - out_top);
++
++              in_bottom = in_top;
++              out_bottom = out_top;
++      }
++
++      if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
++          ipu_rot_mode_is_irt(ctx->rot_mode))
++              flipped_out_top = resized_height - out_bottom;
++      else
++              flipped_out_top = 0;
++
++      fill_tile_row(ctx, 0, in, 0, in_bottom,
++                    out, flipped_out_top, out_bottom);
++
++      dev_dbg(dev, "%s: row 0: 0, %u -> %u, %u\n", __func__,
++              in_bottom, flipped_out_top, out_bottom);
++}
++
++static int calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
++                              struct ipu_image_convert_image *image)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      unsigned int max_width = 1024;
++      unsigned int max_height = 1024;
++      unsigned int i;
++
++      if (image->type == IMAGE_CONVERT_IN) {
++              /* Up to 4096x4096 input tile size */
++              max_width <<= ctx->downsize_coeff_h;
++              max_height <<= ctx->downsize_coeff_v;
++      }
++
++      for (i = 0; i < ctx->num_tiles; i++) {
++              struct ipu_image_tile *tile;
++              const unsigned int row = i / image->num_cols;
++              const unsigned int col = i % image->num_cols;
++
++              if (image->type == IMAGE_CONVERT_OUT)
++                      tile = &image->tile[ctx->out_tile_map[i]];
++              else
++                      tile = &image->tile[i];
++
++              tile->size = ((tile->height * image->fmt->bpp) >> 3) *
++                      tile->width;
++
++              if (image->fmt->planar) {
++                      tile->stride = tile->width;
++                      tile->rot_stride = tile->height;
++              } else {
++                      tile->stride =
++                              (image->fmt->bpp * tile->width) >> 3;
++                      tile->rot_stride =
++                              (image->fmt->bpp * tile->height) >> 3;
++              }
++
++              dev_dbg(priv->ipu->dev,
++                      "task %u: ctx %p: %s@[%u,%u]: %ux%u@%u,%u\n",
++                      chan->ic_task, ctx,
++                      image->type == IMAGE_CONVERT_IN ? "Input" : "Output",
++                      row, col,
++                      tile->width, tile->height, tile->left, tile->top);
++
++              if (!tile->width || tile->width > max_width ||
++                  !tile->height || tile->height > max_height) {
++                      dev_err(priv->ipu->dev, "invalid %s tile size: %ux%u\n",
++                              image->type == IMAGE_CONVERT_IN ? "input" :
++                              "output", tile->width, tile->height);
++                      return -EINVAL;
++              }
++      }
++
++      return 0;
++}
++
++/*
++ * Use the rotation transformation to find the tile coordinates
++ * (row, col) of a tile in the destination frame that corresponds
++ * to the given tile coordinates of a source frame. The destination
++ * coordinate is then converted to a tile index.
++ */
++static int transform_tile_index(struct ipu_image_convert_ctx *ctx,
++                              int src_row, int src_col)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_convert_image *s_image = &ctx->in;
++      struct ipu_image_convert_image *d_image = &ctx->out;
++      int dst_row, dst_col;
++
++      /* with no rotation it's a 1:1 mapping */
++      if (ctx->rot_mode == IPU_ROTATE_NONE)
++              return src_row * s_image->num_cols + src_col;
++
++      /*
++       * before doing the transform, first we have to translate
++       * source row,col for an origin in the center of s_image
++       */
++      src_row = src_row * 2 - (s_image->num_rows - 1);
++      src_col = src_col * 2 - (s_image->num_cols - 1);
++
++      /* do the rotation transform */
++      if (ctx->rot_mode & IPU_ROT_BIT_90) {
++              dst_col = -src_row;
++              dst_row = src_col;
++      } else {
++              dst_col = src_col;
++              dst_row = src_row;
++      }
++
++      /* apply flip */
++      if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
++              dst_col = -dst_col;
++      if (ctx->rot_mode & IPU_ROT_BIT_VFLIP)
++              dst_row = -dst_row;
++
++      dev_dbg(priv->ipu->dev, "task %u: ctx %p: [%d,%d] --> [%d,%d]\n",
++              chan->ic_task, ctx, src_col, src_row, dst_col, dst_row);
++
++      /*
++       * finally translate dest row,col using an origin in upper
++       * left of d_image
++       */
++      dst_row += d_image->num_rows - 1;
++      dst_col += d_image->num_cols - 1;
++      dst_row /= 2;
++      dst_col /= 2;
++
++      return dst_row * d_image->num_cols + dst_col;
++}
++
++/*
++ * Fill the out_tile_map[] with transformed destination tile indeces.
++ */
++static void calc_out_tile_map(struct ipu_image_convert_ctx *ctx)
++{
++      struct ipu_image_convert_image *s_image = &ctx->in;
++      unsigned int row, col, tile = 0;
++
++      for (row = 0; row < s_image->num_rows; row++) {
++              for (col = 0; col < s_image->num_cols; col++) {
++                      ctx->out_tile_map[tile] =
++                              transform_tile_index(ctx, row, col);
++                      tile++;
++              }
++      }
++}
++
++static int calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
++                                  struct ipu_image_convert_image *image)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      const struct ipu_image_pixfmt *fmt = image->fmt;
++      unsigned int row, col, tile = 0;
++      u32 H, top, y_stride, uv_stride;
++      u32 uv_row_off, uv_col_off, uv_off, u_off, v_off, tmp;
++      u32 y_row_off, y_col_off, y_off;
++      u32 y_size, uv_size;
++
++      /* setup some convenience vars */
++      H = image->base.pix.height;
++
++      y_stride = image->stride;
++      uv_stride = y_stride / fmt->uv_width_dec;
++      if (fmt->uv_packed)
++              uv_stride *= 2;
++
++      y_size = H * y_stride;
++      uv_size = y_size / (fmt->uv_width_dec * fmt->uv_height_dec);
++
++      for (row = 0; row < image->num_rows; row++) {
++              top = image->tile[tile].top;
++              y_row_off = top * y_stride;
++              uv_row_off = (top * uv_stride) / fmt->uv_height_dec;
++
++              for (col = 0; col < image->num_cols; col++) {
++                      y_col_off = image->tile[tile].left;
++                      uv_col_off = y_col_off / fmt->uv_width_dec;
++                      if (fmt->uv_packed)
++                              uv_col_off *= 2;
++
++                      y_off = y_row_off + y_col_off;
++                      uv_off = uv_row_off + uv_col_off;
++
++                      u_off = y_size - y_off + uv_off;
++                      v_off = (fmt->uv_packed) ? 0 : u_off + uv_size;
++                      if (fmt->uv_swapped) {
++                              tmp = u_off;
++                              u_off = v_off;
++                              v_off = tmp;
++                      }
++
++                      image->tile[tile].offset = y_off;
++                      image->tile[tile].u_off = u_off;
++                      image->tile[tile++].v_off = v_off;
++
++                      if ((y_off & 0x7) || (u_off & 0x7) || (v_off & 0x7)) {
++                              dev_err(priv->ipu->dev,
++                                      "task %u: ctx %p: %s@[%d,%d]: "
++                                      "y_off %08x, u_off %08x, v_off %08x\n",
++                                      chan->ic_task, ctx,
++                                      image->type == IMAGE_CONVERT_IN ?
++                                      "Input" : "Output", row, col,
++                                      y_off, u_off, v_off);
++                              return -EINVAL;
++                      }
++              }
++      }
++
++      return 0;
++}
++
++static int calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
++                                  struct ipu_image_convert_image *image)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      const struct ipu_image_pixfmt *fmt = image->fmt;
++      unsigned int row, col, tile = 0;
++      u32 bpp, stride, offset;
++      u32 row_off, col_off;
++
++      /* setup some convenience vars */
++      stride = image->stride;
++      bpp = fmt->bpp;
++
++      for (row = 0; row < image->num_rows; row++) {
++              row_off = image->tile[tile].top * stride;
++
++              for (col = 0; col < image->num_cols; col++) {
++                      col_off = (image->tile[tile].left * bpp) >> 3;
++
++                      offset = row_off + col_off;
++
++                      image->tile[tile].offset = offset;
++                      image->tile[tile].u_off = 0;
++                      image->tile[tile++].v_off = 0;
++
++                      if (offset & 0x7) {
++                              dev_err(priv->ipu->dev,
++                                      "task %u: ctx %p: %s@[%d,%d]: "
++                                      "phys %08x\n",
++                                      chan->ic_task, ctx,
++                                      image->type == IMAGE_CONVERT_IN ?
++                                      "Input" : "Output", row, col,
++                                      row_off + col_off);
++                              return -EINVAL;
++                      }
++              }
++      }
++
++      return 0;
++}
++
++static int calc_tile_offsets(struct ipu_image_convert_ctx *ctx,
++                            struct ipu_image_convert_image *image)
++{
++      if (image->fmt->planar)
++              return calc_tile_offsets_planar(ctx, image);
++
++      return calc_tile_offsets_packed(ctx, image);
++}
++
++/*
++ * Calculate the resizing ratio for the IC main processing section given input
++ * size, fixed downsizing coefficient, and output size.
++ * Either round to closest for the next tile's first pixel to minimize seams
++ * and distortion (for all but right column / bottom row), or round down to
++ * avoid sampling beyond the edges of the input image for this tile's last
++ * pixel.
++ * Returns the resizing coefficient, resizing ratio is 8192.0 / resize_coeff.
++ */
++static u32 calc_resize_coeff(u32 input_size, u32 downsize_coeff,
++                           u32 output_size, bool allow_overshoot)
++{
++      u32 downsized = input_size >> downsize_coeff;
++
++      if (allow_overshoot)
++              return DIV_ROUND_CLOSEST(8192 * downsized, output_size);
++      else
++              return 8192 * (downsized - 1) / (output_size - 1);
++}
++
++/*
++ * Slightly modify resize coefficients per tile to hide the bilinear
++ * interpolator reset at tile borders, shifting the right / bottom edge
++ * by up to a half input pixel. This removes noticeable seams between
++ * tiles at higher upscaling factors.
++ */
++static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_tile *in_tile, *out_tile;
++      unsigned int col, row, tile_idx;
++      unsigned int last_output;
++
++      for (col = 0; col < ctx->in.num_cols; col++) {
++              bool closest = (col < ctx->in.num_cols - 1) &&
++                             !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
++              u32 resized_width;
++              u32 resize_coeff_h;
++              u32 in_width;
++
++              tile_idx = col;
++              in_tile = &ctx->in.tile[tile_idx];
++              out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
++
++              if (ipu_rot_mode_is_irt(ctx->rot_mode))
++                      resized_width = out_tile->height;
++              else
++                      resized_width = out_tile->width;
++
++              resize_coeff_h = calc_resize_coeff(in_tile->width,
++                                                 ctx->downsize_coeff_h,
++                                                 resized_width, closest);
++
++              dev_dbg(priv->ipu->dev, "%s: column %u hscale: *8192/%u\n",
++                      __func__, col, resize_coeff_h);
++
++              /*
++               * With the horizontal scaling factor known, round up resized
++               * width (output width or height) to burst size.
++               */
++              resized_width = round_up(resized_width, 8);
++
++              /*
++               * Calculate input width from the last accessed input pixel
++               * given resized width and scaling coefficients. Round up to
++               * burst size.
++               */
++              last_output = resized_width - 1;
++              if (closest && ((last_output * resize_coeff_h) % 8192))
++                      last_output++;
++              in_width = round_up(
++                      (DIV_ROUND_UP(last_output * resize_coeff_h, 8192) + 1)
++                      << ctx->downsize_coeff_h, 8);
++
++              for (row = 0; row < ctx->in.num_rows; row++) {
++                      tile_idx = row * ctx->in.num_cols + col;
++                      in_tile = &ctx->in.tile[tile_idx];
++                      out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
++
++                      if (ipu_rot_mode_is_irt(ctx->rot_mode))
++                              out_tile->height = resized_width;
++                      else
++                              out_tile->width = resized_width;
++
++                      in_tile->width = in_width;
++              }
++
++              ctx->resize_coeffs_h[col] = resize_coeff_h;
++      }
++
++      for (row = 0; row < ctx->in.num_rows; row++) {
++              bool closest = (row < ctx->in.num_rows - 1) &&
++                             !(ctx->rot_mode & IPU_ROT_BIT_VFLIP);
++              u32 resized_height;
++              u32 resize_coeff_v;
++              u32 in_height;
++
++              tile_idx = row * ctx->in.num_cols;
++              in_tile = &ctx->in.tile[tile_idx];
++              out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
++
++              if (ipu_rot_mode_is_irt(ctx->rot_mode))
++                      resized_height = out_tile->width;
++              else
++                      resized_height = out_tile->height;
++
++              resize_coeff_v = calc_resize_coeff(in_tile->height,
++                                                 ctx->downsize_coeff_v,
++                                                 resized_height, closest);
++
++              dev_dbg(priv->ipu->dev, "%s: row %u vscale: *8192/%u\n",
++                      __func__, row, resize_coeff_v);
++
++              /*
++               * With the vertical scaling factor known, round up resized
++               * height (output width or height) to IDMAC limitations.
++               */
++              resized_height = round_up(resized_height, 2);
++
++              /*
++               * Calculate input width from the last accessed input pixel
++               * given resized height and scaling coefficients. Align to
++               * IDMAC restrictions.
++               */
++              last_output = resized_height - 1;
++              if (closest && ((last_output * resize_coeff_v) % 8192))
++                      last_output++;
++              in_height = round_up(
++                      (DIV_ROUND_UP(last_output * resize_coeff_v, 8192) + 1)
++                      << ctx->downsize_coeff_v, 2);
++
++              for (col = 0; col < ctx->in.num_cols; col++) {
++                      tile_idx = row * ctx->in.num_cols + col;
++                      in_tile = &ctx->in.tile[tile_idx];
++                      out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
++
++                      if (ipu_rot_mode_is_irt(ctx->rot_mode))
++                              out_tile->width = resized_height;
++                      else
++                              out_tile->height = resized_height;
++
++                      in_tile->height = in_height;
++              }
++
++              ctx->resize_coeffs_v[row] = resize_coeff_v;
++      }
++}
++
++/*
++ * return the number of runs in given queue (pending_q or done_q)
++ * for this context. hold irqlock when calling.
++ */
++static int get_run_count(struct ipu_image_convert_ctx *ctx,
++                       struct list_head *q)
++{
++      struct ipu_image_convert_run *run;
++      int count = 0;
++
++      lockdep_assert_held(&ctx->chan->irqlock);
++
++      list_for_each_entry(run, q, list) {
++              if (run->ctx == ctx)
++                      count++;
++      }
++
++      return count;
++}
++
++static void convert_stop(struct ipu_image_convert_run *run)
++{
++      struct ipu_image_convert_ctx *ctx = run->ctx;
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++
++      dev_dbg(priv->ipu->dev, "%s: task %u: stopping ctx %p run %p\n",
++              __func__, chan->ic_task, ctx, run);
++
++      /* disable IC tasks and the channels */
++      ipu_ic_task_disable(chan->ic);
++      ipu_idmac_disable_channel(chan->in_chan);
++      ipu_idmac_disable_channel(chan->out_chan);
++
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              ipu_idmac_disable_channel(chan->rotation_in_chan);
++              ipu_idmac_disable_channel(chan->rotation_out_chan);
++              ipu_idmac_unlink(chan->out_chan, chan->rotation_in_chan);
++      }
++
++      ipu_ic_disable(chan->ic);
++}
++
++static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
++                             struct ipuv3_channel *channel,
++                             struct ipu_image_convert_image *image,
++                             enum ipu_rotate_mode rot_mode,
++                             bool rot_swap_width_height,
++                             unsigned int tile)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      unsigned int burst_size;
++      u32 width, height, stride;
++      dma_addr_t addr0, addr1 = 0;
++      struct ipu_image tile_image;
++      unsigned int tile_idx[2];
++
++      if (image->type == IMAGE_CONVERT_OUT) {
++              tile_idx[0] = ctx->out_tile_map[tile];
++              tile_idx[1] = ctx->out_tile_map[1];
++      } else {
++              tile_idx[0] = tile;
++              tile_idx[1] = 1;
++      }
++
++      if (rot_swap_width_height) {
++              width = image->tile[tile_idx[0]].height;
++              height = image->tile[tile_idx[0]].width;
++              stride = image->tile[tile_idx[0]].rot_stride;
++              addr0 = ctx->rot_intermediate[0].phys;
++              if (ctx->double_buffering)
++                      addr1 = ctx->rot_intermediate[1].phys;
++      } else {
++              width = image->tile[tile_idx[0]].width;
++              height = image->tile[tile_idx[0]].height;
++              stride = image->stride;
++              addr0 = image->base.phys0 +
++                      image->tile[tile_idx[0]].offset;
++              if (ctx->double_buffering)
++                      addr1 = image->base.phys0 +
++                              image->tile[tile_idx[1]].offset;
++      }
++
++      ipu_cpmem_zero(channel);
++
++      memset(&tile_image, 0, sizeof(tile_image));
++      tile_image.pix.width = tile_image.rect.width = width;
++      tile_image.pix.height = tile_image.rect.height = height;
++      tile_image.pix.bytesperline = stride;
++      tile_image.pix.pixelformat =  image->fmt->fourcc;
++      tile_image.phys0 = addr0;
++      tile_image.phys1 = addr1;
++      if (image->fmt->planar && !rot_swap_width_height) {
++              tile_image.u_offset = image->tile[tile_idx[0]].u_off;
++              tile_image.v_offset = image->tile[tile_idx[0]].v_off;
++      }
++
++      ipu_cpmem_set_image(channel, &tile_image);
++
++      if (rot_mode)
++              ipu_cpmem_set_rotation(channel, rot_mode);
++
++      /*
++       * Skip writing U and V components to odd rows in the output
++       * channels for planar 4:2:0.
++       */
++      if ((channel == chan->out_chan ||
++           channel == chan->rotation_out_chan) &&
++          image->fmt->planar && image->fmt->uv_height_dec == 2)
++              ipu_cpmem_skip_odd_chroma_rows(channel);
++
++      if (channel == chan->rotation_in_chan ||
++          channel == chan->rotation_out_chan) {
++              burst_size = 8;
++              ipu_cpmem_set_block_mode(channel);
++      } else
++              burst_size = (width % 16) ? 8 : 16;
++
++      ipu_cpmem_set_burstsize(channel, burst_size);
++
++      ipu_ic_task_idma_init(chan->ic, channel, width, height,
++                            burst_size, rot_mode);
++
++      /*
++       * Setting a non-zero AXI ID collides with the PRG AXI snooping, so
++       * only do this when there is no PRG present.
++       */
++      if (!channel->ipu->prg_priv)
++              ipu_cpmem_set_axi_id(channel, 1);
++
++      ipu_idmac_set_double_buffer(channel, ctx->double_buffering);
++}
++
++static int convert_start(struct ipu_image_convert_run *run, unsigned int tile)
++{
++      struct ipu_image_convert_ctx *ctx = run->ctx;
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_convert_image *s_image = &ctx->in;
++      struct ipu_image_convert_image *d_image = &ctx->out;
++      unsigned int dst_tile = ctx->out_tile_map[tile];
++      unsigned int dest_width, dest_height;
++      unsigned int col, row;
++      u32 rsc;
++      int ret;
++
++      dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n",
++              __func__, chan->ic_task, ctx, run, tile, dst_tile);
++
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              /* swap width/height for resizer */
++              dest_width = d_image->tile[dst_tile].height;
++              dest_height = d_image->tile[dst_tile].width;
++      } else {
++              dest_width = d_image->tile[dst_tile].width;
++              dest_height = d_image->tile[dst_tile].height;
++      }
++
++      row = tile / s_image->num_cols;
++      col = tile % s_image->num_cols;
++
++      rsc =  (ctx->downsize_coeff_v << 30) |
++             (ctx->resize_coeffs_v[row] << 16) |
++             (ctx->downsize_coeff_h << 14) |
++             (ctx->resize_coeffs_h[col]);
++
++      dev_dbg(priv->ipu->dev, "%s: %ux%u -> %ux%u (rsc = 0x%x)\n",
++              __func__, s_image->tile[tile].width,
++              s_image->tile[tile].height, dest_width, dest_height, rsc);
++
++      /* setup the IC resizer and CSC */
++      ret = ipu_ic_task_init_rsc(chan->ic, &ctx->csc,
++                                 s_image->tile[tile].width,
++                                 s_image->tile[tile].height,
++                                 dest_width,
++                                 dest_height,
++                                 rsc);
++      if (ret) {
++              dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret);
++              return ret;
++      }
++
++      /* init the source MEM-->IC PP IDMAC channel */
++      init_idmac_channel(ctx, chan->in_chan, s_image,
++                         IPU_ROTATE_NONE, false, tile);
++
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              /* init the IC PP-->MEM IDMAC channel */
++              init_idmac_channel(ctx, chan->out_chan, d_image,
++                                 IPU_ROTATE_NONE, true, tile);
++
++              /* init the MEM-->IC PP ROT IDMAC channel */
++              init_idmac_channel(ctx, chan->rotation_in_chan, d_image,
++                                 ctx->rot_mode, true, tile);
++
++              /* init the destination IC PP ROT-->MEM IDMAC channel */
++              init_idmac_channel(ctx, chan->rotation_out_chan, d_image,
++                                 IPU_ROTATE_NONE, false, tile);
++
++              /* now link IC PP-->MEM to MEM-->IC PP ROT */
++              ipu_idmac_link(chan->out_chan, chan->rotation_in_chan);
++      } else {
++              /* init the destination IC PP-->MEM IDMAC channel */
++              init_idmac_channel(ctx, chan->out_chan, d_image,
++                                 ctx->rot_mode, false, tile);
++      }
++
++      /* enable the IC */
++      ipu_ic_enable(chan->ic);
++
++      /* set buffers ready */
++      ipu_idmac_select_buffer(chan->in_chan, 0);
++      ipu_idmac_select_buffer(chan->out_chan, 0);
++      if (ipu_rot_mode_is_irt(ctx->rot_mode))
++              ipu_idmac_select_buffer(chan->rotation_out_chan, 0);
++      if (ctx->double_buffering) {
++              ipu_idmac_select_buffer(chan->in_chan, 1);
++              ipu_idmac_select_buffer(chan->out_chan, 1);
++              if (ipu_rot_mode_is_irt(ctx->rot_mode))
++                      ipu_idmac_select_buffer(chan->rotation_out_chan, 1);
++      }
++
++      /* enable the channels! */
++      ipu_idmac_enable_channel(chan->in_chan);
++      ipu_idmac_enable_channel(chan->out_chan);
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              ipu_idmac_enable_channel(chan->rotation_in_chan);
++              ipu_idmac_enable_channel(chan->rotation_out_chan);
++      }
++
++      ipu_ic_task_enable(chan->ic);
++
++      ipu_cpmem_dump(chan->in_chan);
++      ipu_cpmem_dump(chan->out_chan);
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              ipu_cpmem_dump(chan->rotation_in_chan);
++              ipu_cpmem_dump(chan->rotation_out_chan);
++      }
++
++      ipu_dump(priv->ipu);
++
++      return 0;
++}
++
++/* hold irqlock when calling */
++static int do_run(struct ipu_image_convert_run *run)
++{
++      struct ipu_image_convert_ctx *ctx = run->ctx;
++      struct ipu_image_convert_chan *chan = ctx->chan;
++
++      lockdep_assert_held(&chan->irqlock);
++
++      ctx->in.base.phys0 = run->in_phys;
++      ctx->out.base.phys0 = run->out_phys;
++
++      ctx->cur_buf_num = 0;
++      ctx->next_tile = 1;
++
++      /* remove run from pending_q and set as current */
++      list_del(&run->list);
++      chan->current_run = run;
++
++      return convert_start(run, 0);
++}
++
++/* hold irqlock when calling */
++static void run_next(struct ipu_image_convert_chan *chan)
++{
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_convert_run *run, *tmp;
++      int ret;
++
++      lockdep_assert_held(&chan->irqlock);
++
++      list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
++              /* skip contexts that are aborting */
++              if (run->ctx->aborting) {
++                      dev_dbg(priv->ipu->dev,
++                              "%s: task %u: skipping aborting ctx %p run %p\n",
++                              __func__, chan->ic_task, run->ctx, run);
++                      continue;
++              }
++
++              ret = do_run(run);
++              if (!ret)
++                      break;
++
++              /*
++               * something went wrong with start, add the run
++               * to done q and continue to the next run in the
++               * pending q.
++               */
++              run->status = ret;
++              list_add_tail(&run->list, &chan->done_q);
++              chan->current_run = NULL;
++      }
++}
++
++static void empty_done_q(struct ipu_image_convert_chan *chan)
++{
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_convert_run *run;
++      unsigned long flags;
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      while (!list_empty(&chan->done_q)) {
++              run = list_entry(chan->done_q.next,
++                               struct ipu_image_convert_run,
++                               list);
++
++              list_del(&run->list);
++
++              dev_dbg(priv->ipu->dev,
++                      "%s: task %u: completing ctx %p run %p with %d\n",
++                      __func__, chan->ic_task, run->ctx, run, run->status);
++
++              /* call the completion callback and free the run */
++              spin_unlock_irqrestore(&chan->irqlock, flags);
++              run->ctx->complete(run, run->ctx->complete_context);
++              spin_lock_irqsave(&chan->irqlock, flags);
++      }
++
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++}
++
++/*
++ * the bottom half thread clears out the done_q, calling the
++ * completion handler for each.
++ */
++static irqreturn_t do_bh(int irq, void *dev_id)
++{
++      struct ipu_image_convert_chan *chan = dev_id;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_convert_ctx *ctx;
++      unsigned long flags;
++
++      dev_dbg(priv->ipu->dev, "%s: task %u: enter\n", __func__,
++              chan->ic_task);
++
++      empty_done_q(chan);
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      /*
++       * the done_q is cleared out, signal any contexts
++       * that are aborting that abort can complete.
++       */
++      list_for_each_entry(ctx, &chan->ctx_list, list) {
++              if (ctx->aborting) {
++                      dev_dbg(priv->ipu->dev,
++                              "%s: task %u: signaling abort for ctx %p\n",
++                              __func__, chan->ic_task, ctx);
++                      complete_all(&ctx->aborted);
++              }
++      }
++
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++
++      dev_dbg(priv->ipu->dev, "%s: task %u: exit\n", __func__,
++              chan->ic_task);
++
++      return IRQ_HANDLED;
++}
++
++static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx)
++{
++      unsigned int cur_tile = ctx->next_tile - 1;
++      unsigned int next_tile = ctx->next_tile;
++
++      if (ctx->resize_coeffs_h[cur_tile % ctx->in.num_cols] !=
++          ctx->resize_coeffs_h[next_tile % ctx->in.num_cols] ||
++          ctx->resize_coeffs_v[cur_tile / ctx->in.num_cols] !=
++          ctx->resize_coeffs_v[next_tile / ctx->in.num_cols] ||
++          ctx->in.tile[cur_tile].width != ctx->in.tile[next_tile].width ||
++          ctx->in.tile[cur_tile].height != ctx->in.tile[next_tile].height ||
++          ctx->out.tile[cur_tile].width != ctx->out.tile[next_tile].width ||
++          ctx->out.tile[cur_tile].height != ctx->out.tile[next_tile].height)
++              return true;
++
++      return false;
++}
++
++/* hold irqlock when calling */
++static irqreturn_t do_irq(struct ipu_image_convert_run *run)
++{
++      struct ipu_image_convert_ctx *ctx = run->ctx;
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_tile *src_tile, *dst_tile;
++      struct ipu_image_convert_image *s_image = &ctx->in;
++      struct ipu_image_convert_image *d_image = &ctx->out;
++      struct ipuv3_channel *outch;
++      unsigned int dst_idx;
++
++      lockdep_assert_held(&chan->irqlock);
++
++      outch = ipu_rot_mode_is_irt(ctx->rot_mode) ?
++              chan->rotation_out_chan : chan->out_chan;
++
++      /*
++       * It is difficult to stop the channel DMA before the channels
++       * enter the paused state. Without double-buffering the channels
++       * are always in a paused state when the EOF irq occurs, so it
++       * is safe to stop the channels now. For double-buffering we
++       * just ignore the abort until the operation completes, when it
++       * is safe to shut down.
++       */
++      if (ctx->aborting && !ctx->double_buffering) {
++              convert_stop(run);
++              run->status = -EIO;
++              goto done;
++      }
++
++      if (ctx->next_tile == ctx->num_tiles) {
++              /*
++               * the conversion is complete
++               */
++              convert_stop(run);
++              run->status = 0;
++              goto done;
++      }
++
++      /*
++       * not done, place the next tile buffers.
++       */
++      if (!ctx->double_buffering) {
++              if (ic_settings_changed(ctx)) {
++                      convert_stop(run);
++                      convert_start(run, ctx->next_tile);
++              } else {
++                      src_tile = &s_image->tile[ctx->next_tile];
++                      dst_idx = ctx->out_tile_map[ctx->next_tile];
++                      dst_tile = &d_image->tile[dst_idx];
++
++                      ipu_cpmem_set_buffer(chan->in_chan, 0,
++                                           s_image->base.phys0 +
++                                           src_tile->offset);
++                      ipu_cpmem_set_buffer(outch, 0,
++                                           d_image->base.phys0 +
++                                           dst_tile->offset);
++                      if (s_image->fmt->planar)
++                              ipu_cpmem_set_uv_offset(chan->in_chan,
++                                                      src_tile->u_off,
++                                                      src_tile->v_off);
++                      if (d_image->fmt->planar)
++                              ipu_cpmem_set_uv_offset(outch,
++                                                      dst_tile->u_off,
++                                                      dst_tile->v_off);
++
++                      ipu_idmac_select_buffer(chan->in_chan, 0);
++                      ipu_idmac_select_buffer(outch, 0);
++              }
++      } else if (ctx->next_tile < ctx->num_tiles - 1) {
++
++              src_tile = &s_image->tile[ctx->next_tile + 1];
++              dst_idx = ctx->out_tile_map[ctx->next_tile + 1];
++              dst_tile = &d_image->tile[dst_idx];
++
++              ipu_cpmem_set_buffer(chan->in_chan, ctx->cur_buf_num,
++                                   s_image->base.phys0 + src_tile->offset);
++              ipu_cpmem_set_buffer(outch, ctx->cur_buf_num,
++                                   d_image->base.phys0 + dst_tile->offset);
++
++              ipu_idmac_select_buffer(chan->in_chan, ctx->cur_buf_num);
++              ipu_idmac_select_buffer(outch, ctx->cur_buf_num);
++
++              ctx->cur_buf_num ^= 1;
++      }
++
++      ctx->next_tile++;
++      return IRQ_HANDLED;
++done:
++      list_add_tail(&run->list, &chan->done_q);
++      chan->current_run = NULL;
++      run_next(chan);
++      return IRQ_WAKE_THREAD;
++}
++
++static irqreturn_t norotate_irq(int irq, void *data)
++{
++      struct ipu_image_convert_chan *chan = data;
++      struct ipu_image_convert_ctx *ctx;
++      struct ipu_image_convert_run *run;
++      unsigned long flags;
++      irqreturn_t ret;
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      /* get current run and its context */
++      run = chan->current_run;
++      if (!run) {
++              ret = IRQ_NONE;
++              goto out;
++      }
++
++      ctx = run->ctx;
++
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              /* this is a rotation operation, just ignore */
++              spin_unlock_irqrestore(&chan->irqlock, flags);
++              return IRQ_HANDLED;
++      }
++
++      ret = do_irq(run);
++out:
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++      return ret;
++}
++
++static irqreturn_t rotate_irq(int irq, void *data)
++{
++      struct ipu_image_convert_chan *chan = data;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_convert_ctx *ctx;
++      struct ipu_image_convert_run *run;
++      unsigned long flags;
++      irqreturn_t ret;
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      /* get current run and its context */
++      run = chan->current_run;
++      if (!run) {
++              ret = IRQ_NONE;
++              goto out;
++      }
++
++      ctx = run->ctx;
++
++      if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              /* this was NOT a rotation operation, shouldn't happen */
++              dev_err(priv->ipu->dev, "Unexpected rotation interrupt\n");
++              spin_unlock_irqrestore(&chan->irqlock, flags);
++              return IRQ_HANDLED;
++      }
++
++      ret = do_irq(run);
++out:
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++      return ret;
++}
++
++/*
++ * try to force the completion of runs for this ctx. Called when
++ * abort wait times out in ipu_image_convert_abort().
++ */
++static void force_abort(struct ipu_image_convert_ctx *ctx)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_run *run;
++      unsigned long flags;
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      run = chan->current_run;
++      if (run && run->ctx == ctx) {
++              convert_stop(run);
++              run->status = -EIO;
++              list_add_tail(&run->list, &chan->done_q);
++              chan->current_run = NULL;
++              run_next(chan);
++      }
++
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++
++      empty_done_q(chan);
++}
++
++static void release_ipu_resources(struct ipu_image_convert_chan *chan)
++{
++      if (chan->out_eof_irq >= 0)
++              free_irq(chan->out_eof_irq, chan);
++      if (chan->rot_out_eof_irq >= 0)
++              free_irq(chan->rot_out_eof_irq, chan);
++
++      if (!IS_ERR_OR_NULL(chan->in_chan))
++              ipu_idmac_put(chan->in_chan);
++      if (!IS_ERR_OR_NULL(chan->out_chan))
++              ipu_idmac_put(chan->out_chan);
++      if (!IS_ERR_OR_NULL(chan->rotation_in_chan))
++              ipu_idmac_put(chan->rotation_in_chan);
++      if (!IS_ERR_OR_NULL(chan->rotation_out_chan))
++              ipu_idmac_put(chan->rotation_out_chan);
++      if (!IS_ERR_OR_NULL(chan->ic))
++              ipu_ic_put(chan->ic);
++
++      chan->in_chan = chan->out_chan = chan->rotation_in_chan =
++              chan->rotation_out_chan = NULL;
++      chan->out_eof_irq = chan->rot_out_eof_irq = -1;
++}
++
++static int get_ipu_resources(struct ipu_image_convert_chan *chan)
++{
++      const struct ipu_image_convert_dma_chan *dma = chan->dma_ch;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      int ret;
++
++      /* get IC */
++      chan->ic = ipu_ic_get(priv->ipu, chan->ic_task);
++      if (IS_ERR(chan->ic)) {
++              dev_err(priv->ipu->dev, "could not acquire IC\n");
++              ret = PTR_ERR(chan->ic);
++              goto err;
++      }
++
++      /* get IDMAC channels */
++      chan->in_chan = ipu_idmac_get(priv->ipu, dma->in);
++      chan->out_chan = ipu_idmac_get(priv->ipu, dma->out);
++      if (IS_ERR(chan->in_chan) || IS_ERR(chan->out_chan)) {
++              dev_err(priv->ipu->dev, "could not acquire idmac channels\n");
++              ret = -EBUSY;
++              goto err;
++      }
++
++      chan->rotation_in_chan = ipu_idmac_get(priv->ipu, dma->rot_in);
++      chan->rotation_out_chan = ipu_idmac_get(priv->ipu, dma->rot_out);
++      if (IS_ERR(chan->rotation_in_chan) || IS_ERR(chan->rotation_out_chan)) {
++              dev_err(priv->ipu->dev,
++                      "could not acquire idmac rotation channels\n");
++              ret = -EBUSY;
++              goto err;
++      }
++
++      /* acquire the EOF interrupts */
++      chan->out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
++                                                chan->out_chan,
++                                                IPU_IRQ_EOF);
++
++      ret = request_threaded_irq(chan->out_eof_irq, norotate_irq, do_bh,
++                                 0, "ipu-ic", chan);
++      if (ret < 0) {
++              dev_err(priv->ipu->dev, "could not acquire irq %d\n",
++                       chan->out_eof_irq);
++              chan->out_eof_irq = -1;
++              goto err;
++      }
++
++      chan->rot_out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
++                                                   chan->rotation_out_chan,
++                                                   IPU_IRQ_EOF);
++
++      ret = request_threaded_irq(chan->rot_out_eof_irq, rotate_irq, do_bh,
++                                 0, "ipu-ic", chan);
++      if (ret < 0) {
++              dev_err(priv->ipu->dev, "could not acquire irq %d\n",
++                      chan->rot_out_eof_irq);
++              chan->rot_out_eof_irq = -1;
++              goto err;
++      }
++
++      return 0;
++err:
++      release_ipu_resources(chan);
++      return ret;
++}
++
++static int fill_image(struct ipu_image_convert_ctx *ctx,
++                    struct ipu_image_convert_image *ic_image,
++                    struct ipu_image *image,
++                    enum ipu_image_convert_type type)
++{
++      struct ipu_image_convert_priv *priv = ctx->chan->priv;
++
++      ic_image->base = *image;
++      ic_image->type = type;
++
++      ic_image->fmt = get_format(image->pix.pixelformat);
++      if (!ic_image->fmt) {
++              dev_err(priv->ipu->dev, "pixelformat not supported for %s\n",
++                      type == IMAGE_CONVERT_OUT ? "Output" : "Input");
++              return -EINVAL;
++      }
++
++      if (ic_image->fmt->planar)
++              ic_image->stride = ic_image->base.pix.width;
++      else
++              ic_image->stride  = ic_image->base.pix.bytesperline;
++
++      return 0;
++}
++
++/* borrowed from drivers/media/v4l2-core/v4l2-common.c */
++static unsigned int clamp_align(unsigned int x, unsigned int min,
++                              unsigned int max, unsigned int align)
++{
++      /* Bits that must be zero to be aligned */
++      unsigned int mask = ~((1 << align) - 1);
++
++      /* Clamp to aligned min and max */
++      x = clamp(x, (min + ~mask) & mask, max & mask);
++
++      /* Round to nearest aligned value */
++      if (align)
++              x = (x + (1 << (align - 1))) & mask;
++
++      return x;
++}
++
++/* Adjusts input/output images to IPU restrictions */
++void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
++                            enum ipu_rotate_mode rot_mode)
++{
++      const struct ipu_image_pixfmt *infmt, *outfmt;
++      u32 w_align_out, h_align_out;
++      u32 w_align_in, h_align_in;
++
++      infmt = get_format(in->pix.pixelformat);
++      outfmt = get_format(out->pix.pixelformat);
++
++      /* set some default pixel formats if needed */
++      if (!infmt) {
++              in->pix.pixelformat = V4L2_PIX_FMT_RGB24;
++              infmt = get_format(V4L2_PIX_FMT_RGB24);
++      }
++      if (!outfmt) {
++              out->pix.pixelformat = V4L2_PIX_FMT_RGB24;
++              outfmt = get_format(V4L2_PIX_FMT_RGB24);
++      }
++
++      /* image converter does not handle fields */
++      in->pix.field = out->pix.field = V4L2_FIELD_NONE;
++
++      /* resizer cannot downsize more than 4:1 */
++      if (ipu_rot_mode_is_irt(rot_mode)) {
++              out->pix.height = max_t(__u32, out->pix.height,
++                                      in->pix.width / 4);
++              out->pix.width = max_t(__u32, out->pix.width,
++                                     in->pix.height / 4);
++      } else {
++              out->pix.width = max_t(__u32, out->pix.width,
++                                     in->pix.width / 4);
++              out->pix.height = max_t(__u32, out->pix.height,
++                                      in->pix.height / 4);
++      }
++
++      /* align input width/height */
++      w_align_in = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt,
++                                          rot_mode));
++      h_align_in = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt,
++                                           rot_mode));
++      in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W,
++                                  w_align_in);
++      in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H,
++                                   h_align_in);
++
++      /* align output width/height */
++      w_align_out = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt,
++                                           rot_mode));
++      h_align_out = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt,
++                                            rot_mode));
++      out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W,
++                                   w_align_out);
++      out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H,
++                                    h_align_out);
++
++      /* set input/output strides and image sizes */
++      in->pix.bytesperline = infmt->planar ?
++              clamp_align(in->pix.width, 2 << w_align_in, MAX_W,
++                          w_align_in) :
++              clamp_align((in->pix.width * infmt->bpp) >> 3,
++                          ((2 << w_align_in) * infmt->bpp) >> 3,
++                          (MAX_W * infmt->bpp) >> 3,
++                          w_align_in);
++      in->pix.sizeimage = infmt->planar ?
++              (in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 :
++              in->pix.height * in->pix.bytesperline;
++      out->pix.bytesperline = outfmt->planar ? out->pix.width :
++              (out->pix.width * outfmt->bpp) >> 3;
++      out->pix.sizeimage = outfmt->planar ?
++              (out->pix.height * out->pix.bytesperline * outfmt->bpp) >> 3 :
++              out->pix.height * out->pix.bytesperline;
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_adjust);
++
++/*
++ * this is used by ipu_image_convert_prepare() to verify set input and
++ * output images are valid before starting the conversion. Clients can
++ * also call it before calling ipu_image_convert_prepare().
++ */
++int ipu_image_convert_verify(struct ipu_image *in, struct ipu_image *out,
++                           enum ipu_rotate_mode rot_mode)
++{
++      struct ipu_image testin, testout;
++
++      testin = *in;
++      testout = *out;
++
++      ipu_image_convert_adjust(&testin, &testout, rot_mode);
++
++      if (testin.pix.width != in->pix.width ||
++          testin.pix.height != in->pix.height ||
++          testout.pix.width != out->pix.width ||
++          testout.pix.height != out->pix.height)
++              return -EINVAL;
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_verify);
++
++/*
++ * Call ipu_image_convert_prepare() to prepare for the conversion of
++ * given images and rotation mode. Returns a new conversion context.
++ */
++struct ipu_image_convert_ctx *
++ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
++                        struct ipu_image *in, struct ipu_image *out,
++                        enum ipu_rotate_mode rot_mode,
++                        ipu_image_convert_cb_t complete,
++                        void *complete_context)
++{
++      struct ipu_image_convert_priv *priv = ipu->image_convert_priv;
++      struct ipu_image_convert_image *s_image, *d_image;
++      struct ipu_image_convert_chan *chan;
++      struct ipu_image_convert_ctx *ctx;
++      unsigned long flags;
++      unsigned int i;
++      bool get_res;
++      int ret;
++
++      if (!in || !out || !complete ||
++          (ic_task != IC_TASK_VIEWFINDER &&
++           ic_task != IC_TASK_POST_PROCESSOR))
++              return ERR_PTR(-EINVAL);
++
++      /* verify the in/out images before continuing */
++      ret = ipu_image_convert_verify(in, out, rot_mode);
++      if (ret) {
++              dev_err(priv->ipu->dev, "%s: in/out formats invalid\n",
++                      __func__);
++              return ERR_PTR(ret);
++      }
++
++      chan = &priv->chan[ic_task];
++
++      ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
++      if (!ctx)
++              return ERR_PTR(-ENOMEM);
++
++      dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p\n", __func__,
++              chan->ic_task, ctx);
++
++      ctx->chan = chan;
++      init_completion(&ctx->aborted);
++
++      ctx->rot_mode = rot_mode;
++
++      /* Sets ctx->in.num_rows/cols as well */
++      ret = calc_image_resize_coefficients(ctx, in, out);
++      if (ret)
++              goto out_free;
++
++      s_image = &ctx->in;
++      d_image = &ctx->out;
++
++      /* set tiling and rotation */
++      if (ipu_rot_mode_is_irt(rot_mode)) {
++              d_image->num_rows = s_image->num_cols;
++              d_image->num_cols = s_image->num_rows;
++      } else {
++              d_image->num_rows = s_image->num_rows;
++              d_image->num_cols = s_image->num_cols;
++      }
++
++      ctx->num_tiles = d_image->num_cols * d_image->num_rows;
++
++      ret = fill_image(ctx, s_image, in, IMAGE_CONVERT_IN);
++      if (ret)
++              goto out_free;
++      ret = fill_image(ctx, d_image, out, IMAGE_CONVERT_OUT);
++      if (ret)
++              goto out_free;
++
++      calc_out_tile_map(ctx);
++
++      find_seams(ctx, s_image, d_image);
++
++      ret = calc_tile_dimensions(ctx, s_image);
++      if (ret)
++              goto out_free;
++
++      ret = calc_tile_offsets(ctx, s_image);
++      if (ret)
++              goto out_free;
++
++      calc_tile_dimensions(ctx, d_image);
++      ret = calc_tile_offsets(ctx, d_image);
++      if (ret)
++              goto out_free;
++
++      calc_tile_resize_coefficients(ctx);
++
++      ret = ipu_ic_calc_csc(&ctx->csc,
++                      s_image->base.pix.ycbcr_enc,
++                      s_image->base.pix.quantization,
++                      ipu_pixelformat_to_colorspace(s_image->fmt->fourcc),
++                      d_image->base.pix.ycbcr_enc,
++                      d_image->base.pix.quantization,
++                      ipu_pixelformat_to_colorspace(d_image->fmt->fourcc));
++      if (ret)
++              goto out_free;
++
++      dump_format(ctx, s_image);
++      dump_format(ctx, d_image);
++
++      ctx->complete = complete;
++      ctx->complete_context = complete_context;
++
++      /*
++       * Can we use double-buffering for this operation? If there is
++       * only one tile (the whole image can be converted in a single
++       * operation) there's no point in using double-buffering. Also,
++       * the IPU's IDMAC channels allow only a single U and V plane
++       * offset shared between both buffers, but these offsets change
++       * for every tile, and therefore would have to be updated for
++       * each buffer which is not possible. So double-buffering is
++       * impossible when either the source or destination images are
++       * a planar format (YUV420, YUV422P, etc.). Further, differently
++       * sized tiles or different resizing coefficients per tile
++       * prevent double-buffering as well.
++       */
++      ctx->double_buffering = (ctx->num_tiles > 1 &&
++                               !s_image->fmt->planar &&
++                               !d_image->fmt->planar);
++      for (i = 1; i < ctx->num_tiles; i++) {
++              if (ctx->in.tile[i].width != ctx->in.tile[0].width ||
++                  ctx->in.tile[i].height != ctx->in.tile[0].height ||
++                  ctx->out.tile[i].width != ctx->out.tile[0].width ||
++                  ctx->out.tile[i].height != ctx->out.tile[0].height) {
++                      ctx->double_buffering = false;
++                      break;
++              }
++      }
++      for (i = 1; i < ctx->in.num_cols; i++) {
++              if (ctx->resize_coeffs_h[i] != ctx->resize_coeffs_h[0]) {
++                      ctx->double_buffering = false;
++                      break;
++              }
++      }
++      for (i = 1; i < ctx->in.num_rows; i++) {
++              if (ctx->resize_coeffs_v[i] != ctx->resize_coeffs_v[0]) {
++                      ctx->double_buffering = false;
++                      break;
++              }
++      }
++
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              unsigned long intermediate_size = d_image->tile[0].size;
++
++              for (i = 1; i < ctx->num_tiles; i++) {
++                      if (d_image->tile[i].size > intermediate_size)
++                              intermediate_size = d_image->tile[i].size;
++              }
++
++              ret = alloc_dma_buf(priv, &ctx->rot_intermediate[0],
++                                  intermediate_size);
++              if (ret)
++                      goto out_free;
++              if (ctx->double_buffering) {
++                      ret = alloc_dma_buf(priv,
++                                          &ctx->rot_intermediate[1],
++                                          intermediate_size);
++                      if (ret)
++                              goto out_free_dmabuf0;
++              }
++      }
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      get_res = list_empty(&chan->ctx_list);
++
++      list_add_tail(&ctx->list, &chan->ctx_list);
++
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++
++      if (get_res) {
++              ret = get_ipu_resources(chan);
++              if (ret)
++                      goto out_free_dmabuf1;
++      }
++
++      return ctx;
++
++out_free_dmabuf1:
++      free_dma_buf(priv, &ctx->rot_intermediate[1]);
++      spin_lock_irqsave(&chan->irqlock, flags);
++      list_del(&ctx->list);
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++out_free_dmabuf0:
++      free_dma_buf(priv, &ctx->rot_intermediate[0]);
++out_free:
++      kfree(ctx);
++      return ERR_PTR(ret);
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_prepare);
++
++/*
++ * Carry out a single image conversion run. Only the physaddr's of the input
++ * and output image buffers are needed. The conversion context must have
++ * been created previously with ipu_image_convert_prepare().
++ */
++int ipu_image_convert_queue(struct ipu_image_convert_run *run)
++{
++      struct ipu_image_convert_chan *chan;
++      struct ipu_image_convert_priv *priv;
++      struct ipu_image_convert_ctx *ctx;
++      unsigned long flags;
++      int ret = 0;
++
++      if (!run || !run->ctx || !run->in_phys || !run->out_phys)
++              return -EINVAL;
++
++      ctx = run->ctx;
++      chan = ctx->chan;
++      priv = chan->priv;
++
++      dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p run %p\n", __func__,
++              chan->ic_task, ctx, run);
++
++      INIT_LIST_HEAD(&run->list);
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      if (ctx->aborting) {
++              ret = -EIO;
++              goto unlock;
++      }
++
++      list_add_tail(&run->list, &chan->pending_q);
++
++      if (!chan->current_run) {
++              ret = do_run(run);
++              if (ret)
++                      chan->current_run = NULL;
++      }
++unlock:
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_queue);
++
++/* Abort any active or pending conversions for this context */
++static void __ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_convert_run *run, *active_run, *tmp;
++      unsigned long flags;
++      int run_count, ret;
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      /* move all remaining pending runs in this context to done_q */
++      list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
++              if (run->ctx != ctx)
++                      continue;
++              run->status = -EIO;
++              list_move_tail(&run->list, &chan->done_q);
++      }
++
++      run_count = get_run_count(ctx, &chan->done_q);
++      active_run = (chan->current_run && chan->current_run->ctx == ctx) ?
++              chan->current_run : NULL;
++
++      if (active_run)
++              reinit_completion(&ctx->aborted);
++
++      ctx->aborting = true;
++
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++
++      if (!run_count && !active_run) {
++              dev_dbg(priv->ipu->dev,
++                      "%s: task %u: no abort needed for ctx %p\n",
++                      __func__, chan->ic_task, ctx);
++              return;
++      }
++
++      if (!active_run) {
++              empty_done_q(chan);
++              return;
++      }
++
++      dev_dbg(priv->ipu->dev,
++              "%s: task %u: wait for completion: %d runs\n",
++              __func__, chan->ic_task, run_count);
++
++      ret = wait_for_completion_timeout(&ctx->aborted,
++                                        msecs_to_jiffies(10000));
++      if (ret == 0) {
++              dev_warn(priv->ipu->dev, "%s: timeout\n", __func__);
++              force_abort(ctx);
++      }
++}
++
++void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
++{
++      __ipu_image_convert_abort(ctx);
++      ctx->aborting = false;
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_abort);
++
++/* Unprepare image conversion context */
++void ipu_image_convert_unprepare(struct ipu_image_convert_ctx *ctx)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      unsigned long flags;
++      bool put_res;
++
++      /* make sure no runs are hanging around */
++      __ipu_image_convert_abort(ctx);
++
++      dev_dbg(priv->ipu->dev, "%s: task %u: removing ctx %p\n", __func__,
++              chan->ic_task, ctx);
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      list_del(&ctx->list);
++
++      put_res = list_empty(&chan->ctx_list);
++
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++
++      if (put_res)
++              release_ipu_resources(chan);
++
++      free_dma_buf(priv, &ctx->rot_intermediate[1]);
++      free_dma_buf(priv, &ctx->rot_intermediate[0]);
++
++      kfree(ctx);
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_unprepare);
++
++/*
++ * "Canned" asynchronous single image conversion. Allocates and returns
++ * a new conversion run.  On successful return the caller must free the
++ * run and call ipu_image_convert_unprepare() after conversion completes.
++ */
++struct ipu_image_convert_run *
++ipu_image_convert(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
++                struct ipu_image *in, struct ipu_image *out,
++                enum ipu_rotate_mode rot_mode,
++                ipu_image_convert_cb_t complete,
++                void *complete_context)
++{
++      struct ipu_image_convert_ctx *ctx;
++      struct ipu_image_convert_run *run;
++      int ret;
++
++      ctx = ipu_image_convert_prepare(ipu, ic_task, in, out, rot_mode,
++                                      complete, complete_context);
++      if (IS_ERR(ctx))
++              return ERR_CAST(ctx);
++
++      run = kzalloc(sizeof(*run), GFP_KERNEL);
++      if (!run) {
++              ipu_image_convert_unprepare(ctx);
++              return ERR_PTR(-ENOMEM);
++      }
++
++      run->ctx = ctx;
++      run->in_phys = in->phys0;
++      run->out_phys = out->phys0;
++
++      ret = ipu_image_convert_queue(run);
++      if (ret) {
++              ipu_image_convert_unprepare(ctx);
++              kfree(run);
++              return ERR_PTR(ret);
++      }
++
++      return run;
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert);
++
++/* "Canned" synchronous single image conversion */
++static void image_convert_sync_complete(struct ipu_image_convert_run *run,
++                                      void *data)
++{
++      struct completion *comp = data;
++
++      complete(comp);
++}
++
++int ipu_image_convert_sync(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
++                         struct ipu_image *in, struct ipu_image *out,
++                         enum ipu_rotate_mode rot_mode)
++{
++      struct ipu_image_convert_run *run;
++      struct completion comp;
++      int ret;
++
++      init_completion(&comp);
++
++      run = ipu_image_convert(ipu, ic_task, in, out, rot_mode,
++                              image_convert_sync_complete, &comp);
++      if (IS_ERR(run))
++              return PTR_ERR(run);
++
++      ret = wait_for_completion_timeout(&comp, msecs_to_jiffies(10000));
++      ret = (ret == 0) ? -ETIMEDOUT : 0;
++
++      ipu_image_convert_unprepare(run->ctx);
++      kfree(run);
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_sync);
++
++int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev)
++{
++      struct ipu_image_convert_priv *priv;
++      int i;
++
++      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++
++      ipu->image_convert_priv = priv;
++      priv->ipu = ipu;
++
++      for (i = 0; i < IC_NUM_TASKS; i++) {
++              struct ipu_image_convert_chan *chan = &priv->chan[i];
++
++              chan->ic_task = i;
++              chan->priv = priv;
++              chan->dma_ch = &image_convert_dma_chan[i];
++              chan->out_eof_irq = -1;
++              chan->rot_out_eof_irq = -1;
++
++              spin_lock_init(&chan->irqlock);
++              INIT_LIST_HEAD(&chan->ctx_list);
++              INIT_LIST_HEAD(&chan->pending_q);
++              INIT_LIST_HEAD(&chan->done_q);
++      }
++
++      return 0;
++}
++
++void ipu_image_convert_exit(struct ipu_soc *ipu)
++{
++}
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/ipu-pre.c
+@@ -0,0 +1,346 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2017 Lucas Stach, Pengutronix
++ */
++
++#include <drm/drm_fourcc.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/genalloc.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <video/imx-ipu-v3.h>
++
++#include "ipu-prv.h"
++
++#define IPU_PRE_MAX_WIDTH     2048
++#define IPU_PRE_NUM_SCANLINES 8
++
++#define IPU_PRE_CTRL                                  0x000
++#define IPU_PRE_CTRL_SET                              0x004
++#define  IPU_PRE_CTRL_ENABLE                          (1 << 0)
++#define  IPU_PRE_CTRL_BLOCK_EN                                (1 << 1)
++#define  IPU_PRE_CTRL_BLOCK_16                                (1 << 2)
++#define  IPU_PRE_CTRL_SDW_UPDATE                      (1 << 4)
++#define  IPU_PRE_CTRL_VFLIP                           (1 << 5)
++#define  IPU_PRE_CTRL_SO                              (1 << 6)
++#define  IPU_PRE_CTRL_INTERLACED_FIELD                        (1 << 7)
++#define  IPU_PRE_CTRL_HANDSHAKE_EN                    (1 << 8)
++#define  IPU_PRE_CTRL_HANDSHAKE_LINE_NUM(v)           ((v & 0x3) << 9)
++#define  IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN         (1 << 11)
++#define  IPU_PRE_CTRL_EN_REPEAT                               (1 << 28)
++#define  IPU_PRE_CTRL_TPR_REST_SEL                    (1 << 29)
++#define  IPU_PRE_CTRL_CLKGATE                         (1 << 30)
++#define  IPU_PRE_CTRL_SFTRST                          (1 << 31)
++
++#define IPU_PRE_CUR_BUF                                       0x030
++
++#define IPU_PRE_NEXT_BUF                              0x040
++
++#define IPU_PRE_TPR_CTRL                              0x070
++#define  IPU_PRE_TPR_CTRL_TILE_FORMAT(v)              ((v & 0xff) << 0)
++#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK            0xff
++#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT          (1 << 0)
++#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_SPLIT_BUF               (1 << 4)
++#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF      (1 << 5)
++#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED     (1 << 6)
++
++#define IPU_PRE_PREFETCH_ENG_CTRL                     0x080
++#define  IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN            (1 << 0)
++#define  IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(v)                ((v & 0x7) << 1)
++#define  IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(v)    ((v & 0x3) << 4)
++#define  IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(v)  ((v & 0x7) << 8)
++#define  IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS           (1 << 11)
++#define  IPU_PRE_PREF_ENG_CTRL_FIELD_INVERSE          (1 << 12)
++#define  IPU_PRE_PREF_ENG_CTRL_PARTIAL_UV_SWAP                (1 << 14)
++#define  IPU_PRE_PREF_ENG_CTRL_TPR_COOR_OFFSET_EN     (1 << 15)
++
++#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE                       0x0a0
++#define  IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(v)     ((v & 0xffff) << 0)
++#define  IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(v)    ((v & 0xffff) << 16)
++
++#define IPU_PRE_PREFETCH_ENG_PITCH                    0x0d0
++#define  IPU_PRE_PREFETCH_ENG_PITCH_Y(v)              ((v & 0xffff) << 0)
++#define  IPU_PRE_PREFETCH_ENG_PITCH_UV(v)             ((v & 0xffff) << 16)
++
++#define IPU_PRE_STORE_ENG_CTRL                                0x110
++#define  IPU_PRE_STORE_ENG_CTRL_STORE_EN              (1 << 0)
++#define  IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(v)               ((v & 0x7) << 1)
++#define  IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(v)  ((v & 0x3) << 4)
++
++#define IPU_PRE_STORE_ENG_STATUS                      0x120
++#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_MASK  0xffff
++#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_SHIFT 0
++#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK  0x3fff
++#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT 16
++#define  IPU_PRE_STORE_ENG_STATUS_STORE_FIFO_FULL     (1 << 30)
++#define  IPU_PRE_STORE_ENG_STATUS_STORE_FIELD         (1 << 31)
++
++#define IPU_PRE_STORE_ENG_SIZE                                0x130
++#define  IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(v)                ((v & 0xffff) << 0)
++#define  IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(v)               ((v & 0xffff) << 16)
++
++#define IPU_PRE_STORE_ENG_PITCH                               0x140
++#define  IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(v)         ((v & 0xffff) << 0)
++
++#define IPU_PRE_STORE_ENG_ADDR                                0x150
++
++struct ipu_pre {
++      struct list_head        list;
++      struct device           *dev;
++
++      void __iomem            *regs;
++      struct clk              *clk_axi;
++      struct gen_pool         *iram;
++
++      dma_addr_t              buffer_paddr;
++      void                    *buffer_virt;
++      bool                    in_use;
++      unsigned int            safe_window_end;
++      unsigned int            last_bufaddr;
++};
++
++static DEFINE_MUTEX(ipu_pre_list_mutex);
++static LIST_HEAD(ipu_pre_list);
++static int available_pres;
++
++int ipu_pre_get_available_count(void)
++{
++      return available_pres;
++}
++
++struct ipu_pre *
++ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
++{
++      struct device_node *pre_node = of_parse_phandle(dev->of_node,
++                                                      name, index);
++      struct ipu_pre *pre;
++
++      mutex_lock(&ipu_pre_list_mutex);
++      list_for_each_entry(pre, &ipu_pre_list, list) {
++              if (pre_node == pre->dev->of_node) {
++                      mutex_unlock(&ipu_pre_list_mutex);
++                      device_link_add(dev, pre->dev,
++                                      DL_FLAG_AUTOREMOVE_CONSUMER);
++                      of_node_put(pre_node);
++                      return pre;
++              }
++      }
++      mutex_unlock(&ipu_pre_list_mutex);
++
++      of_node_put(pre_node);
++
++      return NULL;
++}
++
++int ipu_pre_get(struct ipu_pre *pre)
++{
++      u32 val;
++
++      if (pre->in_use)
++              return -EBUSY;
++
++      /* first get the engine out of reset and remove clock gating */
++      writel(0, pre->regs + IPU_PRE_CTRL);
++
++      /* init defaults that should be applied to all streams */
++      val = IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN |
++            IPU_PRE_CTRL_HANDSHAKE_EN |
++            IPU_PRE_CTRL_TPR_REST_SEL |
++            IPU_PRE_CTRL_SDW_UPDATE;
++      writel(val, pre->regs + IPU_PRE_CTRL);
++
++      pre->in_use = true;
++      return 0;
++}
++
++void ipu_pre_put(struct ipu_pre *pre)
++{
++      writel(IPU_PRE_CTRL_SFTRST, pre->regs + IPU_PRE_CTRL);
++
++      pre->in_use = false;
++}
++
++void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
++                     unsigned int height, unsigned int stride, u32 format,
++                     uint64_t modifier, unsigned int bufaddr)
++{
++      const struct drm_format_info *info = drm_format_info(format);
++      u32 active_bpp = info->cpp[0] >> 1;
++      u32 val;
++
++      /* calculate safe window for ctrl register updates */
++      if (modifier == DRM_FORMAT_MOD_LINEAR)
++              pre->safe_window_end = height - 2;
++      else
++              pre->safe_window_end = DIV_ROUND_UP(height, 4) - 1;
++
++      writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF);
++      writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
++      pre->last_bufaddr = bufaddr;
++
++      val = IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(0) |
++            IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(active_bpp) |
++            IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(4) |
++            IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS |
++            IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN;
++      writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_CTRL);
++
++      val = IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(width) |
++            IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(height);
++      writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_INPUT_SIZE);
++
++      val = IPU_PRE_PREFETCH_ENG_PITCH_Y(stride);
++      writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_PITCH);
++
++      val = IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(active_bpp) |
++            IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(4) |
++            IPU_PRE_STORE_ENG_CTRL_STORE_EN;
++      writel(val, pre->regs + IPU_PRE_STORE_ENG_CTRL);
++
++      val = IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(width) |
++            IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(height);
++      writel(val, pre->regs + IPU_PRE_STORE_ENG_SIZE);
++
++      val = IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(stride);
++      writel(val, pre->regs + IPU_PRE_STORE_ENG_PITCH);
++
++      writel(pre->buffer_paddr, pre->regs + IPU_PRE_STORE_ENG_ADDR);
++
++      val = readl(pre->regs + IPU_PRE_TPR_CTRL);
++      val &= ~IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK;
++      if (modifier != DRM_FORMAT_MOD_LINEAR) {
++              /* only support single buffer formats for now */
++              val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF;
++              if (modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED)
++                      val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED;
++              if (info->cpp[0] == 2)
++                      val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT;
++      }
++      writel(val, pre->regs + IPU_PRE_TPR_CTRL);
++
++      val = readl(pre->regs + IPU_PRE_CTRL);
++      val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE |
++             IPU_PRE_CTRL_SDW_UPDATE;
++      if (modifier == DRM_FORMAT_MOD_LINEAR)
++              val &= ~IPU_PRE_CTRL_BLOCK_EN;
++      else
++              val |= IPU_PRE_CTRL_BLOCK_EN;
++      writel(val, pre->regs + IPU_PRE_CTRL);
++}
++
++void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
++{
++      unsigned long timeout = jiffies + msecs_to_jiffies(5);
++      unsigned short current_yblock;
++      u32 val;
++
++      if (bufaddr == pre->last_bufaddr)
++              return;
++
++      writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
++      pre->last_bufaddr = bufaddr;
++
++      do {
++              if (time_after(jiffies, timeout)) {
++                      dev_warn(pre->dev, "timeout waiting for PRE safe window\n");
++                      return;
++              }
++
++              val = readl(pre->regs + IPU_PRE_STORE_ENG_STATUS);
++              current_yblock =
++                      (val >> IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT) &
++                      IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK;
++      } while (current_yblock == 0 || current_yblock >= pre->safe_window_end);
++
++      writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
++}
++
++bool ipu_pre_update_pending(struct ipu_pre *pre)
++{
++      return !!(readl_relaxed(pre->regs + IPU_PRE_CTRL) &
++                IPU_PRE_CTRL_SDW_UPDATE);
++}
++
++u32 ipu_pre_get_baddr(struct ipu_pre *pre)
++{
++      return (u32)pre->buffer_paddr;
++}
++
++static int ipu_pre_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct resource *res;
++      struct ipu_pre *pre;
++
++      pre = devm_kzalloc(dev, sizeof(*pre), GFP_KERNEL);
++      if (!pre)
++              return -ENOMEM;
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      pre->regs = devm_ioremap_resource(&pdev->dev, res);
++      if (IS_ERR(pre->regs))
++              return PTR_ERR(pre->regs);
++
++      pre->clk_axi = devm_clk_get(dev, "axi");
++      if (IS_ERR(pre->clk_axi))
++              return PTR_ERR(pre->clk_axi);
++
++      pre->iram = of_gen_pool_get(dev->of_node, "fsl,iram", 0);
++      if (!pre->iram)
++              return -EPROBE_DEFER;
++
++      /*
++       * Allocate IRAM buffer with maximum size. This could be made dynamic,
++       * but as there is no other user of this IRAM region and we can fit all
++       * max sized buffers into it, there is no need yet.
++       */
++      pre->buffer_virt = gen_pool_dma_alloc(pre->iram, IPU_PRE_MAX_WIDTH *
++                                            IPU_PRE_NUM_SCANLINES * 4,
++                                            &pre->buffer_paddr);
++      if (!pre->buffer_virt)
++              return -ENOMEM;
++
++      clk_prepare_enable(pre->clk_axi);
++
++      pre->dev = dev;
++      platform_set_drvdata(pdev, pre);
++      mutex_lock(&ipu_pre_list_mutex);
++      list_add(&pre->list, &ipu_pre_list);
++      available_pres++;
++      mutex_unlock(&ipu_pre_list_mutex);
++
++      return 0;
++}
++
++static int ipu_pre_remove(struct platform_device *pdev)
++{
++      struct ipu_pre *pre = platform_get_drvdata(pdev);
++
++      mutex_lock(&ipu_pre_list_mutex);
++      list_del(&pre->list);
++      available_pres--;
++      mutex_unlock(&ipu_pre_list_mutex);
++
++      clk_disable_unprepare(pre->clk_axi);
++
++      if (pre->buffer_virt)
++              gen_pool_free(pre->iram, (unsigned long)pre->buffer_virt,
++                            IPU_PRE_MAX_WIDTH * IPU_PRE_NUM_SCANLINES * 4);
++      return 0;
++}
++
++static const struct of_device_id ipu_pre_dt_ids[] = {
++      { .compatible = "fsl,imx6qp-pre", },
++      { /* sentinel */ },
++};
++
++struct platform_driver ipu_pre_drv = {
++      .probe          = ipu_pre_probe,
++      .remove         = ipu_pre_remove,
++      .driver         = {
++              .name   = "imx-ipu-pre",
++              .of_match_table = ipu_pre_dt_ids,
++      },
++};
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/ipu-prg.c
+@@ -0,0 +1,483 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2016-2017 Lucas Stach, Pengutronix
++ */
++
++#include <drm/drm_fourcc.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/iopoll.h>
++#include <linux/mfd/syscon.h>
++#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/regmap.h>
++#include <video/imx-ipu-v3.h>
++
++#include "ipu-prv.h"
++
++#define IPU_PRG_CTL                           0x00
++#define  IPU_PRG_CTL_BYPASS(i)                        (1 << (0 + i))
++#define  IPU_PRG_CTL_SOFT_ARID_MASK           0x3
++#define  IPU_PRG_CTL_SOFT_ARID_SHIFT(i)               (8 + i * 2)
++#define  IPU_PRG_CTL_SOFT_ARID(i, v)          ((v & 0x3) << (8 + 2 * i))
++#define  IPU_PRG_CTL_SO(i)                    (1 << (16 + i))
++#define  IPU_PRG_CTL_VFLIP(i)                 (1 << (19 + i))
++#define  IPU_PRG_CTL_BLOCK_MODE(i)            (1 << (22 + i))
++#define  IPU_PRG_CTL_CNT_LOAD_EN(i)           (1 << (25 + i))
++#define  IPU_PRG_CTL_SOFTRST                  (1 << 30)
++#define  IPU_PRG_CTL_SHADOW_EN                        (1 << 31)
++
++#define IPU_PRG_STATUS                                0x04
++#define  IPU_PRG_STATUS_BUFFER0_READY(i)      (1 << (0 + i * 2))
++#define  IPU_PRG_STATUS_BUFFER1_READY(i)      (1 << (1 + i * 2))
++
++#define IPU_PRG_QOS                           0x08
++#define  IPU_PRG_QOS_ARID_MASK                        0xf
++#define  IPU_PRG_QOS_ARID_SHIFT(i)            (0 + i * 4)
++
++#define IPU_PRG_REG_UPDATE                    0x0c
++#define  IPU_PRG_REG_UPDATE_REG_UPDATE                (1 << 0)
++
++#define IPU_PRG_STRIDE(i)                     (0x10 + i * 0x4)
++#define  IPU_PRG_STRIDE_STRIDE_MASK           0x3fff
++
++#define IPU_PRG_CROP_LINE                     0x1c
++
++#define IPU_PRG_THD                           0x20
++
++#define IPU_PRG_BADDR(i)                      (0x24 + i * 0x4)
++
++#define IPU_PRG_OFFSET(i)                     (0x30 + i * 0x4)
++
++#define IPU_PRG_ILO(i)                                (0x3c + i * 0x4)
++
++#define IPU_PRG_HEIGHT(i)                     (0x48 + i * 0x4)
++#define  IPU_PRG_HEIGHT_PRE_HEIGHT_MASK               0xfff
++#define  IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT      0
++#define  IPU_PRG_HEIGHT_IPU_HEIGHT_MASK               0xfff
++#define  IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT      16
++
++struct ipu_prg_channel {
++      bool                    enabled;
++      int                     used_pre;
++};
++
++struct ipu_prg {
++      struct list_head        list;
++      struct device           *dev;
++      int                     id;
++
++      void __iomem            *regs;
++      struct clk              *clk_ipg, *clk_axi;
++      struct regmap           *iomuxc_gpr;
++      struct ipu_pre          *pres[3];
++
++      struct ipu_prg_channel  chan[3];
++};
++
++static DEFINE_MUTEX(ipu_prg_list_mutex);
++static LIST_HEAD(ipu_prg_list);
++
++struct ipu_prg *
++ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id)
++{
++      struct device_node *prg_node = of_parse_phandle(dev->of_node,
++                                                      name, 0);
++      struct ipu_prg *prg;
++
++      mutex_lock(&ipu_prg_list_mutex);
++      list_for_each_entry(prg, &ipu_prg_list, list) {
++              if (prg_node == prg->dev->of_node) {
++                      mutex_unlock(&ipu_prg_list_mutex);
++                      device_link_add(dev, prg->dev,
++                                      DL_FLAG_AUTOREMOVE_CONSUMER);
++                      prg->id = ipu_id;
++                      of_node_put(prg_node);
++                      return prg;
++              }
++      }
++      mutex_unlock(&ipu_prg_list_mutex);
++
++      of_node_put(prg_node);
++
++      return NULL;
++}
++
++int ipu_prg_max_active_channels(void)
++{
++      return ipu_pre_get_available_count();
++}
++EXPORT_SYMBOL_GPL(ipu_prg_max_active_channels);
++
++bool ipu_prg_present(struct ipu_soc *ipu)
++{
++      if (ipu->prg_priv)
++              return true;
++
++      return false;
++}
++EXPORT_SYMBOL_GPL(ipu_prg_present);
++
++bool ipu_prg_format_supported(struct ipu_soc *ipu, uint32_t format,
++                            uint64_t modifier)
++{
++      const struct drm_format_info *info = drm_format_info(format);
++
++      if (info->num_planes != 1)
++              return false;
++
++      switch (modifier) {
++      case DRM_FORMAT_MOD_LINEAR:
++      case DRM_FORMAT_MOD_VIVANTE_TILED:
++      case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
++              return true;
++      default:
++              return false;
++      }
++}
++EXPORT_SYMBOL_GPL(ipu_prg_format_supported);
++
++int ipu_prg_enable(struct ipu_soc *ipu)
++{
++      struct ipu_prg *prg = ipu->prg_priv;
++
++      if (!prg)
++              return 0;
++
++      return pm_runtime_get_sync(prg->dev);
++}
++EXPORT_SYMBOL_GPL(ipu_prg_enable);
++
++void ipu_prg_disable(struct ipu_soc *ipu)
++{
++      struct ipu_prg *prg = ipu->prg_priv;
++
++      if (!prg)
++              return;
++
++      pm_runtime_put(prg->dev);
++}
++EXPORT_SYMBOL_GPL(ipu_prg_disable);
++
++/*
++ * The channel configuartion functions below are not thread safe, as they
++ * must be only called from the atomic commit path in the DRM driver, which
++ * is properly serialized.
++ */
++static int ipu_prg_ipu_to_prg_chan(int ipu_chan)
++{
++      /*
++       * This isn't clearly documented in the RM, but IPU to PRG channel
++       * assignment is fixed, as only with this mapping the control signals
++       * match up.
++       */
++      switch (ipu_chan) {
++      case IPUV3_CHANNEL_MEM_BG_SYNC:
++              return 0;
++      case IPUV3_CHANNEL_MEM_FG_SYNC:
++              return 1;
++      case IPUV3_CHANNEL_MEM_DC_SYNC:
++              return 2;
++      default:
++              return -EINVAL;
++      }
++}
++
++static int ipu_prg_get_pre(struct ipu_prg *prg, int prg_chan)
++{
++      int i, ret;
++
++      /* channel 0 is special as it is hardwired to one of the PREs */
++      if (prg_chan == 0) {
++              ret = ipu_pre_get(prg->pres[0]);
++              if (ret)
++                      goto fail;
++              prg->chan[prg_chan].used_pre = 0;
++              return 0;
++      }
++
++      for (i = 1; i < 3; i++) {
++              ret = ipu_pre_get(prg->pres[i]);
++              if (!ret) {
++                      u32 val, mux;
++                      int shift;
++
++                      prg->chan[prg_chan].used_pre = i;
++
++                      /* configure the PRE to PRG channel mux */
++                      shift = (i == 1) ? 12 : 14;
++                      mux = (prg->id << 1) | (prg_chan - 1);
++                      regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
++                                         0x3 << shift, mux << shift);
++
++                      /* check other mux, must not point to same channel */
++                      shift = (i == 1) ? 14 : 12;
++                      regmap_read(prg->iomuxc_gpr, IOMUXC_GPR5, &val);
++                      if (((val >> shift) & 0x3) == mux) {
++                              regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
++                                                 0x3 << shift,
++                                                 (mux ^ 0x1) << shift);
++                      }
++
++                      return 0;
++              }
++      }
++
++fail:
++      dev_err(prg->dev, "could not get PRE for PRG chan %d", prg_chan);
++      return ret;
++}
++
++static void ipu_prg_put_pre(struct ipu_prg *prg, int prg_chan)
++{
++      struct ipu_prg_channel *chan = &prg->chan[prg_chan];
++
++      ipu_pre_put(prg->pres[chan->used_pre]);
++      chan->used_pre = -1;
++}
++
++void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan)
++{
++      int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
++      struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
++      struct ipu_prg_channel *chan;
++      u32 val;
++
++      if (prg_chan < 0)
++              return;
++
++      chan = &prg->chan[prg_chan];
++      if (!chan->enabled)
++              return;
++
++      pm_runtime_get_sync(prg->dev);
++
++      val = readl(prg->regs + IPU_PRG_CTL);
++      val |= IPU_PRG_CTL_BYPASS(prg_chan);
++      writel(val, prg->regs + IPU_PRG_CTL);
++
++      val = IPU_PRG_REG_UPDATE_REG_UPDATE;
++      writel(val, prg->regs + IPU_PRG_REG_UPDATE);
++
++      pm_runtime_put(prg->dev);
++
++      ipu_prg_put_pre(prg, prg_chan);
++
++      chan->enabled = false;
++}
++EXPORT_SYMBOL_GPL(ipu_prg_channel_disable);
++
++int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
++                            unsigned int axi_id, unsigned int width,
++                            unsigned int height, unsigned int stride,
++                            u32 format, uint64_t modifier, unsigned long *eba)
++{
++      int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
++      struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
++      struct ipu_prg_channel *chan;
++      u32 val;
++      int ret;
++
++      if (prg_chan < 0)
++              return prg_chan;
++
++      chan = &prg->chan[prg_chan];
++
++      if (chan->enabled) {
++              ipu_pre_update(prg->pres[chan->used_pre], *eba);
++              return 0;
++      }
++
++      ret = ipu_prg_get_pre(prg, prg_chan);
++      if (ret)
++              return ret;
++
++      ipu_pre_configure(prg->pres[chan->used_pre],
++                        width, height, stride, format, modifier, *eba);
++
++
++      pm_runtime_get_sync(prg->dev);
++
++      val = (stride - 1) & IPU_PRG_STRIDE_STRIDE_MASK;
++      writel(val, prg->regs + IPU_PRG_STRIDE(prg_chan));
++
++      val = ((height & IPU_PRG_HEIGHT_PRE_HEIGHT_MASK) <<
++             IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT) |
++            ((height & IPU_PRG_HEIGHT_IPU_HEIGHT_MASK) <<
++             IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT);
++      writel(val, prg->regs + IPU_PRG_HEIGHT(prg_chan));
++
++      val = ipu_pre_get_baddr(prg->pres[chan->used_pre]);
++      *eba = val;
++      writel(val, prg->regs + IPU_PRG_BADDR(prg_chan));
++
++      val = readl(prg->regs + IPU_PRG_CTL);
++      /* config AXI ID */
++      val &= ~(IPU_PRG_CTL_SOFT_ARID_MASK <<
++               IPU_PRG_CTL_SOFT_ARID_SHIFT(prg_chan));
++      val |= IPU_PRG_CTL_SOFT_ARID(prg_chan, axi_id);
++      /* enable channel */
++      val &= ~IPU_PRG_CTL_BYPASS(prg_chan);
++      writel(val, prg->regs + IPU_PRG_CTL);
++
++      val = IPU_PRG_REG_UPDATE_REG_UPDATE;
++      writel(val, prg->regs + IPU_PRG_REG_UPDATE);
++
++      /* wait for both double buffers to be filled */
++      readl_poll_timeout(prg->regs + IPU_PRG_STATUS, val,
++                         (val & IPU_PRG_STATUS_BUFFER0_READY(prg_chan)) &&
++                         (val & IPU_PRG_STATUS_BUFFER1_READY(prg_chan)),
++                         5, 1000);
++
++      pm_runtime_put(prg->dev);
++
++      chan->enabled = true;
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_prg_channel_configure);
++
++bool ipu_prg_channel_configure_pending(struct ipuv3_channel *ipu_chan)
++{
++      int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
++      struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
++      struct ipu_prg_channel *chan;
++
++      if (prg_chan < 0)
++              return false;
++
++      chan = &prg->chan[prg_chan];
++      WARN_ON(!chan->enabled);
++
++      return ipu_pre_update_pending(prg->pres[chan->used_pre]);
++}
++EXPORT_SYMBOL_GPL(ipu_prg_channel_configure_pending);
++
++static int ipu_prg_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct resource *res;
++      struct ipu_prg *prg;
++      u32 val;
++      int i, ret;
++
++      prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
++      if (!prg)
++              return -ENOMEM;
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      prg->regs = devm_ioremap_resource(&pdev->dev, res);
++      if (IS_ERR(prg->regs))
++              return PTR_ERR(prg->regs);
++
++
++      prg->clk_ipg = devm_clk_get(dev, "ipg");
++      if (IS_ERR(prg->clk_ipg))
++              return PTR_ERR(prg->clk_ipg);
++
++      prg->clk_axi = devm_clk_get(dev, "axi");
++      if (IS_ERR(prg->clk_axi))
++              return PTR_ERR(prg->clk_axi);
++
++      prg->iomuxc_gpr =
++              syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
++      if (IS_ERR(prg->iomuxc_gpr))
++              return PTR_ERR(prg->iomuxc_gpr);
++
++      for (i = 0; i < 3; i++) {
++              prg->pres[i] = ipu_pre_lookup_by_phandle(dev, "fsl,pres", i);
++              if (!prg->pres[i])
++                      return -EPROBE_DEFER;
++      }
++
++      ret = clk_prepare_enable(prg->clk_ipg);
++      if (ret)
++              return ret;
++
++      ret = clk_prepare_enable(prg->clk_axi);
++      if (ret) {
++              clk_disable_unprepare(prg->clk_ipg);
++              return ret;
++      }
++
++      /* init to free running mode */
++      val = readl(prg->regs + IPU_PRG_CTL);
++      val |= IPU_PRG_CTL_SHADOW_EN;
++      writel(val, prg->regs + IPU_PRG_CTL);
++
++      /* disable address threshold */
++      writel(0xffffffff, prg->regs + IPU_PRG_THD);
++
++      pm_runtime_set_active(dev);
++      pm_runtime_enable(dev);
++
++      prg->dev = dev;
++      platform_set_drvdata(pdev, prg);
++      mutex_lock(&ipu_prg_list_mutex);
++      list_add(&prg->list, &ipu_prg_list);
++      mutex_unlock(&ipu_prg_list_mutex);
++
++      return 0;
++}
++
++static int ipu_prg_remove(struct platform_device *pdev)
++{
++      struct ipu_prg *prg = platform_get_drvdata(pdev);
++
++      mutex_lock(&ipu_prg_list_mutex);
++      list_del(&prg->list);
++      mutex_unlock(&ipu_prg_list_mutex);
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++static int prg_suspend(struct device *dev)
++{
++      struct ipu_prg *prg = dev_get_drvdata(dev);
++
++      clk_disable_unprepare(prg->clk_axi);
++      clk_disable_unprepare(prg->clk_ipg);
++
++      return 0;
++}
++
++static int prg_resume(struct device *dev)
++{
++      struct ipu_prg *prg = dev_get_drvdata(dev);
++      int ret;
++
++      ret = clk_prepare_enable(prg->clk_ipg);
++      if (ret)
++              return ret;
++
++      ret = clk_prepare_enable(prg->clk_axi);
++      if (ret) {
++              clk_disable_unprepare(prg->clk_ipg);
++              return ret;
++      }
++
++      return 0;
++}
++#endif
++
++static const struct dev_pm_ops prg_pm_ops = {
++      SET_RUNTIME_PM_OPS(prg_suspend, prg_resume, NULL)
++};
++
++static const struct of_device_id ipu_prg_dt_ids[] = {
++      { .compatible = "fsl,imx6qp-prg", },
++      { /* sentinel */ },
++};
++
++struct platform_driver ipu_prg_drv = {
++      .probe          = ipu_prg_probe,
++      .remove         = ipu_prg_remove,
++      .driver         = {
++              .name   = "imx-ipu-prg",
++              .pm     = &prg_pm_ops,
++              .of_match_table = ipu_prg_dt_ids,
++      },
++};
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/ipu-prv.h
+@@ -0,0 +1,274 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++#ifndef __IPU_PRV_H__
++#define __IPU_PRV_H__
++
++struct ipu_soc;
++
++#include <linux/types.h>
++#include <linux/device.h>
++#include <linux/clk.h>
++#include <linux/platform_device.h>
++
++#include <video/imx-ipu-v3.h>
++
++#define IPU_MCU_T_DEFAULT     8
++#define IPU_CM_IDMAC_REG_OFS  0x00008000
++#define IPU_CM_IC_REG_OFS     0x00020000
++#define IPU_CM_IRT_REG_OFS    0x00028000
++#define IPU_CM_CSI0_REG_OFS   0x00030000
++#define IPU_CM_CSI1_REG_OFS   0x00038000
++#define IPU_CM_SMFC_REG_OFS   0x00050000
++#define IPU_CM_DC_REG_OFS     0x00058000
++#define IPU_CM_DMFC_REG_OFS   0x00060000
++
++/* Register addresses */
++/* IPU Common registers */
++#define IPU_CM_REG(offset)    (offset)
++
++#define IPU_CONF                      IPU_CM_REG(0)
++
++#define IPU_SRM_PRI1                  IPU_CM_REG(0x00a0)
++#define IPU_SRM_PRI2                  IPU_CM_REG(0x00a4)
++#define IPU_FS_PROC_FLOW1             IPU_CM_REG(0x00a8)
++#define IPU_FS_PROC_FLOW2             IPU_CM_REG(0x00ac)
++#define IPU_FS_PROC_FLOW3             IPU_CM_REG(0x00b0)
++#define IPU_FS_DISP_FLOW1             IPU_CM_REG(0x00b4)
++#define IPU_FS_DISP_FLOW2             IPU_CM_REG(0x00b8)
++#define IPU_SKIP                      IPU_CM_REG(0x00bc)
++#define IPU_DISP_ALT_CONF             IPU_CM_REG(0x00c0)
++#define IPU_DISP_GEN                  IPU_CM_REG(0x00c4)
++#define IPU_DISP_ALT1                 IPU_CM_REG(0x00c8)
++#define IPU_DISP_ALT2                 IPU_CM_REG(0x00cc)
++#define IPU_DISP_ALT3                 IPU_CM_REG(0x00d0)
++#define IPU_DISP_ALT4                 IPU_CM_REG(0x00d4)
++#define IPU_SNOOP                     IPU_CM_REG(0x00d8)
++#define IPU_MEM_RST                   IPU_CM_REG(0x00dc)
++#define IPU_PM                                IPU_CM_REG(0x00e0)
++#define IPU_GPR                               IPU_CM_REG(0x00e4)
++#define IPU_CHA_DB_MODE_SEL(ch)               IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
++#define IPU_ALT_CHA_DB_MODE_SEL(ch)   IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
++#define IPU_CHA_CUR_BUF(ch)           IPU_CM_REG(0x023C + 4 * ((ch) / 32))
++#define IPU_ALT_CUR_BUF0              IPU_CM_REG(0x0244)
++#define IPU_ALT_CUR_BUF1              IPU_CM_REG(0x0248)
++#define IPU_SRM_STAT                  IPU_CM_REG(0x024C)
++#define IPU_PROC_TASK_STAT            IPU_CM_REG(0x0250)
++#define IPU_DISP_TASK_STAT            IPU_CM_REG(0x0254)
++#define IPU_CHA_BUF0_RDY(ch)          IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
++#define IPU_CHA_BUF1_RDY(ch)          IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
++#define IPU_CHA_BUF2_RDY(ch)          IPU_CM_REG(0x0288 + 4 * ((ch) / 32))
++#define IPU_ALT_CHA_BUF0_RDY(ch)      IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
++#define IPU_ALT_CHA_BUF1_RDY(ch)      IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
++
++#define IPU_INT_CTRL(n)               IPU_CM_REG(0x003C + 4 * (n))
++#define IPU_INT_STAT(n)               IPU_CM_REG(0x0200 + 4 * (n))
++
++/* SRM_PRI2 */
++#define DP_S_SRM_MODE_MASK            (0x3 << 3)
++#define DP_S_SRM_MODE_NOW             (0x3 << 3)
++#define DP_S_SRM_MODE_NEXT_FRAME      (0x1 << 3)
++
++/* FS_PROC_FLOW1 */
++#define FS_PRPENC_ROT_SRC_SEL_MASK    (0xf << 0)
++#define FS_PRPENC_ROT_SRC_SEL_ENC             (0x7 << 0)
++#define FS_PRPVF_ROT_SRC_SEL_MASK     (0xf << 8)
++#define FS_PRPVF_ROT_SRC_SEL_VF                       (0x8 << 8)
++#define FS_PP_SRC_SEL_MASK            (0xf << 12)
++#define FS_PP_ROT_SRC_SEL_MASK                (0xf << 16)
++#define FS_PP_ROT_SRC_SEL_PP                  (0x5 << 16)
++#define FS_VDI1_SRC_SEL_MASK          (0x3 << 20)
++#define FS_VDI3_SRC_SEL_MASK          (0x3 << 20)
++#define FS_PRP_SRC_SEL_MASK           (0xf << 24)
++#define FS_VDI_SRC_SEL_MASK           (0x3 << 28)
++#define FS_VDI_SRC_SEL_CSI_DIRECT             (0x1 << 28)
++#define FS_VDI_SRC_SEL_VDOA                   (0x2 << 28)
++
++/* FS_PROC_FLOW2 */
++#define FS_PRP_ENC_DEST_SEL_MASK      (0xf << 0)
++#define FS_PRP_ENC_DEST_SEL_IRT_ENC           (0x1 << 0)
++#define FS_PRPVF_DEST_SEL_MASK                (0xf << 4)
++#define FS_PRPVF_DEST_SEL_IRT_VF              (0x1 << 4)
++#define FS_PRPVF_ROT_DEST_SEL_MASK    (0xf << 8)
++#define FS_PP_DEST_SEL_MASK           (0xf << 12)
++#define FS_PP_DEST_SEL_IRT_PP                 (0x3 << 12)
++#define FS_PP_ROT_DEST_SEL_MASK               (0xf << 16)
++#define FS_PRPENC_ROT_DEST_SEL_MASK   (0xf << 20)
++#define FS_PRP_DEST_SEL_MASK          (0xf << 24)
++
++#define IPU_DI0_COUNTER_RELEASE                       (1 << 24)
++#define IPU_DI1_COUNTER_RELEASE                       (1 << 25)
++
++#define IPU_IDMAC_REG(offset) (offset)
++
++#define IDMAC_CONF                    IPU_IDMAC_REG(0x0000)
++#define IDMAC_CHA_EN(ch)              IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
++#define IDMAC_SEP_ALPHA                       IPU_IDMAC_REG(0x000c)
++#define IDMAC_ALT_SEP_ALPHA           IPU_IDMAC_REG(0x0010)
++#define IDMAC_CHA_PRI(ch)             IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
++#define IDMAC_WM_EN(ch)                       IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32))
++#define IDMAC_CH_LOCK_EN_1            IPU_IDMAC_REG(0x0024)
++#define IDMAC_CH_LOCK_EN_2            IPU_IDMAC_REG(0x0028)
++#define IDMAC_SUB_ADDR_0              IPU_IDMAC_REG(0x002c)
++#define IDMAC_SUB_ADDR_1              IPU_IDMAC_REG(0x0030)
++#define IDMAC_SUB_ADDR_2              IPU_IDMAC_REG(0x0034)
++#define IDMAC_BAND_EN(ch)             IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32))
++#define IDMAC_CHA_BUSY(ch)            IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32))
++
++#define IPU_NUM_IRQS  (32 * 15)
++
++enum ipu_modules {
++      IPU_CONF_CSI0_EN                = (1 << 0),
++      IPU_CONF_CSI1_EN                = (1 << 1),
++      IPU_CONF_IC_EN                  = (1 << 2),
++      IPU_CONF_ROT_EN                 = (1 << 3),
++      IPU_CONF_ISP_EN                 = (1 << 4),
++      IPU_CONF_DP_EN                  = (1 << 5),
++      IPU_CONF_DI0_EN                 = (1 << 6),
++      IPU_CONF_DI1_EN                 = (1 << 7),
++      IPU_CONF_SMFC_EN                = (1 << 8),
++      IPU_CONF_DC_EN                  = (1 << 9),
++      IPU_CONF_DMFC_EN                = (1 << 10),
++
++      IPU_CONF_VDI_EN                 = (1 << 12),
++
++      IPU_CONF_IDMAC_DIS              = (1 << 22),
++
++      IPU_CONF_IC_DMFC_SEL            = (1 << 25),
++      IPU_CONF_IC_DMFC_SYNC           = (1 << 26),
++      IPU_CONF_VDI_DMFC_SYNC          = (1 << 27),
++
++      IPU_CONF_CSI0_DATA_SOURCE       = (1 << 28),
++      IPU_CONF_CSI1_DATA_SOURCE       = (1 << 29),
++      IPU_CONF_IC_INPUT               = (1 << 30),
++      IPU_CONF_CSI_SEL                = (1 << 31),
++};
++
++struct ipuv3_channel {
++      unsigned int num;
++      struct ipu_soc *ipu;
++      struct list_head list;
++};
++
++struct ipu_cpmem;
++struct ipu_csi;
++struct ipu_dc_priv;
++struct ipu_dmfc_priv;
++struct ipu_di;
++struct ipu_ic_priv;
++struct ipu_vdi;
++struct ipu_image_convert_priv;
++struct ipu_smfc_priv;
++struct ipu_pre;
++struct ipu_prg;
++
++struct ipu_devtype;
++
++struct ipu_soc {
++      struct device           *dev;
++      const struct ipu_devtype        *devtype;
++      enum ipuv3_type         ipu_type;
++      spinlock_t              lock;
++      struct mutex            channel_lock;
++      struct list_head        channels;
++
++      void __iomem            *cm_reg;
++      void __iomem            *idmac_reg;
++
++      int                     id;
++      int                     usecount;
++
++      struct clk              *clk;
++
++      int                     irq_sync;
++      int                     irq_err;
++      struct irq_domain       *domain;
++
++      struct ipu_cpmem        *cpmem_priv;
++      struct ipu_dc_priv      *dc_priv;
++      struct ipu_dp_priv      *dp_priv;
++      struct ipu_dmfc_priv    *dmfc_priv;
++      struct ipu_di           *di_priv[2];
++      struct ipu_csi          *csi_priv[2];
++      struct ipu_ic_priv      *ic_priv;
++      struct ipu_vdi          *vdi_priv;
++      struct ipu_image_convert_priv *image_convert_priv;
++      struct ipu_smfc_priv    *smfc_priv;
++      struct ipu_prg          *prg_priv;
++};
++
++static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
++{
++      return readl(ipu->idmac_reg + offset);
++}
++
++static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
++                                 unsigned offset)
++{
++      writel(value, ipu->idmac_reg + offset);
++}
++
++void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync);
++
++int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
++int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
++
++bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno);
++
++int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
++               unsigned long base, u32 module, struct clk *clk_ipu);
++void ipu_csi_exit(struct ipu_soc *ipu, int id);
++
++int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
++              unsigned long base, unsigned long tpmem_base);
++void ipu_ic_exit(struct ipu_soc *ipu);
++
++int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
++               unsigned long base, u32 module);
++void ipu_vdi_exit(struct ipu_soc *ipu);
++
++int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev);
++void ipu_image_convert_exit(struct ipu_soc *ipu);
++
++int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
++              unsigned long base, u32 module, struct clk *ipu_clk);
++void ipu_di_exit(struct ipu_soc *ipu, int id);
++
++int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
++              struct clk *ipu_clk);
++void ipu_dmfc_exit(struct ipu_soc *ipu);
++
++int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
++void ipu_dp_exit(struct ipu_soc *ipu);
++
++int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
++              unsigned long template_base);
++void ipu_dc_exit(struct ipu_soc *ipu);
++
++int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
++void ipu_cpmem_exit(struct ipu_soc *ipu);
++
++int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
++void ipu_smfc_exit(struct ipu_soc *ipu);
++
++struct ipu_pre *ipu_pre_lookup_by_phandle(struct device *dev, const char *name,
++                                        int index);
++int ipu_pre_get_available_count(void);
++int ipu_pre_get(struct ipu_pre *pre);
++void ipu_pre_put(struct ipu_pre *pre);
++u32 ipu_pre_get_baddr(struct ipu_pre *pre);
++void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
++                     unsigned int height, unsigned int stride, u32 format,
++                     uint64_t modifier, unsigned int bufaddr);
++void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr);
++bool ipu_pre_update_pending(struct ipu_pre *pre);
++
++struct ipu_prg *ipu_prg_lookup_by_phandle(struct device *dev, const char *name,
++                                        int ipu_id);
++
++extern struct platform_driver ipu_pre_drv;
++extern struct platform_driver ipu_prg_drv;
++
++#endif                                /* __IPU_PRV_H__ */
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/ipu-smfc.c
+@@ -0,0 +1,202 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++#include <linux/export.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/errno.h>
++#include <linux/spinlock.h>
++#include <linux/delay.h>
++#include <linux/clk.h>
++#include <video/imx-ipu-v3.h>
++
++#include "ipu-prv.h"
++
++struct ipu_smfc {
++      struct ipu_smfc_priv *priv;
++      int chno;
++      bool inuse;
++};
++
++struct ipu_smfc_priv {
++      void __iomem *base;
++      spinlock_t lock;
++      struct ipu_soc *ipu;
++      struct ipu_smfc channel[4];
++      int use_count;
++};
++
++/*SMFC Registers */
++#define SMFC_MAP      0x0000
++#define SMFC_WMC      0x0004
++#define SMFC_BS               0x0008
++
++int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
++{
++      struct ipu_smfc_priv *priv = smfc->priv;
++      unsigned long flags;
++      u32 val, shift;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      shift = smfc->chno * 4;
++      val = readl(priv->base + SMFC_BS);
++      val &= ~(0xf << shift);
++      val |= burstsize << shift;
++      writel(val, priv->base + SMFC_BS);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);
++
++int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
++{
++      struct ipu_smfc_priv *priv = smfc->priv;
++      unsigned long flags;
++      u32 val, shift;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      shift = smfc->chno * 3;
++      val = readl(priv->base + SMFC_MAP);
++      val &= ~(0x7 << shift);
++      val |= ((csi_id << 2) | mipi_id) << shift;
++      writel(val, priv->base + SMFC_MAP);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
++
++int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level)
++{
++      struct ipu_smfc_priv *priv = smfc->priv;
++      unsigned long flags;
++      u32 val, shift;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0);
++      val = readl(priv->base + SMFC_WMC);
++      val &= ~(0x3f << shift);
++      val |= ((clr_level << 3) | set_level) << shift;
++      writel(val, priv->base + SMFC_WMC);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark);
++
++int ipu_smfc_enable(struct ipu_smfc *smfc)
++{
++      struct ipu_smfc_priv *priv = smfc->priv;
++      unsigned long flags;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      if (!priv->use_count)
++              ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);
++
++      priv->use_count++;
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_smfc_enable);
++
++int ipu_smfc_disable(struct ipu_smfc *smfc)
++{
++      struct ipu_smfc_priv *priv = smfc->priv;
++      unsigned long flags;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      priv->use_count--;
++
++      if (!priv->use_count)
++              ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);
++
++      if (priv->use_count < 0)
++              priv->use_count = 0;
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_smfc_disable);
++
++struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
++{
++      struct ipu_smfc_priv *priv = ipu->smfc_priv;
++      struct ipu_smfc *smfc, *ret;
++      unsigned long flags;
++
++      if (chno >= 4)
++              return ERR_PTR(-EINVAL);
++
++      smfc = &priv->channel[chno];
++      ret = smfc;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      if (smfc->inuse) {
++              ret = ERR_PTR(-EBUSY);
++              goto unlock;
++      }
++
++      smfc->inuse = true;
++unlock:
++      spin_unlock_irqrestore(&priv->lock, flags);
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_smfc_get);
++
++void ipu_smfc_put(struct ipu_smfc *smfc)
++{
++      struct ipu_smfc_priv *priv = smfc->priv;
++      unsigned long flags;
++
++      spin_lock_irqsave(&priv->lock, flags);
++      smfc->inuse = false;
++      spin_unlock_irqrestore(&priv->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_smfc_put);
++
++int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
++                unsigned long base)
++{
++      struct ipu_smfc_priv *priv;
++      int i;
++
++      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++
++      ipu->smfc_priv = priv;
++      spin_lock_init(&priv->lock);
++      priv->ipu = ipu;
++
++      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
++      if (!priv->base)
++              return -ENOMEM;
++
++      for (i = 0; i < 4; i++) {
++              priv->channel[i].priv = priv;
++              priv->channel[i].chno = i;
++      }
++
++      pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
++
++      return 0;
++}
++
++void ipu_smfc_exit(struct ipu_soc *ipu)
++{
++}
+--- /dev/null
++++ b/drivers/gpu/imx/ipu-v3/ipu-vdi.c
+@@ -0,0 +1,234 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (C) 2012-2016 Mentor Graphics Inc.
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++#include <linux/io.h>
++#include "ipu-prv.h"
++
++struct ipu_vdi {
++      void __iomem *base;
++      u32 module;
++      spinlock_t lock;
++      int use_count;
++      struct ipu_soc *ipu;
++};
++
++
++/* VDI Register Offsets */
++#define VDI_FSIZE 0x0000
++#define VDI_C     0x0004
++
++/* VDI Register Fields */
++#define VDI_C_CH_420             (0 << 1)
++#define VDI_C_CH_422             (1 << 1)
++#define VDI_C_MOT_SEL_MASK       (0x3 << 2)
++#define VDI_C_MOT_SEL_FULL       (2 << 2)
++#define VDI_C_MOT_SEL_LOW        (1 << 2)
++#define VDI_C_MOT_SEL_MED        (0 << 2)
++#define VDI_C_BURST_SIZE1_4      (3 << 4)
++#define VDI_C_BURST_SIZE2_4      (3 << 8)
++#define VDI_C_BURST_SIZE3_4      (3 << 12)
++#define VDI_C_BURST_SIZE_MASK    0xF
++#define VDI_C_BURST_SIZE1_OFFSET 4
++#define VDI_C_BURST_SIZE2_OFFSET 8
++#define VDI_C_BURST_SIZE3_OFFSET 12
++#define VDI_C_VWM1_SET_1         (0 << 16)
++#define VDI_C_VWM1_SET_2         (1 << 16)
++#define VDI_C_VWM1_CLR_2         (1 << 19)
++#define VDI_C_VWM3_SET_1         (0 << 22)
++#define VDI_C_VWM3_SET_2         (1 << 22)
++#define VDI_C_VWM3_CLR_2         (1 << 25)
++#define VDI_C_TOP_FIELD_MAN_1    (1 << 30)
++#define VDI_C_TOP_FIELD_AUTO_1   (1 << 31)
++
++static inline u32 ipu_vdi_read(struct ipu_vdi *vdi, unsigned int offset)
++{
++      return readl(vdi->base + offset);
++}
++
++static inline void ipu_vdi_write(struct ipu_vdi *vdi, u32 value,
++                               unsigned int offset)
++{
++      writel(value, vdi->base + offset);
++}
++
++void ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field)
++{
++      bool top_field_0 = false;
++      unsigned long flags;
++      u32 reg;
++
++      switch (field) {
++      case V4L2_FIELD_INTERLACED_TB:
++      case V4L2_FIELD_SEQ_TB:
++      case V4L2_FIELD_TOP:
++              top_field_0 = true;
++              break;
++      case V4L2_FIELD_INTERLACED_BT:
++      case V4L2_FIELD_SEQ_BT:
++      case V4L2_FIELD_BOTTOM:
++              top_field_0 = false;
++              break;
++      default:
++              top_field_0 = (std & V4L2_STD_525_60) ? true : false;
++              break;
++      }
++
++      spin_lock_irqsave(&vdi->lock, flags);
++
++      reg = ipu_vdi_read(vdi, VDI_C);
++      if (top_field_0)
++              reg &= ~(VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1);
++      else
++              reg |= VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1;
++      ipu_vdi_write(vdi, reg, VDI_C);
++
++      spin_unlock_irqrestore(&vdi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_set_field_order);
++
++void ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel)
++{
++      unsigned long flags;
++      u32 reg;
++
++      spin_lock_irqsave(&vdi->lock, flags);
++
++      reg = ipu_vdi_read(vdi, VDI_C);
++
++      reg &= ~VDI_C_MOT_SEL_MASK;
++
++      switch (motion_sel) {
++      case MED_MOTION:
++              reg |= VDI_C_MOT_SEL_MED;
++              break;
++      case HIGH_MOTION:
++              reg |= VDI_C_MOT_SEL_FULL;
++              break;
++      default:
++              reg |= VDI_C_MOT_SEL_LOW;
++              break;
++      }
++
++      ipu_vdi_write(vdi, reg, VDI_C);
++
++      spin_unlock_irqrestore(&vdi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_set_motion);
++
++void ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres)
++{
++      unsigned long flags;
++      u32 pixel_fmt, reg;
++
++      spin_lock_irqsave(&vdi->lock, flags);
++
++      reg = ((yres - 1) << 16) | (xres - 1);
++      ipu_vdi_write(vdi, reg, VDI_FSIZE);
++
++      /*
++       * Full motion, only vertical filter is used.
++       * Burst size is 4 accesses
++       */
++      if (code == MEDIA_BUS_FMT_UYVY8_2X8 ||
++          code == MEDIA_BUS_FMT_UYVY8_1X16 ||
++          code == MEDIA_BUS_FMT_YUYV8_2X8 ||
++          code == MEDIA_BUS_FMT_YUYV8_1X16)
++              pixel_fmt = VDI_C_CH_422;
++      else
++              pixel_fmt = VDI_C_CH_420;
++
++      reg = ipu_vdi_read(vdi, VDI_C);
++      reg |= pixel_fmt;
++      reg |= VDI_C_BURST_SIZE2_4;
++      reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_CLR_2;
++      reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_CLR_2;
++      ipu_vdi_write(vdi, reg, VDI_C);
++
++      spin_unlock_irqrestore(&vdi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_setup);
++
++void ipu_vdi_unsetup(struct ipu_vdi *vdi)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&vdi->lock, flags);
++      ipu_vdi_write(vdi, 0, VDI_FSIZE);
++      ipu_vdi_write(vdi, 0, VDI_C);
++      spin_unlock_irqrestore(&vdi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_unsetup);
++
++int ipu_vdi_enable(struct ipu_vdi *vdi)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&vdi->lock, flags);
++
++      if (!vdi->use_count)
++              ipu_module_enable(vdi->ipu, vdi->module);
++
++      vdi->use_count++;
++
++      spin_unlock_irqrestore(&vdi->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_enable);
++
++int ipu_vdi_disable(struct ipu_vdi *vdi)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&vdi->lock, flags);
++
++      if (vdi->use_count) {
++              if (!--vdi->use_count)
++                      ipu_module_disable(vdi->ipu, vdi->module);
++      }
++
++      spin_unlock_irqrestore(&vdi->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_disable);
++
++struct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu)
++{
++      return ipu->vdi_priv;
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_get);
++
++void ipu_vdi_put(struct ipu_vdi *vdi)
++{
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_put);
++
++int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
++               unsigned long base, u32 module)
++{
++      struct ipu_vdi *vdi;
++
++      vdi = devm_kzalloc(dev, sizeof(*vdi), GFP_KERNEL);
++      if (!vdi)
++              return -ENOMEM;
++
++      ipu->vdi_priv = vdi;
++
++      spin_lock_init(&vdi->lock);
++      vdi->module = module;
++      vdi->base = devm_ioremap(dev, base, PAGE_SIZE);
++      if (!vdi->base)
++              return -ENOMEM;
++
++      dev_dbg(dev, "VDI base: 0x%08lx remapped to %p\n", base, vdi->base);
++      vdi->ipu = ipu;
++
++      return 0;
++}
++
++void ipu_vdi_exit(struct ipu_soc *ipu)
++{
++}
+--- a/drivers/gpu/ipu-v3/Kconfig
++++ /dev/null
+@@ -1,11 +0,0 @@
+-# SPDX-License-Identifier: GPL-2.0-only
+-config IMX_IPUV3_CORE
+-      tristate "IPUv3 core support"
+-      depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM || COMPILE_TEST
+-      depends on DRM || !DRM # if DRM=m, this can't be 'y'
+-      select BITREVERSE
+-      select GENERIC_ALLOCATOR if DRM
+-      select GENERIC_IRQ_CHIP
+-      help
+-        Choose this if you have a i.MX5/6 system and want to use the Image
+-        Processing Unit. This option only enables IPU base support.
+--- a/drivers/gpu/ipu-v3/Makefile
++++ /dev/null
+@@ -1,10 +0,0 @@
+-# SPDX-License-Identifier: GPL-2.0
+-obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
+-
+-imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
+-              ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-ic-csc.o \
+-              ipu-image-convert.o ipu-smfc.o ipu-vdi.o
+-
+-ifdef CONFIG_DRM
+-      imx-ipu-v3-objs += ipu-pre.o ipu-prg.o
+-endif
+--- a/drivers/gpu/ipu-v3/ipu-common.c
++++ /dev/null
+@@ -1,1565 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-#include <linux/module.h>
+-#include <linux/export.h>
+-#include <linux/types.h>
+-#include <linux/reset.h>
+-#include <linux/platform_device.h>
+-#include <linux/err.h>
+-#include <linux/spinlock.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/io.h>
+-#include <linux/clk.h>
+-#include <linux/list.h>
+-#include <linux/irq.h>
+-#include <linux/irqchip/chained_irq.h>
+-#include <linux/irqdomain.h>
+-#include <linux/of_device.h>
+-#include <linux/of_graph.h>
+-
+-#include <drm/drm_fourcc.h>
+-
+-#include <video/imx-ipu-v3.h>
+-#include "ipu-prv.h"
+-
+-static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
+-{
+-      return readl(ipu->cm_reg + offset);
+-}
+-
+-static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
+-{
+-      writel(value, ipu->cm_reg + offset);
+-}
+-
+-int ipu_get_num(struct ipu_soc *ipu)
+-{
+-      return ipu->id;
+-}
+-EXPORT_SYMBOL_GPL(ipu_get_num);
+-
+-void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync)
+-{
+-      u32 val;
+-
+-      val = ipu_cm_read(ipu, IPU_SRM_PRI2);
+-      val &= ~DP_S_SRM_MODE_MASK;
+-      val |= sync ? DP_S_SRM_MODE_NEXT_FRAME :
+-                    DP_S_SRM_MODE_NOW;
+-      ipu_cm_write(ipu, val, IPU_SRM_PRI2);
+-}
+-EXPORT_SYMBOL_GPL(ipu_srm_dp_update);
+-
+-enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
+-{
+-      switch (drm_fourcc) {
+-      case DRM_FORMAT_ARGB1555:
+-      case DRM_FORMAT_ABGR1555:
+-      case DRM_FORMAT_RGBA5551:
+-      case DRM_FORMAT_BGRA5551:
+-      case DRM_FORMAT_RGB565:
+-      case DRM_FORMAT_BGR565:
+-      case DRM_FORMAT_RGB888:
+-      case DRM_FORMAT_BGR888:
+-      case DRM_FORMAT_ARGB4444:
+-      case DRM_FORMAT_XRGB8888:
+-      case DRM_FORMAT_XBGR8888:
+-      case DRM_FORMAT_RGBX8888:
+-      case DRM_FORMAT_BGRX8888:
+-      case DRM_FORMAT_ARGB8888:
+-      case DRM_FORMAT_ABGR8888:
+-      case DRM_FORMAT_RGBA8888:
+-      case DRM_FORMAT_BGRA8888:
+-      case DRM_FORMAT_RGB565_A8:
+-      case DRM_FORMAT_BGR565_A8:
+-      case DRM_FORMAT_RGB888_A8:
+-      case DRM_FORMAT_BGR888_A8:
+-      case DRM_FORMAT_RGBX8888_A8:
+-      case DRM_FORMAT_BGRX8888_A8:
+-              return IPUV3_COLORSPACE_RGB;
+-      case DRM_FORMAT_YUYV:
+-      case DRM_FORMAT_UYVY:
+-      case DRM_FORMAT_YUV420:
+-      case DRM_FORMAT_YVU420:
+-      case DRM_FORMAT_YUV422:
+-      case DRM_FORMAT_YVU422:
+-      case DRM_FORMAT_YUV444:
+-      case DRM_FORMAT_YVU444:
+-      case DRM_FORMAT_NV12:
+-      case DRM_FORMAT_NV21:
+-      case DRM_FORMAT_NV16:
+-      case DRM_FORMAT_NV61:
+-              return IPUV3_COLORSPACE_YUV;
+-      default:
+-              return IPUV3_COLORSPACE_UNKNOWN;
+-      }
+-}
+-EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace);
+-
+-enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
+-{
+-      switch (pixelformat) {
+-      case V4L2_PIX_FMT_YUV420:
+-      case V4L2_PIX_FMT_YVU420:
+-      case V4L2_PIX_FMT_YUV422P:
+-      case V4L2_PIX_FMT_UYVY:
+-      case V4L2_PIX_FMT_YUYV:
+-      case V4L2_PIX_FMT_NV12:
+-      case V4L2_PIX_FMT_NV21:
+-      case V4L2_PIX_FMT_NV16:
+-      case V4L2_PIX_FMT_NV61:
+-              return IPUV3_COLORSPACE_YUV;
+-      case V4L2_PIX_FMT_RGB565:
+-      case V4L2_PIX_FMT_BGR24:
+-      case V4L2_PIX_FMT_RGB24:
+-      case V4L2_PIX_FMT_ABGR32:
+-      case V4L2_PIX_FMT_XBGR32:
+-      case V4L2_PIX_FMT_BGRA32:
+-      case V4L2_PIX_FMT_BGRX32:
+-      case V4L2_PIX_FMT_RGBA32:
+-      case V4L2_PIX_FMT_RGBX32:
+-      case V4L2_PIX_FMT_ARGB32:
+-      case V4L2_PIX_FMT_XRGB32:
+-              return IPUV3_COLORSPACE_RGB;
+-      default:
+-              return IPUV3_COLORSPACE_UNKNOWN;
+-      }
+-}
+-EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
+-
+-bool ipu_pixelformat_is_planar(u32 pixelformat)
+-{
+-      switch (pixelformat) {
+-      case V4L2_PIX_FMT_YUV420:
+-      case V4L2_PIX_FMT_YVU420:
+-      case V4L2_PIX_FMT_YUV422P:
+-      case V4L2_PIX_FMT_NV12:
+-      case V4L2_PIX_FMT_NV21:
+-      case V4L2_PIX_FMT_NV16:
+-      case V4L2_PIX_FMT_NV61:
+-              return true;
+-      }
+-
+-      return false;
+-}
+-EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar);
+-
+-enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
+-{
+-      switch (mbus_code & 0xf000) {
+-      case 0x1000:
+-              return IPUV3_COLORSPACE_RGB;
+-      case 0x2000:
+-              return IPUV3_COLORSPACE_YUV;
+-      default:
+-              return IPUV3_COLORSPACE_UNKNOWN;
+-      }
+-}
+-EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
+-
+-int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat)
+-{
+-      switch (pixelformat) {
+-      case V4L2_PIX_FMT_YUV420:
+-      case V4L2_PIX_FMT_YVU420:
+-      case V4L2_PIX_FMT_YUV422P:
+-      case V4L2_PIX_FMT_NV12:
+-      case V4L2_PIX_FMT_NV21:
+-      case V4L2_PIX_FMT_NV16:
+-      case V4L2_PIX_FMT_NV61:
+-              /*
+-               * for the planar YUV formats, the stride passed to
+-               * cpmem must be the stride in bytes of the Y plane.
+-               * And all the planar YUV formats have an 8-bit
+-               * Y component.
+-               */
+-              return (8 * pixel_stride) >> 3;
+-      case V4L2_PIX_FMT_RGB565:
+-      case V4L2_PIX_FMT_YUYV:
+-      case V4L2_PIX_FMT_UYVY:
+-              return (16 * pixel_stride) >> 3;
+-      case V4L2_PIX_FMT_BGR24:
+-      case V4L2_PIX_FMT_RGB24:
+-              return (24 * pixel_stride) >> 3;
+-      case V4L2_PIX_FMT_BGR32:
+-      case V4L2_PIX_FMT_RGB32:
+-      case V4L2_PIX_FMT_XBGR32:
+-      case V4L2_PIX_FMT_XRGB32:
+-              return (32 * pixel_stride) >> 3;
+-      default:
+-              break;
+-      }
+-
+-      return -EINVAL;
+-}
+-EXPORT_SYMBOL_GPL(ipu_stride_to_bytes);
+-
+-int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
+-                          bool hflip, bool vflip)
+-{
+-      u32 r90, vf, hf;
+-
+-      switch (degrees) {
+-      case 0:
+-              vf = hf = r90 = 0;
+-              break;
+-      case 90:
+-              vf = hf = 0;
+-              r90 = 1;
+-              break;
+-      case 180:
+-              vf = hf = 1;
+-              r90 = 0;
+-              break;
+-      case 270:
+-              vf = hf = r90 = 1;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      hf ^= (u32)hflip;
+-      vf ^= (u32)vflip;
+-
+-      *mode = (enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf);
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode);
+-
+-int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
+-                          bool hflip, bool vflip)
+-{
+-      u32 r90, vf, hf;
+-
+-      r90 = ((u32)mode >> 2) & 0x1;
+-      hf = ((u32)mode >> 1) & 0x1;
+-      vf = ((u32)mode >> 0) & 0x1;
+-      hf ^= (u32)hflip;
+-      vf ^= (u32)vflip;
+-
+-      switch ((enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf)) {
+-      case IPU_ROTATE_NONE:
+-              *degrees = 0;
+-              break;
+-      case IPU_ROTATE_90_RIGHT:
+-              *degrees = 90;
+-              break;
+-      case IPU_ROTATE_180:
+-              *degrees = 180;
+-              break;
+-      case IPU_ROTATE_90_LEFT:
+-              *degrees = 270;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees);
+-
+-struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
+-{
+-      struct ipuv3_channel *channel;
+-
+-      dev_dbg(ipu->dev, "%s %d\n", __func__, num);
+-
+-      if (num > 63)
+-              return ERR_PTR(-ENODEV);
+-
+-      mutex_lock(&ipu->channel_lock);
+-
+-      list_for_each_entry(channel, &ipu->channels, list) {
+-              if (channel->num == num) {
+-                      channel = ERR_PTR(-EBUSY);
+-                      goto out;
+-              }
+-      }
+-
+-      channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+-      if (!channel) {
+-              channel = ERR_PTR(-ENOMEM);
+-              goto out;
+-      }
+-
+-      channel->num = num;
+-      channel->ipu = ipu;
+-      list_add(&channel->list, &ipu->channels);
+-
+-out:
+-      mutex_unlock(&ipu->channel_lock);
+-
+-      return channel;
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_get);
+-
+-void ipu_idmac_put(struct ipuv3_channel *channel)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-
+-      dev_dbg(ipu->dev, "%s %d\n", __func__, channel->num);
+-
+-      mutex_lock(&ipu->channel_lock);
+-
+-      list_del(&channel->list);
+-      kfree(channel);
+-
+-      mutex_unlock(&ipu->channel_lock);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_put);
+-
+-#define idma_mask(ch)                 (1 << ((ch) & 0x1f))
+-
+-/*
+- * This is an undocumented feature, a write one to a channel bit in
+- * IPU_CHA_CUR_BUF and IPU_CHA_TRIPLE_CUR_BUF will reset the channel's
+- * internal current buffer pointer so that transfers start from buffer
+- * 0 on the next channel enable (that's the theory anyway, the imx6 TRM
+- * only says these are read-only registers). This operation is required
+- * for channel linking to work correctly, for instance video capture
+- * pipelines that carry out image rotations will fail after the first
+- * streaming unless this function is called for each channel before
+- * re-enabling the channels.
+- */
+-static void __ipu_idmac_reset_current_buffer(struct ipuv3_channel *channel)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned int chno = channel->num;
+-
+-      ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_CUR_BUF(chno));
+-}
+-
+-void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
+-              bool doublebuffer)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned long flags;
+-      u32 reg;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
+-      if (doublebuffer)
+-              reg |= idma_mask(channel->num);
+-      else
+-              reg &= ~idma_mask(channel->num);
+-      ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
+-
+-      __ipu_idmac_reset_current_buffer(channel);
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
+-
+-static const struct {
+-      int chnum;
+-      u32 reg;
+-      int shift;
+-} idmac_lock_en_info[] = {
+-      { .chnum =  5, .reg = IDMAC_CH_LOCK_EN_1, .shift =  0, },
+-      { .chnum = 11, .reg = IDMAC_CH_LOCK_EN_1, .shift =  2, },
+-      { .chnum = 12, .reg = IDMAC_CH_LOCK_EN_1, .shift =  4, },
+-      { .chnum = 14, .reg = IDMAC_CH_LOCK_EN_1, .shift =  6, },
+-      { .chnum = 15, .reg = IDMAC_CH_LOCK_EN_1, .shift =  8, },
+-      { .chnum = 20, .reg = IDMAC_CH_LOCK_EN_1, .shift = 10, },
+-      { .chnum = 21, .reg = IDMAC_CH_LOCK_EN_1, .shift = 12, },
+-      { .chnum = 22, .reg = IDMAC_CH_LOCK_EN_1, .shift = 14, },
+-      { .chnum = 23, .reg = IDMAC_CH_LOCK_EN_1, .shift = 16, },
+-      { .chnum = 27, .reg = IDMAC_CH_LOCK_EN_1, .shift = 18, },
+-      { .chnum = 28, .reg = IDMAC_CH_LOCK_EN_1, .shift = 20, },
+-      { .chnum = 45, .reg = IDMAC_CH_LOCK_EN_2, .shift =  0, },
+-      { .chnum = 46, .reg = IDMAC_CH_LOCK_EN_2, .shift =  2, },
+-      { .chnum = 47, .reg = IDMAC_CH_LOCK_EN_2, .shift =  4, },
+-      { .chnum = 48, .reg = IDMAC_CH_LOCK_EN_2, .shift =  6, },
+-      { .chnum = 49, .reg = IDMAC_CH_LOCK_EN_2, .shift =  8, },
+-      { .chnum = 50, .reg = IDMAC_CH_LOCK_EN_2, .shift = 10, },
+-};
+-
+-int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned long flags;
+-      u32 bursts, regval;
+-      int i;
+-
+-      switch (num_bursts) {
+-      case 0:
+-      case 1:
+-              bursts = 0x00; /* locking disabled */
+-              break;
+-      case 2:
+-              bursts = 0x01;
+-              break;
+-      case 4:
+-              bursts = 0x02;
+-              break;
+-      case 8:
+-              bursts = 0x03;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      /*
+-       * IPUv3EX / i.MX51 has a different register layout, and on IPUv3M /
+-       * i.MX53 channel arbitration locking doesn't seem to work properly.
+-       * Allow enabling the lock feature on IPUv3H / i.MX6 only.
+-       */
+-      if (bursts && ipu->ipu_type != IPUV3H)
+-              return -EINVAL;
+-
+-      for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) {
+-              if (channel->num == idmac_lock_en_info[i].chnum)
+-                      break;
+-      }
+-      if (i >= ARRAY_SIZE(idmac_lock_en_info))
+-              return -EINVAL;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      regval = ipu_idmac_read(ipu, idmac_lock_en_info[i].reg);
+-      regval &= ~(0x03 << idmac_lock_en_info[i].shift);
+-      regval |= (bursts << idmac_lock_en_info[i].shift);
+-      ipu_idmac_write(ipu, regval, idmac_lock_en_info[i].reg);
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_lock_enable);
+-
+-int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
+-{
+-      unsigned long lock_flags;
+-      u32 val;
+-
+-      spin_lock_irqsave(&ipu->lock, lock_flags);
+-
+-      val = ipu_cm_read(ipu, IPU_DISP_GEN);
+-
+-      if (mask & IPU_CONF_DI0_EN)
+-              val |= IPU_DI0_COUNTER_RELEASE;
+-      if (mask & IPU_CONF_DI1_EN)
+-              val |= IPU_DI1_COUNTER_RELEASE;
+-
+-      ipu_cm_write(ipu, val, IPU_DISP_GEN);
+-
+-      val = ipu_cm_read(ipu, IPU_CONF);
+-      val |= mask;
+-      ipu_cm_write(ipu, val, IPU_CONF);
+-
+-      spin_unlock_irqrestore(&ipu->lock, lock_flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_module_enable);
+-
+-int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
+-{
+-      unsigned long lock_flags;
+-      u32 val;
+-
+-      spin_lock_irqsave(&ipu->lock, lock_flags);
+-
+-      val = ipu_cm_read(ipu, IPU_CONF);
+-      val &= ~mask;
+-      ipu_cm_write(ipu, val, IPU_CONF);
+-
+-      val = ipu_cm_read(ipu, IPU_DISP_GEN);
+-
+-      if (mask & IPU_CONF_DI0_EN)
+-              val &= ~IPU_DI0_COUNTER_RELEASE;
+-      if (mask & IPU_CONF_DI1_EN)
+-              val &= ~IPU_DI1_COUNTER_RELEASE;
+-
+-      ipu_cm_write(ipu, val, IPU_DISP_GEN);
+-
+-      spin_unlock_irqrestore(&ipu->lock, lock_flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_module_disable);
+-
+-int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned int chno = channel->num;
+-
+-      return (ipu_cm_read(ipu, IPU_CHA_CUR_BUF(chno)) & idma_mask(chno)) ? 1 : 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer);
+-
+-bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned long flags;
+-      u32 reg = 0;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-      switch (buf_num) {
+-      case 0:
+-              reg = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num));
+-              break;
+-      case 1:
+-              reg = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num));
+-              break;
+-      case 2:
+-              reg = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(channel->num));
+-              break;
+-      }
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-
+-      return ((reg & idma_mask(channel->num)) != 0);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_buffer_is_ready);
+-
+-void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned int chno = channel->num;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      /* Mark buffer as ready. */
+-      if (buf_num == 0)
+-              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
+-      else
+-              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
+-
+-void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned int chno = channel->num;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */
+-      switch (buf_num) {
+-      case 0:
+-              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
+-              break;
+-      case 1:
+-              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
+-              break;
+-      case 2:
+-              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF2_RDY(chno));
+-              break;
+-      default:
+-              break;
+-      }
+-      ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer);
+-
+-int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      u32 val;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
+-      val |= idma_mask(channel->num);
+-      ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
+-
+-bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno)
+-{
+-      return (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(chno)) & idma_mask(chno));
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_channel_busy);
+-
+-int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned long timeout;
+-
+-      timeout = jiffies + msecs_to_jiffies(ms);
+-      while (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(channel->num)) &
+-                      idma_mask(channel->num)) {
+-              if (time_after(jiffies, timeout))
+-                      return -ETIMEDOUT;
+-              cpu_relax();
+-      }
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy);
+-
+-int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      u32 val;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      /* Disable DMA channel(s) */
+-      val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
+-      val &= ~idma_mask(channel->num);
+-      ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
+-
+-      __ipu_idmac_reset_current_buffer(channel);
+-
+-      /* Set channel buffers NOT to be ready */
+-      ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
+-
+-      if (ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num)) &
+-                      idma_mask(channel->num)) {
+-              ipu_cm_write(ipu, idma_mask(channel->num),
+-                           IPU_CHA_BUF0_RDY(channel->num));
+-      }
+-
+-      if (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num)) &
+-                      idma_mask(channel->num)) {
+-              ipu_cm_write(ipu, idma_mask(channel->num),
+-                           IPU_CHA_BUF1_RDY(channel->num));
+-      }
+-
+-      ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
+-
+-      /* Reset the double buffer */
+-      val = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
+-      val &= ~idma_mask(channel->num);
+-      ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num));
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
+-
+-/*
+- * The imx6 rev. D TRM says that enabling the WM feature will increase
+- * a channel's priority. Refer to Table 36-8 Calculated priority value.
+- * The sub-module that is the sink or source for the channel must enable
+- * watermark signal for this to take effect (SMFC_WM for instance).
+- */
+-void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned long flags;
+-      u32 val;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      val = ipu_idmac_read(ipu, IDMAC_WM_EN(channel->num));
+-      if (enable)
+-              val |= 1 << (channel->num % 32);
+-      else
+-              val &= ~(1 << (channel->num % 32));
+-      ipu_idmac_write(ipu, val, IDMAC_WM_EN(channel->num));
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_enable_watermark);
+-
+-static int ipu_memory_reset(struct ipu_soc *ipu)
+-{
+-      unsigned long timeout;
+-
+-      ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST);
+-
+-      timeout = jiffies + msecs_to_jiffies(1000);
+-      while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) {
+-              if (time_after(jiffies, timeout))
+-                      return -ETIME;
+-              cpu_relax();
+-      }
+-
+-      return 0;
+-}
+-
+-/*
+- * Set the source mux for the given CSI. Selects either parallel or
+- * MIPI CSI2 sources.
+- */
+-void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2)
+-{
+-      unsigned long flags;
+-      u32 val, mask;
+-
+-      mask = (csi_id == 1) ? IPU_CONF_CSI1_DATA_SOURCE :
+-              IPU_CONF_CSI0_DATA_SOURCE;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      val = ipu_cm_read(ipu, IPU_CONF);
+-      if (mipi_csi2)
+-              val |= mask;
+-      else
+-              val &= ~mask;
+-      ipu_cm_write(ipu, val, IPU_CONF);
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_set_csi_src_mux);
+-
+-/*
+- * Set the source mux for the IC. Selects either CSI[01] or the VDI.
+- */
+-void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi)
+-{
+-      unsigned long flags;
+-      u32 val;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      val = ipu_cm_read(ipu, IPU_CONF);
+-      if (vdi)
+-              val |= IPU_CONF_IC_INPUT;
+-      else
+-              val &= ~IPU_CONF_IC_INPUT;
+-
+-      if (csi_id == 1)
+-              val |= IPU_CONF_CSI_SEL;
+-      else
+-              val &= ~IPU_CONF_CSI_SEL;
+-
+-      ipu_cm_write(ipu, val, IPU_CONF);
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux);
+-
+-
+-/* Frame Synchronization Unit Channel Linking */
+-
+-struct fsu_link_reg_info {
+-      int chno;
+-      u32 reg;
+-      u32 mask;
+-      u32 val;
+-};
+-
+-struct fsu_link_info {
+-      struct fsu_link_reg_info src;
+-      struct fsu_link_reg_info sink;
+-};
+-
+-static const struct fsu_link_info fsu_link_info[] = {
+-      {
+-              .src  = { IPUV3_CHANNEL_IC_PRP_ENC_MEM, IPU_FS_PROC_FLOW2,
+-                        FS_PRP_ENC_DEST_SEL_MASK, FS_PRP_ENC_DEST_SEL_IRT_ENC },
+-              .sink = { IPUV3_CHANNEL_MEM_ROT_ENC, IPU_FS_PROC_FLOW1,
+-                        FS_PRPENC_ROT_SRC_SEL_MASK, FS_PRPENC_ROT_SRC_SEL_ENC },
+-      }, {
+-              .src =  { IPUV3_CHANNEL_IC_PRP_VF_MEM, IPU_FS_PROC_FLOW2,
+-                        FS_PRPVF_DEST_SEL_MASK, FS_PRPVF_DEST_SEL_IRT_VF },
+-              .sink = { IPUV3_CHANNEL_MEM_ROT_VF, IPU_FS_PROC_FLOW1,
+-                        FS_PRPVF_ROT_SRC_SEL_MASK, FS_PRPVF_ROT_SRC_SEL_VF },
+-      }, {
+-              .src =  { IPUV3_CHANNEL_IC_PP_MEM, IPU_FS_PROC_FLOW2,
+-                        FS_PP_DEST_SEL_MASK, FS_PP_DEST_SEL_IRT_PP },
+-              .sink = { IPUV3_CHANNEL_MEM_ROT_PP, IPU_FS_PROC_FLOW1,
+-                        FS_PP_ROT_SRC_SEL_MASK, FS_PP_ROT_SRC_SEL_PP },
+-      }, {
+-              .src =  { IPUV3_CHANNEL_CSI_DIRECT, 0 },
+-              .sink = { IPUV3_CHANNEL_CSI_VDI_PREV, IPU_FS_PROC_FLOW1,
+-                        FS_VDI_SRC_SEL_MASK, FS_VDI_SRC_SEL_CSI_DIRECT },
+-      },
+-};
+-
+-static const struct fsu_link_info *find_fsu_link_info(int src, int sink)
+-{
+-      int i;
+-
+-      for (i = 0; i < ARRAY_SIZE(fsu_link_info); i++) {
+-              if (src == fsu_link_info[i].src.chno &&
+-                  sink == fsu_link_info[i].sink.chno)
+-                      return &fsu_link_info[i];
+-      }
+-
+-      return NULL;
+-}
+-
+-/*
+- * Links a source channel to a sink channel in the FSU.
+- */
+-int ipu_fsu_link(struct ipu_soc *ipu, int src_ch, int sink_ch)
+-{
+-      const struct fsu_link_info *link;
+-      u32 src_reg, sink_reg;
+-      unsigned long flags;
+-
+-      link = find_fsu_link_info(src_ch, sink_ch);
+-      if (!link)
+-              return -EINVAL;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      if (link->src.mask) {
+-              src_reg = ipu_cm_read(ipu, link->src.reg);
+-              src_reg &= ~link->src.mask;
+-              src_reg |= link->src.val;
+-              ipu_cm_write(ipu, src_reg, link->src.reg);
+-      }
+-
+-      if (link->sink.mask) {
+-              sink_reg = ipu_cm_read(ipu, link->sink.reg);
+-              sink_reg &= ~link->sink.mask;
+-              sink_reg |= link->sink.val;
+-              ipu_cm_write(ipu, sink_reg, link->sink.reg);
+-      }
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_fsu_link);
+-
+-/*
+- * Unlinks source and sink channels in the FSU.
+- */
+-int ipu_fsu_unlink(struct ipu_soc *ipu, int src_ch, int sink_ch)
+-{
+-      const struct fsu_link_info *link;
+-      u32 src_reg, sink_reg;
+-      unsigned long flags;
+-
+-      link = find_fsu_link_info(src_ch, sink_ch);
+-      if (!link)
+-              return -EINVAL;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      if (link->src.mask) {
+-              src_reg = ipu_cm_read(ipu, link->src.reg);
+-              src_reg &= ~link->src.mask;
+-              ipu_cm_write(ipu, src_reg, link->src.reg);
+-      }
+-
+-      if (link->sink.mask) {
+-              sink_reg = ipu_cm_read(ipu, link->sink.reg);
+-              sink_reg &= ~link->sink.mask;
+-              ipu_cm_write(ipu, sink_reg, link->sink.reg);
+-      }
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_fsu_unlink);
+-
+-/* Link IDMAC channels in the FSU */
+-int ipu_idmac_link(struct ipuv3_channel *src, struct ipuv3_channel *sink)
+-{
+-      return ipu_fsu_link(src->ipu, src->num, sink->num);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_link);
+-
+-/* Unlink IDMAC channels in the FSU */
+-int ipu_idmac_unlink(struct ipuv3_channel *src, struct ipuv3_channel *sink)
+-{
+-      return ipu_fsu_unlink(src->ipu, src->num, sink->num);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_unlink);
+-
+-struct ipu_devtype {
+-      const char *name;
+-      unsigned long cm_ofs;
+-      unsigned long cpmem_ofs;
+-      unsigned long srm_ofs;
+-      unsigned long tpm_ofs;
+-      unsigned long csi0_ofs;
+-      unsigned long csi1_ofs;
+-      unsigned long ic_ofs;
+-      unsigned long disp0_ofs;
+-      unsigned long disp1_ofs;
+-      unsigned long dc_tmpl_ofs;
+-      unsigned long vdi_ofs;
+-      enum ipuv3_type type;
+-};
+-
+-static struct ipu_devtype ipu_type_imx51 = {
+-      .name = "IPUv3EX",
+-      .cm_ofs = 0x1e000000,
+-      .cpmem_ofs = 0x1f000000,
+-      .srm_ofs = 0x1f040000,
+-      .tpm_ofs = 0x1f060000,
+-      .csi0_ofs = 0x1e030000,
+-      .csi1_ofs = 0x1e038000,
+-      .ic_ofs = 0x1e020000,
+-      .disp0_ofs = 0x1e040000,
+-      .disp1_ofs = 0x1e048000,
+-      .dc_tmpl_ofs = 0x1f080000,
+-      .vdi_ofs = 0x1e068000,
+-      .type = IPUV3EX,
+-};
+-
+-static struct ipu_devtype ipu_type_imx53 = {
+-      .name = "IPUv3M",
+-      .cm_ofs = 0x06000000,
+-      .cpmem_ofs = 0x07000000,
+-      .srm_ofs = 0x07040000,
+-      .tpm_ofs = 0x07060000,
+-      .csi0_ofs = 0x06030000,
+-      .csi1_ofs = 0x06038000,
+-      .ic_ofs = 0x06020000,
+-      .disp0_ofs = 0x06040000,
+-      .disp1_ofs = 0x06048000,
+-      .dc_tmpl_ofs = 0x07080000,
+-      .vdi_ofs = 0x06068000,
+-      .type = IPUV3M,
+-};
+-
+-static struct ipu_devtype ipu_type_imx6q = {
+-      .name = "IPUv3H",
+-      .cm_ofs = 0x00200000,
+-      .cpmem_ofs = 0x00300000,
+-      .srm_ofs = 0x00340000,
+-      .tpm_ofs = 0x00360000,
+-      .csi0_ofs = 0x00230000,
+-      .csi1_ofs = 0x00238000,
+-      .ic_ofs = 0x00220000,
+-      .disp0_ofs = 0x00240000,
+-      .disp1_ofs = 0x00248000,
+-      .dc_tmpl_ofs = 0x00380000,
+-      .vdi_ofs = 0x00268000,
+-      .type = IPUV3H,
+-};
+-
+-static const struct of_device_id imx_ipu_dt_ids[] = {
+-      { .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
+-      { .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
+-      { .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
+-      { .compatible = "fsl,imx6qp-ipu", .data = &ipu_type_imx6q, },
+-      { /* sentinel */ }
+-};
+-MODULE_DEVICE_TABLE(of, imx_ipu_dt_ids);
+-
+-static int ipu_submodules_init(struct ipu_soc *ipu,
+-              struct platform_device *pdev, unsigned long ipu_base,
+-              struct clk *ipu_clk)
+-{
+-      char *unit;
+-      int ret;
+-      struct device *dev = &pdev->dev;
+-      const struct ipu_devtype *devtype = ipu->devtype;
+-
+-      ret = ipu_cpmem_init(ipu, dev, ipu_base + devtype->cpmem_ofs);
+-      if (ret) {
+-              unit = "cpmem";
+-              goto err_cpmem;
+-      }
+-
+-      ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs,
+-                         IPU_CONF_CSI0_EN, ipu_clk);
+-      if (ret) {
+-              unit = "csi0";
+-              goto err_csi_0;
+-      }
+-
+-      ret = ipu_csi_init(ipu, dev, 1, ipu_base + devtype->csi1_ofs,
+-                         IPU_CONF_CSI1_EN, ipu_clk);
+-      if (ret) {
+-              unit = "csi1";
+-              goto err_csi_1;
+-      }
+-
+-      ret = ipu_ic_init(ipu, dev,
+-                        ipu_base + devtype->ic_ofs,
+-                        ipu_base + devtype->tpm_ofs);
+-      if (ret) {
+-              unit = "ic";
+-              goto err_ic;
+-      }
+-
+-      ret = ipu_vdi_init(ipu, dev, ipu_base + devtype->vdi_ofs,
+-                         IPU_CONF_VDI_EN | IPU_CONF_ISP_EN |
+-                         IPU_CONF_IC_INPUT);
+-      if (ret) {
+-              unit = "vdi";
+-              goto err_vdi;
+-      }
+-
+-      ret = ipu_image_convert_init(ipu, dev);
+-      if (ret) {
+-              unit = "image_convert";
+-              goto err_image_convert;
+-      }
+-
+-      ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
+-                        IPU_CONF_DI0_EN, ipu_clk);
+-      if (ret) {
+-              unit = "di0";
+-              goto err_di_0;
+-      }
+-
+-      ret = ipu_di_init(ipu, dev, 1, ipu_base + devtype->disp1_ofs,
+-                      IPU_CONF_DI1_EN, ipu_clk);
+-      if (ret) {
+-              unit = "di1";
+-              goto err_di_1;
+-      }
+-
+-      ret = ipu_dc_init(ipu, dev, ipu_base + devtype->cm_ofs +
+-                      IPU_CM_DC_REG_OFS, ipu_base + devtype->dc_tmpl_ofs);
+-      if (ret) {
+-              unit = "dc_template";
+-              goto err_dc;
+-      }
+-
+-      ret = ipu_dmfc_init(ipu, dev, ipu_base +
+-                      devtype->cm_ofs + IPU_CM_DMFC_REG_OFS, ipu_clk);
+-      if (ret) {
+-              unit = "dmfc";
+-              goto err_dmfc;
+-      }
+-
+-      ret = ipu_dp_init(ipu, dev, ipu_base + devtype->srm_ofs);
+-      if (ret) {
+-              unit = "dp";
+-              goto err_dp;
+-      }
+-
+-      ret = ipu_smfc_init(ipu, dev, ipu_base +
+-                      devtype->cm_ofs + IPU_CM_SMFC_REG_OFS);
+-      if (ret) {
+-              unit = "smfc";
+-              goto err_smfc;
+-      }
+-
+-      return 0;
+-
+-err_smfc:
+-      ipu_dp_exit(ipu);
+-err_dp:
+-      ipu_dmfc_exit(ipu);
+-err_dmfc:
+-      ipu_dc_exit(ipu);
+-err_dc:
+-      ipu_di_exit(ipu, 1);
+-err_di_1:
+-      ipu_di_exit(ipu, 0);
+-err_di_0:
+-      ipu_image_convert_exit(ipu);
+-err_image_convert:
+-      ipu_vdi_exit(ipu);
+-err_vdi:
+-      ipu_ic_exit(ipu);
+-err_ic:
+-      ipu_csi_exit(ipu, 1);
+-err_csi_1:
+-      ipu_csi_exit(ipu, 0);
+-err_csi_0:
+-      ipu_cpmem_exit(ipu);
+-err_cpmem:
+-      dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
+-      return ret;
+-}
+-
+-static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs)
+-{
+-      unsigned long status;
+-      int i, bit, irq;
+-
+-      for (i = 0; i < num_regs; i++) {
+-
+-              status = ipu_cm_read(ipu, IPU_INT_STAT(regs[i]));
+-              status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i]));
+-
+-              for_each_set_bit(bit, &status, 32) {
+-                      irq = irq_linear_revmap(ipu->domain,
+-                                              regs[i] * 32 + bit);
+-                      if (irq)
+-                              generic_handle_irq(irq);
+-              }
+-      }
+-}
+-
+-static void ipu_irq_handler(struct irq_desc *desc)
+-{
+-      struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
+-      struct irq_chip *chip = irq_desc_get_chip(desc);
+-      static const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
+-
+-      chained_irq_enter(chip, desc);
+-
+-      ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
+-
+-      chained_irq_exit(chip, desc);
+-}
+-
+-static void ipu_err_irq_handler(struct irq_desc *desc)
+-{
+-      struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
+-      struct irq_chip *chip = irq_desc_get_chip(desc);
+-      static const int int_reg[] = { 4, 5, 8, 9};
+-
+-      chained_irq_enter(chip, desc);
+-
+-      ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
+-
+-      chained_irq_exit(chip, desc);
+-}
+-
+-int ipu_map_irq(struct ipu_soc *ipu, int irq)
+-{
+-      int virq;
+-
+-      virq = irq_linear_revmap(ipu->domain, irq);
+-      if (!virq)
+-              virq = irq_create_mapping(ipu->domain, irq);
+-
+-      return virq;
+-}
+-EXPORT_SYMBOL_GPL(ipu_map_irq);
+-
+-int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
+-              enum ipu_channel_irq irq_type)
+-{
+-      return ipu_map_irq(ipu, irq_type + channel->num);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq);
+-
+-static void ipu_submodules_exit(struct ipu_soc *ipu)
+-{
+-      ipu_smfc_exit(ipu);
+-      ipu_dp_exit(ipu);
+-      ipu_dmfc_exit(ipu);
+-      ipu_dc_exit(ipu);
+-      ipu_di_exit(ipu, 1);
+-      ipu_di_exit(ipu, 0);
+-      ipu_image_convert_exit(ipu);
+-      ipu_vdi_exit(ipu);
+-      ipu_ic_exit(ipu);
+-      ipu_csi_exit(ipu, 1);
+-      ipu_csi_exit(ipu, 0);
+-      ipu_cpmem_exit(ipu);
+-}
+-
+-static int platform_remove_devices_fn(struct device *dev, void *unused)
+-{
+-      struct platform_device *pdev = to_platform_device(dev);
+-
+-      platform_device_unregister(pdev);
+-
+-      return 0;
+-}
+-
+-static void platform_device_unregister_children(struct platform_device *pdev)
+-{
+-      device_for_each_child(&pdev->dev, NULL, platform_remove_devices_fn);
+-}
+-
+-struct ipu_platform_reg {
+-      struct ipu_client_platformdata pdata;
+-      const char *name;
+-};
+-
+-/* These must be in the order of the corresponding device tree port nodes */
+-static struct ipu_platform_reg client_reg[] = {
+-      {
+-              .pdata = {
+-                      .csi = 0,
+-                      .dma[0] = IPUV3_CHANNEL_CSI0,
+-                      .dma[1] = -EINVAL,
+-              },
+-              .name = "imx-ipuv3-csi",
+-      }, {
+-              .pdata = {
+-                      .csi = 1,
+-                      .dma[0] = IPUV3_CHANNEL_CSI1,
+-                      .dma[1] = -EINVAL,
+-              },
+-              .name = "imx-ipuv3-csi",
+-      }, {
+-              .pdata = {
+-                      .di = 0,
+-                      .dc = 5,
+-                      .dp = IPU_DP_FLOW_SYNC_BG,
+-                      .dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC,
+-                      .dma[1] = IPUV3_CHANNEL_MEM_FG_SYNC,
+-              },
+-              .name = "imx-ipuv3-crtc",
+-      }, {
+-              .pdata = {
+-                      .di = 1,
+-                      .dc = 1,
+-                      .dp = -EINVAL,
+-                      .dma[0] = IPUV3_CHANNEL_MEM_DC_SYNC,
+-                      .dma[1] = -EINVAL,
+-              },
+-              .name = "imx-ipuv3-crtc",
+-      },
+-};
+-
+-static DEFINE_MUTEX(ipu_client_id_mutex);
+-static int ipu_client_id;
+-
+-static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
+-{
+-      struct device *dev = ipu->dev;
+-      unsigned i;
+-      int id, ret;
+-
+-      mutex_lock(&ipu_client_id_mutex);
+-      id = ipu_client_id;
+-      ipu_client_id += ARRAY_SIZE(client_reg);
+-      mutex_unlock(&ipu_client_id_mutex);
+-
+-      for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
+-              struct ipu_platform_reg *reg = &client_reg[i];
+-              struct platform_device *pdev;
+-              struct device_node *of_node;
+-
+-              /* Associate subdevice with the corresponding port node */
+-              of_node = of_graph_get_port_by_id(dev->of_node, i);
+-              if (!of_node) {
+-                      dev_info(dev,
+-                               "no port@%d node in %pOF, not using %s%d\n",
+-                               i, dev->of_node,
+-                               (i / 2) ? "DI" : "CSI", i % 2);
+-                      continue;
+-              }
+-
+-              pdev = platform_device_alloc(reg->name, id++);
+-              if (!pdev) {
+-                      ret = -ENOMEM;
+-                      goto err_register;
+-              }
+-
+-              pdev->dev.parent = dev;
+-
+-              reg->pdata.of_node = of_node;
+-              ret = platform_device_add_data(pdev, &reg->pdata,
+-                                             sizeof(reg->pdata));
+-              if (!ret)
+-                      ret = platform_device_add(pdev);
+-              if (ret) {
+-                      platform_device_put(pdev);
+-                      goto err_register;
+-              }
+-      }
+-
+-      return 0;
+-
+-err_register:
+-      platform_device_unregister_children(to_platform_device(dev));
+-
+-      return ret;
+-}
+-
+-
+-static int ipu_irq_init(struct ipu_soc *ipu)
+-{
+-      struct irq_chip_generic *gc;
+-      struct irq_chip_type *ct;
+-      unsigned long unused[IPU_NUM_IRQS / 32] = {
+-              0x400100d0, 0xffe000fd,
+-              0x400100d0, 0xffe000fd,
+-              0x400100d0, 0xffe000fd,
+-              0x4077ffff, 0xffe7e1fd,
+-              0x23fffffe, 0x8880fff0,
+-              0xf98fe7d0, 0xfff81fff,
+-              0x400100d0, 0xffe000fd,
+-              0x00000000,
+-      };
+-      int ret, i;
+-
+-      ipu->domain = irq_domain_add_linear(ipu->dev->of_node, IPU_NUM_IRQS,
+-                                          &irq_generic_chip_ops, ipu);
+-      if (!ipu->domain) {
+-              dev_err(ipu->dev, "failed to add irq domain\n");
+-              return -ENODEV;
+-      }
+-
+-      ret = irq_alloc_domain_generic_chips(ipu->domain, 32, 1, "IPU",
+-                                           handle_level_irq, 0, 0, 0);
+-      if (ret < 0) {
+-              dev_err(ipu->dev, "failed to alloc generic irq chips\n");
+-              irq_domain_remove(ipu->domain);
+-              return ret;
+-      }
+-
+-      /* Mask and clear all interrupts */
+-      for (i = 0; i < IPU_NUM_IRQS; i += 32) {
+-              ipu_cm_write(ipu, 0, IPU_INT_CTRL(i / 32));
+-              ipu_cm_write(ipu, ~unused[i / 32], IPU_INT_STAT(i / 32));
+-      }
+-
+-      for (i = 0; i < IPU_NUM_IRQS; i += 32) {
+-              gc = irq_get_domain_generic_chip(ipu->domain, i);
+-              gc->reg_base = ipu->cm_reg;
+-              gc->unused = unused[i / 32];
+-              ct = gc->chip_types;
+-              ct->chip.irq_ack = irq_gc_ack_set_bit;
+-              ct->chip.irq_mask = irq_gc_mask_clr_bit;
+-              ct->chip.irq_unmask = irq_gc_mask_set_bit;
+-              ct->regs.ack = IPU_INT_STAT(i / 32);
+-              ct->regs.mask = IPU_INT_CTRL(i / 32);
+-      }
+-
+-      irq_set_chained_handler_and_data(ipu->irq_sync, ipu_irq_handler, ipu);
+-      irq_set_chained_handler_and_data(ipu->irq_err, ipu_err_irq_handler,
+-                                       ipu);
+-
+-      return 0;
+-}
+-
+-static void ipu_irq_exit(struct ipu_soc *ipu)
+-{
+-      int i, irq;
+-
+-      irq_set_chained_handler_and_data(ipu->irq_err, NULL, NULL);
+-      irq_set_chained_handler_and_data(ipu->irq_sync, NULL, NULL);
+-
+-      /* TODO: remove irq_domain_generic_chips */
+-
+-      for (i = 0; i < IPU_NUM_IRQS; i++) {
+-              irq = irq_linear_revmap(ipu->domain, i);
+-              if (irq)
+-                      irq_dispose_mapping(irq);
+-      }
+-
+-      irq_domain_remove(ipu->domain);
+-}
+-
+-void ipu_dump(struct ipu_soc *ipu)
+-{
+-      int i;
+-
+-      dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n",
+-              ipu_cm_read(ipu, IPU_CONF));
+-      dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n",
+-              ipu_idmac_read(ipu, IDMAC_CONF));
+-      dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n",
+-              ipu_idmac_read(ipu, IDMAC_CHA_EN(0)));
+-      dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n",
+-              ipu_idmac_read(ipu, IDMAC_CHA_EN(32)));
+-      dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n",
+-              ipu_idmac_read(ipu, IDMAC_CHA_PRI(0)));
+-      dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n",
+-              ipu_idmac_read(ipu, IDMAC_CHA_PRI(32)));
+-      dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n",
+-              ipu_idmac_read(ipu, IDMAC_BAND_EN(0)));
+-      dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n",
+-              ipu_idmac_read(ipu, IDMAC_BAND_EN(32)));
+-      dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
+-              ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0)));
+-      dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
+-              ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32)));
+-      dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n",
+-              ipu_cm_read(ipu, IPU_FS_PROC_FLOW1));
+-      dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n",
+-              ipu_cm_read(ipu, IPU_FS_PROC_FLOW2));
+-      dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n",
+-              ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
+-      dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
+-              ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
+-      for (i = 0; i < 15; i++)
+-              dev_dbg(ipu->dev, "IPU_INT_CTRL(%d) = \t%08X\n", i,
+-                      ipu_cm_read(ipu, IPU_INT_CTRL(i)));
+-}
+-EXPORT_SYMBOL_GPL(ipu_dump);
+-
+-static int ipu_probe(struct platform_device *pdev)
+-{
+-      struct device_node *np = pdev->dev.of_node;
+-      struct ipu_soc *ipu;
+-      struct resource *res;
+-      unsigned long ipu_base;
+-      int ret, irq_sync, irq_err;
+-      const struct ipu_devtype *devtype;
+-
+-      devtype = of_device_get_match_data(&pdev->dev);
+-      if (!devtype)
+-              return -EINVAL;
+-
+-      irq_sync = platform_get_irq(pdev, 0);
+-      irq_err = platform_get_irq(pdev, 1);
+-      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-
+-      dev_dbg(&pdev->dev, "irq_sync: %d irq_err: %d\n",
+-                      irq_sync, irq_err);
+-
+-      if (!res || irq_sync < 0 || irq_err < 0)
+-              return -ENODEV;
+-
+-      ipu_base = res->start;
+-
+-      ipu = devm_kzalloc(&pdev->dev, sizeof(*ipu), GFP_KERNEL);
+-      if (!ipu)
+-              return -ENODEV;
+-
+-      ipu->id = of_alias_get_id(np, "ipu");
+-      if (ipu->id < 0)
+-              ipu->id = 0;
+-
+-      if (of_device_is_compatible(np, "fsl,imx6qp-ipu") &&
+-          IS_ENABLED(CONFIG_DRM)) {
+-              ipu->prg_priv = ipu_prg_lookup_by_phandle(&pdev->dev,
+-                                                        "fsl,prg", ipu->id);
+-              if (!ipu->prg_priv)
+-                      return -EPROBE_DEFER;
+-      }
+-
+-      ipu->devtype = devtype;
+-      ipu->ipu_type = devtype->type;
+-
+-      spin_lock_init(&ipu->lock);
+-      mutex_init(&ipu->channel_lock);
+-      INIT_LIST_HEAD(&ipu->channels);
+-
+-      dev_dbg(&pdev->dev, "cm_reg:   0x%08lx\n",
+-                      ipu_base + devtype->cm_ofs);
+-      dev_dbg(&pdev->dev, "idmac:    0x%08lx\n",
+-                      ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS);
+-      dev_dbg(&pdev->dev, "cpmem:    0x%08lx\n",
+-                      ipu_base + devtype->cpmem_ofs);
+-      dev_dbg(&pdev->dev, "csi0:    0x%08lx\n",
+-                      ipu_base + devtype->csi0_ofs);
+-      dev_dbg(&pdev->dev, "csi1:    0x%08lx\n",
+-                      ipu_base + devtype->csi1_ofs);
+-      dev_dbg(&pdev->dev, "ic:      0x%08lx\n",
+-                      ipu_base + devtype->ic_ofs);
+-      dev_dbg(&pdev->dev, "disp0:    0x%08lx\n",
+-                      ipu_base + devtype->disp0_ofs);
+-      dev_dbg(&pdev->dev, "disp1:    0x%08lx\n",
+-                      ipu_base + devtype->disp1_ofs);
+-      dev_dbg(&pdev->dev, "srm:      0x%08lx\n",
+-                      ipu_base + devtype->srm_ofs);
+-      dev_dbg(&pdev->dev, "tpm:      0x%08lx\n",
+-                      ipu_base + devtype->tpm_ofs);
+-      dev_dbg(&pdev->dev, "dc:       0x%08lx\n",
+-                      ipu_base + devtype->cm_ofs + IPU_CM_DC_REG_OFS);
+-      dev_dbg(&pdev->dev, "ic:       0x%08lx\n",
+-                      ipu_base + devtype->cm_ofs + IPU_CM_IC_REG_OFS);
+-      dev_dbg(&pdev->dev, "dmfc:     0x%08lx\n",
+-                      ipu_base + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS);
+-      dev_dbg(&pdev->dev, "vdi:      0x%08lx\n",
+-                      ipu_base + devtype->vdi_ofs);
+-
+-      ipu->cm_reg = devm_ioremap(&pdev->dev,
+-                      ipu_base + devtype->cm_ofs, PAGE_SIZE);
+-      ipu->idmac_reg = devm_ioremap(&pdev->dev,
+-                      ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS,
+-                      PAGE_SIZE);
+-
+-      if (!ipu->cm_reg || !ipu->idmac_reg)
+-              return -ENOMEM;
+-
+-      ipu->clk = devm_clk_get(&pdev->dev, "bus");
+-      if (IS_ERR(ipu->clk)) {
+-              ret = PTR_ERR(ipu->clk);
+-              dev_err(&pdev->dev, "clk_get failed with %d", ret);
+-              return ret;
+-      }
+-
+-      platform_set_drvdata(pdev, ipu);
+-
+-      ret = clk_prepare_enable(ipu->clk);
+-      if (ret) {
+-              dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
+-              return ret;
+-      }
+-
+-      ipu->dev = &pdev->dev;
+-      ipu->irq_sync = irq_sync;
+-      ipu->irq_err = irq_err;
+-
+-      ret = device_reset(&pdev->dev);
+-      if (ret) {
+-              dev_err(&pdev->dev, "failed to reset: %d\n", ret);
+-              goto out_failed_reset;
+-      }
+-      ret = ipu_memory_reset(ipu);
+-      if (ret)
+-              goto out_failed_reset;
+-
+-      ret = ipu_irq_init(ipu);
+-      if (ret)
+-              goto out_failed_irq;
+-
+-      /* Set MCU_T to divide MCU access window into 2 */
+-      ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
+-                      IPU_DISP_GEN);
+-
+-      ret = ipu_submodules_init(ipu, pdev, ipu_base, ipu->clk);
+-      if (ret)
+-              goto failed_submodules_init;
+-
+-      ret = ipu_add_client_devices(ipu, ipu_base);
+-      if (ret) {
+-              dev_err(&pdev->dev, "adding client devices failed with %d\n",
+-                              ret);
+-              goto failed_add_clients;
+-      }
+-
+-      dev_info(&pdev->dev, "%s probed\n", devtype->name);
+-
+-      return 0;
+-
+-failed_add_clients:
+-      ipu_submodules_exit(ipu);
+-failed_submodules_init:
+-      ipu_irq_exit(ipu);
+-out_failed_irq:
+-out_failed_reset:
+-      clk_disable_unprepare(ipu->clk);
+-      return ret;
+-}
+-
+-static int ipu_remove(struct platform_device *pdev)
+-{
+-      struct ipu_soc *ipu = platform_get_drvdata(pdev);
+-
+-      platform_device_unregister_children(pdev);
+-      ipu_submodules_exit(ipu);
+-      ipu_irq_exit(ipu);
+-
+-      clk_disable_unprepare(ipu->clk);
+-
+-      return 0;
+-}
+-
+-static struct platform_driver imx_ipu_driver = {
+-      .driver = {
+-              .name = "imx-ipuv3",
+-              .of_match_table = imx_ipu_dt_ids,
+-      },
+-      .probe = ipu_probe,
+-      .remove = ipu_remove,
+-};
+-
+-static struct platform_driver * const drivers[] = {
+-#if IS_ENABLED(CONFIG_DRM)
+-      &ipu_pre_drv,
+-      &ipu_prg_drv,
+-#endif
+-      &imx_ipu_driver,
+-};
+-
+-static int __init imx_ipu_init(void)
+-{
+-      return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
+-}
+-module_init(imx_ipu_init);
+-
+-static void __exit imx_ipu_exit(void)
+-{
+-      platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
+-}
+-module_exit(imx_ipu_exit);
+-
+-MODULE_ALIAS("platform:imx-ipuv3");
+-MODULE_DESCRIPTION("i.MX IPU v3 driver");
+-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+-MODULE_LICENSE("GPL");
+--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
++++ /dev/null
+@@ -1,976 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (C) 2012 Mentor Graphics Inc.
+- * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+- */
+-#include <linux/types.h>
+-#include <linux/bitrev.h>
+-#include <linux/io.h>
+-#include <linux/sizes.h>
+-#include <drm/drm_fourcc.h>
+-#include "ipu-prv.h"
+-
+-struct ipu_cpmem_word {
+-      u32 data[5];
+-      u32 res[3];
+-};
+-
+-struct ipu_ch_param {
+-      struct ipu_cpmem_word word[2];
+-};
+-
+-struct ipu_cpmem {
+-      struct ipu_ch_param __iomem *base;
+-      u32 module;
+-      spinlock_t lock;
+-      int use_count;
+-      struct ipu_soc *ipu;
+-};
+-
+-#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
+-
+-#define IPU_FIELD_UBO         IPU_CPMEM_WORD(0, 46, 22)
+-#define IPU_FIELD_VBO         IPU_CPMEM_WORD(0, 68, 22)
+-#define IPU_FIELD_IOX         IPU_CPMEM_WORD(0, 90, 4)
+-#define IPU_FIELD_RDRW                IPU_CPMEM_WORD(0, 94, 1)
+-#define IPU_FIELD_SO          IPU_CPMEM_WORD(0, 113, 1)
+-#define IPU_FIELD_SLY         IPU_CPMEM_WORD(1, 102, 14)
+-#define IPU_FIELD_SLUV                IPU_CPMEM_WORD(1, 128, 14)
+-
+-#define IPU_FIELD_XV          IPU_CPMEM_WORD(0, 0, 10)
+-#define IPU_FIELD_YV          IPU_CPMEM_WORD(0, 10, 9)
+-#define IPU_FIELD_XB          IPU_CPMEM_WORD(0, 19, 13)
+-#define IPU_FIELD_YB          IPU_CPMEM_WORD(0, 32, 12)
+-#define IPU_FIELD_NSB_B               IPU_CPMEM_WORD(0, 44, 1)
+-#define IPU_FIELD_CF          IPU_CPMEM_WORD(0, 45, 1)
+-#define IPU_FIELD_SX          IPU_CPMEM_WORD(0, 46, 12)
+-#define IPU_FIELD_SY          IPU_CPMEM_WORD(0, 58, 11)
+-#define IPU_FIELD_NS          IPU_CPMEM_WORD(0, 69, 10)
+-#define IPU_FIELD_SDX         IPU_CPMEM_WORD(0, 79, 7)
+-#define IPU_FIELD_SM          IPU_CPMEM_WORD(0, 86, 10)
+-#define IPU_FIELD_SCC         IPU_CPMEM_WORD(0, 96, 1)
+-#define IPU_FIELD_SCE         IPU_CPMEM_WORD(0, 97, 1)
+-#define IPU_FIELD_SDY         IPU_CPMEM_WORD(0, 98, 7)
+-#define IPU_FIELD_SDRX                IPU_CPMEM_WORD(0, 105, 1)
+-#define IPU_FIELD_SDRY                IPU_CPMEM_WORD(0, 106, 1)
+-#define IPU_FIELD_BPP         IPU_CPMEM_WORD(0, 107, 3)
+-#define IPU_FIELD_DEC_SEL     IPU_CPMEM_WORD(0, 110, 2)
+-#define IPU_FIELD_DIM         IPU_CPMEM_WORD(0, 112, 1)
+-#define IPU_FIELD_BNDM                IPU_CPMEM_WORD(0, 114, 3)
+-#define IPU_FIELD_BM          IPU_CPMEM_WORD(0, 117, 2)
+-#define IPU_FIELD_ROT         IPU_CPMEM_WORD(0, 119, 1)
+-#define IPU_FIELD_ROT_HF_VF   IPU_CPMEM_WORD(0, 119, 3)
+-#define IPU_FIELD_HF          IPU_CPMEM_WORD(0, 120, 1)
+-#define IPU_FIELD_VF          IPU_CPMEM_WORD(0, 121, 1)
+-#define IPU_FIELD_THE         IPU_CPMEM_WORD(0, 122, 1)
+-#define IPU_FIELD_CAP         IPU_CPMEM_WORD(0, 123, 1)
+-#define IPU_FIELD_CAE         IPU_CPMEM_WORD(0, 124, 1)
+-#define IPU_FIELD_FW          IPU_CPMEM_WORD(0, 125, 13)
+-#define IPU_FIELD_FH          IPU_CPMEM_WORD(0, 138, 12)
+-#define IPU_FIELD_EBA0                IPU_CPMEM_WORD(1, 0, 29)
+-#define IPU_FIELD_EBA1                IPU_CPMEM_WORD(1, 29, 29)
+-#define IPU_FIELD_ILO         IPU_CPMEM_WORD(1, 58, 20)
+-#define IPU_FIELD_NPB         IPU_CPMEM_WORD(1, 78, 7)
+-#define IPU_FIELD_PFS         IPU_CPMEM_WORD(1, 85, 4)
+-#define IPU_FIELD_ALU         IPU_CPMEM_WORD(1, 89, 1)
+-#define IPU_FIELD_ALBM                IPU_CPMEM_WORD(1, 90, 3)
+-#define IPU_FIELD_ID          IPU_CPMEM_WORD(1, 93, 2)
+-#define IPU_FIELD_TH          IPU_CPMEM_WORD(1, 95, 7)
+-#define IPU_FIELD_SL          IPU_CPMEM_WORD(1, 102, 14)
+-#define IPU_FIELD_WID0                IPU_CPMEM_WORD(1, 116, 3)
+-#define IPU_FIELD_WID1                IPU_CPMEM_WORD(1, 119, 3)
+-#define IPU_FIELD_WID2                IPU_CPMEM_WORD(1, 122, 3)
+-#define IPU_FIELD_WID3                IPU_CPMEM_WORD(1, 125, 3)
+-#define IPU_FIELD_OFS0                IPU_CPMEM_WORD(1, 128, 5)
+-#define IPU_FIELD_OFS1                IPU_CPMEM_WORD(1, 133, 5)
+-#define IPU_FIELD_OFS2                IPU_CPMEM_WORD(1, 138, 5)
+-#define IPU_FIELD_OFS3                IPU_CPMEM_WORD(1, 143, 5)
+-#define IPU_FIELD_SXYS                IPU_CPMEM_WORD(1, 148, 1)
+-#define IPU_FIELD_CRE         IPU_CPMEM_WORD(1, 149, 1)
+-#define IPU_FIELD_DEC_SEL2    IPU_CPMEM_WORD(1, 150, 1)
+-
+-static inline struct ipu_ch_param __iomem *
+-ipu_get_cpmem(struct ipuv3_channel *ch)
+-{
+-      struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv;
+-
+-      return cpmem->base + ch->num;
+-}
+-
+-static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v)
+-{
+-      struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
+-      u32 bit = (wbs >> 8) % 160;
+-      u32 size = wbs & 0xff;
+-      u32 word = (wbs >> 8) / 160;
+-      u32 i = bit / 32;
+-      u32 ofs = bit % 32;
+-      u32 mask = (1 << size) - 1;
+-      u32 val;
+-
+-      pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+-
+-      val = readl(&base->word[word].data[i]);
+-      val &= ~(mask << ofs);
+-      val |= v << ofs;
+-      writel(val, &base->word[word].data[i]);
+-
+-      if ((bit + size - 1) / 32 > i) {
+-              val = readl(&base->word[word].data[i + 1]);
+-              val &= ~(mask >> (ofs ? (32 - ofs) : 0));
+-              val |= v >> (ofs ? (32 - ofs) : 0);
+-              writel(val, &base->word[word].data[i + 1]);
+-      }
+-}
+-
+-static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs)
+-{
+-      struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
+-      u32 bit = (wbs >> 8) % 160;
+-      u32 size = wbs & 0xff;
+-      u32 word = (wbs >> 8) / 160;
+-      u32 i = bit / 32;
+-      u32 ofs = bit % 32;
+-      u32 mask = (1 << size) - 1;
+-      u32 val = 0;
+-
+-      pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+-
+-      val = (readl(&base->word[word].data[i]) >> ofs) & mask;
+-
+-      if ((bit + size - 1) / 32 > i) {
+-              u32 tmp;
+-
+-              tmp = readl(&base->word[word].data[i + 1]);
+-              tmp &= mask >> (ofs ? (32 - ofs) : 0);
+-              val |= tmp << (ofs ? (32 - ofs) : 0);
+-      }
+-
+-      return val;
+-}
+-
+-/*
+- * The V4L2 spec defines packed RGB formats in memory byte order, which from
+- * point of view of the IPU corresponds to little-endian words with the first
+- * component in the least significant bits.
+- * The DRM pixel formats and IPU internal representation are ordered the other
+- * way around, with the first named component ordered at the most significant
+- * bits. Further, V4L2 formats are not well defined:
+- *     https://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
+- * We choose the interpretation which matches GStreamer behavior.
+- */
+-static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
+-{
+-      switch (pixelformat) {
+-      case V4L2_PIX_FMT_RGB565:
+-              /*
+-               * Here we choose the 'corrected' interpretation of RGBP, a
+-               * little-endian 16-bit word with the red component at the most
+-               * significant bits:
+-               * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
+-               */
+-              return DRM_FORMAT_RGB565;
+-      case V4L2_PIX_FMT_BGR24:
+-              /* B G R <=> [24:0] R:G:B */
+-              return DRM_FORMAT_RGB888;
+-      case V4L2_PIX_FMT_RGB24:
+-              /* R G B <=> [24:0] B:G:R */
+-              return DRM_FORMAT_BGR888;
+-      case V4L2_PIX_FMT_BGR32:
+-              /* B G R A <=> [32:0] A:B:G:R */
+-              return DRM_FORMAT_XRGB8888;
+-      case V4L2_PIX_FMT_RGB32:
+-              /* R G B A <=> [32:0] A:B:G:R */
+-              return DRM_FORMAT_XBGR8888;
+-      case V4L2_PIX_FMT_ABGR32:
+-              /* B G R A <=> [32:0] A:R:G:B */
+-              return DRM_FORMAT_ARGB8888;
+-      case V4L2_PIX_FMT_XBGR32:
+-              /* B G R X <=> [32:0] X:R:G:B */
+-              return DRM_FORMAT_XRGB8888;
+-      case V4L2_PIX_FMT_BGRA32:
+-              /* A B G R <=> [32:0] R:G:B:A */
+-              return DRM_FORMAT_RGBA8888;
+-      case V4L2_PIX_FMT_BGRX32:
+-              /* X B G R <=> [32:0] R:G:B:X */
+-              return DRM_FORMAT_RGBX8888;
+-      case V4L2_PIX_FMT_RGBA32:
+-              /* R G B A <=> [32:0] A:B:G:R */
+-              return DRM_FORMAT_ABGR8888;
+-      case V4L2_PIX_FMT_RGBX32:
+-              /* R G B X <=> [32:0] X:B:G:R */
+-              return DRM_FORMAT_XBGR8888;
+-      case V4L2_PIX_FMT_ARGB32:
+-              /* A R G B <=> [32:0] B:G:R:A */
+-              return DRM_FORMAT_BGRA8888;
+-      case V4L2_PIX_FMT_XRGB32:
+-              /* X R G B <=> [32:0] B:G:R:X */
+-              return DRM_FORMAT_BGRX8888;
+-      case V4L2_PIX_FMT_UYVY:
+-              return DRM_FORMAT_UYVY;
+-      case V4L2_PIX_FMT_YUYV:
+-              return DRM_FORMAT_YUYV;
+-      case V4L2_PIX_FMT_YUV420:
+-              return DRM_FORMAT_YUV420;
+-      case V4L2_PIX_FMT_YUV422P:
+-              return DRM_FORMAT_YUV422;
+-      case V4L2_PIX_FMT_YVU420:
+-              return DRM_FORMAT_YVU420;
+-      case V4L2_PIX_FMT_NV12:
+-              return DRM_FORMAT_NV12;
+-      case V4L2_PIX_FMT_NV16:
+-              return DRM_FORMAT_NV16;
+-      }
+-
+-      return -EINVAL;
+-}
+-
+-void ipu_cpmem_zero(struct ipuv3_channel *ch)
+-{
+-      struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
+-      void __iomem *base = p;
+-      int i;
+-
+-      for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
+-              writel(0, base + i * sizeof(u32));
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
+-
+-void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres)
+-{
+-      ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
+-
+-void ipu_cpmem_skip_odd_chroma_rows(struct ipuv3_channel *ch)
+-{
+-      ipu_ch_param_write_field(ch, IPU_FIELD_RDRW, 1);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_skip_odd_chroma_rows);
+-
+-void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
+-{
+-      ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
+-
+-void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch)
+-{
+-      struct ipu_soc *ipu = ch->ipu;
+-      u32 val;
+-
+-      if (ipu->ipu_type == IPUV3EX)
+-              ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1);
+-
+-      val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num));
+-      val |= 1 << (ch->num % 32);
+-      ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num));
+-};
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
+-
+-void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
+-{
+-      WARN_ON_ONCE(buf & 0x7);
+-
+-      if (bufnum)
+-              ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
+-      else
+-              ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
+-
+-void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
+-{
+-      WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7));
+-
+-      ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
+-
+-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+-                             u32 pixelformat)
+-{
+-      u32 ilo, sly, sluv;
+-
+-      if (stride < 0) {
+-              stride = -stride;
+-              ilo = 0x100000 - (stride / 8);
+-      } else {
+-              ilo = stride / 8;
+-      }
+-
+-      sly = (stride * 2) - 1;
+-
+-      switch (pixelformat) {
+-      case V4L2_PIX_FMT_YUV420:
+-      case V4L2_PIX_FMT_YVU420:
+-              sluv = stride / 2 - 1;
+-              break;
+-      case V4L2_PIX_FMT_NV12:
+-              sluv = stride - 1;
+-              break;
+-      case V4L2_PIX_FMT_YUV422P:
+-              sluv = stride - 1;
+-              break;
+-      case V4L2_PIX_FMT_NV16:
+-              sluv = stride * 2 - 1;
+-              break;
+-      default:
+-              sluv = 0;
+-              break;
+-      }
+-
+-      ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
+-      if (sluv)
+-              ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
+-};
+-EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
+-
+-void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
+-{
+-      id &= 0x3;
+-      ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
+-
+-int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
+-{
+-      return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
+-
+-void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
+-{
+-      ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
+-};
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
+-
+-void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
+-{
+-      ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
+-
+-void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
+-                          enum ipu_rotate_mode rot)
+-{
+-      u32 temp_rot = bitrev8(rot) >> 5;
+-
+-      ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
+-
+-int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
+-                           const struct ipu_rgb *rgb)
+-{
+-      int bpp = 0, npb = 0, ro, go, bo, to;
+-
+-      ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
+-      go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
+-      bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
+-      to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
+-
+-      ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo);
+-
+-      if (rgb->transp.length) {
+-              ipu_ch_param_write_field(ch, IPU_FIELD_WID3,
+-                              rgb->transp.length - 1);
+-              ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to);
+-      } else {
+-              ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
+-              ipu_ch_param_write_field(ch, IPU_FIELD_OFS3,
+-                              rgb->bits_per_pixel);
+-      }
+-
+-      switch (rgb->bits_per_pixel) {
+-      case 32:
+-              bpp = 0;
+-              npb = 15;
+-              break;
+-      case 24:
+-              bpp = 1;
+-              npb = 19;
+-              break;
+-      case 16:
+-              bpp = 3;
+-              npb = 31;
+-              break;
+-      case 8:
+-              bpp = 5;
+-              npb = 63;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-      ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
+-
+-int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width)
+-{
+-      int bpp = 0, npb = 0;
+-
+-      switch (width) {
+-      case 32:
+-              bpp = 0;
+-              npb = 15;
+-              break;
+-      case 24:
+-              bpp = 1;
+-              npb = 19;
+-              break;
+-      case 16:
+-              bpp = 3;
+-              npb = 31;
+-              break;
+-      case 8:
+-              bpp = 5;
+-              npb = 63;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
+-
+-void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format)
+-{
+-      switch (pixel_format) {
+-      case V4L2_PIX_FMT_UYVY:
+-              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
+-              break;
+-      case V4L2_PIX_FMT_YUYV:
+-              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
+-              break;
+-      }
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
+-
+-void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
+-                                 unsigned int uv_stride,
+-                                 unsigned int u_offset, unsigned int v_offset)
+-{
+-      WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7));
+-
+-      ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
+-
+-static const struct ipu_rgb def_xrgb_32 = {
+-      .red    = { .offset = 16, .length = 8, },
+-      .green  = { .offset =  8, .length = 8, },
+-      .blue   = { .offset =  0, .length = 8, },
+-      .transp = { .offset = 24, .length = 8, },
+-      .bits_per_pixel = 32,
+-};
+-
+-static const struct ipu_rgb def_xbgr_32 = {
+-      .red    = { .offset =  0, .length = 8, },
+-      .green  = { .offset =  8, .length = 8, },
+-      .blue   = { .offset = 16, .length = 8, },
+-      .transp = { .offset = 24, .length = 8, },
+-      .bits_per_pixel = 32,
+-};
+-
+-static const struct ipu_rgb def_rgbx_32 = {
+-      .red    = { .offset = 24, .length = 8, },
+-      .green  = { .offset = 16, .length = 8, },
+-      .blue   = { .offset =  8, .length = 8, },
+-      .transp = { .offset =  0, .length = 8, },
+-      .bits_per_pixel = 32,
+-};
+-
+-static const struct ipu_rgb def_bgrx_32 = {
+-      .red    = { .offset =  8, .length = 8, },
+-      .green  = { .offset = 16, .length = 8, },
+-      .blue   = { .offset = 24, .length = 8, },
+-      .transp = { .offset =  0, .length = 8, },
+-      .bits_per_pixel = 32,
+-};
+-
+-static const struct ipu_rgb def_rgb_24 = {
+-      .red    = { .offset = 16, .length = 8, },
+-      .green  = { .offset =  8, .length = 8, },
+-      .blue   = { .offset =  0, .length = 8, },
+-      .transp = { .offset =  0, .length = 0, },
+-      .bits_per_pixel = 24,
+-};
+-
+-static const struct ipu_rgb def_bgr_24 = {
+-      .red    = { .offset =  0, .length = 8, },
+-      .green  = { .offset =  8, .length = 8, },
+-      .blue   = { .offset = 16, .length = 8, },
+-      .transp = { .offset =  0, .length = 0, },
+-      .bits_per_pixel = 24,
+-};
+-
+-static const struct ipu_rgb def_rgb_16 = {
+-      .red    = { .offset = 11, .length = 5, },
+-      .green  = { .offset =  5, .length = 6, },
+-      .blue   = { .offset =  0, .length = 5, },
+-      .transp = { .offset =  0, .length = 0, },
+-      .bits_per_pixel = 16,
+-};
+-
+-static const struct ipu_rgb def_bgr_16 = {
+-      .red    = { .offset =  0, .length = 5, },
+-      .green  = { .offset =  5, .length = 6, },
+-      .blue   = { .offset = 11, .length = 5, },
+-      .transp = { .offset =  0, .length = 0, },
+-      .bits_per_pixel = 16,
+-};
+-
+-static const struct ipu_rgb def_argb_16 = {
+-      .red    = { .offset = 10, .length = 5, },
+-      .green  = { .offset =  5, .length = 5, },
+-      .blue   = { .offset =  0, .length = 5, },
+-      .transp = { .offset = 15, .length = 1, },
+-      .bits_per_pixel = 16,
+-};
+-
+-static const struct ipu_rgb def_argb_16_4444 = {
+-      .red    = { .offset =  8, .length = 4, },
+-      .green  = { .offset =  4, .length = 4, },
+-      .blue   = { .offset =  0, .length = 4, },
+-      .transp = { .offset = 12, .length = 4, },
+-      .bits_per_pixel = 16,
+-};
+-
+-static const struct ipu_rgb def_abgr_16 = {
+-      .red    = { .offset =  0, .length = 5, },
+-      .green  = { .offset =  5, .length = 5, },
+-      .blue   = { .offset = 10, .length = 5, },
+-      .transp = { .offset = 15, .length = 1, },
+-      .bits_per_pixel = 16,
+-};
+-
+-static const struct ipu_rgb def_rgba_16 = {
+-      .red    = { .offset = 11, .length = 5, },
+-      .green  = { .offset =  6, .length = 5, },
+-      .blue   = { .offset =  1, .length = 5, },
+-      .transp = { .offset =  0, .length = 1, },
+-      .bits_per_pixel = 16,
+-};
+-
+-static const struct ipu_rgb def_bgra_16 = {
+-      .red    = { .offset =  1, .length = 5, },
+-      .green  = { .offset =  6, .length = 5, },
+-      .blue   = { .offset = 11, .length = 5, },
+-      .transp = { .offset =  0, .length = 1, },
+-      .bits_per_pixel = 16,
+-};
+-
+-#define Y_OFFSET(pix, x, y)   ((x) + pix->width * (y))
+-#define U_OFFSET(pix, x, y)   ((pix->width * pix->height) +           \
+-                               (pix->width * ((y) / 2) / 2) + (x) / 2)
+-#define V_OFFSET(pix, x, y)   ((pix->width * pix->height) +           \
+-                               (pix->width * pix->height / 4) +       \
+-                               (pix->width * ((y) / 2) / 2) + (x) / 2)
+-#define U2_OFFSET(pix, x, y)  ((pix->width * pix->height) +           \
+-                               (pix->width * (y) / 2) + (x) / 2)
+-#define V2_OFFSET(pix, x, y)  ((pix->width * pix->height) +           \
+-                               (pix->width * pix->height / 2) +       \
+-                               (pix->width * (y) / 2) + (x) / 2)
+-#define UV_OFFSET(pix, x, y)  ((pix->width * pix->height) +   \
+-                               (pix->width * ((y) / 2)) + (x))
+-#define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) +   \
+-                               (pix->width * y) + (x))
+-
+-#define NUM_ALPHA_CHANNELS    7
+-
+-/* See Table 37-12. Alpha channels mapping. */
+-static int ipu_channel_albm(int ch_num)
+-{
+-      switch (ch_num) {
+-      case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:     return 0;
+-      case IPUV3_CHANNEL_G_MEM_IC_PP:         return 1;
+-      case IPUV3_CHANNEL_MEM_FG_SYNC:         return 2;
+-      case IPUV3_CHANNEL_MEM_FG_ASYNC:        return 3;
+-      case IPUV3_CHANNEL_MEM_BG_SYNC:         return 4;
+-      case IPUV3_CHANNEL_MEM_BG_ASYNC:        return 5;
+-      case IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB: return 6;
+-      default:
+-              return -EINVAL;
+-      }
+-}
+-
+-static void ipu_cpmem_set_separate_alpha(struct ipuv3_channel *ch)
+-{
+-      struct ipu_soc *ipu = ch->ipu;
+-      int albm;
+-      u32 val;
+-
+-      albm = ipu_channel_albm(ch->num);
+-      if (albm < 0)
+-              return;
+-
+-      ipu_ch_param_write_field(ch, IPU_FIELD_ALU, 1);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_ALBM, albm);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_CRE, 1);
+-
+-      val = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
+-      val |= BIT(ch->num);
+-      ipu_idmac_write(ipu, val, IDMAC_SEP_ALPHA);
+-}
+-
+-int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
+-{
+-      switch (drm_fourcc) {
+-      case DRM_FORMAT_YUV420:
+-      case DRM_FORMAT_YVU420:
+-              /* pix format */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
+-              /* burst size */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+-              break;
+-      case DRM_FORMAT_YUV422:
+-      case DRM_FORMAT_YVU422:
+-              /* pix format */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
+-              /* burst size */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+-              break;
+-      case DRM_FORMAT_YUV444:
+-      case DRM_FORMAT_YVU444:
+-              /* pix format */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0);
+-              /* burst size */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+-              break;
+-      case DRM_FORMAT_NV12:
+-              /* pix format */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
+-              /* burst size */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+-              break;
+-      case DRM_FORMAT_NV16:
+-              /* pix format */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
+-              /* burst size */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+-              break;
+-      case DRM_FORMAT_UYVY:
+-              /* bits/pixel */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
+-              /* pix format */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
+-              /* burst size */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+-              break;
+-      case DRM_FORMAT_YUYV:
+-              /* bits/pixel */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
+-              /* pix format */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
+-              /* burst size */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+-              break;
+-      case DRM_FORMAT_ABGR8888:
+-      case DRM_FORMAT_XBGR8888:
+-              ipu_cpmem_set_format_rgb(ch, &def_xbgr_32);
+-              break;
+-      case DRM_FORMAT_ARGB8888:
+-      case DRM_FORMAT_XRGB8888:
+-              ipu_cpmem_set_format_rgb(ch, &def_xrgb_32);
+-              break;
+-      case DRM_FORMAT_RGBA8888:
+-      case DRM_FORMAT_RGBX8888:
+-      case DRM_FORMAT_RGBX8888_A8:
+-              ipu_cpmem_set_format_rgb(ch, &def_rgbx_32);
+-              break;
+-      case DRM_FORMAT_BGRA8888:
+-      case DRM_FORMAT_BGRX8888:
+-      case DRM_FORMAT_BGRX8888_A8:
+-              ipu_cpmem_set_format_rgb(ch, &def_bgrx_32);
+-              break;
+-      case DRM_FORMAT_BGR888:
+-      case DRM_FORMAT_BGR888_A8:
+-              ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
+-              break;
+-      case DRM_FORMAT_RGB888:
+-      case DRM_FORMAT_RGB888_A8:
+-              ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
+-              break;
+-      case DRM_FORMAT_RGB565:
+-      case DRM_FORMAT_RGB565_A8:
+-              ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
+-              break;
+-      case DRM_FORMAT_BGR565:
+-      case DRM_FORMAT_BGR565_A8:
+-              ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
+-              break;
+-      case DRM_FORMAT_ARGB1555:
+-              ipu_cpmem_set_format_rgb(ch, &def_argb_16);
+-              break;
+-      case DRM_FORMAT_ABGR1555:
+-              ipu_cpmem_set_format_rgb(ch, &def_abgr_16);
+-              break;
+-      case DRM_FORMAT_RGBA5551:
+-              ipu_cpmem_set_format_rgb(ch, &def_rgba_16);
+-              break;
+-      case DRM_FORMAT_BGRA5551:
+-              ipu_cpmem_set_format_rgb(ch, &def_bgra_16);
+-              break;
+-      case DRM_FORMAT_ARGB4444:
+-              ipu_cpmem_set_format_rgb(ch, &def_argb_16_4444);
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      switch (drm_fourcc) {
+-      case DRM_FORMAT_RGB565_A8:
+-      case DRM_FORMAT_BGR565_A8:
+-      case DRM_FORMAT_RGB888_A8:
+-      case DRM_FORMAT_BGR888_A8:
+-      case DRM_FORMAT_RGBX8888_A8:
+-      case DRM_FORMAT_BGRX8888_A8:
+-              ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
+-              ipu_cpmem_set_separate_alpha(ch);
+-              break;
+-      default:
+-              break;
+-      }
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
+-
+-int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
+-{
+-      struct v4l2_pix_format *pix = &image->pix;
+-      int offset, u_offset, v_offset;
+-      int ret = 0;
+-
+-      pr_debug("%s: resolution: %dx%d stride: %d\n",
+-               __func__, pix->width, pix->height,
+-               pix->bytesperline);
+-
+-      ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
+-      ipu_cpmem_set_stride(ch, pix->bytesperline);
+-
+-      ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
+-
+-      switch (pix->pixelformat) {
+-      case V4L2_PIX_FMT_YUV420:
+-              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+-              u_offset = image->u_offset ?
+-                      image->u_offset : U_OFFSET(pix, image->rect.left,
+-                                                 image->rect.top) - offset;
+-              v_offset = image->v_offset ?
+-                      image->v_offset : V_OFFSET(pix, image->rect.left,
+-                                                 image->rect.top) - offset;
+-
+-              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
+-                                            u_offset, v_offset);
+-              break;
+-      case V4L2_PIX_FMT_YVU420:
+-              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+-              u_offset = image->u_offset ?
+-                      image->u_offset : V_OFFSET(pix, image->rect.left,
+-                                                 image->rect.top) - offset;
+-              v_offset = image->v_offset ?
+-                      image->v_offset : U_OFFSET(pix, image->rect.left,
+-                                                 image->rect.top) - offset;
+-
+-              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
+-                                            u_offset, v_offset);
+-              break;
+-      case V4L2_PIX_FMT_YUV422P:
+-              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+-              u_offset = image->u_offset ?
+-                      image->u_offset : U2_OFFSET(pix, image->rect.left,
+-                                                  image->rect.top) - offset;
+-              v_offset = image->v_offset ?
+-                      image->v_offset : V2_OFFSET(pix, image->rect.left,
+-                                                  image->rect.top) - offset;
+-
+-              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
+-                                            u_offset, v_offset);
+-              break;
+-      case V4L2_PIX_FMT_NV12:
+-              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+-              u_offset = image->u_offset ?
+-                      image->u_offset : UV_OFFSET(pix, image->rect.left,
+-                                                  image->rect.top) - offset;
+-              v_offset = image->v_offset ? image->v_offset : 0;
+-
+-              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
+-                                            u_offset, v_offset);
+-              break;
+-      case V4L2_PIX_FMT_NV16:
+-              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+-              u_offset = image->u_offset ?
+-                      image->u_offset : UV2_OFFSET(pix, image->rect.left,
+-                                                   image->rect.top) - offset;
+-              v_offset = image->v_offset ? image->v_offset : 0;
+-
+-              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
+-                                            u_offset, v_offset);
+-              break;
+-      case V4L2_PIX_FMT_UYVY:
+-      case V4L2_PIX_FMT_YUYV:
+-      case V4L2_PIX_FMT_RGB565:
+-              offset = image->rect.left * 2 +
+-                      image->rect.top * pix->bytesperline;
+-              break;
+-      case V4L2_PIX_FMT_RGB32:
+-      case V4L2_PIX_FMT_BGR32:
+-      case V4L2_PIX_FMT_ABGR32:
+-      case V4L2_PIX_FMT_XBGR32:
+-      case V4L2_PIX_FMT_BGRA32:
+-      case V4L2_PIX_FMT_BGRX32:
+-      case V4L2_PIX_FMT_RGBA32:
+-      case V4L2_PIX_FMT_RGBX32:
+-      case V4L2_PIX_FMT_ARGB32:
+-      case V4L2_PIX_FMT_XRGB32:
+-              offset = image->rect.left * 4 +
+-                      image->rect.top * pix->bytesperline;
+-              break;
+-      case V4L2_PIX_FMT_RGB24:
+-      case V4L2_PIX_FMT_BGR24:
+-              offset = image->rect.left * 3 +
+-                      image->rect.top * pix->bytesperline;
+-              break;
+-      case V4L2_PIX_FMT_SBGGR8:
+-      case V4L2_PIX_FMT_SGBRG8:
+-      case V4L2_PIX_FMT_SGRBG8:
+-      case V4L2_PIX_FMT_SRGGB8:
+-      case V4L2_PIX_FMT_GREY:
+-              offset = image->rect.left + image->rect.top * pix->bytesperline;
+-              break;
+-      case V4L2_PIX_FMT_SBGGR16:
+-      case V4L2_PIX_FMT_SGBRG16:
+-      case V4L2_PIX_FMT_SGRBG16:
+-      case V4L2_PIX_FMT_SRGGB16:
+-      case V4L2_PIX_FMT_Y16:
+-              offset = image->rect.left * 2 +
+-                       image->rect.top * pix->bytesperline;
+-              break;
+-      default:
+-              /* This should not happen */
+-              WARN_ON(1);
+-              offset = 0;
+-              ret = -EINVAL;
+-      }
+-
+-      ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
+-      ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
+-
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
+-
+-void ipu_cpmem_dump(struct ipuv3_channel *ch)
+-{
+-      struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
+-      struct ipu_soc *ipu = ch->ipu;
+-      int chno = ch->num;
+-
+-      dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
+-              readl(&p->word[0].data[0]),
+-              readl(&p->word[0].data[1]),
+-              readl(&p->word[0].data[2]),
+-              readl(&p->word[0].data[3]),
+-              readl(&p->word[0].data[4]));
+-      dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
+-              readl(&p->word[1].data[0]),
+-              readl(&p->word[1].data[1]),
+-              readl(&p->word[1].data[2]),
+-              readl(&p->word[1].data[3]),
+-              readl(&p->word[1].data[4]));
+-      dev_dbg(ipu->dev, "PFS 0x%x, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
+-      dev_dbg(ipu->dev, "BPP 0x%x, ",
+-              ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
+-      dev_dbg(ipu->dev, "NPB 0x%x\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
+-
+-      dev_dbg(ipu->dev, "FW %d, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_FW));
+-      dev_dbg(ipu->dev, "FH %d, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_FH));
+-      dev_dbg(ipu->dev, "EBA0 0x%x\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
+-      dev_dbg(ipu->dev, "EBA1 0x%x\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
+-      dev_dbg(ipu->dev, "Stride %d\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_SL));
+-      dev_dbg(ipu->dev, "scan_order %d\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_SO));
+-      dev_dbg(ipu->dev, "uv_stride %d\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
+-      dev_dbg(ipu->dev, "u_offset 0x%x\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
+-      dev_dbg(ipu->dev, "v_offset 0x%x\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
+-
+-      dev_dbg(ipu->dev, "Width0 %d+1, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
+-      dev_dbg(ipu->dev, "Width1 %d+1, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
+-      dev_dbg(ipu->dev, "Width2 %d+1, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
+-      dev_dbg(ipu->dev, "Width3 %d+1, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
+-      dev_dbg(ipu->dev, "Offset0 %d, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
+-      dev_dbg(ipu->dev, "Offset1 %d, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
+-      dev_dbg(ipu->dev, "Offset2 %d, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
+-      dev_dbg(ipu->dev, "Offset3 %d\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
+-
+-int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
+-{
+-      struct ipu_cpmem *cpmem;
+-
+-      cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
+-      if (!cpmem)
+-              return -ENOMEM;
+-
+-      ipu->cpmem_priv = cpmem;
+-
+-      spin_lock_init(&cpmem->lock);
+-      cpmem->base = devm_ioremap(dev, base, SZ_128K);
+-      if (!cpmem->base)
+-              return -ENOMEM;
+-
+-      dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
+-              base, cpmem->base);
+-      cpmem->ipu = ipu;
+-
+-      return 0;
+-}
+-
+-void ipu_cpmem_exit(struct ipu_soc *ipu)
+-{
+-}
+--- a/drivers/gpu/ipu-v3/ipu-csi.c
++++ /dev/null
+@@ -1,821 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (C) 2012-2014 Mentor Graphics Inc.
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-#include <linux/export.h>
+-#include <linux/module.h>
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/delay.h>
+-#include <linux/io.h>
+-#include <linux/err.h>
+-#include <linux/platform_device.h>
+-#include <linux/videodev2.h>
+-#include <uapi/linux/v4l2-mediabus.h>
+-#include <linux/clk.h>
+-#include <linux/clk-provider.h>
+-#include <linux/clkdev.h>
+-
+-#include "ipu-prv.h"
+-
+-struct ipu_csi {
+-      void __iomem *base;
+-      int id;
+-      u32 module;
+-      struct clk *clk_ipu;    /* IPU bus clock */
+-      spinlock_t lock;
+-      bool inuse;
+-      struct ipu_soc *ipu;
+-};
+-
+-/* CSI Register Offsets */
+-#define CSI_SENS_CONF         0x0000
+-#define CSI_SENS_FRM_SIZE     0x0004
+-#define CSI_ACT_FRM_SIZE      0x0008
+-#define CSI_OUT_FRM_CTRL      0x000c
+-#define CSI_TST_CTRL          0x0010
+-#define CSI_CCIR_CODE_1               0x0014
+-#define CSI_CCIR_CODE_2               0x0018
+-#define CSI_CCIR_CODE_3               0x001c
+-#define CSI_MIPI_DI           0x0020
+-#define CSI_SKIP              0x0024
+-#define CSI_CPD_CTRL          0x0028
+-#define CSI_CPD_RC(n)         (0x002c + ((n)*4))
+-#define CSI_CPD_RS(n)         (0x004c + ((n)*4))
+-#define CSI_CPD_GRC(n)                (0x005c + ((n)*4))
+-#define CSI_CPD_GRS(n)                (0x007c + ((n)*4))
+-#define CSI_CPD_GBC(n)                (0x008c + ((n)*4))
+-#define CSI_CPD_GBS(n)                (0x00Ac + ((n)*4))
+-#define CSI_CPD_BC(n)         (0x00Bc + ((n)*4))
+-#define CSI_CPD_BS(n)         (0x00Dc + ((n)*4))
+-#define CSI_CPD_OFFSET1               0x00ec
+-#define CSI_CPD_OFFSET2               0x00f0
+-
+-/* CSI Register Fields */
+-#define CSI_SENS_CONF_DATA_FMT_SHIFT          8
+-#define CSI_SENS_CONF_DATA_FMT_MASK           0x00000700
+-#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444     0L
+-#define CSI_SENS_CONF_DATA_FMT_YUV422_YUYV    1L
+-#define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY    2L
+-#define CSI_SENS_CONF_DATA_FMT_BAYER          3L
+-#define CSI_SENS_CONF_DATA_FMT_RGB565         4L
+-#define CSI_SENS_CONF_DATA_FMT_RGB555         5L
+-#define CSI_SENS_CONF_DATA_FMT_RGB444         6L
+-#define CSI_SENS_CONF_DATA_FMT_JPEG           7L
+-
+-#define CSI_SENS_CONF_VSYNC_POL_SHIFT         0
+-#define CSI_SENS_CONF_HSYNC_POL_SHIFT         1
+-#define CSI_SENS_CONF_DATA_POL_SHIFT          2
+-#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT               3
+-#define CSI_SENS_CONF_SENS_PRTCL_MASK         0x00000070
+-#define CSI_SENS_CONF_SENS_PRTCL_SHIFT                4
+-#define CSI_SENS_CONF_PACK_TIGHT_SHIFT                7
+-#define CSI_SENS_CONF_DATA_WIDTH_SHIFT                11
+-#define CSI_SENS_CONF_EXT_VSYNC_SHIFT         15
+-#define CSI_SENS_CONF_DIVRATIO_SHIFT          16
+-
+-#define CSI_SENS_CONF_DIVRATIO_MASK           0x00ff0000
+-#define CSI_SENS_CONF_DATA_DEST_SHIFT         24
+-#define CSI_SENS_CONF_DATA_DEST_MASK          0x07000000
+-#define CSI_SENS_CONF_JPEG8_EN_SHIFT          27
+-#define CSI_SENS_CONF_JPEG_EN_SHIFT           28
+-#define CSI_SENS_CONF_FORCE_EOF_SHIFT         29
+-#define CSI_SENS_CONF_DATA_EN_POL_SHIFT               31
+-
+-#define CSI_DATA_DEST_IC                      2
+-#define CSI_DATA_DEST_IDMAC                   4
+-
+-#define CSI_CCIR_ERR_DET_EN                   0x01000000
+-#define CSI_HORI_DOWNSIZE_EN                  0x80000000
+-#define CSI_VERT_DOWNSIZE_EN                  0x40000000
+-#define CSI_TEST_GEN_MODE_EN                  0x01000000
+-
+-#define CSI_HSC_MASK                          0x1fff0000
+-#define CSI_HSC_SHIFT                         16
+-#define CSI_VSC_MASK                          0x00000fff
+-#define CSI_VSC_SHIFT                         0
+-
+-#define CSI_TEST_GEN_R_MASK                   0x000000ff
+-#define CSI_TEST_GEN_R_SHIFT                  0
+-#define CSI_TEST_GEN_G_MASK                   0x0000ff00
+-#define CSI_TEST_GEN_G_SHIFT                  8
+-#define CSI_TEST_GEN_B_MASK                   0x00ff0000
+-#define CSI_TEST_GEN_B_SHIFT                  16
+-
+-#define CSI_MAX_RATIO_SKIP_SMFC_MASK          0x00000007
+-#define CSI_MAX_RATIO_SKIP_SMFC_SHIFT         0
+-#define CSI_SKIP_SMFC_MASK                    0x000000f8
+-#define CSI_SKIP_SMFC_SHIFT                   3
+-#define CSI_ID_2_SKIP_MASK                    0x00000300
+-#define CSI_ID_2_SKIP_SHIFT                   8
+-
+-#define CSI_COLOR_FIRST_ROW_MASK              0x00000002
+-#define CSI_COLOR_FIRST_COMP_MASK             0x00000001
+-
+-/* MIPI CSI-2 data types */
+-#define MIPI_DT_YUV420                0x18 /* YYY.../UYVY.... */
+-#define MIPI_DT_YUV420_LEGACY 0x1a /* UYY.../VYY...   */
+-#define MIPI_DT_YUV422                0x1e /* UYVY...         */
+-#define MIPI_DT_RGB444                0x20
+-#define MIPI_DT_RGB555                0x21
+-#define MIPI_DT_RGB565                0x22
+-#define MIPI_DT_RGB666                0x23
+-#define MIPI_DT_RGB888                0x24
+-#define MIPI_DT_RAW6          0x28
+-#define MIPI_DT_RAW7          0x29
+-#define MIPI_DT_RAW8          0x2a
+-#define MIPI_DT_RAW10         0x2b
+-#define MIPI_DT_RAW12         0x2c
+-#define MIPI_DT_RAW14         0x2d
+-
+-/*
+- * Bitfield of CSI bus signal polarities and modes.
+- */
+-struct ipu_csi_bus_config {
+-      unsigned data_width:4;
+-      unsigned clk_mode:3;
+-      unsigned ext_vsync:1;
+-      unsigned vsync_pol:1;
+-      unsigned hsync_pol:1;
+-      unsigned pixclk_pol:1;
+-      unsigned data_pol:1;
+-      unsigned sens_clksrc:1;
+-      unsigned pack_tight:1;
+-      unsigned force_eof:1;
+-      unsigned data_en_pol:1;
+-
+-      unsigned data_fmt;
+-      unsigned mipi_dt;
+-};
+-
+-/*
+- * Enumeration of CSI data bus widths.
+- */
+-enum ipu_csi_data_width {
+-      IPU_CSI_DATA_WIDTH_4   = 0,
+-      IPU_CSI_DATA_WIDTH_8   = 1,
+-      IPU_CSI_DATA_WIDTH_10  = 3,
+-      IPU_CSI_DATA_WIDTH_12  = 5,
+-      IPU_CSI_DATA_WIDTH_16  = 9,
+-};
+-
+-/*
+- * Enumeration of CSI clock modes.
+- */
+-enum ipu_csi_clk_mode {
+-      IPU_CSI_CLK_MODE_GATED_CLK,
+-      IPU_CSI_CLK_MODE_NONGATED_CLK,
+-      IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
+-      IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
+-      IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
+-      IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
+-      IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
+-      IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
+-};
+-
+-static inline u32 ipu_csi_read(struct ipu_csi *csi, unsigned offset)
+-{
+-      return readl(csi->base + offset);
+-}
+-
+-static inline void ipu_csi_write(struct ipu_csi *csi, u32 value,
+-                               unsigned offset)
+-{
+-      writel(value, csi->base + offset);
+-}
+-
+-/*
+- * Set mclk division ratio for generating test mode mclk. Only used
+- * for test generator.
+- */
+-static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk,
+-                                      u32 ipu_clk)
+-{
+-      u32 temp;
+-      int div_ratio;
+-
+-      div_ratio = (ipu_clk / pixel_clk) - 1;
+-
+-      if (div_ratio > 0xFF || div_ratio < 0) {
+-              dev_err(csi->ipu->dev,
+-                      "value of pixel_clk extends normal range\n");
+-              return -EINVAL;
+-      }
+-
+-      temp = ipu_csi_read(csi, CSI_SENS_CONF);
+-      temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
+-      ipu_csi_write(csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
+-                        CSI_SENS_CONF);
+-
+-      return 0;
+-}
+-
+-/*
+- * Find the CSI data format and data width for the given V4L2 media
+- * bus pixel format code.
+- */
+-static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code,
+-                              enum v4l2_mbus_type mbus_type)
+-{
+-      switch (mbus_code) {
+-      case MEDIA_BUS_FMT_BGR565_2X8_BE:
+-      case MEDIA_BUS_FMT_BGR565_2X8_LE:
+-      case MEDIA_BUS_FMT_RGB565_2X8_BE:
+-      case MEDIA_BUS_FMT_RGB565_2X8_LE:
+-              if (mbus_type == V4L2_MBUS_CSI2_DPHY)
+-                      cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
+-              else
+-                      cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+-              cfg->mipi_dt = MIPI_DT_RGB565;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE:
+-      case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444;
+-              cfg->mipi_dt = MIPI_DT_RGB444;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
+-      case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
+-              cfg->mipi_dt = MIPI_DT_RGB555;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_RGB888_1X24:
+-      case MEDIA_BUS_FMT_BGR888_1X24:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
+-              cfg->mipi_dt = MIPI_DT_RGB888;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_UYVY8_2X8:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
+-              cfg->mipi_dt = MIPI_DT_YUV422;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_YUYV8_2X8:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
+-              cfg->mipi_dt = MIPI_DT_YUV422;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_UYVY8_1X16:
+-      case MEDIA_BUS_FMT_YUYV8_1X16:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+-              cfg->mipi_dt = MIPI_DT_YUV422;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_16;
+-              break;
+-      case MEDIA_BUS_FMT_SBGGR8_1X8:
+-      case MEDIA_BUS_FMT_SGBRG8_1X8:
+-      case MEDIA_BUS_FMT_SGRBG8_1X8:
+-      case MEDIA_BUS_FMT_SRGGB8_1X8:
+-      case MEDIA_BUS_FMT_Y8_1X8:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+-              cfg->mipi_dt = MIPI_DT_RAW8;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8:
+-      case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
+-      case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
+-      case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8:
+-      case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE:
+-      case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE:
+-      case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE:
+-      case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+-              cfg->mipi_dt = MIPI_DT_RAW10;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_SBGGR10_1X10:
+-      case MEDIA_BUS_FMT_SGBRG10_1X10:
+-      case MEDIA_BUS_FMT_SGRBG10_1X10:
+-      case MEDIA_BUS_FMT_SRGGB10_1X10:
+-      case MEDIA_BUS_FMT_Y10_1X10:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+-              cfg->mipi_dt = MIPI_DT_RAW10;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_10;
+-              break;
+-      case MEDIA_BUS_FMT_SBGGR12_1X12:
+-      case MEDIA_BUS_FMT_SGBRG12_1X12:
+-      case MEDIA_BUS_FMT_SGRBG12_1X12:
+-      case MEDIA_BUS_FMT_SRGGB12_1X12:
+-      case MEDIA_BUS_FMT_Y12_1X12:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+-              cfg->mipi_dt = MIPI_DT_RAW12;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_12;
+-              break;
+-      case MEDIA_BUS_FMT_JPEG_1X8:
+-              /* TODO */
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG;
+-              cfg->mipi_dt = MIPI_DT_RAW8;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      return 0;
+-}
+-
+-/* translate alternate field mode based on given standard */
+-static inline enum v4l2_field
+-ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
+-{
+-      return (field != V4L2_FIELD_ALTERNATE) ? field :
+-              ((std & V4L2_STD_525_60) ?
+-               V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
+-}
+-
+-/*
+- * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
+- */
+-static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
+-                          const struct v4l2_mbus_config *mbus_cfg,
+-                          const struct v4l2_mbus_framefmt *mbus_fmt)
+-{
+-      int ret;
+-
+-      memset(csicfg, 0, sizeof(*csicfg));
+-
+-      ret = mbus_code_to_bus_cfg(csicfg, mbus_fmt->code, mbus_cfg->type);
+-      if (ret < 0)
+-              return ret;
+-
+-      switch (mbus_cfg->type) {
+-      case V4L2_MBUS_PARALLEL:
+-              csicfg->ext_vsync = 1;
+-              csicfg->vsync_pol = (mbus_cfg->flags &
+-                                   V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0;
+-              csicfg->hsync_pol = (mbus_cfg->flags &
+-                                   V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0;
+-              csicfg->pixclk_pol = (mbus_cfg->flags &
+-                                    V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0;
+-              csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
+-              break;
+-      case V4L2_MBUS_BT656:
+-              csicfg->ext_vsync = 0;
+-              if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field) ||
+-                  mbus_fmt->field == V4L2_FIELD_ALTERNATE)
+-                      csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
+-              else
+-                      csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
+-              break;
+-      case V4L2_MBUS_CSI2_DPHY:
+-              /*
+-               * MIPI CSI-2 requires non gated clock mode, all other
+-               * parameters are not applicable for MIPI CSI-2 bus.
+-               */
+-              csicfg->clk_mode = IPU_CSI_CLK_MODE_NONGATED_CLK;
+-              break;
+-      default:
+-              /* will never get here, keep compiler quiet */
+-              break;
+-      }
+-
+-      return 0;
+-}
+-
+-static int
+-ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
+-                              const struct v4l2_mbus_framefmt *infmt,
+-                              const struct v4l2_mbus_framefmt *outfmt,
+-                              v4l2_std_id std)
+-{
+-      enum v4l2_field infield, outfield;
+-      bool swap_fields;
+-
+-      /* get translated field type of input and output */
+-      infield = ipu_csi_translate_field(infmt->field, std);
+-      outfield = ipu_csi_translate_field(outfmt->field, std);
+-
+-      /*
+-       * Write the H-V-F codes the CSI will match against the
+-       * incoming data for start/end of active and blanking
+-       * field intervals. If input and output field types are
+-       * sequential but not the same (one is SEQ_BT and the other
+-       * is SEQ_TB), swap the F-bit so that the CSI will capture
+-       * field 1 lines before field 0 lines.
+-       */
+-      swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
+-                     V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
+-                     infield != outfield);
+-
+-      if (!swap_fields) {
+-              /*
+-               * Field0BlankEnd  = 110, Field0BlankStart  = 010
+-               * Field0ActiveEnd = 100, Field0ActiveStart = 000
+-               * Field1BlankEnd  = 111, Field1BlankStart  = 011
+-               * Field1ActiveEnd = 101, Field1ActiveStart = 001
+-               */
+-              ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
+-                            CSI_CCIR_CODE_1);
+-              ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+-      } else {
+-              dev_dbg(csi->ipu->dev, "capture field swap\n");
+-
+-              /* same as above but with F-bit inverted */
+-              ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
+-                            CSI_CCIR_CODE_1);
+-              ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+-      }
+-
+-      ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+-
+-      return 0;
+-}
+-
+-
+-int ipu_csi_init_interface(struct ipu_csi *csi,
+-                         const struct v4l2_mbus_config *mbus_cfg,
+-                         const struct v4l2_mbus_framefmt *infmt,
+-                         const struct v4l2_mbus_framefmt *outfmt)
+-{
+-      struct ipu_csi_bus_config cfg;
+-      unsigned long flags;
+-      u32 width, height, data = 0;
+-      v4l2_std_id std;
+-      int ret;
+-
+-      ret = fill_csi_bus_cfg(&cfg, mbus_cfg, infmt);
+-      if (ret < 0)
+-              return ret;
+-
+-      /* set default sensor frame width and height */
+-      width = infmt->width;
+-      height = infmt->height;
+-      if (infmt->field == V4L2_FIELD_ALTERNATE)
+-              height *= 2;
+-
+-      /* Set the CSI_SENS_CONF register remaining fields */
+-      data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
+-              cfg.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
+-              cfg.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
+-              cfg.vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
+-              cfg.hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
+-              cfg.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
+-              cfg.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
+-              cfg.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
+-              cfg.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
+-              cfg.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
+-              cfg.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      ipu_csi_write(csi, data, CSI_SENS_CONF);
+-
+-      /* Set CCIR registers */
+-
+-      switch (cfg.clk_mode) {
+-      case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+-              ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
+-              ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+-              break;
+-      case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+-              if (width == 720 && height == 480) {
+-                      std = V4L2_STD_NTSC;
+-                      height = 525;
+-              } else if (width == 720 && height == 576) {
+-                      std = V4L2_STD_PAL;
+-                      height = 625;
+-              } else {
+-                      dev_err(csi->ipu->dev,
+-                              "Unsupported interlaced video mode\n");
+-                      ret = -EINVAL;
+-                      goto out_unlock;
+-              }
+-
+-              ret = ipu_csi_set_bt_interlaced_codes(csi, infmt, outfmt, std);
+-              if (ret)
+-                      goto out_unlock;
+-              break;
+-      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+-      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+-      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+-      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+-              ipu_csi_write(csi, 0x40030 | CSI_CCIR_ERR_DET_EN,
+-                                 CSI_CCIR_CODE_1);
+-              ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+-              break;
+-      case IPU_CSI_CLK_MODE_GATED_CLK:
+-      case IPU_CSI_CLK_MODE_NONGATED_CLK:
+-              ipu_csi_write(csi, 0, CSI_CCIR_CODE_1);
+-              break;
+-      }
+-
+-      /* Setup sensor frame size */
+-      ipu_csi_write(csi, (width - 1) | ((height - 1) << 16),
+-                    CSI_SENS_FRM_SIZE);
+-
+-      dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
+-              ipu_csi_read(csi, CSI_SENS_CONF));
+-      dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
+-              ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
+-
+-out_unlock:
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_init_interface);
+-
+-bool ipu_csi_is_interlaced(struct ipu_csi *csi)
+-{
+-      unsigned long flags;
+-      u32 sensor_protocol;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-      sensor_protocol =
+-              (ipu_csi_read(csi, CSI_SENS_CONF) &
+-               CSI_SENS_CONF_SENS_PRTCL_MASK) >>
+-              CSI_SENS_CONF_SENS_PRTCL_SHIFT;
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-
+-      switch (sensor_protocol) {
+-      case IPU_CSI_CLK_MODE_GATED_CLK:
+-      case IPU_CSI_CLK_MODE_NONGATED_CLK:
+-      case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+-      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+-      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+-              return false;
+-      case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+-      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+-      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+-              return true;
+-      default:
+-              dev_err(csi->ipu->dev,
+-                      "CSI %d sensor protocol unsupported\n", csi->id);
+-              return false;
+-      }
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_is_interlaced);
+-
+-void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w)
+-{
+-      unsigned long flags;
+-      u32 reg;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE);
+-      w->width = (reg & 0xFFFF) + 1;
+-      w->height = (reg >> 16 & 0xFFFF) + 1;
+-
+-      reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+-      w->left = (reg & CSI_HSC_MASK) >> CSI_HSC_SHIFT;
+-      w->top = (reg & CSI_VSC_MASK) >> CSI_VSC_SHIFT;
+-
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_get_window);
+-
+-void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w)
+-{
+-      unsigned long flags;
+-      u32 reg;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      ipu_csi_write(csi, (w->width - 1) | ((w->height - 1) << 16),
+-                        CSI_ACT_FRM_SIZE);
+-
+-      reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+-      reg &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
+-      reg |= ((w->top << CSI_VSC_SHIFT) | (w->left << CSI_HSC_SHIFT));
+-      ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
+-
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_set_window);
+-
+-void ipu_csi_set_downsize(struct ipu_csi *csi, bool horiz, bool vert)
+-{
+-      unsigned long flags;
+-      u32 reg;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+-      reg &= ~(CSI_HORI_DOWNSIZE_EN | CSI_VERT_DOWNSIZE_EN);
+-      reg |= (horiz ? CSI_HORI_DOWNSIZE_EN : 0) |
+-             (vert ? CSI_VERT_DOWNSIZE_EN : 0);
+-      ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
+-
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_set_downsize);
+-
+-void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
+-                              u32 r_value, u32 g_value, u32 b_value,
+-                              u32 pix_clk)
+-{
+-      unsigned long flags;
+-      u32 ipu_clk = clk_get_rate(csi->clk_ipu);
+-      u32 temp;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      temp = ipu_csi_read(csi, CSI_TST_CTRL);
+-
+-      if (!active) {
+-              temp &= ~CSI_TEST_GEN_MODE_EN;
+-              ipu_csi_write(csi, temp, CSI_TST_CTRL);
+-      } else {
+-              /* Set sensb_mclk div_ratio */
+-              ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk);
+-
+-              temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
+-                        CSI_TEST_GEN_B_MASK);
+-              temp |= CSI_TEST_GEN_MODE_EN;
+-              temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
+-                      (g_value << CSI_TEST_GEN_G_SHIFT) |
+-                      (b_value << CSI_TEST_GEN_B_SHIFT);
+-              ipu_csi_write(csi, temp, CSI_TST_CTRL);
+-      }
+-
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator);
+-
+-int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
+-                            struct v4l2_mbus_framefmt *mbus_fmt)
+-{
+-      struct ipu_csi_bus_config cfg;
+-      unsigned long flags;
+-      u32 temp;
+-      int ret;
+-
+-      if (vc > 3)
+-              return -EINVAL;
+-
+-      ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code, V4L2_MBUS_CSI2_DPHY);
+-      if (ret < 0)
+-              return ret;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      temp = ipu_csi_read(csi, CSI_MIPI_DI);
+-      temp &= ~(0xff << (vc * 8));
+-      temp |= (cfg.mipi_dt << (vc * 8));
+-      ipu_csi_write(csi, temp, CSI_MIPI_DI);
+-
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype);
+-
+-int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
+-                        u32 max_ratio, u32 id)
+-{
+-      unsigned long flags;
+-      u32 temp;
+-
+-      if (max_ratio > 5 || id > 3)
+-              return -EINVAL;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      temp = ipu_csi_read(csi, CSI_SKIP);
+-      temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
+-                CSI_SKIP_SMFC_MASK);
+-      temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
+-              (id << CSI_ID_2_SKIP_SHIFT) |
+-              (skip << CSI_SKIP_SMFC_SHIFT);
+-      ipu_csi_write(csi, temp, CSI_SKIP);
+-
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc);
+-
+-int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest)
+-{
+-      unsigned long flags;
+-      u32 csi_sens_conf, dest;
+-
+-      if (csi_dest == IPU_CSI_DEST_IDMAC)
+-              dest = CSI_DATA_DEST_IDMAC;
+-      else
+-              dest = CSI_DATA_DEST_IC; /* IC or VDIC */
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF);
+-      csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
+-      csi_sens_conf |= (dest << CSI_SENS_CONF_DATA_DEST_SHIFT);
+-      ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF);
+-
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_set_dest);
+-
+-int ipu_csi_enable(struct ipu_csi *csi)
+-{
+-      ipu_module_enable(csi->ipu, csi->module);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_enable);
+-
+-int ipu_csi_disable(struct ipu_csi *csi)
+-{
+-      ipu_module_disable(csi->ipu, csi->module);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_disable);
+-
+-struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id)
+-{
+-      unsigned long flags;
+-      struct ipu_csi *csi, *ret;
+-
+-      if (id > 1)
+-              return ERR_PTR(-EINVAL);
+-
+-      csi = ipu->csi_priv[id];
+-      ret = csi;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      if (csi->inuse) {
+-              ret = ERR_PTR(-EBUSY);
+-              goto unlock;
+-      }
+-
+-      csi->inuse = true;
+-unlock:
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_get);
+-
+-void ipu_csi_put(struct ipu_csi *csi)
+-{
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-      csi->inuse = false;
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_put);
+-
+-int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
+-               unsigned long base, u32 module, struct clk *clk_ipu)
+-{
+-      struct ipu_csi *csi;
+-
+-      if (id > 1)
+-              return -ENODEV;
+-
+-      csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL);
+-      if (!csi)
+-              return -ENOMEM;
+-
+-      ipu->csi_priv[id] = csi;
+-
+-      spin_lock_init(&csi->lock);
+-      csi->module = module;
+-      csi->id = id;
+-      csi->clk_ipu = clk_ipu;
+-      csi->base = devm_ioremap(dev, base, PAGE_SIZE);
+-      if (!csi->base)
+-              return -ENOMEM;
+-
+-      dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n",
+-              id, base, csi->base);
+-      csi->ipu = ipu;
+-
+-      return 0;
+-}
+-
+-void ipu_csi_exit(struct ipu_soc *ipu, int id)
+-{
+-}
+-
+-void ipu_csi_dump(struct ipu_csi *csi)
+-{
+-      dev_dbg(csi->ipu->dev, "CSI_SENS_CONF:     %08x\n",
+-              ipu_csi_read(csi, CSI_SENS_CONF));
+-      dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n",
+-              ipu_csi_read(csi, CSI_SENS_FRM_SIZE));
+-      dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE:  %08x\n",
+-              ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
+-      dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL:  %08x\n",
+-              ipu_csi_read(csi, CSI_OUT_FRM_CTRL));
+-      dev_dbg(csi->ipu->dev, "CSI_TST_CTRL:      %08x\n",
+-              ipu_csi_read(csi, CSI_TST_CTRL));
+-      dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1:   %08x\n",
+-              ipu_csi_read(csi, CSI_CCIR_CODE_1));
+-      dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2:   %08x\n",
+-              ipu_csi_read(csi, CSI_CCIR_CODE_2));
+-      dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3:   %08x\n",
+-              ipu_csi_read(csi, CSI_CCIR_CODE_3));
+-      dev_dbg(csi->ipu->dev, "CSI_MIPI_DI:       %08x\n",
+-              ipu_csi_read(csi, CSI_MIPI_DI));
+-      dev_dbg(csi->ipu->dev, "CSI_SKIP:          %08x\n",
+-              ipu_csi_read(csi, CSI_SKIP));
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_dump);
+--- a/drivers/gpu/ipu-v3/ipu-dc.c
++++ /dev/null
+@@ -1,420 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-
+-#include <linux/export.h>
+-#include <linux/module.h>
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/io.h>
+-
+-#include <video/imx-ipu-v3.h>
+-#include "ipu-prv.h"
+-
+-#define DC_MAP_CONF_PTR(n)    (0x108 + ((n) & ~0x1) * 2)
+-#define DC_MAP_CONF_VAL(n)    (0x144 + ((n) & ~0x1) * 2)
+-
+-#define DC_EVT_NF             0
+-#define DC_EVT_NL             1
+-#define DC_EVT_EOF            2
+-#define DC_EVT_NFIELD         3
+-#define DC_EVT_EOL            4
+-#define DC_EVT_EOFIELD                5
+-#define DC_EVT_NEW_ADDR               6
+-#define DC_EVT_NEW_CHAN               7
+-#define DC_EVT_NEW_DATA               8
+-
+-#define DC_EVT_NEW_ADDR_W_0   0
+-#define DC_EVT_NEW_ADDR_W_1   1
+-#define DC_EVT_NEW_CHAN_W_0   2
+-#define DC_EVT_NEW_CHAN_W_1   3
+-#define DC_EVT_NEW_DATA_W_0   4
+-#define DC_EVT_NEW_DATA_W_1   5
+-#define DC_EVT_NEW_ADDR_R_0   6
+-#define DC_EVT_NEW_ADDR_R_1   7
+-#define DC_EVT_NEW_CHAN_R_0   8
+-#define DC_EVT_NEW_CHAN_R_1   9
+-#define DC_EVT_NEW_DATA_R_0   10
+-#define DC_EVT_NEW_DATA_R_1   11
+-
+-#define DC_WR_CH_CONF         0x0
+-#define DC_WR_CH_ADDR         0x4
+-#define DC_RL_CH(evt)         (8 + ((evt) & ~0x1) * 2)
+-
+-#define DC_GEN                        0xd4
+-#define DC_DISP_CONF1(disp)   (0xd8 + (disp) * 4)
+-#define DC_DISP_CONF2(disp)   (0xe8 + (disp) * 4)
+-#define DC_STAT                       0x1c8
+-
+-#define WROD(lf)              (0x18 | ((lf) << 1))
+-#define WRG                   0x01
+-#define WCLK                  0xc9
+-
+-#define SYNC_WAVE 0
+-#define NULL_WAVE (-1)
+-
+-#define DC_GEN_SYNC_1_6_SYNC  (2 << 1)
+-#define DC_GEN_SYNC_PRIORITY_1        (1 << 7)
+-
+-#define DC_WR_CH_CONF_WORD_SIZE_8             (0 << 0)
+-#define DC_WR_CH_CONF_WORD_SIZE_16            (1 << 0)
+-#define DC_WR_CH_CONF_WORD_SIZE_24            (2 << 0)
+-#define DC_WR_CH_CONF_WORD_SIZE_32            (3 << 0)
+-#define DC_WR_CH_CONF_DISP_ID_PARALLEL(i)     (((i) & 0x1) << 3)
+-#define DC_WR_CH_CONF_DISP_ID_SERIAL          (2 << 3)
+-#define DC_WR_CH_CONF_DISP_ID_ASYNC           (3 << 4)
+-#define DC_WR_CH_CONF_FIELD_MODE              (1 << 9)
+-#define DC_WR_CH_CONF_PROG_TYPE_NORMAL                (4 << 5)
+-#define DC_WR_CH_CONF_PROG_TYPE_MASK          (7 << 5)
+-#define DC_WR_CH_CONF_PROG_DI_ID              (1 << 2)
+-#define DC_WR_CH_CONF_PROG_DISP_ID(i)         (((i) & 0x1) << 3)
+-
+-#define IPU_DC_NUM_CHANNELS   10
+-
+-struct ipu_dc_priv;
+-
+-enum ipu_dc_map {
+-      IPU_DC_MAP_RGB24,
+-      IPU_DC_MAP_RGB565,
+-      IPU_DC_MAP_GBR24, /* TVEv2 */
+-      IPU_DC_MAP_BGR666,
+-      IPU_DC_MAP_LVDS666,
+-      IPU_DC_MAP_BGR24,
+-};
+-
+-struct ipu_dc {
+-      /* The display interface number assigned to this dc channel */
+-      unsigned int            di;
+-      void __iomem            *base;
+-      struct ipu_dc_priv      *priv;
+-      int                     chno;
+-      bool                    in_use;
+-};
+-
+-struct ipu_dc_priv {
+-      void __iomem            *dc_reg;
+-      void __iomem            *dc_tmpl_reg;
+-      struct ipu_soc          *ipu;
+-      struct device           *dev;
+-      struct ipu_dc           channels[IPU_DC_NUM_CHANNELS];
+-      struct mutex            mutex;
+-      struct completion       comp;
+-      int                     use_count;
+-};
+-
+-static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
+-{
+-      u32 reg;
+-
+-      reg = readl(dc->base + DC_RL_CH(event));
+-      reg &= ~(0xffff << (16 * (event & 0x1)));
+-      reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
+-      writel(reg, dc->base + DC_RL_CH(event));
+-}
+-
+-static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
+-              int map, int wave, int glue, int sync, int stop)
+-{
+-      struct ipu_dc_priv *priv = dc->priv;
+-      u32 reg1, reg2;
+-
+-      if (opcode == WCLK) {
+-              reg1 = (operand << 20) & 0xfff00000;
+-              reg2 = operand >> 12 | opcode << 1 | stop << 9;
+-      } else if (opcode == WRG) {
+-              reg1 = sync | glue << 4 | ++wave << 11 | ((operand << 15) & 0xffff8000);
+-              reg2 = operand >> 17 | opcode << 7 | stop << 9;
+-      } else {
+-              reg1 = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000);
+-              reg2 = operand >> 12 | opcode << 4 | stop << 9;
+-      }
+-      writel(reg1, priv->dc_tmpl_reg + word * 8);
+-      writel(reg2, priv->dc_tmpl_reg + word * 8 + 4);
+-}
+-
+-static int ipu_bus_format_to_map(u32 fmt)
+-{
+-      switch (fmt) {
+-      default:
+-              WARN_ON(1);
+-              /* fall-through */
+-      case MEDIA_BUS_FMT_RGB888_1X24:
+-              return IPU_DC_MAP_RGB24;
+-      case MEDIA_BUS_FMT_RGB565_1X16:
+-              return IPU_DC_MAP_RGB565;
+-      case MEDIA_BUS_FMT_GBR888_1X24:
+-              return IPU_DC_MAP_GBR24;
+-      case MEDIA_BUS_FMT_RGB666_1X18:
+-              return IPU_DC_MAP_BGR666;
+-      case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+-              return IPU_DC_MAP_LVDS666;
+-      case MEDIA_BUS_FMT_BGR888_1X24:
+-              return IPU_DC_MAP_BGR24;
+-      }
+-}
+-
+-int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
+-              u32 bus_format, u32 width)
+-{
+-      struct ipu_dc_priv *priv = dc->priv;
+-      int addr, sync;
+-      u32 reg = 0;
+-      int map;
+-
+-      dc->di = ipu_di_get_num(di);
+-
+-      map = ipu_bus_format_to_map(bus_format);
+-
+-      /*
+-       * In interlaced mode we need more counters to create the asymmetric
+-       * per-field VSYNC signals. The pixel active signal synchronising DC
+-       * to DI moves to signal generator #6 (see ipu-di.c). In progressive
+-       * mode counter #5 is used.
+-       */
+-      sync = interlaced ? 6 : 5;
+-
+-      /* Reserve 5 microcode template words for each DI */
+-      if (dc->di)
+-              addr = 5;
+-      else
+-              addr = 0;
+-
+-      if (interlaced) {
+-              dc_link_event(dc, DC_EVT_NL, addr, 3);
+-              dc_link_event(dc, DC_EVT_EOL, addr, 2);
+-              dc_link_event(dc, DC_EVT_NEW_DATA, addr, 1);
+-
+-              /* Init template microcode */
+-              dc_write_tmpl(dc, addr, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
+-      } else {
+-              dc_link_event(dc, DC_EVT_NL, addr + 2, 3);
+-              dc_link_event(dc, DC_EVT_EOL, addr + 3, 2);
+-              dc_link_event(dc, DC_EVT_NEW_DATA, addr + 1, 1);
+-
+-              /* Init template microcode */
+-              dc_write_tmpl(dc, addr + 2, WROD(0), 0, map, SYNC_WAVE, 8, sync, 1);
+-              dc_write_tmpl(dc, addr + 3, WROD(0), 0, map, SYNC_WAVE, 4, sync, 0);
+-              dc_write_tmpl(dc, addr + 4, WRG, 0, map, NULL_WAVE, 0, 0, 1);
+-              dc_write_tmpl(dc, addr + 1, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
+-      }
+-
+-      dc_link_event(dc, DC_EVT_NF, 0, 0);
+-      dc_link_event(dc, DC_EVT_NFIELD, 0, 0);
+-      dc_link_event(dc, DC_EVT_EOF, 0, 0);
+-      dc_link_event(dc, DC_EVT_EOFIELD, 0, 0);
+-      dc_link_event(dc, DC_EVT_NEW_CHAN, 0, 0);
+-      dc_link_event(dc, DC_EVT_NEW_ADDR, 0, 0);
+-
+-      reg = readl(dc->base + DC_WR_CH_CONF);
+-      if (interlaced)
+-              reg |= DC_WR_CH_CONF_FIELD_MODE;
+-      else
+-              reg &= ~DC_WR_CH_CONF_FIELD_MODE;
+-      writel(reg, dc->base + DC_WR_CH_CONF);
+-
+-      writel(0x0, dc->base + DC_WR_CH_ADDR);
+-      writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
+-
+-void ipu_dc_enable(struct ipu_soc *ipu)
+-{
+-      struct ipu_dc_priv *priv = ipu->dc_priv;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      if (!priv->use_count)
+-              ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
+-
+-      priv->use_count++;
+-
+-      mutex_unlock(&priv->mutex);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dc_enable);
+-
+-void ipu_dc_enable_channel(struct ipu_dc *dc)
+-{
+-      u32 reg;
+-
+-      reg = readl(dc->base + DC_WR_CH_CONF);
+-      reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL;
+-      writel(reg, dc->base + DC_WR_CH_CONF);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
+-
+-void ipu_dc_disable_channel(struct ipu_dc *dc)
+-{
+-      u32 val;
+-
+-      val = readl(dc->base + DC_WR_CH_CONF);
+-      val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+-      writel(val, dc->base + DC_WR_CH_CONF);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
+-
+-void ipu_dc_disable(struct ipu_soc *ipu)
+-{
+-      struct ipu_dc_priv *priv = ipu->dc_priv;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      priv->use_count--;
+-      if (!priv->use_count)
+-              ipu_module_disable(priv->ipu, IPU_CONF_DC_EN);
+-
+-      if (priv->use_count < 0)
+-              priv->use_count = 0;
+-
+-      mutex_unlock(&priv->mutex);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dc_disable);
+-
+-static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
+-              int byte_num, int offset, int mask)
+-{
+-      int ptr = map * 3 + byte_num;
+-      u32 reg;
+-
+-      reg = readl(priv->dc_reg + DC_MAP_CONF_VAL(ptr));
+-      reg &= ~(0xffff << (16 * (ptr & 0x1)));
+-      reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
+-      writel(reg, priv->dc_reg + DC_MAP_CONF_VAL(ptr));
+-
+-      reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
+-      reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
+-      reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
+-      writel(reg, priv->dc_reg + DC_MAP_CONF_PTR(map));
+-}
+-
+-static void ipu_dc_map_clear(struct ipu_dc_priv *priv, int map)
+-{
+-      u32 reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
+-
+-      writel(reg & ~(0xffff << (16 * (map & 0x1))),
+-                   priv->dc_reg + DC_MAP_CONF_PTR(map));
+-}
+-
+-struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel)
+-{
+-      struct ipu_dc_priv *priv = ipu->dc_priv;
+-      struct ipu_dc *dc;
+-
+-      if (channel >= IPU_DC_NUM_CHANNELS)
+-              return ERR_PTR(-ENODEV);
+-
+-      dc = &priv->channels[channel];
+-
+-      mutex_lock(&priv->mutex);
+-
+-      if (dc->in_use) {
+-              mutex_unlock(&priv->mutex);
+-              return ERR_PTR(-EBUSY);
+-      }
+-
+-      dc->in_use = true;
+-
+-      mutex_unlock(&priv->mutex);
+-
+-      return dc;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dc_get);
+-
+-void ipu_dc_put(struct ipu_dc *dc)
+-{
+-      struct ipu_dc_priv *priv = dc->priv;
+-
+-      mutex_lock(&priv->mutex);
+-      dc->in_use = false;
+-      mutex_unlock(&priv->mutex);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dc_put);
+-
+-int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
+-              unsigned long base, unsigned long template_base)
+-{
+-      struct ipu_dc_priv *priv;
+-      static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
+-              0x78, 0, 0x94, 0xb4};
+-      int i;
+-
+-      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-      if (!priv)
+-              return -ENOMEM;
+-
+-      mutex_init(&priv->mutex);
+-
+-      priv->dev = dev;
+-      priv->ipu = ipu;
+-      priv->dc_reg = devm_ioremap(dev, base, PAGE_SIZE);
+-      priv->dc_tmpl_reg = devm_ioremap(dev, template_base, PAGE_SIZE);
+-      if (!priv->dc_reg || !priv->dc_tmpl_reg)
+-              return -ENOMEM;
+-
+-      for (i = 0; i < IPU_DC_NUM_CHANNELS; i++) {
+-              priv->channels[i].chno = i;
+-              priv->channels[i].priv = priv;
+-              priv->channels[i].base = priv->dc_reg + channel_offsets[i];
+-      }
+-
+-      writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
+-                      DC_WR_CH_CONF_PROG_DI_ID,
+-                      priv->channels[1].base + DC_WR_CH_CONF);
+-      writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0),
+-                      priv->channels[5].base + DC_WR_CH_CONF);
+-
+-      writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1,
+-              priv->dc_reg + DC_GEN);
+-
+-      ipu->dc_priv = priv;
+-
+-      dev_dbg(dev, "DC base: 0x%08lx template base: 0x%08lx\n",
+-                      base, template_base);
+-
+-      /* rgb24 */
+-      ipu_dc_map_clear(priv, IPU_DC_MAP_RGB24);
+-      ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 0, 7, 0xff); /* blue */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 1, 15, 0xff); /* green */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 2, 23, 0xff); /* red */
+-
+-      /* rgb565 */
+-      ipu_dc_map_clear(priv, IPU_DC_MAP_RGB565);
+-      ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 0, 4, 0xf8); /* blue */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc); /* green */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8); /* red */
+-
+-      /* gbr24 */
+-      ipu_dc_map_clear(priv, IPU_DC_MAP_GBR24);
+-      ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 2, 15, 0xff); /* green */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 1, 7, 0xff); /* blue */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 0, 23, 0xff); /* red */
+-
+-      /* bgr666 */
+-      ipu_dc_map_clear(priv, IPU_DC_MAP_BGR666);
+-      ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 0, 5, 0xfc); /* blue */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc); /* green */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc); /* red */
+-
+-      /* lvds666 */
+-      ipu_dc_map_clear(priv, IPU_DC_MAP_LVDS666);
+-      ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 0, 5, 0xfc); /* blue */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 1, 13, 0xfc); /* green */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 2, 21, 0xfc); /* red */
+-
+-      /* bgr24 */
+-      ipu_dc_map_clear(priv, IPU_DC_MAP_BGR24);
+-      ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 2, 7, 0xff); /* red */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */
+-
+-      return 0;
+-}
+-
+-void ipu_dc_exit(struct ipu_soc *ipu)
+-{
+-}
+--- a/drivers/gpu/ipu-v3/ipu-di.c
++++ /dev/null
+@@ -1,745 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-#include <linux/export.h>
+-#include <linux/module.h>
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/io.h>
+-#include <linux/err.h>
+-#include <linux/platform_device.h>
+-
+-#include <video/imx-ipu-v3.h>
+-#include "ipu-prv.h"
+-
+-struct ipu_di {
+-      void __iomem *base;
+-      int id;
+-      u32 module;
+-      struct clk *clk_di;     /* display input clock */
+-      struct clk *clk_ipu;    /* IPU bus clock */
+-      struct clk *clk_di_pixel; /* resulting pixel clock */
+-      bool inuse;
+-      struct ipu_soc *ipu;
+-};
+-
+-static DEFINE_MUTEX(di_mutex);
+-
+-struct di_sync_config {
+-      int run_count;
+-      int run_src;
+-      int offset_count;
+-      int offset_src;
+-      int repeat_count;
+-      int cnt_clr_src;
+-      int cnt_polarity_gen_en;
+-      int cnt_polarity_clr_src;
+-      int cnt_polarity_trigger_src;
+-      int cnt_up;
+-      int cnt_down;
+-};
+-
+-enum di_pins {
+-      DI_PIN11 = 0,
+-      DI_PIN12 = 1,
+-      DI_PIN13 = 2,
+-      DI_PIN14 = 3,
+-      DI_PIN15 = 4,
+-      DI_PIN16 = 5,
+-      DI_PIN17 = 6,
+-      DI_PIN_CS = 7,
+-
+-      DI_PIN_SER_CLK = 0,
+-      DI_PIN_SER_RS = 1,
+-};
+-
+-enum di_sync_wave {
+-      DI_SYNC_NONE = 0,
+-      DI_SYNC_CLK = 1,
+-      DI_SYNC_INT_HSYNC = 2,
+-      DI_SYNC_HSYNC = 3,
+-      DI_SYNC_VSYNC = 4,
+-      DI_SYNC_DE = 6,
+-
+-      DI_SYNC_CNT1 = 2,       /* counter >= 2 only */
+-      DI_SYNC_CNT4 = 5,       /* counter >= 5 only */
+-      DI_SYNC_CNT5 = 6,       /* counter >= 6 only */
+-};
+-
+-#define SYNC_WAVE 0
+-
+-#define DI_GENERAL            0x0000
+-#define DI_BS_CLKGEN0         0x0004
+-#define DI_BS_CLKGEN1         0x0008
+-#define DI_SW_GEN0(gen)               (0x000c + 4 * ((gen) - 1))
+-#define DI_SW_GEN1(gen)               (0x0030 + 4 * ((gen) - 1))
+-#define DI_STP_REP(gen)               (0x0148 + 4 * (((gen) - 1)/2))
+-#define DI_SYNC_AS_GEN                0x0054
+-#define DI_DW_GEN(gen)                (0x0058 + 4 * (gen))
+-#define DI_DW_SET(gen, set)   (0x0088 + 4 * ((gen) + 0xc * (set)))
+-#define DI_SER_CONF           0x015c
+-#define DI_SSC                        0x0160
+-#define DI_POL                        0x0164
+-#define DI_AW0                        0x0168
+-#define DI_AW1                        0x016c
+-#define DI_SCR_CONF           0x0170
+-#define DI_STAT                       0x0174
+-
+-#define DI_SW_GEN0_RUN_COUNT(x)                       ((x) << 19)
+-#define DI_SW_GEN0_RUN_SRC(x)                 ((x) << 16)
+-#define DI_SW_GEN0_OFFSET_COUNT(x)            ((x) << 3)
+-#define DI_SW_GEN0_OFFSET_SRC(x)              ((x) << 0)
+-
+-#define DI_SW_GEN1_CNT_POL_GEN_EN(x)          ((x) << 29)
+-#define DI_SW_GEN1_CNT_CLR_SRC(x)             ((x) << 25)
+-#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x)     ((x) << 12)
+-#define DI_SW_GEN1_CNT_POL_CLR_SRC(x)         ((x) << 9)
+-#define DI_SW_GEN1_CNT_DOWN(x)                        ((x) << 16)
+-#define DI_SW_GEN1_CNT_UP(x)                  (x)
+-#define DI_SW_GEN1_AUTO_RELOAD                        (0x10000000)
+-
+-#define DI_DW_GEN_ACCESS_SIZE_OFFSET          24
+-#define DI_DW_GEN_COMPONENT_SIZE_OFFSET               16
+-
+-#define DI_GEN_POLARITY_1                     (1 << 0)
+-#define DI_GEN_POLARITY_2                     (1 << 1)
+-#define DI_GEN_POLARITY_3                     (1 << 2)
+-#define DI_GEN_POLARITY_4                     (1 << 3)
+-#define DI_GEN_POLARITY_5                     (1 << 4)
+-#define DI_GEN_POLARITY_6                     (1 << 5)
+-#define DI_GEN_POLARITY_7                     (1 << 6)
+-#define DI_GEN_POLARITY_8                     (1 << 7)
+-#define DI_GEN_POLARITY_DISP_CLK              (1 << 17)
+-#define DI_GEN_DI_CLK_EXT                     (1 << 20)
+-#define DI_GEN_DI_VSYNC_EXT                   (1 << 21)
+-
+-#define DI_POL_DRDY_DATA_POLARITY             (1 << 7)
+-#define DI_POL_DRDY_POLARITY_15                       (1 << 4)
+-
+-#define DI_VSYNC_SEL_OFFSET                   13
+-
+-static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
+-{
+-      return readl(di->base + offset);
+-}
+-
+-static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
+-{
+-      writel(value, di->base + offset);
+-}
+-
+-static void ipu_di_data_wave_config(struct ipu_di *di,
+-                                   int wave_gen,
+-                                   int access_size, int component_size)
+-{
+-      u32 reg;
+-      reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
+-          (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
+-      ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+-}
+-
+-static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin,
+-              int set, int up, int down)
+-{
+-      u32 reg;
+-
+-      reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
+-      reg &= ~(0x3 << (di_pin * 2));
+-      reg |= set << (di_pin * 2);
+-      ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+-
+-      ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
+-}
+-
+-static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config,
+-              int start, int count)
+-{
+-      u32 reg;
+-      int i;
+-
+-      for (i = 0; i < count; i++) {
+-              struct di_sync_config *c = &config[i];
+-              int wave_gen = start + i + 1;
+-
+-              if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) ||
+-                              (c->repeat_count >= 0x1000) ||
+-                              (c->cnt_up >= 0x400) ||
+-                              (c->cnt_down >= 0x400)) {
+-                      dev_err(di->ipu->dev, "DI%d counters out of range.\n",
+-                                      di->id);
+-                      return;
+-              }
+-
+-              reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
+-                      DI_SW_GEN0_RUN_SRC(c->run_src) |
+-                      DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
+-                      DI_SW_GEN0_OFFSET_SRC(c->offset_src);
+-              ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
+-
+-              reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
+-                      DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
+-                      DI_SW_GEN1_CNT_POL_TRIGGER_SRC(
+-                                      c->cnt_polarity_trigger_src) |
+-                      DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
+-                      DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
+-                      DI_SW_GEN1_CNT_UP(c->cnt_up);
+-
+-              /* Enable auto reload */
+-              if (c->repeat_count == 0)
+-                      reg |= DI_SW_GEN1_AUTO_RELOAD;
+-
+-              ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
+-
+-              reg = ipu_di_read(di, DI_STP_REP(wave_gen));
+-              reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
+-              reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
+-              ipu_di_write(di, reg, DI_STP_REP(wave_gen));
+-      }
+-}
+-
+-static void ipu_di_sync_config_interlaced(struct ipu_di *di,
+-              struct ipu_di_signal_cfg *sig)
+-{
+-      u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
+-              sig->mode.hback_porch + sig->mode.hfront_porch;
+-      u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
+-              sig->mode.vback_porch + sig->mode.vfront_porch;
+-      struct di_sync_config cfg[] = {
+-              {
+-                      /* 1: internal VSYNC for each frame */
+-                      .run_count = v_total * 2 - 1,
+-                      .run_src = 3,                   /* == counter 7 */
+-              }, {
+-                      /* PIN2: HSYNC waveform */
+-                      .run_count = h_total - 1,
+-                      .run_src = DI_SYNC_CLK,
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
+-                      .cnt_down = sig->mode.hsync_len * 2,
+-              }, {
+-                      /* PIN3: VSYNC waveform */
+-                      .run_count = v_total - 1,
+-                      .run_src = 4,                   /* == counter 7 */
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = 4,  /* == counter 7 */
+-                      .cnt_down = sig->mode.vsync_len * 2,
+-                      .cnt_clr_src = DI_SYNC_CNT1,
+-              }, {
+-                      /* 4: Field */
+-                      .run_count = v_total / 2,
+-                      .run_src = DI_SYNC_HSYNC,
+-                      .offset_count = h_total / 2,
+-                      .offset_src = DI_SYNC_CLK,
+-                      .repeat_count = 2,
+-                      .cnt_clr_src = DI_SYNC_CNT1,
+-              }, {
+-                      /* 5: Active lines */
+-                      .run_src = DI_SYNC_HSYNC,
+-                      .offset_count = (sig->mode.vsync_len +
+-                                       sig->mode.vback_porch) / 2,
+-                      .offset_src = DI_SYNC_HSYNC,
+-                      .repeat_count = sig->mode.vactive / 2,
+-                      .cnt_clr_src = DI_SYNC_CNT4,
+-              }, {
+-                      /* 6: Active pixel, referenced by DC */
+-                      .run_src = DI_SYNC_CLK,
+-                      .offset_count = sig->mode.hsync_len +
+-                                      sig->mode.hback_porch,
+-                      .offset_src = DI_SYNC_CLK,
+-                      .repeat_count = sig->mode.hactive,
+-                      .cnt_clr_src = DI_SYNC_CNT5,
+-              }, {
+-                      /* 7: Half line HSYNC */
+-                      .run_count = h_total / 2 - 1,
+-                      .run_src = DI_SYNC_CLK,
+-              }
+-      };
+-
+-      ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
+-
+-      ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
+-}
+-
+-static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
+-              struct ipu_di_signal_cfg *sig, int div)
+-{
+-      u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
+-              sig->mode.hback_porch + sig->mode.hfront_porch;
+-      u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
+-              sig->mode.vback_porch + sig->mode.vfront_porch;
+-      struct di_sync_config cfg[] = {
+-              {
+-                      /* 1: INT_HSYNC */
+-                      .run_count = h_total - 1,
+-                      .run_src = DI_SYNC_CLK,
+-              } , {
+-                      /* PIN2: HSYNC */
+-                      .run_count = h_total - 1,
+-                      .run_src = DI_SYNC_CLK,
+-                      .offset_count = div * sig->v_to_h_sync,
+-                      .offset_src = DI_SYNC_CLK,
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
+-                      .cnt_down = sig->mode.hsync_len * 2,
+-              } , {
+-                      /* PIN3: VSYNC */
+-                      .run_count = v_total - 1,
+-                      .run_src = DI_SYNC_INT_HSYNC,
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+-                      .cnt_down = sig->mode.vsync_len * 2,
+-              } , {
+-                      /* 4: Line Active */
+-                      .run_src = DI_SYNC_HSYNC,
+-                      .offset_count = sig->mode.vsync_len +
+-                                      sig->mode.vback_porch,
+-                      .offset_src = DI_SYNC_HSYNC,
+-                      .repeat_count = sig->mode.vactive,
+-                      .cnt_clr_src = DI_SYNC_VSYNC,
+-              } , {
+-                      /* 5: Pixel Active, referenced by DC */
+-                      .run_src = DI_SYNC_CLK,
+-                      .offset_count = sig->mode.hsync_len +
+-                                      sig->mode.hback_porch,
+-                      .offset_src = DI_SYNC_CLK,
+-                      .repeat_count = sig->mode.hactive,
+-                      .cnt_clr_src = 5, /* Line Active */
+-              } , {
+-                      /* unused */
+-              } , {
+-                      /* unused */
+-              } , {
+-                      /* unused */
+-              } , {
+-                      /* unused */
+-              },
+-      };
+-      /* can't use #7 and #8 for line active and pixel active counters */
+-      struct di_sync_config cfg_vga[] = {
+-              {
+-                      /* 1: INT_HSYNC */
+-                      .run_count = h_total - 1,
+-                      .run_src = DI_SYNC_CLK,
+-              } , {
+-                      /* 2: VSYNC */
+-                      .run_count = v_total - 1,
+-                      .run_src = DI_SYNC_INT_HSYNC,
+-              } , {
+-                      /* 3: Line Active */
+-                      .run_src = DI_SYNC_INT_HSYNC,
+-                      .offset_count = sig->mode.vsync_len +
+-                                      sig->mode.vback_porch,
+-                      .offset_src = DI_SYNC_INT_HSYNC,
+-                      .repeat_count = sig->mode.vactive,
+-                      .cnt_clr_src = 3 /* VSYNC */,
+-              } , {
+-                      /* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
+-                      .run_count = h_total - 1,
+-                      .run_src = DI_SYNC_CLK,
+-                      .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
+-                      .offset_src = DI_SYNC_CLK,
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
+-                      .cnt_down = sig->mode.hsync_len * 2,
+-              } , {
+-                      /* 5: Pixel Active signal to DC */
+-                      .run_src = DI_SYNC_CLK,
+-                      .offset_count = sig->mode.hsync_len +
+-                                      sig->mode.hback_porch,
+-                      .offset_src = DI_SYNC_CLK,
+-                      .repeat_count = sig->mode.hactive,
+-                      .cnt_clr_src = 4, /* Line Active */
+-              } , {
+-                      /* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
+-                      .run_count = v_total - 1,
+-                      .run_src = DI_SYNC_INT_HSYNC,
+-                      .offset_count = 1, /* magic value from Freescale TVE driver */
+-                      .offset_src = DI_SYNC_INT_HSYNC,
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+-                      .cnt_down = sig->mode.vsync_len * 2,
+-              } , {
+-                      /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
+-                      .run_count = h_total - 1,
+-                      .run_src = DI_SYNC_CLK,
+-                      .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
+-                      .offset_src = DI_SYNC_CLK,
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
+-                      .cnt_down = sig->mode.hsync_len * 2,
+-              } , {
+-                      /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
+-                      .run_count = v_total - 1,
+-                      .run_src = DI_SYNC_INT_HSYNC,
+-                      .offset_count = 1, /* magic value from Freescale TVE driver */
+-                      .offset_src = DI_SYNC_INT_HSYNC,
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+-                      .cnt_down = sig->mode.vsync_len * 2,
+-              } , {
+-                      /* unused */
+-              },
+-      };
+-
+-      ipu_di_write(di, v_total - 1, DI_SCR_CONF);
+-      if (sig->hsync_pin == 2 && sig->vsync_pin == 3)
+-              ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
+-      else
+-              ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
+-}
+-
+-static void ipu_di_config_clock(struct ipu_di *di,
+-      const struct ipu_di_signal_cfg *sig)
+-{
+-      struct clk *clk;
+-      unsigned clkgen0;
+-      uint32_t val;
+-
+-      if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
+-              /*
+-               * CLKMODE_EXT means we must use the DI clock: this is
+-               * needed for things like LVDS which needs to feed the
+-               * DI and LDB with the same pixel clock.
+-               */
+-              clk = di->clk_di;
+-
+-              if (sig->clkflags & IPU_DI_CLKMODE_SYNC) {
+-                      /*
+-                       * CLKMODE_SYNC means that we want the DI to be
+-                       * clocked at the same rate as the parent clock.
+-                       * This is needed (eg) for LDB which needs to be
+-                       * fed with the same pixel clock.  We assume that
+-                       * the LDB clock has already been set correctly.
+-                       */
+-                      clkgen0 = 1 << 4;
+-              } else {
+-                      /*
+-                       * We can use the divider.  We should really have
+-                       * a flag here indicating whether the bridge can
+-                       * cope with a fractional divider or not.  For the
+-                       * time being, let's go for simplicitly and
+-                       * reliability.
+-                       */
+-                      unsigned long in_rate;
+-                      unsigned div;
+-
+-                      clk_set_rate(clk, sig->mode.pixelclock);
+-
+-                      in_rate = clk_get_rate(clk);
+-                      div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
+-                      div = clamp(div, 1U, 255U);
+-
+-                      clkgen0 = div << 4;
+-              }
+-      } else {
+-              /*
+-               * For other interfaces, we can arbitarily select between
+-               * the DI specific clock and the internal IPU clock.  See
+-               * DI_GENERAL bit 20.  We select the IPU clock if it can
+-               * give us a clock rate within 1% of the requested frequency,
+-               * otherwise we use the DI clock.
+-               */
+-              unsigned long rate, clkrate;
+-              unsigned div, error;
+-
+-              clkrate = clk_get_rate(di->clk_ipu);
+-              div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
+-              div = clamp(div, 1U, 255U);
+-              rate = clkrate / div;
+-
+-              error = rate / (sig->mode.pixelclock / 1000);
+-
+-              dev_dbg(di->ipu->dev, "  IPU clock can give %lu with divider %u, error %d.%u%%\n",
+-                      rate, div, (signed)(error - 1000) / 10, error % 10);
+-
+-              /* Allow a 1% error */
+-              if (error < 1010 && error >= 990) {
+-                      clk = di->clk_ipu;
+-
+-                      clkgen0 = div << 4;
+-              } else {
+-                      unsigned long in_rate;
+-                      unsigned div;
+-
+-                      clk = di->clk_di;
+-
+-                      clk_set_rate(clk, sig->mode.pixelclock);
+-
+-                      in_rate = clk_get_rate(clk);
+-                      div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
+-                      div = clamp(div, 1U, 255U);
+-
+-                      clkgen0 = div << 4;
+-              }
+-      }
+-
+-      di->clk_di_pixel = clk;
+-
+-      /* Set the divider */
+-      ipu_di_write(di, clkgen0, DI_BS_CLKGEN0);
+-
+-      /*
+-       * Set the high/low periods.  Bits 24:16 give us the falling edge,
+-       * and bits 8:0 give the rising edge.  LSB is fraction, and is
+-       * based on the divider above.  We want a 50% duty cycle, so set
+-       * the falling edge to be half the divider.
+-       */
+-      ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1);
+-
+-      /* Finally select the input clock */
+-      val = ipu_di_read(di, DI_GENERAL) & ~DI_GEN_DI_CLK_EXT;
+-      if (clk == di->clk_di)
+-              val |= DI_GEN_DI_CLK_EXT;
+-      ipu_di_write(di, val, DI_GENERAL);
+-
+-      dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
+-              sig->mode.pixelclock,
+-              clk_get_rate(di->clk_ipu),
+-              clk_get_rate(di->clk_di),
+-              clk == di->clk_di ? "DI" : "IPU",
+-              clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
+-}
+-
+-/*
+- * This function is called to adjust a video mode to IPU restrictions.
+- * It is meant to be called from drm crtc mode_fixup() methods.
+- */
+-int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode)
+-{
+-      u32 diff;
+-
+-      if (mode->vfront_porch >= 2)
+-              return 0;
+-
+-      diff = 2 - mode->vfront_porch;
+-
+-      if (mode->vback_porch >= diff) {
+-              mode->vfront_porch = 2;
+-              mode->vback_porch -= diff;
+-      } else if (mode->vsync_len > diff) {
+-              mode->vfront_porch = 2;
+-              mode->vsync_len = mode->vsync_len - diff;
+-      } else {
+-              dev_warn(di->ipu->dev, "failed to adjust videomode\n");
+-              return -EINVAL;
+-      }
+-
+-      dev_dbg(di->ipu->dev, "videomode adapted for IPU restrictions\n");
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode);
+-
+-static u32 ipu_di_gen_polarity(int pin)
+-{
+-      switch (pin) {
+-      case 1:
+-              return DI_GEN_POLARITY_1;
+-      case 2:
+-              return DI_GEN_POLARITY_2;
+-      case 3:
+-              return DI_GEN_POLARITY_3;
+-      case 4:
+-              return DI_GEN_POLARITY_4;
+-      case 5:
+-              return DI_GEN_POLARITY_5;
+-      case 6:
+-              return DI_GEN_POLARITY_6;
+-      case 7:
+-              return DI_GEN_POLARITY_7;
+-      case 8:
+-              return DI_GEN_POLARITY_8;
+-      }
+-      return 0;
+-}
+-
+-int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
+-{
+-      u32 reg;
+-      u32 di_gen, vsync_cnt;
+-      u32 div;
+-
+-      dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
+-              di->id, sig->mode.hactive, sig->mode.vactive);
+-
+-      dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
+-              clk_get_rate(di->clk_ipu),
+-              clk_get_rate(di->clk_di),
+-              sig->mode.pixelclock);
+-
+-      mutex_lock(&di_mutex);
+-
+-      ipu_di_config_clock(di, sig);
+-
+-      div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
+-      div = div / 16;         /* Now divider is integer portion */
+-
+-      /* Setup pixel clock timing */
+-      /* Down time is half of period */
+-      ipu_di_write(di, (div << 16), DI_BS_CLKGEN1);
+-
+-      ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1);
+-      ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
+-
+-      di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
+-      di_gen |= DI_GEN_DI_VSYNC_EXT;
+-
+-      if (sig->mode.flags & DISPLAY_FLAGS_INTERLACED) {
+-              ipu_di_sync_config_interlaced(di, sig);
+-
+-              /* set y_sel = 1 */
+-              di_gen |= 0x10000000;
+-
+-              vsync_cnt = 3;
+-      } else {
+-              ipu_di_sync_config_noninterlaced(di, sig, div);
+-
+-              vsync_cnt = 3;
+-              if (di->id == 1)
+-                      /*
+-                       * TODO: change only for TVEv2, parallel display
+-                       * uses pin 2 / 3
+-                       */
+-                      if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3))
+-                              vsync_cnt = 6;
+-      }
+-
+-      if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH)
+-              di_gen |= ipu_di_gen_polarity(sig->hsync_pin);
+-      if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH)
+-              di_gen |= ipu_di_gen_polarity(sig->vsync_pin);
+-
+-      if (sig->clk_pol)
+-              di_gen |= DI_GEN_POLARITY_DISP_CLK;
+-
+-      ipu_di_write(di, di_gen, DI_GENERAL);
+-
+-      ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
+-                   DI_SYNC_AS_GEN);
+-
+-      reg = ipu_di_read(di, DI_POL);
+-      reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
+-
+-      if (sig->enable_pol)
+-              reg |= DI_POL_DRDY_POLARITY_15;
+-      if (sig->data_pol)
+-              reg |= DI_POL_DRDY_DATA_POLARITY;
+-
+-      ipu_di_write(di, reg, DI_POL);
+-
+-      mutex_unlock(&di_mutex);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
+-
+-int ipu_di_enable(struct ipu_di *di)
+-{
+-      int ret;
+-
+-      WARN_ON(IS_ERR(di->clk_di_pixel));
+-
+-      ret = clk_prepare_enable(di->clk_di_pixel);
+-      if (ret)
+-              return ret;
+-
+-      ipu_module_enable(di->ipu, di->module);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_di_enable);
+-
+-int ipu_di_disable(struct ipu_di *di)
+-{
+-      WARN_ON(IS_ERR(di->clk_di_pixel));
+-
+-      ipu_module_disable(di->ipu, di->module);
+-
+-      clk_disable_unprepare(di->clk_di_pixel);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_di_disable);
+-
+-int ipu_di_get_num(struct ipu_di *di)
+-{
+-      return di->id;
+-}
+-EXPORT_SYMBOL_GPL(ipu_di_get_num);
+-
+-static DEFINE_MUTEX(ipu_di_lock);
+-
+-struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp)
+-{
+-      struct ipu_di *di;
+-
+-      if (disp > 1)
+-              return ERR_PTR(-EINVAL);
+-
+-      di = ipu->di_priv[disp];
+-
+-      mutex_lock(&ipu_di_lock);
+-
+-      if (di->inuse) {
+-              di = ERR_PTR(-EBUSY);
+-              goto out;
+-      }
+-
+-      di->inuse = true;
+-out:
+-      mutex_unlock(&ipu_di_lock);
+-
+-      return di;
+-}
+-EXPORT_SYMBOL_GPL(ipu_di_get);
+-
+-void ipu_di_put(struct ipu_di *di)
+-{
+-      mutex_lock(&ipu_di_lock);
+-
+-      di->inuse = false;
+-
+-      mutex_unlock(&ipu_di_lock);
+-}
+-EXPORT_SYMBOL_GPL(ipu_di_put);
+-
+-int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
+-              unsigned long base,
+-              u32 module, struct clk *clk_ipu)
+-{
+-      struct ipu_di *di;
+-
+-      if (id > 1)
+-              return -ENODEV;
+-
+-      di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
+-      if (!di)
+-              return -ENOMEM;
+-
+-      ipu->di_priv[id] = di;
+-
+-      di->clk_di = devm_clk_get(dev, id ? "di1" : "di0");
+-      if (IS_ERR(di->clk_di))
+-              return PTR_ERR(di->clk_di);
+-
+-      di->module = module;
+-      di->id = id;
+-      di->clk_ipu = clk_ipu;
+-      di->base = devm_ioremap(dev, base, PAGE_SIZE);
+-      if (!di->base)
+-              return -ENOMEM;
+-
+-      ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
+-
+-      dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n",
+-                      id, base, di->base);
+-      di->inuse = false;
+-      di->ipu = ipu;
+-
+-      return 0;
+-}
+-
+-void ipu_di_exit(struct ipu_soc *ipu, int id)
+-{
+-}
+--- a/drivers/gpu/ipu-v3/ipu-dmfc.c
++++ /dev/null
+@@ -1,214 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-#include <linux/export.h>
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/io.h>
+-
+-#include <video/imx-ipu-v3.h>
+-#include "ipu-prv.h"
+-
+-#define DMFC_RD_CHAN          0x0000
+-#define DMFC_WR_CHAN          0x0004
+-#define DMFC_WR_CHAN_DEF      0x0008
+-#define DMFC_DP_CHAN          0x000c
+-#define DMFC_DP_CHAN_DEF      0x0010
+-#define DMFC_GENERAL1         0x0014
+-#define DMFC_GENERAL2         0x0018
+-#define DMFC_IC_CTRL          0x001c
+-#define DMFC_WR_CHAN_ALT      0x0020
+-#define DMFC_WR_CHAN_DEF_ALT  0x0024
+-#define DMFC_DP_CHAN_ALT      0x0028
+-#define DMFC_DP_CHAN_DEF_ALT  0x002c
+-#define DMFC_GENERAL1_ALT     0x0030
+-#define DMFC_STAT             0x0034
+-
+-#define DMFC_WR_CHAN_1_28             0
+-#define DMFC_WR_CHAN_2_41             8
+-#define DMFC_WR_CHAN_1C_42            16
+-#define DMFC_WR_CHAN_2C_43            24
+-
+-#define DMFC_DP_CHAN_5B_23            0
+-#define DMFC_DP_CHAN_5F_27            8
+-#define DMFC_DP_CHAN_6B_24            16
+-#define DMFC_DP_CHAN_6F_29            24
+-
+-struct dmfc_channel_data {
+-      int             ipu_channel;
+-      unsigned long   channel_reg;
+-      unsigned long   shift;
+-      unsigned        eot_shift;
+-      unsigned        max_fifo_lines;
+-};
+-
+-static const struct dmfc_channel_data dmfcdata[] = {
+-      {
+-              .ipu_channel    = IPUV3_CHANNEL_MEM_BG_SYNC,
+-              .channel_reg    = DMFC_DP_CHAN,
+-              .shift          = DMFC_DP_CHAN_5B_23,
+-              .eot_shift      = 20,
+-              .max_fifo_lines = 3,
+-      }, {
+-              .ipu_channel    = 24,
+-              .channel_reg    = DMFC_DP_CHAN,
+-              .shift          = DMFC_DP_CHAN_6B_24,
+-              .eot_shift      = 22,
+-              .max_fifo_lines = 1,
+-      }, {
+-              .ipu_channel    = IPUV3_CHANNEL_MEM_FG_SYNC,
+-              .channel_reg    = DMFC_DP_CHAN,
+-              .shift          = DMFC_DP_CHAN_5F_27,
+-              .eot_shift      = 21,
+-              .max_fifo_lines = 2,
+-      }, {
+-              .ipu_channel    = IPUV3_CHANNEL_MEM_DC_SYNC,
+-              .channel_reg    = DMFC_WR_CHAN,
+-              .shift          = DMFC_WR_CHAN_1_28,
+-              .eot_shift      = 16,
+-              .max_fifo_lines = 2,
+-      }, {
+-              .ipu_channel    = 29,
+-              .channel_reg    = DMFC_DP_CHAN,
+-              .shift          = DMFC_DP_CHAN_6F_29,
+-              .eot_shift      = 23,
+-              .max_fifo_lines = 1,
+-      },
+-};
+-
+-#define DMFC_NUM_CHANNELS     ARRAY_SIZE(dmfcdata)
+-
+-struct ipu_dmfc_priv;
+-
+-struct dmfc_channel {
+-      unsigned                        slots;
+-      struct ipu_soc                  *ipu;
+-      struct ipu_dmfc_priv            *priv;
+-      const struct dmfc_channel_data  *data;
+-};
+-
+-struct ipu_dmfc_priv {
+-      struct ipu_soc *ipu;
+-      struct device *dev;
+-      struct dmfc_channel channels[DMFC_NUM_CHANNELS];
+-      struct mutex mutex;
+-      void __iomem *base;
+-      int use_count;
+-};
+-
+-int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
+-{
+-      struct ipu_dmfc_priv *priv = dmfc->priv;
+-      mutex_lock(&priv->mutex);
+-
+-      if (!priv->use_count)
+-              ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
+-
+-      priv->use_count++;
+-
+-      mutex_unlock(&priv->mutex);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
+-
+-void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
+-{
+-      struct ipu_dmfc_priv *priv = dmfc->priv;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      priv->use_count--;
+-
+-      if (!priv->use_count)
+-              ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
+-
+-      if (priv->use_count < 0)
+-              priv->use_count = 0;
+-
+-      mutex_unlock(&priv->mutex);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
+-
+-void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width)
+-{
+-      struct ipu_dmfc_priv *priv = dmfc->priv;
+-      u32 dmfc_gen1;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
+-
+-      if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
+-              dmfc_gen1 |= 1 << dmfc->data->eot_shift;
+-      else
+-              dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
+-
+-      writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
+-
+-      mutex_unlock(&priv->mutex);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
+-
+-struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
+-{
+-      struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
+-      int i;
+-
+-      for (i = 0; i < DMFC_NUM_CHANNELS; i++)
+-              if (dmfcdata[i].ipu_channel == ipu_channel)
+-                      return &priv->channels[i];
+-      return ERR_PTR(-ENODEV);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dmfc_get);
+-
+-void ipu_dmfc_put(struct dmfc_channel *dmfc)
+-{
+-}
+-EXPORT_SYMBOL_GPL(ipu_dmfc_put);
+-
+-int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
+-              struct clk *ipu_clk)
+-{
+-      struct ipu_dmfc_priv *priv;
+-      int i;
+-
+-      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-      if (!priv)
+-              return -ENOMEM;
+-
+-      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+-      if (!priv->base)
+-              return -ENOMEM;
+-
+-      priv->dev = dev;
+-      priv->ipu = ipu;
+-      mutex_init(&priv->mutex);
+-
+-      ipu->dmfc_priv = priv;
+-
+-      for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
+-              priv->channels[i].priv = priv;
+-              priv->channels[i].ipu = ipu;
+-              priv->channels[i].data = &dmfcdata[i];
+-
+-              if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC ||
+-                  dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC ||
+-                  dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC)
+-                      priv->channels[i].slots = 2;
+-      }
+-
+-      writel(0x00000050, priv->base + DMFC_WR_CHAN);
+-      writel(0x00005654, priv->base + DMFC_DP_CHAN);
+-      writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
+-      writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
+-      writel(0x00000003, priv->base + DMFC_GENERAL1);
+-
+-      return 0;
+-}
+-
+-void ipu_dmfc_exit(struct ipu_soc *ipu)
+-{
+-}
+--- a/drivers/gpu/ipu-v3/ipu-dp.c
++++ /dev/null
+@@ -1,357 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-#include <linux/export.h>
+-#include <linux/kernel.h>
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/io.h>
+-#include <linux/err.h>
+-
+-#include <video/imx-ipu-v3.h>
+-#include "ipu-prv.h"
+-
+-#define DP_SYNC 0
+-#define DP_ASYNC0 0x60
+-#define DP_ASYNC1 0xBC
+-
+-#define DP_COM_CONF           0x0
+-#define DP_GRAPH_WIND_CTRL    0x0004
+-#define DP_FG_POS             0x0008
+-#define DP_CSC_A_0            0x0044
+-#define DP_CSC_A_1            0x0048
+-#define DP_CSC_A_2            0x004C
+-#define DP_CSC_A_3            0x0050
+-#define DP_CSC_0              0x0054
+-#define DP_CSC_1              0x0058
+-
+-#define DP_COM_CONF_FG_EN             (1 << 0)
+-#define DP_COM_CONF_GWSEL             (1 << 1)
+-#define DP_COM_CONF_GWAM              (1 << 2)
+-#define DP_COM_CONF_GWCKE             (1 << 3)
+-#define DP_COM_CONF_CSC_DEF_MASK      (3 << 8)
+-#define DP_COM_CONF_CSC_DEF_OFFSET    8
+-#define DP_COM_CONF_CSC_DEF_FG                (3 << 8)
+-#define DP_COM_CONF_CSC_DEF_BG                (2 << 8)
+-#define DP_COM_CONF_CSC_DEF_BOTH      (1 << 8)
+-
+-#define IPUV3_NUM_FLOWS               3
+-
+-struct ipu_dp_priv;
+-
+-struct ipu_dp {
+-      u32 flow;
+-      bool in_use;
+-      bool foreground;
+-      enum ipu_color_space in_cs;
+-};
+-
+-struct ipu_flow {
+-      struct ipu_dp foreground;
+-      struct ipu_dp background;
+-      enum ipu_color_space out_cs;
+-      void __iomem *base;
+-      struct ipu_dp_priv *priv;
+-};
+-
+-struct ipu_dp_priv {
+-      struct ipu_soc *ipu;
+-      struct device *dev;
+-      void __iomem *base;
+-      struct ipu_flow flow[IPUV3_NUM_FLOWS];
+-      struct mutex mutex;
+-      int use_count;
+-};
+-
+-static u32 ipu_dp_flow_base[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1};
+-
+-static inline struct ipu_flow *to_flow(struct ipu_dp *dp)
+-{
+-      if (dp->foreground)
+-              return container_of(dp, struct ipu_flow, foreground);
+-      else
+-              return container_of(dp, struct ipu_flow, background);
+-}
+-
+-int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable,
+-              u8 alpha, bool bg_chan)
+-{
+-      struct ipu_flow *flow = to_flow(dp);
+-      struct ipu_dp_priv *priv = flow->priv;
+-      u32 reg;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      reg = readl(flow->base + DP_COM_CONF);
+-      if (bg_chan)
+-              reg &= ~DP_COM_CONF_GWSEL;
+-      else
+-              reg |= DP_COM_CONF_GWSEL;
+-      writel(reg, flow->base + DP_COM_CONF);
+-
+-      if (enable) {
+-              reg = readl(flow->base + DP_GRAPH_WIND_CTRL) & 0x00FFFFFFL;
+-              writel(reg | ((u32) alpha << 24),
+-                           flow->base + DP_GRAPH_WIND_CTRL);
+-
+-              reg = readl(flow->base + DP_COM_CONF);
+-              writel(reg | DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
+-      } else {
+-              reg = readl(flow->base + DP_COM_CONF);
+-              writel(reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
+-      }
+-
+-      ipu_srm_dp_update(priv->ipu, true);
+-
+-      mutex_unlock(&priv->mutex);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha);
+-
+-int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
+-{
+-      struct ipu_flow *flow = to_flow(dp);
+-      struct ipu_dp_priv *priv = flow->priv;
+-
+-      writel((x_pos << 16) | y_pos, flow->base + DP_FG_POS);
+-
+-      ipu_srm_dp_update(priv->ipu, true);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos);
+-
+-static void ipu_dp_csc_init(struct ipu_flow *flow,
+-              enum ipu_color_space in,
+-              enum ipu_color_space out,
+-              u32 place)
+-{
+-      u32 reg;
+-
+-      reg = readl(flow->base + DP_COM_CONF);
+-      reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+-
+-      if (in == out) {
+-              writel(reg, flow->base + DP_COM_CONF);
+-              return;
+-      }
+-
+-      if (in == IPUV3_COLORSPACE_RGB && out == IPUV3_COLORSPACE_YUV) {
+-              writel(0x099 | (0x12d << 16), flow->base + DP_CSC_A_0);
+-              writel(0x03a | (0x3a9 << 16), flow->base + DP_CSC_A_1);
+-              writel(0x356 | (0x100 << 16), flow->base + DP_CSC_A_2);
+-              writel(0x100 | (0x329 << 16), flow->base + DP_CSC_A_3);
+-              writel(0x3d6 | (0x0000 << 16) | (2 << 30),
+-                              flow->base + DP_CSC_0);
+-              writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30),
+-                              flow->base + DP_CSC_1);
+-      } else {
+-              writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0);
+-              writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1);
+-              writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2);
+-              writel(0x095 | (0x0ff << 16), flow->base + DP_CSC_A_3);
+-              writel(0x000 | (0x3e42 << 16) | (1 << 30),
+-                              flow->base + DP_CSC_0);
+-              writel(0x10a | (1 << 14) | (0x3dd6 << 16) | (1 << 30),
+-                              flow->base + DP_CSC_1);
+-      }
+-
+-      reg |= place;
+-
+-      writel(reg, flow->base + DP_COM_CONF);
+-}
+-
+-int ipu_dp_setup_channel(struct ipu_dp *dp,
+-              enum ipu_color_space in,
+-              enum ipu_color_space out)
+-{
+-      struct ipu_flow *flow = to_flow(dp);
+-      struct ipu_dp_priv *priv = flow->priv;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      dp->in_cs = in;
+-
+-      if (!dp->foreground)
+-              flow->out_cs = out;
+-
+-      if (flow->foreground.in_cs == flow->background.in_cs) {
+-              /*
+-               * foreground and background are of same colorspace, put
+-               * colorspace converter after combining unit.
+-               */
+-              ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs,
+-                              DP_COM_CONF_CSC_DEF_BOTH);
+-      } else {
+-              if (flow->foreground.in_cs == IPUV3_COLORSPACE_UNKNOWN ||
+-                  flow->foreground.in_cs == flow->out_cs)
+-                      /*
+-                       * foreground identical to output, apply color
+-                       * conversion on background
+-                       */
+-                      ipu_dp_csc_init(flow, flow->background.in_cs,
+-                                      flow->out_cs, DP_COM_CONF_CSC_DEF_BG);
+-              else
+-                      ipu_dp_csc_init(flow, flow->foreground.in_cs,
+-                                      flow->out_cs, DP_COM_CONF_CSC_DEF_FG);
+-      }
+-
+-      ipu_srm_dp_update(priv->ipu, true);
+-
+-      mutex_unlock(&priv->mutex);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
+-
+-int ipu_dp_enable(struct ipu_soc *ipu)
+-{
+-      struct ipu_dp_priv *priv = ipu->dp_priv;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      if (!priv->use_count)
+-              ipu_module_enable(priv->ipu, IPU_CONF_DP_EN);
+-
+-      priv->use_count++;
+-
+-      mutex_unlock(&priv->mutex);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_enable);
+-
+-int ipu_dp_enable_channel(struct ipu_dp *dp)
+-{
+-      struct ipu_flow *flow = to_flow(dp);
+-      struct ipu_dp_priv *priv = flow->priv;
+-      u32 reg;
+-
+-      if (!dp->foreground)
+-              return 0;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      reg = readl(flow->base + DP_COM_CONF);
+-      reg |= DP_COM_CONF_FG_EN;
+-      writel(reg, flow->base + DP_COM_CONF);
+-
+-      ipu_srm_dp_update(priv->ipu, true);
+-
+-      mutex_unlock(&priv->mutex);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
+-
+-void ipu_dp_disable_channel(struct ipu_dp *dp, bool sync)
+-{
+-      struct ipu_flow *flow = to_flow(dp);
+-      struct ipu_dp_priv *priv = flow->priv;
+-      u32 reg, csc;
+-
+-      dp->in_cs = IPUV3_COLORSPACE_UNKNOWN;
+-
+-      if (!dp->foreground)
+-              return;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      reg = readl(flow->base + DP_COM_CONF);
+-      csc = reg & DP_COM_CONF_CSC_DEF_MASK;
+-      reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+-      if (csc == DP_COM_CONF_CSC_DEF_BOTH || csc == DP_COM_CONF_CSC_DEF_BG)
+-              reg |= DP_COM_CONF_CSC_DEF_BG;
+-
+-      reg &= ~DP_COM_CONF_FG_EN;
+-      writel(reg, flow->base + DP_COM_CONF);
+-
+-      writel(0, flow->base + DP_FG_POS);
+-      ipu_srm_dp_update(priv->ipu, sync);
+-
+-      mutex_unlock(&priv->mutex);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
+-
+-void ipu_dp_disable(struct ipu_soc *ipu)
+-{
+-      struct ipu_dp_priv *priv = ipu->dp_priv;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      priv->use_count--;
+-
+-      if (!priv->use_count)
+-              ipu_module_disable(priv->ipu, IPU_CONF_DP_EN);
+-
+-      if (priv->use_count < 0)
+-              priv->use_count = 0;
+-
+-      mutex_unlock(&priv->mutex);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_disable);
+-
+-struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
+-{
+-      struct ipu_dp_priv *priv = ipu->dp_priv;
+-      struct ipu_dp *dp;
+-
+-      if ((flow >> 1) >= IPUV3_NUM_FLOWS)
+-              return ERR_PTR(-EINVAL);
+-
+-      if (flow & 1)
+-              dp = &priv->flow[flow >> 1].foreground;
+-      else
+-              dp = &priv->flow[flow >> 1].background;
+-
+-      if (dp->in_use)
+-              return ERR_PTR(-EBUSY);
+-
+-      dp->in_use = true;
+-
+-      return dp;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_get);
+-
+-void ipu_dp_put(struct ipu_dp *dp)
+-{
+-      dp->in_use = false;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_put);
+-
+-int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
+-{
+-      struct ipu_dp_priv *priv;
+-      int i;
+-
+-      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-      if (!priv)
+-              return -ENOMEM;
+-      priv->dev = dev;
+-      priv->ipu = ipu;
+-
+-      ipu->dp_priv = priv;
+-
+-      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+-      if (!priv->base)
+-              return -ENOMEM;
+-
+-      mutex_init(&priv->mutex);
+-
+-      for (i = 0; i < IPUV3_NUM_FLOWS; i++) {
+-              priv->flow[i].background.in_cs = IPUV3_COLORSPACE_UNKNOWN;
+-              priv->flow[i].foreground.in_cs = IPUV3_COLORSPACE_UNKNOWN;
+-              priv->flow[i].foreground.foreground = true;
+-              priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
+-              priv->flow[i].priv = priv;
+-      }
+-
+-      return 0;
+-}
+-
+-void ipu_dp_exit(struct ipu_soc *ipu)
+-{
+-}
+--- a/drivers/gpu/ipu-v3/ipu-ic.c
++++ /dev/null
+@@ -1,761 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (C) 2012-2014 Mentor Graphics Inc.
+- * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+- */
+-
+-#include <linux/types.h>
+-#include <linux/init.h>
+-#include <linux/errno.h>
+-#include <linux/spinlock.h>
+-#include <linux/bitrev.h>
+-#include <linux/io.h>
+-#include <linux/err.h>
+-#include <linux/sizes.h>
+-#include "ipu-prv.h"
+-
+-/* IC Register Offsets */
+-#define IC_CONF                 0x0000
+-#define IC_PRP_ENC_RSC          0x0004
+-#define IC_PRP_VF_RSC           0x0008
+-#define IC_PP_RSC               0x000C
+-#define IC_CMBP_1               0x0010
+-#define IC_CMBP_2               0x0014
+-#define IC_IDMAC_1              0x0018
+-#define IC_IDMAC_2              0x001C
+-#define IC_IDMAC_3              0x0020
+-#define IC_IDMAC_4              0x0024
+-
+-/* IC Register Fields */
+-#define IC_CONF_PRPENC_EN       (1 << 0)
+-#define IC_CONF_PRPENC_CSC1     (1 << 1)
+-#define IC_CONF_PRPENC_ROT_EN   (1 << 2)
+-#define IC_CONF_PRPVF_EN        (1 << 8)
+-#define IC_CONF_PRPVF_CSC1      (1 << 9)
+-#define IC_CONF_PRPVF_CSC2      (1 << 10)
+-#define IC_CONF_PRPVF_CMB       (1 << 11)
+-#define IC_CONF_PRPVF_ROT_EN    (1 << 12)
+-#define IC_CONF_PP_EN           (1 << 16)
+-#define IC_CONF_PP_CSC1         (1 << 17)
+-#define IC_CONF_PP_CSC2         (1 << 18)
+-#define IC_CONF_PP_CMB          (1 << 19)
+-#define IC_CONF_PP_ROT_EN       (1 << 20)
+-#define IC_CONF_IC_GLB_LOC_A    (1 << 28)
+-#define IC_CONF_KEY_COLOR_EN    (1 << 29)
+-#define IC_CONF_RWS_EN          (1 << 30)
+-#define IC_CONF_CSI_MEM_WR_EN   (1 << 31)
+-
+-#define IC_IDMAC_1_CB0_BURST_16         (1 << 0)
+-#define IC_IDMAC_1_CB1_BURST_16         (1 << 1)
+-#define IC_IDMAC_1_CB2_BURST_16         (1 << 2)
+-#define IC_IDMAC_1_CB3_BURST_16         (1 << 3)
+-#define IC_IDMAC_1_CB4_BURST_16         (1 << 4)
+-#define IC_IDMAC_1_CB5_BURST_16         (1 << 5)
+-#define IC_IDMAC_1_CB6_BURST_16         (1 << 6)
+-#define IC_IDMAC_1_CB7_BURST_16         (1 << 7)
+-#define IC_IDMAC_1_PRPENC_ROT_MASK      (0x7 << 11)
+-#define IC_IDMAC_1_PRPENC_ROT_OFFSET    11
+-#define IC_IDMAC_1_PRPVF_ROT_MASK       (0x7 << 14)
+-#define IC_IDMAC_1_PRPVF_ROT_OFFSET     14
+-#define IC_IDMAC_1_PP_ROT_MASK          (0x7 << 17)
+-#define IC_IDMAC_1_PP_ROT_OFFSET        17
+-#define IC_IDMAC_1_PP_FLIP_RS           (1 << 22)
+-#define IC_IDMAC_1_PRPVF_FLIP_RS        (1 << 21)
+-#define IC_IDMAC_1_PRPENC_FLIP_RS       (1 << 20)
+-
+-#define IC_IDMAC_2_PRPENC_HEIGHT_MASK   (0x3ff << 0)
+-#define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0
+-#define IC_IDMAC_2_PRPVF_HEIGHT_MASK    (0x3ff << 10)
+-#define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET  10
+-#define IC_IDMAC_2_PP_HEIGHT_MASK       (0x3ff << 20)
+-#define IC_IDMAC_2_PP_HEIGHT_OFFSET     20
+-
+-#define IC_IDMAC_3_PRPENC_WIDTH_MASK    (0x3ff << 0)
+-#define IC_IDMAC_3_PRPENC_WIDTH_OFFSET  0
+-#define IC_IDMAC_3_PRPVF_WIDTH_MASK     (0x3ff << 10)
+-#define IC_IDMAC_3_PRPVF_WIDTH_OFFSET   10
+-#define IC_IDMAC_3_PP_WIDTH_MASK        (0x3ff << 20)
+-#define IC_IDMAC_3_PP_WIDTH_OFFSET      20
+-
+-struct ic_task_regoffs {
+-      u32 rsc;
+-      u32 tpmem_csc[2];
+-};
+-
+-struct ic_task_bitfields {
+-      u32 ic_conf_en;
+-      u32 ic_conf_rot_en;
+-      u32 ic_conf_cmb_en;
+-      u32 ic_conf_csc1_en;
+-      u32 ic_conf_csc2_en;
+-      u32 ic_cmb_galpha_bit;
+-};
+-
+-static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
+-      [IC_TASK_ENCODER] = {
+-              .rsc = IC_PRP_ENC_RSC,
+-              .tpmem_csc = {0x2008, 0},
+-      },
+-      [IC_TASK_VIEWFINDER] = {
+-              .rsc = IC_PRP_VF_RSC,
+-              .tpmem_csc = {0x4028, 0x4040},
+-      },
+-      [IC_TASK_POST_PROCESSOR] = {
+-              .rsc = IC_PP_RSC,
+-              .tpmem_csc = {0x6060, 0x6078},
+-      },
+-};
+-
+-static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = {
+-      [IC_TASK_ENCODER] = {
+-              .ic_conf_en = IC_CONF_PRPENC_EN,
+-              .ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN,
+-              .ic_conf_cmb_en = 0,    /* NA */
+-              .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
+-              .ic_conf_csc2_en = 0,   /* NA */
+-              .ic_cmb_galpha_bit = 0, /* NA */
+-      },
+-      [IC_TASK_VIEWFINDER] = {
+-              .ic_conf_en = IC_CONF_PRPVF_EN,
+-              .ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN,
+-              .ic_conf_cmb_en = IC_CONF_PRPVF_CMB,
+-              .ic_conf_csc1_en = IC_CONF_PRPVF_CSC1,
+-              .ic_conf_csc2_en = IC_CONF_PRPVF_CSC2,
+-              .ic_cmb_galpha_bit = 0,
+-      },
+-      [IC_TASK_POST_PROCESSOR] = {
+-              .ic_conf_en = IC_CONF_PP_EN,
+-              .ic_conf_rot_en = IC_CONF_PP_ROT_EN,
+-              .ic_conf_cmb_en = IC_CONF_PP_CMB,
+-              .ic_conf_csc1_en = IC_CONF_PP_CSC1,
+-              .ic_conf_csc2_en = IC_CONF_PP_CSC2,
+-              .ic_cmb_galpha_bit = 8,
+-      },
+-};
+-
+-struct ipu_ic_priv;
+-
+-struct ipu_ic {
+-      enum ipu_ic_task task;
+-      const struct ic_task_regoffs *reg;
+-      const struct ic_task_bitfields *bit;
+-
+-      struct ipu_ic_colorspace in_cs;
+-      struct ipu_ic_colorspace g_in_cs;
+-      struct ipu_ic_colorspace out_cs;
+-
+-      bool graphics;
+-      bool rotation;
+-      bool in_use;
+-
+-      struct ipu_ic_priv *priv;
+-};
+-
+-struct ipu_ic_priv {
+-      void __iomem *base;
+-      void __iomem *tpmem_base;
+-      spinlock_t lock;
+-      struct ipu_soc *ipu;
+-      int use_count;
+-      int irt_use_count;
+-      struct ipu_ic task[IC_NUM_TASKS];
+-};
+-
+-static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset)
+-{
+-      return readl(ic->priv->base + offset);
+-}
+-
+-static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset)
+-{
+-      writel(value, ic->priv->base + offset);
+-}
+-
+-static int init_csc(struct ipu_ic *ic,
+-                  const struct ipu_ic_csc *csc,
+-                  int csc_index)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      u32 __iomem *base;
+-      const u16 (*c)[3];
+-      const u16 *a;
+-      u32 param;
+-
+-      base = (u32 __iomem *)
+-              (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
+-
+-      /* Cast to unsigned */
+-      c = (const u16 (*)[3])csc->params.coeff;
+-      a = (const u16 *)csc->params.offset;
+-
+-      param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) |
+-              ((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff);
+-      writel(param, base++);
+-
+-      param = ((a[0] & 0x1fe0) >> 5) | (csc->params.scale << 8) |
+-              (csc->params.sat << 10);
+-      writel(param, base++);
+-
+-      param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
+-              ((c[1][0] & 0x1ff) << 9) | (c[2][0] & 0x1ff);
+-      writel(param, base++);
+-
+-      param = ((a[1] & 0x1fe0) >> 5);
+-      writel(param, base++);
+-
+-      param = ((a[2] & 0x1f) << 27) | ((c[0][2] & 0x1ff) << 18) |
+-              ((c[1][2] & 0x1ff) << 9) | (c[2][1] & 0x1ff);
+-      writel(param, base++);
+-
+-      param = ((a[2] & 0x1fe0) >> 5);
+-      writel(param, base++);
+-
+-      return 0;
+-}
+-
+-static int calc_resize_coeffs(struct ipu_ic *ic,
+-                            u32 in_size, u32 out_size,
+-                            u32 *resize_coeff,
+-                            u32 *downsize_coeff)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      struct ipu_soc *ipu = priv->ipu;
+-      u32 temp_size, temp_downsize;
+-
+-      /*
+-       * Input size cannot be more than 4096, and output size cannot
+-       * be more than 1024
+-       */
+-      if (in_size > 4096) {
+-              dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
+-              return -EINVAL;
+-      }
+-      if (out_size > 1024) {
+-              dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
+-              return -EINVAL;
+-      }
+-
+-      /* Cannot downsize more than 4:1 */
+-      if ((out_size << 2) < in_size) {
+-              dev_err(ipu->dev, "Unsupported downsize\n");
+-              return -EINVAL;
+-      }
+-
+-      /* Compute downsizing coefficient */
+-      temp_downsize = 0;
+-      temp_size = in_size;
+-      while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
+-             (temp_downsize < 2)) {
+-              temp_size >>= 1;
+-              temp_downsize++;
+-      }
+-      *downsize_coeff = temp_downsize;
+-
+-      /*
+-       * compute resizing coefficient using the following equation:
+-       * resize_coeff = M * (SI - 1) / (SO - 1)
+-       * where M = 2^13, SI = input size, SO = output size
+-       */
+-      *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
+-      if (*resize_coeff >= 16384L) {
+-              dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
+-              *resize_coeff = 0x3FFF;
+-      }
+-
+-      return 0;
+-}
+-
+-void ipu_ic_task_enable(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      unsigned long flags;
+-      u32 ic_conf;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      ic_conf = ipu_ic_read(ic, IC_CONF);
+-
+-      ic_conf |= ic->bit->ic_conf_en;
+-
+-      if (ic->rotation)
+-              ic_conf |= ic->bit->ic_conf_rot_en;
+-
+-      if (ic->in_cs.cs != ic->out_cs.cs)
+-              ic_conf |= ic->bit->ic_conf_csc1_en;
+-
+-      if (ic->graphics) {
+-              ic_conf |= ic->bit->ic_conf_cmb_en;
+-              ic_conf |= ic->bit->ic_conf_csc1_en;
+-
+-              if (ic->g_in_cs.cs != ic->out_cs.cs)
+-                      ic_conf |= ic->bit->ic_conf_csc2_en;
+-      }
+-
+-      ipu_ic_write(ic, ic_conf, IC_CONF);
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_task_enable);
+-
+-void ipu_ic_task_disable(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      unsigned long flags;
+-      u32 ic_conf;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      ic_conf = ipu_ic_read(ic, IC_CONF);
+-
+-      ic_conf &= ~(ic->bit->ic_conf_en |
+-                   ic->bit->ic_conf_csc1_en |
+-                   ic->bit->ic_conf_rot_en);
+-      if (ic->bit->ic_conf_csc2_en)
+-              ic_conf &= ~ic->bit->ic_conf_csc2_en;
+-      if (ic->bit->ic_conf_cmb_en)
+-              ic_conf &= ~ic->bit->ic_conf_cmb_en;
+-
+-      ipu_ic_write(ic, ic_conf, IC_CONF);
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
+-
+-int ipu_ic_task_graphics_init(struct ipu_ic *ic,
+-                            const struct ipu_ic_colorspace *g_in_cs,
+-                            bool galpha_en, u32 galpha,
+-                            bool colorkey_en, u32 colorkey)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      struct ipu_ic_csc csc2;
+-      unsigned long flags;
+-      u32 reg, ic_conf;
+-      int ret = 0;
+-
+-      if (ic->task == IC_TASK_ENCODER)
+-              return -EINVAL;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      ic_conf = ipu_ic_read(ic, IC_CONF);
+-
+-      if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
+-              struct ipu_ic_csc csc1;
+-
+-              ret = ipu_ic_calc_csc(&csc1,
+-                                    V4L2_YCBCR_ENC_601,
+-                                    V4L2_QUANTIZATION_FULL_RANGE,
+-                                    IPUV3_COLORSPACE_RGB,
+-                                    V4L2_YCBCR_ENC_601,
+-                                    V4L2_QUANTIZATION_FULL_RANGE,
+-                                    IPUV3_COLORSPACE_RGB);
+-              if (ret)
+-                      goto unlock;
+-
+-              /* need transparent CSC1 conversion */
+-              ret = init_csc(ic, &csc1, 0);
+-              if (ret)
+-                      goto unlock;
+-      }
+-
+-      ic->g_in_cs = *g_in_cs;
+-      csc2.in_cs = ic->g_in_cs;
+-      csc2.out_cs = ic->out_cs;
+-
+-      ret = __ipu_ic_calc_csc(&csc2);
+-      if (ret)
+-              goto unlock;
+-
+-      ret = init_csc(ic, &csc2, 1);
+-      if (ret)
+-              goto unlock;
+-
+-      if (galpha_en) {
+-              ic_conf |= IC_CONF_IC_GLB_LOC_A;
+-              reg = ipu_ic_read(ic, IC_CMBP_1);
+-              reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit);
+-              reg |= (galpha << ic->bit->ic_cmb_galpha_bit);
+-              ipu_ic_write(ic, reg, IC_CMBP_1);
+-      } else
+-              ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
+-
+-      if (colorkey_en) {
+-              ic_conf |= IC_CONF_KEY_COLOR_EN;
+-              ipu_ic_write(ic, colorkey, IC_CMBP_2);
+-      } else
+-              ic_conf &= ~IC_CONF_KEY_COLOR_EN;
+-
+-      ipu_ic_write(ic, ic_conf, IC_CONF);
+-
+-      ic->graphics = true;
+-unlock:
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
+-
+-int ipu_ic_task_init_rsc(struct ipu_ic *ic,
+-                       const struct ipu_ic_csc *csc,
+-                       int in_width, int in_height,
+-                       int out_width, int out_height,
+-                       u32 rsc)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      u32 downsize_coeff, resize_coeff;
+-      unsigned long flags;
+-      int ret = 0;
+-
+-      if (!rsc) {
+-              /* Setup vertical resizing */
+-
+-              ret = calc_resize_coeffs(ic, in_height, out_height,
+-                                       &resize_coeff, &downsize_coeff);
+-              if (ret)
+-                      return ret;
+-
+-              rsc = (downsize_coeff << 30) | (resize_coeff << 16);
+-
+-              /* Setup horizontal resizing */
+-              ret = calc_resize_coeffs(ic, in_width, out_width,
+-                                       &resize_coeff, &downsize_coeff);
+-              if (ret)
+-                      return ret;
+-
+-              rsc |= (downsize_coeff << 14) | resize_coeff;
+-      }
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      ipu_ic_write(ic, rsc, ic->reg->rsc);
+-
+-      /* Setup color space conversion */
+-      ic->in_cs = csc->in_cs;
+-      ic->out_cs = csc->out_cs;
+-
+-      ret = init_csc(ic, csc, 0);
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-      return ret;
+-}
+-
+-int ipu_ic_task_init(struct ipu_ic *ic,
+-                   const struct ipu_ic_csc *csc,
+-                   int in_width, int in_height,
+-                   int out_width, int out_height)
+-{
+-      return ipu_ic_task_init_rsc(ic, csc,
+-                                  in_width, in_height,
+-                                  out_width, out_height, 0);
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_task_init);
+-
+-int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
+-                        u32 width, u32 height, int burst_size,
+-                        enum ipu_rotate_mode rot)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      struct ipu_soc *ipu = priv->ipu;
+-      u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
+-      u32 temp_rot = bitrev8(rot) >> 5;
+-      bool need_hor_flip = false;
+-      unsigned long flags;
+-      int ret = 0;
+-
+-      if ((burst_size != 8) && (burst_size != 16)) {
+-              dev_err(ipu->dev, "Illegal burst length for IC\n");
+-              return -EINVAL;
+-      }
+-
+-      width--;
+-      height--;
+-
+-      if (temp_rot & 0x2)     /* Need horizontal flip */
+-              need_hor_flip = true;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1);
+-      ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2);
+-      ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3);
+-
+-      switch (channel->num) {
+-      case IPUV3_CHANNEL_IC_PP_MEM:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
+-
+-              if (need_hor_flip)
+-                      ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
+-
+-              ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
+-              ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
+-
+-              ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
+-              ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
+-              break;
+-      case IPUV3_CHANNEL_MEM_IC_PP:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
+-              break;
+-      case IPUV3_CHANNEL_MEM_ROT_PP:
+-              ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
+-              ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
+-              break;
+-      case IPUV3_CHANNEL_MEM_IC_PRP_VF:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
+-              break;
+-      case IPUV3_CHANNEL_IC_PRP_ENC_MEM:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
+-
+-              if (need_hor_flip)
+-                      ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
+-
+-              ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
+-              ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
+-
+-              ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
+-              ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
+-              break;
+-      case IPUV3_CHANNEL_MEM_ROT_ENC:
+-              ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
+-              ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
+-              break;
+-      case IPUV3_CHANNEL_IC_PRP_VF_MEM:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
+-
+-              if (need_hor_flip)
+-                      ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
+-
+-              ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
+-              ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
+-
+-              ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
+-              ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
+-              break;
+-      case IPUV3_CHANNEL_MEM_ROT_VF:
+-              ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
+-              ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
+-              break;
+-      case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
+-              break;
+-      case IPUV3_CHANNEL_G_MEM_IC_PP:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
+-              break;
+-      case IPUV3_CHANNEL_VDI_MEM_IC_VF:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
+-              break;
+-      default:
+-              goto unlock;
+-      }
+-
+-      ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1);
+-      ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
+-      ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
+-
+-      if (ipu_rot_mode_is_irt(rot))
+-              ic->rotation = true;
+-
+-unlock:
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
+-
+-static void ipu_irt_enable(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-
+-      if (!priv->irt_use_count)
+-              ipu_module_enable(priv->ipu, IPU_CONF_ROT_EN);
+-
+-      priv->irt_use_count++;
+-}
+-
+-static void ipu_irt_disable(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-
+-      if (priv->irt_use_count) {
+-              if (!--priv->irt_use_count)
+-                      ipu_module_disable(priv->ipu, IPU_CONF_ROT_EN);
+-      }
+-}
+-
+-int ipu_ic_enable(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      if (!priv->use_count)
+-              ipu_module_enable(priv->ipu, IPU_CONF_IC_EN);
+-
+-      priv->use_count++;
+-
+-      if (ic->rotation)
+-              ipu_irt_enable(ic);
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_enable);
+-
+-int ipu_ic_disable(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      priv->use_count--;
+-
+-      if (!priv->use_count)
+-              ipu_module_disable(priv->ipu, IPU_CONF_IC_EN);
+-
+-      if (priv->use_count < 0)
+-              priv->use_count = 0;
+-
+-      if (ic->rotation)
+-              ipu_irt_disable(ic);
+-
+-      ic->rotation = ic->graphics = false;
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_disable);
+-
+-struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
+-{
+-      struct ipu_ic_priv *priv = ipu->ic_priv;
+-      unsigned long flags;
+-      struct ipu_ic *ic, *ret;
+-
+-      if (task >= IC_NUM_TASKS)
+-              return ERR_PTR(-EINVAL);
+-
+-      ic = &priv->task[task];
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      if (ic->in_use) {
+-              ret = ERR_PTR(-EBUSY);
+-              goto unlock;
+-      }
+-
+-      ic->in_use = true;
+-      ret = ic;
+-
+-unlock:
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_get);
+-
+-void ipu_ic_put(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-      ic->in_use = false;
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_put);
+-
+-int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
+-              unsigned long base, unsigned long tpmem_base)
+-{
+-      struct ipu_ic_priv *priv;
+-      int i;
+-
+-      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-      if (!priv)
+-              return -ENOMEM;
+-
+-      ipu->ic_priv = priv;
+-
+-      spin_lock_init(&priv->lock);
+-      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+-      if (!priv->base)
+-              return -ENOMEM;
+-      priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K);
+-      if (!priv->tpmem_base)
+-              return -ENOMEM;
+-
+-      dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base);
+-
+-      priv->ipu = ipu;
+-
+-      for (i = 0; i < IC_NUM_TASKS; i++) {
+-              priv->task[i].task = i;
+-              priv->task[i].priv = priv;
+-              priv->task[i].reg = &ic_task_reg[i];
+-              priv->task[i].bit = &ic_task_bit[i];
+-      }
+-
+-      return 0;
+-}
+-
+-void ipu_ic_exit(struct ipu_soc *ipu)
+-{
+-}
+-
+-void ipu_ic_dump(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      struct ipu_soc *ipu = priv->ipu;
+-
+-      dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_CONF));
+-      dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_PRP_ENC_RSC));
+-      dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_PRP_VF_RSC));
+-      dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_PP_RSC));
+-      dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_CMBP_1));
+-      dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_CMBP_2));
+-      dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_IDMAC_1));
+-      dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_IDMAC_2));
+-      dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_IDMAC_3));
+-      dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_IDMAC_4));
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_dump);
+--- a/drivers/gpu/ipu-v3/ipu-image-convert.c
++++ /dev/null
+@@ -1,2475 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (C) 2012-2016 Mentor Graphics Inc.
+- *
+- * Queued image conversion support, with tiling and rotation.
+- */
+-
+-#include <linux/interrupt.h>
+-#include <linux/dma-mapping.h>
+-#include <video/imx-ipu-image-convert.h>
+-#include "ipu-prv.h"
+-
+-/*
+- * The IC Resizer has a restriction that the output frame from the
+- * resizer must be 1024 or less in both width (pixels) and height
+- * (lines).
+- *
+- * The image converter attempts to split up a conversion when
+- * the desired output (converted) frame resolution exceeds the
+- * IC resizer limit of 1024 in either dimension.
+- *
+- * If either dimension of the output frame exceeds the limit, the
+- * dimension is split into 1, 2, or 4 equal stripes, for a maximum
+- * of 4*4 or 16 tiles. A conversion is then carried out for each
+- * tile (but taking care to pass the full frame stride length to
+- * the DMA channel's parameter memory!). IDMA double-buffering is used
+- * to convert each tile back-to-back when possible (see note below
+- * when double_buffering boolean is set).
+- *
+- * Note that the input frame must be split up into the same number
+- * of tiles as the output frame:
+- *
+- *                       +---------+-----+
+- *   +-----+---+         |  A      | B   |
+- *   | A   | B |         |         |     |
+- *   +-----+---+   -->   +---------+-----+
+- *   | C   | D |         |  C      | D   |
+- *   +-----+---+         |         |     |
+- *                       +---------+-----+
+- *
+- * Clockwise 90° rotations are handled by first rescaling into a
+- * reusable temporary tile buffer and then rotating with the 8x8
+- * block rotator, writing to the correct destination:
+- *
+- *                                         +-----+-----+
+- *                                         |     |     |
+- *   +-----+---+         +---------+       | C   | A   |
+- *   | A   | B |         | A,B, |  |       |     |     |
+- *   +-----+---+   -->   | C,D  |  |  -->  |     |     |
+- *   | C   | D |         +---------+       +-----+-----+
+- *   +-----+---+                           | D   | B   |
+- *                                         |     |     |
+- *                                         +-----+-----+
+- *
+- * If the 8x8 block rotator is used, horizontal or vertical flipping
+- * is done during the rotation step, otherwise flipping is done
+- * during the scaling step.
+- * With rotation or flipping, tile order changes between input and
+- * output image. Tiles are numbered row major from top left to bottom
+- * right for both input and output image.
+- */
+-
+-#define MAX_STRIPES_W    4
+-#define MAX_STRIPES_H    4
+-#define MAX_TILES (MAX_STRIPES_W * MAX_STRIPES_H)
+-
+-#define MIN_W     16
+-#define MIN_H     8
+-#define MAX_W     4096
+-#define MAX_H     4096
+-
+-enum ipu_image_convert_type {
+-      IMAGE_CONVERT_IN = 0,
+-      IMAGE_CONVERT_OUT,
+-};
+-
+-struct ipu_image_convert_dma_buf {
+-      void          *virt;
+-      dma_addr_t    phys;
+-      unsigned long len;
+-};
+-
+-struct ipu_image_convert_dma_chan {
+-      int in;
+-      int out;
+-      int rot_in;
+-      int rot_out;
+-      int vdi_in_p;
+-      int vdi_in;
+-      int vdi_in_n;
+-};
+-
+-/* dimensions of one tile */
+-struct ipu_image_tile {
+-      u32 width;
+-      u32 height;
+-      u32 left;
+-      u32 top;
+-      /* size and strides are in bytes */
+-      u32 size;
+-      u32 stride;
+-      u32 rot_stride;
+-      /* start Y or packed offset of this tile */
+-      u32 offset;
+-      /* offset from start to tile in U plane, for planar formats */
+-      u32 u_off;
+-      /* offset from start to tile in V plane, for planar formats */
+-      u32 v_off;
+-};
+-
+-struct ipu_image_convert_image {
+-      struct ipu_image base;
+-      enum ipu_image_convert_type type;
+-
+-      const struct ipu_image_pixfmt *fmt;
+-      unsigned int stride;
+-
+-      /* # of rows (horizontal stripes) if dest height is > 1024 */
+-      unsigned int num_rows;
+-      /* # of columns (vertical stripes) if dest width is > 1024 */
+-      unsigned int num_cols;
+-
+-      struct ipu_image_tile tile[MAX_TILES];
+-};
+-
+-struct ipu_image_pixfmt {
+-      u32     fourcc;        /* V4L2 fourcc */
+-      int     bpp;           /* total bpp */
+-      int     uv_width_dec;  /* decimation in width for U/V planes */
+-      int     uv_height_dec; /* decimation in height for U/V planes */
+-      bool    planar;        /* planar format */
+-      bool    uv_swapped;    /* U and V planes are swapped */
+-      bool    uv_packed;     /* partial planar (U and V in same plane) */
+-};
+-
+-struct ipu_image_convert_ctx;
+-struct ipu_image_convert_chan;
+-struct ipu_image_convert_priv;
+-
+-struct ipu_image_convert_ctx {
+-      struct ipu_image_convert_chan *chan;
+-
+-      ipu_image_convert_cb_t complete;
+-      void *complete_context;
+-
+-      /* Source/destination image data and rotation mode */
+-      struct ipu_image_convert_image in;
+-      struct ipu_image_convert_image out;
+-      struct ipu_ic_csc csc;
+-      enum ipu_rotate_mode rot_mode;
+-      u32 downsize_coeff_h;
+-      u32 downsize_coeff_v;
+-      u32 image_resize_coeff_h;
+-      u32 image_resize_coeff_v;
+-      u32 resize_coeffs_h[MAX_STRIPES_W];
+-      u32 resize_coeffs_v[MAX_STRIPES_H];
+-
+-      /* intermediate buffer for rotation */
+-      struct ipu_image_convert_dma_buf rot_intermediate[2];
+-
+-      /* current buffer number for double buffering */
+-      int cur_buf_num;
+-
+-      bool aborting;
+-      struct completion aborted;
+-
+-      /* can we use double-buffering for this conversion operation? */
+-      bool double_buffering;
+-      /* num_rows * num_cols */
+-      unsigned int num_tiles;
+-      /* next tile to process */
+-      unsigned int next_tile;
+-      /* where to place converted tile in dest image */
+-      unsigned int out_tile_map[MAX_TILES];
+-
+-      struct list_head list;
+-};
+-
+-struct ipu_image_convert_chan {
+-      struct ipu_image_convert_priv *priv;
+-
+-      enum ipu_ic_task ic_task;
+-      const struct ipu_image_convert_dma_chan *dma_ch;
+-
+-      struct ipu_ic *ic;
+-      struct ipuv3_channel *in_chan;
+-      struct ipuv3_channel *out_chan;
+-      struct ipuv3_channel *rotation_in_chan;
+-      struct ipuv3_channel *rotation_out_chan;
+-
+-      /* the IPU end-of-frame irqs */
+-      int out_eof_irq;
+-      int rot_out_eof_irq;
+-
+-      spinlock_t irqlock;
+-
+-      /* list of convert contexts */
+-      struct list_head ctx_list;
+-      /* queue of conversion runs */
+-      struct list_head pending_q;
+-      /* queue of completed runs */
+-      struct list_head done_q;
+-
+-      /* the current conversion run */
+-      struct ipu_image_convert_run *current_run;
+-};
+-
+-struct ipu_image_convert_priv {
+-      struct ipu_image_convert_chan chan[IC_NUM_TASKS];
+-      struct ipu_soc *ipu;
+-};
+-
+-static const struct ipu_image_convert_dma_chan
+-image_convert_dma_chan[IC_NUM_TASKS] = {
+-      [IC_TASK_VIEWFINDER] = {
+-              .in = IPUV3_CHANNEL_MEM_IC_PRP_VF,
+-              .out = IPUV3_CHANNEL_IC_PRP_VF_MEM,
+-              .rot_in = IPUV3_CHANNEL_MEM_ROT_VF,
+-              .rot_out = IPUV3_CHANNEL_ROT_VF_MEM,
+-              .vdi_in_p = IPUV3_CHANNEL_MEM_VDI_PREV,
+-              .vdi_in = IPUV3_CHANNEL_MEM_VDI_CUR,
+-              .vdi_in_n = IPUV3_CHANNEL_MEM_VDI_NEXT,
+-      },
+-      [IC_TASK_POST_PROCESSOR] = {
+-              .in = IPUV3_CHANNEL_MEM_IC_PP,
+-              .out = IPUV3_CHANNEL_IC_PP_MEM,
+-              .rot_in = IPUV3_CHANNEL_MEM_ROT_PP,
+-              .rot_out = IPUV3_CHANNEL_ROT_PP_MEM,
+-      },
+-};
+-
+-static const struct ipu_image_pixfmt image_convert_formats[] = {
+-      {
+-              .fourcc = V4L2_PIX_FMT_RGB565,
+-              .bpp    = 16,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_RGB24,
+-              .bpp    = 24,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_BGR24,
+-              .bpp    = 24,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_RGB32,
+-              .bpp    = 32,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_BGR32,
+-              .bpp    = 32,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_XRGB32,
+-              .bpp    = 32,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_XBGR32,
+-              .bpp    = 32,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_BGRX32,
+-              .bpp    = 32,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_RGBX32,
+-              .bpp    = 32,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_YUYV,
+-              .bpp    = 16,
+-              .uv_width_dec = 2,
+-              .uv_height_dec = 1,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_UYVY,
+-              .bpp    = 16,
+-              .uv_width_dec = 2,
+-              .uv_height_dec = 1,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_YUV420,
+-              .bpp    = 12,
+-              .planar = true,
+-              .uv_width_dec = 2,
+-              .uv_height_dec = 2,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_YVU420,
+-              .bpp    = 12,
+-              .planar = true,
+-              .uv_width_dec = 2,
+-              .uv_height_dec = 2,
+-              .uv_swapped = true,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_NV12,
+-              .bpp    = 12,
+-              .planar = true,
+-              .uv_width_dec = 2,
+-              .uv_height_dec = 2,
+-              .uv_packed = true,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_YUV422P,
+-              .bpp    = 16,
+-              .planar = true,
+-              .uv_width_dec = 2,
+-              .uv_height_dec = 1,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_NV16,
+-              .bpp    = 16,
+-              .planar = true,
+-              .uv_width_dec = 2,
+-              .uv_height_dec = 1,
+-              .uv_packed = true,
+-      },
+-};
+-
+-static const struct ipu_image_pixfmt *get_format(u32 fourcc)
+-{
+-      const struct ipu_image_pixfmt *ret = NULL;
+-      unsigned int i;
+-
+-      for (i = 0; i < ARRAY_SIZE(image_convert_formats); i++) {
+-              if (image_convert_formats[i].fourcc == fourcc) {
+-                      ret = &image_convert_formats[i];
+-                      break;
+-              }
+-      }
+-
+-      return ret;
+-}
+-
+-static void dump_format(struct ipu_image_convert_ctx *ctx,
+-                      struct ipu_image_convert_image *ic_image)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-
+-      dev_dbg(priv->ipu->dev,
+-              "task %u: ctx %p: %s format: %dx%d (%dx%d tiles), %c%c%c%c\n",
+-              chan->ic_task, ctx,
+-              ic_image->type == IMAGE_CONVERT_OUT ? "Output" : "Input",
+-              ic_image->base.pix.width, ic_image->base.pix.height,
+-              ic_image->num_cols, ic_image->num_rows,
+-              ic_image->fmt->fourcc & 0xff,
+-              (ic_image->fmt->fourcc >> 8) & 0xff,
+-              (ic_image->fmt->fourcc >> 16) & 0xff,
+-              (ic_image->fmt->fourcc >> 24) & 0xff);
+-}
+-
+-int ipu_image_convert_enum_format(int index, u32 *fourcc)
+-{
+-      const struct ipu_image_pixfmt *fmt;
+-
+-      if (index >= (int)ARRAY_SIZE(image_convert_formats))
+-              return -EINVAL;
+-
+-      /* Format found */
+-      fmt = &image_convert_formats[index];
+-      *fourcc = fmt->fourcc;
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_enum_format);
+-
+-static void free_dma_buf(struct ipu_image_convert_priv *priv,
+-                       struct ipu_image_convert_dma_buf *buf)
+-{
+-      if (buf->virt)
+-              dma_free_coherent(priv->ipu->dev,
+-                                buf->len, buf->virt, buf->phys);
+-      buf->virt = NULL;
+-      buf->phys = 0;
+-}
+-
+-static int alloc_dma_buf(struct ipu_image_convert_priv *priv,
+-                       struct ipu_image_convert_dma_buf *buf,
+-                       int size)
+-{
+-      buf->len = PAGE_ALIGN(size);
+-      buf->virt = dma_alloc_coherent(priv->ipu->dev, buf->len, &buf->phys,
+-                                     GFP_DMA | GFP_KERNEL);
+-      if (!buf->virt) {
+-              dev_err(priv->ipu->dev, "failed to alloc dma buffer\n");
+-              return -ENOMEM;
+-      }
+-
+-      return 0;
+-}
+-
+-static inline int num_stripes(int dim)
+-{
+-      return (dim - 1) / 1024 + 1;
+-}
+-
+-/*
+- * Calculate downsizing coefficients, which are the same for all tiles,
+- * and initial bilinear resizing coefficients, which are used to find the
+- * best seam positions.
+- * Also determine the number of tiles necessary to guarantee that no tile
+- * is larger than 1024 pixels in either dimension at the output and between
+- * IC downsizing and main processing sections.
+- */
+-static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
+-                                        struct ipu_image *in,
+-                                        struct ipu_image *out)
+-{
+-      u32 downsized_width = in->rect.width;
+-      u32 downsized_height = in->rect.height;
+-      u32 downsize_coeff_v = 0;
+-      u32 downsize_coeff_h = 0;
+-      u32 resized_width = out->rect.width;
+-      u32 resized_height = out->rect.height;
+-      u32 resize_coeff_h;
+-      u32 resize_coeff_v;
+-      u32 cols;
+-      u32 rows;
+-
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              resized_width = out->rect.height;
+-              resized_height = out->rect.width;
+-      }
+-
+-      /* Do not let invalid input lead to an endless loop below */
+-      if (WARN_ON(resized_width == 0 || resized_height == 0))
+-              return -EINVAL;
+-
+-      while (downsized_width >= resized_width * 2) {
+-              downsized_width >>= 1;
+-              downsize_coeff_h++;
+-      }
+-
+-      while (downsized_height >= resized_height * 2) {
+-              downsized_height >>= 1;
+-              downsize_coeff_v++;
+-      }
+-
+-      /*
+-       * Calculate the bilinear resizing coefficients that could be used if
+-       * we were converting with a single tile. The bottom right output pixel
+-       * should sample as close as possible to the bottom right input pixel
+-       * out of the decimator, but not overshoot it:
+-       */
+-      resize_coeff_h = 8192 * (downsized_width - 1) / (resized_width - 1);
+-      resize_coeff_v = 8192 * (downsized_height - 1) / (resized_height - 1);
+-
+-      /*
+-       * Both the output of the IC downsizing section before being passed to
+-       * the IC main processing section and the final output of the IC main
+-       * processing section must be <= 1024 pixels in both dimensions.
+-       */
+-      cols = num_stripes(max_t(u32, downsized_width, resized_width));
+-      rows = num_stripes(max_t(u32, downsized_height, resized_height));
+-
+-      dev_dbg(ctx->chan->priv->ipu->dev,
+-              "%s: hscale: >>%u, *8192/%u vscale: >>%u, *8192/%u, %ux%u tiles\n",
+-              __func__, downsize_coeff_h, resize_coeff_h, downsize_coeff_v,
+-              resize_coeff_v, cols, rows);
+-
+-      if (downsize_coeff_h > 2 || downsize_coeff_v  > 2 ||
+-          resize_coeff_h > 0x3fff || resize_coeff_v > 0x3fff)
+-              return -EINVAL;
+-
+-      ctx->downsize_coeff_h = downsize_coeff_h;
+-      ctx->downsize_coeff_v = downsize_coeff_v;
+-      ctx->image_resize_coeff_h = resize_coeff_h;
+-      ctx->image_resize_coeff_v = resize_coeff_v;
+-      ctx->in.num_cols = cols;
+-      ctx->in.num_rows = rows;
+-
+-      return 0;
+-}
+-
+-#define round_closest(x, y) round_down((x) + (y)/2, (y))
+-
+-/*
+- * Find the best aligned seam position for the given column / row index.
+- * Rotation and image offsets are out of scope.
+- *
+- * @index: column / row index, used to calculate valid interval
+- * @in_edge: input right / bottom edge
+- * @out_edge: output right / bottom edge
+- * @in_align: input alignment, either horizontal 8-byte line start address
+- *            alignment, or pixel alignment due to image format
+- * @out_align: output alignment, either horizontal 8-byte line start address
+- *             alignment, or pixel alignment due to image format or rotator
+- *             block size
+- * @in_burst: horizontal input burst size in case of horizontal flip
+- * @out_burst: horizontal output burst size or rotator block size
+- * @downsize_coeff: downsizing section coefficient
+- * @resize_coeff: main processing section resizing coefficient
+- * @_in_seam: aligned input seam position return value
+- * @_out_seam: aligned output seam position return value
+- */
+-static void find_best_seam(struct ipu_image_convert_ctx *ctx,
+-                         unsigned int index,
+-                         unsigned int in_edge,
+-                         unsigned int out_edge,
+-                         unsigned int in_align,
+-                         unsigned int out_align,
+-                         unsigned int in_burst,
+-                         unsigned int out_burst,
+-                         unsigned int downsize_coeff,
+-                         unsigned int resize_coeff,
+-                         u32 *_in_seam,
+-                         u32 *_out_seam)
+-{
+-      struct device *dev = ctx->chan->priv->ipu->dev;
+-      unsigned int out_pos;
+-      /* Input / output seam position candidates */
+-      unsigned int out_seam = 0;
+-      unsigned int in_seam = 0;
+-      unsigned int min_diff = UINT_MAX;
+-      unsigned int out_start;
+-      unsigned int out_end;
+-      unsigned int in_start;
+-      unsigned int in_end;
+-
+-      /* Start within 1024 pixels of the right / bottom edge */
+-      out_start = max_t(int, index * out_align, out_edge - 1024);
+-      /* End before having to add more columns to the left / rows above */
+-      out_end = min_t(unsigned int, out_edge, index * 1024 + 1);
+-
+-      /*
+-       * Limit input seam position to make sure that the downsized input tile
+-       * to the right or bottom does not exceed 1024 pixels.
+-       */
+-      in_start = max_t(int, index * in_align,
+-                       in_edge - (1024 << downsize_coeff));
+-      in_end = min_t(unsigned int, in_edge,
+-                     index * (1024 << downsize_coeff) + 1);
+-
+-      /*
+-       * Output tiles must start at a multiple of 8 bytes horizontally and
+-       * possibly at an even line horizontally depending on the pixel format.
+-       * Only consider output aligned positions for the seam.
+-       */
+-      out_start = round_up(out_start, out_align);
+-      for (out_pos = out_start; out_pos < out_end; out_pos += out_align) {
+-              unsigned int in_pos;
+-              unsigned int in_pos_aligned;
+-              unsigned int in_pos_rounded;
+-              unsigned int abs_diff;
+-
+-              /*
+-               * Tiles in the right row / bottom column may not be allowed to
+-               * overshoot horizontally / vertically. out_burst may be the
+-               * actual DMA burst size, or the rotator block size.
+-               */
+-              if ((out_burst > 1) && (out_edge - out_pos) % out_burst)
+-                      continue;
+-
+-              /*
+-               * Input sample position, corresponding to out_pos, 19.13 fixed
+-               * point.
+-               */
+-              in_pos = (out_pos * resize_coeff) << downsize_coeff;
+-              /*
+-               * The closest input sample position that we could actually
+-               * start the input tile at, 19.13 fixed point.
+-               */
+-              in_pos_aligned = round_closest(in_pos, 8192U * in_align);
+-              /* Convert 19.13 fixed point to integer */
+-              in_pos_rounded = in_pos_aligned / 8192U;
+-
+-              if (in_pos_rounded < in_start)
+-                      continue;
+-              if (in_pos_rounded >= in_end)
+-                      break;
+-
+-              if ((in_burst > 1) &&
+-                  (in_edge - in_pos_rounded) % in_burst)
+-                      continue;
+-
+-              if (in_pos < in_pos_aligned)
+-                      abs_diff = in_pos_aligned - in_pos;
+-              else
+-                      abs_diff = in_pos - in_pos_aligned;
+-
+-              if (abs_diff < min_diff) {
+-                      in_seam = in_pos_rounded;
+-                      out_seam = out_pos;
+-                      min_diff = abs_diff;
+-              }
+-      }
+-
+-      *_out_seam = out_seam;
+-      *_in_seam = in_seam;
+-
+-      dev_dbg(dev, "%s: out_seam %u(%u) in [%u, %u], in_seam %u(%u) in [%u, %u] diff %u.%03u\n",
+-              __func__, out_seam, out_align, out_start, out_end,
+-              in_seam, in_align, in_start, in_end, min_diff / 8192,
+-              DIV_ROUND_CLOSEST(min_diff % 8192 * 1000, 8192));
+-}
+-
+-/*
+- * Tile left edges are required to be aligned to multiples of 8 bytes
+- * by the IDMAC.
+- */
+-static inline u32 tile_left_align(const struct ipu_image_pixfmt *fmt)
+-{
+-      if (fmt->planar)
+-              return fmt->uv_packed ? 8 : 8 * fmt->uv_width_dec;
+-      else
+-              return fmt->bpp == 32 ? 2 : fmt->bpp == 16 ? 4 : 8;
+-}
+-
+-/*
+- * Tile top edge alignment is only limited by chroma subsampling.
+- */
+-static inline u32 tile_top_align(const struct ipu_image_pixfmt *fmt)
+-{
+-      return fmt->uv_height_dec > 1 ? 2 : 1;
+-}
+-
+-static inline u32 tile_width_align(enum ipu_image_convert_type type,
+-                                 const struct ipu_image_pixfmt *fmt,
+-                                 enum ipu_rotate_mode rot_mode)
+-{
+-      if (type == IMAGE_CONVERT_IN) {
+-              /*
+-               * The IC burst reads 8 pixels at a time. Reading beyond the
+-               * end of the line is usually acceptable. Those pixels are
+-               * ignored, unless the IC has to write the scaled line in
+-               * reverse.
+-               */
+-              return (!ipu_rot_mode_is_irt(rot_mode) &&
+-                      (rot_mode & IPU_ROT_BIT_HFLIP)) ? 8 : 2;
+-      }
+-
+-      /*
+-       * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
+-       * formats to guarantee 8-byte aligned line start addresses in the
+-       * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
+-       * for all other formats.
+-       */
+-      return (ipu_rot_mode_is_irt(rot_mode) &&
+-              fmt->planar && !fmt->uv_packed) ?
+-              8 * fmt->uv_width_dec : 8;
+-}
+-
+-static inline u32 tile_height_align(enum ipu_image_convert_type type,
+-                                  const struct ipu_image_pixfmt *fmt,
+-                                  enum ipu_rotate_mode rot_mode)
+-{
+-      if (type == IMAGE_CONVERT_IN || !ipu_rot_mode_is_irt(rot_mode))
+-              return 2;
+-
+-      /*
+-       * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
+-       * formats to guarantee 8-byte aligned line start addresses in the
+-       * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
+-       * for all other formats.
+-       */
+-      return (fmt->planar && !fmt->uv_packed) ? 8 * fmt->uv_width_dec : 8;
+-}
+-
+-/*
+- * Fill in left position and width and for all tiles in an input column, and
+- * for all corresponding output tiles. If the 90° rotator is used, the output
+- * tiles are in a row, and output tile top position and height are set.
+- */
+-static void fill_tile_column(struct ipu_image_convert_ctx *ctx,
+-                           unsigned int col,
+-                           struct ipu_image_convert_image *in,
+-                           unsigned int in_left, unsigned int in_width,
+-                           struct ipu_image_convert_image *out,
+-                           unsigned int out_left, unsigned int out_width)
+-{
+-      unsigned int row, tile_idx;
+-      struct ipu_image_tile *in_tile, *out_tile;
+-
+-      for (row = 0; row < in->num_rows; row++) {
+-              tile_idx = in->num_cols * row + col;
+-              in_tile = &in->tile[tile_idx];
+-              out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
+-
+-              in_tile->left = in_left;
+-              in_tile->width = in_width;
+-
+-              if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-                      out_tile->top = out_left;
+-                      out_tile->height = out_width;
+-              } else {
+-                      out_tile->left = out_left;
+-                      out_tile->width = out_width;
+-              }
+-      }
+-}
+-
+-/*
+- * Fill in top position and height and for all tiles in an input row, and
+- * for all corresponding output tiles. If the 90° rotator is used, the output
+- * tiles are in a column, and output tile left position and width are set.
+- */
+-static void fill_tile_row(struct ipu_image_convert_ctx *ctx, unsigned int row,
+-                        struct ipu_image_convert_image *in,
+-                        unsigned int in_top, unsigned int in_height,
+-                        struct ipu_image_convert_image *out,
+-                        unsigned int out_top, unsigned int out_height)
+-{
+-      unsigned int col, tile_idx;
+-      struct ipu_image_tile *in_tile, *out_tile;
+-
+-      for (col = 0; col < in->num_cols; col++) {
+-              tile_idx = in->num_cols * row + col;
+-              in_tile = &in->tile[tile_idx];
+-              out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
+-
+-              in_tile->top = in_top;
+-              in_tile->height = in_height;
+-
+-              if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-                      out_tile->left = out_top;
+-                      out_tile->width = out_height;
+-              } else {
+-                      out_tile->top = out_top;
+-                      out_tile->height = out_height;
+-              }
+-      }
+-}
+-
+-/*
+- * Find the best horizontal and vertical seam positions to split into tiles.
+- * Minimize the fractional part of the input sampling position for the
+- * top / left pixels of each tile.
+- */
+-static void find_seams(struct ipu_image_convert_ctx *ctx,
+-                     struct ipu_image_convert_image *in,
+-                     struct ipu_image_convert_image *out)
+-{
+-      struct device *dev = ctx->chan->priv->ipu->dev;
+-      unsigned int resized_width = out->base.rect.width;
+-      unsigned int resized_height = out->base.rect.height;
+-      unsigned int col;
+-      unsigned int row;
+-      unsigned int in_left_align = tile_left_align(in->fmt);
+-      unsigned int in_top_align = tile_top_align(in->fmt);
+-      unsigned int out_left_align = tile_left_align(out->fmt);
+-      unsigned int out_top_align = tile_top_align(out->fmt);
+-      unsigned int out_width_align = tile_width_align(out->type, out->fmt,
+-                                                      ctx->rot_mode);
+-      unsigned int out_height_align = tile_height_align(out->type, out->fmt,
+-                                                        ctx->rot_mode);
+-      unsigned int in_right = in->base.rect.width;
+-      unsigned int in_bottom = in->base.rect.height;
+-      unsigned int out_right = out->base.rect.width;
+-      unsigned int out_bottom = out->base.rect.height;
+-      unsigned int flipped_out_left;
+-      unsigned int flipped_out_top;
+-
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              /* Switch width/height and align top left to IRT block size */
+-              resized_width = out->base.rect.height;
+-              resized_height = out->base.rect.width;
+-              out_left_align = out_height_align;
+-              out_top_align = out_width_align;
+-              out_width_align = out_left_align;
+-              out_height_align = out_top_align;
+-              out_right = out->base.rect.height;
+-              out_bottom = out->base.rect.width;
+-      }
+-
+-      for (col = in->num_cols - 1; col > 0; col--) {
+-              bool allow_in_overshoot = ipu_rot_mode_is_irt(ctx->rot_mode) ||
+-                                        !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
+-              bool allow_out_overshoot = (col < in->num_cols - 1) &&
+-                                         !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
+-              unsigned int in_left;
+-              unsigned int out_left;
+-
+-              /*
+-               * Align input width to burst length if the scaling step flips
+-               * horizontally.
+-               */
+-
+-              find_best_seam(ctx, col,
+-                             in_right, out_right,
+-                             in_left_align, out_left_align,
+-                             allow_in_overshoot ? 1 : 8 /* burst length */,
+-                             allow_out_overshoot ? 1 : out_width_align,
+-                             ctx->downsize_coeff_h, ctx->image_resize_coeff_h,
+-                             &in_left, &out_left);
+-
+-              if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
+-                      flipped_out_left = resized_width - out_right;
+-              else
+-                      flipped_out_left = out_left;
+-
+-              fill_tile_column(ctx, col, in, in_left, in_right - in_left,
+-                               out, flipped_out_left, out_right - out_left);
+-
+-              dev_dbg(dev, "%s: col %u: %u, %u -> %u, %u\n", __func__, col,
+-                      in_left, in_right - in_left,
+-                      flipped_out_left, out_right - out_left);
+-
+-              in_right = in_left;
+-              out_right = out_left;
+-      }
+-
+-      flipped_out_left = (ctx->rot_mode & IPU_ROT_BIT_HFLIP) ?
+-                         resized_width - out_right : 0;
+-
+-      fill_tile_column(ctx, 0, in, 0, in_right,
+-                       out, flipped_out_left, out_right);
+-
+-      dev_dbg(dev, "%s: col 0: 0, %u -> %u, %u\n", __func__,
+-              in_right, flipped_out_left, out_right);
+-
+-      for (row = in->num_rows - 1; row > 0; row--) {
+-              bool allow_overshoot = row < in->num_rows - 1;
+-              unsigned int in_top;
+-              unsigned int out_top;
+-
+-              find_best_seam(ctx, row,
+-                             in_bottom, out_bottom,
+-                             in_top_align, out_top_align,
+-                             1, allow_overshoot ? 1 : out_height_align,
+-                             ctx->downsize_coeff_v, ctx->image_resize_coeff_v,
+-                             &in_top, &out_top);
+-
+-              if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
+-                  ipu_rot_mode_is_irt(ctx->rot_mode))
+-                      flipped_out_top = resized_height - out_bottom;
+-              else
+-                      flipped_out_top = out_top;
+-
+-              fill_tile_row(ctx, row, in, in_top, in_bottom - in_top,
+-                            out, flipped_out_top, out_bottom - out_top);
+-
+-              dev_dbg(dev, "%s: row %u: %u, %u -> %u, %u\n", __func__, row,
+-                      in_top, in_bottom - in_top,
+-                      flipped_out_top, out_bottom - out_top);
+-
+-              in_bottom = in_top;
+-              out_bottom = out_top;
+-      }
+-
+-      if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
+-          ipu_rot_mode_is_irt(ctx->rot_mode))
+-              flipped_out_top = resized_height - out_bottom;
+-      else
+-              flipped_out_top = 0;
+-
+-      fill_tile_row(ctx, 0, in, 0, in_bottom,
+-                    out, flipped_out_top, out_bottom);
+-
+-      dev_dbg(dev, "%s: row 0: 0, %u -> %u, %u\n", __func__,
+-              in_bottom, flipped_out_top, out_bottom);
+-}
+-
+-static int calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
+-                              struct ipu_image_convert_image *image)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      unsigned int max_width = 1024;
+-      unsigned int max_height = 1024;
+-      unsigned int i;
+-
+-      if (image->type == IMAGE_CONVERT_IN) {
+-              /* Up to 4096x4096 input tile size */
+-              max_width <<= ctx->downsize_coeff_h;
+-              max_height <<= ctx->downsize_coeff_v;
+-      }
+-
+-      for (i = 0; i < ctx->num_tiles; i++) {
+-              struct ipu_image_tile *tile;
+-              const unsigned int row = i / image->num_cols;
+-              const unsigned int col = i % image->num_cols;
+-
+-              if (image->type == IMAGE_CONVERT_OUT)
+-                      tile = &image->tile[ctx->out_tile_map[i]];
+-              else
+-                      tile = &image->tile[i];
+-
+-              tile->size = ((tile->height * image->fmt->bpp) >> 3) *
+-                      tile->width;
+-
+-              if (image->fmt->planar) {
+-                      tile->stride = tile->width;
+-                      tile->rot_stride = tile->height;
+-              } else {
+-                      tile->stride =
+-                              (image->fmt->bpp * tile->width) >> 3;
+-                      tile->rot_stride =
+-                              (image->fmt->bpp * tile->height) >> 3;
+-              }
+-
+-              dev_dbg(priv->ipu->dev,
+-                      "task %u: ctx %p: %s@[%u,%u]: %ux%u@%u,%u\n",
+-                      chan->ic_task, ctx,
+-                      image->type == IMAGE_CONVERT_IN ? "Input" : "Output",
+-                      row, col,
+-                      tile->width, tile->height, tile->left, tile->top);
+-
+-              if (!tile->width || tile->width > max_width ||
+-                  !tile->height || tile->height > max_height) {
+-                      dev_err(priv->ipu->dev, "invalid %s tile size: %ux%u\n",
+-                              image->type == IMAGE_CONVERT_IN ? "input" :
+-                              "output", tile->width, tile->height);
+-                      return -EINVAL;
+-              }
+-      }
+-
+-      return 0;
+-}
+-
+-/*
+- * Use the rotation transformation to find the tile coordinates
+- * (row, col) of a tile in the destination frame that corresponds
+- * to the given tile coordinates of a source frame. The destination
+- * coordinate is then converted to a tile index.
+- */
+-static int transform_tile_index(struct ipu_image_convert_ctx *ctx,
+-                              int src_row, int src_col)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_convert_image *s_image = &ctx->in;
+-      struct ipu_image_convert_image *d_image = &ctx->out;
+-      int dst_row, dst_col;
+-
+-      /* with no rotation it's a 1:1 mapping */
+-      if (ctx->rot_mode == IPU_ROTATE_NONE)
+-              return src_row * s_image->num_cols + src_col;
+-
+-      /*
+-       * before doing the transform, first we have to translate
+-       * source row,col for an origin in the center of s_image
+-       */
+-      src_row = src_row * 2 - (s_image->num_rows - 1);
+-      src_col = src_col * 2 - (s_image->num_cols - 1);
+-
+-      /* do the rotation transform */
+-      if (ctx->rot_mode & IPU_ROT_BIT_90) {
+-              dst_col = -src_row;
+-              dst_row = src_col;
+-      } else {
+-              dst_col = src_col;
+-              dst_row = src_row;
+-      }
+-
+-      /* apply flip */
+-      if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
+-              dst_col = -dst_col;
+-      if (ctx->rot_mode & IPU_ROT_BIT_VFLIP)
+-              dst_row = -dst_row;
+-
+-      dev_dbg(priv->ipu->dev, "task %u: ctx %p: [%d,%d] --> [%d,%d]\n",
+-              chan->ic_task, ctx, src_col, src_row, dst_col, dst_row);
+-
+-      /*
+-       * finally translate dest row,col using an origin in upper
+-       * left of d_image
+-       */
+-      dst_row += d_image->num_rows - 1;
+-      dst_col += d_image->num_cols - 1;
+-      dst_row /= 2;
+-      dst_col /= 2;
+-
+-      return dst_row * d_image->num_cols + dst_col;
+-}
+-
+-/*
+- * Fill the out_tile_map[] with transformed destination tile indeces.
+- */
+-static void calc_out_tile_map(struct ipu_image_convert_ctx *ctx)
+-{
+-      struct ipu_image_convert_image *s_image = &ctx->in;
+-      unsigned int row, col, tile = 0;
+-
+-      for (row = 0; row < s_image->num_rows; row++) {
+-              for (col = 0; col < s_image->num_cols; col++) {
+-                      ctx->out_tile_map[tile] =
+-                              transform_tile_index(ctx, row, col);
+-                      tile++;
+-              }
+-      }
+-}
+-
+-static int calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
+-                                  struct ipu_image_convert_image *image)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      const struct ipu_image_pixfmt *fmt = image->fmt;
+-      unsigned int row, col, tile = 0;
+-      u32 H, top, y_stride, uv_stride;
+-      u32 uv_row_off, uv_col_off, uv_off, u_off, v_off, tmp;
+-      u32 y_row_off, y_col_off, y_off;
+-      u32 y_size, uv_size;
+-
+-      /* setup some convenience vars */
+-      H = image->base.pix.height;
+-
+-      y_stride = image->stride;
+-      uv_stride = y_stride / fmt->uv_width_dec;
+-      if (fmt->uv_packed)
+-              uv_stride *= 2;
+-
+-      y_size = H * y_stride;
+-      uv_size = y_size / (fmt->uv_width_dec * fmt->uv_height_dec);
+-
+-      for (row = 0; row < image->num_rows; row++) {
+-              top = image->tile[tile].top;
+-              y_row_off = top * y_stride;
+-              uv_row_off = (top * uv_stride) / fmt->uv_height_dec;
+-
+-              for (col = 0; col < image->num_cols; col++) {
+-                      y_col_off = image->tile[tile].left;
+-                      uv_col_off = y_col_off / fmt->uv_width_dec;
+-                      if (fmt->uv_packed)
+-                              uv_col_off *= 2;
+-
+-                      y_off = y_row_off + y_col_off;
+-                      uv_off = uv_row_off + uv_col_off;
+-
+-                      u_off = y_size - y_off + uv_off;
+-                      v_off = (fmt->uv_packed) ? 0 : u_off + uv_size;
+-                      if (fmt->uv_swapped) {
+-                              tmp = u_off;
+-                              u_off = v_off;
+-                              v_off = tmp;
+-                      }
+-
+-                      image->tile[tile].offset = y_off;
+-                      image->tile[tile].u_off = u_off;
+-                      image->tile[tile++].v_off = v_off;
+-
+-                      if ((y_off & 0x7) || (u_off & 0x7) || (v_off & 0x7)) {
+-                              dev_err(priv->ipu->dev,
+-                                      "task %u: ctx %p: %s@[%d,%d]: "
+-                                      "y_off %08x, u_off %08x, v_off %08x\n",
+-                                      chan->ic_task, ctx,
+-                                      image->type == IMAGE_CONVERT_IN ?
+-                                      "Input" : "Output", row, col,
+-                                      y_off, u_off, v_off);
+-                              return -EINVAL;
+-                      }
+-              }
+-      }
+-
+-      return 0;
+-}
+-
+-static int calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
+-                                  struct ipu_image_convert_image *image)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      const struct ipu_image_pixfmt *fmt = image->fmt;
+-      unsigned int row, col, tile = 0;
+-      u32 bpp, stride, offset;
+-      u32 row_off, col_off;
+-
+-      /* setup some convenience vars */
+-      stride = image->stride;
+-      bpp = fmt->bpp;
+-
+-      for (row = 0; row < image->num_rows; row++) {
+-              row_off = image->tile[tile].top * stride;
+-
+-              for (col = 0; col < image->num_cols; col++) {
+-                      col_off = (image->tile[tile].left * bpp) >> 3;
+-
+-                      offset = row_off + col_off;
+-
+-                      image->tile[tile].offset = offset;
+-                      image->tile[tile].u_off = 0;
+-                      image->tile[tile++].v_off = 0;
+-
+-                      if (offset & 0x7) {
+-                              dev_err(priv->ipu->dev,
+-                                      "task %u: ctx %p: %s@[%d,%d]: "
+-                                      "phys %08x\n",
+-                                      chan->ic_task, ctx,
+-                                      image->type == IMAGE_CONVERT_IN ?
+-                                      "Input" : "Output", row, col,
+-                                      row_off + col_off);
+-                              return -EINVAL;
+-                      }
+-              }
+-      }
+-
+-      return 0;
+-}
+-
+-static int calc_tile_offsets(struct ipu_image_convert_ctx *ctx,
+-                            struct ipu_image_convert_image *image)
+-{
+-      if (image->fmt->planar)
+-              return calc_tile_offsets_planar(ctx, image);
+-
+-      return calc_tile_offsets_packed(ctx, image);
+-}
+-
+-/*
+- * Calculate the resizing ratio for the IC main processing section given input
+- * size, fixed downsizing coefficient, and output size.
+- * Either round to closest for the next tile's first pixel to minimize seams
+- * and distortion (for all but right column / bottom row), or round down to
+- * avoid sampling beyond the edges of the input image for this tile's last
+- * pixel.
+- * Returns the resizing coefficient, resizing ratio is 8192.0 / resize_coeff.
+- */
+-static u32 calc_resize_coeff(u32 input_size, u32 downsize_coeff,
+-                           u32 output_size, bool allow_overshoot)
+-{
+-      u32 downsized = input_size >> downsize_coeff;
+-
+-      if (allow_overshoot)
+-              return DIV_ROUND_CLOSEST(8192 * downsized, output_size);
+-      else
+-              return 8192 * (downsized - 1) / (output_size - 1);
+-}
+-
+-/*
+- * Slightly modify resize coefficients per tile to hide the bilinear
+- * interpolator reset at tile borders, shifting the right / bottom edge
+- * by up to a half input pixel. This removes noticeable seams between
+- * tiles at higher upscaling factors.
+- */
+-static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_tile *in_tile, *out_tile;
+-      unsigned int col, row, tile_idx;
+-      unsigned int last_output;
+-
+-      for (col = 0; col < ctx->in.num_cols; col++) {
+-              bool closest = (col < ctx->in.num_cols - 1) &&
+-                             !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
+-              u32 resized_width;
+-              u32 resize_coeff_h;
+-              u32 in_width;
+-
+-              tile_idx = col;
+-              in_tile = &ctx->in.tile[tile_idx];
+-              out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
+-
+-              if (ipu_rot_mode_is_irt(ctx->rot_mode))
+-                      resized_width = out_tile->height;
+-              else
+-                      resized_width = out_tile->width;
+-
+-              resize_coeff_h = calc_resize_coeff(in_tile->width,
+-                                                 ctx->downsize_coeff_h,
+-                                                 resized_width, closest);
+-
+-              dev_dbg(priv->ipu->dev, "%s: column %u hscale: *8192/%u\n",
+-                      __func__, col, resize_coeff_h);
+-
+-              /*
+-               * With the horizontal scaling factor known, round up resized
+-               * width (output width or height) to burst size.
+-               */
+-              resized_width = round_up(resized_width, 8);
+-
+-              /*
+-               * Calculate input width from the last accessed input pixel
+-               * given resized width and scaling coefficients. Round up to
+-               * burst size.
+-               */
+-              last_output = resized_width - 1;
+-              if (closest && ((last_output * resize_coeff_h) % 8192))
+-                      last_output++;
+-              in_width = round_up(
+-                      (DIV_ROUND_UP(last_output * resize_coeff_h, 8192) + 1)
+-                      << ctx->downsize_coeff_h, 8);
+-
+-              for (row = 0; row < ctx->in.num_rows; row++) {
+-                      tile_idx = row * ctx->in.num_cols + col;
+-                      in_tile = &ctx->in.tile[tile_idx];
+-                      out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
+-
+-                      if (ipu_rot_mode_is_irt(ctx->rot_mode))
+-                              out_tile->height = resized_width;
+-                      else
+-                              out_tile->width = resized_width;
+-
+-                      in_tile->width = in_width;
+-              }
+-
+-              ctx->resize_coeffs_h[col] = resize_coeff_h;
+-      }
+-
+-      for (row = 0; row < ctx->in.num_rows; row++) {
+-              bool closest = (row < ctx->in.num_rows - 1) &&
+-                             !(ctx->rot_mode & IPU_ROT_BIT_VFLIP);
+-              u32 resized_height;
+-              u32 resize_coeff_v;
+-              u32 in_height;
+-
+-              tile_idx = row * ctx->in.num_cols;
+-              in_tile = &ctx->in.tile[tile_idx];
+-              out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
+-
+-              if (ipu_rot_mode_is_irt(ctx->rot_mode))
+-                      resized_height = out_tile->width;
+-              else
+-                      resized_height = out_tile->height;
+-
+-              resize_coeff_v = calc_resize_coeff(in_tile->height,
+-                                                 ctx->downsize_coeff_v,
+-                                                 resized_height, closest);
+-
+-              dev_dbg(priv->ipu->dev, "%s: row %u vscale: *8192/%u\n",
+-                      __func__, row, resize_coeff_v);
+-
+-              /*
+-               * With the vertical scaling factor known, round up resized
+-               * height (output width or height) to IDMAC limitations.
+-               */
+-              resized_height = round_up(resized_height, 2);
+-
+-              /*
+-               * Calculate input width from the last accessed input pixel
+-               * given resized height and scaling coefficients. Align to
+-               * IDMAC restrictions.
+-               */
+-              last_output = resized_height - 1;
+-              if (closest && ((last_output * resize_coeff_v) % 8192))
+-                      last_output++;
+-              in_height = round_up(
+-                      (DIV_ROUND_UP(last_output * resize_coeff_v, 8192) + 1)
+-                      << ctx->downsize_coeff_v, 2);
+-
+-              for (col = 0; col < ctx->in.num_cols; col++) {
+-                      tile_idx = row * ctx->in.num_cols + col;
+-                      in_tile = &ctx->in.tile[tile_idx];
+-                      out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
+-
+-                      if (ipu_rot_mode_is_irt(ctx->rot_mode))
+-                              out_tile->width = resized_height;
+-                      else
+-                              out_tile->height = resized_height;
+-
+-                      in_tile->height = in_height;
+-              }
+-
+-              ctx->resize_coeffs_v[row] = resize_coeff_v;
+-      }
+-}
+-
+-/*
+- * return the number of runs in given queue (pending_q or done_q)
+- * for this context. hold irqlock when calling.
+- */
+-static int get_run_count(struct ipu_image_convert_ctx *ctx,
+-                       struct list_head *q)
+-{
+-      struct ipu_image_convert_run *run;
+-      int count = 0;
+-
+-      lockdep_assert_held(&ctx->chan->irqlock);
+-
+-      list_for_each_entry(run, q, list) {
+-              if (run->ctx == ctx)
+-                      count++;
+-      }
+-
+-      return count;
+-}
+-
+-static void convert_stop(struct ipu_image_convert_run *run)
+-{
+-      struct ipu_image_convert_ctx *ctx = run->ctx;
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-
+-      dev_dbg(priv->ipu->dev, "%s: task %u: stopping ctx %p run %p\n",
+-              __func__, chan->ic_task, ctx, run);
+-
+-      /* disable IC tasks and the channels */
+-      ipu_ic_task_disable(chan->ic);
+-      ipu_idmac_disable_channel(chan->in_chan);
+-      ipu_idmac_disable_channel(chan->out_chan);
+-
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              ipu_idmac_disable_channel(chan->rotation_in_chan);
+-              ipu_idmac_disable_channel(chan->rotation_out_chan);
+-              ipu_idmac_unlink(chan->out_chan, chan->rotation_in_chan);
+-      }
+-
+-      ipu_ic_disable(chan->ic);
+-}
+-
+-static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
+-                             struct ipuv3_channel *channel,
+-                             struct ipu_image_convert_image *image,
+-                             enum ipu_rotate_mode rot_mode,
+-                             bool rot_swap_width_height,
+-                             unsigned int tile)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      unsigned int burst_size;
+-      u32 width, height, stride;
+-      dma_addr_t addr0, addr1 = 0;
+-      struct ipu_image tile_image;
+-      unsigned int tile_idx[2];
+-
+-      if (image->type == IMAGE_CONVERT_OUT) {
+-              tile_idx[0] = ctx->out_tile_map[tile];
+-              tile_idx[1] = ctx->out_tile_map[1];
+-      } else {
+-              tile_idx[0] = tile;
+-              tile_idx[1] = 1;
+-      }
+-
+-      if (rot_swap_width_height) {
+-              width = image->tile[tile_idx[0]].height;
+-              height = image->tile[tile_idx[0]].width;
+-              stride = image->tile[tile_idx[0]].rot_stride;
+-              addr0 = ctx->rot_intermediate[0].phys;
+-              if (ctx->double_buffering)
+-                      addr1 = ctx->rot_intermediate[1].phys;
+-      } else {
+-              width = image->tile[tile_idx[0]].width;
+-              height = image->tile[tile_idx[0]].height;
+-              stride = image->stride;
+-              addr0 = image->base.phys0 +
+-                      image->tile[tile_idx[0]].offset;
+-              if (ctx->double_buffering)
+-                      addr1 = image->base.phys0 +
+-                              image->tile[tile_idx[1]].offset;
+-      }
+-
+-      ipu_cpmem_zero(channel);
+-
+-      memset(&tile_image, 0, sizeof(tile_image));
+-      tile_image.pix.width = tile_image.rect.width = width;
+-      tile_image.pix.height = tile_image.rect.height = height;
+-      tile_image.pix.bytesperline = stride;
+-      tile_image.pix.pixelformat =  image->fmt->fourcc;
+-      tile_image.phys0 = addr0;
+-      tile_image.phys1 = addr1;
+-      if (image->fmt->planar && !rot_swap_width_height) {
+-              tile_image.u_offset = image->tile[tile_idx[0]].u_off;
+-              tile_image.v_offset = image->tile[tile_idx[0]].v_off;
+-      }
+-
+-      ipu_cpmem_set_image(channel, &tile_image);
+-
+-      if (rot_mode)
+-              ipu_cpmem_set_rotation(channel, rot_mode);
+-
+-      /*
+-       * Skip writing U and V components to odd rows in the output
+-       * channels for planar 4:2:0.
+-       */
+-      if ((channel == chan->out_chan ||
+-           channel == chan->rotation_out_chan) &&
+-          image->fmt->planar && image->fmt->uv_height_dec == 2)
+-              ipu_cpmem_skip_odd_chroma_rows(channel);
+-
+-      if (channel == chan->rotation_in_chan ||
+-          channel == chan->rotation_out_chan) {
+-              burst_size = 8;
+-              ipu_cpmem_set_block_mode(channel);
+-      } else
+-              burst_size = (width % 16) ? 8 : 16;
+-
+-      ipu_cpmem_set_burstsize(channel, burst_size);
+-
+-      ipu_ic_task_idma_init(chan->ic, channel, width, height,
+-                            burst_size, rot_mode);
+-
+-      /*
+-       * Setting a non-zero AXI ID collides with the PRG AXI snooping, so
+-       * only do this when there is no PRG present.
+-       */
+-      if (!channel->ipu->prg_priv)
+-              ipu_cpmem_set_axi_id(channel, 1);
+-
+-      ipu_idmac_set_double_buffer(channel, ctx->double_buffering);
+-}
+-
+-static int convert_start(struct ipu_image_convert_run *run, unsigned int tile)
+-{
+-      struct ipu_image_convert_ctx *ctx = run->ctx;
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_convert_image *s_image = &ctx->in;
+-      struct ipu_image_convert_image *d_image = &ctx->out;
+-      unsigned int dst_tile = ctx->out_tile_map[tile];
+-      unsigned int dest_width, dest_height;
+-      unsigned int col, row;
+-      u32 rsc;
+-      int ret;
+-
+-      dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n",
+-              __func__, chan->ic_task, ctx, run, tile, dst_tile);
+-
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              /* swap width/height for resizer */
+-              dest_width = d_image->tile[dst_tile].height;
+-              dest_height = d_image->tile[dst_tile].width;
+-      } else {
+-              dest_width = d_image->tile[dst_tile].width;
+-              dest_height = d_image->tile[dst_tile].height;
+-      }
+-
+-      row = tile / s_image->num_cols;
+-      col = tile % s_image->num_cols;
+-
+-      rsc =  (ctx->downsize_coeff_v << 30) |
+-             (ctx->resize_coeffs_v[row] << 16) |
+-             (ctx->downsize_coeff_h << 14) |
+-             (ctx->resize_coeffs_h[col]);
+-
+-      dev_dbg(priv->ipu->dev, "%s: %ux%u -> %ux%u (rsc = 0x%x)\n",
+-              __func__, s_image->tile[tile].width,
+-              s_image->tile[tile].height, dest_width, dest_height, rsc);
+-
+-      /* setup the IC resizer and CSC */
+-      ret = ipu_ic_task_init_rsc(chan->ic, &ctx->csc,
+-                                 s_image->tile[tile].width,
+-                                 s_image->tile[tile].height,
+-                                 dest_width,
+-                                 dest_height,
+-                                 rsc);
+-      if (ret) {
+-              dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret);
+-              return ret;
+-      }
+-
+-      /* init the source MEM-->IC PP IDMAC channel */
+-      init_idmac_channel(ctx, chan->in_chan, s_image,
+-                         IPU_ROTATE_NONE, false, tile);
+-
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              /* init the IC PP-->MEM IDMAC channel */
+-              init_idmac_channel(ctx, chan->out_chan, d_image,
+-                                 IPU_ROTATE_NONE, true, tile);
+-
+-              /* init the MEM-->IC PP ROT IDMAC channel */
+-              init_idmac_channel(ctx, chan->rotation_in_chan, d_image,
+-                                 ctx->rot_mode, true, tile);
+-
+-              /* init the destination IC PP ROT-->MEM IDMAC channel */
+-              init_idmac_channel(ctx, chan->rotation_out_chan, d_image,
+-                                 IPU_ROTATE_NONE, false, tile);
+-
+-              /* now link IC PP-->MEM to MEM-->IC PP ROT */
+-              ipu_idmac_link(chan->out_chan, chan->rotation_in_chan);
+-      } else {
+-              /* init the destination IC PP-->MEM IDMAC channel */
+-              init_idmac_channel(ctx, chan->out_chan, d_image,
+-                                 ctx->rot_mode, false, tile);
+-      }
+-
+-      /* enable the IC */
+-      ipu_ic_enable(chan->ic);
+-
+-      /* set buffers ready */
+-      ipu_idmac_select_buffer(chan->in_chan, 0);
+-      ipu_idmac_select_buffer(chan->out_chan, 0);
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode))
+-              ipu_idmac_select_buffer(chan->rotation_out_chan, 0);
+-      if (ctx->double_buffering) {
+-              ipu_idmac_select_buffer(chan->in_chan, 1);
+-              ipu_idmac_select_buffer(chan->out_chan, 1);
+-              if (ipu_rot_mode_is_irt(ctx->rot_mode))
+-                      ipu_idmac_select_buffer(chan->rotation_out_chan, 1);
+-      }
+-
+-      /* enable the channels! */
+-      ipu_idmac_enable_channel(chan->in_chan);
+-      ipu_idmac_enable_channel(chan->out_chan);
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              ipu_idmac_enable_channel(chan->rotation_in_chan);
+-              ipu_idmac_enable_channel(chan->rotation_out_chan);
+-      }
+-
+-      ipu_ic_task_enable(chan->ic);
+-
+-      ipu_cpmem_dump(chan->in_chan);
+-      ipu_cpmem_dump(chan->out_chan);
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              ipu_cpmem_dump(chan->rotation_in_chan);
+-              ipu_cpmem_dump(chan->rotation_out_chan);
+-      }
+-
+-      ipu_dump(priv->ipu);
+-
+-      return 0;
+-}
+-
+-/* hold irqlock when calling */
+-static int do_run(struct ipu_image_convert_run *run)
+-{
+-      struct ipu_image_convert_ctx *ctx = run->ctx;
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-
+-      lockdep_assert_held(&chan->irqlock);
+-
+-      ctx->in.base.phys0 = run->in_phys;
+-      ctx->out.base.phys0 = run->out_phys;
+-
+-      ctx->cur_buf_num = 0;
+-      ctx->next_tile = 1;
+-
+-      /* remove run from pending_q and set as current */
+-      list_del(&run->list);
+-      chan->current_run = run;
+-
+-      return convert_start(run, 0);
+-}
+-
+-/* hold irqlock when calling */
+-static void run_next(struct ipu_image_convert_chan *chan)
+-{
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_convert_run *run, *tmp;
+-      int ret;
+-
+-      lockdep_assert_held(&chan->irqlock);
+-
+-      list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
+-              /* skip contexts that are aborting */
+-              if (run->ctx->aborting) {
+-                      dev_dbg(priv->ipu->dev,
+-                              "%s: task %u: skipping aborting ctx %p run %p\n",
+-                              __func__, chan->ic_task, run->ctx, run);
+-                      continue;
+-              }
+-
+-              ret = do_run(run);
+-              if (!ret)
+-                      break;
+-
+-              /*
+-               * something went wrong with start, add the run
+-               * to done q and continue to the next run in the
+-               * pending q.
+-               */
+-              run->status = ret;
+-              list_add_tail(&run->list, &chan->done_q);
+-              chan->current_run = NULL;
+-      }
+-}
+-
+-static void empty_done_q(struct ipu_image_convert_chan *chan)
+-{
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_convert_run *run;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      while (!list_empty(&chan->done_q)) {
+-              run = list_entry(chan->done_q.next,
+-                               struct ipu_image_convert_run,
+-                               list);
+-
+-              list_del(&run->list);
+-
+-              dev_dbg(priv->ipu->dev,
+-                      "%s: task %u: completing ctx %p run %p with %d\n",
+-                      __func__, chan->ic_task, run->ctx, run, run->status);
+-
+-              /* call the completion callback and free the run */
+-              spin_unlock_irqrestore(&chan->irqlock, flags);
+-              run->ctx->complete(run, run->ctx->complete_context);
+-              spin_lock_irqsave(&chan->irqlock, flags);
+-      }
+-
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-}
+-
+-/*
+- * the bottom half thread clears out the done_q, calling the
+- * completion handler for each.
+- */
+-static irqreturn_t do_bh(int irq, void *dev_id)
+-{
+-      struct ipu_image_convert_chan *chan = dev_id;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_convert_ctx *ctx;
+-      unsigned long flags;
+-
+-      dev_dbg(priv->ipu->dev, "%s: task %u: enter\n", __func__,
+-              chan->ic_task);
+-
+-      empty_done_q(chan);
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      /*
+-       * the done_q is cleared out, signal any contexts
+-       * that are aborting that abort can complete.
+-       */
+-      list_for_each_entry(ctx, &chan->ctx_list, list) {
+-              if (ctx->aborting) {
+-                      dev_dbg(priv->ipu->dev,
+-                              "%s: task %u: signaling abort for ctx %p\n",
+-                              __func__, chan->ic_task, ctx);
+-                      complete_all(&ctx->aborted);
+-              }
+-      }
+-
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-
+-      dev_dbg(priv->ipu->dev, "%s: task %u: exit\n", __func__,
+-              chan->ic_task);
+-
+-      return IRQ_HANDLED;
+-}
+-
+-static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx)
+-{
+-      unsigned int cur_tile = ctx->next_tile - 1;
+-      unsigned int next_tile = ctx->next_tile;
+-
+-      if (ctx->resize_coeffs_h[cur_tile % ctx->in.num_cols] !=
+-          ctx->resize_coeffs_h[next_tile % ctx->in.num_cols] ||
+-          ctx->resize_coeffs_v[cur_tile / ctx->in.num_cols] !=
+-          ctx->resize_coeffs_v[next_tile / ctx->in.num_cols] ||
+-          ctx->in.tile[cur_tile].width != ctx->in.tile[next_tile].width ||
+-          ctx->in.tile[cur_tile].height != ctx->in.tile[next_tile].height ||
+-          ctx->out.tile[cur_tile].width != ctx->out.tile[next_tile].width ||
+-          ctx->out.tile[cur_tile].height != ctx->out.tile[next_tile].height)
+-              return true;
+-
+-      return false;
+-}
+-
+-/* hold irqlock when calling */
+-static irqreturn_t do_irq(struct ipu_image_convert_run *run)
+-{
+-      struct ipu_image_convert_ctx *ctx = run->ctx;
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_tile *src_tile, *dst_tile;
+-      struct ipu_image_convert_image *s_image = &ctx->in;
+-      struct ipu_image_convert_image *d_image = &ctx->out;
+-      struct ipuv3_channel *outch;
+-      unsigned int dst_idx;
+-
+-      lockdep_assert_held(&chan->irqlock);
+-
+-      outch = ipu_rot_mode_is_irt(ctx->rot_mode) ?
+-              chan->rotation_out_chan : chan->out_chan;
+-
+-      /*
+-       * It is difficult to stop the channel DMA before the channels
+-       * enter the paused state. Without double-buffering the channels
+-       * are always in a paused state when the EOF irq occurs, so it
+-       * is safe to stop the channels now. For double-buffering we
+-       * just ignore the abort until the operation completes, when it
+-       * is safe to shut down.
+-       */
+-      if (ctx->aborting && !ctx->double_buffering) {
+-              convert_stop(run);
+-              run->status = -EIO;
+-              goto done;
+-      }
+-
+-      if (ctx->next_tile == ctx->num_tiles) {
+-              /*
+-               * the conversion is complete
+-               */
+-              convert_stop(run);
+-              run->status = 0;
+-              goto done;
+-      }
+-
+-      /*
+-       * not done, place the next tile buffers.
+-       */
+-      if (!ctx->double_buffering) {
+-              if (ic_settings_changed(ctx)) {
+-                      convert_stop(run);
+-                      convert_start(run, ctx->next_tile);
+-              } else {
+-                      src_tile = &s_image->tile[ctx->next_tile];
+-                      dst_idx = ctx->out_tile_map[ctx->next_tile];
+-                      dst_tile = &d_image->tile[dst_idx];
+-
+-                      ipu_cpmem_set_buffer(chan->in_chan, 0,
+-                                           s_image->base.phys0 +
+-                                           src_tile->offset);
+-                      ipu_cpmem_set_buffer(outch, 0,
+-                                           d_image->base.phys0 +
+-                                           dst_tile->offset);
+-                      if (s_image->fmt->planar)
+-                              ipu_cpmem_set_uv_offset(chan->in_chan,
+-                                                      src_tile->u_off,
+-                                                      src_tile->v_off);
+-                      if (d_image->fmt->planar)
+-                              ipu_cpmem_set_uv_offset(outch,
+-                                                      dst_tile->u_off,
+-                                                      dst_tile->v_off);
+-
+-                      ipu_idmac_select_buffer(chan->in_chan, 0);
+-                      ipu_idmac_select_buffer(outch, 0);
+-              }
+-      } else if (ctx->next_tile < ctx->num_tiles - 1) {
+-
+-              src_tile = &s_image->tile[ctx->next_tile + 1];
+-              dst_idx = ctx->out_tile_map[ctx->next_tile + 1];
+-              dst_tile = &d_image->tile[dst_idx];
+-
+-              ipu_cpmem_set_buffer(chan->in_chan, ctx->cur_buf_num,
+-                                   s_image->base.phys0 + src_tile->offset);
+-              ipu_cpmem_set_buffer(outch, ctx->cur_buf_num,
+-                                   d_image->base.phys0 + dst_tile->offset);
+-
+-              ipu_idmac_select_buffer(chan->in_chan, ctx->cur_buf_num);
+-              ipu_idmac_select_buffer(outch, ctx->cur_buf_num);
+-
+-              ctx->cur_buf_num ^= 1;
+-      }
+-
+-      ctx->next_tile++;
+-      return IRQ_HANDLED;
+-done:
+-      list_add_tail(&run->list, &chan->done_q);
+-      chan->current_run = NULL;
+-      run_next(chan);
+-      return IRQ_WAKE_THREAD;
+-}
+-
+-static irqreturn_t norotate_irq(int irq, void *data)
+-{
+-      struct ipu_image_convert_chan *chan = data;
+-      struct ipu_image_convert_ctx *ctx;
+-      struct ipu_image_convert_run *run;
+-      unsigned long flags;
+-      irqreturn_t ret;
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      /* get current run and its context */
+-      run = chan->current_run;
+-      if (!run) {
+-              ret = IRQ_NONE;
+-              goto out;
+-      }
+-
+-      ctx = run->ctx;
+-
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              /* this is a rotation operation, just ignore */
+-              spin_unlock_irqrestore(&chan->irqlock, flags);
+-              return IRQ_HANDLED;
+-      }
+-
+-      ret = do_irq(run);
+-out:
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-      return ret;
+-}
+-
+-static irqreturn_t rotate_irq(int irq, void *data)
+-{
+-      struct ipu_image_convert_chan *chan = data;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_convert_ctx *ctx;
+-      struct ipu_image_convert_run *run;
+-      unsigned long flags;
+-      irqreturn_t ret;
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      /* get current run and its context */
+-      run = chan->current_run;
+-      if (!run) {
+-              ret = IRQ_NONE;
+-              goto out;
+-      }
+-
+-      ctx = run->ctx;
+-
+-      if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              /* this was NOT a rotation operation, shouldn't happen */
+-              dev_err(priv->ipu->dev, "Unexpected rotation interrupt\n");
+-              spin_unlock_irqrestore(&chan->irqlock, flags);
+-              return IRQ_HANDLED;
+-      }
+-
+-      ret = do_irq(run);
+-out:
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-      return ret;
+-}
+-
+-/*
+- * try to force the completion of runs for this ctx. Called when
+- * abort wait times out in ipu_image_convert_abort().
+- */
+-static void force_abort(struct ipu_image_convert_ctx *ctx)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_run *run;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      run = chan->current_run;
+-      if (run && run->ctx == ctx) {
+-              convert_stop(run);
+-              run->status = -EIO;
+-              list_add_tail(&run->list, &chan->done_q);
+-              chan->current_run = NULL;
+-              run_next(chan);
+-      }
+-
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-
+-      empty_done_q(chan);
+-}
+-
+-static void release_ipu_resources(struct ipu_image_convert_chan *chan)
+-{
+-      if (chan->out_eof_irq >= 0)
+-              free_irq(chan->out_eof_irq, chan);
+-      if (chan->rot_out_eof_irq >= 0)
+-              free_irq(chan->rot_out_eof_irq, chan);
+-
+-      if (!IS_ERR_OR_NULL(chan->in_chan))
+-              ipu_idmac_put(chan->in_chan);
+-      if (!IS_ERR_OR_NULL(chan->out_chan))
+-              ipu_idmac_put(chan->out_chan);
+-      if (!IS_ERR_OR_NULL(chan->rotation_in_chan))
+-              ipu_idmac_put(chan->rotation_in_chan);
+-      if (!IS_ERR_OR_NULL(chan->rotation_out_chan))
+-              ipu_idmac_put(chan->rotation_out_chan);
+-      if (!IS_ERR_OR_NULL(chan->ic))
+-              ipu_ic_put(chan->ic);
+-
+-      chan->in_chan = chan->out_chan = chan->rotation_in_chan =
+-              chan->rotation_out_chan = NULL;
+-      chan->out_eof_irq = chan->rot_out_eof_irq = -1;
+-}
+-
+-static int get_ipu_resources(struct ipu_image_convert_chan *chan)
+-{
+-      const struct ipu_image_convert_dma_chan *dma = chan->dma_ch;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      int ret;
+-
+-      /* get IC */
+-      chan->ic = ipu_ic_get(priv->ipu, chan->ic_task);
+-      if (IS_ERR(chan->ic)) {
+-              dev_err(priv->ipu->dev, "could not acquire IC\n");
+-              ret = PTR_ERR(chan->ic);
+-              goto err;
+-      }
+-
+-      /* get IDMAC channels */
+-      chan->in_chan = ipu_idmac_get(priv->ipu, dma->in);
+-      chan->out_chan = ipu_idmac_get(priv->ipu, dma->out);
+-      if (IS_ERR(chan->in_chan) || IS_ERR(chan->out_chan)) {
+-              dev_err(priv->ipu->dev, "could not acquire idmac channels\n");
+-              ret = -EBUSY;
+-              goto err;
+-      }
+-
+-      chan->rotation_in_chan = ipu_idmac_get(priv->ipu, dma->rot_in);
+-      chan->rotation_out_chan = ipu_idmac_get(priv->ipu, dma->rot_out);
+-      if (IS_ERR(chan->rotation_in_chan) || IS_ERR(chan->rotation_out_chan)) {
+-              dev_err(priv->ipu->dev,
+-                      "could not acquire idmac rotation channels\n");
+-              ret = -EBUSY;
+-              goto err;
+-      }
+-
+-      /* acquire the EOF interrupts */
+-      chan->out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
+-                                                chan->out_chan,
+-                                                IPU_IRQ_EOF);
+-
+-      ret = request_threaded_irq(chan->out_eof_irq, norotate_irq, do_bh,
+-                                 0, "ipu-ic", chan);
+-      if (ret < 0) {
+-              dev_err(priv->ipu->dev, "could not acquire irq %d\n",
+-                       chan->out_eof_irq);
+-              chan->out_eof_irq = -1;
+-              goto err;
+-      }
+-
+-      chan->rot_out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
+-                                                   chan->rotation_out_chan,
+-                                                   IPU_IRQ_EOF);
+-
+-      ret = request_threaded_irq(chan->rot_out_eof_irq, rotate_irq, do_bh,
+-                                 0, "ipu-ic", chan);
+-      if (ret < 0) {
+-              dev_err(priv->ipu->dev, "could not acquire irq %d\n",
+-                      chan->rot_out_eof_irq);
+-              chan->rot_out_eof_irq = -1;
+-              goto err;
+-      }
+-
+-      return 0;
+-err:
+-      release_ipu_resources(chan);
+-      return ret;
+-}
+-
+-static int fill_image(struct ipu_image_convert_ctx *ctx,
+-                    struct ipu_image_convert_image *ic_image,
+-                    struct ipu_image *image,
+-                    enum ipu_image_convert_type type)
+-{
+-      struct ipu_image_convert_priv *priv = ctx->chan->priv;
+-
+-      ic_image->base = *image;
+-      ic_image->type = type;
+-
+-      ic_image->fmt = get_format(image->pix.pixelformat);
+-      if (!ic_image->fmt) {
+-              dev_err(priv->ipu->dev, "pixelformat not supported for %s\n",
+-                      type == IMAGE_CONVERT_OUT ? "Output" : "Input");
+-              return -EINVAL;
+-      }
+-
+-      if (ic_image->fmt->planar)
+-              ic_image->stride = ic_image->base.pix.width;
+-      else
+-              ic_image->stride  = ic_image->base.pix.bytesperline;
+-
+-      return 0;
+-}
+-
+-/* borrowed from drivers/media/v4l2-core/v4l2-common.c */
+-static unsigned int clamp_align(unsigned int x, unsigned int min,
+-                              unsigned int max, unsigned int align)
+-{
+-      /* Bits that must be zero to be aligned */
+-      unsigned int mask = ~((1 << align) - 1);
+-
+-      /* Clamp to aligned min and max */
+-      x = clamp(x, (min + ~mask) & mask, max & mask);
+-
+-      /* Round to nearest aligned value */
+-      if (align)
+-              x = (x + (1 << (align - 1))) & mask;
+-
+-      return x;
+-}
+-
+-/* Adjusts input/output images to IPU restrictions */
+-void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
+-                            enum ipu_rotate_mode rot_mode)
+-{
+-      const struct ipu_image_pixfmt *infmt, *outfmt;
+-      u32 w_align_out, h_align_out;
+-      u32 w_align_in, h_align_in;
+-
+-      infmt = get_format(in->pix.pixelformat);
+-      outfmt = get_format(out->pix.pixelformat);
+-
+-      /* set some default pixel formats if needed */
+-      if (!infmt) {
+-              in->pix.pixelformat = V4L2_PIX_FMT_RGB24;
+-              infmt = get_format(V4L2_PIX_FMT_RGB24);
+-      }
+-      if (!outfmt) {
+-              out->pix.pixelformat = V4L2_PIX_FMT_RGB24;
+-              outfmt = get_format(V4L2_PIX_FMT_RGB24);
+-      }
+-
+-      /* image converter does not handle fields */
+-      in->pix.field = out->pix.field = V4L2_FIELD_NONE;
+-
+-      /* resizer cannot downsize more than 4:1 */
+-      if (ipu_rot_mode_is_irt(rot_mode)) {
+-              out->pix.height = max_t(__u32, out->pix.height,
+-                                      in->pix.width / 4);
+-              out->pix.width = max_t(__u32, out->pix.width,
+-                                     in->pix.height / 4);
+-      } else {
+-              out->pix.width = max_t(__u32, out->pix.width,
+-                                     in->pix.width / 4);
+-              out->pix.height = max_t(__u32, out->pix.height,
+-                                      in->pix.height / 4);
+-      }
+-
+-      /* align input width/height */
+-      w_align_in = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt,
+-                                          rot_mode));
+-      h_align_in = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt,
+-                                           rot_mode));
+-      in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W,
+-                                  w_align_in);
+-      in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H,
+-                                   h_align_in);
+-
+-      /* align output width/height */
+-      w_align_out = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt,
+-                                           rot_mode));
+-      h_align_out = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt,
+-                                            rot_mode));
+-      out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W,
+-                                   w_align_out);
+-      out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H,
+-                                    h_align_out);
+-
+-      /* set input/output strides and image sizes */
+-      in->pix.bytesperline = infmt->planar ?
+-              clamp_align(in->pix.width, 2 << w_align_in, MAX_W,
+-                          w_align_in) :
+-              clamp_align((in->pix.width * infmt->bpp) >> 3,
+-                          ((2 << w_align_in) * infmt->bpp) >> 3,
+-                          (MAX_W * infmt->bpp) >> 3,
+-                          w_align_in);
+-      in->pix.sizeimage = infmt->planar ?
+-              (in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 :
+-              in->pix.height * in->pix.bytesperline;
+-      out->pix.bytesperline = outfmt->planar ? out->pix.width :
+-              (out->pix.width * outfmt->bpp) >> 3;
+-      out->pix.sizeimage = outfmt->planar ?
+-              (out->pix.height * out->pix.bytesperline * outfmt->bpp) >> 3 :
+-              out->pix.height * out->pix.bytesperline;
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_adjust);
+-
+-/*
+- * this is used by ipu_image_convert_prepare() to verify set input and
+- * output images are valid before starting the conversion. Clients can
+- * also call it before calling ipu_image_convert_prepare().
+- */
+-int ipu_image_convert_verify(struct ipu_image *in, struct ipu_image *out,
+-                           enum ipu_rotate_mode rot_mode)
+-{
+-      struct ipu_image testin, testout;
+-
+-      testin = *in;
+-      testout = *out;
+-
+-      ipu_image_convert_adjust(&testin, &testout, rot_mode);
+-
+-      if (testin.pix.width != in->pix.width ||
+-          testin.pix.height != in->pix.height ||
+-          testout.pix.width != out->pix.width ||
+-          testout.pix.height != out->pix.height)
+-              return -EINVAL;
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_verify);
+-
+-/*
+- * Call ipu_image_convert_prepare() to prepare for the conversion of
+- * given images and rotation mode. Returns a new conversion context.
+- */
+-struct ipu_image_convert_ctx *
+-ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
+-                        struct ipu_image *in, struct ipu_image *out,
+-                        enum ipu_rotate_mode rot_mode,
+-                        ipu_image_convert_cb_t complete,
+-                        void *complete_context)
+-{
+-      struct ipu_image_convert_priv *priv = ipu->image_convert_priv;
+-      struct ipu_image_convert_image *s_image, *d_image;
+-      struct ipu_image_convert_chan *chan;
+-      struct ipu_image_convert_ctx *ctx;
+-      unsigned long flags;
+-      unsigned int i;
+-      bool get_res;
+-      int ret;
+-
+-      if (!in || !out || !complete ||
+-          (ic_task != IC_TASK_VIEWFINDER &&
+-           ic_task != IC_TASK_POST_PROCESSOR))
+-              return ERR_PTR(-EINVAL);
+-
+-      /* verify the in/out images before continuing */
+-      ret = ipu_image_convert_verify(in, out, rot_mode);
+-      if (ret) {
+-              dev_err(priv->ipu->dev, "%s: in/out formats invalid\n",
+-                      __func__);
+-              return ERR_PTR(ret);
+-      }
+-
+-      chan = &priv->chan[ic_task];
+-
+-      ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+-      if (!ctx)
+-              return ERR_PTR(-ENOMEM);
+-
+-      dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p\n", __func__,
+-              chan->ic_task, ctx);
+-
+-      ctx->chan = chan;
+-      init_completion(&ctx->aborted);
+-
+-      ctx->rot_mode = rot_mode;
+-
+-      /* Sets ctx->in.num_rows/cols as well */
+-      ret = calc_image_resize_coefficients(ctx, in, out);
+-      if (ret)
+-              goto out_free;
+-
+-      s_image = &ctx->in;
+-      d_image = &ctx->out;
+-
+-      /* set tiling and rotation */
+-      if (ipu_rot_mode_is_irt(rot_mode)) {
+-              d_image->num_rows = s_image->num_cols;
+-              d_image->num_cols = s_image->num_rows;
+-      } else {
+-              d_image->num_rows = s_image->num_rows;
+-              d_image->num_cols = s_image->num_cols;
+-      }
+-
+-      ctx->num_tiles = d_image->num_cols * d_image->num_rows;
+-
+-      ret = fill_image(ctx, s_image, in, IMAGE_CONVERT_IN);
+-      if (ret)
+-              goto out_free;
+-      ret = fill_image(ctx, d_image, out, IMAGE_CONVERT_OUT);
+-      if (ret)
+-              goto out_free;
+-
+-      calc_out_tile_map(ctx);
+-
+-      find_seams(ctx, s_image, d_image);
+-
+-      ret = calc_tile_dimensions(ctx, s_image);
+-      if (ret)
+-              goto out_free;
+-
+-      ret = calc_tile_offsets(ctx, s_image);
+-      if (ret)
+-              goto out_free;
+-
+-      calc_tile_dimensions(ctx, d_image);
+-      ret = calc_tile_offsets(ctx, d_image);
+-      if (ret)
+-              goto out_free;
+-
+-      calc_tile_resize_coefficients(ctx);
+-
+-      ret = ipu_ic_calc_csc(&ctx->csc,
+-                      s_image->base.pix.ycbcr_enc,
+-                      s_image->base.pix.quantization,
+-                      ipu_pixelformat_to_colorspace(s_image->fmt->fourcc),
+-                      d_image->base.pix.ycbcr_enc,
+-                      d_image->base.pix.quantization,
+-                      ipu_pixelformat_to_colorspace(d_image->fmt->fourcc));
+-      if (ret)
+-              goto out_free;
+-
+-      dump_format(ctx, s_image);
+-      dump_format(ctx, d_image);
+-
+-      ctx->complete = complete;
+-      ctx->complete_context = complete_context;
+-
+-      /*
+-       * Can we use double-buffering for this operation? If there is
+-       * only one tile (the whole image can be converted in a single
+-       * operation) there's no point in using double-buffering. Also,
+-       * the IPU's IDMAC channels allow only a single U and V plane
+-       * offset shared between both buffers, but these offsets change
+-       * for every tile, and therefore would have to be updated for
+-       * each buffer which is not possible. So double-buffering is
+-       * impossible when either the source or destination images are
+-       * a planar format (YUV420, YUV422P, etc.). Further, differently
+-       * sized tiles or different resizing coefficients per tile
+-       * prevent double-buffering as well.
+-       */
+-      ctx->double_buffering = (ctx->num_tiles > 1 &&
+-                               !s_image->fmt->planar &&
+-                               !d_image->fmt->planar);
+-      for (i = 1; i < ctx->num_tiles; i++) {
+-              if (ctx->in.tile[i].width != ctx->in.tile[0].width ||
+-                  ctx->in.tile[i].height != ctx->in.tile[0].height ||
+-                  ctx->out.tile[i].width != ctx->out.tile[0].width ||
+-                  ctx->out.tile[i].height != ctx->out.tile[0].height) {
+-                      ctx->double_buffering = false;
+-                      break;
+-              }
+-      }
+-      for (i = 1; i < ctx->in.num_cols; i++) {
+-              if (ctx->resize_coeffs_h[i] != ctx->resize_coeffs_h[0]) {
+-                      ctx->double_buffering = false;
+-                      break;
+-              }
+-      }
+-      for (i = 1; i < ctx->in.num_rows; i++) {
+-              if (ctx->resize_coeffs_v[i] != ctx->resize_coeffs_v[0]) {
+-                      ctx->double_buffering = false;
+-                      break;
+-              }
+-      }
+-
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              unsigned long intermediate_size = d_image->tile[0].size;
+-
+-              for (i = 1; i < ctx->num_tiles; i++) {
+-                      if (d_image->tile[i].size > intermediate_size)
+-                              intermediate_size = d_image->tile[i].size;
+-              }
+-
+-              ret = alloc_dma_buf(priv, &ctx->rot_intermediate[0],
+-                                  intermediate_size);
+-              if (ret)
+-                      goto out_free;
+-              if (ctx->double_buffering) {
+-                      ret = alloc_dma_buf(priv,
+-                                          &ctx->rot_intermediate[1],
+-                                          intermediate_size);
+-                      if (ret)
+-                              goto out_free_dmabuf0;
+-              }
+-      }
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      get_res = list_empty(&chan->ctx_list);
+-
+-      list_add_tail(&ctx->list, &chan->ctx_list);
+-
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-
+-      if (get_res) {
+-              ret = get_ipu_resources(chan);
+-              if (ret)
+-                      goto out_free_dmabuf1;
+-      }
+-
+-      return ctx;
+-
+-out_free_dmabuf1:
+-      free_dma_buf(priv, &ctx->rot_intermediate[1]);
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-      list_del(&ctx->list);
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-out_free_dmabuf0:
+-      free_dma_buf(priv, &ctx->rot_intermediate[0]);
+-out_free:
+-      kfree(ctx);
+-      return ERR_PTR(ret);
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_prepare);
+-
+-/*
+- * Carry out a single image conversion run. Only the physaddr's of the input
+- * and output image buffers are needed. The conversion context must have
+- * been created previously with ipu_image_convert_prepare().
+- */
+-int ipu_image_convert_queue(struct ipu_image_convert_run *run)
+-{
+-      struct ipu_image_convert_chan *chan;
+-      struct ipu_image_convert_priv *priv;
+-      struct ipu_image_convert_ctx *ctx;
+-      unsigned long flags;
+-      int ret = 0;
+-
+-      if (!run || !run->ctx || !run->in_phys || !run->out_phys)
+-              return -EINVAL;
+-
+-      ctx = run->ctx;
+-      chan = ctx->chan;
+-      priv = chan->priv;
+-
+-      dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p run %p\n", __func__,
+-              chan->ic_task, ctx, run);
+-
+-      INIT_LIST_HEAD(&run->list);
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      if (ctx->aborting) {
+-              ret = -EIO;
+-              goto unlock;
+-      }
+-
+-      list_add_tail(&run->list, &chan->pending_q);
+-
+-      if (!chan->current_run) {
+-              ret = do_run(run);
+-              if (ret)
+-                      chan->current_run = NULL;
+-      }
+-unlock:
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_queue);
+-
+-/* Abort any active or pending conversions for this context */
+-static void __ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_convert_run *run, *active_run, *tmp;
+-      unsigned long flags;
+-      int run_count, ret;
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      /* move all remaining pending runs in this context to done_q */
+-      list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
+-              if (run->ctx != ctx)
+-                      continue;
+-              run->status = -EIO;
+-              list_move_tail(&run->list, &chan->done_q);
+-      }
+-
+-      run_count = get_run_count(ctx, &chan->done_q);
+-      active_run = (chan->current_run && chan->current_run->ctx == ctx) ?
+-              chan->current_run : NULL;
+-
+-      if (active_run)
+-              reinit_completion(&ctx->aborted);
+-
+-      ctx->aborting = true;
+-
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-
+-      if (!run_count && !active_run) {
+-              dev_dbg(priv->ipu->dev,
+-                      "%s: task %u: no abort needed for ctx %p\n",
+-                      __func__, chan->ic_task, ctx);
+-              return;
+-      }
+-
+-      if (!active_run) {
+-              empty_done_q(chan);
+-              return;
+-      }
+-
+-      dev_dbg(priv->ipu->dev,
+-              "%s: task %u: wait for completion: %d runs\n",
+-              __func__, chan->ic_task, run_count);
+-
+-      ret = wait_for_completion_timeout(&ctx->aborted,
+-                                        msecs_to_jiffies(10000));
+-      if (ret == 0) {
+-              dev_warn(priv->ipu->dev, "%s: timeout\n", __func__);
+-              force_abort(ctx);
+-      }
+-}
+-
+-void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
+-{
+-      __ipu_image_convert_abort(ctx);
+-      ctx->aborting = false;
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_abort);
+-
+-/* Unprepare image conversion context */
+-void ipu_image_convert_unprepare(struct ipu_image_convert_ctx *ctx)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      unsigned long flags;
+-      bool put_res;
+-
+-      /* make sure no runs are hanging around */
+-      __ipu_image_convert_abort(ctx);
+-
+-      dev_dbg(priv->ipu->dev, "%s: task %u: removing ctx %p\n", __func__,
+-              chan->ic_task, ctx);
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      list_del(&ctx->list);
+-
+-      put_res = list_empty(&chan->ctx_list);
+-
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-
+-      if (put_res)
+-              release_ipu_resources(chan);
+-
+-      free_dma_buf(priv, &ctx->rot_intermediate[1]);
+-      free_dma_buf(priv, &ctx->rot_intermediate[0]);
+-
+-      kfree(ctx);
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_unprepare);
+-
+-/*
+- * "Canned" asynchronous single image conversion. Allocates and returns
+- * a new conversion run.  On successful return the caller must free the
+- * run and call ipu_image_convert_unprepare() after conversion completes.
+- */
+-struct ipu_image_convert_run *
+-ipu_image_convert(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
+-                struct ipu_image *in, struct ipu_image *out,
+-                enum ipu_rotate_mode rot_mode,
+-                ipu_image_convert_cb_t complete,
+-                void *complete_context)
+-{
+-      struct ipu_image_convert_ctx *ctx;
+-      struct ipu_image_convert_run *run;
+-      int ret;
+-
+-      ctx = ipu_image_convert_prepare(ipu, ic_task, in, out, rot_mode,
+-                                      complete, complete_context);
+-      if (IS_ERR(ctx))
+-              return ERR_CAST(ctx);
+-
+-      run = kzalloc(sizeof(*run), GFP_KERNEL);
+-      if (!run) {
+-              ipu_image_convert_unprepare(ctx);
+-              return ERR_PTR(-ENOMEM);
+-      }
+-
+-      run->ctx = ctx;
+-      run->in_phys = in->phys0;
+-      run->out_phys = out->phys0;
+-
+-      ret = ipu_image_convert_queue(run);
+-      if (ret) {
+-              ipu_image_convert_unprepare(ctx);
+-              kfree(run);
+-              return ERR_PTR(ret);
+-      }
+-
+-      return run;
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert);
+-
+-/* "Canned" synchronous single image conversion */
+-static void image_convert_sync_complete(struct ipu_image_convert_run *run,
+-                                      void *data)
+-{
+-      struct completion *comp = data;
+-
+-      complete(comp);
+-}
+-
+-int ipu_image_convert_sync(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
+-                         struct ipu_image *in, struct ipu_image *out,
+-                         enum ipu_rotate_mode rot_mode)
+-{
+-      struct ipu_image_convert_run *run;
+-      struct completion comp;
+-      int ret;
+-
+-      init_completion(&comp);
+-
+-      run = ipu_image_convert(ipu, ic_task, in, out, rot_mode,
+-                              image_convert_sync_complete, &comp);
+-      if (IS_ERR(run))
+-              return PTR_ERR(run);
+-
+-      ret = wait_for_completion_timeout(&comp, msecs_to_jiffies(10000));
+-      ret = (ret == 0) ? -ETIMEDOUT : 0;
+-
+-      ipu_image_convert_unprepare(run->ctx);
+-      kfree(run);
+-
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_sync);
+-
+-int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev)
+-{
+-      struct ipu_image_convert_priv *priv;
+-      int i;
+-
+-      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-      if (!priv)
+-              return -ENOMEM;
+-
+-      ipu->image_convert_priv = priv;
+-      priv->ipu = ipu;
+-
+-      for (i = 0; i < IC_NUM_TASKS; i++) {
+-              struct ipu_image_convert_chan *chan = &priv->chan[i];
+-
+-              chan->ic_task = i;
+-              chan->priv = priv;
+-              chan->dma_ch = &image_convert_dma_chan[i];
+-              chan->out_eof_irq = -1;
+-              chan->rot_out_eof_irq = -1;
+-
+-              spin_lock_init(&chan->irqlock);
+-              INIT_LIST_HEAD(&chan->ctx_list);
+-              INIT_LIST_HEAD(&chan->pending_q);
+-              INIT_LIST_HEAD(&chan->done_q);
+-      }
+-
+-      return 0;
+-}
+-
+-void ipu_image_convert_exit(struct ipu_soc *ipu)
+-{
+-}
+--- a/drivers/gpu/ipu-v3/ipu-pre.c
++++ /dev/null
+@@ -1,346 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-only
+-/*
+- * Copyright (c) 2017 Lucas Stach, Pengutronix
+- */
+-
+-#include <drm/drm_fourcc.h>
+-#include <linux/clk.h>
+-#include <linux/err.h>
+-#include <linux/genalloc.h>
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/platform_device.h>
+-#include <video/imx-ipu-v3.h>
+-
+-#include "ipu-prv.h"
+-
+-#define IPU_PRE_MAX_WIDTH     2048
+-#define IPU_PRE_NUM_SCANLINES 8
+-
+-#define IPU_PRE_CTRL                                  0x000
+-#define IPU_PRE_CTRL_SET                              0x004
+-#define  IPU_PRE_CTRL_ENABLE                          (1 << 0)
+-#define  IPU_PRE_CTRL_BLOCK_EN                                (1 << 1)
+-#define  IPU_PRE_CTRL_BLOCK_16                                (1 << 2)
+-#define  IPU_PRE_CTRL_SDW_UPDATE                      (1 << 4)
+-#define  IPU_PRE_CTRL_VFLIP                           (1 << 5)
+-#define  IPU_PRE_CTRL_SO                              (1 << 6)
+-#define  IPU_PRE_CTRL_INTERLACED_FIELD                        (1 << 7)
+-#define  IPU_PRE_CTRL_HANDSHAKE_EN                    (1 << 8)
+-#define  IPU_PRE_CTRL_HANDSHAKE_LINE_NUM(v)           ((v & 0x3) << 9)
+-#define  IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN         (1 << 11)
+-#define  IPU_PRE_CTRL_EN_REPEAT                               (1 << 28)
+-#define  IPU_PRE_CTRL_TPR_REST_SEL                    (1 << 29)
+-#define  IPU_PRE_CTRL_CLKGATE                         (1 << 30)
+-#define  IPU_PRE_CTRL_SFTRST                          (1 << 31)
+-
+-#define IPU_PRE_CUR_BUF                                       0x030
+-
+-#define IPU_PRE_NEXT_BUF                              0x040
+-
+-#define IPU_PRE_TPR_CTRL                              0x070
+-#define  IPU_PRE_TPR_CTRL_TILE_FORMAT(v)              ((v & 0xff) << 0)
+-#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK            0xff
+-#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT          (1 << 0)
+-#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_SPLIT_BUF               (1 << 4)
+-#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF      (1 << 5)
+-#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED     (1 << 6)
+-
+-#define IPU_PRE_PREFETCH_ENG_CTRL                     0x080
+-#define  IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN            (1 << 0)
+-#define  IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(v)                ((v & 0x7) << 1)
+-#define  IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(v)    ((v & 0x3) << 4)
+-#define  IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(v)  ((v & 0x7) << 8)
+-#define  IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS           (1 << 11)
+-#define  IPU_PRE_PREF_ENG_CTRL_FIELD_INVERSE          (1 << 12)
+-#define  IPU_PRE_PREF_ENG_CTRL_PARTIAL_UV_SWAP                (1 << 14)
+-#define  IPU_PRE_PREF_ENG_CTRL_TPR_COOR_OFFSET_EN     (1 << 15)
+-
+-#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE                       0x0a0
+-#define  IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(v)     ((v & 0xffff) << 0)
+-#define  IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(v)    ((v & 0xffff) << 16)
+-
+-#define IPU_PRE_PREFETCH_ENG_PITCH                    0x0d0
+-#define  IPU_PRE_PREFETCH_ENG_PITCH_Y(v)              ((v & 0xffff) << 0)
+-#define  IPU_PRE_PREFETCH_ENG_PITCH_UV(v)             ((v & 0xffff) << 16)
+-
+-#define IPU_PRE_STORE_ENG_CTRL                                0x110
+-#define  IPU_PRE_STORE_ENG_CTRL_STORE_EN              (1 << 0)
+-#define  IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(v)               ((v & 0x7) << 1)
+-#define  IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(v)  ((v & 0x3) << 4)
+-
+-#define IPU_PRE_STORE_ENG_STATUS                      0x120
+-#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_MASK  0xffff
+-#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_SHIFT 0
+-#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK  0x3fff
+-#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT 16
+-#define  IPU_PRE_STORE_ENG_STATUS_STORE_FIFO_FULL     (1 << 30)
+-#define  IPU_PRE_STORE_ENG_STATUS_STORE_FIELD         (1 << 31)
+-
+-#define IPU_PRE_STORE_ENG_SIZE                                0x130
+-#define  IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(v)                ((v & 0xffff) << 0)
+-#define  IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(v)               ((v & 0xffff) << 16)
+-
+-#define IPU_PRE_STORE_ENG_PITCH                               0x140
+-#define  IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(v)         ((v & 0xffff) << 0)
+-
+-#define IPU_PRE_STORE_ENG_ADDR                                0x150
+-
+-struct ipu_pre {
+-      struct list_head        list;
+-      struct device           *dev;
+-
+-      void __iomem            *regs;
+-      struct clk              *clk_axi;
+-      struct gen_pool         *iram;
+-
+-      dma_addr_t              buffer_paddr;
+-      void                    *buffer_virt;
+-      bool                    in_use;
+-      unsigned int            safe_window_end;
+-      unsigned int            last_bufaddr;
+-};
+-
+-static DEFINE_MUTEX(ipu_pre_list_mutex);
+-static LIST_HEAD(ipu_pre_list);
+-static int available_pres;
+-
+-int ipu_pre_get_available_count(void)
+-{
+-      return available_pres;
+-}
+-
+-struct ipu_pre *
+-ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
+-{
+-      struct device_node *pre_node = of_parse_phandle(dev->of_node,
+-                                                      name, index);
+-      struct ipu_pre *pre;
+-
+-      mutex_lock(&ipu_pre_list_mutex);
+-      list_for_each_entry(pre, &ipu_pre_list, list) {
+-              if (pre_node == pre->dev->of_node) {
+-                      mutex_unlock(&ipu_pre_list_mutex);
+-                      device_link_add(dev, pre->dev,
+-                                      DL_FLAG_AUTOREMOVE_CONSUMER);
+-                      of_node_put(pre_node);
+-                      return pre;
+-              }
+-      }
+-      mutex_unlock(&ipu_pre_list_mutex);
+-
+-      of_node_put(pre_node);
+-
+-      return NULL;
+-}
+-
+-int ipu_pre_get(struct ipu_pre *pre)
+-{
+-      u32 val;
+-
+-      if (pre->in_use)
+-              return -EBUSY;
+-
+-      /* first get the engine out of reset and remove clock gating */
+-      writel(0, pre->regs + IPU_PRE_CTRL);
+-
+-      /* init defaults that should be applied to all streams */
+-      val = IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN |
+-            IPU_PRE_CTRL_HANDSHAKE_EN |
+-            IPU_PRE_CTRL_TPR_REST_SEL |
+-            IPU_PRE_CTRL_SDW_UPDATE;
+-      writel(val, pre->regs + IPU_PRE_CTRL);
+-
+-      pre->in_use = true;
+-      return 0;
+-}
+-
+-void ipu_pre_put(struct ipu_pre *pre)
+-{
+-      writel(IPU_PRE_CTRL_SFTRST, pre->regs + IPU_PRE_CTRL);
+-
+-      pre->in_use = false;
+-}
+-
+-void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
+-                     unsigned int height, unsigned int stride, u32 format,
+-                     uint64_t modifier, unsigned int bufaddr)
+-{
+-      const struct drm_format_info *info = drm_format_info(format);
+-      u32 active_bpp = info->cpp[0] >> 1;
+-      u32 val;
+-
+-      /* calculate safe window for ctrl register updates */
+-      if (modifier == DRM_FORMAT_MOD_LINEAR)
+-              pre->safe_window_end = height - 2;
+-      else
+-              pre->safe_window_end = DIV_ROUND_UP(height, 4) - 1;
+-
+-      writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF);
+-      writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
+-      pre->last_bufaddr = bufaddr;
+-
+-      val = IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(0) |
+-            IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(active_bpp) |
+-            IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(4) |
+-            IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS |
+-            IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN;
+-      writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_CTRL);
+-
+-      val = IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(width) |
+-            IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(height);
+-      writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_INPUT_SIZE);
+-
+-      val = IPU_PRE_PREFETCH_ENG_PITCH_Y(stride);
+-      writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_PITCH);
+-
+-      val = IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(active_bpp) |
+-            IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(4) |
+-            IPU_PRE_STORE_ENG_CTRL_STORE_EN;
+-      writel(val, pre->regs + IPU_PRE_STORE_ENG_CTRL);
+-
+-      val = IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(width) |
+-            IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(height);
+-      writel(val, pre->regs + IPU_PRE_STORE_ENG_SIZE);
+-
+-      val = IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(stride);
+-      writel(val, pre->regs + IPU_PRE_STORE_ENG_PITCH);
+-
+-      writel(pre->buffer_paddr, pre->regs + IPU_PRE_STORE_ENG_ADDR);
+-
+-      val = readl(pre->regs + IPU_PRE_TPR_CTRL);
+-      val &= ~IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK;
+-      if (modifier != DRM_FORMAT_MOD_LINEAR) {
+-              /* only support single buffer formats for now */
+-              val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF;
+-              if (modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED)
+-                      val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED;
+-              if (info->cpp[0] == 2)
+-                      val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT;
+-      }
+-      writel(val, pre->regs + IPU_PRE_TPR_CTRL);
+-
+-      val = readl(pre->regs + IPU_PRE_CTRL);
+-      val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE |
+-             IPU_PRE_CTRL_SDW_UPDATE;
+-      if (modifier == DRM_FORMAT_MOD_LINEAR)
+-              val &= ~IPU_PRE_CTRL_BLOCK_EN;
+-      else
+-              val |= IPU_PRE_CTRL_BLOCK_EN;
+-      writel(val, pre->regs + IPU_PRE_CTRL);
+-}
+-
+-void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
+-{
+-      unsigned long timeout = jiffies + msecs_to_jiffies(5);
+-      unsigned short current_yblock;
+-      u32 val;
+-
+-      if (bufaddr == pre->last_bufaddr)
+-              return;
+-
+-      writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
+-      pre->last_bufaddr = bufaddr;
+-
+-      do {
+-              if (time_after(jiffies, timeout)) {
+-                      dev_warn(pre->dev, "timeout waiting for PRE safe window\n");
+-                      return;
+-              }
+-
+-              val = readl(pre->regs + IPU_PRE_STORE_ENG_STATUS);
+-              current_yblock =
+-                      (val >> IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT) &
+-                      IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK;
+-      } while (current_yblock == 0 || current_yblock >= pre->safe_window_end);
+-
+-      writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
+-}
+-
+-bool ipu_pre_update_pending(struct ipu_pre *pre)
+-{
+-      return !!(readl_relaxed(pre->regs + IPU_PRE_CTRL) &
+-                IPU_PRE_CTRL_SDW_UPDATE);
+-}
+-
+-u32 ipu_pre_get_baddr(struct ipu_pre *pre)
+-{
+-      return (u32)pre->buffer_paddr;
+-}
+-
+-static int ipu_pre_probe(struct platform_device *pdev)
+-{
+-      struct device *dev = &pdev->dev;
+-      struct resource *res;
+-      struct ipu_pre *pre;
+-
+-      pre = devm_kzalloc(dev, sizeof(*pre), GFP_KERNEL);
+-      if (!pre)
+-              return -ENOMEM;
+-
+-      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-      pre->regs = devm_ioremap_resource(&pdev->dev, res);
+-      if (IS_ERR(pre->regs))
+-              return PTR_ERR(pre->regs);
+-
+-      pre->clk_axi = devm_clk_get(dev, "axi");
+-      if (IS_ERR(pre->clk_axi))
+-              return PTR_ERR(pre->clk_axi);
+-
+-      pre->iram = of_gen_pool_get(dev->of_node, "fsl,iram", 0);
+-      if (!pre->iram)
+-              return -EPROBE_DEFER;
+-
+-      /*
+-       * Allocate IRAM buffer with maximum size. This could be made dynamic,
+-       * but as there is no other user of this IRAM region and we can fit all
+-       * max sized buffers into it, there is no need yet.
+-       */
+-      pre->buffer_virt = gen_pool_dma_alloc(pre->iram, IPU_PRE_MAX_WIDTH *
+-                                            IPU_PRE_NUM_SCANLINES * 4,
+-                                            &pre->buffer_paddr);
+-      if (!pre->buffer_virt)
+-              return -ENOMEM;
+-
+-      clk_prepare_enable(pre->clk_axi);
+-
+-      pre->dev = dev;
+-      platform_set_drvdata(pdev, pre);
+-      mutex_lock(&ipu_pre_list_mutex);
+-      list_add(&pre->list, &ipu_pre_list);
+-      available_pres++;
+-      mutex_unlock(&ipu_pre_list_mutex);
+-
+-      return 0;
+-}
+-
+-static int ipu_pre_remove(struct platform_device *pdev)
+-{
+-      struct ipu_pre *pre = platform_get_drvdata(pdev);
+-
+-      mutex_lock(&ipu_pre_list_mutex);
+-      list_del(&pre->list);
+-      available_pres--;
+-      mutex_unlock(&ipu_pre_list_mutex);
+-
+-      clk_disable_unprepare(pre->clk_axi);
+-
+-      if (pre->buffer_virt)
+-              gen_pool_free(pre->iram, (unsigned long)pre->buffer_virt,
+-                            IPU_PRE_MAX_WIDTH * IPU_PRE_NUM_SCANLINES * 4);
+-      return 0;
+-}
+-
+-static const struct of_device_id ipu_pre_dt_ids[] = {
+-      { .compatible = "fsl,imx6qp-pre", },
+-      { /* sentinel */ },
+-};
+-
+-struct platform_driver ipu_pre_drv = {
+-      .probe          = ipu_pre_probe,
+-      .remove         = ipu_pre_remove,
+-      .driver         = {
+-              .name   = "imx-ipu-pre",
+-              .of_match_table = ipu_pre_dt_ids,
+-      },
+-};
+--- a/drivers/gpu/ipu-v3/ipu-prg.c
++++ /dev/null
+@@ -1,483 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-only
+-/*
+- * Copyright (c) 2016-2017 Lucas Stach, Pengutronix
+- */
+-
+-#include <drm/drm_fourcc.h>
+-#include <linux/clk.h>
+-#include <linux/err.h>
+-#include <linux/iopoll.h>
+-#include <linux/mfd/syscon.h>
+-#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/platform_device.h>
+-#include <linux/pm_runtime.h>
+-#include <linux/regmap.h>
+-#include <video/imx-ipu-v3.h>
+-
+-#include "ipu-prv.h"
+-
+-#define IPU_PRG_CTL                           0x00
+-#define  IPU_PRG_CTL_BYPASS(i)                        (1 << (0 + i))
+-#define  IPU_PRG_CTL_SOFT_ARID_MASK           0x3
+-#define  IPU_PRG_CTL_SOFT_ARID_SHIFT(i)               (8 + i * 2)
+-#define  IPU_PRG_CTL_SOFT_ARID(i, v)          ((v & 0x3) << (8 + 2 * i))
+-#define  IPU_PRG_CTL_SO(i)                    (1 << (16 + i))
+-#define  IPU_PRG_CTL_VFLIP(i)                 (1 << (19 + i))
+-#define  IPU_PRG_CTL_BLOCK_MODE(i)            (1 << (22 + i))
+-#define  IPU_PRG_CTL_CNT_LOAD_EN(i)           (1 << (25 + i))
+-#define  IPU_PRG_CTL_SOFTRST                  (1 << 30)
+-#define  IPU_PRG_CTL_SHADOW_EN                        (1 << 31)
+-
+-#define IPU_PRG_STATUS                                0x04
+-#define  IPU_PRG_STATUS_BUFFER0_READY(i)      (1 << (0 + i * 2))
+-#define  IPU_PRG_STATUS_BUFFER1_READY(i)      (1 << (1 + i * 2))
+-
+-#define IPU_PRG_QOS                           0x08
+-#define  IPU_PRG_QOS_ARID_MASK                        0xf
+-#define  IPU_PRG_QOS_ARID_SHIFT(i)            (0 + i * 4)
+-
+-#define IPU_PRG_REG_UPDATE                    0x0c
+-#define  IPU_PRG_REG_UPDATE_REG_UPDATE                (1 << 0)
+-
+-#define IPU_PRG_STRIDE(i)                     (0x10 + i * 0x4)
+-#define  IPU_PRG_STRIDE_STRIDE_MASK           0x3fff
+-
+-#define IPU_PRG_CROP_LINE                     0x1c
+-
+-#define IPU_PRG_THD                           0x20
+-
+-#define IPU_PRG_BADDR(i)                      (0x24 + i * 0x4)
+-
+-#define IPU_PRG_OFFSET(i)                     (0x30 + i * 0x4)
+-
+-#define IPU_PRG_ILO(i)                                (0x3c + i * 0x4)
+-
+-#define IPU_PRG_HEIGHT(i)                     (0x48 + i * 0x4)
+-#define  IPU_PRG_HEIGHT_PRE_HEIGHT_MASK               0xfff
+-#define  IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT      0
+-#define  IPU_PRG_HEIGHT_IPU_HEIGHT_MASK               0xfff
+-#define  IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT      16
+-
+-struct ipu_prg_channel {
+-      bool                    enabled;
+-      int                     used_pre;
+-};
+-
+-struct ipu_prg {
+-      struct list_head        list;
+-      struct device           *dev;
+-      int                     id;
+-
+-      void __iomem            *regs;
+-      struct clk              *clk_ipg, *clk_axi;
+-      struct regmap           *iomuxc_gpr;
+-      struct ipu_pre          *pres[3];
+-
+-      struct ipu_prg_channel  chan[3];
+-};
+-
+-static DEFINE_MUTEX(ipu_prg_list_mutex);
+-static LIST_HEAD(ipu_prg_list);
+-
+-struct ipu_prg *
+-ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id)
+-{
+-      struct device_node *prg_node = of_parse_phandle(dev->of_node,
+-                                                      name, 0);
+-      struct ipu_prg *prg;
+-
+-      mutex_lock(&ipu_prg_list_mutex);
+-      list_for_each_entry(prg, &ipu_prg_list, list) {
+-              if (prg_node == prg->dev->of_node) {
+-                      mutex_unlock(&ipu_prg_list_mutex);
+-                      device_link_add(dev, prg->dev,
+-                                      DL_FLAG_AUTOREMOVE_CONSUMER);
+-                      prg->id = ipu_id;
+-                      of_node_put(prg_node);
+-                      return prg;
+-              }
+-      }
+-      mutex_unlock(&ipu_prg_list_mutex);
+-
+-      of_node_put(prg_node);
+-
+-      return NULL;
+-}
+-
+-int ipu_prg_max_active_channels(void)
+-{
+-      return ipu_pre_get_available_count();
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_max_active_channels);
+-
+-bool ipu_prg_present(struct ipu_soc *ipu)
+-{
+-      if (ipu->prg_priv)
+-              return true;
+-
+-      return false;
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_present);
+-
+-bool ipu_prg_format_supported(struct ipu_soc *ipu, uint32_t format,
+-                            uint64_t modifier)
+-{
+-      const struct drm_format_info *info = drm_format_info(format);
+-
+-      if (info->num_planes != 1)
+-              return false;
+-
+-      switch (modifier) {
+-      case DRM_FORMAT_MOD_LINEAR:
+-      case DRM_FORMAT_MOD_VIVANTE_TILED:
+-      case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+-              return true;
+-      default:
+-              return false;
+-      }
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_format_supported);
+-
+-int ipu_prg_enable(struct ipu_soc *ipu)
+-{
+-      struct ipu_prg *prg = ipu->prg_priv;
+-
+-      if (!prg)
+-              return 0;
+-
+-      return pm_runtime_get_sync(prg->dev);
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_enable);
+-
+-void ipu_prg_disable(struct ipu_soc *ipu)
+-{
+-      struct ipu_prg *prg = ipu->prg_priv;
+-
+-      if (!prg)
+-              return;
+-
+-      pm_runtime_put(prg->dev);
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_disable);
+-
+-/*
+- * The channel configuartion functions below are not thread safe, as they
+- * must be only called from the atomic commit path in the DRM driver, which
+- * is properly serialized.
+- */
+-static int ipu_prg_ipu_to_prg_chan(int ipu_chan)
+-{
+-      /*
+-       * This isn't clearly documented in the RM, but IPU to PRG channel
+-       * assignment is fixed, as only with this mapping the control signals
+-       * match up.
+-       */
+-      switch (ipu_chan) {
+-      case IPUV3_CHANNEL_MEM_BG_SYNC:
+-              return 0;
+-      case IPUV3_CHANNEL_MEM_FG_SYNC:
+-              return 1;
+-      case IPUV3_CHANNEL_MEM_DC_SYNC:
+-              return 2;
+-      default:
+-              return -EINVAL;
+-      }
+-}
+-
+-static int ipu_prg_get_pre(struct ipu_prg *prg, int prg_chan)
+-{
+-      int i, ret;
+-
+-      /* channel 0 is special as it is hardwired to one of the PREs */
+-      if (prg_chan == 0) {
+-              ret = ipu_pre_get(prg->pres[0]);
+-              if (ret)
+-                      goto fail;
+-              prg->chan[prg_chan].used_pre = 0;
+-              return 0;
+-      }
+-
+-      for (i = 1; i < 3; i++) {
+-              ret = ipu_pre_get(prg->pres[i]);
+-              if (!ret) {
+-                      u32 val, mux;
+-                      int shift;
+-
+-                      prg->chan[prg_chan].used_pre = i;
+-
+-                      /* configure the PRE to PRG channel mux */
+-                      shift = (i == 1) ? 12 : 14;
+-                      mux = (prg->id << 1) | (prg_chan - 1);
+-                      regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
+-                                         0x3 << shift, mux << shift);
+-
+-                      /* check other mux, must not point to same channel */
+-                      shift = (i == 1) ? 14 : 12;
+-                      regmap_read(prg->iomuxc_gpr, IOMUXC_GPR5, &val);
+-                      if (((val >> shift) & 0x3) == mux) {
+-                              regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
+-                                                 0x3 << shift,
+-                                                 (mux ^ 0x1) << shift);
+-                      }
+-
+-                      return 0;
+-              }
+-      }
+-
+-fail:
+-      dev_err(prg->dev, "could not get PRE for PRG chan %d", prg_chan);
+-      return ret;
+-}
+-
+-static void ipu_prg_put_pre(struct ipu_prg *prg, int prg_chan)
+-{
+-      struct ipu_prg_channel *chan = &prg->chan[prg_chan];
+-
+-      ipu_pre_put(prg->pres[chan->used_pre]);
+-      chan->used_pre = -1;
+-}
+-
+-void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan)
+-{
+-      int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
+-      struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
+-      struct ipu_prg_channel *chan;
+-      u32 val;
+-
+-      if (prg_chan < 0)
+-              return;
+-
+-      chan = &prg->chan[prg_chan];
+-      if (!chan->enabled)
+-              return;
+-
+-      pm_runtime_get_sync(prg->dev);
+-
+-      val = readl(prg->regs + IPU_PRG_CTL);
+-      val |= IPU_PRG_CTL_BYPASS(prg_chan);
+-      writel(val, prg->regs + IPU_PRG_CTL);
+-
+-      val = IPU_PRG_REG_UPDATE_REG_UPDATE;
+-      writel(val, prg->regs + IPU_PRG_REG_UPDATE);
+-
+-      pm_runtime_put(prg->dev);
+-
+-      ipu_prg_put_pre(prg, prg_chan);
+-
+-      chan->enabled = false;
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_channel_disable);
+-
+-int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
+-                            unsigned int axi_id, unsigned int width,
+-                            unsigned int height, unsigned int stride,
+-                            u32 format, uint64_t modifier, unsigned long *eba)
+-{
+-      int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
+-      struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
+-      struct ipu_prg_channel *chan;
+-      u32 val;
+-      int ret;
+-
+-      if (prg_chan < 0)
+-              return prg_chan;
+-
+-      chan = &prg->chan[prg_chan];
+-
+-      if (chan->enabled) {
+-              ipu_pre_update(prg->pres[chan->used_pre], *eba);
+-              return 0;
+-      }
+-
+-      ret = ipu_prg_get_pre(prg, prg_chan);
+-      if (ret)
+-              return ret;
+-
+-      ipu_pre_configure(prg->pres[chan->used_pre],
+-                        width, height, stride, format, modifier, *eba);
+-
+-
+-      pm_runtime_get_sync(prg->dev);
+-
+-      val = (stride - 1) & IPU_PRG_STRIDE_STRIDE_MASK;
+-      writel(val, prg->regs + IPU_PRG_STRIDE(prg_chan));
+-
+-      val = ((height & IPU_PRG_HEIGHT_PRE_HEIGHT_MASK) <<
+-             IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT) |
+-            ((height & IPU_PRG_HEIGHT_IPU_HEIGHT_MASK) <<
+-             IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT);
+-      writel(val, prg->regs + IPU_PRG_HEIGHT(prg_chan));
+-
+-      val = ipu_pre_get_baddr(prg->pres[chan->used_pre]);
+-      *eba = val;
+-      writel(val, prg->regs + IPU_PRG_BADDR(prg_chan));
+-
+-      val = readl(prg->regs + IPU_PRG_CTL);
+-      /* config AXI ID */
+-      val &= ~(IPU_PRG_CTL_SOFT_ARID_MASK <<
+-               IPU_PRG_CTL_SOFT_ARID_SHIFT(prg_chan));
+-      val |= IPU_PRG_CTL_SOFT_ARID(prg_chan, axi_id);
+-      /* enable channel */
+-      val &= ~IPU_PRG_CTL_BYPASS(prg_chan);
+-      writel(val, prg->regs + IPU_PRG_CTL);
+-
+-      val = IPU_PRG_REG_UPDATE_REG_UPDATE;
+-      writel(val, prg->regs + IPU_PRG_REG_UPDATE);
+-
+-      /* wait for both double buffers to be filled */
+-      readl_poll_timeout(prg->regs + IPU_PRG_STATUS, val,
+-                         (val & IPU_PRG_STATUS_BUFFER0_READY(prg_chan)) &&
+-                         (val & IPU_PRG_STATUS_BUFFER1_READY(prg_chan)),
+-                         5, 1000);
+-
+-      pm_runtime_put(prg->dev);
+-
+-      chan->enabled = true;
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_channel_configure);
+-
+-bool ipu_prg_channel_configure_pending(struct ipuv3_channel *ipu_chan)
+-{
+-      int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
+-      struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
+-      struct ipu_prg_channel *chan;
+-
+-      if (prg_chan < 0)
+-              return false;
+-
+-      chan = &prg->chan[prg_chan];
+-      WARN_ON(!chan->enabled);
+-
+-      return ipu_pre_update_pending(prg->pres[chan->used_pre]);
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_channel_configure_pending);
+-
+-static int ipu_prg_probe(struct platform_device *pdev)
+-{
+-      struct device *dev = &pdev->dev;
+-      struct resource *res;
+-      struct ipu_prg *prg;
+-      u32 val;
+-      int i, ret;
+-
+-      prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
+-      if (!prg)
+-              return -ENOMEM;
+-
+-      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-      prg->regs = devm_ioremap_resource(&pdev->dev, res);
+-      if (IS_ERR(prg->regs))
+-              return PTR_ERR(prg->regs);
+-
+-
+-      prg->clk_ipg = devm_clk_get(dev, "ipg");
+-      if (IS_ERR(prg->clk_ipg))
+-              return PTR_ERR(prg->clk_ipg);
+-
+-      prg->clk_axi = devm_clk_get(dev, "axi");
+-      if (IS_ERR(prg->clk_axi))
+-              return PTR_ERR(prg->clk_axi);
+-
+-      prg->iomuxc_gpr =
+-              syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
+-      if (IS_ERR(prg->iomuxc_gpr))
+-              return PTR_ERR(prg->iomuxc_gpr);
+-
+-      for (i = 0; i < 3; i++) {
+-              prg->pres[i] = ipu_pre_lookup_by_phandle(dev, "fsl,pres", i);
+-              if (!prg->pres[i])
+-                      return -EPROBE_DEFER;
+-      }
+-
+-      ret = clk_prepare_enable(prg->clk_ipg);
+-      if (ret)
+-              return ret;
+-
+-      ret = clk_prepare_enable(prg->clk_axi);
+-      if (ret) {
+-              clk_disable_unprepare(prg->clk_ipg);
+-              return ret;
+-      }
+-
+-      /* init to free running mode */
+-      val = readl(prg->regs + IPU_PRG_CTL);
+-      val |= IPU_PRG_CTL_SHADOW_EN;
+-      writel(val, prg->regs + IPU_PRG_CTL);
+-
+-      /* disable address threshold */
+-      writel(0xffffffff, prg->regs + IPU_PRG_THD);
+-
+-      pm_runtime_set_active(dev);
+-      pm_runtime_enable(dev);
+-
+-      prg->dev = dev;
+-      platform_set_drvdata(pdev, prg);
+-      mutex_lock(&ipu_prg_list_mutex);
+-      list_add(&prg->list, &ipu_prg_list);
+-      mutex_unlock(&ipu_prg_list_mutex);
+-
+-      return 0;
+-}
+-
+-static int ipu_prg_remove(struct platform_device *pdev)
+-{
+-      struct ipu_prg *prg = platform_get_drvdata(pdev);
+-
+-      mutex_lock(&ipu_prg_list_mutex);
+-      list_del(&prg->list);
+-      mutex_unlock(&ipu_prg_list_mutex);
+-
+-      return 0;
+-}
+-
+-#ifdef CONFIG_PM
+-static int prg_suspend(struct device *dev)
+-{
+-      struct ipu_prg *prg = dev_get_drvdata(dev);
+-
+-      clk_disable_unprepare(prg->clk_axi);
+-      clk_disable_unprepare(prg->clk_ipg);
+-
+-      return 0;
+-}
+-
+-static int prg_resume(struct device *dev)
+-{
+-      struct ipu_prg *prg = dev_get_drvdata(dev);
+-      int ret;
+-
+-      ret = clk_prepare_enable(prg->clk_ipg);
+-      if (ret)
+-              return ret;
+-
+-      ret = clk_prepare_enable(prg->clk_axi);
+-      if (ret) {
+-              clk_disable_unprepare(prg->clk_ipg);
+-              return ret;
+-      }
+-
+-      return 0;
+-}
+-#endif
+-
+-static const struct dev_pm_ops prg_pm_ops = {
+-      SET_RUNTIME_PM_OPS(prg_suspend, prg_resume, NULL)
+-};
+-
+-static const struct of_device_id ipu_prg_dt_ids[] = {
+-      { .compatible = "fsl,imx6qp-prg", },
+-      { /* sentinel */ },
+-};
+-
+-struct platform_driver ipu_prg_drv = {
+-      .probe          = ipu_prg_probe,
+-      .remove         = ipu_prg_remove,
+-      .driver         = {
+-              .name   = "imx-ipu-prg",
+-              .pm     = &prg_pm_ops,
+-              .of_match_table = ipu_prg_dt_ids,
+-      },
+-};
+--- a/drivers/gpu/ipu-v3/ipu-prv.h
++++ /dev/null
+@@ -1,274 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0-or-later */
+-/*
+- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-#ifndef __IPU_PRV_H__
+-#define __IPU_PRV_H__
+-
+-struct ipu_soc;
+-
+-#include <linux/types.h>
+-#include <linux/device.h>
+-#include <linux/clk.h>
+-#include <linux/platform_device.h>
+-
+-#include <video/imx-ipu-v3.h>
+-
+-#define IPU_MCU_T_DEFAULT     8
+-#define IPU_CM_IDMAC_REG_OFS  0x00008000
+-#define IPU_CM_IC_REG_OFS     0x00020000
+-#define IPU_CM_IRT_REG_OFS    0x00028000
+-#define IPU_CM_CSI0_REG_OFS   0x00030000
+-#define IPU_CM_CSI1_REG_OFS   0x00038000
+-#define IPU_CM_SMFC_REG_OFS   0x00050000
+-#define IPU_CM_DC_REG_OFS     0x00058000
+-#define IPU_CM_DMFC_REG_OFS   0x00060000
+-
+-/* Register addresses */
+-/* IPU Common registers */
+-#define IPU_CM_REG(offset)    (offset)
+-
+-#define IPU_CONF                      IPU_CM_REG(0)
+-
+-#define IPU_SRM_PRI1                  IPU_CM_REG(0x00a0)
+-#define IPU_SRM_PRI2                  IPU_CM_REG(0x00a4)
+-#define IPU_FS_PROC_FLOW1             IPU_CM_REG(0x00a8)
+-#define IPU_FS_PROC_FLOW2             IPU_CM_REG(0x00ac)
+-#define IPU_FS_PROC_FLOW3             IPU_CM_REG(0x00b0)
+-#define IPU_FS_DISP_FLOW1             IPU_CM_REG(0x00b4)
+-#define IPU_FS_DISP_FLOW2             IPU_CM_REG(0x00b8)
+-#define IPU_SKIP                      IPU_CM_REG(0x00bc)
+-#define IPU_DISP_ALT_CONF             IPU_CM_REG(0x00c0)
+-#define IPU_DISP_GEN                  IPU_CM_REG(0x00c4)
+-#define IPU_DISP_ALT1                 IPU_CM_REG(0x00c8)
+-#define IPU_DISP_ALT2                 IPU_CM_REG(0x00cc)
+-#define IPU_DISP_ALT3                 IPU_CM_REG(0x00d0)
+-#define IPU_DISP_ALT4                 IPU_CM_REG(0x00d4)
+-#define IPU_SNOOP                     IPU_CM_REG(0x00d8)
+-#define IPU_MEM_RST                   IPU_CM_REG(0x00dc)
+-#define IPU_PM                                IPU_CM_REG(0x00e0)
+-#define IPU_GPR                               IPU_CM_REG(0x00e4)
+-#define IPU_CHA_DB_MODE_SEL(ch)               IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
+-#define IPU_ALT_CHA_DB_MODE_SEL(ch)   IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
+-#define IPU_CHA_CUR_BUF(ch)           IPU_CM_REG(0x023C + 4 * ((ch) / 32))
+-#define IPU_ALT_CUR_BUF0              IPU_CM_REG(0x0244)
+-#define IPU_ALT_CUR_BUF1              IPU_CM_REG(0x0248)
+-#define IPU_SRM_STAT                  IPU_CM_REG(0x024C)
+-#define IPU_PROC_TASK_STAT            IPU_CM_REG(0x0250)
+-#define IPU_DISP_TASK_STAT            IPU_CM_REG(0x0254)
+-#define IPU_CHA_BUF0_RDY(ch)          IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
+-#define IPU_CHA_BUF1_RDY(ch)          IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
+-#define IPU_CHA_BUF2_RDY(ch)          IPU_CM_REG(0x0288 + 4 * ((ch) / 32))
+-#define IPU_ALT_CHA_BUF0_RDY(ch)      IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
+-#define IPU_ALT_CHA_BUF1_RDY(ch)      IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
+-
+-#define IPU_INT_CTRL(n)               IPU_CM_REG(0x003C + 4 * (n))
+-#define IPU_INT_STAT(n)               IPU_CM_REG(0x0200 + 4 * (n))
+-
+-/* SRM_PRI2 */
+-#define DP_S_SRM_MODE_MASK            (0x3 << 3)
+-#define DP_S_SRM_MODE_NOW             (0x3 << 3)
+-#define DP_S_SRM_MODE_NEXT_FRAME      (0x1 << 3)
+-
+-/* FS_PROC_FLOW1 */
+-#define FS_PRPENC_ROT_SRC_SEL_MASK    (0xf << 0)
+-#define FS_PRPENC_ROT_SRC_SEL_ENC             (0x7 << 0)
+-#define FS_PRPVF_ROT_SRC_SEL_MASK     (0xf << 8)
+-#define FS_PRPVF_ROT_SRC_SEL_VF                       (0x8 << 8)
+-#define FS_PP_SRC_SEL_MASK            (0xf << 12)
+-#define FS_PP_ROT_SRC_SEL_MASK                (0xf << 16)
+-#define FS_PP_ROT_SRC_SEL_PP                  (0x5 << 16)
+-#define FS_VDI1_SRC_SEL_MASK          (0x3 << 20)
+-#define FS_VDI3_SRC_SEL_MASK          (0x3 << 20)
+-#define FS_PRP_SRC_SEL_MASK           (0xf << 24)
+-#define FS_VDI_SRC_SEL_MASK           (0x3 << 28)
+-#define FS_VDI_SRC_SEL_CSI_DIRECT             (0x1 << 28)
+-#define FS_VDI_SRC_SEL_VDOA                   (0x2 << 28)
+-
+-/* FS_PROC_FLOW2 */
+-#define FS_PRP_ENC_DEST_SEL_MASK      (0xf << 0)
+-#define FS_PRP_ENC_DEST_SEL_IRT_ENC           (0x1 << 0)
+-#define FS_PRPVF_DEST_SEL_MASK                (0xf << 4)
+-#define FS_PRPVF_DEST_SEL_IRT_VF              (0x1 << 4)
+-#define FS_PRPVF_ROT_DEST_SEL_MASK    (0xf << 8)
+-#define FS_PP_DEST_SEL_MASK           (0xf << 12)
+-#define FS_PP_DEST_SEL_IRT_PP                 (0x3 << 12)
+-#define FS_PP_ROT_DEST_SEL_MASK               (0xf << 16)
+-#define FS_PRPENC_ROT_DEST_SEL_MASK   (0xf << 20)
+-#define FS_PRP_DEST_SEL_MASK          (0xf << 24)
+-
+-#define IPU_DI0_COUNTER_RELEASE                       (1 << 24)
+-#define IPU_DI1_COUNTER_RELEASE                       (1 << 25)
+-
+-#define IPU_IDMAC_REG(offset) (offset)
+-
+-#define IDMAC_CONF                    IPU_IDMAC_REG(0x0000)
+-#define IDMAC_CHA_EN(ch)              IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
+-#define IDMAC_SEP_ALPHA                       IPU_IDMAC_REG(0x000c)
+-#define IDMAC_ALT_SEP_ALPHA           IPU_IDMAC_REG(0x0010)
+-#define IDMAC_CHA_PRI(ch)             IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
+-#define IDMAC_WM_EN(ch)                       IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32))
+-#define IDMAC_CH_LOCK_EN_1            IPU_IDMAC_REG(0x0024)
+-#define IDMAC_CH_LOCK_EN_2            IPU_IDMAC_REG(0x0028)
+-#define IDMAC_SUB_ADDR_0              IPU_IDMAC_REG(0x002c)
+-#define IDMAC_SUB_ADDR_1              IPU_IDMAC_REG(0x0030)
+-#define IDMAC_SUB_ADDR_2              IPU_IDMAC_REG(0x0034)
+-#define IDMAC_BAND_EN(ch)             IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32))
+-#define IDMAC_CHA_BUSY(ch)            IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32))
+-
+-#define IPU_NUM_IRQS  (32 * 15)
+-
+-enum ipu_modules {
+-      IPU_CONF_CSI0_EN                = (1 << 0),
+-      IPU_CONF_CSI1_EN                = (1 << 1),
+-      IPU_CONF_IC_EN                  = (1 << 2),
+-      IPU_CONF_ROT_EN                 = (1 << 3),
+-      IPU_CONF_ISP_EN                 = (1 << 4),
+-      IPU_CONF_DP_EN                  = (1 << 5),
+-      IPU_CONF_DI0_EN                 = (1 << 6),
+-      IPU_CONF_DI1_EN                 = (1 << 7),
+-      IPU_CONF_SMFC_EN                = (1 << 8),
+-      IPU_CONF_DC_EN                  = (1 << 9),
+-      IPU_CONF_DMFC_EN                = (1 << 10),
+-
+-      IPU_CONF_VDI_EN                 = (1 << 12),
+-
+-      IPU_CONF_IDMAC_DIS              = (1 << 22),
+-
+-      IPU_CONF_IC_DMFC_SEL            = (1 << 25),
+-      IPU_CONF_IC_DMFC_SYNC           = (1 << 26),
+-      IPU_CONF_VDI_DMFC_SYNC          = (1 << 27),
+-
+-      IPU_CONF_CSI0_DATA_SOURCE       = (1 << 28),
+-      IPU_CONF_CSI1_DATA_SOURCE       = (1 << 29),
+-      IPU_CONF_IC_INPUT               = (1 << 30),
+-      IPU_CONF_CSI_SEL                = (1 << 31),
+-};
+-
+-struct ipuv3_channel {
+-      unsigned int num;
+-      struct ipu_soc *ipu;
+-      struct list_head list;
+-};
+-
+-struct ipu_cpmem;
+-struct ipu_csi;
+-struct ipu_dc_priv;
+-struct ipu_dmfc_priv;
+-struct ipu_di;
+-struct ipu_ic_priv;
+-struct ipu_vdi;
+-struct ipu_image_convert_priv;
+-struct ipu_smfc_priv;
+-struct ipu_pre;
+-struct ipu_prg;
+-
+-struct ipu_devtype;
+-
+-struct ipu_soc {
+-      struct device           *dev;
+-      const struct ipu_devtype        *devtype;
+-      enum ipuv3_type         ipu_type;
+-      spinlock_t              lock;
+-      struct mutex            channel_lock;
+-      struct list_head        channels;
+-
+-      void __iomem            *cm_reg;
+-      void __iomem            *idmac_reg;
+-
+-      int                     id;
+-      int                     usecount;
+-
+-      struct clk              *clk;
+-
+-      int                     irq_sync;
+-      int                     irq_err;
+-      struct irq_domain       *domain;
+-
+-      struct ipu_cpmem        *cpmem_priv;
+-      struct ipu_dc_priv      *dc_priv;
+-      struct ipu_dp_priv      *dp_priv;
+-      struct ipu_dmfc_priv    *dmfc_priv;
+-      struct ipu_di           *di_priv[2];
+-      struct ipu_csi          *csi_priv[2];
+-      struct ipu_ic_priv      *ic_priv;
+-      struct ipu_vdi          *vdi_priv;
+-      struct ipu_image_convert_priv *image_convert_priv;
+-      struct ipu_smfc_priv    *smfc_priv;
+-      struct ipu_prg          *prg_priv;
+-};
+-
+-static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
+-{
+-      return readl(ipu->idmac_reg + offset);
+-}
+-
+-static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
+-                                 unsigned offset)
+-{
+-      writel(value, ipu->idmac_reg + offset);
+-}
+-
+-void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync);
+-
+-int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
+-int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
+-
+-bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno);
+-
+-int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
+-               unsigned long base, u32 module, struct clk *clk_ipu);
+-void ipu_csi_exit(struct ipu_soc *ipu, int id);
+-
+-int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
+-              unsigned long base, unsigned long tpmem_base);
+-void ipu_ic_exit(struct ipu_soc *ipu);
+-
+-int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
+-               unsigned long base, u32 module);
+-void ipu_vdi_exit(struct ipu_soc *ipu);
+-
+-int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev);
+-void ipu_image_convert_exit(struct ipu_soc *ipu);
+-
+-int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
+-              unsigned long base, u32 module, struct clk *ipu_clk);
+-void ipu_di_exit(struct ipu_soc *ipu, int id);
+-
+-int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
+-              struct clk *ipu_clk);
+-void ipu_dmfc_exit(struct ipu_soc *ipu);
+-
+-int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
+-void ipu_dp_exit(struct ipu_soc *ipu);
+-
+-int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
+-              unsigned long template_base);
+-void ipu_dc_exit(struct ipu_soc *ipu);
+-
+-int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
+-void ipu_cpmem_exit(struct ipu_soc *ipu);
+-
+-int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
+-void ipu_smfc_exit(struct ipu_soc *ipu);
+-
+-struct ipu_pre *ipu_pre_lookup_by_phandle(struct device *dev, const char *name,
+-                                        int index);
+-int ipu_pre_get_available_count(void);
+-int ipu_pre_get(struct ipu_pre *pre);
+-void ipu_pre_put(struct ipu_pre *pre);
+-u32 ipu_pre_get_baddr(struct ipu_pre *pre);
+-void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
+-                     unsigned int height, unsigned int stride, u32 format,
+-                     uint64_t modifier, unsigned int bufaddr);
+-void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr);
+-bool ipu_pre_update_pending(struct ipu_pre *pre);
+-
+-struct ipu_prg *ipu_prg_lookup_by_phandle(struct device *dev, const char *name,
+-                                        int ipu_id);
+-
+-extern struct platform_driver ipu_pre_drv;
+-extern struct platform_driver ipu_prg_drv;
+-
+-#endif                                /* __IPU_PRV_H__ */
+--- a/drivers/gpu/ipu-v3/ipu-smfc.c
++++ /dev/null
+@@ -1,202 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+- */
+-#include <linux/export.h>
+-#include <linux/types.h>
+-#include <linux/init.h>
+-#include <linux/io.h>
+-#include <linux/errno.h>
+-#include <linux/spinlock.h>
+-#include <linux/delay.h>
+-#include <linux/clk.h>
+-#include <video/imx-ipu-v3.h>
+-
+-#include "ipu-prv.h"
+-
+-struct ipu_smfc {
+-      struct ipu_smfc_priv *priv;
+-      int chno;
+-      bool inuse;
+-};
+-
+-struct ipu_smfc_priv {
+-      void __iomem *base;
+-      spinlock_t lock;
+-      struct ipu_soc *ipu;
+-      struct ipu_smfc channel[4];
+-      int use_count;
+-};
+-
+-/*SMFC Registers */
+-#define SMFC_MAP      0x0000
+-#define SMFC_WMC      0x0004
+-#define SMFC_BS               0x0008
+-
+-int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
+-{
+-      struct ipu_smfc_priv *priv = smfc->priv;
+-      unsigned long flags;
+-      u32 val, shift;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      shift = smfc->chno * 4;
+-      val = readl(priv->base + SMFC_BS);
+-      val &= ~(0xf << shift);
+-      val |= burstsize << shift;
+-      writel(val, priv->base + SMFC_BS);
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);
+-
+-int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
+-{
+-      struct ipu_smfc_priv *priv = smfc->priv;
+-      unsigned long flags;
+-      u32 val, shift;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      shift = smfc->chno * 3;
+-      val = readl(priv->base + SMFC_MAP);
+-      val &= ~(0x7 << shift);
+-      val |= ((csi_id << 2) | mipi_id) << shift;
+-      writel(val, priv->base + SMFC_MAP);
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
+-
+-int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level)
+-{
+-      struct ipu_smfc_priv *priv = smfc->priv;
+-      unsigned long flags;
+-      u32 val, shift;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0);
+-      val = readl(priv->base + SMFC_WMC);
+-      val &= ~(0x3f << shift);
+-      val |= ((clr_level << 3) | set_level) << shift;
+-      writel(val, priv->base + SMFC_WMC);
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark);
+-
+-int ipu_smfc_enable(struct ipu_smfc *smfc)
+-{
+-      struct ipu_smfc_priv *priv = smfc->priv;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      if (!priv->use_count)
+-              ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);
+-
+-      priv->use_count++;
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_smfc_enable);
+-
+-int ipu_smfc_disable(struct ipu_smfc *smfc)
+-{
+-      struct ipu_smfc_priv *priv = smfc->priv;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      priv->use_count--;
+-
+-      if (!priv->use_count)
+-              ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);
+-
+-      if (priv->use_count < 0)
+-              priv->use_count = 0;
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_smfc_disable);
+-
+-struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
+-{
+-      struct ipu_smfc_priv *priv = ipu->smfc_priv;
+-      struct ipu_smfc *smfc, *ret;
+-      unsigned long flags;
+-
+-      if (chno >= 4)
+-              return ERR_PTR(-EINVAL);
+-
+-      smfc = &priv->channel[chno];
+-      ret = smfc;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      if (smfc->inuse) {
+-              ret = ERR_PTR(-EBUSY);
+-              goto unlock;
+-      }
+-
+-      smfc->inuse = true;
+-unlock:
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_smfc_get);
+-
+-void ipu_smfc_put(struct ipu_smfc *smfc)
+-{
+-      struct ipu_smfc_priv *priv = smfc->priv;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-      smfc->inuse = false;
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_smfc_put);
+-
+-int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
+-                unsigned long base)
+-{
+-      struct ipu_smfc_priv *priv;
+-      int i;
+-
+-      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-      if (!priv)
+-              return -ENOMEM;
+-
+-      ipu->smfc_priv = priv;
+-      spin_lock_init(&priv->lock);
+-      priv->ipu = ipu;
+-
+-      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+-      if (!priv->base)
+-              return -ENOMEM;
+-
+-      for (i = 0; i < 4; i++) {
+-              priv->channel[i].priv = priv;
+-              priv->channel[i].chno = i;
+-      }
+-
+-      pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
+-
+-      return 0;
+-}
+-
+-void ipu_smfc_exit(struct ipu_soc *ipu)
+-{
+-}
+--- a/drivers/gpu/ipu-v3/ipu-vdi.c
++++ /dev/null
+@@ -1,234 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (C) 2012-2016 Mentor Graphics Inc.
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-#include <linux/io.h>
+-#include "ipu-prv.h"
+-
+-struct ipu_vdi {
+-      void __iomem *base;
+-      u32 module;
+-      spinlock_t lock;
+-      int use_count;
+-      struct ipu_soc *ipu;
+-};
+-
+-
+-/* VDI Register Offsets */
+-#define VDI_FSIZE 0x0000
+-#define VDI_C     0x0004
+-
+-/* VDI Register Fields */
+-#define VDI_C_CH_420             (0 << 1)
+-#define VDI_C_CH_422             (1 << 1)
+-#define VDI_C_MOT_SEL_MASK       (0x3 << 2)
+-#define VDI_C_MOT_SEL_FULL       (2 << 2)
+-#define VDI_C_MOT_SEL_LOW        (1 << 2)
+-#define VDI_C_MOT_SEL_MED        (0 << 2)
+-#define VDI_C_BURST_SIZE1_4      (3 << 4)
+-#define VDI_C_BURST_SIZE2_4      (3 << 8)
+-#define VDI_C_BURST_SIZE3_4      (3 << 12)
+-#define VDI_C_BURST_SIZE_MASK    0xF
+-#define VDI_C_BURST_SIZE1_OFFSET 4
+-#define VDI_C_BURST_SIZE2_OFFSET 8
+-#define VDI_C_BURST_SIZE3_OFFSET 12
+-#define VDI_C_VWM1_SET_1         (0 << 16)
+-#define VDI_C_VWM1_SET_2         (1 << 16)
+-#define VDI_C_VWM1_CLR_2         (1 << 19)
+-#define VDI_C_VWM3_SET_1         (0 << 22)
+-#define VDI_C_VWM3_SET_2         (1 << 22)
+-#define VDI_C_VWM3_CLR_2         (1 << 25)
+-#define VDI_C_TOP_FIELD_MAN_1    (1 << 30)
+-#define VDI_C_TOP_FIELD_AUTO_1   (1 << 31)
+-
+-static inline u32 ipu_vdi_read(struct ipu_vdi *vdi, unsigned int offset)
+-{
+-      return readl(vdi->base + offset);
+-}
+-
+-static inline void ipu_vdi_write(struct ipu_vdi *vdi, u32 value,
+-                               unsigned int offset)
+-{
+-      writel(value, vdi->base + offset);
+-}
+-
+-void ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field)
+-{
+-      bool top_field_0 = false;
+-      unsigned long flags;
+-      u32 reg;
+-
+-      switch (field) {
+-      case V4L2_FIELD_INTERLACED_TB:
+-      case V4L2_FIELD_SEQ_TB:
+-      case V4L2_FIELD_TOP:
+-              top_field_0 = true;
+-              break;
+-      case V4L2_FIELD_INTERLACED_BT:
+-      case V4L2_FIELD_SEQ_BT:
+-      case V4L2_FIELD_BOTTOM:
+-              top_field_0 = false;
+-              break;
+-      default:
+-              top_field_0 = (std & V4L2_STD_525_60) ? true : false;
+-              break;
+-      }
+-
+-      spin_lock_irqsave(&vdi->lock, flags);
+-
+-      reg = ipu_vdi_read(vdi, VDI_C);
+-      if (top_field_0)
+-              reg &= ~(VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1);
+-      else
+-              reg |= VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1;
+-      ipu_vdi_write(vdi, reg, VDI_C);
+-
+-      spin_unlock_irqrestore(&vdi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_set_field_order);
+-
+-void ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel)
+-{
+-      unsigned long flags;
+-      u32 reg;
+-
+-      spin_lock_irqsave(&vdi->lock, flags);
+-
+-      reg = ipu_vdi_read(vdi, VDI_C);
+-
+-      reg &= ~VDI_C_MOT_SEL_MASK;
+-
+-      switch (motion_sel) {
+-      case MED_MOTION:
+-              reg |= VDI_C_MOT_SEL_MED;
+-              break;
+-      case HIGH_MOTION:
+-              reg |= VDI_C_MOT_SEL_FULL;
+-              break;
+-      default:
+-              reg |= VDI_C_MOT_SEL_LOW;
+-              break;
+-      }
+-
+-      ipu_vdi_write(vdi, reg, VDI_C);
+-
+-      spin_unlock_irqrestore(&vdi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_set_motion);
+-
+-void ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres)
+-{
+-      unsigned long flags;
+-      u32 pixel_fmt, reg;
+-
+-      spin_lock_irqsave(&vdi->lock, flags);
+-
+-      reg = ((yres - 1) << 16) | (xres - 1);
+-      ipu_vdi_write(vdi, reg, VDI_FSIZE);
+-
+-      /*
+-       * Full motion, only vertical filter is used.
+-       * Burst size is 4 accesses
+-       */
+-      if (code == MEDIA_BUS_FMT_UYVY8_2X8 ||
+-          code == MEDIA_BUS_FMT_UYVY8_1X16 ||
+-          code == MEDIA_BUS_FMT_YUYV8_2X8 ||
+-          code == MEDIA_BUS_FMT_YUYV8_1X16)
+-              pixel_fmt = VDI_C_CH_422;
+-      else
+-              pixel_fmt = VDI_C_CH_420;
+-
+-      reg = ipu_vdi_read(vdi, VDI_C);
+-      reg |= pixel_fmt;
+-      reg |= VDI_C_BURST_SIZE2_4;
+-      reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_CLR_2;
+-      reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_CLR_2;
+-      ipu_vdi_write(vdi, reg, VDI_C);
+-
+-      spin_unlock_irqrestore(&vdi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_setup);
+-
+-void ipu_vdi_unsetup(struct ipu_vdi *vdi)
+-{
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&vdi->lock, flags);
+-      ipu_vdi_write(vdi, 0, VDI_FSIZE);
+-      ipu_vdi_write(vdi, 0, VDI_C);
+-      spin_unlock_irqrestore(&vdi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_unsetup);
+-
+-int ipu_vdi_enable(struct ipu_vdi *vdi)
+-{
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&vdi->lock, flags);
+-
+-      if (!vdi->use_count)
+-              ipu_module_enable(vdi->ipu, vdi->module);
+-
+-      vdi->use_count++;
+-
+-      spin_unlock_irqrestore(&vdi->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_enable);
+-
+-int ipu_vdi_disable(struct ipu_vdi *vdi)
+-{
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&vdi->lock, flags);
+-
+-      if (vdi->use_count) {
+-              if (!--vdi->use_count)
+-                      ipu_module_disable(vdi->ipu, vdi->module);
+-      }
+-
+-      spin_unlock_irqrestore(&vdi->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_disable);
+-
+-struct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu)
+-{
+-      return ipu->vdi_priv;
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_get);
+-
+-void ipu_vdi_put(struct ipu_vdi *vdi)
+-{
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_put);
+-
+-int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
+-               unsigned long base, u32 module)
+-{
+-      struct ipu_vdi *vdi;
+-
+-      vdi = devm_kzalloc(dev, sizeof(*vdi), GFP_KERNEL);
+-      if (!vdi)
+-              return -ENOMEM;
+-
+-      ipu->vdi_priv = vdi;
+-
+-      spin_lock_init(&vdi->lock);
+-      vdi->module = module;
+-      vdi->base = devm_ioremap(dev, base, PAGE_SIZE);
+-      if (!vdi->base)
+-              return -ENOMEM;
+-
+-      dev_dbg(dev, "VDI base: 0x%08lx remapped to %p\n", base, vdi->base);
+-      vdi->ipu = ipu;
+-
+-      return 0;
+-}
+-
+-void ipu_vdi_exit(struct ipu_soc *ipu)
+-{
+-}
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -15,7 +15,7 @@ source "drivers/char/agp/Kconfig"
+ source "drivers/gpu/vga/Kconfig"
+ source "drivers/gpu/host1x/Kconfig"
+-source "drivers/gpu/ipu-v3/Kconfig"
++source "drivers/gpu/imx/Kconfig"
+ source "drivers/gpu/drm/Kconfig"
diff --git a/target/linux/layerscape/patches-5.4/805-display-0044-drm-imx-Extract-IPUv3-specific-KMS-functions-to-ipuv.patch b/target/linux/layerscape/patches-5.4/805-display-0044-drm-imx-Extract-IPUv3-specific-KMS-functions-to-ipuv.patch
new file mode 100644 (file)
index 0000000..cd155a5
--- /dev/null
@@ -0,0 +1,142 @@
+From 6b1bc8ad2bdcfa0cbda91a0963aed746c424465d Mon Sep 17 00:00:00 2001
+From: Liu Ying <victor.liu@nxp.com>
+Date: Thu, 24 Jan 2019 17:06:30 +0800
+Subject: [PATCH] drm/imx: Extract IPUv3 specific KMS functions to ipuv3-kms.c
+ (part 1)
+
+Since we want to add i.MX DPU support into imx-drm, the imx-drm core
+driver should be no more IPUv3 specific.  Let's make imx-drm more generic
+and extract IPUv3 specific KMS functions to ipuv3-kms.c.
+
+Signed-off-by: Liu Ying <victor.liu@nxp.com>
+[ Aisheng: update to new kernel version accordingly ]
+[ Aisheng: split IPU changes out of imx-drm-core change ]
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ drivers/gpu/drm/imx/imx-drm-core.c | 81 --------------------------------------
+ drivers/gpu/drm/imx/imx-drm.h      |  5 +--
+ 2 files changed, 2 insertions(+), 84 deletions(-)
+
+--- a/drivers/gpu/drm/imx/imx-drm-core.c
++++ b/drivers/gpu/drm/imx/imx-drm-core.c
+@@ -26,9 +26,6 @@
+ #include <drm/drm_vblank.h>
+ #include "imx-drm.h"
+-#include "ipuv3-plane.h"
+-
+-#define MAX_CRTC      4
+ static int legacyfb_depth = 16;
+ module_param(legacyfb_depth, int, 0444);
+@@ -48,81 +45,6 @@ void imx_drm_encoder_destroy(struct drm_
+ }
+ EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
+-static int imx_drm_atomic_check(struct drm_device *dev,
+-                              struct drm_atomic_state *state)
+-{
+-      int ret;
+-
+-      ret = drm_atomic_helper_check(dev, state);
+-      if (ret)
+-              return ret;
+-
+-      /*
+-       * Check modeset again in case crtc_state->mode_changed is
+-       * updated in plane's ->atomic_check callback.
+-       */
+-      ret = drm_atomic_helper_check_modeset(dev, state);
+-      if (ret)
+-              return ret;
+-
+-      /* Assign PRG/PRE channels and check if all constrains are satisfied. */
+-      ret = ipu_planes_assign_pre(dev, state);
+-      if (ret)
+-              return ret;
+-
+-      return ret;
+-}
+-
+-static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
+-      .fb_create = drm_gem_fb_create,
+-      .atomic_check = imx_drm_atomic_check,
+-      .atomic_commit = drm_atomic_helper_commit,
+-};
+-
+-static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
+-{
+-      struct drm_device *dev = state->dev;
+-      struct drm_plane *plane;
+-      struct drm_plane_state *old_plane_state, *new_plane_state;
+-      bool plane_disabling = false;
+-      int i;
+-
+-      drm_atomic_helper_commit_modeset_disables(dev, state);
+-
+-      drm_atomic_helper_commit_planes(dev, state,
+-                              DRM_PLANE_COMMIT_ACTIVE_ONLY |
+-                              DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET);
+-
+-      drm_atomic_helper_commit_modeset_enables(dev, state);
+-
+-      for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
+-              if (drm_atomic_plane_disabling(old_plane_state, new_plane_state))
+-                      plane_disabling = true;
+-      }
+-
+-      /*
+-       * The flip done wait is only strictly required by imx-drm if a deferred
+-       * plane disable is in-flight. As the core requires blocking commits
+-       * to wait for the flip it is done here unconditionally. This keeps the
+-       * workitem around a bit longer than required for the majority of
+-       * non-blocking commits, but we accept that for the sake of simplicity.
+-       */
+-      drm_atomic_helper_wait_for_flip_done(dev, state);
+-
+-      if (plane_disabling) {
+-              for_each_old_plane_in_state(state, plane, old_plane_state, i)
+-                      ipu_plane_disable_deferred(plane);
+-
+-      }
+-
+-      drm_atomic_helper_commit_hw_done(state);
+-}
+-
+-static const struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = {
+-      .atomic_commit_tail = imx_drm_atomic_commit_tail,
+-};
+-
+-
+ int imx_drm_encoder_parse_of(struct drm_device *drm,
+       struct drm_encoder *encoder, struct device_node *np)
+ {
+@@ -223,9 +145,6 @@ static int imx_drm_bind(struct device *d
+       drm->mode_config.min_height = 1;
+       drm->mode_config.max_width = 4096;
+       drm->mode_config.max_height = 4096;
+-      drm->mode_config.funcs = &imx_drm_mode_config_funcs;
+-      drm->mode_config.helper_private = &imx_drm_mode_config_helpers;
+-      drm->mode_config.allow_fb_modifiers = true;
+       drm->mode_config.normalize_zpos = true;
+       drm_mode_config_init(drm);
+--- a/drivers/gpu/drm/imx/imx-drm.h
++++ b/drivers/gpu/drm/imx/imx-drm.h
+@@ -2,6 +2,8 @@
+ #ifndef _IMX_DRM_H_
+ #define _IMX_DRM_H_
++#define MAX_CRTC      4
++
+ struct device_node;
+ struct drm_crtc;
+ struct drm_connector;
+@@ -38,7 +40,4 @@ int imx_drm_encoder_parse_of(struct drm_
+ void imx_drm_connector_destroy(struct drm_connector *connector);
+ void imx_drm_encoder_destroy(struct drm_encoder *encoder);
+-int ipu_planes_assign_pre(struct drm_device *dev,
+-                        struct drm_atomic_state *state);
+-
+ #endif /* _IMX_DRM_H_ */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0045-drm-imx-Add-DPU-KMS-support-part-2.patch b/target/linux/layerscape/patches-5.4/805-display-0045-drm-imx-Add-DPU-KMS-support-part-2.patch
new file mode 100644 (file)
index 0000000..e00e805
--- /dev/null
@@ -0,0 +1,34 @@
+From 2e4fbc789ef2743a6e425b9ca8bf40e40e236d22 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Mon, 5 Aug 2019 19:08:35 +0800
+Subject: [PATCH] drm/imx: Add DPU KMS support (part 2)
+
+This patch adds i.MX DPU KMS support.
+
+Signed-off-by: Liu Ying <victor.liu@nxp.com>
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ drivers/gpu/drm/imx/imx-drm-core.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/gpu/drm/imx/imx-drm-core.c
++++ b/drivers/gpu/drm/imx/imx-drm-core.c
+@@ -24,6 +24,7 @@
+ #include <drm/drm_plane_helper.h>
+ #include <drm/drm_probe_helper.h>
+ #include <drm/drm_vblank.h>
++#include <video/dpu.h>
+ #include "imx-drm.h"
+@@ -105,6 +106,10 @@ static int compare_of(struct device *dev
+               struct ipu_client_platformdata *pdata = dev->platform_data;
+               return pdata->of_node == np;
++      } else if (strcmp(dev->driver->name, "imx-dpu-crtc") == 0) {
++              struct dpu_client_platformdata *pdata = dev->platform_data;
++
++              return pdata->of_node == np;
+       }
+       /* Special case for LDB, one device for two channels */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0046-MLK-22171-drm-imx-Avoid-leaking-dangling-pointer-dev.patch b/target/linux/layerscape/patches-5.4/805-display-0046-MLK-22171-drm-imx-Avoid-leaking-dangling-pointer-dev.patch
new file mode 100644 (file)
index 0000000..b65727d
--- /dev/null
@@ -0,0 +1,37 @@
+From 98917e88ec975eee0194ca011479e507029009ae Mon Sep 17 00:00:00 2001
+From: Liu Ying <victor.liu@nxp.com>
+Date: Tue, 30 Jul 2019 13:13:16 +0800
+Subject: [PATCH] MLK-22171 drm/imx: Avoid leaking dangling pointer
+ dev->driver_data to PM ops
+
+In case ->bind() fails, we should avoid leaking dangling pointer
+dev->driver_data which is set by dev_set_drvdata(), otherwise
+it would be leaked, and seen/dereferenced by PM ops, thus hang
+happens.  Moving dev_set_drvdata() down just before ->bind()
+successfully returns may address this issue.
+
+Signed-off-by: Liu Ying <victor.liu@nxp.com>
+---
+ drivers/gpu/drm/imx/imx-drm-core.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/imx/imx-drm-core.c
++++ b/drivers/gpu/drm/imx/imx-drm-core.c
+@@ -158,8 +158,6 @@ static int imx_drm_bind(struct device *d
+       if (ret)
+               goto err_kms;
+-      dev_set_drvdata(dev, drm);
+-
+       /* Now try and bind all our sub-components */
+       ret = component_bind_all(dev, drm);
+       if (ret)
+@@ -185,6 +183,8 @@ static int imx_drm_bind(struct device *d
+       drm_fbdev_generic_setup(drm, legacyfb_depth);
++      dev_set_drvdata(dev, drm);
++
+       return 0;
+ err_poll_fini:
diff --git a/target/linux/layerscape/patches-5.4/805-display-0047-MLK-18535-6-drm-imx-core-add-LCDIF-support.patch b/target/linux/layerscape/patches-5.4/805-display-0047-MLK-18535-6-drm-imx-core-add-LCDIF-support.patch
new file mode 100644 (file)
index 0000000..6bf4e59
--- /dev/null
@@ -0,0 +1,43 @@
+From 813cf104c571bf54e155d6be247c32a8f6aa3e2e Mon Sep 17 00:00:00 2001
+From: Fancy Fang <chen.fang@nxp.com>
+Date: Wed, 6 Jun 2018 23:20:43 +0800
+Subject: [PATCH] MLK-18535-6 drm/imx: core: add LCDIF support
+
+Allows the LCDIF to be one of the supported client
+components. And set the 'legacyfb_depth' of LCDIF
+to be 32.
+
+Signed-off-by: Fancy Fang <chen.fang@nxp.com>
+---
+ drivers/gpu/drm/imx/imx-drm-core.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/drivers/gpu/drm/imx/imx-drm-core.c
++++ b/drivers/gpu/drm/imx/imx-drm-core.c
+@@ -12,6 +12,7 @@
+ #include <linux/platform_device.h>
+ #include <video/imx-ipu-v3.h>
++#include <video/imx-lcdif.h>
+ #include <drm/drm_atomic.h>
+ #include <drm/drm_atomic_helper.h>
+@@ -110,6 +111,18 @@ static int compare_of(struct device *dev
+               struct dpu_client_platformdata *pdata = dev->platform_data;
+               return pdata->of_node == np;
++      } else if (strcmp(dev->driver->name, "imx-lcdif-crtc") == 0) {
++              struct lcdif_client_platformdata *pdata = dev->platform_data;
++#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
++              /* set legacyfb_depth to be 32 for lcdif, since
++               * default format of the connectors attached to
++               * lcdif is usually RGB888
++               */
++              if (pdata->of_node == np)
++                      legacyfb_depth = 32;
++#endif
++
++              return pdata->of_node == np;
+       }
+       /* Special case for LDB, one device for two channels */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0048-Revert-drm-imx-Extract-IPUv3-specific-KMS-functions-.patch b/target/linux/layerscape/patches-5.4/805-display-0048-Revert-drm-imx-Extract-IPUv3-specific-KMS-functions-.patch
new file mode 100644 (file)
index 0000000..23411bc
--- /dev/null
@@ -0,0 +1,135 @@
+From d2943462cef18cb78680215dec058d5254e63dc3 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Mon, 2 Mar 2020 13:45:41 +0800
+Subject: [PATCH] Revert "drm/imx: Extract IPUv3 specific KMS functions to
+ ipuv3-kms.c (part 1)"
+
+This reverts commit aad8cd9d3f10c57bbf405e25ed1be491d99b6294.
+---
+ drivers/gpu/drm/imx/imx-drm-core.c | 81 ++++++++++++++++++++++++++++++++++++++
+ drivers/gpu/drm/imx/imx-drm.h      |  5 ++-
+ 2 files changed, 84 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/imx/imx-drm-core.c
++++ b/drivers/gpu/drm/imx/imx-drm-core.c
+@@ -28,6 +28,9 @@
+ #include <video/dpu.h>
+ #include "imx-drm.h"
++#include "ipuv3-plane.h"
++
++#define MAX_CRTC      4
+ static int legacyfb_depth = 16;
+ module_param(legacyfb_depth, int, 0444);
+@@ -47,6 +50,81 @@ void imx_drm_encoder_destroy(struct drm_
+ }
+ EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
++static int imx_drm_atomic_check(struct drm_device *dev,
++                              struct drm_atomic_state *state)
++{
++      int ret;
++
++      ret = drm_atomic_helper_check(dev, state);
++      if (ret)
++              return ret;
++
++      /*
++       * Check modeset again in case crtc_state->mode_changed is
++       * updated in plane's ->atomic_check callback.
++       */
++      ret = drm_atomic_helper_check_modeset(dev, state);
++      if (ret)
++              return ret;
++
++      /* Assign PRG/PRE channels and check if all constrains are satisfied. */
++      ret = ipu_planes_assign_pre(dev, state);
++      if (ret)
++              return ret;
++
++      return ret;
++}
++
++static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
++      .fb_create = drm_gem_fb_create,
++      .atomic_check = imx_drm_atomic_check,
++      .atomic_commit = drm_atomic_helper_commit,
++};
++
++static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
++{
++      struct drm_device *dev = state->dev;
++      struct drm_plane *plane;
++      struct drm_plane_state *old_plane_state, *new_plane_state;
++      bool plane_disabling = false;
++      int i;
++
++      drm_atomic_helper_commit_modeset_disables(dev, state);
++
++      drm_atomic_helper_commit_planes(dev, state,
++                              DRM_PLANE_COMMIT_ACTIVE_ONLY |
++                              DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET);
++
++      drm_atomic_helper_commit_modeset_enables(dev, state);
++
++      for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
++              if (drm_atomic_plane_disabling(old_plane_state, new_plane_state))
++                      plane_disabling = true;
++      }
++
++      /*
++       * The flip done wait is only strictly required by imx-drm if a deferred
++       * plane disable is in-flight. As the core requires blocking commits
++       * to wait for the flip it is done here unconditionally. This keeps the
++       * workitem around a bit longer than required for the majority of
++       * non-blocking commits, but we accept that for the sake of simplicity.
++       */
++      drm_atomic_helper_wait_for_flip_done(dev, state);
++
++      if (plane_disabling) {
++              for_each_old_plane_in_state(state, plane, old_plane_state, i)
++                      ipu_plane_disable_deferred(plane);
++
++      }
++
++      drm_atomic_helper_commit_hw_done(state);
++}
++
++static const struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = {
++      .atomic_commit_tail = imx_drm_atomic_commit_tail,
++};
++
++
+ int imx_drm_encoder_parse_of(struct drm_device *drm,
+       struct drm_encoder *encoder, struct device_node *np)
+ {
+@@ -163,6 +241,9 @@ static int imx_drm_bind(struct device *d
+       drm->mode_config.min_height = 1;
+       drm->mode_config.max_width = 4096;
+       drm->mode_config.max_height = 4096;
++      drm->mode_config.funcs = &imx_drm_mode_config_funcs;
++      drm->mode_config.helper_private = &imx_drm_mode_config_helpers;
++      drm->mode_config.allow_fb_modifiers = true;
+       drm->mode_config.normalize_zpos = true;
+       drm_mode_config_init(drm);
+--- a/drivers/gpu/drm/imx/imx-drm.h
++++ b/drivers/gpu/drm/imx/imx-drm.h
+@@ -2,8 +2,6 @@
+ #ifndef _IMX_DRM_H_
+ #define _IMX_DRM_H_
+-#define MAX_CRTC      4
+-
+ struct device_node;
+ struct drm_crtc;
+ struct drm_connector;
+@@ -40,4 +38,7 @@ int imx_drm_encoder_parse_of(struct drm_
+ void imx_drm_connector_destroy(struct drm_connector *connector);
+ void imx_drm_encoder_destroy(struct drm_encoder *encoder);
++int ipu_planes_assign_pre(struct drm_device *dev,
++                        struct drm_atomic_state *state);
++
+ #endif /* _IMX_DRM_H_ */
diff --git a/target/linux/layerscape/patches-5.4/805-display-0049-Revert-gpu-Move-ipu-v3-to-imx-folder.patch b/target/linux/layerscape/patches-5.4/805-display-0049-Revert-gpu-Move-ipu-v3-to-imx-folder.patch
new file mode 100644 (file)
index 0000000..1c1886b
--- /dev/null
@@ -0,0 +1,19991 @@
+From 9a941f832d8b88fb29b40e4b3f9c2b42a8a9b000 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Mon, 2 Mar 2020 13:46:13 +0800
+Subject: [PATCH] Revert "gpu: Move ipu-v3 to imx folder"
+
+This reverts commit 9da4beb1c9ce90f97c8d3b5c6254da576746d2cd.
+---
+ drivers/gpu/Makefile                       |    2 +-
+ drivers/gpu/imx/Kconfig                    |    1 -
+ drivers/gpu/imx/Makefile                   |    1 -
+ drivers/gpu/imx/ipu-v3/Kconfig             |   11 -
+ drivers/gpu/imx/ipu-v3/Makefile            |   10 -
+ drivers/gpu/imx/ipu-v3/ipu-common.c        | 1565 ------------------
+ drivers/gpu/imx/ipu-v3/ipu-cpmem.c         |  976 -----------
+ drivers/gpu/imx/ipu-v3/ipu-csi.c           |  821 ---------
+ drivers/gpu/imx/ipu-v3/ipu-dc.c            |  420 -----
+ drivers/gpu/imx/ipu-v3/ipu-di.c            |  745 ---------
+ drivers/gpu/imx/ipu-v3/ipu-dmfc.c          |  214 ---
+ drivers/gpu/imx/ipu-v3/ipu-dp.c            |  357 ----
+ drivers/gpu/imx/ipu-v3/ipu-ic.c            |  761 ---------
+ drivers/gpu/imx/ipu-v3/ipu-image-convert.c | 2475 ----------------------------
+ drivers/gpu/imx/ipu-v3/ipu-pre.c           |  346 ----
+ drivers/gpu/imx/ipu-v3/ipu-prg.c           |  483 ------
+ drivers/gpu/imx/ipu-v3/ipu-prv.h           |  274 ---
+ drivers/gpu/imx/ipu-v3/ipu-smfc.c          |  202 ---
+ drivers/gpu/imx/ipu-v3/ipu-vdi.c           |  234 ---
+ drivers/gpu/ipu-v3/Kconfig                 |   11 +
+ drivers/gpu/ipu-v3/Makefile                |   10 +
+ drivers/gpu/ipu-v3/ipu-common.c            | 1565 ++++++++++++++++++
+ drivers/gpu/ipu-v3/ipu-cpmem.c             |  976 +++++++++++
+ drivers/gpu/ipu-v3/ipu-csi.c               |  821 +++++++++
+ drivers/gpu/ipu-v3/ipu-dc.c                |  420 +++++
+ drivers/gpu/ipu-v3/ipu-di.c                |  745 +++++++++
+ drivers/gpu/ipu-v3/ipu-dmfc.c              |  214 +++
+ drivers/gpu/ipu-v3/ipu-dp.c                |  357 ++++
+ drivers/gpu/ipu-v3/ipu-ic.c                |  761 +++++++++
+ drivers/gpu/ipu-v3/ipu-image-convert.c     | 2475 ++++++++++++++++++++++++++++
+ drivers/gpu/ipu-v3/ipu-pre.c               |  346 ++++
+ drivers/gpu/ipu-v3/ipu-prg.c               |  483 ++++++
+ drivers/gpu/ipu-v3/ipu-prv.h               |  274 +++
+ drivers/gpu/ipu-v3/ipu-smfc.c              |  202 +++
+ drivers/gpu/ipu-v3/ipu-vdi.c               |  234 +++
+ drivers/video/Kconfig                      |    2 +-
+ 36 files changed, 9896 insertions(+), 9898 deletions(-)
+ delete mode 100644 drivers/gpu/imx/Kconfig
+ delete mode 100644 drivers/gpu/imx/Makefile
+ delete mode 100644 drivers/gpu/imx/ipu-v3/Kconfig
+ delete mode 100644 drivers/gpu/imx/ipu-v3/Makefile
+ delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-common.c
+ delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-cpmem.c
+ delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-csi.c
+ delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-dc.c
+ delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-di.c
+ delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-dmfc.c
+ delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-dp.c
+ delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-ic.c
+ delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-image-convert.c
+ delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-pre.c
+ delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-prg.c
+ delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-prv.h
+ delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-smfc.c
+ delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-vdi.c
+ create mode 100644 drivers/gpu/ipu-v3/Kconfig
+ create mode 100644 drivers/gpu/ipu-v3/Makefile
+ create mode 100644 drivers/gpu/ipu-v3/ipu-common.c
+ create mode 100644 drivers/gpu/ipu-v3/ipu-cpmem.c
+ create mode 100644 drivers/gpu/ipu-v3/ipu-csi.c
+ create mode 100644 drivers/gpu/ipu-v3/ipu-dc.c
+ create mode 100644 drivers/gpu/ipu-v3/ipu-di.c
+ create mode 100644 drivers/gpu/ipu-v3/ipu-dmfc.c
+ create mode 100644 drivers/gpu/ipu-v3/ipu-dp.c
+ create mode 100644 drivers/gpu/ipu-v3/ipu-ic.c
+ create mode 100644 drivers/gpu/ipu-v3/ipu-image-convert.c
+ create mode 100644 drivers/gpu/ipu-v3/ipu-pre.c
+ create mode 100644 drivers/gpu/ipu-v3/ipu-prg.c
+ create mode 100644 drivers/gpu/ipu-v3/ipu-prv.h
+ create mode 100644 drivers/gpu/ipu-v3/ipu-smfc.c
+ create mode 100644 drivers/gpu/ipu-v3/ipu-vdi.c
+
+--- a/drivers/gpu/Makefile
++++ b/drivers/gpu/Makefile
+@@ -3,5 +3,5 @@
+ # taken to initialize them in the correct order. Link order is the only way
+ # to ensure this currently.
+ obj-$(CONFIG_TEGRA_HOST1X)    += host1x/
+-obj-y                 += imx/
+ obj-y                 += drm/ vga/
++obj-$(CONFIG_IMX_IPUV3_CORE)  += ipu-v3/
+--- a/drivers/gpu/imx/Kconfig
++++ /dev/null
+@@ -1 +0,0 @@
+-source "drivers/gpu/imx/ipu-v3/Kconfig"
+--- a/drivers/gpu/imx/Makefile
++++ /dev/null
+@@ -1 +0,0 @@
+-obj-$(CONFIG_IMX_IPUV3_CORE)  += ipu-v3/
+--- a/drivers/gpu/imx/ipu-v3/Kconfig
++++ /dev/null
+@@ -1,11 +0,0 @@
+-# SPDX-License-Identifier: GPL-2.0-only
+-config IMX_IPUV3_CORE
+-      tristate "IPUv3 core support"
+-      depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM || COMPILE_TEST
+-      depends on DRM || !DRM # if DRM=m, this can't be 'y'
+-      select BITREVERSE
+-      select GENERIC_ALLOCATOR if DRM
+-      select GENERIC_IRQ_CHIP
+-      help
+-        Choose this if you have a i.MX5/6 system and want to use the Image
+-        Processing Unit. This option only enables IPU base support.
+--- a/drivers/gpu/imx/ipu-v3/Makefile
++++ /dev/null
+@@ -1,10 +0,0 @@
+-# SPDX-License-Identifier: GPL-2.0
+-obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
+-
+-imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
+-              ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-ic-csc.o \
+-              ipu-image-convert.o ipu-smfc.o ipu-vdi.o
+-
+-ifdef CONFIG_DRM
+-      imx-ipu-v3-objs += ipu-pre.o ipu-prg.o
+-endif
+--- a/drivers/gpu/imx/ipu-v3/ipu-common.c
++++ /dev/null
+@@ -1,1565 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-#include <linux/module.h>
+-#include <linux/export.h>
+-#include <linux/types.h>
+-#include <linux/reset.h>
+-#include <linux/platform_device.h>
+-#include <linux/err.h>
+-#include <linux/spinlock.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/io.h>
+-#include <linux/clk.h>
+-#include <linux/list.h>
+-#include <linux/irq.h>
+-#include <linux/irqchip/chained_irq.h>
+-#include <linux/irqdomain.h>
+-#include <linux/of_device.h>
+-#include <linux/of_graph.h>
+-
+-#include <drm/drm_fourcc.h>
+-
+-#include <video/imx-ipu-v3.h>
+-#include "ipu-prv.h"
+-
+-static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
+-{
+-      return readl(ipu->cm_reg + offset);
+-}
+-
+-static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
+-{
+-      writel(value, ipu->cm_reg + offset);
+-}
+-
+-int ipu_get_num(struct ipu_soc *ipu)
+-{
+-      return ipu->id;
+-}
+-EXPORT_SYMBOL_GPL(ipu_get_num);
+-
+-void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync)
+-{
+-      u32 val;
+-
+-      val = ipu_cm_read(ipu, IPU_SRM_PRI2);
+-      val &= ~DP_S_SRM_MODE_MASK;
+-      val |= sync ? DP_S_SRM_MODE_NEXT_FRAME :
+-                    DP_S_SRM_MODE_NOW;
+-      ipu_cm_write(ipu, val, IPU_SRM_PRI2);
+-}
+-EXPORT_SYMBOL_GPL(ipu_srm_dp_update);
+-
+-enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
+-{
+-      switch (drm_fourcc) {
+-      case DRM_FORMAT_ARGB1555:
+-      case DRM_FORMAT_ABGR1555:
+-      case DRM_FORMAT_RGBA5551:
+-      case DRM_FORMAT_BGRA5551:
+-      case DRM_FORMAT_RGB565:
+-      case DRM_FORMAT_BGR565:
+-      case DRM_FORMAT_RGB888:
+-      case DRM_FORMAT_BGR888:
+-      case DRM_FORMAT_ARGB4444:
+-      case DRM_FORMAT_XRGB8888:
+-      case DRM_FORMAT_XBGR8888:
+-      case DRM_FORMAT_RGBX8888:
+-      case DRM_FORMAT_BGRX8888:
+-      case DRM_FORMAT_ARGB8888:
+-      case DRM_FORMAT_ABGR8888:
+-      case DRM_FORMAT_RGBA8888:
+-      case DRM_FORMAT_BGRA8888:
+-      case DRM_FORMAT_RGB565_A8:
+-      case DRM_FORMAT_BGR565_A8:
+-      case DRM_FORMAT_RGB888_A8:
+-      case DRM_FORMAT_BGR888_A8:
+-      case DRM_FORMAT_RGBX8888_A8:
+-      case DRM_FORMAT_BGRX8888_A8:
+-              return IPUV3_COLORSPACE_RGB;
+-      case DRM_FORMAT_YUYV:
+-      case DRM_FORMAT_UYVY:
+-      case DRM_FORMAT_YUV420:
+-      case DRM_FORMAT_YVU420:
+-      case DRM_FORMAT_YUV422:
+-      case DRM_FORMAT_YVU422:
+-      case DRM_FORMAT_YUV444:
+-      case DRM_FORMAT_YVU444:
+-      case DRM_FORMAT_NV12:
+-      case DRM_FORMAT_NV21:
+-      case DRM_FORMAT_NV16:
+-      case DRM_FORMAT_NV61:
+-              return IPUV3_COLORSPACE_YUV;
+-      default:
+-              return IPUV3_COLORSPACE_UNKNOWN;
+-      }
+-}
+-EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace);
+-
+-enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
+-{
+-      switch (pixelformat) {
+-      case V4L2_PIX_FMT_YUV420:
+-      case V4L2_PIX_FMT_YVU420:
+-      case V4L2_PIX_FMT_YUV422P:
+-      case V4L2_PIX_FMT_UYVY:
+-      case V4L2_PIX_FMT_YUYV:
+-      case V4L2_PIX_FMT_NV12:
+-      case V4L2_PIX_FMT_NV21:
+-      case V4L2_PIX_FMT_NV16:
+-      case V4L2_PIX_FMT_NV61:
+-              return IPUV3_COLORSPACE_YUV;
+-      case V4L2_PIX_FMT_RGB565:
+-      case V4L2_PIX_FMT_BGR24:
+-      case V4L2_PIX_FMT_RGB24:
+-      case V4L2_PIX_FMT_ABGR32:
+-      case V4L2_PIX_FMT_XBGR32:
+-      case V4L2_PIX_FMT_BGRA32:
+-      case V4L2_PIX_FMT_BGRX32:
+-      case V4L2_PIX_FMT_RGBA32:
+-      case V4L2_PIX_FMT_RGBX32:
+-      case V4L2_PIX_FMT_ARGB32:
+-      case V4L2_PIX_FMT_XRGB32:
+-              return IPUV3_COLORSPACE_RGB;
+-      default:
+-              return IPUV3_COLORSPACE_UNKNOWN;
+-      }
+-}
+-EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
+-
+-bool ipu_pixelformat_is_planar(u32 pixelformat)
+-{
+-      switch (pixelformat) {
+-      case V4L2_PIX_FMT_YUV420:
+-      case V4L2_PIX_FMT_YVU420:
+-      case V4L2_PIX_FMT_YUV422P:
+-      case V4L2_PIX_FMT_NV12:
+-      case V4L2_PIX_FMT_NV21:
+-      case V4L2_PIX_FMT_NV16:
+-      case V4L2_PIX_FMT_NV61:
+-              return true;
+-      }
+-
+-      return false;
+-}
+-EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar);
+-
+-enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
+-{
+-      switch (mbus_code & 0xf000) {
+-      case 0x1000:
+-              return IPUV3_COLORSPACE_RGB;
+-      case 0x2000:
+-              return IPUV3_COLORSPACE_YUV;
+-      default:
+-              return IPUV3_COLORSPACE_UNKNOWN;
+-      }
+-}
+-EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
+-
+-int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat)
+-{
+-      switch (pixelformat) {
+-      case V4L2_PIX_FMT_YUV420:
+-      case V4L2_PIX_FMT_YVU420:
+-      case V4L2_PIX_FMT_YUV422P:
+-      case V4L2_PIX_FMT_NV12:
+-      case V4L2_PIX_FMT_NV21:
+-      case V4L2_PIX_FMT_NV16:
+-      case V4L2_PIX_FMT_NV61:
+-              /*
+-               * for the planar YUV formats, the stride passed to
+-               * cpmem must be the stride in bytes of the Y plane.
+-               * And all the planar YUV formats have an 8-bit
+-               * Y component.
+-               */
+-              return (8 * pixel_stride) >> 3;
+-      case V4L2_PIX_FMT_RGB565:
+-      case V4L2_PIX_FMT_YUYV:
+-      case V4L2_PIX_FMT_UYVY:
+-              return (16 * pixel_stride) >> 3;
+-      case V4L2_PIX_FMT_BGR24:
+-      case V4L2_PIX_FMT_RGB24:
+-              return (24 * pixel_stride) >> 3;
+-      case V4L2_PIX_FMT_BGR32:
+-      case V4L2_PIX_FMT_RGB32:
+-      case V4L2_PIX_FMT_XBGR32:
+-      case V4L2_PIX_FMT_XRGB32:
+-              return (32 * pixel_stride) >> 3;
+-      default:
+-              break;
+-      }
+-
+-      return -EINVAL;
+-}
+-EXPORT_SYMBOL_GPL(ipu_stride_to_bytes);
+-
+-int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
+-                          bool hflip, bool vflip)
+-{
+-      u32 r90, vf, hf;
+-
+-      switch (degrees) {
+-      case 0:
+-              vf = hf = r90 = 0;
+-              break;
+-      case 90:
+-              vf = hf = 0;
+-              r90 = 1;
+-              break;
+-      case 180:
+-              vf = hf = 1;
+-              r90 = 0;
+-              break;
+-      case 270:
+-              vf = hf = r90 = 1;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      hf ^= (u32)hflip;
+-      vf ^= (u32)vflip;
+-
+-      *mode = (enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf);
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode);
+-
+-int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
+-                          bool hflip, bool vflip)
+-{
+-      u32 r90, vf, hf;
+-
+-      r90 = ((u32)mode >> 2) & 0x1;
+-      hf = ((u32)mode >> 1) & 0x1;
+-      vf = ((u32)mode >> 0) & 0x1;
+-      hf ^= (u32)hflip;
+-      vf ^= (u32)vflip;
+-
+-      switch ((enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf)) {
+-      case IPU_ROTATE_NONE:
+-              *degrees = 0;
+-              break;
+-      case IPU_ROTATE_90_RIGHT:
+-              *degrees = 90;
+-              break;
+-      case IPU_ROTATE_180:
+-              *degrees = 180;
+-              break;
+-      case IPU_ROTATE_90_LEFT:
+-              *degrees = 270;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees);
+-
+-struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
+-{
+-      struct ipuv3_channel *channel;
+-
+-      dev_dbg(ipu->dev, "%s %d\n", __func__, num);
+-
+-      if (num > 63)
+-              return ERR_PTR(-ENODEV);
+-
+-      mutex_lock(&ipu->channel_lock);
+-
+-      list_for_each_entry(channel, &ipu->channels, list) {
+-              if (channel->num == num) {
+-                      channel = ERR_PTR(-EBUSY);
+-                      goto out;
+-              }
+-      }
+-
+-      channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+-      if (!channel) {
+-              channel = ERR_PTR(-ENOMEM);
+-              goto out;
+-      }
+-
+-      channel->num = num;
+-      channel->ipu = ipu;
+-      list_add(&channel->list, &ipu->channels);
+-
+-out:
+-      mutex_unlock(&ipu->channel_lock);
+-
+-      return channel;
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_get);
+-
+-void ipu_idmac_put(struct ipuv3_channel *channel)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-
+-      dev_dbg(ipu->dev, "%s %d\n", __func__, channel->num);
+-
+-      mutex_lock(&ipu->channel_lock);
+-
+-      list_del(&channel->list);
+-      kfree(channel);
+-
+-      mutex_unlock(&ipu->channel_lock);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_put);
+-
+-#define idma_mask(ch)                 (1 << ((ch) & 0x1f))
+-
+-/*
+- * This is an undocumented feature, a write one to a channel bit in
+- * IPU_CHA_CUR_BUF and IPU_CHA_TRIPLE_CUR_BUF will reset the channel's
+- * internal current buffer pointer so that transfers start from buffer
+- * 0 on the next channel enable (that's the theory anyway, the imx6 TRM
+- * only says these are read-only registers). This operation is required
+- * for channel linking to work correctly, for instance video capture
+- * pipelines that carry out image rotations will fail after the first
+- * streaming unless this function is called for each channel before
+- * re-enabling the channels.
+- */
+-static void __ipu_idmac_reset_current_buffer(struct ipuv3_channel *channel)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned int chno = channel->num;
+-
+-      ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_CUR_BUF(chno));
+-}
+-
+-void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
+-              bool doublebuffer)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned long flags;
+-      u32 reg;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
+-      if (doublebuffer)
+-              reg |= idma_mask(channel->num);
+-      else
+-              reg &= ~idma_mask(channel->num);
+-      ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
+-
+-      __ipu_idmac_reset_current_buffer(channel);
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
+-
+-static const struct {
+-      int chnum;
+-      u32 reg;
+-      int shift;
+-} idmac_lock_en_info[] = {
+-      { .chnum =  5, .reg = IDMAC_CH_LOCK_EN_1, .shift =  0, },
+-      { .chnum = 11, .reg = IDMAC_CH_LOCK_EN_1, .shift =  2, },
+-      { .chnum = 12, .reg = IDMAC_CH_LOCK_EN_1, .shift =  4, },
+-      { .chnum = 14, .reg = IDMAC_CH_LOCK_EN_1, .shift =  6, },
+-      { .chnum = 15, .reg = IDMAC_CH_LOCK_EN_1, .shift =  8, },
+-      { .chnum = 20, .reg = IDMAC_CH_LOCK_EN_1, .shift = 10, },
+-      { .chnum = 21, .reg = IDMAC_CH_LOCK_EN_1, .shift = 12, },
+-      { .chnum = 22, .reg = IDMAC_CH_LOCK_EN_1, .shift = 14, },
+-      { .chnum = 23, .reg = IDMAC_CH_LOCK_EN_1, .shift = 16, },
+-      { .chnum = 27, .reg = IDMAC_CH_LOCK_EN_1, .shift = 18, },
+-      { .chnum = 28, .reg = IDMAC_CH_LOCK_EN_1, .shift = 20, },
+-      { .chnum = 45, .reg = IDMAC_CH_LOCK_EN_2, .shift =  0, },
+-      { .chnum = 46, .reg = IDMAC_CH_LOCK_EN_2, .shift =  2, },
+-      { .chnum = 47, .reg = IDMAC_CH_LOCK_EN_2, .shift =  4, },
+-      { .chnum = 48, .reg = IDMAC_CH_LOCK_EN_2, .shift =  6, },
+-      { .chnum = 49, .reg = IDMAC_CH_LOCK_EN_2, .shift =  8, },
+-      { .chnum = 50, .reg = IDMAC_CH_LOCK_EN_2, .shift = 10, },
+-};
+-
+-int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned long flags;
+-      u32 bursts, regval;
+-      int i;
+-
+-      switch (num_bursts) {
+-      case 0:
+-      case 1:
+-              bursts = 0x00; /* locking disabled */
+-              break;
+-      case 2:
+-              bursts = 0x01;
+-              break;
+-      case 4:
+-              bursts = 0x02;
+-              break;
+-      case 8:
+-              bursts = 0x03;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      /*
+-       * IPUv3EX / i.MX51 has a different register layout, and on IPUv3M /
+-       * i.MX53 channel arbitration locking doesn't seem to work properly.
+-       * Allow enabling the lock feature on IPUv3H / i.MX6 only.
+-       */
+-      if (bursts && ipu->ipu_type != IPUV3H)
+-              return -EINVAL;
+-
+-      for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) {
+-              if (channel->num == idmac_lock_en_info[i].chnum)
+-                      break;
+-      }
+-      if (i >= ARRAY_SIZE(idmac_lock_en_info))
+-              return -EINVAL;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      regval = ipu_idmac_read(ipu, idmac_lock_en_info[i].reg);
+-      regval &= ~(0x03 << idmac_lock_en_info[i].shift);
+-      regval |= (bursts << idmac_lock_en_info[i].shift);
+-      ipu_idmac_write(ipu, regval, idmac_lock_en_info[i].reg);
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_lock_enable);
+-
+-int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
+-{
+-      unsigned long lock_flags;
+-      u32 val;
+-
+-      spin_lock_irqsave(&ipu->lock, lock_flags);
+-
+-      val = ipu_cm_read(ipu, IPU_DISP_GEN);
+-
+-      if (mask & IPU_CONF_DI0_EN)
+-              val |= IPU_DI0_COUNTER_RELEASE;
+-      if (mask & IPU_CONF_DI1_EN)
+-              val |= IPU_DI1_COUNTER_RELEASE;
+-
+-      ipu_cm_write(ipu, val, IPU_DISP_GEN);
+-
+-      val = ipu_cm_read(ipu, IPU_CONF);
+-      val |= mask;
+-      ipu_cm_write(ipu, val, IPU_CONF);
+-
+-      spin_unlock_irqrestore(&ipu->lock, lock_flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_module_enable);
+-
+-int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
+-{
+-      unsigned long lock_flags;
+-      u32 val;
+-
+-      spin_lock_irqsave(&ipu->lock, lock_flags);
+-
+-      val = ipu_cm_read(ipu, IPU_CONF);
+-      val &= ~mask;
+-      ipu_cm_write(ipu, val, IPU_CONF);
+-
+-      val = ipu_cm_read(ipu, IPU_DISP_GEN);
+-
+-      if (mask & IPU_CONF_DI0_EN)
+-              val &= ~IPU_DI0_COUNTER_RELEASE;
+-      if (mask & IPU_CONF_DI1_EN)
+-              val &= ~IPU_DI1_COUNTER_RELEASE;
+-
+-      ipu_cm_write(ipu, val, IPU_DISP_GEN);
+-
+-      spin_unlock_irqrestore(&ipu->lock, lock_flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_module_disable);
+-
+-int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned int chno = channel->num;
+-
+-      return (ipu_cm_read(ipu, IPU_CHA_CUR_BUF(chno)) & idma_mask(chno)) ? 1 : 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer);
+-
+-bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned long flags;
+-      u32 reg = 0;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-      switch (buf_num) {
+-      case 0:
+-              reg = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num));
+-              break;
+-      case 1:
+-              reg = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num));
+-              break;
+-      case 2:
+-              reg = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(channel->num));
+-              break;
+-      }
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-
+-      return ((reg & idma_mask(channel->num)) != 0);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_buffer_is_ready);
+-
+-void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned int chno = channel->num;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      /* Mark buffer as ready. */
+-      if (buf_num == 0)
+-              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
+-      else
+-              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
+-
+-void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned int chno = channel->num;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */
+-      switch (buf_num) {
+-      case 0:
+-              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
+-              break;
+-      case 1:
+-              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
+-              break;
+-      case 2:
+-              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF2_RDY(chno));
+-              break;
+-      default:
+-              break;
+-      }
+-      ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer);
+-
+-int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      u32 val;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
+-      val |= idma_mask(channel->num);
+-      ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
+-
+-bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno)
+-{
+-      return (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(chno)) & idma_mask(chno));
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_channel_busy);
+-
+-int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned long timeout;
+-
+-      timeout = jiffies + msecs_to_jiffies(ms);
+-      while (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(channel->num)) &
+-                      idma_mask(channel->num)) {
+-              if (time_after(jiffies, timeout))
+-                      return -ETIMEDOUT;
+-              cpu_relax();
+-      }
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy);
+-
+-int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      u32 val;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      /* Disable DMA channel(s) */
+-      val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
+-      val &= ~idma_mask(channel->num);
+-      ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
+-
+-      __ipu_idmac_reset_current_buffer(channel);
+-
+-      /* Set channel buffers NOT to be ready */
+-      ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
+-
+-      if (ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num)) &
+-                      idma_mask(channel->num)) {
+-              ipu_cm_write(ipu, idma_mask(channel->num),
+-                           IPU_CHA_BUF0_RDY(channel->num));
+-      }
+-
+-      if (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num)) &
+-                      idma_mask(channel->num)) {
+-              ipu_cm_write(ipu, idma_mask(channel->num),
+-                           IPU_CHA_BUF1_RDY(channel->num));
+-      }
+-
+-      ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
+-
+-      /* Reset the double buffer */
+-      val = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
+-      val &= ~idma_mask(channel->num);
+-      ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num));
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
+-
+-/*
+- * The imx6 rev. D TRM says that enabling the WM feature will increase
+- * a channel's priority. Refer to Table 36-8 Calculated priority value.
+- * The sub-module that is the sink or source for the channel must enable
+- * watermark signal for this to take effect (SMFC_WM for instance).
+- */
+-void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable)
+-{
+-      struct ipu_soc *ipu = channel->ipu;
+-      unsigned long flags;
+-      u32 val;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      val = ipu_idmac_read(ipu, IDMAC_WM_EN(channel->num));
+-      if (enable)
+-              val |= 1 << (channel->num % 32);
+-      else
+-              val &= ~(1 << (channel->num % 32));
+-      ipu_idmac_write(ipu, val, IDMAC_WM_EN(channel->num));
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_enable_watermark);
+-
+-static int ipu_memory_reset(struct ipu_soc *ipu)
+-{
+-      unsigned long timeout;
+-
+-      ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST);
+-
+-      timeout = jiffies + msecs_to_jiffies(1000);
+-      while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) {
+-              if (time_after(jiffies, timeout))
+-                      return -ETIME;
+-              cpu_relax();
+-      }
+-
+-      return 0;
+-}
+-
+-/*
+- * Set the source mux for the given CSI. Selects either parallel or
+- * MIPI CSI2 sources.
+- */
+-void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2)
+-{
+-      unsigned long flags;
+-      u32 val, mask;
+-
+-      mask = (csi_id == 1) ? IPU_CONF_CSI1_DATA_SOURCE :
+-              IPU_CONF_CSI0_DATA_SOURCE;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      val = ipu_cm_read(ipu, IPU_CONF);
+-      if (mipi_csi2)
+-              val |= mask;
+-      else
+-              val &= ~mask;
+-      ipu_cm_write(ipu, val, IPU_CONF);
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_set_csi_src_mux);
+-
+-/*
+- * Set the source mux for the IC. Selects either CSI[01] or the VDI.
+- */
+-void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi)
+-{
+-      unsigned long flags;
+-      u32 val;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      val = ipu_cm_read(ipu, IPU_CONF);
+-      if (vdi)
+-              val |= IPU_CONF_IC_INPUT;
+-      else
+-              val &= ~IPU_CONF_IC_INPUT;
+-
+-      if (csi_id == 1)
+-              val |= IPU_CONF_CSI_SEL;
+-      else
+-              val &= ~IPU_CONF_CSI_SEL;
+-
+-      ipu_cm_write(ipu, val, IPU_CONF);
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux);
+-
+-
+-/* Frame Synchronization Unit Channel Linking */
+-
+-struct fsu_link_reg_info {
+-      int chno;
+-      u32 reg;
+-      u32 mask;
+-      u32 val;
+-};
+-
+-struct fsu_link_info {
+-      struct fsu_link_reg_info src;
+-      struct fsu_link_reg_info sink;
+-};
+-
+-static const struct fsu_link_info fsu_link_info[] = {
+-      {
+-              .src  = { IPUV3_CHANNEL_IC_PRP_ENC_MEM, IPU_FS_PROC_FLOW2,
+-                        FS_PRP_ENC_DEST_SEL_MASK, FS_PRP_ENC_DEST_SEL_IRT_ENC },
+-              .sink = { IPUV3_CHANNEL_MEM_ROT_ENC, IPU_FS_PROC_FLOW1,
+-                        FS_PRPENC_ROT_SRC_SEL_MASK, FS_PRPENC_ROT_SRC_SEL_ENC },
+-      }, {
+-              .src =  { IPUV3_CHANNEL_IC_PRP_VF_MEM, IPU_FS_PROC_FLOW2,
+-                        FS_PRPVF_DEST_SEL_MASK, FS_PRPVF_DEST_SEL_IRT_VF },
+-              .sink = { IPUV3_CHANNEL_MEM_ROT_VF, IPU_FS_PROC_FLOW1,
+-                        FS_PRPVF_ROT_SRC_SEL_MASK, FS_PRPVF_ROT_SRC_SEL_VF },
+-      }, {
+-              .src =  { IPUV3_CHANNEL_IC_PP_MEM, IPU_FS_PROC_FLOW2,
+-                        FS_PP_DEST_SEL_MASK, FS_PP_DEST_SEL_IRT_PP },
+-              .sink = { IPUV3_CHANNEL_MEM_ROT_PP, IPU_FS_PROC_FLOW1,
+-                        FS_PP_ROT_SRC_SEL_MASK, FS_PP_ROT_SRC_SEL_PP },
+-      }, {
+-              .src =  { IPUV3_CHANNEL_CSI_DIRECT, 0 },
+-              .sink = { IPUV3_CHANNEL_CSI_VDI_PREV, IPU_FS_PROC_FLOW1,
+-                        FS_VDI_SRC_SEL_MASK, FS_VDI_SRC_SEL_CSI_DIRECT },
+-      },
+-};
+-
+-static const struct fsu_link_info *find_fsu_link_info(int src, int sink)
+-{
+-      int i;
+-
+-      for (i = 0; i < ARRAY_SIZE(fsu_link_info); i++) {
+-              if (src == fsu_link_info[i].src.chno &&
+-                  sink == fsu_link_info[i].sink.chno)
+-                      return &fsu_link_info[i];
+-      }
+-
+-      return NULL;
+-}
+-
+-/*
+- * Links a source channel to a sink channel in the FSU.
+- */
+-int ipu_fsu_link(struct ipu_soc *ipu, int src_ch, int sink_ch)
+-{
+-      const struct fsu_link_info *link;
+-      u32 src_reg, sink_reg;
+-      unsigned long flags;
+-
+-      link = find_fsu_link_info(src_ch, sink_ch);
+-      if (!link)
+-              return -EINVAL;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      if (link->src.mask) {
+-              src_reg = ipu_cm_read(ipu, link->src.reg);
+-              src_reg &= ~link->src.mask;
+-              src_reg |= link->src.val;
+-              ipu_cm_write(ipu, src_reg, link->src.reg);
+-      }
+-
+-      if (link->sink.mask) {
+-              sink_reg = ipu_cm_read(ipu, link->sink.reg);
+-              sink_reg &= ~link->sink.mask;
+-              sink_reg |= link->sink.val;
+-              ipu_cm_write(ipu, sink_reg, link->sink.reg);
+-      }
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_fsu_link);
+-
+-/*
+- * Unlinks source and sink channels in the FSU.
+- */
+-int ipu_fsu_unlink(struct ipu_soc *ipu, int src_ch, int sink_ch)
+-{
+-      const struct fsu_link_info *link;
+-      u32 src_reg, sink_reg;
+-      unsigned long flags;
+-
+-      link = find_fsu_link_info(src_ch, sink_ch);
+-      if (!link)
+-              return -EINVAL;
+-
+-      spin_lock_irqsave(&ipu->lock, flags);
+-
+-      if (link->src.mask) {
+-              src_reg = ipu_cm_read(ipu, link->src.reg);
+-              src_reg &= ~link->src.mask;
+-              ipu_cm_write(ipu, src_reg, link->src.reg);
+-      }
+-
+-      if (link->sink.mask) {
+-              sink_reg = ipu_cm_read(ipu, link->sink.reg);
+-              sink_reg &= ~link->sink.mask;
+-              ipu_cm_write(ipu, sink_reg, link->sink.reg);
+-      }
+-
+-      spin_unlock_irqrestore(&ipu->lock, flags);
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_fsu_unlink);
+-
+-/* Link IDMAC channels in the FSU */
+-int ipu_idmac_link(struct ipuv3_channel *src, struct ipuv3_channel *sink)
+-{
+-      return ipu_fsu_link(src->ipu, src->num, sink->num);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_link);
+-
+-/* Unlink IDMAC channels in the FSU */
+-int ipu_idmac_unlink(struct ipuv3_channel *src, struct ipuv3_channel *sink)
+-{
+-      return ipu_fsu_unlink(src->ipu, src->num, sink->num);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_unlink);
+-
+-struct ipu_devtype {
+-      const char *name;
+-      unsigned long cm_ofs;
+-      unsigned long cpmem_ofs;
+-      unsigned long srm_ofs;
+-      unsigned long tpm_ofs;
+-      unsigned long csi0_ofs;
+-      unsigned long csi1_ofs;
+-      unsigned long ic_ofs;
+-      unsigned long disp0_ofs;
+-      unsigned long disp1_ofs;
+-      unsigned long dc_tmpl_ofs;
+-      unsigned long vdi_ofs;
+-      enum ipuv3_type type;
+-};
+-
+-static struct ipu_devtype ipu_type_imx51 = {
+-      .name = "IPUv3EX",
+-      .cm_ofs = 0x1e000000,
+-      .cpmem_ofs = 0x1f000000,
+-      .srm_ofs = 0x1f040000,
+-      .tpm_ofs = 0x1f060000,
+-      .csi0_ofs = 0x1e030000,
+-      .csi1_ofs = 0x1e038000,
+-      .ic_ofs = 0x1e020000,
+-      .disp0_ofs = 0x1e040000,
+-      .disp1_ofs = 0x1e048000,
+-      .dc_tmpl_ofs = 0x1f080000,
+-      .vdi_ofs = 0x1e068000,
+-      .type = IPUV3EX,
+-};
+-
+-static struct ipu_devtype ipu_type_imx53 = {
+-      .name = "IPUv3M",
+-      .cm_ofs = 0x06000000,
+-      .cpmem_ofs = 0x07000000,
+-      .srm_ofs = 0x07040000,
+-      .tpm_ofs = 0x07060000,
+-      .csi0_ofs = 0x06030000,
+-      .csi1_ofs = 0x06038000,
+-      .ic_ofs = 0x06020000,
+-      .disp0_ofs = 0x06040000,
+-      .disp1_ofs = 0x06048000,
+-      .dc_tmpl_ofs = 0x07080000,
+-      .vdi_ofs = 0x06068000,
+-      .type = IPUV3M,
+-};
+-
+-static struct ipu_devtype ipu_type_imx6q = {
+-      .name = "IPUv3H",
+-      .cm_ofs = 0x00200000,
+-      .cpmem_ofs = 0x00300000,
+-      .srm_ofs = 0x00340000,
+-      .tpm_ofs = 0x00360000,
+-      .csi0_ofs = 0x00230000,
+-      .csi1_ofs = 0x00238000,
+-      .ic_ofs = 0x00220000,
+-      .disp0_ofs = 0x00240000,
+-      .disp1_ofs = 0x00248000,
+-      .dc_tmpl_ofs = 0x00380000,
+-      .vdi_ofs = 0x00268000,
+-      .type = IPUV3H,
+-};
+-
+-static const struct of_device_id imx_ipu_dt_ids[] = {
+-      { .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
+-      { .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
+-      { .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
+-      { .compatible = "fsl,imx6qp-ipu", .data = &ipu_type_imx6q, },
+-      { /* sentinel */ }
+-};
+-MODULE_DEVICE_TABLE(of, imx_ipu_dt_ids);
+-
+-static int ipu_submodules_init(struct ipu_soc *ipu,
+-              struct platform_device *pdev, unsigned long ipu_base,
+-              struct clk *ipu_clk)
+-{
+-      char *unit;
+-      int ret;
+-      struct device *dev = &pdev->dev;
+-      const struct ipu_devtype *devtype = ipu->devtype;
+-
+-      ret = ipu_cpmem_init(ipu, dev, ipu_base + devtype->cpmem_ofs);
+-      if (ret) {
+-              unit = "cpmem";
+-              goto err_cpmem;
+-      }
+-
+-      ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs,
+-                         IPU_CONF_CSI0_EN, ipu_clk);
+-      if (ret) {
+-              unit = "csi0";
+-              goto err_csi_0;
+-      }
+-
+-      ret = ipu_csi_init(ipu, dev, 1, ipu_base + devtype->csi1_ofs,
+-                         IPU_CONF_CSI1_EN, ipu_clk);
+-      if (ret) {
+-              unit = "csi1";
+-              goto err_csi_1;
+-      }
+-
+-      ret = ipu_ic_init(ipu, dev,
+-                        ipu_base + devtype->ic_ofs,
+-                        ipu_base + devtype->tpm_ofs);
+-      if (ret) {
+-              unit = "ic";
+-              goto err_ic;
+-      }
+-
+-      ret = ipu_vdi_init(ipu, dev, ipu_base + devtype->vdi_ofs,
+-                         IPU_CONF_VDI_EN | IPU_CONF_ISP_EN |
+-                         IPU_CONF_IC_INPUT);
+-      if (ret) {
+-              unit = "vdi";
+-              goto err_vdi;
+-      }
+-
+-      ret = ipu_image_convert_init(ipu, dev);
+-      if (ret) {
+-              unit = "image_convert";
+-              goto err_image_convert;
+-      }
+-
+-      ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
+-                        IPU_CONF_DI0_EN, ipu_clk);
+-      if (ret) {
+-              unit = "di0";
+-              goto err_di_0;
+-      }
+-
+-      ret = ipu_di_init(ipu, dev, 1, ipu_base + devtype->disp1_ofs,
+-                      IPU_CONF_DI1_EN, ipu_clk);
+-      if (ret) {
+-              unit = "di1";
+-              goto err_di_1;
+-      }
+-
+-      ret = ipu_dc_init(ipu, dev, ipu_base + devtype->cm_ofs +
+-                      IPU_CM_DC_REG_OFS, ipu_base + devtype->dc_tmpl_ofs);
+-      if (ret) {
+-              unit = "dc_template";
+-              goto err_dc;
+-      }
+-
+-      ret = ipu_dmfc_init(ipu, dev, ipu_base +
+-                      devtype->cm_ofs + IPU_CM_DMFC_REG_OFS, ipu_clk);
+-      if (ret) {
+-              unit = "dmfc";
+-              goto err_dmfc;
+-      }
+-
+-      ret = ipu_dp_init(ipu, dev, ipu_base + devtype->srm_ofs);
+-      if (ret) {
+-              unit = "dp";
+-              goto err_dp;
+-      }
+-
+-      ret = ipu_smfc_init(ipu, dev, ipu_base +
+-                      devtype->cm_ofs + IPU_CM_SMFC_REG_OFS);
+-      if (ret) {
+-              unit = "smfc";
+-              goto err_smfc;
+-      }
+-
+-      return 0;
+-
+-err_smfc:
+-      ipu_dp_exit(ipu);
+-err_dp:
+-      ipu_dmfc_exit(ipu);
+-err_dmfc:
+-      ipu_dc_exit(ipu);
+-err_dc:
+-      ipu_di_exit(ipu, 1);
+-err_di_1:
+-      ipu_di_exit(ipu, 0);
+-err_di_0:
+-      ipu_image_convert_exit(ipu);
+-err_image_convert:
+-      ipu_vdi_exit(ipu);
+-err_vdi:
+-      ipu_ic_exit(ipu);
+-err_ic:
+-      ipu_csi_exit(ipu, 1);
+-err_csi_1:
+-      ipu_csi_exit(ipu, 0);
+-err_csi_0:
+-      ipu_cpmem_exit(ipu);
+-err_cpmem:
+-      dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
+-      return ret;
+-}
+-
+-static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs)
+-{
+-      unsigned long status;
+-      int i, bit, irq;
+-
+-      for (i = 0; i < num_regs; i++) {
+-
+-              status = ipu_cm_read(ipu, IPU_INT_STAT(regs[i]));
+-              status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i]));
+-
+-              for_each_set_bit(bit, &status, 32) {
+-                      irq = irq_linear_revmap(ipu->domain,
+-                                              regs[i] * 32 + bit);
+-                      if (irq)
+-                              generic_handle_irq(irq);
+-              }
+-      }
+-}
+-
+-static void ipu_irq_handler(struct irq_desc *desc)
+-{
+-      struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
+-      struct irq_chip *chip = irq_desc_get_chip(desc);
+-      static const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
+-
+-      chained_irq_enter(chip, desc);
+-
+-      ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
+-
+-      chained_irq_exit(chip, desc);
+-}
+-
+-static void ipu_err_irq_handler(struct irq_desc *desc)
+-{
+-      struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
+-      struct irq_chip *chip = irq_desc_get_chip(desc);
+-      static const int int_reg[] = { 4, 5, 8, 9};
+-
+-      chained_irq_enter(chip, desc);
+-
+-      ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
+-
+-      chained_irq_exit(chip, desc);
+-}
+-
+-int ipu_map_irq(struct ipu_soc *ipu, int irq)
+-{
+-      int virq;
+-
+-      virq = irq_linear_revmap(ipu->domain, irq);
+-      if (!virq)
+-              virq = irq_create_mapping(ipu->domain, irq);
+-
+-      return virq;
+-}
+-EXPORT_SYMBOL_GPL(ipu_map_irq);
+-
+-int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
+-              enum ipu_channel_irq irq_type)
+-{
+-      return ipu_map_irq(ipu, irq_type + channel->num);
+-}
+-EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq);
+-
+-static void ipu_submodules_exit(struct ipu_soc *ipu)
+-{
+-      ipu_smfc_exit(ipu);
+-      ipu_dp_exit(ipu);
+-      ipu_dmfc_exit(ipu);
+-      ipu_dc_exit(ipu);
+-      ipu_di_exit(ipu, 1);
+-      ipu_di_exit(ipu, 0);
+-      ipu_image_convert_exit(ipu);
+-      ipu_vdi_exit(ipu);
+-      ipu_ic_exit(ipu);
+-      ipu_csi_exit(ipu, 1);
+-      ipu_csi_exit(ipu, 0);
+-      ipu_cpmem_exit(ipu);
+-}
+-
+-static int platform_remove_devices_fn(struct device *dev, void *unused)
+-{
+-      struct platform_device *pdev = to_platform_device(dev);
+-
+-      platform_device_unregister(pdev);
+-
+-      return 0;
+-}
+-
+-static void platform_device_unregister_children(struct platform_device *pdev)
+-{
+-      device_for_each_child(&pdev->dev, NULL, platform_remove_devices_fn);
+-}
+-
+-struct ipu_platform_reg {
+-      struct ipu_client_platformdata pdata;
+-      const char *name;
+-};
+-
+-/* These must be in the order of the corresponding device tree port nodes */
+-static struct ipu_platform_reg client_reg[] = {
+-      {
+-              .pdata = {
+-                      .csi = 0,
+-                      .dma[0] = IPUV3_CHANNEL_CSI0,
+-                      .dma[1] = -EINVAL,
+-              },
+-              .name = "imx-ipuv3-csi",
+-      }, {
+-              .pdata = {
+-                      .csi = 1,
+-                      .dma[0] = IPUV3_CHANNEL_CSI1,
+-                      .dma[1] = -EINVAL,
+-              },
+-              .name = "imx-ipuv3-csi",
+-      }, {
+-              .pdata = {
+-                      .di = 0,
+-                      .dc = 5,
+-                      .dp = IPU_DP_FLOW_SYNC_BG,
+-                      .dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC,
+-                      .dma[1] = IPUV3_CHANNEL_MEM_FG_SYNC,
+-              },
+-              .name = "imx-ipuv3-crtc",
+-      }, {
+-              .pdata = {
+-                      .di = 1,
+-                      .dc = 1,
+-                      .dp = -EINVAL,
+-                      .dma[0] = IPUV3_CHANNEL_MEM_DC_SYNC,
+-                      .dma[1] = -EINVAL,
+-              },
+-              .name = "imx-ipuv3-crtc",
+-      },
+-};
+-
+-static DEFINE_MUTEX(ipu_client_id_mutex);
+-static int ipu_client_id;
+-
+-static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
+-{
+-      struct device *dev = ipu->dev;
+-      unsigned i;
+-      int id, ret;
+-
+-      mutex_lock(&ipu_client_id_mutex);
+-      id = ipu_client_id;
+-      ipu_client_id += ARRAY_SIZE(client_reg);
+-      mutex_unlock(&ipu_client_id_mutex);
+-
+-      for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
+-              struct ipu_platform_reg *reg = &client_reg[i];
+-              struct platform_device *pdev;
+-              struct device_node *of_node;
+-
+-              /* Associate subdevice with the corresponding port node */
+-              of_node = of_graph_get_port_by_id(dev->of_node, i);
+-              if (!of_node) {
+-                      dev_info(dev,
+-                               "no port@%d node in %pOF, not using %s%d\n",
+-                               i, dev->of_node,
+-                               (i / 2) ? "DI" : "CSI", i % 2);
+-                      continue;
+-              }
+-
+-              pdev = platform_device_alloc(reg->name, id++);
+-              if (!pdev) {
+-                      ret = -ENOMEM;
+-                      goto err_register;
+-              }
+-
+-              pdev->dev.parent = dev;
+-
+-              reg->pdata.of_node = of_node;
+-              ret = platform_device_add_data(pdev, &reg->pdata,
+-                                             sizeof(reg->pdata));
+-              if (!ret)
+-                      ret = platform_device_add(pdev);
+-              if (ret) {
+-                      platform_device_put(pdev);
+-                      goto err_register;
+-              }
+-      }
+-
+-      return 0;
+-
+-err_register:
+-      platform_device_unregister_children(to_platform_device(dev));
+-
+-      return ret;
+-}
+-
+-
+-static int ipu_irq_init(struct ipu_soc *ipu)
+-{
+-      struct irq_chip_generic *gc;
+-      struct irq_chip_type *ct;
+-      unsigned long unused[IPU_NUM_IRQS / 32] = {
+-              0x400100d0, 0xffe000fd,
+-              0x400100d0, 0xffe000fd,
+-              0x400100d0, 0xffe000fd,
+-              0x4077ffff, 0xffe7e1fd,
+-              0x23fffffe, 0x8880fff0,
+-              0xf98fe7d0, 0xfff81fff,
+-              0x400100d0, 0xffe000fd,
+-              0x00000000,
+-      };
+-      int ret, i;
+-
+-      ipu->domain = irq_domain_add_linear(ipu->dev->of_node, IPU_NUM_IRQS,
+-                                          &irq_generic_chip_ops, ipu);
+-      if (!ipu->domain) {
+-              dev_err(ipu->dev, "failed to add irq domain\n");
+-              return -ENODEV;
+-      }
+-
+-      ret = irq_alloc_domain_generic_chips(ipu->domain, 32, 1, "IPU",
+-                                           handle_level_irq, 0, 0, 0);
+-      if (ret < 0) {
+-              dev_err(ipu->dev, "failed to alloc generic irq chips\n");
+-              irq_domain_remove(ipu->domain);
+-              return ret;
+-      }
+-
+-      /* Mask and clear all interrupts */
+-      for (i = 0; i < IPU_NUM_IRQS; i += 32) {
+-              ipu_cm_write(ipu, 0, IPU_INT_CTRL(i / 32));
+-              ipu_cm_write(ipu, ~unused[i / 32], IPU_INT_STAT(i / 32));
+-      }
+-
+-      for (i = 0; i < IPU_NUM_IRQS; i += 32) {
+-              gc = irq_get_domain_generic_chip(ipu->domain, i);
+-              gc->reg_base = ipu->cm_reg;
+-              gc->unused = unused[i / 32];
+-              ct = gc->chip_types;
+-              ct->chip.irq_ack = irq_gc_ack_set_bit;
+-              ct->chip.irq_mask = irq_gc_mask_clr_bit;
+-              ct->chip.irq_unmask = irq_gc_mask_set_bit;
+-              ct->regs.ack = IPU_INT_STAT(i / 32);
+-              ct->regs.mask = IPU_INT_CTRL(i / 32);
+-      }
+-
+-      irq_set_chained_handler_and_data(ipu->irq_sync, ipu_irq_handler, ipu);
+-      irq_set_chained_handler_and_data(ipu->irq_err, ipu_err_irq_handler,
+-                                       ipu);
+-
+-      return 0;
+-}
+-
+-static void ipu_irq_exit(struct ipu_soc *ipu)
+-{
+-      int i, irq;
+-
+-      irq_set_chained_handler_and_data(ipu->irq_err, NULL, NULL);
+-      irq_set_chained_handler_and_data(ipu->irq_sync, NULL, NULL);
+-
+-      /* TODO: remove irq_domain_generic_chips */
+-
+-      for (i = 0; i < IPU_NUM_IRQS; i++) {
+-              irq = irq_linear_revmap(ipu->domain, i);
+-              if (irq)
+-                      irq_dispose_mapping(irq);
+-      }
+-
+-      irq_domain_remove(ipu->domain);
+-}
+-
+-void ipu_dump(struct ipu_soc *ipu)
+-{
+-      int i;
+-
+-      dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n",
+-              ipu_cm_read(ipu, IPU_CONF));
+-      dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n",
+-              ipu_idmac_read(ipu, IDMAC_CONF));
+-      dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n",
+-              ipu_idmac_read(ipu, IDMAC_CHA_EN(0)));
+-      dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n",
+-              ipu_idmac_read(ipu, IDMAC_CHA_EN(32)));
+-      dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n",
+-              ipu_idmac_read(ipu, IDMAC_CHA_PRI(0)));
+-      dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n",
+-              ipu_idmac_read(ipu, IDMAC_CHA_PRI(32)));
+-      dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n",
+-              ipu_idmac_read(ipu, IDMAC_BAND_EN(0)));
+-      dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n",
+-              ipu_idmac_read(ipu, IDMAC_BAND_EN(32)));
+-      dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
+-              ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0)));
+-      dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
+-              ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32)));
+-      dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n",
+-              ipu_cm_read(ipu, IPU_FS_PROC_FLOW1));
+-      dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n",
+-              ipu_cm_read(ipu, IPU_FS_PROC_FLOW2));
+-      dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n",
+-              ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
+-      dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
+-              ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
+-      for (i = 0; i < 15; i++)
+-              dev_dbg(ipu->dev, "IPU_INT_CTRL(%d) = \t%08X\n", i,
+-                      ipu_cm_read(ipu, IPU_INT_CTRL(i)));
+-}
+-EXPORT_SYMBOL_GPL(ipu_dump);
+-
+-static int ipu_probe(struct platform_device *pdev)
+-{
+-      struct device_node *np = pdev->dev.of_node;
+-      struct ipu_soc *ipu;
+-      struct resource *res;
+-      unsigned long ipu_base;
+-      int ret, irq_sync, irq_err;
+-      const struct ipu_devtype *devtype;
+-
+-      devtype = of_device_get_match_data(&pdev->dev);
+-      if (!devtype)
+-              return -EINVAL;
+-
+-      irq_sync = platform_get_irq(pdev, 0);
+-      irq_err = platform_get_irq(pdev, 1);
+-      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-
+-      dev_dbg(&pdev->dev, "irq_sync: %d irq_err: %d\n",
+-                      irq_sync, irq_err);
+-
+-      if (!res || irq_sync < 0 || irq_err < 0)
+-              return -ENODEV;
+-
+-      ipu_base = res->start;
+-
+-      ipu = devm_kzalloc(&pdev->dev, sizeof(*ipu), GFP_KERNEL);
+-      if (!ipu)
+-              return -ENODEV;
+-
+-      ipu->id = of_alias_get_id(np, "ipu");
+-      if (ipu->id < 0)
+-              ipu->id = 0;
+-
+-      if (of_device_is_compatible(np, "fsl,imx6qp-ipu") &&
+-          IS_ENABLED(CONFIG_DRM)) {
+-              ipu->prg_priv = ipu_prg_lookup_by_phandle(&pdev->dev,
+-                                                        "fsl,prg", ipu->id);
+-              if (!ipu->prg_priv)
+-                      return -EPROBE_DEFER;
+-      }
+-
+-      ipu->devtype = devtype;
+-      ipu->ipu_type = devtype->type;
+-
+-      spin_lock_init(&ipu->lock);
+-      mutex_init(&ipu->channel_lock);
+-      INIT_LIST_HEAD(&ipu->channels);
+-
+-      dev_dbg(&pdev->dev, "cm_reg:   0x%08lx\n",
+-                      ipu_base + devtype->cm_ofs);
+-      dev_dbg(&pdev->dev, "idmac:    0x%08lx\n",
+-                      ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS);
+-      dev_dbg(&pdev->dev, "cpmem:    0x%08lx\n",
+-                      ipu_base + devtype->cpmem_ofs);
+-      dev_dbg(&pdev->dev, "csi0:    0x%08lx\n",
+-                      ipu_base + devtype->csi0_ofs);
+-      dev_dbg(&pdev->dev, "csi1:    0x%08lx\n",
+-                      ipu_base + devtype->csi1_ofs);
+-      dev_dbg(&pdev->dev, "ic:      0x%08lx\n",
+-                      ipu_base + devtype->ic_ofs);
+-      dev_dbg(&pdev->dev, "disp0:    0x%08lx\n",
+-                      ipu_base + devtype->disp0_ofs);
+-      dev_dbg(&pdev->dev, "disp1:    0x%08lx\n",
+-                      ipu_base + devtype->disp1_ofs);
+-      dev_dbg(&pdev->dev, "srm:      0x%08lx\n",
+-                      ipu_base + devtype->srm_ofs);
+-      dev_dbg(&pdev->dev, "tpm:      0x%08lx\n",
+-                      ipu_base + devtype->tpm_ofs);
+-      dev_dbg(&pdev->dev, "dc:       0x%08lx\n",
+-                      ipu_base + devtype->cm_ofs + IPU_CM_DC_REG_OFS);
+-      dev_dbg(&pdev->dev, "ic:       0x%08lx\n",
+-                      ipu_base + devtype->cm_ofs + IPU_CM_IC_REG_OFS);
+-      dev_dbg(&pdev->dev, "dmfc:     0x%08lx\n",
+-                      ipu_base + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS);
+-      dev_dbg(&pdev->dev, "vdi:      0x%08lx\n",
+-                      ipu_base + devtype->vdi_ofs);
+-
+-      ipu->cm_reg = devm_ioremap(&pdev->dev,
+-                      ipu_base + devtype->cm_ofs, PAGE_SIZE);
+-      ipu->idmac_reg = devm_ioremap(&pdev->dev,
+-                      ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS,
+-                      PAGE_SIZE);
+-
+-      if (!ipu->cm_reg || !ipu->idmac_reg)
+-              return -ENOMEM;
+-
+-      ipu->clk = devm_clk_get(&pdev->dev, "bus");
+-      if (IS_ERR(ipu->clk)) {
+-              ret = PTR_ERR(ipu->clk);
+-              dev_err(&pdev->dev, "clk_get failed with %d", ret);
+-              return ret;
+-      }
+-
+-      platform_set_drvdata(pdev, ipu);
+-
+-      ret = clk_prepare_enable(ipu->clk);
+-      if (ret) {
+-              dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
+-              return ret;
+-      }
+-
+-      ipu->dev = &pdev->dev;
+-      ipu->irq_sync = irq_sync;
+-      ipu->irq_err = irq_err;
+-
+-      ret = device_reset(&pdev->dev);
+-      if (ret) {
+-              dev_err(&pdev->dev, "failed to reset: %d\n", ret);
+-              goto out_failed_reset;
+-      }
+-      ret = ipu_memory_reset(ipu);
+-      if (ret)
+-              goto out_failed_reset;
+-
+-      ret = ipu_irq_init(ipu);
+-      if (ret)
+-              goto out_failed_irq;
+-
+-      /* Set MCU_T to divide MCU access window into 2 */
+-      ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
+-                      IPU_DISP_GEN);
+-
+-      ret = ipu_submodules_init(ipu, pdev, ipu_base, ipu->clk);
+-      if (ret)
+-              goto failed_submodules_init;
+-
+-      ret = ipu_add_client_devices(ipu, ipu_base);
+-      if (ret) {
+-              dev_err(&pdev->dev, "adding client devices failed with %d\n",
+-                              ret);
+-              goto failed_add_clients;
+-      }
+-
+-      dev_info(&pdev->dev, "%s probed\n", devtype->name);
+-
+-      return 0;
+-
+-failed_add_clients:
+-      ipu_submodules_exit(ipu);
+-failed_submodules_init:
+-      ipu_irq_exit(ipu);
+-out_failed_irq:
+-out_failed_reset:
+-      clk_disable_unprepare(ipu->clk);
+-      return ret;
+-}
+-
+-static int ipu_remove(struct platform_device *pdev)
+-{
+-      struct ipu_soc *ipu = platform_get_drvdata(pdev);
+-
+-      platform_device_unregister_children(pdev);
+-      ipu_submodules_exit(ipu);
+-      ipu_irq_exit(ipu);
+-
+-      clk_disable_unprepare(ipu->clk);
+-
+-      return 0;
+-}
+-
+-static struct platform_driver imx_ipu_driver = {
+-      .driver = {
+-              .name = "imx-ipuv3",
+-              .of_match_table = imx_ipu_dt_ids,
+-      },
+-      .probe = ipu_probe,
+-      .remove = ipu_remove,
+-};
+-
+-static struct platform_driver * const drivers[] = {
+-#if IS_ENABLED(CONFIG_DRM)
+-      &ipu_pre_drv,
+-      &ipu_prg_drv,
+-#endif
+-      &imx_ipu_driver,
+-};
+-
+-static int __init imx_ipu_init(void)
+-{
+-      return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
+-}
+-module_init(imx_ipu_init);
+-
+-static void __exit imx_ipu_exit(void)
+-{
+-      platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
+-}
+-module_exit(imx_ipu_exit);
+-
+-MODULE_ALIAS("platform:imx-ipuv3");
+-MODULE_DESCRIPTION("i.MX IPU v3 driver");
+-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+-MODULE_LICENSE("GPL");
+--- a/drivers/gpu/imx/ipu-v3/ipu-cpmem.c
++++ /dev/null
+@@ -1,976 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (C) 2012 Mentor Graphics Inc.
+- * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+- */
+-#include <linux/types.h>
+-#include <linux/bitrev.h>
+-#include <linux/io.h>
+-#include <linux/sizes.h>
+-#include <drm/drm_fourcc.h>
+-#include "ipu-prv.h"
+-
+-struct ipu_cpmem_word {
+-      u32 data[5];
+-      u32 res[3];
+-};
+-
+-struct ipu_ch_param {
+-      struct ipu_cpmem_word word[2];
+-};
+-
+-struct ipu_cpmem {
+-      struct ipu_ch_param __iomem *base;
+-      u32 module;
+-      spinlock_t lock;
+-      int use_count;
+-      struct ipu_soc *ipu;
+-};
+-
+-#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
+-
+-#define IPU_FIELD_UBO         IPU_CPMEM_WORD(0, 46, 22)
+-#define IPU_FIELD_VBO         IPU_CPMEM_WORD(0, 68, 22)
+-#define IPU_FIELD_IOX         IPU_CPMEM_WORD(0, 90, 4)
+-#define IPU_FIELD_RDRW                IPU_CPMEM_WORD(0, 94, 1)
+-#define IPU_FIELD_SO          IPU_CPMEM_WORD(0, 113, 1)
+-#define IPU_FIELD_SLY         IPU_CPMEM_WORD(1, 102, 14)
+-#define IPU_FIELD_SLUV                IPU_CPMEM_WORD(1, 128, 14)
+-
+-#define IPU_FIELD_XV          IPU_CPMEM_WORD(0, 0, 10)
+-#define IPU_FIELD_YV          IPU_CPMEM_WORD(0, 10, 9)
+-#define IPU_FIELD_XB          IPU_CPMEM_WORD(0, 19, 13)
+-#define IPU_FIELD_YB          IPU_CPMEM_WORD(0, 32, 12)
+-#define IPU_FIELD_NSB_B               IPU_CPMEM_WORD(0, 44, 1)
+-#define IPU_FIELD_CF          IPU_CPMEM_WORD(0, 45, 1)
+-#define IPU_FIELD_SX          IPU_CPMEM_WORD(0, 46, 12)
+-#define IPU_FIELD_SY          IPU_CPMEM_WORD(0, 58, 11)
+-#define IPU_FIELD_NS          IPU_CPMEM_WORD(0, 69, 10)
+-#define IPU_FIELD_SDX         IPU_CPMEM_WORD(0, 79, 7)
+-#define IPU_FIELD_SM          IPU_CPMEM_WORD(0, 86, 10)
+-#define IPU_FIELD_SCC         IPU_CPMEM_WORD(0, 96, 1)
+-#define IPU_FIELD_SCE         IPU_CPMEM_WORD(0, 97, 1)
+-#define IPU_FIELD_SDY         IPU_CPMEM_WORD(0, 98, 7)
+-#define IPU_FIELD_SDRX                IPU_CPMEM_WORD(0, 105, 1)
+-#define IPU_FIELD_SDRY                IPU_CPMEM_WORD(0, 106, 1)
+-#define IPU_FIELD_BPP         IPU_CPMEM_WORD(0, 107, 3)
+-#define IPU_FIELD_DEC_SEL     IPU_CPMEM_WORD(0, 110, 2)
+-#define IPU_FIELD_DIM         IPU_CPMEM_WORD(0, 112, 1)
+-#define IPU_FIELD_BNDM                IPU_CPMEM_WORD(0, 114, 3)
+-#define IPU_FIELD_BM          IPU_CPMEM_WORD(0, 117, 2)
+-#define IPU_FIELD_ROT         IPU_CPMEM_WORD(0, 119, 1)
+-#define IPU_FIELD_ROT_HF_VF   IPU_CPMEM_WORD(0, 119, 3)
+-#define IPU_FIELD_HF          IPU_CPMEM_WORD(0, 120, 1)
+-#define IPU_FIELD_VF          IPU_CPMEM_WORD(0, 121, 1)
+-#define IPU_FIELD_THE         IPU_CPMEM_WORD(0, 122, 1)
+-#define IPU_FIELD_CAP         IPU_CPMEM_WORD(0, 123, 1)
+-#define IPU_FIELD_CAE         IPU_CPMEM_WORD(0, 124, 1)
+-#define IPU_FIELD_FW          IPU_CPMEM_WORD(0, 125, 13)
+-#define IPU_FIELD_FH          IPU_CPMEM_WORD(0, 138, 12)
+-#define IPU_FIELD_EBA0                IPU_CPMEM_WORD(1, 0, 29)
+-#define IPU_FIELD_EBA1                IPU_CPMEM_WORD(1, 29, 29)
+-#define IPU_FIELD_ILO         IPU_CPMEM_WORD(1, 58, 20)
+-#define IPU_FIELD_NPB         IPU_CPMEM_WORD(1, 78, 7)
+-#define IPU_FIELD_PFS         IPU_CPMEM_WORD(1, 85, 4)
+-#define IPU_FIELD_ALU         IPU_CPMEM_WORD(1, 89, 1)
+-#define IPU_FIELD_ALBM                IPU_CPMEM_WORD(1, 90, 3)
+-#define IPU_FIELD_ID          IPU_CPMEM_WORD(1, 93, 2)
+-#define IPU_FIELD_TH          IPU_CPMEM_WORD(1, 95, 7)
+-#define IPU_FIELD_SL          IPU_CPMEM_WORD(1, 102, 14)
+-#define IPU_FIELD_WID0                IPU_CPMEM_WORD(1, 116, 3)
+-#define IPU_FIELD_WID1                IPU_CPMEM_WORD(1, 119, 3)
+-#define IPU_FIELD_WID2                IPU_CPMEM_WORD(1, 122, 3)
+-#define IPU_FIELD_WID3                IPU_CPMEM_WORD(1, 125, 3)
+-#define IPU_FIELD_OFS0                IPU_CPMEM_WORD(1, 128, 5)
+-#define IPU_FIELD_OFS1                IPU_CPMEM_WORD(1, 133, 5)
+-#define IPU_FIELD_OFS2                IPU_CPMEM_WORD(1, 138, 5)
+-#define IPU_FIELD_OFS3                IPU_CPMEM_WORD(1, 143, 5)
+-#define IPU_FIELD_SXYS                IPU_CPMEM_WORD(1, 148, 1)
+-#define IPU_FIELD_CRE         IPU_CPMEM_WORD(1, 149, 1)
+-#define IPU_FIELD_DEC_SEL2    IPU_CPMEM_WORD(1, 150, 1)
+-
+-static inline struct ipu_ch_param __iomem *
+-ipu_get_cpmem(struct ipuv3_channel *ch)
+-{
+-      struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv;
+-
+-      return cpmem->base + ch->num;
+-}
+-
+-static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v)
+-{
+-      struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
+-      u32 bit = (wbs >> 8) % 160;
+-      u32 size = wbs & 0xff;
+-      u32 word = (wbs >> 8) / 160;
+-      u32 i = bit / 32;
+-      u32 ofs = bit % 32;
+-      u32 mask = (1 << size) - 1;
+-      u32 val;
+-
+-      pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+-
+-      val = readl(&base->word[word].data[i]);
+-      val &= ~(mask << ofs);
+-      val |= v << ofs;
+-      writel(val, &base->word[word].data[i]);
+-
+-      if ((bit + size - 1) / 32 > i) {
+-              val = readl(&base->word[word].data[i + 1]);
+-              val &= ~(mask >> (ofs ? (32 - ofs) : 0));
+-              val |= v >> (ofs ? (32 - ofs) : 0);
+-              writel(val, &base->word[word].data[i + 1]);
+-      }
+-}
+-
+-static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs)
+-{
+-      struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
+-      u32 bit = (wbs >> 8) % 160;
+-      u32 size = wbs & 0xff;
+-      u32 word = (wbs >> 8) / 160;
+-      u32 i = bit / 32;
+-      u32 ofs = bit % 32;
+-      u32 mask = (1 << size) - 1;
+-      u32 val = 0;
+-
+-      pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+-
+-      val = (readl(&base->word[word].data[i]) >> ofs) & mask;
+-
+-      if ((bit + size - 1) / 32 > i) {
+-              u32 tmp;
+-
+-              tmp = readl(&base->word[word].data[i + 1]);
+-              tmp &= mask >> (ofs ? (32 - ofs) : 0);
+-              val |= tmp << (ofs ? (32 - ofs) : 0);
+-      }
+-
+-      return val;
+-}
+-
+-/*
+- * The V4L2 spec defines packed RGB formats in memory byte order, which from
+- * point of view of the IPU corresponds to little-endian words with the first
+- * component in the least significant bits.
+- * The DRM pixel formats and IPU internal representation are ordered the other
+- * way around, with the first named component ordered at the most significant
+- * bits. Further, V4L2 formats are not well defined:
+- *     https://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
+- * We choose the interpretation which matches GStreamer behavior.
+- */
+-static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
+-{
+-      switch (pixelformat) {
+-      case V4L2_PIX_FMT_RGB565:
+-              /*
+-               * Here we choose the 'corrected' interpretation of RGBP, a
+-               * little-endian 16-bit word with the red component at the most
+-               * significant bits:
+-               * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
+-               */
+-              return DRM_FORMAT_RGB565;
+-      case V4L2_PIX_FMT_BGR24:
+-              /* B G R <=> [24:0] R:G:B */
+-              return DRM_FORMAT_RGB888;
+-      case V4L2_PIX_FMT_RGB24:
+-              /* R G B <=> [24:0] B:G:R */
+-              return DRM_FORMAT_BGR888;
+-      case V4L2_PIX_FMT_BGR32:
+-              /* B G R A <=> [32:0] A:B:G:R */
+-              return DRM_FORMAT_XRGB8888;
+-      case V4L2_PIX_FMT_RGB32:
+-              /* R G B A <=> [32:0] A:B:G:R */
+-              return DRM_FORMAT_XBGR8888;
+-      case V4L2_PIX_FMT_ABGR32:
+-              /* B G R A <=> [32:0] A:R:G:B */
+-              return DRM_FORMAT_ARGB8888;
+-      case V4L2_PIX_FMT_XBGR32:
+-              /* B G R X <=> [32:0] X:R:G:B */
+-              return DRM_FORMAT_XRGB8888;
+-      case V4L2_PIX_FMT_BGRA32:
+-              /* A B G R <=> [32:0] R:G:B:A */
+-              return DRM_FORMAT_RGBA8888;
+-      case V4L2_PIX_FMT_BGRX32:
+-              /* X B G R <=> [32:0] R:G:B:X */
+-              return DRM_FORMAT_RGBX8888;
+-      case V4L2_PIX_FMT_RGBA32:
+-              /* R G B A <=> [32:0] A:B:G:R */
+-              return DRM_FORMAT_ABGR8888;
+-      case V4L2_PIX_FMT_RGBX32:
+-              /* R G B X <=> [32:0] X:B:G:R */
+-              return DRM_FORMAT_XBGR8888;
+-      case V4L2_PIX_FMT_ARGB32:
+-              /* A R G B <=> [32:0] B:G:R:A */
+-              return DRM_FORMAT_BGRA8888;
+-      case V4L2_PIX_FMT_XRGB32:
+-              /* X R G B <=> [32:0] B:G:R:X */
+-              return DRM_FORMAT_BGRX8888;
+-      case V4L2_PIX_FMT_UYVY:
+-              return DRM_FORMAT_UYVY;
+-      case V4L2_PIX_FMT_YUYV:
+-              return DRM_FORMAT_YUYV;
+-      case V4L2_PIX_FMT_YUV420:
+-              return DRM_FORMAT_YUV420;
+-      case V4L2_PIX_FMT_YUV422P:
+-              return DRM_FORMAT_YUV422;
+-      case V4L2_PIX_FMT_YVU420:
+-              return DRM_FORMAT_YVU420;
+-      case V4L2_PIX_FMT_NV12:
+-              return DRM_FORMAT_NV12;
+-      case V4L2_PIX_FMT_NV16:
+-              return DRM_FORMAT_NV16;
+-      }
+-
+-      return -EINVAL;
+-}
+-
+-void ipu_cpmem_zero(struct ipuv3_channel *ch)
+-{
+-      struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
+-      void __iomem *base = p;
+-      int i;
+-
+-      for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
+-              writel(0, base + i * sizeof(u32));
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
+-
+-void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres)
+-{
+-      ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
+-
+-void ipu_cpmem_skip_odd_chroma_rows(struct ipuv3_channel *ch)
+-{
+-      ipu_ch_param_write_field(ch, IPU_FIELD_RDRW, 1);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_skip_odd_chroma_rows);
+-
+-void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
+-{
+-      ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
+-
+-void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch)
+-{
+-      struct ipu_soc *ipu = ch->ipu;
+-      u32 val;
+-
+-      if (ipu->ipu_type == IPUV3EX)
+-              ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1);
+-
+-      val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num));
+-      val |= 1 << (ch->num % 32);
+-      ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num));
+-};
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
+-
+-void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
+-{
+-      WARN_ON_ONCE(buf & 0x7);
+-
+-      if (bufnum)
+-              ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
+-      else
+-              ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
+-
+-void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
+-{
+-      WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7));
+-
+-      ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
+-
+-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+-                             u32 pixelformat)
+-{
+-      u32 ilo, sly, sluv;
+-
+-      if (stride < 0) {
+-              stride = -stride;
+-              ilo = 0x100000 - (stride / 8);
+-      } else {
+-              ilo = stride / 8;
+-      }
+-
+-      sly = (stride * 2) - 1;
+-
+-      switch (pixelformat) {
+-      case V4L2_PIX_FMT_YUV420:
+-      case V4L2_PIX_FMT_YVU420:
+-              sluv = stride / 2 - 1;
+-              break;
+-      case V4L2_PIX_FMT_NV12:
+-              sluv = stride - 1;
+-              break;
+-      case V4L2_PIX_FMT_YUV422P:
+-              sluv = stride - 1;
+-              break;
+-      case V4L2_PIX_FMT_NV16:
+-              sluv = stride * 2 - 1;
+-              break;
+-      default:
+-              sluv = 0;
+-              break;
+-      }
+-
+-      ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
+-      if (sluv)
+-              ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
+-};
+-EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
+-
+-void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
+-{
+-      id &= 0x3;
+-      ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
+-
+-int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
+-{
+-      return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
+-
+-void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
+-{
+-      ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
+-};
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
+-
+-void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
+-{
+-      ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
+-
+-void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
+-                          enum ipu_rotate_mode rot)
+-{
+-      u32 temp_rot = bitrev8(rot) >> 5;
+-
+-      ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
+-
+-int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
+-                           const struct ipu_rgb *rgb)
+-{
+-      int bpp = 0, npb = 0, ro, go, bo, to;
+-
+-      ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
+-      go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
+-      bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
+-      to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
+-
+-      ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo);
+-
+-      if (rgb->transp.length) {
+-              ipu_ch_param_write_field(ch, IPU_FIELD_WID3,
+-                              rgb->transp.length - 1);
+-              ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to);
+-      } else {
+-              ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
+-              ipu_ch_param_write_field(ch, IPU_FIELD_OFS3,
+-                              rgb->bits_per_pixel);
+-      }
+-
+-      switch (rgb->bits_per_pixel) {
+-      case 32:
+-              bpp = 0;
+-              npb = 15;
+-              break;
+-      case 24:
+-              bpp = 1;
+-              npb = 19;
+-              break;
+-      case 16:
+-              bpp = 3;
+-              npb = 31;
+-              break;
+-      case 8:
+-              bpp = 5;
+-              npb = 63;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-      ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
+-
+-int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width)
+-{
+-      int bpp = 0, npb = 0;
+-
+-      switch (width) {
+-      case 32:
+-              bpp = 0;
+-              npb = 15;
+-              break;
+-      case 24:
+-              bpp = 1;
+-              npb = 19;
+-              break;
+-      case 16:
+-              bpp = 3;
+-              npb = 31;
+-              break;
+-      case 8:
+-              bpp = 5;
+-              npb = 63;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
+-
+-void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format)
+-{
+-      switch (pixel_format) {
+-      case V4L2_PIX_FMT_UYVY:
+-              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
+-              break;
+-      case V4L2_PIX_FMT_YUYV:
+-              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
+-              break;
+-      }
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
+-
+-void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
+-                                 unsigned int uv_stride,
+-                                 unsigned int u_offset, unsigned int v_offset)
+-{
+-      WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7));
+-
+-      ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
+-
+-static const struct ipu_rgb def_xrgb_32 = {
+-      .red    = { .offset = 16, .length = 8, },
+-      .green  = { .offset =  8, .length = 8, },
+-      .blue   = { .offset =  0, .length = 8, },
+-      .transp = { .offset = 24, .length = 8, },
+-      .bits_per_pixel = 32,
+-};
+-
+-static const struct ipu_rgb def_xbgr_32 = {
+-      .red    = { .offset =  0, .length = 8, },
+-      .green  = { .offset =  8, .length = 8, },
+-      .blue   = { .offset = 16, .length = 8, },
+-      .transp = { .offset = 24, .length = 8, },
+-      .bits_per_pixel = 32,
+-};
+-
+-static const struct ipu_rgb def_rgbx_32 = {
+-      .red    = { .offset = 24, .length = 8, },
+-      .green  = { .offset = 16, .length = 8, },
+-      .blue   = { .offset =  8, .length = 8, },
+-      .transp = { .offset =  0, .length = 8, },
+-      .bits_per_pixel = 32,
+-};
+-
+-static const struct ipu_rgb def_bgrx_32 = {
+-      .red    = { .offset =  8, .length = 8, },
+-      .green  = { .offset = 16, .length = 8, },
+-      .blue   = { .offset = 24, .length = 8, },
+-      .transp = { .offset =  0, .length = 8, },
+-      .bits_per_pixel = 32,
+-};
+-
+-static const struct ipu_rgb def_rgb_24 = {
+-      .red    = { .offset = 16, .length = 8, },
+-      .green  = { .offset =  8, .length = 8, },
+-      .blue   = { .offset =  0, .length = 8, },
+-      .transp = { .offset =  0, .length = 0, },
+-      .bits_per_pixel = 24,
+-};
+-
+-static const struct ipu_rgb def_bgr_24 = {
+-      .red    = { .offset =  0, .length = 8, },
+-      .green  = { .offset =  8, .length = 8, },
+-      .blue   = { .offset = 16, .length = 8, },
+-      .transp = { .offset =  0, .length = 0, },
+-      .bits_per_pixel = 24,
+-};
+-
+-static const struct ipu_rgb def_rgb_16 = {
+-      .red    = { .offset = 11, .length = 5, },
+-      .green  = { .offset =  5, .length = 6, },
+-      .blue   = { .offset =  0, .length = 5, },
+-      .transp = { .offset =  0, .length = 0, },
+-      .bits_per_pixel = 16,
+-};
+-
+-static const struct ipu_rgb def_bgr_16 = {
+-      .red    = { .offset =  0, .length = 5, },
+-      .green  = { .offset =  5, .length = 6, },
+-      .blue   = { .offset = 11, .length = 5, },
+-      .transp = { .offset =  0, .length = 0, },
+-      .bits_per_pixel = 16,
+-};
+-
+-static const struct ipu_rgb def_argb_16 = {
+-      .red    = { .offset = 10, .length = 5, },
+-      .green  = { .offset =  5, .length = 5, },
+-      .blue   = { .offset =  0, .length = 5, },
+-      .transp = { .offset = 15, .length = 1, },
+-      .bits_per_pixel = 16,
+-};
+-
+-static const struct ipu_rgb def_argb_16_4444 = {
+-      .red    = { .offset =  8, .length = 4, },
+-      .green  = { .offset =  4, .length = 4, },
+-      .blue   = { .offset =  0, .length = 4, },
+-      .transp = { .offset = 12, .length = 4, },
+-      .bits_per_pixel = 16,
+-};
+-
+-static const struct ipu_rgb def_abgr_16 = {
+-      .red    = { .offset =  0, .length = 5, },
+-      .green  = { .offset =  5, .length = 5, },
+-      .blue   = { .offset = 10, .length = 5, },
+-      .transp = { .offset = 15, .length = 1, },
+-      .bits_per_pixel = 16,
+-};
+-
+-static const struct ipu_rgb def_rgba_16 = {
+-      .red    = { .offset = 11, .length = 5, },
+-      .green  = { .offset =  6, .length = 5, },
+-      .blue   = { .offset =  1, .length = 5, },
+-      .transp = { .offset =  0, .length = 1, },
+-      .bits_per_pixel = 16,
+-};
+-
+-static const struct ipu_rgb def_bgra_16 = {
+-      .red    = { .offset =  1, .length = 5, },
+-      .green  = { .offset =  6, .length = 5, },
+-      .blue   = { .offset = 11, .length = 5, },
+-      .transp = { .offset =  0, .length = 1, },
+-      .bits_per_pixel = 16,
+-};
+-
+-#define Y_OFFSET(pix, x, y)   ((x) + pix->width * (y))
+-#define U_OFFSET(pix, x, y)   ((pix->width * pix->height) +           \
+-                               (pix->width * ((y) / 2) / 2) + (x) / 2)
+-#define V_OFFSET(pix, x, y)   ((pix->width * pix->height) +           \
+-                               (pix->width * pix->height / 4) +       \
+-                               (pix->width * ((y) / 2) / 2) + (x) / 2)
+-#define U2_OFFSET(pix, x, y)  ((pix->width * pix->height) +           \
+-                               (pix->width * (y) / 2) + (x) / 2)
+-#define V2_OFFSET(pix, x, y)  ((pix->width * pix->height) +           \
+-                               (pix->width * pix->height / 2) +       \
+-                               (pix->width * (y) / 2) + (x) / 2)
+-#define UV_OFFSET(pix, x, y)  ((pix->width * pix->height) +   \
+-                               (pix->width * ((y) / 2)) + (x))
+-#define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) +   \
+-                               (pix->width * y) + (x))
+-
+-#define NUM_ALPHA_CHANNELS    7
+-
+-/* See Table 37-12. Alpha channels mapping. */
+-static int ipu_channel_albm(int ch_num)
+-{
+-      switch (ch_num) {
+-      case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:     return 0;
+-      case IPUV3_CHANNEL_G_MEM_IC_PP:         return 1;
+-      case IPUV3_CHANNEL_MEM_FG_SYNC:         return 2;
+-      case IPUV3_CHANNEL_MEM_FG_ASYNC:        return 3;
+-      case IPUV3_CHANNEL_MEM_BG_SYNC:         return 4;
+-      case IPUV3_CHANNEL_MEM_BG_ASYNC:        return 5;
+-      case IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB: return 6;
+-      default:
+-              return -EINVAL;
+-      }
+-}
+-
+-static void ipu_cpmem_set_separate_alpha(struct ipuv3_channel *ch)
+-{
+-      struct ipu_soc *ipu = ch->ipu;
+-      int albm;
+-      u32 val;
+-
+-      albm = ipu_channel_albm(ch->num);
+-      if (albm < 0)
+-              return;
+-
+-      ipu_ch_param_write_field(ch, IPU_FIELD_ALU, 1);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_ALBM, albm);
+-      ipu_ch_param_write_field(ch, IPU_FIELD_CRE, 1);
+-
+-      val = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
+-      val |= BIT(ch->num);
+-      ipu_idmac_write(ipu, val, IDMAC_SEP_ALPHA);
+-}
+-
+-int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
+-{
+-      switch (drm_fourcc) {
+-      case DRM_FORMAT_YUV420:
+-      case DRM_FORMAT_YVU420:
+-              /* pix format */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
+-              /* burst size */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+-              break;
+-      case DRM_FORMAT_YUV422:
+-      case DRM_FORMAT_YVU422:
+-              /* pix format */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
+-              /* burst size */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+-              break;
+-      case DRM_FORMAT_YUV444:
+-      case DRM_FORMAT_YVU444:
+-              /* pix format */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0);
+-              /* burst size */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+-              break;
+-      case DRM_FORMAT_NV12:
+-              /* pix format */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
+-              /* burst size */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+-              break;
+-      case DRM_FORMAT_NV16:
+-              /* pix format */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
+-              /* burst size */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+-              break;
+-      case DRM_FORMAT_UYVY:
+-              /* bits/pixel */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
+-              /* pix format */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
+-              /* burst size */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+-              break;
+-      case DRM_FORMAT_YUYV:
+-              /* bits/pixel */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
+-              /* pix format */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
+-              /* burst size */
+-              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+-              break;
+-      case DRM_FORMAT_ABGR8888:
+-      case DRM_FORMAT_XBGR8888:
+-              ipu_cpmem_set_format_rgb(ch, &def_xbgr_32);
+-              break;
+-      case DRM_FORMAT_ARGB8888:
+-      case DRM_FORMAT_XRGB8888:
+-              ipu_cpmem_set_format_rgb(ch, &def_xrgb_32);
+-              break;
+-      case DRM_FORMAT_RGBA8888:
+-      case DRM_FORMAT_RGBX8888:
+-      case DRM_FORMAT_RGBX8888_A8:
+-              ipu_cpmem_set_format_rgb(ch, &def_rgbx_32);
+-              break;
+-      case DRM_FORMAT_BGRA8888:
+-      case DRM_FORMAT_BGRX8888:
+-      case DRM_FORMAT_BGRX8888_A8:
+-              ipu_cpmem_set_format_rgb(ch, &def_bgrx_32);
+-              break;
+-      case DRM_FORMAT_BGR888:
+-      case DRM_FORMAT_BGR888_A8:
+-              ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
+-              break;
+-      case DRM_FORMAT_RGB888:
+-      case DRM_FORMAT_RGB888_A8:
+-              ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
+-              break;
+-      case DRM_FORMAT_RGB565:
+-      case DRM_FORMAT_RGB565_A8:
+-              ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
+-              break;
+-      case DRM_FORMAT_BGR565:
+-      case DRM_FORMAT_BGR565_A8:
+-              ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
+-              break;
+-      case DRM_FORMAT_ARGB1555:
+-              ipu_cpmem_set_format_rgb(ch, &def_argb_16);
+-              break;
+-      case DRM_FORMAT_ABGR1555:
+-              ipu_cpmem_set_format_rgb(ch, &def_abgr_16);
+-              break;
+-      case DRM_FORMAT_RGBA5551:
+-              ipu_cpmem_set_format_rgb(ch, &def_rgba_16);
+-              break;
+-      case DRM_FORMAT_BGRA5551:
+-              ipu_cpmem_set_format_rgb(ch, &def_bgra_16);
+-              break;
+-      case DRM_FORMAT_ARGB4444:
+-              ipu_cpmem_set_format_rgb(ch, &def_argb_16_4444);
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      switch (drm_fourcc) {
+-      case DRM_FORMAT_RGB565_A8:
+-      case DRM_FORMAT_BGR565_A8:
+-      case DRM_FORMAT_RGB888_A8:
+-      case DRM_FORMAT_BGR888_A8:
+-      case DRM_FORMAT_RGBX8888_A8:
+-      case DRM_FORMAT_BGRX8888_A8:
+-              ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
+-              ipu_cpmem_set_separate_alpha(ch);
+-              break;
+-      default:
+-              break;
+-      }
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
+-
+-int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
+-{
+-      struct v4l2_pix_format *pix = &image->pix;
+-      int offset, u_offset, v_offset;
+-      int ret = 0;
+-
+-      pr_debug("%s: resolution: %dx%d stride: %d\n",
+-               __func__, pix->width, pix->height,
+-               pix->bytesperline);
+-
+-      ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
+-      ipu_cpmem_set_stride(ch, pix->bytesperline);
+-
+-      ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
+-
+-      switch (pix->pixelformat) {
+-      case V4L2_PIX_FMT_YUV420:
+-              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+-              u_offset = image->u_offset ?
+-                      image->u_offset : U_OFFSET(pix, image->rect.left,
+-                                                 image->rect.top) - offset;
+-              v_offset = image->v_offset ?
+-                      image->v_offset : V_OFFSET(pix, image->rect.left,
+-                                                 image->rect.top) - offset;
+-
+-              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
+-                                            u_offset, v_offset);
+-              break;
+-      case V4L2_PIX_FMT_YVU420:
+-              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+-              u_offset = image->u_offset ?
+-                      image->u_offset : V_OFFSET(pix, image->rect.left,
+-                                                 image->rect.top) - offset;
+-              v_offset = image->v_offset ?
+-                      image->v_offset : U_OFFSET(pix, image->rect.left,
+-                                                 image->rect.top) - offset;
+-
+-              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
+-                                            u_offset, v_offset);
+-              break;
+-      case V4L2_PIX_FMT_YUV422P:
+-              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+-              u_offset = image->u_offset ?
+-                      image->u_offset : U2_OFFSET(pix, image->rect.left,
+-                                                  image->rect.top) - offset;
+-              v_offset = image->v_offset ?
+-                      image->v_offset : V2_OFFSET(pix, image->rect.left,
+-                                                  image->rect.top) - offset;
+-
+-              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
+-                                            u_offset, v_offset);
+-              break;
+-      case V4L2_PIX_FMT_NV12:
+-              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+-              u_offset = image->u_offset ?
+-                      image->u_offset : UV_OFFSET(pix, image->rect.left,
+-                                                  image->rect.top) - offset;
+-              v_offset = image->v_offset ? image->v_offset : 0;
+-
+-              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
+-                                            u_offset, v_offset);
+-              break;
+-      case V4L2_PIX_FMT_NV16:
+-              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+-              u_offset = image->u_offset ?
+-                      image->u_offset : UV2_OFFSET(pix, image->rect.left,
+-                                                   image->rect.top) - offset;
+-              v_offset = image->v_offset ? image->v_offset : 0;
+-
+-              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
+-                                            u_offset, v_offset);
+-              break;
+-      case V4L2_PIX_FMT_UYVY:
+-      case V4L2_PIX_FMT_YUYV:
+-      case V4L2_PIX_FMT_RGB565:
+-              offset = image->rect.left * 2 +
+-                      image->rect.top * pix->bytesperline;
+-              break;
+-      case V4L2_PIX_FMT_RGB32:
+-      case V4L2_PIX_FMT_BGR32:
+-      case V4L2_PIX_FMT_ABGR32:
+-      case V4L2_PIX_FMT_XBGR32:
+-      case V4L2_PIX_FMT_BGRA32:
+-      case V4L2_PIX_FMT_BGRX32:
+-      case V4L2_PIX_FMT_RGBA32:
+-      case V4L2_PIX_FMT_RGBX32:
+-      case V4L2_PIX_FMT_ARGB32:
+-      case V4L2_PIX_FMT_XRGB32:
+-              offset = image->rect.left * 4 +
+-                      image->rect.top * pix->bytesperline;
+-              break;
+-      case V4L2_PIX_FMT_RGB24:
+-      case V4L2_PIX_FMT_BGR24:
+-              offset = image->rect.left * 3 +
+-                      image->rect.top * pix->bytesperline;
+-              break;
+-      case V4L2_PIX_FMT_SBGGR8:
+-      case V4L2_PIX_FMT_SGBRG8:
+-      case V4L2_PIX_FMT_SGRBG8:
+-      case V4L2_PIX_FMT_SRGGB8:
+-      case V4L2_PIX_FMT_GREY:
+-              offset = image->rect.left + image->rect.top * pix->bytesperline;
+-              break;
+-      case V4L2_PIX_FMT_SBGGR16:
+-      case V4L2_PIX_FMT_SGBRG16:
+-      case V4L2_PIX_FMT_SGRBG16:
+-      case V4L2_PIX_FMT_SRGGB16:
+-      case V4L2_PIX_FMT_Y16:
+-              offset = image->rect.left * 2 +
+-                       image->rect.top * pix->bytesperline;
+-              break;
+-      default:
+-              /* This should not happen */
+-              WARN_ON(1);
+-              offset = 0;
+-              ret = -EINVAL;
+-      }
+-
+-      ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
+-      ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
+-
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
+-
+-void ipu_cpmem_dump(struct ipuv3_channel *ch)
+-{
+-      struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
+-      struct ipu_soc *ipu = ch->ipu;
+-      int chno = ch->num;
+-
+-      dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
+-              readl(&p->word[0].data[0]),
+-              readl(&p->word[0].data[1]),
+-              readl(&p->word[0].data[2]),
+-              readl(&p->word[0].data[3]),
+-              readl(&p->word[0].data[4]));
+-      dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
+-              readl(&p->word[1].data[0]),
+-              readl(&p->word[1].data[1]),
+-              readl(&p->word[1].data[2]),
+-              readl(&p->word[1].data[3]),
+-              readl(&p->word[1].data[4]));
+-      dev_dbg(ipu->dev, "PFS 0x%x, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
+-      dev_dbg(ipu->dev, "BPP 0x%x, ",
+-              ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
+-      dev_dbg(ipu->dev, "NPB 0x%x\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
+-
+-      dev_dbg(ipu->dev, "FW %d, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_FW));
+-      dev_dbg(ipu->dev, "FH %d, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_FH));
+-      dev_dbg(ipu->dev, "EBA0 0x%x\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
+-      dev_dbg(ipu->dev, "EBA1 0x%x\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
+-      dev_dbg(ipu->dev, "Stride %d\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_SL));
+-      dev_dbg(ipu->dev, "scan_order %d\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_SO));
+-      dev_dbg(ipu->dev, "uv_stride %d\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
+-      dev_dbg(ipu->dev, "u_offset 0x%x\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
+-      dev_dbg(ipu->dev, "v_offset 0x%x\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
+-
+-      dev_dbg(ipu->dev, "Width0 %d+1, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
+-      dev_dbg(ipu->dev, "Width1 %d+1, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
+-      dev_dbg(ipu->dev, "Width2 %d+1, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
+-      dev_dbg(ipu->dev, "Width3 %d+1, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
+-      dev_dbg(ipu->dev, "Offset0 %d, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
+-      dev_dbg(ipu->dev, "Offset1 %d, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
+-      dev_dbg(ipu->dev, "Offset2 %d, ",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
+-      dev_dbg(ipu->dev, "Offset3 %d\n",
+-               ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
+-}
+-EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
+-
+-int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
+-{
+-      struct ipu_cpmem *cpmem;
+-
+-      cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
+-      if (!cpmem)
+-              return -ENOMEM;
+-
+-      ipu->cpmem_priv = cpmem;
+-
+-      spin_lock_init(&cpmem->lock);
+-      cpmem->base = devm_ioremap(dev, base, SZ_128K);
+-      if (!cpmem->base)
+-              return -ENOMEM;
+-
+-      dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
+-              base, cpmem->base);
+-      cpmem->ipu = ipu;
+-
+-      return 0;
+-}
+-
+-void ipu_cpmem_exit(struct ipu_soc *ipu)
+-{
+-}
+--- a/drivers/gpu/imx/ipu-v3/ipu-csi.c
++++ /dev/null
+@@ -1,821 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (C) 2012-2014 Mentor Graphics Inc.
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-#include <linux/export.h>
+-#include <linux/module.h>
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/delay.h>
+-#include <linux/io.h>
+-#include <linux/err.h>
+-#include <linux/platform_device.h>
+-#include <linux/videodev2.h>
+-#include <uapi/linux/v4l2-mediabus.h>
+-#include <linux/clk.h>
+-#include <linux/clk-provider.h>
+-#include <linux/clkdev.h>
+-
+-#include "ipu-prv.h"
+-
+-struct ipu_csi {
+-      void __iomem *base;
+-      int id;
+-      u32 module;
+-      struct clk *clk_ipu;    /* IPU bus clock */
+-      spinlock_t lock;
+-      bool inuse;
+-      struct ipu_soc *ipu;
+-};
+-
+-/* CSI Register Offsets */
+-#define CSI_SENS_CONF         0x0000
+-#define CSI_SENS_FRM_SIZE     0x0004
+-#define CSI_ACT_FRM_SIZE      0x0008
+-#define CSI_OUT_FRM_CTRL      0x000c
+-#define CSI_TST_CTRL          0x0010
+-#define CSI_CCIR_CODE_1               0x0014
+-#define CSI_CCIR_CODE_2               0x0018
+-#define CSI_CCIR_CODE_3               0x001c
+-#define CSI_MIPI_DI           0x0020
+-#define CSI_SKIP              0x0024
+-#define CSI_CPD_CTRL          0x0028
+-#define CSI_CPD_RC(n)         (0x002c + ((n)*4))
+-#define CSI_CPD_RS(n)         (0x004c + ((n)*4))
+-#define CSI_CPD_GRC(n)                (0x005c + ((n)*4))
+-#define CSI_CPD_GRS(n)                (0x007c + ((n)*4))
+-#define CSI_CPD_GBC(n)                (0x008c + ((n)*4))
+-#define CSI_CPD_GBS(n)                (0x00Ac + ((n)*4))
+-#define CSI_CPD_BC(n)         (0x00Bc + ((n)*4))
+-#define CSI_CPD_BS(n)         (0x00Dc + ((n)*4))
+-#define CSI_CPD_OFFSET1               0x00ec
+-#define CSI_CPD_OFFSET2               0x00f0
+-
+-/* CSI Register Fields */
+-#define CSI_SENS_CONF_DATA_FMT_SHIFT          8
+-#define CSI_SENS_CONF_DATA_FMT_MASK           0x00000700
+-#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444     0L
+-#define CSI_SENS_CONF_DATA_FMT_YUV422_YUYV    1L
+-#define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY    2L
+-#define CSI_SENS_CONF_DATA_FMT_BAYER          3L
+-#define CSI_SENS_CONF_DATA_FMT_RGB565         4L
+-#define CSI_SENS_CONF_DATA_FMT_RGB555         5L
+-#define CSI_SENS_CONF_DATA_FMT_RGB444         6L
+-#define CSI_SENS_CONF_DATA_FMT_JPEG           7L
+-
+-#define CSI_SENS_CONF_VSYNC_POL_SHIFT         0
+-#define CSI_SENS_CONF_HSYNC_POL_SHIFT         1
+-#define CSI_SENS_CONF_DATA_POL_SHIFT          2
+-#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT               3
+-#define CSI_SENS_CONF_SENS_PRTCL_MASK         0x00000070
+-#define CSI_SENS_CONF_SENS_PRTCL_SHIFT                4
+-#define CSI_SENS_CONF_PACK_TIGHT_SHIFT                7
+-#define CSI_SENS_CONF_DATA_WIDTH_SHIFT                11
+-#define CSI_SENS_CONF_EXT_VSYNC_SHIFT         15
+-#define CSI_SENS_CONF_DIVRATIO_SHIFT          16
+-
+-#define CSI_SENS_CONF_DIVRATIO_MASK           0x00ff0000
+-#define CSI_SENS_CONF_DATA_DEST_SHIFT         24
+-#define CSI_SENS_CONF_DATA_DEST_MASK          0x07000000
+-#define CSI_SENS_CONF_JPEG8_EN_SHIFT          27
+-#define CSI_SENS_CONF_JPEG_EN_SHIFT           28
+-#define CSI_SENS_CONF_FORCE_EOF_SHIFT         29
+-#define CSI_SENS_CONF_DATA_EN_POL_SHIFT               31
+-
+-#define CSI_DATA_DEST_IC                      2
+-#define CSI_DATA_DEST_IDMAC                   4
+-
+-#define CSI_CCIR_ERR_DET_EN                   0x01000000
+-#define CSI_HORI_DOWNSIZE_EN                  0x80000000
+-#define CSI_VERT_DOWNSIZE_EN                  0x40000000
+-#define CSI_TEST_GEN_MODE_EN                  0x01000000
+-
+-#define CSI_HSC_MASK                          0x1fff0000
+-#define CSI_HSC_SHIFT                         16
+-#define CSI_VSC_MASK                          0x00000fff
+-#define CSI_VSC_SHIFT                         0
+-
+-#define CSI_TEST_GEN_R_MASK                   0x000000ff
+-#define CSI_TEST_GEN_R_SHIFT                  0
+-#define CSI_TEST_GEN_G_MASK                   0x0000ff00
+-#define CSI_TEST_GEN_G_SHIFT                  8
+-#define CSI_TEST_GEN_B_MASK                   0x00ff0000
+-#define CSI_TEST_GEN_B_SHIFT                  16
+-
+-#define CSI_MAX_RATIO_SKIP_SMFC_MASK          0x00000007
+-#define CSI_MAX_RATIO_SKIP_SMFC_SHIFT         0
+-#define CSI_SKIP_SMFC_MASK                    0x000000f8
+-#define CSI_SKIP_SMFC_SHIFT                   3
+-#define CSI_ID_2_SKIP_MASK                    0x00000300
+-#define CSI_ID_2_SKIP_SHIFT                   8
+-
+-#define CSI_COLOR_FIRST_ROW_MASK              0x00000002
+-#define CSI_COLOR_FIRST_COMP_MASK             0x00000001
+-
+-/* MIPI CSI-2 data types */
+-#define MIPI_DT_YUV420                0x18 /* YYY.../UYVY.... */
+-#define MIPI_DT_YUV420_LEGACY 0x1a /* UYY.../VYY...   */
+-#define MIPI_DT_YUV422                0x1e /* UYVY...         */
+-#define MIPI_DT_RGB444                0x20
+-#define MIPI_DT_RGB555                0x21
+-#define MIPI_DT_RGB565                0x22
+-#define MIPI_DT_RGB666                0x23
+-#define MIPI_DT_RGB888                0x24
+-#define MIPI_DT_RAW6          0x28
+-#define MIPI_DT_RAW7          0x29
+-#define MIPI_DT_RAW8          0x2a
+-#define MIPI_DT_RAW10         0x2b
+-#define MIPI_DT_RAW12         0x2c
+-#define MIPI_DT_RAW14         0x2d
+-
+-/*
+- * Bitfield of CSI bus signal polarities and modes.
+- */
+-struct ipu_csi_bus_config {
+-      unsigned data_width:4;
+-      unsigned clk_mode:3;
+-      unsigned ext_vsync:1;
+-      unsigned vsync_pol:1;
+-      unsigned hsync_pol:1;
+-      unsigned pixclk_pol:1;
+-      unsigned data_pol:1;
+-      unsigned sens_clksrc:1;
+-      unsigned pack_tight:1;
+-      unsigned force_eof:1;
+-      unsigned data_en_pol:1;
+-
+-      unsigned data_fmt;
+-      unsigned mipi_dt;
+-};
+-
+-/*
+- * Enumeration of CSI data bus widths.
+- */
+-enum ipu_csi_data_width {
+-      IPU_CSI_DATA_WIDTH_4   = 0,
+-      IPU_CSI_DATA_WIDTH_8   = 1,
+-      IPU_CSI_DATA_WIDTH_10  = 3,
+-      IPU_CSI_DATA_WIDTH_12  = 5,
+-      IPU_CSI_DATA_WIDTH_16  = 9,
+-};
+-
+-/*
+- * Enumeration of CSI clock modes.
+- */
+-enum ipu_csi_clk_mode {
+-      IPU_CSI_CLK_MODE_GATED_CLK,
+-      IPU_CSI_CLK_MODE_NONGATED_CLK,
+-      IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
+-      IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
+-      IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
+-      IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
+-      IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
+-      IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
+-};
+-
+-static inline u32 ipu_csi_read(struct ipu_csi *csi, unsigned offset)
+-{
+-      return readl(csi->base + offset);
+-}
+-
+-static inline void ipu_csi_write(struct ipu_csi *csi, u32 value,
+-                               unsigned offset)
+-{
+-      writel(value, csi->base + offset);
+-}
+-
+-/*
+- * Set mclk division ratio for generating test mode mclk. Only used
+- * for test generator.
+- */
+-static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk,
+-                                      u32 ipu_clk)
+-{
+-      u32 temp;
+-      int div_ratio;
+-
+-      div_ratio = (ipu_clk / pixel_clk) - 1;
+-
+-      if (div_ratio > 0xFF || div_ratio < 0) {
+-              dev_err(csi->ipu->dev,
+-                      "value of pixel_clk extends normal range\n");
+-              return -EINVAL;
+-      }
+-
+-      temp = ipu_csi_read(csi, CSI_SENS_CONF);
+-      temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
+-      ipu_csi_write(csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
+-                        CSI_SENS_CONF);
+-
+-      return 0;
+-}
+-
+-/*
+- * Find the CSI data format and data width for the given V4L2 media
+- * bus pixel format code.
+- */
+-static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code,
+-                              enum v4l2_mbus_type mbus_type)
+-{
+-      switch (mbus_code) {
+-      case MEDIA_BUS_FMT_BGR565_2X8_BE:
+-      case MEDIA_BUS_FMT_BGR565_2X8_LE:
+-      case MEDIA_BUS_FMT_RGB565_2X8_BE:
+-      case MEDIA_BUS_FMT_RGB565_2X8_LE:
+-              if (mbus_type == V4L2_MBUS_CSI2_DPHY)
+-                      cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
+-              else
+-                      cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+-              cfg->mipi_dt = MIPI_DT_RGB565;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE:
+-      case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444;
+-              cfg->mipi_dt = MIPI_DT_RGB444;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
+-      case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
+-              cfg->mipi_dt = MIPI_DT_RGB555;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_RGB888_1X24:
+-      case MEDIA_BUS_FMT_BGR888_1X24:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
+-              cfg->mipi_dt = MIPI_DT_RGB888;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_UYVY8_2X8:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
+-              cfg->mipi_dt = MIPI_DT_YUV422;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_YUYV8_2X8:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
+-              cfg->mipi_dt = MIPI_DT_YUV422;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_UYVY8_1X16:
+-      case MEDIA_BUS_FMT_YUYV8_1X16:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+-              cfg->mipi_dt = MIPI_DT_YUV422;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_16;
+-              break;
+-      case MEDIA_BUS_FMT_SBGGR8_1X8:
+-      case MEDIA_BUS_FMT_SGBRG8_1X8:
+-      case MEDIA_BUS_FMT_SGRBG8_1X8:
+-      case MEDIA_BUS_FMT_SRGGB8_1X8:
+-      case MEDIA_BUS_FMT_Y8_1X8:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+-              cfg->mipi_dt = MIPI_DT_RAW8;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8:
+-      case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
+-      case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
+-      case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8:
+-      case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE:
+-      case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE:
+-      case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE:
+-      case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+-              cfg->mipi_dt = MIPI_DT_RAW10;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      case MEDIA_BUS_FMT_SBGGR10_1X10:
+-      case MEDIA_BUS_FMT_SGBRG10_1X10:
+-      case MEDIA_BUS_FMT_SGRBG10_1X10:
+-      case MEDIA_BUS_FMT_SRGGB10_1X10:
+-      case MEDIA_BUS_FMT_Y10_1X10:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+-              cfg->mipi_dt = MIPI_DT_RAW10;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_10;
+-              break;
+-      case MEDIA_BUS_FMT_SBGGR12_1X12:
+-      case MEDIA_BUS_FMT_SGBRG12_1X12:
+-      case MEDIA_BUS_FMT_SGRBG12_1X12:
+-      case MEDIA_BUS_FMT_SRGGB12_1X12:
+-      case MEDIA_BUS_FMT_Y12_1X12:
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+-              cfg->mipi_dt = MIPI_DT_RAW12;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_12;
+-              break;
+-      case MEDIA_BUS_FMT_JPEG_1X8:
+-              /* TODO */
+-              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG;
+-              cfg->mipi_dt = MIPI_DT_RAW8;
+-              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      return 0;
+-}
+-
+-/* translate alternate field mode based on given standard */
+-static inline enum v4l2_field
+-ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
+-{
+-      return (field != V4L2_FIELD_ALTERNATE) ? field :
+-              ((std & V4L2_STD_525_60) ?
+-               V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
+-}
+-
+-/*
+- * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
+- */
+-static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
+-                          const struct v4l2_mbus_config *mbus_cfg,
+-                          const struct v4l2_mbus_framefmt *mbus_fmt)
+-{
+-      int ret;
+-
+-      memset(csicfg, 0, sizeof(*csicfg));
+-
+-      ret = mbus_code_to_bus_cfg(csicfg, mbus_fmt->code, mbus_cfg->type);
+-      if (ret < 0)
+-              return ret;
+-
+-      switch (mbus_cfg->type) {
+-      case V4L2_MBUS_PARALLEL:
+-              csicfg->ext_vsync = 1;
+-              csicfg->vsync_pol = (mbus_cfg->flags &
+-                                   V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0;
+-              csicfg->hsync_pol = (mbus_cfg->flags &
+-                                   V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0;
+-              csicfg->pixclk_pol = (mbus_cfg->flags &
+-                                    V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0;
+-              csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
+-              break;
+-      case V4L2_MBUS_BT656:
+-              csicfg->ext_vsync = 0;
+-              if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field) ||
+-                  mbus_fmt->field == V4L2_FIELD_ALTERNATE)
+-                      csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
+-              else
+-                      csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
+-              break;
+-      case V4L2_MBUS_CSI2_DPHY:
+-              /*
+-               * MIPI CSI-2 requires non gated clock mode, all other
+-               * parameters are not applicable for MIPI CSI-2 bus.
+-               */
+-              csicfg->clk_mode = IPU_CSI_CLK_MODE_NONGATED_CLK;
+-              break;
+-      default:
+-              /* will never get here, keep compiler quiet */
+-              break;
+-      }
+-
+-      return 0;
+-}
+-
+-static int
+-ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
+-                              const struct v4l2_mbus_framefmt *infmt,
+-                              const struct v4l2_mbus_framefmt *outfmt,
+-                              v4l2_std_id std)
+-{
+-      enum v4l2_field infield, outfield;
+-      bool swap_fields;
+-
+-      /* get translated field type of input and output */
+-      infield = ipu_csi_translate_field(infmt->field, std);
+-      outfield = ipu_csi_translate_field(outfmt->field, std);
+-
+-      /*
+-       * Write the H-V-F codes the CSI will match against the
+-       * incoming data for start/end of active and blanking
+-       * field intervals. If input and output field types are
+-       * sequential but not the same (one is SEQ_BT and the other
+-       * is SEQ_TB), swap the F-bit so that the CSI will capture
+-       * field 1 lines before field 0 lines.
+-       */
+-      swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
+-                     V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
+-                     infield != outfield);
+-
+-      if (!swap_fields) {
+-              /*
+-               * Field0BlankEnd  = 110, Field0BlankStart  = 010
+-               * Field0ActiveEnd = 100, Field0ActiveStart = 000
+-               * Field1BlankEnd  = 111, Field1BlankStart  = 011
+-               * Field1ActiveEnd = 101, Field1ActiveStart = 001
+-               */
+-              ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
+-                            CSI_CCIR_CODE_1);
+-              ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+-      } else {
+-              dev_dbg(csi->ipu->dev, "capture field swap\n");
+-
+-              /* same as above but with F-bit inverted */
+-              ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
+-                            CSI_CCIR_CODE_1);
+-              ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+-      }
+-
+-      ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+-
+-      return 0;
+-}
+-
+-
+-int ipu_csi_init_interface(struct ipu_csi *csi,
+-                         const struct v4l2_mbus_config *mbus_cfg,
+-                         const struct v4l2_mbus_framefmt *infmt,
+-                         const struct v4l2_mbus_framefmt *outfmt)
+-{
+-      struct ipu_csi_bus_config cfg;
+-      unsigned long flags;
+-      u32 width, height, data = 0;
+-      v4l2_std_id std;
+-      int ret;
+-
+-      ret = fill_csi_bus_cfg(&cfg, mbus_cfg, infmt);
+-      if (ret < 0)
+-              return ret;
+-
+-      /* set default sensor frame width and height */
+-      width = infmt->width;
+-      height = infmt->height;
+-      if (infmt->field == V4L2_FIELD_ALTERNATE)
+-              height *= 2;
+-
+-      /* Set the CSI_SENS_CONF register remaining fields */
+-      data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
+-              cfg.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
+-              cfg.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
+-              cfg.vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
+-              cfg.hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
+-              cfg.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
+-              cfg.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
+-              cfg.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
+-              cfg.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
+-              cfg.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
+-              cfg.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      ipu_csi_write(csi, data, CSI_SENS_CONF);
+-
+-      /* Set CCIR registers */
+-
+-      switch (cfg.clk_mode) {
+-      case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+-              ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
+-              ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+-              break;
+-      case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+-              if (width == 720 && height == 480) {
+-                      std = V4L2_STD_NTSC;
+-                      height = 525;
+-              } else if (width == 720 && height == 576) {
+-                      std = V4L2_STD_PAL;
+-                      height = 625;
+-              } else {
+-                      dev_err(csi->ipu->dev,
+-                              "Unsupported interlaced video mode\n");
+-                      ret = -EINVAL;
+-                      goto out_unlock;
+-              }
+-
+-              ret = ipu_csi_set_bt_interlaced_codes(csi, infmt, outfmt, std);
+-              if (ret)
+-                      goto out_unlock;
+-              break;
+-      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+-      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+-      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+-      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+-              ipu_csi_write(csi, 0x40030 | CSI_CCIR_ERR_DET_EN,
+-                                 CSI_CCIR_CODE_1);
+-              ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+-              break;
+-      case IPU_CSI_CLK_MODE_GATED_CLK:
+-      case IPU_CSI_CLK_MODE_NONGATED_CLK:
+-              ipu_csi_write(csi, 0, CSI_CCIR_CODE_1);
+-              break;
+-      }
+-
+-      /* Setup sensor frame size */
+-      ipu_csi_write(csi, (width - 1) | ((height - 1) << 16),
+-                    CSI_SENS_FRM_SIZE);
+-
+-      dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
+-              ipu_csi_read(csi, CSI_SENS_CONF));
+-      dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
+-              ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
+-
+-out_unlock:
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_init_interface);
+-
+-bool ipu_csi_is_interlaced(struct ipu_csi *csi)
+-{
+-      unsigned long flags;
+-      u32 sensor_protocol;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-      sensor_protocol =
+-              (ipu_csi_read(csi, CSI_SENS_CONF) &
+-               CSI_SENS_CONF_SENS_PRTCL_MASK) >>
+-              CSI_SENS_CONF_SENS_PRTCL_SHIFT;
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-
+-      switch (sensor_protocol) {
+-      case IPU_CSI_CLK_MODE_GATED_CLK:
+-      case IPU_CSI_CLK_MODE_NONGATED_CLK:
+-      case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+-      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+-      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+-              return false;
+-      case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+-      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+-      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+-              return true;
+-      default:
+-              dev_err(csi->ipu->dev,
+-                      "CSI %d sensor protocol unsupported\n", csi->id);
+-              return false;
+-      }
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_is_interlaced);
+-
+-void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w)
+-{
+-      unsigned long flags;
+-      u32 reg;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE);
+-      w->width = (reg & 0xFFFF) + 1;
+-      w->height = (reg >> 16 & 0xFFFF) + 1;
+-
+-      reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+-      w->left = (reg & CSI_HSC_MASK) >> CSI_HSC_SHIFT;
+-      w->top = (reg & CSI_VSC_MASK) >> CSI_VSC_SHIFT;
+-
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_get_window);
+-
+-void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w)
+-{
+-      unsigned long flags;
+-      u32 reg;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      ipu_csi_write(csi, (w->width - 1) | ((w->height - 1) << 16),
+-                        CSI_ACT_FRM_SIZE);
+-
+-      reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+-      reg &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
+-      reg |= ((w->top << CSI_VSC_SHIFT) | (w->left << CSI_HSC_SHIFT));
+-      ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
+-
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_set_window);
+-
+-void ipu_csi_set_downsize(struct ipu_csi *csi, bool horiz, bool vert)
+-{
+-      unsigned long flags;
+-      u32 reg;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+-      reg &= ~(CSI_HORI_DOWNSIZE_EN | CSI_VERT_DOWNSIZE_EN);
+-      reg |= (horiz ? CSI_HORI_DOWNSIZE_EN : 0) |
+-             (vert ? CSI_VERT_DOWNSIZE_EN : 0);
+-      ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
+-
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_set_downsize);
+-
+-void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
+-                              u32 r_value, u32 g_value, u32 b_value,
+-                              u32 pix_clk)
+-{
+-      unsigned long flags;
+-      u32 ipu_clk = clk_get_rate(csi->clk_ipu);
+-      u32 temp;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      temp = ipu_csi_read(csi, CSI_TST_CTRL);
+-
+-      if (!active) {
+-              temp &= ~CSI_TEST_GEN_MODE_EN;
+-              ipu_csi_write(csi, temp, CSI_TST_CTRL);
+-      } else {
+-              /* Set sensb_mclk div_ratio */
+-              ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk);
+-
+-              temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
+-                        CSI_TEST_GEN_B_MASK);
+-              temp |= CSI_TEST_GEN_MODE_EN;
+-              temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
+-                      (g_value << CSI_TEST_GEN_G_SHIFT) |
+-                      (b_value << CSI_TEST_GEN_B_SHIFT);
+-              ipu_csi_write(csi, temp, CSI_TST_CTRL);
+-      }
+-
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator);
+-
+-int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
+-                            struct v4l2_mbus_framefmt *mbus_fmt)
+-{
+-      struct ipu_csi_bus_config cfg;
+-      unsigned long flags;
+-      u32 temp;
+-      int ret;
+-
+-      if (vc > 3)
+-              return -EINVAL;
+-
+-      ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code, V4L2_MBUS_CSI2_DPHY);
+-      if (ret < 0)
+-              return ret;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      temp = ipu_csi_read(csi, CSI_MIPI_DI);
+-      temp &= ~(0xff << (vc * 8));
+-      temp |= (cfg.mipi_dt << (vc * 8));
+-      ipu_csi_write(csi, temp, CSI_MIPI_DI);
+-
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype);
+-
+-int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
+-                        u32 max_ratio, u32 id)
+-{
+-      unsigned long flags;
+-      u32 temp;
+-
+-      if (max_ratio > 5 || id > 3)
+-              return -EINVAL;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      temp = ipu_csi_read(csi, CSI_SKIP);
+-      temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
+-                CSI_SKIP_SMFC_MASK);
+-      temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
+-              (id << CSI_ID_2_SKIP_SHIFT) |
+-              (skip << CSI_SKIP_SMFC_SHIFT);
+-      ipu_csi_write(csi, temp, CSI_SKIP);
+-
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc);
+-
+-int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest)
+-{
+-      unsigned long flags;
+-      u32 csi_sens_conf, dest;
+-
+-      if (csi_dest == IPU_CSI_DEST_IDMAC)
+-              dest = CSI_DATA_DEST_IDMAC;
+-      else
+-              dest = CSI_DATA_DEST_IC; /* IC or VDIC */
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF);
+-      csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
+-      csi_sens_conf |= (dest << CSI_SENS_CONF_DATA_DEST_SHIFT);
+-      ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF);
+-
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_set_dest);
+-
+-int ipu_csi_enable(struct ipu_csi *csi)
+-{
+-      ipu_module_enable(csi->ipu, csi->module);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_enable);
+-
+-int ipu_csi_disable(struct ipu_csi *csi)
+-{
+-      ipu_module_disable(csi->ipu, csi->module);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_disable);
+-
+-struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id)
+-{
+-      unsigned long flags;
+-      struct ipu_csi *csi, *ret;
+-
+-      if (id > 1)
+-              return ERR_PTR(-EINVAL);
+-
+-      csi = ipu->csi_priv[id];
+-      ret = csi;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-
+-      if (csi->inuse) {
+-              ret = ERR_PTR(-EBUSY);
+-              goto unlock;
+-      }
+-
+-      csi->inuse = true;
+-unlock:
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_get);
+-
+-void ipu_csi_put(struct ipu_csi *csi)
+-{
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&csi->lock, flags);
+-      csi->inuse = false;
+-      spin_unlock_irqrestore(&csi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_put);
+-
+-int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
+-               unsigned long base, u32 module, struct clk *clk_ipu)
+-{
+-      struct ipu_csi *csi;
+-
+-      if (id > 1)
+-              return -ENODEV;
+-
+-      csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL);
+-      if (!csi)
+-              return -ENOMEM;
+-
+-      ipu->csi_priv[id] = csi;
+-
+-      spin_lock_init(&csi->lock);
+-      csi->module = module;
+-      csi->id = id;
+-      csi->clk_ipu = clk_ipu;
+-      csi->base = devm_ioremap(dev, base, PAGE_SIZE);
+-      if (!csi->base)
+-              return -ENOMEM;
+-
+-      dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n",
+-              id, base, csi->base);
+-      csi->ipu = ipu;
+-
+-      return 0;
+-}
+-
+-void ipu_csi_exit(struct ipu_soc *ipu, int id)
+-{
+-}
+-
+-void ipu_csi_dump(struct ipu_csi *csi)
+-{
+-      dev_dbg(csi->ipu->dev, "CSI_SENS_CONF:     %08x\n",
+-              ipu_csi_read(csi, CSI_SENS_CONF));
+-      dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n",
+-              ipu_csi_read(csi, CSI_SENS_FRM_SIZE));
+-      dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE:  %08x\n",
+-              ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
+-      dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL:  %08x\n",
+-              ipu_csi_read(csi, CSI_OUT_FRM_CTRL));
+-      dev_dbg(csi->ipu->dev, "CSI_TST_CTRL:      %08x\n",
+-              ipu_csi_read(csi, CSI_TST_CTRL));
+-      dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1:   %08x\n",
+-              ipu_csi_read(csi, CSI_CCIR_CODE_1));
+-      dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2:   %08x\n",
+-              ipu_csi_read(csi, CSI_CCIR_CODE_2));
+-      dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3:   %08x\n",
+-              ipu_csi_read(csi, CSI_CCIR_CODE_3));
+-      dev_dbg(csi->ipu->dev, "CSI_MIPI_DI:       %08x\n",
+-              ipu_csi_read(csi, CSI_MIPI_DI));
+-      dev_dbg(csi->ipu->dev, "CSI_SKIP:          %08x\n",
+-              ipu_csi_read(csi, CSI_SKIP));
+-}
+-EXPORT_SYMBOL_GPL(ipu_csi_dump);
+--- a/drivers/gpu/imx/ipu-v3/ipu-dc.c
++++ /dev/null
+@@ -1,420 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-
+-#include <linux/export.h>
+-#include <linux/module.h>
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/io.h>
+-
+-#include <video/imx-ipu-v3.h>
+-#include "ipu-prv.h"
+-
+-#define DC_MAP_CONF_PTR(n)    (0x108 + ((n) & ~0x1) * 2)
+-#define DC_MAP_CONF_VAL(n)    (0x144 + ((n) & ~0x1) * 2)
+-
+-#define DC_EVT_NF             0
+-#define DC_EVT_NL             1
+-#define DC_EVT_EOF            2
+-#define DC_EVT_NFIELD         3
+-#define DC_EVT_EOL            4
+-#define DC_EVT_EOFIELD                5
+-#define DC_EVT_NEW_ADDR               6
+-#define DC_EVT_NEW_CHAN               7
+-#define DC_EVT_NEW_DATA               8
+-
+-#define DC_EVT_NEW_ADDR_W_0   0
+-#define DC_EVT_NEW_ADDR_W_1   1
+-#define DC_EVT_NEW_CHAN_W_0   2
+-#define DC_EVT_NEW_CHAN_W_1   3
+-#define DC_EVT_NEW_DATA_W_0   4
+-#define DC_EVT_NEW_DATA_W_1   5
+-#define DC_EVT_NEW_ADDR_R_0   6
+-#define DC_EVT_NEW_ADDR_R_1   7
+-#define DC_EVT_NEW_CHAN_R_0   8
+-#define DC_EVT_NEW_CHAN_R_1   9
+-#define DC_EVT_NEW_DATA_R_0   10
+-#define DC_EVT_NEW_DATA_R_1   11
+-
+-#define DC_WR_CH_CONF         0x0
+-#define DC_WR_CH_ADDR         0x4
+-#define DC_RL_CH(evt)         (8 + ((evt) & ~0x1) * 2)
+-
+-#define DC_GEN                        0xd4
+-#define DC_DISP_CONF1(disp)   (0xd8 + (disp) * 4)
+-#define DC_DISP_CONF2(disp)   (0xe8 + (disp) * 4)
+-#define DC_STAT                       0x1c8
+-
+-#define WROD(lf)              (0x18 | ((lf) << 1))
+-#define WRG                   0x01
+-#define WCLK                  0xc9
+-
+-#define SYNC_WAVE 0
+-#define NULL_WAVE (-1)
+-
+-#define DC_GEN_SYNC_1_6_SYNC  (2 << 1)
+-#define DC_GEN_SYNC_PRIORITY_1        (1 << 7)
+-
+-#define DC_WR_CH_CONF_WORD_SIZE_8             (0 << 0)
+-#define DC_WR_CH_CONF_WORD_SIZE_16            (1 << 0)
+-#define DC_WR_CH_CONF_WORD_SIZE_24            (2 << 0)
+-#define DC_WR_CH_CONF_WORD_SIZE_32            (3 << 0)
+-#define DC_WR_CH_CONF_DISP_ID_PARALLEL(i)     (((i) & 0x1) << 3)
+-#define DC_WR_CH_CONF_DISP_ID_SERIAL          (2 << 3)
+-#define DC_WR_CH_CONF_DISP_ID_ASYNC           (3 << 4)
+-#define DC_WR_CH_CONF_FIELD_MODE              (1 << 9)
+-#define DC_WR_CH_CONF_PROG_TYPE_NORMAL                (4 << 5)
+-#define DC_WR_CH_CONF_PROG_TYPE_MASK          (7 << 5)
+-#define DC_WR_CH_CONF_PROG_DI_ID              (1 << 2)
+-#define DC_WR_CH_CONF_PROG_DISP_ID(i)         (((i) & 0x1) << 3)
+-
+-#define IPU_DC_NUM_CHANNELS   10
+-
+-struct ipu_dc_priv;
+-
+-enum ipu_dc_map {
+-      IPU_DC_MAP_RGB24,
+-      IPU_DC_MAP_RGB565,
+-      IPU_DC_MAP_GBR24, /* TVEv2 */
+-      IPU_DC_MAP_BGR666,
+-      IPU_DC_MAP_LVDS666,
+-      IPU_DC_MAP_BGR24,
+-};
+-
+-struct ipu_dc {
+-      /* The display interface number assigned to this dc channel */
+-      unsigned int            di;
+-      void __iomem            *base;
+-      struct ipu_dc_priv      *priv;
+-      int                     chno;
+-      bool                    in_use;
+-};
+-
+-struct ipu_dc_priv {
+-      void __iomem            *dc_reg;
+-      void __iomem            *dc_tmpl_reg;
+-      struct ipu_soc          *ipu;
+-      struct device           *dev;
+-      struct ipu_dc           channels[IPU_DC_NUM_CHANNELS];
+-      struct mutex            mutex;
+-      struct completion       comp;
+-      int                     use_count;
+-};
+-
+-static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
+-{
+-      u32 reg;
+-
+-      reg = readl(dc->base + DC_RL_CH(event));
+-      reg &= ~(0xffff << (16 * (event & 0x1)));
+-      reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
+-      writel(reg, dc->base + DC_RL_CH(event));
+-}
+-
+-static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
+-              int map, int wave, int glue, int sync, int stop)
+-{
+-      struct ipu_dc_priv *priv = dc->priv;
+-      u32 reg1, reg2;
+-
+-      if (opcode == WCLK) {
+-              reg1 = (operand << 20) & 0xfff00000;
+-              reg2 = operand >> 12 | opcode << 1 | stop << 9;
+-      } else if (opcode == WRG) {
+-              reg1 = sync | glue << 4 | ++wave << 11 | ((operand << 15) & 0xffff8000);
+-              reg2 = operand >> 17 | opcode << 7 | stop << 9;
+-      } else {
+-              reg1 = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000);
+-              reg2 = operand >> 12 | opcode << 4 | stop << 9;
+-      }
+-      writel(reg1, priv->dc_tmpl_reg + word * 8);
+-      writel(reg2, priv->dc_tmpl_reg + word * 8 + 4);
+-}
+-
+-static int ipu_bus_format_to_map(u32 fmt)
+-{
+-      switch (fmt) {
+-      default:
+-              WARN_ON(1);
+-              /* fall-through */
+-      case MEDIA_BUS_FMT_RGB888_1X24:
+-              return IPU_DC_MAP_RGB24;
+-      case MEDIA_BUS_FMT_RGB565_1X16:
+-              return IPU_DC_MAP_RGB565;
+-      case MEDIA_BUS_FMT_GBR888_1X24:
+-              return IPU_DC_MAP_GBR24;
+-      case MEDIA_BUS_FMT_RGB666_1X18:
+-              return IPU_DC_MAP_BGR666;
+-      case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+-              return IPU_DC_MAP_LVDS666;
+-      case MEDIA_BUS_FMT_BGR888_1X24:
+-              return IPU_DC_MAP_BGR24;
+-      }
+-}
+-
+-int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
+-              u32 bus_format, u32 width)
+-{
+-      struct ipu_dc_priv *priv = dc->priv;
+-      int addr, sync;
+-      u32 reg = 0;
+-      int map;
+-
+-      dc->di = ipu_di_get_num(di);
+-
+-      map = ipu_bus_format_to_map(bus_format);
+-
+-      /*
+-       * In interlaced mode we need more counters to create the asymmetric
+-       * per-field VSYNC signals. The pixel active signal synchronising DC
+-       * to DI moves to signal generator #6 (see ipu-di.c). In progressive
+-       * mode counter #5 is used.
+-       */
+-      sync = interlaced ? 6 : 5;
+-
+-      /* Reserve 5 microcode template words for each DI */
+-      if (dc->di)
+-              addr = 5;
+-      else
+-              addr = 0;
+-
+-      if (interlaced) {
+-              dc_link_event(dc, DC_EVT_NL, addr, 3);
+-              dc_link_event(dc, DC_EVT_EOL, addr, 2);
+-              dc_link_event(dc, DC_EVT_NEW_DATA, addr, 1);
+-
+-              /* Init template microcode */
+-              dc_write_tmpl(dc, addr, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
+-      } else {
+-              dc_link_event(dc, DC_EVT_NL, addr + 2, 3);
+-              dc_link_event(dc, DC_EVT_EOL, addr + 3, 2);
+-              dc_link_event(dc, DC_EVT_NEW_DATA, addr + 1, 1);
+-
+-              /* Init template microcode */
+-              dc_write_tmpl(dc, addr + 2, WROD(0), 0, map, SYNC_WAVE, 8, sync, 1);
+-              dc_write_tmpl(dc, addr + 3, WROD(0), 0, map, SYNC_WAVE, 4, sync, 0);
+-              dc_write_tmpl(dc, addr + 4, WRG, 0, map, NULL_WAVE, 0, 0, 1);
+-              dc_write_tmpl(dc, addr + 1, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
+-      }
+-
+-      dc_link_event(dc, DC_EVT_NF, 0, 0);
+-      dc_link_event(dc, DC_EVT_NFIELD, 0, 0);
+-      dc_link_event(dc, DC_EVT_EOF, 0, 0);
+-      dc_link_event(dc, DC_EVT_EOFIELD, 0, 0);
+-      dc_link_event(dc, DC_EVT_NEW_CHAN, 0, 0);
+-      dc_link_event(dc, DC_EVT_NEW_ADDR, 0, 0);
+-
+-      reg = readl(dc->base + DC_WR_CH_CONF);
+-      if (interlaced)
+-              reg |= DC_WR_CH_CONF_FIELD_MODE;
+-      else
+-              reg &= ~DC_WR_CH_CONF_FIELD_MODE;
+-      writel(reg, dc->base + DC_WR_CH_CONF);
+-
+-      writel(0x0, dc->base + DC_WR_CH_ADDR);
+-      writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
+-
+-void ipu_dc_enable(struct ipu_soc *ipu)
+-{
+-      struct ipu_dc_priv *priv = ipu->dc_priv;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      if (!priv->use_count)
+-              ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
+-
+-      priv->use_count++;
+-
+-      mutex_unlock(&priv->mutex);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dc_enable);
+-
+-void ipu_dc_enable_channel(struct ipu_dc *dc)
+-{
+-      u32 reg;
+-
+-      reg = readl(dc->base + DC_WR_CH_CONF);
+-      reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL;
+-      writel(reg, dc->base + DC_WR_CH_CONF);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
+-
+-void ipu_dc_disable_channel(struct ipu_dc *dc)
+-{
+-      u32 val;
+-
+-      val = readl(dc->base + DC_WR_CH_CONF);
+-      val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+-      writel(val, dc->base + DC_WR_CH_CONF);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
+-
+-void ipu_dc_disable(struct ipu_soc *ipu)
+-{
+-      struct ipu_dc_priv *priv = ipu->dc_priv;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      priv->use_count--;
+-      if (!priv->use_count)
+-              ipu_module_disable(priv->ipu, IPU_CONF_DC_EN);
+-
+-      if (priv->use_count < 0)
+-              priv->use_count = 0;
+-
+-      mutex_unlock(&priv->mutex);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dc_disable);
+-
+-static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
+-              int byte_num, int offset, int mask)
+-{
+-      int ptr = map * 3 + byte_num;
+-      u32 reg;
+-
+-      reg = readl(priv->dc_reg + DC_MAP_CONF_VAL(ptr));
+-      reg &= ~(0xffff << (16 * (ptr & 0x1)));
+-      reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
+-      writel(reg, priv->dc_reg + DC_MAP_CONF_VAL(ptr));
+-
+-      reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
+-      reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
+-      reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
+-      writel(reg, priv->dc_reg + DC_MAP_CONF_PTR(map));
+-}
+-
+-static void ipu_dc_map_clear(struct ipu_dc_priv *priv, int map)
+-{
+-      u32 reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
+-
+-      writel(reg & ~(0xffff << (16 * (map & 0x1))),
+-                   priv->dc_reg + DC_MAP_CONF_PTR(map));
+-}
+-
+-struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel)
+-{
+-      struct ipu_dc_priv *priv = ipu->dc_priv;
+-      struct ipu_dc *dc;
+-
+-      if (channel >= IPU_DC_NUM_CHANNELS)
+-              return ERR_PTR(-ENODEV);
+-
+-      dc = &priv->channels[channel];
+-
+-      mutex_lock(&priv->mutex);
+-
+-      if (dc->in_use) {
+-              mutex_unlock(&priv->mutex);
+-              return ERR_PTR(-EBUSY);
+-      }
+-
+-      dc->in_use = true;
+-
+-      mutex_unlock(&priv->mutex);
+-
+-      return dc;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dc_get);
+-
+-void ipu_dc_put(struct ipu_dc *dc)
+-{
+-      struct ipu_dc_priv *priv = dc->priv;
+-
+-      mutex_lock(&priv->mutex);
+-      dc->in_use = false;
+-      mutex_unlock(&priv->mutex);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dc_put);
+-
+-int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
+-              unsigned long base, unsigned long template_base)
+-{
+-      struct ipu_dc_priv *priv;
+-      static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
+-              0x78, 0, 0x94, 0xb4};
+-      int i;
+-
+-      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-      if (!priv)
+-              return -ENOMEM;
+-
+-      mutex_init(&priv->mutex);
+-
+-      priv->dev = dev;
+-      priv->ipu = ipu;
+-      priv->dc_reg = devm_ioremap(dev, base, PAGE_SIZE);
+-      priv->dc_tmpl_reg = devm_ioremap(dev, template_base, PAGE_SIZE);
+-      if (!priv->dc_reg || !priv->dc_tmpl_reg)
+-              return -ENOMEM;
+-
+-      for (i = 0; i < IPU_DC_NUM_CHANNELS; i++) {
+-              priv->channels[i].chno = i;
+-              priv->channels[i].priv = priv;
+-              priv->channels[i].base = priv->dc_reg + channel_offsets[i];
+-      }
+-
+-      writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
+-                      DC_WR_CH_CONF_PROG_DI_ID,
+-                      priv->channels[1].base + DC_WR_CH_CONF);
+-      writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0),
+-                      priv->channels[5].base + DC_WR_CH_CONF);
+-
+-      writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1,
+-              priv->dc_reg + DC_GEN);
+-
+-      ipu->dc_priv = priv;
+-
+-      dev_dbg(dev, "DC base: 0x%08lx template base: 0x%08lx\n",
+-                      base, template_base);
+-
+-      /* rgb24 */
+-      ipu_dc_map_clear(priv, IPU_DC_MAP_RGB24);
+-      ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 0, 7, 0xff); /* blue */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 1, 15, 0xff); /* green */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 2, 23, 0xff); /* red */
+-
+-      /* rgb565 */
+-      ipu_dc_map_clear(priv, IPU_DC_MAP_RGB565);
+-      ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 0, 4, 0xf8); /* blue */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc); /* green */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8); /* red */
+-
+-      /* gbr24 */
+-      ipu_dc_map_clear(priv, IPU_DC_MAP_GBR24);
+-      ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 2, 15, 0xff); /* green */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 1, 7, 0xff); /* blue */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 0, 23, 0xff); /* red */
+-
+-      /* bgr666 */
+-      ipu_dc_map_clear(priv, IPU_DC_MAP_BGR666);
+-      ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 0, 5, 0xfc); /* blue */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc); /* green */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc); /* red */
+-
+-      /* lvds666 */
+-      ipu_dc_map_clear(priv, IPU_DC_MAP_LVDS666);
+-      ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 0, 5, 0xfc); /* blue */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 1, 13, 0xfc); /* green */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 2, 21, 0xfc); /* red */
+-
+-      /* bgr24 */
+-      ipu_dc_map_clear(priv, IPU_DC_MAP_BGR24);
+-      ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 2, 7, 0xff); /* red */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */
+-      ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */
+-
+-      return 0;
+-}
+-
+-void ipu_dc_exit(struct ipu_soc *ipu)
+-{
+-}
+--- a/drivers/gpu/imx/ipu-v3/ipu-di.c
++++ /dev/null
+@@ -1,745 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-#include <linux/export.h>
+-#include <linux/module.h>
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/io.h>
+-#include <linux/err.h>
+-#include <linux/platform_device.h>
+-
+-#include <video/imx-ipu-v3.h>
+-#include "ipu-prv.h"
+-
+-struct ipu_di {
+-      void __iomem *base;
+-      int id;
+-      u32 module;
+-      struct clk *clk_di;     /* display input clock */
+-      struct clk *clk_ipu;    /* IPU bus clock */
+-      struct clk *clk_di_pixel; /* resulting pixel clock */
+-      bool inuse;
+-      struct ipu_soc *ipu;
+-};
+-
+-static DEFINE_MUTEX(di_mutex);
+-
+-struct di_sync_config {
+-      int run_count;
+-      int run_src;
+-      int offset_count;
+-      int offset_src;
+-      int repeat_count;
+-      int cnt_clr_src;
+-      int cnt_polarity_gen_en;
+-      int cnt_polarity_clr_src;
+-      int cnt_polarity_trigger_src;
+-      int cnt_up;
+-      int cnt_down;
+-};
+-
+-enum di_pins {
+-      DI_PIN11 = 0,
+-      DI_PIN12 = 1,
+-      DI_PIN13 = 2,
+-      DI_PIN14 = 3,
+-      DI_PIN15 = 4,
+-      DI_PIN16 = 5,
+-      DI_PIN17 = 6,
+-      DI_PIN_CS = 7,
+-
+-      DI_PIN_SER_CLK = 0,
+-      DI_PIN_SER_RS = 1,
+-};
+-
+-enum di_sync_wave {
+-      DI_SYNC_NONE = 0,
+-      DI_SYNC_CLK = 1,
+-      DI_SYNC_INT_HSYNC = 2,
+-      DI_SYNC_HSYNC = 3,
+-      DI_SYNC_VSYNC = 4,
+-      DI_SYNC_DE = 6,
+-
+-      DI_SYNC_CNT1 = 2,       /* counter >= 2 only */
+-      DI_SYNC_CNT4 = 5,       /* counter >= 5 only */
+-      DI_SYNC_CNT5 = 6,       /* counter >= 6 only */
+-};
+-
+-#define SYNC_WAVE 0
+-
+-#define DI_GENERAL            0x0000
+-#define DI_BS_CLKGEN0         0x0004
+-#define DI_BS_CLKGEN1         0x0008
+-#define DI_SW_GEN0(gen)               (0x000c + 4 * ((gen) - 1))
+-#define DI_SW_GEN1(gen)               (0x0030 + 4 * ((gen) - 1))
+-#define DI_STP_REP(gen)               (0x0148 + 4 * (((gen) - 1)/2))
+-#define DI_SYNC_AS_GEN                0x0054
+-#define DI_DW_GEN(gen)                (0x0058 + 4 * (gen))
+-#define DI_DW_SET(gen, set)   (0x0088 + 4 * ((gen) + 0xc * (set)))
+-#define DI_SER_CONF           0x015c
+-#define DI_SSC                        0x0160
+-#define DI_POL                        0x0164
+-#define DI_AW0                        0x0168
+-#define DI_AW1                        0x016c
+-#define DI_SCR_CONF           0x0170
+-#define DI_STAT                       0x0174
+-
+-#define DI_SW_GEN0_RUN_COUNT(x)                       ((x) << 19)
+-#define DI_SW_GEN0_RUN_SRC(x)                 ((x) << 16)
+-#define DI_SW_GEN0_OFFSET_COUNT(x)            ((x) << 3)
+-#define DI_SW_GEN0_OFFSET_SRC(x)              ((x) << 0)
+-
+-#define DI_SW_GEN1_CNT_POL_GEN_EN(x)          ((x) << 29)
+-#define DI_SW_GEN1_CNT_CLR_SRC(x)             ((x) << 25)
+-#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x)     ((x) << 12)
+-#define DI_SW_GEN1_CNT_POL_CLR_SRC(x)         ((x) << 9)
+-#define DI_SW_GEN1_CNT_DOWN(x)                        ((x) << 16)
+-#define DI_SW_GEN1_CNT_UP(x)                  (x)
+-#define DI_SW_GEN1_AUTO_RELOAD                        (0x10000000)
+-
+-#define DI_DW_GEN_ACCESS_SIZE_OFFSET          24
+-#define DI_DW_GEN_COMPONENT_SIZE_OFFSET               16
+-
+-#define DI_GEN_POLARITY_1                     (1 << 0)
+-#define DI_GEN_POLARITY_2                     (1 << 1)
+-#define DI_GEN_POLARITY_3                     (1 << 2)
+-#define DI_GEN_POLARITY_4                     (1 << 3)
+-#define DI_GEN_POLARITY_5                     (1 << 4)
+-#define DI_GEN_POLARITY_6                     (1 << 5)
+-#define DI_GEN_POLARITY_7                     (1 << 6)
+-#define DI_GEN_POLARITY_8                     (1 << 7)
+-#define DI_GEN_POLARITY_DISP_CLK              (1 << 17)
+-#define DI_GEN_DI_CLK_EXT                     (1 << 20)
+-#define DI_GEN_DI_VSYNC_EXT                   (1 << 21)
+-
+-#define DI_POL_DRDY_DATA_POLARITY             (1 << 7)
+-#define DI_POL_DRDY_POLARITY_15                       (1 << 4)
+-
+-#define DI_VSYNC_SEL_OFFSET                   13
+-
+-static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
+-{
+-      return readl(di->base + offset);
+-}
+-
+-static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
+-{
+-      writel(value, di->base + offset);
+-}
+-
+-static void ipu_di_data_wave_config(struct ipu_di *di,
+-                                   int wave_gen,
+-                                   int access_size, int component_size)
+-{
+-      u32 reg;
+-      reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
+-          (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
+-      ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+-}
+-
+-static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin,
+-              int set, int up, int down)
+-{
+-      u32 reg;
+-
+-      reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
+-      reg &= ~(0x3 << (di_pin * 2));
+-      reg |= set << (di_pin * 2);
+-      ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+-
+-      ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
+-}
+-
+-static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config,
+-              int start, int count)
+-{
+-      u32 reg;
+-      int i;
+-
+-      for (i = 0; i < count; i++) {
+-              struct di_sync_config *c = &config[i];
+-              int wave_gen = start + i + 1;
+-
+-              if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) ||
+-                              (c->repeat_count >= 0x1000) ||
+-                              (c->cnt_up >= 0x400) ||
+-                              (c->cnt_down >= 0x400)) {
+-                      dev_err(di->ipu->dev, "DI%d counters out of range.\n",
+-                                      di->id);
+-                      return;
+-              }
+-
+-              reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
+-                      DI_SW_GEN0_RUN_SRC(c->run_src) |
+-                      DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
+-                      DI_SW_GEN0_OFFSET_SRC(c->offset_src);
+-              ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
+-
+-              reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
+-                      DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
+-                      DI_SW_GEN1_CNT_POL_TRIGGER_SRC(
+-                                      c->cnt_polarity_trigger_src) |
+-                      DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
+-                      DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
+-                      DI_SW_GEN1_CNT_UP(c->cnt_up);
+-
+-              /* Enable auto reload */
+-              if (c->repeat_count == 0)
+-                      reg |= DI_SW_GEN1_AUTO_RELOAD;
+-
+-              ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
+-
+-              reg = ipu_di_read(di, DI_STP_REP(wave_gen));
+-              reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
+-              reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
+-              ipu_di_write(di, reg, DI_STP_REP(wave_gen));
+-      }
+-}
+-
+-static void ipu_di_sync_config_interlaced(struct ipu_di *di,
+-              struct ipu_di_signal_cfg *sig)
+-{
+-      u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
+-              sig->mode.hback_porch + sig->mode.hfront_porch;
+-      u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
+-              sig->mode.vback_porch + sig->mode.vfront_porch;
+-      struct di_sync_config cfg[] = {
+-              {
+-                      /* 1: internal VSYNC for each frame */
+-                      .run_count = v_total * 2 - 1,
+-                      .run_src = 3,                   /* == counter 7 */
+-              }, {
+-                      /* PIN2: HSYNC waveform */
+-                      .run_count = h_total - 1,
+-                      .run_src = DI_SYNC_CLK,
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
+-                      .cnt_down = sig->mode.hsync_len * 2,
+-              }, {
+-                      /* PIN3: VSYNC waveform */
+-                      .run_count = v_total - 1,
+-                      .run_src = 4,                   /* == counter 7 */
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = 4,  /* == counter 7 */
+-                      .cnt_down = sig->mode.vsync_len * 2,
+-                      .cnt_clr_src = DI_SYNC_CNT1,
+-              }, {
+-                      /* 4: Field */
+-                      .run_count = v_total / 2,
+-                      .run_src = DI_SYNC_HSYNC,
+-                      .offset_count = h_total / 2,
+-                      .offset_src = DI_SYNC_CLK,
+-                      .repeat_count = 2,
+-                      .cnt_clr_src = DI_SYNC_CNT1,
+-              }, {
+-                      /* 5: Active lines */
+-                      .run_src = DI_SYNC_HSYNC,
+-                      .offset_count = (sig->mode.vsync_len +
+-                                       sig->mode.vback_porch) / 2,
+-                      .offset_src = DI_SYNC_HSYNC,
+-                      .repeat_count = sig->mode.vactive / 2,
+-                      .cnt_clr_src = DI_SYNC_CNT4,
+-              }, {
+-                      /* 6: Active pixel, referenced by DC */
+-                      .run_src = DI_SYNC_CLK,
+-                      .offset_count = sig->mode.hsync_len +
+-                                      sig->mode.hback_porch,
+-                      .offset_src = DI_SYNC_CLK,
+-                      .repeat_count = sig->mode.hactive,
+-                      .cnt_clr_src = DI_SYNC_CNT5,
+-              }, {
+-                      /* 7: Half line HSYNC */
+-                      .run_count = h_total / 2 - 1,
+-                      .run_src = DI_SYNC_CLK,
+-              }
+-      };
+-
+-      ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
+-
+-      ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
+-}
+-
+-static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
+-              struct ipu_di_signal_cfg *sig, int div)
+-{
+-      u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
+-              sig->mode.hback_porch + sig->mode.hfront_porch;
+-      u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
+-              sig->mode.vback_porch + sig->mode.vfront_porch;
+-      struct di_sync_config cfg[] = {
+-              {
+-                      /* 1: INT_HSYNC */
+-                      .run_count = h_total - 1,
+-                      .run_src = DI_SYNC_CLK,
+-              } , {
+-                      /* PIN2: HSYNC */
+-                      .run_count = h_total - 1,
+-                      .run_src = DI_SYNC_CLK,
+-                      .offset_count = div * sig->v_to_h_sync,
+-                      .offset_src = DI_SYNC_CLK,
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
+-                      .cnt_down = sig->mode.hsync_len * 2,
+-              } , {
+-                      /* PIN3: VSYNC */
+-                      .run_count = v_total - 1,
+-                      .run_src = DI_SYNC_INT_HSYNC,
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+-                      .cnt_down = sig->mode.vsync_len * 2,
+-              } , {
+-                      /* 4: Line Active */
+-                      .run_src = DI_SYNC_HSYNC,
+-                      .offset_count = sig->mode.vsync_len +
+-                                      sig->mode.vback_porch,
+-                      .offset_src = DI_SYNC_HSYNC,
+-                      .repeat_count = sig->mode.vactive,
+-                      .cnt_clr_src = DI_SYNC_VSYNC,
+-              } , {
+-                      /* 5: Pixel Active, referenced by DC */
+-                      .run_src = DI_SYNC_CLK,
+-                      .offset_count = sig->mode.hsync_len +
+-                                      sig->mode.hback_porch,
+-                      .offset_src = DI_SYNC_CLK,
+-                      .repeat_count = sig->mode.hactive,
+-                      .cnt_clr_src = 5, /* Line Active */
+-              } , {
+-                      /* unused */
+-              } , {
+-                      /* unused */
+-              } , {
+-                      /* unused */
+-              } , {
+-                      /* unused */
+-              },
+-      };
+-      /* can't use #7 and #8 for line active and pixel active counters */
+-      struct di_sync_config cfg_vga[] = {
+-              {
+-                      /* 1: INT_HSYNC */
+-                      .run_count = h_total - 1,
+-                      .run_src = DI_SYNC_CLK,
+-              } , {
+-                      /* 2: VSYNC */
+-                      .run_count = v_total - 1,
+-                      .run_src = DI_SYNC_INT_HSYNC,
+-              } , {
+-                      /* 3: Line Active */
+-                      .run_src = DI_SYNC_INT_HSYNC,
+-                      .offset_count = sig->mode.vsync_len +
+-                                      sig->mode.vback_porch,
+-                      .offset_src = DI_SYNC_INT_HSYNC,
+-                      .repeat_count = sig->mode.vactive,
+-                      .cnt_clr_src = 3 /* VSYNC */,
+-              } , {
+-                      /* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
+-                      .run_count = h_total - 1,
+-                      .run_src = DI_SYNC_CLK,
+-                      .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
+-                      .offset_src = DI_SYNC_CLK,
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
+-                      .cnt_down = sig->mode.hsync_len * 2,
+-              } , {
+-                      /* 5: Pixel Active signal to DC */
+-                      .run_src = DI_SYNC_CLK,
+-                      .offset_count = sig->mode.hsync_len +
+-                                      sig->mode.hback_porch,
+-                      .offset_src = DI_SYNC_CLK,
+-                      .repeat_count = sig->mode.hactive,
+-                      .cnt_clr_src = 4, /* Line Active */
+-              } , {
+-                      /* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
+-                      .run_count = v_total - 1,
+-                      .run_src = DI_SYNC_INT_HSYNC,
+-                      .offset_count = 1, /* magic value from Freescale TVE driver */
+-                      .offset_src = DI_SYNC_INT_HSYNC,
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+-                      .cnt_down = sig->mode.vsync_len * 2,
+-              } , {
+-                      /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
+-                      .run_count = h_total - 1,
+-                      .run_src = DI_SYNC_CLK,
+-                      .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
+-                      .offset_src = DI_SYNC_CLK,
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
+-                      .cnt_down = sig->mode.hsync_len * 2,
+-              } , {
+-                      /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
+-                      .run_count = v_total - 1,
+-                      .run_src = DI_SYNC_INT_HSYNC,
+-                      .offset_count = 1, /* magic value from Freescale TVE driver */
+-                      .offset_src = DI_SYNC_INT_HSYNC,
+-                      .cnt_polarity_gen_en = 1,
+-                      .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+-                      .cnt_down = sig->mode.vsync_len * 2,
+-              } , {
+-                      /* unused */
+-              },
+-      };
+-
+-      ipu_di_write(di, v_total - 1, DI_SCR_CONF);
+-      if (sig->hsync_pin == 2 && sig->vsync_pin == 3)
+-              ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
+-      else
+-              ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
+-}
+-
+-static void ipu_di_config_clock(struct ipu_di *di,
+-      const struct ipu_di_signal_cfg *sig)
+-{
+-      struct clk *clk;
+-      unsigned clkgen0;
+-      uint32_t val;
+-
+-      if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
+-              /*
+-               * CLKMODE_EXT means we must use the DI clock: this is
+-               * needed for things like LVDS which needs to feed the
+-               * DI and LDB with the same pixel clock.
+-               */
+-              clk = di->clk_di;
+-
+-              if (sig->clkflags & IPU_DI_CLKMODE_SYNC) {
+-                      /*
+-                       * CLKMODE_SYNC means that we want the DI to be
+-                       * clocked at the same rate as the parent clock.
+-                       * This is needed (eg) for LDB which needs to be
+-                       * fed with the same pixel clock.  We assume that
+-                       * the LDB clock has already been set correctly.
+-                       */
+-                      clkgen0 = 1 << 4;
+-              } else {
+-                      /*
+-                       * We can use the divider.  We should really have
+-                       * a flag here indicating whether the bridge can
+-                       * cope with a fractional divider or not.  For the
+-                       * time being, let's go for simplicitly and
+-                       * reliability.
+-                       */
+-                      unsigned long in_rate;
+-                      unsigned div;
+-
+-                      clk_set_rate(clk, sig->mode.pixelclock);
+-
+-                      in_rate = clk_get_rate(clk);
+-                      div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
+-                      div = clamp(div, 1U, 255U);
+-
+-                      clkgen0 = div << 4;
+-              }
+-      } else {
+-              /*
+-               * For other interfaces, we can arbitarily select between
+-               * the DI specific clock and the internal IPU clock.  See
+-               * DI_GENERAL bit 20.  We select the IPU clock if it can
+-               * give us a clock rate within 1% of the requested frequency,
+-               * otherwise we use the DI clock.
+-               */
+-              unsigned long rate, clkrate;
+-              unsigned div, error;
+-
+-              clkrate = clk_get_rate(di->clk_ipu);
+-              div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
+-              div = clamp(div, 1U, 255U);
+-              rate = clkrate / div;
+-
+-              error = rate / (sig->mode.pixelclock / 1000);
+-
+-              dev_dbg(di->ipu->dev, "  IPU clock can give %lu with divider %u, error %d.%u%%\n",
+-                      rate, div, (signed)(error - 1000) / 10, error % 10);
+-
+-              /* Allow a 1% error */
+-              if (error < 1010 && error >= 990) {
+-                      clk = di->clk_ipu;
+-
+-                      clkgen0 = div << 4;
+-              } else {
+-                      unsigned long in_rate;
+-                      unsigned div;
+-
+-                      clk = di->clk_di;
+-
+-                      clk_set_rate(clk, sig->mode.pixelclock);
+-
+-                      in_rate = clk_get_rate(clk);
+-                      div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
+-                      div = clamp(div, 1U, 255U);
+-
+-                      clkgen0 = div << 4;
+-              }
+-      }
+-
+-      di->clk_di_pixel = clk;
+-
+-      /* Set the divider */
+-      ipu_di_write(di, clkgen0, DI_BS_CLKGEN0);
+-
+-      /*
+-       * Set the high/low periods.  Bits 24:16 give us the falling edge,
+-       * and bits 8:0 give the rising edge.  LSB is fraction, and is
+-       * based on the divider above.  We want a 50% duty cycle, so set
+-       * the falling edge to be half the divider.
+-       */
+-      ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1);
+-
+-      /* Finally select the input clock */
+-      val = ipu_di_read(di, DI_GENERAL) & ~DI_GEN_DI_CLK_EXT;
+-      if (clk == di->clk_di)
+-              val |= DI_GEN_DI_CLK_EXT;
+-      ipu_di_write(di, val, DI_GENERAL);
+-
+-      dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
+-              sig->mode.pixelclock,
+-              clk_get_rate(di->clk_ipu),
+-              clk_get_rate(di->clk_di),
+-              clk == di->clk_di ? "DI" : "IPU",
+-              clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
+-}
+-
+-/*
+- * This function is called to adjust a video mode to IPU restrictions.
+- * It is meant to be called from drm crtc mode_fixup() methods.
+- */
+-int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode)
+-{
+-      u32 diff;
+-
+-      if (mode->vfront_porch >= 2)
+-              return 0;
+-
+-      diff = 2 - mode->vfront_porch;
+-
+-      if (mode->vback_porch >= diff) {
+-              mode->vfront_porch = 2;
+-              mode->vback_porch -= diff;
+-      } else if (mode->vsync_len > diff) {
+-              mode->vfront_porch = 2;
+-              mode->vsync_len = mode->vsync_len - diff;
+-      } else {
+-              dev_warn(di->ipu->dev, "failed to adjust videomode\n");
+-              return -EINVAL;
+-      }
+-
+-      dev_dbg(di->ipu->dev, "videomode adapted for IPU restrictions\n");
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode);
+-
+-static u32 ipu_di_gen_polarity(int pin)
+-{
+-      switch (pin) {
+-      case 1:
+-              return DI_GEN_POLARITY_1;
+-      case 2:
+-              return DI_GEN_POLARITY_2;
+-      case 3:
+-              return DI_GEN_POLARITY_3;
+-      case 4:
+-              return DI_GEN_POLARITY_4;
+-      case 5:
+-              return DI_GEN_POLARITY_5;
+-      case 6:
+-              return DI_GEN_POLARITY_6;
+-      case 7:
+-              return DI_GEN_POLARITY_7;
+-      case 8:
+-              return DI_GEN_POLARITY_8;
+-      }
+-      return 0;
+-}
+-
+-int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
+-{
+-      u32 reg;
+-      u32 di_gen, vsync_cnt;
+-      u32 div;
+-
+-      dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
+-              di->id, sig->mode.hactive, sig->mode.vactive);
+-
+-      dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
+-              clk_get_rate(di->clk_ipu),
+-              clk_get_rate(di->clk_di),
+-              sig->mode.pixelclock);
+-
+-      mutex_lock(&di_mutex);
+-
+-      ipu_di_config_clock(di, sig);
+-
+-      div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
+-      div = div / 16;         /* Now divider is integer portion */
+-
+-      /* Setup pixel clock timing */
+-      /* Down time is half of period */
+-      ipu_di_write(di, (div << 16), DI_BS_CLKGEN1);
+-
+-      ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1);
+-      ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
+-
+-      di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
+-      di_gen |= DI_GEN_DI_VSYNC_EXT;
+-
+-      if (sig->mode.flags & DISPLAY_FLAGS_INTERLACED) {
+-              ipu_di_sync_config_interlaced(di, sig);
+-
+-              /* set y_sel = 1 */
+-              di_gen |= 0x10000000;
+-
+-              vsync_cnt = 3;
+-      } else {
+-              ipu_di_sync_config_noninterlaced(di, sig, div);
+-
+-              vsync_cnt = 3;
+-              if (di->id == 1)
+-                      /*
+-                       * TODO: change only for TVEv2, parallel display
+-                       * uses pin 2 / 3
+-                       */
+-                      if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3))
+-                              vsync_cnt = 6;
+-      }
+-
+-      if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH)
+-              di_gen |= ipu_di_gen_polarity(sig->hsync_pin);
+-      if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH)
+-              di_gen |= ipu_di_gen_polarity(sig->vsync_pin);
+-
+-      if (sig->clk_pol)
+-              di_gen |= DI_GEN_POLARITY_DISP_CLK;
+-
+-      ipu_di_write(di, di_gen, DI_GENERAL);
+-
+-      ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
+-                   DI_SYNC_AS_GEN);
+-
+-      reg = ipu_di_read(di, DI_POL);
+-      reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
+-
+-      if (sig->enable_pol)
+-              reg |= DI_POL_DRDY_POLARITY_15;
+-      if (sig->data_pol)
+-              reg |= DI_POL_DRDY_DATA_POLARITY;
+-
+-      ipu_di_write(di, reg, DI_POL);
+-
+-      mutex_unlock(&di_mutex);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
+-
+-int ipu_di_enable(struct ipu_di *di)
+-{
+-      int ret;
+-
+-      WARN_ON(IS_ERR(di->clk_di_pixel));
+-
+-      ret = clk_prepare_enable(di->clk_di_pixel);
+-      if (ret)
+-              return ret;
+-
+-      ipu_module_enable(di->ipu, di->module);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_di_enable);
+-
+-int ipu_di_disable(struct ipu_di *di)
+-{
+-      WARN_ON(IS_ERR(di->clk_di_pixel));
+-
+-      ipu_module_disable(di->ipu, di->module);
+-
+-      clk_disable_unprepare(di->clk_di_pixel);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_di_disable);
+-
+-int ipu_di_get_num(struct ipu_di *di)
+-{
+-      return di->id;
+-}
+-EXPORT_SYMBOL_GPL(ipu_di_get_num);
+-
+-static DEFINE_MUTEX(ipu_di_lock);
+-
+-struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp)
+-{
+-      struct ipu_di *di;
+-
+-      if (disp > 1)
+-              return ERR_PTR(-EINVAL);
+-
+-      di = ipu->di_priv[disp];
+-
+-      mutex_lock(&ipu_di_lock);
+-
+-      if (di->inuse) {
+-              di = ERR_PTR(-EBUSY);
+-              goto out;
+-      }
+-
+-      di->inuse = true;
+-out:
+-      mutex_unlock(&ipu_di_lock);
+-
+-      return di;
+-}
+-EXPORT_SYMBOL_GPL(ipu_di_get);
+-
+-void ipu_di_put(struct ipu_di *di)
+-{
+-      mutex_lock(&ipu_di_lock);
+-
+-      di->inuse = false;
+-
+-      mutex_unlock(&ipu_di_lock);
+-}
+-EXPORT_SYMBOL_GPL(ipu_di_put);
+-
+-int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
+-              unsigned long base,
+-              u32 module, struct clk *clk_ipu)
+-{
+-      struct ipu_di *di;
+-
+-      if (id > 1)
+-              return -ENODEV;
+-
+-      di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
+-      if (!di)
+-              return -ENOMEM;
+-
+-      ipu->di_priv[id] = di;
+-
+-      di->clk_di = devm_clk_get(dev, id ? "di1" : "di0");
+-      if (IS_ERR(di->clk_di))
+-              return PTR_ERR(di->clk_di);
+-
+-      di->module = module;
+-      di->id = id;
+-      di->clk_ipu = clk_ipu;
+-      di->base = devm_ioremap(dev, base, PAGE_SIZE);
+-      if (!di->base)
+-              return -ENOMEM;
+-
+-      ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
+-
+-      dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n",
+-                      id, base, di->base);
+-      di->inuse = false;
+-      di->ipu = ipu;
+-
+-      return 0;
+-}
+-
+-void ipu_di_exit(struct ipu_soc *ipu, int id)
+-{
+-}
+--- a/drivers/gpu/imx/ipu-v3/ipu-dmfc.c
++++ /dev/null
+@@ -1,214 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-#include <linux/export.h>
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/io.h>
+-
+-#include <video/imx-ipu-v3.h>
+-#include "ipu-prv.h"
+-
+-#define DMFC_RD_CHAN          0x0000
+-#define DMFC_WR_CHAN          0x0004
+-#define DMFC_WR_CHAN_DEF      0x0008
+-#define DMFC_DP_CHAN          0x000c
+-#define DMFC_DP_CHAN_DEF      0x0010
+-#define DMFC_GENERAL1         0x0014
+-#define DMFC_GENERAL2         0x0018
+-#define DMFC_IC_CTRL          0x001c
+-#define DMFC_WR_CHAN_ALT      0x0020
+-#define DMFC_WR_CHAN_DEF_ALT  0x0024
+-#define DMFC_DP_CHAN_ALT      0x0028
+-#define DMFC_DP_CHAN_DEF_ALT  0x002c
+-#define DMFC_GENERAL1_ALT     0x0030
+-#define DMFC_STAT             0x0034
+-
+-#define DMFC_WR_CHAN_1_28             0
+-#define DMFC_WR_CHAN_2_41             8
+-#define DMFC_WR_CHAN_1C_42            16
+-#define DMFC_WR_CHAN_2C_43            24
+-
+-#define DMFC_DP_CHAN_5B_23            0
+-#define DMFC_DP_CHAN_5F_27            8
+-#define DMFC_DP_CHAN_6B_24            16
+-#define DMFC_DP_CHAN_6F_29            24
+-
+-struct dmfc_channel_data {
+-      int             ipu_channel;
+-      unsigned long   channel_reg;
+-      unsigned long   shift;
+-      unsigned        eot_shift;
+-      unsigned        max_fifo_lines;
+-};
+-
+-static const struct dmfc_channel_data dmfcdata[] = {
+-      {
+-              .ipu_channel    = IPUV3_CHANNEL_MEM_BG_SYNC,
+-              .channel_reg    = DMFC_DP_CHAN,
+-              .shift          = DMFC_DP_CHAN_5B_23,
+-              .eot_shift      = 20,
+-              .max_fifo_lines = 3,
+-      }, {
+-              .ipu_channel    = 24,
+-              .channel_reg    = DMFC_DP_CHAN,
+-              .shift          = DMFC_DP_CHAN_6B_24,
+-              .eot_shift      = 22,
+-              .max_fifo_lines = 1,
+-      }, {
+-              .ipu_channel    = IPUV3_CHANNEL_MEM_FG_SYNC,
+-              .channel_reg    = DMFC_DP_CHAN,
+-              .shift          = DMFC_DP_CHAN_5F_27,
+-              .eot_shift      = 21,
+-              .max_fifo_lines = 2,
+-      }, {
+-              .ipu_channel    = IPUV3_CHANNEL_MEM_DC_SYNC,
+-              .channel_reg    = DMFC_WR_CHAN,
+-              .shift          = DMFC_WR_CHAN_1_28,
+-              .eot_shift      = 16,
+-              .max_fifo_lines = 2,
+-      }, {
+-              .ipu_channel    = 29,
+-              .channel_reg    = DMFC_DP_CHAN,
+-              .shift          = DMFC_DP_CHAN_6F_29,
+-              .eot_shift      = 23,
+-              .max_fifo_lines = 1,
+-      },
+-};
+-
+-#define DMFC_NUM_CHANNELS     ARRAY_SIZE(dmfcdata)
+-
+-struct ipu_dmfc_priv;
+-
+-struct dmfc_channel {
+-      unsigned                        slots;
+-      struct ipu_soc                  *ipu;
+-      struct ipu_dmfc_priv            *priv;
+-      const struct dmfc_channel_data  *data;
+-};
+-
+-struct ipu_dmfc_priv {
+-      struct ipu_soc *ipu;
+-      struct device *dev;
+-      struct dmfc_channel channels[DMFC_NUM_CHANNELS];
+-      struct mutex mutex;
+-      void __iomem *base;
+-      int use_count;
+-};
+-
+-int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
+-{
+-      struct ipu_dmfc_priv *priv = dmfc->priv;
+-      mutex_lock(&priv->mutex);
+-
+-      if (!priv->use_count)
+-              ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
+-
+-      priv->use_count++;
+-
+-      mutex_unlock(&priv->mutex);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
+-
+-void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
+-{
+-      struct ipu_dmfc_priv *priv = dmfc->priv;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      priv->use_count--;
+-
+-      if (!priv->use_count)
+-              ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
+-
+-      if (priv->use_count < 0)
+-              priv->use_count = 0;
+-
+-      mutex_unlock(&priv->mutex);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
+-
+-void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width)
+-{
+-      struct ipu_dmfc_priv *priv = dmfc->priv;
+-      u32 dmfc_gen1;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
+-
+-      if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
+-              dmfc_gen1 |= 1 << dmfc->data->eot_shift;
+-      else
+-              dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
+-
+-      writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
+-
+-      mutex_unlock(&priv->mutex);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
+-
+-struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
+-{
+-      struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
+-      int i;
+-
+-      for (i = 0; i < DMFC_NUM_CHANNELS; i++)
+-              if (dmfcdata[i].ipu_channel == ipu_channel)
+-                      return &priv->channels[i];
+-      return ERR_PTR(-ENODEV);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dmfc_get);
+-
+-void ipu_dmfc_put(struct dmfc_channel *dmfc)
+-{
+-}
+-EXPORT_SYMBOL_GPL(ipu_dmfc_put);
+-
+-int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
+-              struct clk *ipu_clk)
+-{
+-      struct ipu_dmfc_priv *priv;
+-      int i;
+-
+-      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-      if (!priv)
+-              return -ENOMEM;
+-
+-      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+-      if (!priv->base)
+-              return -ENOMEM;
+-
+-      priv->dev = dev;
+-      priv->ipu = ipu;
+-      mutex_init(&priv->mutex);
+-
+-      ipu->dmfc_priv = priv;
+-
+-      for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
+-              priv->channels[i].priv = priv;
+-              priv->channels[i].ipu = ipu;
+-              priv->channels[i].data = &dmfcdata[i];
+-
+-              if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC ||
+-                  dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC ||
+-                  dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC)
+-                      priv->channels[i].slots = 2;
+-      }
+-
+-      writel(0x00000050, priv->base + DMFC_WR_CHAN);
+-      writel(0x00005654, priv->base + DMFC_DP_CHAN);
+-      writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
+-      writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
+-      writel(0x00000003, priv->base + DMFC_GENERAL1);
+-
+-      return 0;
+-}
+-
+-void ipu_dmfc_exit(struct ipu_soc *ipu)
+-{
+-}
+--- a/drivers/gpu/imx/ipu-v3/ipu-dp.c
++++ /dev/null
+@@ -1,357 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-#include <linux/export.h>
+-#include <linux/kernel.h>
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/io.h>
+-#include <linux/err.h>
+-
+-#include <video/imx-ipu-v3.h>
+-#include "ipu-prv.h"
+-
+-#define DP_SYNC 0
+-#define DP_ASYNC0 0x60
+-#define DP_ASYNC1 0xBC
+-
+-#define DP_COM_CONF           0x0
+-#define DP_GRAPH_WIND_CTRL    0x0004
+-#define DP_FG_POS             0x0008
+-#define DP_CSC_A_0            0x0044
+-#define DP_CSC_A_1            0x0048
+-#define DP_CSC_A_2            0x004C
+-#define DP_CSC_A_3            0x0050
+-#define DP_CSC_0              0x0054
+-#define DP_CSC_1              0x0058
+-
+-#define DP_COM_CONF_FG_EN             (1 << 0)
+-#define DP_COM_CONF_GWSEL             (1 << 1)
+-#define DP_COM_CONF_GWAM              (1 << 2)
+-#define DP_COM_CONF_GWCKE             (1 << 3)
+-#define DP_COM_CONF_CSC_DEF_MASK      (3 << 8)
+-#define DP_COM_CONF_CSC_DEF_OFFSET    8
+-#define DP_COM_CONF_CSC_DEF_FG                (3 << 8)
+-#define DP_COM_CONF_CSC_DEF_BG                (2 << 8)
+-#define DP_COM_CONF_CSC_DEF_BOTH      (1 << 8)
+-
+-#define IPUV3_NUM_FLOWS               3
+-
+-struct ipu_dp_priv;
+-
+-struct ipu_dp {
+-      u32 flow;
+-      bool in_use;
+-      bool foreground;
+-      enum ipu_color_space in_cs;
+-};
+-
+-struct ipu_flow {
+-      struct ipu_dp foreground;
+-      struct ipu_dp background;
+-      enum ipu_color_space out_cs;
+-      void __iomem *base;
+-      struct ipu_dp_priv *priv;
+-};
+-
+-struct ipu_dp_priv {
+-      struct ipu_soc *ipu;
+-      struct device *dev;
+-      void __iomem *base;
+-      struct ipu_flow flow[IPUV3_NUM_FLOWS];
+-      struct mutex mutex;
+-      int use_count;
+-};
+-
+-static u32 ipu_dp_flow_base[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1};
+-
+-static inline struct ipu_flow *to_flow(struct ipu_dp *dp)
+-{
+-      if (dp->foreground)
+-              return container_of(dp, struct ipu_flow, foreground);
+-      else
+-              return container_of(dp, struct ipu_flow, background);
+-}
+-
+-int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable,
+-              u8 alpha, bool bg_chan)
+-{
+-      struct ipu_flow *flow = to_flow(dp);
+-      struct ipu_dp_priv *priv = flow->priv;
+-      u32 reg;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      reg = readl(flow->base + DP_COM_CONF);
+-      if (bg_chan)
+-              reg &= ~DP_COM_CONF_GWSEL;
+-      else
+-              reg |= DP_COM_CONF_GWSEL;
+-      writel(reg, flow->base + DP_COM_CONF);
+-
+-      if (enable) {
+-              reg = readl(flow->base + DP_GRAPH_WIND_CTRL) & 0x00FFFFFFL;
+-              writel(reg | ((u32) alpha << 24),
+-                           flow->base + DP_GRAPH_WIND_CTRL);
+-
+-              reg = readl(flow->base + DP_COM_CONF);
+-              writel(reg | DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
+-      } else {
+-              reg = readl(flow->base + DP_COM_CONF);
+-              writel(reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
+-      }
+-
+-      ipu_srm_dp_update(priv->ipu, true);
+-
+-      mutex_unlock(&priv->mutex);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha);
+-
+-int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
+-{
+-      struct ipu_flow *flow = to_flow(dp);
+-      struct ipu_dp_priv *priv = flow->priv;
+-
+-      writel((x_pos << 16) | y_pos, flow->base + DP_FG_POS);
+-
+-      ipu_srm_dp_update(priv->ipu, true);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos);
+-
+-static void ipu_dp_csc_init(struct ipu_flow *flow,
+-              enum ipu_color_space in,
+-              enum ipu_color_space out,
+-              u32 place)
+-{
+-      u32 reg;
+-
+-      reg = readl(flow->base + DP_COM_CONF);
+-      reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+-
+-      if (in == out) {
+-              writel(reg, flow->base + DP_COM_CONF);
+-              return;
+-      }
+-
+-      if (in == IPUV3_COLORSPACE_RGB && out == IPUV3_COLORSPACE_YUV) {
+-              writel(0x099 | (0x12d << 16), flow->base + DP_CSC_A_0);
+-              writel(0x03a | (0x3a9 << 16), flow->base + DP_CSC_A_1);
+-              writel(0x356 | (0x100 << 16), flow->base + DP_CSC_A_2);
+-              writel(0x100 | (0x329 << 16), flow->base + DP_CSC_A_3);
+-              writel(0x3d6 | (0x0000 << 16) | (2 << 30),
+-                              flow->base + DP_CSC_0);
+-              writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30),
+-                              flow->base + DP_CSC_1);
+-      } else {
+-              writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0);
+-              writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1);
+-              writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2);
+-              writel(0x095 | (0x0ff << 16), flow->base + DP_CSC_A_3);
+-              writel(0x000 | (0x3e42 << 16) | (1 << 30),
+-                              flow->base + DP_CSC_0);
+-              writel(0x10a | (1 << 14) | (0x3dd6 << 16) | (1 << 30),
+-                              flow->base + DP_CSC_1);
+-      }
+-
+-      reg |= place;
+-
+-      writel(reg, flow->base + DP_COM_CONF);
+-}
+-
+-int ipu_dp_setup_channel(struct ipu_dp *dp,
+-              enum ipu_color_space in,
+-              enum ipu_color_space out)
+-{
+-      struct ipu_flow *flow = to_flow(dp);
+-      struct ipu_dp_priv *priv = flow->priv;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      dp->in_cs = in;
+-
+-      if (!dp->foreground)
+-              flow->out_cs = out;
+-
+-      if (flow->foreground.in_cs == flow->background.in_cs) {
+-              /*
+-               * foreground and background are of same colorspace, put
+-               * colorspace converter after combining unit.
+-               */
+-              ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs,
+-                              DP_COM_CONF_CSC_DEF_BOTH);
+-      } else {
+-              if (flow->foreground.in_cs == IPUV3_COLORSPACE_UNKNOWN ||
+-                  flow->foreground.in_cs == flow->out_cs)
+-                      /*
+-                       * foreground identical to output, apply color
+-                       * conversion on background
+-                       */
+-                      ipu_dp_csc_init(flow, flow->background.in_cs,
+-                                      flow->out_cs, DP_COM_CONF_CSC_DEF_BG);
+-              else
+-                      ipu_dp_csc_init(flow, flow->foreground.in_cs,
+-                                      flow->out_cs, DP_COM_CONF_CSC_DEF_FG);
+-      }
+-
+-      ipu_srm_dp_update(priv->ipu, true);
+-
+-      mutex_unlock(&priv->mutex);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
+-
+-int ipu_dp_enable(struct ipu_soc *ipu)
+-{
+-      struct ipu_dp_priv *priv = ipu->dp_priv;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      if (!priv->use_count)
+-              ipu_module_enable(priv->ipu, IPU_CONF_DP_EN);
+-
+-      priv->use_count++;
+-
+-      mutex_unlock(&priv->mutex);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_enable);
+-
+-int ipu_dp_enable_channel(struct ipu_dp *dp)
+-{
+-      struct ipu_flow *flow = to_flow(dp);
+-      struct ipu_dp_priv *priv = flow->priv;
+-      u32 reg;
+-
+-      if (!dp->foreground)
+-              return 0;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      reg = readl(flow->base + DP_COM_CONF);
+-      reg |= DP_COM_CONF_FG_EN;
+-      writel(reg, flow->base + DP_COM_CONF);
+-
+-      ipu_srm_dp_update(priv->ipu, true);
+-
+-      mutex_unlock(&priv->mutex);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
+-
+-void ipu_dp_disable_channel(struct ipu_dp *dp, bool sync)
+-{
+-      struct ipu_flow *flow = to_flow(dp);
+-      struct ipu_dp_priv *priv = flow->priv;
+-      u32 reg, csc;
+-
+-      dp->in_cs = IPUV3_COLORSPACE_UNKNOWN;
+-
+-      if (!dp->foreground)
+-              return;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      reg = readl(flow->base + DP_COM_CONF);
+-      csc = reg & DP_COM_CONF_CSC_DEF_MASK;
+-      reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+-      if (csc == DP_COM_CONF_CSC_DEF_BOTH || csc == DP_COM_CONF_CSC_DEF_BG)
+-              reg |= DP_COM_CONF_CSC_DEF_BG;
+-
+-      reg &= ~DP_COM_CONF_FG_EN;
+-      writel(reg, flow->base + DP_COM_CONF);
+-
+-      writel(0, flow->base + DP_FG_POS);
+-      ipu_srm_dp_update(priv->ipu, sync);
+-
+-      mutex_unlock(&priv->mutex);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
+-
+-void ipu_dp_disable(struct ipu_soc *ipu)
+-{
+-      struct ipu_dp_priv *priv = ipu->dp_priv;
+-
+-      mutex_lock(&priv->mutex);
+-
+-      priv->use_count--;
+-
+-      if (!priv->use_count)
+-              ipu_module_disable(priv->ipu, IPU_CONF_DP_EN);
+-
+-      if (priv->use_count < 0)
+-              priv->use_count = 0;
+-
+-      mutex_unlock(&priv->mutex);
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_disable);
+-
+-struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
+-{
+-      struct ipu_dp_priv *priv = ipu->dp_priv;
+-      struct ipu_dp *dp;
+-
+-      if ((flow >> 1) >= IPUV3_NUM_FLOWS)
+-              return ERR_PTR(-EINVAL);
+-
+-      if (flow & 1)
+-              dp = &priv->flow[flow >> 1].foreground;
+-      else
+-              dp = &priv->flow[flow >> 1].background;
+-
+-      if (dp->in_use)
+-              return ERR_PTR(-EBUSY);
+-
+-      dp->in_use = true;
+-
+-      return dp;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_get);
+-
+-void ipu_dp_put(struct ipu_dp *dp)
+-{
+-      dp->in_use = false;
+-}
+-EXPORT_SYMBOL_GPL(ipu_dp_put);
+-
+-int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
+-{
+-      struct ipu_dp_priv *priv;
+-      int i;
+-
+-      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-      if (!priv)
+-              return -ENOMEM;
+-      priv->dev = dev;
+-      priv->ipu = ipu;
+-
+-      ipu->dp_priv = priv;
+-
+-      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+-      if (!priv->base)
+-              return -ENOMEM;
+-
+-      mutex_init(&priv->mutex);
+-
+-      for (i = 0; i < IPUV3_NUM_FLOWS; i++) {
+-              priv->flow[i].background.in_cs = IPUV3_COLORSPACE_UNKNOWN;
+-              priv->flow[i].foreground.in_cs = IPUV3_COLORSPACE_UNKNOWN;
+-              priv->flow[i].foreground.foreground = true;
+-              priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
+-              priv->flow[i].priv = priv;
+-      }
+-
+-      return 0;
+-}
+-
+-void ipu_dp_exit(struct ipu_soc *ipu)
+-{
+-}
+--- a/drivers/gpu/imx/ipu-v3/ipu-ic.c
++++ /dev/null
+@@ -1,761 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (C) 2012-2014 Mentor Graphics Inc.
+- * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+- */
+-
+-#include <linux/types.h>
+-#include <linux/init.h>
+-#include <linux/errno.h>
+-#include <linux/spinlock.h>
+-#include <linux/bitrev.h>
+-#include <linux/io.h>
+-#include <linux/err.h>
+-#include <linux/sizes.h>
+-#include "ipu-prv.h"
+-
+-/* IC Register Offsets */
+-#define IC_CONF                 0x0000
+-#define IC_PRP_ENC_RSC          0x0004
+-#define IC_PRP_VF_RSC           0x0008
+-#define IC_PP_RSC               0x000C
+-#define IC_CMBP_1               0x0010
+-#define IC_CMBP_2               0x0014
+-#define IC_IDMAC_1              0x0018
+-#define IC_IDMAC_2              0x001C
+-#define IC_IDMAC_3              0x0020
+-#define IC_IDMAC_4              0x0024
+-
+-/* IC Register Fields */
+-#define IC_CONF_PRPENC_EN       (1 << 0)
+-#define IC_CONF_PRPENC_CSC1     (1 << 1)
+-#define IC_CONF_PRPENC_ROT_EN   (1 << 2)
+-#define IC_CONF_PRPVF_EN        (1 << 8)
+-#define IC_CONF_PRPVF_CSC1      (1 << 9)
+-#define IC_CONF_PRPVF_CSC2      (1 << 10)
+-#define IC_CONF_PRPVF_CMB       (1 << 11)
+-#define IC_CONF_PRPVF_ROT_EN    (1 << 12)
+-#define IC_CONF_PP_EN           (1 << 16)
+-#define IC_CONF_PP_CSC1         (1 << 17)
+-#define IC_CONF_PP_CSC2         (1 << 18)
+-#define IC_CONF_PP_CMB          (1 << 19)
+-#define IC_CONF_PP_ROT_EN       (1 << 20)
+-#define IC_CONF_IC_GLB_LOC_A    (1 << 28)
+-#define IC_CONF_KEY_COLOR_EN    (1 << 29)
+-#define IC_CONF_RWS_EN          (1 << 30)
+-#define IC_CONF_CSI_MEM_WR_EN   (1 << 31)
+-
+-#define IC_IDMAC_1_CB0_BURST_16         (1 << 0)
+-#define IC_IDMAC_1_CB1_BURST_16         (1 << 1)
+-#define IC_IDMAC_1_CB2_BURST_16         (1 << 2)
+-#define IC_IDMAC_1_CB3_BURST_16         (1 << 3)
+-#define IC_IDMAC_1_CB4_BURST_16         (1 << 4)
+-#define IC_IDMAC_1_CB5_BURST_16         (1 << 5)
+-#define IC_IDMAC_1_CB6_BURST_16         (1 << 6)
+-#define IC_IDMAC_1_CB7_BURST_16         (1 << 7)
+-#define IC_IDMAC_1_PRPENC_ROT_MASK      (0x7 << 11)
+-#define IC_IDMAC_1_PRPENC_ROT_OFFSET    11
+-#define IC_IDMAC_1_PRPVF_ROT_MASK       (0x7 << 14)
+-#define IC_IDMAC_1_PRPVF_ROT_OFFSET     14
+-#define IC_IDMAC_1_PP_ROT_MASK          (0x7 << 17)
+-#define IC_IDMAC_1_PP_ROT_OFFSET        17
+-#define IC_IDMAC_1_PP_FLIP_RS           (1 << 22)
+-#define IC_IDMAC_1_PRPVF_FLIP_RS        (1 << 21)
+-#define IC_IDMAC_1_PRPENC_FLIP_RS       (1 << 20)
+-
+-#define IC_IDMAC_2_PRPENC_HEIGHT_MASK   (0x3ff << 0)
+-#define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0
+-#define IC_IDMAC_2_PRPVF_HEIGHT_MASK    (0x3ff << 10)
+-#define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET  10
+-#define IC_IDMAC_2_PP_HEIGHT_MASK       (0x3ff << 20)
+-#define IC_IDMAC_2_PP_HEIGHT_OFFSET     20
+-
+-#define IC_IDMAC_3_PRPENC_WIDTH_MASK    (0x3ff << 0)
+-#define IC_IDMAC_3_PRPENC_WIDTH_OFFSET  0
+-#define IC_IDMAC_3_PRPVF_WIDTH_MASK     (0x3ff << 10)
+-#define IC_IDMAC_3_PRPVF_WIDTH_OFFSET   10
+-#define IC_IDMAC_3_PP_WIDTH_MASK        (0x3ff << 20)
+-#define IC_IDMAC_3_PP_WIDTH_OFFSET      20
+-
+-struct ic_task_regoffs {
+-      u32 rsc;
+-      u32 tpmem_csc[2];
+-};
+-
+-struct ic_task_bitfields {
+-      u32 ic_conf_en;
+-      u32 ic_conf_rot_en;
+-      u32 ic_conf_cmb_en;
+-      u32 ic_conf_csc1_en;
+-      u32 ic_conf_csc2_en;
+-      u32 ic_cmb_galpha_bit;
+-};
+-
+-static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
+-      [IC_TASK_ENCODER] = {
+-              .rsc = IC_PRP_ENC_RSC,
+-              .tpmem_csc = {0x2008, 0},
+-      },
+-      [IC_TASK_VIEWFINDER] = {
+-              .rsc = IC_PRP_VF_RSC,
+-              .tpmem_csc = {0x4028, 0x4040},
+-      },
+-      [IC_TASK_POST_PROCESSOR] = {
+-              .rsc = IC_PP_RSC,
+-              .tpmem_csc = {0x6060, 0x6078},
+-      },
+-};
+-
+-static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = {
+-      [IC_TASK_ENCODER] = {
+-              .ic_conf_en = IC_CONF_PRPENC_EN,
+-              .ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN,
+-              .ic_conf_cmb_en = 0,    /* NA */
+-              .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
+-              .ic_conf_csc2_en = 0,   /* NA */
+-              .ic_cmb_galpha_bit = 0, /* NA */
+-      },
+-      [IC_TASK_VIEWFINDER] = {
+-              .ic_conf_en = IC_CONF_PRPVF_EN,
+-              .ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN,
+-              .ic_conf_cmb_en = IC_CONF_PRPVF_CMB,
+-              .ic_conf_csc1_en = IC_CONF_PRPVF_CSC1,
+-              .ic_conf_csc2_en = IC_CONF_PRPVF_CSC2,
+-              .ic_cmb_galpha_bit = 0,
+-      },
+-      [IC_TASK_POST_PROCESSOR] = {
+-              .ic_conf_en = IC_CONF_PP_EN,
+-              .ic_conf_rot_en = IC_CONF_PP_ROT_EN,
+-              .ic_conf_cmb_en = IC_CONF_PP_CMB,
+-              .ic_conf_csc1_en = IC_CONF_PP_CSC1,
+-              .ic_conf_csc2_en = IC_CONF_PP_CSC2,
+-              .ic_cmb_galpha_bit = 8,
+-      },
+-};
+-
+-struct ipu_ic_priv;
+-
+-struct ipu_ic {
+-      enum ipu_ic_task task;
+-      const struct ic_task_regoffs *reg;
+-      const struct ic_task_bitfields *bit;
+-
+-      struct ipu_ic_colorspace in_cs;
+-      struct ipu_ic_colorspace g_in_cs;
+-      struct ipu_ic_colorspace out_cs;
+-
+-      bool graphics;
+-      bool rotation;
+-      bool in_use;
+-
+-      struct ipu_ic_priv *priv;
+-};
+-
+-struct ipu_ic_priv {
+-      void __iomem *base;
+-      void __iomem *tpmem_base;
+-      spinlock_t lock;
+-      struct ipu_soc *ipu;
+-      int use_count;
+-      int irt_use_count;
+-      struct ipu_ic task[IC_NUM_TASKS];
+-};
+-
+-static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset)
+-{
+-      return readl(ic->priv->base + offset);
+-}
+-
+-static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset)
+-{
+-      writel(value, ic->priv->base + offset);
+-}
+-
+-static int init_csc(struct ipu_ic *ic,
+-                  const struct ipu_ic_csc *csc,
+-                  int csc_index)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      u32 __iomem *base;
+-      const u16 (*c)[3];
+-      const u16 *a;
+-      u32 param;
+-
+-      base = (u32 __iomem *)
+-              (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
+-
+-      /* Cast to unsigned */
+-      c = (const u16 (*)[3])csc->params.coeff;
+-      a = (const u16 *)csc->params.offset;
+-
+-      param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) |
+-              ((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff);
+-      writel(param, base++);
+-
+-      param = ((a[0] & 0x1fe0) >> 5) | (csc->params.scale << 8) |
+-              (csc->params.sat << 10);
+-      writel(param, base++);
+-
+-      param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
+-              ((c[1][0] & 0x1ff) << 9) | (c[2][0] & 0x1ff);
+-      writel(param, base++);
+-
+-      param = ((a[1] & 0x1fe0) >> 5);
+-      writel(param, base++);
+-
+-      param = ((a[2] & 0x1f) << 27) | ((c[0][2] & 0x1ff) << 18) |
+-              ((c[1][2] & 0x1ff) << 9) | (c[2][1] & 0x1ff);
+-      writel(param, base++);
+-
+-      param = ((a[2] & 0x1fe0) >> 5);
+-      writel(param, base++);
+-
+-      return 0;
+-}
+-
+-static int calc_resize_coeffs(struct ipu_ic *ic,
+-                            u32 in_size, u32 out_size,
+-                            u32 *resize_coeff,
+-                            u32 *downsize_coeff)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      struct ipu_soc *ipu = priv->ipu;
+-      u32 temp_size, temp_downsize;
+-
+-      /*
+-       * Input size cannot be more than 4096, and output size cannot
+-       * be more than 1024
+-       */
+-      if (in_size > 4096) {
+-              dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
+-              return -EINVAL;
+-      }
+-      if (out_size > 1024) {
+-              dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
+-              return -EINVAL;
+-      }
+-
+-      /* Cannot downsize more than 4:1 */
+-      if ((out_size << 2) < in_size) {
+-              dev_err(ipu->dev, "Unsupported downsize\n");
+-              return -EINVAL;
+-      }
+-
+-      /* Compute downsizing coefficient */
+-      temp_downsize = 0;
+-      temp_size = in_size;
+-      while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
+-             (temp_downsize < 2)) {
+-              temp_size >>= 1;
+-              temp_downsize++;
+-      }
+-      *downsize_coeff = temp_downsize;
+-
+-      /*
+-       * compute resizing coefficient using the following equation:
+-       * resize_coeff = M * (SI - 1) / (SO - 1)
+-       * where M = 2^13, SI = input size, SO = output size
+-       */
+-      *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
+-      if (*resize_coeff >= 16384L) {
+-              dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
+-              *resize_coeff = 0x3FFF;
+-      }
+-
+-      return 0;
+-}
+-
+-void ipu_ic_task_enable(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      unsigned long flags;
+-      u32 ic_conf;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      ic_conf = ipu_ic_read(ic, IC_CONF);
+-
+-      ic_conf |= ic->bit->ic_conf_en;
+-
+-      if (ic->rotation)
+-              ic_conf |= ic->bit->ic_conf_rot_en;
+-
+-      if (ic->in_cs.cs != ic->out_cs.cs)
+-              ic_conf |= ic->bit->ic_conf_csc1_en;
+-
+-      if (ic->graphics) {
+-              ic_conf |= ic->bit->ic_conf_cmb_en;
+-              ic_conf |= ic->bit->ic_conf_csc1_en;
+-
+-              if (ic->g_in_cs.cs != ic->out_cs.cs)
+-                      ic_conf |= ic->bit->ic_conf_csc2_en;
+-      }
+-
+-      ipu_ic_write(ic, ic_conf, IC_CONF);
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_task_enable);
+-
+-void ipu_ic_task_disable(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      unsigned long flags;
+-      u32 ic_conf;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      ic_conf = ipu_ic_read(ic, IC_CONF);
+-
+-      ic_conf &= ~(ic->bit->ic_conf_en |
+-                   ic->bit->ic_conf_csc1_en |
+-                   ic->bit->ic_conf_rot_en);
+-      if (ic->bit->ic_conf_csc2_en)
+-              ic_conf &= ~ic->bit->ic_conf_csc2_en;
+-      if (ic->bit->ic_conf_cmb_en)
+-              ic_conf &= ~ic->bit->ic_conf_cmb_en;
+-
+-      ipu_ic_write(ic, ic_conf, IC_CONF);
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
+-
+-int ipu_ic_task_graphics_init(struct ipu_ic *ic,
+-                            const struct ipu_ic_colorspace *g_in_cs,
+-                            bool galpha_en, u32 galpha,
+-                            bool colorkey_en, u32 colorkey)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      struct ipu_ic_csc csc2;
+-      unsigned long flags;
+-      u32 reg, ic_conf;
+-      int ret = 0;
+-
+-      if (ic->task == IC_TASK_ENCODER)
+-              return -EINVAL;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      ic_conf = ipu_ic_read(ic, IC_CONF);
+-
+-      if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
+-              struct ipu_ic_csc csc1;
+-
+-              ret = ipu_ic_calc_csc(&csc1,
+-                                    V4L2_YCBCR_ENC_601,
+-                                    V4L2_QUANTIZATION_FULL_RANGE,
+-                                    IPUV3_COLORSPACE_RGB,
+-                                    V4L2_YCBCR_ENC_601,
+-                                    V4L2_QUANTIZATION_FULL_RANGE,
+-                                    IPUV3_COLORSPACE_RGB);
+-              if (ret)
+-                      goto unlock;
+-
+-              /* need transparent CSC1 conversion */
+-              ret = init_csc(ic, &csc1, 0);
+-              if (ret)
+-                      goto unlock;
+-      }
+-
+-      ic->g_in_cs = *g_in_cs;
+-      csc2.in_cs = ic->g_in_cs;
+-      csc2.out_cs = ic->out_cs;
+-
+-      ret = __ipu_ic_calc_csc(&csc2);
+-      if (ret)
+-              goto unlock;
+-
+-      ret = init_csc(ic, &csc2, 1);
+-      if (ret)
+-              goto unlock;
+-
+-      if (galpha_en) {
+-              ic_conf |= IC_CONF_IC_GLB_LOC_A;
+-              reg = ipu_ic_read(ic, IC_CMBP_1);
+-              reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit);
+-              reg |= (galpha << ic->bit->ic_cmb_galpha_bit);
+-              ipu_ic_write(ic, reg, IC_CMBP_1);
+-      } else
+-              ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
+-
+-      if (colorkey_en) {
+-              ic_conf |= IC_CONF_KEY_COLOR_EN;
+-              ipu_ic_write(ic, colorkey, IC_CMBP_2);
+-      } else
+-              ic_conf &= ~IC_CONF_KEY_COLOR_EN;
+-
+-      ipu_ic_write(ic, ic_conf, IC_CONF);
+-
+-      ic->graphics = true;
+-unlock:
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
+-
+-int ipu_ic_task_init_rsc(struct ipu_ic *ic,
+-                       const struct ipu_ic_csc *csc,
+-                       int in_width, int in_height,
+-                       int out_width, int out_height,
+-                       u32 rsc)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      u32 downsize_coeff, resize_coeff;
+-      unsigned long flags;
+-      int ret = 0;
+-
+-      if (!rsc) {
+-              /* Setup vertical resizing */
+-
+-              ret = calc_resize_coeffs(ic, in_height, out_height,
+-                                       &resize_coeff, &downsize_coeff);
+-              if (ret)
+-                      return ret;
+-
+-              rsc = (downsize_coeff << 30) | (resize_coeff << 16);
+-
+-              /* Setup horizontal resizing */
+-              ret = calc_resize_coeffs(ic, in_width, out_width,
+-                                       &resize_coeff, &downsize_coeff);
+-              if (ret)
+-                      return ret;
+-
+-              rsc |= (downsize_coeff << 14) | resize_coeff;
+-      }
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      ipu_ic_write(ic, rsc, ic->reg->rsc);
+-
+-      /* Setup color space conversion */
+-      ic->in_cs = csc->in_cs;
+-      ic->out_cs = csc->out_cs;
+-
+-      ret = init_csc(ic, csc, 0);
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-      return ret;
+-}
+-
+-int ipu_ic_task_init(struct ipu_ic *ic,
+-                   const struct ipu_ic_csc *csc,
+-                   int in_width, int in_height,
+-                   int out_width, int out_height)
+-{
+-      return ipu_ic_task_init_rsc(ic, csc,
+-                                  in_width, in_height,
+-                                  out_width, out_height, 0);
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_task_init);
+-
+-int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
+-                        u32 width, u32 height, int burst_size,
+-                        enum ipu_rotate_mode rot)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      struct ipu_soc *ipu = priv->ipu;
+-      u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
+-      u32 temp_rot = bitrev8(rot) >> 5;
+-      bool need_hor_flip = false;
+-      unsigned long flags;
+-      int ret = 0;
+-
+-      if ((burst_size != 8) && (burst_size != 16)) {
+-              dev_err(ipu->dev, "Illegal burst length for IC\n");
+-              return -EINVAL;
+-      }
+-
+-      width--;
+-      height--;
+-
+-      if (temp_rot & 0x2)     /* Need horizontal flip */
+-              need_hor_flip = true;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1);
+-      ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2);
+-      ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3);
+-
+-      switch (channel->num) {
+-      case IPUV3_CHANNEL_IC_PP_MEM:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
+-
+-              if (need_hor_flip)
+-                      ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
+-
+-              ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
+-              ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
+-
+-              ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
+-              ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
+-              break;
+-      case IPUV3_CHANNEL_MEM_IC_PP:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
+-              break;
+-      case IPUV3_CHANNEL_MEM_ROT_PP:
+-              ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
+-              ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
+-              break;
+-      case IPUV3_CHANNEL_MEM_IC_PRP_VF:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
+-              break;
+-      case IPUV3_CHANNEL_IC_PRP_ENC_MEM:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
+-
+-              if (need_hor_flip)
+-                      ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
+-
+-              ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
+-              ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
+-
+-              ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
+-              ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
+-              break;
+-      case IPUV3_CHANNEL_MEM_ROT_ENC:
+-              ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
+-              ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
+-              break;
+-      case IPUV3_CHANNEL_IC_PRP_VF_MEM:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
+-
+-              if (need_hor_flip)
+-                      ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
+-
+-              ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
+-              ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
+-
+-              ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
+-              ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
+-              break;
+-      case IPUV3_CHANNEL_MEM_ROT_VF:
+-              ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
+-              ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
+-              break;
+-      case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
+-              break;
+-      case IPUV3_CHANNEL_G_MEM_IC_PP:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
+-              break;
+-      case IPUV3_CHANNEL_VDI_MEM_IC_VF:
+-              if (burst_size == 16)
+-                      ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
+-              else
+-                      ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
+-              break;
+-      default:
+-              goto unlock;
+-      }
+-
+-      ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1);
+-      ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
+-      ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
+-
+-      if (ipu_rot_mode_is_irt(rot))
+-              ic->rotation = true;
+-
+-unlock:
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
+-
+-static void ipu_irt_enable(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-
+-      if (!priv->irt_use_count)
+-              ipu_module_enable(priv->ipu, IPU_CONF_ROT_EN);
+-
+-      priv->irt_use_count++;
+-}
+-
+-static void ipu_irt_disable(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-
+-      if (priv->irt_use_count) {
+-              if (!--priv->irt_use_count)
+-                      ipu_module_disable(priv->ipu, IPU_CONF_ROT_EN);
+-      }
+-}
+-
+-int ipu_ic_enable(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      if (!priv->use_count)
+-              ipu_module_enable(priv->ipu, IPU_CONF_IC_EN);
+-
+-      priv->use_count++;
+-
+-      if (ic->rotation)
+-              ipu_irt_enable(ic);
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_enable);
+-
+-int ipu_ic_disable(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      priv->use_count--;
+-
+-      if (!priv->use_count)
+-              ipu_module_disable(priv->ipu, IPU_CONF_IC_EN);
+-
+-      if (priv->use_count < 0)
+-              priv->use_count = 0;
+-
+-      if (ic->rotation)
+-              ipu_irt_disable(ic);
+-
+-      ic->rotation = ic->graphics = false;
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_disable);
+-
+-struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
+-{
+-      struct ipu_ic_priv *priv = ipu->ic_priv;
+-      unsigned long flags;
+-      struct ipu_ic *ic, *ret;
+-
+-      if (task >= IC_NUM_TASKS)
+-              return ERR_PTR(-EINVAL);
+-
+-      ic = &priv->task[task];
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      if (ic->in_use) {
+-              ret = ERR_PTR(-EBUSY);
+-              goto unlock;
+-      }
+-
+-      ic->in_use = true;
+-      ret = ic;
+-
+-unlock:
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_get);
+-
+-void ipu_ic_put(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-      ic->in_use = false;
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_put);
+-
+-int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
+-              unsigned long base, unsigned long tpmem_base)
+-{
+-      struct ipu_ic_priv *priv;
+-      int i;
+-
+-      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-      if (!priv)
+-              return -ENOMEM;
+-
+-      ipu->ic_priv = priv;
+-
+-      spin_lock_init(&priv->lock);
+-      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+-      if (!priv->base)
+-              return -ENOMEM;
+-      priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K);
+-      if (!priv->tpmem_base)
+-              return -ENOMEM;
+-
+-      dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base);
+-
+-      priv->ipu = ipu;
+-
+-      for (i = 0; i < IC_NUM_TASKS; i++) {
+-              priv->task[i].task = i;
+-              priv->task[i].priv = priv;
+-              priv->task[i].reg = &ic_task_reg[i];
+-              priv->task[i].bit = &ic_task_bit[i];
+-      }
+-
+-      return 0;
+-}
+-
+-void ipu_ic_exit(struct ipu_soc *ipu)
+-{
+-}
+-
+-void ipu_ic_dump(struct ipu_ic *ic)
+-{
+-      struct ipu_ic_priv *priv = ic->priv;
+-      struct ipu_soc *ipu = priv->ipu;
+-
+-      dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_CONF));
+-      dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_PRP_ENC_RSC));
+-      dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_PRP_VF_RSC));
+-      dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_PP_RSC));
+-      dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_CMBP_1));
+-      dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_CMBP_2));
+-      dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_IDMAC_1));
+-      dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_IDMAC_2));
+-      dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_IDMAC_3));
+-      dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n",
+-              ipu_ic_read(ic, IC_IDMAC_4));
+-}
+-EXPORT_SYMBOL_GPL(ipu_ic_dump);
+--- a/drivers/gpu/imx/ipu-v3/ipu-image-convert.c
++++ /dev/null
+@@ -1,2475 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (C) 2012-2016 Mentor Graphics Inc.
+- *
+- * Queued image conversion support, with tiling and rotation.
+- */
+-
+-#include <linux/interrupt.h>
+-#include <linux/dma-mapping.h>
+-#include <video/imx-ipu-image-convert.h>
+-#include "ipu-prv.h"
+-
+-/*
+- * The IC Resizer has a restriction that the output frame from the
+- * resizer must be 1024 or less in both width (pixels) and height
+- * (lines).
+- *
+- * The image converter attempts to split up a conversion when
+- * the desired output (converted) frame resolution exceeds the
+- * IC resizer limit of 1024 in either dimension.
+- *
+- * If either dimension of the output frame exceeds the limit, the
+- * dimension is split into 1, 2, or 4 equal stripes, for a maximum
+- * of 4*4 or 16 tiles. A conversion is then carried out for each
+- * tile (but taking care to pass the full frame stride length to
+- * the DMA channel's parameter memory!). IDMA double-buffering is used
+- * to convert each tile back-to-back when possible (see note below
+- * when double_buffering boolean is set).
+- *
+- * Note that the input frame must be split up into the same number
+- * of tiles as the output frame:
+- *
+- *                       +---------+-----+
+- *   +-----+---+         |  A      | B   |
+- *   | A   | B |         |         |     |
+- *   +-----+---+   -->   +---------+-----+
+- *   | C   | D |         |  C      | D   |
+- *   +-----+---+         |         |     |
+- *                       +---------+-----+
+- *
+- * Clockwise 90° rotations are handled by first rescaling into a
+- * reusable temporary tile buffer and then rotating with the 8x8
+- * block rotator, writing to the correct destination:
+- *
+- *                                         +-----+-----+
+- *                                         |     |     |
+- *   +-----+---+         +---------+       | C   | A   |
+- *   | A   | B |         | A,B, |  |       |     |     |
+- *   +-----+---+   -->   | C,D  |  |  -->  |     |     |
+- *   | C   | D |         +---------+       +-----+-----+
+- *   +-----+---+                           | D   | B   |
+- *                                         |     |     |
+- *                                         +-----+-----+
+- *
+- * If the 8x8 block rotator is used, horizontal or vertical flipping
+- * is done during the rotation step, otherwise flipping is done
+- * during the scaling step.
+- * With rotation or flipping, tile order changes between input and
+- * output image. Tiles are numbered row major from top left to bottom
+- * right for both input and output image.
+- */
+-
+-#define MAX_STRIPES_W    4
+-#define MAX_STRIPES_H    4
+-#define MAX_TILES (MAX_STRIPES_W * MAX_STRIPES_H)
+-
+-#define MIN_W     16
+-#define MIN_H     8
+-#define MAX_W     4096
+-#define MAX_H     4096
+-
+-enum ipu_image_convert_type {
+-      IMAGE_CONVERT_IN = 0,
+-      IMAGE_CONVERT_OUT,
+-};
+-
+-struct ipu_image_convert_dma_buf {
+-      void          *virt;
+-      dma_addr_t    phys;
+-      unsigned long len;
+-};
+-
+-struct ipu_image_convert_dma_chan {
+-      int in;
+-      int out;
+-      int rot_in;
+-      int rot_out;
+-      int vdi_in_p;
+-      int vdi_in;
+-      int vdi_in_n;
+-};
+-
+-/* dimensions of one tile */
+-struct ipu_image_tile {
+-      u32 width;
+-      u32 height;
+-      u32 left;
+-      u32 top;
+-      /* size and strides are in bytes */
+-      u32 size;
+-      u32 stride;
+-      u32 rot_stride;
+-      /* start Y or packed offset of this tile */
+-      u32 offset;
+-      /* offset from start to tile in U plane, for planar formats */
+-      u32 u_off;
+-      /* offset from start to tile in V plane, for planar formats */
+-      u32 v_off;
+-};
+-
+-struct ipu_image_convert_image {
+-      struct ipu_image base;
+-      enum ipu_image_convert_type type;
+-
+-      const struct ipu_image_pixfmt *fmt;
+-      unsigned int stride;
+-
+-      /* # of rows (horizontal stripes) if dest height is > 1024 */
+-      unsigned int num_rows;
+-      /* # of columns (vertical stripes) if dest width is > 1024 */
+-      unsigned int num_cols;
+-
+-      struct ipu_image_tile tile[MAX_TILES];
+-};
+-
+-struct ipu_image_pixfmt {
+-      u32     fourcc;        /* V4L2 fourcc */
+-      int     bpp;           /* total bpp */
+-      int     uv_width_dec;  /* decimation in width for U/V planes */
+-      int     uv_height_dec; /* decimation in height for U/V planes */
+-      bool    planar;        /* planar format */
+-      bool    uv_swapped;    /* U and V planes are swapped */
+-      bool    uv_packed;     /* partial planar (U and V in same plane) */
+-};
+-
+-struct ipu_image_convert_ctx;
+-struct ipu_image_convert_chan;
+-struct ipu_image_convert_priv;
+-
+-struct ipu_image_convert_ctx {
+-      struct ipu_image_convert_chan *chan;
+-
+-      ipu_image_convert_cb_t complete;
+-      void *complete_context;
+-
+-      /* Source/destination image data and rotation mode */
+-      struct ipu_image_convert_image in;
+-      struct ipu_image_convert_image out;
+-      struct ipu_ic_csc csc;
+-      enum ipu_rotate_mode rot_mode;
+-      u32 downsize_coeff_h;
+-      u32 downsize_coeff_v;
+-      u32 image_resize_coeff_h;
+-      u32 image_resize_coeff_v;
+-      u32 resize_coeffs_h[MAX_STRIPES_W];
+-      u32 resize_coeffs_v[MAX_STRIPES_H];
+-
+-      /* intermediate buffer for rotation */
+-      struct ipu_image_convert_dma_buf rot_intermediate[2];
+-
+-      /* current buffer number for double buffering */
+-      int cur_buf_num;
+-
+-      bool aborting;
+-      struct completion aborted;
+-
+-      /* can we use double-buffering for this conversion operation? */
+-      bool double_buffering;
+-      /* num_rows * num_cols */
+-      unsigned int num_tiles;
+-      /* next tile to process */
+-      unsigned int next_tile;
+-      /* where to place converted tile in dest image */
+-      unsigned int out_tile_map[MAX_TILES];
+-
+-      struct list_head list;
+-};
+-
+-struct ipu_image_convert_chan {
+-      struct ipu_image_convert_priv *priv;
+-
+-      enum ipu_ic_task ic_task;
+-      const struct ipu_image_convert_dma_chan *dma_ch;
+-
+-      struct ipu_ic *ic;
+-      struct ipuv3_channel *in_chan;
+-      struct ipuv3_channel *out_chan;
+-      struct ipuv3_channel *rotation_in_chan;
+-      struct ipuv3_channel *rotation_out_chan;
+-
+-      /* the IPU end-of-frame irqs */
+-      int out_eof_irq;
+-      int rot_out_eof_irq;
+-
+-      spinlock_t irqlock;
+-
+-      /* list of convert contexts */
+-      struct list_head ctx_list;
+-      /* queue of conversion runs */
+-      struct list_head pending_q;
+-      /* queue of completed runs */
+-      struct list_head done_q;
+-
+-      /* the current conversion run */
+-      struct ipu_image_convert_run *current_run;
+-};
+-
+-struct ipu_image_convert_priv {
+-      struct ipu_image_convert_chan chan[IC_NUM_TASKS];
+-      struct ipu_soc *ipu;
+-};
+-
+-static const struct ipu_image_convert_dma_chan
+-image_convert_dma_chan[IC_NUM_TASKS] = {
+-      [IC_TASK_VIEWFINDER] = {
+-              .in = IPUV3_CHANNEL_MEM_IC_PRP_VF,
+-              .out = IPUV3_CHANNEL_IC_PRP_VF_MEM,
+-              .rot_in = IPUV3_CHANNEL_MEM_ROT_VF,
+-              .rot_out = IPUV3_CHANNEL_ROT_VF_MEM,
+-              .vdi_in_p = IPUV3_CHANNEL_MEM_VDI_PREV,
+-              .vdi_in = IPUV3_CHANNEL_MEM_VDI_CUR,
+-              .vdi_in_n = IPUV3_CHANNEL_MEM_VDI_NEXT,
+-      },
+-      [IC_TASK_POST_PROCESSOR] = {
+-              .in = IPUV3_CHANNEL_MEM_IC_PP,
+-              .out = IPUV3_CHANNEL_IC_PP_MEM,
+-              .rot_in = IPUV3_CHANNEL_MEM_ROT_PP,
+-              .rot_out = IPUV3_CHANNEL_ROT_PP_MEM,
+-      },
+-};
+-
+-static const struct ipu_image_pixfmt image_convert_formats[] = {
+-      {
+-              .fourcc = V4L2_PIX_FMT_RGB565,
+-              .bpp    = 16,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_RGB24,
+-              .bpp    = 24,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_BGR24,
+-              .bpp    = 24,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_RGB32,
+-              .bpp    = 32,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_BGR32,
+-              .bpp    = 32,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_XRGB32,
+-              .bpp    = 32,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_XBGR32,
+-              .bpp    = 32,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_BGRX32,
+-              .bpp    = 32,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_RGBX32,
+-              .bpp    = 32,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_YUYV,
+-              .bpp    = 16,
+-              .uv_width_dec = 2,
+-              .uv_height_dec = 1,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_UYVY,
+-              .bpp    = 16,
+-              .uv_width_dec = 2,
+-              .uv_height_dec = 1,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_YUV420,
+-              .bpp    = 12,
+-              .planar = true,
+-              .uv_width_dec = 2,
+-              .uv_height_dec = 2,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_YVU420,
+-              .bpp    = 12,
+-              .planar = true,
+-              .uv_width_dec = 2,
+-              .uv_height_dec = 2,
+-              .uv_swapped = true,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_NV12,
+-              .bpp    = 12,
+-              .planar = true,
+-              .uv_width_dec = 2,
+-              .uv_height_dec = 2,
+-              .uv_packed = true,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_YUV422P,
+-              .bpp    = 16,
+-              .planar = true,
+-              .uv_width_dec = 2,
+-              .uv_height_dec = 1,
+-      }, {
+-              .fourcc = V4L2_PIX_FMT_NV16,
+-              .bpp    = 16,
+-              .planar = true,
+-              .uv_width_dec = 2,
+-              .uv_height_dec = 1,
+-              .uv_packed = true,
+-      },
+-};
+-
+-static const struct ipu_image_pixfmt *get_format(u32 fourcc)
+-{
+-      const struct ipu_image_pixfmt *ret = NULL;
+-      unsigned int i;
+-
+-      for (i = 0; i < ARRAY_SIZE(image_convert_formats); i++) {
+-              if (image_convert_formats[i].fourcc == fourcc) {
+-                      ret = &image_convert_formats[i];
+-                      break;
+-              }
+-      }
+-
+-      return ret;
+-}
+-
+-static void dump_format(struct ipu_image_convert_ctx *ctx,
+-                      struct ipu_image_convert_image *ic_image)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-
+-      dev_dbg(priv->ipu->dev,
+-              "task %u: ctx %p: %s format: %dx%d (%dx%d tiles), %c%c%c%c\n",
+-              chan->ic_task, ctx,
+-              ic_image->type == IMAGE_CONVERT_OUT ? "Output" : "Input",
+-              ic_image->base.pix.width, ic_image->base.pix.height,
+-              ic_image->num_cols, ic_image->num_rows,
+-              ic_image->fmt->fourcc & 0xff,
+-              (ic_image->fmt->fourcc >> 8) & 0xff,
+-              (ic_image->fmt->fourcc >> 16) & 0xff,
+-              (ic_image->fmt->fourcc >> 24) & 0xff);
+-}
+-
+-int ipu_image_convert_enum_format(int index, u32 *fourcc)
+-{
+-      const struct ipu_image_pixfmt *fmt;
+-
+-      if (index >= (int)ARRAY_SIZE(image_convert_formats))
+-              return -EINVAL;
+-
+-      /* Format found */
+-      fmt = &image_convert_formats[index];
+-      *fourcc = fmt->fourcc;
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_enum_format);
+-
+-static void free_dma_buf(struct ipu_image_convert_priv *priv,
+-                       struct ipu_image_convert_dma_buf *buf)
+-{
+-      if (buf->virt)
+-              dma_free_coherent(priv->ipu->dev,
+-                                buf->len, buf->virt, buf->phys);
+-      buf->virt = NULL;
+-      buf->phys = 0;
+-}
+-
+-static int alloc_dma_buf(struct ipu_image_convert_priv *priv,
+-                       struct ipu_image_convert_dma_buf *buf,
+-                       int size)
+-{
+-      buf->len = PAGE_ALIGN(size);
+-      buf->virt = dma_alloc_coherent(priv->ipu->dev, buf->len, &buf->phys,
+-                                     GFP_DMA | GFP_KERNEL);
+-      if (!buf->virt) {
+-              dev_err(priv->ipu->dev, "failed to alloc dma buffer\n");
+-              return -ENOMEM;
+-      }
+-
+-      return 0;
+-}
+-
+-static inline int num_stripes(int dim)
+-{
+-      return (dim - 1) / 1024 + 1;
+-}
+-
+-/*
+- * Calculate downsizing coefficients, which are the same for all tiles,
+- * and initial bilinear resizing coefficients, which are used to find the
+- * best seam positions.
+- * Also determine the number of tiles necessary to guarantee that no tile
+- * is larger than 1024 pixels in either dimension at the output and between
+- * IC downsizing and main processing sections.
+- */
+-static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
+-                                        struct ipu_image *in,
+-                                        struct ipu_image *out)
+-{
+-      u32 downsized_width = in->rect.width;
+-      u32 downsized_height = in->rect.height;
+-      u32 downsize_coeff_v = 0;
+-      u32 downsize_coeff_h = 0;
+-      u32 resized_width = out->rect.width;
+-      u32 resized_height = out->rect.height;
+-      u32 resize_coeff_h;
+-      u32 resize_coeff_v;
+-      u32 cols;
+-      u32 rows;
+-
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              resized_width = out->rect.height;
+-              resized_height = out->rect.width;
+-      }
+-
+-      /* Do not let invalid input lead to an endless loop below */
+-      if (WARN_ON(resized_width == 0 || resized_height == 0))
+-              return -EINVAL;
+-
+-      while (downsized_width >= resized_width * 2) {
+-              downsized_width >>= 1;
+-              downsize_coeff_h++;
+-      }
+-
+-      while (downsized_height >= resized_height * 2) {
+-              downsized_height >>= 1;
+-              downsize_coeff_v++;
+-      }
+-
+-      /*
+-       * Calculate the bilinear resizing coefficients that could be used if
+-       * we were converting with a single tile. The bottom right output pixel
+-       * should sample as close as possible to the bottom right input pixel
+-       * out of the decimator, but not overshoot it:
+-       */
+-      resize_coeff_h = 8192 * (downsized_width - 1) / (resized_width - 1);
+-      resize_coeff_v = 8192 * (downsized_height - 1) / (resized_height - 1);
+-
+-      /*
+-       * Both the output of the IC downsizing section before being passed to
+-       * the IC main processing section and the final output of the IC main
+-       * processing section must be <= 1024 pixels in both dimensions.
+-       */
+-      cols = num_stripes(max_t(u32, downsized_width, resized_width));
+-      rows = num_stripes(max_t(u32, downsized_height, resized_height));
+-
+-      dev_dbg(ctx->chan->priv->ipu->dev,
+-              "%s: hscale: >>%u, *8192/%u vscale: >>%u, *8192/%u, %ux%u tiles\n",
+-              __func__, downsize_coeff_h, resize_coeff_h, downsize_coeff_v,
+-              resize_coeff_v, cols, rows);
+-
+-      if (downsize_coeff_h > 2 || downsize_coeff_v  > 2 ||
+-          resize_coeff_h > 0x3fff || resize_coeff_v > 0x3fff)
+-              return -EINVAL;
+-
+-      ctx->downsize_coeff_h = downsize_coeff_h;
+-      ctx->downsize_coeff_v = downsize_coeff_v;
+-      ctx->image_resize_coeff_h = resize_coeff_h;
+-      ctx->image_resize_coeff_v = resize_coeff_v;
+-      ctx->in.num_cols = cols;
+-      ctx->in.num_rows = rows;
+-
+-      return 0;
+-}
+-
+-#define round_closest(x, y) round_down((x) + (y)/2, (y))
+-
+-/*
+- * Find the best aligned seam position for the given column / row index.
+- * Rotation and image offsets are out of scope.
+- *
+- * @index: column / row index, used to calculate valid interval
+- * @in_edge: input right / bottom edge
+- * @out_edge: output right / bottom edge
+- * @in_align: input alignment, either horizontal 8-byte line start address
+- *            alignment, or pixel alignment due to image format
+- * @out_align: output alignment, either horizontal 8-byte line start address
+- *             alignment, or pixel alignment due to image format or rotator
+- *             block size
+- * @in_burst: horizontal input burst size in case of horizontal flip
+- * @out_burst: horizontal output burst size or rotator block size
+- * @downsize_coeff: downsizing section coefficient
+- * @resize_coeff: main processing section resizing coefficient
+- * @_in_seam: aligned input seam position return value
+- * @_out_seam: aligned output seam position return value
+- */
+-static void find_best_seam(struct ipu_image_convert_ctx *ctx,
+-                         unsigned int index,
+-                         unsigned int in_edge,
+-                         unsigned int out_edge,
+-                         unsigned int in_align,
+-                         unsigned int out_align,
+-                         unsigned int in_burst,
+-                         unsigned int out_burst,
+-                         unsigned int downsize_coeff,
+-                         unsigned int resize_coeff,
+-                         u32 *_in_seam,
+-                         u32 *_out_seam)
+-{
+-      struct device *dev = ctx->chan->priv->ipu->dev;
+-      unsigned int out_pos;
+-      /* Input / output seam position candidates */
+-      unsigned int out_seam = 0;
+-      unsigned int in_seam = 0;
+-      unsigned int min_diff = UINT_MAX;
+-      unsigned int out_start;
+-      unsigned int out_end;
+-      unsigned int in_start;
+-      unsigned int in_end;
+-
+-      /* Start within 1024 pixels of the right / bottom edge */
+-      out_start = max_t(int, index * out_align, out_edge - 1024);
+-      /* End before having to add more columns to the left / rows above */
+-      out_end = min_t(unsigned int, out_edge, index * 1024 + 1);
+-
+-      /*
+-       * Limit input seam position to make sure that the downsized input tile
+-       * to the right or bottom does not exceed 1024 pixels.
+-       */
+-      in_start = max_t(int, index * in_align,
+-                       in_edge - (1024 << downsize_coeff));
+-      in_end = min_t(unsigned int, in_edge,
+-                     index * (1024 << downsize_coeff) + 1);
+-
+-      /*
+-       * Output tiles must start at a multiple of 8 bytes horizontally and
+-       * possibly at an even line horizontally depending on the pixel format.
+-       * Only consider output aligned positions for the seam.
+-       */
+-      out_start = round_up(out_start, out_align);
+-      for (out_pos = out_start; out_pos < out_end; out_pos += out_align) {
+-              unsigned int in_pos;
+-              unsigned int in_pos_aligned;
+-              unsigned int in_pos_rounded;
+-              unsigned int abs_diff;
+-
+-              /*
+-               * Tiles in the right row / bottom column may not be allowed to
+-               * overshoot horizontally / vertically. out_burst may be the
+-               * actual DMA burst size, or the rotator block size.
+-               */
+-              if ((out_burst > 1) && (out_edge - out_pos) % out_burst)
+-                      continue;
+-
+-              /*
+-               * Input sample position, corresponding to out_pos, 19.13 fixed
+-               * point.
+-               */
+-              in_pos = (out_pos * resize_coeff) << downsize_coeff;
+-              /*
+-               * The closest input sample position that we could actually
+-               * start the input tile at, 19.13 fixed point.
+-               */
+-              in_pos_aligned = round_closest(in_pos, 8192U * in_align);
+-              /* Convert 19.13 fixed point to integer */
+-              in_pos_rounded = in_pos_aligned / 8192U;
+-
+-              if (in_pos_rounded < in_start)
+-                      continue;
+-              if (in_pos_rounded >= in_end)
+-                      break;
+-
+-              if ((in_burst > 1) &&
+-                  (in_edge - in_pos_rounded) % in_burst)
+-                      continue;
+-
+-              if (in_pos < in_pos_aligned)
+-                      abs_diff = in_pos_aligned - in_pos;
+-              else
+-                      abs_diff = in_pos - in_pos_aligned;
+-
+-              if (abs_diff < min_diff) {
+-                      in_seam = in_pos_rounded;
+-                      out_seam = out_pos;
+-                      min_diff = abs_diff;
+-              }
+-      }
+-
+-      *_out_seam = out_seam;
+-      *_in_seam = in_seam;
+-
+-      dev_dbg(dev, "%s: out_seam %u(%u) in [%u, %u], in_seam %u(%u) in [%u, %u] diff %u.%03u\n",
+-              __func__, out_seam, out_align, out_start, out_end,
+-              in_seam, in_align, in_start, in_end, min_diff / 8192,
+-              DIV_ROUND_CLOSEST(min_diff % 8192 * 1000, 8192));
+-}
+-
+-/*
+- * Tile left edges are required to be aligned to multiples of 8 bytes
+- * by the IDMAC.
+- */
+-static inline u32 tile_left_align(const struct ipu_image_pixfmt *fmt)
+-{
+-      if (fmt->planar)
+-              return fmt->uv_packed ? 8 : 8 * fmt->uv_width_dec;
+-      else
+-              return fmt->bpp == 32 ? 2 : fmt->bpp == 16 ? 4 : 8;
+-}
+-
+-/*
+- * Tile top edge alignment is only limited by chroma subsampling.
+- */
+-static inline u32 tile_top_align(const struct ipu_image_pixfmt *fmt)
+-{
+-      return fmt->uv_height_dec > 1 ? 2 : 1;
+-}
+-
+-static inline u32 tile_width_align(enum ipu_image_convert_type type,
+-                                 const struct ipu_image_pixfmt *fmt,
+-                                 enum ipu_rotate_mode rot_mode)
+-{
+-      if (type == IMAGE_CONVERT_IN) {
+-              /*
+-               * The IC burst reads 8 pixels at a time. Reading beyond the
+-               * end of the line is usually acceptable. Those pixels are
+-               * ignored, unless the IC has to write the scaled line in
+-               * reverse.
+-               */
+-              return (!ipu_rot_mode_is_irt(rot_mode) &&
+-                      (rot_mode & IPU_ROT_BIT_HFLIP)) ? 8 : 2;
+-      }
+-
+-      /*
+-       * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
+-       * formats to guarantee 8-byte aligned line start addresses in the
+-       * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
+-       * for all other formats.
+-       */
+-      return (ipu_rot_mode_is_irt(rot_mode) &&
+-              fmt->planar && !fmt->uv_packed) ?
+-              8 * fmt->uv_width_dec : 8;
+-}
+-
+-static inline u32 tile_height_align(enum ipu_image_convert_type type,
+-                                  const struct ipu_image_pixfmt *fmt,
+-                                  enum ipu_rotate_mode rot_mode)
+-{
+-      if (type == IMAGE_CONVERT_IN || !ipu_rot_mode_is_irt(rot_mode))
+-              return 2;
+-
+-      /*
+-       * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
+-       * formats to guarantee 8-byte aligned line start addresses in the
+-       * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
+-       * for all other formats.
+-       */
+-      return (fmt->planar && !fmt->uv_packed) ? 8 * fmt->uv_width_dec : 8;
+-}
+-
+-/*
+- * Fill in left position and width and for all tiles in an input column, and
+- * for all corresponding output tiles. If the 90° rotator is used, the output
+- * tiles are in a row, and output tile top position and height are set.
+- */
+-static void fill_tile_column(struct ipu_image_convert_ctx *ctx,
+-                           unsigned int col,
+-                           struct ipu_image_convert_image *in,
+-                           unsigned int in_left, unsigned int in_width,
+-                           struct ipu_image_convert_image *out,
+-                           unsigned int out_left, unsigned int out_width)
+-{
+-      unsigned int row, tile_idx;
+-      struct ipu_image_tile *in_tile, *out_tile;
+-
+-      for (row = 0; row < in->num_rows; row++) {
+-              tile_idx = in->num_cols * row + col;
+-              in_tile = &in->tile[tile_idx];
+-              out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
+-
+-              in_tile->left = in_left;
+-              in_tile->width = in_width;
+-
+-              if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-                      out_tile->top = out_left;
+-                      out_tile->height = out_width;
+-              } else {
+-                      out_tile->left = out_left;
+-                      out_tile->width = out_width;
+-              }
+-      }
+-}
+-
+-/*
+- * Fill in top position and height and for all tiles in an input row, and
+- * for all corresponding output tiles. If the 90° rotator is used, the output
+- * tiles are in a column, and output tile left position and width are set.
+- */
+-static void fill_tile_row(struct ipu_image_convert_ctx *ctx, unsigned int row,
+-                        struct ipu_image_convert_image *in,
+-                        unsigned int in_top, unsigned int in_height,
+-                        struct ipu_image_convert_image *out,
+-                        unsigned int out_top, unsigned int out_height)
+-{
+-      unsigned int col, tile_idx;
+-      struct ipu_image_tile *in_tile, *out_tile;
+-
+-      for (col = 0; col < in->num_cols; col++) {
+-              tile_idx = in->num_cols * row + col;
+-              in_tile = &in->tile[tile_idx];
+-              out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
+-
+-              in_tile->top = in_top;
+-              in_tile->height = in_height;
+-
+-              if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-                      out_tile->left = out_top;
+-                      out_tile->width = out_height;
+-              } else {
+-                      out_tile->top = out_top;
+-                      out_tile->height = out_height;
+-              }
+-      }
+-}
+-
+-/*
+- * Find the best horizontal and vertical seam positions to split into tiles.
+- * Minimize the fractional part of the input sampling position for the
+- * top / left pixels of each tile.
+- */
+-static void find_seams(struct ipu_image_convert_ctx *ctx,
+-                     struct ipu_image_convert_image *in,
+-                     struct ipu_image_convert_image *out)
+-{
+-      struct device *dev = ctx->chan->priv->ipu->dev;
+-      unsigned int resized_width = out->base.rect.width;
+-      unsigned int resized_height = out->base.rect.height;
+-      unsigned int col;
+-      unsigned int row;
+-      unsigned int in_left_align = tile_left_align(in->fmt);
+-      unsigned int in_top_align = tile_top_align(in->fmt);
+-      unsigned int out_left_align = tile_left_align(out->fmt);
+-      unsigned int out_top_align = tile_top_align(out->fmt);
+-      unsigned int out_width_align = tile_width_align(out->type, out->fmt,
+-                                                      ctx->rot_mode);
+-      unsigned int out_height_align = tile_height_align(out->type, out->fmt,
+-                                                        ctx->rot_mode);
+-      unsigned int in_right = in->base.rect.width;
+-      unsigned int in_bottom = in->base.rect.height;
+-      unsigned int out_right = out->base.rect.width;
+-      unsigned int out_bottom = out->base.rect.height;
+-      unsigned int flipped_out_left;
+-      unsigned int flipped_out_top;
+-
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              /* Switch width/height and align top left to IRT block size */
+-              resized_width = out->base.rect.height;
+-              resized_height = out->base.rect.width;
+-              out_left_align = out_height_align;
+-              out_top_align = out_width_align;
+-              out_width_align = out_left_align;
+-              out_height_align = out_top_align;
+-              out_right = out->base.rect.height;
+-              out_bottom = out->base.rect.width;
+-      }
+-
+-      for (col = in->num_cols - 1; col > 0; col--) {
+-              bool allow_in_overshoot = ipu_rot_mode_is_irt(ctx->rot_mode) ||
+-                                        !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
+-              bool allow_out_overshoot = (col < in->num_cols - 1) &&
+-                                         !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
+-              unsigned int in_left;
+-              unsigned int out_left;
+-
+-              /*
+-               * Align input width to burst length if the scaling step flips
+-               * horizontally.
+-               */
+-
+-              find_best_seam(ctx, col,
+-                             in_right, out_right,
+-                             in_left_align, out_left_align,
+-                             allow_in_overshoot ? 1 : 8 /* burst length */,
+-                             allow_out_overshoot ? 1 : out_width_align,
+-                             ctx->downsize_coeff_h, ctx->image_resize_coeff_h,
+-                             &in_left, &out_left);
+-
+-              if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
+-                      flipped_out_left = resized_width - out_right;
+-              else
+-                      flipped_out_left = out_left;
+-
+-              fill_tile_column(ctx, col, in, in_left, in_right - in_left,
+-                               out, flipped_out_left, out_right - out_left);
+-
+-              dev_dbg(dev, "%s: col %u: %u, %u -> %u, %u\n", __func__, col,
+-                      in_left, in_right - in_left,
+-                      flipped_out_left, out_right - out_left);
+-
+-              in_right = in_left;
+-              out_right = out_left;
+-      }
+-
+-      flipped_out_left = (ctx->rot_mode & IPU_ROT_BIT_HFLIP) ?
+-                         resized_width - out_right : 0;
+-
+-      fill_tile_column(ctx, 0, in, 0, in_right,
+-                       out, flipped_out_left, out_right);
+-
+-      dev_dbg(dev, "%s: col 0: 0, %u -> %u, %u\n", __func__,
+-              in_right, flipped_out_left, out_right);
+-
+-      for (row = in->num_rows - 1; row > 0; row--) {
+-              bool allow_overshoot = row < in->num_rows - 1;
+-              unsigned int in_top;
+-              unsigned int out_top;
+-
+-              find_best_seam(ctx, row,
+-                             in_bottom, out_bottom,
+-                             in_top_align, out_top_align,
+-                             1, allow_overshoot ? 1 : out_height_align,
+-                             ctx->downsize_coeff_v, ctx->image_resize_coeff_v,
+-                             &in_top, &out_top);
+-
+-              if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
+-                  ipu_rot_mode_is_irt(ctx->rot_mode))
+-                      flipped_out_top = resized_height - out_bottom;
+-              else
+-                      flipped_out_top = out_top;
+-
+-              fill_tile_row(ctx, row, in, in_top, in_bottom - in_top,
+-                            out, flipped_out_top, out_bottom - out_top);
+-
+-              dev_dbg(dev, "%s: row %u: %u, %u -> %u, %u\n", __func__, row,
+-                      in_top, in_bottom - in_top,
+-                      flipped_out_top, out_bottom - out_top);
+-
+-              in_bottom = in_top;
+-              out_bottom = out_top;
+-      }
+-
+-      if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
+-          ipu_rot_mode_is_irt(ctx->rot_mode))
+-              flipped_out_top = resized_height - out_bottom;
+-      else
+-              flipped_out_top = 0;
+-
+-      fill_tile_row(ctx, 0, in, 0, in_bottom,
+-                    out, flipped_out_top, out_bottom);
+-
+-      dev_dbg(dev, "%s: row 0: 0, %u -> %u, %u\n", __func__,
+-              in_bottom, flipped_out_top, out_bottom);
+-}
+-
+-static int calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
+-                              struct ipu_image_convert_image *image)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      unsigned int max_width = 1024;
+-      unsigned int max_height = 1024;
+-      unsigned int i;
+-
+-      if (image->type == IMAGE_CONVERT_IN) {
+-              /* Up to 4096x4096 input tile size */
+-              max_width <<= ctx->downsize_coeff_h;
+-              max_height <<= ctx->downsize_coeff_v;
+-      }
+-
+-      for (i = 0; i < ctx->num_tiles; i++) {
+-              struct ipu_image_tile *tile;
+-              const unsigned int row = i / image->num_cols;
+-              const unsigned int col = i % image->num_cols;
+-
+-              if (image->type == IMAGE_CONVERT_OUT)
+-                      tile = &image->tile[ctx->out_tile_map[i]];
+-              else
+-                      tile = &image->tile[i];
+-
+-              tile->size = ((tile->height * image->fmt->bpp) >> 3) *
+-                      tile->width;
+-
+-              if (image->fmt->planar) {
+-                      tile->stride = tile->width;
+-                      tile->rot_stride = tile->height;
+-              } else {
+-                      tile->stride =
+-                              (image->fmt->bpp * tile->width) >> 3;
+-                      tile->rot_stride =
+-                              (image->fmt->bpp * tile->height) >> 3;
+-              }
+-
+-              dev_dbg(priv->ipu->dev,
+-                      "task %u: ctx %p: %s@[%u,%u]: %ux%u@%u,%u\n",
+-                      chan->ic_task, ctx,
+-                      image->type == IMAGE_CONVERT_IN ? "Input" : "Output",
+-                      row, col,
+-                      tile->width, tile->height, tile->left, tile->top);
+-
+-              if (!tile->width || tile->width > max_width ||
+-                  !tile->height || tile->height > max_height) {
+-                      dev_err(priv->ipu->dev, "invalid %s tile size: %ux%u\n",
+-                              image->type == IMAGE_CONVERT_IN ? "input" :
+-                              "output", tile->width, tile->height);
+-                      return -EINVAL;
+-              }
+-      }
+-
+-      return 0;
+-}
+-
+-/*
+- * Use the rotation transformation to find the tile coordinates
+- * (row, col) of a tile in the destination frame that corresponds
+- * to the given tile coordinates of a source frame. The destination
+- * coordinate is then converted to a tile index.
+- */
+-static int transform_tile_index(struct ipu_image_convert_ctx *ctx,
+-                              int src_row, int src_col)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_convert_image *s_image = &ctx->in;
+-      struct ipu_image_convert_image *d_image = &ctx->out;
+-      int dst_row, dst_col;
+-
+-      /* with no rotation it's a 1:1 mapping */
+-      if (ctx->rot_mode == IPU_ROTATE_NONE)
+-              return src_row * s_image->num_cols + src_col;
+-
+-      /*
+-       * before doing the transform, first we have to translate
+-       * source row,col for an origin in the center of s_image
+-       */
+-      src_row = src_row * 2 - (s_image->num_rows - 1);
+-      src_col = src_col * 2 - (s_image->num_cols - 1);
+-
+-      /* do the rotation transform */
+-      if (ctx->rot_mode & IPU_ROT_BIT_90) {
+-              dst_col = -src_row;
+-              dst_row = src_col;
+-      } else {
+-              dst_col = src_col;
+-              dst_row = src_row;
+-      }
+-
+-      /* apply flip */
+-      if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
+-              dst_col = -dst_col;
+-      if (ctx->rot_mode & IPU_ROT_BIT_VFLIP)
+-              dst_row = -dst_row;
+-
+-      dev_dbg(priv->ipu->dev, "task %u: ctx %p: [%d,%d] --> [%d,%d]\n",
+-              chan->ic_task, ctx, src_col, src_row, dst_col, dst_row);
+-
+-      /*
+-       * finally translate dest row,col using an origin in upper
+-       * left of d_image
+-       */
+-      dst_row += d_image->num_rows - 1;
+-      dst_col += d_image->num_cols - 1;
+-      dst_row /= 2;
+-      dst_col /= 2;
+-
+-      return dst_row * d_image->num_cols + dst_col;
+-}
+-
+-/*
+- * Fill the out_tile_map[] with transformed destination tile indeces.
+- */
+-static void calc_out_tile_map(struct ipu_image_convert_ctx *ctx)
+-{
+-      struct ipu_image_convert_image *s_image = &ctx->in;
+-      unsigned int row, col, tile = 0;
+-
+-      for (row = 0; row < s_image->num_rows; row++) {
+-              for (col = 0; col < s_image->num_cols; col++) {
+-                      ctx->out_tile_map[tile] =
+-                              transform_tile_index(ctx, row, col);
+-                      tile++;
+-              }
+-      }
+-}
+-
+-static int calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
+-                                  struct ipu_image_convert_image *image)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      const struct ipu_image_pixfmt *fmt = image->fmt;
+-      unsigned int row, col, tile = 0;
+-      u32 H, top, y_stride, uv_stride;
+-      u32 uv_row_off, uv_col_off, uv_off, u_off, v_off, tmp;
+-      u32 y_row_off, y_col_off, y_off;
+-      u32 y_size, uv_size;
+-
+-      /* setup some convenience vars */
+-      H = image->base.pix.height;
+-
+-      y_stride = image->stride;
+-      uv_stride = y_stride / fmt->uv_width_dec;
+-      if (fmt->uv_packed)
+-              uv_stride *= 2;
+-
+-      y_size = H * y_stride;
+-      uv_size = y_size / (fmt->uv_width_dec * fmt->uv_height_dec);
+-
+-      for (row = 0; row < image->num_rows; row++) {
+-              top = image->tile[tile].top;
+-              y_row_off = top * y_stride;
+-              uv_row_off = (top * uv_stride) / fmt->uv_height_dec;
+-
+-              for (col = 0; col < image->num_cols; col++) {
+-                      y_col_off = image->tile[tile].left;
+-                      uv_col_off = y_col_off / fmt->uv_width_dec;
+-                      if (fmt->uv_packed)
+-                              uv_col_off *= 2;
+-
+-                      y_off = y_row_off + y_col_off;
+-                      uv_off = uv_row_off + uv_col_off;
+-
+-                      u_off = y_size - y_off + uv_off;
+-                      v_off = (fmt->uv_packed) ? 0 : u_off + uv_size;
+-                      if (fmt->uv_swapped) {
+-                              tmp = u_off;
+-                              u_off = v_off;
+-                              v_off = tmp;
+-                      }
+-
+-                      image->tile[tile].offset = y_off;
+-                      image->tile[tile].u_off = u_off;
+-                      image->tile[tile++].v_off = v_off;
+-
+-                      if ((y_off & 0x7) || (u_off & 0x7) || (v_off & 0x7)) {
+-                              dev_err(priv->ipu->dev,
+-                                      "task %u: ctx %p: %s@[%d,%d]: "
+-                                      "y_off %08x, u_off %08x, v_off %08x\n",
+-                                      chan->ic_task, ctx,
+-                                      image->type == IMAGE_CONVERT_IN ?
+-                                      "Input" : "Output", row, col,
+-                                      y_off, u_off, v_off);
+-                              return -EINVAL;
+-                      }
+-              }
+-      }
+-
+-      return 0;
+-}
+-
+-static int calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
+-                                  struct ipu_image_convert_image *image)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      const struct ipu_image_pixfmt *fmt = image->fmt;
+-      unsigned int row, col, tile = 0;
+-      u32 bpp, stride, offset;
+-      u32 row_off, col_off;
+-
+-      /* setup some convenience vars */
+-      stride = image->stride;
+-      bpp = fmt->bpp;
+-
+-      for (row = 0; row < image->num_rows; row++) {
+-              row_off = image->tile[tile].top * stride;
+-
+-              for (col = 0; col < image->num_cols; col++) {
+-                      col_off = (image->tile[tile].left * bpp) >> 3;
+-
+-                      offset = row_off + col_off;
+-
+-                      image->tile[tile].offset = offset;
+-                      image->tile[tile].u_off = 0;
+-                      image->tile[tile++].v_off = 0;
+-
+-                      if (offset & 0x7) {
+-                              dev_err(priv->ipu->dev,
+-                                      "task %u: ctx %p: %s@[%d,%d]: "
+-                                      "phys %08x\n",
+-                                      chan->ic_task, ctx,
+-                                      image->type == IMAGE_CONVERT_IN ?
+-                                      "Input" : "Output", row, col,
+-                                      row_off + col_off);
+-                              return -EINVAL;
+-                      }
+-              }
+-      }
+-
+-      return 0;
+-}
+-
+-static int calc_tile_offsets(struct ipu_image_convert_ctx *ctx,
+-                            struct ipu_image_convert_image *image)
+-{
+-      if (image->fmt->planar)
+-              return calc_tile_offsets_planar(ctx, image);
+-
+-      return calc_tile_offsets_packed(ctx, image);
+-}
+-
+-/*
+- * Calculate the resizing ratio for the IC main processing section given input
+- * size, fixed downsizing coefficient, and output size.
+- * Either round to closest for the next tile's first pixel to minimize seams
+- * and distortion (for all but right column / bottom row), or round down to
+- * avoid sampling beyond the edges of the input image for this tile's last
+- * pixel.
+- * Returns the resizing coefficient, resizing ratio is 8192.0 / resize_coeff.
+- */
+-static u32 calc_resize_coeff(u32 input_size, u32 downsize_coeff,
+-                           u32 output_size, bool allow_overshoot)
+-{
+-      u32 downsized = input_size >> downsize_coeff;
+-
+-      if (allow_overshoot)
+-              return DIV_ROUND_CLOSEST(8192 * downsized, output_size);
+-      else
+-              return 8192 * (downsized - 1) / (output_size - 1);
+-}
+-
+-/*
+- * Slightly modify resize coefficients per tile to hide the bilinear
+- * interpolator reset at tile borders, shifting the right / bottom edge
+- * by up to a half input pixel. This removes noticeable seams between
+- * tiles at higher upscaling factors.
+- */
+-static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_tile *in_tile, *out_tile;
+-      unsigned int col, row, tile_idx;
+-      unsigned int last_output;
+-
+-      for (col = 0; col < ctx->in.num_cols; col++) {
+-              bool closest = (col < ctx->in.num_cols - 1) &&
+-                             !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
+-              u32 resized_width;
+-              u32 resize_coeff_h;
+-              u32 in_width;
+-
+-              tile_idx = col;
+-              in_tile = &ctx->in.tile[tile_idx];
+-              out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
+-
+-              if (ipu_rot_mode_is_irt(ctx->rot_mode))
+-                      resized_width = out_tile->height;
+-              else
+-                      resized_width = out_tile->width;
+-
+-              resize_coeff_h = calc_resize_coeff(in_tile->width,
+-                                                 ctx->downsize_coeff_h,
+-                                                 resized_width, closest);
+-
+-              dev_dbg(priv->ipu->dev, "%s: column %u hscale: *8192/%u\n",
+-                      __func__, col, resize_coeff_h);
+-
+-              /*
+-               * With the horizontal scaling factor known, round up resized
+-               * width (output width or height) to burst size.
+-               */
+-              resized_width = round_up(resized_width, 8);
+-
+-              /*
+-               * Calculate input width from the last accessed input pixel
+-               * given resized width and scaling coefficients. Round up to
+-               * burst size.
+-               */
+-              last_output = resized_width - 1;
+-              if (closest && ((last_output * resize_coeff_h) % 8192))
+-                      last_output++;
+-              in_width = round_up(
+-                      (DIV_ROUND_UP(last_output * resize_coeff_h, 8192) + 1)
+-                      << ctx->downsize_coeff_h, 8);
+-
+-              for (row = 0; row < ctx->in.num_rows; row++) {
+-                      tile_idx = row * ctx->in.num_cols + col;
+-                      in_tile = &ctx->in.tile[tile_idx];
+-                      out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
+-
+-                      if (ipu_rot_mode_is_irt(ctx->rot_mode))
+-                              out_tile->height = resized_width;
+-                      else
+-                              out_tile->width = resized_width;
+-
+-                      in_tile->width = in_width;
+-              }
+-
+-              ctx->resize_coeffs_h[col] = resize_coeff_h;
+-      }
+-
+-      for (row = 0; row < ctx->in.num_rows; row++) {
+-              bool closest = (row < ctx->in.num_rows - 1) &&
+-                             !(ctx->rot_mode & IPU_ROT_BIT_VFLIP);
+-              u32 resized_height;
+-              u32 resize_coeff_v;
+-              u32 in_height;
+-
+-              tile_idx = row * ctx->in.num_cols;
+-              in_tile = &ctx->in.tile[tile_idx];
+-              out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
+-
+-              if (ipu_rot_mode_is_irt(ctx->rot_mode))
+-                      resized_height = out_tile->width;
+-              else
+-                      resized_height = out_tile->height;
+-
+-              resize_coeff_v = calc_resize_coeff(in_tile->height,
+-                                                 ctx->downsize_coeff_v,
+-                                                 resized_height, closest);
+-
+-              dev_dbg(priv->ipu->dev, "%s: row %u vscale: *8192/%u\n",
+-                      __func__, row, resize_coeff_v);
+-
+-              /*
+-               * With the vertical scaling factor known, round up resized
+-               * height (output width or height) to IDMAC limitations.
+-               */
+-              resized_height = round_up(resized_height, 2);
+-
+-              /*
+-               * Calculate input width from the last accessed input pixel
+-               * given resized height and scaling coefficients. Align to
+-               * IDMAC restrictions.
+-               */
+-              last_output = resized_height - 1;
+-              if (closest && ((last_output * resize_coeff_v) % 8192))
+-                      last_output++;
+-              in_height = round_up(
+-                      (DIV_ROUND_UP(last_output * resize_coeff_v, 8192) + 1)
+-                      << ctx->downsize_coeff_v, 2);
+-
+-              for (col = 0; col < ctx->in.num_cols; col++) {
+-                      tile_idx = row * ctx->in.num_cols + col;
+-                      in_tile = &ctx->in.tile[tile_idx];
+-                      out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
+-
+-                      if (ipu_rot_mode_is_irt(ctx->rot_mode))
+-                              out_tile->width = resized_height;
+-                      else
+-                              out_tile->height = resized_height;
+-
+-                      in_tile->height = in_height;
+-              }
+-
+-              ctx->resize_coeffs_v[row] = resize_coeff_v;
+-      }
+-}
+-
+-/*
+- * return the number of runs in given queue (pending_q or done_q)
+- * for this context. hold irqlock when calling.
+- */
+-static int get_run_count(struct ipu_image_convert_ctx *ctx,
+-                       struct list_head *q)
+-{
+-      struct ipu_image_convert_run *run;
+-      int count = 0;
+-
+-      lockdep_assert_held(&ctx->chan->irqlock);
+-
+-      list_for_each_entry(run, q, list) {
+-              if (run->ctx == ctx)
+-                      count++;
+-      }
+-
+-      return count;
+-}
+-
+-static void convert_stop(struct ipu_image_convert_run *run)
+-{
+-      struct ipu_image_convert_ctx *ctx = run->ctx;
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-
+-      dev_dbg(priv->ipu->dev, "%s: task %u: stopping ctx %p run %p\n",
+-              __func__, chan->ic_task, ctx, run);
+-
+-      /* disable IC tasks and the channels */
+-      ipu_ic_task_disable(chan->ic);
+-      ipu_idmac_disable_channel(chan->in_chan);
+-      ipu_idmac_disable_channel(chan->out_chan);
+-
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              ipu_idmac_disable_channel(chan->rotation_in_chan);
+-              ipu_idmac_disable_channel(chan->rotation_out_chan);
+-              ipu_idmac_unlink(chan->out_chan, chan->rotation_in_chan);
+-      }
+-
+-      ipu_ic_disable(chan->ic);
+-}
+-
+-static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
+-                             struct ipuv3_channel *channel,
+-                             struct ipu_image_convert_image *image,
+-                             enum ipu_rotate_mode rot_mode,
+-                             bool rot_swap_width_height,
+-                             unsigned int tile)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      unsigned int burst_size;
+-      u32 width, height, stride;
+-      dma_addr_t addr0, addr1 = 0;
+-      struct ipu_image tile_image;
+-      unsigned int tile_idx[2];
+-
+-      if (image->type == IMAGE_CONVERT_OUT) {
+-              tile_idx[0] = ctx->out_tile_map[tile];
+-              tile_idx[1] = ctx->out_tile_map[1];
+-      } else {
+-              tile_idx[0] = tile;
+-              tile_idx[1] = 1;
+-      }
+-
+-      if (rot_swap_width_height) {
+-              width = image->tile[tile_idx[0]].height;
+-              height = image->tile[tile_idx[0]].width;
+-              stride = image->tile[tile_idx[0]].rot_stride;
+-              addr0 = ctx->rot_intermediate[0].phys;
+-              if (ctx->double_buffering)
+-                      addr1 = ctx->rot_intermediate[1].phys;
+-      } else {
+-              width = image->tile[tile_idx[0]].width;
+-              height = image->tile[tile_idx[0]].height;
+-              stride = image->stride;
+-              addr0 = image->base.phys0 +
+-                      image->tile[tile_idx[0]].offset;
+-              if (ctx->double_buffering)
+-                      addr1 = image->base.phys0 +
+-                              image->tile[tile_idx[1]].offset;
+-      }
+-
+-      ipu_cpmem_zero(channel);
+-
+-      memset(&tile_image, 0, sizeof(tile_image));
+-      tile_image.pix.width = tile_image.rect.width = width;
+-      tile_image.pix.height = tile_image.rect.height = height;
+-      tile_image.pix.bytesperline = stride;
+-      tile_image.pix.pixelformat =  image->fmt->fourcc;
+-      tile_image.phys0 = addr0;
+-      tile_image.phys1 = addr1;
+-      if (image->fmt->planar && !rot_swap_width_height) {
+-              tile_image.u_offset = image->tile[tile_idx[0]].u_off;
+-              tile_image.v_offset = image->tile[tile_idx[0]].v_off;
+-      }
+-
+-      ipu_cpmem_set_image(channel, &tile_image);
+-
+-      if (rot_mode)
+-              ipu_cpmem_set_rotation(channel, rot_mode);
+-
+-      /*
+-       * Skip writing U and V components to odd rows in the output
+-       * channels for planar 4:2:0.
+-       */
+-      if ((channel == chan->out_chan ||
+-           channel == chan->rotation_out_chan) &&
+-          image->fmt->planar && image->fmt->uv_height_dec == 2)
+-              ipu_cpmem_skip_odd_chroma_rows(channel);
+-
+-      if (channel == chan->rotation_in_chan ||
+-          channel == chan->rotation_out_chan) {
+-              burst_size = 8;
+-              ipu_cpmem_set_block_mode(channel);
+-      } else
+-              burst_size = (width % 16) ? 8 : 16;
+-
+-      ipu_cpmem_set_burstsize(channel, burst_size);
+-
+-      ipu_ic_task_idma_init(chan->ic, channel, width, height,
+-                            burst_size, rot_mode);
+-
+-      /*
+-       * Setting a non-zero AXI ID collides with the PRG AXI snooping, so
+-       * only do this when there is no PRG present.
+-       */
+-      if (!channel->ipu->prg_priv)
+-              ipu_cpmem_set_axi_id(channel, 1);
+-
+-      ipu_idmac_set_double_buffer(channel, ctx->double_buffering);
+-}
+-
+-static int convert_start(struct ipu_image_convert_run *run, unsigned int tile)
+-{
+-      struct ipu_image_convert_ctx *ctx = run->ctx;
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_convert_image *s_image = &ctx->in;
+-      struct ipu_image_convert_image *d_image = &ctx->out;
+-      unsigned int dst_tile = ctx->out_tile_map[tile];
+-      unsigned int dest_width, dest_height;
+-      unsigned int col, row;
+-      u32 rsc;
+-      int ret;
+-
+-      dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n",
+-              __func__, chan->ic_task, ctx, run, tile, dst_tile);
+-
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              /* swap width/height for resizer */
+-              dest_width = d_image->tile[dst_tile].height;
+-              dest_height = d_image->tile[dst_tile].width;
+-      } else {
+-              dest_width = d_image->tile[dst_tile].width;
+-              dest_height = d_image->tile[dst_tile].height;
+-      }
+-
+-      row = tile / s_image->num_cols;
+-      col = tile % s_image->num_cols;
+-
+-      rsc =  (ctx->downsize_coeff_v << 30) |
+-             (ctx->resize_coeffs_v[row] << 16) |
+-             (ctx->downsize_coeff_h << 14) |
+-             (ctx->resize_coeffs_h[col]);
+-
+-      dev_dbg(priv->ipu->dev, "%s: %ux%u -> %ux%u (rsc = 0x%x)\n",
+-              __func__, s_image->tile[tile].width,
+-              s_image->tile[tile].height, dest_width, dest_height, rsc);
+-
+-      /* setup the IC resizer and CSC */
+-      ret = ipu_ic_task_init_rsc(chan->ic, &ctx->csc,
+-                                 s_image->tile[tile].width,
+-                                 s_image->tile[tile].height,
+-                                 dest_width,
+-                                 dest_height,
+-                                 rsc);
+-      if (ret) {
+-              dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret);
+-              return ret;
+-      }
+-
+-      /* init the source MEM-->IC PP IDMAC channel */
+-      init_idmac_channel(ctx, chan->in_chan, s_image,
+-                         IPU_ROTATE_NONE, false, tile);
+-
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              /* init the IC PP-->MEM IDMAC channel */
+-              init_idmac_channel(ctx, chan->out_chan, d_image,
+-                                 IPU_ROTATE_NONE, true, tile);
+-
+-              /* init the MEM-->IC PP ROT IDMAC channel */
+-              init_idmac_channel(ctx, chan->rotation_in_chan, d_image,
+-                                 ctx->rot_mode, true, tile);
+-
+-              /* init the destination IC PP ROT-->MEM IDMAC channel */
+-              init_idmac_channel(ctx, chan->rotation_out_chan, d_image,
+-                                 IPU_ROTATE_NONE, false, tile);
+-
+-              /* now link IC PP-->MEM to MEM-->IC PP ROT */
+-              ipu_idmac_link(chan->out_chan, chan->rotation_in_chan);
+-      } else {
+-              /* init the destination IC PP-->MEM IDMAC channel */
+-              init_idmac_channel(ctx, chan->out_chan, d_image,
+-                                 ctx->rot_mode, false, tile);
+-      }
+-
+-      /* enable the IC */
+-      ipu_ic_enable(chan->ic);
+-
+-      /* set buffers ready */
+-      ipu_idmac_select_buffer(chan->in_chan, 0);
+-      ipu_idmac_select_buffer(chan->out_chan, 0);
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode))
+-              ipu_idmac_select_buffer(chan->rotation_out_chan, 0);
+-      if (ctx->double_buffering) {
+-              ipu_idmac_select_buffer(chan->in_chan, 1);
+-              ipu_idmac_select_buffer(chan->out_chan, 1);
+-              if (ipu_rot_mode_is_irt(ctx->rot_mode))
+-                      ipu_idmac_select_buffer(chan->rotation_out_chan, 1);
+-      }
+-
+-      /* enable the channels! */
+-      ipu_idmac_enable_channel(chan->in_chan);
+-      ipu_idmac_enable_channel(chan->out_chan);
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              ipu_idmac_enable_channel(chan->rotation_in_chan);
+-              ipu_idmac_enable_channel(chan->rotation_out_chan);
+-      }
+-
+-      ipu_ic_task_enable(chan->ic);
+-
+-      ipu_cpmem_dump(chan->in_chan);
+-      ipu_cpmem_dump(chan->out_chan);
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              ipu_cpmem_dump(chan->rotation_in_chan);
+-              ipu_cpmem_dump(chan->rotation_out_chan);
+-      }
+-
+-      ipu_dump(priv->ipu);
+-
+-      return 0;
+-}
+-
+-/* hold irqlock when calling */
+-static int do_run(struct ipu_image_convert_run *run)
+-{
+-      struct ipu_image_convert_ctx *ctx = run->ctx;
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-
+-      lockdep_assert_held(&chan->irqlock);
+-
+-      ctx->in.base.phys0 = run->in_phys;
+-      ctx->out.base.phys0 = run->out_phys;
+-
+-      ctx->cur_buf_num = 0;
+-      ctx->next_tile = 1;
+-
+-      /* remove run from pending_q and set as current */
+-      list_del(&run->list);
+-      chan->current_run = run;
+-
+-      return convert_start(run, 0);
+-}
+-
+-/* hold irqlock when calling */
+-static void run_next(struct ipu_image_convert_chan *chan)
+-{
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_convert_run *run, *tmp;
+-      int ret;
+-
+-      lockdep_assert_held(&chan->irqlock);
+-
+-      list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
+-              /* skip contexts that are aborting */
+-              if (run->ctx->aborting) {
+-                      dev_dbg(priv->ipu->dev,
+-                              "%s: task %u: skipping aborting ctx %p run %p\n",
+-                              __func__, chan->ic_task, run->ctx, run);
+-                      continue;
+-              }
+-
+-              ret = do_run(run);
+-              if (!ret)
+-                      break;
+-
+-              /*
+-               * something went wrong with start, add the run
+-               * to done q and continue to the next run in the
+-               * pending q.
+-               */
+-              run->status = ret;
+-              list_add_tail(&run->list, &chan->done_q);
+-              chan->current_run = NULL;
+-      }
+-}
+-
+-static void empty_done_q(struct ipu_image_convert_chan *chan)
+-{
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_convert_run *run;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      while (!list_empty(&chan->done_q)) {
+-              run = list_entry(chan->done_q.next,
+-                               struct ipu_image_convert_run,
+-                               list);
+-
+-              list_del(&run->list);
+-
+-              dev_dbg(priv->ipu->dev,
+-                      "%s: task %u: completing ctx %p run %p with %d\n",
+-                      __func__, chan->ic_task, run->ctx, run, run->status);
+-
+-              /* call the completion callback and free the run */
+-              spin_unlock_irqrestore(&chan->irqlock, flags);
+-              run->ctx->complete(run, run->ctx->complete_context);
+-              spin_lock_irqsave(&chan->irqlock, flags);
+-      }
+-
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-}
+-
+-/*
+- * the bottom half thread clears out the done_q, calling the
+- * completion handler for each.
+- */
+-static irqreturn_t do_bh(int irq, void *dev_id)
+-{
+-      struct ipu_image_convert_chan *chan = dev_id;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_convert_ctx *ctx;
+-      unsigned long flags;
+-
+-      dev_dbg(priv->ipu->dev, "%s: task %u: enter\n", __func__,
+-              chan->ic_task);
+-
+-      empty_done_q(chan);
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      /*
+-       * the done_q is cleared out, signal any contexts
+-       * that are aborting that abort can complete.
+-       */
+-      list_for_each_entry(ctx, &chan->ctx_list, list) {
+-              if (ctx->aborting) {
+-                      dev_dbg(priv->ipu->dev,
+-                              "%s: task %u: signaling abort for ctx %p\n",
+-                              __func__, chan->ic_task, ctx);
+-                      complete_all(&ctx->aborted);
+-              }
+-      }
+-
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-
+-      dev_dbg(priv->ipu->dev, "%s: task %u: exit\n", __func__,
+-              chan->ic_task);
+-
+-      return IRQ_HANDLED;
+-}
+-
+-static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx)
+-{
+-      unsigned int cur_tile = ctx->next_tile - 1;
+-      unsigned int next_tile = ctx->next_tile;
+-
+-      if (ctx->resize_coeffs_h[cur_tile % ctx->in.num_cols] !=
+-          ctx->resize_coeffs_h[next_tile % ctx->in.num_cols] ||
+-          ctx->resize_coeffs_v[cur_tile / ctx->in.num_cols] !=
+-          ctx->resize_coeffs_v[next_tile / ctx->in.num_cols] ||
+-          ctx->in.tile[cur_tile].width != ctx->in.tile[next_tile].width ||
+-          ctx->in.tile[cur_tile].height != ctx->in.tile[next_tile].height ||
+-          ctx->out.tile[cur_tile].width != ctx->out.tile[next_tile].width ||
+-          ctx->out.tile[cur_tile].height != ctx->out.tile[next_tile].height)
+-              return true;
+-
+-      return false;
+-}
+-
+-/* hold irqlock when calling */
+-static irqreturn_t do_irq(struct ipu_image_convert_run *run)
+-{
+-      struct ipu_image_convert_ctx *ctx = run->ctx;
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_tile *src_tile, *dst_tile;
+-      struct ipu_image_convert_image *s_image = &ctx->in;
+-      struct ipu_image_convert_image *d_image = &ctx->out;
+-      struct ipuv3_channel *outch;
+-      unsigned int dst_idx;
+-
+-      lockdep_assert_held(&chan->irqlock);
+-
+-      outch = ipu_rot_mode_is_irt(ctx->rot_mode) ?
+-              chan->rotation_out_chan : chan->out_chan;
+-
+-      /*
+-       * It is difficult to stop the channel DMA before the channels
+-       * enter the paused state. Without double-buffering the channels
+-       * are always in a paused state when the EOF irq occurs, so it
+-       * is safe to stop the channels now. For double-buffering we
+-       * just ignore the abort until the operation completes, when it
+-       * is safe to shut down.
+-       */
+-      if (ctx->aborting && !ctx->double_buffering) {
+-              convert_stop(run);
+-              run->status = -EIO;
+-              goto done;
+-      }
+-
+-      if (ctx->next_tile == ctx->num_tiles) {
+-              /*
+-               * the conversion is complete
+-               */
+-              convert_stop(run);
+-              run->status = 0;
+-              goto done;
+-      }
+-
+-      /*
+-       * not done, place the next tile buffers.
+-       */
+-      if (!ctx->double_buffering) {
+-              if (ic_settings_changed(ctx)) {
+-                      convert_stop(run);
+-                      convert_start(run, ctx->next_tile);
+-              } else {
+-                      src_tile = &s_image->tile[ctx->next_tile];
+-                      dst_idx = ctx->out_tile_map[ctx->next_tile];
+-                      dst_tile = &d_image->tile[dst_idx];
+-
+-                      ipu_cpmem_set_buffer(chan->in_chan, 0,
+-                                           s_image->base.phys0 +
+-                                           src_tile->offset);
+-                      ipu_cpmem_set_buffer(outch, 0,
+-                                           d_image->base.phys0 +
+-                                           dst_tile->offset);
+-                      if (s_image->fmt->planar)
+-                              ipu_cpmem_set_uv_offset(chan->in_chan,
+-                                                      src_tile->u_off,
+-                                                      src_tile->v_off);
+-                      if (d_image->fmt->planar)
+-                              ipu_cpmem_set_uv_offset(outch,
+-                                                      dst_tile->u_off,
+-                                                      dst_tile->v_off);
+-
+-                      ipu_idmac_select_buffer(chan->in_chan, 0);
+-                      ipu_idmac_select_buffer(outch, 0);
+-              }
+-      } else if (ctx->next_tile < ctx->num_tiles - 1) {
+-
+-              src_tile = &s_image->tile[ctx->next_tile + 1];
+-              dst_idx = ctx->out_tile_map[ctx->next_tile + 1];
+-              dst_tile = &d_image->tile[dst_idx];
+-
+-              ipu_cpmem_set_buffer(chan->in_chan, ctx->cur_buf_num,
+-                                   s_image->base.phys0 + src_tile->offset);
+-              ipu_cpmem_set_buffer(outch, ctx->cur_buf_num,
+-                                   d_image->base.phys0 + dst_tile->offset);
+-
+-              ipu_idmac_select_buffer(chan->in_chan, ctx->cur_buf_num);
+-              ipu_idmac_select_buffer(outch, ctx->cur_buf_num);
+-
+-              ctx->cur_buf_num ^= 1;
+-      }
+-
+-      ctx->next_tile++;
+-      return IRQ_HANDLED;
+-done:
+-      list_add_tail(&run->list, &chan->done_q);
+-      chan->current_run = NULL;
+-      run_next(chan);
+-      return IRQ_WAKE_THREAD;
+-}
+-
+-static irqreturn_t norotate_irq(int irq, void *data)
+-{
+-      struct ipu_image_convert_chan *chan = data;
+-      struct ipu_image_convert_ctx *ctx;
+-      struct ipu_image_convert_run *run;
+-      unsigned long flags;
+-      irqreturn_t ret;
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      /* get current run and its context */
+-      run = chan->current_run;
+-      if (!run) {
+-              ret = IRQ_NONE;
+-              goto out;
+-      }
+-
+-      ctx = run->ctx;
+-
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              /* this is a rotation operation, just ignore */
+-              spin_unlock_irqrestore(&chan->irqlock, flags);
+-              return IRQ_HANDLED;
+-      }
+-
+-      ret = do_irq(run);
+-out:
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-      return ret;
+-}
+-
+-static irqreturn_t rotate_irq(int irq, void *data)
+-{
+-      struct ipu_image_convert_chan *chan = data;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_convert_ctx *ctx;
+-      struct ipu_image_convert_run *run;
+-      unsigned long flags;
+-      irqreturn_t ret;
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      /* get current run and its context */
+-      run = chan->current_run;
+-      if (!run) {
+-              ret = IRQ_NONE;
+-              goto out;
+-      }
+-
+-      ctx = run->ctx;
+-
+-      if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              /* this was NOT a rotation operation, shouldn't happen */
+-              dev_err(priv->ipu->dev, "Unexpected rotation interrupt\n");
+-              spin_unlock_irqrestore(&chan->irqlock, flags);
+-              return IRQ_HANDLED;
+-      }
+-
+-      ret = do_irq(run);
+-out:
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-      return ret;
+-}
+-
+-/*
+- * try to force the completion of runs for this ctx. Called when
+- * abort wait times out in ipu_image_convert_abort().
+- */
+-static void force_abort(struct ipu_image_convert_ctx *ctx)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_run *run;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      run = chan->current_run;
+-      if (run && run->ctx == ctx) {
+-              convert_stop(run);
+-              run->status = -EIO;
+-              list_add_tail(&run->list, &chan->done_q);
+-              chan->current_run = NULL;
+-              run_next(chan);
+-      }
+-
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-
+-      empty_done_q(chan);
+-}
+-
+-static void release_ipu_resources(struct ipu_image_convert_chan *chan)
+-{
+-      if (chan->out_eof_irq >= 0)
+-              free_irq(chan->out_eof_irq, chan);
+-      if (chan->rot_out_eof_irq >= 0)
+-              free_irq(chan->rot_out_eof_irq, chan);
+-
+-      if (!IS_ERR_OR_NULL(chan->in_chan))
+-              ipu_idmac_put(chan->in_chan);
+-      if (!IS_ERR_OR_NULL(chan->out_chan))
+-              ipu_idmac_put(chan->out_chan);
+-      if (!IS_ERR_OR_NULL(chan->rotation_in_chan))
+-              ipu_idmac_put(chan->rotation_in_chan);
+-      if (!IS_ERR_OR_NULL(chan->rotation_out_chan))
+-              ipu_idmac_put(chan->rotation_out_chan);
+-      if (!IS_ERR_OR_NULL(chan->ic))
+-              ipu_ic_put(chan->ic);
+-
+-      chan->in_chan = chan->out_chan = chan->rotation_in_chan =
+-              chan->rotation_out_chan = NULL;
+-      chan->out_eof_irq = chan->rot_out_eof_irq = -1;
+-}
+-
+-static int get_ipu_resources(struct ipu_image_convert_chan *chan)
+-{
+-      const struct ipu_image_convert_dma_chan *dma = chan->dma_ch;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      int ret;
+-
+-      /* get IC */
+-      chan->ic = ipu_ic_get(priv->ipu, chan->ic_task);
+-      if (IS_ERR(chan->ic)) {
+-              dev_err(priv->ipu->dev, "could not acquire IC\n");
+-              ret = PTR_ERR(chan->ic);
+-              goto err;
+-      }
+-
+-      /* get IDMAC channels */
+-      chan->in_chan = ipu_idmac_get(priv->ipu, dma->in);
+-      chan->out_chan = ipu_idmac_get(priv->ipu, dma->out);
+-      if (IS_ERR(chan->in_chan) || IS_ERR(chan->out_chan)) {
+-              dev_err(priv->ipu->dev, "could not acquire idmac channels\n");
+-              ret = -EBUSY;
+-              goto err;
+-      }
+-
+-      chan->rotation_in_chan = ipu_idmac_get(priv->ipu, dma->rot_in);
+-      chan->rotation_out_chan = ipu_idmac_get(priv->ipu, dma->rot_out);
+-      if (IS_ERR(chan->rotation_in_chan) || IS_ERR(chan->rotation_out_chan)) {
+-              dev_err(priv->ipu->dev,
+-                      "could not acquire idmac rotation channels\n");
+-              ret = -EBUSY;
+-              goto err;
+-      }
+-
+-      /* acquire the EOF interrupts */
+-      chan->out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
+-                                                chan->out_chan,
+-                                                IPU_IRQ_EOF);
+-
+-      ret = request_threaded_irq(chan->out_eof_irq, norotate_irq, do_bh,
+-                                 0, "ipu-ic", chan);
+-      if (ret < 0) {
+-              dev_err(priv->ipu->dev, "could not acquire irq %d\n",
+-                       chan->out_eof_irq);
+-              chan->out_eof_irq = -1;
+-              goto err;
+-      }
+-
+-      chan->rot_out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
+-                                                   chan->rotation_out_chan,
+-                                                   IPU_IRQ_EOF);
+-
+-      ret = request_threaded_irq(chan->rot_out_eof_irq, rotate_irq, do_bh,
+-                                 0, "ipu-ic", chan);
+-      if (ret < 0) {
+-              dev_err(priv->ipu->dev, "could not acquire irq %d\n",
+-                      chan->rot_out_eof_irq);
+-              chan->rot_out_eof_irq = -1;
+-              goto err;
+-      }
+-
+-      return 0;
+-err:
+-      release_ipu_resources(chan);
+-      return ret;
+-}
+-
+-static int fill_image(struct ipu_image_convert_ctx *ctx,
+-                    struct ipu_image_convert_image *ic_image,
+-                    struct ipu_image *image,
+-                    enum ipu_image_convert_type type)
+-{
+-      struct ipu_image_convert_priv *priv = ctx->chan->priv;
+-
+-      ic_image->base = *image;
+-      ic_image->type = type;
+-
+-      ic_image->fmt = get_format(image->pix.pixelformat);
+-      if (!ic_image->fmt) {
+-              dev_err(priv->ipu->dev, "pixelformat not supported for %s\n",
+-                      type == IMAGE_CONVERT_OUT ? "Output" : "Input");
+-              return -EINVAL;
+-      }
+-
+-      if (ic_image->fmt->planar)
+-              ic_image->stride = ic_image->base.pix.width;
+-      else
+-              ic_image->stride  = ic_image->base.pix.bytesperline;
+-
+-      return 0;
+-}
+-
+-/* borrowed from drivers/media/v4l2-core/v4l2-common.c */
+-static unsigned int clamp_align(unsigned int x, unsigned int min,
+-                              unsigned int max, unsigned int align)
+-{
+-      /* Bits that must be zero to be aligned */
+-      unsigned int mask = ~((1 << align) - 1);
+-
+-      /* Clamp to aligned min and max */
+-      x = clamp(x, (min + ~mask) & mask, max & mask);
+-
+-      /* Round to nearest aligned value */
+-      if (align)
+-              x = (x + (1 << (align - 1))) & mask;
+-
+-      return x;
+-}
+-
+-/* Adjusts input/output images to IPU restrictions */
+-void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
+-                            enum ipu_rotate_mode rot_mode)
+-{
+-      const struct ipu_image_pixfmt *infmt, *outfmt;
+-      u32 w_align_out, h_align_out;
+-      u32 w_align_in, h_align_in;
+-
+-      infmt = get_format(in->pix.pixelformat);
+-      outfmt = get_format(out->pix.pixelformat);
+-
+-      /* set some default pixel formats if needed */
+-      if (!infmt) {
+-              in->pix.pixelformat = V4L2_PIX_FMT_RGB24;
+-              infmt = get_format(V4L2_PIX_FMT_RGB24);
+-      }
+-      if (!outfmt) {
+-              out->pix.pixelformat = V4L2_PIX_FMT_RGB24;
+-              outfmt = get_format(V4L2_PIX_FMT_RGB24);
+-      }
+-
+-      /* image converter does not handle fields */
+-      in->pix.field = out->pix.field = V4L2_FIELD_NONE;
+-
+-      /* resizer cannot downsize more than 4:1 */
+-      if (ipu_rot_mode_is_irt(rot_mode)) {
+-              out->pix.height = max_t(__u32, out->pix.height,
+-                                      in->pix.width / 4);
+-              out->pix.width = max_t(__u32, out->pix.width,
+-                                     in->pix.height / 4);
+-      } else {
+-              out->pix.width = max_t(__u32, out->pix.width,
+-                                     in->pix.width / 4);
+-              out->pix.height = max_t(__u32, out->pix.height,
+-                                      in->pix.height / 4);
+-      }
+-
+-      /* align input width/height */
+-      w_align_in = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt,
+-                                          rot_mode));
+-      h_align_in = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt,
+-                                           rot_mode));
+-      in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W,
+-                                  w_align_in);
+-      in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H,
+-                                   h_align_in);
+-
+-      /* align output width/height */
+-      w_align_out = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt,
+-                                           rot_mode));
+-      h_align_out = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt,
+-                                            rot_mode));
+-      out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W,
+-                                   w_align_out);
+-      out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H,
+-                                    h_align_out);
+-
+-      /* set input/output strides and image sizes */
+-      in->pix.bytesperline = infmt->planar ?
+-              clamp_align(in->pix.width, 2 << w_align_in, MAX_W,
+-                          w_align_in) :
+-              clamp_align((in->pix.width * infmt->bpp) >> 3,
+-                          ((2 << w_align_in) * infmt->bpp) >> 3,
+-                          (MAX_W * infmt->bpp) >> 3,
+-                          w_align_in);
+-      in->pix.sizeimage = infmt->planar ?
+-              (in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 :
+-              in->pix.height * in->pix.bytesperline;
+-      out->pix.bytesperline = outfmt->planar ? out->pix.width :
+-              (out->pix.width * outfmt->bpp) >> 3;
+-      out->pix.sizeimage = outfmt->planar ?
+-              (out->pix.height * out->pix.bytesperline * outfmt->bpp) >> 3 :
+-              out->pix.height * out->pix.bytesperline;
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_adjust);
+-
+-/*
+- * this is used by ipu_image_convert_prepare() to verify set input and
+- * output images are valid before starting the conversion. Clients can
+- * also call it before calling ipu_image_convert_prepare().
+- */
+-int ipu_image_convert_verify(struct ipu_image *in, struct ipu_image *out,
+-                           enum ipu_rotate_mode rot_mode)
+-{
+-      struct ipu_image testin, testout;
+-
+-      testin = *in;
+-      testout = *out;
+-
+-      ipu_image_convert_adjust(&testin, &testout, rot_mode);
+-
+-      if (testin.pix.width != in->pix.width ||
+-          testin.pix.height != in->pix.height ||
+-          testout.pix.width != out->pix.width ||
+-          testout.pix.height != out->pix.height)
+-              return -EINVAL;
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_verify);
+-
+-/*
+- * Call ipu_image_convert_prepare() to prepare for the conversion of
+- * given images and rotation mode. Returns a new conversion context.
+- */
+-struct ipu_image_convert_ctx *
+-ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
+-                        struct ipu_image *in, struct ipu_image *out,
+-                        enum ipu_rotate_mode rot_mode,
+-                        ipu_image_convert_cb_t complete,
+-                        void *complete_context)
+-{
+-      struct ipu_image_convert_priv *priv = ipu->image_convert_priv;
+-      struct ipu_image_convert_image *s_image, *d_image;
+-      struct ipu_image_convert_chan *chan;
+-      struct ipu_image_convert_ctx *ctx;
+-      unsigned long flags;
+-      unsigned int i;
+-      bool get_res;
+-      int ret;
+-
+-      if (!in || !out || !complete ||
+-          (ic_task != IC_TASK_VIEWFINDER &&
+-           ic_task != IC_TASK_POST_PROCESSOR))
+-              return ERR_PTR(-EINVAL);
+-
+-      /* verify the in/out images before continuing */
+-      ret = ipu_image_convert_verify(in, out, rot_mode);
+-      if (ret) {
+-              dev_err(priv->ipu->dev, "%s: in/out formats invalid\n",
+-                      __func__);
+-              return ERR_PTR(ret);
+-      }
+-
+-      chan = &priv->chan[ic_task];
+-
+-      ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+-      if (!ctx)
+-              return ERR_PTR(-ENOMEM);
+-
+-      dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p\n", __func__,
+-              chan->ic_task, ctx);
+-
+-      ctx->chan = chan;
+-      init_completion(&ctx->aborted);
+-
+-      ctx->rot_mode = rot_mode;
+-
+-      /* Sets ctx->in.num_rows/cols as well */
+-      ret = calc_image_resize_coefficients(ctx, in, out);
+-      if (ret)
+-              goto out_free;
+-
+-      s_image = &ctx->in;
+-      d_image = &ctx->out;
+-
+-      /* set tiling and rotation */
+-      if (ipu_rot_mode_is_irt(rot_mode)) {
+-              d_image->num_rows = s_image->num_cols;
+-              d_image->num_cols = s_image->num_rows;
+-      } else {
+-              d_image->num_rows = s_image->num_rows;
+-              d_image->num_cols = s_image->num_cols;
+-      }
+-
+-      ctx->num_tiles = d_image->num_cols * d_image->num_rows;
+-
+-      ret = fill_image(ctx, s_image, in, IMAGE_CONVERT_IN);
+-      if (ret)
+-              goto out_free;
+-      ret = fill_image(ctx, d_image, out, IMAGE_CONVERT_OUT);
+-      if (ret)
+-              goto out_free;
+-
+-      calc_out_tile_map(ctx);
+-
+-      find_seams(ctx, s_image, d_image);
+-
+-      ret = calc_tile_dimensions(ctx, s_image);
+-      if (ret)
+-              goto out_free;
+-
+-      ret = calc_tile_offsets(ctx, s_image);
+-      if (ret)
+-              goto out_free;
+-
+-      calc_tile_dimensions(ctx, d_image);
+-      ret = calc_tile_offsets(ctx, d_image);
+-      if (ret)
+-              goto out_free;
+-
+-      calc_tile_resize_coefficients(ctx);
+-
+-      ret = ipu_ic_calc_csc(&ctx->csc,
+-                      s_image->base.pix.ycbcr_enc,
+-                      s_image->base.pix.quantization,
+-                      ipu_pixelformat_to_colorspace(s_image->fmt->fourcc),
+-                      d_image->base.pix.ycbcr_enc,
+-                      d_image->base.pix.quantization,
+-                      ipu_pixelformat_to_colorspace(d_image->fmt->fourcc));
+-      if (ret)
+-              goto out_free;
+-
+-      dump_format(ctx, s_image);
+-      dump_format(ctx, d_image);
+-
+-      ctx->complete = complete;
+-      ctx->complete_context = complete_context;
+-
+-      /*
+-       * Can we use double-buffering for this operation? If there is
+-       * only one tile (the whole image can be converted in a single
+-       * operation) there's no point in using double-buffering. Also,
+-       * the IPU's IDMAC channels allow only a single U and V plane
+-       * offset shared between both buffers, but these offsets change
+-       * for every tile, and therefore would have to be updated for
+-       * each buffer which is not possible. So double-buffering is
+-       * impossible when either the source or destination images are
+-       * a planar format (YUV420, YUV422P, etc.). Further, differently
+-       * sized tiles or different resizing coefficients per tile
+-       * prevent double-buffering as well.
+-       */
+-      ctx->double_buffering = (ctx->num_tiles > 1 &&
+-                               !s_image->fmt->planar &&
+-                               !d_image->fmt->planar);
+-      for (i = 1; i < ctx->num_tiles; i++) {
+-              if (ctx->in.tile[i].width != ctx->in.tile[0].width ||
+-                  ctx->in.tile[i].height != ctx->in.tile[0].height ||
+-                  ctx->out.tile[i].width != ctx->out.tile[0].width ||
+-                  ctx->out.tile[i].height != ctx->out.tile[0].height) {
+-                      ctx->double_buffering = false;
+-                      break;
+-              }
+-      }
+-      for (i = 1; i < ctx->in.num_cols; i++) {
+-              if (ctx->resize_coeffs_h[i] != ctx->resize_coeffs_h[0]) {
+-                      ctx->double_buffering = false;
+-                      break;
+-              }
+-      }
+-      for (i = 1; i < ctx->in.num_rows; i++) {
+-              if (ctx->resize_coeffs_v[i] != ctx->resize_coeffs_v[0]) {
+-                      ctx->double_buffering = false;
+-                      break;
+-              }
+-      }
+-
+-      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+-              unsigned long intermediate_size = d_image->tile[0].size;
+-
+-              for (i = 1; i < ctx->num_tiles; i++) {
+-                      if (d_image->tile[i].size > intermediate_size)
+-                              intermediate_size = d_image->tile[i].size;
+-              }
+-
+-              ret = alloc_dma_buf(priv, &ctx->rot_intermediate[0],
+-                                  intermediate_size);
+-              if (ret)
+-                      goto out_free;
+-              if (ctx->double_buffering) {
+-                      ret = alloc_dma_buf(priv,
+-                                          &ctx->rot_intermediate[1],
+-                                          intermediate_size);
+-                      if (ret)
+-                              goto out_free_dmabuf0;
+-              }
+-      }
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      get_res = list_empty(&chan->ctx_list);
+-
+-      list_add_tail(&ctx->list, &chan->ctx_list);
+-
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-
+-      if (get_res) {
+-              ret = get_ipu_resources(chan);
+-              if (ret)
+-                      goto out_free_dmabuf1;
+-      }
+-
+-      return ctx;
+-
+-out_free_dmabuf1:
+-      free_dma_buf(priv, &ctx->rot_intermediate[1]);
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-      list_del(&ctx->list);
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-out_free_dmabuf0:
+-      free_dma_buf(priv, &ctx->rot_intermediate[0]);
+-out_free:
+-      kfree(ctx);
+-      return ERR_PTR(ret);
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_prepare);
+-
+-/*
+- * Carry out a single image conversion run. Only the physaddr's of the input
+- * and output image buffers are needed. The conversion context must have
+- * been created previously with ipu_image_convert_prepare().
+- */
+-int ipu_image_convert_queue(struct ipu_image_convert_run *run)
+-{
+-      struct ipu_image_convert_chan *chan;
+-      struct ipu_image_convert_priv *priv;
+-      struct ipu_image_convert_ctx *ctx;
+-      unsigned long flags;
+-      int ret = 0;
+-
+-      if (!run || !run->ctx || !run->in_phys || !run->out_phys)
+-              return -EINVAL;
+-
+-      ctx = run->ctx;
+-      chan = ctx->chan;
+-      priv = chan->priv;
+-
+-      dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p run %p\n", __func__,
+-              chan->ic_task, ctx, run);
+-
+-      INIT_LIST_HEAD(&run->list);
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      if (ctx->aborting) {
+-              ret = -EIO;
+-              goto unlock;
+-      }
+-
+-      list_add_tail(&run->list, &chan->pending_q);
+-
+-      if (!chan->current_run) {
+-              ret = do_run(run);
+-              if (ret)
+-                      chan->current_run = NULL;
+-      }
+-unlock:
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_queue);
+-
+-/* Abort any active or pending conversions for this context */
+-static void __ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      struct ipu_image_convert_run *run, *active_run, *tmp;
+-      unsigned long flags;
+-      int run_count, ret;
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      /* move all remaining pending runs in this context to done_q */
+-      list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
+-              if (run->ctx != ctx)
+-                      continue;
+-              run->status = -EIO;
+-              list_move_tail(&run->list, &chan->done_q);
+-      }
+-
+-      run_count = get_run_count(ctx, &chan->done_q);
+-      active_run = (chan->current_run && chan->current_run->ctx == ctx) ?
+-              chan->current_run : NULL;
+-
+-      if (active_run)
+-              reinit_completion(&ctx->aborted);
+-
+-      ctx->aborting = true;
+-
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-
+-      if (!run_count && !active_run) {
+-              dev_dbg(priv->ipu->dev,
+-                      "%s: task %u: no abort needed for ctx %p\n",
+-                      __func__, chan->ic_task, ctx);
+-              return;
+-      }
+-
+-      if (!active_run) {
+-              empty_done_q(chan);
+-              return;
+-      }
+-
+-      dev_dbg(priv->ipu->dev,
+-              "%s: task %u: wait for completion: %d runs\n",
+-              __func__, chan->ic_task, run_count);
+-
+-      ret = wait_for_completion_timeout(&ctx->aborted,
+-                                        msecs_to_jiffies(10000));
+-      if (ret == 0) {
+-              dev_warn(priv->ipu->dev, "%s: timeout\n", __func__);
+-              force_abort(ctx);
+-      }
+-}
+-
+-void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
+-{
+-      __ipu_image_convert_abort(ctx);
+-      ctx->aborting = false;
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_abort);
+-
+-/* Unprepare image conversion context */
+-void ipu_image_convert_unprepare(struct ipu_image_convert_ctx *ctx)
+-{
+-      struct ipu_image_convert_chan *chan = ctx->chan;
+-      struct ipu_image_convert_priv *priv = chan->priv;
+-      unsigned long flags;
+-      bool put_res;
+-
+-      /* make sure no runs are hanging around */
+-      __ipu_image_convert_abort(ctx);
+-
+-      dev_dbg(priv->ipu->dev, "%s: task %u: removing ctx %p\n", __func__,
+-              chan->ic_task, ctx);
+-
+-      spin_lock_irqsave(&chan->irqlock, flags);
+-
+-      list_del(&ctx->list);
+-
+-      put_res = list_empty(&chan->ctx_list);
+-
+-      spin_unlock_irqrestore(&chan->irqlock, flags);
+-
+-      if (put_res)
+-              release_ipu_resources(chan);
+-
+-      free_dma_buf(priv, &ctx->rot_intermediate[1]);
+-      free_dma_buf(priv, &ctx->rot_intermediate[0]);
+-
+-      kfree(ctx);
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_unprepare);
+-
+-/*
+- * "Canned" asynchronous single image conversion. Allocates and returns
+- * a new conversion run.  On successful return the caller must free the
+- * run and call ipu_image_convert_unprepare() after conversion completes.
+- */
+-struct ipu_image_convert_run *
+-ipu_image_convert(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
+-                struct ipu_image *in, struct ipu_image *out,
+-                enum ipu_rotate_mode rot_mode,
+-                ipu_image_convert_cb_t complete,
+-                void *complete_context)
+-{
+-      struct ipu_image_convert_ctx *ctx;
+-      struct ipu_image_convert_run *run;
+-      int ret;
+-
+-      ctx = ipu_image_convert_prepare(ipu, ic_task, in, out, rot_mode,
+-                                      complete, complete_context);
+-      if (IS_ERR(ctx))
+-              return ERR_CAST(ctx);
+-
+-      run = kzalloc(sizeof(*run), GFP_KERNEL);
+-      if (!run) {
+-              ipu_image_convert_unprepare(ctx);
+-              return ERR_PTR(-ENOMEM);
+-      }
+-
+-      run->ctx = ctx;
+-      run->in_phys = in->phys0;
+-      run->out_phys = out->phys0;
+-
+-      ret = ipu_image_convert_queue(run);
+-      if (ret) {
+-              ipu_image_convert_unprepare(ctx);
+-              kfree(run);
+-              return ERR_PTR(ret);
+-      }
+-
+-      return run;
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert);
+-
+-/* "Canned" synchronous single image conversion */
+-static void image_convert_sync_complete(struct ipu_image_convert_run *run,
+-                                      void *data)
+-{
+-      struct completion *comp = data;
+-
+-      complete(comp);
+-}
+-
+-int ipu_image_convert_sync(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
+-                         struct ipu_image *in, struct ipu_image *out,
+-                         enum ipu_rotate_mode rot_mode)
+-{
+-      struct ipu_image_convert_run *run;
+-      struct completion comp;
+-      int ret;
+-
+-      init_completion(&comp);
+-
+-      run = ipu_image_convert(ipu, ic_task, in, out, rot_mode,
+-                              image_convert_sync_complete, &comp);
+-      if (IS_ERR(run))
+-              return PTR_ERR(run);
+-
+-      ret = wait_for_completion_timeout(&comp, msecs_to_jiffies(10000));
+-      ret = (ret == 0) ? -ETIMEDOUT : 0;
+-
+-      ipu_image_convert_unprepare(run->ctx);
+-      kfree(run);
+-
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_image_convert_sync);
+-
+-int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev)
+-{
+-      struct ipu_image_convert_priv *priv;
+-      int i;
+-
+-      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-      if (!priv)
+-              return -ENOMEM;
+-
+-      ipu->image_convert_priv = priv;
+-      priv->ipu = ipu;
+-
+-      for (i = 0; i < IC_NUM_TASKS; i++) {
+-              struct ipu_image_convert_chan *chan = &priv->chan[i];
+-
+-              chan->ic_task = i;
+-              chan->priv = priv;
+-              chan->dma_ch = &image_convert_dma_chan[i];
+-              chan->out_eof_irq = -1;
+-              chan->rot_out_eof_irq = -1;
+-
+-              spin_lock_init(&chan->irqlock);
+-              INIT_LIST_HEAD(&chan->ctx_list);
+-              INIT_LIST_HEAD(&chan->pending_q);
+-              INIT_LIST_HEAD(&chan->done_q);
+-      }
+-
+-      return 0;
+-}
+-
+-void ipu_image_convert_exit(struct ipu_soc *ipu)
+-{
+-}
+--- a/drivers/gpu/imx/ipu-v3/ipu-pre.c
++++ /dev/null
+@@ -1,346 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-only
+-/*
+- * Copyright (c) 2017 Lucas Stach, Pengutronix
+- */
+-
+-#include <drm/drm_fourcc.h>
+-#include <linux/clk.h>
+-#include <linux/err.h>
+-#include <linux/genalloc.h>
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/platform_device.h>
+-#include <video/imx-ipu-v3.h>
+-
+-#include "ipu-prv.h"
+-
+-#define IPU_PRE_MAX_WIDTH     2048
+-#define IPU_PRE_NUM_SCANLINES 8
+-
+-#define IPU_PRE_CTRL                                  0x000
+-#define IPU_PRE_CTRL_SET                              0x004
+-#define  IPU_PRE_CTRL_ENABLE                          (1 << 0)
+-#define  IPU_PRE_CTRL_BLOCK_EN                                (1 << 1)
+-#define  IPU_PRE_CTRL_BLOCK_16                                (1 << 2)
+-#define  IPU_PRE_CTRL_SDW_UPDATE                      (1 << 4)
+-#define  IPU_PRE_CTRL_VFLIP                           (1 << 5)
+-#define  IPU_PRE_CTRL_SO                              (1 << 6)
+-#define  IPU_PRE_CTRL_INTERLACED_FIELD                        (1 << 7)
+-#define  IPU_PRE_CTRL_HANDSHAKE_EN                    (1 << 8)
+-#define  IPU_PRE_CTRL_HANDSHAKE_LINE_NUM(v)           ((v & 0x3) << 9)
+-#define  IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN         (1 << 11)
+-#define  IPU_PRE_CTRL_EN_REPEAT                               (1 << 28)
+-#define  IPU_PRE_CTRL_TPR_REST_SEL                    (1 << 29)
+-#define  IPU_PRE_CTRL_CLKGATE                         (1 << 30)
+-#define  IPU_PRE_CTRL_SFTRST                          (1 << 31)
+-
+-#define IPU_PRE_CUR_BUF                                       0x030
+-
+-#define IPU_PRE_NEXT_BUF                              0x040
+-
+-#define IPU_PRE_TPR_CTRL                              0x070
+-#define  IPU_PRE_TPR_CTRL_TILE_FORMAT(v)              ((v & 0xff) << 0)
+-#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK            0xff
+-#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT          (1 << 0)
+-#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_SPLIT_BUF               (1 << 4)
+-#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF      (1 << 5)
+-#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED     (1 << 6)
+-
+-#define IPU_PRE_PREFETCH_ENG_CTRL                     0x080
+-#define  IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN            (1 << 0)
+-#define  IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(v)                ((v & 0x7) << 1)
+-#define  IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(v)    ((v & 0x3) << 4)
+-#define  IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(v)  ((v & 0x7) << 8)
+-#define  IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS           (1 << 11)
+-#define  IPU_PRE_PREF_ENG_CTRL_FIELD_INVERSE          (1 << 12)
+-#define  IPU_PRE_PREF_ENG_CTRL_PARTIAL_UV_SWAP                (1 << 14)
+-#define  IPU_PRE_PREF_ENG_CTRL_TPR_COOR_OFFSET_EN     (1 << 15)
+-
+-#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE                       0x0a0
+-#define  IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(v)     ((v & 0xffff) << 0)
+-#define  IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(v)    ((v & 0xffff) << 16)
+-
+-#define IPU_PRE_PREFETCH_ENG_PITCH                    0x0d0
+-#define  IPU_PRE_PREFETCH_ENG_PITCH_Y(v)              ((v & 0xffff) << 0)
+-#define  IPU_PRE_PREFETCH_ENG_PITCH_UV(v)             ((v & 0xffff) << 16)
+-
+-#define IPU_PRE_STORE_ENG_CTRL                                0x110
+-#define  IPU_PRE_STORE_ENG_CTRL_STORE_EN              (1 << 0)
+-#define  IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(v)               ((v & 0x7) << 1)
+-#define  IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(v)  ((v & 0x3) << 4)
+-
+-#define IPU_PRE_STORE_ENG_STATUS                      0x120
+-#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_MASK  0xffff
+-#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_SHIFT 0
+-#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK  0x3fff
+-#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT 16
+-#define  IPU_PRE_STORE_ENG_STATUS_STORE_FIFO_FULL     (1 << 30)
+-#define  IPU_PRE_STORE_ENG_STATUS_STORE_FIELD         (1 << 31)
+-
+-#define IPU_PRE_STORE_ENG_SIZE                                0x130
+-#define  IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(v)                ((v & 0xffff) << 0)
+-#define  IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(v)               ((v & 0xffff) << 16)
+-
+-#define IPU_PRE_STORE_ENG_PITCH                               0x140
+-#define  IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(v)         ((v & 0xffff) << 0)
+-
+-#define IPU_PRE_STORE_ENG_ADDR                                0x150
+-
+-struct ipu_pre {
+-      struct list_head        list;
+-      struct device           *dev;
+-
+-      void __iomem            *regs;
+-      struct clk              *clk_axi;
+-      struct gen_pool         *iram;
+-
+-      dma_addr_t              buffer_paddr;
+-      void                    *buffer_virt;
+-      bool                    in_use;
+-      unsigned int            safe_window_end;
+-      unsigned int            last_bufaddr;
+-};
+-
+-static DEFINE_MUTEX(ipu_pre_list_mutex);
+-static LIST_HEAD(ipu_pre_list);
+-static int available_pres;
+-
+-int ipu_pre_get_available_count(void)
+-{
+-      return available_pres;
+-}
+-
+-struct ipu_pre *
+-ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
+-{
+-      struct device_node *pre_node = of_parse_phandle(dev->of_node,
+-                                                      name, index);
+-      struct ipu_pre *pre;
+-
+-      mutex_lock(&ipu_pre_list_mutex);
+-      list_for_each_entry(pre, &ipu_pre_list, list) {
+-              if (pre_node == pre->dev->of_node) {
+-                      mutex_unlock(&ipu_pre_list_mutex);
+-                      device_link_add(dev, pre->dev,
+-                                      DL_FLAG_AUTOREMOVE_CONSUMER);
+-                      of_node_put(pre_node);
+-                      return pre;
+-              }
+-      }
+-      mutex_unlock(&ipu_pre_list_mutex);
+-
+-      of_node_put(pre_node);
+-
+-      return NULL;
+-}
+-
+-int ipu_pre_get(struct ipu_pre *pre)
+-{
+-      u32 val;
+-
+-      if (pre->in_use)
+-              return -EBUSY;
+-
+-      /* first get the engine out of reset and remove clock gating */
+-      writel(0, pre->regs + IPU_PRE_CTRL);
+-
+-      /* init defaults that should be applied to all streams */
+-      val = IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN |
+-            IPU_PRE_CTRL_HANDSHAKE_EN |
+-            IPU_PRE_CTRL_TPR_REST_SEL |
+-            IPU_PRE_CTRL_SDW_UPDATE;
+-      writel(val, pre->regs + IPU_PRE_CTRL);
+-
+-      pre->in_use = true;
+-      return 0;
+-}
+-
+-void ipu_pre_put(struct ipu_pre *pre)
+-{
+-      writel(IPU_PRE_CTRL_SFTRST, pre->regs + IPU_PRE_CTRL);
+-
+-      pre->in_use = false;
+-}
+-
+-void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
+-                     unsigned int height, unsigned int stride, u32 format,
+-                     uint64_t modifier, unsigned int bufaddr)
+-{
+-      const struct drm_format_info *info = drm_format_info(format);
+-      u32 active_bpp = info->cpp[0] >> 1;
+-      u32 val;
+-
+-      /* calculate safe window for ctrl register updates */
+-      if (modifier == DRM_FORMAT_MOD_LINEAR)
+-              pre->safe_window_end = height - 2;
+-      else
+-              pre->safe_window_end = DIV_ROUND_UP(height, 4) - 1;
+-
+-      writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF);
+-      writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
+-      pre->last_bufaddr = bufaddr;
+-
+-      val = IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(0) |
+-            IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(active_bpp) |
+-            IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(4) |
+-            IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS |
+-            IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN;
+-      writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_CTRL);
+-
+-      val = IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(width) |
+-            IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(height);
+-      writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_INPUT_SIZE);
+-
+-      val = IPU_PRE_PREFETCH_ENG_PITCH_Y(stride);
+-      writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_PITCH);
+-
+-      val = IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(active_bpp) |
+-            IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(4) |
+-            IPU_PRE_STORE_ENG_CTRL_STORE_EN;
+-      writel(val, pre->regs + IPU_PRE_STORE_ENG_CTRL);
+-
+-      val = IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(width) |
+-            IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(height);
+-      writel(val, pre->regs + IPU_PRE_STORE_ENG_SIZE);
+-
+-      val = IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(stride);
+-      writel(val, pre->regs + IPU_PRE_STORE_ENG_PITCH);
+-
+-      writel(pre->buffer_paddr, pre->regs + IPU_PRE_STORE_ENG_ADDR);
+-
+-      val = readl(pre->regs + IPU_PRE_TPR_CTRL);
+-      val &= ~IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK;
+-      if (modifier != DRM_FORMAT_MOD_LINEAR) {
+-              /* only support single buffer formats for now */
+-              val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF;
+-              if (modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED)
+-                      val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED;
+-              if (info->cpp[0] == 2)
+-                      val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT;
+-      }
+-      writel(val, pre->regs + IPU_PRE_TPR_CTRL);
+-
+-      val = readl(pre->regs + IPU_PRE_CTRL);
+-      val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE |
+-             IPU_PRE_CTRL_SDW_UPDATE;
+-      if (modifier == DRM_FORMAT_MOD_LINEAR)
+-              val &= ~IPU_PRE_CTRL_BLOCK_EN;
+-      else
+-              val |= IPU_PRE_CTRL_BLOCK_EN;
+-      writel(val, pre->regs + IPU_PRE_CTRL);
+-}
+-
+-void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
+-{
+-      unsigned long timeout = jiffies + msecs_to_jiffies(5);
+-      unsigned short current_yblock;
+-      u32 val;
+-
+-      if (bufaddr == pre->last_bufaddr)
+-              return;
+-
+-      writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
+-      pre->last_bufaddr = bufaddr;
+-
+-      do {
+-              if (time_after(jiffies, timeout)) {
+-                      dev_warn(pre->dev, "timeout waiting for PRE safe window\n");
+-                      return;
+-              }
+-
+-              val = readl(pre->regs + IPU_PRE_STORE_ENG_STATUS);
+-              current_yblock =
+-                      (val >> IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT) &
+-                      IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK;
+-      } while (current_yblock == 0 || current_yblock >= pre->safe_window_end);
+-
+-      writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
+-}
+-
+-bool ipu_pre_update_pending(struct ipu_pre *pre)
+-{
+-      return !!(readl_relaxed(pre->regs + IPU_PRE_CTRL) &
+-                IPU_PRE_CTRL_SDW_UPDATE);
+-}
+-
+-u32 ipu_pre_get_baddr(struct ipu_pre *pre)
+-{
+-      return (u32)pre->buffer_paddr;
+-}
+-
+-static int ipu_pre_probe(struct platform_device *pdev)
+-{
+-      struct device *dev = &pdev->dev;
+-      struct resource *res;
+-      struct ipu_pre *pre;
+-
+-      pre = devm_kzalloc(dev, sizeof(*pre), GFP_KERNEL);
+-      if (!pre)
+-              return -ENOMEM;
+-
+-      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-      pre->regs = devm_ioremap_resource(&pdev->dev, res);
+-      if (IS_ERR(pre->regs))
+-              return PTR_ERR(pre->regs);
+-
+-      pre->clk_axi = devm_clk_get(dev, "axi");
+-      if (IS_ERR(pre->clk_axi))
+-              return PTR_ERR(pre->clk_axi);
+-
+-      pre->iram = of_gen_pool_get(dev->of_node, "fsl,iram", 0);
+-      if (!pre->iram)
+-              return -EPROBE_DEFER;
+-
+-      /*
+-       * Allocate IRAM buffer with maximum size. This could be made dynamic,
+-       * but as there is no other user of this IRAM region and we can fit all
+-       * max sized buffers into it, there is no need yet.
+-       */
+-      pre->buffer_virt = gen_pool_dma_alloc(pre->iram, IPU_PRE_MAX_WIDTH *
+-                                            IPU_PRE_NUM_SCANLINES * 4,
+-                                            &pre->buffer_paddr);
+-      if (!pre->buffer_virt)
+-              return -ENOMEM;
+-
+-      clk_prepare_enable(pre->clk_axi);
+-
+-      pre->dev = dev;
+-      platform_set_drvdata(pdev, pre);
+-      mutex_lock(&ipu_pre_list_mutex);
+-      list_add(&pre->list, &ipu_pre_list);
+-      available_pres++;
+-      mutex_unlock(&ipu_pre_list_mutex);
+-
+-      return 0;
+-}
+-
+-static int ipu_pre_remove(struct platform_device *pdev)
+-{
+-      struct ipu_pre *pre = platform_get_drvdata(pdev);
+-
+-      mutex_lock(&ipu_pre_list_mutex);
+-      list_del(&pre->list);
+-      available_pres--;
+-      mutex_unlock(&ipu_pre_list_mutex);
+-
+-      clk_disable_unprepare(pre->clk_axi);
+-
+-      if (pre->buffer_virt)
+-              gen_pool_free(pre->iram, (unsigned long)pre->buffer_virt,
+-                            IPU_PRE_MAX_WIDTH * IPU_PRE_NUM_SCANLINES * 4);
+-      return 0;
+-}
+-
+-static const struct of_device_id ipu_pre_dt_ids[] = {
+-      { .compatible = "fsl,imx6qp-pre", },
+-      { /* sentinel */ },
+-};
+-
+-struct platform_driver ipu_pre_drv = {
+-      .probe          = ipu_pre_probe,
+-      .remove         = ipu_pre_remove,
+-      .driver         = {
+-              .name   = "imx-ipu-pre",
+-              .of_match_table = ipu_pre_dt_ids,
+-      },
+-};
+--- a/drivers/gpu/imx/ipu-v3/ipu-prg.c
++++ /dev/null
+@@ -1,483 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-only
+-/*
+- * Copyright (c) 2016-2017 Lucas Stach, Pengutronix
+- */
+-
+-#include <drm/drm_fourcc.h>
+-#include <linux/clk.h>
+-#include <linux/err.h>
+-#include <linux/iopoll.h>
+-#include <linux/mfd/syscon.h>
+-#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/platform_device.h>
+-#include <linux/pm_runtime.h>
+-#include <linux/regmap.h>
+-#include <video/imx-ipu-v3.h>
+-
+-#include "ipu-prv.h"
+-
+-#define IPU_PRG_CTL                           0x00
+-#define  IPU_PRG_CTL_BYPASS(i)                        (1 << (0 + i))
+-#define  IPU_PRG_CTL_SOFT_ARID_MASK           0x3
+-#define  IPU_PRG_CTL_SOFT_ARID_SHIFT(i)               (8 + i * 2)
+-#define  IPU_PRG_CTL_SOFT_ARID(i, v)          ((v & 0x3) << (8 + 2 * i))
+-#define  IPU_PRG_CTL_SO(i)                    (1 << (16 + i))
+-#define  IPU_PRG_CTL_VFLIP(i)                 (1 << (19 + i))
+-#define  IPU_PRG_CTL_BLOCK_MODE(i)            (1 << (22 + i))
+-#define  IPU_PRG_CTL_CNT_LOAD_EN(i)           (1 << (25 + i))
+-#define  IPU_PRG_CTL_SOFTRST                  (1 << 30)
+-#define  IPU_PRG_CTL_SHADOW_EN                        (1 << 31)
+-
+-#define IPU_PRG_STATUS                                0x04
+-#define  IPU_PRG_STATUS_BUFFER0_READY(i)      (1 << (0 + i * 2))
+-#define  IPU_PRG_STATUS_BUFFER1_READY(i)      (1 << (1 + i * 2))
+-
+-#define IPU_PRG_QOS                           0x08
+-#define  IPU_PRG_QOS_ARID_MASK                        0xf
+-#define  IPU_PRG_QOS_ARID_SHIFT(i)            (0 + i * 4)
+-
+-#define IPU_PRG_REG_UPDATE                    0x0c
+-#define  IPU_PRG_REG_UPDATE_REG_UPDATE                (1 << 0)
+-
+-#define IPU_PRG_STRIDE(i)                     (0x10 + i * 0x4)
+-#define  IPU_PRG_STRIDE_STRIDE_MASK           0x3fff
+-
+-#define IPU_PRG_CROP_LINE                     0x1c
+-
+-#define IPU_PRG_THD                           0x20
+-
+-#define IPU_PRG_BADDR(i)                      (0x24 + i * 0x4)
+-
+-#define IPU_PRG_OFFSET(i)                     (0x30 + i * 0x4)
+-
+-#define IPU_PRG_ILO(i)                                (0x3c + i * 0x4)
+-
+-#define IPU_PRG_HEIGHT(i)                     (0x48 + i * 0x4)
+-#define  IPU_PRG_HEIGHT_PRE_HEIGHT_MASK               0xfff
+-#define  IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT      0
+-#define  IPU_PRG_HEIGHT_IPU_HEIGHT_MASK               0xfff
+-#define  IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT      16
+-
+-struct ipu_prg_channel {
+-      bool                    enabled;
+-      int                     used_pre;
+-};
+-
+-struct ipu_prg {
+-      struct list_head        list;
+-      struct device           *dev;
+-      int                     id;
+-
+-      void __iomem            *regs;
+-      struct clk              *clk_ipg, *clk_axi;
+-      struct regmap           *iomuxc_gpr;
+-      struct ipu_pre          *pres[3];
+-
+-      struct ipu_prg_channel  chan[3];
+-};
+-
+-static DEFINE_MUTEX(ipu_prg_list_mutex);
+-static LIST_HEAD(ipu_prg_list);
+-
+-struct ipu_prg *
+-ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id)
+-{
+-      struct device_node *prg_node = of_parse_phandle(dev->of_node,
+-                                                      name, 0);
+-      struct ipu_prg *prg;
+-
+-      mutex_lock(&ipu_prg_list_mutex);
+-      list_for_each_entry(prg, &ipu_prg_list, list) {
+-              if (prg_node == prg->dev->of_node) {
+-                      mutex_unlock(&ipu_prg_list_mutex);
+-                      device_link_add(dev, prg->dev,
+-                                      DL_FLAG_AUTOREMOVE_CONSUMER);
+-                      prg->id = ipu_id;
+-                      of_node_put(prg_node);
+-                      return prg;
+-              }
+-      }
+-      mutex_unlock(&ipu_prg_list_mutex);
+-
+-      of_node_put(prg_node);
+-
+-      return NULL;
+-}
+-
+-int ipu_prg_max_active_channels(void)
+-{
+-      return ipu_pre_get_available_count();
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_max_active_channels);
+-
+-bool ipu_prg_present(struct ipu_soc *ipu)
+-{
+-      if (ipu->prg_priv)
+-              return true;
+-
+-      return false;
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_present);
+-
+-bool ipu_prg_format_supported(struct ipu_soc *ipu, uint32_t format,
+-                            uint64_t modifier)
+-{
+-      const struct drm_format_info *info = drm_format_info(format);
+-
+-      if (info->num_planes != 1)
+-              return false;
+-
+-      switch (modifier) {
+-      case DRM_FORMAT_MOD_LINEAR:
+-      case DRM_FORMAT_MOD_VIVANTE_TILED:
+-      case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+-              return true;
+-      default:
+-              return false;
+-      }
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_format_supported);
+-
+-int ipu_prg_enable(struct ipu_soc *ipu)
+-{
+-      struct ipu_prg *prg = ipu->prg_priv;
+-
+-      if (!prg)
+-              return 0;
+-
+-      return pm_runtime_get_sync(prg->dev);
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_enable);
+-
+-void ipu_prg_disable(struct ipu_soc *ipu)
+-{
+-      struct ipu_prg *prg = ipu->prg_priv;
+-
+-      if (!prg)
+-              return;
+-
+-      pm_runtime_put(prg->dev);
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_disable);
+-
+-/*
+- * The channel configuartion functions below are not thread safe, as they
+- * must be only called from the atomic commit path in the DRM driver, which
+- * is properly serialized.
+- */
+-static int ipu_prg_ipu_to_prg_chan(int ipu_chan)
+-{
+-      /*
+-       * This isn't clearly documented in the RM, but IPU to PRG channel
+-       * assignment is fixed, as only with this mapping the control signals
+-       * match up.
+-       */
+-      switch (ipu_chan) {
+-      case IPUV3_CHANNEL_MEM_BG_SYNC:
+-              return 0;
+-      case IPUV3_CHANNEL_MEM_FG_SYNC:
+-              return 1;
+-      case IPUV3_CHANNEL_MEM_DC_SYNC:
+-              return 2;
+-      default:
+-              return -EINVAL;
+-      }
+-}
+-
+-static int ipu_prg_get_pre(struct ipu_prg *prg, int prg_chan)
+-{
+-      int i, ret;
+-
+-      /* channel 0 is special as it is hardwired to one of the PREs */
+-      if (prg_chan == 0) {
+-              ret = ipu_pre_get(prg->pres[0]);
+-              if (ret)
+-                      goto fail;
+-              prg->chan[prg_chan].used_pre = 0;
+-              return 0;
+-      }
+-
+-      for (i = 1; i < 3; i++) {
+-              ret = ipu_pre_get(prg->pres[i]);
+-              if (!ret) {
+-                      u32 val, mux;
+-                      int shift;
+-
+-                      prg->chan[prg_chan].used_pre = i;
+-
+-                      /* configure the PRE to PRG channel mux */
+-                      shift = (i == 1) ? 12 : 14;
+-                      mux = (prg->id << 1) | (prg_chan - 1);
+-                      regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
+-                                         0x3 << shift, mux << shift);
+-
+-                      /* check other mux, must not point to same channel */
+-                      shift = (i == 1) ? 14 : 12;
+-                      regmap_read(prg->iomuxc_gpr, IOMUXC_GPR5, &val);
+-                      if (((val >> shift) & 0x3) == mux) {
+-                              regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
+-                                                 0x3 << shift,
+-                                                 (mux ^ 0x1) << shift);
+-                      }
+-
+-                      return 0;
+-              }
+-      }
+-
+-fail:
+-      dev_err(prg->dev, "could not get PRE for PRG chan %d", prg_chan);
+-      return ret;
+-}
+-
+-static void ipu_prg_put_pre(struct ipu_prg *prg, int prg_chan)
+-{
+-      struct ipu_prg_channel *chan = &prg->chan[prg_chan];
+-
+-      ipu_pre_put(prg->pres[chan->used_pre]);
+-      chan->used_pre = -1;
+-}
+-
+-void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan)
+-{
+-      int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
+-      struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
+-      struct ipu_prg_channel *chan;
+-      u32 val;
+-
+-      if (prg_chan < 0)
+-              return;
+-
+-      chan = &prg->chan[prg_chan];
+-      if (!chan->enabled)
+-              return;
+-
+-      pm_runtime_get_sync(prg->dev);
+-
+-      val = readl(prg->regs + IPU_PRG_CTL);
+-      val |= IPU_PRG_CTL_BYPASS(prg_chan);
+-      writel(val, prg->regs + IPU_PRG_CTL);
+-
+-      val = IPU_PRG_REG_UPDATE_REG_UPDATE;
+-      writel(val, prg->regs + IPU_PRG_REG_UPDATE);
+-
+-      pm_runtime_put(prg->dev);
+-
+-      ipu_prg_put_pre(prg, prg_chan);
+-
+-      chan->enabled = false;
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_channel_disable);
+-
+-int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
+-                            unsigned int axi_id, unsigned int width,
+-                            unsigned int height, unsigned int stride,
+-                            u32 format, uint64_t modifier, unsigned long *eba)
+-{
+-      int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
+-      struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
+-      struct ipu_prg_channel *chan;
+-      u32 val;
+-      int ret;
+-
+-      if (prg_chan < 0)
+-              return prg_chan;
+-
+-      chan = &prg->chan[prg_chan];
+-
+-      if (chan->enabled) {
+-              ipu_pre_update(prg->pres[chan->used_pre], *eba);
+-              return 0;
+-      }
+-
+-      ret = ipu_prg_get_pre(prg, prg_chan);
+-      if (ret)
+-              return ret;
+-
+-      ipu_pre_configure(prg->pres[chan->used_pre],
+-                        width, height, stride, format, modifier, *eba);
+-
+-
+-      pm_runtime_get_sync(prg->dev);
+-
+-      val = (stride - 1) & IPU_PRG_STRIDE_STRIDE_MASK;
+-      writel(val, prg->regs + IPU_PRG_STRIDE(prg_chan));
+-
+-      val = ((height & IPU_PRG_HEIGHT_PRE_HEIGHT_MASK) <<
+-             IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT) |
+-            ((height & IPU_PRG_HEIGHT_IPU_HEIGHT_MASK) <<
+-             IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT);
+-      writel(val, prg->regs + IPU_PRG_HEIGHT(prg_chan));
+-
+-      val = ipu_pre_get_baddr(prg->pres[chan->used_pre]);
+-      *eba = val;
+-      writel(val, prg->regs + IPU_PRG_BADDR(prg_chan));
+-
+-      val = readl(prg->regs + IPU_PRG_CTL);
+-      /* config AXI ID */
+-      val &= ~(IPU_PRG_CTL_SOFT_ARID_MASK <<
+-               IPU_PRG_CTL_SOFT_ARID_SHIFT(prg_chan));
+-      val |= IPU_PRG_CTL_SOFT_ARID(prg_chan, axi_id);
+-      /* enable channel */
+-      val &= ~IPU_PRG_CTL_BYPASS(prg_chan);
+-      writel(val, prg->regs + IPU_PRG_CTL);
+-
+-      val = IPU_PRG_REG_UPDATE_REG_UPDATE;
+-      writel(val, prg->regs + IPU_PRG_REG_UPDATE);
+-
+-      /* wait for both double buffers to be filled */
+-      readl_poll_timeout(prg->regs + IPU_PRG_STATUS, val,
+-                         (val & IPU_PRG_STATUS_BUFFER0_READY(prg_chan)) &&
+-                         (val & IPU_PRG_STATUS_BUFFER1_READY(prg_chan)),
+-                         5, 1000);
+-
+-      pm_runtime_put(prg->dev);
+-
+-      chan->enabled = true;
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_channel_configure);
+-
+-bool ipu_prg_channel_configure_pending(struct ipuv3_channel *ipu_chan)
+-{
+-      int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
+-      struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
+-      struct ipu_prg_channel *chan;
+-
+-      if (prg_chan < 0)
+-              return false;
+-
+-      chan = &prg->chan[prg_chan];
+-      WARN_ON(!chan->enabled);
+-
+-      return ipu_pre_update_pending(prg->pres[chan->used_pre]);
+-}
+-EXPORT_SYMBOL_GPL(ipu_prg_channel_configure_pending);
+-
+-static int ipu_prg_probe(struct platform_device *pdev)
+-{
+-      struct device *dev = &pdev->dev;
+-      struct resource *res;
+-      struct ipu_prg *prg;
+-      u32 val;
+-      int i, ret;
+-
+-      prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
+-      if (!prg)
+-              return -ENOMEM;
+-
+-      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-      prg->regs = devm_ioremap_resource(&pdev->dev, res);
+-      if (IS_ERR(prg->regs))
+-              return PTR_ERR(prg->regs);
+-
+-
+-      prg->clk_ipg = devm_clk_get(dev, "ipg");
+-      if (IS_ERR(prg->clk_ipg))
+-              return PTR_ERR(prg->clk_ipg);
+-
+-      prg->clk_axi = devm_clk_get(dev, "axi");
+-      if (IS_ERR(prg->clk_axi))
+-              return PTR_ERR(prg->clk_axi);
+-
+-      prg->iomuxc_gpr =
+-              syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
+-      if (IS_ERR(prg->iomuxc_gpr))
+-              return PTR_ERR(prg->iomuxc_gpr);
+-
+-      for (i = 0; i < 3; i++) {
+-              prg->pres[i] = ipu_pre_lookup_by_phandle(dev, "fsl,pres", i);
+-              if (!prg->pres[i])
+-                      return -EPROBE_DEFER;
+-      }
+-
+-      ret = clk_prepare_enable(prg->clk_ipg);
+-      if (ret)
+-              return ret;
+-
+-      ret = clk_prepare_enable(prg->clk_axi);
+-      if (ret) {
+-              clk_disable_unprepare(prg->clk_ipg);
+-              return ret;
+-      }
+-
+-      /* init to free running mode */
+-      val = readl(prg->regs + IPU_PRG_CTL);
+-      val |= IPU_PRG_CTL_SHADOW_EN;
+-      writel(val, prg->regs + IPU_PRG_CTL);
+-
+-      /* disable address threshold */
+-      writel(0xffffffff, prg->regs + IPU_PRG_THD);
+-
+-      pm_runtime_set_active(dev);
+-      pm_runtime_enable(dev);
+-
+-      prg->dev = dev;
+-      platform_set_drvdata(pdev, prg);
+-      mutex_lock(&ipu_prg_list_mutex);
+-      list_add(&prg->list, &ipu_prg_list);
+-      mutex_unlock(&ipu_prg_list_mutex);
+-
+-      return 0;
+-}
+-
+-static int ipu_prg_remove(struct platform_device *pdev)
+-{
+-      struct ipu_prg *prg = platform_get_drvdata(pdev);
+-
+-      mutex_lock(&ipu_prg_list_mutex);
+-      list_del(&prg->list);
+-      mutex_unlock(&ipu_prg_list_mutex);
+-
+-      return 0;
+-}
+-
+-#ifdef CONFIG_PM
+-static int prg_suspend(struct device *dev)
+-{
+-      struct ipu_prg *prg = dev_get_drvdata(dev);
+-
+-      clk_disable_unprepare(prg->clk_axi);
+-      clk_disable_unprepare(prg->clk_ipg);
+-
+-      return 0;
+-}
+-
+-static int prg_resume(struct device *dev)
+-{
+-      struct ipu_prg *prg = dev_get_drvdata(dev);
+-      int ret;
+-
+-      ret = clk_prepare_enable(prg->clk_ipg);
+-      if (ret)
+-              return ret;
+-
+-      ret = clk_prepare_enable(prg->clk_axi);
+-      if (ret) {
+-              clk_disable_unprepare(prg->clk_ipg);
+-              return ret;
+-      }
+-
+-      return 0;
+-}
+-#endif
+-
+-static const struct dev_pm_ops prg_pm_ops = {
+-      SET_RUNTIME_PM_OPS(prg_suspend, prg_resume, NULL)
+-};
+-
+-static const struct of_device_id ipu_prg_dt_ids[] = {
+-      { .compatible = "fsl,imx6qp-prg", },
+-      { /* sentinel */ },
+-};
+-
+-struct platform_driver ipu_prg_drv = {
+-      .probe          = ipu_prg_probe,
+-      .remove         = ipu_prg_remove,
+-      .driver         = {
+-              .name   = "imx-ipu-prg",
+-              .pm     = &prg_pm_ops,
+-              .of_match_table = ipu_prg_dt_ids,
+-      },
+-};
+--- a/drivers/gpu/imx/ipu-v3/ipu-prv.h
++++ /dev/null
+@@ -1,274 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0-or-later */
+-/*
+- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-#ifndef __IPU_PRV_H__
+-#define __IPU_PRV_H__
+-
+-struct ipu_soc;
+-
+-#include <linux/types.h>
+-#include <linux/device.h>
+-#include <linux/clk.h>
+-#include <linux/platform_device.h>
+-
+-#include <video/imx-ipu-v3.h>
+-
+-#define IPU_MCU_T_DEFAULT     8
+-#define IPU_CM_IDMAC_REG_OFS  0x00008000
+-#define IPU_CM_IC_REG_OFS     0x00020000
+-#define IPU_CM_IRT_REG_OFS    0x00028000
+-#define IPU_CM_CSI0_REG_OFS   0x00030000
+-#define IPU_CM_CSI1_REG_OFS   0x00038000
+-#define IPU_CM_SMFC_REG_OFS   0x00050000
+-#define IPU_CM_DC_REG_OFS     0x00058000
+-#define IPU_CM_DMFC_REG_OFS   0x00060000
+-
+-/* Register addresses */
+-/* IPU Common registers */
+-#define IPU_CM_REG(offset)    (offset)
+-
+-#define IPU_CONF                      IPU_CM_REG(0)
+-
+-#define IPU_SRM_PRI1                  IPU_CM_REG(0x00a0)
+-#define IPU_SRM_PRI2                  IPU_CM_REG(0x00a4)
+-#define IPU_FS_PROC_FLOW1             IPU_CM_REG(0x00a8)
+-#define IPU_FS_PROC_FLOW2             IPU_CM_REG(0x00ac)
+-#define IPU_FS_PROC_FLOW3             IPU_CM_REG(0x00b0)
+-#define IPU_FS_DISP_FLOW1             IPU_CM_REG(0x00b4)
+-#define IPU_FS_DISP_FLOW2             IPU_CM_REG(0x00b8)
+-#define IPU_SKIP                      IPU_CM_REG(0x00bc)
+-#define IPU_DISP_ALT_CONF             IPU_CM_REG(0x00c0)
+-#define IPU_DISP_GEN                  IPU_CM_REG(0x00c4)
+-#define IPU_DISP_ALT1                 IPU_CM_REG(0x00c8)
+-#define IPU_DISP_ALT2                 IPU_CM_REG(0x00cc)
+-#define IPU_DISP_ALT3                 IPU_CM_REG(0x00d0)
+-#define IPU_DISP_ALT4                 IPU_CM_REG(0x00d4)
+-#define IPU_SNOOP                     IPU_CM_REG(0x00d8)
+-#define IPU_MEM_RST                   IPU_CM_REG(0x00dc)
+-#define IPU_PM                                IPU_CM_REG(0x00e0)
+-#define IPU_GPR                               IPU_CM_REG(0x00e4)
+-#define IPU_CHA_DB_MODE_SEL(ch)               IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
+-#define IPU_ALT_CHA_DB_MODE_SEL(ch)   IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
+-#define IPU_CHA_CUR_BUF(ch)           IPU_CM_REG(0x023C + 4 * ((ch) / 32))
+-#define IPU_ALT_CUR_BUF0              IPU_CM_REG(0x0244)
+-#define IPU_ALT_CUR_BUF1              IPU_CM_REG(0x0248)
+-#define IPU_SRM_STAT                  IPU_CM_REG(0x024C)
+-#define IPU_PROC_TASK_STAT            IPU_CM_REG(0x0250)
+-#define IPU_DISP_TASK_STAT            IPU_CM_REG(0x0254)
+-#define IPU_CHA_BUF0_RDY(ch)          IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
+-#define IPU_CHA_BUF1_RDY(ch)          IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
+-#define IPU_CHA_BUF2_RDY(ch)          IPU_CM_REG(0x0288 + 4 * ((ch) / 32))
+-#define IPU_ALT_CHA_BUF0_RDY(ch)      IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
+-#define IPU_ALT_CHA_BUF1_RDY(ch)      IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
+-
+-#define IPU_INT_CTRL(n)               IPU_CM_REG(0x003C + 4 * (n))
+-#define IPU_INT_STAT(n)               IPU_CM_REG(0x0200 + 4 * (n))
+-
+-/* SRM_PRI2 */
+-#define DP_S_SRM_MODE_MASK            (0x3 << 3)
+-#define DP_S_SRM_MODE_NOW             (0x3 << 3)
+-#define DP_S_SRM_MODE_NEXT_FRAME      (0x1 << 3)
+-
+-/* FS_PROC_FLOW1 */
+-#define FS_PRPENC_ROT_SRC_SEL_MASK    (0xf << 0)
+-#define FS_PRPENC_ROT_SRC_SEL_ENC             (0x7 << 0)
+-#define FS_PRPVF_ROT_SRC_SEL_MASK     (0xf << 8)
+-#define FS_PRPVF_ROT_SRC_SEL_VF                       (0x8 << 8)
+-#define FS_PP_SRC_SEL_MASK            (0xf << 12)
+-#define FS_PP_ROT_SRC_SEL_MASK                (0xf << 16)
+-#define FS_PP_ROT_SRC_SEL_PP                  (0x5 << 16)
+-#define FS_VDI1_SRC_SEL_MASK          (0x3 << 20)
+-#define FS_VDI3_SRC_SEL_MASK          (0x3 << 20)
+-#define FS_PRP_SRC_SEL_MASK           (0xf << 24)
+-#define FS_VDI_SRC_SEL_MASK           (0x3 << 28)
+-#define FS_VDI_SRC_SEL_CSI_DIRECT             (0x1 << 28)
+-#define FS_VDI_SRC_SEL_VDOA                   (0x2 << 28)
+-
+-/* FS_PROC_FLOW2 */
+-#define FS_PRP_ENC_DEST_SEL_MASK      (0xf << 0)
+-#define FS_PRP_ENC_DEST_SEL_IRT_ENC           (0x1 << 0)
+-#define FS_PRPVF_DEST_SEL_MASK                (0xf << 4)
+-#define FS_PRPVF_DEST_SEL_IRT_VF              (0x1 << 4)
+-#define FS_PRPVF_ROT_DEST_SEL_MASK    (0xf << 8)
+-#define FS_PP_DEST_SEL_MASK           (0xf << 12)
+-#define FS_PP_DEST_SEL_IRT_PP                 (0x3 << 12)
+-#define FS_PP_ROT_DEST_SEL_MASK               (0xf << 16)
+-#define FS_PRPENC_ROT_DEST_SEL_MASK   (0xf << 20)
+-#define FS_PRP_DEST_SEL_MASK          (0xf << 24)
+-
+-#define IPU_DI0_COUNTER_RELEASE                       (1 << 24)
+-#define IPU_DI1_COUNTER_RELEASE                       (1 << 25)
+-
+-#define IPU_IDMAC_REG(offset) (offset)
+-
+-#define IDMAC_CONF                    IPU_IDMAC_REG(0x0000)
+-#define IDMAC_CHA_EN(ch)              IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
+-#define IDMAC_SEP_ALPHA                       IPU_IDMAC_REG(0x000c)
+-#define IDMAC_ALT_SEP_ALPHA           IPU_IDMAC_REG(0x0010)
+-#define IDMAC_CHA_PRI(ch)             IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
+-#define IDMAC_WM_EN(ch)                       IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32))
+-#define IDMAC_CH_LOCK_EN_1            IPU_IDMAC_REG(0x0024)
+-#define IDMAC_CH_LOCK_EN_2            IPU_IDMAC_REG(0x0028)
+-#define IDMAC_SUB_ADDR_0              IPU_IDMAC_REG(0x002c)
+-#define IDMAC_SUB_ADDR_1              IPU_IDMAC_REG(0x0030)
+-#define IDMAC_SUB_ADDR_2              IPU_IDMAC_REG(0x0034)
+-#define IDMAC_BAND_EN(ch)             IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32))
+-#define IDMAC_CHA_BUSY(ch)            IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32))
+-
+-#define IPU_NUM_IRQS  (32 * 15)
+-
+-enum ipu_modules {
+-      IPU_CONF_CSI0_EN                = (1 << 0),
+-      IPU_CONF_CSI1_EN                = (1 << 1),
+-      IPU_CONF_IC_EN                  = (1 << 2),
+-      IPU_CONF_ROT_EN                 = (1 << 3),
+-      IPU_CONF_ISP_EN                 = (1 << 4),
+-      IPU_CONF_DP_EN                  = (1 << 5),
+-      IPU_CONF_DI0_EN                 = (1 << 6),
+-      IPU_CONF_DI1_EN                 = (1 << 7),
+-      IPU_CONF_SMFC_EN                = (1 << 8),
+-      IPU_CONF_DC_EN                  = (1 << 9),
+-      IPU_CONF_DMFC_EN                = (1 << 10),
+-
+-      IPU_CONF_VDI_EN                 = (1 << 12),
+-
+-      IPU_CONF_IDMAC_DIS              = (1 << 22),
+-
+-      IPU_CONF_IC_DMFC_SEL            = (1 << 25),
+-      IPU_CONF_IC_DMFC_SYNC           = (1 << 26),
+-      IPU_CONF_VDI_DMFC_SYNC          = (1 << 27),
+-
+-      IPU_CONF_CSI0_DATA_SOURCE       = (1 << 28),
+-      IPU_CONF_CSI1_DATA_SOURCE       = (1 << 29),
+-      IPU_CONF_IC_INPUT               = (1 << 30),
+-      IPU_CONF_CSI_SEL                = (1 << 31),
+-};
+-
+-struct ipuv3_channel {
+-      unsigned int num;
+-      struct ipu_soc *ipu;
+-      struct list_head list;
+-};
+-
+-struct ipu_cpmem;
+-struct ipu_csi;
+-struct ipu_dc_priv;
+-struct ipu_dmfc_priv;
+-struct ipu_di;
+-struct ipu_ic_priv;
+-struct ipu_vdi;
+-struct ipu_image_convert_priv;
+-struct ipu_smfc_priv;
+-struct ipu_pre;
+-struct ipu_prg;
+-
+-struct ipu_devtype;
+-
+-struct ipu_soc {
+-      struct device           *dev;
+-      const struct ipu_devtype        *devtype;
+-      enum ipuv3_type         ipu_type;
+-      spinlock_t              lock;
+-      struct mutex            channel_lock;
+-      struct list_head        channels;
+-
+-      void __iomem            *cm_reg;
+-      void __iomem            *idmac_reg;
+-
+-      int                     id;
+-      int                     usecount;
+-
+-      struct clk              *clk;
+-
+-      int                     irq_sync;
+-      int                     irq_err;
+-      struct irq_domain       *domain;
+-
+-      struct ipu_cpmem        *cpmem_priv;
+-      struct ipu_dc_priv      *dc_priv;
+-      struct ipu_dp_priv      *dp_priv;
+-      struct ipu_dmfc_priv    *dmfc_priv;
+-      struct ipu_di           *di_priv[2];
+-      struct ipu_csi          *csi_priv[2];
+-      struct ipu_ic_priv      *ic_priv;
+-      struct ipu_vdi          *vdi_priv;
+-      struct ipu_image_convert_priv *image_convert_priv;
+-      struct ipu_smfc_priv    *smfc_priv;
+-      struct ipu_prg          *prg_priv;
+-};
+-
+-static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
+-{
+-      return readl(ipu->idmac_reg + offset);
+-}
+-
+-static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
+-                                 unsigned offset)
+-{
+-      writel(value, ipu->idmac_reg + offset);
+-}
+-
+-void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync);
+-
+-int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
+-int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
+-
+-bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno);
+-
+-int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
+-               unsigned long base, u32 module, struct clk *clk_ipu);
+-void ipu_csi_exit(struct ipu_soc *ipu, int id);
+-
+-int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
+-              unsigned long base, unsigned long tpmem_base);
+-void ipu_ic_exit(struct ipu_soc *ipu);
+-
+-int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
+-               unsigned long base, u32 module);
+-void ipu_vdi_exit(struct ipu_soc *ipu);
+-
+-int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev);
+-void ipu_image_convert_exit(struct ipu_soc *ipu);
+-
+-int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
+-              unsigned long base, u32 module, struct clk *ipu_clk);
+-void ipu_di_exit(struct ipu_soc *ipu, int id);
+-
+-int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
+-              struct clk *ipu_clk);
+-void ipu_dmfc_exit(struct ipu_soc *ipu);
+-
+-int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
+-void ipu_dp_exit(struct ipu_soc *ipu);
+-
+-int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
+-              unsigned long template_base);
+-void ipu_dc_exit(struct ipu_soc *ipu);
+-
+-int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
+-void ipu_cpmem_exit(struct ipu_soc *ipu);
+-
+-int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
+-void ipu_smfc_exit(struct ipu_soc *ipu);
+-
+-struct ipu_pre *ipu_pre_lookup_by_phandle(struct device *dev, const char *name,
+-                                        int index);
+-int ipu_pre_get_available_count(void);
+-int ipu_pre_get(struct ipu_pre *pre);
+-void ipu_pre_put(struct ipu_pre *pre);
+-u32 ipu_pre_get_baddr(struct ipu_pre *pre);
+-void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
+-                     unsigned int height, unsigned int stride, u32 format,
+-                     uint64_t modifier, unsigned int bufaddr);
+-void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr);
+-bool ipu_pre_update_pending(struct ipu_pre *pre);
+-
+-struct ipu_prg *ipu_prg_lookup_by_phandle(struct device *dev, const char *name,
+-                                        int ipu_id);
+-
+-extern struct platform_driver ipu_pre_drv;
+-extern struct platform_driver ipu_prg_drv;
+-
+-#endif                                /* __IPU_PRV_H__ */
+--- a/drivers/gpu/imx/ipu-v3/ipu-smfc.c
++++ /dev/null
+@@ -1,202 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+- */
+-#include <linux/export.h>
+-#include <linux/types.h>
+-#include <linux/init.h>
+-#include <linux/io.h>
+-#include <linux/errno.h>
+-#include <linux/spinlock.h>
+-#include <linux/delay.h>
+-#include <linux/clk.h>
+-#include <video/imx-ipu-v3.h>
+-
+-#include "ipu-prv.h"
+-
+-struct ipu_smfc {
+-      struct ipu_smfc_priv *priv;
+-      int chno;
+-      bool inuse;
+-};
+-
+-struct ipu_smfc_priv {
+-      void __iomem *base;
+-      spinlock_t lock;
+-      struct ipu_soc *ipu;
+-      struct ipu_smfc channel[4];
+-      int use_count;
+-};
+-
+-/*SMFC Registers */
+-#define SMFC_MAP      0x0000
+-#define SMFC_WMC      0x0004
+-#define SMFC_BS               0x0008
+-
+-int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
+-{
+-      struct ipu_smfc_priv *priv = smfc->priv;
+-      unsigned long flags;
+-      u32 val, shift;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      shift = smfc->chno * 4;
+-      val = readl(priv->base + SMFC_BS);
+-      val &= ~(0xf << shift);
+-      val |= burstsize << shift;
+-      writel(val, priv->base + SMFC_BS);
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);
+-
+-int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
+-{
+-      struct ipu_smfc_priv *priv = smfc->priv;
+-      unsigned long flags;
+-      u32 val, shift;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      shift = smfc->chno * 3;
+-      val = readl(priv->base + SMFC_MAP);
+-      val &= ~(0x7 << shift);
+-      val |= ((csi_id << 2) | mipi_id) << shift;
+-      writel(val, priv->base + SMFC_MAP);
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
+-
+-int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level)
+-{
+-      struct ipu_smfc_priv *priv = smfc->priv;
+-      unsigned long flags;
+-      u32 val, shift;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0);
+-      val = readl(priv->base + SMFC_WMC);
+-      val &= ~(0x3f << shift);
+-      val |= ((clr_level << 3) | set_level) << shift;
+-      writel(val, priv->base + SMFC_WMC);
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark);
+-
+-int ipu_smfc_enable(struct ipu_smfc *smfc)
+-{
+-      struct ipu_smfc_priv *priv = smfc->priv;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      if (!priv->use_count)
+-              ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);
+-
+-      priv->use_count++;
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_smfc_enable);
+-
+-int ipu_smfc_disable(struct ipu_smfc *smfc)
+-{
+-      struct ipu_smfc_priv *priv = smfc->priv;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      priv->use_count--;
+-
+-      if (!priv->use_count)
+-              ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);
+-
+-      if (priv->use_count < 0)
+-              priv->use_count = 0;
+-
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_smfc_disable);
+-
+-struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
+-{
+-      struct ipu_smfc_priv *priv = ipu->smfc_priv;
+-      struct ipu_smfc *smfc, *ret;
+-      unsigned long flags;
+-
+-      if (chno >= 4)
+-              return ERR_PTR(-EINVAL);
+-
+-      smfc = &priv->channel[chno];
+-      ret = smfc;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-
+-      if (smfc->inuse) {
+-              ret = ERR_PTR(-EBUSY);
+-              goto unlock;
+-      }
+-
+-      smfc->inuse = true;
+-unlock:
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-      return ret;
+-}
+-EXPORT_SYMBOL_GPL(ipu_smfc_get);
+-
+-void ipu_smfc_put(struct ipu_smfc *smfc)
+-{
+-      struct ipu_smfc_priv *priv = smfc->priv;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&priv->lock, flags);
+-      smfc->inuse = false;
+-      spin_unlock_irqrestore(&priv->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_smfc_put);
+-
+-int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
+-                unsigned long base)
+-{
+-      struct ipu_smfc_priv *priv;
+-      int i;
+-
+-      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-      if (!priv)
+-              return -ENOMEM;
+-
+-      ipu->smfc_priv = priv;
+-      spin_lock_init(&priv->lock);
+-      priv->ipu = ipu;
+-
+-      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+-      if (!priv->base)
+-              return -ENOMEM;
+-
+-      for (i = 0; i < 4; i++) {
+-              priv->channel[i].priv = priv;
+-              priv->channel[i].chno = i;
+-      }
+-
+-      pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
+-
+-      return 0;
+-}
+-
+-void ipu_smfc_exit(struct ipu_soc *ipu)
+-{
+-}
+--- a/drivers/gpu/imx/ipu-v3/ipu-vdi.c
++++ /dev/null
+@@ -1,234 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Copyright (C) 2012-2016 Mentor Graphics Inc.
+- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+- */
+-#include <linux/io.h>
+-#include "ipu-prv.h"
+-
+-struct ipu_vdi {
+-      void __iomem *base;
+-      u32 module;
+-      spinlock_t lock;
+-      int use_count;
+-      struct ipu_soc *ipu;
+-};
+-
+-
+-/* VDI Register Offsets */
+-#define VDI_FSIZE 0x0000
+-#define VDI_C     0x0004
+-
+-/* VDI Register Fields */
+-#define VDI_C_CH_420             (0 << 1)
+-#define VDI_C_CH_422             (1 << 1)
+-#define VDI_C_MOT_SEL_MASK       (0x3 << 2)
+-#define VDI_C_MOT_SEL_FULL       (2 << 2)
+-#define VDI_C_MOT_SEL_LOW        (1 << 2)
+-#define VDI_C_MOT_SEL_MED        (0 << 2)
+-#define VDI_C_BURST_SIZE1_4      (3 << 4)
+-#define VDI_C_BURST_SIZE2_4      (3 << 8)
+-#define VDI_C_BURST_SIZE3_4      (3 << 12)
+-#define VDI_C_BURST_SIZE_MASK    0xF
+-#define VDI_C_BURST_SIZE1_OFFSET 4
+-#define VDI_C_BURST_SIZE2_OFFSET 8
+-#define VDI_C_BURST_SIZE3_OFFSET 12
+-#define VDI_C_VWM1_SET_1         (0 << 16)
+-#define VDI_C_VWM1_SET_2         (1 << 16)
+-#define VDI_C_VWM1_CLR_2         (1 << 19)
+-#define VDI_C_VWM3_SET_1         (0 << 22)
+-#define VDI_C_VWM3_SET_2         (1 << 22)
+-#define VDI_C_VWM3_CLR_2         (1 << 25)
+-#define VDI_C_TOP_FIELD_MAN_1    (1 << 30)
+-#define VDI_C_TOP_FIELD_AUTO_1   (1 << 31)
+-
+-static inline u32 ipu_vdi_read(struct ipu_vdi *vdi, unsigned int offset)
+-{
+-      return readl(vdi->base + offset);
+-}
+-
+-static inline void ipu_vdi_write(struct ipu_vdi *vdi, u32 value,
+-                               unsigned int offset)
+-{
+-      writel(value, vdi->base + offset);
+-}
+-
+-void ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field)
+-{
+-      bool top_field_0 = false;
+-      unsigned long flags;
+-      u32 reg;
+-
+-      switch (field) {
+-      case V4L2_FIELD_INTERLACED_TB:
+-      case V4L2_FIELD_SEQ_TB:
+-      case V4L2_FIELD_TOP:
+-              top_field_0 = true;
+-              break;
+-      case V4L2_FIELD_INTERLACED_BT:
+-      case V4L2_FIELD_SEQ_BT:
+-      case V4L2_FIELD_BOTTOM:
+-              top_field_0 = false;
+-              break;
+-      default:
+-              top_field_0 = (std & V4L2_STD_525_60) ? true : false;
+-              break;
+-      }
+-
+-      spin_lock_irqsave(&vdi->lock, flags);
+-
+-      reg = ipu_vdi_read(vdi, VDI_C);
+-      if (top_field_0)
+-              reg &= ~(VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1);
+-      else
+-              reg |= VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1;
+-      ipu_vdi_write(vdi, reg, VDI_C);
+-
+-      spin_unlock_irqrestore(&vdi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_set_field_order);
+-
+-void ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel)
+-{
+-      unsigned long flags;
+-      u32 reg;
+-
+-      spin_lock_irqsave(&vdi->lock, flags);
+-
+-      reg = ipu_vdi_read(vdi, VDI_C);
+-
+-      reg &= ~VDI_C_MOT_SEL_MASK;
+-
+-      switch (motion_sel) {
+-      case MED_MOTION:
+-              reg |= VDI_C_MOT_SEL_MED;
+-              break;
+-      case HIGH_MOTION:
+-              reg |= VDI_C_MOT_SEL_FULL;
+-              break;
+-      default:
+-              reg |= VDI_C_MOT_SEL_LOW;
+-              break;
+-      }
+-
+-      ipu_vdi_write(vdi, reg, VDI_C);
+-
+-      spin_unlock_irqrestore(&vdi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_set_motion);
+-
+-void ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres)
+-{
+-      unsigned long flags;
+-      u32 pixel_fmt, reg;
+-
+-      spin_lock_irqsave(&vdi->lock, flags);
+-
+-      reg = ((yres - 1) << 16) | (xres - 1);
+-      ipu_vdi_write(vdi, reg, VDI_FSIZE);
+-
+-      /*
+-       * Full motion, only vertical filter is used.
+-       * Burst size is 4 accesses
+-       */
+-      if (code == MEDIA_BUS_FMT_UYVY8_2X8 ||
+-          code == MEDIA_BUS_FMT_UYVY8_1X16 ||
+-          code == MEDIA_BUS_FMT_YUYV8_2X8 ||
+-          code == MEDIA_BUS_FMT_YUYV8_1X16)
+-              pixel_fmt = VDI_C_CH_422;
+-      else
+-              pixel_fmt = VDI_C_CH_420;
+-
+-      reg = ipu_vdi_read(vdi, VDI_C);
+-      reg |= pixel_fmt;
+-      reg |= VDI_C_BURST_SIZE2_4;
+-      reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_CLR_2;
+-      reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_CLR_2;
+-      ipu_vdi_write(vdi, reg, VDI_C);
+-
+-      spin_unlock_irqrestore(&vdi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_setup);
+-
+-void ipu_vdi_unsetup(struct ipu_vdi *vdi)
+-{
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&vdi->lock, flags);
+-      ipu_vdi_write(vdi, 0, VDI_FSIZE);
+-      ipu_vdi_write(vdi, 0, VDI_C);
+-      spin_unlock_irqrestore(&vdi->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_unsetup);
+-
+-int ipu_vdi_enable(struct ipu_vdi *vdi)
+-{
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&vdi->lock, flags);
+-
+-      if (!vdi->use_count)
+-              ipu_module_enable(vdi->ipu, vdi->module);
+-
+-      vdi->use_count++;
+-
+-      spin_unlock_irqrestore(&vdi->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_enable);
+-
+-int ipu_vdi_disable(struct ipu_vdi *vdi)
+-{
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&vdi->lock, flags);
+-
+-      if (vdi->use_count) {
+-              if (!--vdi->use_count)
+-                      ipu_module_disable(vdi->ipu, vdi->module);
+-      }
+-
+-      spin_unlock_irqrestore(&vdi->lock, flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_disable);
+-
+-struct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu)
+-{
+-      return ipu->vdi_priv;
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_get);
+-
+-void ipu_vdi_put(struct ipu_vdi *vdi)
+-{
+-}
+-EXPORT_SYMBOL_GPL(ipu_vdi_put);
+-
+-int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
+-               unsigned long base, u32 module)
+-{
+-      struct ipu_vdi *vdi;
+-
+-      vdi = devm_kzalloc(dev, sizeof(*vdi), GFP_KERNEL);
+-      if (!vdi)
+-              return -ENOMEM;
+-
+-      ipu->vdi_priv = vdi;
+-
+-      spin_lock_init(&vdi->lock);
+-      vdi->module = module;
+-      vdi->base = devm_ioremap(dev, base, PAGE_SIZE);
+-      if (!vdi->base)
+-              return -ENOMEM;
+-
+-      dev_dbg(dev, "VDI base: 0x%08lx remapped to %p\n", base, vdi->base);
+-      vdi->ipu = ipu;
+-
+-      return 0;
+-}
+-
+-void ipu_vdi_exit(struct ipu_soc *ipu)
+-{
+-}
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/Kconfig
+@@ -0,0 +1,11 @@
++# SPDX-License-Identifier: GPL-2.0-only
++config IMX_IPUV3_CORE
++      tristate "IPUv3 core support"
++      depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM || COMPILE_TEST
++      depends on DRM || !DRM # if DRM=m, this can't be 'y'
++      select BITREVERSE
++      select GENERIC_ALLOCATOR if DRM
++      select GENERIC_IRQ_CHIP
++      help
++        Choose this if you have a i.MX5/6 system and want to use the Image
++        Processing Unit. This option only enables IPU base support.
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/Makefile
+@@ -0,0 +1,10 @@
++# SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
++
++imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
++              ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-ic-csc.o \
++              ipu-image-convert.o ipu-smfc.o ipu-vdi.o
++
++ifdef CONFIG_DRM
++      imx-ipu-v3-objs += ipu-pre.o ipu-prg.o
++endif
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/ipu-common.c
+@@ -0,0 +1,1565 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++#include <linux/module.h>
++#include <linux/export.h>
++#include <linux/types.h>
++#include <linux/reset.h>
++#include <linux/platform_device.h>
++#include <linux/err.h>
++#include <linux/spinlock.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/clk.h>
++#include <linux/list.h>
++#include <linux/irq.h>
++#include <linux/irqchip/chained_irq.h>
++#include <linux/irqdomain.h>
++#include <linux/of_device.h>
++#include <linux/of_graph.h>
++
++#include <drm/drm_fourcc.h>
++
++#include <video/imx-ipu-v3.h>
++#include "ipu-prv.h"
++
++static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
++{
++      return readl(ipu->cm_reg + offset);
++}
++
++static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
++{
++      writel(value, ipu->cm_reg + offset);
++}
++
++int ipu_get_num(struct ipu_soc *ipu)
++{
++      return ipu->id;
++}
++EXPORT_SYMBOL_GPL(ipu_get_num);
++
++void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync)
++{
++      u32 val;
++
++      val = ipu_cm_read(ipu, IPU_SRM_PRI2);
++      val &= ~DP_S_SRM_MODE_MASK;
++      val |= sync ? DP_S_SRM_MODE_NEXT_FRAME :
++                    DP_S_SRM_MODE_NOW;
++      ipu_cm_write(ipu, val, IPU_SRM_PRI2);
++}
++EXPORT_SYMBOL_GPL(ipu_srm_dp_update);
++
++enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
++{
++      switch (drm_fourcc) {
++      case DRM_FORMAT_ARGB1555:
++      case DRM_FORMAT_ABGR1555:
++      case DRM_FORMAT_RGBA5551:
++      case DRM_FORMAT_BGRA5551:
++      case DRM_FORMAT_RGB565:
++      case DRM_FORMAT_BGR565:
++      case DRM_FORMAT_RGB888:
++      case DRM_FORMAT_BGR888:
++      case DRM_FORMAT_ARGB4444:
++      case DRM_FORMAT_XRGB8888:
++      case DRM_FORMAT_XBGR8888:
++      case DRM_FORMAT_RGBX8888:
++      case DRM_FORMAT_BGRX8888:
++      case DRM_FORMAT_ARGB8888:
++      case DRM_FORMAT_ABGR8888:
++      case DRM_FORMAT_RGBA8888:
++      case DRM_FORMAT_BGRA8888:
++      case DRM_FORMAT_RGB565_A8:
++      case DRM_FORMAT_BGR565_A8:
++      case DRM_FORMAT_RGB888_A8:
++      case DRM_FORMAT_BGR888_A8:
++      case DRM_FORMAT_RGBX8888_A8:
++      case DRM_FORMAT_BGRX8888_A8:
++              return IPUV3_COLORSPACE_RGB;
++      case DRM_FORMAT_YUYV:
++      case DRM_FORMAT_UYVY:
++      case DRM_FORMAT_YUV420:
++      case DRM_FORMAT_YVU420:
++      case DRM_FORMAT_YUV422:
++      case DRM_FORMAT_YVU422:
++      case DRM_FORMAT_YUV444:
++      case DRM_FORMAT_YVU444:
++      case DRM_FORMAT_NV12:
++      case DRM_FORMAT_NV21:
++      case DRM_FORMAT_NV16:
++      case DRM_FORMAT_NV61:
++              return IPUV3_COLORSPACE_YUV;
++      default:
++              return IPUV3_COLORSPACE_UNKNOWN;
++      }
++}
++EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace);
++
++enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
++{
++      switch (pixelformat) {
++      case V4L2_PIX_FMT_YUV420:
++      case V4L2_PIX_FMT_YVU420:
++      case V4L2_PIX_FMT_YUV422P:
++      case V4L2_PIX_FMT_UYVY:
++      case V4L2_PIX_FMT_YUYV:
++      case V4L2_PIX_FMT_NV12:
++      case V4L2_PIX_FMT_NV21:
++      case V4L2_PIX_FMT_NV16:
++      case V4L2_PIX_FMT_NV61:
++              return IPUV3_COLORSPACE_YUV;
++      case V4L2_PIX_FMT_RGB565:
++      case V4L2_PIX_FMT_BGR24:
++      case V4L2_PIX_FMT_RGB24:
++      case V4L2_PIX_FMT_ABGR32:
++      case V4L2_PIX_FMT_XBGR32:
++      case V4L2_PIX_FMT_BGRA32:
++      case V4L2_PIX_FMT_BGRX32:
++      case V4L2_PIX_FMT_RGBA32:
++      case V4L2_PIX_FMT_RGBX32:
++      case V4L2_PIX_FMT_ARGB32:
++      case V4L2_PIX_FMT_XRGB32:
++              return IPUV3_COLORSPACE_RGB;
++      default:
++              return IPUV3_COLORSPACE_UNKNOWN;
++      }
++}
++EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
++
++bool ipu_pixelformat_is_planar(u32 pixelformat)
++{
++      switch (pixelformat) {
++      case V4L2_PIX_FMT_YUV420:
++      case V4L2_PIX_FMT_YVU420:
++      case V4L2_PIX_FMT_YUV422P:
++      case V4L2_PIX_FMT_NV12:
++      case V4L2_PIX_FMT_NV21:
++      case V4L2_PIX_FMT_NV16:
++      case V4L2_PIX_FMT_NV61:
++              return true;
++      }
++
++      return false;
++}
++EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar);
++
++enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
++{
++      switch (mbus_code & 0xf000) {
++      case 0x1000:
++              return IPUV3_COLORSPACE_RGB;
++      case 0x2000:
++              return IPUV3_COLORSPACE_YUV;
++      default:
++              return IPUV3_COLORSPACE_UNKNOWN;
++      }
++}
++EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
++
++int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat)
++{
++      switch (pixelformat) {
++      case V4L2_PIX_FMT_YUV420:
++      case V4L2_PIX_FMT_YVU420:
++      case V4L2_PIX_FMT_YUV422P:
++      case V4L2_PIX_FMT_NV12:
++      case V4L2_PIX_FMT_NV21:
++      case V4L2_PIX_FMT_NV16:
++      case V4L2_PIX_FMT_NV61:
++              /*
++               * for the planar YUV formats, the stride passed to
++               * cpmem must be the stride in bytes of the Y plane.
++               * And all the planar YUV formats have an 8-bit
++               * Y component.
++               */
++              return (8 * pixel_stride) >> 3;
++      case V4L2_PIX_FMT_RGB565:
++      case V4L2_PIX_FMT_YUYV:
++      case V4L2_PIX_FMT_UYVY:
++              return (16 * pixel_stride) >> 3;
++      case V4L2_PIX_FMT_BGR24:
++      case V4L2_PIX_FMT_RGB24:
++              return (24 * pixel_stride) >> 3;
++      case V4L2_PIX_FMT_BGR32:
++      case V4L2_PIX_FMT_RGB32:
++      case V4L2_PIX_FMT_XBGR32:
++      case V4L2_PIX_FMT_XRGB32:
++              return (32 * pixel_stride) >> 3;
++      default:
++              break;
++      }
++
++      return -EINVAL;
++}
++EXPORT_SYMBOL_GPL(ipu_stride_to_bytes);
++
++int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
++                          bool hflip, bool vflip)
++{
++      u32 r90, vf, hf;
++
++      switch (degrees) {
++      case 0:
++              vf = hf = r90 = 0;
++              break;
++      case 90:
++              vf = hf = 0;
++              r90 = 1;
++              break;
++      case 180:
++              vf = hf = 1;
++              r90 = 0;
++              break;
++      case 270:
++              vf = hf = r90 = 1;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      hf ^= (u32)hflip;
++      vf ^= (u32)vflip;
++
++      *mode = (enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf);
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode);
++
++int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
++                          bool hflip, bool vflip)
++{
++      u32 r90, vf, hf;
++
++      r90 = ((u32)mode >> 2) & 0x1;
++      hf = ((u32)mode >> 1) & 0x1;
++      vf = ((u32)mode >> 0) & 0x1;
++      hf ^= (u32)hflip;
++      vf ^= (u32)vflip;
++
++      switch ((enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf)) {
++      case IPU_ROTATE_NONE:
++              *degrees = 0;
++              break;
++      case IPU_ROTATE_90_RIGHT:
++              *degrees = 90;
++              break;
++      case IPU_ROTATE_180:
++              *degrees = 180;
++              break;
++      case IPU_ROTATE_90_LEFT:
++              *degrees = 270;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees);
++
++struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
++{
++      struct ipuv3_channel *channel;
++
++      dev_dbg(ipu->dev, "%s %d\n", __func__, num);
++
++      if (num > 63)
++              return ERR_PTR(-ENODEV);
++
++      mutex_lock(&ipu->channel_lock);
++
++      list_for_each_entry(channel, &ipu->channels, list) {
++              if (channel->num == num) {
++                      channel = ERR_PTR(-EBUSY);
++                      goto out;
++              }
++      }
++
++      channel = kzalloc(sizeof(*channel), GFP_KERNEL);
++      if (!channel) {
++              channel = ERR_PTR(-ENOMEM);
++              goto out;
++      }
++
++      channel->num = num;
++      channel->ipu = ipu;
++      list_add(&channel->list, &ipu->channels);
++
++out:
++      mutex_unlock(&ipu->channel_lock);
++
++      return channel;
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_get);
++
++void ipu_idmac_put(struct ipuv3_channel *channel)
++{
++      struct ipu_soc *ipu = channel->ipu;
++
++      dev_dbg(ipu->dev, "%s %d\n", __func__, channel->num);
++
++      mutex_lock(&ipu->channel_lock);
++
++      list_del(&channel->list);
++      kfree(channel);
++
++      mutex_unlock(&ipu->channel_lock);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_put);
++
++#define idma_mask(ch)                 (1 << ((ch) & 0x1f))
++
++/*
++ * This is an undocumented feature, a write one to a channel bit in
++ * IPU_CHA_CUR_BUF and IPU_CHA_TRIPLE_CUR_BUF will reset the channel's
++ * internal current buffer pointer so that transfers start from buffer
++ * 0 on the next channel enable (that's the theory anyway, the imx6 TRM
++ * only says these are read-only registers). This operation is required
++ * for channel linking to work correctly, for instance video capture
++ * pipelines that carry out image rotations will fail after the first
++ * streaming unless this function is called for each channel before
++ * re-enabling the channels.
++ */
++static void __ipu_idmac_reset_current_buffer(struct ipuv3_channel *channel)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned int chno = channel->num;
++
++      ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_CUR_BUF(chno));
++}
++
++void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
++              bool doublebuffer)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned long flags;
++      u32 reg;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
++      if (doublebuffer)
++              reg |= idma_mask(channel->num);
++      else
++              reg &= ~idma_mask(channel->num);
++      ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
++
++      __ipu_idmac_reset_current_buffer(channel);
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
++
++static const struct {
++      int chnum;
++      u32 reg;
++      int shift;
++} idmac_lock_en_info[] = {
++      { .chnum =  5, .reg = IDMAC_CH_LOCK_EN_1, .shift =  0, },
++      { .chnum = 11, .reg = IDMAC_CH_LOCK_EN_1, .shift =  2, },
++      { .chnum = 12, .reg = IDMAC_CH_LOCK_EN_1, .shift =  4, },
++      { .chnum = 14, .reg = IDMAC_CH_LOCK_EN_1, .shift =  6, },
++      { .chnum = 15, .reg = IDMAC_CH_LOCK_EN_1, .shift =  8, },
++      { .chnum = 20, .reg = IDMAC_CH_LOCK_EN_1, .shift = 10, },
++      { .chnum = 21, .reg = IDMAC_CH_LOCK_EN_1, .shift = 12, },
++      { .chnum = 22, .reg = IDMAC_CH_LOCK_EN_1, .shift = 14, },
++      { .chnum = 23, .reg = IDMAC_CH_LOCK_EN_1, .shift = 16, },
++      { .chnum = 27, .reg = IDMAC_CH_LOCK_EN_1, .shift = 18, },
++      { .chnum = 28, .reg = IDMAC_CH_LOCK_EN_1, .shift = 20, },
++      { .chnum = 45, .reg = IDMAC_CH_LOCK_EN_2, .shift =  0, },
++      { .chnum = 46, .reg = IDMAC_CH_LOCK_EN_2, .shift =  2, },
++      { .chnum = 47, .reg = IDMAC_CH_LOCK_EN_2, .shift =  4, },
++      { .chnum = 48, .reg = IDMAC_CH_LOCK_EN_2, .shift =  6, },
++      { .chnum = 49, .reg = IDMAC_CH_LOCK_EN_2, .shift =  8, },
++      { .chnum = 50, .reg = IDMAC_CH_LOCK_EN_2, .shift = 10, },
++};
++
++int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned long flags;
++      u32 bursts, regval;
++      int i;
++
++      switch (num_bursts) {
++      case 0:
++      case 1:
++              bursts = 0x00; /* locking disabled */
++              break;
++      case 2:
++              bursts = 0x01;
++              break;
++      case 4:
++              bursts = 0x02;
++              break;
++      case 8:
++              bursts = 0x03;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      /*
++       * IPUv3EX / i.MX51 has a different register layout, and on IPUv3M /
++       * i.MX53 channel arbitration locking doesn't seem to work properly.
++       * Allow enabling the lock feature on IPUv3H / i.MX6 only.
++       */
++      if (bursts && ipu->ipu_type != IPUV3H)
++              return -EINVAL;
++
++      for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) {
++              if (channel->num == idmac_lock_en_info[i].chnum)
++                      break;
++      }
++      if (i >= ARRAY_SIZE(idmac_lock_en_info))
++              return -EINVAL;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      regval = ipu_idmac_read(ipu, idmac_lock_en_info[i].reg);
++      regval &= ~(0x03 << idmac_lock_en_info[i].shift);
++      regval |= (bursts << idmac_lock_en_info[i].shift);
++      ipu_idmac_write(ipu, regval, idmac_lock_en_info[i].reg);
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_lock_enable);
++
++int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
++{
++      unsigned long lock_flags;
++      u32 val;
++
++      spin_lock_irqsave(&ipu->lock, lock_flags);
++
++      val = ipu_cm_read(ipu, IPU_DISP_GEN);
++
++      if (mask & IPU_CONF_DI0_EN)
++              val |= IPU_DI0_COUNTER_RELEASE;
++      if (mask & IPU_CONF_DI1_EN)
++              val |= IPU_DI1_COUNTER_RELEASE;
++
++      ipu_cm_write(ipu, val, IPU_DISP_GEN);
++
++      val = ipu_cm_read(ipu, IPU_CONF);
++      val |= mask;
++      ipu_cm_write(ipu, val, IPU_CONF);
++
++      spin_unlock_irqrestore(&ipu->lock, lock_flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_module_enable);
++
++int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
++{
++      unsigned long lock_flags;
++      u32 val;
++
++      spin_lock_irqsave(&ipu->lock, lock_flags);
++
++      val = ipu_cm_read(ipu, IPU_CONF);
++      val &= ~mask;
++      ipu_cm_write(ipu, val, IPU_CONF);
++
++      val = ipu_cm_read(ipu, IPU_DISP_GEN);
++
++      if (mask & IPU_CONF_DI0_EN)
++              val &= ~IPU_DI0_COUNTER_RELEASE;
++      if (mask & IPU_CONF_DI1_EN)
++              val &= ~IPU_DI1_COUNTER_RELEASE;
++
++      ipu_cm_write(ipu, val, IPU_DISP_GEN);
++
++      spin_unlock_irqrestore(&ipu->lock, lock_flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_module_disable);
++
++int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned int chno = channel->num;
++
++      return (ipu_cm_read(ipu, IPU_CHA_CUR_BUF(chno)) & idma_mask(chno)) ? 1 : 0;
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer);
++
++bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned long flags;
++      u32 reg = 0;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++      switch (buf_num) {
++      case 0:
++              reg = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num));
++              break;
++      case 1:
++              reg = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num));
++              break;
++      case 2:
++              reg = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(channel->num));
++              break;
++      }
++      spin_unlock_irqrestore(&ipu->lock, flags);
++
++      return ((reg & idma_mask(channel->num)) != 0);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_buffer_is_ready);
++
++void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned int chno = channel->num;
++      unsigned long flags;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      /* Mark buffer as ready. */
++      if (buf_num == 0)
++              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
++      else
++              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
++
++void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned int chno = channel->num;
++      unsigned long flags;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */
++      switch (buf_num) {
++      case 0:
++              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
++              break;
++      case 1:
++              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
++              break;
++      case 2:
++              ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF2_RDY(chno));
++              break;
++      default:
++              break;
++      }
++      ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer);
++
++int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      u32 val;
++      unsigned long flags;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
++      val |= idma_mask(channel->num);
++      ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
++
++bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno)
++{
++      return (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(chno)) & idma_mask(chno));
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_channel_busy);
++
++int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned long timeout;
++
++      timeout = jiffies + msecs_to_jiffies(ms);
++      while (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(channel->num)) &
++                      idma_mask(channel->num)) {
++              if (time_after(jiffies, timeout))
++                      return -ETIMEDOUT;
++              cpu_relax();
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy);
++
++int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      u32 val;
++      unsigned long flags;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      /* Disable DMA channel(s) */
++      val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
++      val &= ~idma_mask(channel->num);
++      ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
++
++      __ipu_idmac_reset_current_buffer(channel);
++
++      /* Set channel buffers NOT to be ready */
++      ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
++
++      if (ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num)) &
++                      idma_mask(channel->num)) {
++              ipu_cm_write(ipu, idma_mask(channel->num),
++                           IPU_CHA_BUF0_RDY(channel->num));
++      }
++
++      if (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num)) &
++                      idma_mask(channel->num)) {
++              ipu_cm_write(ipu, idma_mask(channel->num),
++                           IPU_CHA_BUF1_RDY(channel->num));
++      }
++
++      ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
++
++      /* Reset the double buffer */
++      val = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
++      val &= ~idma_mask(channel->num);
++      ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num));
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
++
++/*
++ * The imx6 rev. D TRM says that enabling the WM feature will increase
++ * a channel's priority. Refer to Table 36-8 Calculated priority value.
++ * The sub-module that is the sink or source for the channel must enable
++ * watermark signal for this to take effect (SMFC_WM for instance).
++ */
++void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable)
++{
++      struct ipu_soc *ipu = channel->ipu;
++      unsigned long flags;
++      u32 val;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      val = ipu_idmac_read(ipu, IDMAC_WM_EN(channel->num));
++      if (enable)
++              val |= 1 << (channel->num % 32);
++      else
++              val &= ~(1 << (channel->num % 32));
++      ipu_idmac_write(ipu, val, IDMAC_WM_EN(channel->num));
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_enable_watermark);
++
++static int ipu_memory_reset(struct ipu_soc *ipu)
++{
++      unsigned long timeout;
++
++      ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST);
++
++      timeout = jiffies + msecs_to_jiffies(1000);
++      while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) {
++              if (time_after(jiffies, timeout))
++                      return -ETIME;
++              cpu_relax();
++      }
++
++      return 0;
++}
++
++/*
++ * Set the source mux for the given CSI. Selects either parallel or
++ * MIPI CSI2 sources.
++ */
++void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2)
++{
++      unsigned long flags;
++      u32 val, mask;
++
++      mask = (csi_id == 1) ? IPU_CONF_CSI1_DATA_SOURCE :
++              IPU_CONF_CSI0_DATA_SOURCE;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      val = ipu_cm_read(ipu, IPU_CONF);
++      if (mipi_csi2)
++              val |= mask;
++      else
++              val &= ~mask;
++      ipu_cm_write(ipu, val, IPU_CONF);
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_set_csi_src_mux);
++
++/*
++ * Set the source mux for the IC. Selects either CSI[01] or the VDI.
++ */
++void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi)
++{
++      unsigned long flags;
++      u32 val;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      val = ipu_cm_read(ipu, IPU_CONF);
++      if (vdi)
++              val |= IPU_CONF_IC_INPUT;
++      else
++              val &= ~IPU_CONF_IC_INPUT;
++
++      if (csi_id == 1)
++              val |= IPU_CONF_CSI_SEL;
++      else
++              val &= ~IPU_CONF_CSI_SEL;
++
++      ipu_cm_write(ipu, val, IPU_CONF);
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux);
++
++
++/* Frame Synchronization Unit Channel Linking */
++
++struct fsu_link_reg_info {
++      int chno;
++      u32 reg;
++      u32 mask;
++      u32 val;
++};
++
++struct fsu_link_info {
++      struct fsu_link_reg_info src;
++      struct fsu_link_reg_info sink;
++};
++
++static const struct fsu_link_info fsu_link_info[] = {
++      {
++              .src  = { IPUV3_CHANNEL_IC_PRP_ENC_MEM, IPU_FS_PROC_FLOW2,
++                        FS_PRP_ENC_DEST_SEL_MASK, FS_PRP_ENC_DEST_SEL_IRT_ENC },
++              .sink = { IPUV3_CHANNEL_MEM_ROT_ENC, IPU_FS_PROC_FLOW1,
++                        FS_PRPENC_ROT_SRC_SEL_MASK, FS_PRPENC_ROT_SRC_SEL_ENC },
++      }, {
++              .src =  { IPUV3_CHANNEL_IC_PRP_VF_MEM, IPU_FS_PROC_FLOW2,
++                        FS_PRPVF_DEST_SEL_MASK, FS_PRPVF_DEST_SEL_IRT_VF },
++              .sink = { IPUV3_CHANNEL_MEM_ROT_VF, IPU_FS_PROC_FLOW1,
++                        FS_PRPVF_ROT_SRC_SEL_MASK, FS_PRPVF_ROT_SRC_SEL_VF },
++      }, {
++              .src =  { IPUV3_CHANNEL_IC_PP_MEM, IPU_FS_PROC_FLOW2,
++                        FS_PP_DEST_SEL_MASK, FS_PP_DEST_SEL_IRT_PP },
++              .sink = { IPUV3_CHANNEL_MEM_ROT_PP, IPU_FS_PROC_FLOW1,
++                        FS_PP_ROT_SRC_SEL_MASK, FS_PP_ROT_SRC_SEL_PP },
++      }, {
++              .src =  { IPUV3_CHANNEL_CSI_DIRECT, 0 },
++              .sink = { IPUV3_CHANNEL_CSI_VDI_PREV, IPU_FS_PROC_FLOW1,
++                        FS_VDI_SRC_SEL_MASK, FS_VDI_SRC_SEL_CSI_DIRECT },
++      },
++};
++
++static const struct fsu_link_info *find_fsu_link_info(int src, int sink)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(fsu_link_info); i++) {
++              if (src == fsu_link_info[i].src.chno &&
++                  sink == fsu_link_info[i].sink.chno)
++                      return &fsu_link_info[i];
++      }
++
++      return NULL;
++}
++
++/*
++ * Links a source channel to a sink channel in the FSU.
++ */
++int ipu_fsu_link(struct ipu_soc *ipu, int src_ch, int sink_ch)
++{
++      const struct fsu_link_info *link;
++      u32 src_reg, sink_reg;
++      unsigned long flags;
++
++      link = find_fsu_link_info(src_ch, sink_ch);
++      if (!link)
++              return -EINVAL;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      if (link->src.mask) {
++              src_reg = ipu_cm_read(ipu, link->src.reg);
++              src_reg &= ~link->src.mask;
++              src_reg |= link->src.val;
++              ipu_cm_write(ipu, src_reg, link->src.reg);
++      }
++
++      if (link->sink.mask) {
++              sink_reg = ipu_cm_read(ipu, link->sink.reg);
++              sink_reg &= ~link->sink.mask;
++              sink_reg |= link->sink.val;
++              ipu_cm_write(ipu, sink_reg, link->sink.reg);
++      }
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_fsu_link);
++
++/*
++ * Unlinks source and sink channels in the FSU.
++ */
++int ipu_fsu_unlink(struct ipu_soc *ipu, int src_ch, int sink_ch)
++{
++      const struct fsu_link_info *link;
++      u32 src_reg, sink_reg;
++      unsigned long flags;
++
++      link = find_fsu_link_info(src_ch, sink_ch);
++      if (!link)
++              return -EINVAL;
++
++      spin_lock_irqsave(&ipu->lock, flags);
++
++      if (link->src.mask) {
++              src_reg = ipu_cm_read(ipu, link->src.reg);
++              src_reg &= ~link->src.mask;
++              ipu_cm_write(ipu, src_reg, link->src.reg);
++      }
++
++      if (link->sink.mask) {
++              sink_reg = ipu_cm_read(ipu, link->sink.reg);
++              sink_reg &= ~link->sink.mask;
++              ipu_cm_write(ipu, sink_reg, link->sink.reg);
++      }
++
++      spin_unlock_irqrestore(&ipu->lock, flags);
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_fsu_unlink);
++
++/* Link IDMAC channels in the FSU */
++int ipu_idmac_link(struct ipuv3_channel *src, struct ipuv3_channel *sink)
++{
++      return ipu_fsu_link(src->ipu, src->num, sink->num);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_link);
++
++/* Unlink IDMAC channels in the FSU */
++int ipu_idmac_unlink(struct ipuv3_channel *src, struct ipuv3_channel *sink)
++{
++      return ipu_fsu_unlink(src->ipu, src->num, sink->num);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_unlink);
++
++struct ipu_devtype {
++      const char *name;
++      unsigned long cm_ofs;
++      unsigned long cpmem_ofs;
++      unsigned long srm_ofs;
++      unsigned long tpm_ofs;
++      unsigned long csi0_ofs;
++      unsigned long csi1_ofs;
++      unsigned long ic_ofs;
++      unsigned long disp0_ofs;
++      unsigned long disp1_ofs;
++      unsigned long dc_tmpl_ofs;
++      unsigned long vdi_ofs;
++      enum ipuv3_type type;
++};
++
++static struct ipu_devtype ipu_type_imx51 = {
++      .name = "IPUv3EX",
++      .cm_ofs = 0x1e000000,
++      .cpmem_ofs = 0x1f000000,
++      .srm_ofs = 0x1f040000,
++      .tpm_ofs = 0x1f060000,
++      .csi0_ofs = 0x1e030000,
++      .csi1_ofs = 0x1e038000,
++      .ic_ofs = 0x1e020000,
++      .disp0_ofs = 0x1e040000,
++      .disp1_ofs = 0x1e048000,
++      .dc_tmpl_ofs = 0x1f080000,
++      .vdi_ofs = 0x1e068000,
++      .type = IPUV3EX,
++};
++
++static struct ipu_devtype ipu_type_imx53 = {
++      .name = "IPUv3M",
++      .cm_ofs = 0x06000000,
++      .cpmem_ofs = 0x07000000,
++      .srm_ofs = 0x07040000,
++      .tpm_ofs = 0x07060000,
++      .csi0_ofs = 0x06030000,
++      .csi1_ofs = 0x06038000,
++      .ic_ofs = 0x06020000,
++      .disp0_ofs = 0x06040000,
++      .disp1_ofs = 0x06048000,
++      .dc_tmpl_ofs = 0x07080000,
++      .vdi_ofs = 0x06068000,
++      .type = IPUV3M,
++};
++
++static struct ipu_devtype ipu_type_imx6q = {
++      .name = "IPUv3H",
++      .cm_ofs = 0x00200000,
++      .cpmem_ofs = 0x00300000,
++      .srm_ofs = 0x00340000,
++      .tpm_ofs = 0x00360000,
++      .csi0_ofs = 0x00230000,
++      .csi1_ofs = 0x00238000,
++      .ic_ofs = 0x00220000,
++      .disp0_ofs = 0x00240000,
++      .disp1_ofs = 0x00248000,
++      .dc_tmpl_ofs = 0x00380000,
++      .vdi_ofs = 0x00268000,
++      .type = IPUV3H,
++};
++
++static const struct of_device_id imx_ipu_dt_ids[] = {
++      { .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
++      { .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
++      { .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
++      { .compatible = "fsl,imx6qp-ipu", .data = &ipu_type_imx6q, },
++      { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, imx_ipu_dt_ids);
++
++static int ipu_submodules_init(struct ipu_soc *ipu,
++              struct platform_device *pdev, unsigned long ipu_base,
++              struct clk *ipu_clk)
++{
++      char *unit;
++      int ret;
++      struct device *dev = &pdev->dev;
++      const struct ipu_devtype *devtype = ipu->devtype;
++
++      ret = ipu_cpmem_init(ipu, dev, ipu_base + devtype->cpmem_ofs);
++      if (ret) {
++              unit = "cpmem";
++              goto err_cpmem;
++      }
++
++      ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs,
++                         IPU_CONF_CSI0_EN, ipu_clk);
++      if (ret) {
++              unit = "csi0";
++              goto err_csi_0;
++      }
++
++      ret = ipu_csi_init(ipu, dev, 1, ipu_base + devtype->csi1_ofs,
++                         IPU_CONF_CSI1_EN, ipu_clk);
++      if (ret) {
++              unit = "csi1";
++              goto err_csi_1;
++      }
++
++      ret = ipu_ic_init(ipu, dev,
++                        ipu_base + devtype->ic_ofs,
++                        ipu_base + devtype->tpm_ofs);
++      if (ret) {
++              unit = "ic";
++              goto err_ic;
++      }
++
++      ret = ipu_vdi_init(ipu, dev, ipu_base + devtype->vdi_ofs,
++                         IPU_CONF_VDI_EN | IPU_CONF_ISP_EN |
++                         IPU_CONF_IC_INPUT);
++      if (ret) {
++              unit = "vdi";
++              goto err_vdi;
++      }
++
++      ret = ipu_image_convert_init(ipu, dev);
++      if (ret) {
++              unit = "image_convert";
++              goto err_image_convert;
++      }
++
++      ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
++                        IPU_CONF_DI0_EN, ipu_clk);
++      if (ret) {
++              unit = "di0";
++              goto err_di_0;
++      }
++
++      ret = ipu_di_init(ipu, dev, 1, ipu_base + devtype->disp1_ofs,
++                      IPU_CONF_DI1_EN, ipu_clk);
++      if (ret) {
++              unit = "di1";
++              goto err_di_1;
++      }
++
++      ret = ipu_dc_init(ipu, dev, ipu_base + devtype->cm_ofs +
++                      IPU_CM_DC_REG_OFS, ipu_base + devtype->dc_tmpl_ofs);
++      if (ret) {
++              unit = "dc_template";
++              goto err_dc;
++      }
++
++      ret = ipu_dmfc_init(ipu, dev, ipu_base +
++                      devtype->cm_ofs + IPU_CM_DMFC_REG_OFS, ipu_clk);
++      if (ret) {
++              unit = "dmfc";
++              goto err_dmfc;
++      }
++
++      ret = ipu_dp_init(ipu, dev, ipu_base + devtype->srm_ofs);
++      if (ret) {
++              unit = "dp";
++              goto err_dp;
++      }
++
++      ret = ipu_smfc_init(ipu, dev, ipu_base +
++                      devtype->cm_ofs + IPU_CM_SMFC_REG_OFS);
++      if (ret) {
++              unit = "smfc";
++              goto err_smfc;
++      }
++
++      return 0;
++
++err_smfc:
++      ipu_dp_exit(ipu);
++err_dp:
++      ipu_dmfc_exit(ipu);
++err_dmfc:
++      ipu_dc_exit(ipu);
++err_dc:
++      ipu_di_exit(ipu, 1);
++err_di_1:
++      ipu_di_exit(ipu, 0);
++err_di_0:
++      ipu_image_convert_exit(ipu);
++err_image_convert:
++      ipu_vdi_exit(ipu);
++err_vdi:
++      ipu_ic_exit(ipu);
++err_ic:
++      ipu_csi_exit(ipu, 1);
++err_csi_1:
++      ipu_csi_exit(ipu, 0);
++err_csi_0:
++      ipu_cpmem_exit(ipu);
++err_cpmem:
++      dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
++      return ret;
++}
++
++static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs)
++{
++      unsigned long status;
++      int i, bit, irq;
++
++      for (i = 0; i < num_regs; i++) {
++
++              status = ipu_cm_read(ipu, IPU_INT_STAT(regs[i]));
++              status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i]));
++
++              for_each_set_bit(bit, &status, 32) {
++                      irq = irq_linear_revmap(ipu->domain,
++                                              regs[i] * 32 + bit);
++                      if (irq)
++                              generic_handle_irq(irq);
++              }
++      }
++}
++
++static void ipu_irq_handler(struct irq_desc *desc)
++{
++      struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
++      struct irq_chip *chip = irq_desc_get_chip(desc);
++      static const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
++
++      chained_irq_enter(chip, desc);
++
++      ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
++
++      chained_irq_exit(chip, desc);
++}
++
++static void ipu_err_irq_handler(struct irq_desc *desc)
++{
++      struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
++      struct irq_chip *chip = irq_desc_get_chip(desc);
++      static const int int_reg[] = { 4, 5, 8, 9};
++
++      chained_irq_enter(chip, desc);
++
++      ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
++
++      chained_irq_exit(chip, desc);
++}
++
++int ipu_map_irq(struct ipu_soc *ipu, int irq)
++{
++      int virq;
++
++      virq = irq_linear_revmap(ipu->domain, irq);
++      if (!virq)
++              virq = irq_create_mapping(ipu->domain, irq);
++
++      return virq;
++}
++EXPORT_SYMBOL_GPL(ipu_map_irq);
++
++int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
++              enum ipu_channel_irq irq_type)
++{
++      return ipu_map_irq(ipu, irq_type + channel->num);
++}
++EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq);
++
++static void ipu_submodules_exit(struct ipu_soc *ipu)
++{
++      ipu_smfc_exit(ipu);
++      ipu_dp_exit(ipu);
++      ipu_dmfc_exit(ipu);
++      ipu_dc_exit(ipu);
++      ipu_di_exit(ipu, 1);
++      ipu_di_exit(ipu, 0);
++      ipu_image_convert_exit(ipu);
++      ipu_vdi_exit(ipu);
++      ipu_ic_exit(ipu);
++      ipu_csi_exit(ipu, 1);
++      ipu_csi_exit(ipu, 0);
++      ipu_cpmem_exit(ipu);
++}
++
++static int platform_remove_devices_fn(struct device *dev, void *unused)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++
++      platform_device_unregister(pdev);
++
++      return 0;
++}
++
++static void platform_device_unregister_children(struct platform_device *pdev)
++{
++      device_for_each_child(&pdev->dev, NULL, platform_remove_devices_fn);
++}
++
++struct ipu_platform_reg {
++      struct ipu_client_platformdata pdata;
++      const char *name;
++};
++
++/* These must be in the order of the corresponding device tree port nodes */
++static struct ipu_platform_reg client_reg[] = {
++      {
++              .pdata = {
++                      .csi = 0,
++                      .dma[0] = IPUV3_CHANNEL_CSI0,
++                      .dma[1] = -EINVAL,
++              },
++              .name = "imx-ipuv3-csi",
++      }, {
++              .pdata = {
++                      .csi = 1,
++                      .dma[0] = IPUV3_CHANNEL_CSI1,
++                      .dma[1] = -EINVAL,
++              },
++              .name = "imx-ipuv3-csi",
++      }, {
++              .pdata = {
++                      .di = 0,
++                      .dc = 5,
++                      .dp = IPU_DP_FLOW_SYNC_BG,
++                      .dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC,
++                      .dma[1] = IPUV3_CHANNEL_MEM_FG_SYNC,
++              },
++              .name = "imx-ipuv3-crtc",
++      }, {
++              .pdata = {
++                      .di = 1,
++                      .dc = 1,
++                      .dp = -EINVAL,
++                      .dma[0] = IPUV3_CHANNEL_MEM_DC_SYNC,
++                      .dma[1] = -EINVAL,
++              },
++              .name = "imx-ipuv3-crtc",
++      },
++};
++
++static DEFINE_MUTEX(ipu_client_id_mutex);
++static int ipu_client_id;
++
++static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
++{
++      struct device *dev = ipu->dev;
++      unsigned i;
++      int id, ret;
++
++      mutex_lock(&ipu_client_id_mutex);
++      id = ipu_client_id;
++      ipu_client_id += ARRAY_SIZE(client_reg);
++      mutex_unlock(&ipu_client_id_mutex);
++
++      for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
++              struct ipu_platform_reg *reg = &client_reg[i];
++              struct platform_device *pdev;
++              struct device_node *of_node;
++
++              /* Associate subdevice with the corresponding port node */
++              of_node = of_graph_get_port_by_id(dev->of_node, i);
++              if (!of_node) {
++                      dev_info(dev,
++                               "no port@%d node in %pOF, not using %s%d\n",
++                               i, dev->of_node,
++                               (i / 2) ? "DI" : "CSI", i % 2);
++                      continue;
++              }
++
++              pdev = platform_device_alloc(reg->name, id++);
++              if (!pdev) {
++                      ret = -ENOMEM;
++                      goto err_register;
++              }
++
++              pdev->dev.parent = dev;
++
++              reg->pdata.of_node = of_node;
++              ret = platform_device_add_data(pdev, &reg->pdata,
++                                             sizeof(reg->pdata));
++              if (!ret)
++                      ret = platform_device_add(pdev);
++              if (ret) {
++                      platform_device_put(pdev);
++                      goto err_register;
++              }
++      }
++
++      return 0;
++
++err_register:
++      platform_device_unregister_children(to_platform_device(dev));
++
++      return ret;
++}
++
++
++static int ipu_irq_init(struct ipu_soc *ipu)
++{
++      struct irq_chip_generic *gc;
++      struct irq_chip_type *ct;
++      unsigned long unused[IPU_NUM_IRQS / 32] = {
++              0x400100d0, 0xffe000fd,
++              0x400100d0, 0xffe000fd,
++              0x400100d0, 0xffe000fd,
++              0x4077ffff, 0xffe7e1fd,
++              0x23fffffe, 0x8880fff0,
++              0xf98fe7d0, 0xfff81fff,
++              0x400100d0, 0xffe000fd,
++              0x00000000,
++      };
++      int ret, i;
++
++      ipu->domain = irq_domain_add_linear(ipu->dev->of_node, IPU_NUM_IRQS,
++                                          &irq_generic_chip_ops, ipu);
++      if (!ipu->domain) {
++              dev_err(ipu->dev, "failed to add irq domain\n");
++              return -ENODEV;
++      }
++
++      ret = irq_alloc_domain_generic_chips(ipu->domain, 32, 1, "IPU",
++                                           handle_level_irq, 0, 0, 0);
++      if (ret < 0) {
++              dev_err(ipu->dev, "failed to alloc generic irq chips\n");
++              irq_domain_remove(ipu->domain);
++              return ret;
++      }
++
++      /* Mask and clear all interrupts */
++      for (i = 0; i < IPU_NUM_IRQS; i += 32) {
++              ipu_cm_write(ipu, 0, IPU_INT_CTRL(i / 32));
++              ipu_cm_write(ipu, ~unused[i / 32], IPU_INT_STAT(i / 32));
++      }
++
++      for (i = 0; i < IPU_NUM_IRQS; i += 32) {
++              gc = irq_get_domain_generic_chip(ipu->domain, i);
++              gc->reg_base = ipu->cm_reg;
++              gc->unused = unused[i / 32];
++              ct = gc->chip_types;
++              ct->chip.irq_ack = irq_gc_ack_set_bit;
++              ct->chip.irq_mask = irq_gc_mask_clr_bit;
++              ct->chip.irq_unmask = irq_gc_mask_set_bit;
++              ct->regs.ack = IPU_INT_STAT(i / 32);
++              ct->regs.mask = IPU_INT_CTRL(i / 32);
++      }
++
++      irq_set_chained_handler_and_data(ipu->irq_sync, ipu_irq_handler, ipu);
++      irq_set_chained_handler_and_data(ipu->irq_err, ipu_err_irq_handler,
++                                       ipu);
++
++      return 0;
++}
++
++static void ipu_irq_exit(struct ipu_soc *ipu)
++{
++      int i, irq;
++
++      irq_set_chained_handler_and_data(ipu->irq_err, NULL, NULL);
++      irq_set_chained_handler_and_data(ipu->irq_sync, NULL, NULL);
++
++      /* TODO: remove irq_domain_generic_chips */
++
++      for (i = 0; i < IPU_NUM_IRQS; i++) {
++              irq = irq_linear_revmap(ipu->domain, i);
++              if (irq)
++                      irq_dispose_mapping(irq);
++      }
++
++      irq_domain_remove(ipu->domain);
++}
++
++void ipu_dump(struct ipu_soc *ipu)
++{
++      int i;
++
++      dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n",
++              ipu_cm_read(ipu, IPU_CONF));
++      dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n",
++              ipu_idmac_read(ipu, IDMAC_CONF));
++      dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n",
++              ipu_idmac_read(ipu, IDMAC_CHA_EN(0)));
++      dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n",
++              ipu_idmac_read(ipu, IDMAC_CHA_EN(32)));
++      dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n",
++              ipu_idmac_read(ipu, IDMAC_CHA_PRI(0)));
++      dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n",
++              ipu_idmac_read(ipu, IDMAC_CHA_PRI(32)));
++      dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n",
++              ipu_idmac_read(ipu, IDMAC_BAND_EN(0)));
++      dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n",
++              ipu_idmac_read(ipu, IDMAC_BAND_EN(32)));
++      dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
++              ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0)));
++      dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
++              ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32)));
++      dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n",
++              ipu_cm_read(ipu, IPU_FS_PROC_FLOW1));
++      dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n",
++              ipu_cm_read(ipu, IPU_FS_PROC_FLOW2));
++      dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n",
++              ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
++      dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
++              ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
++      for (i = 0; i < 15; i++)
++              dev_dbg(ipu->dev, "IPU_INT_CTRL(%d) = \t%08X\n", i,
++                      ipu_cm_read(ipu, IPU_INT_CTRL(i)));
++}
++EXPORT_SYMBOL_GPL(ipu_dump);
++
++static int ipu_probe(struct platform_device *pdev)
++{
++      struct device_node *np = pdev->dev.of_node;
++      struct ipu_soc *ipu;
++      struct resource *res;
++      unsigned long ipu_base;
++      int ret, irq_sync, irq_err;
++      const struct ipu_devtype *devtype;
++
++      devtype = of_device_get_match_data(&pdev->dev);
++      if (!devtype)
++              return -EINVAL;
++
++      irq_sync = platform_get_irq(pdev, 0);
++      irq_err = platform_get_irq(pdev, 1);
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++
++      dev_dbg(&pdev->dev, "irq_sync: %d irq_err: %d\n",
++                      irq_sync, irq_err);
++
++      if (!res || irq_sync < 0 || irq_err < 0)
++              return -ENODEV;
++
++      ipu_base = res->start;
++
++      ipu = devm_kzalloc(&pdev->dev, sizeof(*ipu), GFP_KERNEL);
++      if (!ipu)
++              return -ENODEV;
++
++      ipu->id = of_alias_get_id(np, "ipu");
++      if (ipu->id < 0)
++              ipu->id = 0;
++
++      if (of_device_is_compatible(np, "fsl,imx6qp-ipu") &&
++          IS_ENABLED(CONFIG_DRM)) {
++              ipu->prg_priv = ipu_prg_lookup_by_phandle(&pdev->dev,
++                                                        "fsl,prg", ipu->id);
++              if (!ipu->prg_priv)
++                      return -EPROBE_DEFER;
++      }
++
++      ipu->devtype = devtype;
++      ipu->ipu_type = devtype->type;
++
++      spin_lock_init(&ipu->lock);
++      mutex_init(&ipu->channel_lock);
++      INIT_LIST_HEAD(&ipu->channels);
++
++      dev_dbg(&pdev->dev, "cm_reg:   0x%08lx\n",
++                      ipu_base + devtype->cm_ofs);
++      dev_dbg(&pdev->dev, "idmac:    0x%08lx\n",
++                      ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS);
++      dev_dbg(&pdev->dev, "cpmem:    0x%08lx\n",
++                      ipu_base + devtype->cpmem_ofs);
++      dev_dbg(&pdev->dev, "csi0:    0x%08lx\n",
++                      ipu_base + devtype->csi0_ofs);
++      dev_dbg(&pdev->dev, "csi1:    0x%08lx\n",
++                      ipu_base + devtype->csi1_ofs);
++      dev_dbg(&pdev->dev, "ic:      0x%08lx\n",
++                      ipu_base + devtype->ic_ofs);
++      dev_dbg(&pdev->dev, "disp0:    0x%08lx\n",
++                      ipu_base + devtype->disp0_ofs);
++      dev_dbg(&pdev->dev, "disp1:    0x%08lx\n",
++                      ipu_base + devtype->disp1_ofs);
++      dev_dbg(&pdev->dev, "srm:      0x%08lx\n",
++                      ipu_base + devtype->srm_ofs);
++      dev_dbg(&pdev->dev, "tpm:      0x%08lx\n",
++                      ipu_base + devtype->tpm_ofs);
++      dev_dbg(&pdev->dev, "dc:       0x%08lx\n",
++                      ipu_base + devtype->cm_ofs + IPU_CM_DC_REG_OFS);
++      dev_dbg(&pdev->dev, "ic:       0x%08lx\n",
++                      ipu_base + devtype->cm_ofs + IPU_CM_IC_REG_OFS);
++      dev_dbg(&pdev->dev, "dmfc:     0x%08lx\n",
++                      ipu_base + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS);
++      dev_dbg(&pdev->dev, "vdi:      0x%08lx\n",
++                      ipu_base + devtype->vdi_ofs);
++
++      ipu->cm_reg = devm_ioremap(&pdev->dev,
++                      ipu_base + devtype->cm_ofs, PAGE_SIZE);
++      ipu->idmac_reg = devm_ioremap(&pdev->dev,
++                      ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS,
++                      PAGE_SIZE);
++
++      if (!ipu->cm_reg || !ipu->idmac_reg)
++              return -ENOMEM;
++
++      ipu->clk = devm_clk_get(&pdev->dev, "bus");
++      if (IS_ERR(ipu->clk)) {
++              ret = PTR_ERR(ipu->clk);
++              dev_err(&pdev->dev, "clk_get failed with %d", ret);
++              return ret;
++      }
++
++      platform_set_drvdata(pdev, ipu);
++
++      ret = clk_prepare_enable(ipu->clk);
++      if (ret) {
++              dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
++              return ret;
++      }
++
++      ipu->dev = &pdev->dev;
++      ipu->irq_sync = irq_sync;
++      ipu->irq_err = irq_err;
++
++      ret = device_reset(&pdev->dev);
++      if (ret) {
++              dev_err(&pdev->dev, "failed to reset: %d\n", ret);
++              goto out_failed_reset;
++      }
++      ret = ipu_memory_reset(ipu);
++      if (ret)
++              goto out_failed_reset;
++
++      ret = ipu_irq_init(ipu);
++      if (ret)
++              goto out_failed_irq;
++
++      /* Set MCU_T to divide MCU access window into 2 */
++      ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
++                      IPU_DISP_GEN);
++
++      ret = ipu_submodules_init(ipu, pdev, ipu_base, ipu->clk);
++      if (ret)
++              goto failed_submodules_init;
++
++      ret = ipu_add_client_devices(ipu, ipu_base);
++      if (ret) {
++              dev_err(&pdev->dev, "adding client devices failed with %d\n",
++                              ret);
++              goto failed_add_clients;
++      }
++
++      dev_info(&pdev->dev, "%s probed\n", devtype->name);
++
++      return 0;
++
++failed_add_clients:
++      ipu_submodules_exit(ipu);
++failed_submodules_init:
++      ipu_irq_exit(ipu);
++out_failed_irq:
++out_failed_reset:
++      clk_disable_unprepare(ipu->clk);
++      return ret;
++}
++
++static int ipu_remove(struct platform_device *pdev)
++{
++      struct ipu_soc *ipu = platform_get_drvdata(pdev);
++
++      platform_device_unregister_children(pdev);
++      ipu_submodules_exit(ipu);
++      ipu_irq_exit(ipu);
++
++      clk_disable_unprepare(ipu->clk);
++
++      return 0;
++}
++
++static struct platform_driver imx_ipu_driver = {
++      .driver = {
++              .name = "imx-ipuv3",
++              .of_match_table = imx_ipu_dt_ids,
++      },
++      .probe = ipu_probe,
++      .remove = ipu_remove,
++};
++
++static struct platform_driver * const drivers[] = {
++#if IS_ENABLED(CONFIG_DRM)
++      &ipu_pre_drv,
++      &ipu_prg_drv,
++#endif
++      &imx_ipu_driver,
++};
++
++static int __init imx_ipu_init(void)
++{
++      return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
++}
++module_init(imx_ipu_init);
++
++static void __exit imx_ipu_exit(void)
++{
++      platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
++}
++module_exit(imx_ipu_exit);
++
++MODULE_ALIAS("platform:imx-ipuv3");
++MODULE_DESCRIPTION("i.MX IPU v3 driver");
++MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
+@@ -0,0 +1,976 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (C) 2012 Mentor Graphics Inc.
++ * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++#include <linux/types.h>
++#include <linux/bitrev.h>
++#include <linux/io.h>
++#include <linux/sizes.h>
++#include <drm/drm_fourcc.h>
++#include "ipu-prv.h"
++
++struct ipu_cpmem_word {
++      u32 data[5];
++      u32 res[3];
++};
++
++struct ipu_ch_param {
++      struct ipu_cpmem_word word[2];
++};
++
++struct ipu_cpmem {
++      struct ipu_ch_param __iomem *base;
++      u32 module;
++      spinlock_t lock;
++      int use_count;
++      struct ipu_soc *ipu;
++};
++
++#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
++
++#define IPU_FIELD_UBO         IPU_CPMEM_WORD(0, 46, 22)
++#define IPU_FIELD_VBO         IPU_CPMEM_WORD(0, 68, 22)
++#define IPU_FIELD_IOX         IPU_CPMEM_WORD(0, 90, 4)
++#define IPU_FIELD_RDRW                IPU_CPMEM_WORD(0, 94, 1)
++#define IPU_FIELD_SO          IPU_CPMEM_WORD(0, 113, 1)
++#define IPU_FIELD_SLY         IPU_CPMEM_WORD(1, 102, 14)
++#define IPU_FIELD_SLUV                IPU_CPMEM_WORD(1, 128, 14)
++
++#define IPU_FIELD_XV          IPU_CPMEM_WORD(0, 0, 10)
++#define IPU_FIELD_YV          IPU_CPMEM_WORD(0, 10, 9)
++#define IPU_FIELD_XB          IPU_CPMEM_WORD(0, 19, 13)
++#define IPU_FIELD_YB          IPU_CPMEM_WORD(0, 32, 12)
++#define IPU_FIELD_NSB_B               IPU_CPMEM_WORD(0, 44, 1)
++#define IPU_FIELD_CF          IPU_CPMEM_WORD(0, 45, 1)
++#define IPU_FIELD_SX          IPU_CPMEM_WORD(0, 46, 12)
++#define IPU_FIELD_SY          IPU_CPMEM_WORD(0, 58, 11)
++#define IPU_FIELD_NS          IPU_CPMEM_WORD(0, 69, 10)
++#define IPU_FIELD_SDX         IPU_CPMEM_WORD(0, 79, 7)
++#define IPU_FIELD_SM          IPU_CPMEM_WORD(0, 86, 10)
++#define IPU_FIELD_SCC         IPU_CPMEM_WORD(0, 96, 1)
++#define IPU_FIELD_SCE         IPU_CPMEM_WORD(0, 97, 1)
++#define IPU_FIELD_SDY         IPU_CPMEM_WORD(0, 98, 7)
++#define IPU_FIELD_SDRX                IPU_CPMEM_WORD(0, 105, 1)
++#define IPU_FIELD_SDRY                IPU_CPMEM_WORD(0, 106, 1)
++#define IPU_FIELD_BPP         IPU_CPMEM_WORD(0, 107, 3)
++#define IPU_FIELD_DEC_SEL     IPU_CPMEM_WORD(0, 110, 2)
++#define IPU_FIELD_DIM         IPU_CPMEM_WORD(0, 112, 1)
++#define IPU_FIELD_BNDM                IPU_CPMEM_WORD(0, 114, 3)
++#define IPU_FIELD_BM          IPU_CPMEM_WORD(0, 117, 2)
++#define IPU_FIELD_ROT         IPU_CPMEM_WORD(0, 119, 1)
++#define IPU_FIELD_ROT_HF_VF   IPU_CPMEM_WORD(0, 119, 3)
++#define IPU_FIELD_HF          IPU_CPMEM_WORD(0, 120, 1)
++#define IPU_FIELD_VF          IPU_CPMEM_WORD(0, 121, 1)
++#define IPU_FIELD_THE         IPU_CPMEM_WORD(0, 122, 1)
++#define IPU_FIELD_CAP         IPU_CPMEM_WORD(0, 123, 1)
++#define IPU_FIELD_CAE         IPU_CPMEM_WORD(0, 124, 1)
++#define IPU_FIELD_FW          IPU_CPMEM_WORD(0, 125, 13)
++#define IPU_FIELD_FH          IPU_CPMEM_WORD(0, 138, 12)
++#define IPU_FIELD_EBA0                IPU_CPMEM_WORD(1, 0, 29)
++#define IPU_FIELD_EBA1                IPU_CPMEM_WORD(1, 29, 29)
++#define IPU_FIELD_ILO         IPU_CPMEM_WORD(1, 58, 20)
++#define IPU_FIELD_NPB         IPU_CPMEM_WORD(1, 78, 7)
++#define IPU_FIELD_PFS         IPU_CPMEM_WORD(1, 85, 4)
++#define IPU_FIELD_ALU         IPU_CPMEM_WORD(1, 89, 1)
++#define IPU_FIELD_ALBM                IPU_CPMEM_WORD(1, 90, 3)
++#define IPU_FIELD_ID          IPU_CPMEM_WORD(1, 93, 2)
++#define IPU_FIELD_TH          IPU_CPMEM_WORD(1, 95, 7)
++#define IPU_FIELD_SL          IPU_CPMEM_WORD(1, 102, 14)
++#define IPU_FIELD_WID0                IPU_CPMEM_WORD(1, 116, 3)
++#define IPU_FIELD_WID1                IPU_CPMEM_WORD(1, 119, 3)
++#define IPU_FIELD_WID2                IPU_CPMEM_WORD(1, 122, 3)
++#define IPU_FIELD_WID3                IPU_CPMEM_WORD(1, 125, 3)
++#define IPU_FIELD_OFS0                IPU_CPMEM_WORD(1, 128, 5)
++#define IPU_FIELD_OFS1                IPU_CPMEM_WORD(1, 133, 5)
++#define IPU_FIELD_OFS2                IPU_CPMEM_WORD(1, 138, 5)
++#define IPU_FIELD_OFS3                IPU_CPMEM_WORD(1, 143, 5)
++#define IPU_FIELD_SXYS                IPU_CPMEM_WORD(1, 148, 1)
++#define IPU_FIELD_CRE         IPU_CPMEM_WORD(1, 149, 1)
++#define IPU_FIELD_DEC_SEL2    IPU_CPMEM_WORD(1, 150, 1)
++
++static inline struct ipu_ch_param __iomem *
++ipu_get_cpmem(struct ipuv3_channel *ch)
++{
++      struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv;
++
++      return cpmem->base + ch->num;
++}
++
++static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v)
++{
++      struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
++      u32 bit = (wbs >> 8) % 160;
++      u32 size = wbs & 0xff;
++      u32 word = (wbs >> 8) / 160;
++      u32 i = bit / 32;
++      u32 ofs = bit % 32;
++      u32 mask = (1 << size) - 1;
++      u32 val;
++
++      pr_debug("%s %d %d %d\n", __func__, word, bit , size);
++
++      val = readl(&base->word[word].data[i]);
++      val &= ~(mask << ofs);
++      val |= v << ofs;
++      writel(val, &base->word[word].data[i]);
++
++      if ((bit + size - 1) / 32 > i) {
++              val = readl(&base->word[word].data[i + 1]);
++              val &= ~(mask >> (ofs ? (32 - ofs) : 0));
++              val |= v >> (ofs ? (32 - ofs) : 0);
++              writel(val, &base->word[word].data[i + 1]);
++      }
++}
++
++static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs)
++{
++      struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
++      u32 bit = (wbs >> 8) % 160;
++      u32 size = wbs & 0xff;
++      u32 word = (wbs >> 8) / 160;
++      u32 i = bit / 32;
++      u32 ofs = bit % 32;
++      u32 mask = (1 << size) - 1;
++      u32 val = 0;
++
++      pr_debug("%s %d %d %d\n", __func__, word, bit , size);
++
++      val = (readl(&base->word[word].data[i]) >> ofs) & mask;
++
++      if ((bit + size - 1) / 32 > i) {
++              u32 tmp;
++
++              tmp = readl(&base->word[word].data[i + 1]);
++              tmp &= mask >> (ofs ? (32 - ofs) : 0);
++              val |= tmp << (ofs ? (32 - ofs) : 0);
++      }
++
++      return val;
++}
++
++/*
++ * The V4L2 spec defines packed RGB formats in memory byte order, which from
++ * point of view of the IPU corresponds to little-endian words with the first
++ * component in the least significant bits.
++ * The DRM pixel formats and IPU internal representation are ordered the other
++ * way around, with the first named component ordered at the most significant
++ * bits. Further, V4L2 formats are not well defined:
++ *     https://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
++ * We choose the interpretation which matches GStreamer behavior.
++ */
++static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
++{
++      switch (pixelformat) {
++      case V4L2_PIX_FMT_RGB565:
++              /*
++               * Here we choose the 'corrected' interpretation of RGBP, a
++               * little-endian 16-bit word with the red component at the most
++               * significant bits:
++               * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
++               */
++              return DRM_FORMAT_RGB565;
++      case V4L2_PIX_FMT_BGR24:
++              /* B G R <=> [24:0] R:G:B */
++              return DRM_FORMAT_RGB888;
++      case V4L2_PIX_FMT_RGB24:
++              /* R G B <=> [24:0] B:G:R */
++              return DRM_FORMAT_BGR888;
++      case V4L2_PIX_FMT_BGR32:
++              /* B G R A <=> [32:0] A:B:G:R */
++              return DRM_FORMAT_XRGB8888;
++      case V4L2_PIX_FMT_RGB32:
++              /* R G B A <=> [32:0] A:B:G:R */
++              return DRM_FORMAT_XBGR8888;
++      case V4L2_PIX_FMT_ABGR32:
++              /* B G R A <=> [32:0] A:R:G:B */
++              return DRM_FORMAT_ARGB8888;
++      case V4L2_PIX_FMT_XBGR32:
++              /* B G R X <=> [32:0] X:R:G:B */
++              return DRM_FORMAT_XRGB8888;
++      case V4L2_PIX_FMT_BGRA32:
++              /* A B G R <=> [32:0] R:G:B:A */
++              return DRM_FORMAT_RGBA8888;
++      case V4L2_PIX_FMT_BGRX32:
++              /* X B G R <=> [32:0] R:G:B:X */
++              return DRM_FORMAT_RGBX8888;
++      case V4L2_PIX_FMT_RGBA32:
++              /* R G B A <=> [32:0] A:B:G:R */
++              return DRM_FORMAT_ABGR8888;
++      case V4L2_PIX_FMT_RGBX32:
++              /* R G B X <=> [32:0] X:B:G:R */
++              return DRM_FORMAT_XBGR8888;
++      case V4L2_PIX_FMT_ARGB32:
++              /* A R G B <=> [32:0] B:G:R:A */
++              return DRM_FORMAT_BGRA8888;
++      case V4L2_PIX_FMT_XRGB32:
++              /* X R G B <=> [32:0] B:G:R:X */
++              return DRM_FORMAT_BGRX8888;
++      case V4L2_PIX_FMT_UYVY:
++              return DRM_FORMAT_UYVY;
++      case V4L2_PIX_FMT_YUYV:
++              return DRM_FORMAT_YUYV;
++      case V4L2_PIX_FMT_YUV420:
++              return DRM_FORMAT_YUV420;
++      case V4L2_PIX_FMT_YUV422P:
++              return DRM_FORMAT_YUV422;
++      case V4L2_PIX_FMT_YVU420:
++              return DRM_FORMAT_YVU420;
++      case V4L2_PIX_FMT_NV12:
++              return DRM_FORMAT_NV12;
++      case V4L2_PIX_FMT_NV16:
++              return DRM_FORMAT_NV16;
++      }
++
++      return -EINVAL;
++}
++
++void ipu_cpmem_zero(struct ipuv3_channel *ch)
++{
++      struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
++      void __iomem *base = p;
++      int i;
++
++      for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
++              writel(0, base + i * sizeof(u32));
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
++
++void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres)
++{
++      ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1);
++      ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
++
++void ipu_cpmem_skip_odd_chroma_rows(struct ipuv3_channel *ch)
++{
++      ipu_ch_param_write_field(ch, IPU_FIELD_RDRW, 1);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_skip_odd_chroma_rows);
++
++void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
++{
++      ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
++
++void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch)
++{
++      struct ipu_soc *ipu = ch->ipu;
++      u32 val;
++
++      if (ipu->ipu_type == IPUV3EX)
++              ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1);
++
++      val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num));
++      val |= 1 << (ch->num % 32);
++      ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num));
++};
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
++
++void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
++{
++      WARN_ON_ONCE(buf & 0x7);
++
++      if (bufnum)
++              ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
++      else
++              ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
++
++void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
++{
++      WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7));
++
++      ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
++      ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
++
++void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
++                             u32 pixelformat)
++{
++      u32 ilo, sly, sluv;
++
++      if (stride < 0) {
++              stride = -stride;
++              ilo = 0x100000 - (stride / 8);
++      } else {
++              ilo = stride / 8;
++      }
++
++      sly = (stride * 2) - 1;
++
++      switch (pixelformat) {
++      case V4L2_PIX_FMT_YUV420:
++      case V4L2_PIX_FMT_YVU420:
++              sluv = stride / 2 - 1;
++              break;
++      case V4L2_PIX_FMT_NV12:
++              sluv = stride - 1;
++              break;
++      case V4L2_PIX_FMT_YUV422P:
++              sluv = stride - 1;
++              break;
++      case V4L2_PIX_FMT_NV16:
++              sluv = stride * 2 - 1;
++              break;
++      default:
++              sluv = 0;
++              break;
++      }
++
++      ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
++      ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
++      ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
++      if (sluv)
++              ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
++};
++EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
++
++void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
++{
++      id &= 0x3;
++      ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
++
++int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
++{
++      return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
++
++void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
++{
++      ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
++};
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
++
++void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
++{
++      ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
++
++void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
++                          enum ipu_rotate_mode rot)
++{
++      u32 temp_rot = bitrev8(rot) >> 5;
++
++      ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
++
++int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
++                           const struct ipu_rgb *rgb)
++{
++      int bpp = 0, npb = 0, ro, go, bo, to;
++
++      ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
++      go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
++      bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
++      to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
++
++      ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1);
++      ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro);
++      ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1);
++      ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go);
++      ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1);
++      ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo);
++
++      if (rgb->transp.length) {
++              ipu_ch_param_write_field(ch, IPU_FIELD_WID3,
++                              rgb->transp.length - 1);
++              ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to);
++      } else {
++              ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
++              ipu_ch_param_write_field(ch, IPU_FIELD_OFS3,
++                              rgb->bits_per_pixel);
++      }
++
++      switch (rgb->bits_per_pixel) {
++      case 32:
++              bpp = 0;
++              npb = 15;
++              break;
++      case 24:
++              bpp = 1;
++              npb = 19;
++              break;
++      case 16:
++              bpp = 3;
++              npb = 31;
++              break;
++      case 8:
++              bpp = 5;
++              npb = 63;
++              break;
++      default:
++              return -EINVAL;
++      }
++      ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
++      ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
++      ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
++
++int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width)
++{
++      int bpp = 0, npb = 0;
++
++      switch (width) {
++      case 32:
++              bpp = 0;
++              npb = 15;
++              break;
++      case 24:
++              bpp = 1;
++              npb = 19;
++              break;
++      case 16:
++              bpp = 3;
++              npb = 31;
++              break;
++      case 8:
++              bpp = 5;
++              npb = 63;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
++      ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
++      ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
++
++void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format)
++{
++      switch (pixel_format) {
++      case V4L2_PIX_FMT_UYVY:
++              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
++              break;
++      case V4L2_PIX_FMT_YUYV:
++              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
++              break;
++      }
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
++
++void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
++                                 unsigned int uv_stride,
++                                 unsigned int u_offset, unsigned int v_offset)
++{
++      WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7));
++
++      ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1);
++      ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
++      ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
++
++static const struct ipu_rgb def_xrgb_32 = {
++      .red    = { .offset = 16, .length = 8, },
++      .green  = { .offset =  8, .length = 8, },
++      .blue   = { .offset =  0, .length = 8, },
++      .transp = { .offset = 24, .length = 8, },
++      .bits_per_pixel = 32,
++};
++
++static const struct ipu_rgb def_xbgr_32 = {
++      .red    = { .offset =  0, .length = 8, },
++      .green  = { .offset =  8, .length = 8, },
++      .blue   = { .offset = 16, .length = 8, },
++      .transp = { .offset = 24, .length = 8, },
++      .bits_per_pixel = 32,
++};
++
++static const struct ipu_rgb def_rgbx_32 = {
++      .red    = { .offset = 24, .length = 8, },
++      .green  = { .offset = 16, .length = 8, },
++      .blue   = { .offset =  8, .length = 8, },
++      .transp = { .offset =  0, .length = 8, },
++      .bits_per_pixel = 32,
++};
++
++static const struct ipu_rgb def_bgrx_32 = {
++      .red    = { .offset =  8, .length = 8, },
++      .green  = { .offset = 16, .length = 8, },
++      .blue   = { .offset = 24, .length = 8, },
++      .transp = { .offset =  0, .length = 8, },
++      .bits_per_pixel = 32,
++};
++
++static const struct ipu_rgb def_rgb_24 = {
++      .red    = { .offset = 16, .length = 8, },
++      .green  = { .offset =  8, .length = 8, },
++      .blue   = { .offset =  0, .length = 8, },
++      .transp = { .offset =  0, .length = 0, },
++      .bits_per_pixel = 24,
++};
++
++static const struct ipu_rgb def_bgr_24 = {
++      .red    = { .offset =  0, .length = 8, },
++      .green  = { .offset =  8, .length = 8, },
++      .blue   = { .offset = 16, .length = 8, },
++      .transp = { .offset =  0, .length = 0, },
++      .bits_per_pixel = 24,
++};
++
++static const struct ipu_rgb def_rgb_16 = {
++      .red    = { .offset = 11, .length = 5, },
++      .green  = { .offset =  5, .length = 6, },
++      .blue   = { .offset =  0, .length = 5, },
++      .transp = { .offset =  0, .length = 0, },
++      .bits_per_pixel = 16,
++};
++
++static const struct ipu_rgb def_bgr_16 = {
++      .red    = { .offset =  0, .length = 5, },
++      .green  = { .offset =  5, .length = 6, },
++      .blue   = { .offset = 11, .length = 5, },
++      .transp = { .offset =  0, .length = 0, },
++      .bits_per_pixel = 16,
++};
++
++static const struct ipu_rgb def_argb_16 = {
++      .red    = { .offset = 10, .length = 5, },
++      .green  = { .offset =  5, .length = 5, },
++      .blue   = { .offset =  0, .length = 5, },
++      .transp = { .offset = 15, .length = 1, },
++      .bits_per_pixel = 16,
++};
++
++static const struct ipu_rgb def_argb_16_4444 = {
++      .red    = { .offset =  8, .length = 4, },
++      .green  = { .offset =  4, .length = 4, },
++      .blue   = { .offset =  0, .length = 4, },
++      .transp = { .offset = 12, .length = 4, },
++      .bits_per_pixel = 16,
++};
++
++static const struct ipu_rgb def_abgr_16 = {
++      .red    = { .offset =  0, .length = 5, },
++      .green  = { .offset =  5, .length = 5, },
++      .blue   = { .offset = 10, .length = 5, },
++      .transp = { .offset = 15, .length = 1, },
++      .bits_per_pixel = 16,
++};
++
++static const struct ipu_rgb def_rgba_16 = {
++      .red    = { .offset = 11, .length = 5, },
++      .green  = { .offset =  6, .length = 5, },
++      .blue   = { .offset =  1, .length = 5, },
++      .transp = { .offset =  0, .length = 1, },
++      .bits_per_pixel = 16,
++};
++
++static const struct ipu_rgb def_bgra_16 = {
++      .red    = { .offset =  1, .length = 5, },
++      .green  = { .offset =  6, .length = 5, },
++      .blue   = { .offset = 11, .length = 5, },
++      .transp = { .offset =  0, .length = 1, },
++      .bits_per_pixel = 16,
++};
++
++#define Y_OFFSET(pix, x, y)   ((x) + pix->width * (y))
++#define U_OFFSET(pix, x, y)   ((pix->width * pix->height) +           \
++                               (pix->width * ((y) / 2) / 2) + (x) / 2)
++#define V_OFFSET(pix, x, y)   ((pix->width * pix->height) +           \
++                               (pix->width * pix->height / 4) +       \
++                               (pix->width * ((y) / 2) / 2) + (x) / 2)
++#define U2_OFFSET(pix, x, y)  ((pix->width * pix->height) +           \
++                               (pix->width * (y) / 2) + (x) / 2)
++#define V2_OFFSET(pix, x, y)  ((pix->width * pix->height) +           \
++                               (pix->width * pix->height / 2) +       \
++                               (pix->width * (y) / 2) + (x) / 2)
++#define UV_OFFSET(pix, x, y)  ((pix->width * pix->height) +   \
++                               (pix->width * ((y) / 2)) + (x))
++#define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) +   \
++                               (pix->width * y) + (x))
++
++#define NUM_ALPHA_CHANNELS    7
++
++/* See Table 37-12. Alpha channels mapping. */
++static int ipu_channel_albm(int ch_num)
++{
++      switch (ch_num) {
++      case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:     return 0;
++      case IPUV3_CHANNEL_G_MEM_IC_PP:         return 1;
++      case IPUV3_CHANNEL_MEM_FG_SYNC:         return 2;
++      case IPUV3_CHANNEL_MEM_FG_ASYNC:        return 3;
++      case IPUV3_CHANNEL_MEM_BG_SYNC:         return 4;
++      case IPUV3_CHANNEL_MEM_BG_ASYNC:        return 5;
++      case IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB: return 6;
++      default:
++              return -EINVAL;
++      }
++}
++
++static void ipu_cpmem_set_separate_alpha(struct ipuv3_channel *ch)
++{
++      struct ipu_soc *ipu = ch->ipu;
++      int albm;
++      u32 val;
++
++      albm = ipu_channel_albm(ch->num);
++      if (albm < 0)
++              return;
++
++      ipu_ch_param_write_field(ch, IPU_FIELD_ALU, 1);
++      ipu_ch_param_write_field(ch, IPU_FIELD_ALBM, albm);
++      ipu_ch_param_write_field(ch, IPU_FIELD_CRE, 1);
++
++      val = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
++      val |= BIT(ch->num);
++      ipu_idmac_write(ipu, val, IDMAC_SEP_ALPHA);
++}
++
++int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
++{
++      switch (drm_fourcc) {
++      case DRM_FORMAT_YUV420:
++      case DRM_FORMAT_YVU420:
++              /* pix format */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
++              /* burst size */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
++              break;
++      case DRM_FORMAT_YUV422:
++      case DRM_FORMAT_YVU422:
++              /* pix format */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
++              /* burst size */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
++              break;
++      case DRM_FORMAT_YUV444:
++      case DRM_FORMAT_YVU444:
++              /* pix format */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0);
++              /* burst size */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
++              break;
++      case DRM_FORMAT_NV12:
++              /* pix format */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
++              /* burst size */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
++              break;
++      case DRM_FORMAT_NV16:
++              /* pix format */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
++              /* burst size */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
++              break;
++      case DRM_FORMAT_UYVY:
++              /* bits/pixel */
++              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
++              /* pix format */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
++              /* burst size */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
++              break;
++      case DRM_FORMAT_YUYV:
++              /* bits/pixel */
++              ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
++              /* pix format */
++              ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
++              /* burst size */
++              ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
++              break;
++      case DRM_FORMAT_ABGR8888:
++      case DRM_FORMAT_XBGR8888:
++              ipu_cpmem_set_format_rgb(ch, &def_xbgr_32);
++              break;
++      case DRM_FORMAT_ARGB8888:
++      case DRM_FORMAT_XRGB8888:
++              ipu_cpmem_set_format_rgb(ch, &def_xrgb_32);
++              break;
++      case DRM_FORMAT_RGBA8888:
++      case DRM_FORMAT_RGBX8888:
++      case DRM_FORMAT_RGBX8888_A8:
++              ipu_cpmem_set_format_rgb(ch, &def_rgbx_32);
++              break;
++      case DRM_FORMAT_BGRA8888:
++      case DRM_FORMAT_BGRX8888:
++      case DRM_FORMAT_BGRX8888_A8:
++              ipu_cpmem_set_format_rgb(ch, &def_bgrx_32);
++              break;
++      case DRM_FORMAT_BGR888:
++      case DRM_FORMAT_BGR888_A8:
++              ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
++              break;
++      case DRM_FORMAT_RGB888:
++      case DRM_FORMAT_RGB888_A8:
++              ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
++              break;
++      case DRM_FORMAT_RGB565:
++      case DRM_FORMAT_RGB565_A8:
++              ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
++              break;
++      case DRM_FORMAT_BGR565:
++      case DRM_FORMAT_BGR565_A8:
++              ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
++              break;
++      case DRM_FORMAT_ARGB1555:
++              ipu_cpmem_set_format_rgb(ch, &def_argb_16);
++              break;
++      case DRM_FORMAT_ABGR1555:
++              ipu_cpmem_set_format_rgb(ch, &def_abgr_16);
++              break;
++      case DRM_FORMAT_RGBA5551:
++              ipu_cpmem_set_format_rgb(ch, &def_rgba_16);
++              break;
++      case DRM_FORMAT_BGRA5551:
++              ipu_cpmem_set_format_rgb(ch, &def_bgra_16);
++              break;
++      case DRM_FORMAT_ARGB4444:
++              ipu_cpmem_set_format_rgb(ch, &def_argb_16_4444);
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      switch (drm_fourcc) {
++      case DRM_FORMAT_RGB565_A8:
++      case DRM_FORMAT_BGR565_A8:
++      case DRM_FORMAT_RGB888_A8:
++      case DRM_FORMAT_BGR888_A8:
++      case DRM_FORMAT_RGBX8888_A8:
++      case DRM_FORMAT_BGRX8888_A8:
++              ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
++              ipu_cpmem_set_separate_alpha(ch);
++              break;
++      default:
++              break;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
++
++int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
++{
++      struct v4l2_pix_format *pix = &image->pix;
++      int offset, u_offset, v_offset;
++      int ret = 0;
++
++      pr_debug("%s: resolution: %dx%d stride: %d\n",
++               __func__, pix->width, pix->height,
++               pix->bytesperline);
++
++      ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
++      ipu_cpmem_set_stride(ch, pix->bytesperline);
++
++      ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
++
++      switch (pix->pixelformat) {
++      case V4L2_PIX_FMT_YUV420:
++              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
++              u_offset = image->u_offset ?
++                      image->u_offset : U_OFFSET(pix, image->rect.left,
++                                                 image->rect.top) - offset;
++              v_offset = image->v_offset ?
++                      image->v_offset : V_OFFSET(pix, image->rect.left,
++                                                 image->rect.top) - offset;
++
++              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
++                                            u_offset, v_offset);
++              break;
++      case V4L2_PIX_FMT_YVU420:
++              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
++              u_offset = image->u_offset ?
++                      image->u_offset : V_OFFSET(pix, image->rect.left,
++                                                 image->rect.top) - offset;
++              v_offset = image->v_offset ?
++                      image->v_offset : U_OFFSET(pix, image->rect.left,
++                                                 image->rect.top) - offset;
++
++              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
++                                            u_offset, v_offset);
++              break;
++      case V4L2_PIX_FMT_YUV422P:
++              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
++              u_offset = image->u_offset ?
++                      image->u_offset : U2_OFFSET(pix, image->rect.left,
++                                                  image->rect.top) - offset;
++              v_offset = image->v_offset ?
++                      image->v_offset : V2_OFFSET(pix, image->rect.left,
++                                                  image->rect.top) - offset;
++
++              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
++                                            u_offset, v_offset);
++              break;
++      case V4L2_PIX_FMT_NV12:
++              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
++              u_offset = image->u_offset ?
++                      image->u_offset : UV_OFFSET(pix, image->rect.left,
++                                                  image->rect.top) - offset;
++              v_offset = image->v_offset ? image->v_offset : 0;
++
++              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
++                                            u_offset, v_offset);
++              break;
++      case V4L2_PIX_FMT_NV16:
++              offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
++              u_offset = image->u_offset ?
++                      image->u_offset : UV2_OFFSET(pix, image->rect.left,
++                                                   image->rect.top) - offset;
++              v_offset = image->v_offset ? image->v_offset : 0;
++
++              ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
++                                            u_offset, v_offset);
++              break;
++      case V4L2_PIX_FMT_UYVY:
++      case V4L2_PIX_FMT_YUYV:
++      case V4L2_PIX_FMT_RGB565:
++              offset = image->rect.left * 2 +
++                      image->rect.top * pix->bytesperline;
++              break;
++      case V4L2_PIX_FMT_RGB32:
++      case V4L2_PIX_FMT_BGR32:
++      case V4L2_PIX_FMT_ABGR32:
++      case V4L2_PIX_FMT_XBGR32:
++      case V4L2_PIX_FMT_BGRA32:
++      case V4L2_PIX_FMT_BGRX32:
++      case V4L2_PIX_FMT_RGBA32:
++      case V4L2_PIX_FMT_RGBX32:
++      case V4L2_PIX_FMT_ARGB32:
++      case V4L2_PIX_FMT_XRGB32:
++              offset = image->rect.left * 4 +
++                      image->rect.top * pix->bytesperline;
++              break;
++      case V4L2_PIX_FMT_RGB24:
++      case V4L2_PIX_FMT_BGR24:
++              offset = image->rect.left * 3 +
++                      image->rect.top * pix->bytesperline;
++              break;
++      case V4L2_PIX_FMT_SBGGR8:
++      case V4L2_PIX_FMT_SGBRG8:
++      case V4L2_PIX_FMT_SGRBG8:
++      case V4L2_PIX_FMT_SRGGB8:
++      case V4L2_PIX_FMT_GREY:
++              offset = image->rect.left + image->rect.top * pix->bytesperline;
++              break;
++      case V4L2_PIX_FMT_SBGGR16:
++      case V4L2_PIX_FMT_SGBRG16:
++      case V4L2_PIX_FMT_SGRBG16:
++      case V4L2_PIX_FMT_SRGGB16:
++      case V4L2_PIX_FMT_Y16:
++              offset = image->rect.left * 2 +
++                       image->rect.top * pix->bytesperline;
++              break;
++      default:
++              /* This should not happen */
++              WARN_ON(1);
++              offset = 0;
++              ret = -EINVAL;
++      }
++
++      ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
++      ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
++
++void ipu_cpmem_dump(struct ipuv3_channel *ch)
++{
++      struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
++      struct ipu_soc *ipu = ch->ipu;
++      int chno = ch->num;
++
++      dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
++              readl(&p->word[0].data[0]),
++              readl(&p->word[0].data[1]),
++              readl(&p->word[0].data[2]),
++              readl(&p->word[0].data[3]),
++              readl(&p->word[0].data[4]));
++      dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
++              readl(&p->word[1].data[0]),
++              readl(&p->word[1].data[1]),
++              readl(&p->word[1].data[2]),
++              readl(&p->word[1].data[3]),
++              readl(&p->word[1].data[4]));
++      dev_dbg(ipu->dev, "PFS 0x%x, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
++      dev_dbg(ipu->dev, "BPP 0x%x, ",
++              ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
++      dev_dbg(ipu->dev, "NPB 0x%x\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
++
++      dev_dbg(ipu->dev, "FW %d, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_FW));
++      dev_dbg(ipu->dev, "FH %d, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_FH));
++      dev_dbg(ipu->dev, "EBA0 0x%x\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
++      dev_dbg(ipu->dev, "EBA1 0x%x\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
++      dev_dbg(ipu->dev, "Stride %d\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_SL));
++      dev_dbg(ipu->dev, "scan_order %d\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_SO));
++      dev_dbg(ipu->dev, "uv_stride %d\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
++      dev_dbg(ipu->dev, "u_offset 0x%x\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
++      dev_dbg(ipu->dev, "v_offset 0x%x\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
++
++      dev_dbg(ipu->dev, "Width0 %d+1, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
++      dev_dbg(ipu->dev, "Width1 %d+1, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
++      dev_dbg(ipu->dev, "Width2 %d+1, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
++      dev_dbg(ipu->dev, "Width3 %d+1, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
++      dev_dbg(ipu->dev, "Offset0 %d, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
++      dev_dbg(ipu->dev, "Offset1 %d, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
++      dev_dbg(ipu->dev, "Offset2 %d, ",
++               ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
++      dev_dbg(ipu->dev, "Offset3 %d\n",
++               ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
++}
++EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
++
++int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
++{
++      struct ipu_cpmem *cpmem;
++
++      cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
++      if (!cpmem)
++              return -ENOMEM;
++
++      ipu->cpmem_priv = cpmem;
++
++      spin_lock_init(&cpmem->lock);
++      cpmem->base = devm_ioremap(dev, base, SZ_128K);
++      if (!cpmem->base)
++              return -ENOMEM;
++
++      dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
++              base, cpmem->base);
++      cpmem->ipu = ipu;
++
++      return 0;
++}
++
++void ipu_cpmem_exit(struct ipu_soc *ipu)
++{
++}
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/ipu-csi.c
+@@ -0,0 +1,821 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (C) 2012-2014 Mentor Graphics Inc.
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++#include <linux/export.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/videodev2.h>
++#include <uapi/linux/v4l2-mediabus.h>
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++#include <linux/clkdev.h>
++
++#include "ipu-prv.h"
++
++struct ipu_csi {
++      void __iomem *base;
++      int id;
++      u32 module;
++      struct clk *clk_ipu;    /* IPU bus clock */
++      spinlock_t lock;
++      bool inuse;
++      struct ipu_soc *ipu;
++};
++
++/* CSI Register Offsets */
++#define CSI_SENS_CONF         0x0000
++#define CSI_SENS_FRM_SIZE     0x0004
++#define CSI_ACT_FRM_SIZE      0x0008
++#define CSI_OUT_FRM_CTRL      0x000c
++#define CSI_TST_CTRL          0x0010
++#define CSI_CCIR_CODE_1               0x0014
++#define CSI_CCIR_CODE_2               0x0018
++#define CSI_CCIR_CODE_3               0x001c
++#define CSI_MIPI_DI           0x0020
++#define CSI_SKIP              0x0024
++#define CSI_CPD_CTRL          0x0028
++#define CSI_CPD_RC(n)         (0x002c + ((n)*4))
++#define CSI_CPD_RS(n)         (0x004c + ((n)*4))
++#define CSI_CPD_GRC(n)                (0x005c + ((n)*4))
++#define CSI_CPD_GRS(n)                (0x007c + ((n)*4))
++#define CSI_CPD_GBC(n)                (0x008c + ((n)*4))
++#define CSI_CPD_GBS(n)                (0x00Ac + ((n)*4))
++#define CSI_CPD_BC(n)         (0x00Bc + ((n)*4))
++#define CSI_CPD_BS(n)         (0x00Dc + ((n)*4))
++#define CSI_CPD_OFFSET1               0x00ec
++#define CSI_CPD_OFFSET2               0x00f0
++
++/* CSI Register Fields */
++#define CSI_SENS_CONF_DATA_FMT_SHIFT          8
++#define CSI_SENS_CONF_DATA_FMT_MASK           0x00000700
++#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444     0L
++#define CSI_SENS_CONF_DATA_FMT_YUV422_YUYV    1L
++#define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY    2L
++#define CSI_SENS_CONF_DATA_FMT_BAYER          3L
++#define CSI_SENS_CONF_DATA_FMT_RGB565         4L
++#define CSI_SENS_CONF_DATA_FMT_RGB555         5L
++#define CSI_SENS_CONF_DATA_FMT_RGB444         6L
++#define CSI_SENS_CONF_DATA_FMT_JPEG           7L
++
++#define CSI_SENS_CONF_VSYNC_POL_SHIFT         0
++#define CSI_SENS_CONF_HSYNC_POL_SHIFT         1
++#define CSI_SENS_CONF_DATA_POL_SHIFT          2
++#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT               3
++#define CSI_SENS_CONF_SENS_PRTCL_MASK         0x00000070
++#define CSI_SENS_CONF_SENS_PRTCL_SHIFT                4
++#define CSI_SENS_CONF_PACK_TIGHT_SHIFT                7
++#define CSI_SENS_CONF_DATA_WIDTH_SHIFT                11
++#define CSI_SENS_CONF_EXT_VSYNC_SHIFT         15
++#define CSI_SENS_CONF_DIVRATIO_SHIFT          16
++
++#define CSI_SENS_CONF_DIVRATIO_MASK           0x00ff0000
++#define CSI_SENS_CONF_DATA_DEST_SHIFT         24
++#define CSI_SENS_CONF_DATA_DEST_MASK          0x07000000
++#define CSI_SENS_CONF_JPEG8_EN_SHIFT          27
++#define CSI_SENS_CONF_JPEG_EN_SHIFT           28
++#define CSI_SENS_CONF_FORCE_EOF_SHIFT         29
++#define CSI_SENS_CONF_DATA_EN_POL_SHIFT               31
++
++#define CSI_DATA_DEST_IC                      2
++#define CSI_DATA_DEST_IDMAC                   4
++
++#define CSI_CCIR_ERR_DET_EN                   0x01000000
++#define CSI_HORI_DOWNSIZE_EN                  0x80000000
++#define CSI_VERT_DOWNSIZE_EN                  0x40000000
++#define CSI_TEST_GEN_MODE_EN                  0x01000000
++
++#define CSI_HSC_MASK                          0x1fff0000
++#define CSI_HSC_SHIFT                         16
++#define CSI_VSC_MASK                          0x00000fff
++#define CSI_VSC_SHIFT                         0
++
++#define CSI_TEST_GEN_R_MASK                   0x000000ff
++#define CSI_TEST_GEN_R_SHIFT                  0
++#define CSI_TEST_GEN_G_MASK                   0x0000ff00
++#define CSI_TEST_GEN_G_SHIFT                  8
++#define CSI_TEST_GEN_B_MASK                   0x00ff0000
++#define CSI_TEST_GEN_B_SHIFT                  16
++
++#define CSI_MAX_RATIO_SKIP_SMFC_MASK          0x00000007
++#define CSI_MAX_RATIO_SKIP_SMFC_SHIFT         0
++#define CSI_SKIP_SMFC_MASK                    0x000000f8
++#define CSI_SKIP_SMFC_SHIFT                   3
++#define CSI_ID_2_SKIP_MASK                    0x00000300
++#define CSI_ID_2_SKIP_SHIFT                   8
++
++#define CSI_COLOR_FIRST_ROW_MASK              0x00000002
++#define CSI_COLOR_FIRST_COMP_MASK             0x00000001
++
++/* MIPI CSI-2 data types */
++#define MIPI_DT_YUV420                0x18 /* YYY.../UYVY.... */
++#define MIPI_DT_YUV420_LEGACY 0x1a /* UYY.../VYY...   */
++#define MIPI_DT_YUV422                0x1e /* UYVY...         */
++#define MIPI_DT_RGB444                0x20
++#define MIPI_DT_RGB555                0x21
++#define MIPI_DT_RGB565                0x22
++#define MIPI_DT_RGB666                0x23
++#define MIPI_DT_RGB888                0x24
++#define MIPI_DT_RAW6          0x28
++#define MIPI_DT_RAW7          0x29
++#define MIPI_DT_RAW8          0x2a
++#define MIPI_DT_RAW10         0x2b
++#define MIPI_DT_RAW12         0x2c
++#define MIPI_DT_RAW14         0x2d
++
++/*
++ * Bitfield of CSI bus signal polarities and modes.
++ */
++struct ipu_csi_bus_config {
++      unsigned data_width:4;
++      unsigned clk_mode:3;
++      unsigned ext_vsync:1;
++      unsigned vsync_pol:1;
++      unsigned hsync_pol:1;
++      unsigned pixclk_pol:1;
++      unsigned data_pol:1;
++      unsigned sens_clksrc:1;
++      unsigned pack_tight:1;
++      unsigned force_eof:1;
++      unsigned data_en_pol:1;
++
++      unsigned data_fmt;
++      unsigned mipi_dt;
++};
++
++/*
++ * Enumeration of CSI data bus widths.
++ */
++enum ipu_csi_data_width {
++      IPU_CSI_DATA_WIDTH_4   = 0,
++      IPU_CSI_DATA_WIDTH_8   = 1,
++      IPU_CSI_DATA_WIDTH_10  = 3,
++      IPU_CSI_DATA_WIDTH_12  = 5,
++      IPU_CSI_DATA_WIDTH_16  = 9,
++};
++
++/*
++ * Enumeration of CSI clock modes.
++ */
++enum ipu_csi_clk_mode {
++      IPU_CSI_CLK_MODE_GATED_CLK,
++      IPU_CSI_CLK_MODE_NONGATED_CLK,
++      IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
++      IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
++      IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
++      IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
++      IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
++      IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
++};
++
++static inline u32 ipu_csi_read(struct ipu_csi *csi, unsigned offset)
++{
++      return readl(csi->base + offset);
++}
++
++static inline void ipu_csi_write(struct ipu_csi *csi, u32 value,
++                               unsigned offset)
++{
++      writel(value, csi->base + offset);
++}
++
++/*
++ * Set mclk division ratio for generating test mode mclk. Only used
++ * for test generator.
++ */
++static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk,
++                                      u32 ipu_clk)
++{
++      u32 temp;
++      int div_ratio;
++
++      div_ratio = (ipu_clk / pixel_clk) - 1;
++
++      if (div_ratio > 0xFF || div_ratio < 0) {
++              dev_err(csi->ipu->dev,
++                      "value of pixel_clk extends normal range\n");
++              return -EINVAL;
++      }
++
++      temp = ipu_csi_read(csi, CSI_SENS_CONF);
++      temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
++      ipu_csi_write(csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
++                        CSI_SENS_CONF);
++
++      return 0;
++}
++
++/*
++ * Find the CSI data format and data width for the given V4L2 media
++ * bus pixel format code.
++ */
++static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code,
++                              enum v4l2_mbus_type mbus_type)
++{
++      switch (mbus_code) {
++      case MEDIA_BUS_FMT_BGR565_2X8_BE:
++      case MEDIA_BUS_FMT_BGR565_2X8_LE:
++      case MEDIA_BUS_FMT_RGB565_2X8_BE:
++      case MEDIA_BUS_FMT_RGB565_2X8_LE:
++              if (mbus_type == V4L2_MBUS_CSI2_DPHY)
++                      cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
++              else
++                      cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
++              cfg->mipi_dt = MIPI_DT_RGB565;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE:
++      case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444;
++              cfg->mipi_dt = MIPI_DT_RGB444;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
++      case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
++              cfg->mipi_dt = MIPI_DT_RGB555;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_RGB888_1X24:
++      case MEDIA_BUS_FMT_BGR888_1X24:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
++              cfg->mipi_dt = MIPI_DT_RGB888;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_UYVY8_2X8:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
++              cfg->mipi_dt = MIPI_DT_YUV422;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_YUYV8_2X8:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
++              cfg->mipi_dt = MIPI_DT_YUV422;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_UYVY8_1X16:
++      case MEDIA_BUS_FMT_YUYV8_1X16:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
++              cfg->mipi_dt = MIPI_DT_YUV422;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_16;
++              break;
++      case MEDIA_BUS_FMT_SBGGR8_1X8:
++      case MEDIA_BUS_FMT_SGBRG8_1X8:
++      case MEDIA_BUS_FMT_SGRBG8_1X8:
++      case MEDIA_BUS_FMT_SRGGB8_1X8:
++      case MEDIA_BUS_FMT_Y8_1X8:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
++              cfg->mipi_dt = MIPI_DT_RAW8;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8:
++      case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
++      case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
++      case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8:
++      case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE:
++      case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE:
++      case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE:
++      case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
++              cfg->mipi_dt = MIPI_DT_RAW10;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      case MEDIA_BUS_FMT_SBGGR10_1X10:
++      case MEDIA_BUS_FMT_SGBRG10_1X10:
++      case MEDIA_BUS_FMT_SGRBG10_1X10:
++      case MEDIA_BUS_FMT_SRGGB10_1X10:
++      case MEDIA_BUS_FMT_Y10_1X10:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
++              cfg->mipi_dt = MIPI_DT_RAW10;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_10;
++              break;
++      case MEDIA_BUS_FMT_SBGGR12_1X12:
++      case MEDIA_BUS_FMT_SGBRG12_1X12:
++      case MEDIA_BUS_FMT_SGRBG12_1X12:
++      case MEDIA_BUS_FMT_SRGGB12_1X12:
++      case MEDIA_BUS_FMT_Y12_1X12:
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
++              cfg->mipi_dt = MIPI_DT_RAW12;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_12;
++              break;
++      case MEDIA_BUS_FMT_JPEG_1X8:
++              /* TODO */
++              cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG;
++              cfg->mipi_dt = MIPI_DT_RAW8;
++              cfg->data_width = IPU_CSI_DATA_WIDTH_8;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++/* translate alternate field mode based on given standard */
++static inline enum v4l2_field
++ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
++{
++      return (field != V4L2_FIELD_ALTERNATE) ? field :
++              ((std & V4L2_STD_525_60) ?
++               V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
++}
++
++/*
++ * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
++ */
++static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
++                          const struct v4l2_mbus_config *mbus_cfg,
++                          const struct v4l2_mbus_framefmt *mbus_fmt)
++{
++      int ret;
++
++      memset(csicfg, 0, sizeof(*csicfg));
++
++      ret = mbus_code_to_bus_cfg(csicfg, mbus_fmt->code, mbus_cfg->type);
++      if (ret < 0)
++              return ret;
++
++      switch (mbus_cfg->type) {
++      case V4L2_MBUS_PARALLEL:
++              csicfg->ext_vsync = 1;
++              csicfg->vsync_pol = (mbus_cfg->flags &
++                                   V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0;
++              csicfg->hsync_pol = (mbus_cfg->flags &
++                                   V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0;
++              csicfg->pixclk_pol = (mbus_cfg->flags &
++                                    V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0;
++              csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
++              break;
++      case V4L2_MBUS_BT656:
++              csicfg->ext_vsync = 0;
++              if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field) ||
++                  mbus_fmt->field == V4L2_FIELD_ALTERNATE)
++                      csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
++              else
++                      csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
++              break;
++      case V4L2_MBUS_CSI2_DPHY:
++              /*
++               * MIPI CSI-2 requires non gated clock mode, all other
++               * parameters are not applicable for MIPI CSI-2 bus.
++               */
++              csicfg->clk_mode = IPU_CSI_CLK_MODE_NONGATED_CLK;
++              break;
++      default:
++              /* will never get here, keep compiler quiet */
++              break;
++      }
++
++      return 0;
++}
++
++static int
++ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
++                              const struct v4l2_mbus_framefmt *infmt,
++                              const struct v4l2_mbus_framefmt *outfmt,
++                              v4l2_std_id std)
++{
++      enum v4l2_field infield, outfield;
++      bool swap_fields;
++
++      /* get translated field type of input and output */
++      infield = ipu_csi_translate_field(infmt->field, std);
++      outfield = ipu_csi_translate_field(outfmt->field, std);
++
++      /*
++       * Write the H-V-F codes the CSI will match against the
++       * incoming data for start/end of active and blanking
++       * field intervals. If input and output field types are
++       * sequential but not the same (one is SEQ_BT and the other
++       * is SEQ_TB), swap the F-bit so that the CSI will capture
++       * field 1 lines before field 0 lines.
++       */
++      swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
++                     V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
++                     infield != outfield);
++
++      if (!swap_fields) {
++              /*
++               * Field0BlankEnd  = 110, Field0BlankStart  = 010
++               * Field0ActiveEnd = 100, Field0ActiveStart = 000
++               * Field1BlankEnd  = 111, Field1BlankStart  = 011
++               * Field1ActiveEnd = 101, Field1ActiveStart = 001
++               */
++              ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
++                            CSI_CCIR_CODE_1);
++              ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
++      } else {
++              dev_dbg(csi->ipu->dev, "capture field swap\n");
++
++              /* same as above but with F-bit inverted */
++              ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
++                            CSI_CCIR_CODE_1);
++              ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
++      }
++
++      ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
++
++      return 0;
++}
++
++
++int ipu_csi_init_interface(struct ipu_csi *csi,
++                         const struct v4l2_mbus_config *mbus_cfg,
++                         const struct v4l2_mbus_framefmt *infmt,
++                         const struct v4l2_mbus_framefmt *outfmt)
++{
++      struct ipu_csi_bus_config cfg;
++      unsigned long flags;
++      u32 width, height, data = 0;
++      v4l2_std_id std;
++      int ret;
++
++      ret = fill_csi_bus_cfg(&cfg, mbus_cfg, infmt);
++      if (ret < 0)
++              return ret;
++
++      /* set default sensor frame width and height */
++      width = infmt->width;
++      height = infmt->height;
++      if (infmt->field == V4L2_FIELD_ALTERNATE)
++              height *= 2;
++
++      /* Set the CSI_SENS_CONF register remaining fields */
++      data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
++              cfg.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
++              cfg.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
++              cfg.vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
++              cfg.hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
++              cfg.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
++              cfg.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
++              cfg.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
++              cfg.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
++              cfg.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
++              cfg.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      ipu_csi_write(csi, data, CSI_SENS_CONF);
++
++      /* Set CCIR registers */
++
++      switch (cfg.clk_mode) {
++      case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
++              ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
++              ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
++              break;
++      case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
++              if (width == 720 && height == 480) {
++                      std = V4L2_STD_NTSC;
++                      height = 525;
++              } else if (width == 720 && height == 576) {
++                      std = V4L2_STD_PAL;
++                      height = 625;
++              } else {
++                      dev_err(csi->ipu->dev,
++                              "Unsupported interlaced video mode\n");
++                      ret = -EINVAL;
++                      goto out_unlock;
++              }
++
++              ret = ipu_csi_set_bt_interlaced_codes(csi, infmt, outfmt, std);
++              if (ret)
++                      goto out_unlock;
++              break;
++      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
++      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
++      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
++      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
++              ipu_csi_write(csi, 0x40030 | CSI_CCIR_ERR_DET_EN,
++                                 CSI_CCIR_CODE_1);
++              ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
++              break;
++      case IPU_CSI_CLK_MODE_GATED_CLK:
++      case IPU_CSI_CLK_MODE_NONGATED_CLK:
++              ipu_csi_write(csi, 0, CSI_CCIR_CODE_1);
++              break;
++      }
++
++      /* Setup sensor frame size */
++      ipu_csi_write(csi, (width - 1) | ((height - 1) << 16),
++                    CSI_SENS_FRM_SIZE);
++
++      dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
++              ipu_csi_read(csi, CSI_SENS_CONF));
++      dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
++              ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
++
++out_unlock:
++      spin_unlock_irqrestore(&csi->lock, flags);
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_csi_init_interface);
++
++bool ipu_csi_is_interlaced(struct ipu_csi *csi)
++{
++      unsigned long flags;
++      u32 sensor_protocol;
++
++      spin_lock_irqsave(&csi->lock, flags);
++      sensor_protocol =
++              (ipu_csi_read(csi, CSI_SENS_CONF) &
++               CSI_SENS_CONF_SENS_PRTCL_MASK) >>
++              CSI_SENS_CONF_SENS_PRTCL_SHIFT;
++      spin_unlock_irqrestore(&csi->lock, flags);
++
++      switch (sensor_protocol) {
++      case IPU_CSI_CLK_MODE_GATED_CLK:
++      case IPU_CSI_CLK_MODE_NONGATED_CLK:
++      case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
++      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
++      case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
++              return false;
++      case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
++      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
++      case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
++              return true;
++      default:
++              dev_err(csi->ipu->dev,
++                      "CSI %d sensor protocol unsupported\n", csi->id);
++              return false;
++      }
++}
++EXPORT_SYMBOL_GPL(ipu_csi_is_interlaced);
++
++void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w)
++{
++      unsigned long flags;
++      u32 reg;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE);
++      w->width = (reg & 0xFFFF) + 1;
++      w->height = (reg >> 16 & 0xFFFF) + 1;
++
++      reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
++      w->left = (reg & CSI_HSC_MASK) >> CSI_HSC_SHIFT;
++      w->top = (reg & CSI_VSC_MASK) >> CSI_VSC_SHIFT;
++
++      spin_unlock_irqrestore(&csi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_csi_get_window);
++
++void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w)
++{
++      unsigned long flags;
++      u32 reg;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      ipu_csi_write(csi, (w->width - 1) | ((w->height - 1) << 16),
++                        CSI_ACT_FRM_SIZE);
++
++      reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
++      reg &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
++      reg |= ((w->top << CSI_VSC_SHIFT) | (w->left << CSI_HSC_SHIFT));
++      ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
++
++      spin_unlock_irqrestore(&csi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_csi_set_window);
++
++void ipu_csi_set_downsize(struct ipu_csi *csi, bool horiz, bool vert)
++{
++      unsigned long flags;
++      u32 reg;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
++      reg &= ~(CSI_HORI_DOWNSIZE_EN | CSI_VERT_DOWNSIZE_EN);
++      reg |= (horiz ? CSI_HORI_DOWNSIZE_EN : 0) |
++             (vert ? CSI_VERT_DOWNSIZE_EN : 0);
++      ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
++
++      spin_unlock_irqrestore(&csi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_csi_set_downsize);
++
++void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
++                              u32 r_value, u32 g_value, u32 b_value,
++                              u32 pix_clk)
++{
++      unsigned long flags;
++      u32 ipu_clk = clk_get_rate(csi->clk_ipu);
++      u32 temp;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      temp = ipu_csi_read(csi, CSI_TST_CTRL);
++
++      if (!active) {
++              temp &= ~CSI_TEST_GEN_MODE_EN;
++              ipu_csi_write(csi, temp, CSI_TST_CTRL);
++      } else {
++              /* Set sensb_mclk div_ratio */
++              ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk);
++
++              temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
++                        CSI_TEST_GEN_B_MASK);
++              temp |= CSI_TEST_GEN_MODE_EN;
++              temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
++                      (g_value << CSI_TEST_GEN_G_SHIFT) |
++                      (b_value << CSI_TEST_GEN_B_SHIFT);
++              ipu_csi_write(csi, temp, CSI_TST_CTRL);
++      }
++
++      spin_unlock_irqrestore(&csi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator);
++
++int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
++                            struct v4l2_mbus_framefmt *mbus_fmt)
++{
++      struct ipu_csi_bus_config cfg;
++      unsigned long flags;
++      u32 temp;
++      int ret;
++
++      if (vc > 3)
++              return -EINVAL;
++
++      ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code, V4L2_MBUS_CSI2_DPHY);
++      if (ret < 0)
++              return ret;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      temp = ipu_csi_read(csi, CSI_MIPI_DI);
++      temp &= ~(0xff << (vc * 8));
++      temp |= (cfg.mipi_dt << (vc * 8));
++      ipu_csi_write(csi, temp, CSI_MIPI_DI);
++
++      spin_unlock_irqrestore(&csi->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype);
++
++int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
++                        u32 max_ratio, u32 id)
++{
++      unsigned long flags;
++      u32 temp;
++
++      if (max_ratio > 5 || id > 3)
++              return -EINVAL;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      temp = ipu_csi_read(csi, CSI_SKIP);
++      temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
++                CSI_SKIP_SMFC_MASK);
++      temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
++              (id << CSI_ID_2_SKIP_SHIFT) |
++              (skip << CSI_SKIP_SMFC_SHIFT);
++      ipu_csi_write(csi, temp, CSI_SKIP);
++
++      spin_unlock_irqrestore(&csi->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc);
++
++int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest)
++{
++      unsigned long flags;
++      u32 csi_sens_conf, dest;
++
++      if (csi_dest == IPU_CSI_DEST_IDMAC)
++              dest = CSI_DATA_DEST_IDMAC;
++      else
++              dest = CSI_DATA_DEST_IC; /* IC or VDIC */
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF);
++      csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
++      csi_sens_conf |= (dest << CSI_SENS_CONF_DATA_DEST_SHIFT);
++      ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF);
++
++      spin_unlock_irqrestore(&csi->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_csi_set_dest);
++
++int ipu_csi_enable(struct ipu_csi *csi)
++{
++      ipu_module_enable(csi->ipu, csi->module);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_csi_enable);
++
++int ipu_csi_disable(struct ipu_csi *csi)
++{
++      ipu_module_disable(csi->ipu, csi->module);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_csi_disable);
++
++struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id)
++{
++      unsigned long flags;
++      struct ipu_csi *csi, *ret;
++
++      if (id > 1)
++              return ERR_PTR(-EINVAL);
++
++      csi = ipu->csi_priv[id];
++      ret = csi;
++
++      spin_lock_irqsave(&csi->lock, flags);
++
++      if (csi->inuse) {
++              ret = ERR_PTR(-EBUSY);
++              goto unlock;
++      }
++
++      csi->inuse = true;
++unlock:
++      spin_unlock_irqrestore(&csi->lock, flags);
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_csi_get);
++
++void ipu_csi_put(struct ipu_csi *csi)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&csi->lock, flags);
++      csi->inuse = false;
++      spin_unlock_irqrestore(&csi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_csi_put);
++
++int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
++               unsigned long base, u32 module, struct clk *clk_ipu)
++{
++      struct ipu_csi *csi;
++
++      if (id > 1)
++              return -ENODEV;
++
++      csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL);
++      if (!csi)
++              return -ENOMEM;
++
++      ipu->csi_priv[id] = csi;
++
++      spin_lock_init(&csi->lock);
++      csi->module = module;
++      csi->id = id;
++      csi->clk_ipu = clk_ipu;
++      csi->base = devm_ioremap(dev, base, PAGE_SIZE);
++      if (!csi->base)
++              return -ENOMEM;
++
++      dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n",
++              id, base, csi->base);
++      csi->ipu = ipu;
++
++      return 0;
++}
++
++void ipu_csi_exit(struct ipu_soc *ipu, int id)
++{
++}
++
++void ipu_csi_dump(struct ipu_csi *csi)
++{
++      dev_dbg(csi->ipu->dev, "CSI_SENS_CONF:     %08x\n",
++              ipu_csi_read(csi, CSI_SENS_CONF));
++      dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n",
++              ipu_csi_read(csi, CSI_SENS_FRM_SIZE));
++      dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE:  %08x\n",
++              ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
++      dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL:  %08x\n",
++              ipu_csi_read(csi, CSI_OUT_FRM_CTRL));
++      dev_dbg(csi->ipu->dev, "CSI_TST_CTRL:      %08x\n",
++              ipu_csi_read(csi, CSI_TST_CTRL));
++      dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1:   %08x\n",
++              ipu_csi_read(csi, CSI_CCIR_CODE_1));
++      dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2:   %08x\n",
++              ipu_csi_read(csi, CSI_CCIR_CODE_2));
++      dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3:   %08x\n",
++              ipu_csi_read(csi, CSI_CCIR_CODE_3));
++      dev_dbg(csi->ipu->dev, "CSI_MIPI_DI:       %08x\n",
++              ipu_csi_read(csi, CSI_MIPI_DI));
++      dev_dbg(csi->ipu->dev, "CSI_SKIP:          %08x\n",
++              ipu_csi_read(csi, CSI_SKIP));
++}
++EXPORT_SYMBOL_GPL(ipu_csi_dump);
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/ipu-dc.c
+@@ -0,0 +1,420 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++
++#include <linux/export.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++
++#include <video/imx-ipu-v3.h>
++#include "ipu-prv.h"
++
++#define DC_MAP_CONF_PTR(n)    (0x108 + ((n) & ~0x1) * 2)
++#define DC_MAP_CONF_VAL(n)    (0x144 + ((n) & ~0x1) * 2)
++
++#define DC_EVT_NF             0
++#define DC_EVT_NL             1
++#define DC_EVT_EOF            2
++#define DC_EVT_NFIELD         3
++#define DC_EVT_EOL            4
++#define DC_EVT_EOFIELD                5
++#define DC_EVT_NEW_ADDR               6
++#define DC_EVT_NEW_CHAN               7
++#define DC_EVT_NEW_DATA               8
++
++#define DC_EVT_NEW_ADDR_W_0   0
++#define DC_EVT_NEW_ADDR_W_1   1
++#define DC_EVT_NEW_CHAN_W_0   2
++#define DC_EVT_NEW_CHAN_W_1   3
++#define DC_EVT_NEW_DATA_W_0   4
++#define DC_EVT_NEW_DATA_W_1   5
++#define DC_EVT_NEW_ADDR_R_0   6
++#define DC_EVT_NEW_ADDR_R_1   7
++#define DC_EVT_NEW_CHAN_R_0   8
++#define DC_EVT_NEW_CHAN_R_1   9
++#define DC_EVT_NEW_DATA_R_0   10
++#define DC_EVT_NEW_DATA_R_1   11
++
++#define DC_WR_CH_CONF         0x0
++#define DC_WR_CH_ADDR         0x4
++#define DC_RL_CH(evt)         (8 + ((evt) & ~0x1) * 2)
++
++#define DC_GEN                        0xd4
++#define DC_DISP_CONF1(disp)   (0xd8 + (disp) * 4)
++#define DC_DISP_CONF2(disp)   (0xe8 + (disp) * 4)
++#define DC_STAT                       0x1c8
++
++#define WROD(lf)              (0x18 | ((lf) << 1))
++#define WRG                   0x01
++#define WCLK                  0xc9
++
++#define SYNC_WAVE 0
++#define NULL_WAVE (-1)
++
++#define DC_GEN_SYNC_1_6_SYNC  (2 << 1)
++#define DC_GEN_SYNC_PRIORITY_1        (1 << 7)
++
++#define DC_WR_CH_CONF_WORD_SIZE_8             (0 << 0)
++#define DC_WR_CH_CONF_WORD_SIZE_16            (1 << 0)
++#define DC_WR_CH_CONF_WORD_SIZE_24            (2 << 0)
++#define DC_WR_CH_CONF_WORD_SIZE_32            (3 << 0)
++#define DC_WR_CH_CONF_DISP_ID_PARALLEL(i)     (((i) & 0x1) << 3)
++#define DC_WR_CH_CONF_DISP_ID_SERIAL          (2 << 3)
++#define DC_WR_CH_CONF_DISP_ID_ASYNC           (3 << 4)
++#define DC_WR_CH_CONF_FIELD_MODE              (1 << 9)
++#define DC_WR_CH_CONF_PROG_TYPE_NORMAL                (4 << 5)
++#define DC_WR_CH_CONF_PROG_TYPE_MASK          (7 << 5)
++#define DC_WR_CH_CONF_PROG_DI_ID              (1 << 2)
++#define DC_WR_CH_CONF_PROG_DISP_ID(i)         (((i) & 0x1) << 3)
++
++#define IPU_DC_NUM_CHANNELS   10
++
++struct ipu_dc_priv;
++
++enum ipu_dc_map {
++      IPU_DC_MAP_RGB24,
++      IPU_DC_MAP_RGB565,
++      IPU_DC_MAP_GBR24, /* TVEv2 */
++      IPU_DC_MAP_BGR666,
++      IPU_DC_MAP_LVDS666,
++      IPU_DC_MAP_BGR24,
++};
++
++struct ipu_dc {
++      /* The display interface number assigned to this dc channel */
++      unsigned int            di;
++      void __iomem            *base;
++      struct ipu_dc_priv      *priv;
++      int                     chno;
++      bool                    in_use;
++};
++
++struct ipu_dc_priv {
++      void __iomem            *dc_reg;
++      void __iomem            *dc_tmpl_reg;
++      struct ipu_soc          *ipu;
++      struct device           *dev;
++      struct ipu_dc           channels[IPU_DC_NUM_CHANNELS];
++      struct mutex            mutex;
++      struct completion       comp;
++      int                     use_count;
++};
++
++static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
++{
++      u32 reg;
++
++      reg = readl(dc->base + DC_RL_CH(event));
++      reg &= ~(0xffff << (16 * (event & 0x1)));
++      reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
++      writel(reg, dc->base + DC_RL_CH(event));
++}
++
++static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
++              int map, int wave, int glue, int sync, int stop)
++{
++      struct ipu_dc_priv *priv = dc->priv;
++      u32 reg1, reg2;
++
++      if (opcode == WCLK) {
++              reg1 = (operand << 20) & 0xfff00000;
++              reg2 = operand >> 12 | opcode << 1 | stop << 9;
++      } else if (opcode == WRG) {
++              reg1 = sync | glue << 4 | ++wave << 11 | ((operand << 15) & 0xffff8000);
++              reg2 = operand >> 17 | opcode << 7 | stop << 9;
++      } else {
++              reg1 = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000);
++              reg2 = operand >> 12 | opcode << 4 | stop << 9;
++      }
++      writel(reg1, priv->dc_tmpl_reg + word * 8);
++      writel(reg2, priv->dc_tmpl_reg + word * 8 + 4);
++}
++
++static int ipu_bus_format_to_map(u32 fmt)
++{
++      switch (fmt) {
++      default:
++              WARN_ON(1);
++              /* fall-through */
++      case MEDIA_BUS_FMT_RGB888_1X24:
++              return IPU_DC_MAP_RGB24;
++      case MEDIA_BUS_FMT_RGB565_1X16:
++              return IPU_DC_MAP_RGB565;
++      case MEDIA_BUS_FMT_GBR888_1X24:
++              return IPU_DC_MAP_GBR24;
++      case MEDIA_BUS_FMT_RGB666_1X18:
++              return IPU_DC_MAP_BGR666;
++      case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
++              return IPU_DC_MAP_LVDS666;
++      case MEDIA_BUS_FMT_BGR888_1X24:
++              return IPU_DC_MAP_BGR24;
++      }
++}
++
++int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
++              u32 bus_format, u32 width)
++{
++      struct ipu_dc_priv *priv = dc->priv;
++      int addr, sync;
++      u32 reg = 0;
++      int map;
++
++      dc->di = ipu_di_get_num(di);
++
++      map = ipu_bus_format_to_map(bus_format);
++
++      /*
++       * In interlaced mode we need more counters to create the asymmetric
++       * per-field VSYNC signals. The pixel active signal synchronising DC
++       * to DI moves to signal generator #6 (see ipu-di.c). In progressive
++       * mode counter #5 is used.
++       */
++      sync = interlaced ? 6 : 5;
++
++      /* Reserve 5 microcode template words for each DI */
++      if (dc->di)
++              addr = 5;
++      else
++              addr = 0;
++
++      if (interlaced) {
++              dc_link_event(dc, DC_EVT_NL, addr, 3);
++              dc_link_event(dc, DC_EVT_EOL, addr, 2);
++              dc_link_event(dc, DC_EVT_NEW_DATA, addr, 1);
++
++              /* Init template microcode */
++              dc_write_tmpl(dc, addr, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
++      } else {
++              dc_link_event(dc, DC_EVT_NL, addr + 2, 3);
++              dc_link_event(dc, DC_EVT_EOL, addr + 3, 2);
++              dc_link_event(dc, DC_EVT_NEW_DATA, addr + 1, 1);
++
++              /* Init template microcode */
++              dc_write_tmpl(dc, addr + 2, WROD(0), 0, map, SYNC_WAVE, 8, sync, 1);
++              dc_write_tmpl(dc, addr + 3, WROD(0), 0, map, SYNC_WAVE, 4, sync, 0);
++              dc_write_tmpl(dc, addr + 4, WRG, 0, map, NULL_WAVE, 0, 0, 1);
++              dc_write_tmpl(dc, addr + 1, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
++      }
++
++      dc_link_event(dc, DC_EVT_NF, 0, 0);
++      dc_link_event(dc, DC_EVT_NFIELD, 0, 0);
++      dc_link_event(dc, DC_EVT_EOF, 0, 0);
++      dc_link_event(dc, DC_EVT_EOFIELD, 0, 0);
++      dc_link_event(dc, DC_EVT_NEW_CHAN, 0, 0);
++      dc_link_event(dc, DC_EVT_NEW_ADDR, 0, 0);
++
++      reg = readl(dc->base + DC_WR_CH_CONF);
++      if (interlaced)
++              reg |= DC_WR_CH_CONF_FIELD_MODE;
++      else
++              reg &= ~DC_WR_CH_CONF_FIELD_MODE;
++      writel(reg, dc->base + DC_WR_CH_CONF);
++
++      writel(0x0, dc->base + DC_WR_CH_ADDR);
++      writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
++
++void ipu_dc_enable(struct ipu_soc *ipu)
++{
++      struct ipu_dc_priv *priv = ipu->dc_priv;
++
++      mutex_lock(&priv->mutex);
++
++      if (!priv->use_count)
++              ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
++
++      priv->use_count++;
++
++      mutex_unlock(&priv->mutex);
++}
++EXPORT_SYMBOL_GPL(ipu_dc_enable);
++
++void ipu_dc_enable_channel(struct ipu_dc *dc)
++{
++      u32 reg;
++
++      reg = readl(dc->base + DC_WR_CH_CONF);
++      reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL;
++      writel(reg, dc->base + DC_WR_CH_CONF);
++}
++EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
++
++void ipu_dc_disable_channel(struct ipu_dc *dc)
++{
++      u32 val;
++
++      val = readl(dc->base + DC_WR_CH_CONF);
++      val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
++      writel(val, dc->base + DC_WR_CH_CONF);
++}
++EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
++
++void ipu_dc_disable(struct ipu_soc *ipu)
++{
++      struct ipu_dc_priv *priv = ipu->dc_priv;
++
++      mutex_lock(&priv->mutex);
++
++      priv->use_count--;
++      if (!priv->use_count)
++              ipu_module_disable(priv->ipu, IPU_CONF_DC_EN);
++
++      if (priv->use_count < 0)
++              priv->use_count = 0;
++
++      mutex_unlock(&priv->mutex);
++}
++EXPORT_SYMBOL_GPL(ipu_dc_disable);
++
++static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
++              int byte_num, int offset, int mask)
++{
++      int ptr = map * 3 + byte_num;
++      u32 reg;
++
++      reg = readl(priv->dc_reg + DC_MAP_CONF_VAL(ptr));
++      reg &= ~(0xffff << (16 * (ptr & 0x1)));
++      reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
++      writel(reg, priv->dc_reg + DC_MAP_CONF_VAL(ptr));
++
++      reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
++      reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
++      reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
++      writel(reg, priv->dc_reg + DC_MAP_CONF_PTR(map));
++}
++
++static void ipu_dc_map_clear(struct ipu_dc_priv *priv, int map)
++{
++      u32 reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
++
++      writel(reg & ~(0xffff << (16 * (map & 0x1))),
++                   priv->dc_reg + DC_MAP_CONF_PTR(map));
++}
++
++struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel)
++{
++      struct ipu_dc_priv *priv = ipu->dc_priv;
++      struct ipu_dc *dc;
++
++      if (channel >= IPU_DC_NUM_CHANNELS)
++              return ERR_PTR(-ENODEV);
++
++      dc = &priv->channels[channel];
++
++      mutex_lock(&priv->mutex);
++
++      if (dc->in_use) {
++              mutex_unlock(&priv->mutex);
++              return ERR_PTR(-EBUSY);
++      }
++
++      dc->in_use = true;
++
++      mutex_unlock(&priv->mutex);
++
++      return dc;
++}
++EXPORT_SYMBOL_GPL(ipu_dc_get);
++
++void ipu_dc_put(struct ipu_dc *dc)
++{
++      struct ipu_dc_priv *priv = dc->priv;
++
++      mutex_lock(&priv->mutex);
++      dc->in_use = false;
++      mutex_unlock(&priv->mutex);
++}
++EXPORT_SYMBOL_GPL(ipu_dc_put);
++
++int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
++              unsigned long base, unsigned long template_base)
++{
++      struct ipu_dc_priv *priv;
++      static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
++              0x78, 0, 0x94, 0xb4};
++      int i;
++
++      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++
++      mutex_init(&priv->mutex);
++
++      priv->dev = dev;
++      priv->ipu = ipu;
++      priv->dc_reg = devm_ioremap(dev, base, PAGE_SIZE);
++      priv->dc_tmpl_reg = devm_ioremap(dev, template_base, PAGE_SIZE);
++      if (!priv->dc_reg || !priv->dc_tmpl_reg)
++              return -ENOMEM;
++
++      for (i = 0; i < IPU_DC_NUM_CHANNELS; i++) {
++              priv->channels[i].chno = i;
++              priv->channels[i].priv = priv;
++              priv->channels[i].base = priv->dc_reg + channel_offsets[i];
++      }
++
++      writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
++                      DC_WR_CH_CONF_PROG_DI_ID,
++                      priv->channels[1].base + DC_WR_CH_CONF);
++      writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0),
++                      priv->channels[5].base + DC_WR_CH_CONF);
++
++      writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1,
++              priv->dc_reg + DC_GEN);
++
++      ipu->dc_priv = priv;
++
++      dev_dbg(dev, "DC base: 0x%08lx template base: 0x%08lx\n",
++                      base, template_base);
++
++      /* rgb24 */
++      ipu_dc_map_clear(priv, IPU_DC_MAP_RGB24);
++      ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 0, 7, 0xff); /* blue */
++      ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 1, 15, 0xff); /* green */
++      ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 2, 23, 0xff); /* red */
++
++      /* rgb565 */
++      ipu_dc_map_clear(priv, IPU_DC_MAP_RGB565);
++      ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 0, 4, 0xf8); /* blue */
++      ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc); /* green */
++      ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8); /* red */
++
++      /* gbr24 */
++      ipu_dc_map_clear(priv, IPU_DC_MAP_GBR24);
++      ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 2, 15, 0xff); /* green */
++      ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 1, 7, 0xff); /* blue */
++      ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 0, 23, 0xff); /* red */
++
++      /* bgr666 */
++      ipu_dc_map_clear(priv, IPU_DC_MAP_BGR666);
++      ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 0, 5, 0xfc); /* blue */
++      ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc); /* green */
++      ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc); /* red */
++
++      /* lvds666 */
++      ipu_dc_map_clear(priv, IPU_DC_MAP_LVDS666);
++      ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 0, 5, 0xfc); /* blue */
++      ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 1, 13, 0xfc); /* green */
++      ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 2, 21, 0xfc); /* red */
++
++      /* bgr24 */
++      ipu_dc_map_clear(priv, IPU_DC_MAP_BGR24);
++      ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 2, 7, 0xff); /* red */
++      ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */
++      ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */
++
++      return 0;
++}
++
++void ipu_dc_exit(struct ipu_soc *ipu)
++{
++}
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/ipu-di.c
+@@ -0,0 +1,745 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++#include <linux/export.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++
++#include <video/imx-ipu-v3.h>
++#include "ipu-prv.h"
++
++struct ipu_di {
++      void __iomem *base;
++      int id;
++      u32 module;
++      struct clk *clk_di;     /* display input clock */
++      struct clk *clk_ipu;    /* IPU bus clock */
++      struct clk *clk_di_pixel; /* resulting pixel clock */
++      bool inuse;
++      struct ipu_soc *ipu;
++};
++
++static DEFINE_MUTEX(di_mutex);
++
++struct di_sync_config {
++      int run_count;
++      int run_src;
++      int offset_count;
++      int offset_src;
++      int repeat_count;
++      int cnt_clr_src;
++      int cnt_polarity_gen_en;
++      int cnt_polarity_clr_src;
++      int cnt_polarity_trigger_src;
++      int cnt_up;
++      int cnt_down;
++};
++
++enum di_pins {
++      DI_PIN11 = 0,
++      DI_PIN12 = 1,
++      DI_PIN13 = 2,
++      DI_PIN14 = 3,
++      DI_PIN15 = 4,
++      DI_PIN16 = 5,
++      DI_PIN17 = 6,
++      DI_PIN_CS = 7,
++
++      DI_PIN_SER_CLK = 0,
++      DI_PIN_SER_RS = 1,
++};
++
++enum di_sync_wave {
++      DI_SYNC_NONE = 0,
++      DI_SYNC_CLK = 1,
++      DI_SYNC_INT_HSYNC = 2,
++      DI_SYNC_HSYNC = 3,
++      DI_SYNC_VSYNC = 4,
++      DI_SYNC_DE = 6,
++
++      DI_SYNC_CNT1 = 2,       /* counter >= 2 only */
++      DI_SYNC_CNT4 = 5,       /* counter >= 5 only */
++      DI_SYNC_CNT5 = 6,       /* counter >= 6 only */
++};
++
++#define SYNC_WAVE 0
++
++#define DI_GENERAL            0x0000
++#define DI_BS_CLKGEN0         0x0004
++#define DI_BS_CLKGEN1         0x0008
++#define DI_SW_GEN0(gen)               (0x000c + 4 * ((gen) - 1))
++#define DI_SW_GEN1(gen)               (0x0030 + 4 * ((gen) - 1))
++#define DI_STP_REP(gen)               (0x0148 + 4 * (((gen) - 1)/2))
++#define DI_SYNC_AS_GEN                0x0054
++#define DI_DW_GEN(gen)                (0x0058 + 4 * (gen))
++#define DI_DW_SET(gen, set)   (0x0088 + 4 * ((gen) + 0xc * (set)))
++#define DI_SER_CONF           0x015c
++#define DI_SSC                        0x0160
++#define DI_POL                        0x0164
++#define DI_AW0                        0x0168
++#define DI_AW1                        0x016c
++#define DI_SCR_CONF           0x0170
++#define DI_STAT                       0x0174
++
++#define DI_SW_GEN0_RUN_COUNT(x)                       ((x) << 19)
++#define DI_SW_GEN0_RUN_SRC(x)                 ((x) << 16)
++#define DI_SW_GEN0_OFFSET_COUNT(x)            ((x) << 3)
++#define DI_SW_GEN0_OFFSET_SRC(x)              ((x) << 0)
++
++#define DI_SW_GEN1_CNT_POL_GEN_EN(x)          ((x) << 29)
++#define DI_SW_GEN1_CNT_CLR_SRC(x)             ((x) << 25)
++#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x)     ((x) << 12)
++#define DI_SW_GEN1_CNT_POL_CLR_SRC(x)         ((x) << 9)
++#define DI_SW_GEN1_CNT_DOWN(x)                        ((x) << 16)
++#define DI_SW_GEN1_CNT_UP(x)                  (x)
++#define DI_SW_GEN1_AUTO_RELOAD                        (0x10000000)
++
++#define DI_DW_GEN_ACCESS_SIZE_OFFSET          24
++#define DI_DW_GEN_COMPONENT_SIZE_OFFSET               16
++
++#define DI_GEN_POLARITY_1                     (1 << 0)
++#define DI_GEN_POLARITY_2                     (1 << 1)
++#define DI_GEN_POLARITY_3                     (1 << 2)
++#define DI_GEN_POLARITY_4                     (1 << 3)
++#define DI_GEN_POLARITY_5                     (1 << 4)
++#define DI_GEN_POLARITY_6                     (1 << 5)
++#define DI_GEN_POLARITY_7                     (1 << 6)
++#define DI_GEN_POLARITY_8                     (1 << 7)
++#define DI_GEN_POLARITY_DISP_CLK              (1 << 17)
++#define DI_GEN_DI_CLK_EXT                     (1 << 20)
++#define DI_GEN_DI_VSYNC_EXT                   (1 << 21)
++
++#define DI_POL_DRDY_DATA_POLARITY             (1 << 7)
++#define DI_POL_DRDY_POLARITY_15                       (1 << 4)
++
++#define DI_VSYNC_SEL_OFFSET                   13
++
++static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
++{
++      return readl(di->base + offset);
++}
++
++static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
++{
++      writel(value, di->base + offset);
++}
++
++static void ipu_di_data_wave_config(struct ipu_di *di,
++                                   int wave_gen,
++                                   int access_size, int component_size)
++{
++      u32 reg;
++      reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
++          (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
++      ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
++}
++
++static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin,
++              int set, int up, int down)
++{
++      u32 reg;
++
++      reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
++      reg &= ~(0x3 << (di_pin * 2));
++      reg |= set << (di_pin * 2);
++      ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
++
++      ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
++}
++
++static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config,
++              int start, int count)
++{
++      u32 reg;
++      int i;
++
++      for (i = 0; i < count; i++) {
++              struct di_sync_config *c = &config[i];
++              int wave_gen = start + i + 1;
++
++              if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) ||
++                              (c->repeat_count >= 0x1000) ||
++                              (c->cnt_up >= 0x400) ||
++                              (c->cnt_down >= 0x400)) {
++                      dev_err(di->ipu->dev, "DI%d counters out of range.\n",
++                                      di->id);
++                      return;
++              }
++
++              reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
++                      DI_SW_GEN0_RUN_SRC(c->run_src) |
++                      DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
++                      DI_SW_GEN0_OFFSET_SRC(c->offset_src);
++              ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
++
++              reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
++                      DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
++                      DI_SW_GEN1_CNT_POL_TRIGGER_SRC(
++                                      c->cnt_polarity_trigger_src) |
++                      DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
++                      DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
++                      DI_SW_GEN1_CNT_UP(c->cnt_up);
++
++              /* Enable auto reload */
++              if (c->repeat_count == 0)
++                      reg |= DI_SW_GEN1_AUTO_RELOAD;
++
++              ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
++
++              reg = ipu_di_read(di, DI_STP_REP(wave_gen));
++              reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
++              reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
++              ipu_di_write(di, reg, DI_STP_REP(wave_gen));
++      }
++}
++
++static void ipu_di_sync_config_interlaced(struct ipu_di *di,
++              struct ipu_di_signal_cfg *sig)
++{
++      u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
++              sig->mode.hback_porch + sig->mode.hfront_porch;
++      u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
++              sig->mode.vback_porch + sig->mode.vfront_porch;
++      struct di_sync_config cfg[] = {
++              {
++                      /* 1: internal VSYNC for each frame */
++                      .run_count = v_total * 2 - 1,
++                      .run_src = 3,                   /* == counter 7 */
++              }, {
++                      /* PIN2: HSYNC waveform */
++                      .run_count = h_total - 1,
++                      .run_src = DI_SYNC_CLK,
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
++                      .cnt_down = sig->mode.hsync_len * 2,
++              }, {
++                      /* PIN3: VSYNC waveform */
++                      .run_count = v_total - 1,
++                      .run_src = 4,                   /* == counter 7 */
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = 4,  /* == counter 7 */
++                      .cnt_down = sig->mode.vsync_len * 2,
++                      .cnt_clr_src = DI_SYNC_CNT1,
++              }, {
++                      /* 4: Field */
++                      .run_count = v_total / 2,
++                      .run_src = DI_SYNC_HSYNC,
++                      .offset_count = h_total / 2,
++                      .offset_src = DI_SYNC_CLK,
++                      .repeat_count = 2,
++                      .cnt_clr_src = DI_SYNC_CNT1,
++              }, {
++                      /* 5: Active lines */
++                      .run_src = DI_SYNC_HSYNC,
++                      .offset_count = (sig->mode.vsync_len +
++                                       sig->mode.vback_porch) / 2,
++                      .offset_src = DI_SYNC_HSYNC,
++                      .repeat_count = sig->mode.vactive / 2,
++                      .cnt_clr_src = DI_SYNC_CNT4,
++              }, {
++                      /* 6: Active pixel, referenced by DC */
++                      .run_src = DI_SYNC_CLK,
++                      .offset_count = sig->mode.hsync_len +
++                                      sig->mode.hback_porch,
++                      .offset_src = DI_SYNC_CLK,
++                      .repeat_count = sig->mode.hactive,
++                      .cnt_clr_src = DI_SYNC_CNT5,
++              }, {
++                      /* 7: Half line HSYNC */
++                      .run_count = h_total / 2 - 1,
++                      .run_src = DI_SYNC_CLK,
++              }
++      };
++
++      ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
++
++      ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
++}
++
++static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
++              struct ipu_di_signal_cfg *sig, int div)
++{
++      u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
++              sig->mode.hback_porch + sig->mode.hfront_porch;
++      u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
++              sig->mode.vback_porch + sig->mode.vfront_porch;
++      struct di_sync_config cfg[] = {
++              {
++                      /* 1: INT_HSYNC */
++                      .run_count = h_total - 1,
++                      .run_src = DI_SYNC_CLK,
++              } , {
++                      /* PIN2: HSYNC */
++                      .run_count = h_total - 1,
++                      .run_src = DI_SYNC_CLK,
++                      .offset_count = div * sig->v_to_h_sync,
++                      .offset_src = DI_SYNC_CLK,
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
++                      .cnt_down = sig->mode.hsync_len * 2,
++              } , {
++                      /* PIN3: VSYNC */
++                      .run_count = v_total - 1,
++                      .run_src = DI_SYNC_INT_HSYNC,
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
++                      .cnt_down = sig->mode.vsync_len * 2,
++              } , {
++                      /* 4: Line Active */
++                      .run_src = DI_SYNC_HSYNC,
++                      .offset_count = sig->mode.vsync_len +
++                                      sig->mode.vback_porch,
++                      .offset_src = DI_SYNC_HSYNC,
++                      .repeat_count = sig->mode.vactive,
++                      .cnt_clr_src = DI_SYNC_VSYNC,
++              } , {
++                      /* 5: Pixel Active, referenced by DC */
++                      .run_src = DI_SYNC_CLK,
++                      .offset_count = sig->mode.hsync_len +
++                                      sig->mode.hback_porch,
++                      .offset_src = DI_SYNC_CLK,
++                      .repeat_count = sig->mode.hactive,
++                      .cnt_clr_src = 5, /* Line Active */
++              } , {
++                      /* unused */
++              } , {
++                      /* unused */
++              } , {
++                      /* unused */
++              } , {
++                      /* unused */
++              },
++      };
++      /* can't use #7 and #8 for line active and pixel active counters */
++      struct di_sync_config cfg_vga[] = {
++              {
++                      /* 1: INT_HSYNC */
++                      .run_count = h_total - 1,
++                      .run_src = DI_SYNC_CLK,
++              } , {
++                      /* 2: VSYNC */
++                      .run_count = v_total - 1,
++                      .run_src = DI_SYNC_INT_HSYNC,
++              } , {
++                      /* 3: Line Active */
++                      .run_src = DI_SYNC_INT_HSYNC,
++                      .offset_count = sig->mode.vsync_len +
++                                      sig->mode.vback_porch,
++                      .offset_src = DI_SYNC_INT_HSYNC,
++                      .repeat_count = sig->mode.vactive,
++                      .cnt_clr_src = 3 /* VSYNC */,
++              } , {
++                      /* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
++                      .run_count = h_total - 1,
++                      .run_src = DI_SYNC_CLK,
++                      .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
++                      .offset_src = DI_SYNC_CLK,
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
++                      .cnt_down = sig->mode.hsync_len * 2,
++              } , {
++                      /* 5: Pixel Active signal to DC */
++                      .run_src = DI_SYNC_CLK,
++                      .offset_count = sig->mode.hsync_len +
++                                      sig->mode.hback_porch,
++                      .offset_src = DI_SYNC_CLK,
++                      .repeat_count = sig->mode.hactive,
++                      .cnt_clr_src = 4, /* Line Active */
++              } , {
++                      /* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
++                      .run_count = v_total - 1,
++                      .run_src = DI_SYNC_INT_HSYNC,
++                      .offset_count = 1, /* magic value from Freescale TVE driver */
++                      .offset_src = DI_SYNC_INT_HSYNC,
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
++                      .cnt_down = sig->mode.vsync_len * 2,
++              } , {
++                      /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
++                      .run_count = h_total - 1,
++                      .run_src = DI_SYNC_CLK,
++                      .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
++                      .offset_src = DI_SYNC_CLK,
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = DI_SYNC_CLK,
++                      .cnt_down = sig->mode.hsync_len * 2,
++              } , {
++                      /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
++                      .run_count = v_total - 1,
++                      .run_src = DI_SYNC_INT_HSYNC,
++                      .offset_count = 1, /* magic value from Freescale TVE driver */
++                      .offset_src = DI_SYNC_INT_HSYNC,
++                      .cnt_polarity_gen_en = 1,
++                      .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
++                      .cnt_down = sig->mode.vsync_len * 2,
++              } , {
++                      /* unused */
++              },
++      };
++
++      ipu_di_write(di, v_total - 1, DI_SCR_CONF);
++      if (sig->hsync_pin == 2 && sig->vsync_pin == 3)
++              ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
++      else
++              ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
++}
++
++static void ipu_di_config_clock(struct ipu_di *di,
++      const struct ipu_di_signal_cfg *sig)
++{
++      struct clk *clk;
++      unsigned clkgen0;
++      uint32_t val;
++
++      if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
++              /*
++               * CLKMODE_EXT means we must use the DI clock: this is
++               * needed for things like LVDS which needs to feed the
++               * DI and LDB with the same pixel clock.
++               */
++              clk = di->clk_di;
++
++              if (sig->clkflags & IPU_DI_CLKMODE_SYNC) {
++                      /*
++                       * CLKMODE_SYNC means that we want the DI to be
++                       * clocked at the same rate as the parent clock.
++                       * This is needed (eg) for LDB which needs to be
++                       * fed with the same pixel clock.  We assume that
++                       * the LDB clock has already been set correctly.
++                       */
++                      clkgen0 = 1 << 4;
++              } else {
++                      /*
++                       * We can use the divider.  We should really have
++                       * a flag here indicating whether the bridge can
++                       * cope with a fractional divider or not.  For the
++                       * time being, let's go for simplicitly and
++                       * reliability.
++                       */
++                      unsigned long in_rate;
++                      unsigned div;
++
++                      clk_set_rate(clk, sig->mode.pixelclock);
++
++                      in_rate = clk_get_rate(clk);
++                      div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
++                      div = clamp(div, 1U, 255U);
++
++                      clkgen0 = div << 4;
++              }
++      } else {
++              /*
++               * For other interfaces, we can arbitarily select between
++               * the DI specific clock and the internal IPU clock.  See
++               * DI_GENERAL bit 20.  We select the IPU clock if it can
++               * give us a clock rate within 1% of the requested frequency,
++               * otherwise we use the DI clock.
++               */
++              unsigned long rate, clkrate;
++              unsigned div, error;
++
++              clkrate = clk_get_rate(di->clk_ipu);
++              div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
++              div = clamp(div, 1U, 255U);
++              rate = clkrate / div;
++
++              error = rate / (sig->mode.pixelclock / 1000);
++
++              dev_dbg(di->ipu->dev, "  IPU clock can give %lu with divider %u, error %d.%u%%\n",
++                      rate, div, (signed)(error - 1000) / 10, error % 10);
++
++              /* Allow a 1% error */
++              if (error < 1010 && error >= 990) {
++                      clk = di->clk_ipu;
++
++                      clkgen0 = div << 4;
++              } else {
++                      unsigned long in_rate;
++                      unsigned div;
++
++                      clk = di->clk_di;
++
++                      clk_set_rate(clk, sig->mode.pixelclock);
++
++                      in_rate = clk_get_rate(clk);
++                      div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
++                      div = clamp(div, 1U, 255U);
++
++                      clkgen0 = div << 4;
++              }
++      }
++
++      di->clk_di_pixel = clk;
++
++      /* Set the divider */
++      ipu_di_write(di, clkgen0, DI_BS_CLKGEN0);
++
++      /*
++       * Set the high/low periods.  Bits 24:16 give us the falling edge,
++       * and bits 8:0 give the rising edge.  LSB is fraction, and is
++       * based on the divider above.  We want a 50% duty cycle, so set
++       * the falling edge to be half the divider.
++       */
++      ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1);
++
++      /* Finally select the input clock */
++      val = ipu_di_read(di, DI_GENERAL) & ~DI_GEN_DI_CLK_EXT;
++      if (clk == di->clk_di)
++              val |= DI_GEN_DI_CLK_EXT;
++      ipu_di_write(di, val, DI_GENERAL);
++
++      dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
++              sig->mode.pixelclock,
++              clk_get_rate(di->clk_ipu),
++              clk_get_rate(di->clk_di),
++              clk == di->clk_di ? "DI" : "IPU",
++              clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
++}
++
++/*
++ * This function is called to adjust a video mode to IPU restrictions.
++ * It is meant to be called from drm crtc mode_fixup() methods.
++ */
++int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode)
++{
++      u32 diff;
++
++      if (mode->vfront_porch >= 2)
++              return 0;
++
++      diff = 2 - mode->vfront_porch;
++
++      if (mode->vback_porch >= diff) {
++              mode->vfront_porch = 2;
++              mode->vback_porch -= diff;
++      } else if (mode->vsync_len > diff) {
++              mode->vfront_porch = 2;
++              mode->vsync_len = mode->vsync_len - diff;
++      } else {
++              dev_warn(di->ipu->dev, "failed to adjust videomode\n");
++              return -EINVAL;
++      }
++
++      dev_dbg(di->ipu->dev, "videomode adapted for IPU restrictions\n");
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode);
++
++static u32 ipu_di_gen_polarity(int pin)
++{
++      switch (pin) {
++      case 1:
++              return DI_GEN_POLARITY_1;
++      case 2:
++              return DI_GEN_POLARITY_2;
++      case 3:
++              return DI_GEN_POLARITY_3;
++      case 4:
++              return DI_GEN_POLARITY_4;
++      case 5:
++              return DI_GEN_POLARITY_5;
++      case 6:
++              return DI_GEN_POLARITY_6;
++      case 7:
++              return DI_GEN_POLARITY_7;
++      case 8:
++              return DI_GEN_POLARITY_8;
++      }
++      return 0;
++}
++
++int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
++{
++      u32 reg;
++      u32 di_gen, vsync_cnt;
++      u32 div;
++
++      dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
++              di->id, sig->mode.hactive, sig->mode.vactive);
++
++      dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
++              clk_get_rate(di->clk_ipu),
++              clk_get_rate(di->clk_di),
++              sig->mode.pixelclock);
++
++      mutex_lock(&di_mutex);
++
++      ipu_di_config_clock(di, sig);
++
++      div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
++      div = div / 16;         /* Now divider is integer portion */
++
++      /* Setup pixel clock timing */
++      /* Down time is half of period */
++      ipu_di_write(di, (div << 16), DI_BS_CLKGEN1);
++
++      ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1);
++      ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
++
++      di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
++      di_gen |= DI_GEN_DI_VSYNC_EXT;
++
++      if (sig->mode.flags & DISPLAY_FLAGS_INTERLACED) {
++              ipu_di_sync_config_interlaced(di, sig);
++
++              /* set y_sel = 1 */
++              di_gen |= 0x10000000;
++
++              vsync_cnt = 3;
++      } else {
++              ipu_di_sync_config_noninterlaced(di, sig, div);
++
++              vsync_cnt = 3;
++              if (di->id == 1)
++                      /*
++                       * TODO: change only for TVEv2, parallel display
++                       * uses pin 2 / 3
++                       */
++                      if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3))
++                              vsync_cnt = 6;
++      }
++
++      if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH)
++              di_gen |= ipu_di_gen_polarity(sig->hsync_pin);
++      if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH)
++              di_gen |= ipu_di_gen_polarity(sig->vsync_pin);
++
++      if (sig->clk_pol)
++              di_gen |= DI_GEN_POLARITY_DISP_CLK;
++
++      ipu_di_write(di, di_gen, DI_GENERAL);
++
++      ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
++                   DI_SYNC_AS_GEN);
++
++      reg = ipu_di_read(di, DI_POL);
++      reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
++
++      if (sig->enable_pol)
++              reg |= DI_POL_DRDY_POLARITY_15;
++      if (sig->data_pol)
++              reg |= DI_POL_DRDY_DATA_POLARITY;
++
++      ipu_di_write(di, reg, DI_POL);
++
++      mutex_unlock(&di_mutex);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
++
++int ipu_di_enable(struct ipu_di *di)
++{
++      int ret;
++
++      WARN_ON(IS_ERR(di->clk_di_pixel));
++
++      ret = clk_prepare_enable(di->clk_di_pixel);
++      if (ret)
++              return ret;
++
++      ipu_module_enable(di->ipu, di->module);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_di_enable);
++
++int ipu_di_disable(struct ipu_di *di)
++{
++      WARN_ON(IS_ERR(di->clk_di_pixel));
++
++      ipu_module_disable(di->ipu, di->module);
++
++      clk_disable_unprepare(di->clk_di_pixel);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_di_disable);
++
++int ipu_di_get_num(struct ipu_di *di)
++{
++      return di->id;
++}
++EXPORT_SYMBOL_GPL(ipu_di_get_num);
++
++static DEFINE_MUTEX(ipu_di_lock);
++
++struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp)
++{
++      struct ipu_di *di;
++
++      if (disp > 1)
++              return ERR_PTR(-EINVAL);
++
++      di = ipu->di_priv[disp];
++
++      mutex_lock(&ipu_di_lock);
++
++      if (di->inuse) {
++              di = ERR_PTR(-EBUSY);
++              goto out;
++      }
++
++      di->inuse = true;
++out:
++      mutex_unlock(&ipu_di_lock);
++
++      return di;
++}
++EXPORT_SYMBOL_GPL(ipu_di_get);
++
++void ipu_di_put(struct ipu_di *di)
++{
++      mutex_lock(&ipu_di_lock);
++
++      di->inuse = false;
++
++      mutex_unlock(&ipu_di_lock);
++}
++EXPORT_SYMBOL_GPL(ipu_di_put);
++
++int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
++              unsigned long base,
++              u32 module, struct clk *clk_ipu)
++{
++      struct ipu_di *di;
++
++      if (id > 1)
++              return -ENODEV;
++
++      di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
++      if (!di)
++              return -ENOMEM;
++
++      ipu->di_priv[id] = di;
++
++      di->clk_di = devm_clk_get(dev, id ? "di1" : "di0");
++      if (IS_ERR(di->clk_di))
++              return PTR_ERR(di->clk_di);
++
++      di->module = module;
++      di->id = id;
++      di->clk_ipu = clk_ipu;
++      di->base = devm_ioremap(dev, base, PAGE_SIZE);
++      if (!di->base)
++              return -ENOMEM;
++
++      ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
++
++      dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n",
++                      id, base, di->base);
++      di->inuse = false;
++      di->ipu = ipu;
++
++      return 0;
++}
++
++void ipu_di_exit(struct ipu_soc *ipu, int id)
++{
++}
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/ipu-dmfc.c
+@@ -0,0 +1,214 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++#include <linux/export.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/io.h>
++
++#include <video/imx-ipu-v3.h>
++#include "ipu-prv.h"
++
++#define DMFC_RD_CHAN          0x0000
++#define DMFC_WR_CHAN          0x0004
++#define DMFC_WR_CHAN_DEF      0x0008
++#define DMFC_DP_CHAN          0x000c
++#define DMFC_DP_CHAN_DEF      0x0010
++#define DMFC_GENERAL1         0x0014
++#define DMFC_GENERAL2         0x0018
++#define DMFC_IC_CTRL          0x001c
++#define DMFC_WR_CHAN_ALT      0x0020
++#define DMFC_WR_CHAN_DEF_ALT  0x0024
++#define DMFC_DP_CHAN_ALT      0x0028
++#define DMFC_DP_CHAN_DEF_ALT  0x002c
++#define DMFC_GENERAL1_ALT     0x0030
++#define DMFC_STAT             0x0034
++
++#define DMFC_WR_CHAN_1_28             0
++#define DMFC_WR_CHAN_2_41             8
++#define DMFC_WR_CHAN_1C_42            16
++#define DMFC_WR_CHAN_2C_43            24
++
++#define DMFC_DP_CHAN_5B_23            0
++#define DMFC_DP_CHAN_5F_27            8
++#define DMFC_DP_CHAN_6B_24            16
++#define DMFC_DP_CHAN_6F_29            24
++
++struct dmfc_channel_data {
++      int             ipu_channel;
++      unsigned long   channel_reg;
++      unsigned long   shift;
++      unsigned        eot_shift;
++      unsigned        max_fifo_lines;
++};
++
++static const struct dmfc_channel_data dmfcdata[] = {
++      {
++              .ipu_channel    = IPUV3_CHANNEL_MEM_BG_SYNC,
++              .channel_reg    = DMFC_DP_CHAN,
++              .shift          = DMFC_DP_CHAN_5B_23,
++              .eot_shift      = 20,
++              .max_fifo_lines = 3,
++      }, {
++              .ipu_channel    = 24,
++              .channel_reg    = DMFC_DP_CHAN,
++              .shift          = DMFC_DP_CHAN_6B_24,
++              .eot_shift      = 22,
++              .max_fifo_lines = 1,
++      }, {
++              .ipu_channel    = IPUV3_CHANNEL_MEM_FG_SYNC,
++              .channel_reg    = DMFC_DP_CHAN,
++              .shift          = DMFC_DP_CHAN_5F_27,
++              .eot_shift      = 21,
++              .max_fifo_lines = 2,
++      }, {
++              .ipu_channel    = IPUV3_CHANNEL_MEM_DC_SYNC,
++              .channel_reg    = DMFC_WR_CHAN,
++              .shift          = DMFC_WR_CHAN_1_28,
++              .eot_shift      = 16,
++              .max_fifo_lines = 2,
++      }, {
++              .ipu_channel    = 29,
++              .channel_reg    = DMFC_DP_CHAN,
++              .shift          = DMFC_DP_CHAN_6F_29,
++              .eot_shift      = 23,
++              .max_fifo_lines = 1,
++      },
++};
++
++#define DMFC_NUM_CHANNELS     ARRAY_SIZE(dmfcdata)
++
++struct ipu_dmfc_priv;
++
++struct dmfc_channel {
++      unsigned                        slots;
++      struct ipu_soc                  *ipu;
++      struct ipu_dmfc_priv            *priv;
++      const struct dmfc_channel_data  *data;
++};
++
++struct ipu_dmfc_priv {
++      struct ipu_soc *ipu;
++      struct device *dev;
++      struct dmfc_channel channels[DMFC_NUM_CHANNELS];
++      struct mutex mutex;
++      void __iomem *base;
++      int use_count;
++};
++
++int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
++{
++      struct ipu_dmfc_priv *priv = dmfc->priv;
++      mutex_lock(&priv->mutex);
++
++      if (!priv->use_count)
++              ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
++
++      priv->use_count++;
++
++      mutex_unlock(&priv->mutex);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
++
++void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
++{
++      struct ipu_dmfc_priv *priv = dmfc->priv;
++
++      mutex_lock(&priv->mutex);
++
++      priv->use_count--;
++
++      if (!priv->use_count)
++              ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
++
++      if (priv->use_count < 0)
++              priv->use_count = 0;
++
++      mutex_unlock(&priv->mutex);
++}
++EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
++
++void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width)
++{
++      struct ipu_dmfc_priv *priv = dmfc->priv;
++      u32 dmfc_gen1;
++
++      mutex_lock(&priv->mutex);
++
++      dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
++
++      if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
++              dmfc_gen1 |= 1 << dmfc->data->eot_shift;
++      else
++              dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
++
++      writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
++
++      mutex_unlock(&priv->mutex);
++}
++EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
++
++struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
++{
++      struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
++      int i;
++
++      for (i = 0; i < DMFC_NUM_CHANNELS; i++)
++              if (dmfcdata[i].ipu_channel == ipu_channel)
++                      return &priv->channels[i];
++      return ERR_PTR(-ENODEV);
++}
++EXPORT_SYMBOL_GPL(ipu_dmfc_get);
++
++void ipu_dmfc_put(struct dmfc_channel *dmfc)
++{
++}
++EXPORT_SYMBOL_GPL(ipu_dmfc_put);
++
++int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
++              struct clk *ipu_clk)
++{
++      struct ipu_dmfc_priv *priv;
++      int i;
++
++      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++
++      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
++      if (!priv->base)
++              return -ENOMEM;
++
++      priv->dev = dev;
++      priv->ipu = ipu;
++      mutex_init(&priv->mutex);
++
++      ipu->dmfc_priv = priv;
++
++      for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
++              priv->channels[i].priv = priv;
++              priv->channels[i].ipu = ipu;
++              priv->channels[i].data = &dmfcdata[i];
++
++              if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC ||
++                  dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC ||
++                  dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC)
++                      priv->channels[i].slots = 2;
++      }
++
++      writel(0x00000050, priv->base + DMFC_WR_CHAN);
++      writel(0x00005654, priv->base + DMFC_DP_CHAN);
++      writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
++      writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
++      writel(0x00000003, priv->base + DMFC_GENERAL1);
++
++      return 0;
++}
++
++void ipu_dmfc_exit(struct ipu_soc *ipu)
++{
++}
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/ipu-dp.c
+@@ -0,0 +1,357 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++#include <linux/export.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/io.h>
++#include <linux/err.h>
++
++#include <video/imx-ipu-v3.h>
++#include "ipu-prv.h"
++
++#define DP_SYNC 0
++#define DP_ASYNC0 0x60
++#define DP_ASYNC1 0xBC
++
++#define DP_COM_CONF           0x0
++#define DP_GRAPH_WIND_CTRL    0x0004
++#define DP_FG_POS             0x0008
++#define DP_CSC_A_0            0x0044
++#define DP_CSC_A_1            0x0048
++#define DP_CSC_A_2            0x004C
++#define DP_CSC_A_3            0x0050
++#define DP_CSC_0              0x0054
++#define DP_CSC_1              0x0058
++
++#define DP_COM_CONF_FG_EN             (1 << 0)
++#define DP_COM_CONF_GWSEL             (1 << 1)
++#define DP_COM_CONF_GWAM              (1 << 2)
++#define DP_COM_CONF_GWCKE             (1 << 3)
++#define DP_COM_CONF_CSC_DEF_MASK      (3 << 8)
++#define DP_COM_CONF_CSC_DEF_OFFSET    8
++#define DP_COM_CONF_CSC_DEF_FG                (3 << 8)
++#define DP_COM_CONF_CSC_DEF_BG                (2 << 8)
++#define DP_COM_CONF_CSC_DEF_BOTH      (1 << 8)
++
++#define IPUV3_NUM_FLOWS               3
++
++struct ipu_dp_priv;
++
++struct ipu_dp {
++      u32 flow;
++      bool in_use;
++      bool foreground;
++      enum ipu_color_space in_cs;
++};
++
++struct ipu_flow {
++      struct ipu_dp foreground;
++      struct ipu_dp background;
++      enum ipu_color_space out_cs;
++      void __iomem *base;
++      struct ipu_dp_priv *priv;
++};
++
++struct ipu_dp_priv {
++      struct ipu_soc *ipu;
++      struct device *dev;
++      void __iomem *base;
++      struct ipu_flow flow[IPUV3_NUM_FLOWS];
++      struct mutex mutex;
++      int use_count;
++};
++
++static u32 ipu_dp_flow_base[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1};
++
++static inline struct ipu_flow *to_flow(struct ipu_dp *dp)
++{
++      if (dp->foreground)
++              return container_of(dp, struct ipu_flow, foreground);
++      else
++              return container_of(dp, struct ipu_flow, background);
++}
++
++int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable,
++              u8 alpha, bool bg_chan)
++{
++      struct ipu_flow *flow = to_flow(dp);
++      struct ipu_dp_priv *priv = flow->priv;
++      u32 reg;
++
++      mutex_lock(&priv->mutex);
++
++      reg = readl(flow->base + DP_COM_CONF);
++      if (bg_chan)
++              reg &= ~DP_COM_CONF_GWSEL;
++      else
++              reg |= DP_COM_CONF_GWSEL;
++      writel(reg, flow->base + DP_COM_CONF);
++
++      if (enable) {
++              reg = readl(flow->base + DP_GRAPH_WIND_CTRL) & 0x00FFFFFFL;
++              writel(reg | ((u32) alpha << 24),
++                           flow->base + DP_GRAPH_WIND_CTRL);
++
++              reg = readl(flow->base + DP_COM_CONF);
++              writel(reg | DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
++      } else {
++              reg = readl(flow->base + DP_COM_CONF);
++              writel(reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
++      }
++
++      ipu_srm_dp_update(priv->ipu, true);
++
++      mutex_unlock(&priv->mutex);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha);
++
++int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
++{
++      struct ipu_flow *flow = to_flow(dp);
++      struct ipu_dp_priv *priv = flow->priv;
++
++      writel((x_pos << 16) | y_pos, flow->base + DP_FG_POS);
++
++      ipu_srm_dp_update(priv->ipu, true);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos);
++
++static void ipu_dp_csc_init(struct ipu_flow *flow,
++              enum ipu_color_space in,
++              enum ipu_color_space out,
++              u32 place)
++{
++      u32 reg;
++
++      reg = readl(flow->base + DP_COM_CONF);
++      reg &= ~DP_COM_CONF_CSC_DEF_MASK;
++
++      if (in == out) {
++              writel(reg, flow->base + DP_COM_CONF);
++              return;
++      }
++
++      if (in == IPUV3_COLORSPACE_RGB && out == IPUV3_COLORSPACE_YUV) {
++              writel(0x099 | (0x12d << 16), flow->base + DP_CSC_A_0);
++              writel(0x03a | (0x3a9 << 16), flow->base + DP_CSC_A_1);
++              writel(0x356 | (0x100 << 16), flow->base + DP_CSC_A_2);
++              writel(0x100 | (0x329 << 16), flow->base + DP_CSC_A_3);
++              writel(0x3d6 | (0x0000 << 16) | (2 << 30),
++                              flow->base + DP_CSC_0);
++              writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30),
++                              flow->base + DP_CSC_1);
++      } else {
++              writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0);
++              writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1);
++              writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2);
++              writel(0x095 | (0x0ff << 16), flow->base + DP_CSC_A_3);
++              writel(0x000 | (0x3e42 << 16) | (1 << 30),
++                              flow->base + DP_CSC_0);
++              writel(0x10a | (1 << 14) | (0x3dd6 << 16) | (1 << 30),
++                              flow->base + DP_CSC_1);
++      }
++
++      reg |= place;
++
++      writel(reg, flow->base + DP_COM_CONF);
++}
++
++int ipu_dp_setup_channel(struct ipu_dp *dp,
++              enum ipu_color_space in,
++              enum ipu_color_space out)
++{
++      struct ipu_flow *flow = to_flow(dp);
++      struct ipu_dp_priv *priv = flow->priv;
++
++      mutex_lock(&priv->mutex);
++
++      dp->in_cs = in;
++
++      if (!dp->foreground)
++              flow->out_cs = out;
++
++      if (flow->foreground.in_cs == flow->background.in_cs) {
++              /*
++               * foreground and background are of same colorspace, put
++               * colorspace converter after combining unit.
++               */
++              ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs,
++                              DP_COM_CONF_CSC_DEF_BOTH);
++      } else {
++              if (flow->foreground.in_cs == IPUV3_COLORSPACE_UNKNOWN ||
++                  flow->foreground.in_cs == flow->out_cs)
++                      /*
++                       * foreground identical to output, apply color
++                       * conversion on background
++                       */
++                      ipu_dp_csc_init(flow, flow->background.in_cs,
++                                      flow->out_cs, DP_COM_CONF_CSC_DEF_BG);
++              else
++                      ipu_dp_csc_init(flow, flow->foreground.in_cs,
++                                      flow->out_cs, DP_COM_CONF_CSC_DEF_FG);
++      }
++
++      ipu_srm_dp_update(priv->ipu, true);
++
++      mutex_unlock(&priv->mutex);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
++
++int ipu_dp_enable(struct ipu_soc *ipu)
++{
++      struct ipu_dp_priv *priv = ipu->dp_priv;
++
++      mutex_lock(&priv->mutex);
++
++      if (!priv->use_count)
++              ipu_module_enable(priv->ipu, IPU_CONF_DP_EN);
++
++      priv->use_count++;
++
++      mutex_unlock(&priv->mutex);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_dp_enable);
++
++int ipu_dp_enable_channel(struct ipu_dp *dp)
++{
++      struct ipu_flow *flow = to_flow(dp);
++      struct ipu_dp_priv *priv = flow->priv;
++      u32 reg;
++
++      if (!dp->foreground)
++              return 0;
++
++      mutex_lock(&priv->mutex);
++
++      reg = readl(flow->base + DP_COM_CONF);
++      reg |= DP_COM_CONF_FG_EN;
++      writel(reg, flow->base + DP_COM_CONF);
++
++      ipu_srm_dp_update(priv->ipu, true);
++
++      mutex_unlock(&priv->mutex);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
++
++void ipu_dp_disable_channel(struct ipu_dp *dp, bool sync)
++{
++      struct ipu_flow *flow = to_flow(dp);
++      struct ipu_dp_priv *priv = flow->priv;
++      u32 reg, csc;
++
++      dp->in_cs = IPUV3_COLORSPACE_UNKNOWN;
++
++      if (!dp->foreground)
++              return;
++
++      mutex_lock(&priv->mutex);
++
++      reg = readl(flow->base + DP_COM_CONF);
++      csc = reg & DP_COM_CONF_CSC_DEF_MASK;
++      reg &= ~DP_COM_CONF_CSC_DEF_MASK;
++      if (csc == DP_COM_CONF_CSC_DEF_BOTH || csc == DP_COM_CONF_CSC_DEF_BG)
++              reg |= DP_COM_CONF_CSC_DEF_BG;
++
++      reg &= ~DP_COM_CONF_FG_EN;
++      writel(reg, flow->base + DP_COM_CONF);
++
++      writel(0, flow->base + DP_FG_POS);
++      ipu_srm_dp_update(priv->ipu, sync);
++
++      mutex_unlock(&priv->mutex);
++}
++EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
++
++void ipu_dp_disable(struct ipu_soc *ipu)
++{
++      struct ipu_dp_priv *priv = ipu->dp_priv;
++
++      mutex_lock(&priv->mutex);
++
++      priv->use_count--;
++
++      if (!priv->use_count)
++              ipu_module_disable(priv->ipu, IPU_CONF_DP_EN);
++
++      if (priv->use_count < 0)
++              priv->use_count = 0;
++
++      mutex_unlock(&priv->mutex);
++}
++EXPORT_SYMBOL_GPL(ipu_dp_disable);
++
++struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
++{
++      struct ipu_dp_priv *priv = ipu->dp_priv;
++      struct ipu_dp *dp;
++
++      if ((flow >> 1) >= IPUV3_NUM_FLOWS)
++              return ERR_PTR(-EINVAL);
++
++      if (flow & 1)
++              dp = &priv->flow[flow >> 1].foreground;
++      else
++              dp = &priv->flow[flow >> 1].background;
++
++      if (dp->in_use)
++              return ERR_PTR(-EBUSY);
++
++      dp->in_use = true;
++
++      return dp;
++}
++EXPORT_SYMBOL_GPL(ipu_dp_get);
++
++void ipu_dp_put(struct ipu_dp *dp)
++{
++      dp->in_use = false;
++}
++EXPORT_SYMBOL_GPL(ipu_dp_put);
++
++int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
++{
++      struct ipu_dp_priv *priv;
++      int i;
++
++      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++      priv->dev = dev;
++      priv->ipu = ipu;
++
++      ipu->dp_priv = priv;
++
++      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
++      if (!priv->base)
++              return -ENOMEM;
++
++      mutex_init(&priv->mutex);
++
++      for (i = 0; i < IPUV3_NUM_FLOWS; i++) {
++              priv->flow[i].background.in_cs = IPUV3_COLORSPACE_UNKNOWN;
++              priv->flow[i].foreground.in_cs = IPUV3_COLORSPACE_UNKNOWN;
++              priv->flow[i].foreground.foreground = true;
++              priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
++              priv->flow[i].priv = priv;
++      }
++
++      return 0;
++}
++
++void ipu_dp_exit(struct ipu_soc *ipu)
++{
++}
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/ipu-ic.c
+@@ -0,0 +1,761 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (C) 2012-2014 Mentor Graphics Inc.
++ * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/spinlock.h>
++#include <linux/bitrev.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/sizes.h>
++#include "ipu-prv.h"
++
++/* IC Register Offsets */
++#define IC_CONF                 0x0000
++#define IC_PRP_ENC_RSC          0x0004
++#define IC_PRP_VF_RSC           0x0008
++#define IC_PP_RSC               0x000C
++#define IC_CMBP_1               0x0010
++#define IC_CMBP_2               0x0014
++#define IC_IDMAC_1              0x0018
++#define IC_IDMAC_2              0x001C
++#define IC_IDMAC_3              0x0020
++#define IC_IDMAC_4              0x0024
++
++/* IC Register Fields */
++#define IC_CONF_PRPENC_EN       (1 << 0)
++#define IC_CONF_PRPENC_CSC1     (1 << 1)
++#define IC_CONF_PRPENC_ROT_EN   (1 << 2)
++#define IC_CONF_PRPVF_EN        (1 << 8)
++#define IC_CONF_PRPVF_CSC1      (1 << 9)
++#define IC_CONF_PRPVF_CSC2      (1 << 10)
++#define IC_CONF_PRPVF_CMB       (1 << 11)
++#define IC_CONF_PRPVF_ROT_EN    (1 << 12)
++#define IC_CONF_PP_EN           (1 << 16)
++#define IC_CONF_PP_CSC1         (1 << 17)
++#define IC_CONF_PP_CSC2         (1 << 18)
++#define IC_CONF_PP_CMB          (1 << 19)
++#define IC_CONF_PP_ROT_EN       (1 << 20)
++#define IC_CONF_IC_GLB_LOC_A    (1 << 28)
++#define IC_CONF_KEY_COLOR_EN    (1 << 29)
++#define IC_CONF_RWS_EN          (1 << 30)
++#define IC_CONF_CSI_MEM_WR_EN   (1 << 31)
++
++#define IC_IDMAC_1_CB0_BURST_16         (1 << 0)
++#define IC_IDMAC_1_CB1_BURST_16         (1 << 1)
++#define IC_IDMAC_1_CB2_BURST_16         (1 << 2)
++#define IC_IDMAC_1_CB3_BURST_16         (1 << 3)
++#define IC_IDMAC_1_CB4_BURST_16         (1 << 4)
++#define IC_IDMAC_1_CB5_BURST_16         (1 << 5)
++#define IC_IDMAC_1_CB6_BURST_16         (1 << 6)
++#define IC_IDMAC_1_CB7_BURST_16         (1 << 7)
++#define IC_IDMAC_1_PRPENC_ROT_MASK      (0x7 << 11)
++#define IC_IDMAC_1_PRPENC_ROT_OFFSET    11
++#define IC_IDMAC_1_PRPVF_ROT_MASK       (0x7 << 14)
++#define IC_IDMAC_1_PRPVF_ROT_OFFSET     14
++#define IC_IDMAC_1_PP_ROT_MASK          (0x7 << 17)
++#define IC_IDMAC_1_PP_ROT_OFFSET        17
++#define IC_IDMAC_1_PP_FLIP_RS           (1 << 22)
++#define IC_IDMAC_1_PRPVF_FLIP_RS        (1 << 21)
++#define IC_IDMAC_1_PRPENC_FLIP_RS       (1 << 20)
++
++#define IC_IDMAC_2_PRPENC_HEIGHT_MASK   (0x3ff << 0)
++#define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0
++#define IC_IDMAC_2_PRPVF_HEIGHT_MASK    (0x3ff << 10)
++#define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET  10
++#define IC_IDMAC_2_PP_HEIGHT_MASK       (0x3ff << 20)
++#define IC_IDMAC_2_PP_HEIGHT_OFFSET     20
++
++#define IC_IDMAC_3_PRPENC_WIDTH_MASK    (0x3ff << 0)
++#define IC_IDMAC_3_PRPENC_WIDTH_OFFSET  0
++#define IC_IDMAC_3_PRPVF_WIDTH_MASK     (0x3ff << 10)
++#define IC_IDMAC_3_PRPVF_WIDTH_OFFSET   10
++#define IC_IDMAC_3_PP_WIDTH_MASK        (0x3ff << 20)
++#define IC_IDMAC_3_PP_WIDTH_OFFSET      20
++
++struct ic_task_regoffs {
++      u32 rsc;
++      u32 tpmem_csc[2];
++};
++
++struct ic_task_bitfields {
++      u32 ic_conf_en;
++      u32 ic_conf_rot_en;
++      u32 ic_conf_cmb_en;
++      u32 ic_conf_csc1_en;
++      u32 ic_conf_csc2_en;
++      u32 ic_cmb_galpha_bit;
++};
++
++static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
++      [IC_TASK_ENCODER] = {
++              .rsc = IC_PRP_ENC_RSC,
++              .tpmem_csc = {0x2008, 0},
++      },
++      [IC_TASK_VIEWFINDER] = {
++              .rsc = IC_PRP_VF_RSC,
++              .tpmem_csc = {0x4028, 0x4040},
++      },
++      [IC_TASK_POST_PROCESSOR] = {
++              .rsc = IC_PP_RSC,
++              .tpmem_csc = {0x6060, 0x6078},
++      },
++};
++
++static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = {
++      [IC_TASK_ENCODER] = {
++              .ic_conf_en = IC_CONF_PRPENC_EN,
++              .ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN,
++              .ic_conf_cmb_en = 0,    /* NA */
++              .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
++              .ic_conf_csc2_en = 0,   /* NA */
++              .ic_cmb_galpha_bit = 0, /* NA */
++      },
++      [IC_TASK_VIEWFINDER] = {
++              .ic_conf_en = IC_CONF_PRPVF_EN,
++              .ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN,
++              .ic_conf_cmb_en = IC_CONF_PRPVF_CMB,
++              .ic_conf_csc1_en = IC_CONF_PRPVF_CSC1,
++              .ic_conf_csc2_en = IC_CONF_PRPVF_CSC2,
++              .ic_cmb_galpha_bit = 0,
++      },
++      [IC_TASK_POST_PROCESSOR] = {
++              .ic_conf_en = IC_CONF_PP_EN,
++              .ic_conf_rot_en = IC_CONF_PP_ROT_EN,
++              .ic_conf_cmb_en = IC_CONF_PP_CMB,
++              .ic_conf_csc1_en = IC_CONF_PP_CSC1,
++              .ic_conf_csc2_en = IC_CONF_PP_CSC2,
++              .ic_cmb_galpha_bit = 8,
++      },
++};
++
++struct ipu_ic_priv;
++
++struct ipu_ic {
++      enum ipu_ic_task task;
++      const struct ic_task_regoffs *reg;
++      const struct ic_task_bitfields *bit;
++
++      struct ipu_ic_colorspace in_cs;
++      struct ipu_ic_colorspace g_in_cs;
++      struct ipu_ic_colorspace out_cs;
++
++      bool graphics;
++      bool rotation;
++      bool in_use;
++
++      struct ipu_ic_priv *priv;
++};
++
++struct ipu_ic_priv {
++      void __iomem *base;
++      void __iomem *tpmem_base;
++      spinlock_t lock;
++      struct ipu_soc *ipu;
++      int use_count;
++      int irt_use_count;
++      struct ipu_ic task[IC_NUM_TASKS];
++};
++
++static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset)
++{
++      return readl(ic->priv->base + offset);
++}
++
++static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset)
++{
++      writel(value, ic->priv->base + offset);
++}
++
++static int init_csc(struct ipu_ic *ic,
++                  const struct ipu_ic_csc *csc,
++                  int csc_index)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      u32 __iomem *base;
++      const u16 (*c)[3];
++      const u16 *a;
++      u32 param;
++
++      base = (u32 __iomem *)
++              (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
++
++      /* Cast to unsigned */
++      c = (const u16 (*)[3])csc->params.coeff;
++      a = (const u16 *)csc->params.offset;
++
++      param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) |
++              ((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff);
++      writel(param, base++);
++
++      param = ((a[0] & 0x1fe0) >> 5) | (csc->params.scale << 8) |
++              (csc->params.sat << 10);
++      writel(param, base++);
++
++      param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
++              ((c[1][0] & 0x1ff) << 9) | (c[2][0] & 0x1ff);
++      writel(param, base++);
++
++      param = ((a[1] & 0x1fe0) >> 5);
++      writel(param, base++);
++
++      param = ((a[2] & 0x1f) << 27) | ((c[0][2] & 0x1ff) << 18) |
++              ((c[1][2] & 0x1ff) << 9) | (c[2][1] & 0x1ff);
++      writel(param, base++);
++
++      param = ((a[2] & 0x1fe0) >> 5);
++      writel(param, base++);
++
++      return 0;
++}
++
++static int calc_resize_coeffs(struct ipu_ic *ic,
++                            u32 in_size, u32 out_size,
++                            u32 *resize_coeff,
++                            u32 *downsize_coeff)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      struct ipu_soc *ipu = priv->ipu;
++      u32 temp_size, temp_downsize;
++
++      /*
++       * Input size cannot be more than 4096, and output size cannot
++       * be more than 1024
++       */
++      if (in_size > 4096) {
++              dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
++              return -EINVAL;
++      }
++      if (out_size > 1024) {
++              dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
++              return -EINVAL;
++      }
++
++      /* Cannot downsize more than 4:1 */
++      if ((out_size << 2) < in_size) {
++              dev_err(ipu->dev, "Unsupported downsize\n");
++              return -EINVAL;
++      }
++
++      /* Compute downsizing coefficient */
++      temp_downsize = 0;
++      temp_size = in_size;
++      while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
++             (temp_downsize < 2)) {
++              temp_size >>= 1;
++              temp_downsize++;
++      }
++      *downsize_coeff = temp_downsize;
++
++      /*
++       * compute resizing coefficient using the following equation:
++       * resize_coeff = M * (SI - 1) / (SO - 1)
++       * where M = 2^13, SI = input size, SO = output size
++       */
++      *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
++      if (*resize_coeff >= 16384L) {
++              dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
++              *resize_coeff = 0x3FFF;
++      }
++
++      return 0;
++}
++
++void ipu_ic_task_enable(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      unsigned long flags;
++      u32 ic_conf;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      ic_conf = ipu_ic_read(ic, IC_CONF);
++
++      ic_conf |= ic->bit->ic_conf_en;
++
++      if (ic->rotation)
++              ic_conf |= ic->bit->ic_conf_rot_en;
++
++      if (ic->in_cs.cs != ic->out_cs.cs)
++              ic_conf |= ic->bit->ic_conf_csc1_en;
++
++      if (ic->graphics) {
++              ic_conf |= ic->bit->ic_conf_cmb_en;
++              ic_conf |= ic->bit->ic_conf_csc1_en;
++
++              if (ic->g_in_cs.cs != ic->out_cs.cs)
++                      ic_conf |= ic->bit->ic_conf_csc2_en;
++      }
++
++      ipu_ic_write(ic, ic_conf, IC_CONF);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_ic_task_enable);
++
++void ipu_ic_task_disable(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      unsigned long flags;
++      u32 ic_conf;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      ic_conf = ipu_ic_read(ic, IC_CONF);
++
++      ic_conf &= ~(ic->bit->ic_conf_en |
++                   ic->bit->ic_conf_csc1_en |
++                   ic->bit->ic_conf_rot_en);
++      if (ic->bit->ic_conf_csc2_en)
++              ic_conf &= ~ic->bit->ic_conf_csc2_en;
++      if (ic->bit->ic_conf_cmb_en)
++              ic_conf &= ~ic->bit->ic_conf_cmb_en;
++
++      ipu_ic_write(ic, ic_conf, IC_CONF);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
++
++int ipu_ic_task_graphics_init(struct ipu_ic *ic,
++                            const struct ipu_ic_colorspace *g_in_cs,
++                            bool galpha_en, u32 galpha,
++                            bool colorkey_en, u32 colorkey)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      struct ipu_ic_csc csc2;
++      unsigned long flags;
++      u32 reg, ic_conf;
++      int ret = 0;
++
++      if (ic->task == IC_TASK_ENCODER)
++              return -EINVAL;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      ic_conf = ipu_ic_read(ic, IC_CONF);
++
++      if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
++              struct ipu_ic_csc csc1;
++
++              ret = ipu_ic_calc_csc(&csc1,
++                                    V4L2_YCBCR_ENC_601,
++                                    V4L2_QUANTIZATION_FULL_RANGE,
++                                    IPUV3_COLORSPACE_RGB,
++                                    V4L2_YCBCR_ENC_601,
++                                    V4L2_QUANTIZATION_FULL_RANGE,
++                                    IPUV3_COLORSPACE_RGB);
++              if (ret)
++                      goto unlock;
++
++              /* need transparent CSC1 conversion */
++              ret = init_csc(ic, &csc1, 0);
++              if (ret)
++                      goto unlock;
++      }
++
++      ic->g_in_cs = *g_in_cs;
++      csc2.in_cs = ic->g_in_cs;
++      csc2.out_cs = ic->out_cs;
++
++      ret = __ipu_ic_calc_csc(&csc2);
++      if (ret)
++              goto unlock;
++
++      ret = init_csc(ic, &csc2, 1);
++      if (ret)
++              goto unlock;
++
++      if (galpha_en) {
++              ic_conf |= IC_CONF_IC_GLB_LOC_A;
++              reg = ipu_ic_read(ic, IC_CMBP_1);
++              reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit);
++              reg |= (galpha << ic->bit->ic_cmb_galpha_bit);
++              ipu_ic_write(ic, reg, IC_CMBP_1);
++      } else
++              ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
++
++      if (colorkey_en) {
++              ic_conf |= IC_CONF_KEY_COLOR_EN;
++              ipu_ic_write(ic, colorkey, IC_CMBP_2);
++      } else
++              ic_conf &= ~IC_CONF_KEY_COLOR_EN;
++
++      ipu_ic_write(ic, ic_conf, IC_CONF);
++
++      ic->graphics = true;
++unlock:
++      spin_unlock_irqrestore(&priv->lock, flags);
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
++
++int ipu_ic_task_init_rsc(struct ipu_ic *ic,
++                       const struct ipu_ic_csc *csc,
++                       int in_width, int in_height,
++                       int out_width, int out_height,
++                       u32 rsc)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      u32 downsize_coeff, resize_coeff;
++      unsigned long flags;
++      int ret = 0;
++
++      if (!rsc) {
++              /* Setup vertical resizing */
++
++              ret = calc_resize_coeffs(ic, in_height, out_height,
++                                       &resize_coeff, &downsize_coeff);
++              if (ret)
++                      return ret;
++
++              rsc = (downsize_coeff << 30) | (resize_coeff << 16);
++
++              /* Setup horizontal resizing */
++              ret = calc_resize_coeffs(ic, in_width, out_width,
++                                       &resize_coeff, &downsize_coeff);
++              if (ret)
++                      return ret;
++
++              rsc |= (downsize_coeff << 14) | resize_coeff;
++      }
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      ipu_ic_write(ic, rsc, ic->reg->rsc);
++
++      /* Setup color space conversion */
++      ic->in_cs = csc->in_cs;
++      ic->out_cs = csc->out_cs;
++
++      ret = init_csc(ic, csc, 0);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++      return ret;
++}
++
++int ipu_ic_task_init(struct ipu_ic *ic,
++                   const struct ipu_ic_csc *csc,
++                   int in_width, int in_height,
++                   int out_width, int out_height)
++{
++      return ipu_ic_task_init_rsc(ic, csc,
++                                  in_width, in_height,
++                                  out_width, out_height, 0);
++}
++EXPORT_SYMBOL_GPL(ipu_ic_task_init);
++
++int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
++                        u32 width, u32 height, int burst_size,
++                        enum ipu_rotate_mode rot)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      struct ipu_soc *ipu = priv->ipu;
++      u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
++      u32 temp_rot = bitrev8(rot) >> 5;
++      bool need_hor_flip = false;
++      unsigned long flags;
++      int ret = 0;
++
++      if ((burst_size != 8) && (burst_size != 16)) {
++              dev_err(ipu->dev, "Illegal burst length for IC\n");
++              return -EINVAL;
++      }
++
++      width--;
++      height--;
++
++      if (temp_rot & 0x2)     /* Need horizontal flip */
++              need_hor_flip = true;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1);
++      ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2);
++      ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3);
++
++      switch (channel->num) {
++      case IPUV3_CHANNEL_IC_PP_MEM:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
++
++              if (need_hor_flip)
++                      ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
++
++              ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
++              ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
++
++              ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
++              ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
++              break;
++      case IPUV3_CHANNEL_MEM_IC_PP:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
++              break;
++      case IPUV3_CHANNEL_MEM_ROT_PP:
++              ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
++              ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
++              break;
++      case IPUV3_CHANNEL_MEM_IC_PRP_VF:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
++              break;
++      case IPUV3_CHANNEL_IC_PRP_ENC_MEM:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
++
++              if (need_hor_flip)
++                      ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
++
++              ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
++              ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
++
++              ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
++              ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
++              break;
++      case IPUV3_CHANNEL_MEM_ROT_ENC:
++              ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
++              ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
++              break;
++      case IPUV3_CHANNEL_IC_PRP_VF_MEM:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
++
++              if (need_hor_flip)
++                      ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
++
++              ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
++              ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
++
++              ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
++              ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
++              break;
++      case IPUV3_CHANNEL_MEM_ROT_VF:
++              ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
++              ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
++              break;
++      case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
++              break;
++      case IPUV3_CHANNEL_G_MEM_IC_PP:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
++              break;
++      case IPUV3_CHANNEL_VDI_MEM_IC_VF:
++              if (burst_size == 16)
++                      ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
++              else
++                      ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
++              break;
++      default:
++              goto unlock;
++      }
++
++      ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1);
++      ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
++      ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
++
++      if (ipu_rot_mode_is_irt(rot))
++              ic->rotation = true;
++
++unlock:
++      spin_unlock_irqrestore(&priv->lock, flags);
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
++
++static void ipu_irt_enable(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++
++      if (!priv->irt_use_count)
++              ipu_module_enable(priv->ipu, IPU_CONF_ROT_EN);
++
++      priv->irt_use_count++;
++}
++
++static void ipu_irt_disable(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++
++      if (priv->irt_use_count) {
++              if (!--priv->irt_use_count)
++                      ipu_module_disable(priv->ipu, IPU_CONF_ROT_EN);
++      }
++}
++
++int ipu_ic_enable(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      unsigned long flags;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      if (!priv->use_count)
++              ipu_module_enable(priv->ipu, IPU_CONF_IC_EN);
++
++      priv->use_count++;
++
++      if (ic->rotation)
++              ipu_irt_enable(ic);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_ic_enable);
++
++int ipu_ic_disable(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      unsigned long flags;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      priv->use_count--;
++
++      if (!priv->use_count)
++              ipu_module_disable(priv->ipu, IPU_CONF_IC_EN);
++
++      if (priv->use_count < 0)
++              priv->use_count = 0;
++
++      if (ic->rotation)
++              ipu_irt_disable(ic);
++
++      ic->rotation = ic->graphics = false;
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_ic_disable);
++
++struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
++{
++      struct ipu_ic_priv *priv = ipu->ic_priv;
++      unsigned long flags;
++      struct ipu_ic *ic, *ret;
++
++      if (task >= IC_NUM_TASKS)
++              return ERR_PTR(-EINVAL);
++
++      ic = &priv->task[task];
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      if (ic->in_use) {
++              ret = ERR_PTR(-EBUSY);
++              goto unlock;
++      }
++
++      ic->in_use = true;
++      ret = ic;
++
++unlock:
++      spin_unlock_irqrestore(&priv->lock, flags);
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_ic_get);
++
++void ipu_ic_put(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      unsigned long flags;
++
++      spin_lock_irqsave(&priv->lock, flags);
++      ic->in_use = false;
++      spin_unlock_irqrestore(&priv->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_ic_put);
++
++int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
++              unsigned long base, unsigned long tpmem_base)
++{
++      struct ipu_ic_priv *priv;
++      int i;
++
++      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++
++      ipu->ic_priv = priv;
++
++      spin_lock_init(&priv->lock);
++      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
++      if (!priv->base)
++              return -ENOMEM;
++      priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K);
++      if (!priv->tpmem_base)
++              return -ENOMEM;
++
++      dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base);
++
++      priv->ipu = ipu;
++
++      for (i = 0; i < IC_NUM_TASKS; i++) {
++              priv->task[i].task = i;
++              priv->task[i].priv = priv;
++              priv->task[i].reg = &ic_task_reg[i];
++              priv->task[i].bit = &ic_task_bit[i];
++      }
++
++      return 0;
++}
++
++void ipu_ic_exit(struct ipu_soc *ipu)
++{
++}
++
++void ipu_ic_dump(struct ipu_ic *ic)
++{
++      struct ipu_ic_priv *priv = ic->priv;
++      struct ipu_soc *ipu = priv->ipu;
++
++      dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n",
++              ipu_ic_read(ic, IC_CONF));
++      dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n",
++              ipu_ic_read(ic, IC_PRP_ENC_RSC));
++      dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n",
++              ipu_ic_read(ic, IC_PRP_VF_RSC));
++      dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n",
++              ipu_ic_read(ic, IC_PP_RSC));
++      dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n",
++              ipu_ic_read(ic, IC_CMBP_1));
++      dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n",
++              ipu_ic_read(ic, IC_CMBP_2));
++      dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n",
++              ipu_ic_read(ic, IC_IDMAC_1));
++      dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n",
++              ipu_ic_read(ic, IC_IDMAC_2));
++      dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n",
++              ipu_ic_read(ic, IC_IDMAC_3));
++      dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n",
++              ipu_ic_read(ic, IC_IDMAC_4));
++}
++EXPORT_SYMBOL_GPL(ipu_ic_dump);
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/ipu-image-convert.c
+@@ -0,0 +1,2475 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (C) 2012-2016 Mentor Graphics Inc.
++ *
++ * Queued image conversion support, with tiling and rotation.
++ */
++
++#include <linux/interrupt.h>
++#include <linux/dma-mapping.h>
++#include <video/imx-ipu-image-convert.h>
++#include "ipu-prv.h"
++
++/*
++ * The IC Resizer has a restriction that the output frame from the
++ * resizer must be 1024 or less in both width (pixels) and height
++ * (lines).
++ *
++ * The image converter attempts to split up a conversion when
++ * the desired output (converted) frame resolution exceeds the
++ * IC resizer limit of 1024 in either dimension.
++ *
++ * If either dimension of the output frame exceeds the limit, the
++ * dimension is split into 1, 2, or 4 equal stripes, for a maximum
++ * of 4*4 or 16 tiles. A conversion is then carried out for each
++ * tile (but taking care to pass the full frame stride length to
++ * the DMA channel's parameter memory!). IDMA double-buffering is used
++ * to convert each tile back-to-back when possible (see note below
++ * when double_buffering boolean is set).
++ *
++ * Note that the input frame must be split up into the same number
++ * of tiles as the output frame:
++ *
++ *                       +---------+-----+
++ *   +-----+---+         |  A      | B   |
++ *   | A   | B |         |         |     |
++ *   +-----+---+   -->   +---------+-----+
++ *   | C   | D |         |  C      | D   |
++ *   +-----+---+         |         |     |
++ *                       +---------+-----+
++ *
++ * Clockwise 90° rotations are handled by first rescaling into a
++ * reusable temporary tile buffer and then rotating with the 8x8
++ * block rotator, writing to the correct destination:
++ *
++ *                                         +-----+-----+
++ *                                         |     |     |
++ *   +-----+---+         +---------+       | C   | A   |
++ *   | A   | B |         | A,B, |  |       |     |     |
++ *   +-----+---+   -->   | C,D  |  |  -->  |     |     |
++ *   | C   | D |         +---------+       +-----+-----+
++ *   +-----+---+                           | D   | B   |
++ *                                         |     |     |
++ *                                         +-----+-----+
++ *
++ * If the 8x8 block rotator is used, horizontal or vertical flipping
++ * is done during the rotation step, otherwise flipping is done
++ * during the scaling step.
++ * With rotation or flipping, tile order changes between input and
++ * output image. Tiles are numbered row major from top left to bottom
++ * right for both input and output image.
++ */
++
++#define MAX_STRIPES_W    4
++#define MAX_STRIPES_H    4
++#define MAX_TILES (MAX_STRIPES_W * MAX_STRIPES_H)
++
++#define MIN_W     16
++#define MIN_H     8
++#define MAX_W     4096
++#define MAX_H     4096
++
++enum ipu_image_convert_type {
++      IMAGE_CONVERT_IN = 0,
++      IMAGE_CONVERT_OUT,
++};
++
++struct ipu_image_convert_dma_buf {
++      void          *virt;
++      dma_addr_t    phys;
++      unsigned long len;
++};
++
++struct ipu_image_convert_dma_chan {
++      int in;
++      int out;
++      int rot_in;
++      int rot_out;
++      int vdi_in_p;
++      int vdi_in;
++      int vdi_in_n;
++};
++
++/* dimensions of one tile */
++struct ipu_image_tile {
++      u32 width;
++      u32 height;
++      u32 left;
++      u32 top;
++      /* size and strides are in bytes */
++      u32 size;
++      u32 stride;
++      u32 rot_stride;
++      /* start Y or packed offset of this tile */
++      u32 offset;
++      /* offset from start to tile in U plane, for planar formats */
++      u32 u_off;
++      /* offset from start to tile in V plane, for planar formats */
++      u32 v_off;
++};
++
++struct ipu_image_convert_image {
++      struct ipu_image base;
++      enum ipu_image_convert_type type;
++
++      const struct ipu_image_pixfmt *fmt;
++      unsigned int stride;
++
++      /* # of rows (horizontal stripes) if dest height is > 1024 */
++      unsigned int num_rows;
++      /* # of columns (vertical stripes) if dest width is > 1024 */
++      unsigned int num_cols;
++
++      struct ipu_image_tile tile[MAX_TILES];
++};
++
++struct ipu_image_pixfmt {
++      u32     fourcc;        /* V4L2 fourcc */
++      int     bpp;           /* total bpp */
++      int     uv_width_dec;  /* decimation in width for U/V planes */
++      int     uv_height_dec; /* decimation in height for U/V planes */
++      bool    planar;        /* planar format */
++      bool    uv_swapped;    /* U and V planes are swapped */
++      bool    uv_packed;     /* partial planar (U and V in same plane) */
++};
++
++struct ipu_image_convert_ctx;
++struct ipu_image_convert_chan;
++struct ipu_image_convert_priv;
++
++struct ipu_image_convert_ctx {
++      struct ipu_image_convert_chan *chan;
++
++      ipu_image_convert_cb_t complete;
++      void *complete_context;
++
++      /* Source/destination image data and rotation mode */
++      struct ipu_image_convert_image in;
++      struct ipu_image_convert_image out;
++      struct ipu_ic_csc csc;
++      enum ipu_rotate_mode rot_mode;
++      u32 downsize_coeff_h;
++      u32 downsize_coeff_v;
++      u32 image_resize_coeff_h;
++      u32 image_resize_coeff_v;
++      u32 resize_coeffs_h[MAX_STRIPES_W];
++      u32 resize_coeffs_v[MAX_STRIPES_H];
++
++      /* intermediate buffer for rotation */
++      struct ipu_image_convert_dma_buf rot_intermediate[2];
++
++      /* current buffer number for double buffering */
++      int cur_buf_num;
++
++      bool aborting;
++      struct completion aborted;
++
++      /* can we use double-buffering for this conversion operation? */
++      bool double_buffering;
++      /* num_rows * num_cols */
++      unsigned int num_tiles;
++      /* next tile to process */
++      unsigned int next_tile;
++      /* where to place converted tile in dest image */
++      unsigned int out_tile_map[MAX_TILES];
++
++      struct list_head list;
++};
++
++struct ipu_image_convert_chan {
++      struct ipu_image_convert_priv *priv;
++
++      enum ipu_ic_task ic_task;
++      const struct ipu_image_convert_dma_chan *dma_ch;
++
++      struct ipu_ic *ic;
++      struct ipuv3_channel *in_chan;
++      struct ipuv3_channel *out_chan;
++      struct ipuv3_channel *rotation_in_chan;
++      struct ipuv3_channel *rotation_out_chan;
++
++      /* the IPU end-of-frame irqs */
++      int out_eof_irq;
++      int rot_out_eof_irq;
++
++      spinlock_t irqlock;
++
++      /* list of convert contexts */
++      struct list_head ctx_list;
++      /* queue of conversion runs */
++      struct list_head pending_q;
++      /* queue of completed runs */
++      struct list_head done_q;
++
++      /* the current conversion run */
++      struct ipu_image_convert_run *current_run;
++};
++
++struct ipu_image_convert_priv {
++      struct ipu_image_convert_chan chan[IC_NUM_TASKS];
++      struct ipu_soc *ipu;
++};
++
++static const struct ipu_image_convert_dma_chan
++image_convert_dma_chan[IC_NUM_TASKS] = {
++      [IC_TASK_VIEWFINDER] = {
++              .in = IPUV3_CHANNEL_MEM_IC_PRP_VF,
++              .out = IPUV3_CHANNEL_IC_PRP_VF_MEM,
++              .rot_in = IPUV3_CHANNEL_MEM_ROT_VF,
++              .rot_out = IPUV3_CHANNEL_ROT_VF_MEM,
++              .vdi_in_p = IPUV3_CHANNEL_MEM_VDI_PREV,
++              .vdi_in = IPUV3_CHANNEL_MEM_VDI_CUR,
++              .vdi_in_n = IPUV3_CHANNEL_MEM_VDI_NEXT,
++      },
++      [IC_TASK_POST_PROCESSOR] = {
++              .in = IPUV3_CHANNEL_MEM_IC_PP,
++              .out = IPUV3_CHANNEL_IC_PP_MEM,
++              .rot_in = IPUV3_CHANNEL_MEM_ROT_PP,
++              .rot_out = IPUV3_CHANNEL_ROT_PP_MEM,
++      },
++};
++
++static const struct ipu_image_pixfmt image_convert_formats[] = {
++      {
++              .fourcc = V4L2_PIX_FMT_RGB565,
++              .bpp    = 16,
++      }, {
++              .fourcc = V4L2_PIX_FMT_RGB24,
++              .bpp    = 24,
++      }, {
++              .fourcc = V4L2_PIX_FMT_BGR24,
++              .bpp    = 24,
++      }, {
++              .fourcc = V4L2_PIX_FMT_RGB32,
++              .bpp    = 32,
++      }, {
++              .fourcc = V4L2_PIX_FMT_BGR32,
++              .bpp    = 32,
++      }, {
++              .fourcc = V4L2_PIX_FMT_XRGB32,
++              .bpp    = 32,
++      }, {
++              .fourcc = V4L2_PIX_FMT_XBGR32,
++              .bpp    = 32,
++      }, {
++              .fourcc = V4L2_PIX_FMT_BGRX32,
++              .bpp    = 32,
++      }, {
++              .fourcc = V4L2_PIX_FMT_RGBX32,
++              .bpp    = 32,
++      }, {
++              .fourcc = V4L2_PIX_FMT_YUYV,
++              .bpp    = 16,
++              .uv_width_dec = 2,
++              .uv_height_dec = 1,
++      }, {
++              .fourcc = V4L2_PIX_FMT_UYVY,
++              .bpp    = 16,
++              .uv_width_dec = 2,
++              .uv_height_dec = 1,
++      }, {
++              .fourcc = V4L2_PIX_FMT_YUV420,
++              .bpp    = 12,
++              .planar = true,
++              .uv_width_dec = 2,
++              .uv_height_dec = 2,
++      }, {
++              .fourcc = V4L2_PIX_FMT_YVU420,
++              .bpp    = 12,
++              .planar = true,
++              .uv_width_dec = 2,
++              .uv_height_dec = 2,
++              .uv_swapped = true,
++      }, {
++              .fourcc = V4L2_PIX_FMT_NV12,
++              .bpp    = 12,
++              .planar = true,
++              .uv_width_dec = 2,
++              .uv_height_dec = 2,
++              .uv_packed = true,
++      }, {
++              .fourcc = V4L2_PIX_FMT_YUV422P,
++              .bpp    = 16,
++              .planar = true,
++              .uv_width_dec = 2,
++              .uv_height_dec = 1,
++      }, {
++              .fourcc = V4L2_PIX_FMT_NV16,
++              .bpp    = 16,
++              .planar = true,
++              .uv_width_dec = 2,
++              .uv_height_dec = 1,
++              .uv_packed = true,
++      },
++};
++
++static const struct ipu_image_pixfmt *get_format(u32 fourcc)
++{
++      const struct ipu_image_pixfmt *ret = NULL;
++      unsigned int i;
++
++      for (i = 0; i < ARRAY_SIZE(image_convert_formats); i++) {
++              if (image_convert_formats[i].fourcc == fourcc) {
++                      ret = &image_convert_formats[i];
++                      break;
++              }
++      }
++
++      return ret;
++}
++
++static void dump_format(struct ipu_image_convert_ctx *ctx,
++                      struct ipu_image_convert_image *ic_image)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++
++      dev_dbg(priv->ipu->dev,
++              "task %u: ctx %p: %s format: %dx%d (%dx%d tiles), %c%c%c%c\n",
++              chan->ic_task, ctx,
++              ic_image->type == IMAGE_CONVERT_OUT ? "Output" : "Input",
++              ic_image->base.pix.width, ic_image->base.pix.height,
++              ic_image->num_cols, ic_image->num_rows,
++              ic_image->fmt->fourcc & 0xff,
++              (ic_image->fmt->fourcc >> 8) & 0xff,
++              (ic_image->fmt->fourcc >> 16) & 0xff,
++              (ic_image->fmt->fourcc >> 24) & 0xff);
++}
++
++int ipu_image_convert_enum_format(int index, u32 *fourcc)
++{
++      const struct ipu_image_pixfmt *fmt;
++
++      if (index >= (int)ARRAY_SIZE(image_convert_formats))
++              return -EINVAL;
++
++      /* Format found */
++      fmt = &image_convert_formats[index];
++      *fourcc = fmt->fourcc;
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_enum_format);
++
++static void free_dma_buf(struct ipu_image_convert_priv *priv,
++                       struct ipu_image_convert_dma_buf *buf)
++{
++      if (buf->virt)
++              dma_free_coherent(priv->ipu->dev,
++                                buf->len, buf->virt, buf->phys);
++      buf->virt = NULL;
++      buf->phys = 0;
++}
++
++static int alloc_dma_buf(struct ipu_image_convert_priv *priv,
++                       struct ipu_image_convert_dma_buf *buf,
++                       int size)
++{
++      buf->len = PAGE_ALIGN(size);
++      buf->virt = dma_alloc_coherent(priv->ipu->dev, buf->len, &buf->phys,
++                                     GFP_DMA | GFP_KERNEL);
++      if (!buf->virt) {
++              dev_err(priv->ipu->dev, "failed to alloc dma buffer\n");
++              return -ENOMEM;
++      }
++
++      return 0;
++}
++
++static inline int num_stripes(int dim)
++{
++      return (dim - 1) / 1024 + 1;
++}
++
++/*
++ * Calculate downsizing coefficients, which are the same for all tiles,
++ * and initial bilinear resizing coefficients, which are used to find the
++ * best seam positions.
++ * Also determine the number of tiles necessary to guarantee that no tile
++ * is larger than 1024 pixels in either dimension at the output and between
++ * IC downsizing and main processing sections.
++ */
++static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
++                                        struct ipu_image *in,
++                                        struct ipu_image *out)
++{
++      u32 downsized_width = in->rect.width;
++      u32 downsized_height = in->rect.height;
++      u32 downsize_coeff_v = 0;
++      u32 downsize_coeff_h = 0;
++      u32 resized_width = out->rect.width;
++      u32 resized_height = out->rect.height;
++      u32 resize_coeff_h;
++      u32 resize_coeff_v;
++      u32 cols;
++      u32 rows;
++
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              resized_width = out->rect.height;
++              resized_height = out->rect.width;
++      }
++
++      /* Do not let invalid input lead to an endless loop below */
++      if (WARN_ON(resized_width == 0 || resized_height == 0))
++              return -EINVAL;
++
++      while (downsized_width >= resized_width * 2) {
++              downsized_width >>= 1;
++              downsize_coeff_h++;
++      }
++
++      while (downsized_height >= resized_height * 2) {
++              downsized_height >>= 1;
++              downsize_coeff_v++;
++      }
++
++      /*
++       * Calculate the bilinear resizing coefficients that could be used if
++       * we were converting with a single tile. The bottom right output pixel
++       * should sample as close as possible to the bottom right input pixel
++       * out of the decimator, but not overshoot it:
++       */
++      resize_coeff_h = 8192 * (downsized_width - 1) / (resized_width - 1);
++      resize_coeff_v = 8192 * (downsized_height - 1) / (resized_height - 1);
++
++      /*
++       * Both the output of the IC downsizing section before being passed to
++       * the IC main processing section and the final output of the IC main
++       * processing section must be <= 1024 pixels in both dimensions.
++       */
++      cols = num_stripes(max_t(u32, downsized_width, resized_width));
++      rows = num_stripes(max_t(u32, downsized_height, resized_height));
++
++      dev_dbg(ctx->chan->priv->ipu->dev,
++              "%s: hscale: >>%u, *8192/%u vscale: >>%u, *8192/%u, %ux%u tiles\n",
++              __func__, downsize_coeff_h, resize_coeff_h, downsize_coeff_v,
++              resize_coeff_v, cols, rows);
++
++      if (downsize_coeff_h > 2 || downsize_coeff_v  > 2 ||
++          resize_coeff_h > 0x3fff || resize_coeff_v > 0x3fff)
++              return -EINVAL;
++
++      ctx->downsize_coeff_h = downsize_coeff_h;
++      ctx->downsize_coeff_v = downsize_coeff_v;
++      ctx->image_resize_coeff_h = resize_coeff_h;
++      ctx->image_resize_coeff_v = resize_coeff_v;
++      ctx->in.num_cols = cols;
++      ctx->in.num_rows = rows;
++
++      return 0;
++}
++
++#define round_closest(x, y) round_down((x) + (y)/2, (y))
++
++/*
++ * Find the best aligned seam position for the given column / row index.
++ * Rotation and image offsets are out of scope.
++ *
++ * @index: column / row index, used to calculate valid interval
++ * @in_edge: input right / bottom edge
++ * @out_edge: output right / bottom edge
++ * @in_align: input alignment, either horizontal 8-byte line start address
++ *            alignment, or pixel alignment due to image format
++ * @out_align: output alignment, either horizontal 8-byte line start address
++ *             alignment, or pixel alignment due to image format or rotator
++ *             block size
++ * @in_burst: horizontal input burst size in case of horizontal flip
++ * @out_burst: horizontal output burst size or rotator block size
++ * @downsize_coeff: downsizing section coefficient
++ * @resize_coeff: main processing section resizing coefficient
++ * @_in_seam: aligned input seam position return value
++ * @_out_seam: aligned output seam position return value
++ */
++static void find_best_seam(struct ipu_image_convert_ctx *ctx,
++                         unsigned int index,
++                         unsigned int in_edge,
++                         unsigned int out_edge,
++                         unsigned int in_align,
++                         unsigned int out_align,
++                         unsigned int in_burst,
++                         unsigned int out_burst,
++                         unsigned int downsize_coeff,
++                         unsigned int resize_coeff,
++                         u32 *_in_seam,
++                         u32 *_out_seam)
++{
++      struct device *dev = ctx->chan->priv->ipu->dev;
++      unsigned int out_pos;
++      /* Input / output seam position candidates */
++      unsigned int out_seam = 0;
++      unsigned int in_seam = 0;
++      unsigned int min_diff = UINT_MAX;
++      unsigned int out_start;
++      unsigned int out_end;
++      unsigned int in_start;
++      unsigned int in_end;
++
++      /* Start within 1024 pixels of the right / bottom edge */
++      out_start = max_t(int, index * out_align, out_edge - 1024);
++      /* End before having to add more columns to the left / rows above */
++      out_end = min_t(unsigned int, out_edge, index * 1024 + 1);
++
++      /*
++       * Limit input seam position to make sure that the downsized input tile
++       * to the right or bottom does not exceed 1024 pixels.
++       */
++      in_start = max_t(int, index * in_align,
++                       in_edge - (1024 << downsize_coeff));
++      in_end = min_t(unsigned int, in_edge,
++                     index * (1024 << downsize_coeff) + 1);
++
++      /*
++       * Output tiles must start at a multiple of 8 bytes horizontally and
++       * possibly at an even line horizontally depending on the pixel format.
++       * Only consider output aligned positions for the seam.
++       */
++      out_start = round_up(out_start, out_align);
++      for (out_pos = out_start; out_pos < out_end; out_pos += out_align) {
++              unsigned int in_pos;
++              unsigned int in_pos_aligned;
++              unsigned int in_pos_rounded;
++              unsigned int abs_diff;
++
++              /*
++               * Tiles in the right row / bottom column may not be allowed to
++               * overshoot horizontally / vertically. out_burst may be the
++               * actual DMA burst size, or the rotator block size.
++               */
++              if ((out_burst > 1) && (out_edge - out_pos) % out_burst)
++                      continue;
++
++              /*
++               * Input sample position, corresponding to out_pos, 19.13 fixed
++               * point.
++               */
++              in_pos = (out_pos * resize_coeff) << downsize_coeff;
++              /*
++               * The closest input sample position that we could actually
++               * start the input tile at, 19.13 fixed point.
++               */
++              in_pos_aligned = round_closest(in_pos, 8192U * in_align);
++              /* Convert 19.13 fixed point to integer */
++              in_pos_rounded = in_pos_aligned / 8192U;
++
++              if (in_pos_rounded < in_start)
++                      continue;
++              if (in_pos_rounded >= in_end)
++                      break;
++
++              if ((in_burst > 1) &&
++                  (in_edge - in_pos_rounded) % in_burst)
++                      continue;
++
++              if (in_pos < in_pos_aligned)
++                      abs_diff = in_pos_aligned - in_pos;
++              else
++                      abs_diff = in_pos - in_pos_aligned;
++
++              if (abs_diff < min_diff) {
++                      in_seam = in_pos_rounded;
++                      out_seam = out_pos;
++                      min_diff = abs_diff;
++              }
++      }
++
++      *_out_seam = out_seam;
++      *_in_seam = in_seam;
++
++      dev_dbg(dev, "%s: out_seam %u(%u) in [%u, %u], in_seam %u(%u) in [%u, %u] diff %u.%03u\n",
++              __func__, out_seam, out_align, out_start, out_end,
++              in_seam, in_align, in_start, in_end, min_diff / 8192,
++              DIV_ROUND_CLOSEST(min_diff % 8192 * 1000, 8192));
++}
++
++/*
++ * Tile left edges are required to be aligned to multiples of 8 bytes
++ * by the IDMAC.
++ */
++static inline u32 tile_left_align(const struct ipu_image_pixfmt *fmt)
++{
++      if (fmt->planar)
++              return fmt->uv_packed ? 8 : 8 * fmt->uv_width_dec;
++      else
++              return fmt->bpp == 32 ? 2 : fmt->bpp == 16 ? 4 : 8;
++}
++
++/*
++ * Tile top edge alignment is only limited by chroma subsampling.
++ */
++static inline u32 tile_top_align(const struct ipu_image_pixfmt *fmt)
++{
++      return fmt->uv_height_dec > 1 ? 2 : 1;
++}
++
++static inline u32 tile_width_align(enum ipu_image_convert_type type,
++                                 const struct ipu_image_pixfmt *fmt,
++                                 enum ipu_rotate_mode rot_mode)
++{
++      if (type == IMAGE_CONVERT_IN) {
++              /*
++               * The IC burst reads 8 pixels at a time. Reading beyond the
++               * end of the line is usually acceptable. Those pixels are
++               * ignored, unless the IC has to write the scaled line in
++               * reverse.
++               */
++              return (!ipu_rot_mode_is_irt(rot_mode) &&
++                      (rot_mode & IPU_ROT_BIT_HFLIP)) ? 8 : 2;
++      }
++
++      /*
++       * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
++       * formats to guarantee 8-byte aligned line start addresses in the
++       * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
++       * for all other formats.
++       */
++      return (ipu_rot_mode_is_irt(rot_mode) &&
++              fmt->planar && !fmt->uv_packed) ?
++              8 * fmt->uv_width_dec : 8;
++}
++
++static inline u32 tile_height_align(enum ipu_image_convert_type type,
++                                  const struct ipu_image_pixfmt *fmt,
++                                  enum ipu_rotate_mode rot_mode)
++{
++      if (type == IMAGE_CONVERT_IN || !ipu_rot_mode_is_irt(rot_mode))
++              return 2;
++
++      /*
++       * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
++       * formats to guarantee 8-byte aligned line start addresses in the
++       * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
++       * for all other formats.
++       */
++      return (fmt->planar && !fmt->uv_packed) ? 8 * fmt->uv_width_dec : 8;
++}
++
++/*
++ * Fill in left position and width and for all tiles in an input column, and
++ * for all corresponding output tiles. If the 90° rotator is used, the output
++ * tiles are in a row, and output tile top position and height are set.
++ */
++static void fill_tile_column(struct ipu_image_convert_ctx *ctx,
++                           unsigned int col,
++                           struct ipu_image_convert_image *in,
++                           unsigned int in_left, unsigned int in_width,
++                           struct ipu_image_convert_image *out,
++                           unsigned int out_left, unsigned int out_width)
++{
++      unsigned int row, tile_idx;
++      struct ipu_image_tile *in_tile, *out_tile;
++
++      for (row = 0; row < in->num_rows; row++) {
++              tile_idx = in->num_cols * row + col;
++              in_tile = &in->tile[tile_idx];
++              out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
++
++              in_tile->left = in_left;
++              in_tile->width = in_width;
++
++              if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++                      out_tile->top = out_left;
++                      out_tile->height = out_width;
++              } else {
++                      out_tile->left = out_left;
++                      out_tile->width = out_width;
++              }
++      }
++}
++
++/*
++ * Fill in top position and height and for all tiles in an input row, and
++ * for all corresponding output tiles. If the 90° rotator is used, the output
++ * tiles are in a column, and output tile left position and width are set.
++ */
++static void fill_tile_row(struct ipu_image_convert_ctx *ctx, unsigned int row,
++                        struct ipu_image_convert_image *in,
++                        unsigned int in_top, unsigned int in_height,
++                        struct ipu_image_convert_image *out,
++                        unsigned int out_top, unsigned int out_height)
++{
++      unsigned int col, tile_idx;
++      struct ipu_image_tile *in_tile, *out_tile;
++
++      for (col = 0; col < in->num_cols; col++) {
++              tile_idx = in->num_cols * row + col;
++              in_tile = &in->tile[tile_idx];
++              out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
++
++              in_tile->top = in_top;
++              in_tile->height = in_height;
++
++              if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++                      out_tile->left = out_top;
++                      out_tile->width = out_height;
++              } else {
++                      out_tile->top = out_top;
++                      out_tile->height = out_height;
++              }
++      }
++}
++
++/*
++ * Find the best horizontal and vertical seam positions to split into tiles.
++ * Minimize the fractional part of the input sampling position for the
++ * top / left pixels of each tile.
++ */
++static void find_seams(struct ipu_image_convert_ctx *ctx,
++                     struct ipu_image_convert_image *in,
++                     struct ipu_image_convert_image *out)
++{
++      struct device *dev = ctx->chan->priv->ipu->dev;
++      unsigned int resized_width = out->base.rect.width;
++      unsigned int resized_height = out->base.rect.height;
++      unsigned int col;
++      unsigned int row;
++      unsigned int in_left_align = tile_left_align(in->fmt);
++      unsigned int in_top_align = tile_top_align(in->fmt);
++      unsigned int out_left_align = tile_left_align(out->fmt);
++      unsigned int out_top_align = tile_top_align(out->fmt);
++      unsigned int out_width_align = tile_width_align(out->type, out->fmt,
++                                                      ctx->rot_mode);
++      unsigned int out_height_align = tile_height_align(out->type, out->fmt,
++                                                        ctx->rot_mode);
++      unsigned int in_right = in->base.rect.width;
++      unsigned int in_bottom = in->base.rect.height;
++      unsigned int out_right = out->base.rect.width;
++      unsigned int out_bottom = out->base.rect.height;
++      unsigned int flipped_out_left;
++      unsigned int flipped_out_top;
++
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              /* Switch width/height and align top left to IRT block size */
++              resized_width = out->base.rect.height;
++              resized_height = out->base.rect.width;
++              out_left_align = out_height_align;
++              out_top_align = out_width_align;
++              out_width_align = out_left_align;
++              out_height_align = out_top_align;
++              out_right = out->base.rect.height;
++              out_bottom = out->base.rect.width;
++      }
++
++      for (col = in->num_cols - 1; col > 0; col--) {
++              bool allow_in_overshoot = ipu_rot_mode_is_irt(ctx->rot_mode) ||
++                                        !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
++              bool allow_out_overshoot = (col < in->num_cols - 1) &&
++                                         !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
++              unsigned int in_left;
++              unsigned int out_left;
++
++              /*
++               * Align input width to burst length if the scaling step flips
++               * horizontally.
++               */
++
++              find_best_seam(ctx, col,
++                             in_right, out_right,
++                             in_left_align, out_left_align,
++                             allow_in_overshoot ? 1 : 8 /* burst length */,
++                             allow_out_overshoot ? 1 : out_width_align,
++                             ctx->downsize_coeff_h, ctx->image_resize_coeff_h,
++                             &in_left, &out_left);
++
++              if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
++                      flipped_out_left = resized_width - out_right;
++              else
++                      flipped_out_left = out_left;
++
++              fill_tile_column(ctx, col, in, in_left, in_right - in_left,
++                               out, flipped_out_left, out_right - out_left);
++
++              dev_dbg(dev, "%s: col %u: %u, %u -> %u, %u\n", __func__, col,
++                      in_left, in_right - in_left,
++                      flipped_out_left, out_right - out_left);
++
++              in_right = in_left;
++              out_right = out_left;
++      }
++
++      flipped_out_left = (ctx->rot_mode & IPU_ROT_BIT_HFLIP) ?
++                         resized_width - out_right : 0;
++
++      fill_tile_column(ctx, 0, in, 0, in_right,
++                       out, flipped_out_left, out_right);
++
++      dev_dbg(dev, "%s: col 0: 0, %u -> %u, %u\n", __func__,
++              in_right, flipped_out_left, out_right);
++
++      for (row = in->num_rows - 1; row > 0; row--) {
++              bool allow_overshoot = row < in->num_rows - 1;
++              unsigned int in_top;
++              unsigned int out_top;
++
++              find_best_seam(ctx, row,
++                             in_bottom, out_bottom,
++                             in_top_align, out_top_align,
++                             1, allow_overshoot ? 1 : out_height_align,
++                             ctx->downsize_coeff_v, ctx->image_resize_coeff_v,
++                             &in_top, &out_top);
++
++              if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
++                  ipu_rot_mode_is_irt(ctx->rot_mode))
++                      flipped_out_top = resized_height - out_bottom;
++              else
++                      flipped_out_top = out_top;
++
++              fill_tile_row(ctx, row, in, in_top, in_bottom - in_top,
++                            out, flipped_out_top, out_bottom - out_top);
++
++              dev_dbg(dev, "%s: row %u: %u, %u -> %u, %u\n", __func__, row,
++                      in_top, in_bottom - in_top,
++                      flipped_out_top, out_bottom - out_top);
++
++              in_bottom = in_top;
++              out_bottom = out_top;
++      }
++
++      if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
++          ipu_rot_mode_is_irt(ctx->rot_mode))
++              flipped_out_top = resized_height - out_bottom;
++      else
++              flipped_out_top = 0;
++
++      fill_tile_row(ctx, 0, in, 0, in_bottom,
++                    out, flipped_out_top, out_bottom);
++
++      dev_dbg(dev, "%s: row 0: 0, %u -> %u, %u\n", __func__,
++              in_bottom, flipped_out_top, out_bottom);
++}
++
++static int calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
++                              struct ipu_image_convert_image *image)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      unsigned int max_width = 1024;
++      unsigned int max_height = 1024;
++      unsigned int i;
++
++      if (image->type == IMAGE_CONVERT_IN) {
++              /* Up to 4096x4096 input tile size */
++              max_width <<= ctx->downsize_coeff_h;
++              max_height <<= ctx->downsize_coeff_v;
++      }
++
++      for (i = 0; i < ctx->num_tiles; i++) {
++              struct ipu_image_tile *tile;
++              const unsigned int row = i / image->num_cols;
++              const unsigned int col = i % image->num_cols;
++
++              if (image->type == IMAGE_CONVERT_OUT)
++                      tile = &image->tile[ctx->out_tile_map[i]];
++              else
++                      tile = &image->tile[i];
++
++              tile->size = ((tile->height * image->fmt->bpp) >> 3) *
++                      tile->width;
++
++              if (image->fmt->planar) {
++                      tile->stride = tile->width;
++                      tile->rot_stride = tile->height;
++              } else {
++                      tile->stride =
++                              (image->fmt->bpp * tile->width) >> 3;
++                      tile->rot_stride =
++                              (image->fmt->bpp * tile->height) >> 3;
++              }
++
++              dev_dbg(priv->ipu->dev,
++                      "task %u: ctx %p: %s@[%u,%u]: %ux%u@%u,%u\n",
++                      chan->ic_task, ctx,
++                      image->type == IMAGE_CONVERT_IN ? "Input" : "Output",
++                      row, col,
++                      tile->width, tile->height, tile->left, tile->top);
++
++              if (!tile->width || tile->width > max_width ||
++                  !tile->height || tile->height > max_height) {
++                      dev_err(priv->ipu->dev, "invalid %s tile size: %ux%u\n",
++                              image->type == IMAGE_CONVERT_IN ? "input" :
++                              "output", tile->width, tile->height);
++                      return -EINVAL;
++              }
++      }
++
++      return 0;
++}
++
++/*
++ * Use the rotation transformation to find the tile coordinates
++ * (row, col) of a tile in the destination frame that corresponds
++ * to the given tile coordinates of a source frame. The destination
++ * coordinate is then converted to a tile index.
++ */
++static int transform_tile_index(struct ipu_image_convert_ctx *ctx,
++                              int src_row, int src_col)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_convert_image *s_image = &ctx->in;
++      struct ipu_image_convert_image *d_image = &ctx->out;
++      int dst_row, dst_col;
++
++      /* with no rotation it's a 1:1 mapping */
++      if (ctx->rot_mode == IPU_ROTATE_NONE)
++              return src_row * s_image->num_cols + src_col;
++
++      /*
++       * before doing the transform, first we have to translate
++       * source row,col for an origin in the center of s_image
++       */
++      src_row = src_row * 2 - (s_image->num_rows - 1);
++      src_col = src_col * 2 - (s_image->num_cols - 1);
++
++      /* do the rotation transform */
++      if (ctx->rot_mode & IPU_ROT_BIT_90) {
++              dst_col = -src_row;
++              dst_row = src_col;
++      } else {
++              dst_col = src_col;
++              dst_row = src_row;
++      }
++
++      /* apply flip */
++      if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
++              dst_col = -dst_col;
++      if (ctx->rot_mode & IPU_ROT_BIT_VFLIP)
++              dst_row = -dst_row;
++
++      dev_dbg(priv->ipu->dev, "task %u: ctx %p: [%d,%d] --> [%d,%d]\n",
++              chan->ic_task, ctx, src_col, src_row, dst_col, dst_row);
++
++      /*
++       * finally translate dest row,col using an origin in upper
++       * left of d_image
++       */
++      dst_row += d_image->num_rows - 1;
++      dst_col += d_image->num_cols - 1;
++      dst_row /= 2;
++      dst_col /= 2;
++
++      return dst_row * d_image->num_cols + dst_col;
++}
++
++/*
++ * Fill the out_tile_map[] with transformed destination tile indeces.
++ */
++static void calc_out_tile_map(struct ipu_image_convert_ctx *ctx)
++{
++      struct ipu_image_convert_image *s_image = &ctx->in;
++      unsigned int row, col, tile = 0;
++
++      for (row = 0; row < s_image->num_rows; row++) {
++              for (col = 0; col < s_image->num_cols; col++) {
++                      ctx->out_tile_map[tile] =
++                              transform_tile_index(ctx, row, col);
++                      tile++;
++              }
++      }
++}
++
++static int calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
++                                  struct ipu_image_convert_image *image)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      const struct ipu_image_pixfmt *fmt = image->fmt;
++      unsigned int row, col, tile = 0;
++      u32 H, top, y_stride, uv_stride;
++      u32 uv_row_off, uv_col_off, uv_off, u_off, v_off, tmp;
++      u32 y_row_off, y_col_off, y_off;
++      u32 y_size, uv_size;
++
++      /* setup some convenience vars */
++      H = image->base.pix.height;
++
++      y_stride = image->stride;
++      uv_stride = y_stride / fmt->uv_width_dec;
++      if (fmt->uv_packed)
++              uv_stride *= 2;
++
++      y_size = H * y_stride;
++      uv_size = y_size / (fmt->uv_width_dec * fmt->uv_height_dec);
++
++      for (row = 0; row < image->num_rows; row++) {
++              top = image->tile[tile].top;
++              y_row_off = top * y_stride;
++              uv_row_off = (top * uv_stride) / fmt->uv_height_dec;
++
++              for (col = 0; col < image->num_cols; col++) {
++                      y_col_off = image->tile[tile].left;
++                      uv_col_off = y_col_off / fmt->uv_width_dec;
++                      if (fmt->uv_packed)
++                              uv_col_off *= 2;
++
++                      y_off = y_row_off + y_col_off;
++                      uv_off = uv_row_off + uv_col_off;
++
++                      u_off = y_size - y_off + uv_off;
++                      v_off = (fmt->uv_packed) ? 0 : u_off + uv_size;
++                      if (fmt->uv_swapped) {
++                              tmp = u_off;
++                              u_off = v_off;
++                              v_off = tmp;
++                      }
++
++                      image->tile[tile].offset = y_off;
++                      image->tile[tile].u_off = u_off;
++                      image->tile[tile++].v_off = v_off;
++
++                      if ((y_off & 0x7) || (u_off & 0x7) || (v_off & 0x7)) {
++                              dev_err(priv->ipu->dev,
++                                      "task %u: ctx %p: %s@[%d,%d]: "
++                                      "y_off %08x, u_off %08x, v_off %08x\n",
++                                      chan->ic_task, ctx,
++                                      image->type == IMAGE_CONVERT_IN ?
++                                      "Input" : "Output", row, col,
++                                      y_off, u_off, v_off);
++                              return -EINVAL;
++                      }
++              }
++      }
++
++      return 0;
++}
++
++static int calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
++                                  struct ipu_image_convert_image *image)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      const struct ipu_image_pixfmt *fmt = image->fmt;
++      unsigned int row, col, tile = 0;
++      u32 bpp, stride, offset;
++      u32 row_off, col_off;
++
++      /* setup some convenience vars */
++      stride = image->stride;
++      bpp = fmt->bpp;
++
++      for (row = 0; row < image->num_rows; row++) {
++              row_off = image->tile[tile].top * stride;
++
++              for (col = 0; col < image->num_cols; col++) {
++                      col_off = (image->tile[tile].left * bpp) >> 3;
++
++                      offset = row_off + col_off;
++
++                      image->tile[tile].offset = offset;
++                      image->tile[tile].u_off = 0;
++                      image->tile[tile++].v_off = 0;
++
++                      if (offset & 0x7) {
++                              dev_err(priv->ipu->dev,
++                                      "task %u: ctx %p: %s@[%d,%d]: "
++                                      "phys %08x\n",
++                                      chan->ic_task, ctx,
++                                      image->type == IMAGE_CONVERT_IN ?
++                                      "Input" : "Output", row, col,
++                                      row_off + col_off);
++                              return -EINVAL;
++                      }
++              }
++      }
++
++      return 0;
++}
++
++static int calc_tile_offsets(struct ipu_image_convert_ctx *ctx,
++                            struct ipu_image_convert_image *image)
++{
++      if (image->fmt->planar)
++              return calc_tile_offsets_planar(ctx, image);
++
++      return calc_tile_offsets_packed(ctx, image);
++}
++
++/*
++ * Calculate the resizing ratio for the IC main processing section given input
++ * size, fixed downsizing coefficient, and output size.
++ * Either round to closest for the next tile's first pixel to minimize seams
++ * and distortion (for all but right column / bottom row), or round down to
++ * avoid sampling beyond the edges of the input image for this tile's last
++ * pixel.
++ * Returns the resizing coefficient, resizing ratio is 8192.0 / resize_coeff.
++ */
++static u32 calc_resize_coeff(u32 input_size, u32 downsize_coeff,
++                           u32 output_size, bool allow_overshoot)
++{
++      u32 downsized = input_size >> downsize_coeff;
++
++      if (allow_overshoot)
++              return DIV_ROUND_CLOSEST(8192 * downsized, output_size);
++      else
++              return 8192 * (downsized - 1) / (output_size - 1);
++}
++
++/*
++ * Slightly modify resize coefficients per tile to hide the bilinear
++ * interpolator reset at tile borders, shifting the right / bottom edge
++ * by up to a half input pixel. This removes noticeable seams between
++ * tiles at higher upscaling factors.
++ */
++static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_tile *in_tile, *out_tile;
++      unsigned int col, row, tile_idx;
++      unsigned int last_output;
++
++      for (col = 0; col < ctx->in.num_cols; col++) {
++              bool closest = (col < ctx->in.num_cols - 1) &&
++                             !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
++              u32 resized_width;
++              u32 resize_coeff_h;
++              u32 in_width;
++
++              tile_idx = col;
++              in_tile = &ctx->in.tile[tile_idx];
++              out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
++
++              if (ipu_rot_mode_is_irt(ctx->rot_mode))
++                      resized_width = out_tile->height;
++              else
++                      resized_width = out_tile->width;
++
++              resize_coeff_h = calc_resize_coeff(in_tile->width,
++                                                 ctx->downsize_coeff_h,
++                                                 resized_width, closest);
++
++              dev_dbg(priv->ipu->dev, "%s: column %u hscale: *8192/%u\n",
++                      __func__, col, resize_coeff_h);
++
++              /*
++               * With the horizontal scaling factor known, round up resized
++               * width (output width or height) to burst size.
++               */
++              resized_width = round_up(resized_width, 8);
++
++              /*
++               * Calculate input width from the last accessed input pixel
++               * given resized width and scaling coefficients. Round up to
++               * burst size.
++               */
++              last_output = resized_width - 1;
++              if (closest && ((last_output * resize_coeff_h) % 8192))
++                      last_output++;
++              in_width = round_up(
++                      (DIV_ROUND_UP(last_output * resize_coeff_h, 8192) + 1)
++                      << ctx->downsize_coeff_h, 8);
++
++              for (row = 0; row < ctx->in.num_rows; row++) {
++                      tile_idx = row * ctx->in.num_cols + col;
++                      in_tile = &ctx->in.tile[tile_idx];
++                      out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
++
++                      if (ipu_rot_mode_is_irt(ctx->rot_mode))
++                              out_tile->height = resized_width;
++                      else
++                              out_tile->width = resized_width;
++
++                      in_tile->width = in_width;
++              }
++
++              ctx->resize_coeffs_h[col] = resize_coeff_h;
++      }
++
++      for (row = 0; row < ctx->in.num_rows; row++) {
++              bool closest = (row < ctx->in.num_rows - 1) &&
++                             !(ctx->rot_mode & IPU_ROT_BIT_VFLIP);
++              u32 resized_height;
++              u32 resize_coeff_v;
++              u32 in_height;
++
++              tile_idx = row * ctx->in.num_cols;
++              in_tile = &ctx->in.tile[tile_idx];
++              out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
++
++              if (ipu_rot_mode_is_irt(ctx->rot_mode))
++                      resized_height = out_tile->width;
++              else
++                      resized_height = out_tile->height;
++
++              resize_coeff_v = calc_resize_coeff(in_tile->height,
++                                                 ctx->downsize_coeff_v,
++                                                 resized_height, closest);
++
++              dev_dbg(priv->ipu->dev, "%s: row %u vscale: *8192/%u\n",
++                      __func__, row, resize_coeff_v);
++
++              /*
++               * With the vertical scaling factor known, round up resized
++               * height (output width or height) to IDMAC limitations.
++               */
++              resized_height = round_up(resized_height, 2);
++
++              /*
++               * Calculate input width from the last accessed input pixel
++               * given resized height and scaling coefficients. Align to
++               * IDMAC restrictions.
++               */
++              last_output = resized_height - 1;
++              if (closest && ((last_output * resize_coeff_v) % 8192))
++                      last_output++;
++              in_height = round_up(
++                      (DIV_ROUND_UP(last_output * resize_coeff_v, 8192) + 1)
++                      << ctx->downsize_coeff_v, 2);
++
++              for (col = 0; col < ctx->in.num_cols; col++) {
++                      tile_idx = row * ctx->in.num_cols + col;
++                      in_tile = &ctx->in.tile[tile_idx];
++                      out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
++
++                      if (ipu_rot_mode_is_irt(ctx->rot_mode))
++                              out_tile->width = resized_height;
++                      else
++                              out_tile->height = resized_height;
++
++                      in_tile->height = in_height;
++              }
++
++              ctx->resize_coeffs_v[row] = resize_coeff_v;
++      }
++}
++
++/*
++ * return the number of runs in given queue (pending_q or done_q)
++ * for this context. hold irqlock when calling.
++ */
++static int get_run_count(struct ipu_image_convert_ctx *ctx,
++                       struct list_head *q)
++{
++      struct ipu_image_convert_run *run;
++      int count = 0;
++
++      lockdep_assert_held(&ctx->chan->irqlock);
++
++      list_for_each_entry(run, q, list) {
++              if (run->ctx == ctx)
++                      count++;
++      }
++
++      return count;
++}
++
++static void convert_stop(struct ipu_image_convert_run *run)
++{
++      struct ipu_image_convert_ctx *ctx = run->ctx;
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++
++      dev_dbg(priv->ipu->dev, "%s: task %u: stopping ctx %p run %p\n",
++              __func__, chan->ic_task, ctx, run);
++
++      /* disable IC tasks and the channels */
++      ipu_ic_task_disable(chan->ic);
++      ipu_idmac_disable_channel(chan->in_chan);
++      ipu_idmac_disable_channel(chan->out_chan);
++
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              ipu_idmac_disable_channel(chan->rotation_in_chan);
++              ipu_idmac_disable_channel(chan->rotation_out_chan);
++              ipu_idmac_unlink(chan->out_chan, chan->rotation_in_chan);
++      }
++
++      ipu_ic_disable(chan->ic);
++}
++
++static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
++                             struct ipuv3_channel *channel,
++                             struct ipu_image_convert_image *image,
++                             enum ipu_rotate_mode rot_mode,
++                             bool rot_swap_width_height,
++                             unsigned int tile)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      unsigned int burst_size;
++      u32 width, height, stride;
++      dma_addr_t addr0, addr1 = 0;
++      struct ipu_image tile_image;
++      unsigned int tile_idx[2];
++
++      if (image->type == IMAGE_CONVERT_OUT) {
++              tile_idx[0] = ctx->out_tile_map[tile];
++              tile_idx[1] = ctx->out_tile_map[1];
++      } else {
++              tile_idx[0] = tile;
++              tile_idx[1] = 1;
++      }
++
++      if (rot_swap_width_height) {
++              width = image->tile[tile_idx[0]].height;
++              height = image->tile[tile_idx[0]].width;
++              stride = image->tile[tile_idx[0]].rot_stride;
++              addr0 = ctx->rot_intermediate[0].phys;
++              if (ctx->double_buffering)
++                      addr1 = ctx->rot_intermediate[1].phys;
++      } else {
++              width = image->tile[tile_idx[0]].width;
++              height = image->tile[tile_idx[0]].height;
++              stride = image->stride;
++              addr0 = image->base.phys0 +
++                      image->tile[tile_idx[0]].offset;
++              if (ctx->double_buffering)
++                      addr1 = image->base.phys0 +
++                              image->tile[tile_idx[1]].offset;
++      }
++
++      ipu_cpmem_zero(channel);
++
++      memset(&tile_image, 0, sizeof(tile_image));
++      tile_image.pix.width = tile_image.rect.width = width;
++      tile_image.pix.height = tile_image.rect.height = height;
++      tile_image.pix.bytesperline = stride;
++      tile_image.pix.pixelformat =  image->fmt->fourcc;
++      tile_image.phys0 = addr0;
++      tile_image.phys1 = addr1;
++      if (image->fmt->planar && !rot_swap_width_height) {
++              tile_image.u_offset = image->tile[tile_idx[0]].u_off;
++              tile_image.v_offset = image->tile[tile_idx[0]].v_off;
++      }
++
++      ipu_cpmem_set_image(channel, &tile_image);
++
++      if (rot_mode)
++              ipu_cpmem_set_rotation(channel, rot_mode);
++
++      /*
++       * Skip writing U and V components to odd rows in the output
++       * channels for planar 4:2:0.
++       */
++      if ((channel == chan->out_chan ||
++           channel == chan->rotation_out_chan) &&
++          image->fmt->planar && image->fmt->uv_height_dec == 2)
++              ipu_cpmem_skip_odd_chroma_rows(channel);
++
++      if (channel == chan->rotation_in_chan ||
++          channel == chan->rotation_out_chan) {
++              burst_size = 8;
++              ipu_cpmem_set_block_mode(channel);
++      } else
++              burst_size = (width % 16) ? 8 : 16;
++
++      ipu_cpmem_set_burstsize(channel, burst_size);
++
++      ipu_ic_task_idma_init(chan->ic, channel, width, height,
++                            burst_size, rot_mode);
++
++      /*
++       * Setting a non-zero AXI ID collides with the PRG AXI snooping, so
++       * only do this when there is no PRG present.
++       */
++      if (!channel->ipu->prg_priv)
++              ipu_cpmem_set_axi_id(channel, 1);
++
++      ipu_idmac_set_double_buffer(channel, ctx->double_buffering);
++}
++
++static int convert_start(struct ipu_image_convert_run *run, unsigned int tile)
++{
++      struct ipu_image_convert_ctx *ctx = run->ctx;
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_convert_image *s_image = &ctx->in;
++      struct ipu_image_convert_image *d_image = &ctx->out;
++      unsigned int dst_tile = ctx->out_tile_map[tile];
++      unsigned int dest_width, dest_height;
++      unsigned int col, row;
++      u32 rsc;
++      int ret;
++
++      dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n",
++              __func__, chan->ic_task, ctx, run, tile, dst_tile);
++
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              /* swap width/height for resizer */
++              dest_width = d_image->tile[dst_tile].height;
++              dest_height = d_image->tile[dst_tile].width;
++      } else {
++              dest_width = d_image->tile[dst_tile].width;
++              dest_height = d_image->tile[dst_tile].height;
++      }
++
++      row = tile / s_image->num_cols;
++      col = tile % s_image->num_cols;
++
++      rsc =  (ctx->downsize_coeff_v << 30) |
++             (ctx->resize_coeffs_v[row] << 16) |
++             (ctx->downsize_coeff_h << 14) |
++             (ctx->resize_coeffs_h[col]);
++
++      dev_dbg(priv->ipu->dev, "%s: %ux%u -> %ux%u (rsc = 0x%x)\n",
++              __func__, s_image->tile[tile].width,
++              s_image->tile[tile].height, dest_width, dest_height, rsc);
++
++      /* setup the IC resizer and CSC */
++      ret = ipu_ic_task_init_rsc(chan->ic, &ctx->csc,
++                                 s_image->tile[tile].width,
++                                 s_image->tile[tile].height,
++                                 dest_width,
++                                 dest_height,
++                                 rsc);
++      if (ret) {
++              dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret);
++              return ret;
++      }
++
++      /* init the source MEM-->IC PP IDMAC channel */
++      init_idmac_channel(ctx, chan->in_chan, s_image,
++                         IPU_ROTATE_NONE, false, tile);
++
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              /* init the IC PP-->MEM IDMAC channel */
++              init_idmac_channel(ctx, chan->out_chan, d_image,
++                                 IPU_ROTATE_NONE, true, tile);
++
++              /* init the MEM-->IC PP ROT IDMAC channel */
++              init_idmac_channel(ctx, chan->rotation_in_chan, d_image,
++                                 ctx->rot_mode, true, tile);
++
++              /* init the destination IC PP ROT-->MEM IDMAC channel */
++              init_idmac_channel(ctx, chan->rotation_out_chan, d_image,
++                                 IPU_ROTATE_NONE, false, tile);
++
++              /* now link IC PP-->MEM to MEM-->IC PP ROT */
++              ipu_idmac_link(chan->out_chan, chan->rotation_in_chan);
++      } else {
++              /* init the destination IC PP-->MEM IDMAC channel */
++              init_idmac_channel(ctx, chan->out_chan, d_image,
++                                 ctx->rot_mode, false, tile);
++      }
++
++      /* enable the IC */
++      ipu_ic_enable(chan->ic);
++
++      /* set buffers ready */
++      ipu_idmac_select_buffer(chan->in_chan, 0);
++      ipu_idmac_select_buffer(chan->out_chan, 0);
++      if (ipu_rot_mode_is_irt(ctx->rot_mode))
++              ipu_idmac_select_buffer(chan->rotation_out_chan, 0);
++      if (ctx->double_buffering) {
++              ipu_idmac_select_buffer(chan->in_chan, 1);
++              ipu_idmac_select_buffer(chan->out_chan, 1);
++              if (ipu_rot_mode_is_irt(ctx->rot_mode))
++                      ipu_idmac_select_buffer(chan->rotation_out_chan, 1);
++      }
++
++      /* enable the channels! */
++      ipu_idmac_enable_channel(chan->in_chan);
++      ipu_idmac_enable_channel(chan->out_chan);
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              ipu_idmac_enable_channel(chan->rotation_in_chan);
++              ipu_idmac_enable_channel(chan->rotation_out_chan);
++      }
++
++      ipu_ic_task_enable(chan->ic);
++
++      ipu_cpmem_dump(chan->in_chan);
++      ipu_cpmem_dump(chan->out_chan);
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              ipu_cpmem_dump(chan->rotation_in_chan);
++              ipu_cpmem_dump(chan->rotation_out_chan);
++      }
++
++      ipu_dump(priv->ipu);
++
++      return 0;
++}
++
++/* hold irqlock when calling */
++static int do_run(struct ipu_image_convert_run *run)
++{
++      struct ipu_image_convert_ctx *ctx = run->ctx;
++      struct ipu_image_convert_chan *chan = ctx->chan;
++
++      lockdep_assert_held(&chan->irqlock);
++
++      ctx->in.base.phys0 = run->in_phys;
++      ctx->out.base.phys0 = run->out_phys;
++
++      ctx->cur_buf_num = 0;
++      ctx->next_tile = 1;
++
++      /* remove run from pending_q and set as current */
++      list_del(&run->list);
++      chan->current_run = run;
++
++      return convert_start(run, 0);
++}
++
++/* hold irqlock when calling */
++static void run_next(struct ipu_image_convert_chan *chan)
++{
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_convert_run *run, *tmp;
++      int ret;
++
++      lockdep_assert_held(&chan->irqlock);
++
++      list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
++              /* skip contexts that are aborting */
++              if (run->ctx->aborting) {
++                      dev_dbg(priv->ipu->dev,
++                              "%s: task %u: skipping aborting ctx %p run %p\n",
++                              __func__, chan->ic_task, run->ctx, run);
++                      continue;
++              }
++
++              ret = do_run(run);
++              if (!ret)
++                      break;
++
++              /*
++               * something went wrong with start, add the run
++               * to done q and continue to the next run in the
++               * pending q.
++               */
++              run->status = ret;
++              list_add_tail(&run->list, &chan->done_q);
++              chan->current_run = NULL;
++      }
++}
++
++static void empty_done_q(struct ipu_image_convert_chan *chan)
++{
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_convert_run *run;
++      unsigned long flags;
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      while (!list_empty(&chan->done_q)) {
++              run = list_entry(chan->done_q.next,
++                               struct ipu_image_convert_run,
++                               list);
++
++              list_del(&run->list);
++
++              dev_dbg(priv->ipu->dev,
++                      "%s: task %u: completing ctx %p run %p with %d\n",
++                      __func__, chan->ic_task, run->ctx, run, run->status);
++
++              /* call the completion callback and free the run */
++              spin_unlock_irqrestore(&chan->irqlock, flags);
++              run->ctx->complete(run, run->ctx->complete_context);
++              spin_lock_irqsave(&chan->irqlock, flags);
++      }
++
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++}
++
++/*
++ * the bottom half thread clears out the done_q, calling the
++ * completion handler for each.
++ */
++static irqreturn_t do_bh(int irq, void *dev_id)
++{
++      struct ipu_image_convert_chan *chan = dev_id;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_convert_ctx *ctx;
++      unsigned long flags;
++
++      dev_dbg(priv->ipu->dev, "%s: task %u: enter\n", __func__,
++              chan->ic_task);
++
++      empty_done_q(chan);
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      /*
++       * the done_q is cleared out, signal any contexts
++       * that are aborting that abort can complete.
++       */
++      list_for_each_entry(ctx, &chan->ctx_list, list) {
++              if (ctx->aborting) {
++                      dev_dbg(priv->ipu->dev,
++                              "%s: task %u: signaling abort for ctx %p\n",
++                              __func__, chan->ic_task, ctx);
++                      complete_all(&ctx->aborted);
++              }
++      }
++
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++
++      dev_dbg(priv->ipu->dev, "%s: task %u: exit\n", __func__,
++              chan->ic_task);
++
++      return IRQ_HANDLED;
++}
++
++static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx)
++{
++      unsigned int cur_tile = ctx->next_tile - 1;
++      unsigned int next_tile = ctx->next_tile;
++
++      if (ctx->resize_coeffs_h[cur_tile % ctx->in.num_cols] !=
++          ctx->resize_coeffs_h[next_tile % ctx->in.num_cols] ||
++          ctx->resize_coeffs_v[cur_tile / ctx->in.num_cols] !=
++          ctx->resize_coeffs_v[next_tile / ctx->in.num_cols] ||
++          ctx->in.tile[cur_tile].width != ctx->in.tile[next_tile].width ||
++          ctx->in.tile[cur_tile].height != ctx->in.tile[next_tile].height ||
++          ctx->out.tile[cur_tile].width != ctx->out.tile[next_tile].width ||
++          ctx->out.tile[cur_tile].height != ctx->out.tile[next_tile].height)
++              return true;
++
++      return false;
++}
++
++/* hold irqlock when calling */
++static irqreturn_t do_irq(struct ipu_image_convert_run *run)
++{
++      struct ipu_image_convert_ctx *ctx = run->ctx;
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_tile *src_tile, *dst_tile;
++      struct ipu_image_convert_image *s_image = &ctx->in;
++      struct ipu_image_convert_image *d_image = &ctx->out;
++      struct ipuv3_channel *outch;
++      unsigned int dst_idx;
++
++      lockdep_assert_held(&chan->irqlock);
++
++      outch = ipu_rot_mode_is_irt(ctx->rot_mode) ?
++              chan->rotation_out_chan : chan->out_chan;
++
++      /*
++       * It is difficult to stop the channel DMA before the channels
++       * enter the paused state. Without double-buffering the channels
++       * are always in a paused state when the EOF irq occurs, so it
++       * is safe to stop the channels now. For double-buffering we
++       * just ignore the abort until the operation completes, when it
++       * is safe to shut down.
++       */
++      if (ctx->aborting && !ctx->double_buffering) {
++              convert_stop(run);
++              run->status = -EIO;
++              goto done;
++      }
++
++      if (ctx->next_tile == ctx->num_tiles) {
++              /*
++               * the conversion is complete
++               */
++              convert_stop(run);
++              run->status = 0;
++              goto done;
++      }
++
++      /*
++       * not done, place the next tile buffers.
++       */
++      if (!ctx->double_buffering) {
++              if (ic_settings_changed(ctx)) {
++                      convert_stop(run);
++                      convert_start(run, ctx->next_tile);
++              } else {
++                      src_tile = &s_image->tile[ctx->next_tile];
++                      dst_idx = ctx->out_tile_map[ctx->next_tile];
++                      dst_tile = &d_image->tile[dst_idx];
++
++                      ipu_cpmem_set_buffer(chan->in_chan, 0,
++                                           s_image->base.phys0 +
++                                           src_tile->offset);
++                      ipu_cpmem_set_buffer(outch, 0,
++                                           d_image->base.phys0 +
++                                           dst_tile->offset);
++                      if (s_image->fmt->planar)
++                              ipu_cpmem_set_uv_offset(chan->in_chan,
++                                                      src_tile->u_off,
++                                                      src_tile->v_off);
++                      if (d_image->fmt->planar)
++                              ipu_cpmem_set_uv_offset(outch,
++                                                      dst_tile->u_off,
++                                                      dst_tile->v_off);
++
++                      ipu_idmac_select_buffer(chan->in_chan, 0);
++                      ipu_idmac_select_buffer(outch, 0);
++              }
++      } else if (ctx->next_tile < ctx->num_tiles - 1) {
++
++              src_tile = &s_image->tile[ctx->next_tile + 1];
++              dst_idx = ctx->out_tile_map[ctx->next_tile + 1];
++              dst_tile = &d_image->tile[dst_idx];
++
++              ipu_cpmem_set_buffer(chan->in_chan, ctx->cur_buf_num,
++                                   s_image->base.phys0 + src_tile->offset);
++              ipu_cpmem_set_buffer(outch, ctx->cur_buf_num,
++                                   d_image->base.phys0 + dst_tile->offset);
++
++              ipu_idmac_select_buffer(chan->in_chan, ctx->cur_buf_num);
++              ipu_idmac_select_buffer(outch, ctx->cur_buf_num);
++
++              ctx->cur_buf_num ^= 1;
++      }
++
++      ctx->next_tile++;
++      return IRQ_HANDLED;
++done:
++      list_add_tail(&run->list, &chan->done_q);
++      chan->current_run = NULL;
++      run_next(chan);
++      return IRQ_WAKE_THREAD;
++}
++
++static irqreturn_t norotate_irq(int irq, void *data)
++{
++      struct ipu_image_convert_chan *chan = data;
++      struct ipu_image_convert_ctx *ctx;
++      struct ipu_image_convert_run *run;
++      unsigned long flags;
++      irqreturn_t ret;
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      /* get current run and its context */
++      run = chan->current_run;
++      if (!run) {
++              ret = IRQ_NONE;
++              goto out;
++      }
++
++      ctx = run->ctx;
++
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              /* this is a rotation operation, just ignore */
++              spin_unlock_irqrestore(&chan->irqlock, flags);
++              return IRQ_HANDLED;
++      }
++
++      ret = do_irq(run);
++out:
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++      return ret;
++}
++
++static irqreturn_t rotate_irq(int irq, void *data)
++{
++      struct ipu_image_convert_chan *chan = data;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_convert_ctx *ctx;
++      struct ipu_image_convert_run *run;
++      unsigned long flags;
++      irqreturn_t ret;
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      /* get current run and its context */
++      run = chan->current_run;
++      if (!run) {
++              ret = IRQ_NONE;
++              goto out;
++      }
++
++      ctx = run->ctx;
++
++      if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              /* this was NOT a rotation operation, shouldn't happen */
++              dev_err(priv->ipu->dev, "Unexpected rotation interrupt\n");
++              spin_unlock_irqrestore(&chan->irqlock, flags);
++              return IRQ_HANDLED;
++      }
++
++      ret = do_irq(run);
++out:
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++      return ret;
++}
++
++/*
++ * try to force the completion of runs for this ctx. Called when
++ * abort wait times out in ipu_image_convert_abort().
++ */
++static void force_abort(struct ipu_image_convert_ctx *ctx)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_run *run;
++      unsigned long flags;
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      run = chan->current_run;
++      if (run && run->ctx == ctx) {
++              convert_stop(run);
++              run->status = -EIO;
++              list_add_tail(&run->list, &chan->done_q);
++              chan->current_run = NULL;
++              run_next(chan);
++      }
++
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++
++      empty_done_q(chan);
++}
++
++static void release_ipu_resources(struct ipu_image_convert_chan *chan)
++{
++      if (chan->out_eof_irq >= 0)
++              free_irq(chan->out_eof_irq, chan);
++      if (chan->rot_out_eof_irq >= 0)
++              free_irq(chan->rot_out_eof_irq, chan);
++
++      if (!IS_ERR_OR_NULL(chan->in_chan))
++              ipu_idmac_put(chan->in_chan);
++      if (!IS_ERR_OR_NULL(chan->out_chan))
++              ipu_idmac_put(chan->out_chan);
++      if (!IS_ERR_OR_NULL(chan->rotation_in_chan))
++              ipu_idmac_put(chan->rotation_in_chan);
++      if (!IS_ERR_OR_NULL(chan->rotation_out_chan))
++              ipu_idmac_put(chan->rotation_out_chan);
++      if (!IS_ERR_OR_NULL(chan->ic))
++              ipu_ic_put(chan->ic);
++
++      chan->in_chan = chan->out_chan = chan->rotation_in_chan =
++              chan->rotation_out_chan = NULL;
++      chan->out_eof_irq = chan->rot_out_eof_irq = -1;
++}
++
++static int get_ipu_resources(struct ipu_image_convert_chan *chan)
++{
++      const struct ipu_image_convert_dma_chan *dma = chan->dma_ch;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      int ret;
++
++      /* get IC */
++      chan->ic = ipu_ic_get(priv->ipu, chan->ic_task);
++      if (IS_ERR(chan->ic)) {
++              dev_err(priv->ipu->dev, "could not acquire IC\n");
++              ret = PTR_ERR(chan->ic);
++              goto err;
++      }
++
++      /* get IDMAC channels */
++      chan->in_chan = ipu_idmac_get(priv->ipu, dma->in);
++      chan->out_chan = ipu_idmac_get(priv->ipu, dma->out);
++      if (IS_ERR(chan->in_chan) || IS_ERR(chan->out_chan)) {
++              dev_err(priv->ipu->dev, "could not acquire idmac channels\n");
++              ret = -EBUSY;
++              goto err;
++      }
++
++      chan->rotation_in_chan = ipu_idmac_get(priv->ipu, dma->rot_in);
++      chan->rotation_out_chan = ipu_idmac_get(priv->ipu, dma->rot_out);
++      if (IS_ERR(chan->rotation_in_chan) || IS_ERR(chan->rotation_out_chan)) {
++              dev_err(priv->ipu->dev,
++                      "could not acquire idmac rotation channels\n");
++              ret = -EBUSY;
++              goto err;
++      }
++
++      /* acquire the EOF interrupts */
++      chan->out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
++                                                chan->out_chan,
++                                                IPU_IRQ_EOF);
++
++      ret = request_threaded_irq(chan->out_eof_irq, norotate_irq, do_bh,
++                                 0, "ipu-ic", chan);
++      if (ret < 0) {
++              dev_err(priv->ipu->dev, "could not acquire irq %d\n",
++                       chan->out_eof_irq);
++              chan->out_eof_irq = -1;
++              goto err;
++      }
++
++      chan->rot_out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
++                                                   chan->rotation_out_chan,
++                                                   IPU_IRQ_EOF);
++
++      ret = request_threaded_irq(chan->rot_out_eof_irq, rotate_irq, do_bh,
++                                 0, "ipu-ic", chan);
++      if (ret < 0) {
++              dev_err(priv->ipu->dev, "could not acquire irq %d\n",
++                      chan->rot_out_eof_irq);
++              chan->rot_out_eof_irq = -1;
++              goto err;
++      }
++
++      return 0;
++err:
++      release_ipu_resources(chan);
++      return ret;
++}
++
++static int fill_image(struct ipu_image_convert_ctx *ctx,
++                    struct ipu_image_convert_image *ic_image,
++                    struct ipu_image *image,
++                    enum ipu_image_convert_type type)
++{
++      struct ipu_image_convert_priv *priv = ctx->chan->priv;
++
++      ic_image->base = *image;
++      ic_image->type = type;
++
++      ic_image->fmt = get_format(image->pix.pixelformat);
++      if (!ic_image->fmt) {
++              dev_err(priv->ipu->dev, "pixelformat not supported for %s\n",
++                      type == IMAGE_CONVERT_OUT ? "Output" : "Input");
++              return -EINVAL;
++      }
++
++      if (ic_image->fmt->planar)
++              ic_image->stride = ic_image->base.pix.width;
++      else
++              ic_image->stride  = ic_image->base.pix.bytesperline;
++
++      return 0;
++}
++
++/* borrowed from drivers/media/v4l2-core/v4l2-common.c */
++static unsigned int clamp_align(unsigned int x, unsigned int min,
++                              unsigned int max, unsigned int align)
++{
++      /* Bits that must be zero to be aligned */
++      unsigned int mask = ~((1 << align) - 1);
++
++      /* Clamp to aligned min and max */
++      x = clamp(x, (min + ~mask) & mask, max & mask);
++
++      /* Round to nearest aligned value */
++      if (align)
++              x = (x + (1 << (align - 1))) & mask;
++
++      return x;
++}
++
++/* Adjusts input/output images to IPU restrictions */
++void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
++                            enum ipu_rotate_mode rot_mode)
++{
++      const struct ipu_image_pixfmt *infmt, *outfmt;
++      u32 w_align_out, h_align_out;
++      u32 w_align_in, h_align_in;
++
++      infmt = get_format(in->pix.pixelformat);
++      outfmt = get_format(out->pix.pixelformat);
++
++      /* set some default pixel formats if needed */
++      if (!infmt) {
++              in->pix.pixelformat = V4L2_PIX_FMT_RGB24;
++              infmt = get_format(V4L2_PIX_FMT_RGB24);
++      }
++      if (!outfmt) {
++              out->pix.pixelformat = V4L2_PIX_FMT_RGB24;
++              outfmt = get_format(V4L2_PIX_FMT_RGB24);
++      }
++
++      /* image converter does not handle fields */
++      in->pix.field = out->pix.field = V4L2_FIELD_NONE;
++
++      /* resizer cannot downsize more than 4:1 */
++      if (ipu_rot_mode_is_irt(rot_mode)) {
++              out->pix.height = max_t(__u32, out->pix.height,
++                                      in->pix.width / 4);
++              out->pix.width = max_t(__u32, out->pix.width,
++                                     in->pix.height / 4);
++      } else {
++              out->pix.width = max_t(__u32, out->pix.width,
++                                     in->pix.width / 4);
++              out->pix.height = max_t(__u32, out->pix.height,
++                                      in->pix.height / 4);
++      }
++
++      /* align input width/height */
++      w_align_in = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt,
++                                          rot_mode));
++      h_align_in = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt,
++                                           rot_mode));
++      in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W,
++                                  w_align_in);
++      in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H,
++                                   h_align_in);
++
++      /* align output width/height */
++      w_align_out = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt,
++                                           rot_mode));
++      h_align_out = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt,
++                                            rot_mode));
++      out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W,
++                                   w_align_out);
++      out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H,
++                                    h_align_out);
++
++      /* set input/output strides and image sizes */
++      in->pix.bytesperline = infmt->planar ?
++              clamp_align(in->pix.width, 2 << w_align_in, MAX_W,
++                          w_align_in) :
++              clamp_align((in->pix.width * infmt->bpp) >> 3,
++                          ((2 << w_align_in) * infmt->bpp) >> 3,
++                          (MAX_W * infmt->bpp) >> 3,
++                          w_align_in);
++      in->pix.sizeimage = infmt->planar ?
++              (in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 :
++              in->pix.height * in->pix.bytesperline;
++      out->pix.bytesperline = outfmt->planar ? out->pix.width :
++              (out->pix.width * outfmt->bpp) >> 3;
++      out->pix.sizeimage = outfmt->planar ?
++              (out->pix.height * out->pix.bytesperline * outfmt->bpp) >> 3 :
++              out->pix.height * out->pix.bytesperline;
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_adjust);
++
++/*
++ * this is used by ipu_image_convert_prepare() to verify set input and
++ * output images are valid before starting the conversion. Clients can
++ * also call it before calling ipu_image_convert_prepare().
++ */
++int ipu_image_convert_verify(struct ipu_image *in, struct ipu_image *out,
++                           enum ipu_rotate_mode rot_mode)
++{
++      struct ipu_image testin, testout;
++
++      testin = *in;
++      testout = *out;
++
++      ipu_image_convert_adjust(&testin, &testout, rot_mode);
++
++      if (testin.pix.width != in->pix.width ||
++          testin.pix.height != in->pix.height ||
++          testout.pix.width != out->pix.width ||
++          testout.pix.height != out->pix.height)
++              return -EINVAL;
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_verify);
++
++/*
++ * Call ipu_image_convert_prepare() to prepare for the conversion of
++ * given images and rotation mode. Returns a new conversion context.
++ */
++struct ipu_image_convert_ctx *
++ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
++                        struct ipu_image *in, struct ipu_image *out,
++                        enum ipu_rotate_mode rot_mode,
++                        ipu_image_convert_cb_t complete,
++                        void *complete_context)
++{
++      struct ipu_image_convert_priv *priv = ipu->image_convert_priv;
++      struct ipu_image_convert_image *s_image, *d_image;
++      struct ipu_image_convert_chan *chan;
++      struct ipu_image_convert_ctx *ctx;
++      unsigned long flags;
++      unsigned int i;
++      bool get_res;
++      int ret;
++
++      if (!in || !out || !complete ||
++          (ic_task != IC_TASK_VIEWFINDER &&
++           ic_task != IC_TASK_POST_PROCESSOR))
++              return ERR_PTR(-EINVAL);
++
++      /* verify the in/out images before continuing */
++      ret = ipu_image_convert_verify(in, out, rot_mode);
++      if (ret) {
++              dev_err(priv->ipu->dev, "%s: in/out formats invalid\n",
++                      __func__);
++              return ERR_PTR(ret);
++      }
++
++      chan = &priv->chan[ic_task];
++
++      ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
++      if (!ctx)
++              return ERR_PTR(-ENOMEM);
++
++      dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p\n", __func__,
++              chan->ic_task, ctx);
++
++      ctx->chan = chan;
++      init_completion(&ctx->aborted);
++
++      ctx->rot_mode = rot_mode;
++
++      /* Sets ctx->in.num_rows/cols as well */
++      ret = calc_image_resize_coefficients(ctx, in, out);
++      if (ret)
++              goto out_free;
++
++      s_image = &ctx->in;
++      d_image = &ctx->out;
++
++      /* set tiling and rotation */
++      if (ipu_rot_mode_is_irt(rot_mode)) {
++              d_image->num_rows = s_image->num_cols;
++              d_image->num_cols = s_image->num_rows;
++      } else {
++              d_image->num_rows = s_image->num_rows;
++              d_image->num_cols = s_image->num_cols;
++      }
++
++      ctx->num_tiles = d_image->num_cols * d_image->num_rows;
++
++      ret = fill_image(ctx, s_image, in, IMAGE_CONVERT_IN);
++      if (ret)
++              goto out_free;
++      ret = fill_image(ctx, d_image, out, IMAGE_CONVERT_OUT);
++      if (ret)
++              goto out_free;
++
++      calc_out_tile_map(ctx);
++
++      find_seams(ctx, s_image, d_image);
++
++      ret = calc_tile_dimensions(ctx, s_image);
++      if (ret)
++              goto out_free;
++
++      ret = calc_tile_offsets(ctx, s_image);
++      if (ret)
++              goto out_free;
++
++      calc_tile_dimensions(ctx, d_image);
++      ret = calc_tile_offsets(ctx, d_image);
++      if (ret)
++              goto out_free;
++
++      calc_tile_resize_coefficients(ctx);
++
++      ret = ipu_ic_calc_csc(&ctx->csc,
++                      s_image->base.pix.ycbcr_enc,
++                      s_image->base.pix.quantization,
++                      ipu_pixelformat_to_colorspace(s_image->fmt->fourcc),
++                      d_image->base.pix.ycbcr_enc,
++                      d_image->base.pix.quantization,
++                      ipu_pixelformat_to_colorspace(d_image->fmt->fourcc));
++      if (ret)
++              goto out_free;
++
++      dump_format(ctx, s_image);
++      dump_format(ctx, d_image);
++
++      ctx->complete = complete;
++      ctx->complete_context = complete_context;
++
++      /*
++       * Can we use double-buffering for this operation? If there is
++       * only one tile (the whole image can be converted in a single
++       * operation) there's no point in using double-buffering. Also,
++       * the IPU's IDMAC channels allow only a single U and V plane
++       * offset shared between both buffers, but these offsets change
++       * for every tile, and therefore would have to be updated for
++       * each buffer which is not possible. So double-buffering is
++       * impossible when either the source or destination images are
++       * a planar format (YUV420, YUV422P, etc.). Further, differently
++       * sized tiles or different resizing coefficients per tile
++       * prevent double-buffering as well.
++       */
++      ctx->double_buffering = (ctx->num_tiles > 1 &&
++                               !s_image->fmt->planar &&
++                               !d_image->fmt->planar);
++      for (i = 1; i < ctx->num_tiles; i++) {
++              if (ctx->in.tile[i].width != ctx->in.tile[0].width ||
++                  ctx->in.tile[i].height != ctx->in.tile[0].height ||
++                  ctx->out.tile[i].width != ctx->out.tile[0].width ||
++                  ctx->out.tile[i].height != ctx->out.tile[0].height) {
++                      ctx->double_buffering = false;
++                      break;
++              }
++      }
++      for (i = 1; i < ctx->in.num_cols; i++) {
++              if (ctx->resize_coeffs_h[i] != ctx->resize_coeffs_h[0]) {
++                      ctx->double_buffering = false;
++                      break;
++              }
++      }
++      for (i = 1; i < ctx->in.num_rows; i++) {
++              if (ctx->resize_coeffs_v[i] != ctx->resize_coeffs_v[0]) {
++                      ctx->double_buffering = false;
++                      break;
++              }
++      }
++
++      if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
++              unsigned long intermediate_size = d_image->tile[0].size;
++
++              for (i = 1; i < ctx->num_tiles; i++) {
++                      if (d_image->tile[i].size > intermediate_size)
++                              intermediate_size = d_image->tile[i].size;
++              }
++
++              ret = alloc_dma_buf(priv, &ctx->rot_intermediate[0],
++                                  intermediate_size);
++              if (ret)
++                      goto out_free;
++              if (ctx->double_buffering) {
++                      ret = alloc_dma_buf(priv,
++                                          &ctx->rot_intermediate[1],
++                                          intermediate_size);
++                      if (ret)
++                              goto out_free_dmabuf0;
++              }
++      }
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      get_res = list_empty(&chan->ctx_list);
++
++      list_add_tail(&ctx->list, &chan->ctx_list);
++
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++
++      if (get_res) {
++              ret = get_ipu_resources(chan);
++              if (ret)
++                      goto out_free_dmabuf1;
++      }
++
++      return ctx;
++
++out_free_dmabuf1:
++      free_dma_buf(priv, &ctx->rot_intermediate[1]);
++      spin_lock_irqsave(&chan->irqlock, flags);
++      list_del(&ctx->list);
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++out_free_dmabuf0:
++      free_dma_buf(priv, &ctx->rot_intermediate[0]);
++out_free:
++      kfree(ctx);
++      return ERR_PTR(ret);
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_prepare);
++
++/*
++ * Carry out a single image conversion run. Only the physaddr's of the input
++ * and output image buffers are needed. The conversion context must have
++ * been created previously with ipu_image_convert_prepare().
++ */
++int ipu_image_convert_queue(struct ipu_image_convert_run *run)
++{
++      struct ipu_image_convert_chan *chan;
++      struct ipu_image_convert_priv *priv;
++      struct ipu_image_convert_ctx *ctx;
++      unsigned long flags;
++      int ret = 0;
++
++      if (!run || !run->ctx || !run->in_phys || !run->out_phys)
++              return -EINVAL;
++
++      ctx = run->ctx;
++      chan = ctx->chan;
++      priv = chan->priv;
++
++      dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p run %p\n", __func__,
++              chan->ic_task, ctx, run);
++
++      INIT_LIST_HEAD(&run->list);
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      if (ctx->aborting) {
++              ret = -EIO;
++              goto unlock;
++      }
++
++      list_add_tail(&run->list, &chan->pending_q);
++
++      if (!chan->current_run) {
++              ret = do_run(run);
++              if (ret)
++                      chan->current_run = NULL;
++      }
++unlock:
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_queue);
++
++/* Abort any active or pending conversions for this context */
++static void __ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      struct ipu_image_convert_run *run, *active_run, *tmp;
++      unsigned long flags;
++      int run_count, ret;
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      /* move all remaining pending runs in this context to done_q */
++      list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
++              if (run->ctx != ctx)
++                      continue;
++              run->status = -EIO;
++              list_move_tail(&run->list, &chan->done_q);
++      }
++
++      run_count = get_run_count(ctx, &chan->done_q);
++      active_run = (chan->current_run && chan->current_run->ctx == ctx) ?
++              chan->current_run : NULL;
++
++      if (active_run)
++              reinit_completion(&ctx->aborted);
++
++      ctx->aborting = true;
++
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++
++      if (!run_count && !active_run) {
++              dev_dbg(priv->ipu->dev,
++                      "%s: task %u: no abort needed for ctx %p\n",
++                      __func__, chan->ic_task, ctx);
++              return;
++      }
++
++      if (!active_run) {
++              empty_done_q(chan);
++              return;
++      }
++
++      dev_dbg(priv->ipu->dev,
++              "%s: task %u: wait for completion: %d runs\n",
++              __func__, chan->ic_task, run_count);
++
++      ret = wait_for_completion_timeout(&ctx->aborted,
++                                        msecs_to_jiffies(10000));
++      if (ret == 0) {
++              dev_warn(priv->ipu->dev, "%s: timeout\n", __func__);
++              force_abort(ctx);
++      }
++}
++
++void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
++{
++      __ipu_image_convert_abort(ctx);
++      ctx->aborting = false;
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_abort);
++
++/* Unprepare image conversion context */
++void ipu_image_convert_unprepare(struct ipu_image_convert_ctx *ctx)
++{
++      struct ipu_image_convert_chan *chan = ctx->chan;
++      struct ipu_image_convert_priv *priv = chan->priv;
++      unsigned long flags;
++      bool put_res;
++
++      /* make sure no runs are hanging around */
++      __ipu_image_convert_abort(ctx);
++
++      dev_dbg(priv->ipu->dev, "%s: task %u: removing ctx %p\n", __func__,
++              chan->ic_task, ctx);
++
++      spin_lock_irqsave(&chan->irqlock, flags);
++
++      list_del(&ctx->list);
++
++      put_res = list_empty(&chan->ctx_list);
++
++      spin_unlock_irqrestore(&chan->irqlock, flags);
++
++      if (put_res)
++              release_ipu_resources(chan);
++
++      free_dma_buf(priv, &ctx->rot_intermediate[1]);
++      free_dma_buf(priv, &ctx->rot_intermediate[0]);
++
++      kfree(ctx);
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_unprepare);
++
++/*
++ * "Canned" asynchronous single image conversion. Allocates and returns
++ * a new conversion run.  On successful return the caller must free the
++ * run and call ipu_image_convert_unprepare() after conversion completes.
++ */
++struct ipu_image_convert_run *
++ipu_image_convert(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
++                struct ipu_image *in, struct ipu_image *out,
++                enum ipu_rotate_mode rot_mode,
++                ipu_image_convert_cb_t complete,
++                void *complete_context)
++{
++      struct ipu_image_convert_ctx *ctx;
++      struct ipu_image_convert_run *run;
++      int ret;
++
++      ctx = ipu_image_convert_prepare(ipu, ic_task, in, out, rot_mode,
++                                      complete, complete_context);
++      if (IS_ERR(ctx))
++              return ERR_CAST(ctx);
++
++      run = kzalloc(sizeof(*run), GFP_KERNEL);
++      if (!run) {
++              ipu_image_convert_unprepare(ctx);
++              return ERR_PTR(-ENOMEM);
++      }
++
++      run->ctx = ctx;
++      run->in_phys = in->phys0;
++      run->out_phys = out->phys0;
++
++      ret = ipu_image_convert_queue(run);
++      if (ret) {
++              ipu_image_convert_unprepare(ctx);
++              kfree(run);
++              return ERR_PTR(ret);
++      }
++
++      return run;
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert);
++
++/* "Canned" synchronous single image conversion */
++static void image_convert_sync_complete(struct ipu_image_convert_run *run,
++                                      void *data)
++{
++      struct completion *comp = data;
++
++      complete(comp);
++}
++
++int ipu_image_convert_sync(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
++                         struct ipu_image *in, struct ipu_image *out,
++                         enum ipu_rotate_mode rot_mode)
++{
++      struct ipu_image_convert_run *run;
++      struct completion comp;
++      int ret;
++
++      init_completion(&comp);
++
++      run = ipu_image_convert(ipu, ic_task, in, out, rot_mode,
++                              image_convert_sync_complete, &comp);
++      if (IS_ERR(run))
++              return PTR_ERR(run);
++
++      ret = wait_for_completion_timeout(&comp, msecs_to_jiffies(10000));
++      ret = (ret == 0) ? -ETIMEDOUT : 0;
++
++      ipu_image_convert_unprepare(run->ctx);
++      kfree(run);
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_image_convert_sync);
++
++int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev)
++{
++      struct ipu_image_convert_priv *priv;
++      int i;
++
++      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++
++      ipu->image_convert_priv = priv;
++      priv->ipu = ipu;
++
++      for (i = 0; i < IC_NUM_TASKS; i++) {
++              struct ipu_image_convert_chan *chan = &priv->chan[i];
++
++              chan->ic_task = i;
++              chan->priv = priv;
++              chan->dma_ch = &image_convert_dma_chan[i];
++              chan->out_eof_irq = -1;
++              chan->rot_out_eof_irq = -1;
++
++              spin_lock_init(&chan->irqlock);
++              INIT_LIST_HEAD(&chan->ctx_list);
++              INIT_LIST_HEAD(&chan->pending_q);
++              INIT_LIST_HEAD(&chan->done_q);
++      }
++
++      return 0;
++}
++
++void ipu_image_convert_exit(struct ipu_soc *ipu)
++{
++}
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/ipu-pre.c
+@@ -0,0 +1,346 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2017 Lucas Stach, Pengutronix
++ */
++
++#include <drm/drm_fourcc.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/genalloc.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <video/imx-ipu-v3.h>
++
++#include "ipu-prv.h"
++
++#define IPU_PRE_MAX_WIDTH     2048
++#define IPU_PRE_NUM_SCANLINES 8
++
++#define IPU_PRE_CTRL                                  0x000
++#define IPU_PRE_CTRL_SET                              0x004
++#define  IPU_PRE_CTRL_ENABLE                          (1 << 0)
++#define  IPU_PRE_CTRL_BLOCK_EN                                (1 << 1)
++#define  IPU_PRE_CTRL_BLOCK_16                                (1 << 2)
++#define  IPU_PRE_CTRL_SDW_UPDATE                      (1 << 4)
++#define  IPU_PRE_CTRL_VFLIP                           (1 << 5)
++#define  IPU_PRE_CTRL_SO                              (1 << 6)
++#define  IPU_PRE_CTRL_INTERLACED_FIELD                        (1 << 7)
++#define  IPU_PRE_CTRL_HANDSHAKE_EN                    (1 << 8)
++#define  IPU_PRE_CTRL_HANDSHAKE_LINE_NUM(v)           ((v & 0x3) << 9)
++#define  IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN         (1 << 11)
++#define  IPU_PRE_CTRL_EN_REPEAT                               (1 << 28)
++#define  IPU_PRE_CTRL_TPR_REST_SEL                    (1 << 29)
++#define  IPU_PRE_CTRL_CLKGATE                         (1 << 30)
++#define  IPU_PRE_CTRL_SFTRST                          (1 << 31)
++
++#define IPU_PRE_CUR_BUF                                       0x030
++
++#define IPU_PRE_NEXT_BUF                              0x040
++
++#define IPU_PRE_TPR_CTRL                              0x070
++#define  IPU_PRE_TPR_CTRL_TILE_FORMAT(v)              ((v & 0xff) << 0)
++#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK            0xff
++#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT          (1 << 0)
++#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_SPLIT_BUF               (1 << 4)
++#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF      (1 << 5)
++#define  IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED     (1 << 6)
++
++#define IPU_PRE_PREFETCH_ENG_CTRL                     0x080
++#define  IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN            (1 << 0)
++#define  IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(v)                ((v & 0x7) << 1)
++#define  IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(v)    ((v & 0x3) << 4)
++#define  IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(v)  ((v & 0x7) << 8)
++#define  IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS           (1 << 11)
++#define  IPU_PRE_PREF_ENG_CTRL_FIELD_INVERSE          (1 << 12)
++#define  IPU_PRE_PREF_ENG_CTRL_PARTIAL_UV_SWAP                (1 << 14)
++#define  IPU_PRE_PREF_ENG_CTRL_TPR_COOR_OFFSET_EN     (1 << 15)
++
++#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE                       0x0a0
++#define  IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(v)     ((v & 0xffff) << 0)
++#define  IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(v)    ((v & 0xffff) << 16)
++
++#define IPU_PRE_PREFETCH_ENG_PITCH                    0x0d0
++#define  IPU_PRE_PREFETCH_ENG_PITCH_Y(v)              ((v & 0xffff) << 0)
++#define  IPU_PRE_PREFETCH_ENG_PITCH_UV(v)             ((v & 0xffff) << 16)
++
++#define IPU_PRE_STORE_ENG_CTRL                                0x110
++#define  IPU_PRE_STORE_ENG_CTRL_STORE_EN              (1 << 0)
++#define  IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(v)               ((v & 0x7) << 1)
++#define  IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(v)  ((v & 0x3) << 4)
++
++#define IPU_PRE_STORE_ENG_STATUS                      0x120
++#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_MASK  0xffff
++#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_SHIFT 0
++#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK  0x3fff
++#define  IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT 16
++#define  IPU_PRE_STORE_ENG_STATUS_STORE_FIFO_FULL     (1 << 30)
++#define  IPU_PRE_STORE_ENG_STATUS_STORE_FIELD         (1 << 31)
++
++#define IPU_PRE_STORE_ENG_SIZE                                0x130
++#define  IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(v)                ((v & 0xffff) << 0)
++#define  IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(v)               ((v & 0xffff) << 16)
++
++#define IPU_PRE_STORE_ENG_PITCH                               0x140
++#define  IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(v)         ((v & 0xffff) << 0)
++
++#define IPU_PRE_STORE_ENG_ADDR                                0x150
++
++struct ipu_pre {
++      struct list_head        list;
++      struct device           *dev;
++
++      void __iomem            *regs;
++      struct clk              *clk_axi;
++      struct gen_pool         *iram;
++
++      dma_addr_t              buffer_paddr;
++      void                    *buffer_virt;
++      bool                    in_use;
++      unsigned int            safe_window_end;
++      unsigned int            last_bufaddr;
++};
++
++static DEFINE_MUTEX(ipu_pre_list_mutex);
++static LIST_HEAD(ipu_pre_list);
++static int available_pres;
++
++int ipu_pre_get_available_count(void)
++{
++      return available_pres;
++}
++
++struct ipu_pre *
++ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
++{
++      struct device_node *pre_node = of_parse_phandle(dev->of_node,
++                                                      name, index);
++      struct ipu_pre *pre;
++
++      mutex_lock(&ipu_pre_list_mutex);
++      list_for_each_entry(pre, &ipu_pre_list, list) {
++              if (pre_node == pre->dev->of_node) {
++                      mutex_unlock(&ipu_pre_list_mutex);
++                      device_link_add(dev, pre->dev,
++                                      DL_FLAG_AUTOREMOVE_CONSUMER);
++                      of_node_put(pre_node);
++                      return pre;
++              }
++      }
++      mutex_unlock(&ipu_pre_list_mutex);
++
++      of_node_put(pre_node);
++
++      return NULL;
++}
++
++int ipu_pre_get(struct ipu_pre *pre)
++{
++      u32 val;
++
++      if (pre->in_use)
++              return -EBUSY;
++
++      /* first get the engine out of reset and remove clock gating */
++      writel(0, pre->regs + IPU_PRE_CTRL);
++
++      /* init defaults that should be applied to all streams */
++      val = IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN |
++            IPU_PRE_CTRL_HANDSHAKE_EN |
++            IPU_PRE_CTRL_TPR_REST_SEL |
++            IPU_PRE_CTRL_SDW_UPDATE;
++      writel(val, pre->regs + IPU_PRE_CTRL);
++
++      pre->in_use = true;
++      return 0;
++}
++
++void ipu_pre_put(struct ipu_pre *pre)
++{
++      writel(IPU_PRE_CTRL_SFTRST, pre->regs + IPU_PRE_CTRL);
++
++      pre->in_use = false;
++}
++
++void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
++                     unsigned int height, unsigned int stride, u32 format,
++                     uint64_t modifier, unsigned int bufaddr)
++{
++      const struct drm_format_info *info = drm_format_info(format);
++      u32 active_bpp = info->cpp[0] >> 1;
++      u32 val;
++
++      /* calculate safe window for ctrl register updates */
++      if (modifier == DRM_FORMAT_MOD_LINEAR)
++              pre->safe_window_end = height - 2;
++      else
++              pre->safe_window_end = DIV_ROUND_UP(height, 4) - 1;
++
++      writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF);
++      writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
++      pre->last_bufaddr = bufaddr;
++
++      val = IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(0) |
++            IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(active_bpp) |
++            IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(4) |
++            IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS |
++            IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN;
++      writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_CTRL);
++
++      val = IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(width) |
++            IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(height);
++      writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_INPUT_SIZE);
++
++      val = IPU_PRE_PREFETCH_ENG_PITCH_Y(stride);
++      writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_PITCH);
++
++      val = IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(active_bpp) |
++            IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(4) |
++            IPU_PRE_STORE_ENG_CTRL_STORE_EN;
++      writel(val, pre->regs + IPU_PRE_STORE_ENG_CTRL);
++
++      val = IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(width) |
++            IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(height);
++      writel(val, pre->regs + IPU_PRE_STORE_ENG_SIZE);
++
++      val = IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(stride);
++      writel(val, pre->regs + IPU_PRE_STORE_ENG_PITCH);
++
++      writel(pre->buffer_paddr, pre->regs + IPU_PRE_STORE_ENG_ADDR);
++
++      val = readl(pre->regs + IPU_PRE_TPR_CTRL);
++      val &= ~IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK;
++      if (modifier != DRM_FORMAT_MOD_LINEAR) {
++              /* only support single buffer formats for now */
++              val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF;
++              if (modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED)
++                      val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED;
++              if (info->cpp[0] == 2)
++                      val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT;
++      }
++      writel(val, pre->regs + IPU_PRE_TPR_CTRL);
++
++      val = readl(pre->regs + IPU_PRE_CTRL);
++      val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE |
++             IPU_PRE_CTRL_SDW_UPDATE;
++      if (modifier == DRM_FORMAT_MOD_LINEAR)
++              val &= ~IPU_PRE_CTRL_BLOCK_EN;
++      else
++              val |= IPU_PRE_CTRL_BLOCK_EN;
++      writel(val, pre->regs + IPU_PRE_CTRL);
++}
++
++void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
++{
++      unsigned long timeout = jiffies + msecs_to_jiffies(5);
++      unsigned short current_yblock;
++      u32 val;
++
++      if (bufaddr == pre->last_bufaddr)
++              return;
++
++      writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
++      pre->last_bufaddr = bufaddr;
++
++      do {
++              if (time_after(jiffies, timeout)) {
++                      dev_warn(pre->dev, "timeout waiting for PRE safe window\n");
++                      return;
++              }
++
++              val = readl(pre->regs + IPU_PRE_STORE_ENG_STATUS);
++              current_yblock =
++                      (val >> IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT) &
++                      IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK;
++      } while (current_yblock == 0 || current_yblock >= pre->safe_window_end);
++
++      writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
++}
++
++bool ipu_pre_update_pending(struct ipu_pre *pre)
++{
++      return !!(readl_relaxed(pre->regs + IPU_PRE_CTRL) &
++                IPU_PRE_CTRL_SDW_UPDATE);
++}
++
++u32 ipu_pre_get_baddr(struct ipu_pre *pre)
++{
++      return (u32)pre->buffer_paddr;
++}
++
++static int ipu_pre_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct resource *res;
++      struct ipu_pre *pre;
++
++      pre = devm_kzalloc(dev, sizeof(*pre), GFP_KERNEL);
++      if (!pre)
++              return -ENOMEM;
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      pre->regs = devm_ioremap_resource(&pdev->dev, res);
++      if (IS_ERR(pre->regs))
++              return PTR_ERR(pre->regs);
++
++      pre->clk_axi = devm_clk_get(dev, "axi");
++      if (IS_ERR(pre->clk_axi))
++              return PTR_ERR(pre->clk_axi);
++
++      pre->iram = of_gen_pool_get(dev->of_node, "fsl,iram", 0);
++      if (!pre->iram)
++              return -EPROBE_DEFER;
++
++      /*
++       * Allocate IRAM buffer with maximum size. This could be made dynamic,
++       * but as there is no other user of this IRAM region and we can fit all
++       * max sized buffers into it, there is no need yet.
++       */
++      pre->buffer_virt = gen_pool_dma_alloc(pre->iram, IPU_PRE_MAX_WIDTH *
++                                            IPU_PRE_NUM_SCANLINES * 4,
++                                            &pre->buffer_paddr);
++      if (!pre->buffer_virt)
++              return -ENOMEM;
++
++      clk_prepare_enable(pre->clk_axi);
++
++      pre->dev = dev;
++      platform_set_drvdata(pdev, pre);
++      mutex_lock(&ipu_pre_list_mutex);
++      list_add(&pre->list, &ipu_pre_list);
++      available_pres++;
++      mutex_unlock(&ipu_pre_list_mutex);
++
++      return 0;
++}
++
++static int ipu_pre_remove(struct platform_device *pdev)
++{
++      struct ipu_pre *pre = platform_get_drvdata(pdev);
++
++      mutex_lock(&ipu_pre_list_mutex);
++      list_del(&pre->list);
++      available_pres--;
++      mutex_unlock(&ipu_pre_list_mutex);
++
++      clk_disable_unprepare(pre->clk_axi);
++
++      if (pre->buffer_virt)
++              gen_pool_free(pre->iram, (unsigned long)pre->buffer_virt,
++                            IPU_PRE_MAX_WIDTH * IPU_PRE_NUM_SCANLINES * 4);
++      return 0;
++}
++
++static const struct of_device_id ipu_pre_dt_ids[] = {
++      { .compatible = "fsl,imx6qp-pre", },
++      { /* sentinel */ },
++};
++
++struct platform_driver ipu_pre_drv = {
++      .probe          = ipu_pre_probe,
++      .remove         = ipu_pre_remove,
++      .driver         = {
++              .name   = "imx-ipu-pre",
++              .of_match_table = ipu_pre_dt_ids,
++      },
++};
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/ipu-prg.c
+@@ -0,0 +1,483 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2016-2017 Lucas Stach, Pengutronix
++ */
++
++#include <drm/drm_fourcc.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/iopoll.h>
++#include <linux/mfd/syscon.h>
++#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/regmap.h>
++#include <video/imx-ipu-v3.h>
++
++#include "ipu-prv.h"
++
++#define IPU_PRG_CTL                           0x00
++#define  IPU_PRG_CTL_BYPASS(i)                        (1 << (0 + i))
++#define  IPU_PRG_CTL_SOFT_ARID_MASK           0x3
++#define  IPU_PRG_CTL_SOFT_ARID_SHIFT(i)               (8 + i * 2)
++#define  IPU_PRG_CTL_SOFT_ARID(i, v)          ((v & 0x3) << (8 + 2 * i))
++#define  IPU_PRG_CTL_SO(i)                    (1 << (16 + i))
++#define  IPU_PRG_CTL_VFLIP(i)                 (1 << (19 + i))
++#define  IPU_PRG_CTL_BLOCK_MODE(i)            (1 << (22 + i))
++#define  IPU_PRG_CTL_CNT_LOAD_EN(i)           (1 << (25 + i))
++#define  IPU_PRG_CTL_SOFTRST                  (1 << 30)
++#define  IPU_PRG_CTL_SHADOW_EN                        (1 << 31)
++
++#define IPU_PRG_STATUS                                0x04
++#define  IPU_PRG_STATUS_BUFFER0_READY(i)      (1 << (0 + i * 2))
++#define  IPU_PRG_STATUS_BUFFER1_READY(i)      (1 << (1 + i * 2))
++
++#define IPU_PRG_QOS                           0x08
++#define  IPU_PRG_QOS_ARID_MASK                        0xf
++#define  IPU_PRG_QOS_ARID_SHIFT(i)            (0 + i * 4)
++
++#define IPU_PRG_REG_UPDATE                    0x0c
++#define  IPU_PRG_REG_UPDATE_REG_UPDATE                (1 << 0)
++
++#define IPU_PRG_STRIDE(i)                     (0x10 + i * 0x4)
++#define  IPU_PRG_STRIDE_STRIDE_MASK           0x3fff
++
++#define IPU_PRG_CROP_LINE                     0x1c
++
++#define IPU_PRG_THD                           0x20
++
++#define IPU_PRG_BADDR(i)                      (0x24 + i * 0x4)
++
++#define IPU_PRG_OFFSET(i)                     (0x30 + i * 0x4)
++
++#define IPU_PRG_ILO(i)                                (0x3c + i * 0x4)
++
++#define IPU_PRG_HEIGHT(i)                     (0x48 + i * 0x4)
++#define  IPU_PRG_HEIGHT_PRE_HEIGHT_MASK               0xfff
++#define  IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT      0
++#define  IPU_PRG_HEIGHT_IPU_HEIGHT_MASK               0xfff
++#define  IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT      16
++
++struct ipu_prg_channel {
++      bool                    enabled;
++      int                     used_pre;
++};
++
++struct ipu_prg {
++      struct list_head        list;
++      struct device           *dev;
++      int                     id;
++
++      void __iomem            *regs;
++      struct clk              *clk_ipg, *clk_axi;
++      struct regmap           *iomuxc_gpr;
++      struct ipu_pre          *pres[3];
++
++      struct ipu_prg_channel  chan[3];
++};
++
++static DEFINE_MUTEX(ipu_prg_list_mutex);
++static LIST_HEAD(ipu_prg_list);
++
++struct ipu_prg *
++ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id)
++{
++      struct device_node *prg_node = of_parse_phandle(dev->of_node,
++                                                      name, 0);
++      struct ipu_prg *prg;
++
++      mutex_lock(&ipu_prg_list_mutex);
++      list_for_each_entry(prg, &ipu_prg_list, list) {
++              if (prg_node == prg->dev->of_node) {
++                      mutex_unlock(&ipu_prg_list_mutex);
++                      device_link_add(dev, prg->dev,
++                                      DL_FLAG_AUTOREMOVE_CONSUMER);
++                      prg->id = ipu_id;
++                      of_node_put(prg_node);
++                      return prg;
++              }
++      }
++      mutex_unlock(&ipu_prg_list_mutex);
++
++      of_node_put(prg_node);
++
++      return NULL;
++}
++
++int ipu_prg_max_active_channels(void)
++{
++      return ipu_pre_get_available_count();
++}
++EXPORT_SYMBOL_GPL(ipu_prg_max_active_channels);
++
++bool ipu_prg_present(struct ipu_soc *ipu)
++{
++      if (ipu->prg_priv)
++              return true;
++
++      return false;
++}
++EXPORT_SYMBOL_GPL(ipu_prg_present);
++
++bool ipu_prg_format_supported(struct ipu_soc *ipu, uint32_t format,
++                            uint64_t modifier)
++{
++      const struct drm_format_info *info = drm_format_info(format);
++
++      if (info->num_planes != 1)
++              return false;
++
++      switch (modifier) {
++      case DRM_FORMAT_MOD_LINEAR:
++      case DRM_FORMAT_MOD_VIVANTE_TILED:
++      case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
++              return true;
++      default:
++              return false;
++      }
++}
++EXPORT_SYMBOL_GPL(ipu_prg_format_supported);
++
++int ipu_prg_enable(struct ipu_soc *ipu)
++{
++      struct ipu_prg *prg = ipu->prg_priv;
++
++      if (!prg)
++              return 0;
++
++      return pm_runtime_get_sync(prg->dev);
++}
++EXPORT_SYMBOL_GPL(ipu_prg_enable);
++
++void ipu_prg_disable(struct ipu_soc *ipu)
++{
++      struct ipu_prg *prg = ipu->prg_priv;
++
++      if (!prg)
++              return;
++
++      pm_runtime_put(prg->dev);
++}
++EXPORT_SYMBOL_GPL(ipu_prg_disable);
++
++/*
++ * The channel configuartion functions below are not thread safe, as they
++ * must be only called from the atomic commit path in the DRM driver, which
++ * is properly serialized.
++ */
++static int ipu_prg_ipu_to_prg_chan(int ipu_chan)
++{
++      /*
++       * This isn't clearly documented in the RM, but IPU to PRG channel
++       * assignment is fixed, as only with this mapping the control signals
++       * match up.
++       */
++      switch (ipu_chan) {
++      case IPUV3_CHANNEL_MEM_BG_SYNC:
++              return 0;
++      case IPUV3_CHANNEL_MEM_FG_SYNC:
++              return 1;
++      case IPUV3_CHANNEL_MEM_DC_SYNC:
++              return 2;
++      default:
++              return -EINVAL;
++      }
++}
++
++static int ipu_prg_get_pre(struct ipu_prg *prg, int prg_chan)
++{
++      int i, ret;
++
++      /* channel 0 is special as it is hardwired to one of the PREs */
++      if (prg_chan == 0) {
++              ret = ipu_pre_get(prg->pres[0]);
++              if (ret)
++                      goto fail;
++              prg->chan[prg_chan].used_pre = 0;
++              return 0;
++      }
++
++      for (i = 1; i < 3; i++) {
++              ret = ipu_pre_get(prg->pres[i]);
++              if (!ret) {
++                      u32 val, mux;
++                      int shift;
++
++                      prg->chan[prg_chan].used_pre = i;
++
++                      /* configure the PRE to PRG channel mux */
++                      shift = (i == 1) ? 12 : 14;
++                      mux = (prg->id << 1) | (prg_chan - 1);
++                      regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
++                                         0x3 << shift, mux << shift);
++
++                      /* check other mux, must not point to same channel */
++                      shift = (i == 1) ? 14 : 12;
++                      regmap_read(prg->iomuxc_gpr, IOMUXC_GPR5, &val);
++                      if (((val >> shift) & 0x3) == mux) {
++                              regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
++                                                 0x3 << shift,
++                                                 (mux ^ 0x1) << shift);
++                      }
++
++                      return 0;
++              }
++      }
++
++fail:
++      dev_err(prg->dev, "could not get PRE for PRG chan %d", prg_chan);
++      return ret;
++}
++
++static void ipu_prg_put_pre(struct ipu_prg *prg, int prg_chan)
++{
++      struct ipu_prg_channel *chan = &prg->chan[prg_chan];
++
++      ipu_pre_put(prg->pres[chan->used_pre]);
++      chan->used_pre = -1;
++}
++
++void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan)
++{
++      int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
++      struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
++      struct ipu_prg_channel *chan;
++      u32 val;
++
++      if (prg_chan < 0)
++              return;
++
++      chan = &prg->chan[prg_chan];
++      if (!chan->enabled)
++              return;
++
++      pm_runtime_get_sync(prg->dev);
++
++      val = readl(prg->regs + IPU_PRG_CTL);
++      val |= IPU_PRG_CTL_BYPASS(prg_chan);
++      writel(val, prg->regs + IPU_PRG_CTL);
++
++      val = IPU_PRG_REG_UPDATE_REG_UPDATE;
++      writel(val, prg->regs + IPU_PRG_REG_UPDATE);
++
++      pm_runtime_put(prg->dev);
++
++      ipu_prg_put_pre(prg, prg_chan);
++
++      chan->enabled = false;
++}
++EXPORT_SYMBOL_GPL(ipu_prg_channel_disable);
++
++int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
++                            unsigned int axi_id, unsigned int width,
++                            unsigned int height, unsigned int stride,
++                            u32 format, uint64_t modifier, unsigned long *eba)
++{
++      int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
++      struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
++      struct ipu_prg_channel *chan;
++      u32 val;
++      int ret;
++
++      if (prg_chan < 0)
++              return prg_chan;
++
++      chan = &prg->chan[prg_chan];
++
++      if (chan->enabled) {
++              ipu_pre_update(prg->pres[chan->used_pre], *eba);
++              return 0;
++      }
++
++      ret = ipu_prg_get_pre(prg, prg_chan);
++      if (ret)
++              return ret;
++
++      ipu_pre_configure(prg->pres[chan->used_pre],
++                        width, height, stride, format, modifier, *eba);
++
++
++      pm_runtime_get_sync(prg->dev);
++
++      val = (stride - 1) & IPU_PRG_STRIDE_STRIDE_MASK;
++      writel(val, prg->regs + IPU_PRG_STRIDE(prg_chan));
++
++      val = ((height & IPU_PRG_HEIGHT_PRE_HEIGHT_MASK) <<
++             IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT) |
++            ((height & IPU_PRG_HEIGHT_IPU_HEIGHT_MASK) <<
++             IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT);
++      writel(val, prg->regs + IPU_PRG_HEIGHT(prg_chan));
++
++      val = ipu_pre_get_baddr(prg->pres[chan->used_pre]);
++      *eba = val;
++      writel(val, prg->regs + IPU_PRG_BADDR(prg_chan));
++
++      val = readl(prg->regs + IPU_PRG_CTL);
++      /* config AXI ID */
++      val &= ~(IPU_PRG_CTL_SOFT_ARID_MASK <<
++               IPU_PRG_CTL_SOFT_ARID_SHIFT(prg_chan));
++      val |= IPU_PRG_CTL_SOFT_ARID(prg_chan, axi_id);
++      /* enable channel */
++      val &= ~IPU_PRG_CTL_BYPASS(prg_chan);
++      writel(val, prg->regs + IPU_PRG_CTL);
++
++      val = IPU_PRG_REG_UPDATE_REG_UPDATE;
++      writel(val, prg->regs + IPU_PRG_REG_UPDATE);
++
++      /* wait for both double buffers to be filled */
++      readl_poll_timeout(prg->regs + IPU_PRG_STATUS, val,
++                         (val & IPU_PRG_STATUS_BUFFER0_READY(prg_chan)) &&
++                         (val & IPU_PRG_STATUS_BUFFER1_READY(prg_chan)),
++                         5, 1000);
++
++      pm_runtime_put(prg->dev);
++
++      chan->enabled = true;
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_prg_channel_configure);
++
++bool ipu_prg_channel_configure_pending(struct ipuv3_channel *ipu_chan)
++{
++      int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
++      struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
++      struct ipu_prg_channel *chan;
++
++      if (prg_chan < 0)
++              return false;
++
++      chan = &prg->chan[prg_chan];
++      WARN_ON(!chan->enabled);
++
++      return ipu_pre_update_pending(prg->pres[chan->used_pre]);
++}
++EXPORT_SYMBOL_GPL(ipu_prg_channel_configure_pending);
++
++static int ipu_prg_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct resource *res;
++      struct ipu_prg *prg;
++      u32 val;
++      int i, ret;
++
++      prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
++      if (!prg)
++              return -ENOMEM;
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      prg->regs = devm_ioremap_resource(&pdev->dev, res);
++      if (IS_ERR(prg->regs))
++              return PTR_ERR(prg->regs);
++
++
++      prg->clk_ipg = devm_clk_get(dev, "ipg");
++      if (IS_ERR(prg->clk_ipg))
++              return PTR_ERR(prg->clk_ipg);
++
++      prg->clk_axi = devm_clk_get(dev, "axi");
++      if (IS_ERR(prg->clk_axi))
++              return PTR_ERR(prg->clk_axi);
++
++      prg->iomuxc_gpr =
++              syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
++      if (IS_ERR(prg->iomuxc_gpr))
++              return PTR_ERR(prg->iomuxc_gpr);
++
++      for (i = 0; i < 3; i++) {
++              prg->pres[i] = ipu_pre_lookup_by_phandle(dev, "fsl,pres", i);
++              if (!prg->pres[i])
++                      return -EPROBE_DEFER;
++      }
++
++      ret = clk_prepare_enable(prg->clk_ipg);
++      if (ret)
++              return ret;
++
++      ret = clk_prepare_enable(prg->clk_axi);
++      if (ret) {
++              clk_disable_unprepare(prg->clk_ipg);
++              return ret;
++      }
++
++      /* init to free running mode */
++      val = readl(prg->regs + IPU_PRG_CTL);
++      val |= IPU_PRG_CTL_SHADOW_EN;
++      writel(val, prg->regs + IPU_PRG_CTL);
++
++      /* disable address threshold */
++      writel(0xffffffff, prg->regs + IPU_PRG_THD);
++
++      pm_runtime_set_active(dev);
++      pm_runtime_enable(dev);
++
++      prg->dev = dev;
++      platform_set_drvdata(pdev, prg);
++      mutex_lock(&ipu_prg_list_mutex);
++      list_add(&prg->list, &ipu_prg_list);
++      mutex_unlock(&ipu_prg_list_mutex);
++
++      return 0;
++}
++
++static int ipu_prg_remove(struct platform_device *pdev)
++{
++      struct ipu_prg *prg = platform_get_drvdata(pdev);
++
++      mutex_lock(&ipu_prg_list_mutex);
++      list_del(&prg->list);
++      mutex_unlock(&ipu_prg_list_mutex);
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++static int prg_suspend(struct device *dev)
++{
++      struct ipu_prg *prg = dev_get_drvdata(dev);
++
++      clk_disable_unprepare(prg->clk_axi);
++      clk_disable_unprepare(prg->clk_ipg);
++
++      return 0;
++}
++
++static int prg_resume(struct device *dev)
++{
++      struct ipu_prg *prg = dev_get_drvdata(dev);
++      int ret;
++
++      ret = clk_prepare_enable(prg->clk_ipg);
++      if (ret)
++              return ret;
++
++      ret = clk_prepare_enable(prg->clk_axi);
++      if (ret) {
++              clk_disable_unprepare(prg->clk_ipg);
++              return ret;
++      }
++
++      return 0;
++}
++#endif
++
++static const struct dev_pm_ops prg_pm_ops = {
++      SET_RUNTIME_PM_OPS(prg_suspend, prg_resume, NULL)
++};
++
++static const struct of_device_id ipu_prg_dt_ids[] = {
++      { .compatible = "fsl,imx6qp-prg", },
++      { /* sentinel */ },
++};
++
++struct platform_driver ipu_prg_drv = {
++      .probe          = ipu_prg_probe,
++      .remove         = ipu_prg_remove,
++      .driver         = {
++              .name   = "imx-ipu-prg",
++              .pm     = &prg_pm_ops,
++              .of_match_table = ipu_prg_dt_ids,
++      },
++};
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/ipu-prv.h
+@@ -0,0 +1,274 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++#ifndef __IPU_PRV_H__
++#define __IPU_PRV_H__
++
++struct ipu_soc;
++
++#include <linux/types.h>
++#include <linux/device.h>
++#include <linux/clk.h>
++#include <linux/platform_device.h>
++
++#include <video/imx-ipu-v3.h>
++
++#define IPU_MCU_T_DEFAULT     8
++#define IPU_CM_IDMAC_REG_OFS  0x00008000
++#define IPU_CM_IC_REG_OFS     0x00020000
++#define IPU_CM_IRT_REG_OFS    0x00028000
++#define IPU_CM_CSI0_REG_OFS   0x00030000
++#define IPU_CM_CSI1_REG_OFS   0x00038000
++#define IPU_CM_SMFC_REG_OFS   0x00050000
++#define IPU_CM_DC_REG_OFS     0x00058000
++#define IPU_CM_DMFC_REG_OFS   0x00060000
++
++/* Register addresses */
++/* IPU Common registers */
++#define IPU_CM_REG(offset)    (offset)
++
++#define IPU_CONF                      IPU_CM_REG(0)
++
++#define IPU_SRM_PRI1                  IPU_CM_REG(0x00a0)
++#define IPU_SRM_PRI2                  IPU_CM_REG(0x00a4)
++#define IPU_FS_PROC_FLOW1             IPU_CM_REG(0x00a8)
++#define IPU_FS_PROC_FLOW2             IPU_CM_REG(0x00ac)
++#define IPU_FS_PROC_FLOW3             IPU_CM_REG(0x00b0)
++#define IPU_FS_DISP_FLOW1             IPU_CM_REG(0x00b4)
++#define IPU_FS_DISP_FLOW2             IPU_CM_REG(0x00b8)
++#define IPU_SKIP                      IPU_CM_REG(0x00bc)
++#define IPU_DISP_ALT_CONF             IPU_CM_REG(0x00c0)
++#define IPU_DISP_GEN                  IPU_CM_REG(0x00c4)
++#define IPU_DISP_ALT1                 IPU_CM_REG(0x00c8)
++#define IPU_DISP_ALT2                 IPU_CM_REG(0x00cc)
++#define IPU_DISP_ALT3                 IPU_CM_REG(0x00d0)
++#define IPU_DISP_ALT4                 IPU_CM_REG(0x00d4)
++#define IPU_SNOOP                     IPU_CM_REG(0x00d8)
++#define IPU_MEM_RST                   IPU_CM_REG(0x00dc)
++#define IPU_PM                                IPU_CM_REG(0x00e0)
++#define IPU_GPR                               IPU_CM_REG(0x00e4)
++#define IPU_CHA_DB_MODE_SEL(ch)               IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
++#define IPU_ALT_CHA_DB_MODE_SEL(ch)   IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
++#define IPU_CHA_CUR_BUF(ch)           IPU_CM_REG(0x023C + 4 * ((ch) / 32))
++#define IPU_ALT_CUR_BUF0              IPU_CM_REG(0x0244)
++#define IPU_ALT_CUR_BUF1              IPU_CM_REG(0x0248)
++#define IPU_SRM_STAT                  IPU_CM_REG(0x024C)
++#define IPU_PROC_TASK_STAT            IPU_CM_REG(0x0250)
++#define IPU_DISP_TASK_STAT            IPU_CM_REG(0x0254)
++#define IPU_CHA_BUF0_RDY(ch)          IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
++#define IPU_CHA_BUF1_RDY(ch)          IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
++#define IPU_CHA_BUF2_RDY(ch)          IPU_CM_REG(0x0288 + 4 * ((ch) / 32))
++#define IPU_ALT_CHA_BUF0_RDY(ch)      IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
++#define IPU_ALT_CHA_BUF1_RDY(ch)      IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
++
++#define IPU_INT_CTRL(n)               IPU_CM_REG(0x003C + 4 * (n))
++#define IPU_INT_STAT(n)               IPU_CM_REG(0x0200 + 4 * (n))
++
++/* SRM_PRI2 */
++#define DP_S_SRM_MODE_MASK            (0x3 << 3)
++#define DP_S_SRM_MODE_NOW             (0x3 << 3)
++#define DP_S_SRM_MODE_NEXT_FRAME      (0x1 << 3)
++
++/* FS_PROC_FLOW1 */
++#define FS_PRPENC_ROT_SRC_SEL_MASK    (0xf << 0)
++#define FS_PRPENC_ROT_SRC_SEL_ENC             (0x7 << 0)
++#define FS_PRPVF_ROT_SRC_SEL_MASK     (0xf << 8)
++#define FS_PRPVF_ROT_SRC_SEL_VF                       (0x8 << 8)
++#define FS_PP_SRC_SEL_MASK            (0xf << 12)
++#define FS_PP_ROT_SRC_SEL_MASK                (0xf << 16)
++#define FS_PP_ROT_SRC_SEL_PP                  (0x5 << 16)
++#define FS_VDI1_SRC_SEL_MASK          (0x3 << 20)
++#define FS_VDI3_SRC_SEL_MASK          (0x3 << 20)
++#define FS_PRP_SRC_SEL_MASK           (0xf << 24)
++#define FS_VDI_SRC_SEL_MASK           (0x3 << 28)
++#define FS_VDI_SRC_SEL_CSI_DIRECT             (0x1 << 28)
++#define FS_VDI_SRC_SEL_VDOA                   (0x2 << 28)
++
++/* FS_PROC_FLOW2 */
++#define FS_PRP_ENC_DEST_SEL_MASK      (0xf << 0)
++#define FS_PRP_ENC_DEST_SEL_IRT_ENC           (0x1 << 0)
++#define FS_PRPVF_DEST_SEL_MASK                (0xf << 4)
++#define FS_PRPVF_DEST_SEL_IRT_VF              (0x1 << 4)
++#define FS_PRPVF_ROT_DEST_SEL_MASK    (0xf << 8)
++#define FS_PP_DEST_SEL_MASK           (0xf << 12)
++#define FS_PP_DEST_SEL_IRT_PP                 (0x3 << 12)
++#define FS_PP_ROT_DEST_SEL_MASK               (0xf << 16)
++#define FS_PRPENC_ROT_DEST_SEL_MASK   (0xf << 20)
++#define FS_PRP_DEST_SEL_MASK          (0xf << 24)
++
++#define IPU_DI0_COUNTER_RELEASE                       (1 << 24)
++#define IPU_DI1_COUNTER_RELEASE                       (1 << 25)
++
++#define IPU_IDMAC_REG(offset) (offset)
++
++#define IDMAC_CONF                    IPU_IDMAC_REG(0x0000)
++#define IDMAC_CHA_EN(ch)              IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
++#define IDMAC_SEP_ALPHA                       IPU_IDMAC_REG(0x000c)
++#define IDMAC_ALT_SEP_ALPHA           IPU_IDMAC_REG(0x0010)
++#define IDMAC_CHA_PRI(ch)             IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
++#define IDMAC_WM_EN(ch)                       IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32))
++#define IDMAC_CH_LOCK_EN_1            IPU_IDMAC_REG(0x0024)
++#define IDMAC_CH_LOCK_EN_2            IPU_IDMAC_REG(0x0028)
++#define IDMAC_SUB_ADDR_0              IPU_IDMAC_REG(0x002c)
++#define IDMAC_SUB_ADDR_1              IPU_IDMAC_REG(0x0030)
++#define IDMAC_SUB_ADDR_2              IPU_IDMAC_REG(0x0034)
++#define IDMAC_BAND_EN(ch)             IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32))
++#define IDMAC_CHA_BUSY(ch)            IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32))
++
++#define IPU_NUM_IRQS  (32 * 15)
++
++enum ipu_modules {
++      IPU_CONF_CSI0_EN                = (1 << 0),
++      IPU_CONF_CSI1_EN                = (1 << 1),
++      IPU_CONF_IC_EN                  = (1 << 2),
++      IPU_CONF_ROT_EN                 = (1 << 3),
++      IPU_CONF_ISP_EN                 = (1 << 4),
++      IPU_CONF_DP_EN                  = (1 << 5),
++      IPU_CONF_DI0_EN                 = (1 << 6),
++      IPU_CONF_DI1_EN                 = (1 << 7),
++      IPU_CONF_SMFC_EN                = (1 << 8),
++      IPU_CONF_DC_EN                  = (1 << 9),
++      IPU_CONF_DMFC_EN                = (1 << 10),
++
++      IPU_CONF_VDI_EN                 = (1 << 12),
++
++      IPU_CONF_IDMAC_DIS              = (1 << 22),
++
++      IPU_CONF_IC_DMFC_SEL            = (1 << 25),
++      IPU_CONF_IC_DMFC_SYNC           = (1 << 26),
++      IPU_CONF_VDI_DMFC_SYNC          = (1 << 27),
++
++      IPU_CONF_CSI0_DATA_SOURCE       = (1 << 28),
++      IPU_CONF_CSI1_DATA_SOURCE       = (1 << 29),
++      IPU_CONF_IC_INPUT               = (1 << 30),
++      IPU_CONF_CSI_SEL                = (1 << 31),
++};
++
++struct ipuv3_channel {
++      unsigned int num;
++      struct ipu_soc *ipu;
++      struct list_head list;
++};
++
++struct ipu_cpmem;
++struct ipu_csi;
++struct ipu_dc_priv;
++struct ipu_dmfc_priv;
++struct ipu_di;
++struct ipu_ic_priv;
++struct ipu_vdi;
++struct ipu_image_convert_priv;
++struct ipu_smfc_priv;
++struct ipu_pre;
++struct ipu_prg;
++
++struct ipu_devtype;
++
++struct ipu_soc {
++      struct device           *dev;
++      const struct ipu_devtype        *devtype;
++      enum ipuv3_type         ipu_type;
++      spinlock_t              lock;
++      struct mutex            channel_lock;
++      struct list_head        channels;
++
++      void __iomem            *cm_reg;
++      void __iomem            *idmac_reg;
++
++      int                     id;
++      int                     usecount;
++
++      struct clk              *clk;
++
++      int                     irq_sync;
++      int                     irq_err;
++      struct irq_domain       *domain;
++
++      struct ipu_cpmem        *cpmem_priv;
++      struct ipu_dc_priv      *dc_priv;
++      struct ipu_dp_priv      *dp_priv;
++      struct ipu_dmfc_priv    *dmfc_priv;
++      struct ipu_di           *di_priv[2];
++      struct ipu_csi          *csi_priv[2];
++      struct ipu_ic_priv      *ic_priv;
++      struct ipu_vdi          *vdi_priv;
++      struct ipu_image_convert_priv *image_convert_priv;
++      struct ipu_smfc_priv    *smfc_priv;
++      struct ipu_prg          *prg_priv;
++};
++
++static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
++{
++      return readl(ipu->idmac_reg + offset);
++}
++
++static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
++                                 unsigned offset)
++{
++      writel(value, ipu->idmac_reg + offset);
++}
++
++void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync);
++
++int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
++int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
++
++bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno);
++
++int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
++               unsigned long base, u32 module, struct clk *clk_ipu);
++void ipu_csi_exit(struct ipu_soc *ipu, int id);
++
++int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
++              unsigned long base, unsigned long tpmem_base);
++void ipu_ic_exit(struct ipu_soc *ipu);
++
++int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
++               unsigned long base, u32 module);
++void ipu_vdi_exit(struct ipu_soc *ipu);
++
++int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev);
++void ipu_image_convert_exit(struct ipu_soc *ipu);
++
++int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
++              unsigned long base, u32 module, struct clk *ipu_clk);
++void ipu_di_exit(struct ipu_soc *ipu, int id);
++
++int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
++              struct clk *ipu_clk);
++void ipu_dmfc_exit(struct ipu_soc *ipu);
++
++int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
++void ipu_dp_exit(struct ipu_soc *ipu);
++
++int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
++              unsigned long template_base);
++void ipu_dc_exit(struct ipu_soc *ipu);
++
++int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
++void ipu_cpmem_exit(struct ipu_soc *ipu);
++
++int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
++void ipu_smfc_exit(struct ipu_soc *ipu);
++
++struct ipu_pre *ipu_pre_lookup_by_phandle(struct device *dev, const char *name,
++                                        int index);
++int ipu_pre_get_available_count(void);
++int ipu_pre_get(struct ipu_pre *pre);
++void ipu_pre_put(struct ipu_pre *pre);
++u32 ipu_pre_get_baddr(struct ipu_pre *pre);
++void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
++                     unsigned int height, unsigned int stride, u32 format,
++                     uint64_t modifier, unsigned int bufaddr);
++void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr);
++bool ipu_pre_update_pending(struct ipu_pre *pre);
++
++struct ipu_prg *ipu_prg_lookup_by_phandle(struct device *dev, const char *name,
++                                        int ipu_id);
++
++extern struct platform_driver ipu_pre_drv;
++extern struct platform_driver ipu_prg_drv;
++
++#endif                                /* __IPU_PRV_H__ */
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/ipu-smfc.c
+@@ -0,0 +1,202 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++#include <linux/export.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/errno.h>
++#include <linux/spinlock.h>
++#include <linux/delay.h>
++#include <linux/clk.h>
++#include <video/imx-ipu-v3.h>
++
++#include "ipu-prv.h"
++
++struct ipu_smfc {
++      struct ipu_smfc_priv *priv;
++      int chno;
++      bool inuse;
++};
++
++struct ipu_smfc_priv {
++      void __iomem *base;
++      spinlock_t lock;
++      struct ipu_soc *ipu;
++      struct ipu_smfc channel[4];
++      int use_count;
++};
++
++/*SMFC Registers */
++#define SMFC_MAP      0x0000
++#define SMFC_WMC      0x0004
++#define SMFC_BS               0x0008
++
++int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
++{
++      struct ipu_smfc_priv *priv = smfc->priv;
++      unsigned long flags;
++      u32 val, shift;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      shift = smfc->chno * 4;
++      val = readl(priv->base + SMFC_BS);
++      val &= ~(0xf << shift);
++      val |= burstsize << shift;
++      writel(val, priv->base + SMFC_BS);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);
++
++int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
++{
++      struct ipu_smfc_priv *priv = smfc->priv;
++      unsigned long flags;
++      u32 val, shift;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      shift = smfc->chno * 3;
++      val = readl(priv->base + SMFC_MAP);
++      val &= ~(0x7 << shift);
++      val |= ((csi_id << 2) | mipi_id) << shift;
++      writel(val, priv->base + SMFC_MAP);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
++
++int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level)
++{
++      struct ipu_smfc_priv *priv = smfc->priv;
++      unsigned long flags;
++      u32 val, shift;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0);
++      val = readl(priv->base + SMFC_WMC);
++      val &= ~(0x3f << shift);
++      val |= ((clr_level << 3) | set_level) << shift;
++      writel(val, priv->base + SMFC_WMC);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark);
++
++int ipu_smfc_enable(struct ipu_smfc *smfc)
++{
++      struct ipu_smfc_priv *priv = smfc->priv;
++      unsigned long flags;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      if (!priv->use_count)
++              ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);
++
++      priv->use_count++;
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_smfc_enable);
++
++int ipu_smfc_disable(struct ipu_smfc *smfc)
++{
++      struct ipu_smfc_priv *priv = smfc->priv;
++      unsigned long flags;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      priv->use_count--;
++
++      if (!priv->use_count)
++              ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);
++
++      if (priv->use_count < 0)
++              priv->use_count = 0;
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_smfc_disable);
++
++struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
++{
++      struct ipu_smfc_priv *priv = ipu->smfc_priv;
++      struct ipu_smfc *smfc, *ret;
++      unsigned long flags;
++
++      if (chno >= 4)
++              return ERR_PTR(-EINVAL);
++
++      smfc = &priv->channel[chno];
++      ret = smfc;
++
++      spin_lock_irqsave(&priv->lock, flags);
++
++      if (smfc->inuse) {
++              ret = ERR_PTR(-EBUSY);
++              goto unlock;
++      }
++
++      smfc->inuse = true;
++unlock:
++      spin_unlock_irqrestore(&priv->lock, flags);
++      return ret;
++}
++EXPORT_SYMBOL_GPL(ipu_smfc_get);
++
++void ipu_smfc_put(struct ipu_smfc *smfc)
++{
++      struct ipu_smfc_priv *priv = smfc->priv;
++      unsigned long flags;
++
++      spin_lock_irqsave(&priv->lock, flags);
++      smfc->inuse = false;
++      spin_unlock_irqrestore(&priv->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_smfc_put);
++
++int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
++                unsigned long base)
++{
++      struct ipu_smfc_priv *priv;
++      int i;
++
++      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++
++      ipu->smfc_priv = priv;
++      spin_lock_init(&priv->lock);
++      priv->ipu = ipu;
++
++      priv->base = devm_ioremap(dev, base, PAGE_SIZE);
++      if (!priv->base)
++              return -ENOMEM;
++
++      for (i = 0; i < 4; i++) {
++              priv->channel[i].priv = priv;
++              priv->channel[i].chno = i;
++      }
++
++      pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
++
++      return 0;
++}
++
++void ipu_smfc_exit(struct ipu_soc *ipu)
++{
++}
+--- /dev/null
++++ b/drivers/gpu/ipu-v3/ipu-vdi.c
+@@ -0,0 +1,234 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (C) 2012-2016 Mentor Graphics Inc.
++ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
++ */
++#include <linux/io.h>
++#include "ipu-prv.h"
++
++struct ipu_vdi {
++      void __iomem *base;
++      u32 module;
++      spinlock_t lock;
++      int use_count;
++      struct ipu_soc *ipu;
++};
++
++
++/* VDI Register Offsets */
++#define VDI_FSIZE 0x0000
++#define VDI_C     0x0004
++
++/* VDI Register Fields */
++#define VDI_C_CH_420             (0 << 1)
++#define VDI_C_CH_422             (1 << 1)
++#define VDI_C_MOT_SEL_MASK       (0x3 << 2)
++#define VDI_C_MOT_SEL_FULL       (2 << 2)
++#define VDI_C_MOT_SEL_LOW        (1 << 2)
++#define VDI_C_MOT_SEL_MED        (0 << 2)
++#define VDI_C_BURST_SIZE1_4      (3 << 4)
++#define VDI_C_BURST_SIZE2_4      (3 << 8)
++#define VDI_C_BURST_SIZE3_4      (3 << 12)
++#define VDI_C_BURST_SIZE_MASK    0xF
++#define VDI_C_BURST_SIZE1_OFFSET 4
++#define VDI_C_BURST_SIZE2_OFFSET 8
++#define VDI_C_BURST_SIZE3_OFFSET 12
++#define VDI_C_VWM1_SET_1         (0 << 16)
++#define VDI_C_VWM1_SET_2         (1 << 16)
++#define VDI_C_VWM1_CLR_2         (1 << 19)
++#define VDI_C_VWM3_SET_1         (0 << 22)
++#define VDI_C_VWM3_SET_2         (1 << 22)
++#define VDI_C_VWM3_CLR_2         (1 << 25)
++#define VDI_C_TOP_FIELD_MAN_1    (1 << 30)
++#define VDI_C_TOP_FIELD_AUTO_1   (1 << 31)
++
++static inline u32 ipu_vdi_read(struct ipu_vdi *vdi, unsigned int offset)
++{
++      return readl(vdi->base + offset);
++}
++
++static inline void ipu_vdi_write(struct ipu_vdi *vdi, u32 value,
++                               unsigned int offset)
++{
++      writel(value, vdi->base + offset);
++}
++
++void ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field)
++{
++      bool top_field_0 = false;
++      unsigned long flags;
++      u32 reg;
++
++      switch (field) {
++      case V4L2_FIELD_INTERLACED_TB:
++      case V4L2_FIELD_SEQ_TB:
++      case V4L2_FIELD_TOP:
++              top_field_0 = true;
++              break;
++      case V4L2_FIELD_INTERLACED_BT:
++      case V4L2_FIELD_SEQ_BT:
++      case V4L2_FIELD_BOTTOM:
++              top_field_0 = false;
++              break;
++      default:
++              top_field_0 = (std & V4L2_STD_525_60) ? true : false;
++              break;
++      }
++
++      spin_lock_irqsave(&vdi->lock, flags);
++
++      reg = ipu_vdi_read(vdi, VDI_C);
++      if (top_field_0)
++              reg &= ~(VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1);
++      else
++              reg |= VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1;
++      ipu_vdi_write(vdi, reg, VDI_C);
++
++      spin_unlock_irqrestore(&vdi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_set_field_order);
++
++void ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel)
++{
++      unsigned long flags;
++      u32 reg;
++
++      spin_lock_irqsave(&vdi->lock, flags);
++
++      reg = ipu_vdi_read(vdi, VDI_C);
++
++      reg &= ~VDI_C_MOT_SEL_MASK;
++
++      switch (motion_sel) {
++      case MED_MOTION:
++              reg |= VDI_C_MOT_SEL_MED;
++              break;
++      case HIGH_MOTION:
++              reg |= VDI_C_MOT_SEL_FULL;
++              break;
++      default:
++              reg |= VDI_C_MOT_SEL_LOW;
++              break;
++      }
++
++      ipu_vdi_write(vdi, reg, VDI_C);
++
++      spin_unlock_irqrestore(&vdi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_set_motion);
++
++void ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres)
++{
++      unsigned long flags;
++      u32 pixel_fmt, reg;
++
++      spin_lock_irqsave(&vdi->lock, flags);
++
++      reg = ((yres - 1) << 16) | (xres - 1);
++      ipu_vdi_write(vdi, reg, VDI_FSIZE);
++
++      /*
++       * Full motion, only vertical filter is used.
++       * Burst size is 4 accesses
++       */
++      if (code == MEDIA_BUS_FMT_UYVY8_2X8 ||
++          code == MEDIA_BUS_FMT_UYVY8_1X16 ||
++          code == MEDIA_BUS_FMT_YUYV8_2X8 ||
++          code == MEDIA_BUS_FMT_YUYV8_1X16)
++              pixel_fmt = VDI_C_CH_422;
++      else
++              pixel_fmt = VDI_C_CH_420;
++
++      reg = ipu_vdi_read(vdi, VDI_C);
++      reg |= pixel_fmt;
++      reg |= VDI_C_BURST_SIZE2_4;
++      reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_CLR_2;
++      reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_CLR_2;
++      ipu_vdi_write(vdi, reg, VDI_C);
++
++      spin_unlock_irqrestore(&vdi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_setup);
++
++void ipu_vdi_unsetup(struct ipu_vdi *vdi)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&vdi->lock, flags);
++      ipu_vdi_write(vdi, 0, VDI_FSIZE);
++      ipu_vdi_write(vdi, 0, VDI_C);
++      spin_unlock_irqrestore(&vdi->lock, flags);
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_unsetup);
++
++int ipu_vdi_enable(struct ipu_vdi *vdi)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&vdi->lock, flags);
++
++      if (!vdi->use_count)
++              ipu_module_enable(vdi->ipu, vdi->module);
++
++      vdi->use_count++;
++
++      spin_unlock_irqrestore(&vdi->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_enable);
++
++int ipu_vdi_disable(struct ipu_vdi *vdi)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&vdi->lock, flags);
++
++      if (vdi->use_count) {
++              if (!--vdi->use_count)
++                      ipu_module_disable(vdi->ipu, vdi->module);
++      }
++
++      spin_unlock_irqrestore(&vdi->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_disable);
++
++struct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu)
++{
++      return ipu->vdi_priv;
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_get);
++
++void ipu_vdi_put(struct ipu_vdi *vdi)
++{
++}
++EXPORT_SYMBOL_GPL(ipu_vdi_put);
++
++int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
++               unsigned long base, u32 module)
++{
++      struct ipu_vdi *vdi;
++
++      vdi = devm_kzalloc(dev, sizeof(*vdi), GFP_KERNEL);
++      if (!vdi)
++              return -ENOMEM;
++
++      ipu->vdi_priv = vdi;
++
++      spin_lock_init(&vdi->lock);
++      vdi->module = module;
++      vdi->base = devm_ioremap(dev, base, PAGE_SIZE);
++      if (!vdi->base)
++              return -ENOMEM;
++
++      dev_dbg(dev, "VDI base: 0x%08lx remapped to %p\n", base, vdi->base);
++      vdi->ipu = ipu;
++
++      return 0;
++}
++
++void ipu_vdi_exit(struct ipu_soc *ipu)
++{
++}
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -15,7 +15,7 @@ source "drivers/char/agp/Kconfig"
+ source "drivers/gpu/vga/Kconfig"
+ source "drivers/gpu/host1x/Kconfig"
+-source "drivers/gpu/imx/Kconfig"
++source "drivers/gpu/ipu-v3/Kconfig"
+ source "drivers/gpu/drm/Kconfig"
diff --git a/target/linux/layerscape/patches-5.4/805-display-0050-Revert-drm-imx-Revert-a-patch-which-merges-imx-drm-c.patch b/target/linux/layerscape/patches-5.4/805-display-0050-Revert-drm-imx-Revert-a-patch-which-merges-imx-drm-c.patch
new file mode 100644 (file)
index 0000000..c04aede
--- /dev/null
@@ -0,0 +1,107 @@
+From c0dd62d0bc48c0d9e833116ea2696cc000633897 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Mon, 2 Mar 2020 13:46:39 +0800
+Subject: [PATCH] Revert "drm/imx: Revert a patch which merges imx-drm-core and
+ ipuv3-crtc in one module"
+
+This reverts commit 1e7f3c4066d9afb4bc036b9d4b6f5b18f3c918c7.
+---
+ drivers/gpu/drm/imx/Kconfig        |  7 -------
+ drivers/gpu/drm/imx/Makefile       |  4 +---
+ drivers/gpu/drm/imx/imx-drm-core.c | 18 +++++++++++++++++-
+ drivers/gpu/drm/imx/imx-drm.h      |  2 ++
+ drivers/gpu/drm/imx/ipuv3-crtc.c   |  8 +-------
+ 5 files changed, 21 insertions(+), 18 deletions(-)
+
+--- a/drivers/gpu/drm/imx/Kconfig
++++ b/drivers/gpu/drm/imx/Kconfig
+@@ -33,13 +33,6 @@ config DRM_IMX_LDB
+         Choose this to enable the internal LVDS Display Bridge (LDB)
+         found on i.MX53 and i.MX6 processors.
+-config DRM_IMX_IPUV3
+-      tristate
+-      depends on DRM_IMX
+-      depends on IMX_IPUV3_CORE
+-      default y if DRM_IMX=y
+-      default m if DRM_IMX=m
+-
+ config DRM_IMX_HDMI
+       tristate "Freescale i.MX DRM HDMI"
+       select DRM_DW_HDMI
+--- a/drivers/gpu/drm/imx/Makefile
++++ b/drivers/gpu/drm/imx/Makefile
+@@ -1,6 +1,6 @@
+ # SPDX-License-Identifier: GPL-2.0
+-imxdrm-objs := imx-drm-core.o
++imxdrm-objs := imx-drm-core.o ipuv3-crtc.o ipuv3-plane.o
+ obj-$(CONFIG_DRM_IMX) += imxdrm.o
+@@ -8,7 +8,5 @@ obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) +
+ obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
+ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
+-imx-ipuv3-crtc-objs  := ipuv3-crtc.o ipuv3-plane.o
+-obj-$(CONFIG_DRM_IMX_IPUV3)   += imx-ipuv3-crtc.o
+ obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
+ obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdn-mhdp-imxdrv.o cdn-mhdp-dp-phy.o cdn-mhdp-hdmi-phy.o cdn-mhdp-imx8qm.o cdn-mhdp-ls1028a.o
+--- a/drivers/gpu/drm/imx/imx-drm-core.c
++++ b/drivers/gpu/drm/imx/imx-drm-core.c
+@@ -361,7 +361,23 @@ static struct platform_driver imx_drm_pd
+               .of_match_table = imx_drm_dt_ids,
+       },
+ };
+-module_platform_driver(imx_drm_pdrv);
++
++static struct platform_driver * const drivers[] = {
++      &imx_drm_pdrv,
++      &ipu_drm_driver,
++};
++
++static int __init imx_drm_init(void)
++{
++      return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
++}
++module_init(imx_drm_init);
++
++static void __exit imx_drm_exit(void)
++{
++      platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
++}
++module_exit(imx_drm_exit);
+ MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+ MODULE_DESCRIPTION("i.MX drm driver core");
+--- a/drivers/gpu/drm/imx/imx-drm.h
++++ b/drivers/gpu/drm/imx/imx-drm.h
+@@ -28,6 +28,8 @@ int imx_drm_init_drm(struct platform_dev
+               int preferred_bpp);
+ int imx_drm_exit_drm(void);
++extern struct platform_driver ipu_drm_driver;
++
+ void imx_drm_mode_config_init(struct drm_device *drm);
+ struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
+--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
++++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
+@@ -492,16 +492,10 @@ static int ipu_drm_remove(struct platfor
+       return 0;
+ }
+-static struct platform_driver ipu_drm_driver = {
++struct platform_driver ipu_drm_driver = {
+       .driver = {
+               .name = "imx-ipuv3-crtc",
+       },
+       .probe = ipu_drm_probe,
+       .remove = ipu_drm_remove,
+ };
+-module_platform_driver(ipu_drm_driver);
+-
+-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+-MODULE_DESCRIPTION(DRIVER_DESC);
+-MODULE_LICENSE("GPL");
+-MODULE_ALIAS("platform:imx-ipuv3-crtc");
diff --git a/target/linux/layerscape/patches-5.4/805-display-0051-LF-296-drm-mhdp-build-mhdp-sub-modules-into-one-driv.patch b/target/linux/layerscape/patches-5.4/805-display-0051-LF-296-drm-mhdp-build-mhdp-sub-modules-into-one-driv.patch
new file mode 100644 (file)
index 0000000..5596fc0
--- /dev/null
@@ -0,0 +1,75 @@
+From 2b8caa86c969cb14e295e60ddc21995b47dc2efe Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Mon, 2 Dec 2019 16:14:09 +0800
+Subject: [PATCH] LF-296: drm: mhdp: build mhdp sub-modules into one driver
+ module
+
+mhdp kernel driver support build as module.
+All mhdp sub-modules are built into one driver module.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+Reviewed-by: Robby Cai <robby.cai@nxp.com>
+(cherry picked from commit f516f7769a52fdda185920a89efa3de9a1ddb9e8)
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/Makefile | 14 +++++++++-----
+ drivers/gpu/drm/imx/Makefile            |  4 +++-
+ include/drm/bridge/cdns-mhdp-common.h   |  4 ----
+ 3 files changed, 12 insertions(+), 10 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/Makefile
++++ b/drivers/gpu/drm/bridge/cadence/Makefile
+@@ -1,5 +1,9 @@
+-obj-$(CONFIG_DRM_CDNS_MHDP) += cdns-mhdp-common.o cdns-mhdp-hdmi.o
+-obj-$(CONFIG_DRM_CDNS_HDMI) += cdns-hdmi-core.o
+-obj-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
+-obj-$(CONFIG_DRM_CDNS_AUDIO) += cdns-mhdp-audio.o
+-obj-$(CONFIG_DRM_CDNS_HDMI_CEC) += cdns-mhdp-cec.o
++
++cdns_mhdp_drmcore-y := cdns-mhdp-common.o cdns-mhdp-hdmi.o
++
++cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_HDMI) += cdns-hdmi-core.o
++cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
++cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_AUDIO) += cdns-mhdp-audio.o
++cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_HDMI_CEC) += cdns-mhdp-cec.o
++
++obj-$(CONFIG_DRM_CDNS_MHDP)           += cdns_mhdp_drmcore.o
+--- a/drivers/gpu/drm/imx/Makefile
++++ b/drivers/gpu/drm/imx/Makefile
+@@ -9,4 +9,6 @@ obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
+ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
+ obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
+-obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdn-mhdp-imxdrv.o cdn-mhdp-dp-phy.o cdn-mhdp-hdmi-phy.o cdn-mhdp-imx8qm.o cdn-mhdp-ls1028a.o
++
++cdns_mhdp_imx-objs := cdn-mhdp-imxdrv.o cdn-mhdp-dp-phy.o cdn-mhdp-hdmi-phy.o cdn-mhdp-imx8qm.o cdn-mhdp-ls1028a.o
++obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdns_mhdp_imx.o
+--- a/include/drm/bridge/cdns-mhdp-common.h
++++ b/include/drm/bridge/cdns-mhdp-common.h
+@@ -621,7 +621,6 @@ struct cdns_mhdp_connector {
+       struct cdns_mhdp_bridge *bridge;
+ };
+-#ifdef CONFIG_DRM_CDNS_HDMI_CEC
+ struct cdns_mhdp_cec {
+        struct cec_adapter *adap;
+        struct device *dev;
+@@ -630,7 +629,6 @@ struct cdns_mhdp_cec {
+        struct cec_msg msg;
+        struct task_struct *cec_worker;
+ };
+-#endif
+ struct cdns_plat_data {
+       /* Vendor PHY support */
+@@ -704,9 +702,7 @@ struct cdns_mhdp_device {
+                       bool can_mst;
+               } dp;
+               struct _hdmi_data {
+-#ifdef CONFIG_DRM_CDNS_HDMI_CEC
+                       struct cdns_mhdp_cec cec;
+-#endif
+                       u32 char_rate;
+                       u32 hdmi_type;
+               } hdmi;
diff --git a/target/linux/layerscape/patches-5.4/805-display-0052-LF-323-1-drm-bridge-cdns-move-link-training-to-bridg.patch b/target/linux/layerscape/patches-5.4/805-display-0052-LF-323-1-drm-bridge-cdns-move-link-training-to-bridg.patch
new file mode 100644 (file)
index 0000000..4dcd5c8
--- /dev/null
@@ -0,0 +1,74 @@
+From fa76cd6f0ed305fb2870083842b1ff7bcf027655 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Mon, 9 Dec 2019 17:52:35 +0800
+Subject: [PATCH] LF-323-1: drm/bridge/cdns: move link training to bridge
+ enable function
+
+Move link training and video enable functions from mode_set to
+bridge_enable. it is more reasonable.
+cdns_dp_mode_set don't needed in HPD thread, DP link training will
+resetup in bridge_enable when cable connecting.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+Reviewed-by: Robby Cai <robby.cai@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 34 +++++++++++++--------------
+ 1 file changed, 16 insertions(+), 18 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -178,19 +178,6 @@ static void cdns_dp_mode_set(struct cdns
+               return;
+       }
+-      /* Link trainning */
+-      ret = cdns_mhdp_train_link(mhdp);
+-      if (ret) {
+-              DRM_DEV_ERROR(mhdp->dev, "Failed link train %d\n", ret);
+-              return;
+-      }
+-
+-      ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_VALID);
+-      if (ret) {
+-              DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
+-              return;
+-      }
+-
+       return;
+ }
+@@ -339,6 +326,21 @@ static void cdns_dp_bridge_mode_set(stru
+ static void cdn_hdp_bridge_enable(struct drm_bridge *bridge)
+ {
++      struct cdns_mhdp_device *mhdp = bridge->driver_private;
++      int ret;
++
++      /* Link trainning */
++      ret = cdns_mhdp_train_link(mhdp);
++      if (ret) {
++              DRM_DEV_ERROR(mhdp->dev, "Failed link train %d\n", ret);
++              return;
++      }
++
++      ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_VALID);
++      if (ret) {
++              DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
++              return;
++      }
+ }
+ static void cdn_hdp_bridge_disable(struct drm_bridge *bridge)
+@@ -366,11 +368,7 @@ static void hotplug_work_func(struct wor
+       drm_helper_hpd_irq_event(connector->dev);
+       if (connector->status == connector_status_connected) {
+-              /* reset video mode after cable plugin */
+-              mutex_lock(&mhdp->lock);
+-              cdns_dp_mode_set(mhdp);
+-              mutex_unlock(&mhdp->lock);
+-
++              /* Cable connedted  */
+               DRM_INFO("HDMI/DP Cable Plug In\n");
+               enable_irq(mhdp->irq[IRQ_OUT]);
+       } else if (connector->status == connector_status_disconnected) {
diff --git a/target/linux/layerscape/patches-5.4/805-display-0053-LF-323-2-drm-bridge-cdns-enhance-link-training-stabi.patch b/target/linux/layerscape/patches-5.4/805-display-0053-LF-323-2-drm-bridge-cdns-enhance-link-training-stabi.patch
new file mode 100644 (file)
index 0000000..dec3d78
--- /dev/null
@@ -0,0 +1,36 @@
+From 06b758a32bb5ca164cff60f20173ecd71508c5ae Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Mon, 9 Dec 2019 17:58:29 +0800
+Subject: [PATCH] LF-323-2: drm/bridge/cdns: enhance link training stability
+
+Remove drm_dp_link_power_down from bridge_disable function,
+in case some DP sinks aren't follow DP 1.1 specification
+and can not exit the power saving state within 1 ms.
+Add drm_dp_link_power_up to bridge_enable function,
+make sure DP sinks are power up before link training.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+Reviewed-by: Robby Cai <robby.cai@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -329,6 +329,8 @@ static void cdn_hdp_bridge_enable(struct
+       struct cdns_mhdp_device *mhdp = bridge->driver_private;
+       int ret;
++      drm_dp_link_power_up(&mhdp->dp.aux, &mhdp->dp.link);
++
+       /* Link trainning */
+       ret = cdns_mhdp_train_link(mhdp);
+       if (ret) {
+@@ -348,7 +350,6 @@ static void cdn_hdp_bridge_disable(struc
+       struct cdns_mhdp_device *mhdp = bridge->driver_private;
+       cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
+-      drm_dp_link_power_down(&mhdp->dp.aux, &mhdp->dp.link);
+ }
+ static const struct drm_bridge_funcs cdns_dp_bridge_funcs = {
diff --git a/target/linux/layerscape/patches-5.4/805-display-0054-LF-568-1-drm-bridge-cdns-dp-change-bridge_enable-dis.patch b/target/linux/layerscape/patches-5.4/805-display-0054-LF-568-1-drm-bridge-cdns-dp-change-bridge_enable-dis.patch
new file mode 100644 (file)
index 0000000..a5a1609
--- /dev/null
@@ -0,0 +1,45 @@
+From f5f8d5aeea1919d587de22a2bfa5ba4db8a32ef1 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Fri, 20 Dec 2019 17:11:20 +0800
+Subject: [PATCH] LF-568-1: drm: bridge: cdns: dp: change bridge_enable/disable
+ name
+
+Change the bridge_enable/disable function name.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+Reviewed-by: Robby Cai <robby.cai@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -324,7 +324,7 @@ static void cdns_dp_bridge_mode_set(stru
+       mutex_unlock(&mhdp->lock);
+ }
+-static void cdn_hdp_bridge_enable(struct drm_bridge *bridge)
++static void cdn_dp_bridge_enable(struct drm_bridge *bridge)
+ {
+       struct cdns_mhdp_device *mhdp = bridge->driver_private;
+       int ret;
+@@ -345,7 +345,7 @@ static void cdn_hdp_bridge_enable(struct
+       }
+ }
+-static void cdn_hdp_bridge_disable(struct drm_bridge *bridge)
++static void cdn_dp_bridge_disable(struct drm_bridge *bridge)
+ {     
+       struct cdns_mhdp_device *mhdp = bridge->driver_private;
+@@ -354,8 +354,8 @@ static void cdn_hdp_bridge_disable(struc
+ static const struct drm_bridge_funcs cdns_dp_bridge_funcs = {
+       .attach = cdns_dp_bridge_attach,
+-      .enable = cdn_hdp_bridge_enable,
+-      .disable = cdn_hdp_bridge_disable,
++      .enable = cdn_dp_bridge_enable,
++      .disable = cdn_dp_bridge_disable,
+       .mode_set = cdns_dp_bridge_mode_set,
+       .mode_valid = cdns_dp_bridge_mode_valid,
+ };
diff --git a/target/linux/layerscape/patches-5.4/805-display-0055-LF-568-2-drm-gpu-bridge-cdns-Add-force-mode-set-flag.patch b/target/linux/layerscape/patches-5.4/805-display-0055-LF-568-2-drm-gpu-bridge-cdns-Add-force-mode-set-flag.patch
new file mode 100644 (file)
index 0000000..1113453
--- /dev/null
@@ -0,0 +1,107 @@
+From d13b544c949e85e39f6c1c20485d8f37f5127e59 Mon Sep 17 00:00:00 2001
+From: Sandor Yu <Sandor.yu@nxp.com>
+Date: Fri, 20 Dec 2019 17:31:52 +0800
+Subject: [PATCH] LF-568-2: drm: gpu: bridge: cdns: Add force mode set flag
+
+In DRM framework, when hdmi/dp cable plugout/plugin in the same HDMI
+sink, because the video mode is same, DRM will not call mode_set.
+But for HDMI 2.0 sink the SCDC configurate will lost, and DP sink
+linktraning status will lost too after cable plugout then plugin.
+
+Currently, hdmi/dp driver will call mode_set function in HPD thread,
+But the mode_set function is called out of DRM framework, and it have
+chance to fail.
+In the patch add force_mode_set flag, set the crtc_state->mode_changed
+to force drm call mode_set when cable plugin.
+
+Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-dp-core.c   |  5 +++++
+ drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 12 ++++++++----
+ drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c           |  4 ++++
+ include/drm/bridge/cdns-mhdp-common.h           |  1 +
+ 4 files changed, 18 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+@@ -322,6 +322,9 @@ static void cdns_dp_bridge_mode_set(stru
+       mutex_lock(&mhdp->lock);
+       cdns_dp_mode_set(mhdp);
+       mutex_unlock(&mhdp->lock);
++
++      /* reset force mode set flag */
++      mhdp->force_mode_set = false;
+ }
+ static void cdn_dp_bridge_enable(struct drm_bridge *bridge)
+@@ -375,6 +378,8 @@ static void hotplug_work_func(struct wor
+       } else if (connector->status == connector_status_disconnected) {
+               /* Cable Disconnedted  */
+               DRM_INFO("HDMI/DP Cable Plug Out\n");
++              /* force mode set for cable replugin to recovery DP video modes */
++              mhdp->force_mode_set = true;
+               enable_irq(mhdp->irq[IRQ_IN]);
+       }
+ }
+--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+@@ -178,6 +178,10 @@ void cdns_hdmi_mode_set(struct cdns_mhdp
+       struct drm_display_mode *mode = &mhdp->mode;
+       int ret;
++      /* video mode valid check */
++      if (mode->clock == 0 || mode->hdisplay == 0 ||  mode->vdisplay == 0)
++              return;
++
+       hdmi_lanes_config(mhdp);
+       cdns_mhdp_plat_call(mhdp, pclk_rate);
+@@ -393,6 +397,8 @@ static void cdns_hdmi_bridge_mode_set(st
+       mutex_lock(&mhdp->lock);
+       cdns_hdmi_mode_set(mhdp);
+       mutex_unlock(&mhdp->lock);
++      /* reset force mode set flag */
++      mhdp->force_mode_set = false;
+ }
+ bool cdns_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
+@@ -467,14 +473,12 @@ static void hotplug_work_func(struct wor
+       if (connector->status == connector_status_connected) {
+               DRM_INFO("HDMI Cable Plug In\n");
+-              /* reset video mode after cable plugin */
+-              mutex_lock(&mhdp->lock);
+-              cdns_hdmi_mode_set(mhdp);
+-              mutex_unlock(&mhdp->lock);
+               enable_irq(mhdp->irq[IRQ_OUT]);
+       } else if (connector->status == connector_status_disconnected) {
+               /* Cable Disconnedted  */
+               DRM_INFO("HDMI Cable Plug Out\n");
++              /* force mode set for cable replugin to recovery HDMI2.0 video modes */
++              mhdp->force_mode_set = true;
+               enable_irq(mhdp->irq[IRQ_IN]);
+       }
+ }
+--- a/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
+@@ -40,6 +40,10 @@ static int cdns_mhdp_imx_encoder_atomic_
+       if (mhdp->plat_data->video_format != 0)
+               imx_crtc_state->bus_format = mhdp->plat_data->video_format;
++
++      if (mhdp->force_mode_set)
++              crtc_state->mode_changed = true;
++
+       return 0;
+ }
+--- a/include/drm/bridge/cdns-mhdp-common.h
++++ b/include/drm/bridge/cdns-mhdp-common.h
+@@ -684,6 +684,7 @@ struct cdns_mhdp_device {
+       bool link_up;
+       bool power_up;
+       bool plugged;
++      bool force_mode_set;
+       bool is_hpd;
+       bool is_ls1028a;
+       struct mutex lock;
diff --git a/target/linux/layerscape/patches-5.4/805-display-0056-LF-794-3-gpu-cdn-imx8qm-Add-firmware-loading-support.patch b/target/linux/layerscape/patches-5.4/805-display-0056-LF-794-3-gpu-cdn-imx8qm-Add-firmware-loading-support.patch
new file mode 100644 (file)
index 0000000..ca7f488
--- /dev/null
@@ -0,0 +1,268 @@
+From 020578dd022e5d869db52e79c5aba95c1f1a84ec Mon Sep 17 00:00:00 2001
+From: Abel Vesa <abel.vesa@nxp.com>
+Date: Wed, 11 Dec 2019 09:21:23 +0200
+Subject: [PATCH] LF-794-3 gpu: cdn: imx8qm: Add firmware loading support
+
+This allows the  HDP i.MX8QM driver to load the firmware on init
+and resume. In order to have backward compatibility, if there is
+no firmware-name property defined in the hdmi node, the driver
+probing sequence skips the firmware loading.
+
+Also, if u-boot has loaded already a firmware, we run with that
+but when probing the driver, the request_firmware_nowait is used
+to locate and keep safe the firmware for when suspend/resume happens.
+
+This leads to 4 possible scenarios:
+
+1. u-boot loads the firmware, the kernel driver finds the firmware
+when rootfs is mounted. This is the most desirable scenario. Also
+this is the only scenario that allows the hdmi to work after resume.
+
+2. u-boot loads the firmware, the kernel driver _doesn't_ find
+the firmware in rootfs. If there is no suspend ever happening,
+the kernel driver will keep using the firmware that was loaded by
+u-boot. On the first suspend/resume, the firmware is lost
+because the HDMI IP gets powered down.
+
+3. u-boot doesn't load the firmare, the kernel driver probing
+tries to load the firmware, assuming this is available
+(see CONFIG_EXTRA_FIRMWARE).
+
+4. u-boot doesn't load the firmware and the kernel driver is not
+able to find it either. The probing fails and there is no HDMI
+available in linux.
+
+Signed-off-by: Abel Vesa <abel.vesa@nxp.com>
+Reviewed-by: Sandor Yu <sandor.yu@nxp.com>
+Acked-by: Wen He <wen.he_1@nxp.com>
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c | 78 +++++++++++++++++++++++++++++++++--
+ drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c | 30 ++++++++++++++
+ drivers/gpu/drm/imx/cdns-mhdp-imx.h   |  4 ++
+ include/drm/bridge/cdns-mhdp-common.h |  3 ++
+ 4 files changed, 111 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
+@@ -7,12 +7,17 @@
+  */
+ #include <dt-bindings/firmware/imx/rsrc.h>
+ #include <linux/firmware/imx/sci.h>
++#include <linux/firmware.h>
+ #include <linux/pm_domain.h>
+ #include <linux/clk.h>
+ #include <drm/drmP.h>
+ #include "cdns-mhdp-imx.h"
++#define FW_IRAM_OFFSET                0x2000
++#define FW_IRAM_SIZE          0x10000
++#define FW_DRAM_SIZE          0x8000
++
+ #define PLL_800MHZ (800000000)
+ #define HDP_DUAL_MODE_MIN_PCLK_RATE   300000  /* KHz */
+@@ -517,24 +522,69 @@ void cdns_mhdp_pclk_rate_imx8qm(struct c
+       imx8qm_pixel_link_mux(imx_mhdp);
+ }
+-int cdns_mhdp_firmware_init_imx8qm(struct cdns_mhdp_device *mhdp)
++static void cdns_mhdp_firmware_load_cont(const struct firmware *fw, void *context)
+ {
+-      struct imx_mhdp_device *imx_mhdp =
+-                              container_of(mhdp, struct imx_mhdp_device, mhdp);
++      struct imx_mhdp_device *imx_mhdp = context;
++
++      imx_mhdp->fw = fw;
++}
++
++static int cdns_mhdp_load_firmware_imx8qm(struct imx_mhdp_device *imx_mhdp)
++{
++      const u8 *iram;
++      const u8 *dram;
+       u32 rate;
+       int ret;
+       /* configure HDMI/DP core clock */
+       rate = clk_get_rate(imx_mhdp->clks.clk_core);
+-      if (mhdp->is_ls1028a)
++      if (imx_mhdp->mhdp.is_ls1028a)
+               rate = rate / 4;
+       cdns_mhdp_set_fw_clk(&imx_mhdp->mhdp, rate);
++      /* skip fw loading if none is specified */
++      if (!imx_mhdp->firmware_name)
++              goto out;
++
++      if (!imx_mhdp->fw) {
++              ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
++                                              imx_mhdp->firmware_name,
++                                              imx_mhdp->mhdp.dev, GFP_KERNEL,
++                                              imx_mhdp,
++                                              cdns_mhdp_firmware_load_cont);
++              if (ret < 0) {
++                      DRM_ERROR("failed to load firmware\n");
++                      return -ENOENT;
++              }
++      } else {
++              iram = imx_mhdp->fw->data + FW_IRAM_OFFSET;
++              dram = iram + FW_IRAM_SIZE;
++
++              cdns_mhdp_load_firmware(&imx_mhdp->mhdp,
++                                      (const u32 *) iram, FW_IRAM_SIZE,
++                                      (const u32 *) dram, FW_DRAM_SIZE);
++      }
++
++out:
+       /* un-reset ucpu */
+       cdns_mhdp_bus_write(0, &imx_mhdp->mhdp, APB_CTRL);
+       DRM_INFO("Started firmware!\n");
++      return 0;
++}
++
++int cdns_mhdp_firmware_init_imx8qm(struct cdns_mhdp_device *mhdp)
++{
++      struct imx_mhdp_device *imx_mhdp =
++                              container_of(mhdp, struct imx_mhdp_device, mhdp);
++      int ret;
++
++      /* load firmware */
++      ret = cdns_mhdp_load_firmware_imx8qm(imx_mhdp);
++      if (ret)
++              return ret;
++
+       ret = cdns_mhdp_check_alive(&imx_mhdp->mhdp);
+       if (ret == false) {
+               DRM_ERROR("NO HDMI FW running\n");
+@@ -550,3 +600,23 @@ int cdns_mhdp_firmware_init_imx8qm(struc
+       return 0;
+ }
++
++int cdns_mhdp_suspend_imx8qm(struct cdns_mhdp_device *mhdp)
++{
++      struct imx_mhdp_device *imx_mhdp =
++                              container_of(mhdp, struct imx_mhdp_device, mhdp);
++
++      imx8qm_pixel_clk_disable(imx_mhdp);
++
++      return 0;
++}
++
++int cdns_mhdp_resume_imx8qm(struct cdns_mhdp_device *mhdp)
++{
++      struct imx_mhdp_device *imx_mhdp =
++                              container_of(mhdp, struct imx_mhdp_device, mhdp);
++
++      imx8qm_pixel_clk_enable(imx_mhdp);
++
++      return cdns_mhdp_firmware_init_imx8qm(mhdp);
++}
+--- a/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
++++ b/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
+@@ -82,6 +82,8 @@ static struct cdns_plat_data imx8qm_hdmi
+       .phy_video_valid = cdns_hdmi_phy_video_valid_imx8qm,
+       .power_on = cdns_mhdp_power_on_imx8qm,
+       .firmware_init = cdns_mhdp_firmware_init_imx8qm,
++      .resume = cdns_mhdp_resume_imx8qm,
++      .suspend = cdns_mhdp_suspend_imx8qm,
+       .pclk_rate = cdns_mhdp_pclk_rate_imx8qm,
+       .plat_init = cdns_mhdp_plat_init_imx8qm,
+       .plat_deinit = cdns_mhdp_plat_deinit_imx8qm,
+@@ -96,6 +98,8 @@ static struct cdns_plat_data imx8qm_dp_d
+       .phy_set = cdns_dp_phy_set_imx8qm,
+       .power_on = cdns_mhdp_power_on_imx8qm,
+       .firmware_init = cdns_mhdp_firmware_init_imx8qm,
++      .resume = cdns_mhdp_resume_imx8qm,
++      .suspend = cdns_mhdp_suspend_imx8qm,
+       .pclk_rate = cdns_mhdp_pclk_rate_imx8qm,
+       .plat_init = cdns_mhdp_plat_init_imx8qm,
+       .plat_deinit = cdns_mhdp_plat_deinit_imx8qm,
+@@ -157,6 +161,9 @@ static int cdns_mhdp_imx_bind(struct dev
+       encoder = &imx_mhdp->encoder;
+       encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
++
++      ret = of_property_read_string(pdev->dev.of_node, "firmware-name",
++                                      &imx_mhdp->firmware_name);
+       /*
+        * If we failed to find the CRTC(s) which this encoder is
+        * supposed to be connected to, it's because the CRTC has
+@@ -198,6 +205,24 @@ static const struct component_ops cdns_m
+       .unbind = cdns_mhdp_imx_unbind,
+ };
++static int cdns_mhdp_imx_suspend(struct device *dev)
++{
++      struct imx_mhdp_device *imx_mhdp = dev_get_drvdata(dev);
++
++      cdns_mhdp_plat_call(&imx_mhdp->mhdp, suspend);
++
++      return 0;
++}
++
++static int cdns_mhdp_imx_resume(struct device *dev)
++{
++      struct imx_mhdp_device *imx_mhdp = dev_get_drvdata(dev);
++
++      cdns_mhdp_plat_call(&imx_mhdp->mhdp, resume);
++
++      return 0;
++}
++
+ static int cdns_mhdp_imx_probe(struct platform_device *pdev)
+ {
+       return component_add(&pdev->dev, &cdns_mhdp_imx_ops);
+@@ -210,12 +235,17 @@ static int cdns_mhdp_imx_remove(struct p
+       return 0;
+ }
++static const struct dev_pm_ops cdns_mhdp_imx_pm_ops = {
++        SET_LATE_SYSTEM_SLEEP_PM_OPS(cdns_mhdp_imx_suspend, cdns_mhdp_imx_resume)
++};
++
+ static struct platform_driver cdns_mhdp_imx_platform_driver = {
+       .probe  = cdns_mhdp_imx_probe,
+       .remove = cdns_mhdp_imx_remove,
+       .driver = {
+               .name = "cdns-mhdp-imx",
+               .of_match_table = cdns_mhdp_imx_dt_ids,
++              .pm = &cdns_mhdp_imx_pm_ops,
+       },
+ };
+--- a/drivers/gpu/drm/imx/cdns-mhdp-imx.h
++++ b/drivers/gpu/drm/imx/cdns-mhdp-imx.h
+@@ -50,6 +50,8 @@ struct imx_mhdp_device {
+       bool active;
+       bool suspended;
+       struct imx_hdp_clks clks;
++      const struct firmware *fw;
++      const char *firmware_name;
+       int bus_type;
+@@ -65,6 +67,8 @@ void cdns_mhdp_plat_init_imx8qm(struct c
+ void cdns_mhdp_plat_deinit_imx8qm(struct cdns_mhdp_device *mhdp);
+ void cdns_mhdp_pclk_rate_imx8qm(struct cdns_mhdp_device *mhdp);
+ int cdns_mhdp_firmware_init_imx8qm(struct cdns_mhdp_device *mhdp);
++int cdns_mhdp_resume_imx8qm(struct cdns_mhdp_device *mhdp);
++int cdns_mhdp_suspend_imx8qm(struct cdns_mhdp_device *mhdp);
+ int cdns_mhdp_power_on_imx8qm(struct cdns_mhdp_device *mhdp);
+ int cdns_mhdp_power_on_ls1028a(struct cdns_mhdp_device *mhdp);
+ void cdns_mhdp_pclk_rate_ls1028a(struct cdns_mhdp_device *mhdp);
+--- a/include/drm/bridge/cdns-mhdp-common.h
++++ b/include/drm/bridge/cdns-mhdp-common.h
+@@ -645,6 +645,9 @@ struct cdns_plat_data {
+       int (*firmware_init)(struct cdns_mhdp_device *mhdp);
+       void (*pclk_rate)(struct cdns_mhdp_device *mhdp);
++      int (*suspend)(struct cdns_mhdp_device *mhdp);
++      int (*resume)(struct cdns_mhdp_device *mhdp);
++
+       int (*power_on)(struct cdns_mhdp_device *mhdp);
+       int (*power_off)(struct cdns_mhdp_device *mhdp);
diff --git a/target/linux/layerscape/patches-5.4/805-display-0057-LF-794-4-gpu-cdn-mhdp-common-Increase-the-check-aliv.patch b/target/linux/layerscape/patches-5.4/805-display-0057-LF-794-4-gpu-cdn-mhdp-common-Increase-the-check-aliv.patch
new file mode 100644 (file)
index 0000000..734c501
--- /dev/null
@@ -0,0 +1,29 @@
+From 5a019410a0908d7a66a0526a47bed1883c02c5fe Mon Sep 17 00:00:00 2001
+From: Abel Vesa <abel.vesa@nxp.com>
+Date: Thu, 9 Jan 2020 15:20:27 +0200
+Subject: [PATCH] LF-794-4 gpu: cdn: mhdp-common: Increase the check alive
+ timeout
+
+It seems that the firmware on i.MX8QM starts a little bit
+after 20us after the ucpu has been relased (un-resetted).
+Therefore, increase the max timeout for check alive to 50us.
+
+Signed-off-by: Abel Vesa <abel.vesa@nxp.com>
+Reviewed-by: Sandor Yu <sandor.yu@nxp.com>
+Acked-by: Wen He <wen.he_1@nxp.com>
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
+@@ -1039,7 +1039,7 @@ EXPORT_SYMBOL(cdns_mhdp_read_hpd);
+ bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp)
+ {
+       u32  alive, newalive;
+-      u8 retries_left = 10;
++      u8 retries_left = 50;
+       alive = cdns_mhdp_bus_read(mhdp, KEEP_ALIVE);
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0001-dmaengine-fsl-dpaa2-qdma-Add-the-DPDMAI-Data-Path-DM.patch b/target/linux/layerscape/patches-5.4/806-dma-0001-dmaengine-fsl-dpaa2-qdma-Add-the-DPDMAI-Data-Path-DM.patch
new file mode 100644 (file)
index 0000000..5ed1725
--- /dev/null
@@ -0,0 +1,593 @@
+From e8a617bd4aa67cc57b7ff8b9a1b2ca0acd4712ac Mon Sep 17 00:00:00 2001
+From: Peng Ma <peng.ma@nxp.com>
+Date: Mon, 4 Mar 2019 15:39:14 +0800
+Subject: [PATCH] dmaengine: fsl-dpaa2-qdma: Add the DPDMAI(Data Path DMA
+ Interface) support
+
+The MC(Management Complex) exports the DPDMAI(Data Path DMA Interface)
+object as an interface to operate the DPAA2(Data Path Acceleration
+Architecture 2) qDMA Engine. The DPDMAI enables sending frame-based
+requests to qDMA and receiving back confirmation response on transaction
+completion, utilizing the DPAA2 QBMan(Queue Manager and Buffer Manager
+hardware) infrastructure. DPDMAI object provides up to two priorities for
+processing qDMA requests.
+The following list summarizes the DPDMAI main features and capabilities:
+       1. Supports up to two scheduling priorities for processing
+       service requests.
+       - Each DPDMAI transmit queue is mapped to one of two service
+       priorities, allowing further prioritization in hardware between
+       requests from different DPDMAI objects.
+       2. Supports up to two receive queues for incoming transaction
+       completion confirmations.
+       - Each DPDMAI receive queue is mapped to one of two receive
+       priorities, allowing further prioritization between other
+       interfaces when associating the DPDMAI receive queues to DPIO
+       or DPCON(Data Path Concentrator) objects.
+       3. Supports different scheduling options for processing received
+       packets:
+       - Queues can be configured either in 'parked' mode (default),
+       or attached to a DPIO object, or attached to DPCON object.
+       4. Allows interaction with one or more DPIO objects for
+       dequeueing/enqueueing frame descriptors(FD) and for
+       acquiring/releasing buffers.
+       5. Supports enable, disable, and reset operations.
+
+Add dpdmai to support some platforms with dpaa2 qdma engine.
+
+Signed-off-by: Peng Ma <peng.ma@nxp.com>
+---
+ drivers/dma/fsl-dpaa2-qdma/dpdmai.c | 366 ++++++++++++++++++++++++++++++++++++
+ drivers/dma/fsl-dpaa2-qdma/dpdmai.h | 177 +++++++++++++++++
+ 2 files changed, 543 insertions(+)
+ create mode 100644 drivers/dma/fsl-dpaa2-qdma/dpdmai.c
+ create mode 100644 drivers/dma/fsl-dpaa2-qdma/dpdmai.h
+
+--- /dev/null
++++ b/drivers/dma/fsl-dpaa2-qdma/dpdmai.c
+@@ -0,0 +1,366 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright 2019 NXP
++
++#include <linux/types.h>
++#include <linux/io.h>
++#include <linux/fsl/mc.h>
++#include "dpdmai.h"
++
++struct dpdmai_rsp_get_attributes {
++      __le32 id;
++      u8 num_of_priorities;
++      u8 pad0[3];
++      __le16 major;
++      __le16 minor;
++};
++
++struct dpdmai_cmd_queue {
++      __le32 dest_id;
++      u8 priority;
++      u8 queue;
++      u8 dest_type;
++      u8 pad;
++      __le64 user_ctx;
++      union {
++              __le32 options;
++              __le32 fqid;
++      };
++};
++
++struct dpdmai_rsp_get_tx_queue {
++      __le64 pad;
++      __le32 fqid;
++};
++
++#define MC_CMD_OP(_cmd, _param, _offset, _width, _type, _arg) \
++      ((_cmd).params[_param] |= mc_enc((_offset), (_width), _arg))
++
++/* cmd, param, offset, width, type, arg_name */
++#define DPDMAI_CMD_CREATE(_cmd, _cfg) \
++do { \
++      typeof(_cmd) (cmd) = (_cmd); \
++      typeof(_cfg) (cfg) = (_cfg); \
++      MC_CMD_OP(cmd, 0, 8,  8,  u8,  (cfg)->priorities[0]);\
++      MC_CMD_OP(cmd, 0, 16, 8,  u8,  (cfg)->priorities[1]);\
++} while (0)
++
++static inline u64 mc_enc(int lsoffset, int width, u64 val)
++{
++      return (val & MAKE_UMASK64(width)) << lsoffset;
++}
++
++/**
++ * dpdmai_open() - Open a control session for the specified object
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @dpdmai_id:        DPDMAI unique ID
++ * @token:    Returned token; use in subsequent API calls
++ *
++ * This function can be used to open a control session for an
++ * already created object; an object may have been declared in
++ * the DPL or by calling the dpdmai_create() function.
++ * This function returns a unique authentication token,
++ * associated with the specific object ID and the specific MC
++ * portal; this token must be used in all subsequent commands for
++ * this specific object.
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmai_open(struct fsl_mc_io *mc_io, u32 cmd_flags,
++              int dpdmai_id, u16 *token)
++{
++      struct fsl_mc_command cmd = { 0 };
++      __le64 *cmd_dpdmai_id;
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_OPEN,
++                                        cmd_flags, 0);
++
++      cmd_dpdmai_id = cmd.params;
++      *cmd_dpdmai_id = cpu_to_le32(dpdmai_id);
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      *token = mc_cmd_hdr_read_token(&cmd);
++
++      return 0;
++}
++
++/**
++ * dpdmai_close() - Close the control session of the object
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMAI object
++ *
++ * After this function is called, no further operations are
++ * allowed on the object without opening a new control session.
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmai_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
++{
++      struct fsl_mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_CLOSE,
++                                        cmd_flags, token);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmai_create() - Create the DPDMAI object
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @cfg:      Configuration structure
++ * @token:    Returned token; use in subsequent API calls
++ *
++ * Create the DPDMAI object, allocate required resources and
++ * perform required initialization.
++ *
++ * The object can be created either by declaring it in the
++ * DPL file, or by calling this function.
++ *
++ * This function returns a unique authentication token,
++ * associated with the specific object ID and the specific MC
++ * portal; this token must be used in all subsequent calls to
++ * this specific object. For objects that are created using the
++ * DPL file, call dpdmai_open() function to get an authentication
++ * token first.
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmai_create(struct fsl_mc_io *mc_io, u32 cmd_flags,
++                const struct dpdmai_cfg *cfg, u16 *token)
++{
++      struct fsl_mc_command cmd = { 0 };
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_CREATE,
++                                        cmd_flags, 0);
++      DPDMAI_CMD_CREATE(cmd, cfg);
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      *token = mc_cmd_hdr_read_token(&cmd);
++
++      return 0;
++}
++
++/**
++ * dpdmai_enable() - Enable the DPDMAI, allow sending and receiving frames.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMAI object
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmai_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
++{
++      struct fsl_mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_ENABLE,
++                                        cmd_flags, token);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmai_disable() - Disable the DPDMAI, stop sending and receiving frames.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMAI object
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmai_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
++{
++      struct fsl_mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_DISABLE,
++                                        cmd_flags, token);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmai_reset() - Reset the DPDMAI, returns the object to initial state.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMAI object
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmai_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
++{
++      struct fsl_mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_RESET,
++                                        cmd_flags, token);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmai_get_attributes() - Retrieve DPDMAI attributes.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMAI object
++ * @attr:     Returned object's attributes
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmai_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags,
++                        u16 token, struct dpdmai_attr *attr)
++{
++      struct dpdmai_rsp_get_attributes *rsp_params;
++      struct fsl_mc_command cmd = { 0 };
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_GET_ATTR,
++                                        cmd_flags, token);
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      rsp_params = (struct dpdmai_rsp_get_attributes *)cmd.params;
++      attr->id = le32_to_cpu(rsp_params->id);
++      attr->version.major = le16_to_cpu(rsp_params->major);
++      attr->version.minor = le16_to_cpu(rsp_params->minor);
++      attr->num_of_priorities = rsp_params->num_of_priorities;
++
++      return 0;
++}
++
++/**
++ * dpdmai_set_rx_queue() - Set Rx queue configuration
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMAI object
++ * @priority: Select the queue relative to number of
++ *            priorities configured at DPDMAI creation
++ * @cfg:      Rx queue configuration
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmai_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                      u8 priority, const struct dpdmai_rx_queue_cfg *cfg)
++{
++      struct dpdmai_cmd_queue *cmd_params;
++      struct fsl_mc_command cmd = { 0 };
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_SET_RX_QUEUE,
++                                        cmd_flags, token);
++
++      cmd_params = (struct dpdmai_cmd_queue *)cmd.params;
++      cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id);
++      cmd_params->priority = cfg->dest_cfg.priority;
++      cmd_params->queue = priority;
++      cmd_params->dest_type = cfg->dest_cfg.dest_type;
++      cmd_params->user_ctx = cpu_to_le64(cfg->user_ctx);
++      cmd_params->options = cpu_to_le32(cfg->options);
++
++      /* send command to mc*/
++      return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpdmai_get_rx_queue() - Retrieve Rx queue attributes.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMAI object
++ * @priority: Select the queue relative to number of
++ *                            priorities configured at DPDMAI creation
++ * @attr:     Returned Rx queue attributes
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmai_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                      u8 priority, struct dpdmai_rx_queue_attr *attr)
++{
++      struct dpdmai_cmd_queue *cmd_params;
++      struct fsl_mc_command cmd = { 0 };
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_GET_RX_QUEUE,
++                                        cmd_flags, token);
++
++      cmd_params = (struct dpdmai_cmd_queue *)cmd.params;
++      cmd_params->queue = priority;
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++      attr->dest_cfg.dest_id = le32_to_cpu(cmd_params->dest_id);
++      attr->dest_cfg.priority = cmd_params->priority;
++      attr->dest_cfg.dest_type = cmd_params->dest_type;
++      attr->user_ctx = le64_to_cpu(cmd_params->user_ctx);
++      attr->fqid = le32_to_cpu(cmd_params->fqid);
++
++      return 0;
++}
++
++/**
++ * dpdmai_get_tx_queue() - Retrieve Tx queue attributes.
++ * @mc_io:    Pointer to MC portal's I/O object
++ * @cmd_flags:        Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token:    Token of DPDMAI object
++ * @priority: Select the queue relative to number of
++ *                    priorities configured at DPDMAI creation
++ * @fqid:     Returned Tx queue
++ *
++ * Return:    '0' on Success; Error code otherwise.
++ */
++int dpdmai_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags,
++                      u16 token, u8 priority, u32 *fqid)
++{
++      struct dpdmai_rsp_get_tx_queue *rsp_params;
++      struct dpdmai_cmd_queue *cmd_params;
++      struct fsl_mc_command cmd = { 0 };
++      int err;
++
++      /* prepare command */
++      cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_GET_TX_QUEUE,
++                                        cmd_flags, token);
++
++      cmd_params = (struct dpdmai_cmd_queue *)cmd.params;
++      cmd_params->queue = priority;
++
++      /* send command to mc*/
++      err = mc_send_command(mc_io, &cmd);
++      if (err)
++              return err;
++
++      /* retrieve response parameters */
++
++      rsp_params = (struct dpdmai_rsp_get_tx_queue *)cmd.params;
++      *fqid = le32_to_cpu(rsp_params->fqid);
++
++      return 0;
++}
+--- /dev/null
++++ b/drivers/dma/fsl-dpaa2-qdma/dpdmai.h
+@@ -0,0 +1,177 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/* Copyright 2019 NXP */
++
++#ifndef __FSL_DPDMAI_H
++#define __FSL_DPDMAI_H
++
++/* DPDMAI Version */
++#define DPDMAI_VER_MAJOR      2
++#define DPDMAI_VER_MINOR      2
++
++#define DPDMAI_CMD_BASE_VERSION       0
++#define DPDMAI_CMD_ID_OFFSET  4
++
++#define DPDMAI_CMDID_FORMAT(x)        (((x) << DPDMAI_CMD_ID_OFFSET) | \
++                              DPDMAI_CMD_BASE_VERSION)
++
++/* Command IDs */
++#define DPDMAI_CMDID_CLOSE            DPDMAI_CMDID_FORMAT(0x800)
++#define DPDMAI_CMDID_OPEN               DPDMAI_CMDID_FORMAT(0x80E)
++#define DPDMAI_CMDID_CREATE             DPDMAI_CMDID_FORMAT(0x90E)
++
++#define DPDMAI_CMDID_ENABLE             DPDMAI_CMDID_FORMAT(0x002)
++#define DPDMAI_CMDID_DISABLE            DPDMAI_CMDID_FORMAT(0x003)
++#define DPDMAI_CMDID_GET_ATTR           DPDMAI_CMDID_FORMAT(0x004)
++#define DPDMAI_CMDID_RESET              DPDMAI_CMDID_FORMAT(0x005)
++#define DPDMAI_CMDID_IS_ENABLED         DPDMAI_CMDID_FORMAT(0x006)
++
++#define DPDMAI_CMDID_SET_IRQ            DPDMAI_CMDID_FORMAT(0x010)
++#define DPDMAI_CMDID_GET_IRQ            DPDMAI_CMDID_FORMAT(0x011)
++#define DPDMAI_CMDID_SET_IRQ_ENABLE     DPDMAI_CMDID_FORMAT(0x012)
++#define DPDMAI_CMDID_GET_IRQ_ENABLE     DPDMAI_CMDID_FORMAT(0x013)
++#define DPDMAI_CMDID_SET_IRQ_MASK       DPDMAI_CMDID_FORMAT(0x014)
++#define DPDMAI_CMDID_GET_IRQ_MASK       DPDMAI_CMDID_FORMAT(0x015)
++#define DPDMAI_CMDID_GET_IRQ_STATUS     DPDMAI_CMDID_FORMAT(0x016)
++#define DPDMAI_CMDID_CLEAR_IRQ_STATUS DPDMAI_CMDID_FORMAT(0x017)
++
++#define DPDMAI_CMDID_SET_RX_QUEUE     DPDMAI_CMDID_FORMAT(0x1A0)
++#define DPDMAI_CMDID_GET_RX_QUEUE       DPDMAI_CMDID_FORMAT(0x1A1)
++#define DPDMAI_CMDID_GET_TX_QUEUE       DPDMAI_CMDID_FORMAT(0x1A2)
++
++#define MC_CMD_HDR_TOKEN_O 32  /* Token field offset */
++#define MC_CMD_HDR_TOKEN_S 16  /* Token field size */
++
++#define MAKE_UMASK64(_width) \
++      ((u64)((_width) < 64 ? ((u64)1 << (_width)) - 1 : (u64)-1))
++
++/* Data Path DMA Interface API
++ * Contains initialization APIs and runtime control APIs for DPDMAI
++ */
++
++/**
++ * Maximum number of Tx/Rx priorities per DPDMAI object
++ */
++#define DPDMAI_PRIO_NUM               2
++
++/* DPDMAI queue modification options */
++
++/**
++ * Select to modify the user's context associated with the queue
++ */
++#define DPDMAI_QUEUE_OPT_USER_CTX     0x1
++
++/**
++ * Select to modify the queue's destination
++ */
++#define DPDMAI_QUEUE_OPT_DEST         0x2
++
++/**
++ * struct dpdmai_cfg - Structure representing DPDMAI configuration
++ * @priorities: Priorities for the DMA hardware processing; valid priorities are
++ *    configured with values 1-8; the entry following last valid entry
++ *    should be configured with 0
++ */
++struct dpdmai_cfg {
++      u8 priorities[DPDMAI_PRIO_NUM];
++};
++
++/**
++ * struct dpdmai_attr - Structure representing DPDMAI attributes
++ * @id: DPDMAI object ID
++ * @version: DPDMAI version
++ * @num_of_priorities: number of priorities
++ */
++struct dpdmai_attr {
++      int     id;
++      /**
++       * struct version - DPDMAI version
++       * @major: DPDMAI major version
++       * @minor: DPDMAI minor version
++       */
++      struct {
++              u16 major;
++              u16 minor;
++      } version;
++      u8 num_of_priorities;
++};
++
++/**
++ * enum dpdmai_dest - DPDMAI destination types
++ * @DPDMAI_DEST_NONE: Unassigned destination; The queue is set in parked mode
++ *    and does not generate FQDAN notifications; user is expected to dequeue
++ *    from the queue based on polling or other user-defined method
++ * @DPDMAI_DEST_DPIO: The queue is set in schedule mode and generates FQDAN
++ *    notifications to the specified DPIO; user is expected to dequeue
++ *    from the queue only after notification is received
++ * @DPDMAI_DEST_DPCON: The queue is set in schedule mode and does not generate
++ *    FQDAN notifications, but is connected to the specified DPCON object;
++ *    user is expected to dequeue from the DPCON channel
++ */
++enum dpdmai_dest {
++      DPDMAI_DEST_NONE = 0,
++      DPDMAI_DEST_DPIO = 1,
++      DPDMAI_DEST_DPCON = 2
++};
++
++/**
++ * struct dpdmai_dest_cfg - Structure representing DPDMAI destination parameters
++ * @dest_type: Destination type
++ * @dest_id: Either DPIO ID or DPCON ID, depending on the destination type
++ * @priority: Priority selection within the DPIO or DPCON channel; valid values
++ *    are 0-1 or 0-7, depending on the number of priorities in that
++ *    channel; not relevant for 'DPDMAI_DEST_NONE' option
++ */
++struct dpdmai_dest_cfg {
++      enum dpdmai_dest dest_type;
++      int dest_id;
++      u8 priority;
++};
++
++/**
++ * struct dpdmai_rx_queue_cfg - DPDMAI RX queue configuration
++ * @options: Flags representing the suggested modifications to the queue;
++ *    Use any combination of 'DPDMAI_QUEUE_OPT_<X>' flags
++ * @user_ctx: User context value provided in the frame descriptor of each
++ *    dequeued frame;
++ *    valid only if 'DPDMAI_QUEUE_OPT_USER_CTX' is contained in 'options'
++ * @dest_cfg: Queue destination parameters;
++ *    valid only if 'DPDMAI_QUEUE_OPT_DEST' is contained in 'options'
++ */
++struct dpdmai_rx_queue_cfg {
++      struct dpdmai_dest_cfg dest_cfg;
++      u32 options;
++      u64 user_ctx;
++
++};
++
++/**
++ * struct dpdmai_rx_queue_attr - Structure representing attributes of Rx queues
++ * @user_ctx:  User context value provided in the frame descriptor of each
++ *     dequeued frame
++ * @dest_cfg: Queue destination configuration
++ * @fqid: Virtual FQID value to be used for dequeue operations
++ */
++struct dpdmai_rx_queue_attr {
++      struct dpdmai_dest_cfg  dest_cfg;
++      u64 user_ctx;
++      u32 fqid;
++};
++
++int dpdmai_open(struct fsl_mc_io *mc_io, u32 cmd_flags,
++              int dpdmai_id, u16 *token);
++int dpdmai_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
++int dpdmai_create(struct fsl_mc_io *mc_io, u32 cmd_flags,
++                const struct dpdmai_cfg *cfg, u16 *token);
++int dpdmai_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
++int dpdmai_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
++int dpdmai_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
++int dpdmai_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags,
++                        u16 token, struct dpdmai_attr *attr);
++int dpdmai_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                      u8 priority, const struct dpdmai_rx_queue_cfg *cfg);
++int dpdmai_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++                      u8 priority, struct dpdmai_rx_queue_attr *attr);
++int dpdmai_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags,
++                      u16 token, u8 priority, u32 *fqid);
++
++#endif /* __FSL_DPDMAI_H */
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0002-dmaengine-fsl-dpaa2-qdma-Add-NXP-dpaa2-qDMA-controll.patch b/target/linux/layerscape/patches-5.4/806-dma-0002-dmaengine-fsl-dpaa2-qdma-Add-NXP-dpaa2-qDMA-controll.patch
new file mode 100644 (file)
index 0000000..897752d
--- /dev/null
@@ -0,0 +1,1061 @@
+From 87db029b2576ccae40dcf8173e2fbb84fdbec1a5 Mon Sep 17 00:00:00 2001
+From: Peng Ma <peng.ma@nxp.com>
+Date: Mon, 4 Mar 2019 15:45:56 +0800
+Subject: [PATCH] dmaengine: fsl-dpaa2-qdma: Add NXP dpaa2 qDMA controller
+ driver for Layerscape SoCs
+
+DPPA2(Data Path Acceleration Architecture 2) qDMA supports
+virtualized channel by allowing DMA jobs to be enqueued into
+different work queues. Core can initiate a DMA transaction by
+preparing a frame descriptor(FD) for each DMA job and enqueuing
+this job through a hardware portal. DPAA2 components can also
+prepare a FD and enqueue a DMA job through a hardware portal.
+The qDMA prefetches DMA jobs through DPAA2 hardware portal. It
+then schedules and dispatches to internal DMA hardware engines,
+which generate read and write requests. Both qDMA source data and
+destination data can be either contiguous or non-contiguous using
+one or more scatter/gather tables.
+The qDMA supports global bandwidth flow control where all DMA
+transactions are stalled if the bandwidth threshold has been reached.
+Also supported are transaction based read throttling.
+
+Add NXP dppa2 qDMA to support some of Layerscape SoCs.
+such as: LS1088A, LS208xA, LX2, etc.
+
+Signed-off-by: Peng Ma <peng.ma@nxp.com>
+---
+ drivers/dma/Kconfig                     |   2 +
+ drivers/dma/Makefile                    |   1 +
+ drivers/dma/fsl-dpaa2-qdma/Kconfig      |   9 +
+ drivers/dma/fsl-dpaa2-qdma/Makefile     |   3 +
+ drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c | 825 ++++++++++++++++++++++++++++++++
+ drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.h | 153 ++++++
+ 6 files changed, 993 insertions(+)
+ create mode 100644 drivers/dma/fsl-dpaa2-qdma/Kconfig
+ create mode 100644 drivers/dma/fsl-dpaa2-qdma/Makefile
+ create mode 100644 drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c
+ create mode 100644 drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.h
+
+--- a/drivers/dma/Kconfig
++++ b/drivers/dma/Kconfig
+@@ -669,6 +669,8 @@ source "drivers/dma/sh/Kconfig"
+ source "drivers/dma/ti/Kconfig"
++source "drivers/dma/fsl-dpaa2-qdma/Kconfig"
++
+ # clients
+ comment "DMA Clients"
+       depends on DMA_ENGINE
+--- a/drivers/dma/Makefile
++++ b/drivers/dma/Makefile
+@@ -75,6 +75,7 @@ obj-$(CONFIG_UNIPHIER_MDMAC) += uniphier
+ obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
+ obj-$(CONFIG_ZX_DMA) += zx_dma.o
+ obj-$(CONFIG_ST_FDMA) += st_fdma.o
++obj-$(CONFIG_FSL_DPAA2_QDMA) += fsl-dpaa2-qdma/
+ obj-y += mediatek/
+ obj-y += qcom/
+--- /dev/null
++++ b/drivers/dma/fsl-dpaa2-qdma/Kconfig
+@@ -0,0 +1,9 @@
++menuconfig FSL_DPAA2_QDMA
++      tristate "NXP DPAA2 QDMA"
++      depends on ARM64
++      depends on FSL_MC_BUS && FSL_MC_DPIO
++      select DMA_ENGINE
++      select DMA_VIRTUAL_CHANNELS
++      help
++        NXP Data Path Acceleration Architecture 2 QDMA driver,
++        using the NXP MC bus driver.
+--- /dev/null
++++ b/drivers/dma/fsl-dpaa2-qdma/Makefile
+@@ -0,0 +1,3 @@
++# SPDX-License-Identifier: GPL-2.0
++# Makefile for the NXP DPAA2 qDMA controllers
++obj-$(CONFIG_FSL_DPAA2_QDMA) += dpaa2-qdma.o dpdmai.o
+--- /dev/null
++++ b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c
+@@ -0,0 +1,825 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright 2019 NXP
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/dmapool.h>
++#include <linux/of_irq.h>
++#include <linux/iommu.h>
++#include <linux/sys_soc.h>
++#include <linux/fsl/mc.h>
++#include <soc/fsl/dpaa2-io.h>
++
++#include "../virt-dma.h"
++#include "dpdmai.h"
++#include "dpaa2-qdma.h"
++
++static bool smmu_disable = true;
++
++static struct dpaa2_qdma_chan *to_dpaa2_qdma_chan(struct dma_chan *chan)
++{
++      return container_of(chan, struct dpaa2_qdma_chan, vchan.chan);
++}
++
++static struct dpaa2_qdma_comp *to_fsl_qdma_comp(struct virt_dma_desc *vd)
++{
++      return container_of(vd, struct dpaa2_qdma_comp, vdesc);
++}
++
++static int dpaa2_qdma_alloc_chan_resources(struct dma_chan *chan)
++{
++      struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan);
++      struct dpaa2_qdma_engine *dpaa2_qdma = dpaa2_chan->qdma;
++      struct device *dev = &dpaa2_qdma->priv->dpdmai_dev->dev;
++
++      dpaa2_chan->fd_pool = dma_pool_create("fd_pool", dev,
++                                            sizeof(struct dpaa2_fd),
++                                            sizeof(struct dpaa2_fd), 0);
++      if (!dpaa2_chan->fd_pool)
++              goto err;
++
++      dpaa2_chan->fl_pool = dma_pool_create("fl_pool", dev,
++                                            sizeof(struct dpaa2_fl_entry),
++                                            sizeof(struct dpaa2_fl_entry), 0);
++      if (!dpaa2_chan->fl_pool)
++              goto err_fd;
++
++      dpaa2_chan->sdd_pool =
++              dma_pool_create("sdd_pool", dev,
++                              sizeof(struct dpaa2_qdma_sd_d),
++                              sizeof(struct dpaa2_qdma_sd_d), 0);
++      if (!dpaa2_chan->sdd_pool)
++              goto err_fl;
++
++      return dpaa2_qdma->desc_allocated++;
++err_fl:
++      dma_pool_destroy(dpaa2_chan->fl_pool);
++err_fd:
++      dma_pool_destroy(dpaa2_chan->fd_pool);
++err:
++      return -ENOMEM;
++}
++
++static void dpaa2_qdma_free_chan_resources(struct dma_chan *chan)
++{
++      struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan);
++      struct dpaa2_qdma_engine *dpaa2_qdma = dpaa2_chan->qdma;
++      unsigned long flags;
++
++      LIST_HEAD(head);
++
++      spin_lock_irqsave(&dpaa2_chan->vchan.lock, flags);
++      vchan_get_all_descriptors(&dpaa2_chan->vchan, &head);
++      spin_unlock_irqrestore(&dpaa2_chan->vchan.lock, flags);
++
++      vchan_dma_desc_free_list(&dpaa2_chan->vchan, &head);
++
++      dpaa2_dpdmai_free_comp(dpaa2_chan, &dpaa2_chan->comp_used);
++      dpaa2_dpdmai_free_comp(dpaa2_chan, &dpaa2_chan->comp_free);
++
++      dma_pool_destroy(dpaa2_chan->fd_pool);
++      dma_pool_destroy(dpaa2_chan->fl_pool);
++      dma_pool_destroy(dpaa2_chan->sdd_pool);
++      dpaa2_qdma->desc_allocated--;
++}
++
++/*
++ * Request a command descriptor for enqueue.
++ */
++static struct dpaa2_qdma_comp *
++dpaa2_qdma_request_desc(struct dpaa2_qdma_chan *dpaa2_chan)
++{
++      struct dpaa2_qdma_priv *qdma_priv = dpaa2_chan->qdma->priv;
++      struct device *dev = &qdma_priv->dpdmai_dev->dev;
++      struct dpaa2_qdma_comp *comp_temp = NULL;
++      unsigned long flags;
++
++      spin_lock_irqsave(&dpaa2_chan->queue_lock, flags);
++      if (list_empty(&dpaa2_chan->comp_free)) {
++              spin_unlock_irqrestore(&dpaa2_chan->queue_lock, flags);
++              comp_temp = kzalloc(sizeof(*comp_temp), GFP_NOWAIT);
++              if (!comp_temp)
++                      goto err;
++              comp_temp->fd_virt_addr =
++                      dma_pool_alloc(dpaa2_chan->fd_pool, GFP_NOWAIT,
++                                     &comp_temp->fd_bus_addr);
++              if (!comp_temp->fd_virt_addr)
++                      goto err_comp;
++
++              comp_temp->fl_virt_addr =
++                      dma_pool_alloc(dpaa2_chan->fl_pool, GFP_NOWAIT,
++                                     &comp_temp->fl_bus_addr);
++              if (!comp_temp->fl_virt_addr)
++                      goto err_fd_virt;
++
++              comp_temp->desc_virt_addr =
++                      dma_pool_alloc(dpaa2_chan->sdd_pool, GFP_NOWAIT,
++                                     &comp_temp->desc_bus_addr);
++              if (!comp_temp->desc_virt_addr)
++                      goto err_fl_virt;
++
++              comp_temp->qchan = dpaa2_chan;
++              return comp_temp;
++      }
++
++      comp_temp = list_first_entry(&dpaa2_chan->comp_free,
++                                   struct dpaa2_qdma_comp, list);
++      list_del(&comp_temp->list);
++      spin_unlock_irqrestore(&dpaa2_chan->queue_lock, flags);
++
++      comp_temp->qchan = dpaa2_chan;
++
++      return comp_temp;
++
++err_fl_virt:
++              dma_pool_free(dpaa2_chan->fl_pool,
++                            comp_temp->fl_virt_addr,
++                            comp_temp->fl_bus_addr);
++err_fd_virt:
++              dma_pool_free(dpaa2_chan->fd_pool,
++                            comp_temp->fd_virt_addr,
++                            comp_temp->fd_bus_addr);
++err_comp:
++      kfree(comp_temp);
++err:
++      dev_err(dev, "Failed to request descriptor\n");
++      return NULL;
++}
++
++static void
++dpaa2_qdma_populate_fd(u32 format, struct dpaa2_qdma_comp *dpaa2_comp)
++{
++      struct dpaa2_fd *fd;
++
++      fd = dpaa2_comp->fd_virt_addr;
++      memset(fd, 0, sizeof(struct dpaa2_fd));
++
++      /* fd populated */
++      dpaa2_fd_set_addr(fd, dpaa2_comp->fl_bus_addr);
++
++      /*
++       * Bypass memory translation, Frame list format, short length disable
++       * we need to disable BMT if fsl-mc use iova addr
++       */
++      if (smmu_disable)
++              dpaa2_fd_set_bpid(fd, QMAN_FD_BMT_ENABLE);
++      dpaa2_fd_set_format(fd, QMAN_FD_FMT_ENABLE | QMAN_FD_SL_DISABLE);
++
++      dpaa2_fd_set_frc(fd, format | QDMA_SER_CTX);
++}
++
++/* first frame list for descriptor buffer */
++static void
++dpaa2_qdma_populate_first_framel(struct dpaa2_fl_entry *f_list,
++                               struct dpaa2_qdma_comp *dpaa2_comp,
++                               bool wrt_changed)
++{
++      struct dpaa2_qdma_sd_d *sdd;
++
++      sdd = dpaa2_comp->desc_virt_addr;
++      memset(sdd, 0, 2 * (sizeof(*sdd)));
++
++      /* source descriptor CMD */
++      sdd->cmd = cpu_to_le32(QDMA_SD_CMD_RDTTYPE_COHERENT);
++      sdd++;
++
++      /* dest descriptor CMD */
++      if (wrt_changed)
++              sdd->cmd = cpu_to_le32(LX2160_QDMA_DD_CMD_WRTTYPE_COHERENT);
++      else
++              sdd->cmd = cpu_to_le32(QDMA_DD_CMD_WRTTYPE_COHERENT);
++
++      memset(f_list, 0, sizeof(struct dpaa2_fl_entry));
++
++      /* first frame list to source descriptor */
++      dpaa2_fl_set_addr(f_list, dpaa2_comp->desc_bus_addr);
++      dpaa2_fl_set_len(f_list, 0x20);
++      dpaa2_fl_set_format(f_list, QDMA_FL_FMT_SBF | QDMA_FL_SL_LONG);
++
++      /* bypass memory translation */
++      if (smmu_disable)
++              f_list->bpid = cpu_to_le16(QDMA_FL_BMT_ENABLE);
++}
++
++/* source and destination frame list */
++static void
++dpaa2_qdma_populate_frames(struct dpaa2_fl_entry *f_list,
++                         dma_addr_t dst, dma_addr_t src,
++                         size_t len, uint8_t fmt)
++{
++      /* source frame list to source buffer */
++      memset(f_list, 0, sizeof(struct dpaa2_fl_entry));
++
++      dpaa2_fl_set_addr(f_list, src);
++      dpaa2_fl_set_len(f_list, len);
++
++      /* single buffer frame or scatter gather frame */
++      dpaa2_fl_set_format(f_list, (fmt | QDMA_FL_SL_LONG));
++
++      /* bypass memory translation */
++      if (smmu_disable)
++              f_list->bpid = cpu_to_le16(QDMA_FL_BMT_ENABLE);
++
++      f_list++;
++
++      /* destination frame list to destination buffer */
++      memset(f_list, 0, sizeof(struct dpaa2_fl_entry));
++
++      dpaa2_fl_set_addr(f_list, dst);
++      dpaa2_fl_set_len(f_list, len);
++      dpaa2_fl_set_format(f_list, (fmt | QDMA_FL_SL_LONG));
++      /* single buffer frame or scatter gather frame */
++      dpaa2_fl_set_final(f_list, QDMA_FL_F);
++      /* bypass memory translation */
++      if (smmu_disable)
++              f_list->bpid = cpu_to_le16(QDMA_FL_BMT_ENABLE);
++}
++
++static struct dma_async_tx_descriptor
++*dpaa2_qdma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst,
++                      dma_addr_t src, size_t len, ulong flags)
++{
++      struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan);
++      struct dpaa2_qdma_engine *dpaa2_qdma;
++      struct dpaa2_qdma_comp *dpaa2_comp;
++      struct dpaa2_fl_entry *f_list;
++      bool wrt_changed;
++
++      dpaa2_qdma = dpaa2_chan->qdma;
++      dpaa2_comp = dpaa2_qdma_request_desc(dpaa2_chan);
++      if (!dpaa2_comp)
++              return NULL;
++
++      wrt_changed = (bool)dpaa2_qdma->qdma_wrtype_fixup;
++
++      /* populate Frame descriptor */
++      dpaa2_qdma_populate_fd(QDMA_FD_LONG_FORMAT, dpaa2_comp);
++
++      f_list = dpaa2_comp->fl_virt_addr;
++
++      /* first frame list for descriptor buffer (logn format) */
++      dpaa2_qdma_populate_first_framel(f_list, dpaa2_comp, wrt_changed);
++
++      f_list++;
++
++      dpaa2_qdma_populate_frames(f_list, dst, src, len, QDMA_FL_FMT_SBF);
++
++      return vchan_tx_prep(&dpaa2_chan->vchan, &dpaa2_comp->vdesc, flags);
++}
++
++static void dpaa2_qdma_issue_pending(struct dma_chan *chan)
++{
++      struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan);
++      struct dpaa2_qdma_comp *dpaa2_comp;
++      struct virt_dma_desc *vdesc;
++      struct dpaa2_fd *fd;
++      unsigned long flags;
++      int err;
++
++      spin_lock_irqsave(&dpaa2_chan->queue_lock, flags);
++      spin_lock(&dpaa2_chan->vchan.lock);
++      if (vchan_issue_pending(&dpaa2_chan->vchan)) {
++              vdesc = vchan_next_desc(&dpaa2_chan->vchan);
++              if (!vdesc)
++                      goto err_enqueue;
++              dpaa2_comp = to_fsl_qdma_comp(vdesc);
++
++              fd = dpaa2_comp->fd_virt_addr;
++
++              list_del(&vdesc->node);
++              list_add_tail(&dpaa2_comp->list, &dpaa2_chan->comp_used);
++
++              err = dpaa2_io_service_enqueue_fq(NULL, dpaa2_chan->fqid, fd);
++              if (err) {
++                      list_del(&dpaa2_comp->list);
++                      list_add_tail(&dpaa2_comp->list,
++                                    &dpaa2_chan->comp_free);
++              }
++      }
++err_enqueue:
++      spin_unlock(&dpaa2_chan->vchan.lock);
++      spin_unlock_irqrestore(&dpaa2_chan->queue_lock, flags);
++}
++
++static int __cold dpaa2_qdma_setup(struct fsl_mc_device *ls_dev)
++{
++      struct dpaa2_qdma_priv_per_prio *ppriv;
++      struct device *dev = &ls_dev->dev;
++      struct dpaa2_qdma_priv *priv;
++      u8 prio_def = DPDMAI_PRIO_NUM;
++      int err = -EINVAL;
++      int i;
++
++      priv = dev_get_drvdata(dev);
++
++      priv->dev = dev;
++      priv->dpqdma_id = ls_dev->obj_desc.id;
++
++      /* Get the handle for the DPDMAI this interface is associate with */
++      err = dpdmai_open(priv->mc_io, 0, priv->dpqdma_id, &ls_dev->mc_handle);
++      if (err) {
++              dev_err(dev, "dpdmai_open() failed\n");
++              return err;
++      }
++
++      dev_dbg(dev, "Opened dpdmai object successfully\n");
++
++      err = dpdmai_get_attributes(priv->mc_io, 0, ls_dev->mc_handle,
++                                  &priv->dpdmai_attr);
++      if (err) {
++              dev_err(dev, "dpdmai_get_attributes() failed\n");
++              goto exit;
++      }
++
++      if (priv->dpdmai_attr.version.major > DPDMAI_VER_MAJOR) {
++              dev_err(dev, "DPDMAI major version mismatch\n"
++                           "Found %u.%u, supported version is %u.%u\n",
++                              priv->dpdmai_attr.version.major,
++                              priv->dpdmai_attr.version.minor,
++                              DPDMAI_VER_MAJOR, DPDMAI_VER_MINOR);
++              goto exit;
++      }
++
++      if (priv->dpdmai_attr.version.minor > DPDMAI_VER_MINOR) {
++              dev_err(dev, "DPDMAI minor version mismatch\n"
++                           "Found %u.%u, supported version is %u.%u\n",
++                              priv->dpdmai_attr.version.major,
++                              priv->dpdmai_attr.version.minor,
++                              DPDMAI_VER_MAJOR, DPDMAI_VER_MINOR);
++              goto exit;
++      }
++
++      priv->num_pairs = min(priv->dpdmai_attr.num_of_priorities, prio_def);
++      ppriv = kcalloc(priv->num_pairs, sizeof(*ppriv), GFP_KERNEL);
++      if (!ppriv) {
++              err = -ENOMEM;
++              goto exit;
++      }
++      priv->ppriv = ppriv;
++
++      for (i = 0; i < priv->num_pairs; i++) {
++              err = dpdmai_get_rx_queue(priv->mc_io, 0, ls_dev->mc_handle,
++                                        i, &priv->rx_queue_attr[i]);
++              if (err) {
++                      dev_err(dev, "dpdmai_get_rx_queue() failed\n");
++                      goto exit;
++              }
++              ppriv->rsp_fqid = priv->rx_queue_attr[i].fqid;
++
++              err = dpdmai_get_tx_queue(priv->mc_io, 0, ls_dev->mc_handle,
++                                        i, &priv->tx_fqid[i]);
++              if (err) {
++                      dev_err(dev, "dpdmai_get_tx_queue() failed\n");
++                      goto exit;
++              }
++              ppriv->req_fqid = priv->tx_fqid[i];
++              ppriv->prio = i;
++              ppriv->priv = priv;
++              ppriv++;
++      }
++
++      return 0;
++exit:
++      dpdmai_close(priv->mc_io, 0, ls_dev->mc_handle);
++      return err;
++}
++
++static void dpaa2_qdma_fqdan_cb(struct dpaa2_io_notification_ctx *ctx)
++{
++      struct dpaa2_qdma_priv_per_prio *ppriv = container_of(ctx,
++                      struct dpaa2_qdma_priv_per_prio, nctx);
++      struct dpaa2_qdma_comp *dpaa2_comp, *_comp_tmp;
++      struct dpaa2_qdma_priv *priv = ppriv->priv;
++      u32 n_chans = priv->dpaa2_qdma->n_chans;
++      struct dpaa2_qdma_chan *qchan;
++      const struct dpaa2_fd *fd_eq;
++      const struct dpaa2_fd *fd;
++      struct dpaa2_dq *dq;
++      int is_last = 0;
++      int found;
++      u8 status;
++      int err;
++      int i;
++
++      do {
++              err = dpaa2_io_service_pull_fq(NULL, ppriv->rsp_fqid,
++                                             ppriv->store);
++      } while (err);
++
++      while (!is_last) {
++              do {
++                      dq = dpaa2_io_store_next(ppriv->store, &is_last);
++              } while (!is_last && !dq);
++              if (!dq) {
++                      dev_err(priv->dev, "FQID returned no valid frames!\n");
++                      continue;
++              }
++
++              /* obtain FD and process the error */
++              fd = dpaa2_dq_fd(dq);
++
++              status = dpaa2_fd_get_ctrl(fd) & 0xff;
++              if (status)
++                      dev_err(priv->dev, "FD error occurred\n");
++              found = 0;
++              for (i = 0; i < n_chans; i++) {
++                      qchan = &priv->dpaa2_qdma->chans[i];
++                      spin_lock(&qchan->queue_lock);
++                      if (list_empty(&qchan->comp_used)) {
++                              spin_unlock(&qchan->queue_lock);
++                              continue;
++                      }
++                      list_for_each_entry_safe(dpaa2_comp, _comp_tmp,
++                                               &qchan->comp_used, list) {
++                              fd_eq = dpaa2_comp->fd_virt_addr;
++
++                              if (le64_to_cpu(fd_eq->simple.addr) ==
++                                  le64_to_cpu(fd->simple.addr)) {
++                                      spin_lock(&qchan->vchan.lock);
++                                      vchan_cookie_complete(&
++                                                      dpaa2_comp->vdesc);
++                                      spin_unlock(&qchan->vchan.lock);
++                                      found = 1;
++                                      break;
++                              }
++                      }
++                      spin_unlock(&qchan->queue_lock);
++                      if (found)
++                              break;
++              }
++      }
++
++      dpaa2_io_service_rearm(NULL, ctx);
++}
++
++static int __cold dpaa2_qdma_dpio_setup(struct dpaa2_qdma_priv *priv)
++{
++      struct dpaa2_qdma_priv_per_prio *ppriv;
++      struct device *dev = priv->dev;
++      int err = -EINVAL;
++      int i, num;
++
++      num = priv->num_pairs;
++      ppriv = priv->ppriv;
++      for (i = 0; i < num; i++) {
++              ppriv->nctx.is_cdan = 0;
++              ppriv->nctx.desired_cpu = DPAA2_IO_ANY_CPU;
++              ppriv->nctx.id = ppriv->rsp_fqid;
++              ppriv->nctx.cb = dpaa2_qdma_fqdan_cb;
++              err = dpaa2_io_service_register(NULL, &ppriv->nctx, dev);
++              if (err) {
++                      dev_err(dev, "Notification register failed\n");
++                      goto err_service;
++              }
++
++              ppriv->store =
++                      dpaa2_io_store_create(DPAA2_QDMA_STORE_SIZE, dev);
++              if (!ppriv->store) {
++                      dev_err(dev, "dpaa2_io_store_create() failed\n");
++                      goto err_store;
++              }
++
++              ppriv++;
++      }
++      return 0;
++
++err_store:
++      dpaa2_io_service_deregister(NULL, &ppriv->nctx, dev);
++err_service:
++      ppriv--;
++      while (ppriv >= priv->ppriv) {
++              dpaa2_io_service_deregister(NULL, &ppriv->nctx, dev);
++              dpaa2_io_store_destroy(ppriv->store);
++              ppriv--;
++      }
++      return err;
++}
++
++static void dpaa2_dpmai_store_free(struct dpaa2_qdma_priv *priv)
++{
++      struct dpaa2_qdma_priv_per_prio *ppriv = priv->ppriv;
++      int i;
++
++      for (i = 0; i < priv->num_pairs; i++) {
++              dpaa2_io_store_destroy(ppriv->store);
++              ppriv++;
++      }
++}
++
++static void dpaa2_dpdmai_dpio_free(struct dpaa2_qdma_priv *priv)
++{
++      struct dpaa2_qdma_priv_per_prio *ppriv = priv->ppriv;
++      struct device *dev = priv->dev;
++      int i;
++
++      for (i = 0; i < priv->num_pairs; i++) {
++              dpaa2_io_service_deregister(NULL, &ppriv->nctx, dev);
++              ppriv++;
++      }
++}
++
++static int __cold dpaa2_dpdmai_bind(struct dpaa2_qdma_priv *priv)
++{
++      struct dpdmai_rx_queue_cfg rx_queue_cfg;
++      struct dpaa2_qdma_priv_per_prio *ppriv;
++      struct device *dev = priv->dev;
++      struct fsl_mc_device *ls_dev;
++      int i, num;
++      int err;
++
++      ls_dev = to_fsl_mc_device(dev);
++      num = priv->num_pairs;
++      ppriv = priv->ppriv;
++      for (i = 0; i < num; i++) {
++              rx_queue_cfg.options = DPDMAI_QUEUE_OPT_USER_CTX |
++                                      DPDMAI_QUEUE_OPT_DEST;
++              rx_queue_cfg.user_ctx = ppriv->nctx.qman64;
++              rx_queue_cfg.dest_cfg.dest_type = DPDMAI_DEST_DPIO;
++              rx_queue_cfg.dest_cfg.dest_id = ppriv->nctx.dpio_id;
++              rx_queue_cfg.dest_cfg.priority = ppriv->prio;
++              err = dpdmai_set_rx_queue(priv->mc_io, 0, ls_dev->mc_handle,
++                                        rx_queue_cfg.dest_cfg.priority,
++                                        &rx_queue_cfg);
++              if (err) {
++                      dev_err(dev, "dpdmai_set_rx_queue() failed\n");
++                      return err;
++              }
++
++              ppriv++;
++      }
++
++      return 0;
++}
++
++static int __cold dpaa2_dpdmai_dpio_unbind(struct dpaa2_qdma_priv *priv)
++{
++      struct dpaa2_qdma_priv_per_prio *ppriv = priv->ppriv;
++      struct device *dev = priv->dev;
++      struct fsl_mc_device *ls_dev;
++      int err = 0;
++      int i;
++
++      ls_dev = to_fsl_mc_device(dev);
++
++      for (i = 0; i < priv->num_pairs; i++) {
++              ppriv->nctx.qman64 = 0;
++              ppriv->nctx.dpio_id = 0;
++              ppriv++;
++      }
++
++      err = dpdmai_reset(priv->mc_io, 0, ls_dev->mc_handle);
++      if (err)
++              dev_err(dev, "dpdmai_reset() failed\n");
++
++      return err;
++}
++
++static void dpaa2_dpdmai_free_comp(struct dpaa2_qdma_chan *qchan,
++                                 struct list_head *head)
++{
++      struct dpaa2_qdma_comp *comp_tmp, *_comp_tmp;
++      unsigned long flags;
++
++      list_for_each_entry_safe(comp_tmp, _comp_tmp,
++                               head, list) {
++              spin_lock_irqsave(&qchan->queue_lock, flags);
++              list_del(&comp_tmp->list);
++              spin_unlock_irqrestore(&qchan->queue_lock, flags);
++              dma_pool_free(qchan->fd_pool,
++                            comp_tmp->fd_virt_addr,
++                            comp_tmp->fd_bus_addr);
++              dma_pool_free(qchan->fl_pool,
++                            comp_tmp->fl_virt_addr,
++                            comp_tmp->fl_bus_addr);
++              dma_pool_free(qchan->sdd_pool,
++                            comp_tmp->desc_virt_addr,
++                            comp_tmp->desc_bus_addr);
++              kfree(comp_tmp);
++      }
++}
++
++static void dpaa2_dpdmai_free_channels(struct dpaa2_qdma_engine *dpaa2_qdma)
++{
++      struct dpaa2_qdma_chan *qchan;
++      int num, i;
++
++      num = dpaa2_qdma->n_chans;
++      for (i = 0; i < num; i++) {
++              qchan = &dpaa2_qdma->chans[i];
++              dpaa2_dpdmai_free_comp(qchan, &qchan->comp_used);
++              dpaa2_dpdmai_free_comp(qchan, &qchan->comp_free);
++              dma_pool_destroy(qchan->fd_pool);
++              dma_pool_destroy(qchan->fl_pool);
++              dma_pool_destroy(qchan->sdd_pool);
++      }
++}
++
++static void dpaa2_qdma_free_desc(struct virt_dma_desc *vdesc)
++{
++      struct dpaa2_qdma_comp *dpaa2_comp;
++      struct dpaa2_qdma_chan *qchan;
++      unsigned long flags;
++
++      dpaa2_comp = to_fsl_qdma_comp(vdesc);
++      qchan = dpaa2_comp->qchan;
++      spin_lock_irqsave(&qchan->queue_lock, flags);
++      list_del(&dpaa2_comp->list);
++      list_add_tail(&dpaa2_comp->list, &qchan->comp_free);
++      spin_unlock_irqrestore(&qchan->queue_lock, flags);
++}
++
++static int dpaa2_dpdmai_init_channels(struct dpaa2_qdma_engine *dpaa2_qdma)
++{
++      struct dpaa2_qdma_priv *priv = dpaa2_qdma->priv;
++      struct dpaa2_qdma_chan *dpaa2_chan;
++      int num = priv->num_pairs;
++      int i;
++
++      INIT_LIST_HEAD(&dpaa2_qdma->dma_dev.channels);
++      for (i = 0; i < dpaa2_qdma->n_chans; i++) {
++              dpaa2_chan = &dpaa2_qdma->chans[i];
++              dpaa2_chan->qdma = dpaa2_qdma;
++              dpaa2_chan->fqid = priv->tx_fqid[i % num];
++              dpaa2_chan->vchan.desc_free = dpaa2_qdma_free_desc;
++              vchan_init(&dpaa2_chan->vchan, &dpaa2_qdma->dma_dev);
++              spin_lock_init(&dpaa2_chan->queue_lock);
++              INIT_LIST_HEAD(&dpaa2_chan->comp_used);
++              INIT_LIST_HEAD(&dpaa2_chan->comp_free);
++      }
++      return 0;
++}
++
++static int dpaa2_qdma_probe(struct fsl_mc_device *dpdmai_dev)
++{
++      struct device *dev = &dpdmai_dev->dev;
++      struct dpaa2_qdma_engine *dpaa2_qdma;
++      struct dpaa2_qdma_priv *priv;
++      int err;
++
++      priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++      dev_set_drvdata(dev, priv);
++      priv->dpdmai_dev = dpdmai_dev;
++
++      priv->iommu_domain = iommu_get_domain_for_dev(dev);
++      if (priv->iommu_domain)
++              smmu_disable = false;
++
++      /* obtain a MC portal */
++      err = fsl_mc_portal_allocate(dpdmai_dev, 0, &priv->mc_io);
++      if (err) {
++              if (err == -ENXIO)
++                      err = -EPROBE_DEFER;
++              else
++                      dev_err(dev, "MC portal allocation failed\n");
++              goto err_mcportal;
++      }
++
++      /* DPDMAI initialization */
++      err = dpaa2_qdma_setup(dpdmai_dev);
++      if (err) {
++              dev_err(dev, "dpaa2_dpdmai_setup() failed\n");
++              goto err_dpdmai_setup;
++      }
++
++      /* DPIO */
++      err = dpaa2_qdma_dpio_setup(priv);
++      if (err) {
++              dev_err(dev, "dpaa2_dpdmai_dpio_setup() failed\n");
++              goto err_dpio_setup;
++      }
++
++      /* DPDMAI binding to DPIO */
++      err = dpaa2_dpdmai_bind(priv);
++      if (err) {
++              dev_err(dev, "dpaa2_dpdmai_bind() failed\n");
++              goto err_bind;
++      }
++
++      /* DPDMAI enable */
++      err = dpdmai_enable(priv->mc_io, 0, dpdmai_dev->mc_handle);
++      if (err) {
++              dev_err(dev, "dpdmai_enable() faile\n");
++              goto err_enable;
++      }
++
++      dpaa2_qdma = kzalloc(sizeof(*dpaa2_qdma), GFP_KERNEL);
++      if (!dpaa2_qdma) {
++              err = -ENOMEM;
++              goto err_eng;
++      }
++
++      priv->dpaa2_qdma = dpaa2_qdma;
++      dpaa2_qdma->priv = priv;
++
++      dpaa2_qdma->desc_allocated = 0;
++      dpaa2_qdma->n_chans = NUM_CH;
++
++      dpaa2_dpdmai_init_channels(dpaa2_qdma);
++
++      if (soc_device_match(soc_fixup_tuning))
++              dpaa2_qdma->qdma_wrtype_fixup = true;
++      else
++              dpaa2_qdma->qdma_wrtype_fixup = false;
++
++      dma_cap_set(DMA_PRIVATE, dpaa2_qdma->dma_dev.cap_mask);
++      dma_cap_set(DMA_SLAVE, dpaa2_qdma->dma_dev.cap_mask);
++      dma_cap_set(DMA_MEMCPY, dpaa2_qdma->dma_dev.cap_mask);
++
++      dpaa2_qdma->dma_dev.dev = dev;
++      dpaa2_qdma->dma_dev.device_alloc_chan_resources =
++              dpaa2_qdma_alloc_chan_resources;
++      dpaa2_qdma->dma_dev.device_free_chan_resources =
++              dpaa2_qdma_free_chan_resources;
++      dpaa2_qdma->dma_dev.device_tx_status = dma_cookie_status;
++      dpaa2_qdma->dma_dev.device_prep_dma_memcpy = dpaa2_qdma_prep_memcpy;
++      dpaa2_qdma->dma_dev.device_issue_pending = dpaa2_qdma_issue_pending;
++
++      err = dma_async_device_register(&dpaa2_qdma->dma_dev);
++      if (err) {
++              dev_err(dev, "Can't register NXP QDMA engine.\n");
++              goto err_dpaa2_qdma;
++      }
++
++      return 0;
++
++err_dpaa2_qdma:
++      kfree(dpaa2_qdma);
++err_eng:
++      dpdmai_disable(priv->mc_io, 0, dpdmai_dev->mc_handle);
++err_enable:
++      dpaa2_dpdmai_dpio_unbind(priv);
++err_bind:
++      dpaa2_dpmai_store_free(priv);
++      dpaa2_dpdmai_dpio_free(priv);
++err_dpio_setup:
++      kfree(priv->ppriv);
++      dpdmai_close(priv->mc_io, 0, dpdmai_dev->mc_handle);
++err_dpdmai_setup:
++      fsl_mc_portal_free(priv->mc_io);
++err_mcportal:
++      kfree(priv);
++      dev_set_drvdata(dev, NULL);
++      return err;
++}
++
++static int dpaa2_qdma_remove(struct fsl_mc_device *ls_dev)
++{
++      struct dpaa2_qdma_engine *dpaa2_qdma;
++      struct dpaa2_qdma_priv *priv;
++      struct device *dev;
++
++      dev = &ls_dev->dev;
++      priv = dev_get_drvdata(dev);
++      dpaa2_qdma = priv->dpaa2_qdma;
++
++      dpdmai_disable(priv->mc_io, 0, ls_dev->mc_handle);
++      dpaa2_dpdmai_dpio_unbind(priv);
++      dpaa2_dpmai_store_free(priv);
++      dpaa2_dpdmai_dpio_free(priv);
++      dpdmai_close(priv->mc_io, 0, ls_dev->mc_handle);
++      fsl_mc_portal_free(priv->mc_io);
++      dev_set_drvdata(dev, NULL);
++      dpaa2_dpdmai_free_channels(dpaa2_qdma);
++
++      dma_async_device_unregister(&dpaa2_qdma->dma_dev);
++      kfree(priv);
++      kfree(dpaa2_qdma);
++
++      return 0;
++}
++
++static const struct fsl_mc_device_id dpaa2_qdma_id_table[] = {
++      {
++              .vendor = FSL_MC_VENDOR_FREESCALE,
++              .obj_type = "dpdmai",
++      },
++      { .vendor = 0x0 }
++};
++
++static struct fsl_mc_driver dpaa2_qdma_driver = {
++      .driver         = {
++              .name   = "dpaa2-qdma",
++              .owner  = THIS_MODULE,
++      },
++      .probe          = dpaa2_qdma_probe,
++      .remove         = dpaa2_qdma_remove,
++      .match_id_table = dpaa2_qdma_id_table
++};
++
++static int __init dpaa2_qdma_driver_init(void)
++{
++      return fsl_mc_driver_register(&(dpaa2_qdma_driver));
++}
++late_initcall(dpaa2_qdma_driver_init);
++
++static void __exit fsl_qdma_exit(void)
++{
++      fsl_mc_driver_unregister(&(dpaa2_qdma_driver));
++}
++module_exit(fsl_qdma_exit);
++
++MODULE_ALIAS("platform:fsl-dpaa2-qdma");
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("NXP Layerscape DPAA2 qDMA engine driver");
+--- /dev/null
++++ b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.h
+@@ -0,0 +1,153 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/* Copyright 2019 NXP */
++
++#ifndef __DPAA2_QDMA_H
++#define __DPAA2_QDMA_H
++
++#define DPAA2_QDMA_STORE_SIZE 16
++#define NUM_CH 8
++
++struct dpaa2_qdma_sd_d {
++      u32 rsv:32;
++      union {
++              struct {
++                      u32 ssd:12; /* souce stride distance */
++                      u32 sss:12; /* souce stride size */
++                      u32 rsv1:8;
++              } sdf;
++              struct {
++                      u32 dsd:12; /* Destination stride distance */
++                      u32 dss:12; /* Destination stride size */
++                      u32 rsv2:8;
++              } ddf;
++      } df;
++      u32 rbpcmd;     /* Route-by-port command */
++      u32 cmd;
++} __attribute__((__packed__));
++
++/* Source descriptor command read transaction type for RBP=0: */
++/* coherent copy of cacheable memory */
++#define QDMA_SD_CMD_RDTTYPE_COHERENT (0xb << 28)
++/* Destination descriptor command write transaction type for RBP=0: */
++/* coherent copy of cacheable memory */
++#define QDMA_DD_CMD_WRTTYPE_COHERENT (0x6 << 28)
++#define LX2160_QDMA_DD_CMD_WRTTYPE_COHERENT (0xb << 28)
++
++#define QMAN_FD_FMT_ENABLE    BIT(0) /* frame list table enable */
++#define QMAN_FD_BMT_ENABLE    BIT(15) /* bypass memory translation */
++#define QMAN_FD_BMT_DISABLE   (0) /* bypass memory translation */
++#define QMAN_FD_SL_DISABLE    (0) /* short lengthe disabled */
++#define QMAN_FD_SL_ENABLE     BIT(14) /* short lengthe enabled */
++
++#define QDMA_FINAL_BIT_DISABLE        (0) /* final bit disable */
++#define QDMA_FINAL_BIT_ENABLE BIT(31) /* final bit enable */
++
++#define QDMA_FD_SHORT_FORMAT  BIT(11) /* short format */
++#define QDMA_FD_LONG_FORMAT   (0) /* long format */
++#define QDMA_SER_DISABLE      (8) /* no notification */
++#define QDMA_SER_CTX          BIT(8) /* notification by FQD_CTX[fqid] */
++#define QDMA_SER_DEST         (2 << 8) /* notification by destination desc */
++#define QDMA_SER_BOTH         (3 << 8) /* soruce and dest notification */
++#define QDMA_FD_SPF_ENALBE    BIT(30) /* source prefetch enable */
++
++#define QMAN_FD_VA_ENABLE     BIT(14) /* Address used is virtual address */
++#define QMAN_FD_VA_DISABLE    (0)/* Address used is a real address */
++/* Flow Context: 49bit physical address */
++#define QMAN_FD_CBMT_ENABLE   BIT(15)
++#define QMAN_FD_CBMT_DISABLE  (0) /* Flow Context: 64bit virtual address */
++#define QMAN_FD_SC_DISABLE    (0) /* stashing control */
++
++#define QDMA_FL_FMT_SBF               (0x0) /* Single buffer frame */
++#define QDMA_FL_FMT_SGE               (0x2) /* Scatter gather frame */
++#define QDMA_FL_BMT_ENABLE    BIT(15) /* enable bypass memory translation */
++#define QDMA_FL_BMT_DISABLE   (0x0) /* enable bypass memory translation */
++#define QDMA_FL_SL_LONG               (0x0)/* long length */
++#define QDMA_FL_SL_SHORT      (0x1) /* short length */
++#define QDMA_FL_F             (0x1)/* last frame list bit */
++
++/*Description of Frame list table structure*/
++struct dpaa2_qdma_chan {
++      struct dpaa2_qdma_engine        *qdma;
++      struct virt_dma_chan            vchan;
++      struct virt_dma_desc            vdesc;
++      enum dma_status                 status;
++      u32                             fqid;
++
++      /* spinlock used by dpaa2 qdma driver */
++      spinlock_t                      queue_lock;
++      struct dma_pool                 *fd_pool;
++      struct dma_pool                 *fl_pool;
++      struct dma_pool                 *sdd_pool;
++
++      struct list_head                comp_used;
++      struct list_head                comp_free;
++
++};
++
++struct dpaa2_qdma_comp {
++      dma_addr_t              fd_bus_addr;
++      dma_addr_t              fl_bus_addr;
++      dma_addr_t              desc_bus_addr;
++      struct dpaa2_fd         *fd_virt_addr;
++      struct dpaa2_fl_entry   *fl_virt_addr;
++      struct dpaa2_qdma_sd_d  *desc_virt_addr;
++      struct dpaa2_qdma_chan  *qchan;
++      struct virt_dma_desc    vdesc;
++      struct list_head        list;
++};
++
++struct dpaa2_qdma_engine {
++      struct dma_device       dma_dev;
++      u32                     n_chans;
++      struct dpaa2_qdma_chan  chans[NUM_CH];
++      int                     qdma_wrtype_fixup;
++      int                     desc_allocated;
++
++      struct dpaa2_qdma_priv *priv;
++};
++
++/*
++ * dpaa2_qdma_priv - driver private data
++ */
++struct dpaa2_qdma_priv {
++      int dpqdma_id;
++
++      struct iommu_domain     *iommu_domain;
++      struct dpdmai_attr      dpdmai_attr;
++      struct device           *dev;
++      struct fsl_mc_io        *mc_io;
++      struct fsl_mc_device    *dpdmai_dev;
++      u8                      num_pairs;
++
++      struct dpaa2_qdma_engine        *dpaa2_qdma;
++      struct dpaa2_qdma_priv_per_prio *ppriv;
++
++      struct dpdmai_rx_queue_attr rx_queue_attr[DPDMAI_PRIO_NUM];
++      u32 tx_fqid[DPDMAI_PRIO_NUM];
++};
++
++struct dpaa2_qdma_priv_per_prio {
++      int req_fqid;
++      int rsp_fqid;
++      int prio;
++
++      struct dpaa2_io_store *store;
++      struct dpaa2_io_notification_ctx nctx;
++
++      struct dpaa2_qdma_priv *priv;
++};
++
++static struct soc_device_attribute soc_fixup_tuning[] = {
++      { .family = "QorIQ LX2160A"},
++      { },
++};
++
++/* FD pool size: one FD + 3 Frame list + 2 source/destination descriptor */
++#define FD_POOL_SIZE (sizeof(struct dpaa2_fd) + \
++              sizeof(struct dpaa2_fl_entry) * 3 + \
++              sizeof(struct dpaa2_qdma_sd_d) * 2)
++
++static void dpaa2_dpdmai_free_channels(struct dpaa2_qdma_engine *dpaa2_qdma);
++static void dpaa2_dpdmai_free_comp(struct dpaa2_qdma_chan *qchan,
++                                 struct list_head *head);
++#endif /* __DPAA2_QDMA_H */
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0003-MLK-14610-DMA-fsl-edma-v3-add-fsl-edma-v3-support.patch b/target/linux/layerscape/patches-5.4/806-dma-0003-MLK-14610-DMA-fsl-edma-v3-add-fsl-edma-v3-support.patch
new file mode 100644 (file)
index 0000000..1744d37
--- /dev/null
@@ -0,0 +1,1008 @@
+From 88476b7fb025afdf9cc2247e8d04ab8e027ce9cb Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Fri, 31 Mar 2017 15:53:39 +0800
+Subject: [PATCH] MLK-14610 DMA: fsl-edma-v3: add fsl-edma-v3 support
+
+Add edma-v3 driver on i.mx8qm.
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+(cherry picked from commit d0ac0971c2e637ebddc853f12f71d130f5df4f91)
+---
+ .../devicetree/bindings/dma/fsl-edma-v3.txt        |  64 ++
+ drivers/dma/Kconfig                                |  11 +
+ drivers/dma/Makefile                               |   1 +
+ drivers/dma/fsl-edma-v3.c                          | 890 +++++++++++++++++++++
+ 4 files changed, 966 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/dma/fsl-edma-v3.txt
+ create mode 100644 drivers/dma/fsl-edma-v3.c
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/dma/fsl-edma-v3.txt
+@@ -0,0 +1,64 @@
++* Freescale enhanced Direct Memory Access(eDMA-v3) Controller
++
++  The eDMA-v3 controller is inherited from FSL eDMA, and firstly is intergrated
++  on Freescale i.MX8QM SOC chip. The eDMA channels have multiplex capability by
++  programmble memory-mapped registers. Specific DMA request source has fixed channel.
++
++* eDMA Controller
++Required properties:
++- compatible :
++      - "fsl,imx8qm-edma" for eDMA used similar to that on i.MX8QM SoC
++      - "fsl,imx8qm-adma" for audio eDMA used on i.MX8QM
++- reg : Specifies base physical address(s) and size of the eDMA channel registers.
++      Each eDMA channel has separated register's address and size.
++- interrupts : A list of interrupt-specifiers, each channel has one interrupt.
++- interrupt-names : Should contain:
++      "edma-chan12-tx" - the channel12 transmission interrupt
++- #dma-cells : Must be <3>.
++      The 1st cell specifies the channel ID.
++      The 2nd cell specifies the channel priority.
++      The 3rd cell specifies the channel type like for transmit or receive:
++              0: transmit, 1: receive.
++      See the SoC's reference manual for all the supported request sources.
++- dma-channels : Number of channels supported by the controller
++
++Examples:
++edma0: dma-controller@40018000 {
++      compatible = "fsl,imx8qm-edma";
++      reg = <0x0 0x5a2c0000 0x0 0x10000>, /* channel12 UART0 rx */
++            <0x0 0x5a2d0000 0x0 0x10000>, /* channel13 UART0 tx */
++            <0x0 0x5a2e0000 0x0 0x10000>, /* channel14 UART1 rx */
++            <0x0 0x5a2f0000 0x0 0x10000>; /* channel15 UART1 tx */
++      #dma-cells = <3>;
++      dma-channels = <4>;
++      interrupts = <GIC_SPI 434 IRQ_TYPE_LEVEL_HIGH>,
++                   <GIC_SPI 435 IRQ_TYPE_LEVEL_HIGH>,
++                   <GIC_SPI 436 IRQ_TYPE_LEVEL_HIGH>,
++                   <GIC_SPI 437 IRQ_TYPE_LEVEL_HIGH>;
++      interrupt-names = "edma-chan12-tx", "edma-chan13-tx",
++                        "edma-chan14-tx", "edma-chan15-tx";
++      status = "okay";
++};
++
++* DMA clients
++DMA client drivers that uses the DMA function must use the format described
++in the dma.txt file, using a three-cell specifier for each channel: the 1st
++specifies the channel number, the 2nd specifies the priority, and the 3rd
++specifies the channel type is for transmit or receive: 0: transmit, 1: receive.
++
++Examples:
++lpuart1: serial@5a070000 {
++      compatible = "fsl,imx8qm-lpuart";
++      reg = <0x0 0x5a070000 0x0 0x1000>;
++      interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
++      interrupt-parent = <&gic>;
++      clocks = <&clk IMX8QM_UART1_CLK>;
++      clock-names = "ipg";
++      assigned-clock-names = <&clk IMX8QM_UART1_CLK>;
++      assigned-clock-rates = <80000000>;
++      power-domains = <&pd_dma_lpuart1>;
++      dma-names = "tx","rx";
++      dmas = <&edma0 15 0 0>,
++              <&edma0 14 0 1>;
++      status = "disabled";
++};
+--- a/drivers/dma/Kconfig
++++ b/drivers/dma/Kconfig
+@@ -227,6 +227,17 @@ config FSL_QDMA
+          or dequeuing DMA jobs from, different work queues.
+          This module can be found on NXP Layerscape SoCs.
+         The qdma driver only work on  SoCs with a DPAA hardware block.
++config FSL_EDMA_V3
++      tristate "Freescale eDMA v3 engine support"
++      depends on OF
++      select DMA_ENGINE
++      select DMA_VIRTUAL_CHANNELS
++      help
++        Support the Freescale eDMA v3 engine with programmable channel.
++        This driver is based on FSL_EDMA but big changes come such as
++        different interrupt for different channel, different register
++        scope for different channel.
++        This module can be found on Freescale i.MX8QM.
+ config FSL_RAID
+         tristate "Freescale RAID engine Support"
+--- a/drivers/dma/Makefile
++++ b/drivers/dma/Makefile
+@@ -32,6 +32,7 @@ obj-$(CONFIG_DW_EDMA) += dw-edma/
+ obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
+ obj-$(CONFIG_FSL_DMA) += fsldma.o
+ obj-$(CONFIG_FSL_EDMA) += fsl-edma.o fsl-edma-common.o
++obj-$(CONFIG_FSL_EDMA_V3) += fsl-edma-v3.o
+ obj-$(CONFIG_MCF_EDMA) += mcf-edma.o fsl-edma-common.o
+ obj-$(CONFIG_FSL_QDMA) += fsl-qdma.o
+ obj-$(CONFIG_FSL_RAID) += fsl_raid.o
+--- /dev/null
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -0,0 +1,890 @@
++/*
++ * drivers/dma/fsl-edma3-v3.c
++ *
++ * Copyright 2017 NXP .
++ *
++ * Driver for the Freescale eDMA engine v3. This driver based on fsl-edma3.c
++ * but changed to meet the IP change on i.MX8QM: every dma channel is specific
++ * to hardware. For example, channel 14 for LPUART1 receive request and channel
++ * 13 for transmit requesst. The eDMA block can be found on i.MX8QM
++ *
++ * This program is free software; you can redistribute  it and/or modify it
++ * under  the terms of  the GNU General  Public License as published by the
++ * Free Software Foundation;  either version 2 of the  License, or (at your
++ * option) any later version.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/clk.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmapool.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/of_dma.h>
++
++#include "virt-dma.h"
++
++#define EDMA_CH_CSR                   0x00
++#define EDMA_CH_ES                    0x04
++#define EDMA_CH_INT                   0x08
++#define EDMA_CH_SBR                   0x0C
++#define EDMA_CH_PRI                   0x10
++#define EDMA_TCD_SADDR                        0x20
++#define EDMA_TCD_SOFF                 0x24
++#define EDMA_TCD_ATTR                 0x26
++#define EDMA_TCD_NBYTES                       0x28
++#define EDMA_TCD_SLAST                        0x2C
++#define EDMA_TCD_DADDR                        0x30
++#define EDMA_TCD_DOFF                 0x34
++#define EDMA_TCD_CITER_ELINK          0x36
++#define EDMA_TCD_CITER                        0x36
++#define EDMA_TCD_DLAST_SGA            0x38
++#define EDMA_TCD_CSR                  0x3C
++#define EDMA_TCD_BITER_ELINK          0x3E
++#define EDMA_TCD_BITER                        0x3E
++
++#define EDMA_CH_SBR_RD                BIT(22)
++#define EDMA_CH_SBR_WR                BIT(21)
++#define EDMA_CH_CSR_ERQ               BIT(0)
++#define EDMA_CH_CSR_EARQ      BIT(1)
++#define EDMA_CH_CSR_EEI               BIT(2)
++#define EDMA_CH_CSR_DONE      BIT(30)
++#define EDMA_CH_CSR_ACTIVE    BIT(31)
++
++#define EDMA_TCD_ATTR_DSIZE(x)                (((x) & 0x0007))
++#define EDMA_TCD_ATTR_DMOD(x)         (((x) & 0x001F) << 3)
++#define EDMA_TCD_ATTR_SSIZE(x)                (((x) & 0x0007) << 8)
++#define EDMA_TCD_ATTR_SMOD(x)         (((x) & 0x001F) << 11)
++#define EDMA_TCD_ATTR_SSIZE_8BIT      (0x0000)
++#define EDMA_TCD_ATTR_SSIZE_16BIT     (0x0100)
++#define EDMA_TCD_ATTR_SSIZE_32BIT     (0x0200)
++#define EDMA_TCD_ATTR_SSIZE_64BIT     (0x0300)
++#define EDMA_TCD_ATTR_SSIZE_16BYTE    (0x0400)
++#define EDMA_TCD_ATTR_SSIZE_32BYTE    (0x0500)
++#define EDMA_TCD_ATTR_SSIZE_64BYTE    (0x0600)
++#define EDMA_TCD_ATTR_DSIZE_8BIT      (0x0000)
++#define EDMA_TCD_ATTR_DSIZE_16BIT     (0x0001)
++#define EDMA_TCD_ATTR_DSIZE_32BIT     (0x0002)
++#define EDMA_TCD_ATTR_DSIZE_64BIT     (0x0003)
++#define EDMA_TCD_ATTR_DSIZE_16BYTE    (0x0004)
++#define EDMA_TCD_ATTR_DSIZE_32BYTE    (0x0005)
++#define EDMA_TCD_ATTR_DSIZE_64BYTE    (0x0006)
++
++#define EDMA_TCD_SOFF_SOFF(x)         (x)
++#define EDMA_TCD_NBYTES_NBYTES(x)     (x)
++#define EDMA_TCD_SLAST_SLAST(x)               (x)
++#define EDMA_TCD_DADDR_DADDR(x)               (x)
++#define EDMA_TCD_CITER_CITER(x)               ((x) & 0x7FFF)
++#define EDMA_TCD_DOFF_DOFF(x)         (x)
++#define EDMA_TCD_DLAST_SGA_DLAST_SGA(x)       (x)
++#define EDMA_TCD_BITER_BITER(x)               ((x) & 0x7FFF)
++
++#define EDMA_TCD_CSR_START            BIT(0)
++#define EDMA_TCD_CSR_INT_MAJOR                BIT(1)
++#define EDMA_TCD_CSR_INT_HALF         BIT(2)
++#define EDMA_TCD_CSR_D_REQ            BIT(3)
++#define EDMA_TCD_CSR_E_SG             BIT(4)
++#define EDMA_TCD_CSR_E_LINK           BIT(5)
++#define EDMA_TCD_CSR_ACTIVE           BIT(6)
++#define EDMA_TCD_CSR_DONE             BIT(7)
++
++#define FSL_EDMA_BUSWIDTHS    (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
++                              BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
++                              BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
++                              BIT(DMA_SLAVE_BUSWIDTH_8_BYTES) | \
++                              BIT(DMA_SLAVE_BUSWIDTH_16_BYTES))
++
++struct fsl_edma3_hw_tcd {
++      __le32  saddr;
++      __le16  soff;
++      __le16  attr;
++      __le32  nbytes;
++      __le32  slast;
++      __le32  daddr;
++      __le16  doff;
++      __le16  citer;
++      __le32  dlast_sga;
++      __le16  csr;
++      __le16  biter;
++};
++
++struct fsl_edma3_sw_tcd {
++      dma_addr_t                      ptcd;
++      struct fsl_edma3_hw_tcd         *vtcd;
++};
++
++struct fsl_edma3_slave_config {
++      enum dma_transfer_direction     dir;
++      enum dma_slave_buswidth         addr_width;
++      u32                             dev_addr;
++      u32                             dev2_addr; /* source addr for dev2dev */
++      u32                             burst;
++      u32                             attr;
++};
++
++struct fsl_edma3_chan {
++      struct virt_dma_chan            vchan;
++      enum dma_status                 status;
++      struct fsl_edma3_engine         *edma3;
++      struct fsl_edma3_desc           *edesc;
++      struct fsl_edma3_slave_config   fsc;
++      void __iomem                    *membase;
++      int                             txirq;
++      int                             hw_chanid;
++      int                             priority;
++      int                             is_rxchan;
++      struct dma_pool                 *tcd_pool;
++      u32                             chn_real_count;
++      char                            txirq_name[32];
++};
++
++struct fsl_edma3_desc {
++      struct virt_dma_desc            vdesc;
++      struct fsl_edma3_chan           *echan;
++      bool                            iscyclic;
++      unsigned int                    n_tcds;
++      struct fsl_edma3_sw_tcd         tcd[];
++};
++
++struct fsl_edma3_engine {
++      struct dma_device       dma_dev;
++      struct mutex            fsl_edma3_mutex;
++      u32                     n_chans;
++      int                     errirq;
++      bool                    swap;   /* remote/local swapped on Audio edma */
++      struct fsl_edma3_chan   chans[];
++};
++
++static struct fsl_edma3_chan *to_fsl_edma3_chan(struct dma_chan *chan)
++{
++      return container_of(chan, struct fsl_edma3_chan, vchan.chan);
++}
++
++static struct fsl_edma3_desc *to_fsl_edma3_desc(struct virt_dma_desc *vd)
++{
++      return container_of(vd, struct fsl_edma3_desc, vdesc);
++}
++
++static void fsl_edma3_enable_request(struct fsl_edma3_chan *fsl_chan)
++{
++      void __iomem *addr = fsl_chan->membase;
++      u32 val;
++
++      val = readl(addr + EDMA_CH_SBR);
++      /* Remote/local swapped wrongly on iMX8 QM Audio edma */
++      if (fsl_chan->edma3->swap) {
++              if (!fsl_chan->is_rxchan)
++                      val |= EDMA_CH_SBR_RD;
++              else
++                      val |= EDMA_CH_SBR_WR;
++      } else {
++              if (fsl_chan->is_rxchan)
++                      val |= EDMA_CH_SBR_RD;
++              else
++                      val |= EDMA_CH_SBR_WR;
++      }
++      writel(val, addr + EDMA_CH_SBR);
++
++      val = readl(addr + EDMA_CH_CSR);
++
++      val |= EDMA_CH_CSR_ERQ;
++      writel(val, addr + EDMA_CH_CSR);
++}
++
++static void fsl_edma3_disable_request(struct fsl_edma3_chan *fsl_chan)
++{
++      void __iomem *addr = fsl_chan->membase;
++      u32 val = readl(addr + EDMA_CH_CSR);
++
++      val &= ~EDMA_CH_CSR_ERQ;
++      writel(val, addr + EDMA_CH_CSR);
++}
++
++static unsigned int fsl_edma3_get_tcd_attr(enum dma_slave_buswidth addr_width)
++{
++      switch (addr_width) {
++      case 1:
++              return EDMA_TCD_ATTR_SSIZE_8BIT | EDMA_TCD_ATTR_DSIZE_8BIT;
++      case 2:
++              return EDMA_TCD_ATTR_SSIZE_16BIT | EDMA_TCD_ATTR_DSIZE_16BIT;
++      case 4:
++              return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
++      case 8:
++              return EDMA_TCD_ATTR_SSIZE_64BIT | EDMA_TCD_ATTR_DSIZE_64BIT;
++      case 16:
++              return EDMA_TCD_ATTR_SSIZE_16BYTE | EDMA_TCD_ATTR_DSIZE_16BYTE;
++      case 32:
++              return EDMA_TCD_ATTR_SSIZE_32BYTE | EDMA_TCD_ATTR_DSIZE_32BYTE;
++      case 64:
++              return EDMA_TCD_ATTR_SSIZE_64BYTE | EDMA_TCD_ATTR_DSIZE_64BYTE;
++      default:
++              return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
++      }
++}
++
++static void fsl_edma3_free_desc(struct virt_dma_desc *vdesc)
++{
++      struct fsl_edma3_desc *fsl_desc;
++      int i;
++
++      fsl_desc = to_fsl_edma3_desc(vdesc);
++      for (i = 0; i < fsl_desc->n_tcds; i++)
++              dma_pool_free(fsl_desc->echan->tcd_pool, fsl_desc->tcd[i].vtcd,
++                            fsl_desc->tcd[i].ptcd);
++      kfree(fsl_desc);
++}
++
++static int fsl_edma3_terminate_all(struct dma_chan *chan)
++{
++      struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
++      unsigned long flags;
++      LIST_HEAD(head);
++
++      spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
++      fsl_edma3_disable_request(fsl_chan);
++      fsl_chan->edesc = NULL;
++      vchan_get_all_descriptors(&fsl_chan->vchan, &head);
++      spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
++      vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
++      return 0;
++}
++
++static int fsl_edma3_pause(struct dma_chan *chan)
++{
++      struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
++      unsigned long flags;
++
++      spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
++      if (fsl_chan->edesc) {
++              fsl_edma3_disable_request(fsl_chan);
++              fsl_chan->status = DMA_PAUSED;
++      }
++      spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
++      return 0;
++}
++
++static int fsl_edma3_resume(struct dma_chan *chan)
++{
++      struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
++      unsigned long flags;
++
++      spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
++      if (fsl_chan->edesc) {
++              fsl_edma3_enable_request(fsl_chan);
++              fsl_chan->status = DMA_IN_PROGRESS;
++      }
++      spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
++      return 0;
++}
++
++static int fsl_edma3_slave_config(struct dma_chan *chan,
++                               struct dma_slave_config *cfg)
++{
++      struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
++
++      fsl_chan->fsc.dir = cfg->direction;
++      if (cfg->direction == DMA_DEV_TO_MEM) {
++              fsl_chan->fsc.dev_addr = cfg->src_addr;
++              fsl_chan->fsc.addr_width = cfg->src_addr_width;
++              fsl_chan->fsc.burst = cfg->src_maxburst;
++              fsl_chan->fsc.attr = fsl_edma3_get_tcd_attr
++                                      (cfg->src_addr_width);
++      } else if (cfg->direction == DMA_MEM_TO_DEV) {
++              fsl_chan->fsc.dev_addr = cfg->dst_addr;
++              fsl_chan->fsc.addr_width = cfg->dst_addr_width;
++              fsl_chan->fsc.burst = cfg->dst_maxburst;
++              fsl_chan->fsc.attr = fsl_edma3_get_tcd_attr
++                                      (cfg->dst_addr_width);
++      } else if (cfg->direction == DMA_DEV_TO_DEV) {
++              fsl_chan->fsc.dev2_addr = cfg->src_addr;
++              fsl_chan->fsc.dev_addr = cfg->dst_addr;
++              fsl_chan->fsc.addr_width = cfg->dst_addr_width;
++              fsl_chan->fsc.burst = cfg->dst_maxburst;
++              fsl_chan->fsc.attr = fsl_edma3_get_tcd_attr
++                                      (cfg->dst_addr_width);
++      } else {
++                      return -EINVAL;
++      }
++      return 0;
++}
++
++static size_t fsl_edma3_desc_residue(struct fsl_edma3_chan *fsl_chan,
++              struct virt_dma_desc *vdesc, bool in_progress)
++{
++      struct fsl_edma3_desc *edesc = fsl_chan->edesc;
++      void __iomem *addr = fsl_chan->membase;
++      enum dma_transfer_direction dir = fsl_chan->fsc.dir;
++      dma_addr_t cur_addr, dma_addr;
++      size_t len, size;
++      int i;
++
++      /* calculate the total size in this desc */
++      for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++)
++              len += le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
++                      * le16_to_cpu(edesc->tcd[i].vtcd->biter);
++
++      if (!in_progress)
++              return len;
++
++      if (dir == DMA_MEM_TO_DEV)
++              cur_addr = readl(addr + EDMA_TCD_SADDR);
++      else
++              cur_addr = readl(addr + EDMA_TCD_DADDR);
++
++      /* figure out the finished and calculate the residue */
++      for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
++              size = le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
++                      * le16_to_cpu(edesc->tcd[i].vtcd->biter);
++              if (dir == DMA_MEM_TO_DEV)
++                      dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->saddr);
++              else
++                      dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->daddr);
++
++              len -= size;
++              if (cur_addr >= dma_addr && cur_addr < dma_addr + size) {
++                      len += dma_addr + size - cur_addr;
++                      break;
++              }
++      }
++
++      return len;
++}
++
++static enum dma_status fsl_edma3_tx_status(struct dma_chan *chan,
++              dma_cookie_t cookie, struct dma_tx_state *txstate)
++{
++      struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
++      struct virt_dma_desc *vdesc;
++      enum dma_status status;
++      unsigned long flags;
++
++      status = dma_cookie_status(chan, cookie, txstate);
++      if (status == DMA_COMPLETE) {
++              spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
++              txstate->residue = fsl_chan->chn_real_count;
++              spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
++              return status;
++      }
++
++      if (!txstate)
++              return fsl_chan->status;
++
++      spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
++      vdesc = vchan_find_desc(&fsl_chan->vchan, cookie);
++      if (fsl_chan->edesc && cookie == fsl_chan->edesc->vdesc.tx.cookie)
++              txstate->residue = fsl_edma3_desc_residue(fsl_chan, vdesc,
++                                                              true);
++      else if (vdesc)
++              txstate->residue = fsl_edma3_desc_residue(fsl_chan, vdesc,
++                                                              false);
++      else
++              txstate->residue = 0;
++
++      spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
++
++      return fsl_chan->status;
++}
++
++static void fsl_edma3_set_tcd_regs(struct fsl_edma3_chan *fsl_chan,
++                                struct fsl_edma3_hw_tcd *tcd)
++{
++      void __iomem *addr = fsl_chan->membase;
++      /*
++       * TCD parameters are stored in struct fsl_edma3_hw_tcd in little
++       * endian format. However, we need to load the TCD registers in
++       * big- or little-endian obeying the eDMA engine model endian.
++       */
++      writew(0, addr + EDMA_TCD_CSR);
++      writel(le32_to_cpu(tcd->saddr), addr + EDMA_TCD_SADDR);
++      writel(le32_to_cpu(tcd->daddr), addr + EDMA_TCD_DADDR);
++
++      writew(le16_to_cpu(tcd->attr), addr + EDMA_TCD_ATTR);
++      writew(le16_to_cpu(tcd->soff), addr + EDMA_TCD_SOFF);
++
++      writel(le32_to_cpu(tcd->nbytes), addr + EDMA_TCD_NBYTES);
++      writel(le32_to_cpu(tcd->slast), addr + EDMA_TCD_SLAST);
++
++      writew(le16_to_cpu(tcd->citer), addr + EDMA_TCD_CITER);
++      writew(le16_to_cpu(tcd->biter), addr + EDMA_TCD_BITER);
++      writew(le16_to_cpu(tcd->doff), addr + EDMA_TCD_DOFF);
++
++      writel(le32_to_cpu(tcd->dlast_sga), addr + EDMA_TCD_DLAST_SGA);
++
++      writew(le16_to_cpu(tcd->csr), addr + EDMA_TCD_CSR);
++}
++
++static inline
++void fsl_edma3_fill_tcd(struct fsl_edma3_chan *fsl_chan,
++                      struct fsl_edma3_hw_tcd *tcd, u32 src, u32 dst,
++                      u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer,
++                      u16 biter, u16 doff, u32 dlast_sga, bool major_int,
++                      bool disable_req, bool enable_sg)
++{
++      u16 csr = 0;
++
++      /*
++       * eDMA hardware SGs require the TCDs to be stored in little
++       * endian format irrespective of the register endian model.
++       * So we put the value in little endian in memory, waiting
++       * for fsl_edma3_set_tcd_regs doing the swap.
++       */
++      tcd->saddr = cpu_to_le32(src);
++      tcd->daddr = cpu_to_le32(dst);
++
++      tcd->attr = cpu_to_le16(attr);
++
++      tcd->soff = cpu_to_le16(EDMA_TCD_SOFF_SOFF(soff));
++
++      tcd->nbytes = cpu_to_le32(EDMA_TCD_NBYTES_NBYTES(nbytes));
++      tcd->slast = cpu_to_le32(EDMA_TCD_SLAST_SLAST(slast));
++
++      tcd->citer = cpu_to_le16(EDMA_TCD_CITER_CITER(citer));
++      tcd->doff = cpu_to_le16(EDMA_TCD_DOFF_DOFF(doff));
++
++      tcd->dlast_sga = cpu_to_le32(EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga));
++
++      tcd->biter = cpu_to_le16(EDMA_TCD_BITER_BITER(biter));
++      if (major_int)
++              csr |= EDMA_TCD_CSR_INT_MAJOR;
++
++      if (disable_req)
++              csr |= EDMA_TCD_CSR_D_REQ;
++
++      if (enable_sg)
++              csr |= EDMA_TCD_CSR_E_SG;
++
++      if (fsl_chan->is_rxchan)
++              csr |= EDMA_TCD_CSR_ACTIVE;
++
++      tcd->csr = cpu_to_le16(csr);
++}
++
++static struct fsl_edma3_desc *fsl_edma3_alloc_desc(struct fsl_edma3_chan
++                                              *fsl_chan, int sg_len)
++{
++      struct fsl_edma3_desc *fsl_desc;
++      int i;
++
++      fsl_desc = kzalloc(sizeof(*fsl_desc) + sizeof(struct fsl_edma3_sw_tcd)
++                              * sg_len, GFP_ATOMIC);
++      if (!fsl_desc)
++              return NULL;
++
++      fsl_desc->echan = fsl_chan;
++      fsl_desc->n_tcds = sg_len;
++      for (i = 0; i < sg_len; i++) {
++              fsl_desc->tcd[i].vtcd = dma_pool_alloc(fsl_chan->tcd_pool,
++                                      GFP_ATOMIC, &fsl_desc->tcd[i].ptcd);
++              if (!fsl_desc->tcd[i].vtcd)
++                      goto err;
++      }
++      return fsl_desc;
++
++err:
++      while (--i >= 0)
++              dma_pool_free(fsl_chan->tcd_pool, fsl_desc->tcd[i].vtcd,
++                              fsl_desc->tcd[i].ptcd);
++      kfree(fsl_desc);
++      return NULL;
++}
++
++static struct dma_async_tx_descriptor *fsl_edma3_prep_dma_cyclic(
++              struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
++              size_t period_len, enum dma_transfer_direction direction,
++              unsigned long flags)
++{
++      struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
++      struct fsl_edma3_desc *fsl_desc;
++      dma_addr_t dma_buf_next;
++      int sg_len, i;
++      u32 src_addr, dst_addr, last_sg, nbytes;
++      u16 soff, doff, iter;
++
++      sg_len = buf_len / period_len;
++      fsl_desc = fsl_edma3_alloc_desc(fsl_chan, sg_len);
++      if (!fsl_desc)
++              return NULL;
++      fsl_desc->iscyclic = true;
++
++      dma_buf_next = dma_addr;
++      nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
++      iter = period_len / nbytes;
++
++      for (i = 0; i < sg_len; i++) {
++              if (dma_buf_next >= dma_addr + buf_len)
++                      dma_buf_next = dma_addr;
++
++              /* get next sg's physical address */
++              last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
++
++              if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
++                      src_addr = dma_buf_next;
++                      dst_addr = fsl_chan->fsc.dev_addr;
++                      soff = fsl_chan->fsc.addr_width;
++                      doff = 0;
++              } else if (fsl_chan->fsc.dir == DMA_DEV_TO_MEM) {
++                      src_addr = fsl_chan->fsc.dev_addr;
++                      dst_addr = dma_buf_next;
++                      soff = 0;
++                      doff = fsl_chan->fsc.addr_width;
++              } else {
++                      /* DMA_DEV_TO_DEV */
++                      src_addr = fsl_chan->fsc.dev2_addr;
++                      dst_addr = fsl_chan->fsc.dev_addr;
++                      soff = 0;
++                      doff = 0;
++              }
++
++              fsl_edma3_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd, src_addr,
++                              dst_addr, fsl_chan->fsc.attr, soff, nbytes, 0,
++                              iter, iter, doff, last_sg, true, false, true);
++              dma_buf_next += period_len;
++      }
++
++      return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
++}
++
++static struct dma_async_tx_descriptor *fsl_edma3_prep_slave_sg(
++              struct dma_chan *chan, struct scatterlist *sgl,
++              unsigned int sg_len, enum dma_transfer_direction direction,
++              unsigned long flags, void *context)
++{
++      struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
++      struct fsl_edma3_desc *fsl_desc;
++      struct scatterlist *sg;
++      u32 src_addr, dst_addr, last_sg, nbytes;
++      u16 soff, doff, iter;
++      int i;
++
++      if (!is_slave_direction(fsl_chan->fsc.dir))
++              return NULL;
++
++      fsl_desc = fsl_edma3_alloc_desc(fsl_chan, sg_len);
++      if (!fsl_desc)
++              return NULL;
++      fsl_desc->iscyclic = false;
++
++      nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
++      for_each_sg(sgl, sg, sg_len, i) {
++              /* get next sg's physical address */
++              last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
++
++              if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
++                      src_addr = sg_dma_address(sg);
++                      dst_addr = fsl_chan->fsc.dev_addr;
++                      soff = fsl_chan->fsc.addr_width;
++                      doff = 0;
++              } else if (fsl_chan->fsc.dir == DMA_DEV_TO_MEM) {
++                      src_addr = fsl_chan->fsc.dev_addr;
++                      dst_addr = sg_dma_address(sg);
++                      soff = 0;
++                      doff = fsl_chan->fsc.addr_width;
++              } else {
++                      /* DMA_DEV_TO_DEV */
++                      src_addr = fsl_chan->fsc.dev2_addr;
++                      dst_addr = fsl_chan->fsc.dev_addr;
++                      soff = 0;
++                      doff = 0;
++              }
++
++              iter = sg_dma_len(sg) / nbytes;
++              if (i < sg_len - 1) {
++                      last_sg = fsl_desc->tcd[(i + 1)].ptcd;
++                      fsl_edma3_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd,
++                                      src_addr, dst_addr, fsl_chan->fsc.attr,
++                                      soff, nbytes, 0, iter, iter, doff,
++                                      last_sg, false, false, true);
++              } else {
++                      last_sg = 0;
++                      fsl_edma3_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd,
++                                      src_addr, dst_addr, fsl_chan->fsc.attr,
++                                      soff, nbytes, 0, iter, iter, doff,
++                                      last_sg, true, true, false);
++              }
++      }
++
++      return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
++}
++
++static void fsl_edma3_xfer_desc(struct fsl_edma3_chan *fsl_chan)
++{
++      struct virt_dma_desc *vdesc;
++
++      vdesc = vchan_next_desc(&fsl_chan->vchan);
++      if (!vdesc)
++              return;
++      fsl_chan->edesc = to_fsl_edma3_desc(vdesc);
++      fsl_edma3_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
++      fsl_edma3_enable_request(fsl_chan);
++      fsl_chan->status = DMA_IN_PROGRESS;
++}
++
++static size_t fsl_edma3_desc_residue(struct fsl_edma3_chan *fsl_chan,
++              struct virt_dma_desc *vdesc, bool in_progress);
++
++static void fsl_edma3_get_realcnt(struct fsl_edma3_chan *fsl_chan)
++{
++      fsl_chan->chn_real_count = fsl_edma3_desc_residue(fsl_chan, NULL, true);
++}
++
++static irqreturn_t fsl_edma3_tx_handler(int irq, void *dev_id)
++{
++      struct fsl_edma3_chan *fsl_chan = dev_id;
++      unsigned int intr;
++      void __iomem *base_addr;
++
++      base_addr = fsl_chan->membase;
++
++      intr = readl(base_addr + EDMA_CH_INT);
++      if (!intr)
++              return IRQ_NONE;
++
++      writel(1, base_addr + EDMA_CH_INT);
++
++      spin_lock(&fsl_chan->vchan.lock);
++      if (!fsl_chan->edesc->iscyclic) {
++              fsl_edma3_get_realcnt(fsl_chan);
++              list_del(&fsl_chan->edesc->vdesc.node);
++              vchan_cookie_complete(&fsl_chan->edesc->vdesc);
++              fsl_chan->edesc = NULL;
++              fsl_chan->status = DMA_COMPLETE;
++      } else {
++              vchan_cyclic_callback(&fsl_chan->edesc->vdesc);
++      }
++
++      if (!fsl_chan->edesc)
++              fsl_edma3_xfer_desc(fsl_chan);
++
++      spin_unlock(&fsl_chan->vchan.lock);
++
++      return IRQ_HANDLED;
++}
++
++static void fsl_edma3_issue_pending(struct dma_chan *chan)
++{
++      struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
++      unsigned long flags;
++
++      spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
++
++      if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
++              fsl_edma3_xfer_desc(fsl_chan);
++
++      spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
++}
++
++static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec,
++              struct of_dma *ofdma)
++{
++      struct fsl_edma3_engine *fsl_edma3 = ofdma->of_dma_data;
++      struct dma_chan *chan, *_chan;
++      struct fsl_edma3_chan *fsl_chan;
++
++      if (dma_spec->args_count != 3)
++              return NULL;
++
++      mutex_lock(&fsl_edma3->fsl_edma3_mutex);
++      list_for_each_entry_safe(chan, _chan, &fsl_edma3->dma_dev.channels,
++                                      device_node) {
++              if (chan->client_count)
++                      continue;
++
++              fsl_chan = to_fsl_edma3_chan(chan);
++              if (fsl_chan->hw_chanid == dma_spec->args[0]) {
++                      chan = dma_get_slave_channel(chan);
++                      chan->device->privatecnt++;
++                      fsl_chan->priority = dma_spec->args[1];
++                      fsl_chan->is_rxchan = dma_spec->args[2];
++                      mutex_unlock(&fsl_edma3->fsl_edma3_mutex);
++                      return chan;
++              }
++      }
++      mutex_unlock(&fsl_edma3->fsl_edma3_mutex);
++      return NULL;
++}
++
++static int fsl_edma3_alloc_chan_resources(struct dma_chan *chan)
++{
++      struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
++
++      fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
++                              sizeof(struct fsl_edma3_hw_tcd),
++                              32, 0);
++      return 0;
++}
++
++static void fsl_edma3_free_chan_resources(struct dma_chan *chan)
++{
++      struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
++      unsigned long flags;
++      LIST_HEAD(head);
++
++      spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
++      fsl_edma3_disable_request(fsl_chan);
++      fsl_chan->edesc = NULL;
++      vchan_get_all_descriptors(&fsl_chan->vchan, &head);
++      spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
++
++      vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
++      dma_pool_destroy(fsl_chan->tcd_pool);
++      fsl_chan->tcd_pool = NULL;
++}
++
++static int fsl_edma3_probe(struct platform_device *pdev)
++{
++      struct device_node *np = pdev->dev.of_node;
++      struct fsl_edma3_engine *fsl_edma3;
++      struct fsl_edma3_chan *fsl_chan;
++      struct resource *res;
++      int len, chans;
++      int ret, i;
++      unsigned long irqflag = 0;
++
++      ret = of_property_read_u32(np, "dma-channels", &chans);
++      if (ret) {
++              dev_err(&pdev->dev, "Can't get dma-channels.\n");
++              return ret;
++      }
++
++      len = sizeof(*fsl_edma3) + sizeof(*fsl_chan) * chans;
++      fsl_edma3 = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
++      if (!fsl_edma3)
++              return -ENOMEM;
++
++      /* Audio edma rx/tx channel shared interrupt */
++      if (of_property_read_bool(np, "shared-interrupt"))
++              irqflag = IRQF_SHARED;
++
++      fsl_edma3->swap = of_device_is_compatible(np, "fsl,imx8qm-adma");
++      fsl_edma3->n_chans = chans;
++
++      INIT_LIST_HEAD(&fsl_edma3->dma_dev.channels);
++      for (i = 0; i < fsl_edma3->n_chans; i++) {
++              struct fsl_edma3_chan *fsl_chan = &fsl_edma3->chans[i];
++              char *txirq_name = fsl_chan->txirq_name;
++
++              fsl_chan->edma3 = fsl_edma3;
++              /* Get per channel membase */
++              res = platform_get_resource(pdev, IORESOURCE_MEM, i);
++              fsl_chan->membase = devm_ioremap_resource(&pdev->dev, res);
++              if (IS_ERR(fsl_chan->membase))
++                      return PTR_ERR(fsl_chan->membase);
++
++              /* Get the hardware chanel id by the channel membase
++               * channel0:0x10000, channel1:0x20000... total 32 channels
++               */
++              fsl_chan->hw_chanid = (res->start >> 16) & 0x1f;
++              sprintf(txirq_name, "edma-chan%d-tx", fsl_chan->hw_chanid);
++
++              /* request channel irq */
++              fsl_chan->txirq = platform_get_irq_byname(pdev, txirq_name);
++              if (fsl_chan->txirq < 0) {
++                      dev_err(&pdev->dev, "Can't get %s irq.\n", txirq_name);
++                      return fsl_chan->txirq;
++              }
++
++              ret = devm_request_irq(&pdev->dev, fsl_chan->txirq,
++                              fsl_edma3_tx_handler, irqflag, txirq_name,
++                              fsl_chan);
++              if (ret) {
++                      dev_err(&pdev->dev, "Can't register %s IRQ.\n",
++                              txirq_name);
++                      return ret;
++              }
++
++              fsl_chan->vchan.desc_free = fsl_edma3_free_desc;
++              vchan_init(&fsl_chan->vchan, &fsl_edma3->dma_dev);
++      }
++
++      mutex_init(&fsl_edma3->fsl_edma3_mutex);
++
++      dma_cap_set(DMA_PRIVATE, fsl_edma3->dma_dev.cap_mask);
++      dma_cap_set(DMA_SLAVE, fsl_edma3->dma_dev.cap_mask);
++      dma_cap_set(DMA_CYCLIC, fsl_edma3->dma_dev.cap_mask);
++
++      fsl_edma3->dma_dev.dev = &pdev->dev;
++      fsl_edma3->dma_dev.device_alloc_chan_resources
++              = fsl_edma3_alloc_chan_resources;
++      fsl_edma3->dma_dev.device_free_chan_resources
++              = fsl_edma3_free_chan_resources;
++      fsl_edma3->dma_dev.device_tx_status = fsl_edma3_tx_status;
++      fsl_edma3->dma_dev.device_prep_slave_sg = fsl_edma3_prep_slave_sg;
++      fsl_edma3->dma_dev.device_prep_dma_cyclic = fsl_edma3_prep_dma_cyclic;
++      fsl_edma3->dma_dev.device_config = fsl_edma3_slave_config;
++      fsl_edma3->dma_dev.device_pause = fsl_edma3_pause;
++      fsl_edma3->dma_dev.device_resume = fsl_edma3_resume;
++      fsl_edma3->dma_dev.device_terminate_all = fsl_edma3_terminate_all;
++      fsl_edma3->dma_dev.device_issue_pending = fsl_edma3_issue_pending;
++
++      fsl_edma3->dma_dev.src_addr_widths = FSL_EDMA_BUSWIDTHS;
++      fsl_edma3->dma_dev.dst_addr_widths = FSL_EDMA_BUSWIDTHS;
++      fsl_edma3->dma_dev.directions = BIT(DMA_DEV_TO_MEM) |
++                                      BIT(DMA_MEM_TO_DEV) |
++                                      BIT(DMA_DEV_TO_DEV);
++
++      platform_set_drvdata(pdev, fsl_edma3);
++
++      ret = dma_async_device_register(&fsl_edma3->dma_dev);
++      if (ret) {
++              dev_err(&pdev->dev, "Can't register Freescale eDMA engine.\n");
++              return ret;
++      }
++
++      ret = of_dma_controller_register(np, fsl_edma3_xlate, fsl_edma3);
++      if (ret) {
++              dev_err(&pdev->dev, "Can't register Freescale eDMA of_dma.\n");
++              dma_async_device_unregister(&fsl_edma3->dma_dev);
++              return ret;
++      }
++
++      return 0;
++}
++
++static int fsl_edma3_remove(struct platform_device *pdev)
++{
++      struct device_node *np = pdev->dev.of_node;
++      struct fsl_edma3_engine *fsl_edma3 = platform_get_drvdata(pdev);
++
++      of_dma_controller_free(np);
++      dma_async_device_unregister(&fsl_edma3->dma_dev);
++
++      return 0;
++}
++
++static const struct of_device_id fsl_edma3_dt_ids[] = {
++      { .compatible = "fsl,imx8qm-edma", },
++      { .compatible = "fsl,imx8qm-adma", },
++      { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, fsl_edma3_dt_ids);
++
++static struct platform_driver fsl_edma3_driver = {
++      .driver         = {
++              .name   = "fsl-edma-v3",
++              .of_match_table = fsl_edma3_dt_ids,
++      },
++      .probe          = fsl_edma3_probe,
++      .remove         = fsl_edma3_remove,
++};
++
++static int __init fsl_edma3_init(void)
++{
++      return platform_driver_register(&fsl_edma3_driver);
++}
++subsys_initcall(fsl_edma3_init);
++
++static void __exit fsl_edma3_exit(void)
++{
++      platform_driver_unregister(&fsl_edma3_driver);
++}
++module_exit(fsl_edma3_exit);
++
++MODULE_ALIAS("platform:fsl-edma3");
++MODULE_DESCRIPTION("Freescale eDMA-V3 engine driver");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0004-MLK-15003-1-DMA-fsl-edma-v3-add-one-more-parameter-f.patch b/target/linux/layerscape/patches-5.4/806-dma-0004-MLK-15003-1-DMA-fsl-edma-v3-add-one-more-parameter-f.patch
new file mode 100644 (file)
index 0000000..1af6c7e
--- /dev/null
@@ -0,0 +1,53 @@
+From f8692ecd13a787c51eca9234312f5f3fd163a04a Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@freescale.com>
+Date: Mon, 5 Jun 2017 11:05:52 +0800
+Subject: [PATCH] MLK-15003-1: DMA: fsl-edma-v3: add one more parameter for
+ xlate
+
+The parameter is "is_remote", which is to use remote access for
+edma, the default access is local access.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
+(cherry picked from commit eee976b30b0523680f30e762742984f5b5a01b97)
+---
+ drivers/dma/fsl-edma-v3.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -139,6 +139,7 @@ struct fsl_edma3_chan {
+       int                             hw_chanid;
+       int                             priority;
+       int                             is_rxchan;
++      int                             is_remote;
+       struct dma_pool                 *tcd_pool;
+       u32                             chn_real_count;
+       char                            txirq_name[32];
+@@ -189,6 +190,10 @@ static void fsl_edma3_enable_request(str
+               else
+                       val |= EDMA_CH_SBR_WR;
+       }
++
++      if (fsl_chan->is_remote)
++              val &= ~(EDMA_CH_SBR_RD | EDMA_CH_SBR_WR);
++
+       writel(val, addr + EDMA_CH_SBR);
+       val = readl(addr + EDMA_CH_CSR);
+@@ -686,7 +691,7 @@ static struct dma_chan *fsl_edma3_xlate(
+       struct dma_chan *chan, *_chan;
+       struct fsl_edma3_chan *fsl_chan;
+-      if (dma_spec->args_count != 3)
++      if (dma_spec->args_count != 4)
+               return NULL;
+       mutex_lock(&fsl_edma3->fsl_edma3_mutex);
+@@ -701,6 +706,7 @@ static struct dma_chan *fsl_edma3_xlate(
+                       chan->device->privatecnt++;
+                       fsl_chan->priority = dma_spec->args[1];
+                       fsl_chan->is_rxchan = dma_spec->args[2];
++                      fsl_chan->is_remote = dma_spec->args[3];
+                       mutex_unlock(&fsl_edma3->fsl_edma3_mutex);
+                       return chan;
+               }
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0005-MLK-15003-2-Document-fsl_edma_v3-update-document.patch b/target/linux/layerscape/patches-5.4/806-dma-0005-MLK-15003-2-Document-fsl_edma_v3-update-document.patch
new file mode 100644 (file)
index 0000000..bde8dd5
--- /dev/null
@@ -0,0 +1,50 @@
+From c5a10c542853662bf85884aecee1c086ecec9acf Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@freescale.com>
+Date: Mon, 5 Jun 2017 11:37:57 +0800
+Subject: [PATCH] MLK-15003-2: Document: fsl_edma_v3: update document
+
+update fsl_edma_v3 document for #dma-cell is changed
+one more cell is added, which is for local/remote access.
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
+(cherry picked from commit 65543fb7fefbdb7df4cb60931a88f61507c5073f)
+---
+ Documentation/devicetree/bindings/dma/fsl-edma-v3.txt | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/Documentation/devicetree/bindings/dma/fsl-edma-v3.txt
++++ b/Documentation/devicetree/bindings/dma/fsl-edma-v3.txt
+@@ -14,11 +14,13 @@ Required properties:
+ - interrupts : A list of interrupt-specifiers, each channel has one interrupt.
+ - interrupt-names : Should contain:
+       "edma-chan12-tx" - the channel12 transmission interrupt
+-- #dma-cells : Must be <3>.
++- #dma-cells : Must be <4>.
+       The 1st cell specifies the channel ID.
+       The 2nd cell specifies the channel priority.
+       The 3rd cell specifies the channel type like for transmit or receive:
+               0: transmit, 1: receive.
++      The 4th cell specifies the local access or remote access:
++              0: local, 1: remote.
+       See the SoC's reference manual for all the supported request sources.
+ - dma-channels : Number of channels supported by the controller
+@@ -29,7 +31,7 @@ edma0: dma-controller@40018000 {
+             <0x0 0x5a2d0000 0x0 0x10000>, /* channel13 UART0 tx */
+             <0x0 0x5a2e0000 0x0 0x10000>, /* channel14 UART1 rx */
+             <0x0 0x5a2f0000 0x0 0x10000>; /* channel15 UART1 tx */
+-      #dma-cells = <3>;
++      #dma-cells = <4>;
+       dma-channels = <4>;
+       interrupts = <GIC_SPI 434 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 435 IRQ_TYPE_LEVEL_HIGH>,
+@@ -58,7 +60,7 @@ lpuart1: serial@5a070000 {
+       assigned-clock-rates = <80000000>;
+       power-domains = <&pd_dma_lpuart1>;
+       dma-names = "tx","rx";
+-      dmas = <&edma0 15 0 0>,
+-              <&edma0 14 0 1>;
++      dmas = <&edma0 15 0 0 0>,
++              <&edma0 14 0 1 0>;
+       status = "disabled";
+ };
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0006-MLK-15014-dma-fsl-edma-v3-clear-DONE-before-E_SG-ena.patch b/target/linux/layerscape/patches-5.4/806-dma-0006-MLK-15014-dma-fsl-edma-v3-clear-DONE-before-E_SG-ena.patch
new file mode 100644 (file)
index 0000000..bb4a83c
--- /dev/null
@@ -0,0 +1,30 @@
+From 03691bf3038250def574c78576a8be39133923fd Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Tue, 6 Jun 2017 16:56:49 +0800
+Subject: [PATCH] MLK-15014 dma: fsl-edma-v3: clear DONE before E_SG enabled
+
+Below described in RM, otherwise, channel error status(CHa_ES)
+may be triggered:
+The user must clear the CHa_CSR[DONE] bit before writing the
+TCDa_CSR[MAJORELINK] or TCDa_CSR[ESG] bits.
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+(cherry picked from commit c4164d0a15306174056c6ff423ba2408dd901fcf)
+---
+ drivers/dma/fsl-edma-v3.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -421,6 +421,11 @@ static void fsl_edma3_set_tcd_regs(struc
+       writel(le32_to_cpu(tcd->dlast_sga), addr + EDMA_TCD_DLAST_SGA);
++      /* Must clear CHa_CSR[DONE] bit before enable TCDa_CSR[ESG] */
++      if ((EDMA_TCD_CSR_E_SG | le16_to_cpu(tcd->csr)) &&
++              EDMA_CH_CSR_DONE | readl(addr + EDMA_CH_CSR))
++              writel(EDMA_CH_CSR_DONE, addr + EDMA_CH_CSR);
++
+       writew(le16_to_cpu(tcd->csr), addr + EDMA_TCD_CSR);
+ }
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0007-MLK-15330-1-dma-fsl-edma-v3-combine-two-cells-into-o.patch b/target/linux/layerscape/patches-5.4/806-dma-0007-MLK-15330-1-dma-fsl-edma-v3-combine-two-cells-into-o.patch
new file mode 100644 (file)
index 0000000..3193f70
--- /dev/null
@@ -0,0 +1,88 @@
+From bae75b5a56bc2c8768541b4b61edb28609486357 Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Tue, 4 Jul 2017 14:45:25 +0800
+Subject: [PATCH] MLK-15330-1: dma: fsl-edma-v3: combine two cells into one
+
+For dual fifo case, fsl-edma-v3 need add another cell. It's not friendly
+for user and it's possible other cells maybe added to other use cases,
+so combine two cells into one now, and for some special use cases such as
+dual fifo property can directly be passed by one bit of cell3 rather than
+another cell.
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+(cherry picked from commit 3ecd1b3382e2c746728842fb2c084fbb030eb5de)
+---
+ Documentation/devicetree/bindings/dma/fsl-edma-v3.txt | 13 +++++++------
+ drivers/dma/fsl-edma-v3.c                             |  9 ++++++---
+ 2 files changed, 13 insertions(+), 9 deletions(-)
+
+--- a/Documentation/devicetree/bindings/dma/fsl-edma-v3.txt
++++ b/Documentation/devicetree/bindings/dma/fsl-edma-v3.txt
+@@ -14,12 +14,13 @@ Required properties:
+ - interrupts : A list of interrupt-specifiers, each channel has one interrupt.
+ - interrupt-names : Should contain:
+       "edma-chan12-tx" - the channel12 transmission interrupt
+-- #dma-cells : Must be <4>.
++- #dma-cells : Must be <3>.
+       The 1st cell specifies the channel ID.
+       The 2nd cell specifies the channel priority.
+-      The 3rd cell specifies the channel type like for transmit or receive:
++      The 3rd cell specifies the channel attributes which include below:
++      BIT(0): transmit or receive:
+               0: transmit, 1: receive.
+-      The 4th cell specifies the local access or remote access:
++      BIT(1): local or remote access:
+               0: local, 1: remote.
+       See the SoC's reference manual for all the supported request sources.
+ - dma-channels : Number of channels supported by the controller
+@@ -31,7 +32,7 @@ edma0: dma-controller@40018000 {
+             <0x0 0x5a2d0000 0x0 0x10000>, /* channel13 UART0 tx */
+             <0x0 0x5a2e0000 0x0 0x10000>, /* channel14 UART1 rx */
+             <0x0 0x5a2f0000 0x0 0x10000>; /* channel15 UART1 tx */
+-      #dma-cells = <4>;
++      #dma-cells = <3>;
+       dma-channels = <4>;
+       interrupts = <GIC_SPI 434 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 435 IRQ_TYPE_LEVEL_HIGH>,
+@@ -60,7 +61,7 @@ lpuart1: serial@5a070000 {
+       assigned-clock-rates = <80000000>;
+       power-domains = <&pd_dma_lpuart1>;
+       dma-names = "tx","rx";
+-      dmas = <&edma0 15 0 0 0>,
+-              <&edma0 14 0 1 0>;
++      dmas = <&edma0 15 0 0>,
++              <&edma0 14 0 1>;
+       status = "disabled";
+ };
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -100,6 +100,9 @@
+                               BIT(DMA_SLAVE_BUSWIDTH_8_BYTES) | \
+                               BIT(DMA_SLAVE_BUSWIDTH_16_BYTES))
++#define ARGS_RX                               BIT(0)
++#define ARGS_REMOTE                   BIT(1)
++
+ struct fsl_edma3_hw_tcd {
+       __le32  saddr;
+       __le16  soff;
+@@ -696,7 +699,7 @@ static struct dma_chan *fsl_edma3_xlate(
+       struct dma_chan *chan, *_chan;
+       struct fsl_edma3_chan *fsl_chan;
+-      if (dma_spec->args_count != 4)
++      if (dma_spec->args_count != 3)
+               return NULL;
+       mutex_lock(&fsl_edma3->fsl_edma3_mutex);
+@@ -710,8 +713,8 @@ static struct dma_chan *fsl_edma3_xlate(
+                       chan = dma_get_slave_channel(chan);
+                       chan->device->privatecnt++;
+                       fsl_chan->priority = dma_spec->args[1];
+-                      fsl_chan->is_rxchan = dma_spec->args[2];
+-                      fsl_chan->is_remote = dma_spec->args[3];
++                      fsl_chan->is_rxchan = dma_spec->args[2] & ARGS_RX;
++                      fsl_chan->is_remote = dma_spec->args[2] & ARGS_REMOTE;
+                       mutex_unlock(&fsl_edma3->fsl_edma3_mutex);
+                       return chan;
+               }
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0008-MLK-15330-3-dma-fsl-edma-v3-add-dual-fifo-support.patch b/target/linux/layerscape/patches-5.4/806-dma-0008-MLK-15330-3-dma-fsl-edma-v3-add-dual-fifo-support.patch
new file mode 100644 (file)
index 0000000..36222ef
--- /dev/null
@@ -0,0 +1,106 @@
+From 6c753f83ffc3fede13582f667a15e7f6e97f972c Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Tue, 4 Jul 2017 16:04:36 +0800
+Subject: [PATCH] MLK-15330-3 dma: fsl-edma-v3: add dual fifo support
+
+There is Audio dual fifo cause that fill fifo one by one and
+loop back after every minor loop:
+  -- fill the first 32bit width fifo
+  -- fill the next 32bit width fifo
+  -- +MLOFF signed offset after the above two FIFOs filled
+  -- loop back to the first step to handle the next minor loop.
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+(cherry picked from commit 5aa5e9663bb3a834444b75ea086bef8c37ecb636)
+---
+ .../devicetree/bindings/dma/fsl-edma-v3.txt        |  2 ++
+ drivers/dma/fsl-edma-v3.c                          | 29 ++++++++++++++++++++--
+ 2 files changed, 29 insertions(+), 2 deletions(-)
+
+--- a/Documentation/devicetree/bindings/dma/fsl-edma-v3.txt
++++ b/Documentation/devicetree/bindings/dma/fsl-edma-v3.txt
+@@ -22,6 +22,8 @@ Required properties:
+               0: transmit, 1: receive.
+       BIT(1): local or remote access:
+               0: local, 1: remote.
++      BIT(2): dualfifo case or not(only in Audio cyclic now):
++              0: not dual fifo case, 1: dualfifo case.
+       See the SoC's reference manual for all the supported request sources.
+ - dma-channels : Number of channels supported by the controller
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -78,6 +78,9 @@
+ #define EDMA_TCD_SOFF_SOFF(x)         (x)
+ #define EDMA_TCD_NBYTES_NBYTES(x)     (x)
++#define EDMA_TCD_NBYTES_MLOFF(x)      (x << 10)
++#define EDMA_TCD_NBYTES_DMLOE         (1 << 30)
++#define EDMA_TCD_NBYTES_SMLOE         (1 << 31)
+ #define EDMA_TCD_SLAST_SLAST(x)               (x)
+ #define EDMA_TCD_DADDR_DADDR(x)               (x)
+ #define EDMA_TCD_CITER_CITER(x)               ((x) & 0x7FFF)
+@@ -102,6 +105,7 @@
+ #define ARGS_RX                               BIT(0)
+ #define ARGS_REMOTE                   BIT(1)
++#define ARGS_DFIFO                    BIT(2)
+ struct fsl_edma3_hw_tcd {
+       __le32  saddr;
+@@ -143,6 +147,7 @@ struct fsl_edma3_chan {
+       int                             priority;
+       int                             is_rxchan;
+       int                             is_remote;
++      int                             is_dfifo;
+       struct dma_pool                 *tcd_pool;
+       u32                             chn_real_count;
+       char                            txirq_name[32];
+@@ -454,6 +459,19 @@ void fsl_edma3_fill_tcd(struct fsl_edma3
+       tcd->soff = cpu_to_le16(EDMA_TCD_SOFF_SOFF(soff));
++      if (fsl_chan->is_dfifo) {
++              /* set mloff as -8 */
++              nbytes |= EDMA_TCD_NBYTES_MLOFF(-8);
++              /* enable DMLOE/SMLOE */
++              if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
++                      nbytes |= EDMA_TCD_NBYTES_DMLOE;
++                      nbytes &= ~EDMA_TCD_NBYTES_SMLOE;
++              } else {
++                      nbytes |= EDMA_TCD_NBYTES_SMLOE;
++                      nbytes &= ~EDMA_TCD_NBYTES_DMLOE;
++              }
++      }
++
+       tcd->nbytes = cpu_to_le32(EDMA_TCD_NBYTES_NBYTES(nbytes));
+       tcd->slast = cpu_to_le32(EDMA_TCD_SLAST_SLAST(slast));
+@@ -540,11 +558,17 @@ static struct dma_async_tx_descriptor *f
+                       src_addr = dma_buf_next;
+                       dst_addr = fsl_chan->fsc.dev_addr;
+                       soff = fsl_chan->fsc.addr_width;
+-                      doff = 0;
++                      if (fsl_chan->is_dfifo)
++                              doff = 4;
++                      else
++                              doff = 0;
+               } else if (fsl_chan->fsc.dir == DMA_DEV_TO_MEM) {
+                       src_addr = fsl_chan->fsc.dev_addr;
+                       dst_addr = dma_buf_next;
+-                      soff = 0;
++                      if (fsl_chan->is_dfifo)
++                              soff = 4;
++                      else
++                              soff = 0;
+                       doff = fsl_chan->fsc.addr_width;
+               } else {
+                       /* DMA_DEV_TO_DEV */
+@@ -715,6 +739,7 @@ static struct dma_chan *fsl_edma3_xlate(
+                       fsl_chan->priority = dma_spec->args[1];
+                       fsl_chan->is_rxchan = dma_spec->args[2] & ARGS_RX;
+                       fsl_chan->is_remote = dma_spec->args[2] & ARGS_REMOTE;
++                      fsl_chan->is_dfifo = dma_spec->args[2] & ARGS_DFIFO;
+                       mutex_unlock(&fsl_edma3->fsl_edma3_mutex);
+                       return chan;
+               }
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0009-MLK-16327-1-dma-fsl-edma-v3-make-exclusive-channel-n.patch b/target/linux/layerscape/patches-5.4/806-dma-0009-MLK-16327-1-dma-fsl-edma-v3-make-exclusive-channel-n.patch
new file mode 100644 (file)
index 0000000..6c770ed
--- /dev/null
@@ -0,0 +1,128 @@
+From c5a5706b8a86660505ef0dc863a85596437ca49b Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Wed, 30 Aug 2017 18:51:16 +0800
+Subject: [PATCH] MLK-16327-1: dma: fsl-edma-v3: make exclusive channel name
+ for all edma channels
+
+  Since there are multi edmav3 instances on i.mx8, every edma channel name
+is better unique.But so far, all edma channel name is 'edma-channel(id)-
+tx',thus some edma channels which share the same channel id but different
+edma instance will show the same channel name in kernel and this is not
+friendly to debug in kernel.
+  Now the edma channel name(interrupt-names property) is define in dts
+as below:
+        "edmaX-chanX-Xx"
+             |     | |---> receive/transmit, r or t
+             |     |---> channel id, the max number is 32
+             |---> edma controller instance, 0, 1, 2,..etc
+and get below correct name with 'cat /proc/interrupts':
+ 43:          0          0          0          0     GICv3 466 Level     edma0-chan8-rx
+ 44:          0          0          0          0     GICv3 467 Level     edma0-chan9-tx
+ 45:         79          0          0          0     GICv3 468 Level     edma0-chan10-rx
+ 46:        311          0          0          0     GICv3 469 Level     edma0-chan11-tx
+ 47:          0          0          0          0     GICv3 470 Level     edma0-chan12-rx
+ 48:          0          0          0          0     GICv3 471 Level     edma0-chan13-tx
+ 49:          0          0          0          0     GICv3 472 Level     edma0-chan14-rx
+ 50:          0          0          0          0     GICv3 473 Level     edma0-chan15-tx
+ 51:          0          0          0          0     GICv3 406 Level     edma2-chan0-tx
+ 52:          0          0          0          0     GICv3 407 Level     edma2-chan1-tx
+ 53:          0          0          0          0     GICv3 408 Level     edma2-chan2-tx
+ 54:          0          0          0          0     GICv3 409 Level     edma2-chan3-tx
+ 55:          0          0          0          0     GICv3 410 Level     edma2-chan4-tx
+ 56:          0          0          0          0     GICv3 411 Level     edma2-chan5-tx
+ 57:          0          0          0          0     GICv3 442 Level     edma2-chan6-rx, edma2-chan7-tx
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+(cherry picked from commit af8e197a92c9c024ec4fbfcf543d744e81748773)
+---
+ .../devicetree/bindings/dma/fsl-edma-v3.txt        | 12 +++++---
+ drivers/dma/fsl-edma-v3.c                          | 35 ++++++++++++++++++++--
+ 2 files changed, 41 insertions(+), 6 deletions(-)
+
+--- a/Documentation/devicetree/bindings/dma/fsl-edma-v3.txt
++++ b/Documentation/devicetree/bindings/dma/fsl-edma-v3.txt
+@@ -12,8 +12,12 @@ Required properties:
+ - reg : Specifies base physical address(s) and size of the eDMA channel registers.
+       Each eDMA channel has separated register's address and size.
+ - interrupts : A list of interrupt-specifiers, each channel has one interrupt.
+-- interrupt-names : Should contain:
+-      "edma-chan12-tx" - the channel12 transmission interrupt
++- interrupt-names : Should contain below template:
++      "edmaX-chanX-Xx"
++           |     | |---> receive/transmit, r or t
++           |     |---> channel id, the max number is 32
++           |---> edma controller instance, 0, 1, 2,..etc
++
+ - #dma-cells : Must be <3>.
+       The 1st cell specifies the channel ID.
+       The 2nd cell specifies the channel priority.
+@@ -40,8 +44,8 @@ edma0: dma-controller@40018000 {
+                    <GIC_SPI 435 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 436 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 437 IRQ_TYPE_LEVEL_HIGH>;
+-      interrupt-names = "edma-chan12-tx", "edma-chan13-tx",
+-                        "edma-chan14-tx", "edma-chan15-tx";
++      interrupt-names = "edma0-chan12-rx", "edma0-chan13-tx",
++                        "edma0-chan14-rx", "edma0-chan15-tx";
+       status = "okay";
+ };
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -107,6 +107,10 @@
+ #define ARGS_REMOTE                   BIT(1)
+ #define ARGS_DFIFO                    BIT(2)
++/* channel name template define in dts */
++#define CHAN_PREFIX                   "edma0-chan"
++#define CHAN_POSFIX                   "-tx"
++
+ struct fsl_edma3_hw_tcd {
+       __le32  saddr;
+       __le16  soff;
+@@ -806,7 +810,10 @@ static int fsl_edma3_probe(struct platfo
+       INIT_LIST_HEAD(&fsl_edma3->dma_dev.channels);
+       for (i = 0; i < fsl_edma3->n_chans; i++) {
+               struct fsl_edma3_chan *fsl_chan = &fsl_edma3->chans[i];
+-              char *txirq_name = fsl_chan->txirq_name;
++              const char *txirq_name = fsl_chan->txirq_name;
++              char chanid[3], id_len = 0;
++              char *p = chanid;
++              unsigned long val;
+               fsl_chan->edma3 = fsl_edma3;
+               /* Get per channel membase */
+@@ -819,7 +826,31 @@ static int fsl_edma3_probe(struct platfo
+                * channel0:0x10000, channel1:0x20000... total 32 channels
+                */
+               fsl_chan->hw_chanid = (res->start >> 16) & 0x1f;
+-              sprintf(txirq_name, "edma-chan%d-tx", fsl_chan->hw_chanid);
++
++              ret = of_property_read_string_index(np, "interrupt-names", i,
++                                                      &txirq_name);
++              if (ret) {
++                      dev_err(&pdev->dev, "read interrupt-names fail.\n");
++                      return ret;
++              }
++              /* Get channel id length from dts, one-digit or double-digit */
++              id_len = strlen(txirq_name) - strlen(CHAN_PREFIX) -
++                       strlen(CHAN_POSFIX);
++              if (id_len > 2) {
++                      dev_err(&pdev->dev, "%s is edmaX-chanX-tx in dts?\n",
++                              res->name);
++                      return -EINVAL;
++              }
++              /* Grab channel id from txirq_name */
++              strncpy(p, txirq_name + strlen(CHAN_PREFIX), id_len);
++              *(p + id_len) = '\0';
++
++              /* check if the channel id match well with hw_chanid */
++              ret = kstrtoul(chanid, 0, &val);
++              if (ret || val != fsl_chan->hw_chanid) {
++                      dev_err(&pdev->dev, "%s,wrong id?\n", txirq_name);
++                      return -EINVAL;
++              }
+               /* request channel irq */
+               fsl_chan->txirq = platform_get_irq_byname(pdev, txirq_name);
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0010-MLK-16437-dma-fsl-edma-v3-fix-kernel-crash-while-edm.patch b/target/linux/layerscape/patches-5.4/806-dma-0010-MLK-16437-dma-fsl-edma-v3-fix-kernel-crash-while-edm.patch
new file mode 100644 (file)
index 0000000..6bc905c
--- /dev/null
@@ -0,0 +1,42 @@
+From e0d0cdff101b2f00ce1fd420522bd22bb6eebd9f Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Wed, 13 Sep 2017 16:39:49 +0800
+Subject: [PATCH] MLK-16437: dma: fsl-edma-v3: fix kernel crash while edma
+ interrupt trigger after channel disabled
+
+edma interrupt may come after channel terminated, so should ignore
+interrupts, else kernel crash as below since fsl_chan->edesc set
+to NULL when terminate.
+
+ 606.837306] Unable to handle kernel NULL pointer dereference at virtual address 00000060
+[  606.845411] pgd = ffff000009295000
+[  606.848814] [00000060] *pgd=00000008bfffe003[  606.852906] , *pud=00000008bfffd003
+ , *pmd=0000000000000000[  606.858395]
+[  606.859885] Internal error: Oops: 96000006 1 PREEMPT SMP
+[  606.865460] Modules linked in:
+[  606.868522] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.9.11-03371-g9904ea0 #42
+[  606.875832] Hardware name: Freescale i.MX8QXP LPDDR4 ARM2 (DT)
+[  606.881662] task: ffff000009120680 task.stack: ffff000009110000
+[  606.887588] PC is at fsl_edma3_tx_handler+0x50/0x150
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+Tested-by: Daniel Baluta <daniel.baluta@nxp.com>
+(cherry picked from commit 625afad5a0900bc3e3288510f61647b1d891a5a4)
+---
+ drivers/dma/fsl-edma-v3.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -689,6 +689,11 @@ static irqreturn_t fsl_edma3_tx_handler(
+       writel(1, base_addr + EDMA_CH_INT);
+       spin_lock(&fsl_chan->vchan.lock);
++
++      /* Ignore this interrupt since channel has been disabled already */
++      if (!fsl_chan->edesc)
++              return IRQ_HANDLED;
++
+       if (!fsl_chan->edesc->iscyclic) {
+               fsl_edma3_get_realcnt(fsl_chan);
+               list_del(&fsl_chan->edesc->vdesc.node);
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0011-MLK-16482-dma-fsl-edma-v3-Fix-RCU-issue-while-playin.patch b/target/linux/layerscape/patches-5.4/806-dma-0011-MLK-16482-dma-fsl-edma-v3-Fix-RCU-issue-while-playin.patch
new file mode 100644 (file)
index 0000000..de37310
--- /dev/null
@@ -0,0 +1,65 @@
+From 46c343673c6eae7909f644f9b67101ce14309670 Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Tue, 19 Sep 2017 11:36:58 +0800
+Subject: [PATCH] MLK-16482: dma: fsl-edma-v3: Fix RCU issue while playing
+ Audio
+
+That's caused by commit 593034f1b908 ("MLK-16437: dma: fsl-edma-v3:
+fix kernel crash while edma interrupt trigger after channel disabled").
+Because fsl_chan->vchan.lock will be hold always and trigger RCU report
+as below:
+
+1571.3  Playing WAVE '/mnt/nfs/vte_mx82/../test_stream/esai_stream/48k16bit-six.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Channels 6
+1571.5  [ 4642.698771] INFO: rcu_preempt detected stalls on CPUs/tasks:
+1571.6  [ 4642.704443] 0-...: (1 GPs behind) idle=2c5/140000000000000/0 softirq=155373/155374 fqs=2541
+1571.7  [ 4642.712967] (detected by 2, t=5252 jiffies, g=104259, c=104258, q=22)
+1571.8  [ 4642.719501] Task dump for CPU 0:
+1571.9  [ 4642.722724] aplay R running task 0 15723 15721 0x00000202
+1571.10  [ 4642.729786] Call trace:
+1571.11  [ 4642.732239] [<ffff0000080855e4>] __switch_to+0x8c/0xa0
+1571.12  [ 4642.737379] [<ffff0000084e3a48>] dma_chan_put+0x70/0xa0
+1571.13  [ 4642.742603] [<ffff0000084e3aac>] dma_release_channel+0x34/0xa0
+1571.14  [ 4642.748435] [<ffff000008972240>] fsl_asrc_dma_hw_free+0x38/0x50
+1571.15  [ 4642.754358] [<ffff000008960568>] soc_pcm_hw_free+0x110/0x1a8
+1571.16  [ 4642.760013] [<ffff000008963bcc>] dpcm_fe_dai_hw_free+0x6c/0xe0
+1571.17  [ 4642.765844] [<ffff000008948ae8>] snd_pcm_common_ioctl1+0xb40/0xce0
+1571.18  [ 4642.772028] [<ffff000008948e64>] snd_pcm_playback_ioctl1+0x1dc/0x310
+1571.19  [ 4642.778378] [<ffff000008948fc0>] snd_pcm_playback_ioctl+0x28/0x40
+1571.20  [ 4642.784470] [<ffff0000081ee0a4>] do_vfs_ioctl+0xa4/0x748
+1571.21  [ 4642.789784] [<ffff0000081ee7d4>] SyS_ioctl+0x8c/0xa0
+1571.22  [ 4642.794745] [<ffff000008082f4c>] __sys_trace_return+0x0/0x4
+1571.23  [ 4705.718740] INFO: rcu_preempt detected stalls on CPUs/tasks:
+1571.24  [ 4705.724420] 0-...: (1 GPs behind) idle=2c5/140000000000000/0 softirq=155373/155374 fqs=10407
+1571.25  [ 4705.733030] (detected by 1, t=21010 jiffies, g=104259, c=104258, q=119)
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+Reported-by: Jason Liu <jason.hui.liu@nxp.com>
+Reviewed-by: Daniel Baluta <daniel.baluta@nxp.com>
+Fixes: 593034f1b908 ("MLK-16437: dma: fsl-edma-v3: fix kernel crash
+while edma interrupt trigger after channel disabled").
+
+(cherry picked from commit e62e8707154f47e168fcfd148e97be4e2f991898)
+---
+ drivers/dma/fsl-edma-v3.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -692,7 +692,7 @@ static irqreturn_t fsl_edma3_tx_handler(
+       /* Ignore this interrupt since channel has been disabled already */
+       if (!fsl_chan->edesc)
+-              return IRQ_HANDLED;
++              goto irq_handled;
+       if (!fsl_chan->edesc->iscyclic) {
+               fsl_edma3_get_realcnt(fsl_chan);
+@@ -706,7 +706,7 @@ static irqreturn_t fsl_edma3_tx_handler(
+       if (!fsl_chan->edesc)
+               fsl_edma3_xfer_desc(fsl_chan);
+-
++irq_handled:
+       spin_unlock(&fsl_chan->vchan.lock);
+       return IRQ_HANDLED;
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0012-MLK-17094-dma-fsl-edma-v3-add-suspend-resume-to-rest.patch b/target/linux/layerscape/patches-5.4/806-dma-0012-MLK-17094-dma-fsl-edma-v3-add-suspend-resume-to-rest.patch
new file mode 100644 (file)
index 0000000..e9ca236
--- /dev/null
@@ -0,0 +1,192 @@
+From 411a2f6ad13bd58646de34a340553232044f0951 Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Mon, 4 Dec 2017 15:35:09 +0800
+Subject: [PATCH] MLK-17094 dma: fsl-edma-v3: add suspend/resume to restore
+ back channel registers
+
+Add suspend to save channel registers and resume to restore them back since
+edmav3 may powered off in suspend.
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+(cherry picked from commit 7eda1ae538ec7e7c0f993b3ea91805459f3dedd3)
+---
+ drivers/dma/fsl-edma-v3.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 86 insertions(+)
+
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -111,6 +111,11 @@
+ #define CHAN_PREFIX                   "edma0-chan"
+ #define CHAN_POSFIX                   "-tx"
++enum fsl_edma3_pm_state {
++      RUNNING = 0,
++      SUSPENDED,
++};
++
+ struct fsl_edma3_hw_tcd {
+       __le32  saddr;
+       __le16  soff;
+@@ -142,6 +147,8 @@ struct fsl_edma3_slave_config {
+ struct fsl_edma3_chan {
+       struct virt_dma_chan            vchan;
+       enum dma_status                 status;
++      enum fsl_edma3_pm_state         pm_state;
++      bool                            idle;
+       struct fsl_edma3_engine         *edma3;
+       struct fsl_edma3_desc           *edesc;
+       struct fsl_edma3_slave_config   fsc;
+@@ -165,11 +172,18 @@ struct fsl_edma3_desc {
+       struct fsl_edma3_sw_tcd         tcd[];
+ };
++struct fsl_edma3_reg_save {
++      u32 csr;
++      u32 sbr;
++};
++
+ struct fsl_edma3_engine {
+       struct dma_device       dma_dev;
+       struct mutex            fsl_edma3_mutex;
+       u32                     n_chans;
+       int                     errirq;
++      #define MAX_CHAN_NUM    32
++      struct fsl_edma3_reg_save edma_regs[MAX_CHAN_NUM];
+       bool                    swap;   /* remote/local swapped on Audio edma */
+       struct fsl_edma3_chan   chans[];
+ };
+@@ -266,6 +280,7 @@ static int fsl_edma3_terminate_all(struc
+       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+       fsl_edma3_disable_request(fsl_chan);
+       fsl_chan->edesc = NULL;
++      fsl_chan->idle = true;
+       vchan_get_all_descriptors(&fsl_chan->vchan, &head);
+       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+       vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
+@@ -281,6 +296,7 @@ static int fsl_edma3_pause(struct dma_ch
+       if (fsl_chan->edesc) {
+               fsl_edma3_disable_request(fsl_chan);
+               fsl_chan->status = DMA_PAUSED;
++              fsl_chan->idle = true;
+       }
+       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+       return 0;
+@@ -295,6 +311,7 @@ static int fsl_edma3_resume(struct dma_c
+       if (fsl_chan->edesc) {
+               fsl_edma3_enable_request(fsl_chan);
+               fsl_chan->status = DMA_IN_PROGRESS;
++              fsl_chan->idle = false;
+       }
+       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+       return 0;
+@@ -664,6 +681,7 @@ static void fsl_edma3_xfer_desc(struct f
+       fsl_edma3_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
+       fsl_edma3_enable_request(fsl_chan);
+       fsl_chan->status = DMA_IN_PROGRESS;
++      fsl_chan->idle = false;
+ }
+ static size_t fsl_edma3_desc_residue(struct fsl_edma3_chan *fsl_chan,
+@@ -700,6 +718,7 @@ static irqreturn_t fsl_edma3_tx_handler(
+               vchan_cookie_complete(&fsl_chan->edesc->vdesc);
+               fsl_chan->edesc = NULL;
+               fsl_chan->status = DMA_COMPLETE;
++              fsl_chan->idle = true;
+       } else {
+               vchan_cyclic_callback(&fsl_chan->edesc->vdesc);
+       }
+@@ -719,6 +738,12 @@ static void fsl_edma3_issue_pending(stru
+       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
++      if (unlikely(fsl_chan->pm_state != RUNNING)) {
++              spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
++              /* cannot submit due to suspend */
++              return;
++      }
++
+       if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
+               fsl_edma3_xfer_desc(fsl_chan);
+@@ -821,6 +846,8 @@ static int fsl_edma3_probe(struct platfo
+               unsigned long val;
+               fsl_chan->edma3 = fsl_edma3;
++              fsl_chan->pm_state = RUNNING;
++              fsl_chan->idle = true;
+               /* Get per channel membase */
+               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+               fsl_chan->membase = devm_ioremap_resource(&pdev->dev, res);
+@@ -932,6 +959,64 @@ static int fsl_edma3_remove(struct platf
+       return 0;
+ }
++static int fsl_edma3_suspend_late(struct device *dev)
++{
++      struct fsl_edma3_engine *fsl_edma = dev_get_drvdata(dev);
++      struct fsl_edma3_chan *fsl_chan;
++      unsigned long flags;
++      void __iomem *addr;
++      int i;
++
++      for (i = 0; i < fsl_edma->n_chans; i++) {
++              fsl_chan = &fsl_edma->chans[i];
++              addr = fsl_chan->membase;
++
++              spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
++              fsl_edma->edma_regs[i].csr = readl(addr + EDMA_CH_CSR);
++              fsl_edma->edma_regs[i].sbr = readl(addr + EDMA_CH_SBR);
++              /* Make sure chan is idle or will force disable. */
++              if (unlikely(!fsl_chan->idle)) {
++                      dev_warn(dev, "WARN: There is non-idle channel.");
++                      fsl_edma3_disable_request(fsl_chan);
++              }
++              fsl_chan->pm_state = SUSPENDED;
++              spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
++      }
++
++      return 0;
++}
++
++static int fsl_edma3_resume_early(struct device *dev)
++{
++      struct fsl_edma3_engine *fsl_edma = dev_get_drvdata(dev);
++      struct fsl_edma3_chan *fsl_chan;
++      void __iomem *addr;
++      unsigned long flags;
++      int i;
++
++      for (i = 0; i < fsl_edma->n_chans; i++) {
++              fsl_chan = &fsl_edma->chans[i];
++              addr = fsl_chan->membase;
++
++              spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
++              writel(fsl_edma->edma_regs[i].csr, addr + EDMA_CH_CSR);
++              writel(fsl_edma->edma_regs[i].sbr, addr + EDMA_CH_SBR);
++              /* restore tcd if this channel not terminated before suspend */
++              if (fsl_chan->edesc)
++                      fsl_edma3_set_tcd_regs(fsl_chan,
++                                              fsl_chan->edesc->tcd[0].vtcd);
++              fsl_chan->pm_state = RUNNING;
++              spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
++      }
++
++      return 0;
++}
++
++static const struct dev_pm_ops fsl_edma3_pm_ops = {
++      .suspend_late   = fsl_edma3_suspend_late,
++      .resume_early   = fsl_edma3_resume_early,
++};
++
+ static const struct of_device_id fsl_edma3_dt_ids[] = {
+       { .compatible = "fsl,imx8qm-edma", },
+       { .compatible = "fsl,imx8qm-adma", },
+@@ -943,6 +1028,7 @@ static struct platform_driver fsl_edma3_
+       .driver         = {
+               .name   = "fsl-edma-v3",
+               .of_match_table = fsl_edma3_dt_ids,
++              .pm     = &fsl_edma3_pm_ops,
+       },
+       .probe          = fsl_edma3_probe,
+       .remove         = fsl_edma3_remove,
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0013-MLK-17782-dma-fsl-edma-v3-fix-issue-reported-by-Cove.patch b/target/linux/layerscape/patches-5.4/806-dma-0013-MLK-17782-dma-fsl-edma-v3-fix-issue-reported-by-Cove.patch
new file mode 100644 (file)
index 0000000..05b9852
--- /dev/null
@@ -0,0 +1,41 @@
+From 82b892c3df4893b123681b2ba725c0861e0112a4 Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Tue, 13 Mar 2018 02:03:09 +0800
+Subject: [PATCH] MLK-17782 dma: fsl-edma-v3: fix issue reported by Coverity
+
+Fix below issue reported by Coverity, actually, don't need this
+condition check here, remove it.
+
+CID undefined (#1 of 1): Wrong operator used (CONSTANT_EXPRESSION_RESULT)operator_confusion:
+(16UL /* 1UL << 4 */) | (__u16)(__le16)tcd->csr is always 1/true regardless of the values of its operand.
+This occurs as the logical first operand of "&&".
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+(cherry picked from commit ab942110975cadcde57ab1110df03f526bd3fec5)
+---
+ drivers/dma/fsl-edma-v3.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -1,7 +1,7 @@
+ /*
+  * drivers/dma/fsl-edma3-v3.c
+  *
+- * Copyright 2017 NXP .
++ * Copyright 2017-2018 NXP .
+  *
+  * Driver for the Freescale eDMA engine v3. This driver based on fsl-edma3.c
+  * but changed to meet the IP change on i.MX8QM: every dma channel is specific
+@@ -451,9 +451,7 @@ static void fsl_edma3_set_tcd_regs(struc
+       writel(le32_to_cpu(tcd->dlast_sga), addr + EDMA_TCD_DLAST_SGA);
+       /* Must clear CHa_CSR[DONE] bit before enable TCDa_CSR[ESG] */
+-      if ((EDMA_TCD_CSR_E_SG | le16_to_cpu(tcd->csr)) &&
+-              EDMA_CH_CSR_DONE | readl(addr + EDMA_CH_CSR))
+-              writel(EDMA_CH_CSR_DONE, addr + EDMA_CH_CSR);
++      writel(readl(addr + EDMA_CH_CSR), addr + EDMA_CH_CSR);
+       writew(le16_to_cpu(tcd->csr), addr + EDMA_TCD_CSR);
+ }
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0014-MLK-18248-dma-fsl-edma-v3-avoid-touch-unused-edma-ch.patch b/target/linux/layerscape/patches-5.4/806-dma-0014-MLK-18248-dma-fsl-edma-v3-avoid-touch-unused-edma-ch.patch
new file mode 100644 (file)
index 0000000..828d673
--- /dev/null
@@ -0,0 +1,77 @@
+From 13d8031dd480b23620923c39400831f7edc68276 Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Thu, 10 May 2018 01:02:01 +0800
+Subject: [PATCH] MLK-18248: dma: fsl-edma-v3: avoid touch unused edma channel
+
+Avoid touch unused edma channel register in susped/resume, otherwise,
+kernel crash if XRDC enabled in scfw.
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+Acked-by: Fugang Duan <fugang.duan@nxp.com>
+(cherry picked from commit aa221c4aba34c6ce1ce5f561fa073bb8297cc0ff)
+---
+ drivers/dma/fsl-edma-v3.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -149,6 +149,7 @@ struct fsl_edma3_chan {
+       enum dma_status                 status;
+       enum fsl_edma3_pm_state         pm_state;
+       bool                            idle;
++      bool                            used;
+       struct fsl_edma3_engine         *edma3;
+       struct fsl_edma3_desc           *edesc;
+       struct fsl_edma3_slave_config   fsc;
+@@ -226,6 +227,8 @@ static void fsl_edma3_enable_request(str
+       val |= EDMA_CH_CSR_ERQ;
+       writel(val, addr + EDMA_CH_CSR);
++
++      fsl_chan->used = true;
+ }
+ static void fsl_edma3_disable_request(struct fsl_edma3_chan *fsl_chan)
+@@ -281,6 +284,7 @@ static int fsl_edma3_terminate_all(struc
+       fsl_edma3_disable_request(fsl_chan);
+       fsl_chan->edesc = NULL;
+       fsl_chan->idle = true;
++      fsl_chan->used = false;
+       vchan_get_all_descriptors(&fsl_chan->vchan, &head);
+       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+       vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
+@@ -805,6 +809,7 @@ static void fsl_edma3_free_chan_resource
+       vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
+       dma_pool_destroy(fsl_chan->tcd_pool);
+       fsl_chan->tcd_pool = NULL;
++      fsl_chan->used = false;
+ }
+ static int fsl_edma3_probe(struct platform_device *pdev)
+@@ -900,6 +905,7 @@ static int fsl_edma3_probe(struct platfo
+               fsl_chan->vchan.desc_free = fsl_edma3_free_desc;
+               vchan_init(&fsl_chan->vchan, &fsl_edma3->dma_dev);
++              fsl_chan->used = false;
+       }
+       mutex_init(&fsl_edma3->fsl_edma3_mutex);
+@@ -969,6 +975,8 @@ static int fsl_edma3_suspend_late(struct
+               fsl_chan = &fsl_edma->chans[i];
+               addr = fsl_chan->membase;
++              if (!fsl_chan->used)
++                      continue;
+               spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+               fsl_edma->edma_regs[i].csr = readl(addr + EDMA_CH_CSR);
+               fsl_edma->edma_regs[i].sbr = readl(addr + EDMA_CH_SBR);
+@@ -996,6 +1004,9 @@ static int fsl_edma3_resume_early(struct
+               fsl_chan = &fsl_edma->chans[i];
+               addr = fsl_chan->membase;
++              if (!fsl_chan->used)
++                      continue;
++
+               spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+               writel(fsl_edma->edma_regs[i].csr, addr + EDMA_CH_CSR);
+               writel(fsl_edma->edma_regs[i].sbr, addr + EDMA_CH_SBR);
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0015-MLK-19022-2-dmaengine-fsl-edma-v3-add-device_synchro.patch b/target/linux/layerscape/patches-5.4/806-dma-0015-MLK-19022-2-dmaengine-fsl-edma-v3-add-device_synchro.patch
new file mode 100644 (file)
index 0000000..5e1eb8b
--- /dev/null
@@ -0,0 +1,41 @@
+From 0ae3e11113b3132167308c26259f25b504da6ddc Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Tue, 24 Jul 2018 22:12:24 +0800
+Subject: [PATCH] MLK-19022-2: dmaengine: fsl-edma-v3: add device_synchronize
+
+Add device_synchronize for edma driver, since some driver such as
+Audio need it to make sure dma done callback never come out after
+resource related with dma channel free-ed by Audio driver. Android
+team report such issue on MA-12087.
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+(cherry picked from commit 483519c063b08fc1ce0dd297b6c186799cf639d6)
+(cherry picked from commit 29ab274aca01ef8f5fc70e8c0a6d43a5bdb3c689)
+---
+ drivers/dma/fsl-edma-v3.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -812,6 +812,13 @@ static void fsl_edma3_free_chan_resource
+       fsl_chan->used = false;
+ }
++static void fsl_edma3_synchronize(struct dma_chan *chan)
++{
++      struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
++
++      vchan_synchronize(&fsl_chan->vchan);
++}
++
+ static int fsl_edma3_probe(struct platform_device *pdev)
+ {
+       struct device_node *np = pdev->dev.of_node;
+@@ -927,6 +934,7 @@ static int fsl_edma3_probe(struct platfo
+       fsl_edma3->dma_dev.device_resume = fsl_edma3_resume;
+       fsl_edma3->dma_dev.device_terminate_all = fsl_edma3_terminate_all;
+       fsl_edma3->dma_dev.device_issue_pending = fsl_edma3_issue_pending;
++      fsl_edma3->dma_dev.device_synchronize = fsl_edma3_synchronize;
+       fsl_edma3->dma_dev.src_addr_widths = FSL_EDMA_BUSWIDTHS;
+       fsl_edma3->dma_dev.dst_addr_widths = FSL_EDMA_BUSWIDTHS;
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0016-MLK-19931-1-dmaengine-fsl-edma-v3-fix-potential-kern.patch b/target/linux/layerscape/patches-5.4/806-dma-0016-MLK-19931-1-dmaengine-fsl-edma-v3-fix-potential-kern.patch
new file mode 100644 (file)
index 0000000..28a59d4
--- /dev/null
@@ -0,0 +1,33 @@
+From 4967ec844a52498af050b1176fedeca37aca111e Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Tue, 16 Oct 2018 01:06:29 +0800
+Subject: [PATCH] MLK-19931-1: dmaengine: fsl-edma-v3: fix potential kernel
+ crash in cyclic
+
+  There is one potential race condition in virt-dma framework as below:
+terminate dma channel after the last dma done interrupt, but before
+vchan_complete tasklet scheduled, thus the free-ed 'vd' (free in
+fsl_edma3_terminate_all) maybe still be touched in vchan_complete()
+which cause NULL pointer crash.
+  Kernel community noticed this issue and fix it at virt-dma level:
+https://patchwork.kernel.org/patch/10057791/. To avoid backport too
+much patches, set 'vc->cyclic = NULL' in terminate dma channel
+interfaces to fix such issue easily.
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+Acked-by: Fugang Duan <fugang.duan@nxp.com>
+(cherry picked from commit 18c9083826400a2ef731496391a0b5e71d461a5f)
+---
+ drivers/dma/fsl-edma-v3.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -285,6 +285,7 @@ static int fsl_edma3_terminate_all(struc
+       fsl_chan->edesc = NULL;
+       fsl_chan->idle = true;
+       fsl_chan->used = false;
++      fsl_chan->vchan.cyclic = NULL;
+       vchan_get_all_descriptors(&fsl_chan->vchan, &head);
+       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+       vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0017-MLK-20205-1-dmaengine-fsl-edma-v3-fix-NULL-pointer-d.patch b/target/linux/layerscape/patches-5.4/806-dma-0017-MLK-20205-1-dmaengine-fsl-edma-v3-fix-NULL-pointer-d.patch
new file mode 100644 (file)
index 0000000..aff6ac0
--- /dev/null
@@ -0,0 +1,26 @@
+From 0059c7ed6c11254f214a07357bbf87296cde446f Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Wed, 7 Nov 2018 22:19:07 +0800
+Subject: [PATCH] MLK-20205-1: dmaengine: fsl-edma-v3: fix NULL pointer
+ dereference
+
+Fix 'null pointer dereferences issue' reported by coverity(CID-1477441).
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+Reviewed-by: Anson Huang <Anson.Huang@nxp.com>
+(cherry picked from commit 5343c0018af0af2eb3bb90c5a75e765b851a2c12)
+---
+ drivers/dma/fsl-edma-v3.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -419,7 +419,7 @@ static enum dma_status fsl_edma3_tx_stat
+       if (fsl_chan->edesc && cookie == fsl_chan->edesc->vdesc.tx.cookie)
+               txstate->residue = fsl_edma3_desc_residue(fsl_chan, vdesc,
+                                                               true);
+-      else if (vdesc)
++      else if (fsl_chan->edesc && vdesc)
+               txstate->residue = fsl_edma3_desc_residue(fsl_chan, vdesc,
+                                                               false);
+       else
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0018-dma-imx-add-the-32bit-dma-limitation.patch b/target/linux/layerscape/patches-5.4/806-dma-0018-dma-imx-add-the-32bit-dma-limitation.patch
new file mode 100644 (file)
index 0000000..7c1f4f9
--- /dev/null
@@ -0,0 +1,38 @@
+From bd7176b9cb91671b248fbdef0c65d2893fd78226 Mon Sep 17 00:00:00 2001
+From: Richard Zhu <hongxing.zhu@nxp.com>
+Date: Fri, 25 Jan 2019 18:02:22 +0800
+Subject: [PATCH] dma: imx: add the 32bit dma limitation
+
+Since the imx8qm/qxp hsio only supports up to 32bit
+dma capability.
+Add the 32bit dma limitation into dma binding document.
+
+Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
+---
+ Documentation/devicetree/bindings/dma/fsl-imx-dma.txt | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+--- a/Documentation/devicetree/bindings/dma/fsl-imx-dma.txt
++++ b/Documentation/devicetree/bindings/dma/fsl-imx-dma.txt
+@@ -16,6 +16,21 @@ Optional properties:
+ - #dma-channels : Number of DMA channels supported. Should be 16.
+ - #dma-requests : Number of DMA requests supported.
++* DMA capability limitation
++
++Specify the DMA capability limitations.
++For example, some SoCs only support up to 32bit DMA capability, although
++they are 64bit SoCs.
++
++- only-dma-mask32: 1 means that the SoCs only suppot up to 32bit DMA
++  capability.
++
++Example:
++      dma_cap: dma_cap {
++              compatible = "dma-capability";
++              only-dma-mask32 = <1>;
++      };
++
+ Example:
+       dma: dma@10001000 {
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0019-dmaengine-fsl-edma-calculate-the-real-count-for-slav.patch b/target/linux/layerscape/patches-5.4/806-dma-0019-dmaengine-fsl-edma-calculate-the-real-count-for-slav.patch
new file mode 100644 (file)
index 0000000..4278711
--- /dev/null
@@ -0,0 +1,70 @@
+From 7b126c5fbddf179c7d2c2393100329aa45cd8ac4 Mon Sep 17 00:00:00 2001
+From: Fugang Duan <fugang.duan@nxp.com>
+Date: Fri, 9 Aug 2019 15:14:08 +0800
+Subject: [PATCH] dmaengine: fsl-edma: calculate the real count for slave sg
+
+Calculate the rela count for current slave sg after eDMA stop.
+
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+---
+ drivers/dma/fsl-edma-common.c | 11 ++++++++++-
+ drivers/dma/fsl-edma-common.h |  2 ++
+ drivers/dma/fsl-edma.c        |  1 +
+ 3 files changed, 13 insertions(+), 1 deletion(-)
+
+--- a/drivers/dma/fsl-edma-common.c
++++ b/drivers/dma/fsl-edma-common.c
+@@ -305,6 +305,11 @@ static size_t fsl_edma_desc_residue(stru
+       return len;
+ }
++void fsl_edma_get_realcnt(struct fsl_edma_chan *fsl_chan)
++{
++      fsl_chan->chn_real_count = fsl_edma_desc_residue(fsl_chan, NULL, true);
++}
++
+ enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
+               dma_cookie_t cookie, struct dma_tx_state *txstate)
+ {
+@@ -314,8 +319,12 @@ enum dma_status fsl_edma_tx_status(struc
+       unsigned long flags;
+       status = dma_cookie_status(chan, cookie, txstate);
+-      if (status == DMA_COMPLETE)
++      if (status == DMA_COMPLETE) {
++              spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
++              txstate->residue = fsl_chan->chn_real_count;
++              spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+               return status;
++      }
+       if (!txstate)
+               return fsl_chan->status;
+--- a/drivers/dma/fsl-edma-common.h
++++ b/drivers/dma/fsl-edma-common.h
+@@ -126,6 +126,7 @@ struct fsl_edma_chan {
+       u32                             dma_dev_size;
+       enum dma_data_direction         dma_dir;
+       char                            chan_name[16];
++      u32                             chn_real_count;
+ };
+ struct fsl_edma_desc {
+@@ -229,6 +230,7 @@ int fsl_edma_pause(struct dma_chan *chan
+ int fsl_edma_resume(struct dma_chan *chan);
+ int fsl_edma_slave_config(struct dma_chan *chan,
+                                struct dma_slave_config *cfg);
++void fsl_edma_get_realcnt(struct fsl_edma_chan *fsl_chan);
+ enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
+               dma_cookie_t cookie, struct dma_tx_state *txstate);
+ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
+--- a/drivers/dma/fsl-edma.c
++++ b/drivers/dma/fsl-edma.c
+@@ -46,6 +46,7 @@ static irqreturn_t fsl_edma_tx_handler(i
+                       spin_lock(&fsl_chan->vchan.lock);
+                       if (!fsl_chan->edesc->iscyclic) {
++                              fsl_edma_get_realcnt(fsl_chan);
+                               list_del(&fsl_chan->edesc->vdesc.node);
+                               vchan_cookie_complete(&fsl_chan->edesc->vdesc);
+                               fsl_chan->edesc = NULL;
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0020-MLK-22798-1-dmaengine-fsl-edma-v3-do-not-enable-inte.patch b/target/linux/layerscape/patches-5.4/806-dma-0020-MLK-22798-1-dmaengine-fsl-edma-v3-do-not-enable-inte.patch
new file mode 100644 (file)
index 0000000..fbfb95e
--- /dev/null
@@ -0,0 +1,42 @@
+From dcb4deb92738a2fd3981550dbf18ae96e22bbe80 Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Wed, 23 Oct 2019 00:33:42 +0800
+Subject: [PATCH] MLK-22798-1: dmaengine: fsl-edma-v3: do not enable interrupt
+ in dev_2_dev
+
+Do not enable interrupt in dev_2_dev with cyclic case, since in such
+case no any interrupt needed. Otherwise many interrupt will come in
+every 64 words transfered in ASRC case, which cause heavy system
+loading.
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+(cherry picked from commit f0a3172e1ceb04c46377160486ad7dc6ee022850)
+---
+ drivers/dma/fsl-edma-v3.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -560,6 +560,7 @@ static struct dma_async_tx_descriptor *f
+       int sg_len, i;
+       u32 src_addr, dst_addr, last_sg, nbytes;
+       u16 soff, doff, iter;
++      bool major_int = true;
+       sg_len = buf_len / period_len;
+       fsl_desc = fsl_edma3_alloc_desc(fsl_chan, sg_len);
+@@ -600,11 +601,12 @@ static struct dma_async_tx_descriptor *f
+                       dst_addr = fsl_chan->fsc.dev_addr;
+                       soff = 0;
+                       doff = 0;
++                      major_int = false;
+               }
+               fsl_edma3_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd, src_addr,
+                               dst_addr, fsl_chan->fsc.attr, soff, nbytes, 0,
+-                              iter, iter, doff, last_sg, true, false, true);
++                              iter, iter, doff, last_sg, major_int, false, true);
+               dma_buf_next += period_len;
+       }
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0021-MLK-21443-dmaengine-fsl-edma-v3-clear-pending-irq-be.patch b/target/linux/layerscape/patches-5.4/806-dma-0021-MLK-21443-dmaengine-fsl-edma-v3-clear-pending-irq-be.patch
new file mode 100644 (file)
index 0000000..7bcbe46
--- /dev/null
@@ -0,0 +1,124 @@
+From 63c3fd953a620873c722494355a345643607c0a2 Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Thu, 11 Apr 2019 14:36:37 +0800
+Subject: [PATCH] MLK-21443: dmaengine: fsl-edma-v3: clear pending irq before
+ request irq
+
+edma interrupt maybe happened during reboot or watchdog reset, meanwhile
+gic never power down on i.mx8QM/QXP, thus the unexpect irq will come in
+once edma driver request irq at probe phase. Unfortunately, at that time
+that edma channel's power domain which power-up by customer driver such
+as audio/uart driver may not be ready, so kernel panic triggered once
+touch such edma registers which still not power up in interrupt handler.
+Move request irq from probe to alloc dma channel so that edma channel's
+power domain has already been powered, besides, clear meaningless
+interrupt before request irq.
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+Acked-by: Fugang Duan <fugang.duan@nxp.com>
+(cherry picked from commit 0a0d8f8b944094342fda18f23f3ac13b8a73871d)
+---
+ drivers/dma/fsl-edma-v3.c | 34 ++++++++++++++++++++++------------
+ 1 file changed, 22 insertions(+), 12 deletions(-)
+
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -162,7 +162,8 @@ struct fsl_edma3_chan {
+       int                             is_dfifo;
+       struct dma_pool                 *tcd_pool;
+       u32                             chn_real_count;
+-      char                            txirq_name[32];
++      char                            txirq_name[32];
++      struct platform_device          *pdev;
+ };
+ struct fsl_edma3_desc {
+@@ -180,6 +181,7 @@ struct fsl_edma3_reg_save {
+ struct fsl_edma3_engine {
+       struct dma_device       dma_dev;
++      unsigned long           irqflag;
+       struct mutex            fsl_edma3_mutex;
+       u32                     n_chans;
+       int                     errirq;
+@@ -790,10 +792,23 @@ static struct dma_chan *fsl_edma3_xlate(
+ static int fsl_edma3_alloc_chan_resources(struct dma_chan *chan)
+ {
+       struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
++      struct platform_device *pdev = fsl_chan->pdev;
++      int ret;
+       fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
+                               sizeof(struct fsl_edma3_hw_tcd),
+                               32, 0);
++      /* clear meaningless pending irq anyway */
++      writel(1, fsl_chan->membase + EDMA_CH_INT);
++      ret = devm_request_irq(&pdev->dev, fsl_chan->txirq,
++                      fsl_edma3_tx_handler, fsl_chan->edma3->irqflag,
++                      fsl_chan->txirq_name, fsl_chan);
++      if (ret) {
++              dev_err(&pdev->dev, "Can't register %s IRQ.\n",
++                      fsl_chan->txirq_name);
++              return ret;
++      }
++
+       return 0;
+ }
+@@ -803,6 +818,8 @@ static void fsl_edma3_free_chan_resource
+       unsigned long flags;
+       LIST_HEAD(head);
++      devm_free_irq(&fsl_chan->pdev->dev, fsl_chan->txirq, fsl_chan);
++
+       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+       fsl_edma3_disable_request(fsl_chan);
+       fsl_chan->edesc = NULL;
+@@ -830,7 +847,6 @@ static int fsl_edma3_probe(struct platfo
+       struct resource *res;
+       int len, chans;
+       int ret, i;
+-      unsigned long irqflag = 0;
+       ret = of_property_read_u32(np, "dma-channels", &chans);
+       if (ret) {
+@@ -845,7 +861,7 @@ static int fsl_edma3_probe(struct platfo
+       /* Audio edma rx/tx channel shared interrupt */
+       if (of_property_read_bool(np, "shared-interrupt"))
+-              irqflag = IRQF_SHARED;
++              fsl_edma3->irqflag = IRQF_SHARED;
+       fsl_edma3->swap = of_device_is_compatible(np, "fsl,imx8qm-adma");
+       fsl_edma3->n_chans = chans;
+@@ -853,12 +869,13 @@ static int fsl_edma3_probe(struct platfo
+       INIT_LIST_HEAD(&fsl_edma3->dma_dev.channels);
+       for (i = 0; i < fsl_edma3->n_chans; i++) {
+               struct fsl_edma3_chan *fsl_chan = &fsl_edma3->chans[i];
+-              const char *txirq_name = fsl_chan->txirq_name;
++              const char *txirq_name;
+               char chanid[3], id_len = 0;
+               char *p = chanid;
+               unsigned long val;
+               fsl_chan->edma3 = fsl_edma3;
++              fsl_chan->pdev = pdev;
+               fsl_chan->pm_state = RUNNING;
+               fsl_chan->idle = true;
+               /* Get per channel membase */
+@@ -904,14 +921,7 @@ static int fsl_edma3_probe(struct platfo
+                       return fsl_chan->txirq;
+               }
+-              ret = devm_request_irq(&pdev->dev, fsl_chan->txirq,
+-                              fsl_edma3_tx_handler, irqflag, txirq_name,
+-                              fsl_chan);
+-              if (ret) {
+-                      dev_err(&pdev->dev, "Can't register %s IRQ.\n",
+-                              txirq_name);
+-                      return ret;
+-              }
++              memcpy(fsl_chan->txirq_name, txirq_name, strlen(txirq_name));
+               fsl_chan->vchan.desc_free = fsl_edma3_free_desc;
+               vchan_init(&fsl_chan->vchan, &fsl_edma3->dma_dev);
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0022-MLK-22284-1-dmaengine-fsl-edma-v3-add-power-domains-.patch b/target/linux/layerscape/patches-5.4/806-dma-0022-MLK-22284-1-dmaengine-fsl-edma-v3-add-power-domains-.patch
new file mode 100644 (file)
index 0000000..8c7fc44
--- /dev/null
@@ -0,0 +1,170 @@
+From 9050c0619cdf5399d19e3683d6fb1db355dda110 Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Wed, 17 Apr 2019 17:05:42 +0800
+Subject: [PATCH] MLK-22284-1 dmaengine: fsl-edma-v3: add power domains for
+ each channel
+
+Add power domains for each dma channel so that edma channel could
+know the power state of every dma channel anytime and clear easily
+unexpected interrupt which triggered before the last partition reset.
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+Reviewed-by: S.j. Wang <shengjiu.wang@nxp.com>
+(cherry picked from commit 0b6da46b7bdb2284e24757d48466268b9feb5b7c)
+---
+ .../devicetree/bindings/dma/fsl-edma-v3.txt        | 11 +++-
+ drivers/dma/fsl-edma-v3.c                          | 58 +++++++++++++++++++++-
+ 2 files changed, 67 insertions(+), 2 deletions(-)
+
+--- a/Documentation/devicetree/bindings/dma/fsl-edma-v3.txt
++++ b/Documentation/devicetree/bindings/dma/fsl-edma-v3.txt
+@@ -30,6 +30,8 @@ Required properties:
+               0: not dual fifo case, 1: dualfifo case.
+       See the SoC's reference manual for all the supported request sources.
+ - dma-channels : Number of channels supported by the controller
++- power-domains: Power domains for edma channel used.
++- power-domain-names: Power domains name for edma channel used.
+ Examples:
+ edma0: dma-controller@40018000 {
+@@ -46,6 +48,12 @@ edma0: dma-controller@40018000 {
+                    <GIC_SPI 437 IRQ_TYPE_LEVEL_HIGH>;
+       interrupt-names = "edma0-chan12-rx", "edma0-chan13-tx",
+                         "edma0-chan14-rx", "edma0-chan15-tx";
++      power-domains = <&pd IMX_SC_R_DMA_0_CH12>,
++                      <&pd IMX_SC_R_DMA_0_CH13>,
++                      <&pd IMX_SC_R_DMA_0_CH14>,
++                      <&pd IMX_SC_R_DMA_0_CH15>;
++      power-domain-names = "edma0-chan12", "edma0-chan13",
++                           "edma0-chan14", "edma0-chan15";
+       status = "okay";
+ };
+@@ -65,7 +73,8 @@ lpuart1: serial@5a070000 {
+       clock-names = "ipg";
+       assigned-clock-names = <&clk IMX8QM_UART1_CLK>;
+       assigned-clock-rates = <80000000>;
+-      power-domains = <&pd_dma_lpuart1>;
++      power-domains = <&pd IMX_SC_R_UART_1>,
++      power-domain-names = "uart";
+       dma-names = "tx","rx";
+       dmas = <&edma0 15 0 0>,
+               <&edma0 14 0 1>;
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -27,6 +27,8 @@
+ #include <linux/of_address.h>
+ #include <linux/of_irq.h>
+ #include <linux/of_dma.h>
++#include <linux/pm_runtime.h>
++#include <linux/pm_domain.h>
+ #include "virt-dma.h"
+@@ -164,6 +166,7 @@ struct fsl_edma3_chan {
+       u32                             chn_real_count;
+       char                            txirq_name[32];
+       struct platform_device          *pdev;
++      struct device                   *dev;
+ };
+ struct fsl_edma3_desc {
+@@ -798,8 +801,10 @@ static int fsl_edma3_alloc_chan_resource
+       fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
+                               sizeof(struct fsl_edma3_hw_tcd),
+                               32, 0);
++      pm_runtime_get_sync(fsl_chan->dev);
+       /* clear meaningless pending irq anyway */
+       writel(1, fsl_chan->membase + EDMA_CH_INT);
++
+       ret = devm_request_irq(&pdev->dev, fsl_chan->txirq,
+                       fsl_edma3_tx_handler, fsl_chan->edma3->irqflag,
+                       fsl_chan->txirq_name, fsl_chan);
+@@ -830,6 +835,7 @@ static void fsl_edma3_free_chan_resource
+       dma_pool_destroy(fsl_chan->tcd_pool);
+       fsl_chan->tcd_pool = NULL;
+       fsl_chan->used = false;
++      pm_runtime_put_sync(fsl_chan->dev);
+ }
+ static void fsl_edma3_synchronize(struct dma_chan *chan)
+@@ -839,6 +845,37 @@ static void fsl_edma3_synchronize(struct
+       vchan_synchronize(&fsl_chan->vchan);
+ }
++static struct device *fsl_edma3_attach_pd(struct device *dev,
++                                        struct device_node *np, int index)
++{
++      const char *domn = "edma0-chan01";
++      struct device *pd_chan;
++      struct device_link *link;
++      int ret;
++
++      ret = of_property_read_string_index(np, "power-domain-names", index,
++                                              &domn);
++      if (ret) {
++              dev_err(dev, "parse power-domain-names error.(%d)\n", ret);
++              return NULL;
++      }
++
++      pd_chan = dev_pm_domain_attach_by_name(dev, domn);
++      if (!pd_chan)
++              return NULL;
++
++      link = device_link_add(dev, pd_chan, DL_FLAG_STATELESS |
++                                           DL_FLAG_PM_RUNTIME |
++                                           DL_FLAG_RPM_ACTIVE);
++      if (IS_ERR(link)) {
++              dev_err(dev, "Failed to add device_link to %s: %ld\n", domn,
++                      PTR_ERR(link));
++              return NULL;
++      }
++
++      return pd_chan;
++}
++
+ static int fsl_edma3_probe(struct platform_device *pdev)
+ {
+       struct device_node *np = pdev->dev.of_node;
+@@ -962,6 +999,22 @@ static int fsl_edma3_probe(struct platfo
+               dev_err(&pdev->dev, "Can't register Freescale eDMA engine.\n");
+               return ret;
+       }
++      /* Attach power domains from dts for each dma chanel device */
++      for (i = 0; i < fsl_edma3->n_chans; i++) {
++              struct fsl_edma3_chan *fsl_chan = &fsl_edma3->chans[i];
++              struct device *dev;
++
++              dev = fsl_edma3_attach_pd(&pdev->dev, np, i);
++              if (!dev) {
++                      dev_err(dev, "edma channel attach failed.\n");
++                      return -EINVAL;
++              }
++
++              fsl_chan->dev = dev;
++              /* clear meaningless pending irq anyway */
++              writel(1, fsl_chan->membase + EDMA_CH_INT);
++              pm_runtime_put_sync(dev);
++      }
+       ret = of_dma_controller_register(np, fsl_edma3_xlate, fsl_edma3);
+       if (ret) {
+@@ -970,6 +1023,9 @@ static int fsl_edma3_probe(struct platfo
+               return ret;
+       }
++      pm_runtime_dont_use_autosuspend(&pdev->dev);
++      pm_runtime_enable(&pdev->dev);
++
+       return 0;
+ }
+@@ -1068,7 +1124,7 @@ static int __init fsl_edma3_init(void)
+ {
+       return platform_driver_register(&fsl_edma3_driver);
+ }
+-subsys_initcall(fsl_edma3_init);
++fs_initcall(fsl_edma3_init);
+ static void __exit fsl_edma3_exit(void)
+ {
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0023-MLK-22284-2-dmaengine-fsl-edma-v3-check-dma-descript.patch b/target/linux/layerscape/patches-5.4/806-dma-0023-MLK-22284-2-dmaengine-fsl-edma-v3-check-dma-descript.patch
new file mode 100644 (file)
index 0000000..c073dd5
--- /dev/null
@@ -0,0 +1,47 @@
+From 89885c09160b04ae2eec82cf9b35117ff6aa4c5d Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Wed, 8 May 2019 00:13:40 +0800
+Subject: [PATCH] MLK-22284-2 dmaengine: fsl-edma-v3: check dma description
+ before register touch
+
+Check dma desscription firstly to ignore any unexpected interrupt
+after channel terminate, otherwise, still have chance to touch channel
+register whose power has been already off.
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+Reviewed-by: S.j. Wang <shengjiu.wang@nxp.com>
+(cherry picked from commit fd073e017e317006a4c254ca5ae3ea17b6f32502)
+---
+ drivers/dma/fsl-edma-v3.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -708,20 +708,20 @@ static irqreturn_t fsl_edma3_tx_handler(
+       unsigned int intr;
+       void __iomem *base_addr;
++      spin_lock(&fsl_chan->vchan.lock);
++
++      /* Ignore this interrupt since channel has been disabled already */
++      if (!fsl_chan->edesc)
++              goto irq_handled;
++
+       base_addr = fsl_chan->membase;
+       intr = readl(base_addr + EDMA_CH_INT);
+       if (!intr)
+-              return IRQ_NONE;
++              goto irq_handled;
+       writel(1, base_addr + EDMA_CH_INT);
+-      spin_lock(&fsl_chan->vchan.lock);
+-
+-      /* Ignore this interrupt since channel has been disabled already */
+-      if (!fsl_chan->edesc)
+-              goto irq_handled;
+-
+       if (!fsl_chan->edesc->iscyclic) {
+               fsl_edma3_get_realcnt(fsl_chan);
+               list_del(&fsl_chan->edesc->vdesc.node);
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0024-MLK-22302-2-dmaengine-fsl-edma-v3-fix-build-warning-.patch b/target/linux/layerscape/patches-5.4/806-dma-0024-MLK-22302-2-dmaengine-fsl-edma-v3-fix-build-warning-.patch
new file mode 100644 (file)
index 0000000..c6fc11c
--- /dev/null
@@ -0,0 +1,39 @@
+From 88ac887c165bffe8b03cc81a74d089abc4c02cd1 Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Tue, 23 Jul 2019 23:42:53 +0800
+Subject: [PATCH] MLK-22302-2: dmaengine: fsl-edma-v3: fix build warning with
+ CONFIG_PM_SLEEP=n
+
+Fix build waring with CONFIG_PM_SLEEP=n.
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+Reviewed-by: Andy Duan <fugang.duan@nxp.com>
+(cherry picked from commit dfe2a755209615f9592ed937957b2efdc3b6d6c0)
+---
+ drivers/dma/fsl-edma-v3.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -1040,6 +1040,7 @@ static int fsl_edma3_remove(struct platf
+       return 0;
+ }
++#ifdef CONFIG_PM_SLEEP
+ static int fsl_edma3_suspend_late(struct device *dev)
+ {
+       struct fsl_edma3_engine *fsl_edma = dev_get_drvdata(dev);
+@@ -1097,10 +1098,11 @@ static int fsl_edma3_resume_early(struct
+       return 0;
+ }
++#endif
+ static const struct dev_pm_ops fsl_edma3_pm_ops = {
+-      .suspend_late   = fsl_edma3_suspend_late,
+-      .resume_early   = fsl_edma3_resume_early,
++      SET_LATE_SYSTEM_SLEEP_PM_OPS(fsl_edma3_suspend_late,
++                                   fsl_edma3_resume_early)
+ };
+ static const struct of_device_id fsl_edma3_dt_ids[] = {
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0025-MLK-22909-dmaengine-fsl-edma-v3-clear-interrupt-comi.patch b/target/linux/layerscape/patches-5.4/806-dma-0025-MLK-22909-dmaengine-fsl-edma-v3-clear-interrupt-comi.patch
new file mode 100644 (file)
index 0000000..42f151f
--- /dev/null
@@ -0,0 +1,43 @@
+From 7021361c27946c60885b3f031ddde342f9a5432f Mon Sep 17 00:00:00 2001
+From: Robin Gong <yibin.gong@nxp.com>
+Date: Tue, 5 Nov 2019 21:32:22 +0800
+Subject: [PATCH] MLK-22909 dmaengine: fsl-edma-v3: clear interrupt coming
+ after channel terminated
+
+Clear EDMA_CH_INT in case dma done interrupt comes after channel terminated
+instead of channel free-ed, otherwise, RCU maybe caught because it's
+ignored without interrupt status cleared as Android team report in Monkey
+test.
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+Acked-by: Fugang Duan <fugang.duan@nxp.com>
+(cherry picked from commit ef91ff6ed465cebe2fe6483a480351abba36e237)
+(cherry picked from commit 56ee55c71c5f3ef254acb4dee581e68f79ef13a5)
+---
+ drivers/dma/fsl-edma-v3.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/dma/fsl-edma-v3.c
++++ b/drivers/dma/fsl-edma-v3.c
+@@ -710,8 +710,8 @@ static irqreturn_t fsl_edma3_tx_handler(
+       spin_lock(&fsl_chan->vchan.lock);
+-      /* Ignore this interrupt since channel has been disabled already */
+-      if (!fsl_chan->edesc)
++      /* Ignore this interrupt since channel has been freeed with power off */
++      if (!fsl_chan->edesc && !fsl_chan->tcd_pool)
+               goto irq_handled;
+       base_addr = fsl_chan->membase;
+@@ -722,6 +722,10 @@ static irqreturn_t fsl_edma3_tx_handler(
+       writel(1, base_addr + EDMA_CH_INT);
++      /* Ignore this interrupt since channel has been disabled already */
++      if (!fsl_chan->edesc)
++              goto irq_handled;
++
+       if (!fsl_chan->edesc->iscyclic) {
+               fsl_edma3_get_realcnt(fsl_chan);
+               list_del(&fsl_chan->edesc->vdesc.node);
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0026-dma-caam-add-dma-memcpy-driver.patch b/target/linux/layerscape/patches-5.4/806-dma-0026-dma-caam-add-dma-memcpy-driver.patch
new file mode 100644 (file)
index 0000000..073842e
--- /dev/null
@@ -0,0 +1,538 @@
+From 27aa9f97887f599267c345075e61979de785c770 Mon Sep 17 00:00:00 2001
+From: Peng Ma <peng.ma@nxp.com>
+Date: Thu, 11 Oct 2018 16:49:41 +0800
+Subject: [PATCH] dma: caam: add dma memcpy driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This module introduces a memcpy DMA driver based on the DMA capabilities
+of the CAAM hardware block. CAAM DMA is a platform driver that is only
+probed if the device is defined in the device tree. The driver creates
+a DMA channel for each JR of the CAAM. This introduces a dependency on
+the JR driver. Therefore a defering mechanism was used to ensure that
+the CAAM DMA driver is probed only after the JR driver.
+
+Signed-off-by: Radu Alexe <radu.alexe@nxp.com>
+Signed-off-by: Tudor Ambarus <tudor-dan.ambarus@nxp.com>
+Signed-off-by: Rajiv Vishwakarma <rajiv.vishwakarma@nxp.com>
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/dma/Kconfig    |  19 +-
+ drivers/dma/Makefile   |   1 +
+ drivers/dma/caam_dma.c | 462 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 481 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/dma/caam_dma.c
+
+--- a/drivers/dma/Kconfig
++++ b/drivers/dma/Kconfig
+@@ -131,6 +131,24 @@ config COH901318
+       help
+         Enable support for ST-Ericsson COH 901 318 DMA.
++config CRYPTO_DEV_FSL_CAAM_DMA
++      tristate "CAAM DMA engine support"
++      depends on CRYPTO_DEV_FSL_CAAM_JR
++      default n
++      select DMA_ENGINE
++      select ASYNC_CORE
++      select ASYNC_TX_ENABLE_CHANNEL_SWITCH
++      help
++        Selecting this will offload the DMA operations for users of
++        the scatter gather memcopy API to the CAAM via job rings. The
++        CAAM is a hardware module that provides hardware acceleration to
++        cryptographic operations. It has a built-in DMA controller that can
++        be programmed to read/write cryptographic data. This module defines
++        a DMA driver that uses the DMA capabilities of the CAAM.
++
++        To compile this as a module, choose M here: the module
++        will be called caam_dma.
++
+ config DMA_BCM2835
+       tristate "BCM2835 DMA engine support"
+       depends on ARCH_BCM2835
+@@ -662,7 +680,6 @@ config ZX_DMA
+       help
+         Support the DMA engine for ZTE ZX family platform devices.
+-
+ # driver files
+ source "drivers/dma/bestcomm/Kconfig"
+--- a/drivers/dma/Makefile
++++ b/drivers/dma/Makefile
+@@ -77,6 +77,7 @@ obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
+ obj-$(CONFIG_ZX_DMA) += zx_dma.o
+ obj-$(CONFIG_ST_FDMA) += st_fdma.o
+ obj-$(CONFIG_FSL_DPAA2_QDMA) += fsl-dpaa2-qdma/
++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_DMA) += caam_dma.o
+ obj-y += mediatek/
+ obj-y += qcom/
+--- /dev/null
++++ b/drivers/dma/caam_dma.c
+@@ -0,0 +1,462 @@
++/*
++ * caam support for SG DMA
++ *
++ * Copyright 2016 Freescale Semiconductor, Inc
++ * Copyright 2017 NXP
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *       notice, this list of conditions and the following disclaimer in the
++ *       documentation and/or other materials provided with the distribution.
++ *     * Neither the names of the above-listed copyright holders nor the
++ *       names of any contributors may be used to endorse or promote products
++ *       derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include "dmaengine.h"
++
++#include "../crypto/caam/regs.h"
++#include "../crypto/caam/jr.h"
++#include "../crypto/caam/error.h"
++#include "../crypto/caam/desc_constr.h"
++
++#define DESC_DMA_MEMCPY_LEN   ((CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN) / \
++                               CAAM_CMD_SZ)
++
++/*
++ * This is max chunk size of a DMA transfer. If a buffer is larger than this
++ * value it is internally broken into chunks of max CAAM_DMA_CHUNK_SIZE bytes
++ * and for each chunk a DMA transfer request is issued.
++ * This value is the largest number on 16 bits that is a multiple of 256 bytes
++ * (the largest configurable CAAM DMA burst size).
++ */
++#define CAAM_DMA_CHUNK_SIZE   65280
++
++struct caam_dma_sh_desc {
++      u32 desc[DESC_DMA_MEMCPY_LEN] ____cacheline_aligned;
++      dma_addr_t desc_dma;
++};
++
++/* caam dma extended descriptor */
++struct caam_dma_edesc {
++      struct dma_async_tx_descriptor async_tx;
++      struct list_head node;
++      struct caam_dma_ctx *ctx;
++      dma_addr_t src_dma;
++      dma_addr_t dst_dma;
++      unsigned int src_len;
++      unsigned int dst_len;
++      u32 jd[] ____cacheline_aligned;
++};
++
++/*
++ * caam_dma_ctx - per jr/channel context
++ * @chan: dma channel used by async_tx API
++ * @node: list_head used to attach to the global dma_ctx_list
++ * @jrdev: Job Ring device
++ * @pending_q: queue of pending (submitted, but not enqueued) jobs
++ * @done_not_acked: jobs that have been completed by jr, but maybe not acked
++ * @edesc_lock: protects extended descriptor
++ */
++struct caam_dma_ctx {
++      struct dma_chan chan;
++      struct list_head node;
++      struct device *jrdev;
++      struct list_head pending_q;
++      struct list_head done_not_acked;
++      spinlock_t edesc_lock;
++};
++
++static struct dma_device *dma_dev;
++static struct caam_dma_sh_desc *dma_sh_desc;
++static LIST_HEAD(dma_ctx_list);
++
++static dma_cookie_t caam_dma_tx_submit(struct dma_async_tx_descriptor *tx)
++{
++      struct caam_dma_edesc *edesc = NULL;
++      struct caam_dma_ctx *ctx = NULL;
++      dma_cookie_t cookie;
++
++      edesc = container_of(tx, struct caam_dma_edesc, async_tx);
++      ctx = container_of(tx->chan, struct caam_dma_ctx, chan);
++
++      spin_lock_bh(&ctx->edesc_lock);
++
++      cookie = dma_cookie_assign(tx);
++      list_add_tail(&edesc->node, &ctx->pending_q);
++
++      spin_unlock_bh(&ctx->edesc_lock);
++
++      return cookie;
++}
++
++static void caam_jr_chan_free_edesc(struct caam_dma_edesc *edesc)
++{
++      struct caam_dma_ctx *ctx = edesc->ctx;
++      struct caam_dma_edesc *_edesc = NULL;
++
++      spin_lock_bh(&ctx->edesc_lock);
++
++      list_add_tail(&edesc->node, &ctx->done_not_acked);
++      list_for_each_entry_safe(edesc, _edesc, &ctx->done_not_acked, node) {
++              if (async_tx_test_ack(&edesc->async_tx)) {
++                      list_del(&edesc->node);
++                      kfree(edesc);
++              }
++      }
++
++      spin_unlock_bh(&ctx->edesc_lock);
++}
++
++static void caam_dma_done(struct device *dev, u32 *hwdesc, u32 err,
++                        void *context)
++{
++      struct caam_dma_edesc *edesc = context;
++      struct caam_dma_ctx *ctx = edesc->ctx;
++      dma_async_tx_callback callback;
++      void *callback_param;
++
++      if (err)
++              caam_jr_strstatus(ctx->jrdev, err);
++
++      dma_run_dependencies(&edesc->async_tx);
++
++      spin_lock_bh(&ctx->edesc_lock);
++      dma_cookie_complete(&edesc->async_tx);
++      spin_unlock_bh(&ctx->edesc_lock);
++
++      callback = edesc->async_tx.callback;
++      callback_param = edesc->async_tx.callback_param;
++
++      dma_descriptor_unmap(&edesc->async_tx);
++
++      caam_jr_chan_free_edesc(edesc);
++
++      if (callback)
++              callback(callback_param);
++}
++
++static void caam_dma_memcpy_init_job_desc(struct caam_dma_edesc *edesc)
++{
++      u32 *jd = edesc->jd;
++      u32 *sh_desc = dma_sh_desc->desc;
++      dma_addr_t desc_dma = dma_sh_desc->desc_dma;
++
++      /* init the job descriptor */
++      init_job_desc_shared(jd, desc_dma, desc_len(sh_desc), HDR_REVERSE);
++
++      /* set SEQIN PTR */
++      append_seq_in_ptr(jd, edesc->src_dma, edesc->src_len, 0);
++
++      /* set SEQOUT PTR */
++      append_seq_out_ptr(jd, edesc->dst_dma, edesc->dst_len, 0);
++
++      print_hex_dump_debug("caam dma desc@" __stringify(__LINE__) ": ",
++                           DUMP_PREFIX_ADDRESS, 16, 4, jd, desc_bytes(jd), 1);
++}
++
++static struct dma_async_tx_descriptor *
++caam_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
++                   size_t len, unsigned long flags)
++{
++      struct caam_dma_edesc *edesc;
++      struct caam_dma_ctx *ctx = container_of(chan, struct caam_dma_ctx,
++                                              chan);
++
++      edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN, GFP_DMA | GFP_NOWAIT);
++      if (!edesc)
++              return ERR_PTR(-ENOMEM);
++
++      dma_async_tx_descriptor_init(&edesc->async_tx, chan);
++      edesc->async_tx.tx_submit = caam_dma_tx_submit;
++      edesc->async_tx.flags = flags;
++      edesc->async_tx.cookie = -EBUSY;
++
++      edesc->src_dma = src;
++      edesc->src_len = len;
++      edesc->dst_dma = dst;
++      edesc->dst_len = len;
++      edesc->ctx = ctx;
++
++      caam_dma_memcpy_init_job_desc(edesc);
++
++      return &edesc->async_tx;
++}
++
++/* This function can be called in an interrupt context */
++static void caam_dma_issue_pending(struct dma_chan *chan)
++{
++      struct caam_dma_ctx *ctx = container_of(chan, struct caam_dma_ctx,
++                                              chan);
++      struct caam_dma_edesc *edesc, *_edesc;
++
++      spin_lock_bh(&ctx->edesc_lock);
++      list_for_each_entry_safe(edesc, _edesc, &ctx->pending_q, node) {
++              if (caam_jr_enqueue(ctx->jrdev, edesc->jd,
++                                  caam_dma_done, edesc) < 0)
++                      break;
++              list_del(&edesc->node);
++      }
++      spin_unlock_bh(&ctx->edesc_lock);
++}
++
++static void caam_dma_free_chan_resources(struct dma_chan *chan)
++{
++      struct caam_dma_ctx *ctx = container_of(chan, struct caam_dma_ctx,
++                                              chan);
++      struct caam_dma_edesc *edesc, *_edesc;
++
++      spin_lock_bh(&ctx->edesc_lock);
++      list_for_each_entry_safe(edesc, _edesc, &ctx->pending_q, node) {
++              list_del(&edesc->node);
++              kfree(edesc);
++      }
++      list_for_each_entry_safe(edesc, _edesc, &ctx->done_not_acked, node) {
++              list_del(&edesc->node);
++              kfree(edesc);
++      }
++      spin_unlock_bh(&ctx->edesc_lock);
++}
++
++static int caam_dma_jr_chan_bind(void)
++{
++      struct device *jrdev;
++      struct caam_dma_ctx *ctx;
++      int bonds = 0;
++      int i;
++
++      for (i = 0; i < caam_jr_driver_probed(); i++) {
++              jrdev = caam_jridx_alloc(i);
++              if (IS_ERR(jrdev)) {
++                      pr_err("job ring device %d allocation failed\n", i);
++                      continue;
++              }
++
++              ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
++              if (!ctx) {
++                      caam_jr_free(jrdev);
++                      continue;
++              }
++
++              ctx->chan.device = dma_dev;
++              ctx->chan.private = ctx;
++
++              ctx->jrdev = jrdev;
++
++              INIT_LIST_HEAD(&ctx->pending_q);
++              INIT_LIST_HEAD(&ctx->done_not_acked);
++              INIT_LIST_HEAD(&ctx->node);
++              spin_lock_init(&ctx->edesc_lock);
++
++              dma_cookie_init(&ctx->chan);
++
++              /* add the context of this channel to the context list */
++              list_add_tail(&ctx->node, &dma_ctx_list);
++
++              /* add this channel to the device chan list */
++              list_add_tail(&ctx->chan.device_node, &dma_dev->channels);
++
++              bonds++;
++      }
++
++      return bonds;
++}
++
++static inline void caam_jr_dma_free(struct dma_chan *chan)
++{
++      struct caam_dma_ctx *ctx = container_of(chan, struct caam_dma_ctx,
++                                              chan);
++
++      list_del(&ctx->node);
++      list_del(&chan->device_node);
++      caam_jr_free(ctx->jrdev);
++      kfree(ctx);
++}
++
++static void set_caam_dma_desc(u32 *desc)
++{
++      u32 *jmp_cmd;
++
++      /* dma shared descriptor */
++      init_sh_desc(desc, HDR_SHARE_NEVER | (1 << HDR_START_IDX_SHIFT));
++
++      /* REG1 = CAAM_DMA_CHUNK_SIZE */
++      append_math_add_imm_u32(desc, REG1, ZERO, IMM, CAAM_DMA_CHUNK_SIZE);
++
++      /* REG0 = SEQINLEN - CAAM_DMA_CHUNK_SIZE */
++      append_math_sub_imm_u32(desc, REG0, SEQINLEN, IMM, CAAM_DMA_CHUNK_SIZE);
++
++      /*
++       * if (REG0 > 0)
++       *      jmp to LABEL1
++       */
++      jmp_cmd = append_jump(desc, JUMP_TEST_INVALL | JUMP_COND_MATH_N |
++                            JUMP_COND_MATH_Z);
++
++      /* REG1 = SEQINLEN */
++      append_math_sub(desc, REG1, SEQINLEN, ZERO, CAAM_CMD_SZ);
++
++      /* LABEL1 */
++      set_jump_tgt_here(desc, jmp_cmd);
++
++      /* VARSEQINLEN = REG1 */
++      append_math_add(desc, VARSEQINLEN, REG1, ZERO, CAAM_CMD_SZ);
++
++      /* VARSEQOUTLEN = REG1 */
++      append_math_add(desc, VARSEQOUTLEN, REG1, ZERO, CAAM_CMD_SZ);
++
++      /* do FIFO STORE */
++      append_seq_fifo_store(desc, 0, FIFOST_TYPE_METADATA | LDST_VLF);
++
++      /* do FIFO LOAD */
++      append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 |
++                           FIFOLD_TYPE_IFIFO | LDST_VLF);
++
++      /*
++       * if (REG0 > 0)
++       *      jmp 0xF8 (after shared desc header)
++       */
++      append_jump(desc, JUMP_TEST_INVALL | JUMP_COND_MATH_N |
++                  JUMP_COND_MATH_Z | 0xF8);
++
++      print_hex_dump_debug("caam dma shdesc@" __stringify(__LINE__) ": ",
++                           DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
++                           1);
++}
++
++static int caam_dma_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct device *ctrldev = dev->parent;
++      struct dma_chan *chan, *_chan;
++      u32 *sh_desc;
++      int err = -ENOMEM;
++      int bonds;
++
++      if (!caam_jr_driver_probed()) {
++              dev_info(dev, "Defer probing after JR driver probing\n");
++              return -EPROBE_DEFER;
++      }
++
++      dma_dev = kzalloc(sizeof(*dma_dev), GFP_KERNEL);
++      if (!dma_dev)
++              return -ENOMEM;
++
++      dma_sh_desc = kzalloc(sizeof(*dma_sh_desc), GFP_KERNEL | GFP_DMA);
++      if (!dma_sh_desc)
++              goto desc_err;
++
++      sh_desc = dma_sh_desc->desc;
++      set_caam_dma_desc(sh_desc);
++      dma_sh_desc->desc_dma = dma_map_single(ctrldev, sh_desc,
++                                             desc_bytes(sh_desc),
++                                             DMA_TO_DEVICE);
++      if (dma_mapping_error(ctrldev, dma_sh_desc->desc_dma)) {
++              dev_err(dev, "unable to map dma descriptor\n");
++              goto map_err;
++      }
++
++      INIT_LIST_HEAD(&dma_dev->channels);
++
++      bonds = caam_dma_jr_chan_bind();
++      if (!bonds) {
++              err = -ENODEV;
++              goto jr_bind_err;
++      }
++
++      dma_dev->dev = dev;
++      dma_dev->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
++      dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
++      dma_cap_set(DMA_PRIVATE, dma_dev->cap_mask);
++      dma_dev->device_tx_status = dma_cookie_status;
++      dma_dev->device_issue_pending = caam_dma_issue_pending;
++      dma_dev->device_prep_dma_memcpy = caam_dma_prep_memcpy;
++      dma_dev->device_free_chan_resources = caam_dma_free_chan_resources;
++
++      err = dma_async_device_register(dma_dev);
++      if (err) {
++              dev_err(dev, "Failed to register CAAM DMA engine\n");
++              goto jr_bind_err;
++      }
++
++      dev_info(dev, "caam dma support with %d job rings\n", bonds);
++
++      return err;
++
++jr_bind_err:
++      list_for_each_entry_safe(chan, _chan, &dma_dev->channels, device_node)
++              caam_jr_dma_free(chan);
++
++      dma_unmap_single(ctrldev, dma_sh_desc->desc_dma, desc_bytes(sh_desc),
++                       DMA_TO_DEVICE);
++map_err:
++      kfree(dma_sh_desc);
++desc_err:
++      kfree(dma_dev);
++      return err;
++}
++
++static int caam_dma_remove(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct device *ctrldev = dev->parent;
++      struct caam_dma_ctx *ctx, *_ctx;
++
++      dma_async_device_unregister(dma_dev);
++
++      list_for_each_entry_safe(ctx, _ctx, &dma_ctx_list, node) {
++              list_del(&ctx->node);
++              caam_jr_free(ctx->jrdev);
++              kfree(ctx);
++      }
++
++      dma_unmap_single(ctrldev, dma_sh_desc->desc_dma,
++                       desc_bytes(dma_sh_desc->desc), DMA_TO_DEVICE);
++
++      kfree(dma_sh_desc);
++      kfree(dma_dev);
++
++      dev_info(dev, "caam dma support disabled\n");
++      return 0;
++}
++
++static struct platform_driver caam_dma_driver = {
++      .driver = {
++              .name = "caam-dma",
++      },
++      .probe  = caam_dma_probe,
++      .remove = caam_dma_remove,
++};
++module_platform_driver(caam_dma_driver);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_DESCRIPTION("NXP CAAM support for DMA engine");
++MODULE_AUTHOR("NXP Semiconductors");
++MODULE_ALIAS("platform:caam-dma");
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0027-dma-caam-fix-compilation-error.patch b/target/linux/layerscape/patches-5.4/806-dma-0027-dma-caam-fix-compilation-error.patch
new file mode 100644 (file)
index 0000000..368185f
--- /dev/null
@@ -0,0 +1,30 @@
+From ced02a1fdc5d9d394bffe4427021de238a0ad697 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Horia=20Geant=C4=83?= <horia.geanta@nxp.com>
+Date: Fri, 4 Oct 2019 14:07:03 +0300
+Subject: [PATCH] dma: caam: fix compilation error
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Fix compilation error, introduced by incorrect rebase of the
+commit 9c51c141264c ("dma: caam: add dma memcpy driver"
+on top of upstream
+commit 1bcdf5a00f41 ("crypto: caam - make CAAM_PTR_SZ dynamic")
+
+Fixes: 9c51c141264c ("dma: caam: add dma memcpy driver")
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+---
+ drivers/dma/caam_dma.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/dma/caam_dma.c
++++ b/drivers/dma/caam_dma.c
+@@ -47,7 +47,7 @@
+ #include "../crypto/caam/error.h"
+ #include "../crypto/caam/desc_constr.h"
+-#define DESC_DMA_MEMCPY_LEN   ((CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN) / \
++#define DESC_DMA_MEMCPY_LEN   ((CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN_MIN) / \
+                                CAAM_CMD_SZ)
+ /*
diff --git a/target/linux/layerscape/patches-5.4/806-dma-0028-dmaengine-fsl-edma-Add-eDMA-support-for-QorIQ-LS1028.patch b/target/linux/layerscape/patches-5.4/806-dma-0028-dmaengine-fsl-edma-Add-eDMA-support-for-QorIQ-LS1028.patch
new file mode 100644 (file)
index 0000000..611f96b
--- /dev/null
@@ -0,0 +1,94 @@
+From 83d2cb1c64c5a34f23b34fcee715a68be230c232 Mon Sep 17 00:00:00 2001
+From: Peng Ma <peng.ma@nxp.com>
+Date: Thu, 12 Dec 2019 03:38:10 +0000
+Subject: [PATCH] dmaengine: fsl-edma: Add eDMA support for QorIQ LS1028A
+ platform
+
+Our platforms(such as LS1021A, LS1012A, LS1043A, LS1046A, LS1028A) with
+below registers(CHCFG0 - CHCFG15) of eDMA as follows:
+*-----------------------------------------------------------*
+|     Offset   |       OTHERS                  |               LS1028A                 |
+|--------------|--------------------|-----------------------|
+|     0x0      |        CHCFG0      |           CHCFG3      |
+|--------------|--------------------|-----------------------|
+|     0x1      |        CHCFG1      |           CHCFG2      |
+|--------------|--------------------|-----------------------|
+|     0x2      |        CHCFG2      |           CHCFG1      |
+|--------------|--------------------|-----------------------|
+|     0x3      |        CHCFG3      |           CHCFG0      |
+|--------------|--------------------|-----------------------|
+|     ...      |        ......      |           ......      |
+|--------------|--------------------|-----------------------|
+|     0xC      |        CHCFG12     |           CHCFG15     |
+|--------------|--------------------|-----------------------|
+|     0xD      |        CHCFG13     |           CHCFG14     |
+|--------------|--------------------|-----------------------|
+|     0xE      |        CHCFG14     |           CHCFG13     |
+|--------------|--------------------|-----------------------|
+|     0xF      |        CHCFG15     |           CHCFG12     |
+*-----------------------------------------------------------*
+
+This patch is to improve edma driver to fit LS1028A platform.
+
+Signed-off-by: Peng Ma <peng.ma@nxp.com>
+Reviewed-by: Robin Gong <yibin.gong@nxp.com>
+Link: https://lore.kernel.org/r/20191212033714.4090-1-peng.ma@nxp.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+---
+ drivers/dma/fsl-edma-common.c | 5 +++++
+ drivers/dma/fsl-edma-common.h | 1 +
+ drivers/dma/fsl-edma.c        | 8 ++++++++
+ 3 files changed, 14 insertions(+)
+
+--- a/drivers/dma/fsl-edma-common.c
++++ b/drivers/dma/fsl-edma-common.c
+@@ -109,10 +109,15 @@ void fsl_edma_chan_mux(struct fsl_edma_c
+       u32 ch = fsl_chan->vchan.chan.chan_id;
+       void __iomem *muxaddr;
+       unsigned int chans_per_mux, ch_off;
++      int endian_diff[4] = {3, 1, -1, -3};
+       u32 dmamux_nr = fsl_chan->edma->drvdata->dmamuxs;
+       chans_per_mux = fsl_chan->edma->n_chans / dmamux_nr;
+       ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux;
++
++      if (fsl_chan->edma->drvdata->mux_swap)
++              ch_off += endian_diff[ch_off % 4];
++
+       muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux];
+       slot = EDMAMUX_CHCFG_SOURCE(slot);
+--- a/drivers/dma/fsl-edma-common.h
++++ b/drivers/dma/fsl-edma-common.h
+@@ -148,6 +148,7 @@ struct fsl_edma_drvdata {
+       enum edma_version       version;
+       u32                     dmamuxs;
+       bool                    has_dmaclk;
++      bool                    mux_swap;
+       int                     (*setup_irq)(struct platform_device *pdev,
+                                            struct fsl_edma_engine *fsl_edma);
+ };
+--- a/drivers/dma/fsl-edma.c
++++ b/drivers/dma/fsl-edma.c
+@@ -234,6 +234,13 @@ static struct fsl_edma_drvdata vf610_dat
+       .setup_irq = fsl_edma_irq_init,
+ };
++static struct fsl_edma_drvdata ls1028a_data = {
++      .version = v1,
++      .dmamuxs = DMAMUX_NR,
++      .mux_swap = true,
++      .setup_irq = fsl_edma_irq_init,
++};
++
+ static struct fsl_edma_drvdata imx7ulp_data = {
+       .version = v3,
+       .dmamuxs = 1,
+@@ -243,6 +250,7 @@ static struct fsl_edma_drvdata imx7ulp_d
+ static const struct of_device_id fsl_edma_dt_ids[] = {
+       { .compatible = "fsl,vf610-edma", .data = &vf610_data},
++      { .compatible = "fsl,ls1028a-edma", .data = &ls1028a_data},
+       { .compatible = "fsl,imx7ulp-edma", .data = &imx7ulp_data},
+       { /* sentinel */ }
+ };
diff --git a/target/linux/layerscape/patches-5.4/807-gpio-0001-gpio-mpc8xxx-change-irq-handler-from-chained-to-norm.patch b/target/linux/layerscape/patches-5.4/807-gpio-0001-gpio-mpc8xxx-change-irq-handler-from-chained-to-norm.patch
new file mode 100644 (file)
index 0000000..01d2772
--- /dev/null
@@ -0,0 +1,80 @@
+From 8070fa91b95e20cd270c8d76bf45f2a5423358bf Mon Sep 17 00:00:00 2001
+From: Song Hui <hui.song_1@nxp.com>
+Date: Fri, 6 Sep 2019 19:42:59 +0800
+Subject: [PATCH] gpio/mpc8xxx: change irq handler from chained to normal
+
+More than one gpio controllers can share one interrupt, change the
+driver to request shared irq.
+
+While this will work, it will mess up userspace accounting of the number
+of interrupts per second in tools such as vmstat.  The reason is that
+for every GPIO interrupt, /proc/interrupts records the count against GIC
+interrupt 68 or 69, as well as the GPIO itself.  So, for every GPIO
+interrupt, the total number of interrupts that the system has seen
+increments by two.
+
+Signed-off-by: Laurentiu Tudor <Laurentiu.Tudor@nxp.com>
+Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
+Signed-off-by: Song Hui <hui.song_1@nxp.com>
+---
+ drivers/gpio/gpio-mpc8xxx.c | 30 +++++++++++++++++++-----------
+ 1 file changed, 19 insertions(+), 11 deletions(-)
+
+--- a/drivers/gpio/gpio-mpc8xxx.c
++++ b/drivers/gpio/gpio-mpc8xxx.c
+@@ -22,6 +22,7 @@
+ #include <linux/irq.h>
+ #include <linux/gpio/driver.h>
+ #include <linux/bitops.h>
++#include <linux/interrupt.h>
+ #define MPC8XXX_GPIO_PINS     32
+@@ -127,20 +128,19 @@ static int mpc8xxx_gpio_to_irq(struct gp
+               return -ENXIO;
+ }
+-static void mpc8xxx_gpio_irq_cascade(struct irq_desc *desc)
++static irqreturn_t mpc8xxx_gpio_irq_cascade(int irq, void *data)
+ {
+-      struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc);
+-      struct irq_chip *chip = irq_desc_get_chip(desc);
++      struct mpc8xxx_gpio_chip *mpc8xxx_gc = data;
+       struct gpio_chip *gc = &mpc8xxx_gc->gc;
+-      unsigned int mask;
++      unsigned long mask;
++      int i;
+       mask = gc->read_reg(mpc8xxx_gc->regs + GPIO_IER)
+               & gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR);
+-      if (mask)
+-              generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq,
+-                                                   32 - ffs(mask)));
+-      if (chip->irq_eoi)
+-              chip->irq_eoi(&desc->irq_data);
++      for_each_set_bit(i, &mask, 32)
++              generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, 31 - i));
++
++      return IRQ_HANDLED;
+ }
+ static void mpc8xxx_irq_unmask(struct irq_data *d)
+@@ -414,8 +414,16 @@ static int mpc8xxx_probe(struct platform
+       if (devtype->gpio_dir_in_init)
+               devtype->gpio_dir_in_init(gc);
+-      irq_set_chained_handler_and_data(mpc8xxx_gc->irqn,
+-                                       mpc8xxx_gpio_irq_cascade, mpc8xxx_gc);
++      ret = devm_request_irq(&pdev->dev, mpc8xxx_gc->irqn,
++                             mpc8xxx_gpio_irq_cascade,
++                             IRQF_NO_THREAD | IRQF_SHARED, "gpio-cascade",
++                             mpc8xxx_gc);
++      if (ret) {
++              dev_err(&pdev->dev, "%s: failed to devm_request_irq(%d), ret = %d\n",
++                      np->full_name, mpc8xxx_gc->irqn, ret);
++              goto err;
++      }
++
+       return 0;
+ err:
+       iounmap(mpc8xxx_gc->regs);
diff --git a/target/linux/layerscape/patches-5.4/807-gpio-0002-gpio-mpc8xxx-ls1088a-ls1028a-edge-detection-mode-bug.patch b/target/linux/layerscape/patches-5.4/807-gpio-0002-gpio-mpc8xxx-ls1088a-ls1028a-edge-detection-mode-bug.patch
new file mode 100644 (file)
index 0000000..2809a83
--- /dev/null
@@ -0,0 +1,24 @@
+From e59637a5f655b54bdca5b5a190e69758a593f1c2 Mon Sep 17 00:00:00 2001
+From: Song Hui <hui.song_1@nxp.com>
+Date: Mon, 18 Nov 2019 13:17:54 +0800
+Subject: [PATCH] gpio : mpc8xxx : ls1088a/ls1028a edge detection mode bug
+ fixs.
+
+On these boards, the irq_set_type must point one valid function pointer
+that can correctly set both edge and falling edge.
+
+Signed-off-by: Song Hui <hui.song_1@nxp.com>
+---
+ drivers/gpio/gpio-mpc8xxx.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/gpio/gpio-mpc8xxx.c
++++ b/drivers/gpio/gpio-mpc8xxx.c
+@@ -296,6 +296,7 @@ static const struct mpc8xxx_gpio_devtype
+ static const struct mpc8xxx_gpio_devtype ls1028a_gpio_devtype = {
+       .gpio_dir_in_init = ls1028a_gpio_dir_in_init,
++      .irq_set_type = mpc8xxx_irq_set_type,
+ };
+ static const struct mpc8xxx_gpio_devtype mpc5125_gpio_devtype = {
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0001-MLK-16095-01-i2c-mux-pca954x-add-i2c-bus-switch-PCA9.patch b/target/linux/layerscape/patches-5.4/808-i2c-0001-MLK-16095-01-i2c-mux-pca954x-add-i2c-bus-switch-PCA9.patch
new file mode 100644 (file)
index 0000000..26a02ce
--- /dev/null
@@ -0,0 +1,52 @@
+From 80720c83833c6009b68958fff4e1cca712808395 Mon Sep 17 00:00:00 2001
+From: Richard Zhu <hongxing.zhu@nxp.com>
+Date: Thu, 24 Jan 2019 15:07:32 +0800
+Subject: [PATCH] MLK-16095-01 i2c: mux: pca954x: add i2c bus switch PCA9646
+ chip support
+
+Add i2c bus switch PCA9646 chip support, which 2-wire bus switch
+and buffered 4-channel.
+
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+---
+ drivers/i2c/muxes/i2c-mux-pca954x.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
++++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
+@@ -64,6 +64,7 @@ enum pca_type {
+       pca_9546,
+       pca_9547,
+       pca_9548,
++      pca_9646,
+       pca_9846,
+       pca_9847,
+       pca_9848,
+@@ -145,6 +146,11 @@ static const struct chip_desc chips[] =
+               .muxtype = pca954x_isswi,
+               .id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
+       },
++      [pca_9646] = {
++              .nchans = 4,
++              .muxtype = pca954x_isswi,
++              .id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
++      },
+       [pca_9846] = {
+               .nchans = 4,
+               .muxtype = pca954x_isswi,
+@@ -190,6 +196,7 @@ static const struct i2c_device_id pca954
+       { "pca9546", pca_9546 },
+       { "pca9547", pca_9547 },
+       { "pca9548", pca_9548 },
++      { "pca9646", pca_9646 },
+       { "pca9846", pca_9846 },
+       { "pca9847", pca_9847 },
+       { "pca9848", pca_9848 },
+@@ -208,6 +215,7 @@ static const struct of_device_id pca954x
+       { .compatible = "nxp,pca9546", .data = &chips[pca_9546] },
+       { .compatible = "nxp,pca9547", .data = &chips[pca_9547] },
+       { .compatible = "nxp,pca9548", .data = &chips[pca_9548] },
++      { .compatible = "nxp,pca9646", .data = &chips[pca_9646] },
+       { .compatible = "nxp,pca9846", .data = &chips[pca_9846] },
+       { .compatible = "nxp,pca9847", .data = &chips[pca_9847] },
+       { .compatible = "nxp,pca9848", .data = &chips[pca_9848] },
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0002-MLK-10893-i2c-imx-add-irqf_no_suspend.patch b/target/linux/layerscape/patches-5.4/808-i2c-0002-MLK-10893-i2c-imx-add-irqf_no_suspend.patch
new file mode 100644 (file)
index 0000000..08f44e7
--- /dev/null
@@ -0,0 +1,29 @@
+From 0d7b6f59e736f6f7389e5346a518f2dc009bbf89 Mon Sep 17 00:00:00 2001
+From: gaopan <b54642@freescale.com>
+Date: Tue, 12 May 2015 18:25:29 +0800
+Subject: [PATCH] MLK-10893: i2c: imx: add irqf_no_suspend
+
+The i2c irq is masked when pcie starts a i2c transfer process
+during noirq suspend stage. As a result, i2c transfer fails.
+To solve the problem, IRQF_NO_SUSPEND is added to i2c bus.
+
+Signed-off-by: Gao Pan <b54642@freescale.com>
+Signed-off-by: Fugang Duan <B38611@freescale.com>
+Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
+(cherry picked from commit d21259d913effcad322e30d389323e72a0f9709d)
+---
+ drivers/i2c/busses/i2c-imx.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/i2c/busses/i2c-imx.c
++++ b/drivers/i2c/busses/i2c-imx.c
+@@ -1113,7 +1113,8 @@ static int i2c_imx_probe(struct platform
+       }
+       /* Request IRQ */
+-      ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, IRQF_SHARED,
++      ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr,
++                              IRQF_SHARED | IRQF_NO_SUSPEND,
+                               pdev->name, i2c_imx);
+       if (ret) {
+               dev_err(&pdev->dev, "can't claim irq %d\n", irq);
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0003-MLK-11403-I2C-imx-restore-pin-setting-for-i2c.patch b/target/linux/layerscape/patches-5.4/808-i2c-0003-MLK-11403-I2C-imx-restore-pin-setting-for-i2c.patch
new file mode 100644 (file)
index 0000000..0c7c644
--- /dev/null
@@ -0,0 +1,57 @@
+From b862ceba838786ac81aa6a295ad91a54aff6909d Mon Sep 17 00:00:00 2001
+From: Gao Pan <b54642@freescale.com>
+Date: Tue, 25 Aug 2015 14:00:32 +0800
+Subject: [PATCH] MLK-11403: I2C: imx: restore pin setting for i2c
+
+restore pin setting for i2c in suspend/resume
+
+Signed-off-by: Gao Pan <gaopan@freescale.com>
+(Vipul: Fixed merge conflicts)
+Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
+(cherry picked from commit 42b5aa1d72c09015d435459c6a59022255e3ef21)
+---
+ drivers/i2c/busses/i2c-imx.c | 19 +++++++++++++++++--
+ 1 file changed, 17 insertions(+), 2 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-imx.c
++++ b/drivers/i2c/busses/i2c-imx.c
+@@ -1227,7 +1227,8 @@ static int __maybe_unused i2c_imx_runtim
+ {
+       struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
+-      clk_disable(i2c_imx->clk);
++      clk_disable_unprepare(i2c_imx->clk);
++      pinctrl_pm_select_sleep_state(dev);
+       return 0;
+ }
+@@ -1237,14 +1238,28 @@ static int __maybe_unused i2c_imx_runtim
+       struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
+       int ret;
+-      ret = clk_enable(i2c_imx->clk);
++      pinctrl_pm_select_default_state(dev);
++      ret = clk_prepare_enable(i2c_imx->clk);
+       if (ret)
+               dev_err(dev, "can't enable I2C clock, ret=%d\n", ret);
+       return ret;
+ }
++static int i2c_imx_suspend(struct device *dev)
++{
++      pinctrl_pm_select_sleep_state(dev);
++      return 0;
++}
++
++static int i2c_imx_resume(struct device *dev)
++{
++      pinctrl_pm_select_default_state(dev);
++      return 0;
++}
++
+ static const struct dev_pm_ops i2c_imx_pm_ops = {
++      SET_SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend, i2c_imx_resume)
+       SET_RUNTIME_PM_OPS(i2c_imx_runtime_suspend,
+                          i2c_imx_runtime_resume, NULL)
+ };
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0004-MLK-16203-enable-runtime-pm-of-i2c-temporary-when-do.patch b/target/linux/layerscape/patches-5.4/808-i2c-0004-MLK-16203-enable-runtime-pm-of-i2c-temporary-when-do.patch
new file mode 100644 (file)
index 0000000..3157750
--- /dev/null
@@ -0,0 +1,58 @@
+From 4a76bb8458cbe93309314c58f276087569b2fc48 Mon Sep 17 00:00:00 2001
+From: Gao Pan <pandy.gao@nxp.com>
+Date: Fri, 18 Aug 2017 18:35:11 +0800
+Subject: [PATCH] MLK-16203 enable runtime pm of i2c temporary when do system
+ suspend
+
+When we do system suspend, the runtime pm will be disabled, but we need
+to control the PMIC to power on/off the regulator, if the runtime pm is
+disabled, if will failed to request runtime wakeup. So data transfer will
+failed.
+
+Signed-off-by: Bai Ping <ping.bai@nxp.com>
+Signed-off-by: Gao Pan <pandy.gao@nxp.com>
+Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
+(cherry picked from commit 93adab71408f1f162015e77715dd04ce2301d673)
+---
+ drivers/i2c/busses/i2c-imx.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/i2c/busses/i2c-imx.c
++++ b/drivers/i2c/busses/i2c-imx.c
+@@ -896,10 +896,17 @@ static int i2c_imx_xfer(struct i2c_adapt
+       unsigned int i, temp;
+       int result;
+       bool is_lastmsg = false;
++      bool enable_runtime_pm = false;
+       struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
+       dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
++
++      if (!pm_runtime_enabled(i2c_imx->adapter.dev.parent)) {
++              pm_runtime_enable(i2c_imx->adapter.dev.parent);
++              enable_runtime_pm = true;
++      }
++
+       result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
+       if (result < 0)
+               goto out;
+@@ -971,6 +978,9 @@ fail0:
+       pm_runtime_put_autosuspend(i2c_imx->adapter.dev.parent);
+ out:
++      if (enable_runtime_pm)
++              pm_runtime_disable(i2c_imx->adapter.dev.parent);
++
+       dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
+               (result < 0) ? "error" : "success msg",
+                       (result < 0) ? result : num);
+@@ -1259,7 +1269,7 @@ static int i2c_imx_resume(struct device
+ }
+ static const struct dev_pm_ops i2c_imx_pm_ops = {
+-      SET_SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend, i2c_imx_resume)
++      SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend, i2c_imx_resume)
+       SET_RUNTIME_PM_OPS(i2c_imx_runtime_suspend,
+                          i2c_imx_runtime_resume, NULL)
+ };
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0005-MLK-20773-i2c-imx-add-a-limit-of-maximum-transfer-sp.patch b/target/linux/layerscape/patches-5.4/808-i2c-0005-MLK-20773-i2c-imx-add-a-limit-of-maximum-transfer-sp.patch
new file mode 100644 (file)
index 0000000..939fb61
--- /dev/null
@@ -0,0 +1,94 @@
+From ede2da5ea630fa2431145992c43aef51fc9c5c5a Mon Sep 17 00:00:00 2001
+From: Clark Wang <xiaoning.wang@nxp.com>
+Date: Fri, 18 Jan 2019 12:00:16 +0800
+Subject: [PATCH] MLK-20773 i2c-imx: add a limit of maximum transfer speed for
+ imx7d
+
+According the e7805 in Errata, the SCK low level period should be less
+than 1.3us.
+
+The other series platform use this same IP can match the errata, and
+ensure the low level period longer than 1.3us when the speed set to
+400KHz. However, only at imx7d platform, the low level period is less
+than 1.3us in the same situation.
+
+Therefore, limit the maximum transfer speed to 384KHz when probe at
+imx7d platform.
+
+Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
+(cherry picked from commit 19f553846e872b5c379b37ed029132b79566cab0)
+(cherry picked from commit 5d355407812025e5157f82b7763580e7295a40fd)
+---
+ drivers/i2c/busses/i2c-imx.c | 26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+--- a/drivers/i2c/busses/i2c-imx.c
++++ b/drivers/i2c/busses/i2c-imx.c
+@@ -51,6 +51,7 @@
+ /* Default value */
+ #define IMX_I2C_BIT_RATE      100000  /* 100kHz */
++#define IMX_I2C_MAX_E_BIT_RATE        384000  /* 384kHz from e7805 errata*/
+ /*
+  * Enable DMA if transfer byte size is bigger than this threshold.
+@@ -161,6 +162,7 @@ enum imx_i2c_type {
+       IMX1_I2C,
+       IMX21_I2C,
+       VF610_I2C,
++      IMX7D_I2C,
+ };
+ struct imx_i2c_hwdata {
+@@ -235,6 +237,16 @@ static struct imx_i2c_hwdata vf610_i2c_h
+ };
++static const struct imx_i2c_hwdata imx7d_i2c_hwdata = {
++      .devtype                = IMX7D_I2C,
++      .regshift               = IMX_I2C_REGSHIFT,
++      .clk_div                = imx_i2c_clk_div,
++      .ndivs                  = ARRAY_SIZE(imx_i2c_clk_div),
++      .i2sr_clr_opcode        = I2SR_CLR_OPCODE_W0C,
++      .i2cr_ien_opcode        = I2CR_IEN_OPCODE_1,
++
++};
++
+ static const struct platform_device_id imx_i2c_devtype[] = {
+       {
+               .name = "imx1-i2c",
+@@ -252,6 +264,7 @@ static const struct of_device_id i2c_imx
+       { .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
+       { .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
+       { .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, },
++      { .compatible = "fsl,imx7d-i2c", .data = &imx7d_i2c_hwdata, },
+       { /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids);
+@@ -267,6 +280,11 @@ static inline int is_imx1_i2c(struct imx
+       return i2c_imx->hwdata->devtype == IMX1_I2C;
+ }
++static inline int is_imx7d_i2c(struct imx_i2c_struct *i2c_imx)
++{
++      return i2c_imx->hwdata->devtype == IMX7D_I2C;
++}
++
+ static inline void imx_i2c_write_reg(unsigned int val,
+               struct imx_i2c_struct *i2c_imx, unsigned int reg)
+ {
+@@ -1159,6 +1177,14 @@ static int i2c_imx_probe(struct platform
+       clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb);
+       i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk));
++      /*
++       * This limit caused by an i.MX7D hardware issue(e7805 in Errata).
++       * If there is no limit, when the bitrate set up to 400KHz, it will
++       * cause the SCK low level period less than 1.3us.
++       */
++      if (is_imx7d_i2c(i2c_imx) && i2c_imx->bitrate > IMX_I2C_MAX_E_BIT_RATE)
++              i2c_imx->bitrate = IMX_I2C_MAX_E_BIT_RATE;
++
+       /* Set up chip registers to defaults */
+       imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
+                       i2c_imx, IMX_I2C_I2CR);
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0006-MLK-20368-i2c-imx-Coverity-fix-divide-by-zero-warnin.patch b/target/linux/layerscape/patches-5.4/808-i2c-0006-MLK-20368-i2c-imx-Coverity-fix-divide-by-zero-warnin.patch
new file mode 100644 (file)
index 0000000..98c5c21
--- /dev/null
@@ -0,0 +1,99 @@
+From 2c2c7e16ad0401f85dd8ff9bc0789fa10e715c0e Mon Sep 17 00:00:00 2001
+From: Clark Wang <xiaoning.wang@nxp.com>
+Date: Tue, 15 Jan 2019 10:04:30 +0800
+Subject: [PATCH] MLK-20368 i2c-imx: Coverity: fix divide by zero warning
+
+"i2c_clk_rate / 2" might be zero when the i2c_clk_rate gets the clock is
+0 or 1, so add a judgment to avoid the denominator is equal to 0.
+
+Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
+[Arul: Add support to check return value everywhere in the driver]
+Signed-off-by: Arulpandiyan Vadivel <arulpandiyan_vadivel@mentor.com>
+
+Signed-off-by: Shrikant Bobade <Shrikant_Bobade@mentor.com>
+(cherry picked from commit d382de595bffc0975ab7c0582e08dd4f7afc0c1a)
+(cherry picked from commit 456caa9ba270ca8f4f962918a0625d1a8348f316)
+---
+ drivers/i2c/busses/i2c-imx.c | 31 +++++++++++++++++++++++++------
+ 1 file changed, 25 insertions(+), 6 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-imx.c
++++ b/drivers/i2c/busses/i2c-imx.c
+@@ -492,16 +492,24 @@ static int i2c_imx_acked(struct imx_i2c_
+       return 0;
+ }
+-static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
++static int i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
+                           unsigned int i2c_clk_rate)
+ {
+       struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div;
+       unsigned int div;
+       int i;
+-      /* Divider value calculation */
+       if (i2c_imx->cur_clk == i2c_clk_rate)
+-              return;
++              return 0;
++
++      /*
++       * Keep the denominator of the following program
++       * always NOT equal to 0.
++       */
++
++      /* Divider value calculation */
++      if (!(i2c_clk_rate / 2))
++              return -EINVAL;
+       i2c_imx->cur_clk = i2c_clk_rate;
+@@ -532,20 +540,23 @@ static void i2c_imx_set_clk(struct imx_i
+       dev_dbg(&i2c_imx->adapter.dev, "IFDR[IC]=0x%x, REAL DIV=%d\n",
+               i2c_clk_div[i].val, i2c_clk_div[i].div);
+ #endif
++
++      return 0;
+ }
+ static int i2c_imx_clk_notifier_call(struct notifier_block *nb,
+                                    unsigned long action, void *data)
+ {
++      int ret = 0;
+       struct clk_notifier_data *ndata = data;
+       struct imx_i2c_struct *i2c_imx = container_of(nb,
+                                                     struct imx_i2c_struct,
+                                                     clk_change_nb);
+       if (action & POST_RATE_CHANGE)
+-              i2c_imx_set_clk(i2c_imx, ndata->new_rate);
++              ret = i2c_imx_set_clk(i2c_imx, ndata->new_rate);
+-      return NOTIFY_OK;
++      return notifier_from_errno(ret);
+ }
+ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+@@ -555,6 +566,10 @@ static int i2c_imx_start(struct imx_i2c_
+       dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
++      result = i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk));
++      if (result)
++              return result;
++
+       imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
+       /* Enable I2C controller */
+       imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
+@@ -1175,7 +1190,11 @@ static int i2c_imx_probe(struct platform
+               i2c_imx->bitrate = pdata->bitrate;
+       i2c_imx->clk_change_nb.notifier_call = i2c_imx_clk_notifier_call;
+       clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb);
+-      i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk));
++      ret = i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk));
++      if (ret < 0) {
++              dev_err(&pdev->dev, "can't get I2C clock\n");
++              goto clk_notifier_unregister;
++      }
+       /*
+        * This limit caused by an i.MX7D hardware issue(e7805 in Errata).
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0007-i2c-imx-add-workaround-for-erratum-ERR010027.patch b/target/linux/layerscape/patches-5.4/808-i2c-0007-i2c-imx-add-workaround-for-erratum-ERR010027.patch
new file mode 100644 (file)
index 0000000..68b08fb
--- /dev/null
@@ -0,0 +1,34 @@
+From 8e7e594b685f3fe44cd4803e3a4634bed897c2f7 Mon Sep 17 00:00:00 2001
+From: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date: Fri, 14 Apr 2017 17:03:03 +0800
+Subject: [PATCH] i2c: imx: add workaround for erratum ERR010027
+
+ERR010027: Attempting a start cycle while the bus is busy may
+generate a short clock pulse.
+
+Software must ensure that the I2C BUS is idle by checking the
+bus busy before switching to master mode and attempting a Start
+cycle.
+
+Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+---
+ drivers/i2c/busses/i2c-imx.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/i2c/busses/i2c-imx.c
++++ b/drivers/i2c/busses/i2c-imx.c
+@@ -940,6 +940,14 @@ static int i2c_imx_xfer(struct i2c_adapt
+               enable_runtime_pm = true;
+       }
++      /*
++       * workround for ERR010027: ensure that the I2C BUS is idle
++       * before switching to master mode and attempting a Start cycle
++       */
++      result =  i2c_imx_bus_busy(i2c_imx, 0);
++      if (result)
++              goto out;
++
+       result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
+       if (result < 0)
+               goto out;
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0008-i2c-imx-implement-bus-recovery-with-gpio-for-Layersc.patch b/target/linux/layerscape/patches-5.4/808-i2c-0008-i2c-imx-implement-bus-recovery-with-gpio-for-Layersc.patch
new file mode 100644 (file)
index 0000000..dacee2a
--- /dev/null
@@ -0,0 +1,268 @@
+From ddf55be668a5e5a22d4b7729e7ba92d928983168 Mon Sep 17 00:00:00 2001
+From: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+Date: Fri, 1 Dec 2017 15:59:28 +0800
+Subject: [PATCH] i2c: imx: implement bus recovery with gpio for Layerscape
+
+Based on the I2C specification, if the data line (SDA) is stuck low,
+the master should send nine clock pulses. The I2C slave device that
+held the bus low should release it sometime within those nine clocks.
+
+Because pinctrl is not supported on Layerscape, current bus recovery
+is not avalible for Layerscape. This patch uses an open drain GPIO
+pin to connect to the IICx_SCL to drive nine clock pulses to unlock
+the I2C bus.
+
+Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
+---
+ drivers/i2c/busses/i2c-imx.c | 190 ++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 188 insertions(+), 2 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-imx.c
++++ b/drivers/i2c/busses/i2c-imx.c
+@@ -39,12 +39,18 @@
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+ #include <linux/of_dma.h>
++#include <linux/of_gpio.h>
+ #include <linux/pinctrl/consumer.h>
+ #include <linux/platform_data/i2c-imx.h>
+ #include <linux/platform_device.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/sched.h>
+ #include <linux/slab.h>
++#include <linux/gpio.h>
++#include <linux/of_address.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/libata.h>
+ /* This will be the driver name the kernel reports */
+ #define DRIVER_NAME "imx-i2c"
+@@ -110,6 +116,54 @@
+ #define I2C_PM_TIMEOUT                10 /* ms */
++enum pinmux_endian_type {
++      BIG_ENDIAN,
++      LITTLE_ENDIAN,
++};
++
++struct pinmux_cfg {
++      enum pinmux_endian_type endian; /* endian of RCWPMUXCR0 */
++      u32 pmuxcr_offset;
++      u32 pmuxcr_set_bit;                 /* pin mux of RCWPMUXCR0 */
++};
++
++static struct pinmux_cfg ls1012a_pinmux_cfg = {
++      .endian = BIG_ENDIAN,
++      .pmuxcr_offset = 0x430,
++      .pmuxcr_set_bit = 0x10,
++};
++
++static struct pinmux_cfg ls1043a_pinmux_cfg = {
++      .endian = BIG_ENDIAN,
++      .pmuxcr_offset = 0x40C,
++      .pmuxcr_set_bit = 0x10,
++};
++
++static struct pinmux_cfg ls1046a_pinmux_cfg = {
++      .endian = BIG_ENDIAN,
++      .pmuxcr_offset = 0x40C,
++      .pmuxcr_set_bit = 0x80000000,
++};
++
++static const struct of_device_id pinmux_of_match[] = {
++      { .compatible = "fsl,ls1012a-vf610-i2c", .data = &ls1012a_pinmux_cfg},
++      { .compatible = "fsl,ls1043a-vf610-i2c", .data = &ls1043a_pinmux_cfg},
++      { .compatible = "fsl,ls1046a-vf610-i2c", .data = &ls1046a_pinmux_cfg},
++      {},
++};
++MODULE_DEVICE_TABLE(of, pinmux_of_match);
++
++/* The SCFG, Supplemental Configuration Unit, provides SoC specific
++ * configuration and status registers for the device. There is a
++ * SDHC IO VSEL control register on SCFG for some platforms. It's
++ * used to support SDHC IO voltage switching.
++ */
++static const struct of_device_id scfg_device_ids[] = {
++      { .compatible = "fsl,ls1012a-scfg", },
++      { .compatible = "fsl,ls1043a-scfg", },
++      { .compatible = "fsl,ls1046a-scfg", },
++      {}
++};
+ /*
+  * sorted list of clock divider, register value pairs
+  * taken from table 26-5, p.26-9, Freescale i.MX
+@@ -205,6 +259,12 @@ struct imx_i2c_struct {
+       struct pinctrl_state *pinctrl_pins_gpio;
+       struct imx_i2c_dma      *dma;
++      int                     layerscape_bus_recover;
++      int                     gpio;
++      int                     need_set_pmuxcr;
++      int                     pmuxcr_set;
++      int                     pmuxcr_endian;
++      void __iomem            *pmuxcr_addr;
+ };
+ static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
+@@ -923,6 +983,78 @@ static int i2c_imx_read(struct imx_i2c_s
+       return 0;
+ }
++/*
++ * Based on the I2C specification, if the data line (SDA) is
++ * stuck low, the master should send nine  * clock pulses.
++ * The I2C slave device that held the bus low should release it
++ * sometime within  * those nine clocks. Due to this erratum,
++ * the I2C controller cannot generate nine clock pulses.
++ */
++static int i2c_imx_recovery_for_layerscape(struct imx_i2c_struct *i2c_imx)
++{
++      u32 pmuxcr = 0;
++      int ret;
++      unsigned int i, temp;
++
++      /* configure IICx_SCL/GPIO pin as a GPIO */
++      if (i2c_imx->need_set_pmuxcr == 1) {
++              pmuxcr = ioread32be(i2c_imx->pmuxcr_addr);
++              if (i2c_imx->pmuxcr_endian == BIG_ENDIAN)
++                      iowrite32be(i2c_imx->pmuxcr_set|pmuxcr,
++                                  i2c_imx->pmuxcr_addr);
++              else
++                      iowrite32(i2c_imx->pmuxcr_set|pmuxcr,
++                                i2c_imx->pmuxcr_addr);
++      }
++
++      ret = gpio_request(i2c_imx->gpio, i2c_imx->adapter.name);
++      if (ret) {
++              dev_err(&i2c_imx->adapter.dev,
++                      "can't get gpio: %d\n", ret);
++              return ret;
++      }
++
++      /* Configure GPIO pin as an output and open drain. */
++      gpio_direction_output(i2c_imx->gpio, 1);
++      udelay(10);
++
++      /* Write data to generate 9 pulses */
++      for (i = 0; i < 9; i++) {
++              gpio_set_value(i2c_imx->gpio, 1);
++              udelay(10);
++              gpio_set_value(i2c_imx->gpio, 0);
++              udelay(10);
++      }
++      /* ensure that the last level sent is always high */
++      gpio_set_value(i2c_imx->gpio, 1);
++
++      /*
++       * Set I2Cx_IBCR = 0h00 to generate a STOP and then
++       * set I2Cx_IBCR = 0h80 to reset
++       */
++      temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
++      temp &= ~(I2CR_MSTA | I2CR_MTX);
++      imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
++
++      /* Restore the saved value of the register SCFG_RCWPMUXCR0 */
++      if (i2c_imx->need_set_pmuxcr == 1) {
++              if (i2c_imx->pmuxcr_endian == BIG_ENDIAN)
++                      iowrite32be(pmuxcr, i2c_imx->pmuxcr_addr);
++              else
++                      iowrite32(pmuxcr, i2c_imx->pmuxcr_addr);
++      }
++      /*
++       * Set I2C_IBSR[IBAL] to clear the IBAL bit if-
++       * I2C_IBSR[IBAL] = 1
++       */
++      temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
++      if (temp & I2SR_IAL) {
++              temp &= ~I2SR_IAL;
++              imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
++      }
++      return 0;
++}
++
+ static int i2c_imx_xfer(struct i2c_adapter *adapter,
+                                               struct i2c_msg *msgs, int num)
+ {
+@@ -945,8 +1077,13 @@ static int i2c_imx_xfer(struct i2c_adapt
+        * before switching to master mode and attempting a Start cycle
+        */
+       result =  i2c_imx_bus_busy(i2c_imx, 0);
+-      if (result)
+-              goto out;
++      if (result) {
++              /* timeout */
++              if ((result == -ETIMEDOUT) && (i2c_imx->layerscape_bus_recover == 1))
++                      i2c_imx_recovery_for_layerscape(i2c_imx);
++              else
++                      goto out;
++      }
+       result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
+       if (result < 0)
+@@ -1093,6 +1230,50 @@ static int i2c_imx_init_recovery_info(st
+       return 0;
+ }
++/*
++ * switch SCL and SDA to their GPIO function and do some bitbanging
++ * for bus recovery.
++ * There are platforms such as Layerscape that don't support pinctrl, so add
++ * workaround for layerscape, it has no effect for other platforms.
++ */
++static int i2c_imx_init_recovery_for_layerscape(
++              struct imx_i2c_struct *i2c_imx,
++              struct platform_device *pdev)
++{
++      const struct of_device_id *of_id;
++      struct device_node *np          = pdev->dev.of_node;
++      struct pinmux_cfg               *pinmux_cfg;
++      struct device_node *scfg_node;
++      void __iomem *scfg_base = NULL;
++
++      i2c_imx->gpio = of_get_named_gpio(np, "scl-gpios", 0);
++      if (!gpio_is_valid(i2c_imx->gpio)) {
++              dev_info(&pdev->dev, "scl-gpios not found\n");
++              return 0;
++      }
++      pinmux_cfg = devm_kzalloc(&pdev->dev, sizeof(*pinmux_cfg), GFP_KERNEL);
++      if (!pinmux_cfg)
++              return -ENOMEM;
++
++      i2c_imx->need_set_pmuxcr = 0;
++      of_id = of_match_node(pinmux_of_match, np);
++      if (of_id) {
++              pinmux_cfg = (struct pinmux_cfg *)of_id->data;
++              i2c_imx->pmuxcr_endian = pinmux_cfg->endian;
++              i2c_imx->pmuxcr_set = pinmux_cfg->pmuxcr_set_bit;
++              scfg_node = of_find_matching_node(NULL, scfg_device_ids);
++              if (scfg_node) {
++                      scfg_base = of_iomap(scfg_node, 0);
++                      if (scfg_base) {
++                              i2c_imx->pmuxcr_addr = scfg_base + pinmux_cfg->pmuxcr_offset;
++                              i2c_imx->need_set_pmuxcr = 1;
++                      }
++              }
++      }
++      i2c_imx->layerscape_bus_recover = 1;
++      return 0;
++}
++
+ static u32 i2c_imx_func(struct i2c_adapter *adapter)
+ {
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
+@@ -1217,8 +1398,13 @@ static int i2c_imx_probe(struct platform
+                       i2c_imx, IMX_I2C_I2CR);
+       imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
++#ifdef CONFIG_ARCH_LAYERSCAPE
++      /* Init optional bus recovery for layerscape */
++      ret = i2c_imx_init_recovery_for_layerscape(i2c_imx, pdev);
++#else
+       /* Init optional bus recovery function */
+       ret = i2c_imx_init_recovery_info(i2c_imx, pdev);
++#endif
+       /* Give it another chance if pinctrl used is not ready yet */
+       if (ret == -EPROBE_DEFER)
+               goto clk_notifier_unregister;
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0009-i2c-imx-get-rid-of-CONFIG_ARCH_LAYERSCAPE.patch b/target/linux/layerscape/patches-5.4/808-i2c-0009-i2c-imx-get-rid-of-CONFIG_ARCH_LAYERSCAPE.patch
new file mode 100644 (file)
index 0000000..1bcc6e0
--- /dev/null
@@ -0,0 +1,36 @@
+From c35124bc3fc5f9f2a79815721db139e5bf186391 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Thu, 26 Sep 2019 21:00:55 +0800
+Subject: [PATCH] i2c: imx: get rid of CONFIG_ARCH_LAYERSCAPE
+
+We can't use CONFIG_ARCH_LAYERSCAPE for one Image multiple platforms
+support.
+
+Reviewed-by: Biwen Li <biwen.li@nxp.com>
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ drivers/i2c/busses/i2c-imx.c | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-imx.c
++++ b/drivers/i2c/busses/i2c-imx.c
+@@ -1398,13 +1398,12 @@ static int i2c_imx_probe(struct platform
+                       i2c_imx, IMX_I2C_I2CR);
+       imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
+-#ifdef CONFIG_ARCH_LAYERSCAPE
+-      /* Init optional bus recovery for layerscape */
+-      ret = i2c_imx_init_recovery_for_layerscape(i2c_imx, pdev);
+-#else
+-      /* Init optional bus recovery function */
+-      ret = i2c_imx_init_recovery_info(i2c_imx, pdev);
+-#endif
++      /* Init optional bus recovery */
++      if (of_match_node(pinmux_of_match, pdev->dev.of_node))
++              ret = i2c_imx_init_recovery_for_layerscape(i2c_imx, pdev);
++      else
++              ret = i2c_imx_init_recovery_info(i2c_imx, pdev);
++
+       /* Give it another chance if pinctrl used is not ready yet */
+       if (ret == -EPROBE_DEFER)
+               goto clk_notifier_unregister;
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0010-i2c-imx-fix-system-hang-due-to-access-i2c-registers-.patch b/target/linux/layerscape/patches-5.4/808-i2c-0010-i2c-imx-fix-system-hang-due-to-access-i2c-registers-.patch
new file mode 100644 (file)
index 0000000..0d80b9e
--- /dev/null
@@ -0,0 +1,52 @@
+From 97db2ca4485dc7b10b8382832befe607ade59a6b Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <aisheng.dong@nxp.com>
+Date: Sat, 26 Jan 2019 17:51:59 +0800
+Subject: [PATCH] i2c: imx: fix system hang due to access i2c registers without
+ clock
+
+Currently, i2c_imx_bus_busy in i2c_imx_xfer is called before
+pm_runtime_get which means the clocks are still not enabled.
+This will cause a hang on IMX as IMX requires accessing registers
+with clocks.
+
+So let's change the order to ensure the clocks are enabled before
+accessing registers. This is also a more safe way to access registers,
+suppose shouldn't affect other platforms.
+
+Fixes: 4a6ebf1c125c ("i2c: imx: add workaround for erratum ERR010027")
+Reviewed-by: Biwen Li <biwen.li@nxp.com>
+Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
+---
+ drivers/i2c/busses/i2c-imx.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-imx.c
++++ b/drivers/i2c/busses/i2c-imx.c
+@@ -1066,12 +1066,15 @@ static int i2c_imx_xfer(struct i2c_adapt
+       dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+-
+       if (!pm_runtime_enabled(i2c_imx->adapter.dev.parent)) {
+               pm_runtime_enable(i2c_imx->adapter.dev.parent);
+               enable_runtime_pm = true;
+       }
++      result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
++      if (result < 0)
++              goto out;
++
+       /*
+        * workround for ERR010027: ensure that the I2C BUS is idle
+        * before switching to master mode and attempting a Start cycle
+@@ -1085,10 +1088,6 @@ static int i2c_imx_xfer(struct i2c_adapt
+                       goto out;
+       }
+-      result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
+-      if (result < 0)
+-              goto out;
+-
+       /* Start I2C transfer */
+       result = i2c_imx_start(i2c_imx);
+       if (result) {
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0011-i2c-imx-support-slave-mode-for-imx-I2C-driver.patch b/target/linux/layerscape/patches-5.4/808-i2c-0011-i2c-imx-support-slave-mode-for-imx-I2C-driver.patch
new file mode 100644 (file)
index 0000000..246a260
--- /dev/null
@@ -0,0 +1,284 @@
+From 865433df5d11aef7cfe5d51b362b6276bddb7a15 Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Fri, 2 Aug 2019 17:45:56 +0800
+Subject: [PATCH] i2c: imx: support slave mode for imx I2C driver
+
+The patch supports slave mode for imx I2C driver
+
+Reviewed-by: Clark Wang <xiaoning.wang@nxp.com>
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+---
+ drivers/i2c/busses/i2c-imx.c | 219 +++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 201 insertions(+), 18 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-imx.c
++++ b/drivers/i2c/busses/i2c-imx.c
+@@ -265,6 +265,9 @@ struct imx_i2c_struct {
+       int                     pmuxcr_set;
+       int                     pmuxcr_endian;
+       void __iomem            *pmuxcr_addr;
++#if IS_ENABLED(CONFIG_I2C_SLAVE)
++      struct i2c_client       *slave;
++#endif
+ };
+ static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
+@@ -357,6 +360,14 @@ static inline unsigned char imx_i2c_read
+       return readb(i2c_imx->base + (reg << i2c_imx->hwdata->regshift));
+ }
++/* Set up i2c controller register and i2c status register to default value. */
++static void i2c_imx_reset_regs(struct imx_i2c_struct *i2c_imx)
++{
++      imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
++                      i2c_imx, IMX_I2C_I2CR);
++      imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
++}
++
+ /* Functions for DMA support */
+ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
+                                               dma_addr_t phy_addr)
+@@ -681,23 +692,33 @@ static void i2c_imx_stop(struct imx_i2c_
+       imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ }
+-static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
++/* Clear interrupt flag bit */
++static void i2c_imx_clr_if_bit(unsigned int status, struct imx_i2c_struct *i2c_imx)
+ {
+-      struct imx_i2c_struct *i2c_imx = dev_id;
+-      unsigned int temp;
++      status &= ~I2SR_IIF;
++      status |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IIF);
++      imx_i2c_write_reg(status, i2c_imx, IMX_I2C_I2SR);
++}
+-      temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
+-      if (temp & I2SR_IIF) {
+-              /* save status register */
+-              i2c_imx->i2csr = temp;
+-              temp &= ~I2SR_IIF;
+-              temp |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IIF);
+-              imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
+-              wake_up(&i2c_imx->queue);
+-              return IRQ_HANDLED;
+-      }
++/* Clear arbitration lost bit */
++static void i2c_imx_clr_al_bit(unsigned int status, struct imx_i2c_struct *i2c_imx)
++{
++      status &= ~I2SR_IAL;
++      status |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IAL);
++      imx_i2c_write_reg(status, i2c_imx, IMX_I2C_I2SR);
++}
+-      return IRQ_NONE;
++static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx)
++{
++      unsigned int status;
++
++      /* Save status register */
++      status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
++      i2c_imx->i2csr = status | I2SR_IIF;
++
++      wake_up(&i2c_imx->queue);
++
++      return IRQ_HANDLED;
+ }
+ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
+@@ -1066,6 +1087,13 @@ static int i2c_imx_xfer(struct i2c_adapt
+       dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
++#if IS_ENABLED(CONFIG_I2C_SLAVE)
++      if (i2c_imx->slave) {
++              dev_err(&i2c_imx->adapter.dev, "Please not do operations of master mode in slave mode");
++              return -EBUSY;
++      }
++#endif
++
+       if (!pm_runtime_enabled(i2c_imx->adapter.dev.parent)) {
+               pm_runtime_enable(i2c_imx->adapter.dev.parent);
+               enable_runtime_pm = true;
+@@ -1279,11 +1307,169 @@ static u32 i2c_imx_func(struct i2c_adapt
+               | I2C_FUNC_SMBUS_READ_BLOCK_DATA;
+ }
++#if IS_ENABLED(CONFIG_I2C_SLAVE)
++static int i2c_imx_slave_init(struct imx_i2c_struct *i2c_imx)
++{
++      int temp;
++
++      /* Resume */
++      temp = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
++      if (temp < 0) {
++              dev_err(&i2c_imx->adapter.dev, "failed to resume i2c controller");
++              return temp;
++      }
++
++      /* Set slave addr. */
++      imx_i2c_write_reg((i2c_imx->slave->addr << 1), i2c_imx, IMX_I2C_IADR);
++
++      i2c_imx_reset_regs(i2c_imx);
++
++      /* Enable module */
++      temp = i2c_imx->hwdata->i2cr_ien_opcode;
++      imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
++
++      /* Enable interrupt from i2c module */
++      temp |= I2CR_IIEN;
++      imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
++
++      /* Wait controller to be stable */
++      usleep_range(50, 150);
++      return 0;
++}
++
++static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx)
++{
++      unsigned int status, ctl;
++      u8 value;
++
++      if (!i2c_imx->slave) {
++              dev_err(&i2c_imx->adapter.dev, "cannot deal with slave irq,i2c_imx->slave is null");
++              return IRQ_NONE;
++      }
++
++      status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
++      ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
++      if (status & I2SR_IAL) { /* Arbitration lost */
++              i2c_imx_clr_al_bit(status, i2c_imx);
++      } else if (status & I2SR_IAAS) { /* Addressed as a slave */
++              if (status & I2SR_SRW) { /* Master wants to read from us*/
++                      dev_dbg(&i2c_imx->adapter.dev, "read requested");
++                      i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_REQUESTED, &value);
++
++                      /* Slave transmit */
++                      ctl |= I2CR_MTX;
++                      imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
++
++                      /* Send data */
++                      imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR);
++              } else { /* Master wants to write to us */
++                      dev_dbg(&i2c_imx->adapter.dev, "write requested");
++                      i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
++
++                      /* Slave receive */
++                      ctl &= ~I2CR_MTX;
++                      imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
++                      /* Dummy read */
++                      imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
++              }
++      } else if (!(ctl & I2CR_MTX)) { /* Receive mode */
++                      if (status & I2SR_IBB) { /* No STOP signal detected */
++                              ctl &= ~I2CR_MTX;
++                              imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
++
++                              value = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
++                              i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
++                      } else { /* STOP signal is detected */
++                              dev_dbg(&i2c_imx->adapter.dev,
++                                      "STOP signal detected");
++                              i2c_slave_event(i2c_imx->slave, I2C_SLAVE_STOP, &value);
++                      }
++      } else if (!(status & I2SR_RXAK)) {     /* Transmit mode received ACK */
++              ctl |= I2CR_MTX;
++              imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
++
++              i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_PROCESSED, &value);
++
++              imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR);
++      } else { /* Transmit mode received NAK */
++              ctl &= ~I2CR_MTX;
++              imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
++              imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
++      }
++      return IRQ_HANDLED;
++}
++
++static int i2c_imx_reg_slave(struct i2c_client *client)
++{
++      struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter);
++      int ret;
++      if (i2c_imx->slave)
++              return -EBUSY;
++
++      i2c_imx->slave = client;
++
++      ret = i2c_imx_slave_init(i2c_imx);
++      if (ret < 0)
++              dev_err(&i2c_imx->adapter.dev, "failed to switch to slave mode");
++
++      return ret;
++}
++
++static int i2c_imx_unreg_slave(struct i2c_client *client)
++{
++      struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter);
++      int ret;
++
++      if (!i2c_imx->slave)
++              return -EINVAL;
++
++      /* Reset slave address. */
++      imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
++
++      i2c_imx_reset_regs(i2c_imx);
++
++      i2c_imx->slave = NULL;
++
++      /* Suspend */
++      ret = pm_runtime_put_sync(i2c_imx->adapter.dev.parent);
++      if (ret < 0)
++              dev_err(&i2c_imx->adapter.dev, "failed to suspend i2c controller");
++
++      return ret;
++}
++#endif
++
+ static const struct i2c_algorithm i2c_imx_algo = {
+       .master_xfer    = i2c_imx_xfer,
+       .functionality  = i2c_imx_func,
++#if IS_ENABLED(CONFIG_I2C_SLAVE)
++      .reg_slave      = i2c_imx_reg_slave,
++      .unreg_slave    = i2c_imx_unreg_slave,
++#endif
+ };
++static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
++{
++      struct imx_i2c_struct *i2c_imx = dev_id;
++      unsigned int status, ctl;
++      irqreturn_t irq_status = IRQ_NONE;
++
++      status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
++      ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
++
++      if (status & I2SR_IIF) {
++              i2c_imx_clr_if_bit(status, i2c_imx);
++              if (ctl & I2CR_MSTA)
++                      irq_status = i2c_imx_master_isr(i2c_imx);
++#if IS_ENABLED(CONFIG_I2C_SLAVE)
++              else
++                      irq_status = i2c_imx_slave_isr(i2c_imx);
++#endif
++      }
++
++      return irq_status;
++}
++
+ static int i2c_imx_probe(struct platform_device *pdev)
+ {
+       struct imx_i2c_struct *i2c_imx;
+@@ -1392,10 +1578,7 @@ static int i2c_imx_probe(struct platform
+       if (is_imx7d_i2c(i2c_imx) && i2c_imx->bitrate > IMX_I2C_MAX_E_BIT_RATE)
+               i2c_imx->bitrate = IMX_I2C_MAX_E_BIT_RATE;
+-      /* Set up chip registers to defaults */
+-      imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
+-                      i2c_imx, IMX_I2C_I2CR);
+-      imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
++      i2c_imx_reset_regs(i2c_imx);
+       /* Init optional bus recovery */
+       if (of_match_node(pinmux_of_match, pdev->dev.of_node))
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0012-i2c-imx-correct-code-of-errata-A-010650-for-layersca.patch b/target/linux/layerscape/patches-5.4/808-i2c-0012-i2c-imx-correct-code-of-errata-A-010650-for-layersca.patch
new file mode 100644 (file)
index 0000000..fe6d6d3
--- /dev/null
@@ -0,0 +1,93 @@
+From 27ea8554c8fdcdf1d7aba5ce47630d878ce96691 Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Thu, 24 Oct 2019 13:14:44 +0800
+Subject: [PATCH] i2c: imx: correct code of errata A-010650 for layerscape
+ platform
+
+- Simplify code with helper function i2c_imx_clr_al_bit
+- Fix an error about clearing arbitration lost bit
+- Fix an error that not set I2Cx_IBCR following by
+  the workaround of A-010650 (in step 5)
+
+Reviewed-by: Clark Wang <xiaoning.wang@nxp.com>
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+---
+ drivers/i2c/busses/i2c-imx.c | 38 +++++++++++++++++++-------------------
+ 1 file changed, 19 insertions(+), 19 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-imx.c
++++ b/drivers/i2c/busses/i2c-imx.c
+@@ -503,6 +503,14 @@ static void i2c_imx_dma_free(struct imx_
+       dma->chan_using = NULL;
+ }
++/* Clear arbitration lost bit */
++static void i2c_imx_clr_al_bit(unsigned int status, struct imx_i2c_struct *i2c_imx)
++{
++      status &= ~I2SR_IAL;
++      status |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IAL);
++      imx_i2c_write_reg(status, i2c_imx, IMX_I2C_I2SR);
++}
++
+ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
+ {
+       unsigned long orig_jiffies = jiffies;
+@@ -515,8 +523,7 @@ static int i2c_imx_bus_busy(struct imx_i
+               /* check for arbitration lost */
+               if (temp & I2SR_IAL) {
+-                      temp &= ~I2SR_IAL;
+-                      imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
++                      i2c_imx_clr_al_bit(temp, i2c_imx);
+                       return -EAGAIN;
+               }
+@@ -700,14 +707,6 @@ static void i2c_imx_clr_if_bit(unsigned
+       imx_i2c_write_reg(status, i2c_imx, IMX_I2C_I2SR);
+ }
+-/* Clear arbitration lost bit */
+-static void i2c_imx_clr_al_bit(unsigned int status, struct imx_i2c_struct *i2c_imx)
+-{
+-      status &= ~I2SR_IAL;
+-      status |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IAL);
+-      imx_i2c_write_reg(status, i2c_imx, IMX_I2C_I2SR);
+-}
+-
+ static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx)
+ {
+       unsigned int status;
+@@ -1050,12 +1049,14 @@ static int i2c_imx_recovery_for_layersca
+       gpio_set_value(i2c_imx->gpio, 1);
+       /*
+-       * Set I2Cx_IBCR = 0h00 to generate a STOP and then
+-       * set I2Cx_IBCR = 0h80 to reset
++       * Set I2Cx_IBCR = 0h00 to generate a STOP
+        */
+-      temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+-      temp &= ~(I2CR_MSTA | I2CR_MTX);
+-      imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
++      imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, IMX_I2C_I2CR);
++
++      /*
++       * Set I2Cx_IBCR = 0h80 to reset the I2Cx controller
++       */
++      imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode | I2CR_IEN, i2c_imx, IMX_I2C_I2CR);
+       /* Restore the saved value of the register SCFG_RCWPMUXCR0 */
+       if (i2c_imx->need_set_pmuxcr == 1) {
+@@ -1069,10 +1070,9 @@ static int i2c_imx_recovery_for_layersca
+        * I2C_IBSR[IBAL] = 1
+        */
+       temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
+-      if (temp & I2SR_IAL) {
+-              temp &= ~I2SR_IAL;
+-              imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
+-      }
++      if (temp & I2SR_IAL)
++              i2c_imx_clr_al_bit(temp, i2c_imx);
++
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0013-LF-98-i2c-imx-fix-the-judgement-of-slave-mode-in-isr.patch b/target/linux/layerscape/patches-5.4/808-i2c-0013-LF-98-i2c-imx-fix-the-judgement-of-slave-mode-in-isr.patch
new file mode 100644 (file)
index 0000000..45f7fa3
--- /dev/null
@@ -0,0 +1,46 @@
+From 85048a8a0df324df94f9585c1e01d0a4419de4dc Mon Sep 17 00:00:00 2001
+From: Clark Wang <xiaoning.wang@nxp.com>
+Date: Wed, 27 Nov 2019 14:23:55 +0800
+Subject: [PATCH] LF-98 i2c: imx: fix the judgement of slave mode in isr
+
+The I2CR[MSTA] will be modified by software or hardware even in master
+mode. The judgment of slave mode by reading CR register is unreliable.
+Change to use i2c_imx->slave registered status to judge i2c mode.
+
+Acked-by: Fugang Duan <fugang.duan@nxp.com>
+Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
+---
+ drivers/i2c/busses/i2c-imx.c | 13 +++++--------
+ 1 file changed, 5 insertions(+), 8 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-imx.c
++++ b/drivers/i2c/busses/i2c-imx.c
+@@ -1451,23 +1451,20 @@ static const struct i2c_algorithm i2c_im
+ static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
+ {
+       struct imx_i2c_struct *i2c_imx = dev_id;
+-      unsigned int status, ctl;
+-      irqreturn_t irq_status = IRQ_NONE;
++      unsigned int status;
+       status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
+-      ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+       if (status & I2SR_IIF) {
+               i2c_imx_clr_if_bit(status, i2c_imx);
+-              if (ctl & I2CR_MSTA)
+-                      irq_status = i2c_imx_master_isr(i2c_imx);
+ #if IS_ENABLED(CONFIG_I2C_SLAVE)
+-              else
+-                      irq_status = i2c_imx_slave_isr(i2c_imx);
++              if (i2c_imx->slave)
++                      return i2c_imx_slave_isr(i2c_imx);
+ #endif
++              return i2c_imx_master_isr(i2c_imx);
+       }
+-      return irq_status;
++      return IRQ_NONE;
+ }
+ static int i2c_imx_probe(struct platform_device *pdev)
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0014-i2c-mux-pca954x-support-property-idle-state.patch b/target/linux/layerscape/patches-5.4/808-i2c-0014-i2c-mux-pca954x-support-property-idle-state.patch
new file mode 100644 (file)
index 0000000..4263717
--- /dev/null
@@ -0,0 +1,165 @@
+From 5b51284db77e6383ff438b1dd21ee83bb6eaa895 Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Tue, 22 Oct 2019 12:11:51 +0800
+Subject: [PATCH] i2c: mux: pca954x: support property idle-state
+
+This supports property idle-state,if present,
+overrides i2c-mux-idle-disconnect.
+
+My use cases:
+       - Use the property idle-state to fix
+         an errata on LS2085ARDB and LS2088ARDB.
+       - Errata id: E-00013(board LS2085ARDB and
+         LS2088ARDB revision on Rev.B, Rev.C and Rev.D).
+       - About E-00013:
+         - Description: I2C1 and I2C3 buses
+           are missing pull-up.
+         - Impact: When the PCA954x device is tri-stated, the I2C bus
+           will float. This makes the I2C bus and its associated
+           downstream devices inaccessible.
+         - Hardware fix: Populate resistors R189 and R190 for I2C1
+           and resistors R228 and R229 for I2C3.
+         - Software fix: Remove the tri-state option from the PCA954x
+           driver(PCA954x always on enable status, specify a
+           channel zero in dts to fix the errata E-00013).
+
+Tested-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+---
+ drivers/i2c/muxes/i2c-mux-pca954x.c | 69 ++++++++++++++++++++++++-------------
+ 1 file changed, 46 insertions(+), 23 deletions(-)
+
+--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
++++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
+@@ -87,7 +87,7 @@ struct pca954x {
+       u8 last_chan;           /* last register value */
+       /* MUX_IDLE_AS_IS, MUX_IDLE_DISCONNECT or >= 0 for channel */
+-      s8 idle_state;
++      s32 idle_state;
+       struct i2c_client *client;
+@@ -237,20 +237,23 @@ static int pca954x_reg_write(struct i2c_
+                               I2C_SMBUS_BYTE, &dummy);
+ }
++static u8 pca954x_regval(struct pca954x *data, u8 chan)
++{
++      /* We make switches look like muxes, not sure how to be smarter. */
++      if (data->chip->muxtype == pca954x_ismux)
++              return chan | data->chip->enable;
++      else
++              return 1 << chan;
++}
++
+ static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
+ {
+       struct pca954x *data = i2c_mux_priv(muxc);
+       struct i2c_client *client = data->client;
+-      const struct chip_desc *chip = data->chip;
+       u8 regval;
+       int ret = 0;
+-      /* we make switches look like muxes, not sure how to be smarter */
+-      if (chip->muxtype == pca954x_ismux)
+-              regval = chan | chip->enable;
+-      else
+-              regval = 1 << chan;
+-
++      regval = pca954x_regval(data, chan);
+       /* Only select the channel if its different from the last channel */
+       if (data->last_chan != regval) {
+               ret = pca954x_reg_write(muxc->parent, client, regval);
+@@ -264,7 +267,7 @@ static int pca954x_deselect_mux(struct i
+ {
+       struct pca954x *data = i2c_mux_priv(muxc);
+       struct i2c_client *client = data->client;
+-      s8 idle_state;
++      s32 idle_state;
+       idle_state = READ_ONCE(data->idle_state);
+       if (idle_state >= 0)
+@@ -410,6 +413,22 @@ static void pca954x_cleanup(struct i2c_m
+       i2c_mux_del_adapters(muxc);
+ }
++static int pca954x_init(struct i2c_client *client, struct pca954x *data)
++{
++      int ret;
++      if (data->idle_state >= 0) {
++              data->last_chan = pca954x_regval(data, data->idle_state);
++      } else {
++              /* Disconnect multiplexer */
++              data->last_chan = 0;
++      }
++      ret = i2c_smbus_write_byte(client, data->last_chan);
++      if (ret < 0)
++              data->last_chan = 0;
++
++      return ret;
++}
++
+ /*
+  * I2C init/probing/exit functions
+  */
+@@ -419,7 +438,6 @@ static int pca954x_probe(struct i2c_clie
+       struct i2c_adapter *adap = client->adapter;
+       struct device *dev = &client->dev;
+       struct device_node *np = dev->of_node;
+-      bool idle_disconnect_dt;
+       struct gpio_desc *gpio;
+       struct i2c_mux_core *muxc;
+       struct pca954x *data;
+@@ -470,23 +488,24 @@ static int pca954x_probe(struct i2c_clie
+               }
+       }
+-      /* Write the mux register at addr to verify
++      data->idle_state = MUX_IDLE_AS_IS;
++      if (of_property_read_u32(np, "idle-state", &data->idle_state)) {
++              if (np && of_property_read_bool(np, "i2c-mux-idle-disconnect"))
++                      data->idle_state = MUX_IDLE_DISCONNECT;
++      }
++
++      /*
++       * Write the mux register at addr to verify
+        * that the mux is in fact present. This also
+-       * initializes the mux to disconnected state.
++       * initializes the mux to a channel
++       * or disconnected state.
+        */
+-      if (i2c_smbus_write_byte(client, 0) < 0) {
++      ret = pca954x_init(client, data);
++      if (ret < 0) {
+               dev_warn(dev, "probe failed\n");
+               return -ENODEV;
+       }
+-      data->last_chan = 0;               /* force the first selection */
+-      data->idle_state = MUX_IDLE_AS_IS;
+-
+-      idle_disconnect_dt = np &&
+-              of_property_read_bool(np, "i2c-mux-idle-disconnect");
+-      if (idle_disconnect_dt)
+-              data->idle_state = MUX_IDLE_DISCONNECT;
+-
+       ret = pca954x_irq_setup(muxc);
+       if (ret)
+               goto fail_cleanup;
+@@ -538,9 +557,13 @@ static int pca954x_resume(struct device
+       struct i2c_client *client = to_i2c_client(dev);
+       struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+       struct pca954x *data = i2c_mux_priv(muxc);
++      int ret;
+-      data->last_chan = 0;
+-      return i2c_smbus_write_byte(client, 0);
++      ret = pca954x_init(client, data);
++      if (ret < 0)
++              dev_err(&client->dev, "failed to verify the mux, the mux maybe not present in fact\n");
++
++      return ret;
+ }
+ #endif
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0015-LF-263-2-i2c-imx-increase-PM-timeout-to-avoid-operat.patch b/target/linux/layerscape/patches-5.4/808-i2c-0015-LF-263-2-i2c-imx-increase-PM-timeout-to-avoid-operat.patch
new file mode 100644 (file)
index 0000000..7579244
--- /dev/null
@@ -0,0 +1,27 @@
+From 929ddb0a7cbc09132512ede0afc935d040e84edf Mon Sep 17 00:00:00 2001
+From: Clark Wang <xiaoning.wang@nxp.com>
+Date: Fri, 29 Nov 2019 17:39:58 +0800
+Subject: [PATCH] LF-263-2 i2c: imx: increase PM timeout to avoid operate clk
+ frequently
+
+Switching the clock frequently will affect the data transmission
+efficiency, and prolong the timeout to reduce autosuspend times for
+i2c-imx.
+
+Acked-by: Fugang Duan <fugang.duan@nxp.com>
+Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
+---
+ drivers/i2c/busses/i2c-imx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/i2c/busses/i2c-imx.c
++++ b/drivers/i2c/busses/i2c-imx.c
+@@ -114,7 +114,7 @@
+ #define I2CR_IEN_OPCODE_0     0x0
+ #define I2CR_IEN_OPCODE_1     I2CR_IEN
+-#define I2C_PM_TIMEOUT                10 /* ms */
++#define I2C_PM_TIMEOUT                1000 /* ms */
+ enum pinmux_endian_type {
+       BIG_ENDIAN,
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0016-LF-162-i2c-imx-Defer-probing-if-EDMA-not-available.patch b/target/linux/layerscape/patches-5.4/808-i2c-0016-LF-162-i2c-imx-Defer-probing-if-EDMA-not-available.patch
new file mode 100644 (file)
index 0000000..ce19d0b
--- /dev/null
@@ -0,0 +1,70 @@
+From 9de3b340d84b75f93081f871b640a065cba4ded0 Mon Sep 17 00:00:00 2001
+From: Peng Ma <peng.ma@nxp.com>
+Date: Tue, 26 Nov 2019 16:02:00 +0800
+Subject: [PATCH] LF-162: i2c: imx: Defer probing if EDMA not available
+
+EDMA may be not available or defered due to dependencies on
+other modules, If these scenarios is encountered, we should
+defer probing.
+
+Signed-off-by: Peng Ma <peng.ma@nxp.com>
+---
+ drivers/i2c/busses/i2c-imx.c | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-imx.c
++++ b/drivers/i2c/busses/i2c-imx.c
+@@ -369,8 +369,8 @@ static void i2c_imx_reset_regs(struct im
+ }
+ /* Functions for DMA support */
+-static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
+-                                              dma_addr_t phy_addr)
++static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
++                             dma_addr_t phy_addr)
+ {
+       struct imx_i2c_dma *dma;
+       struct dma_slave_config dma_sconfig;
+@@ -379,7 +379,7 @@ static void i2c_imx_dma_request(struct i
+       dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+       if (!dma)
+-              return;
++              return -ENOMEM;
+       dma->chan_tx = dma_request_chan(dev, "tx");
+       if (IS_ERR(dma->chan_tx)) {
+@@ -424,7 +424,7 @@ static void i2c_imx_dma_request(struct i
+       dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n",
+               dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
+-      return;
++      return 0;
+ fail_rx:
+       dma_release_channel(dma->chan_rx);
+@@ -432,6 +432,8 @@ fail_tx:
+       dma_release_channel(dma->chan_tx);
+ fail_al:
+       devm_kfree(dev, dma);
++
++      return ret;
+ }
+ static void i2c_imx_dma_callback(void *arg)
+@@ -1602,10 +1604,14 @@ static int i2c_imx_probe(struct platform
+       dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
+       /* Init DMA config if supported */
+-      i2c_imx_dma_request(i2c_imx, phy_addr);
++      ret = i2c_imx_dma_request(i2c_imx, phy_addr);
++      if (ret == -EPROBE_DEFER)
++              goto i2c_adapter_remove;
+       return 0;   /* Return OK */
++i2c_adapter_remove:
++      i2c_del_adapter(&i2c_imx->adapter);
+ clk_notifier_unregister:
+       clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
+ rpm_disable:
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0001-ivshmem-net-virtual-network-device-for-Jailhouse.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0001-ivshmem-net-virtual-network-device-for-Jailhouse.patch
new file mode 100644 (file)
index 0000000..617e937
--- /dev/null
@@ -0,0 +1,960 @@
+From 7f48bab7c7b468961cf70efa1d86a75173e3987a Mon Sep 17 00:00:00 2001
+From: Mans Rullgard <mans@mansr.com>
+Date: Thu, 26 May 2016 16:04:02 +0100
+Subject: [PATCH] ivshmem-net: virtual network device for Jailhouse
+
+Work in progress.
+
+(cherry picked from commit ed818547b45e652db57d5966efe336ed646feb45)
+---
+ drivers/net/Kconfig       |   4 +
+ drivers/net/Makefile      |   2 +
+ drivers/net/ivshmem-net.c | 923 ++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 929 insertions(+)
+ create mode 100644 drivers/net/ivshmem-net.c
+
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -528,4 +528,8 @@ config NET_FAILOVER
+         a VM with direct attached VF by failing over to the paravirtual
+         datapath when the VF is unplugged.
++config IVSHMEM_NET
++      tristate "IVSHMEM virtual network device"
++      depends on PCI
++
+ endif # NETDEVICES
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -79,3 +79,5 @@ thunderbolt-net-y += thunderbolt.o
+ obj-$(CONFIG_THUNDERBOLT_NET) += thunderbolt-net.o
+ obj-$(CONFIG_NETDEVSIM) += netdevsim/
+ obj-$(CONFIG_NET_FAILOVER) += net_failover.o
++
++obj-$(CONFIG_IVSHMEM_NET) += ivshmem-net.o
+--- /dev/null
++++ b/drivers/net/ivshmem-net.c
+@@ -0,0 +1,923 @@
++/*
++ * Copyright 2016 Mans Rullgard <mans@mansr.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/io.h>
++#include <linux/bitops.h>
++#include <linux/interrupt.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/virtio_ring.h>
++
++#define DRV_NAME "ivshmem-net"
++
++#define JAILHOUSE_CFG_SHMEM_PTR       0x40
++#define JAILHOUSE_CFG_SHMEM_SZ        0x48
++
++#define IVSHM_NET_STATE_RESET 0
++#define IVSHM_NET_STATE_INIT  1
++#define IVSHM_NET_STATE_READY 2
++#define IVSHM_NET_STATE_RUN   3
++
++#define IVSHM_NET_MTU_MIN 256
++#define IVSHM_NET_MTU_MAX 65535
++#define IVSHM_NET_MTU_DEF 16384
++
++#define IVSHM_NET_FRAME_SIZE(s) ALIGN(18 + (s), SMP_CACHE_BYTES)
++
++#define IVSHM_NET_VQ_ALIGN 64
++
++struct ivshmem_regs {
++      u32 imask;
++      u32 istat;
++      u32 ivpos;
++      u32 doorbell;
++      u32 lstate;
++      u32 rstate;
++};
++
++struct ivshm_net_queue {
++      struct vring vr;
++      u32 free_head;
++      u32 num_free;
++      u32 num_added;
++      u16 last_avail_idx;
++      u16 last_used_idx;
++
++      void *data;
++      void *end;
++      u32 size;
++      u32 head;
++      u32 tail;
++};
++
++struct ivshm_net_stats {
++      u32 interrupts;
++      u32 tx_packets;
++      u32 tx_notify;
++      u32 tx_pause;
++      u32 rx_packets;
++      u32 rx_notify;
++      u32 napi_poll;
++      u32 napi_complete;
++      u32 napi_poll_n[10];
++};
++
++struct ivshm_net {
++      struct ivshm_net_queue rx;
++      struct ivshm_net_queue tx;
++
++      u32 vrsize;
++      u32 qlen;
++      u32 qsize;
++
++      spinlock_t tx_free_lock;
++      spinlock_t tx_clean_lock;
++
++      struct napi_struct napi;
++
++      u32 lstate;
++      u32 rstate;
++
++      struct workqueue_struct *state_wq;
++      struct work_struct state_work;
++
++      struct ivshm_net_stats stats;
++
++      struct ivshmem_regs __iomem *ivshm_regs;
++      void *shm;
++      phys_addr_t shmaddr;
++      resource_size_t shmlen;
++      u32 peer_id;
++
++      struct pci_dev *pdev;
++      struct msix_entry msix;
++      bool using_msix;
++};
++
++static void *ivshm_net_desc_data(struct ivshm_net *in,
++                               struct ivshm_net_queue *q,
++                               struct vring_desc *desc,
++                               u32 *len)
++{
++      u64 addr = READ_ONCE(desc->addr);
++      u32 dlen = READ_ONCE(desc->len);
++      void *data;
++
++      if (addr < in->shmaddr || desc->addr > in->shmaddr + in->shmlen)
++              return NULL;
++
++      data = in->shm + (addr - in->shmaddr);
++
++      if (data < q->data || data >= q->end)
++              return NULL;
++
++      if (dlen > q->end - data)
++              return NULL;
++
++      *len = dlen;
++
++      return data;
++}
++
++static void ivshm_net_init_queue(struct ivshm_net *in,
++                               struct ivshm_net_queue *q,
++                               void *mem, unsigned int len)
++{
++      memset(q, 0, sizeof(*q));
++
++      vring_init(&q->vr, len, mem, IVSHM_NET_VQ_ALIGN);
++      q->data = mem + in->vrsize;
++      q->end = q->data + in->qsize;
++      q->size = in->qsize;
++}
++
++static void ivshm_net_init_queues(struct net_device *ndev)
++{
++      struct ivshm_net *in = netdev_priv(ndev);
++      int ivpos = readl(&in->ivshm_regs->ivpos);
++      void *tx;
++      void *rx;
++      int i;
++
++      tx = in->shm +  ivpos * in->shmlen / 2;
++      rx = in->shm + !ivpos * in->shmlen / 2;
++
++      memset(tx, 0, in->shmlen / 2);
++
++      ivshm_net_init_queue(in, &in->rx, rx, in->qlen);
++      ivshm_net_init_queue(in, &in->tx, tx, in->qlen);
++
++      swap(in->rx.vr.used, in->tx.vr.used);
++
++      in->tx.num_free = in->tx.vr.num;
++
++      for (i = 0; i < in->tx.vr.num - 1; i++)
++              in->tx.vr.desc[i].next = i + 1;
++}
++
++static int ivshm_net_calc_qsize(struct net_device *ndev)
++{
++      struct ivshm_net *in = netdev_priv(ndev);
++      unsigned int vrsize;
++      unsigned int qsize;
++      unsigned int qlen;
++
++      for (qlen = 4096; qlen > 32; qlen >>= 1) {
++              vrsize = vring_size(qlen, IVSHM_NET_VQ_ALIGN);
++              vrsize = ALIGN(vrsize, IVSHM_NET_VQ_ALIGN);
++              if (vrsize < in->shmlen / 16)
++                      break;
++      }
++
++      if (vrsize > in->shmlen / 2)
++              return -EINVAL;
++
++      qsize = in->shmlen / 2 - vrsize;
++
++      if (qsize < 4 * IVSHM_NET_MTU_MIN)
++              return -EINVAL;
++
++      in->vrsize = vrsize;
++      in->qlen = qlen;
++      in->qsize = qsize;
++
++      return 0;
++}
++
++static void ivshm_net_notify_tx(struct ivshm_net *in, unsigned int num)
++{
++      u16 evt, old, new;
++
++      virt_mb();
++
++      evt = READ_ONCE(vring_avail_event(&in->tx.vr));
++      old = in->tx.last_avail_idx - num;
++      new = in->tx.last_avail_idx;
++
++      if (vring_need_event(evt, new, old)) {
++              writel(in->peer_id << 16, &in->ivshm_regs->doorbell);
++              in->stats.tx_notify++;
++      }
++}
++
++static void ivshm_net_enable_rx_irq(struct ivshm_net *in)
++{
++      vring_avail_event(&in->rx.vr) = in->rx.last_avail_idx;
++      virt_wmb();
++}
++
++static void ivshm_net_notify_rx(struct ivshm_net *in, unsigned int num)
++{
++      u16 evt, old, new;
++
++      virt_mb();
++
++      evt = vring_used_event(&in->rx.vr);
++      old = in->rx.last_used_idx - num;
++      new = in->rx.last_used_idx;
++
++      if (vring_need_event(evt, new, old)) {
++              writel(in->peer_id << 16, &in->ivshm_regs->doorbell);
++              in->stats.rx_notify++;
++      }
++}
++
++static void ivshm_net_enable_tx_irq(struct ivshm_net *in)
++{
++      vring_used_event(&in->tx.vr) = in->tx.last_used_idx;
++      virt_wmb();
++}
++
++static bool ivshm_net_rx_avail(struct ivshm_net *in)
++{
++      virt_mb();
++      return READ_ONCE(in->rx.vr.avail->idx) != in->rx.last_avail_idx;
++}
++
++static size_t ivshm_net_tx_space(struct ivshm_net *in)
++{
++      struct ivshm_net_queue *tx = &in->tx;
++      u32 tail = tx->tail;
++      u32 head = tx->head;
++      u32 space;
++
++      if (head < tail)
++              space = tail - head;
++      else
++              space = max(tx->size - head, tail);
++
++      return space;
++}
++
++static bool ivshm_net_tx_ok(struct ivshm_net *in, unsigned int mtu)
++{
++      return in->tx.num_free >= 2 &&
++              ivshm_net_tx_space(in) >= 2 * IVSHM_NET_FRAME_SIZE(mtu);
++}
++
++static u32 ivshm_net_tx_advance(struct ivshm_net_queue *q, u32 *pos, u32 len)
++{
++      u32 p = *pos;
++
++      len = IVSHM_NET_FRAME_SIZE(len);
++
++      if (q->size - p < len)
++              p = 0;
++      *pos = p + len;
++
++      return p;
++}
++
++static int ivshm_net_tx_frame(struct net_device *ndev, struct sk_buff *skb)
++{
++      struct ivshm_net *in = netdev_priv(ndev);
++      struct ivshm_net_queue *tx = &in->tx;
++      struct vring *vr = &tx->vr;
++      struct vring_desc *desc;
++      unsigned int desc_idx;
++      unsigned int avail;
++      u32 head;
++      void *buf;
++
++      BUG_ON(tx->num_free < 1);
++
++      spin_lock(&in->tx_free_lock);
++      desc_idx = tx->free_head;
++      desc = &vr->desc[desc_idx];
++      tx->free_head = desc->next;
++      tx->num_free--;
++      spin_unlock(&in->tx_free_lock);
++
++      head = ivshm_net_tx_advance(tx, &tx->head, skb->len);
++
++      buf = tx->data + head;
++      skb_copy_and_csum_dev(skb, buf);
++
++      desc->addr = in->shmaddr + (buf - in->shm);
++      desc->len = skb->len;
++
++      avail = tx->last_avail_idx++ & (vr->num - 1);
++      vr->avail->ring[avail] = desc_idx;
++      tx->num_added++;
++
++      if (!skb->xmit_more) {
++              virt_store_release(&vr->avail->idx, tx->last_avail_idx);
++              ivshm_net_notify_tx(in, tx->num_added);
++              tx->num_added = 0;
++      }
++
++      return 0;
++}
++
++static void ivshm_net_tx_clean(struct net_device *ndev)
++{
++      struct ivshm_net *in = netdev_priv(ndev);
++      struct ivshm_net_queue *tx = &in->tx;
++      struct vring *vr = &tx->vr;
++      struct vring_desc *desc;
++      struct vring_desc *fdesc;
++      unsigned int used;
++      unsigned int num;
++      u16 used_idx;
++      u16 last;
++      u32 fhead;
++
++      if (!spin_trylock(&in->tx_clean_lock))
++              return;
++
++      used_idx = virt_load_acquire(&vr->used->idx);
++      last = tx->last_used_idx;
++
++      fdesc = NULL;
++      num = 0;
++
++      while (last != used_idx) {
++              void *data;
++              u32 len;
++              u32 tail;
++
++              used = vr->used->ring[last & (vr->num - 1)].id;
++              if (used >= vr->num) {
++                      netdev_err(ndev, "invalid tx used %d\n", used);
++                      break;
++              }
++
++              desc = &vr->desc[used];
++
++              data = ivshm_net_desc_data(in, &in->tx, desc, &len);
++              if (!data) {
++                      netdev_err(ndev, "bad tx descriptor\n");
++                      break;
++              }
++
++              tail = ivshm_net_tx_advance(tx, &tx->tail, len);
++              if (data != tx->data + tail) {
++                      netdev_err(ndev, "bad tx descriptor\n");
++                      break;
++              }
++
++              if (!num)
++                      fdesc = desc;
++              else
++                      desc->next = fhead;
++
++              fhead = used;
++              last++;
++              num++;
++      }
++
++      tx->last_used_idx = last;
++
++      spin_unlock(&in->tx_clean_lock);
++
++      if (num) {
++              spin_lock(&in->tx_free_lock);
++              fdesc->next = tx->free_head;
++              tx->free_head = fhead;
++              tx->num_free += num;
++              BUG_ON(tx->num_free > vr->num);
++              spin_unlock(&in->tx_free_lock);
++      }
++}
++
++static struct vring_desc *ivshm_net_rx_desc(struct net_device *ndev)
++{
++      struct ivshm_net *in = netdev_priv(ndev);
++      struct ivshm_net_queue *rx = &in->rx;
++      struct vring *vr = &rx->vr;
++      unsigned int avail;
++      u16 avail_idx;
++
++      avail_idx = virt_load_acquire(&vr->avail->idx);
++
++      if (avail_idx == rx->last_avail_idx)
++              return NULL;
++
++      avail = vr->avail->ring[rx->last_avail_idx++ & (vr->num - 1)];
++      if (avail >= vr->num) {
++              netdev_err(ndev, "invalid rx avail %d\n", avail);
++              return NULL;
++      }
++
++      return &vr->desc[avail];
++}
++
++static void ivshm_net_rx_finish(struct ivshm_net *in, struct vring_desc *desc)
++{
++      struct ivshm_net_queue *rx = &in->rx;
++      struct vring *vr = &rx->vr;
++      unsigned int desc_id = desc - vr->desc;
++      unsigned int used;
++
++      used = rx->last_used_idx++ & (vr->num - 1);
++      vr->used->ring[used].id = desc_id;
++
++      virt_store_release(&vr->used->idx, rx->last_used_idx);
++}
++
++static int ivshm_net_poll(struct napi_struct *napi, int budget)
++{
++      struct net_device *ndev = napi->dev;
++      struct ivshm_net *in = container_of(napi, struct ivshm_net, napi);
++      int received = 0;
++
++      in->stats.napi_poll++;
++
++      ivshm_net_tx_clean(ndev);
++
++      while (received < budget) {
++              struct vring_desc *desc;
++              struct sk_buff *skb;
++              void *data;
++              u32 len;
++
++              desc = ivshm_net_rx_desc(ndev);
++              if (!desc)
++                      break;
++
++              data = ivshm_net_desc_data(in, &in->rx, desc, &len);
++              if (!data) {
++                      netdev_err(ndev, "bad rx descriptor\n");
++                      break;
++              }
++
++              skb = napi_alloc_skb(napi, len);
++
++              if (skb) {
++                      memcpy(skb_put(skb, len), data, len);
++                      skb->protocol = eth_type_trans(skb, ndev);
++                      napi_gro_receive(napi, skb);
++              }
++
++              ndev->stats.rx_packets++;
++              ndev->stats.rx_bytes += len;
++
++              ivshm_net_rx_finish(in, desc);
++              received++;
++      }
++
++      if (received < budget) {
++              in->stats.napi_complete++;
++              napi_complete_done(napi, received);
++              ivshm_net_enable_rx_irq(in);
++              if (ivshm_net_rx_avail(in))
++                      napi_schedule(napi);
++      }
++
++      if (received)
++              ivshm_net_notify_rx(in, received);
++
++      in->stats.rx_packets += received;
++      in->stats.napi_poll_n[received ? 1 + min(ilog2(received), 8) : 0]++;
++
++      if (ivshm_net_tx_ok(in, ndev->mtu))
++              netif_wake_queue(ndev);
++
++      return received;
++}
++
++static netdev_tx_t ivshm_net_xmit(struct sk_buff *skb, struct net_device *ndev)
++{
++      struct ivshm_net *in = netdev_priv(ndev);
++
++      ivshm_net_tx_clean(ndev);
++
++      if (!ivshm_net_tx_ok(in, ndev->mtu)) {
++              ivshm_net_enable_tx_irq(in);
++              netif_stop_queue(ndev);
++              skb->xmit_more = 0;
++              in->stats.tx_pause++;
++      }
++
++      ivshm_net_tx_frame(ndev, skb);
++
++      in->stats.tx_packets++;
++      ndev->stats.tx_packets++;
++      ndev->stats.tx_bytes += skb->len;
++
++      dev_consume_skb_any(skb);
++
++      return NETDEV_TX_OK;
++}
++
++static void ivshm_net_set_state(struct ivshm_net *in, u32 state)
++{
++      virt_wmb();
++      WRITE_ONCE(in->lstate, state);
++      writel(state, &in->ivshm_regs->lstate);
++}
++
++static void ivshm_net_run(struct net_device *ndev)
++{
++      struct ivshm_net *in = netdev_priv(ndev);
++
++      netif_start_queue(ndev);
++      napi_enable(&in->napi);
++      napi_schedule(&in->napi);
++      ivshm_net_set_state(in, IVSHM_NET_STATE_RUN);
++}
++
++static void ivshm_net_state_change(struct work_struct *work)
++{
++      struct ivshm_net *in = container_of(work, struct ivshm_net, state_work);
++      struct net_device *ndev = in->napi.dev;
++      u32 rstate = readl(&in->ivshm_regs->rstate);
++
++
++      switch (in->lstate) {
++      case IVSHM_NET_STATE_RESET:
++              if (rstate < IVSHM_NET_STATE_READY)
++                      ivshm_net_set_state(in, IVSHM_NET_STATE_INIT);
++              break;
++
++      case IVSHM_NET_STATE_INIT:
++              if (rstate > IVSHM_NET_STATE_RESET) {
++                      ivshm_net_init_queues(ndev);
++                      ivshm_net_set_state(in, IVSHM_NET_STATE_READY);
++
++                      rtnl_lock();
++                      call_netdevice_notifiers(NETDEV_CHANGEADDR, ndev);
++                      rtnl_unlock();
++              }
++              break;
++
++      case IVSHM_NET_STATE_READY:
++              if (rstate >= IVSHM_NET_STATE_READY) {
++                      netif_carrier_on(ndev);
++                      if (ndev->flags & IFF_UP)
++                              ivshm_net_run(ndev);
++              } else {
++                      netif_carrier_off(ndev);
++                      ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
++              }
++              break;
++
++      case IVSHM_NET_STATE_RUN:
++              if (rstate < IVSHM_NET_STATE_READY) {
++                      netif_stop_queue(ndev);
++                      napi_disable(&in->napi);
++                      netif_carrier_off(ndev);
++                      ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
++              }
++              break;
++      }
++
++      virt_wmb();
++      WRITE_ONCE(in->rstate, rstate);
++}
++
++static bool ivshm_net_check_state(struct net_device *ndev)
++{
++      struct ivshm_net *in = netdev_priv(ndev);
++      u32 rstate = readl(&in->ivshm_regs->rstate);
++
++      if (rstate != READ_ONCE(in->rstate) ||
++          in->lstate != IVSHM_NET_STATE_RUN) {
++              queue_work(in->state_wq, &in->state_work);
++              return false;
++      }
++
++      return true;
++}
++
++static irqreturn_t ivshm_net_int(int irq, void *data)
++{
++      struct net_device *ndev = data;
++      struct ivshm_net *in = netdev_priv(ndev);
++
++      in->stats.interrupts++;
++
++      ivshm_net_check_state(ndev);
++      napi_schedule_irqoff(&in->napi);
++
++      return IRQ_HANDLED;
++}
++
++static int ivshm_net_open(struct net_device *ndev)
++{
++      struct ivshm_net *in = netdev_priv(ndev);
++
++      netdev_reset_queue(ndev);
++      ndev->operstate = IF_OPER_UP;
++
++      if (in->lstate == IVSHM_NET_STATE_READY)
++              ivshm_net_run(ndev);
++
++      return 0;
++}
++
++static int ivshm_net_stop(struct net_device *ndev)
++{
++      struct ivshm_net *in = netdev_priv(ndev);
++
++      ndev->operstate = IF_OPER_DOWN;
++
++      if (in->lstate == IVSHM_NET_STATE_RUN) {
++              napi_disable(&in->napi);
++              netif_stop_queue(ndev);
++              ivshm_net_set_state(in, IVSHM_NET_STATE_READY);
++      }
++
++      return 0;
++}
++
++static int ivshm_net_change_mtu(struct net_device *ndev, int mtu)
++{
++      struct ivshm_net *in = netdev_priv(ndev);
++      struct ivshm_net_queue *tx = &in->tx;
++
++      if (mtu < IVSHM_NET_MTU_MIN || mtu > IVSHM_NET_MTU_MAX)
++              return -EINVAL;
++
++      if (in->tx.size / mtu < 4)
++              return -EINVAL;
++
++      if (ivshm_net_tx_space(in) < 2 * IVSHM_NET_FRAME_SIZE(mtu))
++              return -EBUSY;
++
++      if (in->tx.size - tx->head < IVSHM_NET_FRAME_SIZE(mtu) &&
++          tx->head < tx->tail)
++              return -EBUSY;
++
++      netif_tx_lock_bh(ndev);
++      if (in->tx.size - tx->head < IVSHM_NET_FRAME_SIZE(mtu))
++              tx->head = 0;
++      netif_tx_unlock_bh(ndev);
++
++      ndev->mtu = mtu;
++
++      return 0;
++}
++
++#ifdef CONFIG_NET_POLL_CONTROLLER
++static void ivshm_net_poll_controller(struct net_device *ndev)
++{
++      struct ivshm_net *in = netdev_priv(ndev);
++
++      napi_schedule(&in->napi);
++}
++#endif
++
++static const struct net_device_ops ivshm_net_ops = {
++      .ndo_open       = ivshm_net_open,
++      .ndo_stop       = ivshm_net_stop,
++      .ndo_start_xmit = ivshm_net_xmit,
++      .ndo_change_mtu = ivshm_net_change_mtu,
++#ifdef CONFIG_NET_POLL_CONTROLLER
++      .ndo_poll_controller = ivshm_net_poll_controller,
++#endif
++};
++
++static const char ivshm_net_stats[][ETH_GSTRING_LEN] = {
++      "interrupts",
++      "tx_packets",
++      "tx_notify",
++      "tx_pause",
++      "rx_packets",
++      "rx_notify",
++      "napi_poll",
++      "napi_complete",
++      "napi_poll_0",
++      "napi_poll_1",
++      "napi_poll_2",
++      "napi_poll_4",
++      "napi_poll_8",
++      "napi_poll_16",
++      "napi_poll_32",
++      "napi_poll_64",
++      "napi_poll_128",
++      "napi_poll_256",
++};
++
++#define NUM_STATS ARRAY_SIZE(ivshm_net_stats)
++
++static int ivshm_net_get_sset_count(struct net_device *ndev, int sset)
++{
++      if (sset == ETH_SS_STATS)
++              return NUM_STATS;
++
++      return -EOPNOTSUPP;
++}
++
++static void ivshm_net_get_strings(struct net_device *ndev, u32 sset, u8 *buf)
++{
++      if (sset == ETH_SS_STATS)
++              memcpy(buf, &ivshm_net_stats, sizeof(ivshm_net_stats));
++}
++
++static void ivshm_net_get_ethtool_stats(struct net_device *ndev,
++                                      struct ethtool_stats *estats, u64 *st)
++{
++      struct ivshm_net *in = netdev_priv(ndev);
++      unsigned int n = 0;
++      unsigned int i;
++
++      st[n++] = in->stats.interrupts;
++      st[n++] = in->stats.tx_packets;
++      st[n++] = in->stats.tx_notify;
++      st[n++] = in->stats.tx_pause;
++      st[n++] = in->stats.rx_packets;
++      st[n++] = in->stats.rx_notify;
++      st[n++] = in->stats.napi_poll;
++      st[n++] = in->stats.napi_complete;
++
++      for (i = 0; i < ARRAY_SIZE(in->stats.napi_poll_n); i++)
++              st[n++] = in->stats.napi_poll_n[i];
++
++      memset(&in->stats, 0, sizeof(in->stats));
++}
++
++static const struct ethtool_ops ivshm_net_ethtool_ops = {
++      .get_sset_count         = ivshm_net_get_sset_count,
++      .get_strings            = ivshm_net_get_strings,
++      .get_ethtool_stats      = ivshm_net_get_ethtool_stats,
++};
++
++static int ivshm_net_probe(struct pci_dev *pdev,
++                         const struct pci_device_id *id)
++{
++      struct net_device *ndev;
++      struct ivshm_net *in;
++      struct ivshmem_regs __iomem *regs;
++      resource_size_t shmaddr;
++      resource_size_t shmlen;
++      int interrupt;
++      void *shm;
++      u32 ivpos;
++      int err;
++
++      err = pcim_enable_device(pdev);
++      if (err) {
++              dev_err(&pdev->dev, "pci_enable_device: %d\n", err);
++              return err;
++      }
++
++      err = pcim_iomap_regions(pdev, BIT(0), DRV_NAME);
++      if (err) {
++              dev_err(&pdev->dev, "pcim_iomap_regions: %d\n", err);
++              return err;
++      }
++
++      regs = pcim_iomap_table(pdev)[0];
++
++      shmlen = pci_resource_len(pdev, 2);
++
++      if (shmlen) {
++              shmaddr = pci_resource_start(pdev, 2);
++      } else {
++              union { u64 v; u32 hl[2]; } val;
++
++              pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_PTR,
++                                    &val.hl[0]);
++              pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_PTR + 4,
++                                    &val.hl[1]);
++              shmaddr = val.v;
++
++              pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_SZ,
++                                    &val.hl[0]);
++              pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_SZ + 4,
++                                    &val.hl[1]);
++              shmlen = val.v;
++      }
++
++
++      if (!devm_request_mem_region(&pdev->dev, shmaddr, shmlen, DRV_NAME))
++              return -EBUSY;
++
++      shm = devm_memremap(&pdev->dev, shmaddr, shmlen, MEMREMAP_WC);
++      if (!shm)
++              return -ENOMEM;
++
++      ivpos = readl(&regs->ivpos);
++      if (ivpos > 1) {
++              dev_err(&pdev->dev, "invalid IVPosition %d\n", ivpos);
++              return -EINVAL;
++      }
++
++      dev_info(&pdev->dev, "shared memory size %pa\n", &shmlen);
++
++      ndev = alloc_etherdev(sizeof(*in));
++      if (!ndev)
++              return -ENOMEM;
++
++      pci_set_drvdata(pdev, ndev);
++      SET_NETDEV_DEV(ndev, &pdev->dev);
++
++      in = netdev_priv(ndev);
++      in->ivshm_regs = regs;
++      in->shm = shm;
++      in->shmaddr = shmaddr;
++      in->shmlen = shmlen;
++      in->peer_id = !ivpos;
++      in->pdev = pdev;
++      spin_lock_init(&in->tx_free_lock);
++      spin_lock_init(&in->tx_clean_lock);
++
++      err = ivshm_net_calc_qsize(ndev);
++      if (err)
++              goto err_free;
++
++      in->state_wq = alloc_ordered_workqueue(DRV_NAME, 0);
++      if (!in->state_wq)
++              goto err_free;
++
++      INIT_WORK(&in->state_work, ivshm_net_state_change);
++
++      eth_random_addr(ndev->dev_addr);
++      ndev->netdev_ops = &ivshm_net_ops;
++      ndev->ethtool_ops = &ivshm_net_ethtool_ops;
++      ndev->mtu = min_t(u32, IVSHM_NET_MTU_DEF, in->qsize / 16);
++      ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG;
++      ndev->features = ndev->hw_features;
++
++      netif_carrier_off(ndev);
++      netif_napi_add(ndev, &in->napi, ivshm_net_poll, NAPI_POLL_WEIGHT);
++
++      err = register_netdev(ndev);
++      if (err)
++              goto err_wq;
++
++      err = pci_enable_msix(pdev, &in->msix, 1);
++      if (!err) {
++              interrupt = in->msix.vector;
++              in->using_msix = true;
++      } else {
++              interrupt = pdev->irq;
++              in->using_msix = false;
++      }
++
++      err = request_irq(interrupt, ivshm_net_int, 0, DRV_NAME, ndev);
++      if (err)
++              goto err_int;
++
++      pci_set_master(pdev);
++
++      writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
++
++      return 0;
++
++err_int:
++      if (in->using_msix)
++              pci_disable_msix(pdev);
++      unregister_netdev(ndev);
++err_wq:
++      destroy_workqueue(in->state_wq);
++err_free:
++      free_netdev(ndev);
++
++      return err;
++}
++
++static void ivshm_net_remove(struct pci_dev *pdev)
++{
++      struct net_device *ndev = pci_get_drvdata(pdev);
++      struct ivshm_net *in = netdev_priv(ndev);
++
++      if (in->using_msix)  {
++              free_irq(in->msix.vector, ndev);
++              pci_disable_msix(pdev);
++      } else {
++              free_irq(pdev->irq, ndev);
++      }
++
++      unregister_netdev(ndev);
++      cancel_work_sync(&in->state_work);
++      destroy_workqueue(in->state_wq);
++      free_netdev(ndev);
++}
++
++static const struct pci_device_id ivshm_net_id_table[] = {
++      { PCI_DEVICE(PCI_VENDOR_ID_REDHAT_QUMRANET, 0x1110),
++              (PCI_CLASS_OTHERS << 16) | (0x01 << 8), 0xffff00 },
++      { 0 }
++};
++MODULE_DEVICE_TABLE(pci, ivshm_net_id_table);
++
++static struct pci_driver ivshm_net_driver = {
++      .name           = DRV_NAME,
++      .id_table       = ivshm_net_id_table,
++      .probe          = ivshm_net_probe,
++      .remove         = ivshm_net_remove,
++};
++module_pci_driver(ivshm_net_driver);
++
++MODULE_AUTHOR("Mans Rullgard <mans@mansr.com>");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0002-ivshmem-net-Map-shmem-region-as-RAM.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0002-ivshmem-net-Map-shmem-region-as-RAM.patch
new file mode 100644 (file)
index 0000000..8a3bcd6
--- /dev/null
@@ -0,0 +1,26 @@
+From 4677dd55d55832dab1e4f41fe9a7fabe8bb95197 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Thu, 24 Nov 2016 08:27:45 +0100
+Subject: [PATCH] ivshmem-net: Map shmem region as RAM
+
+No need for special caching, simply map the shared memory region like
+RAM, thus write-back. This gives us another order of magnitude in
+throughput.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit af59c6541a65622cab498851e01653dd378cd9f8)
+---
+ drivers/net/ivshmem-net.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -802,7 +802,7 @@ static int ivshm_net_probe(struct pci_de
+       if (!devm_request_mem_region(&pdev->dev, shmaddr, shmlen, DRV_NAME))
+               return -EBUSY;
+-      shm = devm_memremap(&pdev->dev, shmaddr, shmlen, MEMREMAP_WC);
++      shm = devm_memremap(&pdev->dev, shmaddr, shmlen, MEMREMAP_WB);
+       if (!shm)
+               return -ENOMEM;
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0003-ivshmem-net-fix-race-in-state-machine.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0003-ivshmem-net-fix-race-in-state-machine.patch
new file mode 100644 (file)
index 0000000..ae6f839
--- /dev/null
@@ -0,0 +1,136 @@
+From 0af5d7d021bb899d9c3880415267e178a20fb7a9 Mon Sep 17 00:00:00 2001
+From: Mans Rullgard <mans@mansr.com>
+Date: Thu, 24 Nov 2016 18:46:41 +0000
+Subject: [PATCH] ivshmem-net: fix race in state machine
+
+(cherry picked from commit 5d663baed6a89d09bae4446f6509f9957c780bc7)
+---
+ drivers/net/ivshmem-net.c | 60 ++++++++++++++++++++++++-----------------------
+ 1 file changed, 31 insertions(+), 29 deletions(-)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -36,6 +36,8 @@
+ #define IVSHM_NET_STATE_READY 2
+ #define IVSHM_NET_STATE_RUN   3
++#define IVSHM_NET_FLAG_RUN    0
++
+ #define IVSHM_NET_MTU_MIN 256
+ #define IVSHM_NET_MTU_MAX 65535
+ #define IVSHM_NET_MTU_DEF 16384
+@@ -96,6 +98,8 @@ struct ivshm_net {
+       u32 lstate;
+       u32 rstate;
++      unsigned long flags;
++
+       struct workqueue_struct *state_wq;
+       struct work_struct state_work;
+@@ -529,12 +533,32 @@ static void ivshm_net_run(struct net_dev
+ {
+       struct ivshm_net *in = netdev_priv(ndev);
++      if (in->lstate < IVSHM_NET_STATE_READY)
++              return;
++
++      if (!netif_running(ndev))
++              return;
++
++      if (test_and_set_bit(IVSHM_NET_FLAG_RUN, &in->flags))
++              return;
++
+       netif_start_queue(ndev);
+       napi_enable(&in->napi);
+       napi_schedule(&in->napi);
+       ivshm_net_set_state(in, IVSHM_NET_STATE_RUN);
+ }
++static void ivshm_net_do_stop(struct net_device *ndev)
++{
++      struct ivshm_net *in = netdev_priv(ndev);
++
++      if (!test_and_clear_bit(IVSHM_NET_FLAG_RUN, &in->flags))
++              return;
++
++      netif_stop_queue(ndev);
++      napi_disable(&in->napi);
++}
++
+ static void ivshm_net_state_change(struct work_struct *work)
+ {
+       struct ivshm_net *in = container_of(work, struct ivshm_net, state_work);
+@@ -560,21 +584,13 @@ static void ivshm_net_state_change(struc
+               break;
+       case IVSHM_NET_STATE_READY:
++      case IVSHM_NET_STATE_RUN:
+               if (rstate >= IVSHM_NET_STATE_READY) {
+                       netif_carrier_on(ndev);
+-                      if (ndev->flags & IFF_UP)
+-                              ivshm_net_run(ndev);
++                      ivshm_net_run(ndev);
+               } else {
+                       netif_carrier_off(ndev);
+-                      ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
+-              }
+-              break;
+-
+-      case IVSHM_NET_STATE_RUN:
+-              if (rstate < IVSHM_NET_STATE_READY) {
+-                      netif_stop_queue(ndev);
+-                      napi_disable(&in->napi);
+-                      netif_carrier_off(ndev);
++                      ivshm_net_do_stop(ndev);
+                       ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
+               }
+               break;
+@@ -584,18 +600,13 @@ static void ivshm_net_state_change(struc
+       WRITE_ONCE(in->rstate, rstate);
+ }
+-static bool ivshm_net_check_state(struct net_device *ndev)
++static void ivshm_net_check_state(struct net_device *ndev)
+ {
+       struct ivshm_net *in = netdev_priv(ndev);
+       u32 rstate = readl(&in->ivshm_regs->rstate);
+-      if (rstate != READ_ONCE(in->rstate) ||
+-          in->lstate != IVSHM_NET_STATE_RUN) {
++      if (rstate != in->rstate || !test_bit(IVSHM_NET_FLAG_RUN, &in->flags))
+               queue_work(in->state_wq, &in->state_work);
+-              return false;
+-      }
+-
+-      return true;
+ }
+ static irqreturn_t ivshm_net_int(int irq, void *data)
+@@ -617,24 +628,15 @@ static int ivshm_net_open(struct net_dev
+       netdev_reset_queue(ndev);
+       ndev->operstate = IF_OPER_UP;
+-
+-      if (in->lstate == IVSHM_NET_STATE_READY)
+-              ivshm_net_run(ndev);
++      ivshm_net_run(ndev);
+       return 0;
+ }
+ static int ivshm_net_stop(struct net_device *ndev)
+ {
+-      struct ivshm_net *in = netdev_priv(ndev);
+-
+       ndev->operstate = IF_OPER_DOWN;
+-
+-      if (in->lstate == IVSHM_NET_STATE_RUN) {
+-              napi_disable(&in->napi);
+-              netif_stop_queue(ndev);
+-              ivshm_net_set_state(in, IVSHM_NET_STATE_READY);
+-      }
++      ivshm_net_do_stop(ndev);
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0004-ivshmem-net-Remove-unused-variable.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0004-ivshmem-net-Remove-unused-variable.patch
new file mode 100644 (file)
index 0000000..348c71f
--- /dev/null
@@ -0,0 +1,24 @@
+From 4bf063d8655698036c42ec34d6cc840d7bdc1a84 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Fri, 25 Nov 2016 17:31:51 +0100
+Subject: [PATCH] ivshmem-net: Remove unused variable
+
+Became unused by previous change.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit 3ea4b31deba3424784f0105c20dc90419e950e2c)
+---
+ drivers/net/ivshmem-net.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -624,8 +624,6 @@ static irqreturn_t ivshm_net_int(int irq
+ static int ivshm_net_open(struct net_device *ndev)
+ {
+-      struct ivshm_net *in = netdev_priv(ndev);
+-
+       netdev_reset_queue(ndev);
+       ndev->operstate = IF_OPER_UP;
+       ivshm_net_run(ndev);
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0005-ivshmem-net-Enable-INTx.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0005-ivshmem-net-Enable-INTx.patch
new file mode 100644 (file)
index 0000000..d872567
--- /dev/null
@@ -0,0 +1,51 @@
+From 3734c2c9ac0fd763deceb686efc93b293acca4c6 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 27 Nov 2016 15:15:51 +0100
+Subject: [PATCH] ivshmem-net: Enable INTx
+
+Activate INTx notification when it has to be used instead of MSI-X,
+disable it after use.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit 8790717bdca6ea58f18baac1749ac347b23b7263)
+---
+ drivers/net/ivshmem-net.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -31,6 +31,8 @@
+ #define JAILHOUSE_CFG_SHMEM_PTR       0x40
+ #define JAILHOUSE_CFG_SHMEM_SZ        0x48
++#define IVSHMEM_INTX_ENABLE   0x1
++
+ #define IVSHM_NET_STATE_RESET 0
+ #define IVSHM_NET_STATE_INIT  1
+ #define IVSHM_NET_STATE_READY 2
+@@ -47,7 +49,7 @@
+ #define IVSHM_NET_VQ_ALIGN 64
+ struct ivshmem_regs {
+-      u32 imask;
++      u32 intxctrl;
+       u32 istat;
+       u32 ivpos;
+       u32 doorbell;
+@@ -869,6 +871,8 @@ static int ivshm_net_probe(struct pci_de
+               goto err_int;
+       pci_set_master(pdev);
++      if (!in->using_msix)
++              writel(IVSHMEM_INTX_ENABLE, &in->ivshm_regs->intxctrl);
+       writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
+@@ -895,6 +899,7 @@ static void ivshm_net_remove(struct pci_
+               free_irq(in->msix.vector, ndev);
+               pci_disable_msix(pdev);
+       } else {
++              writel(0, &in->ivshm_regs->intxctrl);
+               free_irq(pdev->irq, ndev);
+       }
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0006-ivshmem-net-Improve-identification-of-resources.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0006-ivshmem-net-Improve-identification-of-resources.patch
new file mode 100644 (file)
index 0000000..8975a96
--- /dev/null
@@ -0,0 +1,55 @@
+From 40985902afd8f4eb0bd7aa4238c7d458282af948 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Wed, 21 Dec 2016 08:20:18 +0100
+Subject: [PATCH] ivshmem-net: Improve identification of resources
+
+Pass a device name consisting of driver name and PCI ID to request_irq
+and alloc_ordered_workqueue. This helps correlating resources with
+devices in case there are multiple of them.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit 43e2ff78b89cbdfaecba54601d85f3d40349a9b5)
+---
+ drivers/net/ivshmem-net.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -762,6 +762,7 @@ static int ivshm_net_probe(struct pci_de
+       resource_size_t shmaddr;
+       resource_size_t shmlen;
+       int interrupt;
++      char *device_name;
+       void *shm;
+       u32 ivpos;
+       int err;
+@@ -814,7 +815,10 @@ static int ivshm_net_probe(struct pci_de
+               return -EINVAL;
+       }
+-      dev_info(&pdev->dev, "shared memory size %pa\n", &shmlen);
++      device_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s[%s]", DRV_NAME,
++                                   dev_name(&pdev->dev));
++      if (!device_name)
++              return -ENOMEM;
+       ndev = alloc_etherdev(sizeof(*in));
+       if (!ndev)
+@@ -837,7 +841,7 @@ static int ivshm_net_probe(struct pci_de
+       if (err)
+               goto err_free;
+-      in->state_wq = alloc_ordered_workqueue(DRV_NAME, 0);
++      in->state_wq = alloc_ordered_workqueue(device_name, 0);
+       if (!in->state_wq)
+               goto err_free;
+@@ -866,7 +870,7 @@ static int ivshm_net_probe(struct pci_de
+               in->using_msix = false;
+       }
+-      err = request_irq(interrupt, ivshm_net_int, 0, DRV_NAME, ndev);
++      err = request_irq(interrupt, ivshm_net_int, 0, device_name, ndev);
+       if (err)
+               goto err_int;
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0007-ivshmem-net-Switch-to-reset-state-on-each-net-stop-a.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0007-ivshmem-net-Switch-to-reset-state-on-each-net-stop-a.patch
new file mode 100644 (file)
index 0000000..609fffe
--- /dev/null
@@ -0,0 +1,43 @@
+From 869dce4a7f48b0642e4c902c5d142503dbd37dda Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 1 Jan 2017 15:43:37 +0100
+Subject: [PATCH] ivshmem-net: Switch to reset state on each net stop and on
+ driver removal
+
+Improves the state signaling to the remote side after ifconfig down and
+driver removal.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit d0f632b2830146d9892a2b1ab93f866f072412bb)
+---
+ drivers/net/ivshmem-net.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -554,6 +554,8 @@ static void ivshm_net_do_stop(struct net
+ {
+       struct ivshm_net *in = netdev_priv(ndev);
++      ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
++
+       if (!test_and_clear_bit(IVSHM_NET_FLAG_RUN, &in->flags))
+               return;
+@@ -593,7 +595,6 @@ static void ivshm_net_state_change(struc
+               } else {
+                       netif_carrier_off(ndev);
+                       ivshm_net_do_stop(ndev);
+-                      ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
+               }
+               break;
+       }
+@@ -899,6 +900,8 @@ static void ivshm_net_remove(struct pci_
+       struct net_device *ndev = pci_get_drvdata(pdev);
+       struct ivshm_net *in = netdev_priv(ndev);
++      writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
++
+       if (in->using_msix)  {
+               free_irq(in->msix.vector, ndev);
+               pci_disable_msix(pdev);
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0008-ivshmem-net-Add-ethtool-register-dump.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0008-ivshmem-net-Add-ethtool-register-dump.patch
new file mode 100644 (file)
index 0000000..1a8b4c6
--- /dev/null
@@ -0,0 +1,57 @@
+From 65e624b3708cb35942297f699d886aa4c8a7e613 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 1 Jan 2017 15:46:26 +0100
+Subject: [PATCH] ivshmem-net: Add ethtool register dump
+
+Helps debugging inconsistent states.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit 81674136b6936fb8219dac1dcdb6df8fe424143d)
+---
+ drivers/net/ivshmem-net.c | 31 +++++++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -748,10 +748,41 @@ static void ivshm_net_get_ethtool_stats(
+       memset(&in->stats, 0, sizeof(in->stats));
+ }
++#define IVSHM_NET_REGS_LEN    (3 * sizeof(u32) + 6 * sizeof(u16))
++
++static int ivshm_net_get_regs_len(struct net_device *ndev)
++{
++      return IVSHM_NET_REGS_LEN;
++}
++
++static void ivshm_net_get_regs(struct net_device *ndev,
++                             struct ethtool_regs *regs, void *p)
++{
++      struct ivshm_net *in = netdev_priv(ndev);
++      u32 *reg32 = p;
++      u16 *reg16;
++
++      *reg32++ = in->lstate;
++      *reg32++ = in->rstate;
++      *reg32++ = in->qlen;
++
++      reg16 = (u16 *)reg32;
++
++      *reg16++ = in->tx.vr.avail ? in->tx.vr.avail->idx : 0;
++      *reg16++ = in->tx.vr.used ? in->tx.vr.used->idx : 0;
++      *reg16++ = in->tx.vr.avail ? vring_avail_event(&in->tx.vr) : 0;
++
++      *reg16++ = in->rx.vr.avail ? in->rx.vr.avail->idx : 0;
++      *reg16++ = in->rx.vr.used ? in->rx.vr.used->idx : 0;
++      *reg16++ = in->rx.vr.avail ? vring_avail_event(&in->rx.vr) : 0;
++}
++
+ static const struct ethtool_ops ivshm_net_ethtool_ops = {
+       .get_sset_count         = ivshm_net_get_sset_count,
+       .get_strings            = ivshm_net_get_strings,
+       .get_ethtool_stats      = ivshm_net_get_ethtool_stats,
++      .get_regs_len           = ivshm_net_get_regs_len,
++      .get_regs               = ivshm_net_get_regs,
+ };
+ static int ivshm_net_probe(struct pci_dev *pdev,
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0009-ivshmem-net-Fix-stuck-state-machine-during-setup.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0009-ivshmem-net-Fix-stuck-state-machine-during-setup.patch
new file mode 100644 (file)
index 0000000..fc23dc4
--- /dev/null
@@ -0,0 +1,26 @@
+From 74de99b0e1df634949c45df1c370d458e6a3c98a Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 1 Jan 2017 15:54:55 +0100
+Subject: [PATCH] ivshmem-net: Fix stuck state machine during setup
+
+If the remote side is already in INIT state (or even higher) and has a
+cached rstate of RESET, we won't make progress when signaling RESET
+again because the remote side won't send a state update. Fix this by
+enforcing a local check after probe completion.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit fceed9d0ab2486589c57c0793fbfbca4832442b9)
+---
+ drivers/net/ivshmem-net.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -911,6 +911,7 @@ static int ivshm_net_probe(struct pci_de
+               writel(IVSHMEM_INTX_ENABLE, &in->ivshm_regs->intxctrl);
+       writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
++      ivshm_net_check_state(ndev);
+       return 0;
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0010-ivshmem-net-Switch-to-relative-descriptor-addresses.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0010-ivshmem-net-Switch-to-relative-descriptor-addresses.patch
new file mode 100644 (file)
index 0000000..a2554c7
--- /dev/null
@@ -0,0 +1,45 @@
+From dd462c6eb2ba6af01ae38644183216c4d5603d90 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Tue, 3 Jan 2017 08:50:01 +0100
+Subject: [PATCH] ivshmem-net: Switch to relative descriptor addresses
+
+Make sure that we do not depend on identity-mapped shared memory
+regions.
+
+This also fixes an off-by-one in the range check of ivshm_net_desc_data.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit fe9c9dd6373892591a7d6b165c3c43045eb349c1)
+---
+ drivers/net/ivshmem-net.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -123,14 +123,14 @@ static void *ivshm_net_desc_data(struct
+                                struct vring_desc *desc,
+                                u32 *len)
+ {
+-      u64 addr = READ_ONCE(desc->addr);
++      u64 offs = READ_ONCE(desc->addr);
+       u32 dlen = READ_ONCE(desc->len);
+       void *data;
+-      if (addr < in->shmaddr || desc->addr > in->shmaddr + in->shmlen)
++      if (offs >= in->shmlen)
+               return NULL;
+-      data = in->shm + (addr - in->shmaddr);
++      data = in->shm + offs;
+       if (data < q->data || data >= q->end)
+               return NULL;
+@@ -317,7 +317,7 @@ static int ivshm_net_tx_frame(struct net
+       buf = tx->data + head;
+       skb_copy_and_csum_dev(skb, buf);
+-      desc->addr = in->shmaddr + (buf - in->shm);
++      desc->addr = buf - in->shm;
+       desc->len = skb->len;
+       avail = tx->last_avail_idx++ & (vr->num - 1);
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0011-ivshmem-net-Switch-to-pci_alloc_irq_vectors.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0011-ivshmem-net-Switch-to-pci_alloc_irq_vectors.patch
new file mode 100644 (file)
index 0000000..ce37c28
--- /dev/null
@@ -0,0 +1,143 @@
+From 8b5d421b2bfa6800d182f74a60afa48cf305fb86 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Tue, 23 May 2017 17:41:00 +0200
+Subject: [PATCH] ivshmem-net: Switch to pci_alloc_irq_vectors
+
+Required by 4.12, and it also simplifies our code. Needs to be folded
+into the initial patch eventually.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit ea6e78c89582711f15a2711f0a35ac3a61d9d074)
+---
+ drivers/net/ivshmem-net.c | 66 ++++++++++++++++++++---------------------------
+ 1 file changed, 28 insertions(+), 38 deletions(-)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -114,8 +114,6 @@ struct ivshm_net {
+       u32 peer_id;
+       struct pci_dev *pdev;
+-      struct msix_entry msix;
+-      bool using_msix;
+ };
+ static void *ivshm_net_desc_data(struct ivshm_net *in,
+@@ -793,22 +791,21 @@ static int ivshm_net_probe(struct pci_de
+       struct ivshmem_regs __iomem *regs;
+       resource_size_t shmaddr;
+       resource_size_t shmlen;
+-      int interrupt;
+       char *device_name;
+       void *shm;
+       u32 ivpos;
+-      int err;
++      int ret;
+-      err = pcim_enable_device(pdev);
+-      if (err) {
+-              dev_err(&pdev->dev, "pci_enable_device: %d\n", err);
+-              return err;
++      ret = pcim_enable_device(pdev);
++      if (ret) {
++              dev_err(&pdev->dev, "pci_enable_device: %d\n", ret);
++              return ret;
+       }
+-      err = pcim_iomap_regions(pdev, BIT(0), DRV_NAME);
+-      if (err) {
+-              dev_err(&pdev->dev, "pcim_iomap_regions: %d\n", err);
+-              return err;
++      ret = pcim_iomap_regions(pdev, BIT(0), DRV_NAME);
++      if (ret) {
++              dev_err(&pdev->dev, "pcim_iomap_regions: %d\n", ret);
++              return ret;
+       }
+       regs = pcim_iomap_table(pdev)[0];
+@@ -869,8 +866,8 @@ static int ivshm_net_probe(struct pci_de
+       spin_lock_init(&in->tx_free_lock);
+       spin_lock_init(&in->tx_clean_lock);
+-      err = ivshm_net_calc_qsize(ndev);
+-      if (err)
++      ret = ivshm_net_calc_qsize(ndev);
++      if (ret)
+               goto err_free;
+       in->state_wq = alloc_ordered_workqueue(device_name, 0);
+@@ -889,25 +886,21 @@ static int ivshm_net_probe(struct pci_de
+       netif_carrier_off(ndev);
+       netif_napi_add(ndev, &in->napi, ivshm_net_poll, NAPI_POLL_WEIGHT);
+-      err = register_netdev(ndev);
+-      if (err)
++      ret = register_netdev(ndev);
++      if (ret)
+               goto err_wq;
+-      err = pci_enable_msix(pdev, &in->msix, 1);
+-      if (!err) {
+-              interrupt = in->msix.vector;
+-              in->using_msix = true;
+-      } else {
+-              interrupt = pdev->irq;
+-              in->using_msix = false;
+-      }
+-
+-      err = request_irq(interrupt, ivshm_net_int, 0, device_name, ndev);
+-      if (err)
+-              goto err_int;
++      ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY | PCI_IRQ_MSIX);
++      if (ret < 0)
++              goto err_alloc_irq;
++
++      ret = request_irq(pci_irq_vector(pdev, 0), ivshm_net_int, 0,
++                        device_name, ndev);
++      if (ret)
++              goto err_request_irq;
+       pci_set_master(pdev);
+-      if (!in->using_msix)
++      if (!pdev->msix_enabled)
+               writel(IVSHMEM_INTX_ENABLE, &in->ivshm_regs->intxctrl);
+       writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
+@@ -915,16 +908,16 @@ static int ivshm_net_probe(struct pci_de
+       return 0;
+-err_int:
+-      if (in->using_msix)
+-              pci_disable_msix(pdev);
++err_request_irq:
++      pci_free_irq_vectors(pdev);
++err_alloc_irq:
+       unregister_netdev(ndev);
+ err_wq:
+       destroy_workqueue(in->state_wq);
+ err_free:
+       free_netdev(ndev);
+-      return err;
++      return ret;
+ }
+ static void ivshm_net_remove(struct pci_dev *pdev)
+@@ -934,13 +927,10 @@ static void ivshm_net_remove(struct pci_
+       writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
+-      if (in->using_msix)  {
+-              free_irq(in->msix.vector, ndev);
+-              pci_disable_msix(pdev);
+-      } else {
++      if (!pdev->msix_enabled)
+               writel(0, &in->ivshm_regs->intxctrl);
+-              free_irq(pdev->irq, ndev);
+-      }
++      free_irq(pci_irq_vector(pdev, 0), ndev);
++      pci_free_irq_vectors(pdev);
+       unregister_netdev(ndev);
+       cancel_work_sync(&in->state_work);
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0012-ivshmem-net-fill-in-and-check-used-descriptor-chain-.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0012-ivshmem-net-fill-in-and-check-used-descriptor-chain-.patch
new file mode 100644 (file)
index 0000000..cdd9f56
--- /dev/null
@@ -0,0 +1,65 @@
+From ec72823546e39cd486360f44db16cf47f7e8f59e Mon Sep 17 00:00:00 2001
+From: Henning Schild <henning.schild@siemens.com>
+Date: Mon, 18 Sep 2017 18:02:08 +0200
+Subject: [PATCH] ivshmem-net: fill in and check used descriptor chain len
+
+We are using chains of len==1 make that explicit and expect that from
+the remote.
+
+Signed-off-by: Henning Schild <henning.schild@siemens.com>
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit f958c360044184f58605815d428b83fe4329cafd)
+---
+ drivers/net/ivshmem-net.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -335,10 +335,10 @@ static void ivshm_net_tx_clean(struct ne
+ {
+       struct ivshm_net *in = netdev_priv(ndev);
+       struct ivshm_net_queue *tx = &in->tx;
++      struct vring_used_elem *used;
+       struct vring *vr = &tx->vr;
+       struct vring_desc *desc;
+       struct vring_desc *fdesc;
+-      unsigned int used;
+       unsigned int num;
+       u16 used_idx;
+       u16 last;
+@@ -358,13 +358,14 @@ static void ivshm_net_tx_clean(struct ne
+               u32 len;
+               u32 tail;
+-              used = vr->used->ring[last & (vr->num - 1)].id;
+-              if (used >= vr->num) {
+-                      netdev_err(ndev, "invalid tx used %d\n", used);
++              used = vr->used->ring + (last % vr->num);
++              if (used->id >= vr->num || used->len != 1) {
++                      netdev_err(ndev, "invalid tx used->id %d ->len %d\n",
++                                 used->id, used->len);
+                       break;
+               }
+-              desc = &vr->desc[used];
++              desc = &vr->desc[used->id];
+               data = ivshm_net_desc_data(in, &in->tx, desc, &len);
+               if (!data) {
+@@ -383,7 +384,7 @@ static void ivshm_net_tx_clean(struct ne
+               else
+                       desc->next = fhead;
+-              fhead = used;
++              fhead = used->id;
+               last++;
+               num++;
+       }
+@@ -433,6 +434,7 @@ static void ivshm_net_rx_finish(struct i
+       used = rx->last_used_idx++ & (vr->num - 1);
+       vr->used->ring[used].id = desc_id;
++      vr->used->ring[used].len = 1;
+       virt_store_release(&vr->used->idx, rx->last_used_idx);
+ }
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0013-ivshmem-net-slightly-improve-debug-output.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0013-ivshmem-net-slightly-improve-debug-output.patch
new file mode 100644 (file)
index 0000000..e671fc0
--- /dev/null
@@ -0,0 +1,25 @@
+From 4ee8d876b25a1345804b66213b92a69602abdd83 Mon Sep 17 00:00:00 2001
+From: Henning Schild <henning.schild@siemens.com>
+Date: Mon, 18 Sep 2017 18:02:10 +0200
+Subject: [PATCH] ivshmem-net: slightly improve debug output
+
+There where two lines with the same error message, change one of them.
+
+Signed-off-by: Henning Schild <henning.schild@siemens.com>
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit d66af388dd2512ea7c7a776c731409854ed40a45)
+---
+ drivers/net/ivshmem-net.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -369,7 +369,7 @@ static void ivshm_net_tx_clean(struct ne
+               data = ivshm_net_desc_data(in, &in->tx, desc, &len);
+               if (!data) {
+-                      netdev_err(ndev, "bad tx descriptor\n");
++                      netdev_err(ndev, "bad tx descriptor, data == NULL\n");
+                       break;
+               }
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0014-ivshmem-net-set-and-check-descriptor-flags.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0014-ivshmem-net-set-and-check-descriptor-flags.patch
new file mode 100644 (file)
index 0000000..b33975b
--- /dev/null
@@ -0,0 +1,39 @@
+From 3661172f5786a3d2ebe1d2244f1f08a95e1cfd09 Mon Sep 17 00:00:00 2001
+From: Henning Schild <henning.schild@siemens.com>
+Date: Mon, 18 Sep 2017 18:02:11 +0200
+Subject: [PATCH] ivshmem-net: set and check descriptor flags
+
+We do not support the use of any flags. Make sure the remote does not
+confuse us using flags.
+
+Signed-off-by: Henning Schild <henning.schild@siemens.com>
+[Jan: Remove wrong removal of next field initialization]
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit 986d58d84245e023a1a66ab6495b354b6b8cd2f0)
+---
+ drivers/net/ivshmem-net.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -123,8 +123,12 @@ static void *ivshm_net_desc_data(struct
+ {
+       u64 offs = READ_ONCE(desc->addr);
+       u32 dlen = READ_ONCE(desc->len);
++      u16 flags = READ_ONCE(desc->flags);
+       void *data;
++      if (flags)
++              return NULL;
++
+       if (offs >= in->shmlen)
+               return NULL;
+@@ -317,6 +321,7 @@ static int ivshm_net_tx_frame(struct net
+       desc->addr = buf - in->shm;
+       desc->len = skb->len;
++      desc->flags = 0;
+       avail = tx->last_avail_idx++ & (vr->num - 1);
+       vr->avail->ring[avail] = desc_idx;
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0015-ivshmem-net-add-MAC-changing-interface.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0015-ivshmem-net-add-MAC-changing-interface.patch
new file mode 100644 (file)
index 0000000..60fe1e6
--- /dev/null
@@ -0,0 +1,37 @@
+From f5dbd1fdd5bf0a85bda432066855f563105fbf9d Mon Sep 17 00:00:00 2001
+From: Henning Schild <henning.schild@siemens.com>
+Date: Wed, 27 Sep 2017 12:59:49 +0200
+Subject: [PATCH] ivshmem-net: add MAC changing interface
+
+Allow ifconfig, ip and other such tools to change the MAC of the
+virtual NIC.
+
+Signed-off-by: Henning Schild <henning.schild@siemens.com>
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit 7744d59d11101f75afaa6f550cabba38c2c0d260)
+---
+ drivers/net/ivshmem-net.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -685,12 +685,14 @@ static void ivshm_net_poll_controller(st
+ #endif
+ static const struct net_device_ops ivshm_net_ops = {
+-      .ndo_open       = ivshm_net_open,
+-      .ndo_stop       = ivshm_net_stop,
+-      .ndo_start_xmit = ivshm_net_xmit,
+-      .ndo_change_mtu = ivshm_net_change_mtu,
++      .ndo_open               = ivshm_net_open,
++      .ndo_stop               = ivshm_net_stop,
++      .ndo_start_xmit         = ivshm_net_xmit,
++      .ndo_change_mtu         = ivshm_net_change_mtu,
++      .ndo_set_mac_address    = eth_mac_addr,
++      .ndo_validate_addr      = eth_validate_addr,
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+-      .ndo_poll_controller = ivshm_net_poll_controller,
++      .ndo_poll_controller    = ivshm_net_poll_controller,
+ #endif
+ };
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0016-ivshmem-net-Silence-compiler-warning.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0016-ivshmem-net-Silence-compiler-warning.patch
new file mode 100644 (file)
index 0000000..9094503
--- /dev/null
@@ -0,0 +1,24 @@
+From efa3ff9e6dfa3ff26c3aef463529047f7285f890 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Tue, 3 Oct 2017 12:24:59 +0200
+Subject: [PATCH] ivshmem-net: Silence compiler warning
+
+At least Linaro's gcc 6.3 does not see the initialization and usage
+dependency of fhead and num. Let's silence this false positive.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit 4d067d37d835c35e8f85481b97c51f20b713ae71)
+---
+ drivers/net/ivshmem-net.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -356,6 +356,7 @@ static void ivshm_net_tx_clean(struct ne
+       last = tx->last_used_idx;
+       fdesc = NULL;
++      fhead = 0;
+       num = 0;
+       while (last != used_idx) {
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0017-ivshmem-net-Fix-bogus-transition-to-RESET-state.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0017-ivshmem-net-Fix-bogus-transition-to-RESET-state.patch
new file mode 100644 (file)
index 0000000..688ad57
--- /dev/null
@@ -0,0 +1,27 @@
+From f9c647d5df14aab2ce40b77a2d8daf9e2065a165 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 4 Mar 2018 13:16:04 +0100
+Subject: [PATCH] ivshmem-net: Fix bogus transition to RESET state
+
+If we are in READY but the remote is still in INIT, we so far fell back
+to RESET which caused the setup to get stuck. Fix this by only
+transitioning from READY/RUN to RESET in ivshm_net_state_change if the
+remote is in RESET as well.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit b58915e11eba2643d5c68ea0328823a62c21dc49)
+---
+ drivers/net/ivshmem-net.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -598,7 +598,7 @@ static void ivshm_net_state_change(struc
+               if (rstate >= IVSHM_NET_STATE_READY) {
+                       netif_carrier_on(ndev);
+                       ivshm_net_run(ndev);
+-              } else {
++              } else if (rstate == IVSHM_NET_STATE_RESET) {
+                       netif_carrier_off(ndev);
+                       ivshm_net_do_stop(ndev);
+               }
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0018-ivshmem-net-Refactor-and-comment-ivshm_net_state_cha.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0018-ivshmem-net-Refactor-and-comment-ivshm_net_state_cha.patch
new file mode 100644 (file)
index 0000000..cb3ffcc
--- /dev/null
@@ -0,0 +1,63 @@
+From 5192fa99f0d267eb7bd1c79e556430ea8911ae38 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 4 Mar 2018 13:50:24 +0100
+Subject: [PATCH] ivshmem-net: Refactor and comment ivshm_net_state_change
+
+This should make the state transitioning logic clearer. Also avoid the
+harmless but redundant netif_carrier_on/ivshm_net_run in RUN state.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit 8539efe70fbdf4a0bea75a97c1628fbb38b6590b)
+---
+ drivers/net/ivshmem-net.c | 23 ++++++++++++++++++++---
+ 1 file changed, 20 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -575,14 +575,21 @@ static void ivshm_net_state_change(struc
+       struct net_device *ndev = in->napi.dev;
+       u32 rstate = readl(&in->ivshm_regs->rstate);
+-
+       switch (in->lstate) {
+       case IVSHM_NET_STATE_RESET:
++              /*
++               * Wait for the remote to leave READY/RUN before transitioning
++               * to INIT.
++               */
+               if (rstate < IVSHM_NET_STATE_READY)
+                       ivshm_net_set_state(in, IVSHM_NET_STATE_INIT);
+               break;
+       case IVSHM_NET_STATE_INIT:
++              /*
++               * Wait for the remote to leave RESET before performing the
++               * initialization and moving to READY.
++               */
+               if (rstate > IVSHM_NET_STATE_RESET) {
+                       ivshm_net_init_queues(ndev);
+                       ivshm_net_set_state(in, IVSHM_NET_STATE_READY);
+@@ -594,11 +601,21 @@ static void ivshm_net_state_change(struc
+               break;
+       case IVSHM_NET_STATE_READY:
+-      case IVSHM_NET_STATE_RUN:
++              /*
++               * Link is up and we are running once the remote is in READY or
++               * RUN.
++               */
+               if (rstate >= IVSHM_NET_STATE_READY) {
+                       netif_carrier_on(ndev);
+                       ivshm_net_run(ndev);
+-              } else if (rstate == IVSHM_NET_STATE_RESET) {
++                      break;
++              }
++              /* fall through */
++      case IVSHM_NET_STATE_RUN:
++              /*
++               * If the remote goes to RESET, we need to follow immediately.
++               */
++              if (rstate == IVSHM_NET_STATE_RESET) {
+                       netif_carrier_off(ndev);
+                       ivshm_net_do_stop(ndev);
+               }
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0019-ivshmem-net-Switch-to-netdev_xmit_more-helper.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0019-ivshmem-net-Switch-to-netdev_xmit_more-helper.patch
new file mode 100644 (file)
index 0000000..3346871
--- /dev/null
@@ -0,0 +1,55 @@
+From 6732a2821cf7eeffa284253f80fd757e1ac2df4f Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 2 Jun 2019 11:58:20 +0200
+Subject: [PATCH] ivshmem-net: Switch to netdev_xmit_more helper
+
+The skb field has been removed by 4f296edeb9d4.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit 80c301552ec0b500dd46a2b4f0c9fef78a610ee6)
+---
+ drivers/net/ivshmem-net.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ivshmem-net.c
++++ b/drivers/net/ivshmem-net.c
+@@ -294,7 +294,8 @@ static u32 ivshm_net_tx_advance(struct i
+       return p;
+ }
+-static int ivshm_net_tx_frame(struct net_device *ndev, struct sk_buff *skb)
++static int ivshm_net_tx_frame(struct net_device *ndev, struct sk_buff *skb,
++                            bool xmit_more)
+ {
+       struct ivshm_net *in = netdev_priv(ndev);
+       struct ivshm_net_queue *tx = &in->tx;
+@@ -327,7 +328,7 @@ static int ivshm_net_tx_frame(struct net
+       vr->avail->ring[avail] = desc_idx;
+       tx->num_added++;
+-      if (!skb->xmit_more) {
++      if (!xmit_more) {
+               virt_store_release(&vr->avail->idx, tx->last_avail_idx);
+               ivshm_net_notify_tx(in, tx->num_added);
+               tx->num_added = 0;
+@@ -509,17 +510,18 @@ static int ivshm_net_poll(struct napi_st
+ static netdev_tx_t ivshm_net_xmit(struct sk_buff *skb, struct net_device *ndev)
+ {
+       struct ivshm_net *in = netdev_priv(ndev);
++      bool xmit_more = netdev_xmit_more();
+       ivshm_net_tx_clean(ndev);
+       if (!ivshm_net_tx_ok(in, ndev->mtu)) {
+               ivshm_net_enable_tx_irq(in);
+               netif_stop_queue(ndev);
+-              skb->xmit_more = 0;
++              xmit_more = false;
+               in->stats.tx_pause++;
+       }
+-      ivshm_net_tx_frame(ndev, skb);
++      ivshm_net_tx_frame(ndev, skb, xmit_more);
+       in->stats.tx_packets++;
+       ndev->stats.tx_packets++;
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0020-jailhouse-Add-simple-debug-console-via-the-hyperviso.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0020-jailhouse-Add-simple-debug-console-via-the-hyperviso.patch
new file mode 100644 (file)
index 0000000..85ea961
--- /dev/null
@@ -0,0 +1,164 @@
+From 58d058f1fe1cc5981c57be8b48d3b2f74f25c0d6 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Sun, 11 Sep 2016 23:30:04 +0200
+Subject: [PATCH] jailhouse: Add simple debug console via the hypervisor
+
+Jailhouse allows explicitly enabled cells to write character-wise
+messages to the hypervisor debug console. Make use of this for a
+platform-agnostic boot diagnosis channel, specifically for non-root
+cells. This also comes with earlycon support.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+(cherry picked from commit 60685bd589aef4972d20724863079edf2039eaa2)
+From http://git.kiszka.org/?p=linux.git;a=shortlog;h=refs/heads/queues/jailhouse
+---
+ MAINTAINERS                     |   1 +
+ drivers/virt/Kconfig            |  11 +++++
+ drivers/virt/Makefile           |   1 +
+ drivers/virt/jailhouse_dbgcon.c | 103 ++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 116 insertions(+)
+ create mode 100644 drivers/virt/jailhouse_dbgcon.c
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -8772,6 +8772,7 @@ L:       jailhouse-dev@googlegroups.com
+ S:    Maintained
+ F:    arch/x86/kernel/jailhouse.c
+ F:    arch/x86/include/asm/jailhouse_para.h
++F:    drivers/virt/jailhouse_dbgcon.c
+ JC42.4 TEMPERATURE SENSOR DRIVER
+ M:    Guenter Roeck <linux@roeck-us.net>
+--- a/drivers/virt/Kconfig
++++ b/drivers/virt/Kconfig
+@@ -31,5 +31,16 @@ config FSL_HV_MANAGER
+           4) A kernel interface for receiving callbacks when a managed
+            partition shuts down.
++config JAILHOUSE_DBGCON
++      tristate "Jailhouse console driver"
++      depends on X86 || ARM || ARM64
++      help
++        The Jailhouse hypervisor provides a simple write-only console for
++        debugging the bootstrap process of its cells. This driver registers
++        a console with the kernel to make use of it.
++
++        Note that Jailhouse has to be configured to permit a cell the usage
++        of the console interface.
++
+ source "drivers/virt/vboxguest/Kconfig"
+ endif
+--- a/drivers/virt/Makefile
++++ b/drivers/virt/Makefile
+@@ -4,4 +4,5 @@
+ #
+ obj-$(CONFIG_FSL_HV_MANAGER)  += fsl_hypervisor.o
++obj-$(CONFIG_JAILHOUSE_DBGCON)        += jailhouse_dbgcon.o
+ obj-y                         += vboxguest/
+--- /dev/null
++++ b/drivers/virt/jailhouse_dbgcon.c
+@@ -0,0 +1,103 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Console driver for running over the Jailhouse partitioning hypervisor
++ *
++ * Copyright (c) Siemens AG, 2016-2018
++ *
++ * Authors:
++ *  Jan Kiszka <jan.kiszka@siemens.com>
++ */
++
++#include <linux/console.h>
++#include <linux/hypervisor.h>
++#include <linux/module.h>
++#include <linux/serial_core.h>
++#ifdef CONFIG_X86
++#include <asm/alternative.h>
++#endif
++#ifdef CONFIG_ARM
++#include <asm/opcodes-virt.h>
++#endif
++
++#define JAILHOUSE_HC_DEBUG_CONSOLE_PUTC               8
++
++static void hypervisor_putc(char c)
++{
++#if defined(CONFIG_X86)
++      int result;
++
++      asm volatile(
++              ALTERNATIVE(".byte 0x0f,0x01,0xc1", ".byte 0x0f,0x01,0xd9",
++                          X86_FEATURE_VMMCALL)
++              : "=a" (result)
++              : "a" (JAILHOUSE_HC_DEBUG_CONSOLE_PUTC), "D" (c)
++              : "memory");
++#elif defined(CONFIG_ARM)
++      register u32 num_res asm("r0") = JAILHOUSE_HC_DEBUG_CONSOLE_PUTC;
++      register u32 arg1 asm("r1") = c;
++
++      asm volatile(
++              __HVC(0x4a48)
++              : "=r" (num_res)
++              : "r" (num_res), "r" (arg1)
++              : "memory");
++#elif defined(CONFIG_ARM64)
++      register u64 num_res asm("x0") = JAILHOUSE_HC_DEBUG_CONSOLE_PUTC;
++      register u64 arg1 asm("x1") = c;
++
++      asm volatile(
++              "hvc #0x4a48\n\t"
++              : "=r" (num_res)
++              : "r" (num_res), "r" (arg1)
++              : "memory");
++#else
++#error Unsupported architecture.
++#endif
++}
++
++static void jailhouse_dbgcon_write(struct console *con, const char *s,
++                                 unsigned count)
++{
++      while (count > 0) {
++              hypervisor_putc(*s);
++              count--;
++              s++;
++      }
++}
++
++static int __init early_jailhouse_dbgcon_setup(struct earlycon_device *device,
++                                             const char *options)
++{
++      device->con->write = jailhouse_dbgcon_write;
++      return 0;
++}
++
++EARLYCON_DECLARE(jailhouse, early_jailhouse_dbgcon_setup);
++
++static struct console jailhouse_dbgcon = {
++      .name = "jailhouse",
++      .write = jailhouse_dbgcon_write,
++      .flags = CON_PRINTBUFFER | CON_ANYTIME,
++      .index = -1,
++};
++
++static int __init jailhouse_dbgcon_init(void)
++{
++      if (!jailhouse_paravirt())
++              return -ENODEV;
++
++      register_console(&jailhouse_dbgcon);
++      return 0;
++}
++
++static void __exit jailhouse_dbgcon_exit(void)
++{
++      unregister_console(&jailhouse_dbgcon);
++}
++
++module_init(jailhouse_dbgcon_init);
++module_exit(jailhouse_dbgcon_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("Jailhouse debug console driver");
++MODULE_AUTHOR("Jan Kiszka <jan.kiszka@siemens.com>");
diff --git a/target/linux/layerscape/patches-5.4/809-jailhouse-0021-arm64-export-__hyp_stub_vectors.patch b/target/linux/layerscape/patches-5.4/809-jailhouse-0021-arm64-export-__hyp_stub_vectors.patch
new file mode 100644 (file)
index 0000000..e523b56
--- /dev/null
@@ -0,0 +1,35 @@
+From a6445874f3371aee451f79c67168f8c4f95d6438 Mon Sep 17 00:00:00 2001
+From: Peng Fan <peng.fan@nxp.com>
+Date: Fri, 15 Nov 2019 17:07:52 +0800
+Subject: [PATCH] arm64: export __hyp_stub_vectors
+
+External hypervisors, like Jailhouse, need this address when they are
+deactivated, in order to restore original state.
+
+Signed-off-by: Peng Fan <peng.fan@nxp.com>
+---
+ arch/arm64/include/asm/virt.h | 2 ++
+ arch/arm64/kernel/hyp-stub.S  | 1 +
+ 2 files changed, 3 insertions(+)
+
+--- a/arch/arm64/include/asm/virt.h
++++ b/arch/arm64/include/asm/virt.h
+@@ -62,6 +62,8 @@
+  */
+ extern u32 __boot_cpu_mode[2];
++extern char __hyp_stub_vectors[];
++
+ void __hyp_set_vectors(phys_addr_t phys_vector_base);
+ void __hyp_reset_vectors(void);
+--- a/arch/arm64/kernel/hyp-stub.S
++++ b/arch/arm64/kernel/hyp-stub.S
+@@ -42,6 +42,7 @@ ENTRY(__hyp_stub_vectors)
+       ventry  el1_fiq_invalid                 // FIQ 32-bit EL1
+       ventry  el1_error_invalid               // Error 32-bit EL1
+ ENDPROC(__hyp_stub_vectors)
++EXPORT_SYMBOL(__hyp_stub_vectors);
+       .align 11
diff --git a/target/linux/layerscape/patches-5.4/810-keys-0001-security-keys-secure_key-Adds-the-secure-key-support.patch b/target/linux/layerscape/patches-5.4/810-keys-0001-security-keys-secure_key-Adds-the-secure-key-support.patch
new file mode 100644 (file)
index 0000000..a681e2d
--- /dev/null
@@ -0,0 +1,1285 @@
+From 808871b2943a386165614daf2e7f5fb5b33e9fd1 Mon Sep 17 00:00:00 2001
+From: Udit Agarwal <udit.agarwal@nxp.com>
+Date: Wed, 4 Jul 2018 09:51:59 +0530
+Subject: [PATCH] security/keys/secure_key: Adds the secure key support based
+ on CAAM.
+
+Secure keys are derieved using CAAM crypto block.
+
+Secure keys derieved are the random number symmetric keys from CAAM.
+Blobs corresponding to the key are formed using CAAM. User space
+will only be able to view the blob of the key.
+
+Signed-off-by: Udit Agarwal <udit.agarwal@nxp.com>
+Reviewed-by: Sahil Malhotra <sahil.malhotra@nxp.com>
+---
+ Documentation/security/keys/secure-key.rst |  67 ++++
+ MAINTAINERS                                |  11 +
+ include/keys/secure-type.h                 |  33 ++
+ security/keys/Kconfig                      |  11 +
+ security/keys/Makefile                     |   5 +
+ security/keys/secure_key.c                 | 339 ++++++++++++++++
+ security/keys/securekey_desc.c             | 608 +++++++++++++++++++++++++++++
+ security/keys/securekey_desc.h             | 141 +++++++
+ 8 files changed, 1215 insertions(+)
+ create mode 100644 Documentation/security/keys/secure-key.rst
+ create mode 100644 include/keys/secure-type.h
+ create mode 100644 security/keys/secure_key.c
+ create mode 100644 security/keys/securekey_desc.c
+ create mode 100644 security/keys/securekey_desc.h
+
+--- /dev/null
++++ b/Documentation/security/keys/secure-key.rst
+@@ -0,0 +1,67 @@
++==========
++Secure Key
++==========
++
++Secure key is the new type added to kernel key ring service.
++Secure key is a symmetric type key of minimum length 32 bytes
++and with maximum possible length to be 128 bytes. It is produced
++in kernel using the CAAM crypto engine. Userspace can only see
++the blob for the corresponding key. All the blobs are displayed
++or loaded in hex ascii.
++
++Secure key can be created on platforms which supports CAAM
++hardware block. Secure key can also be used as a master key to
++create the encrypted keys along with the existing key types in
++kernel.
++
++Secure key uses CAAM hardware to generate the key and blobify its
++content for userspace. Generated blobs are tied up with the hardware
++secret key stored in CAAM, hence the same blob will not be able to
++de-blobify with the different secret key on another machine.
++
++Usage::
++
++      keyctl add secure <name> "new <keylen>" <ring>
++      keyctl load secure <name> "load <hex_blob>" <ring>
++      keyctl print <key_id>
++
++"keyctl add secure" option will create the random data of the
++specified key len using CAAM and store it as a key in kernel.
++Key contents will be displayed as blobs to the user in hex ascii.
++User can input key len from 32 bytes to 128 bytes.
++
++"keyctl load secure" option will load the blob contents. In kernel,
++key will be deirved using input blob and CAAM, along with the secret
++key stored in CAAM.
++
++"keyctl print" will return the hex string of the blob corresponding to
++key_id. Returned blob will be of key_len + 48 bytes. Extra 48 bytes are
++the header bytes added by the CAAM.
++
++Example of secure key usage::
++
++1. Create the secure key with name kmk-master of length 32 bytes::
++
++      $ keyctl add secure kmk-master "new 32" @u
++      46001928
++
++      $keyctl show
++      Session Keyring
++      1030783626 --alswrv      0 65534  keyring: _uid_ses.0
++       695927745 --alswrv      0 65534   \_ keyring: _uid.0
++        46001928 --als-rv      0     0       \_ secure: kmk-master
++
++2. Print the blob contents for the kmk-master key::
++
++      $ keyctl print 46001928
++      d9743445b640f3d59c1670dddc0bc9c2
++      34fc9aab7dd05c965e6120025012f029b
++      07faa4776c4f6ed02899e35a135531e9a
++      6e5c2b51132f9d5aef28f68738e658296
++      3fe583177cfe50d2542b659a13039
++
++      $ keyctl pipe 46001928 > secure_key.blob
++
++3. Load the blob in the user key ring::
++
++      $ keyctl load secure kmk-master "load 'cat secure_key.blob'" @u
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -9073,6 +9073,17 @@ F:      include/keys/trusted-type.h
+ F:    security/keys/trusted.c
+ F:    include/keys/trusted.h
++KEYS-SECURE
++M:    Udit Agarwal <udit.agarwal@nxp.com>
++R:    Sahil Malhotra <sahil.malhotra@nxp.com>
++L:    linux-security-module@vger.kernel.org
++L:    keyrings@vger.kernel.org
++S:    Supported
++F:    include/keys/secure-type.h
++F:    security/keys/secure_key.c
++F:    security/keys/securekey_desc.c
++F:    security/keys/securekey_desc.h
++
+ KEYS/KEYRINGS:
+ M:    David Howells <dhowells@redhat.com>
+ M:    Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+--- /dev/null
++++ b/include/keys/secure-type.h
+@@ -0,0 +1,33 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2018 NXP.
++ *
++ */
++
++#ifndef _KEYS_SECURE_TYPE_H
++#define _KEYS_SECURE_TYPE_H
++
++#include <linux/key.h>
++#include <linux/rcupdate.h>
++
++/* Minimum key size to be used is 32 bytes and maximum key size fixed
++ * is 128 bytes.
++ * Blob size to be kept is Maximum key size + blob header added by CAAM.
++ */
++
++#define MIN_KEY_SIZE                    32
++#define MAX_KEY_SIZE                    128
++#define BLOB_HEADER_SIZE              48
++
++#define MAX_BLOB_SIZE                   (MAX_KEY_SIZE + BLOB_HEADER_SIZE)
++
++struct secure_key_payload {
++      struct rcu_head rcu;
++      unsigned int key_len;
++      unsigned int blob_len;
++      unsigned char key[MAX_KEY_SIZE + 1];
++      unsigned char blob[MAX_BLOB_SIZE];
++};
++
++extern struct key_type key_type_secure;
++#endif
+--- a/security/keys/Kconfig
++++ b/security/keys/Kconfig
+@@ -90,6 +90,17 @@ config TRUSTED_KEYS
+         If you are unsure as to whether this is required, answer N.
++config SECURE_KEYS
++      tristate "SECURE_KEYS"
++      depends on KEYS && CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR
++      help
++        This option provide support for creating secure-type key and blobs
++        in kernel. Secure keys are random number symmetric keys generated
++        from CAAM. The CAAM creates the blobs for the random key.
++        Userspace will only be able to see the blob.
++
++        If you are unsure as to whether this is required, answer N.
++
+ config ENCRYPTED_KEYS
+       tristate "ENCRYPTED KEYS"
+       depends on KEYS
+--- a/security/keys/Makefile
++++ b/security/keys/Makefile
+@@ -29,4 +29,9 @@ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += key
+ #
+ obj-$(CONFIG_BIG_KEYS) += big_key.o
+ obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
++CFLAGS_secure_key.o += -I$(obj)/../../drivers/crypto/caam/
++CFLAGS_securekey_desc.o += -I$(obj)/../../drivers/crypto/caam/
++obj-$(CONFIG_SECURE_KEYS) += securekey.o
++securekey-y := securekey_desc.o \
++             secure_key.o
+ obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/
+--- /dev/null
++++ b/security/keys/secure_key.c
+@@ -0,0 +1,339 @@
++// SPDX-License-Identifier: GPL-2.0
++/* Copyright (C) 2018 NXP
++ * Secure key is generated using NXP CAAM hardware block. CAAM generates the
++ * random number (used as a key) and creates its blob for the user.
++ */
++
++#include <linux/slab.h>
++#include <linux/parser.h>
++#include <linux/string.h>
++#include <linux/key-type.h>
++#include <linux/rcupdate.h>
++#include <keys/secure-type.h>
++#include <linux/completion.h>
++
++#include "securekey_desc.h"
++
++static const char hmac_alg[] = "hmac(sha1)";
++static const char hash_alg[] = "sha1";
++
++static struct crypto_shash *hashalg;
++static struct crypto_shash *hmacalg;
++
++enum {
++      error = -1,
++      new_key,
++      load_blob,
++};
++
++static const match_table_t key_tokens = {
++      {new_key, "new"},
++      {load_blob, "load"},
++      {error, NULL}
++};
++
++static struct secure_key_payload *secure_payload_alloc(struct key *key)
++{
++      struct secure_key_payload *sec_key = NULL;
++      int ret = 0;
++
++      ret = key_payload_reserve(key, sizeof(*sec_key));
++      if (ret < 0)
++              goto out;
++
++      sec_key = kzalloc(sizeof(*sec_key), GFP_KERNEL);
++      if (!sec_key)
++              goto out;
++
++out:
++      return sec_key;
++}
++
++/*
++ * parse_inputdata - parse the keyctl input data and fill in the
++ *                 payload structure for key or its blob.
++ * param[in]: data pointer to the data to be parsed for creating key.
++ * param[in]: p pointer to secure key payload structure to fill parsed data
++ * On success returns 0, otherwise -EINVAL.
++ */
++static int parse_inputdata(char *data, struct secure_key_payload *p)
++{
++      substring_t args[MAX_OPT_ARGS];
++      long keylen = 0;
++      int ret = -EINVAL;
++      int key_cmd = -EINVAL;
++      char *c = NULL;
++
++      c = strsep(&data, " \t");
++      if (!c) {
++              ret = -EINVAL;
++              goto out;
++      }
++
++      /* Get the keyctl command i.e. new_key or load_blob etc */
++      key_cmd = match_token(c, key_tokens, args);
++
++      switch (key_cmd) {
++      case new_key:
++              /* first argument is key size */
++              c = strsep(&data, " \t");
++              if (!c) {
++                      ret = -EINVAL;
++                      goto out;
++              }
++
++              ret = kstrtol(c, 10, &keylen);
++              if (ret < 0 || keylen < MIN_KEY_SIZE ||
++                                              keylen > MAX_KEY_SIZE) {
++                      ret = -EINVAL;
++                      goto out;
++              }
++
++              p->key_len = keylen;
++              ret = new_key;
++
++              break;
++      case load_blob:
++              /* first argument is blob data for CAAM*/
++              c = strsep(&data, " \t");
++              if (!c) {
++                      ret = -EINVAL;
++                      goto out;
++              }
++
++              /* Blob_len = No of characters in blob/2 */
++              p->blob_len = strlen(c) / 2;
++              if (p->blob_len > MAX_BLOB_SIZE) {
++                      ret = -EINVAL;
++                      goto out;
++              }
++
++              ret = hex2bin(p->blob, c, p->blob_len);
++              if (ret < 0) {
++                      ret = -EINVAL;
++                      goto out;
++              }
++              ret = load_blob;
++
++              break;
++      case error:
++              ret = -EINVAL;
++              break;
++      }
++
++out:
++      return ret;
++}
++
++/*
++ * secure_instantiate - create a new secure type key.
++ * Supports the operation to generate a new key. A random number
++ * is generated from CAAM as key data and the corresponding red blob
++ * is formed and stored as key_blob.
++ * Also supports the operation to load the blob and key is derived using
++ * that blob from CAAM.
++ * On success, return 0. Otherwise return errno.
++ */
++static int secure_instantiate(struct key *key,
++              struct key_preparsed_payload *prep)
++{
++      struct secure_key_payload *payload = NULL;
++      size_t datalen = prep->datalen;
++      char *data = NULL;
++      int key_cmd = 0;
++      int ret = 0;
++      enum sk_req_type sk_op_type;
++      struct device *dev = NULL;
++
++      if (datalen <= 0 || datalen > 32767 || !prep->data) {
++              ret = -EINVAL;
++              goto out;
++      }
++
++      data = kmalloc(datalen + 1, GFP_KERNEL);
++      if (!data) {
++              ret = -ENOMEM;
++              goto out;
++      }
++
++      memcpy(data, prep->data, datalen);
++      data[datalen] = '\0';
++
++      payload = secure_payload_alloc(key);
++      if (!payload) {
++              ret = -ENOMEM;
++              goto out;
++      }
++
++      /* Allocate caam job ring for operation to be performed from CAAM */
++      dev = caam_jr_alloc();
++      if (!dev) {
++              pr_info("caam_jr_alloc failed\n");
++              ret = -ENODEV;
++              goto out;
++      }
++
++      key_cmd = parse_inputdata(data, payload);
++      if (key_cmd < 0) {
++              ret = key_cmd;
++              goto out;
++      }
++
++      switch (key_cmd) {
++      case load_blob:
++              /*
++               * Red blob decryption to be done for load operation
++               * to derive the key.
++               */
++              sk_op_type = sk_red_blob_dec;
++              ret = key_deblob(payload, sk_op_type, dev);
++              if (ret != 0) {
++                      pr_info("secure_key: key_blob decap fail (%d)\n", ret);
++                      goto out;
++              }
++              break;
++      case new_key:
++              /* Get Random number from caam of the specified length */
++              sk_op_type = sk_get_random;
++              ret = caam_get_random(payload, sk_op_type, dev);
++              if (ret != 0) {
++                      pr_info("secure_key: get_random fail (%d)\n", ret);
++                      goto out;
++              }
++
++              /* Generate red blob of key random bytes with CAAM */
++              sk_op_type = sk_red_blob_enc;
++              ret = key_blob(payload, sk_op_type, dev);
++              if (ret != 0) {
++                      pr_info("secure_key: key_blob encap fail (%d)\n", ret);
++                      goto out;
++              }
++              break;
++      default:
++              ret = -EINVAL;
++              goto out;
++      }
++out:
++      if (data)
++              kzfree(data);
++      if (dev)
++              caam_jr_free(dev);
++
++      if (!ret)
++              rcu_assign_keypointer(key, payload);
++      else
++              kzfree(payload);
++
++      return ret;
++}
++
++/*
++ * secure_read - copy the  blob data to userspace in hex.
++ * param[in]: key pointer to key struct
++ * param[in]: buffer pointer to user data for creating key
++ * param[in]: buflen is the length of the buffer
++ * On success, return to userspace the secure key data size.
++ */
++static long secure_read(const struct key *key, char __user *buffer,
++                       size_t buflen)
++{
++      const struct secure_key_payload *p = NULL;
++      char *ascii_buf;
++      char *bufp;
++      int i;
++
++      p = dereference_key_locked(key);
++      if (!p)
++              return -EINVAL;
++
++      if (buffer && buflen >= 2 * p->blob_len) {
++              ascii_buf = kmalloc(2 * p->blob_len, GFP_KERNEL);
++              if (!ascii_buf)
++                      return -ENOMEM;
++
++              bufp = ascii_buf;
++              for (i = 0; i < p->blob_len; i++)
++                      bufp = hex_byte_pack(bufp, p->blob[i]);
++              if (copy_to_user(buffer, ascii_buf, 2 * p->blob_len) != 0) {
++                      kzfree(ascii_buf);
++                      return -EFAULT;
++              }
++              kzfree(ascii_buf);
++      }
++      return 2 * p->blob_len;
++}
++
++/*
++ * secure_destroy - clear and free the key's payload
++ */
++static void secure_destroy(struct key *key)
++{
++      kzfree(key->payload.data[0]);
++}
++
++struct key_type key_type_secure = {
++      .name = "secure",
++      .instantiate = secure_instantiate,
++      .destroy = secure_destroy,
++      .read = secure_read,
++};
++EXPORT_SYMBOL_GPL(key_type_secure);
++
++static void secure_shash_release(void)
++{
++      if (hashalg)
++              crypto_free_shash(hashalg);
++      if (hmacalg)
++              crypto_free_shash(hmacalg);
++}
++
++static int __init secure_shash_alloc(void)
++{
++      int ret;
++
++      hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC);
++      if (IS_ERR(hmacalg)) {
++              pr_info("secure_key: could not allocate crypto %s\n",
++                              hmac_alg);
++              return PTR_ERR(hmacalg);
++      }
++
++      hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC);
++      if (IS_ERR(hashalg)) {
++              pr_info("secure_key: could not allocate crypto %s\n",
++                              hash_alg);
++              ret = PTR_ERR(hashalg);
++              goto hashalg_fail;
++      }
++
++      return 0;
++
++hashalg_fail:
++      crypto_free_shash(hmacalg);
++      return ret;
++}
++
++static int __init init_secure_key(void)
++{
++      int ret;
++
++      ret = secure_shash_alloc();
++      if (ret < 0)
++              return ret;
++
++      ret = register_key_type(&key_type_secure);
++      if (ret < 0)
++              secure_shash_release();
++      return ret;
++}
++
++static void __exit cleanup_secure_key(void)
++{
++      secure_shash_release();
++      unregister_key_type(&key_type_secure);
++}
++
++late_initcall(init_secure_key);
++module_exit(cleanup_secure_key);
++
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/security/keys/securekey_desc.c
+@@ -0,0 +1,608 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2018 NXP
++ *
++ */
++
++#include <keys/secure-type.h>
++#include "securekey_desc.h"
++
++/* key modifier for blob encapsulation & decapsulation descriptor */
++u8 key_modifier[] = "SECURE_KEY";
++u32 key_modifier_len = 10;
++
++void caam_sk_rng_desc(struct sk_req *skreq, struct sk_desc *skdesc)
++{
++      struct sk_fetch_rnd_data *fetch_rnd_data = NULL;
++      struct random_desc *rnd_desc = NULL;
++      size_t len = 0;
++      u32 *desc = skreq->hwdesc;
++
++      init_job_desc(desc, 0);
++
++      fetch_rnd_data = &skreq->req_u.sk_fetch_rnd_data;
++      rnd_desc = &skdesc->dma_u.random_descp;
++      len = fetch_rnd_data->key_len;
++
++      /* command 0x82500000 */
++      append_cmd(desc, CMD_OPERATION | OP_TYPE_CLASS1_ALG |
++                      OP_ALG_ALGSEL_RNG);
++      /* command 0x60340000 | len */
++      append_cmd(desc, CMD_FIFO_STORE | FIFOST_TYPE_RNGSTORE | len);
++      append_ptr(desc, rnd_desc->rnd_data);
++}
++
++void caam_sk_redblob_encap_desc(struct sk_req *skreq, struct sk_desc *skdesc)
++{
++      struct redblob_encap_desc *red_blob_desc =
++                                      &skdesc->dma_u.redblob_encapdesc;
++      struct sk_red_blob_encap *red_blob_req =
++                                      &skreq->req_u.sk_red_blob_encap;
++      u32 *desc = skreq->hwdesc;
++
++      init_job_desc(desc, 0);
++
++      /* Load class 2 key with key modifier. */
++      append_key_as_imm(desc, key_modifier, key_modifier_len,
++                        key_modifier_len, CLASS_2 | KEY_DEST_CLASS_REG);
++
++      /* SEQ IN PTR Command. */
++      append_seq_in_ptr(desc, red_blob_desc->in_data, red_blob_req->data_sz,
++                        0);
++
++      /* SEQ OUT PTR Command. */
++      append_seq_out_ptr(desc, red_blob_desc->redblob,
++                         red_blob_req->redblob_sz, 0);
++
++      /* RedBlob encapsulation PROTOCOL Command. */
++      append_operation(desc, OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB);
++}
++
++/* void caam_sk_redblob_decap_desc(struct sk_req *skreq, struct sk_desc *skdesc)
++ * brief CAAM Descriptor creator from redblob to plaindata.
++ * param[in] skreq Pointer to secure key request structure
++ * param[in] skdesc Pointer to secure key descriptor structure
++ */
++void caam_sk_redblob_decap_desc(struct sk_req *skreq, struct sk_desc *skdesc)
++{
++      struct redblob_decap_desc *red_blob_desc =
++                                      &skdesc->dma_u.redblob_decapdesc;
++      struct sk_red_blob_decap *red_blob_req =
++                                      &skreq->req_u.sk_red_blob_decap;
++      u32 *desc = skreq->hwdesc;
++
++      init_job_desc(desc, 0);
++
++      /* Load class 2 key with key modifier. */
++      append_key_as_imm(desc, key_modifier, key_modifier_len,
++                        key_modifier_len, CLASS_2 | KEY_DEST_CLASS_REG);
++
++      /* SEQ IN PTR Command. */
++      append_seq_in_ptr(desc, red_blob_desc->redblob,
++                        red_blob_req->redblob_sz, 0);
++
++      /* SEQ OUT PTR Command. */
++      append_seq_out_ptr(desc, red_blob_desc->out_data,
++                         red_blob_req->data_sz, 0);
++
++      /* RedBlob decapsulation PROTOCOL Command. */
++      append_operation(desc, OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB);
++}
++
++/* int caam_sk_get_random_map(struct device *dev, struct sk_req *req,
++ *                          struct sk_desc *skdesc)
++ * brief DMA map the buffer virtual pointers to physical address.
++ * param[in] dev Pointer to job ring device structure
++ * param[in] req Pointer to secure key request structure
++ * param[in] skdesc Pointer to secure key descriptor structure
++ * return 0 on success, error value otherwise.
++ */
++int caam_sk_get_random_map(struct device *dev, struct sk_req *req,
++                         struct sk_desc *skdesc)
++{
++      struct sk_fetch_rnd_data *fetch_rnd_data;
++      struct random_desc *rnd_desc;
++
++      fetch_rnd_data = &req->req_u.sk_fetch_rnd_data;
++      rnd_desc = &skdesc->dma_u.random_descp;
++
++      rnd_desc->rnd_data = dma_map_single(dev, fetch_rnd_data->data,
++                              fetch_rnd_data->key_len, DMA_FROM_DEVICE);
++
++      if (dma_mapping_error(dev, rnd_desc->rnd_data)) {
++              dev_err(dev, "Unable to map memory\n");
++              goto sk_random_map_fail;
++      }
++      return 0;
++
++sk_random_map_fail:
++      return -ENOMEM;
++}
++
++/* int caam_sk_redblob_encap_map(struct device *dev, struct sk_req *req,
++ *                                    struct sk_desc *skdesc)
++ * brief DMA map the buffer virtual pointers to physical address.
++ * param[in] dev Pointer to job ring device structure
++ * param[in] req Pointer to secure key request structure
++ * param[in] skdesc Pointer to secure key descriptor structure
++ * return 0 on success, error value otherwise.
++ */
++int caam_sk_redblob_encap_map(struct device *dev, struct sk_req *req,
++                            struct sk_desc *skdesc)
++{
++      struct sk_red_blob_encap *red_blob_encap;
++      struct redblob_encap_desc *red_blob_desc;
++
++      red_blob_encap = &req->req_u.sk_red_blob_encap;
++      red_blob_desc = &skdesc->dma_u.redblob_encapdesc;
++
++      red_blob_desc->in_data = dma_map_single(dev, red_blob_encap->data,
++                                      red_blob_encap->data_sz, DMA_TO_DEVICE);
++      if (dma_mapping_error(dev, red_blob_desc->in_data)) {
++              dev_err(dev, "Unable to map memory\n");
++              goto sk_data_fail;
++      }
++
++      red_blob_desc->redblob = dma_map_single(dev, red_blob_encap->redblob,
++                              red_blob_encap->redblob_sz, DMA_FROM_DEVICE);
++      if (dma_mapping_error(dev, red_blob_desc->redblob)) {
++              dev_err(dev, "Unable to map memory\n");
++              goto sk_redblob_fail;
++      }
++
++      return 0;
++
++sk_redblob_fail:
++      dma_unmap_single(dev, red_blob_desc->in_data, red_blob_encap->data_sz,
++                       DMA_TO_DEVICE);
++sk_data_fail:
++      return -ENOMEM;
++}
++
++/* static int caam_sk_redblob_decap_map(struct device *dev,
++ *                                        struct sk_req *req,
++ *                                        struct sk_desc *skdesc)
++ * brief DMA map the buffer virtual pointers to physical address.
++ * param[in] dev Pointer to job ring device structure
++ * param[in] req Pointer to secure key request structure
++ * param[in] skdesc Pointer to secure key descriptor structure
++ * return 0 on success, error value otherwise.
++ */
++int caam_sk_redblob_decap_map(struct device *dev, struct sk_req *req,
++                            struct sk_desc *skdesc)
++{
++      struct sk_red_blob_decap *red_blob_decap;
++      struct redblob_decap_desc *red_blob_desc;
++
++      red_blob_decap = &req->req_u.sk_red_blob_decap;
++      red_blob_desc = &skdesc->dma_u.redblob_decapdesc;
++
++      red_blob_desc->redblob = dma_map_single(dev, red_blob_decap->redblob,
++                              red_blob_decap->redblob_sz, DMA_TO_DEVICE);
++      if (dma_mapping_error(dev, red_blob_desc->redblob)) {
++              dev_err(dev, "Unable to map memory\n");
++              goto sk_redblob_fail;
++      }
++
++      red_blob_desc->out_data = dma_map_single(dev, red_blob_decap->data,
++                              red_blob_decap->data_sz, DMA_FROM_DEVICE);
++      if (dma_mapping_error(dev, red_blob_desc->out_data)) {
++              dev_err(dev, "Unable to map memory\n");
++              goto sk_data_fail;
++      }
++
++      return 0;
++
++sk_data_fail:
++      dma_unmap_single(dev, red_blob_desc->redblob,
++                       red_blob_decap->redblob_sz, DMA_TO_DEVICE);
++sk_redblob_fail:
++      return -ENOMEM;
++}
++
++/* @fn void securekey_unmap(struct device *dev,
++ *                        struct sk_desc *skdesc, struct sk_req *req)
++ * @brief DMA unmap the buffer pointers.
++ * @param[in] dev Pointer to job ring device structure
++ * @param[in] skdesc Pointer to secure key descriptor structure
++ * @param[in] req Pointer to secure key request structure
++ */
++void securekey_unmap(struct device *dev,
++                   struct sk_desc *skdesc, struct sk_req *req)
++{
++
++      switch (req->type) {
++      case sk_get_random:
++              {
++                      struct sk_fetch_rnd_data *fetch_rnd_data;
++                      struct random_desc *rnd_desc;
++
++                      fetch_rnd_data = &req->req_u.sk_fetch_rnd_data;
++                      rnd_desc = &skdesc->dma_u.random_descp;
++
++                      /* Unmap Descriptor buffer pointers. */
++                      dma_unmap_single(dev, rnd_desc->rnd_data,
++                                       fetch_rnd_data->key_len,
++                                       DMA_FROM_DEVICE);
++                      break;
++              }
++      case sk_red_blob_enc:
++              {
++                      struct sk_red_blob_encap *red_blob_encap;
++                      struct redblob_encap_desc *red_blob_desc;
++
++                      red_blob_encap = &req->req_u.sk_red_blob_encap;
++                      red_blob_desc = &skdesc->dma_u.redblob_encapdesc;
++
++                      /* Unmap Descriptor buffer pointers. */
++                      dma_unmap_single(dev, red_blob_desc->in_data,
++                                       red_blob_encap->data_sz,
++                                       DMA_TO_DEVICE);
++
++                      dma_unmap_single(dev, red_blob_desc->redblob,
++                                       red_blob_encap->redblob_sz,
++                                       DMA_FROM_DEVICE);
++
++                      break;
++              }
++      case sk_red_blob_dec:
++              {
++                      struct sk_red_blob_decap *red_blob_decap;
++                      struct redblob_decap_desc *red_blob_desc;
++
++                      red_blob_decap = &req->req_u.sk_red_blob_decap;
++                      red_blob_desc = &skdesc->dma_u.redblob_decapdesc;
++
++                      /* Unmap Descriptor buffer pointers. */
++                      dma_unmap_single(dev, red_blob_desc->redblob,
++                                       red_blob_decap->redblob_sz,
++                                       DMA_TO_DEVICE);
++
++                      dma_unmap_single(dev, red_blob_desc->out_data,
++                                       red_blob_decap->data_sz,
++                                       DMA_FROM_DEVICE);
++
++                      break;
++              }
++      default:
++              dev_err(dev, "Unable to find request type\n");
++              break;
++      }
++      kfree(skdesc);
++}
++
++/*  int caam_securekey_desc_init(struct device *dev, struct sk_req *req)
++ *  brief CAAM Descriptor creator for secure key operations.
++ *  param[in] dev Pointer to job ring device structure
++ *  param[in] req Pointer to secure key request structure
++ *  return 0 on success, error value otherwise.
++ */
++int caam_securekey_desc_init(struct device *dev, struct sk_req *req)
++{
++      struct sk_desc *skdesc = NULL;
++      int ret = 0;
++
++      switch (req->type) {
++      case sk_get_random:
++              {
++                      skdesc = kmalloc(sizeof(*skdesc), GFP_DMA);
++                      if (!skdesc) {
++                              ret = -ENOMEM;
++                              goto out;
++                      }
++                      skdesc->req_type = req->type;
++
++                      if (caam_sk_get_random_map(dev, req, skdesc)) {
++                              dev_err(dev, "caam get_random map fail\n");
++                              ret = -ENOMEM;
++                              goto out;
++                      }
++                      caam_sk_rng_desc(req, skdesc);
++                      break;
++              }
++      case sk_red_blob_enc:
++              {
++                      skdesc = kmalloc(sizeof(*skdesc), GFP_DMA);
++                      if (!skdesc) {
++                              ret = -ENOMEM;
++                              goto out;
++                      }
++
++                      skdesc->req_type = req->type;
++
++                      if (caam_sk_redblob_encap_map(dev, req, skdesc)) {
++                              dev_err(dev, "caam redblob_encap map fail\n");
++                              ret = -ENOMEM;
++                              goto out;
++                      }
++
++                      /* Descriptor function to create redblob from data. */
++                      caam_sk_redblob_encap_desc(req, skdesc);
++                      break;
++              }
++
++      case sk_red_blob_dec:
++              {
++                      skdesc = kmalloc(sizeof(*skdesc), GFP_DMA);
++                      if (!skdesc) {
++                              ret = -ENOMEM;
++                              goto out;
++                      }
++
++                      skdesc->req_type = req->type;
++
++                      if (caam_sk_redblob_decap_map(dev, req, skdesc)) {
++                              dev_err(dev, "caam redblob_decap map fail\n");
++                              ret = -ENOMEM;
++                              goto out;
++                      }
++
++                      /* Descriptor function to decap data from redblob. */
++                      caam_sk_redblob_decap_desc(req, skdesc);
++                      break;
++              }
++      default:
++              pr_debug("Unknown request type\n");
++              ret = -EINVAL;
++              goto out;
++      }
++
++      req->desc_pointer = (void *)skdesc;
++
++out:
++      return ret;
++}
++
++/* static void caam_op_done (struct device *dev, u32 *desc, u32 ret,
++ *                         void *context)
++ * brief callback function to be called when descriptor executed.
++ * param[in] dev Pointer to device structure
++ * param[in] desc descriptor pointer
++ * param[in] ret return status of Job submitted
++ * param[in] context void pointer
++ */
++static void caam_op_done(struct device *dev, u32 *desc, u32 ret,
++                       void *context)
++{
++      struct sk_req *req = context;
++
++      if (ret) {
++              dev_err(dev, "caam op done err: %x\n", ret);
++              /* print the error source name. */
++              caam_jr_strstatus(dev, ret);
++      }
++      /* Call securekey_unmap function for unmapping the buffer pointers. */
++      securekey_unmap(dev, req->desc_pointer, req);
++
++      req->ret = ret;
++      complete(&req->comp);
++}
++
++
++/*  static int sk_job_submit(struct device *jrdev, struct sk_req *req)
++ *  brief Enqueue a Job descriptor to Job ring and wait until SEC returns.
++ *  param[in] jrdev Pointer to job ring device structure
++ *  param[in] req Pointer to secure key request structure
++ *  return 0 on success, error value otherwise.
++ */
++static int sk_job_submit(struct device *jrdev, struct sk_req *req)
++{
++      int ret;
++
++      init_completion(&req->comp);
++
++      /* caam_jr_enqueue function for Enqueue a job descriptor */
++      ret = caam_jr_enqueue(jrdev, req->hwdesc, caam_op_done, req);
++      if (!ret)
++              wait_for_completion_interruptible(&req->comp);
++
++      ret = req->ret;
++      return ret;
++}
++
++/* caam_get_random(struct secure_key_payload *p,  enum sk_req_type fetch_rnd,
++ *               struct device *dev)
++ * Create the random number of the specified length using CAAM block
++ * param[in]: out pointer to place the random bytes
++ * param[in]: length for the random data bytes.
++ * param[in]: dev Pointer to job ring device structure
++ * If operation is successful return 0, otherwise error.
++ */
++int caam_get_random(struct secure_key_payload *p,  enum sk_req_type fetch_rnd,
++                  struct device *dev)
++{
++      struct sk_fetch_rnd_data *fetch_rnd_data = NULL;
++      struct sk_req *req = NULL;
++      int ret = 0;
++      void *temp = NULL;
++
++      req = kmalloc(sizeof(struct sk_req), GFP_DMA);
++      if (!req) {
++              ret = -ENOMEM;
++              goto out;
++      }
++
++      req->type = fetch_rnd;
++      fetch_rnd_data = &(req->req_u.sk_fetch_rnd_data);
++
++      /* initialise with key length */
++      fetch_rnd_data->key_len = p->key_len;
++
++      temp = kmalloc(fetch_rnd_data->key_len, GFP_DMA);
++      if (!temp) {
++              ret = -ENOMEM;
++              goto out;
++      }
++      fetch_rnd_data->data = temp;
++
++      ret = caam_securekey_desc_init(dev, req);
++
++      if (ret) {
++              pr_info("caam_securekey_desc_init failed\n");
++              goto out;
++      }
++
++      ret = sk_job_submit(dev, req);
++      if (!ret) {
++              /*Copy output to key buffer. */
++              memcpy(p->key, fetch_rnd_data->data, p->key_len);
++      } else {
++              ret = -EINVAL;
++      }
++
++out:
++      if (req)
++              kfree(req);
++
++      if (temp)
++              kfree(temp);
++
++      return ret;
++}
++EXPORT_SYMBOL(caam_get_random);
++
++/* key_deblob(struct secure_key_payload *p, enum sk_req_type decap_type
++ *            struct device *dev)
++ * Deblobify the blob to get the key data and fill in secure key payload struct
++ * param[in] p pointer to the secure key payload
++ * param[in] decap_type operation to be done.
++ * param[in] dev dev Pointer to job ring device structure
++ * If operation is successful return 0, otherwise error.
++ */
++int key_deblob(struct secure_key_payload *p, enum sk_req_type decap_type,
++             struct device *dev)
++{
++      unsigned int blob_len;
++      struct sk_red_blob_decap *d_blob;
++      struct sk_req *req = NULL;
++      int total_sz = 0, *temp = NULL, ret = 0;
++
++      req = kmalloc(sizeof(struct sk_req), GFP_DMA);
++      if (!req) {
++              ret = -ENOMEM;
++              goto out;
++      }
++
++      d_blob = &(req->req_u.sk_red_blob_decap);
++      blob_len = p->blob_len;
++      req->type = decap_type;
++
++      /*
++       * Red blob size is the blob_len filled in payload struct
++       * Data_sz i.e. key is the blob_len - blob header size
++       */
++
++      d_blob->redblob_sz = blob_len;
++      d_blob->data_sz = blob_len - (SK_BLOB_KEY_SZ + SK_BLOB_MAC_SZ);
++      total_sz = d_blob->data_sz + d_blob->redblob_sz;
++
++      temp = kmalloc(total_sz, GFP_DMA);
++      if (!temp) {
++              ret = -ENOMEM;
++              goto out;
++      }
++
++      req->mem_pointer = temp;
++      d_blob->redblob = temp;
++      d_blob->data = d_blob->redblob + d_blob->redblob_sz;
++      memcpy(d_blob->redblob, p->blob, blob_len);
++
++      ret = caam_securekey_desc_init(dev, req);
++
++      if (ret) {
++              pr_info("caam_securekey_desc_init: Failed\n");
++              goto out;
++      }
++
++      ret = sk_job_submit(dev, req);
++      if (!ret) {
++              /*Copy output to key buffer. */
++              p->key_len = d_blob->data_sz;
++              memcpy(p->key, d_blob->data, p->key_len);
++      } else {
++              ret = -EINVAL;
++      }
++
++out:
++      if (temp)
++              kfree(temp);
++      if (req)
++              kfree(req);
++      return ret;
++}
++EXPORT_SYMBOL(key_deblob);
++
++/* key_blob(struct secure_key_payload *p, enum sk_req_type encap_type,
++ *            struct device *dev)
++ * To blobify the key data to get the blob. This blob can only be seen by
++ * userspace.
++ * param[in] p pointer to the secure key payload
++ * param[in] decap_type operation to be done.
++ * param[in] dev dev Pointer to job ring device structure
++ * If operation is successful return 0, otherwise error.
++ */
++int key_blob(struct secure_key_payload *p, enum sk_req_type encap_type,
++           struct device *dev)
++{
++      unsigned int key_len;
++      struct sk_red_blob_encap *k_blob;
++      struct sk_req *req = NULL;
++      int total_sz = 0, *temp = NULL, ret = 0;
++
++      req = kmalloc(sizeof(struct sk_req), GFP_DMA);
++      if (!req) {
++              ret = -ENOMEM;
++              goto out;
++      }
++
++      key_len = p->key_len;
++
++      req->type = encap_type;
++      k_blob = &(req->req_u.sk_red_blob_encap);
++
++      /*
++       * Data_sz i.e. key len and the corresponding blob_len is
++       * key_len + BLOB header size.
++       */
++
++      k_blob->data_sz = key_len;
++      k_blob->redblob_sz = key_len + SK_BLOB_KEY_SZ + SK_BLOB_MAC_SZ;
++      total_sz = k_blob->data_sz + k_blob->redblob_sz;
++
++      temp = kmalloc(total_sz, GFP_DMA);
++      if (!temp) {
++              ret = -ENOMEM;
++              goto out;
++      }
++
++      req->mem_pointer = temp;
++      k_blob->data = temp;
++
++      k_blob->redblob = k_blob->data + k_blob->data_sz;
++      memcpy(k_blob->data, p->key, key_len);
++
++      ret = caam_securekey_desc_init(dev, req);
++
++      if (ret) {
++              pr_info("caam_securekey_desc_init failed\n");
++              goto out;
++      }
++
++      ret = sk_job_submit(dev, req);
++      if (!ret) {
++              /*Copy output to key buffer. */
++              p->blob_len = k_blob->redblob_sz;
++              memcpy(p->blob, k_blob->redblob, p->blob_len);
++      } else {
++              ret = -EINVAL;
++      }
++
++out:
++      if (temp)
++              kfree(req->mem_pointer);
++      if (req)
++              kfree(req);
++      return ret;
++
++}
++EXPORT_SYMBOL(key_blob);
+--- /dev/null
++++ b/security/keys/securekey_desc.h
+@@ -0,0 +1,141 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright 2018 NXP
++ *
++ */
++#ifndef _SECUREKEY_DESC_H_
++#define _SECUREKEY_DESC_H_
++
++#include "compat.h"
++#include "regs.h"
++#include "intern.h"
++#include "desc.h"
++#include "desc_constr.h"
++#include "jr.h"
++#include "error.h"
++#include "pdb.h"
++
++#define SK_BLOB_KEY_SZ                32      /* Blob key size. */
++#define SK_BLOB_MAC_SZ                16      /* Blob MAC size. */
++
++/*
++ * brief defines different kinds of operations supported by this module.
++ */
++enum sk_req_type {
++      sk_get_random,
++      sk_red_blob_enc,
++      sk_red_blob_dec,
++};
++
++
++/*
++ * struct random_des
++ * param[out] rnd_data output buffer for random data.
++ */
++struct random_desc {
++      dma_addr_t rnd_data;
++};
++
++/* struct redblob_encap_desc
++ * details Structure containing dma address for redblob encapsulation.
++ * param[in] in_data input data to redblob encap descriptor.
++ * param[out] redblob output buffer for redblob.
++ */
++struct redblob_encap_desc {
++      dma_addr_t in_data;
++      dma_addr_t redblob;
++};
++
++/* struct redblob_decap_desc
++ * details Structure containing dma address for redblob decapsulation.
++ * param[in] redblob input buffer to redblob decap descriptor.
++ * param[out] out_data output data from redblob decap descriptor.
++ */
++struct redblob_decap_desc {
++      dma_addr_t redblob;
++      dma_addr_t out_data;
++};
++
++/* struct sk_desc
++ * details Structure for securekey descriptor creation.
++ * param[in] req_type operation supported.
++ * param[in] dma_u union of struct for supported operation.
++ */
++struct sk_desc {
++      u32 req_type;
++      union {
++              struct redblob_encap_desc redblob_encapdesc;
++              struct redblob_decap_desc redblob_decapdesc;
++              struct random_desc random_descp;
++      } dma_u;
++};
++
++/* struct sk_fetch_rnd_data
++ * decriptor structure containing key length.
++ */
++struct sk_fetch_rnd_data {
++      void *data;
++      size_t key_len;
++};
++
++/* struct sk_red_blob_encap
++ * details Structure containing buffer pointers for redblob encapsulation.
++ * param[in] data Input data.
++ * param[in] data_sz size of Input data.
++ * param[out] redblob output buffer for redblob.
++ * param[in] redblob_sz size of redblob.
++ */
++struct sk_red_blob_encap {
++      void *data;
++      uint32_t data_sz;
++      void *redblob;
++      uint32_t redblob_sz;
++};
++
++/* struct sk_red_blob_decap
++ * details Structure containing buffer pointers for redblob decapsulation.
++ * param[in] redblob Input redblob.
++ * param[in] redblob_sz size of redblob.
++ * param[out] data output buffer for data.
++ * param[in] data_sz size of output data.
++ */
++struct sk_red_blob_decap {
++      void *redblob;
++      uint32_t redblob_sz;
++      void *data;
++      uint32_t data_sz;
++};
++
++/* struct sk_req
++ * details Structure for securekey request creation.
++ * param[in] type operation supported.
++ * param[in] req_u union of struct for supported operation.
++ * param[out] ret return status of CAAM operation.
++ * param[in] mem_pointer memory pointer for allocated kernel memory.
++ * param[in] desc_pointer Pointer to securekey descriptor creation structure.
++ * param[in] comp struct completion object.
++ * param[in] hwdesc contains descriptor instructions.
++ */
++struct sk_req {
++      enum sk_req_type type;
++      void *arg;
++      union {
++              struct sk_red_blob_encap sk_red_blob_encap;
++              struct sk_red_blob_decap sk_red_blob_decap;
++              struct sk_fetch_rnd_data sk_fetch_rnd_data;
++      } req_u;
++      int ret;
++      void *mem_pointer;
++      void *desc_pointer;
++      struct completion comp;
++      u32 hwdesc[MAX_CAAM_DESCSIZE];
++};
++
++int caam_get_random(struct secure_key_payload *p,  enum sk_req_type fetch_rnd,
++                  struct device *dev);
++int key_blob(struct secure_key_payload *p, enum sk_req_type encap_type,
++           struct device *dev);
++int key_deblob(struct secure_key_payload *p, enum sk_req_type decap_type,
++             struct device *dev);
++
++#endif /*_SECUREKEY_DESC_H_*/
diff --git a/target/linux/layerscape/patches-5.4/810-keys-0002-encrypted_keys-Adds-support-for-secure-key-type-as-m.patch b/target/linux/layerscape/patches-5.4/810-keys-0002-encrypted_keys-Adds-support-for-secure-key-type-as-m.patch
new file mode 100644 (file)
index 0000000..977082b
--- /dev/null
@@ -0,0 +1,162 @@
+From a8b1717089d6d215a48bb2816dff4a02376f3d16 Mon Sep 17 00:00:00 2001
+From: Udit Agarwal <udit.agarwal@nxp.com>
+Date: Wed, 4 Jul 2018 11:24:49 +0530
+Subject: [PATCH] encrypted_keys: Adds support for secure key-type as master
+ key.
+
+Encrypted keys can use secure key-type as master key along with
+trusted/user keys.
+
+Secure key as master key uses, secure key type payload derieved
+using CAAM hardware.
+
+Signed-off-by: Udit Agarwal <udit.agarwal@nxp.com>
+Reviewed-by: Sahil Malhotra <sahil.malhotra@nxp.com>
+---
+ MAINTAINERS                                     |  1 +
+ security/keys/encrypted-keys/Makefile           |  2 ++
+ security/keys/encrypted-keys/encrypted.c        | 13 +++++++--
+ security/keys/encrypted-keys/encrypted.h        | 13 +++++++++
+ security/keys/encrypted-keys/masterkey_secure.c | 37 +++++++++++++++++++++++++
+ 5 files changed, 64 insertions(+), 2 deletions(-)
+ create mode 100644 security/keys/encrypted-keys/masterkey_secure.c
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -9083,6 +9083,7 @@ F:       include/keys/secure-type.h
+ F:    security/keys/secure_key.c
+ F:    security/keys/securekey_desc.c
+ F:    security/keys/securekey_desc.h
++F:    security/keys/encrypted-keys/masterkey_secure.c
+ KEYS/KEYRINGS:
+ M:    David Howells <dhowells@redhat.com>
+--- a/security/keys/encrypted-keys/Makefile
++++ b/security/keys/encrypted-keys/Makefile
+@@ -7,5 +7,7 @@ obj-$(CONFIG_ENCRYPTED_KEYS) += encrypte
+ encrypted-keys-y := encrypted.o ecryptfs_format.o
+ masterkey-$(CONFIG_TRUSTED_KEYS) := masterkey_trusted.o
++masterkey-$(CONFIG_SECURE_KEYS) := masterkey_secure.o
+ masterkey-$(CONFIG_TRUSTED_KEYS)-$(CONFIG_ENCRYPTED_KEYS) := masterkey_trusted.o
++masterkey-$(CONFIG_SECURE_KEYS)-$(CONFIG_ENCRYPTED_KEYS) := masterkey_secure.o
+ encrypted-keys-y += $(masterkey-y) $(masterkey-m-m)
+--- a/security/keys/encrypted-keys/encrypted.c
++++ b/security/keys/encrypted-keys/encrypted.c
+@@ -36,6 +36,7 @@
+ #include "ecryptfs_format.h"
+ static const char KEY_TRUSTED_PREFIX[] = "trusted:";
++static const char KEY_SECURE_PREFIX[] = "secure:";
+ static const char KEY_USER_PREFIX[] = "user:";
+ static const char hash_alg[] = "sha256";
+ static const char hmac_alg[] = "hmac(sha256)";
+@@ -47,6 +48,7 @@ static unsigned int ivsize;
+ static int blksize;
+ #define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1)
++#define KEY_SECURE_PREFIX_LEN (sizeof(KEY_SECURE_PREFIX) - 1)
+ #define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1)
+ #define KEY_ECRYPTFS_DESC_LEN 16
+ #define HASH_SIZE SHA256_DIGEST_SIZE
+@@ -125,7 +127,7 @@ static int valid_ecryptfs_desc(const cha
+ /*
+  * valid_master_desc - verify the 'key-type:desc' of a new/updated master-key
+  *
+- * key-type:= "trusted:" | "user:"
++ * key-type:= "trusted:" | "user:" | "secure:"
+  * desc:= master-key description
+  *
+  * Verify that 'key-type' is valid and that 'desc' exists. On key update,
+@@ -140,6 +142,8 @@ static int valid_master_desc(const char
+       if (!strncmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN))
+               prefix_len = KEY_TRUSTED_PREFIX_LEN;
++      else if (!strncmp(new_desc, KEY_SECURE_PREFIX, KEY_SECURE_PREFIX_LEN))
++              prefix_len = KEY_SECURE_PREFIX_LEN;
+       else if (!strncmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN))
+               prefix_len = KEY_USER_PREFIX_LEN;
+       else
+@@ -358,7 +362,7 @@ static int calc_hmac(u8 *digest, const u
+ enum derived_key_type { ENC_KEY, AUTH_KEY };
+-/* Derive authentication/encryption key from trusted key */
++/* Derive authentication/encryption key from trusted/secure key */
+ static int get_derived_key(u8 *derived_key, enum derived_key_type key_type,
+                          const u8 *master_key, size_t master_keylen)
+ {
+@@ -429,6 +433,11 @@ static struct key *request_master_key(st
+               mkey = request_trusted_key(epayload->master_desc +
+                                          KEY_TRUSTED_PREFIX_LEN,
+                                          master_key, master_keylen);
++      } else if (!strncmp(epayload->master_desc, KEY_SECURE_PREFIX,
++                          KEY_SECURE_PREFIX_LEN)) {
++              mkey = request_secure_key(epayload->master_desc +
++                                        KEY_SECURE_PREFIX_LEN,
++                                        master_key, master_keylen);
+       } else if (!strncmp(epayload->master_desc, KEY_USER_PREFIX,
+                           KEY_USER_PREFIX_LEN)) {
+               mkey = request_user_key(epayload->master_desc +
+--- a/security/keys/encrypted-keys/encrypted.h
++++ b/security/keys/encrypted-keys/encrypted.h
+@@ -16,6 +16,19 @@ static inline struct key *request_truste
+ }
+ #endif
++#if defined(CONFIG_SECURE_KEYS)
++extern struct key *request_secure_key(const char *secure_desc,
++                                    const u8 **master_key,
++                                    size_t *master_keylen);
++#else
++static inline struct key *request_secure_key(const char *secure_desc,
++                                           const u8 **master_key,
++                                           size_t *master_keylen)
++{
++      return ERR_PTR(-EOPNOTSUPP);
++}
++#endif
++
+ #if ENCRYPTED_DEBUG
+ static inline void dump_master_key(const u8 *master_key, size_t master_keylen)
+ {
+--- /dev/null
++++ b/security/keys/encrypted-keys/masterkey_secure.c
+@@ -0,0 +1,37 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2018 NXP.
++ *
++ */
++
++#include <linux/uaccess.h>
++#include <linux/module.h>
++#include <linux/err.h>
++#include <keys/secure-type.h>
++#include <keys/encrypted-type.h>
++#include "encrypted.h"
++
++/*
++ * request_secure_key - request the secure key
++ *
++ * Secure keys and their blobs are derived from CAAM hardware.
++ * Userspace manages secure  key-type data, but key data is not
++ * visible in plain form. It is presented as blobs.
++ */
++struct key *request_secure_key(const char *secure_desc,
++                              const u8 **master_key, size_t *master_keylen)
++{
++      struct secure_key_payload *spayload;
++      struct key *skey;
++
++      skey = request_key(&key_type_secure, secure_desc, NULL);
++      if (IS_ERR(skey))
++              goto error;
++
++      down_read(&skey->sem);
++      spayload = skey->payload.data[0];
++      *master_key = spayload->key;
++      *master_keylen = spayload->key_len;
++error:
++      return skey;
++}
diff --git a/target/linux/layerscape/patches-5.4/810-keys-0003-security-keys-secure_key-Fix-the-path-of-included-he.patch b/target/linux/layerscape/patches-5.4/810-keys-0003-security-keys-secure_key-Fix-the-path-of-included-he.patch
new file mode 100644 (file)
index 0000000..c1f6081
--- /dev/null
@@ -0,0 +1,38 @@
+From 0dacdd2fb2f7a5ac016544ac9c4c5d29b81d6ffd Mon Sep 17 00:00:00 2001
+From: Shengzhou Liu <shengzhou.liu@nxp.com>
+Date: Thu, 9 Jan 2020 10:18:44 +0800
+Subject: [PATCH] security/keys/secure_key: Fix the path of included header
+ file
+
+Fix the path of included header file.
+
+Signed-off-by: Shengzhou Liu <shengzhou.liu@nxp.com>
+---
+ security/keys/securekey_desc.h | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+--- a/security/keys/securekey_desc.h
++++ b/security/keys/securekey_desc.h
+@@ -6,14 +6,14 @@
+ #ifndef _SECUREKEY_DESC_H_
+ #define _SECUREKEY_DESC_H_
+-#include "compat.h"
+-#include "regs.h"
+-#include "intern.h"
+-#include "desc.h"
+-#include "desc_constr.h"
+-#include "jr.h"
+-#include "error.h"
+-#include "pdb.h"
++#include "../../drivers/crypto/caam/compat.h"
++#include "../../drivers/crypto/caam/regs.h"
++#include "../../drivers/crypto/caam/intern.h"
++#include "../../drivers/crypto/caam/desc.h"
++#include "../../drivers/crypto/caam/desc_constr.h"
++#include "../../drivers/crypto/caam/jr.h"
++#include "../../drivers/crypto/caam/error.h"
++#include "../../drivers/crypto/caam/pdb.h"
+ #define SK_BLOB_KEY_SZ                32      /* Blob key size. */
+ #define SK_BLOB_MAC_SZ                16      /* Blob MAC size. */
diff --git a/target/linux/layerscape/patches-5.4/811-kvm-0001-arm64-KVM-support-flushing-device-memory.patch b/target/linux/layerscape/patches-5.4/811-kvm-0001-arm64-KVM-support-flushing-device-memory.patch
new file mode 100644 (file)
index 0000000..7c9bc07
--- /dev/null
@@ -0,0 +1,42 @@
+From aa9e99f77f92814a0d83af8e6ed3148458d0f611 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 26 Jul 2016 15:43:43 +0300
+Subject: [PATCH] arm64: KVM: support flushing device memory
+
+In the current implementation, trying to flush
+memory not covered by the linear map (e.g. device
+memory) causes a crash. Add support for flushing
+"non-normal" memory by explicitly ioremap()-ing
+it when such a case appears and do the cache flush
+through this temporary mapping.
+This allows dropping the special checks for qman
+cacheable region when doing cache flushes.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+[fixed formatting issue]
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ arch/arm64/include/asm/kvm_mmu.h | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/include/asm/kvm_mmu.h
++++ b/arch/arm64/include/asm/kvm_mmu.h
+@@ -341,8 +341,16 @@ static inline void __invalidate_icache_g
+ static inline void __kvm_flush_dcache_pte(pte_t pte)
+ {
+       if (!cpus_have_const_cap(ARM64_HAS_STAGE2_FWB)) {
+-              struct page *page = pte_page(pte);
+-              kvm_flush_dcache_to_poc(page_address(page), PAGE_SIZE);
++              if (pfn_valid(pte_pfn(pte))) {
++                      struct page *page = pte_page(pte);
++
++                      kvm_flush_dcache_to_poc(page_address(page), PAGE_SIZE);
++              } else {
++                      void __iomem *va = ioremap_cache_ns(pte_pfn(pte) << PAGE_SHIFT, PAGE_SIZE);
++
++                      kvm_flush_dcache_to_poc(va, PAGE_SIZE);
++                      iounmap(va);
++              }
+       }
+ }
diff --git a/target/linux/layerscape/patches-5.4/811-kvm-0002-arm-arm64-KVM-allow-specifying-s2-prot-bits-when-map.patch b/target/linux/layerscape/patches-5.4/811-kvm-0002-arm-arm64-KVM-allow-specifying-s2-prot-bits-when-map.patch
new file mode 100644 (file)
index 0000000..d4fcf5c
--- /dev/null
@@ -0,0 +1,87 @@
+From 7a291e75b7793f1fbd0ad9ad39ae35a2b091d84b Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 26 Jul 2016 16:12:30 +0300
+Subject: [PATCH] arm/arm64 KVM: allow specifying s2 prot bits when mapping i/o
+
+Add parameter allowing to specify s2 page table
+protection and type bits and update the callers
+accordingly.
+The parameter will be used in a forthcoming patch.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+---
+ arch/arm/include/asm/kvm_mmu.h   | 3 ++-
+ arch/arm64/include/asm/kvm_mmu.h | 3 ++-
+ virt/kvm/arm/mmu.c               | 8 +++++---
+ virt/kvm/arm/vgic/vgic-v2.c      | 3 ++-
+ 4 files changed, 11 insertions(+), 6 deletions(-)
+
+--- a/arch/arm/include/asm/kvm_mmu.h
++++ b/arch/arm/include/asm/kvm_mmu.h
+@@ -55,7 +55,8 @@ void stage2_unmap_vm(struct kvm *kvm);
+ int kvm_alloc_stage2_pgd(struct kvm *kvm);
+ void kvm_free_stage2_pgd(struct kvm *kvm);
+ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
+-                        phys_addr_t pa, unsigned long size, bool writable);
++                        phys_addr_t pa, unsigned long size, bool writable,
++                        pgprot_t prot);
+ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
+--- a/arch/arm64/include/asm/kvm_mmu.h
++++ b/arch/arm64/include/asm/kvm_mmu.h
+@@ -156,7 +156,8 @@ void stage2_unmap_vm(struct kvm *kvm);
+ int kvm_alloc_stage2_pgd(struct kvm *kvm);
+ void kvm_free_stage2_pgd(struct kvm *kvm);
+ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
+-                        phys_addr_t pa, unsigned long size, bool writable);
++                        phys_addr_t pa, unsigned long size, bool writable,
++                        pgprot_t prot);
+ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
+--- a/virt/kvm/arm/mmu.c
++++ b/virt/kvm/arm/mmu.c
+@@ -1335,9 +1335,11 @@ static int stage2_pudp_test_and_clear_yo
+  * @guest_ipa:        The IPA at which to insert the mapping
+  * @pa:               The physical address of the device
+  * @size:     The size of the mapping
++ * @prot:     S2 page translation bits
+  */
+ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
+-                        phys_addr_t pa, unsigned long size, bool writable)
++                        phys_addr_t pa, unsigned long size, bool writable,
++                        pgprot_t prot)
+ {
+       phys_addr_t addr, end;
+       int ret = 0;
+@@ -1348,7 +1350,7 @@ int kvm_phys_addr_ioremap(struct kvm *kv
+       pfn = __phys_to_pfn(pa);
+       for (addr = guest_ipa; addr < end; addr += PAGE_SIZE) {
+-              pte_t pte = kvm_pfn_pte(pfn, PAGE_S2_DEVICE);
++              pte_t pte = kvm_pfn_pte(pfn, prot);
+               if (writable)
+                       pte = kvm_s2pte_mkwrite(pte);
+@@ -2346,7 +2348,7 @@ int kvm_arch_prepare_memory_region(struc
+                       ret = kvm_phys_addr_ioremap(kvm, gpa, pa,
+                                                   vm_end - vm_start,
+-                                                  writable);
++                                                  writable, PAGE_S2_DEVICE);
+                       if (ret)
+                               break;
+               }
+--- a/virt/kvm/arm/vgic/vgic-v2.c
++++ b/virt/kvm/arm/vgic/vgic-v2.c
+@@ -341,7 +341,8 @@ int vgic_v2_map_resources(struct kvm *kv
+       if (!static_branch_unlikely(&vgic_v2_cpuif_trap)) {
+               ret = kvm_phys_addr_ioremap(kvm, dist->vgic_cpu_base,
+                                           kvm_vgic_global_state.vcpu_base,
+-                                          KVM_VGIC_V2_CPU_SIZE, true);
++                                          KVM_VGIC_V2_CPU_SIZE, true,
++                                          PAGE_S2_DEVICE);
+               if (ret) {
+                       kvm_err("Unable to remap VGIC CPU to VCPU\n");
+                       goto out;
diff --git a/target/linux/layerscape/patches-5.4/811-kvm-0003-arm-arm64-KVM-drop-qman-mmio-cacheable-mapping-hack.patch b/target/linux/layerscape/patches-5.4/811-kvm-0003-arm-arm64-KVM-drop-qman-mmio-cacheable-mapping-hack.patch
new file mode 100644 (file)
index 0000000..8593714
--- /dev/null
@@ -0,0 +1,132 @@
+From d637252f72998261c9d77c0be57317c73ad77f83 Mon Sep 17 00:00:00 2001
+From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+Date: Tue, 26 Jul 2016 16:38:18 +0300
+Subject: [PATCH] arm/arm64: KVM: drop qman mmio cacheable mapping hack
+
+Instead of hardcoding checks for qman cacheable
+mmio region physical addresses extract mapping
+information from the user-space mapping.
+The involves several steps;
+ - get access to a pte part of the user-space mapping
+   by using get_locked_pte() / pte_unmap_unlock() apis
+ - extract memtype (normal / device), shareability from
+   the pte
+ - convert to S2 translation bits in newly added
+   function stage1_to_stage2_pgprot()
+ - finish making the s2 translation with the obtained bits
+
+Another explored option was using vm_area_struct::vm_page_prot
+which is set in vfio-mc mmap code to the correct page bits.
+However, experiments show that these bits are later altered
+in the generic mmap code (e.g. the shareability bit is always
+set on arm64).
+The only place where the original bits can still be found
+is the user-space mapping, using the method described above.
+
+Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
+[Bharat - Fixed mem_type check issue]
+[changed "ifdef ARM64" to CONFIG_ARM64]
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+[Ioana - added a sanity check for hugepages]
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+[Fixed format issues]
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ virt/kvm/arm/mmu.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 53 insertions(+), 2 deletions(-)
+
+--- a/virt/kvm/arm/mmu.c
++++ b/virt/kvm/arm/mmu.c
+@@ -1375,6 +1375,30 @@ out:
+       return ret;
+ }
++#ifdef CONFIG_ARM64
++static pgprot_t stage1_to_stage2_pgprot(pgprot_t prot)
++{
++      switch (pgprot_val(prot) & PTE_ATTRINDX_MASK) {
++      case PTE_ATTRINDX(MT_DEVICE_nGnRE):
++      case PTE_ATTRINDX(MT_DEVICE_nGnRnE):
++      case PTE_ATTRINDX(MT_DEVICE_GRE):
++              return PAGE_S2_DEVICE;
++      case PTE_ATTRINDX(MT_NORMAL_NC):
++      case PTE_ATTRINDX(MT_NORMAL):
++              return (pgprot_val(prot) & PTE_SHARED)
++                      ? PAGE_S2
++                      : PAGE_S2_NS;
++      }
++
++      return PAGE_S2_DEVICE;
++}
++#else
++static pgprot_t stage1_to_stage2_pgprot(pgprot_t prot)
++{
++      return PAGE_S2_DEVICE;
++}
++#endif
++
+ static bool transparent_hugepage_adjust(kvm_pfn_t *pfnp, phys_addr_t *ipap)
+ {
+       kvm_pfn_t pfn = *pfnp;
+@@ -1719,8 +1743,23 @@ static int user_mem_abort(struct kvm_vcp
+        * 3 levels, i.e, PMD is not folded.
+        */
+       if (vma_pagesize == PMD_SIZE ||
+-          (vma_pagesize == PUD_SIZE && kvm_stage2_has_pmd(kvm)))
++          (vma_pagesize == PUD_SIZE && kvm_stage2_has_pmd(kvm))) {
+               gfn = (fault_ipa & huge_page_mask(hstate_vma(vma))) >> PAGE_SHIFT;
++      } else {
++              if (!is_vm_hugetlb_page(vma)) {
++                      pte_t *pte;
++                      spinlock_t *ptl;
++                      pgprot_t prot;
++
++                      pte = get_locked_pte(current->mm, memslot->userspace_addr, &ptl);
++                      prot = stage1_to_stage2_pgprot(__pgprot(pte_val(*pte)));
++                      pte_unmap_unlock(pte, ptl);
++#ifdef CONFIG_ARM64
++                      if (pgprot_val(prot) == pgprot_val(PAGE_S2_NS))
++                              mem_type = PAGE_S2_NS;
++#endif
++              }
++      }
+       up_read(&current->mm->mmap_sem);
+       /* We need minimum second+third level pages */
+@@ -1749,6 +1788,11 @@ static int user_mem_abort(struct kvm_vcp
+       if (is_error_noslot_pfn(pfn))
+               return -EFAULT;
++#ifdef CONFIG_ARM64
++      if (pgprot_val(mem_type) == pgprot_val(PAGE_S2_NS)) {
++              flags |= KVM_S2PTE_FLAG_IS_IOMAP;
++      } else
++#endif
+       if (kvm_is_device_pfn(pfn)) {
+               mem_type = PAGE_S2_DEVICE;
+               flags |= KVM_S2PTE_FLAG_IS_IOMAP;
+@@ -2336,6 +2380,9 @@ int kvm_arch_prepare_memory_region(struc
+                       gpa_t gpa = mem->guest_phys_addr +
+                                   (vm_start - mem->userspace_addr);
+                       phys_addr_t pa;
++                      pgprot_t prot;
++                      pte_t *pte;
++                      spinlock_t *ptl;
+                       pa = (phys_addr_t)vma->vm_pgoff << PAGE_SHIFT;
+                       pa += vm_start - vma->vm_start;
+@@ -2346,9 +2393,13 @@ int kvm_arch_prepare_memory_region(struc
+                               goto out;
+                       }
++                      pte = get_locked_pte(current->mm, mem->userspace_addr, &ptl);
++                      prot = stage1_to_stage2_pgprot(__pgprot(pte_val(*pte)));
++                      pte_unmap_unlock(pte, ptl);
++
+                       ret = kvm_phys_addr_ioremap(kvm, gpa, pa,
+                                                   vm_end - vm_start,
+-                                                  writable, PAGE_S2_DEVICE);
++                                                  writable, prot);
+                       if (ret)
+                               break;
+               }
diff --git a/target/linux/layerscape/patches-5.4/811-kvm-0004-virt-vgic-Increase-number-of-DeviceIDs-to-17.patch b/target/linux/layerscape/patches-5.4/811-kvm-0004-virt-vgic-Increase-number-of-DeviceIDs-to-17.patch
new file mode 100644 (file)
index 0000000..11492b0
--- /dev/null
@@ -0,0 +1,26 @@
+From d157696b1761a710499207c6011a611a5c76826f Mon Sep 17 00:00:00 2001
+From: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Date: Thu, 25 Jan 2018 10:28:53 +0000
+Subject: [PATCH] virt/vgic: Increase number of DeviceIDs to 17
+
+FSL-MC bus devices uses device-ids from 0x10000 to 0x20000.
+So to support MSI interrupts for mc-bus devices we need
+vgi-ITS device-id table of size 2^17 to support deviceid
+range from 0x10000 to 0x20000.
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+---
+ virt/kvm/arm/vgic/vgic-its.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/virt/kvm/arm/vgic/vgic-its.c
++++ b/virt/kvm/arm/vgic/vgic-its.c
+@@ -241,7 +241,7 @@ static struct its_ite *find_ite(struct v
+ #define GIC_LPI_OFFSET 8192
+ #define VITS_TYPER_IDBITS 16
+-#define VITS_TYPER_DEVBITS 16
++#define VITS_TYPER_DEVBITS 17
+ #define VITS_DTE_MAX_DEVID_OFFSET     (BIT(14) - 1)
+ #define VITS_ITE_MAX_EVENTID_OFFSET   (BIT(16) - 1)
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0001-PCI-layerscape-Add-LS1028a-support.patch b/target/linux/layerscape/patches-5.4/812-pcie-0001-PCI-layerscape-Add-LS1028a-support.patch
new file mode 100644 (file)
index 0000000..4e7cdb3
--- /dev/null
@@ -0,0 +1,23 @@
+From f4980947debc7865bd923d60bf36d6fb0b80ecc5 Mon Sep 17 00:00:00 2001
+From: Xiaowei Bao <xiaowei.bao@nxp.com>
+Date: Fri, 23 Aug 2019 16:26:43 +0800
+Subject: [PATCH] PCI: layerscape: Add LS1028a support
+
+Add support for the LS1028a PCIe controller.
+
+Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+---
+ drivers/pci/controller/dwc/pci-layerscape.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/pci/controller/dwc/pci-layerscape.c
++++ b/drivers/pci/controller/dwc/pci-layerscape.c
+@@ -263,6 +263,7 @@ static const struct ls_pcie_drvdata ls20
+ static const struct of_device_id ls_pcie_of_match[] = {
+       { .compatible = "fsl,ls1012a-pcie", .data = &ls1046_drvdata },
+       { .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata },
++      { .compatible = "fsl,ls1028a-pcie", .data = &ls2088_drvdata },
+       { .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata },
+       { .compatible = "fsl,ls1046a-pcie", .data = &ls1046_drvdata },
+       { .compatible = "fsl,ls2080a-pcie", .data = &ls2080_drvdata },
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0002-PCI-dwc-Use-interrupt-disabling-instead-of-masking.patch b/target/linux/layerscape/patches-5.4/812-pcie-0002-PCI-dwc-Use-interrupt-disabling-instead-of-masking.patch
new file mode 100644 (file)
index 0000000..e82b83a
--- /dev/null
@@ -0,0 +1,60 @@
+From c89d85a39df353290ea7af84a32d5ca692a3c27a Mon Sep 17 00:00:00 2001
+From: Fugang Duan <fugang.duan@nxp.com>
+Date: Sat, 2 Nov 2019 15:51:40 +0800
+Subject: [PATCH] PCI: dwc: Use interrupt disabling instead of masking
+
+commit 830920e065e9("PCI: dwc: Use interrupt masking instead
+of disabling") break i.MX platform PCIe suspend/resume when
+MSI enabled.
+
+Revert the commit to keep orinigal method that using interrupt
+disabling instead of masking.
+
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+---
+ drivers/pci/controller/dwc/pcie-designware-host.c | 19 +++++++------------
+ 1 file changed, 7 insertions(+), 12 deletions(-)
+
+--- a/drivers/pci/controller/dwc/pcie-designware-host.c
++++ b/drivers/pci/controller/dwc/pcie-designware-host.c
+@@ -157,8 +157,8 @@ static void dw_pci_bottom_mask(struct ir
+       bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
+       pp->irq_mask[ctrl] |= BIT(bit);
+-      dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
+-                          pp->irq_mask[ctrl]);
++      dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
++                          ~pp->irq_mask[ctrl]);
+       raw_spin_unlock_irqrestore(&pp->lock, flags);
+ }
+@@ -176,8 +176,8 @@ static void dw_pci_bottom_unmask(struct
+       bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
+       pp->irq_mask[ctrl] &= ~BIT(bit);
+-      dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
+-                          pp->irq_mask[ctrl]);
++      dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
++                          ~pp->irq_mask[ctrl]);
+       raw_spin_unlock_irqrestore(&pp->lock, flags);
+ }
+@@ -657,15 +657,10 @@ void dw_pcie_setup_rc(struct pcie_port *
+               num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
+               /* Initialize IRQ Status array */
+-              for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
+-                      pp->irq_mask[ctrl] = ~0;
+-                      dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK +
++              for (ctrl = 0; ctrl < num_ctrls; ctrl++)
++                      dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
+                                           (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
+-                                          4, pp->irq_mask[ctrl]);
+-                      dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
+-                                          (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
+-                                          4, ~0);
+-              }
++                                          4, &pp->irq_mask[ctrl]);
+       }
+       /* Setup RC BARs */
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0003-PCI-dwc-fix-the-msi-failure-after-pm-operations.patch b/target/linux/layerscape/patches-5.4/812-pcie-0003-PCI-dwc-fix-the-msi-failure-after-pm-operations.patch
new file mode 100644 (file)
index 0000000..235daca
--- /dev/null
@@ -0,0 +1,32 @@
+From f5db8274c8d6c86812fd2036ae49153d3ade3eaa Mon Sep 17 00:00:00 2001
+From: richard zhu <hongxing.zhu@nxp.com>
+Date: Wed, 6 Nov 2019 15:11:36 +0800
+Subject: [PATCH] PCI: dwc: fix the msi failure after pm operations
+
+The controller may be powered off (Link is in L3) during the suspend
+mode. The MSI_ADDR would be missed after resume and MSI function
+would be failed.
+Re-store MSI_ADDR to fix the MSI failure after PM operations.
+
+Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
+Acked-by: Fugang Duan <fugang.duan@nxp.com>
+Acked-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+---
+ drivers/pci/controller/dwc/pcie-designware-host.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/pci/controller/dwc/pcie-designware-host.c
++++ b/drivers/pci/controller/dwc/pcie-designware-host.c
+@@ -654,6 +654,12 @@ void dw_pcie_setup_rc(struct pcie_port *
+       dw_pcie_setup(pci);
+       if (!pp->ops->msi_host_init) {
++              /* Program the msi_data */
++              dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
++                                  lower_32_bits((u64)pp->msi_data));
++              dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4,
++                                  upper_32_bits((u64)pp->msi_data));
++
+               num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
+               /* Initialize IRQ Status array */
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0004-pci-add-support-aer-pme-interrupts-with-none-MSI-MSI.patch b/target/linux/layerscape/patches-5.4/812-pcie-0004-pci-add-support-aer-pme-interrupts-with-none-MSI-MSI.patch
new file mode 100644 (file)
index 0000000..1175efa
--- /dev/null
@@ -0,0 +1,239 @@
+From dc17fd4b8c27ca47fb5d9113df715579bc4a04a3 Mon Sep 17 00:00:00 2001
+From: Po Liu <po.liu@nxp.com>
+Date: Fri, 30 Sep 2016 17:11:37 +0800
+Subject: [PATCH] pci:add support aer/pme interrupts with none MSI/MSI-X/INTx
+ mode
+
+On some platforms, root port doesn't support MSI/MSI-X/INTx in RC mode.
+When chip support the aer/pme interrupts with none MSI/MSI-X/INTx mode,
+maybe there is interrupt line for aer pme etc. Search the interrupt
+number in the fdt file. Then fixup the dev->irq with it.
+
+Signed-off-by: Po Liu <po.liu@nxp.com>
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+---
+ .../devicetree/bindings/pci/layerscape-pci.txt     | 13 +++++--
+ arch/arm/kernel/bios32.c                           | 44 ++++++++++++++++++++++
+ arch/arm64/kernel/pci.c                            | 44 ++++++++++++++++++++++
+ drivers/pci/pcie/portdrv_core.c                    | 29 ++++++++++++++
+ include/linux/pci.h                                |  1 +
+ 5 files changed, 127 insertions(+), 4 deletions(-)
+
+--- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt
++++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt
+@@ -26,8 +26,12 @@ Required properties:
+ - reg: base addresses and lengths of the PCIe controller register blocks.
+ - interrupts: A list of interrupt outputs of the controller. Must contain an
+   entry for each entry in the interrupt-names property.
+-- interrupt-names: Must include the following entries:
+-  "intr": The interrupt that is asserted for controller interrupts
++- interrupt-names: It could include the following entries:
++  "aer": Asserted for aer interrupt when chip support the aer interrupt with
++               none MSI/MSI-X/INTx mode,but there is interrupt line for aer.
++  "pme": Asserted for pme interrupt when chip support the pme interrupt with
++               none MSI/MSI-X/INTx mode,but there is interrupt line for pme.
++  ......
+ - fsl,pcie-scfg: Must include two entries.
+   The first entry must be a link to the SCFG device node
+   The second entry must be '0' or '1' based on physical PCIe controller index.
+@@ -43,8 +47,9 @@ Example:
+               reg = <0x00 0x03400000 0x0 0x00010000   /* controller registers */
+                      0x40 0x00000000 0x0 0x00002000>; /* configuration space */
+               reg-names = "regs", "config";
+-              interrupts = <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>; /* controller interrupt */
+-              interrupt-names = "intr";
++              interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>, /* aer interrupt */
++                      <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>; /* pme interrupt */
++              interrupt-names = "aer", "pme";
+               fsl,pcie-scfg = <&scfg 0>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+--- a/arch/arm/kernel/bios32.c
++++ b/arch/arm/kernel/bios32.c
+@@ -12,11 +12,14 @@
+ #include <linux/slab.h>
+ #include <linux/init.h>
+ #include <linux/io.h>
++#include <linux/of_irq.h>
+ #include <asm/mach-types.h>
+ #include <asm/mach/map.h>
+ #include <asm/mach/pci.h>
++#include "../../../drivers/pci/pcie/portdrv.h"
++
+ static int debug_pci;
+ /*
+@@ -65,6 +68,47 @@ void pcibios_report_status(u_int status_
+ }
+ /*
++ * Check device tree if the service interrupts are there
++ */
++int pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask)
++{
++      int ret, count = 0;
++      struct device_node *np = NULL;
++
++      if (dev->bus->dev.of_node)
++              np = dev->bus->dev.of_node;
++
++      if (np == NULL)
++              return 0;
++
++      if (!IS_ENABLED(CONFIG_OF_IRQ))
++              return 0;
++
++      /* If root port doesn't support MSI/MSI-X/INTx in RC mode,
++       * request irq for aer
++       */
++      if (mask & PCIE_PORT_SERVICE_AER) {
++              ret = of_irq_get_byname(np, "aer");
++              if (ret > 0) {
++                      irqs[PCIE_PORT_SERVICE_AER_SHIFT] = ret;
++                      count++;
++              }
++      }
++
++      if (mask & PCIE_PORT_SERVICE_PME) {
++              ret = of_irq_get_byname(np, "pme");
++              if (ret > 0) {
++                      irqs[PCIE_PORT_SERVICE_PME_SHIFT] = ret;
++                      count++;
++              }
++      }
++
++      /* TODO: add more service interrupts if there it is in the device tree*/
++
++      return count;
++}
++
++/*
+  * We don't use this to fix the device, but initialisation of it.
+  * It's not the correct use for this, but it works.
+  * Note that the arbiter/ISA bridge appears to be buggy, specifically in
+--- a/arch/arm64/kernel/pci.c
++++ b/arch/arm64/kernel/pci.c
+@@ -13,11 +13,14 @@
+ #include <linux/mm.h>
+ #include <linux/of_pci.h>
+ #include <linux/of_platform.h>
++#include <linux/of_irq.h>
+ #include <linux/pci.h>
+ #include <linux/pci-acpi.h>
+ #include <linux/pci-ecam.h>
+ #include <linux/slab.h>
++#include "../../../drivers/pci/pcie/portdrv.h"
++
+ #ifdef CONFIG_ACPI
+ /*
+  * Try to assign the IRQ number when probing a new device
+@@ -32,6 +35,47 @@ int pcibios_alloc_irq(struct pci_dev *de
+ #endif
+ /*
++ * Check device tree if the service interrupts are there
++ */
++int pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask)
++{
++      int ret, count = 0;
++      struct device_node *np = NULL;
++
++      if (dev->bus->dev.of_node)
++              np = dev->bus->dev.of_node;
++
++      if (np == NULL)
++              return 0;
++
++      if (!IS_ENABLED(CONFIG_OF_IRQ))
++              return 0;
++
++      /* If root port doesn't support MSI/MSI-X/INTx in RC mode,
++       * request irq for aer
++       */
++      if (mask & PCIE_PORT_SERVICE_AER) {
++              ret = of_irq_get_byname(np, "aer");
++              if (ret > 0) {
++                      irqs[PCIE_PORT_SERVICE_AER_SHIFT] = ret;
++                      count++;
++              }
++      }
++
++      if (mask & PCIE_PORT_SERVICE_PME) {
++              ret = of_irq_get_byname(np, "pme");
++              if (ret > 0) {
++                      irqs[PCIE_PORT_SERVICE_PME_SHIFT] = ret;
++                      count++;
++              }
++      }
++
++      /* TODO: add more service interrupts if there it is in the device tree*/
++
++      return count;
++}
++
++/*
+  * raw_pci_read/write - Platform-specific PCI config space access.
+  */
+ int raw_pci_read(unsigned int domain, unsigned int bus,
+--- a/drivers/pci/pcie/portdrv_core.c
++++ b/drivers/pci/pcie/portdrv_core.c
+@@ -37,6 +37,20 @@ static void release_pcie_device(struct d
+       kfree(to_pcie_device(dev));
+ }
++/**
++ * pcibios_check_service_irqs - check irqs in the device tree
++ * @dev: PCI Express port to handle
++ * @irqs: Array of irqs to populate
++ * @mask: Bitmask of port capabilities returned by get_port_device_capability()
++ *
++ * Return value: 0 means no service irqs in the device tree
++ *
++ */
++int __weak pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask)
++{
++      return 0;
++}
++
+ /*
+  * Fill in *pme, *aer, *dpc with the relevant Interrupt Message Numbers if
+  * services are enabled in "mask".  Return the number of MSI/MSI-X vectors
+@@ -165,10 +179,25 @@ static int pcie_port_enable_irq_vec(stru
+ static int pcie_init_service_irqs(struct pci_dev *dev, int *irqs, int mask)
+ {
+       int ret, i;
++      int irq = -1;
+       for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
+               irqs[i] = -1;
++      /* Check if some platforms owns independent irq pins for AER/PME etc.
++       * Some platforms may own independent AER/PME interrupts and set
++       * them in the device tree file.
++       */
++      ret = pcibios_check_service_irqs(dev, irqs, mask);
++      if (ret) {
++              if (dev->irq)
++                      irq = dev->irq;
++              for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
++                      if (irqs[i] == -1)
++                              irqs[i] = irq;
++              return 0;
++      }
++
+       /*
+        * If we support PME but can't use MSI/MSI-X for it, we have to
+        * fall back to INTx or other interrupts, e.g., a system shared
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -2021,6 +2021,7 @@ static inline void pcibios_penalize_isa_
+ int pcibios_alloc_irq(struct pci_dev *dev);
+ void pcibios_free_irq(struct pci_dev *dev);
+ resource_size_t pcibios_default_alignment(void);
++int pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask);
+ #ifdef CONFIG_HIBERNATE_CALLBACKS
+ extern struct dev_pm_ops pcibios_pm_ops;
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0005-MLK-20684-PCI-Disable-MSI-on-CYW4356-and-CYW4359-chi.patch b/target/linux/layerscape/patches-5.4/812-pcie-0005-MLK-20684-PCI-Disable-MSI-on-CYW4356-and-CYW4359-chi.patch
new file mode 100644 (file)
index 0000000..dfda1aa
--- /dev/null
@@ -0,0 +1,30 @@
+From 852d91023cc24663e6b3b0707e98a189a7b1de87 Mon Sep 17 00:00:00 2001
+From: Andy Duan <fugang.duan@nxp.com>
+Date: Wed, 2 Jan 2019 17:55:44 +0800
+Subject: [PATCH] MLK-20684 PCI: Disable MSI on CYW4356 and CYW4359 chips
+
+MSI is broken on CYW4356/4359 chips. This causes CYW4356 1CX not
+work on i.MX8x platforms with bandwidth test. It is known issue
+that i.MX8x PCIe host driver MSI interrupt lost.
+
+Disable MSI completely for this chipset to let wifi can stable work
+until PCIe RC driver fix the issue.
+
+Reviewed-by: Richard Zhu <hongxing.zhu@nxp.com>
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+(cherry picked from commit d99766187fb99d4a6655a1e0fdf5dc9451a8e4a0)
+---
+ drivers/pci/quirks.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -2444,6 +2444,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VI
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3364, quirk_disable_all_msi);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8380_0, quirk_disable_all_msi);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, 0x0761, quirk_disable_all_msi);
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x43ec, quirk_disable_all_msi);
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x43ef, quirk_disable_all_msi);
+ /* Disable MSI on chipsets that are known to not support it */
+ static void quirk_disable_msi(struct pci_dev *dev)
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0006-MLK-20716-PCI-add-quirk-for-cyw4356-to-disable-D3-mo.patch b/target/linux/layerscape/patches-5.4/812-pcie-0006-MLK-20716-PCI-add-quirk-for-cyw4356-to-disable-D3-mo.patch
new file mode 100644 (file)
index 0000000..cb81748
--- /dev/null
@@ -0,0 +1,30 @@
+From c116c7d1393e5afdcbb2e4defd002bb3445f5708 Mon Sep 17 00:00:00 2001
+From: Andy Duan <fugang.duan@nxp.com>
+Date: Mon, 7 Jan 2019 18:45:41 +0800
+Subject: [PATCH] MLK-20716 PCI: add quirk for cyw4356 to disable D3 mode
+
+Add quirk for cyw4356 to disable D3 mode because current firmware
+still doesn't support D3 mode.
+
+Reviewed-by: Richard Zhu <hongxing.zhu@nxp.com>
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+Signed-off-by: Arulpandiyan Vadivel <arulpandiyan_vadivel@mentor.com>
+Signed-off-by: Shrikant Bobade <Shrikant_Bobade@mentor.com>
+(cherry picked from commit 22212c60d7fb067e28a2fed16914515e3d6d3950)
+---
+ drivers/pci/quirks.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -1356,6 +1356,10 @@ DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR
+    occur when mode detecting */
+ DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_VIA, PCI_ANY_ID,
+                               PCI_CLASS_STORAGE_IDE, 8, quirk_no_ata_d3);
++/* Quirk the CYW4356 WIFI chip because the firmware still doesn't support
++   D3 mode */
++DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_BROADCOM, 0x43ec,
++                              PCI_CLASS_NETWORK_OTHER, 8, quirk_no_ata_d3);
+ /*
+  * This was originally an Alpha-specific thing, but it really fits here.
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0007-PCI-Disable-MSI-on-marvel-88w9098-and-88w8997-chips.patch b/target/linux/layerscape/patches-5.4/812-pcie-0007-PCI-Disable-MSI-on-marvel-88w9098-and-88w8997-chips.patch
new file mode 100644 (file)
index 0000000..5b96b84
--- /dev/null
@@ -0,0 +1,26 @@
+From 086cbc69787a71693ef94aa97438b06631850ed5 Mon Sep 17 00:00:00 2001
+From: Fugang Duan <fugang.duan@nxp.com>
+Date: Mon, 4 Nov 2019 13:48:52 +0800
+Subject: [PATCH] PCI: Disable MSI on marvel 88w9098 and 88w8997 chips
+
+i.MX8x with MSI enable suspend/resume doesn't work for
+marvell 88w9098 and 88w8997 wlan chips, disable the feature
+before the issue fixed.
+
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+---
+ drivers/pci/quirks.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -2450,6 +2450,9 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VI
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, 0x0761, quirk_disable_all_msi);
+ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x43ec, quirk_disable_all_msi);
+ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x43ef, quirk_disable_all_msi);
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL_EXT, 0x2b42, quirk_disable_all_msi);
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL_EXT, 0x2b43, quirk_disable_all_msi);
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL_EXT, 0x2b44, quirk_disable_all_msi);
+ /* Disable MSI on chipsets that are known to not support it */
+ static void quirk_disable_msi(struct pci_dev *dev)
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0008-Revert-PCI-mobiveil-Fix-csr_read-write-build-issue.patch b/target/linux/layerscape/patches-5.4/812-pcie-0008-Revert-PCI-mobiveil-Fix-csr_read-write-build-issue.patch
new file mode 100644 (file)
index 0000000..f6ac0c4
--- /dev/null
@@ -0,0 +1,286 @@
+From c3f16eeaa68f3be291dd62efadeb733d6d40279a Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Tue, 18 Feb 2020 09:13:00 +0800
+Subject: [PATCH] Revert "PCI: mobiveil: Fix csr_read()/write() build issue"
+
+This reverts commit 1865d6440fb63ad979d7034b2d7c94937bfd2200.
+
+PCI: mobiveil: Fix csr_read()/write() build issue
+
+[ Upstream commit 4906c05b87d44c19b225935e24d62e4480ca556d ]
+---
+ drivers/pci/controller/pcie-mobiveil.c | 119 ++++++++++++++++-----------------
+ 1 file changed, 57 insertions(+), 62 deletions(-)
+
+--- a/drivers/pci/controller/pcie-mobiveil.c
++++ b/drivers/pci/controller/pcie-mobiveil.c
+@@ -235,7 +235,7 @@ static int mobiveil_pcie_write(void __io
+       return PCIBIOS_SUCCESSFUL;
+ }
+-static u32 mobiveil_csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
++static u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
+ {
+       void *addr;
+       u32 val;
+@@ -250,8 +250,7 @@ static u32 mobiveil_csr_read(struct mobi
+       return val;
+ }
+-static void mobiveil_csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off,
+-                             size_t size)
++static void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_t size)
+ {
+       void *addr;
+       int ret;
+@@ -263,19 +262,19 @@ static void mobiveil_csr_write(struct mo
+               dev_err(&pcie->pdev->dev, "write CSR address failed\n");
+ }
+-static u32 mobiveil_csr_readl(struct mobiveil_pcie *pcie, u32 off)
++static u32 csr_readl(struct mobiveil_pcie *pcie, u32 off)
+ {
+-      return mobiveil_csr_read(pcie, off, 0x4);
++      return csr_read(pcie, off, 0x4);
+ }
+-static void mobiveil_csr_writel(struct mobiveil_pcie *pcie, u32 val, u32 off)
++static void csr_writel(struct mobiveil_pcie *pcie, u32 val, u32 off)
+ {
+-      mobiveil_csr_write(pcie, val, off, 0x4);
++      csr_write(pcie, val, off, 0x4);
+ }
+ static bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie)
+ {
+-      return (mobiveil_csr_readl(pcie, LTSSM_STATUS) &
++      return (csr_readl(pcie, LTSSM_STATUS) &
+               LTSSM_STATUS_L0_MASK) == LTSSM_STATUS_L0;
+ }
+@@ -324,7 +323,7 @@ static void __iomem *mobiveil_pcie_map_b
+               PCI_SLOT(devfn) << PAB_DEVICE_SHIFT |
+               PCI_FUNC(devfn) << PAB_FUNCTION_SHIFT;
+-      mobiveil_csr_writel(pcie, value, PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));
++      csr_writel(pcie, value, PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));
+       return pcie->config_axi_slave_base + where;
+ }
+@@ -354,14 +353,13 @@ static void mobiveil_pcie_isr(struct irq
+       chained_irq_enter(chip, desc);
+       /* read INTx status */
+-      val = mobiveil_csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT);
+-      mask = mobiveil_csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
++      val = csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT);
++      mask = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
+       intr_status = val & mask;
+       /* Handle INTx */
+       if (intr_status & PAB_INTP_INTX_MASK) {
+-              shifted_status = mobiveil_csr_readl(pcie,
+-                                                  PAB_INTP_AMBA_MISC_STAT);
++              shifted_status = csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT);
+               shifted_status &= PAB_INTP_INTX_MASK;
+               shifted_status >>= PAB_INTX_START;
+               do {
+@@ -375,13 +373,12 @@ static void mobiveil_pcie_isr(struct irq
+                                                           bit);
+                               /* clear interrupt handled */
+-                              mobiveil_csr_writel(pcie,
+-                                                  1 << (PAB_INTX_START + bit),
+-                                                  PAB_INTP_AMBA_MISC_STAT);
++                              csr_writel(pcie, 1 << (PAB_INTX_START + bit),
++                                         PAB_INTP_AMBA_MISC_STAT);
+                       }
+-                      shifted_status = mobiveil_csr_readl(pcie,
+-                                                          PAB_INTP_AMBA_MISC_STAT);
++                      shifted_status = csr_readl(pcie,
++                                                 PAB_INTP_AMBA_MISC_STAT);
+                       shifted_status &= PAB_INTP_INTX_MASK;
+                       shifted_status >>= PAB_INTX_START;
+               } while (shifted_status != 0);
+@@ -416,7 +413,7 @@ static void mobiveil_pcie_isr(struct irq
+       }
+       /* Clear the interrupt status */
+-      mobiveil_csr_writel(pcie, intr_status, PAB_INTP_AMBA_MISC_STAT);
++      csr_writel(pcie, intr_status, PAB_INTP_AMBA_MISC_STAT);
+       chained_irq_exit(chip, desc);
+ }
+@@ -477,24 +474,24 @@ static void program_ib_windows(struct mo
+               return;
+       }
+-      value = mobiveil_csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
++      value = csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
+       value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK);
+       value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT |
+                (lower_32_bits(size64) & WIN_SIZE_MASK);
+-      mobiveil_csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));
++      csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));
+-      mobiveil_csr_writel(pcie, upper_32_bits(size64),
+-                          PAB_EXT_PEX_AMAP_SIZEN(win_num));
++      csr_writel(pcie, upper_32_bits(size64),
++                 PAB_EXT_PEX_AMAP_SIZEN(win_num));
+-      mobiveil_csr_writel(pcie, lower_32_bits(cpu_addr),
+-                          PAB_PEX_AMAP_AXI_WIN(win_num));
+-      mobiveil_csr_writel(pcie, upper_32_bits(cpu_addr),
+-                          PAB_EXT_PEX_AMAP_AXI_WIN(win_num));
+-
+-      mobiveil_csr_writel(pcie, lower_32_bits(pci_addr),
+-                          PAB_PEX_AMAP_PEX_WIN_L(win_num));
+-      mobiveil_csr_writel(pcie, upper_32_bits(pci_addr),
+-                          PAB_PEX_AMAP_PEX_WIN_H(win_num));
++      csr_writel(pcie, lower_32_bits(cpu_addr),
++                 PAB_PEX_AMAP_AXI_WIN(win_num));
++      csr_writel(pcie, upper_32_bits(cpu_addr),
++                 PAB_EXT_PEX_AMAP_AXI_WIN(win_num));
++
++      csr_writel(pcie, lower_32_bits(pci_addr),
++                 PAB_PEX_AMAP_PEX_WIN_L(win_num));
++      csr_writel(pcie, upper_32_bits(pci_addr),
++                 PAB_PEX_AMAP_PEX_WIN_H(win_num));
+       pcie->ib_wins_configured++;
+ }
+@@ -518,29 +515,27 @@ static void program_ob_windows(struct mo
+        * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
+        * to 4 KB in PAB_AXI_AMAP_CTRL register
+        */
+-      value = mobiveil_csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
++      value = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
+       value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK);
+       value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT |
+                (lower_32_bits(size64) & WIN_SIZE_MASK);
+-      mobiveil_csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num));
++      csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num));
+-      mobiveil_csr_writel(pcie, upper_32_bits(size64),
+-                          PAB_EXT_AXI_AMAP_SIZE(win_num));
++      csr_writel(pcie, upper_32_bits(size64), PAB_EXT_AXI_AMAP_SIZE(win_num));
+       /*
+        * program AXI window base with appropriate value in
+        * PAB_AXI_AMAP_AXI_WIN0 register
+        */
+-      mobiveil_csr_writel(pcie,
+-                          lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
+-                          PAB_AXI_AMAP_AXI_WIN(win_num));
+-      mobiveil_csr_writel(pcie, upper_32_bits(cpu_addr),
+-                          PAB_EXT_AXI_AMAP_AXI_WIN(win_num));
+-
+-      mobiveil_csr_writel(pcie, lower_32_bits(pci_addr),
+-                          PAB_AXI_AMAP_PEX_WIN_L(win_num));
+-      mobiveil_csr_writel(pcie, upper_32_bits(pci_addr),
+-                          PAB_AXI_AMAP_PEX_WIN_H(win_num));
++      csr_writel(pcie, lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
++                 PAB_AXI_AMAP_AXI_WIN(win_num));
++      csr_writel(pcie, upper_32_bits(cpu_addr),
++                 PAB_EXT_AXI_AMAP_AXI_WIN(win_num));
++
++      csr_writel(pcie, lower_32_bits(pci_addr),
++                 PAB_AXI_AMAP_PEX_WIN_L(win_num));
++      csr_writel(pcie, upper_32_bits(pci_addr),
++                 PAB_AXI_AMAP_PEX_WIN_H(win_num));
+       pcie->ob_wins_configured++;
+ }
+@@ -584,42 +579,42 @@ static int mobiveil_host_init(struct mob
+       struct resource_entry *win;
+       /* setup bus numbers */
+-      value = mobiveil_csr_readl(pcie, PCI_PRIMARY_BUS);
++      value = csr_readl(pcie, PCI_PRIMARY_BUS);
+       value &= 0xff000000;
+       value |= 0x00ff0100;
+-      mobiveil_csr_writel(pcie, value, PCI_PRIMARY_BUS);
++      csr_writel(pcie, value, PCI_PRIMARY_BUS);
+       /*
+        * program Bus Master Enable Bit in Command Register in PAB Config
+        * Space
+        */
+-      value = mobiveil_csr_readl(pcie, PCI_COMMAND);
++      value = csr_readl(pcie, PCI_COMMAND);
+       value |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+-      mobiveil_csr_writel(pcie, value, PCI_COMMAND);
++      csr_writel(pcie, value, PCI_COMMAND);
+       /*
+        * program PIO Enable Bit to 1 (and PEX PIO Enable to 1) in PAB_CTRL
+        * register
+        */
+-      pab_ctrl = mobiveil_csr_readl(pcie, PAB_CTRL);
++      pab_ctrl = csr_readl(pcie, PAB_CTRL);
+       pab_ctrl |= (1 << AMBA_PIO_ENABLE_SHIFT) | (1 << PEX_PIO_ENABLE_SHIFT);
+-      mobiveil_csr_writel(pcie, pab_ctrl, PAB_CTRL);
++      csr_writel(pcie, pab_ctrl, PAB_CTRL);
+-      mobiveil_csr_writel(pcie, (PAB_INTP_INTX_MASK | PAB_INTP_MSI_MASK),
+-                          PAB_INTP_AMBA_MISC_ENB);
++      csr_writel(pcie, (PAB_INTP_INTX_MASK | PAB_INTP_MSI_MASK),
++                 PAB_INTP_AMBA_MISC_ENB);
+       /*
+        * program PIO Enable Bit to 1 and Config Window Enable Bit to 1 in
+        * PAB_AXI_PIO_CTRL Register
+        */
+-      value = mobiveil_csr_readl(pcie, PAB_AXI_PIO_CTRL);
++      value = csr_readl(pcie, PAB_AXI_PIO_CTRL);
+       value |= APIO_EN_MASK;
+-      mobiveil_csr_writel(pcie, value, PAB_AXI_PIO_CTRL);
++      csr_writel(pcie, value, PAB_AXI_PIO_CTRL);
+       /* Enable PCIe PIO master */
+-      value = mobiveil_csr_readl(pcie, PAB_PEX_PIO_CTRL);
++      value = csr_readl(pcie, PAB_PEX_PIO_CTRL);
+       value |= 1 << PIO_ENABLE_SHIFT;
+-      mobiveil_csr_writel(pcie, value, PAB_PEX_PIO_CTRL);
++      csr_writel(pcie, value, PAB_PEX_PIO_CTRL);
+       /*
+        * we'll program one outbound window for config reads and
+@@ -652,10 +647,10 @@ static int mobiveil_host_init(struct mob
+       }
+       /* fixup for PCIe class register */
+-      value = mobiveil_csr_readl(pcie, PAB_INTP_AXI_PIO_CLASS);
++      value = csr_readl(pcie, PAB_INTP_AXI_PIO_CLASS);
+       value &= 0xff;
+       value |= (PCI_CLASS_BRIDGE_PCI << 16);
+-      mobiveil_csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS);
++      csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS);
+       /* setup MSI hardware registers */
+       mobiveil_pcie_enable_msi(pcie);
+@@ -673,9 +668,9 @@ static void mobiveil_mask_intx_irq(struc
+       pcie = irq_desc_get_chip_data(desc);
+       mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
+       raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
+-      shifted_val = mobiveil_csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
++      shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
+       shifted_val &= ~mask;
+-      mobiveil_csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
++      csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
+       raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags);
+ }
+@@ -689,9 +684,9 @@ static void mobiveil_unmask_intx_irq(str
+       pcie = irq_desc_get_chip_data(desc);
+       mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
+       raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
+-      shifted_val = mobiveil_csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
++      shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
+       shifted_val |= mask;
+-      mobiveil_csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
++      csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
+       raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags);
+ }
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0009-PCI-mobiveil-Refactor-Mobiveil-PCIe-Host-Bridge-IP-d.patch b/target/linux/layerscape/patches-5.4/812-pcie-0009-PCI-mobiveil-Refactor-Mobiveil-PCIe-Host-Bridge-IP-d.patch
new file mode 100644 (file)
index 0000000..9494317
--- /dev/null
@@ -0,0 +1,2184 @@
+From ab6a07d577dbd45d00a1738a6b5a28a6666be754 Mon Sep 17 00:00:00 2001
+From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Date: Tue, 25 Jun 2019 09:09:07 +0000
+Subject: [PATCH] PCI: mobiveil: Refactor Mobiveil PCIe Host Bridge IP driver
+
+Refactor the Mobiveil PCIe Host Bridge IP driver to make
+it easier to add support for both RC and EP mode driver.
+This patch moved the Mobiveil driver to an new directory
+'drivers/pci/controller/mobiveil' and refactor it according
+to the RC and EP abstraction.
+
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Reviewed-by: Minghuan Lian <Minghuan.Lian@nxp.com>
+Reviewed-by: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
+---
+ MAINTAINERS                                        |   2 +-
+ drivers/pci/controller/Kconfig                     |  11 +-
+ drivers/pci/controller/Makefile                    |   2 +-
+ drivers/pci/controller/mobiveil/Kconfig            |  24 +
+ drivers/pci/controller/mobiveil/Makefile           |   4 +
+ .../pci/controller/mobiveil/pcie-mobiveil-host.c   | 611 +++++++++++++
+ .../pci/controller/mobiveil/pcie-mobiveil-plat.c   |  59 ++
+ drivers/pci/controller/mobiveil/pcie-mobiveil.c    | 227 +++++
+ drivers/pci/controller/mobiveil/pcie-mobiveil.h    | 189 ++++
+ drivers/pci/controller/pcie-mobiveil.c             | 964 ---------------------
+ 10 files changed, 1117 insertions(+), 976 deletions(-)
+ create mode 100644 drivers/pci/controller/mobiveil/Kconfig
+ create mode 100644 drivers/pci/controller/mobiveil/Makefile
+ create mode 100644 drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
+ create mode 100644 drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c
+ create mode 100644 drivers/pci/controller/mobiveil/pcie-mobiveil.c
+ create mode 100644 drivers/pci/controller/mobiveil/pcie-mobiveil.h
+ delete mode 100644 drivers/pci/controller/pcie-mobiveil.c
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -12502,7 +12502,7 @@ M:     Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+ L:    linux-pci@vger.kernel.org
+ S:    Supported
+ F:    Documentation/devicetree/bindings/pci/mobiveil-pcie.txt
+-F:    drivers/pci/controller/pcie-mobiveil.c
++F:    drivers/pci/controller/mobiveil/pcie-mobiveil*
+ PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support)
+ M:    Thomas Petazzoni <thomas.petazzoni@bootlin.com>
+--- a/drivers/pci/controller/Kconfig
++++ b/drivers/pci/controller/Kconfig
+@@ -241,16 +241,6 @@ config PCIE_MEDIATEK
+         Say Y here if you want to enable PCIe controller support on
+         MediaTek SoCs.
+-config PCIE_MOBIVEIL
+-      bool "Mobiveil AXI PCIe controller"
+-      depends on ARCH_ZYNQMP || COMPILE_TEST
+-      depends on OF
+-      depends on PCI_MSI_IRQ_DOMAIN
+-      help
+-        Say Y here if you want to enable support for the Mobiveil AXI PCIe
+-        Soft IP. It has up to 8 outbound and inbound windows
+-        for address translation and it is a PCIe Gen4 IP.
+-
+ config PCIE_TANGO_SMP8759
+       bool "Tango SMP8759 PCIe controller (DANGEROUS)"
+       depends on ARCH_TANGO && PCI_MSI && OF
+@@ -289,4 +279,5 @@ config PCI_HYPERV_INTERFACE
+         have a common interface with the Hyper-V PCI frontend driver.
+ source "drivers/pci/controller/dwc/Kconfig"
++source "drivers/pci/controller/mobiveil/Kconfig"
+ endmenu
+--- a/drivers/pci/controller/Makefile
++++ b/drivers/pci/controller/Makefile
+@@ -27,11 +27,11 @@ obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rock
+ obj-$(CONFIG_PCIE_ROCKCHIP_EP) += pcie-rockchip-ep.o
+ obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o
+ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
+-obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
+ obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
+ obj-$(CONFIG_VMD) += vmd.o
+ # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
+ obj-y                         += dwc/
++obj-y                         += mobiveil/
+ # The following drivers are for devices that use the generic ACPI
+--- /dev/null
++++ b/drivers/pci/controller/mobiveil/Kconfig
+@@ -0,0 +1,24 @@
++# SPDX-License-Identifier: GPL-2.0
++
++menu "Mobiveil PCIe Core Support"
++      depends on PCI
++
++config PCIE_MOBIVEIL
++      bool
++
++config PCIE_MOBIVEIL_HOST
++        bool
++      depends on PCI_MSI_IRQ_DOMAIN
++        select PCIE_MOBIVEIL
++
++config PCIE_MOBIVEIL_PLAT
++      bool "Mobiveil AXI PCIe controller"
++      depends on ARCH_ZYNQMP || COMPILE_TEST
++      depends on OF
++      select PCIE_MOBIVEIL_HOST
++      help
++        Say Y here if you want to enable support for the Mobiveil AXI PCIe
++        Soft IP. It has up to 8 outbound and inbound windows
++        for address translation and it is a PCIe Gen4 IP.
++
++endmenu
+--- /dev/null
++++ b/drivers/pci/controller/mobiveil/Makefile
+@@ -0,0 +1,4 @@
++# SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
++obj-$(CONFIG_PCIE_MOBIVEIL_HOST) += pcie-mobiveil-host.o
++obj-$(CONFIG_PCIE_MOBIVEIL_PLAT) += pcie-mobiveil-plat.o
+--- /dev/null
++++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
+@@ -0,0 +1,611 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * PCIe host controller driver for Mobiveil PCIe Host controller
++ *
++ * Copyright (c) 2018 Mobiveil Inc.
++ * Copyright 2019 NXP
++ *
++ * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
++ * Refactor: Zhiqiang Hou <Zhiqiang.Hou@nxp.com>
++ */
++
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/irqchip/chained_irq.h>
++#include <linux/irqdomain.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/msi.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/of_platform.h>
++#include <linux/of_pci.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include "pcie-mobiveil.h"
++
++static bool mobiveil_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
++{
++      struct mobiveil_pcie *pcie = bus->sysdata;
++
++      /* Only one device down on each root port */
++      if ((bus->number == pcie->rp.root_bus_nr) && (devfn > 0))
++              return false;
++
++      /*
++       * Do not read more than one device on the bus directly
++       * attached to RC
++       */
++      if ((bus->primary == pcie->rp.root_bus_nr) && (PCI_SLOT(devfn) > 0))
++              return false;
++
++      return true;
++}
++
++/*
++ * mobiveil_pcie_map_bus - routine to get the configuration base of either
++ * root port or endpoint
++ */
++static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus,
++                                         unsigned int devfn, int where)
++{
++      struct mobiveil_pcie *pcie = bus->sysdata;
++      u32 value;
++
++      if (!mobiveil_pcie_valid_device(bus, devfn))
++              return NULL;
++
++      /* RC config access */
++      if (bus->number == pcie->rp.root_bus_nr)
++              return pcie->csr_axi_slave_base + where;
++
++      /*
++       * EP config access (in Config/APIO space)
++       * Program PEX Address base (31..16 bits) with appropriate value
++       * (BDF) in PAB_AXI_AMAP_PEX_WIN_L0 Register.
++       * Relies on pci_lock serialization
++       */
++      value = bus->number << PAB_BUS_SHIFT |
++              PCI_SLOT(devfn) << PAB_DEVICE_SHIFT |
++              PCI_FUNC(devfn) << PAB_FUNCTION_SHIFT;
++
++      csr_writel(pcie, value, PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));
++
++      return pcie->rp.config_axi_slave_base + where;
++}
++
++static struct pci_ops mobiveil_pcie_ops = {
++      .map_bus = mobiveil_pcie_map_bus,
++      .read = pci_generic_config_read,
++      .write = pci_generic_config_write,
++};
++
++static void mobiveil_pcie_isr(struct irq_desc *desc)
++{
++      struct irq_chip *chip = irq_desc_get_chip(desc);
++      struct mobiveil_pcie *pcie = irq_desc_get_handler_data(desc);
++      struct device *dev = &pcie->pdev->dev;
++      struct mobiveil_msi *msi = &pcie->rp.msi;
++      u32 msi_data, msi_addr_lo, msi_addr_hi;
++      u32 intr_status, msi_status;
++      unsigned long shifted_status;
++      u32 bit, virq, val, mask;
++
++      /*
++       * The core provides a single interrupt for both INTx/MSI messages.
++       * So we'll read both INTx and MSI status
++       */
++
++      chained_irq_enter(chip, desc);
++
++      /* read INTx status */
++      val = csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT);
++      mask = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
++      intr_status = val & mask;
++
++      /* Handle INTx */
++      if (intr_status & PAB_INTP_INTX_MASK) {
++              shifted_status = csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT);
++              shifted_status &= PAB_INTP_INTX_MASK;
++              shifted_status >>= PAB_INTX_START;
++              do {
++                      for_each_set_bit(bit, &shifted_status, PCI_NUM_INTX) {
++                              virq = irq_find_mapping(pcie->rp.intx_domain,
++                                                      bit + 1);
++                              if (virq)
++                                      generic_handle_irq(virq);
++                              else
++                                      dev_err_ratelimited(dev, "unexpected IRQ, INT%d\n",
++                                                          bit);
++
++                              /* clear interrupt handled */
++                              csr_writel(pcie, 1 << (PAB_INTX_START + bit),
++                                         PAB_INTP_AMBA_MISC_STAT);
++                      }
++
++                      shifted_status = csr_readl(pcie,
++                                                 PAB_INTP_AMBA_MISC_STAT);
++                      shifted_status &= PAB_INTP_INTX_MASK;
++                      shifted_status >>= PAB_INTX_START;
++              } while (shifted_status != 0);
++      }
++
++      /* read extra MSI status register */
++      msi_status = readl_relaxed(pcie->apb_csr_base + MSI_STATUS_OFFSET);
++
++      /* handle MSI interrupts */
++      while (msi_status & 1) {
++              msi_data = readl_relaxed(pcie->apb_csr_base + MSI_DATA_OFFSET);
++
++              /*
++               * MSI_STATUS_OFFSET register gets updated to zero
++               * once we pop not only the MSI data but also address
++               * from MSI hardware FIFO. So keeping these following
++               * two dummy reads.
++               */
++              msi_addr_lo = readl_relaxed(pcie->apb_csr_base +
++                                          MSI_ADDR_L_OFFSET);
++              msi_addr_hi = readl_relaxed(pcie->apb_csr_base +
++                                          MSI_ADDR_H_OFFSET);
++              dev_dbg(dev, "MSI registers, data: %08x, addr: %08x:%08x\n",
++                      msi_data, msi_addr_hi, msi_addr_lo);
++
++              virq = irq_find_mapping(msi->dev_domain, msi_data);
++              if (virq)
++                      generic_handle_irq(virq);
++
++              msi_status = readl_relaxed(pcie->apb_csr_base +
++                                         MSI_STATUS_OFFSET);
++      }
++
++      /* Clear the interrupt status */
++      csr_writel(pcie, intr_status, PAB_INTP_AMBA_MISC_STAT);
++      chained_irq_exit(chip, desc);
++}
++
++static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
++{
++      struct device *dev = &pcie->pdev->dev;
++      struct platform_device *pdev = pcie->pdev;
++      struct device_node *node = dev->of_node;
++      struct resource *res;
++
++      /* map config resource */
++      res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
++                                         "config_axi_slave");
++      pcie->rp.config_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
++      if (IS_ERR(pcie->rp.config_axi_slave_base))
++              return PTR_ERR(pcie->rp.config_axi_slave_base);
++      pcie->rp.ob_io_res = res;
++
++      /* map csr resource */
++      res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
++                                         "csr_axi_slave");
++      pcie->csr_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
++      if (IS_ERR(pcie->csr_axi_slave_base))
++              return PTR_ERR(pcie->csr_axi_slave_base);
++      pcie->pcie_reg_base = res->start;
++
++      /* read the number of windows requested */
++      if (of_property_read_u32(node, "apio-wins", &pcie->apio_wins))
++              pcie->apio_wins = MAX_PIO_WINDOWS;
++
++      if (of_property_read_u32(node, "ppio-wins", &pcie->ppio_wins))
++              pcie->ppio_wins = MAX_PIO_WINDOWS;
++
++      return 0;
++}
++
++static void mobiveil_pcie_enable_msi(struct mobiveil_pcie *pcie)
++{
++      phys_addr_t msg_addr = pcie->pcie_reg_base;
++      struct mobiveil_msi *msi = &pcie->rp.msi;
++
++      msi->num_of_vectors = PCI_NUM_MSI;
++      msi->msi_pages_phys = (phys_addr_t)msg_addr;
++
++      writel_relaxed(lower_32_bits(msg_addr),
++                     pcie->apb_csr_base + MSI_BASE_LO_OFFSET);
++      writel_relaxed(upper_32_bits(msg_addr),
++                     pcie->apb_csr_base + MSI_BASE_HI_OFFSET);
++      writel_relaxed(4096, pcie->apb_csr_base + MSI_SIZE_OFFSET);
++      writel_relaxed(1, pcie->apb_csr_base + MSI_ENABLE_OFFSET);
++}
++
++static int mobiveil_host_init(struct mobiveil_pcie *pcie)
++{
++      u32 value, pab_ctrl, type;
++      struct resource_entry *win;
++
++      /* setup bus numbers */
++      value = csr_readl(pcie, PCI_PRIMARY_BUS);
++      value &= 0xff000000;
++      value |= 0x00ff0100;
++      csr_writel(pcie, value, PCI_PRIMARY_BUS);
++
++      /*
++       * program Bus Master Enable Bit in Command Register in PAB Config
++       * Space
++       */
++      value = csr_readl(pcie, PCI_COMMAND);
++      value |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
++      csr_writel(pcie, value, PCI_COMMAND);
++
++      /*
++       * program PIO Enable Bit to 1 (and PEX PIO Enable to 1) in PAB_CTRL
++       * register
++       */
++      pab_ctrl = csr_readl(pcie, PAB_CTRL);
++      pab_ctrl |= (1 << AMBA_PIO_ENABLE_SHIFT) | (1 << PEX_PIO_ENABLE_SHIFT);
++      csr_writel(pcie, pab_ctrl, PAB_CTRL);
++
++      /*
++       * program PIO Enable Bit to 1 and Config Window Enable Bit to 1 in
++       * PAB_AXI_PIO_CTRL Register
++       */
++      value = csr_readl(pcie, PAB_AXI_PIO_CTRL);
++      value |= APIO_EN_MASK;
++      csr_writel(pcie, value, PAB_AXI_PIO_CTRL);
++
++      /* Enable PCIe PIO master */
++      value = csr_readl(pcie, PAB_PEX_PIO_CTRL);
++      value |= 1 << PIO_ENABLE_SHIFT;
++      csr_writel(pcie, value, PAB_PEX_PIO_CTRL);
++
++      /*
++       * we'll program one outbound window for config reads and
++       * another default inbound window for all the upstream traffic
++       * rest of the outbound windows will be configured according to
++       * the "ranges" field defined in device tree
++       */
++
++      /* config outbound translation window */
++      program_ob_windows(pcie, WIN_NUM_0, pcie->rp.ob_io_res->start, 0,
++                         CFG_WINDOW_TYPE, resource_size(pcie->rp.ob_io_res));
++
++      /* memory inbound translation window */
++      program_ib_windows(pcie, WIN_NUM_0, 0, 0, MEM_WINDOW_TYPE, IB_WIN_SIZE);
++
++      /* Get the I/O and memory ranges from DT */
++      resource_list_for_each_entry(win, &pcie->resources) {
++              if (resource_type(win->res) == IORESOURCE_MEM) {
++                      type = MEM_WINDOW_TYPE;
++              } else if (resource_type(win->res) == IORESOURCE_IO) {
++                      type = IO_WINDOW_TYPE;
++              } else if (resource_type(win->res) == IORESOURCE_BUS) {
++                      pcie->rp.root_bus_nr = win->res->start;
++                      continue;
++              } else {
++                      continue;
++              }
++
++              /* configure outbound translation window */
++              program_ob_windows(pcie, pcie->ob_wins_configured,
++                                 win->res->start,
++                                 win->res->start - win->offset,
++                                 type, resource_size(win->res));
++      }
++
++      /* fixup for PCIe class register */
++      value = csr_readl(pcie, PAB_INTP_AXI_PIO_CLASS);
++      value &= 0xff;
++      value |= (PCI_CLASS_BRIDGE_PCI << 16);
++      csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS);
++
++      return 0;
++}
++
++static void mobiveil_mask_intx_irq(struct irq_data *data)
++{
++      struct irq_desc *desc = irq_to_desc(data->irq);
++      struct mobiveil_pcie *pcie;
++      unsigned long flags;
++      u32 mask, shifted_val;
++
++      pcie = irq_desc_get_chip_data(desc);
++      mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
++      raw_spin_lock_irqsave(&pcie->rp.intx_mask_lock, flags);
++      shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
++      shifted_val &= ~mask;
++      csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
++      raw_spin_unlock_irqrestore(&pcie->rp.intx_mask_lock, flags);
++}
++
++static void mobiveil_unmask_intx_irq(struct irq_data *data)
++{
++      struct irq_desc *desc = irq_to_desc(data->irq);
++      struct mobiveil_pcie *pcie;
++      unsigned long flags;
++      u32 shifted_val, mask;
++
++      pcie = irq_desc_get_chip_data(desc);
++      mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
++      raw_spin_lock_irqsave(&pcie->rp.intx_mask_lock, flags);
++      shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
++      shifted_val |= mask;
++      csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
++      raw_spin_unlock_irqrestore(&pcie->rp.intx_mask_lock, flags);
++}
++
++static struct irq_chip intx_irq_chip = {
++      .name = "mobiveil_pcie:intx",
++      .irq_enable = mobiveil_unmask_intx_irq,
++      .irq_disable = mobiveil_mask_intx_irq,
++      .irq_mask = mobiveil_mask_intx_irq,
++      .irq_unmask = mobiveil_unmask_intx_irq,
++};
++
++/* routine to setup the INTx related data */
++static int mobiveil_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
++                                irq_hw_number_t hwirq)
++{
++      irq_set_chip_and_handler(irq, &intx_irq_chip, handle_level_irq);
++      irq_set_chip_data(irq, domain->host_data);
++
++      return 0;
++}
++
++/* INTx domain operations structure */
++static const struct irq_domain_ops intx_domain_ops = {
++      .map = mobiveil_pcie_intx_map,
++};
++
++static struct irq_chip mobiveil_msi_irq_chip = {
++      .name = "Mobiveil PCIe MSI",
++      .irq_mask = pci_msi_mask_irq,
++      .irq_unmask = pci_msi_unmask_irq,
++};
++
++static struct msi_domain_info mobiveil_msi_domain_info = {
++      .flags  = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
++                 MSI_FLAG_PCI_MSIX),
++      .chip   = &mobiveil_msi_irq_chip,
++};
++
++static void mobiveil_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
++{
++      struct mobiveil_pcie *pcie = irq_data_get_irq_chip_data(data);
++      phys_addr_t addr = pcie->pcie_reg_base + (data->hwirq * sizeof(int));
++
++      msg->address_lo = lower_32_bits(addr);
++      msg->address_hi = upper_32_bits(addr);
++      msg->data = data->hwirq;
++
++      dev_dbg(&pcie->pdev->dev, "msi#%d address_hi %#x address_lo %#x\n",
++              (int)data->hwirq, msg->address_hi, msg->address_lo);
++}
++
++static int mobiveil_msi_set_affinity(struct irq_data *irq_data,
++                                   const struct cpumask *mask, bool force)
++{
++      return -EINVAL;
++}
++
++static struct irq_chip mobiveil_msi_bottom_irq_chip = {
++      .name                   = "Mobiveil MSI",
++      .irq_compose_msi_msg    = mobiveil_compose_msi_msg,
++      .irq_set_affinity       = mobiveil_msi_set_affinity,
++};
++
++static int mobiveil_irq_msi_domain_alloc(struct irq_domain *domain,
++                                       unsigned int virq,
++                                       unsigned int nr_irqs, void *args)
++{
++      struct mobiveil_pcie *pcie = domain->host_data;
++      struct mobiveil_msi *msi = &pcie->rp.msi;
++      unsigned long bit;
++
++      WARN_ON(nr_irqs != 1);
++      mutex_lock(&msi->lock);
++
++      bit = find_first_zero_bit(msi->msi_irq_in_use, msi->num_of_vectors);
++      if (bit >= msi->num_of_vectors) {
++              mutex_unlock(&msi->lock);
++              return -ENOSPC;
++      }
++
++      set_bit(bit, msi->msi_irq_in_use);
++
++      mutex_unlock(&msi->lock);
++
++      irq_domain_set_info(domain, virq, bit, &mobiveil_msi_bottom_irq_chip,
++                          domain->host_data, handle_level_irq, NULL, NULL);
++      return 0;
++}
++
++static void mobiveil_irq_msi_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 mobiveil_pcie *pcie = irq_data_get_irq_chip_data(d);
++      struct mobiveil_msi *msi = &pcie->rp.msi;
++
++      mutex_lock(&msi->lock);
++
++      if (!test_bit(d->hwirq, msi->msi_irq_in_use))
++              dev_err(&pcie->pdev->dev, "trying to free unused MSI#%lu\n",
++                      d->hwirq);
++      else
++              __clear_bit(d->hwirq, msi->msi_irq_in_use);
++
++      mutex_unlock(&msi->lock);
++}
++static const struct irq_domain_ops msi_domain_ops = {
++      .alloc  = mobiveil_irq_msi_domain_alloc,
++      .free   = mobiveil_irq_msi_domain_free,
++};
++
++static int mobiveil_allocate_msi_domains(struct mobiveil_pcie *pcie)
++{
++      struct device *dev = &pcie->pdev->dev;
++      struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
++      struct mobiveil_msi *msi = &pcie->rp.msi;
++
++      mutex_init(&msi->lock);
++      msi->dev_domain = irq_domain_add_linear(NULL, msi->num_of_vectors,
++                                              &msi_domain_ops, pcie);
++      if (!msi->dev_domain) {
++              dev_err(dev, "failed to create IRQ domain\n");
++              return -ENOMEM;
++      }
++
++      msi->msi_domain = pci_msi_create_irq_domain(fwnode,
++                                                  &mobiveil_msi_domain_info,
++                                                  msi->dev_domain);
++      if (!msi->msi_domain) {
++              dev_err(dev, "failed to create MSI domain\n");
++              irq_domain_remove(msi->dev_domain);
++              return -ENOMEM;
++      }
++
++      return 0;
++}
++
++static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie)
++{
++      struct device *dev = &pcie->pdev->dev;
++      struct device_node *node = dev->of_node;
++      int ret;
++
++      /* setup INTx */
++      pcie->rp.intx_domain = irq_domain_add_linear(node, PCI_NUM_INTX,
++                                                   &intx_domain_ops, pcie);
++
++      if (!pcie->rp.intx_domain) {
++              dev_err(dev, "Failed to get a INTx IRQ domain\n");
++              return -ENOMEM;
++      }
++
++      raw_spin_lock_init(&pcie->rp.intx_mask_lock);
++
++      /* setup MSI */
++      ret = mobiveil_allocate_msi_domains(pcie);
++      if (ret)
++              return ret;
++
++      return 0;
++}
++
++static int mobiveil_pcie_interrupt_init(struct mobiveil_pcie *pcie)
++{
++      struct device *dev = &pcie->pdev->dev;
++      struct resource *res;
++      int ret;
++
++      if (pcie->rp.ops->interrupt_init)
++              return pcie->rp.ops->interrupt_init(pcie);
++
++      /* map MSI config resource */
++      res = platform_get_resource_byname(pcie->pdev, IORESOURCE_MEM,
++                                         "apb_csr");
++      pcie->apb_csr_base = devm_pci_remap_cfg_resource(dev, res);
++      if (IS_ERR(pcie->apb_csr_base))
++              return PTR_ERR(pcie->apb_csr_base);
++
++      /* setup MSI hardware registers */
++      mobiveil_pcie_enable_msi(pcie);
++
++      pcie->rp.irq = platform_get_irq(pcie->pdev, 0);
++      if (pcie->rp.irq <= 0) {
++              dev_err(dev, "failed to map IRQ: %d\n", pcie->rp.irq);
++              return -ENODEV;
++      }
++
++      /* initialize the IRQ domains */
++      ret = mobiveil_pcie_init_irq_domain(pcie);
++      if (ret) {
++              dev_err(dev, "Failed creating IRQ Domain\n");
++              return ret;
++      }
++
++      irq_set_chained_handler_and_data(pcie->rp.irq,
++                                       mobiveil_pcie_isr, pcie);
++
++      /* Enable interrupts */
++      csr_writel(pcie, (PAB_INTP_INTX_MASK | PAB_INTP_MSI_MASK),
++                 PAB_INTP_AMBA_MISC_ENB);
++
++      return 0;
++}
++
++int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie)
++{
++      struct pci_bus *bus;
++      struct pci_bus *child;
++      struct pci_host_bridge *bridge = pcie->bridge;
++      struct device *dev = &pcie->pdev->dev;
++      resource_size_t iobase;
++      int ret;
++
++      INIT_LIST_HEAD(&pcie->resources);
++
++      ret = mobiveil_pcie_parse_dt(pcie);
++      if (ret) {
++              dev_err(dev, "Parsing DT failed, ret: %x\n", ret);
++              return ret;
++      }
++
++      /* 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);
++      if (ret) {
++              dev_err(dev, "Getting bridge resources failed\n");
++              return ret;
++      }
++
++      /*
++       * configure all inbound and outbound windows and prepare the RC for
++       * config access
++       */
++      ret = mobiveil_host_init(pcie);
++      if (ret) {
++              dev_err(dev, "Failed to initialize host\n");
++              goto error;
++      }
++
++      ret = mobiveil_pcie_interrupt_init(pcie);
++      if (ret) {
++              dev_err(dev, "Interrupt init failed\n");
++              goto error;
++      }
++
++      ret = devm_request_pci_bus_resources(dev, &pcie->resources);
++      if (ret)
++              goto error;
++
++      /* Initialize bridge */
++      list_splice_init(&pcie->resources, &bridge->windows);
++      bridge->dev.parent = dev;
++      bridge->sysdata = pcie;
++      bridge->busnr = pcie->rp.root_bus_nr;
++      bridge->ops = &mobiveil_pcie_ops;
++      bridge->map_irq = of_irq_parse_and_map_pci;
++      bridge->swizzle_irq = pci_common_swizzle;
++
++      ret = mobiveil_bringup_link(pcie);
++      if (ret) {
++              dev_info(dev, "link bring-up failed\n");
++              goto error;
++      }
++
++      /* setup the kernel resources for the newly added PCIe root bus */
++      ret = pci_scan_root_bus_bridge(bridge);
++      if (ret)
++              goto error;
++
++      bus = bridge->bus;
++
++      pci_assign_unassigned_bus_resources(bus);
++      list_for_each_entry(child, &bus->children, node)
++              pcie_bus_configure_settings(child);
++      pci_bus_add_devices(bus);
++
++      return 0;
++error:
++      pci_free_resource_list(&pcie->resources);
++      return ret;
++}
+--- /dev/null
++++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c
+@@ -0,0 +1,59 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * PCIe host controller driver for Mobiveil PCIe Host controller
++ *
++ * Copyright (c) 2018 Mobiveil Inc.
++ * Copyright 2019 NXP
++ *
++ * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
++ * Refactor: Zhiqiang Hou <Zhiqiang.Hou@nxp.com>
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of_pci.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include "pcie-mobiveil.h"
++
++static int mobiveil_pcie_probe(struct platform_device *pdev)
++{
++      struct mobiveil_pcie *pcie;
++      struct pci_host_bridge *bridge;
++      struct device *dev = &pdev->dev;
++
++      bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
++      if (!bridge)
++              return -ENOMEM;
++
++      pcie = pci_host_bridge_priv(bridge);
++
++      pcie->pdev = pdev;
++
++      return mobiveil_pcie_host_probe(pcie);
++}
++
++static const struct of_device_id mobiveil_pcie_of_match[] = {
++      {.compatible = "mbvl,gpex40-pcie",},
++      {},
++};
++
++MODULE_DEVICE_TABLE(of, mobiveil_pcie_of_match);
++
++static struct platform_driver mobiveil_pcie_driver = {
++      .probe = mobiveil_pcie_probe,
++      .driver = {
++              .name = "mobiveil-pcie",
++              .of_match_table = mobiveil_pcie_of_match,
++              .suppress_bind_attrs = true,
++      },
++};
++
++builtin_platform_driver(mobiveil_pcie_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("Mobiveil PCIe host controller driver");
++MODULE_AUTHOR("Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>");
+--- /dev/null
++++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.c
+@@ -0,0 +1,227 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * PCIe host controller driver for Mobiveil PCIe Host controller
++ *
++ * Copyright (c) 2018 Mobiveil Inc.
++ * Copyright 2019 NXP
++ *
++ * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
++ * Refactor: Zhiqiang Hou <Zhiqiang.Hou@nxp.com>
++ */
++
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++
++#include "pcie-mobiveil.h"
++
++/*
++ * mobiveil_pcie_sel_page - routine to access paged register
++ *
++ * Registers whose address greater than PAGED_ADDR_BNDRY (0xc00) are paged,
++ * for this scheme to work extracted higher 6 bits of the offset will be
++ * written to pg_sel field of PAB_CTRL register and rest of the lower 10
++ * bits enabled with PAGED_ADDR_BNDRY are used as offset of the register.
++ */
++static void mobiveil_pcie_sel_page(struct mobiveil_pcie *pcie, u8 pg_idx)
++{
++      u32 val;
++
++      val = readl(pcie->csr_axi_slave_base + PAB_CTRL);
++      val &= ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT);
++      val |= (pg_idx & PAGE_SEL_MASK) << PAGE_SEL_SHIFT;
++
++      writel(val, pcie->csr_axi_slave_base + PAB_CTRL);
++}
++
++static void *mobiveil_pcie_comp_addr(struct mobiveil_pcie *pcie, u32 off)
++{
++      if (off < PAGED_ADDR_BNDRY) {
++              /* For directly accessed registers, clear the pg_sel field */
++              mobiveil_pcie_sel_page(pcie, 0);
++              return pcie->csr_axi_slave_base + off;
++      }
++
++      mobiveil_pcie_sel_page(pcie, OFFSET_TO_PAGE_IDX(off));
++      return pcie->csr_axi_slave_base + OFFSET_TO_PAGE_ADDR(off);
++}
++
++static int mobiveil_pcie_read(void __iomem *addr, int size, u32 *val)
++{
++      if ((uintptr_t)addr & (size - 1)) {
++              *val = 0;
++              return PCIBIOS_BAD_REGISTER_NUMBER;
++      }
++
++      switch (size) {
++      case 4:
++              *val = readl(addr);
++              break;
++      case 2:
++              *val = readw(addr);
++              break;
++      case 1:
++              *val = readb(addr);
++              break;
++      default:
++              *val = 0;
++              return PCIBIOS_BAD_REGISTER_NUMBER;
++      }
++
++      return PCIBIOS_SUCCESSFUL;
++}
++
++static int mobiveil_pcie_write(void __iomem *addr, int size, u32 val)
++{
++      if ((uintptr_t)addr & (size - 1))
++              return PCIBIOS_BAD_REGISTER_NUMBER;
++
++      switch (size) {
++      case 4:
++              writel(val, addr);
++              break;
++      case 2:
++              writew(val, addr);
++              break;
++      case 1:
++              writeb(val, addr);
++              break;
++      default:
++              return PCIBIOS_BAD_REGISTER_NUMBER;
++      }
++
++      return PCIBIOS_SUCCESSFUL;
++}
++
++u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
++{
++      void *addr;
++      u32 val;
++      int ret;
++
++      addr = mobiveil_pcie_comp_addr(pcie, off);
++
++      ret = mobiveil_pcie_read(addr, size, &val);
++      if (ret)
++              dev_err(&pcie->pdev->dev, "read CSR address failed\n");
++
++      return val;
++}
++
++void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_t size)
++{
++      void *addr;
++      int ret;
++
++      addr = mobiveil_pcie_comp_addr(pcie, off);
++
++      ret = mobiveil_pcie_write(addr, size, val);
++      if (ret)
++              dev_err(&pcie->pdev->dev, "write CSR address failed\n");
++}
++
++bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie)
++{
++      if (pcie->ops->link_up)
++              return pcie->ops->link_up(pcie);
++
++      return (csr_readl(pcie, LTSSM_STATUS) &
++              LTSSM_STATUS_L0_MASK) == LTSSM_STATUS_L0;
++}
++
++void program_ib_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
++                      u64 pci_addr, u32 type, u64 size)
++{
++      u32 value;
++      u64 size64 = ~(size - 1);
++
++      if (win_num >= pcie->ppio_wins) {
++              dev_err(&pcie->pdev->dev,
++                      "ERROR: max inbound windows reached !\n");
++              return;
++      }
++
++      value = csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
++      value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK);
++      value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT |
++               (lower_32_bits(size64) & WIN_SIZE_MASK);
++      csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));
++
++      csr_writel(pcie, upper_32_bits(size64),
++                 PAB_EXT_PEX_AMAP_SIZEN(win_num));
++
++      csr_writel(pcie, lower_32_bits(cpu_addr),
++                 PAB_PEX_AMAP_AXI_WIN(win_num));
++      csr_writel(pcie, upper_32_bits(cpu_addr),
++                 PAB_EXT_PEX_AMAP_AXI_WIN(win_num));
++
++      csr_writel(pcie, lower_32_bits(pci_addr),
++                 PAB_PEX_AMAP_PEX_WIN_L(win_num));
++      csr_writel(pcie, upper_32_bits(pci_addr),
++                 PAB_PEX_AMAP_PEX_WIN_H(win_num));
++
++      pcie->ib_wins_configured++;
++}
++
++/*
++ * routine to program the outbound windows
++ */
++void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
++                      u64 pci_addr, u32 type, u64 size)
++{
++      u32 value;
++      u64 size64 = ~(size - 1);
++
++      if (win_num >= pcie->apio_wins) {
++              dev_err(&pcie->pdev->dev,
++                      "ERROR: max outbound windows reached !\n");
++              return;
++      }
++
++      /*
++       * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
++       * to 4 KB in PAB_AXI_AMAP_CTRL register
++       */
++      value = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
++      value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK);
++      value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT |
++               (lower_32_bits(size64) & WIN_SIZE_MASK);
++      csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num));
++
++      csr_writel(pcie, upper_32_bits(size64), PAB_EXT_AXI_AMAP_SIZE(win_num));
++
++      /*
++       * program AXI window base with appropriate value in
++       * PAB_AXI_AMAP_AXI_WIN0 register
++       */
++      csr_writel(pcie, lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
++                 PAB_AXI_AMAP_AXI_WIN(win_num));
++      csr_writel(pcie, upper_32_bits(cpu_addr),
++                 PAB_EXT_AXI_AMAP_AXI_WIN(win_num));
++
++      csr_writel(pcie, lower_32_bits(pci_addr),
++                 PAB_AXI_AMAP_PEX_WIN_L(win_num));
++      csr_writel(pcie, upper_32_bits(pci_addr),
++                 PAB_AXI_AMAP_PEX_WIN_H(win_num));
++
++      pcie->ob_wins_configured++;
++}
++
++int mobiveil_bringup_link(struct mobiveil_pcie *pcie)
++{
++      int retries;
++
++      /* check if the link is up or not */
++      for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
++              if (mobiveil_pcie_link_up(pcie))
++                      return 0;
++
++              usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
++      }
++
++      dev_err(&pcie->pdev->dev, "link never came up\n");
++
++      return -ETIMEDOUT;
++}
+--- /dev/null
++++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
+@@ -0,0 +1,189 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * PCIe host controller driver for Mobiveil PCIe Host controller
++ *
++ * Copyright (c) 2018 Mobiveil Inc.
++ * Copyright 2019 NXP
++ *
++ * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
++ * Refactor: Zhiqiang Hou <Zhiqiang.Hou@nxp.com>
++ */
++
++#ifndef _PCIE_MOBIVEIL_H
++#define _PCIE_MOBIVEIL_H
++
++#include <linux/pci.h>
++#include <linux/irq.h>
++#include <linux/msi.h>
++#include "../../pci.h"
++
++/* register offsets and bit positions */
++
++/*
++ * translation tables are grouped into windows, each window registers are
++ * grouped into blocks of 4 or 16 registers each
++ */
++#define PAB_REG_BLOCK_SIZE            16
++#define PAB_EXT_REG_BLOCK_SIZE                4
++
++#define PAB_REG_ADDR(offset, win)     \
++      (offset + (win * PAB_REG_BLOCK_SIZE))
++#define PAB_EXT_REG_ADDR(offset, win) \
++      (offset + (win * PAB_EXT_REG_BLOCK_SIZE))
++
++#define LTSSM_STATUS                  0x0404
++#define  LTSSM_STATUS_L0_MASK         0x3f
++#define  LTSSM_STATUS_L0              0x2d
++
++#define PAB_CTRL                      0x0808
++#define  AMBA_PIO_ENABLE_SHIFT                0
++#define  PEX_PIO_ENABLE_SHIFT         1
++#define  PAGE_SEL_SHIFT                       13
++#define  PAGE_SEL_MASK                        0x3f
++#define  PAGE_LO_MASK                 0x3ff
++#define  PAGE_SEL_OFFSET_SHIFT                10
++
++#define PAB_AXI_PIO_CTRL              0x0840
++#define  APIO_EN_MASK                 0xf
++
++#define PAB_PEX_PIO_CTRL              0x08c0
++#define  PIO_ENABLE_SHIFT             0
++
++#define PAB_INTP_AMBA_MISC_ENB                0x0b0c
++#define PAB_INTP_AMBA_MISC_STAT               0x0b1c
++#define  PAB_INTP_INTX_MASK           0x01e0
++#define  PAB_INTP_MSI_MASK            0x8
++
++#define PAB_AXI_AMAP_CTRL(win)                PAB_REG_ADDR(0x0ba0, win)
++#define  WIN_ENABLE_SHIFT             0
++#define  WIN_TYPE_SHIFT                       1
++#define  WIN_TYPE_MASK                        0x3
++#define  WIN_SIZE_MASK                        0xfffffc00
++
++#define PAB_EXT_AXI_AMAP_SIZE(win)    PAB_EXT_REG_ADDR(0xbaf0, win)
++
++#define PAB_EXT_AXI_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0x80a0, win)
++#define PAB_AXI_AMAP_AXI_WIN(win)     PAB_REG_ADDR(0x0ba4, win)
++#define  AXI_WINDOW_ALIGN_MASK                3
++
++#define PAB_AXI_AMAP_PEX_WIN_L(win)   PAB_REG_ADDR(0x0ba8, win)
++#define  PAB_BUS_SHIFT                        24
++#define  PAB_DEVICE_SHIFT             19
++#define  PAB_FUNCTION_SHIFT           16
++
++#define PAB_AXI_AMAP_PEX_WIN_H(win)   PAB_REG_ADDR(0x0bac, win)
++#define PAB_INTP_AXI_PIO_CLASS                0x474
++
++#define PAB_PEX_AMAP_CTRL(win)                PAB_REG_ADDR(0x4ba0, win)
++#define  AMAP_CTRL_EN_SHIFT           0
++#define  AMAP_CTRL_TYPE_SHIFT         1
++#define  AMAP_CTRL_TYPE_MASK          3
++
++#define PAB_EXT_PEX_AMAP_SIZEN(win)   PAB_EXT_REG_ADDR(0xbef0, win)
++#define PAB_EXT_PEX_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0xb4a0, win)
++#define PAB_PEX_AMAP_AXI_WIN(win)     PAB_REG_ADDR(0x4ba4, win)
++#define PAB_PEX_AMAP_PEX_WIN_L(win)   PAB_REG_ADDR(0x4ba8, win)
++#define PAB_PEX_AMAP_PEX_WIN_H(win)   PAB_REG_ADDR(0x4bac, win)
++
++/* starting offset of INTX bits in status register */
++#define PAB_INTX_START                        5
++
++/* supported number of MSI interrupts */
++#define PCI_NUM_MSI                   16
++
++/* MSI registers */
++#define MSI_BASE_LO_OFFSET            0x04
++#define MSI_BASE_HI_OFFSET            0x08
++#define MSI_SIZE_OFFSET                       0x0c
++#define MSI_ENABLE_OFFSET             0x14
++#define MSI_STATUS_OFFSET             0x18
++#define MSI_DATA_OFFSET                       0x20
++#define MSI_ADDR_L_OFFSET             0x24
++#define MSI_ADDR_H_OFFSET             0x28
++
++/* outbound and inbound window definitions */
++#define WIN_NUM_0                     0
++#define WIN_NUM_1                     1
++#define CFG_WINDOW_TYPE                       0
++#define IO_WINDOW_TYPE                        1
++#define MEM_WINDOW_TYPE                       2
++#define IB_WIN_SIZE                   ((u64)256 * 1024 * 1024 * 1024)
++#define MAX_PIO_WINDOWS                       8
++
++/* Parameters for the waiting for link up routine */
++#define LINK_WAIT_MAX_RETRIES         10
++#define LINK_WAIT_MIN                 90000
++#define LINK_WAIT_MAX                 100000
++
++#define PAGED_ADDR_BNDRY              0xc00
++#define OFFSET_TO_PAGE_ADDR(off)      \
++      ((off & PAGE_LO_MASK) | PAGED_ADDR_BNDRY)
++#define OFFSET_TO_PAGE_IDX(off)               \
++      ((off >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK)
++
++struct mobiveil_pcie;
++
++struct mobiveil_msi {                 /* MSI information */
++      struct mutex lock;              /* protect bitmap variable */
++      struct irq_domain *msi_domain;
++      struct irq_domain *dev_domain;
++      phys_addr_t msi_pages_phys;
++      int num_of_vectors;
++      DECLARE_BITMAP(msi_irq_in_use, PCI_NUM_MSI);
++};
++
++struct mobiveil_rp_ops {
++      int (*interrupt_init)(struct mobiveil_pcie *pcie);
++};
++
++struct root_port {
++      u8 root_bus_nr;
++      void __iomem *config_axi_slave_base;    /* endpoint config base */
++      struct resource *ob_io_res;
++      struct mobiveil_rp_ops *ops;
++      int irq;
++      raw_spinlock_t intx_mask_lock;
++      struct irq_domain *intx_domain;
++      struct mobiveil_msi msi;
++};
++
++struct mobiveil_pab_ops {
++      int (*link_up)(struct mobiveil_pcie *pcie);
++};
++
++struct mobiveil_pcie {
++      struct platform_device *pdev;
++      struct list_head resources;
++      void __iomem *csr_axi_slave_base;       /* PAB registers base */
++      phys_addr_t pcie_reg_base;      /* Physical PCIe Controller Base */
++      void __iomem *apb_csr_base;     /* MSI register base */
++      u32 apio_wins;
++      u32 ppio_wins;
++      u32 ob_wins_configured;         /* configured outbound windows */
++      u32 ib_wins_configured;         /* configured inbound windows */
++      const struct mobiveil_pab_ops *ops;
++      struct root_port rp;
++      struct pci_host_bridge *bridge;
++};
++
++int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie);
++bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie);
++int mobiveil_bringup_link(struct mobiveil_pcie *pcie);
++void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
++                      u64 pci_addr, u32 type, u64 size);
++void program_ib_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
++                      u64 pci_addr, u32 type, u64 size);
++u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size);
++void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_t size);
++
++static inline u32 csr_readl(struct mobiveil_pcie *pcie, u32 off)
++{
++      return csr_read(pcie, off, 0x4);
++}
++
++static inline void csr_writel(struct mobiveil_pcie *pcie, u32 val, u32 off)
++{
++      csr_write(pcie, val, off, 0x4);
++}
++
++#endif /* _PCIE_MOBIVEIL_H */
+--- a/drivers/pci/controller/pcie-mobiveil.c
++++ /dev/null
+@@ -1,964 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-/*
+- * PCIe host controller driver for Mobiveil PCIe Host controller
+- *
+- * Copyright (c) 2018 Mobiveil Inc.
+- * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
+- */
+-
+-#include <linux/delay.h>
+-#include <linux/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/irq.h>
+-#include <linux/irqchip/chained_irq.h>
+-#include <linux/irqdomain.h>
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/msi.h>
+-#include <linux/of_address.h>
+-#include <linux/of_irq.h>
+-#include <linux/of_platform.h>
+-#include <linux/of_pci.h>
+-#include <linux/pci.h>
+-#include <linux/platform_device.h>
+-#include <linux/slab.h>
+-
+-#include "../pci.h"
+-
+-/* register offsets and bit positions */
+-
+-/*
+- * translation tables are grouped into windows, each window registers are
+- * grouped into blocks of 4 or 16 registers each
+- */
+-#define PAB_REG_BLOCK_SIZE            16
+-#define PAB_EXT_REG_BLOCK_SIZE                4
+-
+-#define PAB_REG_ADDR(offset, win)     \
+-      (offset + (win * PAB_REG_BLOCK_SIZE))
+-#define PAB_EXT_REG_ADDR(offset, win) \
+-      (offset + (win * PAB_EXT_REG_BLOCK_SIZE))
+-
+-#define LTSSM_STATUS                  0x0404
+-#define  LTSSM_STATUS_L0_MASK         0x3f
+-#define  LTSSM_STATUS_L0              0x2d
+-
+-#define PAB_CTRL                      0x0808
+-#define  AMBA_PIO_ENABLE_SHIFT                0
+-#define  PEX_PIO_ENABLE_SHIFT         1
+-#define  PAGE_SEL_SHIFT                       13
+-#define  PAGE_SEL_MASK                        0x3f
+-#define  PAGE_LO_MASK                 0x3ff
+-#define  PAGE_SEL_OFFSET_SHIFT                10
+-
+-#define PAB_AXI_PIO_CTRL              0x0840
+-#define  APIO_EN_MASK                 0xf
+-
+-#define PAB_PEX_PIO_CTRL              0x08c0
+-#define  PIO_ENABLE_SHIFT             0
+-
+-#define PAB_INTP_AMBA_MISC_ENB                0x0b0c
+-#define PAB_INTP_AMBA_MISC_STAT               0x0b1c
+-#define  PAB_INTP_INTX_MASK           0x01e0
+-#define  PAB_INTP_MSI_MASK            0x8
+-
+-#define PAB_AXI_AMAP_CTRL(win)                PAB_REG_ADDR(0x0ba0, win)
+-#define  WIN_ENABLE_SHIFT             0
+-#define  WIN_TYPE_SHIFT                       1
+-#define  WIN_TYPE_MASK                        0x3
+-#define  WIN_SIZE_MASK                        0xfffffc00
+-
+-#define PAB_EXT_AXI_AMAP_SIZE(win)    PAB_EXT_REG_ADDR(0xbaf0, win)
+-
+-#define PAB_EXT_AXI_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0x80a0, win)
+-#define PAB_AXI_AMAP_AXI_WIN(win)     PAB_REG_ADDR(0x0ba4, win)
+-#define  AXI_WINDOW_ALIGN_MASK                3
+-
+-#define PAB_AXI_AMAP_PEX_WIN_L(win)   PAB_REG_ADDR(0x0ba8, win)
+-#define  PAB_BUS_SHIFT                        24
+-#define  PAB_DEVICE_SHIFT             19
+-#define  PAB_FUNCTION_SHIFT           16
+-
+-#define PAB_AXI_AMAP_PEX_WIN_H(win)   PAB_REG_ADDR(0x0bac, win)
+-#define PAB_INTP_AXI_PIO_CLASS                0x474
+-
+-#define PAB_PEX_AMAP_CTRL(win)                PAB_REG_ADDR(0x4ba0, win)
+-#define  AMAP_CTRL_EN_SHIFT           0
+-#define  AMAP_CTRL_TYPE_SHIFT         1
+-#define  AMAP_CTRL_TYPE_MASK          3
+-
+-#define PAB_EXT_PEX_AMAP_SIZEN(win)   PAB_EXT_REG_ADDR(0xbef0, win)
+-#define PAB_EXT_PEX_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0xb4a0, win)
+-#define PAB_PEX_AMAP_AXI_WIN(win)     PAB_REG_ADDR(0x4ba4, win)
+-#define PAB_PEX_AMAP_PEX_WIN_L(win)   PAB_REG_ADDR(0x4ba8, win)
+-#define PAB_PEX_AMAP_PEX_WIN_H(win)   PAB_REG_ADDR(0x4bac, win)
+-
+-/* starting offset of INTX bits in status register */
+-#define PAB_INTX_START                        5
+-
+-/* supported number of MSI interrupts */
+-#define PCI_NUM_MSI                   16
+-
+-/* MSI registers */
+-#define MSI_BASE_LO_OFFSET            0x04
+-#define MSI_BASE_HI_OFFSET            0x08
+-#define MSI_SIZE_OFFSET                       0x0c
+-#define MSI_ENABLE_OFFSET             0x14
+-#define MSI_STATUS_OFFSET             0x18
+-#define MSI_DATA_OFFSET                       0x20
+-#define MSI_ADDR_L_OFFSET             0x24
+-#define MSI_ADDR_H_OFFSET             0x28
+-
+-/* outbound and inbound window definitions */
+-#define WIN_NUM_0                     0
+-#define WIN_NUM_1                     1
+-#define CFG_WINDOW_TYPE                       0
+-#define IO_WINDOW_TYPE                        1
+-#define MEM_WINDOW_TYPE                       2
+-#define IB_WIN_SIZE                   ((u64)256 * 1024 * 1024 * 1024)
+-#define MAX_PIO_WINDOWS                       8
+-
+-/* Parameters for the waiting for link up routine */
+-#define LINK_WAIT_MAX_RETRIES         10
+-#define LINK_WAIT_MIN                 90000
+-#define LINK_WAIT_MAX                 100000
+-
+-#define PAGED_ADDR_BNDRY              0xc00
+-#define OFFSET_TO_PAGE_ADDR(off)      \
+-      ((off & PAGE_LO_MASK) | PAGED_ADDR_BNDRY)
+-#define OFFSET_TO_PAGE_IDX(off)               \
+-      ((off >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK)
+-
+-struct mobiveil_msi {                 /* MSI information */
+-      struct mutex lock;              /* protect bitmap variable */
+-      struct irq_domain *msi_domain;
+-      struct irq_domain *dev_domain;
+-      phys_addr_t msi_pages_phys;
+-      int num_of_vectors;
+-      DECLARE_BITMAP(msi_irq_in_use, PCI_NUM_MSI);
+-};
+-
+-struct mobiveil_pcie {
+-      struct platform_device *pdev;
+-      struct list_head resources;
+-      void __iomem *config_axi_slave_base;    /* endpoint config base */
+-      void __iomem *csr_axi_slave_base;       /* root port config base */
+-      void __iomem *apb_csr_base;     /* MSI register base */
+-      phys_addr_t pcie_reg_base;      /* Physical PCIe Controller Base */
+-      struct irq_domain *intx_domain;
+-      raw_spinlock_t intx_mask_lock;
+-      int irq;
+-      int apio_wins;
+-      int ppio_wins;
+-      int ob_wins_configured;         /* configured outbound windows */
+-      int ib_wins_configured;         /* configured inbound windows */
+-      struct resource *ob_io_res;
+-      char root_bus_nr;
+-      struct mobiveil_msi msi;
+-};
+-
+-/*
+- * mobiveil_pcie_sel_page - routine to access paged register
+- *
+- * Registers whose address greater than PAGED_ADDR_BNDRY (0xc00) are paged,
+- * for this scheme to work extracted higher 6 bits of the offset will be
+- * written to pg_sel field of PAB_CTRL register and rest of the lower 10
+- * bits enabled with PAGED_ADDR_BNDRY are used as offset of the register.
+- */
+-static void mobiveil_pcie_sel_page(struct mobiveil_pcie *pcie, u8 pg_idx)
+-{
+-      u32 val;
+-
+-      val = readl(pcie->csr_axi_slave_base + PAB_CTRL);
+-      val &= ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT);
+-      val |= (pg_idx & PAGE_SEL_MASK) << PAGE_SEL_SHIFT;
+-
+-      writel(val, pcie->csr_axi_slave_base + PAB_CTRL);
+-}
+-
+-static void *mobiveil_pcie_comp_addr(struct mobiveil_pcie *pcie, u32 off)
+-{
+-      if (off < PAGED_ADDR_BNDRY) {
+-              /* For directly accessed registers, clear the pg_sel field */
+-              mobiveil_pcie_sel_page(pcie, 0);
+-              return pcie->csr_axi_slave_base + off;
+-      }
+-
+-      mobiveil_pcie_sel_page(pcie, OFFSET_TO_PAGE_IDX(off));
+-      return pcie->csr_axi_slave_base + OFFSET_TO_PAGE_ADDR(off);
+-}
+-
+-static int mobiveil_pcie_read(void __iomem *addr, int size, u32 *val)
+-{
+-      if ((uintptr_t)addr & (size - 1)) {
+-              *val = 0;
+-              return PCIBIOS_BAD_REGISTER_NUMBER;
+-      }
+-
+-      switch (size) {
+-      case 4:
+-              *val = readl(addr);
+-              break;
+-      case 2:
+-              *val = readw(addr);
+-              break;
+-      case 1:
+-              *val = readb(addr);
+-              break;
+-      default:
+-              *val = 0;
+-              return PCIBIOS_BAD_REGISTER_NUMBER;
+-      }
+-
+-      return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static int mobiveil_pcie_write(void __iomem *addr, int size, u32 val)
+-{
+-      if ((uintptr_t)addr & (size - 1))
+-              return PCIBIOS_BAD_REGISTER_NUMBER;
+-
+-      switch (size) {
+-      case 4:
+-              writel(val, addr);
+-              break;
+-      case 2:
+-              writew(val, addr);
+-              break;
+-      case 1:
+-              writeb(val, addr);
+-              break;
+-      default:
+-              return PCIBIOS_BAD_REGISTER_NUMBER;
+-      }
+-
+-      return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
+-{
+-      void *addr;
+-      u32 val;
+-      int ret;
+-
+-      addr = mobiveil_pcie_comp_addr(pcie, off);
+-
+-      ret = mobiveil_pcie_read(addr, size, &val);
+-      if (ret)
+-              dev_err(&pcie->pdev->dev, "read CSR address failed\n");
+-
+-      return val;
+-}
+-
+-static void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_t size)
+-{
+-      void *addr;
+-      int ret;
+-
+-      addr = mobiveil_pcie_comp_addr(pcie, off);
+-
+-      ret = mobiveil_pcie_write(addr, size, val);
+-      if (ret)
+-              dev_err(&pcie->pdev->dev, "write CSR address failed\n");
+-}
+-
+-static u32 csr_readl(struct mobiveil_pcie *pcie, u32 off)
+-{
+-      return csr_read(pcie, off, 0x4);
+-}
+-
+-static void csr_writel(struct mobiveil_pcie *pcie, u32 val, u32 off)
+-{
+-      csr_write(pcie, val, off, 0x4);
+-}
+-
+-static bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie)
+-{
+-      return (csr_readl(pcie, LTSSM_STATUS) &
+-              LTSSM_STATUS_L0_MASK) == LTSSM_STATUS_L0;
+-}
+-
+-static bool mobiveil_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
+-{
+-      struct mobiveil_pcie *pcie = bus->sysdata;
+-
+-      /* Only one device down on each root port */
+-      if ((bus->number == pcie->root_bus_nr) && (devfn > 0))
+-              return false;
+-
+-      /*
+-       * Do not read more than one device on the bus directly
+-       * attached to RC
+-       */
+-      if ((bus->primary == pcie->root_bus_nr) && (PCI_SLOT(devfn) > 0))
+-              return false;
+-
+-      return true;
+-}
+-
+-/*
+- * mobiveil_pcie_map_bus - routine to get the configuration base of either
+- * root port or endpoint
+- */
+-static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus,
+-                                         unsigned int devfn, int where)
+-{
+-      struct mobiveil_pcie *pcie = bus->sysdata;
+-      u32 value;
+-
+-      if (!mobiveil_pcie_valid_device(bus, devfn))
+-              return NULL;
+-
+-      /* RC config access */
+-      if (bus->number == pcie->root_bus_nr)
+-              return pcie->csr_axi_slave_base + where;
+-
+-      /*
+-       * EP config access (in Config/APIO space)
+-       * Program PEX Address base (31..16 bits) with appropriate value
+-       * (BDF) in PAB_AXI_AMAP_PEX_WIN_L0 Register.
+-       * Relies on pci_lock serialization
+-       */
+-      value = bus->number << PAB_BUS_SHIFT |
+-              PCI_SLOT(devfn) << PAB_DEVICE_SHIFT |
+-              PCI_FUNC(devfn) << PAB_FUNCTION_SHIFT;
+-
+-      csr_writel(pcie, value, PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));
+-
+-      return pcie->config_axi_slave_base + where;
+-}
+-
+-static struct pci_ops mobiveil_pcie_ops = {
+-      .map_bus = mobiveil_pcie_map_bus,
+-      .read = pci_generic_config_read,
+-      .write = pci_generic_config_write,
+-};
+-
+-static void mobiveil_pcie_isr(struct irq_desc *desc)
+-{
+-      struct irq_chip *chip = irq_desc_get_chip(desc);
+-      struct mobiveil_pcie *pcie = irq_desc_get_handler_data(desc);
+-      struct device *dev = &pcie->pdev->dev;
+-      struct mobiveil_msi *msi = &pcie->msi;
+-      u32 msi_data, msi_addr_lo, msi_addr_hi;
+-      u32 intr_status, msi_status;
+-      unsigned long shifted_status;
+-      u32 bit, virq, val, mask;
+-
+-      /*
+-       * The core provides a single interrupt for both INTx/MSI messages.
+-       * So we'll read both INTx and MSI status
+-       */
+-
+-      chained_irq_enter(chip, desc);
+-
+-      /* read INTx status */
+-      val = csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT);
+-      mask = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
+-      intr_status = val & mask;
+-
+-      /* Handle INTx */
+-      if (intr_status & PAB_INTP_INTX_MASK) {
+-              shifted_status = csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT);
+-              shifted_status &= PAB_INTP_INTX_MASK;
+-              shifted_status >>= PAB_INTX_START;
+-              do {
+-                      for_each_set_bit(bit, &shifted_status, PCI_NUM_INTX) {
+-                              virq = irq_find_mapping(pcie->intx_domain,
+-                                                      bit + 1);
+-                              if (virq)
+-                                      generic_handle_irq(virq);
+-                              else
+-                                      dev_err_ratelimited(dev, "unexpected IRQ, INT%d\n",
+-                                                          bit);
+-
+-                              /* clear interrupt handled */
+-                              csr_writel(pcie, 1 << (PAB_INTX_START + bit),
+-                                         PAB_INTP_AMBA_MISC_STAT);
+-                      }
+-
+-                      shifted_status = csr_readl(pcie,
+-                                                 PAB_INTP_AMBA_MISC_STAT);
+-                      shifted_status &= PAB_INTP_INTX_MASK;
+-                      shifted_status >>= PAB_INTX_START;
+-              } while (shifted_status != 0);
+-      }
+-
+-      /* read extra MSI status register */
+-      msi_status = readl_relaxed(pcie->apb_csr_base + MSI_STATUS_OFFSET);
+-
+-      /* handle MSI interrupts */
+-      while (msi_status & 1) {
+-              msi_data = readl_relaxed(pcie->apb_csr_base + MSI_DATA_OFFSET);
+-
+-              /*
+-               * MSI_STATUS_OFFSET register gets updated to zero
+-               * once we pop not only the MSI data but also address
+-               * from MSI hardware FIFO. So keeping these following
+-               * two dummy reads.
+-               */
+-              msi_addr_lo = readl_relaxed(pcie->apb_csr_base +
+-                                          MSI_ADDR_L_OFFSET);
+-              msi_addr_hi = readl_relaxed(pcie->apb_csr_base +
+-                                          MSI_ADDR_H_OFFSET);
+-              dev_dbg(dev, "MSI registers, data: %08x, addr: %08x:%08x\n",
+-                      msi_data, msi_addr_hi, msi_addr_lo);
+-
+-              virq = irq_find_mapping(msi->dev_domain, msi_data);
+-              if (virq)
+-                      generic_handle_irq(virq);
+-
+-              msi_status = readl_relaxed(pcie->apb_csr_base +
+-                                         MSI_STATUS_OFFSET);
+-      }
+-
+-      /* Clear the interrupt status */
+-      csr_writel(pcie, intr_status, PAB_INTP_AMBA_MISC_STAT);
+-      chained_irq_exit(chip, desc);
+-}
+-
+-static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
+-{
+-      struct device *dev = &pcie->pdev->dev;
+-      struct platform_device *pdev = pcie->pdev;
+-      struct device_node *node = dev->of_node;
+-      struct resource *res;
+-
+-      /* map config resource */
+-      res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+-                                         "config_axi_slave");
+-      pcie->config_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
+-      if (IS_ERR(pcie->config_axi_slave_base))
+-              return PTR_ERR(pcie->config_axi_slave_base);
+-      pcie->ob_io_res = res;
+-
+-      /* map csr resource */
+-      res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+-                                         "csr_axi_slave");
+-      pcie->csr_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
+-      if (IS_ERR(pcie->csr_axi_slave_base))
+-              return PTR_ERR(pcie->csr_axi_slave_base);
+-      pcie->pcie_reg_base = res->start;
+-
+-      /* map MSI config resource */
+-      res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apb_csr");
+-      pcie->apb_csr_base = devm_pci_remap_cfg_resource(dev, res);
+-      if (IS_ERR(pcie->apb_csr_base))
+-              return PTR_ERR(pcie->apb_csr_base);
+-
+-      /* read the number of windows requested */
+-      if (of_property_read_u32(node, "apio-wins", &pcie->apio_wins))
+-              pcie->apio_wins = MAX_PIO_WINDOWS;
+-
+-      if (of_property_read_u32(node, "ppio-wins", &pcie->ppio_wins))
+-              pcie->ppio_wins = MAX_PIO_WINDOWS;
+-
+-      pcie->irq = platform_get_irq(pdev, 0);
+-      if (pcie->irq <= 0) {
+-              dev_err(dev, "failed to map IRQ: %d\n", pcie->irq);
+-              return -ENODEV;
+-      }
+-
+-      return 0;
+-}
+-
+-static void program_ib_windows(struct mobiveil_pcie *pcie, int win_num,
+-                             u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
+-{
+-      u32 value;
+-      u64 size64 = ~(size - 1);
+-
+-      if (win_num >= pcie->ppio_wins) {
+-              dev_err(&pcie->pdev->dev,
+-                      "ERROR: max inbound windows reached !\n");
+-              return;
+-      }
+-
+-      value = csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
+-      value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK);
+-      value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT |
+-               (lower_32_bits(size64) & WIN_SIZE_MASK);
+-      csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));
+-
+-      csr_writel(pcie, upper_32_bits(size64),
+-                 PAB_EXT_PEX_AMAP_SIZEN(win_num));
+-
+-      csr_writel(pcie, lower_32_bits(cpu_addr),
+-                 PAB_PEX_AMAP_AXI_WIN(win_num));
+-      csr_writel(pcie, upper_32_bits(cpu_addr),
+-                 PAB_EXT_PEX_AMAP_AXI_WIN(win_num));
+-
+-      csr_writel(pcie, lower_32_bits(pci_addr),
+-                 PAB_PEX_AMAP_PEX_WIN_L(win_num));
+-      csr_writel(pcie, upper_32_bits(pci_addr),
+-                 PAB_PEX_AMAP_PEX_WIN_H(win_num));
+-
+-      pcie->ib_wins_configured++;
+-}
+-
+-/*
+- * routine to program the outbound windows
+- */
+-static void program_ob_windows(struct mobiveil_pcie *pcie, int win_num,
+-                             u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
+-{
+-      u32 value;
+-      u64 size64 = ~(size - 1);
+-
+-      if (win_num >= pcie->apio_wins) {
+-              dev_err(&pcie->pdev->dev,
+-                      "ERROR: max outbound windows reached !\n");
+-              return;
+-      }
+-
+-      /*
+-       * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
+-       * to 4 KB in PAB_AXI_AMAP_CTRL register
+-       */
+-      value = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
+-      value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK);
+-      value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT |
+-               (lower_32_bits(size64) & WIN_SIZE_MASK);
+-      csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num));
+-
+-      csr_writel(pcie, upper_32_bits(size64), PAB_EXT_AXI_AMAP_SIZE(win_num));
+-
+-      /*
+-       * program AXI window base with appropriate value in
+-       * PAB_AXI_AMAP_AXI_WIN0 register
+-       */
+-      csr_writel(pcie, lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
+-                 PAB_AXI_AMAP_AXI_WIN(win_num));
+-      csr_writel(pcie, upper_32_bits(cpu_addr),
+-                 PAB_EXT_AXI_AMAP_AXI_WIN(win_num));
+-
+-      csr_writel(pcie, lower_32_bits(pci_addr),
+-                 PAB_AXI_AMAP_PEX_WIN_L(win_num));
+-      csr_writel(pcie, upper_32_bits(pci_addr),
+-                 PAB_AXI_AMAP_PEX_WIN_H(win_num));
+-
+-      pcie->ob_wins_configured++;
+-}
+-
+-static int mobiveil_bringup_link(struct mobiveil_pcie *pcie)
+-{
+-      int retries;
+-
+-      /* check if the link is up or not */
+-      for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+-              if (mobiveil_pcie_link_up(pcie))
+-                      return 0;
+-
+-              usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
+-      }
+-
+-      dev_err(&pcie->pdev->dev, "link never came up\n");
+-
+-      return -ETIMEDOUT;
+-}
+-
+-static void mobiveil_pcie_enable_msi(struct mobiveil_pcie *pcie)
+-{
+-      phys_addr_t msg_addr = pcie->pcie_reg_base;
+-      struct mobiveil_msi *msi = &pcie->msi;
+-
+-      pcie->msi.num_of_vectors = PCI_NUM_MSI;
+-      msi->msi_pages_phys = (phys_addr_t)msg_addr;
+-
+-      writel_relaxed(lower_32_bits(msg_addr),
+-                     pcie->apb_csr_base + MSI_BASE_LO_OFFSET);
+-      writel_relaxed(upper_32_bits(msg_addr),
+-                     pcie->apb_csr_base + MSI_BASE_HI_OFFSET);
+-      writel_relaxed(4096, pcie->apb_csr_base + MSI_SIZE_OFFSET);
+-      writel_relaxed(1, pcie->apb_csr_base + MSI_ENABLE_OFFSET);
+-}
+-
+-static int mobiveil_host_init(struct mobiveil_pcie *pcie)
+-{
+-      u32 value, pab_ctrl, type;
+-      struct resource_entry *win;
+-
+-      /* setup bus numbers */
+-      value = csr_readl(pcie, PCI_PRIMARY_BUS);
+-      value &= 0xff000000;
+-      value |= 0x00ff0100;
+-      csr_writel(pcie, value, PCI_PRIMARY_BUS);
+-
+-      /*
+-       * program Bus Master Enable Bit in Command Register in PAB Config
+-       * Space
+-       */
+-      value = csr_readl(pcie, PCI_COMMAND);
+-      value |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+-      csr_writel(pcie, value, PCI_COMMAND);
+-
+-      /*
+-       * program PIO Enable Bit to 1 (and PEX PIO Enable to 1) in PAB_CTRL
+-       * register
+-       */
+-      pab_ctrl = csr_readl(pcie, PAB_CTRL);
+-      pab_ctrl |= (1 << AMBA_PIO_ENABLE_SHIFT) | (1 << PEX_PIO_ENABLE_SHIFT);
+-      csr_writel(pcie, pab_ctrl, PAB_CTRL);
+-
+-      csr_writel(pcie, (PAB_INTP_INTX_MASK | PAB_INTP_MSI_MASK),
+-                 PAB_INTP_AMBA_MISC_ENB);
+-
+-      /*
+-       * program PIO Enable Bit to 1 and Config Window Enable Bit to 1 in
+-       * PAB_AXI_PIO_CTRL Register
+-       */
+-      value = csr_readl(pcie, PAB_AXI_PIO_CTRL);
+-      value |= APIO_EN_MASK;
+-      csr_writel(pcie, value, PAB_AXI_PIO_CTRL);
+-
+-      /* Enable PCIe PIO master */
+-      value = csr_readl(pcie, PAB_PEX_PIO_CTRL);
+-      value |= 1 << PIO_ENABLE_SHIFT;
+-      csr_writel(pcie, value, PAB_PEX_PIO_CTRL);
+-
+-      /*
+-       * we'll program one outbound window for config reads and
+-       * another default inbound window for all the upstream traffic
+-       * rest of the outbound windows will be configured according to
+-       * the "ranges" field defined in device tree
+-       */
+-
+-      /* config outbound translation window */
+-      program_ob_windows(pcie, WIN_NUM_0, pcie->ob_io_res->start, 0,
+-                         CFG_WINDOW_TYPE, resource_size(pcie->ob_io_res));
+-
+-      /* memory inbound translation window */
+-      program_ib_windows(pcie, WIN_NUM_0, 0, 0, MEM_WINDOW_TYPE, IB_WIN_SIZE);
+-
+-      /* Get the I/O and memory ranges from DT */
+-      resource_list_for_each_entry(win, &pcie->resources) {
+-              if (resource_type(win->res) == IORESOURCE_MEM)
+-                      type = MEM_WINDOW_TYPE;
+-              else if (resource_type(win->res) == IORESOURCE_IO)
+-                      type = IO_WINDOW_TYPE;
+-              else
+-                      continue;
+-
+-              /* configure outbound translation window */
+-              program_ob_windows(pcie, pcie->ob_wins_configured,
+-                                 win->res->start,
+-                                 win->res->start - win->offset,
+-                                 type, resource_size(win->res));
+-      }
+-
+-      /* fixup for PCIe class register */
+-      value = csr_readl(pcie, PAB_INTP_AXI_PIO_CLASS);
+-      value &= 0xff;
+-      value |= (PCI_CLASS_BRIDGE_PCI << 16);
+-      csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS);
+-
+-      /* setup MSI hardware registers */
+-      mobiveil_pcie_enable_msi(pcie);
+-
+-      return 0;
+-}
+-
+-static void mobiveil_mask_intx_irq(struct irq_data *data)
+-{
+-      struct irq_desc *desc = irq_to_desc(data->irq);
+-      struct mobiveil_pcie *pcie;
+-      unsigned long flags;
+-      u32 mask, shifted_val;
+-
+-      pcie = irq_desc_get_chip_data(desc);
+-      mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
+-      raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
+-      shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
+-      shifted_val &= ~mask;
+-      csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
+-      raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags);
+-}
+-
+-static void mobiveil_unmask_intx_irq(struct irq_data *data)
+-{
+-      struct irq_desc *desc = irq_to_desc(data->irq);
+-      struct mobiveil_pcie *pcie;
+-      unsigned long flags;
+-      u32 shifted_val, mask;
+-
+-      pcie = irq_desc_get_chip_data(desc);
+-      mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
+-      raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
+-      shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
+-      shifted_val |= mask;
+-      csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
+-      raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags);
+-}
+-
+-static struct irq_chip intx_irq_chip = {
+-      .name = "mobiveil_pcie:intx",
+-      .irq_enable = mobiveil_unmask_intx_irq,
+-      .irq_disable = mobiveil_mask_intx_irq,
+-      .irq_mask = mobiveil_mask_intx_irq,
+-      .irq_unmask = mobiveil_unmask_intx_irq,
+-};
+-
+-/* routine to setup the INTx related data */
+-static int mobiveil_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
+-                                irq_hw_number_t hwirq)
+-{
+-      irq_set_chip_and_handler(irq, &intx_irq_chip, handle_level_irq);
+-      irq_set_chip_data(irq, domain->host_data);
+-
+-      return 0;
+-}
+-
+-/* INTx domain operations structure */
+-static const struct irq_domain_ops intx_domain_ops = {
+-      .map = mobiveil_pcie_intx_map,
+-};
+-
+-static struct irq_chip mobiveil_msi_irq_chip = {
+-      .name = "Mobiveil PCIe MSI",
+-      .irq_mask = pci_msi_mask_irq,
+-      .irq_unmask = pci_msi_unmask_irq,
+-};
+-
+-static struct msi_domain_info mobiveil_msi_domain_info = {
+-      .flags  = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+-                 MSI_FLAG_PCI_MSIX),
+-      .chip   = &mobiveil_msi_irq_chip,
+-};
+-
+-static void mobiveil_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+-{
+-      struct mobiveil_pcie *pcie = irq_data_get_irq_chip_data(data);
+-      phys_addr_t addr = pcie->pcie_reg_base + (data->hwirq * sizeof(int));
+-
+-      msg->address_lo = lower_32_bits(addr);
+-      msg->address_hi = upper_32_bits(addr);
+-      msg->data = data->hwirq;
+-
+-      dev_dbg(&pcie->pdev->dev, "msi#%d address_hi %#x address_lo %#x\n",
+-              (int)data->hwirq, msg->address_hi, msg->address_lo);
+-}
+-
+-static int mobiveil_msi_set_affinity(struct irq_data *irq_data,
+-                                   const struct cpumask *mask, bool force)
+-{
+-      return -EINVAL;
+-}
+-
+-static struct irq_chip mobiveil_msi_bottom_irq_chip = {
+-      .name                   = "Mobiveil MSI",
+-      .irq_compose_msi_msg    = mobiveil_compose_msi_msg,
+-      .irq_set_affinity       = mobiveil_msi_set_affinity,
+-};
+-
+-static int mobiveil_irq_msi_domain_alloc(struct irq_domain *domain,
+-                                       unsigned int virq,
+-                                       unsigned int nr_irqs, void *args)
+-{
+-      struct mobiveil_pcie *pcie = domain->host_data;
+-      struct mobiveil_msi *msi = &pcie->msi;
+-      unsigned long bit;
+-
+-      WARN_ON(nr_irqs != 1);
+-      mutex_lock(&msi->lock);
+-
+-      bit = find_first_zero_bit(msi->msi_irq_in_use, msi->num_of_vectors);
+-      if (bit >= msi->num_of_vectors) {
+-              mutex_unlock(&msi->lock);
+-              return -ENOSPC;
+-      }
+-
+-      set_bit(bit, msi->msi_irq_in_use);
+-
+-      mutex_unlock(&msi->lock);
+-
+-      irq_domain_set_info(domain, virq, bit, &mobiveil_msi_bottom_irq_chip,
+-                          domain->host_data, handle_level_irq, NULL, NULL);
+-      return 0;
+-}
+-
+-static void mobiveil_irq_msi_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 mobiveil_pcie *pcie = irq_data_get_irq_chip_data(d);
+-      struct mobiveil_msi *msi = &pcie->msi;
+-
+-      mutex_lock(&msi->lock);
+-
+-      if (!test_bit(d->hwirq, msi->msi_irq_in_use))
+-              dev_err(&pcie->pdev->dev, "trying to free unused MSI#%lu\n",
+-                      d->hwirq);
+-      else
+-              __clear_bit(d->hwirq, msi->msi_irq_in_use);
+-
+-      mutex_unlock(&msi->lock);
+-}
+-static const struct irq_domain_ops msi_domain_ops = {
+-      .alloc  = mobiveil_irq_msi_domain_alloc,
+-      .free   = mobiveil_irq_msi_domain_free,
+-};
+-
+-static int mobiveil_allocate_msi_domains(struct mobiveil_pcie *pcie)
+-{
+-      struct device *dev = &pcie->pdev->dev;
+-      struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
+-      struct mobiveil_msi *msi = &pcie->msi;
+-
+-      mutex_init(&pcie->msi.lock);
+-      msi->dev_domain = irq_domain_add_linear(NULL, msi->num_of_vectors,
+-                                              &msi_domain_ops, pcie);
+-      if (!msi->dev_domain) {
+-              dev_err(dev, "failed to create IRQ domain\n");
+-              return -ENOMEM;
+-      }
+-
+-      msi->msi_domain = pci_msi_create_irq_domain(fwnode,
+-                                                  &mobiveil_msi_domain_info,
+-                                                  msi->dev_domain);
+-      if (!msi->msi_domain) {
+-              dev_err(dev, "failed to create MSI domain\n");
+-              irq_domain_remove(msi->dev_domain);
+-              return -ENOMEM;
+-      }
+-
+-      return 0;
+-}
+-
+-static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie)
+-{
+-      struct device *dev = &pcie->pdev->dev;
+-      struct device_node *node = dev->of_node;
+-      int ret;
+-
+-      /* setup INTx */
+-      pcie->intx_domain = irq_domain_add_linear(node, PCI_NUM_INTX,
+-                                                &intx_domain_ops, pcie);
+-
+-      if (!pcie->intx_domain) {
+-              dev_err(dev, "Failed to get a INTx IRQ domain\n");
+-              return -ENOMEM;
+-      }
+-
+-      raw_spin_lock_init(&pcie->intx_mask_lock);
+-
+-      /* setup MSI */
+-      ret = mobiveil_allocate_msi_domains(pcie);
+-      if (ret)
+-              return ret;
+-
+-      return 0;
+-}
+-
+-static int mobiveil_pcie_probe(struct platform_device *pdev)
+-{
+-      struct mobiveil_pcie *pcie;
+-      struct pci_bus *bus;
+-      struct pci_bus *child;
+-      struct pci_host_bridge *bridge;
+-      struct device *dev = &pdev->dev;
+-      resource_size_t iobase;
+-      int ret;
+-
+-      /* allocate the PCIe port */
+-      bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
+-      if (!bridge)
+-              return -ENOMEM;
+-
+-      pcie = pci_host_bridge_priv(bridge);
+-
+-      pcie->pdev = pdev;
+-
+-      ret = mobiveil_pcie_parse_dt(pcie);
+-      if (ret) {
+-              dev_err(dev, "Parsing DT failed, ret: %x\n", ret);
+-              return ret;
+-      }
+-
+-      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);
+-      if (ret) {
+-              dev_err(dev, "Getting bridge resources failed\n");
+-              return ret;
+-      }
+-
+-      /*
+-       * configure all inbound and outbound windows and prepare the RC for
+-       * config access
+-       */
+-      ret = mobiveil_host_init(pcie);
+-      if (ret) {
+-              dev_err(dev, "Failed to initialize host\n");
+-              goto error;
+-      }
+-
+-      /* initialize the IRQ domains */
+-      ret = mobiveil_pcie_init_irq_domain(pcie);
+-      if (ret) {
+-              dev_err(dev, "Failed creating IRQ Domain\n");
+-              goto error;
+-      }
+-
+-      irq_set_chained_handler_and_data(pcie->irq, mobiveil_pcie_isr, pcie);
+-
+-      ret = devm_request_pci_bus_resources(dev, &pcie->resources);
+-      if (ret)
+-              goto error;
+-
+-      /* Initialize bridge */
+-      list_splice_init(&pcie->resources, &bridge->windows);
+-      bridge->dev.parent = dev;
+-      bridge->sysdata = pcie;
+-      bridge->busnr = pcie->root_bus_nr;
+-      bridge->ops = &mobiveil_pcie_ops;
+-      bridge->map_irq = of_irq_parse_and_map_pci;
+-      bridge->swizzle_irq = pci_common_swizzle;
+-
+-      ret = mobiveil_bringup_link(pcie);
+-      if (ret) {
+-              dev_info(dev, "link bring-up failed\n");
+-              goto error;
+-      }
+-
+-      /* setup the kernel resources for the newly added PCIe root bus */
+-      ret = pci_scan_root_bus_bridge(bridge);
+-      if (ret)
+-              goto error;
+-
+-      bus = bridge->bus;
+-
+-      pci_assign_unassigned_bus_resources(bus);
+-      list_for_each_entry(child, &bus->children, node)
+-              pcie_bus_configure_settings(child);
+-      pci_bus_add_devices(bus);
+-
+-      return 0;
+-error:
+-      pci_free_resource_list(&pcie->resources);
+-      return ret;
+-}
+-
+-static const struct of_device_id mobiveil_pcie_of_match[] = {
+-      {.compatible = "mbvl,gpex40-pcie",},
+-      {},
+-};
+-
+-MODULE_DEVICE_TABLE(of, mobiveil_pcie_of_match);
+-
+-static struct platform_driver mobiveil_pcie_driver = {
+-      .probe = mobiveil_pcie_probe,
+-      .driver = {
+-              .name = "mobiveil-pcie",
+-              .of_match_table = mobiveil_pcie_of_match,
+-              .suppress_bind_attrs = true,
+-      },
+-};
+-
+-builtin_platform_driver(mobiveil_pcie_driver);
+-
+-MODULE_LICENSE("GPL v2");
+-MODULE_DESCRIPTION("Mobiveil PCIe host controller driver");
+-MODULE_AUTHOR("Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>");
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0010-PCI-mobiveil-Make-mobiveil_host_init-can-be-used-to-.patch b/target/linux/layerscape/patches-5.4/812-pcie-0010-PCI-mobiveil-Make-mobiveil_host_init-can-be-used-to-.patch
new file mode 100644 (file)
index 0000000..e38eca5
--- /dev/null
@@ -0,0 +1,152 @@
+From d4bb5e0d43909758046c527d883405f556de85fa Mon Sep 17 00:00:00 2001
+From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Date: Tue, 25 Jun 2019 09:09:14 +0000
+Subject: [PATCH] PCI: mobiveil: Make mobiveil_host_init() can be used to
+ re-init host
+
+Make the mobiveil_host_init() function can be used to re-init
+host controller's PAB and GPEX CSR register block, as NXP
+integrated Mobiveil IP has to reset and then re-init the PAB
+and GPEX CSR registers upon hot-reset.
+
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Reviewed-by: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
+---
+ .../pci/controller/mobiveil/pcie-mobiveil-host.c   | 43 +++++++++++-----------
+ drivers/pci/controller/mobiveil/pcie-mobiveil.h    |  3 +-
+ 2 files changed, 24 insertions(+), 22 deletions(-)
+
+--- a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
++++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
+@@ -215,16 +215,21 @@ static void mobiveil_pcie_enable_msi(str
+       writel_relaxed(1, pcie->apb_csr_base + MSI_ENABLE_OFFSET);
+ }
+-static int mobiveil_host_init(struct mobiveil_pcie *pcie)
++int mobiveil_host_init(struct mobiveil_pcie *pcie, bool reinit)
+ {
+       u32 value, pab_ctrl, type;
+       struct resource_entry *win;
+-      /* setup bus numbers */
+-      value = csr_readl(pcie, PCI_PRIMARY_BUS);
+-      value &= 0xff000000;
+-      value |= 0x00ff0100;
+-      csr_writel(pcie, value, PCI_PRIMARY_BUS);
++      pcie->ib_wins_configured = 0;
++      pcie->ob_wins_configured = 0;
++
++      if (!reinit) {
++              /* setup bus numbers */
++              value = csr_readl(pcie, PCI_PRIMARY_BUS);
++              value &= 0xff000000;
++              value |= 0x00ff0100;
++              csr_writel(pcie, value, PCI_PRIMARY_BUS);
++      }
+       /*
+        * program Bus Master Enable Bit in Command Register in PAB Config
+@@ -270,7 +275,7 @@ static int mobiveil_host_init(struct mob
+       program_ib_windows(pcie, WIN_NUM_0, 0, 0, MEM_WINDOW_TYPE, IB_WIN_SIZE);
+       /* Get the I/O and memory ranges from DT */
+-      resource_list_for_each_entry(win, &pcie->resources) {
++      resource_list_for_each_entry(win, pcie->resources) {
+               if (resource_type(win->res) == IORESOURCE_MEM) {
+                       type = MEM_WINDOW_TYPE;
+               } else if (resource_type(win->res) == IORESOURCE_IO) {
+@@ -541,8 +546,6 @@ int mobiveil_pcie_host_probe(struct mobi
+       resource_size_t iobase;
+       int ret;
+-      INIT_LIST_HEAD(&pcie->resources);
+-
+       ret = mobiveil_pcie_parse_dt(pcie);
+       if (ret) {
+               dev_err(dev, "Parsing DT failed, ret: %x\n", ret);
+@@ -551,34 +554,35 @@ int mobiveil_pcie_host_probe(struct mobi
+       /* 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);
++                                                  &bridge->windows, &iobase);
+       if (ret) {
+               dev_err(dev, "Getting bridge resources failed\n");
+               return ret;
+       }
++      pcie->resources = &bridge->windows;
++
+       /*
+        * configure all inbound and outbound windows and prepare the RC for
+        * config access
+        */
+-      ret = mobiveil_host_init(pcie);
++      ret = mobiveil_host_init(pcie, false);
+       if (ret) {
+               dev_err(dev, "Failed to initialize host\n");
+-              goto error;
++              return ret;
+       }
+       ret = mobiveil_pcie_interrupt_init(pcie);
+       if (ret) {
+               dev_err(dev, "Interrupt init failed\n");
+-              goto error;
++              return ret;
+       }
+-      ret = devm_request_pci_bus_resources(dev, &pcie->resources);
++      ret = devm_request_pci_bus_resources(dev, pcie->resources);
+       if (ret)
+-              goto error;
++              return ret;
+       /* Initialize bridge */
+-      list_splice_init(&pcie->resources, &bridge->windows);
+       bridge->dev.parent = dev;
+       bridge->sysdata = pcie;
+       bridge->busnr = pcie->rp.root_bus_nr;
+@@ -589,13 +593,13 @@ int mobiveil_pcie_host_probe(struct mobi
+       ret = mobiveil_bringup_link(pcie);
+       if (ret) {
+               dev_info(dev, "link bring-up failed\n");
+-              goto error;
++              return ret;
+       }
+       /* setup the kernel resources for the newly added PCIe root bus */
+       ret = pci_scan_root_bus_bridge(bridge);
+       if (ret)
+-              goto error;
++              return ret;
+       bus = bridge->bus;
+@@ -605,7 +609,4 @@ int mobiveil_pcie_host_probe(struct mobi
+       pci_bus_add_devices(bus);
+       return 0;
+-error:
+-      pci_free_resource_list(&pcie->resources);
+-      return ret;
+ }
+--- a/drivers/pci/controller/mobiveil/pcie-mobiveil.h
++++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
+@@ -153,7 +153,7 @@ struct mobiveil_pab_ops {
+ struct mobiveil_pcie {
+       struct platform_device *pdev;
+-      struct list_head resources;
++      struct list_head *resources;
+       void __iomem *csr_axi_slave_base;       /* PAB registers base */
+       phys_addr_t pcie_reg_base;      /* Physical PCIe Controller Base */
+       void __iomem *apb_csr_base;     /* MSI register base */
+@@ -167,6 +167,7 @@ struct mobiveil_pcie {
+ };
+ int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie);
++int mobiveil_host_init(struct mobiveil_pcie *pcie, bool reinit);
+ bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie);
+ int mobiveil_bringup_link(struct mobiveil_pcie *pcie);
+ void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0011-PCI-mobiveil-Add-8-bit-and-16-bit-CSR-register-acces.patch b/target/linux/layerscape/patches-5.4/812-pcie-0011-PCI-mobiveil-Add-8-bit-and-16-bit-CSR-register-acces.patch
new file mode 100644 (file)
index 0000000..ee8c519
--- /dev/null
@@ -0,0 +1,47 @@
+From 7e92994ec22c9d337f6012ac913e7958012ad52e Mon Sep 17 00:00:00 2001
+From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Date: Tue, 25 Jun 2019 09:09:28 +0000
+Subject: [PATCH] PCI: mobiveil: Add 8-bit and 16-bit CSR register accessors
+
+There are some 8-bit and 16-bit registers in PCIe configuration
+space, so add these accessors accordingly.
+
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Reviewed-by: Minghuan Lian <Minghuan.Lian@nxp.com>
+Reviewed-by: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
+---
+ drivers/pci/controller/mobiveil/pcie-mobiveil.h | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+--- a/drivers/pci/controller/mobiveil/pcie-mobiveil.h
++++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
+@@ -182,9 +182,29 @@ static inline u32 csr_readl(struct mobiv
+       return csr_read(pcie, off, 0x4);
+ }
++static inline u32 csr_readw(struct mobiveil_pcie *pcie, u32 off)
++{
++      return csr_read(pcie, off, 0x2);
++}
++
++static inline u32 csr_readb(struct mobiveil_pcie *pcie, u32 off)
++{
++      return csr_read(pcie, off, 0x1);
++}
++
+ static inline void csr_writel(struct mobiveil_pcie *pcie, u32 val, u32 off)
+ {
+       csr_write(pcie, val, off, 0x4);
+ }
++static inline void csr_writew(struct mobiveil_pcie *pcie, u32 val, u32 off)
++{
++      csr_write(pcie, val, off, 0x2);
++}
++
++static inline void csr_writeb(struct mobiveil_pcie *pcie, u32 val, u32 off)
++{
++      csr_write(pcie, val, off, 0x1);
++}
++
+ #endif /* _PCIE_MOBIVEIL_H */
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0012-PCI-mobiveil-Add-PCIe-Gen4-RC-driver-for-NXP-Layersc.patch b/target/linux/layerscape/patches-5.4/812-pcie-0012-PCI-mobiveil-Add-PCIe-Gen4-RC-driver-for-NXP-Layersc.patch
new file mode 100644 (file)
index 0000000..33e01c1
--- /dev/null
@@ -0,0 +1,355 @@
+From 68b6fec37f4c6fa382da4b76039743c4de89b028 Mon Sep 17 00:00:00 2001
+From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Date: Tue, 25 Jun 2019 09:09:35 +0000
+Subject: [PATCH] PCI: mobiveil: Add PCIe Gen4 RC driver for NXP Layerscape
+ SoCs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This PCIe controller is based on the Mobiveil GPEX IP, which is
+compatible with the PCI Express™ Base Specification, Revision 4.0.
+
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Reviewed-by: Minghuan Lian <Minghuan.Lian@nxp.com>
+---
+ drivers/pci/controller/mobiveil/Kconfig            |  10 +
+ drivers/pci/controller/mobiveil/Makefile           |   1 +
+ .../pci/controller/mobiveil/pcie-layerscape-gen4.c | 274 +++++++++++++++++++++
+ drivers/pci/controller/mobiveil/pcie-mobiveil.h    |  16 +-
+ 4 files changed, 299 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c
+
+--- a/drivers/pci/controller/mobiveil/Kconfig
++++ b/drivers/pci/controller/mobiveil/Kconfig
+@@ -21,4 +21,14 @@ config PCIE_MOBIVEIL_PLAT
+         Soft IP. It has up to 8 outbound and inbound windows
+         for address translation and it is a PCIe Gen4 IP.
++config PCIE_LAYERSCAPE_GEN4
++      bool "Freescale Layerscape PCIe Gen4 controller"
++      depends on PCI
++      depends on OF && (ARM64 || ARCH_LAYERSCAPE)
++      depends on PCI_MSI_IRQ_DOMAIN
++      select PCIE_MOBIVEIL_HOST
++      help
++        Say Y here if you want PCIe Gen4 controller support on
++        Layerscape SoCs. The PCIe controller can work in RC or
++        EP mode according to RCW[HOST_AGT_PEX] setting.
+ endmenu
+--- a/drivers/pci/controller/mobiveil/Makefile
++++ b/drivers/pci/controller/mobiveil/Makefile
+@@ -2,3 +2,4 @@
+ obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
+ obj-$(CONFIG_PCIE_MOBIVEIL_HOST) += pcie-mobiveil-host.o
+ obj-$(CONFIG_PCIE_MOBIVEIL_PLAT) += pcie-mobiveil-plat.o
++obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie-layerscape-gen4.o
+--- /dev/null
++++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c
+@@ -0,0 +1,274 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * PCIe Gen4 host controller driver for NXP Layerscape SoCs
++ *
++ * Copyright 2019 NXP
++ *
++ * Author: Zhiqiang Hou <Zhiqiang.Hou@nxp.com>
++ */
++
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/of_pci.h>
++#include <linux/of_platform.h>
++#include <linux/of_irq.h>
++#include <linux/of_address.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <linux/resource.h>
++#include <linux/mfd/syscon.h>
++#include <linux/regmap.h>
++
++#include "pcie-mobiveil.h"
++
++/* LUT and PF control registers */
++#define PCIE_LUT_OFF                  0x80000
++#define PCIE_PF_OFF                   0xc0000
++#define PCIE_PF_INT_STAT              0x18
++#define PF_INT_STAT_PABRST            BIT(31)
++
++#define PCIE_PF_DBG                   0x7fc
++#define PF_DBG_LTSSM_MASK             0x3f
++#define PF_DBG_LTSSM_L0                       0x2d /* L0 state */
++#define PF_DBG_WE                     BIT(31)
++#define PF_DBG_PABR                   BIT(27)
++
++#define to_ls_pcie_g4(x)              platform_get_drvdata((x)->pdev)
++
++struct ls_pcie_g4 {
++      struct mobiveil_pcie pci;
++      struct delayed_work dwork;
++      int irq;
++};
++
++static inline u32 ls_pcie_g4_lut_readl(struct ls_pcie_g4 *pcie, u32 off)
++{
++      return ioread32(pcie->pci.csr_axi_slave_base + PCIE_LUT_OFF + off);
++}
++
++static inline void ls_pcie_g4_lut_writel(struct ls_pcie_g4 *pcie,
++                                       u32 off, u32 val)
++{
++      iowrite32(val, pcie->pci.csr_axi_slave_base + PCIE_LUT_OFF + off);
++}
++
++static inline u32 ls_pcie_g4_pf_readl(struct ls_pcie_g4 *pcie, u32 off)
++{
++      return ioread32(pcie->pci.csr_axi_slave_base + PCIE_PF_OFF + off);
++}
++
++static inline void ls_pcie_g4_pf_writel(struct ls_pcie_g4 *pcie,
++                                      u32 off, u32 val)
++{
++      iowrite32(val, pcie->pci.csr_axi_slave_base + PCIE_PF_OFF + off);
++}
++
++static bool ls_pcie_g4_is_bridge(struct ls_pcie_g4 *pcie)
++{
++      struct mobiveil_pcie *mv_pci = &pcie->pci;
++      u32 header_type;
++
++      header_type = csr_readb(mv_pci, PCI_HEADER_TYPE);
++      header_type &= 0x7f;
++
++      return header_type == PCI_HEADER_TYPE_BRIDGE;
++}
++
++static int ls_pcie_g4_link_up(struct mobiveil_pcie *pci)
++{
++      struct ls_pcie_g4 *pcie = to_ls_pcie_g4(pci);
++      u32 state;
++
++      state = ls_pcie_g4_pf_readl(pcie, PCIE_PF_DBG);
++      state = state & PF_DBG_LTSSM_MASK;
++
++      if (state == PF_DBG_LTSSM_L0)
++              return 1;
++
++      return 0;
++}
++
++static void ls_pcie_g4_disable_interrupt(struct ls_pcie_g4 *pcie)
++{
++      struct mobiveil_pcie *mv_pci = &pcie->pci;
++
++      csr_writel(mv_pci, 0, PAB_INTP_AMBA_MISC_ENB);
++}
++
++static void ls_pcie_g4_enable_interrupt(struct ls_pcie_g4 *pcie)
++{
++      struct mobiveil_pcie *mv_pci = &pcie->pci;
++      u32 val;
++
++      /* Clear the interrupt status */
++      csr_writel(mv_pci, 0xffffffff, PAB_INTP_AMBA_MISC_STAT);
++
++      val = PAB_INTP_INTX_MASK | PAB_INTP_MSI | PAB_INTP_RESET |
++            PAB_INTP_PCIE_UE | PAB_INTP_IE_PMREDI | PAB_INTP_IE_EC;
++      csr_writel(mv_pci, val, PAB_INTP_AMBA_MISC_ENB);
++}
++
++static void ls_pcie_g4_reinit_hw(struct ls_pcie_g4 *pcie)
++{
++      struct mobiveil_pcie *mv_pci = &pcie->pci;
++      struct device *dev = &mv_pci->pdev->dev;
++      u32 val, act_stat;
++      int to = 100;
++
++      /* Poll for pab_csb_reset to set and PAB activity to clear */
++      do {
++              usleep_range(10, 15);
++              val = ls_pcie_g4_pf_readl(pcie, PCIE_PF_INT_STAT);
++              act_stat = csr_readl(mv_pci, PAB_ACTIVITY_STAT);
++      } while (((val & PF_INT_STAT_PABRST) == 0 || act_stat) && to--);
++      if (to < 0) {
++              dev_err(dev, "Poll PABRST&PABACT timeout\n");
++              return;
++      }
++
++      /* clear PEX_RESET bit in PEX_PF0_DBG register */
++      val = ls_pcie_g4_pf_readl(pcie, PCIE_PF_DBG);
++      val |= PF_DBG_WE;
++      ls_pcie_g4_pf_writel(pcie, PCIE_PF_DBG, val);
++
++      val = ls_pcie_g4_pf_readl(pcie, PCIE_PF_DBG);
++      val |= PF_DBG_PABR;
++      ls_pcie_g4_pf_writel(pcie, PCIE_PF_DBG, val);
++
++      val = ls_pcie_g4_pf_readl(pcie, PCIE_PF_DBG);
++      val &= ~PF_DBG_WE;
++      ls_pcie_g4_pf_writel(pcie, PCIE_PF_DBG, val);
++
++      mobiveil_host_init(mv_pci, true);
++
++      to = 100;
++      while (!ls_pcie_g4_link_up(mv_pci) && to--)
++              usleep_range(200, 250);
++      if (to < 0)
++              dev_err(dev, "PCIe link training timeout\n");
++}
++
++static irqreturn_t ls_pcie_g4_isr(int irq, void *dev_id)
++{
++      struct ls_pcie_g4 *pcie = (struct ls_pcie_g4 *)dev_id;
++      struct mobiveil_pcie *mv_pci = &pcie->pci;
++      u32 val;
++
++      val = csr_readl(mv_pci, PAB_INTP_AMBA_MISC_STAT);
++      if (!val)
++              return IRQ_NONE;
++
++      if (val & PAB_INTP_RESET) {
++              ls_pcie_g4_disable_interrupt(pcie);
++              schedule_delayed_work(&pcie->dwork, msecs_to_jiffies(1));
++      }
++
++      csr_writel(mv_pci, val, PAB_INTP_AMBA_MISC_STAT);
++
++      return IRQ_HANDLED;
++}
++
++static int ls_pcie_g4_interrupt_init(struct mobiveil_pcie *mv_pci)
++{
++      struct ls_pcie_g4 *pcie = to_ls_pcie_g4(mv_pci);
++      struct platform_device *pdev = mv_pci->pdev;
++      struct device *dev = &pdev->dev;
++      int ret;
++
++      pcie->irq = platform_get_irq_byname(pdev, "intr");
++      if (pcie->irq < 0) {
++              dev_err(dev, "Can't get 'intr' IRQ, errno = %d\n", pcie->irq);
++              return pcie->irq;
++      }
++      ret = devm_request_irq(dev, pcie->irq, ls_pcie_g4_isr,
++                             IRQF_SHARED, pdev->name, pcie);
++      if (ret) {
++              dev_err(dev, "Can't register PCIe IRQ, errno = %d\n", ret);
++              return  ret;
++      }
++
++      return 0;
++}
++
++static void ls_pcie_g4_reset(struct work_struct *work)
++{
++      struct delayed_work *dwork = container_of(work, struct delayed_work,
++                                                work);
++      struct ls_pcie_g4 *pcie = container_of(dwork, struct ls_pcie_g4, dwork);
++      struct mobiveil_pcie *mv_pci = &pcie->pci;
++      u16 ctrl;
++
++      ctrl = csr_readw(mv_pci, PCI_BRIDGE_CONTROL);
++      ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
++      csr_writew(mv_pci, ctrl, PCI_BRIDGE_CONTROL);
++      ls_pcie_g4_reinit_hw(pcie);
++      ls_pcie_g4_enable_interrupt(pcie);
++}
++
++static struct mobiveil_rp_ops ls_pcie_g4_rp_ops = {
++      .interrupt_init = ls_pcie_g4_interrupt_init,
++};
++
++static const struct mobiveil_pab_ops ls_pcie_g4_pab_ops = {
++      .link_up = ls_pcie_g4_link_up,
++};
++
++static int __init ls_pcie_g4_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct pci_host_bridge *bridge;
++      struct mobiveil_pcie *mv_pci;
++      struct ls_pcie_g4 *pcie;
++      struct device_node *np = dev->of_node;
++      int ret;
++
++      if (!of_parse_phandle(np, "msi-parent", 0)) {
++              dev_err(dev, "Failed to find msi-parent\n");
++              return -EINVAL;
++      }
++
++      bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
++      if (!bridge)
++              return -ENOMEM;
++
++      pcie = pci_host_bridge_priv(bridge);
++      mv_pci = &pcie->pci;
++
++      mv_pci->pdev = pdev;
++      mv_pci->ops = &ls_pcie_g4_pab_ops;
++      mv_pci->rp.ops = &ls_pcie_g4_rp_ops;
++      mv_pci->bridge = bridge;
++
++      platform_set_drvdata(pdev, pcie);
++
++      INIT_DELAYED_WORK(&pcie->dwork, ls_pcie_g4_reset);
++
++      ret = mobiveil_pcie_host_probe(mv_pci);
++      if (ret) {
++              dev_err(dev, "Fail to probe\n");
++              return  ret;
++      }
++
++      if (!ls_pcie_g4_is_bridge(pcie))
++              return -ENODEV;
++
++      ls_pcie_g4_enable_interrupt(pcie);
++
++      return 0;
++}
++
++static const struct of_device_id ls_pcie_g4_of_match[] = {
++      { .compatible = "fsl,lx2160a-pcie", },
++      { },
++};
++
++static struct platform_driver ls_pcie_g4_driver = {
++      .driver = {
++              .name = "layerscape-pcie-gen4",
++              .of_match_table = ls_pcie_g4_of_match,
++              .suppress_bind_attrs = true,
++      },
++};
++
++builtin_platform_driver_probe(ls_pcie_g4_driver, ls_pcie_g4_probe);
+--- a/drivers/pci/controller/mobiveil/pcie-mobiveil.h
++++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
+@@ -43,6 +43,8 @@
+ #define  PAGE_LO_MASK                 0x3ff
+ #define  PAGE_SEL_OFFSET_SHIFT                10
++#define PAB_ACTIVITY_STAT             0x81c
++
+ #define PAB_AXI_PIO_CTRL              0x0840
+ #define  APIO_EN_MASK                 0xf
+@@ -51,8 +53,18 @@
+ #define PAB_INTP_AMBA_MISC_ENB                0x0b0c
+ #define PAB_INTP_AMBA_MISC_STAT               0x0b1c
+-#define  PAB_INTP_INTX_MASK           0x01e0
+-#define  PAB_INTP_MSI_MASK            0x8
++#define  PAB_INTP_RESET                       BIT(1)
++#define  PAB_INTP_MSI                 BIT(3)
++#define  PAB_INTP_INTA                        BIT(5)
++#define  PAB_INTP_INTB                        BIT(6)
++#define  PAB_INTP_INTC                        BIT(7)
++#define  PAB_INTP_INTD                        BIT(8)
++#define  PAB_INTP_PCIE_UE             BIT(9)
++#define  PAB_INTP_IE_PMREDI           BIT(29)
++#define  PAB_INTP_IE_EC                       BIT(30)
++#define  PAB_INTP_MSI_MASK            PAB_INTP_MSI
++#define  PAB_INTP_INTX_MASK           (PAB_INTP_INTA | PAB_INTP_INTB |\
++                                      PAB_INTP_INTC | PAB_INTP_INTD)
+ #define PAB_AXI_AMAP_CTRL(win)                PAB_REG_ADDR(0x0ba0, win)
+ #define  WIN_ENABLE_SHIFT             0
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0013-PCI-mobiveil-ls_pcie_g4-add-Workaround-for-A-011577.patch b/target/linux/layerscape/patches-5.4/812-pcie-0013-PCI-mobiveil-ls_pcie_g4-add-Workaround-for-A-011577.patch
new file mode 100644 (file)
index 0000000..6171a62
--- /dev/null
@@ -0,0 +1,150 @@
+From 7f38d09c9fd7906cea160e198299a7e378f9c796 Mon Sep 17 00:00:00 2001
+From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Date: Tue, 6 Nov 2018 09:44:05 +0800
+Subject: [PATCH] PCI: mobiveil: ls_pcie_g4: add Workaround for A-011577
+
+PCIe configuration access to non-existent function triggered
+SERROR interrupt exception.
+
+Workaround:
+Disable error reporting on AXI bus during the Vendor ID read
+transactions in enumeration.
+
+This ERRATA is only for LX2160A Rev1.0, and it will be fixed
+in Rev2.0.
+
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+---
+ .../pci/controller/mobiveil/pcie-layerscape-gen4.c | 36 ++++++++++++++++++++++
+ .../pci/controller/mobiveil/pcie-mobiveil-host.c   | 17 +++++++++-
+ drivers/pci/controller/mobiveil/pcie-mobiveil.h    |  3 ++
+ 3 files changed, 55 insertions(+), 1 deletion(-)
+
+--- a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c
++++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c
+@@ -22,8 +22,12 @@
+ #include "pcie-mobiveil.h"
++#define REV_1_0                               (0x10)
++
+ /* LUT and PF control registers */
+ #define PCIE_LUT_OFF                  0x80000
++#define PCIE_LUT_GCR                  (0x28)
++#define PCIE_LUT_GCR_RRE              (0)
+ #define PCIE_PF_OFF                   0xc0000
+ #define PCIE_PF_INT_STAT              0x18
+ #define PF_INT_STAT_PABRST            BIT(31)
+@@ -40,6 +44,7 @@ struct ls_pcie_g4 {
+       struct mobiveil_pcie pci;
+       struct delayed_work dwork;
+       int irq;
++      u8 rev;
+ };
+ static inline u32 ls_pcie_g4_lut_readl(struct ls_pcie_g4 *pcie, u32 off)
+@@ -75,6 +80,15 @@ static bool ls_pcie_g4_is_bridge(struct
+       return header_type == PCI_HEADER_TYPE_BRIDGE;
+ }
++static int ls_pcie_g4_host_init(struct mobiveil_pcie *pci)
++{
++      struct ls_pcie_g4 *pcie = to_ls_pcie_g4(pci);
++
++      pcie->rev = csr_readb(pci, PCI_REVISION_ID);
++
++      return 0;
++}
++
+ static int ls_pcie_g4_link_up(struct mobiveil_pcie *pci)
+ {
+       struct ls_pcie_g4 *pcie = to_ls_pcie_g4(pci);
+@@ -206,12 +220,34 @@ static void ls_pcie_g4_reset(struct work
+       ls_pcie_g4_enable_interrupt(pcie);
+ }
++static int ls_pcie_g4_read_other_conf(struct pci_bus *bus, unsigned int devfn,
++                                 int where, int size, u32 *val)
++{
++      struct mobiveil_pcie *pci = bus->sysdata;
++      struct ls_pcie_g4 *pcie = to_ls_pcie_g4(pci);
++      int ret;
++
++      if (pcie->rev == REV_1_0 && where == PCI_VENDOR_ID)
++              ls_pcie_g4_lut_writel(pcie, PCIE_LUT_GCR,
++                                    0 << PCIE_LUT_GCR_RRE);
++
++      ret = pci_generic_config_read(bus, devfn, where, size, val);
++
++      if (pcie->rev == REV_1_0 && where == PCI_VENDOR_ID)
++              ls_pcie_g4_lut_writel(pcie, PCIE_LUT_GCR,
++                                    1 << PCIE_LUT_GCR_RRE);
++
++      return ret;
++}
++
+ static struct mobiveil_rp_ops ls_pcie_g4_rp_ops = {
+       .interrupt_init = ls_pcie_g4_interrupt_init,
++      .read_other_conf = ls_pcie_g4_read_other_conf,
+ };
+ static const struct mobiveil_pab_ops ls_pcie_g4_pab_ops = {
+       .link_up = ls_pcie_g4_link_up,
++      .host_init = ls_pcie_g4_host_init,
+ };
+ static int __init ls_pcie_g4_probe(struct platform_device *pdev)
+--- a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
++++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
+@@ -77,9 +77,20 @@ static void __iomem *mobiveil_pcie_map_b
+       return pcie->rp.config_axi_slave_base + where;
+ }
++static int mobiveil_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
++                                   int where, int size, u32 *val)
++{
++      struct mobiveil_pcie *pcie = bus->sysdata;
++      struct root_port *rp = &pcie->rp;
++
++      if (bus->number > rp->root_bus_nr && rp->ops->read_other_conf)
++              return rp->ops->read_other_conf(bus, devfn, where, size, val);
++
++      return pci_generic_config_read(bus, devfn, where, size, val);
++}
+ static struct pci_ops mobiveil_pcie_ops = {
+       .map_bus = mobiveil_pcie_map_bus,
+-      .read = pci_generic_config_read,
++      .read = mobiveil_pcie_config_read,
+       .write = pci_generic_config_write,
+ };
+@@ -300,6 +311,10 @@ int mobiveil_host_init(struct mobiveil_p
+       value |= (PCI_CLASS_BRIDGE_PCI << 16);
+       csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS);
++      /* Platform specific host init */
++      if (pcie->ops->host_init)
++              return pcie->ops->host_init(pcie);
++
+       return 0;
+ }
+--- a/drivers/pci/controller/mobiveil/pcie-mobiveil.h
++++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
+@@ -146,6 +146,8 @@ struct mobiveil_msi {                      /* MSI informati
+ struct mobiveil_rp_ops {
+       int (*interrupt_init)(struct mobiveil_pcie *pcie);
++      int (*read_other_conf)(struct pci_bus *bus, unsigned int devfn,
++                             int where, int size, u32 *val);
+ };
+ struct root_port {
+@@ -161,6 +163,7 @@ struct root_port {
+ struct mobiveil_pab_ops {
+       int (*link_up)(struct mobiveil_pcie *pcie);
++      int (*host_init)(struct mobiveil_pcie *pcie);
+ };
+ struct mobiveil_pcie {
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0014-PCI-mobiveil-ls_pcie_g4-add-Workaround-for-A-011451.patch b/target/linux/layerscape/patches-5.4/812-pcie-0014-PCI-mobiveil-ls_pcie_g4-add-Workaround-for-A-011451.patch
new file mode 100644 (file)
index 0000000..5486bdd
--- /dev/null
@@ -0,0 +1,73 @@
+From 5f1673ff67d5e8acf590fb5a4cc2d0d5d4115927 Mon Sep 17 00:00:00 2001
+From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Date: Tue, 6 Nov 2018 10:14:57 +0800
+Subject: [PATCH] PCI: mobiveil: ls_pcie_g4: add Workaround for A-011451
+
+When LX2 PCIe controller is sending multiple split completions and
+ACK latency expires indicating that ACK should be send at priority.
+But because of large number of split completions and FC update DLLP,
+the controller does not give priority to ACK transmission. This
+results into ACK latency timer timeout error at the link partner and
+the pending TLPs are replayed by the link partner again.
+
+Workaround:
+1. Reduce the ACK latency timeout value to a very small value.
+2. Restrict the number of completions from the LX2 PCIe controller
+   to 1, by changing the Max Read Request Size (MRRS) of link partner
+   to the same value as Max Packet size (MPS).
+
+This patch implemented part 1, the part 2 can be set by kernel parameter
+'pci=pcie_bus_perf'
+
+This ERRATA is only for LX2160A Rev1.0, and it will be fixed
+in Rev2.0.
+
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+---
+ drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c | 15 +++++++++++++++
+ drivers/pci/controller/mobiveil/pcie-mobiveil.h        |  4 ++++
+ 2 files changed, 19 insertions(+)
+
+--- a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c
++++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c
+@@ -80,12 +80,27 @@ static bool ls_pcie_g4_is_bridge(struct
+       return header_type == PCI_HEADER_TYPE_BRIDGE;
+ }
++static void workaround_A011451(struct ls_pcie_g4 *pcie)
++{
++      struct mobiveil_pcie *mv_pci = &pcie->pci;
++      u32 val;
++
++      /* Set ACK latency timeout */
++      val = csr_readl(mv_pci, GPEX_ACK_REPLAY_TO);
++      val &= ~(ACK_LAT_TO_VAL_MASK << ACK_LAT_TO_VAL_SHIFT);
++      val |= (4 << ACK_LAT_TO_VAL_SHIFT);
++      csr_writel(mv_pci, val, GPEX_ACK_REPLAY_TO);
++}
++
+ static int ls_pcie_g4_host_init(struct mobiveil_pcie *pci)
+ {
+       struct ls_pcie_g4 *pcie = to_ls_pcie_g4(pci);
+       pcie->rev = csr_readb(pci, PCI_REVISION_ID);
++      if (pcie->rev == REV_1_0)
++              workaround_A011451(pcie);
++
+       return 0;
+ }
+--- a/drivers/pci/controller/mobiveil/pcie-mobiveil.h
++++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
+@@ -86,6 +86,10 @@
+ #define PAB_AXI_AMAP_PEX_WIN_H(win)   PAB_REG_ADDR(0x0bac, win)
+ #define PAB_INTP_AXI_PIO_CLASS                0x474
++#define GPEX_ACK_REPLAY_TO            0x438
++#define  ACK_LAT_TO_VAL_MASK          0x1fff
++#define  ACK_LAT_TO_VAL_SHIFT         0
++
+ #define PAB_PEX_AMAP_CTRL(win)                PAB_REG_ADDR(0x4ba0, win)
+ #define  AMAP_CTRL_EN_SHIFT           0
+ #define  AMAP_CTRL_TYPE_SHIFT         1
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0015-PCI-ls_gen4-WA-for-SERROR.patch b/target/linux/layerscape/patches-5.4/812-pcie-0015-PCI-ls_gen4-WA-for-SERROR.patch
new file mode 100644 (file)
index 0000000..77d837d
--- /dev/null
@@ -0,0 +1,28 @@
+From 76b810d5fc0cf60e4c98c135011730f84ebe448d Mon Sep 17 00:00:00 2001
+From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Date: Tue, 28 May 2019 11:17:35 +0800
+Subject: [PATCH] PCI: ls_gen4: WA for SERROR
+
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+---
+ drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c
++++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c
+@@ -242,13 +242,13 @@ static int ls_pcie_g4_read_other_conf(st
+       struct ls_pcie_g4 *pcie = to_ls_pcie_g4(pci);
+       int ret;
+-      if (pcie->rev == REV_1_0 && where == PCI_VENDOR_ID)
++      if (pcie->rev == REV_1_0)
+               ls_pcie_g4_lut_writel(pcie, PCIE_LUT_GCR,
+                                     0 << PCIE_LUT_GCR_RRE);
+       ret = pci_generic_config_read(bus, devfn, where, size, val);
+-      if (pcie->rev == REV_1_0 && where == PCI_VENDOR_ID)
++      if (pcie->rev == REV_1_0)
+               ls_pcie_g4_lut_writel(pcie, PCIE_LUT_GCR,
+                                     1 << PCIE_LUT_GCR_RRE);
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0016-PCI-mobiveil-Add-the-EP-driver-support.patch b/target/linux/layerscape/patches-5.4/812-pcie-0016-PCI-mobiveil-Add-the-EP-driver-support.patch
new file mode 100644 (file)
index 0000000..908f40a
--- /dev/null
@@ -0,0 +1,889 @@
+From 21d86ac5a6c0ede443676cb455e988adcc0e3762 Mon Sep 17 00:00:00 2001
+From: Xiaowei Bao <xiaowei.bao@nxp.com>
+Date: Sat, 5 Jan 2019 16:06:43 +0800
+Subject: [PATCH] PCI: mobiveil: Add the EP driver support
+
+Add the EP driver support for Mobiveil base on endpoint framework.
+
+Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
+[Zhiqiang: Correct the Copyright]
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+---
+ MAINTAINERS                                        |   1 +
+ drivers/pci/controller/mobiveil/Kconfig            |   5 +
+ drivers/pci/controller/mobiveil/Makefile           |   1 +
+ drivers/pci/controller/mobiveil/pcie-mobiveil-ep.c | 568 +++++++++++++++++++++
+ drivers/pci/controller/mobiveil/pcie-mobiveil.c    |  99 +++-
+ drivers/pci/controller/mobiveil/pcie-mobiveil.h    |  68 +++
+ 6 files changed, 734 insertions(+), 8 deletions(-)
+ create mode 100644 drivers/pci/controller/mobiveil/pcie-mobiveil-ep.c
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -12499,6 +12499,7 @@ F:     drivers/ntb/hw/mscc/
+ PCI DRIVER FOR MOBIVEIL PCIE IP
+ M:    Karthikeyan Mitran <m.karthikeyan@mobiveil.co.in>
+ M:    Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
++M:    Xiaowei Bao <xiaowei.bao@nxp.com>
+ L:    linux-pci@vger.kernel.org
+ S:    Supported
+ F:    Documentation/devicetree/bindings/pci/mobiveil-pcie.txt
+--- a/drivers/pci/controller/mobiveil/Kconfig
++++ b/drivers/pci/controller/mobiveil/Kconfig
+@@ -11,6 +11,11 @@ config PCIE_MOBIVEIL_HOST
+       depends on PCI_MSI_IRQ_DOMAIN
+         select PCIE_MOBIVEIL
++config PCIE_MOBIVEIL_EP
++      bool
++      depends on PCI_ENDPOINT
++      select PCIE_MOBIVEIL
++
+ config PCIE_MOBIVEIL_PLAT
+       bool "Mobiveil AXI PCIe controller"
+       depends on ARCH_ZYNQMP || COMPILE_TEST
+--- a/drivers/pci/controller/mobiveil/Makefile
++++ b/drivers/pci/controller/mobiveil/Makefile
+@@ -1,5 +1,6 @@
+ # SPDX-License-Identifier: GPL-2.0
+ obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
+ obj-$(CONFIG_PCIE_MOBIVEIL_HOST) += pcie-mobiveil-host.o
++obj-$(CONFIG_PCIE_MOBIVEIL_EP) += pcie-mobiveil-ep.o
+ obj-$(CONFIG_PCIE_MOBIVEIL_PLAT) += pcie-mobiveil-plat.o
+ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie-layerscape-gen4.o
+--- /dev/null
++++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-ep.c
+@@ -0,0 +1,568 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Mobiveil PCIe Endpoint controller driver
++ *
++ * Copyright 2019 NXP
++ * Author: Xiaowei Bao <xiaowei.bao@nxp.com>
++ */
++
++#include <linux/of.h>
++#include <linux/pci-epc.h>
++#include <linux/pci-epf.h>
++#include <linux/platform_device.h>
++#include "pcie-mobiveil.h"
++
++static void mobiveil_pcie_ep_func_select(struct mobiveil_pcie *pcie, u8 func_no)
++{
++      u32 func_num;
++
++      /*
++       * select to access the config space of func_no by setting func_no
++       * to FUNC_SEL_SHIFT bit of PAB_CTRL register.
++       */
++      func_num = csr_readl(pcie, PAB_CTRL);
++      func_num &= ~(FUNC_SEL_MASK << FUNC_SEL_SHIFT);
++      func_num |= (func_no & FUNC_SEL_MASK) << FUNC_SEL_SHIFT;
++      csr_writel(pcie, func_num, PAB_CTRL);
++}
++
++static void mobiveil_pcie_ep_func_deselect(struct mobiveil_pcie *pcie)
++{
++      u32 func_num;
++
++      /*
++       * clear the FUNC_SEL_SHIFT bits when access other registers except
++       * config space register.
++       */
++      func_num = csr_readl(pcie, PAB_CTRL);
++      func_num &= ~(FUNC_SEL_MASK << FUNC_SEL_SHIFT);
++      csr_writel(pcie, func_num, PAB_CTRL);
++}
++
++static void __mobiveil_pcie_ep_reset_bar(struct mobiveil_pcie *pcie, u8 bar)
++{
++      csr_writel(pcie, bar, GPEX_BAR_SELECT);
++      csr_writel(pcie, 0, GPEX_BAR_SIZE_LDW);
++      csr_writel(pcie, 0, GPEX_BAR_SIZE_UDW);
++}
++
++void mobiveil_pcie_ep_reset_bar(struct mobiveil_pcie *pcie, u8 bar)
++{
++      __mobiveil_pcie_ep_reset_bar(pcie, bar);
++}
++
++static u8 __mobiveil_pcie_ep_find_next_cap(struct mobiveil_pcie *pcie,
++                                         u8 func_no, u8 cap_ptr, u8 cap)
++{
++      u8 cap_id, next_cap_ptr;
++      u16 reg;
++
++      if (!cap_ptr)
++              return 0;
++
++      mobiveil_pcie_ep_func_select(pcie, func_no);
++
++      reg = csr_readw(pcie, cap_ptr);
++      cap_id = (reg & 0x00ff);
++
++      mobiveil_pcie_ep_func_deselect(pcie);
++
++      if (cap_id > PCI_CAP_ID_MAX)
++              return 0;
++
++      if (cap_id == cap)
++              return cap_ptr;
++
++      next_cap_ptr = (reg & 0xff00) >> 8;
++      return __mobiveil_pcie_ep_find_next_cap(pcie, func_no,
++                                              next_cap_ptr, cap);
++}
++
++static u8 mobiveil_pcie_ep_find_capability(struct mobiveil_pcie_ep *ep,
++                                         u8 func_no, u8 cap)
++{
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++      u8 next_cap_ptr;
++      u16 reg;
++
++      mobiveil_pcie_ep_func_select(pcie, func_no);
++
++      reg = csr_readw(pcie, PCI_CAPABILITY_LIST);
++      next_cap_ptr = (reg & 0x00ff);
++
++      mobiveil_pcie_ep_func_deselect(pcie);
++
++      return __mobiveil_pcie_ep_find_next_cap(pcie, func_no,
++                                              next_cap_ptr, cap);
++}
++
++static int mobiveil_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
++                                       struct pci_epf_header *hdr)
++{
++      struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++
++      mobiveil_pcie_ep_func_select(pcie, func_no);
++
++      csr_writew(pcie, hdr->vendorid, PCI_VENDOR_ID);
++      csr_writew(pcie, hdr->deviceid, PCI_DEVICE_ID);
++      csr_writeb(pcie, hdr->revid, PCI_REVISION_ID);
++      csr_writeb(pcie, hdr->progif_code, PCI_CLASS_PROG);
++      csr_writew(pcie, hdr->subclass_code | hdr->baseclass_code << 8,
++                 PCI_CLASS_DEVICE);
++      csr_writeb(pcie, hdr->cache_line_size, PCI_CACHE_LINE_SIZE);
++      csr_writew(pcie, hdr->subsys_vendor_id, PCI_SUBSYSTEM_VENDOR_ID);
++      csr_writew(pcie, hdr->subsys_id, PCI_SUBSYSTEM_ID);
++      csr_writeb(pcie, hdr->interrupt_pin, PCI_INTERRUPT_PIN);
++
++      mobiveil_pcie_ep_func_deselect(pcie);
++
++      return 0;
++}
++
++static void mobiveil_pcie_ep_inbound_win(struct mobiveil_pcie_ep *ep,
++                                       u8 func_no, enum pci_barno bar,
++                                       dma_addr_t cpu_addr)
++{
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++
++      program_ib_windows_ep(pcie, func_no, bar, cpu_addr);
++}
++
++static int mobiveil_pcie_ep_outbound_win(struct mobiveil_pcie_ep *ep,
++                                       phys_addr_t phys_addr,
++                                       u64 pci_addr, u8 func_no,
++                                       size_t size)
++{
++      u32 free_win;
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++
++      free_win = find_first_zero_bit(ep->apio_wins_map, ep->apio_wins);
++      if (free_win >= ep->apio_wins) {
++              dev_err(&pcie->pdev->dev, "No free outbound window\n");
++              return -EINVAL;
++      }
++
++      program_ob_windows_ep(pcie, func_no, free_win, phys_addr,
++                            pci_addr, MEM_WINDOW_TYPE, size);
++
++      set_bit(free_win, ep->apio_wins_map);
++      ep->apio_addr[free_win] = phys_addr;
++
++      return 0;
++}
++
++static void mobiveil_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no,
++                                     struct pci_epf_bar *epf_bar)
++{
++      struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++      enum pci_barno bar = epf_bar->barno;
++
++      if (bar < ep->bar_num) {
++              __mobiveil_pcie_ep_reset_bar(pcie, func_no * ep->bar_num + bar);
++
++              mobiveil_pcie_disable_ib_win_ep(pcie, func_no, bar);
++      }
++}
++
++static int mobiveil_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no,
++                                  struct pci_epf_bar *epf_bar)
++{
++      struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++      enum pci_barno bar = epf_bar->barno;
++      size_t size = epf_bar->size;
++
++      if (bar < ep->bar_num) {
++              mobiveil_pcie_ep_inbound_win(ep, func_no, bar,
++                                           epf_bar->phys_addr);
++
++              csr_writel(pcie, func_no * ep->bar_num + bar,
++                         GPEX_BAR_SELECT);
++              csr_writel(pcie, lower_32_bits(~(size - 1)),
++                         GPEX_BAR_SIZE_LDW);
++              csr_writel(pcie, upper_32_bits(~(size - 1)),
++                         GPEX_BAR_SIZE_UDW);
++      }
++
++      return 0;
++}
++
++static int mobiveil_pcie_find_index(struct mobiveil_pcie_ep *ep,
++                                  phys_addr_t addr,
++                                  u32 *atu_index)
++{
++      u32 index;
++
++      for (index = 0; index < ep->apio_wins; index++) {
++              if (ep->apio_addr[index] != addr)
++                      continue;
++              *atu_index = index;
++              return 0;
++      }
++
++      return -EINVAL;
++}
++
++static void mobiveil_pcie_ep_unmap_addr(struct pci_epc *epc, u8 func_no,
++                                      phys_addr_t addr)
++{
++      int ret;
++      u32 atu_index;
++      struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++
++      ret = mobiveil_pcie_find_index(ep, addr, &atu_index);
++      if (ret < 0)
++              return;
++
++      mobiveil_pcie_disable_ob_win(pcie, atu_index);
++      clear_bit(atu_index, ep->apio_wins_map);
++}
++
++static int mobiveil_pcie_ep_map_addr(struct pci_epc *epc, u8 func_no,
++                                   phys_addr_t addr,
++                                   u64 pci_addr, size_t size)
++{
++      int ret;
++      struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++
++      ret = mobiveil_pcie_ep_outbound_win(ep, addr, pci_addr, func_no, size);
++      if (ret) {
++              dev_err(&pcie->pdev->dev, "Failed to enable address\n");
++              return ret;
++      }
++
++      return 0;
++}
++
++static int mobiveil_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no)
++{
++      struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++      u32 val, reg;
++      u8 msi_cap;
++
++      msi_cap = mobiveil_pcie_ep_find_capability(ep, func_no,
++                                                 PCI_CAP_ID_MSI);
++      if (!msi_cap)
++              return -EINVAL;
++
++      mobiveil_pcie_ep_func_select(pcie, func_no);
++
++      reg = msi_cap + PCI_MSI_FLAGS;
++      val = csr_readw(pcie, reg);
++
++      mobiveil_pcie_ep_func_deselect(pcie);
++
++      if (!(val & PCI_MSI_FLAGS_ENABLE))
++              return -EINVAL;
++
++      val = (val & PCI_MSI_FLAGS_QSIZE) >> 4;
++
++      return val;
++}
++
++static int mobiveil_pcie_ep_set_msi(struct pci_epc *epc,
++                                  u8 func_no, u8 interrupts)
++{
++      struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++      u32 val, reg;
++      u8 msi_cap;
++
++      msi_cap = mobiveil_pcie_ep_find_capability(ep, func_no,
++                                                 PCI_CAP_ID_MSI);
++      if (!msi_cap)
++              return -EINVAL;
++
++      mobiveil_pcie_ep_func_select(pcie, func_no);
++
++      reg = msi_cap + PCI_MSI_FLAGS;
++      val = csr_readw(pcie, reg);
++      val &= ~PCI_MSI_FLAGS_QMASK;
++      val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK;
++      csr_writew(pcie, val, reg);
++
++      mobiveil_pcie_ep_func_deselect(pcie);
++
++      return 0;
++}
++
++static int mobiveil_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
++{
++      struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++      u32 val, reg;
++      u8 msix_cap;
++
++      msix_cap = mobiveil_pcie_ep_find_capability(ep, func_no,
++                                                  PCI_CAP_ID_MSIX);
++      if (!msix_cap)
++              return -EINVAL;
++
++      mobiveil_pcie_ep_func_select(pcie, func_no);
++
++      reg = msix_cap + PCI_MSIX_FLAGS;
++      val = csr_readw(pcie, reg);
++
++      mobiveil_pcie_ep_func_deselect(pcie);
++
++      if (!(val & PCI_MSIX_FLAGS_ENABLE))
++              return -EINVAL;
++
++      val &= PCI_MSIX_FLAGS_QSIZE;
++
++      return val;
++}
++
++static int mobiveil_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no,
++                                   u16 interrupts)
++{
++      struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++      u32 val, reg;
++      u8 msix_cap;
++
++      msix_cap = mobiveil_pcie_ep_find_capability(ep, func_no,
++                                                  PCI_CAP_ID_MSIX);
++      if (!msix_cap)
++              return -EINVAL;
++
++      mobiveil_pcie_ep_func_select(pcie, func_no);
++
++      reg = msix_cap + PCI_MSIX_FLAGS;
++      val = csr_readw(pcie, reg);
++      val &= ~PCI_MSIX_FLAGS_QSIZE;
++      val |= interrupts;
++      csr_writew(pcie, val, reg);
++
++      mobiveil_pcie_ep_func_deselect(pcie);
++
++      return 0;
++}
++
++static int mobiveil_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no,
++                                    enum pci_epc_irq_type type,
++                                    u16 interrupt_num)
++{
++      struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
++
++      if (!ep->ops->raise_irq)
++              return -EINVAL;
++
++      return ep->ops->raise_irq(ep, func_no, type, interrupt_num);
++}
++
++static const struct pci_epc_features*
++mobiveil_pcie_ep_get_features(struct pci_epc *epc, u8 func_no)
++{
++      struct mobiveil_pcie_ep *ep = epc_get_drvdata(epc);
++
++      if (!ep->ops->get_features)
++              return NULL;
++
++      return ep->ops->get_features(ep);
++}
++
++static const struct pci_epc_ops epc_ops = {
++      .write_header           = mobiveil_pcie_ep_write_header,
++      .set_bar                = mobiveil_pcie_ep_set_bar,
++      .clear_bar              = mobiveil_pcie_ep_clear_bar,
++      .map_addr               = mobiveil_pcie_ep_map_addr,
++      .unmap_addr             = mobiveil_pcie_ep_unmap_addr,
++      .set_msi                = mobiveil_pcie_ep_set_msi,
++      .get_msi                = mobiveil_pcie_ep_get_msi,
++      .set_msix               = mobiveil_pcie_ep_set_msix,
++      .get_msix               = mobiveil_pcie_ep_get_msix,
++      .raise_irq              = mobiveil_pcie_ep_raise_irq,
++      .get_features           = mobiveil_pcie_ep_get_features,
++};
++
++int mobiveil_pcie_ep_raise_legacy_irq(struct mobiveil_pcie_ep *ep, u8 func_no)
++{
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++
++      dev_err(&pcie->pdev->dev, "EP cannot trigger legacy IRQs\n");
++
++      return -EINVAL;
++}
++
++int mobiveil_pcie_ep_raise_msi_irq(struct mobiveil_pcie_ep *ep, u8 func_no,
++                                 u8 interrupt_num)
++{
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++      struct pci_epc *epc = ep->epc;
++      u16 msg_ctrl, msg_data;
++      u32 msg_addr_lower, msg_addr_upper, reg;
++      u64 msg_addr;
++      bool has_upper;
++      int ret;
++      u8 msi_cap;
++
++      msi_cap = mobiveil_pcie_ep_find_capability(ep, func_no,
++                                                 PCI_CAP_ID_MSI);
++      if (!msi_cap)
++              return -EINVAL;
++
++      mobiveil_pcie_ep_func_select(pcie, func_no);
++
++      reg = msi_cap + PCI_MSI_FLAGS;
++      msg_ctrl = csr_readw(pcie, reg);
++      has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT);
++      reg = msi_cap + PCI_MSI_ADDRESS_LO;
++      msg_addr_lower = csr_readl(pcie, reg);
++      if (has_upper) {
++              reg = msi_cap + PCI_MSI_ADDRESS_HI;
++              msg_addr_upper = csr_readl(pcie, reg);
++              reg = msi_cap + PCI_MSI_DATA_64;
++              msg_data = csr_readw(pcie, reg);
++      } else {
++              msg_addr_upper = 0;
++              reg = msi_cap + PCI_MSI_DATA_32;
++              msg_data = csr_readw(pcie, reg);
++      }
++      msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower;
++
++      mobiveil_pcie_ep_func_deselect(pcie);
++
++      ret = mobiveil_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys,
++                                      msg_addr, epc->mem->page_size);
++      if (ret)
++              return ret;
++
++      writel(msg_data | (interrupt_num - 1), ep->msi_mem);
++
++      mobiveil_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys);
++
++      return 0;
++}
++
++int mobiveil_pcie_ep_raise_msix_irq(struct mobiveil_pcie_ep *ep, u8 func_no,
++                                  u16 interrupt_num)
++{
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++      struct pci_epc *epc = ep->epc;
++      u32 msg_addr_upper, msg_addr_lower;
++      u32 msg_data;
++      u64 msg_addr;
++      u8 msix_cap;
++      int ret;
++
++      msix_cap = mobiveil_pcie_ep_find_capability(ep, func_no,
++                                                 PCI_CAP_ID_MSIX);
++      if (!msix_cap)
++              return -EINVAL;
++
++      mobiveil_pcie_ep_func_deselect(pcie);
++
++      msg_addr_lower = csr_readl(pcie, PAB_MSIX_TABLE_PBA_ACCESS +
++                                 PCI_MSIX_ENTRY_LOWER_ADDR +
++                                 (interrupt_num - 1) * PCI_MSIX_ENTRY_SIZE);
++      msg_addr_upper = csr_readl(pcie, PAB_MSIX_TABLE_PBA_ACCESS +
++                                 PCI_MSIX_ENTRY_UPPER_ADDR +
++                                 (interrupt_num - 1) * PCI_MSIX_ENTRY_SIZE);
++      msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower;
++      msg_data = csr_readl(pcie, PAB_MSIX_TABLE_PBA_ACCESS +
++                           PCI_MSIX_ENTRY_DATA +
++                           (interrupt_num - 1) * PCI_MSIX_ENTRY_SIZE);
++
++      ret = mobiveil_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys,
++                                      msg_addr, epc->mem->page_size);
++      if (ret)
++              return ret;
++
++      writel(msg_data, ep->msi_mem);
++
++      mobiveil_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys);
++
++      return 0;
++}
++
++void mobiveil_pcie_ep_exit(struct mobiveil_pcie_ep *ep)
++{
++      struct pci_epc *epc = ep->epc;
++
++      pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
++                            epc->mem->page_size);
++
++      pci_epc_mem_exit(epc);
++}
++
++int mobiveil_pcie_ep_init(struct mobiveil_pcie_ep *ep)
++{
++      int ret;
++      void *addr;
++      struct pci_epc *epc;
++      struct mobiveil_pcie *pcie = to_mobiveil_pcie_from_ep(ep);
++      struct device *dev = &pcie->pdev->dev;
++      struct device_node *np = dev->of_node;
++
++      if (!pcie->csr_axi_slave_base) {
++              dev_err(dev, "csr_base is not populated\n");
++              return -EINVAL;
++      }
++
++      ret = of_property_read_u32(np, "apio-wins", &ep->apio_wins);
++      if (ret < 0) {
++              dev_err(dev, "Unable to read apio-wins property\n");
++              return ret;
++      }
++
++      if (ep->apio_wins > MAX_IATU_OUT) {
++              dev_err(dev, "Invalid apio-wins\n");
++              return -EINVAL;
++      }
++      ep->apio_wins_map = devm_kcalloc(dev,
++                                       BITS_TO_LONGS(ep->apio_wins),
++                                       sizeof(long),
++                                       GFP_KERNEL);
++      if (!ep->apio_wins_map)
++              return -ENOMEM;
++
++      addr = devm_kcalloc(dev, ep->apio_wins, sizeof(phys_addr_t),
++                          GFP_KERNEL);
++      if (!addr)
++              return -ENOMEM;
++
++      ep->apio_addr = addr;
++
++      mobiveil_pcie_enable_bridge_pio(pcie);
++      mobiveil_pcie_enable_engine_apio(pcie);
++      mobiveil_pcie_enable_engine_ppio(pcie);
++      mobiveil_pcie_enable_msi_ep(pcie);
++
++      epc = devm_pci_epc_create(dev, &epc_ops);
++      if (IS_ERR(epc)) {
++              dev_err(dev, "Failed to create epc device\n");
++              return PTR_ERR(epc);
++      }
++
++      ep->epc = epc;
++      epc_set_drvdata(epc, ep);
++
++      ret = of_property_read_u8(np, "max-functions", &epc->max_functions);
++      if (ret < 0)
++              epc->max_functions = 1;
++
++      if (ep->ops->ep_init)
++              ep->ops->ep_init(ep);
++
++      ret = __pci_epc_mem_init(epc, ep->phys_base, ep->addr_size,
++                               ep->page_size);
++      if (ret < 0) {
++              dev_err(dev, "Failed to initialize address space\n");
++              return ret;
++      }
++
++      ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys,
++                                           epc->mem->page_size);
++      if (!ep->msi_mem) {
++              dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n");
++              return -ENOMEM;
++      }
++
++      return 0;
++}
+--- a/drivers/pci/controller/mobiveil/pcie-mobiveil.c
++++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.c
+@@ -168,18 +168,12 @@ void program_ib_windows(struct mobiveil_
+ /*
+  * routine to program the outbound windows
+  */
+-void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
+-                      u64 pci_addr, u32 type, u64 size)
++void __program_ob_windows(struct mobiveil_pcie *pcie, u8 func_no, int win_num,
++                        u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
+ {
+       u32 value;
+       u64 size64 = ~(size - 1);
+-      if (win_num >= pcie->apio_wins) {
+-              dev_err(&pcie->pdev->dev,
+-                      "ERROR: max outbound windows reached !\n");
+-              return;
+-      }
+-
+       /*
+        * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
+        * to 4 KB in PAB_AXI_AMAP_CTRL register
+@@ -192,6 +186,7 @@ void program_ob_windows(struct mobiveil_
+       csr_writel(pcie, upper_32_bits(size64), PAB_EXT_AXI_AMAP_SIZE(win_num));
++      csr_writel(pcie, func_no, PAB_AXI_AMAP_PCI_HDR_PARAM(win_num));
+       /*
+        * program AXI window base with appropriate value in
+        * PAB_AXI_AMAP_AXI_WIN0 register
+@@ -205,10 +200,98 @@ void program_ob_windows(struct mobiveil_
+                  PAB_AXI_AMAP_PEX_WIN_L(win_num));
+       csr_writel(pcie, upper_32_bits(pci_addr),
+                  PAB_AXI_AMAP_PEX_WIN_H(win_num));
++}
++
++void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
++                      u64 pci_addr, u32 type, u64 size)
++{
++      if (win_num >= pcie->apio_wins) {
++              dev_err(&pcie->pdev->dev,
++                      "ERROR: max outbound windows reached !\n");
++              return;
++      }
++
++      __program_ob_windows(pcie, 0, win_num, cpu_addr,
++                           pci_addr, type, size);
+       pcie->ob_wins_configured++;
+ }
++void program_ob_windows_ep(struct mobiveil_pcie *pcie, u8 func_no, int win_num,
++                         u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
++{
++      if (size & (size - 1))
++              size = 1 << (1 + ilog2(size));
++
++      __program_ob_windows(pcie, func_no, win_num, cpu_addr,
++                           pci_addr, type, size);
++}
++
++void program_ib_windows_ep(struct mobiveil_pcie *pcie, u8 func_no,
++                         int bar, u64 phys)
++{
++      csr_writel(pcie, upper_32_bits(phys),
++                 PAB_EXT_PEX_BAR_AMAP(func_no, bar));
++      csr_writel(pcie, lower_32_bits(phys) | PEX_BAR_AMAP_EN,
++                 PAB_PEX_BAR_AMAP(func_no, bar));
++}
++
++void mobiveil_pcie_disable_ib_win_ep(struct mobiveil_pcie *pcie,
++                                   u8 func_no, u8 bar)
++{
++      u32 val;
++
++      val = csr_readl(pcie, PAB_PEX_BAR_AMAP(func_no, bar));
++      val &= ~(1 << 0);
++      csr_writel(pcie, val, PAB_PEX_BAR_AMAP(func_no, bar));
++}
++
++void mobiveil_pcie_disable_ob_win(struct mobiveil_pcie *pcie, int win_num)
++{
++      u32 val;
++
++      val = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
++      val &= ~(1 << WIN_ENABLE_SHIFT);
++      csr_writel(pcie, val, PAB_AXI_AMAP_CTRL(win_num));
++}
++
++void mobiveil_pcie_enable_bridge_pio(struct mobiveil_pcie *pcie)
++{
++      u32 val;
++
++      val = csr_readl(pcie, PAB_CTRL);
++      val |= 1 << AMBA_PIO_ENABLE_SHIFT;
++      val |= 1 << PEX_PIO_ENABLE_SHIFT;
++      csr_writel(pcie, val, PAB_CTRL);
++}
++
++void mobiveil_pcie_enable_engine_apio(struct mobiveil_pcie *pcie)
++{
++      u32 val;
++
++      val = csr_readl(pcie, PAB_AXI_PIO_CTRL);
++      val |= APIO_EN_MASK;
++      csr_writel(pcie, val, PAB_AXI_PIO_CTRL);
++}
++
++void mobiveil_pcie_enable_engine_ppio(struct mobiveil_pcie *pcie)
++{
++      u32 val;
++
++      val = csr_readl(pcie, PAB_PEX_PIO_CTRL);
++      val |= 1 << PIO_ENABLE_SHIFT;
++      csr_writel(pcie, val, PAB_PEX_PIO_CTRL);
++}
++
++void mobiveil_pcie_enable_msi_ep(struct mobiveil_pcie *pcie)
++{
++      u32 val;
++
++      val =  csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
++      val |= PAB_INTP_PAMR;
++      csr_writel(pcie, val, PAB_INTP_AMBA_MISC_ENB);
++}
++
+ int mobiveil_bringup_link(struct mobiveil_pcie *pcie)
+ {
+       int retries;
+--- a/drivers/pci/controller/mobiveil/pcie-mobiveil.h
++++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
+@@ -15,8 +15,12 @@
+ #include <linux/pci.h>
+ #include <linux/irq.h>
+ #include <linux/msi.h>
++#include <linux/pci-epc.h>
++#include <linux/pci-epf.h>
++
+ #include "../../pci.h"
++#define MAX_IATU_OUT                  256
+ /* register offsets and bit positions */
+ /*
+@@ -42,6 +46,9 @@
+ #define  PAGE_SEL_MASK                        0x3f
+ #define  PAGE_LO_MASK                 0x3ff
+ #define  PAGE_SEL_OFFSET_SHIFT                10
++#define  FUNC_SEL_SHIFT                       19
++#define  FUNC_SEL_MASK                        0x1ff
++#define  MSI_SW_CTRL_EN                       BIT(29)
+ #define PAB_ACTIVITY_STAT             0x81c
+@@ -52,6 +59,7 @@
+ #define  PIO_ENABLE_SHIFT             0
+ #define PAB_INTP_AMBA_MISC_ENB                0x0b0c
++#define  PAB_INTP_PAMR                        BIT(0)
+ #define PAB_INTP_AMBA_MISC_STAT               0x0b1c
+ #define  PAB_INTP_RESET                       BIT(1)
+ #define  PAB_INTP_MSI                 BIT(3)
+@@ -72,6 +80,8 @@
+ #define  WIN_TYPE_MASK                        0x3
+ #define  WIN_SIZE_MASK                        0xfffffc00
++#define PAB_AXI_AMAP_PCI_HDR_PARAM(win)       PAB_EXT_REG_ADDR(0x5ba0, win)
++
+ #define PAB_EXT_AXI_AMAP_SIZE(win)    PAB_EXT_REG_ADDR(0xbaf0, win)
+ #define PAB_EXT_AXI_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0x80a0, win)
+@@ -101,6 +111,18 @@
+ #define PAB_PEX_AMAP_PEX_WIN_L(win)   PAB_REG_ADDR(0x4ba8, win)
+ #define PAB_PEX_AMAP_PEX_WIN_H(win)   PAB_REG_ADDR(0x4bac, win)
++/* PPIO WINs EP mode */
++#define PAB_PEX_BAR_AMAP(func, bar)   (0x1ba0 + 0x20 * func + 4 * bar)
++#define PAB_EXT_PEX_BAR_AMAP(func, bar)       (0x84a0 + 0x20 * func + 4 * bar)
++#define PEX_BAR_AMAP_EN                       BIT(0)
++
++#define PAB_MSIX_TABLE_PBA_ACCESS     0xD000
++
++#define GPEX_BAR_ENABLE                       0x4D4
++#define GPEX_BAR_SIZE_LDW             0x4D8
++#define GPEX_BAR_SIZE_UDW             0x4DC
++#define GPEX_BAR_SELECT                       0x4E0
++
+ /* starting offset of INTX bits in status register */
+ #define PAB_INTX_START                        5
+@@ -138,6 +160,7 @@
+       ((off >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK)
+ struct mobiveil_pcie;
++struct mobiveil_pcie_ep;
+ struct mobiveil_msi {                 /* MSI information */
+       struct mutex lock;              /* protect bitmap variable */
+@@ -170,6 +193,28 @@ struct mobiveil_pab_ops {
+       int (*host_init)(struct mobiveil_pcie *pcie);
+ };
++struct mobiveil_pcie_ep_ops {
++      void (*ep_init)(struct mobiveil_pcie_ep *ep);
++      int (*raise_irq)(struct mobiveil_pcie_ep *ep, u8 func_no,
++                       enum pci_epc_irq_type type, u16 interrupt_num);
++      const struct pci_epc_features* (*get_features)
++                                     (struct mobiveil_pcie_ep *ep);
++};
++
++struct mobiveil_pcie_ep {
++      struct pci_epc *epc;
++      const struct mobiveil_pcie_ep_ops *ops;
++      phys_addr_t phys_base;
++      size_t addr_size;
++      size_t page_size;
++      phys_addr_t *apio_addr;
++      unsigned long *apio_wins_map;
++      u32 apio_wins;
++      void __iomem *msi_mem;
++      phys_addr_t msi_mem_phys;
++      u8 bar_num;
++};
++
+ struct mobiveil_pcie {
+       struct platform_device *pdev;
+       struct list_head *resources;
+@@ -183,8 +228,12 @@ struct mobiveil_pcie {
+       const struct mobiveil_pab_ops *ops;
+       struct root_port rp;
+       struct pci_host_bridge *bridge;
++      struct mobiveil_pcie_ep ep;
+ };
++#define to_mobiveil_pcie_from_ep(endpoint)   \
++                          container_of((endpoint), struct mobiveil_pcie, ep)
++
+ int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie);
+ int mobiveil_host_init(struct mobiveil_pcie *pcie, bool reinit);
+ bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie);
+@@ -226,4 +275,23 @@ static inline void csr_writeb(struct mob
+       csr_write(pcie, val, off, 0x1);
+ }
++void program_ib_windows_ep(struct mobiveil_pcie *pcie, u8 func_no,
++                         int bar, u64 phys);
++void program_ob_windows_ep(struct mobiveil_pcie *pcie, u8 func_num, int win_num,
++                         u64 cpu_addr, u64 pci_addr, u32 type, u64 size);
++void mobiveil_pcie_disable_ib_win_ep(struct mobiveil_pcie *pci,
++                                   u8 func_no, u8 bar);
++void mobiveil_pcie_disable_ob_win(struct mobiveil_pcie *pcie, int win_num);
++int mobiveil_pcie_ep_init(struct mobiveil_pcie_ep *ep);
++int mobiveil_pcie_ep_raise_legacy_irq(struct mobiveil_pcie_ep *ep, u8 func_no);
++int mobiveil_pcie_ep_raise_msi_irq(struct mobiveil_pcie_ep *ep, u8 func_no,
++                                 u8 interrupt_num);
++int mobiveil_pcie_ep_raise_msix_irq(struct mobiveil_pcie_ep *ep, u8 func_no,
++                                  u16 interrupt_num);
++void mobiveil_pcie_ep_reset_bar(struct mobiveil_pcie *pci, u8 bar);
++u8 mobiveil_pcie_ep_get_bar_num(struct mobiveil_pcie_ep *ep, u8 func_no);
++void mobiveil_pcie_enable_bridge_pio(struct mobiveil_pcie *pci);
++void mobiveil_pcie_enable_engine_apio(struct mobiveil_pcie *pci);
++void mobiveil_pcie_enable_engine_ppio(struct mobiveil_pcie *pci);
++void mobiveil_pcie_enable_msi_ep(struct mobiveil_pcie *pci);
+ #endif /* _PCIE_MOBIVEIL_H */
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0017-PCI-mobiveil-Add-PCIe-Gen4-EP-driver-for-NXP-Layersc.patch b/target/linux/layerscape/patches-5.4/812-pcie-0017-PCI-mobiveil-Add-PCIe-Gen4-EP-driver-for-NXP-Layersc.patch
new file mode 100644 (file)
index 0000000..16f9bc3
--- /dev/null
@@ -0,0 +1,217 @@
+From 9e1faafe9d650a06e212ad5a3b8ed0e7eb7f0aa2 Mon Sep 17 00:00:00 2001
+From: Xiaowei Bao <xiaowei.bao@nxp.com>
+Date: Sat, 5 Jan 2019 16:30:42 +0800
+Subject: [PATCH] PCI: mobiveil: Add PCIe Gen4 EP driver for NXP Layerscape
+ SoCs
+
+This PCIe controller is based on the Mobiveil GPEX IP, it work in EP
+mode if select this config opteration.
+
+Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
+[Zhiqiang: Correct the Copyright]
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+[drop maintainer change]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/pci/controller/mobiveil/Kconfig            |  17 ++-
+ drivers/pci/controller/mobiveil/Makefile           |   1 +
+ .../controller/mobiveil/pcie-layerscape-gen4-ep.c  | 156 +++++++++++++++++++++
+ 3 files changed, 171 insertions(+), 3 deletions(-)
+ create mode 100644 drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c
+
+--- a/drivers/pci/controller/mobiveil/Kconfig
++++ b/drivers/pci/controller/mobiveil/Kconfig
+@@ -27,13 +27,24 @@ config PCIE_MOBIVEIL_PLAT
+         for address translation and it is a PCIe Gen4 IP.
+ config PCIE_LAYERSCAPE_GEN4
+-      bool "Freescale Layerscape PCIe Gen4 controller"
++      bool "Freescale Layerscpe PCIe Gen4 controller in RC mode"
+       depends on PCI
+       depends on OF && (ARM64 || ARCH_LAYERSCAPE)
+       depends on PCI_MSI_IRQ_DOMAIN
+       select PCIE_MOBIVEIL_HOST
+       help
+         Say Y here if you want PCIe Gen4 controller support on
+-        Layerscape SoCs. The PCIe controller can work in RC or
+-        EP mode according to RCW[HOST_AGT_PEX] setting.
++        Layerscape SoCs. And the PCIe controller work in RC mode
++        by setting the RCW[HOST_AGT_PEX] to 0.
++
++config PCIE_LAYERSCAPE_GEN4_EP
++      bool "Freescale Layerscpe PCIe Gen4 controller in EP mode"
++      depends on PCI
++      depends on OF && (ARM64 || ARCH_LAYERSCAPE)
++      depends on PCI_ENDPOINT
++      select PCIE_MOBIVEIL_EP
++      help
++        Say Y here if you want PCIe Gen4 controller support on
++        Layerscape SoCs. And the PCIe controller work in EP mode
++        by setting the RCW[HOST_AGT_PEX] to 1.
+ endmenu
+--- a/drivers/pci/controller/mobiveil/Makefile
++++ b/drivers/pci/controller/mobiveil/Makefile
+@@ -4,3 +4,4 @@ obj-$(CONFIG_PCIE_MOBIVEIL_HOST) += pcie
+ obj-$(CONFIG_PCIE_MOBIVEIL_EP) += pcie-mobiveil-ep.o
+ obj-$(CONFIG_PCIE_MOBIVEIL_PLAT) += pcie-mobiveil-plat.o
+ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie-layerscape-gen4.o
++obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4_EP) += pcie-layerscape-gen4-ep.o
+--- /dev/null
++++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c
+@@ -0,0 +1,156 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * PCIe controller EP driver for Freescale Layerscape SoCs
++ *
++ * Copyright 2019 NXP
++ *
++ * Author: Xiaowei Bao <xiaowei.bao@nxp.com>
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/of_pci.h>
++#include <linux/of_platform.h>
++#include <linux/of_address.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <linux/resource.h>
++
++#include "pcie-mobiveil.h"
++
++#define PCIE_LX2_BAR_NUM      4
++
++#define to_ls_pcie_g4_ep(x)   dev_get_drvdata((x)->dev)
++
++struct ls_pcie_g4_ep {
++      struct mobiveil_pcie            *mv_pci;
++};
++
++static const struct of_device_id ls_pcie_g4_ep_of_match[] = {
++      { .compatible = "fsl,lx2160a-pcie-ep",},
++      { },
++};
++
++static const struct pci_epc_features ls_pcie_g4_epc_features = {
++      .linkup_notifier = false,
++      .msi_capable = true,
++      .msix_capable = true,
++      .reserved_bar = (1 << BAR_4) | (1 << BAR_5),
++};
++
++static const struct pci_epc_features*
++ls_pcie_g4_ep_get_features(struct mobiveil_pcie_ep *ep)
++{
++      return &ls_pcie_g4_epc_features;
++}
++
++static void ls_pcie_g4_ep_init(struct mobiveil_pcie_ep *ep)
++{
++      struct mobiveil_pcie *mv_pci = to_mobiveil_pcie_from_ep(ep);
++      int win_idx;
++      u8 bar;
++
++      ep->bar_num = PCIE_LX2_BAR_NUM;
++
++      for (bar = BAR_0; bar < ep->epc->max_functions * ep->bar_num; bar++)
++              mobiveil_pcie_ep_reset_bar(mv_pci, bar);
++
++      for (win_idx = 0; win_idx < ep->apio_wins; win_idx++)
++              mobiveil_pcie_disable_ob_win(mv_pci, win_idx);
++}
++
++static int ls_pcie_g4_ep_raise_irq(struct mobiveil_pcie_ep *ep, u8 func_no,
++                                 enum pci_epc_irq_type type,
++                                 u16 interrupt_num)
++{
++      struct mobiveil_pcie *mv_pci = to_mobiveil_pcie_from_ep(ep);
++
++      switch (type) {
++      case PCI_EPC_IRQ_LEGACY:
++              return mobiveil_pcie_ep_raise_legacy_irq(ep, func_no);
++      case PCI_EPC_IRQ_MSI:
++              return mobiveil_pcie_ep_raise_msi_irq(ep, func_no,
++                                                    interrupt_num);
++      case PCI_EPC_IRQ_MSIX:
++              return mobiveil_pcie_ep_raise_msix_irq(ep, func_no,
++                                                     interrupt_num);
++      default:
++              dev_err(&mv_pci->pdev->dev, "UNKNOWN IRQ type\n");
++      }
++
++      return 0;
++}
++
++static const struct mobiveil_pcie_ep_ops pcie_ep_ops = {
++      .ep_init = ls_pcie_g4_ep_init,
++      .raise_irq = ls_pcie_g4_ep_raise_irq,
++      .get_features = ls_pcie_g4_ep_get_features,
++};
++
++static int __init ls_pcie_gen4_add_pcie_ep(struct ls_pcie_g4_ep *ls_ep,
++                                         struct platform_device *pdev)
++{
++      struct mobiveil_pcie *mv_pci = ls_ep->mv_pci;
++      struct device *dev = &pdev->dev;
++      struct mobiveil_pcie_ep *ep;
++      struct resource *res;
++      int ret;
++
++      ep = &mv_pci->ep;
++      ep->ops = &pcie_ep_ops;
++
++      res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
++      if (!res)
++              return -EINVAL;
++
++      ep->phys_base = res->start;
++      ep->addr_size = resource_size(res);
++
++      ret = mobiveil_pcie_ep_init(ep);
++      if (ret) {
++              dev_err(dev, "failed to initialize layerscape endpoint\n");
++              return ret;
++      }
++
++      return 0;
++}
++
++static int __init ls_pcie_g4_ep_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct mobiveil_pcie *mv_pci;
++      struct ls_pcie_g4_ep *ls_ep;
++      struct resource *res;
++      int ret;
++
++      ls_ep = devm_kzalloc(dev, sizeof(*ls_ep), GFP_KERNEL);
++      if (!ls_ep)
++              return -ENOMEM;
++
++      mv_pci = devm_kzalloc(dev, sizeof(*mv_pci), GFP_KERNEL);
++      if (!mv_pci)
++              return -ENOMEM;
++
++      res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
++      mv_pci->csr_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
++      if (IS_ERR(mv_pci->csr_axi_slave_base))
++              return PTR_ERR(mv_pci->csr_axi_slave_base);
++
++      mv_pci->pdev = pdev;
++      ls_ep->mv_pci = mv_pci;
++
++      platform_set_drvdata(pdev, ls_ep);
++
++      ret = ls_pcie_gen4_add_pcie_ep(ls_ep, pdev);
++
++      return ret;
++}
++
++static struct platform_driver ls_pcie_g4_ep_driver = {
++      .driver = {
++              .name = "layerscape-pcie-gen4-ep",
++              .of_match_table = ls_pcie_g4_ep_of_match,
++              .suppress_bind_attrs = true,
++      },
++};
++builtin_platform_driver_probe(ls_pcie_g4_ep_driver, ls_pcie_g4_ep_probe);
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0018-PCI-mobiveil-Add-workaround-for-unsupported-request-.patch b/target/linux/layerscape/patches-5.4/812-pcie-0018-PCI-mobiveil-Add-workaround-for-unsupported-request-.patch
new file mode 100644 (file)
index 0000000..a08edfa
--- /dev/null
@@ -0,0 +1,51 @@
+From 7cc1ca9e3a87027dbe6598a0c50cb466fc5861e4 Mon Sep 17 00:00:00 2001
+From: Xiaowei Bao <xiaowei.bao@nxp.com>
+Date: Tue, 22 Jan 2019 19:19:30 +0800
+Subject: [PATCH] PCI: mobiveil: Add workaround for unsupported request error
+
+Errata: unsupported request error on inbound posted write
+transaction, PCIe controller reports advisory error instead
+of uncorrectable error message to RC.
+
+Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+---
+ drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c | 13 +++++++++++++
+ drivers/pci/controller/mobiveil/pcie-mobiveil.h           |  4 ++++
+ 2 files changed, 17 insertions(+)
+
+--- a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c
++++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c
+@@ -49,6 +49,19 @@ static void ls_pcie_g4_ep_init(struct mo
+       struct mobiveil_pcie *mv_pci = to_mobiveil_pcie_from_ep(ep);
+       int win_idx;
+       u8 bar;
++      u32 val;
++
++      /*
++       * Errata: unsupported request error on inbound posted write
++       * transaction, PCIe controller reports advisory error instead
++       * of uncorrectable error message to RC.
++       * workaround: set the bit20(unsupported_request_Error_severity) with
++       * value 1 in uncorrectable_Error_Severity_Register, make the
++       * unsupported request error generate the fatal error.
++       */
++      val =  csr_readl(mv_pci, CFG_UNCORRECTABLE_ERROR_SEVERITY);
++      val |= 1 << UNSUPPORTED_REQUEST_ERROR_SHIFT;
++      csr_writel(mv_pci, val, CFG_UNCORRECTABLE_ERROR_SEVERITY);
+       ep->bar_num = PCIE_LX2_BAR_NUM;
+--- a/drivers/pci/controller/mobiveil/pcie-mobiveil.h
++++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
+@@ -123,6 +123,10 @@
+ #define GPEX_BAR_SIZE_UDW             0x4DC
+ #define GPEX_BAR_SELECT                       0x4E0
++#define CFG_UNCORRECTABLE_ERROR_SEVERITY      0x10c
++#define UNSUPPORTED_REQUEST_ERROR_SHIFT               20
++#define CFG_UNCORRECTABLE_ERROR_MASK          0x108
++
+ /* starting offset of INTX bits in status register */
+ #define PAB_INTX_START                        5
diff --git a/target/linux/layerscape/patches-5.4/812-pcie-0019-misc-pci_endpoint_test-Add-the-layerscape-PCIe-GEN4-.patch b/target/linux/layerscape/patches-5.4/812-pcie-0019-misc-pci_endpoint_test-Add-the-layerscape-PCIe-GEN4-.patch
new file mode 100644 (file)
index 0000000..7eb6bf7
--- /dev/null
@@ -0,0 +1,32 @@
+From 19d95534071c0bc330cce57d26391d804b24257c Mon Sep 17 00:00:00 2001
+From: Xiaowei Bao <xiaowei.bao@nxp.com>
+Date: Mon, 18 Feb 2019 16:12:42 +0800
+Subject: [PATCH] misc: pci_endpoint_test: Add the layerscape PCIe GEN4 EP
+ device support
+
+Add the layerscape PCIE GEN4 EP device support in pci_endpoint_test driver.
+
+Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+---
+ drivers/misc/pci_endpoint_test.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/misc/pci_endpoint_test.c
++++ b/drivers/misc/pci_endpoint_test.c
+@@ -65,6 +65,7 @@
+ #define PCI_ENDPOINT_TEST_IRQ_NUMBER          0x28
+ #define PCI_DEVICE_ID_TI_AM654                        0xb00c
++#define PCI_DEVICE_ID_LX2160A                 0x8d80
+ #define is_am654_pci_dev(pdev)                \
+               ((pdev)->device == PCI_DEVICE_ID_TI_AM654)
+@@ -799,6 +800,7 @@ static const struct pci_device_id pci_en
+       { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) },
+       { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) },
+       { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) },
++      { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LX2160A) },
+       { PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) },
+       { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
+         .driver_data = (kernel_ulong_t)&am654_data
diff --git a/target/linux/layerscape/patches-5.4/813-pm-0001-soc-fsl-add-RCPM-driver.patch b/target/linux/layerscape/patches-5.4/813-pm-0001-soc-fsl-add-RCPM-driver.patch
new file mode 100644 (file)
index 0000000..533534d
--- /dev/null
@@ -0,0 +1,201 @@
+From 2bd25a6b5b5af59a33c22c2bf2cc4ea3043f33c5 Mon Sep 17 00:00:00 2001
+From: Ran Wang <ran.wang_1@nxp.com>
+Date: Thu, 24 Oct 2019 16:39:30 +0800
+Subject: [PATCH] soc: fsl: add RCPM driver
+
+The NXP's QorIQ processors based on ARM Core have RCPM module
+(Run Control and Power Management), which performs system level
+tasks associated with power management such as wakeup source control.
+
+Note that this driver will not support PowerPC based QorIQ processors,
+and it depends on PM wakeup source framework which provide collect
+wake information.
+
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/soc/fsl/Kconfig  |   9 +++
+ drivers/soc/fsl/Makefile |   1 +
+ drivers/soc/fsl/rcpm.c   | 151 +++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 161 insertions(+)
+ create mode 100644 drivers/soc/fsl/rcpm.c
+
+--- a/drivers/soc/fsl/Kconfig
++++ b/drivers/soc/fsl/Kconfig
+@@ -52,4 +52,13 @@ config FSL_QIXIS
+         Say y here to enable QIXIS system controller api. The qixis driver
+         provides FPGA functions to control system.
++config FSL_RCPM
++      bool "Freescale RCPM support"
++      depends on PM_SLEEP && (ARM || ARM64)
++      help
++        The NXP QorIQ Processors based on ARM Core have RCPM module
++        (Run Control and Power Management), which performs all device-level
++        tasks associated with power management, such as wakeup source control.
++        Note that currently this driver will not support PowerPC based
++        QorIQ processor.
+ endmenu
+--- a/drivers/soc/fsl/Makefile
++++ b/drivers/soc/fsl/Makefile
+@@ -10,3 +10,4 @@ obj-$(CONFIG_FSL_QIXIS)              += qixis_ctrl.
+ obj-$(CONFIG_FSL_GUTS)                        += guts.o
+ obj-$(CONFIG_FSL_MC_DPIO)             += dpio/
+ obj-$(CONFIG_DPAA2_CONSOLE)           += dpaa2-console.o
++obj-$(CONFIG_FSL_RCPM)                        += rcpm.o
+--- /dev/null
++++ b/drivers/soc/fsl/rcpm.c
+@@ -0,0 +1,151 @@
++// SPDX-License-Identifier: GPL-2.0
++//
++// rcpm.c - Freescale QorIQ RCPM driver
++//
++// Copyright 2019 NXP
++//
++// Author: Ran Wang <ran.wang_1@nxp.com>
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/of_address.h>
++#include <linux/slab.h>
++#include <linux/suspend.h>
++#include <linux/kernel.h>
++
++#define RCPM_WAKEUP_CELL_MAX_SIZE     7
++
++struct rcpm {
++      unsigned int    wakeup_cells;
++      void __iomem    *ippdexpcr_base;
++      bool            little_endian;
++};
++
++/**
++ * rcpm_pm_prepare - performs device-level tasks associated with power
++ * management, such as programming related to the wakeup source control.
++ * @dev: Device to handle.
++ *
++ */
++static int rcpm_pm_prepare(struct device *dev)
++{
++      int i, ret, idx;
++      void __iomem *base;
++      struct wakeup_source    *ws;
++      struct rcpm             *rcpm;
++      struct device_node      *np = dev->of_node;
++      u32 value[RCPM_WAKEUP_CELL_MAX_SIZE + 1];
++      u32 setting[RCPM_WAKEUP_CELL_MAX_SIZE] = {0};
++
++      rcpm = dev_get_drvdata(dev);
++      if (!rcpm)
++              return -EINVAL;
++
++      base = rcpm->ippdexpcr_base;
++      idx = wakeup_sources_read_lock();
++
++      /* Begin with first registered wakeup source */
++      for_each_wakeup_source(ws) {
++
++              /* skip object which is not attached to device */
++              if (!ws->dev || !ws->dev->parent)
++                      continue;
++
++              ret = device_property_read_u32_array(ws->dev->parent,
++                              "fsl,rcpm-wakeup", value,
++                              rcpm->wakeup_cells + 1);
++
++              /*  Wakeup source should refer to current rcpm device */
++              if (ret || (np->phandle != value[0]))
++                      continue;
++
++              /* Property "#fsl,rcpm-wakeup-cells" of rcpm node defines the
++               * number of IPPDEXPCR register cells, and "fsl,rcpm-wakeup"
++               * of wakeup source IP contains an integer array: <phandle to
++               * RCPM node, IPPDEXPCR0 setting, IPPDEXPCR1 setting,
++               * IPPDEXPCR2 setting, etc>.
++               *
++               * So we will go thought them to collect setting data.
++               */
++              for (i = 0; i < rcpm->wakeup_cells; i++)
++                      setting[i] |= value[i + 1];
++      }
++
++      wakeup_sources_read_unlock(idx);
++
++      /* Program all IPPDEXPCRn once */
++      for (i = 0; i < rcpm->wakeup_cells; i++) {
++              u32 tmp = setting[i];
++              void __iomem *address = base + i * 4;
++
++              if (!tmp)
++                      continue;
++
++              /* We can only OR related bits */
++              if (rcpm->little_endian) {
++                      tmp |= ioread32(address);
++                      iowrite32(tmp, address);
++              } else {
++                      tmp |= ioread32be(address);
++                      iowrite32be(tmp, address);
++              }
++      }
++
++      return 0;
++}
++
++static const struct dev_pm_ops rcpm_pm_ops = {
++      .prepare =  rcpm_pm_prepare,
++};
++
++static int rcpm_probe(struct platform_device *pdev)
++{
++      struct device   *dev = &pdev->dev;
++      struct resource *r;
++      struct rcpm     *rcpm;
++      int ret;
++
++      rcpm = devm_kzalloc(dev, sizeof(*rcpm), GFP_KERNEL);
++      if (!rcpm)
++              return -ENOMEM;
++
++      r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (!r)
++              return -ENODEV;
++
++      rcpm->ippdexpcr_base = devm_ioremap_resource(&pdev->dev, r);
++      if (IS_ERR(rcpm->ippdexpcr_base)) {
++              ret =  PTR_ERR(rcpm->ippdexpcr_base);
++              return ret;
++      }
++
++      rcpm->little_endian = device_property_read_bool(
++                      &pdev->dev, "little-endian");
++
++      ret = device_property_read_u32(&pdev->dev,
++                      "#fsl,rcpm-wakeup-cells", &rcpm->wakeup_cells);
++      if (ret)
++              return ret;
++
++      dev_set_drvdata(&pdev->dev, rcpm);
++
++      return 0;
++}
++
++static const struct of_device_id rcpm_of_match[] = {
++      { .compatible = "fsl,qoriq-rcpm-2.1+", },
++      {}
++};
++MODULE_DEVICE_TABLE(of, rcpm_of_match);
++
++static struct platform_driver rcpm_driver = {
++      .driver = {
++              .name = "rcpm",
++              .of_match_table = rcpm_of_match,
++              .pm     = &rcpm_pm_ops,
++      },
++      .probe = rcpm_probe,
++};
++
++module_platform_driver(rcpm_driver);
diff --git a/target/linux/layerscape/patches-5.4/813-pm-0002-fsl_pmc-update-device-bindings.patch b/target/linux/layerscape/patches-5.4/813-pm-0002-fsl_pmc-update-device-bindings.patch
new file mode 100644 (file)
index 0000000..9889710
--- /dev/null
@@ -0,0 +1,98 @@
+From f48ec27500239c0400114327ecbbfec34bfc2deb Mon Sep 17 00:00:00 2001
+From: Li Yang <leoli@freescale.com>
+Date: Wed, 22 Feb 2012 15:52:50 +0000
+Subject: [PATCH] fsl_pmc: update device bindings
+
+Signed-off-by: Li Yang <leoyang.li@nxp.com>
+Signed-off-by: Zhao Chenhui <chenhui.zhao@nxp.com>
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+---
+ .../devicetree/bindings/powerpc/fsl/pmc.txt        | 59 +++++++++++++---------
+ 1 file changed, 34 insertions(+), 25 deletions(-)
+
+--- a/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt
++++ b/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt
+@@ -9,15 +9,20 @@ Properties:
+   "fsl,mpc8548-pmc" should be listed for any chip whose PMC is
+   compatible.  "fsl,mpc8536-pmc" should also be listed for any chip
+-  whose PMC is compatible, and implies deep-sleep capability.
++  whose PMC is compatible, and implies deep-sleep capability and
++  wake on user defined packet(wakeup on ARP).
++
++  "fsl,p1022-pmc" should be listed for any chip whose PMC is
++  compatible, and implies lossless Ethernet capability during sleep.
+   "fsl,mpc8641d-pmc" should be listed for any chip whose PMC is
+   compatible; all statements below that apply to "fsl,mpc8548-pmc" also
+   apply to "fsl,mpc8641d-pmc".
+   Compatibility does not include bit assignments in SCCR/PMCDR/DEVDISR; these
+-  bit assignments are indicated via the sleep specifier in each device's
+-  sleep property.
++  bit assignments are indicated via the clock nodes.  Device which has a
++  controllable clock source should have a "fsl,pmc-handle" property pointing
++  to the clock node.
+ - reg: For devices compatible with "fsl,mpc8349-pmc", the first resource
+   is the PMC block, and the second resource is the Clock Configuration
+@@ -33,31 +38,35 @@ Properties:
+   this is a phandle to an "fsl,gtm" node on which timer 4 can be used as
+   a wakeup source from deep sleep.
+-Sleep specifiers:
+-
+-  fsl,mpc8349-pmc: Sleep specifiers consist of one cell.  For each bit
+-  that is set in the cell, the corresponding bit in SCCR will be saved
+-  and cleared on suspend, and restored on resume.  This sleep controller
+-  supports disabling and resuming devices at any time.
+-
+-  fsl,mpc8536-pmc: Sleep specifiers consist of three cells, the third of
+-  which will be ORed into PMCDR upon suspend, and cleared from PMCDR
+-  upon resume.  The first two cells are as described for fsl,mpc8578-pmc.
+-  This sleep controller only supports disabling devices during system
+-  sleep, or permanently.
+-
+-  fsl,mpc8548-pmc: Sleep specifiers consist of one or two cells, the
+-  first of which will be ORed into DEVDISR (and the second into
+-  DEVDISR2, if present -- this cell should be zero or absent if the
+-  hardware does not have DEVDISR2) upon a request for permanent device
+-  disabling.  This sleep controller does not support configuring devices
+-  to disable during system sleep (unless supported by another compatible
+-  match), or dynamically.
++Clock nodes:
++The clock nodes are to describe the masks in PM controller registers for each
++soc clock.
++- fsl,pmcdr-mask: For "fsl,mpc8548-pmc"-compatible devices, the mask will be
++  ORed into PMCDR before suspend if the device using this clock is the wake-up
++  source and need to be running during low power mode; clear the mask if
++  otherwise.
++
++- fsl,sccr-mask: For "fsl,mpc8349-pmc"-compatible devices, the corresponding
++  bit specified by the mask in SCCR will be saved and cleared on suspend, and
++  restored on resume.
++
++- fsl,devdisr-mask: Contain one or two cells, depending on the availability of
++  DEVDISR2 register.  For compatible devices, the mask will be ORed into DEVDISR
++  or DEVDISR2 when the clock should be permenently disabled.
+ Example:
+-      power@b00 {
+-              compatible = "fsl,mpc8313-pmc", "fsl,mpc8349-pmc";
+-              reg = <0xb00 0x100 0xa00 0x100>;
+-              interrupts = <80 8>;
++      power@e0070 {
++              compatible = "fsl,mpc8536-pmc", "fsl,mpc8548-pmc";
++              reg = <0xe0070 0x20>;
++
++              etsec1_clk: soc-clk@24 {
++                      fsl,pmcdr-mask = <0x00000080>;
++              };
++              etsec2_clk: soc-clk@25 {
++                      fsl,pmcdr-mask = <0x00000040>;
++              };
++              etsec3_clk: soc-clk@26 {
++                      fsl,pmcdr-mask = <0x00000020>;
++              };
+       };
diff --git a/target/linux/layerscape/patches-5.4/813-pm-0003-drivers-soc-fsl-add-EPU-FSM-configuration-for-deep-s.patch b/target/linux/layerscape/patches-5.4/813-pm-0003-drivers-soc-fsl-add-EPU-FSM-configuration-for-deep-s.patch
new file mode 100644 (file)
index 0000000..21ac78b
--- /dev/null
@@ -0,0 +1,464 @@
+From 051f3793314e2fb3f1945f3e6fa6942a355ebb50 Mon Sep 17 00:00:00 2001
+From: Ran Wang <ran.wang_1@nxp.com>
+Date: Thu, 12 Apr 2018 14:35:40 +0800
+Subject: [PATCH] drivers/soc/fsl: add EPU FSM configuration for deep sleep
+
+In the last stage of deep sleep, software will trigger a Finite
+State Machine (FSM) to control the hardware procedure, such a
+board isolation, killing PLLs, removing power, and so on.
+
+When the system is waked up by an interrupt, the FSM controls
+the hardware to complete the early resume procedure.
+
+This patch configure the EPU FSM preparing for deep sleep.
+
+Signed-off-by: Hongbo Zhang <hongbo.zhang@freescale.com>
+Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+---
+ drivers/soc/fsl/Kconfig     |   7 ++
+ drivers/soc/fsl/Makefile    |   1 +
+ drivers/soc/fsl/sleep_fsm.c | 279 ++++++++++++++++++++++++++++++++++++++++++++
+ drivers/soc/fsl/sleep_fsm.h | 130 +++++++++++++++++++++
+ 4 files changed, 417 insertions(+)
+ create mode 100644 drivers/soc/fsl/sleep_fsm.c
+ create mode 100644 drivers/soc/fsl/sleep_fsm.h
+
+--- a/drivers/soc/fsl/Kconfig
++++ b/drivers/soc/fsl/Kconfig
+@@ -31,6 +31,13 @@ config FSL_MC_DPIO
+         objects individually, but groups them under a service layer
+         API.
++config FSL_SLEEP_FSM
++      bool
++      help
++        This driver configures a hardware FSM (Finite State Machine) for deep sleep.
++        The FSM is used to finish clean-ups at the last stage of system entering deep
++        sleep, and also wakes up system when a wake up event happens.
++
+ config DPAA2_CONSOLE
+       tristate "QorIQ DPAA2 console driver"
+       depends on OF && (ARCH_LAYERSCAPE || COMPILE_TEST)
+--- a/drivers/soc/fsl/Makefile
++++ b/drivers/soc/fsl/Makefile
+@@ -11,3 +11,4 @@ obj-$(CONFIG_FSL_GUTS)                       += guts.o
+ obj-$(CONFIG_FSL_MC_DPIO)             += dpio/
+ obj-$(CONFIG_DPAA2_CONSOLE)           += dpaa2-console.o
+ obj-$(CONFIG_FSL_RCPM)                        += rcpm.o
++obj-$(CONFIG_FSL_SLEEP_FSM)           += sleep_fsm.o
+--- /dev/null
++++ b/drivers/soc/fsl/sleep_fsm.c
+@@ -0,0 +1,279 @@
++/*
++ * deep sleep FSM (finite-state machine) configuration
++ *
++ * Copyright 2018 NXP
++ *
++ * Author: Hongbo Zhang <hongbo.zhang@freescale.com>
++ *         Chenhui Zhao <chenhui.zhao@freescale.com>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of the above-listed copyright holders nor the
++ *     names of any contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <linux/types.h>
++
++#include "sleep_fsm.h"
++/*
++ * These values are from chip's reference manual. For example,
++ * the values for T1040 can be found in "8.4.3.8 Programming
++ * supporting deep sleep mode" of Chapter 8 "Run Control and
++ * Power Management (RCPM)".
++ * The default value can be applied to T104x, LS1021.
++ */
++struct fsm_reg_vals epu_default_val[] = {
++      /* EPGCR (Event Processor Global Control Register) */
++      {EPGCR, 0},
++      /* EPECR (Event Processor Event Control Registers) */
++      {EPECR0 + EPECR_STRIDE * 0, 0},
++      {EPECR0 + EPECR_STRIDE * 1, 0},
++      {EPECR0 + EPECR_STRIDE * 2, 0xF0004004},
++      {EPECR0 + EPECR_STRIDE * 3, 0x80000084},
++      {EPECR0 + EPECR_STRIDE * 4, 0x20000084},
++      {EPECR0 + EPECR_STRIDE * 5, 0x08000004},
++      {EPECR0 + EPECR_STRIDE * 6, 0x80000084},
++      {EPECR0 + EPECR_STRIDE * 7, 0x80000084},
++      {EPECR0 + EPECR_STRIDE * 8, 0x60000084},
++      {EPECR0 + EPECR_STRIDE * 9, 0x08000084},
++      {EPECR0 + EPECR_STRIDE * 10, 0x42000084},
++      {EPECR0 + EPECR_STRIDE * 11, 0x90000084},
++      {EPECR0 + EPECR_STRIDE * 12, 0x80000084},
++      {EPECR0 + EPECR_STRIDE * 13, 0x08000084},
++      {EPECR0 + EPECR_STRIDE * 14, 0x02000084},
++      {EPECR0 + EPECR_STRIDE * 15, 0x00000004},
++      /*
++       * EPEVTCR (Event Processor EVT Pin Control Registers)
++       * SCU8 triger EVT2, and SCU11 triger EVT9
++       */
++      {EPEVTCR0 + EPEVTCR_STRIDE * 0, 0},
++      {EPEVTCR0 + EPEVTCR_STRIDE * 1, 0},
++      {EPEVTCR0 + EPEVTCR_STRIDE * 2, 0x80000001},
++      {EPEVTCR0 + EPEVTCR_STRIDE * 3, 0},
++      {EPEVTCR0 + EPEVTCR_STRIDE * 4, 0},
++      {EPEVTCR0 + EPEVTCR_STRIDE * 5, 0},
++      {EPEVTCR0 + EPEVTCR_STRIDE * 6, 0},
++      {EPEVTCR0 + EPEVTCR_STRIDE * 7, 0},
++      {EPEVTCR0 + EPEVTCR_STRIDE * 8, 0},
++      {EPEVTCR0 + EPEVTCR_STRIDE * 9, 0xB0000001},
++      /* EPCMPR (Event Processor Counter Compare Registers) */
++      {EPCMPR0 + EPCMPR_STRIDE * 0, 0},
++      {EPCMPR0 + EPCMPR_STRIDE * 1, 0},
++      {EPCMPR0 + EPCMPR_STRIDE * 2, 0x000000FF},
++      {EPCMPR0 + EPCMPR_STRIDE * 3, 0},
++      {EPCMPR0 + EPCMPR_STRIDE * 4, 0x000000FF},
++      {EPCMPR0 + EPCMPR_STRIDE * 5, 0x00000020},
++      {EPCMPR0 + EPCMPR_STRIDE * 6, 0},
++      {EPCMPR0 + EPCMPR_STRIDE * 7, 0},
++      {EPCMPR0 + EPCMPR_STRIDE * 8, 0x000000FF},
++      {EPCMPR0 + EPCMPR_STRIDE * 9, 0x000000FF},
++      {EPCMPR0 + EPCMPR_STRIDE * 10, 0x000000FF},
++      {EPCMPR0 + EPCMPR_STRIDE * 11, 0x000000FF},
++      {EPCMPR0 + EPCMPR_STRIDE * 12, 0x000000FF},
++      {EPCMPR0 + EPCMPR_STRIDE * 13, 0},
++      {EPCMPR0 + EPCMPR_STRIDE * 14, 0x000000FF},
++      {EPCMPR0 + EPCMPR_STRIDE * 15, 0x000000FF},
++      /* EPCCR (Event Processor Counter Control Registers) */
++      {EPCCR0 + EPCCR_STRIDE * 0, 0},
++      {EPCCR0 + EPCCR_STRIDE * 1, 0},
++      {EPCCR0 + EPCCR_STRIDE * 2, 0x92840000},
++      {EPCCR0 + EPCCR_STRIDE * 3, 0},
++      {EPCCR0 + EPCCR_STRIDE * 4, 0x92840000},
++      {EPCCR0 + EPCCR_STRIDE * 5, 0x92840000},
++      {EPCCR0 + EPCCR_STRIDE * 6, 0},
++      {EPCCR0 + EPCCR_STRIDE * 7, 0},
++      {EPCCR0 + EPCCR_STRIDE * 8, 0x92840000},
++      {EPCCR0 + EPCCR_STRIDE * 9, 0x92840000},
++      {EPCCR0 + EPCCR_STRIDE * 10, 0x92840000},
++      {EPCCR0 + EPCCR_STRIDE * 11, 0x92840000},
++      {EPCCR0 + EPCCR_STRIDE * 12, 0x92840000},
++      {EPCCR0 + EPCCR_STRIDE * 13, 0},
++      {EPCCR0 + EPCCR_STRIDE * 14, 0x92840000},
++      {EPCCR0 + EPCCR_STRIDE * 15, 0x92840000},
++      /* EPSMCR (Event Processor SCU Mux Control Registers) */
++      {EPSMCR0 + EPSMCR_STRIDE * 0, 0},
++      {EPSMCR0 + EPSMCR_STRIDE * 1, 0},
++      {EPSMCR0 + EPSMCR_STRIDE * 2, 0x6C700000},
++      {EPSMCR0 + EPSMCR_STRIDE * 3, 0x2F000000},
++      {EPSMCR0 + EPSMCR_STRIDE * 4, 0x002F0000},
++      {EPSMCR0 + EPSMCR_STRIDE * 5, 0x00002E00},
++      {EPSMCR0 + EPSMCR_STRIDE * 6, 0x7C000000},
++      {EPSMCR0 + EPSMCR_STRIDE * 7, 0x30000000},
++      {EPSMCR0 + EPSMCR_STRIDE * 8, 0x64300000},
++      {EPSMCR0 + EPSMCR_STRIDE * 9, 0x00003000},
++      {EPSMCR0 + EPSMCR_STRIDE * 10, 0x65000030},
++      {EPSMCR0 + EPSMCR_STRIDE * 11, 0x31740000},
++      {EPSMCR0 + EPSMCR_STRIDE * 12, 0x7F000000},
++      {EPSMCR0 + EPSMCR_STRIDE * 13, 0x00003100},
++      {EPSMCR0 + EPSMCR_STRIDE * 14, 0x00000031},
++      {EPSMCR0 + EPSMCR_STRIDE * 15, 0x76000000},
++      /* EPACR (Event Processor Action Control Registers) */
++      {EPACR0 + EPACR_STRIDE * 0, 0},
++      {EPACR0 + EPACR_STRIDE * 1, 0},
++      {EPACR0 + EPACR_STRIDE * 2, 0},
++      {EPACR0 + EPACR_STRIDE * 3, 0x00000080},
++      {EPACR0 + EPACR_STRIDE * 4, 0},
++      {EPACR0 + EPACR_STRIDE * 5, 0x00000040},
++      {EPACR0 + EPACR_STRIDE * 6, 0},
++      {EPACR0 + EPACR_STRIDE * 7, 0},
++      {EPACR0 + EPACR_STRIDE * 8, 0},
++      {EPACR0 + EPACR_STRIDE * 9, 0x0000001C},
++      {EPACR0 + EPACR_STRIDE * 10, 0x00000020},
++      {EPACR0 + EPACR_STRIDE * 11, 0},
++      {EPACR0 + EPACR_STRIDE * 12, 0x00000003},
++      {EPACR0 + EPACR_STRIDE * 13, 0x06000000},
++      {EPACR0 + EPACR_STRIDE * 14, 0x04000000},
++      {EPACR0 + EPACR_STRIDE * 15, 0x02000000},
++      /* EPIMCR (Event Processor Input Mux Control Registers) */
++      {EPIMCR0 + EPIMCR_STRIDE * 0, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 1, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 2, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 3, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 4, 0x44000000},
++      {EPIMCR0 + EPIMCR_STRIDE * 5, 0x40000000},
++      {EPIMCR0 + EPIMCR_STRIDE * 6, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 7, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 8, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 9, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 10, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 11, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 12, 0x44000000},
++      {EPIMCR0 + EPIMCR_STRIDE * 13, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 14, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 15, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 16, 0x6A000000},
++      {EPIMCR0 + EPIMCR_STRIDE * 17, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 18, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 19, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 20, 0x48000000},
++      {EPIMCR0 + EPIMCR_STRIDE * 21, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 22, 0x6C000000},
++      {EPIMCR0 + EPIMCR_STRIDE * 23, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 24, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 25, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 26, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 27, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 28, 0x76000000},
++      {EPIMCR0 + EPIMCR_STRIDE * 29, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 30, 0},
++      {EPIMCR0 + EPIMCR_STRIDE * 31, 0x76000000},
++      /* EPXTRIGCR (Event Processor Crosstrigger Control Register) */
++      {EPXTRIGCR, 0x0000FFDF},
++      /* end */
++      {FSM_END_FLAG, 0},
++};
++
++struct fsm_reg_vals npc_default_val[] = {
++      /* NPC triggered Memory-Mapped Access Registers */
++      {NCR, 0x80000000},
++      {MCCR1, 0},
++      {MCSR1, 0},
++      {MMAR1LO, 0},
++      {MMAR1HI, 0},
++      {MMDR1, 0},
++      {MCSR2, 0},
++      {MMAR2LO, 0},
++      {MMAR2HI, 0},
++      {MMDR2, 0},
++      {MCSR3, 0x80000000},
++      {MMAR3LO, 0x000E2130},
++      {MMAR3HI, 0x00030000},
++      {MMDR3, 0x00020000},
++      /* end */
++      {FSM_END_FLAG, 0},
++};
++
++/**
++ * fsl_fsm_setup - Configure EPU's FSM registers
++ * @base: the base address of registers
++ * @val: Pointer to address-value pairs for FSM registers
++ */
++void fsl_fsm_setup(void __iomem *base, struct fsm_reg_vals *val)
++{
++      struct fsm_reg_vals *data = val;
++
++      WARN_ON(!base || !data);
++      while (data->offset != FSM_END_FLAG) {
++              iowrite32be(data->value, base + data->offset);
++              data++;
++      }
++}
++
++void fsl_epu_setup_default(void __iomem *epu_base)
++{
++      fsl_fsm_setup(epu_base, epu_default_val);
++}
++
++void fsl_npc_setup_default(void __iomem *npc_base)
++{
++      fsl_fsm_setup(npc_base, npc_default_val);
++}
++
++void fsl_epu_clean_default(void __iomem *epu_base)
++{
++      u32 offset;
++
++      /* follow the exact sequence to clear the registers */
++      /* Clear EPACRn */
++      for (offset = EPACR0; offset <= EPACR15; offset += EPACR_STRIDE)
++              iowrite32be(0, epu_base + offset);
++
++      /* Clear EPEVTCRn */
++      for (offset = EPEVTCR0; offset <= EPEVTCR9; offset += EPEVTCR_STRIDE)
++              iowrite32be(0, epu_base + offset);
++
++      /* Clear EPGCR */
++      iowrite32be(0, epu_base + EPGCR);
++
++      /* Clear EPSMCRn */
++      for (offset = EPSMCR0; offset <= EPSMCR15; offset += EPSMCR_STRIDE)
++              iowrite32be(0, epu_base + offset);
++
++      /* Clear EPCCRn */
++      for (offset = EPCCR0; offset <= EPCCR31; offset += EPCCR_STRIDE)
++              iowrite32be(0, epu_base + offset);
++
++      /* Clear EPCMPRn */
++      for (offset = EPCMPR0; offset <= EPCMPR31; offset += EPCMPR_STRIDE)
++              iowrite32be(0, epu_base + offset);
++
++      /* Clear EPCTRn */
++      for (offset = EPCTR0; offset <= EPCTR31; offset += EPCTR_STRIDE)
++              iowrite32be(0, epu_base + offset);
++
++      /* Clear EPIMCRn */
++      for (offset = EPIMCR0; offset <= EPIMCR31; offset += EPIMCR_STRIDE)
++              iowrite32be(0, epu_base + offset);
++
++      /* Clear EPXTRIGCRn */
++      iowrite32be(0, epu_base + EPXTRIGCR);
++
++      /* Clear EPECRn */
++      for (offset = EPECR0; offset <= EPECR15; offset += EPECR_STRIDE)
++              iowrite32be(0, epu_base + offset);
++}
+--- /dev/null
++++ b/drivers/soc/fsl/sleep_fsm.h
+@@ -0,0 +1,130 @@
++/*
++ * deep sleep FSM (finite-state machine) configuration
++ *
++ * Copyright 2018 NXP
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *     * Redistributions of source code must retain the above copyright
++ *     notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above copyright
++ *     notice, this list of conditions and the following disclaimer in the
++ *     documentation and/or other materials provided with the distribution.
++ *     * Neither the name of the above-listed copyright holders nor the
++ *     names of any contributors may be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _FSL_SLEEP_FSM_H
++#define _FSL_SLEEP_FSM_H
++
++#define FSL_STRIDE_4B 4
++#define FSL_STRIDE_8B 8
++
++/* End flag */
++#define FSM_END_FLAG          0xFFFFFFFFUL
++
++/* Block offsets */
++#define RCPM_BLOCK_OFFSET     0x00022000
++#define EPU_BLOCK_OFFSET      0x00000000
++#define NPC_BLOCK_OFFSET      0x00001000
++
++/* EPGCR (Event Processor Global Control Register) */
++#define EPGCR         0x000
++
++/* EPEVTCR0-9 (Event Processor EVT Pin Control Registers) */
++#define EPEVTCR0      0x050
++#define EPEVTCR9      0x074
++#define EPEVTCR_STRIDE        FSL_STRIDE_4B
++
++/* EPXTRIGCR (Event Processor Crosstrigger Control Register) */
++#define EPXTRIGCR     0x090
++
++/* EPIMCR0-31 (Event Processor Input Mux Control Registers) */
++#define EPIMCR0               0x100
++#define EPIMCR31      0x17C
++#define EPIMCR_STRIDE FSL_STRIDE_4B
++
++/* EPSMCR0-15 (Event Processor SCU Mux Control Registers) */
++#define EPSMCR0               0x200
++#define EPSMCR15      0x278
++#define EPSMCR_STRIDE FSL_STRIDE_8B
++
++/* EPECR0-15 (Event Processor Event Control Registers) */
++#define EPECR0                0x300
++#define EPECR15               0x33C
++#define EPECR_STRIDE  FSL_STRIDE_4B
++
++/* EPACR0-15 (Event Processor Action Control Registers) */
++#define EPACR0                0x400
++#define EPACR15               0x43C
++#define EPACR_STRIDE  FSL_STRIDE_4B
++
++/* EPCCRi0-15 (Event Processor Counter Control Registers) */
++#define EPCCR0                0x800
++#define EPCCR15               0x83C
++#define EPCCR31               0x87C
++#define EPCCR_STRIDE  FSL_STRIDE_4B
++
++/* EPCMPR0-15 (Event Processor Counter Compare Registers) */
++#define EPCMPR0               0x900
++#define EPCMPR15      0x93C
++#define EPCMPR31      0x97C
++#define EPCMPR_STRIDE FSL_STRIDE_4B
++
++/* EPCTR0-31 (Event Processor Counter Register) */
++#define EPCTR0                0xA00
++#define EPCTR31               0xA7C
++#define EPCTR_STRIDE  FSL_STRIDE_4B
++
++/* NPC triggered Memory-Mapped Access Registers */
++#define NCR           0x000
++#define MCCR1         0x0CC
++#define MCSR1         0x0D0
++#define MMAR1LO               0x0D4
++#define MMAR1HI               0x0D8
++#define MMDR1         0x0DC
++#define MCSR2         0x0E0
++#define MMAR2LO               0x0E4
++#define MMAR2HI               0x0E8
++#define MMDR2         0x0EC
++#define MCSR3         0x0F0
++#define MMAR3LO               0x0F4
++#define MMAR3HI               0x0F8
++#define MMDR3         0x0FC
++
++/* RCPM Core State Action Control Register 0 */
++#define CSTTACR0      0xB00
++
++/* RCPM Core Group 1 Configuration Register 0 */
++#define CG1CR0                0x31C
++
++struct fsm_reg_vals {
++      u32 offset;
++      u32 value;
++};
++
++void fsl_fsm_setup(void __iomem *base, struct fsm_reg_vals *val);
++void fsl_epu_setup_default(void __iomem *epu_base);
++void fsl_npc_setup_default(void __iomem *npc_base);
++void fsl_epu_clean_default(void __iomem *epu_base);
++
++#endif /* _FSL_SLEEP_FSM_H */
diff --git a/target/linux/layerscape/patches-5.4/813-pm-0004-PM-wakeup-Add-routine-to-help-fetch-wakeup-source-ob.patch b/target/linux/layerscape/patches-5.4/813-pm-0004-PM-wakeup-Add-routine-to-help-fetch-wakeup-source-ob.patch
new file mode 100644 (file)
index 0000000..42514bb
--- /dev/null
@@ -0,0 +1,108 @@
+From a9647655a2240148b7b6d29227dc76e9d6f12766 Mon Sep 17 00:00:00 2001
+From: Ran Wang <ran.wang_1@nxp.com>
+Date: Thu, 24 Oct 2019 16:36:14 +0800
+Subject: [PATCH] PM: wakeup: Add routine to help fetch wakeup source object.
+
+Some user might want to go through all registered wakeup sources
+and doing things accordingly. For example, SoC PM driver might need to
+do HW programming to prevent powering down specific IP which wakeup
+source depending on. So add this API to help walk through all registered
+wakeup source objects on that list and return them one by one.
+
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+Tested-by: Leonard Crestez <leonard.crestez@nxp.com>
+Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Acked-by: Anson Huang <Anson.Huang@nxp.com>
+---
+ drivers/base/power/wakeup.c | 54 +++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/pm_wakeup.h   |  9 ++++++++
+ 2 files changed, 63 insertions(+)
+
+--- a/drivers/base/power/wakeup.c
++++ b/drivers/base/power/wakeup.c
+@@ -248,6 +248,60 @@ void wakeup_source_unregister(struct wak
+ EXPORT_SYMBOL_GPL(wakeup_source_unregister);
+ /**
++ * wakeup_sources_read_lock - Lock wakeup source list for read.
++ *
++ * Returns an index of srcu lock for struct wakeup_srcu.
++ * This index must be passed to the matching wakeup_sources_read_unlock().
++ */
++int wakeup_sources_read_lock(void)
++{
++      return srcu_read_lock(&wakeup_srcu);
++}
++EXPORT_SYMBOL_GPL(wakeup_sources_read_lock);
++
++/**
++ * wakeup_sources_read_unlock - Unlock wakeup source list.
++ * @idx: return value from corresponding wakeup_sources_read_lock()
++ */
++void wakeup_sources_read_unlock(int idx)
++{
++      srcu_read_unlock(&wakeup_srcu, idx);
++}
++EXPORT_SYMBOL_GPL(wakeup_sources_read_unlock);
++
++/**
++ * wakeup_sources_walk_start - Begin a walk on wakeup source list
++ *
++ * Returns first object of the list of wakeup sources.
++ *
++ * Note that to be safe, wakeup sources list needs to be locked by calling
++ * wakeup_source_read_lock() for this.
++ */
++struct wakeup_source *wakeup_sources_walk_start(void)
++{
++      struct list_head *ws_head = &wakeup_sources;
++
++      return list_entry_rcu(ws_head->next, struct wakeup_source, entry);
++}
++EXPORT_SYMBOL_GPL(wakeup_sources_walk_start);
++
++/**
++ * wakeup_sources_walk_next - Get next wakeup source from the list
++ * @ws: Previous wakeup source object
++ *
++ * Note that to be safe, wakeup sources list needs to be locked by calling
++ * wakeup_source_read_lock() for this.
++ */
++struct wakeup_source *wakeup_sources_walk_next(struct wakeup_source *ws)
++{
++      struct list_head *ws_head = &wakeup_sources;
++
++      return list_next_or_null_rcu(ws_head, &ws->entry,
++                              struct wakeup_source, entry);
++}
++EXPORT_SYMBOL_GPL(wakeup_sources_walk_next);
++
++/**
+  * device_wakeup_attach - Attach a wakeup source object to a device object.
+  * @dev: Device to handle.
+  * @ws: Wakeup source object to attach to @dev.
+--- a/include/linux/pm_wakeup.h
++++ b/include/linux/pm_wakeup.h
+@@ -63,6 +63,11 @@ struct wakeup_source {
+       bool                    autosleep_enabled:1;
+ };
++#define for_each_wakeup_source(ws) \
++      for ((ws) = wakeup_sources_walk_start();        \
++           (ws);                                      \
++           (ws) = wakeup_sources_walk_next((ws)))
++
+ #ifdef CONFIG_PM_SLEEP
+ /*
+@@ -92,6 +97,10 @@ extern void wakeup_source_remove(struct
+ extern struct wakeup_source *wakeup_source_register(struct device *dev,
+                                                   const char *name);
+ extern void wakeup_source_unregister(struct wakeup_source *ws);
++extern int wakeup_sources_read_lock(void);
++extern void wakeup_sources_read_unlock(int idx);
++extern struct wakeup_source *wakeup_sources_walk_start(void);
++extern struct wakeup_source *wakeup_sources_walk_next(struct wakeup_source *ws);
+ extern int device_wakeup_enable(struct device *dev);
+ extern int device_wakeup_disable(struct device *dev);
+ extern void device_set_wakeup_capable(struct device *dev, bool capable);
diff --git a/target/linux/layerscape/patches-5.4/813-pm-0005-soc-fsl-handle-RCPM-errata-A-008646-on-SoC-LS1021A.patch b/target/linux/layerscape/patches-5.4/813-pm-0005-soc-fsl-handle-RCPM-errata-A-008646-on-SoC-LS1021A.patch
new file mode 100644 (file)
index 0000000..faf5627
--- /dev/null
@@ -0,0 +1,100 @@
+From 12ae7ff3ecb4527ebe30ec6feb29ebb0ec4cd0a7 Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Sat, 14 Sep 2019 12:37:49 +0800
+Subject: [PATCH] soc: fsl: handle RCPM errata A-008646 on SoC LS1021A
+
+Description:
+       - Reading configuration register RCPM_IPPDEXPCR1
+         always return zero
+
+Workaround:
+       - Save register RCPM_IPPDEXPCR1's value to
+         register SCFG_SPARECR8.(uboot's psci also
+         need reading value from the register SCFG_SPARECR8
+         to set register RCPM_IPPDEXPCR1)
+
+Impact:
+       - FlexTimer module will cannot wakeup system in
+         deep sleep on SoC LS1021A
+
+Reviewed-by: Ran Wang <ran.wang_1@nxp.com>
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+---
+ drivers/soc/fsl/rcpm.c | 47 +++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 45 insertions(+), 2 deletions(-)
+
+--- a/drivers/soc/fsl/rcpm.c
++++ b/drivers/soc/fsl/rcpm.c
+@@ -6,13 +6,16 @@
+ //
+ // Author: Ran Wang <ran.wang_1@nxp.com>
++#include <linux/acpi.h>
+ #include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/mfd/syscon.h>
+ #include <linux/module.h>
+-#include <linux/platform_device.h>
+ #include <linux/of_address.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
+ #include <linux/slab.h>
+ #include <linux/suspend.h>
+-#include <linux/kernel.h>
+ #define RCPM_WAKEUP_CELL_MAX_SIZE     7
+@@ -37,6 +40,9 @@ static int rcpm_pm_prepare(struct device
+       struct device_node      *np = dev->of_node;
+       u32 value[RCPM_WAKEUP_CELL_MAX_SIZE + 1];
+       u32 setting[RCPM_WAKEUP_CELL_MAX_SIZE] = {0};
++      struct regmap *scfg_addr_regmap = NULL;
++      u32 reg_offset[RCPM_WAKEUP_CELL_MAX_SIZE + 1];
++      u32 reg_value = 0;
+       rcpm = dev_get_drvdata(dev);
+       if (!rcpm)
+@@ -90,6 +96,43 @@ static int rcpm_pm_prepare(struct device
+                       tmp |= ioread32be(address);
+                       iowrite32be(tmp, address);
+               }
++              /*
++               * Workaround of errata A-008646 on SoC LS1021A:
++               * There is a bug of register ippdexpcr1.
++               * Reading configuration register RCPM_IPPDEXPCR1
++               * always return zero. So save ippdexpcr1's value
++               * to register SCFG_SPARECR8.And the value of
++               * ippdexpcr1 will be read from SCFG_SPARECR8.
++               */
++              if (device_property_present(dev, "fsl,ippdexpcr1-alt-addr")) {
++                      if (dev_of_node(dev)) {
++                              scfg_addr_regmap = syscon_regmap_lookup_by_phandle(np,
++                                                                                 "fsl,ippdexpcr1-alt-addr");
++                      } else if (is_acpi_node(dev->fwnode)) {
++                              dev_err(dev, "not support acpi for rcpm\n");
++                              continue;
++                      }
++
++                      if (scfg_addr_regmap && (i == 1)) {
++                              if (device_property_read_u32_array(dev,
++                                  "fsl,ippdexpcr1-alt-addr",
++                                  reg_offset,
++                                  1 + sizeof(u64)/sizeof(u32))) {
++                                      scfg_addr_regmap = NULL;
++                                      continue;
++                              }
++                              /* Read value from register SCFG_SPARECR8 */
++                              regmap_read(scfg_addr_regmap,
++                                          (u32)(((u64)(reg_offset[1] << (sizeof(u32) * 8) |
++                                          reg_offset[2])) & 0xffffffff),
++                                          &reg_value);
++                              /* Write value to register SCFG_SPARECR8 */
++                              regmap_write(scfg_addr_regmap,
++                                           (u32)(((u64)(reg_offset[1] << (sizeof(u32) * 8) |
++                                           reg_offset[2])) & 0xffffffff),
++                                           tmp | reg_value);
++                      }
++              }
+       }
+       return 0;
diff --git a/target/linux/layerscape/patches-5.4/813-pm-0006-soc-fsl-rcpm-remove-build-warning.patch b/target/linux/layerscape/patches-5.4/813-pm-0006-soc-fsl-rcpm-remove-build-warning.patch
new file mode 100644 (file)
index 0000000..e59e4f5
--- /dev/null
@@ -0,0 +1,39 @@
+From 341e6a1cbbc8a06702df15c147cbe1264418bf3b Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Thu, 5 Dec 2019 17:21:06 +0800
+Subject: [PATCH] soc: fsl: rcpm: remove build warning
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This removes build warning,
+drivers/soc/fsl/rcpm.c: In function ‘rcpm_pm_prepare’:
+drivers/soc/fsl/rcpm.c:126:37: warning: left shift count >= width of type [-Wshift-count-overflow]
+          (u32)(((u64)(reg_offset[1] << (sizeof(u32) * 8) |
+                                     ^~
+drivers/soc/fsl/rcpm.c:131:38: warning: left shift count >= width of type [-Wshift-count-overflow]
+           (u32)(((u64)(reg_offset[1] << (sizeof(u32) * 8) |
+
+Reviewed-by: Ran Wang <ran.wang_1@nxp.com>
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+---
+ drivers/soc/fsl/rcpm.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/soc/fsl/rcpm.c
++++ b/drivers/soc/fsl/rcpm.c
+@@ -123,12 +123,12 @@ static int rcpm_pm_prepare(struct device
+                               }
+                               /* Read value from register SCFG_SPARECR8 */
+                               regmap_read(scfg_addr_regmap,
+-                                          (u32)(((u64)(reg_offset[1] << (sizeof(u32) * 8) |
++                                          ((((u64)reg_offset[1] << (sizeof(u32) * 8) |
+                                           reg_offset[2])) & 0xffffffff),
+                                           &reg_value);
+                               /* Write value to register SCFG_SPARECR8 */
+                               regmap_write(scfg_addr_regmap,
+-                                           (u32)(((u64)(reg_offset[1] << (sizeof(u32) * 8) |
++                                           ((((u64)reg_offset[1] << (sizeof(u32) * 8) |
+                                            reg_offset[2])) & 0xffffffff),
+                                            tmp | reg_value);
+                       }
diff --git a/target/linux/layerscape/patches-5.4/814-qe-0001-irqchip-qeic-move-qeic-driver-from-drivers-soc-fsl-q.patch b/target/linux/layerscape/patches-5.4/814-qe-0001-irqchip-qeic-move-qeic-driver-from-drivers-soc-fsl-q.patch
new file mode 100644 (file)
index 0000000..bedc902
--- /dev/null
@@ -0,0 +1,1243 @@
+From 0172b31512827b9fd735df47751c7aa88b6aa5f6 Mon Sep 17 00:00:00 2001
+From: Zhao Qiang <qiang.zhao@nxp.com>
+Date: Thu, 27 Apr 2017 09:52:54 +0800
+Subject: [PATCH] irqchip/qeic: move qeic driver from drivers/soc/fsl/qe
+
+move the driver from drivers/soc/fsl/qe to drivers/irqchip,
+merge qe_ic.h and qe_ic.c into irq-qeic.c.
+
+Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
+---
+ drivers/irqchip/irq-qeic.c  | 597 ++++++++++++++++++++++++++++++++++++++++++++
+ drivers/soc/fsl/qe/Makefile |   2 +-
+ drivers/soc/fsl/qe/qe_ic.c  | 508 -------------------------------------
+ drivers/soc/fsl/qe/qe_ic.h  |  99 --------
+ 4 files changed, 598 insertions(+), 608 deletions(-)
+ create mode 100644 drivers/irqchip/irq-qeic.c
+ delete mode 100644 drivers/soc/fsl/qe/qe_ic.c
+ delete mode 100644 drivers/soc/fsl/qe/qe_ic.h
+
+--- /dev/null
++++ b/drivers/irqchip/irq-qeic.c
+@@ -0,0 +1,597 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * drivers/irqchip/irq-qeic.c
++ *
++ * Copyright (C) 2016 Freescale Semiconductor, Inc.  All rights reserved.
++ *
++ * Author: Li Yang <leoli@freescale.com>
++ * Based on code from Shlomi Gridish <gridish@freescale.com>
++ *
++ * QUICC ENGINE Interrupt Controller
++ */
++
++#include <linux/of_irq.h>
++#include <linux/of_address.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/reboot.h>
++#include <linux/slab.h>
++#include <linux/stddef.h>
++#include <linux/sched.h>
++#include <linux/signal.h>
++#include <linux/device.h>
++#include <linux/spinlock.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <soc/fsl/qe/qe_ic.h>
++
++#define NR_QE_IC_INTS         64
++
++/* QE IC registers offset */
++#define QEIC_CICR             0x00
++#define QEIC_CIVEC            0x04
++#define QEIC_CRIPNR           0x08
++#define QEIC_CIPNR            0x0c
++#define QEIC_CIPXCC           0x10
++#define QEIC_CIPYCC           0x14
++#define QEIC_CIPWCC           0x18
++#define QEIC_CIPZCC           0x1c
++#define QEIC_CIMR             0x20
++#define QEIC_CRIMR            0x24
++#define QEIC_CICNR            0x28
++#define QEIC_CIPRTA           0x30
++#define QEIC_CIPRTB           0x34
++#define QEIC_CRICR            0x3c
++#define QEIC_CHIVEC           0x60
++
++/* Interrupt priority registers */
++#define CIPCC_SHIFT_PRI0      29
++#define CIPCC_SHIFT_PRI1      26
++#define CIPCC_SHIFT_PRI2      23
++#define CIPCC_SHIFT_PRI3      20
++#define CIPCC_SHIFT_PRI4      13
++#define CIPCC_SHIFT_PRI5      10
++#define CIPCC_SHIFT_PRI6      7
++#define CIPCC_SHIFT_PRI7      4
++
++/* CICR priority modes */
++#define CICR_GWCC             0x00040000
++#define CICR_GXCC             0x00020000
++#define CICR_GYCC             0x00010000
++#define CICR_GZCC             0x00080000
++#define CICR_GRTA             0x00200000
++#define CICR_GRTB             0x00400000
++#define CICR_HPIT_SHIFT               8
++#define CICR_HPIT_MASK                0x00000300
++#define CICR_HP_SHIFT         24
++#define CICR_HP_MASK          0x3f000000
++
++/* CICNR */
++#define CICNR_WCC1T_SHIFT     20
++#define CICNR_ZCC1T_SHIFT     28
++#define CICNR_YCC1T_SHIFT     12
++#define CICNR_XCC1T_SHIFT     4
++
++/* CRICR */
++#define CRICR_RTA1T_SHIFT     20
++#define CRICR_RTB1T_SHIFT     28
++
++/* Signal indicator */
++#define SIGNAL_MASK           3
++#define SIGNAL_HIGH           2
++#define SIGNAL_LOW            0
++
++struct qe_ic {
++      /* Control registers offset */
++      u32 __iomem *regs;
++
++      /* The remapper for this QEIC */
++      struct irq_domain *irqhost;
++
++      /* The "linux" controller struct */
++      struct irq_chip hc_irq;
++
++      /* VIRQ numbers of QE high/low irqs */
++      unsigned int virq_high;
++      unsigned int virq_low;
++};
++
++/*
++ * QE interrupt controller internal structure
++ */
++struct qe_ic_info {
++      /* location of this source at the QIMR register. */
++      u32     mask;
++
++      /* Mask register offset */
++      u32     mask_reg;
++
++      /*
++       * for grouped interrupts sources - the interrupt
++       * code as appears at the group priority register
++       */
++      u8      pri_code;
++
++      /* Group priority register offset */
++      u32     pri_reg;
++};
++
++static DEFINE_RAW_SPINLOCK(qe_ic_lock);
++
++static struct qe_ic_info qe_ic_info[] = {
++      [1] = {
++             .mask = 0x00008000,
++             .mask_reg = QEIC_CIMR,
++             .pri_code = 0,
++             .pri_reg = QEIC_CIPWCC,
++             },
++      [2] = {
++             .mask = 0x00004000,
++             .mask_reg = QEIC_CIMR,
++             .pri_code = 1,
++             .pri_reg = QEIC_CIPWCC,
++             },
++      [3] = {
++             .mask = 0x00002000,
++             .mask_reg = QEIC_CIMR,
++             .pri_code = 2,
++             .pri_reg = QEIC_CIPWCC,
++             },
++      [10] = {
++              .mask = 0x00000040,
++              .mask_reg = QEIC_CIMR,
++              .pri_code = 1,
++              .pri_reg = QEIC_CIPZCC,
++              },
++      [11] = {
++              .mask = 0x00000020,
++              .mask_reg = QEIC_CIMR,
++              .pri_code = 2,
++              .pri_reg = QEIC_CIPZCC,
++              },
++      [12] = {
++              .mask = 0x00000010,
++              .mask_reg = QEIC_CIMR,
++              .pri_code = 3,
++              .pri_reg = QEIC_CIPZCC,
++              },
++      [13] = {
++              .mask = 0x00000008,
++              .mask_reg = QEIC_CIMR,
++              .pri_code = 4,
++              .pri_reg = QEIC_CIPZCC,
++              },
++      [14] = {
++              .mask = 0x00000004,
++              .mask_reg = QEIC_CIMR,
++              .pri_code = 5,
++              .pri_reg = QEIC_CIPZCC,
++              },
++      [15] = {
++              .mask = 0x00000002,
++              .mask_reg = QEIC_CIMR,
++              .pri_code = 6,
++              .pri_reg = QEIC_CIPZCC,
++              },
++      [20] = {
++              .mask = 0x10000000,
++              .mask_reg = QEIC_CRIMR,
++              .pri_code = 3,
++              .pri_reg = QEIC_CIPRTA,
++              },
++      [25] = {
++              .mask = 0x00800000,
++              .mask_reg = QEIC_CRIMR,
++              .pri_code = 0,
++              .pri_reg = QEIC_CIPRTB,
++              },
++      [26] = {
++              .mask = 0x00400000,
++              .mask_reg = QEIC_CRIMR,
++              .pri_code = 1,
++              .pri_reg = QEIC_CIPRTB,
++              },
++      [27] = {
++              .mask = 0x00200000,
++              .mask_reg = QEIC_CRIMR,
++              .pri_code = 2,
++              .pri_reg = QEIC_CIPRTB,
++              },
++      [28] = {
++              .mask = 0x00100000,
++              .mask_reg = QEIC_CRIMR,
++              .pri_code = 3,
++              .pri_reg = QEIC_CIPRTB,
++              },
++      [32] = {
++              .mask = 0x80000000,
++              .mask_reg = QEIC_CIMR,
++              .pri_code = 0,
++              .pri_reg = QEIC_CIPXCC,
++              },
++      [33] = {
++              .mask = 0x40000000,
++              .mask_reg = QEIC_CIMR,
++              .pri_code = 1,
++              .pri_reg = QEIC_CIPXCC,
++              },
++      [34] = {
++              .mask = 0x20000000,
++              .mask_reg = QEIC_CIMR,
++              .pri_code = 2,
++              .pri_reg = QEIC_CIPXCC,
++              },
++      [35] = {
++              .mask = 0x10000000,
++              .mask_reg = QEIC_CIMR,
++              .pri_code = 3,
++              .pri_reg = QEIC_CIPXCC,
++              },
++      [36] = {
++              .mask = 0x08000000,
++              .mask_reg = QEIC_CIMR,
++              .pri_code = 4,
++              .pri_reg = QEIC_CIPXCC,
++              },
++      [40] = {
++              .mask = 0x00800000,
++              .mask_reg = QEIC_CIMR,
++              .pri_code = 0,
++              .pri_reg = QEIC_CIPYCC,
++              },
++      [41] = {
++              .mask = 0x00400000,
++              .mask_reg = QEIC_CIMR,
++              .pri_code = 1,
++              .pri_reg = QEIC_CIPYCC,
++              },
++      [42] = {
++              .mask = 0x00200000,
++              .mask_reg = QEIC_CIMR,
++              .pri_code = 2,
++              .pri_reg = QEIC_CIPYCC,
++              },
++      [43] = {
++              .mask = 0x00100000,
++              .mask_reg = QEIC_CIMR,
++              .pri_code = 3,
++              .pri_reg = QEIC_CIPYCC,
++              },
++};
++
++static inline u32 qe_ic_read(volatile __be32  __iomem * base, unsigned int reg)
++{
++      return in_be32(base + (reg >> 2));
++}
++
++static inline void qe_ic_write(volatile __be32  __iomem * base, unsigned int reg,
++                             u32 value)
++{
++      out_be32(base + (reg >> 2), value);
++}
++
++static inline struct qe_ic *qe_ic_from_irq(unsigned int virq)
++{
++      return irq_get_chip_data(virq);
++}
++
++static inline struct qe_ic *qe_ic_from_irq_data(struct irq_data *d)
++{
++      return irq_data_get_irq_chip_data(d);
++}
++
++static void qe_ic_unmask_irq(struct irq_data *d)
++{
++      struct qe_ic *qe_ic = qe_ic_from_irq_data(d);
++      unsigned int src = irqd_to_hwirq(d);
++      unsigned long flags;
++      u32 temp;
++
++      raw_spin_lock_irqsave(&qe_ic_lock, flags);
++
++      temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
++      qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
++                  temp | qe_ic_info[src].mask);
++
++      raw_spin_unlock_irqrestore(&qe_ic_lock, flags);
++}
++
++static void qe_ic_mask_irq(struct irq_data *d)
++{
++      struct qe_ic *qe_ic = qe_ic_from_irq_data(d);
++      unsigned int src = irqd_to_hwirq(d);
++      unsigned long flags;
++      u32 temp;
++
++      raw_spin_lock_irqsave(&qe_ic_lock, flags);
++
++      temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
++      qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
++                  temp & ~qe_ic_info[src].mask);
++
++      /* Flush the above write before enabling interrupts; otherwise,
++       * spurious interrupts will sometimes happen.  To be 100% sure
++       * that the write has reached the device before interrupts are
++       * enabled, the mask register would have to be read back; however,
++       * this is not required for correctness, only to avoid wasting
++       * time on a large number of spurious interrupts.  In testing,
++       * a sync reduced the observed spurious interrupts to zero.
++       */
++      mb();
++
++      raw_spin_unlock_irqrestore(&qe_ic_lock, flags);
++}
++
++static struct irq_chip qe_ic_irq_chip = {
++      .name = "QEIC",
++      .irq_unmask = qe_ic_unmask_irq,
++      .irq_mask = qe_ic_mask_irq,
++      .irq_mask_ack = qe_ic_mask_irq,
++};
++
++static int qe_ic_host_match(struct irq_domain *h, struct device_node *node,
++                          enum irq_domain_bus_token bus_token)
++{
++      /* Exact match, unless qe_ic node is NULL */
++      struct device_node *of_node = irq_domain_get_of_node(h);
++      return of_node == NULL || of_node == node;
++}
++
++static int qe_ic_host_map(struct irq_domain *h, unsigned int virq,
++                        irq_hw_number_t hw)
++{
++      struct qe_ic *qe_ic = h->host_data;
++      struct irq_chip *chip;
++
++      if (hw >= ARRAY_SIZE(qe_ic_info)) {
++              pr_err("%s: Invalid hw irq number for QEIC\n", __func__);
++              return -EINVAL;
++      }
++
++      if (qe_ic_info[hw].mask == 0) {
++              printk(KERN_ERR "Can't map reserved IRQ\n");
++              return -EINVAL;
++      }
++      /* Default chip */
++      chip = &qe_ic->hc_irq;
++
++      irq_set_chip_data(virq, qe_ic);
++      irq_set_status_flags(virq, IRQ_LEVEL);
++
++      irq_set_chip_and_handler(virq, chip, handle_level_irq);
++
++      return 0;
++}
++
++static const struct irq_domain_ops qe_ic_host_ops = {
++      .match = qe_ic_host_match,
++      .map = qe_ic_host_map,
++      .xlate = irq_domain_xlate_onetwocell,
++};
++
++/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
++unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic)
++{
++      int irq;
++
++      BUG_ON(qe_ic == NULL);
++
++      /* get the interrupt source vector. */
++      irq = qe_ic_read(qe_ic->regs, QEIC_CIVEC) >> 26;
++
++      if (irq == 0)
++              return NO_IRQ;
++
++      return irq_linear_revmap(qe_ic->irqhost, irq);
++}
++
++/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
++unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
++{
++      int irq;
++
++      BUG_ON(qe_ic == NULL);
++
++      /* get the interrupt source vector. */
++      irq = qe_ic_read(qe_ic->regs, QEIC_CHIVEC) >> 26;
++
++      if (irq == 0)
++              return NO_IRQ;
++
++      return irq_linear_revmap(qe_ic->irqhost, irq);
++}
++
++void __init qe_ic_init(struct device_node *node, unsigned int flags,
++                     void (*low_handler)(struct irq_desc *desc),
++                     void (*high_handler)(struct irq_desc *desc))
++{
++      struct qe_ic *qe_ic;
++      struct resource res;
++      u32 temp = 0, ret, high_active = 0;
++
++      ret = of_address_to_resource(node, 0, &res);
++      if (ret)
++              return;
++
++      qe_ic = kzalloc(sizeof(*qe_ic), GFP_KERNEL);
++      if (qe_ic == NULL)
++              return;
++
++      qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS,
++                                             &qe_ic_host_ops, qe_ic);
++      if (qe_ic->irqhost == NULL) {
++              kfree(qe_ic);
++              return;
++      }
++
++      qe_ic->regs = ioremap(res.start, resource_size(&res));
++
++      qe_ic->hc_irq = qe_ic_irq_chip;
++
++      qe_ic->virq_high = irq_of_parse_and_map(node, 0);
++      qe_ic->virq_low = irq_of_parse_and_map(node, 1);
++
++      if (qe_ic->virq_low == NO_IRQ) {
++              printk(KERN_ERR "Failed to map QE_IC low IRQ\n");
++              kfree(qe_ic);
++              return;
++      }
++
++      /* default priority scheme is grouped. If spread mode is    */
++      /* required, configure cicr accordingly.                    */
++      if (flags & QE_IC_SPREADMODE_GRP_W)
++              temp |= CICR_GWCC;
++      if (flags & QE_IC_SPREADMODE_GRP_X)
++              temp |= CICR_GXCC;
++      if (flags & QE_IC_SPREADMODE_GRP_Y)
++              temp |= CICR_GYCC;
++      if (flags & QE_IC_SPREADMODE_GRP_Z)
++              temp |= CICR_GZCC;
++      if (flags & QE_IC_SPREADMODE_GRP_RISCA)
++              temp |= CICR_GRTA;
++      if (flags & QE_IC_SPREADMODE_GRP_RISCB)
++              temp |= CICR_GRTB;
++
++      /* choose destination signal for highest priority interrupt */
++      if (flags & QE_IC_HIGH_SIGNAL) {
++              temp |= (SIGNAL_HIGH << CICR_HPIT_SHIFT);
++              high_active = 1;
++      }
++
++      qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
++
++      irq_set_handler_data(qe_ic->virq_low, qe_ic);
++      irq_set_chained_handler(qe_ic->virq_low, low_handler);
++
++      if (qe_ic->virq_high != NO_IRQ &&
++                      qe_ic->virq_high != qe_ic->virq_low) {
++              irq_set_handler_data(qe_ic->virq_high, qe_ic);
++              irq_set_chained_handler(qe_ic->virq_high, high_handler);
++      }
++}
++
++void qe_ic_set_highest_priority(unsigned int virq, int high)
++{
++      struct qe_ic *qe_ic = qe_ic_from_irq(virq);
++      unsigned int src = virq_to_hw(virq);
++      u32 temp = 0;
++
++      temp = qe_ic_read(qe_ic->regs, QEIC_CICR);
++
++      temp &= ~CICR_HP_MASK;
++      temp |= src << CICR_HP_SHIFT;
++
++      temp &= ~CICR_HPIT_MASK;
++      temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << CICR_HPIT_SHIFT;
++
++      qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
++}
++
++/* Set Priority level within its group, from 1 to 8 */
++int qe_ic_set_priority(unsigned int virq, unsigned int priority)
++{
++      struct qe_ic *qe_ic = qe_ic_from_irq(virq);
++      unsigned int src = virq_to_hw(virq);
++      u32 temp;
++
++      if (priority > 8 || priority == 0)
++              return -EINVAL;
++      if (WARN_ONCE(src >= ARRAY_SIZE(qe_ic_info),
++                    "%s: Invalid hw irq number for QEIC\n", __func__))
++              return -EINVAL;
++      if (qe_ic_info[src].pri_reg == 0)
++              return -EINVAL;
++
++      temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].pri_reg);
++
++      if (priority < 4) {
++              temp &= ~(0x7 << (32 - priority * 3));
++              temp |= qe_ic_info[src].pri_code << (32 - priority * 3);
++      } else {
++              temp &= ~(0x7 << (24 - priority * 3));
++              temp |= qe_ic_info[src].pri_code << (24 - priority * 3);
++      }
++
++      qe_ic_write(qe_ic->regs, qe_ic_info[src].pri_reg, temp);
++
++      return 0;
++}
++
++/* Set a QE priority to use high irq, only priority 1~2 can use high irq */
++int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high)
++{
++      struct qe_ic *qe_ic = qe_ic_from_irq(virq);
++      unsigned int src = virq_to_hw(virq);
++      u32 temp, control_reg = QEIC_CICNR, shift = 0;
++
++      if (priority > 2 || priority == 0)
++              return -EINVAL;
++      if (WARN_ONCE(src >= ARRAY_SIZE(qe_ic_info),
++                    "%s: Invalid hw irq number for QEIC\n", __func__))
++              return -EINVAL;
++
++      switch (qe_ic_info[src].pri_reg) {
++      case QEIC_CIPZCC:
++              shift = CICNR_ZCC1T_SHIFT;
++              break;
++      case QEIC_CIPWCC:
++              shift = CICNR_WCC1T_SHIFT;
++              break;
++      case QEIC_CIPYCC:
++              shift = CICNR_YCC1T_SHIFT;
++              break;
++      case QEIC_CIPXCC:
++              shift = CICNR_XCC1T_SHIFT;
++              break;
++      case QEIC_CIPRTA:
++              shift = CRICR_RTA1T_SHIFT;
++              control_reg = QEIC_CRICR;
++              break;
++      case QEIC_CIPRTB:
++              shift = CRICR_RTB1T_SHIFT;
++              control_reg = QEIC_CRICR;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      shift += (2 - priority) * 2;
++      temp = qe_ic_read(qe_ic->regs, control_reg);
++      temp &= ~(SIGNAL_MASK << shift);
++      temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << shift;
++      qe_ic_write(qe_ic->regs, control_reg, temp);
++
++      return 0;
++}
++
++static struct bus_type qe_ic_subsys = {
++      .name = "qe_ic",
++      .dev_name = "qe_ic",
++};
++
++static struct device device_qe_ic = {
++      .id = 0,
++      .bus = &qe_ic_subsys,
++};
++
++static int __init init_qe_ic_sysfs(void)
++{
++      int rc;
++
++      printk(KERN_DEBUG "Registering qe_ic with sysfs...\n");
++
++      rc = subsys_system_register(&qe_ic_subsys, NULL);
++      if (rc) {
++              printk(KERN_ERR "Failed registering qe_ic sys class\n");
++              return -ENODEV;
++      }
++      rc = device_register(&device_qe_ic);
++      if (rc) {
++              printk(KERN_ERR "Failed registering qe_ic sys device\n");
++              return -ENODEV;
++      }
++      return 0;
++}
++
++subsys_initcall(init_qe_ic_sysfs);
+--- a/drivers/soc/fsl/qe/Makefile
++++ b/drivers/soc/fsl/qe/Makefile
+@@ -2,7 +2,7 @@
+ #
+ # Makefile for the linux ppc-specific parts of QE
+ #
+-obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_common.o qe_ic.o qe_io.o
++obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_common.o qe_io.o
+ obj-$(CONFIG_CPM)     += qe_common.o
+ obj-$(CONFIG_UCC)     += ucc.o
+ obj-$(CONFIG_UCC_SLOW)        += ucc_slow.o
+--- a/drivers/soc/fsl/qe/qe_ic.c
++++ /dev/null
+@@ -1,508 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * arch/powerpc/sysdev/qe_lib/qe_ic.c
+- *
+- * Copyright (C) 2006 Freescale Semiconductor, Inc.  All rights reserved.
+- *
+- * Author: Li Yang <leoli@freescale.com>
+- * Based on code from Shlomi Gridish <gridish@freescale.com>
+- *
+- * QUICC ENGINE Interrupt Controller
+- */
+-
+-#include <linux/of_irq.h>
+-#include <linux/of_address.h>
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/errno.h>
+-#include <linux/reboot.h>
+-#include <linux/slab.h>
+-#include <linux/stddef.h>
+-#include <linux/sched.h>
+-#include <linux/signal.h>
+-#include <linux/device.h>
+-#include <linux/spinlock.h>
+-#include <asm/irq.h>
+-#include <asm/io.h>
+-#include <soc/fsl/qe/qe_ic.h>
+-
+-#include "qe_ic.h"
+-
+-static DEFINE_RAW_SPINLOCK(qe_ic_lock);
+-
+-static struct qe_ic_info qe_ic_info[] = {
+-      [1] = {
+-             .mask = 0x00008000,
+-             .mask_reg = QEIC_CIMR,
+-             .pri_code = 0,
+-             .pri_reg = QEIC_CIPWCC,
+-             },
+-      [2] = {
+-             .mask = 0x00004000,
+-             .mask_reg = QEIC_CIMR,
+-             .pri_code = 1,
+-             .pri_reg = QEIC_CIPWCC,
+-             },
+-      [3] = {
+-             .mask = 0x00002000,
+-             .mask_reg = QEIC_CIMR,
+-             .pri_code = 2,
+-             .pri_reg = QEIC_CIPWCC,
+-             },
+-      [10] = {
+-              .mask = 0x00000040,
+-              .mask_reg = QEIC_CIMR,
+-              .pri_code = 1,
+-              .pri_reg = QEIC_CIPZCC,
+-              },
+-      [11] = {
+-              .mask = 0x00000020,
+-              .mask_reg = QEIC_CIMR,
+-              .pri_code = 2,
+-              .pri_reg = QEIC_CIPZCC,
+-              },
+-      [12] = {
+-              .mask = 0x00000010,
+-              .mask_reg = QEIC_CIMR,
+-              .pri_code = 3,
+-              .pri_reg = QEIC_CIPZCC,
+-              },
+-      [13] = {
+-              .mask = 0x00000008,
+-              .mask_reg = QEIC_CIMR,
+-              .pri_code = 4,
+-              .pri_reg = QEIC_CIPZCC,
+-              },
+-      [14] = {
+-              .mask = 0x00000004,
+-              .mask_reg = QEIC_CIMR,
+-              .pri_code = 5,
+-              .pri_reg = QEIC_CIPZCC,
+-              },
+-      [15] = {
+-              .mask = 0x00000002,
+-              .mask_reg = QEIC_CIMR,
+-              .pri_code = 6,
+-              .pri_reg = QEIC_CIPZCC,
+-              },
+-      [20] = {
+-              .mask = 0x10000000,
+-              .mask_reg = QEIC_CRIMR,
+-              .pri_code = 3,
+-              .pri_reg = QEIC_CIPRTA,
+-              },
+-      [25] = {
+-              .mask = 0x00800000,
+-              .mask_reg = QEIC_CRIMR,
+-              .pri_code = 0,
+-              .pri_reg = QEIC_CIPRTB,
+-              },
+-      [26] = {
+-              .mask = 0x00400000,
+-              .mask_reg = QEIC_CRIMR,
+-              .pri_code = 1,
+-              .pri_reg = QEIC_CIPRTB,
+-              },
+-      [27] = {
+-              .mask = 0x00200000,
+-              .mask_reg = QEIC_CRIMR,
+-              .pri_code = 2,
+-              .pri_reg = QEIC_CIPRTB,
+-              },
+-      [28] = {
+-              .mask = 0x00100000,
+-              .mask_reg = QEIC_CRIMR,
+-              .pri_code = 3,
+-              .pri_reg = QEIC_CIPRTB,
+-              },
+-      [32] = {
+-              .mask = 0x80000000,
+-              .mask_reg = QEIC_CIMR,
+-              .pri_code = 0,
+-              .pri_reg = QEIC_CIPXCC,
+-              },
+-      [33] = {
+-              .mask = 0x40000000,
+-              .mask_reg = QEIC_CIMR,
+-              .pri_code = 1,
+-              .pri_reg = QEIC_CIPXCC,
+-              },
+-      [34] = {
+-              .mask = 0x20000000,
+-              .mask_reg = QEIC_CIMR,
+-              .pri_code = 2,
+-              .pri_reg = QEIC_CIPXCC,
+-              },
+-      [35] = {
+-              .mask = 0x10000000,
+-              .mask_reg = QEIC_CIMR,
+-              .pri_code = 3,
+-              .pri_reg = QEIC_CIPXCC,
+-              },
+-      [36] = {
+-              .mask = 0x08000000,
+-              .mask_reg = QEIC_CIMR,
+-              .pri_code = 4,
+-              .pri_reg = QEIC_CIPXCC,
+-              },
+-      [40] = {
+-              .mask = 0x00800000,
+-              .mask_reg = QEIC_CIMR,
+-              .pri_code = 0,
+-              .pri_reg = QEIC_CIPYCC,
+-              },
+-      [41] = {
+-              .mask = 0x00400000,
+-              .mask_reg = QEIC_CIMR,
+-              .pri_code = 1,
+-              .pri_reg = QEIC_CIPYCC,
+-              },
+-      [42] = {
+-              .mask = 0x00200000,
+-              .mask_reg = QEIC_CIMR,
+-              .pri_code = 2,
+-              .pri_reg = QEIC_CIPYCC,
+-              },
+-      [43] = {
+-              .mask = 0x00100000,
+-              .mask_reg = QEIC_CIMR,
+-              .pri_code = 3,
+-              .pri_reg = QEIC_CIPYCC,
+-              },
+-};
+-
+-static inline u32 qe_ic_read(volatile __be32  __iomem * base, unsigned int reg)
+-{
+-      return in_be32(base + (reg >> 2));
+-}
+-
+-static inline void qe_ic_write(volatile __be32  __iomem * base, unsigned int reg,
+-                             u32 value)
+-{
+-      out_be32(base + (reg >> 2), value);
+-}
+-
+-static inline struct qe_ic *qe_ic_from_irq(unsigned int virq)
+-{
+-      return irq_get_chip_data(virq);
+-}
+-
+-static inline struct qe_ic *qe_ic_from_irq_data(struct irq_data *d)
+-{
+-      return irq_data_get_irq_chip_data(d);
+-}
+-
+-static void qe_ic_unmask_irq(struct irq_data *d)
+-{
+-      struct qe_ic *qe_ic = qe_ic_from_irq_data(d);
+-      unsigned int src = irqd_to_hwirq(d);
+-      unsigned long flags;
+-      u32 temp;
+-
+-      raw_spin_lock_irqsave(&qe_ic_lock, flags);
+-
+-      temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
+-      qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
+-                  temp | qe_ic_info[src].mask);
+-
+-      raw_spin_unlock_irqrestore(&qe_ic_lock, flags);
+-}
+-
+-static void qe_ic_mask_irq(struct irq_data *d)
+-{
+-      struct qe_ic *qe_ic = qe_ic_from_irq_data(d);
+-      unsigned int src = irqd_to_hwirq(d);
+-      unsigned long flags;
+-      u32 temp;
+-
+-      raw_spin_lock_irqsave(&qe_ic_lock, flags);
+-
+-      temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
+-      qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
+-                  temp & ~qe_ic_info[src].mask);
+-
+-      /* Flush the above write before enabling interrupts; otherwise,
+-       * spurious interrupts will sometimes happen.  To be 100% sure
+-       * that the write has reached the device before interrupts are
+-       * enabled, the mask register would have to be read back; however,
+-       * this is not required for correctness, only to avoid wasting
+-       * time on a large number of spurious interrupts.  In testing,
+-       * a sync reduced the observed spurious interrupts to zero.
+-       */
+-      mb();
+-
+-      raw_spin_unlock_irqrestore(&qe_ic_lock, flags);
+-}
+-
+-static struct irq_chip qe_ic_irq_chip = {
+-      .name = "QEIC",
+-      .irq_unmask = qe_ic_unmask_irq,
+-      .irq_mask = qe_ic_mask_irq,
+-      .irq_mask_ack = qe_ic_mask_irq,
+-};
+-
+-static int qe_ic_host_match(struct irq_domain *h, struct device_node *node,
+-                          enum irq_domain_bus_token bus_token)
+-{
+-      /* Exact match, unless qe_ic node is NULL */
+-      struct device_node *of_node = irq_domain_get_of_node(h);
+-      return of_node == NULL || of_node == node;
+-}
+-
+-static int qe_ic_host_map(struct irq_domain *h, unsigned int virq,
+-                        irq_hw_number_t hw)
+-{
+-      struct qe_ic *qe_ic = h->host_data;
+-      struct irq_chip *chip;
+-
+-      if (hw >= ARRAY_SIZE(qe_ic_info)) {
+-              pr_err("%s: Invalid hw irq number for QEIC\n", __func__);
+-              return -EINVAL;
+-      }
+-
+-      if (qe_ic_info[hw].mask == 0) {
+-              printk(KERN_ERR "Can't map reserved IRQ\n");
+-              return -EINVAL;
+-      }
+-      /* Default chip */
+-      chip = &qe_ic->hc_irq;
+-
+-      irq_set_chip_data(virq, qe_ic);
+-      irq_set_status_flags(virq, IRQ_LEVEL);
+-
+-      irq_set_chip_and_handler(virq, chip, handle_level_irq);
+-
+-      return 0;
+-}
+-
+-static const struct irq_domain_ops qe_ic_host_ops = {
+-      .match = qe_ic_host_match,
+-      .map = qe_ic_host_map,
+-      .xlate = irq_domain_xlate_onetwocell,
+-};
+-
+-/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+-unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic)
+-{
+-      int irq;
+-
+-      BUG_ON(qe_ic == NULL);
+-
+-      /* get the interrupt source vector. */
+-      irq = qe_ic_read(qe_ic->regs, QEIC_CIVEC) >> 26;
+-
+-      if (irq == 0)
+-              return NO_IRQ;
+-
+-      return irq_linear_revmap(qe_ic->irqhost, irq);
+-}
+-
+-/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+-unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
+-{
+-      int irq;
+-
+-      BUG_ON(qe_ic == NULL);
+-
+-      /* get the interrupt source vector. */
+-      irq = qe_ic_read(qe_ic->regs, QEIC_CHIVEC) >> 26;
+-
+-      if (irq == 0)
+-              return NO_IRQ;
+-
+-      return irq_linear_revmap(qe_ic->irqhost, irq);
+-}
+-
+-void __init qe_ic_init(struct device_node *node, unsigned int flags,
+-                     void (*low_handler)(struct irq_desc *desc),
+-                     void (*high_handler)(struct irq_desc *desc))
+-{
+-      struct qe_ic *qe_ic;
+-      struct resource res;
+-      u32 temp = 0, ret, high_active = 0;
+-
+-      ret = of_address_to_resource(node, 0, &res);
+-      if (ret)
+-              return;
+-
+-      qe_ic = kzalloc(sizeof(*qe_ic), GFP_KERNEL);
+-      if (qe_ic == NULL)
+-              return;
+-
+-      qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS,
+-                                             &qe_ic_host_ops, qe_ic);
+-      if (qe_ic->irqhost == NULL) {
+-              kfree(qe_ic);
+-              return;
+-      }
+-
+-      qe_ic->regs = ioremap(res.start, resource_size(&res));
+-
+-      qe_ic->hc_irq = qe_ic_irq_chip;
+-
+-      qe_ic->virq_high = irq_of_parse_and_map(node, 0);
+-      qe_ic->virq_low = irq_of_parse_and_map(node, 1);
+-
+-      if (qe_ic->virq_low == NO_IRQ) {
+-              printk(KERN_ERR "Failed to map QE_IC low IRQ\n");
+-              kfree(qe_ic);
+-              return;
+-      }
+-
+-      /* default priority scheme is grouped. If spread mode is    */
+-      /* required, configure cicr accordingly.                    */
+-      if (flags & QE_IC_SPREADMODE_GRP_W)
+-              temp |= CICR_GWCC;
+-      if (flags & QE_IC_SPREADMODE_GRP_X)
+-              temp |= CICR_GXCC;
+-      if (flags & QE_IC_SPREADMODE_GRP_Y)
+-              temp |= CICR_GYCC;
+-      if (flags & QE_IC_SPREADMODE_GRP_Z)
+-              temp |= CICR_GZCC;
+-      if (flags & QE_IC_SPREADMODE_GRP_RISCA)
+-              temp |= CICR_GRTA;
+-      if (flags & QE_IC_SPREADMODE_GRP_RISCB)
+-              temp |= CICR_GRTB;
+-
+-      /* choose destination signal for highest priority interrupt */
+-      if (flags & QE_IC_HIGH_SIGNAL) {
+-              temp |= (SIGNAL_HIGH << CICR_HPIT_SHIFT);
+-              high_active = 1;
+-      }
+-
+-      qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
+-
+-      irq_set_handler_data(qe_ic->virq_low, qe_ic);
+-      irq_set_chained_handler(qe_ic->virq_low, low_handler);
+-
+-      if (qe_ic->virq_high != NO_IRQ &&
+-                      qe_ic->virq_high != qe_ic->virq_low) {
+-              irq_set_handler_data(qe_ic->virq_high, qe_ic);
+-              irq_set_chained_handler(qe_ic->virq_high, high_handler);
+-      }
+-}
+-
+-void qe_ic_set_highest_priority(unsigned int virq, int high)
+-{
+-      struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+-      unsigned int src = virq_to_hw(virq);
+-      u32 temp = 0;
+-
+-      temp = qe_ic_read(qe_ic->regs, QEIC_CICR);
+-
+-      temp &= ~CICR_HP_MASK;
+-      temp |= src << CICR_HP_SHIFT;
+-
+-      temp &= ~CICR_HPIT_MASK;
+-      temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << CICR_HPIT_SHIFT;
+-
+-      qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
+-}
+-
+-/* Set Priority level within its group, from 1 to 8 */
+-int qe_ic_set_priority(unsigned int virq, unsigned int priority)
+-{
+-      struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+-      unsigned int src = virq_to_hw(virq);
+-      u32 temp;
+-
+-      if (priority > 8 || priority == 0)
+-              return -EINVAL;
+-      if (WARN_ONCE(src >= ARRAY_SIZE(qe_ic_info),
+-                    "%s: Invalid hw irq number for QEIC\n", __func__))
+-              return -EINVAL;
+-      if (qe_ic_info[src].pri_reg == 0)
+-              return -EINVAL;
+-
+-      temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].pri_reg);
+-
+-      if (priority < 4) {
+-              temp &= ~(0x7 << (32 - priority * 3));
+-              temp |= qe_ic_info[src].pri_code << (32 - priority * 3);
+-      } else {
+-              temp &= ~(0x7 << (24 - priority * 3));
+-              temp |= qe_ic_info[src].pri_code << (24 - priority * 3);
+-      }
+-
+-      qe_ic_write(qe_ic->regs, qe_ic_info[src].pri_reg, temp);
+-
+-      return 0;
+-}
+-
+-/* Set a QE priority to use high irq, only priority 1~2 can use high irq */
+-int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high)
+-{
+-      struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+-      unsigned int src = virq_to_hw(virq);
+-      u32 temp, control_reg = QEIC_CICNR, shift = 0;
+-
+-      if (priority > 2 || priority == 0)
+-              return -EINVAL;
+-      if (WARN_ONCE(src >= ARRAY_SIZE(qe_ic_info),
+-                    "%s: Invalid hw irq number for QEIC\n", __func__))
+-              return -EINVAL;
+-
+-      switch (qe_ic_info[src].pri_reg) {
+-      case QEIC_CIPZCC:
+-              shift = CICNR_ZCC1T_SHIFT;
+-              break;
+-      case QEIC_CIPWCC:
+-              shift = CICNR_WCC1T_SHIFT;
+-              break;
+-      case QEIC_CIPYCC:
+-              shift = CICNR_YCC1T_SHIFT;
+-              break;
+-      case QEIC_CIPXCC:
+-              shift = CICNR_XCC1T_SHIFT;
+-              break;
+-      case QEIC_CIPRTA:
+-              shift = CRICR_RTA1T_SHIFT;
+-              control_reg = QEIC_CRICR;
+-              break;
+-      case QEIC_CIPRTB:
+-              shift = CRICR_RTB1T_SHIFT;
+-              control_reg = QEIC_CRICR;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      shift += (2 - priority) * 2;
+-      temp = qe_ic_read(qe_ic->regs, control_reg);
+-      temp &= ~(SIGNAL_MASK << shift);
+-      temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << shift;
+-      qe_ic_write(qe_ic->regs, control_reg, temp);
+-
+-      return 0;
+-}
+-
+-static struct bus_type qe_ic_subsys = {
+-      .name = "qe_ic",
+-      .dev_name = "qe_ic",
+-};
+-
+-static struct device device_qe_ic = {
+-      .id = 0,
+-      .bus = &qe_ic_subsys,
+-};
+-
+-static int __init init_qe_ic_sysfs(void)
+-{
+-      int rc;
+-
+-      printk(KERN_DEBUG "Registering qe_ic with sysfs...\n");
+-
+-      rc = subsys_system_register(&qe_ic_subsys, NULL);
+-      if (rc) {
+-              printk(KERN_ERR "Failed registering qe_ic sys class\n");
+-              return -ENODEV;
+-      }
+-      rc = device_register(&device_qe_ic);
+-      if (rc) {
+-              printk(KERN_ERR "Failed registering qe_ic sys device\n");
+-              return -ENODEV;
+-      }
+-      return 0;
+-}
+-
+-subsys_initcall(init_qe_ic_sysfs);
+--- a/drivers/soc/fsl/qe/qe_ic.h
++++ /dev/null
+@@ -1,99 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0-or-later */
+-/*
+- * drivers/soc/fsl/qe/qe_ic.h
+- *
+- * QUICC ENGINE Interrupt Controller Header
+- *
+- * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
+- *
+- * Author: Li Yang <leoli@freescale.com>
+- * Based on code from Shlomi Gridish <gridish@freescale.com>
+- */
+-#ifndef _POWERPC_SYSDEV_QE_IC_H
+-#define _POWERPC_SYSDEV_QE_IC_H
+-
+-#include <soc/fsl/qe/qe_ic.h>
+-
+-#define NR_QE_IC_INTS         64
+-
+-/* QE IC registers offset */
+-#define QEIC_CICR             0x00
+-#define QEIC_CIVEC            0x04
+-#define QEIC_CRIPNR           0x08
+-#define QEIC_CIPNR            0x0c
+-#define QEIC_CIPXCC           0x10
+-#define QEIC_CIPYCC           0x14
+-#define QEIC_CIPWCC           0x18
+-#define QEIC_CIPZCC           0x1c
+-#define QEIC_CIMR             0x20
+-#define QEIC_CRIMR            0x24
+-#define QEIC_CICNR            0x28
+-#define QEIC_CIPRTA           0x30
+-#define QEIC_CIPRTB           0x34
+-#define QEIC_CRICR            0x3c
+-#define QEIC_CHIVEC           0x60
+-
+-/* Interrupt priority registers */
+-#define CIPCC_SHIFT_PRI0      29
+-#define CIPCC_SHIFT_PRI1      26
+-#define CIPCC_SHIFT_PRI2      23
+-#define CIPCC_SHIFT_PRI3      20
+-#define CIPCC_SHIFT_PRI4      13
+-#define CIPCC_SHIFT_PRI5      10
+-#define CIPCC_SHIFT_PRI6      7
+-#define CIPCC_SHIFT_PRI7      4
+-
+-/* CICR priority modes */
+-#define CICR_GWCC             0x00040000
+-#define CICR_GXCC             0x00020000
+-#define CICR_GYCC             0x00010000
+-#define CICR_GZCC             0x00080000
+-#define CICR_GRTA             0x00200000
+-#define CICR_GRTB             0x00400000
+-#define CICR_HPIT_SHIFT               8
+-#define CICR_HPIT_MASK                0x00000300
+-#define CICR_HP_SHIFT         24
+-#define CICR_HP_MASK          0x3f000000
+-
+-/* CICNR */
+-#define CICNR_WCC1T_SHIFT     20
+-#define CICNR_ZCC1T_SHIFT     28
+-#define CICNR_YCC1T_SHIFT     12
+-#define CICNR_XCC1T_SHIFT     4
+-
+-/* CRICR */
+-#define CRICR_RTA1T_SHIFT     20
+-#define CRICR_RTB1T_SHIFT     28
+-
+-/* Signal indicator */
+-#define SIGNAL_MASK           3
+-#define SIGNAL_HIGH           2
+-#define SIGNAL_LOW            0
+-
+-struct qe_ic {
+-      /* Control registers offset */
+-      volatile u32 __iomem *regs;
+-
+-      /* The remapper for this QEIC */
+-      struct irq_domain *irqhost;
+-
+-      /* The "linux" controller struct */
+-      struct irq_chip hc_irq;
+-
+-      /* VIRQ numbers of QE high/low irqs */
+-      unsigned int virq_high;
+-      unsigned int virq_low;
+-};
+-
+-/*
+- * QE interrupt controller internal structure
+- */
+-struct qe_ic_info {
+-      u32     mask;     /* location of this source at the QIMR register. */
+-      u32     mask_reg; /* Mask register offset */
+-      u8      pri_code; /* for grouped interrupts sources - the interrupt
+-                           code as appears at the group priority register */
+-      u32     pri_reg;  /* Group priority register offset */
+-};
+-
+-#endif /* _POWERPC_SYSDEV_QE_IC_H */
diff --git a/target/linux/layerscape/patches-5.4/814-qe-0002-irqchip-qeic-merge-qeic-init-code-from-platforms-to-.patch b/target/linux/layerscape/patches-5.4/814-qe-0002-irqchip-qeic-merge-qeic-init-code-from-platforms-to-.patch
new file mode 100644 (file)
index 0000000..73656ce
--- /dev/null
@@ -0,0 +1,40 @@
+From 61c30dbddd180c5bc0d544a81970765a009f7deb Mon Sep 17 00:00:00 2001
+From: Zhao Qiang <qiang.zhao@nxp.com>
+Date: Thu, 27 Apr 2017 09:54:22 +0800
+Subject: [PATCH] irqchip/qeic: merge qeic init code from platforms to a common
+ function
+
+The codes of qe_ic init from a variety of platforms are redundant,
+merge them to a common function and put it to irqchip/irq-qeic.c
+
+For non-p1021_mds mpc85xx_mds boards, use "qe_ic_init(np, 0,
+qe_ic_cascade_low_mpic, qe_ic_cascade_high_mpic);" instead of
+"qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL);".
+
+qe_ic_cascade_muxed_mpic was used for boards has the same interrupt
+number for low interrupt and high interrupt, qe_ic_init has checked
+if "low interrupt == high interrupt"
+
+Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
+---
+ drivers/irqchip/irq-qeic.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/drivers/irqchip/irq-qeic.c
++++ b/drivers/irqchip/irq-qeic.c
+@@ -594,4 +594,15 @@ static int __init init_qe_ic_sysfs(void)
+       return 0;
+ }
++static int __init qeic_of_init(struct device_node *node,
++                             struct device_node *parent)
++{
++      if (!node)
++              return;
++      qe_ic_init(node, 0, qe_ic_cascade_low_mpic,
++                 qe_ic_cascade_high_mpic);
++      of_node_put(node);
++}
++
++IRQCHIP_DECLARE(qeic, "fsl,qe-ic", qeic_of_init);
+ subsys_initcall(init_qe_ic_sysfs);
diff --git a/target/linux/layerscape/patches-5.4/814-qe-0003-irqchip-qeic-merge-qeic_of_init-into-qe_ic_init.patch b/target/linux/layerscape/patches-5.4/814-qe-0003-irqchip-qeic-merge-qeic_of_init-into-qe_ic_init.patch
new file mode 100644 (file)
index 0000000..877cd94
--- /dev/null
@@ -0,0 +1,173 @@
+From 25694a71e1958a4d72891b99b6a2805b7a7bffff Mon Sep 17 00:00:00 2001
+From: Zhao Qiang <qiang.zhao@nxp.com>
+Date: Tue, 14 Mar 2017 10:40:38 +0800
+Subject: [PATCH] irqchip/qeic: merge qeic_of_init into qe_ic_init
+
+qeic_of_init just get device_node of qeic from dtb and call qe_ic_init,
+pass the device_node to qe_ic_init.
+So merge qeic_of_init into qe_ic_init to get the qeic node in
+qe_ic_init.
+
+Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
+---
+ drivers/irqchip/irq-qeic.c | 89 ++++++++++++++++++++--------------------------
+ include/soc/fsl/qe/qe_ic.h |  7 ----
+ 2 files changed, 39 insertions(+), 57 deletions(-)
+
+--- a/drivers/irqchip/irq-qeic.c
++++ b/drivers/irqchip/irq-qeic.c
+@@ -402,27 +402,33 @@ unsigned int qe_ic_get_high_irq(struct q
+       return irq_linear_revmap(qe_ic->irqhost, irq);
+ }
+-void __init qe_ic_init(struct device_node *node, unsigned int flags,
+-                     void (*low_handler)(struct irq_desc *desc),
+-                     void (*high_handler)(struct irq_desc *desc))
++static int __init qe_ic_init(struct device_node *node, unsigned int flags)
+ {
+       struct qe_ic *qe_ic;
+       struct resource res;
+-      u32 temp = 0, ret, high_active = 0;
++      u32 temp = 0, high_active = 0;
++      int ret = 0;
++
++      if (!node)
++              return -ENODEV;
+       ret = of_address_to_resource(node, 0, &res);
+-      if (ret)
+-              return;
++      if (ret) {
++              ret = -ENODEV;
++              goto err_put_node;
++      }
+       qe_ic = kzalloc(sizeof(*qe_ic), GFP_KERNEL);
+-      if (qe_ic == NULL)
+-              return;
++      if (qe_ic == NULL) {
++              ret = -ENOMEM;
++              goto err_put_node;
++      }
+       qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS,
+                                              &qe_ic_host_ops, qe_ic);
+       if (qe_ic->irqhost == NULL) {
+-              kfree(qe_ic);
+-              return;
++              ret = -ENOMEM;
++              goto err_free_qe_ic;
+       }
+       qe_ic->regs = ioremap(res.start, resource_size(&res));
+@@ -433,9 +439,9 @@ void __init qe_ic_init(struct device_nod
+       qe_ic->virq_low = irq_of_parse_and_map(node, 1);
+       if (qe_ic->virq_low == NO_IRQ) {
+-              printk(KERN_ERR "Failed to map QE_IC low IRQ\n");
+-              kfree(qe_ic);
+-              return;
++              pr_err("Failed to map QE_IC low IRQ\n");
++              ret = -ENOMEM;
++              goto err_domain_remove;
+       }
+       /* default priority scheme is grouped. If spread mode is    */
+@@ -462,13 +468,24 @@ void __init qe_ic_init(struct device_nod
+       qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
+       irq_set_handler_data(qe_ic->virq_low, qe_ic);
+-      irq_set_chained_handler(qe_ic->virq_low, low_handler);
++      irq_set_chained_handler(qe_ic->virq_low, qe_ic_cascade_low_mpic);
+       if (qe_ic->virq_high != NO_IRQ &&
+                       qe_ic->virq_high != qe_ic->virq_low) {
+               irq_set_handler_data(qe_ic->virq_high, qe_ic);
+-              irq_set_chained_handler(qe_ic->virq_high, high_handler);
++              irq_set_chained_handler(qe_ic->virq_high,
++                                      qe_ic_cascade_high_mpic);
+       }
++      of_node_put(node);
++      return 0;
++
++err_domain_remove:
++      irq_domain_remove(qe_ic->irqhost);
++err_free_qe_ic:
++      kfree(qe_ic);
++err_put_node:
++      of_node_put(node);
++      return ret;
+ }
+ void qe_ic_set_highest_priority(unsigned int virq, int high)
+@@ -565,44 +582,16 @@ int qe_ic_set_high_priority(unsigned int
+       return 0;
+ }
+-static struct bus_type qe_ic_subsys = {
+-      .name = "qe_ic",
+-      .dev_name = "qe_ic",
+-};
+-
+-static struct device device_qe_ic = {
+-      .id = 0,
+-      .bus = &qe_ic_subsys,
+-};
+-
+-static int __init init_qe_ic_sysfs(void)
++static int __init init_qe_ic(struct device_node *node,
++                           struct device_node *parent)
+ {
+-      int rc;
++      int ret;
+-      printk(KERN_DEBUG "Registering qe_ic with sysfs...\n");
++      ret = qe_ic_init(node, 0);
++      if (ret)
++              return ret;
+-      rc = subsys_system_register(&qe_ic_subsys, NULL);
+-      if (rc) {
+-              printk(KERN_ERR "Failed registering qe_ic sys class\n");
+-              return -ENODEV;
+-      }
+-      rc = device_register(&device_qe_ic);
+-      if (rc) {
+-              printk(KERN_ERR "Failed registering qe_ic sys device\n");
+-              return -ENODEV;
+-      }
+       return 0;
+ }
+-static int __init qeic_of_init(struct device_node *node,
+-                             struct device_node *parent)
+-{
+-      if (!node)
+-              return;
+-      qe_ic_init(node, 0, qe_ic_cascade_low_mpic,
+-                 qe_ic_cascade_high_mpic);
+-      of_node_put(node);
+-}
+-
+-IRQCHIP_DECLARE(qeic, "fsl,qe-ic", qeic_of_init);
+-subsys_initcall(init_qe_ic_sysfs);
++IRQCHIP_DECLARE(qeic, "fsl,qe-ic", init_qe_ic);
+--- a/include/soc/fsl/qe/qe_ic.h
++++ b/include/soc/fsl/qe/qe_ic.h
+@@ -54,16 +54,9 @@ enum qe_ic_grp_id {
+ };
+ #ifdef CONFIG_QUICC_ENGINE
+-void qe_ic_init(struct device_node *node, unsigned int flags,
+-              void (*low_handler)(struct irq_desc *desc),
+-              void (*high_handler)(struct irq_desc *desc));
+ unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic);
+ unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic);
+ #else
+-static inline void qe_ic_init(struct device_node *node, unsigned int flags,
+-              void (*low_handler)(struct irq_desc *desc),
+-              void (*high_handler)(struct irq_desc *desc))
+-{}
+ static inline unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic)
+ { return 0; }
+ static inline unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
diff --git a/target/linux/layerscape/patches-5.4/814-qe-0004-irqchip-qeic-remove-PPCisms-for-QEIC.patch b/target/linux/layerscape/patches-5.4/814-qe-0004-irqchip-qeic-remove-PPCisms-for-QEIC.patch
new file mode 100644 (file)
index 0000000..fbb6867
--- /dev/null
@@ -0,0 +1,453 @@
+From c9e8d4b75d48f02731f25e55247017d60c59d510 Mon Sep 17 00:00:00 2001
+From: Zhao Qiang <qiang.zhao@nxp.com>
+Date: Thu, 27 Apr 2017 09:56:20 +0800
+Subject: [PATCH] irqchip/qeic: remove PPCisms for QEIC
+
+QEIC was supported on PowerPC, and dependent on PPC,
+Now it is supported on other platforms, so remove PPCisms.
+
+Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
+---
+ drivers/irqchip/irq-qeic.c | 220 +++++++++++++++++++++++----------------------
+ include/soc/fsl/qe/qe_ic.h | 128 --------------------------
+ 2 files changed, 112 insertions(+), 236 deletions(-)
+ delete mode 100644 include/soc/fsl/qe/qe_ic.h
+
+--- a/drivers/irqchip/irq-qeic.c
++++ b/drivers/irqchip/irq-qeic.c
+@@ -14,7 +14,11 @@
+ #include <linux/of_address.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
++#include <linux/irqdomain.h>
++#include <linux/irqchip.h>
+ #include <linux/errno.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
+ #include <linux/reboot.h>
+ #include <linux/slab.h>
+ #include <linux/stddef.h>
+@@ -22,9 +26,8 @@
+ #include <linux/signal.h>
+ #include <linux/device.h>
+ #include <linux/spinlock.h>
+-#include <asm/irq.h>
++#include <linux/irq.h>
+ #include <asm/io.h>
+-#include <soc/fsl/qe/qe_ic.h>
+ #define NR_QE_IC_INTS         64
+@@ -82,6 +85,43 @@
+ #define SIGNAL_HIGH           2
+ #define SIGNAL_LOW            0
++#define NUM_OF_QE_IC_GROUPS   6
++
++/* Flags when we init the QE IC */
++#define QE_IC_SPREADMODE_GRP_W                        0x00000001
++#define QE_IC_SPREADMODE_GRP_X                        0x00000002
++#define QE_IC_SPREADMODE_GRP_Y                        0x00000004
++#define QE_IC_SPREADMODE_GRP_Z                        0x00000008
++#define QE_IC_SPREADMODE_GRP_RISCA            0x00000010
++#define QE_IC_SPREADMODE_GRP_RISCB            0x00000020
++
++#define QE_IC_LOW_SIGNAL                      0x00000100
++#define QE_IC_HIGH_SIGNAL                     0x00000200
++
++#define QE_IC_GRP_W_PRI0_DEST_SIGNAL_HIGH     0x00001000
++#define QE_IC_GRP_W_PRI1_DEST_SIGNAL_HIGH     0x00002000
++#define QE_IC_GRP_X_PRI0_DEST_SIGNAL_HIGH     0x00004000
++#define QE_IC_GRP_X_PRI1_DEST_SIGNAL_HIGH     0x00008000
++#define QE_IC_GRP_Y_PRI0_DEST_SIGNAL_HIGH     0x00010000
++#define QE_IC_GRP_Y_PRI1_DEST_SIGNAL_HIGH     0x00020000
++#define QE_IC_GRP_Z_PRI0_DEST_SIGNAL_HIGH     0x00040000
++#define QE_IC_GRP_Z_PRI1_DEST_SIGNAL_HIGH     0x00080000
++#define QE_IC_GRP_RISCA_PRI0_DEST_SIGNAL_HIGH 0x00100000
++#define QE_IC_GRP_RISCA_PRI1_DEST_SIGNAL_HIGH 0x00200000
++#define QE_IC_GRP_RISCB_PRI0_DEST_SIGNAL_HIGH 0x00400000
++#define QE_IC_GRP_RISCB_PRI1_DEST_SIGNAL_HIGH 0x00800000
++#define QE_IC_GRP_W_DEST_SIGNAL_SHIFT         (12)
++
++/* QE interrupt sources groups */
++enum qe_ic_grp_id {
++      QE_IC_GRP_W = 0,        /* QE interrupt controller group W */
++      QE_IC_GRP_X,            /* QE interrupt controller group X */
++      QE_IC_GRP_Y,            /* QE interrupt controller group Y */
++      QE_IC_GRP_Z,            /* QE interrupt controller group Z */
++      QE_IC_GRP_RISCA,        /* QE interrupt controller RISC group A */
++      QE_IC_GRP_RISCB         /* QE interrupt controller RISC group B */
++};
++
+ struct qe_ic {
+       /* Control registers offset */
+       u32 __iomem *regs;
+@@ -260,15 +300,15 @@ static struct qe_ic_info qe_ic_info[] =
+               },
+ };
+-static inline u32 qe_ic_read(volatile __be32  __iomem * base, unsigned int reg)
++static inline u32 qe_ic_read(__be32  __iomem *base, unsigned int reg)
+ {
+-      return in_be32(base + (reg >> 2));
++      return ioread32be(base + (reg >> 2));
+ }
+-static inline void qe_ic_write(volatile __be32  __iomem * base, unsigned int reg,
++static inline void qe_ic_write(__be32  __iomem *base, unsigned int reg,
+                              u32 value)
+ {
+-      out_be32(base + (reg >> 2), value);
++      iowrite32be(value, base + (reg >> 2));
+ }
+ static inline struct qe_ic *qe_ic_from_irq(unsigned int virq)
+@@ -370,8 +410,8 @@ static const struct irq_domain_ops qe_ic
+       .xlate = irq_domain_xlate_onetwocell,
+ };
+-/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+-unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic)
++/* Return an interrupt vector or 0 if no interrupt is pending. */
++static unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic)
+ {
+       int irq;
+@@ -381,13 +421,13 @@ unsigned int qe_ic_get_low_irq(struct qe
+       irq = qe_ic_read(qe_ic->regs, QEIC_CIVEC) >> 26;
+       if (irq == 0)
+-              return NO_IRQ;
++              return 0;
+       return irq_linear_revmap(qe_ic->irqhost, irq);
+ }
+-/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+-unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
++/* Return an interrupt vector or 0 if no interrupt is pending. */
++static unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
+ {
+       int irq;
+@@ -397,11 +437,69 @@ unsigned int qe_ic_get_high_irq(struct q
+       irq = qe_ic_read(qe_ic->regs, QEIC_CHIVEC) >> 26;
+       if (irq == 0)
+-              return NO_IRQ;
++              return 0;
+       return irq_linear_revmap(qe_ic->irqhost, irq);
+ }
++static inline void qe_ic_cascade_low_ipic(struct irq_desc *desc)
++{
++      struct qe_ic *qe_ic = irq_desc_get_handler_data(desc);
++      unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
++
++      if (cascade_irq != 0)
++              generic_handle_irq(cascade_irq);
++}
++
++static inline void qe_ic_cascade_high_ipic(struct irq_desc *desc)
++{
++      struct qe_ic *qe_ic = irq_desc_get_handler_data(desc);
++      unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
++
++      if (cascade_irq != 0)
++              generic_handle_irq(cascade_irq);
++}
++
++static inline void qe_ic_cascade_low_mpic(struct irq_desc *desc)
++{
++      struct qe_ic *qe_ic = irq_desc_get_handler_data(desc);
++      unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
++      struct irq_chip *chip = irq_desc_get_chip(desc);
++
++      if (cascade_irq != 0)
++              generic_handle_irq(cascade_irq);
++
++      chip->irq_eoi(&desc->irq_data);
++}
++
++static inline void qe_ic_cascade_high_mpic(struct irq_desc *desc)
++{
++      struct qe_ic *qe_ic = irq_desc_get_handler_data(desc);
++      unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
++      struct irq_chip *chip = irq_desc_get_chip(desc);
++
++      if (cascade_irq != 0)
++              generic_handle_irq(cascade_irq);
++
++      chip->irq_eoi(&desc->irq_data);
++}
++
++static inline void qe_ic_cascade_muxed_mpic(struct irq_desc *desc)
++{
++      struct qe_ic *qe_ic = irq_desc_get_handler_data(desc);
++      unsigned int cascade_irq;
++      struct irq_chip *chip = irq_desc_get_chip(desc);
++
++      cascade_irq = qe_ic_get_high_irq(qe_ic);
++      if (cascade_irq == 0)
++              cascade_irq = qe_ic_get_low_irq(qe_ic);
++
++      if (cascade_irq != 0)
++              generic_handle_irq(cascade_irq);
++
++      chip->irq_eoi(&desc->irq_data);
++}
++
+ static int __init qe_ic_init(struct device_node *node, unsigned int flags)
+ {
+       struct qe_ic *qe_ic;
+@@ -438,7 +536,7 @@ static int __init qe_ic_init(struct devi
+       qe_ic->virq_high = irq_of_parse_and_map(node, 0);
+       qe_ic->virq_low = irq_of_parse_and_map(node, 1);
+-      if (qe_ic->virq_low == NO_IRQ) {
++      if (qe_ic->virq_low == 0) {
+               pr_err("Failed to map QE_IC low IRQ\n");
+               ret = -ENOMEM;
+               goto err_domain_remove;
+@@ -470,7 +568,7 @@ static int __init qe_ic_init(struct devi
+       irq_set_handler_data(qe_ic->virq_low, qe_ic);
+       irq_set_chained_handler(qe_ic->virq_low, qe_ic_cascade_low_mpic);
+-      if (qe_ic->virq_high != NO_IRQ &&
++      if (qe_ic->virq_high != 0 &&
+                       qe_ic->virq_high != qe_ic->virq_low) {
+               irq_set_handler_data(qe_ic->virq_high, qe_ic);
+               irq_set_chained_handler(qe_ic->virq_high,
+@@ -488,100 +586,6 @@ err_put_node:
+       return ret;
+ }
+-void qe_ic_set_highest_priority(unsigned int virq, int high)
+-{
+-      struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+-      unsigned int src = virq_to_hw(virq);
+-      u32 temp = 0;
+-
+-      temp = qe_ic_read(qe_ic->regs, QEIC_CICR);
+-
+-      temp &= ~CICR_HP_MASK;
+-      temp |= src << CICR_HP_SHIFT;
+-
+-      temp &= ~CICR_HPIT_MASK;
+-      temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << CICR_HPIT_SHIFT;
+-
+-      qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
+-}
+-
+-/* Set Priority level within its group, from 1 to 8 */
+-int qe_ic_set_priority(unsigned int virq, unsigned int priority)
+-{
+-      struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+-      unsigned int src = virq_to_hw(virq);
+-      u32 temp;
+-
+-      if (priority > 8 || priority == 0)
+-              return -EINVAL;
+-      if (WARN_ONCE(src >= ARRAY_SIZE(qe_ic_info),
+-                    "%s: Invalid hw irq number for QEIC\n", __func__))
+-              return -EINVAL;
+-      if (qe_ic_info[src].pri_reg == 0)
+-              return -EINVAL;
+-
+-      temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].pri_reg);
+-
+-      if (priority < 4) {
+-              temp &= ~(0x7 << (32 - priority * 3));
+-              temp |= qe_ic_info[src].pri_code << (32 - priority * 3);
+-      } else {
+-              temp &= ~(0x7 << (24 - priority * 3));
+-              temp |= qe_ic_info[src].pri_code << (24 - priority * 3);
+-      }
+-
+-      qe_ic_write(qe_ic->regs, qe_ic_info[src].pri_reg, temp);
+-
+-      return 0;
+-}
+-
+-/* Set a QE priority to use high irq, only priority 1~2 can use high irq */
+-int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high)
+-{
+-      struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+-      unsigned int src = virq_to_hw(virq);
+-      u32 temp, control_reg = QEIC_CICNR, shift = 0;
+-
+-      if (priority > 2 || priority == 0)
+-              return -EINVAL;
+-      if (WARN_ONCE(src >= ARRAY_SIZE(qe_ic_info),
+-                    "%s: Invalid hw irq number for QEIC\n", __func__))
+-              return -EINVAL;
+-
+-      switch (qe_ic_info[src].pri_reg) {
+-      case QEIC_CIPZCC:
+-              shift = CICNR_ZCC1T_SHIFT;
+-              break;
+-      case QEIC_CIPWCC:
+-              shift = CICNR_WCC1T_SHIFT;
+-              break;
+-      case QEIC_CIPYCC:
+-              shift = CICNR_YCC1T_SHIFT;
+-              break;
+-      case QEIC_CIPXCC:
+-              shift = CICNR_XCC1T_SHIFT;
+-              break;
+-      case QEIC_CIPRTA:
+-              shift = CRICR_RTA1T_SHIFT;
+-              control_reg = QEIC_CRICR;
+-              break;
+-      case QEIC_CIPRTB:
+-              shift = CRICR_RTB1T_SHIFT;
+-              control_reg = QEIC_CRICR;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      shift += (2 - priority) * 2;
+-      temp = qe_ic_read(qe_ic->regs, control_reg);
+-      temp &= ~(SIGNAL_MASK << shift);
+-      temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << shift;
+-      qe_ic_write(qe_ic->regs, control_reg, temp);
+-
+-      return 0;
+-}
+-
+ static int __init init_qe_ic(struct device_node *node,
+                            struct device_node *parent)
+ {
+--- a/include/soc/fsl/qe/qe_ic.h
++++ /dev/null
+@@ -1,128 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0-or-later */
+-/*
+- * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
+- *
+- * Authors:   Shlomi Gridish <gridish@freescale.com>
+- *            Li Yang <leoli@freescale.com>
+- *
+- * Description:
+- * QE IC external definitions and structure.
+- */
+-#ifndef _ASM_POWERPC_QE_IC_H
+-#define _ASM_POWERPC_QE_IC_H
+-
+-#include <linux/irq.h>
+-
+-struct device_node;
+-struct qe_ic;
+-
+-#define NUM_OF_QE_IC_GROUPS   6
+-
+-/* Flags when we init the QE IC */
+-#define QE_IC_SPREADMODE_GRP_W                        0x00000001
+-#define QE_IC_SPREADMODE_GRP_X                        0x00000002
+-#define QE_IC_SPREADMODE_GRP_Y                        0x00000004
+-#define QE_IC_SPREADMODE_GRP_Z                        0x00000008
+-#define QE_IC_SPREADMODE_GRP_RISCA            0x00000010
+-#define QE_IC_SPREADMODE_GRP_RISCB            0x00000020
+-
+-#define QE_IC_LOW_SIGNAL                      0x00000100
+-#define QE_IC_HIGH_SIGNAL                     0x00000200
+-
+-#define QE_IC_GRP_W_PRI0_DEST_SIGNAL_HIGH     0x00001000
+-#define QE_IC_GRP_W_PRI1_DEST_SIGNAL_HIGH     0x00002000
+-#define QE_IC_GRP_X_PRI0_DEST_SIGNAL_HIGH     0x00004000
+-#define QE_IC_GRP_X_PRI1_DEST_SIGNAL_HIGH     0x00008000
+-#define QE_IC_GRP_Y_PRI0_DEST_SIGNAL_HIGH     0x00010000
+-#define QE_IC_GRP_Y_PRI1_DEST_SIGNAL_HIGH     0x00020000
+-#define QE_IC_GRP_Z_PRI0_DEST_SIGNAL_HIGH     0x00040000
+-#define QE_IC_GRP_Z_PRI1_DEST_SIGNAL_HIGH     0x00080000
+-#define QE_IC_GRP_RISCA_PRI0_DEST_SIGNAL_HIGH 0x00100000
+-#define QE_IC_GRP_RISCA_PRI1_DEST_SIGNAL_HIGH 0x00200000
+-#define QE_IC_GRP_RISCB_PRI0_DEST_SIGNAL_HIGH 0x00400000
+-#define QE_IC_GRP_RISCB_PRI1_DEST_SIGNAL_HIGH 0x00800000
+-#define QE_IC_GRP_W_DEST_SIGNAL_SHIFT         (12)
+-
+-/* QE interrupt sources groups */
+-enum qe_ic_grp_id {
+-      QE_IC_GRP_W = 0,        /* QE interrupt controller group W */
+-      QE_IC_GRP_X,            /* QE interrupt controller group X */
+-      QE_IC_GRP_Y,            /* QE interrupt controller group Y */
+-      QE_IC_GRP_Z,            /* QE interrupt controller group Z */
+-      QE_IC_GRP_RISCA,        /* QE interrupt controller RISC group A */
+-      QE_IC_GRP_RISCB         /* QE interrupt controller RISC group B */
+-};
+-
+-#ifdef CONFIG_QUICC_ENGINE
+-unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic);
+-unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic);
+-#else
+-static inline unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic)
+-{ return 0; }
+-static inline unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
+-{ return 0; }
+-#endif /* CONFIG_QUICC_ENGINE */
+-
+-void qe_ic_set_highest_priority(unsigned int virq, int high);
+-int qe_ic_set_priority(unsigned int virq, unsigned int priority);
+-int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high);
+-
+-static inline void qe_ic_cascade_low_ipic(struct irq_desc *desc)
+-{
+-      struct qe_ic *qe_ic = irq_desc_get_handler_data(desc);
+-      unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
+-
+-      if (cascade_irq != NO_IRQ)
+-              generic_handle_irq(cascade_irq);
+-}
+-
+-static inline void qe_ic_cascade_high_ipic(struct irq_desc *desc)
+-{
+-      struct qe_ic *qe_ic = irq_desc_get_handler_data(desc);
+-      unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
+-
+-      if (cascade_irq != NO_IRQ)
+-              generic_handle_irq(cascade_irq);
+-}
+-
+-static inline void qe_ic_cascade_low_mpic(struct irq_desc *desc)
+-{
+-      struct qe_ic *qe_ic = irq_desc_get_handler_data(desc);
+-      unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
+-      struct irq_chip *chip = irq_desc_get_chip(desc);
+-
+-      if (cascade_irq != NO_IRQ)
+-              generic_handle_irq(cascade_irq);
+-
+-      chip->irq_eoi(&desc->irq_data);
+-}
+-
+-static inline void qe_ic_cascade_high_mpic(struct irq_desc *desc)
+-{
+-      struct qe_ic *qe_ic = irq_desc_get_handler_data(desc);
+-      unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
+-      struct irq_chip *chip = irq_desc_get_chip(desc);
+-
+-      if (cascade_irq != NO_IRQ)
+-              generic_handle_irq(cascade_irq);
+-
+-      chip->irq_eoi(&desc->irq_data);
+-}
+-
+-static inline void qe_ic_cascade_muxed_mpic(struct irq_desc *desc)
+-{
+-      struct qe_ic *qe_ic = irq_desc_get_handler_data(desc);
+-      unsigned int cascade_irq;
+-      struct irq_chip *chip = irq_desc_get_chip(desc);
+-
+-      cascade_irq = qe_ic_get_high_irq(qe_ic);
+-      if (cascade_irq == NO_IRQ)
+-              cascade_irq = qe_ic_get_low_irq(qe_ic);
+-
+-      if (cascade_irq != NO_IRQ)
+-              generic_handle_irq(cascade_irq);
+-
+-      chip->irq_eoi(&desc->irq_data);
+-}
+-
+-#endif /* _ASM_POWERPC_QE_IC_H */
diff --git a/target/linux/layerscape/patches-5.4/814-qe-0005-QE-remove-PPCisms-for-QE.patch b/target/linux/layerscape/patches-5.4/814-qe-0005-QE-remove-PPCisms-for-QE.patch
new file mode 100644 (file)
index 0000000..496cd3c
--- /dev/null
@@ -0,0 +1,547 @@
+From 3fb2f44e30cc3a151a0fa8160d8bf70062722ed7 Mon Sep 17 00:00:00 2001
+From: Zhao Qiang <qiang.zhao@nxp.com>
+Date: Thu, 27 Apr 2017 09:47:29 +0800
+Subject: [PATCH] QE: remove PPCisms for QE
+
+QE was supported on PowerPC, and dependent on PPC,
+Now it is supported on other platforms. so remove PPCisms.
+
+Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
+---
+ drivers/soc/fsl/qe/Kconfig    |  2 +-
+ drivers/soc/fsl/qe/qe.c       | 70 +++++++++++++++++++++++++---------------
+ drivers/soc/fsl/qe/qe_io.c    | 42 +++++++++++-------------
+ drivers/soc/fsl/qe/qe_tdm.c   |  8 ++---
+ drivers/soc/fsl/qe/ucc.c      | 10 +++---
+ drivers/soc/fsl/qe/ucc_fast.c | 74 ++++++++++++++++++++++---------------------
+ drivers/tty/serial/ucc_uart.c |  1 +
+ include/soc/fsl/qe/qe.h       |  1 -
+ 8 files changed, 112 insertions(+), 96 deletions(-)
+
+--- a/drivers/soc/fsl/qe/Kconfig
++++ b/drivers/soc/fsl/qe/Kconfig
+@@ -5,7 +5,7 @@
+ config QUICC_ENGINE
+       bool "QUICC Engine (QE) framework support"
+-      depends on FSL_SOC && PPC32
++      depends on OF && HAS_IOMEM
+       select GENERIC_ALLOCATOR
+       select CRC32
+       help
+--- a/drivers/soc/fsl/qe/qe.c
++++ b/drivers/soc/fsl/qe/qe.c
+@@ -30,8 +30,6 @@
+ #include <asm/pgtable.h>
+ #include <soc/fsl/qe/immap_qe.h>
+ #include <soc/fsl/qe/qe.h>
+-#include <asm/prom.h>
+-#include <asm/rheap.h>
+ static void qe_snums_init(void);
+ static int qe_sdma_init(void);
+@@ -104,15 +102,27 @@ void qe_reset(void)
+               panic("sdma init failed!");
+ }
++/* issue commands to QE, return 0 on success while -EIO on error
++ *
++ * @cmd: the command code, should be QE_INIT_TX_RX, QE_STOP_TX and so on
++ * @device: which sub-block will run the command, QE_CR_SUBBLOCK_UCCFAST1 - 8
++ * , QE_CR_SUBBLOCK_UCCSLOW1 - 8, QE_CR_SUBBLOCK_MCC1 - 3,
++ * QE_CR_SUBBLOCK_IDMA1 - 4 and such on.
++ * @mcn_protocol: specifies mode for the command for non-MCC, should be
++ * QE_CR_PROTOCOL_HDLC_TRANSPARENT, QE_CR_PROTOCOL_QMC, QE_CR_PROTOCOL_UART
++ * and such on.
++ * @cmd_input: command related data.
++ */
+ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input)
+ {
+       unsigned long flags;
+       u8 mcn_shift = 0, dev_shift = 0;
+-      u32 ret;
++      int ret;
++      int i;
+       spin_lock_irqsave(&qe_lock, flags);
+       if (cmd == QE_RESET) {
+-              out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG));
++              iowrite32be((cmd | QE_CR_FLG), &qe_immr->cp.cecr);
+       } else {
+               if (cmd == QE_ASSIGN_PAGE) {
+                       /* Here device is the SNUM, not sub-block */
+@@ -129,20 +139,26 @@ int qe_issue_cmd(u32 cmd, u32 device, u8
+                               mcn_shift = QE_CR_MCN_NORMAL_SHIFT;
+               }
+-              out_be32(&qe_immr->cp.cecdr, cmd_input);
+-              out_be32(&qe_immr->cp.cecr,
+-                       (cmd | QE_CR_FLG | ((u32) device << dev_shift) | (u32)
+-                        mcn_protocol << mcn_shift));
++              iowrite32be(cmd_input, &qe_immr->cp.cecdr);
++              iowrite32be((cmd | QE_CR_FLG | ((u32)device << dev_shift) |
++                          (u32)mcn_protocol << mcn_shift), &qe_immr->cp.cecr);
+       }
+       /* wait for the QE_CR_FLG to clear */
+-      ret = spin_event_timeout((in_be32(&qe_immr->cp.cecr) & QE_CR_FLG) == 0,
+-                         100, 0);
++      ret = -EIO;
++      for (i = 0; i < 100; i++) {
++              if ((ioread32be(&qe_immr->cp.cecr) & QE_CR_FLG) == 0) {
++                      ret = 0;
++                      break;
++              }
++              udelay(1);
++      }
++
+       /* On timeout (e.g. failure), the expression will be false (ret == 0),
+          otherwise it will be true (ret == 1). */
+       spin_unlock_irqrestore(&qe_lock, flags);
+-      return ret == 1;
++      return ret;
+ }
+ EXPORT_SYMBOL(qe_issue_cmd);
+@@ -167,6 +183,8 @@ unsigned int qe_get_brg_clk(void)
+       int size;
+       const u32 *prop;
+       unsigned int mod;
++      u32 val;
++      int ret;
+       if (brg_clk)
+               return brg_clk;
+@@ -175,9 +193,9 @@ unsigned int qe_get_brg_clk(void)
+       if (!qe)
+               return brg_clk;
+-      prop = of_get_property(qe, "brg-frequency", &size);
+-      if (prop && size == sizeof(*prop))
+-              brg_clk = *prop;
++      ret = of_property_read_u32(qe, "brg-frequency", &val);
++      if (!ret)
++              brg_clk = val;
+       of_node_put(qe);
+@@ -223,14 +241,16 @@ int qe_setbrg(enum qe_clock brg, unsigne
+       /* Errata QE_General4, which affects some MPC832x and MPC836x SOCs, says
+          that the BRG divisor must be even if you're not using divide-by-16
+          mode. */
++#ifdef CONFIG_PPC
+       if (pvr_version_is(PVR_VER_836x) || pvr_version_is(PVR_VER_832x))
+               if (!div16 && (divisor & 1) && (divisor > 3))
+                       divisor++;
++#endif
+       tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) |
+               QE_BRGC_ENABLE | div16;
+-      out_be32(&qe_immr->brg.brgc[brg - QE_BRG1], tempval);
++      iowrite32be(tempval, &qe_immr->brg.brgc[brg - QE_BRG1]);
+       return 0;
+ }
+@@ -377,9 +397,9 @@ static int qe_sdma_init(void)
+                       return -ENOMEM;
+       }
+-      out_be32(&sdma->sdebcr, (u32) sdma_buf_offset & QE_SDEBCR_BA_MASK);
+-      out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK |
+-                                      (0x1 << QE_SDMR_CEN_SHIFT)));
++      iowrite32be((u32)sdma_buf_offset & QE_SDEBCR_BA_MASK, &sdma->sdebcr);
++      iowrite32be((QE_SDMR_GLB_1_MSK | (0x1 << QE_SDMR_CEN_SHIFT)),
++                  &sdma->sdmr);
+       return 0;
+ }
+@@ -417,14 +437,14 @@ static void qe_upload_microcode(const vo
+                       "uploading microcode '%s'\n", ucode->id);
+       /* Use auto-increment */
+-      out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
+-              QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
++      iowrite32be(be32_to_cpu(ucode->iram_offset) | QE_IRAM_IADD_AIE |
++                  QE_IRAM_IADD_BADDR, &qe_immr->iram.iadd);
+       for (i = 0; i < be32_to_cpu(ucode->count); i++)
+-              out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
++              iowrite32be(be32_to_cpu(code[i]), &qe_immr->iram.idata);
+       
+       /* Set I-RAM Ready Register */
+-      out_be32(&qe_immr->iram.iready, be32_to_cpu(QE_IRAM_READY));
++      iowrite32be(be32_to_cpu(QE_IRAM_READY), &qe_immr->iram.iready);
+ }
+ /*
+@@ -509,7 +529,7 @@ int qe_upload_firmware(const struct qe_f
+        * If the microcode calls for it, split the I-RAM.
+        */
+       if (!firmware->split)
+-              setbits16(&qe_immr->cp.cercr, QE_CP_CERCR_CIR);
++              qe_setbits16(&qe_immr->cp.cercr, QE_CP_CERCR_CIR);
+       if (firmware->soc.model)
+               printk(KERN_INFO
+@@ -543,11 +563,11 @@ int qe_upload_firmware(const struct qe_f
+                       u32 trap = be32_to_cpu(ucode->traps[j]);
+                       if (trap)
+-                              out_be32(&qe_immr->rsp[i].tibcr[j], trap);
++                              iowrite32be(trap, &qe_immr->rsp[i].tibcr[j]);
+               }
+               /* Enable traps */
+-              out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
++              iowrite32be(be32_to_cpu(ucode->eccr), &qe_immr->rsp[i].eccr);
+       }
+       qe_firmware_uploaded = 1;
+--- a/drivers/soc/fsl/qe/qe_io.c
++++ b/drivers/soc/fsl/qe/qe_io.c
+@@ -18,8 +18,6 @@
+ #include <asm/io.h>
+ #include <soc/fsl/qe/qe.h>
+-#include <asm/prom.h>
+-#include <sysdev/fsl_soc.h>
+ #undef DEBUG
+@@ -57,16 +55,16 @@ void __par_io_config_pin(struct qe_pio_r
+       pin_mask1bit = (u32) (1 << (QE_PIO_PINS - (pin + 1)));
+       /* Set open drain, if required */
+-      tmp_val = in_be32(&par_io->cpodr);
++      tmp_val = ioread32be(&par_io->cpodr);
+       if (open_drain)
+-              out_be32(&par_io->cpodr, pin_mask1bit | tmp_val);
++              iowrite32be(pin_mask1bit | tmp_val, &par_io->cpodr);
+       else
+-              out_be32(&par_io->cpodr, ~pin_mask1bit & tmp_val);
++              iowrite32be(~pin_mask1bit & tmp_val, &par_io->cpodr);
+       /* define direction */
+       tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ?
+-              in_be32(&par_io->cpdir2) :
+-              in_be32(&par_io->cpdir1);
++              ioread32be(&par_io->cpdir2) :
++              ioread32be(&par_io->cpdir1);
+       /* get all bits mask for 2 bit per port */
+       pin_mask2bits = (u32) (0x3 << (QE_PIO_PINS -
+@@ -78,34 +76,30 @@ void __par_io_config_pin(struct qe_pio_r
+       /* clear and set 2 bits mask */
+       if (pin > (QE_PIO_PINS / 2) - 1) {
+-              out_be32(&par_io->cpdir2,
+-                       ~pin_mask2bits & tmp_val);
++              iowrite32be(~pin_mask2bits & tmp_val, &par_io->cpdir2);
+               tmp_val &= ~pin_mask2bits;
+-              out_be32(&par_io->cpdir2, new_mask2bits | tmp_val);
++              iowrite32be(new_mask2bits | tmp_val, &par_io->cpdir2);
+       } else {
+-              out_be32(&par_io->cpdir1,
+-                       ~pin_mask2bits & tmp_val);
++              iowrite32be(~pin_mask2bits & tmp_val, &par_io->cpdir1);
+               tmp_val &= ~pin_mask2bits;
+-              out_be32(&par_io->cpdir1, new_mask2bits | tmp_val);
++              iowrite32be(new_mask2bits | tmp_val, &par_io->cpdir1);
+       }
+       /* define pin assignment */
+       tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ?
+-              in_be32(&par_io->cppar2) :
+-              in_be32(&par_io->cppar1);
++              ioread32be(&par_io->cppar2) :
++              ioread32be(&par_io->cppar1);
+       new_mask2bits = (u32) (assignment << (QE_PIO_PINS -
+                       (pin % (QE_PIO_PINS / 2) + 1) * 2));
+       /* clear and set 2 bits mask */
+       if (pin > (QE_PIO_PINS / 2) - 1) {
+-              out_be32(&par_io->cppar2,
+-                       ~pin_mask2bits & tmp_val);
++              iowrite32be(~pin_mask2bits & tmp_val, &par_io->cppar2);
+               tmp_val &= ~pin_mask2bits;
+-              out_be32(&par_io->cppar2, new_mask2bits | tmp_val);
++              iowrite32be(new_mask2bits | tmp_val, &par_io->cppar2);
+       } else {
+-              out_be32(&par_io->cppar1,
+-                       ~pin_mask2bits & tmp_val);
++              iowrite32be(~pin_mask2bits & tmp_val, &par_io->cppar1);
+               tmp_val &= ~pin_mask2bits;
+-              out_be32(&par_io->cppar1, new_mask2bits | tmp_val);
++              iowrite32be(new_mask2bits | tmp_val, &par_io->cppar1);
+       }
+ }
+ EXPORT_SYMBOL(__par_io_config_pin);
+@@ -133,12 +127,12 @@ int par_io_data_set(u8 port, u8 pin, u8
+       /* calculate pin location */
+       pin_mask = (u32) (1 << (QE_PIO_PINS - 1 - pin));
+-      tmp_val = in_be32(&par_io[port].cpdata);
++      tmp_val = ioread32be(&par_io[port].cpdata);
+       if (val == 0)           /* clear */
+-              out_be32(&par_io[port].cpdata, ~pin_mask & tmp_val);
++              iowrite32be(~pin_mask & tmp_val, &par_io[port].cpdata);
+       else                    /* set */
+-              out_be32(&par_io[port].cpdata, pin_mask | tmp_val);
++              iowrite32be(pin_mask | tmp_val, &par_io[port].cpdata);
+       return 0;
+ }
+--- a/drivers/soc/fsl/qe/qe_tdm.c
++++ b/drivers/soc/fsl/qe/qe_tdm.c
+@@ -169,10 +169,10 @@ void ucc_tdm_init(struct ucc_tdm *utdm,
+                                   &siram[siram_entry_id * 32 + 0x200 +  i]);
+       }
+-      setbits16(&siram[(siram_entry_id * 32) + (utdm->num_of_ts - 1)],
+-                SIR_LAST);
+-      setbits16(&siram[(siram_entry_id * 32) + 0x200 + (utdm->num_of_ts - 1)],
+-                SIR_LAST);
++      qe_setbits16(&siram[(siram_entry_id * 32) + (utdm->num_of_ts - 1)],
++                   SIR_LAST);
++      qe_setbits16(&siram[(siram_entry_id * 32) + 0x200 +
++                   (utdm->num_of_ts - 1)], SIR_LAST);
+       /* Set SIxMR register */
+       sixmr = SIMR_SAD(siram_entry_id);
+--- a/drivers/soc/fsl/qe/ucc.c
++++ b/drivers/soc/fsl/qe/ucc.c
+@@ -35,7 +35,7 @@ int ucc_set_qe_mux_mii_mng(unsigned int
+               return -EINVAL;
+       spin_lock_irqsave(&cmxgcr_lock, flags);
+-      clrsetbits_be32(&qe_immr->qmx.cmxgcr, QE_CMXGCR_MII_ENET_MNG,
++      qe_clrsetbits32(&qe_immr->qmx.cmxgcr, QE_CMXGCR_MII_ENET_MNG,
+               ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT);
+       spin_unlock_irqrestore(&cmxgcr_lock, flags);
+@@ -80,7 +80,7 @@ int ucc_set_type(unsigned int ucc_num, e
+               return -EINVAL;
+       }
+-      clrsetbits_8(guemr, UCC_GUEMR_MODE_MASK,
++      qe_clrsetbits8(guemr, UCC_GUEMR_MODE_MASK,
+               UCC_GUEMR_SET_RESERVED3 | speed);
+       return 0;
+@@ -109,9 +109,9 @@ int ucc_mux_set_grant_tsa_bkpt(unsigned
+       get_cmxucr_reg(ucc_num, &cmxucr, &reg_num, &shift);
+       if (set)
+-              setbits32(cmxucr, mask << shift);
++              qe_setbits32(cmxucr, mask << shift);
+       else
+-              clrbits32(cmxucr, mask << shift);
++              qe_clrbits32(cmxucr, mask << shift);
+       return 0;
+ }
+@@ -207,7 +207,7 @@ int ucc_set_qe_mux_rxtx(unsigned int ucc
+       if (mode == COMM_DIR_RX)
+               shift += 4;
+-      clrsetbits_be32(cmxucr, QE_CMXUCR_TX_CLK_SRC_MASK << shift,
++      qe_clrsetbits32(cmxucr, QE_CMXUCR_TX_CLK_SRC_MASK << shift,
+               clock_bits << shift);
+       return 0;
+--- a/drivers/soc/fsl/qe/ucc_fast.c
++++ b/drivers/soc/fsl/qe/ucc_fast.c
+@@ -29,41 +29,41 @@ void ucc_fast_dump_regs(struct ucc_fast_
+       printk(KERN_INFO "Base address: 0x%p\n", uccf->uf_regs);
+       printk(KERN_INFO "gumr  : addr=0x%p, val=0x%08x\n",
+-                &uccf->uf_regs->gumr, in_be32(&uccf->uf_regs->gumr));
++             &uccf->uf_regs->gumr, ioread32be(&uccf->uf_regs->gumr));
+       printk(KERN_INFO "upsmr : addr=0x%p, val=0x%08x\n",
+-                &uccf->uf_regs->upsmr, in_be32(&uccf->uf_regs->upsmr));
++                &uccf->uf_regs->upsmr, ioread32be(&uccf->uf_regs->upsmr));
+       printk(KERN_INFO "utodr : addr=0x%p, val=0x%04x\n",
+-                &uccf->uf_regs->utodr, in_be16(&uccf->uf_regs->utodr));
++                &uccf->uf_regs->utodr, ioread16be(&uccf->uf_regs->utodr));
+       printk(KERN_INFO "udsr  : addr=0x%p, val=0x%04x\n",
+-                &uccf->uf_regs->udsr, in_be16(&uccf->uf_regs->udsr));
++                &uccf->uf_regs->udsr, ioread16be(&uccf->uf_regs->udsr));
+       printk(KERN_INFO "ucce  : addr=0x%p, val=0x%08x\n",
+-                &uccf->uf_regs->ucce, in_be32(&uccf->uf_regs->ucce));
++                &uccf->uf_regs->ucce, ioread32be(&uccf->uf_regs->ucce));
+       printk(KERN_INFO "uccm  : addr=0x%p, val=0x%08x\n",
+-                &uccf->uf_regs->uccm, in_be32(&uccf->uf_regs->uccm));
++                &uccf->uf_regs->uccm, ioread32be(&uccf->uf_regs->uccm));
+       printk(KERN_INFO "uccs  : addr=0x%p, val=0x%02x\n",
+-                &uccf->uf_regs->uccs, in_8(&uccf->uf_regs->uccs));
++                &uccf->uf_regs->uccs, ioread8(&uccf->uf_regs->uccs));
+       printk(KERN_INFO "urfb  : addr=0x%p, val=0x%08x\n",
+-                &uccf->uf_regs->urfb, in_be32(&uccf->uf_regs->urfb));
++                &uccf->uf_regs->urfb, ioread32be(&uccf->uf_regs->urfb));
+       printk(KERN_INFO "urfs  : addr=0x%p, val=0x%04x\n",
+-                &uccf->uf_regs->urfs, in_be16(&uccf->uf_regs->urfs));
++                &uccf->uf_regs->urfs, ioread16be(&uccf->uf_regs->urfs));
+       printk(KERN_INFO "urfet : addr=0x%p, val=0x%04x\n",
+-                &uccf->uf_regs->urfet, in_be16(&uccf->uf_regs->urfet));
++                &uccf->uf_regs->urfet, ioread16be(&uccf->uf_regs->urfet));
+       printk(KERN_INFO "urfset: addr=0x%p, val=0x%04x\n",
+-                &uccf->uf_regs->urfset, in_be16(&uccf->uf_regs->urfset));
++                &uccf->uf_regs->urfset, ioread16be(&uccf->uf_regs->urfset));
+       printk(KERN_INFO "utfb  : addr=0x%p, val=0x%08x\n",
+-                &uccf->uf_regs->utfb, in_be32(&uccf->uf_regs->utfb));
++                &uccf->uf_regs->utfb, ioread32be(&uccf->uf_regs->utfb));
+       printk(KERN_INFO "utfs  : addr=0x%p, val=0x%04x\n",
+-                &uccf->uf_regs->utfs, in_be16(&uccf->uf_regs->utfs));
++                &uccf->uf_regs->utfs, ioread16be(&uccf->uf_regs->utfs));
+       printk(KERN_INFO "utfet : addr=0x%p, val=0x%04x\n",
+-                &uccf->uf_regs->utfet, in_be16(&uccf->uf_regs->utfet));
++                &uccf->uf_regs->utfet, ioread16be(&uccf->uf_regs->utfet));
+       printk(KERN_INFO "utftt : addr=0x%p, val=0x%04x\n",
+-                &uccf->uf_regs->utftt, in_be16(&uccf->uf_regs->utftt));
++                &uccf->uf_regs->utftt, ioread16be(&uccf->uf_regs->utftt));
+       printk(KERN_INFO "utpt  : addr=0x%p, val=0x%04x\n",
+-                &uccf->uf_regs->utpt, in_be16(&uccf->uf_regs->utpt));
++                &uccf->uf_regs->utpt, ioread16be(&uccf->uf_regs->utpt));
+       printk(KERN_INFO "urtry : addr=0x%p, val=0x%08x\n",
+-                &uccf->uf_regs->urtry, in_be32(&uccf->uf_regs->urtry));
++                &uccf->uf_regs->urtry, ioread32be(&uccf->uf_regs->urtry));
+       printk(KERN_INFO "guemr : addr=0x%p, val=0x%02x\n",
+-                &uccf->uf_regs->guemr, in_8(&uccf->uf_regs->guemr));
++                &uccf->uf_regs->guemr, ioread8(&uccf->uf_regs->guemr));
+ }
+ EXPORT_SYMBOL(ucc_fast_dump_regs);
+@@ -85,7 +85,7 @@ EXPORT_SYMBOL(ucc_fast_get_qe_cr_subbloc
+ void ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf)
+ {
+-      out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD);
++      iowrite16be(UCC_FAST_TOD, &uccf->uf_regs->utodr);
+ }
+ EXPORT_SYMBOL(ucc_fast_transmit_on_demand);
+@@ -97,7 +97,7 @@ void ucc_fast_enable(struct ucc_fast_pri
+       uf_regs = uccf->uf_regs;
+       /* Enable reception and/or transmission on this UCC. */
+-      gumr = in_be32(&uf_regs->gumr);
++      gumr = ioread32be(&uf_regs->gumr);
+       if (mode & COMM_DIR_TX) {
+               gumr |= UCC_FAST_GUMR_ENT;
+               uccf->enabled_tx = 1;
+@@ -106,7 +106,7 @@ void ucc_fast_enable(struct ucc_fast_pri
+               gumr |= UCC_FAST_GUMR_ENR;
+               uccf->enabled_rx = 1;
+       }
+-      out_be32(&uf_regs->gumr, gumr);
++      iowrite32be(gumr, &uf_regs->gumr);
+ }
+ EXPORT_SYMBOL(ucc_fast_enable);
+@@ -118,7 +118,7 @@ void ucc_fast_disable(struct ucc_fast_pr
+       uf_regs = uccf->uf_regs;
+       /* Disable reception and/or transmission on this UCC. */
+-      gumr = in_be32(&uf_regs->gumr);
++      gumr = ioread32be(&uf_regs->gumr);
+       if (mode & COMM_DIR_TX) {
+               gumr &= ~UCC_FAST_GUMR_ENT;
+               uccf->enabled_tx = 0;
+@@ -127,7 +127,7 @@ void ucc_fast_disable(struct ucc_fast_pr
+               gumr &= ~UCC_FAST_GUMR_ENR;
+               uccf->enabled_rx = 0;
+       }
+-      out_be32(&uf_regs->gumr, gumr);
++      iowrite32be(gumr, &uf_regs->gumr);
+ }
+ EXPORT_SYMBOL(ucc_fast_disable);
+@@ -259,12 +259,13 @@ int ucc_fast_init(struct ucc_fast_info *
+       gumr |= uf_info->tenc;
+       gumr |= uf_info->tcrc;
+       gumr |= uf_info->mode;
+-      out_be32(&uf_regs->gumr, gumr);
++      iowrite32be(gumr, &uf_regs->gumr);
+       /* Allocate memory for Tx Virtual Fifo */
+       uccf->ucc_fast_tx_virtual_fifo_base_offset =
+           qe_muram_alloc(uf_info->utfs, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
+-      if (IS_ERR_VALUE(uccf->ucc_fast_tx_virtual_fifo_base_offset)) {
++      if (IS_ERR_VALUE((unsigned long)uccf->
++                       ucc_fast_tx_virtual_fifo_base_offset)) {
+               printk(KERN_ERR "%s: cannot allocate MURAM for TX FIFO\n",
+                       __func__);
+               uccf->ucc_fast_tx_virtual_fifo_base_offset = 0;
+@@ -277,7 +278,8 @@ int ucc_fast_init(struct ucc_fast_info *
+               qe_muram_alloc(uf_info->urfs +
+                          UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR,
+                          UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
+-      if (IS_ERR_VALUE(uccf->ucc_fast_rx_virtual_fifo_base_offset)) {
++      if (IS_ERR_VALUE((unsigned long)uccf->
++                       ucc_fast_rx_virtual_fifo_base_offset)) {
+               printk(KERN_ERR "%s: cannot allocate MURAM for RX FIFO\n",
+                       __func__);
+               uccf->ucc_fast_rx_virtual_fifo_base_offset = 0;
+@@ -286,15 +288,15 @@ int ucc_fast_init(struct ucc_fast_info *
+       }
+       /* Set Virtual Fifo registers */
+-      out_be16(&uf_regs->urfs, uf_info->urfs);
+-      out_be16(&uf_regs->urfet, uf_info->urfet);
+-      out_be16(&uf_regs->urfset, uf_info->urfset);
+-      out_be16(&uf_regs->utfs, uf_info->utfs);
+-      out_be16(&uf_regs->utfet, uf_info->utfet);
+-      out_be16(&uf_regs->utftt, uf_info->utftt);
++      iowrite16be(uf_info->urfs, &uf_regs->urfs);
++      iowrite16be(uf_info->urfet, &uf_regs->urfet);
++      iowrite16be(uf_info->urfset, &uf_regs->urfset);
++      iowrite16be(uf_info->utfs, &uf_regs->utfs);
++      iowrite16be(uf_info->utfet, &uf_regs->utfet);
++      iowrite16be(uf_info->utftt, &uf_regs->utftt);
+       /* utfb, urfb are offsets from MURAM base */
+-      out_be32(&uf_regs->utfb, uccf->ucc_fast_tx_virtual_fifo_base_offset);
+-      out_be32(&uf_regs->urfb, uccf->ucc_fast_rx_virtual_fifo_base_offset);
++      iowrite32be(uccf->ucc_fast_tx_virtual_fifo_base_offset, &uf_regs->utfb);
++      iowrite32be(uccf->ucc_fast_rx_virtual_fifo_base_offset, &uf_regs->urfb);
+       /* Mux clocking */
+       /* Grant Support */
+@@ -362,14 +364,14 @@ int ucc_fast_init(struct ucc_fast_info *
+       }
+       /* Set interrupt mask register at UCC level. */
+-      out_be32(&uf_regs->uccm, uf_info->uccm_mask);
++      iowrite32be(uf_info->uccm_mask, &uf_regs->uccm);
+       /* First, clear anything pending at UCC level,
+        * otherwise, old garbage may come through
+        * as soon as the dam is opened. */
+       /* Writing '1' clears */
+-      out_be32(&uf_regs->ucce, 0xffffffff);
++      iowrite32be(0xffffffff, &uf_regs->ucce);
+       *uccf_ret = uccf;
+       return 0;
+--- a/drivers/tty/serial/ucc_uart.c
++++ b/drivers/tty/serial/ucc_uart.c
+@@ -32,6 +32,7 @@
+ #include <soc/fsl/qe/ucc_slow.h>
+ #include <linux/firmware.h>
++#include <asm/cpm.h>
+ #include <asm/reg.h>
+ /*
+--- a/include/soc/fsl/qe/qe.h
++++ b/include/soc/fsl/qe/qe.h
+@@ -17,7 +17,6 @@
+ #include <linux/spinlock.h>
+ #include <linux/errno.h>
+ #include <linux/err.h>
+-#include <asm/cpm.h>
+ #include <soc/fsl/qe/immap_qe.h>
+ #include <linux/of.h>
+ #include <linux/of_address.h>
diff --git a/target/linux/layerscape/patches-5.4/814-qe-0006-config-qe-add-irq-qeic-support.patch b/target/linux/layerscape/patches-5.4/814-qe-0006-config-qe-add-irq-qeic-support.patch
new file mode 100644 (file)
index 0000000..7aaf8c7
--- /dev/null
@@ -0,0 +1,61 @@
+From 69673b5ab6f814cf679285f0c45baa318ab9e0d7 Mon Sep 17 00:00:00 2001
+From: Zhao Qiang <qiang.zhao@nxp.com>
+Date: Thu, 27 Apr 2017 10:22:12 +0800
+Subject: [PATCH] config/qe: add irq-qeic support.
+
+Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
+---
+ MAINTAINERS                            |  6 ++++++
+ drivers/irqchip/Makefile               |  1 +
+ drivers/net/ethernet/freescale/Kconfig | 11 ++++++-----
+ 3 files changed, 13 insertions(+), 5 deletions(-)
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -6596,6 +6596,12 @@ F:      drivers/soc/fsl/qe/
+ F:    include/soc/fsl/*qe*.h
+ F:    include/soc/fsl/*ucc*.h
++FREESCALE QEIC DRIVERS
++M:    Qiang Zhao <qiang.zhao@nxp.com>
++L:    linux-kernel@vger.kernel.org
++S:    Maintained
++F:    drivers/irqchip/irq-qeic.c
++
+ FREESCALE QUICC ENGINE UCC ETHERNET DRIVER
+ M:    Li Yang <leoyang.li@nxp.com>
+ L:    netdev@vger.kernel.org
+--- a/drivers/irqchip/Makefile
++++ b/drivers/irqchip/Makefile
+@@ -103,3 +103,4 @@ obj-$(CONFIG_MADERA_IRQ)           += irq-madera.
+ obj-$(CONFIG_LS1X_IRQ)                        += irq-ls1x.o
+ obj-$(CONFIG_TI_SCI_INTR_IRQCHIP)     += irq-ti-sci-intr.o
+ obj-$(CONFIG_TI_SCI_INTA_IRQCHIP)     += irq-ti-sci-inta.o
++obj-$(CONFIG_QUICC_ENGINE)            += irq-qeic.o
+--- a/drivers/net/ethernet/freescale/Kconfig
++++ b/drivers/net/ethernet/freescale/Kconfig
+@@ -6,10 +6,11 @@
+ config NET_VENDOR_FREESCALE
+       bool "Freescale devices"
+       default y
+-      depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \
+-                 M523x || M527x || M5272 || M528x || M520x || M532x || \
+-                 ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) || \
+-                 ARCH_LAYERSCAPE || COMPILE_TEST
++      depends on FSL_SOC || (QUICC_ENGINE && PPC32) || CPM1 || CPM2 || \
++                 PPC_MPC512x || M523x || M527x || M5272 || M528x || M520x || \
++                 M532x || ARCH_MXC || ARCH_MXS || \
++                 (PPC_MPC52xx && PPC_BESTCOMM) || ARCH_LAYERSCAPE || \
++                 COMPILE_TEST
+       ---help---
+         If you have a network (Ethernet) card belonging to this class, say Y.
+@@ -74,7 +75,7 @@ config FSL_XGMAC_MDIO
+ config UCC_GETH
+       tristate "Freescale QE Gigabit Ethernet"
+-      depends on QUICC_ENGINE
++      depends on QUICC_ENGINE && FSL_SOC && PPC32
+       select FSL_PQ_MDIO
+       select PHYLIB
+       ---help---
diff --git a/target/linux/layerscape/patches-5.4/815-sata-0001-ahci-qoriq-enable-acpi-support-in-qoriq-ahci-driver.patch b/target/linux/layerscape/patches-5.4/815-sata-0001-ahci-qoriq-enable-acpi-support-in-qoriq-ahci-driver.patch
new file mode 100644 (file)
index 0000000..74d75d0
--- /dev/null
@@ -0,0 +1,83 @@
+From 8f0baa717e7854b795567678415bc7173d66bc13 Mon Sep 17 00:00:00 2001
+From: Peng Ma <peng.ma@nxp.com>
+Date: Wed, 15 May 2019 05:45:35 +0000
+Subject: [PATCH] ahci: qoriq: enable acpi support in qoriq ahci driver
+
+This patch enables ACPI support in qoriq ahci driver.
+
+Signed-off-by: Udit Kumar <udit.kumar@nxp.com>
+Signed-off-by: Peng Ma <peng.ma@nxp.com>
+---
+ drivers/ata/ahci_qoriq.c | 20 +++++++++++++++++---
+ 1 file changed, 17 insertions(+), 3 deletions(-)
+
+--- a/drivers/ata/ahci_qoriq.c
++++ b/drivers/ata/ahci_qoriq.c
+@@ -6,6 +6,7 @@
+  *   Tang Yuantian <Yuantian.Tang@freescale.com>
+  */
++#include <linux/acpi.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/pm.h>
+@@ -80,6 +81,12 @@ static const struct of_device_id ahci_qo
+ };
+ MODULE_DEVICE_TABLE(of, ahci_qoriq_of_match);
++static const struct acpi_device_id ahci_qoriq_acpi_match[] = {
++      {"NXP0004", .driver_data = (kernel_ulong_t)AHCI_LX2160A},
++      { }
++};
++MODULE_DEVICE_TABLE(acpi, ahci_qoriq_acpi_match);
++
+ static int ahci_qoriq_hardreset(struct ata_link *link, unsigned int *class,
+                         unsigned long deadline)
+ {
+@@ -255,6 +262,7 @@ static int ahci_qoriq_phy_init(struct ah
+ static int ahci_qoriq_probe(struct platform_device *pdev)
+ {
+       struct device_node *np = pdev->dev.of_node;
++      const struct acpi_device_id *acpi_id;
+       struct device *dev = &pdev->dev;
+       struct ahci_host_priv *hpriv;
+       struct ahci_qoriq_priv *qoriq_priv;
+@@ -267,14 +275,18 @@ static int ahci_qoriq_probe(struct platf
+               return PTR_ERR(hpriv);
+       of_id = of_match_node(ahci_qoriq_of_match, np);
+-      if (!of_id)
++      acpi_id = acpi_match_device(ahci_qoriq_acpi_match, &pdev->dev);
++      if (!(of_id || acpi_id))
+               return -ENODEV;
+       qoriq_priv = devm_kzalloc(dev, sizeof(*qoriq_priv), GFP_KERNEL);
+       if (!qoriq_priv)
+               return -ENOMEM;
+-      qoriq_priv->type = (enum ahci_qoriq_type)of_id->data;
++      if (of_id)
++              qoriq_priv->type = (enum ahci_qoriq_type)of_id->data;
++      else
++              qoriq_priv->type = (enum ahci_qoriq_type)acpi_id->driver_data;
+       if (unlikely(!ecc_initialized)) {
+               res = platform_get_resource_byname(pdev,
+@@ -288,7 +300,8 @@ static int ahci_qoriq_probe(struct platf
+               }
+       }
+-      qoriq_priv->is_dmacoherent = of_dma_is_coherent(np);
++      if (device_get_dma_attr(&pdev->dev) == DEV_DMA_COHERENT)
++              qoriq_priv->is_dmacoherent = true;
+       rc = ahci_platform_enable_resources(hpriv);
+       if (rc)
+@@ -354,6 +367,7 @@ static struct platform_driver ahci_qoriq
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table = ahci_qoriq_of_match,
++              .acpi_match_table = ahci_qoriq_acpi_match,
+               .pm = &ahci_qoriq_pm_ops,
+       },
+ };
diff --git a/target/linux/layerscape/patches-5.4/815-sata-0002-ahci-qoriq-workaround-for-errata-A-379364-on-lx2160a.patch b/target/linux/layerscape/patches-5.4/815-sata-0002-ahci-qoriq-workaround-for-errata-A-379364-on-lx2160a.patch
new file mode 100644 (file)
index 0000000..ff5ae9c
--- /dev/null
@@ -0,0 +1,191 @@
+From 73f7122003fca0d08142370e5b6c25783a7b43e9 Mon Sep 17 00:00:00 2001
+From: Peng Ma <peng.ma@nxp.com>
+Date: Wed, 15 May 2019 05:52:44 +0000
+Subject: [PATCH] ahci: qoriq: workaround for errata A-379364 on lx2160a
+
+There is a erratum on lx2160a which is: "SATA link is
+going down sometime during sata initialization"
+The workaround for it is to reset the lane. This patch
+implements this workaround.
+This erratum only exists on lx2160 Rev1, will be addressed
+on Rev2 and later.
+
+Signed-off-by: Peng Ma <peng.ma@nxp.com>
+---
+ drivers/ata/ahci_qoriq.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 144 insertions(+)
+
+--- a/drivers/ata/ahci_qoriq.c
++++ b/drivers/ata/ahci_qoriq.c
+@@ -48,6 +48,27 @@
+ #define ECC_DIS_ARMV8_CH2     0x80000000
+ #define ECC_DIS_LS1088A               0x40000000
++/* errata for lx2160 */
++#define RCWSR29_BASE                  0x1E00170
++#define SERDES2_BASE                  0x1EB0000
++#define DEVICE_CONFIG_REG_BASE                0x1E00000
++#define SERDES2_LNAX_RX_CR(x)         (0x840 + (0x100 * (x)))
++#define SERDES2_LNAX_RX_CBR(x)                (0x8C0 + (0x100 * (x)))
++#define SYS_VER_REG                   0xA4
++#define LN_RX_RST                     0x80000010
++#define LN_RX_RST_DONE                        0x3
++#define LN_RX_MASK                    0xf
++#define LX2160A_VER1                  0x1
++
++#define SERDES2_LNAA 0
++#define SERDES2_LNAB 1
++#define SERDES2_LNAC 2
++#define SERDES2_LNAD 3
++#define SERDES2_LNAE 4
++#define SERDES2_LNAF 5
++#define SERDES2_LNAG 6
++#define SERDES2_LNAH 7
++
+ enum ahci_qoriq_type {
+       AHCI_LS1021A,
+       AHCI_LS1028A,
+@@ -87,6 +108,126 @@ static const struct acpi_device_id ahci_
+ };
+ MODULE_DEVICE_TABLE(acpi, ahci_qoriq_acpi_match);
++static void fsl_sata_errata_379364(bool select)
++{
++      int val = 0;
++      void __iomem *rcw_base = NULL;
++      void __iomem *serdes_base = NULL;
++      void __iomem *dev_con_base = NULL;
++
++      if (select) {
++              dev_con_base = ioremap(DEVICE_CONFIG_REG_BASE, PAGE_SIZE);
++              if (!dev_con_base)
++                      return;
++
++              val = (readl(dev_con_base + SYS_VER_REG) & GENMASK(7, 4)) >> 4;
++              if (val != LX2160A_VER1)
++                      goto dev_unmap;
++
++              /*
++               * Add few msec delay.
++               * Check for corresponding serdes lane RST_DONE .
++               * apply lane reset.
++               */
++
++              serdes_base = ioremap(SERDES2_BASE, PAGE_SIZE);
++              if (!serdes_base)
++                      goto dev_unmap;
++
++              rcw_base = ioremap(RCWSR29_BASE, PAGE_SIZE);
++              if (!rcw_base)
++                      goto serdes_unmap;
++
++              msleep(20);
++
++              val = (readl(rcw_base) & GENMASK(25, 21)) >> 21;
++
++              switch (val) {
++              case 1:
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAC)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAC));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAD)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAD));
++                      break;
++
++              case 4:
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAG)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAG));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAH)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAH));
++                      break;
++
++              case 5:
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAE)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAE));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAF)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAF));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAG)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAG));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAH)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAH));
++                      break;
++
++              case 8:
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAC)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAC));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAD)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAD));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAE)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAE));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAF)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAF));
++                      break;
++
++              case 12:
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAG)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAG));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAH)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAH));
++                      break;
++
++              default:
++                      break;
++              }
++      } else {
++              return;
++      }
++
++      iounmap(rcw_base);
++serdes_unmap:
++      iounmap(serdes_base);
++dev_unmap:
++      iounmap(dev_con_base);
++}
++
+ static int ahci_qoriq_hardreset(struct ata_link *link, unsigned int *class,
+                         unsigned long deadline)
+ {
+@@ -102,6 +243,7 @@ static int ahci_qoriq_hardreset(struct a
+       bool online;
+       int rc;
+       bool ls1021a_workaround = (qoriq_priv->type == AHCI_LS1021A);
++      bool lx2160a_workaround = (qoriq_priv->type == AHCI_LX2160A);
+       DPRINTK("ENTER\n");
+@@ -128,6 +270,8 @@ static int ahci_qoriq_hardreset(struct a
+       tf.command = ATA_BUSY;
+       ata_tf_to_fis(&tf, 0, 0, d2h_fis);
++      fsl_sata_errata_379364(lx2160a_workaround);
++
+       rc = sata_link_hardreset(link, timing, deadline, &online,
+                                ahci_check_ready);
diff --git a/target/linux/layerscape/patches-5.4/815-sata-0003-ahci_qoriq-bug-fix-for-ecc_addr.patch b/target/linux/layerscape/patches-5.4/815-sata-0003-ahci_qoriq-bug-fix-for-ecc_addr.patch
new file mode 100644 (file)
index 0000000..ab9cc8c
--- /dev/null
@@ -0,0 +1,31 @@
+From a148b8623b7d97c87857f9e203bad538ebd837f0 Mon Sep 17 00:00:00 2001
+From: Udit Kumar <udit.kumar@nxp.com>
+Date: Wed, 12 Jun 2019 10:42:02 +0530
+Subject: [PATCH] ahci_qoriq: bug fix for ecc_addr
+
+Original driver expect a register node with name "sata-ecc"
+this node is of 64 bit wide.
+In ACPI such nodes can be provided with QWordMemory, but
+QWordMemory can not hold DescriptorName more than 4 characters.
+
+Therefore this patch changes platform property retrival based
+upon index instead of named.
+
+Signed-off-by: Udit Kumar <udit.kumar@nxp.com>
+---
+ drivers/ata/ahci_qoriq.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/ata/ahci_qoriq.c
++++ b/drivers/ata/ahci_qoriq.c
+@@ -433,9 +433,7 @@ static int ahci_qoriq_probe(struct platf
+               qoriq_priv->type = (enum ahci_qoriq_type)acpi_id->driver_data;
+       if (unlikely(!ecc_initialized)) {
+-              res = platform_get_resource_byname(pdev,
+-                                                 IORESOURCE_MEM,
+-                                                 "sata-ecc");
++              res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+               if (res) {
+                       qoriq_priv->ecc_addr =
+                               devm_ioremap_resource(dev, res);
diff --git a/target/linux/layerscape/patches-5.4/816-sdhc-0001-mmc-sdhci-of-esdhc-poll-ESDHC_FLUSH_ASYNC_FIFO-bit-u.patch b/target/linux/layerscape/patches-5.4/816-sdhc-0001-mmc-sdhci-of-esdhc-poll-ESDHC_FLUSH_ASYNC_FIFO-bit-u.patch
new file mode 100644 (file)
index 0000000..91d1f2c
--- /dev/null
@@ -0,0 +1,72 @@
+From 0f5cf5dcc3ca4f8e610ebe1e62e3d3546b9d09ca Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Mon, 16 Sep 2019 19:17:44 +0800
+Subject: [PATCH] mmc: sdhci-of-esdhc: poll ESDHC_FLUSH_ASYNC_FIFO bit until
+ completion
+
+The ESDHC_FLUSH_ASYNC_FIFO bit which is set to flush asynchronous FIFO
+should be polled until it's auto cleared by hardware.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/mmc/host/sdhci-of-esdhc.c | 35 ++++++++++++++++++++++++++++-------
+ 1 file changed, 28 insertions(+), 7 deletions(-)
+
+--- a/drivers/mmc/host/sdhci-of-esdhc.c
++++ b/drivers/mmc/host/sdhci-of-esdhc.c
+@@ -591,6 +591,32 @@ static void esdhc_clock_enable(struct sd
+       }
+ }
++static void esdhc_flush_async_fifo(struct sdhci_host *host)
++{
++      ktime_t timeout;
++      u32 val;
++
++      val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
++      val |= ESDHC_FLUSH_ASYNC_FIFO;
++      sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
++
++      /* Wait max 20 ms */
++      timeout = ktime_add_ms(ktime_get(), 20);
++      while (1) {
++              bool timedout = ktime_after(ktime_get(), timeout);
++
++              if (!(sdhci_readl(host, ESDHC_DMA_SYSCTL) &
++                    ESDHC_FLUSH_ASYNC_FIFO))
++                      break;
++              if (timedout) {
++                      pr_err("%s: flushing asynchronous FIFO timeout.\n",
++                              mmc_hostname(host->mmc));
++                      break;
++              }
++              usleep_range(10, 20);
++      }
++}
++
+ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
+ {
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+@@ -683,9 +709,7 @@ static void esdhc_of_set_clock(struct sd
+               sdhci_writel(host, temp | ESDHC_HS400_WNDW_ADJUST, ESDHC_TBCTL);
+               esdhc_clock_enable(host, false);
+-              temp = sdhci_readl(host, ESDHC_DMA_SYSCTL);
+-              temp |= ESDHC_FLUSH_ASYNC_FIFO;
+-              sdhci_writel(host, temp, ESDHC_DMA_SYSCTL);
++              esdhc_flush_async_fifo(host);
+       }
+       /* Wait max 20 ms */
+@@ -852,10 +876,7 @@ static void esdhc_tuning_block_enable(st
+       u32 val;
+       esdhc_clock_enable(host, false);
+-
+-      val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
+-      val |= ESDHC_FLUSH_ASYNC_FIFO;
+-      sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
++      esdhc_flush_async_fifo(host);
+       val = sdhci_readl(host, ESDHC_TBCTL);
+       if (enable)
diff --git a/target/linux/layerscape/patches-5.4/816-sdhc-0002-LF-605-mmc-sdhci-of-esdhc-convert-to-use-esdhc_tunin.patch b/target/linux/layerscape/patches-5.4/816-sdhc-0002-LF-605-mmc-sdhci-of-esdhc-convert-to-use-esdhc_tunin.patch
new file mode 100644 (file)
index 0000000..74dd63d
--- /dev/null
@@ -0,0 +1,77 @@
+From e95c04bd6d9ebe081126184fb228461b1b3fa7aa Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Thu, 12 Dec 2019 15:52:18 +0800
+Subject: [PATCH] LF-605 mmc: sdhci-of-esdhc: convert to use
+ esdhc_tuning_window_ptr()
+
+Convert to use a new function esdhc_tuning_window_ptr() to
+get tuning window start point and end point.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+Acked-by: Adrian Hunter <adrian.hunter@intel.com>
+---
+ drivers/mmc/host/sdhci-of-esdhc.c | 34 +++++++++++++++++++++-------------
+ 1 file changed, 21 insertions(+), 13 deletions(-)
+
+--- a/drivers/mmc/host/sdhci-of-esdhc.c
++++ b/drivers/mmc/host/sdhci-of-esdhc.c
+@@ -888,20 +888,11 @@ static void esdhc_tuning_block_enable(st
+       esdhc_clock_enable(host, true);
+ }
+-static void esdhc_prepare_sw_tuning(struct sdhci_host *host, u8 *window_start,
++static void esdhc_tuning_window_ptr(struct sdhci_host *host, u8 *window_start,
+                                   u8 *window_end)
+ {
+-      struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+-      struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
+-      u8 tbstat_15_8, tbstat_7_0;
+       u32 val;
+-      if (esdhc->quirk_tuning_erratum_type1) {
+-              *window_start = 5 * esdhc->div_ratio;
+-              *window_end = 3 * esdhc->div_ratio;
+-              return;
+-      }
+-
+       /* Write TBCTL[11:8]=4'h8 */
+       val = sdhci_readl(host, ESDHC_TBCTL);
+       val &= ~(0xf << 8);
+@@ -920,6 +911,25 @@ static void esdhc_prepare_sw_tuning(stru
+       val = sdhci_readl(host, ESDHC_TBSTAT);
+       val = sdhci_readl(host, ESDHC_TBSTAT);
++      *window_end = val & 0xff;
++      *window_start = (val >> 8) & 0xff;
++}
++
++static void esdhc_prepare_sw_tuning(struct sdhci_host *host, u8 *window_start,
++                                  u8 *window_end)
++{
++      struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
++      struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
++      u8 start_ptr, end_ptr;
++
++      if (esdhc->quirk_tuning_erratum_type1) {
++              *window_start = 5 * esdhc->div_ratio;
++              *window_end = 3 * esdhc->div_ratio;
++              return;
++      }
++
++      esdhc_tuning_window_ptr(host, &start_ptr, &end_ptr);
++
+       /* Reset data lines by setting ESDHCCTL[RSTD] */
+       sdhci_reset(host, SDHCI_RESET_DATA);
+       /* Write 32'hFFFF_FFFF to IRQSTAT register */
+@@ -930,10 +940,8 @@ static void esdhc_prepare_sw_tuning(stru
+        * then program TBPTR[TB_WNDW_END_PTR] = 4 * div_ratio
+        * and program TBPTR[TB_WNDW_START_PTR] = 8 * div_ratio.
+        */
+-      tbstat_7_0 = val & 0xff;
+-      tbstat_15_8 = (val >> 8) & 0xff;
+-      if (abs(tbstat_15_8 - tbstat_7_0) > (4 * esdhc->div_ratio)) {
++      if (abs(start_ptr - end_ptr) > (4 * esdhc->div_ratio)) {
+               *window_start = 8 * esdhc->div_ratio;
+               *window_end = 4 * esdhc->div_ratio;
+       } else {
diff --git a/target/linux/layerscape/patches-5.4/816-sdhc-0003-LF-605-mmc-sdhci-of-esdhc-update-tuning-erratum-A-00.patch b/target/linux/layerscape/patches-5.4/816-sdhc-0003-LF-605-mmc-sdhci-of-esdhc-update-tuning-erratum-A-00.patch
new file mode 100644 (file)
index 0000000..a391616
--- /dev/null
@@ -0,0 +1,90 @@
+From f3d460fb85677a5f62324771e5715ceb11726ecc Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Thu, 12 Dec 2019 15:52:19 +0800
+Subject: [PATCH] LF-605 mmc: sdhci-of-esdhc: update tuning erratum A-008171
+
+There is an official update for eSDHC tuning erratum A-008171.
+This patch is to implement the changes,
+- Affect all revisions of SoC.
+- Changes for tuning window checking.
+- Hardware hits a new condition that tuning succeeds although
+  the eSDHC might not have tuned properly for type2 SoCs
+  (soc_tuning_erratum_type2[] array in driver). So check
+  tuning window after tuning succeeds.
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+Acked-by: Adrian Hunter <adrian.hunter@intel.com>
+---
+ drivers/mmc/host/sdhci-of-esdhc.c | 39 ++++++++++++++++++++++++++-------------
+ 1 file changed, 26 insertions(+), 13 deletions(-)
+
+--- a/drivers/mmc/host/sdhci-of-esdhc.c
++++ b/drivers/mmc/host/sdhci-of-esdhc.c
+@@ -854,20 +854,20 @@ static int esdhc_signal_voltage_switch(s
+ }
+ static struct soc_device_attribute soc_tuning_erratum_type1[] = {
+-      { .family = "QorIQ T1023", .revision = "1.0", },
+-      { .family = "QorIQ T1040", .revision = "1.0", },
+-      { .family = "QorIQ T2080", .revision = "1.0", },
+-      { .family = "QorIQ LS1021A", .revision = "1.0", },
++      { .family = "QorIQ T1023", },
++      { .family = "QorIQ T1040", },
++      { .family = "QorIQ T2080", },
++      { .family = "QorIQ LS1021A", },
+       { },
+ };
+ static struct soc_device_attribute soc_tuning_erratum_type2[] = {
+-      { .family = "QorIQ LS1012A", .revision = "1.0", },
+-      { .family = "QorIQ LS1043A", .revision = "1.*", },
+-      { .family = "QorIQ LS1046A", .revision = "1.0", },
+-      { .family = "QorIQ LS1080A", .revision = "1.0", },
+-      { .family = "QorIQ LS2080A", .revision = "1.0", },
+-      { .family = "QorIQ LA1575A", .revision = "1.0", },
++      { .family = "QorIQ LS1012A", },
++      { .family = "QorIQ LS1043A", },
++      { .family = "QorIQ LS1046A", },
++      { .family = "QorIQ LS1080A", },
++      { .family = "QorIQ LS2080A", },
++      { .family = "QorIQ LA1575A", },
+       { },
+ };
+@@ -935,13 +935,13 @@ static void esdhc_prepare_sw_tuning(stru
+       /* Write 32'hFFFF_FFFF to IRQSTAT register */
+       sdhci_writel(host, 0xFFFFFFFF, SDHCI_INT_STATUS);
+-      /* If TBSTAT[15:8]-TBSTAT[7:0] > 4 * div_ratio
+-       * or TBSTAT[7:0]-TBSTAT[15:8] > 4 * div_ratio,
++      /* If TBSTAT[15:8]-TBSTAT[7:0] > (4 * div_ratio) + 2
++       * or TBSTAT[7:0]-TBSTAT[15:8] > (4 * div_ratio) + 2,
+        * then program TBPTR[TB_WNDW_END_PTR] = 4 * div_ratio
+        * and program TBPTR[TB_WNDW_START_PTR] = 8 * div_ratio.
+        */
+-      if (abs(start_ptr - end_ptr) > (4 * esdhc->div_ratio)) {
++      if (abs(start_ptr - end_ptr) > (4 * esdhc->div_ratio + 2)) {
+               *window_start = 8 * esdhc->div_ratio;
+               *window_end = 4 * esdhc->div_ratio;
+       } else {
+@@ -1014,6 +1014,19 @@ static int esdhc_execute_tuning(struct m
+               if (ret)
+                       break;
++              /* For type2 affected platforms of the tuning erratum,
++               * tuning may succeed although eSDHC might not have
++               * tuned properly. Need to check tuning window.
++               */
++              if (esdhc->quirk_tuning_erratum_type2 &&
++                  !host->tuning_err) {
++                      esdhc_tuning_window_ptr(host, &window_start,
++                                              &window_end);
++                      if (abs(window_start - window_end) >
++                          (4 * esdhc->div_ratio + 2))
++                              host->tuning_err = -EAGAIN;
++              }
++
+               /* If HW tuning fails and triggers erratum,
+                * try workaround.
+                */
diff --git a/target/linux/layerscape/patches-5.4/817-spi-0001-spi-spi-fsl-qspi-dynamically-alloc-AHB-memory-for-QS.patch b/target/linux/layerscape/patches-5.4/817-spi-0001-spi-spi-fsl-qspi-dynamically-alloc-AHB-memory-for-QS.patch
new file mode 100644 (file)
index 0000000..97c8eab
--- /dev/null
@@ -0,0 +1,139 @@
+From e1cf48a13626d0c42c5191dc4852f4dc271de010 Mon Sep 17 00:00:00 2001
+From: Han Xu <han.xu@nxp.com>
+Date: Tue, 9 Jul 2019 16:21:14 -0500
+Subject: [PATCH] spi: spi-fsl-qspi: dynamically alloc AHB memory for QSPI
+
+dynamically alloc AHB memory for QSPI controller.
+
+Signed-off-by: Han Xu <han.xu@nxp.com>
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/spi/spi-fsl-qspi.c | 60 +++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 43 insertions(+), 17 deletions(-)
+
+--- a/drivers/spi/spi-fsl-qspi.c
++++ b/drivers/spi/spi-fsl-qspi.c
+@@ -192,6 +192,8 @@
+  */
+ #define QUADSPI_QUIRK_USE_TDH_SETTING BIT(5)
++#define QUADSPI_MIN_IOMAP             SZ_4M
++
+ struct fsl_qspi_devtype_data {
+       unsigned int rxfifo;
+       unsigned int txfifo;
+@@ -254,6 +256,9 @@ struct fsl_qspi {
+       void __iomem *iobase;
+       void __iomem *ahb_addr;
+       u32 memmap_phy;
++      u32 memmap_phy_size;
++      u32 memmap_start;
++      u32 memmap_len;
+       struct clk *clk, *clk_en;
+       struct device *dev;
+       struct completion c;
+@@ -537,11 +542,34 @@ static void fsl_qspi_select_mem(struct f
+       fsl_qspi_invalidate(q);
+ }
+-static void fsl_qspi_read_ahb(struct fsl_qspi *q, const struct spi_mem_op *op)
++static int fsl_qspi_read_ahb(struct fsl_qspi *q, const struct spi_mem_op *op)
+ {
++      u32 start = op->addr.val + q->selected * q->memmap_phy_size / 4;
++      u32 len = op->data.nbytes;
++
++      /* if necessary, ioremap before AHB read */
++      if ((!q->ahb_addr) || start < q->memmap_start ||
++          start + len > q->memmap_start + q->memmap_len) {
++              if (q->ahb_addr) {
++                      iounmap(q->ahb_addr);
++              }
++
++              q->memmap_start = start;
++              q->memmap_len = len > QUADSPI_MIN_IOMAP ?
++                              len : QUADSPI_MIN_IOMAP;
++
++              q->ahb_addr = ioremap_wc(q->memmap_phy + q->memmap_start,
++                                       q->memmap_len);
++              if (!q->ahb_addr) {
++                      dev_err(q->dev, "failed to alloc memory\n");
++                      return -ENOMEM;
++              }
++      }
++
+       memcpy_fromio(op->data.buf.in,
+-                    q->ahb_addr + q->selected * q->devtype_data->ahb_buf_size,
+-                    op->data.nbytes);
++                    q->ahb_addr + start - q->memmap_start, len);
++
++      return 0;
+ }
+ static void fsl_qspi_fill_txfifo(struct fsl_qspi *q,
+@@ -646,7 +674,7 @@ static int fsl_qspi_exec_op(struct spi_m
+               addr_offset = q->memmap_phy;
+       qspi_writel(q,
+-                  q->selected * q->devtype_data->ahb_buf_size + addr_offset,
++                  q->selected * q->memmap_phy_size / 4 + addr_offset,
+                   base + QUADSPI_SFAR);
+       qspi_writel(q, qspi_readl(q, base + QUADSPI_MCR) |
+@@ -665,7 +693,7 @@ static int fsl_qspi_exec_op(struct spi_m
+        */
+       if (op->data.nbytes > (q->devtype_data->rxfifo - 4) &&
+           op->data.dir == SPI_MEM_DATA_IN) {
+-              fsl_qspi_read_ahb(q, op);
++              err = fsl_qspi_read_ahb(q, op);
+       } else {
+               qspi_writel(q, QUADSPI_RBCT_WMRK_MASK |
+                           QUADSPI_RBCT_RXBRD_USEIPS, base + QUADSPI_RBCT);
+@@ -763,16 +791,16 @@ static int fsl_qspi_default_setup(struct
+        * In HW there can be a maximum of four chips on two buses with
+        * two chip selects on each bus. We use four chip selects in SW
+        * to differentiate between the four chips.
+-       * We use ahb_buf_size for each chip and set SFA1AD, SFA2AD, SFB1AD,
+-       * SFB2AD accordingly.
++       * We divide the total memory region size equally for each chip
++       * and set SFA1AD, SFA2AD, SFB1AD, SFB2AD accordingly.
+        */
+-      qspi_writel(q, q->devtype_data->ahb_buf_size + addr_offset,
++      qspi_writel(q, q->memmap_phy_size / 4 + addr_offset,
+                   base + QUADSPI_SFA1AD);
+-      qspi_writel(q, q->devtype_data->ahb_buf_size * 2 + addr_offset,
++      qspi_writel(q, q->memmap_phy_size / 4 * 2 + addr_offset,
+                   base + QUADSPI_SFA2AD);
+-      qspi_writel(q, q->devtype_data->ahb_buf_size * 3 + addr_offset,
++      qspi_writel(q, q->memmap_phy_size / 4 * 3 + addr_offset,
+                   base + QUADSPI_SFB1AD);
+-      qspi_writel(q, q->devtype_data->ahb_buf_size * 4 + addr_offset,
++      qspi_writel(q, q->memmap_phy_size / 4 * 4 + addr_offset,
+                   base + QUADSPI_SFB2AD);
+       q->selected = -1;
+@@ -859,13 +887,8 @@ static int fsl_qspi_probe(struct platfor
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                       "QuadSPI-memory");
+-      q->ahb_addr = devm_ioremap_resource(dev, res);
+-      if (IS_ERR(q->ahb_addr)) {
+-              ret = PTR_ERR(q->ahb_addr);
+-              goto err_put_ctrl;
+-      }
+-
+       q->memmap_phy = res->start;
++      q->memmap_phy_size = resource_size(res);
+       /* find the clocks */
+       q->clk_en = devm_clk_get(dev, "qspi_en");
+@@ -939,6 +962,9 @@ static int fsl_qspi_remove(struct platfo
+       mutex_destroy(&q->lock);
++      if (q->ahb_addr)
++              iounmap(q->ahb_addr);
++
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/817-spi-0002-spi-spi-fsl-qspi-Introduce-variable-to-fix-different.patch b/target/linux/layerscape/patches-5.4/817-spi-0002-spi-spi-fsl-qspi-Introduce-variable-to-fix-different.patch
new file mode 100644 (file)
index 0000000..2afc651
--- /dev/null
@@ -0,0 +1,108 @@
+From be9165b9fdcf2a18ee201ffdaf8d69801387eb91 Mon Sep 17 00:00:00 2001
+From: Kuldeep Singh <kuldeep.singh@nxp.com>
+Date: Tue, 18 Feb 2020 10:42:50 +0800
+Subject: [PATCH] spi: spi-fsl-qspi: Introduce variable to fix different
+ invalid master Id
+
+Different platforms have different Master with different SourceID on
+AHB bus. The 0X0E Master ID is used by cluster 3 in case of LS2088A.
+So, patch introduce an invalid master id variable to fix invalid
+mastered on different platforms.
+
+Signed-off-by: Suresh Gupta <suresh.gupta@nxp.com>
+Signed-off-by: Kuldeep Singh <kuldeep.singh@nxp.com>
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/spi/spi-fsl-qspi.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/drivers/spi/spi-fsl-qspi.c
++++ b/drivers/spi/spi-fsl-qspi.c
+@@ -68,6 +68,11 @@
+ #define QUADSPI_FLSHCR_TCSH_MASK      GENMASK(11, 8)
+ #define QUADSPI_FLSHCR_TDH_MASK               GENMASK(17, 16)
++#define QUADSPI_BUF0CR                  0x10
++#define QUADSPI_BUF1CR                  0x14
++#define QUADSPI_BUF2CR                  0x18
++#define QUADSPI_BUFXCR_INVALID_MSTRID   0xe
++
+ #define QUADSPI_BUF3CR                        0x1c
+ #define QUADSPI_BUF3CR_ALLMST_MASK    BIT(31)
+ #define QUADSPI_BUF3CR_ADATSZ(x)      ((x) << 8)
+@@ -197,6 +202,7 @@
+ struct fsl_qspi_devtype_data {
+       unsigned int rxfifo;
+       unsigned int txfifo;
++      int invalid_mstrid;
+       unsigned int ahb_buf_size;
+       unsigned int quirks;
+       bool little_endian;
+@@ -205,6 +211,7 @@ struct fsl_qspi_devtype_data {
+ static const struct fsl_qspi_devtype_data vybrid_data = {
+       .rxfifo = SZ_128,
+       .txfifo = SZ_64,
++      .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
+       .ahb_buf_size = SZ_1K,
+       .quirks = QUADSPI_QUIRK_SWAP_ENDIAN,
+       .little_endian = true,
+@@ -213,6 +220,7 @@ static const struct fsl_qspi_devtype_dat
+ static const struct fsl_qspi_devtype_data imx6sx_data = {
+       .rxfifo = SZ_128,
+       .txfifo = SZ_512,
++      .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
+       .ahb_buf_size = SZ_1K,
+       .quirks = QUADSPI_QUIRK_4X_INT_CLK | QUADSPI_QUIRK_TKT245618,
+       .little_endian = true,
+@@ -221,6 +229,7 @@ static const struct fsl_qspi_devtype_dat
+ static const struct fsl_qspi_devtype_data imx7d_data = {
+       .rxfifo = SZ_128,
+       .txfifo = SZ_512,
++      .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
+       .ahb_buf_size = SZ_1K,
+       .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK |
+                 QUADSPI_QUIRK_USE_TDH_SETTING,
+@@ -230,6 +239,7 @@ static const struct fsl_qspi_devtype_dat
+ static const struct fsl_qspi_devtype_data imx6ul_data = {
+       .rxfifo = SZ_128,
+       .txfifo = SZ_512,
++      .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
+       .ahb_buf_size = SZ_1K,
+       .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK |
+                 QUADSPI_QUIRK_USE_TDH_SETTING,
+@@ -239,6 +249,7 @@ static const struct fsl_qspi_devtype_dat
+ static const struct fsl_qspi_devtype_data ls1021a_data = {
+       .rxfifo = SZ_128,
+       .txfifo = SZ_64,
++      .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
+       .ahb_buf_size = SZ_1K,
+       .quirks = 0,
+       .little_endian = false,
+@@ -248,6 +259,7 @@ static const struct fsl_qspi_devtype_dat
+       .rxfifo = SZ_128,
+       .txfifo = SZ_64,
+       .ahb_buf_size = SZ_1K,
++      .invalid_mstrid = 0x0,
+       .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_BASE_INTERNAL,
+       .little_endian = true,
+ };
+@@ -661,6 +673,7 @@ static int fsl_qspi_exec_op(struct spi_m
+       void __iomem *base = q->iobase;
+       u32 addr_offset = 0;
+       int err = 0;
++      int invalid_mstrid = q->devtype_data->invalid_mstrid;
+       mutex_lock(&q->lock);
+@@ -684,6 +697,10 @@ static int fsl_qspi_exec_op(struct spi_m
+       qspi_writel(q, QUADSPI_SPTRCLR_BFPTRC | QUADSPI_SPTRCLR_IPPTRC,
+                   base + QUADSPI_SPTRCLR);
++      qspi_writel(q, invalid_mstrid, base + QUADSPI_BUF0CR);
++      qspi_writel(q, invalid_mstrid, base + QUADSPI_BUF1CR);
++      qspi_writel(q, invalid_mstrid, base + QUADSPI_BUF2CR);
++
+       fsl_qspi_prepare_lut(q, op);
+       /*
diff --git a/target/linux/layerscape/patches-5.4/817-spi-0003-MLK-21960-1-spi-fspi-enable-fspi-on-imx8qxp-and-imx8.patch b/target/linux/layerscape/patches-5.4/817-spi-0003-MLK-21960-1-spi-fspi-enable-fspi-on-imx8qxp-and-imx8.patch
new file mode 100644 (file)
index 0000000..59906dd
--- /dev/null
@@ -0,0 +1,46 @@
+From 13f63bc4a1a08aaed6d64ea9c6b0bec02be225ce Mon Sep 17 00:00:00 2001
+From: Han Xu <han.xu@nxp.com>
+Date: Wed, 5 Jun 2019 16:43:08 -0500
+Subject: [PATCH] MLK-21960-1: spi: fspi: enable fspi on imx8qxp and imx8mm
+
+enable fspi on imx8qxp and imx8mm
+
+Signed-off-by: Han Xu <han.xu@nxp.com>
+---
+ drivers/spi/spi-nxp-fspi.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+--- a/drivers/spi/spi-nxp-fspi.c
++++ b/drivers/spi/spi-nxp-fspi.c
+@@ -324,6 +324,22 @@ static const struct nxp_fspi_devtype_dat
+       .little_endian = true,  /* little-endian    */
+ };
++static const struct nxp_fspi_devtype_data imx8mm_data = {
++      .rxfifo = SZ_512,       /* (64  * 64 bits)  */
++      .txfifo = SZ_1K,        /* (128 * 64 bits)  */
++      .ahb_buf_size = SZ_2K,  /* (256 * 64 bits)  */
++      .quirks = 0,
++      .little_endian = true,  /* little-endian    */
++};
++
++static const struct nxp_fspi_devtype_data imx8qxp_data = {
++      .rxfifo = SZ_512,       /* (64  * 64 bits)  */
++      .txfifo = SZ_1K,        /* (128 * 64 bits)  */
++      .ahb_buf_size = SZ_2K,  /* (256 * 64 bits)  */
++      .quirks = 0,
++      .little_endian = true,  /* little-endian    */
++};
++
+ struct nxp_fspi {
+       void __iomem *iobase;
+       void __iomem *ahb_addr;
+@@ -1076,6 +1092,8 @@ static int nxp_fspi_resume(struct device
+ static const struct of_device_id nxp_fspi_dt_ids[] = {
+       { .compatible = "nxp,lx2160a-fspi", .data = (void *)&lx2160a_data, },
++      { .compatible = "nxp,imx8mm-fspi", .data = (void *)&imx8mm_data, },
++      { .compatible = "nxp,imx8qxp-fspi", .data = (void *)&imx8qxp_data, },
+       { /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, nxp_fspi_dt_ids);
diff --git a/target/linux/layerscape/patches-5.4/817-spi-0004-MLK-21960-2-spi-fspi-dynamically-alloc-AHB-memory.patch b/target/linux/layerscape/patches-5.4/817-spi-0004-MLK-21960-2-spi-fspi-dynamically-alloc-AHB-memory.patch
new file mode 100644 (file)
index 0000000..ed8dc30
--- /dev/null
@@ -0,0 +1,100 @@
+From 6e46fe6d9428a41543bd19644de3c9f2611b73bf Mon Sep 17 00:00:00 2001
+From: Han Xu <han.xu@nxp.com>
+Date: Wed, 5 Jun 2019 16:43:30 -0500
+Subject: [PATCH] MLK-21960-2: spi: fspi: dynamically alloc AHB memory
+
+dynamically allocate AHB memory as needed.
+
+Signed-off-by: Han Xu <han.xu@nxp.com>
+---
+ drivers/spi/spi-nxp-fspi.c | 40 ++++++++++++++++++++++++++++++++++------
+ 1 file changed, 34 insertions(+), 6 deletions(-)
+
+--- a/drivers/spi/spi-nxp-fspi.c
++++ b/drivers/spi/spi-nxp-fspi.c
+@@ -307,6 +307,7 @@
+ #define POLL_TOUT             5000
+ #define NXP_FSPI_MAX_CHIPSELECT               4
++#define NXP_FSPI_MIN_IOMAP    SZ_4M
+ struct nxp_fspi_devtype_data {
+       unsigned int rxfifo;
+@@ -345,6 +346,8 @@ struct nxp_fspi {
+       void __iomem *ahb_addr;
+       u32 memmap_phy;
+       u32 memmap_phy_size;
++      u32 memmap_start;
++      u32 memmap_len;
+       struct clk *clk, *clk_en;
+       struct device *dev;
+       struct completion c;
+@@ -657,12 +660,35 @@ static void nxp_fspi_select_mem(struct n
+       f->selected = spi->chip_select;
+ }
+-static void nxp_fspi_read_ahb(struct nxp_fspi *f, const struct spi_mem_op *op)
++static int nxp_fspi_read_ahb(struct nxp_fspi *f, const struct spi_mem_op *op)
+ {
++      u32 start = op->addr.val;
+       u32 len = op->data.nbytes;
++      /* if necessary, ioremap before AHB read */
++      if ((!f->ahb_addr) || start < f->memmap_start ||
++           start + len > f->memmap_start + f->memmap_len) {
++              if (f->ahb_addr)
++                      iounmap(f->ahb_addr);
++
++              f->memmap_start = start;
++              f->memmap_len = len > NXP_FSPI_MIN_IOMAP ?
++                              len : NXP_FSPI_MIN_IOMAP;
++
++              f->ahb_addr = ioremap_wc(f->memmap_phy + f->memmap_start,
++                                       f->memmap_len);
++
++              if (!f->ahb_addr) {
++                      dev_err(f->dev, "failed to alloc memory\n");
++                      return -ENOMEM;
++              }
++      }
++
+       /* Read out the data directly from the AHB buffer. */
+-      memcpy_fromio(op->data.buf.in, (f->ahb_addr + op->addr.val), len);
++      memcpy_fromio(op->data.buf.in,
++                    f->ahb_addr + start - f->memmap_start, len);
++
++      return 0;
+ }
+ static void nxp_fspi_fill_txfifo(struct nxp_fspi *f,
+@@ -822,7 +848,7 @@ static int nxp_fspi_exec_op(struct spi_m
+        */
+       if (op->data.nbytes > (f->devtype_data->rxfifo - 4) &&
+           op->data.dir == SPI_MEM_DATA_IN) {
+-              nxp_fspi_read_ahb(f, op);
++              err = nxp_fspi_read_ahb(f, op);
+       } else {
+               if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT)
+                       nxp_fspi_fill_txfifo(f, op);
+@@ -992,9 +1018,8 @@ static int nxp_fspi_probe(struct platfor
+       /* find the resources - controller memory mapped space */
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fspi_mmap");
+-      f->ahb_addr = devm_ioremap_resource(dev, res);
+-      if (IS_ERR(f->ahb_addr)) {
+-              ret = PTR_ERR(f->ahb_addr);
++      if (IS_ERR(res)) {
++              ret = PTR_ERR(res);
+               goto err_put_ctrl;
+       }
+@@ -1073,6 +1098,9 @@ static int nxp_fspi_remove(struct platfo
+       mutex_destroy(&f->lock);
++      if (f->ahb_addr)
++              iounmap(f->ahb_addr);
++
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/817-spi-0005-spi-spi-nxp-fspi-Enable-the-Octal-Mode-in-MCR0.patch b/target/linux/layerscape/patches-5.4/817-spi-0005-spi-spi-nxp-fspi-Enable-the-Octal-Mode-in-MCR0.patch
new file mode 100644 (file)
index 0000000..4f7f784
--- /dev/null
@@ -0,0 +1,26 @@
+From cfa4dd5aafd797de69eb7c450d1236ba456dc543 Mon Sep 17 00:00:00 2001
+From: Han Xu <han.xu@nxp.com>
+Date: Wed, 30 Oct 2019 10:46:15 -0500
+Subject: [PATCH] spi: spi-nxp-fspi: Enable the Octal Mode in MCR0
+
+Enable the octal combination mode in MCR0
+
+Signed-off-by: Han Xu <han.xu@nxp.com>
+---
+ drivers/spi/spi-nxp-fspi.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/spi/spi-nxp-fspi.c
++++ b/drivers/spi/spi-nxp-fspi.c
+@@ -913,8 +913,9 @@ static int nxp_fspi_default_setup(struct
+       fspi_writel(f, FSPI_DLLBCR_OVRDEN, base + FSPI_DLLBCR);
+       /* enable module */
+-      fspi_writel(f, FSPI_MCR0_AHB_TIMEOUT(0xFF) | FSPI_MCR0_IP_TIMEOUT(0xFF),
+-               base + FSPI_MCR0);
++      fspi_writel(f, FSPI_MCR0_AHB_TIMEOUT(0xFF) |
++                  FSPI_MCR0_IP_TIMEOUT(0xFF) | (u32) FSPI_MCR0_OCTCOMB_EN,
++                  base + FSPI_MCR0);
+       /*
+        * Disable same device enable bit and configure all slave devices
diff --git a/target/linux/layerscape/patches-5.4/817-spi-0006-LF-20-2-mtd-spi-nor-Use-1-bit-mode-of-spansion-s25fs.patch b/target/linux/layerscape/patches-5.4/817-spi-0006-LF-20-2-mtd-spi-nor-Use-1-bit-mode-of-spansion-s25fs.patch
new file mode 100644 (file)
index 0000000..ddf7db9
--- /dev/null
@@ -0,0 +1,22 @@
+From 316be7f5f5f05e846b639b1eeee4267e18db9e69 Mon Sep 17 00:00:00 2001
+From: Kuldeep Singh <kuldeep.singh@nxp.com>
+Date: Fri, 3 Jan 2020 14:45:05 +0530
+Subject: [PATCH] LF-20-2 mtd: spi-nor: Use 1 bit mode of spansion(s25fs512s)
+ flash
+
+Signed-off-by: Kuldeep Singh <kuldeep.singh@nxp.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -2352,7 +2352,7 @@ static const struct flash_info spi_nor_i
+       { "s25fl512s",  INFO6(0x010220, 0x4d0080, 256 * 1024, 256,
+                       SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+                       SPI_NOR_HAS_LOCK | USE_CLSR) },
+-      { "s25fs512s",  INFO6(0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
++      { "s25fs512s",  INFO6(0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_4B_OPCODES | USE_CLSR) },
+       { "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
+       { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
+       { "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
diff --git a/target/linux/layerscape/patches-5.4/817-spi-0007-LF-18-3-spi-fsl-qspi-Allocate-AHB-memory-dynamically.patch b/target/linux/layerscape/patches-5.4/817-spi-0007-LF-18-3-spi-fsl-qspi-Allocate-AHB-memory-dynamically.patch
new file mode 100644 (file)
index 0000000..256d205
--- /dev/null
@@ -0,0 +1,187 @@
+From 2fc26b1b6377156e07c6c9ce934c58f634fcd21b Mon Sep 17 00:00:00 2001
+From: Kuldeep Singh <kuldeep.singh@nxp.com>
+Date: Wed, 1 Apr 2020 14:51:37 +0800
+Subject: [PATCH] LF-18-3 spi: fsl-qspi: Allocate AHB memory dynamically for
+ imx platforms
+
+LS platforms doesn't require dynamic allocaltion of AHB memory. So, let's
+define a quirk which allocates AHB memory dynamically only for imx
+platforms.
+
+Fixes: c70adc97("spi: spi-fsl-qspi: dynamically alloc AHB memory for QSPI")
+Signed-off-by: Kuldeep Singh <kuldeep.singh@nxp.com>
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/spi/spi-fsl-qspi.c | 71 +++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 55 insertions(+), 16 deletions(-)
+
+--- a/drivers/spi/spi-fsl-qspi.c
++++ b/drivers/spi/spi-fsl-qspi.c
+@@ -197,6 +197,12 @@
+  */
+ #define QUADSPI_QUIRK_USE_TDH_SETTING BIT(5)
++/*
++ * Use flash size for imx platforms and not for LS platforms. Define a
++ * quirk which enables it only on imx platforms.
++ */
++#define QUADSPI_QUIRK_USE_FLASH_SIZE  BIT(6)
++
+ #define QUADSPI_MIN_IOMAP             SZ_4M
+ struct fsl_qspi_devtype_data {
+@@ -213,7 +219,7 @@ static const struct fsl_qspi_devtype_dat
+       .txfifo = SZ_64,
+       .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
+       .ahb_buf_size = SZ_1K,
+-      .quirks = QUADSPI_QUIRK_SWAP_ENDIAN,
++      .quirks = QUADSPI_QUIRK_SWAP_ENDIAN | QUADSPI_QUIRK_USE_FLASH_SIZE,
+       .little_endian = true,
+ };
+@@ -222,7 +228,8 @@ static const struct fsl_qspi_devtype_dat
+       .txfifo = SZ_512,
+       .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
+       .ahb_buf_size = SZ_1K,
+-      .quirks = QUADSPI_QUIRK_4X_INT_CLK | QUADSPI_QUIRK_TKT245618,
++      .quirks = QUADSPI_QUIRK_4X_INT_CLK | QUADSPI_QUIRK_TKT245618 |
++                QUADSPI_QUIRK_USE_FLASH_SIZE,
+       .little_endian = true,
+ };
+@@ -232,7 +239,7 @@ static const struct fsl_qspi_devtype_dat
+       .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
+       .ahb_buf_size = SZ_1K,
+       .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK |
+-                QUADSPI_QUIRK_USE_TDH_SETTING,
++                QUADSPI_QUIRK_USE_TDH_SETTING | QUADSPI_QUIRK_USE_FLASH_SIZE,
+       .little_endian = true,
+ };
+@@ -242,7 +249,7 @@ static const struct fsl_qspi_devtype_dat
+       .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
+       .ahb_buf_size = SZ_1K,
+       .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK |
+-                QUADSPI_QUIRK_USE_TDH_SETTING,
++                QUADSPI_QUIRK_USE_TDH_SETTING | QUADSPI_QUIRK_USE_FLASH_SIZE,
+       .little_endian = true,
+ };
+@@ -310,6 +317,11 @@ static inline int needs_tdh_setting(stru
+       return q->devtype_data->quirks & QUADSPI_QUIRK_USE_TDH_SETTING;
+ }
++static inline int needs_flash_size(struct fsl_qspi *q)
++{
++      return q->devtype_data->quirks & QUADSPI_QUIRK_USE_FLASH_SIZE;
++}
++
+ /*
+  * An IC bug makes it necessary to rearrange the 32-bit data.
+  * Later chips, such as IMX6SLX, have fixed this bug.
+@@ -556,6 +568,14 @@ static void fsl_qspi_select_mem(struct f
+ static int fsl_qspi_read_ahb(struct fsl_qspi *q, const struct spi_mem_op *op)
+ {
++      if (!needs_flash_size(q)) {
++              u32 size = q->devtype_data->ahb_buf_size;
++              memcpy_fromio(op->data.buf.in,
++                            q->ahb_addr + q->selected * size,
++                            op->data.nbytes);
++              return 0;
++      }
++
+       u32 start = op->addr.val + q->selected * q->memmap_phy_size / 4;
+       u32 len = op->data.nbytes;
+@@ -674,6 +694,7 @@ static int fsl_qspi_exec_op(struct spi_m
+       u32 addr_offset = 0;
+       int err = 0;
+       int invalid_mstrid = q->devtype_data->invalid_mstrid;
++      u32 size = q->devtype_data->ahb_buf_size;
+       mutex_lock(&q->lock);
+@@ -686,8 +707,11 @@ static int fsl_qspi_exec_op(struct spi_m
+       if (needs_amba_base_offset(q))
+               addr_offset = q->memmap_phy;
++      if (needs_flash_size(q))
++              size = q->memmap_phy_size / 4;
++
+       qspi_writel(q,
+-                  q->selected * q->memmap_phy_size / 4 + addr_offset,
++                  q->selected * size + addr_offset,
+                   base + QUADSPI_SFAR);
+       qspi_writel(q, qspi_readl(q, base + QUADSPI_MCR) |
+@@ -751,6 +775,7 @@ static int fsl_qspi_default_setup(struct
+       void __iomem *base = q->iobase;
+       u32 reg, addr_offset = 0;
+       int ret;
++      u32 size = q->devtype_data->ahb_buf_size;
+       /* disable and unprepare clock to avoid glitch pass to controller */
+       fsl_qspi_clk_disable_unprep(q);
+@@ -805,19 +830,22 @@ static int fsl_qspi_default_setup(struct
+               addr_offset = q->memmap_phy;
+       /*
+-       * In HW there can be a maximum of four chips on two buses with
+-       * two chip selects on each bus. We use four chip selects in SW
+-       * to differentiate between the four chips.
+-       * We divide the total memory region size equally for each chip
+-       * and set SFA1AD, SFA2AD, SFB1AD, SFB2AD accordingly.
++       * In HW there can be a maximum of four chips on two buses with two
++       * chip selects on each bus. We use four chip selects in SW to
++       * differentiate between the four chips. We divide the total memory
++       * region/ahb_buf_size size equally for each chip and set SFA1AD,
++       * SFA2AD, SFB1AD, SFB2AD accordingly.
+        */
+-      qspi_writel(q, q->memmap_phy_size / 4 + addr_offset,
++      if (needs_flash_size(q))
++              size = q->memmap_phy_size / 4;
++
++      qspi_writel(q, size + addr_offset,
+                   base + QUADSPI_SFA1AD);
+-      qspi_writel(q, q->memmap_phy_size / 4 * 2 + addr_offset,
++      qspi_writel(q, size * 2 + addr_offset,
+                   base + QUADSPI_SFA2AD);
+-      qspi_writel(q, q->memmap_phy_size / 4 * 3 + addr_offset,
++      qspi_writel(q, size * 3 + addr_offset,
+                   base + QUADSPI_SFB1AD);
+-      qspi_writel(q, q->memmap_phy_size / 4 * 4 + addr_offset,
++      qspi_writel(q, size * 4 + addr_offset,
+                   base + QUADSPI_SFB2AD);
+       q->selected = -1;
+@@ -904,6 +932,15 @@ static int fsl_qspi_probe(struct platfor
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                       "QuadSPI-memory");
++
++      if (!needs_flash_size(q)) {
++              q->ahb_addr = devm_ioremap_resource(dev, res);
++              if (IS_ERR(q->ahb_addr)) {
++                      ret = PTR_ERR(q->ahb_addr);
++                      goto err_put_ctrl;
++              }
++      }
++
+       q->memmap_phy = res->start;
+       q->memmap_phy_size = resource_size(res);
+@@ -979,8 +1016,10 @@ static int fsl_qspi_remove(struct platfo
+       mutex_destroy(&q->lock);
+-      if (q->ahb_addr)
+-              iounmap(q->ahb_addr);
++      if (needs_flash_size(q)) {
++              if (q->ahb_addr)
++                      iounmap(q->ahb_addr);
++      }
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/818-thermal-0001-thermal-Add-generic-device-cooling-support.patch b/target/linux/layerscape/patches-5.4/818-thermal-0001-thermal-Add-generic-device-cooling-support.patch
new file mode 100644 (file)
index 0000000..f947eb6
--- /dev/null
@@ -0,0 +1,253 @@
+From 97abcfc5219149ff7d4883b295c80257f0315b5e Mon Sep 17 00:00:00 2001
+From: Anson Huang <Anson.Huang@nxp.com>
+Date: Wed, 7 Aug 2019 08:40:59 +0800
+Subject: [PATCH] thermal: Add generic device cooling support
+
+To compatible with previous implementation, add generic device
+cooling support, each thermal zone will register a cooling
+device, and when temperature exceed passive trip, the device
+cooling driver will send out a system wide notification, each
+device supporting cooling will need to register device cooling
+and takes action when passive trip is exceeded;
+
+Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/thermal/Kconfig          |   7 ++
+ drivers/thermal/Makefile         |   1 +
+ drivers/thermal/device_cooling.c | 152 +++++++++++++++++++++++++++++++++++++++
+ include/linux/device_cooling.h   |  45 ++++++++++++
+ 4 files changed, 205 insertions(+)
+ create mode 100644 drivers/thermal/device_cooling.c
+ create mode 100644 include/linux/device_cooling.h
+
+--- a/drivers/thermal/Kconfig
++++ b/drivers/thermal/Kconfig
+@@ -233,6 +233,13 @@ config IMX_THERMAL
+         cpufreq is used as the cooling device to throttle CPUs when the
+         passive trip is crossed.
++config DEVICE_THERMAL
++      tristate "generic device cooling support"
++      help
++        Support for device cooling.
++        It supports notification of crossing passive trip for devices,
++        devices need to do their own actions to cool down the SOC.
++
+ config MAX77620_THERMAL
+       tristate "Temperature sensor driver for Maxim MAX77620 PMIC"
+       depends on MFD_MAX77620
+--- a/drivers/thermal/Makefile
++++ b/drivers/thermal/Makefile
+@@ -41,6 +41,7 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_t
+ obj-$(CONFIG_ARMADA_THERMAL)  += armada_thermal.o
+ obj-$(CONFIG_TANGO_THERMAL)   += tango_thermal.o
+ obj-$(CONFIG_IMX_THERMAL)     += imx_thermal.o
++obj-$(CONFIG_DEVICE_THERMAL)  += device_cooling.o
+ obj-$(CONFIG_MAX77620_THERMAL)        += max77620_thermal.o
+ obj-$(CONFIG_QORIQ_THERMAL)   += qoriq_thermal.o
+ obj-$(CONFIG_DA9062_THERMAL)  += da9062-thermal.o
+--- /dev/null
++++ b/drivers/thermal/device_cooling.c
+@@ -0,0 +1,152 @@
++/*
++ * Copyright (C) 2013-2015 Freescale Semiconductor, 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/thermal.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++
++struct devfreq_cooling_device {
++      int id;
++      struct thermal_cooling_device *cool_dev;
++      unsigned int devfreq_state;
++};
++
++static DEFINE_IDR(devfreq_idr);
++static DEFINE_MUTEX(devfreq_cooling_lock);
++
++#define       MAX_STATE       1
++
++static BLOCKING_NOTIFIER_HEAD(devfreq_cooling_chain_head);
++
++int register_devfreq_cooling_notifier(struct notifier_block *nb)
++{
++      return blocking_notifier_chain_register(
++              &devfreq_cooling_chain_head, nb);
++}
++EXPORT_SYMBOL_GPL(register_devfreq_cooling_notifier);
++
++int unregister_devfreq_cooling_notifier(struct notifier_block *nb)
++{
++      return blocking_notifier_chain_unregister(
++              &devfreq_cooling_chain_head, nb);
++}
++EXPORT_SYMBOL_GPL(unregister_devfreq_cooling_notifier);
++
++static int devfreq_cooling_notifier_call_chain(unsigned long val)
++{
++      return (blocking_notifier_call_chain(
++              &devfreq_cooling_chain_head, val, NULL)
++              == NOTIFY_BAD) ? -EINVAL : 0;
++}
++
++static int devfreq_set_cur_state(struct thermal_cooling_device *cdev,
++                               unsigned long state)
++{
++      struct devfreq_cooling_device *devfreq_device = cdev->devdata;
++      int ret;
++
++      ret = devfreq_cooling_notifier_call_chain(state);
++      if (ret)
++              return -EINVAL;
++
++      devfreq_device->devfreq_state = state;
++
++      return 0;
++}
++
++static int devfreq_get_max_state(struct thermal_cooling_device *cdev,
++                               unsigned long *state)
++{
++      *state = MAX_STATE;
++
++      return 0;
++}
++
++static int devfreq_get_cur_state(struct thermal_cooling_device *cdev,
++                               unsigned long *state)
++{
++      struct devfreq_cooling_device *devfreq_device = cdev->devdata;
++
++      *state = devfreq_device->devfreq_state;
++
++      return 0;
++}
++
++static struct thermal_cooling_device_ops const devfreq_cooling_ops = {
++      .get_max_state = devfreq_get_max_state,
++      .get_cur_state = devfreq_get_cur_state,
++      .set_cur_state = devfreq_set_cur_state,
++};
++
++static int get_idr(struct idr *idr, int *id)
++{
++      int ret;
++
++      mutex_lock(&devfreq_cooling_lock);
++      ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
++      mutex_unlock(&devfreq_cooling_lock);
++      if (unlikely(ret < 0))
++              return ret;
++      *id = ret;
++
++      return 0;
++}
++
++static void release_idr(struct idr *idr, int id)
++{
++      mutex_lock(&devfreq_cooling_lock);
++      idr_remove(idr, id);
++      mutex_unlock(&devfreq_cooling_lock);
++}
++
++struct thermal_cooling_device *devfreq_cooling_register(void)
++{
++      struct thermal_cooling_device *cool_dev;
++      struct devfreq_cooling_device *devfreq_dev = NULL;
++      char dev_name[THERMAL_NAME_LENGTH];
++      int ret = 0;
++
++      devfreq_dev = kzalloc(sizeof(struct devfreq_cooling_device),
++                            GFP_KERNEL);
++      if (!devfreq_dev)
++              return ERR_PTR(-ENOMEM);
++
++      ret = get_idr(&devfreq_idr, &devfreq_dev->id);
++      if (ret) {
++              kfree(devfreq_dev);
++              return ERR_PTR(-EINVAL);
++      }
++
++      snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d",
++               devfreq_dev->id);
++
++      cool_dev = thermal_cooling_device_register(dev_name, devfreq_dev,
++                                                 &devfreq_cooling_ops);
++      if (!cool_dev) {
++              release_idr(&devfreq_idr, devfreq_dev->id);
++              kfree(devfreq_dev);
++              return ERR_PTR(-EINVAL);
++      }
++      devfreq_dev->cool_dev = cool_dev;
++      devfreq_dev->devfreq_state = 0;
++
++      return cool_dev;
++}
++EXPORT_SYMBOL_GPL(devfreq_cooling_register);
++
++void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
++{
++      struct devfreq_cooling_device *devfreq_dev = cdev->devdata;
++
++      thermal_cooling_device_unregister(devfreq_dev->cool_dev);
++      release_idr(&devfreq_idr, devfreq_dev->id);
++      kfree(devfreq_dev);
++}
++EXPORT_SYMBOL_GPL(devfreq_cooling_unregister);
+--- /dev/null
++++ b/include/linux/device_cooling.h
+@@ -0,0 +1,45 @@
++/*
++ * Copyright (C) 2013-2015 Freescale Semiconductor, 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.
++ *
++ */
++
++#ifndef __DEVICE_THERMAL_H__
++#define __DEVICE_THERMAL_H__
++
++#include <linux/thermal.h>
++
++#ifdef CONFIG_DEVICE_THERMAL
++int register_devfreq_cooling_notifier(struct notifier_block *nb);
++int unregister_devfreq_cooling_notifier(struct notifier_block *nb);
++struct thermal_cooling_device *devfreq_cooling_register(void);
++void devfreq_cooling_unregister(struct thermal_cooling_device *cdev);
++#else
++static inline
++int register_devfreq_cooling_notifier(struct notifier_block *nb)
++{
++      return 0;
++}
++
++static inline
++int unregister_devfreq_cooling_notifier(struct notifier_block *nb)
++{
++      return 0;
++}
++
++static inline
++struct thermal_cooling_device *devfreq_cooling_register(void)
++{
++      return NULL;
++}
++
++static inline
++void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
++{
++      return;
++}
++#endif
++#endif /* __DEVICE_THERMAL_H__ */
diff --git a/target/linux/layerscape/patches-5.4/818-thermal-0002-thermal-qoriq-Add-device-cooling-support.patch b/target/linux/layerscape/patches-5.4/818-thermal-0002-thermal-qoriq-Add-device-cooling-support.patch
new file mode 100644 (file)
index 0000000..4777ce9
--- /dev/null
@@ -0,0 +1,145 @@
+From 0a5d1b571ba5bca9c6737572ea4c8b1ad896c3fc Mon Sep 17 00:00:00 2001
+From: Anson Huang <Anson.Huang@nxp.com>
+Date: Wed, 7 Aug 2019 13:24:26 +0800
+Subject: [PATCH] thermal: qoriq: Add device cooling support
+
+Register device cooling for first thermal zone manually, when
+temperature exceeds passive trip, system wide cooling notification
+will be triggered.
+
+Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
+---
+ drivers/thermal/qoriq_thermal.c | 80 ++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 79 insertions(+), 1 deletion(-)
+
+--- a/drivers/thermal/qoriq_thermal.c
++++ b/drivers/thermal/qoriq_thermal.c
+@@ -3,6 +3,7 @@
+ // Copyright 2016 Freescale Semiconductor, Inc.
+ #include <linux/clk.h>
++#include <linux/device_cooling.h>
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/err.h>
+@@ -14,6 +15,7 @@
+ #include "thermal_core.h"
+ #define SITES_MAX     16
++#define TMU_TEMP_PASSIVE_COOL_DELTA   10000
+ /*
+  * QorIQ TMU Registers
+@@ -69,6 +71,9 @@ struct qoriq_sensor {
+       struct thermal_zone_device      *tzd;
+       struct qoriq_tmu_data           *qdata;
+       int                             id;
++      int                             temp_passive;
++      int                             temp_critical;
++      struct thermal_cooling_device   *cdev;
+ };
+ struct qoriq_tmu_data {
+@@ -78,6 +83,12 @@ struct qoriq_tmu_data {
+       struct qoriq_sensor     *sensor[SITES_MAX];
+ };
++enum tmu_trip {
++      TMU_TRIP_PASSIVE,
++      TMU_TRIP_CRITICAL,
++      TMU_TRIP_NUM,
++};
++
+ static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem *addr)
+ {
+       if (p->little_endian)
+@@ -106,14 +117,51 @@ static int tmu_get_temp(void *p, int *te
+       return 0;
+ }
++static int tmu_get_trend(void *p, int trip, enum thermal_trend *trend)
++{
++      struct qoriq_sensor *qsensor = p;
++      int trip_temp;
++
++      if (!qsensor->tzd)
++              return 0;
++
++      trip_temp = (trip == TMU_TRIP_PASSIVE) ? qsensor->temp_passive :
++                                           qsensor->temp_critical;
++
++      if (qsensor->tzd->temperature >=
++              (trip_temp - TMU_TEMP_PASSIVE_COOL_DELTA))
++              *trend = THERMAL_TREND_RAISE_FULL;
++      else
++              *trend = THERMAL_TREND_DROP_FULL;
++
++      return 0;
++}
++
++static int tmu_set_trip_temp(void *p, int trip,
++                           int temp)
++{
++      struct qoriq_sensor *qsensor = p;
++
++      if (trip == TMU_TRIP_CRITICAL)
++              qsensor->temp_critical = temp;
++
++      if (trip == TMU_TRIP_PASSIVE)
++              qsensor->temp_passive = temp;
++
++      return 0;
++}
++
+ static const struct thermal_zone_of_device_ops tmu_tz_ops = {
+       .get_temp = tmu_get_temp,
++      .get_trend = tmu_get_trend,
++      .set_trip_temp = tmu_set_trip_temp,
+ };
+ static int qoriq_tmu_register_tmu_zone(struct platform_device *pdev)
+ {
+       struct qoriq_tmu_data *qdata = platform_get_drvdata(pdev);
+-      int id, sites = 0;
++      const struct thermal_trip *trip;
++      int id, sites = 0, ret;
+       for (id = 0; id < SITES_MAX; id++) {
+               qdata->sensor[id] = devm_kzalloc(&pdev->dev,
+@@ -132,6 +180,36 @@ static int qoriq_tmu_register_tmu_zone(s
+                               return PTR_ERR(qdata->sensor[id]->tzd);
+               }
++              /* first thermal zone takes care of system-wide device cooling */
++              if (id == 0) {
++                      qdata->sensor[id]->cdev = devfreq_cooling_register();
++                      if (IS_ERR(qdata->sensor[id]->cdev)) {
++                              ret = PTR_ERR(qdata->sensor[id]->cdev);
++                              pr_err("failed to register devfreq cooling device: %d\n",
++                                      ret);
++                              return ret;
++                      }
++
++                      ret = thermal_zone_bind_cooling_device(qdata->sensor[id]->tzd,
++                              TMU_TRIP_PASSIVE,
++                              qdata->sensor[id]->cdev,
++                              THERMAL_NO_LIMIT,
++                              THERMAL_NO_LIMIT,
++                              THERMAL_WEIGHT_DEFAULT);
++                      if (ret) {
++                              pr_err("binding zone %s with cdev %s failed:%d\n",
++                                      qdata->sensor[id]->tzd->type,
++                                      qdata->sensor[id]->cdev->type,
++                                      ret);
++                              devfreq_cooling_unregister(qdata->sensor[id]->cdev);
++                              return ret;
++                      }
++
++                      trip = of_thermal_get_trip_points(qdata->sensor[id]->tzd);
++                      qdata->sensor[id]->temp_passive = trip[0].temperature;
++                      qdata->sensor[id]->temp_critical = trip[1].temperature;
++              }
++
+               sites |= 0x1 << (15 - id);
+       }
diff --git a/target/linux/layerscape/patches-5.4/818-thermal-0003-thermal-qoriq-add-thermal-monitor-unit-version-2-sup.patch b/target/linux/layerscape/patches-5.4/818-thermal-0003-thermal-qoriq-add-thermal-monitor-unit-version-2-sup.patch
new file mode 100644 (file)
index 0000000..5dbf3ec
--- /dev/null
@@ -0,0 +1,211 @@
+From 031573a8a1e73b0ac548812c10c3e426c2b4ce61 Mon Sep 17 00:00:00 2001
+From: Yuantian Tang <andy.tang@nxp.com>
+Date: Tue, 15 Oct 2019 20:08:58 +0800
+Subject: [PATCH] thermal: qoriq: add thermal monitor unit version 2 support
+
+Thermal Monitor Unit v2 is introduced on new Layscape SoC.
+Compared to v1, TMUv2 has a little different register layout
+and digital output is fairly linear.
+
+Signed-off-by: Yuantian Tang <andy.tang@nxp.com>
+Reviewed-by: Anson Huang <Anson.Huang@nxp.com>
+---
+ drivers/thermal/qoriq_thermal.c | 118 ++++++++++++++++++++++++++++++++--------
+ 1 file changed, 96 insertions(+), 22 deletions(-)
+
+--- a/drivers/thermal/qoriq_thermal.c
++++ b/drivers/thermal/qoriq_thermal.c
+@@ -16,6 +16,15 @@
+ #define SITES_MAX     16
+ #define TMU_TEMP_PASSIVE_COOL_DELTA   10000
++#define TMR_DISABLE           0x0
++#define TMR_ME                        0x80000000
++#define TMR_ALPF              0x0c000000
++#define TMR_ALPF_V2           0x03000000
++#define TMTMIR_DEFAULT        0x0000000f
++#define TIER_DISABLE  0x0
++#define TEUMR0_V2             0x51009c00
++#define TMU_VER1              0x1
++#define TMU_VER2              0x2
+ /*
+  * QorIQ TMU Registers
+@@ -26,17 +35,12 @@ struct qoriq_tmu_site_regs {
+       u8 res0[0x8];
+ };
+-struct qoriq_tmu_regs {
++struct qoriq_tmu_regs_v1 {
+       u32 tmr;                /* Mode Register */
+-#define TMR_DISABLE   0x0
+-#define TMR_ME                0x80000000
+-#define TMR_ALPF      0x0c000000
+       u32 tsr;                /* Status Register */
+       u32 tmtmir;             /* Temperature measurement interval Register */
+-#define TMTMIR_DEFAULT        0x0000000f
+       u8 res0[0x14];
+       u32 tier;               /* Interrupt Enable Register */
+-#define TIER_DISABLE  0x0
+       u32 tidr;               /* Interrupt Detect Register */
+       u32 tiscr;              /* Interrupt Site Capture Register */
+       u32 ticscr;             /* Interrupt Critical Site Capture Register */
+@@ -56,12 +60,52 @@ struct qoriq_tmu_regs {
+       u32 ipbrr0;             /* IP Block Revision Register 0 */
+       u32 ipbrr1;             /* IP Block Revision Register 1 */
+       u8 res6[0x310];
+-      u32 ttr0cr;             /* Temperature Range 0 Control Register */
+-      u32 ttr1cr;             /* Temperature Range 1 Control Register */
+-      u32 ttr2cr;             /* Temperature Range 2 Control Register */
+-      u32 ttr3cr;             /* Temperature Range 3 Control Register */
++      u32 ttrcr[4];           /* Temperature Range Control Register */
+ };
++struct qoriq_tmu_regs_v2 {
++      u32 tmr;                /* Mode Register */
++      u32 tsr;                /* Status Register */
++      u32 tmsr;               /* monitor site register */
++      u32 tmtmir;             /* Temperature measurement interval Register */
++      u8 res0[0x10];
++      u32 tier;               /* Interrupt Enable Register */
++      u32 tidr;               /* Interrupt Detect Register */
++      u8 res1[0x8];
++      u32 tiiscr;             /* interrupt immediate site capture register */
++      u32 tiascr;             /* interrupt average site capture register */
++      u32 ticscr;             /* Interrupt Critical Site Capture Register */
++      u32 res2;
++      u32 tmhtcr;             /* monitor high temperature capture register */
++      u32 tmltcr;             /* monitor low temperature capture register */
++      u32 tmrtrcr;    /* monitor rising temperature rate capture register */
++      u32 tmftrcr;    /* monitor falling temperature rate capture register */
++      u32 tmhtitr;    /* High Temperature Immediate Threshold */
++      u32 tmhtatr;    /* High Temperature Average Threshold */
++      u32 tmhtactr;   /* High Temperature Average Crit Threshold */
++      u32 res3;
++      u32 tmltitr;    /* monitor low temperature immediate threshold */
++      u32 tmltatr;    /* monitor low temperature average threshold register */
++      u32 tmltactr;   /* monitor low temperature average critical threshold */
++      u32 res4;
++      u32 tmrtrctr;   /* monitor rising temperature rate critical threshold */
++      u32 tmftrctr;   /* monitor falling temperature rate critical threshold*/
++      u8 res5[0x8];
++      u32 ttcfgr;     /* Temperature Configuration Register */
++      u32 tscfgr;     /* Sensor Configuration Register */
++      u8 res6[0x78];
++      struct qoriq_tmu_site_regs site[SITES_MAX];
++      u8 res7[0x9f8];
++      u32 ipbrr0;             /* IP Block Revision Register 0 */
++      u32 ipbrr1;             /* IP Block Revision Register 1 */
++      u8 res8[0x300];
++      u32 teumr0;
++      u32 teumr1;
++      u32 teumr2;
++      u32 res9;
++      u32 ttrcr[4];   /* Temperature Range Control Register */
++ };
++ 
+ struct qoriq_tmu_data;
+ /*
+@@ -77,7 +121,9 @@ struct qoriq_sensor {
+ };
+ struct qoriq_tmu_data {
+-      struct qoriq_tmu_regs __iomem *regs;
++      int ver;
++      struct qoriq_tmu_regs_v1 __iomem *regs;
++      struct qoriq_tmu_regs_v2 __iomem *regs_v2;
+       struct clk *clk;
+       bool little_endian;
+       struct qoriq_sensor     *sensor[SITES_MAX];
+@@ -210,12 +256,23 @@ static int qoriq_tmu_register_tmu_zone(s
+                       qdata->sensor[id]->temp_critical = trip[1].temperature;
+               }
+-              sites |= 0x1 << (15 - id);
++              if (qdata->ver == TMU_VER1)
++                      sites |= 0x1 << (15 - id);
++              else
++                      sites |= 0x1 << id;
+       }
+       /* Enable monitoring */
+-      if (sites != 0)
+-              tmu_write(qdata, sites | TMR_ME | TMR_ALPF, &qdata->regs->tmr);
++      if (sites != 0) {
++              if (qdata->ver == TMU_VER1) {
++                      tmu_write(qdata, sites | TMR_ME | TMR_ALPF,
++                                      &qdata->regs->tmr);
++              } else {
++                      tmu_write(qdata, sites, &qdata->regs_v2->tmsr);
++                      tmu_write(qdata, TMR_ME | TMR_ALPF_V2,
++                                      &qdata->regs_v2->tmr);
++              }
++      }
+       return 0;
+ }
+@@ -228,16 +285,21 @@ static int qoriq_tmu_calibration(struct
+       struct device_node *np = pdev->dev.of_node;
+       struct qoriq_tmu_data *data = platform_get_drvdata(pdev);
+-      if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) {
+-              dev_err(&pdev->dev, "missing calibration range.\n");
+-              return -ENODEV;
++      len = of_property_count_u32_elems(np, "fsl,tmu-range");
++      if (len < 0 || len > 4) {
++              dev_err(&pdev->dev, "invalid range data.\n");
++              return len;
++      }
++
++      val = of_property_read_u32_array(np, "fsl,tmu-range", range, len);
++      if (val != 0) {
++              dev_err(&pdev->dev, "failed to read range data.\n");
++              return val;
+       }
+       /* Init temperature range registers */
+-      tmu_write(data, range[0], &data->regs->ttr0cr);
+-      tmu_write(data, range[1], &data->regs->ttr1cr);
+-      tmu_write(data, range[2], &data->regs->ttr2cr);
+-      tmu_write(data, range[3], &data->regs->ttr3cr);
++      for (i = 0; i < len; i++)
++              tmu_write(data, range[i], &data->regs->ttrcr[i]);
+       calibration = of_get_property(np, "fsl,tmu-calibration", &len);
+       if (calibration == NULL || len % 8) {
+@@ -261,7 +323,12 @@ static void qoriq_tmu_init_device(struct
+       tmu_write(data, TIER_DISABLE, &data->regs->tier);
+       /* Set update_interval */
+-      tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir);
++      if (data->ver == TMU_VER1) {
++              tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir);
++      } else {
++              tmu_write(data, TMTMIR_DEFAULT, &data->regs_v2->tmtmir);
++              tmu_write(data, TEUMR0_V2, &data->regs_v2->teumr0);
++      }
+       /* Disable monitoring */
+       tmu_write(data, TMR_DISABLE, &data->regs->tmr);
+@@ -270,6 +337,7 @@ static void qoriq_tmu_init_device(struct
+ static int qoriq_tmu_probe(struct platform_device *pdev)
+ {
+       int ret;
++      u32 ver;
+       struct qoriq_tmu_data *data;
+       struct device_node *np = pdev->dev.of_node;
+@@ -298,6 +366,12 @@ static int qoriq_tmu_probe(struct platfo
+               return ret;
+       }
++      /* version register offset at: 0xbf8 on both v1 and v2 */
++      ver = tmu_read(data, &data->regs->ipbrr0);
++      data->ver = (ver >> 8) & 0xff;
++      if (data->ver == TMU_VER2)
++              data->regs_v2 = (void __iomem *)data->regs;
++
+       qoriq_tmu_init_device(data);    /* TMU initialization */
+       ret = qoriq_tmu_calibration(pdev);      /* TMU calibration */
diff --git a/target/linux/layerscape/patches-5.4/819-uart-0001-tty-serial-lpuart-add-power-domain-support.patch b/target/linux/layerscape/patches-5.4/819-uart-0001-tty-serial-lpuart-add-power-domain-support.patch
new file mode 100644 (file)
index 0000000..bad4128
--- /dev/null
@@ -0,0 +1,95 @@
+From e8730a6bd02cf4f6a3e2d11585d91c0417ed92e5 Mon Sep 17 00:00:00 2001
+From: Fugang Duan <fugang.duan@nxp.com>
+Date: Wed, 10 Jul 2019 14:20:45 +0800
+Subject: [PATCH] tty: serial: lpuart: add power domain support
+
+lpuart dma mode depends on dma channel's power domain like:
+power-domains = <&pd IMX_SC_R_UART_1>,
+                <&pd IMX_SC_R_DMA_2_CH10>,
+                <&pd IMX_SC_R_DMA_2_CH11>;
+power-domain-names = "uart", "rxdma", "txdma";
+
+So define the multiple power domain for lpuart.
+
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+---
+ drivers/tty/serial/fsl_lpuart.c | 54 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 54 insertions(+)
+
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -20,6 +20,8 @@
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+ #include <linux/of_dma.h>
++#include <linux/pm_domain.h>
++#include <linux/pm_runtime.h>
+ #include <linux/serial_core.h>
+ #include <linux/slab.h>
+ #include <linux/tty_flip.h>
+@@ -2369,6 +2371,54 @@ static struct uart_driver lpuart_reg = {
+       .cons           = LPUART_CONSOLE,
+ };
++static int lpuart_attach_pd(struct device *dev)
++{
++      struct device *pd_uart;
++      struct device *pd_txdma, *pd_rxdma;
++      struct device_link *link;
++
++      if (dev->pm_domain)
++              return 0;
++
++      pd_uart = dev_pm_domain_attach_by_name(dev, "uart");
++      if (IS_ERR(pd_uart))
++              return PTR_ERR(pd_uart);
++      link = device_link_add(dev, pd_uart, DL_FLAG_STATELESS |
++                                           DL_FLAG_PM_RUNTIME |
++                                           DL_FLAG_RPM_ACTIVE);
++      if (IS_ERR(link)) {
++              dev_err(dev, "Failed to add device_link to uart pd: %ld\n",
++                      PTR_ERR(link));
++              return PTR_ERR(link);
++      }
++
++      pd_txdma = dev_pm_domain_attach_by_name(dev, "txdma");
++      if (IS_ERR(pd_txdma))
++              return PTR_ERR(pd_txdma);
++      link = device_link_add(dev, pd_txdma, DL_FLAG_STATELESS |
++                                           DL_FLAG_PM_RUNTIME |
++                                           DL_FLAG_RPM_ACTIVE);
++      if (IS_ERR(link)) {
++              dev_err(dev, "Failed to add device_link to uart pd: %ld\n",
++                      PTR_ERR(link));
++              return PTR_ERR(link);
++      }
++
++      pd_rxdma = dev_pm_domain_attach_by_name(dev, "rxdma");
++      if (IS_ERR(pd_rxdma))
++              return PTR_ERR(pd_rxdma);
++      link = device_link_add(dev, pd_rxdma, DL_FLAG_STATELESS |
++                                           DL_FLAG_PM_RUNTIME |
++                                           DL_FLAG_RPM_ACTIVE);
++      if (IS_ERR(link)) {
++              dev_err(dev, "Failed to add device_link to uart pd: %ld\n",
++                      PTR_ERR(link));
++              return PTR_ERR(link);
++      }
++
++      return 0;
++}
++
+ static int lpuart_probe(struct platform_device *pdev)
+ {
+       const struct of_device_id *of_id = of_match_device(lpuart_dt_ids,
+@@ -2406,6 +2456,10 @@ static int lpuart_probe(struct platform_
+       sport->port.rs485_config = lpuart_config_rs485;
++      ret = lpuart_attach_pd(&pdev->dev);
++      if (ret)
++              return ret;
++
+       sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
+       if (IS_ERR(sport->ipg_clk)) {
+               ret = PTR_ERR(sport->ipg_clk);
diff --git a/target/linux/layerscape/patches-5.4/819-uart-0002-tty-serial-fsl_lpuart-add-modem-device-reset.patch b/target/linux/layerscape/patches-5.4/819-uart-0002-tty-serial-fsl_lpuart-add-modem-device-reset.patch
new file mode 100644 (file)
index 0000000..37fd23d
--- /dev/null
@@ -0,0 +1,40 @@
+From 5b05462e88dc87d83566d04dd196b4f3d9dc0eef Mon Sep 17 00:00:00 2001
+From: Fugang Duan <fugang.duan@nxp.com>
+Date: Mon, 28 Jan 2019 10:12:52 +0800
+Subject: [PATCH] tty: serial: fsl_lpuart: add modem device reset
+
+Add modem device reset, wthether to reset depend on dts configuration.
+
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+---
+ drivers/tty/serial/fsl_lpuart.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -22,6 +22,7 @@
+ #include <linux/of_dma.h>
+ #include <linux/pm_domain.h>
+ #include <linux/pm_runtime.h>
++#include <linux/reset.h>
+ #include <linux/serial_core.h>
+ #include <linux/slab.h>
+ #include <linux/tty_flip.h>
+@@ -1544,8 +1545,17 @@ static void lpuart32_configure(struct lp
+ static int lpuart32_startup(struct uart_port *port)
+ {
+       struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
++      struct tty_port *tty_port = &sport->port.state->port;
+       unsigned long flags;
+       unsigned long temp;
++      int ret;
++
++      /* some modem may need reset */
++      if (!tty_port_suspended(tty_port)) {
++              ret = device_reset(sport->port.dev);
++              if (ret && ret != -ENOENT)
++                      return ret;
++      }
+       /* determine FIFO size */
+       temp = lpuart32_read(&sport->port, UARTFIFO);
diff --git a/target/linux/layerscape/patches-5.4/819-uart-0003-tty-serial-fsl_lpuart-add-magic-SysRq-support.patch b/target/linux/layerscape/patches-5.4/819-uart-0003-tty-serial-fsl_lpuart-add-magic-SysRq-support.patch
new file mode 100644 (file)
index 0000000..043d246
--- /dev/null
@@ -0,0 +1,28 @@
+From 74d7e639cce7ae95cacd948dcf5ed3b28c3fff5c Mon Sep 17 00:00:00 2001
+From: Fugang Duan <fugang.duan@nxp.com>
+Date: Mon, 28 Jan 2019 10:27:27 +0800
+Subject: [PATCH] tty: serial: fsl_lpuart: add magic SysRq support
+
+Add magic SysRq key support.
+
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+---
+ drivers/tty/serial/fsl_lpuart.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -920,7 +920,12 @@ static void lpuart32_rxint(struct lpuart
+                */
+               sr = lpuart32_read(&sport->port, UARTSTAT);
+               rx = lpuart32_read(&sport->port, UARTDATA);
+-              rx &= 0x3ff;
++
++              if ((sr & UARTSTAT_FE) && (rx & UARTDATA_FRETSC) &&
++                      !(rx & UARTDATA_MASK)) {
++                      if (uart_handle_break(&sport->port))
++                              continue;
++              }
+               if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
+                       continue;
diff --git a/target/linux/layerscape/patches-5.4/819-uart-0004-MLK-18137-fsl_lpuart-Fix-loopback-mode.patch b/target/linux/layerscape/patches-5.4/819-uart-0004-MLK-18137-fsl_lpuart-Fix-loopback-mode.patch
new file mode 100644 (file)
index 0000000..0f9f2dc
--- /dev/null
@@ -0,0 +1,28 @@
+From 392865cdcca83fbc9624725e505feb31dda7e67a Mon Sep 17 00:00:00 2001
+From: Andy Duan <fugang.duan@nxp.com>
+Date: Mon, 28 Jan 2019 14:29:14 +0800
+Subject: [PATCH] MLK-18137: fsl_lpuart: Fix loopback mode
+
+Register offset needs to be applied on mapbase also.
+dma_tx/rx_request use the physical address of UARTDATA.
+Register offset is currently only applied to membase (the
+corresponding virtual addr) but not on mapbase.
+
+Reviewed-by: Leonard Crestez <leonard.crestez@nxp.com>
+Acked-by: Fugang Duan <fugang.duan@nxp.com>
+Signed-off-by: Adriana Reus <adriana.reus@nxp.com>
+---
+ drivers/tty/serial/fsl_lpuart.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -2454,7 +2454,7 @@ static int lpuart_probe(struct platform_
+               return PTR_ERR(sport->port.membase);
+       sport->port.membase += sdata->reg_off;
+-      sport->port.mapbase = res->start;
++      sport->port.mapbase = res->start + sdata->reg_off;
+       sport->port.dev = &pdev->dev;
+       sport->port.type = PORT_LPUART;
+       sport->devtype = sdata->devtype;
diff --git a/target/linux/layerscape/patches-5.4/819-uart-0005-tty-serial-fsl_lpuart-enable-dma-mode-for-imx8qxp.patch b/target/linux/layerscape/patches-5.4/819-uart-0005-tty-serial-fsl_lpuart-enable-dma-mode-for-imx8qxp.patch
new file mode 100644 (file)
index 0000000..1a2d6c2
--- /dev/null
@@ -0,0 +1,551 @@
+From 0d6e214f5a257f9b53619ef8aa3b6e767189bdcf Mon Sep 17 00:00:00 2001
+From: Fugang Duan <fugang.duan@nxp.com>
+Date: Wed, 11 Sep 2019 16:21:06 +0800
+Subject: [PATCH] tty: serial: fsl_lpuart: enable dma mode for imx8qxp
+
+imx8qxp lpuart support eDMA for dma mode, support EOP (end-of-packet)
+feature. But eDMA cannot detect the correct DADDR for current major
+loop in cyclic mode, so it doesn't support cyclic mode.
+
+The patch is to enable lpuart prep slave sg dma mode for imx8qxp.
+
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+---
+ drivers/tty/serial/fsl_lpuart.c | 280 +++++++++++++++++++++++++++++++---------
+ 1 file changed, 219 insertions(+), 61 deletions(-)
+
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -131,6 +131,7 @@
+ #define UARTBAUD_M10          0x20000000
+ #define UARTBAUD_TDMAE                0x00800000
+ #define UARTBAUD_RDMAE                0x00200000
++#define UARTBAUD_RIDMAE               0x00100000
+ #define UARTBAUD_MATCFG               0x00400000
+ #define UARTBAUD_BOTHEDGE     0x00020000
+ #define UARTBAUD_RESYNCDIS    0x00010000
+@@ -179,7 +180,7 @@
+ #define UARTCTRL_SBK          0x00010000
+ #define UARTCTRL_MA1IE                0x00008000
+ #define UARTCTRL_MA2IE                0x00004000
+-#define UARTCTRL_IDLECFG      0x00000100
++#define UARTCTRL_IDLECFG_OFF  0x8
+ #define UARTCTRL_LOOPS                0x00000080
+ #define UARTCTRL_DOZEEN               0x00000040
+ #define UARTCTRL_RSRC         0x00000020
+@@ -197,6 +198,7 @@
+ #define UARTDATA_MASK         0x3ff
+ #define UARTMODIR_IREN                0x00020000
++#define UARTMODIR_RTSWATER_S  0x8
+ #define UARTMODIR_TXCTSSRC    0x00000020
+ #define UARTMODIR_TXCTSC      0x00000010
+ #define UARTMODIR_RXRTSE      0x00000008
+@@ -210,6 +212,8 @@
+ #define UARTFIFO_RXUF         0x00010000
+ #define UARTFIFO_TXFLUSH      0x00008000
+ #define UARTFIFO_RXFLUSH      0x00004000
++#define UARTFIFO_RXIDEN_MASK  0x7
++#define UARTFIFO_RXIDEN_OFF   10
+ #define UARTFIFO_TXOFE                0x00000200
+ #define UARTFIFO_RXUFE                0x00000100
+ #define UARTFIFO_TXFE         0x00000080
+@@ -226,6 +230,9 @@
+ #define UARTWATER_TXWATER_OFF 0
+ #define UARTWATER_RXWATER_OFF 16
++#define UARTFIFO_RXIDEN_RDRF  0x3
++#define UARTCTRL_IDLECFG      0x7
++
+ /* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */
+ #define DMA_RX_TIMEOUT                (10)
+@@ -253,6 +260,9 @@ struct lpuart_port {
+       unsigned int            txfifo_size;
+       unsigned int            rxfifo_size;
++      u8                      rx_watermark;
++      bool                    dma_eeop;
++      bool                    rx_dma_cyclic;
+       bool                    lpuart_dma_tx_use;
+       bool                    lpuart_dma_rx_use;
+       struct dma_chan         *dma_tx_chan;
+@@ -278,28 +288,38 @@ struct lpuart_soc_data {
+       enum lpuart_type devtype;
+       char iotype;
+       u8 reg_off;
++      u8 rx_watermark;
++      bool rx_dma_cyclic;
+ };
+ static const struct lpuart_soc_data vf_data = {
+       .devtype = VF610_LPUART,
+       .iotype = UPIO_MEM,
++      .rx_watermark = 1,
++      .rx_dma_cyclic = true,
+ };
+ static const struct lpuart_soc_data ls_data = {
+       .devtype = LS1021A_LPUART,
+       .iotype = UPIO_MEM32BE,
++      .rx_watermark = 0,
++      .rx_dma_cyclic = true,
+ };
+ static struct lpuart_soc_data imx7ulp_data = {
+       .devtype = IMX7ULP_LPUART,
+       .iotype = UPIO_MEM32,
+       .reg_off = IMX_REG_OFF,
++      .rx_watermark = 0,
++      .rx_dma_cyclic = true,
+ };
+ static struct lpuart_soc_data imx8qxp_data = {
+       .devtype = IMX8QXP_LPUART,
+       .iotype = UPIO_MEM32,
+       .reg_off = IMX_REG_OFF,
++      .rx_watermark = 31,
++      .rx_dma_cyclic = false,
+ };
+ static const struct of_device_id lpuart_dt_ids[] = {
+@@ -313,6 +333,7 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
+ /* Forward declare this for the dma callbacks*/
+ static void lpuart_dma_tx_complete(void *arg);
++static int lpuart_sched_rx_dma(struct lpuart_port *sport);
+ static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport)
+ {
+@@ -1000,19 +1021,15 @@ static irqreturn_t lpuart32_int(int irq,
+       if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use)
+               lpuart32_txint(sport);
++      if (sport->lpuart_dma_rx_use && sport->dma_eeop)
++              sts &= ~UARTSTAT_IDLE;
++
+       lpuart32_write(&sport->port, sts, UARTSTAT);
+       return IRQ_HANDLED;
+ }
+-static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
++static void lpuart_rx_error_stat(struct lpuart_port *sport)
+ {
+-      struct tty_port *port = &sport->port.state->port;
+-      struct dma_tx_state state;
+-      enum dma_status dmastat;
+-      struct circ_buf *ring = &sport->rx_ring;
+-      unsigned long flags;
+-      int count = 0;
+-
+       if (lpuart_is_32(sport)) {
+               unsigned long sr = lpuart32_read(&sport->port, UARTSTAT);
+@@ -1064,8 +1081,21 @@ static void lpuart_copy_rx_to_tty(struct
+                       writeb(cr2, sport->port.membase + UARTCR2);
+               }
+       }
++}
++
++static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
++{
++      struct tty_port *port = &sport->port.state->port;
++      struct dma_tx_state state;
++      enum dma_status dmastat;
++      struct circ_buf *ring = &sport->rx_ring;
++      unsigned long flags;
++      int count = 0;
+-      async_tx_ack(sport->dma_rx_desc);
++      if (!is_imx8qxp_lpuart(sport)) {
++              lpuart_rx_error_stat(sport);
++              async_tx_ack(sport->dma_rx_desc);
++      }
+       spin_lock_irqsave(&sport->port.lock, flags);
+@@ -1128,7 +1158,33 @@ static void lpuart_copy_rx_to_tty(struct
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+       tty_flip_buffer_push(port);
+-      mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout);
++
++      if (!sport->dma_eeop)
++              mod_timer(&sport->lpuart_timer,
++                        jiffies + sport->dma_rx_timeout);
++}
++
++static void lpuart_dma_rx_post_handler(struct lpuart_port *sport)
++{
++      unsigned long flags;
++      unsigned long rxcount;
++
++      spin_lock_irqsave(&sport->port.lock, flags);
++
++      /* For end of packet, clear the idle flag to avoid to trigger
++       * the next transfer. Only i.MX8x lpuart support EEOP.
++       */
++      if (sport->dma_eeop && lpuart_is_32(sport)) {
++              rxcount = lpuart32_read(&sport->port, UARTWATER);
++              rxcount = rxcount >> UARTWATER_RXCNT_OFF;
++              if (!rxcount)
++                      lpuart32_write(&sport->port, UARTSTAT_IDLE, UARTSTAT);
++      }
++
++      lpuart_sched_rx_dma(sport);
++
++      spin_unlock_irqrestore(&sport->port.lock, flags);
++
+ }
+ static void lpuart_dma_rx_complete(void *arg)
+@@ -1136,6 +1192,8 @@ static void lpuart_dma_rx_complete(void
+       struct lpuart_port *sport = arg;
+       lpuart_copy_rx_to_tty(sport);
++      if (!sport->rx_dma_cyclic)
++              lpuart_dma_rx_post_handler(sport);
+ }
+ static void lpuart_timer_func(struct timer_list *t)
+@@ -1143,13 +1201,78 @@ static void lpuart_timer_func(struct tim
+       struct lpuart_port *sport = from_timer(sport, t, lpuart_timer);
+       lpuart_copy_rx_to_tty(sport);
++      if (!sport->rx_dma_cyclic) {
++              dmaengine_terminate_async(sport->dma_rx_chan);
++              lpuart_dma_rx_post_handler(sport);
++      }
+ }
+-static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
++static int lpuart_sched_rxdma_cyclic(struct lpuart_port *sport)
++{
++      sport->dma_rx_desc = dmaengine_prep_dma_cyclic(sport->dma_rx_chan,
++                               sg_dma_address(&sport->rx_sgl),
++                               sport->rx_sgl.length,
++                               sport->rx_sgl.length / 2,
++                               DMA_DEV_TO_MEM,
++                               DMA_PREP_INTERRUPT);
++      if (!sport->dma_rx_desc) {
++              dev_err(sport->port.dev, "Cannot prepare cyclic DMA\n");
++              return -EFAULT;
++      }
++
++      return 0;
++}
++
++static int lpuart_sched_rxdma_slave_sg(struct lpuart_port *sport)
++{
++      dma_sync_sg_for_device(sport->port.dev, &sport->rx_sgl, 1,
++                             DMA_FROM_DEVICE);
++      sport->dma_rx_desc = dmaengine_prep_slave_sg(sport->dma_rx_chan,
++                              &sport->rx_sgl,
++                              1,
++                              DMA_DEV_TO_MEM,
++                              DMA_PREP_INTERRUPT);
++      if (!sport->dma_rx_desc) {
++              dev_err(sport->port.dev, "Cannot prepare slave_sg DMA\n");
++              return -EFAULT;
++      }
++      sport->rx_ring.tail = 0;
++      sport->rx_ring.head = 0;
++
++      return 0;
++}
++
++static int lpuart_sched_rx_dma(struct lpuart_port *sport)
++{
++      unsigned long temp;
++      int ret;
++
++      if (sport->rx_dma_cyclic)
++              ret = lpuart_sched_rxdma_cyclic(sport);
++      else
++              ret = lpuart_sched_rxdma_slave_sg(sport);
++
++      sport->dma_rx_desc->callback = lpuart_dma_rx_complete;
++      sport->dma_rx_desc->callback_param = sport;
++      sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc);
++      dma_async_issue_pending(sport->dma_rx_chan);
++
++      if (lpuart_is_32(sport)) {
++              temp = lpuart32_read(&sport->port, UARTBAUD);
++              if (sport->dma_eeop)
++                      temp |= UARTBAUD_RIDMAE;
++              temp |= UARTBAUD_RDMAE;
++              lpuart32_write(&sport->port, temp, UARTBAUD);
++      } else {
++              writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_RDMAS,
++                     sport->port.membase + UARTCR5);
++      }
++
++      return ret;
++}
++
++static void lpuart_get_rx_dma_rng_len(struct lpuart_port *sport)
+ {
+-      struct dma_slave_config dma_rx_sconfig = {};
+-      struct circ_buf *ring = &sport->rx_ring;
+-      int ret, nent;
+       int bits, baud;
+       struct tty_port *port = &sport->port.state->port;
+       struct tty_struct *tty = port->tty;
+@@ -1169,6 +1292,18 @@ static inline int lpuart_start_rx_dma(st
+       sport->rx_dma_rng_buf_len = (1 << (fls(sport->rx_dma_rng_buf_len) - 1));
+       if (sport->rx_dma_rng_buf_len < 16)
+               sport->rx_dma_rng_buf_len = 16;
++}
++
++static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
++{
++      struct dma_slave_config dma_rx_sconfig = {};
++      struct circ_buf *ring = &sport->rx_ring;
++      int ret, nent;
++
++      if (!sport->dma_eeop)
++              lpuart_get_rx_dma_rng_len(sport);
++      else
++              sport->rx_dma_rng_buf_len = PAGE_SIZE;
+       ring->buf = kzalloc(sport->rx_dma_rng_buf_len, GFP_ATOMIC);
+       if (!ring->buf)
+@@ -1194,32 +1329,7 @@ static inline int lpuart_start_rx_dma(st
+               return ret;
+       }
+-      sport->dma_rx_desc = dmaengine_prep_dma_cyclic(sport->dma_rx_chan,
+-                               sg_dma_address(&sport->rx_sgl),
+-                               sport->rx_sgl.length,
+-                               sport->rx_sgl.length / 2,
+-                               DMA_DEV_TO_MEM,
+-                               DMA_PREP_INTERRUPT);
+-      if (!sport->dma_rx_desc) {
+-              dev_err(sport->port.dev, "Cannot prepare cyclic DMA\n");
+-              return -EFAULT;
+-      }
+-
+-      sport->dma_rx_desc->callback = lpuart_dma_rx_complete;
+-      sport->dma_rx_desc->callback_param = sport;
+-      sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc);
+-      dma_async_issue_pending(sport->dma_rx_chan);
+-
+-      if (lpuart_is_32(sport)) {
+-              unsigned long temp = lpuart32_read(&sport->port, UARTBAUD);
+-
+-              lpuart32_write(&sport->port, temp | UARTBAUD_RDMAE, UARTBAUD);
+-      } else {
+-              writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_RDMAS,
+-                     sport->port.membase + UARTCR5);
+-      }
+-
+-      return 0;
++      return lpuart_sched_rx_dma(sport);
+ }
+ static void lpuart_dma_rx_free(struct uart_port *port)
+@@ -1405,8 +1515,10 @@ static void lpuart_setup_watermark(struc
+               writeb(UARTSFIFO_RXUF, sport->port.membase + UARTSFIFO);
+       }
++      if (uart_console(&sport->port))
++              sport->rx_watermark = 1;
+       writeb(0, sport->port.membase + UARTTWFIFO);
+-      writeb(1, sport->port.membase + UARTRWFIFO);
++      writeb(sport->rx_watermark, sport->port.membase + UARTRWFIFO);
+       /* Restore cr2 */
+       writeb(cr2_saved, sport->port.membase + UARTCR2);
+@@ -1427,6 +1539,7 @@ static void lpuart32_setup_watermark(str
+ {
+       unsigned long val, ctrl;
+       unsigned long ctrl_saved;
++      unsigned long rxiden_cnt;
+       ctrl = lpuart32_read(&sport->port, UARTCTRL);
+       ctrl_saved = ctrl;
+@@ -1438,12 +1551,26 @@ static void lpuart32_setup_watermark(str
+       val = lpuart32_read(&sport->port, UARTFIFO);
+       val |= UARTFIFO_TXFE | UARTFIFO_RXFE;
+       val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
++      val &= ~(UARTFIFO_RXIDEN_MASK << UARTFIFO_RXIDEN_OFF);
++      rxiden_cnt = sport->dma_eeop ? 0 : UARTFIFO_RXIDEN_RDRF;
++      val |= ((rxiden_cnt & UARTFIFO_RXIDEN_MASK) <<
++              UARTFIFO_RXIDEN_OFF);
+       lpuart32_write(&sport->port, val, UARTFIFO);
+       /* set the watermark */
+-      val = (0x1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF);
++      if (uart_console(&sport->port))
++              sport->rx_watermark = 1;
++      val = (sport->rx_watermark << UARTWATER_RXWATER_OFF) |
++            (0x0 << UARTWATER_TXWATER_OFF);
+       lpuart32_write(&sport->port, val, UARTWATER);
++      /* set RTS watermark */
++      if (!uart_console(&sport->port)) {
++              val = lpuart32_read(&sport->port, UARTMODIR);
++              val = (sport->rxfifo_size >> 1) << UARTMODIR_RTSWATER_S;
++              lpuart32_write(&sport->port, val, UARTMODIR);
++      }
++
+       /* Restore cr2 */
+       lpuart32_write(&sport->port, ctrl_saved, UARTCTRL);
+ }
+@@ -1455,17 +1582,29 @@ static void lpuart32_setup_watermark_ena
+       lpuart32_setup_watermark(sport);
+       temp = lpuart32_read(&sport->port, UARTCTRL);
+-      temp |= UARTCTRL_RE | UARTCTRL_TE | UARTCTRL_ILIE;
++      temp |= UARTCTRL_RE | UARTCTRL_TE;
++      temp |= UARTCTRL_IDLECFG << UARTCTRL_IDLECFG_OFF;
+       lpuart32_write(&sport->port, temp, UARTCTRL);
+ }
+ static void rx_dma_timer_init(struct lpuart_port *sport)
+ {
++      if (sport->dma_eeop)
++              return;
++
+       timer_setup(&sport->lpuart_timer, lpuart_timer_func, 0);
+       sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
+       add_timer(&sport->lpuart_timer);
+ }
++static void lpuart_del_timer_sync(struct lpuart_port *sport)
++{
++      if (sport->dma_eeop)
++              return;
++
++      del_timer_sync(&sport->lpuart_timer);
++}
++
+ static void lpuart_tx_dma_startup(struct lpuart_port *sport)
+ {
+       u32 uartbaud;
+@@ -1529,19 +1668,23 @@ static int lpuart_startup(struct uart_po
+       return 0;
+ }
++static void lpuart32_hw_disable(struct lpuart_port *sport)
++{
++      unsigned long temp;
++
++      temp = lpuart32_read(&sport->port, UARTCTRL);
++      temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE |
++                UARTCTRL_TIE | UARTCTRL_TE);
++      lpuart32_write(&sport->port, temp, UARTCTRL);
++}
++
+ static void lpuart32_configure(struct lpuart_port *sport)
+ {
+       unsigned long temp;
+-      if (sport->lpuart_dma_rx_use) {
+-              /* RXWATER must be 0 */
+-              temp = lpuart32_read(&sport->port, UARTWATER);
+-              temp &= ~(UARTWATER_WATER_MASK << UARTWATER_RXWATER_OFF);
+-              lpuart32_write(&sport->port, temp, UARTWATER);
+-      }
+       temp = lpuart32_read(&sport->port, UARTCTRL);
+       if (!sport->lpuart_dma_rx_use)
+-              temp |= UARTCTRL_RIE;
++              temp |= UARTCTRL_RIE | UARTCTRL_ILIE;
+       if (!sport->lpuart_dma_tx_use)
+               temp |= UARTCTRL_TIE;
+       lpuart32_write(&sport->port, temp, UARTCTRL);
+@@ -1574,12 +1717,12 @@ static int lpuart32_startup(struct uart_
+       spin_lock_irqsave(&sport->port.lock, flags);
+-      lpuart32_setup_watermark_enable(sport);
+-
++      lpuart32_hw_disable(sport);
+       lpuart_rx_dma_startup(sport);
+       lpuart_tx_dma_startup(sport);
++      lpuart32_setup_watermark_enable(sport);
+       lpuart32_configure(sport);
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+@@ -1589,7 +1732,7 @@ static int lpuart32_startup(struct uart_
+ static void lpuart_dma_shutdown(struct lpuart_port *sport)
+ {
+       if (sport->lpuart_dma_rx_use) {
+-              del_timer_sync(&sport->lpuart_timer);
++              lpuart_del_timer_sync(sport);
+               lpuart_dma_rx_free(&sport->port);
+       }
+@@ -1630,11 +1773,22 @@ static void lpuart32_shutdown(struct uar
+       spin_lock_irqsave(&port->lock, flags);
++      /* clear statue */
++      temp = lpuart32_read(&sport->port, UARTSTAT);
++      lpuart32_write(&sport->port, temp, UARTSTAT);
++
++      /* disable Rx/Tx DMA */
++      temp = lpuart32_read(port, UARTBAUD);
++      temp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE | UARTBAUD_RIDMAE);
++      lpuart32_write(port, temp, UARTBAUD);
++
+       /* disable Rx/Tx and interrupts */
+       temp = lpuart32_read(port, UARTCTRL);
+-      temp &= ~(UARTCTRL_TE | UARTCTRL_RE |
+-                      UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE);
++      temp &= ~(UARTCTRL_TE | UARTCTRL_RE | UARTCTRL_TIE |
++              UARTCTRL_TCIE | UARTCTRL_RIE | UARTCTRL_ILIE |
++              UARTCTRL_LOOPS);
+       lpuart32_write(port, temp, UARTCTRL);
++      lpuart32_write(port, 0, UARTMODIR);
+       spin_unlock_irqrestore(&port->lock, flags);
+@@ -1731,10 +1885,10 @@ lpuart_set_termios(struct uart_port *por
+        * baud rate and restart Rx DMA path.
+        *
+        * Since timer function acqures sport->port.lock, need to stop before
+-       * acquring same lock because otherwise del_timer_sync() can deadlock.
++       * acquring same lock because otherwise lpuart_del_timer_sync() can deadlock.
+        */
+       if (old && sport->lpuart_dma_rx_use) {
+-              del_timer_sync(&sport->lpuart_timer);
++              lpuart_del_timer_sync(sport);
+               lpuart_dma_rx_free(&sport->port);
+       }
+@@ -1946,10 +2100,10 @@ lpuart32_set_termios(struct uart_port *p
+        * baud rate and restart Rx DMA path.
+        *
+        * Since timer function acqures sport->port.lock, need to stop before
+-       * acquring same lock because otherwise del_timer_sync() can deadlock.
++       * acquring same lock because otherwise lpuart_del_timer_sync() can deadlock.
+        */
+       if (old && sport->lpuart_dma_rx_use) {
+-              del_timer_sync(&sport->lpuart_timer);
++              lpuart_del_timer_sync(sport);
+               lpuart_dma_rx_free(&sport->port);
+       }
+@@ -2458,6 +2612,10 @@ static int lpuart_probe(struct platform_
+       sport->port.dev = &pdev->dev;
+       sport->port.type = PORT_LPUART;
+       sport->devtype = sdata->devtype;
++      sport->rx_dma_cyclic = sdata->rx_dma_cyclic;
++      sport->rx_watermark = sdata->rx_watermark;
++      sport->dma_eeop = is_imx8qxp_lpuart(sport);
++
+       ret = platform_get_irq(pdev, 0);
+       if (ret < 0)
+               return ret;
+@@ -2620,7 +2778,7 @@ static int lpuart_suspend(struct device
+                * Rx DMA path before suspend and start Rx DMA path on resume.
+                */
+               if (irq_wake) {
+-                      del_timer_sync(&sport->lpuart_timer);
++                      lpuart_del_timer_sync(sport);
+                       lpuart_dma_rx_free(&sport->port);
+               }
diff --git a/target/linux/layerscape/patches-5.4/819-uart-0006-tty-serial-fsl_lpuart-enable-loopback-mode.patch b/target/linux/layerscape/patches-5.4/819-uart-0006-tty-serial-fsl_lpuart-enable-loopback-mode.patch
new file mode 100644 (file)
index 0000000..f643b27
--- /dev/null
@@ -0,0 +1,29 @@
+From 4dc6f2b9d454099445b8bc3a4a6328761335ce4d Mon Sep 17 00:00:00 2001
+From: Fugang Duan <fugang.duan@nxp.com>
+Date: Wed, 11 Sep 2019 16:23:25 +0800
+Subject: [PATCH] tty: serial: fsl_lpuart: enable loopback mode
+
+Enable lpuart32 loopback mode.
+
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+---
+ drivers/tty/serial/fsl_lpuart.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -1464,6 +1464,14 @@ static void lpuart32_set_mctrl(struct ua
+               temp |= UARTMODIR_TXCTSE;
+       lpuart32_write(port, temp, UARTMODIR);
++
++      temp = lpuart32_read(port, UARTCTRL);
++      if (mctrl & TIOCM_LOOP)
++              temp |= UARTCTRL_LOOPS;
++      else
++              temp &= ~UARTCTRL_LOOPS;
++
++      lpuart32_write(port, temp, UARTCTRL);
+ }
+ static void lpuart_break_ctl(struct uart_port *port, int break_state)
diff --git a/target/linux/layerscape/patches-5.4/819-uart-0007-MLK-15094-tty-serial-fsl_lpuart-check-dma_tx_in_prog.patch b/target/linux/layerscape/patches-5.4/819-uart-0007-MLK-15094-tty-serial-fsl_lpuart-check-dma_tx_in_prog.patch
new file mode 100644 (file)
index 0000000..58f44e8
--- /dev/null
@@ -0,0 +1,29 @@
+From 31a4e41820cdaad9d4c151beefe5ab0698f4865a Mon Sep 17 00:00:00 2001
+From: Fugang Duan <fugang.duan@nxp.com>
+Date: Thu, 15 Jun 2017 16:48:31 +0800
+Subject: [PATCH] MLK-15094 tty: serial: fsl_lpuart: check dma_tx_in_progress
+ in callback
+
+There have a corner case that tx DMA .callback() is coming after
+.flush_buffer(), then .callback() should check dma_tx_in_progress
+flag and return in directly.
+
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
+---
+ drivers/tty/serial/fsl_lpuart.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -490,6 +490,10 @@ static void lpuart_dma_tx_complete(void
+       unsigned long flags;
+       spin_lock_irqsave(&sport->port.lock, flags);
++      if (!sport->dma_tx_in_progress) {
++              spin_unlock_irqrestore(&sport->port.lock, flags);
++              return;
++      }
+       dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
diff --git a/target/linux/layerscape/patches-5.4/819-uart-0008-MLK-21445-serial-fsl_lpuart-do-HW-reset-for-communic.patch b/target/linux/layerscape/patches-5.4/819-uart-0008-MLK-21445-serial-fsl_lpuart-do-HW-reset-for-communic.patch
new file mode 100644 (file)
index 0000000..8892bc9
--- /dev/null
@@ -0,0 +1,127 @@
+From d9d113c22c634219cc248a7c6dcf157e2927edad Mon Sep 17 00:00:00 2001
+From: Fugang Duan <fugang.duan@nxp.com>
+Date: Tue, 23 Jul 2019 11:36:22 +0800
+Subject: [PATCH] MLK-21445 serial: fsl_lpuart: do HW reset for communication
+ port
+
+Do HW reset for communication port after the port is registered
+if the UART controller support the feature.
+
+Do partition reset with LPUART's power on, LPUART registers will
+keep the previous status, like on i.MX8QM platform,  which is not
+expected action, so reset the HW is required.
+
+Currently, only i.MX7ULP and i.MX8QM LPUART controllers include
+global register that support HW reset.
+
+Tested-by: Robin Gong <yibin.gong@nxp.com>
+Tested-by: Peng Fan <peng.fan@nxp.com>
+Reviewed-by: Robby Cai <robby.cai@nxp.com>
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+(cherry picked from commit c2bc1f62ec28981462c9cb5ceac17134931ca19f)
+Signed-off-by: Arulpandiyan Vadivel <arulpandiyan_vadivel@mentor.com>
+Signed-off-by: Shrikant Bobade <Shrikant_Bobade@mentor.com>
+(cherry picked from commit 9f396f540093402317c3c1b9a8fe955b91c89164)
+---
+ drivers/tty/serial/fsl_lpuart.c | 48 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 48 insertions(+)
+
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -11,6 +11,7 @@
+ #include <linux/clk.h>
+ #include <linux/console.h>
++#include <linux/delay.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/dmaengine.h>
+ #include <linux/dmapool.h>
+@@ -116,6 +117,11 @@
+ #define UARTSFIFO_TXOF                0x02
+ #define UARTSFIFO_RXUF                0x01
++/* 32-bit global registers only for i.MX7ulp/MX8x
++ * The driver only use the reset feature to reset HW.
++ */
++#define UART_GLOBAL           0x8
++
+ /* 32-bit register definition */
+ #define UARTBAUD              0x00
+ #define UARTSTAT              0x04
+@@ -230,6 +236,10 @@
+ #define UARTWATER_TXWATER_OFF 0
+ #define UARTWATER_RXWATER_OFF 16
++#define UART_GLOBAL_RST               0x2
++#define RST_HW_MIN_US         20
++#define RST_HW_MAX_US         40
++
+ #define UARTFIFO_RXIDEN_RDRF  0x3
+ #define UARTCTRL_IDLECFG      0x7
+@@ -335,6 +345,11 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
+ static void lpuart_dma_tx_complete(void *arg);
+ static int lpuart_sched_rx_dma(struct lpuart_port *sport);
++static inline bool is_imx7ulp_lpuart(struct lpuart_port *sport)
++{
++      return sport->devtype == IMX7ULP_LPUART;
++}
++
+ static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport)
+ {
+       return sport->devtype == IMX8QXP_LPUART;
+@@ -398,6 +413,33 @@ static unsigned int lpuart_get_baud_clk_
+ #define lpuart_enable_clks(x) __lpuart_enable_clks(x, true)
+ #define lpuart_disable_clks(x)        __lpuart_enable_clks(x, false)
++static int lpuart_hw_reset(struct lpuart_port *sport)
++{
++      struct uart_port *port = &sport->port;
++      void __iomem *global_addr;
++      int ret;
++
++      if (uart_console(port))
++              return 0;
++
++      ret = clk_prepare_enable(sport->ipg_clk);
++      if (ret) {
++              dev_err(sport->port.dev, "failed to enable uart ipg clk: %d\n", ret);
++              return ret;
++      }
++
++      if (is_imx7ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) {
++              global_addr = port->membase + UART_GLOBAL - IMX_REG_OFF;
++              writel(UART_GLOBAL_RST, global_addr);
++              usleep_range(RST_HW_MIN_US, RST_HW_MAX_US);
++              writel(0, global_addr);
++              usleep_range(RST_HW_MIN_US, RST_HW_MAX_US);
++      }
++
++      clk_disable_unprepare(sport->ipg_clk);
++      return 0;
++}
++
+ static void lpuart_stop_tx(struct uart_port *port)
+ {
+       unsigned char temp;
+@@ -2704,6 +2746,10 @@ static int lpuart_probe(struct platform_
+       if (ret)
+               goto failed_attach_port;
++      ret = lpuart_hw_reset(sport);
++      if (ret)
++              goto failed_reset;
++
+       uart_get_rs485_mode(&pdev->dev, &sport->port.rs485);
+       if (sport->port.rs485.flags & SER_RS485_RX_DURING_TX)
+@@ -2727,6 +2773,8 @@ static int lpuart_probe(struct platform_
+       return 0;
++failed_reset:
++      uart_remove_one_port(&lpuart_reg, &sport->port);
+ failed_attach_port:
+ failed_irq_request:
+       lpuart_disable_clks(sport);
diff --git a/target/linux/layerscape/patches-5.4/819-uart-0009-MLK-17133-02-tty-serial-lpuart-add-runtime-pm-suppor.patch b/target/linux/layerscape/patches-5.4/819-uart-0009-MLK-17133-02-tty-serial-lpuart-add-runtime-pm-suppor.patch
new file mode 100644 (file)
index 0000000..457b483
--- /dev/null
@@ -0,0 +1,199 @@
+From ff3d8063eed907bed728a14e1519dc659036315a Mon Sep 17 00:00:00 2001
+From: Fugang Duan <fugang.duan@nxp.com>
+Date: Wed, 11 Sep 2019 16:36:48 +0800
+Subject: [PATCH] MLK-17133-02 tty: serial: lpuart: add runtime pm support
+
+Add runtime pm support to manage lpuart clock and its power domain
+to save power in system idle and system suspend stages.
+
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+Reviewed-by: Robin Gong <yibin.gong@nxp.com>
+---
+ drivers/tty/serial/fsl_lpuart.c | 80 ++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 72 insertions(+), 8 deletions(-)
+
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -245,6 +245,7 @@
+ /* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */
+ #define DMA_RX_TIMEOUT                (10)
++#define UART_AUTOSUSPEND_TIMEOUT      3000
+ #define DRIVER_NAME   "fsl-lpuart"
+ #define DEV_NAME      "ttyLP"
+@@ -846,6 +847,20 @@ static void lpuart32_start_tx(struct uar
+       }
+ }
++static void
++lpuart_uart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
++{
++      switch (state) {
++      case UART_PM_STATE_OFF:
++              pm_runtime_mark_last_busy(port->dev);
++              pm_runtime_put_autosuspend(port->dev);
++              break;
++      default:
++              pm_runtime_get_sync(port->dev);
++              break;
++      }
++}
++
+ /* return TIOCSER_TEMT when transmitter is not busy */
+ static unsigned int lpuart_tx_empty(struct uart_port *port)
+ {
+@@ -2259,6 +2274,7 @@ static const struct uart_ops lpuart_pops
+       .break_ctl      = lpuart_break_ctl,
+       .startup        = lpuart_startup,
+       .shutdown       = lpuart_shutdown,
++      .pm             = lpuart_uart_pm,
+       .set_termios    = lpuart_set_termios,
+       .type           = lpuart_type,
+       .request_port   = lpuart_request_port,
+@@ -2283,6 +2299,7 @@ static const struct uart_ops lpuart32_po
+       .break_ctl      = lpuart32_break_ctl,
+       .startup        = lpuart32_startup,
+       .shutdown       = lpuart32_shutdown,
++      .pm             = lpuart_uart_pm,
+       .set_termios    = lpuart32_set_termios,
+       .type           = lpuart_type,
+       .request_port   = lpuart_request_port,
+@@ -2742,6 +2759,11 @@ static int lpuart_probe(struct platform_
+       if (ret)
+               goto failed_irq_request;
++      pm_runtime_use_autosuspend(&pdev->dev);
++      pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
++      pm_runtime_set_active(&pdev->dev);
++      pm_runtime_enable(&pdev->dev);
++
+       ret = uart_add_one_port(&lpuart_reg, &sport->port);
+       if (ret)
+               goto failed_attach_port;
+@@ -2776,6 +2798,9 @@ static int lpuart_probe(struct platform_
+ failed_reset:
+       uart_remove_one_port(&lpuart_reg, &sport->port);
+ failed_attach_port:
++      pm_runtime_disable(&pdev->dev);
++      pm_runtime_set_suspended(&pdev->dev);
++      pm_runtime_dont_use_autosuspend(&pdev->dev);
+ failed_irq_request:
+       lpuart_disable_clks(sport);
+ failed_clock_enable:
+@@ -2802,15 +2827,41 @@ static int lpuart_remove(struct platform
+       if (sport->dma_rx_chan)
+               dma_release_channel(sport->dma_rx_chan);
++      pm_runtime_disable(&pdev->dev);
++      pm_runtime_set_suspended(&pdev->dev);
++      pm_runtime_dont_use_autosuspend(&pdev->dev);
+       return 0;
+ }
+ #ifdef CONFIG_PM_SLEEP
++static int lpuart_runtime_suspend(struct device *dev)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++      struct lpuart_port *sport = platform_get_drvdata(pdev);
++
++      lpuart_disable_clks(sport);
++
++      return 0;
++};
++
++static int lpuart_runtime_resume(struct device *dev)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++      struct lpuart_port *sport = platform_get_drvdata(pdev);
++
++      return lpuart_enable_clks(sport);
++};
++
+ static int lpuart_suspend(struct device *dev)
+ {
+       struct lpuart_port *sport = dev_get_drvdata(dev);
+       unsigned long temp;
+       bool irq_wake;
++      int ret;
++
++      ret = clk_prepare_enable(sport->ipg_clk);
++      if (ret)
++              return ret;
+       if (lpuart_is_32(sport)) {
+               /* disable Rx/Tx and interrupts */
+@@ -2824,10 +2875,14 @@ static int lpuart_suspend(struct device
+               writeb(temp, sport->port.membase + UARTCR2);
+       }
++      clk_disable_unprepare(sport->ipg_clk);
++
+       uart_suspend_port(&lpuart_reg, &sport->port);
+       /* uart_suspend_port() might set wakeup flag */
+       irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
++      if (sport->port.suspended && !irq_wake)
++              return 0;
+       if (sport->lpuart_dma_rx_use) {
+               /*
+@@ -2858,9 +2913,6 @@ static int lpuart_suspend(struct device
+               dmaengine_terminate_all(sport->dma_tx_chan);
+       }
+-      if (sport->port.suspended && !irq_wake)
+-              lpuart_disable_clks(sport);
+-
+       return 0;
+ }
+@@ -2868,9 +2920,11 @@ static int lpuart_resume(struct device *
+ {
+       struct lpuart_port *sport = dev_get_drvdata(dev);
+       bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
++      int ret;
+-      if (sport->port.suspended && !irq_wake)
+-              lpuart_enable_clks(sport);
++      ret = clk_prepare_enable(sport->ipg_clk);
++      if (ret)
++              return ret;
+       if (lpuart_is_32(sport))
+               lpuart32_setup_watermark_enable(sport);
+@@ -2891,13 +2945,23 @@ static int lpuart_resume(struct device *
+       if (lpuart_is_32(sport))
+               lpuart32_configure(sport);
++      clk_disable_unprepare(sport->ipg_clk);
++
+       uart_resume_port(&lpuart_reg, &sport->port);
+       return 0;
+ }
+-#endif
++static const struct dev_pm_ops lpuart_pm_ops = {
++      SET_RUNTIME_PM_OPS(lpuart_runtime_suspend,
++                         lpuart_runtime_resume, NULL)
++      SET_SYSTEM_SLEEP_PM_OPS(lpuart_suspend, lpuart_resume)
++};
++#define SERIAL_LPUART_PM_OPS  (&lpuart_pm_ops)
+-static SIMPLE_DEV_PM_OPS(lpuart_pm_ops, lpuart_suspend, lpuart_resume);
++#else /* !CONFIG_PM_SLEEP */
++
++#define SERIAL_LPUART_PM_OPS  NULL
++#endif
+ static struct platform_driver lpuart_driver = {
+       .probe          = lpuart_probe,
+@@ -2905,7 +2969,7 @@ static struct platform_driver lpuart_dri
+       .driver         = {
+               .name   = "fsl-lpuart",
+               .of_match_table = lpuart_dt_ids,
+-              .pm     = &lpuart_pm_ops,
++              .pm     = SERIAL_LPUART_PM_OPS,
+       },
+ };
diff --git a/target/linux/layerscape/patches-5.4/819-uart-0010-tty-serial-lpuart-enable-wakeup-source-for-lpuart.patch b/target/linux/layerscape/patches-5.4/819-uart-0010-tty-serial-lpuart-enable-wakeup-source-for-lpuart.patch
new file mode 100644 (file)
index 0000000..b3c03bc
--- /dev/null
@@ -0,0 +1,392 @@
+From 4db59ee0d7224e0c8008534c9247480a83889034 Mon Sep 17 00:00:00 2001
+From: Fugang Duan <fugang.duan@nxp.com>
+Date: Wed, 11 Sep 2019 17:01:45 +0800
+Subject: [PATCH] tty: serial: lpuart: enable wakeup source for lpuart
+
+When use lpuart with DMA mode as wake up source, it still switch to
+cpu mode in .suspend() that enable cpu interrupts RIE and ILIE as
+wakeup source. Enable the wakeup irq bits in .suspend_noirq() and
+disable the wakeup irq bits in .resume_noirq().
+
+For DMA mode, after system resume back, it needs to setup DMA again,
+if DMA setup is failed, it switchs to CPU mode. .resume() will share
+the HW setup code with .startup(), so abstract the same code to the
+api like lpuartx_hw_setup().
+
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+---
+ drivers/tty/serial/fsl_lpuart.c | 285 ++++++++++++++++++++++++++++------------
+ 1 file changed, 198 insertions(+), 87 deletions(-)
+
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -21,6 +21,7 @@
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+ #include <linux/of_dma.h>
++#include <linux/pinctrl/consumer.h>
+ #include <linux/pm_domain.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/reset.h>
+@@ -1709,10 +1710,23 @@ static void lpuart_rx_dma_startup(struct
+       }
+ }
++static void lpuart_hw_setup(struct lpuart_port *sport)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&sport->port.lock, flags);
++
++      lpuart_setup_watermark_enable(sport);
++
++      lpuart_rx_dma_startup(sport);
++      lpuart_tx_dma_startup(sport);
++
++      spin_unlock_irqrestore(&sport->port.lock, flags);
++}
++
+ static int lpuart_startup(struct uart_port *port)
+ {
+       struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+-      unsigned long flags;
+       unsigned char temp;
+       /* determine FIFO size and enable FIFO mode */
+@@ -1725,14 +1739,7 @@ static int lpuart_startup(struct uart_po
+       sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_RXSIZE_OFF) &
+                                           UARTPFIFO_FIFOSIZE_MASK);
+-      spin_lock_irqsave(&sport->port.lock, flags);
+-
+-      lpuart_setup_watermark_enable(sport);
+-
+-      lpuart_rx_dma_startup(sport);
+-      lpuart_tx_dma_startup(sport);
+-
+-      spin_unlock_irqrestore(&sport->port.lock, flags);
++      lpuart_hw_setup(sport);
+       return 0;
+ }
+@@ -1759,11 +1766,27 @@ static void lpuart32_configure(struct lp
+       lpuart32_write(&sport->port, temp, UARTCTRL);
+ }
++static void lpuart32_hw_setup(struct lpuart_port *sport)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&sport->port.lock, flags);
++
++      lpuart32_hw_disable(sport);
++
++      lpuart_rx_dma_startup(sport);
++      lpuart_tx_dma_startup(sport);
++
++      lpuart32_setup_watermark_enable(sport);
++      lpuart32_configure(sport);
++
++      spin_unlock_irqrestore(&sport->port.lock, flags);
++}
++
+ static int lpuart32_startup(struct uart_port *port)
+ {
+       struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+       struct tty_port *tty_port = &sport->port.state->port;
+-      unsigned long flags;
+       unsigned long temp;
+       int ret;
+@@ -1784,17 +1807,8 @@ static int lpuart32_startup(struct uart_
+       sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_RXSIZE_OFF) &
+                                           UARTFIFO_FIFOSIZE_MASK);
+-      spin_lock_irqsave(&sport->port.lock, flags);
+-
+-      lpuart32_hw_disable(sport);
+-
+-      lpuart_rx_dma_startup(sport);
+-      lpuart_tx_dma_startup(sport);
+-
+-      lpuart32_setup_watermark_enable(sport);
+-      lpuart32_configure(sport);
++      lpuart32_hw_setup(sport);
+-      spin_unlock_irqrestore(&sport->port.lock, flags);
+       return 0;
+ }
+@@ -2852,108 +2866,205 @@ static int lpuart_runtime_resume(struct
+       return lpuart_enable_clks(sport);
+ };
+-static int lpuart_suspend(struct device *dev)
++static void serial_lpuart_enable_wakeup(struct lpuart_port *sport, bool on)
+ {
+-      struct lpuart_port *sport = dev_get_drvdata(dev);
+-      unsigned long temp;
+-      bool irq_wake;
+-      int ret;
+-
+-      ret = clk_prepare_enable(sport->ipg_clk);
+-      if (ret)
+-              return ret;
++      unsigned int val;
+       if (lpuart_is_32(sport)) {
+-              /* disable Rx/Tx and interrupts */
+-              temp = lpuart32_read(&sport->port, UARTCTRL);
+-              temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
+-              lpuart32_write(&sport->port, temp, UARTCTRL);
++              val = lpuart32_read(&sport->port, UARTCTRL);
++              if (on)
++                      val |= (UARTCTRL_RIE | UARTCTRL_ILIE);
++              else
++                      val &= ~(UARTCTRL_RIE | UARTCTRL_ILIE);
++              lpuart32_write(&sport->port, val, UARTCTRL);
+       } else {
+-              /* disable Rx/Tx and interrupts */
+-              temp = readb(sport->port.membase + UARTCR2);
+-              temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
+-              writeb(temp, sport->port.membase + UARTCR2);
++              val = readb(sport->port.membase + UARTCR2);
++              if (on)
++                      val |= UARTCR2_RIE;
++              else
++                      val &= ~UARTCR2_RIE;
++              writeb(val, sport->port.membase + UARTCR2);
+       }
++}
+-      clk_disable_unprepare(sport->ipg_clk);
++static bool lpuart_uport_is_active(struct lpuart_port *sport)
++{
++      struct tty_port *port = &sport->port.state->port;
++      struct tty_struct *tty;
++      struct device *tty_dev;
++      int may_wake = 0;
+-      uart_suspend_port(&lpuart_reg, &sport->port);
++      tty = tty_port_tty_get(port);
++      if (tty) {
++              tty_dev = tty->dev;
++              may_wake = device_may_wakeup(tty_dev);
++              tty_kref_put(tty);
++      }
+-      /* uart_suspend_port() might set wakeup flag */
+-      irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
+-      if (sport->port.suspended && !irq_wake)
+-              return 0;
++      if ((tty_port_initialized(port) && may_wake) ||
++          (!console_suspend_enabled && uart_console(&sport->port)))
++              return true;
+-      if (sport->lpuart_dma_rx_use) {
+-              /*
+-               * EDMA driver during suspend will forcefully release any
+-               * non-idle DMA channels. If port wakeup is enabled or if port
+-               * is console port or 'no_console_suspend' is set the Rx DMA
+-               * cannot resume as as expected, hence gracefully release the
+-               * Rx DMA path before suspend and start Rx DMA path on resume.
+-               */
+-              if (irq_wake) {
+-                      lpuart_del_timer_sync(sport);
+-                      lpuart_dma_rx_free(&sport->port);
+-              }
++      return false;
++}
+-              /* Disable Rx DMA to use UART port as wakeup source */
++static int lpuart_suspend_noirq(struct device *dev)
++{
++      struct lpuart_port *sport = dev_get_drvdata(dev);
++      bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
++
++      if (lpuart_uport_is_active(sport))
++              serial_lpuart_enable_wakeup(sport, !!irq_wake);
++
++      pinctrl_pm_select_sleep_state(dev);
++
++      return 0;
++}
++
++static int lpuart_resume_noirq(struct device *dev)
++{
++      struct lpuart_port *sport = dev_get_drvdata(dev);
++      unsigned int val;
++
++      pinctrl_pm_select_default_state(dev);
++
++      if (lpuart_uport_is_active(sport)) {
++              serial_lpuart_enable_wakeup(sport, false);
++
++              /* clear the wakeup flags */
+               if (lpuart_is_32(sport)) {
+-                      temp = lpuart32_read(&sport->port, UARTBAUD);
+-                      lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE,
+-                                     UARTBAUD);
+-              } else {
+-                      writeb(readb(sport->port.membase + UARTCR5) &
+-                             ~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
++                      val = lpuart32_read(&sport->port, UARTSTAT);
++                      lpuart32_write(&sport->port, val, UARTSTAT);
+               }
+       }
+-      if (sport->lpuart_dma_tx_use) {
+-              sport->dma_tx_in_progress = false;
+-              dmaengine_terminate_all(sport->dma_tx_chan);
+-      }
+-
+       return 0;
+ }
+-static int lpuart_resume(struct device *dev)
++static int lpuart_suspend(struct device *dev)
+ {
+       struct lpuart_port *sport = dev_get_drvdata(dev);
+-      bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
+-      int ret;
++      unsigned long temp;
++      unsigned long flags;
+-      ret = clk_prepare_enable(sport->ipg_clk);
+-      if (ret)
+-              return ret;
++      uart_suspend_port(&lpuart_reg, &sport->port);
+-      if (lpuart_is_32(sport))
+-              lpuart32_setup_watermark_enable(sport);
+-      else
+-              lpuart_setup_watermark_enable(sport);
++      if (lpuart_uport_is_active(sport)) {
++              spin_lock_irqsave(&sport->port.lock, flags);
++              if (lpuart_is_32(sport)) {
++                      temp = lpuart32_read(&sport->port, UARTCTRL);
++                      temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
++                      lpuart32_write(&sport->port, temp, UARTCTRL);
++              } else {
++                      temp = readb(sport->port.membase + UARTCR2);
++                      temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
++                      writeb(temp, sport->port.membase + UARTCR2);
++              }
++              spin_unlock_irqrestore(&sport->port.lock, flags);
+-      if (sport->lpuart_dma_rx_use) {
+-              if (irq_wake) {
+-                      if (!lpuart_start_rx_dma(sport))
+-                              rx_dma_timer_init(sport);
+-                      else
+-                              sport->lpuart_dma_rx_use = false;
++              if (sport->lpuart_dma_rx_use) {
++                      /*
++                       * EDMA driver during suspend will forcefully release any
++                       * non-idle DMA channels. If port wakeup is enabled or if port
++                       * is console port or 'no_console_suspend' is set the Rx DMA
++                       * cannot resume as as expected, hence gracefully release the
++                       * Rx DMA path before suspend and start Rx DMA path on resume.
++                       */
++                      lpuart_del_timer_sync(sport);
++                      lpuart_dma_rx_free(&sport->port);
++
++                      /* Disable Rx DMA to use UART port as wakeup source */
++                      spin_lock_irqsave(&sport->port.lock, flags);
++                      if (lpuart_is_32(sport)) {
++                              temp = lpuart32_read(&sport->port, UARTBAUD);
++                              lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE,
++                                             UARTBAUD);
++                      } else {
++                              writeb(readb(sport->port.membase + UARTCR5) &
++                                     ~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
++                      }
++                      spin_unlock_irqrestore(&sport->port.lock, flags);
++              }
++
++              if (sport->lpuart_dma_tx_use) {
++                      spin_lock_irqsave(&sport->port.lock, flags);
++                      if (lpuart_is_32(sport)) {
++                              temp = lpuart32_read(&sport->port, UARTBAUD);
++                              temp &= ~UARTBAUD_TDMAE;
++                              lpuart32_write(&sport->port, temp, UARTBAUD);
++                      } else {
++                              temp = readb(sport->port.membase + UARTCR5);
++                              temp &= ~UARTCR5_TDMAS;
++                              writeb(temp, sport->port.membase + UARTCR5);
++                      }
++                      spin_unlock_irqrestore(&sport->port.lock, flags);
++                      sport->dma_tx_in_progress = false;
++                      dmaengine_terminate_all(sport->dma_tx_chan);
+               }
++      } else if (pm_runtime_active(sport->port.dev)) {
++              lpuart_disable_clks(sport);
++              pm_runtime_disable(sport->port.dev);
++              pm_runtime_set_suspended(sport->port.dev);
+       }
+-      lpuart_tx_dma_startup(sport);
++      return 0;
++}
+-      if (lpuart_is_32(sport))
+-              lpuart32_configure(sport);
++static void lpuart_console_fixup(struct lpuart_port *sport)
++{
++      struct tty_port *port = &sport->port.state->port;
++      struct uart_port *uport = &sport->port;
++      struct ktermios termios;
+-      clk_disable_unprepare(sport->ipg_clk);
++      /* i.MX7ULP enter VLLS mode that lpuart module power off and registers
++       * all lost no matter the port is wakeup source.
++       * For console port, console baud rate setting lost and print messy
++       * log when enable the console port as wakeup source. To avoid the
++       * issue happen, user should not enable uart port as wakeup source
++       * in VLLS mode, or restore console setting here.
++       */
++      if (is_imx7ulp_lpuart(sport) && lpuart_uport_is_active(sport) &&
++          console_suspend_enabled && uart_console(&sport->port)) {
++
++              mutex_lock(&port->mutex);
++              memset(&termios, 0, sizeof(struct ktermios));
++              termios.c_cflag = uport->cons->cflag;
++              if (port->tty && termios.c_cflag == 0)
++                      termios = port->tty->termios;
++              uport->ops->set_termios(uport, &termios, NULL);
++              mutex_unlock(&port->mutex);
++      }
++}
++
++static int lpuart_resume(struct device *dev)
++{
++      struct lpuart_port *sport = dev_get_drvdata(dev);
++      int ret;
++      if (lpuart_uport_is_active(sport)) {
++              if (lpuart_is_32(sport))
++                      lpuart32_hw_setup(sport);
++              else
++                      lpuart_hw_setup(sport);
++      } else if (pm_runtime_active(sport->port.dev)) {
++              ret = lpuart_enable_clks(sport);
++              if (ret)
++                      return ret;
++              pm_runtime_set_active(sport->port.dev);
++              pm_runtime_enable(sport->port.dev);
++      }
++
++      lpuart_console_fixup(sport);
+       uart_resume_port(&lpuart_reg, &sport->port);
+       return 0;
+ }
++
+ static const struct dev_pm_ops lpuart_pm_ops = {
+       SET_RUNTIME_PM_OPS(lpuart_runtime_suspend,
+                          lpuart_runtime_resume, NULL)
++      SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(lpuart_suspend_noirq,
++                                    lpuart_resume_noirq)
+       SET_SYSTEM_SLEEP_PM_OPS(lpuart_suspend, lpuart_resume)
+ };
+ #define SERIAL_LPUART_PM_OPS  (&lpuart_pm_ops)
diff --git a/target/linux/layerscape/patches-5.4/819-uart-0011-serial-fsl_lpuart-enable-two-stop-bits.patch b/target/linux/layerscape/patches-5.4/819-uart-0011-serial-fsl_lpuart-enable-two-stop-bits.patch
new file mode 100644 (file)
index 0000000..1079095
--- /dev/null
@@ -0,0 +1,49 @@
+From 5f1a35c3f5c17cc6229873248a56784fcd03db1c Mon Sep 17 00:00:00 2001
+From: Fugang Duan <fugang.duan@nxp.com>
+Date: Fri, 27 Sep 2019 15:18:41 +0800
+Subject: [PATCH] serial: fsl_lpuart: enable two stop bits
+
+Add two stop bits support.
+User can run the command to enable two stop bits
+for test: stty  cstopb  -F /dev/ttyLPx
+
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+---
+ drivers/tty/serial/fsl_lpuart.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -2111,11 +2111,12 @@ lpuart32_set_termios(struct uart_port *p
+ {
+       struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+       unsigned long flags;
+-      unsigned long ctrl, old_ctrl, modem;
++      unsigned long ctrl, old_ctrl, bd, modem;
+       unsigned int  baud;
+       unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+       ctrl = old_ctrl = lpuart32_read(&sport->port, UARTCTRL);
++      bd = lpuart32_read(&sport->port, UARTBAUD);
+       modem = lpuart32_read(&sport->port, UARTMODIR);
+       /*
+        * only support CS8 and CS7, and for CS7 must enable PE.
+@@ -2152,7 +2153,9 @@ lpuart32_set_termios(struct uart_port *p
+       }
+       if (termios->c_cflag & CSTOPB)
+-              termios->c_cflag &= ~CSTOPB;
++              bd |= UARTBAUD_SBNS;
++      else
++              bd &= ~UARTBAUD_SBNS;
+       /* parity must be enabled when CS7 to match 8-bits format */
+       if ((termios->c_cflag & CSIZE) == CS7)
+@@ -2222,6 +2225,7 @@ lpuart32_set_termios(struct uart_port *p
+       lpuart32_write(&sport->port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE),
+                      UARTCTRL);
++      lpuart32_write(&sport->port, bd, UARTBAUD);
+       lpuart32_serial_setbrg(sport, baud);
+       lpuart32_write(&sport->port, modem, UARTMODIR);
+       lpuart32_write(&sport->port, ctrl, UARTCTRL);
diff --git a/target/linux/layerscape/patches-5.4/819-uart-0012-tty-serial-lpuart-add-LS1028A-support.patch b/target/linux/layerscape/patches-5.4/819-uart-0012-tty-serial-lpuart-add-LS1028A-support.patch
new file mode 100644 (file)
index 0000000..a4cb65c
--- /dev/null
@@ -0,0 +1,68 @@
+From 932dac0380bbf7276d4111c35674679bc9ad6384 Mon Sep 17 00:00:00 2001
+From: Vabhav Sharma <vabhav.sharma@nxp.com>
+Date: Thu, 31 Oct 2019 19:20:47 +0530
+Subject: [PATCH] tty: serial: lpuart: add LS1028A support
+
+NXP LS1028A lpuart is the same IP as LS1021A, but it is
+little endian for register accessing instead of big endian
+on LS1021A.
+
+So add LS1028A matching data to distiguish the chips.
+
+Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
+Signed-off-by: Vabhav Sharma <vabhav.sharma@nxp.com>
+Acked-by: Fugang Duan <fugang.duan@nxp.com>
+---
+ drivers/tty/serial/fsl_lpuart.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -3,6 +3,7 @@
+  *  Freescale lpuart serial port driver
+  *
+  *  Copyright 2012-2014 Freescale Semiconductor, Inc.
++ *  Copyright 2019 NXP
+  */
+ #if defined(CONFIG_SERIAL_FSL_LPUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+@@ -260,6 +261,7 @@ static DEFINE_IDA(fsl_lpuart_ida);
+ enum lpuart_type {
+       VF610_LPUART,
+       LS1021A_LPUART,
++      LS1028A_LPUART,
+       IMX7ULP_LPUART,
+       IMX8QXP_LPUART,
+ };
+@@ -311,13 +313,20 @@ static const struct lpuart_soc_data vf_d
+       .rx_dma_cyclic = true,
+ };
+-static const struct lpuart_soc_data ls_data = {
++static const struct lpuart_soc_data ls1021a_data = {
+       .devtype = LS1021A_LPUART,
+       .iotype = UPIO_MEM32BE,
+       .rx_watermark = 0,
+       .rx_dma_cyclic = true,
+ };
++static const struct lpuart_soc_data ls1028a_data = {
++      .devtype = LS1028A_LPUART,
++      .iotype = UPIO_MEM32,
++      .rx_watermark = 0,
++      .rx_dma_cyclic = true,
++};
++
+ static struct lpuart_soc_data imx7ulp_data = {
+       .devtype = IMX7ULP_LPUART,
+       .iotype = UPIO_MEM32,
+@@ -336,7 +345,8 @@ static struct lpuart_soc_data imx8qxp_da
+ static const struct of_device_id lpuart_dt_ids[] = {
+       { .compatible = "fsl,vf610-lpuart",     .data = &vf_data, },
+-      { .compatible = "fsl,ls1021a-lpuart",   .data = &ls_data, },
++      { .compatible = "fsl,ls1021a-lpuart",   .data = &ls1021a_data, },
++      { .compatible = "fsl,ls1028a-lpuart",   .data = &ls1028a_data, },
+       { .compatible = "fsl,imx7ulp-lpuart",   .data = &imx7ulp_data, },
+       { .compatible = "fsl,imx8qxp-lpuart",   .data = &imx8qxp_data, },
+       { /* sentinel */ }
diff --git a/target/linux/layerscape/patches-5.4/819-uart-0013-LF-484-tty-serial-lpuart-support-UPIO_MEM32-for-lpua.patch b/target/linux/layerscape/patches-5.4/819-uart-0013-LF-484-tty-serial-lpuart-support-UPIO_MEM32-for-lpua.patch
new file mode 100644 (file)
index 0000000..b94389c
--- /dev/null
@@ -0,0 +1,37 @@
+From 1b00d871c9aaa05583b50abb5ba7dfb4ed8bc4f1 Mon Sep 17 00:00:00 2001
+From: Peng Fan <peng.fan@nxp.com>
+Date: Mon, 16 Dec 2019 15:53:00 +0800
+Subject: [PATCH] LF-484 tty: serial: lpuart: support UPIO_MEM32 for lpuart32
+
+"earlycon" no need to specify the value string since it uses
+stdout-path parameters. However when earlycon and normal console
+are not using the same uart port, we need specify value string
+to earlycon, this is what we need to do when support dual linux
+using jailhouse hypervisor. The 2nd linux will use the uart
+of the 1st linux as earlycon.
+
+earlycon=lpuart32,mmio32,0x5a060010,115200 not work for i.MX8QXP.
+It is because lpuart32_early_console_setup not support little endian.
+
+Since the original code is to support UPIO_MEM32BE, so if not
+UPIO_MEM32, we still take it as UPIO_MEM32BE
+
+Acked-by: Fugang Duan <fugang.duan@nxp.com>
+Signed-off-by: Peng Fan <peng.fan@nxp.com>
+---
+ drivers/tty/serial/fsl_lpuart.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -2600,7 +2600,9 @@ static int __init lpuart32_early_console
+       if (!device->port.membase)
+               return -ENODEV;
+-      device->port.iotype = UPIO_MEM32BE;
++      if (device->port.iotype != UPIO_MEM32)
++              device->port.iotype = UPIO_MEM32BE;
++
+       device->con->write = lpuart32_early_write;
+       return 0;
+ }
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0001-MLK-11340-26-usb-phy-add-notify-suspend-and-resume-c.patch b/target/linux/layerscape/patches-5.4/820-usb-0001-MLK-11340-26-usb-phy-add-notify-suspend-and-resume-c.patch
new file mode 100644 (file)
index 0000000..5057a2a
--- /dev/null
@@ -0,0 +1,53 @@
+From 7306c576fd8463f915192e68b7d0b93a24d43c9e Mon Sep 17 00:00:00 2001
+From: Peter Chen <peter.chen@freescale.com>
+Date: Mon, 16 Sep 2013 16:31:24 +0800
+Subject: [PATCH] MLK-11340-26 usb: phy: add notify suspend and resume callback
+
+They are used to notify PHY that the controller enters suspend
+or finishes resume.
+
+Signed-off-by: Peter Chen <peter.chen@freescale.com>
+---
+ include/linux/usb/phy.h | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+--- a/include/linux/usb/phy.h
++++ b/include/linux/usb/phy.h
+@@ -155,6 +155,12 @@ struct usb_phy {
+        * manually detect the charger type.
+        */
+       enum usb_charger_type (*charger_detect)(struct usb_phy *x);
++
++      int     (*notify_suspend)(struct usb_phy *x,
++                      enum usb_device_speed speed);
++      int     (*notify_resume)(struct usb_phy *x,
++                      enum usb_device_speed speed);
++
+ };
+ /* for board-specific init logic */
+@@ -333,6 +339,24 @@ usb_phy_notify_disconnect(struct usb_phy
+       else
+               return 0;
+ }
++
++static inline int usb_phy_notify_suspend
++      (struct usb_phy *x, enum usb_device_speed speed)
++{
++      if (x && x->notify_suspend)
++              return x->notify_suspend(x, speed);
++      else
++              return 0;
++}
++
++static inline int usb_phy_notify_resume
++      (struct usb_phy *x, enum usb_device_speed speed)
++{
++      if (x && x->notify_resume)
++              return x->notify_resume(x, speed);
++      else
++              return 0;
++}
+ /* notifiers */
+ static inline int
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0002-MLK-14285-1-usb-phy-add-usb-mode-for-usb_phy.patch b/target/linux/layerscape/patches-5.4/820-usb-0002-MLK-14285-1-usb-phy-add-usb-mode-for-usb_phy.patch
new file mode 100644 (file)
index 0000000..d61388c
--- /dev/null
@@ -0,0 +1,59 @@
+From ec89a34069e9d33dd8f809c02a12ffb619d67e1f Mon Sep 17 00:00:00 2001
+From: Li Jun <jun.li@nxp.com>
+Date: Wed, 12 Apr 2017 05:31:17 +0800
+Subject: [PATCH] MLK-14285-1 usb: phy: add usb mode for usb_phy
+
+USB phy driver may need to know the current working mode of
+the controller, and does some different settings according to
+host mode or device mode.
+
+Signed-off-by: Li Jun <jun.li@nxp.com>
+(cherry picked from commit 2286cb30feedd6f4a5cb82a0f0af5aa3a04ab698)
+Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
+Signed-off-by: Srikanth Krishnakar <Srikanth_Krishnakar@mentor.com>
+---
+ include/linux/usb/phy.h | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+--- a/include/linux/usb/phy.h
++++ b/include/linux/usb/phy.h
+@@ -63,6 +63,13 @@ enum usb_otg_state {
+       OTG_STATE_A_VBUS_ERR,
+ };
++/* The usb role of phy to be working with */
++enum usb_current_mode {
++      CUR_USB_MODE_NONE,
++      CUR_USB_MODE_HOST,
++      CUR_USB_MODE_DEVICE,
++};
++
+ struct usb_phy;
+ struct usb_otg;
+@@ -161,6 +168,9 @@ struct usb_phy {
+       int     (*notify_resume)(struct usb_phy *x,
+                       enum usb_device_speed speed);
++      int     (*set_mode)(struct usb_phy *x,
++                      enum usb_current_mode mode);
++
+ };
+ /* for board-specific init logic */
+@@ -219,6 +229,15 @@ usb_phy_vbus_off(struct usb_phy *x)
+       return x->set_vbus(x, false);
+ }
++static inline int
++usb_phy_set_mode(struct usb_phy *x, enum usb_current_mode mode)
++{
++      if (!x || !x->set_mode)
++              return 0;
++
++      return x->set_mode(x, mode);
++}
++
+ /* for usb host and peripheral controller drivers */
+ #if IS_ENABLED(CONFIG_USB_PHY)
+ extern struct usb_phy *usb_get_phy(enum usb_phy_type type);
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0003-usb-phy-show-USB-charger-type-for-user.patch b/target/linux/layerscape/patches-5.4/820-usb-0003-usb-phy-show-USB-charger-type-for-user.patch
new file mode 100644 (file)
index 0000000..c2e85c0
--- /dev/null
@@ -0,0 +1,49 @@
+From 8eaa50485af15a4e1cc0c7c04f5ce3916e712ae1 Mon Sep 17 00:00:00 2001
+From: Peter Chen <peter.chen@nxp.com>
+Date: Wed, 6 Nov 2019 17:24:29 +0800
+Subject: [PATCH] usb: phy: show USB charger type for user
+
+Current USB charger framework only shows charger state for user, but the
+user may also need charger type for further use, add support for it.
+
+Signed-off-by: Peter Chen <peter.chen@nxp.com>
+---
+ drivers/usb/phy/phy.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/phy/phy.c
++++ b/drivers/usb/phy/phy.c
+@@ -34,6 +34,14 @@ struct phy_devm {
+       struct notifier_block *nb;
+ };
++static const char *const usb_chger_type[] = {
++      [UNKNOWN_TYPE]                  = "USB_CHARGER_UNKNOWN_TYPE",
++      [SDP_TYPE]                      = "USB_CHARGER_SDP_TYPE",
++      [CDP_TYPE]                      = "USB_CHARGER_CDP_TYPE",
++      [DCP_TYPE]                      = "USB_CHARGER_DCP_TYPE",
++      [ACA_TYPE]                      = "USB_CHARGER_ACA_TYPE",
++};
++
+ static struct usb_phy *__usb_find_phy(struct list_head *list,
+       enum usb_phy_type type)
+ {
+@@ -98,7 +106,8 @@ static void usb_phy_notify_charger_work(
+ {
+       struct usb_phy *usb_phy = container_of(work, struct usb_phy, chg_work);
+       char uchger_state[50] = { 0 };
+-      char *envp[] = { uchger_state, NULL };
++      char uchger_type[50] = { 0 };
++      char *envp[] = { uchger_state, uchger_type, NULL };
+       unsigned int min, max;
+       switch (usb_phy->chg_state) {
+@@ -122,6 +131,8 @@ static void usb_phy_notify_charger_work(
+               return;
+       }
++      snprintf(uchger_type, ARRAY_SIZE(uchger_type),
++               "USB_CHARGER_TYPE=%s", usb_chger_type[usb_phy->chg_type]);
+       kobject_uevent_env(&usb_phy->dev->kobj, KOBJ_CHANGE, envp);
+ }
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0004-usb-dwc3-use-suspend-clock-from-dt-to-set-power-down.patch b/target/linux/layerscape/patches-5.4/820-usb-0004-usb-dwc3-use-suspend-clock-from-dt-to-set-power-down.patch
new file mode 100644 (file)
index 0000000..a1a06f0
--- /dev/null
@@ -0,0 +1,62 @@
+From 0d4749abb6f7d042643ba1aa27a7388e8290b6f5 Mon Sep 17 00:00:00 2001
+From: Li Jun <jun.li@nxp.com>
+Date: Tue, 16 Apr 2019 14:02:38 +0800
+Subject: [PATCH] usb: dwc3: use suspend clock from dt to set power down scale
+
+Since the new dwc3 use bulk clks including the suspend clk, so we can
+use it to calculate the power down scale value.
+
+Acked-by: Peter Chen <peter.chen@nxp.com>
+Signed-off-by: Li Jun <jun.li@nxp.com>
+---
+ drivers/usb/dwc3/core.c | 21 +++++++++++++++++++++
+ drivers/usb/dwc3/core.h |  1 +
+ 2 files changed, 22 insertions(+)
+
+--- a/drivers/usb/dwc3/core.c
++++ b/drivers/usb/dwc3/core.c
+@@ -894,6 +894,25 @@ static void dwc3_set_incr_burst_type(str
+       dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg);
+ }
++static void dwc3_set_power_down_clk_scale(struct dwc3 *dwc)
++{
++      u32 reg, scale;
++
++      if (dwc->num_clks == 0)
++              return;
++
++      /*
++       * The power down scale field specifies how many suspend_clk
++       * periods fit into a 16KHz clock period. When performing
++       * the division, round up the remainder.
++       */
++      scale = DIV_ROUND_UP(clk_get_rate(dwc->clks[2].clk), 16384);
++      reg = dwc3_readl(dwc->regs, DWC3_GCTL);
++      reg &= ~(DWC3_GCTL_PWRDNSCALE_MASK);
++      reg |= DWC3_GCTL_PWRDNSCALE(scale);
++      dwc3_writel(dwc->regs, DWC3_GCTL, reg);
++}
++
+ /**
+  * dwc3_core_init - Low-level initialization of DWC3 Core
+  * @dwc: Pointer to our controller context structure
+@@ -918,6 +937,8 @@ static int dwc3_core_init(struct dwc3 *d
+                       dwc->maximum_speed = USB_SPEED_HIGH;
+       }
++      dwc3_set_power_down_clk_scale(dwc);
++
+       ret = dwc3_phy_setup(dwc);
+       if (ret)
+               goto err0;
+--- a/drivers/usb/dwc3/core.h
++++ b/drivers/usb/dwc3/core.h
+@@ -223,6 +223,7 @@
+ /* Global Configuration Register */
+ #define DWC3_GCTL_PWRDNSCALE(n)       ((n) << 19)
++#define DWC3_GCTL_PWRDNSCALE_MASK     DWC3_GCTL_PWRDNSCALE(0x1fff)
+ #define DWC3_GCTL_U2RSTECN    BIT(16)
+ #define DWC3_GCTL_RAMCLKSEL(x)        (((x) & DWC3_GCTL_CLK_MASK) << 6)
+ #define DWC3_GCTL_CLK_BUS     (0)
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0005-usb-dwc3-add-otg-properties-update.patch b/target/linux/layerscape/patches-5.4/820-usb-0005-usb-dwc3-add-otg-properties-update.patch
new file mode 100644 (file)
index 0000000..2187972
--- /dev/null
@@ -0,0 +1,67 @@
+From 504c440dd9c391ed97299a9d4b2e41b3ac3b6211 Mon Sep 17 00:00:00 2001
+From: Peter Chen <peter.chen@nxp.com>
+Date: Mon, 28 Jan 2019 15:15:11 +0800
+Subject: [PATCH] usb: dwc3: add otg properties update
+
+During the USB certification CV9 test, if we report OTG descriptor
+to test suite, it will require doing OTG test, but in fact, it does
+not support OTG-compliance in dwc3 driver.
+
+Signed-off-by: Peter Chen <peter.chen@nxp.com>
+---
+ drivers/usb/dwc3/core.c   | 11 +++++++++++
+ drivers/usb/dwc3/core.h   |  2 ++
+ drivers/usb/dwc3/gadget.c |  4 ++++
+ 3 files changed, 17 insertions(+)
+
+--- a/drivers/usb/dwc3/core.c
++++ b/drivers/usb/dwc3/core.c
+@@ -1260,6 +1260,17 @@ static void dwc3_get_properties(struct d
+       dwc->maximum_speed = usb_get_maximum_speed(dev);
+       dwc->dr_mode = usb_get_dr_mode(dev);
++      if (dwc->dr_mode == USB_DR_MODE_OTG) {
++              dwc->otg_caps.otg_rev = 0x0300;
++              dwc->otg_caps.hnp_support = true;
++              dwc->otg_caps.srp_support = true;
++              dwc->otg_caps.adp_support = true;
++
++              /* Update otg capabilities by DT properties */
++              of_usb_update_otg_caps(dev->of_node,
++                                     &dwc->otg_caps);
++      }
++
+       dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node);
+       dwc->sysdev_is_parent = device_property_read_bool(dev,
+--- a/drivers/usb/dwc3/core.h
++++ b/drivers/usb/dwc3/core.h
+@@ -944,6 +944,7 @@ struct dwc3_scratchpad_array {
+  * @nr_scratch: number of scratch buffers
+  * @u1u2: only used on revisions <1.83a for workaround
+  * @maximum_speed: maximum speed requested (mainly for testing purposes)
++ * @otg_caps: the OTG capabilities from hardware point
+  * @revision: revision register contents
+  * @version_type: VERSIONTYPE register contents, a sub release of a revision
+  * @dr_mode: requested mode of operation
+@@ -1097,6 +1098,7 @@ struct dwc3 {
+       u32                     nr_scratch;
+       u32                     u1u2;
+       u32                     maximum_speed;
++      struct usb_otg_caps     otg_caps;
+       /*
+        * All 3.1 IP version constants are greater than the 3.0 IP
+--- a/drivers/usb/dwc3/gadget.c
++++ b/drivers/usb/dwc3/gadget.c
+@@ -3376,6 +3376,10 @@ int dwc3_gadget_init(struct dwc3 *dwc)
+       dwc->gadget.sg_supported        = true;
+       dwc->gadget.name                = "dwc3-gadget";
+       dwc->gadget.lpm_capable         = true;
++      dwc->gadget.is_otg              = (dwc->dr_mode == USB_DR_MODE_OTG) &&
++                                        (dwc->otg_caps.hnp_support ||
++                                         dwc->otg_caps.srp_support ||
++                                         dwc->otg_caps.adp_support);
+       /*
+        * FIXME We might be setting max_speed to <SUPER, however versions
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0006-usb-dwc3-drd-add-usb-role-switch-class-support-for-d.patch b/target/linux/layerscape/patches-5.4/820-usb-0006-usb-dwc3-drd-add-usb-role-switch-class-support-for-d.patch
new file mode 100644 (file)
index 0000000..aece52c
--- /dev/null
@@ -0,0 +1,103 @@
+From 8595748e58885439c7e18a11a94702378bff3b02 Mon Sep 17 00:00:00 2001
+From: Li Jun <jun.li@nxp.com>
+Date: Sun, 27 Jan 2019 19:40:03 +0800
+Subject: [PATCH] usb: dwc3: drd: add usb role switch class support for dual
+ role swap
+
+Register a usb_role_switch for dual role swap if the property
+"usb-role-switch" is present.
+
+Signed-off-by: Li Jun <jun.li@nxp.com>
+---
+ drivers/usb/dwc3/core.h |  2 ++
+ drivers/usb/dwc3/drd.c  | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 48 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/dwc3/core.h
++++ b/drivers/usb/dwc3/core.h
+@@ -25,6 +25,7 @@
+ #include <linux/usb/ch9.h>
+ #include <linux/usb/gadget.h>
+ #include <linux/usb/otg.h>
++#include <linux/usb/role.h>
+ #include <linux/ulpi/interface.h>
+ #include <linux/phy/phy.h>
+@@ -1082,6 +1083,7 @@ struct dwc3 {
+       void __iomem            *regs;
+       size_t                  regs_size;
++      struct usb_role_switch  *role_switch;
+       enum usb_dr_mode        dr_mode;
+       u32                     current_dr_role;
+       u32                     desired_dr_role;
+--- a/drivers/usb/dwc3/drd.c
++++ b/drivers/usb/dwc3/drd.c
+@@ -476,6 +476,43 @@ static struct extcon_dev *dwc3_get_extco
+       return edev;
+ }
++static int dwc3_usb_role_switch_set(struct device *dev, enum usb_role role)
++{
++      u32 mode;
++
++      switch (role) {
++      case USB_ROLE_HOST:
++              mode = DWC3_GCTL_PRTCAP_HOST;
++              break;
++      case USB_ROLE_DEVICE:
++              mode = DWC3_GCTL_PRTCAP_DEVICE;
++              break;
++      default:
++              return 0;
++      };
++
++      dwc3_set_mode(dev_get_drvdata(dev), mode);
++      return 0;
++}
++
++static enum usb_role dwc3_usb_role_switch_get(struct device *dev)
++{
++      struct dwc3 *dwc = dev_get_drvdata(dev);
++      unsigned long flags;
++      enum usb_role role;
++
++      spin_lock_irqsave(&dwc->lock, flags);
++      role = dwc->current_dr_role;
++      spin_unlock_irqrestore(&dwc->lock, flags);
++
++      return role;
++}
++
++static const struct usb_role_switch_desc dwc3_role_switch = {
++      .set = dwc3_usb_role_switch_set,
++      .get = dwc3_usb_role_switch_get,
++};
++
+ int dwc3_drd_init(struct dwc3 *dwc)
+ {
+       int ret, irq;
+@@ -484,7 +521,12 @@ int dwc3_drd_init(struct dwc3 *dwc)
+       if (IS_ERR(dwc->edev))
+               return PTR_ERR(dwc->edev);
+-      if (dwc->edev) {
++      if (device_property_read_bool(dwc->dev, "usb-role-switch")) {
++              dwc->role_switch = usb_role_switch_register(dwc->dev,
++                                                          &dwc3_role_switch);
++              if (IS_ERR(dwc->role_switch))
++                      return PTR_ERR(dwc->role_switch);
++      } else if (dwc->edev) {
+               dwc->edev_nb.notifier_call = dwc3_drd_notifier;
+               ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
+                                              &dwc->edev_nb);
+@@ -531,6 +573,9 @@ void dwc3_drd_exit(struct dwc3 *dwc)
+ {
+       unsigned long flags;
++      if (dwc->role_switch)
++              usb_role_switch_unregister(dwc->role_switch);
++
+       if (dwc->edev)
+               extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
+                                          &dwc->edev_nb);
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0007-usb-dwc3-gadget-increase-timeout-value-for-send-ep-c.patch b/target/linux/layerscape/patches-5.4/820-usb-0007-usb-dwc3-gadget-increase-timeout-value-for-send-ep-c.patch
new file mode 100644 (file)
index 0000000..98bf576
--- /dev/null
@@ -0,0 +1,27 @@
+From 355f342af78a54051f38ffa4b4018e6ea6b9e3d4 Mon Sep 17 00:00:00 2001
+From: Li Jun <jun.li@nxp.com>
+Date: Mon, 28 Jan 2019 11:19:03 +0800
+Subject: [PATCH] usb: dwc3: gadget: increase timeout value for send ep cmd
+
+In case the USB3 PHY enters P3, then ep command may need a long
+time to complete, per test of ep0out enable, the dwc3 trace time
+stamp shows the time is more then 280us, so increase the timeout
+loop count to be 2000, this has no side effect for HW which has
+no this problem.
+
+Signed-off-by: Li Jun <jun.li@nxp.com>
+---
+ drivers/usb/dwc3/gadget.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/dwc3/gadget.c
++++ b/drivers/usb/dwc3/gadget.c
+@@ -270,7 +270,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_
+ {
+       const struct usb_endpoint_descriptor *desc = dep->endpoint.desc;
+       struct dwc3             *dwc = dep->dwc;
+-      u32                     timeout = 1000;
++      u32                     timeout = 2000;
+       u32                     saved_config = 0;
+       u32                     reg;
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0008-usb-dwc3-set-fwnode-for-role-switch.patch b/target/linux/layerscape/patches-5.4/820-usb-0008-usb-dwc3-set-fwnode-for-role-switch.patch
new file mode 100644 (file)
index 0000000..4da2080
--- /dev/null
@@ -0,0 +1,33 @@
+From 96f35f42495918262455a6208d37e74609ae2c97 Mon Sep 17 00:00:00 2001
+From: Li Jun <jun.li@nxp.com>
+Date: Mon, 19 Aug 2019 10:29:07 +0800
+Subject: [PATCH] usb: dwc3: set fwnode for role switch
+
+As the usb role switch use device connection which uses the fwnode
+of dwc3 for match, so set the role switch fwnode to be the fwnode
+of dwc3.
+
+Signed-off-by: Li Jun <jun.li@nxp.com>
+---
+ drivers/usb/dwc3/drd.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/dwc3/drd.c
++++ b/drivers/usb/dwc3/drd.c
+@@ -508,7 +508,7 @@ static enum usb_role dwc3_usb_role_switc
+       return role;
+ }
+-static const struct usb_role_switch_desc dwc3_role_switch = {
++static struct usb_role_switch_desc dwc3_role_switch = {
+       .set = dwc3_usb_role_switch_set,
+       .get = dwc3_usb_role_switch_get,
+ };
+@@ -522,6 +522,7 @@ int dwc3_drd_init(struct dwc3 *dwc)
+               return PTR_ERR(dwc->edev);
+       if (device_property_read_bool(dwc->dev, "usb-role-switch")) {
++              dwc3_role_switch.fwnode = dev_fwnode(dwc->dev);
+               dwc->role_switch = usb_role_switch_register(dwc->dev,
+                                                           &dwc3_role_switch);
+               if (IS_ERR(dwc->role_switch))
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0009-usb-dwc3-Add-workaround-for-host-mode-VBUS-glitch-wh.patch b/target/linux/layerscape/patches-5.4/820-usb-0009-usb-dwc3-Add-workaround-for-host-mode-VBUS-glitch-wh.patch
new file mode 100644 (file)
index 0000000..18fe69d
--- /dev/null
@@ -0,0 +1,129 @@
+From 61d471c8da972c7ebbaf63779bf8100ee1ec54eb Mon Sep 17 00:00:00 2001
+From: Ran Wang <ran.wang_1@nxp.com>
+Date: Wed, 16 Jan 2019 13:23:17 +0800
+Subject: [PATCH] usb: dwc3: Add workaround for host mode VBUS glitch when boot
+
+When DWC3 is set to host mode by programming register DWC3_GCTL, VBUS
+(or its control signal) will be turned on immediately on related Root Hub
+ports. Then, the VBUS is turned off for a little while(15us) when do xhci
+reset (conducted by xhci driver) and back to normal finally, we can
+observe a negative glitch of related signal happen.
+
+This VBUS glitch might cause some USB devices enumeration fail if kernel
+boot with them connected. Such as LS1012AFWRY/LS1043ARDB/LX2160AQDS
+/LS1088ARDB with Kingston 16GB USB2.0/Kingston USB3.0/JetFlash Transcend
+4GB USB2.0 drives. The fail cases include enumerated as full-speed device
+or report wrong device descriptor, etc.
+
+One SW workaround which can fix this is by programing all xhci PORTSC[PP]
+to 0 to turn off VBUS immediately after setting host mode in DWC3 driver
+(per signal measurement result, it will be too late to do it in
+xhci-plat.c or xhci.c). Then, after xhci reset complete in xhci driver,
+PORTSC[PP]s' value will back to 1 automatically and VBUS on at that time,
+no glitch happen and normal enumeration process has no impact.
+
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+Reviewed-by: Peter Chen <peter.chen@nxp.com>
+---
+ drivers/usb/dwc3/core.c |  3 +++
+ drivers/usb/dwc3/core.h |  3 +++
+ drivers/usb/dwc3/host.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 54 insertions(+)
+
+--- a/drivers/usb/dwc3/core.c
++++ b/drivers/usb/dwc3/core.c
+@@ -1350,6 +1350,9 @@ static void dwc3_get_properties(struct d
+       dwc->dis_metastability_quirk = device_property_read_bool(dev,
+                               "snps,dis_metastability_quirk");
++      dwc->host_vbus_glitches = device_property_read_bool(dev,
++                              "snps,host-vbus-glitches");
++
+       dwc->lpm_nyet_threshold = lpm_nyet_threshold;
+       dwc->tx_de_emphasis = tx_de_emphasis;
+--- a/drivers/usb/dwc3/core.h
++++ b/drivers/usb/dwc3/core.h
+@@ -1034,6 +1034,8 @@ struct dwc3_scratchpad_array {
+  *    2       - No de-emphasis
+  *    3       - Reserved
+  * @dis_metastability_quirk: set to disable metastability quirk.
++ * @host_vbus_glitches: set to avoid vbus glitch during
++ *                      xhci reset.
+  * @imod_interval: set the interrupt moderation interval in 250ns
+  *                 increments or 0 to disable.
+  */
+@@ -1225,6 +1227,7 @@ struct dwc3 {
+       unsigned                tx_de_emphasis:2;
+       unsigned                dis_metastability_quirk:1;
++      unsigned                host_vbus_glitches:1;
+       u16                     imod_interval;
+ };
+--- a/drivers/usb/dwc3/host.c
++++ b/drivers/usb/dwc3/host.c
+@@ -9,8 +9,49 @@
+ #include <linux/platform_device.h>
++#include "../host/xhci.h"
++
+ #include "core.h"
++
++#define XHCI_HCSPARAMS1               0x4
++#define XHCI_PORTSC_BASE      0x400
++
++/*
++ * dwc3_power_off_all_roothub_ports - Power off all Root hub ports
++ * @dwc3: Pointer to our controller context structure
++ */
++static void dwc3_power_off_all_roothub_ports(struct dwc3 *dwc)
++{
++      int i, port_num;
++      u32 reg, op_regs_base, offset;
++      void __iomem *xhci_regs;
++
++      /* xhci regs is not mapped yet, do it temperary here */
++      if (dwc->xhci_resources[0].start) {
++              xhci_regs = ioremap(dwc->xhci_resources[0].start,
++                              DWC3_XHCI_REGS_END);
++              if (IS_ERR(xhci_regs)) {
++                      dev_err(dwc->dev, "Failed to ioremap xhci_regs\n");
++                      return;
++              }
++
++              op_regs_base = HC_LENGTH(readl(xhci_regs));
++              reg = readl(xhci_regs + XHCI_HCSPARAMS1);
++              port_num = HCS_MAX_PORTS(reg);
++
++              for (i = 1; i <= port_num; i++) {
++                      offset = op_regs_base + XHCI_PORTSC_BASE + 0x10*(i-1);
++                      reg = readl(xhci_regs + offset);
++                      reg &= ~PORT_POWER;
++                      writel(reg, xhci_regs + offset);
++              }
++
++              iounmap(xhci_regs);
++      } else
++              dev_err(dwc->dev, "xhci base reg invalid\n");
++}
++
+ static int dwc3_host_get_irq(struct dwc3 *dwc)
+ {
+       struct platform_device  *dwc3_pdev = to_platform_device(dwc->dev);
+@@ -50,6 +91,13 @@ int dwc3_host_init(struct dwc3 *dwc)
+       struct platform_device  *dwc3_pdev = to_platform_device(dwc->dev);
+       int                     prop_idx = 0;
++      /*
++       * We have to power off all Root hub ports immediately after DWC3 set
++       * to host mode to avoid VBUS glitch happen when xhci get reset later.
++       */
++      if (dwc->host_vbus_glitches)
++              dwc3_power_off_all_roothub_ports(dwc);
++
+       irq = dwc3_host_get_irq(dwc);
+       if (irq < 0)
+               return irq;
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0010-MLK-22675-usb-dwc3-host-disable-park-mode.patch b/target/linux/layerscape/patches-5.4/820-usb-0010-MLK-22675-usb-dwc3-host-disable-park-mode.patch
new file mode 100644 (file)
index 0000000..bca63de
--- /dev/null
@@ -0,0 +1,88 @@
+From c5324b25fe98c7a4784248b53a75720b226436c2 Mon Sep 17 00:00:00 2001
+From: Li Jun <jun.li@nxp.com>
+Date: Tue, 29 Oct 2019 17:40:25 +0800
+Subject: [PATCH] MLK-22675 usb: dwc3: host: disable park mode
+
+- Advantage of park mode
+  When only a single Async endpoint is active.
+
+- Behavior of park mode
+  1. The controller prefetches data/TRBs to do 3 * burst_size worth
+     of packets.
+  2. When park mode is disabled there will be some delay between
+     bursts on the USB. This can be avoided if park mode is enabled
+     in cases of only one endpoint is active.
+  3. But this delay is significant only with systems of large
+     latencies.
+  4. We have noticed that in cases where a device NAKs often, it
+     tends to bring down the performance for a single endpoint case.
+
+- Issue on "park mode"
+  1. LSP (List Processor) goes in and out of park mode irrespective
+     of the fact that there are more endpoints active. #LSP consider
+     that there is only one endpoint active.
+  2. This causes master scheduler and transaction handlers to think
+     that they are in park mode even though they are not. This is
+     because request to transaction handlers, generated by HSCH is
+     in park mode when the request is made
+  3. This causes a case where the master scheduler calculates wrongly
+     the number of TRB cache space available.
+  4. Because of the wrongly calculated number of TRB spaces, the core
+     fetches more TRBS than there is space for.
+  5. This causes overwriting the TRB cache area into the TRQ cache
+     area which is next to the TRB cache area.
+  6. This causes invalidating an entry in the TRQ
+  7. This causes transaction handlers to ignore a request in the TRQ
+     which it should have processed.
+  8. This causes the main scheduler to hang because it is waiting for
+     status from transaction handler.
+  9. This causes host controller to hang.
+
+- Work Around
+  Disabling park mode for super speed by setting GUCTL1[17] to be 1.
+
+The STAR number is 9001415732, which is target to be released around
+May,2020.
+
+Reviewed-by: Peter Chen <peter.chen@nxp.com>
+Reviewed-by: Ran Wang <ran.wang_1@nxp.com>
+Signed-off-by: Li Jun <jun.li@nxp.com>
+---
+ drivers/usb/dwc3/core.c | 15 +++++++++++++++
+ drivers/usb/dwc3/core.h |  1 +
+ 2 files changed, 16 insertions(+)
+
+--- a/drivers/usb/dwc3/core.c
++++ b/drivers/usb/dwc3/core.c
+@@ -1030,6 +1030,21 @@ static int dwc3_core_init(struct dwc3 *d
+               reg |= DWC3_GUCTL_HSTINAUTORETRY;
+               dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
++
++              /*
++               * Disable Park Mode for super speed:
++               * Park mode is used in host mode when only a single async
++               * endpoint is active, but which has a known issue cause
++               * USB3.0 HC may die when read and write at the same time,
++               * considering the advantages of this mode are minimal,
++               * this issue only impacts super speed and exist on all IP
++               * versions, disable it for SS, Synopsys will release a formal
++               * STAR 9001415732, and disable it by default in next IP
++               * release.
++               */
++              reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
++              reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS;
++              dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
+       }
+       /*
+--- a/drivers/usb/dwc3/core.h
++++ b/drivers/usb/dwc3/core.h
+@@ -253,6 +253,7 @@
+ /* Global User Control 1 Register */
+ #define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS    BIT(28)
+ #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
++#define DWC3_GUCTL1_PARKMODE_DISABLE_SS       BIT(17)
+ /* Global Status Register */
+ #define DWC3_GSTS_OTG_IP      BIT(10)
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0011-usb-dwc3-Add-cache-type-configuration-support.patch b/target/linux/layerscape/patches-5.4/820-usb-0011-usb-dwc3-Add-cache-type-configuration-support.patch
new file mode 100644 (file)
index 0000000..b0d5c9c
--- /dev/null
@@ -0,0 +1,151 @@
+From 63d47233f18ab6bb880cc4005a373a55c8364e0b Mon Sep 17 00:00:00 2001
+From: Ran Wang <ran.wang_1@nxp.com>
+Date: Fri, 22 Nov 2019 14:17:32 +0800
+Subject: [PATCH] usb: dwc3: Add cache type configuration support
+
+This feature is telling how to configure cache type on 4 different
+transfer types: Data Read, Desc Read, Data Write and Desc write. For each
+transfer type, controller has a 4-bit register field to enable different
+cache type. Quoted from DWC3 data book Table 6-5 Cache Type Bit Assignments:
+----------------------------------------------------------------
+MBUS_TYPE| bit[3]       |bit[2]       |bit[1]     |bit[0]
+----------------------------------------------------------------
+AHB      |Cacheable     |Bufferable   |Privilegge |Data
+AXI3     |Write Allocate|Read Allocate|Cacheable  |Bufferable
+AXI4     |Allocate Other|Allocate     |Modifiable |Bufferable
+AXI4     |Other Allocate|Allocate     |Modifiable |Bufferable
+Native   |Same as AXI   |Same as AXI  |Same as AXI|Same as AXI
+----------------------------------------------------------------
+Note: The AHB, AXI3, AXI4, and PCIe busses use different names for certain
+signals, which have the same meaning:
+  Bufferable = Posted
+  Cacheable = Modifiable = Snoop (negation of No Snoop)
+
+In most cases, driver support is not required unless the default values of
+registers are not correct *and* DWC3 node has enabled dma-coherent. So far we
+have observed USB device detect failure on some Layerscape platforms if this
+programming was not applied.
+
+Related struct:
+struct dwc3_cache_type {
+       u8 transfer_type_datard;
+       u8 transfer_type_descrd;
+       u8 transfer_type_datawr;
+       u8 transfer_type_descwr;
+};
+
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+Reviewed-by: Jun Li <jun.li@nxp.com>
+---
+ drivers/usb/dwc3/core.c | 61 ++++++++++++++++++++++++++++++++++++++++++++-----
+ drivers/usb/dwc3/core.h | 15 ++++++++++++
+ 2 files changed, 70 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/dwc3/core.c
++++ b/drivers/usb/dwc3/core.c
+@@ -913,6 +913,54 @@ static void dwc3_set_power_down_clk_scal
+       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ }
++#ifdef CONFIG_OF
++struct dwc3_cache_type {
++      u8 transfer_type_datard;
++      u8 transfer_type_descrd;
++      u8 transfer_type_datawr;
++      u8 transfer_type_descwr;
++};
++
++static const struct dwc3_cache_type layerscape_dwc3_cache_type = {
++      .transfer_type_datard = 2,
++      .transfer_type_descrd = 2,
++      .transfer_type_datawr = 2,
++      .transfer_type_descwr = 2,
++};
++
++/**
++ * dwc3_set_cache_type - Configure cache type registers
++ * @dwc: Pointer to our controller context structure
++ */
++static void dwc3_set_cache_type(struct dwc3 *dwc)
++{
++      u32 tmp, reg;
++      const struct dwc3_cache_type *cache_type =
++              device_get_match_data(dwc->dev);
++
++      if (cache_type) {
++              reg = dwc3_readl(dwc->regs,  DWC3_GSBUSCFG0);
++              tmp = reg;
++
++              reg &= ~DWC3_GSBUSCFG0_DATARD(~0);
++              reg |= DWC3_GSBUSCFG0_DATARD(cache_type->transfer_type_datard);
++
++              reg &= ~DWC3_GSBUSCFG0_DESCRD(~0);
++              reg |= DWC3_GSBUSCFG0_DESCRD(cache_type->transfer_type_descrd);
++
++              reg &= ~DWC3_GSBUSCFG0_DATAWR(~0);
++              reg |= DWC3_GSBUSCFG0_DATAWR(cache_type->transfer_type_datawr);
++
++              reg &= ~DWC3_GSBUSCFG0_DESCWR(~0);
++              reg |= DWC3_GSBUSCFG0_DESCWR(cache_type->transfer_type_descwr);
++
++              if (tmp != reg)
++                      dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, reg);
++      }
++}
++#endif
++
++
+ /**
+  * dwc3_core_init - Low-level initialization of DWC3 Core
+  * @dwc: Pointer to our controller context structure
+@@ -973,6 +1021,10 @@ static int dwc3_core_init(struct dwc3 *d
+       dwc3_set_incr_burst_type(dwc);
++#ifdef CONFIG_OF
++      dwc3_set_cache_type(dwc);
++#endif
++
+       usb_phy_set_suspend(dwc->usb2_phy, 0);
+       usb_phy_set_suspend(dwc->usb3_phy, 0);
+       ret = phy_power_on(dwc->usb2_generic_phy);
+@@ -1890,12 +1942,9 @@ static const struct dev_pm_ops dwc3_dev_
+ #ifdef CONFIG_OF
+ static const struct of_device_id of_dwc3_match[] = {
+-      {
+-              .compatible = "snps,dwc3"
+-      },
+-      {
+-              .compatible = "synopsys,dwc3"
+-      },
++      { .compatible = "fsl,layerscape-dwc3", .data = &layerscape_dwc3_cache_type, },
++      { .compatible = "snps,dwc3" },
++      { .compatible = "synopsys,dwc3" },
+       { },
+ };
+ MODULE_DEVICE_TABLE(of, of_dwc3_match);
+--- a/drivers/usb/dwc3/core.h
++++ b/drivers/usb/dwc3/core.h
+@@ -166,6 +166,21 @@
+ /* Bit fields */
+ /* Global SoC Bus Configuration INCRx Register 0 */
++#ifdef CONFIG_OF
++#define DWC3_GSBUSCFG0_DATARD_SHIFT   28
++#define DWC3_GSBUSCFG0_DATARD(n)      (((n) & 0xf)            \
++                      << DWC3_GSBUSCFG0_DATARD_SHIFT)
++#define DWC3_GSBUSCFG0_DESCRD_SHIFT   24
++#define DWC3_GSBUSCFG0_DESCRD(n)      (((n) & 0xf)            \
++                      << DWC3_GSBUSCFG0_DESCRD_SHIFT)
++#define DWC3_GSBUSCFG0_DATAWR_SHIFT   20
++#define DWC3_GSBUSCFG0_DATAWR(n)      (((n) & 0xf)            \
++                      << DWC3_GSBUSCFG0_DATAWR_SHIFT)
++#define DWC3_GSBUSCFG0_DESCWR_SHIFT   16
++#define DWC3_GSBUSCFG0_DESCWR(n)      (((n) & 0xf)            \
++                      << DWC3_GSBUSCFG0_DESCWR_SHIFT)
++#endif
++
+ #define DWC3_GSBUSCFG0_INCR256BRSTENA (1 << 7) /* INCR256 burst */
+ #define DWC3_GSBUSCFG0_INCR128BRSTENA (1 << 6) /* INCR128 burst */
+ #define DWC3_GSBUSCFG0_INCR64BRSTENA  (1 << 5) /* INCR64 burst */
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0012-MLK-11340-40-usb-whitelist-update-otg-eh-s-TPL-for-f.patch b/target/linux/layerscape/patches-5.4/820-usb-0012-MLK-11340-40-usb-whitelist-update-otg-eh-s-TPL-for-f.patch
new file mode 100644 (file)
index 0000000..259af8e
--- /dev/null
@@ -0,0 +1,117 @@
+From 93cd22091be5d549fb5b0ec78955c2ec272a52e5 Mon Sep 17 00:00:00 2001
+From: Peter Chen <peter.chen@freescale.com>
+Date: Fri, 8 Aug 2014 09:12:52 +0800
+Subject: [PATCH] MLK-11340-40 usb: whitelist: update otg & eh's TPL for fsl
+ i.mx
+
+The default TPL is for USB OTG & EH compliance test, the supported
+class is: mass storage, hub, and hid.
+
+Besides, we add one match criterion that matching targeted device
+through class at interface descriptor.
+
+Tested-by: Li Jun <b47624@freescale.com>
+Signed-off-by: Peter Chen <peter.chen@freescale.com>
+(cherry picked from commit 483c071d989ceb36cacf76e1e3e779c67e5b8280)
+(cherry picked from commit defcf3883f60f8ea913481f16411752cb0132a74)
+---
+ drivers/usb/core/otg_whitelist.h | 73 ++++++++++++++++++++++++++++------------
+ 1 file changed, 52 insertions(+), 21 deletions(-)
+
+--- a/drivers/usb/core/otg_whitelist.h
++++ b/drivers/usb/core/otg_whitelist.h
+@@ -13,35 +13,62 @@
+  */
+ static struct usb_device_id whitelist_table[] = {
+-
+-/* hubs are optional in OTG, but very handy ... */
+-{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
+-{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
+-
+-#ifdef        CONFIG_USB_PRINTER              /* ignoring nonstatic linkage! */
+-/* FIXME actually, printers are NOT supposed to use device classes;
+- * they're supposed to use interface classes...
+- */
+-{ USB_DEVICE_INFO(7, 1, 1) },
+-{ USB_DEVICE_INFO(7, 1, 2) },
+-{ USB_DEVICE_INFO(7, 1, 3) },
++/* Add FSL i.mx whitelist, the default list is for USB Compliance Test */
++#if defined(CONFIG_USB_EHSET_TEST_FIXTURE)    \
++      || defined(CONFIG_USB_EHSET_TEST_FIXTURE_MODULE)
++#define TEST_SE0_NAK_PID                      0x0101
++#define TEST_J_PID                            0x0102
++#define TEST_K_PID                            0x0103
++#define TEST_PACKET_PID                               0x0104
++#define TEST_HS_HOST_PORT_SUSPEND_RESUME      0x0106
++#define TEST_SINGLE_STEP_GET_DEV_DESC         0x0107
++#define TEST_SINGLE_STEP_SET_FEATURE          0x0108
++{ USB_DEVICE(0x1a0a, TEST_SE0_NAK_PID) },
++{ USB_DEVICE(0x1a0a, TEST_J_PID) },
++{ USB_DEVICE(0x1a0a, TEST_K_PID) },
++{ USB_DEVICE(0x1a0a, TEST_PACKET_PID) },
++{ USB_DEVICE(0x1a0a, TEST_HS_HOST_PORT_SUSPEND_RESUME) },
++{ USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_GET_DEV_DESC) },
++{ USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_SET_FEATURE) },
+ #endif
+-#ifdef        CONFIG_USB_NET_CDCETHER
+-/* Linux-USB CDC Ethernet gadget */
+-{ USB_DEVICE(0x0525, 0xa4a1), },
+-/* Linux-USB CDC Ethernet + RNDIS gadget */
+-{ USB_DEVICE(0x0525, 0xa4a2), },
++#define USB_INTERFACE_CLASS_INFO(cl) \
++      .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, \
++      .bInterfaceClass = (cl)
++
++{USB_INTERFACE_CLASS_INFO(USB_CLASS_HUB) },
++#if defined(CONFIG_USB_STORAGE) || defined(CONFIG_USB_STORAGE_MODULE)
++{USB_INTERFACE_CLASS_INFO(USB_CLASS_MASS_STORAGE) },
+ #endif
+-
+-#if   IS_ENABLED(CONFIG_USB_TEST)
+-/* gadget zero, for testing */
+-{ USB_DEVICE(0x0525, 0xa4a0), },
++#if defined(CONFIG_USB_HID) || defined(CONFIG_USB_HID_MODULE)
++{USB_INTERFACE_CLASS_INFO(USB_CLASS_HID) },
+ #endif
+ { }   /* Terminating entry */
+ };
++static bool match_int_class(struct usb_device_id *id, struct usb_device *udev)
++{
++      struct usb_host_config *c;
++      int num_configs, i;
++
++      /* Copy the code from generic.c */
++      c = udev->config;
++      num_configs = udev->descriptor.bNumConfigurations;
++      for (i = 0; i < num_configs; (i++, c++)) {
++              struct usb_interface_descriptor *desc = NULL;
++
++              /* It's possible that a config has no interfaces! */
++              if (c->desc.bNumInterfaces > 0)
++                      desc = &c->intf_cache[0]->altsetting->desc;
++
++              if (desc && (desc->bInterfaceClass == id->bInterfaceClass))
++                      return true;
++      }
++
++      return false;
++}
++
+ static int is_targeted(struct usb_device *dev)
+ {
+       struct usb_device_id    *id = whitelist_table;
+@@ -90,6 +117,10 @@ static int is_targeted(struct usb_device
+                   (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
+                       continue;
++              if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
++                  (!match_int_class(id, dev)))
++                      continue;
++
+               return 1;
+       }
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0013-MLK-9785-1-usb-host-ehci-hcd-enable-park-mode.patch b/target/linux/layerscape/patches-5.4/820-usb-0013-MLK-9785-1-usb-host-ehci-hcd-enable-park-mode.patch
new file mode 100644 (file)
index 0000000..b07c680
--- /dev/null
@@ -0,0 +1,38 @@
+From df4f2de9834b02c58bc59cbd6c148db03fcbaba5 Mon Sep 17 00:00:00 2001
+From: Peter Chen <peter.chen@freescale.com>
+Date: Tue, 4 Nov 2014 20:46:15 +0800
+Subject: [PATCH] MLK-9785-1 usb: host: ehci-hcd: enable park mode
+
+Enable park mode will improve the performance a lot at USB ethernet use
+case, but a little at USB mass storage use case, and it is not harm from
+the tests. Below the performance comparison at imx6sl:
+
+USB Ethernet (Mbps)
+       Default                 Enable Park
+TX     192                     262
+RX     262                     290
+
+USB Mass Storage (MB/s)
+Read   21.8                    22.9
+Write  19.5                    22.8
+
+This patch is used for freescale internal.
+
+Signed-off-by: Peter Chen <peter.chen@freescale.com>
+(cherry picked from commit b2289a78958859cff37508e4db0314463f33c2e0)
+(cherry picked from commit 233f37db41b01b0f827b91422711642228371615)
+---
+ drivers/usb/host/ehci-hcd.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -80,7 +80,7 @@ module_param (log2_irq_thresh, int, S_IR
+ MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
+ /* initial park setting:  slower than hw default */
+-static unsigned park = 0;
++static unsigned park = 3;
+ module_param (park, uint, S_IRUGO);
+ MODULE_PARM_DESC (park, "park setting; 1-3 back-to-back async packets");
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0014-MLK-17380-3-usb-move-EH-SINGLE_STEP_SET_FEATURE-impl.patch b/target/linux/layerscape/patches-5.4/820-usb-0014-MLK-17380-3-usb-move-EH-SINGLE_STEP_SET_FEATURE-impl.patch
new file mode 100644 (file)
index 0000000..2ea9390
--- /dev/null
@@ -0,0 +1,364 @@
+From d4806e4f103895387dc679fe53e1f4a5d41391bf Mon Sep 17 00:00:00 2001
+From: Peter Chen <peter.chen@nxp.com>
+Date: Thu, 18 Jan 2018 11:03:24 +0800
+Subject: [PATCH] MLK-17380-3 usb: move EH SINGLE_STEP_SET_FEATURE implement to
+ core
+
+Since other USB 2.0 host may need it, like USB2 for XHCI. We move
+this design to HCD core.
+
+Acked-by: Jun Li <jun.li@nxp.com>
+Signed-off-by: Peter Chen <peter.chen@nxp.com>
+(cherry picked from commit 035a27e1a3088261f40f77534aaccfe5825c2f96)
+---
+ drivers/usb/core/hcd.c      | 134 ++++++++++++++++++++++++++++++++++++++++++
+ drivers/usb/host/ehci-hcd.c |   4 ++
+ drivers/usb/host/ehci-hub.c | 139 --------------------------------------------
+ drivers/usb/host/ehci-q.c   |   2 +-
+ include/linux/usb/hcd.h     |  13 ++++-
+ 5 files changed, 151 insertions(+), 141 deletions(-)
+
+--- a/drivers/usb/core/hcd.c
++++ b/drivers/usb/core/hcd.c
+@@ -2104,6 +2104,140 @@ int usb_hcd_get_frame_number (struct usb
+ }
+ /*-------------------------------------------------------------------------*/
++#ifdef CONFIG_USB_HCD_TEST_MODE
++
++static void usb_ehset_completion(struct urb *urb)
++{
++      struct completion  *done = urb->context;
++
++      complete(done);
++}
++/*
++ * Allocate and initialize a control URB. This request will be used by the
++ * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages
++ * of the GetDescriptor request are sent 15 seconds after the SETUP stage.
++ * Return NULL if failed.
++ */
++static struct urb *request_single_step_set_feature_urb(
++      struct usb_device       *udev,
++      void                    *dr,
++      void                    *buf,
++      struct completion       *done
++) {
++      struct urb *urb;
++      struct usb_hcd *hcd = bus_to_hcd(udev->bus);
++      struct usb_host_endpoint *ep;
++
++      urb = usb_alloc_urb(0, GFP_KERNEL);
++      if (!urb)
++              return NULL;
++
++      urb->pipe = usb_rcvctrlpipe(udev, 0);
++      ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
++                              [usb_pipeendpoint(urb->pipe)];
++      if (!ep) {
++              usb_free_urb(urb);
++              return NULL;
++      }
++
++      urb->ep = ep;
++      urb->dev = udev;
++      urb->setup_packet = (void *)dr;
++      urb->transfer_buffer = buf;
++      urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
++      urb->complete = usb_ehset_completion;
++      urb->status = -EINPROGRESS;
++      urb->actual_length = 0;
++      urb->transfer_flags = URB_DIR_IN;
++      usb_get_urb(urb);
++      atomic_inc(&urb->use_count);
++      atomic_inc(&urb->dev->urbnum);
++      urb->setup_dma = dma_map_single(
++                      hcd->self.sysdev,
++                      urb->setup_packet,
++                      sizeof(struct usb_ctrlrequest),
++                      DMA_TO_DEVICE);
++      urb->transfer_dma = dma_map_single(
++                      hcd->self.sysdev,
++                      urb->transfer_buffer,
++                      urb->transfer_buffer_length,
++                      DMA_FROM_DEVICE);
++      urb->context = done;
++      return urb;
++}
++
++int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
++{
++      int retval = -ENOMEM;
++      struct usb_ctrlrequest *dr;
++      struct urb *urb;
++      struct usb_device *udev;
++      struct usb_device_descriptor *buf;
++      DECLARE_COMPLETION_ONSTACK(done);
++
++      /* Obtain udev of the rhub's child port */
++      udev = usb_hub_find_child(hcd->self.root_hub, port);
++      if (!udev) {
++              dev_err(hcd->self.controller, "No device attached to the RootHub\n");
++              return -ENODEV;
++      }
++      buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
++      if (!buf)
++              return -ENOMEM;
++
++      dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
++      if (!dr) {
++              kfree(buf);
++              return -ENOMEM;
++      }
++
++      /* Fill Setup packet for GetDescriptor */
++      dr->bRequestType = USB_DIR_IN;
++      dr->bRequest = USB_REQ_GET_DESCRIPTOR;
++      dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
++      dr->wIndex = 0;
++      dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
++      urb = request_single_step_set_feature_urb(udev, dr, buf, &done);
++      if (!urb)
++              goto cleanup;
++
++      /* Submit just the SETUP stage */
++      retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 1);
++      if (retval)
++              goto out1;
++      if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
++              usb_kill_urb(urb);
++              retval = -ETIMEDOUT;
++              dev_err(hcd->self.controller,
++                      "%s SETUP stage timed out on ep0\n", __func__);
++              goto out1;
++      }
++      msleep(15 * 1000);
++
++      /* Complete remaining DATA and STATUS stages using the same URB */
++      urb->status = -EINPROGRESS;
++      usb_get_urb(urb);
++      atomic_inc(&urb->use_count);
++      atomic_inc(&urb->dev->urbnum);
++      retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 0);
++      if (!retval && !wait_for_completion_timeout(&done,
++                                              msecs_to_jiffies(2000))) {
++              usb_kill_urb(urb);
++              retval = -ETIMEDOUT;
++              dev_err(hcd->self.controller,
++                      "%s IN stage timed out on ep0\n", __func__);
++      }
++out1:
++      usb_free_urb(urb);
++cleanup:
++      kfree(dr);
++      kfree(buf);
++      return retval;
++}
++EXPORT_SYMBOL_GPL(ehset_single_step_set_feature);
++#endif /* CONFIG_USB_HCD_TEST_MODE */
++
++/*-------------------------------------------------------------------------*/
+ #ifdef        CONFIG_PM
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -1232,6 +1232,10 @@ static const struct hc_driver ehci_hc_dr
+        * device support
+        */
+       .free_dev =             ehci_remove_device,
++#ifdef CONFIG_USB_HCD_TEST_MODE
++      /* EH SINGLE_STEP_SET_FEATURE test support */
++      .submit_single_step_set_feature = ehci_submit_single_step_set_feature,
++#endif
+ };
+ void ehci_init_driver(struct hc_driver *drv,
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -725,145 +725,6 @@ ehci_hub_descriptor (
+ }
+ /*-------------------------------------------------------------------------*/
+-#ifdef CONFIG_USB_HCD_TEST_MODE
+-
+-#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06
+-
+-static void usb_ehset_completion(struct urb *urb)
+-{
+-      struct completion  *done = urb->context;
+-
+-      complete(done);
+-}
+-static int submit_single_step_set_feature(
+-      struct usb_hcd  *hcd,
+-      struct urb      *urb,
+-      int             is_setup
+-);
+-
+-/*
+- * Allocate and initialize a control URB. This request will be used by the
+- * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages
+- * of the GetDescriptor request are sent 15 seconds after the SETUP stage.
+- * Return NULL if failed.
+- */
+-static struct urb *request_single_step_set_feature_urb(
+-      struct usb_device       *udev,
+-      void                    *dr,
+-      void                    *buf,
+-      struct completion       *done
+-) {
+-      struct urb *urb;
+-      struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+-      struct usb_host_endpoint *ep;
+-
+-      urb = usb_alloc_urb(0, GFP_KERNEL);
+-      if (!urb)
+-              return NULL;
+-
+-      urb->pipe = usb_rcvctrlpipe(udev, 0);
+-      ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
+-                              [usb_pipeendpoint(urb->pipe)];
+-      if (!ep) {
+-              usb_free_urb(urb);
+-              return NULL;
+-      }
+-
+-      urb->ep = ep;
+-      urb->dev = udev;
+-      urb->setup_packet = (void *)dr;
+-      urb->transfer_buffer = buf;
+-      urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
+-      urb->complete = usb_ehset_completion;
+-      urb->status = -EINPROGRESS;
+-      urb->actual_length = 0;
+-      urb->transfer_flags = URB_DIR_IN;
+-      usb_get_urb(urb);
+-      atomic_inc(&urb->use_count);
+-      atomic_inc(&urb->dev->urbnum);
+-      urb->setup_dma = dma_map_single(
+-                      hcd->self.sysdev,
+-                      urb->setup_packet,
+-                      sizeof(struct usb_ctrlrequest),
+-                      DMA_TO_DEVICE);
+-      urb->transfer_dma = dma_map_single(
+-                      hcd->self.sysdev,
+-                      urb->transfer_buffer,
+-                      urb->transfer_buffer_length,
+-                      DMA_FROM_DEVICE);
+-      urb->context = done;
+-      return urb;
+-}
+-
+-static int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
+-{
+-      int retval = -ENOMEM;
+-      struct usb_ctrlrequest *dr;
+-      struct urb *urb;
+-      struct usb_device *udev;
+-      struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+-      struct usb_device_descriptor *buf;
+-      DECLARE_COMPLETION_ONSTACK(done);
+-
+-      /* Obtain udev of the rhub's child port */
+-      udev = usb_hub_find_child(hcd->self.root_hub, port);
+-      if (!udev) {
+-              ehci_err(ehci, "No device attached to the RootHub\n");
+-              return -ENODEV;
+-      }
+-      buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
+-      if (!buf)
+-              return -ENOMEM;
+-
+-      dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+-      if (!dr) {
+-              kfree(buf);
+-              return -ENOMEM;
+-      }
+-
+-      /* Fill Setup packet for GetDescriptor */
+-      dr->bRequestType = USB_DIR_IN;
+-      dr->bRequest = USB_REQ_GET_DESCRIPTOR;
+-      dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
+-      dr->wIndex = 0;
+-      dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
+-      urb = request_single_step_set_feature_urb(udev, dr, buf, &done);
+-      if (!urb)
+-              goto cleanup;
+-
+-      /* Submit just the SETUP stage */
+-      retval = submit_single_step_set_feature(hcd, urb, 1);
+-      if (retval)
+-              goto out1;
+-      if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
+-              usb_kill_urb(urb);
+-              retval = -ETIMEDOUT;
+-              ehci_err(ehci, "%s SETUP stage timed out on ep0\n", __func__);
+-              goto out1;
+-      }
+-      msleep(15 * 1000);
+-
+-      /* Complete remaining DATA and STATUS stages using the same URB */
+-      urb->status = -EINPROGRESS;
+-      usb_get_urb(urb);
+-      atomic_inc(&urb->use_count);
+-      atomic_inc(&urb->dev->urbnum);
+-      retval = submit_single_step_set_feature(hcd, urb, 0);
+-      if (!retval && !wait_for_completion_timeout(&done,
+-                                              msecs_to_jiffies(2000))) {
+-              usb_kill_urb(urb);
+-              retval = -ETIMEDOUT;
+-              ehci_err(ehci, "%s IN stage timed out on ep0\n", __func__);
+-      }
+-out1:
+-      usb_free_urb(urb);
+-cleanup:
+-      kfree(dr);
+-      kfree(buf);
+-      return retval;
+-}
+-#endif /* CONFIG_USB_HCD_TEST_MODE */
+-/*-------------------------------------------------------------------------*/
+ int ehci_hub_control(
+       struct usb_hcd  *hcd,
+--- a/drivers/usb/host/ehci-q.c
++++ b/drivers/usb/host/ehci-q.c
+@@ -1165,7 +1165,7 @@ submit_async (
+  * performed; TRUE - SETUP and FALSE - IN+STATUS
+  * Returns 0 if success
+  */
+-static int submit_single_step_set_feature(
++static int ehci_submit_single_step_set_feature(
+       struct usb_hcd  *hcd,
+       struct urb      *urb,
+       int             is_setup
+--- a/include/linux/usb/hcd.h
++++ b/include/linux/usb/hcd.h
+@@ -409,7 +409,10 @@ struct hc_driver {
+       int     (*find_raw_port_number)(struct usb_hcd *, int);
+       /* Call for power on/off the port if necessary */
+       int     (*port_power)(struct usb_hcd *hcd, int portnum, bool enable);
+-
++      /* Call for SINGLE_STEP_SET_FEATURE Test for USB2 EH certification */
++#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06
++      int     (*submit_single_step_set_feature)(struct usb_hcd *,
++                      struct urb *, int);
+ };
+ static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
+@@ -474,6 +477,14 @@ int usb_hcd_setup_local_mem(struct usb_h
+ struct platform_device;
+ extern void usb_hcd_platform_shutdown(struct platform_device *dev);
++#ifdef CONFIG_USB_HCD_TEST_MODE
++extern int ehset_single_step_set_feature(struct usb_hcd *hcd, int port);
++#else
++static inline int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
++{
++      return 0;
++}
++#endif /* CONFIG_USB_HCD_TEST_MODE */
+ #ifdef CONFIG_USB_PCI
+ struct pci_dev;
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0015-MLK-17380-4-usb-host-xhci-add-EH-SINGLE_STEP_SET_FEA.patch b/target/linux/layerscape/patches-5.4/820-usb-0015-MLK-17380-4-usb-host-xhci-add-EH-SINGLE_STEP_SET_FEA.patch
new file mode 100644 (file)
index 0000000..cec6a90
--- /dev/null
@@ -0,0 +1,203 @@
+From 6a313b6072925ab757688328b9f91b16d5a39bb3 Mon Sep 17 00:00:00 2001
+From: Peter Chen <peter.chen@nxp.com>
+Date: Fri, 9 Feb 2018 10:11:32 +0800
+Subject: [PATCH] MLK-17380-4 usb: host: xhci: add EH SINGLE_STEP_SET_FEATURE
+ Test for USB2
+
+This function is similar with EHCI's, but implemented using XHCI.
+The USB2 host needs to send SETUP packet first, then wait 15
+seconds before DATA (IN) + STATUS stage.
+
+It is needed at USB Certification test for Embedded Host 2.0, and
+the detail is at CH6.4.1.1 of On-The-Go and Embedded Host Supplement
+to the USB Revision 2.0 Specification
+
+Acked-by: Jun Li <jun.li@nxp.com>
+Signed-off-by: Peter Chen <peter.chen@nxp.com>
+(cherry picked from commit 8d46e3bca527a5d899446d3858274fb5cbab1a1e)
+---
+ drivers/usb/host/xhci-hub.c  |   9 ++++
+ drivers/usb/host/xhci-ring.c | 123 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/usb/host/xhci.c      |   1 +
+ drivers/usb/host/xhci.h      |  10 ++++
+ 4 files changed, 143 insertions(+)
+
+--- a/drivers/usb/host/xhci-hub.c
++++ b/drivers/usb/host/xhci-hub.c
+@@ -1378,6 +1378,15 @@ int xhci_hub_control(struct usb_hcd *hcd
+                       /* 4.19.6 Port Test Modes (USB2 Test Mode) */
+                       if (hcd->speed != HCD_USB2)
+                               goto error;
++#ifdef CONFIG_USB_HCD_TEST_MODE
++                      if (test_mode == EHSET_TEST_SINGLE_STEP_SET_FEATURE) {
++                              spin_unlock_irqrestore(&xhci->lock, flags);
++                              retval = ehset_single_step_set_feature(hcd,
++                                                              wIndex + 1);
++                              spin_lock_irqsave(&xhci->lock, flags);
++                              break;
++                      }
++#endif
+                       if (test_mode > TEST_FORCE_EN || test_mode < TEST_J)
+                               goto error;
+                       retval = xhci_enter_test_mode(xhci, test_mode, wIndex,
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -3545,6 +3545,129 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *
+       return 0;
+ }
++#ifdef CONFIG_USB_HCD_TEST_MODE
++/*
++ * This function prepare TRBs and submits them for the
++ * SINGLE_STEP_SET_FEATURE Test.
++ * This is done in two parts: first SETUP req for GetDesc is sent then
++ * 15 seconds later, the IN stage for GetDesc starts to req data from dev
++ *
++ * is_setup : argument decides which of the two stage needs to be
++ * performed; TRUE - SETUP and FALSE - IN+STATUS
++ * Returns 0 if success
++ */
++int xhci_submit_single_step_set_feature(struct usb_hcd *hcd,
++      struct urb *urb, int is_setup)
++{
++      int slot_id;
++      unsigned int ep_index;
++      struct xhci_ring *ep_ring;
++      int ret;
++      struct usb_ctrlrequest *setup;
++      struct xhci_generic_trb *start_trb;
++      int start_cycle;
++      u32 field, length_field, remainder;
++      struct urb_priv *urb_priv;
++      struct xhci_td *td;
++      struct xhci_hcd *xhci = hcd_to_xhci(hcd);
++
++      /* urb_priv will be free after transcation has completed */
++      urb_priv = kzalloc(sizeof(struct urb_priv) +
++                      sizeof(struct xhci_td), GFP_KERNEL);
++      if (!urb_priv)
++              return -ENOMEM;
++
++      td = &urb_priv->td[0];
++      urb_priv->num_tds = 1;
++      urb_priv->num_tds_done = 0;
++      urb->hcpriv = urb_priv;
++
++      ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
++      if (!ep_ring) {
++              ret = -EINVAL;
++              goto free_priv;
++      }
++
++      slot_id = urb->dev->slot_id;
++      ep_index = xhci_get_endpoint_index(&urb->ep->desc);
++
++      setup = (struct usb_ctrlrequest *) urb->setup_packet;
++      if (is_setup) {
++              ret = prepare_transfer(xhci, xhci->devs[slot_id],
++                              ep_index, urb->stream_id,
++                              1, urb, 0, GFP_KERNEL);
++              if (ret < 0)
++                      goto free_priv;
++
++              start_trb = &ep_ring->enqueue->generic;
++              start_cycle = ep_ring->cycle_state;
++              /* Save the DMA address of the last TRB in the TD */
++              td->last_trb = ep_ring->enqueue;
++              field = TRB_IOC | TRB_IDT | TRB_TYPE(TRB_SETUP) | start_cycle;
++              /* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */
++              if ((xhci->hci_version >= 0x100) ||
++                              (xhci->quirks & XHCI_MTK_HOST))
++                      field |= TRB_TX_TYPE(TRB_DATA_IN);
++
++              queue_trb(xhci, ep_ring, false,
++                        setup->bRequestType | setup->bRequest << 8 |
++                        le16_to_cpu(setup->wValue) << 16,
++                        le16_to_cpu(setup->wIndex) |
++                        le16_to_cpu(setup->wLength) << 16,
++                        TRB_LEN(8) | TRB_INTR_TARGET(0),
++                        /* Immediate data in pointer */
++                        field);
++              giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
++                              start_cycle, start_trb);
++              return 0;
++      }
++
++      ret = prepare_transfer(xhci, xhci->devs[slot_id],
++                      ep_index, urb->stream_id,
++                      2, urb, 0, GFP_KERNEL);
++      if (ret < 0)
++              goto free_priv;
++
++      start_trb = &ep_ring->enqueue->generic;
++      start_cycle = ep_ring->cycle_state;
++      field = TRB_ISP | TRB_TYPE(TRB_DATA);
++
++      remainder = xhci_td_remainder(xhci, 0,
++                                 urb->transfer_buffer_length,
++                                 urb->transfer_buffer_length,
++                                 urb, 1);
++
++      length_field = TRB_LEN(urb->transfer_buffer_length) |
++              TRB_TD_SIZE(remainder) |
++              TRB_INTR_TARGET(0);
++
++      if (urb->transfer_buffer_length > 0) {
++              field |= TRB_DIR_IN;
++              queue_trb(xhci, ep_ring, true,
++                              lower_32_bits(urb->transfer_dma),
++                              upper_32_bits(urb->transfer_dma),
++                              length_field,
++                              field | ep_ring->cycle_state);
++      }
++
++      td->last_trb = ep_ring->enqueue;
++      field = TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state;
++      queue_trb(xhci, ep_ring, false,
++                      0,
++                      0,
++                      TRB_INTR_TARGET(0),
++                      field);
++
++      giveback_first_trb(xhci, slot_id, ep_index, 0,
++                      start_cycle, start_trb);
++
++      return 0;
++free_priv:
++      xhci_urb_free_priv(urb_priv);
++      return ret;
++}
++#endif /* CONFIG_USB_HCD_TEST_MODE */
++
+ /*
+  * The transfer burst count field of the isochronous TRB defines the number of
+  * bursts that are required to move all packets in this TD.  Only SuperSpeed
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -5352,6 +5352,7 @@ static const struct hc_driver xhci_hc_dr
+       .disable_usb3_lpm_timeout =     xhci_disable_usb3_lpm_timeout,
+       .find_raw_port_number = xhci_find_raw_port_number,
+       .clear_tt_buffer_complete = xhci_clear_tt_buffer_complete,
++      .submit_single_step_set_feature = xhci_submit_single_step_set_feature,
+ };
+ void xhci_init_driver(struct hc_driver *drv,
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -2141,6 +2141,16 @@ int xhci_find_raw_port_number(struct usb
+ struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd);
+ void xhci_hc_died(struct xhci_hcd *xhci);
++#ifdef CONFIG_USB_HCD_TEST_MODE
++int xhci_submit_single_step_set_feature(struct usb_hcd *hcd,
++      struct urb *urb, int is_setup);
++#else
++static inline int xhci_submit_single_step_set_feature(struct usb_hcd *hcd,
++      struct urb *urb, int is_setup)
++{
++      return 0;
++}
++#endif
+ #ifdef CONFIG_PM
+ int xhci_bus_suspend(struct usb_hcd *hcd);
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0016-MLK-16735-usb-host-add-XHCI_CDNS_HOST-flag.patch b/target/linux/layerscape/patches-5.4/820-usb-0016-MLK-16735-usb-host-add-XHCI_CDNS_HOST-flag.patch
new file mode 100644 (file)
index 0000000..f21f700
--- /dev/null
@@ -0,0 +1,42 @@
+From a9f1d7994a9f8a38fdace19454ef031244e24e5e Mon Sep 17 00:00:00 2001
+From: Peter Chen <peter.chen@nxp.com>
+Date: Thu, 9 Nov 2017 16:58:40 +0800
+Subject: [PATCH] MLK-16735 usb: host: add XHCI_CDNS_HOST flag
+
+The NXP Cadence XHCI host has the same issue with Intel's,
+it is triggered by reboot test, the test case is described
+at this jira ticket.
+
+BuildInfo:
+- SCFW 8dcff26, IMX-MKIMAGE ea027c4b, ATF
+- U-Boot 2017.03-imx_v2017.03_4.9.51_imx8_beta1+g6dc7b0f
+
+Acked-by: Jun Li <jun.li@nxp.com>
+Signed-off-by: Peter Chen <peter.chen@nxp.com>
+(cherry picked from commit 5e353132931b9dc6e05f6bea1281ae35dd6a59d8)
+---
+ drivers/usb/host/xhci.c | 2 +-
+ drivers/usb/host/xhci.h | 1 +
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -193,7 +193,7 @@ int xhci_reset(struct xhci_hcd *xhci)
+        * Without this delay, the subsequent HC register access,
+        * may result in a system hang very rarely.
+        */
+-      if (xhci->quirks & XHCI_INTEL_HOST)
++      if (xhci->quirks & (XHCI_INTEL_HOST | XHCI_CDNS_HOST))
+               udelay(1000);
+       ret = xhci_handshake(&xhci->op_regs->command,
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1872,6 +1872,7 @@ struct xhci_hcd {
+ #define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33)
+ #define XHCI_RESET_PLL_ON_DISCONNECT  BIT_ULL(34)
+ #define XHCI_SNPS_BROKEN_SUSPEND    BIT_ULL(35)
++#define XHCI_CDNS_HOST                BIT_ULL(36)
+       unsigned int            num_active_eps;
+       unsigned int            limit_active_eps;
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0017-MLK-19153-2-usb-host-xhci-do-not-return-error-status.patch b/target/linux/layerscape/patches-5.4/820-usb-0017-MLK-19153-2-usb-host-xhci-do-not-return-error-status.patch
new file mode 100644 (file)
index 0000000..ba95233
--- /dev/null
@@ -0,0 +1,39 @@
+From c1f9fa8de2548172a69f35aeb6a43daedac7cb30 Mon Sep 17 00:00:00 2001
+From: Peter Chen <peter.chen@nxp.com>
+Date: Mon, 5 Mar 2018 09:13:26 +0800
+Subject: [PATCH] MLK-19153-2 usb: host: xhci: do not return error status for
+ URB
+
+Current XHCI implementation does not consider completion interrupt
+for SETUP packet standalone, so it will show warning message
+and return error status for URB. In fact, it can support it. In
+this commit, we change warning message as debug message and set
+status as zero for URB.
+
+Support completion interrupt for SETUP packet is needed for USB EH2.0
+SINGLE_STEP_SET_FEATURE Test.
+
+Acked-by: Jun Li <jun.li@nxp.com>
+Signed-off-by: Peter Chen <peter.chen@nxp.com>
+(cherry picked from commit 78b212e8c2e083f513610efdff60b58c986381de)
+---
+ drivers/usb/host/xhci-ring.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -2027,12 +2027,9 @@ static int process_ctrl_td(struct xhci_h
+       switch (trb_comp_code) {
+       case COMP_SUCCESS:
+-              if (trb_type != TRB_STATUS) {
+-                      xhci_warn(xhci, "WARN: Success on ctrl %s TRB without IOC set?\n",
++              if (trb_type != TRB_STATUS)
++                      xhci_dbg(xhci, "Success on ctrl %s TRB without IOC set?\n",
+                                 (trb_type == TRB_DATA) ? "data" : "setup");
+-                      *status = -ESHUTDOWN;
+-                      break;
+-              }
+               *status = 0;
+               break;
+       case COMP_SHORT_PACKET:
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0018-MLK-18794-1-usb-host-xhci-add-.bus_suspend-override.patch b/target/linux/layerscape/patches-5.4/820-usb-0018-MLK-18794-1-usb-host-xhci-add-.bus_suspend-override.patch
new file mode 100644 (file)
index 0000000..c5f59a3
--- /dev/null
@@ -0,0 +1,45 @@
+From b5c498026a95f9d80be23711dd6c178cc78d6c33 Mon Sep 17 00:00:00 2001
+From: Peter Chen <peter.chen@nxp.com>
+Date: Wed, 15 Aug 2018 14:59:55 +0800
+Subject: [PATCH] MLK-18794-1 usb: host: xhci: add .bus_suspend override
+
+Some platforms (eg: Cadence USB3) have special requirements to add
+platform USB register setting between xhci_bus_suspend and
+platform USB controller suspend routine. Eg, The Cadence USB3 needs
+RX detect clock switch from 24Mhz to 32Khz within 100ms after set
+port to U3, but sometimes, for USB3 HUB connection, the USB2
+bus suspend will cost more than 100ms, and introduce the disconnection
+before the PHY enters low power mode, then the state is in mess from
+controller side.
+
+So in this commit, we introduce .bus_suspend for xhci_driver_overrides
+for above use cases.
+
+Signed-off-by: Peter Chen <peter.chen@nxp.com>
+(cherry picked from commit f6baa57913ceb40da14a945820cb87e8d6ceb7c7)
+---
+ drivers/usb/host/xhci.c | 2 ++
+ drivers/usb/host/xhci.h | 1 +
+ 2 files changed, 3 insertions(+)
+
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -5369,6 +5369,8 @@ void xhci_init_driver(struct hc_driver *
+                       drv->reset = over->reset;
+               if (over->start)
+                       drv->start = over->start;
++              if (over->bus_suspend)
++                      drv->bus_suspend = over->bus_suspend;
+       }
+ }
+ EXPORT_SYMBOL_GPL(xhci_init_driver);
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1910,6 +1910,7 @@ struct xhci_driver_overrides {
+       size_t extra_priv_size;
+       int (*reset)(struct usb_hcd *hcd);
+       int (*start)(struct usb_hcd *hcd);
++      int (*bus_suspend)(struct usb_hcd *hcd);
+ };
+ #define       XHCI_CFC_DELAY          10
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0019-MLK-9829-usb-core-print-suggested-message-if-failed-.patch b/target/linux/layerscape/patches-5.4/820-usb-0019-MLK-9829-usb-core-print-suggested-message-if-failed-.patch
new file mode 100644 (file)
index 0000000..3f7d385
--- /dev/null
@@ -0,0 +1,32 @@
+From 9b297faabe3fc35741746aca39128fbb12e28113 Mon Sep 17 00:00:00 2001
+From: Li Jun <b47624@freescale.com>
+Date: Wed, 12 Nov 2014 15:16:33 +0800
+Subject: [PATCH] MLK-9829 usb: core: print suggested message if failed to get
+ device descriptor
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This is required for USB OTG and EH compliance test 6.7.22(A-UUT “Device No
+Response” for connection timeout). When the connected usb device(PET) does
+not response to transactions, host will fail to get device descriptor.
+
+Signed-off-by: Li Jun <jun.li@freescale.com>
+(cherry picked from commit 86d0bd661ecbbdf97dd9a8ddbaf0d3811de7f39e)
+(cherry picked from commit 858af83637291d2ececfc7b2b4b17e3a371b53f3)
+---
+ drivers/usb/core/hub.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -4716,7 +4716,8 @@ hub_port_init(struct usb_hub *hub, struc
+                       }
+                       if (r) {
+                               if (r != -ENODEV)
+-                                      dev_err(&udev->dev, "device descriptor read/64, error %d\n",
++                                      dev_err(&udev->dev,
++                                              "device no response, device descriptor read/64, error %d\n",
+                                                       r);
+                               retval = -EMSGSIZE;
+                               continue;
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0020-MLK-16604-1-usb-host-xhci-plat-add-XHCI_MISSING_CAS-.patch b/target/linux/layerscape/patches-5.4/820-usb-0020-MLK-16604-1-usb-host-xhci-plat-add-XHCI_MISSING_CAS-.patch
new file mode 100644 (file)
index 0000000..ff15031
--- /dev/null
@@ -0,0 +1,29 @@
+From 0767542941c535ebb156087593426bb1fb25e967 Mon Sep 17 00:00:00 2001
+From: Li Jun <jun.li@nxp.com>
+Date: Tue, 28 Nov 2017 21:43:18 +0800
+Subject: [PATCH] MLK-16604-1 usb: host: xhci-plat: add XHCI_MISSING_CAS quirk
+
+i.MX8MQ USB3 host needs XHCI_MISSING_CAS quirk to warm reset the port to
+enum the USB3 device plugged in while system sleep, as the port state is
+stuck in polling mode after resume.
+
+Signed-off-by: Li Jun <jun.li@nxp.com>
+Acked-by: Peter Chen <peter.chen@nxp.com>
+(cherry picked from commit 9f1f4316775a061d3ad46c63f84a377e2ffd015d)
+---
+ drivers/usb/host/xhci-plat.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/usb/host/xhci-plat.c
++++ b/drivers/usb/host/xhci-plat.c
+@@ -291,6 +291,10 @@ static int xhci_plat_probe(struct platfo
+               device_property_read_u32(tmpdev, "imod-interval-ns",
+                                        &xhci->imod_interval);
++
++              if (device_property_read_bool(tmpdev,
++                                            "usb3-resume-missing-cas"))
++                      xhci->quirks |= XHCI_MISSING_CAS;
+       }
+       hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, "usb-phy", 0);
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0021-MLK-22099-usb-host-xhci-do-warm-reset-for-link-state.patch b/target/linux/layerscape/patches-5.4/820-usb-0021-MLK-22099-usb-host-xhci-do-warm-reset-for-link-state.patch
new file mode 100644 (file)
index 0000000..18c9401
--- /dev/null
@@ -0,0 +1,28 @@
+From 6921c206918a2bd9882bbf77211d37a063233d95 Mon Sep 17 00:00:00 2001
+From: Li Jun <jun.li@nxp.com>
+Date: Thu, 8 Aug 2019 16:13:40 +0800
+Subject: [PATCH] MLK-22099 usb: host: xhci: do warm reset for link state
+ rxdect
+
+As some USB3 port will lose link state while system sleep, then
+the link state will be at rxdect after resume, we need a warm
+reset to bring it back, so add the rxdect condition for CAS
+missing.
+
+Signed-off-by: Li Jun <jun.li@nxp.com>
+---
+ drivers/usb/host/xhci-hub.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/xhci-hub.c
++++ b/drivers/usb/host/xhci-hub.c
+@@ -1682,7 +1682,8 @@ static bool xhci_port_missing_cas_quirk(
+               return false;
+       if (((portsc & PORT_PLS_MASK) != XDEV_POLLING) &&
+-          ((portsc & PORT_PLS_MASK) != XDEV_COMP_MODE))
++          ((portsc & PORT_PLS_MASK) != XDEV_COMP_MODE) &&
++          ((portsc & PORT_PLS_MASK) != XDEV_RXDETECT))
+               return false;
+       /* clear wakeup/change bits, and do a warm port reset */
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0022-usb-fsl-Remove-unused-variable.patch b/target/linux/layerscape/patches-5.4/820-usb-0022-usb-fsl-Remove-unused-variable.patch
new file mode 100644 (file)
index 0000000..9d8c8ba
--- /dev/null
@@ -0,0 +1,44 @@
+From 7dc31f24c77d41660047ea0dcddbe33ae1d819ee Mon Sep 17 00:00:00 2001
+From: Nikhil Badola <nikhil.badola@freescale.com>
+Date: Mon, 11 May 2015 13:19:09 +0530
+Subject: [PATCH] usb: fsl: Remove unused variable
+
+Remove unused variable td_complete
+
+Signed-off-by: Nikhil Badola <nikhil.badola@freescale.com>
+Reviewed-by: Ran Wang <ran.wang_1@nxp.com>
+Reviewed-by: Peter Chen <peter.chen@nxp.com>
+---
+ drivers/usb/gadget/udc/fsl_udc_core.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+--- a/drivers/usb/gadget/udc/fsl_udc_core.c
++++ b/drivers/usb/gadget/udc/fsl_udc_core.c
+@@ -1595,14 +1595,13 @@ static int process_ep_req(struct fsl_udc
+               struct fsl_req *curr_req)
+ {
+       struct ep_td_struct *curr_td;
+-      int     td_complete, actual, remaining_length, j, tmp;
++      int     actual, remaining_length, j, tmp;
+       int     status = 0;
+       int     errors = 0;
+       struct  ep_queue_head *curr_qh = &udc->ep_qh[pipe];
+       int direction = pipe % 2;
+       curr_td = curr_req->head;
+-      td_complete = 0;
+       actual = curr_req->req.length;
+       for (j = 0; j < curr_req->dtd_count; j++) {
+@@ -1647,11 +1646,9 @@ static int process_ep_req(struct fsl_udc
+                               status = -EPROTO;
+                               break;
+                       } else {
+-                              td_complete++;
+                               break;
+                       }
+               } else {
+-                      td_complete++;
+                       VDBG("dTD transmitted successful");
+               }
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0023-usb-gadget-Correct-NULL-pointer-checking-in-fsl-gadg.patch b/target/linux/layerscape/patches-5.4/820-usb-0023-usb-gadget-Correct-NULL-pointer-checking-in-fsl-gadg.patch
new file mode 100644 (file)
index 0000000..1195dc5
--- /dev/null
@@ -0,0 +1,31 @@
+From 56c801e09a2b8fdc8f4ec889d7a9cec57d55f545 Mon Sep 17 00:00:00 2001
+From: Nikhil Badola <nikhil.badola@freescale.com>
+Date: Tue, 9 Jun 2015 16:47:17 +0530
+Subject: [PATCH] usb: gadget: Correct NULL pointer checking in fsl gadget
+
+Correct NULL pointer checking for endpoint descriptor
+before it gets dereferenced
+
+Signed-off-by: Nikhil Badola <nikhil.badola@freescale.com>
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+Reviewed-by: Peter Chen <peter.chen@nxp.com>
+---
+ drivers/usb/gadget/udc/fsl_udc_core.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/gadget/udc/fsl_udc_core.c
++++ b/drivers/usb/gadget/udc/fsl_udc_core.c
+@@ -1052,10 +1052,11 @@ static int fsl_ep_fifo_status(struct usb
+       u32 bitmask;
+       struct ep_queue_head *qh;
+-      ep = container_of(_ep, struct fsl_ep, ep);
+-      if (!_ep || (!ep->ep.desc && ep_index(ep) != 0))
++      if (!_ep || _ep->desc || !(_ep->desc->bEndpointAddress&0xF))
+               return -ENODEV;
++      ep = container_of(_ep, struct fsl_ep, ep);
++
+       udc = (struct fsl_udc *)ep->udc;
+       if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0024-LF-387-1-Revert-usb-dwc3-Add-cache-type-configuratio.patch b/target/linux/layerscape/patches-5.4/820-usb-0024-LF-387-1-Revert-usb-dwc3-Add-cache-type-configuratio.patch
new file mode 100644 (file)
index 0000000..47e4bfc
--- /dev/null
@@ -0,0 +1,123 @@
+From d408e9c29dd580cb94e39da2b0eef81061d22061 Mon Sep 17 00:00:00 2001
+From: Ran Wang <ran.wang_1@nxp.com>
+Date: Thu, 19 Dec 2019 17:02:36 +0800
+Subject: [PATCH] LF-387-1 Revert "usb: dwc3: Add cache type configuration
+ support"
+
+This reverts commit ebceaf435cc96892d22b334b2a6517374c0d6a6e.
+Will use next version patch to replace this.
+
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+---
+ drivers/usb/dwc3/core.c | 61 +++++--------------------------------------------
+ drivers/usb/dwc3/core.h | 15 ------------
+ 2 files changed, 6 insertions(+), 70 deletions(-)
+
+--- a/drivers/usb/dwc3/core.c
++++ b/drivers/usb/dwc3/core.c
+@@ -913,54 +913,6 @@ static void dwc3_set_power_down_clk_scal
+       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ }
+-#ifdef CONFIG_OF
+-struct dwc3_cache_type {
+-      u8 transfer_type_datard;
+-      u8 transfer_type_descrd;
+-      u8 transfer_type_datawr;
+-      u8 transfer_type_descwr;
+-};
+-
+-static const struct dwc3_cache_type layerscape_dwc3_cache_type = {
+-      .transfer_type_datard = 2,
+-      .transfer_type_descrd = 2,
+-      .transfer_type_datawr = 2,
+-      .transfer_type_descwr = 2,
+-};
+-
+-/**
+- * dwc3_set_cache_type - Configure cache type registers
+- * @dwc: Pointer to our controller context structure
+- */
+-static void dwc3_set_cache_type(struct dwc3 *dwc)
+-{
+-      u32 tmp, reg;
+-      const struct dwc3_cache_type *cache_type =
+-              device_get_match_data(dwc->dev);
+-
+-      if (cache_type) {
+-              reg = dwc3_readl(dwc->regs,  DWC3_GSBUSCFG0);
+-              tmp = reg;
+-
+-              reg &= ~DWC3_GSBUSCFG0_DATARD(~0);
+-              reg |= DWC3_GSBUSCFG0_DATARD(cache_type->transfer_type_datard);
+-
+-              reg &= ~DWC3_GSBUSCFG0_DESCRD(~0);
+-              reg |= DWC3_GSBUSCFG0_DESCRD(cache_type->transfer_type_descrd);
+-
+-              reg &= ~DWC3_GSBUSCFG0_DATAWR(~0);
+-              reg |= DWC3_GSBUSCFG0_DATAWR(cache_type->transfer_type_datawr);
+-
+-              reg &= ~DWC3_GSBUSCFG0_DESCWR(~0);
+-              reg |= DWC3_GSBUSCFG0_DESCWR(cache_type->transfer_type_descwr);
+-
+-              if (tmp != reg)
+-                      dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, reg);
+-      }
+-}
+-#endif
+-
+-
+ /**
+  * dwc3_core_init - Low-level initialization of DWC3 Core
+  * @dwc: Pointer to our controller context structure
+@@ -1021,10 +973,6 @@ static int dwc3_core_init(struct dwc3 *d
+       dwc3_set_incr_burst_type(dwc);
+-#ifdef CONFIG_OF
+-      dwc3_set_cache_type(dwc);
+-#endif
+-
+       usb_phy_set_suspend(dwc->usb2_phy, 0);
+       usb_phy_set_suspend(dwc->usb3_phy, 0);
+       ret = phy_power_on(dwc->usb2_generic_phy);
+@@ -1942,9 +1890,12 @@ static const struct dev_pm_ops dwc3_dev_
+ #ifdef CONFIG_OF
+ static const struct of_device_id of_dwc3_match[] = {
+-      { .compatible = "fsl,layerscape-dwc3", .data = &layerscape_dwc3_cache_type, },
+-      { .compatible = "snps,dwc3" },
+-      { .compatible = "synopsys,dwc3" },
++      {
++              .compatible = "snps,dwc3"
++      },
++      {
++              .compatible = "synopsys,dwc3"
++      },
+       { },
+ };
+ MODULE_DEVICE_TABLE(of, of_dwc3_match);
+--- a/drivers/usb/dwc3/core.h
++++ b/drivers/usb/dwc3/core.h
+@@ -166,21 +166,6 @@
+ /* Bit fields */
+ /* Global SoC Bus Configuration INCRx Register 0 */
+-#ifdef CONFIG_OF
+-#define DWC3_GSBUSCFG0_DATARD_SHIFT   28
+-#define DWC3_GSBUSCFG0_DATARD(n)      (((n) & 0xf)            \
+-                      << DWC3_GSBUSCFG0_DATARD_SHIFT)
+-#define DWC3_GSBUSCFG0_DESCRD_SHIFT   24
+-#define DWC3_GSBUSCFG0_DESCRD(n)      (((n) & 0xf)            \
+-                      << DWC3_GSBUSCFG0_DESCRD_SHIFT)
+-#define DWC3_GSBUSCFG0_DATAWR_SHIFT   20
+-#define DWC3_GSBUSCFG0_DATAWR(n)      (((n) & 0xf)            \
+-                      << DWC3_GSBUSCFG0_DATAWR_SHIFT)
+-#define DWC3_GSBUSCFG0_DESCWR_SHIFT   16
+-#define DWC3_GSBUSCFG0_DESCWR(n)      (((n) & 0xf)            \
+-                      << DWC3_GSBUSCFG0_DESCWR_SHIFT)
+-#endif
+-
+ #define DWC3_GSBUSCFG0_INCR256BRSTENA (1 << 7) /* INCR256 burst */
+ #define DWC3_GSBUSCFG0_INCR128BRSTENA (1 << 6) /* INCR128 burst */
+ #define DWC3_GSBUSCFG0_INCR64BRSTENA  (1 << 5) /* INCR64 burst */
diff --git a/target/linux/layerscape/patches-5.4/820-usb-0025-LF-387-4-usb-dwc3-Add-cache-type-configuration-suppo.patch b/target/linux/layerscape/patches-5.4/820-usb-0025-LF-387-4-usb-dwc3-Add-cache-type-configuration-suppo.patch
new file mode 100644 (file)
index 0000000..4f6df78
--- /dev/null
@@ -0,0 +1,157 @@
+From cda32ee78d8b448bcbfc8e3d55dc04d809657ce2 Mon Sep 17 00:00:00 2001
+From: Ran Wang <ran.wang_1@nxp.com>
+Date: Wed, 20 Nov 2019 14:09:23 +0800
+Subject: [PATCH] LF-387-4 usb: dwc3: Add cache type configuration support
+
+This feature is telling how to configure cache type on 4 different
+transfer types: Data Read, Desc Read, Data Write and Desc write. For each
+treasfer type, controller has a 4-bit register field to enable different
+cache type. Quoted from DWC3 data book Table 6-5 Cache Type Bit Assignments:
+----------------------------------------------------------------
+MBUS_TYPE| bit[3]       |bit[2]       |bit[1]     |bit[0]
+----------------------------------------------------------------
+AHB      |Cacheable     |Bufferable   |Privilegge |Data
+AXI3     |Write Allocate|Read Allocate|Cacheable  |Bufferable
+AXI4     |Allocate Other|Allocate     |Modifiable |Bufferable
+AXI4     |Other Allocate|Allocate     |Modifiable |Bufferable
+Native   |Same as AXI   |Same as AXI  |Same as AXI|Same as AXI
+----------------------------------------------------------------
+Note: The AHB, AXI3, AXI4, and PCIe busses use different names for certain
+signals, which have the same meaning:
+  Bufferable = Posted
+  Cacheable = Modifiable = Snoop (negation of No Snoop)
+
+In most cases, driver support is not required unless the default values of
+registers are not correct *and* DWC3 node has enabled dma-coherent. So far we
+have observed USB device detect failure on some Layerscape platforms if this
+programming was not applied.
+
+Related struct:
+struct dwc3_cache_type {
+       u8 transfer_type_datard;
+       u8 transfer_type_descrd;
+       u8 transfer_type_datawr;
+       u8 transfer_type_descwr;
+};
+
+Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
+Reviewed-by: Jun Li <jun.li@nxp.com>
+---
+ drivers/usb/dwc3/core.c | 67 ++++++++++++++++++++++++++++++++++++++++++++-----
+ drivers/usb/dwc3/core.h | 15 +++++++++++
+ 2 files changed, 76 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/dwc3/core.c
++++ b/drivers/usb/dwc3/core.c
+@@ -913,6 +913,53 @@ static void dwc3_set_power_down_clk_scal
+       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ }
++#ifdef CONFIG_OF
++struct dwc3_cache_type {
++      u8 transfer_type_datard;
++      u8 transfer_type_descrd;
++      u8 transfer_type_datawr;
++      u8 transfer_type_descwr;
++};
++
++static const struct dwc3_cache_type ls1088a_dwc3_cache_type = {
++      .transfer_type_datard = 2,
++      .transfer_type_descrd = 2,
++      .transfer_type_datawr = 2,
++      .transfer_type_descwr = 2,
++};
++
++/**
++ * dwc3_set_cache_type - Configure cache type registers
++ * @dwc: Pointer to our controller context structure
++ */
++static void dwc3_set_cache_type(struct dwc3 *dwc)
++{
++      u32 tmp, reg;
++      const struct dwc3_cache_type *cache_type =
++              device_get_match_data(dwc->dev);
++
++      if (cache_type) {
++              reg = dwc3_readl(dwc->regs,  DWC3_GSBUSCFG0);
++              tmp = reg;
++
++              reg &= ~DWC3_GSBUSCFG0_DATARD(~0);
++              reg |= DWC3_GSBUSCFG0_DATARD(cache_type->transfer_type_datard);
++
++              reg &= ~DWC3_GSBUSCFG0_DESCRD(~0);
++              reg |= DWC3_GSBUSCFG0_DESCRD(cache_type->transfer_type_descrd);
++
++              reg &= ~DWC3_GSBUSCFG0_DATAWR(~0);
++              reg |= DWC3_GSBUSCFG0_DATAWR(cache_type->transfer_type_datawr);
++
++              reg &= ~DWC3_GSBUSCFG0_DESCWR(~0);
++              reg |= DWC3_GSBUSCFG0_DESCWR(cache_type->transfer_type_descwr);
++
++              if (tmp != reg)
++                      dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, reg);
++      }
++}
++#endif
++
+ /**
+  * dwc3_core_init - Low-level initialization of DWC3 Core
+  * @dwc: Pointer to our controller context structure
+@@ -973,6 +1020,10 @@ static int dwc3_core_init(struct dwc3 *d
+       dwc3_set_incr_burst_type(dwc);
++#ifdef CONFIG_OF
++      dwc3_set_cache_type(dwc);
++#endif
++
+       usb_phy_set_suspend(dwc->usb2_phy, 0);
+       usb_phy_set_suspend(dwc->usb3_phy, 0);
+       ret = phy_power_on(dwc->usb2_generic_phy);
+@@ -1890,12 +1941,16 @@ static const struct dev_pm_ops dwc3_dev_
+ #ifdef CONFIG_OF
+ static const struct of_device_id of_dwc3_match[] = {
+-      {
+-              .compatible = "snps,dwc3"
+-      },
+-      {
+-              .compatible = "synopsys,dwc3"
+-      },
++      { .compatible = "fsl,ls1012a-dwc3", .data = &ls1088a_dwc3_cache_type, },
++      { .compatible = "fsl,ls1021a-dwc3", .data = &ls1088a_dwc3_cache_type, },
++      { .compatible = "fsl,ls1028a-dwc3", .data = &ls1088a_dwc3_cache_type, },
++      { .compatible = "fsl,ls1043a-dwc3", .data = &ls1088a_dwc3_cache_type, },
++      { .compatible = "fsl,ls1046a-dwc3", .data = &ls1088a_dwc3_cache_type, },
++      { .compatible = "fsl,ls1088a-dwc3", .data = &ls1088a_dwc3_cache_type, },
++      { .compatible = "fsl,ls2088a-dwc3", .data = &ls1088a_dwc3_cache_type, },
++      { .compatible = "fsl,lx2160a-dwc3", .data = &ls1088a_dwc3_cache_type, },
++      { .compatible = "snps,dwc3" },
++      { .compatible = "synopsys,dwc3" },
+       { },
+ };
+ MODULE_DEVICE_TABLE(of, of_dwc3_match);
+--- a/drivers/usb/dwc3/core.h
++++ b/drivers/usb/dwc3/core.h
+@@ -166,6 +166,21 @@
+ /* Bit fields */
+ /* Global SoC Bus Configuration INCRx Register 0 */
++#ifdef CONFIG_OF
++#define DWC3_GSBUSCFG0_DATARD_SHIFT   28
++#define DWC3_GSBUSCFG0_DATARD(n)      (((n) & 0xf)            \
++                      << DWC3_GSBUSCFG0_DATARD_SHIFT)
++#define DWC3_GSBUSCFG0_DESCRD_SHIFT   24
++#define DWC3_GSBUSCFG0_DESCRD(n)      (((n) & 0xf)            \
++                      << DWC3_GSBUSCFG0_DESCRD_SHIFT)
++#define DWC3_GSBUSCFG0_DATAWR_SHIFT   20
++#define DWC3_GSBUSCFG0_DATAWR(n)      (((n) & 0xf)            \
++                      << DWC3_GSBUSCFG0_DATAWR_SHIFT)
++#define DWC3_GSBUSCFG0_DESCWR_SHIFT   16
++#define DWC3_GSBUSCFG0_DESCWR(n)      (((n) & 0xf)            \
++                      << DWC3_GSBUSCFG0_DESCWR_SHIFT)
++#endif
++
+ #define DWC3_GSBUSCFG0_INCR256BRSTENA (1 << 7) /* INCR256 burst */
+ #define DWC3_GSBUSCFG0_INCR128BRSTENA (1 << 6) /* INCR128 burst */
+ #define DWC3_GSBUSCFG0_INCR64BRSTENA  (1 << 5) /* INCR64 burst */
diff --git a/target/linux/layerscape/patches-5.4/821-vfio-0001-vfio-fsl-mc-Add-VFIO-framework-skeleton-for-fsl-mc-d.patch b/target/linux/layerscape/patches-5.4/821-vfio-0001-vfio-fsl-mc-Add-VFIO-framework-skeleton-for-fsl-mc-d.patch
new file mode 100644 (file)
index 0000000..5dc86f7
--- /dev/null
@@ -0,0 +1,252 @@
+From 8b9efd00727523c56eb9d17ad42338b6090b4b8e Mon Sep 17 00:00:00 2001
+From: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Date: Fri, 12 May 2017 10:27:07 +0530
+Subject: [PATCH] vfio/fsl-mc: Add VFIO framework skeleton for fsl-mc devices
+
+This patch adds the infrastructure for VFIO support for fsl-mc
+devices. Subsequent patches will add support for binding and secure
+assigning these devices using VFIO.
+
+FSL-MC is a new bus (driver/bus/fsl-mc/) which is different
+from PCI and Platform bus.
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ drivers/vfio/Kconfig                      |   1 +
+ drivers/vfio/Makefile                     |   1 +
+ drivers/vfio/fsl-mc/Kconfig               |   9 ++
+ drivers/vfio/fsl-mc/Makefile              |   2 +
+ drivers/vfio/fsl-mc/vfio_fsl_mc.c         | 162 ++++++++++++++++++++++++++++++
+ drivers/vfio/fsl-mc/vfio_fsl_mc_private.h |  14 +++
+ include/uapi/linux/vfio.h                 |   1 +
+ 7 files changed, 190 insertions(+)
+ create mode 100644 drivers/vfio/fsl-mc/Kconfig
+ create mode 100644 drivers/vfio/fsl-mc/Makefile
+ create mode 100644 drivers/vfio/fsl-mc/vfio_fsl_mc.c
+ create mode 100644 drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
+
+--- a/drivers/vfio/Kconfig
++++ b/drivers/vfio/Kconfig
+@@ -47,4 +47,5 @@ menuconfig VFIO_NOIOMMU
+ source "drivers/vfio/pci/Kconfig"
+ source "drivers/vfio/platform/Kconfig"
+ source "drivers/vfio/mdev/Kconfig"
++source "drivers/vfio/fsl-mc/Kconfig"
+ source "virt/lib/Kconfig"
+--- a/drivers/vfio/Makefile
++++ b/drivers/vfio/Makefile
+@@ -9,3 +9,4 @@ obj-$(CONFIG_VFIO_SPAPR_EEH) += vfio_spa
+ obj-$(CONFIG_VFIO_PCI) += pci/
+ obj-$(CONFIG_VFIO_PLATFORM) += platform/
+ obj-$(CONFIG_VFIO_MDEV) += mdev/
++obj-$(CONFIG_VFIO_FSL_MC) += fsl-mc/
+--- /dev/null
++++ b/drivers/vfio/fsl-mc/Kconfig
+@@ -0,0 +1,9 @@
++config VFIO_FSL_MC
++      tristate "VFIO support for QorIQ DPAA2 fsl-mc bus devices"
++      depends on VFIO && FSL_MC_BUS && EVENTFD
++      help
++        Driver to enable support for the VFIO QorIQ DPAA2 fsl-mc
++        (Management Complex) devices. This is required to passthrough
++        fsl-mc bus devices using the VFIO framework.
++
++        If you don't know what to do here, say N.
+--- /dev/null
++++ b/drivers/vfio/fsl-mc/Makefile
+@@ -0,0 +1,2 @@
++vfio-fsl_mc-y := vfio_fsl_mc.o
++obj-$(CONFIG_VFIO_FSL_MC) += vfio_fsl_mc.o
+--- /dev/null
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+@@ -0,0 +1,162 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
++/*
++ * Copyright 2013-2016 Freescale Semiconductor Inc.
++ * Copyright 2016-2017,2019 NXP
++ */
++
++#include <linux/device.h>
++#include <linux/iommu.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/vfio.h>
++#include <linux/fsl/mc.h>
++
++#include "vfio_fsl_mc_private.h"
++
++
++static int vfio_fsl_mc_open(void *device_data)
++{
++      if (!try_module_get(THIS_MODULE))
++              return -ENODEV;
++
++      return 0;
++}
++
++static void vfio_fsl_mc_release(void *device_data)
++{
++      module_put(THIS_MODULE);
++}
++
++static long vfio_fsl_mc_ioctl(void *device_data, unsigned int cmd,
++                            unsigned long arg)
++{
++      switch (cmd) {
++      case VFIO_DEVICE_GET_INFO:
++      {
++              return -EINVAL;
++      }
++      case VFIO_DEVICE_GET_REGION_INFO:
++      {
++              return -EINVAL;
++      }
++      case VFIO_DEVICE_GET_IRQ_INFO:
++      {
++              return -EINVAL;
++      }
++      case VFIO_DEVICE_SET_IRQS:
++      {
++              return -EINVAL;
++      }
++      case VFIO_DEVICE_RESET:
++      {
++              return -EINVAL;
++      }
++      default:
++              return -EINVAL;
++      }
++}
++
++static ssize_t vfio_fsl_mc_read(void *device_data, char __user *buf,
++                              size_t count, loff_t *ppos)
++{
++      return -EINVAL;
++}
++
++static ssize_t vfio_fsl_mc_write(void *device_data, const char __user *buf,
++                               size_t count, loff_t *ppos)
++{
++      return -EINVAL;
++}
++
++static int vfio_fsl_mc_mmap(void *device_data, struct vm_area_struct *vma)
++{
++      return -EINVAL;
++}
++
++static const struct vfio_device_ops vfio_fsl_mc_ops = {
++      .name           = "vfio-fsl-mc",
++      .open           = vfio_fsl_mc_open,
++      .release        = vfio_fsl_mc_release,
++      .ioctl          = vfio_fsl_mc_ioctl,
++      .read           = vfio_fsl_mc_read,
++      .write          = vfio_fsl_mc_write,
++      .mmap           = vfio_fsl_mc_mmap,
++};
++
++static int vfio_fsl_mc_probe(struct fsl_mc_device *mc_dev)
++{
++      struct iommu_group *group;
++      struct vfio_fsl_mc_device *vdev;
++      struct device *dev = &mc_dev->dev;
++      int ret;
++
++      group = vfio_iommu_group_get(dev);
++      if (!group) {
++              dev_err(dev, "%s: VFIO: No IOMMU group\n", __func__);
++              return -EINVAL;
++      }
++
++      vdev = devm_kzalloc(dev, sizeof(*vdev), GFP_KERNEL);
++      if (!vdev) {
++              vfio_iommu_group_put(group, dev);
++              return -ENOMEM;
++      }
++
++      vdev->mc_dev = mc_dev;
++
++      ret = vfio_add_group_dev(dev, &vfio_fsl_mc_ops, vdev);
++      if (ret) {
++              dev_err(dev, "%s: Failed to add to vfio group\n", __func__);
++              vfio_iommu_group_put(group, dev);
++              return ret;
++      }
++
++      return ret;
++}
++
++static int vfio_fsl_mc_remove(struct fsl_mc_device *mc_dev)
++{
++      struct vfio_fsl_mc_device *vdev;
++      struct device *dev = &mc_dev->dev;
++
++      vdev = vfio_del_group_dev(dev);
++      if (!vdev)
++              return -EINVAL;
++
++      vfio_iommu_group_put(mc_dev->dev.iommu_group, dev);
++      devm_kfree(dev, vdev);
++
++      return 0;
++}
++
++/*
++ * vfio-fsl_mc is a meta-driver, so use driver_override interface to
++ * bind a fsl_mc container with this driver and match_id_table is NULL.
++ */
++static struct fsl_mc_driver vfio_fsl_mc_driver = {
++      .probe          = vfio_fsl_mc_probe,
++      .remove         = vfio_fsl_mc_remove,
++      .match_id_table = NULL,
++      .driver = {
++              .name   = "vfio-fsl-mc",
++              .owner  = THIS_MODULE,
++      },
++};
++
++static int __init vfio_fsl_mc_driver_init(void)
++{
++      return fsl_mc_driver_register(&vfio_fsl_mc_driver);
++}
++
++static void __exit vfio_fsl_mc_driver_exit(void)
++{
++      fsl_mc_driver_unregister(&vfio_fsl_mc_driver);
++}
++
++module_init(vfio_fsl_mc_driver_init);
++module_exit(vfio_fsl_mc_driver_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("VFIO for FSL-MC devices - User Level meta-driver");
+--- /dev/null
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
+@@ -0,0 +1,14 @@
++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
++/*
++ * Copyright 2013-2016 Freescale Semiconductor Inc.
++ * Copyright 2016,2019 NXP
++ */
++
++#ifndef VFIO_FSL_MC_PRIVATE_H
++#define VFIO_FSL_MC_PRIVATE_H
++
++struct vfio_fsl_mc_device {
++      struct fsl_mc_device            *mc_dev;
++};
++
++#endif /* VFIO_PCI_PRIVATE_H */
+--- a/include/uapi/linux/vfio.h
++++ b/include/uapi/linux/vfio.h
+@@ -201,6 +201,7 @@ struct vfio_device_info {
+ #define VFIO_DEVICE_FLAGS_AMBA  (1 << 3)      /* vfio-amba device */
+ #define VFIO_DEVICE_FLAGS_CCW (1 << 4)        /* vfio-ccw device */
+ #define VFIO_DEVICE_FLAGS_AP  (1 << 5)        /* vfio-ap device */
++#define VFIO_DEVICE_FLAGS_FSL_MC (1 << 6)     /* vfio-fsl-mc device */
+       __u32   num_regions;    /* Max region index + 1 */
+       __u32   num_irqs;       /* Max IRQ index + 1 */
+ };
diff --git a/target/linux/layerscape/patches-5.4/821-vfio-0002-vfio-fsl-mc-Scan-DPRC-objects-on-vfio-fsl-mc-driver-.patch b/target/linux/layerscape/patches-5.4/821-vfio-0002-vfio-fsl-mc-Scan-DPRC-objects-on-vfio-fsl-mc-driver-.patch
new file mode 100644 (file)
index 0000000..6887477
--- /dev/null
@@ -0,0 +1,140 @@
+From a309870f6fa4a9f69ca7490b355d147b0caeffd0 Mon Sep 17 00:00:00 2001
+From: Diana Craciun <diana.craciun@nxp.com>
+Date: Fri, 13 Sep 2019 17:20:35 +0300
+Subject: [PATCH] vfio/fsl-mc: Scan DPRC objects on vfio-fsl-mc driver bind
+
+The DPRC(Data Path Resource Container) device is a bus device and has
+child devices attached to it. When the vfio-fsl-mc driver is probed
+the DPRC is scanned and the child devices discovered and initialized.
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ drivers/vfio/fsl-mc/vfio_fsl_mc.c | 99 +++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 99 insertions(+)
+
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+@@ -74,7 +74,75 @@ static int vfio_fsl_mc_mmap(void *device
+ {
+       return -EINVAL;
+ }
++static int vfio_fsl_mc_init_device(struct vfio_fsl_mc_device *vdev)
++{
++      struct fsl_mc_device *mc_dev = vdev->mc_dev;
++      struct fsl_mc_bus *mc_bus;
++      size_t region_size;
++      int ret = 0;
++      unsigned int irq_count;
++
++      /* Non-dprc devices share mc_io from parent */
++      if (!is_fsl_mc_bus_dprc(mc_dev)) {
++              struct fsl_mc_device *mc_cont = to_fsl_mc_device(mc_dev->dev.parent);
++
++              mc_dev->mc_io = mc_cont->mc_io;
++              return 0;
++      }
++
++      /* Use dprc mc-portal for interaction with MC f/w. */
++      region_size = resource_size(mc_dev->regions);
++      ret = fsl_create_mc_io(&mc_dev->dev,
++                       mc_dev->regions[0].start,
++                       region_size,
++                       NULL,
++                       FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
++                       &mc_dev->mc_io);
++      if (ret < 0) {
++              dev_err(&mc_dev->dev, "failed to create mc-io (error = %d)\n", ret);
++              return ret;
++      }
++      ret = dprc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id,
++                        &mc_dev->mc_handle);
++      if (ret < 0) {
++              dev_err(&mc_dev->dev, "dprc_open() failed: %d\n", ret);
++              goto clean_mc_io;
++      }
++      mc_bus = to_fsl_mc_bus(mc_dev);
++      /* initialize resource pools */
++      fsl_mc_init_all_resource_pools(mc_dev);
++
++      mutex_init(&mc_bus->scan_mutex);
++
++      mutex_lock(&mc_bus->scan_mutex);
++      ret = dprc_scan_objects(mc_dev, mc_dev->driver_override, false,
++              &irq_count);
++      mutex_unlock(&mc_bus->scan_mutex);
++
++      if (ret < 0) {
++              dev_err(&mc_dev->dev, "dprc_scan_objects() failed: %d\n", ret);
++              goto clean_resource_pool;
++      }
++
++      if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) {
++              dev_warn(&mc_dev->dev,
++                       "IRQs needed (%u) exceed IRQs preallocated (%u)\n",
++                       irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
++      }
++
++return 0;
++
++clean_resource_pool:
++      fsl_mc_cleanup_all_resource_pools(mc_dev);
++      dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
++
++clean_mc_io:
++      fsl_destroy_mc_io(mc_dev->mc_io);
++      mc_dev->mc_io = NULL;
++
++      return ret;
++}
+ static const struct vfio_device_ops vfio_fsl_mc_ops = {
+       .name           = "vfio-fsl-mc",
+       .open           = vfio_fsl_mc_open,
+@@ -113,8 +181,34 @@ static int vfio_fsl_mc_probe(struct fsl_
+               return ret;
+       }
++      ret = vfio_fsl_mc_init_device(vdev);
++      if (ret) {
++              vfio_iommu_group_put(group, dev);
++              return ret;
++      }
++
+       return ret;
+ }
++static int vfio_fsl_mc_device_remove(struct device *dev, void *data)
++{
++      struct fsl_mc_device *mc_dev;
++
++      WARN_ON(dev == NULL);
++      mc_dev = to_fsl_mc_device(dev);
++      if (WARN_ON(mc_dev == NULL))
++              return -ENODEV;
++      fsl_mc_device_remove(mc_dev);
++
++      return 0;
++}
++
++static void vfio_fsl_mc_cleanup_dprc(struct fsl_mc_device *mc_dev)
++{
++      device_for_each_child(&mc_dev->dev, NULL, vfio_fsl_mc_device_remove);
++      fsl_mc_cleanup_all_resource_pools(mc_dev);
++      dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
++      fsl_destroy_mc_io(mc_dev->mc_io);
++}
+ static int vfio_fsl_mc_remove(struct fsl_mc_device *mc_dev)
+ {
+@@ -125,6 +219,11 @@ static int vfio_fsl_mc_remove(struct fsl
+       if (!vdev)
+               return -EINVAL;
++      if (is_fsl_mc_bus_dprc(mc_dev))
++              vfio_fsl_mc_cleanup_dprc(vdev->mc_dev);
++
++      mc_dev->mc_io = NULL;
++
+       vfio_iommu_group_put(mc_dev->dev.iommu_group, dev);
+       devm_kfree(dev, vdev);
diff --git a/target/linux/layerscape/patches-5.4/821-vfio-0003-vfio-fsl-mc-Implement-VFIO_DEVICE_GET_INFO-ioctl.patch b/target/linux/layerscape/patches-5.4/821-vfio-0003-vfio-fsl-mc-Implement-VFIO_DEVICE_GET_INFO-ioctl.patch
new file mode 100644 (file)
index 0000000..7ec0305
--- /dev/null
@@ -0,0 +1,48 @@
+From a548dc00536e2cc6e7e7f95487f5261b3133a0d7 Mon Sep 17 00:00:00 2001
+From: Diana Craciun <diana.craciun@nxp.com>
+Date: Wed, 18 Sep 2019 18:26:14 +0300
+Subject: [PATCH] vfio/fsl-mc: Implement VFIO_DEVICE_GET_INFO ioctl
+
+Allow userspace to get fsl-mc device info (number of regions
+and irqs).
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ drivers/vfio/fsl-mc/vfio_fsl_mc.c | 22 +++++++++++++++++++++-
+ 1 file changed, 21 insertions(+), 1 deletion(-)
+
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+@@ -32,10 +32,30 @@ static void vfio_fsl_mc_release(void *de
+ static long vfio_fsl_mc_ioctl(void *device_data, unsigned int cmd,
+                             unsigned long arg)
+ {
++      unsigned long minsz;
++      struct vfio_fsl_mc_device *vdev = device_data;
++      struct fsl_mc_device *mc_dev = vdev->mc_dev;
++
+       switch (cmd) {
+       case VFIO_DEVICE_GET_INFO:
+       {
+-              return -EINVAL;
++              struct vfio_device_info info;
++
++              minsz = offsetofend(struct vfio_device_info, num_irqs);
++
++              if (copy_from_user(&info, (void __user *)arg, minsz))
++                      return -EFAULT;
++
++              if (info.argsz < minsz)
++                      return -EINVAL;
++
++              info.flags = VFIO_DEVICE_FLAGS_FSL_MC;
++              info.num_regions = mc_dev->obj_desc.region_count;
++              info.num_irqs = mc_dev->obj_desc.irq_count;
++
++              return copy_to_user((void __user *)arg, &info, minsz) ?
++                      -EFAULT : 0;
++
+       }
+       case VFIO_DEVICE_GET_REGION_INFO:
+       {
diff --git a/target/linux/layerscape/patches-5.4/821-vfio-0004-vfio-fsl-mc-Implement-VFIO_DEVICE_GET_REGION_INFO-io.patch b/target/linux/layerscape/patches-5.4/821-vfio-0004-vfio-fsl-mc-Implement-VFIO_DEVICE_GET_REGION_INFO-io.patch
new file mode 100644 (file)
index 0000000..c538ed0
--- /dev/null
@@ -0,0 +1,153 @@
+From 10abb46294d1569826854f77bcdb5d38d8db8e79 Mon Sep 17 00:00:00 2001
+From: Diana Craciun <diana.craciun@nxp.com>
+Date: Thu, 26 Sep 2019 15:13:24 +0300
+Subject: [PATCH] vfio/fsl-mc: Implement VFIO_DEVICE_GET_REGION_INFO ioctl call
+
+Expose to userspace information about the memory regions.
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ drivers/vfio/fsl-mc/vfio_fsl_mc.c         | 76 ++++++++++++++++++++++++++++++-
+ drivers/vfio/fsl-mc/vfio_fsl_mc_private.h | 19 ++++++++
+ 2 files changed, 94 insertions(+), 1 deletion(-)
+
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+@@ -16,16 +16,70 @@
+ #include "vfio_fsl_mc_private.h"
++static int vfio_fsl_mc_regions_init(struct vfio_fsl_mc_device *vdev)
++{
++      struct fsl_mc_device *mc_dev = vdev->mc_dev;
++      int count = mc_dev->obj_desc.region_count;
++      int i;
++
++      vdev->regions = kcalloc(count, sizeof(struct vfio_fsl_mc_region),
++                              GFP_KERNEL);
++      if (!vdev->regions)
++              return -ENOMEM;
++
++      for (i = 0; i < count; i++) {
++              struct resource *res = &mc_dev->regions[i];
++
++              vdev->regions[i].addr = res->start;
++              vdev->regions[i].size = PAGE_ALIGN((resource_size(res)));
++              vdev->regions[i].flags = 0;
++      }
++
++      vdev->num_regions = mc_dev->obj_desc.region_count;
++      return 0;
++}
++static void vfio_fsl_mc_regions_cleanup(struct vfio_fsl_mc_device *vdev)
++{
++      vdev->num_regions = 0;
++      kfree(vdev->regions);
++}
++
+ static int vfio_fsl_mc_open(void *device_data)
+ {
++      struct vfio_fsl_mc_device *vdev = device_data;
++      int ret;
++
+       if (!try_module_get(THIS_MODULE))
+               return -ENODEV;
++      mutex_lock(&vdev->driver_lock);
++      if (!vdev->refcnt) {
++              ret = vfio_fsl_mc_regions_init(vdev);
++              if (ret)
++                      goto err_reg_init;
++      }
++      vdev->refcnt++;
++
++      mutex_unlock(&vdev->driver_lock);
+       return 0;
++
++err_reg_init:
++      mutex_unlock(&vdev->driver_lock);
++      module_put(THIS_MODULE);
++      return ret;
+ }
+ static void vfio_fsl_mc_release(void *device_data)
+ {
++      struct vfio_fsl_mc_device *vdev = device_data;
++
++      mutex_lock(&vdev->driver_lock);
++
++      if (!(--vdev->refcnt))
++              vfio_fsl_mc_regions_cleanup(vdev);
++
++      mutex_unlock(&vdev->driver_lock);
++
+       module_put(THIS_MODULE);
+ }
+@@ -59,7 +113,26 @@ static long vfio_fsl_mc_ioctl(void *devi
+       }
+       case VFIO_DEVICE_GET_REGION_INFO:
+       {
+-              return -EINVAL;
++              struct vfio_region_info info;
++
++              minsz = offsetofend(struct vfio_region_info, offset);
++
++              if (copy_from_user(&info, (void __user *)arg, minsz))
++                      return -EFAULT;
++
++              if (info.argsz < minsz)
++                      return -EINVAL;
++
++              if (info.index >= vdev->num_regions)
++                      return -EINVAL;
++
++              /* map offset to the physical address  */
++              info.offset = VFIO_FSL_MC_INDEX_TO_OFFSET(info.index);
++              info.size = vdev->regions[info.index].size;
++              info.flags = vdev->regions[info.index].flags;
++
++              return copy_to_user((void __user *)arg, &info, minsz);
++
+       }
+       case VFIO_DEVICE_GET_IRQ_INFO:
+       {
+@@ -206,6 +279,7 @@ static int vfio_fsl_mc_probe(struct fsl_
+               vfio_iommu_group_put(group, dev);
+               return ret;
+       }
++      mutex_init(&vdev->driver_lock);
+       return ret;
+ }
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
+@@ -7,8 +7,27 @@
+ #ifndef VFIO_FSL_MC_PRIVATE_H
+ #define VFIO_FSL_MC_PRIVATE_H
++#define VFIO_FSL_MC_OFFSET_SHIFT    40
++#define VFIO_FSL_MC_OFFSET_MASK (((u64)(1) << VFIO_FSL_MC_OFFSET_SHIFT) - 1)
++
++#define VFIO_FSL_MC_OFFSET_TO_INDEX(off) (off >> VFIO_FSL_MC_OFFSET_SHIFT)
++
++#define VFIO_FSL_MC_INDEX_TO_OFFSET(index)    \
++      ((u64)(index) << VFIO_FSL_MC_OFFSET_SHIFT)
++
++struct vfio_fsl_mc_region {
++      u32                     flags;
++      u32                     type;
++      u64                     addr;
++      resource_size_t         size;
++};
++
+ struct vfio_fsl_mc_device {
+       struct fsl_mc_device            *mc_dev;
++      int                             refcnt;
++      u32                             num_regions;
++      struct vfio_fsl_mc_region       *regions;
++      struct mutex driver_lock;
+ };
+ #endif /* VFIO_PCI_PRIVATE_H */
diff --git a/target/linux/layerscape/patches-5.4/821-vfio-0005-vfio-fsl-mc-Allow-userspace-to-MMAP-fsl-mc-device-MM.patch b/target/linux/layerscape/patches-5.4/821-vfio-0005-vfio-fsl-mc-Allow-userspace-to-MMAP-fsl-mc-device-MM.patch
new file mode 100644 (file)
index 0000000..67bdd20
--- /dev/null
@@ -0,0 +1,99 @@
+From 3b81ac2bdcff0f611cad468329cc726600bb23ba Mon Sep 17 00:00:00 2001
+From: Diana Craciun <diana.craciun@nxp.com>
+Date: Fri, 27 Sep 2019 16:40:34 +0300
+Subject: [PATCH] vfio/fsl-mc: Allow userspace to MMAP fsl-mc device MMIO
+ regions
+
+Allow userspace to mmap device regions for direct access of
+fsl-mc devices.
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ drivers/vfio/fsl-mc/vfio_fsl_mc.c | 65 +++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 63 insertions(+), 2 deletions(-)
+
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+@@ -32,7 +32,10 @@ static int vfio_fsl_mc_regions_init(stru
+               vdev->regions[i].addr = res->start;
+               vdev->regions[i].size = PAGE_ALIGN((resource_size(res)));
+-              vdev->regions[i].flags = 0;
++              vdev->regions[i].flags = VFIO_REGION_INFO_FLAG_MMAP;
++              vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_READ;
++              if (!(mc_dev->regions[i].flags & IORESOURCE_READONLY))
++                      vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_WRITE;
+       }
+       vdev->num_regions = mc_dev->obj_desc.region_count;
+@@ -163,10 +166,68 @@ static ssize_t vfio_fsl_mc_write(void *d
+       return -EINVAL;
+ }
++static int vfio_fsl_mc_mmap_mmio(struct vfio_fsl_mc_region region,
++                               struct vm_area_struct *vma)
++{
++      u64 size = vma->vm_end - vma->vm_start;
++      u64 pgoff, base;
++
++      pgoff = vma->vm_pgoff &
++              ((1U << (VFIO_FSL_MC_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
++      base = pgoff << PAGE_SHIFT;
++
++      if (region.size < PAGE_SIZE || base + size > region.size)
++              return -EINVAL;
++
++      vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++
++      vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff;
++
++      return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
++                             size, vma->vm_page_prot);
++}
++
+ static int vfio_fsl_mc_mmap(void *device_data, struct vm_area_struct *vma)
+ {
+-      return -EINVAL;
++      struct vfio_fsl_mc_device *vdev = device_data;
++      struct fsl_mc_device *mc_dev = vdev->mc_dev;
++      unsigned long size, addr;
++      int index;
++
++      index = vma->vm_pgoff >> (VFIO_FSL_MC_OFFSET_SHIFT - PAGE_SHIFT);
++
++      if (vma->vm_end < vma->vm_start)
++              return -EINVAL;
++      if (vma->vm_start & ~PAGE_MASK)
++              return -EINVAL;
++      if (vma->vm_end & ~PAGE_MASK)
++              return -EINVAL;
++      if (!(vma->vm_flags & VM_SHARED))
++              return -EINVAL;
++      if (index >= vdev->num_regions)
++              return -EINVAL;
++
++      if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_MMAP))
++              return -EINVAL;
++
++      if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ)
++                      && (vma->vm_flags & VM_READ))
++              return -EINVAL;
++
++      if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE)
++                      && (vma->vm_flags & VM_WRITE))
++              return -EINVAL;
++
++      addr = vdev->regions[index].addr;
++      size = vdev->regions[index].size;
++
++      vma->vm_private_data = mc_dev;
++
++      return vfio_fsl_mc_mmap_mmio(vdev->regions[index], vma);
++
++      return -EFAULT;
+ }
++
+ static int vfio_fsl_mc_init_device(struct vfio_fsl_mc_device *vdev)
+ {
+       struct fsl_mc_device *mc_dev = vdev->mc_dev;
diff --git a/target/linux/layerscape/patches-5.4/821-vfio-0006-vfio-fsl-mc-Added-lock-support-in-preparation-for-in.patch b/target/linux/layerscape/patches-5.4/821-vfio-0006-vfio-fsl-mc-Added-lock-support-in-preparation-for-in.patch
new file mode 100644 (file)
index 0000000..490f4e3
--- /dev/null
@@ -0,0 +1,193 @@
+From 9ea8e954812efc4fc9b27e553019295d4dcd0407 Mon Sep 17 00:00:00 2001
+From: Diana Craciun <diana.craciun@nxp.com>
+Date: Tue, 15 Oct 2019 11:22:26 +0300
+Subject: [PATCH] vfio/fsl-mc: Added lock support in preparation for interrupt
+ handling
+
+All the devices in a DPRC share the same pool of interrupts.
+Because of this the access to the pool of interrupts must be
+protected with a lock. Extend the current lock implementation
+to have a lock per DPRC.
+
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ drivers/vfio/fsl-mc/vfio_fsl_mc.c         | 90 ++++++++++++++++++++++++++++---
+ drivers/vfio/fsl-mc/vfio_fsl_mc_private.h |  7 ++-
+ 2 files changed, 89 insertions(+), 8 deletions(-)
+
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+@@ -15,6 +15,75 @@
+ #include "vfio_fsl_mc_private.h"
++static DEFINE_MUTEX(reflck_lock);
++
++static void vfio_fsl_mc_reflck_get(struct vfio_fsl_mc_reflck *reflck)
++{
++      kref_get(&reflck->kref);
++}
++
++static void vfio_fsl_mc_reflck_release(struct kref *kref)
++{
++      struct vfio_fsl_mc_reflck *reflck = container_of(kref,
++                                                    struct vfio_fsl_mc_reflck,
++                                                    kref);
++
++      kfree(reflck);
++      mutex_unlock(&reflck_lock);
++}
++
++static void vfio_fsl_mc_reflck_put(struct vfio_fsl_mc_reflck *reflck)
++{
++      kref_put_mutex(&reflck->kref, vfio_fsl_mc_reflck_release, &reflck_lock);
++}
++
++static struct vfio_fsl_mc_reflck *vfio_fsl_mc_reflck_alloc(void)
++{
++      struct vfio_fsl_mc_reflck *reflck;
++
++      reflck = kzalloc(sizeof(*reflck), GFP_KERNEL);
++      if (!reflck)
++              return ERR_PTR(-ENOMEM);
++
++      kref_init(&reflck->kref);
++      mutex_init(&reflck->lock);
++
++      return reflck;
++}
++
++static int vfio_fsl_mc_reflck_attach(struct vfio_fsl_mc_device *vdev)
++{
++      int ret = 0;
++
++      mutex_lock(&reflck_lock);
++      if (is_fsl_mc_bus_dprc(vdev->mc_dev)) {
++              vdev->reflck = vfio_fsl_mc_reflck_alloc();
++      } else {
++              struct device *mc_cont_dev = vdev->mc_dev->dev.parent;
++              struct vfio_device *device;
++              struct vfio_fsl_mc_device *cont_vdev;
++
++              device = vfio_device_get_from_dev(mc_cont_dev);
++              if (!device) {
++                      ret = -ENODEV;
++                      goto unlock;
++              }
++
++              cont_vdev = vfio_device_data(device);
++              if (!cont_vdev->reflck) {
++                      vfio_device_put(device);
++                      ret = -ENODEV;
++                      goto unlock;
++              }
++              vfio_fsl_mc_reflck_get(cont_vdev->reflck);
++              vdev->reflck = cont_vdev->reflck;
++              vfio_device_put(device);
++      }
++
++unlock:
++      mutex_unlock(&reflck_lock);
++      return ret;
++}
+ static int vfio_fsl_mc_regions_init(struct vfio_fsl_mc_device *vdev)
+ {
+@@ -55,7 +124,7 @@ static int vfio_fsl_mc_open(void *device
+       if (!try_module_get(THIS_MODULE))
+               return -ENODEV;
+-      mutex_lock(&vdev->driver_lock);
++      mutex_lock(&vdev->reflck->lock);
+       if (!vdev->refcnt) {
+               ret = vfio_fsl_mc_regions_init(vdev);
+               if (ret)
+@@ -63,11 +132,11 @@ static int vfio_fsl_mc_open(void *device
+       }
+       vdev->refcnt++;
+-      mutex_unlock(&vdev->driver_lock);
++      mutex_unlock(&vdev->reflck->lock);
+       return 0;
+ err_reg_init:
+-      mutex_unlock(&vdev->driver_lock);
++      mutex_unlock(&vdev->reflck->lock);
+       module_put(THIS_MODULE);
+       return ret;
+ }
+@@ -76,12 +145,12 @@ static void vfio_fsl_mc_release(void *de
+ {
+       struct vfio_fsl_mc_device *vdev = device_data;
+-      mutex_lock(&vdev->driver_lock);
++      mutex_lock(&vdev->reflck->lock);
+       if (!(--vdev->refcnt))
+               vfio_fsl_mc_regions_cleanup(vdev);
+-      mutex_unlock(&vdev->driver_lock);
++      mutex_unlock(&vdev->reflck->lock);
+       module_put(THIS_MODULE);
+ }
+@@ -180,7 +249,6 @@ static int vfio_fsl_mc_mmap_mmio(struct
+               return -EINVAL;
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+-
+       vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff;
+       return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+@@ -335,12 +403,18 @@ static int vfio_fsl_mc_probe(struct fsl_
+               return ret;
+       }
++      ret = vfio_fsl_mc_reflck_attach(vdev);
++      if (ret) {
++              vfio_iommu_group_put(group, dev);
++              return ret;
++      }
++
+       ret = vfio_fsl_mc_init_device(vdev);
+       if (ret) {
++              vfio_fsl_mc_reflck_put(vdev->reflck);
+               vfio_iommu_group_put(group, dev);
+               return ret;
+       }
+-      mutex_init(&vdev->driver_lock);
+       return ret;
+ }
+@@ -374,6 +448,8 @@ static int vfio_fsl_mc_remove(struct fsl
+       if (!vdev)
+               return -EINVAL;
++      vfio_fsl_mc_reflck_put(vdev->reflck);
++
+       if (is_fsl_mc_bus_dprc(mc_dev))
+               vfio_fsl_mc_cleanup_dprc(vdev->mc_dev);
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
+@@ -15,6 +15,11 @@
+ #define VFIO_FSL_MC_INDEX_TO_OFFSET(index)    \
+       ((u64)(index) << VFIO_FSL_MC_OFFSET_SHIFT)
++struct vfio_fsl_mc_reflck {
++      struct kref             kref;
++      struct mutex            lock;
++};
++
+ struct vfio_fsl_mc_region {
+       u32                     flags;
+       u32                     type;
+@@ -27,7 +32,7 @@ struct vfio_fsl_mc_device {
+       int                             refcnt;
+       u32                             num_regions;
+       struct vfio_fsl_mc_region       *regions;
+-      struct mutex driver_lock;
++      struct vfio_fsl_mc_reflck   *reflck;
+ };
+ #endif /* VFIO_PCI_PRIVATE_H */
diff --git a/target/linux/layerscape/patches-5.4/821-vfio-0007-vfio-fsl-mc-Add-irq-infrastructure-for-fsl-mc-device.patch b/target/linux/layerscape/patches-5.4/821-vfio-0007-vfio-fsl-mc-Add-irq-infrastructure-for-fsl-mc-device.patch
new file mode 100644 (file)
index 0000000..025b037
--- /dev/null
@@ -0,0 +1,192 @@
+From aa8dac23408e24432f7d6c404cddc8997a142bd6 Mon Sep 17 00:00:00 2001
+From: Diana Craciun <diana.craciun@nxp.com>
+Date: Mon, 30 Sep 2019 11:56:35 +0300
+Subject: [PATCH] vfio/fsl-mc: Add irq infrastructure for fsl-mc devices
+
+This patch adds the skeleton for interrupt support
+for fsl-mc devices. The interrupts are not yet functional,
+the functionality will be added by subsequent patches.
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ drivers/vfio/fsl-mc/Makefile              |  2 +-
+ drivers/vfio/fsl-mc/vfio_fsl_mc.c         | 71 ++++++++++++++++++++++++++++++-
+ drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c    | 62 +++++++++++++++++++++++++++
+ drivers/vfio/fsl-mc/vfio_fsl_mc_private.h |  5 +++
+ 4 files changed, 137 insertions(+), 3 deletions(-)
+ create mode 100644 drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
+
+--- a/drivers/vfio/fsl-mc/Makefile
++++ b/drivers/vfio/fsl-mc/Makefile
+@@ -1,2 +1,2 @@
+ vfio-fsl_mc-y := vfio_fsl_mc.o
+-obj-$(CONFIG_VFIO_FSL_MC) += vfio_fsl_mc.o
++obj-$(CONFIG_VFIO_FSL_MC) += vfio_fsl_mc.o vfio_fsl_mc_intr.o
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+@@ -208,11 +208,75 @@ static long vfio_fsl_mc_ioctl(void *devi
+       }
+       case VFIO_DEVICE_GET_IRQ_INFO:
+       {
+-              return -EINVAL;
++              struct vfio_irq_info info;
++
++              minsz = offsetofend(struct vfio_irq_info, count);
++              if (copy_from_user(&info, (void __user *)arg, minsz))
++                      return -EFAULT;
++
++              if (info.argsz < minsz)
++                      return -EINVAL;
++
++              if (info.index >= mc_dev->obj_desc.irq_count)
++                      return -EINVAL;
++
++              info.flags = VFIO_IRQ_INFO_EVENTFD;
++              info.count = 1;
++
++              return copy_to_user((void __user *)arg, &info, minsz);
+       }
+       case VFIO_DEVICE_SET_IRQS:
+       {
+-              return -EINVAL;
++              struct vfio_irq_set hdr;
++              u8 *data = NULL;
++              int ret = 0;
++
++              minsz = offsetofend(struct vfio_irq_set, count);
++
++              if (copy_from_user(&hdr, (void __user *)arg, minsz))
++                      return -EFAULT;
++
++              if (hdr.argsz < minsz)
++                      return -EINVAL;
++
++              if (hdr.index >= mc_dev->obj_desc.irq_count)
++                      return -EINVAL;
++
++              if (hdr.start != 0 || hdr.count > 1)
++                      return -EINVAL;
++
++              if (hdr.count == 0 &&
++                  (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE) ||
++                  !(hdr.flags & VFIO_IRQ_SET_ACTION_TRIGGER)))
++                      return -EINVAL;
++
++              if (hdr.flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK |
++                                VFIO_IRQ_SET_ACTION_TYPE_MASK))
++                      return -EINVAL;
++
++              if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) {
++                      size_t size;
++
++                      if (hdr.flags & VFIO_IRQ_SET_DATA_BOOL)
++                              size = sizeof(uint8_t);
++                      else if (hdr.flags & VFIO_IRQ_SET_DATA_EVENTFD)
++                              size = sizeof(int32_t);
++                      else
++                              return -EINVAL;
++
++                      if (hdr.argsz - minsz < hdr.count * size)
++                              return -EINVAL;
++
++                      data = memdup_user((void __user *)(arg + minsz),
++                                         hdr.count * size);
++                      if (IS_ERR(data))
++                              return PTR_ERR(data);
++              }
++
++              ret = vfio_fsl_mc_set_irqs_ioctl(vdev, hdr.flags,
++                                               hdr.index, hdr.start,
++                                               hdr.count, data);
++              return ret;
+       }
+       case VFIO_DEVICE_RESET:
+       {
+@@ -304,6 +368,9 @@ static int vfio_fsl_mc_init_device(struc
+       int ret = 0;
+       unsigned int irq_count;
++      /* innherit the msi domain from parent */
++      dev_set_msi_domain(&mc_dev->dev, dev_get_msi_domain(mc_dev->dev.parent));
++
+       /* Non-dprc devices share mc_io from parent */
+       if (!is_fsl_mc_bus_dprc(mc_dev)) {
+               struct fsl_mc_device *mc_cont = to_fsl_mc_device(mc_dev->dev.parent);
+--- /dev/null
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
+@@ -0,0 +1,62 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
++/*
++ * Copyright 2013-2016 Freescale Semiconductor Inc.
++ * Copyright 2019 NXP
++ */
++
++#include <linux/vfio.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/eventfd.h>
++#include <linux/msi.h>
++
++#include "linux/fsl/mc.h"
++#include "vfio_fsl_mc_private.h"
++
++static int vfio_fsl_mc_irq_mask(struct vfio_fsl_mc_device *vdev,
++                              unsigned int index, unsigned int start,
++                              unsigned int count, uint32_t flags,
++                              void *data)
++{
++      return -EINVAL;
++}
++
++static int vfio_fsl_mc_irq_unmask(struct vfio_fsl_mc_device *vdev,
++                              unsigned int index, unsigned int start,
++                              unsigned int count, uint32_t flags,
++                              void *data)
++{
++      return -EINVAL;
++}
++
++static int vfio_fsl_mc_set_irq_trigger(struct vfio_fsl_mc_device *vdev,
++                                     unsigned int index, unsigned int start,
++                                     unsigned int count, uint32_t flags,
++                                     void *data)
++{
++      return -EINVAL;
++}
++int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev,
++                             uint32_t flags, unsigned int index,
++                             unsigned int start, unsigned int count,
++                             void *data)
++{
++      int ret = -ENOTTY;
++
++      switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
++      case VFIO_IRQ_SET_ACTION_MASK:
++              ret = vfio_fsl_mc_irq_mask(vdev, index, start, count,
++                                         flags, data);
++              break;
++      case VFIO_IRQ_SET_ACTION_UNMASK:
++              ret = vfio_fsl_mc_irq_unmask(vdev, index, start, count,
++                                           flags, data);
++              break;
++      case VFIO_IRQ_SET_ACTION_TRIGGER:
++              ret = vfio_fsl_mc_set_irq_trigger(vdev, index, start,
++                                                count, flags, data);
++              break;
++      }
++
++      return ret;
++}
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
+@@ -35,4 +35,9 @@ struct vfio_fsl_mc_device {
+       struct vfio_fsl_mc_reflck   *reflck;
+ };
++int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev,
++                             uint32_t flags, unsigned int index,
++                             unsigned int start, unsigned int count,
++                             void *data);
++
+ #endif /* VFIO_PCI_PRIVATE_H */
diff --git a/target/linux/layerscape/patches-5.4/821-vfio-0008-vfio-fsl-mc-trigger-an-interrupt-via-eventfd.patch b/target/linux/layerscape/patches-5.4/821-vfio-0008-vfio-fsl-mc-trigger-an-interrupt-via-eventfd.patch
new file mode 100644 (file)
index 0000000..4f1e099
--- /dev/null
@@ -0,0 +1,268 @@
+From 8f0239c9385028a0c15306966c66a56315b11dbc Mon Sep 17 00:00:00 2001
+From: Diana Craciun <diana.craciun@nxp.com>
+Date: Tue, 1 Oct 2019 16:44:04 +0300
+Subject: [PATCH] vfio/fsl-mc: trigger an interrupt via eventfd
+
+This patch allows to set an eventfd for fsl-mc device interrupt
+and also to trigger the interrupt eventfd from userspace for testing.
+
+All fsl-mc device interrupts are MSI type. This does not yet handle
+correctly DPRC container interrupt where re-scanning on container is
+required.
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ drivers/vfio/fsl-mc/vfio_fsl_mc.c         |  20 +++-
+ drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c    | 165 +++++++++++++++++++++++++++++-
+ drivers/vfio/fsl-mc/vfio_fsl_mc_private.h |  10 ++
+ 3 files changed, 193 insertions(+), 2 deletions(-)
+
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+@@ -144,12 +144,30 @@ err_reg_init:
+ static void vfio_fsl_mc_release(void *device_data)
+ {
+       struct vfio_fsl_mc_device *vdev = device_data;
++      int ret;
+       mutex_lock(&vdev->reflck->lock);
+-      if (!(--vdev->refcnt))
++      if (!(--vdev->refcnt)) {
++              struct fsl_mc_device *mc_dev = vdev->mc_dev;
++              struct device *cont_dev = fsl_mc_cont_dev(&mc_dev->dev);
++              struct fsl_mc_device *mc_cont = to_fsl_mc_device(cont_dev);
++              struct fsl_mc_bus *mc_bus;
++
++              mc_bus = to_fsl_mc_bus(mc_cont);
++
+               vfio_fsl_mc_regions_cleanup(vdev);
++              /* reset the device before cleaning up the interrupts */
++              ret = dprc_reset_container(mc_dev->mc_io, 0,
++                    mc_dev->mc_handle,
++                        mc_dev->obj_desc.id);
++
++              vfio_fsl_mc_irqs_cleanup(vdev);
++
++              fsl_mc_cleanup_irq_pool(mc_bus);
++      }
++
+       mutex_unlock(&vdev->reflck->lock);
+       module_put(THIS_MODULE);
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
+@@ -29,12 +29,154 @@ static int vfio_fsl_mc_irq_unmask(struct
+       return -EINVAL;
+ }
++int vfio_fsl_mc_irqs_allocate(struct vfio_fsl_mc_device *vdev)
++{
++      struct fsl_mc_device *mc_dev = vdev->mc_dev;
++      struct vfio_fsl_mc_irq *mc_irq;
++      int irq_count;
++      int ret, i;
++
++    /* Device does not support any interrupt */
++      if (mc_dev->obj_desc.irq_count == 0)
++              return 0;
++
++      /* interrupts were already allocated for this device */
++      if (vdev->mc_irqs)
++              return 0;
++
++      irq_count = mc_dev->obj_desc.irq_count;
++
++      mc_irq = kcalloc(irq_count, sizeof(*mc_irq), GFP_KERNEL);
++      if (mc_irq == NULL)
++              return -ENOMEM;
++
++      /* Allocate IRQs */
++      ret = fsl_mc_allocate_irqs(mc_dev);
++      if (ret) {
++              kfree(mc_irq);
++              return ret;
++      }
++
++      for (i = 0; i < irq_count; i++) {
++              mc_irq[i].count = 1;
++              mc_irq[i].flags = VFIO_IRQ_INFO_EVENTFD;
++      }
++
++      vdev->mc_irqs = mc_irq;
++
++      return 0;
++}
++static irqreturn_t vfio_fsl_mc_irq_handler(int irq_num, void *arg)
++{
++      struct vfio_fsl_mc_irq *mc_irq = (struct vfio_fsl_mc_irq *)arg;
++
++      eventfd_signal(mc_irq->trigger, 1);
++      return IRQ_HANDLED;
++}
++
++static int vfio_set_trigger(struct vfio_fsl_mc_device *vdev,
++                                                 int index, int fd)
++{
++      struct vfio_fsl_mc_irq *irq = &vdev->mc_irqs[index];
++      struct eventfd_ctx *trigger;
++      int hwirq;
++      int ret;
++
++      hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq;
++      if (irq->trigger) {
++              free_irq(hwirq, irq);
++              kfree(irq->name);
++              eventfd_ctx_put(irq->trigger);
++              irq->trigger = NULL;
++      }
++
++      if (fd < 0) /* Disable only */
++              return 0;
++
++      irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)",
++                          hwirq, dev_name(&vdev->mc_dev->dev));
++      if (!irq->name)
++              return -ENOMEM;
++
++      trigger = eventfd_ctx_fdget(fd);
++      if (IS_ERR(trigger)) {
++              kfree(irq->name);
++              return PTR_ERR(trigger);
++      }
++
++      irq->trigger = trigger;
++
++      ret = request_irq(hwirq, vfio_fsl_mc_irq_handler, 0,
++                irq->name, irq);
++      if (ret) {
++              kfree(irq->name);
++              eventfd_ctx_put(trigger);
++              irq->trigger = NULL;
++              return ret;
++      }
++
++      return 0;
++}
++
+ static int vfio_fsl_mc_set_irq_trigger(struct vfio_fsl_mc_device *vdev,
+                                      unsigned int index, unsigned int start,
+                                      unsigned int count, uint32_t flags,
+                                      void *data)
+ {
+-      return -EINVAL;
++      struct fsl_mc_device *mc_dev = vdev->mc_dev;
++      struct fsl_mc_bus *mc_bus;
++      int ret, hwirq;
++      struct vfio_fsl_mc_irq *irq;
++      struct device *cont_dev = fsl_mc_cont_dev(&mc_dev->dev);
++      struct fsl_mc_device *mc_cont = to_fsl_mc_device(cont_dev);
++
++      if (start != 0 || count != 1)
++              return -EINVAL;
++
++      mc_bus = to_fsl_mc_bus(mc_cont);
++
++      mutex_lock(&vdev->reflck->lock);
++      if (!mc_bus->irq_resources) {
++
++              ret = fsl_mc_populate_irq_pool(mc_bus,
++                      FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
++              if (ret)
++                      goto unlock;
++      }
++
++      ret = vfio_fsl_mc_irqs_allocate(vdev);
++      if (ret)
++              goto unlock;
++      mutex_unlock(&vdev->reflck->lock);
++
++      if (!count && (flags & VFIO_IRQ_SET_DATA_NONE))
++              return vfio_set_trigger(vdev, index, -1);
++
++      if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
++              int32_t fd = *(int32_t *)data;
++
++              return vfio_set_trigger(vdev, index, fd);
++      }
++
++      hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq;
++
++      irq = &vdev->mc_irqs[index];
++
++      if (flags & VFIO_IRQ_SET_DATA_NONE) {
++              vfio_fsl_mc_irq_handler(hwirq, irq);
++
++      } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
++              uint8_t trigger = *(uint8_t *)data;
++
++              if (trigger)
++                      vfio_fsl_mc_irq_handler(hwirq, irq);
++      }
++
++      return 0;
++
++unlock:
++      mutex_unlock(&vdev->reflck->lock);
++      return ret;
+ }
+ int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev,
+                              uint32_t flags, unsigned int index,
+@@ -60,3 +202,24 @@ int vfio_fsl_mc_set_irqs_ioctl(struct vf
+       return ret;
+ }
++
++/* Free All IRQs for the given MC object */
++void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev)
++{
++      struct fsl_mc_device *mc_dev = vdev->mc_dev;
++      int irq_count = mc_dev->obj_desc.irq_count;
++      int i;
++
++      /* Device does not support any interrupt or the interrupts
++       * were not configured
++       */
++      if (mc_dev->obj_desc.irq_count == 0 || !vdev->mc_irqs)
++              return;
++
++      for (i = 0; i < irq_count; i++)
++              vfio_set_trigger(vdev, i, -1);
++
++      fsl_mc_free_irqs(mc_dev);
++      kfree(vdev->mc_irqs);
++      vdev->mc_irqs = NULL;
++}
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
+@@ -15,6 +15,13 @@
+ #define VFIO_FSL_MC_INDEX_TO_OFFSET(index)    \
+       ((u64)(index) << VFIO_FSL_MC_OFFSET_SHIFT)
++struct vfio_fsl_mc_irq {
++      u32         flags;
++      u32         count;
++      struct eventfd_ctx  *trigger;
++      char            *name;
++};
++
+ struct vfio_fsl_mc_reflck {
+       struct kref             kref;
+       struct mutex            lock;
+@@ -33,6 +40,7 @@ struct vfio_fsl_mc_device {
+       u32                             num_regions;
+       struct vfio_fsl_mc_region       *regions;
+       struct vfio_fsl_mc_reflck   *reflck;
++      struct vfio_fsl_mc_irq      *mc_irqs;
+ };
+ int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev,
+@@ -40,4 +48,6 @@ int vfio_fsl_mc_set_irqs_ioctl(struct vf
+                              unsigned int start, unsigned int count,
+                              void *data);
++void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev);
++
+ #endif /* VFIO_PCI_PRIVATE_H */
diff --git a/target/linux/layerscape/patches-5.4/821-vfio-0009-vfio-fsl-mc-Add-read-write-support-for-fsl-mc-device.patch b/target/linux/layerscape/patches-5.4/821-vfio-0009-vfio-fsl-mc-Add-read-write-support-for-fsl-mc-device.patch
new file mode 100644 (file)
index 0000000..5d3d963
--- /dev/null
@@ -0,0 +1,183 @@
+From c4fbb93e85b13edc174fa6fc3105341f646305e4 Mon Sep 17 00:00:00 2001
+From: Diana Craciun <diana.craciun@nxp.com>
+Date: Wed, 2 Oct 2019 11:14:52 +0300
+Subject: [PATCH] vfio/fsl-mc: Add read/write support for fsl-mc devices
+
+This patch adds support to read and write ioctls for
+fsl-mc devices. Only read-write to DPRC/DPMCP devices
+are supported while read writes on other fsl-mc devices
+is not supported by this patch.
+
+Also current patch limits userspace to write complete
+64byte command once and read 64byte response by one ioctl.
+
+Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ drivers/vfio/fsl-mc/vfio_fsl_mc.c         | 125 +++++++++++++++++++++++++++++-
+ drivers/vfio/fsl-mc/vfio_fsl_mc_private.h |   1 +
+ 2 files changed, 124 insertions(+), 2 deletions(-)
+
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+@@ -12,6 +12,7 @@
+ #include <linux/types.h>
+ #include <linux/vfio.h>
+ #include <linux/fsl/mc.h>
++#include <linux/delay.h>
+ #include "vfio_fsl_mc_private.h"
+@@ -112,6 +113,11 @@ static int vfio_fsl_mc_regions_init(stru
+ }
+ static void vfio_fsl_mc_regions_cleanup(struct vfio_fsl_mc_device *vdev)
+ {
++      int i;
++
++      for (i = 0; i < vdev->num_regions; i++)
++              iounmap(vdev->regions[i].ioaddr);
++
+       vdev->num_regions = 0;
+       kfree(vdev->regions);
+ }
+@@ -308,13 +314,128 @@ static long vfio_fsl_mc_ioctl(void *devi
+ static ssize_t vfio_fsl_mc_read(void *device_data, char __user *buf,
+                               size_t count, loff_t *ppos)
+ {
+-      return -EINVAL;
++      struct vfio_fsl_mc_device *vdev = device_data;
++      unsigned int index = VFIO_FSL_MC_OFFSET_TO_INDEX(*ppos);
++      loff_t off = *ppos & VFIO_FSL_MC_OFFSET_MASK;
++      struct vfio_fsl_mc_region *region;
++      uint64_t data[8];
++      int i;
++
++      /* Read ioctl supported only for DPRC and DPMCP device */
++      if (strcmp(vdev->mc_dev->obj_desc.type, "dprc") &&
++          strcmp(vdev->mc_dev->obj_desc.type, "dpmcp"))
++              return -EINVAL;
++
++      if (index >= vdev->num_regions)
++              return -EINVAL;
++
++      region = &vdev->regions[index];
++
++      if (!(region->flags & VFIO_REGION_INFO_FLAG_READ))
++              return -EINVAL;
++
++
++      if (!region->ioaddr) {
++              region->ioaddr = ioremap_nocache(region->addr, region->size);
++              if (!region->ioaddr)
++                      return -ENOMEM;
++      }
++
++      if (count != 64 || off != 0)
++              return -EINVAL;
++
++      for (i = 7; i >= 0; i--)
++              data[i] = readq(region->ioaddr + i * sizeof(uint64_t));
++
++      if (copy_to_user(buf, data, 64))
++              return -EFAULT;
++
++      return count;
+ }
++#define MC_CMD_COMPLETION_TIMEOUT_MS    5000
++#define MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS    500
++
++static int vfio_fsl_mc_send_command(void __iomem *ioaddr, uint64_t *cmd_data)
++{
++      int i;
++      enum mc_cmd_status status;
++      unsigned long timeout_usecs = MC_CMD_COMPLETION_TIMEOUT_MS * 1000;
++
++      /* Write at command parameter into portal */
++      for (i = 7; i >= 1; i--)
++              writeq_relaxed(cmd_data[i], ioaddr + i * sizeof(uint64_t));
++
++      /* Write command header in the end */
++      writeq(cmd_data[0], ioaddr);
++
++      /* Wait for response before returning to user-space
++       * This can be optimized in future to even prepare response
++       * before returning to user-space and avoid read ioctl.
++       */
++      for (;;) {
++              u64 header;
++              struct mc_cmd_header *resp_hdr;
++
++              header = cpu_to_le64(readq_relaxed(ioaddr));
++
++              resp_hdr = (struct mc_cmd_header *)&header;
++              status = (enum mc_cmd_status)resp_hdr->status;
++              if (status != MC_CMD_STATUS_READY)
++                      break;
++
++              udelay(MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS);
++              timeout_usecs -= MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS;
++              if (timeout_usecs == 0)
++                      return -ETIMEDOUT;
++      }
++
++      return 0;
++}
++
++
+ static ssize_t vfio_fsl_mc_write(void *device_data, const char __user *buf,
+                                size_t count, loff_t *ppos)
+ {
+-      return -EINVAL;
++      struct vfio_fsl_mc_device *vdev = device_data;
++      unsigned int index = VFIO_FSL_MC_OFFSET_TO_INDEX(*ppos);
++      loff_t off = *ppos & VFIO_FSL_MC_OFFSET_MASK;
++      struct vfio_fsl_mc_region *region;
++      uint64_t data[8];
++      int ret;
++
++
++      /* Write ioctl supported only for DPRC and DPMCP device */
++      if (strcmp(vdev->mc_dev->obj_desc.type, "dprc") &&
++          strcmp(vdev->mc_dev->obj_desc.type, "dpmcp"))
++              return -EINVAL;
++
++      if (index >= vdev->num_regions)
++              return -EINVAL;
++
++      region = &vdev->regions[index];
++
++      if (!(region->flags & VFIO_REGION_INFO_FLAG_WRITE))
++              return -EINVAL;
++
++      if (!region->ioaddr) {
++              region->ioaddr = ioremap_nocache(region->addr, region->size);
++              if (!region->ioaddr)
++                      return -ENOMEM;
++      }
++
++      if (count != 64 || off != 0)
++              return -EINVAL;
++
++      if (copy_from_user(&data, buf, 64))
++              return -EFAULT;
++
++      ret = vfio_fsl_mc_send_command(region->ioaddr, data);
++      if (ret)
++              return ret;
++
++      return count;
++
+ }
+ static int vfio_fsl_mc_mmap_mmio(struct vfio_fsl_mc_region region,
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
+@@ -32,6 +32,7 @@ struct vfio_fsl_mc_region {
+       u32                     type;
+       u64                     addr;
+       resource_size_t         size;
++      void __iomem            *ioaddr;
+ };
+ struct vfio_fsl_mc_device {
diff --git a/target/linux/layerscape/patches-5.4/821-vfio-0010-vfio-fsl-mc-Map-the-VFIO-region-according-to-the-fla.patch b/target/linux/layerscape/patches-5.4/821-vfio-0010-vfio-fsl-mc-Map-the-VFIO-region-according-to-the-fla.patch
new file mode 100644 (file)
index 0000000..1ddbd8e
--- /dev/null
@@ -0,0 +1,38 @@
+From 41a18521d40ed19c2e22d8e41cc427d18f082b71 Mon Sep 17 00:00:00 2001
+From: Diana Craciun <diana.craciun@nxp.com>
+Date: Mon, 18 Nov 2019 16:32:08 +0200
+Subject: [PATCH] vfio/fsl-mc: Map the VFIO region according to the flags
+ received from mc firmware
+
+There are some VFIO regions which are cacheable (QMAN CENA region).
+These regions should be mapped cacheable.
+
+Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
+---
+ drivers/vfio/fsl-mc/vfio_fsl_mc.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+@@ -106,6 +106,7 @@ static int vfio_fsl_mc_regions_init(stru
+               vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_READ;
+               if (!(mc_dev->regions[i].flags & IORESOURCE_READONLY))
+                       vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_WRITE;
++              vdev->regions[i].type = mc_dev->regions[i].flags & IORESOURCE_BITS;
+       }
+       vdev->num_regions = mc_dev->obj_desc.region_count;
+@@ -451,7 +452,12 @@ static int vfio_fsl_mc_mmap_mmio(struct
+       if (region.size < PAGE_SIZE || base + size > region.size)
+               return -EINVAL;
+-      vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++      if (region.type & DPRC_REGION_CACHEABLE) {
++              if (!(region.type & DPRC_REGION_SHAREABLE))
++                      vma->vm_page_prot = pgprot_cached_ns(vma->vm_page_prot);
++      } else
++              vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++
+       vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff;
+       return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,